From b889fe4b6d3f2cad73529b77966ae98f78215e44 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 15:44:08 +0800 Subject: [PATCH 0001/2794] change mainform.dataProcess to tdbdataprocess --- baseunits/uGetMangaInfosThread.pas | 5 +- baseunits/uUpdateDBThread.pas | 8 +- baseunits/uUpdateThread.pas | 14 +- mangadownloader/forms/frmMain.lfm | 89 +++++++++- mangadownloader/forms/frmMain.pas | 260 ++++++++++------------------- 5 files changed, 182 insertions(+), 194 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index b7afe8940..21f037c5b 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -70,7 +70,7 @@ procedure TGetMangaInfosThread.DoGetInfos; if (FMangaListPos >= 0) and (website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex]) then begin - filterPos := MainForm.dataProcess.GetPos(FMangaListPos); + filterPos := FMangaListPos; FInfo.mangaInfo.title := MainForm.dataProcess.Param[filterPos, DATA_PARAM_NAME]; FInfo.mangaInfo.link := MainForm.dataProcess.Param[filterPos, DATA_PARAM_LINK]; FInfo.mangaInfo.authors := MainForm.dataProcess.Param[filterPos, DATA_PARAM_AUTHORS]; @@ -112,7 +112,8 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.mangaInfo.summary := MainForm.DataProcess.Param[filterPos, DATA_PARAM_SUMMARY]; end; - FInfo.SyncInfoToData(MainForm.DataProcess, filterPos); + { TODO -ocholif : syncinfo with tdbdataprocess } + //FInfo.SyncInfoToData(MainForm.DataProcess, filterPos); end; end; Result := True; diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 07a38582d..d87691d14 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -41,12 +41,12 @@ procedure TUpdateDBThread.MainThreadRefreshList; MainForm.edSearch.Clear; MainForm.dataProcess.RemoveFilter; MainForm.dataProcess.Free; - MainForm.dataProcess := TDataProcess.Create; - MainForm.dataProcess.LoadFromFile(websiteName); + MainForm.dataProcess := TDBDataProcess.Create; + MainForm.dataProcess.Open(websiteName); MainForm.vtMangaList.Clear; - MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.filterPos.Count; + MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; MainForm.lbMode.Caption := - Format(RS_ModeAll, [MainForm.dataProcess.filterPos.Count]); + Format(RS_ModeAll, [MainForm.dataProcess.DataCount]); end; except on E: Exception do diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 3568aed29..5fc6bbb97 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -347,13 +347,11 @@ procedure TUpdateMangaManagerThread.RefreshList; Screen.Cursor := crHourGlass; MainForm.edSearch.Clear; MainForm.dataProcess.RemoveFilter; - MainForm.dataProcess.Free; - MainForm.dataProcess := TDataProcess.Create; - MainForm.dataProcess.LoadFromFile(website); + MainForm.dataProcess.Refresh; MainForm.vtMangaList.Clear; - MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.filterPos.Count; + MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; MainForm.lbMode.Caption := - Format(RS_ModeAll, [MainForm.dataProcess.filterPos.Count]); + Format(RS_ModeAll, [MainForm.dataProcess.DataCount]); Screen.Cursor := crDefault; end; except @@ -587,8 +585,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.Param[k, DATA_PARAM_STATUS] + SEPERATOR + mainDataProcess.Param[k, DATA_PARAM_SUMMARY] + SEPERATOR + mainDataProcess.Param[k, DATA_PARAM_NUMCHAPTER] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_JDN] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_READ] + SEPERATOR); + mainDataProcess.Param[k, DATA_PARAM_JDN] + SEPERATOR); end; end; mainDataProcess.SaveToFile(website); @@ -871,8 +868,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.Param[k, DATA_PARAM_STATUS] + SEPERATOR + s + SEPERATOR + mainDataProcess.Param[k, DATA_PARAM_NUMCHAPTER] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_JDN] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_READ] + SEPERATOR); + mainDataProcess.Param[k, DATA_PARAM_JDN] + SEPERATOR); Break; end; end; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 7e4f697b5..de98f3645 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -140,10 +140,10 @@ object MainForm: TMainForm ClientWidth = 600 TabOrder = 1 object TransferRateGraph: TChart - Left = 339 + Left = 321 Height = 26 Top = 0 - Width = 261 + Width = 279 AllowZoom = False AxisList = < item @@ -201,18 +201,18 @@ object MainForm: TMainForm Left = 0 Height = 28 Top = 0 - Width = 339 + Width = 321 Align = alLeft AutoSize = True BevelOuter = bvNone ClientHeight = 28 - ClientWidth = 339 + ClientWidth = 321 TabOrder = 1 object ToolBarDownload: TToolBar Left = 0 Height = 25 Top = 0 - Width = 339 + Width = 321 AutoSize = True ButtonHeight = 25 EdgeBorders = [] @@ -243,11 +243,11 @@ object MainForm: TMainForm Left = 153 Height = 25 Top = 0 - Width = 23 + Width = 5 Style = tbsDivider end object tbDownloadDeleteCompleted: TToolButton - Left = 176 + Left = 158 Top = 0 AutoSize = True Caption = 'Delete all completed tasks' @@ -3132,10 +3132,9 @@ object MainForm: TMainForm OnColumnDblClick = vtMangaListColumnDblClick OnDragAllowed = vtMangaListDragAllowed OnDragOver = vtMangaListDragOver - OnFreeNode = vtMangaListFreeNode OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint - OnInitNode = vtMangaListInitNode + OnGetNodeDataSize = vtMangaListGetNodeDataSize end object edSearch: TEdit Left = 3 @@ -3756,11 +3755,83 @@ object MainForm: TMainForm top = 432 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 + 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 + 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB + E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 + 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 + E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 + 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 + D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 + 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 + BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 + 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 + 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 + 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F + 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 + 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D + 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 + 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F + 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 + 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 + 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 + 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 + 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 + 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 + 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 + 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 + 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 + 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 + 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 + E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 + 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550073AA550000AA550000 + } ImageIndex = 21 OnClick = miFavoritesCheckNewChapterClick end object miFavoritesStopCheckNewChapter: TMenuItem Caption = 'Stop check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 7 OnClick = miFavoritesStopCheckNewChapterClick end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1969b4204..e7d9abe84 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -499,21 +499,17 @@ TMainForm = class(TForm) procedure vtMangaListDragOver(Sender : TBaseVirtualTree; Source : TObject; Shift : TShiftState; State : TDragState; const Pt : TPoint; Mode : TDropMode; var Effect : LongWord; var Accept : Boolean); - // for search feature - procedure vtMangaListInitSearchNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure vtMangaListFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); procedure vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure vtMangaListInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure tmBackupTimer(Sender: TObject); procedure vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); @@ -549,7 +545,7 @@ TMainForm = class(TForm) isUpdating: Boolean; revisionIni, updates, mangalistIni, options: TIniFile; FavoriteManager: TFavoriteManager; - dataProcess: TDataProcess; + dataProcess: TDBDataProcess; mangaInfo: TMangaInfo; ChapterList: array of TChapterStateItem; DLManager: TDownloadManager; @@ -755,7 +751,7 @@ procedure TMainForm.FormCreate(Sender: TObject); end; end; - dataProcess := TDataProcess.Create; + dataProcess := TDBDataProcess.Create; DLManager := TDownloadManager.Create; DLManager.Restore; @@ -799,8 +795,6 @@ procedure TMainForm.FormCreate(Sender: TObject); InitCheckboxes; - //lbMode.Caption := Format(RS_ModeAll, [dataProcess.filterPos.Count]); - pcMain.ActivePage := tsDownload; CheckForTopPanel; @@ -922,8 +916,7 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); end; //Backup data - if not dataProcess.isFilterAllSites then - dataProcess.SaveToFile; + dataProcess.Save; DLManager.Backup; DLManager.BackupDownloadedChaptersList; isExiting := True; @@ -1060,10 +1053,10 @@ procedure TMainForm.itStartupTimer(Sender: TObject); isStartup := True; try if cbSelectManga.ItemIndex > -1 then - dataProcess.LoadFromFile(cbSelectManga.Items[cbSelectManga.ItemIndex]); - vtMangaList.NodeDataSize := SizeOf(TMangaListItem); - vtMangaList.RootNodeCount := dataProcess.filterPos.Count; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.filterPos.Count]); + dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); + vtMangaList.RootNodeCount := dataProcess.DataCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + dataProcess.Refresh; finally Screen.Cursor := crDefault; end; @@ -1845,10 +1838,6 @@ procedure TMainForm.btFavoritesImportClick(Sender: TObject); procedure TMainForm.btChecksClick(Sender: TObject); begin - if dataProcess.Title.Count = 0 then - pmUpdate.Items[0].Enabled := False - else - pmUpdate.Items[0].Enabled := True; if Sender is TControl then with TControl(Sender) do begin pmChapterList.Alignment := Menus.paRight; @@ -1860,7 +1849,6 @@ procedure TMainForm.btChecksClick(Sender: TObject); procedure TMainForm.cbSelectMangaChange(Sender: TObject); var - isFilterAllSites: Boolean; K: Word; begin if cbSelectManga.ItemIndex < 0 then @@ -1870,25 +1858,15 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); begin Screen.Cursor := crHourGlass; try - if dataProcess.Title.Count > 0 then - begin - isFilterAllSites := dataProcess.isFilterAllSites; - dataProcess.RemoveFilter; - if not isFilterAllSites then - dataProcess.SaveToFile; - end; - if Assigned(dataProcess) then - dataProcess.Free; - dataProcess := TDataProcess.Create; - if not dataProcess.LoadFromFile( + if dataProcess = nil then + dataProcess := TDBDataProcess.Create; + if not dataProcess.Open( cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]) then - begin RunGetList; - end; - vtMangaList.OnInitNode := @vtMangaListInitNode; vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.filterPos.Count; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.filterPos.Count]); + vtMangaList.RootNodeCount := dataProcess.DataCount; + dataProcess.Refresh; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; dataProcess.website := cbSelectManga.Items[cbSelectManga.ItemIndex]; CheckForTopPanel; @@ -2069,22 +2047,21 @@ procedure TMainForm.edWebsitesSearchChange(Sender: TObject); procedure TMainForm.btRemoveFilterClick(Sender: TObject); begin - if dataProcess.isFiltered then + if dataProcess.Filtered then begin Screen.Cursor := crHourGlass; try dataProcess.RemoveFilter; - if dataProcess.isFilterAllSites then + if dataProcess.FilterAllSites then begin - dataProcess.isFilterAllSites := False; + dataProcess.FilterAllSites := False; dataProcess.Free; - dataProcess := TDataProcess.Create; - dataProcess.LoadFromFile(cbSelectManga.Items[cbSelectManga.ItemIndex]); + dataProcess := TDBDataProcess.Create; + dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); end; - vtMangaList.OnInitNode := @vtMangaListInitNode; vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.filterPos.Count; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.filterPos.Count]); + vtMangaList.RootNodeCount := dataProcess.DataCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); edSearch.Text := ''; except on E: Exception do @@ -2098,7 +2075,7 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); procedure TMainForm.btFilterClick(Sender: TObject); var - l, checkGenres, uncheckGenres: TStringList; + checkGenres, uncheckGenres: TStringList; i: Cardinal; s: String; begin @@ -2140,8 +2117,7 @@ procedure TMainForm.btFilterClick(Sender: TObject); end; // we will reload the list if search from all websites is enabled - if (cbSearchFromAllSites.Checked) and (not dataProcess.isFilterAllSites) and - (not dataProcess.isFiltered) then + if cbSearchFromAllSites.Checked then begin if not dataProcess.CanFilter(checkGenres, uncheckGenres, edFilterTitle.Text, edFilterAuthors.Text, @@ -2154,14 +2130,8 @@ procedure TMainForm.btFilterClick(Sender: TObject); checkGenres.Free; Exit; end; - l := TStringList.Create; - for i := 0 to cbSelectManga.Items.Count - 1 do - l.Add(cbSelectManga.Items[i]); - dataProcess.Free; - dataProcess := TDataProcess.Create; - dataProcess.LoadFromAllFiles(l); - dataProcess.isFilterAllSites := True; - l.Free; + dataProcess.SitesList.Assign(cbSelectManga.Items); + dataProcess.FilterAllSites := True; end; if dataProcess.Filter(checkGenres, uncheckGenres, @@ -2171,10 +2141,9 @@ procedure TMainForm.btFilterClick(Sender: TObject); seOptionNewMangaTime.Value, rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked) then begin - lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.filterPos.Count]); - vtMangaList.OnInitNode := @vtMangaListInitNode; + lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.DataCount]); vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.filterPos.Count; + vtMangaList.RootNodeCount := dataProcess.DataCount; end; except on E: Exception do @@ -2214,9 +2183,9 @@ procedure TMainForm.miMangaListAddToFavoritesClick(Sender: TObject); if vtMangaList.Selected[xNode] then begin SilentThreadManager.Add(MD_AddToFavorites, - GetMangaSiteName(DataProcess.site.Items[DataProcess.GetPos(xNode^.Index)]), - DataProcess.Param[DataProcess.GetPos(xNode^.Index), DATA_PARAM_NAME], - DataProcess.Param[DataProcess.GetPos(xNode^.Index), DATA_PARAM_LINK]); + dataProcess.WebsiteName[xNode^.Index], + DataProcess.Param[xNode^.Index, DATA_PARAM_NAME], + DataProcess.Param[xNode^.Index, DATA_PARAM_LINK]); end; xNode := vtMangaList.GetNextSelected(xNode); end; @@ -2614,7 +2583,7 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); AllowedToCreate := True; if DLManager.Count > 0 then for j := 0 to DLManager.Count - 1 do - if dataProcess.Param[dataProcess.GetPos(xNode^.Index), DATA_PARAM_NAME] = + if dataProcess.Param[xNode^.Index, DATA_PARAM_NAME] = DLManager.TaskItem(j).DownloadInfo.title then begin if YesAll then @@ -2649,9 +2618,9 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); if AllowedToCreate then SilentThreadManager.Add(MD_DownloadAll, - GetMangaSiteName(DataProcess.site.Items[DataProcess.GetPos(xNode^.Index)]), - dataProcess.Param[DataProcess.GetPos(xNode^.Index), DATA_PARAM_NAME], - dataProcess.Param[DataProcess.GetPos(xNode^.Index), DATA_PARAM_LINK]); + dataProcess.WebsiteName[xNode^.Index], + dataProcess.Param[xNode^.Index, DATA_PARAM_NAME], + dataProcess.Param[xNode^.Index, DATA_PARAM_LINK]); end; xNode := vtMangaList.GetNextSelected(xNode); end; @@ -2684,26 +2653,11 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); end; GetInfosThread := TGetMangaInfosThread.Create; GetInfosThread.MangaListPos := vtMangaList.FocusedNode^.Index; - if DataProcess.searchPos.Count = 0 then - begin - website := GetMangaSiteName( - DataProcess.site.Items[DataProcess.GetPos(GetInfosThread.mangaListPos)]); - //cbSelectManga.Items[cbSelectManga.ItemIndex]; - title := DataProcess.Param[DataProcess.GetPos(GetInfosThread.mangaListPos), - DATA_PARAM_NAME]; - link := DataProcess.Param[DataProcess.GetPos(GetInfosThread.mangaListPos), - DATA_PARAM_LINK]; - end - else - begin - website := GetMangaSiteName( - DataProcess.site.Items[DataProcess.searchPos.Items[GetInfosThread.mangaListPos]]); - //cbSelectManga.Items[cbSelectManga.ItemIndex]; - title := DataProcess.Param[DataProcess.searchPos.Items[GetInfosThread.mangaListPos], - DATA_PARAM_NAME]; - link := DataProcess.Param[DataProcess.searchPos.Items[GetInfosThread.mangaListPos], - DATA_PARAM_LINK]; - end; + + website := dataProcess.WebsiteName[GetInfosThread.MangaListPos]; + title := DataProcess.Param[GetInfosThread.mangaListPos, DATA_PARAM_NAME]; + link := DataProcess.Param[GetInfosThread.mangaListPos, DATA_PARAM_LINK]; + GetInfosThread.Title := title; GetInfosThread.Website := website; GetInfosThread.Link := link; @@ -3851,6 +3805,13 @@ procedure TMainForm.vtMangaListDragOver(Sender : TBaseVirtualTree; Accept := False; end; +procedure TMainForm.vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + Exit; + NodeDataSize := SizeOf(PMangaListItem); +end; + // options procedure TMainForm.btOptionApplyClick(Sender: TObject); @@ -4080,32 +4041,26 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin - if (isExiting) or (dataProcess.JDN.Count = 0) or (dataProcess.filterPos.Count = 0) then + Exit; + if (isExiting) or (dataProcess.DataCount = 0) then Exit; if miHighlightNewManga.Checked then begin try - if currentJDN - cardinal(dataProcess.JDN.Items[dataProcess.GetPos(Node^.Index)]) < + if currentJDN - StrToInt(dataProcess.Param[Node^.Index, DATA_PARAM_JDN]) < seOptionNewMangaTime.Value then begin TargetCanvas.Brush.Color := CL_HLBlueMarks; TargetCanvas.FillRect(CellRect); end; except - on E: Exception do ; + on E: Exception do + WriteLog_E('vtMangaListBeforeCellPaint.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); end; end; end; -procedure TMainForm.vtMangaListFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - Data: PMangaListItem; -begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - Finalize(Data^); -end; - procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -4114,77 +4069,47 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; s: String; begin s := ''; - LPos := dataProcess.GetPos(Node^.Index); - if dataProcess.isFilterAllSites then - s := s + RS_InfoWebsite + LineEnding + - GetMangaSiteName(dataProcess.site.Items[LPos]) + LineEnding + LineEnding; - if Trim(dataProcess.Param[LPos, DATA_PARAM_NAME]) <> '' then - s := s + RS_InfoTitle + LineEnding + dataProcess.Param[LPos, DATA_PARAM_NAME]; - if Trim(dataProcess.Param[LPos, DATA_PARAM_AUTHORS]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoAuthors + LineEnding + - dataProcess.Param[LPos, DATA_PARAM_AUTHORS]; - if Trim(dataProcess.Param[LPos, DATA_PARAM_ARTISTS]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoArtists + LineEnding + - dataProcess.Param[LPos, DATA_PARAM_ARTISTS]; - if Trim(dataProcess.Param[LPos, DATA_PARAM_GENRES]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoGenres + LineEnding + - dataProcess.Param[LPos, DATA_PARAM_GENRES]; - if Trim(dataProcess.Param[LPos, DATA_PARAM_STATUS]) <> '' then + LPos := Node^.Index; + with dataProcess do begin - s := s + LineEnding + LineEnding + RS_InfoStatus + LineEnding; - if dataProcess.Param[LPos, DATA_PARAM_STATUS] = '0' then - s := s + cbFilterStatus.Items[0] - else - s := s + cbFilterStatus.Items[1]; + if FilterAllSites then + s := s + RS_InfoWebsite + LineEnding + + dataProcess.WebsiteName[LPos] + LineEnding + LineEnding; + if Trim(Param[LPos, DATA_PARAM_NAME]) <> '' then + s := s + RS_InfoTitle + LineEnding + Param[LPos, DATA_PARAM_NAME]; + if Trim(Param[LPos, DATA_PARAM_AUTHORS]) <> '' then + s := s + LineEnding + LineEnding + RS_InfoAuthors + LineEnding + + Param[LPos, DATA_PARAM_AUTHORS]; + if Trim(Param[LPos, DATA_PARAM_ARTISTS]) <> '' then + s := s + LineEnding + LineEnding + RS_InfoArtists + LineEnding + + Param[LPos, DATA_PARAM_ARTISTS]; + if Trim(Param[LPos, DATA_PARAM_GENRES]) <> '' then + s := s + LineEnding + LineEnding + RS_InfoGenres + LineEnding + + Param[LPos, DATA_PARAM_GENRES]; + if Trim(Param[LPos, DATA_PARAM_STATUS]) <> '' then + begin + s := s + LineEnding + LineEnding + RS_InfoStatus + LineEnding; + if Param[LPos, DATA_PARAM_STATUS] = '0' then + s := s + cbFilterStatus.Items[0] + else + s := s + cbFilterStatus.Items[1]; + end; + if Trim(Param[LPos, DATA_PARAM_SUMMARY]) <> '' then + //s := s + LineEndingLineEnding + infoSummary + ':' + LineEnding + PrepareSummaryForHint(dataProcess.Param[LPos, DATA_PARAM_SUMMARY], 80); + s := s + LineEnding + LineEnding + RS_InfoSummary + ':' + LineEnding + + StringBreaks(dataProcess.Param[LPos, DATA_PARAM_SUMMARY]); end; - if Trim(dataProcess.Param[LPos, DATA_PARAM_SUMMARY]) <> '' then - //s := s + LineEndingLineEnding + infoSummary + ':' + LineEnding + PrepareSummaryForHint(dataProcess.Param[LPos, DATA_PARAM_SUMMARY], 80); - s := s + LineEnding + LineEnding + RS_InfoSummary + ':' + LineEnding + - StringBreaks(dataProcess.Param[LPos, DATA_PARAM_SUMMARY]); HintText := s; end; procedure TMainForm.vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - Data: PMangaListItem; -begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - CellText := Data^.Text; -end; - -procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Data: PMangaListItem; - pos: Cardinal; begin - with Sender do - begin - pos := dataProcess.filterPos.Items[Node^.Index]; - Data := GetNodeData(Node); - Data^.Text := dataProcess.Param[pos, DATA_PARAM_NAME] + - ' (' + - dataProcess.Param[pos, DATA_PARAM_NUMCHAPTER] + ')'; - end; - vtMangaList.ValidateNode(Node, False); -end; - -procedure TMainForm.vtMangaListInitSearchNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Data: PMangaListItem; - pos: Cardinal; -begin - with Sender do + if Assigned(Node) then begin - pos := dataProcess.searchPos.Items[Node^.Index]; - Data := GetNodeData(Node); - Data^.Text := dataProcess.Param[pos, DATA_PARAM_NAME] + - ' (' + - dataProcess.Param[pos, DATA_PARAM_NUMCHAPTER] + ')'; + CellText := dataProcess.Param[Node^.Index, DATA_PARAM_NAME] + ' ' + + BracketStr(dataProcess.Param[Node^.Index, DATA_PARAM_NUMCHAPTER]) end; end; @@ -4758,10 +4683,9 @@ procedure TMainForm.edSearchChange(Sender: TObject); begin LastSearchStr := ''; //Screen.Cursor := crHourGlass; - DataProcess.searchPos.Clear; - vtMangaList.OnInitNode := @vtMangaListInitNode; vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.filterPos.Count; + dataProcess.Search(edSearch.Text); + vtMangaList.RootNodeCount := dataProcess.DataCount; //Screen.Cursor := crDefault; Exit; end @@ -4770,10 +4694,9 @@ procedure TMainForm.edSearchChange(Sender: TObject); begin LastSearchWeb := currentWebsite; LastSearchStr := upcase(edSearch.Text); - DataProcess.Search(edSearch.Text); vtMangaList.Clear; - vtMangaList.OnInitNode := @vtMangaListInitSearchNode; - vtMangaList.RootNodeCount := dataProcess.searchPos.Count; + DataProcess.Search(edSearch.Text); + vtMangaList.RootNodeCount := dataProcess.DataCount; end; end; @@ -4789,10 +4712,8 @@ procedure TMainForm.edSearchKeyUp(Sender: TObject; var Key: Word; Shift: TShiftS if edSearch.Text = '' then begin Screen.Cursor := crHourGlass; - DataProcess.searchPos.Clear; - vtMangaList.OnInitNode := @vtMangaListInitNode; vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.filterPos.Count; + vtMangaList.RootNodeCount := dataProcess.DataCount; Screen.Cursor := crDefault; end else @@ -4800,9 +4721,8 @@ procedure TMainForm.edSearchKeyUp(Sender: TObject; var Key: Word; Shift: TShiftS Screen.Cursor := crHourGlass; LastSearchWeb := currentWebsite; DataProcess.Search(edSearch.Text); - vtMangaList.OnInitNode := @vtMangaListInitSearchNode; vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.searchPos.Count; + vtMangaList.RootNodeCount := dataProcess.DataCount; Screen.Cursor := crDefault; end; end; From 3ec6c99289132dab11ad49862059dc4704f76240 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 15:48:18 +0800 Subject: [PATCH 0002/2794] remove unused data param --- baseunits/uBaseUnit.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3aac76203..cabf7441b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -52,7 +52,6 @@ interface DATA_PARAM_SUMMARY = 6; DATA_PARAM_NUMCHAPTER = 7; DATA_PARAM_JDN = 8; - DATA_PARAM_READ = 9; FILTER_HIDE = 0; FILTER_SHOW = 1; From c20ea8110c7a8881dbd0c8445af63504e16e1514 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 16:09:17 +0800 Subject: [PATCH 0003/2794] don't need to change currentdir --- baseunits/uBaseUnit.pas | 1 - baseunits/uDownloadsManager.pas | 1 - 2 files changed, 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cabf7441b..b96037fd1 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1211,7 +1211,6 @@ procedure CheckPath(const S: String); end; end; end; - SetCurrentDirUTF8(fmdDirectory); end; function GetMangaSiteID(const Name: String): Cardinal; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 68dd42648..84e35031e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1288,7 +1288,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; prefix, manager.container.Manager.retryConnect); - SetCurrentDirUTF8(fmdDirectory); if Terminated then Exit(False); if Result then manager.container.PageLinks[workCounter] := 'D'; From ab00b03d0f0814251f182b4bcbe952778124aaf2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 16:10:30 +0800 Subject: [PATCH 0004/2794] set sqlite3 library path to app root dir at initialization --- baseunits/uData.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 60f6e22d4..0f4c139c1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, sqlite3conn, sqldb, USimpleLogger, - strutils, dateutils, RegExpr, sqlite3, FileUtil, httpsend; + strutils, dateutils, RegExpr, sqlite3, sqlite3dyn, FileUtil, httpsend; type @@ -2614,4 +2614,8 @@ function TMangaInformation.GetPage(var output: TObject; URL: String; Result := uBaseUnit.GetPage(FHTTP, output, URL, Reconnect); end; +initialization + sqlite3dyn.SQLiteDefaultLibrary := + CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; + end. From 6690114ec94f1a0d06d9bdbb2436419d706ab683 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 16:42:22 +0800 Subject: [PATCH 0005/2794] tdbdataprocess add close method --- baseunits/uData.pas | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0f4c139c1..064b99d1a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -50,6 +50,7 @@ TDBDataProcess = class constructor Create; destructor Destroy; override; function Open(AWebsite: String = ''): Boolean; + procedure Close; procedure Save; procedure Refresh; procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; @@ -398,12 +399,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; if not FileExistsUTF8(filepath) then Exit; try - if FConn.Connected then - begin - FTrans.Commit; - VacuumTable; - FConn.Connected := False; - end; + Self.Close; FConn.DatabaseName := filepath; FConn.Connected := True; sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, @@ -433,6 +429,18 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; end; end; +procedure TDBDataProcess.Close; +begin + if FConn.Connected then + begin + FTrans.Commit; + VacuumTable; + FQuery.Close; + FTrans.Active := False; + FConn.Connected := False; + end; +end; + procedure TDBDataProcess.Save; begin Self.ApplyUpdates; From 69848eebd7df0f0bec1232a2ce5a0d93e07460b8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 17:40:17 +0800 Subject: [PATCH 0006/2794] using pathdelim instead of fixed separator --- baseunits/uBaseUnit.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b96037fd1..cfa5f6a45 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -197,15 +197,15 @@ interface ); README_FILE = 'readme.rtf'; - WORK_FOLDER = 'works/'; + WORK_FOLDER = 'works' + PathDelim; WORK_FILE = 'works.ini'; DOWNLOADEDCHAPTERS_FILE = 'downloadedchapters.ini'; FAVORITES_FILE = 'favorites.ini'; - IMAGE_FOLDER = 'images/'; - DATA_FOLDER = 'data/'; + IMAGE_FOLDER = 'images' + PathDelim; + DATA_FOLDER = 'data' + PathDelim; DATA_EXT = '.dat'; DBDATA_EXT = '.db'; - CONFIG_FOLDER = 'config/'; + CONFIG_FOLDER = 'config' + PathDelim; CONFIG_FILE = 'config.ini'; CONFIG_ADVANCED = 'advanced.ini'; REVISION_FILE = 'revision.ini'; From e6cad600c4f8fef1c77cf0172592b0c550b4ca3c Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 17:42:36 +0800 Subject: [PATCH 0007/2794] clear vtlist before open data --- mangadownloader/forms/frmMain.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e7d9abe84..76ddc6f13 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1047,13 +1047,17 @@ procedure TMainForm.itSaveDownloadedListTimer(Sender: TObject); procedure TMainForm.itStartupTimer(Sender: TObject); begin + itStartup.Enabled := False; if not isStartup then begin Screen.Cursor := crHourGlass; isStartup := True; try if cbSelectManga.ItemIndex > -1 then + begin + vtMangaList.Clear; dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); + end; vtMangaList.RootNodeCount := dataProcess.DataCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); dataProcess.Refresh; @@ -1063,7 +1067,6 @@ procedure TMainForm.itStartupTimer(Sender: TObject); if cbOptionAutoCheckUpdate.Checked then SubThread.CheckUpdate := True; SubThread.Start; - itStartup.Enabled := False; end; end; @@ -1860,10 +1863,10 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); try if dataProcess = nil then dataProcess := TDBDataProcess.Create; + vtMangaList.Clear; if not dataProcess.Open( cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]) then RunGetList; - vtMangaList.Clear; vtMangaList.RootNodeCount := dataProcess.DataCount; dataProcess.Refresh; lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); From 09b1c211a6f33cd248ca440155faf672ea6ab860 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 17:43:10 +0800 Subject: [PATCH 0008/2794] tdbdataprocess, fix open/convert data --- baseunits/uData.pas | 120 +++++++++++++++++++++++++++++++------------- 1 file changed, 86 insertions(+), 34 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 064b99d1a..dc7a7a634 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -40,16 +40,19 @@ TDBDataProcess = class FSitesList: TStringList; FSQLSelect: String; protected - function GetConnected: Boolean; procedure CreateTable; procedure VacuumTable; procedure GetDataCount; + function GetConnected: Boolean; + function InternalOpen(const FilePath: String = ''): Boolean; function GetWebsiteName(RecIndex: Integer): String; function GetParam(RecIndex, ParamNo: Integer): String; public constructor Create; destructor Destroy; override; function Open(AWebsite: String = ''): Boolean; + function OpenTable(const ATableName: String = ''): Boolean; + function TableExist(const ATableName: String): Boolean; procedure Close; procedure Save; procedure Refresh; @@ -256,7 +259,8 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); if FileExistsUTF8(filepath + DBDATA_EXT) then DeleteFileUTF8(filepath + DBDATA_EXT); rawdata.LoadFromFile(AWebsite); - dbdata.Open(AWebsite); + dbdata.InternalOpen(filepath + DBDATA_EXT); + dbdata.CreateTable; if rawdata.Data.Count > 0 then with rawdata do begin @@ -268,6 +272,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); end; dbdata.ApplyUpdates; end; + dbdata.OpenTable; dbdata.Sort; finally rawdata.Free; @@ -280,11 +285,6 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); { TDBDataProcess } -function TDBDataProcess.GetConnected: Boolean; -begin - Result := FConn.Connected; -end; - procedure TDBDataProcess.CreateTable; begin if FConn.Connected then @@ -318,6 +318,35 @@ procedure TDBDataProcess.GetDataCount; FDataCount := 0; end; +function TDBDataProcess.GetConnected: Boolean; +begin + Result := FConn.Connected; +end; + +function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; +begin + Result := False; + if FilePath <> '' then + FConn.DatabaseName := FilePath; + if FConn.DatabaseName = '' then Exit; + try + FConn.Connected := True; + sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, + NaturalCompareCallback); + sqlite3_create_function(FConn.Handle, PChar('REGEXP'), 2, SQLITE_UTF8, FRegxp, + RegexCallback, nil, nil); + FTrans.Active := True; + Result := FConn.Connected; + except + on E: Exception do + begin + WriteLog_E('TDBDataProcess.InternalOpen.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); + Result := False; + end; + end; +end; + function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; begin if FConn.Connected then @@ -385,42 +414,25 @@ destructor TDBDataProcess.Destroy; function TDBDataProcess.Open(AWebsite: String): Boolean; var - ts: TStringList; filepath: String; - i: Integer; begin Result := False; if AWebsite <> '' then FWebsite := AWebsite; if FWebsite = '' then Exit; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; if not FileExistsUTF8(filepath) then - ConvertDataProccessToDB(AWebsite); + ConvertDataProccessToDB(AWebsite, True); if not FileExistsUTF8(filepath) then Exit; - try Self.Close; - FConn.DatabaseName := filepath; - FConn.Connected := True; - sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, - NaturalCompareCallback); - sqlite3_create_function(FConn.Handle, PChar('REGEXP'), 2, SQLITE_UTF8, FRegxp, - RegexCallback, nil, nil); - FTrans.Active := True; - ts := TStringList.Create; - try - FConn.GetTableNames(ts); - ts.Sort; - if not ts.Find(FTableName, i) then + if InternalOpen(filepath) then + begin + if not TableExist(FTableName) then CreateTable; - finally - ts.Free; + OpenTable; + GetDataCount; + FFiltered := False; end; - FSQLSelect := 'SELECT * FROM ' + FTableName;; - FQuery.SQL.Text := FSQLSelect; - FQuery.Open; - GetDataCount; - FFiltered := False; Result := FQuery.Active; except on E: Exception do @@ -429,6 +441,44 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; end; end; +function TDBDataProcess.OpenTable(const ATableName: String): Boolean; +begin + Result := False; + if FConn.Connected then + begin + if ATableName <> '' then + FTableName := ATableName; + if FTableName = '' then Exit; + if TableExist(FTableName) then + begin + if FQuery.Active then + FQuery.Close; + FSQLSelect := 'SELECT * FROM ' + FTableName;; + FQuery.SQL.Text := FSQLSelect; + FQuery.Open; + end; + end; +end; + +function TDBDataProcess.TableExist(const ATableName: String): Boolean; +var + ts: TStringList; + i: Integer; +begin + Result := False; + if FConn.Connected then + begin + ts := TStringList.Create; + try + FConn.GetTableNames(ts); + ts.Sort; + Result := ts.Find(FTableName, i); + finally + ts.Free; + end; + end; +end; + procedure TDBDataProcess.Close; begin if FConn.Connected then @@ -485,10 +535,12 @@ procedure TDBDataProcess.ApplyUpdates; begin if FConn.Connected then begin - FQuery.Close; FTrans.Commit; - FQuery.Open; - GetDataCount; + if FQuery.Active then + begin + FQuery.Refresh; + GetDataCount; + end; end; end; From 36d25529a6aba6721ffb4e155fceb40fbed0cbc9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 17:50:23 +0800 Subject: [PATCH 0009/2794] tdbdataprocess, close first before open --- baseunits/uData.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index dc7a7a634..d2f45aeb8 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -417,6 +417,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; filepath: String; begin Result := False; + Self.Close; if AWebsite <> '' then FWebsite := AWebsite; if FWebsite = '' then Exit; filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; @@ -424,7 +425,6 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; ConvertDataProccessToDB(AWebsite, True); if not FileExistsUTF8(filepath) then Exit; try - Self.Close; if InternalOpen(filepath) then begin if not TableExist(FTableName) then @@ -488,6 +488,8 @@ procedure TDBDataProcess.Close; FQuery.Close; FTrans.Active := False; FConn.Connected := False; + FFiltered := False; + FDataCount := 0; end; end; From ad06291b951a96bb2e6d20abe67b8d500e202f90 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 17:52:12 +0800 Subject: [PATCH 0010/2794] tdbdataprocess, close query first before close database --- baseunits/uData.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d2f45aeb8..b8a14cb8a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -481,15 +481,15 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; procedure TDBDataProcess.Close; begin + FQuery.Close; + FFiltered := False; + FDataCount := 0; if FConn.Connected then begin FTrans.Commit; VacuumTable; - FQuery.Close; FTrans.Active := False; FConn.Connected := False; - FFiltered := False; - FDataCount := 0; end; end; From 48fdf4d371df928ad1602c72c308cb85eeb079f0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 18:02:11 +0800 Subject: [PATCH 0011/2794] tdbdataprocess, don't need to vacuum database on close --- baseunits/uData.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b8a14cb8a..4abeb7dcf 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -487,7 +487,6 @@ procedure TDBDataProcess.Close; if FConn.Connected then begin FTrans.Commit; - VacuumTable; FTrans.Active := False; FConn.Connected := False; end; From 3f0d2bd179d851f52732dc697157cd9ffd9f58c9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 18:13:07 +0800 Subject: [PATCH 0012/2794] replace deprecated fileutil with lazfileutils --- baseunits/uBaseUnit.pas | 4 ++-- baseunits/uData.pas | 4 ++-- baseunits/uDownloadsManager.pas | 2 +- mangadownloader/forms/frmImportFavorites.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 16 ++++++++-------- mangadownloader/md.lpr | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cfa5f6a45..dc8cabbb6 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -18,8 +18,8 @@ interface {$else} UTF8Process, {$endif} - SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, strutils, - fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, FileUtil, RegExpr, + SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, + strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, uMisc, USimpleException, USimpleLogger; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 4abeb7dcf..1476dc1ab 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,8 +14,8 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, sqlite3conn, sqldb, USimpleLogger, - strutils, dateutils, RegExpr, sqlite3, sqlite3dyn, FileUtil, httpsend; + Classes, SysUtils, uBaseUnit, uFMDThread, LazFileUtils, sqlite3conn, sqldb, + USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; type diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 84e35031e..0d57f1476 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -11,7 +11,7 @@ interface uses - lazutf8classes, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, FileUtil, + lazutf8classes, LazFileUtils, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, Controls, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, USimpleLogger, dateutils, frmShutdownCounter; diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index dba70344f..a1f5ab083 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -11,8 +11,8 @@ interface uses - Classes, SysUtils, FileUtil, Forms, Dialogs, StdCtrls, - Buttons, DefaultTranslator, lazutf8classes, uBaseUnit, frmNewChapter; + Classes, SysUtils, Forms, Dialogs, StdCtrls, Buttons, DefaultTranslator, + lazutf8classes, LazFileUtils, uBaseUnit, frmNewChapter; type diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 76ddc6f13..b2f486375 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -16,13 +16,13 @@ interface {$else} FakeActiveX, {$endif} - Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, - LCLType, ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, - IniFiles, simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, - EditBtn, LazUTF8, TAGraph, TASources, TASeries, AnimatedGif, uBaseUnit, uData, - uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, - uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, - frmDropTarget, USimpleException, USimpleLogger; + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, + ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, + simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, + LazUTF8, FileUtil, TAGraph, TASources, TASeries, AnimatedGif, + uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, + uUpdateDBThread, uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, + uTranslation, frmDropTarget, USimpleException, USimpleLogger; type @@ -707,7 +707,7 @@ implementation {$R *.lfm} uses - frmImportFavorites, RegExpr, Clipbrd; + frmImportFavorites, RegExpr, Clipbrd, LazFileUtils; { TMainForm } diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 2da98d4ff..3bcb444a9 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -14,7 +14,7 @@ cthreads, {$ENDIF} {$ENDIF} - Forms, Interfaces, FileUtil, tachartlazaruspkg, simpleipc, IniFiles, + Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, uBaseUnit, frmMain; var From 302a96db712b86e1a177ea75f2368f6c0b60dee3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 18:31:10 +0800 Subject: [PATCH 0013/2794] hide some compiler warning --- baseunits/includes/EHentai/image_url.inc | 2 +- baseunits/includes/MangaReader/image_url.inc | 2 +- .../includes/MeinManga/chapter_page_number.inc | 2 +- baseunits/uDownloadsManager.pas | 18 +++++++++++++++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/baseunits/includes/EHentai/image_url.inc b/baseunits/includes/EHentai/image_url.inc index 784e2b500..2572e5ffa 100644 --- a/baseunits/includes/EHentai/image_url.inc +++ b/baseunits/includes/EHentai/image_url.inc @@ -1,6 +1,6 @@ function getEHentaiImageURL: Boolean; var - i, RetryCount: Cardinal; + i, RetryCount: Integer; prs: TStringList; hparser: THTMLParser; {s, }purl, iurl, base_url, startkey, gid, startpage, nl: String; diff --git a/baseunits/includes/MangaReader/image_url.inc b/baseunits/includes/MangaReader/image_url.inc index 76d5205c4..9d2b0f208 100644 --- a/baseunits/includes/MangaReader/image_url.inc +++ b/baseunits/includes/MangaReader/image_url.inc @@ -1,7 +1,7 @@ function GetMangaReaderImageURL: Boolean; var realURL: String; - i: Cardinal; + i: Integer; l: TStringList; procedure BreakURL; diff --git a/baseunits/includes/MeinManga/chapter_page_number.inc b/baseunits/includes/MeinManga/chapter_page_number.inc index 6eaf62bc9..26ab4b57e 100644 --- a/baseunits/includes/MeinManga/chapter_page_number.inc +++ b/baseunits/includes/MeinManga/chapter_page_number.inc @@ -1,7 +1,7 @@ function GetMeinMangaPageNumber: Boolean; var s: String; - i: Cardinal; + i: Integer; l: TStringList; begin l := TStringList.Create; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 0d57f1476..15cfc59f4 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -8,6 +8,10 @@ {$mode delphi} +{$IF FPC_FULLVERSION >= 20701} + {$DEFINE FPC271} +{$ENDIF} + interface uses @@ -46,7 +50,7 @@ TDownloadThread = class(TFMDThread) // Download image function DownloadImage(const prefix: String = ''): Boolean; - procedure OnTag(NoCaseTag, ActualTag: string); + procedure OnTag({%H-}NoCaseTag, ActualTag: string); procedure OnText(Text: String); procedure SockOnStatus(Sender: TObject; Reason: THookSocketReason; @@ -189,7 +193,7 @@ TDownloadManager = class procedure CheckAndActiveTaskAtStartup; // Check and active waiting tasks. procedure CheckAndActiveTask(const isCheckForFMDDo: Boolean = False; - SenderThread: TThread = nil); + {%H-}SenderThread: TThread = nil); // Check if we can active another wating task or not. function CanActiveTask(const pos : Integer) : Boolean; // Active a stopped task. @@ -237,6 +241,11 @@ implementation uses frmMain; +function IntToStr(Value: Cardinal): string; +begin + Result := SysUtils.IntToStr(QWord(Value)); +end; + { TDownloadThread } procedure TDownloadThread.OnTag(NoCaseTag, ActualTag : string); @@ -1099,6 +1108,9 @@ procedure TDownloadThread.Merge2Images( if (not FileExistsUTF8(fullImgName1)) or (not FileExistsUTF8(fullImgName2)) then Exit; + Initialize(img1); + Initialize(img2); + Initialize(finalImg); // Load first image to stream. stream := TFileStreamUTF8.Create(fullImgName1, fmOpenRead); LoadImageFromStream(stream, img1); @@ -2116,7 +2128,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; Self.Backup; if ThreadID <> MainThreadID then begin - {$IF FPC_FULLVERSION >= 20701} + {$IFDEF FPC271} TThread.Synchronize(TThread.CurrentThread, doExitWaitCounter); {$ELSE} if SenderThread <> nil then From 60102d22661d6aa354b521f96eefdb63ef78aea6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 18:42:22 +0800 Subject: [PATCH 0014/2794] hide some compiler warning --- baseunits/SimpleException/USimpleException.pas | 4 ++-- baseunits/SimpleException/USimpleLogger.pas | 2 +- baseunits/uData.pas | 2 +- baseunits/uFavoritesManager.pas | 2 +- baseunits/uPacker.pas | 6 +++--- baseunits/uUpdateThread.pas | 4 ++-- baseunits/utranslation.pas | 4 ++-- mangadownloader/forms/frmDropTarget.pas | 2 +- mangadownloader/forms/frmMain.pas | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/baseunits/SimpleException/USimpleException.pas b/baseunits/SimpleException/USimpleException.pas index 099b13331..8431079e6 100644 --- a/baseunits/SimpleException/USimpleException.pas +++ b/baseunits/SimpleException/USimpleException.pas @@ -25,8 +25,8 @@ interface uses - Classes, SysUtils, FileUtil, Forms, Controls, LCLVersion, DbgInfoReader, - USimpleExceptionForm, USimpleLogger, + Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, LCLVersion, + DbgInfoReader, USimpleExceptionForm, USimpleLogger, {$IFDEF WINDOWS} windows, win32proc, {$ENDIF} diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index 9d00ec68d..05b11ede4 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -25,7 +25,7 @@ interface uses - Classes, SysUtils, DbgInfoReader, FileUtil; + Classes, SysUtils, DbgInfoReader, LazFileUtils, LazUTF8; type TLogType = (ERROR, WARNING, INFO, DEBUG, VERBOSE); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1476dc1ab..2c67a65fc 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -964,7 +964,7 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; for i := 0 to filterPos.Count - 1 do begin fpos := filterPos.Items[i]; - if (currentJDN - Integer(jdn.Items[fpos]) >= minusDay) and + if (currentJDN - {%H-}Integer(jdn.Items[fpos]) >= minusDay) and (filterMark.Items[fpos] = FILTER_SHOW) then filterMark.Items[fpos] := FILTER_HIDE; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index be923b1b2..17a7a639b 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, FileUtil, + Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, USimpleLogger; type diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 9c2fe64ce..9ae16a6ac 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -11,8 +11,8 @@ interface uses - Classes, FileUtil, Zipper, SysUtils, uBaseUnit, uImg2Pdf, USimpleException, - USimpleLogger; + Classes, Zipper, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, + USimpleException, USimpleLogger; type TPacker = class @@ -30,7 +30,7 @@ TPacker = class implementation uses - lazutf8classes; + lazutf8classes, LazFileUtils; procedure TPacker.OnFileFound(FileIterator: TFileIterator); begin diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 5fc6bbb97..88cc4226d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,8 +12,8 @@ interface uses - Classes, SysUtils, typinfo, FileUtil, syncobjs, uData, uBaseUnit, - uFMDThread, uTranslation; + Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, + uBaseUnit, uFMDThread, uTranslation; type TUpdateMangaManagerThread = class; diff --git a/baseunits/utranslation.pas b/baseunits/utranslation.pas index 9bac7ef1e..abd96361d 100644 --- a/baseunits/utranslation.pas +++ b/baseunits/utranslation.pas @@ -25,8 +25,8 @@ interface uses - Classes, SysUtils, strutils, gettext, FileUtil, LCLTranslator, Translations, - LResources, Forms; + Classes, SysUtils, strutils, gettext, LazFileUtils, LazUTF8, + LCLTranslator, Translations, LResources, Forms; type TLanguageItem = record diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 5a822bb98..15ee8460e 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -37,7 +37,7 @@ TFormDropTarget = class(TForm, IDropTarget) // IDropTarget function DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; - function DragOver(grfKeyState: DWORD; pt: TPoint; + function {%H-}DragOver(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; function DragLeave: HResult; stdcall; function Drop(const dataObj: IDataObject; grfKeyState: DWORD; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b2f486375..8f8ebd26e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -19,7 +19,7 @@ interface Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, - LazUTF8, FileUtil, TAGraph, TASources, TASeries, AnimatedGif, + FileUtil, TAGraph, TASources, TASeries, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, USimpleException, USimpleLogger; @@ -707,7 +707,7 @@ implementation {$R *.lfm} uses - frmImportFavorites, RegExpr, Clipbrd, LazFileUtils; + frmImportFavorites, RegExpr, Clipbrd, LazFileUtils, LazUTF8; { TMainForm } From 444f39f51c523a6ef657ceef739be16c7706ceff Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 19:05:20 +0800 Subject: [PATCH 0015/2794] restore missing tachartlazaruspkg --- mangadownloader/md.lpr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 3bcb444a9..cbba90ab0 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -14,7 +14,7 @@ cthreads, {$ENDIF} {$ENDIF} - Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, + Forms, LazFileUtils, TAChartLazarusPkg, Interfaces, simpleipc, IniFiles, uBaseUnit, frmMain; var From 23a77d013885136029e8763df5b881dd6159f3ac Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 19:10:43 +0800 Subject: [PATCH 0016/2794] add space between transfer rate graph and download toolbar --- mangadownloader/forms/frmMain.lfm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index de98f3645..4a9c3c994 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -140,10 +140,10 @@ object MainForm: TMainForm ClientWidth = 600 TabOrder = 1 object TransferRateGraph: TChart - Left = 321 + Left = 323 Height = 26 Top = 0 - Width = 279 + Width = 277 AllowZoom = False AxisList = < item @@ -201,12 +201,12 @@ object MainForm: TMainForm Left = 0 Height = 28 Top = 0 - Width = 321 + Width = 323 Align = alLeft AutoSize = True BevelOuter = bvNone ClientHeight = 28 - ClientWidth = 321 + ClientWidth = 323 TabOrder = 1 object ToolBarDownload: TToolBar Left = 0 @@ -214,6 +214,7 @@ object MainForm: TMainForm Top = 0 Width = 321 AutoSize = True + BorderSpacing.Right = 2 ButtonHeight = 25 EdgeBorders = [] Images = IconList From 88af64582f610e2fa24996e63d44289f97964075 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 19:24:51 +0800 Subject: [PATCH 0017/2794] mainform, adapt vtmangalist to tdbdataprocess --- mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.pas | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 4a9c3c994..9c2a68706 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3135,7 +3135,6 @@ object MainForm: TMainForm OnDragOver = vtMangaListDragOver OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint - OnGetNodeDataSize = vtMangaListGetNodeDataSize end object edSearch: TEdit Left = 3 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8f8ebd26e..ecd3e105c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -499,8 +499,6 @@ TMainForm = class(TForm) procedure vtMangaListDragOver(Sender : TBaseVirtualTree; Source : TObject; Shift : TShiftState; State : TDragState; const Pt : TPoint; Mode : TDropMode; var Effect : LongWord; var Accept : Boolean); - procedure vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -3808,13 +3806,6 @@ procedure TMainForm.vtMangaListDragOver(Sender : TBaseVirtualTree; Accept := False; end; -procedure TMainForm.vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - Exit; - NodeDataSize := SizeOf(PMangaListItem); -end; - // options procedure TMainForm.btOptionApplyClick(Sender: TObject); @@ -4044,7 +4035,6 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin - Exit; if (isExiting) or (dataProcess.DataCount = 0) then Exit; if miHighlightNewManga.Checked then From 180d9c94322033a11ea3ebecc18a94f8f1bce288 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 19:36:41 +0800 Subject: [PATCH 0018/2794] clear mangalist before filter --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ecd3e105c..3ca05e589 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2135,6 +2135,7 @@ procedure TMainForm.btFilterClick(Sender: TObject); dataProcess.FilterAllSites := True; end; + vtMangaList.Clear; if dataProcess.Filter(checkGenres, uncheckGenres, edFilterTitle.Text, edFilterAuthors.Text, edFilterArtists.Text, IntToStr(cbFilterStatus.ItemIndex), @@ -2143,7 +2144,6 @@ procedure TMainForm.btFilterClick(Sender: TObject); rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked) then begin lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.DataCount]); - vtMangaList.Clear; vtMangaList.RootNodeCount := dataProcess.DataCount; end; except From 4e6e2dcbfc48ed01fbebaa6aa2e842d4056cc65d Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 19:52:31 +0800 Subject: [PATCH 0019/2794] clear mangalist before removefilter --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3ca05e589..fe1ac796a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2050,6 +2050,7 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); begin if dataProcess.Filtered then begin + vtMangaList.Clear; Screen.Cursor := crHourGlass; try dataProcess.RemoveFilter; @@ -2060,7 +2061,6 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); dataProcess := TDBDataProcess.Create; dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); end; - vtMangaList.Clear; vtMangaList.RootNodeCount := dataProcess.DataCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); edSearch.Text := ''; From 3623026b5ada45147d3349414dc193dbbb5c36d7 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 19:53:12 +0800 Subject: [PATCH 0020/2794] tdbdataprocess, filter jdn --- baseunits/uData.pas | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2c67a65fc..0a73252af 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -576,17 +576,28 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean): Boolean; + + procedure AddSQL(const S: string); + begin + if FQuery.SQL.Count > 0 then + FQuery.SQL.Add('AND'); + FQuery.SQL.Add(S); + end; + begin Result := False; + if FConn.Connected = False then Exit; with FQuery do begin + FDataCount := 0; Close; try SQL.Clear; - SQL.Add(FSQLSelect); - SQL.Add('WHERE'); if searchNewManga then - SQL.Add('jdn > ' + QuotedStrd(DateToJDN(IncDay(Now, (0-minusDay))))); + AddSQL('jdn > ' + QuotedStrd(DateToJDN(IncDay(Now, (0-minusDay))))); + if Trim(SQL.Text) <> '' then + SQL.Insert(0, 'WHERE'); + SQL.Insert(0, FSQLSelect); Open; FFiltered := Active; except @@ -600,6 +611,7 @@ function TDBDataProcess.Filter(const checkedGenres, FFiltered := False; end; end; + GetDataCount; Result := FFiltered; end; end; @@ -607,6 +619,8 @@ function TDBDataProcess.Filter(const checkedGenres, procedure TDBDataProcess.RemoveFilter; begin FFiltered := False; + OpenTable; + GetDataCount; end; procedure TDBDataProcess.Sort; From bac111554562f98b55ef707fda0af75e1e2c64ad Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 20:14:40 +0800 Subject: [PATCH 0021/2794] remove sync data don't need to fill empty information from other data, because it's not valid anyway --- baseunits/uUpdateThread.pas | 127 ++++-------------------------------- 1 file changed, 14 insertions(+), 113 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 88cc4226d..6e07f2d22 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -56,7 +56,7 @@ TUpdateMangaManagerThread = class(TFMDThread) public CS_AddInfoToData, CS_AddNamesAndLinks: TCriticalSection; isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; - mainDataProcess, syncProcess: TDataProcess; + mainDataProcess: TDataProcess; names, links, websites, dataLinks: TStringList; website: String; workPtr, directoryCount, @@ -301,7 +301,6 @@ constructor TUpdateMangaManagerThread.Create; dataLinks := TStringList.Create; mainDataProcess := TDataProcess.Create; - syncProcess := TDataProcess.Create; threads := TFPList.Create; end; @@ -313,7 +312,6 @@ destructor TUpdateMangaManagerThread.Destroy; links.Free; dataLinks.Free; mainDataProcess.Free; - syncProcess.Free; threads.Free; {$IFDEF DOWNLOADER} MainForm.isUpdating := False; @@ -342,17 +340,20 @@ procedure TUpdateMangaManagerThread.RefreshList; begin {$IFDEF DOWNLOADER} try - if MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex] = website then + with MainForm do begin - Screen.Cursor := crHourGlass; - MainForm.edSearch.Clear; - MainForm.dataProcess.RemoveFilter; - MainForm.dataProcess.Refresh; - MainForm.vtMangaList.Clear; - MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; - MainForm.lbMode.Caption := - Format(RS_ModeAll, [MainForm.dataProcess.DataCount]); - Screen.Cursor := crDefault; + if cbSelectManga.Items[cbSelectManga.ItemIndex] = website then + begin + Screen.Cursor := crHourGlass; + edSearch.Clear; + vtMangaList.Clear; + if dataProcess = nil then + dataProcess := TDBDataProcess.Create; + dataProcess.Open(website); + vtMangaList.RootNodeCount := dataProcess.DataCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + Screen.Cursor := crDefault; + end; end; except on E: Exception do @@ -785,106 +786,6 @@ procedure TUpdateMangaManagerThread.Execute; WaitForThreads; names.Clear; links.Clear; - - // sync data based on existing sites - if (mainDataProcess.Data.Count > 0) and - (SitesWithoutInformation(website)) and - (FileExistsUTF8(DATA_FOLDER + WebsiteRoots[BATOTO_ID, 0] + DATA_EXT) or - FileExistsUTF8(DATA_FOLDER + WebsiteRoots[ANIMEA_ID, 0] + DATA_EXT) or - FileExistsUTF8(DATA_FOLDER + WebsiteRoots[MANGAGO_ID, 0] + DATA_EXT) or - FileExistsUTF8(DATA_FOLDER + WebsiteRoots[MANGAPARK_ID, 0] + DATA_EXT)) - then - begin - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SynchronizingData + '...'; - Synchronize(MainThreadShowGetting); - - syncProcess.Clear; - if FileExistsUTF8(DATA_FOLDER + WebsiteRoots[GetMangaSiteID(website), 0] + DATA_EXT) then - syncProcess.LoadFromFile(website); - - //remove existed data - if syncProcess.Data.Count > 0 then - begin - j := 0; - while j < mainDataProcess.Link.Count do - begin - if Terminated then - Break; - del := False; - for k := 0 to syncProcess.Link.Count - 1 do - begin - if Terminated then - Break; - if SameText(mainDataProcess.Link[j], syncProcess.Link[k]) then - begin - mainDataProcess.Title.Delete(j); - mainDataProcess.Link.Delete(j); - mainDataProcess.Data.Delete(j); - del := True; - Break; - end; - end; - if not del then - Inc(j); - end; - end; - - syncProcess.Clear; - if mainDataProcess.Link.Count > 0 then - begin - if FileExistsUTF8(DATA_FOLDER + WebsiteRoots[BATOTO_ID, 0] + DATA_EXT) then - syncProcess.LoadFromFile(WebsiteRoots[BATOTO_ID, 0]) - else - if FileExistsUTF8(DATA_FOLDER + WebsiteRoots[ANIMEA_ID, 0] + DATA_EXT) then - syncProcess.LoadFromFile(WebsiteRoots[ANIMEA_ID, 0]) - else - if FileExistsUTF8(DATA_FOLDER + WebsiteRoots[MANGAGO_ID, 0] + DATA_EXT) then - syncProcess.LoadFromFile(WebsiteRoots[MANGAGO_ID, 0]) - else - if FileExistsUTF8(DATA_FOLDER + WebsiteRoots[MANGAPARK_ID, 0] + DATA_EXT) then - syncProcess.LoadFromFile(WebsiteRoots[MANGAPARK_ID, 0]); - - // brute force ... - if syncProcess.Link.Count > 0 then - begin - for k := 0 to mainDataProcess.Data.Count - 1 do - begin - if Terminated then - Break; - for j := 0 to syncProcess.Link.Count - 1 do - begin - if Terminated then - Break; - if SameText(mainDataProcess.Title[k], syncProcess.Title[j]) then - begin - s := syncProcess.Param[j, DATA_PARAM_SUMMARY]; - mainDataProcess.Data.Strings[k] := RemoveBreaks( - mainDataProcess.Param[k, DATA_PARAM_NAME] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_LINK] + SEPERATOR + - syncProcess.Param[j, DATA_PARAM_AUTHORS] + SEPERATOR + - syncProcess.Param[j, DATA_PARAM_ARTISTS] + SEPERATOR + - syncProcess.Param[j, DATA_PARAM_GENRES] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_STATUS] + SEPERATOR + - s + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_NUMCHAPTER] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_JDN] + SEPERATOR); - Break; - end; - end; - end; - end; - syncProcess.Clear; - // add back existing data - if FileExistsUTF8(DATA_FOLDER + WebsiteRoots[GetMangaSiteID(website), 0] + DATA_EXT) then - begin - syncProcess.LoadFromFile(website); - if syncProcess.Data.Count > 0 then - mainDataProcess.Data.AddStrings(syncProcess.Data); - syncProcess.Clear; - end; - end; - end; end; if (not Terminated) or (not SitesWithSortedList(website)) then From c999976e7216b8e6ec999b7026045b960d0a5794 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 20:22:32 +0800 Subject: [PATCH 0022/2794] remove unused ifdef I don't know what ifndef downloader for, maybe for creating mangalist from scratch from other app which I don't have the source. And since current fmd can build mangalist from scratch by itself, we don't need it anymore. --- baseunits/uUpdateThread.pas | 79 ++----------------------------------- 1 file changed, 4 insertions(+), 75 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 6e07f2d22..97c356311 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -7,7 +7,6 @@ unit uUpdateThread; {$mode delphi} -{$DEFINE DOWNLOADER} interface @@ -87,12 +86,7 @@ TUpdateMangaManagerThread = class(TFMDThread) implementation uses - {$IFDEF DOWNLOADER} - frmMain, - {$ELSE} - mainunit, - {$ENDIF} - Dialogs, ComCtrls, Forms, Controls; + frmMain, Dialogs, ComCtrls, Forms, Controls; // ----- TUpdateMangaThread ----- @@ -187,14 +181,12 @@ procedure TUpdateMangaThread.Execute; //Synchronize(MainThreadUpdateNamesAndLinks); // For Fakku and Pururin only, reduce the number of page we have to visit // in order to search for new series. - {$IFDEF DOWNLOADER} if SitesWithSortedList(manager.website) then begin if links.Count > 0 then if manager.dataLinks.Find(links.Strings[0], iPos) then manager.isFinishSearchingForNewManga := True; end; - {$ENDIF} //**removing hostname in links RemoveHostFromURLs(links); @@ -214,11 +206,8 @@ procedure TUpdateMangaThread.Execute; CS_INFO: begin Info.mangaInfo.title := manager.names[workPtr]; - {$IFDEF DOWNLOADER} - Info.GetInfoFromURL(manager.website, manager.links[workPtr], 5); - {$ELSE} - Info.GetInfoFromURL(manager.website, manager.links[workPtr], 0); - {$ENDIF} + Info.GetInfoFromURL(manager.website, manager.links[workPtr], + MainForm.DLManager.retryConnect); if not Terminated then begin manager.CS_AddInfoToData.Acquire; @@ -259,11 +248,10 @@ procedure TUpdateMangaThread.DoTerminate; inherited DoTerminate; end; -// ----- TUpdateMangaManagerThread ----- +{ TUpdateMangaManagerThread } procedure TUpdateMangaManagerThread.MainThreadShowGetting; begin - {$IFDEF DOWNLOADER} if MainForm.sbUpdateList.Visible = False then begin //statusbar reordering based on who's show up first? @@ -276,7 +264,6 @@ procedure TUpdateMangaManagerThread.MainThreadShowGetting; end; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; MainForm.sbUpdateList.Panels[0].Text := FStatus; - {$ENDIF} end; procedure TUpdateMangaManagerThread.MainThreadEndGetting; @@ -313,32 +300,15 @@ destructor TUpdateMangaManagerThread.Destroy; dataLinks.Free; mainDataProcess.Free; threads.Free; - {$IFDEF DOWNLOADER} MainForm.isUpdating := False; - {$ENDIF} CS_AddInfoToData.Free; CS_AddNamesAndLinks.Free; CS_threads.Free; inherited Destroy; end; -{$IFNDEF DOWNLOADER} -procedure TUpdateMangaManagerThread.ConsoleReport; -begin - MainForm.Memo1.Lines.Add(S); -end; - -procedure TUpdateMangaManagerThread.SaveCurrentDatabase; -begin - mainDataProcess.SaveToFile(website); - MainForm.Memo1.Lines.Clear; -end; - -{$ENDIF} - procedure TUpdateMangaManagerThread.RefreshList; begin - {$IFDEF DOWNLOADER} try with MainForm do begin @@ -359,7 +329,6 @@ procedure TUpdateMangaManagerThread.RefreshList; on E: Exception do MainForm.ExceptionHandler(Self, E); end; - {$ENDIF} end; procedure TUpdateMangaManagerThread.DlgReport; @@ -426,7 +395,6 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Cardinal; numberOfThreads := 1; //default // Finish searching for new series - {$IFDEF DOWNLOADER} if ((cs = CS_DIRECTORY_PAGE) or (cs = CS_DIRECTORY_PAGE_2)) and (isFinishSearchingForNewManga) then begin @@ -434,7 +402,6 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Cardinal; workPtr := limit; Break; end; - {$ENDIF} while threads.Count >= numberOfThreads do begin @@ -477,15 +444,8 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Cardinal; s := s + ' | ' + RS_GettingInfo + ' "' + names.Strings[workPtr - 1] + '" "' + WebsiteRoots[GetMangaSiteID(website), 1] + links.Strings[workPtr - 1] + '"'; - {$IFNDEF DOWNLOADER} - Synchronize(ConsoleReport); - if (workPtr mod 100 = 0) and (workPtr > 50) and (cs = CS_INFO) and - (mainDataProcess.Data.Count > 5) then - Synchronize(SaveCurrentDatabase); - {$ELSE} FStatus := s; Synchronize(MainThreadShowGetting); - {$ENDIF} finally CS_threads.Release; end; @@ -529,7 +489,6 @@ procedure TUpdateMangaManagerThread.Execute; Exit; try websitePtr := 0; - {$IFDEF DOWNLOADER} if isDownloadFromServer then begin while websitePtr < websites.Count do @@ -544,7 +503,6 @@ procedure TUpdateMangaManagerThread.Execute; end; end else - {$ENDIF} while websitePtr < websites.Count do begin website := websites.Strings[websitePtr]; @@ -736,7 +694,6 @@ procedure TUpdateMangaManagerThread.Execute; end; end; - //get manga info if links.Count > 0 then begin @@ -747,7 +704,6 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.Link.AddStrings(links); for k := 0 to links.Count - 1 do begin - {$IFDEF DOWNLOADER} mainDataProcess.Data.Add( RemoveStringBreaks( SetParams( @@ -761,21 +717,6 @@ procedure TUpdateMangaManagerThread.Execute; '0', IntToStr(GetCurrentJDN), '0']))); - {$ELSE} - mainDataProcess.Data.Add( - RemoveStringBreaks( - SetParams( - [names.Strings[k], - links.Strings[k], - '', - '', - '', - '', - '', - '0', - '0', - '0']))); - {$ENDIF} end; end else @@ -797,24 +738,12 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.Sort; mainDataProcess.SaveToFile(website); end; - {$IFDEF DOWNLOADER} Synchronize(RefreshList); - {$ENDIF} if Terminated then Break; websites[websitePtr - 1] := UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); end; - {$IFNDEF DOWNLOADER} - S := 'Saving to ' + website + '.dat ...'; - Synchronize(ConsoleReport); - S := 'Done.'; - Synchronize(ConsoleReport); - {$ELSE} - // Synchronize(DlgReport); - //Synchronize(MainThreadEndGetting); - {$ENDIF} - // Synchronize(DlgReport); except on E: Exception do MainForm.ExceptionHandler(Self, E); From 37ce206d47b4e7058cd5ff670624112811b47cde Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 21:31:14 +0800 Subject: [PATCH 0023/2794] tmangainformation, overload addinfotodata with tdbdataprocess --- baseunits/uData.pas | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0a73252af..0bb40a718 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -165,8 +165,9 @@ TMangaInformation = class(TObject) procedure AddInfoToDataWithoutBreak(const Name, link: String; const DataProcess: TDataProcess); // Only use this function for update manga list - procedure AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); - + procedure AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); overload; + // to add data to TDBDataProcess + procedure AddInfoToData(const Title, Link: string; const DataProcess: TDBDataProcess); overload; //wrapper function GetPage(var output: TObject; URL: String; const Reconnect: Cardinal): Boolean; overload; end; @@ -2683,6 +2684,21 @@ procedure TMangaInformation.AddInfoToData(const Name, link: String; l.Free; end; +procedure TMangaInformation.AddInfoToData(const Title, Link: string; + const DataProcess: TDBDataProcess); +begin + if Assigned(DataProcess) then + begin + if Title <> '' then + mangaInfo.title := Title; + if Link <> '' then + mangaInfo.link := Link; + with mangaInfo do + DataProcess.AddData(title, link, authors, artists, genres, status, + StringBreaks(summary), numChapter, DateToJDN(Now)); + end; +end; + function TMangaInformation.GetPage(var output: TObject; URL: String; const Reconnect: Cardinal): Boolean; begin From 1e12d1a1456bc0c243758a27170c5386d16459b5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 21:34:41 +0800 Subject: [PATCH 0024/2794] tmangainformation, addinfotodata use tdatetime parameter --- baseunits/uData.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0bb40a718..cd82caf7b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -69,6 +69,7 @@ TDBDataProcess = class const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; + function Locate(FieldIndex: Integer; Value: String): Boolean; procedure RemoveFilter; procedure Sort; property Website: String read FWebsite write FWebsite; @@ -2695,7 +2696,7 @@ procedure TMangaInformation.AddInfoToData(const Title, Link: string; mangaInfo.link := Link; with mangaInfo do DataProcess.AddData(title, link, authors, artists, genres, status, - StringBreaks(summary), numChapter, DateToJDN(Now)); + StringBreaks(summary), numChapter, Now); end; end; From 1235a46dc0323c45477ed6e20bbb3450b34250be Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 21:41:08 +0800 Subject: [PATCH 0025/2794] tdbdataprocess, add locate function with critical section --- baseunits/uData.pas | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index cd82caf7b..991299fdf 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, LazFileUtils, sqlite3conn, sqldb, - USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; + db, USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; type @@ -28,6 +28,7 @@ TSQLite3Connectionx = class(TSQLite3Connection) TDBDataProcess = class private + FCSRecord: TRTLCriticalSection; FConn: TSQLite3Connectionx; FTrans: TSQLTransaction; FQuery: TSQLQuery; @@ -382,6 +383,7 @@ function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; constructor TDBDataProcess.Create; begin + InitCriticalSection(FCSRecord); FConn := TSQLite3Connectionx.Create(nil); FTrans := TSQLTransaction.Create(nil); FQuery := TSQLQuery.Create(nil); @@ -411,6 +413,7 @@ destructor TDBDataProcess.Destroy; FTrans.Free; FConn.Free; FRegxp.Free; + DoneCriticalsection(FCSRecord); inherited Destroy; end; @@ -618,6 +621,20 @@ function TDBDataProcess.Filter(const checkedGenres, end; end; +function TDBDataProcess.Locate(FieldIndex: Integer; Value: String): Boolean; +begin + Result := false; + if FQuery.Active then + begin + EnterCriticalsection(FCSRecord); + try + Result := FQuery.Locate(DBDataProcessParams[FieldIndex], Value, [loCaseInsensitive]); + finally + LeaveCriticalsection(FCSRecord); + end; + end; +end; + procedure TDBDataProcess.RemoveFilter; begin FFiltered := False; From adad00fa7d0facd9c6f7a417258b341f6bc31413 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 21:42:32 +0800 Subject: [PATCH 0026/2794] tdbdataprocess, getparam using critical section --- baseunits/uData.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 991299fdf..984cbfd71 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -370,6 +370,7 @@ function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; (ParamNo < Length(DBDataProcessParams)) and (RecIndex < FDataCount) then begin + EnterCriticalsection(FCSRecord); try FQuery.RecNo := RecIndex+1; Result:= FQuery.FieldByName(DBDataProcessParams[ParamNo]).AsString; @@ -378,6 +379,7 @@ function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; WriteLog_E('TDBDataProcess.GetParam.Error: ' + E.Message + LineEnding + GetStackTraceInfo); end; + LeaveCriticalsection(FCSRecord); end; end; From 18b779d257cb2a81b33caecf01efcdfce3d452a0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 21:43:18 +0800 Subject: [PATCH 0027/2794] updatethread, change to tdbdataprocess clean up some code to adapt to tdbdataprocess --- baseunits/uUpdateThread.pas | 131 ++++++------------------------------ 1 file changed, 19 insertions(+), 112 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 97c356311..718bad5ae 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -55,8 +55,8 @@ TUpdateMangaManagerThread = class(TFMDThread) public CS_AddInfoToData, CS_AddNamesAndLinks: TCriticalSection; isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; - mainDataProcess: TDataProcess; - names, links, websites, dataLinks: TStringList; + mainDataProcess: TDBDataProcess; + names, links, websites: TStringList; website: String; workPtr, directoryCount, // for fakku's doujinshi only @@ -184,7 +184,7 @@ procedure TUpdateMangaThread.Execute; if SitesWithSortedList(manager.website) then begin if links.Count > 0 then - if manager.dataLinks.Find(links.Strings[0], iPos) then + if manager.mainDataProcess.Locate(DATA_PARAM_LINK, links.Strings[0]) then manager.isFinishSearchingForNewManga := True; end; @@ -212,8 +212,8 @@ procedure TUpdateMangaThread.Execute; begin manager.CS_AddInfoToData.Acquire; try - Info.AddInfoToDataWithoutBreak(manager.names[workPtr], - manager.links[workPtr], manager.mainDataProcess); + Info.AddInfoToData(manager.names[workPtr], manager.links[workPtr], + manager.mainDataProcess); finally manager.CS_AddInfoToData.Release; end; @@ -285,9 +285,8 @@ constructor TUpdateMangaManagerThread.Create; websites := TStringList.Create; names := TStringList.Create; links := TStringList.Create; - dataLinks := TStringList.Create; - mainDataProcess := TDataProcess.Create; + mainDataProcess := TDBDataProcess.Create; threads := TFPList.Create; end; @@ -297,7 +296,6 @@ destructor TUpdateMangaManagerThread.Destroy; websites.Free; names.Free; links.Free; - dataLinks.Free; mainDataProcess.Free; threads.Free; MainForm.isUpdating := False; @@ -511,48 +509,8 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); - mainDataProcess.Clear; - mainDataProcess.LoadFromFile(website); - - //Sort first for faster searching - dataLinks.Assign(mainDataProcess.Link); - dataLinks.Sort; - - // convert old data - if (mainDataProcess.Link.Count > 0) and - (website = WebsiteRoots[MANGAFOX_ID, 0]) then - begin - purg := False; - s := WebsiteRoots[GetMangaSiteID(website), 1]; - if dataLinks.Find(s, iPos) then - purg := True; - if purg then - begin - for k := 0 to mainDataProcess.Link.Count - 1 do - begin - if Pos(s, mainDataProcess.Link[k]) > 0 then - begin - mainDataProcess.Link[k] := - StringReplace(mainDataProcess.Link[k], s, '', [rfIgnoreCase]); - - mainDataProcess.Data[k] := RemoveStringBreaks( - mainDataProcess.Param[k, DATA_PARAM_NAME] + SEPERATOR + - mainDataProcess.Link[k] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_AUTHORS] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_ARTISTS] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_GENRES] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_STATUS] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_SUMMARY] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_NUMCHAPTER] + SEPERATOR + - mainDataProcess.Param[k, DATA_PARAM_JDN] + SEPERATOR); - end; - end; - mainDataProcess.SaveToFile(website); - dataLinks.Assign(mainDataProcess.Link); - dataLinks.Sort; - end; - mainDataProcess.Clear; - end; + mainDataProcess.Close; + mainDataProcess.Open(website); names.Clear; links.Clear; @@ -589,17 +547,6 @@ procedure TUpdateMangaManagerThread.Execute; if Terminated then Break; - {$IFNDEF DOWNLOADER} - names.SaveToFile(website + '_names.txt'); - links.SaveToFile(website + '_links.txt'); - - names.Clear; - links.Clear; - - names.LoadFromFile(website + '_names.txt'); - links.LoadFromFile(website + '_links.txt'); - {$ENDIF} - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; Synchronize(MainThreadShowGetting); @@ -621,7 +568,7 @@ procedure TUpdateMangaManagerThread.Execute; begin if Terminated then Break; - if SameText(links.Strings[j], links.Strings[k]) then + if SameText(links[j], links[k]) then begin links.Delete(j); names.Delete(j); @@ -645,7 +592,7 @@ procedure TUpdateMangaManagerThread.Execute; begin if Terminated then Break; - if dataLinks.Find(links[j], integer(workPtr)) then + if mainDataProcess.Locate(DATA_PARAM_LINK, links[j]) then begin links.Delete(j); names.Delete(j); @@ -654,45 +601,9 @@ procedure TUpdateMangaManagerThread.Execute; Inc(j); end; end; - dataLinks.Clear; - - mainDataProcess.Clear; - mainDataProcess.LoadFromFile(website); - if OptionUpdateListRemoveDuplicateLocalData then - begin - FStatus := RS_UpdatingList + Format(' [ %d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromLocalData + '...'; - Synchronize(MainThreadShowGetting); - if mainDataProcess.Link.Count > 0 then - begin - j := 0; - while j < (mainDataProcess.Link.Count - 1) do - begin - if Terminated then - Break; - del := False; - if (j + 1) < mainDataProcess.Link.Count then - for k := j + 1 to mainDataProcess.Link.Count - 1 do - begin - if Terminated then - Break; - - if SameText(mainDataProcess.Link.Strings[j], - mainDataProcess.Link.Strings[k]) then - begin - mainDataProcess.Link.Delete(j); - mainDataProcess.Title.Delete(j); - mainDataProcess.Data.Delete(j); - del := True; - Break; - end; - end; - if not del then - Inc(j); - end; - end; - end; + mainDataProcess.Close; + mainDataProcess.Open(website); //get manga info if links.Count > 0 then @@ -700,23 +611,19 @@ procedure TUpdateMangaManagerThread.Execute; if (SitesWithoutInformation(website)) or OptionUpdateListNoMangaInfo then begin - mainDataProcess.Title.AddStrings(names); - mainDataProcess.Link.AddStrings(links); for k := 0 to links.Count - 1 do begin - mainDataProcess.Data.Add( - RemoveStringBreaks( - SetParams( - [names.Strings[k], - links.Strings[k], + mainDataProcess.AddData( + names[k], + links[k], '', '', '', '', '', - '0', - IntToStr(GetCurrentJDN), - '0']))); + 0, + Now + ); end; end else @@ -736,7 +643,7 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(MainThreadShowGetting); { TODO -ocholif : Sort after update } mainDataProcess.Sort; - mainDataProcess.SaveToFile(website); + mainDataProcess.Save; end; Synchronize(RefreshList); if Terminated then From 954a9a7d1514cbe253a77c350a4b76b2cad054fe Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 22:17:32 +0800 Subject: [PATCH 0028/2794] tdbdataprocess, add createdatabase and change datatype to string --- baseunits/uData.pas | 50 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 984cbfd71..0b1287346 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -54,14 +54,6 @@ TDBDataProcess = class function Open(AWebsite: String = ''): Boolean; function OpenTable(const ATableName: String = ''): Boolean; function TableExist(const ATableName: String): Boolean; - procedure Close; - procedure Save; - procedure Refresh; - procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter, JDN: Integer); overload; - procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer; JDN: TDateTime); overload; - procedure ApplyUpdates; function Search(ATitle: String): Boolean; function CanFilter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; @@ -71,6 +63,15 @@ TDBDataProcess = class const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; function Locate(FieldIndex: Integer; Value: String): Boolean; + procedure CreateDatabase(AWebsite: string = ''); + procedure Close; + procedure Save; + procedure Refresh; + procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter, JDN: Integer); overload; + procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter: Integer; JDN: TDateTime); overload; + procedure ApplyUpdates; procedure RemoveFilter; procedure Sort; property Website: String read FWebsite write FWebsite; @@ -181,13 +182,13 @@ TMangaInformation = class(TObject) DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; DBDataProcessParams: array [0..8] of ShortString = ('title', 'link', 'authors', 'artists', 'genres', 'status', 'summary', 'numchapter', 'jdn'); - DBDataProccesCreateParam = '(title TEXT,'+ - 'link TEXT NOT NULL PRIMARY KEY,'+ - 'authors TEXT,'+ - 'artists TEXT,'+ - 'genres TEXT,'+ - 'status TEXT,'+ - 'summary TEXT,'+ + DBDataProccesCreateParam = '(title STRING,'+ + 'link STRING NOT NULL PRIMARY KEY,'+ + 'authors STRING,'+ + 'artists STRING,'+ + 'genres STRING,'+ + 'status STRING,'+ + 'summary STRING,'+ 'numchapter INTEGER,'+ 'jdn INTEGER);'; @@ -262,8 +263,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); if FileExistsUTF8(filepath + DBDATA_EXT) then DeleteFileUTF8(filepath + DBDATA_EXT); rawdata.LoadFromFile(AWebsite); - dbdata.InternalOpen(filepath + DBDATA_EXT); - dbdata.CreateTable; + dbdata.CreateDatabase(AWebsite); if rawdata.Data.Count > 0 then with rawdata do begin @@ -626,7 +626,7 @@ function TDBDataProcess.Filter(const checkedGenres, function TDBDataProcess.Locate(FieldIndex: Integer; Value: String): Boolean; begin Result := false; - if FQuery.Active then + if (FQuery.Active) and (FDataCount > 0) then begin EnterCriticalsection(FCSRecord); try @@ -637,6 +637,20 @@ function TDBDataProcess.Locate(FieldIndex: Integer; Value: String): Boolean; end; end; +procedure TDBDataProcess.CreateDatabase(AWebsite: string); +var + filepath: string; +begin + if AWebsite <> '' then + FWebsite := AWebsite; + if FWebsite = '' then Exit; + filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + if FileExistsUTF8(filepath) then + DeleteFileUTF8(filepath); + InternalOpen(filepath); + CreateTable; +end; + procedure TDBDataProcess.RemoveFilter; begin FFiltered := False; From 23c9d8df7b46a74d189b32274d7b3487f339021c Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 22:19:22 +0800 Subject: [PATCH 0029/2794] updatethread, createdatabase if file doesn't exist --- baseunits/uUpdateThread.pas | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 718bad5ae..2eb2c36a6 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -86,7 +86,7 @@ TUpdateMangaManagerThread = class(TFMDThread) implementation uses - frmMain, Dialogs, ComCtrls, Forms, Controls; + frmMain, Dialogs, ComCtrls, Forms, Controls, USimpleLogger; // ----- TUpdateMangaThread ----- @@ -509,8 +509,11 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); - mainDataProcess.Close; - mainDataProcess.Open(website); + if not mainDataProcess.Open(website) then + begin + mainDataProcess.CreateDatabase(website); + mainDataProcess.OpenTable; + end; names.Clear; links.Clear; @@ -602,9 +605,6 @@ procedure TUpdateMangaManagerThread.Execute; end; end; - mainDataProcess.Close; - mainDataProcess.Open(website); - //get manga info if links.Count > 0 then begin @@ -643,7 +643,7 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(MainThreadShowGetting); { TODO -ocholif : Sort after update } mainDataProcess.Sort; - mainDataProcess.Save; + mainDataProcess.Close; end; Synchronize(RefreshList); if Terminated then From 08b563e45e3b4b345426abfde26d13b2fadd5e8d Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 22:46:34 +0800 Subject: [PATCH 0030/2794] add fileutils for dbdataprocess --- baseunits/uData.pas | 35 ++++++++++++++++++++++++++++++++--- baseunits/uUpdateThread.pas | 18 +++++++++++++----- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0b1287346..ecf25f6ed 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,8 +14,8 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, LazFileUtils, sqlite3conn, sqldb, - db, USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; + Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, + sqldb, db, USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; type @@ -193,6 +193,9 @@ TMangaInformation = class(TObject) 'jdn INTEGER);'; procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); + function DBDataProcessExist(const AWebsite: string): Boolean; + procedure CopyDBDataProcess(const AWebsite, NWebsite: string); + procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); implementation @@ -286,6 +289,32 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); end; end; +function DBDataProcessExist(const AWebsite: string): Boolean; +begin + if AWebsite = '' then Exit(False); + Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); +end; + +procedure CopyDBDataProcess(const AWebsite, NWebsite: string); +begin + if DBDataProcessExist(AWebsite) then + begin + CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT); + end; +end; + +procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); +begin + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then + begin + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then + DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + RenameFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT); + end; +end; + { TDBDataProcess } procedure TDBDataProcess.CreateTable; @@ -488,11 +517,11 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; procedure TDBDataProcess.Close; begin - FQuery.Close; FFiltered := False; FDataCount := 0; if FConn.Connected then begin + FQuery.Close; FTrans.Commit; FTrans.Active := False; FConn.Connected := False; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 2eb2c36a6..b743bd67f 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -57,7 +57,7 @@ TUpdateMangaManagerThread = class(TFMDThread) isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; mainDataProcess: TDBDataProcess; names, links, websites: TStringList; - website: String; + website, twebsite: String; workPtr, directoryCount, // for fakku's doujinshi only directoryCount2, numberOfThreads, websitePtr: Cardinal; @@ -316,12 +316,17 @@ procedure TUpdateMangaManagerThread.RefreshList; edSearch.Clear; vtMangaList.Clear; if dataProcess = nil then - dataProcess := TDBDataProcess.Create; + dataProcess := TDBDataProcess.Create + else + dataProcess.Close; + OverwriteDBDataProcess(website, twebsite); dataProcess.Open(website); vtMangaList.RootNodeCount := dataProcess.DataCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); Screen.Cursor := crDefault; - end; + end + else + OverwriteDBDataProcess(website, twebsite); end; except on E: Exception do @@ -509,9 +514,12 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); - if not mainDataProcess.Open(website) then + twebsite := '__' + website; + CopyDBDataProcess(website, twebsite); + + if not mainDataProcess.Open(twebsite) then begin - mainDataProcess.CreateDatabase(website); + mainDataProcess.CreateDatabase(twebsite); mainDataProcess.OpenTable; end; From cb25397e9e4d19933237f63bc37d9ccb1d997ace Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 6 Jul 2015 23:24:37 +0800 Subject: [PATCH 0031/2794] alter copyfile with fmsharedenynone --- baseunits/uData.pas | 78 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index ecf25f6ed..1dcd2d5ea 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,8 +14,9 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, - sqldb, db, USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; + Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, + LazUTF8Classes, sqlite3conn, sqldb, db, USimpleLogger, strutils, dateutils, + RegExpr, sqlite3dyn, httpsend; type @@ -295,12 +296,83 @@ function DBDataProcessExist(const AWebsite: string): Boolean; Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; +function CopyFile(const SrcFilename, DestFilename: String; + Flags: TCopyFileFlags=[cffOverwriteFile]; ExceptionOnError: Boolean=False): Boolean; +var + SrcHandle: THandle; + DestHandle: THandle; + Buffer: array[1..4096] of byte; + ReadCount, WriteCount, TryCount: LongInt; +begin + Result := False; + // check overwrite + if (not (cffOverwriteFile in Flags)) and FileExistsUTF8(DestFileName) then + exit; + // check directory + if (cffCreateDestDirectory in Flags) + and (not DirectoryExistsUTF8(ExtractFilePath(DestFileName))) + and (not ForceDirectoriesUTF8(ExtractFilePath(DestFileName))) then + exit; + TryCount := 0; + While TryCount <> 3 Do Begin + SrcHandle := FileOpenUTF8(SrcFilename, fmOpenRead or fmShareDenyNone); + if (THandle(SrcHandle)=feInvalidHandle) then Begin + Inc(TryCount); + Sleep(10); + End + Else Begin + TryCount := 0; + Break; + End; + End; + If TryCount > 0 Then + begin + if ExceptionOnError then + raise EFOpenError.CreateFmt({SFOpenError}'Unable to open file "%s"', [SrcFilename]) + else + exit; + end; + try + DestHandle := FileCreateUTF8(DestFileName); + if (THandle(DestHandle)=feInvalidHandle) then + begin + if ExceptionOnError then + raise EFCreateError.CreateFmt({SFCreateError}'Unable to create file "%s"',[DestFileName]) + else + Exit; + end; + try + repeat + ReadCount:=FileRead(SrcHandle,Buffer[1],High(Buffer)); + if ReadCount<=0 then break; + WriteCount:=FileWrite(DestHandle,Buffer[1],ReadCount); + if WriteCount Date: Tue, 7 Jul 2015 00:13:47 +0800 Subject: [PATCH 0032/2794] updatethread, close active database, blocking mode --- baseunits/uData.pas | 30 ++++++++++++++++-------------- baseunits/uUpdateThread.pas | 12 ++++++++++++ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1dcd2d5ea..670b5e6d6 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,8 +15,8 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, - LazUTF8Classes, sqlite3conn, sqldb, db, USimpleLogger, strutils, dateutils, - RegExpr, sqlite3dyn, httpsend; + sqlite3conn, sqldb, db, USimpleLogger, strutils, dateutils, RegExpr, + sqlite3dyn, httpsend; type @@ -382,8 +382,8 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); begin if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - RenameFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT); + RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; end; @@ -503,15 +503,13 @@ constructor TDBDataProcess.Create; destructor TDBDataProcess.Destroy; begin - FSitesList.Free; - FQuery.Close; if FConn.Connected then begin FTrans.Commit; VacuumTable; + FConn.Connected := False; end; - FTrans.Active := False; - FConn.Connected := False; + FSitesList.Free; FQuery.Free; FTrans.Free; FConn.Free; @@ -591,12 +589,16 @@ procedure TDBDataProcess.Close; begin FFiltered := False; FDataCount := 0; - if FConn.Connected then - begin - FQuery.Close; - FTrans.Commit; - FTrans.Active := False; - FConn.Connected := False; + try + if FConn.Connected then + begin + FTrans.Commit; + FConn.Connected := False; + end; + except + on E: Exception do + WriteLog_E('TDBDataProcess.Close.Error: ' + E.Message + LineEnding + + GetStackTraceInfo); end; end; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index b743bd67f..30e07aa6c 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -514,6 +514,12 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); + if MainForm.cbSelectManga.Text = website then + begin + MainForm.vtMangaList.Clear; + MainForm.dataProcess.Close; + end; + twebsite := '__' + website; CopyDBDataProcess(website, twebsite); @@ -523,6 +529,12 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.OpenTable; end; + //if MainForm.cbSelectManga.Text = website then + //begin + // MainForm.dataProcess.Open; + // MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; + //end; + // names.Clear; links.Clear; From a889aab3252e8cc57ea5ca18e2d680fbe8db8b45 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 00:50:10 +0800 Subject: [PATCH 0033/2794] updatethread, blocking mode for selected website --- baseunits/uData.pas | 18 ++++++++++++++++++ baseunits/uUpdateThread.pas | 11 +++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 670b5e6d6..e23fe21ac 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -67,6 +67,7 @@ TDBDataProcess = class procedure CreateDatabase(AWebsite: string = ''); procedure Close; procedure Save; + procedure Backup(AWebsite: string); procedure Refresh; procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer); overload; @@ -370,9 +371,15 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: string); if NWebsite = '' then Exit; if DBDataProcessExist(AWebsite) then begin + try CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, [cffPreserveTime, cffOverwriteFile], True); + except + on E: Exception do + Writelog_D('CopyDBDataProcess.Error: ' + E.Message + LineEnding + + GetStackTraceInfo); + end; end; end; @@ -594,6 +601,7 @@ procedure TDBDataProcess.Close; begin FTrans.Commit; FConn.Connected := False; + FConn.DatabaseName := ''; end; except on E: Exception do @@ -607,6 +615,16 @@ procedure TDBDataProcess.Save; Self.ApplyUpdates; end; +procedure TDBDataProcess.Backup(AWebsite: string); +begin + if AWebsite = '' then Exit; + if FConn.Connected then + FConn.ExecuteDirect('END TRANSACTION'); + CopyDBDataProcess(FWebsite, AWebsite); + if FConn.Connected then + FConn.ExecuteDirect('BEGIN TRANSACTION'); +end; + procedure TDBDataProcess.Refresh; begin if FQuery.Active then diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 30e07aa6c..afdad15f9 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -319,6 +319,7 @@ procedure TUpdateMangaManagerThread.RefreshList; dataProcess := TDBDataProcess.Create else dataProcess.Close; + Sleep(500); OverwriteDBDataProcess(website, twebsite); dataProcess.Open(website); vtMangaList.RootNodeCount := dataProcess.DataCount; @@ -514,15 +515,17 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); - if MainForm.cbSelectManga.Text = website then + twebsite := '__' + website; + + if (MainForm.cbSelectManga.Text = website) and + (MainForm.dataProcess.Connected) then begin MainForm.vtMangaList.Clear; MainForm.dataProcess.Close; + Sleep(500); end; - twebsite := '__' + website; CopyDBDataProcess(website, twebsite); - if not mainDataProcess.Open(twebsite) then begin mainDataProcess.CreateDatabase(twebsite); @@ -534,7 +537,7 @@ procedure TUpdateMangaManagerThread.Execute; // MainForm.dataProcess.Open; // MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; //end; - // + names.Clear; links.Clear; From 704d4af9a04a5a39d8884173341368cb9feca57c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 12:36:36 +0800 Subject: [PATCH 0034/2794] tdbdataprocess, use sqlite3backup to backup from active database --- baseunits/uData.pas | 85 ++++++--------------------------------------- 1 file changed, 10 insertions(+), 75 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index e23fe21ac..6e7aca650 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,8 +14,8 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, - sqlite3conn, sqldb, db, USimpleLogger, strutils, dateutils, RegExpr, + Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, + sqlite3backup, sqldb, db, USimpleLogger, strutils, dateutils, RegExpr, sqlite3dyn, httpsend; type @@ -297,75 +297,6 @@ function DBDataProcessExist(const AWebsite: string): Boolean; Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; -function CopyFile(const SrcFilename, DestFilename: String; - Flags: TCopyFileFlags=[cffOverwriteFile]; ExceptionOnError: Boolean=False): Boolean; -var - SrcHandle: THandle; - DestHandle: THandle; - Buffer: array[1..4096] of byte; - ReadCount, WriteCount, TryCount: LongInt; -begin - Result := False; - // check overwrite - if (not (cffOverwriteFile in Flags)) and FileExistsUTF8(DestFileName) then - exit; - // check directory - if (cffCreateDestDirectory in Flags) - and (not DirectoryExistsUTF8(ExtractFilePath(DestFileName))) - and (not ForceDirectoriesUTF8(ExtractFilePath(DestFileName))) then - exit; - TryCount := 0; - While TryCount <> 3 Do Begin - SrcHandle := FileOpenUTF8(SrcFilename, fmOpenRead or fmShareDenyNone); - if (THandle(SrcHandle)=feInvalidHandle) then Begin - Inc(TryCount); - Sleep(10); - End - Else Begin - TryCount := 0; - Break; - End; - End; - If TryCount > 0 Then - begin - if ExceptionOnError then - raise EFOpenError.CreateFmt({SFOpenError}'Unable to open file "%s"', [SrcFilename]) - else - exit; - end; - try - DestHandle := FileCreateUTF8(DestFileName); - if (THandle(DestHandle)=feInvalidHandle) then - begin - if ExceptionOnError then - raise EFCreateError.CreateFmt({SFCreateError}'Unable to create file "%s"',[DestFileName]) - else - Exit; - end; - try - repeat - ReadCount:=FileRead(SrcHandle,Buffer[1],High(Buffer)); - if ReadCount<=0 then break; - WriteCount:=FileWrite(DestHandle,Buffer[1],ReadCount); - if WriteCount Date: Tue, 7 Jul 2015 12:37:04 +0800 Subject: [PATCH 0035/2794] updatethread, backup before update --- baseunits/uUpdateThread.pas | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index afdad15f9..09bd7c848 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -519,25 +519,16 @@ procedure TUpdateMangaManagerThread.Execute; if (MainForm.cbSelectManga.Text = website) and (MainForm.dataProcess.Connected) then - begin - MainForm.vtMangaList.Clear; - MainForm.dataProcess.Close; - Sleep(500); - end; + MainForm.dataProcess.Backup(twebsite) + else + CopyDBDataProcess(website, twebsite); - CopyDBDataProcess(website, twebsite); if not mainDataProcess.Open(twebsite) then begin mainDataProcess.CreateDatabase(twebsite); mainDataProcess.OpenTable; end; - //if MainForm.cbSelectManga.Text = website then - //begin - // MainForm.dataProcess.Open; - // MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; - //end; - names.Clear; links.Clear; @@ -655,8 +646,6 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(links.Count, CS_INFO); end; WaitForThreads; - names.Clear; - links.Clear; end; if (not Terminated) or (not SitesWithSortedList(website)) then @@ -664,7 +653,6 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); - { TODO -ocholif : Sort after update } mainDataProcess.Sort; mainDataProcess.Close; end; From ab7d81e6053caa3991dd53369bb16a7ac89ec14a Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 12:37:57 +0800 Subject: [PATCH 0036/2794] mainform, temporary disable filterallsites --- mangadownloader/forms/frmMain.lfm | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9c2a68706..045a35819 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1451,6 +1451,7 @@ object MainForm: TMainForm Width = 149 Caption = 'Search in all manga sites' TabOrder = 9 + Visible = False end object btFilter: TBitBtn Left = 39 From 384c9a06f9a7817e2dbba4bf100c23928d6a0425 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:00:32 +0800 Subject: [PATCH 0037/2794] tdbdataprocess, tmangainfo, add sync and fix backup --- baseunits/uData.pas | 108 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 12 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 6e7aca650..5b08b4409 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -68,12 +68,15 @@ TDBDataProcess = class procedure Close; procedure Save; procedure Backup(AWebsite: string); - procedure Refresh; + procedure Refresh(RecheckDataCount: Boolean = False); procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer); overload; procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; JDN: TDateTime); overload; - procedure ApplyUpdates; + procedure UpdateData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter: Integer); + procedure Commit; + procedure ApplyUpdates(RecheckDataCount: Boolean = False); procedure RemoveFilter; procedure Sort; property Website: String read FWebsite write FWebsite; @@ -162,7 +165,8 @@ TMangaInformation = class(TObject) function GetNameAndLink(const names, links: TStringList; const website, URL: String): Byte; function GetInfoFromURL(const website, URL: String; const Reconnect: Cardinal): Byte; - procedure SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); + procedure SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); overload; + procedure SyncInfoToData(const DataProcess: TDBDataProcess); overload; procedure SyncMinorInfoToData(const DataProcess: TDataProcess; const index: Cardinal); @@ -278,7 +282,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); Status[i], StringBreaks(Summary[i]), StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), {%H-}Integer(JDN[i])-3); end; - dbdata.ApplyUpdates; + dbdata.Commit; end; dbdata.OpenTable; dbdata.Sort; @@ -404,7 +408,10 @@ function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; begin - Result := ''; + if ParamNo in [DATA_PARAM_JDN, DATA_PARAM_NUMCHAPTER] then + Result := '0' + else + Result := ''; if FQuery.Active and (ParamNo < Length(DBDataProcessParams)) and (RecIndex < FDataCount) then @@ -560,10 +567,14 @@ procedure TDBDataProcess.Backup(AWebsite: string); end; end; -procedure TDBDataProcess.Refresh; +procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); begin if FQuery.Active then + begin FQuery.Refresh; + if RecheckDataCount then + GetDataCount; + end; end; procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, @@ -595,15 +606,81 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, NumChapter, DateToJDN(JDN)); end; -procedure TDBDataProcess.ApplyUpdates; +procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter: Integer); +var + sql: string; + + procedure AddSQL(const field, value: string); + begin + if value <> '' then + begin + if sql <> '' then + sql += ','#13#10; + sql += field + '=' + QuotedStrd(value); + end; + end; + begin + if Link = '' then Exit; if FConn.Connected then begin - FTrans.Commit; - if FQuery.Active then - begin - FQuery.Refresh; - GetDataCount; + try + sql := ''; + AddSQL('title', Title); + AddSQL('authors', Authors); + AddSQL('artists', Artists); + AddSQL('genres', Genres); + AddSQL('status', Status); + AddSQL('summary', Summary); + AddSQL('numchapter', IntToStr(NumChapter)); + sql := 'UPDATE ' + QuotedStrd(FTableName) + ' SET'#13#10 + sql; + sql += #13#10'WHERE link=' + QuotedStrd(Link) + ';'; + FConn.ExecuteDirect(sql); + except + on E: Exception do + WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + LineEnding + GetStackTraceInfo); + end; + end; +end; + +procedure TDBDataProcess.Commit; +begin + if FConn.Connected then + begin + try + FTrans.Commit; + except + on E: Exception do + begin + WriteLog_E('TDBDataProcess.ApplyUpdates.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); + FTrans.Rollback; + end; + end; + end; +end; + +procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); +begin + if FQuery.Active then + begin + try + FQuery.ApplyUpdates; + FTrans.Commit; + if RecheckDataCount then + GetDataCount; + except + on E: Exception do + begin + WriteLog_E('TDBDataProcess.ApplyUpdates.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); + FTrans.Rollback; + if FQuery.Active = False then + FQuery.Open; + if RecheckDataCount then + GetDataCount; + end; end; end; end; @@ -2711,6 +2788,13 @@ procedure TMangaInformation.SyncInfoToData(const DataProcess: TDataProcess; dataProcess.BreakDataToParts(index); end; +procedure TMangaInformation.SyncInfoToData(const DataProcess: TDBDataProcess); +begin + if Assigned(DataProcess) then + with mangaInfo do + DataProcess.UpdateData(title, link, authors, artists, genres, status, summary, numChapter); +end; + procedure TMangaInformation.AddInfoToDataWithoutBreak(const Name, link: String; const DataProcess: TDataProcess); var From 07759dabd9dd4515878c3959f85419d47a47f43b Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:01:00 +0800 Subject: [PATCH 0038/2794] mainform, fix beforecellpaint with empty value --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fe1ac796a..9134171eb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4040,8 +4040,8 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; if miHighlightNewManga.Checked then begin try - if currentJDN - StrToInt(dataProcess.Param[Node^.Index, DATA_PARAM_JDN]) < - seOptionNewMangaTime.Value then + if StrToIntDef(dataProcess.Param[Node^.Index, DATA_PARAM_JDN], 0) > + (currentJDN - seOptionNewMangaTime.Value) then begin TargetCanvas.Brush.Color := CL_HLBlueMarks; TargetCanvas.FillRect(CellRect); From ee601466f8f4e19b021b77a98952e549b8e7bdb6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:01:25 +0800 Subject: [PATCH 0039/2794] getmangainfo, sync and update --- baseunits/uGetMangaInfosThread.pas | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 21f037c5b..607888ac1 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -112,8 +112,10 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.mangaInfo.summary := MainForm.DataProcess.Param[filterPos, DATA_PARAM_SUMMARY]; end; - { TODO -ocholif : syncinfo with tdbdataprocess } - //FInfo.SyncInfoToData(MainForm.DataProcess, filterPos); + + FInfo.SyncInfoToData(MainForm.DataProcess); + MainForm.dataProcess.Commit; + //MainForm.dataProcess.Refresh; end; end; Result := True; @@ -183,21 +185,17 @@ procedure TGetMangaInfosThread.MainThreadShowInfos; if IsFlushed then Exit; try TransferMangaInfo(MainForm.mangaInfo, FInfo.mangaInfo); - if (Website = MainForm.cbSelectManga.Text) and - (FMangaListPos > -1) then - begin - if (FInfo.mangaInfo.title <> FTitle) or - (FInfo.mangaInfo.numChapter <> FNumChapter) then - begin - FTitle := FInfo.mangaInfo.title; - with MainForm.vtMangaList do + with MainForm do begin + if (FMangaListPos > -1) and + (Website = MainForm.cbSelectManga.Text) then begin - ReinitNode(RootNode, True); - Repaint; + vtMangaList.BeginUpdate; + dataProcess.Refresh; + vtMangaList.EndUpdate; + vtMangaList.Repaint; end; - end; + ShowInformation(FTitle, FWebsite, FLink); end; - MainForm.ShowInformation(FTitle, FWebsite, FLink); except on E: Exception do MainForm.ExceptionHandler(Self, E); From bfc990ebc9cb3e8a1708f04d95c0ff63fd98661e Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:10:08 +0800 Subject: [PATCH 0040/2794] tdbdataprocess use commitretaining --- baseunits/uData.pas | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5b08b4409..0e1c4f665 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -647,27 +647,24 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, procedure TDBDataProcess.Commit; begin if FConn.Connected then - begin try - FTrans.Commit; + FTrans.CommitRetaining; except on E: Exception do begin WriteLog_E('TDBDataProcess.ApplyUpdates.Error: ' + E.Message + LineEnding + GetStackTraceInfo); - FTrans.Rollback; + FTrans.RollbackRetaining; end; end; - end; end; procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); begin if FQuery.Active then - begin try FQuery.ApplyUpdates; - FTrans.Commit; + FTrans.CommitRetaining; if RecheckDataCount then GetDataCount; except @@ -675,14 +672,13 @@ procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); begin WriteLog_E('TDBDataProcess.ApplyUpdates.Error: ' + E.Message + LineEnding + GetStackTraceInfo); - FTrans.Rollback; + FTrans.RollbackRetaining; if FQuery.Active = False then FQuery.Open; if RecheckDataCount then GetDataCount; end; end; - end; end; function TDBDataProcess.Search(ATitle: String): Boolean; From 748ebf288405ba1f508d7a1d2bb0a58cd7b3bb4e Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:13:49 +0800 Subject: [PATCH 0041/2794] getmangainfo, update data on mainform --- baseunits/uGetMangaInfosThread.pas | 2 -- 1 file changed, 2 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 607888ac1..5d5be6d76 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -115,7 +115,6 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.SyncInfoToData(MainForm.DataProcess); MainForm.dataProcess.Commit; - //MainForm.dataProcess.Refresh; end; end; Result := True; @@ -192,7 +191,6 @@ procedure TGetMangaInfosThread.MainThreadShowInfos; vtMangaList.BeginUpdate; dataProcess.Refresh; vtMangaList.EndUpdate; - vtMangaList.Repaint; end; ShowInformation(FTitle, FWebsite, FLink); end; From e0d18dcaacc9045fbe4f717f9c3104e07d430678 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:18:53 +0800 Subject: [PATCH 0042/2794] tdbdataprocess, updatedata even if value is empty --- baseunits/uData.pas | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0e1c4f665..56e6ce2f0 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -613,12 +613,9 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, procedure AddSQL(const field, value: string); begin - if value <> '' then - begin - if sql <> '' then - sql += ','#13#10; - sql += field + '=' + QuotedStrd(value); - end; + if sql <> '' then + sql += ','#13#10; + sql += field + '=' + QuotedStrd(value); end; begin @@ -634,7 +631,7 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, AddSQL('status', Status); AddSQL('summary', Summary); AddSQL('numchapter', IntToStr(NumChapter)); - sql := 'UPDATE ' + QuotedStrd(FTableName) + ' SET'#13#10 + sql; + sql := 'UPDATE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; sql += #13#10'WHERE link=' + QuotedStrd(Link) + ';'; FConn.ExecuteDirect(sql); except From 8a3095e30d17fee014678165ed26f7003e53fb70 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 15:41:06 +0800 Subject: [PATCH 0043/2794] tdbdataprocess, use quotedstr instead --- baseunits/uData.pas | 51 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 56e6ce2f0..79642e750 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -312,7 +312,7 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: string); [cffPreserveTime, cffOverwriteFile], True); except on E: Exception do - Writelog_D('CopyDBDataProcess.Error: ' + E.Message + LineEnding + + Writelog_E('CopyDBDataProcess.Error: ' + E.Message + LineEnding + GetStackTraceInfo); end; end; @@ -442,7 +442,7 @@ constructor TDBDataProcess.Create; FRegxp.ModifierI := True; FSitesList := TStringList.Create; FTableName := 'masterlist'; - FSQLSelect := 'SELECT * FROM ' + FTableName; + FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); FDataCount := 0; end; @@ -504,7 +504,7 @@ function TDBDataProcess.OpenTable(const ATableName: String): Boolean; begin if FQuery.Active then FQuery.Close; - FSQLSelect := 'SELECT * FROM ' + FTableName;; + FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); FQuery.SQL.Text := FSQLSelect; FQuery.Open; end; @@ -582,17 +582,18 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, begin if FConn.Connected then try - FConn.ExecuteDirect('INSERT INTO ' + FTableName + '(' + DBDataProcessParam + - ') VALUES (' + - QuotedStrd(Title) + ',' + - QuotedStrd(Link) + ',' + - QuotedStrd(Authors) + ',' + - QuotedStrd(Artists) + ',' + - QuotedStrd(Genres) + ',' + - QuotedStrd(Status) + ',' + - QuotedStrd(Summary) + ',' + - QuotedStrd(NumChapter) + ',' + - QuotedStrd(JDN) + ');'); + FConn.ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName) + + #13#10'(' + DBDataProcessParam + ')'+ + #13#10'VALUES (' + + QuotedStr(Title) + ',' + + QuotedStr(Link) + ',' + + QuotedStr(Authors) + ',' + + QuotedStr(Artists) + ',' + + QuotedStr(Genres) + ',' + + QuotedStr(Status) + ',' + + QuotedStr(Summary) + ',' + + QuotedStr(IntToStr(NumChapter)) + ',' + + QuotedStr(IntToStr(JDN)) + ');'); except on E: Exception do WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + LineEnding + GetStackTraceInfo); @@ -615,7 +616,7 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, begin if sql <> '' then sql += ','#13#10; - sql += field + '=' + QuotedStrd(value); + sql += field + '=' + QuotedStr(value); end; begin @@ -631,8 +632,8 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, AddSQL('status', Status); AddSQL('summary', Summary); AddSQL('numchapter', IntToStr(NumChapter)); - sql := 'UPDATE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; - sql += #13#10'WHERE link=' + QuotedStrd(Link) + ';'; + sql := 'UPDATE ' + QuotedStr(FTableName) + #13#10'SET'#13#10 + sql; + sql += #13#10'WHERE link=' + QuotedStr(Link) + ';'; FConn.ExecuteDirect(sql); except on E: Exception do @@ -687,7 +688,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; FQuery.Close; FQuery.SQL.Text := FSQLSelect; if ATitle <> '' then - FQuery.SQL.Add('WHERE title LIKE ' + QuotedStrd(AnsiQuotedStr(ATitle, '%'))); + FQuery.SQL.Add('WHERE title LIKE ' + QuotedStr(AnsiQuotedStr(ATitle, '%'))); FQuery.Open; GetDataCount; except @@ -727,7 +728,7 @@ function TDBDataProcess.Filter(const checkedGenres, try SQL.Clear; if searchNewManga then - AddSQL('jdn > ' + QuotedStrd(DateToJDN(IncDay(Now, (0-minusDay))))); + AddSQL('jdn > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0-minusDay)))))); if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); @@ -791,14 +792,14 @@ procedure TDBDataProcess.Sort; FQuery.Close; with FConn do begin - ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName+'_ordered') + + ExecuteDirect('CREATE TABLE ' + QuotedStr(FTableName+'_ordered') + DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO '+ QuotedStrd(FTableName+'_ordered') + ' ' + + ExecuteDirect('INSERT INTO '+ QuotedStr(FTableName+'_ordered') + ' ' + BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + - ' FROM '+ QuotedStrd(FTableName) + 'ORDER BY title COLLATE NATCMP'); - ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE '+ QuotedStrd(FTableName+'_ordered') + - 'RENAME TO ' + QuotedStrd(FTableName)); + ' FROM '+ QuotedStr(FTableName) + 'ORDER BY title COLLATE NATCMP'); + ExecuteDirect('DROP TABLE ' + QuotedStr(FTableName)); + ExecuteDirect('ALTER TABLE '+ QuotedStr(FTableName+'_ordered') + + 'RENAME TO ' + QuotedStr(FTableName)); FTrans.Commit; VacuumTable end; From eb25cc65cedae270734e94fe5b8328433676f4b0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 16:15:00 +0800 Subject: [PATCH 0044/2794] simpleexception, use windows terminate process on windows --- baseunits/SimpleException/USimpleExceptionForm.pas | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/baseunits/SimpleException/USimpleExceptionForm.pas b/baseunits/SimpleException/USimpleExceptionForm.pas index 6483dd253..93074b747 100644 --- a/baseunits/SimpleException/USimpleExceptionForm.pas +++ b/baseunits/SimpleException/USimpleExceptionForm.pas @@ -25,6 +25,9 @@ interface uses + {$ifdef windows} + windows, + {$endif} Forms, Controls, StdCtrls, ExtCtrls, Buttons; type @@ -77,8 +80,11 @@ procedure TSimpleExceptionForm.ButtonDetailsClick(Sender: TObject); procedure TSimpleExceptionForm.ButtonTerminateClick(Sender: TObject); begin - //Application.Terminate; - halt(1); + {$ifdef windows} + TerminateProcess(GetCurrentProcess, 0); + {$else} + halt; + {$endif} end; procedure TSimpleExceptionForm.FormCreate(Sender: TObject); From ee15009b5a04a0e07a0d26edb6dd0cff67af8c20 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 16:16:53 +0800 Subject: [PATCH 0045/2794] dataprocess, use try count when trying to delete file --- baseunits/uData.pas | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 79642e750..8dd0b24f1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -319,13 +319,26 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: string); end; procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); +var + tryc: Integer; + canrename: boolean; begin if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then begin + canrename := True; + tryc := 0; if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then - DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + while not (tryc < 5) and + DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do + begin + Inc(tryc); + canrename := False; + Writelog_W('Try delete: '+IntToStr(tryc)); + Sleep(200); + end; + if canrename then + RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; end; @@ -448,11 +461,17 @@ constructor TDBDataProcess.Create; destructor TDBDataProcess.Destroy; begin - if FConn.Connected then - begin - FTrans.Commit; - VacuumTable; - FConn.Connected := False; + WriteLog_E('TDBDataProcess.Destroy'); + try + if FConn.Connected then + begin + FTrans.Commit; + VacuumTable; + FConn.Connected := False; + end; + except + on E: Exception do + WriteLog_E('TDBDataProcess.Destroy.Commit,Error: '+E.Message+LineEnding+GetStackTraceInfo); end; FSitesList.Free; FQuery.Free; From 4f6f0fa696c18e6d9fc318f232a082f2956bf28c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 16:45:01 +0800 Subject: [PATCH 0046/2794] mainform, don't need to save again --- mangadownloader/forms/frmMain.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9134171eb..d14a89534 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -914,7 +914,6 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); end; //Backup data - dataProcess.Save; DLManager.Backup; DLManager.BackupDownloadedChaptersList; isExiting := True; From b6f5dc12b7ecd3ce98c0fd40ef85dfdbb25965db Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 18:26:25 +0800 Subject: [PATCH 0047/2794] updatethread,tdbdataprocess, clean up --- baseunits/uData.pas | 37 +++++++++++++++++++++++++------------ baseunits/uUpdateThread.pas | 32 ++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8dd0b24f1..b056aa34a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -202,6 +202,7 @@ TMangaInformation = class(TObject) function DBDataProcessExist(const AWebsite: string): Boolean; procedure CopyDBDataProcess(const AWebsite, NWebsite: string); procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); + procedure DeleteDBDataProcess(const AWebsite: string); implementation @@ -333,7 +334,6 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); begin Inc(tryc); canrename := False; - Writelog_W('Try delete: '+IntToStr(tryc)); Sleep(200); end; if canrename then @@ -342,6 +342,12 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); end; end; +procedure DeleteDBDataProcess(const AWebsite: string); +begin + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then + DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); +end; + { TDBDataProcess } procedure TDBDataProcess.CreateTable; @@ -448,8 +454,7 @@ constructor TDBDataProcess.Create; FConn := TSQLite3Connectionx.Create(nil); FTrans := TSQLTransaction.Create(nil); FQuery := TSQLQuery.Create(nil); - FTrans.DataBase := FConn; - FQuery.Transaction := FTrans; + FConn.Transaction := FTrans; FQuery.DataBase := FTrans.DataBase; FRegxp := TRegExpr.Create; FRegxp.ModifierI := True; @@ -461,17 +466,20 @@ constructor TDBDataProcess.Create; destructor TDBDataProcess.Destroy; begin - WriteLog_E('TDBDataProcess.Destroy'); try if FConn.Connected then begin - FTrans.Commit; + try + FTrans.CommitRetaining; + except + FTrans.RollbackRetaining; + end; VacuumTable; FConn.Connected := False; end; except on E: Exception do - WriteLog_E('TDBDataProcess.Destroy.Commit,Error: '+E.Message+LineEnding+GetStackTraceInfo); + WriteLog_E('TDBDataProcess.Destroy,Error: '+E.Message+LineEnding+GetStackTraceInfo); end; FSitesList.Free; FQuery.Free; @@ -487,7 +495,9 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; filepath: String; begin Result := False; - Self.Close; + FFiltered := False; + FDataCount := 0; + Close; if AWebsite <> '' then FWebsite := AWebsite; if FWebsite = '' then Exit; filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; @@ -501,12 +511,11 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; CreateTable; OpenTable; GetDataCount; - FFiltered := False; end; Result := FQuery.Active; except on E: Exception do - WriteLog_E('TDBDataProcess.LoadFromFile.Error: ' + E.Message + + WriteLog_E('TDBDataProcess.Open.Error: ' + E.Message + LineEnding + GetStackTraceInfo); end; end; @@ -556,7 +565,11 @@ procedure TDBDataProcess.Close; try if FConn.Connected then begin - FTrans.Commit; + try + FTrans.CommitRetaining; + except + FTrans.RollbackRetaining; + end; FConn.Connected := False; FConn.DatabaseName := ''; end; @@ -569,7 +582,7 @@ procedure TDBDataProcess.Close; procedure TDBDataProcess.Save; begin - Self.ApplyUpdates; + Commit; end; procedure TDBDataProcess.Backup(AWebsite: string); @@ -622,7 +635,7 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; JDN: TDateTime); begin - Self.AddData(Title, Link, Authors, Artists, Genres, Status, Summary, + AddData(Title, Link, Authors, Artists, Genres, Status, Summary, NumChapter, DateToJDN(JDN)); end; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 09bd7c848..689b5ecf5 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -307,24 +307,27 @@ destructor TUpdateMangaManagerThread.Destroy; procedure TUpdateMangaManagerThread.RefreshList; begin + exit; try with MainForm do begin if cbSelectManga.Items[cbSelectManga.ItemIndex] = website then begin Screen.Cursor := crHourGlass; - edSearch.Clear; - vtMangaList.Clear; - if dataProcess = nil then - dataProcess := TDBDataProcess.Create - else - dataProcess.Close; - Sleep(500); - OverwriteDBDataProcess(website, twebsite); - dataProcess.Open(website); - vtMangaList.RootNodeCount := dataProcess.DataCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); - Screen.Cursor := crDefault; + try + edSearch.Clear; + vtMangaList.Clear; + if dataProcess = nil then + dataProcess := TDBDataProcess.Create + else + dataProcess.Close; + OverwriteDBDataProcess(website, twebsite); + dataProcess.Open(website); + vtMangaList.RootNodeCount := dataProcess.DataCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + finally + Screen.Cursor := crDefault; + end; end else OverwriteDBDataProcess(website, twebsite); @@ -516,7 +519,7 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(MainThreadShowGetting); twebsite := '__' + website; - + DeleteDBDataProcess(twebsite); if (MainForm.cbSelectManga.Text = website) and (MainForm.dataProcess.Connected) then MainForm.dataProcess.Backup(twebsite) @@ -654,9 +657,10 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); mainDataProcess.Sort; - mainDataProcess.Close; end; + mainDataProcess.Close; Synchronize(RefreshList); + DeleteDBDataProcess(twebsite); if Terminated then Break; websites[websitePtr - 1] := From 63a6efdfdd5331e8c2dc30d6fa07fda6a2c1bfec Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 7 Jul 2015 18:36:31 +0800 Subject: [PATCH 0048/2794] clean up code --- baseunits/uUpdateThread.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 689b5ecf5..72c6cd24a 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -307,7 +307,6 @@ destructor TUpdateMangaManagerThread.Destroy; procedure TUpdateMangaManagerThread.RefreshList; begin - exit; try with MainForm do begin @@ -522,7 +521,11 @@ procedure TUpdateMangaManagerThread.Execute; DeleteDBDataProcess(twebsite); if (MainForm.cbSelectManga.Text = website) and (MainForm.dataProcess.Connected) then - MainForm.dataProcess.Backup(twebsite) + begin + MainForm.dataProcess.Backup(twebsite); + MainForm.vtMangaList.Clear; + MainForm.dataProcess.Close; + end else CopyDBDataProcess(website, twebsite); From 30342976f9d972a17d4518e564e833036cc893a9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Wed, 8 Jul 2015 04:59:10 +0800 Subject: [PATCH 0049/2794] no changes reclone local --- 3rd/synapse/source/ssl_streamsec.pas | 1078 +++--- 3rd/synapse/source/synachar.pas | 4076 ++++++++++---------- 3rd/synapse/source/synacode.pas | 2934 +++++++------- 3rd/synapse/source/synacrypt.pas | 4824 ++++++++++++------------ 3rd/synapse/source/synadbg.pas | 312 +- 3rd/synapse/source/synafpc.pas | 296 +- 3rd/synapse/source/synaicnv.pas | 736 ++-- 3rd/synapse/source/synaip.pas | 844 ++--- 3rd/synapse/source/synamisc.pas | 816 ++-- 3rd/synapse/source/synaser.pas | 4670 +++++++++++------------ 3rd/synapse/source/synautil.pas | 4248 ++++++++++----------- 3rd/synapse/source/synsock.pas | 172 +- 3rd/synapse/source/tlntsend.pas | 728 ++-- 3rd/synapse/source/tzutil.pas | 1404 +++---- baseunits/animatedgifs/animatedgif.pas | 2326 ++++++------ baseunits/animatedgifs/membitmap.pas | 2774 +++++++------- 16 files changed, 16119 insertions(+), 16119 deletions(-) diff --git a/3rd/synapse/source/ssl_streamsec.pas b/3rd/synapse/source/ssl_streamsec.pas index 8c36ac8ca..1dc67f95b 100644 --- a/3rd/synapse/source/ssl_streamsec.pas +++ b/3rd/synapse/source/ssl_streamsec.pas @@ -1,539 +1,539 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.000.006 | -|==============================================================================| -| Content: SSL support by StreamSecII | -|==============================================================================| -| Copyright (c)1999-2005, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2005. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Henrick Hellstr�m | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(SSL plugin for StreamSecII or OpenStreamSecII) - -StreamSecII is native pascal library, you not need any external libraries! - -You can tune lot of StreamSecII properties by using your GlobalServer. If you not -using your GlobalServer, then this plugin create own TSimpleTLSInternalServer -instance for each TCP connection. Formore information about GlobalServer usage -refer StreamSecII documentation. - -If you are not using key and certificate by GlobalServer, then you can use -properties of this plugin instead, but this have limited features and -@link(TCustomSSL.KeyPassword) not working properly yet! - -For handling keys and certificates you can use this properties: -@link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA), -@link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate), -@link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey), -@link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate), -@link(TCustomSSL.PFXFile). For usage of this properties and for possible formats -of keys and certificates refer to StreamSecII documentation. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -unit ssl_streamsec; - -interface - -uses - SysUtils, Classes, - blcksock, synsock, synautil, synacode, - TlsInternalServer, TlsSynaSock, TlsConst, StreamSecII, Asn1, X509Base, - SecUtils; - -type - {:@exclude} - TMyTLSSynSockSlave = class(TTLSSynSockSlave) - protected - procedure SetMyTLSServer(const Value: TCustomTLSInternalServer); - function GetMyTLSServer: TCustomTLSInternalServer; - published - property MyTLSServer: TCustomTLSInternalServer read GetMyTLSServer write SetMyTLSServer; - end; - - {:@abstract(class implementing StreamSecII SSL plugin.) - Instance of this class will be created for each @link(TTCPBlockSocket). - You not need to create instance of this class, all is done by Synapse itself!} - TSSLStreamSec = class(TCustomSSL) - protected - FSlave: TMyTLSSynSockSlave; - FIsServer: Boolean; - FTLSServer: TCustomTLSInternalServer; - FServerCreated: Boolean; - function SSLCheck: Boolean; - function Init(server:Boolean): Boolean; - function DeInit: Boolean; - function Prepare(server:Boolean): Boolean; - procedure NotTrustEvent(Sender: TObject; Cert: TASN1Struct; var ExplicitTrust: Boolean); - function X500StrToStr(const Prefix: string; const Value: TX500String): string; - function X501NameToStr(const Value: TX501Name): string; - function GetCert: PASN1Struct; - public - constructor Create(const Value: TTCPBlockSocket); override; - destructor Destroy; override; - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - {:See @inherited and @link(ssl_streamsec) for more details.} - function Connect: boolean; override; - {:See @inherited and @link(ssl_streamsec) for more details.} - function Accept: boolean; override; - {:See @inherited} - function Shutdown: boolean; override; - {:See @inherited} - function BiShutdown: boolean; override; - {:See @inherited} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function WaitingData: Integer; override; - {:See @inherited} - function GetSSLVersion: string; override; - {:See @inherited} - function GetPeerSubject: string; override; - {:See @inherited} - function GetPeerIssuer: string; override; - {:See @inherited} - function GetPeerName: string; override; - {:See @inherited} - function GetPeerFingerprint: string; override; - {:See @inherited} - function GetCertInfo: string; override; - published - {:TLS server for tuning of StreamSecII.} - property TLSServer: TCustomTLSInternalServer read FTLSServer write FTLSServer; - end; - -implementation - -{==============================================================================} -procedure TMyTLSSynSockSlave.SetMyTLSServer(const Value: TCustomTLSInternalServer); -begin - TLSServer := Value; -end; - -function TMyTLSSynSockSlave.GetMyTLSServer: TCustomTLSInternalServer; -begin - Result := TLSServer; -end; - -{==============================================================================} - -constructor TSSLStreamSec.Create(const Value: TTCPBlockSocket); -begin - inherited Create(Value); - FSlave := nil; - FIsServer := False; - FTLSServer := nil; -end; - -destructor TSSLStreamSec.Destroy; -begin - DeInit; - inherited Destroy; -end; - -function TSSLStreamSec.LibVersion: String; -begin - Result := 'StreamSecII'; -end; - -function TSSLStreamSec.LibName: String; -begin - Result := 'ssl_streamsec'; -end; - -function TSSLStreamSec.SSLCheck: Boolean; -begin - Result := true; - FLastErrorDesc := ''; - if not Assigned(FSlave) then - Exit; - FLastError := FSlave.ErrorCode; - if FLastError <> 0 then - begin - FLastErrorDesc := TlsConst.AlertMsg(FLastError); - end; -end; - -procedure TSSLStreamSec.NotTrustEvent(Sender: TObject; Cert: TASN1Struct; var ExplicitTrust: Boolean); -begin - ExplicitTrust := true; -end; - -function TSSLStreamSec.Init(server:Boolean): Boolean; -var - st: TMemoryStream; - pass: ISecretKey; - ws: WideString; -begin - Result := False; - ws := FKeyPassword; - pass := TSecretKey.CreateBmpStr(PWideChar(ws), length(ws)); - try - FIsServer := Server; - FSlave := TMyTLSSynSockSlave.CreateSocket(FSocket.Socket); - if Assigned(FTLSServer) then - FSlave.MyTLSServer := FTLSServer - else - if Assigned(TLSInternalServer.GlobalServer) then - FSlave.MyTLSServer := TLSInternalServer.GlobalServer - else begin - FSlave.MyTLSServer := TSimpleTLSInternalServer.Create(nil); - FServerCreated := True; - end; - if server then - FSlave.MyTLSServer.ClientOrServer := cosServerSide - else - FSlave.MyTLSServer.ClientOrServer := cosClientSide; - if not FVerifyCert then - begin - FSlave.MyTLSServer.OnCertNotTrusted := NotTrustEvent; - end; - FSlave.MyTLSServer.Options.VerifyServerName := []; - FSlave.MyTLSServer.Options.Export40Bit := prAllowed; - FSlave.MyTLSServer.Options.Export56Bit := prAllowed; - FSlave.MyTLSServer.Options.RequestClientCertificate := False; - FSlave.MyTLSServer.Options.RequireClientCertificate := False; - if server and FVerifyCert then - begin - FSlave.MyTLSServer.Options.RequestClientCertificate := True; - FSlave.MyTLSServer.Options.RequireClientCertificate := True; - end; - if FCertCAFile <> '' then - FSlave.MyTLSServer.LoadRootCertsFromFile(CertCAFile); - if FCertCA <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FCertCA); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadRootCertsFromStream(st); - finally - st.free; - end; - end; - if FTrustCertificateFile <> '' then - FSlave.MyTLSServer.LoadTrustedCertsFromFile(FTrustCertificateFile); - if FTrustCertificate <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FTrustCertificate); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadTrustedCertsFromStream(st); - finally - st.free; - end; - end; - if FPrivateKeyFile <> '' then - FSlave.MyTLSServer.LoadPrivateKeyRingFromFile(FPrivateKeyFile, pass); -// FSlave.MyTLSServer.PrivateKeyRing.LoadPrivateKeyFromFile(FPrivateKeyFile, pass); - if FPrivateKey <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FPrivateKey); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadPrivateKeyRingFromStream(st, pass); - finally - st.free; - end; - end; - if FCertificateFile <> '' then - FSlave.MyTLSServer.LoadMyCertsFromFile(FCertificateFile); - if FCertificate <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FCertificate); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadMyCertsFromStream(st); - finally - st.free; - end; - end; - if FPFXfile <> '' then - FSlave.MyTLSServer.ImportFromPFX(FPFXfile, pass); - if server and FServerCreated then - begin - FSlave.MyTLSServer.Options.BulkCipherAES128 := prPrefer; - FSlave.MyTLSServer.Options.BulkCipherAES256 := prAllowed; - FSlave.MyTLSServer.Options.EphemeralECDHKeySize := ecs256; - FSlave.MyTLSServer.Options.SignatureRSA := prPrefer; - FSlave.MyTLSServer.Options.KeyAgreementRSA := prAllowed; - FSlave.MyTLSServer.Options.KeyAgreementECDHE := prAllowed; - FSlave.MyTLSServer.Options.KeyAgreementDHE := prPrefer; - FSlave.MyTLSServer.TLSSetupServer; - end; - Result := true; - finally - pass := nil; - end; -end; - -function TSSLStreamSec.DeInit: Boolean; -var - obj: TObject; -begin - Result := True; - if assigned(FSlave) then - begin - FSlave.Close; - if FServerCreated then - obj := FSlave.TLSServer - else - obj := nil; - FSlave.Free; - obj.Free; - FSlave := nil; - end; - FSSLEnabled := false; -end; - -function TSSLStreamSec.Prepare(server:Boolean): Boolean; -begin - Result := false; - DeInit; - if Init(server) then - Result := true - else - DeInit; -end; - -function TSSLStreamSec.Connect: boolean; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(false) then - begin - FSlave.Open; - SSLCheck; - if FLastError <> 0 then - Exit; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLStreamSec.Accept: boolean; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(true) then - begin - FSlave.DoConnect; - SSLCheck; - if FLastError <> 0 then - Exit; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLStreamSec.Shutdown: boolean; -begin - Result := BiShutdown; -end; - -function TSSLStreamSec.BiShutdown: boolean; -begin - DeInit; - Result := True; -end; - -function TSSLStreamSec.SendBuffer(Buffer: TMemory; Len: Integer): Integer; -var - l: integer; -begin - l := len; - FSlave.SendBuf(Buffer^, l, true); - Result := l; - SSLCheck; -end; - -function TSSLStreamSec.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -var - l: integer; -begin - l := Len; - Result := FSlave.ReceiveBuf(Buffer^, l); - SSLCheck; -end; - -function TSSLStreamSec.WaitingData: Integer; -begin - Result := 0; - while FSlave.Connected do begin - Result := FSlave.ReceiveLength; - if Result > 0 then - Break; - Sleep(1); - end; -end; - -function TSSLStreamSec.GetSSLVersion: string; -begin - Result := 'SSLv3 or TLSv1'; -end; - -function TSSLStreamSec.GetCert: PASN1Struct; -begin - if FIsServer then - Result := FSlave.GetClientCert - else - Result := FSlave.GetServerCert; -end; - -function TSSLStreamSec.GetPeerSubject: string; -var - XName: TX501Name; - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - ExtractSubject(Cert^,XName, false); - Result := X501NameToStr(XName); - end; -end; - -function TSSLStreamSec.GetPeerName: string; -var - XName: TX501Name; - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - ExtractSubject(Cert^,XName, false); - Result := XName.commonName.Str; - end; -end; - -function TSSLStreamSec.GetPeerIssuer: string; -var - XName: TX501Name; - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - ExtractIssuer(Cert^, XName, false); - Result := X501NameToStr(XName); - end; -end; - -function TSSLStreamSec.GetPeerFingerprint: string; -var - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - Result := MD5(Cert.ContentAsOctetString); -end; - -function TSSLStreamSec.GetCertInfo: string; -var - Cert: PASN1Struct; - l: Tstringlist; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - l := TStringList.Create; - try - Asn1.RenderAsText(cert^, l, true, true, true, 2); - Result := l.Text; - finally - l.free; - end; - end; -end; - -function TSSLStreamSec.X500StrToStr(const Prefix: string; - const Value: TX500String): string; -begin - if Value.Str = '' then - Result := '' - else - Result := '/' + Prefix + '=' + Value.Str; -end; - -function TSSLStreamSec.X501NameToStr(const Value: TX501Name): string; -begin - Result := X500StrToStr('CN',Value.commonName) + - X500StrToStr('C',Value.countryName) + - X500StrToStr('L',Value.localityName) + - X500StrToStr('ST',Value.stateOrProvinceName) + - X500StrToStr('O',Value.organizationName) + - X500StrToStr('OU',Value.organizationalUnitName) + - X500StrToStr('T',Value.title) + - X500StrToStr('N',Value.name) + - X500StrToStr('G',Value.givenName) + - X500StrToStr('I',Value.initials) + - X500StrToStr('SN',Value.surname) + - X500StrToStr('GQ',Value.generationQualifier) + - X500StrToStr('DNQ',Value.dnQualifier) + - X500StrToStr('E',Value.emailAddress); -end; - - -{==============================================================================} - -initialization - SSLImplementation := TSSLStreamSec; - -finalization - -end. - - +{==============================================================================| +| Project : Ararat Synapse | 001.000.006 | +|==============================================================================| +| Content: SSL support by StreamSecII | +|==============================================================================| +| Copyright (c)1999-2005, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2005. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| Henrick Hellstr�m | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(SSL plugin for StreamSecII or OpenStreamSecII) + +StreamSecII is native pascal library, you not need any external libraries! + +You can tune lot of StreamSecII properties by using your GlobalServer. If you not +using your GlobalServer, then this plugin create own TSimpleTLSInternalServer +instance for each TCP connection. Formore information about GlobalServer usage +refer StreamSecII documentation. + +If you are not using key and certificate by GlobalServer, then you can use +properties of this plugin instead, but this have limited features and +@link(TCustomSSL.KeyPassword) not working properly yet! + +For handling keys and certificates you can use this properties: +@link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA), +@link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate), +@link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey), +@link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate), +@link(TCustomSSL.PFXFile). For usage of this properties and for possible formats +of keys and certificates refer to StreamSecII documentation. +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$H+} + +unit ssl_streamsec; + +interface + +uses + SysUtils, Classes, + blcksock, synsock, synautil, synacode, + TlsInternalServer, TlsSynaSock, TlsConst, StreamSecII, Asn1, X509Base, + SecUtils; + +type + {:@exclude} + TMyTLSSynSockSlave = class(TTLSSynSockSlave) + protected + procedure SetMyTLSServer(const Value: TCustomTLSInternalServer); + function GetMyTLSServer: TCustomTLSInternalServer; + published + property MyTLSServer: TCustomTLSInternalServer read GetMyTLSServer write SetMyTLSServer; + end; + + {:@abstract(class implementing StreamSecII SSL plugin.) + Instance of this class will be created for each @link(TTCPBlockSocket). + You not need to create instance of this class, all is done by Synapse itself!} + TSSLStreamSec = class(TCustomSSL) + protected + FSlave: TMyTLSSynSockSlave; + FIsServer: Boolean; + FTLSServer: TCustomTLSInternalServer; + FServerCreated: Boolean; + function SSLCheck: Boolean; + function Init(server:Boolean): Boolean; + function DeInit: Boolean; + function Prepare(server:Boolean): Boolean; + procedure NotTrustEvent(Sender: TObject; Cert: TASN1Struct; var ExplicitTrust: Boolean); + function X500StrToStr(const Prefix: string; const Value: TX500String): string; + function X501NameToStr(const Value: TX501Name): string; + function GetCert: PASN1Struct; + public + constructor Create(const Value: TTCPBlockSocket); override; + destructor Destroy; override; + {:See @inherited} + function LibVersion: String; override; + {:See @inherited} + function LibName: String; override; + {:See @inherited and @link(ssl_streamsec) for more details.} + function Connect: boolean; override; + {:See @inherited and @link(ssl_streamsec) for more details.} + function Accept: boolean; override; + {:See @inherited} + function Shutdown: boolean; override; + {:See @inherited} + function BiShutdown: boolean; override; + {:See @inherited} + function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; + {:See @inherited} + function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; + {:See @inherited} + function WaitingData: Integer; override; + {:See @inherited} + function GetSSLVersion: string; override; + {:See @inherited} + function GetPeerSubject: string; override; + {:See @inherited} + function GetPeerIssuer: string; override; + {:See @inherited} + function GetPeerName: string; override; + {:See @inherited} + function GetPeerFingerprint: string; override; + {:See @inherited} + function GetCertInfo: string; override; + published + {:TLS server for tuning of StreamSecII.} + property TLSServer: TCustomTLSInternalServer read FTLSServer write FTLSServer; + end; + +implementation + +{==============================================================================} +procedure TMyTLSSynSockSlave.SetMyTLSServer(const Value: TCustomTLSInternalServer); +begin + TLSServer := Value; +end; + +function TMyTLSSynSockSlave.GetMyTLSServer: TCustomTLSInternalServer; +begin + Result := TLSServer; +end; + +{==============================================================================} + +constructor TSSLStreamSec.Create(const Value: TTCPBlockSocket); +begin + inherited Create(Value); + FSlave := nil; + FIsServer := False; + FTLSServer := nil; +end; + +destructor TSSLStreamSec.Destroy; +begin + DeInit; + inherited Destroy; +end; + +function TSSLStreamSec.LibVersion: String; +begin + Result := 'StreamSecII'; +end; + +function TSSLStreamSec.LibName: String; +begin + Result := 'ssl_streamsec'; +end; + +function TSSLStreamSec.SSLCheck: Boolean; +begin + Result := true; + FLastErrorDesc := ''; + if not Assigned(FSlave) then + Exit; + FLastError := FSlave.ErrorCode; + if FLastError <> 0 then + begin + FLastErrorDesc := TlsConst.AlertMsg(FLastError); + end; +end; + +procedure TSSLStreamSec.NotTrustEvent(Sender: TObject; Cert: TASN1Struct; var ExplicitTrust: Boolean); +begin + ExplicitTrust := true; +end; + +function TSSLStreamSec.Init(server:Boolean): Boolean; +var + st: TMemoryStream; + pass: ISecretKey; + ws: WideString; +begin + Result := False; + ws := FKeyPassword; + pass := TSecretKey.CreateBmpStr(PWideChar(ws), length(ws)); + try + FIsServer := Server; + FSlave := TMyTLSSynSockSlave.CreateSocket(FSocket.Socket); + if Assigned(FTLSServer) then + FSlave.MyTLSServer := FTLSServer + else + if Assigned(TLSInternalServer.GlobalServer) then + FSlave.MyTLSServer := TLSInternalServer.GlobalServer + else begin + FSlave.MyTLSServer := TSimpleTLSInternalServer.Create(nil); + FServerCreated := True; + end; + if server then + FSlave.MyTLSServer.ClientOrServer := cosServerSide + else + FSlave.MyTLSServer.ClientOrServer := cosClientSide; + if not FVerifyCert then + begin + FSlave.MyTLSServer.OnCertNotTrusted := NotTrustEvent; + end; + FSlave.MyTLSServer.Options.VerifyServerName := []; + FSlave.MyTLSServer.Options.Export40Bit := prAllowed; + FSlave.MyTLSServer.Options.Export56Bit := prAllowed; + FSlave.MyTLSServer.Options.RequestClientCertificate := False; + FSlave.MyTLSServer.Options.RequireClientCertificate := False; + if server and FVerifyCert then + begin + FSlave.MyTLSServer.Options.RequestClientCertificate := True; + FSlave.MyTLSServer.Options.RequireClientCertificate := True; + end; + if FCertCAFile <> '' then + FSlave.MyTLSServer.LoadRootCertsFromFile(CertCAFile); + if FCertCA <> '' then + begin + st := TMemoryStream.Create; + try + WriteStrToStream(st, FCertCA); + st.Seek(0, soFromBeginning); + FSlave.MyTLSServer.LoadRootCertsFromStream(st); + finally + st.free; + end; + end; + if FTrustCertificateFile <> '' then + FSlave.MyTLSServer.LoadTrustedCertsFromFile(FTrustCertificateFile); + if FTrustCertificate <> '' then + begin + st := TMemoryStream.Create; + try + WriteStrToStream(st, FTrustCertificate); + st.Seek(0, soFromBeginning); + FSlave.MyTLSServer.LoadTrustedCertsFromStream(st); + finally + st.free; + end; + end; + if FPrivateKeyFile <> '' then + FSlave.MyTLSServer.LoadPrivateKeyRingFromFile(FPrivateKeyFile, pass); +// FSlave.MyTLSServer.PrivateKeyRing.LoadPrivateKeyFromFile(FPrivateKeyFile, pass); + if FPrivateKey <> '' then + begin + st := TMemoryStream.Create; + try + WriteStrToStream(st, FPrivateKey); + st.Seek(0, soFromBeginning); + FSlave.MyTLSServer.LoadPrivateKeyRingFromStream(st, pass); + finally + st.free; + end; + end; + if FCertificateFile <> '' then + FSlave.MyTLSServer.LoadMyCertsFromFile(FCertificateFile); + if FCertificate <> '' then + begin + st := TMemoryStream.Create; + try + WriteStrToStream(st, FCertificate); + st.Seek(0, soFromBeginning); + FSlave.MyTLSServer.LoadMyCertsFromStream(st); + finally + st.free; + end; + end; + if FPFXfile <> '' then + FSlave.MyTLSServer.ImportFromPFX(FPFXfile, pass); + if server and FServerCreated then + begin + FSlave.MyTLSServer.Options.BulkCipherAES128 := prPrefer; + FSlave.MyTLSServer.Options.BulkCipherAES256 := prAllowed; + FSlave.MyTLSServer.Options.EphemeralECDHKeySize := ecs256; + FSlave.MyTLSServer.Options.SignatureRSA := prPrefer; + FSlave.MyTLSServer.Options.KeyAgreementRSA := prAllowed; + FSlave.MyTLSServer.Options.KeyAgreementECDHE := prAllowed; + FSlave.MyTLSServer.Options.KeyAgreementDHE := prPrefer; + FSlave.MyTLSServer.TLSSetupServer; + end; + Result := true; + finally + pass := nil; + end; +end; + +function TSSLStreamSec.DeInit: Boolean; +var + obj: TObject; +begin + Result := True; + if assigned(FSlave) then + begin + FSlave.Close; + if FServerCreated then + obj := FSlave.TLSServer + else + obj := nil; + FSlave.Free; + obj.Free; + FSlave := nil; + end; + FSSLEnabled := false; +end; + +function TSSLStreamSec.Prepare(server:Boolean): Boolean; +begin + Result := false; + DeInit; + if Init(server) then + Result := true + else + DeInit; +end; + +function TSSLStreamSec.Connect: boolean; +begin + Result := False; + if FSocket.Socket = INVALID_SOCKET then + Exit; + if Prepare(false) then + begin + FSlave.Open; + SSLCheck; + if FLastError <> 0 then + Exit; + FSSLEnabled := True; + Result := True; + end; +end; + +function TSSLStreamSec.Accept: boolean; +begin + Result := False; + if FSocket.Socket = INVALID_SOCKET then + Exit; + if Prepare(true) then + begin + FSlave.DoConnect; + SSLCheck; + if FLastError <> 0 then + Exit; + FSSLEnabled := True; + Result := True; + end; +end; + +function TSSLStreamSec.Shutdown: boolean; +begin + Result := BiShutdown; +end; + +function TSSLStreamSec.BiShutdown: boolean; +begin + DeInit; + Result := True; +end; + +function TSSLStreamSec.SendBuffer(Buffer: TMemory; Len: Integer): Integer; +var + l: integer; +begin + l := len; + FSlave.SendBuf(Buffer^, l, true); + Result := l; + SSLCheck; +end; + +function TSSLStreamSec.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; +var + l: integer; +begin + l := Len; + Result := FSlave.ReceiveBuf(Buffer^, l); + SSLCheck; +end; + +function TSSLStreamSec.WaitingData: Integer; +begin + Result := 0; + while FSlave.Connected do begin + Result := FSlave.ReceiveLength; + if Result > 0 then + Break; + Sleep(1); + end; +end; + +function TSSLStreamSec.GetSSLVersion: string; +begin + Result := 'SSLv3 or TLSv1'; +end; + +function TSSLStreamSec.GetCert: PASN1Struct; +begin + if FIsServer then + Result := FSlave.GetClientCert + else + Result := FSlave.GetServerCert; +end; + +function TSSLStreamSec.GetPeerSubject: string; +var + XName: TX501Name; + Cert: PASN1Struct; +begin + Result := ''; + Cert := GetCert; + if Assigned(cert) then + begin + ExtractSubject(Cert^,XName, false); + Result := X501NameToStr(XName); + end; +end; + +function TSSLStreamSec.GetPeerName: string; +var + XName: TX501Name; + Cert: PASN1Struct; +begin + Result := ''; + Cert := GetCert; + if Assigned(cert) then + begin + ExtractSubject(Cert^,XName, false); + Result := XName.commonName.Str; + end; +end; + +function TSSLStreamSec.GetPeerIssuer: string; +var + XName: TX501Name; + Cert: PASN1Struct; +begin + Result := ''; + Cert := GetCert; + if Assigned(cert) then + begin + ExtractIssuer(Cert^, XName, false); + Result := X501NameToStr(XName); + end; +end; + +function TSSLStreamSec.GetPeerFingerprint: string; +var + Cert: PASN1Struct; +begin + Result := ''; + Cert := GetCert; + if Assigned(cert) then + Result := MD5(Cert.ContentAsOctetString); +end; + +function TSSLStreamSec.GetCertInfo: string; +var + Cert: PASN1Struct; + l: Tstringlist; +begin + Result := ''; + Cert := GetCert; + if Assigned(cert) then + begin + l := TStringList.Create; + try + Asn1.RenderAsText(cert^, l, true, true, true, 2); + Result := l.Text; + finally + l.free; + end; + end; +end; + +function TSSLStreamSec.X500StrToStr(const Prefix: string; + const Value: TX500String): string; +begin + if Value.Str = '' then + Result := '' + else + Result := '/' + Prefix + '=' + Value.Str; +end; + +function TSSLStreamSec.X501NameToStr(const Value: TX501Name): string; +begin + Result := X500StrToStr('CN',Value.commonName) + + X500StrToStr('C',Value.countryName) + + X500StrToStr('L',Value.localityName) + + X500StrToStr('ST',Value.stateOrProvinceName) + + X500StrToStr('O',Value.organizationName) + + X500StrToStr('OU',Value.organizationalUnitName) + + X500StrToStr('T',Value.title) + + X500StrToStr('N',Value.name) + + X500StrToStr('G',Value.givenName) + + X500StrToStr('I',Value.initials) + + X500StrToStr('SN',Value.surname) + + X500StrToStr('GQ',Value.generationQualifier) + + X500StrToStr('DNQ',Value.dnQualifier) + + X500StrToStr('E',Value.emailAddress); +end; + + +{==============================================================================} + +initialization + SSLImplementation := TSSLStreamSec; + +finalization + +end. + + diff --git a/3rd/synapse/source/synachar.pas b/3rd/synapse/source/synachar.pas index 5d39b2960..9a9d2dd26 100644 --- a/3rd/synapse/source/synachar.pas +++ b/3rd/synapse/source/synachar.pas @@ -1,2038 +1,2038 @@ -{==============================================================================| -| Project : Ararat Synapse | 005.002.003 | -|==============================================================================| -| Content: Charset conversion support | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(Charset conversion support) -This unit contains a routines for lot of charset conversions. - -It using built-in conversion tables or external Iconv library. Iconv is used - when needed conversion is known by Iconv library. When Iconv library is not - found or Iconv not know requested conversion, then are internal routines used - for conversion. (You can disable Iconv support from your program too!) - -Internal routines knows all major charsets for Europe or America. For East-Asian - charsets you must use Iconv library! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synachar; - -interface - -uses -{$IFNDEF MSWINDOWS} - {$IFNDEF FPC} - Libc, - {$ENDIF} -{$ELSE} - Windows, -{$ENDIF} - SysUtils, - synautil, synacode, synaicnv; - -type - {:Type with all supported charsets.} - TMimeChar = (ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, - ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, ISO_8859_13, - ISO_8859_14, ISO_8859_15, CP1250, CP1251, CP1252, CP1253, CP1254, CP1255, - CP1256, CP1257, CP1258, KOI8_R, CP895, CP852, UCS_2, UCS_4, UTF_8, UTF_7, - UTF_7mod, UCS_2LE, UCS_4LE, - //next is supported by Iconv only... - UTF_16, UTF_16LE, UTF_32, UTF_32LE, C99, JAVA, ISO_8859_16, KOI8_U, KOI8_RU, - CP862, CP866, MAC, MACCE, MACICE, MACCRO, MACRO, MACCYR, MACUK, MACGR, MACTU, - MACHEB, MACAR, MACTH, ROMAN8, NEXTSTEP, ARMASCII, GEORGIAN_AC, GEORGIAN_PS, - KOI8_T, MULELAO, CP1133, TIS620, CP874, VISCII, TCVN, ISO_IR_14, JIS_X0201, - JIS_X0208, JIS_X0212, GB1988_80, GB2312_80, ISO_IR_165, ISO_IR_149, EUC_JP, - SHIFT_JIS, CP932, ISO_2022_JP, ISO_2022_JP1, ISO_2022_JP2, GB2312, CP936, - GB18030, ISO_2022_CN, ISO_2022_CNE, HZ, EUC_TW, BIG5, CP950, BIG5_HKSCS, - EUC_KR, CP949, CP1361, ISO_2022_KR, CP737, CP775, CP853, CP855, CP857, - CP858, CP860, CP861, CP863, CP864, CP865, CP869, CP1125); - - {:Set of any charsets.} - TMimeSetChar = set of TMimeChar; - -const - {:Set of charsets supported by Iconv library only.} - IconvOnlyChars: set of TMimeChar = [UTF_16, UTF_16LE, UTF_32, UTF_32LE, - C99, JAVA, ISO_8859_16, KOI8_U, KOI8_RU, CP862, CP866, MAC, MACCE, MACICE, - MACCRO, MACRO, MACCYR, MACUK, MACGR, MACTU, MACHEB, MACAR, MACTH, ROMAN8, - NEXTSTEP, ARMASCII, GEORGIAN_AC, GEORGIAN_PS, KOI8_T, MULELAO, CP1133, - TIS620, CP874, VISCII, TCVN, ISO_IR_14, JIS_X0201, JIS_X0208, JIS_X0212, - GB1988_80, GB2312_80, ISO_IR_165, ISO_IR_149, EUC_JP, SHIFT_JIS, CP932, - ISO_2022_JP, ISO_2022_JP1, ISO_2022_JP2, GB2312, CP936, GB18030, - ISO_2022_CN, ISO_2022_CNE, HZ, EUC_TW, BIG5, CP950, BIG5_HKSCS, EUC_KR, - CP949, CP1361, ISO_2022_KR, CP737, CP775, CP853, CP855, CP857, CP858, - CP860, CP861, CP863, CP864, CP865, CP869, CP1125]; - - {:Set of charsets supported by internal routines only.} - NoIconvChars: set of TMimeChar = [CP895, UTF_7mod]; - - {:null character replace table. (Usable for disable charater replacing.)} - Replace_None: array[0..0] of Word = - (0); - - {:Character replace table for remove Czech diakritics.} - Replace_Czech: array[0..59] of Word = - ( - $00E1, $0061, - $010D, $0063, - $010F, $0064, - $010E, $0044, - $00E9, $0065, - $011B, $0065, - $00ED, $0069, - $0148, $006E, - $00F3, $006F, - $0159, $0072, - $0161, $0073, - $0165, $0074, - $00FA, $0075, - $016F, $0075, - $00FD, $0079, - $017E, $007A, - $00C1, $0041, - $010C, $0043, - $00C9, $0045, - $011A, $0045, - $00CD, $0049, - $0147, $004E, - $00D3, $004F, - $0158, $0052, - $0160, $0053, - $0164, $0054, - $00DA, $0055, - $016E, $0055, - $00DD, $0059, - $017D, $005A - ); - -var - {:By this you can generally disable/enable Iconv support.} - DisableIconv: Boolean = False; - - {:Default set of charsets for @link(IdealCharsetCoding) function.} - IdealCharsets: TMimeSetChar = - [ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, - ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, - KOI8_R, KOI8_U - {$IFNDEF CIL} //error URW778 ??? :-O - , GB2312, EUC_KR, ISO_2022_JP, EUC_TW - {$ENDIF} - ]; - -{==============================================================================} -{:Convert Value from one charset to another. See: @link(CharsetConversionEx)} -function CharsetConversion(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar): AnsiString; - -{:Convert Value from one charset to another with additional character conversion. -see: @link(Replace_None) and @link(Replace_Czech)} -function CharsetConversionEx(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word): AnsiString; - -{:Convert Value from one charset to another with additional character conversion. - This funtion is similar to @link(CharsetConversionEx), but you can disable - transliteration of unconvertible characters.} -function CharsetConversionTrans(Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word; Translit: Boolean): AnsiString; - -{:Returns charset used by operating system.} -function GetCurCP: TMimeChar; - -{:Returns charset used by operating system as OEM charset. (in Windows DOS box, - for example)} -function GetCurOEMCP: TMimeChar; - -{:Converting string with charset name to TMimeChar.} -function GetCPFromID(Value: AnsiString): TMimeChar; - -{:Converting TMimeChar to string with name of charset.} -function GetIDFromCP(Value: TMimeChar): AnsiString; - -{:return @true when value need to be converted. (It is not 7-bit ASCII)} -function NeedCharsetConversion(const Value: AnsiString): Boolean; - -{:Finding best target charset from set of TMimeChars with minimal count of - unconvertible characters.} -function IdealCharsetCoding(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeSetChar): TMimeChar; - -{:Return BOM (Byte Order Mark) for given unicode charset.} -function GetBOM(Value: TMimeChar): AnsiString; - -{:Convert binary string with unicode content to WideString.} -function StringToWide(const Value: AnsiString): WideString; - -{:Convert WideString to binary string with unicode content.} -function WideToString(const Value: WideString): AnsiString; - -function GetIconvIDFromCP(Value: TMimeChar): AnsiString; -function GetCPFromIconvID(Value: AnsiString): TMimeChar; - -{==============================================================================} -implementation - -//character transcoding tables X to UCS-2 -{ -//dummy table -$0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, -$0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, -$0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, -$0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, -$00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, -$00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, -$00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, -$00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, -$00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, -$00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, -$00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, -$00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, -$00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, -$00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, -$00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, -$00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF -} - -const - -{Latin-1 - Danish, Dutch, English, Faeroese, Finnish, French, German, Icelandic, - Irish, Italian, Norwegian, Portuguese, Spanish and Swedish. -} - CharISO_8859_1: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF - ); - -{Latin-2 - Albanian, Czech, English, German, Hungarian, Polish, Rumanian, - Serbo-Croatian, Slovak, Slovene and Swedish. -} - CharISO_8859_2: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $02D8, $0141, $00A4, $013D, $015A, $00A7, - $00A8, $0160, $015E, $0164, $0179, $00AD, $017D, $017B, - $00B0, $0105, $02DB, $0142, $00B4, $013E, $015B, $02C7, - $00B8, $0161, $015F, $0165, $017A, $02DD, $017E, $017C, - $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, - $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, - $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7, - $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF, - $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7, - $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F, - $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7, - $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9 - ); - -{Latin-3 - Afrikaans, Catalan, English, Esperanto, French, Galician, - German, Italian, Maltese and Turkish. -} - CharISO_8859_3: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0126, $02D8, $00A3, $00A4, $FFFD, $0124, $00A7, - $00A8, $0130, $015E, $011E, $0134, $00AD, $FFFD, $017B, - $00B0, $0127, $00B2, $00B3, $00B4, $00B5, $0125, $00B7, - $00B8, $0131, $015F, $011F, $0135, $00BD, $FFFD, $017C, - $00C0, $00C1, $00C2, $FFFD, $00C4, $010A, $0108, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $FFFD, $00D1, $00D2, $00D3, $00D4, $0120, $00D6, $00D7, - $011C, $00D9, $00DA, $00DB, $00DC, $016C, $015C, $00DF, - $00E0, $00E1, $00E2, $FFFD, $00E4, $010B, $0109, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $FFFD, $00F1, $00F2, $00F3, $00F4, $0121, $00F6, $00F7, - $011D, $00F9, $00FA, $00FB, $00FC, $016D, $015D, $02D9 - ); - -{Latin-4 - Danish, English, Estonian, Finnish, German, Greenlandic, - Lappish, Latvian, Lithuanian, Norwegian and Swedish. -} - CharISO_8859_4: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $0138, $0156, $00A4, $0128, $013B, $00A7, - $00A8, $0160, $0112, $0122, $0166, $00AD, $017D, $00AF, - $00B0, $0105, $02DB, $0157, $00B4, $0129, $013C, $02C7, - $00B8, $0161, $0113, $0123, $0167, $014A, $017E, $014B, - $0100, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $012E, - $010C, $00C9, $0118, $00CB, $0116, $00CD, $00CE, $012A, - $0110, $0145, $014C, $0136, $00D4, $00D5, $00D6, $00D7, - $00D8, $0172, $00DA, $00DB, $00DC, $0168, $016A, $00DF, - $0101, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $012F, - $010D, $00E9, $0119, $00EB, $0117, $00ED, $00EE, $012B, - $0111, $0146, $014D, $0137, $00F4, $00F5, $00F6, $00F7, - $00F8, $0173, $00FA, $00FB, $00FC, $0169, $016B, $02D9 - ); - -{CYRILLIC - Bulgarian, Bielorussian, English, Macedonian, Russian, - Serbo-Croatian and Ukrainian. -} - CharISO_8859_5: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0401, $0402, $0403, $0404, $0405, $0406, $0407, - $0408, $0409, $040A, $040B, $040C, $00AD, $040E, $040F, - $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417, - $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, - $0420, $0421, $0422, $0423, $0424, $0425, $0426, $0427, - $0428, $0429, $042A, $042B, $042C, $042D, $042E, $042F, - $0430, $0431, $0432, $0433, $0434, $0435, $0436, $0437, - $0438, $0439, $043A, $043B, $043C, $043D, $043E, $043F, - $0440, $0441, $0442, $0443, $0444, $0445, $0446, $0447, - $0448, $0449, $044A, $044B, $044C, $044D, $044E, $044F, - $2116, $0451, $0452, $0453, $0454, $0455, $0456, $0457, - $0458, $0459, $045A, $045B, $045C, $00A7, $045E, $045F - ); - -{ARABIC -} - CharISO_8859_6: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $FFFD, $FFFD, $FFFD, $00A4, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $060C, $00AD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $061B, $FFFD, $FFFD, $FFFD, $061F, - $FFFD, $0621, $0622, $0623, $0624, $0625, $0626, $0627, - $0628, $0629, $062A, $062B, $062C, $062D, $062E, $062F, - $0630, $0631, $0632, $0633, $0634, $0635, $0636, $0637, - $0638, $0639, $063A, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $0640, $0641, $0642, $0643, $0644, $0645, $0646, $0647, - $0648, $0649, $064A, $064B, $064C, $064D, $064E, $064F, - $0650, $0651, $0652, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD - ); - -{GREEK -} - CharISO_8859_7: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $2018, $2019, $00A3, $FFFD, $FFFD, $00A6, $00A7, - $00A8, $00A9, $FFFD, $00AB, $00AC, $00AD, $FFFD, $2015, - $00B0, $00B1, $00B2, $00B3, $0384, $0385, $0386, $00B7, - $0388, $0389, $038A, $00BB, $038C, $00BD, $038E, $038F, - $0390, $0391, $0392, $0393, $0394, $0395, $0396, $0397, - $0398, $0399, $039A, $039B, $039C, $039D, $039E, $039F, - $03A0, $03A1, $FFFD, $03A3, $03A4, $03A5, $03A6, $03A7, - $03A8, $03A9, $03AA, $03AB, $03AC, $03AD, $03AE, $03AF, - $03B0, $03B1, $03B2, $03B3, $03B4, $03B5, $03B6, $03B7, - $03B8, $03B9, $03BA, $03BB, $03BC, $03BD, $03BE, $03BF, - $03C0, $03C1, $03C2, $03C3, $03C4, $03C5, $03C6, $03C7, - $03C8, $03C9, $03CA, $03CB, $03CC, $03CD, $03CE, $FFFD - ); - -{HEBREW -} - CharISO_8859_8: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $FFFD, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00D7, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00F7, $00BB, $00BC, $00BD, $00BE, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $2017, - $05D0, $05D1, $05D2, $05D3, $05D4, $05D5, $05D6, $05D7, - $05D8, $05D9, $05DA, $05DB, $05DC, $05DD, $05DE, $05DF, - $05E0, $05E1, $05E2, $05E3, $05E4, $05E5, $05E6, $05E7, - $05E8, $05E9, $05EA, $FFFD, $FFFD, $200E, $200F, $FFFD - ); - -{Latin-5 - English, Finnish, French, German, Irish, Italian, Norwegian, - Portuguese, Spanish, Swedish and Turkish. -} - CharISO_8859_9: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $02D8, $0141, $00A4, $013D, $015A, $00A7, - $00A8, $0160, $015E, $0164, $0179, $00AD, $017D, $017B, - $00B0, $0105, $02DB, $0142, $00B4, $013E, $015B, $02C7, - $00B8, $0161, $015F, $0165, $017A, $02DD, $017E, $017C, - $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, - $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, - $011E, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $0130, $015E, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $011F, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $0131, $015F, $00FF - ); - -{Latin-6 - Danish, English, Estonian, Faeroese, Finnish, German, Greenlandic, - Icelandic, Lappish, Latvian, Lithuanian, Norwegian and Swedish. -} - CharISO_8859_10: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $0112, $0122, $012A, $0128, $0136, $00A7, - $013B, $0110, $0160, $0166, $017D, $00AD, $016A, $014A, - $00B0, $0105, $0113, $0123, $012B, $0129, $0137, $00B7, - $013C, $0111, $0161, $0167, $017E, $2015, $016B, $014B, - $0100, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $012E, - $010C, $00C9, $0118, $00CB, $0116, $00CD, $00CE, $00CF, - $00D0, $0145, $014C, $00D3, $00D4, $00D5, $00D6, $0168, - $00D8, $0172, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $0101, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $012F, - $010D, $00E9, $0119, $00EB, $0117, $00ED, $00EE, $00EF, - $00F0, $0146, $014D, $00F3, $00F4, $00F5, $00F6, $0169, - $00F8, $0173, $00FA, $00FB, $00FC, $00FD, $00FE, $0138 - ); - - CharISO_8859_13: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $201D, $00A2, $00A3, $00A4, $201E, $00A6, $00A7, - $00D8, $00A9, $0156, $00AB, $00AC, $00AD, $00AE, $00C6, - $00B0, $00B1, $00B2, $00B3, $201C, $00B5, $00B6, $00B7, - $00F8, $00B9, $0157, $00BB, $00BC, $00BD, $00BE, $00E6, - $0104, $012E, $0100, $0106, $00C4, $00C5, $0118, $0112, - $010C, $00C9, $0179, $0116, $0122, $0136, $012A, $013B, - $0160, $0143, $0145, $00D3, $014C, $00D5, $00D6, $00D7, - $0172, $0141, $015A, $016A, $00DC, $017B, $017D, $00DF, - $0105, $012F, $0101, $0107, $00E4, $00E5, $0119, $0113, - $010D, $00E9, $017A, $0117, $0123, $0137, $012B, $013C, - $0161, $0144, $0146, $00F3, $014D, $00F5, $00F6, $00F7, - $0173, $0142, $015B, $016B, $00FC, $017C, $017E, $2019 - ); - - CharISO_8859_14: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $1E02, $1E03, $00A3, $010A, $010B, $1E0A, $00A7, - $1E80, $00A9, $1E82, $1E0B, $1EF2, $00AD, $00AE, $0178, - $1E1E, $1E1F, $0120, $0121, $1E40, $1E41, $00B6, $1E56, - $1E81, $1E57, $1E83, $1E60, $1EF3, $1E84, $1E85, $1E61, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $0174, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $1E6A, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $0176, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $0175, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $1E6B, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $0177, $00FF - ); - - CharISO_8859_15: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $00A1, $00A2, $00A3, $20AC, $00A5, $0160, $00A7, - $0161, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $017D, $00B5, $00B6, $00B7, - $017E, $00B9, $00BA, $00BB, $0152, $0153, $0178, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF - ); - -{Eastern European -} - CharCP_1250: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $FFFD, $201E, $2026, $2020, $2021, - $FFFD, $2030, $0160, $2039, $015A, $0164, $017D, $0179, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $0161, $203A, $015B, $0165, $017E, $017A, - $00A0, $02C7, $02D8, $0141, $00A4, $0104, $00A6, $00A7, - $00A8, $00A9, $015E, $00AB, $00AC, $00AD, $00AE, $017B, - $00B0, $00B1, $02DB, $0142, $00B4, $00B5, $00B6, $00B7, - $00B8, $0105, $015F, $00BB, $013D, $02DD, $013E, $017C, - $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, - $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, - $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7, - $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF, - $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7, - $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F, - $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7, - $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9 - ); - -{Cyrillic -} - CharCP_1251: array[128..255] of Word = - ( - $0402, $0403, $201A, $0453, $201E, $2026, $2020, $2021, - $20AC, $2030, $0409, $2039, $040A, $040C, $040B, $040F, - $0452, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $0459, $203A, $045A, $045C, $045B, $045F, - $00A0, $040E, $045E, $0408, $00A4, $0490, $00A6, $00A7, - $0401, $00A9, $0404, $00AB, $00AC, $00AD, $00AE, $0407, - $00B0, $00B1, $0406, $0456, $0491, $00B5, $00B6, $00B7, - $0451, $2116, $0454, $00BB, $0458, $0405, $0455, $0457, - $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417, - $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, - $0420, $0421, $0422, $0423, $0424, $0425, $0426, $0427, - $0428, $0429, $042A, $042B, $042C, $042D, $042E, $042F, - $0430, $0431, $0432, $0433, $0434, $0435, $0436, $0437, - $0438, $0439, $043A, $043B, $043C, $043D, $043E, $043F, - $0440, $0441, $0442, $0443, $0444, $0445, $0446, $0447, - $0448, $0449, $044A, $044B, $044C, $044D, $044E, $044F - ); - -{Latin-1 (US, Western Europe) -} - CharCP_1252: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $0160, $2039, $0152, $FFFD, $017D, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $0161, $203A, $0153, $FFFD, $017E, $0178, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF - ); - -{Greek -} - CharCP_1253: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $FFFD, $2030, $FFFD, $2039, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $FFFD, $203A, $FFFD, $FFFD, $FFFD, $FFFD, - $00A0, $0385, $0386, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $FFFD, $00AB, $00AC, $00AD, $00AE, $2015, - $00B0, $00B1, $00B2, $00B3, $0384, $00B5, $00B6, $00B7, - $0388, $0389, $038A, $00BB, $038C, $00BD, $038E, $038F, - $0390, $0391, $0392, $0393, $0394, $0395, $0396, $0397, - $0398, $0399, $039A, $039B, $039C, $039D, $039E, $039F, - $03A0, $03A1, $FFFD, $03A3, $03A4, $03A5, $03A6, $03A7, - $03A8, $03A9, $03AA, $03AB, $03AC, $03AD, $03AE, $03AF, - $03B0, $03B1, $03B2, $03B3, $03B4, $03B5, $03B6, $03B7, - $03B8, $03B9, $03BA, $03BB, $03BC, $03BD, $03BE, $03BF, - $03C0, $03C1, $03C2, $03C3, $03C4, $03C5, $03C6, $03C7, - $03C8, $03C9, $03CA, $03CB, $03CC, $03CD, $03CE, $FFFD - ); - -{Turkish -} - CharCP_1254: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $0160, $2039, $0152, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $0161, $203A, $0153, $FFFD, $FFFD, $0178, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $011E, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $0130, $015E, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $011F, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $0131, $015F, $00FF - ); - -{Hebrew -} - CharCP_1255: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $FFFD, $2039, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $FFFD, $203A, $FFFD, $FFFD, $FFFD, $FFFD, - $00A0, $00A1, $00A2, $00A3, $20AA, $00A5, $00A6, $00A7, - $00A8, $00A9, $00D7, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00F7, $00BB, $00BC, $00BD, $00BE, $00BF, - $05B0, $05B1, $05B2, $05B3, $05B4, $05B5, $05B6, $05B7, - $05B8, $05B9, $FFFD, $05BB, $05BC, $05BD, $05BE, $05BF, - $05C0, $05C1, $05C2, $05C3, $05F0, $05F1, $05F2, $05F3, - $05F4, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $05D0, $05D1, $05D2, $05D3, $05D4, $05D5, $05D6, $05D7, - $05D8, $05D9, $05DA, $05DB, $05DC, $05DD, $05DE, $05DF, - $05E0, $05E1, $05E2, $05E3, $05E4, $05E5, $05E6, $05E7, - $05E8, $05E9, $05EA, $FFFD, $FFFD, $200E, $200F, $FFFD - ); - -{Arabic -} - CharCP_1256: array[128..255] of Word = - ( - $20AC, $067E, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $0679, $2039, $0152, $0686, $0698, $0688, - $06AF, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $06A9, $2122, $0691, $203A, $0153, $200C, $200D, $06BA, - $00A0, $060C, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $06BE, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $061B, $00BB, $00BC, $00BD, $00BE, $061F, - $06C1, $0621, $0622, $0623, $0624, $0625, $0626, $0627, - $0628, $0629, $062A, $062B, $062C, $062D, $062E, $062F, - $0630, $0631, $0632, $0633, $0634, $0635, $0636, $00D7, - $0637, $0638, $0639, $063A, $0640, $0641, $0642, $0643, - $00E0, $0644, $00E2, $0645, $0646, $0647, $0648, $00E7, - $00E8, $00E9, $00EA, $00EB, $0649, $064A, $00EE, $00EF, - $064B, $064C, $064D, $064E, $00F4, $064F, $0650, $00F7, - $0651, $00F9, $0652, $00FB, $00FC, $200E, $200F, $06D2 - ); - -{Baltic -} - CharCP_1257: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $FFFD, $201E, $2026, $2020, $2021, - $FFFD, $2030, $FFFD, $2039, $FFFD, $00A8, $02C7, $00B8, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $FFFD, $203A, $FFFD, $00AF, $02DB, $FFFD, - $00A0, $FFFD, $00A2, $00A3, $00A4, $FFFD, $00A6, $00A7, - $00D8, $00A9, $0156, $00AB, $00AC, $00AD, $00AE, $00C6, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00F8, $00B9, $0157, $00BB, $00BC, $00BD, $00BE, $00E6, - $0104, $012E, $0100, $0106, $00C4, $00C5, $0118, $0112, - $010C, $00C9, $0179, $0116, $0122, $0136, $012A, $013B, - $0160, $0143, $0145, $00D3, $014C, $00D5, $00D6, $00D7, - $0172, $0141, $015A, $016A, $00DC, $017B, $017D, $00DF, - $0105, $012F, $0101, $0107, $00E4, $00E5, $0119, $0113, - $010D, $00E9, $017A, $0117, $0123, $0137, $012B, $013C, - $0161, $0144, $0146, $00F3, $014D, $00F5, $00F6, $00F7, - $0173, $0142, $015B, $016B, $00FC, $017C, $017E, $02D9 - ); - -{Vietnamese -} - CharCP_1258: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $FFFD, $2039, $0152, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $FFFD, $203A, $0153, $FFFD, $FFFD, $0178, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $0102, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $0300, $00CD, $00CE, $00CF, - $0110, $00D1, $0309, $00D3, $00D4, $01A0, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $01AF, $0303, $00DF, - $00E0, $00E1, $00E2, $0103, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $0301, $00ED, $00EE, $00EF, - $0111, $00F1, $0323, $00F3, $00F4, $01A1, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $01B0, $20AB, $00FF - ); - -{Cyrillic -} - CharKOI8_R: array[128..255] of Word = - ( - $2500, $2502, $250C, $2510, $2514, $2518, $251C, $2524, - $252C, $2534, $253C, $2580, $2584, $2588, $258C, $2590, - $2591, $2592, $2593, $2320, $25A0, $2219, $221A, $2248, - $2264, $2265, $00A0, $2321, $00B0, $00B2, $00B7, $00F7, - $2550, $2551, $2552, $0451, $2553, $2554, $2555, $2556, - $2557, $2558, $2559, $255A, $255B, $255C, $255D, $255E, - $255F, $2560, $2561, $0401, $2562, $2563, $2564, $2565, - $2566, $2567, $2568, $2569, $256A, $256B, $256C, $00A9, - $044E, $0430, $0431, $0446, $0434, $0435, $0444, $0433, - $0445, $0438, $0439, $043A, $043B, $043C, $043D, $043E, - $043F, $044F, $0440, $0441, $0442, $0443, $0436, $0432, - $044C, $044B, $0437, $0448, $044D, $0449, $0447, $044A, - $042E, $0410, $0411, $0426, $0414, $0415, $0424, $0413, - $0425, $0418, $0419, $041A, $041B, $041C, $041D, $041E, - $041F, $042F, $0420, $0421, $0422, $0423, $0416, $0412, - $042C, $042B, $0417, $0428, $042D, $0429, $0427, $042A - ); - -{Czech (Kamenicky) -} - CharCP_895: array[128..255] of Word = - ( - $010C, $00FC, $00E9, $010F, $00E4, $010E, $0164, $010D, - $011B, $011A, $0139, $00CD, $013E, $013A, $00C4, $00C1, - $00C9, $017E, $017D, $00F4, $00F6, $00D3, $016F, $00DA, - $00FD, $00D6, $00DC, $0160, $013D, $00DD, $0158, $0165, - $00E1, $00ED, $00F3, $00FA, $0148, $0147, $016E, $00D4, - $0161, $0159, $0155, $0154, $00BC, $00A7, $00AB, $00BB, - $2591, $2592, $2593, $2502, $2524, $2561, $2562, $2556, - $2555, $2563, $2551, $2557, $255D, $255C, $255B, $2510, - $2514, $2534, $252C, $251C, $2500, $253C, $255E, $255F, - $255A, $2554, $2569, $2566, $2560, $2550, $256C, $2567, - $2568, $2564, $2565, $2559, $2558, $2552, $2553, $256B, - $256A, $2518, $250C, $2588, $2584, $258C, $2590, $2580, - $03B1, $03B2, $0393, $03C0, $03A3, $03C3, $03BC, $03C4, - $03A6, $0398, $03A9, $03B4, $221E, $2205, $03B5, $2229, - $2261, $00B1, $2265, $2264, $2320, $2321, $00F7, $2248, - $2218, $00B7, $2219, $221A, $207F, $00B2, $25A0, $00A0 - ); - -{Eastern European -} - CharCP_852: array[128..255] of Word = - ( - $00C7, $00FC, $00E9, $00E2, $00E4, $016F, $0107, $00E7, - $0142, $00EB, $0150, $0151, $00EE, $0179, $00C4, $0106, - $00C9, $0139, $013A, $00F4, $00F6, $013D, $013E, $015A, - $015B, $00D6, $00DC, $0164, $0165, $0141, $00D7, $010D, - $00E1, $00ED, $00F3, $00FA, $0104, $0105, $017D, $017E, - $0118, $0119, $00AC, $017A, $010C, $015F, $00AB, $00BB, - $2591, $2592, $2593, $2502, $2524, $00C1, $00C2, $011A, - $015E, $2563, $2551, $2557, $255D, $017B, $017C, $2510, - $2514, $2534, $252C, $251C, $2500, $253C, $0102, $0103, - $255A, $2554, $2569, $2566, $2560, $2550, $256C, $00A4, - $0111, $0110, $010E, $00CB, $010F, $0147, $00CD, $00CE, - $011B, $2518, $250C, $2588, $2584, $0162, $016E, $2580, - $00D3, $00DF, $00D4, $0143, $0144, $0148, $0160, $0161, - $0154, $00DA, $0155, $0170, $00FD, $00DD, $0163, $00B4, - $00AD, $02DD, $02DB, $02C7, $02D8, $00A7, $00F7, $00B8, - $00B0, $00A8, $02D9, $0171, $0158, $0159, $25A0, $00A0 - ); - -{==============================================================================} -type - TIconvChar = record - Charset: TMimeChar; - CharName: string; - end; - TIconvArr = array [0..112] of TIconvChar; - -const - NotFoundChar = '_'; - -var - SetTwo: set of TMimeChar = [UCS_2, UCS_2LE, UTF_7, UTF_7mod]; - SetFour: set of TMimeChar = [UCS_4, UCS_4LE, UTF_8]; - SetLE: set of TMimeChar = [UCS_2LE, UCS_4LE]; - - IconvArr: TIconvArr; - -{==============================================================================} -function FindIconvID(const Value, Charname: string): Boolean; -var - s: string; -begin - Result := True; - //exact match - if Value = Charname then - Exit; - //Value is on begin of charname - s := Value + ' '; - if s = Copy(Charname, 1, Length(s)) then - Exit; - //Value is on end of charname - s := ' ' + Value; - if s = Copy(Charname, Length(Charname) - Length(s) + 1, Length(s)) then - Exit; - //value is somewhere inside charname - if Pos( s + ' ', Charname) > 0 then - Exit; - Result := False; -end; - -function GetCPFromIconvID(Value: AnsiString): TMimeChar; -var - n: integer; -begin - Result := ISO_8859_1; - Value := UpperCase(Value); - for n := 0 to High(IconvArr) do - if FindIconvID(Value, IconvArr[n].Charname) then - begin - Result := IconvArr[n].Charset; - Break; - end; -end; - -{==============================================================================} -function GetIconvIDFromCP(Value: TMimeChar): AnsiString; -var - n: integer; -begin - Result := 'ISO-8859-1'; - for n := 0 to High(IconvArr) do - if IconvArr[n].Charset = Value then - begin - Result := Separateleft(IconvArr[n].Charname, ' '); - Break; - end; -end; - -{==============================================================================} -function ReplaceUnicode(Value: Word; const TransformTable: array of Word): Word; -var - n: integer; -begin - if High(TransformTable) <> 0 then - for n := 0 to High(TransformTable) do - if not odd(n) then - if TransformTable[n] = Value then - begin - Value := TransformTable[n+1]; - break; - end; - Result := Value; -end; - -{==============================================================================} -procedure CopyArray(const SourceTable: array of Word; - var TargetTable: array of Word); -var - n: Integer; -begin - for n := 0 to 127 do - TargetTable[n] := SourceTable[n]; -end; - -{==============================================================================} -procedure GetArray(CharSet: TMimeChar; var Result: array of Word); -begin - case CharSet of - ISO_8859_2: - CopyArray(CharISO_8859_2, Result); - ISO_8859_3: - CopyArray(CharISO_8859_3, Result); - ISO_8859_4: - CopyArray(CharISO_8859_4, Result); - ISO_8859_5: - CopyArray(CharISO_8859_5, Result); - ISO_8859_6: - CopyArray(CharISO_8859_6, Result); - ISO_8859_7: - CopyArray(CharISO_8859_7, Result); - ISO_8859_8: - CopyArray(CharISO_8859_8, Result); - ISO_8859_9: - CopyArray(CharISO_8859_9, Result); - ISO_8859_10: - CopyArray(CharISO_8859_10, Result); - ISO_8859_13: - CopyArray(CharISO_8859_13, Result); - ISO_8859_14: - CopyArray(CharISO_8859_14, Result); - ISO_8859_15: - CopyArray(CharISO_8859_15, Result); - CP1250: - CopyArray(CharCP_1250, Result); - CP1251: - CopyArray(CharCP_1251, Result); - CP1252: - CopyArray(CharCP_1252, Result); - CP1253: - CopyArray(CharCP_1253, Result); - CP1254: - CopyArray(CharCP_1254, Result); - CP1255: - CopyArray(CharCP_1255, Result); - CP1256: - CopyArray(CharCP_1256, Result); - CP1257: - CopyArray(CharCP_1257, Result); - CP1258: - CopyArray(CharCP_1258, Result); - KOI8_R: - CopyArray(CharKOI8_R, Result); - CP895: - CopyArray(CharCP_895, Result); - CP852: - CopyArray(CharCP_852, Result); - else - CopyArray(CharISO_8859_1, Result); - end; -end; - -{==============================================================================} -procedure ReadMulti(const Value: AnsiString; var Index: Integer; mb: Byte; - var b1, b2, b3, b4: Byte; le: boolean); -Begin - b1 := 0; - b2 := 0; - b3 := 0; - b4 := 0; - if Index < 0 then - Index := 1; - if mb > 4 then - mb := 1; - if (Index + mb - 1) <= Length(Value) then - begin - if le then - Case mb Of - 1: - b1 := Ord(Value[Index]); - 2: - Begin - b1 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - End; - 3: - Begin - b1 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - b3 := Ord(Value[Index + 2]); - End; - 4: - Begin - b1 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - b3 := Ord(Value[Index + 2]); - b4 := Ord(Value[Index + 3]); - End; - end - else - Case mb Of - 1: - b1 := Ord(Value[Index]); - 2: - Begin - b2 := Ord(Value[Index]); - b1 := Ord(Value[Index + 1]); - End; - 3: - Begin - b3 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - b1 := Ord(Value[Index + 2]); - End; - 4: - Begin - b4 := Ord(Value[Index]); - b3 := Ord(Value[Index + 1]); - b2 := Ord(Value[Index + 2]); - b1 := Ord(Value[Index + 3]); - End; - end; - end; - Inc(Index, mb); -end; - -{==============================================================================} -function WriteMulti(b1, b2, b3, b4: Byte; mb: Byte; le: boolean): AnsiString; -begin - if mb > 4 then - mb := 1; - SetLength(Result, mb); - if le then - case mb Of - 1: - Result[1] := AnsiChar(b1); - 2: - begin - Result[1] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - end; - 3: - begin - Result[1] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - Result[3] := AnsiChar(b3); - end; - 4: - begin - Result[1] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - Result[3] := AnsiChar(b3); - Result[4] := AnsiChar(b4); - end; - end - else - case mb Of - 1: - Result[1] := AnsiChar(b1); - 2: - begin - Result[2] := AnsiChar(b1); - Result[1] := AnsiChar(b2); - end; - 3: - begin - Result[3] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - Result[1] := AnsiChar(b3); - end; - 4: - begin - Result[4] := AnsiChar(b1); - Result[3] := AnsiChar(b2); - Result[2] := AnsiChar(b3); - Result[1] := AnsiChar(b4); - end; - end; -end; - -{==============================================================================} -function UTF8toUCS4(const Value: AnsiString): AnsiString; -var - n, x, ul, m: Integer; - s: AnsiString; - w1, w2: Word; -begin - Result := ''; - n := 1; - while Length(Value) >= n do - begin - x := Ord(Value[n]); - Inc(n); - if x < 128 then - Result := Result + WriteMulti(x, 0, 0, 0, 4, false) - else - begin - m := 0; - if (x and $E0) = $C0 then - m := $1F; - if (x and $F0) = $E0 then - m := $0F; - if (x and $F8) = $F0 then - m := $07; - if (x and $FC) = $F8 then - m := $03; - if (x and $FE) = $FC then - m := $01; - ul := x and m; - s := IntToBin(ul, 0); - while Length(Value) >= n do - begin - x := Ord(Value[n]); - Inc(n); - if (x and $C0) = $80 then - s := s + IntToBin(x and $3F, 6) - else - begin - Dec(n); - Break; - end; - end; - ul := BinToInt(s); - w1 := ul div 65536; - w2 := ul mod 65536; - Result := Result + WriteMulti(Lo(w2), Hi(w2), Lo(w1), Hi(w1), 4, false); - end; - end; -end; - -{==============================================================================} -function UCS4toUTF8(const Value: AnsiString): AnsiString; -var - s, l, k: AnsiString; - b1, b2, b3, b4: Byte; - n, m, x, y: Integer; - b: Byte; -begin - Result := ''; - n := 1; - while Length(Value) >= n do - begin - ReadMulti(Value, n, 4, b1, b2, b3, b4, false); - if (b2 = 0) and (b3 = 0) and (b4 = 0) and (b1 < 128) then - Result := Result + AnsiChar(b1) - else - begin - x := (b1 + 256 * b2) + (b3 + 256 * b4) * 65536; - l := IntToBin(x, 0); - y := Length(l) div 6; - s := ''; - for m := 1 to y do - begin - k := Copy(l, Length(l) - 5, 6); - l := Copy(l, 1, Length(l) - 6); - b := BinToInt(k) or $80; - s := AnsiChar(b) + s; - end; - b := BinToInt(l); - case y of - 5: - b := b or $FC; - 4: - b := b or $F8; - 3: - b := b or $F0; - 2: - b := b or $E0; - 1: - b := b or $C0; - end; - s := AnsiChar(b) + s; - Result := Result + s; - end; - end; -end; - -{==============================================================================} -function UTF7toUCS2(const Value: AnsiString; Modified: Boolean): AnsiString; -var - n, i: Integer; - c: AnsiChar; - s, t: AnsiString; - shift: AnsiChar; - table: String; -begin - Result := ''; - n := 1; - if modified then - begin - shift := '&'; - table := TableBase64mod; - end - else - begin - shift := '+'; - table := TableBase64; - end; - while Length(Value) >= n do - begin - c := Value[n]; - Inc(n); - if c <> shift then - Result := Result + WriteMulti(Ord(c), 0, 0, 0, 2, false) - else - begin - s := ''; - while Length(Value) >= n do - begin - c := Value[n]; - Inc(n); - if c = '-' then - Break; - if (c = '=') or (Pos(c, table) < 1) then - begin - Dec(n); - Break; - end; - s := s + c; - end; - if s = '' then - s := WriteMulti(Ord(shift), 0, 0, 0, 2, false) - else - begin - if modified then - t := DecodeBase64mod(s) - else - t := DecodeBase64(s); - if not odd(length(t)) then - s := t - else - begin //ill-formed sequence - t := s; - s := WriteMulti(Ord(shift), 0, 0, 0, 2, false); - for i := 1 to length(t) do - s := s + WriteMulti(Ord(t[i]), 0, 0, 0, 2, false); - end; - end; - Result := Result + s; - end; - end; -end; - -{==============================================================================} -function UCS2toUTF7(const Value: AnsiString; Modified: Boolean): AnsiString; -var - s: AnsiString; - b1, b2, b3, b4: Byte; - n, m: Integer; - shift: AnsiChar; -begin - Result := ''; - n := 1; - if modified then - shift := '&' - else - shift := '+'; - while Length(Value) >= n do - begin - ReadMulti(Value, n, 2, b1, b2, b3, b4, false); - if (b2 = 0) and (b1 < 128) then - if AnsiChar(b1) = shift then - Result := Result + shift + '-' - else - Result := Result + AnsiChar(b1) - else - begin - s := AnsiChar(b2) + AnsiChar(b1); - while Length(Value) >= n do - begin - ReadMulti(Value, n, 2, b1, b2, b3, b4, false); - if (b2 = 0) and (b1 < 128) then - begin - Dec(n, 2); - Break; - end; - s := s + AnsiChar(b2) + AnsiChar(b1); - end; - if modified then - s := EncodeBase64mod(s) - else - s := EncodeBase64(s); - m := Pos('=', s); - if m > 0 then - s := Copy(s, 1, m - 1); - Result := Result + shift + s + '-'; - end; - end; -end; - -{==============================================================================} -function CharsetConversion(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar): AnsiString; -begin - Result := CharsetConversionEx(Value, CharFrom, CharTo, Replace_None); -end; - -{==============================================================================} -function CharsetConversionEx(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word): AnsiString; -begin - Result := CharsetConversionTrans(Value, CharFrom, CharTo, TransformTable, True); -end; - -{==============================================================================} - -function InternalToUcs(const Value: AnsiString; Charfrom: TMimeChar): AnsiString; -var - uni: Word; - n: Integer; - b1, b2, b3, b4: Byte; - SourceTable: array[128..255] of Word; - mbf: Byte; - lef: Boolean; - s: AnsiString; -begin - if CharFrom = UTF_8 then - s := UTF8toUCS4(Value) - else - if CharFrom = UTF_7 then - s := UTF7toUCS2(Value, False) - else - if CharFrom = UTF_7mod then - s := UTF7toUCS2(Value, True) - else - s := Value; - GetArray(CharFrom, SourceTable); - mbf := 1; - if CharFrom in SetTwo then - mbf := 2; - if CharFrom in SetFour then - mbf := 4; - lef := CharFrom in SetLe; - Result := ''; - n := 1; - while Length(s) >= n do - begin - ReadMulti(s, n, mbf, b1, b2, b3, b4, lef); - //handle BOM - if (b3 = 0) and (b4 = 0) then - begin - if (b1 = $FE) and (b2 = $FF) then - begin - lef := not lef; - continue; - end; - if (b1 = $FF) and (b2 = $FE) then - continue; - end; - if mbf = 1 then - if b1 > 127 then - begin - uni := SourceTable[b1]; - b1 := Lo(uni); - b2 := Hi(uni); - end; - Result := Result + WriteMulti(b1, b2, b3, b4, 2, False); - end; -end; - -function CharsetConversionTrans(Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word; Translit: Boolean): AnsiString; -var - uni: Word; - n, m: Integer; - b: Byte; - b1, b2, b3, b4: Byte; - TargetTable: array[128..255] of Word; - mbt: Byte; - let: Boolean; - ucsstring, s, t: AnsiString; - cd: iconv_t; - f: Boolean; - NotNeedTransform: Boolean; - FromID, ToID: string; -begin - NotNeedTransform := (High(TransformTable) = 0); - if (CharFrom = CharTo) and NotNeedTransform then - begin - Result := Value; - Exit; - end; - FromID := GetIDFromCP(CharFrom); - ToID := GetIDFromCP(CharTo); - cd := Iconv_t(-1); - //do two-pass conversion. Transform to UCS-2 first. - if not DisableIconv then - cd := SynaIconvOpenIgnore('UCS-2BE', FromID); - try - if cd <> iconv_t(-1) then - SynaIconv(cd, Value, ucsstring) - else - ucsstring := InternalToUcs(Value, CharFrom); - finally - SynaIconvClose(cd); - end; - //here we allways have ucstring with UCS-2 encoding - //second pass... from UCS-2 to target encoding. - if not DisableIconv then - if translit then - cd := SynaIconvOpenTranslit(ToID, 'UCS-2BE') - else - cd := SynaIconvOpenIgnore(ToID, 'UCS-2BE'); - try - if (cd <> iconv_t(-1)) and NotNeedTransform then - begin - if CharTo = UTF_7 then - ucsstring := ucsstring + #0 + '-'; - //when transformtable is not needed and Iconv know target charset, - //do it fast by one call. - SynaIconv(cd, ucsstring, Result); - if CharTo = UTF_7 then - Delete(Result, Length(Result), 1); - end - else - begin - GetArray(CharTo, TargetTable); - mbt := 1; - if CharTo in SetTwo then - mbt := 2; - if CharTo in SetFour then - mbt := 4; - let := CharTo in SetLe; - b3 := 0; - b4 := 0; - Result := ''; - for n:= 0 to (Length(ucsstring) div 2) - 1 do - begin - s := Copy(ucsstring, n * 2 + 1, 2); - b2 := Ord(s[1]); - b1 := Ord(s[2]); - uni := b2 * 256 + b1; - if not NotNeedTransform then - begin - uni := ReplaceUnicode(uni, TransformTable); - b1 := Lo(uni); - b2 := Hi(uni); - s[1] := AnsiChar(b2); - s[2] := AnsiChar(b1); - end; - if cd <> iconv_t(-1) then - begin - if CharTo = UTF_7 then - s := s + #0 + '-'; - SynaIconv(cd, s, t); - if CharTo = UTF_7 then - Delete(t, Length(t), 1); - Result := Result + t; - end - else - begin - f := True; - if mbt = 1 then - if uni > 127 then - begin - f := False; - b := 0; - for m := 128 to 255 do - if TargetTable[m] = uni then - begin - b := m; - f := True; - Break; - end; - b1 := b; - b2 := 0; - end - else - b1 := Lo(uni); - if not f then - if translit then - begin - b1 := Ord(NotFoundChar); - b2 := 0; - f := True; - end; - if f then - Result := Result + WriteMulti(b1, b2, b3, b4, mbt, let) - end; - end; - if cd = iconv_t(-1) then - begin - if CharTo = UTF_7 then - Result := UCS2toUTF7(Result, false); - if CharTo = UTF_7mod then - Result := UCS2toUTF7(Result, true); - if CharTo = UTF_8 then - Result := UCS4toUTF8(Result); - end; - end; - finally - SynaIconvClose(cd); - end; -end; - -{==============================================================================} -{$IFNDEF MSWINDOWS} - -function GetCurCP: TMimeChar; -begin - {$IFNDEF FPC} - Result := GetCPFromID(nl_langinfo(_NL_CTYPE_CODESET_NAME)); - {$ELSE} - //How to get system codepage without LIBC? - Result := UTF_8; -{ TODO : Waiting for FPC 2.8 solution } - {$ENDIF} -end; - -function GetCurOEMCP: TMimeChar; -begin - Result := GetCurCP; -end; - -{$ELSE} - -function CPToMimeChar(Value: Integer): TMimeChar; -begin - case Value of - 437, 850, 20127: - Result := ISO_8859_1; //I know, it is not ideal! - 737: - Result := CP737; - 775: - Result := CP775; - 852: - Result := CP852; - 855: - Result := CP855; - 857: - Result := CP857; - 858: - Result := CP858; - 860: - Result := CP860; - 861: - Result := CP861; - 862: - Result := CP862; - 863: - Result := CP863; - 864: - Result := CP864; - 865: - Result := CP865; - 866: - Result := CP866; - 869: - Result := CP869; - 874: - Result := ISO_8859_15; - 895: - Result := CP895; - 932: - Result := CP932; - 936: - Result := CP936; - 949: - Result := CP949; - 950: - Result := CP950; - 1200: - Result := UCS_2LE; - 1201: - Result := UCS_2; - 1250: - Result := CP1250; - 1251: - Result := CP1251; - 1253: - Result := CP1253; - 1254: - Result := CP1254; - 1255: - Result := CP1255; - 1256: - Result := CP1256; - 1257: - Result := CP1257; - 1258: - Result := CP1258; - 1361: - Result := CP1361; - 10000: - Result := MAC; - 10004: - Result := MACAR; - 10005: - Result := MACHEB; - 10006: - Result := MACGR; - 10007: - Result := MACCYR; - 10010: - Result := MACRO; - 10017: - Result := MACUK; - 10021: - Result := MACTH; - 10029: - Result := MACCE; - 10079: - Result := MACICE; - 10081: - Result := MACTU; - 10082: - Result := MACCRO; - 12000: - Result := UCS_4LE; - 12001: - Result := UCS_4; - 20866: - Result := KOI8_R; - 20932: - Result := JIS_X0208; - 20936: - Result := GB2312; - 21866: - Result := KOI8_U; - 28591: - Result := ISO_8859_1; - 28592: - Result := ISO_8859_2; - 28593: - Result := ISO_8859_3; - 28594: - Result := ISO_8859_4; - 28595: - Result := ISO_8859_5; - 28596, 708: - Result := ISO_8859_6; - 28597: - Result := ISO_8859_7; - 28598, 38598: - Result := ISO_8859_8; - 28599: - Result := ISO_8859_9; - 28605: - Result := ISO_8859_15; - 50220: - Result := ISO_2022_JP; //? ISO 2022 Japanese with no halfwidth Katakana - 50221: - Result := ISO_2022_JP1;//? Japanese with halfwidth Katakana - 50222: - Result := ISO_2022_JP2;//? Japanese JIS X 0201-1989 - 50225: - Result := ISO_2022_KR; - 50227: - Result := ISO_2022_CN;//? ISO 2022 Simplified Chinese - 50229: - Result := ISO_2022_CNE;//? ISO 2022 Traditional Chinese - 51932: - Result := EUC_JP; - 51936: - Result := GB2312; - 51949: - Result := EUC_KR; - 52936: - Result := HZ; - 54936: - Result := GB18030; - 65000: - Result := UTF_7; - 65001: - Result := UTF_8; - 0: - Result := UCS_2LE; - else - Result := CP1252; - end; -end; - -function GetCurCP: TMimeChar; -begin - Result := CPToMimeChar(GetACP); -end; - -function GetCurOEMCP: TMimeChar; -begin - Result := CPToMimeChar(GetOEMCP); -end; -{$ENDIF} - -{==============================================================================} -function NeedCharsetConversion(const Value: AnsiString): Boolean; -var - n: Integer; -begin - Result := False; - for n := 1 to Length(Value) do - if (Ord(Value[n]) > 127) or (Ord(Value[n]) = 0) then - begin - Result := True; - Break; - end; -end; - -{==============================================================================} -function IdealCharsetCoding(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeSetChar): TMimeChar; -var - n: Integer; - max: Integer; - s, t, u: AnsiString; - CharSet: TMimeChar; -begin - Result := ISO_8859_1; - s := Copy(Value, 1, 1024); //max first 1KB for next procedure - max := 0; - for n := Ord(Low(TMimeChar)) to Ord(High(TMimeChar)) do - begin - CharSet := TMimeChar(n); - if CharSet in CharTo then - begin - t := CharsetConversionTrans(s, CharFrom, CharSet, Replace_None, False); - u := CharsetConversionTrans(t, CharSet, CharFrom, Replace_None, False); - if s = u then - begin - Result := CharSet; - Exit; - end; - if Length(u) > max then - begin - Result := CharSet; - max := Length(u); - end; - end; - end; -end; - -{==============================================================================} -function GetBOM(Value: TMimeChar): AnsiString; -begin - Result := ''; - case Value of - UCS_2: - Result := #$fe + #$ff; - UCS_4: - Result := #$00 + #$00 + #$fe + #$ff; - UCS_2LE: - Result := #$ff + #$fe; - UCS_4LE: - Result := #$ff + #$fe + #$00 + #$00; - UTF_8: - Result := #$ef + #$bb + #$bf; - end; -end; - -{==============================================================================} -function GetCPFromID(Value: AnsiString): TMimeChar; -begin - Value := UpperCase(Value); - if (Pos('KAMENICKY', Value) > 0) or (Pos('895', Value) > 0) then - Result := CP895 - else - if Pos('MUTF-7', Value) > 0 then - Result := UTF_7mod - else - Result := GetCPFromIconvID(Value); -end; - -{==============================================================================} -function GetIDFromCP(Value: TMimeChar): AnsiString; -begin - case Value of - CP895: - Result := 'CP-895'; - UTF_7mod: - Result := 'mUTF-7'; - else - Result := GetIconvIDFromCP(Value); - end; -end; - -{==============================================================================} -function StringToWide(const Value: AnsiString): WideString; -var - n: integer; - x, y: integer; -begin - SetLength(Result, Length(Value) div 2); - for n := 1 to Length(Value) div 2 do - begin - x := Ord(Value[((n-1) * 2) + 1]); - y := Ord(Value[((n-1) * 2) + 2]); - Result[n] := WideChar(x * 256 + y); - end; -end; - -{==============================================================================} -function WideToString(const Value: WideString): AnsiString; -var - n: integer; - x: integer; -begin - SetLength(Result, Length(Value) * 2); - for n := 1 to Length(Value) do - begin - x := Ord(Value[n]); - Result[((n-1) * 2) + 1] := AnsiChar(x div 256); - Result[((n-1) * 2) + 2] := AnsiChar(x mod 256); - end; -end; - -{==============================================================================} -initialization -begin - IconvArr[0].Charset := ISO_8859_1; - IconvArr[0].Charname := 'ISO-8859-1 CP819 IBM819 ISO-IR-100 ISO8859-1 ISO_8859-1 ISO_8859-1:1987 L1 LATIN1 CSISOLATIN1'; - IconvArr[1].Charset := UTF_8; - IconvArr[1].Charname := 'UTF-8'; - IconvArr[2].Charset := UCS_2; - IconvArr[2].Charname := 'ISO-10646-UCS-2 UCS-2 CSUNICODE'; - IconvArr[3].Charset := UCS_2; - IconvArr[3].Charname := 'UCS-2BE UNICODE-1-1 UNICODEBIG CSUNICODE11'; - IconvArr[4].Charset := UCS_2LE; - IconvArr[4].Charname := 'UCS-2LE UNICODELITTLE'; - IconvArr[5].Charset := UCS_4; - IconvArr[5].Charname := 'ISO-10646-UCS-4 UCS-4 CSUCS4'; - IconvArr[6].Charset := UCS_4; - IconvArr[6].Charname := 'UCS-4BE'; - IconvArr[7].Charset := UCS_2LE; - IconvArr[7].Charname := 'UCS-4LE'; - IconvArr[8].Charset := UTF_16; - IconvArr[8].Charname := 'UTF-16'; - IconvArr[9].Charset := UTF_16; - IconvArr[9].Charname := 'UTF-16BE'; - IconvArr[10].Charset := UTF_16LE; - IconvArr[10].Charname := 'UTF-16LE'; - IconvArr[11].Charset := UTF_32; - IconvArr[11].Charname := 'UTF-32'; - IconvArr[12].Charset := UTF_32; - IconvArr[12].Charname := 'UTF-32BE'; - IconvArr[13].Charset := UTF_32; - IconvArr[13].Charname := 'UTF-32LE'; - IconvArr[14].Charset := UTF_7; - IconvArr[14].Charname := 'UNICODE-1-1-UTF-7 UTF-7 CSUNICODE11UTF7'; - IconvArr[15].Charset := C99; - IconvArr[15].Charname := 'C99'; - IconvArr[16].Charset := JAVA; - IconvArr[16].Charname := 'JAVA'; - IconvArr[17].Charset := ISO_8859_1; - IconvArr[17].Charname := 'US-ASCII ANSI_X3.4-1968 ANSI_X3.4-1986 ASCII CP367 IBM367 ISO-IR-6 ISO646-US ISO_646.IRV:1991 US CSASCII'; - IconvArr[18].Charset := ISO_8859_2; - IconvArr[18].Charname := 'ISO-8859-2 ISO-IR-101 ISO8859-2 ISO_8859-2 ISO_8859-2:1987 L2 LATIN2 CSISOLATIN2'; - IconvArr[19].Charset := ISO_8859_3; - IconvArr[19].Charname := 'ISO-8859-3 ISO-IR-109 ISO8859-3 ISO_8859-3 ISO_8859-3:1988 L3 LATIN3 CSISOLATIN3'; - IconvArr[20].Charset := ISO_8859_4; - IconvArr[20].Charname := 'ISO-8859-4 ISO-IR-110 ISO8859-4 ISO_8859-4 ISO_8859-4:1988 L4 LATIN4 CSISOLATIN4'; - IconvArr[21].Charset := ISO_8859_5; - IconvArr[21].Charname := 'ISO-8859-5 CYRILLIC ISO-IR-144 ISO8859-5 ISO_8859-5 ISO_8859-5:1988 CSISOLATINCYRILLIC'; - IconvArr[22].Charset := ISO_8859_6; - IconvArr[22].Charname := 'ISO-8859-6 ARABIC ASMO-708 ECMA-114 ISO-IR-127 ISO8859-6 ISO_8859-6 ISO_8859-6:1987 CSISOLATINARABIC'; - IconvArr[23].Charset := ISO_8859_7; - IconvArr[23].Charname := 'ISO-8859-7 ECMA-118 ELOT_928 GREEK GREEK8 ISO-IR-126 ISO8859-7 ISO_8859-7 ISO_8859-7:1987 CSISOLATINGREEK'; - IconvArr[24].Charset := ISO_8859_8; - IconvArr[24].Charname := 'ISO-8859-8 HEBREW ISO_8859-8 ISO-IR-138 ISO8859-8 ISO_8859-8:1988 CSISOLATINHEBREW ISO-8859-8-I'; - IconvArr[25].Charset := ISO_8859_9; - IconvArr[25].Charname := 'ISO-8859-9 ISO-IR-148 ISO8859-9 ISO_8859-9 ISO_8859-9:1989 L5 LATIN5 CSISOLATIN5'; - IconvArr[26].Charset := ISO_8859_10; - IconvArr[26].Charname := 'ISO-8859-10 ISO-IR-157 ISO8859-10 ISO_8859-10 ISO_8859-10:1992 L6 LATIN6 CSISOLATIN6'; - IconvArr[27].Charset := ISO_8859_13; - IconvArr[27].Charname := 'ISO-8859-13 ISO-IR-179 ISO8859-13 ISO_8859-13 L7 LATIN7'; - IconvArr[28].Charset := ISO_8859_14; - IconvArr[28].Charname := 'ISO-8859-14 ISO-CELTIC ISO-IR-199 ISO8859-14 ISO_8859-14 ISO_8859-14:1998 L8 LATIN8'; - IconvArr[29].Charset := ISO_8859_15; - IconvArr[29].Charname := 'ISO-8859-15 ISO-IR-203 ISO8859-15 ISO_8859-15 ISO_8859-15:1998'; - IconvArr[30].Charset := ISO_8859_16; - IconvArr[30].Charname := 'ISO-8859-16 ISO-IR-226 ISO8859-16 ISO_8859-16 ISO_8859-16:2000'; - IconvArr[31].Charset := KOI8_R; - IconvArr[31].Charname := 'KOI8-R CSKOI8R'; - IconvArr[32].Charset := KOI8_U; - IconvArr[32].Charname := 'KOI8-U'; - IconvArr[33].Charset := KOI8_RU; - IconvArr[33].Charname := 'KOI8-RU'; - IconvArr[34].Charset := CP1250; - IconvArr[34].Charname := 'WINDOWS-1250 CP1250 MS-EE'; - IconvArr[35].Charset := CP1251; - IconvArr[35].Charname := 'WINDOWS-1251 CP1251 MS-CYRL'; - IconvArr[36].Charset := CP1252; - IconvArr[36].Charname := 'WINDOWS-1252 CP1252 MS-ANSI'; - IconvArr[37].Charset := CP1253; - IconvArr[37].Charname := 'WINDOWS-1253 CP1253 MS-GREEK'; - IconvArr[38].Charset := CP1254; - IconvArr[38].Charname := 'WINDOWS-1254 CP1254 MS-TURK'; - IconvArr[39].Charset := CP1255; - IconvArr[39].Charname := 'WINDOWS-1255 CP1255 MS-HEBR'; - IconvArr[40].Charset := CP1256; - IconvArr[40].Charname := 'WINDOWS-1256 CP1256 MS-ARAB'; - IconvArr[41].Charset := CP1257; - IconvArr[41].Charname := 'WINDOWS-1257 CP1257 WINBALTRIM'; - IconvArr[42].Charset := CP1258; - IconvArr[42].Charname := 'WINDOWS-1258 CP1258'; - IconvArr[43].Charset := ISO_8859_1; - IconvArr[43].Charname := '850 CP850 IBM850 CSPC850MULTILINGUAL'; - IconvArr[44].Charset := CP862; - IconvArr[44].Charname := '862 CP862 IBM862 CSPC862LATINHEBREW'; - IconvArr[45].Charset := CP866; - IconvArr[45].Charname := '866 CP866 IBM866 CSIBM866'; - IconvArr[46].Charset := MAC; - IconvArr[46].Charname := 'MAC MACINTOSH MACROMAN CSMACINTOSH'; - IconvArr[47].Charset := MACCE; - IconvArr[47].Charname := 'MACCENTRALEUROPE'; - IconvArr[48].Charset := MACICE; - IconvArr[48].Charname := 'MACICELAND'; - IconvArr[49].Charset := MACCRO; - IconvArr[49].Charname := 'MACCROATIAN'; - IconvArr[50].Charset := MACRO; - IconvArr[50].Charname := 'MACROMANIA'; - IconvArr[51].Charset := MACCYR; - IconvArr[51].Charname := 'MACCYRILLIC'; - IconvArr[52].Charset := MACUK; - IconvArr[52].Charname := 'MACUKRAINE'; - IconvArr[53].Charset := MACGR; - IconvArr[53].Charname := 'MACGREEK'; - IconvArr[54].Charset := MACTU; - IconvArr[54].Charname := 'MACTURKISH'; - IconvArr[55].Charset := MACHEB; - IconvArr[55].Charname := 'MACHEBREW'; - IconvArr[56].Charset := MACAR; - IconvArr[56].Charname := 'MACARABIC'; - IconvArr[57].Charset := MACTH; - IconvArr[57].Charname := 'MACTHAI'; - IconvArr[58].Charset := ROMAN8; - IconvArr[58].Charname := 'HP-ROMAN8 R8 ROMAN8 CSHPROMAN8'; - IconvArr[59].Charset := NEXTSTEP; - IconvArr[59].Charname := 'NEXTSTEP'; - IconvArr[60].Charset := ARMASCII; - IconvArr[60].Charname := 'ARMSCII-8'; - IconvArr[61].Charset := GEORGIAN_AC; - IconvArr[61].Charname := 'GEORGIAN-ACADEMY'; - IconvArr[62].Charset := GEORGIAN_PS; - IconvArr[62].Charname := 'GEORGIAN-PS'; - IconvArr[63].Charset := KOI8_T; - IconvArr[63].Charname := 'KOI8-T'; - IconvArr[64].Charset := MULELAO; - IconvArr[64].Charname := 'MULELAO-1'; - IconvArr[65].Charset := CP1133; - IconvArr[65].Charname := 'CP1133 IBM-CP1133'; - IconvArr[66].Charset := TIS620; - IconvArr[66].Charname := 'TIS-620 ISO-IR-166 TIS620 TIS620-0 TIS620.2529-1 TIS620.2533-0 TIS620.2533-1'; - IconvArr[67].Charset := CP874; - IconvArr[67].Charname := 'CP874 WINDOWS-874'; - IconvArr[68].Charset := VISCII; - IconvArr[68].Charname := 'VISCII VISCII1.1-1 CSVISCII'; - IconvArr[69].Charset := TCVN; - IconvArr[69].Charname := 'TCVN TCVN-5712 TCVN5712-1 TCVN5712-1:1993'; - IconvArr[70].Charset := ISO_IR_14; - IconvArr[70].Charname := 'ISO-IR-14 ISO646-JP JIS_C6220-1969-RO JP CSISO14JISC6220RO'; - IconvArr[71].Charset := JIS_X0201; - IconvArr[71].Charname := 'JISX0201-1976 JIS_X0201 X0201 CSHALFWIDTHKATAKANA'; - IconvArr[72].Charset := JIS_X0208; - IconvArr[72].Charname := 'ISO-IR-87 JIS0208 JIS_C6226-1983 JIS_X0208 JIS_X0208-1983 JIS_X0208-1990 X0208 CSISO87JISX0208'; - IconvArr[73].Charset := JIS_X0212; - IconvArr[73].Charname := 'ISO-IR-159 JIS_X0212 JIS_X0212-1990 JIS_X0212.1990-0 X0212 CSISO159JISX02121990'; - IconvArr[74].Charset := GB1988_80; - IconvArr[74].Charname := 'CN GB_1988-80 ISO-IR-57 ISO646-CN CSISO57GB1988'; - IconvArr[75].Charset := GB2312_80; - IconvArr[75].Charname := 'CHINESE GB_2312-80 ISO-IR-58 CSISO58GB231280'; - IconvArr[76].Charset := ISO_IR_165; - IconvArr[76].Charname := 'CN-GB-ISOIR165 ISO-IR-165'; - IconvArr[77].Charset := ISO_IR_149; - IconvArr[77].Charname := 'ISO-IR-149 KOREAN KSC_5601 KS_C_5601-1987 KS_C_5601-1989 CSKSC56011987'; - IconvArr[78].Charset := EUC_JP; - IconvArr[78].Charname := 'EUC-JP EUCJP EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE CSEUCPKDFMTJAPANESE'; - IconvArr[79].Charset := SHIFT_JIS; - IconvArr[79].Charname := 'SHIFT-JIS MS_KANJI SHIFT_JIS SJIS CSSHIFTJIS'; - IconvArr[80].Charset := CP932; - IconvArr[80].Charname := 'CP932'; - IconvArr[81].Charset := ISO_2022_JP; - IconvArr[81].Charname := 'ISO-2022-JP CSISO2022JP'; - IconvArr[82].Charset := ISO_2022_JP1; - IconvArr[82].Charname := 'ISO-2022-JP-1'; - IconvArr[83].Charset := ISO_2022_JP2; - IconvArr[83].Charname := 'ISO-2022-JP-2 CSISO2022JP2'; - IconvArr[84].Charset := GB2312; - IconvArr[84].Charname := 'CN-GB EUC-CN EUCCN GB2312 CSGB2312'; - IconvArr[85].Charset := CP936; - IconvArr[85].Charname := 'CP936 GBK'; - IconvArr[86].Charset := GB18030; - IconvArr[86].Charname := 'GB18030'; - IconvArr[87].Charset := ISO_2022_CN; - IconvArr[87].Charname := 'ISO-2022-CN CSISO2022CN'; - IconvArr[88].Charset := ISO_2022_CNE; - IconvArr[88].Charname := 'ISO-2022-CN-EXT'; - IconvArr[89].Charset := HZ; - IconvArr[89].Charname := 'HZ HZ-GB-2312'; - IconvArr[90].Charset := EUC_TW; - IconvArr[90].Charname := 'EUC-TW EUCTW CSEUCTW'; - IconvArr[91].Charset := BIG5; - IconvArr[91].Charname := 'BIG5 BIG-5 BIG-FIVE BIGFIVE CN-BIG5 CSBIG5'; - IconvArr[92].Charset := CP950; - IconvArr[92].Charname := 'CP950'; - IconvArr[93].Charset := BIG5_HKSCS; - IconvArr[93].Charname := 'BIG5-HKSCS BIG5HKSCS'; - IconvArr[94].Charset := EUC_KR; - IconvArr[94].Charname := 'EUC-KR EUCKR CSEUCKR'; - IconvArr[95].Charset := CP949; - IconvArr[95].Charname := 'CP949 UHC'; - IconvArr[96].Charset := CP1361; - IconvArr[96].Charname := 'CP1361 JOHAB'; - IconvArr[97].Charset := ISO_2022_KR; - IconvArr[97].Charname := 'ISO-2022-KR CSISO2022KR'; - IconvArr[98].Charset := ISO_8859_1; - IconvArr[98].Charname := '437 CP437 IBM437 CSPC8CODEPAGE437'; - IconvArr[99].Charset := CP737; - IconvArr[99].Charname := 'CP737'; - IconvArr[100].Charset := CP775; - IconvArr[100].Charname := 'CP775 IBM775 CSPC775BALTIC'; - IconvArr[101].Charset := CP852; - IconvArr[101].Charname := '852 CP852 IBM852 CSPCP852'; - IconvArr[102].Charset := CP853; - IconvArr[102].Charname := 'CP853'; - IconvArr[103].Charset := CP855; - IconvArr[103].Charname := '855 CP855 IBM855 CSIBM855'; - IconvArr[104].Charset := CP857; - IconvArr[104].Charname := '857 CP857 IBM857 CSIBM857'; - IconvArr[105].Charset := CP858; - IconvArr[105].Charname := 'CP858'; - IconvArr[106].Charset := CP860; - IconvArr[106].Charname := '860 CP860 IBM860 CSIBM860'; - IconvArr[107].Charset := CP861; - IconvArr[107].Charname := '861 CP-IS CP861 IBM861 CSIBM861'; - IconvArr[108].Charset := CP863; - IconvArr[108].Charname := '863 CP863 IBM863 CSIBM863'; - IconvArr[109].Charset := CP864; - IconvArr[109].Charname := 'CP864 IBM864 CSIBM864'; - IconvArr[110].Charset := CP865; - IconvArr[110].Charname := '865 CP865 IBM865 CSIBM865'; - IconvArr[111].Charset := CP869; - IconvArr[111].Charname := '869 CP-GR CP869 IBM869 CSIBM869'; - IconvArr[112].Charset := CP1125; - IconvArr[112].Charname := 'CP1125'; -end; - -end. +{==============================================================================| +| Project : Ararat Synapse | 005.002.003 | +|==============================================================================| +| Content: Charset conversion support | +|==============================================================================| +| Copyright (c)1999-2012, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2000-2012. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{: @abstract(Charset conversion support) +This unit contains a routines for lot of charset conversions. + +It using built-in conversion tables or external Iconv library. Iconv is used + when needed conversion is known by Iconv library. When Iconv library is not + found or Iconv not know requested conversion, then are internal routines used + for conversion. (You can disable Iconv support from your program too!) + +Internal routines knows all major charsets for Europe or America. For East-Asian + charsets you must use Iconv library! +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$H+} + +//old Delphi does not have MSWINDOWS define. +{$IFDEF WIN32} + {$IFNDEF MSWINDOWS} + {$DEFINE MSWINDOWS} + {$ENDIF} +{$ENDIF} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} +{$ENDIF} + +unit synachar; + +interface + +uses +{$IFNDEF MSWINDOWS} + {$IFNDEF FPC} + Libc, + {$ENDIF} +{$ELSE} + Windows, +{$ENDIF} + SysUtils, + synautil, synacode, synaicnv; + +type + {:Type with all supported charsets.} + TMimeChar = (ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, + ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, ISO_8859_13, + ISO_8859_14, ISO_8859_15, CP1250, CP1251, CP1252, CP1253, CP1254, CP1255, + CP1256, CP1257, CP1258, KOI8_R, CP895, CP852, UCS_2, UCS_4, UTF_8, UTF_7, + UTF_7mod, UCS_2LE, UCS_4LE, + //next is supported by Iconv only... + UTF_16, UTF_16LE, UTF_32, UTF_32LE, C99, JAVA, ISO_8859_16, KOI8_U, KOI8_RU, + CP862, CP866, MAC, MACCE, MACICE, MACCRO, MACRO, MACCYR, MACUK, MACGR, MACTU, + MACHEB, MACAR, MACTH, ROMAN8, NEXTSTEP, ARMASCII, GEORGIAN_AC, GEORGIAN_PS, + KOI8_T, MULELAO, CP1133, TIS620, CP874, VISCII, TCVN, ISO_IR_14, JIS_X0201, + JIS_X0208, JIS_X0212, GB1988_80, GB2312_80, ISO_IR_165, ISO_IR_149, EUC_JP, + SHIFT_JIS, CP932, ISO_2022_JP, ISO_2022_JP1, ISO_2022_JP2, GB2312, CP936, + GB18030, ISO_2022_CN, ISO_2022_CNE, HZ, EUC_TW, BIG5, CP950, BIG5_HKSCS, + EUC_KR, CP949, CP1361, ISO_2022_KR, CP737, CP775, CP853, CP855, CP857, + CP858, CP860, CP861, CP863, CP864, CP865, CP869, CP1125); + + {:Set of any charsets.} + TMimeSetChar = set of TMimeChar; + +const + {:Set of charsets supported by Iconv library only.} + IconvOnlyChars: set of TMimeChar = [UTF_16, UTF_16LE, UTF_32, UTF_32LE, + C99, JAVA, ISO_8859_16, KOI8_U, KOI8_RU, CP862, CP866, MAC, MACCE, MACICE, + MACCRO, MACRO, MACCYR, MACUK, MACGR, MACTU, MACHEB, MACAR, MACTH, ROMAN8, + NEXTSTEP, ARMASCII, GEORGIAN_AC, GEORGIAN_PS, KOI8_T, MULELAO, CP1133, + TIS620, CP874, VISCII, TCVN, ISO_IR_14, JIS_X0201, JIS_X0208, JIS_X0212, + GB1988_80, GB2312_80, ISO_IR_165, ISO_IR_149, EUC_JP, SHIFT_JIS, CP932, + ISO_2022_JP, ISO_2022_JP1, ISO_2022_JP2, GB2312, CP936, GB18030, + ISO_2022_CN, ISO_2022_CNE, HZ, EUC_TW, BIG5, CP950, BIG5_HKSCS, EUC_KR, + CP949, CP1361, ISO_2022_KR, CP737, CP775, CP853, CP855, CP857, CP858, + CP860, CP861, CP863, CP864, CP865, CP869, CP1125]; + + {:Set of charsets supported by internal routines only.} + NoIconvChars: set of TMimeChar = [CP895, UTF_7mod]; + + {:null character replace table. (Usable for disable charater replacing.)} + Replace_None: array[0..0] of Word = + (0); + + {:Character replace table for remove Czech diakritics.} + Replace_Czech: array[0..59] of Word = + ( + $00E1, $0061, + $010D, $0063, + $010F, $0064, + $010E, $0044, + $00E9, $0065, + $011B, $0065, + $00ED, $0069, + $0148, $006E, + $00F3, $006F, + $0159, $0072, + $0161, $0073, + $0165, $0074, + $00FA, $0075, + $016F, $0075, + $00FD, $0079, + $017E, $007A, + $00C1, $0041, + $010C, $0043, + $00C9, $0045, + $011A, $0045, + $00CD, $0049, + $0147, $004E, + $00D3, $004F, + $0158, $0052, + $0160, $0053, + $0164, $0054, + $00DA, $0055, + $016E, $0055, + $00DD, $0059, + $017D, $005A + ); + +var + {:By this you can generally disable/enable Iconv support.} + DisableIconv: Boolean = False; + + {:Default set of charsets for @link(IdealCharsetCoding) function.} + IdealCharsets: TMimeSetChar = + [ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, + ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, + KOI8_R, KOI8_U + {$IFNDEF CIL} //error URW778 ??? :-O + , GB2312, EUC_KR, ISO_2022_JP, EUC_TW + {$ENDIF} + ]; + +{==============================================================================} +{:Convert Value from one charset to another. See: @link(CharsetConversionEx)} +function CharsetConversion(const Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeChar): AnsiString; + +{:Convert Value from one charset to another with additional character conversion. +see: @link(Replace_None) and @link(Replace_Czech)} +function CharsetConversionEx(const Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeChar; const TransformTable: array of Word): AnsiString; + +{:Convert Value from one charset to another with additional character conversion. + This funtion is similar to @link(CharsetConversionEx), but you can disable + transliteration of unconvertible characters.} +function CharsetConversionTrans(Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeChar; const TransformTable: array of Word; Translit: Boolean): AnsiString; + +{:Returns charset used by operating system.} +function GetCurCP: TMimeChar; + +{:Returns charset used by operating system as OEM charset. (in Windows DOS box, + for example)} +function GetCurOEMCP: TMimeChar; + +{:Converting string with charset name to TMimeChar.} +function GetCPFromID(Value: AnsiString): TMimeChar; + +{:Converting TMimeChar to string with name of charset.} +function GetIDFromCP(Value: TMimeChar): AnsiString; + +{:return @true when value need to be converted. (It is not 7-bit ASCII)} +function NeedCharsetConversion(const Value: AnsiString): Boolean; + +{:Finding best target charset from set of TMimeChars with minimal count of + unconvertible characters.} +function IdealCharsetCoding(const Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeSetChar): TMimeChar; + +{:Return BOM (Byte Order Mark) for given unicode charset.} +function GetBOM(Value: TMimeChar): AnsiString; + +{:Convert binary string with unicode content to WideString.} +function StringToWide(const Value: AnsiString): WideString; + +{:Convert WideString to binary string with unicode content.} +function WideToString(const Value: WideString): AnsiString; + +function GetIconvIDFromCP(Value: TMimeChar): AnsiString; +function GetCPFromIconvID(Value: AnsiString): TMimeChar; + +{==============================================================================} +implementation + +//character transcoding tables X to UCS-2 +{ +//dummy table +$0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, +$0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, +$0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, +$0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, +$00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, +$00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, +$00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, +$00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, +$00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, +$00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, +$00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, +$00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, +$00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, +$00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, +$00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, +$00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF +} + +const + +{Latin-1 + Danish, Dutch, English, Faeroese, Finnish, French, German, Icelandic, + Irish, Italian, Norwegian, Portuguese, Spanish and Swedish. +} + CharISO_8859_1: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, + $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, + $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, + $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, + $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, + $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, + $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF + ); + +{Latin-2 + Albanian, Czech, English, German, Hungarian, Polish, Rumanian, + Serbo-Croatian, Slovak, Slovene and Swedish. +} + CharISO_8859_2: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $0104, $02D8, $0141, $00A4, $013D, $015A, $00A7, + $00A8, $0160, $015E, $0164, $0179, $00AD, $017D, $017B, + $00B0, $0105, $02DB, $0142, $00B4, $013E, $015B, $02C7, + $00B8, $0161, $015F, $0165, $017A, $02DD, $017E, $017C, + $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, + $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, + $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7, + $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF, + $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7, + $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F, + $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7, + $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9 + ); + +{Latin-3 + Afrikaans, Catalan, English, Esperanto, French, Galician, + German, Italian, Maltese and Turkish. +} + CharISO_8859_3: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $0126, $02D8, $00A3, $00A4, $FFFD, $0124, $00A7, + $00A8, $0130, $015E, $011E, $0134, $00AD, $FFFD, $017B, + $00B0, $0127, $00B2, $00B3, $00B4, $00B5, $0125, $00B7, + $00B8, $0131, $015F, $011F, $0135, $00BD, $FFFD, $017C, + $00C0, $00C1, $00C2, $FFFD, $00C4, $010A, $0108, $00C7, + $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, + $FFFD, $00D1, $00D2, $00D3, $00D4, $0120, $00D6, $00D7, + $011C, $00D9, $00DA, $00DB, $00DC, $016C, $015C, $00DF, + $00E0, $00E1, $00E2, $FFFD, $00E4, $010B, $0109, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $FFFD, $00F1, $00F2, $00F3, $00F4, $0121, $00F6, $00F7, + $011D, $00F9, $00FA, $00FB, $00FC, $016D, $015D, $02D9 + ); + +{Latin-4 + Danish, English, Estonian, Finnish, German, Greenlandic, + Lappish, Latvian, Lithuanian, Norwegian and Swedish. +} + CharISO_8859_4: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $0104, $0138, $0156, $00A4, $0128, $013B, $00A7, + $00A8, $0160, $0112, $0122, $0166, $00AD, $017D, $00AF, + $00B0, $0105, $02DB, $0157, $00B4, $0129, $013C, $02C7, + $00B8, $0161, $0113, $0123, $0167, $014A, $017E, $014B, + $0100, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $012E, + $010C, $00C9, $0118, $00CB, $0116, $00CD, $00CE, $012A, + $0110, $0145, $014C, $0136, $00D4, $00D5, $00D6, $00D7, + $00D8, $0172, $00DA, $00DB, $00DC, $0168, $016A, $00DF, + $0101, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $012F, + $010D, $00E9, $0119, $00EB, $0117, $00ED, $00EE, $012B, + $0111, $0146, $014D, $0137, $00F4, $00F5, $00F6, $00F7, + $00F8, $0173, $00FA, $00FB, $00FC, $0169, $016B, $02D9 + ); + +{CYRILLIC + Bulgarian, Bielorussian, English, Macedonian, Russian, + Serbo-Croatian and Ukrainian. +} + CharISO_8859_5: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $0401, $0402, $0403, $0404, $0405, $0406, $0407, + $0408, $0409, $040A, $040B, $040C, $00AD, $040E, $040F, + $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417, + $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, + $0420, $0421, $0422, $0423, $0424, $0425, $0426, $0427, + $0428, $0429, $042A, $042B, $042C, $042D, $042E, $042F, + $0430, $0431, $0432, $0433, $0434, $0435, $0436, $0437, + $0438, $0439, $043A, $043B, $043C, $043D, $043E, $043F, + $0440, $0441, $0442, $0443, $0444, $0445, $0446, $0447, + $0448, $0449, $044A, $044B, $044C, $044D, $044E, $044F, + $2116, $0451, $0452, $0453, $0454, $0455, $0456, $0457, + $0458, $0459, $045A, $045B, $045C, $00A7, $045E, $045F + ); + +{ARABIC +} + CharISO_8859_6: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $FFFD, $FFFD, $FFFD, $00A4, $FFFD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $060C, $00AD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $061B, $FFFD, $FFFD, $FFFD, $061F, + $FFFD, $0621, $0622, $0623, $0624, $0625, $0626, $0627, + $0628, $0629, $062A, $062B, $062C, $062D, $062E, $062F, + $0630, $0631, $0632, $0633, $0634, $0635, $0636, $0637, + $0638, $0639, $063A, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $0640, $0641, $0642, $0643, $0644, $0645, $0646, $0647, + $0648, $0649, $064A, $064B, $064C, $064D, $064E, $064F, + $0650, $0651, $0652, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD + ); + +{GREEK +} + CharISO_8859_7: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $2018, $2019, $00A3, $FFFD, $FFFD, $00A6, $00A7, + $00A8, $00A9, $FFFD, $00AB, $00AC, $00AD, $FFFD, $2015, + $00B0, $00B1, $00B2, $00B3, $0384, $0385, $0386, $00B7, + $0388, $0389, $038A, $00BB, $038C, $00BD, $038E, $038F, + $0390, $0391, $0392, $0393, $0394, $0395, $0396, $0397, + $0398, $0399, $039A, $039B, $039C, $039D, $039E, $039F, + $03A0, $03A1, $FFFD, $03A3, $03A4, $03A5, $03A6, $03A7, + $03A8, $03A9, $03AA, $03AB, $03AC, $03AD, $03AE, $03AF, + $03B0, $03B1, $03B2, $03B3, $03B4, $03B5, $03B6, $03B7, + $03B8, $03B9, $03BA, $03BB, $03BC, $03BD, $03BE, $03BF, + $03C0, $03C1, $03C2, $03C3, $03C4, $03C5, $03C6, $03C7, + $03C8, $03C9, $03CA, $03CB, $03CC, $03CD, $03CE, $FFFD + ); + +{HEBREW +} + CharISO_8859_8: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $FFFD, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $00D7, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $00F7, $00BB, $00BC, $00BD, $00BE, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $2017, + $05D0, $05D1, $05D2, $05D3, $05D4, $05D5, $05D6, $05D7, + $05D8, $05D9, $05DA, $05DB, $05DC, $05DD, $05DE, $05DF, + $05E0, $05E1, $05E2, $05E3, $05E4, $05E5, $05E6, $05E7, + $05E8, $05E9, $05EA, $FFFD, $FFFD, $200E, $200F, $FFFD + ); + +{Latin-5 + English, Finnish, French, German, Irish, Italian, Norwegian, + Portuguese, Spanish, Swedish and Turkish. +} + CharISO_8859_9: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $0104, $02D8, $0141, $00A4, $013D, $015A, $00A7, + $00A8, $0160, $015E, $0164, $0179, $00AD, $017D, $017B, + $00B0, $0105, $02DB, $0142, $00B4, $013E, $015B, $02C7, + $00B8, $0161, $015F, $0165, $017A, $02DD, $017E, $017C, + $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, + $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, + $011E, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, + $00D8, $00D9, $00DA, $00DB, $00DC, $0130, $015E, $00DF, + $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $011F, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, + $00F8, $00F9, $00FA, $00FB, $00FC, $0131, $015F, $00FF + ); + +{Latin-6 + Danish, English, Estonian, Faeroese, Finnish, German, Greenlandic, + Icelandic, Lappish, Latvian, Lithuanian, Norwegian and Swedish. +} + CharISO_8859_10: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $0104, $0112, $0122, $012A, $0128, $0136, $00A7, + $013B, $0110, $0160, $0166, $017D, $00AD, $016A, $014A, + $00B0, $0105, $0113, $0123, $012B, $0129, $0137, $00B7, + $013C, $0111, $0161, $0167, $017E, $2015, $016B, $014B, + $0100, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $012E, + $010C, $00C9, $0118, $00CB, $0116, $00CD, $00CE, $00CF, + $00D0, $0145, $014C, $00D3, $00D4, $00D5, $00D6, $0168, + $00D8, $0172, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, + $0101, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $012F, + $010D, $00E9, $0119, $00EB, $0117, $00ED, $00EE, $00EF, + $00F0, $0146, $014D, $00F3, $00F4, $00F5, $00F6, $0169, + $00F8, $0173, $00FA, $00FB, $00FC, $00FD, $00FE, $0138 + ); + + CharISO_8859_13: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $201D, $00A2, $00A3, $00A4, $201E, $00A6, $00A7, + $00D8, $00A9, $0156, $00AB, $00AC, $00AD, $00AE, $00C6, + $00B0, $00B1, $00B2, $00B3, $201C, $00B5, $00B6, $00B7, + $00F8, $00B9, $0157, $00BB, $00BC, $00BD, $00BE, $00E6, + $0104, $012E, $0100, $0106, $00C4, $00C5, $0118, $0112, + $010C, $00C9, $0179, $0116, $0122, $0136, $012A, $013B, + $0160, $0143, $0145, $00D3, $014C, $00D5, $00D6, $00D7, + $0172, $0141, $015A, $016A, $00DC, $017B, $017D, $00DF, + $0105, $012F, $0101, $0107, $00E4, $00E5, $0119, $0113, + $010D, $00E9, $017A, $0117, $0123, $0137, $012B, $013C, + $0161, $0144, $0146, $00F3, $014D, $00F5, $00F6, $00F7, + $0173, $0142, $015B, $016B, $00FC, $017C, $017E, $2019 + ); + + CharISO_8859_14: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $1E02, $1E03, $00A3, $010A, $010B, $1E0A, $00A7, + $1E80, $00A9, $1E82, $1E0B, $1EF2, $00AD, $00AE, $0178, + $1E1E, $1E1F, $0120, $0121, $1E40, $1E41, $00B6, $1E56, + $1E81, $1E57, $1E83, $1E60, $1EF3, $1E84, $1E85, $1E61, + $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, + $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, + $0174, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $1E6A, + $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $0176, $00DF, + $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $0175, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $1E6B, + $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $0177, $00FF + ); + + CharISO_8859_15: array[128..255] of Word = + ( + $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, + $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, + $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, + $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, + $00A0, $00A1, $00A2, $00A3, $20AC, $00A5, $0160, $00A7, + $0161, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $017D, $00B5, $00B6, $00B7, + $017E, $00B9, $00BA, $00BB, $0152, $0153, $0178, $00BF, + $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, + $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, + $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, + $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, + $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, + $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF + ); + +{Eastern European +} + CharCP_1250: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $FFFD, $201E, $2026, $2020, $2021, + $FFFD, $2030, $0160, $2039, $015A, $0164, $017D, $0179, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $FFFD, $2122, $0161, $203A, $015B, $0165, $017E, $017A, + $00A0, $02C7, $02D8, $0141, $00A4, $0104, $00A6, $00A7, + $00A8, $00A9, $015E, $00AB, $00AC, $00AD, $00AE, $017B, + $00B0, $00B1, $02DB, $0142, $00B4, $00B5, $00B6, $00B7, + $00B8, $0105, $015F, $00BB, $013D, $02DD, $013E, $017C, + $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, + $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, + $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7, + $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF, + $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7, + $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F, + $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7, + $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9 + ); + +{Cyrillic +} + CharCP_1251: array[128..255] of Word = + ( + $0402, $0403, $201A, $0453, $201E, $2026, $2020, $2021, + $20AC, $2030, $0409, $2039, $040A, $040C, $040B, $040F, + $0452, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $FFFD, $2122, $0459, $203A, $045A, $045C, $045B, $045F, + $00A0, $040E, $045E, $0408, $00A4, $0490, $00A6, $00A7, + $0401, $00A9, $0404, $00AB, $00AC, $00AD, $00AE, $0407, + $00B0, $00B1, $0406, $0456, $0491, $00B5, $00B6, $00B7, + $0451, $2116, $0454, $00BB, $0458, $0405, $0455, $0457, + $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417, + $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, + $0420, $0421, $0422, $0423, $0424, $0425, $0426, $0427, + $0428, $0429, $042A, $042B, $042C, $042D, $042E, $042F, + $0430, $0431, $0432, $0433, $0434, $0435, $0436, $0437, + $0438, $0439, $043A, $043B, $043C, $043D, $043E, $043F, + $0440, $0441, $0442, $0443, $0444, $0445, $0446, $0447, + $0448, $0449, $044A, $044B, $044C, $044D, $044E, $044F + ); + +{Latin-1 (US, Western Europe) +} + CharCP_1252: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, + $02C6, $2030, $0160, $2039, $0152, $FFFD, $017D, $FFFD, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $02DC, $2122, $0161, $203A, $0153, $FFFD, $017E, $0178, + $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, + $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, + $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, + $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, + $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, + $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, + $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF + ); + +{Greek +} + CharCP_1253: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, + $FFFD, $2030, $FFFD, $2039, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $FFFD, $2122, $FFFD, $203A, $FFFD, $FFFD, $FFFD, $FFFD, + $00A0, $0385, $0386, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $FFFD, $00AB, $00AC, $00AD, $00AE, $2015, + $00B0, $00B1, $00B2, $00B3, $0384, $00B5, $00B6, $00B7, + $0388, $0389, $038A, $00BB, $038C, $00BD, $038E, $038F, + $0390, $0391, $0392, $0393, $0394, $0395, $0396, $0397, + $0398, $0399, $039A, $039B, $039C, $039D, $039E, $039F, + $03A0, $03A1, $FFFD, $03A3, $03A4, $03A5, $03A6, $03A7, + $03A8, $03A9, $03AA, $03AB, $03AC, $03AD, $03AE, $03AF, + $03B0, $03B1, $03B2, $03B3, $03B4, $03B5, $03B6, $03B7, + $03B8, $03B9, $03BA, $03BB, $03BC, $03BD, $03BE, $03BF, + $03C0, $03C1, $03C2, $03C3, $03C4, $03C5, $03C6, $03C7, + $03C8, $03C9, $03CA, $03CB, $03CC, $03CD, $03CE, $FFFD + ); + +{Turkish +} + CharCP_1254: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, + $02C6, $2030, $0160, $2039, $0152, $FFFD, $FFFD, $FFFD, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $02DC, $2122, $0161, $203A, $0153, $FFFD, $FFFD, $0178, + $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, + $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, + $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, + $011E, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, + $00D8, $00D9, $00DA, $00DB, $00DC, $0130, $015E, $00DF, + $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, + $011F, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, + $00F8, $00F9, $00FA, $00FB, $00FC, $0131, $015F, $00FF + ); + +{Hebrew +} + CharCP_1255: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, + $02C6, $2030, $FFFD, $2039, $FFFD, $FFFD, $FFFD, $FFFD, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $02DC, $2122, $FFFD, $203A, $FFFD, $FFFD, $FFFD, $FFFD, + $00A0, $00A1, $00A2, $00A3, $20AA, $00A5, $00A6, $00A7, + $00A8, $00A9, $00D7, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $00F7, $00BB, $00BC, $00BD, $00BE, $00BF, + $05B0, $05B1, $05B2, $05B3, $05B4, $05B5, $05B6, $05B7, + $05B8, $05B9, $FFFD, $05BB, $05BC, $05BD, $05BE, $05BF, + $05C0, $05C1, $05C2, $05C3, $05F0, $05F1, $05F2, $05F3, + $05F4, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, + $05D0, $05D1, $05D2, $05D3, $05D4, $05D5, $05D6, $05D7, + $05D8, $05D9, $05DA, $05DB, $05DC, $05DD, $05DE, $05DF, + $05E0, $05E1, $05E2, $05E3, $05E4, $05E5, $05E6, $05E7, + $05E8, $05E9, $05EA, $FFFD, $FFFD, $200E, $200F, $FFFD + ); + +{Arabic +} + CharCP_1256: array[128..255] of Word = + ( + $20AC, $067E, $201A, $0192, $201E, $2026, $2020, $2021, + $02C6, $2030, $0679, $2039, $0152, $0686, $0698, $0688, + $06AF, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $06A9, $2122, $0691, $203A, $0153, $200C, $200D, $06BA, + $00A0, $060C, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $06BE, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $061B, $00BB, $00BC, $00BD, $00BE, $061F, + $06C1, $0621, $0622, $0623, $0624, $0625, $0626, $0627, + $0628, $0629, $062A, $062B, $062C, $062D, $062E, $062F, + $0630, $0631, $0632, $0633, $0634, $0635, $0636, $00D7, + $0637, $0638, $0639, $063A, $0640, $0641, $0642, $0643, + $00E0, $0644, $00E2, $0645, $0646, $0647, $0648, $00E7, + $00E8, $00E9, $00EA, $00EB, $0649, $064A, $00EE, $00EF, + $064B, $064C, $064D, $064E, $00F4, $064F, $0650, $00F7, + $0651, $00F9, $0652, $00FB, $00FC, $200E, $200F, $06D2 + ); + +{Baltic +} + CharCP_1257: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $FFFD, $201E, $2026, $2020, $2021, + $FFFD, $2030, $FFFD, $2039, $FFFD, $00A8, $02C7, $00B8, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $FFFD, $2122, $FFFD, $203A, $FFFD, $00AF, $02DB, $FFFD, + $00A0, $FFFD, $00A2, $00A3, $00A4, $FFFD, $00A6, $00A7, + $00D8, $00A9, $0156, $00AB, $00AC, $00AD, $00AE, $00C6, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00F8, $00B9, $0157, $00BB, $00BC, $00BD, $00BE, $00E6, + $0104, $012E, $0100, $0106, $00C4, $00C5, $0118, $0112, + $010C, $00C9, $0179, $0116, $0122, $0136, $012A, $013B, + $0160, $0143, $0145, $00D3, $014C, $00D5, $00D6, $00D7, + $0172, $0141, $015A, $016A, $00DC, $017B, $017D, $00DF, + $0105, $012F, $0101, $0107, $00E4, $00E5, $0119, $0113, + $010D, $00E9, $017A, $0117, $0123, $0137, $012B, $013C, + $0161, $0144, $0146, $00F3, $014D, $00F5, $00F6, $00F7, + $0173, $0142, $015B, $016B, $00FC, $017C, $017E, $02D9 + ); + +{Vietnamese +} + CharCP_1258: array[128..255] of Word = + ( + $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, + $02C6, $2030, $FFFD, $2039, $0152, $FFFD, $FFFD, $FFFD, + $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, + $02DC, $2122, $FFFD, $203A, $0153, $FFFD, $FFFD, $0178, + $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, + $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, + $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, + $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, + $00C0, $00C1, $00C2, $0102, $00C4, $00C5, $00C6, $00C7, + $00C8, $00C9, $00CA, $00CB, $0300, $00CD, $00CE, $00CF, + $0110, $00D1, $0309, $00D3, $00D4, $01A0, $00D6, $00D7, + $00D8, $00D9, $00DA, $00DB, $00DC, $01AF, $0303, $00DF, + $00E0, $00E1, $00E2, $0103, $00E4, $00E5, $00E6, $00E7, + $00E8, $00E9, $00EA, $00EB, $0301, $00ED, $00EE, $00EF, + $0111, $00F1, $0323, $00F3, $00F4, $01A1, $00F6, $00F7, + $00F8, $00F9, $00FA, $00FB, $00FC, $01B0, $20AB, $00FF + ); + +{Cyrillic +} + CharKOI8_R: array[128..255] of Word = + ( + $2500, $2502, $250C, $2510, $2514, $2518, $251C, $2524, + $252C, $2534, $253C, $2580, $2584, $2588, $258C, $2590, + $2591, $2592, $2593, $2320, $25A0, $2219, $221A, $2248, + $2264, $2265, $00A0, $2321, $00B0, $00B2, $00B7, $00F7, + $2550, $2551, $2552, $0451, $2553, $2554, $2555, $2556, + $2557, $2558, $2559, $255A, $255B, $255C, $255D, $255E, + $255F, $2560, $2561, $0401, $2562, $2563, $2564, $2565, + $2566, $2567, $2568, $2569, $256A, $256B, $256C, $00A9, + $044E, $0430, $0431, $0446, $0434, $0435, $0444, $0433, + $0445, $0438, $0439, $043A, $043B, $043C, $043D, $043E, + $043F, $044F, $0440, $0441, $0442, $0443, $0436, $0432, + $044C, $044B, $0437, $0448, $044D, $0449, $0447, $044A, + $042E, $0410, $0411, $0426, $0414, $0415, $0424, $0413, + $0425, $0418, $0419, $041A, $041B, $041C, $041D, $041E, + $041F, $042F, $0420, $0421, $0422, $0423, $0416, $0412, + $042C, $042B, $0417, $0428, $042D, $0429, $0427, $042A + ); + +{Czech (Kamenicky) +} + CharCP_895: array[128..255] of Word = + ( + $010C, $00FC, $00E9, $010F, $00E4, $010E, $0164, $010D, + $011B, $011A, $0139, $00CD, $013E, $013A, $00C4, $00C1, + $00C9, $017E, $017D, $00F4, $00F6, $00D3, $016F, $00DA, + $00FD, $00D6, $00DC, $0160, $013D, $00DD, $0158, $0165, + $00E1, $00ED, $00F3, $00FA, $0148, $0147, $016E, $00D4, + $0161, $0159, $0155, $0154, $00BC, $00A7, $00AB, $00BB, + $2591, $2592, $2593, $2502, $2524, $2561, $2562, $2556, + $2555, $2563, $2551, $2557, $255D, $255C, $255B, $2510, + $2514, $2534, $252C, $251C, $2500, $253C, $255E, $255F, + $255A, $2554, $2569, $2566, $2560, $2550, $256C, $2567, + $2568, $2564, $2565, $2559, $2558, $2552, $2553, $256B, + $256A, $2518, $250C, $2588, $2584, $258C, $2590, $2580, + $03B1, $03B2, $0393, $03C0, $03A3, $03C3, $03BC, $03C4, + $03A6, $0398, $03A9, $03B4, $221E, $2205, $03B5, $2229, + $2261, $00B1, $2265, $2264, $2320, $2321, $00F7, $2248, + $2218, $00B7, $2219, $221A, $207F, $00B2, $25A0, $00A0 + ); + +{Eastern European +} + CharCP_852: array[128..255] of Word = + ( + $00C7, $00FC, $00E9, $00E2, $00E4, $016F, $0107, $00E7, + $0142, $00EB, $0150, $0151, $00EE, $0179, $00C4, $0106, + $00C9, $0139, $013A, $00F4, $00F6, $013D, $013E, $015A, + $015B, $00D6, $00DC, $0164, $0165, $0141, $00D7, $010D, + $00E1, $00ED, $00F3, $00FA, $0104, $0105, $017D, $017E, + $0118, $0119, $00AC, $017A, $010C, $015F, $00AB, $00BB, + $2591, $2592, $2593, $2502, $2524, $00C1, $00C2, $011A, + $015E, $2563, $2551, $2557, $255D, $017B, $017C, $2510, + $2514, $2534, $252C, $251C, $2500, $253C, $0102, $0103, + $255A, $2554, $2569, $2566, $2560, $2550, $256C, $00A4, + $0111, $0110, $010E, $00CB, $010F, $0147, $00CD, $00CE, + $011B, $2518, $250C, $2588, $2584, $0162, $016E, $2580, + $00D3, $00DF, $00D4, $0143, $0144, $0148, $0160, $0161, + $0154, $00DA, $0155, $0170, $00FD, $00DD, $0163, $00B4, + $00AD, $02DD, $02DB, $02C7, $02D8, $00A7, $00F7, $00B8, + $00B0, $00A8, $02D9, $0171, $0158, $0159, $25A0, $00A0 + ); + +{==============================================================================} +type + TIconvChar = record + Charset: TMimeChar; + CharName: string; + end; + TIconvArr = array [0..112] of TIconvChar; + +const + NotFoundChar = '_'; + +var + SetTwo: set of TMimeChar = [UCS_2, UCS_2LE, UTF_7, UTF_7mod]; + SetFour: set of TMimeChar = [UCS_4, UCS_4LE, UTF_8]; + SetLE: set of TMimeChar = [UCS_2LE, UCS_4LE]; + + IconvArr: TIconvArr; + +{==============================================================================} +function FindIconvID(const Value, Charname: string): Boolean; +var + s: string; +begin + Result := True; + //exact match + if Value = Charname then + Exit; + //Value is on begin of charname + s := Value + ' '; + if s = Copy(Charname, 1, Length(s)) then + Exit; + //Value is on end of charname + s := ' ' + Value; + if s = Copy(Charname, Length(Charname) - Length(s) + 1, Length(s)) then + Exit; + //value is somewhere inside charname + if Pos( s + ' ', Charname) > 0 then + Exit; + Result := False; +end; + +function GetCPFromIconvID(Value: AnsiString): TMimeChar; +var + n: integer; +begin + Result := ISO_8859_1; + Value := UpperCase(Value); + for n := 0 to High(IconvArr) do + if FindIconvID(Value, IconvArr[n].Charname) then + begin + Result := IconvArr[n].Charset; + Break; + end; +end; + +{==============================================================================} +function GetIconvIDFromCP(Value: TMimeChar): AnsiString; +var + n: integer; +begin + Result := 'ISO-8859-1'; + for n := 0 to High(IconvArr) do + if IconvArr[n].Charset = Value then + begin + Result := Separateleft(IconvArr[n].Charname, ' '); + Break; + end; +end; + +{==============================================================================} +function ReplaceUnicode(Value: Word; const TransformTable: array of Word): Word; +var + n: integer; +begin + if High(TransformTable) <> 0 then + for n := 0 to High(TransformTable) do + if not odd(n) then + if TransformTable[n] = Value then + begin + Value := TransformTable[n+1]; + break; + end; + Result := Value; +end; + +{==============================================================================} +procedure CopyArray(const SourceTable: array of Word; + var TargetTable: array of Word); +var + n: Integer; +begin + for n := 0 to 127 do + TargetTable[n] := SourceTable[n]; +end; + +{==============================================================================} +procedure GetArray(CharSet: TMimeChar; var Result: array of Word); +begin + case CharSet of + ISO_8859_2: + CopyArray(CharISO_8859_2, Result); + ISO_8859_3: + CopyArray(CharISO_8859_3, Result); + ISO_8859_4: + CopyArray(CharISO_8859_4, Result); + ISO_8859_5: + CopyArray(CharISO_8859_5, Result); + ISO_8859_6: + CopyArray(CharISO_8859_6, Result); + ISO_8859_7: + CopyArray(CharISO_8859_7, Result); + ISO_8859_8: + CopyArray(CharISO_8859_8, Result); + ISO_8859_9: + CopyArray(CharISO_8859_9, Result); + ISO_8859_10: + CopyArray(CharISO_8859_10, Result); + ISO_8859_13: + CopyArray(CharISO_8859_13, Result); + ISO_8859_14: + CopyArray(CharISO_8859_14, Result); + ISO_8859_15: + CopyArray(CharISO_8859_15, Result); + CP1250: + CopyArray(CharCP_1250, Result); + CP1251: + CopyArray(CharCP_1251, Result); + CP1252: + CopyArray(CharCP_1252, Result); + CP1253: + CopyArray(CharCP_1253, Result); + CP1254: + CopyArray(CharCP_1254, Result); + CP1255: + CopyArray(CharCP_1255, Result); + CP1256: + CopyArray(CharCP_1256, Result); + CP1257: + CopyArray(CharCP_1257, Result); + CP1258: + CopyArray(CharCP_1258, Result); + KOI8_R: + CopyArray(CharKOI8_R, Result); + CP895: + CopyArray(CharCP_895, Result); + CP852: + CopyArray(CharCP_852, Result); + else + CopyArray(CharISO_8859_1, Result); + end; +end; + +{==============================================================================} +procedure ReadMulti(const Value: AnsiString; var Index: Integer; mb: Byte; + var b1, b2, b3, b4: Byte; le: boolean); +Begin + b1 := 0; + b2 := 0; + b3 := 0; + b4 := 0; + if Index < 0 then + Index := 1; + if mb > 4 then + mb := 1; + if (Index + mb - 1) <= Length(Value) then + begin + if le then + Case mb Of + 1: + b1 := Ord(Value[Index]); + 2: + Begin + b1 := Ord(Value[Index]); + b2 := Ord(Value[Index + 1]); + End; + 3: + Begin + b1 := Ord(Value[Index]); + b2 := Ord(Value[Index + 1]); + b3 := Ord(Value[Index + 2]); + End; + 4: + Begin + b1 := Ord(Value[Index]); + b2 := Ord(Value[Index + 1]); + b3 := Ord(Value[Index + 2]); + b4 := Ord(Value[Index + 3]); + End; + end + else + Case mb Of + 1: + b1 := Ord(Value[Index]); + 2: + Begin + b2 := Ord(Value[Index]); + b1 := Ord(Value[Index + 1]); + End; + 3: + Begin + b3 := Ord(Value[Index]); + b2 := Ord(Value[Index + 1]); + b1 := Ord(Value[Index + 2]); + End; + 4: + Begin + b4 := Ord(Value[Index]); + b3 := Ord(Value[Index + 1]); + b2 := Ord(Value[Index + 2]); + b1 := Ord(Value[Index + 3]); + End; + end; + end; + Inc(Index, mb); +end; + +{==============================================================================} +function WriteMulti(b1, b2, b3, b4: Byte; mb: Byte; le: boolean): AnsiString; +begin + if mb > 4 then + mb := 1; + SetLength(Result, mb); + if le then + case mb Of + 1: + Result[1] := AnsiChar(b1); + 2: + begin + Result[1] := AnsiChar(b1); + Result[2] := AnsiChar(b2); + end; + 3: + begin + Result[1] := AnsiChar(b1); + Result[2] := AnsiChar(b2); + Result[3] := AnsiChar(b3); + end; + 4: + begin + Result[1] := AnsiChar(b1); + Result[2] := AnsiChar(b2); + Result[3] := AnsiChar(b3); + Result[4] := AnsiChar(b4); + end; + end + else + case mb Of + 1: + Result[1] := AnsiChar(b1); + 2: + begin + Result[2] := AnsiChar(b1); + Result[1] := AnsiChar(b2); + end; + 3: + begin + Result[3] := AnsiChar(b1); + Result[2] := AnsiChar(b2); + Result[1] := AnsiChar(b3); + end; + 4: + begin + Result[4] := AnsiChar(b1); + Result[3] := AnsiChar(b2); + Result[2] := AnsiChar(b3); + Result[1] := AnsiChar(b4); + end; + end; +end; + +{==============================================================================} +function UTF8toUCS4(const Value: AnsiString): AnsiString; +var + n, x, ul, m: Integer; + s: AnsiString; + w1, w2: Word; +begin + Result := ''; + n := 1; + while Length(Value) >= n do + begin + x := Ord(Value[n]); + Inc(n); + if x < 128 then + Result := Result + WriteMulti(x, 0, 0, 0, 4, false) + else + begin + m := 0; + if (x and $E0) = $C0 then + m := $1F; + if (x and $F0) = $E0 then + m := $0F; + if (x and $F8) = $F0 then + m := $07; + if (x and $FC) = $F8 then + m := $03; + if (x and $FE) = $FC then + m := $01; + ul := x and m; + s := IntToBin(ul, 0); + while Length(Value) >= n do + begin + x := Ord(Value[n]); + Inc(n); + if (x and $C0) = $80 then + s := s + IntToBin(x and $3F, 6) + else + begin + Dec(n); + Break; + end; + end; + ul := BinToInt(s); + w1 := ul div 65536; + w2 := ul mod 65536; + Result := Result + WriteMulti(Lo(w2), Hi(w2), Lo(w1), Hi(w1), 4, false); + end; + end; +end; + +{==============================================================================} +function UCS4toUTF8(const Value: AnsiString): AnsiString; +var + s, l, k: AnsiString; + b1, b2, b3, b4: Byte; + n, m, x, y: Integer; + b: Byte; +begin + Result := ''; + n := 1; + while Length(Value) >= n do + begin + ReadMulti(Value, n, 4, b1, b2, b3, b4, false); + if (b2 = 0) and (b3 = 0) and (b4 = 0) and (b1 < 128) then + Result := Result + AnsiChar(b1) + else + begin + x := (b1 + 256 * b2) + (b3 + 256 * b4) * 65536; + l := IntToBin(x, 0); + y := Length(l) div 6; + s := ''; + for m := 1 to y do + begin + k := Copy(l, Length(l) - 5, 6); + l := Copy(l, 1, Length(l) - 6); + b := BinToInt(k) or $80; + s := AnsiChar(b) + s; + end; + b := BinToInt(l); + case y of + 5: + b := b or $FC; + 4: + b := b or $F8; + 3: + b := b or $F0; + 2: + b := b or $E0; + 1: + b := b or $C0; + end; + s := AnsiChar(b) + s; + Result := Result + s; + end; + end; +end; + +{==============================================================================} +function UTF7toUCS2(const Value: AnsiString; Modified: Boolean): AnsiString; +var + n, i: Integer; + c: AnsiChar; + s, t: AnsiString; + shift: AnsiChar; + table: String; +begin + Result := ''; + n := 1; + if modified then + begin + shift := '&'; + table := TableBase64mod; + end + else + begin + shift := '+'; + table := TableBase64; + end; + while Length(Value) >= n do + begin + c := Value[n]; + Inc(n); + if c <> shift then + Result := Result + WriteMulti(Ord(c), 0, 0, 0, 2, false) + else + begin + s := ''; + while Length(Value) >= n do + begin + c := Value[n]; + Inc(n); + if c = '-' then + Break; + if (c = '=') or (Pos(c, table) < 1) then + begin + Dec(n); + Break; + end; + s := s + c; + end; + if s = '' then + s := WriteMulti(Ord(shift), 0, 0, 0, 2, false) + else + begin + if modified then + t := DecodeBase64mod(s) + else + t := DecodeBase64(s); + if not odd(length(t)) then + s := t + else + begin //ill-formed sequence + t := s; + s := WriteMulti(Ord(shift), 0, 0, 0, 2, false); + for i := 1 to length(t) do + s := s + WriteMulti(Ord(t[i]), 0, 0, 0, 2, false); + end; + end; + Result := Result + s; + end; + end; +end; + +{==============================================================================} +function UCS2toUTF7(const Value: AnsiString; Modified: Boolean): AnsiString; +var + s: AnsiString; + b1, b2, b3, b4: Byte; + n, m: Integer; + shift: AnsiChar; +begin + Result := ''; + n := 1; + if modified then + shift := '&' + else + shift := '+'; + while Length(Value) >= n do + begin + ReadMulti(Value, n, 2, b1, b2, b3, b4, false); + if (b2 = 0) and (b1 < 128) then + if AnsiChar(b1) = shift then + Result := Result + shift + '-' + else + Result := Result + AnsiChar(b1) + else + begin + s := AnsiChar(b2) + AnsiChar(b1); + while Length(Value) >= n do + begin + ReadMulti(Value, n, 2, b1, b2, b3, b4, false); + if (b2 = 0) and (b1 < 128) then + begin + Dec(n, 2); + Break; + end; + s := s + AnsiChar(b2) + AnsiChar(b1); + end; + if modified then + s := EncodeBase64mod(s) + else + s := EncodeBase64(s); + m := Pos('=', s); + if m > 0 then + s := Copy(s, 1, m - 1); + Result := Result + shift + s + '-'; + end; + end; +end; + +{==============================================================================} +function CharsetConversion(const Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeChar): AnsiString; +begin + Result := CharsetConversionEx(Value, CharFrom, CharTo, Replace_None); +end; + +{==============================================================================} +function CharsetConversionEx(const Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeChar; const TransformTable: array of Word): AnsiString; +begin + Result := CharsetConversionTrans(Value, CharFrom, CharTo, TransformTable, True); +end; + +{==============================================================================} + +function InternalToUcs(const Value: AnsiString; Charfrom: TMimeChar): AnsiString; +var + uni: Word; + n: Integer; + b1, b2, b3, b4: Byte; + SourceTable: array[128..255] of Word; + mbf: Byte; + lef: Boolean; + s: AnsiString; +begin + if CharFrom = UTF_8 then + s := UTF8toUCS4(Value) + else + if CharFrom = UTF_7 then + s := UTF7toUCS2(Value, False) + else + if CharFrom = UTF_7mod then + s := UTF7toUCS2(Value, True) + else + s := Value; + GetArray(CharFrom, SourceTable); + mbf := 1; + if CharFrom in SetTwo then + mbf := 2; + if CharFrom in SetFour then + mbf := 4; + lef := CharFrom in SetLe; + Result := ''; + n := 1; + while Length(s) >= n do + begin + ReadMulti(s, n, mbf, b1, b2, b3, b4, lef); + //handle BOM + if (b3 = 0) and (b4 = 0) then + begin + if (b1 = $FE) and (b2 = $FF) then + begin + lef := not lef; + continue; + end; + if (b1 = $FF) and (b2 = $FE) then + continue; + end; + if mbf = 1 then + if b1 > 127 then + begin + uni := SourceTable[b1]; + b1 := Lo(uni); + b2 := Hi(uni); + end; + Result := Result + WriteMulti(b1, b2, b3, b4, 2, False); + end; +end; + +function CharsetConversionTrans(Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeChar; const TransformTable: array of Word; Translit: Boolean): AnsiString; +var + uni: Word; + n, m: Integer; + b: Byte; + b1, b2, b3, b4: Byte; + TargetTable: array[128..255] of Word; + mbt: Byte; + let: Boolean; + ucsstring, s, t: AnsiString; + cd: iconv_t; + f: Boolean; + NotNeedTransform: Boolean; + FromID, ToID: string; +begin + NotNeedTransform := (High(TransformTable) = 0); + if (CharFrom = CharTo) and NotNeedTransform then + begin + Result := Value; + Exit; + end; + FromID := GetIDFromCP(CharFrom); + ToID := GetIDFromCP(CharTo); + cd := Iconv_t(-1); + //do two-pass conversion. Transform to UCS-2 first. + if not DisableIconv then + cd := SynaIconvOpenIgnore('UCS-2BE', FromID); + try + if cd <> iconv_t(-1) then + SynaIconv(cd, Value, ucsstring) + else + ucsstring := InternalToUcs(Value, CharFrom); + finally + SynaIconvClose(cd); + end; + //here we allways have ucstring with UCS-2 encoding + //second pass... from UCS-2 to target encoding. + if not DisableIconv then + if translit then + cd := SynaIconvOpenTranslit(ToID, 'UCS-2BE') + else + cd := SynaIconvOpenIgnore(ToID, 'UCS-2BE'); + try + if (cd <> iconv_t(-1)) and NotNeedTransform then + begin + if CharTo = UTF_7 then + ucsstring := ucsstring + #0 + '-'; + //when transformtable is not needed and Iconv know target charset, + //do it fast by one call. + SynaIconv(cd, ucsstring, Result); + if CharTo = UTF_7 then + Delete(Result, Length(Result), 1); + end + else + begin + GetArray(CharTo, TargetTable); + mbt := 1; + if CharTo in SetTwo then + mbt := 2; + if CharTo in SetFour then + mbt := 4; + let := CharTo in SetLe; + b3 := 0; + b4 := 0; + Result := ''; + for n:= 0 to (Length(ucsstring) div 2) - 1 do + begin + s := Copy(ucsstring, n * 2 + 1, 2); + b2 := Ord(s[1]); + b1 := Ord(s[2]); + uni := b2 * 256 + b1; + if not NotNeedTransform then + begin + uni := ReplaceUnicode(uni, TransformTable); + b1 := Lo(uni); + b2 := Hi(uni); + s[1] := AnsiChar(b2); + s[2] := AnsiChar(b1); + end; + if cd <> iconv_t(-1) then + begin + if CharTo = UTF_7 then + s := s + #0 + '-'; + SynaIconv(cd, s, t); + if CharTo = UTF_7 then + Delete(t, Length(t), 1); + Result := Result + t; + end + else + begin + f := True; + if mbt = 1 then + if uni > 127 then + begin + f := False; + b := 0; + for m := 128 to 255 do + if TargetTable[m] = uni then + begin + b := m; + f := True; + Break; + end; + b1 := b; + b2 := 0; + end + else + b1 := Lo(uni); + if not f then + if translit then + begin + b1 := Ord(NotFoundChar); + b2 := 0; + f := True; + end; + if f then + Result := Result + WriteMulti(b1, b2, b3, b4, mbt, let) + end; + end; + if cd = iconv_t(-1) then + begin + if CharTo = UTF_7 then + Result := UCS2toUTF7(Result, false); + if CharTo = UTF_7mod then + Result := UCS2toUTF7(Result, true); + if CharTo = UTF_8 then + Result := UCS4toUTF8(Result); + end; + end; + finally + SynaIconvClose(cd); + end; +end; + +{==============================================================================} +{$IFNDEF MSWINDOWS} + +function GetCurCP: TMimeChar; +begin + {$IFNDEF FPC} + Result := GetCPFromID(nl_langinfo(_NL_CTYPE_CODESET_NAME)); + {$ELSE} + //How to get system codepage without LIBC? + Result := UTF_8; +{ TODO : Waiting for FPC 2.8 solution } + {$ENDIF} +end; + +function GetCurOEMCP: TMimeChar; +begin + Result := GetCurCP; +end; + +{$ELSE} + +function CPToMimeChar(Value: Integer): TMimeChar; +begin + case Value of + 437, 850, 20127: + Result := ISO_8859_1; //I know, it is not ideal! + 737: + Result := CP737; + 775: + Result := CP775; + 852: + Result := CP852; + 855: + Result := CP855; + 857: + Result := CP857; + 858: + Result := CP858; + 860: + Result := CP860; + 861: + Result := CP861; + 862: + Result := CP862; + 863: + Result := CP863; + 864: + Result := CP864; + 865: + Result := CP865; + 866: + Result := CP866; + 869: + Result := CP869; + 874: + Result := ISO_8859_15; + 895: + Result := CP895; + 932: + Result := CP932; + 936: + Result := CP936; + 949: + Result := CP949; + 950: + Result := CP950; + 1200: + Result := UCS_2LE; + 1201: + Result := UCS_2; + 1250: + Result := CP1250; + 1251: + Result := CP1251; + 1253: + Result := CP1253; + 1254: + Result := CP1254; + 1255: + Result := CP1255; + 1256: + Result := CP1256; + 1257: + Result := CP1257; + 1258: + Result := CP1258; + 1361: + Result := CP1361; + 10000: + Result := MAC; + 10004: + Result := MACAR; + 10005: + Result := MACHEB; + 10006: + Result := MACGR; + 10007: + Result := MACCYR; + 10010: + Result := MACRO; + 10017: + Result := MACUK; + 10021: + Result := MACTH; + 10029: + Result := MACCE; + 10079: + Result := MACICE; + 10081: + Result := MACTU; + 10082: + Result := MACCRO; + 12000: + Result := UCS_4LE; + 12001: + Result := UCS_4; + 20866: + Result := KOI8_R; + 20932: + Result := JIS_X0208; + 20936: + Result := GB2312; + 21866: + Result := KOI8_U; + 28591: + Result := ISO_8859_1; + 28592: + Result := ISO_8859_2; + 28593: + Result := ISO_8859_3; + 28594: + Result := ISO_8859_4; + 28595: + Result := ISO_8859_5; + 28596, 708: + Result := ISO_8859_6; + 28597: + Result := ISO_8859_7; + 28598, 38598: + Result := ISO_8859_8; + 28599: + Result := ISO_8859_9; + 28605: + Result := ISO_8859_15; + 50220: + Result := ISO_2022_JP; //? ISO 2022 Japanese with no halfwidth Katakana + 50221: + Result := ISO_2022_JP1;//? Japanese with halfwidth Katakana + 50222: + Result := ISO_2022_JP2;//? Japanese JIS X 0201-1989 + 50225: + Result := ISO_2022_KR; + 50227: + Result := ISO_2022_CN;//? ISO 2022 Simplified Chinese + 50229: + Result := ISO_2022_CNE;//? ISO 2022 Traditional Chinese + 51932: + Result := EUC_JP; + 51936: + Result := GB2312; + 51949: + Result := EUC_KR; + 52936: + Result := HZ; + 54936: + Result := GB18030; + 65000: + Result := UTF_7; + 65001: + Result := UTF_8; + 0: + Result := UCS_2LE; + else + Result := CP1252; + end; +end; + +function GetCurCP: TMimeChar; +begin + Result := CPToMimeChar(GetACP); +end; + +function GetCurOEMCP: TMimeChar; +begin + Result := CPToMimeChar(GetOEMCP); +end; +{$ENDIF} + +{==============================================================================} +function NeedCharsetConversion(const Value: AnsiString): Boolean; +var + n: Integer; +begin + Result := False; + for n := 1 to Length(Value) do + if (Ord(Value[n]) > 127) or (Ord(Value[n]) = 0) then + begin + Result := True; + Break; + end; +end; + +{==============================================================================} +function IdealCharsetCoding(const Value: AnsiString; CharFrom: TMimeChar; + CharTo: TMimeSetChar): TMimeChar; +var + n: Integer; + max: Integer; + s, t, u: AnsiString; + CharSet: TMimeChar; +begin + Result := ISO_8859_1; + s := Copy(Value, 1, 1024); //max first 1KB for next procedure + max := 0; + for n := Ord(Low(TMimeChar)) to Ord(High(TMimeChar)) do + begin + CharSet := TMimeChar(n); + if CharSet in CharTo then + begin + t := CharsetConversionTrans(s, CharFrom, CharSet, Replace_None, False); + u := CharsetConversionTrans(t, CharSet, CharFrom, Replace_None, False); + if s = u then + begin + Result := CharSet; + Exit; + end; + if Length(u) > max then + begin + Result := CharSet; + max := Length(u); + end; + end; + end; +end; + +{==============================================================================} +function GetBOM(Value: TMimeChar): AnsiString; +begin + Result := ''; + case Value of + UCS_2: + Result := #$fe + #$ff; + UCS_4: + Result := #$00 + #$00 + #$fe + #$ff; + UCS_2LE: + Result := #$ff + #$fe; + UCS_4LE: + Result := #$ff + #$fe + #$00 + #$00; + UTF_8: + Result := #$ef + #$bb + #$bf; + end; +end; + +{==============================================================================} +function GetCPFromID(Value: AnsiString): TMimeChar; +begin + Value := UpperCase(Value); + if (Pos('KAMENICKY', Value) > 0) or (Pos('895', Value) > 0) then + Result := CP895 + else + if Pos('MUTF-7', Value) > 0 then + Result := UTF_7mod + else + Result := GetCPFromIconvID(Value); +end; + +{==============================================================================} +function GetIDFromCP(Value: TMimeChar): AnsiString; +begin + case Value of + CP895: + Result := 'CP-895'; + UTF_7mod: + Result := 'mUTF-7'; + else + Result := GetIconvIDFromCP(Value); + end; +end; + +{==============================================================================} +function StringToWide(const Value: AnsiString): WideString; +var + n: integer; + x, y: integer; +begin + SetLength(Result, Length(Value) div 2); + for n := 1 to Length(Value) div 2 do + begin + x := Ord(Value[((n-1) * 2) + 1]); + y := Ord(Value[((n-1) * 2) + 2]); + Result[n] := WideChar(x * 256 + y); + end; +end; + +{==============================================================================} +function WideToString(const Value: WideString): AnsiString; +var + n: integer; + x: integer; +begin + SetLength(Result, Length(Value) * 2); + for n := 1 to Length(Value) do + begin + x := Ord(Value[n]); + Result[((n-1) * 2) + 1] := AnsiChar(x div 256); + Result[((n-1) * 2) + 2] := AnsiChar(x mod 256); + end; +end; + +{==============================================================================} +initialization +begin + IconvArr[0].Charset := ISO_8859_1; + IconvArr[0].Charname := 'ISO-8859-1 CP819 IBM819 ISO-IR-100 ISO8859-1 ISO_8859-1 ISO_8859-1:1987 L1 LATIN1 CSISOLATIN1'; + IconvArr[1].Charset := UTF_8; + IconvArr[1].Charname := 'UTF-8'; + IconvArr[2].Charset := UCS_2; + IconvArr[2].Charname := 'ISO-10646-UCS-2 UCS-2 CSUNICODE'; + IconvArr[3].Charset := UCS_2; + IconvArr[3].Charname := 'UCS-2BE UNICODE-1-1 UNICODEBIG CSUNICODE11'; + IconvArr[4].Charset := UCS_2LE; + IconvArr[4].Charname := 'UCS-2LE UNICODELITTLE'; + IconvArr[5].Charset := UCS_4; + IconvArr[5].Charname := 'ISO-10646-UCS-4 UCS-4 CSUCS4'; + IconvArr[6].Charset := UCS_4; + IconvArr[6].Charname := 'UCS-4BE'; + IconvArr[7].Charset := UCS_2LE; + IconvArr[7].Charname := 'UCS-4LE'; + IconvArr[8].Charset := UTF_16; + IconvArr[8].Charname := 'UTF-16'; + IconvArr[9].Charset := UTF_16; + IconvArr[9].Charname := 'UTF-16BE'; + IconvArr[10].Charset := UTF_16LE; + IconvArr[10].Charname := 'UTF-16LE'; + IconvArr[11].Charset := UTF_32; + IconvArr[11].Charname := 'UTF-32'; + IconvArr[12].Charset := UTF_32; + IconvArr[12].Charname := 'UTF-32BE'; + IconvArr[13].Charset := UTF_32; + IconvArr[13].Charname := 'UTF-32LE'; + IconvArr[14].Charset := UTF_7; + IconvArr[14].Charname := 'UNICODE-1-1-UTF-7 UTF-7 CSUNICODE11UTF7'; + IconvArr[15].Charset := C99; + IconvArr[15].Charname := 'C99'; + IconvArr[16].Charset := JAVA; + IconvArr[16].Charname := 'JAVA'; + IconvArr[17].Charset := ISO_8859_1; + IconvArr[17].Charname := 'US-ASCII ANSI_X3.4-1968 ANSI_X3.4-1986 ASCII CP367 IBM367 ISO-IR-6 ISO646-US ISO_646.IRV:1991 US CSASCII'; + IconvArr[18].Charset := ISO_8859_2; + IconvArr[18].Charname := 'ISO-8859-2 ISO-IR-101 ISO8859-2 ISO_8859-2 ISO_8859-2:1987 L2 LATIN2 CSISOLATIN2'; + IconvArr[19].Charset := ISO_8859_3; + IconvArr[19].Charname := 'ISO-8859-3 ISO-IR-109 ISO8859-3 ISO_8859-3 ISO_8859-3:1988 L3 LATIN3 CSISOLATIN3'; + IconvArr[20].Charset := ISO_8859_4; + IconvArr[20].Charname := 'ISO-8859-4 ISO-IR-110 ISO8859-4 ISO_8859-4 ISO_8859-4:1988 L4 LATIN4 CSISOLATIN4'; + IconvArr[21].Charset := ISO_8859_5; + IconvArr[21].Charname := 'ISO-8859-5 CYRILLIC ISO-IR-144 ISO8859-5 ISO_8859-5 ISO_8859-5:1988 CSISOLATINCYRILLIC'; + IconvArr[22].Charset := ISO_8859_6; + IconvArr[22].Charname := 'ISO-8859-6 ARABIC ASMO-708 ECMA-114 ISO-IR-127 ISO8859-6 ISO_8859-6 ISO_8859-6:1987 CSISOLATINARABIC'; + IconvArr[23].Charset := ISO_8859_7; + IconvArr[23].Charname := 'ISO-8859-7 ECMA-118 ELOT_928 GREEK GREEK8 ISO-IR-126 ISO8859-7 ISO_8859-7 ISO_8859-7:1987 CSISOLATINGREEK'; + IconvArr[24].Charset := ISO_8859_8; + IconvArr[24].Charname := 'ISO-8859-8 HEBREW ISO_8859-8 ISO-IR-138 ISO8859-8 ISO_8859-8:1988 CSISOLATINHEBREW ISO-8859-8-I'; + IconvArr[25].Charset := ISO_8859_9; + IconvArr[25].Charname := 'ISO-8859-9 ISO-IR-148 ISO8859-9 ISO_8859-9 ISO_8859-9:1989 L5 LATIN5 CSISOLATIN5'; + IconvArr[26].Charset := ISO_8859_10; + IconvArr[26].Charname := 'ISO-8859-10 ISO-IR-157 ISO8859-10 ISO_8859-10 ISO_8859-10:1992 L6 LATIN6 CSISOLATIN6'; + IconvArr[27].Charset := ISO_8859_13; + IconvArr[27].Charname := 'ISO-8859-13 ISO-IR-179 ISO8859-13 ISO_8859-13 L7 LATIN7'; + IconvArr[28].Charset := ISO_8859_14; + IconvArr[28].Charname := 'ISO-8859-14 ISO-CELTIC ISO-IR-199 ISO8859-14 ISO_8859-14 ISO_8859-14:1998 L8 LATIN8'; + IconvArr[29].Charset := ISO_8859_15; + IconvArr[29].Charname := 'ISO-8859-15 ISO-IR-203 ISO8859-15 ISO_8859-15 ISO_8859-15:1998'; + IconvArr[30].Charset := ISO_8859_16; + IconvArr[30].Charname := 'ISO-8859-16 ISO-IR-226 ISO8859-16 ISO_8859-16 ISO_8859-16:2000'; + IconvArr[31].Charset := KOI8_R; + IconvArr[31].Charname := 'KOI8-R CSKOI8R'; + IconvArr[32].Charset := KOI8_U; + IconvArr[32].Charname := 'KOI8-U'; + IconvArr[33].Charset := KOI8_RU; + IconvArr[33].Charname := 'KOI8-RU'; + IconvArr[34].Charset := CP1250; + IconvArr[34].Charname := 'WINDOWS-1250 CP1250 MS-EE'; + IconvArr[35].Charset := CP1251; + IconvArr[35].Charname := 'WINDOWS-1251 CP1251 MS-CYRL'; + IconvArr[36].Charset := CP1252; + IconvArr[36].Charname := 'WINDOWS-1252 CP1252 MS-ANSI'; + IconvArr[37].Charset := CP1253; + IconvArr[37].Charname := 'WINDOWS-1253 CP1253 MS-GREEK'; + IconvArr[38].Charset := CP1254; + IconvArr[38].Charname := 'WINDOWS-1254 CP1254 MS-TURK'; + IconvArr[39].Charset := CP1255; + IconvArr[39].Charname := 'WINDOWS-1255 CP1255 MS-HEBR'; + IconvArr[40].Charset := CP1256; + IconvArr[40].Charname := 'WINDOWS-1256 CP1256 MS-ARAB'; + IconvArr[41].Charset := CP1257; + IconvArr[41].Charname := 'WINDOWS-1257 CP1257 WINBALTRIM'; + IconvArr[42].Charset := CP1258; + IconvArr[42].Charname := 'WINDOWS-1258 CP1258'; + IconvArr[43].Charset := ISO_8859_1; + IconvArr[43].Charname := '850 CP850 IBM850 CSPC850MULTILINGUAL'; + IconvArr[44].Charset := CP862; + IconvArr[44].Charname := '862 CP862 IBM862 CSPC862LATINHEBREW'; + IconvArr[45].Charset := CP866; + IconvArr[45].Charname := '866 CP866 IBM866 CSIBM866'; + IconvArr[46].Charset := MAC; + IconvArr[46].Charname := 'MAC MACINTOSH MACROMAN CSMACINTOSH'; + IconvArr[47].Charset := MACCE; + IconvArr[47].Charname := 'MACCENTRALEUROPE'; + IconvArr[48].Charset := MACICE; + IconvArr[48].Charname := 'MACICELAND'; + IconvArr[49].Charset := MACCRO; + IconvArr[49].Charname := 'MACCROATIAN'; + IconvArr[50].Charset := MACRO; + IconvArr[50].Charname := 'MACROMANIA'; + IconvArr[51].Charset := MACCYR; + IconvArr[51].Charname := 'MACCYRILLIC'; + IconvArr[52].Charset := MACUK; + IconvArr[52].Charname := 'MACUKRAINE'; + IconvArr[53].Charset := MACGR; + IconvArr[53].Charname := 'MACGREEK'; + IconvArr[54].Charset := MACTU; + IconvArr[54].Charname := 'MACTURKISH'; + IconvArr[55].Charset := MACHEB; + IconvArr[55].Charname := 'MACHEBREW'; + IconvArr[56].Charset := MACAR; + IconvArr[56].Charname := 'MACARABIC'; + IconvArr[57].Charset := MACTH; + IconvArr[57].Charname := 'MACTHAI'; + IconvArr[58].Charset := ROMAN8; + IconvArr[58].Charname := 'HP-ROMAN8 R8 ROMAN8 CSHPROMAN8'; + IconvArr[59].Charset := NEXTSTEP; + IconvArr[59].Charname := 'NEXTSTEP'; + IconvArr[60].Charset := ARMASCII; + IconvArr[60].Charname := 'ARMSCII-8'; + IconvArr[61].Charset := GEORGIAN_AC; + IconvArr[61].Charname := 'GEORGIAN-ACADEMY'; + IconvArr[62].Charset := GEORGIAN_PS; + IconvArr[62].Charname := 'GEORGIAN-PS'; + IconvArr[63].Charset := KOI8_T; + IconvArr[63].Charname := 'KOI8-T'; + IconvArr[64].Charset := MULELAO; + IconvArr[64].Charname := 'MULELAO-1'; + IconvArr[65].Charset := CP1133; + IconvArr[65].Charname := 'CP1133 IBM-CP1133'; + IconvArr[66].Charset := TIS620; + IconvArr[66].Charname := 'TIS-620 ISO-IR-166 TIS620 TIS620-0 TIS620.2529-1 TIS620.2533-0 TIS620.2533-1'; + IconvArr[67].Charset := CP874; + IconvArr[67].Charname := 'CP874 WINDOWS-874'; + IconvArr[68].Charset := VISCII; + IconvArr[68].Charname := 'VISCII VISCII1.1-1 CSVISCII'; + IconvArr[69].Charset := TCVN; + IconvArr[69].Charname := 'TCVN TCVN-5712 TCVN5712-1 TCVN5712-1:1993'; + IconvArr[70].Charset := ISO_IR_14; + IconvArr[70].Charname := 'ISO-IR-14 ISO646-JP JIS_C6220-1969-RO JP CSISO14JISC6220RO'; + IconvArr[71].Charset := JIS_X0201; + IconvArr[71].Charname := 'JISX0201-1976 JIS_X0201 X0201 CSHALFWIDTHKATAKANA'; + IconvArr[72].Charset := JIS_X0208; + IconvArr[72].Charname := 'ISO-IR-87 JIS0208 JIS_C6226-1983 JIS_X0208 JIS_X0208-1983 JIS_X0208-1990 X0208 CSISO87JISX0208'; + IconvArr[73].Charset := JIS_X0212; + IconvArr[73].Charname := 'ISO-IR-159 JIS_X0212 JIS_X0212-1990 JIS_X0212.1990-0 X0212 CSISO159JISX02121990'; + IconvArr[74].Charset := GB1988_80; + IconvArr[74].Charname := 'CN GB_1988-80 ISO-IR-57 ISO646-CN CSISO57GB1988'; + IconvArr[75].Charset := GB2312_80; + IconvArr[75].Charname := 'CHINESE GB_2312-80 ISO-IR-58 CSISO58GB231280'; + IconvArr[76].Charset := ISO_IR_165; + IconvArr[76].Charname := 'CN-GB-ISOIR165 ISO-IR-165'; + IconvArr[77].Charset := ISO_IR_149; + IconvArr[77].Charname := 'ISO-IR-149 KOREAN KSC_5601 KS_C_5601-1987 KS_C_5601-1989 CSKSC56011987'; + IconvArr[78].Charset := EUC_JP; + IconvArr[78].Charname := 'EUC-JP EUCJP EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE CSEUCPKDFMTJAPANESE'; + IconvArr[79].Charset := SHIFT_JIS; + IconvArr[79].Charname := 'SHIFT-JIS MS_KANJI SHIFT_JIS SJIS CSSHIFTJIS'; + IconvArr[80].Charset := CP932; + IconvArr[80].Charname := 'CP932'; + IconvArr[81].Charset := ISO_2022_JP; + IconvArr[81].Charname := 'ISO-2022-JP CSISO2022JP'; + IconvArr[82].Charset := ISO_2022_JP1; + IconvArr[82].Charname := 'ISO-2022-JP-1'; + IconvArr[83].Charset := ISO_2022_JP2; + IconvArr[83].Charname := 'ISO-2022-JP-2 CSISO2022JP2'; + IconvArr[84].Charset := GB2312; + IconvArr[84].Charname := 'CN-GB EUC-CN EUCCN GB2312 CSGB2312'; + IconvArr[85].Charset := CP936; + IconvArr[85].Charname := 'CP936 GBK'; + IconvArr[86].Charset := GB18030; + IconvArr[86].Charname := 'GB18030'; + IconvArr[87].Charset := ISO_2022_CN; + IconvArr[87].Charname := 'ISO-2022-CN CSISO2022CN'; + IconvArr[88].Charset := ISO_2022_CNE; + IconvArr[88].Charname := 'ISO-2022-CN-EXT'; + IconvArr[89].Charset := HZ; + IconvArr[89].Charname := 'HZ HZ-GB-2312'; + IconvArr[90].Charset := EUC_TW; + IconvArr[90].Charname := 'EUC-TW EUCTW CSEUCTW'; + IconvArr[91].Charset := BIG5; + IconvArr[91].Charname := 'BIG5 BIG-5 BIG-FIVE BIGFIVE CN-BIG5 CSBIG5'; + IconvArr[92].Charset := CP950; + IconvArr[92].Charname := 'CP950'; + IconvArr[93].Charset := BIG5_HKSCS; + IconvArr[93].Charname := 'BIG5-HKSCS BIG5HKSCS'; + IconvArr[94].Charset := EUC_KR; + IconvArr[94].Charname := 'EUC-KR EUCKR CSEUCKR'; + IconvArr[95].Charset := CP949; + IconvArr[95].Charname := 'CP949 UHC'; + IconvArr[96].Charset := CP1361; + IconvArr[96].Charname := 'CP1361 JOHAB'; + IconvArr[97].Charset := ISO_2022_KR; + IconvArr[97].Charname := 'ISO-2022-KR CSISO2022KR'; + IconvArr[98].Charset := ISO_8859_1; + IconvArr[98].Charname := '437 CP437 IBM437 CSPC8CODEPAGE437'; + IconvArr[99].Charset := CP737; + IconvArr[99].Charname := 'CP737'; + IconvArr[100].Charset := CP775; + IconvArr[100].Charname := 'CP775 IBM775 CSPC775BALTIC'; + IconvArr[101].Charset := CP852; + IconvArr[101].Charname := '852 CP852 IBM852 CSPCP852'; + IconvArr[102].Charset := CP853; + IconvArr[102].Charname := 'CP853'; + IconvArr[103].Charset := CP855; + IconvArr[103].Charname := '855 CP855 IBM855 CSIBM855'; + IconvArr[104].Charset := CP857; + IconvArr[104].Charname := '857 CP857 IBM857 CSIBM857'; + IconvArr[105].Charset := CP858; + IconvArr[105].Charname := 'CP858'; + IconvArr[106].Charset := CP860; + IconvArr[106].Charname := '860 CP860 IBM860 CSIBM860'; + IconvArr[107].Charset := CP861; + IconvArr[107].Charname := '861 CP-IS CP861 IBM861 CSIBM861'; + IconvArr[108].Charset := CP863; + IconvArr[108].Charname := '863 CP863 IBM863 CSIBM863'; + IconvArr[109].Charset := CP864; + IconvArr[109].Charname := 'CP864 IBM864 CSIBM864'; + IconvArr[110].Charset := CP865; + IconvArr[110].Charname := '865 CP865 IBM865 CSIBM865'; + IconvArr[111].Charset := CP869; + IconvArr[111].Charname := '869 CP-GR CP869 IBM869 CSIBM869'; + IconvArr[112].Charset := CP1125; + IconvArr[112].Charname := 'CP1125'; +end; + +end. diff --git a/3rd/synapse/source/synacode.pas b/3rd/synapse/source/synacode.pas index 52c9dfed9..6ab39c1ab 100644 --- a/3rd/synapse/source/synacode.pas +++ b/3rd/synapse/source/synacode.pas @@ -1,1467 +1,1467 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.002.003 | -|==============================================================================| -| Content: Coding and decoding support | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Various encoding and decoding support)} -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} -{$TYPEDADDRESS OFF} - -{$IFDEF CIL} - {$DEFINE SYNACODE_NATIVE} -{$ENDIF} -{$IFDEF FPC_BIG_ENDIAN} - {$DEFINE SYNACODE_NATIVE} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit synacode; - -interface - -uses - SysUtils; - -type - TSpecials = set of AnsiChar; - -const - - SpecialChar: TSpecials = - ['=', '(', ')', '[', ']', '<', '>', ':', ';', ',', '@', '/', '?', '\', - '"', '_']; - NonAsciiChar: TSpecials = - [#0..#31, #127..#255]; - URLFullSpecialChar: TSpecials = - [';', '/', '?', ':', '@', '=', '&', '#', '+']; - URLSpecialChar: TSpecials = - [#$00..#$20, '<', '>', '"', '%', '{', '}', '|', '\', '^', '[', ']', '`', #$7F..#$FF]; - TableBase64 = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - TableBase64mod = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,='; - TableUU = - '`!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'; - TableXX = - '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - ReTablebase64 = - #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$3E +#$40 - +#$40 +#$40 +#$3F +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C - +#$3D +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$01 +#$02 +#$03 - +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C +#$0D +#$0E +#$0F - +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 - +#$22 +#$23 +#$24 +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D - +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; - ReTableUU = - #$01 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C - +#$0D +#$0E +#$0F +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 - +#$19 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 - +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D +#$2E +#$2F +#$30 - +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C - +#$3D +#$3E +#$3F +#$00 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; - ReTableXX = - #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$40 - +#$01 +#$40 +#$40 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A - +#$0B +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$0C +#$0D +#$0E +#$0F - +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$1A +#$1B - +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 +#$25 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D - +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 - +#$3A +#$3B +#$3C +#$3D +#$3E +#$3F +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; - -{:Decodes triplet encoding with a given character delimiter. It is used for - decoding quoted-printable or URL encoding.} -function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; - -{:Decodes a string from quoted printable form. (also decodes triplet sequences - like '=7F')} -function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; - -{:Decodes a string of URL encoding. (also decodes triplet sequences like '%7F')} -function DecodeURL(const Value: AnsiString): AnsiString; - -{:Performs triplet encoding with a given character delimiter. Used for encoding - quoted-printable or URL encoding.} -function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; - Specials: TSpecials): AnsiString; - -{:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) - are encoded.} -function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; - -{:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) and - @link(SpecialChar) are encoded.} -function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; - -{:Encodes a string to URL format. Used for encoding data from a form field in - HTTP, etc. (Encodes all critical characters including characters used as URL - delimiters ('/',':', etc.)} -function EncodeURLElement(const Value: AnsiString): AnsiString; - -{:Encodes a string to URL format. Used to encode critical characters in all - URLs.} -function EncodeURL(const Value: AnsiString): AnsiString; - -{:Decode 4to3 encoding with given table. If some element is not found in table, - first item from table is used. This is good for buggy coded items by Microsoft - Outlook. This software sometimes using wrong table for UUcode, where is used - ' ' instead '`'.} -function Decode4to3(const Value, Table: AnsiString): AnsiString; - -{:Decode 4to3 encoding with given REVERSE table. Using this function with -reverse table is much faster then @link(Decode4to3). This function is used -internally for Base64, UU or XX decoding.} -function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; - -{:Encode by system 3to4 (used by Base64, UU coding, etc) by given table.} -function Encode3to4(const Value, Table: AnsiString): AnsiString; - -{:Decode string from base64 format.} -function DecodeBase64(const Value: AnsiString): AnsiString; - -{:Encodes a string to base64 format.} -function EncodeBase64(const Value: AnsiString): AnsiString; - -{:Decode string from modified base64 format. (used in IMAP, for example.)} -function DecodeBase64mod(const Value: AnsiString): AnsiString; - -{:Encodes a string to modified base64 format. (used in IMAP, for example.)} -function EncodeBase64mod(const Value: AnsiString): AnsiString; - -{:Decodes a string from UUcode format.} -function DecodeUU(const Value: AnsiString): AnsiString; - -{:encode UUcode. it encode only datas, you must also add header and footer for - proper encode.} -function EncodeUU(const Value: AnsiString): AnsiString; - -{:Decodes a string from XXcode format.} -function DecodeXX(const Value: AnsiString): AnsiString; - -{:decode line with Yenc code. This code is sometimes used in newsgroups.} -function DecodeYEnc(const Value: AnsiString): AnsiString; - -{:Returns a new CRC32 value after adding a new byte of data.} -function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; - -{:return CRC32 from a value string.} -function Crc32(const Value: AnsiString): Integer; - -{:Returns a new CRC16 value after adding a new byte of data.} -function UpdateCrc16(Value: Byte; Crc16: Word): Word; - -{:return CRC16 from a value string.} -function Crc16(const Value: AnsiString): Word; - -{:Returns a binary string with a RSA-MD5 hashing of "Value" string.} -function MD5(const Value: AnsiString): AnsiString; - -{:Returns a binary string with HMAC-MD5 hash.} -function HMAC_MD5(Text, Key: AnsiString): AnsiString; - -{:Returns a binary string with a RSA-MD5 hashing of string what is constructed - by repeating "value" until length is "Len".} -function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; - -{:Returns a binary string with a SHA-1 hashing of "Value" string.} -function SHA1(const Value: AnsiString): AnsiString; - -{:Returns a binary string with HMAC-SHA1 hash.} -function HMAC_SHA1(Text, Key: AnsiString): AnsiString; - -{:Returns a binary string with a SHA-1 hashing of string what is constructed - by repeating "value" until length is "Len".} -function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; - -{:Returns a binary string with a RSA-MD4 hashing of "Value" string.} -function MD4(const Value: AnsiString): AnsiString; - -implementation - -const - - Crc32Tab: array[0..255] of Integer = ( - Integer($00000000), Integer($77073096), Integer($EE0E612C), Integer($990951BA), - Integer($076DC419), Integer($706AF48F), Integer($E963A535), Integer($9E6495A3), - Integer($0EDB8832), Integer($79DCB8A4), Integer($E0D5E91E), Integer($97D2D988), - Integer($09B64C2B), Integer($7EB17CBD), Integer($E7B82D07), Integer($90BF1D91), - Integer($1DB71064), Integer($6AB020F2), Integer($F3B97148), Integer($84BE41DE), - Integer($1ADAD47D), Integer($6DDDE4EB), Integer($F4D4B551), Integer($83D385C7), - Integer($136C9856), Integer($646BA8C0), Integer($FD62F97A), Integer($8A65C9EC), - Integer($14015C4F), Integer($63066CD9), Integer($FA0F3D63), Integer($8D080DF5), - Integer($3B6E20C8), Integer($4C69105E), Integer($D56041E4), Integer($A2677172), - Integer($3C03E4D1), Integer($4B04D447), Integer($D20D85FD), Integer($A50AB56B), - Integer($35B5A8FA), Integer($42B2986C), Integer($DBBBC9D6), Integer($ACBCF940), - Integer($32D86CE3), Integer($45DF5C75), Integer($DCD60DCF), Integer($ABD13D59), - Integer($26D930AC), Integer($51DE003A), Integer($C8D75180), Integer($BFD06116), - Integer($21B4F4B5), Integer($56B3C423), Integer($CFBA9599), Integer($B8BDA50F), - Integer($2802B89E), Integer($5F058808), Integer($C60CD9B2), Integer($B10BE924), - Integer($2F6F7C87), Integer($58684C11), Integer($C1611DAB), Integer($B6662D3D), - Integer($76DC4190), Integer($01DB7106), Integer($98D220BC), Integer($EFD5102A), - Integer($71B18589), Integer($06B6B51F), Integer($9FBFE4A5), Integer($E8B8D433), - Integer($7807C9A2), Integer($0F00F934), Integer($9609A88E), Integer($E10E9818), - Integer($7F6A0DBB), Integer($086D3D2D), Integer($91646C97), Integer($E6635C01), - Integer($6B6B51F4), Integer($1C6C6162), Integer($856530D8), Integer($F262004E), - Integer($6C0695ED), Integer($1B01A57B), Integer($8208F4C1), Integer($F50FC457), - Integer($65B0D9C6), Integer($12B7E950), Integer($8BBEB8EA), Integer($FCB9887C), - Integer($62DD1DDF), Integer($15DA2D49), Integer($8CD37CF3), Integer($FBD44C65), - Integer($4DB26158), Integer($3AB551CE), Integer($A3BC0074), Integer($D4BB30E2), - Integer($4ADFA541), Integer($3DD895D7), Integer($A4D1C46D), Integer($D3D6F4FB), - Integer($4369E96A), Integer($346ED9FC), Integer($AD678846), Integer($DA60B8D0), - Integer($44042D73), Integer($33031DE5), Integer($AA0A4C5F), Integer($DD0D7CC9), - Integer($5005713C), Integer($270241AA), Integer($BE0B1010), Integer($C90C2086), - Integer($5768B525), Integer($206F85B3), Integer($B966D409), Integer($CE61E49F), - Integer($5EDEF90E), Integer($29D9C998), Integer($B0D09822), Integer($C7D7A8B4), - Integer($59B33D17), Integer($2EB40D81), Integer($B7BD5C3B), Integer($C0BA6CAD), - Integer($EDB88320), Integer($9ABFB3B6), Integer($03B6E20C), Integer($74B1D29A), - Integer($EAD54739), Integer($9DD277AF), Integer($04DB2615), Integer($73DC1683), - Integer($E3630B12), Integer($94643B84), Integer($0D6D6A3E), Integer($7A6A5AA8), - Integer($E40ECF0B), Integer($9309FF9D), Integer($0A00AE27), Integer($7D079EB1), - Integer($F00F9344), Integer($8708A3D2), Integer($1E01F268), Integer($6906C2FE), - Integer($F762575D), Integer($806567CB), Integer($196C3671), Integer($6E6B06E7), - Integer($FED41B76), Integer($89D32BE0), Integer($10DA7A5A), Integer($67DD4ACC), - Integer($F9B9DF6F), Integer($8EBEEFF9), Integer($17B7BE43), Integer($60B08ED5), - Integer($D6D6A3E8), Integer($A1D1937E), Integer($38D8C2C4), Integer($4FDFF252), - Integer($D1BB67F1), Integer($A6BC5767), Integer($3FB506DD), Integer($48B2364B), - Integer($D80D2BDA), Integer($AF0A1B4C), Integer($36034AF6), Integer($41047A60), - Integer($DF60EFC3), Integer($A867DF55), Integer($316E8EEF), Integer($4669BE79), - Integer($CB61B38C), Integer($BC66831A), Integer($256FD2A0), Integer($5268E236), - Integer($CC0C7795), Integer($BB0B4703), Integer($220216B9), Integer($5505262F), - Integer($C5BA3BBE), Integer($B2BD0B28), Integer($2BB45A92), Integer($5CB36A04), - Integer($C2D7FFA7), Integer($B5D0CF31), Integer($2CD99E8B), Integer($5BDEAE1D), - Integer($9B64C2B0), Integer($EC63F226), Integer($756AA39C), Integer($026D930A), - Integer($9C0906A9), Integer($EB0E363F), Integer($72076785), Integer($05005713), - Integer($95BF4A82), Integer($E2B87A14), Integer($7BB12BAE), Integer($0CB61B38), - Integer($92D28E9B), Integer($E5D5BE0D), Integer($7CDCEFB7), Integer($0BDBDF21), - Integer($86D3D2D4), Integer($F1D4E242), Integer($68DDB3F8), Integer($1FDA836E), - Integer($81BE16CD), Integer($F6B9265B), Integer($6FB077E1), Integer($18B74777), - Integer($88085AE6), Integer($FF0F6A70), Integer($66063BCA), Integer($11010B5C), - Integer($8F659EFF), Integer($F862AE69), Integer($616BFFD3), Integer($166CCF45), - Integer($A00AE278), Integer($D70DD2EE), Integer($4E048354), Integer($3903B3C2), - Integer($A7672661), Integer($D06016F7), Integer($4969474D), Integer($3E6E77DB), - Integer($AED16A4A), Integer($D9D65ADC), Integer($40DF0B66), Integer($37D83BF0), - Integer($A9BCAE53), Integer($DEBB9EC5), Integer($47B2CF7F), Integer($30B5FFE9), - Integer($BDBDF21C), Integer($CABAC28A), Integer($53B39330), Integer($24B4A3A6), - Integer($BAD03605), Integer($CDD70693), Integer($54DE5729), Integer($23D967BF), - Integer($B3667A2E), Integer($C4614AB8), Integer($5D681B02), Integer($2A6F2B94), - Integer($B40BBE37), Integer($C30C8EA1), Integer($5A05DF1B), Integer($2D02EF8D) - ); - - Crc16Tab: array[0..255] of Word = ( - $0000, $1189, $2312, $329B, $4624, $57AD, $6536, $74BF, - $8C48, $9DC1, $AF5A, $BED3, $CA6C, $DBE5, $E97E, $F8F7, - $1081, $0108, $3393, $221A, $56A5, $472C, $75B7, $643E, - $9CC9, $8D40, $BFDB, $AE52, $DAED, $CB64, $F9FF, $E876, - $2102, $308B, $0210, $1399, $6726, $76AF, $4434, $55BD, - $AD4A, $BCC3, $8E58, $9FD1, $EB6E, $FAE7, $C87C, $D9F5, - $3183, $200A, $1291, $0318, $77A7, $662E, $54B5, $453C, - $BDCB, $AC42, $9ED9, $8F50, $FBEF, $EA66, $D8FD, $C974, - $4204, $538D, $6116, $709F, $0420, $15A9, $2732, $36BB, - $CE4C, $DFC5, $ED5E, $FCD7, $8868, $99E1, $AB7A, $BAF3, - $5285, $430C, $7197, $601E, $14A1, $0528, $37B3, $263A, - $DECD, $CF44, $FDDF, $EC56, $98E9, $8960, $BBFB, $AA72, - $6306, $728F, $4014, $519D, $2522, $34AB, $0630, $17B9, - $EF4E, $FEC7, $CC5C, $DDD5, $A96A, $B8E3, $8A78, $9BF1, - $7387, $620E, $5095, $411C, $35A3, $242A, $16B1, $0738, - $FFCF, $EE46, $DCDD, $CD54, $B9EB, $A862, $9AF9, $8B70, - $8408, $9581, $A71A, $B693, $C22C, $D3A5, $E13E, $F0B7, - $0840, $19C9, $2B52, $3ADB, $4E64, $5FED, $6D76, $7CFF, - $9489, $8500, $B79B, $A612, $D2AD, $C324, $F1BF, $E036, - $18C1, $0948, $3BD3, $2A5A, $5EE5, $4F6C, $7DF7, $6C7E, - $A50A, $B483, $8618, $9791, $E32E, $F2A7, $C03C, $D1B5, - $2942, $38CB, $0A50, $1BD9, $6F66, $7EEF, $4C74, $5DFD, - $B58B, $A402, $9699, $8710, $F3AF, $E226, $D0BD, $C134, - $39C3, $284A, $1AD1, $0B58, $7FE7, $6E6E, $5CF5, $4D7C, - $C60C, $D785, $E51E, $F497, $8028, $91A1, $A33A, $B2B3, - $4A44, $5BCD, $6956, $78DF, $0C60, $1DE9, $2F72, $3EFB, - $D68D, $C704, $F59F, $E416, $90A9, $8120, $B3BB, $A232, - $5AC5, $4B4C, $79D7, $685E, $1CE1, $0D68, $3FF3, $2E7A, - $E70E, $F687, $C41C, $D595, $A12A, $B0A3, $8238, $93B1, - $6B46, $7ACF, $4854, $59DD, $2D62, $3CEB, $0E70, $1FF9, - $F78F, $E606, $D49D, $C514, $B1AB, $A022, $92B9, $8330, - $7BC7, $6A4E, $58D5, $495C, $3DE3, $2C6A, $1EF1, $0F78 - ); - -procedure ArrByteToLong(var ArByte: Array of byte; var ArLong: Array of Integer); -{$IFDEF SYNACODE_NATIVE} -var - n: integer; -{$ENDIF} -begin - if (High(ArByte) + 1) > ((High(ArLong) + 1) * 4) then - Exit; - {$IFDEF SYNACODE_NATIVE} - for n := 0 to ((high(ArByte) + 1) div 4) - 1 do - ArLong[n] := ArByte[n * 4 + 0] - + (ArByte[n * 4 + 1] shl 8) - + (ArByte[n * 4 + 2] shl 16) - + (ArByte[n * 4 + 3] shl 24); - {$ELSE} - Move(ArByte[0], ArLong[0], High(ArByte) + 1); - {$ENDIF} -end; - -procedure ArrLongToByte(var ArLong: Array of Integer; var ArByte: Array of byte); -{$IFDEF SYNACODE_NATIVE} -var - n: integer; -{$ENDIF} -begin - if (High(ArByte) + 1) < ((High(ArLong) + 1) * 4) then - Exit; - {$IFDEF SYNACODE_NATIVE} - for n := 0 to high(ArLong) do - begin - ArByte[n * 4 + 0] := ArLong[n] and $000000FF; - ArByte[n * 4 + 1] := (ArLong[n] shr 8) and $000000FF; - ArByte[n * 4 + 2] := (ArLong[n] shr 16) and $000000FF; - ArByte[n * 4 + 3] := (ArLong[n] shr 24) and $000000FF; - end; - {$ELSE} - Move(ArLong[0], ArByte[0], High(ArByte) + 1); - {$ENDIF} -end; - -type - TMDCtx = record - State: array[0..3] of Integer; - Count: array[0..1] of Integer; - BufAnsiChar: array[0..63] of Byte; - BufLong: array[0..15] of Integer; - end; - TSHA1Ctx= record - Hi, Lo: integer; - Buffer: array[0..63] of byte; - Index: integer; - Hash: array[0..4] of Integer; - HashByte: array[0..19] of byte; - end; - - TMDTransform = procedure(var Buf: array of LongInt; const Data: array of LongInt); - -{==============================================================================} - -function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; -var - x, l, lv: Integer; - c: AnsiChar; - b: Byte; - bad: Boolean; -begin - lv := Length(Value); - SetLength(Result, lv); - x := 1; - l := 1; - while x <= lv do - begin - c := Value[x]; - Inc(x); - if c <> Delimiter then - begin - Result[l] := c; - Inc(l); - end - else - if x < lv then - begin - Case Value[x] Of - #13: - if (Value[x + 1] = #10) then - Inc(x, 2) - else - Inc(x); - #10: - if (Value[x + 1] = #13) then - Inc(x, 2) - else - Inc(x); - else - begin - bad := False; - Case Value[x] Of - '0'..'9': b := (Byte(Value[x]) - 48) Shl 4; - 'a'..'f', 'A'..'F': b := ((Byte(Value[x]) And 7) + 9) shl 4; - else - begin - b := 0; - bad := True; - end; - end; - Case Value[x + 1] Of - '0'..'9': b := b Or (Byte(Value[x + 1]) - 48); - 'a'..'f', 'A'..'F': b := b Or ((Byte(Value[x + 1]) And 7) + 9); - else - bad := True; - end; - if bad then - begin - Result[l] := c; - Inc(l); - end - else - begin - Inc(x, 2); - Result[l] := AnsiChar(b); - Inc(l); - end; - end; - end; - end - else - break; - end; - Dec(l); - SetLength(Result, l); -end; - -{==============================================================================} - -function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; -begin - Result := DecodeTriplet(Value, '='); -end; - -{==============================================================================} - -function DecodeURL(const Value: AnsiString): AnsiString; -begin - Result := DecodeTriplet(Value, '%'); -end; - -{==============================================================================} - -function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; - Specials: TSpecials): AnsiString; -var - n, l: Integer; - s: AnsiString; - c: AnsiChar; -begin - SetLength(Result, Length(Value) * 3); - l := 1; - for n := 1 to Length(Value) do - begin - c := Value[n]; - if c in Specials then - begin - Result[l] := Delimiter; - Inc(l); - s := IntToHex(Ord(c), 2); - Result[l] := s[1]; - Inc(l); - Result[l] := s[2]; - Inc(l); - end - else - begin - Result[l] := c; - Inc(l); - end; - end; - Dec(l); - SetLength(Result, l); -end; - -{==============================================================================} - -function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '=', ['='] + NonAsciiChar); -end; - -{==============================================================================} - -function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '=', SpecialChar + NonAsciiChar); -end; - -{==============================================================================} - -function EncodeURLElement(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '%', URLSpecialChar + URLFullSpecialChar); -end; - -{==============================================================================} - -function EncodeURL(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '%', URLSpecialChar); -end; - -{==============================================================================} - -function Decode4to3(const Value, Table: AnsiString): AnsiString; -var - x, y, n, l: Integer; - d: array[0..3] of Byte; -begin - SetLength(Result, Length(Value)); - x := 1; - l := 1; - while x <= Length(Value) do - begin - for n := 0 to 3 do - begin - if x > Length(Value) then - d[n] := 64 - else - begin - y := Pos(Value[x], Table); - if y < 1 then - y := 1; - d[n] := y - 1; - end; - Inc(x); - end; - Result[l] := AnsiChar((D[0] and $3F) shl 2 + (D[1] and $30) shr 4); - Inc(l); - if d[2] <> 64 then - begin - Result[l] := AnsiChar((D[1] and $0F) shl 4 + (D[2] and $3C) shr 2); - Inc(l); - if d[3] <> 64 then - begin - Result[l] := AnsiChar((D[2] and $03) shl 6 + (D[3] and $3F)); - Inc(l); - end; - end; - end; - Dec(l); - SetLength(Result, l); -end; - -{==============================================================================} -function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; -var - x, y, lv: Integer; - d: integer; - dl: integer; - c: byte; - p: integer; -begin - lv := Length(Value); - SetLength(Result, lv); - x := 1; - dl := 4; - d := 0; - p := 1; - while x <= lv do - begin - y := Ord(Value[x]); - if y in [33..127] then - c := Ord(Table[y - 32]) - else - c := 64; - Inc(x); - if c > 63 then - continue; - d := (d shl 6) or c; - dec(dl); - if dl <> 0 then - continue; - Result[p] := AnsiChar((d shr 16) and $ff); - inc(p); - Result[p] := AnsiChar((d shr 8) and $ff); - inc(p); - Result[p] := AnsiChar(d and $ff); - inc(p); - d := 0; - dl := 4; - end; - case dl of - 1: - begin - d := d shr 2; - Result[p] := AnsiChar((d shr 8) and $ff); - inc(p); - Result[p] := AnsiChar(d and $ff); - inc(p); - end; - 2: - begin - d := d shr 4; - Result[p] := AnsiChar(d and $ff); - inc(p); - end; - end; - SetLength(Result, p - 1); -end; - -{==============================================================================} - -function Encode3to4(const Value, Table: AnsiString): AnsiString; -var - c: Byte; - n, l: Integer; - Count: Integer; - DOut: array[0..3] of Byte; -begin - setlength(Result, ((Length(Value) + 2) div 3) * 4); - l := 1; - Count := 1; - while Count <= Length(Value) do - begin - c := Ord(Value[Count]); - Inc(Count); - DOut[0] := (c and $FC) shr 2; - DOut[1] := (c and $03) shl 4; - if Count <= Length(Value) then - begin - c := Ord(Value[Count]); - Inc(Count); - DOut[1] := DOut[1] + (c and $F0) shr 4; - DOut[2] := (c and $0F) shl 2; - if Count <= Length(Value) then - begin - c := Ord(Value[Count]); - Inc(Count); - DOut[2] := DOut[2] + (c and $C0) shr 6; - DOut[3] := (c and $3F); - end - else - begin - DOut[3] := $40; - end; - end - else - begin - DOut[2] := $40; - DOut[3] := $40; - end; - for n := 0 to 3 do - begin - if (DOut[n] + 1) <= Length(Table) then - begin - Result[l] := Table[DOut[n] + 1]; - Inc(l); - end; - end; - end; - SetLength(Result, l - 1); -end; - -{==============================================================================} - -function DecodeBase64(const Value: AnsiString): AnsiString; -begin - Result := Decode4to3Ex(Value, ReTableBase64); -end; - -{==============================================================================} - -function EncodeBase64(const Value: AnsiString): AnsiString; -begin - Result := Encode3to4(Value, TableBase64); -end; - -{==============================================================================} - -function DecodeBase64mod(const Value: AnsiString): AnsiString; -begin - Result := Decode4to3(Value, TableBase64mod); -end; - -{==============================================================================} - -function EncodeBase64mod(const Value: AnsiString): AnsiString; -begin - Result := Encode3to4(Value, TableBase64mod); -end; - -{==============================================================================} - -function DecodeUU(const Value: AnsiString): AnsiString; -var - s: AnsiString; - uut: AnsiString; - x: Integer; -begin - Result := ''; - uut := TableUU; - s := trim(UpperCase(Value)); - if s = '' then Exit; - if Pos('BEGIN', s) = 1 then - Exit; - if Pos('END', s) = 1 then - Exit; - if Pos('TABLE', s) = 1 then - Exit; //ignore Table yet (set custom UUT) - //begin decoding - x := Pos(Value[1], uut) - 1; - case (x mod 3) of - 0: x :=(x div 3)* 4; - 1: x :=((x div 3) * 4) + 2; - 2: x :=((x div 3) * 4) + 3; - end; - //x - lenght UU line - s := Copy(Value, 2, x); - if s = '' then - Exit; - s := s + StringOfChar(' ', x - length(s)); - Result := Decode4to3(s, uut); -end; - -{==============================================================================} - -function EncodeUU(const Value: AnsiString): AnsiString; -begin - Result := ''; - if Length(Value) < Length(TableUU) then - Result := TableUU[Length(Value) + 1] + Encode3to4(Value, TableUU); -end; - -{==============================================================================} - -function DecodeXX(const Value: AnsiString): AnsiString; -var - s: AnsiString; - x: Integer; -begin - Result := ''; - s := trim(UpperCase(Value)); - if s = '' then - Exit; - if Pos('BEGIN', s) = 1 then - Exit; - if Pos('END', s) = 1 then - Exit; - //begin decoding - x := Pos(Value[1], TableXX) - 1; - case (x mod 3) of - 0: x :=(x div 3)* 4; - 1: x :=((x div 3) * 4) + 2; - 2: x :=((x div 3) * 4) + 3; - end; - //x - lenght XX line - s := Copy(Value, 2, x); - if s = '' then - Exit; - s := s + StringOfChar(' ', x - length(s)); - Result := Decode4to3(s, TableXX); -end; - -{==============================================================================} - -function DecodeYEnc(const Value: AnsiString): AnsiString; -var - C : Byte; - i: integer; -begin - Result := ''; - i := 1; - while i <= Length(Value) do - begin - c := Ord(Value[i]); - Inc(i); - if c = Ord('=') then - begin - c := Ord(Value[i]); - Inc(i); - Dec(c, 64); - end; - Dec(C, 42); - Result := Result + AnsiChar(C); - end; -end; - -{==============================================================================} - -function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; -begin - Result := (Crc32 shr 8) - xor crc32tab[Byte(Value xor (Crc32 and Integer($000000FF)))]; -end; - -{==============================================================================} - -function Crc32(const Value: AnsiString): Integer; -var - n: Integer; -begin - Result := Integer($FFFFFFFF); - for n := 1 to Length(Value) do - Result := UpdateCrc32(Ord(Value[n]), Result); - Result := not Result; -end; - -{==============================================================================} - -function UpdateCrc16(Value: Byte; Crc16: Word): Word; -begin - Result := ((Crc16 shr 8) and $00FF) xor - crc16tab[Byte(Crc16 xor (Word(Value)) and $00FF)]; -end; - -{==============================================================================} - -function Crc16(const Value: AnsiString): Word; -var - n: Integer; -begin - Result := $FFFF; - for n := 1 to Length(Value) do - Result := UpdateCrc16(Ord(Value[n]), Result); -end; - -{==============================================================================} - -procedure MDInit(var MDContext: TMDCtx); -var - n: integer; -begin - MDContext.Count[0] := 0; - MDContext.Count[1] := 0; - for n := 0 to high(MDContext.BufAnsiChar) do - MDContext.BufAnsiChar[n] := 0; - for n := 0 to high(MDContext.BufLong) do - MDContext.BufLong[n] := 0; - MDContext.State[0] := Integer($67452301); - MDContext.State[1] := Integer($EFCDAB89); - MDContext.State[2] := Integer($98BADCFE); - MDContext.State[3] := Integer($10325476); -end; - -procedure MD5Transform(var Buf: array of LongInt; const Data: array of LongInt); -var - A, B, C, D: LongInt; - - procedure Round1(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (Z xor (X and (Y xor Z))) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; - - procedure Round2(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (Y xor (Z and (X xor Y))) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; - - procedure Round3(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (X xor Y xor Z) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; - - procedure Round4(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (Y xor (X or not Z)) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; -begin - A := Buf[0]; - B := Buf[1]; - C := Buf[2]; - D := Buf[3]; - - Round1(A, B, C, D, Data[0] + Longint($D76AA478), 7); - Round1(D, A, B, C, Data[1] + Longint($E8C7B756), 12); - Round1(C, D, A, B, Data[2] + Longint($242070DB), 17); - Round1(B, C, D, A, Data[3] + Longint($C1BDCEEE), 22); - Round1(A, B, C, D, Data[4] + Longint($F57C0FAF), 7); - Round1(D, A, B, C, Data[5] + Longint($4787C62A), 12); - Round1(C, D, A, B, Data[6] + Longint($A8304613), 17); - Round1(B, C, D, A, Data[7] + Longint($FD469501), 22); - Round1(A, B, C, D, Data[8] + Longint($698098D8), 7); - Round1(D, A, B, C, Data[9] + Longint($8B44F7AF), 12); - Round1(C, D, A, B, Data[10] + Longint($FFFF5BB1), 17); - Round1(B, C, D, A, Data[11] + Longint($895CD7BE), 22); - Round1(A, B, C, D, Data[12] + Longint($6B901122), 7); - Round1(D, A, B, C, Data[13] + Longint($FD987193), 12); - Round1(C, D, A, B, Data[14] + Longint($A679438E), 17); - Round1(B, C, D, A, Data[15] + Longint($49B40821), 22); - - Round2(A, B, C, D, Data[1] + Longint($F61E2562), 5); - Round2(D, A, B, C, Data[6] + Longint($C040B340), 9); - Round2(C, D, A, B, Data[11] + Longint($265E5A51), 14); - Round2(B, C, D, A, Data[0] + Longint($E9B6C7AA), 20); - Round2(A, B, C, D, Data[5] + Longint($D62F105D), 5); - Round2(D, A, B, C, Data[10] + Longint($02441453), 9); - Round2(C, D, A, B, Data[15] + Longint($D8A1E681), 14); - Round2(B, C, D, A, Data[4] + Longint($E7D3FBC8), 20); - Round2(A, B, C, D, Data[9] + Longint($21E1CDE6), 5); - Round2(D, A, B, C, Data[14] + Longint($C33707D6), 9); - Round2(C, D, A, B, Data[3] + Longint($F4D50D87), 14); - Round2(B, C, D, A, Data[8] + Longint($455A14ED), 20); - Round2(A, B, C, D, Data[13] + Longint($A9E3E905), 5); - Round2(D, A, B, C, Data[2] + Longint($FCEFA3F8), 9); - Round2(C, D, A, B, Data[7] + Longint($676F02D9), 14); - Round2(B, C, D, A, Data[12] + Longint($8D2A4C8A), 20); - - Round3(A, B, C, D, Data[5] + Longint($FFFA3942), 4); - Round3(D, A, B, C, Data[8] + Longint($8771F681), 11); - Round3(C, D, A, B, Data[11] + Longint($6D9D6122), 16); - Round3(B, C, D, A, Data[14] + Longint($FDE5380C), 23); - Round3(A, B, C, D, Data[1] + Longint($A4BEEA44), 4); - Round3(D, A, B, C, Data[4] + Longint($4BDECFA9), 11); - Round3(C, D, A, B, Data[7] + Longint($F6BB4B60), 16); - Round3(B, C, D, A, Data[10] + Longint($BEBFBC70), 23); - Round3(A, B, C, D, Data[13] + Longint($289B7EC6), 4); - Round3(D, A, B, C, Data[0] + Longint($EAA127FA), 11); - Round3(C, D, A, B, Data[3] + Longint($D4EF3085), 16); - Round3(B, C, D, A, Data[6] + Longint($04881D05), 23); - Round3(A, B, C, D, Data[9] + Longint($D9D4D039), 4); - Round3(D, A, B, C, Data[12] + Longint($E6DB99E5), 11); - Round3(C, D, A, B, Data[15] + Longint($1FA27CF8), 16); - Round3(B, C, D, A, Data[2] + Longint($C4AC5665), 23); - - Round4(A, B, C, D, Data[0] + Longint($F4292244), 6); - Round4(D, A, B, C, Data[7] + Longint($432AFF97), 10); - Round4(C, D, A, B, Data[14] + Longint($AB9423A7), 15); - Round4(B, C, D, A, Data[5] + Longint($FC93A039), 21); - Round4(A, B, C, D, Data[12] + Longint($655B59C3), 6); - Round4(D, A, B, C, Data[3] + Longint($8F0CCC92), 10); - Round4(C, D, A, B, Data[10] + Longint($FFEFF47D), 15); - Round4(B, C, D, A, Data[1] + Longint($85845DD1), 21); - Round4(A, B, C, D, Data[8] + Longint($6FA87E4F), 6); - Round4(D, A, B, C, Data[15] + Longint($FE2CE6E0), 10); - Round4(C, D, A, B, Data[6] + Longint($A3014314), 15); - Round4(B, C, D, A, Data[13] + Longint($4E0811A1), 21); - Round4(A, B, C, D, Data[4] + Longint($F7537E82), 6); - Round4(D, A, B, C, Data[11] + Longint($BD3AF235), 10); - Round4(C, D, A, B, Data[2] + Longint($2AD7D2BB), 15); - Round4(B, C, D, A, Data[9] + Longint($EB86D391), 21); - - Inc(Buf[0], A); - Inc(Buf[1], B); - Inc(Buf[2], C); - Inc(Buf[3], D); -end; - -//fixed by James McAdams -procedure MDUpdate(var MDContext: TMDCtx; const Data: AnsiString; transform: TMDTransform); -var - Index, partLen, InputLen, I: integer; -{$IFDEF SYNACODE_NATIVE} - n: integer; -{$ENDIF} -begin - InputLen := Length(Data); - with MDContext do - begin - Index := (Count[0] shr 3) and $3F; - Inc(Count[0], InputLen shl 3); - if Count[0] < (InputLen shl 3) then - Inc(Count[1]); - Inc(Count[1], InputLen shr 29); - partLen := 64 - Index; - if InputLen >= partLen then - begin - ArrLongToByte(BufLong, BufAnsiChar); - {$IFDEF SYNACODE_NATIVE} - for n := 1 to partLen do - BufAnsiChar[index - 1 + n] := Ord(Data[n]); - {$ELSE} - Move(Data[1], BufAnsiChar[Index], partLen); - {$ENDIF} - ArrByteToLong(BufAnsiChar, BufLong); - Transform(State, Buflong); - I := partLen; - while I + 63 < InputLen do - begin - ArrLongToByte(BufLong, BufAnsiChar); - {$IFDEF SYNACODE_NATIVE} - for n := 1 to 64 do - BufAnsiChar[n - 1] := Ord(Data[i + n]); - {$ELSE} - Move(Data[I+1], BufAnsiChar, 64); - {$ENDIF} - ArrByteToLong(BufAnsiChar, BufLong); - Transform(State, Buflong); - inc(I, 64); - end; - Index := 0; - end - else - I := 0; - ArrLongToByte(BufLong, BufAnsiChar); - {$IFDEF SYNACODE_NATIVE} - for n := 1 to InputLen-I do - BufAnsiChar[Index + n - 1] := Ord(Data[i + n]); - {$ELSE} - Move(Data[I+1], BufAnsiChar[Index], InputLen-I); - {$ENDIF} - ArrByteToLong(BufAnsiChar, BufLong); - end -end; - -function MDFinal(var MDContext: TMDCtx; transform: TMDTransform): AnsiString; -var - Cnt: Word; - P: Byte; - digest: array[0..15] of Byte; - i: Integer; - n: integer; -begin - for I := 0 to 15 do - Digest[I] := I + 1; - with MDContext do - begin - Cnt := (Count[0] shr 3) and $3F; - P := Cnt; - BufAnsiChar[P] := $80; - Inc(P); - Cnt := 64 - 1 - Cnt; - if Cnt < 8 then - begin - for n := 0 to cnt - 1 do - BufAnsiChar[P + n] := 0; - ArrByteToLong(BufAnsiChar, BufLong); -// FillChar(BufAnsiChar[P], Cnt, #0); - Transform(State, BufLong); - ArrLongToByte(BufLong, BufAnsiChar); - for n := 0 to 55 do - BufAnsiChar[n] := 0; - ArrByteToLong(BufAnsiChar, BufLong); -// FillChar(BufAnsiChar, 56, #0); - end - else - begin - for n := 0 to Cnt - 8 - 1 do - BufAnsiChar[p + n] := 0; - ArrByteToLong(BufAnsiChar, BufLong); -// FillChar(BufAnsiChar[P], Cnt - 8, #0); - end; - BufLong[14] := Count[0]; - BufLong[15] := Count[1]; - Transform(State, BufLong); - ArrLongToByte(State, Digest); -// Move(State, Digest, 16); - Result := ''; - for i := 0 to 15 do - Result := Result + AnsiChar(digest[i]); - end; -// FillChar(MD5Context, SizeOf(TMD5Ctx), #0) -end; - -{==============================================================================} - -function MD5(const Value: AnsiString): AnsiString; -var - MDContext: TMDCtx; -begin - MDInit(MDContext); - MDUpdate(MDContext, Value, @MD5Transform); - Result := MDFinal(MDContext, @MD5Transform); -end; - -{==============================================================================} - -function HMAC_MD5(Text, Key: AnsiString): AnsiString; -var - ipad, opad, s: AnsiString; - n: Integer; - MDContext: TMDCtx; -begin - if Length(Key) > 64 then - Key := md5(Key); - ipad := StringOfChar(#$36, 64); - opad := StringOfChar(#$5C, 64); - for n := 1 to Length(Key) do - begin - ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); - opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); - end; - MDInit(MDContext); - MDUpdate(MDContext, ipad, @MD5Transform); - MDUpdate(MDContext, Text, @MD5Transform); - s := MDFinal(MDContext, @MD5Transform); - MDInit(MDContext); - MDUpdate(MDContext, opad, @MD5Transform); - MDUpdate(MDContext, s, @MD5Transform); - Result := MDFinal(MDContext, @MD5Transform); -end; - -{==============================================================================} - -function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; -var - cnt, rest: integer; - l: integer; - n: integer; - MDContext: TMDCtx; -begin - l := length(Value); - cnt := Len div l; - rest := Len mod l; - MDInit(MDContext); - for n := 1 to cnt do - MDUpdate(MDContext, Value, @MD5Transform); - if rest > 0 then - MDUpdate(MDContext, Copy(Value, 1, rest), @MD5Transform); - Result := MDFinal(MDContext, @MD5Transform); -end; - -{==============================================================================} -// SHA1 is based on sources by Dave Barton (davebarton@bigfoot.com) - -procedure SHA1init( var SHA1Context: TSHA1Ctx ); -var - n: integer; -begin - SHA1Context.Hi := 0; - SHA1Context.Lo := 0; - SHA1Context.Index := 0; - for n := 0 to High(SHA1Context.Buffer) do - SHA1Context.Buffer[n] := 0; - for n := 0 to High(SHA1Context.HashByte) do - SHA1Context.HashByte[n] := 0; -// FillChar(SHA1Context, SizeOf(TSHA1Ctx), #0); - SHA1Context.Hash[0] := integer($67452301); - SHA1Context.Hash[1] := integer($EFCDAB89); - SHA1Context.Hash[2] := integer($98BADCFE); - SHA1Context.Hash[3] := integer($10325476); - SHA1Context.Hash[4] := integer($C3D2E1F0); -end; - -//****************************************************************************** -function RB(A: integer): integer; -begin - Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); -end; - -procedure SHA1Compress(var Data: TSHA1Ctx); -var - A, B, C, D, E, T: integer; - W: array[0..79] of integer; - i: integer; - n: integer; - - function F1(x, y, z: integer): integer; - begin - Result := z xor (x and (y xor z)); - end; - function F2(x, y, z: integer): integer; - begin - Result := x xor y xor z; - end; - function F3(x, y, z: integer): integer; - begin - Result := (x and y) or (z and (x or y)); - end; - function LRot32(X: integer; c: integer): integer; - begin - result := (x shl c) or (x shr (32 - c)); - end; -begin - ArrByteToLong(Data.Buffer, W); -// Move(Data.Buffer, W, Sizeof(Data.Buffer)); - for i := 0 to 15 do - W[i] := RB(W[i]); - for i := 16 to 79 do - W[i] := LRot32(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16], 1); - A := Data.Hash[0]; - B := Data.Hash[1]; - C := Data.Hash[2]; - D := Data.Hash[3]; - E := Data.Hash[4]; - for i := 0 to 19 do - begin - T := LRot32(A, 5) + F1(B, C, D) + E + W[i] + integer($5A827999); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for i := 20 to 39 do - begin - T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($6ED9EBA1); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for i := 40 to 59 do - begin - T := LRot32(A, 5) + F3(B, C, D) + E + W[i] + integer($8F1BBCDC); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for i := 60 to 79 do - begin - T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($CA62C1D6); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - Data.Hash[0] := Data.Hash[0] + A; - Data.Hash[1] := Data.Hash[1] + B; - Data.Hash[2] := Data.Hash[2] + C; - Data.Hash[3] := Data.Hash[3] + D; - Data.Hash[4] := Data.Hash[4] + E; - for n := 0 to high(w) do - w[n] := 0; -// FillChar(W, Sizeof(W), 0); - for n := 0 to high(Data.Buffer) do - Data.Buffer[n] := 0; -// FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); -end; - -//****************************************************************************** -procedure SHA1Update(var Context: TSHA1Ctx; const Data: AnsiString); -var - Len: integer; - n: integer; - i, k: integer; -begin - Len := Length(data); - for k := 0 to 7 do - begin - i := Context.Lo; - Inc(Context.Lo, Len); - if Context.Lo < i then - Inc(Context.Hi); - end; - for n := 1 to len do - begin - Context.Buffer[Context.Index] := byte(Data[n]); - Inc(Context.Index); - if Context.Index = 64 then - begin - Context.Index := 0; - SHA1Compress(Context); - end; - end; -end; - -//****************************************************************************** -function SHA1Final(var Context: TSHA1Ctx): AnsiString; -type - Pinteger = ^integer; -var - i: integer; - procedure ItoArr(var Ar: Array of byte; I, value: Integer); - begin - Ar[i + 0] := Value and $000000FF; - Ar[i + 1] := (Value shr 8) and $000000FF; - Ar[i + 2] := (Value shr 16) and $000000FF; - Ar[i + 3] := (Value shr 24) and $000000FF; - end; -begin - Context.Buffer[Context.Index] := $80; - if Context.Index >= 56 then - SHA1Compress(Context); - ItoArr(Context.Buffer, 56, RB(Context.Hi)); - ItoArr(Context.Buffer, 60, RB(Context.Lo)); -// Pinteger(@Context.Buffer[56])^ := RB(Context.Hi); -// Pinteger(@Context.Buffer[60])^ := RB(Context.Lo); - SHA1Compress(Context); - Context.Hash[0] := RB(Context.Hash[0]); - Context.Hash[1] := RB(Context.Hash[1]); - Context.Hash[2] := RB(Context.Hash[2]); - Context.Hash[3] := RB(Context.Hash[3]); - Context.Hash[4] := RB(Context.Hash[4]); - ArrLongToByte(Context.Hash, Context.HashByte); - Result := ''; - for i := 0 to 19 do - Result := Result + AnsiChar(Context.HashByte[i]); -end; - -function SHA1(const Value: AnsiString): AnsiString; -var - SHA1Context: TSHA1Ctx; -begin - SHA1Init(SHA1Context); - SHA1Update(SHA1Context, Value); - Result := SHA1Final(SHA1Context); -end; - -{==============================================================================} - -function HMAC_SHA1(Text, Key: AnsiString): AnsiString; -var - ipad, opad, s: AnsiString; - n: Integer; - SHA1Context: TSHA1Ctx; -begin - if Length(Key) > 64 then - Key := SHA1(Key); - ipad := StringOfChar(#$36, 64); - opad := StringOfChar(#$5C, 64); - for n := 1 to Length(Key) do - begin - ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); - opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); - end; - SHA1Init(SHA1Context); - SHA1Update(SHA1Context, ipad); - SHA1Update(SHA1Context, Text); - s := SHA1Final(SHA1Context); - SHA1Init(SHA1Context); - SHA1Update(SHA1Context, opad); - SHA1Update(SHA1Context, s); - Result := SHA1Final(SHA1Context); -end; - -{==============================================================================} - -function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; -var - cnt, rest: integer; - l: integer; - n: integer; - SHA1Context: TSHA1Ctx; -begin - l := length(Value); - cnt := Len div l; - rest := Len mod l; - SHA1Init(SHA1Context); - for n := 1 to cnt do - SHA1Update(SHA1Context, Value); - if rest > 0 then - SHA1Update(SHA1Context, Copy(Value, 1, rest)); - Result := SHA1Final(SHA1Context); -end; - -{==============================================================================} - -procedure MD4Transform(var Buf: array of LongInt; const Data: array of LongInt); -var - A, B, C, D: LongInt; - function LRot32(a, b: longint): longint; - begin - Result:= (a shl b) or (a shr (32 - b)); - end; -begin - A := Buf[0]; - B := Buf[1]; - C := Buf[2]; - D := Buf[3]; - - A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 0], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 1], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 2], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 3], 19); - A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 4], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 5], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 6], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 7], 19); - A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 8], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 9], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[10], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[11], 19); - A:= LRot32(A + (D xor (B and (C xor D))) + Data[12], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[13], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[14], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[15], 19); - - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 0] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 4] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 8] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[12] + longint($5a827999), 13); - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 1] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 5] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 9] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[13] + longint($5a827999), 13); - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 2] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 6] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[10] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[14] + longint($5a827999), 13); - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 3] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 7] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[11] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[15] + longint($5a827999), 13); - - A:= LRot32(A + (B xor C xor D) + Data[ 0] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[ 8] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 4] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[12] + longint($6ed9eba1), 15); - A:= LRot32(A + (B xor C xor D) + Data[ 2] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[10] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 6] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[14] + longint($6ed9eba1), 15); - A:= LRot32(A + (B xor C xor D) + Data[ 1] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[ 9] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 5] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[13] + longint($6ed9eba1), 15); - A:= LRot32(A + (B xor C xor D) + Data[ 3] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[11] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 7] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[15] + longint($6ed9eba1), 15); - - Inc(Buf[0], A); - Inc(Buf[1], B); - Inc(Buf[2], C); - Inc(Buf[3], D); -end; - -{==============================================================================} - -function MD4(const Value: AnsiString): AnsiString; -var - MDContext: TMDCtx; -begin - MDInit(MDContext); - MDUpdate(MDContext, Value, @MD4Transform); - Result := MDFinal(MDContext, @MD4Transform); -end; - -{==============================================================================} - - -end. +{==============================================================================| +| Project : Ararat Synapse | 002.002.003 | +|==============================================================================| +| Content: Coding and decoding support | +|==============================================================================| +| Copyright (c)1999-2013, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2000-2013. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(Various encoding and decoding support)} +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$R-} +{$H+} +{$TYPEDADDRESS OFF} + +{$IFDEF CIL} + {$DEFINE SYNACODE_NATIVE} +{$ENDIF} +{$IFDEF FPC_BIG_ENDIAN} + {$DEFINE SYNACODE_NATIVE} +{$ENDIF} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} + {$WARN SUSPICIOUS_TYPECAST OFF} +{$ENDIF} + +unit synacode; + +interface + +uses + SysUtils; + +type + TSpecials = set of AnsiChar; + +const + + SpecialChar: TSpecials = + ['=', '(', ')', '[', ']', '<', '>', ':', ';', ',', '@', '/', '?', '\', + '"', '_']; + NonAsciiChar: TSpecials = + [#0..#31, #127..#255]; + URLFullSpecialChar: TSpecials = + [';', '/', '?', ':', '@', '=', '&', '#', '+']; + URLSpecialChar: TSpecials = + [#$00..#$20, '<', '>', '"', '%', '{', '}', '|', '\', '^', '[', ']', '`', #$7F..#$FF]; + TableBase64 = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + TableBase64mod = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,='; + TableUU = + '`!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'; + TableXX = + '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; + ReTablebase64 = + #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$3E +#$40 + +#$40 +#$40 +#$3F +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C + +#$3D +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$01 +#$02 +#$03 + +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C +#$0D +#$0E +#$0F + +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$40 +#$40 + +#$40 +#$40 +#$40 +#$40 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 + +#$22 +#$23 +#$24 +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D + +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; + ReTableUU = + #$01 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C + +#$0D +#$0E +#$0F +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 + +#$19 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 + +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D +#$2E +#$2F +#$30 + +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C + +#$3D +#$3E +#$3F +#$00 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 + +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 + +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; + ReTableXX = + #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$40 + +#$01 +#$40 +#$40 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A + +#$0B +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$0C +#$0D +#$0E +#$0F + +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$1A +#$1B + +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 +#$25 +#$40 +#$40 + +#$40 +#$40 +#$40 +#$40 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D + +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 + +#$3A +#$3B +#$3C +#$3D +#$3E +#$3F +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; + +{:Decodes triplet encoding with a given character delimiter. It is used for + decoding quoted-printable or URL encoding.} +function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; + +{:Decodes a string from quoted printable form. (also decodes triplet sequences + like '=7F')} +function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; + +{:Decodes a string of URL encoding. (also decodes triplet sequences like '%7F')} +function DecodeURL(const Value: AnsiString): AnsiString; + +{:Performs triplet encoding with a given character delimiter. Used for encoding + quoted-printable or URL encoding.} +function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; + Specials: TSpecials): AnsiString; + +{:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) + are encoded.} +function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; + +{:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) and + @link(SpecialChar) are encoded.} +function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; + +{:Encodes a string to URL format. Used for encoding data from a form field in + HTTP, etc. (Encodes all critical characters including characters used as URL + delimiters ('/',':', etc.)} +function EncodeURLElement(const Value: AnsiString): AnsiString; + +{:Encodes a string to URL format. Used to encode critical characters in all + URLs.} +function EncodeURL(const Value: AnsiString): AnsiString; + +{:Decode 4to3 encoding with given table. If some element is not found in table, + first item from table is used. This is good for buggy coded items by Microsoft + Outlook. This software sometimes using wrong table for UUcode, where is used + ' ' instead '`'.} +function Decode4to3(const Value, Table: AnsiString): AnsiString; + +{:Decode 4to3 encoding with given REVERSE table. Using this function with +reverse table is much faster then @link(Decode4to3). This function is used +internally for Base64, UU or XX decoding.} +function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; + +{:Encode by system 3to4 (used by Base64, UU coding, etc) by given table.} +function Encode3to4(const Value, Table: AnsiString): AnsiString; + +{:Decode string from base64 format.} +function DecodeBase64(const Value: AnsiString): AnsiString; + +{:Encodes a string to base64 format.} +function EncodeBase64(const Value: AnsiString): AnsiString; + +{:Decode string from modified base64 format. (used in IMAP, for example.)} +function DecodeBase64mod(const Value: AnsiString): AnsiString; + +{:Encodes a string to modified base64 format. (used in IMAP, for example.)} +function EncodeBase64mod(const Value: AnsiString): AnsiString; + +{:Decodes a string from UUcode format.} +function DecodeUU(const Value: AnsiString): AnsiString; + +{:encode UUcode. it encode only datas, you must also add header and footer for + proper encode.} +function EncodeUU(const Value: AnsiString): AnsiString; + +{:Decodes a string from XXcode format.} +function DecodeXX(const Value: AnsiString): AnsiString; + +{:decode line with Yenc code. This code is sometimes used in newsgroups.} +function DecodeYEnc(const Value: AnsiString): AnsiString; + +{:Returns a new CRC32 value after adding a new byte of data.} +function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; + +{:return CRC32 from a value string.} +function Crc32(const Value: AnsiString): Integer; + +{:Returns a new CRC16 value after adding a new byte of data.} +function UpdateCrc16(Value: Byte; Crc16: Word): Word; + +{:return CRC16 from a value string.} +function Crc16(const Value: AnsiString): Word; + +{:Returns a binary string with a RSA-MD5 hashing of "Value" string.} +function MD5(const Value: AnsiString): AnsiString; + +{:Returns a binary string with HMAC-MD5 hash.} +function HMAC_MD5(Text, Key: AnsiString): AnsiString; + +{:Returns a binary string with a RSA-MD5 hashing of string what is constructed + by repeating "value" until length is "Len".} +function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; + +{:Returns a binary string with a SHA-1 hashing of "Value" string.} +function SHA1(const Value: AnsiString): AnsiString; + +{:Returns a binary string with HMAC-SHA1 hash.} +function HMAC_SHA1(Text, Key: AnsiString): AnsiString; + +{:Returns a binary string with a SHA-1 hashing of string what is constructed + by repeating "value" until length is "Len".} +function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; + +{:Returns a binary string with a RSA-MD4 hashing of "Value" string.} +function MD4(const Value: AnsiString): AnsiString; + +implementation + +const + + Crc32Tab: array[0..255] of Integer = ( + Integer($00000000), Integer($77073096), Integer($EE0E612C), Integer($990951BA), + Integer($076DC419), Integer($706AF48F), Integer($E963A535), Integer($9E6495A3), + Integer($0EDB8832), Integer($79DCB8A4), Integer($E0D5E91E), Integer($97D2D988), + Integer($09B64C2B), Integer($7EB17CBD), Integer($E7B82D07), Integer($90BF1D91), + Integer($1DB71064), Integer($6AB020F2), Integer($F3B97148), Integer($84BE41DE), + Integer($1ADAD47D), Integer($6DDDE4EB), Integer($F4D4B551), Integer($83D385C7), + Integer($136C9856), Integer($646BA8C0), Integer($FD62F97A), Integer($8A65C9EC), + Integer($14015C4F), Integer($63066CD9), Integer($FA0F3D63), Integer($8D080DF5), + Integer($3B6E20C8), Integer($4C69105E), Integer($D56041E4), Integer($A2677172), + Integer($3C03E4D1), Integer($4B04D447), Integer($D20D85FD), Integer($A50AB56B), + Integer($35B5A8FA), Integer($42B2986C), Integer($DBBBC9D6), Integer($ACBCF940), + Integer($32D86CE3), Integer($45DF5C75), Integer($DCD60DCF), Integer($ABD13D59), + Integer($26D930AC), Integer($51DE003A), Integer($C8D75180), Integer($BFD06116), + Integer($21B4F4B5), Integer($56B3C423), Integer($CFBA9599), Integer($B8BDA50F), + Integer($2802B89E), Integer($5F058808), Integer($C60CD9B2), Integer($B10BE924), + Integer($2F6F7C87), Integer($58684C11), Integer($C1611DAB), Integer($B6662D3D), + Integer($76DC4190), Integer($01DB7106), Integer($98D220BC), Integer($EFD5102A), + Integer($71B18589), Integer($06B6B51F), Integer($9FBFE4A5), Integer($E8B8D433), + Integer($7807C9A2), Integer($0F00F934), Integer($9609A88E), Integer($E10E9818), + Integer($7F6A0DBB), Integer($086D3D2D), Integer($91646C97), Integer($E6635C01), + Integer($6B6B51F4), Integer($1C6C6162), Integer($856530D8), Integer($F262004E), + Integer($6C0695ED), Integer($1B01A57B), Integer($8208F4C1), Integer($F50FC457), + Integer($65B0D9C6), Integer($12B7E950), Integer($8BBEB8EA), Integer($FCB9887C), + Integer($62DD1DDF), Integer($15DA2D49), Integer($8CD37CF3), Integer($FBD44C65), + Integer($4DB26158), Integer($3AB551CE), Integer($A3BC0074), Integer($D4BB30E2), + Integer($4ADFA541), Integer($3DD895D7), Integer($A4D1C46D), Integer($D3D6F4FB), + Integer($4369E96A), Integer($346ED9FC), Integer($AD678846), Integer($DA60B8D0), + Integer($44042D73), Integer($33031DE5), Integer($AA0A4C5F), Integer($DD0D7CC9), + Integer($5005713C), Integer($270241AA), Integer($BE0B1010), Integer($C90C2086), + Integer($5768B525), Integer($206F85B3), Integer($B966D409), Integer($CE61E49F), + Integer($5EDEF90E), Integer($29D9C998), Integer($B0D09822), Integer($C7D7A8B4), + Integer($59B33D17), Integer($2EB40D81), Integer($B7BD5C3B), Integer($C0BA6CAD), + Integer($EDB88320), Integer($9ABFB3B6), Integer($03B6E20C), Integer($74B1D29A), + Integer($EAD54739), Integer($9DD277AF), Integer($04DB2615), Integer($73DC1683), + Integer($E3630B12), Integer($94643B84), Integer($0D6D6A3E), Integer($7A6A5AA8), + Integer($E40ECF0B), Integer($9309FF9D), Integer($0A00AE27), Integer($7D079EB1), + Integer($F00F9344), Integer($8708A3D2), Integer($1E01F268), Integer($6906C2FE), + Integer($F762575D), Integer($806567CB), Integer($196C3671), Integer($6E6B06E7), + Integer($FED41B76), Integer($89D32BE0), Integer($10DA7A5A), Integer($67DD4ACC), + Integer($F9B9DF6F), Integer($8EBEEFF9), Integer($17B7BE43), Integer($60B08ED5), + Integer($D6D6A3E8), Integer($A1D1937E), Integer($38D8C2C4), Integer($4FDFF252), + Integer($D1BB67F1), Integer($A6BC5767), Integer($3FB506DD), Integer($48B2364B), + Integer($D80D2BDA), Integer($AF0A1B4C), Integer($36034AF6), Integer($41047A60), + Integer($DF60EFC3), Integer($A867DF55), Integer($316E8EEF), Integer($4669BE79), + Integer($CB61B38C), Integer($BC66831A), Integer($256FD2A0), Integer($5268E236), + Integer($CC0C7795), Integer($BB0B4703), Integer($220216B9), Integer($5505262F), + Integer($C5BA3BBE), Integer($B2BD0B28), Integer($2BB45A92), Integer($5CB36A04), + Integer($C2D7FFA7), Integer($B5D0CF31), Integer($2CD99E8B), Integer($5BDEAE1D), + Integer($9B64C2B0), Integer($EC63F226), Integer($756AA39C), Integer($026D930A), + Integer($9C0906A9), Integer($EB0E363F), Integer($72076785), Integer($05005713), + Integer($95BF4A82), Integer($E2B87A14), Integer($7BB12BAE), Integer($0CB61B38), + Integer($92D28E9B), Integer($E5D5BE0D), Integer($7CDCEFB7), Integer($0BDBDF21), + Integer($86D3D2D4), Integer($F1D4E242), Integer($68DDB3F8), Integer($1FDA836E), + Integer($81BE16CD), Integer($F6B9265B), Integer($6FB077E1), Integer($18B74777), + Integer($88085AE6), Integer($FF0F6A70), Integer($66063BCA), Integer($11010B5C), + Integer($8F659EFF), Integer($F862AE69), Integer($616BFFD3), Integer($166CCF45), + Integer($A00AE278), Integer($D70DD2EE), Integer($4E048354), Integer($3903B3C2), + Integer($A7672661), Integer($D06016F7), Integer($4969474D), Integer($3E6E77DB), + Integer($AED16A4A), Integer($D9D65ADC), Integer($40DF0B66), Integer($37D83BF0), + Integer($A9BCAE53), Integer($DEBB9EC5), Integer($47B2CF7F), Integer($30B5FFE9), + Integer($BDBDF21C), Integer($CABAC28A), Integer($53B39330), Integer($24B4A3A6), + Integer($BAD03605), Integer($CDD70693), Integer($54DE5729), Integer($23D967BF), + Integer($B3667A2E), Integer($C4614AB8), Integer($5D681B02), Integer($2A6F2B94), + Integer($B40BBE37), Integer($C30C8EA1), Integer($5A05DF1B), Integer($2D02EF8D) + ); + + Crc16Tab: array[0..255] of Word = ( + $0000, $1189, $2312, $329B, $4624, $57AD, $6536, $74BF, + $8C48, $9DC1, $AF5A, $BED3, $CA6C, $DBE5, $E97E, $F8F7, + $1081, $0108, $3393, $221A, $56A5, $472C, $75B7, $643E, + $9CC9, $8D40, $BFDB, $AE52, $DAED, $CB64, $F9FF, $E876, + $2102, $308B, $0210, $1399, $6726, $76AF, $4434, $55BD, + $AD4A, $BCC3, $8E58, $9FD1, $EB6E, $FAE7, $C87C, $D9F5, + $3183, $200A, $1291, $0318, $77A7, $662E, $54B5, $453C, + $BDCB, $AC42, $9ED9, $8F50, $FBEF, $EA66, $D8FD, $C974, + $4204, $538D, $6116, $709F, $0420, $15A9, $2732, $36BB, + $CE4C, $DFC5, $ED5E, $FCD7, $8868, $99E1, $AB7A, $BAF3, + $5285, $430C, $7197, $601E, $14A1, $0528, $37B3, $263A, + $DECD, $CF44, $FDDF, $EC56, $98E9, $8960, $BBFB, $AA72, + $6306, $728F, $4014, $519D, $2522, $34AB, $0630, $17B9, + $EF4E, $FEC7, $CC5C, $DDD5, $A96A, $B8E3, $8A78, $9BF1, + $7387, $620E, $5095, $411C, $35A3, $242A, $16B1, $0738, + $FFCF, $EE46, $DCDD, $CD54, $B9EB, $A862, $9AF9, $8B70, + $8408, $9581, $A71A, $B693, $C22C, $D3A5, $E13E, $F0B7, + $0840, $19C9, $2B52, $3ADB, $4E64, $5FED, $6D76, $7CFF, + $9489, $8500, $B79B, $A612, $D2AD, $C324, $F1BF, $E036, + $18C1, $0948, $3BD3, $2A5A, $5EE5, $4F6C, $7DF7, $6C7E, + $A50A, $B483, $8618, $9791, $E32E, $F2A7, $C03C, $D1B5, + $2942, $38CB, $0A50, $1BD9, $6F66, $7EEF, $4C74, $5DFD, + $B58B, $A402, $9699, $8710, $F3AF, $E226, $D0BD, $C134, + $39C3, $284A, $1AD1, $0B58, $7FE7, $6E6E, $5CF5, $4D7C, + $C60C, $D785, $E51E, $F497, $8028, $91A1, $A33A, $B2B3, + $4A44, $5BCD, $6956, $78DF, $0C60, $1DE9, $2F72, $3EFB, + $D68D, $C704, $F59F, $E416, $90A9, $8120, $B3BB, $A232, + $5AC5, $4B4C, $79D7, $685E, $1CE1, $0D68, $3FF3, $2E7A, + $E70E, $F687, $C41C, $D595, $A12A, $B0A3, $8238, $93B1, + $6B46, $7ACF, $4854, $59DD, $2D62, $3CEB, $0E70, $1FF9, + $F78F, $E606, $D49D, $C514, $B1AB, $A022, $92B9, $8330, + $7BC7, $6A4E, $58D5, $495C, $3DE3, $2C6A, $1EF1, $0F78 + ); + +procedure ArrByteToLong(var ArByte: Array of byte; var ArLong: Array of Integer); +{$IFDEF SYNACODE_NATIVE} +var + n: integer; +{$ENDIF} +begin + if (High(ArByte) + 1) > ((High(ArLong) + 1) * 4) then + Exit; + {$IFDEF SYNACODE_NATIVE} + for n := 0 to ((high(ArByte) + 1) div 4) - 1 do + ArLong[n] := ArByte[n * 4 + 0] + + (ArByte[n * 4 + 1] shl 8) + + (ArByte[n * 4 + 2] shl 16) + + (ArByte[n * 4 + 3] shl 24); + {$ELSE} + Move(ArByte[0], ArLong[0], High(ArByte) + 1); + {$ENDIF} +end; + +procedure ArrLongToByte(var ArLong: Array of Integer; var ArByte: Array of byte); +{$IFDEF SYNACODE_NATIVE} +var + n: integer; +{$ENDIF} +begin + if (High(ArByte) + 1) < ((High(ArLong) + 1) * 4) then + Exit; + {$IFDEF SYNACODE_NATIVE} + for n := 0 to high(ArLong) do + begin + ArByte[n * 4 + 0] := ArLong[n] and $000000FF; + ArByte[n * 4 + 1] := (ArLong[n] shr 8) and $000000FF; + ArByte[n * 4 + 2] := (ArLong[n] shr 16) and $000000FF; + ArByte[n * 4 + 3] := (ArLong[n] shr 24) and $000000FF; + end; + {$ELSE} + Move(ArLong[0], ArByte[0], High(ArByte) + 1); + {$ENDIF} +end; + +type + TMDCtx = record + State: array[0..3] of Integer; + Count: array[0..1] of Integer; + BufAnsiChar: array[0..63] of Byte; + BufLong: array[0..15] of Integer; + end; + TSHA1Ctx= record + Hi, Lo: integer; + Buffer: array[0..63] of byte; + Index: integer; + Hash: array[0..4] of Integer; + HashByte: array[0..19] of byte; + end; + + TMDTransform = procedure(var Buf: array of LongInt; const Data: array of LongInt); + +{==============================================================================} + +function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; +var + x, l, lv: Integer; + c: AnsiChar; + b: Byte; + bad: Boolean; +begin + lv := Length(Value); + SetLength(Result, lv); + x := 1; + l := 1; + while x <= lv do + begin + c := Value[x]; + Inc(x); + if c <> Delimiter then + begin + Result[l] := c; + Inc(l); + end + else + if x < lv then + begin + Case Value[x] Of + #13: + if (Value[x + 1] = #10) then + Inc(x, 2) + else + Inc(x); + #10: + if (Value[x + 1] = #13) then + Inc(x, 2) + else + Inc(x); + else + begin + bad := False; + Case Value[x] Of + '0'..'9': b := (Byte(Value[x]) - 48) Shl 4; + 'a'..'f', 'A'..'F': b := ((Byte(Value[x]) And 7) + 9) shl 4; + else + begin + b := 0; + bad := True; + end; + end; + Case Value[x + 1] Of + '0'..'9': b := b Or (Byte(Value[x + 1]) - 48); + 'a'..'f', 'A'..'F': b := b Or ((Byte(Value[x + 1]) And 7) + 9); + else + bad := True; + end; + if bad then + begin + Result[l] := c; + Inc(l); + end + else + begin + Inc(x, 2); + Result[l] := AnsiChar(b); + Inc(l); + end; + end; + end; + end + else + break; + end; + Dec(l); + SetLength(Result, l); +end; + +{==============================================================================} + +function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; +begin + Result := DecodeTriplet(Value, '='); +end; + +{==============================================================================} + +function DecodeURL(const Value: AnsiString): AnsiString; +begin + Result := DecodeTriplet(Value, '%'); +end; + +{==============================================================================} + +function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; + Specials: TSpecials): AnsiString; +var + n, l: Integer; + s: AnsiString; + c: AnsiChar; +begin + SetLength(Result, Length(Value) * 3); + l := 1; + for n := 1 to Length(Value) do + begin + c := Value[n]; + if c in Specials then + begin + Result[l] := Delimiter; + Inc(l); + s := IntToHex(Ord(c), 2); + Result[l] := s[1]; + Inc(l); + Result[l] := s[2]; + Inc(l); + end + else + begin + Result[l] := c; + Inc(l); + end; + end; + Dec(l); + SetLength(Result, l); +end; + +{==============================================================================} + +function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; +begin + Result := EncodeTriplet(Value, '=', ['='] + NonAsciiChar); +end; + +{==============================================================================} + +function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; +begin + Result := EncodeTriplet(Value, '=', SpecialChar + NonAsciiChar); +end; + +{==============================================================================} + +function EncodeURLElement(const Value: AnsiString): AnsiString; +begin + Result := EncodeTriplet(Value, '%', URLSpecialChar + URLFullSpecialChar); +end; + +{==============================================================================} + +function EncodeURL(const Value: AnsiString): AnsiString; +begin + Result := EncodeTriplet(Value, '%', URLSpecialChar); +end; + +{==============================================================================} + +function Decode4to3(const Value, Table: AnsiString): AnsiString; +var + x, y, n, l: Integer; + d: array[0..3] of Byte; +begin + SetLength(Result, Length(Value)); + x := 1; + l := 1; + while x <= Length(Value) do + begin + for n := 0 to 3 do + begin + if x > Length(Value) then + d[n] := 64 + else + begin + y := Pos(Value[x], Table); + if y < 1 then + y := 1; + d[n] := y - 1; + end; + Inc(x); + end; + Result[l] := AnsiChar((D[0] and $3F) shl 2 + (D[1] and $30) shr 4); + Inc(l); + if d[2] <> 64 then + begin + Result[l] := AnsiChar((D[1] and $0F) shl 4 + (D[2] and $3C) shr 2); + Inc(l); + if d[3] <> 64 then + begin + Result[l] := AnsiChar((D[2] and $03) shl 6 + (D[3] and $3F)); + Inc(l); + end; + end; + end; + Dec(l); + SetLength(Result, l); +end; + +{==============================================================================} +function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; +var + x, y, lv: Integer; + d: integer; + dl: integer; + c: byte; + p: integer; +begin + lv := Length(Value); + SetLength(Result, lv); + x := 1; + dl := 4; + d := 0; + p := 1; + while x <= lv do + begin + y := Ord(Value[x]); + if y in [33..127] then + c := Ord(Table[y - 32]) + else + c := 64; + Inc(x); + if c > 63 then + continue; + d := (d shl 6) or c; + dec(dl); + if dl <> 0 then + continue; + Result[p] := AnsiChar((d shr 16) and $ff); + inc(p); + Result[p] := AnsiChar((d shr 8) and $ff); + inc(p); + Result[p] := AnsiChar(d and $ff); + inc(p); + d := 0; + dl := 4; + end; + case dl of + 1: + begin + d := d shr 2; + Result[p] := AnsiChar((d shr 8) and $ff); + inc(p); + Result[p] := AnsiChar(d and $ff); + inc(p); + end; + 2: + begin + d := d shr 4; + Result[p] := AnsiChar(d and $ff); + inc(p); + end; + end; + SetLength(Result, p - 1); +end; + +{==============================================================================} + +function Encode3to4(const Value, Table: AnsiString): AnsiString; +var + c: Byte; + n, l: Integer; + Count: Integer; + DOut: array[0..3] of Byte; +begin + setlength(Result, ((Length(Value) + 2) div 3) * 4); + l := 1; + Count := 1; + while Count <= Length(Value) do + begin + c := Ord(Value[Count]); + Inc(Count); + DOut[0] := (c and $FC) shr 2; + DOut[1] := (c and $03) shl 4; + if Count <= Length(Value) then + begin + c := Ord(Value[Count]); + Inc(Count); + DOut[1] := DOut[1] + (c and $F0) shr 4; + DOut[2] := (c and $0F) shl 2; + if Count <= Length(Value) then + begin + c := Ord(Value[Count]); + Inc(Count); + DOut[2] := DOut[2] + (c and $C0) shr 6; + DOut[3] := (c and $3F); + end + else + begin + DOut[3] := $40; + end; + end + else + begin + DOut[2] := $40; + DOut[3] := $40; + end; + for n := 0 to 3 do + begin + if (DOut[n] + 1) <= Length(Table) then + begin + Result[l] := Table[DOut[n] + 1]; + Inc(l); + end; + end; + end; + SetLength(Result, l - 1); +end; + +{==============================================================================} + +function DecodeBase64(const Value: AnsiString): AnsiString; +begin + Result := Decode4to3Ex(Value, ReTableBase64); +end; + +{==============================================================================} + +function EncodeBase64(const Value: AnsiString): AnsiString; +begin + Result := Encode3to4(Value, TableBase64); +end; + +{==============================================================================} + +function DecodeBase64mod(const Value: AnsiString): AnsiString; +begin + Result := Decode4to3(Value, TableBase64mod); +end; + +{==============================================================================} + +function EncodeBase64mod(const Value: AnsiString): AnsiString; +begin + Result := Encode3to4(Value, TableBase64mod); +end; + +{==============================================================================} + +function DecodeUU(const Value: AnsiString): AnsiString; +var + s: AnsiString; + uut: AnsiString; + x: Integer; +begin + Result := ''; + uut := TableUU; + s := trim(UpperCase(Value)); + if s = '' then Exit; + if Pos('BEGIN', s) = 1 then + Exit; + if Pos('END', s) = 1 then + Exit; + if Pos('TABLE', s) = 1 then + Exit; //ignore Table yet (set custom UUT) + //begin decoding + x := Pos(Value[1], uut) - 1; + case (x mod 3) of + 0: x :=(x div 3)* 4; + 1: x :=((x div 3) * 4) + 2; + 2: x :=((x div 3) * 4) + 3; + end; + //x - lenght UU line + s := Copy(Value, 2, x); + if s = '' then + Exit; + s := s + StringOfChar(' ', x - length(s)); + Result := Decode4to3(s, uut); +end; + +{==============================================================================} + +function EncodeUU(const Value: AnsiString): AnsiString; +begin + Result := ''; + if Length(Value) < Length(TableUU) then + Result := TableUU[Length(Value) + 1] + Encode3to4(Value, TableUU); +end; + +{==============================================================================} + +function DecodeXX(const Value: AnsiString): AnsiString; +var + s: AnsiString; + x: Integer; +begin + Result := ''; + s := trim(UpperCase(Value)); + if s = '' then + Exit; + if Pos('BEGIN', s) = 1 then + Exit; + if Pos('END', s) = 1 then + Exit; + //begin decoding + x := Pos(Value[1], TableXX) - 1; + case (x mod 3) of + 0: x :=(x div 3)* 4; + 1: x :=((x div 3) * 4) + 2; + 2: x :=((x div 3) * 4) + 3; + end; + //x - lenght XX line + s := Copy(Value, 2, x); + if s = '' then + Exit; + s := s + StringOfChar(' ', x - length(s)); + Result := Decode4to3(s, TableXX); +end; + +{==============================================================================} + +function DecodeYEnc(const Value: AnsiString): AnsiString; +var + C : Byte; + i: integer; +begin + Result := ''; + i := 1; + while i <= Length(Value) do + begin + c := Ord(Value[i]); + Inc(i); + if c = Ord('=') then + begin + c := Ord(Value[i]); + Inc(i); + Dec(c, 64); + end; + Dec(C, 42); + Result := Result + AnsiChar(C); + end; +end; + +{==============================================================================} + +function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; +begin + Result := (Crc32 shr 8) + xor crc32tab[Byte(Value xor (Crc32 and Integer($000000FF)))]; +end; + +{==============================================================================} + +function Crc32(const Value: AnsiString): Integer; +var + n: Integer; +begin + Result := Integer($FFFFFFFF); + for n := 1 to Length(Value) do + Result := UpdateCrc32(Ord(Value[n]), Result); + Result := not Result; +end; + +{==============================================================================} + +function UpdateCrc16(Value: Byte; Crc16: Word): Word; +begin + Result := ((Crc16 shr 8) and $00FF) xor + crc16tab[Byte(Crc16 xor (Word(Value)) and $00FF)]; +end; + +{==============================================================================} + +function Crc16(const Value: AnsiString): Word; +var + n: Integer; +begin + Result := $FFFF; + for n := 1 to Length(Value) do + Result := UpdateCrc16(Ord(Value[n]), Result); +end; + +{==============================================================================} + +procedure MDInit(var MDContext: TMDCtx); +var + n: integer; +begin + MDContext.Count[0] := 0; + MDContext.Count[1] := 0; + for n := 0 to high(MDContext.BufAnsiChar) do + MDContext.BufAnsiChar[n] := 0; + for n := 0 to high(MDContext.BufLong) do + MDContext.BufLong[n] := 0; + MDContext.State[0] := Integer($67452301); + MDContext.State[1] := Integer($EFCDAB89); + MDContext.State[2] := Integer($98BADCFE); + MDContext.State[3] := Integer($10325476); +end; + +procedure MD5Transform(var Buf: array of LongInt; const Data: array of LongInt); +var + A, B, C, D: LongInt; + + procedure Round1(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); + begin + Inc(W, (Z xor (X and (Y xor Z))) + Data); + W := (W shl S) or (W shr (32 - S)); + Inc(W, X); + end; + + procedure Round2(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); + begin + Inc(W, (Y xor (Z and (X xor Y))) + Data); + W := (W shl S) or (W shr (32 - S)); + Inc(W, X); + end; + + procedure Round3(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); + begin + Inc(W, (X xor Y xor Z) + Data); + W := (W shl S) or (W shr (32 - S)); + Inc(W, X); + end; + + procedure Round4(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); + begin + Inc(W, (Y xor (X or not Z)) + Data); + W := (W shl S) or (W shr (32 - S)); + Inc(W, X); + end; +begin + A := Buf[0]; + B := Buf[1]; + C := Buf[2]; + D := Buf[3]; + + Round1(A, B, C, D, Data[0] + Longint($D76AA478), 7); + Round1(D, A, B, C, Data[1] + Longint($E8C7B756), 12); + Round1(C, D, A, B, Data[2] + Longint($242070DB), 17); + Round1(B, C, D, A, Data[3] + Longint($C1BDCEEE), 22); + Round1(A, B, C, D, Data[4] + Longint($F57C0FAF), 7); + Round1(D, A, B, C, Data[5] + Longint($4787C62A), 12); + Round1(C, D, A, B, Data[6] + Longint($A8304613), 17); + Round1(B, C, D, A, Data[7] + Longint($FD469501), 22); + Round1(A, B, C, D, Data[8] + Longint($698098D8), 7); + Round1(D, A, B, C, Data[9] + Longint($8B44F7AF), 12); + Round1(C, D, A, B, Data[10] + Longint($FFFF5BB1), 17); + Round1(B, C, D, A, Data[11] + Longint($895CD7BE), 22); + Round1(A, B, C, D, Data[12] + Longint($6B901122), 7); + Round1(D, A, B, C, Data[13] + Longint($FD987193), 12); + Round1(C, D, A, B, Data[14] + Longint($A679438E), 17); + Round1(B, C, D, A, Data[15] + Longint($49B40821), 22); + + Round2(A, B, C, D, Data[1] + Longint($F61E2562), 5); + Round2(D, A, B, C, Data[6] + Longint($C040B340), 9); + Round2(C, D, A, B, Data[11] + Longint($265E5A51), 14); + Round2(B, C, D, A, Data[0] + Longint($E9B6C7AA), 20); + Round2(A, B, C, D, Data[5] + Longint($D62F105D), 5); + Round2(D, A, B, C, Data[10] + Longint($02441453), 9); + Round2(C, D, A, B, Data[15] + Longint($D8A1E681), 14); + Round2(B, C, D, A, Data[4] + Longint($E7D3FBC8), 20); + Round2(A, B, C, D, Data[9] + Longint($21E1CDE6), 5); + Round2(D, A, B, C, Data[14] + Longint($C33707D6), 9); + Round2(C, D, A, B, Data[3] + Longint($F4D50D87), 14); + Round2(B, C, D, A, Data[8] + Longint($455A14ED), 20); + Round2(A, B, C, D, Data[13] + Longint($A9E3E905), 5); + Round2(D, A, B, C, Data[2] + Longint($FCEFA3F8), 9); + Round2(C, D, A, B, Data[7] + Longint($676F02D9), 14); + Round2(B, C, D, A, Data[12] + Longint($8D2A4C8A), 20); + + Round3(A, B, C, D, Data[5] + Longint($FFFA3942), 4); + Round3(D, A, B, C, Data[8] + Longint($8771F681), 11); + Round3(C, D, A, B, Data[11] + Longint($6D9D6122), 16); + Round3(B, C, D, A, Data[14] + Longint($FDE5380C), 23); + Round3(A, B, C, D, Data[1] + Longint($A4BEEA44), 4); + Round3(D, A, B, C, Data[4] + Longint($4BDECFA9), 11); + Round3(C, D, A, B, Data[7] + Longint($F6BB4B60), 16); + Round3(B, C, D, A, Data[10] + Longint($BEBFBC70), 23); + Round3(A, B, C, D, Data[13] + Longint($289B7EC6), 4); + Round3(D, A, B, C, Data[0] + Longint($EAA127FA), 11); + Round3(C, D, A, B, Data[3] + Longint($D4EF3085), 16); + Round3(B, C, D, A, Data[6] + Longint($04881D05), 23); + Round3(A, B, C, D, Data[9] + Longint($D9D4D039), 4); + Round3(D, A, B, C, Data[12] + Longint($E6DB99E5), 11); + Round3(C, D, A, B, Data[15] + Longint($1FA27CF8), 16); + Round3(B, C, D, A, Data[2] + Longint($C4AC5665), 23); + + Round4(A, B, C, D, Data[0] + Longint($F4292244), 6); + Round4(D, A, B, C, Data[7] + Longint($432AFF97), 10); + Round4(C, D, A, B, Data[14] + Longint($AB9423A7), 15); + Round4(B, C, D, A, Data[5] + Longint($FC93A039), 21); + Round4(A, B, C, D, Data[12] + Longint($655B59C3), 6); + Round4(D, A, B, C, Data[3] + Longint($8F0CCC92), 10); + Round4(C, D, A, B, Data[10] + Longint($FFEFF47D), 15); + Round4(B, C, D, A, Data[1] + Longint($85845DD1), 21); + Round4(A, B, C, D, Data[8] + Longint($6FA87E4F), 6); + Round4(D, A, B, C, Data[15] + Longint($FE2CE6E0), 10); + Round4(C, D, A, B, Data[6] + Longint($A3014314), 15); + Round4(B, C, D, A, Data[13] + Longint($4E0811A1), 21); + Round4(A, B, C, D, Data[4] + Longint($F7537E82), 6); + Round4(D, A, B, C, Data[11] + Longint($BD3AF235), 10); + Round4(C, D, A, B, Data[2] + Longint($2AD7D2BB), 15); + Round4(B, C, D, A, Data[9] + Longint($EB86D391), 21); + + Inc(Buf[0], A); + Inc(Buf[1], B); + Inc(Buf[2], C); + Inc(Buf[3], D); +end; + +//fixed by James McAdams +procedure MDUpdate(var MDContext: TMDCtx; const Data: AnsiString; transform: TMDTransform); +var + Index, partLen, InputLen, I: integer; +{$IFDEF SYNACODE_NATIVE} + n: integer; +{$ENDIF} +begin + InputLen := Length(Data); + with MDContext do + begin + Index := (Count[0] shr 3) and $3F; + Inc(Count[0], InputLen shl 3); + if Count[0] < (InputLen shl 3) then + Inc(Count[1]); + Inc(Count[1], InputLen shr 29); + partLen := 64 - Index; + if InputLen >= partLen then + begin + ArrLongToByte(BufLong, BufAnsiChar); + {$IFDEF SYNACODE_NATIVE} + for n := 1 to partLen do + BufAnsiChar[index - 1 + n] := Ord(Data[n]); + {$ELSE} + Move(Data[1], BufAnsiChar[Index], partLen); + {$ENDIF} + ArrByteToLong(BufAnsiChar, BufLong); + Transform(State, Buflong); + I := partLen; + while I + 63 < InputLen do + begin + ArrLongToByte(BufLong, BufAnsiChar); + {$IFDEF SYNACODE_NATIVE} + for n := 1 to 64 do + BufAnsiChar[n - 1] := Ord(Data[i + n]); + {$ELSE} + Move(Data[I+1], BufAnsiChar, 64); + {$ENDIF} + ArrByteToLong(BufAnsiChar, BufLong); + Transform(State, Buflong); + inc(I, 64); + end; + Index := 0; + end + else + I := 0; + ArrLongToByte(BufLong, BufAnsiChar); + {$IFDEF SYNACODE_NATIVE} + for n := 1 to InputLen-I do + BufAnsiChar[Index + n - 1] := Ord(Data[i + n]); + {$ELSE} + Move(Data[I+1], BufAnsiChar[Index], InputLen-I); + {$ENDIF} + ArrByteToLong(BufAnsiChar, BufLong); + end +end; + +function MDFinal(var MDContext: TMDCtx; transform: TMDTransform): AnsiString; +var + Cnt: Word; + P: Byte; + digest: array[0..15] of Byte; + i: Integer; + n: integer; +begin + for I := 0 to 15 do + Digest[I] := I + 1; + with MDContext do + begin + Cnt := (Count[0] shr 3) and $3F; + P := Cnt; + BufAnsiChar[P] := $80; + Inc(P); + Cnt := 64 - 1 - Cnt; + if Cnt < 8 then + begin + for n := 0 to cnt - 1 do + BufAnsiChar[P + n] := 0; + ArrByteToLong(BufAnsiChar, BufLong); +// FillChar(BufAnsiChar[P], Cnt, #0); + Transform(State, BufLong); + ArrLongToByte(BufLong, BufAnsiChar); + for n := 0 to 55 do + BufAnsiChar[n] := 0; + ArrByteToLong(BufAnsiChar, BufLong); +// FillChar(BufAnsiChar, 56, #0); + end + else + begin + for n := 0 to Cnt - 8 - 1 do + BufAnsiChar[p + n] := 0; + ArrByteToLong(BufAnsiChar, BufLong); +// FillChar(BufAnsiChar[P], Cnt - 8, #0); + end; + BufLong[14] := Count[0]; + BufLong[15] := Count[1]; + Transform(State, BufLong); + ArrLongToByte(State, Digest); +// Move(State, Digest, 16); + Result := ''; + for i := 0 to 15 do + Result := Result + AnsiChar(digest[i]); + end; +// FillChar(MD5Context, SizeOf(TMD5Ctx), #0) +end; + +{==============================================================================} + +function MD5(const Value: AnsiString): AnsiString; +var + MDContext: TMDCtx; +begin + MDInit(MDContext); + MDUpdate(MDContext, Value, @MD5Transform); + Result := MDFinal(MDContext, @MD5Transform); +end; + +{==============================================================================} + +function HMAC_MD5(Text, Key: AnsiString): AnsiString; +var + ipad, opad, s: AnsiString; + n: Integer; + MDContext: TMDCtx; +begin + if Length(Key) > 64 then + Key := md5(Key); + ipad := StringOfChar(#$36, 64); + opad := StringOfChar(#$5C, 64); + for n := 1 to Length(Key) do + begin + ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); + opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); + end; + MDInit(MDContext); + MDUpdate(MDContext, ipad, @MD5Transform); + MDUpdate(MDContext, Text, @MD5Transform); + s := MDFinal(MDContext, @MD5Transform); + MDInit(MDContext); + MDUpdate(MDContext, opad, @MD5Transform); + MDUpdate(MDContext, s, @MD5Transform); + Result := MDFinal(MDContext, @MD5Transform); +end; + +{==============================================================================} + +function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; +var + cnt, rest: integer; + l: integer; + n: integer; + MDContext: TMDCtx; +begin + l := length(Value); + cnt := Len div l; + rest := Len mod l; + MDInit(MDContext); + for n := 1 to cnt do + MDUpdate(MDContext, Value, @MD5Transform); + if rest > 0 then + MDUpdate(MDContext, Copy(Value, 1, rest), @MD5Transform); + Result := MDFinal(MDContext, @MD5Transform); +end; + +{==============================================================================} +// SHA1 is based on sources by Dave Barton (davebarton@bigfoot.com) + +procedure SHA1init( var SHA1Context: TSHA1Ctx ); +var + n: integer; +begin + SHA1Context.Hi := 0; + SHA1Context.Lo := 0; + SHA1Context.Index := 0; + for n := 0 to High(SHA1Context.Buffer) do + SHA1Context.Buffer[n] := 0; + for n := 0 to High(SHA1Context.HashByte) do + SHA1Context.HashByte[n] := 0; +// FillChar(SHA1Context, SizeOf(TSHA1Ctx), #0); + SHA1Context.Hash[0] := integer($67452301); + SHA1Context.Hash[1] := integer($EFCDAB89); + SHA1Context.Hash[2] := integer($98BADCFE); + SHA1Context.Hash[3] := integer($10325476); + SHA1Context.Hash[4] := integer($C3D2E1F0); +end; + +//****************************************************************************** +function RB(A: integer): integer; +begin + Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); +end; + +procedure SHA1Compress(var Data: TSHA1Ctx); +var + A, B, C, D, E, T: integer; + W: array[0..79] of integer; + i: integer; + n: integer; + + function F1(x, y, z: integer): integer; + begin + Result := z xor (x and (y xor z)); + end; + function F2(x, y, z: integer): integer; + begin + Result := x xor y xor z; + end; + function F3(x, y, z: integer): integer; + begin + Result := (x and y) or (z and (x or y)); + end; + function LRot32(X: integer; c: integer): integer; + begin + result := (x shl c) or (x shr (32 - c)); + end; +begin + ArrByteToLong(Data.Buffer, W); +// Move(Data.Buffer, W, Sizeof(Data.Buffer)); + for i := 0 to 15 do + W[i] := RB(W[i]); + for i := 16 to 79 do + W[i] := LRot32(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16], 1); + A := Data.Hash[0]; + B := Data.Hash[1]; + C := Data.Hash[2]; + D := Data.Hash[3]; + E := Data.Hash[4]; + for i := 0 to 19 do + begin + T := LRot32(A, 5) + F1(B, C, D) + E + W[i] + integer($5A827999); + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for i := 20 to 39 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($6ED9EBA1); + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for i := 40 to 59 do + begin + T := LRot32(A, 5) + F3(B, C, D) + E + W[i] + integer($8F1BBCDC); + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + for i := 60 to 79 do + begin + T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($CA62C1D6); + E := D; + D := C; + C := LRot32(B, 30); + B := A; + A := T; + end; + Data.Hash[0] := Data.Hash[0] + A; + Data.Hash[1] := Data.Hash[1] + B; + Data.Hash[2] := Data.Hash[2] + C; + Data.Hash[3] := Data.Hash[3] + D; + Data.Hash[4] := Data.Hash[4] + E; + for n := 0 to high(w) do + w[n] := 0; +// FillChar(W, Sizeof(W), 0); + for n := 0 to high(Data.Buffer) do + Data.Buffer[n] := 0; +// FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); +end; + +//****************************************************************************** +procedure SHA1Update(var Context: TSHA1Ctx; const Data: AnsiString); +var + Len: integer; + n: integer; + i, k: integer; +begin + Len := Length(data); + for k := 0 to 7 do + begin + i := Context.Lo; + Inc(Context.Lo, Len); + if Context.Lo < i then + Inc(Context.Hi); + end; + for n := 1 to len do + begin + Context.Buffer[Context.Index] := byte(Data[n]); + Inc(Context.Index); + if Context.Index = 64 then + begin + Context.Index := 0; + SHA1Compress(Context); + end; + end; +end; + +//****************************************************************************** +function SHA1Final(var Context: TSHA1Ctx): AnsiString; +type + Pinteger = ^integer; +var + i: integer; + procedure ItoArr(var Ar: Array of byte; I, value: Integer); + begin + Ar[i + 0] := Value and $000000FF; + Ar[i + 1] := (Value shr 8) and $000000FF; + Ar[i + 2] := (Value shr 16) and $000000FF; + Ar[i + 3] := (Value shr 24) and $000000FF; + end; +begin + Context.Buffer[Context.Index] := $80; + if Context.Index >= 56 then + SHA1Compress(Context); + ItoArr(Context.Buffer, 56, RB(Context.Hi)); + ItoArr(Context.Buffer, 60, RB(Context.Lo)); +// Pinteger(@Context.Buffer[56])^ := RB(Context.Hi); +// Pinteger(@Context.Buffer[60])^ := RB(Context.Lo); + SHA1Compress(Context); + Context.Hash[0] := RB(Context.Hash[0]); + Context.Hash[1] := RB(Context.Hash[1]); + Context.Hash[2] := RB(Context.Hash[2]); + Context.Hash[3] := RB(Context.Hash[3]); + Context.Hash[4] := RB(Context.Hash[4]); + ArrLongToByte(Context.Hash, Context.HashByte); + Result := ''; + for i := 0 to 19 do + Result := Result + AnsiChar(Context.HashByte[i]); +end; + +function SHA1(const Value: AnsiString): AnsiString; +var + SHA1Context: TSHA1Ctx; +begin + SHA1Init(SHA1Context); + SHA1Update(SHA1Context, Value); + Result := SHA1Final(SHA1Context); +end; + +{==============================================================================} + +function HMAC_SHA1(Text, Key: AnsiString): AnsiString; +var + ipad, opad, s: AnsiString; + n: Integer; + SHA1Context: TSHA1Ctx; +begin + if Length(Key) > 64 then + Key := SHA1(Key); + ipad := StringOfChar(#$36, 64); + opad := StringOfChar(#$5C, 64); + for n := 1 to Length(Key) do + begin + ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); + opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); + end; + SHA1Init(SHA1Context); + SHA1Update(SHA1Context, ipad); + SHA1Update(SHA1Context, Text); + s := SHA1Final(SHA1Context); + SHA1Init(SHA1Context); + SHA1Update(SHA1Context, opad); + SHA1Update(SHA1Context, s); + Result := SHA1Final(SHA1Context); +end; + +{==============================================================================} + +function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; +var + cnt, rest: integer; + l: integer; + n: integer; + SHA1Context: TSHA1Ctx; +begin + l := length(Value); + cnt := Len div l; + rest := Len mod l; + SHA1Init(SHA1Context); + for n := 1 to cnt do + SHA1Update(SHA1Context, Value); + if rest > 0 then + SHA1Update(SHA1Context, Copy(Value, 1, rest)); + Result := SHA1Final(SHA1Context); +end; + +{==============================================================================} + +procedure MD4Transform(var Buf: array of LongInt; const Data: array of LongInt); +var + A, B, C, D: LongInt; + function LRot32(a, b: longint): longint; + begin + Result:= (a shl b) or (a shr (32 - b)); + end; +begin + A := Buf[0]; + B := Buf[1]; + C := Buf[2]; + D := Buf[3]; + + A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 0], 3); + D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 1], 7); + C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 2], 11); + B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 3], 19); + A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 4], 3); + D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 5], 7); + C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 6], 11); + B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 7], 19); + A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 8], 3); + D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 9], 7); + C:= LRot32(C + (B xor (D and (A xor B))) + Data[10], 11); + B:= LRot32(B + (A xor (C and (D xor A))) + Data[11], 19); + A:= LRot32(A + (D xor (B and (C xor D))) + Data[12], 3); + D:= LRot32(D + (C xor (A and (B xor C))) + Data[13], 7); + C:= LRot32(C + (B xor (D and (A xor B))) + Data[14], 11); + B:= LRot32(B + (A xor (C and (D xor A))) + Data[15], 19); + + A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 0] + longint($5a827999), 3); + D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 4] + longint($5a827999), 5); + C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 8] + longint($5a827999), 9); + B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[12] + longint($5a827999), 13); + A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 1] + longint($5a827999), 3); + D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 5] + longint($5a827999), 5); + C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 9] + longint($5a827999), 9); + B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[13] + longint($5a827999), 13); + A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 2] + longint($5a827999), 3); + D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 6] + longint($5a827999), 5); + C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[10] + longint($5a827999), 9); + B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[14] + longint($5a827999), 13); + A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 3] + longint($5a827999), 3); + D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 7] + longint($5a827999), 5); + C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[11] + longint($5a827999), 9); + B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[15] + longint($5a827999), 13); + + A:= LRot32(A + (B xor C xor D) + Data[ 0] + longint($6ed9eba1), 3); + D:= LRot32(D + (A xor B xor C) + Data[ 8] + longint($6ed9eba1), 9); + C:= LRot32(C + (D xor A xor B) + Data[ 4] + longint($6ed9eba1), 11); + B:= LRot32(B + (C xor D xor A) + Data[12] + longint($6ed9eba1), 15); + A:= LRot32(A + (B xor C xor D) + Data[ 2] + longint($6ed9eba1), 3); + D:= LRot32(D + (A xor B xor C) + Data[10] + longint($6ed9eba1), 9); + C:= LRot32(C + (D xor A xor B) + Data[ 6] + longint($6ed9eba1), 11); + B:= LRot32(B + (C xor D xor A) + Data[14] + longint($6ed9eba1), 15); + A:= LRot32(A + (B xor C xor D) + Data[ 1] + longint($6ed9eba1), 3); + D:= LRot32(D + (A xor B xor C) + Data[ 9] + longint($6ed9eba1), 9); + C:= LRot32(C + (D xor A xor B) + Data[ 5] + longint($6ed9eba1), 11); + B:= LRot32(B + (C xor D xor A) + Data[13] + longint($6ed9eba1), 15); + A:= LRot32(A + (B xor C xor D) + Data[ 3] + longint($6ed9eba1), 3); + D:= LRot32(D + (A xor B xor C) + Data[11] + longint($6ed9eba1), 9); + C:= LRot32(C + (D xor A xor B) + Data[ 7] + longint($6ed9eba1), 11); + B:= LRot32(B + (C xor D xor A) + Data[15] + longint($6ed9eba1), 15); + + Inc(Buf[0], A); + Inc(Buf[1], B); + Inc(Buf[2], C); + Inc(Buf[3], D); +end; + +{==============================================================================} + +function MD4(const Value: AnsiString): AnsiString; +var + MDContext: TMDCtx; +begin + MDInit(MDContext); + MDUpdate(MDContext, Value, @MD4Transform); + Result := MDFinal(MDContext, @MD4Transform); +end; + +{==============================================================================} + + +end. diff --git a/3rd/synapse/source/synacrypt.pas b/3rd/synapse/source/synacrypt.pas index f19d25604..31e915d0e 100644 --- a/3rd/synapse/source/synacrypt.pas +++ b/3rd/synapse/source/synacrypt.pas @@ -1,2412 +1,2412 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.000 | -|==============================================================================| -| Content: Encryption support | -|==============================================================================| -| Copyright (c)2007-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2007-2011. | -| All Rights Reserved. | -| Based on work of David Barton and Eric Young | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Encryption support) - -Implemented are DES and 3DES encryption/decryption by ECB, CBC, CFB-8bit, - CFB-block, OFB and CTR methods. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synacrypt; - -interface - -uses - SysUtils, Classes, synautil, synafpc; - -type - {:@abstract(Implementation of common routines block ciphers (dafault size is 64-bits)) - - Do not use this class directly, use descendants only!} - TSynaBlockCipher= class(TObject) - protected - procedure InitKey(Key: AnsiString); virtual; - function GetSize: byte; virtual; - private - IV, CV: AnsiString; - procedure IncCounter; - public - {:Sets the IV to Value and performs a reset} - procedure SetIV(const Value: AnsiString); virtual; - {:Returns the current chaining information, not the actual IV} - function GetIV: AnsiString; virtual; - {:Reset any stored chaining information} - procedure Reset; virtual; - {:Encrypt a 64-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; virtual; - {:Decrypt a 64-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; virtual; - {:Encrypt data using the CBC method of encryption} - function EncryptCBC(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CBC method of decryption} - function DecryptCBC(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the CFB (8 bit) method of encryption} - function EncryptCFB8bit(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CFB (8 bit) method of decryption} - function DecryptCFB8bit(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the CFB (block) method of encryption} - function EncryptCFBblock(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CFB (block) method of decryption} - function DecryptCFBblock(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the OFB method of encryption} - function EncryptOFB(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the OFB method of decryption} - function DecryptOFB(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the CTR method of encryption} - function EncryptCTR(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CTR method of decryption} - function DecryptCTR(const Indata: AnsiString): AnsiString; virtual; - {:Create a encryptor/decryptor instance and initialize it by the Key.} - constructor Create(Key: AnsiString); - end; - - {:@abstract(Datatype for holding one DES key data) - - This data type is used internally.} - TDesKeyData = array[0..31] of integer; - - {:@abstract(Implementation of common routines for DES encryption) - - Do not use this class directly, use descendants only!} - TSynaCustomDes = class(TSynaBlockcipher) - protected - procedure DoInit(KeyB: AnsiString; var KeyData: TDesKeyData); - function EncryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; - function DecryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; - end; - - {:@abstract(Implementation of DES encryption)} - TSynaDes= class(TSynaCustomDes) - protected - KeyData: TDesKeyData; - procedure InitKey(Key: AnsiString); override; - public - {:Encrypt a 64-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; override; - {:Decrypt a 64-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; override; - end; - - {:@abstract(Implementation of 3DES encryption)} - TSyna3Des= class(TSynaCustomDes) - protected - KeyData: array[0..2] of TDesKeyData; - procedure InitKey(Key: AnsiString); override; - public - {:Encrypt a 64-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; override; - {:Decrypt a 64-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; override; - end; - -const - BC = 4; - MAXROUNDS = 14; -type - {:@abstract(Implementation of AES encryption)} - TSynaAes= class(TSynaBlockcipher) - protected - numrounds: longword; - rk, drk: array[0..MAXROUNDS,0..7] of longword; - procedure InitKey(Key: AnsiString); override; - function GetSize: byte; override; - public - {:Encrypt a 128-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; override; - {:Decrypt a 128-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; override; - end; - -{:Call internal test of all DES encryptions. Returns @true if all is OK.} -function TestDes: boolean; -{:Call internal test of all 3DES encryptions. Returns @true if all is OK.} -function Test3Des: boolean; -{:Call internal test of all AES encryptions. Returns @true if all is OK.} -function TestAes: boolean; - -{==============================================================================} -implementation - -//DES consts -const - shifts2: array[0..15]of byte= - (0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0); - - des_skb: array[0..7,0..63]of integer=( - ( - (* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 *) - integer($00000000),integer($00000010),integer($20000000),integer($20000010), - integer($00010000),integer($00010010),integer($20010000),integer($20010010), - integer($00000800),integer($00000810),integer($20000800),integer($20000810), - integer($00010800),integer($00010810),integer($20010800),integer($20010810), - integer($00000020),integer($00000030),integer($20000020),integer($20000030), - integer($00010020),integer($00010030),integer($20010020),integer($20010030), - integer($00000820),integer($00000830),integer($20000820),integer($20000830), - integer($00010820),integer($00010830),integer($20010820),integer($20010830), - integer($00080000),integer($00080010),integer($20080000),integer($20080010), - integer($00090000),integer($00090010),integer($20090000),integer($20090010), - integer($00080800),integer($00080810),integer($20080800),integer($20080810), - integer($00090800),integer($00090810),integer($20090800),integer($20090810), - integer($00080020),integer($00080030),integer($20080020),integer($20080030), - integer($00090020),integer($00090030),integer($20090020),integer($20090030), - integer($00080820),integer($00080830),integer($20080820),integer($20080830), - integer($00090820),integer($00090830),integer($20090820),integer($20090830) - ),( - (* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 *) - integer($00000000),integer($02000000),integer($00002000),integer($02002000), - integer($00200000),integer($02200000),integer($00202000),integer($02202000), - integer($00000004),integer($02000004),integer($00002004),integer($02002004), - integer($00200004),integer($02200004),integer($00202004),integer($02202004), - integer($00000400),integer($02000400),integer($00002400),integer($02002400), - integer($00200400),integer($02200400),integer($00202400),integer($02202400), - integer($00000404),integer($02000404),integer($00002404),integer($02002404), - integer($00200404),integer($02200404),integer($00202404),integer($02202404), - integer($10000000),integer($12000000),integer($10002000),integer($12002000), - integer($10200000),integer($12200000),integer($10202000),integer($12202000), - integer($10000004),integer($12000004),integer($10002004),integer($12002004), - integer($10200004),integer($12200004),integer($10202004),integer($12202004), - integer($10000400),integer($12000400),integer($10002400),integer($12002400), - integer($10200400),integer($12200400),integer($10202400),integer($12202400), - integer($10000404),integer($12000404),integer($10002404),integer($12002404), - integer($10200404),integer($12200404),integer($10202404),integer($12202404) - ),( - (* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 *) - integer($00000000),integer($00000001),integer($00040000),integer($00040001), - integer($01000000),integer($01000001),integer($01040000),integer($01040001), - integer($00000002),integer($00000003),integer($00040002),integer($00040003), - integer($01000002),integer($01000003),integer($01040002),integer($01040003), - integer($00000200),integer($00000201),integer($00040200),integer($00040201), - integer($01000200),integer($01000201),integer($01040200),integer($01040201), - integer($00000202),integer($00000203),integer($00040202),integer($00040203), - integer($01000202),integer($01000203),integer($01040202),integer($01040203), - integer($08000000),integer($08000001),integer($08040000),integer($08040001), - integer($09000000),integer($09000001),integer($09040000),integer($09040001), - integer($08000002),integer($08000003),integer($08040002),integer($08040003), - integer($09000002),integer($09000003),integer($09040002),integer($09040003), - integer($08000200),integer($08000201),integer($08040200),integer($08040201), - integer($09000200),integer($09000201),integer($09040200),integer($09040201), - integer($08000202),integer($08000203),integer($08040202),integer($08040203), - integer($09000202),integer($09000203),integer($09040202),integer($09040203) - ),( - (* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 *) - integer($00000000),integer($00100000),integer($00000100),integer($00100100), - integer($00000008),integer($00100008),integer($00000108),integer($00100108), - integer($00001000),integer($00101000),integer($00001100),integer($00101100), - integer($00001008),integer($00101008),integer($00001108),integer($00101108), - integer($04000000),integer($04100000),integer($04000100),integer($04100100), - integer($04000008),integer($04100008),integer($04000108),integer($04100108), - integer($04001000),integer($04101000),integer($04001100),integer($04101100), - integer($04001008),integer($04101008),integer($04001108),integer($04101108), - integer($00020000),integer($00120000),integer($00020100),integer($00120100), - integer($00020008),integer($00120008),integer($00020108),integer($00120108), - integer($00021000),integer($00121000),integer($00021100),integer($00121100), - integer($00021008),integer($00121008),integer($00021108),integer($00121108), - integer($04020000),integer($04120000),integer($04020100),integer($04120100), - integer($04020008),integer($04120008),integer($04020108),integer($04120108), - integer($04021000),integer($04121000),integer($04021100),integer($04121100), - integer($04021008),integer($04121008),integer($04021108),integer($04121108) - ),( - (* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 *) - integer($00000000),integer($10000000),integer($00010000),integer($10010000), - integer($00000004),integer($10000004),integer($00010004),integer($10010004), - integer($20000000),integer($30000000),integer($20010000),integer($30010000), - integer($20000004),integer($30000004),integer($20010004),integer($30010004), - integer($00100000),integer($10100000),integer($00110000),integer($10110000), - integer($00100004),integer($10100004),integer($00110004),integer($10110004), - integer($20100000),integer($30100000),integer($20110000),integer($30110000), - integer($20100004),integer($30100004),integer($20110004),integer($30110004), - integer($00001000),integer($10001000),integer($00011000),integer($10011000), - integer($00001004),integer($10001004),integer($00011004),integer($10011004), - integer($20001000),integer($30001000),integer($20011000),integer($30011000), - integer($20001004),integer($30001004),integer($20011004),integer($30011004), - integer($00101000),integer($10101000),integer($00111000),integer($10111000), - integer($00101004),integer($10101004),integer($00111004),integer($10111004), - integer($20101000),integer($30101000),integer($20111000),integer($30111000), - integer($20101004),integer($30101004),integer($20111004),integer($30111004) - ),( - (* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 *) - integer($00000000),integer($08000000),integer($00000008),integer($08000008), - integer($00000400),integer($08000400),integer($00000408),integer($08000408), - integer($00020000),integer($08020000),integer($00020008),integer($08020008), - integer($00020400),integer($08020400),integer($00020408),integer($08020408), - integer($00000001),integer($08000001),integer($00000009),integer($08000009), - integer($00000401),integer($08000401),integer($00000409),integer($08000409), - integer($00020001),integer($08020001),integer($00020009),integer($08020009), - integer($00020401),integer($08020401),integer($00020409),integer($08020409), - integer($02000000),integer($0A000000),integer($02000008),integer($0A000008), - integer($02000400),integer($0A000400),integer($02000408),integer($0A000408), - integer($02020000),integer($0A020000),integer($02020008),integer($0A020008), - integer($02020400),integer($0A020400),integer($02020408),integer($0A020408), - integer($02000001),integer($0A000001),integer($02000009),integer($0A000009), - integer($02000401),integer($0A000401),integer($02000409),integer($0A000409), - integer($02020001),integer($0A020001),integer($02020009),integer($0A020009), - integer($02020401),integer($0A020401),integer($02020409),integer($0A020409) - ),( - (* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 *) - integer($00000000),integer($00000100),integer($00080000),integer($00080100), - integer($01000000),integer($01000100),integer($01080000),integer($01080100), - integer($00000010),integer($00000110),integer($00080010),integer($00080110), - integer($01000010),integer($01000110),integer($01080010),integer($01080110), - integer($00200000),integer($00200100),integer($00280000),integer($00280100), - integer($01200000),integer($01200100),integer($01280000),integer($01280100), - integer($00200010),integer($00200110),integer($00280010),integer($00280110), - integer($01200010),integer($01200110),integer($01280010),integer($01280110), - integer($00000200),integer($00000300),integer($00080200),integer($00080300), - integer($01000200),integer($01000300),integer($01080200),integer($01080300), - integer($00000210),integer($00000310),integer($00080210),integer($00080310), - integer($01000210),integer($01000310),integer($01080210),integer($01080310), - integer($00200200),integer($00200300),integer($00280200),integer($00280300), - integer($01200200),integer($01200300),integer($01280200),integer($01280300), - integer($00200210),integer($00200310),integer($00280210),integer($00280310), - integer($01200210),integer($01200310),integer($01280210),integer($01280310) - ),( - (* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 *) - integer($00000000),integer($04000000),integer($00040000),integer($04040000), - integer($00000002),integer($04000002),integer($00040002),integer($04040002), - integer($00002000),integer($04002000),integer($00042000),integer($04042000), - integer($00002002),integer($04002002),integer($00042002),integer($04042002), - integer($00000020),integer($04000020),integer($00040020),integer($04040020), - integer($00000022),integer($04000022),integer($00040022),integer($04040022), - integer($00002020),integer($04002020),integer($00042020),integer($04042020), - integer($00002022),integer($04002022),integer($00042022),integer($04042022), - integer($00000800),integer($04000800),integer($00040800),integer($04040800), - integer($00000802),integer($04000802),integer($00040802),integer($04040802), - integer($00002800),integer($04002800),integer($00042800),integer($04042800), - integer($00002802),integer($04002802),integer($00042802),integer($04042802), - integer($00000820),integer($04000820),integer($00040820),integer($04040820), - integer($00000822),integer($04000822),integer($00040822),integer($04040822), - integer($00002820),integer($04002820),integer($00042820),integer($04042820), - integer($00002822),integer($04002822),integer($00042822),integer($04042822) - )); - - des_sptrans: array[0..7,0..63] of integer=( - ( - (* nibble 0 *) - integer($02080800), integer($00080000), integer($02000002), integer($02080802), - integer($02000000), integer($00080802), integer($00080002), integer($02000002), - integer($00080802), integer($02080800), integer($02080000), integer($00000802), - integer($02000802), integer($02000000), integer($00000000), integer($00080002), - integer($00080000), integer($00000002), integer($02000800), integer($00080800), - integer($02080802), integer($02080000), integer($00000802), integer($02000800), - integer($00000002), integer($00000800), integer($00080800), integer($02080002), - integer($00000800), integer($02000802), integer($02080002), integer($00000000), - integer($00000000), integer($02080802), integer($02000800), integer($00080002), - integer($02080800), integer($00080000), integer($00000802), integer($02000800), - integer($02080002), integer($00000800), integer($00080800), integer($02000002), - integer($00080802), integer($00000002), integer($02000002), integer($02080000), - integer($02080802), integer($00080800), integer($02080000), integer($02000802), - integer($02000000), integer($00000802), integer($00080002), integer($00000000), - integer($00080000), integer($02000000), integer($02000802), integer($02080800), - integer($00000002), integer($02080002), integer($00000800), integer($00080802) - ),( - (* nibble 1 *) - integer($40108010), integer($00000000), integer($00108000), integer($40100000), - integer($40000010), integer($00008010), integer($40008000), integer($00108000), - integer($00008000), integer($40100010), integer($00000010), integer($40008000), - integer($00100010), integer($40108000), integer($40100000), integer($00000010), - integer($00100000), integer($40008010), integer($40100010), integer($00008000), - integer($00108010), integer($40000000), integer($00000000), integer($00100010), - integer($40008010), integer($00108010), integer($40108000), integer($40000010), - integer($40000000), integer($00100000), integer($00008010), integer($40108010), - integer($00100010), integer($40108000), integer($40008000), integer($00108010), - integer($40108010), integer($00100010), integer($40000010), integer($00000000), - integer($40000000), integer($00008010), integer($00100000), integer($40100010), - integer($00008000), integer($40000000), integer($00108010), integer($40008010), - integer($40108000), integer($00008000), integer($00000000), integer($40000010), - integer($00000010), integer($40108010), integer($00108000), integer($40100000), - integer($40100010), integer($00100000), integer($00008010), integer($40008000), - integer($40008010), integer($00000010), integer($40100000), integer($00108000) - ),( - (* nibble 2 *) - integer($04000001), integer($04040100), integer($00000100), integer($04000101), - integer($00040001), integer($04000000), integer($04000101), integer($00040100), - integer($04000100), integer($00040000), integer($04040000), integer($00000001), - integer($04040101), integer($00000101), integer($00000001), integer($04040001), - integer($00000000), integer($00040001), integer($04040100), integer($00000100), - integer($00000101), integer($04040101), integer($00040000), integer($04000001), - integer($04040001), integer($04000100), integer($00040101), integer($04040000), - integer($00040100), integer($00000000), integer($04000000), integer($00040101), - integer($04040100), integer($00000100), integer($00000001), integer($00040000), - integer($00000101), integer($00040001), integer($04040000), integer($04000101), - integer($00000000), integer($04040100), integer($00040100), integer($04040001), - integer($00040001), integer($04000000), integer($04040101), integer($00000001), - integer($00040101), integer($04000001), integer($04000000), integer($04040101), - integer($00040000), integer($04000100), integer($04000101), integer($00040100), - integer($04000100), integer($00000000), integer($04040001), integer($00000101), - integer($04000001), integer($00040101), integer($00000100), integer($04040000) - ),( - (* nibble 3 *) - integer($00401008), integer($10001000), integer($00000008), integer($10401008), - integer($00000000), integer($10400000), integer($10001008), integer($00400008), - integer($10401000), integer($10000008), integer($10000000), integer($00001008), - integer($10000008), integer($00401008), integer($00400000), integer($10000000), - integer($10400008), integer($00401000), integer($00001000), integer($00000008), - integer($00401000), integer($10001008), integer($10400000), integer($00001000), - integer($00001008), integer($00000000), integer($00400008), integer($10401000), - integer($10001000), integer($10400008), integer($10401008), integer($00400000), - integer($10400008), integer($00001008), integer($00400000), integer($10000008), - integer($00401000), integer($10001000), integer($00000008), integer($10400000), - integer($10001008), integer($00000000), integer($00001000), integer($00400008), - integer($00000000), integer($10400008), integer($10401000), integer($00001000), - integer($10000000), integer($10401008), integer($00401008), integer($00400000), - integer($10401008), integer($00000008), integer($10001000), integer($00401008), - integer($00400008), integer($00401000), integer($10400000), integer($10001008), - integer($00001008), integer($10000000), integer($10000008), integer($10401000) - ),( - (* nibble 4 *) - integer($08000000), integer($00010000), integer($00000400), integer($08010420), - integer($08010020), integer($08000400), integer($00010420), integer($08010000), - integer($00010000), integer($00000020), integer($08000020), integer($00010400), - integer($08000420), integer($08010020), integer($08010400), integer($00000000), - integer($00010400), integer($08000000), integer($00010020), integer($00000420), - integer($08000400), integer($00010420), integer($00000000), integer($08000020), - integer($00000020), integer($08000420), integer($08010420), integer($00010020), - integer($08010000), integer($00000400), integer($00000420), integer($08010400), - integer($08010400), integer($08000420), integer($00010020), integer($08010000), - integer($00010000), integer($00000020), integer($08000020), integer($08000400), - integer($08000000), integer($00010400), integer($08010420), integer($00000000), - integer($00010420), integer($08000000), integer($00000400), integer($00010020), - integer($08000420), integer($00000400), integer($00000000), integer($08010420), - integer($08010020), integer($08010400), integer($00000420), integer($00010000), - integer($00010400), integer($08010020), integer($08000400), integer($00000420), - integer($00000020), integer($00010420), integer($08010000), integer($08000020) - ),( - (* nibble 5 *) - integer($80000040), integer($00200040), integer($00000000), integer($80202000), - integer($00200040), integer($00002000), integer($80002040), integer($00200000), - integer($00002040), integer($80202040), integer($00202000), integer($80000000), - integer($80002000), integer($80000040), integer($80200000), integer($00202040), - integer($00200000), integer($80002040), integer($80200040), integer($00000000), - integer($00002000), integer($00000040), integer($80202000), integer($80200040), - integer($80202040), integer($80200000), integer($80000000), integer($00002040), - integer($00000040), integer($00202000), integer($00202040), integer($80002000), - integer($00002040), integer($80000000), integer($80002000), integer($00202040), - integer($80202000), integer($00200040), integer($00000000), integer($80002000), - integer($80000000), integer($00002000), integer($80200040), integer($00200000), - integer($00200040), integer($80202040), integer($00202000), integer($00000040), - integer($80202040), integer($00202000), integer($00200000), integer($80002040), - integer($80000040), integer($80200000), integer($00202040), integer($00000000), - integer($00002000), integer($80000040), integer($80002040), integer($80202000), - integer($80200000), integer($00002040), integer($00000040), integer($80200040) - ),( - (* nibble 6 *) - integer($00004000), integer($00000200), integer($01000200), integer($01000004), - integer($01004204), integer($00004004), integer($00004200), integer($00000000), - integer($01000000), integer($01000204), integer($00000204), integer($01004000), - integer($00000004), integer($01004200), integer($01004000), integer($00000204), - integer($01000204), integer($00004000), integer($00004004), integer($01004204), - integer($00000000), integer($01000200), integer($01000004), integer($00004200), - integer($01004004), integer($00004204), integer($01004200), integer($00000004), - integer($00004204), integer($01004004), integer($00000200), integer($01000000), - integer($00004204), integer($01004000), integer($01004004), integer($00000204), - integer($00004000), integer($00000200), integer($01000000), integer($01004004), - integer($01000204), integer($00004204), integer($00004200), integer($00000000), - integer($00000200), integer($01000004), integer($00000004), integer($01000200), - integer($00000000), integer($01000204), integer($01000200), integer($00004200), - integer($00000204), integer($00004000), integer($01004204), integer($01000000), - integer($01004200), integer($00000004), integer($00004004), integer($01004204), - integer($01000004), integer($01004200), integer($01004000), integer($00004004) - ),( - (* nibble 7 *) - integer($20800080), integer($20820000), integer($00020080), integer($00000000), - integer($20020000), integer($00800080), integer($20800000), integer($20820080), - integer($00000080), integer($20000000), integer($00820000), integer($00020080), - integer($00820080), integer($20020080), integer($20000080), integer($20800000), - integer($00020000), integer($00820080), integer($00800080), integer($20020000), - integer($20820080), integer($20000080), integer($00000000), integer($00820000), - integer($20000000), integer($00800000), integer($20020080), integer($20800080), - integer($00800000), integer($00020000), integer($20820000), integer($00000080), - integer($00800000), integer($00020000), integer($20000080), integer($20820080), - integer($00020080), integer($20000000), integer($00000000), integer($00820000), - integer($20800080), integer($20020080), integer($20020000), integer($00800080), - integer($20820000), integer($00000080), integer($00800080), integer($20020000), - integer($20820080), integer($00800000), integer($20800000), integer($20000080), - integer($00820000), integer($00020080), integer($20020080), integer($20800000), - integer($00000080), integer($20820000), integer($00820080), integer($00000000), - integer($20000000), integer($20800080), integer($00020000), integer($00820080) - )); - -//AES consts -const - MAXBC= 8; - MAXKC= 8; - - S: array[0..255] of byte= ( - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, - 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, - 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, - 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, - 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, - 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, - 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, - 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, - 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, - 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, - 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, - 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22); - T1: array[0..255,0..3] of byte= ( - ($c6,$63,$63,$a5), ($f8,$7c,$7c,$84), ($ee,$77,$77,$99), ($f6,$7b,$7b,$8d), - ($ff,$f2,$f2,$0d), ($d6,$6b,$6b,$bd), ($de,$6f,$6f,$b1), ($91,$c5,$c5,$54), - ($60,$30,$30,$50), ($02,$01,$01,$03), ($ce,$67,$67,$a9), ($56,$2b,$2b,$7d), - ($e7,$fe,$fe,$19), ($b5,$d7,$d7,$62), ($4d,$ab,$ab,$e6), ($ec,$76,$76,$9a), - ($8f,$ca,$ca,$45), ($1f,$82,$82,$9d), ($89,$c9,$c9,$40), ($fa,$7d,$7d,$87), - ($ef,$fa,$fa,$15), ($b2,$59,$59,$eb), ($8e,$47,$47,$c9), ($fb,$f0,$f0,$0b), - ($41,$ad,$ad,$ec), ($b3,$d4,$d4,$67), ($5f,$a2,$a2,$fd), ($45,$af,$af,$ea), - ($23,$9c,$9c,$bf), ($53,$a4,$a4,$f7), ($e4,$72,$72,$96), ($9b,$c0,$c0,$5b), - ($75,$b7,$b7,$c2), ($e1,$fd,$fd,$1c), ($3d,$93,$93,$ae), ($4c,$26,$26,$6a), - ($6c,$36,$36,$5a), ($7e,$3f,$3f,$41), ($f5,$f7,$f7,$02), ($83,$cc,$cc,$4f), - ($68,$34,$34,$5c), ($51,$a5,$a5,$f4), ($d1,$e5,$e5,$34), ($f9,$f1,$f1,$08), - ($e2,$71,$71,$93), ($ab,$d8,$d8,$73), ($62,$31,$31,$53), ($2a,$15,$15,$3f), - ($08,$04,$04,$0c), ($95,$c7,$c7,$52), ($46,$23,$23,$65), ($9d,$c3,$c3,$5e), - ($30,$18,$18,$28), ($37,$96,$96,$a1), ($0a,$05,$05,$0f), ($2f,$9a,$9a,$b5), - ($0e,$07,$07,$09), ($24,$12,$12,$36), ($1b,$80,$80,$9b), ($df,$e2,$e2,$3d), - ($cd,$eb,$eb,$26), ($4e,$27,$27,$69), ($7f,$b2,$b2,$cd), ($ea,$75,$75,$9f), - ($12,$09,$09,$1b), ($1d,$83,$83,$9e), ($58,$2c,$2c,$74), ($34,$1a,$1a,$2e), - ($36,$1b,$1b,$2d), ($dc,$6e,$6e,$b2), ($b4,$5a,$5a,$ee), ($5b,$a0,$a0,$fb), - ($a4,$52,$52,$f6), ($76,$3b,$3b,$4d), ($b7,$d6,$d6,$61), ($7d,$b3,$b3,$ce), - ($52,$29,$29,$7b), ($dd,$e3,$e3,$3e), ($5e,$2f,$2f,$71), ($13,$84,$84,$97), - ($a6,$53,$53,$f5), ($b9,$d1,$d1,$68), ($00,$00,$00,$00), ($c1,$ed,$ed,$2c), - ($40,$20,$20,$60), ($e3,$fc,$fc,$1f), ($79,$b1,$b1,$c8), ($b6,$5b,$5b,$ed), - ($d4,$6a,$6a,$be), ($8d,$cb,$cb,$46), ($67,$be,$be,$d9), ($72,$39,$39,$4b), - ($94,$4a,$4a,$de), ($98,$4c,$4c,$d4), ($b0,$58,$58,$e8), ($85,$cf,$cf,$4a), - ($bb,$d0,$d0,$6b), ($c5,$ef,$ef,$2a), ($4f,$aa,$aa,$e5), ($ed,$fb,$fb,$16), - ($86,$43,$43,$c5), ($9a,$4d,$4d,$d7), ($66,$33,$33,$55), ($11,$85,$85,$94), - ($8a,$45,$45,$cf), ($e9,$f9,$f9,$10), ($04,$02,$02,$06), ($fe,$7f,$7f,$81), - ($a0,$50,$50,$f0), ($78,$3c,$3c,$44), ($25,$9f,$9f,$ba), ($4b,$a8,$a8,$e3), - ($a2,$51,$51,$f3), ($5d,$a3,$a3,$fe), ($80,$40,$40,$c0), ($05,$8f,$8f,$8a), - ($3f,$92,$92,$ad), ($21,$9d,$9d,$bc), ($70,$38,$38,$48), ($f1,$f5,$f5,$04), - ($63,$bc,$bc,$df), ($77,$b6,$b6,$c1), ($af,$da,$da,$75), ($42,$21,$21,$63), - ($20,$10,$10,$30), ($e5,$ff,$ff,$1a), ($fd,$f3,$f3,$0e), ($bf,$d2,$d2,$6d), - ($81,$cd,$cd,$4c), ($18,$0c,$0c,$14), ($26,$13,$13,$35), ($c3,$ec,$ec,$2f), - ($be,$5f,$5f,$e1), ($35,$97,$97,$a2), ($88,$44,$44,$cc), ($2e,$17,$17,$39), - ($93,$c4,$c4,$57), ($55,$a7,$a7,$f2), ($fc,$7e,$7e,$82), ($7a,$3d,$3d,$47), - ($c8,$64,$64,$ac), ($ba,$5d,$5d,$e7), ($32,$19,$19,$2b), ($e6,$73,$73,$95), - ($c0,$60,$60,$a0), ($19,$81,$81,$98), ($9e,$4f,$4f,$d1), ($a3,$dc,$dc,$7f), - ($44,$22,$22,$66), ($54,$2a,$2a,$7e), ($3b,$90,$90,$ab), ($0b,$88,$88,$83), - ($8c,$46,$46,$ca), ($c7,$ee,$ee,$29), ($6b,$b8,$b8,$d3), ($28,$14,$14,$3c), - ($a7,$de,$de,$79), ($bc,$5e,$5e,$e2), ($16,$0b,$0b,$1d), ($ad,$db,$db,$76), - ($db,$e0,$e0,$3b), ($64,$32,$32,$56), ($74,$3a,$3a,$4e), ($14,$0a,$0a,$1e), - ($92,$49,$49,$db), ($0c,$06,$06,$0a), ($48,$24,$24,$6c), ($b8,$5c,$5c,$e4), - ($9f,$c2,$c2,$5d), ($bd,$d3,$d3,$6e), ($43,$ac,$ac,$ef), ($c4,$62,$62,$a6), - ($39,$91,$91,$a8), ($31,$95,$95,$a4), ($d3,$e4,$e4,$37), ($f2,$79,$79,$8b), - ($d5,$e7,$e7,$32), ($8b,$c8,$c8,$43), ($6e,$37,$37,$59), ($da,$6d,$6d,$b7), - ($01,$8d,$8d,$8c), ($b1,$d5,$d5,$64), ($9c,$4e,$4e,$d2), ($49,$a9,$a9,$e0), - ($d8,$6c,$6c,$b4), ($ac,$56,$56,$fa), ($f3,$f4,$f4,$07), ($cf,$ea,$ea,$25), - ($ca,$65,$65,$af), ($f4,$7a,$7a,$8e), ($47,$ae,$ae,$e9), ($10,$08,$08,$18), - ($6f,$ba,$ba,$d5), ($f0,$78,$78,$88), ($4a,$25,$25,$6f), ($5c,$2e,$2e,$72), - ($38,$1c,$1c,$24), ($57,$a6,$a6,$f1), ($73,$b4,$b4,$c7), ($97,$c6,$c6,$51), - ($cb,$e8,$e8,$23), ($a1,$dd,$dd,$7c), ($e8,$74,$74,$9c), ($3e,$1f,$1f,$21), - ($96,$4b,$4b,$dd), ($61,$bd,$bd,$dc), ($0d,$8b,$8b,$86), ($0f,$8a,$8a,$85), - ($e0,$70,$70,$90), ($7c,$3e,$3e,$42), ($71,$b5,$b5,$c4), ($cc,$66,$66,$aa), - ($90,$48,$48,$d8), ($06,$03,$03,$05), ($f7,$f6,$f6,$01), ($1c,$0e,$0e,$12), - ($c2,$61,$61,$a3), ($6a,$35,$35,$5f), ($ae,$57,$57,$f9), ($69,$b9,$b9,$d0), - ($17,$86,$86,$91), ($99,$c1,$c1,$58), ($3a,$1d,$1d,$27), ($27,$9e,$9e,$b9), - ($d9,$e1,$e1,$38), ($eb,$f8,$f8,$13), ($2b,$98,$98,$b3), ($22,$11,$11,$33), - ($d2,$69,$69,$bb), ($a9,$d9,$d9,$70), ($07,$8e,$8e,$89), ($33,$94,$94,$a7), - ($2d,$9b,$9b,$b6), ($3c,$1e,$1e,$22), ($15,$87,$87,$92), ($c9,$e9,$e9,$20), - ($87,$ce,$ce,$49), ($aa,$55,$55,$ff), ($50,$28,$28,$78), ($a5,$df,$df,$7a), - ($03,$8c,$8c,$8f), ($59,$a1,$a1,$f8), ($09,$89,$89,$80), ($1a,$0d,$0d,$17), - ($65,$bf,$bf,$da), ($d7,$e6,$e6,$31), ($84,$42,$42,$c6), ($d0,$68,$68,$b8), - ($82,$41,$41,$c3), ($29,$99,$99,$b0), ($5a,$2d,$2d,$77), ($1e,$0f,$0f,$11), - ($7b,$b0,$b0,$cb), ($a8,$54,$54,$fc), ($6d,$bb,$bb,$d6), ($2c,$16,$16,$3a)); - T2: array[0..255,0..3] of byte= ( - ($a5,$c6,$63,$63), ($84,$f8,$7c,$7c), ($99,$ee,$77,$77), ($8d,$f6,$7b,$7b), - ($0d,$ff,$f2,$f2), ($bd,$d6,$6b,$6b), ($b1,$de,$6f,$6f), ($54,$91,$c5,$c5), - ($50,$60,$30,$30), ($03,$02,$01,$01), ($a9,$ce,$67,$67), ($7d,$56,$2b,$2b), - ($19,$e7,$fe,$fe), ($62,$b5,$d7,$d7), ($e6,$4d,$ab,$ab), ($9a,$ec,$76,$76), - ($45,$8f,$ca,$ca), ($9d,$1f,$82,$82), ($40,$89,$c9,$c9), ($87,$fa,$7d,$7d), - ($15,$ef,$fa,$fa), ($eb,$b2,$59,$59), ($c9,$8e,$47,$47), ($0b,$fb,$f0,$f0), - ($ec,$41,$ad,$ad), ($67,$b3,$d4,$d4), ($fd,$5f,$a2,$a2), ($ea,$45,$af,$af), - ($bf,$23,$9c,$9c), ($f7,$53,$a4,$a4), ($96,$e4,$72,$72), ($5b,$9b,$c0,$c0), - ($c2,$75,$b7,$b7), ($1c,$e1,$fd,$fd), ($ae,$3d,$93,$93), ($6a,$4c,$26,$26), - ($5a,$6c,$36,$36), ($41,$7e,$3f,$3f), ($02,$f5,$f7,$f7), ($4f,$83,$cc,$cc), - ($5c,$68,$34,$34), ($f4,$51,$a5,$a5), ($34,$d1,$e5,$e5), ($08,$f9,$f1,$f1), - ($93,$e2,$71,$71), ($73,$ab,$d8,$d8), ($53,$62,$31,$31), ($3f,$2a,$15,$15), - ($0c,$08,$04,$04), ($52,$95,$c7,$c7), ($65,$46,$23,$23), ($5e,$9d,$c3,$c3), - ($28,$30,$18,$18), ($a1,$37,$96,$96), ($0f,$0a,$05,$05), ($b5,$2f,$9a,$9a), - ($09,$0e,$07,$07), ($36,$24,$12,$12), ($9b,$1b,$80,$80), ($3d,$df,$e2,$e2), - ($26,$cd,$eb,$eb), ($69,$4e,$27,$27), ($cd,$7f,$b2,$b2), ($9f,$ea,$75,$75), - ($1b,$12,$09,$09), ($9e,$1d,$83,$83), ($74,$58,$2c,$2c), ($2e,$34,$1a,$1a), - ($2d,$36,$1b,$1b), ($b2,$dc,$6e,$6e), ($ee,$b4,$5a,$5a), ($fb,$5b,$a0,$a0), - ($f6,$a4,$52,$52), ($4d,$76,$3b,$3b), ($61,$b7,$d6,$d6), ($ce,$7d,$b3,$b3), - ($7b,$52,$29,$29), ($3e,$dd,$e3,$e3), ($71,$5e,$2f,$2f), ($97,$13,$84,$84), - ($f5,$a6,$53,$53), ($68,$b9,$d1,$d1), ($00,$00,$00,$00), ($2c,$c1,$ed,$ed), - ($60,$40,$20,$20), ($1f,$e3,$fc,$fc), ($c8,$79,$b1,$b1), ($ed,$b6,$5b,$5b), - ($be,$d4,$6a,$6a), ($46,$8d,$cb,$cb), ($d9,$67,$be,$be), ($4b,$72,$39,$39), - ($de,$94,$4a,$4a), ($d4,$98,$4c,$4c), ($e8,$b0,$58,$58), ($4a,$85,$cf,$cf), - ($6b,$bb,$d0,$d0), ($2a,$c5,$ef,$ef), ($e5,$4f,$aa,$aa), ($16,$ed,$fb,$fb), - ($c5,$86,$43,$43), ($d7,$9a,$4d,$4d), ($55,$66,$33,$33), ($94,$11,$85,$85), - ($cf,$8a,$45,$45), ($10,$e9,$f9,$f9), ($06,$04,$02,$02), ($81,$fe,$7f,$7f), - ($f0,$a0,$50,$50), ($44,$78,$3c,$3c), ($ba,$25,$9f,$9f), ($e3,$4b,$a8,$a8), - ($f3,$a2,$51,$51), ($fe,$5d,$a3,$a3), ($c0,$80,$40,$40), ($8a,$05,$8f,$8f), - ($ad,$3f,$92,$92), ($bc,$21,$9d,$9d), ($48,$70,$38,$38), ($04,$f1,$f5,$f5), - ($df,$63,$bc,$bc), ($c1,$77,$b6,$b6), ($75,$af,$da,$da), ($63,$42,$21,$21), - ($30,$20,$10,$10), ($1a,$e5,$ff,$ff), ($0e,$fd,$f3,$f3), ($6d,$bf,$d2,$d2), - ($4c,$81,$cd,$cd), ($14,$18,$0c,$0c), ($35,$26,$13,$13), ($2f,$c3,$ec,$ec), - ($e1,$be,$5f,$5f), ($a2,$35,$97,$97), ($cc,$88,$44,$44), ($39,$2e,$17,$17), - ($57,$93,$c4,$c4), ($f2,$55,$a7,$a7), ($82,$fc,$7e,$7e), ($47,$7a,$3d,$3d), - ($ac,$c8,$64,$64), ($e7,$ba,$5d,$5d), ($2b,$32,$19,$19), ($95,$e6,$73,$73), - ($a0,$c0,$60,$60), ($98,$19,$81,$81), ($d1,$9e,$4f,$4f), ($7f,$a3,$dc,$dc), - ($66,$44,$22,$22), ($7e,$54,$2a,$2a), ($ab,$3b,$90,$90), ($83,$0b,$88,$88), - ($ca,$8c,$46,$46), ($29,$c7,$ee,$ee), ($d3,$6b,$b8,$b8), ($3c,$28,$14,$14), - ($79,$a7,$de,$de), ($e2,$bc,$5e,$5e), ($1d,$16,$0b,$0b), ($76,$ad,$db,$db), - ($3b,$db,$e0,$e0), ($56,$64,$32,$32), ($4e,$74,$3a,$3a), ($1e,$14,$0a,$0a), - ($db,$92,$49,$49), ($0a,$0c,$06,$06), ($6c,$48,$24,$24), ($e4,$b8,$5c,$5c), - ($5d,$9f,$c2,$c2), ($6e,$bd,$d3,$d3), ($ef,$43,$ac,$ac), ($a6,$c4,$62,$62), - ($a8,$39,$91,$91), ($a4,$31,$95,$95), ($37,$d3,$e4,$e4), ($8b,$f2,$79,$79), - ($32,$d5,$e7,$e7), ($43,$8b,$c8,$c8), ($59,$6e,$37,$37), ($b7,$da,$6d,$6d), - ($8c,$01,$8d,$8d), ($64,$b1,$d5,$d5), ($d2,$9c,$4e,$4e), ($e0,$49,$a9,$a9), - ($b4,$d8,$6c,$6c), ($fa,$ac,$56,$56), ($07,$f3,$f4,$f4), ($25,$cf,$ea,$ea), - ($af,$ca,$65,$65), ($8e,$f4,$7a,$7a), ($e9,$47,$ae,$ae), ($18,$10,$08,$08), - ($d5,$6f,$ba,$ba), ($88,$f0,$78,$78), ($6f,$4a,$25,$25), ($72,$5c,$2e,$2e), - ($24,$38,$1c,$1c), ($f1,$57,$a6,$a6), ($c7,$73,$b4,$b4), ($51,$97,$c6,$c6), - ($23,$cb,$e8,$e8), ($7c,$a1,$dd,$dd), ($9c,$e8,$74,$74), ($21,$3e,$1f,$1f), - ($dd,$96,$4b,$4b), ($dc,$61,$bd,$bd), ($86,$0d,$8b,$8b), ($85,$0f,$8a,$8a), - ($90,$e0,$70,$70), ($42,$7c,$3e,$3e), ($c4,$71,$b5,$b5), ($aa,$cc,$66,$66), - ($d8,$90,$48,$48), ($05,$06,$03,$03), ($01,$f7,$f6,$f6), ($12,$1c,$0e,$0e), - ($a3,$c2,$61,$61), ($5f,$6a,$35,$35), ($f9,$ae,$57,$57), ($d0,$69,$b9,$b9), - ($91,$17,$86,$86), ($58,$99,$c1,$c1), ($27,$3a,$1d,$1d), ($b9,$27,$9e,$9e), - ($38,$d9,$e1,$e1), ($13,$eb,$f8,$f8), ($b3,$2b,$98,$98), ($33,$22,$11,$11), - ($bb,$d2,$69,$69), ($70,$a9,$d9,$d9), ($89,$07,$8e,$8e), ($a7,$33,$94,$94), - ($b6,$2d,$9b,$9b), ($22,$3c,$1e,$1e), ($92,$15,$87,$87), ($20,$c9,$e9,$e9), - ($49,$87,$ce,$ce), ($ff,$aa,$55,$55), ($78,$50,$28,$28), ($7a,$a5,$df,$df), - ($8f,$03,$8c,$8c), ($f8,$59,$a1,$a1), ($80,$09,$89,$89), ($17,$1a,$0d,$0d), - ($da,$65,$bf,$bf), ($31,$d7,$e6,$e6), ($c6,$84,$42,$42), ($b8,$d0,$68,$68), - ($c3,$82,$41,$41), ($b0,$29,$99,$99), ($77,$5a,$2d,$2d), ($11,$1e,$0f,$0f), - ($cb,$7b,$b0,$b0), ($fc,$a8,$54,$54), ($d6,$6d,$bb,$bb), ($3a,$2c,$16,$16)); - T3: array[0..255,0..3] of byte= ( - ($63,$a5,$c6,$63), ($7c,$84,$f8,$7c), ($77,$99,$ee,$77), ($7b,$8d,$f6,$7b), - ($f2,$0d,$ff,$f2), ($6b,$bd,$d6,$6b), ($6f,$b1,$de,$6f), ($c5,$54,$91,$c5), - ($30,$50,$60,$30), ($01,$03,$02,$01), ($67,$a9,$ce,$67), ($2b,$7d,$56,$2b), - ($fe,$19,$e7,$fe), ($d7,$62,$b5,$d7), ($ab,$e6,$4d,$ab), ($76,$9a,$ec,$76), - ($ca,$45,$8f,$ca), ($82,$9d,$1f,$82), ($c9,$40,$89,$c9), ($7d,$87,$fa,$7d), - ($fa,$15,$ef,$fa), ($59,$eb,$b2,$59), ($47,$c9,$8e,$47), ($f0,$0b,$fb,$f0), - ($ad,$ec,$41,$ad), ($d4,$67,$b3,$d4), ($a2,$fd,$5f,$a2), ($af,$ea,$45,$af), - ($9c,$bf,$23,$9c), ($a4,$f7,$53,$a4), ($72,$96,$e4,$72), ($c0,$5b,$9b,$c0), - ($b7,$c2,$75,$b7), ($fd,$1c,$e1,$fd), ($93,$ae,$3d,$93), ($26,$6a,$4c,$26), - ($36,$5a,$6c,$36), ($3f,$41,$7e,$3f), ($f7,$02,$f5,$f7), ($cc,$4f,$83,$cc), - ($34,$5c,$68,$34), ($a5,$f4,$51,$a5), ($e5,$34,$d1,$e5), ($f1,$08,$f9,$f1), - ($71,$93,$e2,$71), ($d8,$73,$ab,$d8), ($31,$53,$62,$31), ($15,$3f,$2a,$15), - ($04,$0c,$08,$04), ($c7,$52,$95,$c7), ($23,$65,$46,$23), ($c3,$5e,$9d,$c3), - ($18,$28,$30,$18), ($96,$a1,$37,$96), ($05,$0f,$0a,$05), ($9a,$b5,$2f,$9a), - ($07,$09,$0e,$07), ($12,$36,$24,$12), ($80,$9b,$1b,$80), ($e2,$3d,$df,$e2), - ($eb,$26,$cd,$eb), ($27,$69,$4e,$27), ($b2,$cd,$7f,$b2), ($75,$9f,$ea,$75), - ($09,$1b,$12,$09), ($83,$9e,$1d,$83), ($2c,$74,$58,$2c), ($1a,$2e,$34,$1a), - ($1b,$2d,$36,$1b), ($6e,$b2,$dc,$6e), ($5a,$ee,$b4,$5a), ($a0,$fb,$5b,$a0), - ($52,$f6,$a4,$52), ($3b,$4d,$76,$3b), ($d6,$61,$b7,$d6), ($b3,$ce,$7d,$b3), - ($29,$7b,$52,$29), ($e3,$3e,$dd,$e3), ($2f,$71,$5e,$2f), ($84,$97,$13,$84), - ($53,$f5,$a6,$53), ($d1,$68,$b9,$d1), ($00,$00,$00,$00), ($ed,$2c,$c1,$ed), - ($20,$60,$40,$20), ($fc,$1f,$e3,$fc), ($b1,$c8,$79,$b1), ($5b,$ed,$b6,$5b), - ($6a,$be,$d4,$6a), ($cb,$46,$8d,$cb), ($be,$d9,$67,$be), ($39,$4b,$72,$39), - ($4a,$de,$94,$4a), ($4c,$d4,$98,$4c), ($58,$e8,$b0,$58), ($cf,$4a,$85,$cf), - ($d0,$6b,$bb,$d0), ($ef,$2a,$c5,$ef), ($aa,$e5,$4f,$aa), ($fb,$16,$ed,$fb), - ($43,$c5,$86,$43), ($4d,$d7,$9a,$4d), ($33,$55,$66,$33), ($85,$94,$11,$85), - ($45,$cf,$8a,$45), ($f9,$10,$e9,$f9), ($02,$06,$04,$02), ($7f,$81,$fe,$7f), - ($50,$f0,$a0,$50), ($3c,$44,$78,$3c), ($9f,$ba,$25,$9f), ($a8,$e3,$4b,$a8), - ($51,$f3,$a2,$51), ($a3,$fe,$5d,$a3), ($40,$c0,$80,$40), ($8f,$8a,$05,$8f), - ($92,$ad,$3f,$92), ($9d,$bc,$21,$9d), ($38,$48,$70,$38), ($f5,$04,$f1,$f5), - ($bc,$df,$63,$bc), ($b6,$c1,$77,$b6), ($da,$75,$af,$da), ($21,$63,$42,$21), - ($10,$30,$20,$10), ($ff,$1a,$e5,$ff), ($f3,$0e,$fd,$f3), ($d2,$6d,$bf,$d2), - ($cd,$4c,$81,$cd), ($0c,$14,$18,$0c), ($13,$35,$26,$13), ($ec,$2f,$c3,$ec), - ($5f,$e1,$be,$5f), ($97,$a2,$35,$97), ($44,$cc,$88,$44), ($17,$39,$2e,$17), - ($c4,$57,$93,$c4), ($a7,$f2,$55,$a7), ($7e,$82,$fc,$7e), ($3d,$47,$7a,$3d), - ($64,$ac,$c8,$64), ($5d,$e7,$ba,$5d), ($19,$2b,$32,$19), ($73,$95,$e6,$73), - ($60,$a0,$c0,$60), ($81,$98,$19,$81), ($4f,$d1,$9e,$4f), ($dc,$7f,$a3,$dc), - ($22,$66,$44,$22), ($2a,$7e,$54,$2a), ($90,$ab,$3b,$90), ($88,$83,$0b,$88), - ($46,$ca,$8c,$46), ($ee,$29,$c7,$ee), ($b8,$d3,$6b,$b8), ($14,$3c,$28,$14), - ($de,$79,$a7,$de), ($5e,$e2,$bc,$5e), ($0b,$1d,$16,$0b), ($db,$76,$ad,$db), - ($e0,$3b,$db,$e0), ($32,$56,$64,$32), ($3a,$4e,$74,$3a), ($0a,$1e,$14,$0a), - ($49,$db,$92,$49), ($06,$0a,$0c,$06), ($24,$6c,$48,$24), ($5c,$e4,$b8,$5c), - ($c2,$5d,$9f,$c2), ($d3,$6e,$bd,$d3), ($ac,$ef,$43,$ac), ($62,$a6,$c4,$62), - ($91,$a8,$39,$91), ($95,$a4,$31,$95), ($e4,$37,$d3,$e4), ($79,$8b,$f2,$79), - ($e7,$32,$d5,$e7), ($c8,$43,$8b,$c8), ($37,$59,$6e,$37), ($6d,$b7,$da,$6d), - ($8d,$8c,$01,$8d), ($d5,$64,$b1,$d5), ($4e,$d2,$9c,$4e), ($a9,$e0,$49,$a9), - ($6c,$b4,$d8,$6c), ($56,$fa,$ac,$56), ($f4,$07,$f3,$f4), ($ea,$25,$cf,$ea), - ($65,$af,$ca,$65), ($7a,$8e,$f4,$7a), ($ae,$e9,$47,$ae), ($08,$18,$10,$08), - ($ba,$d5,$6f,$ba), ($78,$88,$f0,$78), ($25,$6f,$4a,$25), ($2e,$72,$5c,$2e), - ($1c,$24,$38,$1c), ($a6,$f1,$57,$a6), ($b4,$c7,$73,$b4), ($c6,$51,$97,$c6), - ($e8,$23,$cb,$e8), ($dd,$7c,$a1,$dd), ($74,$9c,$e8,$74), ($1f,$21,$3e,$1f), - ($4b,$dd,$96,$4b), ($bd,$dc,$61,$bd), ($8b,$86,$0d,$8b), ($8a,$85,$0f,$8a), - ($70,$90,$e0,$70), ($3e,$42,$7c,$3e), ($b5,$c4,$71,$b5), ($66,$aa,$cc,$66), - ($48,$d8,$90,$48), ($03,$05,$06,$03), ($f6,$01,$f7,$f6), ($0e,$12,$1c,$0e), - ($61,$a3,$c2,$61), ($35,$5f,$6a,$35), ($57,$f9,$ae,$57), ($b9,$d0,$69,$b9), - ($86,$91,$17,$86), ($c1,$58,$99,$c1), ($1d,$27,$3a,$1d), ($9e,$b9,$27,$9e), - ($e1,$38,$d9,$e1), ($f8,$13,$eb,$f8), ($98,$b3,$2b,$98), ($11,$33,$22,$11), - ($69,$bb,$d2,$69), ($d9,$70,$a9,$d9), ($8e,$89,$07,$8e), ($94,$a7,$33,$94), - ($9b,$b6,$2d,$9b), ($1e,$22,$3c,$1e), ($87,$92,$15,$87), ($e9,$20,$c9,$e9), - ($ce,$49,$87,$ce), ($55,$ff,$aa,$55), ($28,$78,$50,$28), ($df,$7a,$a5,$df), - ($8c,$8f,$03,$8c), ($a1,$f8,$59,$a1), ($89,$80,$09,$89), ($0d,$17,$1a,$0d), - ($bf,$da,$65,$bf), ($e6,$31,$d7,$e6), ($42,$c6,$84,$42), ($68,$b8,$d0,$68), - ($41,$c3,$82,$41), ($99,$b0,$29,$99), ($2d,$77,$5a,$2d), ($0f,$11,$1e,$0f), - ($b0,$cb,$7b,$b0), ($54,$fc,$a8,$54), ($bb,$d6,$6d,$bb), ($16,$3a,$2c,$16)); - T4: array[0..255,0..3] of byte= ( - ($63,$63,$a5,$c6), ($7c,$7c,$84,$f8), ($77,$77,$99,$ee), ($7b,$7b,$8d,$f6), - ($f2,$f2,$0d,$ff), ($6b,$6b,$bd,$d6), ($6f,$6f,$b1,$de), ($c5,$c5,$54,$91), - ($30,$30,$50,$60), ($01,$01,$03,$02), ($67,$67,$a9,$ce), ($2b,$2b,$7d,$56), - ($fe,$fe,$19,$e7), ($d7,$d7,$62,$b5), ($ab,$ab,$e6,$4d), ($76,$76,$9a,$ec), - ($ca,$ca,$45,$8f), ($82,$82,$9d,$1f), ($c9,$c9,$40,$89), ($7d,$7d,$87,$fa), - ($fa,$fa,$15,$ef), ($59,$59,$eb,$b2), ($47,$47,$c9,$8e), ($f0,$f0,$0b,$fb), - ($ad,$ad,$ec,$41), ($d4,$d4,$67,$b3), ($a2,$a2,$fd,$5f), ($af,$af,$ea,$45), - ($9c,$9c,$bf,$23), ($a4,$a4,$f7,$53), ($72,$72,$96,$e4), ($c0,$c0,$5b,$9b), - ($b7,$b7,$c2,$75), ($fd,$fd,$1c,$e1), ($93,$93,$ae,$3d), ($26,$26,$6a,$4c), - ($36,$36,$5a,$6c), ($3f,$3f,$41,$7e), ($f7,$f7,$02,$f5), ($cc,$cc,$4f,$83), - ($34,$34,$5c,$68), ($a5,$a5,$f4,$51), ($e5,$e5,$34,$d1), ($f1,$f1,$08,$f9), - ($71,$71,$93,$e2), ($d8,$d8,$73,$ab), ($31,$31,$53,$62), ($15,$15,$3f,$2a), - ($04,$04,$0c,$08), ($c7,$c7,$52,$95), ($23,$23,$65,$46), ($c3,$c3,$5e,$9d), - ($18,$18,$28,$30), ($96,$96,$a1,$37), ($05,$05,$0f,$0a), ($9a,$9a,$b5,$2f), - ($07,$07,$09,$0e), ($12,$12,$36,$24), ($80,$80,$9b,$1b), ($e2,$e2,$3d,$df), - ($eb,$eb,$26,$cd), ($27,$27,$69,$4e), ($b2,$b2,$cd,$7f), ($75,$75,$9f,$ea), - ($09,$09,$1b,$12), ($83,$83,$9e,$1d), ($2c,$2c,$74,$58), ($1a,$1a,$2e,$34), - ($1b,$1b,$2d,$36), ($6e,$6e,$b2,$dc), ($5a,$5a,$ee,$b4), ($a0,$a0,$fb,$5b), - ($52,$52,$f6,$a4), ($3b,$3b,$4d,$76), ($d6,$d6,$61,$b7), ($b3,$b3,$ce,$7d), - ($29,$29,$7b,$52), ($e3,$e3,$3e,$dd), ($2f,$2f,$71,$5e), ($84,$84,$97,$13), - ($53,$53,$f5,$a6), ($d1,$d1,$68,$b9), ($00,$00,$00,$00), ($ed,$ed,$2c,$c1), - ($20,$20,$60,$40), ($fc,$fc,$1f,$e3), ($b1,$b1,$c8,$79), ($5b,$5b,$ed,$b6), - ($6a,$6a,$be,$d4), ($cb,$cb,$46,$8d), ($be,$be,$d9,$67), ($39,$39,$4b,$72), - ($4a,$4a,$de,$94), ($4c,$4c,$d4,$98), ($58,$58,$e8,$b0), ($cf,$cf,$4a,$85), - ($d0,$d0,$6b,$bb), ($ef,$ef,$2a,$c5), ($aa,$aa,$e5,$4f), ($fb,$fb,$16,$ed), - ($43,$43,$c5,$86), ($4d,$4d,$d7,$9a), ($33,$33,$55,$66), ($85,$85,$94,$11), - ($45,$45,$cf,$8a), ($f9,$f9,$10,$e9), ($02,$02,$06,$04), ($7f,$7f,$81,$fe), - ($50,$50,$f0,$a0), ($3c,$3c,$44,$78), ($9f,$9f,$ba,$25), ($a8,$a8,$e3,$4b), - ($51,$51,$f3,$a2), ($a3,$a3,$fe,$5d), ($40,$40,$c0,$80), ($8f,$8f,$8a,$05), - ($92,$92,$ad,$3f), ($9d,$9d,$bc,$21), ($38,$38,$48,$70), ($f5,$f5,$04,$f1), - ($bc,$bc,$df,$63), ($b6,$b6,$c1,$77), ($da,$da,$75,$af), ($21,$21,$63,$42), - ($10,$10,$30,$20), ($ff,$ff,$1a,$e5), ($f3,$f3,$0e,$fd), ($d2,$d2,$6d,$bf), - ($cd,$cd,$4c,$81), ($0c,$0c,$14,$18), ($13,$13,$35,$26), ($ec,$ec,$2f,$c3), - ($5f,$5f,$e1,$be), ($97,$97,$a2,$35), ($44,$44,$cc,$88), ($17,$17,$39,$2e), - ($c4,$c4,$57,$93), ($a7,$a7,$f2,$55), ($7e,$7e,$82,$fc), ($3d,$3d,$47,$7a), - ($64,$64,$ac,$c8), ($5d,$5d,$e7,$ba), ($19,$19,$2b,$32), ($73,$73,$95,$e6), - ($60,$60,$a0,$c0), ($81,$81,$98,$19), ($4f,$4f,$d1,$9e), ($dc,$dc,$7f,$a3), - ($22,$22,$66,$44), ($2a,$2a,$7e,$54), ($90,$90,$ab,$3b), ($88,$88,$83,$0b), - ($46,$46,$ca,$8c), ($ee,$ee,$29,$c7), ($b8,$b8,$d3,$6b), ($14,$14,$3c,$28), - ($de,$de,$79,$a7), ($5e,$5e,$e2,$bc), ($0b,$0b,$1d,$16), ($db,$db,$76,$ad), - ($e0,$e0,$3b,$db), ($32,$32,$56,$64), ($3a,$3a,$4e,$74), ($0a,$0a,$1e,$14), - ($49,$49,$db,$92), ($06,$06,$0a,$0c), ($24,$24,$6c,$48), ($5c,$5c,$e4,$b8), - ($c2,$c2,$5d,$9f), ($d3,$d3,$6e,$bd), ($ac,$ac,$ef,$43), ($62,$62,$a6,$c4), - ($91,$91,$a8,$39), ($95,$95,$a4,$31), ($e4,$e4,$37,$d3), ($79,$79,$8b,$f2), - ($e7,$e7,$32,$d5), ($c8,$c8,$43,$8b), ($37,$37,$59,$6e), ($6d,$6d,$b7,$da), - ($8d,$8d,$8c,$01), ($d5,$d5,$64,$b1), ($4e,$4e,$d2,$9c), ($a9,$a9,$e0,$49), - ($6c,$6c,$b4,$d8), ($56,$56,$fa,$ac), ($f4,$f4,$07,$f3), ($ea,$ea,$25,$cf), - ($65,$65,$af,$ca), ($7a,$7a,$8e,$f4), ($ae,$ae,$e9,$47), ($08,$08,$18,$10), - ($ba,$ba,$d5,$6f), ($78,$78,$88,$f0), ($25,$25,$6f,$4a), ($2e,$2e,$72,$5c), - ($1c,$1c,$24,$38), ($a6,$a6,$f1,$57), ($b4,$b4,$c7,$73), ($c6,$c6,$51,$97), - ($e8,$e8,$23,$cb), ($dd,$dd,$7c,$a1), ($74,$74,$9c,$e8), ($1f,$1f,$21,$3e), - ($4b,$4b,$dd,$96), ($bd,$bd,$dc,$61), ($8b,$8b,$86,$0d), ($8a,$8a,$85,$0f), - ($70,$70,$90,$e0), ($3e,$3e,$42,$7c), ($b5,$b5,$c4,$71), ($66,$66,$aa,$cc), - ($48,$48,$d8,$90), ($03,$03,$05,$06), ($f6,$f6,$01,$f7), ($0e,$0e,$12,$1c), - ($61,$61,$a3,$c2), ($35,$35,$5f,$6a), ($57,$57,$f9,$ae), ($b9,$b9,$d0,$69), - ($86,$86,$91,$17), ($c1,$c1,$58,$99), ($1d,$1d,$27,$3a), ($9e,$9e,$b9,$27), - ($e1,$e1,$38,$d9), ($f8,$f8,$13,$eb), ($98,$98,$b3,$2b), ($11,$11,$33,$22), - ($69,$69,$bb,$d2), ($d9,$d9,$70,$a9), ($8e,$8e,$89,$07), ($94,$94,$a7,$33), - ($9b,$9b,$b6,$2d), ($1e,$1e,$22,$3c), ($87,$87,$92,$15), ($e9,$e9,$20,$c9), - ($ce,$ce,$49,$87), ($55,$55,$ff,$aa), ($28,$28,$78,$50), ($df,$df,$7a,$a5), - ($8c,$8c,$8f,$03), ($a1,$a1,$f8,$59), ($89,$89,$80,$09), ($0d,$0d,$17,$1a), - ($bf,$bf,$da,$65), ($e6,$e6,$31,$d7), ($42,$42,$c6,$84), ($68,$68,$b8,$d0), - ($41,$41,$c3,$82), ($99,$99,$b0,$29), ($2d,$2d,$77,$5a), ($0f,$0f,$11,$1e), - ($b0,$b0,$cb,$7b), ($54,$54,$fc,$a8), ($bb,$bb,$d6,$6d), ($16,$16,$3a,$2c)); - T5: array[0..255,0..3] of byte= ( - ($51,$f4,$a7,$50), ($7e,$41,$65,$53), ($1a,$17,$a4,$c3), ($3a,$27,$5e,$96), - ($3b,$ab,$6b,$cb), ($1f,$9d,$45,$f1), ($ac,$fa,$58,$ab), ($4b,$e3,$03,$93), - ($20,$30,$fa,$55), ($ad,$76,$6d,$f6), ($88,$cc,$76,$91), ($f5,$02,$4c,$25), - ($4f,$e5,$d7,$fc), ($c5,$2a,$cb,$d7), ($26,$35,$44,$80), ($b5,$62,$a3,$8f), - ($de,$b1,$5a,$49), ($25,$ba,$1b,$67), ($45,$ea,$0e,$98), ($5d,$fe,$c0,$e1), - ($c3,$2f,$75,$02), ($81,$4c,$f0,$12), ($8d,$46,$97,$a3), ($6b,$d3,$f9,$c6), - ($03,$8f,$5f,$e7), ($15,$92,$9c,$95), ($bf,$6d,$7a,$eb), ($95,$52,$59,$da), - ($d4,$be,$83,$2d), ($58,$74,$21,$d3), ($49,$e0,$69,$29), ($8e,$c9,$c8,$44), - ($75,$c2,$89,$6a), ($f4,$8e,$79,$78), ($99,$58,$3e,$6b), ($27,$b9,$71,$dd), - ($be,$e1,$4f,$b6), ($f0,$88,$ad,$17), ($c9,$20,$ac,$66), ($7d,$ce,$3a,$b4), - ($63,$df,$4a,$18), ($e5,$1a,$31,$82), ($97,$51,$33,$60), ($62,$53,$7f,$45), - ($b1,$64,$77,$e0), ($bb,$6b,$ae,$84), ($fe,$81,$a0,$1c), ($f9,$08,$2b,$94), - ($70,$48,$68,$58), ($8f,$45,$fd,$19), ($94,$de,$6c,$87), ($52,$7b,$f8,$b7), - ($ab,$73,$d3,$23), ($72,$4b,$02,$e2), ($e3,$1f,$8f,$57), ($66,$55,$ab,$2a), - ($b2,$eb,$28,$07), ($2f,$b5,$c2,$03), ($86,$c5,$7b,$9a), ($d3,$37,$08,$a5), - ($30,$28,$87,$f2), ($23,$bf,$a5,$b2), ($02,$03,$6a,$ba), ($ed,$16,$82,$5c), - ($8a,$cf,$1c,$2b), ($a7,$79,$b4,$92), ($f3,$07,$f2,$f0), ($4e,$69,$e2,$a1), - ($65,$da,$f4,$cd), ($06,$05,$be,$d5), ($d1,$34,$62,$1f), ($c4,$a6,$fe,$8a), - ($34,$2e,$53,$9d), ($a2,$f3,$55,$a0), ($05,$8a,$e1,$32), ($a4,$f6,$eb,$75), - ($0b,$83,$ec,$39), ($40,$60,$ef,$aa), ($5e,$71,$9f,$06), ($bd,$6e,$10,$51), - ($3e,$21,$8a,$f9), ($96,$dd,$06,$3d), ($dd,$3e,$05,$ae), ($4d,$e6,$bd,$46), - ($91,$54,$8d,$b5), ($71,$c4,$5d,$05), ($04,$06,$d4,$6f), ($60,$50,$15,$ff), - ($19,$98,$fb,$24), ($d6,$bd,$e9,$97), ($89,$40,$43,$cc), ($67,$d9,$9e,$77), - ($b0,$e8,$42,$bd), ($07,$89,$8b,$88), ($e7,$19,$5b,$38), ($79,$c8,$ee,$db), - ($a1,$7c,$0a,$47), ($7c,$42,$0f,$e9), ($f8,$84,$1e,$c9), ($00,$00,$00,$00), - ($09,$80,$86,$83), ($32,$2b,$ed,$48), ($1e,$11,$70,$ac), ($6c,$5a,$72,$4e), - ($fd,$0e,$ff,$fb), ($0f,$85,$38,$56), ($3d,$ae,$d5,$1e), ($36,$2d,$39,$27), - ($0a,$0f,$d9,$64), ($68,$5c,$a6,$21), ($9b,$5b,$54,$d1), ($24,$36,$2e,$3a), - ($0c,$0a,$67,$b1), ($93,$57,$e7,$0f), ($b4,$ee,$96,$d2), ($1b,$9b,$91,$9e), - ($80,$c0,$c5,$4f), ($61,$dc,$20,$a2), ($5a,$77,$4b,$69), ($1c,$12,$1a,$16), - ($e2,$93,$ba,$0a), ($c0,$a0,$2a,$e5), ($3c,$22,$e0,$43), ($12,$1b,$17,$1d), - ($0e,$09,$0d,$0b), ($f2,$8b,$c7,$ad), ($2d,$b6,$a8,$b9), ($14,$1e,$a9,$c8), - ($57,$f1,$19,$85), ($af,$75,$07,$4c), ($ee,$99,$dd,$bb), ($a3,$7f,$60,$fd), - ($f7,$01,$26,$9f), ($5c,$72,$f5,$bc), ($44,$66,$3b,$c5), ($5b,$fb,$7e,$34), - ($8b,$43,$29,$76), ($cb,$23,$c6,$dc), ($b6,$ed,$fc,$68), ($b8,$e4,$f1,$63), - ($d7,$31,$dc,$ca), ($42,$63,$85,$10), ($13,$97,$22,$40), ($84,$c6,$11,$20), - ($85,$4a,$24,$7d), ($d2,$bb,$3d,$f8), ($ae,$f9,$32,$11), ($c7,$29,$a1,$6d), - ($1d,$9e,$2f,$4b), ($dc,$b2,$30,$f3), ($0d,$86,$52,$ec), ($77,$c1,$e3,$d0), - ($2b,$b3,$16,$6c), ($a9,$70,$b9,$99), ($11,$94,$48,$fa), ($47,$e9,$64,$22), - ($a8,$fc,$8c,$c4), ($a0,$f0,$3f,$1a), ($56,$7d,$2c,$d8), ($22,$33,$90,$ef), - ($87,$49,$4e,$c7), ($d9,$38,$d1,$c1), ($8c,$ca,$a2,$fe), ($98,$d4,$0b,$36), - ($a6,$f5,$81,$cf), ($a5,$7a,$de,$28), ($da,$b7,$8e,$26), ($3f,$ad,$bf,$a4), - ($2c,$3a,$9d,$e4), ($50,$78,$92,$0d), ($6a,$5f,$cc,$9b), ($54,$7e,$46,$62), - ($f6,$8d,$13,$c2), ($90,$d8,$b8,$e8), ($2e,$39,$f7,$5e), ($82,$c3,$af,$f5), - ($9f,$5d,$80,$be), ($69,$d0,$93,$7c), ($6f,$d5,$2d,$a9), ($cf,$25,$12,$b3), - ($c8,$ac,$99,$3b), ($10,$18,$7d,$a7), ($e8,$9c,$63,$6e), ($db,$3b,$bb,$7b), - ($cd,$26,$78,$09), ($6e,$59,$18,$f4), ($ec,$9a,$b7,$01), ($83,$4f,$9a,$a8), - ($e6,$95,$6e,$65), ($aa,$ff,$e6,$7e), ($21,$bc,$cf,$08), ($ef,$15,$e8,$e6), - ($ba,$e7,$9b,$d9), ($4a,$6f,$36,$ce), ($ea,$9f,$09,$d4), ($29,$b0,$7c,$d6), - ($31,$a4,$b2,$af), ($2a,$3f,$23,$31), ($c6,$a5,$94,$30), ($35,$a2,$66,$c0), - ($74,$4e,$bc,$37), ($fc,$82,$ca,$a6), ($e0,$90,$d0,$b0), ($33,$a7,$d8,$15), - ($f1,$04,$98,$4a), ($41,$ec,$da,$f7), ($7f,$cd,$50,$0e), ($17,$91,$f6,$2f), - ($76,$4d,$d6,$8d), ($43,$ef,$b0,$4d), ($cc,$aa,$4d,$54), ($e4,$96,$04,$df), - ($9e,$d1,$b5,$e3), ($4c,$6a,$88,$1b), ($c1,$2c,$1f,$b8), ($46,$65,$51,$7f), - ($9d,$5e,$ea,$04), ($01,$8c,$35,$5d), ($fa,$87,$74,$73), ($fb,$0b,$41,$2e), - ($b3,$67,$1d,$5a), ($92,$db,$d2,$52), ($e9,$10,$56,$33), ($6d,$d6,$47,$13), - ($9a,$d7,$61,$8c), ($37,$a1,$0c,$7a), ($59,$f8,$14,$8e), ($eb,$13,$3c,$89), - ($ce,$a9,$27,$ee), ($b7,$61,$c9,$35), ($e1,$1c,$e5,$ed), ($7a,$47,$b1,$3c), - ($9c,$d2,$df,$59), ($55,$f2,$73,$3f), ($18,$14,$ce,$79), ($73,$c7,$37,$bf), - ($53,$f7,$cd,$ea), ($5f,$fd,$aa,$5b), ($df,$3d,$6f,$14), ($78,$44,$db,$86), - ($ca,$af,$f3,$81), ($b9,$68,$c4,$3e), ($38,$24,$34,$2c), ($c2,$a3,$40,$5f), - ($16,$1d,$c3,$72), ($bc,$e2,$25,$0c), ($28,$3c,$49,$8b), ($ff,$0d,$95,$41), - ($39,$a8,$01,$71), ($08,$0c,$b3,$de), ($d8,$b4,$e4,$9c), ($64,$56,$c1,$90), - ($7b,$cb,$84,$61), ($d5,$32,$b6,$70), ($48,$6c,$5c,$74), ($d0,$b8,$57,$42)); - T6: array[0..255,0..3] of byte= ( - ($50,$51,$f4,$a7), ($53,$7e,$41,$65), ($c3,$1a,$17,$a4), ($96,$3a,$27,$5e), - ($cb,$3b,$ab,$6b), ($f1,$1f,$9d,$45), ($ab,$ac,$fa,$58), ($93,$4b,$e3,$03), - ($55,$20,$30,$fa), ($f6,$ad,$76,$6d), ($91,$88,$cc,$76), ($25,$f5,$02,$4c), - ($fc,$4f,$e5,$d7), ($d7,$c5,$2a,$cb), ($80,$26,$35,$44), ($8f,$b5,$62,$a3), - ($49,$de,$b1,$5a), ($67,$25,$ba,$1b), ($98,$45,$ea,$0e), ($e1,$5d,$fe,$c0), - ($02,$c3,$2f,$75), ($12,$81,$4c,$f0), ($a3,$8d,$46,$97), ($c6,$6b,$d3,$f9), - ($e7,$03,$8f,$5f), ($95,$15,$92,$9c), ($eb,$bf,$6d,$7a), ($da,$95,$52,$59), - ($2d,$d4,$be,$83), ($d3,$58,$74,$21), ($29,$49,$e0,$69), ($44,$8e,$c9,$c8), - ($6a,$75,$c2,$89), ($78,$f4,$8e,$79), ($6b,$99,$58,$3e), ($dd,$27,$b9,$71), - ($b6,$be,$e1,$4f), ($17,$f0,$88,$ad), ($66,$c9,$20,$ac), ($b4,$7d,$ce,$3a), - ($18,$63,$df,$4a), ($82,$e5,$1a,$31), ($60,$97,$51,$33), ($45,$62,$53,$7f), - ($e0,$b1,$64,$77), ($84,$bb,$6b,$ae), ($1c,$fe,$81,$a0), ($94,$f9,$08,$2b), - ($58,$70,$48,$68), ($19,$8f,$45,$fd), ($87,$94,$de,$6c), ($b7,$52,$7b,$f8), - ($23,$ab,$73,$d3), ($e2,$72,$4b,$02), ($57,$e3,$1f,$8f), ($2a,$66,$55,$ab), - ($07,$b2,$eb,$28), ($03,$2f,$b5,$c2), ($9a,$86,$c5,$7b), ($a5,$d3,$37,$08), - ($f2,$30,$28,$87), ($b2,$23,$bf,$a5), ($ba,$02,$03,$6a), ($5c,$ed,$16,$82), - ($2b,$8a,$cf,$1c), ($92,$a7,$79,$b4), ($f0,$f3,$07,$f2), ($a1,$4e,$69,$e2), - ($cd,$65,$da,$f4), ($d5,$06,$05,$be), ($1f,$d1,$34,$62), ($8a,$c4,$a6,$fe), - ($9d,$34,$2e,$53), ($a0,$a2,$f3,$55), ($32,$05,$8a,$e1), ($75,$a4,$f6,$eb), - ($39,$0b,$83,$ec), ($aa,$40,$60,$ef), ($06,$5e,$71,$9f), ($51,$bd,$6e,$10), - ($f9,$3e,$21,$8a), ($3d,$96,$dd,$06), ($ae,$dd,$3e,$05), ($46,$4d,$e6,$bd), - ($b5,$91,$54,$8d), ($05,$71,$c4,$5d), ($6f,$04,$06,$d4), ($ff,$60,$50,$15), - ($24,$19,$98,$fb), ($97,$d6,$bd,$e9), ($cc,$89,$40,$43), ($77,$67,$d9,$9e), - ($bd,$b0,$e8,$42), ($88,$07,$89,$8b), ($38,$e7,$19,$5b), ($db,$79,$c8,$ee), - ($47,$a1,$7c,$0a), ($e9,$7c,$42,$0f), ($c9,$f8,$84,$1e), ($00,$00,$00,$00), - ($83,$09,$80,$86), ($48,$32,$2b,$ed), ($ac,$1e,$11,$70), ($4e,$6c,$5a,$72), - ($fb,$fd,$0e,$ff), ($56,$0f,$85,$38), ($1e,$3d,$ae,$d5), ($27,$36,$2d,$39), - ($64,$0a,$0f,$d9), ($21,$68,$5c,$a6), ($d1,$9b,$5b,$54), ($3a,$24,$36,$2e), - ($b1,$0c,$0a,$67), ($0f,$93,$57,$e7), ($d2,$b4,$ee,$96), ($9e,$1b,$9b,$91), - ($4f,$80,$c0,$c5), ($a2,$61,$dc,$20), ($69,$5a,$77,$4b), ($16,$1c,$12,$1a), - ($0a,$e2,$93,$ba), ($e5,$c0,$a0,$2a), ($43,$3c,$22,$e0), ($1d,$12,$1b,$17), - ($0b,$0e,$09,$0d), ($ad,$f2,$8b,$c7), ($b9,$2d,$b6,$a8), ($c8,$14,$1e,$a9), - ($85,$57,$f1,$19), ($4c,$af,$75,$07), ($bb,$ee,$99,$dd), ($fd,$a3,$7f,$60), - ($9f,$f7,$01,$26), ($bc,$5c,$72,$f5), ($c5,$44,$66,$3b), ($34,$5b,$fb,$7e), - ($76,$8b,$43,$29), ($dc,$cb,$23,$c6), ($68,$b6,$ed,$fc), ($63,$b8,$e4,$f1), - ($ca,$d7,$31,$dc), ($10,$42,$63,$85), ($40,$13,$97,$22), ($20,$84,$c6,$11), - ($7d,$85,$4a,$24), ($f8,$d2,$bb,$3d), ($11,$ae,$f9,$32), ($6d,$c7,$29,$a1), - ($4b,$1d,$9e,$2f), ($f3,$dc,$b2,$30), ($ec,$0d,$86,$52), ($d0,$77,$c1,$e3), - ($6c,$2b,$b3,$16), ($99,$a9,$70,$b9), ($fa,$11,$94,$48), ($22,$47,$e9,$64), - ($c4,$a8,$fc,$8c), ($1a,$a0,$f0,$3f), ($d8,$56,$7d,$2c), ($ef,$22,$33,$90), - ($c7,$87,$49,$4e), ($c1,$d9,$38,$d1), ($fe,$8c,$ca,$a2), ($36,$98,$d4,$0b), - ($cf,$a6,$f5,$81), ($28,$a5,$7a,$de), ($26,$da,$b7,$8e), ($a4,$3f,$ad,$bf), - ($e4,$2c,$3a,$9d), ($0d,$50,$78,$92), ($9b,$6a,$5f,$cc), ($62,$54,$7e,$46), - ($c2,$f6,$8d,$13), ($e8,$90,$d8,$b8), ($5e,$2e,$39,$f7), ($f5,$82,$c3,$af), - ($be,$9f,$5d,$80), ($7c,$69,$d0,$93), ($a9,$6f,$d5,$2d), ($b3,$cf,$25,$12), - ($3b,$c8,$ac,$99), ($a7,$10,$18,$7d), ($6e,$e8,$9c,$63), ($7b,$db,$3b,$bb), - ($09,$cd,$26,$78), ($f4,$6e,$59,$18), ($01,$ec,$9a,$b7), ($a8,$83,$4f,$9a), - ($65,$e6,$95,$6e), ($7e,$aa,$ff,$e6), ($08,$21,$bc,$cf), ($e6,$ef,$15,$e8), - ($d9,$ba,$e7,$9b), ($ce,$4a,$6f,$36), ($d4,$ea,$9f,$09), ($d6,$29,$b0,$7c), - ($af,$31,$a4,$b2), ($31,$2a,$3f,$23), ($30,$c6,$a5,$94), ($c0,$35,$a2,$66), - ($37,$74,$4e,$bc), ($a6,$fc,$82,$ca), ($b0,$e0,$90,$d0), ($15,$33,$a7,$d8), - ($4a,$f1,$04,$98), ($f7,$41,$ec,$da), ($0e,$7f,$cd,$50), ($2f,$17,$91,$f6), - ($8d,$76,$4d,$d6), ($4d,$43,$ef,$b0), ($54,$cc,$aa,$4d), ($df,$e4,$96,$04), - ($e3,$9e,$d1,$b5), ($1b,$4c,$6a,$88), ($b8,$c1,$2c,$1f), ($7f,$46,$65,$51), - ($04,$9d,$5e,$ea), ($5d,$01,$8c,$35), ($73,$fa,$87,$74), ($2e,$fb,$0b,$41), - ($5a,$b3,$67,$1d), ($52,$92,$db,$d2), ($33,$e9,$10,$56), ($13,$6d,$d6,$47), - ($8c,$9a,$d7,$61), ($7a,$37,$a1,$0c), ($8e,$59,$f8,$14), ($89,$eb,$13,$3c), - ($ee,$ce,$a9,$27), ($35,$b7,$61,$c9), ($ed,$e1,$1c,$e5), ($3c,$7a,$47,$b1), - ($59,$9c,$d2,$df), ($3f,$55,$f2,$73), ($79,$18,$14,$ce), ($bf,$73,$c7,$37), - ($ea,$53,$f7,$cd), ($5b,$5f,$fd,$aa), ($14,$df,$3d,$6f), ($86,$78,$44,$db), - ($81,$ca,$af,$f3), ($3e,$b9,$68,$c4), ($2c,$38,$24,$34), ($5f,$c2,$a3,$40), - ($72,$16,$1d,$c3), ($0c,$bc,$e2,$25), ($8b,$28,$3c,$49), ($41,$ff,$0d,$95), - ($71,$39,$a8,$01), ($de,$08,$0c,$b3), ($9c,$d8,$b4,$e4), ($90,$64,$56,$c1), - ($61,$7b,$cb,$84), ($70,$d5,$32,$b6), ($74,$48,$6c,$5c), ($42,$d0,$b8,$57)); - T7: array[0..255,0..3] of byte= ( - ($a7,$50,$51,$f4), ($65,$53,$7e,$41), ($a4,$c3,$1a,$17), ($5e,$96,$3a,$27), - ($6b,$cb,$3b,$ab), ($45,$f1,$1f,$9d), ($58,$ab,$ac,$fa), ($03,$93,$4b,$e3), - ($fa,$55,$20,$30), ($6d,$f6,$ad,$76), ($76,$91,$88,$cc), ($4c,$25,$f5,$02), - ($d7,$fc,$4f,$e5), ($cb,$d7,$c5,$2a), ($44,$80,$26,$35), ($a3,$8f,$b5,$62), - ($5a,$49,$de,$b1), ($1b,$67,$25,$ba), ($0e,$98,$45,$ea), ($c0,$e1,$5d,$fe), - ($75,$02,$c3,$2f), ($f0,$12,$81,$4c), ($97,$a3,$8d,$46), ($f9,$c6,$6b,$d3), - ($5f,$e7,$03,$8f), ($9c,$95,$15,$92), ($7a,$eb,$bf,$6d), ($59,$da,$95,$52), - ($83,$2d,$d4,$be), ($21,$d3,$58,$74), ($69,$29,$49,$e0), ($c8,$44,$8e,$c9), - ($89,$6a,$75,$c2), ($79,$78,$f4,$8e), ($3e,$6b,$99,$58), ($71,$dd,$27,$b9), - ($4f,$b6,$be,$e1), ($ad,$17,$f0,$88), ($ac,$66,$c9,$20), ($3a,$b4,$7d,$ce), - ($4a,$18,$63,$df), ($31,$82,$e5,$1a), ($33,$60,$97,$51), ($7f,$45,$62,$53), - ($77,$e0,$b1,$64), ($ae,$84,$bb,$6b), ($a0,$1c,$fe,$81), ($2b,$94,$f9,$08), - ($68,$58,$70,$48), ($fd,$19,$8f,$45), ($6c,$87,$94,$de), ($f8,$b7,$52,$7b), - ($d3,$23,$ab,$73), ($02,$e2,$72,$4b), ($8f,$57,$e3,$1f), ($ab,$2a,$66,$55), - ($28,$07,$b2,$eb), ($c2,$03,$2f,$b5), ($7b,$9a,$86,$c5), ($08,$a5,$d3,$37), - ($87,$f2,$30,$28), ($a5,$b2,$23,$bf), ($6a,$ba,$02,$03), ($82,$5c,$ed,$16), - ($1c,$2b,$8a,$cf), ($b4,$92,$a7,$79), ($f2,$f0,$f3,$07), ($e2,$a1,$4e,$69), - ($f4,$cd,$65,$da), ($be,$d5,$06,$05), ($62,$1f,$d1,$34), ($fe,$8a,$c4,$a6), - ($53,$9d,$34,$2e), ($55,$a0,$a2,$f3), ($e1,$32,$05,$8a), ($eb,$75,$a4,$f6), - ($ec,$39,$0b,$83), ($ef,$aa,$40,$60), ($9f,$06,$5e,$71), ($10,$51,$bd,$6e), - ($8a,$f9,$3e,$21), ($06,$3d,$96,$dd), ($05,$ae,$dd,$3e), ($bd,$46,$4d,$e6), - ($8d,$b5,$91,$54), ($5d,$05,$71,$c4), ($d4,$6f,$04,$06), ($15,$ff,$60,$50), - ($fb,$24,$19,$98), ($e9,$97,$d6,$bd), ($43,$cc,$89,$40), ($9e,$77,$67,$d9), - ($42,$bd,$b0,$e8), ($8b,$88,$07,$89), ($5b,$38,$e7,$19), ($ee,$db,$79,$c8), - ($0a,$47,$a1,$7c), ($0f,$e9,$7c,$42), ($1e,$c9,$f8,$84), ($00,$00,$00,$00), - ($86,$83,$09,$80), ($ed,$48,$32,$2b), ($70,$ac,$1e,$11), ($72,$4e,$6c,$5a), - ($ff,$fb,$fd,$0e), ($38,$56,$0f,$85), ($d5,$1e,$3d,$ae), ($39,$27,$36,$2d), - ($d9,$64,$0a,$0f), ($a6,$21,$68,$5c), ($54,$d1,$9b,$5b), ($2e,$3a,$24,$36), - ($67,$b1,$0c,$0a), ($e7,$0f,$93,$57), ($96,$d2,$b4,$ee), ($91,$9e,$1b,$9b), - ($c5,$4f,$80,$c0), ($20,$a2,$61,$dc), ($4b,$69,$5a,$77), ($1a,$16,$1c,$12), - ($ba,$0a,$e2,$93), ($2a,$e5,$c0,$a0), ($e0,$43,$3c,$22), ($17,$1d,$12,$1b), - ($0d,$0b,$0e,$09), ($c7,$ad,$f2,$8b), ($a8,$b9,$2d,$b6), ($a9,$c8,$14,$1e), - ($19,$85,$57,$f1), ($07,$4c,$af,$75), ($dd,$bb,$ee,$99), ($60,$fd,$a3,$7f), - ($26,$9f,$f7,$01), ($f5,$bc,$5c,$72), ($3b,$c5,$44,$66), ($7e,$34,$5b,$fb), - ($29,$76,$8b,$43), ($c6,$dc,$cb,$23), ($fc,$68,$b6,$ed), ($f1,$63,$b8,$e4), - ($dc,$ca,$d7,$31), ($85,$10,$42,$63), ($22,$40,$13,$97), ($11,$20,$84,$c6), - ($24,$7d,$85,$4a), ($3d,$f8,$d2,$bb), ($32,$11,$ae,$f9), ($a1,$6d,$c7,$29), - ($2f,$4b,$1d,$9e), ($30,$f3,$dc,$b2), ($52,$ec,$0d,$86), ($e3,$d0,$77,$c1), - ($16,$6c,$2b,$b3), ($b9,$99,$a9,$70), ($48,$fa,$11,$94), ($64,$22,$47,$e9), - ($8c,$c4,$a8,$fc), ($3f,$1a,$a0,$f0), ($2c,$d8,$56,$7d), ($90,$ef,$22,$33), - ($4e,$c7,$87,$49), ($d1,$c1,$d9,$38), ($a2,$fe,$8c,$ca), ($0b,$36,$98,$d4), - ($81,$cf,$a6,$f5), ($de,$28,$a5,$7a), ($8e,$26,$da,$b7), ($bf,$a4,$3f,$ad), - ($9d,$e4,$2c,$3a), ($92,$0d,$50,$78), ($cc,$9b,$6a,$5f), ($46,$62,$54,$7e), - ($13,$c2,$f6,$8d), ($b8,$e8,$90,$d8), ($f7,$5e,$2e,$39), ($af,$f5,$82,$c3), - ($80,$be,$9f,$5d), ($93,$7c,$69,$d0), ($2d,$a9,$6f,$d5), ($12,$b3,$cf,$25), - ($99,$3b,$c8,$ac), ($7d,$a7,$10,$18), ($63,$6e,$e8,$9c), ($bb,$7b,$db,$3b), - ($78,$09,$cd,$26), ($18,$f4,$6e,$59), ($b7,$01,$ec,$9a), ($9a,$a8,$83,$4f), - ($6e,$65,$e6,$95), ($e6,$7e,$aa,$ff), ($cf,$08,$21,$bc), ($e8,$e6,$ef,$15), - ($9b,$d9,$ba,$e7), ($36,$ce,$4a,$6f), ($09,$d4,$ea,$9f), ($7c,$d6,$29,$b0), - ($b2,$af,$31,$a4), ($23,$31,$2a,$3f), ($94,$30,$c6,$a5), ($66,$c0,$35,$a2), - ($bc,$37,$74,$4e), ($ca,$a6,$fc,$82), ($d0,$b0,$e0,$90), ($d8,$15,$33,$a7), - ($98,$4a,$f1,$04), ($da,$f7,$41,$ec), ($50,$0e,$7f,$cd), ($f6,$2f,$17,$91), - ($d6,$8d,$76,$4d), ($b0,$4d,$43,$ef), ($4d,$54,$cc,$aa), ($04,$df,$e4,$96), - ($b5,$e3,$9e,$d1), ($88,$1b,$4c,$6a), ($1f,$b8,$c1,$2c), ($51,$7f,$46,$65), - ($ea,$04,$9d,$5e), ($35,$5d,$01,$8c), ($74,$73,$fa,$87), ($41,$2e,$fb,$0b), - ($1d,$5a,$b3,$67), ($d2,$52,$92,$db), ($56,$33,$e9,$10), ($47,$13,$6d,$d6), - ($61,$8c,$9a,$d7), ($0c,$7a,$37,$a1), ($14,$8e,$59,$f8), ($3c,$89,$eb,$13), - ($27,$ee,$ce,$a9), ($c9,$35,$b7,$61), ($e5,$ed,$e1,$1c), ($b1,$3c,$7a,$47), - ($df,$59,$9c,$d2), ($73,$3f,$55,$f2), ($ce,$79,$18,$14), ($37,$bf,$73,$c7), - ($cd,$ea,$53,$f7), ($aa,$5b,$5f,$fd), ($6f,$14,$df,$3d), ($db,$86,$78,$44), - ($f3,$81,$ca,$af), ($c4,$3e,$b9,$68), ($34,$2c,$38,$24), ($40,$5f,$c2,$a3), - ($c3,$72,$16,$1d), ($25,$0c,$bc,$e2), ($49,$8b,$28,$3c), ($95,$41,$ff,$0d), - ($01,$71,$39,$a8), ($b3,$de,$08,$0c), ($e4,$9c,$d8,$b4), ($c1,$90,$64,$56), - ($84,$61,$7b,$cb), ($b6,$70,$d5,$32), ($5c,$74,$48,$6c), ($57,$42,$d0,$b8)); - T8: array[0..255,0..3] of byte= ( - ($f4,$a7,$50,$51), ($41,$65,$53,$7e), ($17,$a4,$c3,$1a), ($27,$5e,$96,$3a), - ($ab,$6b,$cb,$3b), ($9d,$45,$f1,$1f), ($fa,$58,$ab,$ac), ($e3,$03,$93,$4b), - ($30,$fa,$55,$20), ($76,$6d,$f6,$ad), ($cc,$76,$91,$88), ($02,$4c,$25,$f5), - ($e5,$d7,$fc,$4f), ($2a,$cb,$d7,$c5), ($35,$44,$80,$26), ($62,$a3,$8f,$b5), - ($b1,$5a,$49,$de), ($ba,$1b,$67,$25), ($ea,$0e,$98,$45), ($fe,$c0,$e1,$5d), - ($2f,$75,$02,$c3), ($4c,$f0,$12,$81), ($46,$97,$a3,$8d), ($d3,$f9,$c6,$6b), - ($8f,$5f,$e7,$03), ($92,$9c,$95,$15), ($6d,$7a,$eb,$bf), ($52,$59,$da,$95), - ($be,$83,$2d,$d4), ($74,$21,$d3,$58), ($e0,$69,$29,$49), ($c9,$c8,$44,$8e), - ($c2,$89,$6a,$75), ($8e,$79,$78,$f4), ($58,$3e,$6b,$99), ($b9,$71,$dd,$27), - ($e1,$4f,$b6,$be), ($88,$ad,$17,$f0), ($20,$ac,$66,$c9), ($ce,$3a,$b4,$7d), - ($df,$4a,$18,$63), ($1a,$31,$82,$e5), ($51,$33,$60,$97), ($53,$7f,$45,$62), - ($64,$77,$e0,$b1), ($6b,$ae,$84,$bb), ($81,$a0,$1c,$fe), ($08,$2b,$94,$f9), - ($48,$68,$58,$70), ($45,$fd,$19,$8f), ($de,$6c,$87,$94), ($7b,$f8,$b7,$52), - ($73,$d3,$23,$ab), ($4b,$02,$e2,$72), ($1f,$8f,$57,$e3), ($55,$ab,$2a,$66), - ($eb,$28,$07,$b2), ($b5,$c2,$03,$2f), ($c5,$7b,$9a,$86), ($37,$08,$a5,$d3), - ($28,$87,$f2,$30), ($bf,$a5,$b2,$23), ($03,$6a,$ba,$02), ($16,$82,$5c,$ed), - ($cf,$1c,$2b,$8a), ($79,$b4,$92,$a7), ($07,$f2,$f0,$f3), ($69,$e2,$a1,$4e), - ($da,$f4,$cd,$65), ($05,$be,$d5,$06), ($34,$62,$1f,$d1), ($a6,$fe,$8a,$c4), - ($2e,$53,$9d,$34), ($f3,$55,$a0,$a2), ($8a,$e1,$32,$05), ($f6,$eb,$75,$a4), - ($83,$ec,$39,$0b), ($60,$ef,$aa,$40), ($71,$9f,$06,$5e), ($6e,$10,$51,$bd), - ($21,$8a,$f9,$3e), ($dd,$06,$3d,$96), ($3e,$05,$ae,$dd), ($e6,$bd,$46,$4d), - ($54,$8d,$b5,$91), ($c4,$5d,$05,$71), ($06,$d4,$6f,$04), ($50,$15,$ff,$60), - ($98,$fb,$24,$19), ($bd,$e9,$97,$d6), ($40,$43,$cc,$89), ($d9,$9e,$77,$67), - ($e8,$42,$bd,$b0), ($89,$8b,$88,$07), ($19,$5b,$38,$e7), ($c8,$ee,$db,$79), - ($7c,$0a,$47,$a1), ($42,$0f,$e9,$7c), ($84,$1e,$c9,$f8), ($00,$00,$00,$00), - ($80,$86,$83,$09), ($2b,$ed,$48,$32), ($11,$70,$ac,$1e), ($5a,$72,$4e,$6c), - ($0e,$ff,$fb,$fd), ($85,$38,$56,$0f), ($ae,$d5,$1e,$3d), ($2d,$39,$27,$36), - ($0f,$d9,$64,$0a), ($5c,$a6,$21,$68), ($5b,$54,$d1,$9b), ($36,$2e,$3a,$24), - ($0a,$67,$b1,$0c), ($57,$e7,$0f,$93), ($ee,$96,$d2,$b4), ($9b,$91,$9e,$1b), - ($c0,$c5,$4f,$80), ($dc,$20,$a2,$61), ($77,$4b,$69,$5a), ($12,$1a,$16,$1c), - ($93,$ba,$0a,$e2), ($a0,$2a,$e5,$c0), ($22,$e0,$43,$3c), ($1b,$17,$1d,$12), - ($09,$0d,$0b,$0e), ($8b,$c7,$ad,$f2), ($b6,$a8,$b9,$2d), ($1e,$a9,$c8,$14), - ($f1,$19,$85,$57), ($75,$07,$4c,$af), ($99,$dd,$bb,$ee), ($7f,$60,$fd,$a3), - ($01,$26,$9f,$f7), ($72,$f5,$bc,$5c), ($66,$3b,$c5,$44), ($fb,$7e,$34,$5b), - ($43,$29,$76,$8b), ($23,$c6,$dc,$cb), ($ed,$fc,$68,$b6), ($e4,$f1,$63,$b8), - ($31,$dc,$ca,$d7), ($63,$85,$10,$42), ($97,$22,$40,$13), ($c6,$11,$20,$84), - ($4a,$24,$7d,$85), ($bb,$3d,$f8,$d2), ($f9,$32,$11,$ae), ($29,$a1,$6d,$c7), - ($9e,$2f,$4b,$1d), ($b2,$30,$f3,$dc), ($86,$52,$ec,$0d), ($c1,$e3,$d0,$77), - ($b3,$16,$6c,$2b), ($70,$b9,$99,$a9), ($94,$48,$fa,$11), ($e9,$64,$22,$47), - ($fc,$8c,$c4,$a8), ($f0,$3f,$1a,$a0), ($7d,$2c,$d8,$56), ($33,$90,$ef,$22), - ($49,$4e,$c7,$87), ($38,$d1,$c1,$d9), ($ca,$a2,$fe,$8c), ($d4,$0b,$36,$98), - ($f5,$81,$cf,$a6), ($7a,$de,$28,$a5), ($b7,$8e,$26,$da), ($ad,$bf,$a4,$3f), - ($3a,$9d,$e4,$2c), ($78,$92,$0d,$50), ($5f,$cc,$9b,$6a), ($7e,$46,$62,$54), - ($8d,$13,$c2,$f6), ($d8,$b8,$e8,$90), ($39,$f7,$5e,$2e), ($c3,$af,$f5,$82), - ($5d,$80,$be,$9f), ($d0,$93,$7c,$69), ($d5,$2d,$a9,$6f), ($25,$12,$b3,$cf), - ($ac,$99,$3b,$c8), ($18,$7d,$a7,$10), ($9c,$63,$6e,$e8), ($3b,$bb,$7b,$db), - ($26,$78,$09,$cd), ($59,$18,$f4,$6e), ($9a,$b7,$01,$ec), ($4f,$9a,$a8,$83), - ($95,$6e,$65,$e6), ($ff,$e6,$7e,$aa), ($bc,$cf,$08,$21), ($15,$e8,$e6,$ef), - ($e7,$9b,$d9,$ba), ($6f,$36,$ce,$4a), ($9f,$09,$d4,$ea), ($b0,$7c,$d6,$29), - ($a4,$b2,$af,$31), ($3f,$23,$31,$2a), ($a5,$94,$30,$c6), ($a2,$66,$c0,$35), - ($4e,$bc,$37,$74), ($82,$ca,$a6,$fc), ($90,$d0,$b0,$e0), ($a7,$d8,$15,$33), - ($04,$98,$4a,$f1), ($ec,$da,$f7,$41), ($cd,$50,$0e,$7f), ($91,$f6,$2f,$17), - ($4d,$d6,$8d,$76), ($ef,$b0,$4d,$43), ($aa,$4d,$54,$cc), ($96,$04,$df,$e4), - ($d1,$b5,$e3,$9e), ($6a,$88,$1b,$4c), ($2c,$1f,$b8,$c1), ($65,$51,$7f,$46), - ($5e,$ea,$04,$9d), ($8c,$35,$5d,$01), ($87,$74,$73,$fa), ($0b,$41,$2e,$fb), - ($67,$1d,$5a,$b3), ($db,$d2,$52,$92), ($10,$56,$33,$e9), ($d6,$47,$13,$6d), - ($d7,$61,$8c,$9a), ($a1,$0c,$7a,$37), ($f8,$14,$8e,$59), ($13,$3c,$89,$eb), - ($a9,$27,$ee,$ce), ($61,$c9,$35,$b7), ($1c,$e5,$ed,$e1), ($47,$b1,$3c,$7a), - ($d2,$df,$59,$9c), ($f2,$73,$3f,$55), ($14,$ce,$79,$18), ($c7,$37,$bf,$73), - ($f7,$cd,$ea,$53), ($fd,$aa,$5b,$5f), ($3d,$6f,$14,$df), ($44,$db,$86,$78), - ($af,$f3,$81,$ca), ($68,$c4,$3e,$b9), ($24,$34,$2c,$38), ($a3,$40,$5f,$c2), - ($1d,$c3,$72,$16), ($e2,$25,$0c,$bc), ($3c,$49,$8b,$28), ($0d,$95,$41,$ff), - ($a8,$01,$71,$39), ($0c,$b3,$de,$08), ($b4,$e4,$9c,$d8), ($56,$c1,$90,$64), - ($cb,$84,$61,$7b), ($32,$b6,$70,$d5), ($6c,$5c,$74,$48), ($b8,$57,$42,$d0)); - S5: array[0..255] of byte= ( - $52,$09,$6a,$d5, - $30,$36,$a5,$38, - $bf,$40,$a3,$9e, - $81,$f3,$d7,$fb, - $7c,$e3,$39,$82, - $9b,$2f,$ff,$87, - $34,$8e,$43,$44, - $c4,$de,$e9,$cb, - $54,$7b,$94,$32, - $a6,$c2,$23,$3d, - $ee,$4c,$95,$0b, - $42,$fa,$c3,$4e, - $08,$2e,$a1,$66, - $28,$d9,$24,$b2, - $76,$5b,$a2,$49, - $6d,$8b,$d1,$25, - $72,$f8,$f6,$64, - $86,$68,$98,$16, - $d4,$a4,$5c,$cc, - $5d,$65,$b6,$92, - $6c,$70,$48,$50, - $fd,$ed,$b9,$da, - $5e,$15,$46,$57, - $a7,$8d,$9d,$84, - $90,$d8,$ab,$00, - $8c,$bc,$d3,$0a, - $f7,$e4,$58,$05, - $b8,$b3,$45,$06, - $d0,$2c,$1e,$8f, - $ca,$3f,$0f,$02, - $c1,$af,$bd,$03, - $01,$13,$8a,$6b, - $3a,$91,$11,$41, - $4f,$67,$dc,$ea, - $97,$f2,$cf,$ce, - $f0,$b4,$e6,$73, - $96,$ac,$74,$22, - $e7,$ad,$35,$85, - $e2,$f9,$37,$e8, - $1c,$75,$df,$6e, - $47,$f1,$1a,$71, - $1d,$29,$c5,$89, - $6f,$b7,$62,$0e, - $aa,$18,$be,$1b, - $fc,$56,$3e,$4b, - $c6,$d2,$79,$20, - $9a,$db,$c0,$fe, - $78,$cd,$5a,$f4, - $1f,$dd,$a8,$33, - $88,$07,$c7,$31, - $b1,$12,$10,$59, - $27,$80,$ec,$5f, - $60,$51,$7f,$a9, - $19,$b5,$4a,$0d, - $2d,$e5,$7a,$9f, - $93,$c9,$9c,$ef, - $a0,$e0,$3b,$4d, - $ae,$2a,$f5,$b0, - $c8,$eb,$bb,$3c, - $83,$53,$99,$61, - $17,$2b,$04,$7e, - $ba,$77,$d6,$26, - $e1,$69,$14,$63, - $55,$21,$0c,$7d); - U1: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($0e,$09,$0d,$0b), ($1c,$12,$1a,$16), ($12,$1b,$17,$1d), - ($38,$24,$34,$2c), ($36,$2d,$39,$27), ($24,$36,$2e,$3a), ($2a,$3f,$23,$31), - ($70,$48,$68,$58), ($7e,$41,$65,$53), ($6c,$5a,$72,$4e), ($62,$53,$7f,$45), - ($48,$6c,$5c,$74), ($46,$65,$51,$7f), ($54,$7e,$46,$62), ($5a,$77,$4b,$69), - ($e0,$90,$d0,$b0), ($ee,$99,$dd,$bb), ($fc,$82,$ca,$a6), ($f2,$8b,$c7,$ad), - ($d8,$b4,$e4,$9c), ($d6,$bd,$e9,$97), ($c4,$a6,$fe,$8a), ($ca,$af,$f3,$81), - ($90,$d8,$b8,$e8), ($9e,$d1,$b5,$e3), ($8c,$ca,$a2,$fe), ($82,$c3,$af,$f5), - ($a8,$fc,$8c,$c4), ($a6,$f5,$81,$cf), ($b4,$ee,$96,$d2), ($ba,$e7,$9b,$d9), - ($db,$3b,$bb,$7b), ($d5,$32,$b6,$70), ($c7,$29,$a1,$6d), ($c9,$20,$ac,$66), - ($e3,$1f,$8f,$57), ($ed,$16,$82,$5c), ($ff,$0d,$95,$41), ($f1,$04,$98,$4a), - ($ab,$73,$d3,$23), ($a5,$7a,$de,$28), ($b7,$61,$c9,$35), ($b9,$68,$c4,$3e), - ($93,$57,$e7,$0f), ($9d,$5e,$ea,$04), ($8f,$45,$fd,$19), ($81,$4c,$f0,$12), - ($3b,$ab,$6b,$cb), ($35,$a2,$66,$c0), ($27,$b9,$71,$dd), ($29,$b0,$7c,$d6), - ($03,$8f,$5f,$e7), ($0d,$86,$52,$ec), ($1f,$9d,$45,$f1), ($11,$94,$48,$fa), - ($4b,$e3,$03,$93), ($45,$ea,$0e,$98), ($57,$f1,$19,$85), ($59,$f8,$14,$8e), - ($73,$c7,$37,$bf), ($7d,$ce,$3a,$b4), ($6f,$d5,$2d,$a9), ($61,$dc,$20,$a2), - ($ad,$76,$6d,$f6), ($a3,$7f,$60,$fd), ($b1,$64,$77,$e0), ($bf,$6d,$7a,$eb), - ($95,$52,$59,$da), ($9b,$5b,$54,$d1), ($89,$40,$43,$cc), ($87,$49,$4e,$c7), - ($dd,$3e,$05,$ae), ($d3,$37,$08,$a5), ($c1,$2c,$1f,$b8), ($cf,$25,$12,$b3), - ($e5,$1a,$31,$82), ($eb,$13,$3c,$89), ($f9,$08,$2b,$94), ($f7,$01,$26,$9f), - ($4d,$e6,$bd,$46), ($43,$ef,$b0,$4d), ($51,$f4,$a7,$50), ($5f,$fd,$aa,$5b), - ($75,$c2,$89,$6a), ($7b,$cb,$84,$61), ($69,$d0,$93,$7c), ($67,$d9,$9e,$77), - ($3d,$ae,$d5,$1e), ($33,$a7,$d8,$15), ($21,$bc,$cf,$08), ($2f,$b5,$c2,$03), - ($05,$8a,$e1,$32), ($0b,$83,$ec,$39), ($19,$98,$fb,$24), ($17,$91,$f6,$2f), - ($76,$4d,$d6,$8d), ($78,$44,$db,$86), ($6a,$5f,$cc,$9b), ($64,$56,$c1,$90), - ($4e,$69,$e2,$a1), ($40,$60,$ef,$aa), ($52,$7b,$f8,$b7), ($5c,$72,$f5,$bc), - ($06,$05,$be,$d5), ($08,$0c,$b3,$de), ($1a,$17,$a4,$c3), ($14,$1e,$a9,$c8), - ($3e,$21,$8a,$f9), ($30,$28,$87,$f2), ($22,$33,$90,$ef), ($2c,$3a,$9d,$e4), - ($96,$dd,$06,$3d), ($98,$d4,$0b,$36), ($8a,$cf,$1c,$2b), ($84,$c6,$11,$20), - ($ae,$f9,$32,$11), ($a0,$f0,$3f,$1a), ($b2,$eb,$28,$07), ($bc,$e2,$25,$0c), - ($e6,$95,$6e,$65), ($e8,$9c,$63,$6e), ($fa,$87,$74,$73), ($f4,$8e,$79,$78), - ($de,$b1,$5a,$49), ($d0,$b8,$57,$42), ($c2,$a3,$40,$5f), ($cc,$aa,$4d,$54), - ($41,$ec,$da,$f7), ($4f,$e5,$d7,$fc), ($5d,$fe,$c0,$e1), ($53,$f7,$cd,$ea), - ($79,$c8,$ee,$db), ($77,$c1,$e3,$d0), ($65,$da,$f4,$cd), ($6b,$d3,$f9,$c6), - ($31,$a4,$b2,$af), ($3f,$ad,$bf,$a4), ($2d,$b6,$a8,$b9), ($23,$bf,$a5,$b2), - ($09,$80,$86,$83), ($07,$89,$8b,$88), ($15,$92,$9c,$95), ($1b,$9b,$91,$9e), - ($a1,$7c,$0a,$47), ($af,$75,$07,$4c), ($bd,$6e,$10,$51), ($b3,$67,$1d,$5a), - ($99,$58,$3e,$6b), ($97,$51,$33,$60), ($85,$4a,$24,$7d), ($8b,$43,$29,$76), - ($d1,$34,$62,$1f), ($df,$3d,$6f,$14), ($cd,$26,$78,$09), ($c3,$2f,$75,$02), - ($e9,$10,$56,$33), ($e7,$19,$5b,$38), ($f5,$02,$4c,$25), ($fb,$0b,$41,$2e), - ($9a,$d7,$61,$8c), ($94,$de,$6c,$87), ($86,$c5,$7b,$9a), ($88,$cc,$76,$91), - ($a2,$f3,$55,$a0), ($ac,$fa,$58,$ab), ($be,$e1,$4f,$b6), ($b0,$e8,$42,$bd), - ($ea,$9f,$09,$d4), ($e4,$96,$04,$df), ($f6,$8d,$13,$c2), ($f8,$84,$1e,$c9), - ($d2,$bb,$3d,$f8), ($dc,$b2,$30,$f3), ($ce,$a9,$27,$ee), ($c0,$a0,$2a,$e5), - ($7a,$47,$b1,$3c), ($74,$4e,$bc,$37), ($66,$55,$ab,$2a), ($68,$5c,$a6,$21), - ($42,$63,$85,$10), ($4c,$6a,$88,$1b), ($5e,$71,$9f,$06), ($50,$78,$92,$0d), - ($0a,$0f,$d9,$64), ($04,$06,$d4,$6f), ($16,$1d,$c3,$72), ($18,$14,$ce,$79), - ($32,$2b,$ed,$48), ($3c,$22,$e0,$43), ($2e,$39,$f7,$5e), ($20,$30,$fa,$55), - ($ec,$9a,$b7,$01), ($e2,$93,$ba,$0a), ($f0,$88,$ad,$17), ($fe,$81,$a0,$1c), - ($d4,$be,$83,$2d), ($da,$b7,$8e,$26), ($c8,$ac,$99,$3b), ($c6,$a5,$94,$30), - ($9c,$d2,$df,$59), ($92,$db,$d2,$52), ($80,$c0,$c5,$4f), ($8e,$c9,$c8,$44), - ($a4,$f6,$eb,$75), ($aa,$ff,$e6,$7e), ($b8,$e4,$f1,$63), ($b6,$ed,$fc,$68), - ($0c,$0a,$67,$b1), ($02,$03,$6a,$ba), ($10,$18,$7d,$a7), ($1e,$11,$70,$ac), - ($34,$2e,$53,$9d), ($3a,$27,$5e,$96), ($28,$3c,$49,$8b), ($26,$35,$44,$80), - ($7c,$42,$0f,$e9), ($72,$4b,$02,$e2), ($60,$50,$15,$ff), ($6e,$59,$18,$f4), - ($44,$66,$3b,$c5), ($4a,$6f,$36,$ce), ($58,$74,$21,$d3), ($56,$7d,$2c,$d8), - ($37,$a1,$0c,$7a), ($39,$a8,$01,$71), ($2b,$b3,$16,$6c), ($25,$ba,$1b,$67), - ($0f,$85,$38,$56), ($01,$8c,$35,$5d), ($13,$97,$22,$40), ($1d,$9e,$2f,$4b), - ($47,$e9,$64,$22), ($49,$e0,$69,$29), ($5b,$fb,$7e,$34), ($55,$f2,$73,$3f), - ($7f,$cd,$50,$0e), ($71,$c4,$5d,$05), ($63,$df,$4a,$18), ($6d,$d6,$47,$13), - ($d7,$31,$dc,$ca), ($d9,$38,$d1,$c1), ($cb,$23,$c6,$dc), ($c5,$2a,$cb,$d7), - ($ef,$15,$e8,$e6), ($e1,$1c,$e5,$ed), ($f3,$07,$f2,$f0), ($fd,$0e,$ff,$fb), - ($a7,$79,$b4,$92), ($a9,$70,$b9,$99), ($bb,$6b,$ae,$84), ($b5,$62,$a3,$8f), - ($9f,$5d,$80,$be), ($91,$54,$8d,$b5), ($83,$4f,$9a,$a8), ($8d,$46,$97,$a3)); - U2: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($0b,$0e,$09,$0d), ($16,$1c,$12,$1a), ($1d,$12,$1b,$17), - ($2c,$38,$24,$34), ($27,$36,$2d,$39), ($3a,$24,$36,$2e), ($31,$2a,$3f,$23), - ($58,$70,$48,$68), ($53,$7e,$41,$65), ($4e,$6c,$5a,$72), ($45,$62,$53,$7f), - ($74,$48,$6c,$5c), ($7f,$46,$65,$51), ($62,$54,$7e,$46), ($69,$5a,$77,$4b), - ($b0,$e0,$90,$d0), ($bb,$ee,$99,$dd), ($a6,$fc,$82,$ca), ($ad,$f2,$8b,$c7), - ($9c,$d8,$b4,$e4), ($97,$d6,$bd,$e9), ($8a,$c4,$a6,$fe), ($81,$ca,$af,$f3), - ($e8,$90,$d8,$b8), ($e3,$9e,$d1,$b5), ($fe,$8c,$ca,$a2), ($f5,$82,$c3,$af), - ($c4,$a8,$fc,$8c), ($cf,$a6,$f5,$81), ($d2,$b4,$ee,$96), ($d9,$ba,$e7,$9b), - ($7b,$db,$3b,$bb), ($70,$d5,$32,$b6), ($6d,$c7,$29,$a1), ($66,$c9,$20,$ac), - ($57,$e3,$1f,$8f), ($5c,$ed,$16,$82), ($41,$ff,$0d,$95), ($4a,$f1,$04,$98), - ($23,$ab,$73,$d3), ($28,$a5,$7a,$de), ($35,$b7,$61,$c9), ($3e,$b9,$68,$c4), - ($0f,$93,$57,$e7), ($04,$9d,$5e,$ea), ($19,$8f,$45,$fd), ($12,$81,$4c,$f0), - ($cb,$3b,$ab,$6b), ($c0,$35,$a2,$66), ($dd,$27,$b9,$71), ($d6,$29,$b0,$7c), - ($e7,$03,$8f,$5f), ($ec,$0d,$86,$52), ($f1,$1f,$9d,$45), ($fa,$11,$94,$48), - ($93,$4b,$e3,$03), ($98,$45,$ea,$0e), ($85,$57,$f1,$19), ($8e,$59,$f8,$14), - ($bf,$73,$c7,$37), ($b4,$7d,$ce,$3a), ($a9,$6f,$d5,$2d), ($a2,$61,$dc,$20), - ($f6,$ad,$76,$6d), ($fd,$a3,$7f,$60), ($e0,$b1,$64,$77), ($eb,$bf,$6d,$7a), - ($da,$95,$52,$59), ($d1,$9b,$5b,$54), ($cc,$89,$40,$43), ($c7,$87,$49,$4e), - ($ae,$dd,$3e,$05), ($a5,$d3,$37,$08), ($b8,$c1,$2c,$1f), ($b3,$cf,$25,$12), - ($82,$e5,$1a,$31), ($89,$eb,$13,$3c), ($94,$f9,$08,$2b), ($9f,$f7,$01,$26), - ($46,$4d,$e6,$bd), ($4d,$43,$ef,$b0), ($50,$51,$f4,$a7), ($5b,$5f,$fd,$aa), - ($6a,$75,$c2,$89), ($61,$7b,$cb,$84), ($7c,$69,$d0,$93), ($77,$67,$d9,$9e), - ($1e,$3d,$ae,$d5), ($15,$33,$a7,$d8), ($08,$21,$bc,$cf), ($03,$2f,$b5,$c2), - ($32,$05,$8a,$e1), ($39,$0b,$83,$ec), ($24,$19,$98,$fb), ($2f,$17,$91,$f6), - ($8d,$76,$4d,$d6), ($86,$78,$44,$db), ($9b,$6a,$5f,$cc), ($90,$64,$56,$c1), - ($a1,$4e,$69,$e2), ($aa,$40,$60,$ef), ($b7,$52,$7b,$f8), ($bc,$5c,$72,$f5), - ($d5,$06,$05,$be), ($de,$08,$0c,$b3), ($c3,$1a,$17,$a4), ($c8,$14,$1e,$a9), - ($f9,$3e,$21,$8a), ($f2,$30,$28,$87), ($ef,$22,$33,$90), ($e4,$2c,$3a,$9d), - ($3d,$96,$dd,$06), ($36,$98,$d4,$0b), ($2b,$8a,$cf,$1c), ($20,$84,$c6,$11), - ($11,$ae,$f9,$32), ($1a,$a0,$f0,$3f), ($07,$b2,$eb,$28), ($0c,$bc,$e2,$25), - ($65,$e6,$95,$6e), ($6e,$e8,$9c,$63), ($73,$fa,$87,$74), ($78,$f4,$8e,$79), - ($49,$de,$b1,$5a), ($42,$d0,$b8,$57), ($5f,$c2,$a3,$40), ($54,$cc,$aa,$4d), - ($f7,$41,$ec,$da), ($fc,$4f,$e5,$d7), ($e1,$5d,$fe,$c0), ($ea,$53,$f7,$cd), - ($db,$79,$c8,$ee), ($d0,$77,$c1,$e3), ($cd,$65,$da,$f4), ($c6,$6b,$d3,$f9), - ($af,$31,$a4,$b2), ($a4,$3f,$ad,$bf), ($b9,$2d,$b6,$a8), ($b2,$23,$bf,$a5), - ($83,$09,$80,$86), ($88,$07,$89,$8b), ($95,$15,$92,$9c), ($9e,$1b,$9b,$91), - ($47,$a1,$7c,$0a), ($4c,$af,$75,$07), ($51,$bd,$6e,$10), ($5a,$b3,$67,$1d), - ($6b,$99,$58,$3e), ($60,$97,$51,$33), ($7d,$85,$4a,$24), ($76,$8b,$43,$29), - ($1f,$d1,$34,$62), ($14,$df,$3d,$6f), ($09,$cd,$26,$78), ($02,$c3,$2f,$75), - ($33,$e9,$10,$56), ($38,$e7,$19,$5b), ($25,$f5,$02,$4c), ($2e,$fb,$0b,$41), - ($8c,$9a,$d7,$61), ($87,$94,$de,$6c), ($9a,$86,$c5,$7b), ($91,$88,$cc,$76), - ($a0,$a2,$f3,$55), ($ab,$ac,$fa,$58), ($b6,$be,$e1,$4f), ($bd,$b0,$e8,$42), - ($d4,$ea,$9f,$09), ($df,$e4,$96,$04), ($c2,$f6,$8d,$13), ($c9,$f8,$84,$1e), - ($f8,$d2,$bb,$3d), ($f3,$dc,$b2,$30), ($ee,$ce,$a9,$27), ($e5,$c0,$a0,$2a), - ($3c,$7a,$47,$b1), ($37,$74,$4e,$bc), ($2a,$66,$55,$ab), ($21,$68,$5c,$a6), - ($10,$42,$63,$85), ($1b,$4c,$6a,$88), ($06,$5e,$71,$9f), ($0d,$50,$78,$92), - ($64,$0a,$0f,$d9), ($6f,$04,$06,$d4), ($72,$16,$1d,$c3), ($79,$18,$14,$ce), - ($48,$32,$2b,$ed), ($43,$3c,$22,$e0), ($5e,$2e,$39,$f7), ($55,$20,$30,$fa), - ($01,$ec,$9a,$b7), ($0a,$e2,$93,$ba), ($17,$f0,$88,$ad), ($1c,$fe,$81,$a0), - ($2d,$d4,$be,$83), ($26,$da,$b7,$8e), ($3b,$c8,$ac,$99), ($30,$c6,$a5,$94), - ($59,$9c,$d2,$df), ($52,$92,$db,$d2), ($4f,$80,$c0,$c5), ($44,$8e,$c9,$c8), - ($75,$a4,$f6,$eb), ($7e,$aa,$ff,$e6), ($63,$b8,$e4,$f1), ($68,$b6,$ed,$fc), - ($b1,$0c,$0a,$67), ($ba,$02,$03,$6a), ($a7,$10,$18,$7d), ($ac,$1e,$11,$70), - ($9d,$34,$2e,$53), ($96,$3a,$27,$5e), ($8b,$28,$3c,$49), ($80,$26,$35,$44), - ($e9,$7c,$42,$0f), ($e2,$72,$4b,$02), ($ff,$60,$50,$15), ($f4,$6e,$59,$18), - ($c5,$44,$66,$3b), ($ce,$4a,$6f,$36), ($d3,$58,$74,$21), ($d8,$56,$7d,$2c), - ($7a,$37,$a1,$0c), ($71,$39,$a8,$01), ($6c,$2b,$b3,$16), ($67,$25,$ba,$1b), - ($56,$0f,$85,$38), ($5d,$01,$8c,$35), ($40,$13,$97,$22), ($4b,$1d,$9e,$2f), - ($22,$47,$e9,$64), ($29,$49,$e0,$69), ($34,$5b,$fb,$7e), ($3f,$55,$f2,$73), - ($0e,$7f,$cd,$50), ($05,$71,$c4,$5d), ($18,$63,$df,$4a), ($13,$6d,$d6,$47), - ($ca,$d7,$31,$dc), ($c1,$d9,$38,$d1), ($dc,$cb,$23,$c6), ($d7,$c5,$2a,$cb), - ($e6,$ef,$15,$e8), ($ed,$e1,$1c,$e5), ($f0,$f3,$07,$f2), ($fb,$fd,$0e,$ff), - ($92,$a7,$79,$b4), ($99,$a9,$70,$b9), ($84,$bb,$6b,$ae), ($8f,$b5,$62,$a3), - ($be,$9f,$5d,$80), ($b5,$91,$54,$8d), ($a8,$83,$4f,$9a), ($a3,$8d,$46,$97)); - U3: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($0d,$0b,$0e,$09), ($1a,$16,$1c,$12), ($17,$1d,$12,$1b), - ($34,$2c,$38,$24), ($39,$27,$36,$2d), ($2e,$3a,$24,$36), ($23,$31,$2a,$3f), - ($68,$58,$70,$48), ($65,$53,$7e,$41), ($72,$4e,$6c,$5a), ($7f,$45,$62,$53), - ($5c,$74,$48,$6c), ($51,$7f,$46,$65), ($46,$62,$54,$7e), ($4b,$69,$5a,$77), - ($d0,$b0,$e0,$90), ($dd,$bb,$ee,$99), ($ca,$a6,$fc,$82), ($c7,$ad,$f2,$8b), - ($e4,$9c,$d8,$b4), ($e9,$97,$d6,$bd), ($fe,$8a,$c4,$a6), ($f3,$81,$ca,$af), - ($b8,$e8,$90,$d8), ($b5,$e3,$9e,$d1), ($a2,$fe,$8c,$ca), ($af,$f5,$82,$c3), - ($8c,$c4,$a8,$fc), ($81,$cf,$a6,$f5), ($96,$d2,$b4,$ee), ($9b,$d9,$ba,$e7), - ($bb,$7b,$db,$3b), ($b6,$70,$d5,$32), ($a1,$6d,$c7,$29), ($ac,$66,$c9,$20), - ($8f,$57,$e3,$1f), ($82,$5c,$ed,$16), ($95,$41,$ff,$0d), ($98,$4a,$f1,$04), - ($d3,$23,$ab,$73), ($de,$28,$a5,$7a), ($c9,$35,$b7,$61), ($c4,$3e,$b9,$68), - ($e7,$0f,$93,$57), ($ea,$04,$9d,$5e), ($fd,$19,$8f,$45), ($f0,$12,$81,$4c), - ($6b,$cb,$3b,$ab), ($66,$c0,$35,$a2), ($71,$dd,$27,$b9), ($7c,$d6,$29,$b0), - ($5f,$e7,$03,$8f), ($52,$ec,$0d,$86), ($45,$f1,$1f,$9d), ($48,$fa,$11,$94), - ($03,$93,$4b,$e3), ($0e,$98,$45,$ea), ($19,$85,$57,$f1), ($14,$8e,$59,$f8), - ($37,$bf,$73,$c7), ($3a,$b4,$7d,$ce), ($2d,$a9,$6f,$d5), ($20,$a2,$61,$dc), - ($6d,$f6,$ad,$76), ($60,$fd,$a3,$7f), ($77,$e0,$b1,$64), ($7a,$eb,$bf,$6d), - ($59,$da,$95,$52), ($54,$d1,$9b,$5b), ($43,$cc,$89,$40), ($4e,$c7,$87,$49), - ($05,$ae,$dd,$3e), ($08,$a5,$d3,$37), ($1f,$b8,$c1,$2c), ($12,$b3,$cf,$25), - ($31,$82,$e5,$1a), ($3c,$89,$eb,$13), ($2b,$94,$f9,$08), ($26,$9f,$f7,$01), - ($bd,$46,$4d,$e6), ($b0,$4d,$43,$ef), ($a7,$50,$51,$f4), ($aa,$5b,$5f,$fd), - ($89,$6a,$75,$c2), ($84,$61,$7b,$cb), ($93,$7c,$69,$d0), ($9e,$77,$67,$d9), - ($d5,$1e,$3d,$ae), ($d8,$15,$33,$a7), ($cf,$08,$21,$bc), ($c2,$03,$2f,$b5), - ($e1,$32,$05,$8a), ($ec,$39,$0b,$83), ($fb,$24,$19,$98), ($f6,$2f,$17,$91), - ($d6,$8d,$76,$4d), ($db,$86,$78,$44), ($cc,$9b,$6a,$5f), ($c1,$90,$64,$56), - ($e2,$a1,$4e,$69), ($ef,$aa,$40,$60), ($f8,$b7,$52,$7b), ($f5,$bc,$5c,$72), - ($be,$d5,$06,$05), ($b3,$de,$08,$0c), ($a4,$c3,$1a,$17), ($a9,$c8,$14,$1e), - ($8a,$f9,$3e,$21), ($87,$f2,$30,$28), ($90,$ef,$22,$33), ($9d,$e4,$2c,$3a), - ($06,$3d,$96,$dd), ($0b,$36,$98,$d4), ($1c,$2b,$8a,$cf), ($11,$20,$84,$c6), - ($32,$11,$ae,$f9), ($3f,$1a,$a0,$f0), ($28,$07,$b2,$eb), ($25,$0c,$bc,$e2), - ($6e,$65,$e6,$95), ($63,$6e,$e8,$9c), ($74,$73,$fa,$87), ($79,$78,$f4,$8e), - ($5a,$49,$de,$b1), ($57,$42,$d0,$b8), ($40,$5f,$c2,$a3), ($4d,$54,$cc,$aa), - ($da,$f7,$41,$ec), ($d7,$fc,$4f,$e5), ($c0,$e1,$5d,$fe), ($cd,$ea,$53,$f7), - ($ee,$db,$79,$c8), ($e3,$d0,$77,$c1), ($f4,$cd,$65,$da), ($f9,$c6,$6b,$d3), - ($b2,$af,$31,$a4), ($bf,$a4,$3f,$ad), ($a8,$b9,$2d,$b6), ($a5,$b2,$23,$bf), - ($86,$83,$09,$80), ($8b,$88,$07,$89), ($9c,$95,$15,$92), ($91,$9e,$1b,$9b), - ($0a,$47,$a1,$7c), ($07,$4c,$af,$75), ($10,$51,$bd,$6e), ($1d,$5a,$b3,$67), - ($3e,$6b,$99,$58), ($33,$60,$97,$51), ($24,$7d,$85,$4a), ($29,$76,$8b,$43), - ($62,$1f,$d1,$34), ($6f,$14,$df,$3d), ($78,$09,$cd,$26), ($75,$02,$c3,$2f), - ($56,$33,$e9,$10), ($5b,$38,$e7,$19), ($4c,$25,$f5,$02), ($41,$2e,$fb,$0b), - ($61,$8c,$9a,$d7), ($6c,$87,$94,$de), ($7b,$9a,$86,$c5), ($76,$91,$88,$cc), - ($55,$a0,$a2,$f3), ($58,$ab,$ac,$fa), ($4f,$b6,$be,$e1), ($42,$bd,$b0,$e8), - ($09,$d4,$ea,$9f), ($04,$df,$e4,$96), ($13,$c2,$f6,$8d), ($1e,$c9,$f8,$84), - ($3d,$f8,$d2,$bb), ($30,$f3,$dc,$b2), ($27,$ee,$ce,$a9), ($2a,$e5,$c0,$a0), - ($b1,$3c,$7a,$47), ($bc,$37,$74,$4e), ($ab,$2a,$66,$55), ($a6,$21,$68,$5c), - ($85,$10,$42,$63), ($88,$1b,$4c,$6a), ($9f,$06,$5e,$71), ($92,$0d,$50,$78), - ($d9,$64,$0a,$0f), ($d4,$6f,$04,$06), ($c3,$72,$16,$1d), ($ce,$79,$18,$14), - ($ed,$48,$32,$2b), ($e0,$43,$3c,$22), ($f7,$5e,$2e,$39), ($fa,$55,$20,$30), - ($b7,$01,$ec,$9a), ($ba,$0a,$e2,$93), ($ad,$17,$f0,$88), ($a0,$1c,$fe,$81), - ($83,$2d,$d4,$be), ($8e,$26,$da,$b7), ($99,$3b,$c8,$ac), ($94,$30,$c6,$a5), - ($df,$59,$9c,$d2), ($d2,$52,$92,$db), ($c5,$4f,$80,$c0), ($c8,$44,$8e,$c9), - ($eb,$75,$a4,$f6), ($e6,$7e,$aa,$ff), ($f1,$63,$b8,$e4), ($fc,$68,$b6,$ed), - ($67,$b1,$0c,$0a), ($6a,$ba,$02,$03), ($7d,$a7,$10,$18), ($70,$ac,$1e,$11), - ($53,$9d,$34,$2e), ($5e,$96,$3a,$27), ($49,$8b,$28,$3c), ($44,$80,$26,$35), - ($0f,$e9,$7c,$42), ($02,$e2,$72,$4b), ($15,$ff,$60,$50), ($18,$f4,$6e,$59), - ($3b,$c5,$44,$66), ($36,$ce,$4a,$6f), ($21,$d3,$58,$74), ($2c,$d8,$56,$7d), - ($0c,$7a,$37,$a1), ($01,$71,$39,$a8), ($16,$6c,$2b,$b3), ($1b,$67,$25,$ba), - ($38,$56,$0f,$85), ($35,$5d,$01,$8c), ($22,$40,$13,$97), ($2f,$4b,$1d,$9e), - ($64,$22,$47,$e9), ($69,$29,$49,$e0), ($7e,$34,$5b,$fb), ($73,$3f,$55,$f2), - ($50,$0e,$7f,$cd), ($5d,$05,$71,$c4), ($4a,$18,$63,$df), ($47,$13,$6d,$d6), - ($dc,$ca,$d7,$31), ($d1,$c1,$d9,$38), ($c6,$dc,$cb,$23), ($cb,$d7,$c5,$2a), - ($e8,$e6,$ef,$15), ($e5,$ed,$e1,$1c), ($f2,$f0,$f3,$07), ($ff,$fb,$fd,$0e), - ($b4,$92,$a7,$79), ($b9,$99,$a9,$70), ($ae,$84,$bb,$6b), ($a3,$8f,$b5,$62), - ($80,$be,$9f,$5d), ($8d,$b5,$91,$54), ($9a,$a8,$83,$4f), ($97,$a3,$8d,$46)); - U4: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($09,$0d,$0b,$0e), ($12,$1a,$16,$1c), ($1b,$17,$1d,$12), - ($24,$34,$2c,$38), ($2d,$39,$27,$36), ($36,$2e,$3a,$24), ($3f,$23,$31,$2a), - ($48,$68,$58,$70), ($41,$65,$53,$7e), ($5a,$72,$4e,$6c), ($53,$7f,$45,$62), - ($6c,$5c,$74,$48), ($65,$51,$7f,$46), ($7e,$46,$62,$54), ($77,$4b,$69,$5a), - ($90,$d0,$b0,$e0), ($99,$dd,$bb,$ee), ($82,$ca,$a6,$fc), ($8b,$c7,$ad,$f2), - ($b4,$e4,$9c,$d8), ($bd,$e9,$97,$d6), ($a6,$fe,$8a,$c4), ($af,$f3,$81,$ca), - ($d8,$b8,$e8,$90), ($d1,$b5,$e3,$9e), ($ca,$a2,$fe,$8c), ($c3,$af,$f5,$82), - ($fc,$8c,$c4,$a8), ($f5,$81,$cf,$a6), ($ee,$96,$d2,$b4), ($e7,$9b,$d9,$ba), - ($3b,$bb,$7b,$db), ($32,$b6,$70,$d5), ($29,$a1,$6d,$c7), ($20,$ac,$66,$c9), - ($1f,$8f,$57,$e3), ($16,$82,$5c,$ed), ($0d,$95,$41,$ff), ($04,$98,$4a,$f1), - ($73,$d3,$23,$ab), ($7a,$de,$28,$a5), ($61,$c9,$35,$b7), ($68,$c4,$3e,$b9), - ($57,$e7,$0f,$93), ($5e,$ea,$04,$9d), ($45,$fd,$19,$8f), ($4c,$f0,$12,$81), - ($ab,$6b,$cb,$3b), ($a2,$66,$c0,$35), ($b9,$71,$dd,$27), ($b0,$7c,$d6,$29), - ($8f,$5f,$e7,$03), ($86,$52,$ec,$0d), ($9d,$45,$f1,$1f), ($94,$48,$fa,$11), - ($e3,$03,$93,$4b), ($ea,$0e,$98,$45), ($f1,$19,$85,$57), ($f8,$14,$8e,$59), - ($c7,$37,$bf,$73), ($ce,$3a,$b4,$7d), ($d5,$2d,$a9,$6f), ($dc,$20,$a2,$61), - ($76,$6d,$f6,$ad), ($7f,$60,$fd,$a3), ($64,$77,$e0,$b1), ($6d,$7a,$eb,$bf), - ($52,$59,$da,$95), ($5b,$54,$d1,$9b), ($40,$43,$cc,$89), ($49,$4e,$c7,$87), - ($3e,$05,$ae,$dd), ($37,$08,$a5,$d3), ($2c,$1f,$b8,$c1), ($25,$12,$b3,$cf), - ($1a,$31,$82,$e5), ($13,$3c,$89,$eb), ($08,$2b,$94,$f9), ($01,$26,$9f,$f7), - ($e6,$bd,$46,$4d), ($ef,$b0,$4d,$43), ($f4,$a7,$50,$51), ($fd,$aa,$5b,$5f), - ($c2,$89,$6a,$75), ($cb,$84,$61,$7b), ($d0,$93,$7c,$69), ($d9,$9e,$77,$67), - ($ae,$d5,$1e,$3d), ($a7,$d8,$15,$33), ($bc,$cf,$08,$21), ($b5,$c2,$03,$2f), - ($8a,$e1,$32,$05), ($83,$ec,$39,$0b), ($98,$fb,$24,$19), ($91,$f6,$2f,$17), - ($4d,$d6,$8d,$76), ($44,$db,$86,$78), ($5f,$cc,$9b,$6a), ($56,$c1,$90,$64), - ($69,$e2,$a1,$4e), ($60,$ef,$aa,$40), ($7b,$f8,$b7,$52), ($72,$f5,$bc,$5c), - ($05,$be,$d5,$06), ($0c,$b3,$de,$08), ($17,$a4,$c3,$1a), ($1e,$a9,$c8,$14), - ($21,$8a,$f9,$3e), ($28,$87,$f2,$30), ($33,$90,$ef,$22), ($3a,$9d,$e4,$2c), - ($dd,$06,$3d,$96), ($d4,$0b,$36,$98), ($cf,$1c,$2b,$8a), ($c6,$11,$20,$84), - ($f9,$32,$11,$ae), ($f0,$3f,$1a,$a0), ($eb,$28,$07,$b2), ($e2,$25,$0c,$bc), - ($95,$6e,$65,$e6), ($9c,$63,$6e,$e8), ($87,$74,$73,$fa), ($8e,$79,$78,$f4), - ($b1,$5a,$49,$de), ($b8,$57,$42,$d0), ($a3,$40,$5f,$c2), ($aa,$4d,$54,$cc), - ($ec,$da,$f7,$41), ($e5,$d7,$fc,$4f), ($fe,$c0,$e1,$5d), ($f7,$cd,$ea,$53), - ($c8,$ee,$db,$79), ($c1,$e3,$d0,$77), ($da,$f4,$cd,$65), ($d3,$f9,$c6,$6b), - ($a4,$b2,$af,$31), ($ad,$bf,$a4,$3f), ($b6,$a8,$b9,$2d), ($bf,$a5,$b2,$23), - ($80,$86,$83,$09), ($89,$8b,$88,$07), ($92,$9c,$95,$15), ($9b,$91,$9e,$1b), - ($7c,$0a,$47,$a1), ($75,$07,$4c,$af), ($6e,$10,$51,$bd), ($67,$1d,$5a,$b3), - ($58,$3e,$6b,$99), ($51,$33,$60,$97), ($4a,$24,$7d,$85), ($43,$29,$76,$8b), - ($34,$62,$1f,$d1), ($3d,$6f,$14,$df), ($26,$78,$09,$cd), ($2f,$75,$02,$c3), - ($10,$56,$33,$e9), ($19,$5b,$38,$e7), ($02,$4c,$25,$f5), ($0b,$41,$2e,$fb), - ($d7,$61,$8c,$9a), ($de,$6c,$87,$94), ($c5,$7b,$9a,$86), ($cc,$76,$91,$88), - ($f3,$55,$a0,$a2), ($fa,$58,$ab,$ac), ($e1,$4f,$b6,$be), ($e8,$42,$bd,$b0), - ($9f,$09,$d4,$ea), ($96,$04,$df,$e4), ($8d,$13,$c2,$f6), ($84,$1e,$c9,$f8), - ($bb,$3d,$f8,$d2), ($b2,$30,$f3,$dc), ($a9,$27,$ee,$ce), ($a0,$2a,$e5,$c0), - ($47,$b1,$3c,$7a), ($4e,$bc,$37,$74), ($55,$ab,$2a,$66), ($5c,$a6,$21,$68), - ($63,$85,$10,$42), ($6a,$88,$1b,$4c), ($71,$9f,$06,$5e), ($78,$92,$0d,$50), - ($0f,$d9,$64,$0a), ($06,$d4,$6f,$04), ($1d,$c3,$72,$16), ($14,$ce,$79,$18), - ($2b,$ed,$48,$32), ($22,$e0,$43,$3c), ($39,$f7,$5e,$2e), ($30,$fa,$55,$20), - ($9a,$b7,$01,$ec), ($93,$ba,$0a,$e2), ($88,$ad,$17,$f0), ($81,$a0,$1c,$fe), - ($be,$83,$2d,$d4), ($b7,$8e,$26,$da), ($ac,$99,$3b,$c8), ($a5,$94,$30,$c6), - ($d2,$df,$59,$9c), ($db,$d2,$52,$92), ($c0,$c5,$4f,$80), ($c9,$c8,$44,$8e), - ($f6,$eb,$75,$a4), ($ff,$e6,$7e,$aa), ($e4,$f1,$63,$b8), ($ed,$fc,$68,$b6), - ($0a,$67,$b1,$0c), ($03,$6a,$ba,$02), ($18,$7d,$a7,$10), ($11,$70,$ac,$1e), - ($2e,$53,$9d,$34), ($27,$5e,$96,$3a), ($3c,$49,$8b,$28), ($35,$44,$80,$26), - ($42,$0f,$e9,$7c), ($4b,$02,$e2,$72), ($50,$15,$ff,$60), ($59,$18,$f4,$6e), - ($66,$3b,$c5,$44), ($6f,$36,$ce,$4a), ($74,$21,$d3,$58), ($7d,$2c,$d8,$56), - ($a1,$0c,$7a,$37), ($a8,$01,$71,$39), ($b3,$16,$6c,$2b), ($ba,$1b,$67,$25), - ($85,$38,$56,$0f), ($8c,$35,$5d,$01), ($97,$22,$40,$13), ($9e,$2f,$4b,$1d), - ($e9,$64,$22,$47), ($e0,$69,$29,$49), ($fb,$7e,$34,$5b), ($f2,$73,$3f,$55), - ($cd,$50,$0e,$7f), ($c4,$5d,$05,$71), ($df,$4a,$18,$63), ($d6,$47,$13,$6d), - ($31,$dc,$ca,$d7), ($38,$d1,$c1,$d9), ($23,$c6,$dc,$cb), ($2a,$cb,$d7,$c5), - ($15,$e8,$e6,$ef), ($1c,$e5,$ed,$e1), ($07,$f2,$f0,$f3), ($0e,$ff,$fb,$fd), - ($79,$b4,$92,$a7), ($70,$b9,$99,$a9), ($6b,$ae,$84,$bb), ($62,$a3,$8f,$b5), - ($5d,$80,$be,$9f), ($54,$8d,$b5,$91), ($4f,$9a,$a8,$83), ($46,$97,$a3,$8d)); - - rcon: array[0..29] of cardinal= ( - $01, $02, $04, $08, $10, $20, $40, $80, $1b, $36, $6c, $d8, $ab, $4d, $9a, - $2f, $5e, $bc, $63, $c6, $97, $35, $6a, $d4, $b3, $7d, $fa, $ef, $c5, $91); - -{==============================================================================} -type - PDWord = ^LongWord; - -procedure hperm_op(var a, t: integer; n, m: integer); -begin - t:= ((a shl (16 - n)) xor a) and m; - a:= a xor t xor (t shr (16 - n)); -end; - -procedure perm_op(var a, b, t: integer; n, m: integer); -begin - t:= ((a shr n) xor b) and m; - b:= b xor t; - a:= a xor (t shl n); -end; - -{==============================================================================} -function TSynaBlockCipher.GetSize: byte; -begin - Result := 8; -end; - -procedure TSynaBlockCipher.IncCounter; -var - i: integer; -begin - Inc(CV[GetSize]); - i:= GetSize -1; - while (i> 0) and (CV[i + 1] = #0) do - begin - Inc(CV[i]); - Dec(i); - end; -end; - -procedure TSynaBlockCipher.Reset; -begin - CV := IV; -end; - -procedure TSynaBlockCipher.InitKey(Key: AnsiString); -begin -end; - -procedure TSynaBlockCipher.SetIV(const Value: AnsiString); -begin - IV := PadString(Value, GetSize, #0); - Reset; -end; - -function TSynaBlockCipher.GetIV: AnsiString; -begin - Result := CV; -end; - -function TSynaBlockCipher.EncryptECB(const InData: AnsiString): AnsiString; -begin - Result := InData; -end; - -function TSynaBlockCipher.DecryptECB(const InData: AnsiString): AnsiString; -begin - Result := InData; -end; - -function TSynaBlockCipher.EncryptCBC(const Indata: AnsiString): AnsiString; -var - i: integer; - s: ansistring; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - s := EncryptECB(s); - CV := s; - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptCBC(const Indata: AnsiString): AnsiString; -var - i: integer; - s, temp: ansistring; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - s := copy(Indata, (i - 1) * bs + 1, bs); - temp := s; - s := DecryptECB(s); - s := XorString(s, CV); - Result := Result + s; - CV := Temp; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.EncryptCFB8bit(const Indata: AnsiString): AnsiString; -var - i: integer; - Temp: AnsiString; - c: AnsiChar; -begin - Result := ''; - for i:= 1 to Length(Indata) do - begin - Temp := EncryptECB(CV); - c := AnsiChar(ord(InData[i]) xor ord(temp[1])); - Result := Result + c; - Delete(CV, 1, 1); - CV := CV + c; - end; -end; - -function TSynaBlockCipher.DecryptCFB8bit(const Indata: AnsiString): AnsiString; -var - i: integer; - Temp: AnsiString; - c: AnsiChar; -begin - Result := ''; - for i:= 1 to length(Indata) do - begin - c:= Indata[i]; - Temp := EncryptECB(CV); - Result := Result + AnsiChar(ord(InData[i]) xor ord(temp[1])); - Delete(CV, 1, 1); - CV := CV + c; - end; -end; - -function TSynaBlockCipher.EncryptCFBblock(const Indata: AnsiString): AnsiString; -var - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - CV := EncryptECB(CV); - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - Result := Result + s; - CV := s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptCFBblock(const Indata: AnsiString): AnsiString; -var - i: integer; - S, Temp: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - s := copy(Indata, (i - 1) * bs + 1, bs); - Temp := s; - CV := EncryptECB(CV); - s := XorString(s, CV); - Result := result + s; - CV := temp; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.EncryptOFB(const Indata: AnsiString): AnsiString; -var - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - CV := EncryptECB(CV); - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptOFB(const Indata: AnsiString): AnsiString; -var - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - Cv := EncryptECB(CV); - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.EncryptCTR(const Indata: AnsiString): AnsiString; -var - temp: AnsiString; - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, temp); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, temp); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptCTR(const Indata: AnsiString): AnsiString; -var - temp: AnsiString; - s: AnsiString; - i: integer; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, temp); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, temp); - Result := Result + s; - end; -end; - -constructor TSynaBlockCipher.Create(Key: AnsiString); -begin - inherited Create; - InitKey(Key); - IV := StringOfChar(#0, GetSize); - IV := EncryptECB(IV); - Reset; -end; - -{==============================================================================} - -procedure TSynaCustomDes.DoInit(KeyB: AnsiString; var KeyData: TDesKeyData); -var - c, d, t, s, t2, i: integer; -begin - KeyB := PadString(KeyB, 8, #0); - c:= ord(KeyB[1]) or (ord(KeyB[2]) shl 8) or (ord(KeyB[3]) shl 16) or (ord(KeyB[4]) shl 24); - d:= ord(KeyB[5]) or (ord(KeyB[6]) shl 8) or (ord(KeyB[7]) shl 16) or (ord(KeyB[8]) shl 24); - perm_op(d,c,t,4,integer($0f0f0f0f)); - hperm_op(c,t,integer(-2),integer($cccc0000)); - hperm_op(d,t,integer(-2),integer($cccc0000)); - perm_op(d,c,t,1,integer($55555555)); - perm_op(c,d,t,8,integer($00ff00ff)); - perm_op(d,c,t,1,integer($55555555)); - d:= ((d and $ff) shl 16) or (d and $ff00) or ((d and $ff0000) shr 16) or - ((c and integer($f0000000)) shr 4); - c:= c and $fffffff; - for i:= 0 to 15 do - begin - if shifts2[i]<> 0 then - begin - c:= ((c shr 2) or (c shl 26)); - d:= ((d shr 2) or (d shl 26)); - end - else - begin - c:= ((c shr 1) or (c shl 27)); - d:= ((d shr 1) or (d shl 27)); - end; - c:= c and $fffffff; - d:= d and $fffffff; - s:= des_skb[0,c and $3f] or - des_skb[1,((c shr 6) and $03) or ((c shr 7) and $3c)] or - des_skb[2,((c shr 13) and $0f) or ((c shr 14) and $30)] or - des_skb[3,((c shr 20) and $01) or ((c shr 21) and $06) or ((c shr 22) and $38)]; - t:= des_skb[4,d and $3f] or - des_skb[5,((d shr 7) and $03) or ((d shr 8) and $3c)] or - des_skb[6, (d shr 15) and $3f ] or - des_skb[7,((d shr 21) and $0f) or ((d shr 22) and $30)]; - t2:= ((t shl 16) or (s and $ffff)); - KeyData[(i shl 1)]:= ((t2 shl 2) or (t2 shr 30)); - t2:= ((s shr 16) or (t and integer($ffff0000))); - KeyData[(i shl 1)+1]:= ((t2 shl 6) or (t2 shr 26)); - end; -end; - -function TSynaCustomDes.EncryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; -var - l, r, t, u: integer; - i: longint; -begin - r := Swapbytes(DecodeLongint(Indata, 1)); - l := swapbytes(DecodeLongint(Indata, 5)); - t:= ((l shr 4) xor r) and $0f0f0f0f; - r:= r xor t; - l:= l xor (t shl 4); - t:= ((r shr 16) xor l) and $0000ffff; - l:= l xor t; - r:= r xor (t shl 16); - t:= ((l shr 2) xor r) and $33333333; - r:= r xor t; - l:= l xor (t shl 2); - t:= ((r shr 8) xor l) and $00ff00ff; - l:= l xor t; - r:= r xor (t shl 8); - t:= ((l shr 1) xor r) and $55555555; - r:= r xor t; - l:= l xor (t shl 1); - r:= (r shr 29) or (r shl 3); - l:= (l shr 29) or (l shl 3); - i:= 0; - while i< 32 do - begin - u:= r xor KeyData[i ]; - t:= r xor KeyData[i+1]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i+2]; - t:= l xor KeyData[i+3]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= r xor KeyData[i+4]; - t:= r xor KeyData[i+5]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i+6]; - t:= l xor KeyData[i+7]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - Inc(i,8); - end; - r:= (r shr 3) or (r shl 29); - l:= (l shr 3) or (l shl 29); - t:= ((r shr 1) xor l) and $55555555; - l:= l xor t; - r:= r xor (t shl 1); - t:= ((l shr 8) xor r) and $00ff00ff; - r:= r xor t; - l:= l xor (t shl 8); - t:= ((r shr 2) xor l) and $33333333; - l:= l xor t; - r:= r xor (t shl 2); - t:= ((l shr 16) xor r) and $0000ffff; - r:= r xor t; - l:= l xor (t shl 16); - t:= ((r shr 4) xor l) and $0f0f0f0f; - l:= l xor t; - r:= r xor (t shl 4); - Result := CodeLongInt(Swapbytes(l)) + CodeLongInt(Swapbytes(r)); -end; - -function TSynaCustomDes.DecryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; -var - l, r, t, u: integer; - i: longint; -begin - r := Swapbytes(DecodeLongint(Indata, 1)); - l := Swapbytes(DecodeLongint(Indata, 5)); - t:= ((l shr 4) xor r) and $0f0f0f0f; - r:= r xor t; - l:= l xor (t shl 4); - t:= ((r shr 16) xor l) and $0000ffff; - l:= l xor t; - r:= r xor (t shl 16); - t:= ((l shr 2) xor r) and $33333333; - r:= r xor t; - l:= l xor (t shl 2); - t:= ((r shr 8) xor l) and $00ff00ff; - l:= l xor t; - r:= r xor (t shl 8); - t:= ((l shr 1) xor r) and $55555555; - r:= r xor t; - l:= l xor (t shl 1); - r:= (r shr 29) or (r shl 3); - l:= (l shr 29) or (l shl 3); - i:= 30; - while i> 0 do - begin - u:= r xor KeyData[i ]; - t:= r xor KeyData[i+1]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i-2]; - t:= l xor KeyData[i-1]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= r xor KeyData[i-4]; - t:= r xor KeyData[i-3]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i-6]; - t:= l xor KeyData[i-5]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - Dec(i,8); - end; - r:= (r shr 3) or (r shl 29); - l:= (l shr 3) or (l shl 29); - t:= ((r shr 1) xor l) and $55555555; - l:= l xor t; - r:= r xor (t shl 1); - t:= ((l shr 8) xor r) and $00ff00ff; - r:= r xor t; - l:= l xor (t shl 8); - t:= ((r shr 2) xor l) and $33333333; - l:= l xor t; - r:= r xor (t shl 2); - t:= ((l shr 16) xor r) and $0000ffff; - r:= r xor t; - l:= l xor (t shl 16); - t:= ((r shr 4) xor l) and $0f0f0f0f; - l:= l xor t; - r:= r xor (t shl 4); - Result := CodeLongInt(Swapbytes(l)) + CodeLongInt(Swapbytes(r)); -end; - -{==============================================================================} - -procedure TSynaDes.InitKey(Key: AnsiString); -begin - Key := PadString(Key, 8, #0); - DoInit(Key,KeyData); -end; - -function TSynaDes.EncryptECB(const InData: AnsiString): AnsiString; -begin - Result := EncryptBlock(InData,KeyData); -end; - -function TSynaDes.DecryptECB(const InData: AnsiString): AnsiString; -begin - Result := DecryptBlock(Indata,KeyData); -end; - -{==============================================================================} - -procedure TSyna3Des.InitKey(Key: AnsiString); -var - Size: integer; - n: integer; -begin - Size := length(Key); - key := PadString(key, 3 * 8, #0); - DoInit(Copy(key, 1, 8),KeyData[0]); - DoInit(Copy(key, 9, 8),KeyData[1]); - if Size > 16 then - DoInit(Copy(key, 17, 8),KeyData[2]) - else - for n := 0 to high(KeyData[0]) do - KeyData[2][n] := Keydata[0][n]; -end; - -function TSyna3Des.EncryptECB(const InData: AnsiString): AnsiString; -begin - Result := EncryptBlock(Indata,KeyData[0]); - Result := DecryptBlock(Result,KeyData[1]); - Result := EncryptBlock(Result,KeyData[2]); -end; - -function TSyna3Des.DecryptECB(const InData: AnsiString): AnsiString; -begin - Result := DecryptBlock(InData,KeyData[2]); - Result := EncryptBlock(Result,KeyData[1]); - Result := DecryptBlock(Result,KeyData[0]); -end; - -{==============================================================================} - -procedure InvMixColumn(a: PByteArray; BC: byte); -var - j: longword; -begin - for j:= 0 to (BC-1) do - PDWord(@(a^[j*4]))^:= PDWord(@U1[a^[j*4+0]])^ - xor PDWord(@U2[a^[j*4+1]])^ - xor PDWord(@U3[a^[j*4+2]])^ - xor PDWord(@U4[a^[j*4+3]])^; -end; - -{==============================================================================} - -function TSynaAes.GetSize: byte; -begin - Result := 16; -end; - -procedure TSynaAes.InitKey(Key: AnsiString); -var - Size: integer; - KC, ROUNDS, j, r, t, rconpointer: longword; - tk: array[0..MAXKC-1,0..3] of byte; - n: integer; -begin - FillChar(tk,Sizeof(tk),0); - //key must have at least 128 bits and max 256 bits - if length(key) < 16 then - key := PadString(key, 16, #0); - if length(key) > 32 then - delete(key, 33, maxint); - Size := length(Key); - Move(PAnsiChar(Key)^, tk, Size); - if Size<= 16 then - begin - KC:= 4; - Rounds:= 10; - end - else if Size<= 24 then - begin - KC:= 6; - Rounds:= 12; - end - else - begin - KC:= 8; - Rounds:= 14; - end; - numrounds:= rounds; - r:= 0; - t:= 0; - j:= 0; - while (j< KC) and (r< (rounds+1)) do - begin - while (j< KC) and (t< BC) do - begin - rk[r,t]:= PDWord(@tk[j])^; - Inc(j); - Inc(t); - end; - if t= BC then - begin - t:= 0; - Inc(r); - end; - end; - rconpointer:= 0; - while (r< (rounds+1)) do - begin - tk[0,0]:= tk[0,0] xor S[tk[KC-1,1]]; - tk[0,1]:= tk[0,1] xor S[tk[KC-1,2]]; - tk[0,2]:= tk[0,2] xor S[tk[KC-1,3]]; - tk[0,3]:= tk[0,3] xor S[tk[KC-1,0]]; - tk[0,0]:= tk[0,0] xor rcon[rconpointer]; - Inc(rconpointer); - if KC<> 8 then - begin - for j:= 1 to (KC-1) do - PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; - end - else - begin - for j:= 1 to ((KC div 2)-1) do - PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; - tk[KC div 2,0]:= tk[KC div 2,0] xor S[tk[KC div 2 - 1,0]]; - tk[KC div 2,1]:= tk[KC div 2,1] xor S[tk[KC div 2 - 1,1]]; - tk[KC div 2,2]:= tk[KC div 2,2] xor S[tk[KC div 2 - 1,2]]; - tk[KC div 2,3]:= tk[KC div 2,3] xor S[tk[KC div 2 - 1,3]]; - for j:= ((KC div 2) + 1) to (KC-1) do - PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; - end; - j:= 0; - while (j< KC) and (r< (rounds+1)) do - begin - while (j< KC) and (t< BC) do - begin - rk[r,t]:= PDWord(@tk[j])^; - Inc(j); - Inc(t); - end; - if t= BC then - begin - Inc(r); - t:= 0; - end; - end; - end; - Move(rk,drk,Sizeof(rk)); - for r:= 1 to (numrounds-1) do - InvMixColumn(@drk[r],BC); -end; - -function TSynaAes.EncryptECB(const InData: AnsiString): AnsiString; -var - r: longword; - tempb: array[0..MAXBC-1,0..3] of byte; - a: array[0..MAXBC,0..3] of byte; - p: pointer; -begin - p := @a[0,0]; - move(pointer(InData)^, p^, 16); - for r:= 0 to (numrounds-2) do - begin - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor rk[r,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor rk[r,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor rk[r,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor rk[r,3]; - PDWord(@a[0])^:= PDWord(@T1[tempb[0,0]])^ xor - PDWord(@T2[tempb[1,1]])^ xor - PDWord(@T3[tempb[2,2]])^ xor - PDWord(@T4[tempb[3,3]])^; - PDWord(@a[1])^:= PDWord(@T1[tempb[1,0]])^ xor - PDWord(@T2[tempb[2,1]])^ xor - PDWord(@T3[tempb[3,2]])^ xor - PDWord(@T4[tempb[0,3]])^; - PDWord(@a[2])^:= PDWord(@T1[tempb[2,0]])^ xor - PDWord(@T2[tempb[3,1]])^ xor - PDWord(@T3[tempb[0,2]])^ xor - PDWord(@T4[tempb[1,3]])^; - PDWord(@a[3])^:= PDWord(@T1[tempb[3,0]])^ xor - PDWord(@T2[tempb[0,1]])^ xor - PDWord(@T3[tempb[1,2]])^ xor - PDWord(@T4[tempb[2,3]])^; - end; - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor rk[numrounds-1,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor rk[numrounds-1,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor rk[numrounds-1,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor rk[numrounds-1,3]; - a[0,0]:= T1[tempb[0,0],1]; - a[0,1]:= T1[tempb[1,1],1]; - a[0,2]:= T1[tempb[2,2],1]; - a[0,3]:= T1[tempb[3,3],1]; - a[1,0]:= T1[tempb[1,0],1]; - a[1,1]:= T1[tempb[2,1],1]; - a[1,2]:= T1[tempb[3,2],1]; - a[1,3]:= T1[tempb[0,3],1]; - a[2,0]:= T1[tempb[2,0],1]; - a[2,1]:= T1[tempb[3,1],1]; - a[2,2]:= T1[tempb[0,2],1]; - a[2,3]:= T1[tempb[1,3],1]; - a[3,0]:= T1[tempb[3,0],1]; - a[3,1]:= T1[tempb[0,1],1]; - a[3,2]:= T1[tempb[1,2],1]; - a[3,3]:= T1[tempb[2,3],1]; - PDWord(@a[0])^:= PDWord(@a[0])^ xor rk[numrounds,0]; - PDWord(@a[1])^:= PDWord(@a[1])^ xor rk[numrounds,1]; - PDWord(@a[2])^:= PDWord(@a[2])^ xor rk[numrounds,2]; - PDWord(@a[3])^:= PDWord(@a[3])^ xor rk[numrounds,3]; - - Result := StringOfChar(#0, 16); - move(p^, pointer(Result)^, 16); -end; - -function TSynaAes.DecryptECB(const InData: AnsiString): AnsiString; -var - r: longword; - tempb: array[0..MAXBC-1,0..3] of byte; - a: array[0..MAXBC,0..3] of byte; - p: pointer; -begin - p := @a[0,0]; - move(pointer(InData)^, p^, 16); - for r:= NumRounds downto 2 do - begin - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor drk[r,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor drk[r,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor drk[r,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor drk[r,3]; - PDWord(@a[0])^:= PDWord(@T5[tempb[0,0]])^ xor - PDWord(@T6[tempb[3,1]])^ xor - PDWord(@T7[tempb[2,2]])^ xor - PDWord(@T8[tempb[1,3]])^; - PDWord(@a[1])^:= PDWord(@T5[tempb[1,0]])^ xor - PDWord(@T6[tempb[0,1]])^ xor - PDWord(@T7[tempb[3,2]])^ xor - PDWord(@T8[tempb[2,3]])^; - PDWord(@a[2])^:= PDWord(@T5[tempb[2,0]])^ xor - PDWord(@T6[tempb[1,1]])^ xor - PDWord(@T7[tempb[0,2]])^ xor - PDWord(@T8[tempb[3,3]])^; - PDWord(@a[3])^:= PDWord(@T5[tempb[3,0]])^ xor - PDWord(@T6[tempb[2,1]])^ xor - PDWord(@T7[tempb[1,2]])^ xor - PDWord(@T8[tempb[0,3]])^; - end; - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor drk[1,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor drk[1,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor drk[1,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor drk[1,3]; - a[0,0]:= S5[tempb[0,0]]; - a[0,1]:= S5[tempb[3,1]]; - a[0,2]:= S5[tempb[2,2]]; - a[0,3]:= S5[tempb[1,3]]; - a[1,0]:= S5[tempb[1,0]]; - a[1,1]:= S5[tempb[0,1]]; - a[1,2]:= S5[tempb[3,2]]; - a[1,3]:= S5[tempb[2,3]]; - a[2,0]:= S5[tempb[2,0]]; - a[2,1]:= S5[tempb[1,1]]; - a[2,2]:= S5[tempb[0,2]]; - a[2,3]:= S5[tempb[3,3]]; - a[3,0]:= S5[tempb[3,0]]; - a[3,1]:= S5[tempb[2,1]]; - a[3,2]:= S5[tempb[1,2]]; - a[3,3]:= S5[tempb[0,3]]; - PDWord(@a[0])^:= PDWord(@a[0])^ xor drk[0,0]; - PDWord(@a[1])^:= PDWord(@a[1])^ xor drk[0,1]; - PDWord(@a[2])^:= PDWord(@a[2])^ xor drk[0,2]; - PDWord(@a[3])^:= PDWord(@a[3])^ xor drk[0,3]; - Result := StringOfChar(#0, 16); - move(p^, pointer(Result)^, 16); -end; - -{==============================================================================} - -function TestDes: boolean; -var - des: TSynaDes; - s, t: string; -const - key = '01234567'; - data1= '01234567'; - data2= '0123456789abcdefghij'; -begin - //ECB - des := TSynaDes.Create(key); - try - s := des.EncryptECB(data1); - t := strtohex(s); - result := t = 'c50ad028c6da9800'; - s := des.DecryptECB(s); - result := result and (data1 = s); - finally - des.free; - end; - //CBC - des := TSynaDes.Create(key); - try - s := des.EncryptCBC(data2); - t := strtohex(s); - result := result and (t = 'eec50f6353115ad6dee90a22ed1b6a88a0926e35'); - des.Reset; - s := des.DecryptCBC(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-8bit - des := TSynaDes.Create(key); - try - s := des.EncryptCFB8bit(data2); - t := strtohex(s); - result := result and (t = 'eb6aa12c2f0ff634b4dfb6da6cb2af8f9c5c1452'); - des.Reset; - s := des.DecryptCFB8bit(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-block - des := TSynaDes.Create(key); - try - s := des.EncryptCFBblock(data2); - t := strtohex(s); - result := result and (t = 'ebdbbaa7f9286cdec28605e07f9b7f3be1053257'); - des.Reset; - s := des.DecryptCFBblock(s); - result := result and (data2 = s); - finally - des.free; - end; - //OFB - des := TSynaDes.Create(key); - try - s := des.EncryptOFB(data2); - t := strtohex(s); - result := result and (t = 'ebdbbaa7f9286cdee0b8b3798c4c34baac87dbdc'); - des.Reset; - s := des.DecryptOFB(s); - result := result and (data2 = s); - finally - des.free; - end; - //CTR - des := TSynaDes.Create(key); - try - s := des.EncryptCTR(data2); - t := strtohex(s); - result := result and (t = 'ebdbbaa7f9286cde0dd20b45f3afd9aa1b91b87e'); - des.Reset; - s := des.DecryptCTR(s); - result := result and (data2 = s); - finally - des.free; - end; -end; - -function Test3Des: boolean; -var - des: TSyna3Des; - s, t: string; -const - key = '0123456789abcdefghijklmn'; - data1= '01234567'; - data2= '0123456789abcdefghij'; -begin - //ECB - des := TSyna3Des.Create(key); - try - s := des.EncryptECB(data1); - t := strtohex(s); - result := t = 'e0dee91008dc460c'; - s := des.DecryptECB(s); - result := result and (data1 = s); - finally - des.free; - end; - //CBC - des := TSyna3Des.Create(key); - try - s := des.EncryptCBC(data2); - t := strtohex(s); - result := result and (t = 'ee844a2a4f49c01b91a1599b8eba29128c1ad87a'); - des.Reset; - s := des.DecryptCBC(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-8bit - des := TSyna3Des.Create(key); - try - s := des.EncryptCFB8bit(data2); - t := strtohex(s); - result := result and (t = '935bbf5210c32cfa1faf61f91e8dc02dfa0ff1e8'); - des.Reset; - s := des.DecryptCFB8bit(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-block - des := TSyna3Des.Create(key); - try - s := des.EncryptCFBblock(data2); - t := strtohex(s); - result := result and (t = '93754e3d54828fbf4bd81f1739419e8d2cfe1671'); - des.Reset; - s := des.DecryptCFBblock(s); - result := result and (data2 = s); - finally - des.free; - end; - //OFB - des := TSyna3Des.Create(key); - try - s := des.EncryptOFB(data2); - t := strtohex(s); - result := result and (t = '93754e3d54828fbf04ef0a5efc926ebdf2d95f20'); - des.Reset; - s := des.DecryptOFB(s); - result := result and (data2 = s); - finally - des.free; - end; - //CTR - des := TSyna3Des.Create(key); - try - s := des.EncryptCTR(data2); - t := strtohex(s); - result := result and (t = '93754e3d54828fbf1c51a121d2c93f989e70b3ad'); - des.Reset; - s := des.DecryptCTR(s); - result := result and (data2 = s); - finally - des.free; - end; -end; - -function TestAes: boolean; -var - aes: TSynaAes; - s, t: string; -const - key1 = #$00#$01#$02#$03#$05#$06#$07#$08#$0A#$0B#$0C#$0D#$0F#$10#$11#$12; - data1= #$50#$68#$12#$A4#$5F#$08#$C8#$89#$B9#$7F#$59#$80#$03#$8B#$83#$59; - key2 = #$A0#$A1#$A2#$A3#$A5#$A6#$A7#$A8#$AA#$AB#$AC#$AD#$AF#$B0#$B1#$B2#$B4#$B5#$B6#$B7#$B9#$BA#$BB#$BC; - data2= #$4F#$1C#$76#$9D#$1E#$5B#$05#$52#$C7#$EC#$A8#$4D#$EA#$26#$A5#$49; - key3 = #$00#$01#$02#$03#$05#$06#$07#$08#$0A#$0B#$0C#$0D#$0F#$10#$11#$12#$14#$15#$16#$17#$19#$1A#$1B#$1C#$1E#$1F#$20#$21#$23#$24#$25#$26; - data3= #$5E#$25#$CA#$78#$F0#$DE#$55#$80#$25#$24#$D3#$8D#$A3#$FE#$44#$56; -begin - //ECB - aes := TSynaAes.Create(key1); - try - t := aes.EncryptECB(data1); - result := t = #$D8#$F5#$32#$53#$82#$89#$EF#$7D#$06#$B5#$06#$A4#$FD#$5B#$E9#$C9; - s := aes.DecryptECB(t); - result := result and (data1 = s); - finally - aes.free; - end; - aes := TSynaAes.Create(key2); - try - t := aes.EncryptECB(data2); - result := result and (t = #$F3#$84#$72#$10#$D5#$39#$1E#$23#$60#$60#$8E#$5A#$CB#$56#$05#$81); - s := aes.DecryptECB(t); - result := result and (data2 = s); - finally - aes.free; - end; - aes := TSynaAes.Create(key3); - try - t := aes.EncryptECB(data3); - result := result and (t = #$E8#$B7#$2B#$4E#$8B#$E2#$43#$43#$8C#$9F#$FF#$1F#$0E#$20#$58#$72); - s := aes.DecryptECB(t); - result := result and (data3 = s); - finally - aes.free; - end; -end; - -{==============================================================================} - -end. +{==============================================================================| +| Project : Ararat Synapse | 001.001.000 | +|==============================================================================| +| Content: Encryption support | +|==============================================================================| +| Copyright (c)2007-2011, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2007-2011. | +| All Rights Reserved. | +| Based on work of David Barton and Eric Young | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(Encryption support) + +Implemented are DES and 3DES encryption/decryption by ECB, CBC, CFB-8bit, + CFB-block, OFB and CTR methods. +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$R-} +{$H+} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} +{$ENDIF} + +unit synacrypt; + +interface + +uses + SysUtils, Classes, synautil, synafpc; + +type + {:@abstract(Implementation of common routines block ciphers (dafault size is 64-bits)) + + Do not use this class directly, use descendants only!} + TSynaBlockCipher= class(TObject) + protected + procedure InitKey(Key: AnsiString); virtual; + function GetSize: byte; virtual; + private + IV, CV: AnsiString; + procedure IncCounter; + public + {:Sets the IV to Value and performs a reset} + procedure SetIV(const Value: AnsiString); virtual; + {:Returns the current chaining information, not the actual IV} + function GetIV: AnsiString; virtual; + {:Reset any stored chaining information} + procedure Reset; virtual; + {:Encrypt a 64-bit block of data using the ECB method of encryption} + function EncryptECB(const InData: AnsiString): AnsiString; virtual; + {:Decrypt a 64-bit block of data using the ECB method of decryption} + function DecryptECB(const InData: AnsiString): AnsiString; virtual; + {:Encrypt data using the CBC method of encryption} + function EncryptCBC(const Indata: AnsiString): AnsiString; virtual; + {:Decrypt data using the CBC method of decryption} + function DecryptCBC(const Indata: AnsiString): AnsiString; virtual; + {:Encrypt data using the CFB (8 bit) method of encryption} + function EncryptCFB8bit(const Indata: AnsiString): AnsiString; virtual; + {:Decrypt data using the CFB (8 bit) method of decryption} + function DecryptCFB8bit(const Indata: AnsiString): AnsiString; virtual; + {:Encrypt data using the CFB (block) method of encryption} + function EncryptCFBblock(const Indata: AnsiString): AnsiString; virtual; + {:Decrypt data using the CFB (block) method of decryption} + function DecryptCFBblock(const Indata: AnsiString): AnsiString; virtual; + {:Encrypt data using the OFB method of encryption} + function EncryptOFB(const Indata: AnsiString): AnsiString; virtual; + {:Decrypt data using the OFB method of decryption} + function DecryptOFB(const Indata: AnsiString): AnsiString; virtual; + {:Encrypt data using the CTR method of encryption} + function EncryptCTR(const Indata: AnsiString): AnsiString; virtual; + {:Decrypt data using the CTR method of decryption} + function DecryptCTR(const Indata: AnsiString): AnsiString; virtual; + {:Create a encryptor/decryptor instance and initialize it by the Key.} + constructor Create(Key: AnsiString); + end; + + {:@abstract(Datatype for holding one DES key data) + + This data type is used internally.} + TDesKeyData = array[0..31] of integer; + + {:@abstract(Implementation of common routines for DES encryption) + + Do not use this class directly, use descendants only!} + TSynaCustomDes = class(TSynaBlockcipher) + protected + procedure DoInit(KeyB: AnsiString; var KeyData: TDesKeyData); + function EncryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; + function DecryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; + end; + + {:@abstract(Implementation of DES encryption)} + TSynaDes= class(TSynaCustomDes) + protected + KeyData: TDesKeyData; + procedure InitKey(Key: AnsiString); override; + public + {:Encrypt a 64-bit block of data using the ECB method of encryption} + function EncryptECB(const InData: AnsiString): AnsiString; override; + {:Decrypt a 64-bit block of data using the ECB method of decryption} + function DecryptECB(const InData: AnsiString): AnsiString; override; + end; + + {:@abstract(Implementation of 3DES encryption)} + TSyna3Des= class(TSynaCustomDes) + protected + KeyData: array[0..2] of TDesKeyData; + procedure InitKey(Key: AnsiString); override; + public + {:Encrypt a 64-bit block of data using the ECB method of encryption} + function EncryptECB(const InData: AnsiString): AnsiString; override; + {:Decrypt a 64-bit block of data using the ECB method of decryption} + function DecryptECB(const InData: AnsiString): AnsiString; override; + end; + +const + BC = 4; + MAXROUNDS = 14; +type + {:@abstract(Implementation of AES encryption)} + TSynaAes= class(TSynaBlockcipher) + protected + numrounds: longword; + rk, drk: array[0..MAXROUNDS,0..7] of longword; + procedure InitKey(Key: AnsiString); override; + function GetSize: byte; override; + public + {:Encrypt a 128-bit block of data using the ECB method of encryption} + function EncryptECB(const InData: AnsiString): AnsiString; override; + {:Decrypt a 128-bit block of data using the ECB method of decryption} + function DecryptECB(const InData: AnsiString): AnsiString; override; + end; + +{:Call internal test of all DES encryptions. Returns @true if all is OK.} +function TestDes: boolean; +{:Call internal test of all 3DES encryptions. Returns @true if all is OK.} +function Test3Des: boolean; +{:Call internal test of all AES encryptions. Returns @true if all is OK.} +function TestAes: boolean; + +{==============================================================================} +implementation + +//DES consts +const + shifts2: array[0..15]of byte= + (0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0); + + des_skb: array[0..7,0..63]of integer=( + ( + (* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 *) + integer($00000000),integer($00000010),integer($20000000),integer($20000010), + integer($00010000),integer($00010010),integer($20010000),integer($20010010), + integer($00000800),integer($00000810),integer($20000800),integer($20000810), + integer($00010800),integer($00010810),integer($20010800),integer($20010810), + integer($00000020),integer($00000030),integer($20000020),integer($20000030), + integer($00010020),integer($00010030),integer($20010020),integer($20010030), + integer($00000820),integer($00000830),integer($20000820),integer($20000830), + integer($00010820),integer($00010830),integer($20010820),integer($20010830), + integer($00080000),integer($00080010),integer($20080000),integer($20080010), + integer($00090000),integer($00090010),integer($20090000),integer($20090010), + integer($00080800),integer($00080810),integer($20080800),integer($20080810), + integer($00090800),integer($00090810),integer($20090800),integer($20090810), + integer($00080020),integer($00080030),integer($20080020),integer($20080030), + integer($00090020),integer($00090030),integer($20090020),integer($20090030), + integer($00080820),integer($00080830),integer($20080820),integer($20080830), + integer($00090820),integer($00090830),integer($20090820),integer($20090830) + ),( + (* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 *) + integer($00000000),integer($02000000),integer($00002000),integer($02002000), + integer($00200000),integer($02200000),integer($00202000),integer($02202000), + integer($00000004),integer($02000004),integer($00002004),integer($02002004), + integer($00200004),integer($02200004),integer($00202004),integer($02202004), + integer($00000400),integer($02000400),integer($00002400),integer($02002400), + integer($00200400),integer($02200400),integer($00202400),integer($02202400), + integer($00000404),integer($02000404),integer($00002404),integer($02002404), + integer($00200404),integer($02200404),integer($00202404),integer($02202404), + integer($10000000),integer($12000000),integer($10002000),integer($12002000), + integer($10200000),integer($12200000),integer($10202000),integer($12202000), + integer($10000004),integer($12000004),integer($10002004),integer($12002004), + integer($10200004),integer($12200004),integer($10202004),integer($12202004), + integer($10000400),integer($12000400),integer($10002400),integer($12002400), + integer($10200400),integer($12200400),integer($10202400),integer($12202400), + integer($10000404),integer($12000404),integer($10002404),integer($12002404), + integer($10200404),integer($12200404),integer($10202404),integer($12202404) + ),( + (* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 *) + integer($00000000),integer($00000001),integer($00040000),integer($00040001), + integer($01000000),integer($01000001),integer($01040000),integer($01040001), + integer($00000002),integer($00000003),integer($00040002),integer($00040003), + integer($01000002),integer($01000003),integer($01040002),integer($01040003), + integer($00000200),integer($00000201),integer($00040200),integer($00040201), + integer($01000200),integer($01000201),integer($01040200),integer($01040201), + integer($00000202),integer($00000203),integer($00040202),integer($00040203), + integer($01000202),integer($01000203),integer($01040202),integer($01040203), + integer($08000000),integer($08000001),integer($08040000),integer($08040001), + integer($09000000),integer($09000001),integer($09040000),integer($09040001), + integer($08000002),integer($08000003),integer($08040002),integer($08040003), + integer($09000002),integer($09000003),integer($09040002),integer($09040003), + integer($08000200),integer($08000201),integer($08040200),integer($08040201), + integer($09000200),integer($09000201),integer($09040200),integer($09040201), + integer($08000202),integer($08000203),integer($08040202),integer($08040203), + integer($09000202),integer($09000203),integer($09040202),integer($09040203) + ),( + (* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 *) + integer($00000000),integer($00100000),integer($00000100),integer($00100100), + integer($00000008),integer($00100008),integer($00000108),integer($00100108), + integer($00001000),integer($00101000),integer($00001100),integer($00101100), + integer($00001008),integer($00101008),integer($00001108),integer($00101108), + integer($04000000),integer($04100000),integer($04000100),integer($04100100), + integer($04000008),integer($04100008),integer($04000108),integer($04100108), + integer($04001000),integer($04101000),integer($04001100),integer($04101100), + integer($04001008),integer($04101008),integer($04001108),integer($04101108), + integer($00020000),integer($00120000),integer($00020100),integer($00120100), + integer($00020008),integer($00120008),integer($00020108),integer($00120108), + integer($00021000),integer($00121000),integer($00021100),integer($00121100), + integer($00021008),integer($00121008),integer($00021108),integer($00121108), + integer($04020000),integer($04120000),integer($04020100),integer($04120100), + integer($04020008),integer($04120008),integer($04020108),integer($04120108), + integer($04021000),integer($04121000),integer($04021100),integer($04121100), + integer($04021008),integer($04121008),integer($04021108),integer($04121108) + ),( + (* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 *) + integer($00000000),integer($10000000),integer($00010000),integer($10010000), + integer($00000004),integer($10000004),integer($00010004),integer($10010004), + integer($20000000),integer($30000000),integer($20010000),integer($30010000), + integer($20000004),integer($30000004),integer($20010004),integer($30010004), + integer($00100000),integer($10100000),integer($00110000),integer($10110000), + integer($00100004),integer($10100004),integer($00110004),integer($10110004), + integer($20100000),integer($30100000),integer($20110000),integer($30110000), + integer($20100004),integer($30100004),integer($20110004),integer($30110004), + integer($00001000),integer($10001000),integer($00011000),integer($10011000), + integer($00001004),integer($10001004),integer($00011004),integer($10011004), + integer($20001000),integer($30001000),integer($20011000),integer($30011000), + integer($20001004),integer($30001004),integer($20011004),integer($30011004), + integer($00101000),integer($10101000),integer($00111000),integer($10111000), + integer($00101004),integer($10101004),integer($00111004),integer($10111004), + integer($20101000),integer($30101000),integer($20111000),integer($30111000), + integer($20101004),integer($30101004),integer($20111004),integer($30111004) + ),( + (* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 *) + integer($00000000),integer($08000000),integer($00000008),integer($08000008), + integer($00000400),integer($08000400),integer($00000408),integer($08000408), + integer($00020000),integer($08020000),integer($00020008),integer($08020008), + integer($00020400),integer($08020400),integer($00020408),integer($08020408), + integer($00000001),integer($08000001),integer($00000009),integer($08000009), + integer($00000401),integer($08000401),integer($00000409),integer($08000409), + integer($00020001),integer($08020001),integer($00020009),integer($08020009), + integer($00020401),integer($08020401),integer($00020409),integer($08020409), + integer($02000000),integer($0A000000),integer($02000008),integer($0A000008), + integer($02000400),integer($0A000400),integer($02000408),integer($0A000408), + integer($02020000),integer($0A020000),integer($02020008),integer($0A020008), + integer($02020400),integer($0A020400),integer($02020408),integer($0A020408), + integer($02000001),integer($0A000001),integer($02000009),integer($0A000009), + integer($02000401),integer($0A000401),integer($02000409),integer($0A000409), + integer($02020001),integer($0A020001),integer($02020009),integer($0A020009), + integer($02020401),integer($0A020401),integer($02020409),integer($0A020409) + ),( + (* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 *) + integer($00000000),integer($00000100),integer($00080000),integer($00080100), + integer($01000000),integer($01000100),integer($01080000),integer($01080100), + integer($00000010),integer($00000110),integer($00080010),integer($00080110), + integer($01000010),integer($01000110),integer($01080010),integer($01080110), + integer($00200000),integer($00200100),integer($00280000),integer($00280100), + integer($01200000),integer($01200100),integer($01280000),integer($01280100), + integer($00200010),integer($00200110),integer($00280010),integer($00280110), + integer($01200010),integer($01200110),integer($01280010),integer($01280110), + integer($00000200),integer($00000300),integer($00080200),integer($00080300), + integer($01000200),integer($01000300),integer($01080200),integer($01080300), + integer($00000210),integer($00000310),integer($00080210),integer($00080310), + integer($01000210),integer($01000310),integer($01080210),integer($01080310), + integer($00200200),integer($00200300),integer($00280200),integer($00280300), + integer($01200200),integer($01200300),integer($01280200),integer($01280300), + integer($00200210),integer($00200310),integer($00280210),integer($00280310), + integer($01200210),integer($01200310),integer($01280210),integer($01280310) + ),( + (* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 *) + integer($00000000),integer($04000000),integer($00040000),integer($04040000), + integer($00000002),integer($04000002),integer($00040002),integer($04040002), + integer($00002000),integer($04002000),integer($00042000),integer($04042000), + integer($00002002),integer($04002002),integer($00042002),integer($04042002), + integer($00000020),integer($04000020),integer($00040020),integer($04040020), + integer($00000022),integer($04000022),integer($00040022),integer($04040022), + integer($00002020),integer($04002020),integer($00042020),integer($04042020), + integer($00002022),integer($04002022),integer($00042022),integer($04042022), + integer($00000800),integer($04000800),integer($00040800),integer($04040800), + integer($00000802),integer($04000802),integer($00040802),integer($04040802), + integer($00002800),integer($04002800),integer($00042800),integer($04042800), + integer($00002802),integer($04002802),integer($00042802),integer($04042802), + integer($00000820),integer($04000820),integer($00040820),integer($04040820), + integer($00000822),integer($04000822),integer($00040822),integer($04040822), + integer($00002820),integer($04002820),integer($00042820),integer($04042820), + integer($00002822),integer($04002822),integer($00042822),integer($04042822) + )); + + des_sptrans: array[0..7,0..63] of integer=( + ( + (* nibble 0 *) + integer($02080800), integer($00080000), integer($02000002), integer($02080802), + integer($02000000), integer($00080802), integer($00080002), integer($02000002), + integer($00080802), integer($02080800), integer($02080000), integer($00000802), + integer($02000802), integer($02000000), integer($00000000), integer($00080002), + integer($00080000), integer($00000002), integer($02000800), integer($00080800), + integer($02080802), integer($02080000), integer($00000802), integer($02000800), + integer($00000002), integer($00000800), integer($00080800), integer($02080002), + integer($00000800), integer($02000802), integer($02080002), integer($00000000), + integer($00000000), integer($02080802), integer($02000800), integer($00080002), + integer($02080800), integer($00080000), integer($00000802), integer($02000800), + integer($02080002), integer($00000800), integer($00080800), integer($02000002), + integer($00080802), integer($00000002), integer($02000002), integer($02080000), + integer($02080802), integer($00080800), integer($02080000), integer($02000802), + integer($02000000), integer($00000802), integer($00080002), integer($00000000), + integer($00080000), integer($02000000), integer($02000802), integer($02080800), + integer($00000002), integer($02080002), integer($00000800), integer($00080802) + ),( + (* nibble 1 *) + integer($40108010), integer($00000000), integer($00108000), integer($40100000), + integer($40000010), integer($00008010), integer($40008000), integer($00108000), + integer($00008000), integer($40100010), integer($00000010), integer($40008000), + integer($00100010), integer($40108000), integer($40100000), integer($00000010), + integer($00100000), integer($40008010), integer($40100010), integer($00008000), + integer($00108010), integer($40000000), integer($00000000), integer($00100010), + integer($40008010), integer($00108010), integer($40108000), integer($40000010), + integer($40000000), integer($00100000), integer($00008010), integer($40108010), + integer($00100010), integer($40108000), integer($40008000), integer($00108010), + integer($40108010), integer($00100010), integer($40000010), integer($00000000), + integer($40000000), integer($00008010), integer($00100000), integer($40100010), + integer($00008000), integer($40000000), integer($00108010), integer($40008010), + integer($40108000), integer($00008000), integer($00000000), integer($40000010), + integer($00000010), integer($40108010), integer($00108000), integer($40100000), + integer($40100010), integer($00100000), integer($00008010), integer($40008000), + integer($40008010), integer($00000010), integer($40100000), integer($00108000) + ),( + (* nibble 2 *) + integer($04000001), integer($04040100), integer($00000100), integer($04000101), + integer($00040001), integer($04000000), integer($04000101), integer($00040100), + integer($04000100), integer($00040000), integer($04040000), integer($00000001), + integer($04040101), integer($00000101), integer($00000001), integer($04040001), + integer($00000000), integer($00040001), integer($04040100), integer($00000100), + integer($00000101), integer($04040101), integer($00040000), integer($04000001), + integer($04040001), integer($04000100), integer($00040101), integer($04040000), + integer($00040100), integer($00000000), integer($04000000), integer($00040101), + integer($04040100), integer($00000100), integer($00000001), integer($00040000), + integer($00000101), integer($00040001), integer($04040000), integer($04000101), + integer($00000000), integer($04040100), integer($00040100), integer($04040001), + integer($00040001), integer($04000000), integer($04040101), integer($00000001), + integer($00040101), integer($04000001), integer($04000000), integer($04040101), + integer($00040000), integer($04000100), integer($04000101), integer($00040100), + integer($04000100), integer($00000000), integer($04040001), integer($00000101), + integer($04000001), integer($00040101), integer($00000100), integer($04040000) + ),( + (* nibble 3 *) + integer($00401008), integer($10001000), integer($00000008), integer($10401008), + integer($00000000), integer($10400000), integer($10001008), integer($00400008), + integer($10401000), integer($10000008), integer($10000000), integer($00001008), + integer($10000008), integer($00401008), integer($00400000), integer($10000000), + integer($10400008), integer($00401000), integer($00001000), integer($00000008), + integer($00401000), integer($10001008), integer($10400000), integer($00001000), + integer($00001008), integer($00000000), integer($00400008), integer($10401000), + integer($10001000), integer($10400008), integer($10401008), integer($00400000), + integer($10400008), integer($00001008), integer($00400000), integer($10000008), + integer($00401000), integer($10001000), integer($00000008), integer($10400000), + integer($10001008), integer($00000000), integer($00001000), integer($00400008), + integer($00000000), integer($10400008), integer($10401000), integer($00001000), + integer($10000000), integer($10401008), integer($00401008), integer($00400000), + integer($10401008), integer($00000008), integer($10001000), integer($00401008), + integer($00400008), integer($00401000), integer($10400000), integer($10001008), + integer($00001008), integer($10000000), integer($10000008), integer($10401000) + ),( + (* nibble 4 *) + integer($08000000), integer($00010000), integer($00000400), integer($08010420), + integer($08010020), integer($08000400), integer($00010420), integer($08010000), + integer($00010000), integer($00000020), integer($08000020), integer($00010400), + integer($08000420), integer($08010020), integer($08010400), integer($00000000), + integer($00010400), integer($08000000), integer($00010020), integer($00000420), + integer($08000400), integer($00010420), integer($00000000), integer($08000020), + integer($00000020), integer($08000420), integer($08010420), integer($00010020), + integer($08010000), integer($00000400), integer($00000420), integer($08010400), + integer($08010400), integer($08000420), integer($00010020), integer($08010000), + integer($00010000), integer($00000020), integer($08000020), integer($08000400), + integer($08000000), integer($00010400), integer($08010420), integer($00000000), + integer($00010420), integer($08000000), integer($00000400), integer($00010020), + integer($08000420), integer($00000400), integer($00000000), integer($08010420), + integer($08010020), integer($08010400), integer($00000420), integer($00010000), + integer($00010400), integer($08010020), integer($08000400), integer($00000420), + integer($00000020), integer($00010420), integer($08010000), integer($08000020) + ),( + (* nibble 5 *) + integer($80000040), integer($00200040), integer($00000000), integer($80202000), + integer($00200040), integer($00002000), integer($80002040), integer($00200000), + integer($00002040), integer($80202040), integer($00202000), integer($80000000), + integer($80002000), integer($80000040), integer($80200000), integer($00202040), + integer($00200000), integer($80002040), integer($80200040), integer($00000000), + integer($00002000), integer($00000040), integer($80202000), integer($80200040), + integer($80202040), integer($80200000), integer($80000000), integer($00002040), + integer($00000040), integer($00202000), integer($00202040), integer($80002000), + integer($00002040), integer($80000000), integer($80002000), integer($00202040), + integer($80202000), integer($00200040), integer($00000000), integer($80002000), + integer($80000000), integer($00002000), integer($80200040), integer($00200000), + integer($00200040), integer($80202040), integer($00202000), integer($00000040), + integer($80202040), integer($00202000), integer($00200000), integer($80002040), + integer($80000040), integer($80200000), integer($00202040), integer($00000000), + integer($00002000), integer($80000040), integer($80002040), integer($80202000), + integer($80200000), integer($00002040), integer($00000040), integer($80200040) + ),( + (* nibble 6 *) + integer($00004000), integer($00000200), integer($01000200), integer($01000004), + integer($01004204), integer($00004004), integer($00004200), integer($00000000), + integer($01000000), integer($01000204), integer($00000204), integer($01004000), + integer($00000004), integer($01004200), integer($01004000), integer($00000204), + integer($01000204), integer($00004000), integer($00004004), integer($01004204), + integer($00000000), integer($01000200), integer($01000004), integer($00004200), + integer($01004004), integer($00004204), integer($01004200), integer($00000004), + integer($00004204), integer($01004004), integer($00000200), integer($01000000), + integer($00004204), integer($01004000), integer($01004004), integer($00000204), + integer($00004000), integer($00000200), integer($01000000), integer($01004004), + integer($01000204), integer($00004204), integer($00004200), integer($00000000), + integer($00000200), integer($01000004), integer($00000004), integer($01000200), + integer($00000000), integer($01000204), integer($01000200), integer($00004200), + integer($00000204), integer($00004000), integer($01004204), integer($01000000), + integer($01004200), integer($00000004), integer($00004004), integer($01004204), + integer($01000004), integer($01004200), integer($01004000), integer($00004004) + ),( + (* nibble 7 *) + integer($20800080), integer($20820000), integer($00020080), integer($00000000), + integer($20020000), integer($00800080), integer($20800000), integer($20820080), + integer($00000080), integer($20000000), integer($00820000), integer($00020080), + integer($00820080), integer($20020080), integer($20000080), integer($20800000), + integer($00020000), integer($00820080), integer($00800080), integer($20020000), + integer($20820080), integer($20000080), integer($00000000), integer($00820000), + integer($20000000), integer($00800000), integer($20020080), integer($20800080), + integer($00800000), integer($00020000), integer($20820000), integer($00000080), + integer($00800000), integer($00020000), integer($20000080), integer($20820080), + integer($00020080), integer($20000000), integer($00000000), integer($00820000), + integer($20800080), integer($20020080), integer($20020000), integer($00800080), + integer($20820000), integer($00000080), integer($00800080), integer($20020000), + integer($20820080), integer($00800000), integer($20800000), integer($20000080), + integer($00820000), integer($00020080), integer($20020080), integer($20800000), + integer($00000080), integer($20820000), integer($00820080), integer($00000000), + integer($20000000), integer($20800080), integer($00020000), integer($00820080) + )); + +//AES consts +const + MAXBC= 8; + MAXKC= 8; + + S: array[0..255] of byte= ( + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, + 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, + 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, + 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, + 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, + 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, + 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, + 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22); + T1: array[0..255,0..3] of byte= ( + ($c6,$63,$63,$a5), ($f8,$7c,$7c,$84), ($ee,$77,$77,$99), ($f6,$7b,$7b,$8d), + ($ff,$f2,$f2,$0d), ($d6,$6b,$6b,$bd), ($de,$6f,$6f,$b1), ($91,$c5,$c5,$54), + ($60,$30,$30,$50), ($02,$01,$01,$03), ($ce,$67,$67,$a9), ($56,$2b,$2b,$7d), + ($e7,$fe,$fe,$19), ($b5,$d7,$d7,$62), ($4d,$ab,$ab,$e6), ($ec,$76,$76,$9a), + ($8f,$ca,$ca,$45), ($1f,$82,$82,$9d), ($89,$c9,$c9,$40), ($fa,$7d,$7d,$87), + ($ef,$fa,$fa,$15), ($b2,$59,$59,$eb), ($8e,$47,$47,$c9), ($fb,$f0,$f0,$0b), + ($41,$ad,$ad,$ec), ($b3,$d4,$d4,$67), ($5f,$a2,$a2,$fd), ($45,$af,$af,$ea), + ($23,$9c,$9c,$bf), ($53,$a4,$a4,$f7), ($e4,$72,$72,$96), ($9b,$c0,$c0,$5b), + ($75,$b7,$b7,$c2), ($e1,$fd,$fd,$1c), ($3d,$93,$93,$ae), ($4c,$26,$26,$6a), + ($6c,$36,$36,$5a), ($7e,$3f,$3f,$41), ($f5,$f7,$f7,$02), ($83,$cc,$cc,$4f), + ($68,$34,$34,$5c), ($51,$a5,$a5,$f4), ($d1,$e5,$e5,$34), ($f9,$f1,$f1,$08), + ($e2,$71,$71,$93), ($ab,$d8,$d8,$73), ($62,$31,$31,$53), ($2a,$15,$15,$3f), + ($08,$04,$04,$0c), ($95,$c7,$c7,$52), ($46,$23,$23,$65), ($9d,$c3,$c3,$5e), + ($30,$18,$18,$28), ($37,$96,$96,$a1), ($0a,$05,$05,$0f), ($2f,$9a,$9a,$b5), + ($0e,$07,$07,$09), ($24,$12,$12,$36), ($1b,$80,$80,$9b), ($df,$e2,$e2,$3d), + ($cd,$eb,$eb,$26), ($4e,$27,$27,$69), ($7f,$b2,$b2,$cd), ($ea,$75,$75,$9f), + ($12,$09,$09,$1b), ($1d,$83,$83,$9e), ($58,$2c,$2c,$74), ($34,$1a,$1a,$2e), + ($36,$1b,$1b,$2d), ($dc,$6e,$6e,$b2), ($b4,$5a,$5a,$ee), ($5b,$a0,$a0,$fb), + ($a4,$52,$52,$f6), ($76,$3b,$3b,$4d), ($b7,$d6,$d6,$61), ($7d,$b3,$b3,$ce), + ($52,$29,$29,$7b), ($dd,$e3,$e3,$3e), ($5e,$2f,$2f,$71), ($13,$84,$84,$97), + ($a6,$53,$53,$f5), ($b9,$d1,$d1,$68), ($00,$00,$00,$00), ($c1,$ed,$ed,$2c), + ($40,$20,$20,$60), ($e3,$fc,$fc,$1f), ($79,$b1,$b1,$c8), ($b6,$5b,$5b,$ed), + ($d4,$6a,$6a,$be), ($8d,$cb,$cb,$46), ($67,$be,$be,$d9), ($72,$39,$39,$4b), + ($94,$4a,$4a,$de), ($98,$4c,$4c,$d4), ($b0,$58,$58,$e8), ($85,$cf,$cf,$4a), + ($bb,$d0,$d0,$6b), ($c5,$ef,$ef,$2a), ($4f,$aa,$aa,$e5), ($ed,$fb,$fb,$16), + ($86,$43,$43,$c5), ($9a,$4d,$4d,$d7), ($66,$33,$33,$55), ($11,$85,$85,$94), + ($8a,$45,$45,$cf), ($e9,$f9,$f9,$10), ($04,$02,$02,$06), ($fe,$7f,$7f,$81), + ($a0,$50,$50,$f0), ($78,$3c,$3c,$44), ($25,$9f,$9f,$ba), ($4b,$a8,$a8,$e3), + ($a2,$51,$51,$f3), ($5d,$a3,$a3,$fe), ($80,$40,$40,$c0), ($05,$8f,$8f,$8a), + ($3f,$92,$92,$ad), ($21,$9d,$9d,$bc), ($70,$38,$38,$48), ($f1,$f5,$f5,$04), + ($63,$bc,$bc,$df), ($77,$b6,$b6,$c1), ($af,$da,$da,$75), ($42,$21,$21,$63), + ($20,$10,$10,$30), ($e5,$ff,$ff,$1a), ($fd,$f3,$f3,$0e), ($bf,$d2,$d2,$6d), + ($81,$cd,$cd,$4c), ($18,$0c,$0c,$14), ($26,$13,$13,$35), ($c3,$ec,$ec,$2f), + ($be,$5f,$5f,$e1), ($35,$97,$97,$a2), ($88,$44,$44,$cc), ($2e,$17,$17,$39), + ($93,$c4,$c4,$57), ($55,$a7,$a7,$f2), ($fc,$7e,$7e,$82), ($7a,$3d,$3d,$47), + ($c8,$64,$64,$ac), ($ba,$5d,$5d,$e7), ($32,$19,$19,$2b), ($e6,$73,$73,$95), + ($c0,$60,$60,$a0), ($19,$81,$81,$98), ($9e,$4f,$4f,$d1), ($a3,$dc,$dc,$7f), + ($44,$22,$22,$66), ($54,$2a,$2a,$7e), ($3b,$90,$90,$ab), ($0b,$88,$88,$83), + ($8c,$46,$46,$ca), ($c7,$ee,$ee,$29), ($6b,$b8,$b8,$d3), ($28,$14,$14,$3c), + ($a7,$de,$de,$79), ($bc,$5e,$5e,$e2), ($16,$0b,$0b,$1d), ($ad,$db,$db,$76), + ($db,$e0,$e0,$3b), ($64,$32,$32,$56), ($74,$3a,$3a,$4e), ($14,$0a,$0a,$1e), + ($92,$49,$49,$db), ($0c,$06,$06,$0a), ($48,$24,$24,$6c), ($b8,$5c,$5c,$e4), + ($9f,$c2,$c2,$5d), ($bd,$d3,$d3,$6e), ($43,$ac,$ac,$ef), ($c4,$62,$62,$a6), + ($39,$91,$91,$a8), ($31,$95,$95,$a4), ($d3,$e4,$e4,$37), ($f2,$79,$79,$8b), + ($d5,$e7,$e7,$32), ($8b,$c8,$c8,$43), ($6e,$37,$37,$59), ($da,$6d,$6d,$b7), + ($01,$8d,$8d,$8c), ($b1,$d5,$d5,$64), ($9c,$4e,$4e,$d2), ($49,$a9,$a9,$e0), + ($d8,$6c,$6c,$b4), ($ac,$56,$56,$fa), ($f3,$f4,$f4,$07), ($cf,$ea,$ea,$25), + ($ca,$65,$65,$af), ($f4,$7a,$7a,$8e), ($47,$ae,$ae,$e9), ($10,$08,$08,$18), + ($6f,$ba,$ba,$d5), ($f0,$78,$78,$88), ($4a,$25,$25,$6f), ($5c,$2e,$2e,$72), + ($38,$1c,$1c,$24), ($57,$a6,$a6,$f1), ($73,$b4,$b4,$c7), ($97,$c6,$c6,$51), + ($cb,$e8,$e8,$23), ($a1,$dd,$dd,$7c), ($e8,$74,$74,$9c), ($3e,$1f,$1f,$21), + ($96,$4b,$4b,$dd), ($61,$bd,$bd,$dc), ($0d,$8b,$8b,$86), ($0f,$8a,$8a,$85), + ($e0,$70,$70,$90), ($7c,$3e,$3e,$42), ($71,$b5,$b5,$c4), ($cc,$66,$66,$aa), + ($90,$48,$48,$d8), ($06,$03,$03,$05), ($f7,$f6,$f6,$01), ($1c,$0e,$0e,$12), + ($c2,$61,$61,$a3), ($6a,$35,$35,$5f), ($ae,$57,$57,$f9), ($69,$b9,$b9,$d0), + ($17,$86,$86,$91), ($99,$c1,$c1,$58), ($3a,$1d,$1d,$27), ($27,$9e,$9e,$b9), + ($d9,$e1,$e1,$38), ($eb,$f8,$f8,$13), ($2b,$98,$98,$b3), ($22,$11,$11,$33), + ($d2,$69,$69,$bb), ($a9,$d9,$d9,$70), ($07,$8e,$8e,$89), ($33,$94,$94,$a7), + ($2d,$9b,$9b,$b6), ($3c,$1e,$1e,$22), ($15,$87,$87,$92), ($c9,$e9,$e9,$20), + ($87,$ce,$ce,$49), ($aa,$55,$55,$ff), ($50,$28,$28,$78), ($a5,$df,$df,$7a), + ($03,$8c,$8c,$8f), ($59,$a1,$a1,$f8), ($09,$89,$89,$80), ($1a,$0d,$0d,$17), + ($65,$bf,$bf,$da), ($d7,$e6,$e6,$31), ($84,$42,$42,$c6), ($d0,$68,$68,$b8), + ($82,$41,$41,$c3), ($29,$99,$99,$b0), ($5a,$2d,$2d,$77), ($1e,$0f,$0f,$11), + ($7b,$b0,$b0,$cb), ($a8,$54,$54,$fc), ($6d,$bb,$bb,$d6), ($2c,$16,$16,$3a)); + T2: array[0..255,0..3] of byte= ( + ($a5,$c6,$63,$63), ($84,$f8,$7c,$7c), ($99,$ee,$77,$77), ($8d,$f6,$7b,$7b), + ($0d,$ff,$f2,$f2), ($bd,$d6,$6b,$6b), ($b1,$de,$6f,$6f), ($54,$91,$c5,$c5), + ($50,$60,$30,$30), ($03,$02,$01,$01), ($a9,$ce,$67,$67), ($7d,$56,$2b,$2b), + ($19,$e7,$fe,$fe), ($62,$b5,$d7,$d7), ($e6,$4d,$ab,$ab), ($9a,$ec,$76,$76), + ($45,$8f,$ca,$ca), ($9d,$1f,$82,$82), ($40,$89,$c9,$c9), ($87,$fa,$7d,$7d), + ($15,$ef,$fa,$fa), ($eb,$b2,$59,$59), ($c9,$8e,$47,$47), ($0b,$fb,$f0,$f0), + ($ec,$41,$ad,$ad), ($67,$b3,$d4,$d4), ($fd,$5f,$a2,$a2), ($ea,$45,$af,$af), + ($bf,$23,$9c,$9c), ($f7,$53,$a4,$a4), ($96,$e4,$72,$72), ($5b,$9b,$c0,$c0), + ($c2,$75,$b7,$b7), ($1c,$e1,$fd,$fd), ($ae,$3d,$93,$93), ($6a,$4c,$26,$26), + ($5a,$6c,$36,$36), ($41,$7e,$3f,$3f), ($02,$f5,$f7,$f7), ($4f,$83,$cc,$cc), + ($5c,$68,$34,$34), ($f4,$51,$a5,$a5), ($34,$d1,$e5,$e5), ($08,$f9,$f1,$f1), + ($93,$e2,$71,$71), ($73,$ab,$d8,$d8), ($53,$62,$31,$31), ($3f,$2a,$15,$15), + ($0c,$08,$04,$04), ($52,$95,$c7,$c7), ($65,$46,$23,$23), ($5e,$9d,$c3,$c3), + ($28,$30,$18,$18), ($a1,$37,$96,$96), ($0f,$0a,$05,$05), ($b5,$2f,$9a,$9a), + ($09,$0e,$07,$07), ($36,$24,$12,$12), ($9b,$1b,$80,$80), ($3d,$df,$e2,$e2), + ($26,$cd,$eb,$eb), ($69,$4e,$27,$27), ($cd,$7f,$b2,$b2), ($9f,$ea,$75,$75), + ($1b,$12,$09,$09), ($9e,$1d,$83,$83), ($74,$58,$2c,$2c), ($2e,$34,$1a,$1a), + ($2d,$36,$1b,$1b), ($b2,$dc,$6e,$6e), ($ee,$b4,$5a,$5a), ($fb,$5b,$a0,$a0), + ($f6,$a4,$52,$52), ($4d,$76,$3b,$3b), ($61,$b7,$d6,$d6), ($ce,$7d,$b3,$b3), + ($7b,$52,$29,$29), ($3e,$dd,$e3,$e3), ($71,$5e,$2f,$2f), ($97,$13,$84,$84), + ($f5,$a6,$53,$53), ($68,$b9,$d1,$d1), ($00,$00,$00,$00), ($2c,$c1,$ed,$ed), + ($60,$40,$20,$20), ($1f,$e3,$fc,$fc), ($c8,$79,$b1,$b1), ($ed,$b6,$5b,$5b), + ($be,$d4,$6a,$6a), ($46,$8d,$cb,$cb), ($d9,$67,$be,$be), ($4b,$72,$39,$39), + ($de,$94,$4a,$4a), ($d4,$98,$4c,$4c), ($e8,$b0,$58,$58), ($4a,$85,$cf,$cf), + ($6b,$bb,$d0,$d0), ($2a,$c5,$ef,$ef), ($e5,$4f,$aa,$aa), ($16,$ed,$fb,$fb), + ($c5,$86,$43,$43), ($d7,$9a,$4d,$4d), ($55,$66,$33,$33), ($94,$11,$85,$85), + ($cf,$8a,$45,$45), ($10,$e9,$f9,$f9), ($06,$04,$02,$02), ($81,$fe,$7f,$7f), + ($f0,$a0,$50,$50), ($44,$78,$3c,$3c), ($ba,$25,$9f,$9f), ($e3,$4b,$a8,$a8), + ($f3,$a2,$51,$51), ($fe,$5d,$a3,$a3), ($c0,$80,$40,$40), ($8a,$05,$8f,$8f), + ($ad,$3f,$92,$92), ($bc,$21,$9d,$9d), ($48,$70,$38,$38), ($04,$f1,$f5,$f5), + ($df,$63,$bc,$bc), ($c1,$77,$b6,$b6), ($75,$af,$da,$da), ($63,$42,$21,$21), + ($30,$20,$10,$10), ($1a,$e5,$ff,$ff), ($0e,$fd,$f3,$f3), ($6d,$bf,$d2,$d2), + ($4c,$81,$cd,$cd), ($14,$18,$0c,$0c), ($35,$26,$13,$13), ($2f,$c3,$ec,$ec), + ($e1,$be,$5f,$5f), ($a2,$35,$97,$97), ($cc,$88,$44,$44), ($39,$2e,$17,$17), + ($57,$93,$c4,$c4), ($f2,$55,$a7,$a7), ($82,$fc,$7e,$7e), ($47,$7a,$3d,$3d), + ($ac,$c8,$64,$64), ($e7,$ba,$5d,$5d), ($2b,$32,$19,$19), ($95,$e6,$73,$73), + ($a0,$c0,$60,$60), ($98,$19,$81,$81), ($d1,$9e,$4f,$4f), ($7f,$a3,$dc,$dc), + ($66,$44,$22,$22), ($7e,$54,$2a,$2a), ($ab,$3b,$90,$90), ($83,$0b,$88,$88), + ($ca,$8c,$46,$46), ($29,$c7,$ee,$ee), ($d3,$6b,$b8,$b8), ($3c,$28,$14,$14), + ($79,$a7,$de,$de), ($e2,$bc,$5e,$5e), ($1d,$16,$0b,$0b), ($76,$ad,$db,$db), + ($3b,$db,$e0,$e0), ($56,$64,$32,$32), ($4e,$74,$3a,$3a), ($1e,$14,$0a,$0a), + ($db,$92,$49,$49), ($0a,$0c,$06,$06), ($6c,$48,$24,$24), ($e4,$b8,$5c,$5c), + ($5d,$9f,$c2,$c2), ($6e,$bd,$d3,$d3), ($ef,$43,$ac,$ac), ($a6,$c4,$62,$62), + ($a8,$39,$91,$91), ($a4,$31,$95,$95), ($37,$d3,$e4,$e4), ($8b,$f2,$79,$79), + ($32,$d5,$e7,$e7), ($43,$8b,$c8,$c8), ($59,$6e,$37,$37), ($b7,$da,$6d,$6d), + ($8c,$01,$8d,$8d), ($64,$b1,$d5,$d5), ($d2,$9c,$4e,$4e), ($e0,$49,$a9,$a9), + ($b4,$d8,$6c,$6c), ($fa,$ac,$56,$56), ($07,$f3,$f4,$f4), ($25,$cf,$ea,$ea), + ($af,$ca,$65,$65), ($8e,$f4,$7a,$7a), ($e9,$47,$ae,$ae), ($18,$10,$08,$08), + ($d5,$6f,$ba,$ba), ($88,$f0,$78,$78), ($6f,$4a,$25,$25), ($72,$5c,$2e,$2e), + ($24,$38,$1c,$1c), ($f1,$57,$a6,$a6), ($c7,$73,$b4,$b4), ($51,$97,$c6,$c6), + ($23,$cb,$e8,$e8), ($7c,$a1,$dd,$dd), ($9c,$e8,$74,$74), ($21,$3e,$1f,$1f), + ($dd,$96,$4b,$4b), ($dc,$61,$bd,$bd), ($86,$0d,$8b,$8b), ($85,$0f,$8a,$8a), + ($90,$e0,$70,$70), ($42,$7c,$3e,$3e), ($c4,$71,$b5,$b5), ($aa,$cc,$66,$66), + ($d8,$90,$48,$48), ($05,$06,$03,$03), ($01,$f7,$f6,$f6), ($12,$1c,$0e,$0e), + ($a3,$c2,$61,$61), ($5f,$6a,$35,$35), ($f9,$ae,$57,$57), ($d0,$69,$b9,$b9), + ($91,$17,$86,$86), ($58,$99,$c1,$c1), ($27,$3a,$1d,$1d), ($b9,$27,$9e,$9e), + ($38,$d9,$e1,$e1), ($13,$eb,$f8,$f8), ($b3,$2b,$98,$98), ($33,$22,$11,$11), + ($bb,$d2,$69,$69), ($70,$a9,$d9,$d9), ($89,$07,$8e,$8e), ($a7,$33,$94,$94), + ($b6,$2d,$9b,$9b), ($22,$3c,$1e,$1e), ($92,$15,$87,$87), ($20,$c9,$e9,$e9), + ($49,$87,$ce,$ce), ($ff,$aa,$55,$55), ($78,$50,$28,$28), ($7a,$a5,$df,$df), + ($8f,$03,$8c,$8c), ($f8,$59,$a1,$a1), ($80,$09,$89,$89), ($17,$1a,$0d,$0d), + ($da,$65,$bf,$bf), ($31,$d7,$e6,$e6), ($c6,$84,$42,$42), ($b8,$d0,$68,$68), + ($c3,$82,$41,$41), ($b0,$29,$99,$99), ($77,$5a,$2d,$2d), ($11,$1e,$0f,$0f), + ($cb,$7b,$b0,$b0), ($fc,$a8,$54,$54), ($d6,$6d,$bb,$bb), ($3a,$2c,$16,$16)); + T3: array[0..255,0..3] of byte= ( + ($63,$a5,$c6,$63), ($7c,$84,$f8,$7c), ($77,$99,$ee,$77), ($7b,$8d,$f6,$7b), + ($f2,$0d,$ff,$f2), ($6b,$bd,$d6,$6b), ($6f,$b1,$de,$6f), ($c5,$54,$91,$c5), + ($30,$50,$60,$30), ($01,$03,$02,$01), ($67,$a9,$ce,$67), ($2b,$7d,$56,$2b), + ($fe,$19,$e7,$fe), ($d7,$62,$b5,$d7), ($ab,$e6,$4d,$ab), ($76,$9a,$ec,$76), + ($ca,$45,$8f,$ca), ($82,$9d,$1f,$82), ($c9,$40,$89,$c9), ($7d,$87,$fa,$7d), + ($fa,$15,$ef,$fa), ($59,$eb,$b2,$59), ($47,$c9,$8e,$47), ($f0,$0b,$fb,$f0), + ($ad,$ec,$41,$ad), ($d4,$67,$b3,$d4), ($a2,$fd,$5f,$a2), ($af,$ea,$45,$af), + ($9c,$bf,$23,$9c), ($a4,$f7,$53,$a4), ($72,$96,$e4,$72), ($c0,$5b,$9b,$c0), + ($b7,$c2,$75,$b7), ($fd,$1c,$e1,$fd), ($93,$ae,$3d,$93), ($26,$6a,$4c,$26), + ($36,$5a,$6c,$36), ($3f,$41,$7e,$3f), ($f7,$02,$f5,$f7), ($cc,$4f,$83,$cc), + ($34,$5c,$68,$34), ($a5,$f4,$51,$a5), ($e5,$34,$d1,$e5), ($f1,$08,$f9,$f1), + ($71,$93,$e2,$71), ($d8,$73,$ab,$d8), ($31,$53,$62,$31), ($15,$3f,$2a,$15), + ($04,$0c,$08,$04), ($c7,$52,$95,$c7), ($23,$65,$46,$23), ($c3,$5e,$9d,$c3), + ($18,$28,$30,$18), ($96,$a1,$37,$96), ($05,$0f,$0a,$05), ($9a,$b5,$2f,$9a), + ($07,$09,$0e,$07), ($12,$36,$24,$12), ($80,$9b,$1b,$80), ($e2,$3d,$df,$e2), + ($eb,$26,$cd,$eb), ($27,$69,$4e,$27), ($b2,$cd,$7f,$b2), ($75,$9f,$ea,$75), + ($09,$1b,$12,$09), ($83,$9e,$1d,$83), ($2c,$74,$58,$2c), ($1a,$2e,$34,$1a), + ($1b,$2d,$36,$1b), ($6e,$b2,$dc,$6e), ($5a,$ee,$b4,$5a), ($a0,$fb,$5b,$a0), + ($52,$f6,$a4,$52), ($3b,$4d,$76,$3b), ($d6,$61,$b7,$d6), ($b3,$ce,$7d,$b3), + ($29,$7b,$52,$29), ($e3,$3e,$dd,$e3), ($2f,$71,$5e,$2f), ($84,$97,$13,$84), + ($53,$f5,$a6,$53), ($d1,$68,$b9,$d1), ($00,$00,$00,$00), ($ed,$2c,$c1,$ed), + ($20,$60,$40,$20), ($fc,$1f,$e3,$fc), ($b1,$c8,$79,$b1), ($5b,$ed,$b6,$5b), + ($6a,$be,$d4,$6a), ($cb,$46,$8d,$cb), ($be,$d9,$67,$be), ($39,$4b,$72,$39), + ($4a,$de,$94,$4a), ($4c,$d4,$98,$4c), ($58,$e8,$b0,$58), ($cf,$4a,$85,$cf), + ($d0,$6b,$bb,$d0), ($ef,$2a,$c5,$ef), ($aa,$e5,$4f,$aa), ($fb,$16,$ed,$fb), + ($43,$c5,$86,$43), ($4d,$d7,$9a,$4d), ($33,$55,$66,$33), ($85,$94,$11,$85), + ($45,$cf,$8a,$45), ($f9,$10,$e9,$f9), ($02,$06,$04,$02), ($7f,$81,$fe,$7f), + ($50,$f0,$a0,$50), ($3c,$44,$78,$3c), ($9f,$ba,$25,$9f), ($a8,$e3,$4b,$a8), + ($51,$f3,$a2,$51), ($a3,$fe,$5d,$a3), ($40,$c0,$80,$40), ($8f,$8a,$05,$8f), + ($92,$ad,$3f,$92), ($9d,$bc,$21,$9d), ($38,$48,$70,$38), ($f5,$04,$f1,$f5), + ($bc,$df,$63,$bc), ($b6,$c1,$77,$b6), ($da,$75,$af,$da), ($21,$63,$42,$21), + ($10,$30,$20,$10), ($ff,$1a,$e5,$ff), ($f3,$0e,$fd,$f3), ($d2,$6d,$bf,$d2), + ($cd,$4c,$81,$cd), ($0c,$14,$18,$0c), ($13,$35,$26,$13), ($ec,$2f,$c3,$ec), + ($5f,$e1,$be,$5f), ($97,$a2,$35,$97), ($44,$cc,$88,$44), ($17,$39,$2e,$17), + ($c4,$57,$93,$c4), ($a7,$f2,$55,$a7), ($7e,$82,$fc,$7e), ($3d,$47,$7a,$3d), + ($64,$ac,$c8,$64), ($5d,$e7,$ba,$5d), ($19,$2b,$32,$19), ($73,$95,$e6,$73), + ($60,$a0,$c0,$60), ($81,$98,$19,$81), ($4f,$d1,$9e,$4f), ($dc,$7f,$a3,$dc), + ($22,$66,$44,$22), ($2a,$7e,$54,$2a), ($90,$ab,$3b,$90), ($88,$83,$0b,$88), + ($46,$ca,$8c,$46), ($ee,$29,$c7,$ee), ($b8,$d3,$6b,$b8), ($14,$3c,$28,$14), + ($de,$79,$a7,$de), ($5e,$e2,$bc,$5e), ($0b,$1d,$16,$0b), ($db,$76,$ad,$db), + ($e0,$3b,$db,$e0), ($32,$56,$64,$32), ($3a,$4e,$74,$3a), ($0a,$1e,$14,$0a), + ($49,$db,$92,$49), ($06,$0a,$0c,$06), ($24,$6c,$48,$24), ($5c,$e4,$b8,$5c), + ($c2,$5d,$9f,$c2), ($d3,$6e,$bd,$d3), ($ac,$ef,$43,$ac), ($62,$a6,$c4,$62), + ($91,$a8,$39,$91), ($95,$a4,$31,$95), ($e4,$37,$d3,$e4), ($79,$8b,$f2,$79), + ($e7,$32,$d5,$e7), ($c8,$43,$8b,$c8), ($37,$59,$6e,$37), ($6d,$b7,$da,$6d), + ($8d,$8c,$01,$8d), ($d5,$64,$b1,$d5), ($4e,$d2,$9c,$4e), ($a9,$e0,$49,$a9), + ($6c,$b4,$d8,$6c), ($56,$fa,$ac,$56), ($f4,$07,$f3,$f4), ($ea,$25,$cf,$ea), + ($65,$af,$ca,$65), ($7a,$8e,$f4,$7a), ($ae,$e9,$47,$ae), ($08,$18,$10,$08), + ($ba,$d5,$6f,$ba), ($78,$88,$f0,$78), ($25,$6f,$4a,$25), ($2e,$72,$5c,$2e), + ($1c,$24,$38,$1c), ($a6,$f1,$57,$a6), ($b4,$c7,$73,$b4), ($c6,$51,$97,$c6), + ($e8,$23,$cb,$e8), ($dd,$7c,$a1,$dd), ($74,$9c,$e8,$74), ($1f,$21,$3e,$1f), + ($4b,$dd,$96,$4b), ($bd,$dc,$61,$bd), ($8b,$86,$0d,$8b), ($8a,$85,$0f,$8a), + ($70,$90,$e0,$70), ($3e,$42,$7c,$3e), ($b5,$c4,$71,$b5), ($66,$aa,$cc,$66), + ($48,$d8,$90,$48), ($03,$05,$06,$03), ($f6,$01,$f7,$f6), ($0e,$12,$1c,$0e), + ($61,$a3,$c2,$61), ($35,$5f,$6a,$35), ($57,$f9,$ae,$57), ($b9,$d0,$69,$b9), + ($86,$91,$17,$86), ($c1,$58,$99,$c1), ($1d,$27,$3a,$1d), ($9e,$b9,$27,$9e), + ($e1,$38,$d9,$e1), ($f8,$13,$eb,$f8), ($98,$b3,$2b,$98), ($11,$33,$22,$11), + ($69,$bb,$d2,$69), ($d9,$70,$a9,$d9), ($8e,$89,$07,$8e), ($94,$a7,$33,$94), + ($9b,$b6,$2d,$9b), ($1e,$22,$3c,$1e), ($87,$92,$15,$87), ($e9,$20,$c9,$e9), + ($ce,$49,$87,$ce), ($55,$ff,$aa,$55), ($28,$78,$50,$28), ($df,$7a,$a5,$df), + ($8c,$8f,$03,$8c), ($a1,$f8,$59,$a1), ($89,$80,$09,$89), ($0d,$17,$1a,$0d), + ($bf,$da,$65,$bf), ($e6,$31,$d7,$e6), ($42,$c6,$84,$42), ($68,$b8,$d0,$68), + ($41,$c3,$82,$41), ($99,$b0,$29,$99), ($2d,$77,$5a,$2d), ($0f,$11,$1e,$0f), + ($b0,$cb,$7b,$b0), ($54,$fc,$a8,$54), ($bb,$d6,$6d,$bb), ($16,$3a,$2c,$16)); + T4: array[0..255,0..3] of byte= ( + ($63,$63,$a5,$c6), ($7c,$7c,$84,$f8), ($77,$77,$99,$ee), ($7b,$7b,$8d,$f6), + ($f2,$f2,$0d,$ff), ($6b,$6b,$bd,$d6), ($6f,$6f,$b1,$de), ($c5,$c5,$54,$91), + ($30,$30,$50,$60), ($01,$01,$03,$02), ($67,$67,$a9,$ce), ($2b,$2b,$7d,$56), + ($fe,$fe,$19,$e7), ($d7,$d7,$62,$b5), ($ab,$ab,$e6,$4d), ($76,$76,$9a,$ec), + ($ca,$ca,$45,$8f), ($82,$82,$9d,$1f), ($c9,$c9,$40,$89), ($7d,$7d,$87,$fa), + ($fa,$fa,$15,$ef), ($59,$59,$eb,$b2), ($47,$47,$c9,$8e), ($f0,$f0,$0b,$fb), + ($ad,$ad,$ec,$41), ($d4,$d4,$67,$b3), ($a2,$a2,$fd,$5f), ($af,$af,$ea,$45), + ($9c,$9c,$bf,$23), ($a4,$a4,$f7,$53), ($72,$72,$96,$e4), ($c0,$c0,$5b,$9b), + ($b7,$b7,$c2,$75), ($fd,$fd,$1c,$e1), ($93,$93,$ae,$3d), ($26,$26,$6a,$4c), + ($36,$36,$5a,$6c), ($3f,$3f,$41,$7e), ($f7,$f7,$02,$f5), ($cc,$cc,$4f,$83), + ($34,$34,$5c,$68), ($a5,$a5,$f4,$51), ($e5,$e5,$34,$d1), ($f1,$f1,$08,$f9), + ($71,$71,$93,$e2), ($d8,$d8,$73,$ab), ($31,$31,$53,$62), ($15,$15,$3f,$2a), + ($04,$04,$0c,$08), ($c7,$c7,$52,$95), ($23,$23,$65,$46), ($c3,$c3,$5e,$9d), + ($18,$18,$28,$30), ($96,$96,$a1,$37), ($05,$05,$0f,$0a), ($9a,$9a,$b5,$2f), + ($07,$07,$09,$0e), ($12,$12,$36,$24), ($80,$80,$9b,$1b), ($e2,$e2,$3d,$df), + ($eb,$eb,$26,$cd), ($27,$27,$69,$4e), ($b2,$b2,$cd,$7f), ($75,$75,$9f,$ea), + ($09,$09,$1b,$12), ($83,$83,$9e,$1d), ($2c,$2c,$74,$58), ($1a,$1a,$2e,$34), + ($1b,$1b,$2d,$36), ($6e,$6e,$b2,$dc), ($5a,$5a,$ee,$b4), ($a0,$a0,$fb,$5b), + ($52,$52,$f6,$a4), ($3b,$3b,$4d,$76), ($d6,$d6,$61,$b7), ($b3,$b3,$ce,$7d), + ($29,$29,$7b,$52), ($e3,$e3,$3e,$dd), ($2f,$2f,$71,$5e), ($84,$84,$97,$13), + ($53,$53,$f5,$a6), ($d1,$d1,$68,$b9), ($00,$00,$00,$00), ($ed,$ed,$2c,$c1), + ($20,$20,$60,$40), ($fc,$fc,$1f,$e3), ($b1,$b1,$c8,$79), ($5b,$5b,$ed,$b6), + ($6a,$6a,$be,$d4), ($cb,$cb,$46,$8d), ($be,$be,$d9,$67), ($39,$39,$4b,$72), + ($4a,$4a,$de,$94), ($4c,$4c,$d4,$98), ($58,$58,$e8,$b0), ($cf,$cf,$4a,$85), + ($d0,$d0,$6b,$bb), ($ef,$ef,$2a,$c5), ($aa,$aa,$e5,$4f), ($fb,$fb,$16,$ed), + ($43,$43,$c5,$86), ($4d,$4d,$d7,$9a), ($33,$33,$55,$66), ($85,$85,$94,$11), + ($45,$45,$cf,$8a), ($f9,$f9,$10,$e9), ($02,$02,$06,$04), ($7f,$7f,$81,$fe), + ($50,$50,$f0,$a0), ($3c,$3c,$44,$78), ($9f,$9f,$ba,$25), ($a8,$a8,$e3,$4b), + ($51,$51,$f3,$a2), ($a3,$a3,$fe,$5d), ($40,$40,$c0,$80), ($8f,$8f,$8a,$05), + ($92,$92,$ad,$3f), ($9d,$9d,$bc,$21), ($38,$38,$48,$70), ($f5,$f5,$04,$f1), + ($bc,$bc,$df,$63), ($b6,$b6,$c1,$77), ($da,$da,$75,$af), ($21,$21,$63,$42), + ($10,$10,$30,$20), ($ff,$ff,$1a,$e5), ($f3,$f3,$0e,$fd), ($d2,$d2,$6d,$bf), + ($cd,$cd,$4c,$81), ($0c,$0c,$14,$18), ($13,$13,$35,$26), ($ec,$ec,$2f,$c3), + ($5f,$5f,$e1,$be), ($97,$97,$a2,$35), ($44,$44,$cc,$88), ($17,$17,$39,$2e), + ($c4,$c4,$57,$93), ($a7,$a7,$f2,$55), ($7e,$7e,$82,$fc), ($3d,$3d,$47,$7a), + ($64,$64,$ac,$c8), ($5d,$5d,$e7,$ba), ($19,$19,$2b,$32), ($73,$73,$95,$e6), + ($60,$60,$a0,$c0), ($81,$81,$98,$19), ($4f,$4f,$d1,$9e), ($dc,$dc,$7f,$a3), + ($22,$22,$66,$44), ($2a,$2a,$7e,$54), ($90,$90,$ab,$3b), ($88,$88,$83,$0b), + ($46,$46,$ca,$8c), ($ee,$ee,$29,$c7), ($b8,$b8,$d3,$6b), ($14,$14,$3c,$28), + ($de,$de,$79,$a7), ($5e,$5e,$e2,$bc), ($0b,$0b,$1d,$16), ($db,$db,$76,$ad), + ($e0,$e0,$3b,$db), ($32,$32,$56,$64), ($3a,$3a,$4e,$74), ($0a,$0a,$1e,$14), + ($49,$49,$db,$92), ($06,$06,$0a,$0c), ($24,$24,$6c,$48), ($5c,$5c,$e4,$b8), + ($c2,$c2,$5d,$9f), ($d3,$d3,$6e,$bd), ($ac,$ac,$ef,$43), ($62,$62,$a6,$c4), + ($91,$91,$a8,$39), ($95,$95,$a4,$31), ($e4,$e4,$37,$d3), ($79,$79,$8b,$f2), + ($e7,$e7,$32,$d5), ($c8,$c8,$43,$8b), ($37,$37,$59,$6e), ($6d,$6d,$b7,$da), + ($8d,$8d,$8c,$01), ($d5,$d5,$64,$b1), ($4e,$4e,$d2,$9c), ($a9,$a9,$e0,$49), + ($6c,$6c,$b4,$d8), ($56,$56,$fa,$ac), ($f4,$f4,$07,$f3), ($ea,$ea,$25,$cf), + ($65,$65,$af,$ca), ($7a,$7a,$8e,$f4), ($ae,$ae,$e9,$47), ($08,$08,$18,$10), + ($ba,$ba,$d5,$6f), ($78,$78,$88,$f0), ($25,$25,$6f,$4a), ($2e,$2e,$72,$5c), + ($1c,$1c,$24,$38), ($a6,$a6,$f1,$57), ($b4,$b4,$c7,$73), ($c6,$c6,$51,$97), + ($e8,$e8,$23,$cb), ($dd,$dd,$7c,$a1), ($74,$74,$9c,$e8), ($1f,$1f,$21,$3e), + ($4b,$4b,$dd,$96), ($bd,$bd,$dc,$61), ($8b,$8b,$86,$0d), ($8a,$8a,$85,$0f), + ($70,$70,$90,$e0), ($3e,$3e,$42,$7c), ($b5,$b5,$c4,$71), ($66,$66,$aa,$cc), + ($48,$48,$d8,$90), ($03,$03,$05,$06), ($f6,$f6,$01,$f7), ($0e,$0e,$12,$1c), + ($61,$61,$a3,$c2), ($35,$35,$5f,$6a), ($57,$57,$f9,$ae), ($b9,$b9,$d0,$69), + ($86,$86,$91,$17), ($c1,$c1,$58,$99), ($1d,$1d,$27,$3a), ($9e,$9e,$b9,$27), + ($e1,$e1,$38,$d9), ($f8,$f8,$13,$eb), ($98,$98,$b3,$2b), ($11,$11,$33,$22), + ($69,$69,$bb,$d2), ($d9,$d9,$70,$a9), ($8e,$8e,$89,$07), ($94,$94,$a7,$33), + ($9b,$9b,$b6,$2d), ($1e,$1e,$22,$3c), ($87,$87,$92,$15), ($e9,$e9,$20,$c9), + ($ce,$ce,$49,$87), ($55,$55,$ff,$aa), ($28,$28,$78,$50), ($df,$df,$7a,$a5), + ($8c,$8c,$8f,$03), ($a1,$a1,$f8,$59), ($89,$89,$80,$09), ($0d,$0d,$17,$1a), + ($bf,$bf,$da,$65), ($e6,$e6,$31,$d7), ($42,$42,$c6,$84), ($68,$68,$b8,$d0), + ($41,$41,$c3,$82), ($99,$99,$b0,$29), ($2d,$2d,$77,$5a), ($0f,$0f,$11,$1e), + ($b0,$b0,$cb,$7b), ($54,$54,$fc,$a8), ($bb,$bb,$d6,$6d), ($16,$16,$3a,$2c)); + T5: array[0..255,0..3] of byte= ( + ($51,$f4,$a7,$50), ($7e,$41,$65,$53), ($1a,$17,$a4,$c3), ($3a,$27,$5e,$96), + ($3b,$ab,$6b,$cb), ($1f,$9d,$45,$f1), ($ac,$fa,$58,$ab), ($4b,$e3,$03,$93), + ($20,$30,$fa,$55), ($ad,$76,$6d,$f6), ($88,$cc,$76,$91), ($f5,$02,$4c,$25), + ($4f,$e5,$d7,$fc), ($c5,$2a,$cb,$d7), ($26,$35,$44,$80), ($b5,$62,$a3,$8f), + ($de,$b1,$5a,$49), ($25,$ba,$1b,$67), ($45,$ea,$0e,$98), ($5d,$fe,$c0,$e1), + ($c3,$2f,$75,$02), ($81,$4c,$f0,$12), ($8d,$46,$97,$a3), ($6b,$d3,$f9,$c6), + ($03,$8f,$5f,$e7), ($15,$92,$9c,$95), ($bf,$6d,$7a,$eb), ($95,$52,$59,$da), + ($d4,$be,$83,$2d), ($58,$74,$21,$d3), ($49,$e0,$69,$29), ($8e,$c9,$c8,$44), + ($75,$c2,$89,$6a), ($f4,$8e,$79,$78), ($99,$58,$3e,$6b), ($27,$b9,$71,$dd), + ($be,$e1,$4f,$b6), ($f0,$88,$ad,$17), ($c9,$20,$ac,$66), ($7d,$ce,$3a,$b4), + ($63,$df,$4a,$18), ($e5,$1a,$31,$82), ($97,$51,$33,$60), ($62,$53,$7f,$45), + ($b1,$64,$77,$e0), ($bb,$6b,$ae,$84), ($fe,$81,$a0,$1c), ($f9,$08,$2b,$94), + ($70,$48,$68,$58), ($8f,$45,$fd,$19), ($94,$de,$6c,$87), ($52,$7b,$f8,$b7), + ($ab,$73,$d3,$23), ($72,$4b,$02,$e2), ($e3,$1f,$8f,$57), ($66,$55,$ab,$2a), + ($b2,$eb,$28,$07), ($2f,$b5,$c2,$03), ($86,$c5,$7b,$9a), ($d3,$37,$08,$a5), + ($30,$28,$87,$f2), ($23,$bf,$a5,$b2), ($02,$03,$6a,$ba), ($ed,$16,$82,$5c), + ($8a,$cf,$1c,$2b), ($a7,$79,$b4,$92), ($f3,$07,$f2,$f0), ($4e,$69,$e2,$a1), + ($65,$da,$f4,$cd), ($06,$05,$be,$d5), ($d1,$34,$62,$1f), ($c4,$a6,$fe,$8a), + ($34,$2e,$53,$9d), ($a2,$f3,$55,$a0), ($05,$8a,$e1,$32), ($a4,$f6,$eb,$75), + ($0b,$83,$ec,$39), ($40,$60,$ef,$aa), ($5e,$71,$9f,$06), ($bd,$6e,$10,$51), + ($3e,$21,$8a,$f9), ($96,$dd,$06,$3d), ($dd,$3e,$05,$ae), ($4d,$e6,$bd,$46), + ($91,$54,$8d,$b5), ($71,$c4,$5d,$05), ($04,$06,$d4,$6f), ($60,$50,$15,$ff), + ($19,$98,$fb,$24), ($d6,$bd,$e9,$97), ($89,$40,$43,$cc), ($67,$d9,$9e,$77), + ($b0,$e8,$42,$bd), ($07,$89,$8b,$88), ($e7,$19,$5b,$38), ($79,$c8,$ee,$db), + ($a1,$7c,$0a,$47), ($7c,$42,$0f,$e9), ($f8,$84,$1e,$c9), ($00,$00,$00,$00), + ($09,$80,$86,$83), ($32,$2b,$ed,$48), ($1e,$11,$70,$ac), ($6c,$5a,$72,$4e), + ($fd,$0e,$ff,$fb), ($0f,$85,$38,$56), ($3d,$ae,$d5,$1e), ($36,$2d,$39,$27), + ($0a,$0f,$d9,$64), ($68,$5c,$a6,$21), ($9b,$5b,$54,$d1), ($24,$36,$2e,$3a), + ($0c,$0a,$67,$b1), ($93,$57,$e7,$0f), ($b4,$ee,$96,$d2), ($1b,$9b,$91,$9e), + ($80,$c0,$c5,$4f), ($61,$dc,$20,$a2), ($5a,$77,$4b,$69), ($1c,$12,$1a,$16), + ($e2,$93,$ba,$0a), ($c0,$a0,$2a,$e5), ($3c,$22,$e0,$43), ($12,$1b,$17,$1d), + ($0e,$09,$0d,$0b), ($f2,$8b,$c7,$ad), ($2d,$b6,$a8,$b9), ($14,$1e,$a9,$c8), + ($57,$f1,$19,$85), ($af,$75,$07,$4c), ($ee,$99,$dd,$bb), ($a3,$7f,$60,$fd), + ($f7,$01,$26,$9f), ($5c,$72,$f5,$bc), ($44,$66,$3b,$c5), ($5b,$fb,$7e,$34), + ($8b,$43,$29,$76), ($cb,$23,$c6,$dc), ($b6,$ed,$fc,$68), ($b8,$e4,$f1,$63), + ($d7,$31,$dc,$ca), ($42,$63,$85,$10), ($13,$97,$22,$40), ($84,$c6,$11,$20), + ($85,$4a,$24,$7d), ($d2,$bb,$3d,$f8), ($ae,$f9,$32,$11), ($c7,$29,$a1,$6d), + ($1d,$9e,$2f,$4b), ($dc,$b2,$30,$f3), ($0d,$86,$52,$ec), ($77,$c1,$e3,$d0), + ($2b,$b3,$16,$6c), ($a9,$70,$b9,$99), ($11,$94,$48,$fa), ($47,$e9,$64,$22), + ($a8,$fc,$8c,$c4), ($a0,$f0,$3f,$1a), ($56,$7d,$2c,$d8), ($22,$33,$90,$ef), + ($87,$49,$4e,$c7), ($d9,$38,$d1,$c1), ($8c,$ca,$a2,$fe), ($98,$d4,$0b,$36), + ($a6,$f5,$81,$cf), ($a5,$7a,$de,$28), ($da,$b7,$8e,$26), ($3f,$ad,$bf,$a4), + ($2c,$3a,$9d,$e4), ($50,$78,$92,$0d), ($6a,$5f,$cc,$9b), ($54,$7e,$46,$62), + ($f6,$8d,$13,$c2), ($90,$d8,$b8,$e8), ($2e,$39,$f7,$5e), ($82,$c3,$af,$f5), + ($9f,$5d,$80,$be), ($69,$d0,$93,$7c), ($6f,$d5,$2d,$a9), ($cf,$25,$12,$b3), + ($c8,$ac,$99,$3b), ($10,$18,$7d,$a7), ($e8,$9c,$63,$6e), ($db,$3b,$bb,$7b), + ($cd,$26,$78,$09), ($6e,$59,$18,$f4), ($ec,$9a,$b7,$01), ($83,$4f,$9a,$a8), + ($e6,$95,$6e,$65), ($aa,$ff,$e6,$7e), ($21,$bc,$cf,$08), ($ef,$15,$e8,$e6), + ($ba,$e7,$9b,$d9), ($4a,$6f,$36,$ce), ($ea,$9f,$09,$d4), ($29,$b0,$7c,$d6), + ($31,$a4,$b2,$af), ($2a,$3f,$23,$31), ($c6,$a5,$94,$30), ($35,$a2,$66,$c0), + ($74,$4e,$bc,$37), ($fc,$82,$ca,$a6), ($e0,$90,$d0,$b0), ($33,$a7,$d8,$15), + ($f1,$04,$98,$4a), ($41,$ec,$da,$f7), ($7f,$cd,$50,$0e), ($17,$91,$f6,$2f), + ($76,$4d,$d6,$8d), ($43,$ef,$b0,$4d), ($cc,$aa,$4d,$54), ($e4,$96,$04,$df), + ($9e,$d1,$b5,$e3), ($4c,$6a,$88,$1b), ($c1,$2c,$1f,$b8), ($46,$65,$51,$7f), + ($9d,$5e,$ea,$04), ($01,$8c,$35,$5d), ($fa,$87,$74,$73), ($fb,$0b,$41,$2e), + ($b3,$67,$1d,$5a), ($92,$db,$d2,$52), ($e9,$10,$56,$33), ($6d,$d6,$47,$13), + ($9a,$d7,$61,$8c), ($37,$a1,$0c,$7a), ($59,$f8,$14,$8e), ($eb,$13,$3c,$89), + ($ce,$a9,$27,$ee), ($b7,$61,$c9,$35), ($e1,$1c,$e5,$ed), ($7a,$47,$b1,$3c), + ($9c,$d2,$df,$59), ($55,$f2,$73,$3f), ($18,$14,$ce,$79), ($73,$c7,$37,$bf), + ($53,$f7,$cd,$ea), ($5f,$fd,$aa,$5b), ($df,$3d,$6f,$14), ($78,$44,$db,$86), + ($ca,$af,$f3,$81), ($b9,$68,$c4,$3e), ($38,$24,$34,$2c), ($c2,$a3,$40,$5f), + ($16,$1d,$c3,$72), ($bc,$e2,$25,$0c), ($28,$3c,$49,$8b), ($ff,$0d,$95,$41), + ($39,$a8,$01,$71), ($08,$0c,$b3,$de), ($d8,$b4,$e4,$9c), ($64,$56,$c1,$90), + ($7b,$cb,$84,$61), ($d5,$32,$b6,$70), ($48,$6c,$5c,$74), ($d0,$b8,$57,$42)); + T6: array[0..255,0..3] of byte= ( + ($50,$51,$f4,$a7), ($53,$7e,$41,$65), ($c3,$1a,$17,$a4), ($96,$3a,$27,$5e), + ($cb,$3b,$ab,$6b), ($f1,$1f,$9d,$45), ($ab,$ac,$fa,$58), ($93,$4b,$e3,$03), + ($55,$20,$30,$fa), ($f6,$ad,$76,$6d), ($91,$88,$cc,$76), ($25,$f5,$02,$4c), + ($fc,$4f,$e5,$d7), ($d7,$c5,$2a,$cb), ($80,$26,$35,$44), ($8f,$b5,$62,$a3), + ($49,$de,$b1,$5a), ($67,$25,$ba,$1b), ($98,$45,$ea,$0e), ($e1,$5d,$fe,$c0), + ($02,$c3,$2f,$75), ($12,$81,$4c,$f0), ($a3,$8d,$46,$97), ($c6,$6b,$d3,$f9), + ($e7,$03,$8f,$5f), ($95,$15,$92,$9c), ($eb,$bf,$6d,$7a), ($da,$95,$52,$59), + ($2d,$d4,$be,$83), ($d3,$58,$74,$21), ($29,$49,$e0,$69), ($44,$8e,$c9,$c8), + ($6a,$75,$c2,$89), ($78,$f4,$8e,$79), ($6b,$99,$58,$3e), ($dd,$27,$b9,$71), + ($b6,$be,$e1,$4f), ($17,$f0,$88,$ad), ($66,$c9,$20,$ac), ($b4,$7d,$ce,$3a), + ($18,$63,$df,$4a), ($82,$e5,$1a,$31), ($60,$97,$51,$33), ($45,$62,$53,$7f), + ($e0,$b1,$64,$77), ($84,$bb,$6b,$ae), ($1c,$fe,$81,$a0), ($94,$f9,$08,$2b), + ($58,$70,$48,$68), ($19,$8f,$45,$fd), ($87,$94,$de,$6c), ($b7,$52,$7b,$f8), + ($23,$ab,$73,$d3), ($e2,$72,$4b,$02), ($57,$e3,$1f,$8f), ($2a,$66,$55,$ab), + ($07,$b2,$eb,$28), ($03,$2f,$b5,$c2), ($9a,$86,$c5,$7b), ($a5,$d3,$37,$08), + ($f2,$30,$28,$87), ($b2,$23,$bf,$a5), ($ba,$02,$03,$6a), ($5c,$ed,$16,$82), + ($2b,$8a,$cf,$1c), ($92,$a7,$79,$b4), ($f0,$f3,$07,$f2), ($a1,$4e,$69,$e2), + ($cd,$65,$da,$f4), ($d5,$06,$05,$be), ($1f,$d1,$34,$62), ($8a,$c4,$a6,$fe), + ($9d,$34,$2e,$53), ($a0,$a2,$f3,$55), ($32,$05,$8a,$e1), ($75,$a4,$f6,$eb), + ($39,$0b,$83,$ec), ($aa,$40,$60,$ef), ($06,$5e,$71,$9f), ($51,$bd,$6e,$10), + ($f9,$3e,$21,$8a), ($3d,$96,$dd,$06), ($ae,$dd,$3e,$05), ($46,$4d,$e6,$bd), + ($b5,$91,$54,$8d), ($05,$71,$c4,$5d), ($6f,$04,$06,$d4), ($ff,$60,$50,$15), + ($24,$19,$98,$fb), ($97,$d6,$bd,$e9), ($cc,$89,$40,$43), ($77,$67,$d9,$9e), + ($bd,$b0,$e8,$42), ($88,$07,$89,$8b), ($38,$e7,$19,$5b), ($db,$79,$c8,$ee), + ($47,$a1,$7c,$0a), ($e9,$7c,$42,$0f), ($c9,$f8,$84,$1e), ($00,$00,$00,$00), + ($83,$09,$80,$86), ($48,$32,$2b,$ed), ($ac,$1e,$11,$70), ($4e,$6c,$5a,$72), + ($fb,$fd,$0e,$ff), ($56,$0f,$85,$38), ($1e,$3d,$ae,$d5), ($27,$36,$2d,$39), + ($64,$0a,$0f,$d9), ($21,$68,$5c,$a6), ($d1,$9b,$5b,$54), ($3a,$24,$36,$2e), + ($b1,$0c,$0a,$67), ($0f,$93,$57,$e7), ($d2,$b4,$ee,$96), ($9e,$1b,$9b,$91), + ($4f,$80,$c0,$c5), ($a2,$61,$dc,$20), ($69,$5a,$77,$4b), ($16,$1c,$12,$1a), + ($0a,$e2,$93,$ba), ($e5,$c0,$a0,$2a), ($43,$3c,$22,$e0), ($1d,$12,$1b,$17), + ($0b,$0e,$09,$0d), ($ad,$f2,$8b,$c7), ($b9,$2d,$b6,$a8), ($c8,$14,$1e,$a9), + ($85,$57,$f1,$19), ($4c,$af,$75,$07), ($bb,$ee,$99,$dd), ($fd,$a3,$7f,$60), + ($9f,$f7,$01,$26), ($bc,$5c,$72,$f5), ($c5,$44,$66,$3b), ($34,$5b,$fb,$7e), + ($76,$8b,$43,$29), ($dc,$cb,$23,$c6), ($68,$b6,$ed,$fc), ($63,$b8,$e4,$f1), + ($ca,$d7,$31,$dc), ($10,$42,$63,$85), ($40,$13,$97,$22), ($20,$84,$c6,$11), + ($7d,$85,$4a,$24), ($f8,$d2,$bb,$3d), ($11,$ae,$f9,$32), ($6d,$c7,$29,$a1), + ($4b,$1d,$9e,$2f), ($f3,$dc,$b2,$30), ($ec,$0d,$86,$52), ($d0,$77,$c1,$e3), + ($6c,$2b,$b3,$16), ($99,$a9,$70,$b9), ($fa,$11,$94,$48), ($22,$47,$e9,$64), + ($c4,$a8,$fc,$8c), ($1a,$a0,$f0,$3f), ($d8,$56,$7d,$2c), ($ef,$22,$33,$90), + ($c7,$87,$49,$4e), ($c1,$d9,$38,$d1), ($fe,$8c,$ca,$a2), ($36,$98,$d4,$0b), + ($cf,$a6,$f5,$81), ($28,$a5,$7a,$de), ($26,$da,$b7,$8e), ($a4,$3f,$ad,$bf), + ($e4,$2c,$3a,$9d), ($0d,$50,$78,$92), ($9b,$6a,$5f,$cc), ($62,$54,$7e,$46), + ($c2,$f6,$8d,$13), ($e8,$90,$d8,$b8), ($5e,$2e,$39,$f7), ($f5,$82,$c3,$af), + ($be,$9f,$5d,$80), ($7c,$69,$d0,$93), ($a9,$6f,$d5,$2d), ($b3,$cf,$25,$12), + ($3b,$c8,$ac,$99), ($a7,$10,$18,$7d), ($6e,$e8,$9c,$63), ($7b,$db,$3b,$bb), + ($09,$cd,$26,$78), ($f4,$6e,$59,$18), ($01,$ec,$9a,$b7), ($a8,$83,$4f,$9a), + ($65,$e6,$95,$6e), ($7e,$aa,$ff,$e6), ($08,$21,$bc,$cf), ($e6,$ef,$15,$e8), + ($d9,$ba,$e7,$9b), ($ce,$4a,$6f,$36), ($d4,$ea,$9f,$09), ($d6,$29,$b0,$7c), + ($af,$31,$a4,$b2), ($31,$2a,$3f,$23), ($30,$c6,$a5,$94), ($c0,$35,$a2,$66), + ($37,$74,$4e,$bc), ($a6,$fc,$82,$ca), ($b0,$e0,$90,$d0), ($15,$33,$a7,$d8), + ($4a,$f1,$04,$98), ($f7,$41,$ec,$da), ($0e,$7f,$cd,$50), ($2f,$17,$91,$f6), + ($8d,$76,$4d,$d6), ($4d,$43,$ef,$b0), ($54,$cc,$aa,$4d), ($df,$e4,$96,$04), + ($e3,$9e,$d1,$b5), ($1b,$4c,$6a,$88), ($b8,$c1,$2c,$1f), ($7f,$46,$65,$51), + ($04,$9d,$5e,$ea), ($5d,$01,$8c,$35), ($73,$fa,$87,$74), ($2e,$fb,$0b,$41), + ($5a,$b3,$67,$1d), ($52,$92,$db,$d2), ($33,$e9,$10,$56), ($13,$6d,$d6,$47), + ($8c,$9a,$d7,$61), ($7a,$37,$a1,$0c), ($8e,$59,$f8,$14), ($89,$eb,$13,$3c), + ($ee,$ce,$a9,$27), ($35,$b7,$61,$c9), ($ed,$e1,$1c,$e5), ($3c,$7a,$47,$b1), + ($59,$9c,$d2,$df), ($3f,$55,$f2,$73), ($79,$18,$14,$ce), ($bf,$73,$c7,$37), + ($ea,$53,$f7,$cd), ($5b,$5f,$fd,$aa), ($14,$df,$3d,$6f), ($86,$78,$44,$db), + ($81,$ca,$af,$f3), ($3e,$b9,$68,$c4), ($2c,$38,$24,$34), ($5f,$c2,$a3,$40), + ($72,$16,$1d,$c3), ($0c,$bc,$e2,$25), ($8b,$28,$3c,$49), ($41,$ff,$0d,$95), + ($71,$39,$a8,$01), ($de,$08,$0c,$b3), ($9c,$d8,$b4,$e4), ($90,$64,$56,$c1), + ($61,$7b,$cb,$84), ($70,$d5,$32,$b6), ($74,$48,$6c,$5c), ($42,$d0,$b8,$57)); + T7: array[0..255,0..3] of byte= ( + ($a7,$50,$51,$f4), ($65,$53,$7e,$41), ($a4,$c3,$1a,$17), ($5e,$96,$3a,$27), + ($6b,$cb,$3b,$ab), ($45,$f1,$1f,$9d), ($58,$ab,$ac,$fa), ($03,$93,$4b,$e3), + ($fa,$55,$20,$30), ($6d,$f6,$ad,$76), ($76,$91,$88,$cc), ($4c,$25,$f5,$02), + ($d7,$fc,$4f,$e5), ($cb,$d7,$c5,$2a), ($44,$80,$26,$35), ($a3,$8f,$b5,$62), + ($5a,$49,$de,$b1), ($1b,$67,$25,$ba), ($0e,$98,$45,$ea), ($c0,$e1,$5d,$fe), + ($75,$02,$c3,$2f), ($f0,$12,$81,$4c), ($97,$a3,$8d,$46), ($f9,$c6,$6b,$d3), + ($5f,$e7,$03,$8f), ($9c,$95,$15,$92), ($7a,$eb,$bf,$6d), ($59,$da,$95,$52), + ($83,$2d,$d4,$be), ($21,$d3,$58,$74), ($69,$29,$49,$e0), ($c8,$44,$8e,$c9), + ($89,$6a,$75,$c2), ($79,$78,$f4,$8e), ($3e,$6b,$99,$58), ($71,$dd,$27,$b9), + ($4f,$b6,$be,$e1), ($ad,$17,$f0,$88), ($ac,$66,$c9,$20), ($3a,$b4,$7d,$ce), + ($4a,$18,$63,$df), ($31,$82,$e5,$1a), ($33,$60,$97,$51), ($7f,$45,$62,$53), + ($77,$e0,$b1,$64), ($ae,$84,$bb,$6b), ($a0,$1c,$fe,$81), ($2b,$94,$f9,$08), + ($68,$58,$70,$48), ($fd,$19,$8f,$45), ($6c,$87,$94,$de), ($f8,$b7,$52,$7b), + ($d3,$23,$ab,$73), ($02,$e2,$72,$4b), ($8f,$57,$e3,$1f), ($ab,$2a,$66,$55), + ($28,$07,$b2,$eb), ($c2,$03,$2f,$b5), ($7b,$9a,$86,$c5), ($08,$a5,$d3,$37), + ($87,$f2,$30,$28), ($a5,$b2,$23,$bf), ($6a,$ba,$02,$03), ($82,$5c,$ed,$16), + ($1c,$2b,$8a,$cf), ($b4,$92,$a7,$79), ($f2,$f0,$f3,$07), ($e2,$a1,$4e,$69), + ($f4,$cd,$65,$da), ($be,$d5,$06,$05), ($62,$1f,$d1,$34), ($fe,$8a,$c4,$a6), + ($53,$9d,$34,$2e), ($55,$a0,$a2,$f3), ($e1,$32,$05,$8a), ($eb,$75,$a4,$f6), + ($ec,$39,$0b,$83), ($ef,$aa,$40,$60), ($9f,$06,$5e,$71), ($10,$51,$bd,$6e), + ($8a,$f9,$3e,$21), ($06,$3d,$96,$dd), ($05,$ae,$dd,$3e), ($bd,$46,$4d,$e6), + ($8d,$b5,$91,$54), ($5d,$05,$71,$c4), ($d4,$6f,$04,$06), ($15,$ff,$60,$50), + ($fb,$24,$19,$98), ($e9,$97,$d6,$bd), ($43,$cc,$89,$40), ($9e,$77,$67,$d9), + ($42,$bd,$b0,$e8), ($8b,$88,$07,$89), ($5b,$38,$e7,$19), ($ee,$db,$79,$c8), + ($0a,$47,$a1,$7c), ($0f,$e9,$7c,$42), ($1e,$c9,$f8,$84), ($00,$00,$00,$00), + ($86,$83,$09,$80), ($ed,$48,$32,$2b), ($70,$ac,$1e,$11), ($72,$4e,$6c,$5a), + ($ff,$fb,$fd,$0e), ($38,$56,$0f,$85), ($d5,$1e,$3d,$ae), ($39,$27,$36,$2d), + ($d9,$64,$0a,$0f), ($a6,$21,$68,$5c), ($54,$d1,$9b,$5b), ($2e,$3a,$24,$36), + ($67,$b1,$0c,$0a), ($e7,$0f,$93,$57), ($96,$d2,$b4,$ee), ($91,$9e,$1b,$9b), + ($c5,$4f,$80,$c0), ($20,$a2,$61,$dc), ($4b,$69,$5a,$77), ($1a,$16,$1c,$12), + ($ba,$0a,$e2,$93), ($2a,$e5,$c0,$a0), ($e0,$43,$3c,$22), ($17,$1d,$12,$1b), + ($0d,$0b,$0e,$09), ($c7,$ad,$f2,$8b), ($a8,$b9,$2d,$b6), ($a9,$c8,$14,$1e), + ($19,$85,$57,$f1), ($07,$4c,$af,$75), ($dd,$bb,$ee,$99), ($60,$fd,$a3,$7f), + ($26,$9f,$f7,$01), ($f5,$bc,$5c,$72), ($3b,$c5,$44,$66), ($7e,$34,$5b,$fb), + ($29,$76,$8b,$43), ($c6,$dc,$cb,$23), ($fc,$68,$b6,$ed), ($f1,$63,$b8,$e4), + ($dc,$ca,$d7,$31), ($85,$10,$42,$63), ($22,$40,$13,$97), ($11,$20,$84,$c6), + ($24,$7d,$85,$4a), ($3d,$f8,$d2,$bb), ($32,$11,$ae,$f9), ($a1,$6d,$c7,$29), + ($2f,$4b,$1d,$9e), ($30,$f3,$dc,$b2), ($52,$ec,$0d,$86), ($e3,$d0,$77,$c1), + ($16,$6c,$2b,$b3), ($b9,$99,$a9,$70), ($48,$fa,$11,$94), ($64,$22,$47,$e9), + ($8c,$c4,$a8,$fc), ($3f,$1a,$a0,$f0), ($2c,$d8,$56,$7d), ($90,$ef,$22,$33), + ($4e,$c7,$87,$49), ($d1,$c1,$d9,$38), ($a2,$fe,$8c,$ca), ($0b,$36,$98,$d4), + ($81,$cf,$a6,$f5), ($de,$28,$a5,$7a), ($8e,$26,$da,$b7), ($bf,$a4,$3f,$ad), + ($9d,$e4,$2c,$3a), ($92,$0d,$50,$78), ($cc,$9b,$6a,$5f), ($46,$62,$54,$7e), + ($13,$c2,$f6,$8d), ($b8,$e8,$90,$d8), ($f7,$5e,$2e,$39), ($af,$f5,$82,$c3), + ($80,$be,$9f,$5d), ($93,$7c,$69,$d0), ($2d,$a9,$6f,$d5), ($12,$b3,$cf,$25), + ($99,$3b,$c8,$ac), ($7d,$a7,$10,$18), ($63,$6e,$e8,$9c), ($bb,$7b,$db,$3b), + ($78,$09,$cd,$26), ($18,$f4,$6e,$59), ($b7,$01,$ec,$9a), ($9a,$a8,$83,$4f), + ($6e,$65,$e6,$95), ($e6,$7e,$aa,$ff), ($cf,$08,$21,$bc), ($e8,$e6,$ef,$15), + ($9b,$d9,$ba,$e7), ($36,$ce,$4a,$6f), ($09,$d4,$ea,$9f), ($7c,$d6,$29,$b0), + ($b2,$af,$31,$a4), ($23,$31,$2a,$3f), ($94,$30,$c6,$a5), ($66,$c0,$35,$a2), + ($bc,$37,$74,$4e), ($ca,$a6,$fc,$82), ($d0,$b0,$e0,$90), ($d8,$15,$33,$a7), + ($98,$4a,$f1,$04), ($da,$f7,$41,$ec), ($50,$0e,$7f,$cd), ($f6,$2f,$17,$91), + ($d6,$8d,$76,$4d), ($b0,$4d,$43,$ef), ($4d,$54,$cc,$aa), ($04,$df,$e4,$96), + ($b5,$e3,$9e,$d1), ($88,$1b,$4c,$6a), ($1f,$b8,$c1,$2c), ($51,$7f,$46,$65), + ($ea,$04,$9d,$5e), ($35,$5d,$01,$8c), ($74,$73,$fa,$87), ($41,$2e,$fb,$0b), + ($1d,$5a,$b3,$67), ($d2,$52,$92,$db), ($56,$33,$e9,$10), ($47,$13,$6d,$d6), + ($61,$8c,$9a,$d7), ($0c,$7a,$37,$a1), ($14,$8e,$59,$f8), ($3c,$89,$eb,$13), + ($27,$ee,$ce,$a9), ($c9,$35,$b7,$61), ($e5,$ed,$e1,$1c), ($b1,$3c,$7a,$47), + ($df,$59,$9c,$d2), ($73,$3f,$55,$f2), ($ce,$79,$18,$14), ($37,$bf,$73,$c7), + ($cd,$ea,$53,$f7), ($aa,$5b,$5f,$fd), ($6f,$14,$df,$3d), ($db,$86,$78,$44), + ($f3,$81,$ca,$af), ($c4,$3e,$b9,$68), ($34,$2c,$38,$24), ($40,$5f,$c2,$a3), + ($c3,$72,$16,$1d), ($25,$0c,$bc,$e2), ($49,$8b,$28,$3c), ($95,$41,$ff,$0d), + ($01,$71,$39,$a8), ($b3,$de,$08,$0c), ($e4,$9c,$d8,$b4), ($c1,$90,$64,$56), + ($84,$61,$7b,$cb), ($b6,$70,$d5,$32), ($5c,$74,$48,$6c), ($57,$42,$d0,$b8)); + T8: array[0..255,0..3] of byte= ( + ($f4,$a7,$50,$51), ($41,$65,$53,$7e), ($17,$a4,$c3,$1a), ($27,$5e,$96,$3a), + ($ab,$6b,$cb,$3b), ($9d,$45,$f1,$1f), ($fa,$58,$ab,$ac), ($e3,$03,$93,$4b), + ($30,$fa,$55,$20), ($76,$6d,$f6,$ad), ($cc,$76,$91,$88), ($02,$4c,$25,$f5), + ($e5,$d7,$fc,$4f), ($2a,$cb,$d7,$c5), ($35,$44,$80,$26), ($62,$a3,$8f,$b5), + ($b1,$5a,$49,$de), ($ba,$1b,$67,$25), ($ea,$0e,$98,$45), ($fe,$c0,$e1,$5d), + ($2f,$75,$02,$c3), ($4c,$f0,$12,$81), ($46,$97,$a3,$8d), ($d3,$f9,$c6,$6b), + ($8f,$5f,$e7,$03), ($92,$9c,$95,$15), ($6d,$7a,$eb,$bf), ($52,$59,$da,$95), + ($be,$83,$2d,$d4), ($74,$21,$d3,$58), ($e0,$69,$29,$49), ($c9,$c8,$44,$8e), + ($c2,$89,$6a,$75), ($8e,$79,$78,$f4), ($58,$3e,$6b,$99), ($b9,$71,$dd,$27), + ($e1,$4f,$b6,$be), ($88,$ad,$17,$f0), ($20,$ac,$66,$c9), ($ce,$3a,$b4,$7d), + ($df,$4a,$18,$63), ($1a,$31,$82,$e5), ($51,$33,$60,$97), ($53,$7f,$45,$62), + ($64,$77,$e0,$b1), ($6b,$ae,$84,$bb), ($81,$a0,$1c,$fe), ($08,$2b,$94,$f9), + ($48,$68,$58,$70), ($45,$fd,$19,$8f), ($de,$6c,$87,$94), ($7b,$f8,$b7,$52), + ($73,$d3,$23,$ab), ($4b,$02,$e2,$72), ($1f,$8f,$57,$e3), ($55,$ab,$2a,$66), + ($eb,$28,$07,$b2), ($b5,$c2,$03,$2f), ($c5,$7b,$9a,$86), ($37,$08,$a5,$d3), + ($28,$87,$f2,$30), ($bf,$a5,$b2,$23), ($03,$6a,$ba,$02), ($16,$82,$5c,$ed), + ($cf,$1c,$2b,$8a), ($79,$b4,$92,$a7), ($07,$f2,$f0,$f3), ($69,$e2,$a1,$4e), + ($da,$f4,$cd,$65), ($05,$be,$d5,$06), ($34,$62,$1f,$d1), ($a6,$fe,$8a,$c4), + ($2e,$53,$9d,$34), ($f3,$55,$a0,$a2), ($8a,$e1,$32,$05), ($f6,$eb,$75,$a4), + ($83,$ec,$39,$0b), ($60,$ef,$aa,$40), ($71,$9f,$06,$5e), ($6e,$10,$51,$bd), + ($21,$8a,$f9,$3e), ($dd,$06,$3d,$96), ($3e,$05,$ae,$dd), ($e6,$bd,$46,$4d), + ($54,$8d,$b5,$91), ($c4,$5d,$05,$71), ($06,$d4,$6f,$04), ($50,$15,$ff,$60), + ($98,$fb,$24,$19), ($bd,$e9,$97,$d6), ($40,$43,$cc,$89), ($d9,$9e,$77,$67), + ($e8,$42,$bd,$b0), ($89,$8b,$88,$07), ($19,$5b,$38,$e7), ($c8,$ee,$db,$79), + ($7c,$0a,$47,$a1), ($42,$0f,$e9,$7c), ($84,$1e,$c9,$f8), ($00,$00,$00,$00), + ($80,$86,$83,$09), ($2b,$ed,$48,$32), ($11,$70,$ac,$1e), ($5a,$72,$4e,$6c), + ($0e,$ff,$fb,$fd), ($85,$38,$56,$0f), ($ae,$d5,$1e,$3d), ($2d,$39,$27,$36), + ($0f,$d9,$64,$0a), ($5c,$a6,$21,$68), ($5b,$54,$d1,$9b), ($36,$2e,$3a,$24), + ($0a,$67,$b1,$0c), ($57,$e7,$0f,$93), ($ee,$96,$d2,$b4), ($9b,$91,$9e,$1b), + ($c0,$c5,$4f,$80), ($dc,$20,$a2,$61), ($77,$4b,$69,$5a), ($12,$1a,$16,$1c), + ($93,$ba,$0a,$e2), ($a0,$2a,$e5,$c0), ($22,$e0,$43,$3c), ($1b,$17,$1d,$12), + ($09,$0d,$0b,$0e), ($8b,$c7,$ad,$f2), ($b6,$a8,$b9,$2d), ($1e,$a9,$c8,$14), + ($f1,$19,$85,$57), ($75,$07,$4c,$af), ($99,$dd,$bb,$ee), ($7f,$60,$fd,$a3), + ($01,$26,$9f,$f7), ($72,$f5,$bc,$5c), ($66,$3b,$c5,$44), ($fb,$7e,$34,$5b), + ($43,$29,$76,$8b), ($23,$c6,$dc,$cb), ($ed,$fc,$68,$b6), ($e4,$f1,$63,$b8), + ($31,$dc,$ca,$d7), ($63,$85,$10,$42), ($97,$22,$40,$13), ($c6,$11,$20,$84), + ($4a,$24,$7d,$85), ($bb,$3d,$f8,$d2), ($f9,$32,$11,$ae), ($29,$a1,$6d,$c7), + ($9e,$2f,$4b,$1d), ($b2,$30,$f3,$dc), ($86,$52,$ec,$0d), ($c1,$e3,$d0,$77), + ($b3,$16,$6c,$2b), ($70,$b9,$99,$a9), ($94,$48,$fa,$11), ($e9,$64,$22,$47), + ($fc,$8c,$c4,$a8), ($f0,$3f,$1a,$a0), ($7d,$2c,$d8,$56), ($33,$90,$ef,$22), + ($49,$4e,$c7,$87), ($38,$d1,$c1,$d9), ($ca,$a2,$fe,$8c), ($d4,$0b,$36,$98), + ($f5,$81,$cf,$a6), ($7a,$de,$28,$a5), ($b7,$8e,$26,$da), ($ad,$bf,$a4,$3f), + ($3a,$9d,$e4,$2c), ($78,$92,$0d,$50), ($5f,$cc,$9b,$6a), ($7e,$46,$62,$54), + ($8d,$13,$c2,$f6), ($d8,$b8,$e8,$90), ($39,$f7,$5e,$2e), ($c3,$af,$f5,$82), + ($5d,$80,$be,$9f), ($d0,$93,$7c,$69), ($d5,$2d,$a9,$6f), ($25,$12,$b3,$cf), + ($ac,$99,$3b,$c8), ($18,$7d,$a7,$10), ($9c,$63,$6e,$e8), ($3b,$bb,$7b,$db), + ($26,$78,$09,$cd), ($59,$18,$f4,$6e), ($9a,$b7,$01,$ec), ($4f,$9a,$a8,$83), + ($95,$6e,$65,$e6), ($ff,$e6,$7e,$aa), ($bc,$cf,$08,$21), ($15,$e8,$e6,$ef), + ($e7,$9b,$d9,$ba), ($6f,$36,$ce,$4a), ($9f,$09,$d4,$ea), ($b0,$7c,$d6,$29), + ($a4,$b2,$af,$31), ($3f,$23,$31,$2a), ($a5,$94,$30,$c6), ($a2,$66,$c0,$35), + ($4e,$bc,$37,$74), ($82,$ca,$a6,$fc), ($90,$d0,$b0,$e0), ($a7,$d8,$15,$33), + ($04,$98,$4a,$f1), ($ec,$da,$f7,$41), ($cd,$50,$0e,$7f), ($91,$f6,$2f,$17), + ($4d,$d6,$8d,$76), ($ef,$b0,$4d,$43), ($aa,$4d,$54,$cc), ($96,$04,$df,$e4), + ($d1,$b5,$e3,$9e), ($6a,$88,$1b,$4c), ($2c,$1f,$b8,$c1), ($65,$51,$7f,$46), + ($5e,$ea,$04,$9d), ($8c,$35,$5d,$01), ($87,$74,$73,$fa), ($0b,$41,$2e,$fb), + ($67,$1d,$5a,$b3), ($db,$d2,$52,$92), ($10,$56,$33,$e9), ($d6,$47,$13,$6d), + ($d7,$61,$8c,$9a), ($a1,$0c,$7a,$37), ($f8,$14,$8e,$59), ($13,$3c,$89,$eb), + ($a9,$27,$ee,$ce), ($61,$c9,$35,$b7), ($1c,$e5,$ed,$e1), ($47,$b1,$3c,$7a), + ($d2,$df,$59,$9c), ($f2,$73,$3f,$55), ($14,$ce,$79,$18), ($c7,$37,$bf,$73), + ($f7,$cd,$ea,$53), ($fd,$aa,$5b,$5f), ($3d,$6f,$14,$df), ($44,$db,$86,$78), + ($af,$f3,$81,$ca), ($68,$c4,$3e,$b9), ($24,$34,$2c,$38), ($a3,$40,$5f,$c2), + ($1d,$c3,$72,$16), ($e2,$25,$0c,$bc), ($3c,$49,$8b,$28), ($0d,$95,$41,$ff), + ($a8,$01,$71,$39), ($0c,$b3,$de,$08), ($b4,$e4,$9c,$d8), ($56,$c1,$90,$64), + ($cb,$84,$61,$7b), ($32,$b6,$70,$d5), ($6c,$5c,$74,$48), ($b8,$57,$42,$d0)); + S5: array[0..255] of byte= ( + $52,$09,$6a,$d5, + $30,$36,$a5,$38, + $bf,$40,$a3,$9e, + $81,$f3,$d7,$fb, + $7c,$e3,$39,$82, + $9b,$2f,$ff,$87, + $34,$8e,$43,$44, + $c4,$de,$e9,$cb, + $54,$7b,$94,$32, + $a6,$c2,$23,$3d, + $ee,$4c,$95,$0b, + $42,$fa,$c3,$4e, + $08,$2e,$a1,$66, + $28,$d9,$24,$b2, + $76,$5b,$a2,$49, + $6d,$8b,$d1,$25, + $72,$f8,$f6,$64, + $86,$68,$98,$16, + $d4,$a4,$5c,$cc, + $5d,$65,$b6,$92, + $6c,$70,$48,$50, + $fd,$ed,$b9,$da, + $5e,$15,$46,$57, + $a7,$8d,$9d,$84, + $90,$d8,$ab,$00, + $8c,$bc,$d3,$0a, + $f7,$e4,$58,$05, + $b8,$b3,$45,$06, + $d0,$2c,$1e,$8f, + $ca,$3f,$0f,$02, + $c1,$af,$bd,$03, + $01,$13,$8a,$6b, + $3a,$91,$11,$41, + $4f,$67,$dc,$ea, + $97,$f2,$cf,$ce, + $f0,$b4,$e6,$73, + $96,$ac,$74,$22, + $e7,$ad,$35,$85, + $e2,$f9,$37,$e8, + $1c,$75,$df,$6e, + $47,$f1,$1a,$71, + $1d,$29,$c5,$89, + $6f,$b7,$62,$0e, + $aa,$18,$be,$1b, + $fc,$56,$3e,$4b, + $c6,$d2,$79,$20, + $9a,$db,$c0,$fe, + $78,$cd,$5a,$f4, + $1f,$dd,$a8,$33, + $88,$07,$c7,$31, + $b1,$12,$10,$59, + $27,$80,$ec,$5f, + $60,$51,$7f,$a9, + $19,$b5,$4a,$0d, + $2d,$e5,$7a,$9f, + $93,$c9,$9c,$ef, + $a0,$e0,$3b,$4d, + $ae,$2a,$f5,$b0, + $c8,$eb,$bb,$3c, + $83,$53,$99,$61, + $17,$2b,$04,$7e, + $ba,$77,$d6,$26, + $e1,$69,$14,$63, + $55,$21,$0c,$7d); + U1: array[0..255,0..3] of byte= ( + ($00,$00,$00,$00), ($0e,$09,$0d,$0b), ($1c,$12,$1a,$16), ($12,$1b,$17,$1d), + ($38,$24,$34,$2c), ($36,$2d,$39,$27), ($24,$36,$2e,$3a), ($2a,$3f,$23,$31), + ($70,$48,$68,$58), ($7e,$41,$65,$53), ($6c,$5a,$72,$4e), ($62,$53,$7f,$45), + ($48,$6c,$5c,$74), ($46,$65,$51,$7f), ($54,$7e,$46,$62), ($5a,$77,$4b,$69), + ($e0,$90,$d0,$b0), ($ee,$99,$dd,$bb), ($fc,$82,$ca,$a6), ($f2,$8b,$c7,$ad), + ($d8,$b4,$e4,$9c), ($d6,$bd,$e9,$97), ($c4,$a6,$fe,$8a), ($ca,$af,$f3,$81), + ($90,$d8,$b8,$e8), ($9e,$d1,$b5,$e3), ($8c,$ca,$a2,$fe), ($82,$c3,$af,$f5), + ($a8,$fc,$8c,$c4), ($a6,$f5,$81,$cf), ($b4,$ee,$96,$d2), ($ba,$e7,$9b,$d9), + ($db,$3b,$bb,$7b), ($d5,$32,$b6,$70), ($c7,$29,$a1,$6d), ($c9,$20,$ac,$66), + ($e3,$1f,$8f,$57), ($ed,$16,$82,$5c), ($ff,$0d,$95,$41), ($f1,$04,$98,$4a), + ($ab,$73,$d3,$23), ($a5,$7a,$de,$28), ($b7,$61,$c9,$35), ($b9,$68,$c4,$3e), + ($93,$57,$e7,$0f), ($9d,$5e,$ea,$04), ($8f,$45,$fd,$19), ($81,$4c,$f0,$12), + ($3b,$ab,$6b,$cb), ($35,$a2,$66,$c0), ($27,$b9,$71,$dd), ($29,$b0,$7c,$d6), + ($03,$8f,$5f,$e7), ($0d,$86,$52,$ec), ($1f,$9d,$45,$f1), ($11,$94,$48,$fa), + ($4b,$e3,$03,$93), ($45,$ea,$0e,$98), ($57,$f1,$19,$85), ($59,$f8,$14,$8e), + ($73,$c7,$37,$bf), ($7d,$ce,$3a,$b4), ($6f,$d5,$2d,$a9), ($61,$dc,$20,$a2), + ($ad,$76,$6d,$f6), ($a3,$7f,$60,$fd), ($b1,$64,$77,$e0), ($bf,$6d,$7a,$eb), + ($95,$52,$59,$da), ($9b,$5b,$54,$d1), ($89,$40,$43,$cc), ($87,$49,$4e,$c7), + ($dd,$3e,$05,$ae), ($d3,$37,$08,$a5), ($c1,$2c,$1f,$b8), ($cf,$25,$12,$b3), + ($e5,$1a,$31,$82), ($eb,$13,$3c,$89), ($f9,$08,$2b,$94), ($f7,$01,$26,$9f), + ($4d,$e6,$bd,$46), ($43,$ef,$b0,$4d), ($51,$f4,$a7,$50), ($5f,$fd,$aa,$5b), + ($75,$c2,$89,$6a), ($7b,$cb,$84,$61), ($69,$d0,$93,$7c), ($67,$d9,$9e,$77), + ($3d,$ae,$d5,$1e), ($33,$a7,$d8,$15), ($21,$bc,$cf,$08), ($2f,$b5,$c2,$03), + ($05,$8a,$e1,$32), ($0b,$83,$ec,$39), ($19,$98,$fb,$24), ($17,$91,$f6,$2f), + ($76,$4d,$d6,$8d), ($78,$44,$db,$86), ($6a,$5f,$cc,$9b), ($64,$56,$c1,$90), + ($4e,$69,$e2,$a1), ($40,$60,$ef,$aa), ($52,$7b,$f8,$b7), ($5c,$72,$f5,$bc), + ($06,$05,$be,$d5), ($08,$0c,$b3,$de), ($1a,$17,$a4,$c3), ($14,$1e,$a9,$c8), + ($3e,$21,$8a,$f9), ($30,$28,$87,$f2), ($22,$33,$90,$ef), ($2c,$3a,$9d,$e4), + ($96,$dd,$06,$3d), ($98,$d4,$0b,$36), ($8a,$cf,$1c,$2b), ($84,$c6,$11,$20), + ($ae,$f9,$32,$11), ($a0,$f0,$3f,$1a), ($b2,$eb,$28,$07), ($bc,$e2,$25,$0c), + ($e6,$95,$6e,$65), ($e8,$9c,$63,$6e), ($fa,$87,$74,$73), ($f4,$8e,$79,$78), + ($de,$b1,$5a,$49), ($d0,$b8,$57,$42), ($c2,$a3,$40,$5f), ($cc,$aa,$4d,$54), + ($41,$ec,$da,$f7), ($4f,$e5,$d7,$fc), ($5d,$fe,$c0,$e1), ($53,$f7,$cd,$ea), + ($79,$c8,$ee,$db), ($77,$c1,$e3,$d0), ($65,$da,$f4,$cd), ($6b,$d3,$f9,$c6), + ($31,$a4,$b2,$af), ($3f,$ad,$bf,$a4), ($2d,$b6,$a8,$b9), ($23,$bf,$a5,$b2), + ($09,$80,$86,$83), ($07,$89,$8b,$88), ($15,$92,$9c,$95), ($1b,$9b,$91,$9e), + ($a1,$7c,$0a,$47), ($af,$75,$07,$4c), ($bd,$6e,$10,$51), ($b3,$67,$1d,$5a), + ($99,$58,$3e,$6b), ($97,$51,$33,$60), ($85,$4a,$24,$7d), ($8b,$43,$29,$76), + ($d1,$34,$62,$1f), ($df,$3d,$6f,$14), ($cd,$26,$78,$09), ($c3,$2f,$75,$02), + ($e9,$10,$56,$33), ($e7,$19,$5b,$38), ($f5,$02,$4c,$25), ($fb,$0b,$41,$2e), + ($9a,$d7,$61,$8c), ($94,$de,$6c,$87), ($86,$c5,$7b,$9a), ($88,$cc,$76,$91), + ($a2,$f3,$55,$a0), ($ac,$fa,$58,$ab), ($be,$e1,$4f,$b6), ($b0,$e8,$42,$bd), + ($ea,$9f,$09,$d4), ($e4,$96,$04,$df), ($f6,$8d,$13,$c2), ($f8,$84,$1e,$c9), + ($d2,$bb,$3d,$f8), ($dc,$b2,$30,$f3), ($ce,$a9,$27,$ee), ($c0,$a0,$2a,$e5), + ($7a,$47,$b1,$3c), ($74,$4e,$bc,$37), ($66,$55,$ab,$2a), ($68,$5c,$a6,$21), + ($42,$63,$85,$10), ($4c,$6a,$88,$1b), ($5e,$71,$9f,$06), ($50,$78,$92,$0d), + ($0a,$0f,$d9,$64), ($04,$06,$d4,$6f), ($16,$1d,$c3,$72), ($18,$14,$ce,$79), + ($32,$2b,$ed,$48), ($3c,$22,$e0,$43), ($2e,$39,$f7,$5e), ($20,$30,$fa,$55), + ($ec,$9a,$b7,$01), ($e2,$93,$ba,$0a), ($f0,$88,$ad,$17), ($fe,$81,$a0,$1c), + ($d4,$be,$83,$2d), ($da,$b7,$8e,$26), ($c8,$ac,$99,$3b), ($c6,$a5,$94,$30), + ($9c,$d2,$df,$59), ($92,$db,$d2,$52), ($80,$c0,$c5,$4f), ($8e,$c9,$c8,$44), + ($a4,$f6,$eb,$75), ($aa,$ff,$e6,$7e), ($b8,$e4,$f1,$63), ($b6,$ed,$fc,$68), + ($0c,$0a,$67,$b1), ($02,$03,$6a,$ba), ($10,$18,$7d,$a7), ($1e,$11,$70,$ac), + ($34,$2e,$53,$9d), ($3a,$27,$5e,$96), ($28,$3c,$49,$8b), ($26,$35,$44,$80), + ($7c,$42,$0f,$e9), ($72,$4b,$02,$e2), ($60,$50,$15,$ff), ($6e,$59,$18,$f4), + ($44,$66,$3b,$c5), ($4a,$6f,$36,$ce), ($58,$74,$21,$d3), ($56,$7d,$2c,$d8), + ($37,$a1,$0c,$7a), ($39,$a8,$01,$71), ($2b,$b3,$16,$6c), ($25,$ba,$1b,$67), + ($0f,$85,$38,$56), ($01,$8c,$35,$5d), ($13,$97,$22,$40), ($1d,$9e,$2f,$4b), + ($47,$e9,$64,$22), ($49,$e0,$69,$29), ($5b,$fb,$7e,$34), ($55,$f2,$73,$3f), + ($7f,$cd,$50,$0e), ($71,$c4,$5d,$05), ($63,$df,$4a,$18), ($6d,$d6,$47,$13), + ($d7,$31,$dc,$ca), ($d9,$38,$d1,$c1), ($cb,$23,$c6,$dc), ($c5,$2a,$cb,$d7), + ($ef,$15,$e8,$e6), ($e1,$1c,$e5,$ed), ($f3,$07,$f2,$f0), ($fd,$0e,$ff,$fb), + ($a7,$79,$b4,$92), ($a9,$70,$b9,$99), ($bb,$6b,$ae,$84), ($b5,$62,$a3,$8f), + ($9f,$5d,$80,$be), ($91,$54,$8d,$b5), ($83,$4f,$9a,$a8), ($8d,$46,$97,$a3)); + U2: array[0..255,0..3] of byte= ( + ($00,$00,$00,$00), ($0b,$0e,$09,$0d), ($16,$1c,$12,$1a), ($1d,$12,$1b,$17), + ($2c,$38,$24,$34), ($27,$36,$2d,$39), ($3a,$24,$36,$2e), ($31,$2a,$3f,$23), + ($58,$70,$48,$68), ($53,$7e,$41,$65), ($4e,$6c,$5a,$72), ($45,$62,$53,$7f), + ($74,$48,$6c,$5c), ($7f,$46,$65,$51), ($62,$54,$7e,$46), ($69,$5a,$77,$4b), + ($b0,$e0,$90,$d0), ($bb,$ee,$99,$dd), ($a6,$fc,$82,$ca), ($ad,$f2,$8b,$c7), + ($9c,$d8,$b4,$e4), ($97,$d6,$bd,$e9), ($8a,$c4,$a6,$fe), ($81,$ca,$af,$f3), + ($e8,$90,$d8,$b8), ($e3,$9e,$d1,$b5), ($fe,$8c,$ca,$a2), ($f5,$82,$c3,$af), + ($c4,$a8,$fc,$8c), ($cf,$a6,$f5,$81), ($d2,$b4,$ee,$96), ($d9,$ba,$e7,$9b), + ($7b,$db,$3b,$bb), ($70,$d5,$32,$b6), ($6d,$c7,$29,$a1), ($66,$c9,$20,$ac), + ($57,$e3,$1f,$8f), ($5c,$ed,$16,$82), ($41,$ff,$0d,$95), ($4a,$f1,$04,$98), + ($23,$ab,$73,$d3), ($28,$a5,$7a,$de), ($35,$b7,$61,$c9), ($3e,$b9,$68,$c4), + ($0f,$93,$57,$e7), ($04,$9d,$5e,$ea), ($19,$8f,$45,$fd), ($12,$81,$4c,$f0), + ($cb,$3b,$ab,$6b), ($c0,$35,$a2,$66), ($dd,$27,$b9,$71), ($d6,$29,$b0,$7c), + ($e7,$03,$8f,$5f), ($ec,$0d,$86,$52), ($f1,$1f,$9d,$45), ($fa,$11,$94,$48), + ($93,$4b,$e3,$03), ($98,$45,$ea,$0e), ($85,$57,$f1,$19), ($8e,$59,$f8,$14), + ($bf,$73,$c7,$37), ($b4,$7d,$ce,$3a), ($a9,$6f,$d5,$2d), ($a2,$61,$dc,$20), + ($f6,$ad,$76,$6d), ($fd,$a3,$7f,$60), ($e0,$b1,$64,$77), ($eb,$bf,$6d,$7a), + ($da,$95,$52,$59), ($d1,$9b,$5b,$54), ($cc,$89,$40,$43), ($c7,$87,$49,$4e), + ($ae,$dd,$3e,$05), ($a5,$d3,$37,$08), ($b8,$c1,$2c,$1f), ($b3,$cf,$25,$12), + ($82,$e5,$1a,$31), ($89,$eb,$13,$3c), ($94,$f9,$08,$2b), ($9f,$f7,$01,$26), + ($46,$4d,$e6,$bd), ($4d,$43,$ef,$b0), ($50,$51,$f4,$a7), ($5b,$5f,$fd,$aa), + ($6a,$75,$c2,$89), ($61,$7b,$cb,$84), ($7c,$69,$d0,$93), ($77,$67,$d9,$9e), + ($1e,$3d,$ae,$d5), ($15,$33,$a7,$d8), ($08,$21,$bc,$cf), ($03,$2f,$b5,$c2), + ($32,$05,$8a,$e1), ($39,$0b,$83,$ec), ($24,$19,$98,$fb), ($2f,$17,$91,$f6), + ($8d,$76,$4d,$d6), ($86,$78,$44,$db), ($9b,$6a,$5f,$cc), ($90,$64,$56,$c1), + ($a1,$4e,$69,$e2), ($aa,$40,$60,$ef), ($b7,$52,$7b,$f8), ($bc,$5c,$72,$f5), + ($d5,$06,$05,$be), ($de,$08,$0c,$b3), ($c3,$1a,$17,$a4), ($c8,$14,$1e,$a9), + ($f9,$3e,$21,$8a), ($f2,$30,$28,$87), ($ef,$22,$33,$90), ($e4,$2c,$3a,$9d), + ($3d,$96,$dd,$06), ($36,$98,$d4,$0b), ($2b,$8a,$cf,$1c), ($20,$84,$c6,$11), + ($11,$ae,$f9,$32), ($1a,$a0,$f0,$3f), ($07,$b2,$eb,$28), ($0c,$bc,$e2,$25), + ($65,$e6,$95,$6e), ($6e,$e8,$9c,$63), ($73,$fa,$87,$74), ($78,$f4,$8e,$79), + ($49,$de,$b1,$5a), ($42,$d0,$b8,$57), ($5f,$c2,$a3,$40), ($54,$cc,$aa,$4d), + ($f7,$41,$ec,$da), ($fc,$4f,$e5,$d7), ($e1,$5d,$fe,$c0), ($ea,$53,$f7,$cd), + ($db,$79,$c8,$ee), ($d0,$77,$c1,$e3), ($cd,$65,$da,$f4), ($c6,$6b,$d3,$f9), + ($af,$31,$a4,$b2), ($a4,$3f,$ad,$bf), ($b9,$2d,$b6,$a8), ($b2,$23,$bf,$a5), + ($83,$09,$80,$86), ($88,$07,$89,$8b), ($95,$15,$92,$9c), ($9e,$1b,$9b,$91), + ($47,$a1,$7c,$0a), ($4c,$af,$75,$07), ($51,$bd,$6e,$10), ($5a,$b3,$67,$1d), + ($6b,$99,$58,$3e), ($60,$97,$51,$33), ($7d,$85,$4a,$24), ($76,$8b,$43,$29), + ($1f,$d1,$34,$62), ($14,$df,$3d,$6f), ($09,$cd,$26,$78), ($02,$c3,$2f,$75), + ($33,$e9,$10,$56), ($38,$e7,$19,$5b), ($25,$f5,$02,$4c), ($2e,$fb,$0b,$41), + ($8c,$9a,$d7,$61), ($87,$94,$de,$6c), ($9a,$86,$c5,$7b), ($91,$88,$cc,$76), + ($a0,$a2,$f3,$55), ($ab,$ac,$fa,$58), ($b6,$be,$e1,$4f), ($bd,$b0,$e8,$42), + ($d4,$ea,$9f,$09), ($df,$e4,$96,$04), ($c2,$f6,$8d,$13), ($c9,$f8,$84,$1e), + ($f8,$d2,$bb,$3d), ($f3,$dc,$b2,$30), ($ee,$ce,$a9,$27), ($e5,$c0,$a0,$2a), + ($3c,$7a,$47,$b1), ($37,$74,$4e,$bc), ($2a,$66,$55,$ab), ($21,$68,$5c,$a6), + ($10,$42,$63,$85), ($1b,$4c,$6a,$88), ($06,$5e,$71,$9f), ($0d,$50,$78,$92), + ($64,$0a,$0f,$d9), ($6f,$04,$06,$d4), ($72,$16,$1d,$c3), ($79,$18,$14,$ce), + ($48,$32,$2b,$ed), ($43,$3c,$22,$e0), ($5e,$2e,$39,$f7), ($55,$20,$30,$fa), + ($01,$ec,$9a,$b7), ($0a,$e2,$93,$ba), ($17,$f0,$88,$ad), ($1c,$fe,$81,$a0), + ($2d,$d4,$be,$83), ($26,$da,$b7,$8e), ($3b,$c8,$ac,$99), ($30,$c6,$a5,$94), + ($59,$9c,$d2,$df), ($52,$92,$db,$d2), ($4f,$80,$c0,$c5), ($44,$8e,$c9,$c8), + ($75,$a4,$f6,$eb), ($7e,$aa,$ff,$e6), ($63,$b8,$e4,$f1), ($68,$b6,$ed,$fc), + ($b1,$0c,$0a,$67), ($ba,$02,$03,$6a), ($a7,$10,$18,$7d), ($ac,$1e,$11,$70), + ($9d,$34,$2e,$53), ($96,$3a,$27,$5e), ($8b,$28,$3c,$49), ($80,$26,$35,$44), + ($e9,$7c,$42,$0f), ($e2,$72,$4b,$02), ($ff,$60,$50,$15), ($f4,$6e,$59,$18), + ($c5,$44,$66,$3b), ($ce,$4a,$6f,$36), ($d3,$58,$74,$21), ($d8,$56,$7d,$2c), + ($7a,$37,$a1,$0c), ($71,$39,$a8,$01), ($6c,$2b,$b3,$16), ($67,$25,$ba,$1b), + ($56,$0f,$85,$38), ($5d,$01,$8c,$35), ($40,$13,$97,$22), ($4b,$1d,$9e,$2f), + ($22,$47,$e9,$64), ($29,$49,$e0,$69), ($34,$5b,$fb,$7e), ($3f,$55,$f2,$73), + ($0e,$7f,$cd,$50), ($05,$71,$c4,$5d), ($18,$63,$df,$4a), ($13,$6d,$d6,$47), + ($ca,$d7,$31,$dc), ($c1,$d9,$38,$d1), ($dc,$cb,$23,$c6), ($d7,$c5,$2a,$cb), + ($e6,$ef,$15,$e8), ($ed,$e1,$1c,$e5), ($f0,$f3,$07,$f2), ($fb,$fd,$0e,$ff), + ($92,$a7,$79,$b4), ($99,$a9,$70,$b9), ($84,$bb,$6b,$ae), ($8f,$b5,$62,$a3), + ($be,$9f,$5d,$80), ($b5,$91,$54,$8d), ($a8,$83,$4f,$9a), ($a3,$8d,$46,$97)); + U3: array[0..255,0..3] of byte= ( + ($00,$00,$00,$00), ($0d,$0b,$0e,$09), ($1a,$16,$1c,$12), ($17,$1d,$12,$1b), + ($34,$2c,$38,$24), ($39,$27,$36,$2d), ($2e,$3a,$24,$36), ($23,$31,$2a,$3f), + ($68,$58,$70,$48), ($65,$53,$7e,$41), ($72,$4e,$6c,$5a), ($7f,$45,$62,$53), + ($5c,$74,$48,$6c), ($51,$7f,$46,$65), ($46,$62,$54,$7e), ($4b,$69,$5a,$77), + ($d0,$b0,$e0,$90), ($dd,$bb,$ee,$99), ($ca,$a6,$fc,$82), ($c7,$ad,$f2,$8b), + ($e4,$9c,$d8,$b4), ($e9,$97,$d6,$bd), ($fe,$8a,$c4,$a6), ($f3,$81,$ca,$af), + ($b8,$e8,$90,$d8), ($b5,$e3,$9e,$d1), ($a2,$fe,$8c,$ca), ($af,$f5,$82,$c3), + ($8c,$c4,$a8,$fc), ($81,$cf,$a6,$f5), ($96,$d2,$b4,$ee), ($9b,$d9,$ba,$e7), + ($bb,$7b,$db,$3b), ($b6,$70,$d5,$32), ($a1,$6d,$c7,$29), ($ac,$66,$c9,$20), + ($8f,$57,$e3,$1f), ($82,$5c,$ed,$16), ($95,$41,$ff,$0d), ($98,$4a,$f1,$04), + ($d3,$23,$ab,$73), ($de,$28,$a5,$7a), ($c9,$35,$b7,$61), ($c4,$3e,$b9,$68), + ($e7,$0f,$93,$57), ($ea,$04,$9d,$5e), ($fd,$19,$8f,$45), ($f0,$12,$81,$4c), + ($6b,$cb,$3b,$ab), ($66,$c0,$35,$a2), ($71,$dd,$27,$b9), ($7c,$d6,$29,$b0), + ($5f,$e7,$03,$8f), ($52,$ec,$0d,$86), ($45,$f1,$1f,$9d), ($48,$fa,$11,$94), + ($03,$93,$4b,$e3), ($0e,$98,$45,$ea), ($19,$85,$57,$f1), ($14,$8e,$59,$f8), + ($37,$bf,$73,$c7), ($3a,$b4,$7d,$ce), ($2d,$a9,$6f,$d5), ($20,$a2,$61,$dc), + ($6d,$f6,$ad,$76), ($60,$fd,$a3,$7f), ($77,$e0,$b1,$64), ($7a,$eb,$bf,$6d), + ($59,$da,$95,$52), ($54,$d1,$9b,$5b), ($43,$cc,$89,$40), ($4e,$c7,$87,$49), + ($05,$ae,$dd,$3e), ($08,$a5,$d3,$37), ($1f,$b8,$c1,$2c), ($12,$b3,$cf,$25), + ($31,$82,$e5,$1a), ($3c,$89,$eb,$13), ($2b,$94,$f9,$08), ($26,$9f,$f7,$01), + ($bd,$46,$4d,$e6), ($b0,$4d,$43,$ef), ($a7,$50,$51,$f4), ($aa,$5b,$5f,$fd), + ($89,$6a,$75,$c2), ($84,$61,$7b,$cb), ($93,$7c,$69,$d0), ($9e,$77,$67,$d9), + ($d5,$1e,$3d,$ae), ($d8,$15,$33,$a7), ($cf,$08,$21,$bc), ($c2,$03,$2f,$b5), + ($e1,$32,$05,$8a), ($ec,$39,$0b,$83), ($fb,$24,$19,$98), ($f6,$2f,$17,$91), + ($d6,$8d,$76,$4d), ($db,$86,$78,$44), ($cc,$9b,$6a,$5f), ($c1,$90,$64,$56), + ($e2,$a1,$4e,$69), ($ef,$aa,$40,$60), ($f8,$b7,$52,$7b), ($f5,$bc,$5c,$72), + ($be,$d5,$06,$05), ($b3,$de,$08,$0c), ($a4,$c3,$1a,$17), ($a9,$c8,$14,$1e), + ($8a,$f9,$3e,$21), ($87,$f2,$30,$28), ($90,$ef,$22,$33), ($9d,$e4,$2c,$3a), + ($06,$3d,$96,$dd), ($0b,$36,$98,$d4), ($1c,$2b,$8a,$cf), ($11,$20,$84,$c6), + ($32,$11,$ae,$f9), ($3f,$1a,$a0,$f0), ($28,$07,$b2,$eb), ($25,$0c,$bc,$e2), + ($6e,$65,$e6,$95), ($63,$6e,$e8,$9c), ($74,$73,$fa,$87), ($79,$78,$f4,$8e), + ($5a,$49,$de,$b1), ($57,$42,$d0,$b8), ($40,$5f,$c2,$a3), ($4d,$54,$cc,$aa), + ($da,$f7,$41,$ec), ($d7,$fc,$4f,$e5), ($c0,$e1,$5d,$fe), ($cd,$ea,$53,$f7), + ($ee,$db,$79,$c8), ($e3,$d0,$77,$c1), ($f4,$cd,$65,$da), ($f9,$c6,$6b,$d3), + ($b2,$af,$31,$a4), ($bf,$a4,$3f,$ad), ($a8,$b9,$2d,$b6), ($a5,$b2,$23,$bf), + ($86,$83,$09,$80), ($8b,$88,$07,$89), ($9c,$95,$15,$92), ($91,$9e,$1b,$9b), + ($0a,$47,$a1,$7c), ($07,$4c,$af,$75), ($10,$51,$bd,$6e), ($1d,$5a,$b3,$67), + ($3e,$6b,$99,$58), ($33,$60,$97,$51), ($24,$7d,$85,$4a), ($29,$76,$8b,$43), + ($62,$1f,$d1,$34), ($6f,$14,$df,$3d), ($78,$09,$cd,$26), ($75,$02,$c3,$2f), + ($56,$33,$e9,$10), ($5b,$38,$e7,$19), ($4c,$25,$f5,$02), ($41,$2e,$fb,$0b), + ($61,$8c,$9a,$d7), ($6c,$87,$94,$de), ($7b,$9a,$86,$c5), ($76,$91,$88,$cc), + ($55,$a0,$a2,$f3), ($58,$ab,$ac,$fa), ($4f,$b6,$be,$e1), ($42,$bd,$b0,$e8), + ($09,$d4,$ea,$9f), ($04,$df,$e4,$96), ($13,$c2,$f6,$8d), ($1e,$c9,$f8,$84), + ($3d,$f8,$d2,$bb), ($30,$f3,$dc,$b2), ($27,$ee,$ce,$a9), ($2a,$e5,$c0,$a0), + ($b1,$3c,$7a,$47), ($bc,$37,$74,$4e), ($ab,$2a,$66,$55), ($a6,$21,$68,$5c), + ($85,$10,$42,$63), ($88,$1b,$4c,$6a), ($9f,$06,$5e,$71), ($92,$0d,$50,$78), + ($d9,$64,$0a,$0f), ($d4,$6f,$04,$06), ($c3,$72,$16,$1d), ($ce,$79,$18,$14), + ($ed,$48,$32,$2b), ($e0,$43,$3c,$22), ($f7,$5e,$2e,$39), ($fa,$55,$20,$30), + ($b7,$01,$ec,$9a), ($ba,$0a,$e2,$93), ($ad,$17,$f0,$88), ($a0,$1c,$fe,$81), + ($83,$2d,$d4,$be), ($8e,$26,$da,$b7), ($99,$3b,$c8,$ac), ($94,$30,$c6,$a5), + ($df,$59,$9c,$d2), ($d2,$52,$92,$db), ($c5,$4f,$80,$c0), ($c8,$44,$8e,$c9), + ($eb,$75,$a4,$f6), ($e6,$7e,$aa,$ff), ($f1,$63,$b8,$e4), ($fc,$68,$b6,$ed), + ($67,$b1,$0c,$0a), ($6a,$ba,$02,$03), ($7d,$a7,$10,$18), ($70,$ac,$1e,$11), + ($53,$9d,$34,$2e), ($5e,$96,$3a,$27), ($49,$8b,$28,$3c), ($44,$80,$26,$35), + ($0f,$e9,$7c,$42), ($02,$e2,$72,$4b), ($15,$ff,$60,$50), ($18,$f4,$6e,$59), + ($3b,$c5,$44,$66), ($36,$ce,$4a,$6f), ($21,$d3,$58,$74), ($2c,$d8,$56,$7d), + ($0c,$7a,$37,$a1), ($01,$71,$39,$a8), ($16,$6c,$2b,$b3), ($1b,$67,$25,$ba), + ($38,$56,$0f,$85), ($35,$5d,$01,$8c), ($22,$40,$13,$97), ($2f,$4b,$1d,$9e), + ($64,$22,$47,$e9), ($69,$29,$49,$e0), ($7e,$34,$5b,$fb), ($73,$3f,$55,$f2), + ($50,$0e,$7f,$cd), ($5d,$05,$71,$c4), ($4a,$18,$63,$df), ($47,$13,$6d,$d6), + ($dc,$ca,$d7,$31), ($d1,$c1,$d9,$38), ($c6,$dc,$cb,$23), ($cb,$d7,$c5,$2a), + ($e8,$e6,$ef,$15), ($e5,$ed,$e1,$1c), ($f2,$f0,$f3,$07), ($ff,$fb,$fd,$0e), + ($b4,$92,$a7,$79), ($b9,$99,$a9,$70), ($ae,$84,$bb,$6b), ($a3,$8f,$b5,$62), + ($80,$be,$9f,$5d), ($8d,$b5,$91,$54), ($9a,$a8,$83,$4f), ($97,$a3,$8d,$46)); + U4: array[0..255,0..3] of byte= ( + ($00,$00,$00,$00), ($09,$0d,$0b,$0e), ($12,$1a,$16,$1c), ($1b,$17,$1d,$12), + ($24,$34,$2c,$38), ($2d,$39,$27,$36), ($36,$2e,$3a,$24), ($3f,$23,$31,$2a), + ($48,$68,$58,$70), ($41,$65,$53,$7e), ($5a,$72,$4e,$6c), ($53,$7f,$45,$62), + ($6c,$5c,$74,$48), ($65,$51,$7f,$46), ($7e,$46,$62,$54), ($77,$4b,$69,$5a), + ($90,$d0,$b0,$e0), ($99,$dd,$bb,$ee), ($82,$ca,$a6,$fc), ($8b,$c7,$ad,$f2), + ($b4,$e4,$9c,$d8), ($bd,$e9,$97,$d6), ($a6,$fe,$8a,$c4), ($af,$f3,$81,$ca), + ($d8,$b8,$e8,$90), ($d1,$b5,$e3,$9e), ($ca,$a2,$fe,$8c), ($c3,$af,$f5,$82), + ($fc,$8c,$c4,$a8), ($f5,$81,$cf,$a6), ($ee,$96,$d2,$b4), ($e7,$9b,$d9,$ba), + ($3b,$bb,$7b,$db), ($32,$b6,$70,$d5), ($29,$a1,$6d,$c7), ($20,$ac,$66,$c9), + ($1f,$8f,$57,$e3), ($16,$82,$5c,$ed), ($0d,$95,$41,$ff), ($04,$98,$4a,$f1), + ($73,$d3,$23,$ab), ($7a,$de,$28,$a5), ($61,$c9,$35,$b7), ($68,$c4,$3e,$b9), + ($57,$e7,$0f,$93), ($5e,$ea,$04,$9d), ($45,$fd,$19,$8f), ($4c,$f0,$12,$81), + ($ab,$6b,$cb,$3b), ($a2,$66,$c0,$35), ($b9,$71,$dd,$27), ($b0,$7c,$d6,$29), + ($8f,$5f,$e7,$03), ($86,$52,$ec,$0d), ($9d,$45,$f1,$1f), ($94,$48,$fa,$11), + ($e3,$03,$93,$4b), ($ea,$0e,$98,$45), ($f1,$19,$85,$57), ($f8,$14,$8e,$59), + ($c7,$37,$bf,$73), ($ce,$3a,$b4,$7d), ($d5,$2d,$a9,$6f), ($dc,$20,$a2,$61), + ($76,$6d,$f6,$ad), ($7f,$60,$fd,$a3), ($64,$77,$e0,$b1), ($6d,$7a,$eb,$bf), + ($52,$59,$da,$95), ($5b,$54,$d1,$9b), ($40,$43,$cc,$89), ($49,$4e,$c7,$87), + ($3e,$05,$ae,$dd), ($37,$08,$a5,$d3), ($2c,$1f,$b8,$c1), ($25,$12,$b3,$cf), + ($1a,$31,$82,$e5), ($13,$3c,$89,$eb), ($08,$2b,$94,$f9), ($01,$26,$9f,$f7), + ($e6,$bd,$46,$4d), ($ef,$b0,$4d,$43), ($f4,$a7,$50,$51), ($fd,$aa,$5b,$5f), + ($c2,$89,$6a,$75), ($cb,$84,$61,$7b), ($d0,$93,$7c,$69), ($d9,$9e,$77,$67), + ($ae,$d5,$1e,$3d), ($a7,$d8,$15,$33), ($bc,$cf,$08,$21), ($b5,$c2,$03,$2f), + ($8a,$e1,$32,$05), ($83,$ec,$39,$0b), ($98,$fb,$24,$19), ($91,$f6,$2f,$17), + ($4d,$d6,$8d,$76), ($44,$db,$86,$78), ($5f,$cc,$9b,$6a), ($56,$c1,$90,$64), + ($69,$e2,$a1,$4e), ($60,$ef,$aa,$40), ($7b,$f8,$b7,$52), ($72,$f5,$bc,$5c), + ($05,$be,$d5,$06), ($0c,$b3,$de,$08), ($17,$a4,$c3,$1a), ($1e,$a9,$c8,$14), + ($21,$8a,$f9,$3e), ($28,$87,$f2,$30), ($33,$90,$ef,$22), ($3a,$9d,$e4,$2c), + ($dd,$06,$3d,$96), ($d4,$0b,$36,$98), ($cf,$1c,$2b,$8a), ($c6,$11,$20,$84), + ($f9,$32,$11,$ae), ($f0,$3f,$1a,$a0), ($eb,$28,$07,$b2), ($e2,$25,$0c,$bc), + ($95,$6e,$65,$e6), ($9c,$63,$6e,$e8), ($87,$74,$73,$fa), ($8e,$79,$78,$f4), + ($b1,$5a,$49,$de), ($b8,$57,$42,$d0), ($a3,$40,$5f,$c2), ($aa,$4d,$54,$cc), + ($ec,$da,$f7,$41), ($e5,$d7,$fc,$4f), ($fe,$c0,$e1,$5d), ($f7,$cd,$ea,$53), + ($c8,$ee,$db,$79), ($c1,$e3,$d0,$77), ($da,$f4,$cd,$65), ($d3,$f9,$c6,$6b), + ($a4,$b2,$af,$31), ($ad,$bf,$a4,$3f), ($b6,$a8,$b9,$2d), ($bf,$a5,$b2,$23), + ($80,$86,$83,$09), ($89,$8b,$88,$07), ($92,$9c,$95,$15), ($9b,$91,$9e,$1b), + ($7c,$0a,$47,$a1), ($75,$07,$4c,$af), ($6e,$10,$51,$bd), ($67,$1d,$5a,$b3), + ($58,$3e,$6b,$99), ($51,$33,$60,$97), ($4a,$24,$7d,$85), ($43,$29,$76,$8b), + ($34,$62,$1f,$d1), ($3d,$6f,$14,$df), ($26,$78,$09,$cd), ($2f,$75,$02,$c3), + ($10,$56,$33,$e9), ($19,$5b,$38,$e7), ($02,$4c,$25,$f5), ($0b,$41,$2e,$fb), + ($d7,$61,$8c,$9a), ($de,$6c,$87,$94), ($c5,$7b,$9a,$86), ($cc,$76,$91,$88), + ($f3,$55,$a0,$a2), ($fa,$58,$ab,$ac), ($e1,$4f,$b6,$be), ($e8,$42,$bd,$b0), + ($9f,$09,$d4,$ea), ($96,$04,$df,$e4), ($8d,$13,$c2,$f6), ($84,$1e,$c9,$f8), + ($bb,$3d,$f8,$d2), ($b2,$30,$f3,$dc), ($a9,$27,$ee,$ce), ($a0,$2a,$e5,$c0), + ($47,$b1,$3c,$7a), ($4e,$bc,$37,$74), ($55,$ab,$2a,$66), ($5c,$a6,$21,$68), + ($63,$85,$10,$42), ($6a,$88,$1b,$4c), ($71,$9f,$06,$5e), ($78,$92,$0d,$50), + ($0f,$d9,$64,$0a), ($06,$d4,$6f,$04), ($1d,$c3,$72,$16), ($14,$ce,$79,$18), + ($2b,$ed,$48,$32), ($22,$e0,$43,$3c), ($39,$f7,$5e,$2e), ($30,$fa,$55,$20), + ($9a,$b7,$01,$ec), ($93,$ba,$0a,$e2), ($88,$ad,$17,$f0), ($81,$a0,$1c,$fe), + ($be,$83,$2d,$d4), ($b7,$8e,$26,$da), ($ac,$99,$3b,$c8), ($a5,$94,$30,$c6), + ($d2,$df,$59,$9c), ($db,$d2,$52,$92), ($c0,$c5,$4f,$80), ($c9,$c8,$44,$8e), + ($f6,$eb,$75,$a4), ($ff,$e6,$7e,$aa), ($e4,$f1,$63,$b8), ($ed,$fc,$68,$b6), + ($0a,$67,$b1,$0c), ($03,$6a,$ba,$02), ($18,$7d,$a7,$10), ($11,$70,$ac,$1e), + ($2e,$53,$9d,$34), ($27,$5e,$96,$3a), ($3c,$49,$8b,$28), ($35,$44,$80,$26), + ($42,$0f,$e9,$7c), ($4b,$02,$e2,$72), ($50,$15,$ff,$60), ($59,$18,$f4,$6e), + ($66,$3b,$c5,$44), ($6f,$36,$ce,$4a), ($74,$21,$d3,$58), ($7d,$2c,$d8,$56), + ($a1,$0c,$7a,$37), ($a8,$01,$71,$39), ($b3,$16,$6c,$2b), ($ba,$1b,$67,$25), + ($85,$38,$56,$0f), ($8c,$35,$5d,$01), ($97,$22,$40,$13), ($9e,$2f,$4b,$1d), + ($e9,$64,$22,$47), ($e0,$69,$29,$49), ($fb,$7e,$34,$5b), ($f2,$73,$3f,$55), + ($cd,$50,$0e,$7f), ($c4,$5d,$05,$71), ($df,$4a,$18,$63), ($d6,$47,$13,$6d), + ($31,$dc,$ca,$d7), ($38,$d1,$c1,$d9), ($23,$c6,$dc,$cb), ($2a,$cb,$d7,$c5), + ($15,$e8,$e6,$ef), ($1c,$e5,$ed,$e1), ($07,$f2,$f0,$f3), ($0e,$ff,$fb,$fd), + ($79,$b4,$92,$a7), ($70,$b9,$99,$a9), ($6b,$ae,$84,$bb), ($62,$a3,$8f,$b5), + ($5d,$80,$be,$9f), ($54,$8d,$b5,$91), ($4f,$9a,$a8,$83), ($46,$97,$a3,$8d)); + + rcon: array[0..29] of cardinal= ( + $01, $02, $04, $08, $10, $20, $40, $80, $1b, $36, $6c, $d8, $ab, $4d, $9a, + $2f, $5e, $bc, $63, $c6, $97, $35, $6a, $d4, $b3, $7d, $fa, $ef, $c5, $91); + +{==============================================================================} +type + PDWord = ^LongWord; + +procedure hperm_op(var a, t: integer; n, m: integer); +begin + t:= ((a shl (16 - n)) xor a) and m; + a:= a xor t xor (t shr (16 - n)); +end; + +procedure perm_op(var a, b, t: integer; n, m: integer); +begin + t:= ((a shr n) xor b) and m; + b:= b xor t; + a:= a xor (t shl n); +end; + +{==============================================================================} +function TSynaBlockCipher.GetSize: byte; +begin + Result := 8; +end; + +procedure TSynaBlockCipher.IncCounter; +var + i: integer; +begin + Inc(CV[GetSize]); + i:= GetSize -1; + while (i> 0) and (CV[i + 1] = #0) do + begin + Inc(CV[i]); + Dec(i); + end; +end; + +procedure TSynaBlockCipher.Reset; +begin + CV := IV; +end; + +procedure TSynaBlockCipher.InitKey(Key: AnsiString); +begin +end; + +procedure TSynaBlockCipher.SetIV(const Value: AnsiString); +begin + IV := PadString(Value, GetSize, #0); + Reset; +end; + +function TSynaBlockCipher.GetIV: AnsiString; +begin + Result := CV; +end; + +function TSynaBlockCipher.EncryptECB(const InData: AnsiString): AnsiString; +begin + Result := InData; +end; + +function TSynaBlockCipher.DecryptECB(const InData: AnsiString): AnsiString; +begin + Result := InData; +end; + +function TSynaBlockCipher.EncryptCBC(const Indata: AnsiString): AnsiString; +var + i: integer; + s: ansistring; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + s := copy(Indata, (i - 1) * bs + 1, bs); + s := XorString(s, CV); + s := EncryptECB(s); + CV := s; + Result := Result + s; + end; + if (l mod bs)<> 0 then + begin + CV := EncryptECB(CV); + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, CV); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.DecryptCBC(const Indata: AnsiString): AnsiString; +var + i: integer; + s, temp: ansistring; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + s := copy(Indata, (i - 1) * bs + 1, bs); + temp := s; + s := DecryptECB(s); + s := XorString(s, CV); + Result := Result + s; + CV := Temp; + end; + if (l mod bs)<> 0 then + begin + CV := EncryptECB(CV); + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, CV); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.EncryptCFB8bit(const Indata: AnsiString): AnsiString; +var + i: integer; + Temp: AnsiString; + c: AnsiChar; +begin + Result := ''; + for i:= 1 to Length(Indata) do + begin + Temp := EncryptECB(CV); + c := AnsiChar(ord(InData[i]) xor ord(temp[1])); + Result := Result + c; + Delete(CV, 1, 1); + CV := CV + c; + end; +end; + +function TSynaBlockCipher.DecryptCFB8bit(const Indata: AnsiString): AnsiString; +var + i: integer; + Temp: AnsiString; + c: AnsiChar; +begin + Result := ''; + for i:= 1 to length(Indata) do + begin + c:= Indata[i]; + Temp := EncryptECB(CV); + Result := Result + AnsiChar(ord(InData[i]) xor ord(temp[1])); + Delete(CV, 1, 1); + CV := CV + c; + end; +end; + +function TSynaBlockCipher.EncryptCFBblock(const Indata: AnsiString): AnsiString; +var + i: integer; + s: AnsiString; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + CV := EncryptECB(CV); + s := copy(Indata, (i - 1) * bs + 1, bs); + s := XorString(s, CV); + Result := Result + s; + CV := s; + end; + if (l mod bs)<> 0 then + begin + CV := EncryptECB(CV); + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, CV); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.DecryptCFBblock(const Indata: AnsiString): AnsiString; +var + i: integer; + S, Temp: AnsiString; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + s := copy(Indata, (i - 1) * bs + 1, bs); + Temp := s; + CV := EncryptECB(CV); + s := XorString(s, CV); + Result := result + s; + CV := temp; + end; + if (l mod bs)<> 0 then + begin + CV := EncryptECB(CV); + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, CV); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.EncryptOFB(const Indata: AnsiString): AnsiString; +var + i: integer; + s: AnsiString; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + CV := EncryptECB(CV); + s := copy(Indata, (i - 1) * bs + 1, bs); + s := XorString(s, CV); + Result := Result + s; + end; + if (l mod bs)<> 0 then + begin + CV := EncryptECB(CV); + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, CV); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.DecryptOFB(const Indata: AnsiString): AnsiString; +var + i: integer; + s: AnsiString; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + Cv := EncryptECB(CV); + s := copy(Indata, (i - 1) * bs + 1, bs); + s := XorString(s, CV); + Result := Result + s; + end; + if (l mod bs)<> 0 then + begin + CV := EncryptECB(CV); + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, CV); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.EncryptCTR(const Indata: AnsiString): AnsiString; +var + temp: AnsiString; + i: integer; + s: AnsiString; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + temp := EncryptECB(CV); + IncCounter; + s := copy(Indata, (i - 1) * bs + 1, bs); + s := XorString(s, temp); + Result := Result + s; + end; + if (l mod bs)<> 0 then + begin + temp := EncryptECB(CV); + IncCounter; + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, temp); + Result := Result + s; + end; +end; + +function TSynaBlockCipher.DecryptCTR(const Indata: AnsiString): AnsiString; +var + temp: AnsiString; + s: AnsiString; + i: integer; + l: integer; + bs: byte; +begin + Result := ''; + l := Length(InData); + bs := GetSize; + for i:= 1 to (l div bs) do + begin + temp := EncryptECB(CV); + IncCounter; + s := copy(Indata, (i - 1) * bs + 1, bs); + s := XorString(s, temp); + Result := Result + s; + end; + if (l mod bs)<> 0 then + begin + temp := EncryptECB(CV); + IncCounter; + s := copy(Indata, (l div bs) * bs + 1, l mod bs); + s := XorString(s, temp); + Result := Result + s; + end; +end; + +constructor TSynaBlockCipher.Create(Key: AnsiString); +begin + inherited Create; + InitKey(Key); + IV := StringOfChar(#0, GetSize); + IV := EncryptECB(IV); + Reset; +end; + +{==============================================================================} + +procedure TSynaCustomDes.DoInit(KeyB: AnsiString; var KeyData: TDesKeyData); +var + c, d, t, s, t2, i: integer; +begin + KeyB := PadString(KeyB, 8, #0); + c:= ord(KeyB[1]) or (ord(KeyB[2]) shl 8) or (ord(KeyB[3]) shl 16) or (ord(KeyB[4]) shl 24); + d:= ord(KeyB[5]) or (ord(KeyB[6]) shl 8) or (ord(KeyB[7]) shl 16) or (ord(KeyB[8]) shl 24); + perm_op(d,c,t,4,integer($0f0f0f0f)); + hperm_op(c,t,integer(-2),integer($cccc0000)); + hperm_op(d,t,integer(-2),integer($cccc0000)); + perm_op(d,c,t,1,integer($55555555)); + perm_op(c,d,t,8,integer($00ff00ff)); + perm_op(d,c,t,1,integer($55555555)); + d:= ((d and $ff) shl 16) or (d and $ff00) or ((d and $ff0000) shr 16) or + ((c and integer($f0000000)) shr 4); + c:= c and $fffffff; + for i:= 0 to 15 do + begin + if shifts2[i]<> 0 then + begin + c:= ((c shr 2) or (c shl 26)); + d:= ((d shr 2) or (d shl 26)); + end + else + begin + c:= ((c shr 1) or (c shl 27)); + d:= ((d shr 1) or (d shl 27)); + end; + c:= c and $fffffff; + d:= d and $fffffff; + s:= des_skb[0,c and $3f] or + des_skb[1,((c shr 6) and $03) or ((c shr 7) and $3c)] or + des_skb[2,((c shr 13) and $0f) or ((c shr 14) and $30)] or + des_skb[3,((c shr 20) and $01) or ((c shr 21) and $06) or ((c shr 22) and $38)]; + t:= des_skb[4,d and $3f] or + des_skb[5,((d shr 7) and $03) or ((d shr 8) and $3c)] or + des_skb[6, (d shr 15) and $3f ] or + des_skb[7,((d shr 21) and $0f) or ((d shr 22) and $30)]; + t2:= ((t shl 16) or (s and $ffff)); + KeyData[(i shl 1)]:= ((t2 shl 2) or (t2 shr 30)); + t2:= ((s shr 16) or (t and integer($ffff0000))); + KeyData[(i shl 1)+1]:= ((t2 shl 6) or (t2 shr 26)); + end; +end; + +function TSynaCustomDes.EncryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; +var + l, r, t, u: integer; + i: longint; +begin + r := Swapbytes(DecodeLongint(Indata, 1)); + l := swapbytes(DecodeLongint(Indata, 5)); + t:= ((l shr 4) xor r) and $0f0f0f0f; + r:= r xor t; + l:= l xor (t shl 4); + t:= ((r shr 16) xor l) and $0000ffff; + l:= l xor t; + r:= r xor (t shl 16); + t:= ((l shr 2) xor r) and $33333333; + r:= r xor t; + l:= l xor (t shl 2); + t:= ((r shr 8) xor l) and $00ff00ff; + l:= l xor t; + r:= r xor (t shl 8); + t:= ((l shr 1) xor r) and $55555555; + r:= r xor t; + l:= l xor (t shl 1); + r:= (r shr 29) or (r shl 3); + l:= (l shr 29) or (l shl 3); + i:= 0; + while i< 32 do + begin + u:= r xor KeyData[i ]; + t:= r xor KeyData[i+1]; + t:= (t shr 4) or (t shl 28); + l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + u:= l xor KeyData[i+2]; + t:= l xor KeyData[i+3]; + t:= (t shr 4) or (t shl 28); + r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + u:= r xor KeyData[i+4]; + t:= r xor KeyData[i+5]; + t:= (t shr 4) or (t shl 28); + l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + u:= l xor KeyData[i+6]; + t:= l xor KeyData[i+7]; + t:= (t shr 4) or (t shl 28); + r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + Inc(i,8); + end; + r:= (r shr 3) or (r shl 29); + l:= (l shr 3) or (l shl 29); + t:= ((r shr 1) xor l) and $55555555; + l:= l xor t; + r:= r xor (t shl 1); + t:= ((l shr 8) xor r) and $00ff00ff; + r:= r xor t; + l:= l xor (t shl 8); + t:= ((r shr 2) xor l) and $33333333; + l:= l xor t; + r:= r xor (t shl 2); + t:= ((l shr 16) xor r) and $0000ffff; + r:= r xor t; + l:= l xor (t shl 16); + t:= ((r shr 4) xor l) and $0f0f0f0f; + l:= l xor t; + r:= r xor (t shl 4); + Result := CodeLongInt(Swapbytes(l)) + CodeLongInt(Swapbytes(r)); +end; + +function TSynaCustomDes.DecryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; +var + l, r, t, u: integer; + i: longint; +begin + r := Swapbytes(DecodeLongint(Indata, 1)); + l := Swapbytes(DecodeLongint(Indata, 5)); + t:= ((l shr 4) xor r) and $0f0f0f0f; + r:= r xor t; + l:= l xor (t shl 4); + t:= ((r shr 16) xor l) and $0000ffff; + l:= l xor t; + r:= r xor (t shl 16); + t:= ((l shr 2) xor r) and $33333333; + r:= r xor t; + l:= l xor (t shl 2); + t:= ((r shr 8) xor l) and $00ff00ff; + l:= l xor t; + r:= r xor (t shl 8); + t:= ((l shr 1) xor r) and $55555555; + r:= r xor t; + l:= l xor (t shl 1); + r:= (r shr 29) or (r shl 3); + l:= (l shr 29) or (l shl 3); + i:= 30; + while i> 0 do + begin + u:= r xor KeyData[i ]; + t:= r xor KeyData[i+1]; + t:= (t shr 4) or (t shl 28); + l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + u:= l xor KeyData[i-2]; + t:= l xor KeyData[i-1]; + t:= (t shr 4) or (t shl 28); + r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + u:= r xor KeyData[i-4]; + t:= r xor KeyData[i-3]; + t:= (t shr 4) or (t shl 28); + l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + u:= l xor KeyData[i-6]; + t:= l xor KeyData[i-5]; + t:= (t shr 4) or (t shl 28); + r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor + des_SPtrans[2,(u shr 10) and $3f] xor + des_SPtrans[4,(u shr 18) and $3f] xor + des_SPtrans[6,(u shr 26) and $3f] xor + des_SPtrans[1,(t shr 2) and $3f] xor + des_SPtrans[3,(t shr 10) and $3f] xor + des_SPtrans[5,(t shr 18) and $3f] xor + des_SPtrans[7,(t shr 26) and $3f]; + Dec(i,8); + end; + r:= (r shr 3) or (r shl 29); + l:= (l shr 3) or (l shl 29); + t:= ((r shr 1) xor l) and $55555555; + l:= l xor t; + r:= r xor (t shl 1); + t:= ((l shr 8) xor r) and $00ff00ff; + r:= r xor t; + l:= l xor (t shl 8); + t:= ((r shr 2) xor l) and $33333333; + l:= l xor t; + r:= r xor (t shl 2); + t:= ((l shr 16) xor r) and $0000ffff; + r:= r xor t; + l:= l xor (t shl 16); + t:= ((r shr 4) xor l) and $0f0f0f0f; + l:= l xor t; + r:= r xor (t shl 4); + Result := CodeLongInt(Swapbytes(l)) + CodeLongInt(Swapbytes(r)); +end; + +{==============================================================================} + +procedure TSynaDes.InitKey(Key: AnsiString); +begin + Key := PadString(Key, 8, #0); + DoInit(Key,KeyData); +end; + +function TSynaDes.EncryptECB(const InData: AnsiString): AnsiString; +begin + Result := EncryptBlock(InData,KeyData); +end; + +function TSynaDes.DecryptECB(const InData: AnsiString): AnsiString; +begin + Result := DecryptBlock(Indata,KeyData); +end; + +{==============================================================================} + +procedure TSyna3Des.InitKey(Key: AnsiString); +var + Size: integer; + n: integer; +begin + Size := length(Key); + key := PadString(key, 3 * 8, #0); + DoInit(Copy(key, 1, 8),KeyData[0]); + DoInit(Copy(key, 9, 8),KeyData[1]); + if Size > 16 then + DoInit(Copy(key, 17, 8),KeyData[2]) + else + for n := 0 to high(KeyData[0]) do + KeyData[2][n] := Keydata[0][n]; +end; + +function TSyna3Des.EncryptECB(const InData: AnsiString): AnsiString; +begin + Result := EncryptBlock(Indata,KeyData[0]); + Result := DecryptBlock(Result,KeyData[1]); + Result := EncryptBlock(Result,KeyData[2]); +end; + +function TSyna3Des.DecryptECB(const InData: AnsiString): AnsiString; +begin + Result := DecryptBlock(InData,KeyData[2]); + Result := EncryptBlock(Result,KeyData[1]); + Result := DecryptBlock(Result,KeyData[0]); +end; + +{==============================================================================} + +procedure InvMixColumn(a: PByteArray; BC: byte); +var + j: longword; +begin + for j:= 0 to (BC-1) do + PDWord(@(a^[j*4]))^:= PDWord(@U1[a^[j*4+0]])^ + xor PDWord(@U2[a^[j*4+1]])^ + xor PDWord(@U3[a^[j*4+2]])^ + xor PDWord(@U4[a^[j*4+3]])^; +end; + +{==============================================================================} + +function TSynaAes.GetSize: byte; +begin + Result := 16; +end; + +procedure TSynaAes.InitKey(Key: AnsiString); +var + Size: integer; + KC, ROUNDS, j, r, t, rconpointer: longword; + tk: array[0..MAXKC-1,0..3] of byte; + n: integer; +begin + FillChar(tk,Sizeof(tk),0); + //key must have at least 128 bits and max 256 bits + if length(key) < 16 then + key := PadString(key, 16, #0); + if length(key) > 32 then + delete(key, 33, maxint); + Size := length(Key); + Move(PAnsiChar(Key)^, tk, Size); + if Size<= 16 then + begin + KC:= 4; + Rounds:= 10; + end + else if Size<= 24 then + begin + KC:= 6; + Rounds:= 12; + end + else + begin + KC:= 8; + Rounds:= 14; + end; + numrounds:= rounds; + r:= 0; + t:= 0; + j:= 0; + while (j< KC) and (r< (rounds+1)) do + begin + while (j< KC) and (t< BC) do + begin + rk[r,t]:= PDWord(@tk[j])^; + Inc(j); + Inc(t); + end; + if t= BC then + begin + t:= 0; + Inc(r); + end; + end; + rconpointer:= 0; + while (r< (rounds+1)) do + begin + tk[0,0]:= tk[0,0] xor S[tk[KC-1,1]]; + tk[0,1]:= tk[0,1] xor S[tk[KC-1,2]]; + tk[0,2]:= tk[0,2] xor S[tk[KC-1,3]]; + tk[0,3]:= tk[0,3] xor S[tk[KC-1,0]]; + tk[0,0]:= tk[0,0] xor rcon[rconpointer]; + Inc(rconpointer); + if KC<> 8 then + begin + for j:= 1 to (KC-1) do + PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; + end + else + begin + for j:= 1 to ((KC div 2)-1) do + PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; + tk[KC div 2,0]:= tk[KC div 2,0] xor S[tk[KC div 2 - 1,0]]; + tk[KC div 2,1]:= tk[KC div 2,1] xor S[tk[KC div 2 - 1,1]]; + tk[KC div 2,2]:= tk[KC div 2,2] xor S[tk[KC div 2 - 1,2]]; + tk[KC div 2,3]:= tk[KC div 2,3] xor S[tk[KC div 2 - 1,3]]; + for j:= ((KC div 2) + 1) to (KC-1) do + PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; + end; + j:= 0; + while (j< KC) and (r< (rounds+1)) do + begin + while (j< KC) and (t< BC) do + begin + rk[r,t]:= PDWord(@tk[j])^; + Inc(j); + Inc(t); + end; + if t= BC then + begin + Inc(r); + t:= 0; + end; + end; + end; + Move(rk,drk,Sizeof(rk)); + for r:= 1 to (numrounds-1) do + InvMixColumn(@drk[r],BC); +end; + +function TSynaAes.EncryptECB(const InData: AnsiString): AnsiString; +var + r: longword; + tempb: array[0..MAXBC-1,0..3] of byte; + a: array[0..MAXBC,0..3] of byte; + p: pointer; +begin + p := @a[0,0]; + move(pointer(InData)^, p^, 16); + for r:= 0 to (numrounds-2) do + begin + PDWord(@tempb[0])^:= PDWord(@a[0])^ xor rk[r,0]; + PDWord(@tempb[1])^:= PDWord(@a[1])^ xor rk[r,1]; + PDWord(@tempb[2])^:= PDWord(@a[2])^ xor rk[r,2]; + PDWord(@tempb[3])^:= PDWord(@a[3])^ xor rk[r,3]; + PDWord(@a[0])^:= PDWord(@T1[tempb[0,0]])^ xor + PDWord(@T2[tempb[1,1]])^ xor + PDWord(@T3[tempb[2,2]])^ xor + PDWord(@T4[tempb[3,3]])^; + PDWord(@a[1])^:= PDWord(@T1[tempb[1,0]])^ xor + PDWord(@T2[tempb[2,1]])^ xor + PDWord(@T3[tempb[3,2]])^ xor + PDWord(@T4[tempb[0,3]])^; + PDWord(@a[2])^:= PDWord(@T1[tempb[2,0]])^ xor + PDWord(@T2[tempb[3,1]])^ xor + PDWord(@T3[tempb[0,2]])^ xor + PDWord(@T4[tempb[1,3]])^; + PDWord(@a[3])^:= PDWord(@T1[tempb[3,0]])^ xor + PDWord(@T2[tempb[0,1]])^ xor + PDWord(@T3[tempb[1,2]])^ xor + PDWord(@T4[tempb[2,3]])^; + end; + PDWord(@tempb[0])^:= PDWord(@a[0])^ xor rk[numrounds-1,0]; + PDWord(@tempb[1])^:= PDWord(@a[1])^ xor rk[numrounds-1,1]; + PDWord(@tempb[2])^:= PDWord(@a[2])^ xor rk[numrounds-1,2]; + PDWord(@tempb[3])^:= PDWord(@a[3])^ xor rk[numrounds-1,3]; + a[0,0]:= T1[tempb[0,0],1]; + a[0,1]:= T1[tempb[1,1],1]; + a[0,2]:= T1[tempb[2,2],1]; + a[0,3]:= T1[tempb[3,3],1]; + a[1,0]:= T1[tempb[1,0],1]; + a[1,1]:= T1[tempb[2,1],1]; + a[1,2]:= T1[tempb[3,2],1]; + a[1,3]:= T1[tempb[0,3],1]; + a[2,0]:= T1[tempb[2,0],1]; + a[2,1]:= T1[tempb[3,1],1]; + a[2,2]:= T1[tempb[0,2],1]; + a[2,3]:= T1[tempb[1,3],1]; + a[3,0]:= T1[tempb[3,0],1]; + a[3,1]:= T1[tempb[0,1],1]; + a[3,2]:= T1[tempb[1,2],1]; + a[3,3]:= T1[tempb[2,3],1]; + PDWord(@a[0])^:= PDWord(@a[0])^ xor rk[numrounds,0]; + PDWord(@a[1])^:= PDWord(@a[1])^ xor rk[numrounds,1]; + PDWord(@a[2])^:= PDWord(@a[2])^ xor rk[numrounds,2]; + PDWord(@a[3])^:= PDWord(@a[3])^ xor rk[numrounds,3]; + + Result := StringOfChar(#0, 16); + move(p^, pointer(Result)^, 16); +end; + +function TSynaAes.DecryptECB(const InData: AnsiString): AnsiString; +var + r: longword; + tempb: array[0..MAXBC-1,0..3] of byte; + a: array[0..MAXBC,0..3] of byte; + p: pointer; +begin + p := @a[0,0]; + move(pointer(InData)^, p^, 16); + for r:= NumRounds downto 2 do + begin + PDWord(@tempb[0])^:= PDWord(@a[0])^ xor drk[r,0]; + PDWord(@tempb[1])^:= PDWord(@a[1])^ xor drk[r,1]; + PDWord(@tempb[2])^:= PDWord(@a[2])^ xor drk[r,2]; + PDWord(@tempb[3])^:= PDWord(@a[3])^ xor drk[r,3]; + PDWord(@a[0])^:= PDWord(@T5[tempb[0,0]])^ xor + PDWord(@T6[tempb[3,1]])^ xor + PDWord(@T7[tempb[2,2]])^ xor + PDWord(@T8[tempb[1,3]])^; + PDWord(@a[1])^:= PDWord(@T5[tempb[1,0]])^ xor + PDWord(@T6[tempb[0,1]])^ xor + PDWord(@T7[tempb[3,2]])^ xor + PDWord(@T8[tempb[2,3]])^; + PDWord(@a[2])^:= PDWord(@T5[tempb[2,0]])^ xor + PDWord(@T6[tempb[1,1]])^ xor + PDWord(@T7[tempb[0,2]])^ xor + PDWord(@T8[tempb[3,3]])^; + PDWord(@a[3])^:= PDWord(@T5[tempb[3,0]])^ xor + PDWord(@T6[tempb[2,1]])^ xor + PDWord(@T7[tempb[1,2]])^ xor + PDWord(@T8[tempb[0,3]])^; + end; + PDWord(@tempb[0])^:= PDWord(@a[0])^ xor drk[1,0]; + PDWord(@tempb[1])^:= PDWord(@a[1])^ xor drk[1,1]; + PDWord(@tempb[2])^:= PDWord(@a[2])^ xor drk[1,2]; + PDWord(@tempb[3])^:= PDWord(@a[3])^ xor drk[1,3]; + a[0,0]:= S5[tempb[0,0]]; + a[0,1]:= S5[tempb[3,1]]; + a[0,2]:= S5[tempb[2,2]]; + a[0,3]:= S5[tempb[1,3]]; + a[1,0]:= S5[tempb[1,0]]; + a[1,1]:= S5[tempb[0,1]]; + a[1,2]:= S5[tempb[3,2]]; + a[1,3]:= S5[tempb[2,3]]; + a[2,0]:= S5[tempb[2,0]]; + a[2,1]:= S5[tempb[1,1]]; + a[2,2]:= S5[tempb[0,2]]; + a[2,3]:= S5[tempb[3,3]]; + a[3,0]:= S5[tempb[3,0]]; + a[3,1]:= S5[tempb[2,1]]; + a[3,2]:= S5[tempb[1,2]]; + a[3,3]:= S5[tempb[0,3]]; + PDWord(@a[0])^:= PDWord(@a[0])^ xor drk[0,0]; + PDWord(@a[1])^:= PDWord(@a[1])^ xor drk[0,1]; + PDWord(@a[2])^:= PDWord(@a[2])^ xor drk[0,2]; + PDWord(@a[3])^:= PDWord(@a[3])^ xor drk[0,3]; + Result := StringOfChar(#0, 16); + move(p^, pointer(Result)^, 16); +end; + +{==============================================================================} + +function TestDes: boolean; +var + des: TSynaDes; + s, t: string; +const + key = '01234567'; + data1= '01234567'; + data2= '0123456789abcdefghij'; +begin + //ECB + des := TSynaDes.Create(key); + try + s := des.EncryptECB(data1); + t := strtohex(s); + result := t = 'c50ad028c6da9800'; + s := des.DecryptECB(s); + result := result and (data1 = s); + finally + des.free; + end; + //CBC + des := TSynaDes.Create(key); + try + s := des.EncryptCBC(data2); + t := strtohex(s); + result := result and (t = 'eec50f6353115ad6dee90a22ed1b6a88a0926e35'); + des.Reset; + s := des.DecryptCBC(s); + result := result and (data2 = s); + finally + des.free; + end; + //CFB-8bit + des := TSynaDes.Create(key); + try + s := des.EncryptCFB8bit(data2); + t := strtohex(s); + result := result and (t = 'eb6aa12c2f0ff634b4dfb6da6cb2af8f9c5c1452'); + des.Reset; + s := des.DecryptCFB8bit(s); + result := result and (data2 = s); + finally + des.free; + end; + //CFB-block + des := TSynaDes.Create(key); + try + s := des.EncryptCFBblock(data2); + t := strtohex(s); + result := result and (t = 'ebdbbaa7f9286cdec28605e07f9b7f3be1053257'); + des.Reset; + s := des.DecryptCFBblock(s); + result := result and (data2 = s); + finally + des.free; + end; + //OFB + des := TSynaDes.Create(key); + try + s := des.EncryptOFB(data2); + t := strtohex(s); + result := result and (t = 'ebdbbaa7f9286cdee0b8b3798c4c34baac87dbdc'); + des.Reset; + s := des.DecryptOFB(s); + result := result and (data2 = s); + finally + des.free; + end; + //CTR + des := TSynaDes.Create(key); + try + s := des.EncryptCTR(data2); + t := strtohex(s); + result := result and (t = 'ebdbbaa7f9286cde0dd20b45f3afd9aa1b91b87e'); + des.Reset; + s := des.DecryptCTR(s); + result := result and (data2 = s); + finally + des.free; + end; +end; + +function Test3Des: boolean; +var + des: TSyna3Des; + s, t: string; +const + key = '0123456789abcdefghijklmn'; + data1= '01234567'; + data2= '0123456789abcdefghij'; +begin + //ECB + des := TSyna3Des.Create(key); + try + s := des.EncryptECB(data1); + t := strtohex(s); + result := t = 'e0dee91008dc460c'; + s := des.DecryptECB(s); + result := result and (data1 = s); + finally + des.free; + end; + //CBC + des := TSyna3Des.Create(key); + try + s := des.EncryptCBC(data2); + t := strtohex(s); + result := result and (t = 'ee844a2a4f49c01b91a1599b8eba29128c1ad87a'); + des.Reset; + s := des.DecryptCBC(s); + result := result and (data2 = s); + finally + des.free; + end; + //CFB-8bit + des := TSyna3Des.Create(key); + try + s := des.EncryptCFB8bit(data2); + t := strtohex(s); + result := result and (t = '935bbf5210c32cfa1faf61f91e8dc02dfa0ff1e8'); + des.Reset; + s := des.DecryptCFB8bit(s); + result := result and (data2 = s); + finally + des.free; + end; + //CFB-block + des := TSyna3Des.Create(key); + try + s := des.EncryptCFBblock(data2); + t := strtohex(s); + result := result and (t = '93754e3d54828fbf4bd81f1739419e8d2cfe1671'); + des.Reset; + s := des.DecryptCFBblock(s); + result := result and (data2 = s); + finally + des.free; + end; + //OFB + des := TSyna3Des.Create(key); + try + s := des.EncryptOFB(data2); + t := strtohex(s); + result := result and (t = '93754e3d54828fbf04ef0a5efc926ebdf2d95f20'); + des.Reset; + s := des.DecryptOFB(s); + result := result and (data2 = s); + finally + des.free; + end; + //CTR + des := TSyna3Des.Create(key); + try + s := des.EncryptCTR(data2); + t := strtohex(s); + result := result and (t = '93754e3d54828fbf1c51a121d2c93f989e70b3ad'); + des.Reset; + s := des.DecryptCTR(s); + result := result and (data2 = s); + finally + des.free; + end; +end; + +function TestAes: boolean; +var + aes: TSynaAes; + s, t: string; +const + key1 = #$00#$01#$02#$03#$05#$06#$07#$08#$0A#$0B#$0C#$0D#$0F#$10#$11#$12; + data1= #$50#$68#$12#$A4#$5F#$08#$C8#$89#$B9#$7F#$59#$80#$03#$8B#$83#$59; + key2 = #$A0#$A1#$A2#$A3#$A5#$A6#$A7#$A8#$AA#$AB#$AC#$AD#$AF#$B0#$B1#$B2#$B4#$B5#$B6#$B7#$B9#$BA#$BB#$BC; + data2= #$4F#$1C#$76#$9D#$1E#$5B#$05#$52#$C7#$EC#$A8#$4D#$EA#$26#$A5#$49; + key3 = #$00#$01#$02#$03#$05#$06#$07#$08#$0A#$0B#$0C#$0D#$0F#$10#$11#$12#$14#$15#$16#$17#$19#$1A#$1B#$1C#$1E#$1F#$20#$21#$23#$24#$25#$26; + data3= #$5E#$25#$CA#$78#$F0#$DE#$55#$80#$25#$24#$D3#$8D#$A3#$FE#$44#$56; +begin + //ECB + aes := TSynaAes.Create(key1); + try + t := aes.EncryptECB(data1); + result := t = #$D8#$F5#$32#$53#$82#$89#$EF#$7D#$06#$B5#$06#$A4#$FD#$5B#$E9#$C9; + s := aes.DecryptECB(t); + result := result and (data1 = s); + finally + aes.free; + end; + aes := TSynaAes.Create(key2); + try + t := aes.EncryptECB(data2); + result := result and (t = #$F3#$84#$72#$10#$D5#$39#$1E#$23#$60#$60#$8E#$5A#$CB#$56#$05#$81); + s := aes.DecryptECB(t); + result := result and (data2 = s); + finally + aes.free; + end; + aes := TSynaAes.Create(key3); + try + t := aes.EncryptECB(data3); + result := result and (t = #$E8#$B7#$2B#$4E#$8B#$E2#$43#$43#$8C#$9F#$FF#$1F#$0E#$20#$58#$72); + s := aes.DecryptECB(t); + result := result and (data3 = s); + finally + aes.free; + end; +end; + +{==============================================================================} + +end. diff --git a/3rd/synapse/source/synadbg.pas b/3rd/synapse/source/synadbg.pas index 6f60f4cc9..c587c3adf 100644 --- a/3rd/synapse/source/synadbg.pas +++ b/3rd/synapse/source/synadbg.pas @@ -1,156 +1,156 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.002 | -|==============================================================================| -| Content: Socket debug tools | -|==============================================================================| -| Copyright (c)2008-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2008-2011. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Socket debug tools) - -Routines for help with debugging of events on the Sockets. -} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synadbg; - -interface - -uses - blcksock, synsock, synautil, classes, sysutils, synafpc; - -type - TSynaDebug = class(TObject) - class procedure HookStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); - class procedure HookMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer); - end; - -procedure AppendToLog(const value: Ansistring); - -var - LogFile: string; - -implementation - -procedure AppendToLog(const value: Ansistring); -var - st: TFileStream; - s: string; - h, m, ss, ms: word; - dt: Tdatetime; -begin - if fileexists(LogFile) then - st := TFileStream.Create(LogFile, fmOpenReadWrite or fmShareDenyWrite) - else - st := TFileStream.Create(LogFile, fmCreate or fmShareDenyWrite); - try - st.Position := st.Size; - dt := now; - decodetime(dt, h, m, ss, ms); - s := formatdatetime('yyyymmdd-hhnnss', dt) + format('.%.3d', [ms]) + ' ' + value; - WriteStrToStream(st, s); - finally - st.free; - end; -end; - -class procedure TSynaDebug.HookStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); -var - s: string; -begin - case Reason of - HR_ResolvingBegin: - s := 'HR_ResolvingBegin'; - HR_ResolvingEnd: - s := 'HR_ResolvingEnd'; - HR_SocketCreate: - s := 'HR_SocketCreate'; - HR_SocketClose: - s := 'HR_SocketClose'; - HR_Bind: - s := 'HR_Bind'; - HR_Connect: - s := 'HR_Connect'; - HR_CanRead: - s := 'HR_CanRead'; - HR_CanWrite: - s := 'HR_CanWrite'; - HR_Listen: - s := 'HR_Listen'; - HR_Accept: - s := 'HR_Accept'; - HR_ReadCount: - s := 'HR_ReadCount'; - HR_WriteCount: - s := 'HR_WriteCount'; - HR_Wait: - s := 'HR_Wait'; - HR_Error: - s := 'HR_Error'; - else - s := '-unknown-'; - end; - s := inttohex(PtrInt(Sender), 8) + s + ': ' + value + CRLF; - AppendToLog(s); -end; - -class procedure TSynaDebug.HookMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer); -var - s, d: Ansistring; -begin - setlength(s, len); - move(Buffer^, pointer(s)^, len); - if writing then - d := '-> ' - else - d := '<- '; - s :=inttohex(PtrInt(Sender), 8) + d + s + CRLF; - AppendToLog(s); -end; - -initialization -begin - Logfile := changefileext(paramstr(0), '.slog'); -end; - -end. +{==============================================================================| +| Project : Ararat Synapse | 001.001.002 | +|==============================================================================| +| Content: Socket debug tools | +|==============================================================================| +| Copyright (c)2008-2011, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2008-2011. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(Socket debug tools) + +Routines for help with debugging of events on the Sockets. +} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} +{$ENDIF} + +unit synadbg; + +interface + +uses + blcksock, synsock, synautil, classes, sysutils, synafpc; + +type + TSynaDebug = class(TObject) + class procedure HookStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); + class procedure HookMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer); + end; + +procedure AppendToLog(const value: Ansistring); + +var + LogFile: string; + +implementation + +procedure AppendToLog(const value: Ansistring); +var + st: TFileStream; + s: string; + h, m, ss, ms: word; + dt: Tdatetime; +begin + if fileexists(LogFile) then + st := TFileStream.Create(LogFile, fmOpenReadWrite or fmShareDenyWrite) + else + st := TFileStream.Create(LogFile, fmCreate or fmShareDenyWrite); + try + st.Position := st.Size; + dt := now; + decodetime(dt, h, m, ss, ms); + s := formatdatetime('yyyymmdd-hhnnss', dt) + format('.%.3d', [ms]) + ' ' + value; + WriteStrToStream(st, s); + finally + st.free; + end; +end; + +class procedure TSynaDebug.HookStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); +var + s: string; +begin + case Reason of + HR_ResolvingBegin: + s := 'HR_ResolvingBegin'; + HR_ResolvingEnd: + s := 'HR_ResolvingEnd'; + HR_SocketCreate: + s := 'HR_SocketCreate'; + HR_SocketClose: + s := 'HR_SocketClose'; + HR_Bind: + s := 'HR_Bind'; + HR_Connect: + s := 'HR_Connect'; + HR_CanRead: + s := 'HR_CanRead'; + HR_CanWrite: + s := 'HR_CanWrite'; + HR_Listen: + s := 'HR_Listen'; + HR_Accept: + s := 'HR_Accept'; + HR_ReadCount: + s := 'HR_ReadCount'; + HR_WriteCount: + s := 'HR_WriteCount'; + HR_Wait: + s := 'HR_Wait'; + HR_Error: + s := 'HR_Error'; + else + s := '-unknown-'; + end; + s := inttohex(PtrInt(Sender), 8) + s + ': ' + value + CRLF; + AppendToLog(s); +end; + +class procedure TSynaDebug.HookMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer); +var + s, d: Ansistring; +begin + setlength(s, len); + move(Buffer^, pointer(s)^, len); + if writing then + d := '-> ' + else + d := '<- '; + s :=inttohex(PtrInt(Sender), 8) + d + s + CRLF; + AppendToLog(s); +end; + +initialization +begin + Logfile := changefileext(paramstr(0), '.slog'); +end; + +end. diff --git a/3rd/synapse/source/synafpc.pas b/3rd/synapse/source/synafpc.pas index 63b5eb23c..b63335d6b 100644 --- a/3rd/synapse/source/synafpc.pas +++ b/3rd/synapse/source/synafpc.pas @@ -1,148 +1,148 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.003.001 | -|==============================================================================| -| Content: Utils for FreePascal compatibility | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -unit synafpc; - -interface - -uses -{$IFDEF FPC} - dynlibs, sysutils; -{$ELSE} - {$IFDEF MSWINDOWS} - Windows; - {$ELSE} - SysUtils; - {$ENDIF} -{$ENDIF} - -{$IFDEF FPC} -type - TLibHandle = dynlibs.TLibHandle; - -function LoadLibrary(ModuleName: PChar): TLibHandle; -function FreeLibrary(Module: TLibHandle): LongBool; -function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; -function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; -{$ELSE} //not FPC -type - {$IFDEF CIL} - TLibHandle = Integer; - PtrInt = Integer; - {$ELSE} - TLibHandle = HModule; - {$IFDEF WIN64} - PtrInt = NativeInt; - {$ELSE} - PtrInt = Integer; - {$ENDIF} - {$ENDIF} - {$IFDEF VER100} - LongWord = DWord; - {$ENDIF} -{$ENDIF} - -procedure Sleep(milliseconds: Cardinal); - - -implementation - -{==============================================================================} -{$IFDEF FPC} -function LoadLibrary(ModuleName: PChar): TLibHandle; -begin - Result := dynlibs.LoadLibrary(Modulename); -end; - -function FreeLibrary(Module: TLibHandle): LongBool; -begin - Result := dynlibs.UnloadLibrary(Module); -end; - -function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; -begin -{$IFDEF OS2GCC} - Result := dynlibs.GetProcedureAddress(Module, '_' + Proc); -{$ELSE OS2GCC} - Result := dynlibs.GetProcedureAddress(Module, Proc); -{$ENDIF OS2GCC} -end; - -function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; -begin - Result := 0; -end; - -{$ELSE} -{$ENDIF} - -procedure Sleep(milliseconds: Cardinal); -begin -{$IFDEF MSWINDOWS} - {$IFDEF FPC} - sysutils.sleep(milliseconds); - {$ELSE} - windows.sleep(milliseconds); - {$ENDIF} -{$ELSE} - sysutils.sleep(milliseconds); -{$ENDIF} - -end; - -end. +{==============================================================================| +| Project : Ararat Synapse | 001.003.001 | +|==============================================================================| +| Content: Utils for FreePascal compatibility | +|==============================================================================| +| Copyright (c)1999-2013, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2003-2013. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| Tomas Hajny (OS2 support) | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@exclude} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$H+} +//old Delphi does not have MSWINDOWS define. +{$IFDEF WIN32} + {$IFNDEF MSWINDOWS} + {$DEFINE MSWINDOWS} + {$ENDIF} +{$ENDIF} + +unit synafpc; + +interface + +uses +{$IFDEF FPC} + dynlibs, sysutils; +{$ELSE} + {$IFDEF MSWINDOWS} + Windows; + {$ELSE} + SysUtils; + {$ENDIF} +{$ENDIF} + +{$IFDEF FPC} +type + TLibHandle = dynlibs.TLibHandle; + +function LoadLibrary(ModuleName: PChar): TLibHandle; +function FreeLibrary(Module: TLibHandle): LongBool; +function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; +function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; +{$ELSE} //not FPC +type + {$IFDEF CIL} + TLibHandle = Integer; + PtrInt = Integer; + {$ELSE} + TLibHandle = HModule; + {$IFDEF WIN64} + PtrInt = NativeInt; + {$ELSE} + PtrInt = Integer; + {$ENDIF} + {$ENDIF} + {$IFDEF VER100} + LongWord = DWord; + {$ENDIF} +{$ENDIF} + +procedure Sleep(milliseconds: Cardinal); + + +implementation + +{==============================================================================} +{$IFDEF FPC} +function LoadLibrary(ModuleName: PChar): TLibHandle; +begin + Result := dynlibs.LoadLibrary(Modulename); +end; + +function FreeLibrary(Module: TLibHandle): LongBool; +begin + Result := dynlibs.UnloadLibrary(Module); +end; + +function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; +begin +{$IFDEF OS2GCC} + Result := dynlibs.GetProcedureAddress(Module, '_' + Proc); +{$ELSE OS2GCC} + Result := dynlibs.GetProcedureAddress(Module, Proc); +{$ENDIF OS2GCC} +end; + +function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; +begin + Result := 0; +end; + +{$ELSE} +{$ENDIF} + +procedure Sleep(milliseconds: Cardinal); +begin +{$IFDEF MSWINDOWS} + {$IFDEF FPC} + sysutils.sleep(milliseconds); + {$ELSE} + windows.sleep(milliseconds); + {$ENDIF} +{$ELSE} + sysutils.sleep(milliseconds); +{$ENDIF} + +end; + +end. diff --git a/3rd/synapse/source/synaicnv.pas b/3rd/synapse/source/synaicnv.pas index 8a51db5b2..cbe0bfcc0 100644 --- a/3rd/synapse/source/synaicnv.pas +++ b/3rd/synapse/source/synaicnv.pas @@ -1,368 +1,368 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.002 | -|==============================================================================| -| Content: ICONV support for Win32, OS/2, Linux and .NET | -|==============================================================================| -| Copyright (c)2004-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2004-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{:@abstract(LibIconv support) - -This unit is Pascal interface to LibIconv library for charset translations. -LibIconv is loaded dynamicly on-demand. If this library is not found in system, -requested LibIconv function just return errorcode. -} -unit synaicnv; - -interface - -uses -{$IFDEF CIL} - System.Runtime.InteropServices, - System.Text, -{$ENDIF} - synafpc, -{$IFNDEF MSWINDOWS} - {$IFNDEF FPC} - Libc, - {$ENDIF} - SysUtils; -{$ELSE} - Windows; -{$ENDIF} - - -const - {$IFNDEF MSWINDOWS} - {$IFDEF OS2} - DLLIconvName = 'iconv.dll'; - {$ELSE OS2} - DLLIconvName = 'libiconv.so'; - {$ENDIF OS2} - {$ELSE} - DLLIconvName = 'iconv.dll'; - {$ENDIF} - -type - size_t = Cardinal; -{$IFDEF CIL} - iconv_t = IntPtr; -{$ELSE} - iconv_t = Pointer; -{$ENDIF} - argptr = iconv_t; - -var - iconvLibHandle: TLibHandle = 0; - -function SynaIconvOpen(const tocode, fromcode: Ansistring): iconv_t; -function SynaIconvOpenTranslit(const tocode, fromcode: Ansistring): iconv_t; -function SynaIconvOpenIgnore(const tocode, fromcode: Ansistring): iconv_t; -function SynaIconv(cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer; -function SynaIconvClose(var cd: iconv_t): integer; -function SynaIconvCtl(cd: iconv_t; request: integer; argument: argptr): integer; - -function IsIconvloaded: Boolean; -function InitIconvInterface: Boolean; -function DestroyIconvInterface: Boolean; - -const - ICONV_TRIVIALP = 0; // int *argument - ICONV_GET_TRANSLITERATE = 1; // int *argument - ICONV_SET_TRANSLITERATE = 2; // const int *argument - ICONV_GET_DISCARD_ILSEQ = 3; // int *argument - ICONV_SET_DISCARD_ILSEQ = 4; // const int *argument - - -implementation - -uses SyncObjs; - -{$IFDEF CIL} - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconv_open')] - function _iconv_open(tocode: string; fromcode: string): iconv_t; external; - - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconv')] - function _iconv(cd: iconv_t; var inbuf: IntPtr; var inbytesleft: size_t; - var outbuf: IntPtr; var outbytesleft: size_t): size_t; external; - - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconv_close')] - function _iconv_close(cd: iconv_t): integer; external; - - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconvctl')] - function _iconvctl(cd: iconv_t; request: integer; argument: argptr): integer; external; - -{$ELSE} -type - Ticonv_open = function(tocode: pAnsichar; fromcode: pAnsichar): iconv_t; cdecl; - Ticonv = function(cd: iconv_t; var inbuf: pointer; var inbytesleft: size_t; - var outbuf: pointer; var outbytesleft: size_t): size_t; cdecl; - Ticonv_close = function(cd: iconv_t): integer; cdecl; - Ticonvctl = function(cd: iconv_t; request: integer; argument: argptr): integer; cdecl; -var - _iconv_open: Ticonv_open = nil; - _iconv: Ticonv = nil; - _iconv_close: Ticonv_close = nil; - _iconvctl: Ticonvctl = nil; -{$ENDIF} - - -var - IconvCS: TCriticalSection; - Iconvloaded: boolean = false; - -function SynaIconvOpen (const tocode, fromcode: Ansistring): iconv_t; -begin -{$IFDEF CIL} - try - Result := _iconv_open(tocode, fromcode); - except - on Exception do - Result := iconv_t(-1); - end; -{$ELSE} - if InitIconvInterface and Assigned(_iconv_open) then - Result := _iconv_open(PAnsiChar(tocode), PAnsiChar(fromcode)) - else - Result := iconv_t(-1); -{$ENDIF} -end; - -function SynaIconvOpenTranslit (const tocode, fromcode: Ansistring): iconv_t; -begin - Result := SynaIconvOpen(tocode + '//IGNORE//TRANSLIT', fromcode); -end; - -function SynaIconvOpenIgnore (const tocode, fromcode: Ansistring): iconv_t; -begin - Result := SynaIconvOpen(tocode + '//IGNORE', fromcode); -end; - -function SynaIconv (cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer; -var -{$IFDEF CIL} - ib, ob: IntPtr; - ibsave, obsave: IntPtr; - l: integer; -{$ELSE} - ib, ob: Pointer; -{$ENDIF} - ix, ox: size_t; -begin -{$IFDEF CIL} - l := Length(inbuf) * 4; - ibsave := IntPtr.Zero; - obsave := IntPtr.Zero; - try - ibsave := Marshal.StringToHGlobalAnsi(inbuf); - obsave := Marshal.AllocHGlobal(l); - ib := ibsave; - ob := obsave; - ix := Length(inbuf); - ox := l; - _iconv(cd, ib, ix, ob, ox); - Outbuf := Marshal.PtrToStringAnsi(obsave, l); - setlength(Outbuf, l - ox); - Result := Length(inbuf) - ix; - finally - Marshal.FreeCoTaskMem(ibsave); - Marshal.FreeHGlobal(obsave); - end; -{$ELSE} - if InitIconvInterface and Assigned(_iconv) then - begin - setlength(Outbuf, Length(inbuf) * 4); - ib := Pointer(inbuf); - ob := Pointer(Outbuf); - ix := Length(inbuf); - ox := Length(Outbuf); - _iconv(cd, ib, ix, ob, ox); - setlength(Outbuf, cardinal(Length(Outbuf)) - ox); - Result := Cardinal(Length(inbuf)) - ix; - end - else - begin - Outbuf := ''; - Result := 0; - end; -{$ENDIF} -end; - -function SynaIconvClose(var cd: iconv_t): integer; -begin - if cd = iconv_t(-1) then - begin - Result := 0; - Exit; - end; -{$IFDEF CIL} - try; - Result := _iconv_close(cd) - except - on Exception do - Result := -1; - end; - cd := iconv_t(-1); -{$ELSE} - if InitIconvInterface and Assigned(_iconv_close) then - Result := _iconv_close(cd) - else - Result := -1; - cd := iconv_t(-1); -{$ENDIF} -end; - -function SynaIconvCtl (cd: iconv_t; request: integer; argument: argptr): integer; -begin -{$IFDEF CIL} - Result := _iconvctl(cd, request, argument) -{$ELSE} - if InitIconvInterface and Assigned(_iconvctl) then - Result := _iconvctl(cd, request, argument) - else - Result := 0; -{$ENDIF} -end; - -function InitIconvInterface: Boolean; -begin - IconvCS.Enter; - try - if not IsIconvloaded then - begin -{$IFDEF CIL} - IconvLibHandle := 1; -{$ELSE} - IconvLibHandle := LoadLibrary(PChar(DLLIconvName)); -{$ENDIF} - if (IconvLibHandle <> 0) then - begin -{$IFNDEF CIL} - _iconv_open := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_open'))); - _iconv := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv'))); - _iconv_close := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_close'))); - _iconvctl := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconvctl'))); -{$ENDIF} - Result := True; - Iconvloaded := True; - end - else - begin - //load failed! - if IconvLibHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(IconvLibHandle); -{$ENDIF} - IconvLibHandle := 0; - end; - Result := False; - end; - end - else - //loaded before... - Result := true; - finally - IconvCS.Leave; - end; -end; - -function DestroyIconvInterface: Boolean; -begin - IconvCS.Enter; - try - Iconvloaded := false; - if IconvLibHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(IconvLibHandle); -{$ENDIF} - IconvLibHandle := 0; - end; -{$IFNDEF CIL} - _iconv_open := nil; - _iconv := nil; - _iconv_close := nil; - _iconvctl := nil; -{$ENDIF} - finally - IconvCS.Leave; - end; - Result := True; -end; - -function IsIconvloaded: Boolean; -begin - Result := IconvLoaded; -end; - - initialization -begin - IconvCS:= TCriticalSection.Create; -end; - -finalization -begin -{$IFNDEF CIL} - DestroyIconvInterface; -{$ENDIF} - IconvCS.Free; -end; - -end. +{==============================================================================| +| Project : Ararat Synapse | 001.001.002 | +|==============================================================================| +| Content: ICONV support for Win32, OS/2, Linux and .NET | +|==============================================================================| +| Copyright (c)2004-2013, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2004-2013. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| Tomas Hajny (OS2 support) | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$H+} +//old Delphi does not have MSWINDOWS define. +{$IFDEF WIN32} + {$IFNDEF MSWINDOWS} + {$DEFINE MSWINDOWS} + {$ENDIF} +{$ENDIF} + +{:@abstract(LibIconv support) + +This unit is Pascal interface to LibIconv library for charset translations. +LibIconv is loaded dynamicly on-demand. If this library is not found in system, +requested LibIconv function just return errorcode. +} +unit synaicnv; + +interface + +uses +{$IFDEF CIL} + System.Runtime.InteropServices, + System.Text, +{$ENDIF} + synafpc, +{$IFNDEF MSWINDOWS} + {$IFNDEF FPC} + Libc, + {$ENDIF} + SysUtils; +{$ELSE} + Windows; +{$ENDIF} + + +const + {$IFNDEF MSWINDOWS} + {$IFDEF OS2} + DLLIconvName = 'iconv.dll'; + {$ELSE OS2} + DLLIconvName = 'libiconv.so'; + {$ENDIF OS2} + {$ELSE} + DLLIconvName = 'iconv.dll'; + {$ENDIF} + +type + size_t = Cardinal; +{$IFDEF CIL} + iconv_t = IntPtr; +{$ELSE} + iconv_t = Pointer; +{$ENDIF} + argptr = iconv_t; + +var + iconvLibHandle: TLibHandle = 0; + +function SynaIconvOpen(const tocode, fromcode: Ansistring): iconv_t; +function SynaIconvOpenTranslit(const tocode, fromcode: Ansistring): iconv_t; +function SynaIconvOpenIgnore(const tocode, fromcode: Ansistring): iconv_t; +function SynaIconv(cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer; +function SynaIconvClose(var cd: iconv_t): integer; +function SynaIconvCtl(cd: iconv_t; request: integer; argument: argptr): integer; + +function IsIconvloaded: Boolean; +function InitIconvInterface: Boolean; +function DestroyIconvInterface: Boolean; + +const + ICONV_TRIVIALP = 0; // int *argument + ICONV_GET_TRANSLITERATE = 1; // int *argument + ICONV_SET_TRANSLITERATE = 2; // const int *argument + ICONV_GET_DISCARD_ILSEQ = 3; // int *argument + ICONV_SET_DISCARD_ILSEQ = 4; // const int *argument + + +implementation + +uses SyncObjs; + +{$IFDEF CIL} + [DllImport(DLLIconvName, CharSet = CharSet.Ansi, + SetLastError = False, CallingConvention= CallingConvention.cdecl, + EntryPoint = 'libiconv_open')] + function _iconv_open(tocode: string; fromcode: string): iconv_t; external; + + [DllImport(DLLIconvName, CharSet = CharSet.Ansi, + SetLastError = False, CallingConvention= CallingConvention.cdecl, + EntryPoint = 'libiconv')] + function _iconv(cd: iconv_t; var inbuf: IntPtr; var inbytesleft: size_t; + var outbuf: IntPtr; var outbytesleft: size_t): size_t; external; + + [DllImport(DLLIconvName, CharSet = CharSet.Ansi, + SetLastError = False, CallingConvention= CallingConvention.cdecl, + EntryPoint = 'libiconv_close')] + function _iconv_close(cd: iconv_t): integer; external; + + [DllImport(DLLIconvName, CharSet = CharSet.Ansi, + SetLastError = False, CallingConvention= CallingConvention.cdecl, + EntryPoint = 'libiconvctl')] + function _iconvctl(cd: iconv_t; request: integer; argument: argptr): integer; external; + +{$ELSE} +type + Ticonv_open = function(tocode: pAnsichar; fromcode: pAnsichar): iconv_t; cdecl; + Ticonv = function(cd: iconv_t; var inbuf: pointer; var inbytesleft: size_t; + var outbuf: pointer; var outbytesleft: size_t): size_t; cdecl; + Ticonv_close = function(cd: iconv_t): integer; cdecl; + Ticonvctl = function(cd: iconv_t; request: integer; argument: argptr): integer; cdecl; +var + _iconv_open: Ticonv_open = nil; + _iconv: Ticonv = nil; + _iconv_close: Ticonv_close = nil; + _iconvctl: Ticonvctl = nil; +{$ENDIF} + + +var + IconvCS: TCriticalSection; + Iconvloaded: boolean = false; + +function SynaIconvOpen (const tocode, fromcode: Ansistring): iconv_t; +begin +{$IFDEF CIL} + try + Result := _iconv_open(tocode, fromcode); + except + on Exception do + Result := iconv_t(-1); + end; +{$ELSE} + if InitIconvInterface and Assigned(_iconv_open) then + Result := _iconv_open(PAnsiChar(tocode), PAnsiChar(fromcode)) + else + Result := iconv_t(-1); +{$ENDIF} +end; + +function SynaIconvOpenTranslit (const tocode, fromcode: Ansistring): iconv_t; +begin + Result := SynaIconvOpen(tocode + '//IGNORE//TRANSLIT', fromcode); +end; + +function SynaIconvOpenIgnore (const tocode, fromcode: Ansistring): iconv_t; +begin + Result := SynaIconvOpen(tocode + '//IGNORE', fromcode); +end; + +function SynaIconv (cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer; +var +{$IFDEF CIL} + ib, ob: IntPtr; + ibsave, obsave: IntPtr; + l: integer; +{$ELSE} + ib, ob: Pointer; +{$ENDIF} + ix, ox: size_t; +begin +{$IFDEF CIL} + l := Length(inbuf) * 4; + ibsave := IntPtr.Zero; + obsave := IntPtr.Zero; + try + ibsave := Marshal.StringToHGlobalAnsi(inbuf); + obsave := Marshal.AllocHGlobal(l); + ib := ibsave; + ob := obsave; + ix := Length(inbuf); + ox := l; + _iconv(cd, ib, ix, ob, ox); + Outbuf := Marshal.PtrToStringAnsi(obsave, l); + setlength(Outbuf, l - ox); + Result := Length(inbuf) - ix; + finally + Marshal.FreeCoTaskMem(ibsave); + Marshal.FreeHGlobal(obsave); + end; +{$ELSE} + if InitIconvInterface and Assigned(_iconv) then + begin + setlength(Outbuf, Length(inbuf) * 4); + ib := Pointer(inbuf); + ob := Pointer(Outbuf); + ix := Length(inbuf); + ox := Length(Outbuf); + _iconv(cd, ib, ix, ob, ox); + setlength(Outbuf, cardinal(Length(Outbuf)) - ox); + Result := Cardinal(Length(inbuf)) - ix; + end + else + begin + Outbuf := ''; + Result := 0; + end; +{$ENDIF} +end; + +function SynaIconvClose(var cd: iconv_t): integer; +begin + if cd = iconv_t(-1) then + begin + Result := 0; + Exit; + end; +{$IFDEF CIL} + try; + Result := _iconv_close(cd) + except + on Exception do + Result := -1; + end; + cd := iconv_t(-1); +{$ELSE} + if InitIconvInterface and Assigned(_iconv_close) then + Result := _iconv_close(cd) + else + Result := -1; + cd := iconv_t(-1); +{$ENDIF} +end; + +function SynaIconvCtl (cd: iconv_t; request: integer; argument: argptr): integer; +begin +{$IFDEF CIL} + Result := _iconvctl(cd, request, argument) +{$ELSE} + if InitIconvInterface and Assigned(_iconvctl) then + Result := _iconvctl(cd, request, argument) + else + Result := 0; +{$ENDIF} +end; + +function InitIconvInterface: Boolean; +begin + IconvCS.Enter; + try + if not IsIconvloaded then + begin +{$IFDEF CIL} + IconvLibHandle := 1; +{$ELSE} + IconvLibHandle := LoadLibrary(PChar(DLLIconvName)); +{$ENDIF} + if (IconvLibHandle <> 0) then + begin +{$IFNDEF CIL} + _iconv_open := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_open'))); + _iconv := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv'))); + _iconv_close := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_close'))); + _iconvctl := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconvctl'))); +{$ENDIF} + Result := True; + Iconvloaded := True; + end + else + begin + //load failed! + if IconvLibHandle <> 0 then + begin +{$IFNDEF CIL} + FreeLibrary(IconvLibHandle); +{$ENDIF} + IconvLibHandle := 0; + end; + Result := False; + end; + end + else + //loaded before... + Result := true; + finally + IconvCS.Leave; + end; +end; + +function DestroyIconvInterface: Boolean; +begin + IconvCS.Enter; + try + Iconvloaded := false; + if IconvLibHandle <> 0 then + begin +{$IFNDEF CIL} + FreeLibrary(IconvLibHandle); +{$ENDIF} + IconvLibHandle := 0; + end; +{$IFNDEF CIL} + _iconv_open := nil; + _iconv := nil; + _iconv_close := nil; + _iconvctl := nil; +{$ENDIF} + finally + IconvCS.Leave; + end; + Result := True; +end; + +function IsIconvloaded: Boolean; +begin + Result := IconvLoaded; +end; + + initialization +begin + IconvCS:= TCriticalSection.Create; +end; + +finalization +begin +{$IFNDEF CIL} + DestroyIconvInterface; +{$ENDIF} + IconvCS.Free; +end; + +end. diff --git a/3rd/synapse/source/synaip.pas b/3rd/synapse/source/synaip.pas index 82a7da47e..f13372321 100644 --- a/3rd/synapse/source/synaip.pas +++ b/3rd/synapse/source/synaip.pas @@ -1,422 +1,422 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.002.001 | -|==============================================================================| -| Content: IP address support procedures and functions | -|==============================================================================| -| Copyright (c)2006-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 2006-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(IP adress support procedures and functions)} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit synaip; - -interface - -uses - SysUtils, SynaUtil; - -type -{:binary form of IPv6 adress (for string conversion routines)} - TIp6Bytes = array [0..15] of Byte; -{:binary form of IPv6 adress (for string conversion routines)} - TIp6Words = array [0..7] of Word; - -{:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!} -function IsIP(const Value: string): Boolean; - -{:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!} -function IsIP6(const Value: string): Boolean; - -{:Returns a string with the "Host" ip address converted to binary form.} -function IPToID(Host: string): Ansistring; - -{:Convert IPv6 address from their string form to binary byte array.} -function StrToIp6(value: string): TIp6Bytes; - -{:Convert IPv6 address from binary byte array to string form.} -function Ip6ToStr(value: TIp6Bytes): string; - -{:Convert IPv4 address from their string form to binary.} -function StrToIp(value: string): integer; - -{:Convert IPv4 address from binary to string form.} -function IpToStr(value: integer): string; - -{:Convert IPv4 address to reverse form.} -function ReverseIP(Value: AnsiString): AnsiString; - -{:Convert IPv6 address to reverse form.} -function ReverseIP6(Value: AnsiString): AnsiString; - -{:Expand short form of IPv6 address to long form.} -function ExpandIP6(Value: AnsiString): AnsiString; - - -implementation - -{==============================================================================} - -function IsIP(const Value: string): Boolean; -var - TempIP: string; - function ByteIsOk(const Value: string): Boolean; - var - x, n: integer; - begin - x := StrToIntDef(Value, -1); - Result := (x >= 0) and (x < 256); - // X may be in correct range, but value still may not be correct value! - // i.e. "$80" - if Result then - for n := 1 to length(Value) do - if not (AnsiChar(Value[n]) in ['0'..'9']) then - begin - Result := False; - Break; - end; - end; -begin - TempIP := Value; - Result := False; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if ByteIsOk(TempIP) then - Result := True; -end; - -{==============================================================================} - -function IsIP6(const Value: string): Boolean; -var - TempIP: string; - s,t: string; - x: integer; - partcount: integer; - zerocount: integer; - First: Boolean; -begin - TempIP := Value; - Result := False; - if Value = '::' then - begin - Result := True; - Exit; - end; - partcount := 0; - zerocount := 0; - First := True; - while tempIP <> '' do - begin - s := fetch(TempIP, ':'); - if not(First) and (s = '') then - Inc(zerocount); - First := False; - if zerocount > 1 then - break; - Inc(partCount); - if s = '' then - Continue; - if partCount > 8 then - break; - if tempIP = '' then - begin - t := SeparateRight(s, '%'); - s := SeparateLeft(s, '%'); - x := StrToIntDef('$' + t, -1); - if (x < 0) or (x > $ffff) then - break; - end; - x := StrToIntDef('$' + s, -1); - if (x < 0) or (x > $ffff) then - break; - if tempIP = '' then - if not((PartCount = 1) and (ZeroCount = 0)) then - Result := True; - end; -end; - -{==============================================================================} -function IPToID(Host: string): Ansistring; -var - s: string; - i, x: Integer; -begin - Result := ''; - for x := 0 to 3 do - begin - s := Fetch(Host, '.'); - i := StrToIntDef(s, 0); - Result := Result + AnsiChar(i); - end; -end; - -{==============================================================================} - -function StrToIp(value: string): integer; -var - s: string; - i, x: Integer; -begin - Result := 0; - for x := 0 to 3 do - begin - s := Fetch(value, '.'); - i := StrToIntDef(s, 0); - Result := (256 * Result) + i; - end; -end; - -{==============================================================================} - -function IpToStr(value: integer): string; -var - x1, x2: word; - y1, y2: byte; -begin - Result := ''; - x1 := value shr 16; - x2 := value and $FFFF; - y1 := x1 div $100; - y2 := x1 mod $100; - Result := inttostr(y1) + '.' + inttostr(y2) + '.'; - y1 := x2 div $100; - y2 := x2 mod $100; - Result := Result + inttostr(y1) + '.' + inttostr(y2); -end; - -{==============================================================================} - -function ExpandIP6(Value: AnsiString): AnsiString; -var - n: integer; - s: ansistring; - x: integer; -begin - Result := ''; - if value = '' then - exit; - x := countofchar(value, ':'); - if x > 7 then - exit; - if value[1] = ':' then - value := '0' + value; - if value[length(value)] = ':' then - value := value + '0'; - x := 8 - x; - s := ''; - for n := 1 to x do - s := s + ':0'; - s := s + ':'; - Result := replacestring(value, '::', s); -end; -{==============================================================================} - -function StrToIp6(Value: string): TIp6Bytes; -var - IPv6: TIp6Words; - Index: Integer; - n: integer; - b1, b2: byte; - s: string; - x: integer; -begin - for n := 0 to 15 do - Result[n] := 0; - for n := 0 to 7 do - Ipv6[n] := 0; - Index := 0; - Value := ExpandIP6(value); - if value = '' then - exit; - while Value <> '' do - begin - if Index > 7 then - Exit; - s := fetch(value, ':'); - if s = '@' then - break; - if s = '' then - begin - IPv6[Index] := 0; - end - else - begin - x := StrToIntDef('$' + s, -1); - if (x > 65535) or (x < 0) then - Exit; - IPv6[Index] := x; - end; - Inc(Index); - end; - for n := 0 to 7 do - begin - b1 := ipv6[n] div 256; - b2 := ipv6[n] mod 256; - Result[n * 2] := b1; - Result[(n * 2) + 1] := b2; - end; -end; - -{==============================================================================} -//based on routine by the Free Pascal development team -function Ip6ToStr(value: TIp6Bytes): string; -var - i, x: byte; - zr1,zr2: set of byte; - zc1,zc2: byte; - have_skipped: boolean; - ip6w: TIp6words; -begin - zr1 := []; - zr2 := []; - zc1 := 0; - zc2 := 0; - for i := 0 to 7 do - begin - x := i * 2; - ip6w[i] := value[x] * 256 + value[x + 1]; - if ip6w[i] = 0 then - begin - include(zr2, i); - inc(zc2); - end - else - begin - if zc1 < zc2 then - begin - zc1 := zc2; - zr1 := zr2; - zc2 := 0; - zr2 := []; - end; - end; - end; - if zc1 < zc2 then - begin - zr1 := zr2; - end; - SetLength(Result, 8*5-1); - SetLength(Result, 0); - have_skipped := false; - for i := 0 to 7 do - begin - if not(i in zr1) then - begin - if have_skipped then - begin - if Result = '' then - Result := '::' - else - Result := Result + ':'; - have_skipped := false; - end; - Result := Result + IntToHex(Ip6w[i], 1) + ':'; - end - else - begin - have_skipped := true; - end; - end; - if have_skipped then - if Result = '' then - Result := '::0' - else - Result := Result + ':'; - - if Result = '' then - Result := '::0'; - if not (7 in zr1) then - SetLength(Result, Length(Result)-1); - Result := LowerCase(result); -end; - -{==============================================================================} -function ReverseIP(Value: AnsiString): AnsiString; -var - x: Integer; -begin - Result := ''; - repeat - x := LastDelimiter('.', Value); - Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x); - Delete(Value, x, Length(Value) - x + 1); - until x < 1; - if Length(Result) > 0 then - if Result[1] = '.' then - Delete(Result, 1, 1); -end; - -{==============================================================================} -function ReverseIP6(Value: AnsiString): AnsiString; -var - ip6: TIp6bytes; - n: integer; - x, y: integer; -begin - ip6 := StrToIP6(Value); - x := ip6[15] div 16; - y := ip6[15] mod 16; - Result := IntToHex(y, 1) + '.' + IntToHex(x, 1); - for n := 14 downto 0 do - begin - x := ip6[n] div 16; - y := ip6[n] mod 16; - Result := Result + '.' + IntToHex(y, 1) + '.' + IntToHex(x, 1); - end; -end; - -{==============================================================================} -end. +{==============================================================================| +| Project : Ararat Synapse | 001.002.001 | +|==============================================================================| +| Content: IP address support procedures and functions | +|==============================================================================| +| Copyright (c)2006-2010, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c) 2006-2010. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(IP adress support procedures and functions)} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$R-} +{$H+} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} + {$WARN SUSPICIOUS_TYPECAST OFF} +{$ENDIF} + +unit synaip; + +interface + +uses + SysUtils, SynaUtil; + +type +{:binary form of IPv6 adress (for string conversion routines)} + TIp6Bytes = array [0..15] of Byte; +{:binary form of IPv6 adress (for string conversion routines)} + TIp6Words = array [0..7] of Word; + +{:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!} +function IsIP(const Value: string): Boolean; + +{:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!} +function IsIP6(const Value: string): Boolean; + +{:Returns a string with the "Host" ip address converted to binary form.} +function IPToID(Host: string): Ansistring; + +{:Convert IPv6 address from their string form to binary byte array.} +function StrToIp6(value: string): TIp6Bytes; + +{:Convert IPv6 address from binary byte array to string form.} +function Ip6ToStr(value: TIp6Bytes): string; + +{:Convert IPv4 address from their string form to binary.} +function StrToIp(value: string): integer; + +{:Convert IPv4 address from binary to string form.} +function IpToStr(value: integer): string; + +{:Convert IPv4 address to reverse form.} +function ReverseIP(Value: AnsiString): AnsiString; + +{:Convert IPv6 address to reverse form.} +function ReverseIP6(Value: AnsiString): AnsiString; + +{:Expand short form of IPv6 address to long form.} +function ExpandIP6(Value: AnsiString): AnsiString; + + +implementation + +{==============================================================================} + +function IsIP(const Value: string): Boolean; +var + TempIP: string; + function ByteIsOk(const Value: string): Boolean; + var + x, n: integer; + begin + x := StrToIntDef(Value, -1); + Result := (x >= 0) and (x < 256); + // X may be in correct range, but value still may not be correct value! + // i.e. "$80" + if Result then + for n := 1 to length(Value) do + if not (AnsiChar(Value[n]) in ['0'..'9']) then + begin + Result := False; + Break; + end; + end; +begin + TempIP := Value; + Result := False; + if not ByteIsOk(Fetch(TempIP, '.')) then + Exit; + if not ByteIsOk(Fetch(TempIP, '.')) then + Exit; + if not ByteIsOk(Fetch(TempIP, '.')) then + Exit; + if ByteIsOk(TempIP) then + Result := True; +end; + +{==============================================================================} + +function IsIP6(const Value: string): Boolean; +var + TempIP: string; + s,t: string; + x: integer; + partcount: integer; + zerocount: integer; + First: Boolean; +begin + TempIP := Value; + Result := False; + if Value = '::' then + begin + Result := True; + Exit; + end; + partcount := 0; + zerocount := 0; + First := True; + while tempIP <> '' do + begin + s := fetch(TempIP, ':'); + if not(First) and (s = '') then + Inc(zerocount); + First := False; + if zerocount > 1 then + break; + Inc(partCount); + if s = '' then + Continue; + if partCount > 8 then + break; + if tempIP = '' then + begin + t := SeparateRight(s, '%'); + s := SeparateLeft(s, '%'); + x := StrToIntDef('$' + t, -1); + if (x < 0) or (x > $ffff) then + break; + end; + x := StrToIntDef('$' + s, -1); + if (x < 0) or (x > $ffff) then + break; + if tempIP = '' then + if not((PartCount = 1) and (ZeroCount = 0)) then + Result := True; + end; +end; + +{==============================================================================} +function IPToID(Host: string): Ansistring; +var + s: string; + i, x: Integer; +begin + Result := ''; + for x := 0 to 3 do + begin + s := Fetch(Host, '.'); + i := StrToIntDef(s, 0); + Result := Result + AnsiChar(i); + end; +end; + +{==============================================================================} + +function StrToIp(value: string): integer; +var + s: string; + i, x: Integer; +begin + Result := 0; + for x := 0 to 3 do + begin + s := Fetch(value, '.'); + i := StrToIntDef(s, 0); + Result := (256 * Result) + i; + end; +end; + +{==============================================================================} + +function IpToStr(value: integer): string; +var + x1, x2: word; + y1, y2: byte; +begin + Result := ''; + x1 := value shr 16; + x2 := value and $FFFF; + y1 := x1 div $100; + y2 := x1 mod $100; + Result := inttostr(y1) + '.' + inttostr(y2) + '.'; + y1 := x2 div $100; + y2 := x2 mod $100; + Result := Result + inttostr(y1) + '.' + inttostr(y2); +end; + +{==============================================================================} + +function ExpandIP6(Value: AnsiString): AnsiString; +var + n: integer; + s: ansistring; + x: integer; +begin + Result := ''; + if value = '' then + exit; + x := countofchar(value, ':'); + if x > 7 then + exit; + if value[1] = ':' then + value := '0' + value; + if value[length(value)] = ':' then + value := value + '0'; + x := 8 - x; + s := ''; + for n := 1 to x do + s := s + ':0'; + s := s + ':'; + Result := replacestring(value, '::', s); +end; +{==============================================================================} + +function StrToIp6(Value: string): TIp6Bytes; +var + IPv6: TIp6Words; + Index: Integer; + n: integer; + b1, b2: byte; + s: string; + x: integer; +begin + for n := 0 to 15 do + Result[n] := 0; + for n := 0 to 7 do + Ipv6[n] := 0; + Index := 0; + Value := ExpandIP6(value); + if value = '' then + exit; + while Value <> '' do + begin + if Index > 7 then + Exit; + s := fetch(value, ':'); + if s = '@' then + break; + if s = '' then + begin + IPv6[Index] := 0; + end + else + begin + x := StrToIntDef('$' + s, -1); + if (x > 65535) or (x < 0) then + Exit; + IPv6[Index] := x; + end; + Inc(Index); + end; + for n := 0 to 7 do + begin + b1 := ipv6[n] div 256; + b2 := ipv6[n] mod 256; + Result[n * 2] := b1; + Result[(n * 2) + 1] := b2; + end; +end; + +{==============================================================================} +//based on routine by the Free Pascal development team +function Ip6ToStr(value: TIp6Bytes): string; +var + i, x: byte; + zr1,zr2: set of byte; + zc1,zc2: byte; + have_skipped: boolean; + ip6w: TIp6words; +begin + zr1 := []; + zr2 := []; + zc1 := 0; + zc2 := 0; + for i := 0 to 7 do + begin + x := i * 2; + ip6w[i] := value[x] * 256 + value[x + 1]; + if ip6w[i] = 0 then + begin + include(zr2, i); + inc(zc2); + end + else + begin + if zc1 < zc2 then + begin + zc1 := zc2; + zr1 := zr2; + zc2 := 0; + zr2 := []; + end; + end; + end; + if zc1 < zc2 then + begin + zr1 := zr2; + end; + SetLength(Result, 8*5-1); + SetLength(Result, 0); + have_skipped := false; + for i := 0 to 7 do + begin + if not(i in zr1) then + begin + if have_skipped then + begin + if Result = '' then + Result := '::' + else + Result := Result + ':'; + have_skipped := false; + end; + Result := Result + IntToHex(Ip6w[i], 1) + ':'; + end + else + begin + have_skipped := true; + end; + end; + if have_skipped then + if Result = '' then + Result := '::0' + else + Result := Result + ':'; + + if Result = '' then + Result := '::0'; + if not (7 in zr1) then + SetLength(Result, Length(Result)-1); + Result := LowerCase(result); +end; + +{==============================================================================} +function ReverseIP(Value: AnsiString): AnsiString; +var + x: Integer; +begin + Result := ''; + repeat + x := LastDelimiter('.', Value); + Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x); + Delete(Value, x, Length(Value) - x + 1); + until x < 1; + if Length(Result) > 0 then + if Result[1] = '.' then + Delete(Result, 1, 1); +end; + +{==============================================================================} +function ReverseIP6(Value: AnsiString): AnsiString; +var + ip6: TIp6bytes; + n: integer; + x, y: integer; +begin + ip6 := StrToIP6(Value); + x := ip6[15] div 16; + y := ip6[15] mod 16; + Result := IntToHex(y, 1) + '.' + IntToHex(x, 1); + for n := 14 downto 0 do + begin + x := ip6[n] div 16; + y := ip6[n] mod 16; + Result := Result + '.' + IntToHex(y, 1) + '.' + IntToHex(x, 1); + end; +end; + +{==============================================================================} +end. diff --git a/3rd/synapse/source/synamisc.pas b/3rd/synapse/source/synamisc.pas index 838c5c615..bf3e5d29a 100644 --- a/3rd/synapse/source/synamisc.pas +++ b/3rd/synapse/source/synamisc.pas @@ -1,408 +1,408 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.003.001 | -|==============================================================================| -| Content: misc. procedures and functions | -|==============================================================================| -| Copyright (c)1999-2014, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 2002-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Miscellaneous network based utilities)} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -//Kylix does not known UNIX define -{$IFDEF LINUX} - {$IFNDEF UNIX} - {$DEFINE UNIX} - {$ENDIF} -{$ENDIF} - -{$TYPEDADDRESS OFF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synamisc; - -interface - -{$IFDEF VER125} - {$DEFINE BCB} -{$ENDIF} -{$IFDEF BCB} - {$ObjExportAll On} - {$HPPEMIT '#pragma comment( lib , "wininet.lib" )'} -{$ENDIF} - -uses - synautil, blcksock, SysUtils, Classes -{$IFDEF UNIX} - {$IFNDEF FPC} - , Libc - {$ENDIF} -{$ELSE} - , Windows -{$ENDIF} -; - -Type - {:@abstract(This record contains information about proxy settings.)} - TProxySetting = record - Host: string; - Port: string; - Bypass: string; - end; - -{:With this function you can turn on a computer on the network, if this computer - supports Wake-on-LAN feature. You need the MAC address - (network card identifier) of the computer. You can also assign a target IP - addres. If you do not specify it, then broadcast is used to deliver magic - wake-on-LAN packet. - However broadcasts work only on your local network. When you need to wake-up a - computer on another network, you must specify any existing IP addres on same - network segment as targeting computer.} -procedure WakeOnLan(MAC, IP: string); - -{:Autodetect current DNS servers used by the system. If more than one DNS server - is defined, then the result is comma-delimited.} -function GetDNS: string; - -{:Autodetect InternetExplorer proxy setting for given protocol. This function -works only on windows!} -function GetIEProxy(protocol: string): TProxySetting; - -{:Return all known IP addresses on the local system. Addresses are divided by -comma/comma-delimited.} -function GetLocalIPs: string; - -implementation - -{==============================================================================} -procedure WakeOnLan(MAC, IP: string); -var - sock: TUDPBlockSocket; - HexMac: Ansistring; - data: Ansistring; - n: integer; - b: Byte; -begin - if MAC <> '' then - begin - MAC := ReplaceString(MAC, '-', ''); - MAC := ReplaceString(MAC, ':', ''); - if Length(MAC) < 12 then - Exit; - HexMac := ''; - for n := 0 to 5 do - begin - b := StrToIntDef('$' + MAC[n * 2 + 1] + MAC[n * 2 + 2], 0); - HexMac := HexMac + char(b); - end; - if IP = '' then - IP := cBroadcast; - sock := TUDPBlockSocket.Create; - try - sock.CreateSocket; - sock.EnableBroadcast(true); - sock.Connect(IP, '9'); - data := #$FF + #$FF + #$FF + #$FF + #$FF + #$FF; - for n := 1 to 16 do - data := data + HexMac; - sock.SendString(data); - finally - sock.Free; - end; - end; -end; - -{==============================================================================} - -{$IFNDEF UNIX} -function GetDNSbyIpHlp: string; -type - PTIP_ADDRESS_STRING = ^TIP_ADDRESS_STRING; - TIP_ADDRESS_STRING = array[0..15] of Ansichar; - PTIP_ADDR_STRING = ^TIP_ADDR_STRING; - TIP_ADDR_STRING = packed record - Next: PTIP_ADDR_STRING; - IpAddress: TIP_ADDRESS_STRING; - IpMask: TIP_ADDRESS_STRING; - Context: DWORD; - end; - PTFixedInfo = ^TFixedInfo; - TFixedInfo = packed record - HostName: array[1..128 + 4] of Ansichar; - DomainName: array[1..128 + 4] of Ansichar; - CurrentDNSServer: PTIP_ADDR_STRING; - DNSServerList: TIP_ADDR_STRING; - NodeType: UINT; - ScopeID: array[1..256 + 4] of Ansichar; - EnableRouting: UINT; - EnableProxy: UINT; - EnableDNS: UINT; - end; -const - IpHlpDLL = 'IPHLPAPI.DLL'; -var - IpHlpModule: THandle; - FixedInfo: PTFixedInfo; - InfoSize: Longint; - PDnsServer: PTIP_ADDR_STRING; - err: integer; - GetNetworkParams: function(FixedInfo: PTFixedInfo; pOutPutLen: PULONG): DWORD; stdcall; -begin - InfoSize := 0; - Result := '...'; - IpHlpModule := LoadLibrary(IpHlpDLL); - if IpHlpModule = 0 then - exit; - try - GetNetworkParams := GetProcAddress(IpHlpModule,PAnsiChar(AnsiString('GetNetworkParams'))); - if @GetNetworkParams = nil then - Exit; - err := GetNetworkParams(Nil, @InfoSize); - if err <> ERROR_BUFFER_OVERFLOW then - Exit; - Result := ''; - GetMem (FixedInfo, InfoSize); - try - err := GetNetworkParams(FixedInfo, @InfoSize); - if err <> ERROR_SUCCESS then - exit; - with FixedInfo^ do - begin - Result := DnsServerList.IpAddress; - PDnsServer := DnsServerList.Next; - while PDnsServer <> Nil do - begin - if Result <> '' then - Result := Result + ','; - Result := Result + PDnsServer^.IPAddress; - PDnsServer := PDnsServer.Next; - end; - end; - finally - FreeMem(FixedInfo); - end; - finally - FreeLibrary(IpHlpModule); - end; -end; - -function ReadReg(SubKey, Vn: PChar): string; -var - OpenKey: HKEY; - DataType, DataSize: integer; - Temp: array [0..2048] of char; -begin - Result := ''; - if RegOpenKeyEx(HKEY_LOCAL_MACHINE, SubKey, REG_OPTION_NON_VOLATILE, - KEY_READ, OpenKey) = ERROR_SUCCESS then - begin - DataType := REG_SZ; - DataSize := SizeOf(Temp); - if RegQueryValueEx(OpenKey, Vn, nil, @DataType, @Temp, @DataSize) = ERROR_SUCCESS then - SetString(Result, Temp, DataSize div SizeOf(Char) - 1); - RegCloseKey(OpenKey); - end; -end ; -{$ENDIF} - -function GetDNS: string; -{$IFDEF UNIX} -var - l: TStringList; - n: integer; -begin - Result := ''; - l := TStringList.Create; - try - l.LoadFromFile('/etc/resolv.conf'); - for n := 0 to l.Count - 1 do - if Pos('NAMESERVER', uppercase(l[n])) = 1 then - begin - if Result <> '' then - Result := Result + ','; - Result := Result + SeparateRight(l[n], ' '); - end; - finally - l.Free; - end; -end; -{$ELSE} -const - NTdyn = 'System\CurrentControlSet\Services\Tcpip\Parameters\Temporary'; - NTfix = 'System\CurrentControlSet\Services\Tcpip\Parameters'; - W9xfix = 'System\CurrentControlSet\Services\MSTCP'; -begin - Result := GetDNSbyIpHlp; - if Result = '...' then - begin - if Win32Platform = VER_PLATFORM_WIN32_NT then - begin - Result := ReadReg(NTdyn, 'NameServer'); - if result = '' then - Result := ReadReg(NTfix, 'NameServer'); - if result = '' then - Result := ReadReg(NTfix, 'DhcpNameServer'); - end - else - Result := ReadReg(W9xfix, 'NameServer'); - Result := ReplaceString(trim(Result), ' ', ','); - end; -end; -{$ENDIF} - -{==============================================================================} - -function GetIEProxy(protocol: string): TProxySetting; -{$IFDEF UNIX} -begin - Result.Host := ''; - Result.Port := ''; - Result.Bypass := ''; -end; -{$ELSE} -type - PInternetProxyInfo = ^TInternetProxyInfo; - TInternetProxyInfo = packed record - dwAccessType: DWORD; - lpszProxy: LPCSTR; - lpszProxyBypass: LPCSTR; - end; -const - INTERNET_OPTION_PROXY = 38; - INTERNET_OPEN_TYPE_PROXY = 3; - WininetDLL = 'WININET.DLL'; -var - WininetModule: THandle; - ProxyInfo: PInternetProxyInfo; - Err: Boolean; - Len: DWORD; - Proxy: string; - DefProxy: string; - ProxyList: TStringList; - n: integer; - InternetQueryOption: function (hInet: Pointer; dwOption: DWORD; - lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL; stdcall; -begin - Result.Host := ''; - Result.Port := ''; - Result.Bypass := ''; - WininetModule := LoadLibrary(WininetDLL); - if WininetModule = 0 then - exit; - try - InternetQueryOption := GetProcAddress(WininetModule,PAnsiChar(AnsiString('InternetQueryOptionA'))); - if @InternetQueryOption = nil then - Exit; - - if protocol = '' then - protocol := 'http'; - Len := 4096; - GetMem(ProxyInfo, Len); - ProxyList := TStringList.Create; - try - Err := InternetQueryOption(nil, INTERNET_OPTION_PROXY, ProxyInfo, Len); - if Err then - if ProxyInfo^.dwAccessType = INTERNET_OPEN_TYPE_PROXY then - begin - ProxyList.CommaText := ReplaceString(ProxyInfo^.lpszProxy, ' ', ','); - Proxy := ''; - DefProxy := ''; - for n := 0 to ProxyList.Count -1 do - begin - if Pos(lowercase(protocol) + '=', lowercase(ProxyList[n])) = 1 then - begin - Proxy := SeparateRight(ProxyList[n], '='); - break; - end; - if Pos('=', ProxyList[n]) < 1 then - DefProxy := ProxyList[n]; - end; - if Proxy = '' then - Proxy := DefProxy; - if Proxy <> '' then - begin - Result.Host := Trim(SeparateLeft(Proxy, ':')); - Result.Port := Trim(SeparateRight(Proxy, ':')); - end; - Result.Bypass := ReplaceString(ProxyInfo^.lpszProxyBypass, ' ', ','); - end; - finally - ProxyList.Free; - FreeMem(ProxyInfo); - end; - finally - FreeLibrary(WininetModule); - end; -end; -{$ENDIF} - -{==============================================================================} - -function GetLocalIPs: string; -var - TcpSock: TTCPBlockSocket; - ipList: TStringList; -begin - Result := ''; - ipList := TStringList.Create; - try - TcpSock := TTCPBlockSocket.create; - try - TcpSock.ResolveNameToIP(TcpSock.LocalName, ipList); - Result := ipList.CommaText; - finally - TcpSock.Free; - end; - finally - ipList.Free; - end; -end; - -{==============================================================================} - -end. +{==============================================================================| +| Project : Ararat Synapse | 001.003.001 | +|==============================================================================| +| Content: misc. procedures and functions | +|==============================================================================| +| Copyright (c)1999-2014, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c) 2002-2010. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(Miscellaneous network based utilities)} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$Q-} +{$H+} + +//Kylix does not known UNIX define +{$IFDEF LINUX} + {$IFNDEF UNIX} + {$DEFINE UNIX} + {$ENDIF} +{$ENDIF} + +{$TYPEDADDRESS OFF} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} +{$ENDIF} + +unit synamisc; + +interface + +{$IFDEF VER125} + {$DEFINE BCB} +{$ENDIF} +{$IFDEF BCB} + {$ObjExportAll On} + {$HPPEMIT '#pragma comment( lib , "wininet.lib" )'} +{$ENDIF} + +uses + synautil, blcksock, SysUtils, Classes +{$IFDEF UNIX} + {$IFNDEF FPC} + , Libc + {$ENDIF} +{$ELSE} + , Windows +{$ENDIF} +; + +Type + {:@abstract(This record contains information about proxy settings.)} + TProxySetting = record + Host: string; + Port: string; + Bypass: string; + end; + +{:With this function you can turn on a computer on the network, if this computer + supports Wake-on-LAN feature. You need the MAC address + (network card identifier) of the computer. You can also assign a target IP + addres. If you do not specify it, then broadcast is used to deliver magic + wake-on-LAN packet. + However broadcasts work only on your local network. When you need to wake-up a + computer on another network, you must specify any existing IP addres on same + network segment as targeting computer.} +procedure WakeOnLan(MAC, IP: string); + +{:Autodetect current DNS servers used by the system. If more than one DNS server + is defined, then the result is comma-delimited.} +function GetDNS: string; + +{:Autodetect InternetExplorer proxy setting for given protocol. This function +works only on windows!} +function GetIEProxy(protocol: string): TProxySetting; + +{:Return all known IP addresses on the local system. Addresses are divided by +comma/comma-delimited.} +function GetLocalIPs: string; + +implementation + +{==============================================================================} +procedure WakeOnLan(MAC, IP: string); +var + sock: TUDPBlockSocket; + HexMac: Ansistring; + data: Ansistring; + n: integer; + b: Byte; +begin + if MAC <> '' then + begin + MAC := ReplaceString(MAC, '-', ''); + MAC := ReplaceString(MAC, ':', ''); + if Length(MAC) < 12 then + Exit; + HexMac := ''; + for n := 0 to 5 do + begin + b := StrToIntDef('$' + MAC[n * 2 + 1] + MAC[n * 2 + 2], 0); + HexMac := HexMac + char(b); + end; + if IP = '' then + IP := cBroadcast; + sock := TUDPBlockSocket.Create; + try + sock.CreateSocket; + sock.EnableBroadcast(true); + sock.Connect(IP, '9'); + data := #$FF + #$FF + #$FF + #$FF + #$FF + #$FF; + for n := 1 to 16 do + data := data + HexMac; + sock.SendString(data); + finally + sock.Free; + end; + end; +end; + +{==============================================================================} + +{$IFNDEF UNIX} +function GetDNSbyIpHlp: string; +type + PTIP_ADDRESS_STRING = ^TIP_ADDRESS_STRING; + TIP_ADDRESS_STRING = array[0..15] of Ansichar; + PTIP_ADDR_STRING = ^TIP_ADDR_STRING; + TIP_ADDR_STRING = packed record + Next: PTIP_ADDR_STRING; + IpAddress: TIP_ADDRESS_STRING; + IpMask: TIP_ADDRESS_STRING; + Context: DWORD; + end; + PTFixedInfo = ^TFixedInfo; + TFixedInfo = packed record + HostName: array[1..128 + 4] of Ansichar; + DomainName: array[1..128 + 4] of Ansichar; + CurrentDNSServer: PTIP_ADDR_STRING; + DNSServerList: TIP_ADDR_STRING; + NodeType: UINT; + ScopeID: array[1..256 + 4] of Ansichar; + EnableRouting: UINT; + EnableProxy: UINT; + EnableDNS: UINT; + end; +const + IpHlpDLL = 'IPHLPAPI.DLL'; +var + IpHlpModule: THandle; + FixedInfo: PTFixedInfo; + InfoSize: Longint; + PDnsServer: PTIP_ADDR_STRING; + err: integer; + GetNetworkParams: function(FixedInfo: PTFixedInfo; pOutPutLen: PULONG): DWORD; stdcall; +begin + InfoSize := 0; + Result := '...'; + IpHlpModule := LoadLibrary(IpHlpDLL); + if IpHlpModule = 0 then + exit; + try + GetNetworkParams := GetProcAddress(IpHlpModule,PAnsiChar(AnsiString('GetNetworkParams'))); + if @GetNetworkParams = nil then + Exit; + err := GetNetworkParams(Nil, @InfoSize); + if err <> ERROR_BUFFER_OVERFLOW then + Exit; + Result := ''; + GetMem (FixedInfo, InfoSize); + try + err := GetNetworkParams(FixedInfo, @InfoSize); + if err <> ERROR_SUCCESS then + exit; + with FixedInfo^ do + begin + Result := DnsServerList.IpAddress; + PDnsServer := DnsServerList.Next; + while PDnsServer <> Nil do + begin + if Result <> '' then + Result := Result + ','; + Result := Result + PDnsServer^.IPAddress; + PDnsServer := PDnsServer.Next; + end; + end; + finally + FreeMem(FixedInfo); + end; + finally + FreeLibrary(IpHlpModule); + end; +end; + +function ReadReg(SubKey, Vn: PChar): string; +var + OpenKey: HKEY; + DataType, DataSize: integer; + Temp: array [0..2048] of char; +begin + Result := ''; + if RegOpenKeyEx(HKEY_LOCAL_MACHINE, SubKey, REG_OPTION_NON_VOLATILE, + KEY_READ, OpenKey) = ERROR_SUCCESS then + begin + DataType := REG_SZ; + DataSize := SizeOf(Temp); + if RegQueryValueEx(OpenKey, Vn, nil, @DataType, @Temp, @DataSize) = ERROR_SUCCESS then + SetString(Result, Temp, DataSize div SizeOf(Char) - 1); + RegCloseKey(OpenKey); + end; +end ; +{$ENDIF} + +function GetDNS: string; +{$IFDEF UNIX} +var + l: TStringList; + n: integer; +begin + Result := ''; + l := TStringList.Create; + try + l.LoadFromFile('/etc/resolv.conf'); + for n := 0 to l.Count - 1 do + if Pos('NAMESERVER', uppercase(l[n])) = 1 then + begin + if Result <> '' then + Result := Result + ','; + Result := Result + SeparateRight(l[n], ' '); + end; + finally + l.Free; + end; +end; +{$ELSE} +const + NTdyn = 'System\CurrentControlSet\Services\Tcpip\Parameters\Temporary'; + NTfix = 'System\CurrentControlSet\Services\Tcpip\Parameters'; + W9xfix = 'System\CurrentControlSet\Services\MSTCP'; +begin + Result := GetDNSbyIpHlp; + if Result = '...' then + begin + if Win32Platform = VER_PLATFORM_WIN32_NT then + begin + Result := ReadReg(NTdyn, 'NameServer'); + if result = '' then + Result := ReadReg(NTfix, 'NameServer'); + if result = '' then + Result := ReadReg(NTfix, 'DhcpNameServer'); + end + else + Result := ReadReg(W9xfix, 'NameServer'); + Result := ReplaceString(trim(Result), ' ', ','); + end; +end; +{$ENDIF} + +{==============================================================================} + +function GetIEProxy(protocol: string): TProxySetting; +{$IFDEF UNIX} +begin + Result.Host := ''; + Result.Port := ''; + Result.Bypass := ''; +end; +{$ELSE} +type + PInternetProxyInfo = ^TInternetProxyInfo; + TInternetProxyInfo = packed record + dwAccessType: DWORD; + lpszProxy: LPCSTR; + lpszProxyBypass: LPCSTR; + end; +const + INTERNET_OPTION_PROXY = 38; + INTERNET_OPEN_TYPE_PROXY = 3; + WininetDLL = 'WININET.DLL'; +var + WininetModule: THandle; + ProxyInfo: PInternetProxyInfo; + Err: Boolean; + Len: DWORD; + Proxy: string; + DefProxy: string; + ProxyList: TStringList; + n: integer; + InternetQueryOption: function (hInet: Pointer; dwOption: DWORD; + lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL; stdcall; +begin + Result.Host := ''; + Result.Port := ''; + Result.Bypass := ''; + WininetModule := LoadLibrary(WininetDLL); + if WininetModule = 0 then + exit; + try + InternetQueryOption := GetProcAddress(WininetModule,PAnsiChar(AnsiString('InternetQueryOptionA'))); + if @InternetQueryOption = nil then + Exit; + + if protocol = '' then + protocol := 'http'; + Len := 4096; + GetMem(ProxyInfo, Len); + ProxyList := TStringList.Create; + try + Err := InternetQueryOption(nil, INTERNET_OPTION_PROXY, ProxyInfo, Len); + if Err then + if ProxyInfo^.dwAccessType = INTERNET_OPEN_TYPE_PROXY then + begin + ProxyList.CommaText := ReplaceString(ProxyInfo^.lpszProxy, ' ', ','); + Proxy := ''; + DefProxy := ''; + for n := 0 to ProxyList.Count -1 do + begin + if Pos(lowercase(protocol) + '=', lowercase(ProxyList[n])) = 1 then + begin + Proxy := SeparateRight(ProxyList[n], '='); + break; + end; + if Pos('=', ProxyList[n]) < 1 then + DefProxy := ProxyList[n]; + end; + if Proxy = '' then + Proxy := DefProxy; + if Proxy <> '' then + begin + Result.Host := Trim(SeparateLeft(Proxy, ':')); + Result.Port := Trim(SeparateRight(Proxy, ':')); + end; + Result.Bypass := ReplaceString(ProxyInfo^.lpszProxyBypass, ' ', ','); + end; + finally + ProxyList.Free; + FreeMem(ProxyInfo); + end; + finally + FreeLibrary(WininetModule); + end; +end; +{$ENDIF} + +{==============================================================================} + +function GetLocalIPs: string; +var + TcpSock: TTCPBlockSocket; + ipList: TStringList; +begin + Result := ''; + ipList := TStringList.Create; + try + TcpSock := TTCPBlockSocket.create; + try + TcpSock.ResolveNameToIP(TcpSock.LocalName, ipList); + Result := ipList.CommaText; + finally + TcpSock.Free; + end; + finally + ipList.Free; + end; +end; + +{==============================================================================} + +end. diff --git a/3rd/synapse/source/synaser.pas b/3rd/synapse/source/synaser.pas index 526ecb4fa..160e9b059 100644 --- a/3rd/synapse/source/synaser.pas +++ b/3rd/synapse/source/synaser.pas @@ -1,2336 +1,2336 @@ -{==============================================================================| -| Project : Ararat Synapse | 007.005.006 | -|==============================================================================| -| Content: Serial port support | -|==============================================================================| -| Copyright (c)2001-2014, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2014. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| (c)2002, Hans-Georg Joepgen (cpom Comport Ownership Manager and bugfixes) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(Serial port communication library) -This unit contains a class that implements serial port communication - for Windows, Linux, Unix or MacOSx. This class provides numerous methods with - same name and functionality as methods of the Ararat Synapse TCP/IP library. - -The following is a small example how establish a connection by modem (in this -case with my USB modem): -@longcode(# - ser:=TBlockSerial.Create; - try - ser.Connect('COM3'); - ser.config(460800,8,'N',0,false,true); - ser.ATCommand('AT'); - if (ser.LastError <> 0) or (not ser.ATResult) then - Exit; - ser.ATConnect('ATDT+420971200111'); - if (ser.LastError <> 0) or (not ser.ATResult) then - Exit; - // you are now connected to a modem at +420971200111 - // you can transmit or receive data now - finally - ser.free; - end; -#) -} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -//Kylix does not known UNIX define -{$IFDEF LINUX} - {$IFNDEF UNIX} - {$DEFINE UNIX} - {$ENDIF} -{$ENDIF} - -{$IFDEF FPC} - {$MODE DELPHI} - {$IFDEF MSWINDOWS} - {$ASMMODE intel} - {$ENDIF} - {define working mode w/o LIBC for fpc} - {$DEFINE NO_LIBC} -{$ENDIF} -{$Q-} -{$H+} -{$M+} - -unit synaser; - -interface - -uses -{$IFNDEF MSWINDOWS} - {$IFNDEF NO_LIBC} - Libc, - KernelIoctl, - {$ELSE} - termio, baseunix, unix, - {$ENDIF} - {$IFNDEF FPC} - Types, - {$ENDIF} -{$ELSE} - Windows, registry, - {$IFDEF FPC} - winver, - {$ENDIF} -{$ENDIF} - synafpc, - Classes, SysUtils, synautil; - -const - CR = #$0d; - LF = #$0a; - CRLF = CR + LF; - cSerialChunk = 8192; - - LockfileDirectory = '/var/lock'; {HGJ} - PortIsClosed = -1; {HGJ} - ErrAlreadyOwned = 9991; {HGJ} - ErrAlreadyInUse = 9992; {HGJ} - ErrWrongParameter = 9993; {HGJ} - ErrPortNotOpen = 9994; {HGJ} - ErrNoDeviceAnswer = 9995; {HGJ} - ErrMaxBuffer = 9996; - ErrTimeout = 9997; - ErrNotRead = 9998; - ErrFrame = 9999; - ErrOverrun = 10000; - ErrRxOver = 10001; - ErrRxParity = 10002; - ErrTxFull = 10003; - - dcb_Binary = $00000001; - dcb_ParityCheck = $00000002; - dcb_OutxCtsFlow = $00000004; - dcb_OutxDsrFlow = $00000008; - dcb_DtrControlMask = $00000030; - dcb_DtrControlDisable = $00000000; - dcb_DtrControlEnable = $00000010; - dcb_DtrControlHandshake = $00000020; - dcb_DsrSensivity = $00000040; - dcb_TXContinueOnXoff = $00000080; - dcb_OutX = $00000100; - dcb_InX = $00000200; - dcb_ErrorChar = $00000400; - dcb_NullStrip = $00000800; - dcb_RtsControlMask = $00003000; - dcb_RtsControlDisable = $00000000; - dcb_RtsControlEnable = $00001000; - dcb_RtsControlHandshake = $00002000; - dcb_RtsControlToggle = $00003000; - dcb_AbortOnError = $00004000; - dcb_Reserveds = $FFFF8000; - - {:stopbit value for 1 stopbit} - SB1 = 0; - {:stopbit value for 1.5 stopbit} - SB1andHalf = 1; - {:stopbit value for 2 stopbits} - SB2 = 2; - -{$IFNDEF MSWINDOWS} -const - INVALID_HANDLE_VALUE = THandle(-1); - CS7fix = $0000020; - -type - TDCB = record - DCBlength: DWORD; - BaudRate: DWORD; - Flags: Longint; - wReserved: Word; - XonLim: Word; - XoffLim: Word; - ByteSize: Byte; - Parity: Byte; - StopBits: Byte; - XonChar: CHAR; - XoffChar: CHAR; - ErrorChar: CHAR; - EofChar: CHAR; - EvtChar: CHAR; - wReserved1: Word; - end; - PDCB = ^TDCB; - -const -{$IFDEF UNIX} - {$IFDEF BSD} - MaxRates = 18; //MAC - {$ELSE} - MaxRates = 30; //UNIX - {$ENDIF} -{$ELSE} - MaxRates = 19; //WIN -{$ENDIF} - Rates: array[0..MaxRates, 0..1] of cardinal = - ( - (0, B0), - (50, B50), - (75, B75), - (110, B110), - (134, B134), - (150, B150), - (200, B200), - (300, B300), - (600, B600), - (1200, B1200), - (1800, B1800), - (2400, B2400), - (4800, B4800), - (9600, B9600), - (19200, B19200), - (38400, B38400), - (57600, B57600), - (115200, B115200), - (230400, B230400) -{$IFNDEF BSD} - ,(460800, B460800) - {$IFDEF UNIX} - ,(500000, B500000), - (576000, B576000), - (921600, B921600), - (1000000, B1000000), - (1152000, B1152000), - (1500000, B1500000), - (2000000, B2000000), - (2500000, B2500000), - (3000000, B3000000), - (3500000, B3500000), - (4000000, B4000000) - {$ENDIF} -{$ENDIF} - ); -{$ENDIF} - -{$IFDEF BSD} -const // From fcntl.h - O_SYNC = $0080; { synchronous writes } -{$ENDIF} - -const - sOK = 0; - sErr = integer(-1); - -type - - {:Possible status event types for @link(THookSerialStatus)} - THookSerialReason = ( - HR_SerialClose, - HR_Connect, - HR_CanRead, - HR_CanWrite, - HR_ReadCount, - HR_WriteCount, - HR_Wait - ); - - {:procedural prototype for status event hooking} - THookSerialStatus = procedure(Sender: TObject; Reason: THookSerialReason; - const Value: string) of object; - - {:@abstract(Exception type for SynaSer errors)} - ESynaSerError = class(Exception) - public - ErrorCode: integer; - ErrorMessage: string; - end; - - {:@abstract(Main class implementing all communication routines)} - TBlockSerial = class(TObject) - protected - FOnStatus: THookSerialStatus; - Fhandle: THandle; - FTag: integer; - FDevice: string; - FLastError: integer; - FLastErrorDesc: string; - FBuffer: AnsiString; - FRaiseExcept: boolean; - FRecvBuffer: integer; - FSendBuffer: integer; - FModemWord: integer; - FRTSToggle: Boolean; - FDeadlockTimeout: integer; - FInstanceActive: boolean; {HGJ} - FTestDSR: Boolean; - FTestCTS: Boolean; - FLastCR: Boolean; - FLastLF: Boolean; - FMaxLineLength: Integer; - FLinuxLock: Boolean; - FMaxSendBandwidth: Integer; - FNextSend: LongWord; - FMaxRecvBandwidth: Integer; - FNextRecv: LongWord; - FConvertLineEnd: Boolean; - FATResult: Boolean; - FAtTimeout: integer; - FInterPacketTimeout: Boolean; - FComNr: integer; -{$IFDEF MSWINDOWS} - FPortAddr: Word; - function CanEvent(Event: dword; Timeout: integer): boolean; - procedure DecodeCommError(Error: DWord); virtual; - {$IFDEF WIN32} - function GetPortAddr: Word; virtual; - function ReadTxEmpty(PortAddr: Word): Boolean; virtual; - {$ENDIF} -{$ENDIF} - procedure SetSizeRecvBuffer(size: integer); virtual; - function GetDSR: Boolean; virtual; - procedure SetDTRF(Value: Boolean); virtual; - function GetCTS: Boolean; virtual; - procedure SetRTSF(Value: Boolean); virtual; - function GetCarrier: Boolean; virtual; - function GetRing: Boolean; virtual; - procedure DoStatus(Reason: THookSerialReason; const Value: string); virtual; - procedure GetComNr(Value: string); virtual; - function PreTestFailing: boolean; virtual;{HGJ} - function TestCtrlLine: Boolean; virtual; -{$IFDEF UNIX} - procedure DcbToTermios(const dcb: TDCB; var term: termios); virtual; - procedure TermiosToDcb(const term: termios; var dcb: TDCB); virtual; - function ReadLockfile: integer; virtual; - function LockfileName: String; virtual; - procedure CreateLockfile(PidNr: integer); virtual; -{$ENDIF} - procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); virtual; - procedure SetBandwidth(Value: Integer); virtual; - public - {: data Control Block with communication parameters. Usable only when you - need to call API directly.} - DCB: Tdcb; -{$IFDEF UNIX} - TermiosStruc: termios; -{$ENDIF} - {:Object constructor.} - constructor Create; - {:Object destructor.} - destructor Destroy; override; - - {:Returns a string containing the version number of the library.} - class function GetVersion: string; virtual; - - {:Destroy handle in use. It close connection to serial port.} - procedure CloseSocket; virtual; - - {:Reconfigure communication parameters on the fly. You must be connected to - port before! - @param(baud Define connection speed. Baud rate can be from 50 to 4000000 - bits per second. (it depends on your hardware!)) - @param(bits Number of bits in communication.) - @param(parity Define communication parity (N - None, O - Odd, E - Even, M - Mark or S - Space).) - @param(stop Define number of stopbits. Use constants @link(SB1), - @link(SB1andHalf) and @link(SB2).) - @param(softflow Enable XON/XOFF handshake.) - @param(hardflow Enable CTS/RTS handshake.)} - procedure Config(baud, bits: integer; parity: char; stop: integer; - softflow, hardflow: boolean); virtual; - - {:Connects to the port indicated by comport. Comport can be used in Windows - style (COM2), or in Linux style (/dev/ttyS1). When you use windows style - in Linux, then it will be converted to Linux name. And vice versa! However - you can specify any device name! (other device names then standart is not - converted!) - - After successfull connection the DTR signal is set (if you not set hardware - handshake, then the RTS signal is set, too!) - - Connection parameters is predefined by your system configuration. If you - need use another parameters, then you can use Config method after. - Notes: - - - Remember, the commonly used serial Laplink cable does not support - hardware handshake. - - - Before setting any handshake you must be sure that it is supported by - your hardware. - - - Some serial devices are slow. In some cases you must wait up to a few - seconds after connection for the device to respond. - - - when you connect to a modem device, then is best to test it by an empty - AT command. (call ATCommand('AT'))} - procedure Connect(comport: string); virtual; - - {:Set communication parameters from the DCB structure (the DCB structure is - simulated under Linux).} - procedure SetCommState; virtual; - - {:Read communication parameters into the DCB structure (DCB structure is - simulated under Linux).} - procedure GetCommState; virtual; - - {:Sends Length bytes of data from Buffer through the connected port.} - function SendBuffer(buffer: pointer; length: integer): integer; virtual; - - {:One data BYTE is sent.} - procedure SendByte(data: byte); virtual; - - {:Send the string in the data parameter. No terminator is appended by this - method. If you need to send a string with CR/LF terminator, you must append - the CR/LF characters to the data string! - - Since no terminator is appended, you can use this function for sending - binary data too.} - procedure SendString(data: AnsiString); virtual; - - {:send four bytes as integer.} - procedure SendInteger(Data: integer); virtual; - - {:send data as one block. Each block begins with integer value with Length - of block.} - procedure SendBlock(const Data: AnsiString); virtual; - - {:send content of stream from current position} - procedure SendStreamRaw(const Stream: TStream); virtual; - - {:send content of stream as block. see @link(SendBlock)} - procedure SendStream(const Stream: TStream); virtual; - - {:send content of stream as block, but this is compatioble with Indy library. - (it have swapped lenght of block). See @link(SendStream)} - procedure SendStreamIndy(const Stream: TStream); virtual; - - {:Waits until the allocated buffer is filled by received data. Returns number - of data bytes received, which equals to the Length value under normal - operation. If it is not equal, the communication channel is possibly broken. - - This method not using any internal buffering, like all others receiving - methods. You cannot freely combine this method with all others receiving - methods!} - function RecvBuffer(buffer: pointer; length: integer): integer; virtual; - - {:Method waits until data is received. If no data is received within - the Timeout (in milliseconds) period, @link(LastError) is set to - @link(ErrTimeout). This method is used to read any amount of data - (e. g. 1MB), and may be freely combined with all receviving methods what - have Timeout parameter, like the @link(RecvString), @link(RecvByte) or - @link(RecvTerminated) methods.} - function RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; virtual; - - {:It is like recvBufferEx, but data is readed to dynamicly allocated binary - string.} - function RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; virtual; - - {:Read all available data and return it in the function result string. This - function may be combined with @link(RecvString), @link(RecvByte) or related - methods.} - function RecvPacket(Timeout: Integer): AnsiString; virtual; - - {:Waits until one data byte is received which is returned as the function - result. If no data is received within the Timeout (in milliseconds) period, - @link(LastError) is set to @link(ErrTimeout).} - function RecvByte(timeout: integer): byte; virtual; - - {:This method waits until a terminated data string is received. This string - is terminated by the Terminator string. The resulting string is returned - without this termination string! If no data is received within the Timeout - (in milliseconds) period, @link(LastError) is set to @link(ErrTimeout).} - function RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; virtual; - - {:This method waits until a terminated data string is received. The string - is terminated by a CR/LF sequence. The resulting string is returned without - the terminator (CR/LF)! If no data is received within the Timeout (in - milliseconds) period, @link(LastError) is set to @link(ErrTimeout). - - If @link(ConvertLineEnd) is used, then the CR/LF sequence may not be exactly - CR/LF. See the description of @link(ConvertLineEnd). - - This method serves for line protocol implementation and uses its own - buffers to maximize performance. Therefore do NOT use this method with the - @link(RecvBuffer) method to receive data as it may cause data loss.} - function Recvstring(timeout: integer): AnsiString; virtual; - - {:Waits until four data bytes are received which is returned as the function - integer result. If no data is received within the Timeout (in milliseconds) period, - @link(LastError) is set to @link(ErrTimeout).} - function RecvInteger(Timeout: Integer): Integer; virtual; - - {:Waits until one data block is received. See @link(sendblock). If no data - is received within the Timeout (in milliseconds) period, @link(LastError) - is set to @link(ErrTimeout).} - function RecvBlock(Timeout: Integer): AnsiString; virtual; - - {:Receive all data to stream, until some error occured. (for example timeout)} - procedure RecvStreamRaw(const Stream: TStream; Timeout: Integer); virtual; - - {:receive requested count of bytes to stream} - procedure RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); virtual; - - {:receive block of data to stream. (Data can be sended by @link(sendstream)} - procedure RecvStream(const Stream: TStream; Timeout: Integer); virtual; - - {:receive block of data to stream. (Data can be sended by @link(sendstreamIndy)} - procedure RecvStreamIndy(const Stream: TStream; Timeout: Integer); virtual; - - {:Returns the number of received bytes waiting for reading. 0 is returned - when there is no data waiting.} - function WaitingData: integer; virtual; - - {:Same as @link(WaitingData), but in respect to data in the internal - @link(LineBuffer).} - function WaitingDataEx: integer; virtual; - - {:Returns the number of bytes waiting to be sent in the output buffer. - 0 is returned when the output buffer is empty.} - function SendingData: integer; virtual; - - {:Enable or disable RTS driven communication (half-duplex). It can be used - to communicate with RS485 converters, or other special equipment. If you - enable this feature, the system automatically controls the RTS signal. - - Notes: - - - On Windows NT (or higher) ir RTS signal driven by system driver. - - - On Win9x family is used special code for waiting until last byte is - sended from your UART. - - - On Linux you must have kernel 2.1 or higher!} - procedure EnableRTSToggle(value: boolean); virtual; - - {:Waits until all data to is sent and buffers are emptied. - Warning: On Windows systems is this method returns when all buffers are - flushed to the serial port controller, before the last byte is sent!} - procedure Flush; virtual; - - {:Unconditionally empty all buffers. It is good when you need to interrupt - communication and for cleanups.} - procedure Purge; virtual; - - {:Returns @True, if you can from read any data from the port. Status is - tested for a period of time given by the Timeout parameter (in milliseconds). - If the value of the Timeout parameter is 0, the status is tested only once - and the function returns immediately. If the value of the Timeout parameter - is set to -1, the function returns only after it detects data on the port - (this may cause the process to hang).} - function CanRead(Timeout: integer): boolean; virtual; - - {:Returns @True, if you can write any data to the port (this function is not - sending the contents of the buffer). Status is tested for a period of time - given by the Timeout parameter (in milliseconds). If the value of - the Timeout parameter is 0, the status is tested only once and the function - returns immediately. If the value of the Timeout parameter is set to -1, - the function returns only after it detects that it can write data to - the port (this may cause the process to hang).} - function CanWrite(Timeout: integer): boolean; virtual; - - {:Same as @link(CanRead), but the test is against data in the internal - @link(LineBuffer) too.} - function CanReadEx(Timeout: integer): boolean; virtual; - - {:Returns the status word of the modem. Decoding the status word could yield - the status of carrier detect signaland other signals. This method is used - internally by the modem status reading properties. You usually do not need - to call this method directly.} - function ModemStatus: integer; virtual; - - {:Send a break signal to the communication device for Duration milliseconds.} - procedure SetBreak(Duration: integer); virtual; - - {:This function is designed to send AT commands to the modem. The AT command - is sent in the Value parameter and the response is returned in the function - return value (may contain multiple lines!). - If the AT command is processed successfully (modem returns OK), then the - @link(ATResult) property is set to True. - - This function is designed only for AT commands that return OK or ERROR - response! To call connection commands the @link(ATConnect) method. - Remember, when you connect to a modem device, it is in AT command mode. - Now you can send AT commands to the modem. If you need to transfer data to - the modem on the other side of the line, you must first switch to data mode - using the @link(ATConnect) method.} - function ATCommand(value: AnsiString): AnsiString; virtual; - - {:This function is used to send connect type AT commands to the modem. It is - for commands to switch to connected state. (ATD, ATA, ATO,...) - It sends the AT command in the Value parameter and returns the modem's - response (may be multiple lines - usually with connection parameters info). - If the AT command is processed successfully (the modem returns CONNECT), - then the ATResult property is set to @True. - - This function is designed only for AT commands which respond by CONNECT, - BUSY, NO DIALTONE NO CARRIER or ERROR. For other AT commands use the - @link(ATCommand) method. - - The connect timeout is 90*@link(ATTimeout). If this command is successful - (@link(ATresult) is @true), then the modem is in data state. When you now - send or receive some data, it is not to or from your modem, but from the - modem on other side of the line. Now you can transfer your data. - If the connection attempt failed (@link(ATResult) is @False), then the - modem is still in AT command mode.} - function ATConnect(value: AnsiString): AnsiString; virtual; - - {:If you "manually" call API functions, forward their return code in - the SerialResult parameter to this function, which evaluates it and sets - @link(LastError) and @link(LastErrorDesc).} - function SerialCheck(SerialResult: integer): integer; virtual; - - {:If @link(Lasterror) is not 0 and exceptions are enabled, then this procedure - raises an exception. This method is used internally. You may need it only - in special cases.} - procedure ExceptCheck; virtual; - - {:Set Synaser to error state with ErrNumber code. Usually used by internal - routines.} - procedure SetSynaError(ErrNumber: integer); virtual; - - {:Raise Synaser error with ErrNumber code. Usually used by internal routines.} - procedure RaiseSynaError(ErrNumber: integer); virtual; -{$IFDEF UNIX} - function cpomComportAccessible: boolean; virtual;{HGJ} - procedure cpomReleaseComport; virtual; {HGJ} -{$ENDIF} - {:True device name of currently used port} - property Device: string read FDevice; - - {:Error code of last operation. Value is defined by the host operating - system, but value 0 is always OK.} - property LastError: integer read FLastError; - - {:Human readable description of LastError code.} - property LastErrorDesc: string read FLastErrorDesc; - - {:Indicates if the last @link(ATCommand) or @link(ATConnect) method was successful} - property ATResult: Boolean read FATResult; - - {:Read the value of the RTS signal.} - property RTS: Boolean write SetRTSF; - - {:Indicates the presence of the CTS signal} - property CTS: boolean read GetCTS; - - {:Use this property to set the value of the DTR signal.} - property DTR: Boolean write SetDTRF; - - {:Exposes the status of the DSR signal.} - property DSR: boolean read GetDSR; - - {:Indicates the presence of the Carrier signal} - property Carrier: boolean read GetCarrier; - - {:Reflects the status of the Ring signal.} - property Ring: boolean read GetRing; - - {:indicates if this instance of SynaSer is active. (Connected to some port)} - property InstanceActive: boolean read FInstanceActive; {HGJ} - - {:Defines maximum bandwidth for all sending operations in bytes per second. - If this value is set to 0 (default), bandwidth limitation is not used.} - property MaxSendBandwidth: Integer read FMaxSendBandwidth Write FMaxSendBandwidth; - - {:Defines maximum bandwidth for all receiving operations in bytes per second. - If this value is set to 0 (default), bandwidth limitation is not used.} - property MaxRecvBandwidth: Integer read FMaxRecvBandwidth Write FMaxRecvBandwidth; - - {:Defines maximum bandwidth for all sending and receiving operations - in bytes per second. If this value is set to 0 (default), bandwidth - limitation is not used.} - property MaxBandwidth: Integer Write SetBandwidth; - - {:Size of the Windows internal receive buffer. Default value is usually - 4096 bytes. Note: Valid only in Windows versions!} - property SizeRecvBuffer: integer read FRecvBuffer write SetSizeRecvBuffer; - published - {:Returns the descriptive text associated with ErrorCode. You need this - method only in special cases. Description of LastError is now accessible - through the LastErrorDesc property.} - class function GetErrorDesc(ErrorCode: integer): string; - - {:Freely usable property} - property Tag: integer read FTag write FTag; - - {:Contains the handle of the open communication port. - You may need this value to directly call communication functions outside - SynaSer.} - property Handle: THandle read Fhandle write FHandle; - - {:Internally used read buffer.} - property LineBuffer: AnsiString read FBuffer write FBuffer; - - {:If @true, communication errors raise exceptions. If @false (default), only - the @link(LastError) value is set.} - property RaiseExcept: boolean read FRaiseExcept write FRaiseExcept; - - {:This event is triggered when the communication status changes. It can be - used to monitor communication status.} - property OnStatus: THookSerialStatus read FOnStatus write FOnStatus; - - {:If you set this property to @true, then the value of the DSR signal - is tested before every data transfer. It can be used to detect the presence - of a communications device.} - property TestDSR: boolean read FTestDSR write FTestDSR; - - {:If you set this property to @true, then the value of the CTS signal - is tested before every data transfer. It can be used to detect the presence - of a communications device. Warning: This property cannot be used if you - need hardware handshake!} - property TestCTS: boolean read FTestCTS write FTestCTS; - - {:Use this property you to limit the maximum size of LineBuffer - (as a protection against unlimited memory allocation for LineBuffer). - Default value is 0 - no limit.} - property MaxLineLength: Integer read FMaxLineLength Write FMaxLineLength; - - {:This timeout value is used as deadlock protection when trying to send data - to (or receive data from) a device that stopped communicating during data - transmission (e.g. by physically disconnecting the device). - The timeout value is in milliseconds. The default value is 30,000 (30 seconds).} - property DeadlockTimeout: Integer read FDeadlockTimeout Write FDeadlockTimeout; - - {:If set to @true (default value), port locking is enabled (under Linux only). - WARNING: To use this feature, the application must run by a user with full - permission to the /var/lock directory!} - property LinuxLock: Boolean read FLinuxLock write FLinuxLock; - - {:Indicates if non-standard line terminators should be converted to a CR/LF pair - (standard DOS line terminator). If @TRUE, line terminators CR, single LF - or LF/CR are converted to CR/LF. Defaults to @FALSE. - This property has effect only on the behavior of the RecvString method.} - property ConvertLineEnd: Boolean read FConvertLineEnd Write FConvertLineEnd; - - {:Timeout for AT modem based operations} - property AtTimeout: integer read FAtTimeout Write FAtTimeout; - - {:If @true (default), then all timeouts is timeout between two characters. - If @False, then timeout is overall for whoole reading operation.} - property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout; - end; - -{:Returns list of existing computer serial ports. Working properly only in Windows!} -function GetSerialPortNames: string; - -implementation - -constructor TBlockSerial.Create; -begin - inherited create; - FRaiseExcept := false; - FHandle := INVALID_HANDLE_VALUE; - FDevice := ''; - FComNr:= PortIsClosed; {HGJ} - FInstanceActive:= false; {HGJ} - Fbuffer := ''; - FRTSToggle := False; - FMaxLineLength := 0; - FTestDSR := False; - FTestCTS := False; - FDeadlockTimeout := 30000; - FLinuxLock := True; - FMaxSendBandwidth := 0; - FNextSend := 0; - FMaxRecvBandwidth := 0; - FNextRecv := 0; - FConvertLineEnd := False; - SetSynaError(sOK); - FRecvBuffer := 4096; - FLastCR := False; - FLastLF := False; - FAtTimeout := 1000; - FInterPacketTimeout := True; -end; - -destructor TBlockSerial.Destroy; -begin - CloseSocket; - inherited destroy; -end; - -class function TBlockSerial.GetVersion: string; -begin - Result := 'SynaSer 7.5.4'; -end; - -procedure TBlockSerial.CloseSocket; -begin - if Fhandle <> INVALID_HANDLE_VALUE then - begin - Purge; - RTS := False; - DTR := False; - FileClose(FHandle); - end; - if InstanceActive then - begin - {$IFDEF UNIX} - if FLinuxLock then - cpomReleaseComport; - {$ENDIF} - FInstanceActive:= false - end; - Fhandle := INVALID_HANDLE_VALUE; - FComNr:= PortIsClosed; - SetSynaError(sOK); - DoStatus(HR_SerialClose, FDevice); -end; - -{$IFDEF WIN32} -function TBlockSerial.GetPortAddr: Word; -begin - Result := 0; - if Win32Platform <> VER_PLATFORM_WIN32_NT then - begin - EscapeCommFunction(FHandle, 10); - asm - MOV @Result, DX; - end; - end; -end; - -function TBlockSerial.ReadTxEmpty(PortAddr: Word): Boolean; -begin - Result := True; - if Win32Platform <> VER_PLATFORM_WIN32_NT then - begin - asm - MOV DX, PortAddr; - ADD DX, 5; - IN AL, DX; - AND AL, $40; - JZ @K; - MOV AL,1; - @K: MOV @Result, AL; - end; - end; -end; -{$ENDIF} - -procedure TBlockSerial.GetComNr(Value: string); -begin - FComNr := PortIsClosed; - if pos('COM', uppercase(Value)) = 1 then - FComNr := StrToIntdef(copy(Value, 4, Length(Value) - 3), PortIsClosed + 1) - 1; - if pos('/DEV/TTYS', uppercase(Value)) = 1 then - FComNr := StrToIntdef(copy(Value, 10, Length(Value) - 9), PortIsClosed - 1); -end; - -procedure TBlockSerial.SetBandwidth(Value: Integer); -begin - MaxSendBandwidth := Value; - MaxRecvBandwidth := Value; -end; - -procedure TBlockSerial.LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); -var - x: LongWord; - y: LongWord; -begin - if MaxB > 0 then - begin - y := GetTick; - if Next > y then - begin - x := Next - y; - if x > 0 then - begin - DoStatus(HR_Wait, IntToStr(x)); - sleep(x); - end; - end; - Next := GetTick + Trunc((Length / MaxB) * 1000); - end; -end; - -procedure TBlockSerial.Config(baud, bits: integer; parity: char; stop: integer; - softflow, hardflow: boolean); -begin - FillChar(dcb, SizeOf(dcb), 0); - GetCommState; - dcb.DCBlength := SizeOf(dcb); - dcb.BaudRate := baud; - dcb.ByteSize := bits; - case parity of - 'N', 'n': dcb.parity := 0; - 'O', 'o': dcb.parity := 1; - 'E', 'e': dcb.parity := 2; - 'M', 'm': dcb.parity := 3; - 'S', 's': dcb.parity := 4; - end; - dcb.StopBits := stop; - dcb.XonChar := #17; - dcb.XoffChar := #19; - dcb.XonLim := FRecvBuffer div 4; - dcb.XoffLim := FRecvBuffer div 4; - dcb.Flags := dcb_Binary; - if softflow then - dcb.Flags := dcb.Flags or dcb_OutX or dcb_InX; - if hardflow then - dcb.Flags := dcb.Flags or dcb_OutxCtsFlow or dcb_RtsControlHandshake - else - dcb.Flags := dcb.Flags or dcb_RtsControlEnable; - dcb.Flags := dcb.Flags or dcb_DtrControlEnable; - if dcb.Parity > 0 then - dcb.Flags := dcb.Flags or dcb_ParityCheck; - SetCommState; -end; - -procedure TBlockSerial.Connect(comport: string); -{$IFDEF MSWINDOWS} -var - CommTimeouts: TCommTimeouts; -{$ENDIF} -begin - // Is this TBlockSerial Instance already busy? - if InstanceActive then {HGJ} - begin {HGJ} - RaiseSynaError(ErrAlreadyInUse); - Exit; {HGJ} - end; {HGJ} - FBuffer := ''; - FDevice := comport; - GetComNr(comport); -{$IFDEF MSWINDOWS} - SetLastError (sOK); -{$ELSE} - {$IFNDEF FPC} - SetLastError (sOK); - {$ELSE} - fpSetErrno(sOK); - {$ENDIF} -{$ENDIF} -{$IFNDEF MSWINDOWS} - if FComNr <> PortIsClosed then - FDevice := '/dev/ttyS' + IntToStr(FComNr); - // Comport already owned by another process? {HGJ} - if FLinuxLock then - if not cpomComportAccessible then - begin - RaiseSynaError(ErrAlreadyOwned); - Exit; - end; -{$IFNDEF FPC} - FHandle := THandle(Libc.open(pchar(FDevice), O_RDWR or O_SYNC)); -{$ELSE} - FHandle := THandle(fpOpen(FDevice, O_RDWR or O_SYNC)); -{$ENDIF} - if FHandle = INVALID_HANDLE_VALUE then //because THandle is not integer on all platforms! - SerialCheck(-1) - else - SerialCheck(0); - {$IFDEF UNIX} - if FLastError <> sOK then - if FLinuxLock then - cpomReleaseComport; - {$ENDIF} - ExceptCheck; - if FLastError <> sOK then - Exit; -{$ELSE} - if FComNr <> PortIsClosed then - FDevice := '\\.\COM' + IntToStr(FComNr + 1); - FHandle := THandle(CreateFile(PChar(FDevice), GENERIC_READ or GENERIC_WRITE, - 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0)); - if FHandle = INVALID_HANDLE_VALUE then //because THandle is not integer on all platforms! - SerialCheck(-1) - else - SerialCheck(0); - ExceptCheck; - if FLastError <> sOK then - Exit; - SetCommMask(FHandle, 0); - SetupComm(Fhandle, FRecvBuffer, 0); - CommTimeOuts.ReadIntervalTimeout := MAXWORD; - CommTimeOuts.ReadTotalTimeoutMultiplier := 0; - CommTimeOuts.ReadTotalTimeoutConstant := 0; - CommTimeOuts.WriteTotalTimeoutMultiplier := 0; - CommTimeOuts.WriteTotalTimeoutConstant := 0; - SetCommTimeOuts(FHandle, CommTimeOuts); - {$IFDEF WIN32} - FPortAddr := GetPortAddr; - {$ENDIF} -{$ENDIF} - SetSynaError(sOK); - if not TestCtrlLine then {HGJ} - begin - SetSynaError(ErrNoDeviceAnswer); - FileClose(FHandle); {HGJ} - {$IFDEF UNIX} - if FLinuxLock then - cpomReleaseComport; {HGJ} - {$ENDIF} {HGJ} - Fhandle := INVALID_HANDLE_VALUE; {HGJ} - FComNr:= PortIsClosed; {HGJ} - end - else - begin - FInstanceActive:= True; - RTS := True; - DTR := True; - Purge; - end; - ExceptCheck; - DoStatus(HR_Connect, FDevice); -end; - -function TBlockSerial.SendBuffer(buffer: pointer; length: integer): integer; -{$IFDEF MSWINDOWS} -var - Overlapped: TOverlapped; - x, y, Err: DWord; -{$ENDIF} -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - LimitBandwidth(Length, FMaxSendBandwidth, FNextsend); - if FRTSToggle then - begin - Flush; - RTS := True; - end; -{$IFNDEF MSWINDOWS} - result := FileWrite(Fhandle, Buffer^, Length); - serialcheck(result); -{$ELSE} - FillChar(Overlapped, Sizeof(Overlapped), 0); - SetSynaError(sOK); - y := 0; - if not WriteFile(FHandle, Buffer^, Length, DWord(Result), @Overlapped) then - y := GetLastError; - if y = ERROR_IO_PENDING then - begin - x := WaitForSingleObject(FHandle, FDeadlockTimeout); - if x = WAIT_TIMEOUT then - begin - PurgeComm(FHandle, PURGE_TXABORT); - SetSynaError(ErrTimeout); - end; - GetOverlappedResult(FHandle, Overlapped, Dword(Result), False); - end - else - SetSynaError(y); - ClearCommError(FHandle, err, nil); - if err <> 0 then - DecodeCommError(err); -{$ENDIF} - if FRTSToggle then - begin - Flush; - CanWrite(255); - RTS := False; - end; - ExceptCheck; - DoStatus(HR_WriteCount, IntToStr(Result)); -end; - -procedure TBlockSerial.SendByte(data: byte); -begin - SendBuffer(@Data, 1); -end; - -procedure TBlockSerial.SendString(data: AnsiString); -begin - SendBuffer(Pointer(Data), Length(Data)); -end; - -procedure TBlockSerial.SendInteger(Data: integer); -begin - SendBuffer(@data, SizeOf(Data)); -end; - -procedure TBlockSerial.SendBlock(const Data: AnsiString); -begin - SendInteger(Length(data)); - SendString(Data); -end; - -procedure TBlockSerial.SendStreamRaw(const Stream: TStream); -var - si: integer; - x, y, yr: integer; - s: AnsiString; -begin - si := Stream.Size - Stream.Position; - x := 0; - while x < si do - begin - y := si - x; - if y > cSerialChunk then - y := cSerialChunk; - Setlength(s, y); - yr := Stream.read(PAnsiChar(s)^, y); - if yr > 0 then - begin - SetLength(s, yr); - SendString(s); - Inc(x, yr); - end - else - break; - end; -end; - -procedure TBlockSerial.SendStreamIndy(const Stream: TStream); -var - si: integer; -begin - si := Stream.Size - Stream.Position; - si := Swapbytes(si); - SendInteger(si); - SendStreamRaw(Stream); -end; - -procedure TBlockSerial.SendStream(const Stream: TStream); -var - si: integer; -begin - si := Stream.Size - Stream.Position; - SendInteger(si); - SendStreamRaw(Stream); -end; - -function TBlockSerial.RecvBuffer(buffer: pointer; length: integer): integer; -{$IFNDEF MSWINDOWS} -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); - result := FileRead(FHandle, Buffer^, length); - serialcheck(result); -{$ELSE} -var - Overlapped: TOverlapped; - x, y, Err: DWord; -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); - FillChar(Overlapped, Sizeof(Overlapped), 0); - SetSynaError(sOK); - y := 0; - if not ReadFile(FHandle, Buffer^, length, Dword(Result), @Overlapped) then - y := GetLastError; - if y = ERROR_IO_PENDING then - begin - x := WaitForSingleObject(FHandle, FDeadlockTimeout); - if x = WAIT_TIMEOUT then - begin - PurgeComm(FHandle, PURGE_RXABORT); - SetSynaError(ErrTimeout); - end; - GetOverlappedResult(FHandle, Overlapped, Dword(Result), False); - end - else - SetSynaError(y); - ClearCommError(FHandle, err, nil); - if err <> 0 then - DecodeCommError(err); -{$ENDIF} - ExceptCheck; - DoStatus(HR_ReadCount, IntToStr(Result)); -end; - -function TBlockSerial.RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; -var - s: AnsiString; - rl, l: integer; - ti: LongWord; -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - rl := 0; - repeat - ti := GetTick; - s := RecvPacket(Timeout); - l := System.Length(s); - if (rl + l) > Length then - l := Length - rl; - Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); - rl := rl + l; - if FLastError <> sOK then - Break; - if rl >= Length then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - SetSynaError(ErrTimeout); - Break; - end; - end; - until False; - delete(s, 1, l); - FBuffer := s; - Result := rl; -end; - -function TBlockSerial.RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - if Length > 0 then - begin - Setlength(Result, Length); - x := RecvBufferEx(PAnsiChar(Result), Length , Timeout); - if FLastError = sOK then - SetLength(Result, x) - else - Result := ''; - end; -end; - -function TBlockSerial.RecvPacket(Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - if FBuffer <> '' then - begin - Result := FBuffer; - FBuffer := ''; - end - else - begin - //not drain CPU on large downloads... - Sleep(0); - x := WaitingData; - if x > 0 then - begin - SetLength(Result, x); - x := RecvBuffer(Pointer(Result), x); - if x >= 0 then - SetLength(Result, x); - end - else - begin - if CanRead(Timeout) then - begin - x := WaitingData; - if x = 0 then - SetSynaError(ErrTimeout); - if x > 0 then - begin - SetLength(Result, x); - x := RecvBuffer(Pointer(Result), x); - if x >= 0 then - SetLength(Result, x); - end; - end - else - SetSynaError(ErrTimeout); - end; - end; - ExceptCheck; -end; - - -function TBlockSerial.RecvByte(timeout: integer): byte; -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - if FBuffer = '' then - FBuffer := RecvPacket(Timeout); - if (FLastError = sOK) and (FBuffer <> '') then - begin - Result := Ord(FBuffer[1]); - System.Delete(FBuffer, 1, 1); - end; - ExceptCheck; -end; - -function TBlockSerial.RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; -var - x: Integer; - s: AnsiString; - l: Integer; - CorCRLF: Boolean; - t: ansistring; - tl: integer; - ti: LongWord; -begin - Result := ''; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - l := system.Length(Terminator); - if l = 0 then - Exit; - tl := l; - CorCRLF := FConvertLineEnd and (Terminator = CRLF); - s := ''; - x := 0; - repeat - ti := GetTick; - //get rest of FBuffer or incomming new data... - s := s + RecvPacket(Timeout); - if FLastError <> sOK then - Break; - x := 0; - if Length(s) > 0 then - if CorCRLF then - begin - if FLastCR and (s[1] = LF) then - Delete(s, 1, 1); - if FLastLF and (s[1] = CR) then - Delete(s, 1, 1); - FLastCR := False; - FLastLF := False; - t := ''; - x := PosCRLF(s, t); - tl := system.Length(t); - if t = CR then - FLastCR := True; - if t = LF then - FLastLF := True; - end - else - begin - x := pos(Terminator, s); - tl := l; - end; - if (FMaxLineLength <> 0) and (system.Length(s) > FMaxLineLength) then - begin - SetSynaError(ErrMaxBuffer); - Break; - end; - if x > 0 then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - SetSynaError(ErrTimeout); - Break; - end; - end; - until False; - if x > 0 then - begin - Result := Copy(s, 1, x - 1); - System.Delete(s, 1, x + tl - 1); - end; - FBuffer := s; - ExceptCheck; -end; - - -function TBlockSerial.RecvString(Timeout: Integer): AnsiString; -var - s: AnsiString; -begin - Result := ''; - s := RecvTerminated(Timeout, #13 + #10); - if FLastError = sOK then - Result := s; -end; - -function TBlockSerial.RecvInteger(Timeout: Integer): Integer; -var - s: AnsiString; -begin - Result := 0; - s := RecvBufferStr(4, Timeout); - if FLastError = 0 then - Result := (ord(s[1]) + ord(s[2]) * 256) + (ord(s[3]) + ord(s[4]) * 256) * 65536; -end; - -function TBlockSerial.RecvBlock(Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - x := RecvInteger(Timeout); - if FLastError = 0 then - Result := RecvBufferStr(x, Timeout); -end; - -procedure TBlockSerial.RecvStreamRaw(const Stream: TStream; Timeout: Integer); -var - s: AnsiString; -begin - repeat - s := RecvPacket(Timeout); - if FLastError = 0 then - WriteStrToStream(Stream, s); - until FLastError <> 0; -end; - -procedure TBlockSerial.RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); -var - s: AnsiString; - n: integer; -begin - for n := 1 to (Size div cSerialChunk) do - begin - s := RecvBufferStr(cSerialChunk, Timeout); - if FLastError <> 0 then - Exit; - Stream.Write(PAnsichar(s)^, cSerialChunk); - end; - n := Size mod cSerialChunk; - if n > 0 then - begin - s := RecvBufferStr(n, Timeout); - if FLastError <> 0 then - Exit; - Stream.Write(PAnsichar(s)^, n); - end; -end; - -procedure TBlockSerial.RecvStreamIndy(const Stream: TStream; Timeout: Integer); -var - x: integer; -begin - x := RecvInteger(Timeout); - x := SwapBytes(x); - if FLastError = 0 then - RecvStreamSize(Stream, Timeout, x); -end; - -procedure TBlockSerial.RecvStream(const Stream: TStream; Timeout: Integer); -var - x: integer; -begin - x := RecvInteger(Timeout); - if FLastError = 0 then - RecvStreamSize(Stream, Timeout, x); -end; - -{$IFNDEF MSWINDOWS} -function TBlockSerial.WaitingData: integer; -begin -{$IFNDEF FPC} - serialcheck(ioctl(FHandle, FIONREAD, @result)); -{$ELSE} - serialcheck(fpIoctl(FHandle, FIONREAD, @result)); -{$ENDIF} - if FLastError <> 0 then - Result := 0; - ExceptCheck; -end; -{$ELSE} -function TBlockSerial.WaitingData: integer; -var - stat: TComStat; - err: DWORD; -begin - if ClearCommError(FHandle, err, @stat) then - begin - SetSynaError(sOK); - Result := stat.cbInQue; - end - else - begin - SerialCheck(sErr); - Result := 0; - end; - ExceptCheck; -end; -{$ENDIF} - -function TBlockSerial.WaitingDataEx: integer; -begin - if FBuffer <> '' then - Result := Length(FBuffer) - else - Result := Waitingdata; -end; - -{$IFNDEF MSWINDOWS} -function TBlockSerial.SendingData: integer; -begin - SetSynaError(sOK); - Result := 0; -end; -{$ELSE} -function TBlockSerial.SendingData: integer; -var - stat: TComStat; - err: DWORD; -begin - SetSynaError(sOK); - if not ClearCommError(FHandle, err, @stat) then - serialcheck(sErr); - ExceptCheck; - result := stat.cbOutQue; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.DcbToTermios(const dcb: TDCB; var term: termios); -var - n: integer; - x: cardinal; -begin - //others - cfmakeraw(term); - term.c_cflag := term.c_cflag or CREAD; - term.c_cflag := term.c_cflag or CLOCAL; - term.c_cflag := term.c_cflag or HUPCL; - //hardware handshake - if (dcb.flags and dcb_RtsControlHandshake) > 0 then - term.c_cflag := term.c_cflag or CRTSCTS - else - term.c_cflag := term.c_cflag and (not CRTSCTS); - //software handshake - if (dcb.flags and dcb_OutX) > 0 then - term.c_iflag := term.c_iflag or IXON or IXOFF or IXANY - else - term.c_iflag := term.c_iflag and (not (IXON or IXOFF or IXANY)); - //size of byte - term.c_cflag := term.c_cflag and (not CSIZE); - case dcb.bytesize of - 5: - term.c_cflag := term.c_cflag or CS5; - 6: - term.c_cflag := term.c_cflag or CS6; - 7: -{$IFDEF FPC} - term.c_cflag := term.c_cflag or CS7; -{$ELSE} - term.c_cflag := term.c_cflag or CS7fix; -{$ENDIF} - 8: - term.c_cflag := term.c_cflag or CS8; - end; - //parity - if (dcb.flags and dcb_ParityCheck) > 0 then - term.c_cflag := term.c_cflag or PARENB - else - term.c_cflag := term.c_cflag and (not PARENB); - case dcb.parity of - 1: //'O' - term.c_cflag := term.c_cflag or PARODD; - 2: //'E' - term.c_cflag := term.c_cflag and (not PARODD); - end; - //stop bits - if dcb.stopbits > 0 then - term.c_cflag := term.c_cflag or CSTOPB - else - term.c_cflag := term.c_cflag and (not CSTOPB); - //set baudrate; - x := 0; - for n := 0 to Maxrates do - if rates[n, 0] = dcb.BaudRate then - begin - x := rates[n, 1]; - break; - end; - cfsetospeed(term, x); - cfsetispeed(term, x); -end; - -procedure TBlockSerial.TermiosToDcb(const term: termios; var dcb: TDCB); -var - n: integer; - x: cardinal; -begin - //set baudrate; - dcb.baudrate := 0; - {$IFDEF FPC} - //why FPC not have cfgetospeed??? - x := term.c_oflag and $0F; - {$ELSE} - x := cfgetospeed(term); - {$ENDIF} - for n := 0 to Maxrates do - if rates[n, 1] = x then - begin - dcb.baudrate := rates[n, 0]; - break; - end; - //hardware handshake - if (term.c_cflag and CRTSCTS) > 0 then - dcb.flags := dcb.flags or dcb_RtsControlHandshake or dcb_OutxCtsFlow - else - dcb.flags := dcb.flags and (not (dcb_RtsControlHandshake or dcb_OutxCtsFlow)); - //software handshake - if (term.c_cflag and IXOFF) > 0 then - dcb.flags := dcb.flags or dcb_OutX or dcb_InX - else - dcb.flags := dcb.flags and (not (dcb_OutX or dcb_InX)); - //size of byte - case term.c_cflag and CSIZE of - CS5: - dcb.bytesize := 5; - CS6: - dcb.bytesize := 6; - CS7fix: - dcb.bytesize := 7; - CS8: - dcb.bytesize := 8; - end; - //parity - if (term.c_cflag and PARENB) > 0 then - dcb.flags := dcb.flags or dcb_ParityCheck - else - dcb.flags := dcb.flags and (not dcb_ParityCheck); - dcb.parity := 0; - if (term.c_cflag and PARODD) > 0 then - dcb.parity := 1 - else - dcb.parity := 2; - //stop bits - if (term.c_cflag and CSTOPB) > 0 then - dcb.stopbits := 2 - else - dcb.stopbits := 0; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.SetCommState; -begin - DcbToTermios(dcb, termiosstruc); - SerialCheck(tcsetattr(FHandle, TCSANOW, termiosstruc)); - ExceptCheck; -end; -{$ELSE} -procedure TBlockSerial.SetCommState; -begin - SetSynaError(sOK); - if not windows.SetCommState(Fhandle, dcb) then - SerialCheck(sErr); - ExceptCheck; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.GetCommState; -begin - SerialCheck(tcgetattr(FHandle, termiosstruc)); - ExceptCheck; - TermiostoDCB(termiosstruc, dcb); -end; -{$ELSE} -procedure TBlockSerial.GetCommState; -begin - SetSynaError(sOK); - if not windows.GetCommState(Fhandle, dcb) then - SerialCheck(sErr); - ExceptCheck; -end; -{$ENDIF} - -procedure TBlockSerial.SetSizeRecvBuffer(size: integer); -begin -{$IFDEF MSWINDOWS} - SetupComm(Fhandle, size, 0); - GetCommState; - dcb.XonLim := size div 4; - dcb.XoffLim := size div 4; - SetCommState; -{$ENDIF} - FRecvBuffer := size; -end; - -function TBlockSerial.GetDSR: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_DSR) > 0; -{$ELSE} - Result := (FModemWord and MS_DSR_ON) > 0; -{$ENDIF} -end; - -procedure TBlockSerial.SetDTRF(Value: Boolean); -begin -{$IFNDEF MSWINDOWS} - ModemStatus; - if Value then - FModemWord := FModemWord or TIOCM_DTR - else - FModemWord := FModemWord and not TIOCM_DTR; - {$IFNDEF FPC} - ioctl(FHandle, TIOCMSET, @FModemWord); - {$ELSE} - fpioctl(FHandle, TIOCMSET, @FModemWord); - {$ENDIF} -{$ELSE} - if Value then - EscapeCommFunction(FHandle, SETDTR) - else - EscapeCommFunction(FHandle, CLRDTR); -{$ENDIF} -end; - -function TBlockSerial.GetCTS: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_CTS) > 0; -{$ELSE} - Result := (FModemWord and MS_CTS_ON) > 0; -{$ENDIF} -end; - -procedure TBlockSerial.SetRTSF(Value: Boolean); -begin -{$IFNDEF MSWINDOWS} - ModemStatus; - if Value then - FModemWord := FModemWord or TIOCM_RTS - else - FModemWord := FModemWord and not TIOCM_RTS; - {$IFNDEF FPC} - ioctl(FHandle, TIOCMSET, @FModemWord); - {$ELSE} - fpioctl(FHandle, TIOCMSET, @FModemWord); - {$ENDIF} -{$ELSE} - if Value then - EscapeCommFunction(FHandle, SETRTS) - else - EscapeCommFunction(FHandle, CLRRTS); -{$ENDIF} -end; - -function TBlockSerial.GetCarrier: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_CAR) > 0; -{$ELSE} - Result := (FModemWord and MS_RLSD_ON) > 0; -{$ENDIF} -end; - -function TBlockSerial.GetRing: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_RNG) > 0; -{$ELSE} - Result := (FModemWord and MS_RING_ON) > 0; -{$ENDIF} -end; - -{$IFDEF MSWINDOWS} -function TBlockSerial.CanEvent(Event: dword; Timeout: integer): boolean; -var - ex: DWord; - y: Integer; - Overlapped: TOverlapped; -begin - FillChar(Overlapped, Sizeof(Overlapped), 0); - Overlapped.hEvent := CreateEvent(nil, True, False, nil); - try - SetCommMask(FHandle, Event); - SetSynaError(sOK); - if (Event = EV_RXCHAR) and (Waitingdata > 0) then - Result := True - else - begin - y := 0; - if not WaitCommEvent(FHandle, ex, @Overlapped) then - y := GetLastError; - if y = ERROR_IO_PENDING then - begin - //timedout - WaitForSingleObject(Overlapped.hEvent, Timeout); - SetCommMask(FHandle, 0); - GetOverlappedResult(FHandle, Overlapped, DWord(y), True); - end; - Result := (ex and Event) = Event; - end; - finally - SetCommMask(FHandle, 0); - CloseHandle(Overlapped.hEvent); - end; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -function TBlockSerial.CanRead(Timeout: integer): boolean; -var - FDSet: TFDSet; - TimeVal: PTimeVal; - TimeV: TTimeVal; - x: Integer; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - {$IFNDEF FPC} - FD_ZERO(FDSet); - FD_SET(FHandle, FDSet); - x := Select(FHandle + 1, @FDSet, nil, nil, TimeVal); - {$ELSE} - fpFD_ZERO(FDSet); - fpFD_SET(FHandle, FDSet); - x := fpSelect(FHandle + 1, @FDSet, nil, nil, TimeVal); - {$ENDIF} - SerialCheck(x); - if FLastError <> sOK then - x := 0; - Result := x > 0; - ExceptCheck; - if Result then - DoStatus(HR_CanRead, ''); -end; -{$ELSE} -function TBlockSerial.CanRead(Timeout: integer): boolean; -begin - Result := WaitingData > 0; - if not Result then - Result := CanEvent(EV_RXCHAR, Timeout) or (WaitingData > 0); - //check WaitingData again due some broken virtual ports - if Result then - DoStatus(HR_CanRead, ''); -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -function TBlockSerial.CanWrite(Timeout: integer): boolean; -var - FDSet: TFDSet; - TimeVal: PTimeVal; - TimeV: TTimeVal; - x: Integer; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - {$IFNDEF FPC} - FD_ZERO(FDSet); - FD_SET(FHandle, FDSet); - x := Select(FHandle + 1, nil, @FDSet, nil, TimeVal); - {$ELSE} - fpFD_ZERO(FDSet); - fpFD_SET(FHandle, FDSet); - x := fpSelect(FHandle + 1, nil, @FDSet, nil, TimeVal); - {$ENDIF} - SerialCheck(x); - if FLastError <> sOK then - x := 0; - Result := x > 0; - ExceptCheck; - if Result then - DoStatus(HR_CanWrite, ''); -end; -{$ELSE} -function TBlockSerial.CanWrite(Timeout: integer): boolean; -var - t: LongWord; -begin - Result := SendingData = 0; - if not Result then - Result := CanEvent(EV_TXEMPTY, Timeout); - {$IFDEF WIN32} - if Result and (Win32Platform <> VER_PLATFORM_WIN32_NT) then - begin - t := GetTick; - while not ReadTxEmpty(FPortAddr) do - begin - if TickDelta(t, GetTick) > 255 then - Break; - Sleep(0); - end; - end; - {$ENDIF} - if Result then - DoStatus(HR_CanWrite, ''); -end; -{$ENDIF} - -function TBlockSerial.CanReadEx(Timeout: integer): boolean; -begin - if Fbuffer <> '' then - Result := True - else - Result := CanRead(Timeout); -end; - -procedure TBlockSerial.EnableRTSToggle(Value: boolean); -begin - SetSynaError(sOK); -{$IFNDEF MSWINDOWS} - FRTSToggle := Value; - if Value then - RTS:=False; -{$ELSE} - if Win32Platform = VER_PLATFORM_WIN32_NT then - begin - GetCommState; - if value then - dcb.Flags := dcb.Flags or dcb_RtsControlToggle - else - dcb.flags := dcb.flags and (not dcb_RtsControlToggle); - SetCommState; - end - else - begin - FRTSToggle := Value; - if Value then - RTS:=False; - end; -{$ENDIF} -end; - -procedure TBlockSerial.Flush; -begin -{$IFNDEF MSWINDOWS} - SerialCheck(tcdrain(FHandle)); -{$ELSE} - SetSynaError(sOK); - if not Flushfilebuffers(FHandle) then - SerialCheck(sErr); -{$ENDIF} - ExceptCheck; -end; - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.Purge; -begin - {$IFNDEF FPC} - SerialCheck(ioctl(FHandle, TCFLSH, TCIOFLUSH)); - {$ELSE} - {$IFDEF DARWIN} - SerialCheck(fpioctl(FHandle, TCIOflush, Pointer(TCIOFLUSH))); - {$ELSE} - SerialCheck(fpioctl(FHandle, {$IFDEF FreeBSD}TCIOFLUSH{$ELSE}TCFLSH{$ENDIF}, Pointer(PtrInt(TCIOFLUSH)))); - {$ENDIF} - {$ENDIF} - FBuffer := ''; - ExceptCheck; -end; -{$ELSE} -procedure TBlockSerial.Purge; -var - x: integer; -begin - SetSynaError(sOK); - x := PURGE_TXABORT or PURGE_TXCLEAR or PURGE_RXABORT or PURGE_RXCLEAR; - if not PurgeComm(FHandle, x) then - SerialCheck(sErr); - FBuffer := ''; - ExceptCheck; -end; -{$ENDIF} - -function TBlockSerial.ModemStatus: integer; -begin - Result := 0; -{$IFNDEF MSWINDOWS} - {$IFNDEF FPC} - SerialCheck(ioctl(FHandle, TIOCMGET, @Result)); - {$ELSE} - SerialCheck(fpioctl(FHandle, TIOCMGET, @Result)); - {$ENDIF} -{$ELSE} - SetSynaError(sOK); - if not GetCommModemStatus(FHandle, dword(Result)) then - SerialCheck(sErr); -{$ENDIF} - ExceptCheck; - FModemWord := Result; -end; - -procedure TBlockSerial.SetBreak(Duration: integer); -begin -{$IFNDEF MSWINDOWS} - SerialCheck(tcsendbreak(FHandle, Duration)); -{$ELSE} - SetCommBreak(FHandle); - Sleep(Duration); - SetSynaError(sOK); - if not ClearCommBreak(FHandle) then - SerialCheck(sErr); -{$ENDIF} -end; - -{$IFDEF MSWINDOWS} -procedure TBlockSerial.DecodeCommError(Error: DWord); -begin - if (Error and DWord(CE_FRAME)) > 1 then - FLastError := ErrFrame; - if (Error and DWord(CE_OVERRUN)) > 1 then - FLastError := ErrOverrun; - if (Error and DWord(CE_RXOVER)) > 1 then - FLastError := ErrRxOver; - if (Error and DWord(CE_RXPARITY)) > 1 then - FLastError := ErrRxParity; - if (Error and DWord(CE_TXFULL)) > 1 then - FLastError := ErrTxFull; -end; -{$ENDIF} - -//HGJ -function TBlockSerial.PreTestFailing: Boolean; -begin - if not FInstanceActive then - begin - RaiseSynaError(ErrPortNotOpen); - result:= true; - Exit; - end; - Result := not TestCtrlLine; - if result then - RaiseSynaError(ErrNoDeviceAnswer) -end; - -function TBlockSerial.TestCtrlLine: Boolean; -begin - result := ((not FTestDSR) or DSR) and ((not FTestCTS) or CTS); -end; - -function TBlockSerial.ATCommand(value: AnsiString): AnsiString; -var - s: AnsiString; - ConvSave: Boolean; -begin - result := ''; - FAtResult := False; - ConvSave := FConvertLineEnd; - try - FConvertLineEnd := True; - SendString(value + #$0D); - repeat - s := RecvString(FAtTimeout); - if s <> Value then - result := result + s + CRLF; - if s = 'OK' then - begin - FAtResult := True; - break; - end; - if s = 'ERROR' then - break; - until FLastError <> sOK; - finally - FConvertLineEnd := Convsave; - end; -end; - - -function TBlockSerial.ATConnect(value: AnsiString): AnsiString; -var - s: AnsiString; - ConvSave: Boolean; -begin - result := ''; - FAtResult := False; - ConvSave := FConvertLineEnd; - try - FConvertLineEnd := True; - SendString(value + #$0D); - repeat - s := RecvString(90 * FAtTimeout); - if s <> Value then - result := result + s + CRLF; - if s = 'NO CARRIER' then - break; - if s = 'ERROR' then - break; - if s = 'BUSY' then - break; - if s = 'NO DIALTONE' then - break; - if Pos('CONNECT', s) = 1 then - begin - FAtResult := True; - break; - end; - until FLastError <> sOK; - finally - FConvertLineEnd := Convsave; - end; -end; - -function TBlockSerial.SerialCheck(SerialResult: integer): integer; -begin - if SerialResult = integer(INVALID_HANDLE_VALUE) then -{$IFDEF MSWINDOWS} - result := GetLastError -{$ELSE} - {$IFNDEF FPC} - result := GetLastError - {$ELSE} - result := fpGetErrno - {$ENDIF} -{$ENDIF} - else - result := sOK; - FLastError := result; - FLastErrorDesc := GetErrorDesc(FLastError); -end; - -procedure TBlockSerial.ExceptCheck; -var - e: ESynaSerError; - s: string; -begin - if FRaiseExcept and (FLastError <> sOK) then - begin - s := GetErrorDesc(FLastError); - e := ESynaSerError.CreateFmt('Communication error %d: %s', [FLastError, s]); - e.ErrorCode := FLastError; - e.ErrorMessage := s; - raise e; - end; -end; - -procedure TBlockSerial.SetSynaError(ErrNumber: integer); -begin - FLastError := ErrNumber; - FLastErrorDesc := GetErrorDesc(FLastError); -end; - -procedure TBlockSerial.RaiseSynaError(ErrNumber: integer); -begin - SetSynaError(ErrNumber); - ExceptCheck; -end; - -procedure TBlockSerial.DoStatus(Reason: THookSerialReason; const Value: string); -begin - if assigned(OnStatus) then - OnStatus(Self, Reason, Value); -end; - -{======================================================================} - -class function TBlockSerial.GetErrorDesc(ErrorCode: integer): string; -begin - Result:= ''; - case ErrorCode of - sOK: Result := 'OK'; - ErrAlreadyOwned: Result := 'Port owned by other process';{HGJ} - ErrAlreadyInUse: Result := 'Instance already in use'; {HGJ} - ErrWrongParameter: Result := 'Wrong parameter at call'; {HGJ} - ErrPortNotOpen: Result := 'Instance not yet connected'; {HGJ} - ErrNoDeviceAnswer: Result := 'No device answer detected'; {HGJ} - ErrMaxBuffer: Result := 'Maximal buffer length exceeded'; - ErrTimeout: Result := 'Timeout during operation'; - ErrNotRead: Result := 'Reading of data failed'; - ErrFrame: Result := 'Receive framing error'; - ErrOverrun: Result := 'Receive Overrun Error'; - ErrRxOver: Result := 'Receive Queue overflow'; - ErrRxParity: Result := 'Receive Parity Error'; - ErrTxFull: Result := 'Tranceive Queue is full'; - end; - if Result = '' then - begin - Result := SysErrorMessage(ErrorCode); - end; -end; - - -{---------- cpom Comport Ownership Manager Routines ------------- - by Hans-Georg Joepgen of Stuttgart, Germany. - Copyright (c) 2002, by Hans-Georg Joepgen - - Stefan Krauss of Stuttgart, Germany, contributed literature and Internet - research results, invaluable advice and excellent answers to the Comport - Ownership Manager. -} - -{$IFDEF UNIX} - -function TBlockSerial.LockfileName: String; -var - s: string; -begin - s := SeparateRight(FDevice, '/dev/'); - result := LockfileDirectory + '/LCK..' + s; -end; - -procedure TBlockSerial.CreateLockfile(PidNr: integer); -var - f: TextFile; - s: string; -begin - // Create content for file - s := IntToStr(PidNr); - while length(s) < 10 do - s := ' ' + s; - // Create file - try - AssignFile(f, LockfileName); - try - Rewrite(f); - writeln(f, s); - finally - CloseFile(f); - end; - // Allow all users to enjoy the benefits of cpom - s := 'chmod a+rw ' + LockfileName; -{$IFNDEF FPC} - FileSetReadOnly( LockfileName, False ) ; - // Libc.system(pchar(s)); -{$ELSE} - fpSystem(s); -{$ENDIF} - except - // not raise exception, if you not have write permission for lock. - on Exception do - ; - end; -end; - -function TBlockSerial.ReadLockfile: integer; -{Returns PID from Lockfile. Lockfile must exist.} -var - f: TextFile; - s: string; -begin - AssignFile(f, LockfileName); - Reset(f); - try - readln(f, s); - finally - CloseFile(f); - end; - Result := StrToIntDef(s, -1) -end; - -function TBlockSerial.cpomComportAccessible: boolean; -var - MyPid: integer; - Filename: string; -begin - Filename := LockfileName; - {$IFNDEF FPC} - MyPid := Libc.getpid; - {$ELSE} - MyPid := fpGetPid; - {$ENDIF} - // Make sure, the Lock Files Directory exists. We need it. - if not DirectoryExists(LockfileDirectory) then - CreateDir(LockfileDirectory); - // Check the Lockfile - if not FileExists (Filename) then - begin // comport is not locked. Lock it for us. - CreateLockfile(MyPid); - result := true; - exit; // done. - end; - // Is port owned by orphan? Then it's time for error recovery. - //FPC forgot to add getsid.. :-( - {$IFNDEF FPC} - if Libc.getsid(ReadLockfile) = -1 then - begin // Lockfile was left from former desaster - DeleteFile(Filename); // error recovery - CreateLockfile(MyPid); - result := true; - exit; - end; - {$ENDIF} - result := false // Sorry, port is owned by living PID and locked -end; - -procedure TBlockSerial.cpomReleaseComport; -begin - DeleteFile(LockfileName); -end; - -{$ENDIF} -{----------------------------------------------------------------} - -{$IFDEF MSWINDOWS} -function GetSerialPortNames: string; -var - reg: TRegistry; - l, v: TStringList; - n: integer; -begin - l := TStringList.Create; - v := TStringList.Create; - reg := TRegistry.Create; - try -{$IFNDEF VER100} -{$IFNDEF VER120} - reg.Access := KEY_READ; -{$ENDIF} -{$ENDIF} - reg.RootKey := HKEY_LOCAL_MACHINE; - reg.OpenKey('\HARDWARE\DEVICEMAP\SERIALCOMM', false); - reg.GetValueNames(l); - for n := 0 to l.Count - 1 do - v.Add(reg.ReadString(l[n])); - Result := v.CommaText; - finally - reg.Free; - l.Free; - v.Free; - end; -end; -{$ENDIF} -{$IFNDEF MSWINDOWS} -function GetSerialPortNames: string; -var - sr : TSearchRec; -begin - Result := ''; - if FindFirst('/dev/ttyS*', $FFFFFFFF, sr) = 0 then - begin - repeat - if (sr.Attr and $FFFFFFFF) = Sr.Attr then - begin - if Result <> '' then - Result := Result + ','; - Result := Result + sr.Name; - end; - until FindNext(sr) <> 0; - end; - FindClose(sr); -end; -{$ENDIF} - +{==============================================================================| +| Project : Ararat Synapse | 007.005.006 | +|==============================================================================| +| Content: Serial port support | +|==============================================================================| +| Copyright (c)2001-2014, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2001-2014. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| (c)2002, Hans-Georg Joepgen (cpom Comport Ownership Manager and bugfixes) | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{: @abstract(Serial port communication library) +This unit contains a class that implements serial port communication + for Windows, Linux, Unix or MacOSx. This class provides numerous methods with + same name and functionality as methods of the Ararat Synapse TCP/IP library. + +The following is a small example how establish a connection by modem (in this +case with my USB modem): +@longcode(# + ser:=TBlockSerial.Create; + try + ser.Connect('COM3'); + ser.config(460800,8,'N',0,false,true); + ser.ATCommand('AT'); + if (ser.LastError <> 0) or (not ser.ATResult) then + Exit; + ser.ATConnect('ATDT+420971200111'); + if (ser.LastError <> 0) or (not ser.ATResult) then + Exit; + // you are now connected to a modem at +420971200111 + // you can transmit or receive data now + finally + ser.free; + end; +#) +} + +//old Delphi does not have MSWINDOWS define. +{$IFDEF WIN32} + {$IFNDEF MSWINDOWS} + {$DEFINE MSWINDOWS} + {$ENDIF} +{$ENDIF} + +//Kylix does not known UNIX define +{$IFDEF LINUX} + {$IFNDEF UNIX} + {$DEFINE UNIX} + {$ENDIF} +{$ENDIF} + +{$IFDEF FPC} + {$MODE DELPHI} + {$IFDEF MSWINDOWS} + {$ASMMODE intel} + {$ENDIF} + {define working mode w/o LIBC for fpc} + {$DEFINE NO_LIBC} +{$ENDIF} +{$Q-} +{$H+} +{$M+} + +unit synaser; + +interface + +uses +{$IFNDEF MSWINDOWS} + {$IFNDEF NO_LIBC} + Libc, + KernelIoctl, + {$ELSE} + termio, baseunix, unix, + {$ENDIF} + {$IFNDEF FPC} + Types, + {$ENDIF} +{$ELSE} + Windows, registry, + {$IFDEF FPC} + winver, + {$ENDIF} +{$ENDIF} + synafpc, + Classes, SysUtils, synautil; + +const + CR = #$0d; + LF = #$0a; + CRLF = CR + LF; + cSerialChunk = 8192; + + LockfileDirectory = '/var/lock'; {HGJ} + PortIsClosed = -1; {HGJ} + ErrAlreadyOwned = 9991; {HGJ} + ErrAlreadyInUse = 9992; {HGJ} + ErrWrongParameter = 9993; {HGJ} + ErrPortNotOpen = 9994; {HGJ} + ErrNoDeviceAnswer = 9995; {HGJ} + ErrMaxBuffer = 9996; + ErrTimeout = 9997; + ErrNotRead = 9998; + ErrFrame = 9999; + ErrOverrun = 10000; + ErrRxOver = 10001; + ErrRxParity = 10002; + ErrTxFull = 10003; + + dcb_Binary = $00000001; + dcb_ParityCheck = $00000002; + dcb_OutxCtsFlow = $00000004; + dcb_OutxDsrFlow = $00000008; + dcb_DtrControlMask = $00000030; + dcb_DtrControlDisable = $00000000; + dcb_DtrControlEnable = $00000010; + dcb_DtrControlHandshake = $00000020; + dcb_DsrSensivity = $00000040; + dcb_TXContinueOnXoff = $00000080; + dcb_OutX = $00000100; + dcb_InX = $00000200; + dcb_ErrorChar = $00000400; + dcb_NullStrip = $00000800; + dcb_RtsControlMask = $00003000; + dcb_RtsControlDisable = $00000000; + dcb_RtsControlEnable = $00001000; + dcb_RtsControlHandshake = $00002000; + dcb_RtsControlToggle = $00003000; + dcb_AbortOnError = $00004000; + dcb_Reserveds = $FFFF8000; + + {:stopbit value for 1 stopbit} + SB1 = 0; + {:stopbit value for 1.5 stopbit} + SB1andHalf = 1; + {:stopbit value for 2 stopbits} + SB2 = 2; + +{$IFNDEF MSWINDOWS} +const + INVALID_HANDLE_VALUE = THandle(-1); + CS7fix = $0000020; + +type + TDCB = record + DCBlength: DWORD; + BaudRate: DWORD; + Flags: Longint; + wReserved: Word; + XonLim: Word; + XoffLim: Word; + ByteSize: Byte; + Parity: Byte; + StopBits: Byte; + XonChar: CHAR; + XoffChar: CHAR; + ErrorChar: CHAR; + EofChar: CHAR; + EvtChar: CHAR; + wReserved1: Word; + end; + PDCB = ^TDCB; + +const +{$IFDEF UNIX} + {$IFDEF BSD} + MaxRates = 18; //MAC + {$ELSE} + MaxRates = 30; //UNIX + {$ENDIF} +{$ELSE} + MaxRates = 19; //WIN +{$ENDIF} + Rates: array[0..MaxRates, 0..1] of cardinal = + ( + (0, B0), + (50, B50), + (75, B75), + (110, B110), + (134, B134), + (150, B150), + (200, B200), + (300, B300), + (600, B600), + (1200, B1200), + (1800, B1800), + (2400, B2400), + (4800, B4800), + (9600, B9600), + (19200, B19200), + (38400, B38400), + (57600, B57600), + (115200, B115200), + (230400, B230400) +{$IFNDEF BSD} + ,(460800, B460800) + {$IFDEF UNIX} + ,(500000, B500000), + (576000, B576000), + (921600, B921600), + (1000000, B1000000), + (1152000, B1152000), + (1500000, B1500000), + (2000000, B2000000), + (2500000, B2500000), + (3000000, B3000000), + (3500000, B3500000), + (4000000, B4000000) + {$ENDIF} +{$ENDIF} + ); +{$ENDIF} + +{$IFDEF BSD} +const // From fcntl.h + O_SYNC = $0080; { synchronous writes } +{$ENDIF} + +const + sOK = 0; + sErr = integer(-1); + +type + + {:Possible status event types for @link(THookSerialStatus)} + THookSerialReason = ( + HR_SerialClose, + HR_Connect, + HR_CanRead, + HR_CanWrite, + HR_ReadCount, + HR_WriteCount, + HR_Wait + ); + + {:procedural prototype for status event hooking} + THookSerialStatus = procedure(Sender: TObject; Reason: THookSerialReason; + const Value: string) of object; + + {:@abstract(Exception type for SynaSer errors)} + ESynaSerError = class(Exception) + public + ErrorCode: integer; + ErrorMessage: string; + end; + + {:@abstract(Main class implementing all communication routines)} + TBlockSerial = class(TObject) + protected + FOnStatus: THookSerialStatus; + Fhandle: THandle; + FTag: integer; + FDevice: string; + FLastError: integer; + FLastErrorDesc: string; + FBuffer: AnsiString; + FRaiseExcept: boolean; + FRecvBuffer: integer; + FSendBuffer: integer; + FModemWord: integer; + FRTSToggle: Boolean; + FDeadlockTimeout: integer; + FInstanceActive: boolean; {HGJ} + FTestDSR: Boolean; + FTestCTS: Boolean; + FLastCR: Boolean; + FLastLF: Boolean; + FMaxLineLength: Integer; + FLinuxLock: Boolean; + FMaxSendBandwidth: Integer; + FNextSend: LongWord; + FMaxRecvBandwidth: Integer; + FNextRecv: LongWord; + FConvertLineEnd: Boolean; + FATResult: Boolean; + FAtTimeout: integer; + FInterPacketTimeout: Boolean; + FComNr: integer; +{$IFDEF MSWINDOWS} + FPortAddr: Word; + function CanEvent(Event: dword; Timeout: integer): boolean; + procedure DecodeCommError(Error: DWord); virtual; + {$IFDEF WIN32} + function GetPortAddr: Word; virtual; + function ReadTxEmpty(PortAddr: Word): Boolean; virtual; + {$ENDIF} +{$ENDIF} + procedure SetSizeRecvBuffer(size: integer); virtual; + function GetDSR: Boolean; virtual; + procedure SetDTRF(Value: Boolean); virtual; + function GetCTS: Boolean; virtual; + procedure SetRTSF(Value: Boolean); virtual; + function GetCarrier: Boolean; virtual; + function GetRing: Boolean; virtual; + procedure DoStatus(Reason: THookSerialReason; const Value: string); virtual; + procedure GetComNr(Value: string); virtual; + function PreTestFailing: boolean; virtual;{HGJ} + function TestCtrlLine: Boolean; virtual; +{$IFDEF UNIX} + procedure DcbToTermios(const dcb: TDCB; var term: termios); virtual; + procedure TermiosToDcb(const term: termios; var dcb: TDCB); virtual; + function ReadLockfile: integer; virtual; + function LockfileName: String; virtual; + procedure CreateLockfile(PidNr: integer); virtual; +{$ENDIF} + procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); virtual; + procedure SetBandwidth(Value: Integer); virtual; + public + {: data Control Block with communication parameters. Usable only when you + need to call API directly.} + DCB: Tdcb; +{$IFDEF UNIX} + TermiosStruc: termios; +{$ENDIF} + {:Object constructor.} + constructor Create; + {:Object destructor.} + destructor Destroy; override; + + {:Returns a string containing the version number of the library.} + class function GetVersion: string; virtual; + + {:Destroy handle in use. It close connection to serial port.} + procedure CloseSocket; virtual; + + {:Reconfigure communication parameters on the fly. You must be connected to + port before! + @param(baud Define connection speed. Baud rate can be from 50 to 4000000 + bits per second. (it depends on your hardware!)) + @param(bits Number of bits in communication.) + @param(parity Define communication parity (N - None, O - Odd, E - Even, M - Mark or S - Space).) + @param(stop Define number of stopbits. Use constants @link(SB1), + @link(SB1andHalf) and @link(SB2).) + @param(softflow Enable XON/XOFF handshake.) + @param(hardflow Enable CTS/RTS handshake.)} + procedure Config(baud, bits: integer; parity: char; stop: integer; + softflow, hardflow: boolean); virtual; + + {:Connects to the port indicated by comport. Comport can be used in Windows + style (COM2), or in Linux style (/dev/ttyS1). When you use windows style + in Linux, then it will be converted to Linux name. And vice versa! However + you can specify any device name! (other device names then standart is not + converted!) + + After successfull connection the DTR signal is set (if you not set hardware + handshake, then the RTS signal is set, too!) + + Connection parameters is predefined by your system configuration. If you + need use another parameters, then you can use Config method after. + Notes: + + - Remember, the commonly used serial Laplink cable does not support + hardware handshake. + + - Before setting any handshake you must be sure that it is supported by + your hardware. + + - Some serial devices are slow. In some cases you must wait up to a few + seconds after connection for the device to respond. + + - when you connect to a modem device, then is best to test it by an empty + AT command. (call ATCommand('AT'))} + procedure Connect(comport: string); virtual; + + {:Set communication parameters from the DCB structure (the DCB structure is + simulated under Linux).} + procedure SetCommState; virtual; + + {:Read communication parameters into the DCB structure (DCB structure is + simulated under Linux).} + procedure GetCommState; virtual; + + {:Sends Length bytes of data from Buffer through the connected port.} + function SendBuffer(buffer: pointer; length: integer): integer; virtual; + + {:One data BYTE is sent.} + procedure SendByte(data: byte); virtual; + + {:Send the string in the data parameter. No terminator is appended by this + method. If you need to send a string with CR/LF terminator, you must append + the CR/LF characters to the data string! + + Since no terminator is appended, you can use this function for sending + binary data too.} + procedure SendString(data: AnsiString); virtual; + + {:send four bytes as integer.} + procedure SendInteger(Data: integer); virtual; + + {:send data as one block. Each block begins with integer value with Length + of block.} + procedure SendBlock(const Data: AnsiString); virtual; + + {:send content of stream from current position} + procedure SendStreamRaw(const Stream: TStream); virtual; + + {:send content of stream as block. see @link(SendBlock)} + procedure SendStream(const Stream: TStream); virtual; + + {:send content of stream as block, but this is compatioble with Indy library. + (it have swapped lenght of block). See @link(SendStream)} + procedure SendStreamIndy(const Stream: TStream); virtual; + + {:Waits until the allocated buffer is filled by received data. Returns number + of data bytes received, which equals to the Length value under normal + operation. If it is not equal, the communication channel is possibly broken. + + This method not using any internal buffering, like all others receiving + methods. You cannot freely combine this method with all others receiving + methods!} + function RecvBuffer(buffer: pointer; length: integer): integer; virtual; + + {:Method waits until data is received. If no data is received within + the Timeout (in milliseconds) period, @link(LastError) is set to + @link(ErrTimeout). This method is used to read any amount of data + (e. g. 1MB), and may be freely combined with all receviving methods what + have Timeout parameter, like the @link(RecvString), @link(RecvByte) or + @link(RecvTerminated) methods.} + function RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; virtual; + + {:It is like recvBufferEx, but data is readed to dynamicly allocated binary + string.} + function RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; virtual; + + {:Read all available data and return it in the function result string. This + function may be combined with @link(RecvString), @link(RecvByte) or related + methods.} + function RecvPacket(Timeout: Integer): AnsiString; virtual; + + {:Waits until one data byte is received which is returned as the function + result. If no data is received within the Timeout (in milliseconds) period, + @link(LastError) is set to @link(ErrTimeout).} + function RecvByte(timeout: integer): byte; virtual; + + {:This method waits until a terminated data string is received. This string + is terminated by the Terminator string. The resulting string is returned + without this termination string! If no data is received within the Timeout + (in milliseconds) period, @link(LastError) is set to @link(ErrTimeout).} + function RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; virtual; + + {:This method waits until a terminated data string is received. The string + is terminated by a CR/LF sequence. The resulting string is returned without + the terminator (CR/LF)! If no data is received within the Timeout (in + milliseconds) period, @link(LastError) is set to @link(ErrTimeout). + + If @link(ConvertLineEnd) is used, then the CR/LF sequence may not be exactly + CR/LF. See the description of @link(ConvertLineEnd). + + This method serves for line protocol implementation and uses its own + buffers to maximize performance. Therefore do NOT use this method with the + @link(RecvBuffer) method to receive data as it may cause data loss.} + function Recvstring(timeout: integer): AnsiString; virtual; + + {:Waits until four data bytes are received which is returned as the function + integer result. If no data is received within the Timeout (in milliseconds) period, + @link(LastError) is set to @link(ErrTimeout).} + function RecvInteger(Timeout: Integer): Integer; virtual; + + {:Waits until one data block is received. See @link(sendblock). If no data + is received within the Timeout (in milliseconds) period, @link(LastError) + is set to @link(ErrTimeout).} + function RecvBlock(Timeout: Integer): AnsiString; virtual; + + {:Receive all data to stream, until some error occured. (for example timeout)} + procedure RecvStreamRaw(const Stream: TStream; Timeout: Integer); virtual; + + {:receive requested count of bytes to stream} + procedure RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); virtual; + + {:receive block of data to stream. (Data can be sended by @link(sendstream)} + procedure RecvStream(const Stream: TStream; Timeout: Integer); virtual; + + {:receive block of data to stream. (Data can be sended by @link(sendstreamIndy)} + procedure RecvStreamIndy(const Stream: TStream; Timeout: Integer); virtual; + + {:Returns the number of received bytes waiting for reading. 0 is returned + when there is no data waiting.} + function WaitingData: integer; virtual; + + {:Same as @link(WaitingData), but in respect to data in the internal + @link(LineBuffer).} + function WaitingDataEx: integer; virtual; + + {:Returns the number of bytes waiting to be sent in the output buffer. + 0 is returned when the output buffer is empty.} + function SendingData: integer; virtual; + + {:Enable or disable RTS driven communication (half-duplex). It can be used + to communicate with RS485 converters, or other special equipment. If you + enable this feature, the system automatically controls the RTS signal. + + Notes: + + - On Windows NT (or higher) ir RTS signal driven by system driver. + + - On Win9x family is used special code for waiting until last byte is + sended from your UART. + + - On Linux you must have kernel 2.1 or higher!} + procedure EnableRTSToggle(value: boolean); virtual; + + {:Waits until all data to is sent and buffers are emptied. + Warning: On Windows systems is this method returns when all buffers are + flushed to the serial port controller, before the last byte is sent!} + procedure Flush; virtual; + + {:Unconditionally empty all buffers. It is good when you need to interrupt + communication and for cleanups.} + procedure Purge; virtual; + + {:Returns @True, if you can from read any data from the port. Status is + tested for a period of time given by the Timeout parameter (in milliseconds). + If the value of the Timeout parameter is 0, the status is tested only once + and the function returns immediately. If the value of the Timeout parameter + is set to -1, the function returns only after it detects data on the port + (this may cause the process to hang).} + function CanRead(Timeout: integer): boolean; virtual; + + {:Returns @True, if you can write any data to the port (this function is not + sending the contents of the buffer). Status is tested for a period of time + given by the Timeout parameter (in milliseconds). If the value of + the Timeout parameter is 0, the status is tested only once and the function + returns immediately. If the value of the Timeout parameter is set to -1, + the function returns only after it detects that it can write data to + the port (this may cause the process to hang).} + function CanWrite(Timeout: integer): boolean; virtual; + + {:Same as @link(CanRead), but the test is against data in the internal + @link(LineBuffer) too.} + function CanReadEx(Timeout: integer): boolean; virtual; + + {:Returns the status word of the modem. Decoding the status word could yield + the status of carrier detect signaland other signals. This method is used + internally by the modem status reading properties. You usually do not need + to call this method directly.} + function ModemStatus: integer; virtual; + + {:Send a break signal to the communication device for Duration milliseconds.} + procedure SetBreak(Duration: integer); virtual; + + {:This function is designed to send AT commands to the modem. The AT command + is sent in the Value parameter and the response is returned in the function + return value (may contain multiple lines!). + If the AT command is processed successfully (modem returns OK), then the + @link(ATResult) property is set to True. + + This function is designed only for AT commands that return OK or ERROR + response! To call connection commands the @link(ATConnect) method. + Remember, when you connect to a modem device, it is in AT command mode. + Now you can send AT commands to the modem. If you need to transfer data to + the modem on the other side of the line, you must first switch to data mode + using the @link(ATConnect) method.} + function ATCommand(value: AnsiString): AnsiString; virtual; + + {:This function is used to send connect type AT commands to the modem. It is + for commands to switch to connected state. (ATD, ATA, ATO,...) + It sends the AT command in the Value parameter and returns the modem's + response (may be multiple lines - usually with connection parameters info). + If the AT command is processed successfully (the modem returns CONNECT), + then the ATResult property is set to @True. + + This function is designed only for AT commands which respond by CONNECT, + BUSY, NO DIALTONE NO CARRIER or ERROR. For other AT commands use the + @link(ATCommand) method. + + The connect timeout is 90*@link(ATTimeout). If this command is successful + (@link(ATresult) is @true), then the modem is in data state. When you now + send or receive some data, it is not to or from your modem, but from the + modem on other side of the line. Now you can transfer your data. + If the connection attempt failed (@link(ATResult) is @False), then the + modem is still in AT command mode.} + function ATConnect(value: AnsiString): AnsiString; virtual; + + {:If you "manually" call API functions, forward their return code in + the SerialResult parameter to this function, which evaluates it and sets + @link(LastError) and @link(LastErrorDesc).} + function SerialCheck(SerialResult: integer): integer; virtual; + + {:If @link(Lasterror) is not 0 and exceptions are enabled, then this procedure + raises an exception. This method is used internally. You may need it only + in special cases.} + procedure ExceptCheck; virtual; + + {:Set Synaser to error state with ErrNumber code. Usually used by internal + routines.} + procedure SetSynaError(ErrNumber: integer); virtual; + + {:Raise Synaser error with ErrNumber code. Usually used by internal routines.} + procedure RaiseSynaError(ErrNumber: integer); virtual; +{$IFDEF UNIX} + function cpomComportAccessible: boolean; virtual;{HGJ} + procedure cpomReleaseComport; virtual; {HGJ} +{$ENDIF} + {:True device name of currently used port} + property Device: string read FDevice; + + {:Error code of last operation. Value is defined by the host operating + system, but value 0 is always OK.} + property LastError: integer read FLastError; + + {:Human readable description of LastError code.} + property LastErrorDesc: string read FLastErrorDesc; + + {:Indicates if the last @link(ATCommand) or @link(ATConnect) method was successful} + property ATResult: Boolean read FATResult; + + {:Read the value of the RTS signal.} + property RTS: Boolean write SetRTSF; + + {:Indicates the presence of the CTS signal} + property CTS: boolean read GetCTS; + + {:Use this property to set the value of the DTR signal.} + property DTR: Boolean write SetDTRF; + + {:Exposes the status of the DSR signal.} + property DSR: boolean read GetDSR; + + {:Indicates the presence of the Carrier signal} + property Carrier: boolean read GetCarrier; + + {:Reflects the status of the Ring signal.} + property Ring: boolean read GetRing; + + {:indicates if this instance of SynaSer is active. (Connected to some port)} + property InstanceActive: boolean read FInstanceActive; {HGJ} + + {:Defines maximum bandwidth for all sending operations in bytes per second. + If this value is set to 0 (default), bandwidth limitation is not used.} + property MaxSendBandwidth: Integer read FMaxSendBandwidth Write FMaxSendBandwidth; + + {:Defines maximum bandwidth for all receiving operations in bytes per second. + If this value is set to 0 (default), bandwidth limitation is not used.} + property MaxRecvBandwidth: Integer read FMaxRecvBandwidth Write FMaxRecvBandwidth; + + {:Defines maximum bandwidth for all sending and receiving operations + in bytes per second. If this value is set to 0 (default), bandwidth + limitation is not used.} + property MaxBandwidth: Integer Write SetBandwidth; + + {:Size of the Windows internal receive buffer. Default value is usually + 4096 bytes. Note: Valid only in Windows versions!} + property SizeRecvBuffer: integer read FRecvBuffer write SetSizeRecvBuffer; + published + {:Returns the descriptive text associated with ErrorCode. You need this + method only in special cases. Description of LastError is now accessible + through the LastErrorDesc property.} + class function GetErrorDesc(ErrorCode: integer): string; + + {:Freely usable property} + property Tag: integer read FTag write FTag; + + {:Contains the handle of the open communication port. + You may need this value to directly call communication functions outside + SynaSer.} + property Handle: THandle read Fhandle write FHandle; + + {:Internally used read buffer.} + property LineBuffer: AnsiString read FBuffer write FBuffer; + + {:If @true, communication errors raise exceptions. If @false (default), only + the @link(LastError) value is set.} + property RaiseExcept: boolean read FRaiseExcept write FRaiseExcept; + + {:This event is triggered when the communication status changes. It can be + used to monitor communication status.} + property OnStatus: THookSerialStatus read FOnStatus write FOnStatus; + + {:If you set this property to @true, then the value of the DSR signal + is tested before every data transfer. It can be used to detect the presence + of a communications device.} + property TestDSR: boolean read FTestDSR write FTestDSR; + + {:If you set this property to @true, then the value of the CTS signal + is tested before every data transfer. It can be used to detect the presence + of a communications device. Warning: This property cannot be used if you + need hardware handshake!} + property TestCTS: boolean read FTestCTS write FTestCTS; + + {:Use this property you to limit the maximum size of LineBuffer + (as a protection against unlimited memory allocation for LineBuffer). + Default value is 0 - no limit.} + property MaxLineLength: Integer read FMaxLineLength Write FMaxLineLength; + + {:This timeout value is used as deadlock protection when trying to send data + to (or receive data from) a device that stopped communicating during data + transmission (e.g. by physically disconnecting the device). + The timeout value is in milliseconds. The default value is 30,000 (30 seconds).} + property DeadlockTimeout: Integer read FDeadlockTimeout Write FDeadlockTimeout; + + {:If set to @true (default value), port locking is enabled (under Linux only). + WARNING: To use this feature, the application must run by a user with full + permission to the /var/lock directory!} + property LinuxLock: Boolean read FLinuxLock write FLinuxLock; + + {:Indicates if non-standard line terminators should be converted to a CR/LF pair + (standard DOS line terminator). If @TRUE, line terminators CR, single LF + or LF/CR are converted to CR/LF. Defaults to @FALSE. + This property has effect only on the behavior of the RecvString method.} + property ConvertLineEnd: Boolean read FConvertLineEnd Write FConvertLineEnd; + + {:Timeout for AT modem based operations} + property AtTimeout: integer read FAtTimeout Write FAtTimeout; + + {:If @true (default), then all timeouts is timeout between two characters. + If @False, then timeout is overall for whoole reading operation.} + property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout; + end; + +{:Returns list of existing computer serial ports. Working properly only in Windows!} +function GetSerialPortNames: string; + +implementation + +constructor TBlockSerial.Create; +begin + inherited create; + FRaiseExcept := false; + FHandle := INVALID_HANDLE_VALUE; + FDevice := ''; + FComNr:= PortIsClosed; {HGJ} + FInstanceActive:= false; {HGJ} + Fbuffer := ''; + FRTSToggle := False; + FMaxLineLength := 0; + FTestDSR := False; + FTestCTS := False; + FDeadlockTimeout := 30000; + FLinuxLock := True; + FMaxSendBandwidth := 0; + FNextSend := 0; + FMaxRecvBandwidth := 0; + FNextRecv := 0; + FConvertLineEnd := False; + SetSynaError(sOK); + FRecvBuffer := 4096; + FLastCR := False; + FLastLF := False; + FAtTimeout := 1000; + FInterPacketTimeout := True; +end; + +destructor TBlockSerial.Destroy; +begin + CloseSocket; + inherited destroy; +end; + +class function TBlockSerial.GetVersion: string; +begin + Result := 'SynaSer 7.5.4'; +end; + +procedure TBlockSerial.CloseSocket; +begin + if Fhandle <> INVALID_HANDLE_VALUE then + begin + Purge; + RTS := False; + DTR := False; + FileClose(FHandle); + end; + if InstanceActive then + begin + {$IFDEF UNIX} + if FLinuxLock then + cpomReleaseComport; + {$ENDIF} + FInstanceActive:= false + end; + Fhandle := INVALID_HANDLE_VALUE; + FComNr:= PortIsClosed; + SetSynaError(sOK); + DoStatus(HR_SerialClose, FDevice); +end; + +{$IFDEF WIN32} +function TBlockSerial.GetPortAddr: Word; +begin + Result := 0; + if Win32Platform <> VER_PLATFORM_WIN32_NT then + begin + EscapeCommFunction(FHandle, 10); + asm + MOV @Result, DX; + end; + end; +end; + +function TBlockSerial.ReadTxEmpty(PortAddr: Word): Boolean; +begin + Result := True; + if Win32Platform <> VER_PLATFORM_WIN32_NT then + begin + asm + MOV DX, PortAddr; + ADD DX, 5; + IN AL, DX; + AND AL, $40; + JZ @K; + MOV AL,1; + @K: MOV @Result, AL; + end; + end; +end; +{$ENDIF} + +procedure TBlockSerial.GetComNr(Value: string); +begin + FComNr := PortIsClosed; + if pos('COM', uppercase(Value)) = 1 then + FComNr := StrToIntdef(copy(Value, 4, Length(Value) - 3), PortIsClosed + 1) - 1; + if pos('/DEV/TTYS', uppercase(Value)) = 1 then + FComNr := StrToIntdef(copy(Value, 10, Length(Value) - 9), PortIsClosed - 1); +end; + +procedure TBlockSerial.SetBandwidth(Value: Integer); +begin + MaxSendBandwidth := Value; + MaxRecvBandwidth := Value; +end; + +procedure TBlockSerial.LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); +var + x: LongWord; + y: LongWord; +begin + if MaxB > 0 then + begin + y := GetTick; + if Next > y then + begin + x := Next - y; + if x > 0 then + begin + DoStatus(HR_Wait, IntToStr(x)); + sleep(x); + end; + end; + Next := GetTick + Trunc((Length / MaxB) * 1000); + end; +end; + +procedure TBlockSerial.Config(baud, bits: integer; parity: char; stop: integer; + softflow, hardflow: boolean); +begin + FillChar(dcb, SizeOf(dcb), 0); + GetCommState; + dcb.DCBlength := SizeOf(dcb); + dcb.BaudRate := baud; + dcb.ByteSize := bits; + case parity of + 'N', 'n': dcb.parity := 0; + 'O', 'o': dcb.parity := 1; + 'E', 'e': dcb.parity := 2; + 'M', 'm': dcb.parity := 3; + 'S', 's': dcb.parity := 4; + end; + dcb.StopBits := stop; + dcb.XonChar := #17; + dcb.XoffChar := #19; + dcb.XonLim := FRecvBuffer div 4; + dcb.XoffLim := FRecvBuffer div 4; + dcb.Flags := dcb_Binary; + if softflow then + dcb.Flags := dcb.Flags or dcb_OutX or dcb_InX; + if hardflow then + dcb.Flags := dcb.Flags or dcb_OutxCtsFlow or dcb_RtsControlHandshake + else + dcb.Flags := dcb.Flags or dcb_RtsControlEnable; + dcb.Flags := dcb.Flags or dcb_DtrControlEnable; + if dcb.Parity > 0 then + dcb.Flags := dcb.Flags or dcb_ParityCheck; + SetCommState; +end; + +procedure TBlockSerial.Connect(comport: string); +{$IFDEF MSWINDOWS} +var + CommTimeouts: TCommTimeouts; +{$ENDIF} +begin + // Is this TBlockSerial Instance already busy? + if InstanceActive then {HGJ} + begin {HGJ} + RaiseSynaError(ErrAlreadyInUse); + Exit; {HGJ} + end; {HGJ} + FBuffer := ''; + FDevice := comport; + GetComNr(comport); +{$IFDEF MSWINDOWS} + SetLastError (sOK); +{$ELSE} + {$IFNDEF FPC} + SetLastError (sOK); + {$ELSE} + fpSetErrno(sOK); + {$ENDIF} +{$ENDIF} +{$IFNDEF MSWINDOWS} + if FComNr <> PortIsClosed then + FDevice := '/dev/ttyS' + IntToStr(FComNr); + // Comport already owned by another process? {HGJ} + if FLinuxLock then + if not cpomComportAccessible then + begin + RaiseSynaError(ErrAlreadyOwned); + Exit; + end; +{$IFNDEF FPC} + FHandle := THandle(Libc.open(pchar(FDevice), O_RDWR or O_SYNC)); +{$ELSE} + FHandle := THandle(fpOpen(FDevice, O_RDWR or O_SYNC)); +{$ENDIF} + if FHandle = INVALID_HANDLE_VALUE then //because THandle is not integer on all platforms! + SerialCheck(-1) + else + SerialCheck(0); + {$IFDEF UNIX} + if FLastError <> sOK then + if FLinuxLock then + cpomReleaseComport; + {$ENDIF} + ExceptCheck; + if FLastError <> sOK then + Exit; +{$ELSE} + if FComNr <> PortIsClosed then + FDevice := '\\.\COM' + IntToStr(FComNr + 1); + FHandle := THandle(CreateFile(PChar(FDevice), GENERIC_READ or GENERIC_WRITE, + 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0)); + if FHandle = INVALID_HANDLE_VALUE then //because THandle is not integer on all platforms! + SerialCheck(-1) + else + SerialCheck(0); + ExceptCheck; + if FLastError <> sOK then + Exit; + SetCommMask(FHandle, 0); + SetupComm(Fhandle, FRecvBuffer, 0); + CommTimeOuts.ReadIntervalTimeout := MAXWORD; + CommTimeOuts.ReadTotalTimeoutMultiplier := 0; + CommTimeOuts.ReadTotalTimeoutConstant := 0; + CommTimeOuts.WriteTotalTimeoutMultiplier := 0; + CommTimeOuts.WriteTotalTimeoutConstant := 0; + SetCommTimeOuts(FHandle, CommTimeOuts); + {$IFDEF WIN32} + FPortAddr := GetPortAddr; + {$ENDIF} +{$ENDIF} + SetSynaError(sOK); + if not TestCtrlLine then {HGJ} + begin + SetSynaError(ErrNoDeviceAnswer); + FileClose(FHandle); {HGJ} + {$IFDEF UNIX} + if FLinuxLock then + cpomReleaseComport; {HGJ} + {$ENDIF} {HGJ} + Fhandle := INVALID_HANDLE_VALUE; {HGJ} + FComNr:= PortIsClosed; {HGJ} + end + else + begin + FInstanceActive:= True; + RTS := True; + DTR := True; + Purge; + end; + ExceptCheck; + DoStatus(HR_Connect, FDevice); +end; + +function TBlockSerial.SendBuffer(buffer: pointer; length: integer): integer; +{$IFDEF MSWINDOWS} +var + Overlapped: TOverlapped; + x, y, Err: DWord; +{$ENDIF} +begin + Result := 0; + if PreTestFailing then {HGJ} + Exit; {HGJ} + LimitBandwidth(Length, FMaxSendBandwidth, FNextsend); + if FRTSToggle then + begin + Flush; + RTS := True; + end; +{$IFNDEF MSWINDOWS} + result := FileWrite(Fhandle, Buffer^, Length); + serialcheck(result); +{$ELSE} + FillChar(Overlapped, Sizeof(Overlapped), 0); + SetSynaError(sOK); + y := 0; + if not WriteFile(FHandle, Buffer^, Length, DWord(Result), @Overlapped) then + y := GetLastError; + if y = ERROR_IO_PENDING then + begin + x := WaitForSingleObject(FHandle, FDeadlockTimeout); + if x = WAIT_TIMEOUT then + begin + PurgeComm(FHandle, PURGE_TXABORT); + SetSynaError(ErrTimeout); + end; + GetOverlappedResult(FHandle, Overlapped, Dword(Result), False); + end + else + SetSynaError(y); + ClearCommError(FHandle, err, nil); + if err <> 0 then + DecodeCommError(err); +{$ENDIF} + if FRTSToggle then + begin + Flush; + CanWrite(255); + RTS := False; + end; + ExceptCheck; + DoStatus(HR_WriteCount, IntToStr(Result)); +end; + +procedure TBlockSerial.SendByte(data: byte); +begin + SendBuffer(@Data, 1); +end; + +procedure TBlockSerial.SendString(data: AnsiString); +begin + SendBuffer(Pointer(Data), Length(Data)); +end; + +procedure TBlockSerial.SendInteger(Data: integer); +begin + SendBuffer(@data, SizeOf(Data)); +end; + +procedure TBlockSerial.SendBlock(const Data: AnsiString); +begin + SendInteger(Length(data)); + SendString(Data); +end; + +procedure TBlockSerial.SendStreamRaw(const Stream: TStream); +var + si: integer; + x, y, yr: integer; + s: AnsiString; +begin + si := Stream.Size - Stream.Position; + x := 0; + while x < si do + begin + y := si - x; + if y > cSerialChunk then + y := cSerialChunk; + Setlength(s, y); + yr := Stream.read(PAnsiChar(s)^, y); + if yr > 0 then + begin + SetLength(s, yr); + SendString(s); + Inc(x, yr); + end + else + break; + end; +end; + +procedure TBlockSerial.SendStreamIndy(const Stream: TStream); +var + si: integer; +begin + si := Stream.Size - Stream.Position; + si := Swapbytes(si); + SendInteger(si); + SendStreamRaw(Stream); +end; + +procedure TBlockSerial.SendStream(const Stream: TStream); +var + si: integer; +begin + si := Stream.Size - Stream.Position; + SendInteger(si); + SendStreamRaw(Stream); +end; + +function TBlockSerial.RecvBuffer(buffer: pointer; length: integer): integer; +{$IFNDEF MSWINDOWS} +begin + Result := 0; + if PreTestFailing then {HGJ} + Exit; {HGJ} + LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); + result := FileRead(FHandle, Buffer^, length); + serialcheck(result); +{$ELSE} +var + Overlapped: TOverlapped; + x, y, Err: DWord; +begin + Result := 0; + if PreTestFailing then {HGJ} + Exit; {HGJ} + LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); + FillChar(Overlapped, Sizeof(Overlapped), 0); + SetSynaError(sOK); + y := 0; + if not ReadFile(FHandle, Buffer^, length, Dword(Result), @Overlapped) then + y := GetLastError; + if y = ERROR_IO_PENDING then + begin + x := WaitForSingleObject(FHandle, FDeadlockTimeout); + if x = WAIT_TIMEOUT then + begin + PurgeComm(FHandle, PURGE_RXABORT); + SetSynaError(ErrTimeout); + end; + GetOverlappedResult(FHandle, Overlapped, Dword(Result), False); + end + else + SetSynaError(y); + ClearCommError(FHandle, err, nil); + if err <> 0 then + DecodeCommError(err); +{$ENDIF} + ExceptCheck; + DoStatus(HR_ReadCount, IntToStr(Result)); +end; + +function TBlockSerial.RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; +var + s: AnsiString; + rl, l: integer; + ti: LongWord; +begin + Result := 0; + if PreTestFailing then {HGJ} + Exit; {HGJ} + SetSynaError(sOK); + rl := 0; + repeat + ti := GetTick; + s := RecvPacket(Timeout); + l := System.Length(s); + if (rl + l) > Length then + l := Length - rl; + Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); + rl := rl + l; + if FLastError <> sOK then + Break; + if rl >= Length then + Break; + if not FInterPacketTimeout then + begin + Timeout := Timeout - integer(TickDelta(ti, GetTick)); + if Timeout <= 0 then + begin + SetSynaError(ErrTimeout); + Break; + end; + end; + until False; + delete(s, 1, l); + FBuffer := s; + Result := rl; +end; + +function TBlockSerial.RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; +var + x: integer; +begin + Result := ''; + if PreTestFailing then {HGJ} + Exit; {HGJ} + SetSynaError(sOK); + if Length > 0 then + begin + Setlength(Result, Length); + x := RecvBufferEx(PAnsiChar(Result), Length , Timeout); + if FLastError = sOK then + SetLength(Result, x) + else + Result := ''; + end; +end; + +function TBlockSerial.RecvPacket(Timeout: Integer): AnsiString; +var + x: integer; +begin + Result := ''; + if PreTestFailing then {HGJ} + Exit; {HGJ} + SetSynaError(sOK); + if FBuffer <> '' then + begin + Result := FBuffer; + FBuffer := ''; + end + else + begin + //not drain CPU on large downloads... + Sleep(0); + x := WaitingData; + if x > 0 then + begin + SetLength(Result, x); + x := RecvBuffer(Pointer(Result), x); + if x >= 0 then + SetLength(Result, x); + end + else + begin + if CanRead(Timeout) then + begin + x := WaitingData; + if x = 0 then + SetSynaError(ErrTimeout); + if x > 0 then + begin + SetLength(Result, x); + x := RecvBuffer(Pointer(Result), x); + if x >= 0 then + SetLength(Result, x); + end; + end + else + SetSynaError(ErrTimeout); + end; + end; + ExceptCheck; +end; + + +function TBlockSerial.RecvByte(timeout: integer): byte; +begin + Result := 0; + if PreTestFailing then {HGJ} + Exit; {HGJ} + SetSynaError(sOK); + if FBuffer = '' then + FBuffer := RecvPacket(Timeout); + if (FLastError = sOK) and (FBuffer <> '') then + begin + Result := Ord(FBuffer[1]); + System.Delete(FBuffer, 1, 1); + end; + ExceptCheck; +end; + +function TBlockSerial.RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; +var + x: Integer; + s: AnsiString; + l: Integer; + CorCRLF: Boolean; + t: ansistring; + tl: integer; + ti: LongWord; +begin + Result := ''; + if PreTestFailing then {HGJ} + Exit; {HGJ} + SetSynaError(sOK); + l := system.Length(Terminator); + if l = 0 then + Exit; + tl := l; + CorCRLF := FConvertLineEnd and (Terminator = CRLF); + s := ''; + x := 0; + repeat + ti := GetTick; + //get rest of FBuffer or incomming new data... + s := s + RecvPacket(Timeout); + if FLastError <> sOK then + Break; + x := 0; + if Length(s) > 0 then + if CorCRLF then + begin + if FLastCR and (s[1] = LF) then + Delete(s, 1, 1); + if FLastLF and (s[1] = CR) then + Delete(s, 1, 1); + FLastCR := False; + FLastLF := False; + t := ''; + x := PosCRLF(s, t); + tl := system.Length(t); + if t = CR then + FLastCR := True; + if t = LF then + FLastLF := True; + end + else + begin + x := pos(Terminator, s); + tl := l; + end; + if (FMaxLineLength <> 0) and (system.Length(s) > FMaxLineLength) then + begin + SetSynaError(ErrMaxBuffer); + Break; + end; + if x > 0 then + Break; + if not FInterPacketTimeout then + begin + Timeout := Timeout - integer(TickDelta(ti, GetTick)); + if Timeout <= 0 then + begin + SetSynaError(ErrTimeout); + Break; + end; + end; + until False; + if x > 0 then + begin + Result := Copy(s, 1, x - 1); + System.Delete(s, 1, x + tl - 1); + end; + FBuffer := s; + ExceptCheck; +end; + + +function TBlockSerial.RecvString(Timeout: Integer): AnsiString; +var + s: AnsiString; +begin + Result := ''; + s := RecvTerminated(Timeout, #13 + #10); + if FLastError = sOK then + Result := s; +end; + +function TBlockSerial.RecvInteger(Timeout: Integer): Integer; +var + s: AnsiString; +begin + Result := 0; + s := RecvBufferStr(4, Timeout); + if FLastError = 0 then + Result := (ord(s[1]) + ord(s[2]) * 256) + (ord(s[3]) + ord(s[4]) * 256) * 65536; +end; + +function TBlockSerial.RecvBlock(Timeout: Integer): AnsiString; +var + x: integer; +begin + Result := ''; + x := RecvInteger(Timeout); + if FLastError = 0 then + Result := RecvBufferStr(x, Timeout); +end; + +procedure TBlockSerial.RecvStreamRaw(const Stream: TStream; Timeout: Integer); +var + s: AnsiString; +begin + repeat + s := RecvPacket(Timeout); + if FLastError = 0 then + WriteStrToStream(Stream, s); + until FLastError <> 0; +end; + +procedure TBlockSerial.RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); +var + s: AnsiString; + n: integer; +begin + for n := 1 to (Size div cSerialChunk) do + begin + s := RecvBufferStr(cSerialChunk, Timeout); + if FLastError <> 0 then + Exit; + Stream.Write(PAnsichar(s)^, cSerialChunk); + end; + n := Size mod cSerialChunk; + if n > 0 then + begin + s := RecvBufferStr(n, Timeout); + if FLastError <> 0 then + Exit; + Stream.Write(PAnsichar(s)^, n); + end; +end; + +procedure TBlockSerial.RecvStreamIndy(const Stream: TStream; Timeout: Integer); +var + x: integer; +begin + x := RecvInteger(Timeout); + x := SwapBytes(x); + if FLastError = 0 then + RecvStreamSize(Stream, Timeout, x); +end; + +procedure TBlockSerial.RecvStream(const Stream: TStream; Timeout: Integer); +var + x: integer; +begin + x := RecvInteger(Timeout); + if FLastError = 0 then + RecvStreamSize(Stream, Timeout, x); +end; + +{$IFNDEF MSWINDOWS} +function TBlockSerial.WaitingData: integer; +begin +{$IFNDEF FPC} + serialcheck(ioctl(FHandle, FIONREAD, @result)); +{$ELSE} + serialcheck(fpIoctl(FHandle, FIONREAD, @result)); +{$ENDIF} + if FLastError <> 0 then + Result := 0; + ExceptCheck; +end; +{$ELSE} +function TBlockSerial.WaitingData: integer; +var + stat: TComStat; + err: DWORD; +begin + if ClearCommError(FHandle, err, @stat) then + begin + SetSynaError(sOK); + Result := stat.cbInQue; + end + else + begin + SerialCheck(sErr); + Result := 0; + end; + ExceptCheck; +end; +{$ENDIF} + +function TBlockSerial.WaitingDataEx: integer; +begin + if FBuffer <> '' then + Result := Length(FBuffer) + else + Result := Waitingdata; +end; + +{$IFNDEF MSWINDOWS} +function TBlockSerial.SendingData: integer; +begin + SetSynaError(sOK); + Result := 0; +end; +{$ELSE} +function TBlockSerial.SendingData: integer; +var + stat: TComStat; + err: DWORD; +begin + SetSynaError(sOK); + if not ClearCommError(FHandle, err, @stat) then + serialcheck(sErr); + ExceptCheck; + result := stat.cbOutQue; +end; +{$ENDIF} + +{$IFNDEF MSWINDOWS} +procedure TBlockSerial.DcbToTermios(const dcb: TDCB; var term: termios); +var + n: integer; + x: cardinal; +begin + //others + cfmakeraw(term); + term.c_cflag := term.c_cflag or CREAD; + term.c_cflag := term.c_cflag or CLOCAL; + term.c_cflag := term.c_cflag or HUPCL; + //hardware handshake + if (dcb.flags and dcb_RtsControlHandshake) > 0 then + term.c_cflag := term.c_cflag or CRTSCTS + else + term.c_cflag := term.c_cflag and (not CRTSCTS); + //software handshake + if (dcb.flags and dcb_OutX) > 0 then + term.c_iflag := term.c_iflag or IXON or IXOFF or IXANY + else + term.c_iflag := term.c_iflag and (not (IXON or IXOFF or IXANY)); + //size of byte + term.c_cflag := term.c_cflag and (not CSIZE); + case dcb.bytesize of + 5: + term.c_cflag := term.c_cflag or CS5; + 6: + term.c_cflag := term.c_cflag or CS6; + 7: +{$IFDEF FPC} + term.c_cflag := term.c_cflag or CS7; +{$ELSE} + term.c_cflag := term.c_cflag or CS7fix; +{$ENDIF} + 8: + term.c_cflag := term.c_cflag or CS8; + end; + //parity + if (dcb.flags and dcb_ParityCheck) > 0 then + term.c_cflag := term.c_cflag or PARENB + else + term.c_cflag := term.c_cflag and (not PARENB); + case dcb.parity of + 1: //'O' + term.c_cflag := term.c_cflag or PARODD; + 2: //'E' + term.c_cflag := term.c_cflag and (not PARODD); + end; + //stop bits + if dcb.stopbits > 0 then + term.c_cflag := term.c_cflag or CSTOPB + else + term.c_cflag := term.c_cflag and (not CSTOPB); + //set baudrate; + x := 0; + for n := 0 to Maxrates do + if rates[n, 0] = dcb.BaudRate then + begin + x := rates[n, 1]; + break; + end; + cfsetospeed(term, x); + cfsetispeed(term, x); +end; + +procedure TBlockSerial.TermiosToDcb(const term: termios; var dcb: TDCB); +var + n: integer; + x: cardinal; +begin + //set baudrate; + dcb.baudrate := 0; + {$IFDEF FPC} + //why FPC not have cfgetospeed??? + x := term.c_oflag and $0F; + {$ELSE} + x := cfgetospeed(term); + {$ENDIF} + for n := 0 to Maxrates do + if rates[n, 1] = x then + begin + dcb.baudrate := rates[n, 0]; + break; + end; + //hardware handshake + if (term.c_cflag and CRTSCTS) > 0 then + dcb.flags := dcb.flags or dcb_RtsControlHandshake or dcb_OutxCtsFlow + else + dcb.flags := dcb.flags and (not (dcb_RtsControlHandshake or dcb_OutxCtsFlow)); + //software handshake + if (term.c_cflag and IXOFF) > 0 then + dcb.flags := dcb.flags or dcb_OutX or dcb_InX + else + dcb.flags := dcb.flags and (not (dcb_OutX or dcb_InX)); + //size of byte + case term.c_cflag and CSIZE of + CS5: + dcb.bytesize := 5; + CS6: + dcb.bytesize := 6; + CS7fix: + dcb.bytesize := 7; + CS8: + dcb.bytesize := 8; + end; + //parity + if (term.c_cflag and PARENB) > 0 then + dcb.flags := dcb.flags or dcb_ParityCheck + else + dcb.flags := dcb.flags and (not dcb_ParityCheck); + dcb.parity := 0; + if (term.c_cflag and PARODD) > 0 then + dcb.parity := 1 + else + dcb.parity := 2; + //stop bits + if (term.c_cflag and CSTOPB) > 0 then + dcb.stopbits := 2 + else + dcb.stopbits := 0; +end; +{$ENDIF} + +{$IFNDEF MSWINDOWS} +procedure TBlockSerial.SetCommState; +begin + DcbToTermios(dcb, termiosstruc); + SerialCheck(tcsetattr(FHandle, TCSANOW, termiosstruc)); + ExceptCheck; +end; +{$ELSE} +procedure TBlockSerial.SetCommState; +begin + SetSynaError(sOK); + if not windows.SetCommState(Fhandle, dcb) then + SerialCheck(sErr); + ExceptCheck; +end; +{$ENDIF} + +{$IFNDEF MSWINDOWS} +procedure TBlockSerial.GetCommState; +begin + SerialCheck(tcgetattr(FHandle, termiosstruc)); + ExceptCheck; + TermiostoDCB(termiosstruc, dcb); +end; +{$ELSE} +procedure TBlockSerial.GetCommState; +begin + SetSynaError(sOK); + if not windows.GetCommState(Fhandle, dcb) then + SerialCheck(sErr); + ExceptCheck; +end; +{$ENDIF} + +procedure TBlockSerial.SetSizeRecvBuffer(size: integer); +begin +{$IFDEF MSWINDOWS} + SetupComm(Fhandle, size, 0); + GetCommState; + dcb.XonLim := size div 4; + dcb.XoffLim := size div 4; + SetCommState; +{$ENDIF} + FRecvBuffer := size; +end; + +function TBlockSerial.GetDSR: Boolean; +begin + ModemStatus; +{$IFNDEF MSWINDOWS} + Result := (FModemWord and TIOCM_DSR) > 0; +{$ELSE} + Result := (FModemWord and MS_DSR_ON) > 0; +{$ENDIF} +end; + +procedure TBlockSerial.SetDTRF(Value: Boolean); +begin +{$IFNDEF MSWINDOWS} + ModemStatus; + if Value then + FModemWord := FModemWord or TIOCM_DTR + else + FModemWord := FModemWord and not TIOCM_DTR; + {$IFNDEF FPC} + ioctl(FHandle, TIOCMSET, @FModemWord); + {$ELSE} + fpioctl(FHandle, TIOCMSET, @FModemWord); + {$ENDIF} +{$ELSE} + if Value then + EscapeCommFunction(FHandle, SETDTR) + else + EscapeCommFunction(FHandle, CLRDTR); +{$ENDIF} +end; + +function TBlockSerial.GetCTS: Boolean; +begin + ModemStatus; +{$IFNDEF MSWINDOWS} + Result := (FModemWord and TIOCM_CTS) > 0; +{$ELSE} + Result := (FModemWord and MS_CTS_ON) > 0; +{$ENDIF} +end; + +procedure TBlockSerial.SetRTSF(Value: Boolean); +begin +{$IFNDEF MSWINDOWS} + ModemStatus; + if Value then + FModemWord := FModemWord or TIOCM_RTS + else + FModemWord := FModemWord and not TIOCM_RTS; + {$IFNDEF FPC} + ioctl(FHandle, TIOCMSET, @FModemWord); + {$ELSE} + fpioctl(FHandle, TIOCMSET, @FModemWord); + {$ENDIF} +{$ELSE} + if Value then + EscapeCommFunction(FHandle, SETRTS) + else + EscapeCommFunction(FHandle, CLRRTS); +{$ENDIF} +end; + +function TBlockSerial.GetCarrier: Boolean; +begin + ModemStatus; +{$IFNDEF MSWINDOWS} + Result := (FModemWord and TIOCM_CAR) > 0; +{$ELSE} + Result := (FModemWord and MS_RLSD_ON) > 0; +{$ENDIF} +end; + +function TBlockSerial.GetRing: Boolean; +begin + ModemStatus; +{$IFNDEF MSWINDOWS} + Result := (FModemWord and TIOCM_RNG) > 0; +{$ELSE} + Result := (FModemWord and MS_RING_ON) > 0; +{$ENDIF} +end; + +{$IFDEF MSWINDOWS} +function TBlockSerial.CanEvent(Event: dword; Timeout: integer): boolean; +var + ex: DWord; + y: Integer; + Overlapped: TOverlapped; +begin + FillChar(Overlapped, Sizeof(Overlapped), 0); + Overlapped.hEvent := CreateEvent(nil, True, False, nil); + try + SetCommMask(FHandle, Event); + SetSynaError(sOK); + if (Event = EV_RXCHAR) and (Waitingdata > 0) then + Result := True + else + begin + y := 0; + if not WaitCommEvent(FHandle, ex, @Overlapped) then + y := GetLastError; + if y = ERROR_IO_PENDING then + begin + //timedout + WaitForSingleObject(Overlapped.hEvent, Timeout); + SetCommMask(FHandle, 0); + GetOverlappedResult(FHandle, Overlapped, DWord(y), True); + end; + Result := (ex and Event) = Event; + end; + finally + SetCommMask(FHandle, 0); + CloseHandle(Overlapped.hEvent); + end; +end; +{$ENDIF} + +{$IFNDEF MSWINDOWS} +function TBlockSerial.CanRead(Timeout: integer): boolean; +var + FDSet: TFDSet; + TimeVal: PTimeVal; + TimeV: TTimeVal; + x: Integer; +begin + TimeV.tv_usec := (Timeout mod 1000) * 1000; + TimeV.tv_sec := Timeout div 1000; + TimeVal := @TimeV; + if Timeout = -1 then + TimeVal := nil; + {$IFNDEF FPC} + FD_ZERO(FDSet); + FD_SET(FHandle, FDSet); + x := Select(FHandle + 1, @FDSet, nil, nil, TimeVal); + {$ELSE} + fpFD_ZERO(FDSet); + fpFD_SET(FHandle, FDSet); + x := fpSelect(FHandle + 1, @FDSet, nil, nil, TimeVal); + {$ENDIF} + SerialCheck(x); + if FLastError <> sOK then + x := 0; + Result := x > 0; + ExceptCheck; + if Result then + DoStatus(HR_CanRead, ''); +end; +{$ELSE} +function TBlockSerial.CanRead(Timeout: integer): boolean; +begin + Result := WaitingData > 0; + if not Result then + Result := CanEvent(EV_RXCHAR, Timeout) or (WaitingData > 0); + //check WaitingData again due some broken virtual ports + if Result then + DoStatus(HR_CanRead, ''); +end; +{$ENDIF} + +{$IFNDEF MSWINDOWS} +function TBlockSerial.CanWrite(Timeout: integer): boolean; +var + FDSet: TFDSet; + TimeVal: PTimeVal; + TimeV: TTimeVal; + x: Integer; +begin + TimeV.tv_usec := (Timeout mod 1000) * 1000; + TimeV.tv_sec := Timeout div 1000; + TimeVal := @TimeV; + if Timeout = -1 then + TimeVal := nil; + {$IFNDEF FPC} + FD_ZERO(FDSet); + FD_SET(FHandle, FDSet); + x := Select(FHandle + 1, nil, @FDSet, nil, TimeVal); + {$ELSE} + fpFD_ZERO(FDSet); + fpFD_SET(FHandle, FDSet); + x := fpSelect(FHandle + 1, nil, @FDSet, nil, TimeVal); + {$ENDIF} + SerialCheck(x); + if FLastError <> sOK then + x := 0; + Result := x > 0; + ExceptCheck; + if Result then + DoStatus(HR_CanWrite, ''); +end; +{$ELSE} +function TBlockSerial.CanWrite(Timeout: integer): boolean; +var + t: LongWord; +begin + Result := SendingData = 0; + if not Result then + Result := CanEvent(EV_TXEMPTY, Timeout); + {$IFDEF WIN32} + if Result and (Win32Platform <> VER_PLATFORM_WIN32_NT) then + begin + t := GetTick; + while not ReadTxEmpty(FPortAddr) do + begin + if TickDelta(t, GetTick) > 255 then + Break; + Sleep(0); + end; + end; + {$ENDIF} + if Result then + DoStatus(HR_CanWrite, ''); +end; +{$ENDIF} + +function TBlockSerial.CanReadEx(Timeout: integer): boolean; +begin + if Fbuffer <> '' then + Result := True + else + Result := CanRead(Timeout); +end; + +procedure TBlockSerial.EnableRTSToggle(Value: boolean); +begin + SetSynaError(sOK); +{$IFNDEF MSWINDOWS} + FRTSToggle := Value; + if Value then + RTS:=False; +{$ELSE} + if Win32Platform = VER_PLATFORM_WIN32_NT then + begin + GetCommState; + if value then + dcb.Flags := dcb.Flags or dcb_RtsControlToggle + else + dcb.flags := dcb.flags and (not dcb_RtsControlToggle); + SetCommState; + end + else + begin + FRTSToggle := Value; + if Value then + RTS:=False; + end; +{$ENDIF} +end; + +procedure TBlockSerial.Flush; +begin +{$IFNDEF MSWINDOWS} + SerialCheck(tcdrain(FHandle)); +{$ELSE} + SetSynaError(sOK); + if not Flushfilebuffers(FHandle) then + SerialCheck(sErr); +{$ENDIF} + ExceptCheck; +end; + +{$IFNDEF MSWINDOWS} +procedure TBlockSerial.Purge; +begin + {$IFNDEF FPC} + SerialCheck(ioctl(FHandle, TCFLSH, TCIOFLUSH)); + {$ELSE} + {$IFDEF DARWIN} + SerialCheck(fpioctl(FHandle, TCIOflush, Pointer(TCIOFLUSH))); + {$ELSE} + SerialCheck(fpioctl(FHandle, {$IFDEF FreeBSD}TCIOFLUSH{$ELSE}TCFLSH{$ENDIF}, Pointer(PtrInt(TCIOFLUSH)))); + {$ENDIF} + {$ENDIF} + FBuffer := ''; + ExceptCheck; +end; +{$ELSE} +procedure TBlockSerial.Purge; +var + x: integer; +begin + SetSynaError(sOK); + x := PURGE_TXABORT or PURGE_TXCLEAR or PURGE_RXABORT or PURGE_RXCLEAR; + if not PurgeComm(FHandle, x) then + SerialCheck(sErr); + FBuffer := ''; + ExceptCheck; +end; +{$ENDIF} + +function TBlockSerial.ModemStatus: integer; +begin + Result := 0; +{$IFNDEF MSWINDOWS} + {$IFNDEF FPC} + SerialCheck(ioctl(FHandle, TIOCMGET, @Result)); + {$ELSE} + SerialCheck(fpioctl(FHandle, TIOCMGET, @Result)); + {$ENDIF} +{$ELSE} + SetSynaError(sOK); + if not GetCommModemStatus(FHandle, dword(Result)) then + SerialCheck(sErr); +{$ENDIF} + ExceptCheck; + FModemWord := Result; +end; + +procedure TBlockSerial.SetBreak(Duration: integer); +begin +{$IFNDEF MSWINDOWS} + SerialCheck(tcsendbreak(FHandle, Duration)); +{$ELSE} + SetCommBreak(FHandle); + Sleep(Duration); + SetSynaError(sOK); + if not ClearCommBreak(FHandle) then + SerialCheck(sErr); +{$ENDIF} +end; + +{$IFDEF MSWINDOWS} +procedure TBlockSerial.DecodeCommError(Error: DWord); +begin + if (Error and DWord(CE_FRAME)) > 1 then + FLastError := ErrFrame; + if (Error and DWord(CE_OVERRUN)) > 1 then + FLastError := ErrOverrun; + if (Error and DWord(CE_RXOVER)) > 1 then + FLastError := ErrRxOver; + if (Error and DWord(CE_RXPARITY)) > 1 then + FLastError := ErrRxParity; + if (Error and DWord(CE_TXFULL)) > 1 then + FLastError := ErrTxFull; +end; +{$ENDIF} + +//HGJ +function TBlockSerial.PreTestFailing: Boolean; +begin + if not FInstanceActive then + begin + RaiseSynaError(ErrPortNotOpen); + result:= true; + Exit; + end; + Result := not TestCtrlLine; + if result then + RaiseSynaError(ErrNoDeviceAnswer) +end; + +function TBlockSerial.TestCtrlLine: Boolean; +begin + result := ((not FTestDSR) or DSR) and ((not FTestCTS) or CTS); +end; + +function TBlockSerial.ATCommand(value: AnsiString): AnsiString; +var + s: AnsiString; + ConvSave: Boolean; +begin + result := ''; + FAtResult := False; + ConvSave := FConvertLineEnd; + try + FConvertLineEnd := True; + SendString(value + #$0D); + repeat + s := RecvString(FAtTimeout); + if s <> Value then + result := result + s + CRLF; + if s = 'OK' then + begin + FAtResult := True; + break; + end; + if s = 'ERROR' then + break; + until FLastError <> sOK; + finally + FConvertLineEnd := Convsave; + end; +end; + + +function TBlockSerial.ATConnect(value: AnsiString): AnsiString; +var + s: AnsiString; + ConvSave: Boolean; +begin + result := ''; + FAtResult := False; + ConvSave := FConvertLineEnd; + try + FConvertLineEnd := True; + SendString(value + #$0D); + repeat + s := RecvString(90 * FAtTimeout); + if s <> Value then + result := result + s + CRLF; + if s = 'NO CARRIER' then + break; + if s = 'ERROR' then + break; + if s = 'BUSY' then + break; + if s = 'NO DIALTONE' then + break; + if Pos('CONNECT', s) = 1 then + begin + FAtResult := True; + break; + end; + until FLastError <> sOK; + finally + FConvertLineEnd := Convsave; + end; +end; + +function TBlockSerial.SerialCheck(SerialResult: integer): integer; +begin + if SerialResult = integer(INVALID_HANDLE_VALUE) then +{$IFDEF MSWINDOWS} + result := GetLastError +{$ELSE} + {$IFNDEF FPC} + result := GetLastError + {$ELSE} + result := fpGetErrno + {$ENDIF} +{$ENDIF} + else + result := sOK; + FLastError := result; + FLastErrorDesc := GetErrorDesc(FLastError); +end; + +procedure TBlockSerial.ExceptCheck; +var + e: ESynaSerError; + s: string; +begin + if FRaiseExcept and (FLastError <> sOK) then + begin + s := GetErrorDesc(FLastError); + e := ESynaSerError.CreateFmt('Communication error %d: %s', [FLastError, s]); + e.ErrorCode := FLastError; + e.ErrorMessage := s; + raise e; + end; +end; + +procedure TBlockSerial.SetSynaError(ErrNumber: integer); +begin + FLastError := ErrNumber; + FLastErrorDesc := GetErrorDesc(FLastError); +end; + +procedure TBlockSerial.RaiseSynaError(ErrNumber: integer); +begin + SetSynaError(ErrNumber); + ExceptCheck; +end; + +procedure TBlockSerial.DoStatus(Reason: THookSerialReason; const Value: string); +begin + if assigned(OnStatus) then + OnStatus(Self, Reason, Value); +end; + +{======================================================================} + +class function TBlockSerial.GetErrorDesc(ErrorCode: integer): string; +begin + Result:= ''; + case ErrorCode of + sOK: Result := 'OK'; + ErrAlreadyOwned: Result := 'Port owned by other process';{HGJ} + ErrAlreadyInUse: Result := 'Instance already in use'; {HGJ} + ErrWrongParameter: Result := 'Wrong parameter at call'; {HGJ} + ErrPortNotOpen: Result := 'Instance not yet connected'; {HGJ} + ErrNoDeviceAnswer: Result := 'No device answer detected'; {HGJ} + ErrMaxBuffer: Result := 'Maximal buffer length exceeded'; + ErrTimeout: Result := 'Timeout during operation'; + ErrNotRead: Result := 'Reading of data failed'; + ErrFrame: Result := 'Receive framing error'; + ErrOverrun: Result := 'Receive Overrun Error'; + ErrRxOver: Result := 'Receive Queue overflow'; + ErrRxParity: Result := 'Receive Parity Error'; + ErrTxFull: Result := 'Tranceive Queue is full'; + end; + if Result = '' then + begin + Result := SysErrorMessage(ErrorCode); + end; +end; + + +{---------- cpom Comport Ownership Manager Routines ------------- + by Hans-Georg Joepgen of Stuttgart, Germany. + Copyright (c) 2002, by Hans-Georg Joepgen + + Stefan Krauss of Stuttgart, Germany, contributed literature and Internet + research results, invaluable advice and excellent answers to the Comport + Ownership Manager. +} + +{$IFDEF UNIX} + +function TBlockSerial.LockfileName: String; +var + s: string; +begin + s := SeparateRight(FDevice, '/dev/'); + result := LockfileDirectory + '/LCK..' + s; +end; + +procedure TBlockSerial.CreateLockfile(PidNr: integer); +var + f: TextFile; + s: string; +begin + // Create content for file + s := IntToStr(PidNr); + while length(s) < 10 do + s := ' ' + s; + // Create file + try + AssignFile(f, LockfileName); + try + Rewrite(f); + writeln(f, s); + finally + CloseFile(f); + end; + // Allow all users to enjoy the benefits of cpom + s := 'chmod a+rw ' + LockfileName; +{$IFNDEF FPC} + FileSetReadOnly( LockfileName, False ) ; + // Libc.system(pchar(s)); +{$ELSE} + fpSystem(s); +{$ENDIF} + except + // not raise exception, if you not have write permission for lock. + on Exception do + ; + end; +end; + +function TBlockSerial.ReadLockfile: integer; +{Returns PID from Lockfile. Lockfile must exist.} +var + f: TextFile; + s: string; +begin + AssignFile(f, LockfileName); + Reset(f); + try + readln(f, s); + finally + CloseFile(f); + end; + Result := StrToIntDef(s, -1) +end; + +function TBlockSerial.cpomComportAccessible: boolean; +var + MyPid: integer; + Filename: string; +begin + Filename := LockfileName; + {$IFNDEF FPC} + MyPid := Libc.getpid; + {$ELSE} + MyPid := fpGetPid; + {$ENDIF} + // Make sure, the Lock Files Directory exists. We need it. + if not DirectoryExists(LockfileDirectory) then + CreateDir(LockfileDirectory); + // Check the Lockfile + if not FileExists (Filename) then + begin // comport is not locked. Lock it for us. + CreateLockfile(MyPid); + result := true; + exit; // done. + end; + // Is port owned by orphan? Then it's time for error recovery. + //FPC forgot to add getsid.. :-( + {$IFNDEF FPC} + if Libc.getsid(ReadLockfile) = -1 then + begin // Lockfile was left from former desaster + DeleteFile(Filename); // error recovery + CreateLockfile(MyPid); + result := true; + exit; + end; + {$ENDIF} + result := false // Sorry, port is owned by living PID and locked +end; + +procedure TBlockSerial.cpomReleaseComport; +begin + DeleteFile(LockfileName); +end; + +{$ENDIF} +{----------------------------------------------------------------} + +{$IFDEF MSWINDOWS} +function GetSerialPortNames: string; +var + reg: TRegistry; + l, v: TStringList; + n: integer; +begin + l := TStringList.Create; + v := TStringList.Create; + reg := TRegistry.Create; + try +{$IFNDEF VER100} +{$IFNDEF VER120} + reg.Access := KEY_READ; +{$ENDIF} +{$ENDIF} + reg.RootKey := HKEY_LOCAL_MACHINE; + reg.OpenKey('\HARDWARE\DEVICEMAP\SERIALCOMM', false); + reg.GetValueNames(l); + for n := 0 to l.Count - 1 do + v.Add(reg.ReadString(l[n])); + Result := v.CommaText; + finally + reg.Free; + l.Free; + v.Free; + end; +end; +{$ENDIF} +{$IFNDEF MSWINDOWS} +function GetSerialPortNames: string; +var + sr : TSearchRec; +begin + Result := ''; + if FindFirst('/dev/ttyS*', $FFFFFFFF, sr) = 0 then + begin + repeat + if (sr.Attr and $FFFFFFFF) = Sr.Attr then + begin + if Result <> '' then + Result := Result + ','; + Result := Result + sr.Name; + end; + until FindNext(sr) <> 0; + end; + FindClose(sr); +end; +{$ENDIF} + end. \ No newline at end of file diff --git a/3rd/synapse/source/synautil.pas b/3rd/synapse/source/synautil.pas index e421840cc..b275d70ca 100644 --- a/3rd/synapse/source/synautil.pas +++ b/3rd/synapse/source/synautil.pas @@ -1,2124 +1,2124 @@ -{==============================================================================| -| Project : Ararat Synapse | 004.015.006 | -|==============================================================================| -| Content: support procedures and functions | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2013. | -| Portions created by Hernan Sanchez are Copyright (c) 2000. | -| Portions created by Petr Fejfar are Copyright (c)2011-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Hernan Sanchez (hernan.sanchez@iname.com) | -| Tomas Hajny (OS2 support) | -| Radek Cervinka (POSIX support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Support procedures and functions)} - -{$I jedi.inc} // load common compiler defines - -{$Q-} -{$R-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit synautil; - -interface - -uses -{$IFDEF MSWINDOWS} - Windows, -{$ELSE MSWINDOWS} - {$IFDEF FPC} - {$IFDEF OS2} - Dos, TZUtil, - {$ELSE OS2} - UnixUtil, Unix, BaseUnix, - {$ENDIF OS2} - {$ELSE FPC} - {$IFDEF POSIX} - Posix.Base, Posix.Time, Posix.SysTypes, Posix.SysTime, Posix.Stdio, - {$ELSE} - Libc, - {$ENDIF} - {$ENDIF} -{$ENDIF} -{$IFDEF CIL} - System.IO, -{$ENDIF} - SysUtils, Classes, SynaFpc; - -{$IFDEF VER100} -type - int64 = integer; -{$ENDIF} -{$IFDEF POSIX} -type - TTimeVal = Posix.SysTime.timeval; - Ttimezone = record - tz_minuteswest: Integer ; // minutes west of Greenwich - tz_dsttime: integer ; // type of DST correction - end; - - PTimeZone = ^Ttimezone; -{$ENDIF} - - -{:Return your timezone bias from UTC time in minutes.} -function TimeZoneBias: integer; - -{:Return your timezone bias from UTC time in string representation like "+0200".} -function TimeZone: string; - -{:Returns current time in format defined in RFC-822. Useful for SMTP messages, - but other protocols use this time format as well. Results contains the timezone - specification. Four digit year is used to break any Y2K concerns. (Example - 'Fri, 15 Oct 1999 21:14:56 +0200')} -function Rfc822DateTime(t: TDateTime): string; - -{:Returns date and time in format defined in C compilers in format "mmm dd hh:nn:ss"} -function CDateTime(t: TDateTime): string; - -{:Returns date and time in format defined in format 'yymmdd hhnnss'} -function SimpleDateTime(t: TDateTime): string; - -{:Returns date and time in format defined in ANSI C compilers in format - "ddd mmm d hh:nn:ss yyyy" } -function AnsiCDateTime(t: TDateTime): string; - -{:Decode three-letter string with name of month to their month number. If string - not match any month name, then is returned 0. For parsing are used predefined - names for English, French and German and names from system locale too.} -function GetMonthNumber(Value: String): integer; - -{:Return decoded time from given string. Time must be witch separator ':'. You - can use "hh:mm" or "hh:mm:ss".} -function GetTimeFromStr(Value: string): TDateTime; - -{:Decode string representation of TimeZone (CEST, GMT, +0200, -0800, etc.) - to timezone offset.} -function DecodeTimeZone(Value: string; var Zone: integer): Boolean; - -{:Decode string in format "m-d-y" to TDateTime type.} -function GetDateMDYFromStr(Value: string): TDateTime; - -{:Decode various string representations of date and time to Tdatetime type. - This function do all timezone corrections too! This function can decode lot of - formats like: - @longcode(# - ddd, d mmm yyyy hh:mm:ss - ddd, d mmm yy hh:mm:ss - ddd, mmm d yyyy hh:mm:ss - ddd mmm dd hh:mm:ss yyyy #) - -and more with lot of modifications, include: -@longcode(# -Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 -Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 -Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format -#) -Timezone corrections known lot of symbolic timezone names (like CEST, EDT, etc.) -or numeric representation (like +0200). By convention defined in RFC timezone - +0000 is GMT and -0000 is current your system timezone.} -function DecodeRfcDateTime(Value: string): TDateTime; - -{:Return current system date and time in UTC timezone.} -function GetUTTime: TDateTime; - -{:Set Newdt as current system date and time in UTC timezone. This function work - only if you have administrator rights!} -function SetUTTime(Newdt: TDateTime): Boolean; - -{:Return current value of system timer with precizion 1 millisecond. Good for - measure time difference.} -function GetTick: LongWord; - -{:Return difference between two timestamps. It working fine only for differences - smaller then maxint. (difference must be smaller then 24 days.)} -function TickDelta(TickOld, TickNew: LongWord): LongWord; - -{:Return two characters, which ordinal values represents the value in byte - format. (High-endian)} -function CodeInt(Value: Word): Ansistring; - -{:Decodes two characters located at "Index" offset position of the "Value" - string to Word values.} -function DecodeInt(const Value: Ansistring; Index: Integer): Word; - -{:Return four characters, which ordinal values represents the value in byte - format. (High-endian)} -function CodeLongInt(Value: LongInt): Ansistring; - -{:Decodes four characters located at "Index" offset position of the "Value" - string to LongInt values.} -function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; - -{:Dump binary buffer stored in a string to a result string.} -function DumpStr(const Buffer: Ansistring): string; - -{:Dump binary buffer stored in a string to a result string. All bytes with code - of character is written as character, not as hexadecimal value.} -function DumpExStr(const Buffer: Ansistring): string; - -{:Dump binary buffer stored in a string to a file with DumpFile filename.} -procedure Dump(const Buffer: AnsiString; DumpFile: string); - -{:Dump binary buffer stored in a string to a file with DumpFile filename. All - bytes with code of character is written as character, not as hexadecimal value.} -procedure DumpEx(const Buffer: AnsiString; DumpFile: string); - -{:Like TrimLeft, but remove only spaces, not control characters!} -function TrimSPLeft(const S: string): string; - -{:Like TrimRight, but remove only spaces, not control characters!} -function TrimSPRight(const S: string): string; - -{:Like Trim, but remove only spaces, not control characters!} -function TrimSP(const S: string): string; - -{:Returns a portion of the "Value" string located to the left of the "Delimiter" - string. If a delimiter is not found, results is original string.} -function SeparateLeft(const Value, Delimiter: string): string; - -{:Returns the portion of the "Value" string located to the right of the - "Delimiter" string. If a delimiter is not found, results is original string.} -function SeparateRight(const Value, Delimiter: string): string; - -{:Returns parameter value from string in format: - parameter1="value1"; parameter2=value2} -function GetParameter(const Value, Parameter: string): string; - -{:parse value string with elements differed by Delimiter into stringlist.} -procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); - -{:parse value string with elements differed by ';' into stringlist.} -procedure ParseParameters(Value: string; const Parameters: TStrings); - -{:Index of string in stringlist with same beginning as Value is returned.} -function IndexByBegin(Value: string; const List: TStrings): integer; - -{:Returns only the e-mail portion of an address from the full address format. - i.e. returns 'nobody@@somewhere.com' from '"someone" '} -function GetEmailAddr(const Value: string): string; - -{:Returns only the description part from a full address format. i.e. returns - 'someone' from '"someone" '} -function GetEmailDesc(Value: string): string; - -{:Returns a string with hexadecimal digits representing the corresponding values - of the bytes found in "Value" string.} -function StrToHex(const Value: Ansistring): string; - -{:Returns a string of binary "Digits" representing "Value".} -function IntToBin(Value: Integer; Digits: Byte): string; - -{:Returns an integer equivalent of the binary string in "Value". - (i.e. ('10001010') returns 138)} -function BinToInt(const Value: string): Integer; - -{:Parses a URL to its various components.} -function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, - Para: string): string; - -{:Replaces all "Search" string values found within "Value" string, with the - "Replace" string value.} -function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; - -{:It is like RPos, but search is from specified possition.} -function RPosEx(const Sub, Value: string; From: integer): Integer; - -{:It is like POS function, but from right side of Value string.} -function RPos(const Sub, Value: String): Integer; - -{:Like @link(fetch), but working with binary strings, not with text.} -function FetchBin(var Value: string; const Delimiter: string): string; - -{:Fetch string from left of Value string.} -function Fetch(var Value: string; const Delimiter: string): string; - -{:Fetch string from left of Value string. This function ignore delimitesr inside - quotations.} -function FetchEx(var Value: string; const Delimiter, Quotation: string): string; - -{:If string is binary string (contains non-printable characters), then is - returned true.} -function IsBinaryString(const Value: AnsiString): Boolean; - -{:return position of string terminator in string. If terminator found, then is - returned in terminator parameter. - Possible line terminators are: CRLF, LFCR, CR, LF} -function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; - -{:Delete empty strings from end of stringlist.} -Procedure StringsTrim(const value: TStrings); - -{:Like Pos function, buf from given string possition.} -function PosFrom(const SubStr, Value: String; From: integer): integer; - -{$IFNDEF CIL} -{:Increase pointer by value.} -function IncPoint(const p: pointer; Value: integer): pointer; -{$ENDIF} - -{:Get string between PairBegin and PairEnd. This function respect nesting. - For example: - @longcode(# - Value is: 'Hi! (hello(yes!))' - pairbegin is: '(' - pairend is: ')' - In this case result is: 'hello(yes!)'#)} -function GetBetween(const PairBegin, PairEnd, Value: string): string; - -{:Return count of Chr in Value string.} -function CountOfChar(const Value: string; Chr: char): integer; - -{:Remove quotation from Value string. If Value is not quoted, then return same - string without any modification. } -function UnquoteStr(const Value: string; Quote: Char): string; - -{:Quote Value string. If Value contains some Quote chars, then it is doubled.} -function QuoteStr(const Value: string; Quote: Char): string; - -{:Convert lines in stringlist from 'name: value' form to 'name=value' form.} -procedure HeadersToList(const Value: TStrings); - -{:Convert lines in stringlist from 'name=value' form to 'name: value' form.} -procedure ListToHeaders(const Value: TStrings); - -{:swap bytes in integer.} -function SwapBytes(Value: integer): integer; - -{:read string with requested length form stream.} -function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; - -{:write string to stream.} -procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); - -{:Return filename of new temporary file in Dir (if empty, then default temporary - directory is used) and with optional filename prefix.} -function GetTempFile(const Dir, prefix: String): String; - -{:Return padded string. If length is greater, string is truncated. If length is - smaller, string is padded by Pad character.} -function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; - -{:XOR each byte in the strings} -function XorString(Indata1, Indata2: AnsiString): AnsiString; - -{:Read header from "Value" stringlist beginning at "Index" position. If header - is Splitted into multiple lines, then this procedure de-split it into one line.} -function NormalizeHeader(Value: TStrings; var Index: Integer): string; - -{pf} -{:Search for one of line terminators CR, LF or NUL. Return position of the - line beginning and length of text.} -procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); -{:Skip both line terminators CR LF (if any). Move APtr position forward.} -procedure SkipLineBreak(var APtr:PANSIChar; AEtx:PANSIChar); -{:Skip all blank lines in a buffer starting at APtr and move APtr position forward.} -procedure SkipNullLines (var APtr:PANSIChar; AEtx:PANSIChar); -{:Copy all lines from a buffer starting at APtr to ALines until empty line - or end of the buffer is reached. Move APtr position forward).} -procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); -{:Copy all lines from a buffer starting at APtr to ALines until ABoundary - or end of the buffer is reached. Move APtr position forward).} -procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); -{:Search ABoundary in a buffer starting at APtr. - Return beginning of the ABoundary. Move APtr forward behind a trailing CRLF if any).} -function SearchForBoundary (var APtr:PANSIChar; AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; -{:Compare a text at position ABOL with ABoundary and return position behind the - match (including a trailing CRLF if any).} -function MatchBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; -{:Compare a text at position ABOL with ABoundary + the last boundary suffix - and return position behind the match (including a trailing CRLF if any).} -function MatchLastBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; -{:Copy data from a buffer starting at position APtr and delimited by AEtx - position into ANSIString.} -function BuildStringFromBuffer (AStx,AEtx:PANSIChar): ANSIString; -{/pf} - -var - {:can be used for your own months strings for @link(getmonthnumber)} - CustomMonthNames: array[1..12] of string; - -implementation - -{==============================================================================} - -const - MyDayNames: array[1..7] of AnsiString = - ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); -var - MyMonthNames: array[0..6, 1..12] of String = - ( - ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //rewrited by system locales - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), - ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //English - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), - ('jan', 'f�v', 'mar', 'avr', 'mai', 'jun', //French - 'jul', 'ao�', 'sep', 'oct', 'nov', 'd�c'), - ('jan', 'fev', 'mar', 'avr', 'mai', 'jun', //French#2 - 'jul', 'aou', 'sep', 'oct', 'nov', 'dec'), - ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', //German - 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), - ('Jan', 'Feb', 'M�r', 'Apr', 'Mai', 'Jun', //German#2 - 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), - ('Led', '�no', 'B�e', 'Dub', 'Kv�', '�en', //Czech - '�ec', 'Srp', 'Z��', '��j', 'Lis', 'Pro') - ); - - -{==============================================================================} - -function TimeZoneBias: integer; -{$IFNDEF MSWINDOWS} -{$IFNDEF FPC} -var -{$IFDEF POSIX} - t: Posix.SysTypes.time_t; - UT: Posix.time.tm; -{$ELSE} - t: TTime_T; - UT: TUnixTime; -{$ENDIF} -begin - {$IFDEF POSIX} - __time(T); - localtime_r(T, UT); - Result := UT.tm_gmtoff div 60; - {$ELSE} - __time(@T); - localtime_r(@T, UT); - Result := ut.__tm_gmtoff div 60; - {$ENDIF} -{$ELSE} -begin - Result := TZSeconds div 60; -{$ENDIF} -{$ELSE} -var - zoneinfo: TTimeZoneInformation; - bias: Integer; -begin - case GetTimeZoneInformation(Zoneinfo) of - 2: - bias := zoneinfo.Bias + zoneinfo.DaylightBias; - 1: - bias := zoneinfo.Bias + zoneinfo.StandardBias; - else - bias := zoneinfo.Bias; - end; - Result := bias * (-1); -{$ENDIF} -end; - -{==============================================================================} - -function TimeZone: string; -var - bias: Integer; - h, m: Integer; -begin - bias := TimeZoneBias; - if bias >= 0 then - Result := '+' - else - Result := '-'; - bias := Abs(bias); - h := bias div 60; - m := bias mod 60; - Result := Result + Format('%.2d%.2d', [h, m]); -end; - -{==============================================================================} - -function Rfc822DateTime(t: TDateTime): string; -var - wYear, wMonth, wDay: word; -begin - DecodeDate(t, wYear, wMonth, wDay); - Result := Format('%s, %d %s %s %s', [MyDayNames[DayOfWeek(t)], wDay, - MyMonthNames[1, wMonth], FormatDateTime('yyyy hh":"nn":"ss', t), TimeZone]); -end; - -{==============================================================================} - -function CDateTime(t: TDateTime): string; -var - wYear, wMonth, wDay: word; -begin - DecodeDate(t, wYear, wMonth, wDay); - Result:= Format('%s %2d %s', [MyMonthNames[1, wMonth], wDay, - FormatDateTime('hh":"nn":"ss', t)]); -end; - -{==============================================================================} - -function SimpleDateTime(t: TDateTime): string; -begin - Result := FormatDateTime('yymmdd hhnnss', t); -end; - -{==============================================================================} - -function AnsiCDateTime(t: TDateTime): string; -var - wYear, wMonth, wDay: word; -begin - DecodeDate(t, wYear, wMonth, wDay); - Result := Format('%s %s %d %s', [MyDayNames[DayOfWeek(t)], MyMonthNames[1, wMonth], - wDay, FormatDateTime('hh":"nn":"ss yyyy ', t)]); -end; - -{==============================================================================} - -function DecodeTimeZone(Value: string; var Zone: integer): Boolean; -var - x: integer; - zh, zm: integer; - s: string; -begin - Result := false; - s := Value; - if (Pos('+', s) = 1) or (Pos('-',s) = 1) then - begin - if s = '-0000' then - Zone := TimeZoneBias - else - if Length(s) > 4 then - begin - zh := StrToIntdef(s[2] + s[3], 0); - zm := StrToIntdef(s[4] + s[5], 0); - zone := zh * 60 + zm; - if s[1] = '-' then - zone := zone * (-1); - end; - Result := True; - end - else - begin - x := 32767; - if s = 'NZDT' then x := 13; - if s = 'IDLE' then x := 12; - if s = 'NZST' then x := 12; - if s = 'NZT' then x := 12; - if s = 'EADT' then x := 11; - if s = 'GST' then x := 10; - if s = 'JST' then x := 9; - if s = 'CCT' then x := 8; - if s = 'WADT' then x := 8; - if s = 'WAST' then x := 7; - if s = 'ZP6' then x := 6; - if s = 'ZP5' then x := 5; - if s = 'ZP4' then x := 4; - if s = 'BT' then x := 3; - if s = 'EET' then x := 2; - if s = 'MEST' then x := 2; - if s = 'MESZ' then x := 2; - if s = 'SST' then x := 2; - if s = 'FST' then x := 2; - if s = 'CEST' then x := 2; - if s = 'CET' then x := 1; - if s = 'FWT' then x := 1; - if s = 'MET' then x := 1; - if s = 'MEWT' then x := 1; - if s = 'SWT' then x := 1; - if s = 'UT' then x := 0; - if s = 'UTC' then x := 0; - if s = 'GMT' then x := 0; - if s = 'WET' then x := 0; - if s = 'WAT' then x := -1; - if s = 'BST' then x := -1; - if s = 'AT' then x := -2; - if s = 'ADT' then x := -3; - if s = 'AST' then x := -4; - if s = 'EDT' then x := -4; - if s = 'EST' then x := -5; - if s = 'CDT' then x := -5; - if s = 'CST' then x := -6; - if s = 'MDT' then x := -6; - if s = 'MST' then x := -7; - if s = 'PDT' then x := -7; - if s = 'PST' then x := -8; - if s = 'YDT' then x := -8; - if s = 'YST' then x := -9; - if s = 'HDT' then x := -9; - if s = 'AHST' then x := -10; - if s = 'CAT' then x := -10; - if s = 'HST' then x := -10; - if s = 'EAST' then x := -10; - if s = 'NT' then x := -11; - if s = 'IDLW' then x := -12; - if x <> 32767 then - begin - zone := x * 60; - Result := True; - end; - end; -end; - -{==============================================================================} - -function GetMonthNumber(Value: String): integer; -var - n: integer; - function TestMonth(Value: String; Index: Integer): Boolean; - var - n: integer; - begin - Result := False; - for n := 0 to 6 do - if Value = AnsiUppercase(MyMonthNames[n, Index]) then - begin - Result := True; - Break; - end; - end; -begin - Result := 0; - Value := AnsiUppercase(Value); - for n := 1 to 12 do - if TestMonth(Value, n) or (Value = AnsiUppercase(CustomMonthNames[n])) then - begin - Result := n; - Break; - end; -end; - -{==============================================================================} - -function GetTimeFromStr(Value: string): TDateTime; -var - x: integer; -begin - x := rpos(':', Value); - if (x > 0) and ((Length(Value) - x) > 2) then - Value := Copy(Value, 1, x + 2); - Value := ReplaceString(Value, ':', {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}TimeSeparator); - Result := -1; - try - Result := StrToTime(Value); - except - on Exception do ; - end; -end; - -{==============================================================================} - -function GetDateMDYFromStr(Value: string): TDateTime; -var - wYear, wMonth, wDay: word; - s: string; -begin - Result := 0; - s := Fetch(Value, '-'); - wMonth := StrToIntDef(s, 12); - s := Fetch(Value, '-'); - wDay := StrToIntDef(s, 30); - wYear := StrToIntDef(Value, 1899); - if wYear < 1000 then - if (wYear > 99) then - wYear := wYear + 1900 - else - if wYear > 50 then - wYear := wYear + 1900 - else - wYear := wYear + 2000; - try - Result := EncodeDate(wYear, wMonth, wDay); - except - on Exception do ; - end; -end; - -{==============================================================================} - -function DecodeRfcDateTime(Value: string): TDateTime; -var - day, month, year: Word; - zone: integer; - x, y: integer; - s: string; - t: TDateTime; -begin -// ddd, d mmm yyyy hh:mm:ss -// ddd, d mmm yy hh:mm:ss -// ddd, mmm d yyyy hh:mm:ss -// ddd mmm dd hh:mm:ss yyyy -// Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 -// Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 -// Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format - - Result := 0; - if Value = '' then - Exit; - day := 0; - month := 0; - year := 0; - zone := 0; - Value := ReplaceString(Value, ' -', ' #'); - Value := ReplaceString(Value, '-', ' '); - Value := ReplaceString(Value, ' #', ' -'); - while Value <> '' do - begin - s := Fetch(Value, ' '); - s := uppercase(s); - // timezone - if DecodetimeZone(s, x) then - begin - zone := x; - continue; - end; - x := StrToIntDef(s, 0); - // day or year - if x > 0 then - if (x < 32) and (day = 0) then - begin - day := x; - continue; - end - else - begin - if (year = 0) and ((month > 0) or (x > 12)) then - begin - year := x; - if year < 32 then - year := year + 2000; - if year < 1000 then - year := year + 1900; - continue; - end; - end; - // time - if rpos(':', s) > Pos(':', s) then - begin - t := GetTimeFromStr(s); - if t <> -1 then - Result := t; - continue; - end; - //timezone daylight saving time - if s = 'DST' then - begin - zone := zone + 60; - continue; - end; - // month - y := GetMonthNumber(s); - if (y > 0) and (month = 0) then - month := y; - end; - if year = 0 then - year := 1980; - if month < 1 then - month := 1; - if month > 12 then - month := 12; - if day < 1 then - day := 1; - x := MonthDays[IsLeapYear(year), month]; - if day > x then - day := x; - Result := Result + Encodedate(year, month, day); - zone := zone - TimeZoneBias; - x := zone div 1440; - Result := Result - x; - zone := zone mod 1440; - t := EncodeTime(Abs(zone) div 60, Abs(zone) mod 60, 0, 0); - if zone < 0 then - t := 0 - t; - Result := Result - t; -end; - -{==============================================================================} - -function GetUTTime: TDateTime; -{$IFDEF MSWINDOWS} -{$IFNDEF FPC} -var - st: TSystemTime; -begin - GetSystemTime(st); - result := SystemTimeToDateTime(st); -{$ELSE} -var - st: SysUtils.TSystemTime; - stw: Windows.TSystemTime; -begin - GetSystemTime(stw); - st.Year := stw.wYear; - st.Month := stw.wMonth; - st.Day := stw.wDay; - st.Hour := stw.wHour; - st.Minute := stw.wMinute; - st.Second := stw.wSecond; - st.Millisecond := stw.wMilliseconds; - result := SystemTimeToDateTime(st); -{$ENDIF} -{$ELSE MSWINDOWS} -{$IFNDEF FPC} -var - TV: TTimeVal; -begin - gettimeofday(TV, nil); - Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; -{$ELSE FPC} - {$IFDEF UNIX} -var - TV: TimeVal; -begin - fpgettimeofday(@TV, nil); - Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; - {$ELSE UNIX} - {$IFDEF OS2} -var - ST: TSystemTime; -begin - GetLocalTime (ST); - Result := SystemTimeToDateTime (ST); - {$ENDIF OS2} - {$ENDIF UNIX} -{$ENDIF FPC} -{$ENDIF MSWINDOWS} -end; - -{==============================================================================} - -function SetUTTime(Newdt: TDateTime): Boolean; -{$IFDEF MSWINDOWS} -{$IFNDEF FPC} -var - st: TSystemTime; -begin - DateTimeToSystemTime(newdt,st); - Result := SetSystemTime(st); -{$ELSE} -var - st: SysUtils.TSystemTime; - stw: Windows.TSystemTime; -begin - DateTimeToSystemTime(newdt,st); - stw.wYear := st.Year; - stw.wMonth := st.Month; - stw.wDay := st.Day; - stw.wHour := st.Hour; - stw.wMinute := st.Minute; - stw.wSecond := st.Second; - stw.wMilliseconds := st.Millisecond; - Result := SetSystemTime(stw); -{$ENDIF} -{$ELSE MSWINDOWS} -{$IFNDEF FPC} -var - TV: TTimeVal; - d: double; - TZ: Ttimezone; - PZ: PTimeZone; -begin - TZ.tz_minuteswest := 0; - TZ.tz_dsttime := 0; - PZ := @TZ; - gettimeofday(TV, PZ); - d := (newdt - UnixDateDelta) * 86400; - TV.tv_sec := trunc(d); - TV.tv_usec := trunc(frac(d) * 1000000); - {$IFNDEF POSIX} - Result := settimeofday(TV, TZ) <> -1; - {$ELSE} - Result := False; // in POSIX settimeofday is not defined? http://www.kernel.org/doc/man-pages/online/pages/man2/gettimeofday.2.html - {$ENDIF} -{$ELSE FPC} - {$IFDEF UNIX} -var - TV: TimeVal; - d: double; -begin - d := (newdt - UnixDateDelta) * 86400; - TV.tv_sec := trunc(d); - TV.tv_usec := trunc(frac(d) * 1000000); - Result := fpsettimeofday(@TV, nil) <> -1; - {$ELSE UNIX} - {$IFDEF OS2} -var - ST: TSystemTime; -begin - DateTimeToSystemTime (NewDT, ST); - SetTime (ST.Hour, ST.Minute, ST.Second, ST.Millisecond div 10); - Result := true; - {$ENDIF OS2} - {$ENDIF UNIX} -{$ENDIF FPC} -{$ENDIF MSWINDOWS} -end; - -{==============================================================================} - -{$IFNDEF MSWINDOWS} -function GetTick: LongWord; -var - Stamp: TTimeStamp; -begin - Stamp := DateTimeToTimeStamp(Now); - Result := Stamp.Time; -end; -{$ELSE} -function GetTick: LongWord; -var - tick, freq: TLargeInteger; -{$IFDEF VER100} - x: TLargeInteger; -{$ENDIF} -begin - if Windows.QueryPerformanceFrequency(freq) then - begin - Windows.QueryPerformanceCounter(tick); -{$IFDEF VER100} - x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000; - Result := x.LowPart; -{$ELSE} - Result := Trunc((tick / freq) * 1000) and High(LongWord) -{$ENDIF} - end - else - Result := Windows.GetTickCount; -end; -{$ENDIF} - -{==============================================================================} - -function TickDelta(TickOld, TickNew: LongWord): LongWord; -begin -//if DWord is signed type (older Deplhi), -// then it not work properly on differencies larger then maxint! - Result := 0; - if TickOld <> TickNew then - begin - if TickNew < TickOld then - begin - TickNew := TickNew + LongWord(MaxInt) + 1; - TickOld := TickOld + LongWord(MaxInt) + 1; - end; - Result := TickNew - TickOld; - if TickNew < TickOld then - if Result > 0 then - Result := 0 - Result; - end; -end; - -{==============================================================================} - -function CodeInt(Value: Word): Ansistring; -begin - setlength(result, 2); - result[1] := AnsiChar(Value div 256); - result[2] := AnsiChar(Value mod 256); -// Result := AnsiChar(Value div 256) + AnsiChar(Value mod 256) -end; - -{==============================================================================} - -function DecodeInt(const Value: Ansistring; Index: Integer): Word; -var - x, y: Byte; -begin - if Length(Value) > Index then - x := Ord(Value[Index]) - else - x := 0; - if Length(Value) >= (Index + 1) then - y := Ord(Value[Index + 1]) - else - y := 0; - Result := x * 256 + y; -end; - -{==============================================================================} - -function CodeLongInt(Value: Longint): Ansistring; -var - x, y: word; -begin - // this is fix for negative numbers on systems where longint = integer - x := (Value shr 16) and integer($ffff); - y := Value and integer($ffff); - setlength(result, 4); - result[1] := AnsiChar(x div 256); - result[2] := AnsiChar(x mod 256); - result[3] := AnsiChar(y div 256); - result[4] := AnsiChar(y mod 256); -end; - -{==============================================================================} - -function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; -var - x, y: Byte; - xl, yl: Byte; -begin - if Length(Value) > Index then - x := Ord(Value[Index]) - else - x := 0; - if Length(Value) >= (Index + 1) then - y := Ord(Value[Index + 1]) - else - y := 0; - if Length(Value) >= (Index + 2) then - xl := Ord(Value[Index + 2]) - else - xl := 0; - if Length(Value) >= (Index + 3) then - yl := Ord(Value[Index + 3]) - else - yl := 0; - Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); -end; - -{==============================================================================} - -function DumpStr(const Buffer: Ansistring): string; -var - n: Integer; -begin - Result := ''; - for n := 1 to Length(Buffer) do - Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); -end; - -{==============================================================================} - -function DumpExStr(const Buffer: Ansistring): string; -var - n: Integer; - x: Byte; -begin - Result := ''; - for n := 1 to Length(Buffer) do - begin - x := Ord(Buffer[n]); - if x in [65..90, 97..122] then - Result := Result + ' +''' + char(x) + '''' - else - Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); - end; -end; - -{==============================================================================} - -procedure Dump(const Buffer: AnsiString; DumpFile: string); -var - f: Text; -begin - AssignFile(f, DumpFile); - if FileExists(DumpFile) then - DeleteFile(DumpFile); - Rewrite(f); - try - Writeln(f, DumpStr(Buffer)); - finally - CloseFile(f); - end; -end; - -{==============================================================================} - -procedure DumpEx(const Buffer: AnsiString; DumpFile: string); -var - f: Text; -begin - AssignFile(f, DumpFile); - if FileExists(DumpFile) then - DeleteFile(DumpFile); - Rewrite(f); - try - Writeln(f, DumpExStr(Buffer)); - finally - CloseFile(f); - end; -end; - -{==============================================================================} - -function TrimSPLeft(const S: string): string; -var - I, L: Integer; -begin - Result := ''; - if S = '' then - Exit; - L := Length(S); - I := 1; - while (I <= L) and (S[I] = ' ') do - Inc(I); - Result := Copy(S, I, Maxint); -end; - -{==============================================================================} - -function TrimSPRight(const S: string): string; -var - I: Integer; -begin - Result := ''; - if S = '' then - Exit; - I := Length(S); - while (I > 0) and (S[I] = ' ') do - Dec(I); - Result := Copy(S, 1, I); -end; - -{==============================================================================} - -function TrimSP(const S: string): string; -begin - Result := TrimSPLeft(s); - Result := TrimSPRight(Result); -end; - -{==============================================================================} - -function SeparateLeft(const Value, Delimiter: string): string; -var - x: Integer; -begin - x := Pos(Delimiter, Value); - if x < 1 then - Result := Value - else - Result := Copy(Value, 1, x - 1); -end; - -{==============================================================================} - -function SeparateRight(const Value, Delimiter: string): string; -var - x: Integer; -begin - x := Pos(Delimiter, Value); - if x > 0 then - x := x + Length(Delimiter) - 1; - Result := Copy(Value, x + 1, Length(Value) - x); -end; - -{==============================================================================} - -function GetParameter(const Value, Parameter: string): string; -var - s: string; - v: string; -begin - Result := ''; - v := Value; - while v <> '' do - begin - s := Trim(FetchEx(v, ';', '"')); - if Pos(Uppercase(parameter), Uppercase(s)) = 1 then - begin - Delete(s, 1, Length(Parameter)); - s := Trim(s); - if s = '' then - Break; - if s[1] = '=' then - begin - Result := Trim(SeparateRight(s, '=')); - Result := UnquoteStr(Result, '"'); - break; - end; - end; - end; -end; - -{==============================================================================} - -procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); -var - s: string; -begin - Parameters.Clear; - while Value <> '' do - begin - s := Trim(FetchEx(Value, Delimiter, '"')); - Parameters.Add(s); - end; -end; - -{==============================================================================} - -procedure ParseParameters(Value: string; const Parameters: TStrings); -begin - ParseParametersEx(Value, ';', Parameters); -end; - -{==============================================================================} - -function IndexByBegin(Value: string; const List: TStrings): integer; -var - n: integer; - s: string; -begin - Result := -1; - Value := uppercase(Value); - for n := 0 to List.Count -1 do - begin - s := UpperCase(List[n]); - if Pos(Value, s) = 1 then - begin - Result := n; - Break; - end; - end; -end; - -{==============================================================================} - -function GetEmailAddr(const Value: string): string; -var - s: string; -begin - s := SeparateRight(Value, '<'); - s := SeparateLeft(s, '>'); - Result := Trim(s); -end; - -{==============================================================================} - -function GetEmailDesc(Value: string): string; -var - s: string; -begin - Value := Trim(Value); - s := SeparateRight(Value, '"'); - if s <> Value then - s := SeparateLeft(s, '"') - else - begin - s := SeparateLeft(Value, '<'); - if s = Value then - begin - s := SeparateRight(Value, '('); - if s <> Value then - s := SeparateLeft(s, ')') - else - s := ''; - end; - end; - Result := Trim(s); -end; - -{==============================================================================} - -function StrToHex(const Value: Ansistring): string; -var - n: Integer; -begin - Result := ''; - for n := 1 to Length(Value) do - Result := Result + IntToHex(Byte(Value[n]), 2); - Result := LowerCase(Result); -end; - -{==============================================================================} - -function IntToBin(Value: Integer; Digits: Byte): string; -var - x, y, n: Integer; -begin - Result := ''; - x := Value; - repeat - y := x mod 2; - x := x div 2; - if y > 0 then - Result := '1' + Result - else - Result := '0' + Result; - until x = 0; - x := Length(Result); - for n := x to Digits - 1 do - Result := '0' + Result; -end; - -{==============================================================================} - -function BinToInt(const Value: string): Integer; -var - n: Integer; -begin - Result := 0; - for n := 1 to Length(Value) do - begin - if Value[n] = '0' then - Result := Result * 2 - else - if Value[n] = '1' then - Result := Result * 2 + 1 - else - Break; - end; -end; - -{==============================================================================} - -function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, - Para: string): string; -var - x, y: Integer; - sURL: string; - s: string; - s1, s2: string; -begin - Prot := 'http'; - User := ''; - Pass := ''; - Port := '80'; - Para := ''; - - x := Pos('://', URL); - if x > 0 then - begin - Prot := SeparateLeft(URL, '://'); - sURL := SeparateRight(URL, '://'); - end - else - sURL := URL; - if UpperCase(Prot) = 'HTTPS' then - Port := '443'; - if UpperCase(Prot) = 'FTP' then - Port := '21'; - x := Pos('@', sURL); - y := Pos('/', sURL); - if (x > 0) and ((x < y) or (y < 1))then - begin - s := SeparateLeft(sURL, '@'); - sURL := SeparateRight(sURL, '@'); - x := Pos(':', s); - if x > 0 then - begin - User := SeparateLeft(s, ':'); - Pass := SeparateRight(s, ':'); - end - else - User := s; - end; - x := Pos('/', sURL); - if x > 0 then - begin - s1 := SeparateLeft(sURL, '/'); - s2 := SeparateRight(sURL, '/'); - end - else - begin - s1 := sURL; - s2 := ''; - end; - if Pos('[', s1) = 1 then - begin - Host := Separateleft(s1, ']'); - Delete(Host, 1, 1); - s1 := SeparateRight(s1, ']'); - if Pos(':', s1) = 1 then - Port := SeparateRight(s1, ':'); - end - else - begin - x := Pos(':', s1); - if x > 0 then - begin - Host := SeparateLeft(s1, ':'); - Port := SeparateRight(s1, ':'); - end - else - Host := s1; - end; - Result := '/' + s2; - x := Pos('?', s2); - if x > 0 then - begin - Path := '/' + SeparateLeft(s2, '?'); - Para := SeparateRight(s2, '?'); - end - else - Path := '/' + s2; - if Host = '' then - Host := 'localhost'; -end; - -{==============================================================================} - -function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; -var - x, l, ls, lr: Integer; -begin - if (Value = '') or (Search = '') then - begin - Result := Value; - Exit; - end; - ls := Length(Search); - lr := Length(Replace); - Result := ''; - x := Pos(Search, Value); - while x > 0 do - begin - {$IFNDEF CIL} - l := Length(Result); - SetLength(Result, l + x - 1); - Move(Pointer(Value)^, Pointer(@Result[l + 1])^, x - 1); - {$ELSE} - Result:=Result+Copy(Value,1,x-1); - {$ENDIF} - {$IFNDEF CIL} - l := Length(Result); - SetLength(Result, l + lr); - Move(Pointer(Replace)^, Pointer(@Result[l + 1])^, lr); - {$ELSE} - Result:=Result+Replace; - {$ENDIF} - Delete(Value, 1, x - 1 + ls); - x := Pos(Search, Value); - end; - Result := Result + Value; -end; - -{==============================================================================} - -function RPosEx(const Sub, Value: string; From: integer): Integer; -var - n: Integer; - l: Integer; -begin - result := 0; - l := Length(Sub); - for n := From - l + 1 downto 1 do - begin - if Copy(Value, n, l) = Sub then - begin - result := n; - break; - end; - end; -end; - -{==============================================================================} - -function RPos(const Sub, Value: String): Integer; -begin - Result := RPosEx(Sub, Value, Length(Value)); -end; - -{==============================================================================} - -function FetchBin(var Value: string; const Delimiter: string): string; -var - s: string; -begin - Result := SeparateLeft(Value, Delimiter); - s := SeparateRight(Value, Delimiter); - if s = Value then - Value := '' - else - Value := s; -end; - -{==============================================================================} - -function Fetch(var Value: string; const Delimiter: string): string; -begin - Result := FetchBin(Value, Delimiter); - Result := TrimSP(Result); - Value := TrimSP(Value); -end; - -{==============================================================================} - -function FetchEx(var Value: string; const Delimiter, Quotation: string): string; -var - b: Boolean; -begin - Result := ''; - b := False; - while Length(Value) > 0 do - begin - if b then - begin - if Pos(Quotation, Value) = 1 then - b := False; - Result := Result + Value[1]; - Delete(Value, 1, 1); - end - else - begin - if Pos(Delimiter, Value) = 1 then - begin - Delete(Value, 1, Length(delimiter)); - break; - end; - b := Pos(Quotation, Value) = 1; - Result := Result + Value[1]; - Delete(Value, 1, 1); - end; - end; -end; - -{==============================================================================} - -function IsBinaryString(const Value: AnsiString): Boolean; -var - n: integer; -begin - Result := False; - for n := 1 to Length(Value) do - if Value[n] in [#0..#8, #10..#31] then - //ignore null-terminated strings - if not ((n = Length(value)) and (Value[n] = AnsiChar(#0))) then - begin - Result := True; - Break; - end; -end; - -{==============================================================================} - -function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; -var - n, l: integer; -begin - Result := -1; - Terminator := ''; - l := length(value); - for n := 1 to l do - if value[n] in [#$0d, #$0a] then - begin - Result := n; - Terminator := Value[n]; - if n <> l then - case value[n] of - #$0d: - if value[n + 1] = #$0a then - Terminator := #$0d + #$0a; - #$0a: - if value[n + 1] = #$0d then - Terminator := #$0a + #$0d; - end; - Break; - end; -end; - -{==============================================================================} - -Procedure StringsTrim(const Value: TStrings); -var - n: integer; -begin - for n := Value.Count - 1 downto 0 do - if Value[n] = '' then - Value.Delete(n) - else - Break; -end; - -{==============================================================================} - -function PosFrom(const SubStr, Value: String; From: integer): integer; -var - ls,lv: integer; -begin - Result := 0; - ls := Length(SubStr); - lv := Length(Value); - if (ls = 0) or (lv = 0) then - Exit; - if From < 1 then - From := 1; - while (ls + from - 1) <= (lv) do - begin - {$IFNDEF CIL} - if CompareMem(@SubStr[1],@Value[from],ls) then - {$ELSE} - if SubStr = copy(Value, from, ls) then - {$ENDIF} - begin - result := from; - break; - end - else - inc(from); - end; -end; - -{==============================================================================} - -{$IFNDEF CIL} -function IncPoint(const p: pointer; Value: integer): pointer; -begin - Result := PAnsiChar(p) + Value; -end; -{$ENDIF} - -{==============================================================================} -//improved by 'DoggyDawg' -function GetBetween(const PairBegin, PairEnd, Value: string): string; -var - n: integer; - x: integer; - s: string; - lenBegin: integer; - lenEnd: integer; - str: string; - max: integer; -begin - lenBegin := Length(PairBegin); - lenEnd := Length(PairEnd); - n := Length(Value); - if (Value = PairBegin + PairEnd) then - begin - Result := '';//nothing between - exit; - end; - if (n < lenBegin + lenEnd) then - begin - Result := Value; - exit; - end; - s := SeparateRight(Value, PairBegin); - if (s = Value) then - begin - Result := Value; - exit; - end; - n := Pos(PairEnd, s); - if (n = 0) then - begin - Result := Value; - exit; - end; - Result := ''; - x := 1; - max := Length(s) - lenEnd + 1; - for n := 1 to max do - begin - str := copy(s, n, lenEnd); - if (str = PairEnd) then - begin - Dec(x); - if (x <= 0) then - Break; - end; - str := copy(s, n, lenBegin); - if (str = PairBegin) then - Inc(x); - Result := Result + s[n]; - end; -end; - -{==============================================================================} - -function CountOfChar(const Value: string; Chr: char): integer; -var - n: integer; -begin - Result := 0; - for n := 1 to Length(Value) do - if Value[n] = chr then - Inc(Result); -end; - -{==============================================================================} -// ! do not use AnsiExtractQuotedStr, it's very buggy and can crash application! -function UnquoteStr(const Value: string; Quote: Char): string; -var - n: integer; - inq, dq: Boolean; - c, cn: char; -begin - Result := ''; - if Value = '' then - Exit; - if Value = Quote + Quote then - Exit; - inq := False; - dq := False; - for n := 1 to Length(Value) do - begin - c := Value[n]; - if n <> Length(Value) then - cn := Value[n + 1] - else - cn := #0; - if c = quote then - if dq then - dq := False - else - if not inq then - inq := True - else - if cn = quote then - begin - Result := Result + Quote; - dq := True; - end - else - inq := False - else - Result := Result + c; - end; -end; - -{==============================================================================} - -function QuoteStr(const Value: string; Quote: Char): string; -var - n: integer; -begin - Result := ''; - for n := 1 to length(value) do - begin - Result := result + Value[n]; - if value[n] = Quote then - Result := Result + Quote; - end; - Result := Quote + Result + Quote; -end; - -{==============================================================================} - -procedure HeadersToList(const Value: TStrings); -var - n, x, y: integer; - s: string; -begin - for n := 0 to Value.Count -1 do - begin - s := Value[n]; - x := Pos(':', s); - if x > 0 then - begin - y:= Pos('=',s); - if not ((y > 0) and (y < x)) then - begin - s[x] := '='; - Value[n] := s; - end; - end; - end; -end; - -{==============================================================================} - -procedure ListToHeaders(const Value: TStrings); -var - n, x: integer; - s: string; -begin - for n := 0 to Value.Count -1 do - begin - s := Value[n]; - x := Pos('=', s); - if x > 0 then - begin - s[x] := ':'; - Value[n] := s; - end; - end; -end; - -{==============================================================================} - -function SwapBytes(Value: integer): integer; -var - s: AnsiString; - x, y, xl, yl: Byte; -begin - s := CodeLongInt(Value); - x := Ord(s[4]); - y := Ord(s[3]); - xl := Ord(s[2]); - yl := Ord(s[1]); - Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); -end; - -{==============================================================================} - -function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; -var - x: integer; -{$IFDEF CIL} - buf: Array of Byte; -{$ENDIF} -begin -{$IFDEF CIL} - Setlength(buf, Len); - x := Stream.read(buf, Len); - SetLength(buf, x); - Result := StringOf(Buf); -{$ELSE} - Setlength(Result, Len); - x := Stream.read(PAnsiChar(Result)^, Len); - SetLength(Result, x); -{$ENDIF} -end; - -{==============================================================================} - -procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); -{$IFDEF CIL} -var - buf: Array of Byte; -{$ENDIF} -begin -{$IFDEF CIL} - buf := BytesOf(Value); - Stream.Write(buf,length(Value)); -{$ELSE} - Stream.Write(PAnsiChar(Value)^, Length(Value)); -{$ENDIF} -end; - -{==============================================================================} - -{$IFDEF POSIX} -function tempnam(const Path: PAnsiChar; const Prefix: PAnsiChar): PAnsiChar; cdecl; - external libc name _PU + 'tempnam'; -{$ENDIF} - -function GetTempFile(const Dir, prefix: String): String; -{$IFNDEF FPC} -{$IFDEF MSWINDOWS} -var - Path: String; - x: integer; -{$ENDIF} -{$ENDIF} -begin -{$IFDEF FPC} - Result := GetTempFileName(Dir, Prefix); -{$ELSE} - {$IFNDEF MSWINDOWS} - Result := tempnam(Pointer(Dir), Pointer(prefix)); - {$ELSE} - {$IFDEF CIL} - Result := System.IO.Path.GetTempFileName; - {$ELSE} - if Dir = '' then - begin - SetLength(Path, MAX_PATH); - x := GetTempPath(Length(Path), PChar(Path)); - SetLength(Path, x); - end - else - Path := Dir; - x := Length(Path); - if Path[x] <> '\' then - Path := Path + '\'; - SetLength(Result, MAX_PATH + 1); - GetTempFileName(PChar(Path), PChar(Prefix), 0, PChar(Result)); - Result := PChar(Result); - SetFileattributes(PChar(Result), GetFileAttributes(PChar(Result)) or FILE_ATTRIBUTE_TEMPORARY); - {$ENDIF} - {$ENDIF} -{$ENDIF} -end; - -{==============================================================================} - -function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; -begin - if length(value) >= len then - Result := Copy(value, 1, len) - else - Result := Value + StringOfChar(Pad, len - length(value)); -end; - -{==============================================================================} - -function XorString(Indata1, Indata2: AnsiString): AnsiString; -var - i: integer; -begin - Indata2 := PadString(Indata2, length(Indata1), #0); - Result := ''; - for i := 1 to length(Indata1) do - Result := Result + AnsiChar(ord(Indata1[i]) xor ord(Indata2[i])); -end; - -{==============================================================================} - -function NormalizeHeader(Value: TStrings; var Index: Integer): string; -var - s, t: string; - n: Integer; -begin - s := Value[Index]; - Inc(Index); - if s <> '' then - while (Value.Count - 1) > Index do - begin - t := Value[Index]; - if t = '' then - Break; - for n := 1 to Length(t) do - if t[n] = #9 then - t[n] := ' '; - if not(AnsiChar(t[1]) in [' ', '"', ':', '=']) then - Break - else - begin - s := s + ' ' + Trim(t); - Inc(Index); - end; - end; - Result := TrimRight(s); -end; - -{==============================================================================} - -{pf} -procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); -begin - ABol := APtr; - while (APtr0 then - begin - APtr := bol; - Break; - end; - end; -end; -{/pf} - -{pf} -procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); -var - bol: PANSIChar; - lng: integer; - s: ANSIString; -begin - // Copying until body separator will be reached - while (APtr#0) do - begin - SearchForLineBreak(APtr,AEtx,bol,lng); - SkipLineBreak(APtr,AEtx); - if lng=0 then - Break; - SetString(s,bol,lng); - ALines.Add(s); - end; -end; -{/pf} - -{pf} -procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); -var - bol: PANSIChar; - lng: integer; - s: ANSIString; - BackStop: ANSIString; - eob1: PANSIChar; - eob2: PANSIChar; -begin - BackStop := '--'+ABoundary; - eob2 := nil; - // Copying until Boundary will be reached - while (APtrAETX then - exit; - if strlcomp(MatchPos,#13#10,2)=0 then - inc(MatchPos,2); - if (MatchPos+2+Lng)>AETX then - exit; - if strlcomp(MatchPos,'--',2)<>0 then - exit; - inc(MatchPos,2); - if strlcomp(MatchPos,PANSIChar(ABoundary),Lng)<>0 then - exit; - inc(MatchPos,Lng); - if ((MatchPos+2)<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then - inc(MatchPos,2); - Result := MatchPos; -end; -{/pf} - -{pf} -function MatchLastBoundary(ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; -var - MatchPos: PANSIChar; -begin - Result := nil; - MatchPos := MatchBoundary(ABOL,AETX,ABoundary); - if not Assigned(MatchPos) then - exit; - if strlcomp(MatchPos,'--',2)<>0 then - exit; - inc(MatchPos,2); - if (MatchPos+2<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then - inc(MatchPos,2); - Result := MatchPos; -end; -{/pf} - -{pf} -function BuildStringFromBuffer(AStx,AEtx:PANSIChar): ANSIString; -var - lng: integer; -begin - Lng := 0; - if Assigned(AStx) and Assigned(AEtx) then - begin - Lng := AEtx-AStx; - if Lng<0 then - Lng := 0; - end; - SetString(Result,AStx,lng); -end; -{/pf} - - - - -{==============================================================================} -var - n: integer; -begin - for n := 1 to 12 do - begin - CustomMonthNames[n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n]; - MyMonthNames[0, n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n]; - end; -end. +{==============================================================================| +| Project : Ararat Synapse | 004.015.006 | +|==============================================================================| +| Content: support procedures and functions | +|==============================================================================| +| Copyright (c)1999-2013, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c) 1999-2013. | +| Portions created by Hernan Sanchez are Copyright (c) 2000. | +| Portions created by Petr Fejfar are Copyright (c)2011-2012. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| Hernan Sanchez (hernan.sanchez@iname.com) | +| Tomas Hajny (OS2 support) | +| Radek Cervinka (POSIX support) | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(Support procedures and functions)} + +{$I jedi.inc} // load common compiler defines + +{$Q-} +{$R-} +{$H+} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} + {$WARN SUSPICIOUS_TYPECAST OFF} +{$ENDIF} + +unit synautil; + +interface + +uses +{$IFDEF MSWINDOWS} + Windows, +{$ELSE MSWINDOWS} + {$IFDEF FPC} + {$IFDEF OS2} + Dos, TZUtil, + {$ELSE OS2} + UnixUtil, Unix, BaseUnix, + {$ENDIF OS2} + {$ELSE FPC} + {$IFDEF POSIX} + Posix.Base, Posix.Time, Posix.SysTypes, Posix.SysTime, Posix.Stdio, + {$ELSE} + Libc, + {$ENDIF} + {$ENDIF} +{$ENDIF} +{$IFDEF CIL} + System.IO, +{$ENDIF} + SysUtils, Classes, SynaFpc; + +{$IFDEF VER100} +type + int64 = integer; +{$ENDIF} +{$IFDEF POSIX} +type + TTimeVal = Posix.SysTime.timeval; + Ttimezone = record + tz_minuteswest: Integer ; // minutes west of Greenwich + tz_dsttime: integer ; // type of DST correction + end; + + PTimeZone = ^Ttimezone; +{$ENDIF} + + +{:Return your timezone bias from UTC time in minutes.} +function TimeZoneBias: integer; + +{:Return your timezone bias from UTC time in string representation like "+0200".} +function TimeZone: string; + +{:Returns current time in format defined in RFC-822. Useful for SMTP messages, + but other protocols use this time format as well. Results contains the timezone + specification. Four digit year is used to break any Y2K concerns. (Example + 'Fri, 15 Oct 1999 21:14:56 +0200')} +function Rfc822DateTime(t: TDateTime): string; + +{:Returns date and time in format defined in C compilers in format "mmm dd hh:nn:ss"} +function CDateTime(t: TDateTime): string; + +{:Returns date and time in format defined in format 'yymmdd hhnnss'} +function SimpleDateTime(t: TDateTime): string; + +{:Returns date and time in format defined in ANSI C compilers in format + "ddd mmm d hh:nn:ss yyyy" } +function AnsiCDateTime(t: TDateTime): string; + +{:Decode three-letter string with name of month to their month number. If string + not match any month name, then is returned 0. For parsing are used predefined + names for English, French and German and names from system locale too.} +function GetMonthNumber(Value: String): integer; + +{:Return decoded time from given string. Time must be witch separator ':'. You + can use "hh:mm" or "hh:mm:ss".} +function GetTimeFromStr(Value: string): TDateTime; + +{:Decode string representation of TimeZone (CEST, GMT, +0200, -0800, etc.) + to timezone offset.} +function DecodeTimeZone(Value: string; var Zone: integer): Boolean; + +{:Decode string in format "m-d-y" to TDateTime type.} +function GetDateMDYFromStr(Value: string): TDateTime; + +{:Decode various string representations of date and time to Tdatetime type. + This function do all timezone corrections too! This function can decode lot of + formats like: + @longcode(# + ddd, d mmm yyyy hh:mm:ss + ddd, d mmm yy hh:mm:ss + ddd, mmm d yyyy hh:mm:ss + ddd mmm dd hh:mm:ss yyyy #) + +and more with lot of modifications, include: +@longcode(# +Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 +Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 +Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format +#) +Timezone corrections known lot of symbolic timezone names (like CEST, EDT, etc.) +or numeric representation (like +0200). By convention defined in RFC timezone + +0000 is GMT and -0000 is current your system timezone.} +function DecodeRfcDateTime(Value: string): TDateTime; + +{:Return current system date and time in UTC timezone.} +function GetUTTime: TDateTime; + +{:Set Newdt as current system date and time in UTC timezone. This function work + only if you have administrator rights!} +function SetUTTime(Newdt: TDateTime): Boolean; + +{:Return current value of system timer with precizion 1 millisecond. Good for + measure time difference.} +function GetTick: LongWord; + +{:Return difference between two timestamps. It working fine only for differences + smaller then maxint. (difference must be smaller then 24 days.)} +function TickDelta(TickOld, TickNew: LongWord): LongWord; + +{:Return two characters, which ordinal values represents the value in byte + format. (High-endian)} +function CodeInt(Value: Word): Ansistring; + +{:Decodes two characters located at "Index" offset position of the "Value" + string to Word values.} +function DecodeInt(const Value: Ansistring; Index: Integer): Word; + +{:Return four characters, which ordinal values represents the value in byte + format. (High-endian)} +function CodeLongInt(Value: LongInt): Ansistring; + +{:Decodes four characters located at "Index" offset position of the "Value" + string to LongInt values.} +function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; + +{:Dump binary buffer stored in a string to a result string.} +function DumpStr(const Buffer: Ansistring): string; + +{:Dump binary buffer stored in a string to a result string. All bytes with code + of character is written as character, not as hexadecimal value.} +function DumpExStr(const Buffer: Ansistring): string; + +{:Dump binary buffer stored in a string to a file with DumpFile filename.} +procedure Dump(const Buffer: AnsiString; DumpFile: string); + +{:Dump binary buffer stored in a string to a file with DumpFile filename. All + bytes with code of character is written as character, not as hexadecimal value.} +procedure DumpEx(const Buffer: AnsiString; DumpFile: string); + +{:Like TrimLeft, but remove only spaces, not control characters!} +function TrimSPLeft(const S: string): string; + +{:Like TrimRight, but remove only spaces, not control characters!} +function TrimSPRight(const S: string): string; + +{:Like Trim, but remove only spaces, not control characters!} +function TrimSP(const S: string): string; + +{:Returns a portion of the "Value" string located to the left of the "Delimiter" + string. If a delimiter is not found, results is original string.} +function SeparateLeft(const Value, Delimiter: string): string; + +{:Returns the portion of the "Value" string located to the right of the + "Delimiter" string. If a delimiter is not found, results is original string.} +function SeparateRight(const Value, Delimiter: string): string; + +{:Returns parameter value from string in format: + parameter1="value1"; parameter2=value2} +function GetParameter(const Value, Parameter: string): string; + +{:parse value string with elements differed by Delimiter into stringlist.} +procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); + +{:parse value string with elements differed by ';' into stringlist.} +procedure ParseParameters(Value: string; const Parameters: TStrings); + +{:Index of string in stringlist with same beginning as Value is returned.} +function IndexByBegin(Value: string; const List: TStrings): integer; + +{:Returns only the e-mail portion of an address from the full address format. + i.e. returns 'nobody@@somewhere.com' from '"someone" '} +function GetEmailAddr(const Value: string): string; + +{:Returns only the description part from a full address format. i.e. returns + 'someone' from '"someone" '} +function GetEmailDesc(Value: string): string; + +{:Returns a string with hexadecimal digits representing the corresponding values + of the bytes found in "Value" string.} +function StrToHex(const Value: Ansistring): string; + +{:Returns a string of binary "Digits" representing "Value".} +function IntToBin(Value: Integer; Digits: Byte): string; + +{:Returns an integer equivalent of the binary string in "Value". + (i.e. ('10001010') returns 138)} +function BinToInt(const Value: string): Integer; + +{:Parses a URL to its various components.} +function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, + Para: string): string; + +{:Replaces all "Search" string values found within "Value" string, with the + "Replace" string value.} +function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; + +{:It is like RPos, but search is from specified possition.} +function RPosEx(const Sub, Value: string; From: integer): Integer; + +{:It is like POS function, but from right side of Value string.} +function RPos(const Sub, Value: String): Integer; + +{:Like @link(fetch), but working with binary strings, not with text.} +function FetchBin(var Value: string; const Delimiter: string): string; + +{:Fetch string from left of Value string.} +function Fetch(var Value: string; const Delimiter: string): string; + +{:Fetch string from left of Value string. This function ignore delimitesr inside + quotations.} +function FetchEx(var Value: string; const Delimiter, Quotation: string): string; + +{:If string is binary string (contains non-printable characters), then is + returned true.} +function IsBinaryString(const Value: AnsiString): Boolean; + +{:return position of string terminator in string. If terminator found, then is + returned in terminator parameter. + Possible line terminators are: CRLF, LFCR, CR, LF} +function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; + +{:Delete empty strings from end of stringlist.} +Procedure StringsTrim(const value: TStrings); + +{:Like Pos function, buf from given string possition.} +function PosFrom(const SubStr, Value: String; From: integer): integer; + +{$IFNDEF CIL} +{:Increase pointer by value.} +function IncPoint(const p: pointer; Value: integer): pointer; +{$ENDIF} + +{:Get string between PairBegin and PairEnd. This function respect nesting. + For example: + @longcode(# + Value is: 'Hi! (hello(yes!))' + pairbegin is: '(' + pairend is: ')' + In this case result is: 'hello(yes!)'#)} +function GetBetween(const PairBegin, PairEnd, Value: string): string; + +{:Return count of Chr in Value string.} +function CountOfChar(const Value: string; Chr: char): integer; + +{:Remove quotation from Value string. If Value is not quoted, then return same + string without any modification. } +function UnquoteStr(const Value: string; Quote: Char): string; + +{:Quote Value string. If Value contains some Quote chars, then it is doubled.} +function QuoteStr(const Value: string; Quote: Char): string; + +{:Convert lines in stringlist from 'name: value' form to 'name=value' form.} +procedure HeadersToList(const Value: TStrings); + +{:Convert lines in stringlist from 'name=value' form to 'name: value' form.} +procedure ListToHeaders(const Value: TStrings); + +{:swap bytes in integer.} +function SwapBytes(Value: integer): integer; + +{:read string with requested length form stream.} +function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; + +{:write string to stream.} +procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); + +{:Return filename of new temporary file in Dir (if empty, then default temporary + directory is used) and with optional filename prefix.} +function GetTempFile(const Dir, prefix: String): String; + +{:Return padded string. If length is greater, string is truncated. If length is + smaller, string is padded by Pad character.} +function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; + +{:XOR each byte in the strings} +function XorString(Indata1, Indata2: AnsiString): AnsiString; + +{:Read header from "Value" stringlist beginning at "Index" position. If header + is Splitted into multiple lines, then this procedure de-split it into one line.} +function NormalizeHeader(Value: TStrings; var Index: Integer): string; + +{pf} +{:Search for one of line terminators CR, LF or NUL. Return position of the + line beginning and length of text.} +procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); +{:Skip both line terminators CR LF (if any). Move APtr position forward.} +procedure SkipLineBreak(var APtr:PANSIChar; AEtx:PANSIChar); +{:Skip all blank lines in a buffer starting at APtr and move APtr position forward.} +procedure SkipNullLines (var APtr:PANSIChar; AEtx:PANSIChar); +{:Copy all lines from a buffer starting at APtr to ALines until empty line + or end of the buffer is reached. Move APtr position forward).} +procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); +{:Copy all lines from a buffer starting at APtr to ALines until ABoundary + or end of the buffer is reached. Move APtr position forward).} +procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); +{:Search ABoundary in a buffer starting at APtr. + Return beginning of the ABoundary. Move APtr forward behind a trailing CRLF if any).} +function SearchForBoundary (var APtr:PANSIChar; AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; +{:Compare a text at position ABOL with ABoundary and return position behind the + match (including a trailing CRLF if any).} +function MatchBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; +{:Compare a text at position ABOL with ABoundary + the last boundary suffix + and return position behind the match (including a trailing CRLF if any).} +function MatchLastBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; +{:Copy data from a buffer starting at position APtr and delimited by AEtx + position into ANSIString.} +function BuildStringFromBuffer (AStx,AEtx:PANSIChar): ANSIString; +{/pf} + +var + {:can be used for your own months strings for @link(getmonthnumber)} + CustomMonthNames: array[1..12] of string; + +implementation + +{==============================================================================} + +const + MyDayNames: array[1..7] of AnsiString = + ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); +var + MyMonthNames: array[0..6, 1..12] of String = + ( + ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //rewrited by system locales + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //English + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), + ('jan', 'f�v', 'mar', 'avr', 'mai', 'jun', //French + 'jul', 'ao�', 'sep', 'oct', 'nov', 'd�c'), + ('jan', 'fev', 'mar', 'avr', 'mai', 'jun', //French#2 + 'jul', 'aou', 'sep', 'oct', 'nov', 'dec'), + ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', //German + 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + ('Jan', 'Feb', 'M�r', 'Apr', 'Mai', 'Jun', //German#2 + 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), + ('Led', '�no', 'B�e', 'Dub', 'Kv�', '�en', //Czech + '�ec', 'Srp', 'Z��', '��j', 'Lis', 'Pro') + ); + + +{==============================================================================} + +function TimeZoneBias: integer; +{$IFNDEF MSWINDOWS} +{$IFNDEF FPC} +var +{$IFDEF POSIX} + t: Posix.SysTypes.time_t; + UT: Posix.time.tm; +{$ELSE} + t: TTime_T; + UT: TUnixTime; +{$ENDIF} +begin + {$IFDEF POSIX} + __time(T); + localtime_r(T, UT); + Result := UT.tm_gmtoff div 60; + {$ELSE} + __time(@T); + localtime_r(@T, UT); + Result := ut.__tm_gmtoff div 60; + {$ENDIF} +{$ELSE} +begin + Result := TZSeconds div 60; +{$ENDIF} +{$ELSE} +var + zoneinfo: TTimeZoneInformation; + bias: Integer; +begin + case GetTimeZoneInformation(Zoneinfo) of + 2: + bias := zoneinfo.Bias + zoneinfo.DaylightBias; + 1: + bias := zoneinfo.Bias + zoneinfo.StandardBias; + else + bias := zoneinfo.Bias; + end; + Result := bias * (-1); +{$ENDIF} +end; + +{==============================================================================} + +function TimeZone: string; +var + bias: Integer; + h, m: Integer; +begin + bias := TimeZoneBias; + if bias >= 0 then + Result := '+' + else + Result := '-'; + bias := Abs(bias); + h := bias div 60; + m := bias mod 60; + Result := Result + Format('%.2d%.2d', [h, m]); +end; + +{==============================================================================} + +function Rfc822DateTime(t: TDateTime): string; +var + wYear, wMonth, wDay: word; +begin + DecodeDate(t, wYear, wMonth, wDay); + Result := Format('%s, %d %s %s %s', [MyDayNames[DayOfWeek(t)], wDay, + MyMonthNames[1, wMonth], FormatDateTime('yyyy hh":"nn":"ss', t), TimeZone]); +end; + +{==============================================================================} + +function CDateTime(t: TDateTime): string; +var + wYear, wMonth, wDay: word; +begin + DecodeDate(t, wYear, wMonth, wDay); + Result:= Format('%s %2d %s', [MyMonthNames[1, wMonth], wDay, + FormatDateTime('hh":"nn":"ss', t)]); +end; + +{==============================================================================} + +function SimpleDateTime(t: TDateTime): string; +begin + Result := FormatDateTime('yymmdd hhnnss', t); +end; + +{==============================================================================} + +function AnsiCDateTime(t: TDateTime): string; +var + wYear, wMonth, wDay: word; +begin + DecodeDate(t, wYear, wMonth, wDay); + Result := Format('%s %s %d %s', [MyDayNames[DayOfWeek(t)], MyMonthNames[1, wMonth], + wDay, FormatDateTime('hh":"nn":"ss yyyy ', t)]); +end; + +{==============================================================================} + +function DecodeTimeZone(Value: string; var Zone: integer): Boolean; +var + x: integer; + zh, zm: integer; + s: string; +begin + Result := false; + s := Value; + if (Pos('+', s) = 1) or (Pos('-',s) = 1) then + begin + if s = '-0000' then + Zone := TimeZoneBias + else + if Length(s) > 4 then + begin + zh := StrToIntdef(s[2] + s[3], 0); + zm := StrToIntdef(s[4] + s[5], 0); + zone := zh * 60 + zm; + if s[1] = '-' then + zone := zone * (-1); + end; + Result := True; + end + else + begin + x := 32767; + if s = 'NZDT' then x := 13; + if s = 'IDLE' then x := 12; + if s = 'NZST' then x := 12; + if s = 'NZT' then x := 12; + if s = 'EADT' then x := 11; + if s = 'GST' then x := 10; + if s = 'JST' then x := 9; + if s = 'CCT' then x := 8; + if s = 'WADT' then x := 8; + if s = 'WAST' then x := 7; + if s = 'ZP6' then x := 6; + if s = 'ZP5' then x := 5; + if s = 'ZP4' then x := 4; + if s = 'BT' then x := 3; + if s = 'EET' then x := 2; + if s = 'MEST' then x := 2; + if s = 'MESZ' then x := 2; + if s = 'SST' then x := 2; + if s = 'FST' then x := 2; + if s = 'CEST' then x := 2; + if s = 'CET' then x := 1; + if s = 'FWT' then x := 1; + if s = 'MET' then x := 1; + if s = 'MEWT' then x := 1; + if s = 'SWT' then x := 1; + if s = 'UT' then x := 0; + if s = 'UTC' then x := 0; + if s = 'GMT' then x := 0; + if s = 'WET' then x := 0; + if s = 'WAT' then x := -1; + if s = 'BST' then x := -1; + if s = 'AT' then x := -2; + if s = 'ADT' then x := -3; + if s = 'AST' then x := -4; + if s = 'EDT' then x := -4; + if s = 'EST' then x := -5; + if s = 'CDT' then x := -5; + if s = 'CST' then x := -6; + if s = 'MDT' then x := -6; + if s = 'MST' then x := -7; + if s = 'PDT' then x := -7; + if s = 'PST' then x := -8; + if s = 'YDT' then x := -8; + if s = 'YST' then x := -9; + if s = 'HDT' then x := -9; + if s = 'AHST' then x := -10; + if s = 'CAT' then x := -10; + if s = 'HST' then x := -10; + if s = 'EAST' then x := -10; + if s = 'NT' then x := -11; + if s = 'IDLW' then x := -12; + if x <> 32767 then + begin + zone := x * 60; + Result := True; + end; + end; +end; + +{==============================================================================} + +function GetMonthNumber(Value: String): integer; +var + n: integer; + function TestMonth(Value: String; Index: Integer): Boolean; + var + n: integer; + begin + Result := False; + for n := 0 to 6 do + if Value = AnsiUppercase(MyMonthNames[n, Index]) then + begin + Result := True; + Break; + end; + end; +begin + Result := 0; + Value := AnsiUppercase(Value); + for n := 1 to 12 do + if TestMonth(Value, n) or (Value = AnsiUppercase(CustomMonthNames[n])) then + begin + Result := n; + Break; + end; +end; + +{==============================================================================} + +function GetTimeFromStr(Value: string): TDateTime; +var + x: integer; +begin + x := rpos(':', Value); + if (x > 0) and ((Length(Value) - x) > 2) then + Value := Copy(Value, 1, x + 2); + Value := ReplaceString(Value, ':', {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}TimeSeparator); + Result := -1; + try + Result := StrToTime(Value); + except + on Exception do ; + end; +end; + +{==============================================================================} + +function GetDateMDYFromStr(Value: string): TDateTime; +var + wYear, wMonth, wDay: word; + s: string; +begin + Result := 0; + s := Fetch(Value, '-'); + wMonth := StrToIntDef(s, 12); + s := Fetch(Value, '-'); + wDay := StrToIntDef(s, 30); + wYear := StrToIntDef(Value, 1899); + if wYear < 1000 then + if (wYear > 99) then + wYear := wYear + 1900 + else + if wYear > 50 then + wYear := wYear + 1900 + else + wYear := wYear + 2000; + try + Result := EncodeDate(wYear, wMonth, wDay); + except + on Exception do ; + end; +end; + +{==============================================================================} + +function DecodeRfcDateTime(Value: string): TDateTime; +var + day, month, year: Word; + zone: integer; + x, y: integer; + s: string; + t: TDateTime; +begin +// ddd, d mmm yyyy hh:mm:ss +// ddd, d mmm yy hh:mm:ss +// ddd, mmm d yyyy hh:mm:ss +// ddd mmm dd hh:mm:ss yyyy +// Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 +// Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 +// Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format + + Result := 0; + if Value = '' then + Exit; + day := 0; + month := 0; + year := 0; + zone := 0; + Value := ReplaceString(Value, ' -', ' #'); + Value := ReplaceString(Value, '-', ' '); + Value := ReplaceString(Value, ' #', ' -'); + while Value <> '' do + begin + s := Fetch(Value, ' '); + s := uppercase(s); + // timezone + if DecodetimeZone(s, x) then + begin + zone := x; + continue; + end; + x := StrToIntDef(s, 0); + // day or year + if x > 0 then + if (x < 32) and (day = 0) then + begin + day := x; + continue; + end + else + begin + if (year = 0) and ((month > 0) or (x > 12)) then + begin + year := x; + if year < 32 then + year := year + 2000; + if year < 1000 then + year := year + 1900; + continue; + end; + end; + // time + if rpos(':', s) > Pos(':', s) then + begin + t := GetTimeFromStr(s); + if t <> -1 then + Result := t; + continue; + end; + //timezone daylight saving time + if s = 'DST' then + begin + zone := zone + 60; + continue; + end; + // month + y := GetMonthNumber(s); + if (y > 0) and (month = 0) then + month := y; + end; + if year = 0 then + year := 1980; + if month < 1 then + month := 1; + if month > 12 then + month := 12; + if day < 1 then + day := 1; + x := MonthDays[IsLeapYear(year), month]; + if day > x then + day := x; + Result := Result + Encodedate(year, month, day); + zone := zone - TimeZoneBias; + x := zone div 1440; + Result := Result - x; + zone := zone mod 1440; + t := EncodeTime(Abs(zone) div 60, Abs(zone) mod 60, 0, 0); + if zone < 0 then + t := 0 - t; + Result := Result - t; +end; + +{==============================================================================} + +function GetUTTime: TDateTime; +{$IFDEF MSWINDOWS} +{$IFNDEF FPC} +var + st: TSystemTime; +begin + GetSystemTime(st); + result := SystemTimeToDateTime(st); +{$ELSE} +var + st: SysUtils.TSystemTime; + stw: Windows.TSystemTime; +begin + GetSystemTime(stw); + st.Year := stw.wYear; + st.Month := stw.wMonth; + st.Day := stw.wDay; + st.Hour := stw.wHour; + st.Minute := stw.wMinute; + st.Second := stw.wSecond; + st.Millisecond := stw.wMilliseconds; + result := SystemTimeToDateTime(st); +{$ENDIF} +{$ELSE MSWINDOWS} +{$IFNDEF FPC} +var + TV: TTimeVal; +begin + gettimeofday(TV, nil); + Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; +{$ELSE FPC} + {$IFDEF UNIX} +var + TV: TimeVal; +begin + fpgettimeofday(@TV, nil); + Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; + {$ELSE UNIX} + {$IFDEF OS2} +var + ST: TSystemTime; +begin + GetLocalTime (ST); + Result := SystemTimeToDateTime (ST); + {$ENDIF OS2} + {$ENDIF UNIX} +{$ENDIF FPC} +{$ENDIF MSWINDOWS} +end; + +{==============================================================================} + +function SetUTTime(Newdt: TDateTime): Boolean; +{$IFDEF MSWINDOWS} +{$IFNDEF FPC} +var + st: TSystemTime; +begin + DateTimeToSystemTime(newdt,st); + Result := SetSystemTime(st); +{$ELSE} +var + st: SysUtils.TSystemTime; + stw: Windows.TSystemTime; +begin + DateTimeToSystemTime(newdt,st); + stw.wYear := st.Year; + stw.wMonth := st.Month; + stw.wDay := st.Day; + stw.wHour := st.Hour; + stw.wMinute := st.Minute; + stw.wSecond := st.Second; + stw.wMilliseconds := st.Millisecond; + Result := SetSystemTime(stw); +{$ENDIF} +{$ELSE MSWINDOWS} +{$IFNDEF FPC} +var + TV: TTimeVal; + d: double; + TZ: Ttimezone; + PZ: PTimeZone; +begin + TZ.tz_minuteswest := 0; + TZ.tz_dsttime := 0; + PZ := @TZ; + gettimeofday(TV, PZ); + d := (newdt - UnixDateDelta) * 86400; + TV.tv_sec := trunc(d); + TV.tv_usec := trunc(frac(d) * 1000000); + {$IFNDEF POSIX} + Result := settimeofday(TV, TZ) <> -1; + {$ELSE} + Result := False; // in POSIX settimeofday is not defined? http://www.kernel.org/doc/man-pages/online/pages/man2/gettimeofday.2.html + {$ENDIF} +{$ELSE FPC} + {$IFDEF UNIX} +var + TV: TimeVal; + d: double; +begin + d := (newdt - UnixDateDelta) * 86400; + TV.tv_sec := trunc(d); + TV.tv_usec := trunc(frac(d) * 1000000); + Result := fpsettimeofday(@TV, nil) <> -1; + {$ELSE UNIX} + {$IFDEF OS2} +var + ST: TSystemTime; +begin + DateTimeToSystemTime (NewDT, ST); + SetTime (ST.Hour, ST.Minute, ST.Second, ST.Millisecond div 10); + Result := true; + {$ENDIF OS2} + {$ENDIF UNIX} +{$ENDIF FPC} +{$ENDIF MSWINDOWS} +end; + +{==============================================================================} + +{$IFNDEF MSWINDOWS} +function GetTick: LongWord; +var + Stamp: TTimeStamp; +begin + Stamp := DateTimeToTimeStamp(Now); + Result := Stamp.Time; +end; +{$ELSE} +function GetTick: LongWord; +var + tick, freq: TLargeInteger; +{$IFDEF VER100} + x: TLargeInteger; +{$ENDIF} +begin + if Windows.QueryPerformanceFrequency(freq) then + begin + Windows.QueryPerformanceCounter(tick); +{$IFDEF VER100} + x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000; + Result := x.LowPart; +{$ELSE} + Result := Trunc((tick / freq) * 1000) and High(LongWord) +{$ENDIF} + end + else + Result := Windows.GetTickCount; +end; +{$ENDIF} + +{==============================================================================} + +function TickDelta(TickOld, TickNew: LongWord): LongWord; +begin +//if DWord is signed type (older Deplhi), +// then it not work properly on differencies larger then maxint! + Result := 0; + if TickOld <> TickNew then + begin + if TickNew < TickOld then + begin + TickNew := TickNew + LongWord(MaxInt) + 1; + TickOld := TickOld + LongWord(MaxInt) + 1; + end; + Result := TickNew - TickOld; + if TickNew < TickOld then + if Result > 0 then + Result := 0 - Result; + end; +end; + +{==============================================================================} + +function CodeInt(Value: Word): Ansistring; +begin + setlength(result, 2); + result[1] := AnsiChar(Value div 256); + result[2] := AnsiChar(Value mod 256); +// Result := AnsiChar(Value div 256) + AnsiChar(Value mod 256) +end; + +{==============================================================================} + +function DecodeInt(const Value: Ansistring; Index: Integer): Word; +var + x, y: Byte; +begin + if Length(Value) > Index then + x := Ord(Value[Index]) + else + x := 0; + if Length(Value) >= (Index + 1) then + y := Ord(Value[Index + 1]) + else + y := 0; + Result := x * 256 + y; +end; + +{==============================================================================} + +function CodeLongInt(Value: Longint): Ansistring; +var + x, y: word; +begin + // this is fix for negative numbers on systems where longint = integer + x := (Value shr 16) and integer($ffff); + y := Value and integer($ffff); + setlength(result, 4); + result[1] := AnsiChar(x div 256); + result[2] := AnsiChar(x mod 256); + result[3] := AnsiChar(y div 256); + result[4] := AnsiChar(y mod 256); +end; + +{==============================================================================} + +function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; +var + x, y: Byte; + xl, yl: Byte; +begin + if Length(Value) > Index then + x := Ord(Value[Index]) + else + x := 0; + if Length(Value) >= (Index + 1) then + y := Ord(Value[Index + 1]) + else + y := 0; + if Length(Value) >= (Index + 2) then + xl := Ord(Value[Index + 2]) + else + xl := 0; + if Length(Value) >= (Index + 3) then + yl := Ord(Value[Index + 3]) + else + yl := 0; + Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); +end; + +{==============================================================================} + +function DumpStr(const Buffer: Ansistring): string; +var + n: Integer; +begin + Result := ''; + for n := 1 to Length(Buffer) do + Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); +end; + +{==============================================================================} + +function DumpExStr(const Buffer: Ansistring): string; +var + n: Integer; + x: Byte; +begin + Result := ''; + for n := 1 to Length(Buffer) do + begin + x := Ord(Buffer[n]); + if x in [65..90, 97..122] then + Result := Result + ' +''' + char(x) + '''' + else + Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); + end; +end; + +{==============================================================================} + +procedure Dump(const Buffer: AnsiString; DumpFile: string); +var + f: Text; +begin + AssignFile(f, DumpFile); + if FileExists(DumpFile) then + DeleteFile(DumpFile); + Rewrite(f); + try + Writeln(f, DumpStr(Buffer)); + finally + CloseFile(f); + end; +end; + +{==============================================================================} + +procedure DumpEx(const Buffer: AnsiString; DumpFile: string); +var + f: Text; +begin + AssignFile(f, DumpFile); + if FileExists(DumpFile) then + DeleteFile(DumpFile); + Rewrite(f); + try + Writeln(f, DumpExStr(Buffer)); + finally + CloseFile(f); + end; +end; + +{==============================================================================} + +function TrimSPLeft(const S: string): string; +var + I, L: Integer; +begin + Result := ''; + if S = '' then + Exit; + L := Length(S); + I := 1; + while (I <= L) and (S[I] = ' ') do + Inc(I); + Result := Copy(S, I, Maxint); +end; + +{==============================================================================} + +function TrimSPRight(const S: string): string; +var + I: Integer; +begin + Result := ''; + if S = '' then + Exit; + I := Length(S); + while (I > 0) and (S[I] = ' ') do + Dec(I); + Result := Copy(S, 1, I); +end; + +{==============================================================================} + +function TrimSP(const S: string): string; +begin + Result := TrimSPLeft(s); + Result := TrimSPRight(Result); +end; + +{==============================================================================} + +function SeparateLeft(const Value, Delimiter: string): string; +var + x: Integer; +begin + x := Pos(Delimiter, Value); + if x < 1 then + Result := Value + else + Result := Copy(Value, 1, x - 1); +end; + +{==============================================================================} + +function SeparateRight(const Value, Delimiter: string): string; +var + x: Integer; +begin + x := Pos(Delimiter, Value); + if x > 0 then + x := x + Length(Delimiter) - 1; + Result := Copy(Value, x + 1, Length(Value) - x); +end; + +{==============================================================================} + +function GetParameter(const Value, Parameter: string): string; +var + s: string; + v: string; +begin + Result := ''; + v := Value; + while v <> '' do + begin + s := Trim(FetchEx(v, ';', '"')); + if Pos(Uppercase(parameter), Uppercase(s)) = 1 then + begin + Delete(s, 1, Length(Parameter)); + s := Trim(s); + if s = '' then + Break; + if s[1] = '=' then + begin + Result := Trim(SeparateRight(s, '=')); + Result := UnquoteStr(Result, '"'); + break; + end; + end; + end; +end; + +{==============================================================================} + +procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); +var + s: string; +begin + Parameters.Clear; + while Value <> '' do + begin + s := Trim(FetchEx(Value, Delimiter, '"')); + Parameters.Add(s); + end; +end; + +{==============================================================================} + +procedure ParseParameters(Value: string; const Parameters: TStrings); +begin + ParseParametersEx(Value, ';', Parameters); +end; + +{==============================================================================} + +function IndexByBegin(Value: string; const List: TStrings): integer; +var + n: integer; + s: string; +begin + Result := -1; + Value := uppercase(Value); + for n := 0 to List.Count -1 do + begin + s := UpperCase(List[n]); + if Pos(Value, s) = 1 then + begin + Result := n; + Break; + end; + end; +end; + +{==============================================================================} + +function GetEmailAddr(const Value: string): string; +var + s: string; +begin + s := SeparateRight(Value, '<'); + s := SeparateLeft(s, '>'); + Result := Trim(s); +end; + +{==============================================================================} + +function GetEmailDesc(Value: string): string; +var + s: string; +begin + Value := Trim(Value); + s := SeparateRight(Value, '"'); + if s <> Value then + s := SeparateLeft(s, '"') + else + begin + s := SeparateLeft(Value, '<'); + if s = Value then + begin + s := SeparateRight(Value, '('); + if s <> Value then + s := SeparateLeft(s, ')') + else + s := ''; + end; + end; + Result := Trim(s); +end; + +{==============================================================================} + +function StrToHex(const Value: Ansistring): string; +var + n: Integer; +begin + Result := ''; + for n := 1 to Length(Value) do + Result := Result + IntToHex(Byte(Value[n]), 2); + Result := LowerCase(Result); +end; + +{==============================================================================} + +function IntToBin(Value: Integer; Digits: Byte): string; +var + x, y, n: Integer; +begin + Result := ''; + x := Value; + repeat + y := x mod 2; + x := x div 2; + if y > 0 then + Result := '1' + Result + else + Result := '0' + Result; + until x = 0; + x := Length(Result); + for n := x to Digits - 1 do + Result := '0' + Result; +end; + +{==============================================================================} + +function BinToInt(const Value: string): Integer; +var + n: Integer; +begin + Result := 0; + for n := 1 to Length(Value) do + begin + if Value[n] = '0' then + Result := Result * 2 + else + if Value[n] = '1' then + Result := Result * 2 + 1 + else + Break; + end; +end; + +{==============================================================================} + +function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, + Para: string): string; +var + x, y: Integer; + sURL: string; + s: string; + s1, s2: string; +begin + Prot := 'http'; + User := ''; + Pass := ''; + Port := '80'; + Para := ''; + + x := Pos('://', URL); + if x > 0 then + begin + Prot := SeparateLeft(URL, '://'); + sURL := SeparateRight(URL, '://'); + end + else + sURL := URL; + if UpperCase(Prot) = 'HTTPS' then + Port := '443'; + if UpperCase(Prot) = 'FTP' then + Port := '21'; + x := Pos('@', sURL); + y := Pos('/', sURL); + if (x > 0) and ((x < y) or (y < 1))then + begin + s := SeparateLeft(sURL, '@'); + sURL := SeparateRight(sURL, '@'); + x := Pos(':', s); + if x > 0 then + begin + User := SeparateLeft(s, ':'); + Pass := SeparateRight(s, ':'); + end + else + User := s; + end; + x := Pos('/', sURL); + if x > 0 then + begin + s1 := SeparateLeft(sURL, '/'); + s2 := SeparateRight(sURL, '/'); + end + else + begin + s1 := sURL; + s2 := ''; + end; + if Pos('[', s1) = 1 then + begin + Host := Separateleft(s1, ']'); + Delete(Host, 1, 1); + s1 := SeparateRight(s1, ']'); + if Pos(':', s1) = 1 then + Port := SeparateRight(s1, ':'); + end + else + begin + x := Pos(':', s1); + if x > 0 then + begin + Host := SeparateLeft(s1, ':'); + Port := SeparateRight(s1, ':'); + end + else + Host := s1; + end; + Result := '/' + s2; + x := Pos('?', s2); + if x > 0 then + begin + Path := '/' + SeparateLeft(s2, '?'); + Para := SeparateRight(s2, '?'); + end + else + Path := '/' + s2; + if Host = '' then + Host := 'localhost'; +end; + +{==============================================================================} + +function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; +var + x, l, ls, lr: Integer; +begin + if (Value = '') or (Search = '') then + begin + Result := Value; + Exit; + end; + ls := Length(Search); + lr := Length(Replace); + Result := ''; + x := Pos(Search, Value); + while x > 0 do + begin + {$IFNDEF CIL} + l := Length(Result); + SetLength(Result, l + x - 1); + Move(Pointer(Value)^, Pointer(@Result[l + 1])^, x - 1); + {$ELSE} + Result:=Result+Copy(Value,1,x-1); + {$ENDIF} + {$IFNDEF CIL} + l := Length(Result); + SetLength(Result, l + lr); + Move(Pointer(Replace)^, Pointer(@Result[l + 1])^, lr); + {$ELSE} + Result:=Result+Replace; + {$ENDIF} + Delete(Value, 1, x - 1 + ls); + x := Pos(Search, Value); + end; + Result := Result + Value; +end; + +{==============================================================================} + +function RPosEx(const Sub, Value: string; From: integer): Integer; +var + n: Integer; + l: Integer; +begin + result := 0; + l := Length(Sub); + for n := From - l + 1 downto 1 do + begin + if Copy(Value, n, l) = Sub then + begin + result := n; + break; + end; + end; +end; + +{==============================================================================} + +function RPos(const Sub, Value: String): Integer; +begin + Result := RPosEx(Sub, Value, Length(Value)); +end; + +{==============================================================================} + +function FetchBin(var Value: string; const Delimiter: string): string; +var + s: string; +begin + Result := SeparateLeft(Value, Delimiter); + s := SeparateRight(Value, Delimiter); + if s = Value then + Value := '' + else + Value := s; +end; + +{==============================================================================} + +function Fetch(var Value: string; const Delimiter: string): string; +begin + Result := FetchBin(Value, Delimiter); + Result := TrimSP(Result); + Value := TrimSP(Value); +end; + +{==============================================================================} + +function FetchEx(var Value: string; const Delimiter, Quotation: string): string; +var + b: Boolean; +begin + Result := ''; + b := False; + while Length(Value) > 0 do + begin + if b then + begin + if Pos(Quotation, Value) = 1 then + b := False; + Result := Result + Value[1]; + Delete(Value, 1, 1); + end + else + begin + if Pos(Delimiter, Value) = 1 then + begin + Delete(Value, 1, Length(delimiter)); + break; + end; + b := Pos(Quotation, Value) = 1; + Result := Result + Value[1]; + Delete(Value, 1, 1); + end; + end; +end; + +{==============================================================================} + +function IsBinaryString(const Value: AnsiString): Boolean; +var + n: integer; +begin + Result := False; + for n := 1 to Length(Value) do + if Value[n] in [#0..#8, #10..#31] then + //ignore null-terminated strings + if not ((n = Length(value)) and (Value[n] = AnsiChar(#0))) then + begin + Result := True; + Break; + end; +end; + +{==============================================================================} + +function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; +var + n, l: integer; +begin + Result := -1; + Terminator := ''; + l := length(value); + for n := 1 to l do + if value[n] in [#$0d, #$0a] then + begin + Result := n; + Terminator := Value[n]; + if n <> l then + case value[n] of + #$0d: + if value[n + 1] = #$0a then + Terminator := #$0d + #$0a; + #$0a: + if value[n + 1] = #$0d then + Terminator := #$0a + #$0d; + end; + Break; + end; +end; + +{==============================================================================} + +Procedure StringsTrim(const Value: TStrings); +var + n: integer; +begin + for n := Value.Count - 1 downto 0 do + if Value[n] = '' then + Value.Delete(n) + else + Break; +end; + +{==============================================================================} + +function PosFrom(const SubStr, Value: String; From: integer): integer; +var + ls,lv: integer; +begin + Result := 0; + ls := Length(SubStr); + lv := Length(Value); + if (ls = 0) or (lv = 0) then + Exit; + if From < 1 then + From := 1; + while (ls + from - 1) <= (lv) do + begin + {$IFNDEF CIL} + if CompareMem(@SubStr[1],@Value[from],ls) then + {$ELSE} + if SubStr = copy(Value, from, ls) then + {$ENDIF} + begin + result := from; + break; + end + else + inc(from); + end; +end; + +{==============================================================================} + +{$IFNDEF CIL} +function IncPoint(const p: pointer; Value: integer): pointer; +begin + Result := PAnsiChar(p) + Value; +end; +{$ENDIF} + +{==============================================================================} +//improved by 'DoggyDawg' +function GetBetween(const PairBegin, PairEnd, Value: string): string; +var + n: integer; + x: integer; + s: string; + lenBegin: integer; + lenEnd: integer; + str: string; + max: integer; +begin + lenBegin := Length(PairBegin); + lenEnd := Length(PairEnd); + n := Length(Value); + if (Value = PairBegin + PairEnd) then + begin + Result := '';//nothing between + exit; + end; + if (n < lenBegin + lenEnd) then + begin + Result := Value; + exit; + end; + s := SeparateRight(Value, PairBegin); + if (s = Value) then + begin + Result := Value; + exit; + end; + n := Pos(PairEnd, s); + if (n = 0) then + begin + Result := Value; + exit; + end; + Result := ''; + x := 1; + max := Length(s) - lenEnd + 1; + for n := 1 to max do + begin + str := copy(s, n, lenEnd); + if (str = PairEnd) then + begin + Dec(x); + if (x <= 0) then + Break; + end; + str := copy(s, n, lenBegin); + if (str = PairBegin) then + Inc(x); + Result := Result + s[n]; + end; +end; + +{==============================================================================} + +function CountOfChar(const Value: string; Chr: char): integer; +var + n: integer; +begin + Result := 0; + for n := 1 to Length(Value) do + if Value[n] = chr then + Inc(Result); +end; + +{==============================================================================} +// ! do not use AnsiExtractQuotedStr, it's very buggy and can crash application! +function UnquoteStr(const Value: string; Quote: Char): string; +var + n: integer; + inq, dq: Boolean; + c, cn: char; +begin + Result := ''; + if Value = '' then + Exit; + if Value = Quote + Quote then + Exit; + inq := False; + dq := False; + for n := 1 to Length(Value) do + begin + c := Value[n]; + if n <> Length(Value) then + cn := Value[n + 1] + else + cn := #0; + if c = quote then + if dq then + dq := False + else + if not inq then + inq := True + else + if cn = quote then + begin + Result := Result + Quote; + dq := True; + end + else + inq := False + else + Result := Result + c; + end; +end; + +{==============================================================================} + +function QuoteStr(const Value: string; Quote: Char): string; +var + n: integer; +begin + Result := ''; + for n := 1 to length(value) do + begin + Result := result + Value[n]; + if value[n] = Quote then + Result := Result + Quote; + end; + Result := Quote + Result + Quote; +end; + +{==============================================================================} + +procedure HeadersToList(const Value: TStrings); +var + n, x, y: integer; + s: string; +begin + for n := 0 to Value.Count -1 do + begin + s := Value[n]; + x := Pos(':', s); + if x > 0 then + begin + y:= Pos('=',s); + if not ((y > 0) and (y < x)) then + begin + s[x] := '='; + Value[n] := s; + end; + end; + end; +end; + +{==============================================================================} + +procedure ListToHeaders(const Value: TStrings); +var + n, x: integer; + s: string; +begin + for n := 0 to Value.Count -1 do + begin + s := Value[n]; + x := Pos('=', s); + if x > 0 then + begin + s[x] := ':'; + Value[n] := s; + end; + end; +end; + +{==============================================================================} + +function SwapBytes(Value: integer): integer; +var + s: AnsiString; + x, y, xl, yl: Byte; +begin + s := CodeLongInt(Value); + x := Ord(s[4]); + y := Ord(s[3]); + xl := Ord(s[2]); + yl := Ord(s[1]); + Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); +end; + +{==============================================================================} + +function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; +var + x: integer; +{$IFDEF CIL} + buf: Array of Byte; +{$ENDIF} +begin +{$IFDEF CIL} + Setlength(buf, Len); + x := Stream.read(buf, Len); + SetLength(buf, x); + Result := StringOf(Buf); +{$ELSE} + Setlength(Result, Len); + x := Stream.read(PAnsiChar(Result)^, Len); + SetLength(Result, x); +{$ENDIF} +end; + +{==============================================================================} + +procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); +{$IFDEF CIL} +var + buf: Array of Byte; +{$ENDIF} +begin +{$IFDEF CIL} + buf := BytesOf(Value); + Stream.Write(buf,length(Value)); +{$ELSE} + Stream.Write(PAnsiChar(Value)^, Length(Value)); +{$ENDIF} +end; + +{==============================================================================} + +{$IFDEF POSIX} +function tempnam(const Path: PAnsiChar; const Prefix: PAnsiChar): PAnsiChar; cdecl; + external libc name _PU + 'tempnam'; +{$ENDIF} + +function GetTempFile(const Dir, prefix: String): String; +{$IFNDEF FPC} +{$IFDEF MSWINDOWS} +var + Path: String; + x: integer; +{$ENDIF} +{$ENDIF} +begin +{$IFDEF FPC} + Result := GetTempFileName(Dir, Prefix); +{$ELSE} + {$IFNDEF MSWINDOWS} + Result := tempnam(Pointer(Dir), Pointer(prefix)); + {$ELSE} + {$IFDEF CIL} + Result := System.IO.Path.GetTempFileName; + {$ELSE} + if Dir = '' then + begin + SetLength(Path, MAX_PATH); + x := GetTempPath(Length(Path), PChar(Path)); + SetLength(Path, x); + end + else + Path := Dir; + x := Length(Path); + if Path[x] <> '\' then + Path := Path + '\'; + SetLength(Result, MAX_PATH + 1); + GetTempFileName(PChar(Path), PChar(Prefix), 0, PChar(Result)); + Result := PChar(Result); + SetFileattributes(PChar(Result), GetFileAttributes(PChar(Result)) or FILE_ATTRIBUTE_TEMPORARY); + {$ENDIF} + {$ENDIF} +{$ENDIF} +end; + +{==============================================================================} + +function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; +begin + if length(value) >= len then + Result := Copy(value, 1, len) + else + Result := Value + StringOfChar(Pad, len - length(value)); +end; + +{==============================================================================} + +function XorString(Indata1, Indata2: AnsiString): AnsiString; +var + i: integer; +begin + Indata2 := PadString(Indata2, length(Indata1), #0); + Result := ''; + for i := 1 to length(Indata1) do + Result := Result + AnsiChar(ord(Indata1[i]) xor ord(Indata2[i])); +end; + +{==============================================================================} + +function NormalizeHeader(Value: TStrings; var Index: Integer): string; +var + s, t: string; + n: Integer; +begin + s := Value[Index]; + Inc(Index); + if s <> '' then + while (Value.Count - 1) > Index do + begin + t := Value[Index]; + if t = '' then + Break; + for n := 1 to Length(t) do + if t[n] = #9 then + t[n] := ' '; + if not(AnsiChar(t[1]) in [' ', '"', ':', '=']) then + Break + else + begin + s := s + ' ' + Trim(t); + Inc(Index); + end; + end; + Result := TrimRight(s); +end; + +{==============================================================================} + +{pf} +procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); +begin + ABol := APtr; + while (APtr0 then + begin + APtr := bol; + Break; + end; + end; +end; +{/pf} + +{pf} +procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); +var + bol: PANSIChar; + lng: integer; + s: ANSIString; +begin + // Copying until body separator will be reached + while (APtr#0) do + begin + SearchForLineBreak(APtr,AEtx,bol,lng); + SkipLineBreak(APtr,AEtx); + if lng=0 then + Break; + SetString(s,bol,lng); + ALines.Add(s); + end; +end; +{/pf} + +{pf} +procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); +var + bol: PANSIChar; + lng: integer; + s: ANSIString; + BackStop: ANSIString; + eob1: PANSIChar; + eob2: PANSIChar; +begin + BackStop := '--'+ABoundary; + eob2 := nil; + // Copying until Boundary will be reached + while (APtrAETX then + exit; + if strlcomp(MatchPos,#13#10,2)=0 then + inc(MatchPos,2); + if (MatchPos+2+Lng)>AETX then + exit; + if strlcomp(MatchPos,'--',2)<>0 then + exit; + inc(MatchPos,2); + if strlcomp(MatchPos,PANSIChar(ABoundary),Lng)<>0 then + exit; + inc(MatchPos,Lng); + if ((MatchPos+2)<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then + inc(MatchPos,2); + Result := MatchPos; +end; +{/pf} + +{pf} +function MatchLastBoundary(ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; +var + MatchPos: PANSIChar; +begin + Result := nil; + MatchPos := MatchBoundary(ABOL,AETX,ABoundary); + if not Assigned(MatchPos) then + exit; + if strlcomp(MatchPos,'--',2)<>0 then + exit; + inc(MatchPos,2); + if (MatchPos+2<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then + inc(MatchPos,2); + Result := MatchPos; +end; +{/pf} + +{pf} +function BuildStringFromBuffer(AStx,AEtx:PANSIChar): ANSIString; +var + lng: integer; +begin + Lng := 0; + if Assigned(AStx) and Assigned(AEtx) then + begin + Lng := AEtx-AStx; + if Lng<0 then + Lng := 0; + end; + SetString(Result,AStx,lng); +end; +{/pf} + + + + +{==============================================================================} +var + n: integer; +begin + for n := 1 to 12 do + begin + CustomMonthNames[n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n]; + MyMonthNames[0, n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n]; + end; +end. diff --git a/3rd/synapse/source/synsock.pas b/3rd/synapse/source/synsock.pas index 8f8aa4a11..640115eac 100644 --- a/3rd/synapse/source/synsock.pas +++ b/3rd/synapse/source/synsock.pas @@ -1,86 +1,86 @@ -{==============================================================================| -| Project : Ararat Synapse | 005.002.003 | -|==============================================================================| -| Content: Socket Independent Platform Layer | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -unit synsock; - -{$MINENUMSIZE 4} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF CIL} - {$I ssdotnet.inc} -{$ELSE} - {$IFDEF MSWINDOWS} - {$I sswin32.inc} - {$ELSE} - {$IFDEF WINCE} - {$I sswin32.inc} //not complete yet! - {$ELSE} - {$IFDEF FPC} - {$IFDEF OS2} - {$I ssos2ws1.inc} - {$ELSE OS2} - {$I ssfpc.inc} - {$ENDIF OS2} - {$ELSE} - {$I sslinux.inc} - {$ENDIF} - {$ENDIF} - {$ENDIF} -{$ENDIF} -{$IFDEF POSIX} -//Posix.SysSocket - {$I ssposix.inc} //experimental! -{$ENDIF} - -end. - +{==============================================================================| +| Project : Ararat Synapse | 005.002.003 | +|==============================================================================| +| Content: Socket Independent Platform Layer | +|==============================================================================| +| Copyright (c)1999-2013, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2001-2013. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +| Tomas Hajny (OS2 support) | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@exclude} + +unit synsock; + +{$MINENUMSIZE 4} + +//old Delphi does not have MSWINDOWS define. +{$IFDEF WIN32} + {$IFNDEF MSWINDOWS} + {$DEFINE MSWINDOWS} + {$ENDIF} +{$ENDIF} + +{$IFDEF CIL} + {$I ssdotnet.inc} +{$ELSE} + {$IFDEF MSWINDOWS} + {$I sswin32.inc} + {$ELSE} + {$IFDEF WINCE} + {$I sswin32.inc} //not complete yet! + {$ELSE} + {$IFDEF FPC} + {$IFDEF OS2} + {$I ssos2ws1.inc} + {$ELSE OS2} + {$I ssfpc.inc} + {$ENDIF OS2} + {$ELSE} + {$I sslinux.inc} + {$ENDIF} + {$ENDIF} + {$ENDIF} +{$ENDIF} +{$IFDEF POSIX} +//Posix.SysSocket + {$I ssposix.inc} //experimental! +{$ENDIF} + +end. + diff --git a/3rd/synapse/source/tlntsend.pas b/3rd/synapse/source/tlntsend.pas index 557266c59..1cac10f98 100644 --- a/3rd/synapse/source/tlntsend.pas +++ b/3rd/synapse/source/tlntsend.pas @@ -1,364 +1,364 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.003.001 | -|==============================================================================| -| Content: TELNET and SSH2 client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2002-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Telnet script client) - -Used RFC: RFC-854 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit tlntsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil; - -const - cTelnetProtocol = '23'; - cSSHProtocol = '22'; - - TLNT_EOR = #239; - TLNT_SE = #240; - TLNT_NOP = #241; - TLNT_DATA_MARK = #242; - TLNT_BREAK = #243; - TLNT_IP = #244; - TLNT_AO = #245; - TLNT_AYT = #246; - TLNT_EC = #247; - TLNT_EL = #248; - TLNT_GA = #249; - TLNT_SB = #250; - TLNT_WILL = #251; - TLNT_WONT = #252; - TLNT_DO = #253; - TLNT_DONT = #254; - TLNT_IAC = #255; - -type - {:@abstract(State of telnet protocol). Used internaly by TTelnetSend.} - TTelnetState =(tsDATA, tsIAC, tsIAC_SB, tsIAC_WILL, tsIAC_DO, tsIAC_WONT, - tsIAC_DONT, tsIAC_SBIAC, tsIAC_SBDATA, tsSBDATA_IAC); - - {:@abstract(Class with implementation of Telnet/SSH script client.) - - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TTelnetSend = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FBuffer: Ansistring; - FState: TTelnetState; - FSessionLog: Ansistring; - FSubNeg: Ansistring; - FSubType: Ansichar; - FTermType: Ansistring; - function Connect: Boolean; - function Negotiate(const Buf: Ansistring): Ansistring; - procedure FilterHook(Sender: TObject; var Value: AnsiString); - public - constructor Create; - destructor Destroy; override; - - {:Connects to Telnet server.} - function Login: Boolean; - - {:Connects to SSH2 server and login by Username and Password properties. - - You must use some of SSL plugins with SSH support. For exammple CryptLib.} - function SSHLogin: Boolean; - - {:Logout from telnet server.} - procedure Logout; - - {:Send this data to telnet server.} - procedure Send(const Value: string); - - {:Reading data from telnet server until Value is readed. If it is not readed - until timeout, result is @false. Otherwise result is @true.} - function WaitFor(const Value: string): Boolean; - - {:Read data terminated by terminator from telnet server.} - function RecvTerminated(const Terminator: string): string; - - {:Read string from telnet server.} - function RecvString: string; - published - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - - {:all readed datas in this session (from connect) is stored in this large - string.} - property SessionLog: Ansistring read FSessionLog write FSessionLog; - - {:Terminal type indentification. By default is 'SYNAPSE'.} - property TermType: Ansistring read FTermType write FTermType; - end; - -implementation - -constructor TTelnetSend.Create; -begin - inherited Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.OnReadFilter := FilterHook; - FTimeout := 60000; - FTargetPort := cTelnetProtocol; - FSubNeg := ''; - FSubType := #0; - FTermType := 'SYNAPSE'; -end; - -destructor TTelnetSend.Destroy; -begin - FSock.Free; - inherited Destroy; -end; - -function TTelnetSend.Connect: Boolean; -begin - // Do not call this function! It is calling by LOGIN method! - FBuffer := ''; - FSessionLog := ''; - FState := tsDATA; - FSock.CloseSocket; - FSock.LineBuffer := ''; - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(FTargetHost, FTargetPort); - Result := FSock.LastError = 0; -end; - -function TTelnetSend.RecvTerminated(const Terminator: string): string; -begin - Result := FSock.RecvTerminated(FTimeout, Terminator); -end; - -function TTelnetSend.RecvString: string; -begin - Result := FSock.RecvTerminated(FTimeout, CRLF); -end; - -function TTelnetSend.WaitFor(const Value: string): Boolean; -begin - Result := FSock.RecvTerminated(FTimeout, Value) <> ''; -end; - -procedure TTelnetSend.FilterHook(Sender: TObject; var Value: AnsiString); -begin - Value := Negotiate(Value); - FSessionLog := FSessionLog + Value; -end; - -function TTelnetSend.Negotiate(const Buf: Ansistring): Ansistring; -var - n: integer; - c: Ansichar; - Reply: Ansistring; - SubReply: Ansistring; -begin - Result := ''; - for n := 1 to Length(Buf) do - begin - c := Buf[n]; - Reply := ''; - case FState of - tsData: - if c = TLNT_IAC then - FState := tsIAC - else - Result := Result + c; - - tsIAC: - case c of - TLNT_IAC: - begin - FState := tsData; - Result := Result + TLNT_IAC; - end; - TLNT_WILL: - FState := tsIAC_WILL; - TLNT_WONT: - FState := tsIAC_WONT; - TLNT_DONT: - FState := tsIAC_DONT; - TLNT_DO: - FState := tsIAC_DO; - TLNT_EOR: - FState := tsDATA; - TLNT_SB: - begin - FState := tsIAC_SB; - FSubType := #0; - FSubNeg := ''; - end; - else - FState := tsData; - end; - - tsIAC_WILL: - begin - case c of - #3: //suppress GA - Reply := TLNT_DO; - else - Reply := TLNT_DONT; - end; - FState := tsData; - end; - - tsIAC_WONT: - begin - Reply := TLNT_DONT; - FState := tsData; - end; - - tsIAC_DO: - begin - case c of - #24: //termtype - Reply := TLNT_WILL; - else - Reply := TLNT_WONT; - end; - FState := tsData; - end; - - tsIAC_DONT: - begin - Reply := TLNT_WONT; - FState := tsData; - end; - - tsIAC_SB: - begin - FSubType := c; - FState := tsIAC_SBDATA; - end; - - tsIAC_SBDATA: - begin - if c = TLNT_IAC then - FState := tsSBDATA_IAC - else - FSubNeg := FSubNeg + c; - end; - - tsSBDATA_IAC: - case c of - TLNT_IAC: - begin - FState := tsIAC_SBDATA; - FSubNeg := FSubNeg + c; - end; - TLNT_SE: - begin - SubReply := ''; - case FSubType of - #24: //termtype - begin - if (FSubNeg <> '') and (FSubNeg[1] = #1) then - SubReply := #0 + FTermType; - end; - end; - Sock.SendString(TLNT_IAC + TLNT_SB + FSubType + SubReply + TLNT_IAC + TLNT_SE); - FState := tsDATA; - end; - else - FState := tsDATA; - end; - - else - FState := tsData; - end; - if Reply <> '' then - Sock.SendString(TLNT_IAC + Reply + c); - end; - -end; - -procedure TTelnetSend.Send(const Value: string); -begin - Sock.SendString(ReplaceString(Value, TLNT_IAC, TLNT_IAC + TLNT_IAC)); -end; - -function TTelnetSend.Login: Boolean; -begin - Result := False; - if not Connect then - Exit; - Result := True; -end; - -function TTelnetSend.SSHLogin: Boolean; -begin - Result := False; - if Connect then - begin - FSock.SSL.SSLType := LT_SSHv2; - FSock.SSL.Username := FUsername; - FSock.SSL.Password := FPassword; - FSock.SSLDoConnect; - Result := FSock.LastError = 0; - end; -end; - -procedure TTelnetSend.Logout; -begin - FSock.CloseSocket; -end; - - -end. +{==============================================================================| +| Project : Ararat Synapse | 001.003.001 | +|==============================================================================| +| Content: TELNET and SSH2 client | +|==============================================================================| +| Copyright (c)1999-2010, Lukas Gebauer | +| All rights reserved. | +| | +| Redistribution and use in source and binary forms, with or without | +| modification, are permitted provided that the following conditions are met: | +| | +| Redistributions of source code must retain the above copyright notice, this | +| list of conditions and the following disclaimer. | +| | +| Redistributions in binary form must reproduce the above copyright notice, | +| this list of conditions and the following disclaimer in the documentation | +| and/or other materials provided with the distribution. | +| | +| Neither the name of Lukas Gebauer nor the names of its contributors may | +| be used to endorse or promote products derived from this software without | +| specific prior written permission. | +| | +| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | +| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | +| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | +| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | +| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | +| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | +| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | +| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | +| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | +| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | +| DAMAGE. | +|==============================================================================| +| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| +| Portions created by Lukas Gebauer are Copyright (c)2002-2010. | +| All Rights Reserved. | +|==============================================================================| +| Contributor(s): | +|==============================================================================| +| History: see HISTORY.HTM from distribution package | +| (Found at URL: http://www.ararat.cz/synapse/) | +|==============================================================================} + +{:@abstract(Telnet script client) + +Used RFC: RFC-854 +} + +{$IFDEF FPC} + {$MODE DELPHI} +{$ENDIF} +{$H+} + +{$IFDEF UNICODE} + {$WARN IMPLICIT_STRING_CAST OFF} + {$WARN IMPLICIT_STRING_CAST_LOSS OFF} +{$ENDIF} + +unit tlntsend; + +interface + +uses + SysUtils, Classes, + blcksock, synautil; + +const + cTelnetProtocol = '23'; + cSSHProtocol = '22'; + + TLNT_EOR = #239; + TLNT_SE = #240; + TLNT_NOP = #241; + TLNT_DATA_MARK = #242; + TLNT_BREAK = #243; + TLNT_IP = #244; + TLNT_AO = #245; + TLNT_AYT = #246; + TLNT_EC = #247; + TLNT_EL = #248; + TLNT_GA = #249; + TLNT_SB = #250; + TLNT_WILL = #251; + TLNT_WONT = #252; + TLNT_DO = #253; + TLNT_DONT = #254; + TLNT_IAC = #255; + +type + {:@abstract(State of telnet protocol). Used internaly by TTelnetSend.} + TTelnetState =(tsDATA, tsIAC, tsIAC_SB, tsIAC_WILL, tsIAC_DO, tsIAC_WONT, + tsIAC_DONT, tsIAC_SBIAC, tsIAC_SBDATA, tsSBDATA_IAC); + + {:@abstract(Class with implementation of Telnet/SSH script client.) + + Note: Are you missing properties for specify server address and port? Look to + parent @link(TSynaClient) too!} + TTelnetSend = class(TSynaClient) + private + FSock: TTCPBlockSocket; + FBuffer: Ansistring; + FState: TTelnetState; + FSessionLog: Ansistring; + FSubNeg: Ansistring; + FSubType: Ansichar; + FTermType: Ansistring; + function Connect: Boolean; + function Negotiate(const Buf: Ansistring): Ansistring; + procedure FilterHook(Sender: TObject; var Value: AnsiString); + public + constructor Create; + destructor Destroy; override; + + {:Connects to Telnet server.} + function Login: Boolean; + + {:Connects to SSH2 server and login by Username and Password properties. + + You must use some of SSL plugins with SSH support. For exammple CryptLib.} + function SSHLogin: Boolean; + + {:Logout from telnet server.} + procedure Logout; + + {:Send this data to telnet server.} + procedure Send(const Value: string); + + {:Reading data from telnet server until Value is readed. If it is not readed + until timeout, result is @false. Otherwise result is @true.} + function WaitFor(const Value: string): Boolean; + + {:Read data terminated by terminator from telnet server.} + function RecvTerminated(const Terminator: string): string; + + {:Read string from telnet server.} + function RecvString: string; + published + {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} + property Sock: TTCPBlockSocket read FSock; + + {:all readed datas in this session (from connect) is stored in this large + string.} + property SessionLog: Ansistring read FSessionLog write FSessionLog; + + {:Terminal type indentification. By default is 'SYNAPSE'.} + property TermType: Ansistring read FTermType write FTermType; + end; + +implementation + +constructor TTelnetSend.Create; +begin + inherited Create; + FSock := TTCPBlockSocket.Create; + FSock.Owner := self; + FSock.OnReadFilter := FilterHook; + FTimeout := 60000; + FTargetPort := cTelnetProtocol; + FSubNeg := ''; + FSubType := #0; + FTermType := 'SYNAPSE'; +end; + +destructor TTelnetSend.Destroy; +begin + FSock.Free; + inherited Destroy; +end; + +function TTelnetSend.Connect: Boolean; +begin + // Do not call this function! It is calling by LOGIN method! + FBuffer := ''; + FSessionLog := ''; + FState := tsDATA; + FSock.CloseSocket; + FSock.LineBuffer := ''; + FSock.Bind(FIPInterface, cAnyPort); + FSock.Connect(FTargetHost, FTargetPort); + Result := FSock.LastError = 0; +end; + +function TTelnetSend.RecvTerminated(const Terminator: string): string; +begin + Result := FSock.RecvTerminated(FTimeout, Terminator); +end; + +function TTelnetSend.RecvString: string; +begin + Result := FSock.RecvTerminated(FTimeout, CRLF); +end; + +function TTelnetSend.WaitFor(const Value: string): Boolean; +begin + Result := FSock.RecvTerminated(FTimeout, Value) <> ''; +end; + +procedure TTelnetSend.FilterHook(Sender: TObject; var Value: AnsiString); +begin + Value := Negotiate(Value); + FSessionLog := FSessionLog + Value; +end; + +function TTelnetSend.Negotiate(const Buf: Ansistring): Ansistring; +var + n: integer; + c: Ansichar; + Reply: Ansistring; + SubReply: Ansistring; +begin + Result := ''; + for n := 1 to Length(Buf) do + begin + c := Buf[n]; + Reply := ''; + case FState of + tsData: + if c = TLNT_IAC then + FState := tsIAC + else + Result := Result + c; + + tsIAC: + case c of + TLNT_IAC: + begin + FState := tsData; + Result := Result + TLNT_IAC; + end; + TLNT_WILL: + FState := tsIAC_WILL; + TLNT_WONT: + FState := tsIAC_WONT; + TLNT_DONT: + FState := tsIAC_DONT; + TLNT_DO: + FState := tsIAC_DO; + TLNT_EOR: + FState := tsDATA; + TLNT_SB: + begin + FState := tsIAC_SB; + FSubType := #0; + FSubNeg := ''; + end; + else + FState := tsData; + end; + + tsIAC_WILL: + begin + case c of + #3: //suppress GA + Reply := TLNT_DO; + else + Reply := TLNT_DONT; + end; + FState := tsData; + end; + + tsIAC_WONT: + begin + Reply := TLNT_DONT; + FState := tsData; + end; + + tsIAC_DO: + begin + case c of + #24: //termtype + Reply := TLNT_WILL; + else + Reply := TLNT_WONT; + end; + FState := tsData; + end; + + tsIAC_DONT: + begin + Reply := TLNT_WONT; + FState := tsData; + end; + + tsIAC_SB: + begin + FSubType := c; + FState := tsIAC_SBDATA; + end; + + tsIAC_SBDATA: + begin + if c = TLNT_IAC then + FState := tsSBDATA_IAC + else + FSubNeg := FSubNeg + c; + end; + + tsSBDATA_IAC: + case c of + TLNT_IAC: + begin + FState := tsIAC_SBDATA; + FSubNeg := FSubNeg + c; + end; + TLNT_SE: + begin + SubReply := ''; + case FSubType of + #24: //termtype + begin + if (FSubNeg <> '') and (FSubNeg[1] = #1) then + SubReply := #0 + FTermType; + end; + end; + Sock.SendString(TLNT_IAC + TLNT_SB + FSubType + SubReply + TLNT_IAC + TLNT_SE); + FState := tsDATA; + end; + else + FState := tsDATA; + end; + + else + FState := tsData; + end; + if Reply <> '' then + Sock.SendString(TLNT_IAC + Reply + c); + end; + +end; + +procedure TTelnetSend.Send(const Value: string); +begin + Sock.SendString(ReplaceString(Value, TLNT_IAC, TLNT_IAC + TLNT_IAC)); +end; + +function TTelnetSend.Login: Boolean; +begin + Result := False; + if not Connect then + Exit; + Result := True; +end; + +function TTelnetSend.SSHLogin: Boolean; +begin + Result := False; + if Connect then + begin + FSock.SSL.SSLType := LT_SSHv2; + FSock.SSL.Username := FUsername; + FSock.SSL.Password := FPassword; + FSock.SSLDoConnect; + Result := FSock.LastError = 0; + end; +end; + +procedure TTelnetSend.Logout; +begin + FSock.CloseSocket; +end; + + +end. diff --git a/3rd/synapse/source/tzutil.pas b/3rd/synapse/source/tzutil.pas index 7657f1645..782402847 100644 --- a/3rd/synapse/source/tzutil.pas +++ b/3rd/synapse/source/tzutil.pas @@ -1,702 +1,702 @@ -//Unit with timezone support for some Freepascal platforms. -//Tomas Hajny - -unit tzutil; - - -interface - -type - DSTSpecType = (DSTMonthWeekDay, DSTMonthDay, DSTJulian, DSTJulianX); - -(* Initialized to default values *) -const - TZName: string = ''; - TZDSTName: string = ''; - TZOffset: longint = 0; - DSTOffset: longint = 0; - DSTStartMonth: byte = 4; - DSTStartWeek: shortint = 1; - DSTStartDay: word = 0; - DSTStartSec: cardinal = 7200; - DSTEndMonth: byte = 10; - DSTEndWeek: shortint = -1; - DSTEndDay: word = 0; - DSTEndSec: cardinal = 10800; - DSTStartSpecType: DSTSpecType = DSTMonthWeekDay; - DSTEndSpecType: DSTSpecType = DSTMonthWeekDay; - -function TZSeconds: longint; -(* Return current offset from UTC in seconds while respecting DST *) - -implementation - -uses - Dos; - -function TZSeconds: longint; -const - MonthDays: array [1..12] of byte = - (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); - MonthEnds: array [1..12] of word = - (31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365); -var - Y, Mo, D, WD, H, Mi, S, S100: word; - MS, DS, ME, DE: byte; - L: longint; - Second: cardinal; - AfterDSTStart, BeforeDSTEnd: boolean; - -function LeapDay: byte; -begin - if (Y mod 400 = 0) or (Y mod 100 <> 0) and (Y mod 4 = 0) then - LeapDay := 1 - else - LeapDay := 0; -end; - -function FirstDay (MM: byte): byte; -(* What day of week (0-6) is the first day of month MM? *) -var - DD: longint; -begin - if MM < Mo then - begin - DD := D + MonthEnds [Pred (Mo)]; - if MM > 1 then - Dec (DD, MonthEnds [Pred (MM)]); - if (MM <= 2) and (Mo > 2) then - Inc (DD, LeapDay); - end - else - if MM > Mo then - begin - DD := - MonthDays [Mo] + D - MonthEnds [Pred (MM)] + MonthEnds [Mo]; - if (Mo <= 2) and (MM > 2) then - Dec (DD, LeapDay); - end - else -(* M = MM *) - DD := D; - DD := WD - DD mod 7 + 1; - if DD < 0 then - FirstDay := DD + 7 - else - FirstDay := DD mod 7; -end; - -begin - TZSeconds := TZOffset; - if DSTOffset <> TZOffset then - begin - GetDate (Y, Mo, D, WD); - GetTime (H, Mi, S, S100); - Second := cardinal (H) * 3600 + Mi * 60 + S; - - if (DSTStartSpecType = DSTMonthWeekDay) or (DSTStartSpecType = DSTMonthDay) - then - begin - MS := DSTStartMonth; - if DSTStartSpecType = DSTMonthDay then - DS := DSTStartDay - else - begin - DS := FirstDay (DSTStartMonth); - if (DSTStartWeek >= 1) and (DSTStartWeek <= 4) then - if DSTStartDay < DS then - DS := DSTStartWeek * 7 + DSTStartDay - DS + 1 - else - DS := Pred (DSTStartWeek) * 7 + DSTStartDay - DS + 1 - else -(* Last week in month *) - begin - DS := DS + MonthDays [MS] - 1; - if MS = 2 then - Inc (DS, LeapDay); - DS := DS mod 7; - if DS < DSTStartDay then - DS := DS + 7 - DSTStartDay - else - DS := DS - DSTStartDay; - DS := MonthDays [MS] - DS; - end; - end; - end - else - begin -(* Julian day *) - L := DSTStartDay; - if (DSTStartSpecType = DSTJulian) then -(* 0-based *) - if (L + LeapDay <= 59) then - Inc (L) - else - L := L + 1 - LeapDay; - if L <= 31 then - begin - MS := 1; - DS := L; - end - else - if (L <= 59) or - (DSTStartSpecType = DSTJulian) and (L - LeapDay <= 59) then - begin - MS := 2; - DS := DSTStartDay - 31; - end - else - begin - MS := 3; - while (MS < 12) and (MonthEnds [MS] > L) do - Inc (MS); - DS := L - MonthEnds [Pred (MS)]; - end; - end; - - if (DSTEndSpecType = DSTMonthWeekDay) or (DSTEndSpecType = DSTMonthDay) then - begin - ME := DSTEndMonth; - if DSTEndSpecType = DSTMonthDay then - DE := DSTEndDay - else - begin - DE := FirstDay (DSTEndMonth); - if (DSTEndWeek >= 1) and (DSTEndWeek <= 4) then - if DSTEndDay < DE then - DE := DSTEndWeek * 7 + DSTEndDay - DE + 1 - else - DE := Pred (DSTEndWeek) * 7 + DSTEndDay - DE + 1 - else -(* Last week in month *) - begin - DE := DE + MonthDays [ME] - 1; - if ME = 2 then - Inc (DE, LeapDay); - DE := DE mod 7; - if DE < DSTEndDay then - DE := DE + 7 - DSTEndDay - else - DE := DE - DSTEndDay; - DE := MonthDays [ME] - DE; - end; - end; - end - else - begin -(* Julian day *) - L := DSTEndDay; - if (DSTEndSpecType = DSTJulian) then -(* 0-based *) - if (L + LeapDay <= 59) then - Inc (L) - else - L := L + 1 - LeapDay; - if L <= 31 then - begin - ME := 1; - DE := L; - end - else - if (L <= 59) or - (DSTEndSpecType = DSTJulian) and (L - LeapDay <= 59) then - begin - ME := 2; - DE := DSTEndDay - 31; - end - else - begin - ME := 3; - while (ME < 12) and (MonthEnds [ME] > L) do - Inc (ME); - DE := L - MonthEnds [Pred (ME)]; - end; - end; - - if Mo < MS then - AfterDSTStart := false - else - if Mo > MS then - AfterDSTStart := true - else - if D < DS then - AfterDSTStart := false - else - if D > DS then - AfterDSTStart := true - else - AfterDSTStart := Second > DSTStartSec; - if Mo > ME then - BeforeDSTEnd := false - else - if Mo < ME then - BeforeDSTEnd := true - else - if D > DE then - BeforeDSTEnd := false - else - if D < DE then - BeforeDSTEnd := true - else - BeforeDSTEnd := Second < DSTEndSec; - if AfterDSTStart and BeforeDSTEnd then - TZSeconds := DSTOffset; - end; -end; - -procedure InitTZ; -const - TZEnvName = 'TZ'; - EMXTZEnvName = 'EMXTZ'; -var - TZ, S: string; - I, J: byte; - Err: longint; - GnuFmt: boolean; - ADSTStartMonth: byte; - ADSTStartWeek: shortint; - ADSTStartDay: word; - ADSTStartSec: cardinal; - ADSTEndMonth: byte; - ADSTEndWeek: shortint; - ADSTEndDay: word; - ADSTEndSec: cardinal; - ADSTStartSpecType: DSTSpecType; - ADSTEndSpecType: DSTSpecType; - ADSTChangeSec: cardinal; - - function ParseOffset (OffStr: string): longint; - (* Parse time offset given as [-|+]HH[:MI[:SS]] and return in seconds *) - var - TZShiftHH, TZShiftDir: shortint; - TZShiftMI, TZShiftSS: byte; - N1, N2: byte; - begin - TZShiftHH := 0; - TZShiftMI := 0; - TZShiftSS := 0; - TZShiftDir := 1; - N1 := 1; - while (N1 <= Length (OffStr)) and (OffStr [N1] <> ':') do - Inc (N1); - Val (Copy (OffStr, 1, Pred (N1)), TZShiftHH, Err); - if (Err = 0) and (TZShiftHH >= -24) and (TZShiftHH <= 23) then - begin -(* Normalize the hour offset to -12..11 if necessary *) - if TZShiftHH > 11 then - Dec (TZShiftHH, 24) else - if TZShiftHH < -12 then - Inc (TZShiftHH, 24); - if TZShiftHH < 0 then - TZShiftDir := -1; - if (N1 <= Length (OffStr)) then - begin - N2 := Succ (N1); - while (N2 <= Length (OffStr)) and (OffStr [N2] <> ':') do - Inc (N2); - Val (Copy (OffStr, Succ (N1), N2 - N1), TZShiftMI, Err); - if (Err = 0) and (TZShiftMI <= 59) then - begin - if (N2 <= Length (OffStr)) then - begin - Val (Copy (OffStr, Succ (N2), Length (OffStr) - N2), TZShiftSS, Err); - if (Err <> 0) or (TZShiftSS > 59) then - TZShiftSS := 0; - end - end - else - TZShiftMI := 0; - end; - end - else - TZShiftHH := 0; - ParseOffset := longint (TZShiftHH) * 3600 + - TZShiftDir * (longint (TZShiftMI) * 60 + TZShiftSS); - end; - -begin - TZ := GetEnv (TZEnvName); - if TZ = '' then - TZ := GetEnv (EMXTZEnvName); - if TZ <> '' then - begin - TZ := Upcase (TZ); -(* Timezone name *) - I := 1; - while (I <= Length (TZ)) and (TZ [I] in ['A'..'Z']) do - Inc (I); - TZName := Copy (TZ, 1, Pred (I)); - if I <= Length (TZ) then - begin -(* Timezone shift *) - J := Succ (I); - while (J <= Length (TZ)) and not (TZ [J] in ['A'..'Z']) do - Inc (J); - TZOffset := ParseOffset (Copy (TZ, I, J - I)); -(* DST timezone name *) - I := J; - while (J <= Length (TZ)) and (TZ [J] in ['A'..'Z']) do - Inc (J); - if J > I then - begin - TZDSTName := Copy (TZ, I, J - I); -(* DST timezone name provided; if equal to the standard timezone *) -(* name then DSTOffset is set to be equal to TZOffset by default, *) -(* otherwise it is set to TZOffset - 3600 seconds. *) - if TZDSTName <> TZName then - DSTOffset := -3600 + TZOffset - else - DSTOffset := TZOffset; - end - else - begin - TZDSTName := TZName; -(* No DST timezone name provided => DSTOffset is equal to TZOffset *) - DSTOffset := TZOffset; - end; - if J <= Length (TZ) then - begin -(* Check if DST offset is specified here; *) -(* if not, default value set above is used. *) - if TZ [J] <> ',' then - begin - I := J; - Inc (J); - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - DSTOffset := ParseOffset (Copy (TZ, I, J - I)); - end; - if J < Length (TZ) then - begin - Inc (J); -(* DST switching details *) - case TZ [J] of - 'M': - begin -(* Mmonth.week.dayofweek[/StartHour] *) - ADSTStartSpecType := DSTMonthWeekDay; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTStartMonth, Err); - if (Err > 0) or (ADSTStartMonth > 12) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTStartWeek, Err); - if (Err > 0) or (ADSTStartWeek < 1) or (ADSTStartWeek > 5) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay < 0) or (ADSTStartDay > 6) - or (J >= Length (TZ)) then - Exit; - if TZ [J] = '/' then - begin - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) - then - Exit - else - ADSTStartSec := ADSTStartSec * 3600; - end - else - (* Use the preset default *) - ADSTStartSec := DSTStartSec; - Inc (J); - end; - 'J': - begin -(* Jjulianday[/StartHour] *) - ADSTStartSpecType := DSTJulianX; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay = 0) or (ADSTStartDay > 365) - or (J >= Length (TZ)) then - Exit; - if TZ [J] = '/' then - begin - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) - then - Exit - else - ADSTStartSec := ADSTStartSec * 3600; - end - else - (* Use the preset default *) - ADSTStartSec := DSTStartSec; - Inc (J); - end - else - begin -(* Check the used format first - GNU libc / GCC / EMX expect *) -(* "NameOffsetDstname[Dstoffset],Start[/StartHour],End[/EndHour]"; *) -(* if more than one comma (',') is found, the following format is assumed: *) -(* "NameOffsetDstname[Dstoffset],StartMonth,StartWeek,StartDay,StartSecond, *) -(* EndMonth,EndWeek,EndDay,EndSecond,DSTDifference". *) - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - S := Copy (TZ, I, J - I); - if J < Length (TZ) then - begin - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - GnuFmt := J > Length (TZ); - end - else - Exit; - if GnuFmt then - begin - ADSTStartSpecType := DSTJulian; - J := Pos ('/', S); - if J = 0 then - begin - Val (S, ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay > 365) then - Exit; - (* Use the preset default *) - ADSTStartSec := DSTStartSec; - end - else - begin - if J = Length (S) then - Exit; - Val (Copy (S, 1, Pred (J)), ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay > 365) then - Exit; - Val (Copy (S, Succ (J), Length (S) - J), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) then - Exit - else - ADSTStartSec := ADSTStartSec * 3600; - end; - J := I; - end - else - begin - Val (S, ADSTStartMonth, Err); - if (Err > 0) or (ADSTStartMonth > 12) then - Exit; - Val (Copy (TZ, I, J - I), ADSTStartWeek, Err); - if (Err > 0) or (ADSTStartWeek < -1) or (ADSTStartWeek > 5) or - (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartDay, Err); - if (DSTStartWeek = 0) then - begin - if (Err > 0) or (ADSTStartDay < 1) or (ADSTStartDay > 31) - or (ADSTStartDay > 30) and (ADSTStartMonth in [4, 6, 9, 11]) - or (ADSTStartMonth = 2) and (ADSTStartDay > 29) then - Exit; - ADSTStartSpecType := DSTMonthDay; - end - else - begin - if (Err > 0) or (ADSTStartDay < 0) or (ADSTStartDay > 6) then - Exit; - ADSTStartSpecType := DSTMonthWeekDay; - end; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndMonth, Err); - if (Err > 0) or (ADSTEndMonth > 12) or (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndWeek, Err); - if (Err > 0) or (ADSTEndWeek < -1) or (ADSTEndWeek > 5) - or (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndDay, Err); - if (DSTEndWeek = 0) then - begin - if (Err > 0) or (ADSTEndDay < 1) or (ADSTEndDay > 31) - or (ADSTEndDay > 30) and (ADSTEndMonth in [4, 6, 9, 11]) - or (ADSTEndMonth = 2) and (ADSTEndDay > 29) then - Exit; - ADSTEndSpecType := DSTMonthDay; - end - else - begin - if (Err > 0) or (ADSTEndDay < 0) or (ADSTEndDay > 6) then - Exit; - ADSTEndSpecType := DSTMonthWeekDay; - end; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndSec, Err); - if (Err > 0) or (ADSTEndSec > 86399) or (J >= Length (TZ)) then - Exit; - Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTChangeSec, Err); - if (Err = 0) and (ADSTChangeSec < 86400) then - begin -(* Format complete, all checks successful => accept the parsed values. *) - DSTStartMonth := ADSTStartMonth; - DSTStartWeek := ADSTStartWeek; - DSTStartDay := ADSTStartDay; - DSTStartSec := ADSTStartSec; - DSTEndMonth := ADSTEndMonth; - DSTEndWeek := ADSTEndWeek; - DSTEndDay := ADSTEndDay; - DSTEndSec := ADSTEndSec; - DSTStartSpecType := ADSTStartSpecType; - DSTEndSpecType := ADSTEndSpecType; - DSTOffset := TZOffset - ADSTChangeSec; - end; -(* Parsing finished *) - Exit; - end; - end; - end; -(* GnuFmt - DST end specification *) - if TZ [J] = 'M' then - begin -(* Mmonth.week.dayofweek *) - ADSTEndSpecType := DSTMonthWeekDay; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTEndMonth, Err); - if (Err > 0) or (ADSTEndMonth > 12) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTEndWeek, Err); - if (Err > 0) or (ADSTEndWeek < 1) or (ADSTEndWeek > 5) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> '/') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndDay, Err); - if (Err > 0) or (ADSTEndDay < 0) or (ADSTEndDay > 6) then - Exit; - end - else - begin - if TZ [J] = 'J' then - begin -(* Jjulianday *) - if J = Length (TZ) then - Exit; - Inc (J); - ADSTEndSpecType := DSTJulianX - end - else - ADSTEndSpecType := DSTJulian; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> '/') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndDay, Err); - if (Err > 0) or (ADSTEndDay = 0) and (ADSTEndSpecType = DSTJulianX) - or (ADSTEndDay > 365) then - Exit; - end; - if (J <= Length (TZ)) and (TZ [J] = '/') then - begin - if J = Length (TZ) then - Exit; - Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTEndSec, Err); - if (Err > 0) or (ADSTEndSec > 86399) then - Exit - else - ADSTEndSec := ADSTEndSec * 3600; - end - else - (* Use the preset default *) - ADSTEndSec := DSTEndSec; - -(* Format complete, all checks successful => accept the parsed values. *) - if ADSTStartSpecType = DSTMonthWeekDay then - begin - DSTStartMonth := ADSTStartMonth; - DSTStartWeek := ADSTStartWeek; - end; - DSTStartDay := ADSTStartDay; - DSTStartSec := ADSTStartSec; - if ADSTStartSpecType = DSTMonthWeekDay then - begin - DSTEndMonth := ADSTEndMonth; - DSTEndWeek := ADSTEndWeek; - end; - DSTEndDay := ADSTEndDay; - DSTEndSec := ADSTEndSec; - DSTStartSpecType := ADSTStartSpecType; - DSTEndSpecType := ADSTEndSpecType; - end; - end - else - DSTOffset := -3600 + TZOffset; - end; - end; -end; - - -begin - InitTZ; -end. +//Unit with timezone support for some Freepascal platforms. +//Tomas Hajny + +unit tzutil; + + +interface + +type + DSTSpecType = (DSTMonthWeekDay, DSTMonthDay, DSTJulian, DSTJulianX); + +(* Initialized to default values *) +const + TZName: string = ''; + TZDSTName: string = ''; + TZOffset: longint = 0; + DSTOffset: longint = 0; + DSTStartMonth: byte = 4; + DSTStartWeek: shortint = 1; + DSTStartDay: word = 0; + DSTStartSec: cardinal = 7200; + DSTEndMonth: byte = 10; + DSTEndWeek: shortint = -1; + DSTEndDay: word = 0; + DSTEndSec: cardinal = 10800; + DSTStartSpecType: DSTSpecType = DSTMonthWeekDay; + DSTEndSpecType: DSTSpecType = DSTMonthWeekDay; + +function TZSeconds: longint; +(* Return current offset from UTC in seconds while respecting DST *) + +implementation + +uses + Dos; + +function TZSeconds: longint; +const + MonthDays: array [1..12] of byte = + (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); + MonthEnds: array [1..12] of word = + (31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365); +var + Y, Mo, D, WD, H, Mi, S, S100: word; + MS, DS, ME, DE: byte; + L: longint; + Second: cardinal; + AfterDSTStart, BeforeDSTEnd: boolean; + +function LeapDay: byte; +begin + if (Y mod 400 = 0) or (Y mod 100 <> 0) and (Y mod 4 = 0) then + LeapDay := 1 + else + LeapDay := 0; +end; + +function FirstDay (MM: byte): byte; +(* What day of week (0-6) is the first day of month MM? *) +var + DD: longint; +begin + if MM < Mo then + begin + DD := D + MonthEnds [Pred (Mo)]; + if MM > 1 then + Dec (DD, MonthEnds [Pred (MM)]); + if (MM <= 2) and (Mo > 2) then + Inc (DD, LeapDay); + end + else + if MM > Mo then + begin + DD := - MonthDays [Mo] + D - MonthEnds [Pred (MM)] + MonthEnds [Mo]; + if (Mo <= 2) and (MM > 2) then + Dec (DD, LeapDay); + end + else +(* M = MM *) + DD := D; + DD := WD - DD mod 7 + 1; + if DD < 0 then + FirstDay := DD + 7 + else + FirstDay := DD mod 7; +end; + +begin + TZSeconds := TZOffset; + if DSTOffset <> TZOffset then + begin + GetDate (Y, Mo, D, WD); + GetTime (H, Mi, S, S100); + Second := cardinal (H) * 3600 + Mi * 60 + S; + + if (DSTStartSpecType = DSTMonthWeekDay) or (DSTStartSpecType = DSTMonthDay) + then + begin + MS := DSTStartMonth; + if DSTStartSpecType = DSTMonthDay then + DS := DSTStartDay + else + begin + DS := FirstDay (DSTStartMonth); + if (DSTStartWeek >= 1) and (DSTStartWeek <= 4) then + if DSTStartDay < DS then + DS := DSTStartWeek * 7 + DSTStartDay - DS + 1 + else + DS := Pred (DSTStartWeek) * 7 + DSTStartDay - DS + 1 + else +(* Last week in month *) + begin + DS := DS + MonthDays [MS] - 1; + if MS = 2 then + Inc (DS, LeapDay); + DS := DS mod 7; + if DS < DSTStartDay then + DS := DS + 7 - DSTStartDay + else + DS := DS - DSTStartDay; + DS := MonthDays [MS] - DS; + end; + end; + end + else + begin +(* Julian day *) + L := DSTStartDay; + if (DSTStartSpecType = DSTJulian) then +(* 0-based *) + if (L + LeapDay <= 59) then + Inc (L) + else + L := L + 1 - LeapDay; + if L <= 31 then + begin + MS := 1; + DS := L; + end + else + if (L <= 59) or + (DSTStartSpecType = DSTJulian) and (L - LeapDay <= 59) then + begin + MS := 2; + DS := DSTStartDay - 31; + end + else + begin + MS := 3; + while (MS < 12) and (MonthEnds [MS] > L) do + Inc (MS); + DS := L - MonthEnds [Pred (MS)]; + end; + end; + + if (DSTEndSpecType = DSTMonthWeekDay) or (DSTEndSpecType = DSTMonthDay) then + begin + ME := DSTEndMonth; + if DSTEndSpecType = DSTMonthDay then + DE := DSTEndDay + else + begin + DE := FirstDay (DSTEndMonth); + if (DSTEndWeek >= 1) and (DSTEndWeek <= 4) then + if DSTEndDay < DE then + DE := DSTEndWeek * 7 + DSTEndDay - DE + 1 + else + DE := Pred (DSTEndWeek) * 7 + DSTEndDay - DE + 1 + else +(* Last week in month *) + begin + DE := DE + MonthDays [ME] - 1; + if ME = 2 then + Inc (DE, LeapDay); + DE := DE mod 7; + if DE < DSTEndDay then + DE := DE + 7 - DSTEndDay + else + DE := DE - DSTEndDay; + DE := MonthDays [ME] - DE; + end; + end; + end + else + begin +(* Julian day *) + L := DSTEndDay; + if (DSTEndSpecType = DSTJulian) then +(* 0-based *) + if (L + LeapDay <= 59) then + Inc (L) + else + L := L + 1 - LeapDay; + if L <= 31 then + begin + ME := 1; + DE := L; + end + else + if (L <= 59) or + (DSTEndSpecType = DSTJulian) and (L - LeapDay <= 59) then + begin + ME := 2; + DE := DSTEndDay - 31; + end + else + begin + ME := 3; + while (ME < 12) and (MonthEnds [ME] > L) do + Inc (ME); + DE := L - MonthEnds [Pred (ME)]; + end; + end; + + if Mo < MS then + AfterDSTStart := false + else + if Mo > MS then + AfterDSTStart := true + else + if D < DS then + AfterDSTStart := false + else + if D > DS then + AfterDSTStart := true + else + AfterDSTStart := Second > DSTStartSec; + if Mo > ME then + BeforeDSTEnd := false + else + if Mo < ME then + BeforeDSTEnd := true + else + if D > DE then + BeforeDSTEnd := false + else + if D < DE then + BeforeDSTEnd := true + else + BeforeDSTEnd := Second < DSTEndSec; + if AfterDSTStart and BeforeDSTEnd then + TZSeconds := DSTOffset; + end; +end; + +procedure InitTZ; +const + TZEnvName = 'TZ'; + EMXTZEnvName = 'EMXTZ'; +var + TZ, S: string; + I, J: byte; + Err: longint; + GnuFmt: boolean; + ADSTStartMonth: byte; + ADSTStartWeek: shortint; + ADSTStartDay: word; + ADSTStartSec: cardinal; + ADSTEndMonth: byte; + ADSTEndWeek: shortint; + ADSTEndDay: word; + ADSTEndSec: cardinal; + ADSTStartSpecType: DSTSpecType; + ADSTEndSpecType: DSTSpecType; + ADSTChangeSec: cardinal; + + function ParseOffset (OffStr: string): longint; + (* Parse time offset given as [-|+]HH[:MI[:SS]] and return in seconds *) + var + TZShiftHH, TZShiftDir: shortint; + TZShiftMI, TZShiftSS: byte; + N1, N2: byte; + begin + TZShiftHH := 0; + TZShiftMI := 0; + TZShiftSS := 0; + TZShiftDir := 1; + N1 := 1; + while (N1 <= Length (OffStr)) and (OffStr [N1] <> ':') do + Inc (N1); + Val (Copy (OffStr, 1, Pred (N1)), TZShiftHH, Err); + if (Err = 0) and (TZShiftHH >= -24) and (TZShiftHH <= 23) then + begin +(* Normalize the hour offset to -12..11 if necessary *) + if TZShiftHH > 11 then + Dec (TZShiftHH, 24) else + if TZShiftHH < -12 then + Inc (TZShiftHH, 24); + if TZShiftHH < 0 then + TZShiftDir := -1; + if (N1 <= Length (OffStr)) then + begin + N2 := Succ (N1); + while (N2 <= Length (OffStr)) and (OffStr [N2] <> ':') do + Inc (N2); + Val (Copy (OffStr, Succ (N1), N2 - N1), TZShiftMI, Err); + if (Err = 0) and (TZShiftMI <= 59) then + begin + if (N2 <= Length (OffStr)) then + begin + Val (Copy (OffStr, Succ (N2), Length (OffStr) - N2), TZShiftSS, Err); + if (Err <> 0) or (TZShiftSS > 59) then + TZShiftSS := 0; + end + end + else + TZShiftMI := 0; + end; + end + else + TZShiftHH := 0; + ParseOffset := longint (TZShiftHH) * 3600 + + TZShiftDir * (longint (TZShiftMI) * 60 + TZShiftSS); + end; + +begin + TZ := GetEnv (TZEnvName); + if TZ = '' then + TZ := GetEnv (EMXTZEnvName); + if TZ <> '' then + begin + TZ := Upcase (TZ); +(* Timezone name *) + I := 1; + while (I <= Length (TZ)) and (TZ [I] in ['A'..'Z']) do + Inc (I); + TZName := Copy (TZ, 1, Pred (I)); + if I <= Length (TZ) then + begin +(* Timezone shift *) + J := Succ (I); + while (J <= Length (TZ)) and not (TZ [J] in ['A'..'Z']) do + Inc (J); + TZOffset := ParseOffset (Copy (TZ, I, J - I)); +(* DST timezone name *) + I := J; + while (J <= Length (TZ)) and (TZ [J] in ['A'..'Z']) do + Inc (J); + if J > I then + begin + TZDSTName := Copy (TZ, I, J - I); +(* DST timezone name provided; if equal to the standard timezone *) +(* name then DSTOffset is set to be equal to TZOffset by default, *) +(* otherwise it is set to TZOffset - 3600 seconds. *) + if TZDSTName <> TZName then + DSTOffset := -3600 + TZOffset + else + DSTOffset := TZOffset; + end + else + begin + TZDSTName := TZName; +(* No DST timezone name provided => DSTOffset is equal to TZOffset *) + DSTOffset := TZOffset; + end; + if J <= Length (TZ) then + begin +(* Check if DST offset is specified here; *) +(* if not, default value set above is used. *) + if TZ [J] <> ',' then + begin + I := J; + Inc (J); + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + DSTOffset := ParseOffset (Copy (TZ, I, J - I)); + end; + if J < Length (TZ) then + begin + Inc (J); +(* DST switching details *) + case TZ [J] of + 'M': + begin +(* Mmonth.week.dayofweek[/StartHour] *) + ADSTStartSpecType := DSTMonthWeekDay; + if J >= Length (TZ) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do + Inc (J); + if (J >= Length (TZ)) or (TZ [J] <> '.') then + Exit; + Val (Copy (TZ, I, J - I), ADSTStartMonth, Err); + if (Err > 0) or (ADSTStartMonth > 12) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do + Inc (J); + if (J >= Length (TZ)) or (TZ [J] <> '.') then + Exit; + Val (Copy (TZ, I, J - I), ADSTStartWeek, Err); + if (Err > 0) or (ADSTStartWeek < 1) or (ADSTStartWeek > 5) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTStartDay, Err); + if (Err > 0) or (ADSTStartDay < 0) or (ADSTStartDay > 6) + or (J >= Length (TZ)) then + Exit; + if TZ [J] = '/' then + begin + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTStartSec, Err); + if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) + then + Exit + else + ADSTStartSec := ADSTStartSec * 3600; + end + else + (* Use the preset default *) + ADSTStartSec := DSTStartSec; + Inc (J); + end; + 'J': + begin +(* Jjulianday[/StartHour] *) + ADSTStartSpecType := DSTJulianX; + if J >= Length (TZ) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTStartDay, Err); + if (Err > 0) or (ADSTStartDay = 0) or (ADSTStartDay > 365) + or (J >= Length (TZ)) then + Exit; + if TZ [J] = '/' then + begin + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTStartSec, Err); + if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) + then + Exit + else + ADSTStartSec := ADSTStartSec * 3600; + end + else + (* Use the preset default *) + ADSTStartSec := DSTStartSec; + Inc (J); + end + else + begin +(* Check the used format first - GNU libc / GCC / EMX expect *) +(* "NameOffsetDstname[Dstoffset],Start[/StartHour],End[/EndHour]"; *) +(* if more than one comma (',') is found, the following format is assumed: *) +(* "NameOffsetDstname[Dstoffset],StartMonth,StartWeek,StartDay,StartSecond, *) +(* EndMonth,EndWeek,EndDay,EndSecond,DSTDifference". *) + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + S := Copy (TZ, I, J - I); + if J < Length (TZ) then + begin + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + GnuFmt := J > Length (TZ); + end + else + Exit; + if GnuFmt then + begin + ADSTStartSpecType := DSTJulian; + J := Pos ('/', S); + if J = 0 then + begin + Val (S, ADSTStartDay, Err); + if (Err > 0) or (ADSTStartDay > 365) then + Exit; + (* Use the preset default *) + ADSTStartSec := DSTStartSec; + end + else + begin + if J = Length (S) then + Exit; + Val (Copy (S, 1, Pred (J)), ADSTStartDay, Err); + if (Err > 0) or (ADSTStartDay > 365) then + Exit; + Val (Copy (S, Succ (J), Length (S) - J), ADSTStartSec, Err); + if (Err > 0) or (ADSTStartSec > 86399) then + Exit + else + ADSTStartSec := ADSTStartSec * 3600; + end; + J := I; + end + else + begin + Val (S, ADSTStartMonth, Err); + if (Err > 0) or (ADSTStartMonth > 12) then + Exit; + Val (Copy (TZ, I, J - I), ADSTStartWeek, Err); + if (Err > 0) or (ADSTStartWeek < -1) or (ADSTStartWeek > 5) or + (J >= Length (TZ)) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTStartDay, Err); + if (DSTStartWeek = 0) then + begin + if (Err > 0) or (ADSTStartDay < 1) or (ADSTStartDay > 31) + or (ADSTStartDay > 30) and (ADSTStartMonth in [4, 6, 9, 11]) + or (ADSTStartMonth = 2) and (ADSTStartDay > 29) then + Exit; + ADSTStartSpecType := DSTMonthDay; + end + else + begin + if (Err > 0) or (ADSTStartDay < 0) or (ADSTStartDay > 6) then + Exit; + ADSTStartSpecType := DSTMonthWeekDay; + end; + if J >= Length (TZ) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTStartSec, Err); + if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTEndMonth, Err); + if (Err > 0) or (ADSTEndMonth > 12) or (J >= Length (TZ)) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTEndWeek, Err); + if (Err > 0) or (ADSTEndWeek < -1) or (ADSTEndWeek > 5) + or (J >= Length (TZ)) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTEndDay, Err); + if (DSTEndWeek = 0) then + begin + if (Err > 0) or (ADSTEndDay < 1) or (ADSTEndDay > 31) + or (ADSTEndDay > 30) and (ADSTEndMonth in [4, 6, 9, 11]) + or (ADSTEndMonth = 2) and (ADSTEndDay > 29) then + Exit; + ADSTEndSpecType := DSTMonthDay; + end + else + begin + if (Err > 0) or (ADSTEndDay < 0) or (ADSTEndDay > 6) then + Exit; + ADSTEndSpecType := DSTMonthWeekDay; + end; + if J >= Length (TZ) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> ',') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTEndSec, Err); + if (Err > 0) or (ADSTEndSec > 86399) or (J >= Length (TZ)) then + Exit; + Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTChangeSec, Err); + if (Err = 0) and (ADSTChangeSec < 86400) then + begin +(* Format complete, all checks successful => accept the parsed values. *) + DSTStartMonth := ADSTStartMonth; + DSTStartWeek := ADSTStartWeek; + DSTStartDay := ADSTStartDay; + DSTStartSec := ADSTStartSec; + DSTEndMonth := ADSTEndMonth; + DSTEndWeek := ADSTEndWeek; + DSTEndDay := ADSTEndDay; + DSTEndSec := ADSTEndSec; + DSTStartSpecType := ADSTStartSpecType; + DSTEndSpecType := ADSTEndSpecType; + DSTOffset := TZOffset - ADSTChangeSec; + end; +(* Parsing finished *) + Exit; + end; + end; + end; +(* GnuFmt - DST end specification *) + if TZ [J] = 'M' then + begin +(* Mmonth.week.dayofweek *) + ADSTEndSpecType := DSTMonthWeekDay; + if J >= Length (TZ) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do + Inc (J); + if (J >= Length (TZ)) or (TZ [J] <> '.') then + Exit; + Val (Copy (TZ, I, J - I), ADSTEndMonth, Err); + if (Err > 0) or (ADSTEndMonth > 12) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do + Inc (J); + if (J >= Length (TZ)) or (TZ [J] <> '.') then + Exit; + Val (Copy (TZ, I, J - I), ADSTEndWeek, Err); + if (Err > 0) or (ADSTEndWeek < 1) or (ADSTEndWeek > 5) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> '/') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTEndDay, Err); + if (Err > 0) or (ADSTEndDay < 0) or (ADSTEndDay > 6) then + Exit; + end + else + begin + if TZ [J] = 'J' then + begin +(* Jjulianday *) + if J = Length (TZ) then + Exit; + Inc (J); + ADSTEndSpecType := DSTJulianX + end + else + ADSTEndSpecType := DSTJulian; + if J >= Length (TZ) then + Exit; + Inc (J); + I := J; + while (J <= Length (TZ)) and (TZ [J] <> '/') do + Inc (J); + Val (Copy (TZ, I, J - I), ADSTEndDay, Err); + if (Err > 0) or (ADSTEndDay = 0) and (ADSTEndSpecType = DSTJulianX) + or (ADSTEndDay > 365) then + Exit; + end; + if (J <= Length (TZ)) and (TZ [J] = '/') then + begin + if J = Length (TZ) then + Exit; + Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTEndSec, Err); + if (Err > 0) or (ADSTEndSec > 86399) then + Exit + else + ADSTEndSec := ADSTEndSec * 3600; + end + else + (* Use the preset default *) + ADSTEndSec := DSTEndSec; + +(* Format complete, all checks successful => accept the parsed values. *) + if ADSTStartSpecType = DSTMonthWeekDay then + begin + DSTStartMonth := ADSTStartMonth; + DSTStartWeek := ADSTStartWeek; + end; + DSTStartDay := ADSTStartDay; + DSTStartSec := ADSTStartSec; + if ADSTStartSpecType = DSTMonthWeekDay then + begin + DSTEndMonth := ADSTEndMonth; + DSTEndWeek := ADSTEndWeek; + end; + DSTEndDay := ADSTEndDay; + DSTEndSec := ADSTEndSec; + DSTStartSpecType := ADSTStartSpecType; + DSTEndSpecType := ADSTEndSpecType; + end; + end + else + DSTOffset := -3600 + TZOffset; + end; + end; +end; + + +begin + InitTZ; +end. diff --git a/baseunits/animatedgifs/animatedgif.pas b/baseunits/animatedgifs/animatedgif.pas index 7864b4097..7969df351 100644 --- a/baseunits/animatedgifs/animatedgif.pas +++ b/baseunits/animatedgifs/animatedgif.pas @@ -1,1163 +1,1163 @@ -unit AnimatedGif; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, Graphics, FPImage, MemBitmap; - -type - TDisposeMode = (dmNone, dmKeep, dmErase, dmRestore); - TGifSubImage = record - Image: TMemBitmap; - Position: TPoint; - Delay: integer; - disposeMode: TDisposeMode; - TransparentColor: TMemPixel; - end; - TGifSubImageArray = array of TGifSubImage; - - TGifBackgroundMode = (gbmSimplePaint, gbmEraseBackground, gbmSaveBackgroundOnce, gbmUpdateBackgroundContinuously); - - { TAnimatedGif } - - TAnimatedGif = class(TGraphic) - private - FWidth,FHeight: integer; - FBackgroundColor: TColor; - - FPrevDate: TDateTime; - FPaused: boolean; - FTimeAccumulator: double; - FCurrentImage, FWantedImage: integer; - FPreviousDisposeMode : TDisposeMode; - - FBackgroundImage, FPreviousVirtualScreen, - FStretchedVirtualScreen, FInternalVirtualScreen, FRestoreImage: TMemBitmap; - FImageChanged: boolean; - - function GetCount: integer; - procedure Render(StretchWidth,StretchHeight: integer); - procedure UpdateSimple(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean = true); - procedure UpdateEraseBackground(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean = true); - procedure Init; - function GetBitmap: TBitmap; - function GetMemBitmap: TMemBitmap; - procedure SaveBackgroundOnce(Canvas: TCanvas; ARect: TRect); - procedure SetCurrentImage(Index: integer); - - protected - FImages: TGifSubImageArray; - procedure LoadImages(stream: TStream); - - {TGraphic} - procedure Draw(ACanvas: TCanvas; const Rect: TRect); override; - function GetEmpty: Boolean; override; - function GetHeight: Integer; override; - function GetTransparent: Boolean; override; - function GetWidth: Integer; override; - procedure SetHeight(Value: Integer); override; - procedure SetTransparent(Value: Boolean); override; - procedure SetWidth(Value: Integer); override; - - public - EraseColor: TColor; - BackgroundMode: TGifBackgroundMode; - - constructor Create(filename: string); - constructor Create(stream: TStream); - constructor Create; override; - function Duplicate: TAnimatedGif; - - {TGraphic} - procedure LoadFromStream(Stream: TStream); override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileExtensions: string; override; - - procedure Clear; override; - destructor Destroy; override; - procedure Pause; - procedure Resume; - - procedure Show(Canvas: TCanvas; ARect: TRect); overload; - procedure Update(Canvas: TCanvas; ARect: TRect); overload; - procedure Hide(Canvas: TCanvas; ARect: TRect); overload; - - property BackgroundColor : TColor read FBackgroundColor; - property Count: Integer read GetCount; - property Width: integer read FWidth; - property Height: integer read FHeight; - property Paused: Boolean read FPaused; - property Bitmap: TBitmap read GetBitmap; - property MemBitmap: TMemBitmap read GetMemBitmap; - property CurrentImage: integer read FCurrentImage write SetCurrentImage; - end; - - { TFPReaderGIF } - - TFPReaderGIF = class (TFPCustomImageReader) - protected - procedure InternalRead (Str:TStream; Img:TFPCustomImage); override; - function InternalCheck (Str:TStream) : boolean; override; - end; - -const - GifBackgroundModeStr : array[TGifBackgroundMode] of string = - ('gbmSimplePaint', 'gbmEraseBackground', 'gbmSaveBackgroundOnce', 'gbmUpdateBackgroundContinuously'); - -implementation - -Const AlphaMask = $FF000000; - -TYPE TGIFSignature=packed array[1..6] of char; - - TGIFScreenDescriptor=packed RECORD - width,height:word; - flags,background,map:byte; - END; - - TGIFImageDescriptor=packed RECORD - x,y,width,height:word; - flags:byte; - END; - - TGIFExtensionBlock=packed RECORD - functioncode:byte; - END; - - TGIFGraphicControlExtension=packed RECORD - flags:byte; - delaytime:word; - transcolor:byte; - END; - -{ TAnimatedGif } - -class function TAnimatedGif.GetFileExtensions: string; -begin - Result := 'gif'; -end; - -procedure TAnimatedGif.Render(StretchWidth,StretchHeight: integer); -var curDate: TDateTime; - previousImage, nextImage: integer; - -begin - if FInternalVirtualScreen = nil then - begin - FInternalVirtualScreen := TMemBitmap.Create(FWidth,FHeight); - if Count = 0 then FInternalVirtualScreen.Fill(BackgroundColor) else FInternalVirtualScreen.Fill(MemPixelTransparent); - FImageChanged := true; - end; - - if Count = 0 then exit; - - previousImage := FCurrentImage; - - curDate := Now; - if FWantedImage <> - 1 then - begin - nextImage := FWantedImage; - FTimeAccumulator:= 0; - FWantedImage := -1; - end else - if FCurrentImage = -1 then - begin - nextImage := 0; - FTimeAccumulator := 0; - FPreviousDisposeMode := dmNone; - end else - begin - if not FPaused then FTimeAccumulator += (curDate-FPrevDate)*24*60*60*1000; - nextImage := FCurrentImage; - while FTimeAccumulator> FImages[nextImage].Delay do - begin - FTimeAccumulator -= FImages[nextImage].Delay; - inc(nextImage); - if nextImage >= Count then nextImage := 0; - - if nextImage = previousImage then - begin - inc(nextImage); - if nextImage >= Count then nextImage := 0; - break; - end; - end; - end; - FPrevDate := curDate; - - while FCurrentImage<>nextImage do - begin - inc(FCurrentImage); - if FCurrentImage >= Count then - begin - FCurrentImage := 0; - FPreviousDisposeMode := dmErase; - end; - - case FPreviousDisposeMode of - dmErase: FInternalVirtualScreen.Fill(MemPixelTransparent); - dmRestore: if FRestoreImage <> nil then FInternalVirtualScreen.PutImage(0,0,FRestoreImage,dmSet); - end; - - with FImages[FCurrentImage] do - begin - If disposeMode = dmRestore then - begin - if FRestoreImage = nil then FRestoreImage := TMemBitmap.Create(FWidth,FHeight); - FRestoreImage.PutImage(0,0,FInternalVirtualScreen,dmSet); - end; - - if Image <> nil then - FInternalVirtualScreen.PutImage(Position.X,Position.Y,Image,dmSetExceptTransparent); - FPreviousDisposeMode := disposeMode; - end; - - FImageChanged := true; - previousImage := FCurrentImage; - FInternalVirtualScreen.InvalidateBitmap; - end; - - if FStretchedVirtualScreen <> nil then FStretchedVirtualScreen.FreeReference; - if (FInternalVirtualScreen.Width = StretchWidth) and (FInternalVirtualScreen.Height = StretchHeight) then - FStretchedVirtualScreen := FInternalVirtualScreen.NewReference else - FStretchedVirtualScreen := FInternalVirtualScreen.Resample(StretchWidth,StretchHeight); -end; - -procedure TAnimatedGif.UpdateSimple(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean = true); -begin - if FPreviousVirtualScreen <> nil then - begin - FPreviousVirtualScreen.FreeReference; - FPreviousVirtualScreen := nil; - end; - - Render(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); - if FImageChanged then - begin - FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - FImageChanged := false; - end else - if not DrawOnlyIfChanged then FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - - FPreviousVirtualScreen := FStretchedVirtualScreen.NewReference; -end; - -function TAnimatedGif.GetCount: integer; -begin - result := length(FImages); -end; - -constructor TAnimatedGif.Create(filename: string); -var Stream: TFileStream; -begin - inherited Create; - Init; - Stream := TFileStream.Create(filename,fmOpenRead); - LoadFromStream(Stream); - Stream.Free; -end; - -constructor TAnimatedGif.Create(stream: TStream); -begin - inherited Create; - Init; - LoadFromStream(stream); -end; - -constructor TAnimatedGif.Create; -begin - inherited Create; - Init; - LoadFromStream(nil); -end; - -function TAnimatedGif.Duplicate: TAnimatedGif; -var i: integer; -begin - result := TAnimatedGif.Create; - setlength(result.FImages, length(FImages)); - for i := 0 to high(FImages) do - begin - result.FImages[i] := FImages[i]; - FImages[i].Image.NewReference; - end; - result.FWidth := FWidth; - result.FHeight := FHeight; - result.FBackgroundColor := FBackgroundColor; -end; - -procedure TAnimatedGif.LoadFromStream(Stream: TStream); -begin - FCurrentImage := -1; - FWantedImage := -1; - FTimeAccumulator := 0; - - if FStretchedVirtualScreen <> nil then FStretchedVirtualScreen.FreeReference; - if FPreviousVirtualScreen <> nil then FPreviousVirtualScreen.FreeReference; - FInternalVirtualScreen.Free; - FRestoreImage.Free; - FBackgroundImage.Free; - - FInternalVirtualScreen := nil; - FStretchedVirtualScreen := nil; - FRestoreImage := nil; - FBackgroundImage := nil; - FPreviousVirtualScreen := nil; - - EraseColor := clBlack; - FPreviousDisposeMode := dmNone; - - FWidth := 0; - FHeight := 0; - - if Stream<>nil then LoadImages(Stream); -end; - -procedure TAnimatedGif.SaveToStream(Stream: TStream); -begin - //not implemented -end; - -{$HINTS OFF} -procedure TAnimatedGif.LoadImages(stream: TStream); - - PROCEDURE DumpData; - VAR count:byte; - BEGIN - REPEAT - stream.read(count,1); - stream.position := stream.position + count; - UNTIL (count=0) OR (stream.position>=stream.size); - END; - -type - TRGB=packed RECORD - r,g,b:byte; - END; - - TPalette= array of TMemPixel; - - function rgbToColor(rgb: TRGB): TMemPixel; - begin - result.red := rgb.r; - result.green := rgb.g; - result.blue := rgb.b; - result.alpha := 255; - end; - -const GIFScreenDescriptor_GlobalColorTableFlag = $80; - GIFImageDescriptor_LocalColorTableFlag = $80; - GIFImageDescriptor_InterlacedFlag = $40; - GIFGraphicControlExtension_TransparentFlag = $01; - -CONST ilstart:array[1..4] of longint=(0,4,2,1); - ilstep:array[1..4] of longint=(8,8,4,2); - -var NewImages: array of TGifSubImage; - NbImages: integer; - - GIFSignature:TGIFSignature; - GIFScreenDescriptor:TGIFScreenDescriptor; - GIFBlockID:char; - GIFImageDescriptor:TGIFImageDescriptor; - - globalPalette: TPalette; - localPalette: TPalette; - - transcolorIndex: integer; - delay: integer; - disposeMode: TDisposeMode; - - procedure LoadGlobalPalette; - var NbEntries,i: integer; - rgb: TRGB; - begin - NbEntries := 1 SHL (GIFScreenDescriptor.flags AND $07+1); - setlength(globalPalette, NbEntries); - FOR i:=0 TO NbEntries-1 DO - BEGIN - stream.read(rgb,3); - globalPalette[i]:=rgbToColor(rgb); - END; - end; - - procedure LoadLocalPalette; - var NbEntries,i: integer; - rgb: TRGB; - begin - NbEntries := 1 SHL (GIFImageDescriptor.flags AND $07+1); - setlength(localPalette, NbEntries); - FOR i:=0 TO NbEntries-1 DO - BEGIN - stream.read(rgb,3); - localPalette[i]:=rgbToColor(rgb); - END; - end; - - PROCEDURE decodeGIFLZW(image:TMemBitmap;const pal:TPalette;interlaced:boolean); - VAR xd,yd:longint; - CONST tablen=4095; - TYPE Pstr=^Tstr; - Tstr=RECORD - prefix:Pstr; - suffix:longint; - END; - Pstrtab=^Tstrtab; - Tstrtab=array[0..tablen] of Tstr; - - VAR strtab:Pstrtab; - oldcode,curcode,clearcode,endcode:longint; - codesize,codelen,codemask:longint; - stridx:longint; - bitbuf,bitsinbuf:longint; - bytbuf:array[0..255] of byte; - bytinbuf,bytbufidx:byte; - endofsrc:boolean; - xcnt,ycnt,ystep,pass:longint; - - PROCEDURE InitStringTable; - VAR i:longint; - BEGIN - new(strtab); - clearcode:=1 SHL codesize; - endcode:=clearcode+1; - stridx:=endcode+1; - codelen:=codesize+1; - codemask:=(1 SHL codelen)-1; - FOR i:=0 TO clearcode-1 DO - BEGIN - strtab^[i].prefix:=nil; - strtab^[i].suffix:=i; - END; - FOR i:=clearcode TO tablen DO - BEGIN - strtab^[i].prefix:=nil; - strtab^[i].suffix:=0; - END; - END; - - PROCEDURE ClearStringTable; - VAR i:longint; - BEGIN - clearcode:=1 SHL codesize; - endcode:=clearcode+1; - stridx:=endcode+1; - codelen:=codesize+1; - codemask:=(1 SHL codelen)-1; - FOR i:=clearcode TO tablen DO - BEGIN - strtab^[i].prefix:=nil; - strtab^[i].suffix:=0; - END; - END; - - PROCEDURE DoneStringTable; - BEGIN - dispose(strtab); - END; - - FUNCTION GetNextCode:longint; - BEGIN - WHILE (bitsinbufnil) THEN WriteStr(s^.prefix); - IF (ycnt>=yd) THEN - BEGIN - IF interlaced THEN - BEGIN - WHILE (ycnt>=yd) AND (pass<5) DO - BEGIN - inc(pass); - ycnt:=ilstart[pass]; - ystep:=ilstep[pass]; - END; - END; - END; - - colorIndex := s^.suffix; - if (colorIndex <> transcolorIndex) and (colorIndex >=0) and (colorIndex < length(pal)) then - image.setpixel(xcnt,ycnt,pal[colorIndex]); - - inc(xcnt); - IF (xcnt>=xd) THEN - BEGIN - xcnt:=0; - inc(ycnt,ystep); - - IF NOT interlaced THEN - IF (ycnt>=yd) THEN - BEGIN - inc(pass); - END; - - END; - END; - - FUNCTION firstchar(s:Pstr):byte; - BEGIN - WHILE (s^.prefix<>nil) DO s:=s^.prefix; - firstchar:=s^.suffix; - END; - - BEGIN -{DBG('lzw start');} - endofsrc:=FALSE; - xd:=image.width; - yd:=image.height; - xcnt:=0; - IF interlaced THEN - BEGIN - pass:=1; - ycnt:=ilstart[pass]; - ystep:=ilstep[pass]; - END - ELSE - BEGIN - pass:=4; - ycnt:=0; - ystep:=1; - END; - oldcode:=0; - bitbuf:=0; - bitsinbuf:=0; - bytinbuf:=0; - bytbufidx:=0; - codesize:=0; - stream.read(codesize,1); -{DBG(codesize);} - InitStringTable; - curcode:=getnextcode; -{DBG(curcode);} - WHILE (curcode<>endcode) AND (pass<5) AND NOT endofsrc{ AND NOT finished} DO - BEGIN -{DBG('-----'); -DBG(curcode); -DBGw(stridx);} - IF (curcode=clearcode) THEN - BEGIN - ClearStringTable; - REPEAT - curcode:=getnextcode; -{DBG('lzw clear');} - UNTIL (curcode<>clearcode); - IF (curcode=endcode) THEN break; - WriteStr(code2str(curcode)); - oldcode:=curcode; - END - ELSE - BEGIN - IF (curcodestridx) THEN break; - AddStr2Tab(Code2Str(oldcode),firstchar(Code2Str(oldcode))); - WriteStr(Code2Str(stridx-1)); - oldcode:=curcode; - END; - END; - curcode:=getnextcode; - END; - DoneStringTable; -{putimage(0,0,image);} -{DBG('lzw end'); -DBG(bytinbuf);} - IF NOT endofsrc THEN DumpData; -{DBG('lzw finished');} - END; - - procedure LoadImage; - var imgWidth,imgHeight: integer; - img: TMemBitmap; - Interlaced: boolean; - palette: TPalette; - BEGIN - stream.read(GIFImageDescriptor,sizeof(GIFImageDescriptor)); - IF (GIFImageDescriptor.flags AND GIFImageDescriptor_LocalColorTableFlag=GIFImageDescriptor_LocalColorTableFlag) THEN LoadLocalPalette else - localPalette := nil; - - if localPalette <> nil then palette := localPalette else palette := globalPalette; - imgWidth:=GIFImageDescriptor.width; - imgHeight:=GIFImageDescriptor.height; - - if length(NewImages) <= NbImages then setlength(NewImages, length(NewImages)*2+1); - img := TMemBitmap.Create(imgWidth,imgHeight); - img.Fill(MemPixelTransparent); - NewImages[NbImages].Image := img; - NewImages[NbImages].Position := point(GIFImageDescriptor.x,GIFImageDescriptor.y); - NewImages[NbImages].Delay:= Delay; - NewImages[NbImages].disposeMode:= disposeMode; - - if (transcolorIndex >= 0) and (transcolorIndex < length(palette)) then - NewImages[nbImages].TransparentColor:= palette[transcolorIndex] else - NewImages[nbImages].TransparentColor := MemPixelTransparent; - - inc(NbImages); - - Interlaced := GIFImageDescriptor.flags AND GIFImageDescriptor_InterlacedFlag=GIFImageDescriptor_InterlacedFlag; - DecodeGIFLZW(img,palette,Interlaced); - END; - - procedure ChangeImages; - var i: integer; - begin - Clear; - SetLength(FImages,NbImages); - for i:= 0 to Count-1 do - FImages[i] := NewImages[i]; - end; - - procedure ReadExtension; - var - GIFExtensionBlock:TGIFExtensionBlock; - GIFGraphicControlExtension:TGIFGraphicControlExtension; - mincount, count: byte; - - begin - stream.read(GIFExtensionBlock,sizeof(GIFExtensionBlock)); - CASE GIFExtensionBlock.functioncode OF - $F9:BEGIN - stream.read(count,1); - if count < sizeof(GIFGraphicControlExtension) then - mincount := 0 else - begin - mincount := sizeof(GIFGraphicControlExtension); - stream.read(GIFGraphicControlExtension,mincount); - - if GIFGraphicControlExtension.flags and GIFGraphicControlExtension_TransparentFlag = GIFGraphicControlExtension_TransparentFlag then - transcolorIndex:=GIFGraphicControlExtension.transcolor else - transcolorIndex := -1; - if GIFGraphicControlExtension.delaytime <> 0 then Delay := GIFGraphicControlExtension.delaytime*10; - disposeMode := TDisposeMode((GIFGraphicControlExtension.flags shr 2) and 7); - end; - stream.Position:= Stream.Position+count-mincount; - DumpData; - END; - ELSE - BEGIN - DumpData; - END; - END; - end; - -begin - NewImages := nil; - NbImages := 0; - transcolorIndex := -1; - Delay := 100; - FBackgroundColor:= clBlack; - FWidth := 0; - FHeight := 0; - disposeMode := dmErase; - - stream.Read(GIFSignature,sizeof(GIFSignature)); - IF (GIFSignature[1]='G') AND (GIFSignature[2]='I') AND (GIFSignature[3]='F') THEN - BEGIN - stream.read(GIFScreenDescriptor,sizeof(GIFScreenDescriptor)); - FWidth := GIFScreenDescriptor.width; - FHeight := GIFScreenDescriptor.Height; - IF (GIFScreenDescriptor.flags AND GIFScreenDescriptor_GlobalColorTableFlag=GIFScreenDescriptor_GlobalColorTableFlag) THEN - begin - LoadGlobalPalette; - if GIFScreenDescriptor.background < length(globalPalette) then - FBackgroundColor := MemPixelToColor(globalPalette[GIFScreenDescriptor.background]); - end; - REPEAT - stream.read(GIFBlockID,sizeof(GIFBlockID)); - CASE GIFBlockID OF - ';':; - ',': LoadImage; - '!': ReadExtension; - ELSE - begin - raise Exception.Create('TAnimatedGif: unexpected block type'); - break; - end; - END; - UNTIL (GIFBlockID=';') OR (stream.Position>=stream.size); - END else - raise Exception.Create('TAnimatedGif: invalid header'); - ChangeImages; -end; - -procedure TAnimatedGif.Draw(ACanvas: TCanvas; const Rect: TRect); -begin - if FBackgroundImage <> nil then FreeAndNil(FBackgroundImage); - SaveBackgroundOnce(ACanvas, Rect); - - if FPreviousVirtualScreen <> nil then - begin - FPreviousVirtualScreen.FreeReference; - FPreviousVirtualScreen := nil; - end; - - Render(Rect.Right-Rect.Left,Rect.Bottom-Rect.Top); - FStretchedVirtualScreen.Draw(ACanvas,Rect.Left,Rect.Top); - FImageChanged := false; - - FPreviousVirtualScreen := FStretchedVirtualScreen.Duplicate; -end; - -function TAnimatedGif.GetEmpty: Boolean; -begin - Result:= (length(FImages)=0); -end; - -function TAnimatedGif.GetHeight: Integer; -begin - Result:= FHeight; -end; - -function TAnimatedGif.GetTransparent: Boolean; -begin - Result:= true; -end; - -function TAnimatedGif.GetWidth: Integer; -begin - Result:= FWidth; -end; - -procedure TAnimatedGif.SetHeight(Value: Integer); -begin - //not implemented -end; - -procedure TAnimatedGif.SetTransparent(Value: Boolean); -begin - //not implemented -end; - -procedure TAnimatedGif.SetWidth(Value: Integer); -begin - //not implemented -end; - -procedure TAnimatedGif.SaveBackgroundOnce(Canvas: TCanvas; ARect: TRect); -begin - if (FBackgroundImage <> nil) and ((FBackgroundImage.Width <> ARect.Right-ARect.Left) or - (FBackgroundImage.Height <> ARect.Bottom-ARect.Top)) then FreeAndNil(FBackgroundImage); - - if (BackgroundMode in [gbmSaveBackgroundOnce, gbmUpdateBackgroundContinuously]) and (FBackgroundImage = nil) then - begin - FBackgroundImage := TMemBitmap.Create(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); - FBackgroundImage.GetImage(Canvas,ARect.Left,ARect.Top,EraseColor); - end; -end; - -procedure TAnimatedGif.SetCurrentImage(Index: integer); -begin - if (Index >= 0) and (Index < Length(FImages)) then FWantedImage := Index; -end; - -{$HINTS ON} - -procedure TAnimatedGif.Clear; -var i: integer; -begin - inherited Clear; - - for i := 0 to Count-1 do - FImages[i].Image.FreeReference; - FImages := nil; -end; - -destructor TAnimatedGif.Destroy; -begin - Clear; - - if FStretchedVirtualScreen <> nil then FStretchedVirtualScreen.FreeReference; - if FPreviousVirtualScreen <> nil then FPreviousVirtualScreen.FreeReference; - FInternalVirtualScreen.Free; - FRestoreImage.Free; - FBackgroundImage.Free; - inherited Destroy; -end; - -procedure TAnimatedGif.Pause; -begin - FPaused := true; -end; - -procedure TAnimatedGif.Resume; -begin - FPaused := false; -end; - -procedure TAnimatedGif.Show(Canvas: TCanvas; ARect: TRect); -begin - Canvas.StretchDraw(ARect,self); -end; - -procedure TAnimatedGif.Update(Canvas: TCanvas; ARect: TRect); -var - n: integer; - PChangePix,PNewPix, PBackground, PNewBackground: PLongWord; - oldpix,newpix,newbackpix: LongWord; - NewBackgroundImage: TMemBitmap; -begin - if (BackgroundMode = gbmUpdateBackgroundContinuously) and (FBackgroundImage = nil) then BackgroundMode := gbmSaveBackgroundOnce; - - SaveBackgroundOnce(Canvas, ARect); - - case BackgroundMode of - gbmSimplePaint: - begin - UpdateSimple(Canvas, ARect); - exit; - end; - gbmEraseBackground: - begin - UpdateEraseBackground(Canvas, ARect); - exit; - end; - gbmSaveBackgroundOnce, gbmUpdateBackgroundContinuously: - begin - if FPreviousVirtualScreen <> nil then - begin - if (FPreviousVirtualScreen.Width <> ARect.Right-ARect.Left) or - (FPreviousVirtualScreen.Height <> ARect.Bottom-ARect.Top) then - begin - FPreviousVirtualScreen.FreeReference; - FPreviousVirtualScreen := nil; - end - else - FPreviousVirtualScreen := FPreviousVirtualScreen.GetUnique; - end; - - Render(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); - - if FImageChanged then - begin - if BackgroundMode = gbmUpdateBackgroundContinuously then - begin - NewBackgroundImage := TMemBitmap.Create(FStretchedVirtualScreen.Width,FStretchedVirtualScreen.Height); - NewBackgroundImage.GetImage(Canvas,ARect.Left,ARect.Top,EraseColor); - - if FPreviousVirtualScreen=nil then - begin - FPreviousVirtualScreen := TMemBitmap.Create(FWidth,FHeight); - FPreviousVirtualScreen.Fill(MemPixelTransparent); - end; - - PChangePix := PLongWord(FPreviousVirtualScreen.ScanLine[0]); - PNewPix := PLongWord(FStretchedVirtualScreen.ScanLine[0]); - PBackground := PLongWord(FBackgroundImage.ScanLine[0]); - PNewBackground := PLongWord(NewBackgroundImage.ScanLine[0]); - for n := FStretchedVirtualScreen.NbPixels-1 downto 0 do - begin - oldpix := PChangePix^; - - if (oldpix and AlphaMask = AlphaMask) then //pixel opaque précédent - begin - newbackpix := PNewBackground^; - if (newbackpix <> oldpix) then //stocke nouveau fond - PBackground^ := newbackpix; - end; - - newpix := PNewPix^; - - if newpix and AlphaMask = AlphaMask then - begin - PChangePix^ := newpix; //pixel opaque - if oldpix and AlphaMask = 0 then //pixel transparent précédent - PBackground^ := PNewBackground^; - end - else if newpix and AlphaMask > 0 then - begin - PChangePix^ := PBackground^; - TMemBitmap.DrawPixel(PMemPixel(PChangePix),PMemPixel(@newpix)^); - end - else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent - -{ if newpix and AlphaMask > AlphaLimit then PChangePix^ := newpix or AlphaMask //pixel opaque - else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent} - - inc(PNewPix); - inc(PChangePix); - inc(PBackground); - inc(PNewBackground); - end; - NewBackgroundImage.Free; - FPreviousVirtualScreen.InvalidateBitmap; - FPreviousVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - FPreviousVirtualScreen.PutImage(0,0,FStretchedVirtualScreen,dmSet); - end else - begin - if FPreviousVirtualScreen =nil then - begin - FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - FPreviousVirtualScreen := FStretchedVirtualScreen.NewReference; - end else - begin - PChangePix := PLongWord(FPreviousVirtualScreen.ScanLine[0]); - PNewPix := PLongWord(FStretchedVirtualScreen.ScanLine[0]); - PBackground := PLongWord(FBackgroundImage.ScanLine[0]); - for n := FStretchedVirtualScreen.NbPixels-1 downto 0 do - begin - newpix := PNewPix^; - - if newpix and AlphaMask = AlphaMask then PChangePix^ := newpix //pixel opaque - else if newpix and AlphaMask > 0 then - begin - PChangePix^ := PBackground^; - TMemBitmap.DrawPixel(PMemPixel(PChangePix),PMemPixel(@newpix)^); - end - else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent - -{ if newpix and AlphaMask > AlphaLimit then PChangePix^ := newpix or AlphaMask //pixel opaque - else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent} - - inc(PNewPix); - inc(PChangePix); - inc(PBackground); - end; - FPreviousVirtualScreen.InvalidateBitmap; - FPreviousVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - FPreviousVirtualScreen.PutImage(0,0,FStretchedVirtualScreen,dmSet); - end; - end; - FImageChanged := false; - end; - end; - end; -end; - -procedure TAnimatedGif.Hide(Canvas: TCanvas; ARect: TRect); -var shape: TMemBitmap; p,pback: PMemPixel; - MemEraseColor : TMemPixel; n: integer; -begin - MemEraseColor := MemPixel(EraseColor); - if FPreviousVirtualScreen <> nil then - begin - if (FPreviousVirtualScreen.Width <> ARect.Right-ARect.Left) or - (FPreviousVirtualScreen.Height <> ARect.Bottom-ARect.Top) then - begin - FPreviousVirtualScreen.FreeReference; - FPreviousVirtualScreen := nil; - end - end; - - case BackgroundMode of - gbmEraseBackground, gbmSimplePaint: - begin - if FPreviousVirtualScreen <> nil then - begin - shape := FPreviousVirtualScreen.Duplicate; - p := shape.ScanLine[0]; - for n := shape.NbPixels-1 downto 0 do - begin - if p^.alpha <> 0 then p^ := MemEraseColor else - p^:= MemPixelTransparent; - inc(p); - end; - shape.Draw(Canvas,ARect.Left,ARect.Top); - shape.FreeReference; - end; - end; - gbmSaveBackgroundOnce,gbmUpdateBackgroundContinuously: - begin - if (FPreviousVirtualScreen <> nil) and (FBackgroundImage <> nil) then - begin - shape := FPreviousVirtualScreen.Duplicate; - p := shape.ScanLine[0]; - pback := FBackgroundImage.ScanLine[0]; - for n := shape.NbPixels-1 downto 0 do - begin - if p^.alpha <> 0 then p^ := pback^ else - p^:= MemPixelTransparent; - inc(p); - inc(pback); - end; - shape.Draw(Canvas,ARect.Left,ARect.Top); - shape.FreeReference; - end; - end; - end; -end; - -procedure TAnimatedGif.UpdateEraseBackground(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean); -var - n: integer; - PChangePix,PNewPix: PLongWord; - newpix: LongWord; - MemPixEraseColor : LongWord; -begin - if EraseColor = clNone then - begin - UpdateSimple(Canvas, ARect, DrawOnlyIfChanged); - exit; - end; - - if FPreviousVirtualScreen <> nil then - begin - if (FPreviousVirtualScreen.Width <> ARect.Right-ARect.Left) or - (FPreviousVirtualScreen.Height <> ARect.Bottom-ARect.Top) then - begin - FPreviousVirtualScreen.FreeReference; - FPreviousVirtualScreen := nil; - end - else - FPreviousVirtualScreen := FPreviousVirtualScreen.GetUnique; - end; - - Render(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); - if FImageChanged then - begin - PMemPixel(@MemPixEraseColor)^ := MemPixel(EraseColor); - if FPreviousVirtualScreen =nil then - begin - FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - FPreviousVirtualScreen := FStretchedVirtualScreen.NewReference; - end else - begin - PChangePix := PLongWord(FPreviousVirtualScreen.ScanLine[0]); - PNewPix := PLongWord(FStretchedVirtualScreen.ScanLine[0]); - for n := FStretchedVirtualScreen.NbPixels-1 downto 0 do - begin - newpix := PNewPix^; - - if newpix and AlphaMask = AlphaMask then PChangePix^ := newpix //pixel opaque - else if newpix and AlphaMask > 0 then - begin - PChangePix^ := MemPixEraseColor; - TMemBitmap.DrawPixel(PMemPixel(PChangePix),PMemPixel(@newpix)^); - end - else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := MemPixEraseColor; //efface précédent -{ if newpix and AlphaMask > AlphaLimit then PChangePix^ := newpix or AlphaMask //pixel opaque - else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := MemPixEraseColor; //efface précédent} - - inc(PNewPix); - inc(PChangePix); - end; - FPreviousVirtualScreen.InvalidateBitmap; - FPreviousVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); - FPreviousVirtualScreen.PutImage(0,0,FStretchedVirtualScreen,dmSet); - end; - - FImageChanged := false; - end; -end; - -procedure TAnimatedGif.Init; -begin - BackgroundMode := gbmSaveBackgroundOnce; -end; - -function TAnimatedGif.GetBitmap: TBitmap; -begin - Render(FWidth,FHeight); - result := FStretchedVirtualScreen.Bitmap; -end; - -function TAnimatedGif.GetMemBitmap: TMemBitmap; -begin - Render(FWidth,FHeight); - result := FStretchedVirtualScreen; -end; - -{ TFPReaderGIF } - -procedure TFPReaderGIF.InternalRead(Str: TStream; Img: TFPCustomImage); -var gif: TAnimatedGif; x,y: integer; Mem: TMemBitmap; -begin - gif := TAnimatedGif.Create(Str); - Mem := gif.MemBitmap; - if Img is TMemBitmap then - begin - TMemBitmap(Img).Assign(Mem); - end else - begin - Img.SetSize(gif.Width,gif.Height); - for y := 0 to gif.height-1 do - for x := 0 to gif.width-1 do - with Mem.GetPixel(x,y) do - Img.Colors[x,y] := FPColor(red*$101,green*$101,blue*$101,alpha*$101); - end; - gif.Free; -end; - -{$HINTS OFF} -function TFPReaderGIF.InternalCheck(Str: TStream): boolean; -var - GIFSignature:TGIFSignature; - savepos: int64; -begin - savepos := str.Position; - try - str.Read(GIFSignature,sizeof(GIFSignature)); - IF (GIFSignature[1]='G') AND (GIFSignature[2]='I') AND (GIFSignature[3]='F') THEN - BEGIN - result := true; - end else - result := false; - except on ex:exception do result := false; - end; - str.Position := savepos; -end; -{$HINTS ON} - -initialization - - //Free Pascal Image - ImageHandlers.RegisterImageReader ('Animated GIF', TAnimatedGif.GetFileExtensions, TFPReaderGIF); - - //Lazarus Picture - TPicture.RegisterFileFormat(TAnimatedGif.GetFileExtensions,'Animated GIF', TAnimatedGif); - -end. - +unit AnimatedGif; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Graphics, FPImage, MemBitmap; + +type + TDisposeMode = (dmNone, dmKeep, dmErase, dmRestore); + TGifSubImage = record + Image: TMemBitmap; + Position: TPoint; + Delay: integer; + disposeMode: TDisposeMode; + TransparentColor: TMemPixel; + end; + TGifSubImageArray = array of TGifSubImage; + + TGifBackgroundMode = (gbmSimplePaint, gbmEraseBackground, gbmSaveBackgroundOnce, gbmUpdateBackgroundContinuously); + + { TAnimatedGif } + + TAnimatedGif = class(TGraphic) + private + FWidth,FHeight: integer; + FBackgroundColor: TColor; + + FPrevDate: TDateTime; + FPaused: boolean; + FTimeAccumulator: double; + FCurrentImage, FWantedImage: integer; + FPreviousDisposeMode : TDisposeMode; + + FBackgroundImage, FPreviousVirtualScreen, + FStretchedVirtualScreen, FInternalVirtualScreen, FRestoreImage: TMemBitmap; + FImageChanged: boolean; + + function GetCount: integer; + procedure Render(StretchWidth,StretchHeight: integer); + procedure UpdateSimple(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean = true); + procedure UpdateEraseBackground(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean = true); + procedure Init; + function GetBitmap: TBitmap; + function GetMemBitmap: TMemBitmap; + procedure SaveBackgroundOnce(Canvas: TCanvas; ARect: TRect); + procedure SetCurrentImage(Index: integer); + + protected + FImages: TGifSubImageArray; + procedure LoadImages(stream: TStream); + + {TGraphic} + procedure Draw(ACanvas: TCanvas; const Rect: TRect); override; + function GetEmpty: Boolean; override; + function GetHeight: Integer; override; + function GetTransparent: Boolean; override; + function GetWidth: Integer; override; + procedure SetHeight(Value: Integer); override; + procedure SetTransparent(Value: Boolean); override; + procedure SetWidth(Value: Integer); override; + + public + EraseColor: TColor; + BackgroundMode: TGifBackgroundMode; + + constructor Create(filename: string); + constructor Create(stream: TStream); + constructor Create; override; + function Duplicate: TAnimatedGif; + + {TGraphic} + procedure LoadFromStream(Stream: TStream); override; + procedure SaveToStream(Stream: TStream); override; + class function GetFileExtensions: string; override; + + procedure Clear; override; + destructor Destroy; override; + procedure Pause; + procedure Resume; + + procedure Show(Canvas: TCanvas; ARect: TRect); overload; + procedure Update(Canvas: TCanvas; ARect: TRect); overload; + procedure Hide(Canvas: TCanvas; ARect: TRect); overload; + + property BackgroundColor : TColor read FBackgroundColor; + property Count: Integer read GetCount; + property Width: integer read FWidth; + property Height: integer read FHeight; + property Paused: Boolean read FPaused; + property Bitmap: TBitmap read GetBitmap; + property MemBitmap: TMemBitmap read GetMemBitmap; + property CurrentImage: integer read FCurrentImage write SetCurrentImage; + end; + + { TFPReaderGIF } + + TFPReaderGIF = class (TFPCustomImageReader) + protected + procedure InternalRead (Str:TStream; Img:TFPCustomImage); override; + function InternalCheck (Str:TStream) : boolean; override; + end; + +const + GifBackgroundModeStr : array[TGifBackgroundMode] of string = + ('gbmSimplePaint', 'gbmEraseBackground', 'gbmSaveBackgroundOnce', 'gbmUpdateBackgroundContinuously'); + +implementation + +Const AlphaMask = $FF000000; + +TYPE TGIFSignature=packed array[1..6] of char; + + TGIFScreenDescriptor=packed RECORD + width,height:word; + flags,background,map:byte; + END; + + TGIFImageDescriptor=packed RECORD + x,y,width,height:word; + flags:byte; + END; + + TGIFExtensionBlock=packed RECORD + functioncode:byte; + END; + + TGIFGraphicControlExtension=packed RECORD + flags:byte; + delaytime:word; + transcolor:byte; + END; + +{ TAnimatedGif } + +class function TAnimatedGif.GetFileExtensions: string; +begin + Result := 'gif'; +end; + +procedure TAnimatedGif.Render(StretchWidth,StretchHeight: integer); +var curDate: TDateTime; + previousImage, nextImage: integer; + +begin + if FInternalVirtualScreen = nil then + begin + FInternalVirtualScreen := TMemBitmap.Create(FWidth,FHeight); + if Count = 0 then FInternalVirtualScreen.Fill(BackgroundColor) else FInternalVirtualScreen.Fill(MemPixelTransparent); + FImageChanged := true; + end; + + if Count = 0 then exit; + + previousImage := FCurrentImage; + + curDate := Now; + if FWantedImage <> - 1 then + begin + nextImage := FWantedImage; + FTimeAccumulator:= 0; + FWantedImage := -1; + end else + if FCurrentImage = -1 then + begin + nextImage := 0; + FTimeAccumulator := 0; + FPreviousDisposeMode := dmNone; + end else + begin + if not FPaused then FTimeAccumulator += (curDate-FPrevDate)*24*60*60*1000; + nextImage := FCurrentImage; + while FTimeAccumulator> FImages[nextImage].Delay do + begin + FTimeAccumulator -= FImages[nextImage].Delay; + inc(nextImage); + if nextImage >= Count then nextImage := 0; + + if nextImage = previousImage then + begin + inc(nextImage); + if nextImage >= Count then nextImage := 0; + break; + end; + end; + end; + FPrevDate := curDate; + + while FCurrentImage<>nextImage do + begin + inc(FCurrentImage); + if FCurrentImage >= Count then + begin + FCurrentImage := 0; + FPreviousDisposeMode := dmErase; + end; + + case FPreviousDisposeMode of + dmErase: FInternalVirtualScreen.Fill(MemPixelTransparent); + dmRestore: if FRestoreImage <> nil then FInternalVirtualScreen.PutImage(0,0,FRestoreImage,dmSet); + end; + + with FImages[FCurrentImage] do + begin + If disposeMode = dmRestore then + begin + if FRestoreImage = nil then FRestoreImage := TMemBitmap.Create(FWidth,FHeight); + FRestoreImage.PutImage(0,0,FInternalVirtualScreen,dmSet); + end; + + if Image <> nil then + FInternalVirtualScreen.PutImage(Position.X,Position.Y,Image,dmSetExceptTransparent); + FPreviousDisposeMode := disposeMode; + end; + + FImageChanged := true; + previousImage := FCurrentImage; + FInternalVirtualScreen.InvalidateBitmap; + end; + + if FStretchedVirtualScreen <> nil then FStretchedVirtualScreen.FreeReference; + if (FInternalVirtualScreen.Width = StretchWidth) and (FInternalVirtualScreen.Height = StretchHeight) then + FStretchedVirtualScreen := FInternalVirtualScreen.NewReference else + FStretchedVirtualScreen := FInternalVirtualScreen.Resample(StretchWidth,StretchHeight); +end; + +procedure TAnimatedGif.UpdateSimple(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean = true); +begin + if FPreviousVirtualScreen <> nil then + begin + FPreviousVirtualScreen.FreeReference; + FPreviousVirtualScreen := nil; + end; + + Render(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); + if FImageChanged then + begin + FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + FImageChanged := false; + end else + if not DrawOnlyIfChanged then FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + + FPreviousVirtualScreen := FStretchedVirtualScreen.NewReference; +end; + +function TAnimatedGif.GetCount: integer; +begin + result := length(FImages); +end; + +constructor TAnimatedGif.Create(filename: string); +var Stream: TFileStream; +begin + inherited Create; + Init; + Stream := TFileStream.Create(filename,fmOpenRead); + LoadFromStream(Stream); + Stream.Free; +end; + +constructor TAnimatedGif.Create(stream: TStream); +begin + inherited Create; + Init; + LoadFromStream(stream); +end; + +constructor TAnimatedGif.Create; +begin + inherited Create; + Init; + LoadFromStream(nil); +end; + +function TAnimatedGif.Duplicate: TAnimatedGif; +var i: integer; +begin + result := TAnimatedGif.Create; + setlength(result.FImages, length(FImages)); + for i := 0 to high(FImages) do + begin + result.FImages[i] := FImages[i]; + FImages[i].Image.NewReference; + end; + result.FWidth := FWidth; + result.FHeight := FHeight; + result.FBackgroundColor := FBackgroundColor; +end; + +procedure TAnimatedGif.LoadFromStream(Stream: TStream); +begin + FCurrentImage := -1; + FWantedImage := -1; + FTimeAccumulator := 0; + + if FStretchedVirtualScreen <> nil then FStretchedVirtualScreen.FreeReference; + if FPreviousVirtualScreen <> nil then FPreviousVirtualScreen.FreeReference; + FInternalVirtualScreen.Free; + FRestoreImage.Free; + FBackgroundImage.Free; + + FInternalVirtualScreen := nil; + FStretchedVirtualScreen := nil; + FRestoreImage := nil; + FBackgroundImage := nil; + FPreviousVirtualScreen := nil; + + EraseColor := clBlack; + FPreviousDisposeMode := dmNone; + + FWidth := 0; + FHeight := 0; + + if Stream<>nil then LoadImages(Stream); +end; + +procedure TAnimatedGif.SaveToStream(Stream: TStream); +begin + //not implemented +end; + +{$HINTS OFF} +procedure TAnimatedGif.LoadImages(stream: TStream); + + PROCEDURE DumpData; + VAR count:byte; + BEGIN + REPEAT + stream.read(count,1); + stream.position := stream.position + count; + UNTIL (count=0) OR (stream.position>=stream.size); + END; + +type + TRGB=packed RECORD + r,g,b:byte; + END; + + TPalette= array of TMemPixel; + + function rgbToColor(rgb: TRGB): TMemPixel; + begin + result.red := rgb.r; + result.green := rgb.g; + result.blue := rgb.b; + result.alpha := 255; + end; + +const GIFScreenDescriptor_GlobalColorTableFlag = $80; + GIFImageDescriptor_LocalColorTableFlag = $80; + GIFImageDescriptor_InterlacedFlag = $40; + GIFGraphicControlExtension_TransparentFlag = $01; + +CONST ilstart:array[1..4] of longint=(0,4,2,1); + ilstep:array[1..4] of longint=(8,8,4,2); + +var NewImages: array of TGifSubImage; + NbImages: integer; + + GIFSignature:TGIFSignature; + GIFScreenDescriptor:TGIFScreenDescriptor; + GIFBlockID:char; + GIFImageDescriptor:TGIFImageDescriptor; + + globalPalette: TPalette; + localPalette: TPalette; + + transcolorIndex: integer; + delay: integer; + disposeMode: TDisposeMode; + + procedure LoadGlobalPalette; + var NbEntries,i: integer; + rgb: TRGB; + begin + NbEntries := 1 SHL (GIFScreenDescriptor.flags AND $07+1); + setlength(globalPalette, NbEntries); + FOR i:=0 TO NbEntries-1 DO + BEGIN + stream.read(rgb,3); + globalPalette[i]:=rgbToColor(rgb); + END; + end; + + procedure LoadLocalPalette; + var NbEntries,i: integer; + rgb: TRGB; + begin + NbEntries := 1 SHL (GIFImageDescriptor.flags AND $07+1); + setlength(localPalette, NbEntries); + FOR i:=0 TO NbEntries-1 DO + BEGIN + stream.read(rgb,3); + localPalette[i]:=rgbToColor(rgb); + END; + end; + + PROCEDURE decodeGIFLZW(image:TMemBitmap;const pal:TPalette;interlaced:boolean); + VAR xd,yd:longint; + CONST tablen=4095; + TYPE Pstr=^Tstr; + Tstr=RECORD + prefix:Pstr; + suffix:longint; + END; + Pstrtab=^Tstrtab; + Tstrtab=array[0..tablen] of Tstr; + + VAR strtab:Pstrtab; + oldcode,curcode,clearcode,endcode:longint; + codesize,codelen,codemask:longint; + stridx:longint; + bitbuf,bitsinbuf:longint; + bytbuf:array[0..255] of byte; + bytinbuf,bytbufidx:byte; + endofsrc:boolean; + xcnt,ycnt,ystep,pass:longint; + + PROCEDURE InitStringTable; + VAR i:longint; + BEGIN + new(strtab); + clearcode:=1 SHL codesize; + endcode:=clearcode+1; + stridx:=endcode+1; + codelen:=codesize+1; + codemask:=(1 SHL codelen)-1; + FOR i:=0 TO clearcode-1 DO + BEGIN + strtab^[i].prefix:=nil; + strtab^[i].suffix:=i; + END; + FOR i:=clearcode TO tablen DO + BEGIN + strtab^[i].prefix:=nil; + strtab^[i].suffix:=0; + END; + END; + + PROCEDURE ClearStringTable; + VAR i:longint; + BEGIN + clearcode:=1 SHL codesize; + endcode:=clearcode+1; + stridx:=endcode+1; + codelen:=codesize+1; + codemask:=(1 SHL codelen)-1; + FOR i:=clearcode TO tablen DO + BEGIN + strtab^[i].prefix:=nil; + strtab^[i].suffix:=0; + END; + END; + + PROCEDURE DoneStringTable; + BEGIN + dispose(strtab); + END; + + FUNCTION GetNextCode:longint; + BEGIN + WHILE (bitsinbufnil) THEN WriteStr(s^.prefix); + IF (ycnt>=yd) THEN + BEGIN + IF interlaced THEN + BEGIN + WHILE (ycnt>=yd) AND (pass<5) DO + BEGIN + inc(pass); + ycnt:=ilstart[pass]; + ystep:=ilstep[pass]; + END; + END; + END; + + colorIndex := s^.suffix; + if (colorIndex <> transcolorIndex) and (colorIndex >=0) and (colorIndex < length(pal)) then + image.setpixel(xcnt,ycnt,pal[colorIndex]); + + inc(xcnt); + IF (xcnt>=xd) THEN + BEGIN + xcnt:=0; + inc(ycnt,ystep); + + IF NOT interlaced THEN + IF (ycnt>=yd) THEN + BEGIN + inc(pass); + END; + + END; + END; + + FUNCTION firstchar(s:Pstr):byte; + BEGIN + WHILE (s^.prefix<>nil) DO s:=s^.prefix; + firstchar:=s^.suffix; + END; + + BEGIN +{DBG('lzw start');} + endofsrc:=FALSE; + xd:=image.width; + yd:=image.height; + xcnt:=0; + IF interlaced THEN + BEGIN + pass:=1; + ycnt:=ilstart[pass]; + ystep:=ilstep[pass]; + END + ELSE + BEGIN + pass:=4; + ycnt:=0; + ystep:=1; + END; + oldcode:=0; + bitbuf:=0; + bitsinbuf:=0; + bytinbuf:=0; + bytbufidx:=0; + codesize:=0; + stream.read(codesize,1); +{DBG(codesize);} + InitStringTable; + curcode:=getnextcode; +{DBG(curcode);} + WHILE (curcode<>endcode) AND (pass<5) AND NOT endofsrc{ AND NOT finished} DO + BEGIN +{DBG('-----'); +DBG(curcode); +DBGw(stridx);} + IF (curcode=clearcode) THEN + BEGIN + ClearStringTable; + REPEAT + curcode:=getnextcode; +{DBG('lzw clear');} + UNTIL (curcode<>clearcode); + IF (curcode=endcode) THEN break; + WriteStr(code2str(curcode)); + oldcode:=curcode; + END + ELSE + BEGIN + IF (curcodestridx) THEN break; + AddStr2Tab(Code2Str(oldcode),firstchar(Code2Str(oldcode))); + WriteStr(Code2Str(stridx-1)); + oldcode:=curcode; + END; + END; + curcode:=getnextcode; + END; + DoneStringTable; +{putimage(0,0,image);} +{DBG('lzw end'); +DBG(bytinbuf);} + IF NOT endofsrc THEN DumpData; +{DBG('lzw finished');} + END; + + procedure LoadImage; + var imgWidth,imgHeight: integer; + img: TMemBitmap; + Interlaced: boolean; + palette: TPalette; + BEGIN + stream.read(GIFImageDescriptor,sizeof(GIFImageDescriptor)); + IF (GIFImageDescriptor.flags AND GIFImageDescriptor_LocalColorTableFlag=GIFImageDescriptor_LocalColorTableFlag) THEN LoadLocalPalette else + localPalette := nil; + + if localPalette <> nil then palette := localPalette else palette := globalPalette; + imgWidth:=GIFImageDescriptor.width; + imgHeight:=GIFImageDescriptor.height; + + if length(NewImages) <= NbImages then setlength(NewImages, length(NewImages)*2+1); + img := TMemBitmap.Create(imgWidth,imgHeight); + img.Fill(MemPixelTransparent); + NewImages[NbImages].Image := img; + NewImages[NbImages].Position := point(GIFImageDescriptor.x,GIFImageDescriptor.y); + NewImages[NbImages].Delay:= Delay; + NewImages[NbImages].disposeMode:= disposeMode; + + if (transcolorIndex >= 0) and (transcolorIndex < length(palette)) then + NewImages[nbImages].TransparentColor:= palette[transcolorIndex] else + NewImages[nbImages].TransparentColor := MemPixelTransparent; + + inc(NbImages); + + Interlaced := GIFImageDescriptor.flags AND GIFImageDescriptor_InterlacedFlag=GIFImageDescriptor_InterlacedFlag; + DecodeGIFLZW(img,palette,Interlaced); + END; + + procedure ChangeImages; + var i: integer; + begin + Clear; + SetLength(FImages,NbImages); + for i:= 0 to Count-1 do + FImages[i] := NewImages[i]; + end; + + procedure ReadExtension; + var + GIFExtensionBlock:TGIFExtensionBlock; + GIFGraphicControlExtension:TGIFGraphicControlExtension; + mincount, count: byte; + + begin + stream.read(GIFExtensionBlock,sizeof(GIFExtensionBlock)); + CASE GIFExtensionBlock.functioncode OF + $F9:BEGIN + stream.read(count,1); + if count < sizeof(GIFGraphicControlExtension) then + mincount := 0 else + begin + mincount := sizeof(GIFGraphicControlExtension); + stream.read(GIFGraphicControlExtension,mincount); + + if GIFGraphicControlExtension.flags and GIFGraphicControlExtension_TransparentFlag = GIFGraphicControlExtension_TransparentFlag then + transcolorIndex:=GIFGraphicControlExtension.transcolor else + transcolorIndex := -1; + if GIFGraphicControlExtension.delaytime <> 0 then Delay := GIFGraphicControlExtension.delaytime*10; + disposeMode := TDisposeMode((GIFGraphicControlExtension.flags shr 2) and 7); + end; + stream.Position:= Stream.Position+count-mincount; + DumpData; + END; + ELSE + BEGIN + DumpData; + END; + END; + end; + +begin + NewImages := nil; + NbImages := 0; + transcolorIndex := -1; + Delay := 100; + FBackgroundColor:= clBlack; + FWidth := 0; + FHeight := 0; + disposeMode := dmErase; + + stream.Read(GIFSignature,sizeof(GIFSignature)); + IF (GIFSignature[1]='G') AND (GIFSignature[2]='I') AND (GIFSignature[3]='F') THEN + BEGIN + stream.read(GIFScreenDescriptor,sizeof(GIFScreenDescriptor)); + FWidth := GIFScreenDescriptor.width; + FHeight := GIFScreenDescriptor.Height; + IF (GIFScreenDescriptor.flags AND GIFScreenDescriptor_GlobalColorTableFlag=GIFScreenDescriptor_GlobalColorTableFlag) THEN + begin + LoadGlobalPalette; + if GIFScreenDescriptor.background < length(globalPalette) then + FBackgroundColor := MemPixelToColor(globalPalette[GIFScreenDescriptor.background]); + end; + REPEAT + stream.read(GIFBlockID,sizeof(GIFBlockID)); + CASE GIFBlockID OF + ';':; + ',': LoadImage; + '!': ReadExtension; + ELSE + begin + raise Exception.Create('TAnimatedGif: unexpected block type'); + break; + end; + END; + UNTIL (GIFBlockID=';') OR (stream.Position>=stream.size); + END else + raise Exception.Create('TAnimatedGif: invalid header'); + ChangeImages; +end; + +procedure TAnimatedGif.Draw(ACanvas: TCanvas; const Rect: TRect); +begin + if FBackgroundImage <> nil then FreeAndNil(FBackgroundImage); + SaveBackgroundOnce(ACanvas, Rect); + + if FPreviousVirtualScreen <> nil then + begin + FPreviousVirtualScreen.FreeReference; + FPreviousVirtualScreen := nil; + end; + + Render(Rect.Right-Rect.Left,Rect.Bottom-Rect.Top); + FStretchedVirtualScreen.Draw(ACanvas,Rect.Left,Rect.Top); + FImageChanged := false; + + FPreviousVirtualScreen := FStretchedVirtualScreen.Duplicate; +end; + +function TAnimatedGif.GetEmpty: Boolean; +begin + Result:= (length(FImages)=0); +end; + +function TAnimatedGif.GetHeight: Integer; +begin + Result:= FHeight; +end; + +function TAnimatedGif.GetTransparent: Boolean; +begin + Result:= true; +end; + +function TAnimatedGif.GetWidth: Integer; +begin + Result:= FWidth; +end; + +procedure TAnimatedGif.SetHeight(Value: Integer); +begin + //not implemented +end; + +procedure TAnimatedGif.SetTransparent(Value: Boolean); +begin + //not implemented +end; + +procedure TAnimatedGif.SetWidth(Value: Integer); +begin + //not implemented +end; + +procedure TAnimatedGif.SaveBackgroundOnce(Canvas: TCanvas; ARect: TRect); +begin + if (FBackgroundImage <> nil) and ((FBackgroundImage.Width <> ARect.Right-ARect.Left) or + (FBackgroundImage.Height <> ARect.Bottom-ARect.Top)) then FreeAndNil(FBackgroundImage); + + if (BackgroundMode in [gbmSaveBackgroundOnce, gbmUpdateBackgroundContinuously]) and (FBackgroundImage = nil) then + begin + FBackgroundImage := TMemBitmap.Create(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); + FBackgroundImage.GetImage(Canvas,ARect.Left,ARect.Top,EraseColor); + end; +end; + +procedure TAnimatedGif.SetCurrentImage(Index: integer); +begin + if (Index >= 0) and (Index < Length(FImages)) then FWantedImage := Index; +end; + +{$HINTS ON} + +procedure TAnimatedGif.Clear; +var i: integer; +begin + inherited Clear; + + for i := 0 to Count-1 do + FImages[i].Image.FreeReference; + FImages := nil; +end; + +destructor TAnimatedGif.Destroy; +begin + Clear; + + if FStretchedVirtualScreen <> nil then FStretchedVirtualScreen.FreeReference; + if FPreviousVirtualScreen <> nil then FPreviousVirtualScreen.FreeReference; + FInternalVirtualScreen.Free; + FRestoreImage.Free; + FBackgroundImage.Free; + inherited Destroy; +end; + +procedure TAnimatedGif.Pause; +begin + FPaused := true; +end; + +procedure TAnimatedGif.Resume; +begin + FPaused := false; +end; + +procedure TAnimatedGif.Show(Canvas: TCanvas; ARect: TRect); +begin + Canvas.StretchDraw(ARect,self); +end; + +procedure TAnimatedGif.Update(Canvas: TCanvas; ARect: TRect); +var + n: integer; + PChangePix,PNewPix, PBackground, PNewBackground: PLongWord; + oldpix,newpix,newbackpix: LongWord; + NewBackgroundImage: TMemBitmap; +begin + if (BackgroundMode = gbmUpdateBackgroundContinuously) and (FBackgroundImage = nil) then BackgroundMode := gbmSaveBackgroundOnce; + + SaveBackgroundOnce(Canvas, ARect); + + case BackgroundMode of + gbmSimplePaint: + begin + UpdateSimple(Canvas, ARect); + exit; + end; + gbmEraseBackground: + begin + UpdateEraseBackground(Canvas, ARect); + exit; + end; + gbmSaveBackgroundOnce, gbmUpdateBackgroundContinuously: + begin + if FPreviousVirtualScreen <> nil then + begin + if (FPreviousVirtualScreen.Width <> ARect.Right-ARect.Left) or + (FPreviousVirtualScreen.Height <> ARect.Bottom-ARect.Top) then + begin + FPreviousVirtualScreen.FreeReference; + FPreviousVirtualScreen := nil; + end + else + FPreviousVirtualScreen := FPreviousVirtualScreen.GetUnique; + end; + + Render(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); + + if FImageChanged then + begin + if BackgroundMode = gbmUpdateBackgroundContinuously then + begin + NewBackgroundImage := TMemBitmap.Create(FStretchedVirtualScreen.Width,FStretchedVirtualScreen.Height); + NewBackgroundImage.GetImage(Canvas,ARect.Left,ARect.Top,EraseColor); + + if FPreviousVirtualScreen=nil then + begin + FPreviousVirtualScreen := TMemBitmap.Create(FWidth,FHeight); + FPreviousVirtualScreen.Fill(MemPixelTransparent); + end; + + PChangePix := PLongWord(FPreviousVirtualScreen.ScanLine[0]); + PNewPix := PLongWord(FStretchedVirtualScreen.ScanLine[0]); + PBackground := PLongWord(FBackgroundImage.ScanLine[0]); + PNewBackground := PLongWord(NewBackgroundImage.ScanLine[0]); + for n := FStretchedVirtualScreen.NbPixels-1 downto 0 do + begin + oldpix := PChangePix^; + + if (oldpix and AlphaMask = AlphaMask) then //pixel opaque précédent + begin + newbackpix := PNewBackground^; + if (newbackpix <> oldpix) then //stocke nouveau fond + PBackground^ := newbackpix; + end; + + newpix := PNewPix^; + + if newpix and AlphaMask = AlphaMask then + begin + PChangePix^ := newpix; //pixel opaque + if oldpix and AlphaMask = 0 then //pixel transparent précédent + PBackground^ := PNewBackground^; + end + else if newpix and AlphaMask > 0 then + begin + PChangePix^ := PBackground^; + TMemBitmap.DrawPixel(PMemPixel(PChangePix),PMemPixel(@newpix)^); + end + else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent + +{ if newpix and AlphaMask > AlphaLimit then PChangePix^ := newpix or AlphaMask //pixel opaque + else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent} + + inc(PNewPix); + inc(PChangePix); + inc(PBackground); + inc(PNewBackground); + end; + NewBackgroundImage.Free; + FPreviousVirtualScreen.InvalidateBitmap; + FPreviousVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + FPreviousVirtualScreen.PutImage(0,0,FStretchedVirtualScreen,dmSet); + end else + begin + if FPreviousVirtualScreen =nil then + begin + FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + FPreviousVirtualScreen := FStretchedVirtualScreen.NewReference; + end else + begin + PChangePix := PLongWord(FPreviousVirtualScreen.ScanLine[0]); + PNewPix := PLongWord(FStretchedVirtualScreen.ScanLine[0]); + PBackground := PLongWord(FBackgroundImage.ScanLine[0]); + for n := FStretchedVirtualScreen.NbPixels-1 downto 0 do + begin + newpix := PNewPix^; + + if newpix and AlphaMask = AlphaMask then PChangePix^ := newpix //pixel opaque + else if newpix and AlphaMask > 0 then + begin + PChangePix^ := PBackground^; + TMemBitmap.DrawPixel(PMemPixel(PChangePix),PMemPixel(@newpix)^); + end + else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent + +{ if newpix and AlphaMask > AlphaLimit then PChangePix^ := newpix or AlphaMask //pixel opaque + else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := PBackground^; //efface précédent} + + inc(PNewPix); + inc(PChangePix); + inc(PBackground); + end; + FPreviousVirtualScreen.InvalidateBitmap; + FPreviousVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + FPreviousVirtualScreen.PutImage(0,0,FStretchedVirtualScreen,dmSet); + end; + end; + FImageChanged := false; + end; + end; + end; +end; + +procedure TAnimatedGif.Hide(Canvas: TCanvas; ARect: TRect); +var shape: TMemBitmap; p,pback: PMemPixel; + MemEraseColor : TMemPixel; n: integer; +begin + MemEraseColor := MemPixel(EraseColor); + if FPreviousVirtualScreen <> nil then + begin + if (FPreviousVirtualScreen.Width <> ARect.Right-ARect.Left) or + (FPreviousVirtualScreen.Height <> ARect.Bottom-ARect.Top) then + begin + FPreviousVirtualScreen.FreeReference; + FPreviousVirtualScreen := nil; + end + end; + + case BackgroundMode of + gbmEraseBackground, gbmSimplePaint: + begin + if FPreviousVirtualScreen <> nil then + begin + shape := FPreviousVirtualScreen.Duplicate; + p := shape.ScanLine[0]; + for n := shape.NbPixels-1 downto 0 do + begin + if p^.alpha <> 0 then p^ := MemEraseColor else + p^:= MemPixelTransparent; + inc(p); + end; + shape.Draw(Canvas,ARect.Left,ARect.Top); + shape.FreeReference; + end; + end; + gbmSaveBackgroundOnce,gbmUpdateBackgroundContinuously: + begin + if (FPreviousVirtualScreen <> nil) and (FBackgroundImage <> nil) then + begin + shape := FPreviousVirtualScreen.Duplicate; + p := shape.ScanLine[0]; + pback := FBackgroundImage.ScanLine[0]; + for n := shape.NbPixels-1 downto 0 do + begin + if p^.alpha <> 0 then p^ := pback^ else + p^:= MemPixelTransparent; + inc(p); + inc(pback); + end; + shape.Draw(Canvas,ARect.Left,ARect.Top); + shape.FreeReference; + end; + end; + end; +end; + +procedure TAnimatedGif.UpdateEraseBackground(Canvas: TCanvas; ARect: TRect; DrawOnlyIfChanged: Boolean); +var + n: integer; + PChangePix,PNewPix: PLongWord; + newpix: LongWord; + MemPixEraseColor : LongWord; +begin + if EraseColor = clNone then + begin + UpdateSimple(Canvas, ARect, DrawOnlyIfChanged); + exit; + end; + + if FPreviousVirtualScreen <> nil then + begin + if (FPreviousVirtualScreen.Width <> ARect.Right-ARect.Left) or + (FPreviousVirtualScreen.Height <> ARect.Bottom-ARect.Top) then + begin + FPreviousVirtualScreen.FreeReference; + FPreviousVirtualScreen := nil; + end + else + FPreviousVirtualScreen := FPreviousVirtualScreen.GetUnique; + end; + + Render(ARect.Right-ARect.Left,ARect.Bottom-ARect.Top); + if FImageChanged then + begin + PMemPixel(@MemPixEraseColor)^ := MemPixel(EraseColor); + if FPreviousVirtualScreen =nil then + begin + FStretchedVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + FPreviousVirtualScreen := FStretchedVirtualScreen.NewReference; + end else + begin + PChangePix := PLongWord(FPreviousVirtualScreen.ScanLine[0]); + PNewPix := PLongWord(FStretchedVirtualScreen.ScanLine[0]); + for n := FStretchedVirtualScreen.NbPixels-1 downto 0 do + begin + newpix := PNewPix^; + + if newpix and AlphaMask = AlphaMask then PChangePix^ := newpix //pixel opaque + else if newpix and AlphaMask > 0 then + begin + PChangePix^ := MemPixEraseColor; + TMemBitmap.DrawPixel(PMemPixel(PChangePix),PMemPixel(@newpix)^); + end + else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := MemPixEraseColor; //efface précédent +{ if newpix and AlphaMask > AlphaLimit then PChangePix^ := newpix or AlphaMask //pixel opaque + else if PChangePix^ and AlphaMask <> 0 then PChangePix^ := MemPixEraseColor; //efface précédent} + + inc(PNewPix); + inc(PChangePix); + end; + FPreviousVirtualScreen.InvalidateBitmap; + FPreviousVirtualScreen.Draw(Canvas,ARect.Left,ARect.Top); + FPreviousVirtualScreen.PutImage(0,0,FStretchedVirtualScreen,dmSet); + end; + + FImageChanged := false; + end; +end; + +procedure TAnimatedGif.Init; +begin + BackgroundMode := gbmSaveBackgroundOnce; +end; + +function TAnimatedGif.GetBitmap: TBitmap; +begin + Render(FWidth,FHeight); + result := FStretchedVirtualScreen.Bitmap; +end; + +function TAnimatedGif.GetMemBitmap: TMemBitmap; +begin + Render(FWidth,FHeight); + result := FStretchedVirtualScreen; +end; + +{ TFPReaderGIF } + +procedure TFPReaderGIF.InternalRead(Str: TStream; Img: TFPCustomImage); +var gif: TAnimatedGif; x,y: integer; Mem: TMemBitmap; +begin + gif := TAnimatedGif.Create(Str); + Mem := gif.MemBitmap; + if Img is TMemBitmap then + begin + TMemBitmap(Img).Assign(Mem); + end else + begin + Img.SetSize(gif.Width,gif.Height); + for y := 0 to gif.height-1 do + for x := 0 to gif.width-1 do + with Mem.GetPixel(x,y) do + Img.Colors[x,y] := FPColor(red*$101,green*$101,blue*$101,alpha*$101); + end; + gif.Free; +end; + +{$HINTS OFF} +function TFPReaderGIF.InternalCheck(Str: TStream): boolean; +var + GIFSignature:TGIFSignature; + savepos: int64; +begin + savepos := str.Position; + try + str.Read(GIFSignature,sizeof(GIFSignature)); + IF (GIFSignature[1]='G') AND (GIFSignature[2]='I') AND (GIFSignature[3]='F') THEN + BEGIN + result := true; + end else + result := false; + except on ex:exception do result := false; + end; + str.Position := savepos; +end; +{$HINTS ON} + +initialization + + //Free Pascal Image + ImageHandlers.RegisterImageReader ('Animated GIF', TAnimatedGif.GetFileExtensions, TFPReaderGIF); + + //Lazarus Picture + TPicture.RegisterFileFormat(TAnimatedGif.GetFileExtensions,'Animated GIF', TAnimatedGif); + +end. + diff --git a/baseunits/animatedgifs/membitmap.pas b/baseunits/animatedgifs/membitmap.pas index 7696bb1aa..d0550ffc7 100644 --- a/baseunits/animatedgifs/membitmap.pas +++ b/baseunits/animatedgifs/membitmap.pas @@ -1,1388 +1,1388 @@ -unit MemBitmap; -{ - /*************************************************************************** - membitmap.pas - -------------- - Easy-to-use memory bitmap 32-bit - 8-bit for each channel, transparency - Channels in that order : B G R A - - - Drawing primitives - - Resample - - Reference counter - - Drawing on LCL canvas - - Loading and saving images - - ***************************************************************************/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - -} - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, FPImage, Graphics; - -type - PMemPixel = ^TMemPixel; - TMemPixel = packed record blue,green,red,alpha: byte; end; - - TDrawMode = (dmSet, dmSetExceptTransparent, dmDrawWithTransparency); - - { TMemBitmap } - - TMemBitmap = class(TFPCustomImage) - private - FBitmap: TBitmap; //LCL bitmap object - FRefCount: integer; //reference counter - - function CheckEmpty: boolean; - function ResampleLarger(newWidth, newHeight: integer): TMemBitmap; - function ResampleSmaller(newWidth, newHeight: integer): TMemBitmap; - function GetHasTransparentPixels: boolean; - function GetAverageColor: TColor; - protected - {Pixel data} - FData: PMemPixel; - FWidth,FHeight,FNbPixels: integer; - FRebuildBmp: Boolean; //if image has changed - - function GetScanLine(y: integer): PMemPixel; - procedure RebuildBitmap; - function GetBitmap: TBitmap; - procedure Init; - {TFPCustomImage} - procedure SetInternalColor (x,y:integer; const Value:TFPColor); override; - function GetInternalColor (x,y:integer) : TFPColor; override; - procedure SetInternalPixel (x,y:integer; Value:integer); override; - function GetInternalPixel (x,y:integer) : integer; override; - public - {Reference counter functions} - function NewReference: TMemBitmap; - procedure FreeReference; - function GetUnique: TMemBitmap; - - {TFPCustomImage} - constructor Create(AWidth,AHeight: integer); override; - procedure SetSize (AWidth, AHeight : integer); override; - procedure SaveToFile(const filename:String); - - {Loading functions} - procedure Assign(Bitmap: TBitmap); overload; - procedure Assign(MemBitmap: TMemBitmap); overload; - constructor Create(AFilename: string); - destructor Destroy; override; - - {Drawing primitives} - procedure DrawPixels(c: TMemPixel; start,count: integer); overload; - procedure SetPixel(x,y: integer; c: TColor); overload; - procedure SetPixel(x,y: integer; c: TMemPixel); overload; - procedure DrawPixel(x,y: integer; c: TMemPixel); overload; - procedure AlphaPixel(x,y: integer; alpha: byte); - class procedure DrawPixel(dest: PMemPixel; c: TMemPixel); overload; inline; - function GetPixel(x,y: integer): TMemPixel; - function GetPixelCycle(x,y: integer): TMemPixel; - - procedure AlphaHorizLine(x,y,x2: integer; alpha: byte); - procedure SetHorizLine(x,y,x2: integer; c: TMemPixel); - procedure DrawHorizLine(x,y,x2: integer; c: TMemPixel); - procedure SetVertLine(x,y,y2: integer; c: TMemPixel); - procedure DrawVertLine(x,y,y2: integer; c: TMemPixel); - procedure AlphaVertLine(x,y,y2: integer; alpha: byte); - procedure Rectangle(x,y,x2,y2: integer; c: TMemPixel; mode: TDrawMode); - procedure Rectangle(x,y,x2,y2: integer; c: TColor); - - procedure FillRect(x,y,x2,y2: integer; c: TMemPixel; mode: TDrawMode); - procedure FillRect(x,y,x2,y2: integer; c: TColor); - procedure AlphaFillRect(x,y,x2,y2: integer; alpha:byte); - - procedure Fill(c: TColor); overload; - procedure Fill(c: TMemPixel); overload; - procedure Fill(c: TMemPixel; start,count: integer); overload; - procedure AlphaFill(alpha: byte); overload; - procedure AlphaFill(alpha: byte; start,count: integer); overload; - procedure ReplaceColor(before,after: TColor); overload; - procedure ReplaceColor(before,after: TMemPixel); overload; - - {LCL drawing functions} - procedure InvalidateBitmap; - procedure Draw(ACanvas: TCanvas; x,y: integer); - procedure Draw(ACanvas: TCanvas; Rect: TRect); - procedure GetImage(Canvas: TCanvas; x,y: integer; defaultColor: TColor); - procedure DrawPartial(ARect: TRect; Canvas: TCanvas; x,y: integer); - - {Mem bitmap functions} - procedure PutImage(x,y: integer; bmp: TMemBitmap; mode: TDrawMode); - function Duplicate: TMemBitmap; - function Resample(NewWidth, NewHeight: Integer): TMemBitmap; - procedure VerticalFlip; - - property Data: PMemPixel read FData; - property Width: Integer read FWidth; - property Height: Integer read FHeight; - property NbPixels: Integer read FNbPixels; - property Empty: boolean read CheckEmpty; - - property ScanLine[y: integer]: PMemPixel read GetScanLine; - property RefCount: integer read FRefCount; - property Bitmap: TBitmap read GetBitmap; //don't forget to call InvalidateBitmap before - //if you changed something - property HasTransparentPixels: boolean read GetHasTransparentPixels; - property AverageColor: TColor read GetAverageColor; - end; - -const - MemPixelTransparent : TMemPixel = (blue:0; green:0; red:0; alpha:0); - -function MemPixel(red,green,blue,alpha: byte): TMemPixel; overload; -function MemPixel(red,green,blue: byte): TMemPixel; overload; -function MemPixel(color: TColor): TMemPixel; overload; -function MemPixelToColor(c: TMemPixel): TColor; -operator = (const c1,c2:TMemPixel) : boolean; - -implementation - -uses FPWritePng, GraphType, LCLIntf, LCLType -{$IFDEF LCLgtk2} - {$DEFINE gtkbugfix} - ,gdk2,gtk2Def, gtk2Proc -{$ENDIF} -{$IFDEF LCLgtk} - {$DEFINE gtkbugfix} - ,gdk,gtkDef, gtkProc -{$ENDIF} -; - -function MemPixel(red, green, blue, alpha: byte): TMemPixel; -begin - result.red := red; - result.green := green; - result.blue := blue; - result.alpha := alpha; -end; - -function MemPixel(red, green, blue: byte): TMemPixel; overload; -begin - result.red := red; - result.green := green; - result.blue := blue; - result.alpha := 255; -end; - -function MemPixel(color: TColor): TMemPixel; overload; -begin - result.red := color; - result.green := color shr 8; - result.blue := color shr 16; - result.alpha := 255; -end; - -function MemPixelToColor(c: TMemPixel): TColor; -begin - result := c.red + (c.green shl 8) + (c.blue shl 16); -end; - -operator=(const c1, c2: TMemPixel): boolean; -begin - if (c1.alpha=0) and (c2.alpha=0) then result := true else - result := (c1.alpha=c2.alpha) and (c1.red=c2.red) and (c1.green=c2.green) and (c1.blue=c2.blue); -end; - -{ TMemBitmap } - -function TMemBitmap.CheckEmpty: boolean; -var i: integer; p: PMemPixel; -begin - p := data; - for i := NbPixels-1 downto 0 do - begin - if p^.alpha <> 0 then - begin - result := false; - exit; - end; - inc(p); - end; - result := true; -end; - -function TMemBitmap.GetScanLine(y: integer): PMemPixel; -begin - if (y < 0) or (y >= height) then - raise ERangeError.Create('Scanline: out of bounds') else - begin - result := data; - inc(result, width*y); - end; -end; - -constructor TMemBitmap.Create(AWidth, AHeight: integer); -begin - Init; - inherited Create(AWidth,AHeight); -end; - -constructor TMemBitmap.Create(AFilename: string); -begin - LoadFromFile(Afilename); -end; - -procedure TMemBitmap.SetSize(AWidth, AHeight: integer); -begin - if (AWidth = Width) and (AHeight = Height) then exit; - inherited SetSize(AWidth, AHeight); - if AWidth < 0 then AWidth := 0; - if AHeight < 0 then AHeight := 0; - FWidth := AWidth; - FHeight := AHeight; - FNbPixels := AWidth*AHeight; - if FNbPixels<0 then raise EOutOfMemory.Create('Image too big'); - ReAllocMem(FData,NbPixels*sizeof(TMemPixel)); - if (NbPixels>0) and (FData=nil) then - raise EOutOfMemory.Create('TMemBitmap: Not enough memory'); -end; - -procedure TMemBitmap.SaveToFile(const filename:String); -var ext: string; writer: TFPCustomImageWriter; - pngWriter : TFPWriterPNG; -begin - ext := AnsiLowerCase(ExtractFileExt(filename)); - - if ext='.png' then - begin - pngWriter := TFPWriterPNG.Create; - pngWriter.Indexed := false; - pngWriter.UseAlpha := HasTransparentPixels; - writer := pngWriter; - end else - writer := nil; - - if writer<> nil then - begin - inherited SaveToFile(Filename,writer); - writer.free; - end else - inherited SaveToFile(Filename); -end; - -procedure TMemBitmap.Assign(Bitmap: TBitmap); -begin - SetSize(Bitmap.width,bitmap.height); - GetImage(Bitmap.Canvas,0,0,clBlack); -end; - -procedure TMemBitmap.Assign(MemBitmap: TMemBitmap); -begin - SetSize(MemBitmap.Width,MemBitmap.height); - PutImage(0,0,MemBitmap,dmSet); -end; - -destructor TMemBitmap.Destroy; -begin - freemem(FData); - FBitmap.Free; - inherited Destroy; -end; - -procedure TMemBitmap.SetPixel(x, y: integer; c: TMemPixel); -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - (Scanline[y]+x)^ := c; -end; - -procedure TMemBitmap.SetPixel(x, y: integer; c: TColor); -var p: PByte; -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - p := PByte(Scanline[y]+x); - p^ := c shr 16; inc(p); - p^ := c shr 8; inc(p); - p^ := c; inc(p); - p^ := 255; -end; - -procedure TMemBitmap.DrawPixel(x, y: integer; c: TMemPixel); -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - DrawPixel(Scanline[y]+x, c); -end; - -procedure TMemBitmap.AlphaPixel(x, y: integer; alpha: byte); -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - (Scanline[y]+x)^.alpha := alpha; -end; - -class procedure TMemBitmap.DrawPixel(dest: PMemPixel; c: TMemPixel); -var p: PByte; a1f, a2f, a12, a12m: cardinal; -begin - if c.alpha = 0 then exit; - - a12 := 65025 - (255-dest^.alpha)*(255-c.alpha); - a12m := a12 shr 1; - - a1f := dest^.alpha*(255-c.alpha); - a2f := c.alpha* 255; - - p := PByte(dest); - p^ := (dest^.blue*a1f + c.blue*a2f + a12m ) div a12; inc(p); - p^ := (dest^.green*a1f + c.green*a2f + a12m ) div a12; inc(p); - p^ := (dest^.red*a1f + c.red*a2f + a12m ) div a12; inc(p); - p^ := (a12 + a12 shr 7) shr 8; -end; -{var p: PByte; a1,r1,g1,b1, a2,r2,g2,b2, a1f, a2f, a12: single; -begin - if c.alpha = 0 then exit; - - a2 := c.alpha/255; - r2 := c.red/255; - g2 := c.green/255; - b2 := c.blue/255; - - a1 := dest^.alpha/255; - r1 := dest^.red/255; - g1 := dest^.green/255; - b1 := dest^.blue/255; - - a12 := 1 - (1-a1)*(1-a2); - - a1f := a1*(1-a2)/a12* 255; - a2f := a2/a12* 255; - - p := PByte(dest); - p^ := round( b1*a1f + b2*a2f ); inc(p); - p^ := round( g1*a1f + g2*a2f ); inc(p); - p^ := round( r1*a1f + r2*a2f ); inc(p); - p^ := round( a12 * 255); -end;} - -function TMemBitmap.GetPixel(x, y: integer): TMemPixel; -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then result := MemPixelTransparent else - result := (Scanline[y]+x)^; -end; - -function TMemBitmap.GetPixelCycle(x, y: integer): TMemPixel; -begin - if (Width=0) or (Height=0) then result := MemPixelTransparent else - begin - x := x mod Width; - if x<0 then inc(x,width); - y := y mod Height; - if y<0 then inc(y,height); - result := (Scanline[y]+x)^; - end; -end; - -procedure TMemBitmap.AlphaHorizLine(x, y, x2: integer; alpha: byte); -var temp: integer; -begin - if (x2= width) or (x2 < 0) then exit; - if x < 0 then x := 0; - if x2 >= width then x2 := width-1; - AlphaFill(alpha, y*width+x, x2-x+1); -end; - -procedure TMemBitmap.InvalidateBitmap; -begin - FRebuildBmp := True; -end; - -procedure TMemBitmap.RebuildBitmap; -var RawImage : TRawImage; ABitmap, AMask: HBitmap; -begin - if FBitmap = nil then FBitmap := TBitmap.Create; - - if Empty then - begin - FBitmap.Height := 0; - FBitmap.Width := 0; - end else - begin - RawImage.Init; - RawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(Width,Height); - RawImage.Data:= PByte(data); - RawImage.DataSize:= nbPixels*sizeof(TMemPixel); - RawImage_CreateBitmaps(RawImage, ABitmap,AMask,False); - FBitmap.Handle := ABitmap; - FBitmap.MaskHandle := AMask; - end; -end; - -function TMemBitmap.GetBitmap: TBitmap; -begin - if FRebuildBmp or (FBitmap = nil) then - begin - RebuildBitmap; - FRebuildBmp := false; - end; - result := FBitmap; -end; - -procedure TMemBitmap.Init; -begin - FRefCount := 1; - FBitmap := nil; - FData := nil; - FWidth := 0; - FHeight := 0; -end; - -procedure TMemBitmap.SetInternalColor(x, y: integer; const Value: TFPColor); -var p: PByte; -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - p := PByte(Scanline[y]+x); - p^ := Value.blue shr 8; inc(p); - p^ := Value.green shr 8; inc(p); - p^ := Value.red shr 8; inc(p); - p^ := Value.alpha shr 8; -end; - -function TMemBitmap.GetInternalColor(x, y: integer): TFPColor; -var p: PByte; v: byte; -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - p := PByte(Scanline[y]+x); - v := p^; result.blue := v shl 8+v; inc(p); - v := p^; result.green := v shl 8+v; inc(p); - v := p^; result.red := v shl 8+v; inc(p); - v := p^; result.alpha := v shl 8+v; -end; - -procedure TMemBitmap.SetInternalPixel(x, y: integer; Value: integer); -var p: PByte; c: TFPColor; -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - c := Palette.Color[Value]; - p := PByte(Scanline[y]+x); - p^ := c.blue shr 8; inc(p); - p^ := c.green shr 8; inc(p); - p^ := c.red shr 8; inc(p); - p^ := c.alpha shr 8; -end; - -function TMemBitmap.GetInternalPixel(x, y: integer): integer; -var p: PByte; v: byte; c: TFPColor; -begin - if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; - p := PByte(Scanline[y]+x); - v := p^; c.blue := v shl 8+v; inc(p); - v := p^; c.green := v shl 8+v; inc(p); - v := p^; c.red := v shl 8+v; inc(p); - v := p^; c.alpha := v shl 8+v; - result := palette.IndexOf(c); -end; - -function TMemBitmap.NewReference: TMemBitmap; -begin - Inc(FRefCount); - result := self; -end; - -procedure TMemBitmap.FreeReference; -begin - if self=nil then exit; - - if FRefCount > 0 then - begin - Dec(FRefCount); - if FRefCount = 0 then - begin - self.Destroy; - end; - end; -end; - -function TMemBitmap.GetUnique: TMemBitmap; -begin - if FRefCount > 1 then - begin - Dec(FRefCount); - result := self.Duplicate; - end else - result := self; -end; - -procedure TMemBitmap.Draw(ACanvas: TCanvas; x, y: integer); -begin - if self=nil then exit; - ACanvas.Draw(x,y,Bitmap); -end; - -procedure TMemBitmap.Draw(ACanvas: TCanvas; Rect: TRect); -begin - if self=nil then exit; - ACanvas.StretchDraw(Rect,Bitmap); -end; - -procedure TMemBitmap.DrawHorizLine(x, y, x2: integer; c: TMemPixel); -var temp: integer; -begin - if (x2= width) or (x2 < 0) then exit; - if x < 0 then x := 0; - if x2 >= width then x2 := width-1; - DrawPixels(c, y*width+x, x2-x+1); -end; - -procedure TMemBitmap.SetHorizLine(x, y, x2: integer; c: TMemPixel); -var temp: integer; -begin - if (x2= width) or (x2 < 0) then exit; - if x < 0 then x := 0; - if x2 >= width then x2 := width-1; - Fill(c, y*width+x, x2-x+1); -end; - -procedure TMemBitmap.SetVertLine(x, y, y2: integer; c: TMemPixel); -var temp,n: integer; p: PMemPixel; -begin - if (y2= height) or (y2 < 0) or (x < 0) or (x >= width) then exit; - if y < 0 then y := 0; - if y2 >= height then y2 := height-1; - p := scanline[y]+x; - for n := y2-y downto 0 do - begin - p^ := c; - inc(p,width); - end; -end; - -procedure TMemBitmap.DrawVertLine(x, y, y2: integer; c: TMemPixel); -var temp,n: integer; p: PMemPixel; -begin - if (y2= height) or (y2 < 0) or (x < 0) or (x >= width) then exit; - if y < 0 then y := 0; - if y2 >= height then y2 := height-1; - p := scanline[y]+x; - for n := y2-y downto 0 do - begin - DrawPixel(p,c); - inc(p,width); - end; -end; - -procedure TMemBitmap.AlphaVertLine(x, y, y2: integer; alpha: byte); -var temp,n: integer; p: PMemPixel; -begin - if (y2= height) or (y2 < 0) or (x < 0) or (x >= width) then exit; - if y < 0 then y := 0; - if y2 >= height then y2 := height-1; - p := scanline[y]+x; - for n := y2-y downto 0 do - begin - p^.alpha := alpha; - inc(p,width); - end; -end; - -procedure TMemBitmap.Rectangle(x, y, x2, y2: integer; c: TMemPixel; - mode: TDrawMode); -var temp: integer; -begin - if (x>x2) then begin temp := x; x := x2; x2 := temp; end; - if (y>y2) then begin temp := y; y := y2; y2 := temp; end; - if (x2-x<=1) or (y2-y<=1) then exit; - case mode of - dmDrawWithTransparency: - begin - DrawHorizLine(x,y,x2-1, c); - DrawHorizLine(x,y2-1,x2-1, c); - if y2-y > 2 then - begin - DrawVertLine(x,y+1,y2-2, c); - DrawVertLine(x2-1,y+1,y2-2, c); - end; - end; - dmSet: - begin - SetHorizLine(x,y,x2-1, c); - SetHorizLine(x,y2-1,x2-1, c); - if y2-y > 2 then - begin - SetVertLine(x,y+1,y2-2, c); - SetVertLine(x2-1,y+1,y2-2, c); - end; - end; - dmSetExceptTransparent: if (c.alpha <> 0) then Rectangle(x,y,x2,y2,c,dmSet); - end; -end; - -procedure TMemBitmap.Rectangle(x, y, x2, y2: integer; c: TColor); -begin - Rectangle(x,y,x2,y2,MemPixel(c),dmSet); -end; - -procedure TMemBitmap.FillRect(x, y, x2, y2: integer; c: TMemPixel; - mode: TDrawMode); -var temp,yb: integer; -begin - if (x>x2) then begin temp := x; x := x2; x2 := temp; end; - if (y>y2) then begin temp := y; y := y2; y2 := temp; end; - if (x2-x<=0) or (y2-y<=0) then exit; - case mode of - dmDrawWithTransparency: - for yb := y to y2-1 do - DrawHorizLine(x,yb,x2-1, c); - dmSet: - for yb := y to y2-1 do - SetHorizLine(x,yb,x2-1, c); - dmSetExceptTransparent: if (c.alpha <> 0) then FillRect(x,y,x2,y2,c,dmSet); - end; -end; - -procedure TMemBitmap.FillRect(x, y, x2, y2: integer; c: TColor); -begin - FillRect(x,y,x2,y2,MemPixel(c),dmSet); -end; - -procedure TMemBitmap.AlphaFillRect(x, y, x2, y2: integer; alpha: byte); -var temp,yb: integer; -begin - if (x>x2) then begin temp := x; x := x2; x2 := temp; end; - if (y>y2) then begin temp := y; y := y2; y2 := temp; end; - if (x2-x<=0) or (y2-y<=0) then exit; - for yb := y to y2-1 do - AlphaHorizLine(x,yb,x2-1, alpha); -end; - -procedure TMemBitmap.Fill(c: TColor); -begin - Fill(MemPixel(c)); -end; - -procedure TMemBitmap.Fill(c: TMemPixel); -begin - Fill(c, 0, width*height); -end; - -procedure TMemBitmap.Fill(c: TMemPixel; start, count: integer); -var p: PMemPixel; -begin - if start < 0 then - begin - count += start; - start := 0; - end; - if start >= nbPixels then exit; - if start+count > nbPixels then count := nbPixels-start; - p := (Data+start); - while count > 0 do - begin - p^ := c; - inc(p); - dec(count); - end; -end; - -procedure TMemBitmap.AlphaFill(alpha: byte); -begin - AlphaFill(alpha,0,NbPixels); -end; - -procedure TMemBitmap.AlphaFill(alpha: byte; start, count: integer); -var p: PMemPixel; -begin - if start < 0 then - begin - count += start; - start := 0; - end; - if start >= nbPixels then exit; - if start+count > nbPixels then count := nbPixels-start; - p := (Data+start); - while count > 0 do - begin - p^.alpha := alpha; - inc(p); - dec(count); - end; -end; - -procedure TMemBitmap.ReplaceColor(before, after: TColor); -const colorMask = $00FFFFFF; -var p: PLongWord; - n: integer; - beforeBGR, afterBGR: LongWord; -begin - beforeBGR := (before and $FF shl 16) + (before and $FF00) + (before shr 16 and $FF); - afterBGR := (after and $FF shl 16) + (after and $FF00) + (after shr 16 and $FF); - p := PLongWord(Data); - for n := NbPixels-1 downto 0 do - begin - if p^ and colorMask = beforeBGR then - p^ := (p^ and not ColorMask) or afterBGR; - inc(p); - end; -end; - -procedure TMemBitmap.ReplaceColor(before, after: TMemPixel); -var p: PMemPixel; - n: integer; -begin - p := Data; - for n := NbPixels-1 downto 0 do - begin - if p^ = before then p^ := after; - inc(p); - end; -end; - -procedure TMemBitmap.DrawPixels(c: TMemPixel; start, count: integer); -var p: PMemPixel; -begin - if c.alpha = 0 then exit; - - if start < 0 then - begin - count += start; - start := 0; - end; - if start >= nbPixels then exit; - if start+count > nbPixels then count := nbPixels-start; - p := Data+start; - while count > 0 do - begin - DrawPixel(p,c); - inc(p); - dec(count); - end; -end; - -procedure TMemBitmap.PutImage(x, y: integer; bmp: TMemBitmap; mode: TDrawMode); -var x2,y2,yb,minxb,minyb,maxxb,ignoreleft,copycount,bmpwidth,i: integer; source,dest: PMemPixel; -begin - bmpwidth := bmp.width; - - if (x>= width) or (y>= height) or (x< -bmpwidth) or (y < -bmp.height) then exit; - - x2 := x+bmpwidth-1; - y2 := y+bmp.height-1; - - if y < 0 then minyb := 0 else minyb := y; - if y2 >= height then y2 := height-1; - - if x < 0 then - begin - ignoreleft := -x; - minxb := 0; - end else - begin - ignoreleft := 0; - minxb := x; - end; - if x2 >= width then maxxb := width-1 else maxxb := x2; - - copycount := maxxb-minxb+1; - - source := bmp.ScanLine[minyb-y]+ignoreleft; - dest := Scanline[minyb]+minxb; - - case mode of - dmSet: begin - copycount *= sizeof(TMemPixel); - for yb := minyb to y2 do - begin - move(source^,dest^, copycount); - inc(source, bmpwidth); - inc(dest, width); - end; - end; - dmSetExceptTransparent: - for yb := minyb to y2 do - begin - for i := copycount-1 downto 0 do - begin - if source^.alpha = 255 then dest^ := source^; - inc(dest); - inc(source); - end; - inc(source, bmpwidth-copycount); - inc(dest, width-copycount); - end; - dmDrawWithTransparency: - for yb := minyb to y2 do - begin - for i := copycount-1 downto 0 do - begin - DrawPixel(dest,source^); - inc(dest); - inc(source); - end; - inc(source, bmpwidth-copycount); - inc(dest, width-copycount); - end; - end; -end; - -function TMemBitmap.Duplicate: TMemBitmap; -begin - result := TMemBitmap.Create(width,height); - result.PutImage(0,0,self,dmSet); -end; - -procedure TMemBitmap.GetImage(Canvas: TCanvas; x, y: integer; defaultColor: TColor); -var bmp: TBitmap; xb,yb: integer; - source: PByte; dest: PByte; - {$IFDEF gtkbugfix} - Ofs: TPoint; - dcSource,dcDest : TGtkDeviceContext; - {$ENDIF} - rectSource,rectDest: TRect; - - function ClipRect: boolean; - var delta: integer; - begin - if rectSource.Left < 0 then - begin - delta := -rectSource.left; - inc(rectSource.Left,delta); - inc(rectDest.Left,delta); - end; - if rectSource.Top < 0 then - begin - delta := -rectSource.Top; - inc(rectSource.Top,delta); - inc(rectDest.Top,delta); - end; - if rectSource.Right > Canvas.Width then - begin - delta := rectSource.Right-Canvas.Width; - dec(rectSource.Right,delta); - dec(rectDest.Right,delta); - end; - if rectSource.Bottom > Canvas.Height then - begin - delta := rectSource.Bottom-Canvas.Height; - dec(rectSource.Bottom,delta); - dec(rectDest.Bottom,delta); - end; - result := (rectSource.Right>rectSource.Left) and - (rectSource.Bottom>rectSource.Top) and - (rectDest.Right>rectDest.Left) and - (rectDest.Bottom>rectDest.Top); - end; - -begin - bmp := TBitmap.Create; - bmp.PixelFormat:= pf24bit; - bmp.width := width; - bmp.height := height; - bmp.Canvas.Brush.Color := defaultColor; - bmp.Canvas.FillRect(0,0,width,height); - rectSource := classes.rect(x,y,x+width,y+height); - rectDest := classes.rect(0,0,width,height); - - {$IFDEF gtkbugfix} - dcDest := TGtkDeviceContext(bmp.Canvas.handle); - dcSource := TGtkDeviceContext(Canvas.Handle); - if (dcSource <> nil) and (dcDest <> nil) then - begin - Ofs := dcSource.Offset; - rectSource.Left += Ofs.X; - rectSource.Top += Ofs.Y; - rectSource.Right += Ofs.X; - rectSource.Bottom += Ofs.Y; - if ClipRect then - begin - if (dcDest.Drawable<>nil) and (dcDest.GC <> nil) and (dcSource.Drawable <> nil) then - gdk_window_copy_area(dcDest.Drawable, dcDest.GC, rectDest.Left,rectDest.top, dcSource.Drawable,rectSource.Left,rectSource.Top, rectSource.Right-rectSource.Left,rectSource.Bottom-rectSource.Top); - end; - end; - {$ELSE} - if ClipRect then - bmp.Canvas.CopyRect(rectDest,Canvas,rectSource); - {$ENDIF} - - if bmp.RawImage.Description.BitsPerPixel = 32 then - begin - for yb := 0 to height-1 do - begin - if bmp.rawImage.Description.LineOrder = riloTopToBottom then - source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(yb) else - source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(height-1-yb); - dest := pbyte(ScanLine[yb]); - for xb := 0 to width-1 do - begin - PWord(dest)^ := PWord(source)^; - inc(dest,2); inc(source, 2); - dest^ := source ^; - inc(dest); inc(source, 2); - dest^:= 255; - inc(dest); - end; - end; - end else - if bmp.RawImage.Description.BitsPerPixel = 24 then - begin - for yb := 0 to height-1 do - begin - if bmp.rawImage.Description.LineOrder = riloTopToBottom then - source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(yb) else - source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(height-1-yb); - dest := pbyte(ScanLine[yb]); - for xb := 0 to width-1 do - begin - PWord(dest)^ := PWord(source)^; - inc(dest,2); inc(source, 2); - dest^ := source ^; - inc(dest); inc(source); - dest^:= 255; - inc(dest); - end; - end; - end; - - bmp.Free; -end; - -function TMemBitmap.ResampleSmaller(newWidth, newHeight: integer - ): TMemBitmap; -const maxvalue= 255; -var - x_dest,y_dest : integer; - inc_x_src, mod_x_src, acc_x_src, inc_y_src, mod_y_src, acc_y_src : integer; - x_src,y_src,prev_x_src,prev_y_src: integer; - x_src2,y_src2: integer; - - xb,yb : integer; - alpha,v1,v2,v3,v4: double; - nb: integer; - c: TMemPixel; - pdest,psrc: PMemPixel; -begin - result := TMemBitmap.Create(NewWidth, NewHeight); - if (newWidth = 0) or (newHeight = 0) or (Width= 0) or (Height = 0) then exit; - inc_x_src := width div newWidth; - mod_x_src := width mod newWidth; - inc_y_src := height div newHeight; - mod_y_src := height mod newHeight; - - y_src := 0; - acc_y_src := 0; - PDest := result.ScanLine[0]; - for y_dest := 0 to newHeight-1 do - begin - prev_y_src := y_src; - inc(y_src,inc_y_src); - inc(acc_y_src,mod_y_src); - if acc_y_src >= newHeight then - begin - dec(acc_y_src,newHeight); - inc(y_src); - end; - - x_src := 0; - acc_x_src := 0; - for x_dest := 0 to newWidth-1 do - begin - prev_x_src := x_src; - inc(x_src,inc_x_src); - inc(acc_x_src,mod_x_src); - if acc_x_src >= newWidth then - begin - dec(acc_x_src,newWidth); - inc(x_src); - end; - - if x_src > prev_x_src then x_src2 := x_src-1 else x_src2 := x_src; - if y_src > prev_y_src then y_src2 := y_src-1 else y_src2 := y_src; - - v1 := 0; - v2 := 0; - v3 := 0; - v4 := 0; - nb := 0; - for yb := prev_y_src to y_src2 do - begin - PSrc := Scanline[yb]+prev_x_src; - for xb := prev_x_src to x_src2 do - begin - c := PSrc^; inc(PSrc); - alpha := c.alpha/maxvalue; - v1 += c.red*alpha; - v2 += c.green*alpha; - v3 += c.blue*alpha; - v4 += alpha; - inc(nb); - end; - end; - - if (v4<>0) and (nb <> 0) then - begin - c.red := round(v1/v4); - c.green := round(v2/v4); - c.blue := round(v3/v4); - c.alpha := round(v4/nb*maxvalue); - end else - begin - c.alpha := 0; - c.red := 0; - c.green := 0; - c.blue := 0; - end; - PDest^ := c; - inc(PDest); - end; - end; -end; - -function TMemBitmap.GetHasTransparentPixels: boolean; -var p: PMemPixel; n: integer; -begin - p := Data; - for n := NbPixels-1 downto 0 do - begin - if p^.alpha <> 255 then - begin - result := true; - exit; - end; - inc(p); - end; - result := false; -end; - -function TMemBitmap.GetAverageColor: TColor; -var n: integer; p: PMemPixel; - r,g,b,sum: double; - alpha: double; -begin - sum := 0; - r := 0; - g := 0; - b := 0; - p := Data; - for n := NbPixels-1 downto 0 do - begin - alpha := p^.alpha/255; - sum += alpha; - r += p^.red*alpha; - g += p^.green*alpha; - b += p^.blue*alpha; - end; - if sum=0 then result := clNone else - result := round(r/sum) + round(g/sum) shl 8 + round(b/sum) shl 16; -end; - -function TMemBitmap.ResampleLarger(newWidth, newHeight: integer): TMemBitmap; -const maxvalue = 255; -var - x_src,y_src : integer; - inc_x_dest, mod_x_dest, acc_x_dest, inc_y_dest, mod_y_dest, acc_y_dest : integer; - x_dest,y_dest,prev_x_dest,prev_y_dest: integer; - x_dest2,y_dest2,{x_src2,}y_src2: integer; - - xb,yb : integer; - cUpLeft,cUpRight,cLowLeft,cLowRight: TMemPixel; - factX,factY,factAddX,factAddY,factCorrX,factCorrY: single; - factUpLeft,factUpRight,factLowLeft,factLowRight: single; - factUpLeftAlpha,factUpRightAlpha,factLowLeftAlpha,factLowRightAlpha: single; - cur: TMemPixel; - alphaUpLeft, alphaUpRight, alphaLowLeft, alphaLowRight: single; - sumFactAlpha: single; - PDest,PSrc,PSrc2 : PMemPixel; - - temp: TMemBitmap; - -begin - result := TMemBitmap.Create(NewWidth, NewHeight); - if (newWidth = 0) or (newHeight = 0) then exit; - - if (width=1) and (height=1) then - begin - result.Fill(GetPixel(0,0)); - exit; - end else - if width=1 then - begin - temp := TMemBitmap.Create(2,Height); - temp.PutImage(0,0,self,dmSet); - temp.PutImage(1,0,self,dmSet); - result := temp.ResampleLarger(newWidth,newHeight); - temp.Free; - exit; - end else - if height=1 then - begin - temp := TMemBitmap.Create(Width,2); - temp.PutImage(0,0,self,dmSet); - temp.PutImage(0,1,self,dmSet); - result := temp.ResampleLarger(newWidth,newHeight); - temp.Free; - exit; - end; - - inc_x_dest := newwidth div (Width-1); - mod_x_dest := newwidth mod (Width-1); - inc_y_dest := newheight div (Height-1); - mod_y_dest := newheight mod (Height-1); - - y_dest := 0; - acc_y_dest := 0; - for y_src := 0 to Height-2 do - begin - prev_y_dest := y_dest; - inc(y_dest,inc_y_dest); - inc(acc_y_dest,mod_y_dest); - if acc_y_dest >= Height then - begin - dec(acc_y_dest,Height); - inc(y_dest); - end; - - y_src2 := y_src+1; - PSrc := Scanline[y_src]; - PSrc2 := Scanline[y_src2]; - cUpLeft := PSrc^; inc(PSrc); - cLowLeft := PSrc2^; inc(PSrc2); - - x_dest := 0; - acc_x_dest := 0; - for x_src := 0 to Width-2 do - begin - prev_x_dest := x_dest; - inc(x_dest,inc_x_dest); - inc(acc_x_dest,mod_x_dest); - if acc_x_dest >= Width then - begin - dec(acc_x_dest,Width); - inc(x_dest); - end; - - //x_src2 := x_src+1; - if x_src < width-2 then - begin - x_dest2 := x_dest-1; - factAddX := 1/(x_dest2-prev_x_dest+1); - end else - begin - x_dest2 := newWidth-1; - factAddX := 1/(x_dest2-prev_x_dest); - end; - if y_src < height-2 then - begin - y_dest2 := y_dest-1; - factAddY := 1/(y_dest2-prev_y_dest+1); - end else - begin - y_dest2 := newHeight-1; - factAddY := 1/(y_dest2-prev_y_dest); - end; - - cUpRight := PSrc^; inc(PSrc); - cLowRight := PSrc2^; inc(PSrc2); - - factY := 0; - for yb := prev_y_dest to y_dest2 do - begin - factX := 0; - PDest := result.scanline[yb]+prev_x_dest; - for xb := prev_x_dest to x_dest2 do - begin - factCorrX := 0.5-cos(factX*Pi)/2; - factCorrY := 0.5-cos(factY*Pi)/2; - - alphaUpLeft := cUpLeft.alpha/maxvalue; - alphaUpRight := cUpRight.alpha/maxvalue; - alphaLowLeft := cLowLeft.alpha/maxvalue; - alphaLowRight := cLowRight.alpha/maxvalue; - - factUpLeft := (1-factCorrX)*(1-factCorrY); - factUpRight := factCorrX*(1-factCorrY); - factLowLeft := (1-factCorrX)*factCorrY; - factLowRight := factCorrX*factCorrY; - - factUpLeftAlpha := factUpLeft*alphaUpLeft; - factUpRightAlpha := factUpRight*alphaUpRight; - factLowLeftAlpha := factLowLeft*alphaLowLeft; - factLowRightAlpha := factLowRight*alphaLowRight; - - sumFactAlpha := factUpLeftAlpha+factUpRightAlpha+factLowLeftAlpha+factLowRightAlpha; - if sumFactAlpha=0 then - begin - cur.alpha := 0; - cur.red := 0; - cur.green := 0; - cur.blue := 0; - end else - begin - cur.red := round((factUpLeftAlpha*cUpLeft.red + factUpRightAlpha*cUpRight.red + - factLowLeftAlpha*cLowLeft.red + factLowRightAlpha*cLowRight.red)/sumFactAlpha); - cur.green := round((factUpLeftAlpha*cUpLeft.green + factUpRightAlpha*cUpRight.green + - factLowLeftAlpha*cLowLeft.green + factLowRightAlpha*cLowRight.green)/sumFactAlpha); - cur.blue := round((factUpLeftAlpha*cUpLeft.blue + factUpRightAlpha*cUpRight.blue + - factLowLeftAlpha*cLowLeft.blue + factLowRightAlpha*cLowRight.blue)/sumFactAlpha); - cur.alpha := round(sumFactAlpha*maxvalue); - end; - PDest^ := cur; inc(PDest); - factX := factX + factAddX; - end; - factY := factY+factAddY; - end; - cUpLeft := cUpRight; - cLowLeft := cLowRight; - end; - end; -end; - -function TMemBitmap.Resample(NewWidth, NewHeight: Integer): TMemBitmap; -var temp,newtemp: TMemBitmap; -begin - if (NewWidth = Width) and (NewHeight = Height) then - result := Duplicate else - if (NewWidth >= Width) and (NewHeight >= Height) then - result := ResampleLarger(NewWidth,NewHeight) else - if (NewWidth <= Width) and (NewHeight <= Height) then - result := ResampleSmaller(NewWidth,NewHeight) else - begin - temp := self; - - if NewWidth < Width then - begin - newtemp := temp.ResampleSmaller(NewWidth,temp.Height); - if (temp<>self) then temp.free; - temp := newtemp; - end; - - if NewHeight < Height then - begin - newtemp := temp.ResampleSmaller(temp.Width,NewHeight); - if (temp<>self) then temp.free; - temp := newtemp; - end; - - if NewWidth > Width then - begin - newtemp := temp.ResampleLarger(NewWidth,temp.Height); - if (temp<>self) then temp.free; - temp := newtemp; - end; - - if NewHeight > Height then - begin - newtemp := temp.ResampleLarger(temp.Width,NewHeight); - if (temp<>self) then temp.free; - temp := newtemp; - end; - - if temp<>self then result := temp else - result := self.Duplicate; - end; -end; - -procedure TMemBitmap.VerticalFlip; -var yb: integer; - line: PMemPixel; - linesize: integer; -begin - if Data= nil then exit; - - linesize := Width*sizeof(TMemPixel); - line := nil; - getmem(line, linesize); - for yb := 0 to (Height div 2)-1 do - begin - move(Scanline[yb]^, line^, linesize); - move(Scanline[Height-1-yb]^, Scanline[yb]^, linesize); - move(line^, Scanline[Height-1-yb]^, linesize); - end; - freemem(line); -end; - -procedure TMemBitmap.DrawPartial(Arect: TRect; Canvas: TCanvas; x,y: integer); -var partial: TMemBitmap; - copywidth,copyheight,widthleft,heightleft,curxin,curyin,xdest,ydest,tx,ty: integer; -begin - tx := ARect.Right-ARect.Left; - ty := ARect.Bottom-ARect.Top; - - if ARect.Left >= Width then ARect.Left := ARect.Left mod Width else - if ARect.Left < 0 then ARect.Left := Width - ((-ARect.Left) mod Width); - ARect.Right := ARect.Left+tx; - - if ARect.Top >= Height then ARect.Top := ARect.Top mod Height else - if ARect.Top < 0 then ARect.Top := Height - ((-ARect.Top) mod Height); - ARect.Bottom := ARect.Top+ty; - - if (ARect.Left = 0) and (ARect.Top = 0) and (ARect.Right = Width) and (ARect.Bottom = Height) then - begin - Draw(Canvas,x,y); - exit; - end; - - partial := TMemBitmap.Create(tx,ty); - heightleft := partial.height; - curyin := ARect.Top; - ydest := -ARect.Top; - while heightleft > 0 do - begin - if curyin + heightleft > height then copyheight := height-curyin else - copyheight := heightleft; - - widthleft := partial.width; - curxin := ARect.Left; - xdest := -ARect.Left; - while widthleft > 0 do - begin - if curxin + widthleft > width then copywidth := width-curxin else - copywidth := widthleft; - - partial.PutImage(xdest,ydest,self,dmSet); - - curxin := 0; - dec(widthleft, copywidth); - inc(xdest,copywidth); - end; - curyin := 0; - dec(heightleft, copyheight); - inc(ydest,copyheight); - end; - partial.Draw(Canvas,x,y); - partial.Free; -end; - -end. +unit MemBitmap; +{ + /*************************************************************************** + membitmap.pas + -------------- + Easy-to-use memory bitmap 32-bit + 8-bit for each channel, transparency + Channels in that order : B G R A + + - Drawing primitives + - Resample + - Reference counter + - Drawing on LCL canvas + - Loading and saving images + + ***************************************************************************/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +} + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FPImage, Graphics; + +type + PMemPixel = ^TMemPixel; + TMemPixel = packed record blue,green,red,alpha: byte; end; + + TDrawMode = (dmSet, dmSetExceptTransparent, dmDrawWithTransparency); + + { TMemBitmap } + + TMemBitmap = class(TFPCustomImage) + private + FBitmap: TBitmap; //LCL bitmap object + FRefCount: integer; //reference counter + + function CheckEmpty: boolean; + function ResampleLarger(newWidth, newHeight: integer): TMemBitmap; + function ResampleSmaller(newWidth, newHeight: integer): TMemBitmap; + function GetHasTransparentPixels: boolean; + function GetAverageColor: TColor; + protected + {Pixel data} + FData: PMemPixel; + FWidth,FHeight,FNbPixels: integer; + FRebuildBmp: Boolean; //if image has changed + + function GetScanLine(y: integer): PMemPixel; + procedure RebuildBitmap; + function GetBitmap: TBitmap; + procedure Init; + {TFPCustomImage} + procedure SetInternalColor (x,y:integer; const Value:TFPColor); override; + function GetInternalColor (x,y:integer) : TFPColor; override; + procedure SetInternalPixel (x,y:integer; Value:integer); override; + function GetInternalPixel (x,y:integer) : integer; override; + public + {Reference counter functions} + function NewReference: TMemBitmap; + procedure FreeReference; + function GetUnique: TMemBitmap; + + {TFPCustomImage} + constructor Create(AWidth,AHeight: integer); override; + procedure SetSize (AWidth, AHeight : integer); override; + procedure SaveToFile(const filename:String); + + {Loading functions} + procedure Assign(Bitmap: TBitmap); overload; + procedure Assign(MemBitmap: TMemBitmap); overload; + constructor Create(AFilename: string); + destructor Destroy; override; + + {Drawing primitives} + procedure DrawPixels(c: TMemPixel; start,count: integer); overload; + procedure SetPixel(x,y: integer; c: TColor); overload; + procedure SetPixel(x,y: integer; c: TMemPixel); overload; + procedure DrawPixel(x,y: integer; c: TMemPixel); overload; + procedure AlphaPixel(x,y: integer; alpha: byte); + class procedure DrawPixel(dest: PMemPixel; c: TMemPixel); overload; inline; + function GetPixel(x,y: integer): TMemPixel; + function GetPixelCycle(x,y: integer): TMemPixel; + + procedure AlphaHorizLine(x,y,x2: integer; alpha: byte); + procedure SetHorizLine(x,y,x2: integer; c: TMemPixel); + procedure DrawHorizLine(x,y,x2: integer; c: TMemPixel); + procedure SetVertLine(x,y,y2: integer; c: TMemPixel); + procedure DrawVertLine(x,y,y2: integer; c: TMemPixel); + procedure AlphaVertLine(x,y,y2: integer; alpha: byte); + procedure Rectangle(x,y,x2,y2: integer; c: TMemPixel; mode: TDrawMode); + procedure Rectangle(x,y,x2,y2: integer; c: TColor); + + procedure FillRect(x,y,x2,y2: integer; c: TMemPixel; mode: TDrawMode); + procedure FillRect(x,y,x2,y2: integer; c: TColor); + procedure AlphaFillRect(x,y,x2,y2: integer; alpha:byte); + + procedure Fill(c: TColor); overload; + procedure Fill(c: TMemPixel); overload; + procedure Fill(c: TMemPixel; start,count: integer); overload; + procedure AlphaFill(alpha: byte); overload; + procedure AlphaFill(alpha: byte; start,count: integer); overload; + procedure ReplaceColor(before,after: TColor); overload; + procedure ReplaceColor(before,after: TMemPixel); overload; + + {LCL drawing functions} + procedure InvalidateBitmap; + procedure Draw(ACanvas: TCanvas; x,y: integer); + procedure Draw(ACanvas: TCanvas; Rect: TRect); + procedure GetImage(Canvas: TCanvas; x,y: integer; defaultColor: TColor); + procedure DrawPartial(ARect: TRect; Canvas: TCanvas; x,y: integer); + + {Mem bitmap functions} + procedure PutImage(x,y: integer; bmp: TMemBitmap; mode: TDrawMode); + function Duplicate: TMemBitmap; + function Resample(NewWidth, NewHeight: Integer): TMemBitmap; + procedure VerticalFlip; + + property Data: PMemPixel read FData; + property Width: Integer read FWidth; + property Height: Integer read FHeight; + property NbPixels: Integer read FNbPixels; + property Empty: boolean read CheckEmpty; + + property ScanLine[y: integer]: PMemPixel read GetScanLine; + property RefCount: integer read FRefCount; + property Bitmap: TBitmap read GetBitmap; //don't forget to call InvalidateBitmap before + //if you changed something + property HasTransparentPixels: boolean read GetHasTransparentPixels; + property AverageColor: TColor read GetAverageColor; + end; + +const + MemPixelTransparent : TMemPixel = (blue:0; green:0; red:0; alpha:0); + +function MemPixel(red,green,blue,alpha: byte): TMemPixel; overload; +function MemPixel(red,green,blue: byte): TMemPixel; overload; +function MemPixel(color: TColor): TMemPixel; overload; +function MemPixelToColor(c: TMemPixel): TColor; +operator = (const c1,c2:TMemPixel) : boolean; + +implementation + +uses FPWritePng, GraphType, LCLIntf, LCLType +{$IFDEF LCLgtk2} + {$DEFINE gtkbugfix} + ,gdk2,gtk2Def, gtk2Proc +{$ENDIF} +{$IFDEF LCLgtk} + {$DEFINE gtkbugfix} + ,gdk,gtkDef, gtkProc +{$ENDIF} +; + +function MemPixel(red, green, blue, alpha: byte): TMemPixel; +begin + result.red := red; + result.green := green; + result.blue := blue; + result.alpha := alpha; +end; + +function MemPixel(red, green, blue: byte): TMemPixel; overload; +begin + result.red := red; + result.green := green; + result.blue := blue; + result.alpha := 255; +end; + +function MemPixel(color: TColor): TMemPixel; overload; +begin + result.red := color; + result.green := color shr 8; + result.blue := color shr 16; + result.alpha := 255; +end; + +function MemPixelToColor(c: TMemPixel): TColor; +begin + result := c.red + (c.green shl 8) + (c.blue shl 16); +end; + +operator=(const c1, c2: TMemPixel): boolean; +begin + if (c1.alpha=0) and (c2.alpha=0) then result := true else + result := (c1.alpha=c2.alpha) and (c1.red=c2.red) and (c1.green=c2.green) and (c1.blue=c2.blue); +end; + +{ TMemBitmap } + +function TMemBitmap.CheckEmpty: boolean; +var i: integer; p: PMemPixel; +begin + p := data; + for i := NbPixels-1 downto 0 do + begin + if p^.alpha <> 0 then + begin + result := false; + exit; + end; + inc(p); + end; + result := true; +end; + +function TMemBitmap.GetScanLine(y: integer): PMemPixel; +begin + if (y < 0) or (y >= height) then + raise ERangeError.Create('Scanline: out of bounds') else + begin + result := data; + inc(result, width*y); + end; +end; + +constructor TMemBitmap.Create(AWidth, AHeight: integer); +begin + Init; + inherited Create(AWidth,AHeight); +end; + +constructor TMemBitmap.Create(AFilename: string); +begin + LoadFromFile(Afilename); +end; + +procedure TMemBitmap.SetSize(AWidth, AHeight: integer); +begin + if (AWidth = Width) and (AHeight = Height) then exit; + inherited SetSize(AWidth, AHeight); + if AWidth < 0 then AWidth := 0; + if AHeight < 0 then AHeight := 0; + FWidth := AWidth; + FHeight := AHeight; + FNbPixels := AWidth*AHeight; + if FNbPixels<0 then raise EOutOfMemory.Create('Image too big'); + ReAllocMem(FData,NbPixels*sizeof(TMemPixel)); + if (NbPixels>0) and (FData=nil) then + raise EOutOfMemory.Create('TMemBitmap: Not enough memory'); +end; + +procedure TMemBitmap.SaveToFile(const filename:String); +var ext: string; writer: TFPCustomImageWriter; + pngWriter : TFPWriterPNG; +begin + ext := AnsiLowerCase(ExtractFileExt(filename)); + + if ext='.png' then + begin + pngWriter := TFPWriterPNG.Create; + pngWriter.Indexed := false; + pngWriter.UseAlpha := HasTransparentPixels; + writer := pngWriter; + end else + writer := nil; + + if writer<> nil then + begin + inherited SaveToFile(Filename,writer); + writer.free; + end else + inherited SaveToFile(Filename); +end; + +procedure TMemBitmap.Assign(Bitmap: TBitmap); +begin + SetSize(Bitmap.width,bitmap.height); + GetImage(Bitmap.Canvas,0,0,clBlack); +end; + +procedure TMemBitmap.Assign(MemBitmap: TMemBitmap); +begin + SetSize(MemBitmap.Width,MemBitmap.height); + PutImage(0,0,MemBitmap,dmSet); +end; + +destructor TMemBitmap.Destroy; +begin + freemem(FData); + FBitmap.Free; + inherited Destroy; +end; + +procedure TMemBitmap.SetPixel(x, y: integer; c: TMemPixel); +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + (Scanline[y]+x)^ := c; +end; + +procedure TMemBitmap.SetPixel(x, y: integer; c: TColor); +var p: PByte; +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + p := PByte(Scanline[y]+x); + p^ := c shr 16; inc(p); + p^ := c shr 8; inc(p); + p^ := c; inc(p); + p^ := 255; +end; + +procedure TMemBitmap.DrawPixel(x, y: integer; c: TMemPixel); +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + DrawPixel(Scanline[y]+x, c); +end; + +procedure TMemBitmap.AlphaPixel(x, y: integer; alpha: byte); +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + (Scanline[y]+x)^.alpha := alpha; +end; + +class procedure TMemBitmap.DrawPixel(dest: PMemPixel; c: TMemPixel); +var p: PByte; a1f, a2f, a12, a12m: cardinal; +begin + if c.alpha = 0 then exit; + + a12 := 65025 - (255-dest^.alpha)*(255-c.alpha); + a12m := a12 shr 1; + + a1f := dest^.alpha*(255-c.alpha); + a2f := c.alpha* 255; + + p := PByte(dest); + p^ := (dest^.blue*a1f + c.blue*a2f + a12m ) div a12; inc(p); + p^ := (dest^.green*a1f + c.green*a2f + a12m ) div a12; inc(p); + p^ := (dest^.red*a1f + c.red*a2f + a12m ) div a12; inc(p); + p^ := (a12 + a12 shr 7) shr 8; +end; +{var p: PByte; a1,r1,g1,b1, a2,r2,g2,b2, a1f, a2f, a12: single; +begin + if c.alpha = 0 then exit; + + a2 := c.alpha/255; + r2 := c.red/255; + g2 := c.green/255; + b2 := c.blue/255; + + a1 := dest^.alpha/255; + r1 := dest^.red/255; + g1 := dest^.green/255; + b1 := dest^.blue/255; + + a12 := 1 - (1-a1)*(1-a2); + + a1f := a1*(1-a2)/a12* 255; + a2f := a2/a12* 255; + + p := PByte(dest); + p^ := round( b1*a1f + b2*a2f ); inc(p); + p^ := round( g1*a1f + g2*a2f ); inc(p); + p^ := round( r1*a1f + r2*a2f ); inc(p); + p^ := round( a12 * 255); +end;} + +function TMemBitmap.GetPixel(x, y: integer): TMemPixel; +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then result := MemPixelTransparent else + result := (Scanline[y]+x)^; +end; + +function TMemBitmap.GetPixelCycle(x, y: integer): TMemPixel; +begin + if (Width=0) or (Height=0) then result := MemPixelTransparent else + begin + x := x mod Width; + if x<0 then inc(x,width); + y := y mod Height; + if y<0 then inc(y,height); + result := (Scanline[y]+x)^; + end; +end; + +procedure TMemBitmap.AlphaHorizLine(x, y, x2: integer; alpha: byte); +var temp: integer; +begin + if (x2= width) or (x2 < 0) then exit; + if x < 0 then x := 0; + if x2 >= width then x2 := width-1; + AlphaFill(alpha, y*width+x, x2-x+1); +end; + +procedure TMemBitmap.InvalidateBitmap; +begin + FRebuildBmp := True; +end; + +procedure TMemBitmap.RebuildBitmap; +var RawImage : TRawImage; ABitmap, AMask: HBitmap; +begin + if FBitmap = nil then FBitmap := TBitmap.Create; + + if Empty then + begin + FBitmap.Height := 0; + FBitmap.Width := 0; + end else + begin + RawImage.Init; + RawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(Width,Height); + RawImage.Data:= PByte(data); + RawImage.DataSize:= nbPixels*sizeof(TMemPixel); + RawImage_CreateBitmaps(RawImage, ABitmap,AMask,False); + FBitmap.Handle := ABitmap; + FBitmap.MaskHandle := AMask; + end; +end; + +function TMemBitmap.GetBitmap: TBitmap; +begin + if FRebuildBmp or (FBitmap = nil) then + begin + RebuildBitmap; + FRebuildBmp := false; + end; + result := FBitmap; +end; + +procedure TMemBitmap.Init; +begin + FRefCount := 1; + FBitmap := nil; + FData := nil; + FWidth := 0; + FHeight := 0; +end; + +procedure TMemBitmap.SetInternalColor(x, y: integer; const Value: TFPColor); +var p: PByte; +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + p := PByte(Scanline[y]+x); + p^ := Value.blue shr 8; inc(p); + p^ := Value.green shr 8; inc(p); + p^ := Value.red shr 8; inc(p); + p^ := Value.alpha shr 8; +end; + +function TMemBitmap.GetInternalColor(x, y: integer): TFPColor; +var p: PByte; v: byte; +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + p := PByte(Scanline[y]+x); + v := p^; result.blue := v shl 8+v; inc(p); + v := p^; result.green := v shl 8+v; inc(p); + v := p^; result.red := v shl 8+v; inc(p); + v := p^; result.alpha := v shl 8+v; +end; + +procedure TMemBitmap.SetInternalPixel(x, y: integer; Value: integer); +var p: PByte; c: TFPColor; +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + c := Palette.Color[Value]; + p := PByte(Scanline[y]+x); + p^ := c.blue shr 8; inc(p); + p^ := c.green shr 8; inc(p); + p^ := c.red shr 8; inc(p); + p^ := c.alpha shr 8; +end; + +function TMemBitmap.GetInternalPixel(x, y: integer): integer; +var p: PByte; v: byte; c: TFPColor; +begin + if (x<0) or (y<0) or (x>=width) or (y>=height) then exit; + p := PByte(Scanline[y]+x); + v := p^; c.blue := v shl 8+v; inc(p); + v := p^; c.green := v shl 8+v; inc(p); + v := p^; c.red := v shl 8+v; inc(p); + v := p^; c.alpha := v shl 8+v; + result := palette.IndexOf(c); +end; + +function TMemBitmap.NewReference: TMemBitmap; +begin + Inc(FRefCount); + result := self; +end; + +procedure TMemBitmap.FreeReference; +begin + if self=nil then exit; + + if FRefCount > 0 then + begin + Dec(FRefCount); + if FRefCount = 0 then + begin + self.Destroy; + end; + end; +end; + +function TMemBitmap.GetUnique: TMemBitmap; +begin + if FRefCount > 1 then + begin + Dec(FRefCount); + result := self.Duplicate; + end else + result := self; +end; + +procedure TMemBitmap.Draw(ACanvas: TCanvas; x, y: integer); +begin + if self=nil then exit; + ACanvas.Draw(x,y,Bitmap); +end; + +procedure TMemBitmap.Draw(ACanvas: TCanvas; Rect: TRect); +begin + if self=nil then exit; + ACanvas.StretchDraw(Rect,Bitmap); +end; + +procedure TMemBitmap.DrawHorizLine(x, y, x2: integer; c: TMemPixel); +var temp: integer; +begin + if (x2= width) or (x2 < 0) then exit; + if x < 0 then x := 0; + if x2 >= width then x2 := width-1; + DrawPixels(c, y*width+x, x2-x+1); +end; + +procedure TMemBitmap.SetHorizLine(x, y, x2: integer; c: TMemPixel); +var temp: integer; +begin + if (x2= width) or (x2 < 0) then exit; + if x < 0 then x := 0; + if x2 >= width then x2 := width-1; + Fill(c, y*width+x, x2-x+1); +end; + +procedure TMemBitmap.SetVertLine(x, y, y2: integer; c: TMemPixel); +var temp,n: integer; p: PMemPixel; +begin + if (y2= height) or (y2 < 0) or (x < 0) or (x >= width) then exit; + if y < 0 then y := 0; + if y2 >= height then y2 := height-1; + p := scanline[y]+x; + for n := y2-y downto 0 do + begin + p^ := c; + inc(p,width); + end; +end; + +procedure TMemBitmap.DrawVertLine(x, y, y2: integer; c: TMemPixel); +var temp,n: integer; p: PMemPixel; +begin + if (y2= height) or (y2 < 0) or (x < 0) or (x >= width) then exit; + if y < 0 then y := 0; + if y2 >= height then y2 := height-1; + p := scanline[y]+x; + for n := y2-y downto 0 do + begin + DrawPixel(p,c); + inc(p,width); + end; +end; + +procedure TMemBitmap.AlphaVertLine(x, y, y2: integer; alpha: byte); +var temp,n: integer; p: PMemPixel; +begin + if (y2= height) or (y2 < 0) or (x < 0) or (x >= width) then exit; + if y < 0 then y := 0; + if y2 >= height then y2 := height-1; + p := scanline[y]+x; + for n := y2-y downto 0 do + begin + p^.alpha := alpha; + inc(p,width); + end; +end; + +procedure TMemBitmap.Rectangle(x, y, x2, y2: integer; c: TMemPixel; + mode: TDrawMode); +var temp: integer; +begin + if (x>x2) then begin temp := x; x := x2; x2 := temp; end; + if (y>y2) then begin temp := y; y := y2; y2 := temp; end; + if (x2-x<=1) or (y2-y<=1) then exit; + case mode of + dmDrawWithTransparency: + begin + DrawHorizLine(x,y,x2-1, c); + DrawHorizLine(x,y2-1,x2-1, c); + if y2-y > 2 then + begin + DrawVertLine(x,y+1,y2-2, c); + DrawVertLine(x2-1,y+1,y2-2, c); + end; + end; + dmSet: + begin + SetHorizLine(x,y,x2-1, c); + SetHorizLine(x,y2-1,x2-1, c); + if y2-y > 2 then + begin + SetVertLine(x,y+1,y2-2, c); + SetVertLine(x2-1,y+1,y2-2, c); + end; + end; + dmSetExceptTransparent: if (c.alpha <> 0) then Rectangle(x,y,x2,y2,c,dmSet); + end; +end; + +procedure TMemBitmap.Rectangle(x, y, x2, y2: integer; c: TColor); +begin + Rectangle(x,y,x2,y2,MemPixel(c),dmSet); +end; + +procedure TMemBitmap.FillRect(x, y, x2, y2: integer; c: TMemPixel; + mode: TDrawMode); +var temp,yb: integer; +begin + if (x>x2) then begin temp := x; x := x2; x2 := temp; end; + if (y>y2) then begin temp := y; y := y2; y2 := temp; end; + if (x2-x<=0) or (y2-y<=0) then exit; + case mode of + dmDrawWithTransparency: + for yb := y to y2-1 do + DrawHorizLine(x,yb,x2-1, c); + dmSet: + for yb := y to y2-1 do + SetHorizLine(x,yb,x2-1, c); + dmSetExceptTransparent: if (c.alpha <> 0) then FillRect(x,y,x2,y2,c,dmSet); + end; +end; + +procedure TMemBitmap.FillRect(x, y, x2, y2: integer; c: TColor); +begin + FillRect(x,y,x2,y2,MemPixel(c),dmSet); +end; + +procedure TMemBitmap.AlphaFillRect(x, y, x2, y2: integer; alpha: byte); +var temp,yb: integer; +begin + if (x>x2) then begin temp := x; x := x2; x2 := temp; end; + if (y>y2) then begin temp := y; y := y2; y2 := temp; end; + if (x2-x<=0) or (y2-y<=0) then exit; + for yb := y to y2-1 do + AlphaHorizLine(x,yb,x2-1, alpha); +end; + +procedure TMemBitmap.Fill(c: TColor); +begin + Fill(MemPixel(c)); +end; + +procedure TMemBitmap.Fill(c: TMemPixel); +begin + Fill(c, 0, width*height); +end; + +procedure TMemBitmap.Fill(c: TMemPixel; start, count: integer); +var p: PMemPixel; +begin + if start < 0 then + begin + count += start; + start := 0; + end; + if start >= nbPixels then exit; + if start+count > nbPixels then count := nbPixels-start; + p := (Data+start); + while count > 0 do + begin + p^ := c; + inc(p); + dec(count); + end; +end; + +procedure TMemBitmap.AlphaFill(alpha: byte); +begin + AlphaFill(alpha,0,NbPixels); +end; + +procedure TMemBitmap.AlphaFill(alpha: byte; start, count: integer); +var p: PMemPixel; +begin + if start < 0 then + begin + count += start; + start := 0; + end; + if start >= nbPixels then exit; + if start+count > nbPixels then count := nbPixels-start; + p := (Data+start); + while count > 0 do + begin + p^.alpha := alpha; + inc(p); + dec(count); + end; +end; + +procedure TMemBitmap.ReplaceColor(before, after: TColor); +const colorMask = $00FFFFFF; +var p: PLongWord; + n: integer; + beforeBGR, afterBGR: LongWord; +begin + beforeBGR := (before and $FF shl 16) + (before and $FF00) + (before shr 16 and $FF); + afterBGR := (after and $FF shl 16) + (after and $FF00) + (after shr 16 and $FF); + p := PLongWord(Data); + for n := NbPixels-1 downto 0 do + begin + if p^ and colorMask = beforeBGR then + p^ := (p^ and not ColorMask) or afterBGR; + inc(p); + end; +end; + +procedure TMemBitmap.ReplaceColor(before, after: TMemPixel); +var p: PMemPixel; + n: integer; +begin + p := Data; + for n := NbPixels-1 downto 0 do + begin + if p^ = before then p^ := after; + inc(p); + end; +end; + +procedure TMemBitmap.DrawPixels(c: TMemPixel; start, count: integer); +var p: PMemPixel; +begin + if c.alpha = 0 then exit; + + if start < 0 then + begin + count += start; + start := 0; + end; + if start >= nbPixels then exit; + if start+count > nbPixels then count := nbPixels-start; + p := Data+start; + while count > 0 do + begin + DrawPixel(p,c); + inc(p); + dec(count); + end; +end; + +procedure TMemBitmap.PutImage(x, y: integer; bmp: TMemBitmap; mode: TDrawMode); +var x2,y2,yb,minxb,minyb,maxxb,ignoreleft,copycount,bmpwidth,i: integer; source,dest: PMemPixel; +begin + bmpwidth := bmp.width; + + if (x>= width) or (y>= height) or (x< -bmpwidth) or (y < -bmp.height) then exit; + + x2 := x+bmpwidth-1; + y2 := y+bmp.height-1; + + if y < 0 then minyb := 0 else minyb := y; + if y2 >= height then y2 := height-1; + + if x < 0 then + begin + ignoreleft := -x; + minxb := 0; + end else + begin + ignoreleft := 0; + minxb := x; + end; + if x2 >= width then maxxb := width-1 else maxxb := x2; + + copycount := maxxb-minxb+1; + + source := bmp.ScanLine[minyb-y]+ignoreleft; + dest := Scanline[minyb]+minxb; + + case mode of + dmSet: begin + copycount *= sizeof(TMemPixel); + for yb := minyb to y2 do + begin + move(source^,dest^, copycount); + inc(source, bmpwidth); + inc(dest, width); + end; + end; + dmSetExceptTransparent: + for yb := minyb to y2 do + begin + for i := copycount-1 downto 0 do + begin + if source^.alpha = 255 then dest^ := source^; + inc(dest); + inc(source); + end; + inc(source, bmpwidth-copycount); + inc(dest, width-copycount); + end; + dmDrawWithTransparency: + for yb := minyb to y2 do + begin + for i := copycount-1 downto 0 do + begin + DrawPixel(dest,source^); + inc(dest); + inc(source); + end; + inc(source, bmpwidth-copycount); + inc(dest, width-copycount); + end; + end; +end; + +function TMemBitmap.Duplicate: TMemBitmap; +begin + result := TMemBitmap.Create(width,height); + result.PutImage(0,0,self,dmSet); +end; + +procedure TMemBitmap.GetImage(Canvas: TCanvas; x, y: integer; defaultColor: TColor); +var bmp: TBitmap; xb,yb: integer; + source: PByte; dest: PByte; + {$IFDEF gtkbugfix} + Ofs: TPoint; + dcSource,dcDest : TGtkDeviceContext; + {$ENDIF} + rectSource,rectDest: TRect; + + function ClipRect: boolean; + var delta: integer; + begin + if rectSource.Left < 0 then + begin + delta := -rectSource.left; + inc(rectSource.Left,delta); + inc(rectDest.Left,delta); + end; + if rectSource.Top < 0 then + begin + delta := -rectSource.Top; + inc(rectSource.Top,delta); + inc(rectDest.Top,delta); + end; + if rectSource.Right > Canvas.Width then + begin + delta := rectSource.Right-Canvas.Width; + dec(rectSource.Right,delta); + dec(rectDest.Right,delta); + end; + if rectSource.Bottom > Canvas.Height then + begin + delta := rectSource.Bottom-Canvas.Height; + dec(rectSource.Bottom,delta); + dec(rectDest.Bottom,delta); + end; + result := (rectSource.Right>rectSource.Left) and + (rectSource.Bottom>rectSource.Top) and + (rectDest.Right>rectDest.Left) and + (rectDest.Bottom>rectDest.Top); + end; + +begin + bmp := TBitmap.Create; + bmp.PixelFormat:= pf24bit; + bmp.width := width; + bmp.height := height; + bmp.Canvas.Brush.Color := defaultColor; + bmp.Canvas.FillRect(0,0,width,height); + rectSource := classes.rect(x,y,x+width,y+height); + rectDest := classes.rect(0,0,width,height); + + {$IFDEF gtkbugfix} + dcDest := TGtkDeviceContext(bmp.Canvas.handle); + dcSource := TGtkDeviceContext(Canvas.Handle); + if (dcSource <> nil) and (dcDest <> nil) then + begin + Ofs := dcSource.Offset; + rectSource.Left += Ofs.X; + rectSource.Top += Ofs.Y; + rectSource.Right += Ofs.X; + rectSource.Bottom += Ofs.Y; + if ClipRect then + begin + if (dcDest.Drawable<>nil) and (dcDest.GC <> nil) and (dcSource.Drawable <> nil) then + gdk_window_copy_area(dcDest.Drawable, dcDest.GC, rectDest.Left,rectDest.top, dcSource.Drawable,rectSource.Left,rectSource.Top, rectSource.Right-rectSource.Left,rectSource.Bottom-rectSource.Top); + end; + end; + {$ELSE} + if ClipRect then + bmp.Canvas.CopyRect(rectDest,Canvas,rectSource); + {$ENDIF} + + if bmp.RawImage.Description.BitsPerPixel = 32 then + begin + for yb := 0 to height-1 do + begin + if bmp.rawImage.Description.LineOrder = riloTopToBottom then + source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(yb) else + source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(height-1-yb); + dest := pbyte(ScanLine[yb]); + for xb := 0 to width-1 do + begin + PWord(dest)^ := PWord(source)^; + inc(dest,2); inc(source, 2); + dest^ := source ^; + inc(dest); inc(source, 2); + dest^:= 255; + inc(dest); + end; + end; + end else + if bmp.RawImage.Description.BitsPerPixel = 24 then + begin + for yb := 0 to height-1 do + begin + if bmp.rawImage.Description.LineOrder = riloTopToBottom then + source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(yb) else + source := bmp.rawImage.Data+ bmp.rawImage.Description.BytesPerLine*cardinal(height-1-yb); + dest := pbyte(ScanLine[yb]); + for xb := 0 to width-1 do + begin + PWord(dest)^ := PWord(source)^; + inc(dest,2); inc(source, 2); + dest^ := source ^; + inc(dest); inc(source); + dest^:= 255; + inc(dest); + end; + end; + end; + + bmp.Free; +end; + +function TMemBitmap.ResampleSmaller(newWidth, newHeight: integer + ): TMemBitmap; +const maxvalue= 255; +var + x_dest,y_dest : integer; + inc_x_src, mod_x_src, acc_x_src, inc_y_src, mod_y_src, acc_y_src : integer; + x_src,y_src,prev_x_src,prev_y_src: integer; + x_src2,y_src2: integer; + + xb,yb : integer; + alpha,v1,v2,v3,v4: double; + nb: integer; + c: TMemPixel; + pdest,psrc: PMemPixel; +begin + result := TMemBitmap.Create(NewWidth, NewHeight); + if (newWidth = 0) or (newHeight = 0) or (Width= 0) or (Height = 0) then exit; + inc_x_src := width div newWidth; + mod_x_src := width mod newWidth; + inc_y_src := height div newHeight; + mod_y_src := height mod newHeight; + + y_src := 0; + acc_y_src := 0; + PDest := result.ScanLine[0]; + for y_dest := 0 to newHeight-1 do + begin + prev_y_src := y_src; + inc(y_src,inc_y_src); + inc(acc_y_src,mod_y_src); + if acc_y_src >= newHeight then + begin + dec(acc_y_src,newHeight); + inc(y_src); + end; + + x_src := 0; + acc_x_src := 0; + for x_dest := 0 to newWidth-1 do + begin + prev_x_src := x_src; + inc(x_src,inc_x_src); + inc(acc_x_src,mod_x_src); + if acc_x_src >= newWidth then + begin + dec(acc_x_src,newWidth); + inc(x_src); + end; + + if x_src > prev_x_src then x_src2 := x_src-1 else x_src2 := x_src; + if y_src > prev_y_src then y_src2 := y_src-1 else y_src2 := y_src; + + v1 := 0; + v2 := 0; + v3 := 0; + v4 := 0; + nb := 0; + for yb := prev_y_src to y_src2 do + begin + PSrc := Scanline[yb]+prev_x_src; + for xb := prev_x_src to x_src2 do + begin + c := PSrc^; inc(PSrc); + alpha := c.alpha/maxvalue; + v1 += c.red*alpha; + v2 += c.green*alpha; + v3 += c.blue*alpha; + v4 += alpha; + inc(nb); + end; + end; + + if (v4<>0) and (nb <> 0) then + begin + c.red := round(v1/v4); + c.green := round(v2/v4); + c.blue := round(v3/v4); + c.alpha := round(v4/nb*maxvalue); + end else + begin + c.alpha := 0; + c.red := 0; + c.green := 0; + c.blue := 0; + end; + PDest^ := c; + inc(PDest); + end; + end; +end; + +function TMemBitmap.GetHasTransparentPixels: boolean; +var p: PMemPixel; n: integer; +begin + p := Data; + for n := NbPixels-1 downto 0 do + begin + if p^.alpha <> 255 then + begin + result := true; + exit; + end; + inc(p); + end; + result := false; +end; + +function TMemBitmap.GetAverageColor: TColor; +var n: integer; p: PMemPixel; + r,g,b,sum: double; + alpha: double; +begin + sum := 0; + r := 0; + g := 0; + b := 0; + p := Data; + for n := NbPixels-1 downto 0 do + begin + alpha := p^.alpha/255; + sum += alpha; + r += p^.red*alpha; + g += p^.green*alpha; + b += p^.blue*alpha; + end; + if sum=0 then result := clNone else + result := round(r/sum) + round(g/sum) shl 8 + round(b/sum) shl 16; +end; + +function TMemBitmap.ResampleLarger(newWidth, newHeight: integer): TMemBitmap; +const maxvalue = 255; +var + x_src,y_src : integer; + inc_x_dest, mod_x_dest, acc_x_dest, inc_y_dest, mod_y_dest, acc_y_dest : integer; + x_dest,y_dest,prev_x_dest,prev_y_dest: integer; + x_dest2,y_dest2,{x_src2,}y_src2: integer; + + xb,yb : integer; + cUpLeft,cUpRight,cLowLeft,cLowRight: TMemPixel; + factX,factY,factAddX,factAddY,factCorrX,factCorrY: single; + factUpLeft,factUpRight,factLowLeft,factLowRight: single; + factUpLeftAlpha,factUpRightAlpha,factLowLeftAlpha,factLowRightAlpha: single; + cur: TMemPixel; + alphaUpLeft, alphaUpRight, alphaLowLeft, alphaLowRight: single; + sumFactAlpha: single; + PDest,PSrc,PSrc2 : PMemPixel; + + temp: TMemBitmap; + +begin + result := TMemBitmap.Create(NewWidth, NewHeight); + if (newWidth = 0) or (newHeight = 0) then exit; + + if (width=1) and (height=1) then + begin + result.Fill(GetPixel(0,0)); + exit; + end else + if width=1 then + begin + temp := TMemBitmap.Create(2,Height); + temp.PutImage(0,0,self,dmSet); + temp.PutImage(1,0,self,dmSet); + result := temp.ResampleLarger(newWidth,newHeight); + temp.Free; + exit; + end else + if height=1 then + begin + temp := TMemBitmap.Create(Width,2); + temp.PutImage(0,0,self,dmSet); + temp.PutImage(0,1,self,dmSet); + result := temp.ResampleLarger(newWidth,newHeight); + temp.Free; + exit; + end; + + inc_x_dest := newwidth div (Width-1); + mod_x_dest := newwidth mod (Width-1); + inc_y_dest := newheight div (Height-1); + mod_y_dest := newheight mod (Height-1); + + y_dest := 0; + acc_y_dest := 0; + for y_src := 0 to Height-2 do + begin + prev_y_dest := y_dest; + inc(y_dest,inc_y_dest); + inc(acc_y_dest,mod_y_dest); + if acc_y_dest >= Height then + begin + dec(acc_y_dest,Height); + inc(y_dest); + end; + + y_src2 := y_src+1; + PSrc := Scanline[y_src]; + PSrc2 := Scanline[y_src2]; + cUpLeft := PSrc^; inc(PSrc); + cLowLeft := PSrc2^; inc(PSrc2); + + x_dest := 0; + acc_x_dest := 0; + for x_src := 0 to Width-2 do + begin + prev_x_dest := x_dest; + inc(x_dest,inc_x_dest); + inc(acc_x_dest,mod_x_dest); + if acc_x_dest >= Width then + begin + dec(acc_x_dest,Width); + inc(x_dest); + end; + + //x_src2 := x_src+1; + if x_src < width-2 then + begin + x_dest2 := x_dest-1; + factAddX := 1/(x_dest2-prev_x_dest+1); + end else + begin + x_dest2 := newWidth-1; + factAddX := 1/(x_dest2-prev_x_dest); + end; + if y_src < height-2 then + begin + y_dest2 := y_dest-1; + factAddY := 1/(y_dest2-prev_y_dest+1); + end else + begin + y_dest2 := newHeight-1; + factAddY := 1/(y_dest2-prev_y_dest); + end; + + cUpRight := PSrc^; inc(PSrc); + cLowRight := PSrc2^; inc(PSrc2); + + factY := 0; + for yb := prev_y_dest to y_dest2 do + begin + factX := 0; + PDest := result.scanline[yb]+prev_x_dest; + for xb := prev_x_dest to x_dest2 do + begin + factCorrX := 0.5-cos(factX*Pi)/2; + factCorrY := 0.5-cos(factY*Pi)/2; + + alphaUpLeft := cUpLeft.alpha/maxvalue; + alphaUpRight := cUpRight.alpha/maxvalue; + alphaLowLeft := cLowLeft.alpha/maxvalue; + alphaLowRight := cLowRight.alpha/maxvalue; + + factUpLeft := (1-factCorrX)*(1-factCorrY); + factUpRight := factCorrX*(1-factCorrY); + factLowLeft := (1-factCorrX)*factCorrY; + factLowRight := factCorrX*factCorrY; + + factUpLeftAlpha := factUpLeft*alphaUpLeft; + factUpRightAlpha := factUpRight*alphaUpRight; + factLowLeftAlpha := factLowLeft*alphaLowLeft; + factLowRightAlpha := factLowRight*alphaLowRight; + + sumFactAlpha := factUpLeftAlpha+factUpRightAlpha+factLowLeftAlpha+factLowRightAlpha; + if sumFactAlpha=0 then + begin + cur.alpha := 0; + cur.red := 0; + cur.green := 0; + cur.blue := 0; + end else + begin + cur.red := round((factUpLeftAlpha*cUpLeft.red + factUpRightAlpha*cUpRight.red + + factLowLeftAlpha*cLowLeft.red + factLowRightAlpha*cLowRight.red)/sumFactAlpha); + cur.green := round((factUpLeftAlpha*cUpLeft.green + factUpRightAlpha*cUpRight.green + + factLowLeftAlpha*cLowLeft.green + factLowRightAlpha*cLowRight.green)/sumFactAlpha); + cur.blue := round((factUpLeftAlpha*cUpLeft.blue + factUpRightAlpha*cUpRight.blue + + factLowLeftAlpha*cLowLeft.blue + factLowRightAlpha*cLowRight.blue)/sumFactAlpha); + cur.alpha := round(sumFactAlpha*maxvalue); + end; + PDest^ := cur; inc(PDest); + factX := factX + factAddX; + end; + factY := factY+factAddY; + end; + cUpLeft := cUpRight; + cLowLeft := cLowRight; + end; + end; +end; + +function TMemBitmap.Resample(NewWidth, NewHeight: Integer): TMemBitmap; +var temp,newtemp: TMemBitmap; +begin + if (NewWidth = Width) and (NewHeight = Height) then + result := Duplicate else + if (NewWidth >= Width) and (NewHeight >= Height) then + result := ResampleLarger(NewWidth,NewHeight) else + if (NewWidth <= Width) and (NewHeight <= Height) then + result := ResampleSmaller(NewWidth,NewHeight) else + begin + temp := self; + + if NewWidth < Width then + begin + newtemp := temp.ResampleSmaller(NewWidth,temp.Height); + if (temp<>self) then temp.free; + temp := newtemp; + end; + + if NewHeight < Height then + begin + newtemp := temp.ResampleSmaller(temp.Width,NewHeight); + if (temp<>self) then temp.free; + temp := newtemp; + end; + + if NewWidth > Width then + begin + newtemp := temp.ResampleLarger(NewWidth,temp.Height); + if (temp<>self) then temp.free; + temp := newtemp; + end; + + if NewHeight > Height then + begin + newtemp := temp.ResampleLarger(temp.Width,NewHeight); + if (temp<>self) then temp.free; + temp := newtemp; + end; + + if temp<>self then result := temp else + result := self.Duplicate; + end; +end; + +procedure TMemBitmap.VerticalFlip; +var yb: integer; + line: PMemPixel; + linesize: integer; +begin + if Data= nil then exit; + + linesize := Width*sizeof(TMemPixel); + line := nil; + getmem(line, linesize); + for yb := 0 to (Height div 2)-1 do + begin + move(Scanline[yb]^, line^, linesize); + move(Scanline[Height-1-yb]^, Scanline[yb]^, linesize); + move(line^, Scanline[Height-1-yb]^, linesize); + end; + freemem(line); +end; + +procedure TMemBitmap.DrawPartial(Arect: TRect; Canvas: TCanvas; x,y: integer); +var partial: TMemBitmap; + copywidth,copyheight,widthleft,heightleft,curxin,curyin,xdest,ydest,tx,ty: integer; +begin + tx := ARect.Right-ARect.Left; + ty := ARect.Bottom-ARect.Top; + + if ARect.Left >= Width then ARect.Left := ARect.Left mod Width else + if ARect.Left < 0 then ARect.Left := Width - ((-ARect.Left) mod Width); + ARect.Right := ARect.Left+tx; + + if ARect.Top >= Height then ARect.Top := ARect.Top mod Height else + if ARect.Top < 0 then ARect.Top := Height - ((-ARect.Top) mod Height); + ARect.Bottom := ARect.Top+ty; + + if (ARect.Left = 0) and (ARect.Top = 0) and (ARect.Right = Width) and (ARect.Bottom = Height) then + begin + Draw(Canvas,x,y); + exit; + end; + + partial := TMemBitmap.Create(tx,ty); + heightleft := partial.height; + curyin := ARect.Top; + ydest := -ARect.Top; + while heightleft > 0 do + begin + if curyin + heightleft > height then copyheight := height-curyin else + copyheight := heightleft; + + widthleft := partial.width; + curxin := ARect.Left; + xdest := -ARect.Left; + while widthleft > 0 do + begin + if curxin + widthleft > width then copywidth := width-curxin else + copywidth := widthleft; + + partial.PutImage(xdest,ydest,self,dmSet); + + curxin := 0; + dec(widthleft, copywidth); + inc(xdest,copywidth); + end; + curyin := 0; + dec(heightleft, copyheight); + inc(ydest,copyheight); + end; + partial.Draw(Canvas,x,y); + partial.Free; +end; + +end. \ No newline at end of file From a8dd48fde1ca6d0c51fd72931d4663ab5022f45a Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 14:16:36 +0800 Subject: [PATCH 0050/2794] simplelogger, overload writelog_e with parameter exception --- .../SimpleException/USimpleException.pas | 3 +-- baseunits/SimpleException/USimpleLogger.pas | 23 +++++++++++++++++-- baseunits/uData.pas | 11 +++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/baseunits/SimpleException/USimpleException.pas b/baseunits/SimpleException/USimpleException.pas index 8431079e6..dba8b6902 100644 --- a/baseunits/SimpleException/USimpleException.pas +++ b/baseunits/SimpleException/USimpleException.pas @@ -210,6 +210,7 @@ function TSimpleException.OSVer: String; else Result := 'Windows'; end; + Initialize(wdir); GetWindowsDirectory(PChar(wdir), MAX_PATH); if DirectoryExists(wdir + '\SysWOW64') then Result := Result + ' 64-bit'; @@ -298,8 +299,6 @@ function TSimpleException.ExceptionHeaderMessage: string; end; end; - - procedure TSimpleException.CreateExceptionReport; begin try diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index 05b11ede4..cd644558c 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -41,7 +41,8 @@ interface _LOG_SYMBOL = 'EWIDV'; procedure SetLogFile(const LogFileName: String); - procedure WriteLog_E(const msg: String); + procedure WriteLog_E(const msg: String); overload; + procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject = nil); overload; procedure Writelog_W(const msg: String); procedure Writelog_I(const msg: String); procedure Writelog_D(const msg: String); @@ -115,6 +116,24 @@ procedure WriteLog_E(const msg: String); WriteLog(msg, ERROR); end; +procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); +var + s: string; +begin + s := ''; + if Assigned(Sender) then + s += LineEnding + + 'Sender Class : ' + Sender.ClassName; + if Assigned(Exc) then + begin + s += LineEnding + + 'Exception Class : ' + Exc.ClassName + LineEnding + + 'Exception Message: ' + Exc.Message; + end; + s += GetStackTraceInfo; + WriteLog_E(msg + s); +end; + procedure Writelog_W(const msg: String); begin WriteLog(msg, WARNING); @@ -145,7 +164,7 @@ function SimpleBackTraceStr(const Addr: Pointer): String; if _HAS_DEBUG_LINE then begin try - GetLineInfo(PtrUInt(Addr), func, Source, line); + GetLineInfo({%H-}PtrUInt(Addr), func, Source, line); if func <> '' then Result := Result + ' ' + func; if Source <> '' then diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b056aa34a..d0d9bcc31 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -207,13 +207,8 @@ TMangaInformation = class(TObject) implementation uses - Dialogs, - fpJSON, JSONParser, IniFiles, - jsHTMLUtil, - FastHTMLParser, HTMLUtil, - SynaCode, - frmMain, - uMisc; + Dialogs, fpJSON, JSONParser, IniFiles, jsHTMLUtil, FastHTMLParser, HTMLUtil, + SynaCode, uMisc, frmMain; function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; @@ -1386,7 +1381,7 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; end; except on E: Exception do - MainForm.ExceptionHandler(Self, E); + WriteLog_E('TDataProcess.Filter.Error!', E, Self); end; regx.Free; end; From 40128cc34f0eb8644c77a47e0815112b86efa976 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 14:19:00 +0800 Subject: [PATCH 0051/2794] simpleexception, clean up unused unit --- baseunits/SimpleException/USimpleException.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/SimpleException/USimpleException.pas b/baseunits/SimpleException/USimpleException.pas index dba8b6902..56d2133e2 100644 --- a/baseunits/SimpleException/USimpleException.pas +++ b/baseunits/SimpleException/USimpleException.pas @@ -26,7 +26,7 @@ interface uses Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, LCLVersion, - DbgInfoReader, USimpleExceptionForm, USimpleLogger, + USimpleExceptionForm, USimpleLogger, {$IFDEF WINDOWS} windows, win32proc, {$ENDIF} From 31e5faeec3a519bd78fbd4507e580752faf82dd3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 14:24:31 +0800 Subject: [PATCH 0052/2794] ubaseunit, fill empty result function --- baseunits/uBaseUnit.pas | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dc8cabbb6..d2d84e019 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -836,7 +836,7 @@ function CorrectFilePath(const APath: String): String; function CorrectURL(const URL: String): String; procedure CheckPath(const S: String); -function GetMangaSiteID(const Name: String): Cardinal; +function GetMangaSiteID(const Name: String): Integer; function GetMangaSiteName(const ID: Cardinal): String; function GetMangaSiteRoot(const Website: String): String; overload; function GetMangaSiteRoot(const MangaID: Cardinal): String; overload; @@ -1213,10 +1213,11 @@ procedure CheckPath(const S: String); end; end; -function GetMangaSiteID(const Name: String): Cardinal; +function GetMangaSiteID(const Name: String): Integer; var i: Integer; begin + Result := -1; for i := Low(WebsiteRoots) to High(WebsiteRoots) do if Name = WebsiteRoots[i, 0] then Exit(i); @@ -1231,6 +1232,7 @@ function GetMangaSiteRoot(const Website : String) : String; var i: Integer; begin + Result := ''; for i := Low(WebsiteRoots) to High(WebsiteRoots) do if Website = WebsiteRoots[i, 0] then Exit(WebsiteRoots[i, 1]); @@ -1628,6 +1630,7 @@ function StringsToArray(const S: TStrings): TArrayOfString; var i: Integer; begin + SetLength(Result, 0); if not Assigned(S) then Exit; if S.Count = 0 then Exit; SetLength(Result, S.Count); @@ -3786,10 +3789,10 @@ function RunExternalProcess(CommandLine: String; ShowWind: Boolean; function HeaderByName(const AHeaders: TStrings; const AHeaderName: String): String; var - i, p: Cardinal; + i, p: Integer; hn: String; - begin + Result := ''; if AHeaders.Count < 1 then Exit; hn := AHeaderName; From dc1a4a41773d21b28267b075a7be93fecdb38bf8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 14:53:06 +0800 Subject: [PATCH 0053/2794] simplelogger, small changes --- baseunits/SimpleException/USimpleLogger.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index cd644558c..de4495637 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -130,7 +130,7 @@ procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); 'Exception Class : ' + Exc.ClassName + LineEnding + 'Exception Message: ' + Exc.Message; end; - s += GetStackTraceInfo; + s += LineEnding + GetStackTraceInfo; WriteLog_E(msg + s); end; From 21c486a40a57d29e12713d06ef988e7a9737eb8c Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 15:07:05 +0800 Subject: [PATCH 0054/2794] tdbdataprocess, clean up --- baseunits/uData.pas | 79 ++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d0d9bcc31..79967d4b1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -464,17 +464,13 @@ destructor TDBDataProcess.Destroy; try if FConn.Connected then begin - try - FTrans.CommitRetaining; - except - FTrans.RollbackRetaining; - end; + Commit; VacuumTable; FConn.Connected := False; end; except on E: Exception do - WriteLog_E('TDBDataProcess.Destroy,Error: '+E.Message+LineEnding+GetStackTraceInfo); + WriteLog_E('TDBDataProcess.Destroy.Error!', E, Self); end; FSitesList.Free; FQuery.Free; @@ -520,18 +516,24 @@ function TDBDataProcess.OpenTable(const ATableName: String): Boolean; Result := False; if FConn.Connected then begin - if ATableName <> '' then - FTableName := ATableName; - if FTableName = '' then Exit; - if TableExist(FTableName) then - begin - if FQuery.Active then - FQuery.Close; - FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); - FQuery.SQL.Text := FSQLSelect; - FQuery.Open; + try + if ATableName <> '' then + FTableName := ATableName; + if FTableName = '' then Exit; + if TableExist(FTableName) then + begin + if FQuery.Active then + FQuery.Close; + FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); + FQuery.SQL.Text := FSQLSelect; + FQuery.Open; + end; + except + on E: Exception do + WriteLog_E('TDBDataProcess.OpenTable.Error!', E, Self); end; end; + Result := FQuery.Active; end; function TDBDataProcess.TableExist(const ATableName: String): Boolean; @@ -557,22 +559,15 @@ procedure TDBDataProcess.Close; begin FFiltered := False; FDataCount := 0; - try - if FConn.Connected then - begin - try - FTrans.CommitRetaining; - except - FTrans.RollbackRetaining; - end; + if FConn.Connected then + try + Commit; FConn.Connected := False; FConn.DatabaseName := ''; + except + on E: Exception do + WriteLog_E('TDBDataProcess.Close.Error!', E, Self); end; - except - on E: Exception do - WriteLog_E('TDBDataProcess.Close.Error: ' + E.Message + LineEnding + - GetStackTraceInfo); - end; end; procedure TDBDataProcess.Save; @@ -673,14 +668,10 @@ procedure TDBDataProcess.Commit; begin if FConn.Connected then try - FTrans.CommitRetaining; + FTrans.Commit; except on E: Exception do - begin - WriteLog_E('TDBDataProcess.ApplyUpdates.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); - FTrans.RollbackRetaining; - end; + WriteLog_E('TDBDataProcess.Commit.Error!', E, Self); end; end; @@ -689,21 +680,15 @@ procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); if FQuery.Active then try FQuery.ApplyUpdates; - FTrans.CommitRetaining; - if RecheckDataCount then - GetDataCount; + Commit; except on E: Exception do - begin - WriteLog_E('TDBDataProcess.ApplyUpdates.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); - FTrans.RollbackRetaining; - if FQuery.Active = False then - FQuery.Open; - if RecheckDataCount then - GetDataCount; - end; + WriteLog_E('TDBDataProcess.ApplyUpdates.Error!', E, Self); end; + if FQuery.Active = False then + FQuery.Open; + if RecheckDataCount then + GetDataCount; end; function TDBDataProcess.Search(ATitle: String): Boolean; From 1089a719c4905ec8915ea65512b1502e05912b74 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 15:09:08 +0800 Subject: [PATCH 0055/2794] tdbdataprocess, don't need to use critical section, let owner thread handle it --- baseunits/uData.pas | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 79967d4b1..03354995c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -29,7 +29,6 @@ TSQLite3Connectionx = class(TSQLite3Connection) TDBDataProcess = class private - FCSRecord: TRTLCriticalSection; FConn: TSQLite3Connectionx; FTrans: TSQLTransaction; FQuery: TSQLQuery; @@ -430,7 +429,6 @@ function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; (ParamNo < Length(DBDataProcessParams)) and (RecIndex < FDataCount) then begin - EnterCriticalsection(FCSRecord); try FQuery.RecNo := RecIndex+1; Result:= FQuery.FieldByName(DBDataProcessParams[ParamNo]).AsString; @@ -439,13 +437,11 @@ function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; WriteLog_E('TDBDataProcess.GetParam.Error: ' + E.Message + LineEnding + GetStackTraceInfo); end; - LeaveCriticalsection(FCSRecord); end; end; constructor TDBDataProcess.Create; begin - InitCriticalSection(FCSRecord); FConn := TSQLite3Connectionx.Create(nil); FTrans := TSQLTransaction.Create(nil); FQuery := TSQLQuery.Create(nil); @@ -477,7 +473,6 @@ destructor TDBDataProcess.Destroy; FTrans.Free; FConn.Free; FRegxp.Free; - DoneCriticalsection(FCSRecord); inherited Destroy; end; @@ -766,14 +761,7 @@ function TDBDataProcess.Locate(FieldIndex: Integer; Value: String): Boolean; begin Result := false; if (FQuery.Active) and (FDataCount > 0) then - begin - EnterCriticalsection(FCSRecord); - try - Result := FQuery.Locate(DBDataProcessParams[FieldIndex], Value, [loCaseInsensitive]); - finally - LeaveCriticalsection(FCSRecord); - end; - end; + Result := FQuery.Locate(DBDataProcessParams[FieldIndex], Value, [loCaseInsensitive]); end; procedure TDBDataProcess.CreateDatabase(AWebsite: string); From 355d7b138b0ff4498565414ee61a40232ab1e119 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 15:39:08 +0800 Subject: [PATCH 0056/2794] updatethread, commit data to disk every 20 record --- baseunits/uUpdateThread.pas | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 72c6cd24a..9c900dc5e 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -40,6 +40,7 @@ TUpdateMangaThread = class(TFMDThread) TUpdateMangaManagerThread = class(TFMDThread) private FStatus: String; + FCommitCount: Integer; protected procedure Execute; override; {$IFNDEF DOWNLOADER} @@ -65,6 +66,7 @@ TUpdateMangaManagerThread = class(TFMDThread) CS_threads: TCriticalSection; constructor Create; destructor Destroy; override; + procedure CheckCommit; end; resourcestring @@ -214,6 +216,7 @@ procedure TUpdateMangaThread.Execute; try Info.AddInfoToData(manager.names[workPtr], manager.links[workPtr], manager.mainDataProcess); + manager.CheckCommit; finally manager.CS_AddInfoToData.Release; end; @@ -305,6 +308,17 @@ destructor TUpdateMangaManagerThread.Destroy; inherited Destroy; end; +procedure TUpdateMangaManagerThread.CheckCommit; +begin + Inc(FCommitCount); + if FCommitCount > 19 then + begin + FCommitCount := 0; + if Assigned(mainDataProcess) then + mainDataProcess.Commit; + end; +end; + procedure TUpdateMangaManagerThread.RefreshList; begin try @@ -628,6 +642,7 @@ procedure TUpdateMangaManagerThread.Execute; //get manga info if links.Count > 0 then begin + FCommitCount := 0; if (SitesWithoutInformation(website)) or OptionUpdateListNoMangaInfo then begin @@ -652,6 +667,7 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(links.Count, CS_INFO); end; WaitForThreads; + mainDataProcess.Commit; end; if (not Terminated) or (not SitesWithSortedList(website)) then From f0f69dbfaad7f4a92f458f9c50fe3fffa631b279 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 16:25:36 +0800 Subject: [PATCH 0057/2794] mainform, vtmangalist store data record to mem --- mangadownloader/forms/frmMain.lfm | 3 +++ mangadownloader/forms/frmMain.pas | 45 +++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 045a35819..ceadf38e9 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3134,8 +3134,11 @@ object MainForm: TMainForm OnColumnDblClick = vtMangaListColumnDblClick OnDragAllowed = vtMangaListDragAllowed OnDragOver = vtMangaListDragOver + OnFreeNode = vtMangaListFreeNode OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint + OnGetNodeDataSize = vtMangaListGetNodeDataSize + OnInitNode = vtMangaListInitNode end object edSearch: TEdit Left = 3 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d14a89534..49be64f80 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -502,13 +502,18 @@ TMainForm = class(TForm) procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure vtMangaListFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); + procedure vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); procedure vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure tmBackupTimer(Sender: TObject); + procedure vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); procedure vtOptionMangaSiteSelectionFocusChanged(Sender : TBaseVirtualTree; @@ -4053,6 +4058,16 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; end; end; +procedure TMainForm.vtMangaListFreeNode(Sender: TBaseVirtualTree; + Node: PVirtualNode); +var + data: PMangaListItem; +begin + data := Sender.GetNodeData(Node); + if Assigned(data) then + Finalize(data^); +end; + procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -4094,15 +4109,21 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; HintText := s; end; +procedure TMainForm.vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TMangaListItem); +end; + procedure TMainForm.vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + data: PMangaListItem; begin - if Assigned(Node) then - begin - CellText := dataProcess.Param[Node^.Index, DATA_PARAM_NAME] + ' ' + - BracketStr(dataProcess.Param[Node^.Index, DATA_PARAM_NUMCHAPTER]) - end; + data := Sender.GetNodeData(Node); + if Assigned(data) then + CellText := data^.Text; end; procedure TMainForm.InitCheckboxes; @@ -4940,6 +4961,20 @@ procedure TMainForm.tmBackupTimer(Sender: TObject); DLManager.Backup; end; +procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + data: PMangaListItem; +begin + data := Sender.GetNodeData(Node); + if Assigned(data) then + begin + data^.Text := Format('%s (%s)', [dataProcess.Param[Node^.Index, DATA_PARAM_NAME], + dataProcess.Param[Node^.Index, DATA_PARAM_NUMCHAPTER]]); + Sender.ValidateNode(Node, False); + end; +end; + procedure TMainForm.vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); begin From 9a6e07324702cf38510100235e788586322d83a9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 16:32:56 +0800 Subject: [PATCH 0058/2794] add jdn to tmangalistitem, for faster read --- baseunits/uBaseUnit.pas | 1 + mangadownloader/forms/frmMain.pas | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d2d84e019..b76ad1be0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -722,6 +722,7 @@ interface TMangaListItem = record Text: String; + JDN: LongInt; end; PSingleItem = ^TSingleItem; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 49be64f80..d228a7e3c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4038,23 +4038,20 @@ procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + data: PMangaListItem; begin if (isExiting) or (dataProcess.DataCount = 0) then Exit; if miHighlightNewManga.Checked then begin - try - if StrToIntDef(dataProcess.Param[Node^.Index, DATA_PARAM_JDN], 0) > - (currentJDN - seOptionNewMangaTime.Value) then + data := Sender.GetNodeData(Node); + if Assigned(data) then + if data^.JDN > (currentJDN - seOptionNewMangaTime.Value) then begin TargetCanvas.Brush.Color := CL_HLBlueMarks; TargetCanvas.FillRect(CellRect); end; - except - on E: Exception do - WriteLog_E('vtMangaListBeforeCellPaint.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); - end; end; end; @@ -4971,6 +4968,7 @@ procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, begin data^.Text := Format('%s (%s)', [dataProcess.Param[Node^.Index, DATA_PARAM_NAME], dataProcess.Param[Node^.Index, DATA_PARAM_NUMCHAPTER]]); + data^.JDN := StrToIntDef(dataProcess.Param[Node^.Index, DATA_PARAM_JDN], 0); Sender.ValidateNode(Node, False); end; end; From 141d949378990926250081ddee397f4220f6f87a Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 10 Jul 2015 17:14:00 +0800 Subject: [PATCH 0059/2794] tdbdataprocess, change datatype and cleanup --- baseunits/uData.pas | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 03354995c..78b397379 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -62,7 +62,7 @@ TDBDataProcess = class const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; - function Locate(FieldIndex: Integer; Value: String): Boolean; + function LocateByLink(ALink: String): Boolean; procedure CreateDatabase(AWebsite: string = ''); procedure Close; procedure Save; @@ -187,13 +187,13 @@ TMangaInformation = class(TObject) DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; DBDataProcessParams: array [0..8] of ShortString = ('title', 'link', 'authors', 'artists', 'genres', 'status', 'summary', 'numchapter', 'jdn'); - DBDataProccesCreateParam = '(title STRING,'+ + DBDataProccesCreateParam = '(title TEXT,'+ 'link STRING NOT NULL PRIMARY KEY,'+ - 'authors STRING,'+ - 'artists STRING,'+ - 'genres STRING,'+ - 'status STRING,'+ - 'summary STRING,'+ + 'authors TEXT,'+ + 'artists TEXT,'+ + 'genres TEXT,'+ + 'status TEXT,'+ + 'summary TEXT,'+ 'numchapter INTEGER,'+ 'jdn INTEGER);'; @@ -688,9 +688,7 @@ procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); function TDBDataProcess.Search(ATitle: String): Boolean; begin - Result := False; if FConn.Connected then - begin try FQuery.Close; FQuery.SQL.Text := FSQLSelect; @@ -702,7 +700,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; on E: Exception do WriteLog_E('TDBDataProcess.Search.Error: ' + E.Message + LineEnding + GetStackTraceInfo); end; - end; + Result := FQuery.Active; end; function TDBDataProcess.CanFilter(const checkedGenres, @@ -757,11 +755,16 @@ function TDBDataProcess.Filter(const checkedGenres, end; end; -function TDBDataProcess.Locate(FieldIndex: Integer; Value: String): Boolean; +function TDBDataProcess.LocateByLink(ALink: String): Boolean; begin Result := false; - if (FQuery.Active) and (FDataCount > 0) then - Result := FQuery.Locate(DBDataProcessParams[FieldIndex], Value, [loCaseInsensitive]); + if (FQuery.Active) and (FDataCount > 0) and (ALink <> '') then + try + Result := FQuery.Locate('link', ALink, [loCaseInsensitive]); + except + on E: Exception do + WriteLog_E('TDBDataProcess.LocateByLink.Error!', E, Self); + end; end; procedure TDBDataProcess.CreateDatabase(AWebsite: string); From 7384d180de46ea891405c406988ba686b32a7ffa Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 02:54:18 +0800 Subject: [PATCH 0060/2794] various changes related to tdbdataprocess --- baseunits/uBaseUnit.pas | 8 +- baseunits/uData.pas | 281 ++++++++++++++++------------- baseunits/uGetMangaInfosThread.pas | 26 +-- baseunits/uUpdateDBThread.pas | 4 +- baseunits/uUpdateThread.pas | 33 ++-- mangadownloader/forms/frmMain.lfm | 4 +- mangadownloader/forms/frmMain.pas | 72 ++++---- 7 files changed, 231 insertions(+), 197 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b76ad1be0..f8aa21c2d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -43,7 +43,7 @@ interface EXPARAM_CHAPTER = '%CHAPTER%'; DEFAULT_EXPARAM = '"' + EXPARAM_PATH + EXPARAM_CHAPTER + '"'; - DATA_PARAM_NAME = 0; + DATA_PARAM_TITLE = 0; DATA_PARAM_LINK = 1; DATA_PARAM_AUTHORS = 2; DATA_PARAM_ARTISTS = 3; @@ -670,7 +670,7 @@ interface Genre: array [0..37] of String; Revision: Cardinal; - currentJDN: Cardinal; + currentJDN: Integer; isChangeDirectory: Boolean = False; currentWebsite: String; @@ -3335,7 +3335,7 @@ procedure QuickSortData(var merge: TStringList); begin output.Clear; GetParams(output, merge.Strings[i]); - names.Add(output.Strings[DATA_PARAM_NAME]); + names.Add(output.Strings[DATA_PARAM_TITLE]); end; QSort(0, names.Count - 1); output.Free; @@ -3387,7 +3387,7 @@ procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteL begin output.Clear; GetParams(output, merge.Strings[i]); - names.Add(output.Strings[DATA_PARAM_NAME]); + names.Add(output.Strings[DATA_PARAM_TITLE]); end; QSort(0, names.Count - 1); output.Free; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 78b397379..0a721ea68 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,8 +15,8 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, - sqlite3backup, sqldb, db, USimpleLogger, strutils, dateutils, RegExpr, - sqlite3dyn, httpsend; + sqlite3backup, sqldb, db, Sqlite3DS, USimpleLogger, strutils, dateutils, + RegExpr, sqlite3dyn, httpsend; type @@ -27,7 +27,7 @@ TSQLite3Connectionx = class(TSQLite3Connection) { TDBDataProcess } - TDBDataProcess = class + TDBDataProcess = class(TObject) private FConn: TSQLite3Connectionx; FTrans: TSQLTransaction; @@ -35,7 +35,7 @@ TDBDataProcess = class FRegxp: TRegExpr; FWebsite: String; FTableName: String; - FDataCount: Integer; + FRecordCount: Integer; FFiltered: Boolean; FFilterAllSites: Boolean; FSitesList: TStringList; @@ -43,14 +43,15 @@ TDBDataProcess = class protected procedure CreateTable; procedure VacuumTable; - procedure GetDataCount; + procedure GetRecordCount; function GetConnected: Boolean; function InternalOpen(const FilePath: String = ''): Boolean; function GetWebsiteName(RecIndex: Integer): String; - function GetParam(RecIndex, ParamNo: Integer): String; + function GetValue(RecIndex, FieldIndex: Integer): String; public constructor Create; destructor Destroy; override; + function Open(AWebsite: String = ''): Boolean; function OpenTable(const ATableName: String = ''): Boolean; function TableExist(const ATableName: String): Boolean; @@ -63,10 +64,12 @@ TDBDataProcess = class const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; function LocateByLink(ALink: String): Boolean; - procedure CreateDatabase(AWebsite: string = ''); + + procedure CreateDatabase(AWebsite: String = ''); + procedure GetFieldNames(List: TStringList); procedure Close; procedure Save; - procedure Backup(AWebsite: string); + procedure Backup(AWebsite: String); procedure Refresh(RecheckDataCount: Boolean = False); procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer); overload; @@ -78,15 +81,16 @@ TDBDataProcess = class procedure ApplyUpdates(RecheckDataCount: Boolean = False); procedure RemoveFilter; procedure Sort; + property Website: String read FWebsite write FWebsite; property TableName: String read FTableName write FTableName; property Connected: Boolean read GetConnected; - property DataCount: Integer read FDataCount; + property RecordCount: Integer read FRecordCount; property Filtered: Boolean read FFiltered; property FilterAllSites: Boolean read FFilterAllSites write FFilterAllSites; property SitesList: TStringList read FSitesList write FSitesList; property WebsiteName[RecIndex: Integer]: String read GetWebsiteName; - property Param[RecIndex, ParamNo: Integer]: String read GetParam; + property Value[RecIndex, ParamNo: Integer]: String read GetValue; end; { TDataProcess } @@ -182,6 +186,7 @@ TMangaInformation = class(TObject) var options: TStringList; + tdset: TSqlite3Dataset; const DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; @@ -357,24 +362,29 @@ procedure TDBDataProcess.CreateTable; procedure TDBDataProcess.VacuumTable; begin if FConn.Connected then - with FConn do - begin - ExecuteDirect('END TRANSACTION'); - ExecuteDirect('VACUUM'); - ExecuteDirect('BEGIN TRANSACTION'); - end; + with FConn do + begin + ExecuteDirect('END TRANSACTION'); + try + ExecuteDirect('VACUUM'); + except + on E: Exception do + WriteLog_E('TDBDataProcess.VacuumTable.Error!', E, Self); + end; + ExecuteDirect('BEGIN TRANSACTION'); + end; end; -procedure TDBDataProcess.GetDataCount; +procedure TDBDataProcess.GetRecordCount; begin if FQuery.Active then begin FQuery.Last; - FDataCount := FQuery.RecordCount; + FRecordCount := FQuery.RecordCount; FQuery.Refresh; end else - FDataCount := 0; + FRecordCount := 0; end; function TDBDataProcess.GetConnected: Boolean; @@ -387,7 +397,8 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; Result := False; if FilePath <> '' then FConn.DatabaseName := FilePath; - if FConn.DatabaseName = '' then Exit; + if FConn.DatabaseName = '' then + Exit; try FConn.Connected := True; sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, @@ -395,7 +406,6 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; sqlite3_create_function(FConn.Handle, PChar('REGEXP'), 2, SQLITE_UTF8, FRegxp, RegexCallback, nil, nil); FTrans.Active := True; - Result := FConn.Connected; except on E: Exception do begin @@ -404,34 +414,31 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; Result := False; end; end; + Result := FConn.Connected; end; function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; begin - if FConn.Connected then + Result := FWebsite; + if FConn.Connected and FilterAllSites and Filtered then begin - if FilterAllSites then - begin - end - else - Result := FWebsite; end; end; -function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; +function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; begin - if ParamNo in [DATA_PARAM_JDN, DATA_PARAM_NUMCHAPTER] then + if FieldIndex in [DATA_PARAM_NUMCHAPTER, DATA_PARAM_JDN] then Result := '0' else Result := ''; if FQuery.Active and - (ParamNo < Length(DBDataProcessParams)) and - (RecIndex < FDataCount) then + (FieldIndex < Length(DBDataProcessParams)) and + (RecIndex < FRecordCount) then begin try - FQuery.RecNo := RecIndex+1; - Result:= FQuery.FieldByName(DBDataProcessParams[ParamNo]).AsString; + FQuery.RecNo := RecIndex + 1; + Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; except on E: Exception do WriteLog_E('TDBDataProcess.GetParam.Error: ' + E.Message + @@ -442,17 +449,19 @@ function TDBDataProcess.GetParam(RecIndex, ParamNo: Integer): String; constructor TDBDataProcess.Create; begin + inherited Create; FConn := TSQLite3Connectionx.Create(nil); FTrans := TSQLTransaction.Create(nil); FQuery := TSQLQuery.Create(nil); FConn.Transaction := FTrans; FQuery.DataBase := FTrans.DataBase; + FQuery.Transaction := FTrans; FRegxp := TRegExpr.Create; FRegxp.ModifierI := True; FSitesList := TStringList.Create; FTableName := 'masterlist'; FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); - FDataCount := 0; + FRecordCount := 0; end; destructor TDBDataProcess.Destroy; @@ -462,7 +471,9 @@ destructor TDBDataProcess.Destroy; begin Commit; VacuumTable; - FConn.Connected := False; + FQuery.Close; + FTrans.Active := False; + FConn.Close(True); end; except on E: Exception do @@ -482,21 +493,24 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; begin Result := False; FFiltered := False; - FDataCount := 0; + FRecordCount := 0; Close; - if AWebsite <> '' then FWebsite := AWebsite; - if FWebsite = '' then Exit; + if AWebsite <> '' then + FWebsite := AWebsite; + if FWebsite = '' then + Exit; filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; if not FileExistsUTF8(filepath) then ConvertDataProccessToDB(AWebsite, True); - if not FileExistsUTF8(filepath) then Exit; + if not FileExistsUTF8(filepath) then + Exit; try if InternalOpen(filepath) then begin if not TableExist(FTableName) then CreateTable; OpenTable; - GetDataCount; + GetRecordCount; end; Result := FQuery.Active; except @@ -514,7 +528,8 @@ function TDBDataProcess.OpenTable(const ATableName: String): Boolean; try if ATableName <> '' then FTableName := ATableName; - if FTableName = '' then Exit; + if FTableName = '' then + Exit; if TableExist(FTableName) then begin if FQuery.Active then @@ -543,7 +558,7 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; try FConn.GetTableNames(ts); ts.Sort; - Result := ts.Find(FTableName, i); + Result := ts.Find(ATableName, i); finally ts.Free; end; @@ -553,11 +568,13 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; procedure TDBDataProcess.Close; begin FFiltered := False; - FDataCount := 0; + FRecordCount := 0; if FConn.Connected then try Commit; - FConn.Connected := False; + FQuery.Close; + FTrans.Active := False; + FConn.Close(True); FConn.DatabaseName := ''; except on E: Exception do @@ -570,74 +587,77 @@ procedure TDBDataProcess.Save; Commit; end; -procedure TDBDataProcess.Backup(AWebsite: string); +procedure TDBDataProcess.Backup(AWebsite: String); begin - if AWebsite = '' then Exit; + if AWebsite = '' then + Exit; if FConn.Connected then begin with TSQLite3Backup.Create do - try - Backup(FConn, fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - finally - Free; - end; + try + Backup(FConn, fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + finally + Free; + end; end; end; procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); begin if FQuery.Active then - begin - FQuery.Refresh; - if RecheckDataCount then - GetDataCount; - end; + FQuery.Refresh + else + OpenTable; + if RecheckDataCount then + GetRecordCount; end; -procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, - Summary: String; NumChapter, JDN: Integer); +procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter, JDN: Integer); begin if FConn.Connected then - try - FConn.ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName) + - #13#10'(' + DBDataProcessParam + ')'+ - #13#10'VALUES (' + - QuotedStr(Title) + ',' + - QuotedStr(Link) + ',' + - QuotedStr(Authors) + ',' + - QuotedStr(Artists) + ',' + - QuotedStr(Genres) + ',' + - QuotedStr(Status) + ',' + - QuotedStr(Summary) + ',' + - QuotedStr(IntToStr(NumChapter)) + ',' + - QuotedStr(IntToStr(JDN)) + ');'); - except - on E: Exception do - WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + LineEnding + GetStackTraceInfo); - end; + try + FConn.ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName) + + #13#10'(' + DBDataProcessParam + ')' + + #13#10'VALUES (' + + QuotedStr(Title) + ',' + + QuotedStr(Link) + ',' + + QuotedStr(Authors) + ',' + + QuotedStr(Artists) + ',' + + QuotedStr(Genres) + ',' + + QuotedStr(Status) + ',' + + QuotedStr(Summary) + ',' + + QuotedStr(IntToStr(NumChapter)) + ',' + + QuotedStr(IntToStr(JDN)) + ');'); + except + on E: Exception do + WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); + end; end; -procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, - Summary: String; NumChapter: Integer; JDN: TDateTime); +procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter: Integer; JDN: TDateTime); begin AddData(Title, Link, Authors, Artists, Genres, Status, Summary, NumChapter, DateToJDN(JDN)); end; -procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, - Status, Summary: String; NumChapter: Integer); +procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, + Genres, Status, Summary: String; NumChapter: Integer); var - sql: string; + sql: String; - procedure AddSQL(const field, value: string); + procedure AddSQL(const field, Value: String); begin if sql <> '' then sql += ','#13#10; - sql += field + '=' + QuotedStr(value); + sql += field + '=' + QuotedStr(Value); end; begin - if Link = '' then Exit; + if Link = '' then + Exit; if FConn.Connected then begin try @@ -654,16 +674,22 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, FConn.ExecuteDirect(sql); except on E: Exception do - WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); end; end; end; procedure TDBDataProcess.Commit; +var + queryactive: Boolean; begin if FConn.Connected then try + queryactive := FQuery.Active; FTrans.Commit; + if FQuery.Active <> queryactive then + FQuery.Active := queryactive; except on E: Exception do WriteLog_E('TDBDataProcess.Commit.Error!', E, Self); @@ -680,10 +706,8 @@ procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); on E: Exception do WriteLog_E('TDBDataProcess.ApplyUpdates.Error!', E, Self); end; - if FQuery.Active = False then - FQuery.Open; if RecheckDataCount then - GetDataCount; + GetRecordCount; end; function TDBDataProcess.Search(ATitle: String): Boolean; @@ -695,28 +719,28 @@ function TDBDataProcess.Search(ATitle: String): Boolean; if ATitle <> '' then FQuery.SQL.Add('WHERE title LIKE ' + QuotedStr(AnsiQuotedStr(ATitle, '%'))); FQuery.Open; - GetDataCount; + GetRecordCount; except on E: Exception do - WriteLog_E('TDBDataProcess.Search.Error: ' + E.Message + LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.Search.Error: ' + E.Message + + LineEnding + GetStackTraceInfo); end; Result := FQuery.Active; end; -function TDBDataProcess.CanFilter(const checkedGenres, - uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, - stSummary: String; const minusDay: Cardinal; const haveAllChecked, - searchNewManga: Boolean): Boolean; +function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; + const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; begin Result := True; end; -function TDBDataProcess.Filter(const checkedGenres, - uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, - stSummary: String; const minusDay: Cardinal; const haveAllChecked, - searchNewManga: Boolean; useRegExpr: Boolean): Boolean; +function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; + const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; + useRegExpr: Boolean): Boolean; - procedure AddSQL(const S: string); + procedure AddSQL(const S: String); begin if FQuery.SQL.Count > 0 then FQuery.SQL.Add('AND'); @@ -725,15 +749,16 @@ function TDBDataProcess.Filter(const checkedGenres, begin Result := False; - if FConn.Connected = False then Exit; + if FConn.Connected = False then + Exit; with FQuery do begin - FDataCount := 0; + FRecordCount := 0; Close; try SQL.Clear; if searchNewManga then - AddSQL('jdn > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0-minusDay)))))); + AddSQL('jdn > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); @@ -750,15 +775,15 @@ function TDBDataProcess.Filter(const checkedGenres, FFiltered := False; end; end; - GetDataCount; + GetRecordCount; Result := FFiltered; end; end; function TDBDataProcess.LocateByLink(ALink: String): Boolean; begin - Result := false; - if (FQuery.Active) and (FDataCount > 0) and (ALink <> '') then + Result := False; + if (FQuery.Active) and (FRecordCount > 0) and (ALink <> '') then try Result := FQuery.Locate('link', ALink, [loCaseInsensitive]); except @@ -767,13 +792,14 @@ function TDBDataProcess.LocateByLink(ALink: String): Boolean; end; end; -procedure TDBDataProcess.CreateDatabase(AWebsite: string); +procedure TDBDataProcess.CreateDatabase(AWebsite: String); var - filepath: string; + filepath: String; begin if AWebsite <> '' then FWebsite := AWebsite; - if FWebsite = '' then Exit; + if FWebsite = '' then + Exit; filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; if FileExistsUTF8(filepath) then DeleteFileUTF8(filepath); @@ -781,11 +807,17 @@ procedure TDBDataProcess.CreateDatabase(AWebsite: string); CreateTable; end; +procedure TDBDataProcess.GetFieldNames(List: TStringList); +begin + if (List <> nil) and (FQuery.Active) then + FQuery.GetFieldNames(List); +end; + procedure TDBDataProcess.RemoveFilter; begin FFiltered := False; OpenTable; - GetDataCount; + GetRecordCount; end; procedure TDBDataProcess.Sort; @@ -795,16 +827,16 @@ procedure TDBDataProcess.Sort; FQuery.Close; with FConn do begin - ExecuteDirect('CREATE TABLE ' + QuotedStr(FTableName+'_ordered') + + ExecuteDirect('CREATE TABLE ' + QuotedStr(FTableName + '_ordered') + DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO '+ QuotedStr(FTableName+'_ordered') + ' ' + + ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName + '_ordered') + ' ' + BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + - ' FROM '+ QuotedStr(FTableName) + 'ORDER BY title COLLATE NATCMP'); + ' FROM ' + QuotedStr(FTableName) + 'ORDER BY title COLLATE NATCMP'); ExecuteDirect('DROP TABLE ' + QuotedStr(FTableName)); - ExecuteDirect('ALTER TABLE '+ QuotedStr(FTableName+'_ordered') + + ExecuteDirect('ALTER TABLE ' + QuotedStr(FTableName + '_ordered') + 'RENAME TO ' + QuotedStr(FTableName)); FTrans.Commit; - VacuumTable + VacuumTable; end; FQuery.Open; end; @@ -920,7 +952,7 @@ procedure TDataProcess.BreakDataToParts(const i: Cardinal); begin if i < Data.Count then begin - Title.Strings[i] := GetParam(i, DATA_PARAM_NAME); + Title.Strings[i] := GetParam(i, DATA_PARAM_TITLE); Link.Strings[i] := GetParam(i, DATA_PARAM_LINK); Authors.Strings[i] := GetParam(i, DATA_PARAM_AUTHORS); Artists.Strings[i] := GetParam(i, DATA_PARAM_ARTISTS); @@ -965,7 +997,7 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; if Data.Count > 0 then begin //QuickSortData(data); - QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_NAME); //Natural Sorting + QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_TITLE); //Natural Sorting for i := 0 to Data.Count - 1 do begin filterMark.Add(FILTER_SHOW); @@ -977,7 +1009,7 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; GetParams(l, Data.Strings[i]); while l.Count < 10 do l.Add(''); - title.Add(l.Strings[DATA_PARAM_NAME]); + title.Add(l.Strings[DATA_PARAM_TITLE]); link.Add(l.Strings[DATA_PARAM_LINK]); authors.Add(l.Strings[DATA_PARAM_AUTHORS]); artists.Add(l.Strings[DATA_PARAM_ARTISTS]); @@ -1052,7 +1084,7 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; GetParams(l, Data.Strings[i]); While l.Count < 10 do l.Add(''); - title.Add(l.Strings[DATA_PARAM_NAME]); + title.Add(l.Strings[DATA_PARAM_TITLE]); link.Add(l.Strings[DATA_PARAM_LINK]); authors.Add(l.Strings[DATA_PARAM_AUTHORS]); artists.Add(l.Strings[DATA_PARAM_ARTISTS]); @@ -1410,7 +1442,7 @@ procedure TDataProcess.RemoveFilter; procedure TDataProcess.Sort; begin //QuickSortData(data); - uMisc.QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_NAME); + uMisc.QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_TITLE); end; { TMangaInformation } @@ -2734,7 +2766,7 @@ procedure TMangaInformation.SyncMinorInfoToData(const DataProcess: TDataProcess; {$ENDIF} begin DataProcess.Data.Strings[index] := SetParams( - [DataProcess.Param[index, DATA_PARAM_NAME], + [DataProcess.Param[index, DATA_PARAM_TITLE], DataProcess.Param[index, DATA_PARAM_LINK], DataProcess.Param[index, DATA_PARAM_AUTHORS], DataProcess.Param[index, DATA_PARAM_ARTISTS], @@ -2762,9 +2794,9 @@ procedure TMangaInformation.SyncInfoToData(const DataProcess: TDataProcess; {$ENDIF} begin if Trim(mangaInfo.title) = '' then - mangaInfo.title := DataProcess.Param[index, DATA_PARAM_NAME]; + mangaInfo.title := DataProcess.Param[index, DATA_PARAM_TITLE]; DataProcess.Data.Strings[index] := SetParams( - //[DataProcess.Param[index, DATA_PARAM_NAME], + //[DataProcess.Param[index, DATA_PARAM_TITLE], //sync title as well, some site possible to change title or when mangainfo script not work [mangaInfo.title, DataProcess.Param[index, DATA_PARAM_LINK], @@ -2840,7 +2872,7 @@ procedure TMangaInformation.AddInfoToData(const Name, link: String; IntToStr(GetCurrentJDN), '0']))); GetParams(l, DataProcess.Data.Strings[DataProcess.Data.Count - 1]); - DataProcess.title.Add(l.Strings[DATA_PARAM_NAME]); + DataProcess.title.Add(l.Strings[DATA_PARAM_TITLE]); DataProcess.link.Add(l.Strings[DATA_PARAM_LINK]); DataProcess.authors.Add(l.Strings[DATA_PARAM_AUTHORS]); DataProcess.artists.Add(l.Strings[DATA_PARAM_ARTISTS]); @@ -2879,5 +2911,10 @@ function TMangaInformation.GetPage(var output: TObject; URL: String; initialization sqlite3dyn.SQLiteDefaultLibrary := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; + tdset := TSqlite3Dataset.Create(nil); + +finalization + if Assigned(tdset) then + FreeAndNil(tdset); end. diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 5d5be6d76..d74a113ce 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -71,17 +71,17 @@ procedure TGetMangaInfosThread.DoGetInfos; (website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex]) then begin filterPos := FMangaListPos; - FInfo.mangaInfo.title := MainForm.dataProcess.Param[filterPos, DATA_PARAM_NAME]; - FInfo.mangaInfo.link := MainForm.dataProcess.Param[filterPos, DATA_PARAM_LINK]; - FInfo.mangaInfo.authors := MainForm.dataProcess.Param[filterPos, DATA_PARAM_AUTHORS]; - FInfo.mangaInfo.artists := MainForm.dataProcess.Param[filterPos, DATA_PARAM_ARTISTS]; - FInfo.mangaInfo.status := MainForm.dataProcess.Param[filterPos, DATA_PARAM_STATUS]; - FInfo.mangaInfo.summary := MainForm.dataProcess.Param[filterPos, DATA_PARAM_SUMMARY]; - FInfo.mangaInfo.numChapter := StrToIntDef(MainForm.dataProcess.Param[filterPos, DATA_PARAM_NUMCHAPTER], 0); - FNumChapter := StrToIntDef(MainForm.dataProcess.Param[filterPos, DATA_PARAM_NUMCHAPTER], 0); + FInfo.mangaInfo.title := MainForm.dataProcess.Value[filterPos, DATA_PARAM_TITLE]; + FInfo.mangaInfo.link := MainForm.dataProcess.Value[filterPos, DATA_PARAM_LINK]; + FInfo.mangaInfo.authors := MainForm.dataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; + FInfo.mangaInfo.artists := MainForm.dataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; + FInfo.mangaInfo.status := MainForm.dataProcess.Value[filterPos, DATA_PARAM_STATUS]; + FInfo.mangaInfo.summary := MainForm.dataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; + FInfo.mangaInfo.numChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); + FNumChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); if SitesWithoutInformation(website) or (website = WebsiteRoots[EHENTAI_ID, 0]) then - FInfo.mangaInfo.genres := MainForm.dataProcess.Param[filterPos, DATA_PARAM_GENRES]; + FInfo.mangaInfo.genres := MainForm.dataProcess.Value[filterPos, DATA_PARAM_GENRES]; end; FInfo.isGenerateFolderChapterName := MainForm.cbOptionGenerateChapterName.Checked; @@ -101,16 +101,16 @@ procedure TGetMangaInfosThread.DoGetInfos; begin if FInfo.mangaInfo.authors = '' then FInfo.mangaInfo.authors := - MainForm.DataProcess.Param[filterPos, DATA_PARAM_AUTHORS]; + MainForm.DataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; if FInfo.mangaInfo.artists = '' then FInfo.mangaInfo.artists := - MainForm.DataProcess.Param[filterPos, DATA_PARAM_ARTISTS]; + MainForm.DataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; if FInfo.mangaInfo.genres = '' then FInfo.mangaInfo.genres := - MainForm.DataProcess.Param[filterPos, DATA_PARAM_GENRES]; + MainForm.DataProcess.Value[filterPos, DATA_PARAM_GENRES]; if FInfo.mangaInfo.summary = '' then FInfo.mangaInfo.summary := - MainForm.DataProcess.Param[filterPos, DATA_PARAM_SUMMARY]; + MainForm.DataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; end; FInfo.SyncInfoToData(MainForm.DataProcess); diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index d87691d14..98d363455 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -44,9 +44,9 @@ procedure TUpdateDBThread.MainThreadRefreshList; MainForm.dataProcess := TDBDataProcess.Create; MainForm.dataProcess.Open(websiteName); MainForm.vtMangaList.Clear; - MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.DataCount; + MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.RecordCount; MainForm.lbMode.Caption := - Format(RS_ModeAll, [MainForm.dataProcess.DataCount]); + Format(RS_ModeAll, [MainForm.dataProcess.RecordCount]); end; except on E: Exception do diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 9c900dc5e..3f7b27fac 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -186,7 +186,7 @@ procedure TUpdateMangaThread.Execute; if SitesWithSortedList(manager.website) then begin if links.Count > 0 then - if manager.mainDataProcess.Locate(DATA_PARAM_LINK, links.Strings[0]) then + if manager.mainDataProcess.LocateByLink(links.Strings[0]) then manager.isFinishSearchingForNewManga := True; end; @@ -336,8 +336,8 @@ procedure TUpdateMangaManagerThread.RefreshList; dataProcess.Close; OverwriteDBDataProcess(website, twebsite); dataProcess.Open(website); - vtMangaList.RootNodeCount := dataProcess.DataCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + vtMangaList.RootNodeCount := dataProcess.RecordCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); finally Screen.Cursor := crDefault; end; @@ -501,9 +501,8 @@ procedure TUpdateMangaManagerThread.Execute; end; var - s: String; - j, k, iPos: Integer; - del, purg: Boolean; + j, k: Integer; + del: Boolean; begin if websites.Count = 0 then Exit; @@ -535,11 +534,7 @@ procedure TUpdateMangaManagerThread.Execute; DeleteDBDataProcess(twebsite); if (MainForm.cbSelectManga.Text = website) and (MainForm.dataProcess.Connected) then - begin - MainForm.dataProcess.Backup(twebsite); - MainForm.vtMangaList.Clear; - MainForm.dataProcess.Close; - end + MainForm.dataProcess.Backup(twebsite) else CopyDBDataProcess(website, twebsite); @@ -548,9 +543,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.CreateDatabase(twebsite); mainDataProcess.OpenTable; end; - - names.Clear; - links.Clear; + mainDataProcess.Refresh(True); //get directory page count INIAdvanced.Reload; @@ -629,7 +622,7 @@ procedure TUpdateMangaManagerThread.Execute; begin if Terminated then Break; - if mainDataProcess.Locate(DATA_PARAM_LINK, links[j]) then + if mainDataProcess.LocateByLink(links[j]) then begin links.Delete(j); names.Delete(j); @@ -675,15 +668,19 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); - mainDataProcess.Sort; + //mainDataProcess.Sort; end; + + names.Clear; + links.Clear; mainDataProcess.Close; + Synchronize(RefreshList); - DeleteDBDataProcess(twebsite); + //DeleteDBDataProcess(twebsite); if Terminated then Break; websites[websitePtr - 1] := - UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); + UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); end; except on E: Exception do diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index ceadf38e9..a0ed9b037 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3106,8 +3106,8 @@ object MainForm: TMainForm object vtMangaList: TVirtualStringTree Cursor = crHourGlass Left = 2 - Height = 384 - Top = 91 + Height = 383 + Top = 92 Width = 181 Align = alBottom Anchors = [akTop, akLeft, akRight, akBottom] diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d228a7e3c..44cd2af6f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1060,8 +1060,8 @@ procedure TMainForm.itStartupTimer(Sender: TObject); vtMangaList.Clear; dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); end; - vtMangaList.RootNodeCount := dataProcess.DataCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + vtMangaList.RootNodeCount := dataProcess.RecordCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); dataProcess.Refresh; finally Screen.Cursor := crDefault; @@ -1869,9 +1869,9 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); if not dataProcess.Open( cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]) then RunGetList; - vtMangaList.RootNodeCount := dataProcess.DataCount; + vtMangaList.RootNodeCount := dataProcess.RecordCount; dataProcess.Refresh; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; dataProcess.website := cbSelectManga.Items[cbSelectManga.ItemIndex]; CheckForTopPanel; @@ -2065,8 +2065,8 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); dataProcess := TDBDataProcess.Create; dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); end; - vtMangaList.RootNodeCount := dataProcess.DataCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.DataCount]); + vtMangaList.RootNodeCount := dataProcess.RecordCount; + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); edSearch.Text := ''; except on E: Exception do @@ -2147,8 +2147,8 @@ procedure TMainForm.btFilterClick(Sender: TObject); seOptionNewMangaTime.Value, rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked) then begin - lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.DataCount]); - vtMangaList.RootNodeCount := dataProcess.DataCount; + lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]); + vtMangaList.RootNodeCount := dataProcess.RecordCount; end; except on E: Exception do @@ -2189,8 +2189,8 @@ procedure TMainForm.miMangaListAddToFavoritesClick(Sender: TObject); begin SilentThreadManager.Add(MD_AddToFavorites, dataProcess.WebsiteName[xNode^.Index], - DataProcess.Param[xNode^.Index, DATA_PARAM_NAME], - DataProcess.Param[xNode^.Index, DATA_PARAM_LINK]); + DataProcess.Value[xNode^.Index, DATA_PARAM_TITLE], + DataProcess.Value[xNode^.Index, DATA_PARAM_LINK]); end; xNode := vtMangaList.GetNextSelected(xNode); end; @@ -2588,7 +2588,7 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); AllowedToCreate := True; if DLManager.Count > 0 then for j := 0 to DLManager.Count - 1 do - if dataProcess.Param[xNode^.Index, DATA_PARAM_NAME] = + if dataProcess.Value[xNode^.Index, DATA_PARAM_TITLE] = DLManager.TaskItem(j).DownloadInfo.title then begin if YesAll then @@ -2624,8 +2624,8 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); if AllowedToCreate then SilentThreadManager.Add(MD_DownloadAll, dataProcess.WebsiteName[xNode^.Index], - dataProcess.Param[xNode^.Index, DATA_PARAM_NAME], - dataProcess.Param[xNode^.Index, DATA_PARAM_LINK]); + dataProcess.Value[xNode^.Index, DATA_PARAM_TITLE], + dataProcess.Value[xNode^.Index, DATA_PARAM_LINK]); end; xNode := vtMangaList.GetNextSelected(xNode); end; @@ -2660,8 +2660,8 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); GetInfosThread.MangaListPos := vtMangaList.FocusedNode^.Index; website := dataProcess.WebsiteName[GetInfosThread.MangaListPos]; - title := DataProcess.Param[GetInfosThread.mangaListPos, DATA_PARAM_NAME]; - link := DataProcess.Param[GetInfosThread.mangaListPos, DATA_PARAM_LINK]; + title := DataProcess.Value[GetInfosThread.mangaListPos, DATA_PARAM_TITLE]; + link := DataProcess.Value[GetInfosThread.mangaListPos, DATA_PARAM_LINK]; GetInfosThread.Title := title; GetInfosThread.Website := website; @@ -4041,7 +4041,7 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; var data: PMangaListItem; begin - if (isExiting) or (dataProcess.DataCount = 0) then + if (isExiting) or (dataProcess.RecordCount = 0) then Exit; if miHighlightNewManga.Checked then begin @@ -4079,29 +4079,29 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; if FilterAllSites then s := s + RS_InfoWebsite + LineEnding + dataProcess.WebsiteName[LPos] + LineEnding + LineEnding; - if Trim(Param[LPos, DATA_PARAM_NAME]) <> '' then - s := s + RS_InfoTitle + LineEnding + Param[LPos, DATA_PARAM_NAME]; - if Trim(Param[LPos, DATA_PARAM_AUTHORS]) <> '' then + if Trim(Value[LPos, DATA_PARAM_TITLE]) <> '' then + s := s + RS_InfoTitle + LineEnding + Value[LPos, DATA_PARAM_TITLE]; + if Trim(Value[LPos, DATA_PARAM_AUTHORS]) <> '' then s := s + LineEnding + LineEnding + RS_InfoAuthors + LineEnding + - Param[LPos, DATA_PARAM_AUTHORS]; - if Trim(Param[LPos, DATA_PARAM_ARTISTS]) <> '' then + Value[LPos, DATA_PARAM_AUTHORS]; + if Trim(Value[LPos, DATA_PARAM_ARTISTS]) <> '' then s := s + LineEnding + LineEnding + RS_InfoArtists + LineEnding + - Param[LPos, DATA_PARAM_ARTISTS]; - if Trim(Param[LPos, DATA_PARAM_GENRES]) <> '' then + Value[LPos, DATA_PARAM_ARTISTS]; + if Trim(Value[LPos, DATA_PARAM_GENRES]) <> '' then s := s + LineEnding + LineEnding + RS_InfoGenres + LineEnding + - Param[LPos, DATA_PARAM_GENRES]; - if Trim(Param[LPos, DATA_PARAM_STATUS]) <> '' then + Value[LPos, DATA_PARAM_GENRES]; + if Trim(Value[LPos, DATA_PARAM_STATUS]) <> '' then begin s := s + LineEnding + LineEnding + RS_InfoStatus + LineEnding; - if Param[LPos, DATA_PARAM_STATUS] = '0' then + if Value[LPos, DATA_PARAM_STATUS] = '0' then s := s + cbFilterStatus.Items[0] else s := s + cbFilterStatus.Items[1]; end; - if Trim(Param[LPos, DATA_PARAM_SUMMARY]) <> '' then - //s := s + LineEndingLineEnding + infoSummary + ':' + LineEnding + PrepareSummaryForHint(dataProcess.Param[LPos, DATA_PARAM_SUMMARY], 80); + if Trim(Value[LPos, DATA_PARAM_SUMMARY]) <> '' then + //s := s + LineEndingLineEnding + infoSummary + ':' + LineEnding + PrepareSummaryForHint(dataProcess.Value[LPos, DATA_PARAM_SUMMARY], 80); s := s + LineEnding + LineEnding + RS_InfoSummary + ':' + LineEnding + - StringBreaks(dataProcess.Param[LPos, DATA_PARAM_SUMMARY]); + StringBreaks(dataProcess.Value[LPos, DATA_PARAM_SUMMARY]); end; HintText := s; end; @@ -4695,7 +4695,7 @@ procedure TMainForm.edSearchChange(Sender: TObject); //Screen.Cursor := crHourGlass; vtMangaList.Clear; dataProcess.Search(edSearch.Text); - vtMangaList.RootNodeCount := dataProcess.DataCount; + vtMangaList.RootNodeCount := dataProcess.RecordCount; //Screen.Cursor := crDefault; Exit; end @@ -4706,7 +4706,7 @@ procedure TMainForm.edSearchChange(Sender: TObject); LastSearchStr := upcase(edSearch.Text); vtMangaList.Clear; DataProcess.Search(edSearch.Text); - vtMangaList.RootNodeCount := dataProcess.DataCount; + vtMangaList.RootNodeCount := dataProcess.RecordCount; end; end; @@ -4723,7 +4723,7 @@ procedure TMainForm.edSearchKeyUp(Sender: TObject; var Key: Word; Shift: TShiftS begin Screen.Cursor := crHourGlass; vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.DataCount; + vtMangaList.RootNodeCount := dataProcess.RecordCount; Screen.Cursor := crDefault; end else @@ -4732,7 +4732,7 @@ procedure TMainForm.edSearchKeyUp(Sender: TObject; var Key: Word; Shift: TShiftS LastSearchWeb := currentWebsite; DataProcess.Search(edSearch.Text); vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.DataCount; + vtMangaList.RootNodeCount := dataProcess.RecordCount; Screen.Cursor := crDefault; end; end; @@ -4966,9 +4966,9 @@ procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, data := Sender.GetNodeData(Node); if Assigned(data) then begin - data^.Text := Format('%s (%s)', [dataProcess.Param[Node^.Index, DATA_PARAM_NAME], - dataProcess.Param[Node^.Index, DATA_PARAM_NUMCHAPTER]]); - data^.JDN := StrToIntDef(dataProcess.Param[Node^.Index, DATA_PARAM_JDN], 0); + data^.Text := Format('%s (%s)', [dataProcess.Value[Node^.Index, DATA_PARAM_TITLE], + dataProcess.Value[Node^.Index, DATA_PARAM_NUMCHAPTER]]); + data^.JDN := StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0); Sender.ValidateNode(Node, False); end; end; From dcef9a1518a3f5272cf386a0471e131a90ab6fbd Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 02:59:23 +0800 Subject: [PATCH 0061/2794] tdbdataprocess, close on destroy --- baseunits/uData.pas | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0a721ea68..1a8608576 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -471,9 +471,7 @@ destructor TDBDataProcess.Destroy; begin Commit; VacuumTable; - FQuery.Close; - FTrans.Active := False; - FConn.Close(True); + Close; end; except on E: Exception do @@ -571,7 +569,6 @@ procedure TDBDataProcess.Close; FRecordCount := 0; if FConn.Connected then try - Commit; FQuery.Close; FTrans.Active := False; FConn.Close(True); From 9212d3187cc26cf206f4f8339228b891e0c125f0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 03:09:04 +0800 Subject: [PATCH 0062/2794] tdbdataprocess, change writelog --- baseunits/uData.pas | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1a8608576..314c201ab 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -312,8 +312,7 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: string); [cffPreserveTime, cffOverwriteFile], True); except on E: Exception do - Writelog_E('CopyDBDataProcess.Error: ' + E.Message + LineEnding + - GetStackTraceInfo); + Writelog_E('CopyDBDataProcess.Error!', E); end; end; end; @@ -409,8 +408,7 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; except on E: Exception do begin - WriteLog_E('TDBDataProcess.InternalOpen.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.InternalOpen.Error!', E, Self); Result := False; end; end; @@ -441,8 +439,7 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; except on E: Exception do - WriteLog_E('TDBDataProcess.GetParam.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.GetParam.Error!', E, Self); end; end; end; @@ -513,8 +510,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; Result := FQuery.Active; except on E: Exception do - WriteLog_E('TDBDataProcess.Open.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.Open.Error!', E, Self); end; end; @@ -628,8 +624,7 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, QuotedStr(IntToStr(JDN)) + ');'); except on E: Exception do - WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.AddData.Error!', E, Self); end; end; @@ -671,8 +666,7 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, FConn.ExecuteDirect(sql); except on E: Exception do - WriteLog_E('TDBDataProcess.AddData.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.AddData.Error!', E, Self); end; end; end; @@ -719,8 +713,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; GetRecordCount; except on E: Exception do - WriteLog_E('TDBDataProcess.Search.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.Search.Error!', E, Self); end; Result := FQuery.Active; end; @@ -764,8 +757,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList except on E: Exception do begin - WriteLog_E('TDBDataProcess.Filter.Error: ' + E.Message + - LineEnding + GetStackTraceInfo); + WriteLog_E('TDBDataProcess.Filter.Error!', E, Self); Close; SQL.Text := FSQLSelect; Open; From 016c980da1d63ebb0fa4d867e9411127716b3ec8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 03:10:46 +0800 Subject: [PATCH 0063/2794] revert: mainform, vtmangalist store data record to mem --- mangadownloader/forms/frmMain.lfm | 3 -- mangadownloader/forms/frmMain.pas | 50 ++++--------------------------- 2 files changed, 5 insertions(+), 48 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index a0ed9b037..168b409eb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3134,11 +3134,8 @@ object MainForm: TMainForm OnColumnDblClick = vtMangaListColumnDblClick OnDragAllowed = vtMangaListDragAllowed OnDragOver = vtMangaListDragOver - OnFreeNode = vtMangaListFreeNode OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint - OnGetNodeDataSize = vtMangaListGetNodeDataSize - OnInitNode = vtMangaListInitNode end object edSearch: TEdit Left = 3 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 44cd2af6f..28311f8e7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -502,18 +502,12 @@ TMainForm = class(TForm) procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure vtMangaListFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); - procedure vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); procedure vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure tmBackupTimer(Sender: TObject); - procedure vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); procedure vtOptionMangaSiteSelectionFocusChanged(Sender : TBaseVirtualTree; @@ -4045,9 +4039,8 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; Exit; if miHighlightNewManga.Checked then begin - data := Sender.GetNodeData(Node); - if Assigned(data) then - if data^.JDN > (currentJDN - seOptionNewMangaTime.Value) then + if Assigned(Node) then + if StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - seOptionNewMangaTime.Value) then begin TargetCanvas.Brush.Color := CL_HLBlueMarks; TargetCanvas.FillRect(CellRect); @@ -4055,16 +4048,6 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; end; end; -procedure TMainForm.vtMangaListFreeNode(Sender: TBaseVirtualTree; - Node: PVirtualNode); -var - data: PMangaListItem; -begin - data := Sender.GetNodeData(Node); - if Assigned(data) then - Finalize(data^); -end; - procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -4106,21 +4089,13 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; HintText := s; end; -procedure TMainForm.vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TMangaListItem); -end; - procedure TMainForm.vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - data: PMangaListItem; begin - data := Sender.GetNodeData(Node); - if Assigned(data) then - CellText := data^.Text; + if Assigned(Node) then + CellText := Format('%s (%s)', [dataProcess.Value[Node^.Index, DATA_PARAM_TITLE], + dataProcess.Value[Node^.Index, DATA_PARAM_NUMCHAPTER]]); end; procedure TMainForm.InitCheckboxes; @@ -4958,21 +4933,6 @@ procedure TMainForm.tmBackupTimer(Sender: TObject); DLManager.Backup; end; -procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - data: PMangaListItem; -begin - data := Sender.GetNodeData(Node); - if Assigned(data) then - begin - data^.Text := Format('%s (%s)', [dataProcess.Value[Node^.Index, DATA_PARAM_TITLE], - dataProcess.Value[Node^.Index, DATA_PARAM_NUMCHAPTER]]); - data^.JDN := StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0); - Sender.ValidateNode(Node, False); - end; -end; - procedure TMainForm.vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); begin From 17e09496f3c64f0a054009e843cdcd7381143a03 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 03:44:28 +0800 Subject: [PATCH 0064/2794] tdbdataprocess, fix destroy --- baseunits/uData.pas | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 314c201ab..d3308f52d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -359,8 +359,13 @@ procedure TDBDataProcess.CreateTable; end; procedure TDBDataProcess.VacuumTable; +var + queryactive: Boolean; begin if FConn.Connected then + begin + queryactive := FQuery.Active; + FQuery.Close; with FConn do begin ExecuteDirect('END TRANSACTION'); @@ -372,6 +377,9 @@ procedure TDBDataProcess.VacuumTable; end; ExecuteDirect('BEGIN TRANSACTION'); end; + if FQuery.Active <> queryactive then + FQuery.Active := queryactive; + end; end; procedure TDBDataProcess.GetRecordCount; @@ -466,6 +474,7 @@ destructor TDBDataProcess.Destroy; try if FConn.Connected then begin + FQuery.Close; Commit; VacuumTable; Close; @@ -566,8 +575,7 @@ procedure TDBDataProcess.Close; if FConn.Connected then try FQuery.Close; - FTrans.Active := False; - FConn.Close(True); + FConn.Close; FConn.DatabaseName := ''; except on E: Exception do @@ -678,6 +686,7 @@ procedure TDBDataProcess.Commit; if FConn.Connected then try queryactive := FQuery.Active; + FQuery.Close; FTrans.Commit; if FQuery.Active <> queryactive then FQuery.Active := queryactive; From 196f508db1f15e3e2e083e18836df7924d650e5c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 03:56:13 +0800 Subject: [PATCH 0065/2794] tdbdataprocess, fix delete/overwrite data --- baseunits/uData.pas | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d3308f52d..6b61409a4 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -205,8 +205,8 @@ TMangaInformation = class(TObject) procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); function DBDataProcessExist(const AWebsite: string): Boolean; procedure CopyDBDataProcess(const AWebsite, NWebsite: string); + function DeleteDBDataProcess(const AWebsite: string): Boolean; procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); - procedure DeleteDBDataProcess(const AWebsite: string); implementation @@ -317,33 +317,33 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: string); end; end; -procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); +function DeleteDBDataProcess(const AWebsite: string): Boolean; var tryc: Integer; - canrename: boolean; begin - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then + Result := True; + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then begin - canrename := True; tryc := 0; - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then - while not (tryc < 5) and - DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do + while not DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do begin + if tryc > 3 then + Break; Inc(tryc); - canrename := False; - Sleep(200); + Sleep(250); end; - if canrename then - RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; end; -procedure DeleteDBDataProcess(const AWebsite: string); +procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); begin - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then - DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then + begin + if DeleteDBDataProcess(AWebsite) then + RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + end; end; { TDBDataProcess } From f415ee4a7eb4b0e5de4b3e33f08865be9d5abb3b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 03:59:29 +0800 Subject: [PATCH 0066/2794] updatethread, fix refresh/overwrite list --- baseunits/uUpdateThread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 3f7b27fac..7efe9997e 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -668,7 +668,7 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); - //mainDataProcess.Sort; + mainDataProcess.Sort; end; names.Clear; @@ -676,7 +676,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.Close; Synchronize(RefreshList); - //DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsite); if Terminated then Break; websites[websitePtr - 1] := From d15731ca14edbc4e3602d57a36ed84f0212fc2cb Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:01:11 +0800 Subject: [PATCH 0067/2794] updatethread, commit data if count>0 --- baseunits/uUpdateThread.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 7efe9997e..e6d3b28b0 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -660,7 +660,8 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(links.Count, CS_INFO); end; WaitForThreads; - mainDataProcess.Commit; + if FCommitCount > 0 then + mainDataProcess.Commit; end; if (not Terminated) or (not SitesWithSortedList(website)) then From 7c7e67dfb3646c29ce2680bc4ec485260d40666c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:10:37 +0800 Subject: [PATCH 0068/2794] updatethread, refresh list only if not terminated --- baseunits/uUpdateThread.pas | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e6d3b28b0..c3beaf1b7 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -664,20 +664,24 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.Commit; end; + names.Clear; + links.Clear; + if (not Terminated) or (not SitesWithSortedList(website)) then begin FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); + end + else + begin + mainDataProcess.Close; + DeleteDBDataProcess(twebsite); end; - names.Clear; - links.Clear; - mainDataProcess.Close; - - Synchronize(RefreshList); - DeleteDBDataProcess(twebsite); if Terminated then Break; websites[websitePtr - 1] := From fe3fe439b1047f9f10c060e91252e58367bf5f58 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:22:24 +0800 Subject: [PATCH 0069/2794] tdbdataprocess, fix delete data --- baseunits/uData.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 6b61409a4..8d476607d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -321,8 +321,8 @@ function DeleteDBDataProcess(const AWebsite: string): Boolean; var tryc: Integer; begin - Result := True; - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) then + Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + if Result = False then begin tryc := 0; while not DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do From 67ce0992fcbadfe8ea06dd257d726cab4f15793c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:22:59 +0800 Subject: [PATCH 0070/2794] updatethread, delete unused data --- baseunits/uUpdateThread.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index c3beaf1b7..66cb0dd01 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -296,6 +296,8 @@ constructor TUpdateMangaManagerThread.Create; destructor TUpdateMangaManagerThread.Destroy; begin + mainDataProcess.Close; + DeleteDBDataProcess(twebsite); websites.Free; names.Free; links.Free; From 1cfc9202380b7ff9a53f76dd0c8b533ba72dce7e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:31:49 +0800 Subject: [PATCH 0071/2794] tdbdataprocess, add closetable --- baseunits/uData.pas | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8d476607d..b57b9ac30 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -68,6 +68,7 @@ TDBDataProcess = class(TObject) procedure CreateDatabase(AWebsite: String = ''); procedure GetFieldNames(List: TStringList); procedure Close; + procedure CloseTable; procedure Save; procedure Backup(AWebsite: String); procedure Refresh(RecheckDataCount: Boolean = False); @@ -583,6 +584,16 @@ procedure TDBDataProcess.Close; end; end; +procedure TDBDataProcess.CloseTable; +begin + if FQuery.Active then + begin + FFiltered := False; + FRecordCount := 0; + FQuery.Close; + end; +end; + procedure TDBDataProcess.Save; begin Commit; @@ -819,9 +830,12 @@ procedure TDBDataProcess.RemoveFilter; end; procedure TDBDataProcess.Sort; +var + queryactive: Boolean; begin if FConn.Connected then begin + queryactive := FQuery.Active; FQuery.Close; with FConn do begin @@ -830,13 +844,15 @@ procedure TDBDataProcess.Sort; ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName + '_ordered') + ' ' + BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + ' FROM ' + QuotedStr(FTableName) + 'ORDER BY title COLLATE NATCMP'); + FTrans.Commit; ExecuteDirect('DROP TABLE ' + QuotedStr(FTableName)); ExecuteDirect('ALTER TABLE ' + QuotedStr(FTableName + '_ordered') + 'RENAME TO ' + QuotedStr(FTableName)); FTrans.Commit; VacuumTable; end; - FQuery.Open; + if FQuery.Active <> queryactive then + FQuery.Open; end; end; From f7e5fb839d083621d3dfd7472fcdb9327d68d6a9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:32:15 +0800 Subject: [PATCH 0072/2794] updatethread, closetable before sort --- baseunits/uUpdateThread.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 66cb0dd01..c0b5e9895 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -665,6 +665,7 @@ procedure TUpdateMangaManagerThread.Execute; if FCommitCount > 0 then mainDataProcess.Commit; end; + mainDataProcess.Refresh; names.Clear; links.Clear; @@ -674,6 +675,7 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); + mainDataProcess.CloseTable; mainDataProcess.Sort; mainDataProcess.Close; Synchronize(RefreshList); From e22f2be2612a2ea7d253c82049776c316c50a170 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 04:34:03 +0800 Subject: [PATCH 0073/2794] tdbdataprocess, don't need to vacuumtable on destroy --- baseunits/uData.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b57b9ac30..ed1012147 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -477,7 +477,6 @@ destructor TDBDataProcess.Destroy; begin FQuery.Close; Commit; - VacuumTable; Close; end; except From c84e94d35f8e0255c96bb076fd6be528abe4d745 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 15:58:19 +0800 Subject: [PATCH 0074/2794] tdbdataprocess, fix search title --- baseunits/uData.pas | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index ed1012147..e7a637192 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -466,7 +466,7 @@ constructor TDBDataProcess.Create; FRegxp.ModifierI := True; FSitesList := TStringList.Create; FTableName := 'masterlist'; - FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); + FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FRecordCount := 0; end; @@ -537,7 +537,7 @@ function TDBDataProcess.OpenTable(const ATableName: String): Boolean; begin if FQuery.Active then FQuery.Close; - FSQLSelect := 'SELECT * FROM ' + QuotedStr(FTableName); + FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FQuery.SQL.Text := FSQLSelect; FQuery.Open; end; @@ -722,12 +722,19 @@ procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); function TDBDataProcess.Search(ATitle: String): Boolean; begin - if FConn.Connected then + if FQuery.Active then try FQuery.Close; - FQuery.SQL.Text := FSQLSelect; + FQuery.SQL.Clear; + FQuery.SQL.Add(FSQLSelect); if ATitle <> '' then - FQuery.SQL.Add('WHERE title LIKE ' + QuotedStr(AnsiQuotedStr(ATitle, '%'))); + begin + FQuery.SQL.Add('WHERE "title" LIKE ' + + QuotedStr(AnsiQuotedStr(ATitle, '%')) + ';'); + FFiltered := True; + end + else + FFiltered := False; FQuery.Open; GetRecordCount; except @@ -735,6 +742,11 @@ function TDBDataProcess.Search(ATitle: String): Boolean; WriteLog_E('TDBDataProcess.Search.Error!', E, Self); end; Result := FQuery.Active; + if not Result then + begin + FFiltered := False; + FRecordCount := 0; + end; end; function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; From 4fe2e8150ed484873fe1f1ca167fb10e92eeb810 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 16:21:21 +0800 Subject: [PATCH 0075/2794] mainform, cleanup search method, now searched list marked as filtered --- mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.pas | 56 ++++++------------------------- 2 files changed, 10 insertions(+), 47 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 168b409eb..03d8a0eb1 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3144,7 +3144,6 @@ object MainForm: TMainForm Width = 157 Anchors = [akTop, akLeft, akRight] OnChange = edSearchChange - OnKeyUp = edSearchKeyUp TabOrder = 1 TextHint = 'Search title...' end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 28311f8e7..c44088e24 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -356,7 +356,6 @@ TMainForm = class(TForm) procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure edSearchChange(Sender: TObject); - procedure edSearchKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure edURLKeyPress(Sender: TObject; var Key: Char); procedure edWebsitesSearchChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -4662,55 +4661,20 @@ function TMainForm.SaveMangaOptions: String; procedure TMainForm.edSearchChange(Sender: TObject); begin + if (cbOptionLiveSearch.Checked = False) and (Sender = edSearch) then Exit; if (upcase(edSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb) then Exit; - if edSearch.Text = '' then - begin - LastSearchStr := ''; - //Screen.Cursor := crHourGlass; - vtMangaList.Clear; - dataProcess.Search(edSearch.Text); - vtMangaList.RootNodeCount := dataProcess.RecordCount; - //Screen.Cursor := crDefault; - Exit; - end - else - if cbOptionLiveSearch.Checked then - begin - LastSearchWeb := currentWebsite; - LastSearchStr := upcase(edSearch.Text); - vtMangaList.Clear; - DataProcess.Search(edSearch.Text); - vtMangaList.RootNodeCount := dataProcess.RecordCount; - end; -end; -procedure TMainForm.edSearchKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - if ((upcase(edSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb)) or - cbOptionLiveSearch.Checked then - Exit; + LastSearchWeb := currentWebsite; + LastSearchStr := UpCase(edSearch.Text); - if Key = VK_RETURN then - begin - LastSearchStr := upcase(edSearch.Text); - if edSearch.Text = '' then - begin - Screen.Cursor := crHourGlass; - vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.RecordCount; - Screen.Cursor := crDefault; - end - else - begin - Screen.Cursor := crHourGlass; - LastSearchWeb := currentWebsite; - DataProcess.Search(edSearch.Text); - vtMangaList.Clear; - vtMangaList.RootNodeCount := dataProcess.RecordCount; - Screen.Cursor := crDefault; - end; - end; + vtMangaList.Clear; + dataProcess.Search(edSearch.Text); + vtMangaList.RootNodeCount := dataProcess.RecordCount; + if dataProcess.Filtered then + lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + else + lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); end; procedure TMainForm.UpdateVtChapter; From 636f305a9aa7933ed6fa7f4b11eab1399ddc6038 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 16:31:22 +0800 Subject: [PATCH 0076/2794] mainform, fix re-search after website change --- mangadownloader/forms/frmMain.pas | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c44088e24..0167ad4fe 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1846,8 +1846,6 @@ procedure TMainForm.btChecksClick(Sender: TObject); end; procedure TMainForm.cbSelectMangaChange(Sender: TObject); -var - K: Word; begin if cbSelectManga.ItemIndex < 0 then Exit; @@ -1869,9 +1867,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); dataProcess.website := cbSelectManga.Items[cbSelectManga.ItemIndex]; CheckForTopPanel; LastSearchStr := ''; - K := VK_RETURN; - edSearchKeyUp(edSearch, K, []); - edSearchChange(edSearch); + edSearchChange(cbSelectManga); finally Screen.Cursor := crDefault; end; From b811b1925aefd385b4b5ae1d61be3fc3a87d8494 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 16:43:42 +0800 Subject: [PATCH 0077/2794] tdbdatafilter, canfilter to validate the filter params --- baseunits/uData.pas | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index e7a637192..c497d1edc 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -753,7 +753,20 @@ function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringL const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; begin - Result := True; + Result := False; + if not FQuery.Active then Exit; + if (FRecordCount = 0) or + ((stTitle = '') and + (stAuthors = '') and + (stArtists = '') and + (stSummary = '') and + (stStatus = '2') and + (checkedGenres.Count = 0) and + (uncheckedGenres.Count = 0)) and + (not searchNewManga) then + Result := False + else + Result := True; end; function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; From 72aa947e0d0acd4302d61a395a2ae9b61f64fc60 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 16:59:55 +0800 Subject: [PATCH 0078/2794] tdbdataprocess, filter, add filter title, regexp --- baseunits/uData.pas | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c497d1edc..fadb9413e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -257,6 +257,11 @@ procedure RegexCallback(context: PSqlite3_Context; argc: longint; end; end; +function QuotedLike(const S: string): string; +begin + Result := QuotedStr(AnsiQuotedStr(S, '%')); +end; + procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); var filepath: String; @@ -729,8 +734,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; FQuery.SQL.Add(FSQLSelect); if ATitle <> '' then begin - FQuery.SQL.Add('WHERE "title" LIKE ' + - QuotedStr(AnsiQuotedStr(ATitle, '%')) + ';'); + FQuery.SQL.Add('WHERE "title" LIKE ' + QuotedStr(AnsiQuotedStr(ATitle, '%'))); FFiltered := True; end else @@ -774,25 +778,39 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean): Boolean; - procedure AddSQL(const S: String); + procedure AddSQL(const sqltext: string); begin if FQuery.SQL.Count > 0 then FQuery.SQL.Add('AND'); - FQuery.SQL.Add(S); + FQuery.SQL.Add(sqltext); end; + var + tsql, s: string; begin Result := False; - if FConn.Connected = False then - Exit; + if FQuery.Active = False then Exit; with FQuery do begin - FRecordCount := 0; Close; + FRecordCount := 0; + tsql := SQL.Text; + SQL.Clear; try - SQL.Clear; + // filter new manga based on date if searchNewManga then - AddSQL('jdn > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); + AddSQL('"jdn" > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); + + // filter title + s := LowerCase(Trim(stTitle)); + if s <> '' then + begin + if useRegExpr then + AddSQL('"title" REGEXP ' + QuotedStr(s)) + else + AddSQL('"title" like ' + QuotedLike(s)); + end; + if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); @@ -803,7 +821,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList begin WriteLog_E('TDBDataProcess.Filter.Error!', E, Self); Close; - SQL.Text := FSQLSelect; + SQL.Text := tsql; Open; FFiltered := False; end; From 2a30a636d403cd9f5f4d00d2b112f3157b4eaf46 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 17:09:01 +0800 Subject: [PATCH 0079/2794] tdbdataprocess, using simple method to filter text --- baseunits/uData.pas | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fadb9413e..8dff0832d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -785,6 +785,18 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList FQuery.SQL.Add(sqltext); end; + procedure AddSQLSimpleFilter(const fieldname, value: string); + var + svalue: string; + begin + svalue := LowerCase(Trim(stTitle)); + if (fieldname = '') or (value = '') then Exit; + if useRegExpr then + AddSQL(QuotedStrd(fieldname) + ' REGEXP ' + QuotedStr(svalue)) + else + AddSQL(QuotedStrd(fieldname) + ' LIKE ' + QuotedLike(svalue)); + end; + var tsql, s: string; begin @@ -802,14 +814,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList AddSQL('"jdn" > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); // filter title - s := LowerCase(Trim(stTitle)); - if s <> '' then - begin - if useRegExpr then - AddSQL('"title" REGEXP ' + QuotedStr(s)) - else - AddSQL('"title" like ' + QuotedLike(s)); - end; + AddSQLSimpleFilter('title', stTitle); if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); From 1cf703553c445d1c66f5ce82dbffbab23cdaa73f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 17:22:16 +0800 Subject: [PATCH 0080/2794] tdbdataprocess, filter, fix wrong value --- baseunits/uData.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8dff0832d..b4111f932 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -789,8 +789,8 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList var svalue: string; begin - svalue := LowerCase(Trim(stTitle)); - if (fieldname = '') or (value = '') then Exit; + svalue := LowerCase(Trim(value)); + if (fieldname = '') or (svalue = '') then Exit; if useRegExpr then AddSQL(QuotedStrd(fieldname) + ' REGEXP ' + QuotedStr(svalue)) else @@ -798,7 +798,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList end; var - tsql, s: string; + tsql: string; begin Result := False; if FQuery.Active = False then Exit; From b75b30b6d465a4f11af5f6a62a0879b96e04a836 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 17:23:06 +0800 Subject: [PATCH 0081/2794] mainform, set filter label based on tdbdataprocess filtered status --- mangadownloader/forms/frmMain.pas | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0167ad4fe..f9c79ad84 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2129,16 +2129,12 @@ procedure TMainForm.btFilterClick(Sender: TObject); end; vtMangaList.Clear; - if dataProcess.Filter(checkGenres, uncheckGenres, + dataProcess.Filter(checkGenres, uncheckGenres, edFilterTitle.Text, edFilterAuthors.Text, edFilterArtists.Text, IntToStr(cbFilterStatus.ItemIndex), edFilterSummary.Text, seOptionNewMangaTime.Value, - rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked) then - begin - lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]); - vtMangaList.RootNodeCount := dataProcess.RecordCount; - end; + rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked); except on E: Exception do ExceptionHandler(Self, E); @@ -2146,6 +2142,12 @@ procedure TMainForm.btFilterClick(Sender: TObject); uncheckGenres.Free; checkGenres.Free; Screen.Cursor := crDefault; + + vtMangaList.RootNodeCount := dataProcess.RecordCount; + if dataProcess.Filtered then + lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + else + lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]) end; procedure TMainForm.btFilterResetClick(Sender: TObject); From da5fbfb641c1a73a3162aea9e654818007a8015d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 17:24:16 +0800 Subject: [PATCH 0082/2794] tdbdataprocess, add filter authors, artists, summary --- baseunits/uData.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b4111f932..a347057a4 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -816,6 +816,15 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList // filter title AddSQLSimpleFilter('title', stTitle); + // filter authors + AddSQLSimpleFilter('authors', stAuthors); + + // filter artists + AddSQLSimpleFilter('artists', stArtists); + + // filter summary + AddSQLSimpleFilter('summary', stSummary); + if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); From 3221048ff1ddbdf7e42a564bfdb5b36971fb07ec Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 17:30:27 +0800 Subject: [PATCH 0083/2794] tdbdataprocess, add filter by status --- baseunits/uData.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a347057a4..12a19942b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -825,6 +825,10 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList // filter summary AddSQLSimpleFilter('summary', stSummary); + // filter status + if stStatus <> '2' then + AddSQL('"status"='+ QuotedStr(stStatus)); + if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); From 6d2f8b81c2f7a42094bea2bd704e0ee0d87dde4b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 17:54:08 +0800 Subject: [PATCH 0084/2794] tdbdataprocess, addsimplefilter, add negative param --- baseunits/uData.pas | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 12a19942b..cab8a867d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -785,16 +785,21 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList FQuery.SQL.Add(sqltext); end; - procedure AddSQLSimpleFilter(const fieldname, value: string); + procedure AddSQLSimpleFilter(const fieldname, value: string; useNOT: Boolean = False); var svalue: string; + scond: string; begin svalue := LowerCase(Trim(value)); if (fieldname = '') or (svalue = '') then Exit; + if useNOT then + scond := ' NOT' + else + scond := ''; if useRegExpr then - AddSQL(QuotedStrd(fieldname) + ' REGEXP ' + QuotedStr(svalue)) + AddSQL(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue)) else - AddSQL(QuotedStrd(fieldname) + ' LIKE ' + QuotedLike(svalue)); + AddSQL(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue)); end; var From 30b7a79df4a294b3a307f5de6c410e4e7d422e9d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 18:01:38 +0800 Subject: [PATCH 0085/2794] tdbdataprocess, add filter genres --- baseunits/uData.pas | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index cab8a867d..2560a3e63 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -804,6 +804,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList var tsql: string; + i: Integer; begin Result := False; if FQuery.Active = False then Exit; @@ -834,6 +835,16 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList if stStatus <> '2' then AddSQL('"status"='+ QuotedStr(stStatus)); + //filter checked genres + if checkedGenres.Count > 0 then + for i := 0 to checkedGenres.Count-1 do + AddSQLSimpleFilter('genres', checkedGenres[i]); + + //filter unchecked genres + if uncheckedGenres.Count > 0 then + for i := 0 to uncheckedGenres.Count-1 do + AddSQLSimpleFilter('genres', uncheckedGenres[i], True); + if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); From e8d1a65b579b9106ff8ff2a96f643e6c146663de Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 18:29:53 +0800 Subject: [PATCH 0086/2794] tdbdataprocess, filter genres, consider haveallchecked/haveonechecked --- baseunits/uData.pas | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2560a3e63..2085dca85 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -778,14 +778,24 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean): Boolean; - procedure AddSQL(const sqltext: string); + procedure AddSQL(const sqltext: string; useOR: Boolean = False); begin - if FQuery.SQL.Count > 0 then - FQuery.SQL.Add('AND'); - FQuery.SQL.Add(sqltext); + with FQuery.SQL do + begin + if Count > 0 then + if (Strings[Count-1] <> '(') and (Strings[Count-1] <> ')') then + begin + if useOR then + Add('OR') + else + Add('AND'); + end; + Add(sqltext); + end; end; - procedure AddSQLSimpleFilter(const fieldname, value: string; useNOT: Boolean = False); + procedure AddSQLSimpleFilter(const fieldname, value: string; + useNOT: Boolean = False; useOR: Boolean = False); var svalue: string; scond: string; @@ -797,9 +807,9 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList else scond := ''; if useRegExpr then - AddSQL(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue)) + AddSQL(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue), useOR) else - AddSQL(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue)); + AddSQL(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); end; var @@ -837,13 +847,21 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList //filter checked genres if checkedGenres.Count > 0 then + begin + AddSQL('('); for i := 0 to checkedGenres.Count-1 do - AddSQLSimpleFilter('genres', checkedGenres[i]); + AddSQLSimpleFilter('genres', checkedGenres[i], False, (not haveAllChecked)); + SQL.Add(')') + end; //filter unchecked genres if uncheckedGenres.Count > 0 then + begin + AddSQL('('); for i := 0 to uncheckedGenres.Count-1 do - AddSQLSimpleFilter('genres', uncheckedGenres[i], True); + AddSQLSimpleFilter('genres', uncheckedGenres[i], True, (not haveAllChecked)); + SQL.Add(')'); + end; if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); From 4b952f3e224e28bec336046da71b462c94183cf3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 18:44:59 +0800 Subject: [PATCH 0087/2794] tdbdataprocess, split addsql utils --- baseunits/uData.pas | 94 +++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2085dca85..d45167bd7 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -44,6 +44,9 @@ TDBDataProcess = class(TObject) procedure CreateTable; procedure VacuumTable; procedure GetRecordCount; + procedure AddSQLCond(const sqltext: string; useOR: Boolean = False); + procedure AddSQLSimpleFilter(const fieldname, value: string; + useNOT: Boolean = False; useOR: Boolean = False; useRegexp: Boolean = False); function GetConnected: Boolean; function InternalOpen(const FilePath: String = ''): Boolean; function GetWebsiteName(RecIndex: Integer): String; @@ -400,6 +403,40 @@ procedure TDBDataProcess.GetRecordCount; FRecordCount := 0; end; +procedure TDBDataProcess.AddSQLCond(const sqltext: string; useOR: Boolean); +begin + with FQuery.SQL do + begin + if Count > 0 then + if (Strings[Count-1] <> '(') and (Strings[Count-1] <> ')') then + begin + if useOR then + Add('OR') + else + Add('AND'); + end; + Add(sqltext); + end; +end; + +procedure TDBDataProcess.AddSQLSimpleFilter(const fieldname, value: string; + useNOT: Boolean; useOR: Boolean; useRegexp: Boolean); +var + svalue: string; + scond: string; +begin + svalue := LowerCase(Trim(value)); + if (fieldname = '') or (svalue = '') then Exit; + if useNOT then + scond := ' NOT' + else + scond := ''; + if useRegexp then + AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue), useOR) + else + AddSQLCond(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); +end; + function TDBDataProcess.GetConnected: Boolean; begin Result := FConn.Connected; @@ -777,41 +814,6 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean): Boolean; - - procedure AddSQL(const sqltext: string; useOR: Boolean = False); - begin - with FQuery.SQL do - begin - if Count > 0 then - if (Strings[Count-1] <> '(') and (Strings[Count-1] <> ')') then - begin - if useOR then - Add('OR') - else - Add('AND'); - end; - Add(sqltext); - end; - end; - - procedure AddSQLSimpleFilter(const fieldname, value: string; - useNOT: Boolean = False; useOR: Boolean = False); - var - svalue: string; - scond: string; - begin - svalue := LowerCase(Trim(value)); - if (fieldname = '') or (svalue = '') then Exit; - if useNOT then - scond := ' NOT' - else - scond := ''; - if useRegExpr then - AddSQL(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue), useOR) - else - AddSQL(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); - end; - var tsql: string; i: Integer; @@ -827,39 +829,41 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList try // filter new manga based on date if searchNewManga then - AddSQL('"jdn" > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); + AddSQLCond('"jdn" > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); // filter title - AddSQLSimpleFilter('title', stTitle); + AddSQLSimpleFilter('title', stTitle, False, False, useRegExpr); // filter authors - AddSQLSimpleFilter('authors', stAuthors); + AddSQLSimpleFilter('authors', stAuthors, False, False, useRegExpr); // filter artists - AddSQLSimpleFilter('artists', stArtists); + AddSQLSimpleFilter('artists', stArtists, False, False, useRegExpr); // filter summary - AddSQLSimpleFilter('summary', stSummary); + AddSQLSimpleFilter('summary', stSummary, False, False, useRegExpr); // filter status if stStatus <> '2' then - AddSQL('"status"='+ QuotedStr(stStatus)); + AddSQLCond('"status"='+ QuotedStr(stStatus)); //filter checked genres if checkedGenres.Count > 0 then begin - AddSQL('('); + AddSQLCond('('); for i := 0 to checkedGenres.Count-1 do - AddSQLSimpleFilter('genres', checkedGenres[i], False, (not haveAllChecked)); + AddSQLSimpleFilter('genres', checkedGenres[i], False, + (not haveAllChecked), useRegExpr); SQL.Add(')') end; //filter unchecked genres if uncheckedGenres.Count > 0 then begin - AddSQL('('); + AddSQLCond('('); for i := 0 to uncheckedGenres.Count-1 do - AddSQLSimpleFilter('genres', uncheckedGenres[i], True, (not haveAllChecked)); + AddSQLSimpleFilter('genres', uncheckedGenres[i], True, + (not haveAllChecked), useRegExpr); SQL.Add(')'); end; From 5a88163d91b932f1758b052aafadf591fb16f954 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 18:51:15 +0800 Subject: [PATCH 0088/2794] tdbdataprocess, fix filter condition --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d45167bd7..c42a4b74f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -408,7 +408,7 @@ procedure TDBDataProcess.AddSQLCond(const sqltext: string; useOR: Boolean); with FQuery.SQL do begin if Count > 0 then - if (Strings[Count-1] <> '(') and (Strings[Count-1] <> ')') then + if (Strings[Count-1] <> '(') then begin if useOR then Add('OR') From 2b2581c327497f293d1617395aeb1fff90b888df Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 19:11:40 +0800 Subject: [PATCH 0089/2794] mainform, filter remove seearch text, identify with tag -1 = ignore 0 = normal 1 = forced --- mangadownloader/forms/frmMain.pas | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f9c79ad84..8521bf2a5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2128,6 +2128,8 @@ procedure TMainForm.btFilterClick(Sender: TObject); dataProcess.FilterAllSites := True; end; + edSearch.Tag := -1; + edSearch.Clear; vtMangaList.Clear; dataProcess.Filter(checkGenres, uncheckGenres, edFilterTitle.Text, edFilterAuthors.Text, @@ -4659,7 +4661,12 @@ function TMainForm.SaveMangaOptions: String; procedure TMainForm.edSearchChange(Sender: TObject); begin - if (cbOptionLiveSearch.Checked = False) and (Sender = edSearch) then Exit; + if edSearch.Tag = -1 then + begin + edSearch.Tag := 0; + Exit; + end; + if not cbOptionLiveSearch.Checked then Exit; if (upcase(edSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb) then Exit; From d7d58de7b7fb0d0633b40c1ef2ef0f4b8b116b29 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 19:30:42 +0800 Subject: [PATCH 0090/2794] mainform, edsearch, force search when vk_return pressed, in case live search is disabled --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 03d8a0eb1..93bc02c83 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3144,6 +3144,7 @@ object MainForm: TMainForm Width = 157 Anchors = [akTop, akLeft, akRight] OnChange = edSearchChange + OnKeyDown = edSearchKeyDown TabOrder = 1 TextHint = 'Search title...' end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8521bf2a5..52aae409f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -356,6 +356,8 @@ TMainForm = class(TForm) procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure edSearchChange(Sender: TObject); + procedure edSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState + ); procedure edURLKeyPress(Sender: TObject; var Key: Char); procedure edWebsitesSearchChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -4666,7 +4668,9 @@ procedure TMainForm.edSearchChange(Sender: TObject); edSearch.Tag := 0; Exit; end; - if not cbOptionLiveSearch.Checked then Exit; + if (not cbOptionLiveSearch.Checked) and (edSearch.Tag = 0) then Exit; + if edSearch.Tag <> 0 then + edSearch.Tag := 0; if (upcase(edSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb) then Exit; @@ -4682,6 +4686,16 @@ procedure TMainForm.edSearchChange(Sender: TObject); lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); end; +procedure TMainForm.edSearchKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if Key = VK_RETURN then + begin + edSearch.Tag := 1; + edSearchChange(edSearch); + end; +end; + procedure TMainForm.UpdateVtChapter; begin clbChapterList.Clear; From 7c057da19dedc91de9169b709a58ecf63ad5e9be Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 21:19:11 +0800 Subject: [PATCH 0091/2794] mainform, force search on clear --- mangadownloader/forms/frmMain.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 52aae409f..b6f686718 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1811,6 +1811,7 @@ procedure TMainForm.btReadOnlineClick(Sender: TObject); procedure TMainForm.btSearchClearClick(Sender: TObject); begin + edSearch.Tag := 1; edSearch.Clear; end; @@ -2058,7 +2059,8 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); end; vtMangaList.RootNodeCount := dataProcess.RecordCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); - edSearch.Text := ''; + edSearch.Tag := -1; + edSearch.Clear; except on E: Exception do ExceptionHandler(Self, E); From 7a0694054f81cd11d89ca417be9152249c42506c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 21:20:32 +0800 Subject: [PATCH 0092/2794] tdbdataprocess, consider to search within filter --- baseunits/uData.pas | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c42a4b74f..abaef02a3 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -40,6 +40,8 @@ TDBDataProcess = class(TObject) FFilterAllSites: Boolean; FSitesList: TStringList; FSQLSelect: String; + FFilterApplied: Boolean; + FFilterSQL: String; protected procedure CreateTable; procedure VacuumTable; @@ -408,7 +410,8 @@ procedure TDBDataProcess.AddSQLCond(const sqltext: string; useOR: Boolean); with FQuery.SQL do begin if Count > 0 then - if (Strings[Count-1] <> '(') then + if (Strings[Count-1] <> '(') and + (UpCase(Trim(Strings[Count-1])) <> 'WHERE') then begin if useOR then Add('OR') @@ -510,6 +513,8 @@ constructor TDBDataProcess.Create; FTableName := 'masterlist'; FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FRecordCount := 0; + FFilterApplied := False; + FFilterSQL := ''; end; destructor TDBDataProcess.Destroy; @@ -768,14 +773,19 @@ function TDBDataProcess.Search(ATitle: String): Boolean; try FQuery.Close; FQuery.SQL.Clear; - FQuery.SQL.Add(FSQLSelect); + if not FFilterApplied then + FQuery.SQL.Add(FSQLSelect) + else + FQuery.SQL.AddText(FFilterSQL); if ATitle <> '' then begin - FQuery.SQL.Add('WHERE "title" LIKE ' + QuotedStr(AnsiQuotedStr(ATitle, '%'))); + if not FFilterApplied then + FQuery.SQL.Add('WHERE'); + AddSQLSimpleFilter('title', ATitle); FFiltered := True; end else - FFiltered := False; + FFiltered := FFilterApplied; FQuery.Open; GetRecordCount; except @@ -822,7 +832,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList if FQuery.Active = False then Exit; with FQuery do begin - Close; + FQuery.Close; FRecordCount := 0; tsql := SQL.Text; SQL.Clear; @@ -870,16 +880,23 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList if Trim(SQL.Text) <> '' then SQL.Insert(0, 'WHERE'); SQL.Insert(0, FSQLSelect); - Open; + FQuery.Open; FFiltered := Active; + FFilterApplied := FFiltered; + if FFilterApplied then + FFilterSQL := SQL.Text + else + FFilterSQL := ''; except on E: Exception do begin WriteLog_E('TDBDataProcess.Filter.Error!', E, Self); - Close; + FQuery.Close; SQL.Text := tsql; - Open; + FQuery.Open; FFiltered := False; + FFilterApplied := False; + FFilterSQL := ''; end; end; GetRecordCount; @@ -923,6 +940,8 @@ procedure TDBDataProcess.GetFieldNames(List: TStringList); procedure TDBDataProcess.RemoveFilter; begin FFiltered := False; + FFilterApplied := False; + FFilterSQL := ''; OpenTable; GetRecordCount; end; From 4b034b10798c9d56115004f2d4578399035f2ce6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 21:42:36 +0800 Subject: [PATCH 0093/2794] tdbdataprocess, log sql syntax on error --- baseunits/uData.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index abaef02a3..da6374080 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -790,7 +790,8 @@ function TDBDataProcess.Search(ATitle: String): Boolean; GetRecordCount; except on E: Exception do - WriteLog_E('TDBDataProcess.Search.Error!', E, Self); + WriteLog_E('TDBDataProcess.Search.Error!'#13#10 + + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); end; Result := FQuery.Active; if not Result then @@ -890,7 +891,8 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList except on E: Exception do begin - WriteLog_E('TDBDataProcess.Filter.Error!', E, Self); + WriteLog_E('TDBDataProcess.Filter.Error!'#13#10 + + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); FQuery.Close; SQL.Text := tsql; FQuery.Open; From 9059858e0529cf967969fe8d97752e6a0ff2a18f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 21:53:01 +0800 Subject: [PATCH 0094/2794] tdbdataprocess, prevent filter default value --- baseunits/uData.pas | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index da6374080..c165e61b1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -63,7 +63,7 @@ TDBDataProcess = class(TObject) function Search(ATitle: String): Boolean; function CanFilter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; + const {%H-}minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; function Filter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; @@ -807,15 +807,15 @@ function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringL begin Result := False; if not FQuery.Active then Exit; - if (FRecordCount = 0) or - ((stTitle = '') and + if ((stTitle = '') and (stAuthors = '') and (stArtists = '') and (stSummary = '') and (stStatus = '2') and (checkedGenres.Count = 0) and (uncheckedGenres.Count = 0)) and - (not searchNewManga) then + (not searchNewManga) and + haveAllChecked then Result := False else Result := True; @@ -831,6 +831,9 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList begin Result := False; if FQuery.Active = False then Exit; + if not CanFilter(checkedGenres, uncheckedGenres, stTitle, stAuthors, + stArtists, stStatus, stSummary, minusDay, haveAllChecked, searchNewManga) then + Exit; with FQuery do begin FQuery.Close; @@ -941,11 +944,14 @@ procedure TDBDataProcess.GetFieldNames(List: TStringList); procedure TDBDataProcess.RemoveFilter; begin - FFiltered := False; - FFilterApplied := False; - FFilterSQL := ''; - OpenTable; - GetRecordCount; + if FFiltered then + begin + FFiltered := False; + FFilterApplied := False; + FFilterSQL := ''; + OpenTable; + GetRecordCount; + end; end; procedure TDBDataProcess.Sort; From e22759db931648beaab29f5f23f2e267c8588f11 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:11:52 +0800 Subject: [PATCH 0095/2794] mainform, fix filter/remove filter --- mangadownloader/forms/frmMain.pas | 70 ++++++++++++++++++------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b6f686718..a31acca12 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2073,8 +2073,9 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); procedure TMainForm.btFilterClick(Sender: TObject); var - checkGenres, uncheckGenres: TStringList; - i: Cardinal; + checkGenres, + uncheckGenres: TStringList; + i: Integer; s: String; begin Screen.Cursor := crHourGlass; @@ -2085,8 +2086,8 @@ procedure TMainForm.btFilterClick(Sender: TObject); checkGenres.Add(Trim(edCustomGenres.Text)) else begin - //CustomGenres(checkGenres, edCustomGenres.Text); - ExtractStrings([',', ';'], [], PChar(edCustomGenres.Text), checkGenres); + checkGenres.Delimiter := ','; + checkGenres.DelimitedText := edCustomGenres.Text; TrimStrings(checkGenres); i := 0; while i < checkGenres.Count do @@ -2114,33 +2115,41 @@ procedure TMainForm.btFilterClick(Sender: TObject); uncheckGenres.Add(TCheckBox(pnGenres.Controls[i]).Caption); end; - // we will reload the list if search from all websites is enabled - if cbSearchFromAllSites.Checked then + if dataProcess.CanFilter( + checkGenres, + uncheckGenres, + edFilterTitle.Text, + edFilterAuthors.Text, + edFilterArtists.Text, + IntToStr(cbFilterStatus.ItemIndex), + edFilterSummary.Text, + seOptionNewMangaTime.Value, + rbAll.Checked, + cbOnlyNew.Checked) then begin - if not dataProcess.CanFilter(checkGenres, uncheckGenres, - edFilterTitle.Text, edFilterAuthors.Text, - edFilterArtists.Text, IntToStr(cbFilterStatus.ItemIndex), - edFilterSummary.Text, - seOptionNewMangaTime.Value, - rbAll.Checked, cbOnlyNew.Checked) then + if cbSearchFromAllSites.Checked then begin - uncheckGenres.Free; - checkGenres.Free; - Exit; + dataProcess.SitesList.Assign(cbSelectManga.Items); + dataProcess.FilterAllSites := True; end; - dataProcess.SitesList.Assign(cbSelectManga.Items); - dataProcess.FilterAllSites := True; - end; - edSearch.Tag := -1; - edSearch.Clear; - vtMangaList.Clear; - dataProcess.Filter(checkGenres, uncheckGenres, - edFilterTitle.Text, edFilterAuthors.Text, - edFilterArtists.Text, IntToStr(cbFilterStatus.ItemIndex), - edFilterSummary.Text, - seOptionNewMangaTime.Value, - rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked); + edSearch.Tag := -1; + edSearch.Clear; + vtMangaList.Clear; + + dataProcess.Filter( + checkGenres, + uncheckGenres, + edFilterTitle.Text, + edFilterAuthors.Text, + edFilterArtists.Text, + IntToStr(cbFilterStatus.ItemIndex), + edFilterSummary.Text, + seOptionNewMangaTime.Value, + rbAll.Checked, + cbOnlyNew.Checked, + cbUseRegExpr.Checked); + end; except on E: Exception do ExceptionHandler(Self, E); @@ -4668,6 +4677,8 @@ procedure TMainForm.edSearchChange(Sender: TObject); if edSearch.Tag = -1 then begin edSearch.Tag := 0; + LastSearchWeb := currentWebsite; + LastSearchStr := UpCase(edSearch.Text); Exit; end; if (not cbOptionLiveSearch.Checked) and (edSearch.Tag = 0) then Exit; @@ -4695,7 +4706,10 @@ procedure TMainForm.edSearchKeyDown(Sender: TObject; var Key: Word; begin edSearch.Tag := 1; edSearchChange(edSearch); - end; + end + else + if edSearch.Tag <> 0 then + edSearch.Tag := 0; end; procedure TMainForm.UpdateVtChapter; From a74d2bb14735c3f79ae4f134c44428cb9ec0972b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:35:52 +0800 Subject: [PATCH 0096/2794] tdbdataprocess, add connect method, for connect only --- baseunits/uData.pas | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c165e61b1..f71aa446f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -57,6 +57,7 @@ TDBDataProcess = class(TObject) constructor Create; destructor Destroy; override; + function Connect(AWebsite: String): Boolean; function Open(AWebsite: String = ''): Boolean; function OpenTable(const ATableName: String = ''): Boolean; function TableExist(const ATableName: String): Boolean; @@ -538,6 +539,20 @@ destructor TDBDataProcess.Destroy; inherited Destroy; end; +function TDBDataProcess.Connect(AWebsite: String): Boolean; +var + filepath: string; +begin + Result := False; + if AWebsite <> '' then + FWebsite := AWebsite; + if FWebsite = '' then + Exit; + filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + if not FileExistsUTF8(filepath) Then Exit; + Result := InternalOpen(filepath); +end; + function TDBDataProcess.Open(AWebsite: String): Boolean; var filepath: String; From 6f3d4a8c8d1ae6599ce121503c870e0a4649dede Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:36:20 +0800 Subject: [PATCH 0097/2794] updatethread, use connect and opentable only if needed --- baseunits/uUpdateThread.pas | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index c0b5e9895..480e07992 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -540,12 +540,8 @@ procedure TUpdateMangaManagerThread.Execute; else CopyDBDataProcess(website, twebsite); - if not mainDataProcess.Open(twebsite) then - begin + if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); - mainDataProcess.OpenTable; - end; - mainDataProcess.Refresh(True); //get directory page count INIAdvanced.Reload; @@ -613,6 +609,7 @@ procedure TUpdateMangaManagerThread.Execute; end; end; + mainDataProcess.OpenTable; // remove duplicate found<>current database if links.Count > 0 then begin @@ -633,6 +630,7 @@ procedure TUpdateMangaManagerThread.Execute; Inc(j); end; end; + mainDataProcess.CloseTable; //get manga info if links.Count > 0 then From 88c47efd87d416bf986d1025b483d92a6283b599 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:47:26 +0800 Subject: [PATCH 0098/2794] tdbdataprocess, convert data don't need to opentable --- baseunits/uData.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index f71aa446f..9ffebf888 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -296,7 +296,6 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); end; dbdata.Commit; end; - dbdata.OpenTable; dbdata.Sort; finally rawdata.Free; From a80894973a73fed67dbb2d878f70fa4a2170544e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:51:55 +0800 Subject: [PATCH 0099/2794] tdbdataprocess, add parameter checkrecordcount on opentable --- baseunits/uData.pas | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9ffebf888..5379b8e64 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -59,7 +59,7 @@ TDBDataProcess = class(TObject) function Connect(AWebsite: String): Boolean; function Open(AWebsite: String = ''): Boolean; - function OpenTable(const ATableName: String = ''): Boolean; + function OpenTable(const ATableName: String = ''; CheckRecordCount: Boolean = False): Boolean; function TableExist(const ATableName: String): Boolean; function Search(ATitle: String): Boolean; function CanFilter(const checkedGenres, uncheckedGenres: TStringList; @@ -574,8 +574,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; begin if not TableExist(FTableName) then CreateTable; - OpenTable; - GetRecordCount; + OpenTable(FTableName, True); end; Result := FQuery.Active; except @@ -584,7 +583,8 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; end; end; -function TDBDataProcess.OpenTable(const ATableName: String): Boolean; +function TDBDataProcess.OpenTable(const ATableName: String; + CheckRecordCount: Boolean): Boolean; begin Result := False; if FConn.Connected then @@ -601,6 +601,8 @@ function TDBDataProcess.OpenTable(const ATableName: String): Boolean; FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FQuery.SQL.Text := FSQLSelect; FQuery.Open; + if CheckRecordCount then + GetRecordCount; end; except on E: Exception do From 343da7373b50f44fc9f1bbd569d868c29b55f66b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:54:46 +0800 Subject: [PATCH 0100/2794] mainform, set label list count to 0 before open another list --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a31acca12..70a3fbca5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1860,6 +1860,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); if dataProcess = nil then dataProcess := TDBDataProcess.Create; vtMangaList.Clear; + lbMode.Caption := Format(RS_ModeAll, [0]); if not dataProcess.Open( cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]) then RunGetList; From 4086a4df1a2e1f2e088ef18ecd2de6b03be511eb Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 22:57:36 +0800 Subject: [PATCH 0101/2794] updatethread, open table and check record count --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 480e07992..7fe0f844f 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -609,7 +609,7 @@ procedure TUpdateMangaManagerThread.Execute; end; end; - mainDataProcess.OpenTable; + mainDataProcess.OpenTable('', True); // remove duplicate found<>current database if links.Count > 0 then begin From 88d5c09235518a8747b8303cea78a4e05c30e685 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 23:07:54 +0800 Subject: [PATCH 0102/2794] tdbdataprocess, commit every 500 record on convertdatadb --- baseunits/uData.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5379b8e64..aa4c3920c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -273,6 +273,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); filepath: String; rawdata: TDataProcess; dbdata: TDBDataProcess; + rcount: Integer; i: Integer; begin filepath := fmdDirectory + DATA_FOLDER + AWebsite; @@ -288,11 +289,18 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); if rawdata.Data.Count > 0 then with rawdata do begin + rcount := 0; for i := 0 to Data.Count-1 do begin dbdata.AddData(Title[i], Link[i], Authors[i], Artists[i], Genres[i], Status[i], StringBreaks(Summary[i]), StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), {%H-}Integer(JDN[i])-3); + Inc(rcount); + if rcount > 499 then + begin + rcount := 0; + dbdata.Commit; + end; end; dbdata.Commit; end; From 448b33ebd4ca51256bd06d53c66bdff55e1981d5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 23:12:31 +0800 Subject: [PATCH 0103/2794] updatethread, commit every 500 record for without info and 20 for with info --- baseunits/uUpdateThread.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 7fe0f844f..2e8049ff8 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -66,7 +66,7 @@ TUpdateMangaManagerThread = class(TFMDThread) CS_threads: TCriticalSection; constructor Create; destructor Destroy; override; - procedure CheckCommit; + procedure CheckCommit(const CommitCount: Integer = 20); end; resourcestring @@ -310,10 +310,10 @@ destructor TUpdateMangaManagerThread.Destroy; inherited Destroy; end; -procedure TUpdateMangaManagerThread.CheckCommit; +procedure TUpdateMangaManagerThread.CheckCommit(const CommitCount: Integer); begin Inc(FCommitCount); - if FCommitCount > 19 then + if FCommitCount >= CommitCount then begin FCommitCount := 0; if Assigned(mainDataProcess) then @@ -652,6 +652,7 @@ procedure TUpdateMangaManagerThread.Execute; 0, Now ); + CheckCommit(500); end; end else @@ -660,8 +661,7 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(links.Count, CS_INFO); end; WaitForThreads; - if FCommitCount > 0 then - mainDataProcess.Commit; + mainDataProcess.Commit; end; mainDataProcess.Refresh; From 72aacaf483916231c5b07bd92a27b64be211c521 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 23:39:43 +0800 Subject: [PATCH 0104/2794] tdbdataprocess, change convert db commit rate to 2000 --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index aa4c3920c..f65a82891 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -296,7 +296,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); Status[i], StringBreaks(Summary[i]), StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), {%H-}Integer(JDN[i])-3); Inc(rcount); - if rcount > 499 then + if rcount >= 2000 then begin rcount := 0; dbdata.Commit; From 6cd7dd6505e76b82cd25c42685c113d19a74e152 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 11 Jul 2015 23:40:50 +0800 Subject: [PATCH 0105/2794] updatethread, change commit rate for without info to 1000 --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 2e8049ff8..6ac22bcd1 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -652,7 +652,7 @@ procedure TUpdateMangaManagerThread.Execute; 0, Now ); - CheckCommit(500); + CheckCommit(1000); end; end else From 16a1e378b42ac2805e145949223205012ae7b5c5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 12 Jul 2015 01:52:09 +0800 Subject: [PATCH 0106/2794] updatethread, change commit rate to 32/2000 --- baseunits/uUpdateThread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 6ac22bcd1..71fe62c4c 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -66,7 +66,7 @@ TUpdateMangaManagerThread = class(TFMDThread) CS_threads: TCriticalSection; constructor Create; destructor Destroy; override; - procedure CheckCommit(const CommitCount: Integer = 20); + procedure CheckCommit(const CommitCount: Integer = 32); end; resourcestring @@ -652,7 +652,7 @@ procedure TUpdateMangaManagerThread.Execute; 0, Now ); - CheckCommit(1000); + CheckCommit(2000); end; end else From 22a2b3d275104ff17797d30f4576e64be8b38a1a Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 12 Jul 2015 01:52:38 +0800 Subject: [PATCH 0107/2794] tdbdataprocess, change commit rate on convertdata to 5000 --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index f65a82891..a92cb2970 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -296,7 +296,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); Status[i], StringBreaks(Summary[i]), StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), {%H-}Integer(JDN[i])-3); Inc(rcount); - if rcount >= 2000 then + if rcount >= 5000 then begin rcount := 0; dbdata.Commit; From 9219798a84499dc3dd3e51d623694279dfac898b Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 06:02:58 +0800 Subject: [PATCH 0108/2794] tdbdataprocess, add filterallsites --- baseunits/uData.pas | 141 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 114 insertions(+), 27 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a92cb2970..b86e9cbaf 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -38,9 +38,10 @@ TDBDataProcess = class(TObject) FRecordCount: Integer; FFiltered: Boolean; FFilterAllSites: Boolean; + FFilterApplied: Boolean; FSitesList: TStringList; + FAttachedSites: TStringList; FSQLSelect: String; - FFilterApplied: Boolean; FFilterSQL: String; protected procedure CreateTable; @@ -53,6 +54,8 @@ TDBDataProcess = class(TObject) function InternalOpen(const FilePath: String = ''): Boolean; function GetWebsiteName(RecIndex: Integer): String; function GetValue(RecIndex, FieldIndex: Integer): String; + procedure AttachAllSites; + procedure DetachAllSites; public constructor Create; destructor Destroy; override; @@ -209,6 +212,7 @@ TMangaInformation = class(TObject) 'numchapter INTEGER,'+ 'jdn INTEGER);'; + function DBDataFilePath(const AWebsite: string): string; procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); function DBDataProcessExist(const AWebsite: string): Boolean; procedure CopyDBDataProcess(const AWebsite, NWebsite: string); @@ -268,6 +272,11 @@ function QuotedLike(const S: string): string; Result := QuotedStr(AnsiQuotedStr(S, '%')); end; +function DBDataFilePath(const AWebsite: string): string; +begin + Result := fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT; +end; + procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); var filepath: String; @@ -480,10 +489,13 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; begin Result := FWebsite; - if FConn.Connected and FilterAllSites and Filtered then - begin - - end; + if FConn.Connected and (FAttachedSites.Count > 0) and (FQuery.Active) then + try + Result := FQuery.FieldByName('website').AsString; + except + on E: Exception do + WriteLog_E('TDBDataProcess.GetWebsiteName', E, Self); + end; end; function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; @@ -506,6 +518,40 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; end; end; +procedure TDBDataProcess.AttachAllSites; +var + i: Integer; +begin + DetachAllSites; + if FConn.Connected and (SitesList.Count > 0) then + begin + FConn.ExecuteDirect('END TRANSACTION'); + for i := 0 to SitesList.Count-1 do + if FileExistsUTF8(DBDataFilePath(SitesList[i])) then + begin + FConn.ExecuteDirect('ATTACH ' + QuotedStrd(DBDataFilePath(SitesList[i])) + + ' AS ' + QuotedStrd(SitesList[i])); + FAttachedSites.Add(SitesList[i]); + end; + FConn.ExecuteDirect('BEGIN TRANSACTION'); + end; +end; + +procedure TDBDataProcess.DetachAllSites; +var + i: Integer; +begin + if FConn.Connected and (FAttachedSites.Count > 0) then + begin + FConn.ExecuteDirect('END TRANSACTION'); + repeat + FConn.ExecuteDirect('DETACH '+ QuotedStrd(FAttachedSites[FAttachedSites.Count-1])); + FAttachedSites.Delete(FAttachedSites.Count-1); + until FAttachedSites.Count = 0; + FConn.ExecuteDirect('BEGIN TRANSACTION'); + end; +end; + constructor TDBDataProcess.Create; begin inherited Create; @@ -518,6 +564,7 @@ constructor TDBDataProcess.Create; FRegxp := TRegExpr.Create; FRegxp.ModifierI := True; FSitesList := TStringList.Create; + FAttachedSites := TStringList.Create; FTableName := 'masterlist'; FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FRecordCount := 0; @@ -531,6 +578,7 @@ destructor TDBDataProcess.Destroy; if FConn.Connected then begin FQuery.Close; + DetachAllSites; Commit; Close; end; @@ -538,6 +586,7 @@ destructor TDBDataProcess.Destroy; on E: Exception do WriteLog_E('TDBDataProcess.Destroy.Error!', E, Self); end; + FAttachedSites.Free; FSitesList.Free; FQuery.Free; FTrans.Free; @@ -646,6 +695,7 @@ procedure TDBDataProcess.Close; if FConn.Connected then try FQuery.Close; + DetachAllSites; FConn.Close; FConn.DatabaseName := ''; except @@ -852,20 +902,13 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList var tsql: string; i: Integer; -begin - Result := False; - if FQuery.Active = False then Exit; - if not CanFilter(checkedGenres, uncheckedGenres, stTitle, stAuthors, - stArtists, stStatus, stSummary, minusDay, haveAllChecked, searchNewManga) then - Exit; - with FQuery do + filtersingle: Boolean = True; + + procedure GenerateSQLFilter; + var + j: Integer; begin - FQuery.Close; - FRecordCount := 0; - tsql := SQL.Text; - SQL.Clear; - try - // filter new manga based on date + // filter new manga based on date if searchNewManga then AddSQLCond('"jdn" > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); @@ -889,25 +932,68 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList if checkedGenres.Count > 0 then begin AddSQLCond('('); - for i := 0 to checkedGenres.Count-1 do - AddSQLSimpleFilter('genres', checkedGenres[i], False, + for j := 0 to checkedGenres.Count-1 do + AddSQLSimpleFilter('genres', checkedGenres[j], False, (not haveAllChecked), useRegExpr); - SQL.Add(')') + FQuery.SQL.Add(')'); end; //filter unchecked genres if uncheckedGenres.Count > 0 then begin AddSQLCond('('); - for i := 0 to uncheckedGenres.Count-1 do - AddSQLSimpleFilter('genres', uncheckedGenres[i], True, + for j := 0 to uncheckedGenres.Count-1 do + AddSQLSimpleFilter('genres', uncheckedGenres[j], True, (not haveAllChecked), useRegExpr); - SQL.Add(')'); + FQuery.SQL.Add(')'); + end; + end; + +begin + Result := False; + if FQuery.Active = False then Exit; + if not CanFilter(checkedGenres, uncheckedGenres, stTitle, stAuthors, + stArtists, stStatus, stSummary, minusDay, haveAllChecked, searchNewManga) then + Exit; + with FQuery do + begin + FQuery.Close; + FRecordCount := 0; + tsql := SQL.Text; + SQL.Clear; + try + if FFilterAllSites and (FSitesList.Count > 0) then + begin + AttachAllSites; + if FAttachedSites.Count > 0 then + begin + SQL.Add('SELECT * FROM'); + SQL.Add('('); + SQL.Add('SELECT *, ' + QuotedStr(FWebsite) + ' AS ''website'' FROM ' + + QuotedStrd(FTableName)); + SQL.Add('WHERE'); + GenerateSQLFilter; + for i := 0 to FAttachedSites.Count-1 do + begin + SQL.Add('UNION ALL'); + SQL.Add('SELECT *, ' + QuotedStr(FAttachedSites[i]) + ' AS ''website'' FROM ' + + FAttachedSites[i] + '.' + QuotedStrd(FTableName)); + SQL.Add('WHERE'); + GenerateSQLFilter; + end; + SQL.Add(')'); + SQL.Add('ORDER BY ''title'' COLLATE NATCMP'); + filtersingle := False; + end; + end; + + if filtersingle then + begin + SQL.Add(FSQLSelect); + SQL.Add('WHERE'); + GenerateSQLFilter; end; - if Trim(SQL.Text) <> '' then - SQL.Insert(0, 'WHERE'); - SQL.Insert(0, FSQLSelect); FQuery.Open; FFiltered := Active; FFilterApplied := FFiltered; @@ -973,6 +1059,7 @@ procedure TDBDataProcess.RemoveFilter; FFiltered := False; FFilterApplied := False; FFilterSQL := ''; + DetachAllSites; OpenTable; GetRecordCount; end; From 67b48a098dd306b854bfd3a9f0d982e594271117 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 06:04:02 +0800 Subject: [PATCH 0109/2794] mainform, enable filter all sites --- mangadownloader/forms/frmMain.lfm | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 93bc02c83..ab0e3716d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1451,7 +1451,6 @@ object MainForm: TMainForm Width = 149 Caption = 'Search in all manga sites' TabOrder = 9 - Visible = False end object btFilter: TBitBtn Left = 39 From 3fb093d9e7ff9249a8b477d4f90987942617a188 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 06:11:19 +0800 Subject: [PATCH 0110/2794] tdbdataprocess, fix sorting filter all sites --- baseunits/uData.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b86e9cbaf..65f856237 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -969,20 +969,20 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList begin SQL.Add('SELECT * FROM'); SQL.Add('('); - SQL.Add('SELECT *, ' + QuotedStr(FWebsite) + ' AS ''website'' FROM ' + + SQL.Add('SELECT *, ' + QuotedStrd(FWebsite) + ' AS "website" FROM ' + QuotedStrd(FTableName)); SQL.Add('WHERE'); GenerateSQLFilter; for i := 0 to FAttachedSites.Count-1 do begin SQL.Add('UNION ALL'); - SQL.Add('SELECT *, ' + QuotedStr(FAttachedSites[i]) + ' AS ''website'' FROM ' + + SQL.Add('SELECT *, ' + QuotedStrd(FAttachedSites[i]) + ' AS "website" FROM ' + FAttachedSites[i] + '.' + QuotedStrd(FTableName)); SQL.Add('WHERE'); GenerateSQLFilter; end; SQL.Add(')'); - SQL.Add('ORDER BY ''title'' COLLATE NATCMP'); + SQL.Add('ORDER BY "title" COLLATE NATCMP'); filtersingle := False; end; end; From f5ceee43e4349f9b43715cc4a7be2cb566876482 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 15:18:31 +0800 Subject: [PATCH 0111/2794] tdbdataprocess, refresh in multi db attached --- baseunits/uData.pas | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 65f856237..289366dad 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -88,7 +88,6 @@ TDBDataProcess = class(TObject) procedure UpdateData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer); procedure Commit; - procedure ApplyUpdates(RecheckDataCount: Boolean = False); procedure RemoveFilter; procedure Sort; @@ -538,14 +537,18 @@ procedure TDBDataProcess.AttachAllSites; end; procedure TDBDataProcess.DetachAllSites; -var - i: Integer; begin if FConn.Connected and (FAttachedSites.Count > 0) then begin FConn.ExecuteDirect('END TRANSACTION'); repeat - FConn.ExecuteDirect('DETACH '+ QuotedStrd(FAttachedSites[FAttachedSites.Count-1])); + try + FConn.ExecuteDirect('DETACH '+ QuotedStrd(FAttachedSites[FAttachedSites.Count-1])); + except + on E: Exception do + Writelog_E('TDBDataProcess.DetachAllSites:'+FAttachedSites[FAttachedSites.Count-1], + E, Self); + end; FAttachedSites.Delete(FAttachedSites.Count-1); until FAttachedSites.Count = 0; FConn.ExecuteDirect('BEGIN TRANSACTION'); @@ -616,7 +619,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; Result := False; FFiltered := False; FRecordCount := 0; - Close; + Self.Close; if AWebsite <> '' then FWebsite := AWebsite; if FWebsite = '' then @@ -739,7 +742,8 @@ procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); if FQuery.Active then FQuery.Refresh else - OpenTable; + if Trim(FQuery.SQL.Text) <> '' then + FQuery.Open; if RecheckDataCount then GetRecordCount; end; @@ -827,20 +831,6 @@ procedure TDBDataProcess.Commit; end; end; -procedure TDBDataProcess.ApplyUpdates(RecheckDataCount: Boolean); -begin - if FQuery.Active then - try - FQuery.ApplyUpdates; - Commit; - except - on E: Exception do - WriteLog_E('TDBDataProcess.ApplyUpdates.Error!', E, Self); - end; - if RecheckDataCount then - GetRecordCount; -end; - function TDBDataProcess.Search(ATitle: String): Boolean; begin if FQuery.Active then From 330963436c7d3f0d6e69964744542299137f4f9a Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 15:25:08 +0800 Subject: [PATCH 0112/2794] tdbdataprocess, add allsitesattached --- baseunits/uData.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 289366dad..d2b00d958 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -39,6 +39,7 @@ TDBDataProcess = class(TObject) FFiltered: Boolean; FFilterAllSites: Boolean; FFilterApplied: Boolean; + FAllSitesAttached: Boolean; FSitesList: TStringList; FAttachedSites: TStringList; FSQLSelect: String; @@ -533,12 +534,13 @@ procedure TDBDataProcess.AttachAllSites; FAttachedSites.Add(SitesList[i]); end; FConn.ExecuteDirect('BEGIN TRANSACTION'); + FAllSitesAttached := FAttachedSites.Count > 0; end; end; procedure TDBDataProcess.DetachAllSites; begin - if FConn.Connected and (FAttachedSites.Count > 0) then + if FConn.Connected and FAllSitesAttached then begin FConn.ExecuteDirect('END TRANSACTION'); repeat @@ -552,6 +554,7 @@ procedure TDBDataProcess.DetachAllSites; FAttachedSites.Delete(FAttachedSites.Count-1); until FAttachedSites.Count = 0; FConn.ExecuteDirect('BEGIN TRANSACTION'); + FAllSitesAttached := False; end; end; @@ -573,6 +576,7 @@ constructor TDBDataProcess.Create; FRecordCount := 0; FFilterApplied := False; FFilterSQL := ''; + FAllSitesAttached := False; end; destructor TDBDataProcess.Destroy; From df944a64a04f834d4192ed946fe3beec138e3f96 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 15:26:59 +0800 Subject: [PATCH 0113/2794] tdbdataprocess, don't need to re-attach same sites --- baseunits/uData.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d2b00d958..bd40005cf 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -522,9 +522,10 @@ procedure TDBDataProcess.AttachAllSites; var i: Integer; begin - DetachAllSites; if FConn.Connected and (SitesList.Count > 0) then begin + if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then Exit; + DetachAllSites; FConn.ExecuteDirect('END TRANSACTION'); for i := 0 to SitesList.Count-1 do if FileExistsUTF8(DBDataFilePath(SitesList[i])) then From 532db0b799824b20a5bc7bbe681a1990e4347d51 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 15:33:18 +0800 Subject: [PATCH 0114/2794] tdbdataprocess, fix getwebsitename --- baseunits/uData.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index bd40005cf..b31ed33bb 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -489,8 +489,9 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; begin Result := FWebsite; - if FConn.Connected and (FAttachedSites.Count > 0) and (FQuery.Active) then + if FQuery.Active and (FAttachedSites.Count > 0) then try + FQuery.RecNo := RecIndex+1; Result := FQuery.FieldByName('website').AsString; except on E: Exception do From db7450f63b4228c7ceb7272d46695cdea9b1af88 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 15:55:09 +0800 Subject: [PATCH 0115/2794] tdbdataprocess, don't need to attach current db --- baseunits/uData.pas | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b31ed33bb..332be1aa5 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -520,11 +520,26 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; end; procedure TDBDataProcess.AttachAllSites; + + procedure RemoveCurrentSite; + var + j: Integer; + begin + if SitesList.Count > 0 then + for j := 0 to SitesList.Count-1 do + if SitesList[j] = FWebsite then + begin + SitesList.Delete(j); + Break; + end; + end; + var i: Integer; begin if FConn.Connected and (SitesList.Count > 0) then begin + RemoveCurrentSite; if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then Exit; DetachAllSites; FConn.ExecuteDirect('END TRANSACTION'); From 9a77b54b0406cab4f91ec6675123afc9d42807bc Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 16:22:00 +0800 Subject: [PATCH 0116/2794] tdbdataprocess, fix open db with filter active --- baseunits/uData.pas | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 332be1aa5..9e0c0fa07 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -638,8 +638,6 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; filepath: String; begin Result := False; - FFiltered := False; - FRecordCount := 0; Self.Close; if AWebsite <> '' then FWebsite := AWebsite; @@ -714,12 +712,11 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; procedure TDBDataProcess.Close; begin - FFiltered := False; FRecordCount := 0; if FConn.Connected then try FQuery.Close; - DetachAllSites; + RemoveFilter; FConn.Close; FConn.DatabaseName := ''; except @@ -732,8 +729,8 @@ procedure TDBDataProcess.CloseTable; begin if FQuery.Active then begin - FFiltered := False; FRecordCount := 0; + RemoveFilter; FQuery.Close; end; end; @@ -855,13 +852,14 @@ procedure TDBDataProcess.Commit; function TDBDataProcess.Search(ATitle: String): Boolean; begin if FQuery.Active then + begin try FQuery.Close; FQuery.SQL.Clear; - if not FFilterApplied then - FQuery.SQL.Add(FSQLSelect) + if FFilterApplied then + FQuery.SQL.AddText(FFilterSQL) else - FQuery.SQL.AddText(FFilterSQL); + FQuery.SQL.Add(FSQLSelect); if ATitle <> '' then begin if not FFilterApplied then @@ -878,6 +876,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; WriteLog_E('TDBDataProcess.Search.Error!'#13#10 + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); end; + end; Result := FQuery.Active; if not Result then begin @@ -1071,8 +1070,11 @@ procedure TDBDataProcess.RemoveFilter; FFilterApplied := False; FFilterSQL := ''; DetachAllSites; - OpenTable; - GetRecordCount; + if FQuery.Active then + begin + OpenTable; + GetRecordCount; + end; end; end; From 44b8958bf4ec9f67518b58bbe6153595b70903e5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 16:49:01 +0800 Subject: [PATCH 0117/2794] tdbdataprocess, fix search while filtering multi site --- baseunits/uData.pas | 50 +++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9e0c0fa07..3b341d976 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -850,25 +850,49 @@ procedure TDBDataProcess.Commit; end; function TDBDataProcess.Search(ATitle: String): Boolean; +var + i: Integer; begin if FQuery.Active then begin try FQuery.Close; - FQuery.SQL.Clear; - if FFilterApplied then - FQuery.SQL.AddText(FFilterSQL) - else - FQuery.SQL.Add(FSQLSelect); - if ATitle <> '' then + with FQuery do begin - if not FFilterApplied then - FQuery.SQL.Add('WHERE'); - AddSQLSimpleFilter('title', ATitle); - FFiltered := True; - end - else - FFiltered := FFilterApplied; + SQL.Clear; + if FFilterApplied then + SQL.AddText(FFilterSQL) + else + SQL.Add(FSQLSelect); + if ATitle <> '' then + begin + if not FFilterApplied then + SQL.Add('WHERE'); + if FAllSitesAttached then + begin + if SQL.Count > 0 then + begin + i := 0; + while i < SQL.Count do + begin + if (SQL[i] = 'UNION ALL') or (SQL[i] = ')') then + begin + SQL.Insert(i, 'AND'); + SQL.Insert(i+1, '"title" LIKE ' + QuotedLike(ATitle)); + Inc(i, 3); + end + else + Inc(i); + end; + end; + end + else + AddSQLSimpleFilter('title', ATitle); + FFiltered := True; + end + else + FFiltered := FFilterApplied; + end; FQuery.Open; GetRecordCount; except From 1ec207bd1e71663d750f7572997060dfd4f2fa47 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 17:19:17 +0800 Subject: [PATCH 0118/2794] tdbdataprocess, update data on multi db attached --- baseunits/uData.pas | 36 +++++++++++++++++++++++------- baseunits/uGetMangaInfosThread.pas | 5 ++--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 3b341d976..848cdbb79 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -87,10 +87,11 @@ TDBDataProcess = class(TObject) procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; JDN: TDateTime); overload; procedure UpdateData(Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer); + NumChapter: Integer; AWebsite: String = ''); procedure Commit; procedure RemoveFilter; procedure Sort; + function WebsiteLoaded(const AWebsite: String): Boolean; property Website: String read FWebsite write FWebsite; property TableName: String read FTableName write FTableName; @@ -796,8 +797,8 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, NumChapter, DateToJDN(JDN)); end; -procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, - Genres, Status, Summary: String; NumChapter: Integer); +procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter: Integer; AWebsite: String); var sql: String; @@ -809,8 +810,7 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, end; begin - if Link = '' then - Exit; + if Link = '' then Exit; if FConn.Connected then begin try @@ -822,12 +822,16 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, AddSQL('status', Status); AddSQL('summary', Summary); AddSQL('numchapter', IntToStr(NumChapter)); - sql := 'UPDATE ' + QuotedStr(FTableName) + #13#10'SET'#13#10 + sql; + if (AWebsite <> '') and (AWebsite <> FWebsite) and FAllSitesAttached then + sql := 'UPDATE ' + AWebsite + '.' + QuotedStrd(FTableName) + + #13#10'SET'#13#10 + sql + else + sql := 'UPDATE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; sql += #13#10'WHERE link=' + QuotedStr(Link) + ';'; FConn.ExecuteDirect(sql); except on E: Exception do - WriteLog_E('TDBDataProcess.AddData.Error!', E, Self); + WriteLog_E('TDBDataProcess.UpdateData.Error!', E, Self); end; end; end; @@ -1129,6 +1133,21 @@ procedure TDBDataProcess.Sort; end; end; +function TDBDataProcess.WebsiteLoaded(const AWebsite: String): Boolean; +var + i: Integer; +begin + Result := False; + if FWebsite = AWebsite then Exit(True); + if FAllSitesAttached then + for i := 0 to FAttachedSites.Count-1 do + if FAttachedSites[i] = AWebsite then + begin + Result := True; + Break; + end; +end; + // ----- TDataProcess ----- constructor TDataProcess.Create; @@ -3108,7 +3127,8 @@ procedure TMangaInformation.SyncInfoToData(const DataProcess: TDBDataProcess); begin if Assigned(DataProcess) then with mangaInfo do - DataProcess.UpdateData(title, link, authors, artists, genres, status, summary, numChapter); + DataProcess.UpdateData(title, link, authors, artists, genres, status, summary, + numChapter, website); end; procedure TMangaInformation.AddInfoToDataWithoutBreak(const Name, link: String; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index d74a113ce..5ca2531b2 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -95,7 +95,7 @@ procedure TGetMangaInfosThread.DoGetInfos; if FMangaListPos >= 0 then begin - if website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex] then + if MainForm.dataProcess.WebsiteLoaded(Website) then begin if SitesWithoutInformation(website) then begin @@ -185,8 +185,7 @@ procedure TGetMangaInfosThread.MainThreadShowInfos; try TransferMangaInfo(MainForm.mangaInfo, FInfo.mangaInfo); with MainForm do begin - if (FMangaListPos > -1) and - (Website = MainForm.cbSelectManga.Text) then + if (FMangaListPos > -1) and dataProcess.WebsiteLoaded(Website) then begin vtMangaList.BeginUpdate; dataProcess.Refresh; From 299c664fc258889571038e66ff6b0728b5bb2e03 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 17:31:18 +0800 Subject: [PATCH 0119/2794] updatethread, remove filter if multi db loaded, db locked --- baseunits/uUpdateThread.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 71fe62c4c..fea2bd803 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -49,6 +49,7 @@ TUpdateMangaManagerThread = class(TFMDThread) {$ENDIF} procedure MainThreadShowGetting; procedure MainThreadEndGetting; + procedure MainThreadRemoveFilter; procedure RefreshList; procedure DlgReport; procedure GetInfo(const limit: Cardinal; const cs: TCheckStyleType); @@ -277,6 +278,11 @@ procedure TUpdateMangaManagerThread.MainThreadEndGetting; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; end; +procedure TUpdateMangaManagerThread.MainThreadRemoveFilter; +begin + MainForm.btRemoveFilterClick(MainForm.btRemoveFilter); +end; + constructor TUpdateMangaManagerThread.Create; begin inherited Create(True); @@ -326,7 +332,7 @@ procedure TUpdateMangaManagerThread.RefreshList; try with MainForm do begin - if cbSelectManga.Items[cbSelectManga.ItemIndex] = website then + if dataProcess.WebsiteLoaded(website) then begin Screen.Cursor := crHourGlass; try @@ -538,7 +544,11 @@ procedure TUpdateMangaManagerThread.Execute; (MainForm.dataProcess.Connected) then MainForm.dataProcess.Backup(twebsite) else + begin + if MainForm.dataProcess.WebsiteLoaded(website) then + Synchronize(MainThreadRemoveFilter); CopyDBDataProcess(website, twebsite); + end; if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); From 15f39553147bddd03cb2d02e1475282fb30adcd4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 16 Jul 2015 20:01:36 +0800 Subject: [PATCH 0120/2794] updatethread, validate against main dataprocess --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index fea2bd803..4d642b6d2 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -540,7 +540,7 @@ procedure TUpdateMangaManagerThread.Execute; twebsite := '__' + website; DeleteDBDataProcess(twebsite); - if (MainForm.cbSelectManga.Text = website) and + if (MainForm.dataProcess.Website = website) and (MainForm.dataProcess.Connected) then MainForm.dataProcess.Backup(twebsite) else From 6b85a8452615e6c8b97885ed107bb8f8f03f160a Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 16:18:28 +0800 Subject: [PATCH 0121/2794] tdbdataprocess, clean up --- baseunits/uData.pas | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 848cdbb79..e9a15e499 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,8 +15,8 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, - sqlite3backup, sqldb, db, Sqlite3DS, USimpleLogger, strutils, dateutils, - RegExpr, sqlite3dyn, httpsend; + sqlite3backup, sqlite3dyn, sqldb, db, USimpleLogger, strutils, dateutils, + RegExpr, httpsend; type @@ -197,7 +197,6 @@ TMangaInformation = class(TObject) var options: TStringList; - tdset: TSqlite3Dataset; const DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; @@ -3218,10 +3217,5 @@ function TMangaInformation.GetPage(var output: TObject; URL: String; initialization sqlite3dyn.SQLiteDefaultLibrary := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; - tdset := TSqlite3Dataset.Create(nil); - -finalization - if Assigned(tdset) then - FreeAndNil(tdset); end. From 6339b309fb4caa689d1a382b71255aca10d30010 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 18:41:12 +0800 Subject: [PATCH 0122/2794] mainform, don't need to refresh when changing db --- mangadownloader/forms/frmMain.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 70a3fbca5..02e20b0c6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1865,7 +1865,6 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]) then RunGetList; vtMangaList.RootNodeCount := dataProcess.RecordCount; - dataProcess.Refresh; lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; dataProcess.website := cbSelectManga.Items[cbSelectManga.ItemIndex]; From a7ad249cf6aead119dafa7901c8ed87f8a013f7c Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 18:43:15 +0800 Subject: [PATCH 0123/2794] tdbdataprocess, only refresh if db connected --- baseunits/uData.pas | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index e9a15e499..72117937f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -757,13 +757,16 @@ procedure TDBDataProcess.Backup(AWebsite: String); procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); begin - if FQuery.Active then - FQuery.Refresh - else - if Trim(FQuery.SQL.Text) <> '' then - FQuery.Open; - if RecheckDataCount then - GetRecordCount; + if FConn.Connected then + begin + if FQuery.Active then + FQuery.Refresh + else + if Trim(FQuery.SQL.Text) <> '' then + FQuery.Open; + if RecheckDataCount then + GetRecordCount; + end; end; procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, From 6472f4999e4a177bdc38b50772612a3de0fd2e7e Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 21:00:35 +0800 Subject: [PATCH 0124/2794] add websitemodules unit --- baseunits/WebsiteModules.pas | 286 +++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 baseunits/WebsiteModules.pas diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas new file mode 100644 index 000000000..56d9aae2c --- /dev/null +++ b/baseunits/WebsiteModules.pas @@ -0,0 +1,286 @@ +unit WebsiteModules; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, uData, uDownloadsManager; + +const + MODULE_NOT_FOUND = -1; + NO_ERROR = 0; + NET_PROBLEM = 1; + INFORMATION_NOT_FOUND = 2; + +type + + TModuleContainer = class; + + TOnGetDirectoryPageNumber = function(var MangaInfo: TMangaInformation; + var Page: Cardinal; Module: TModuleContainer): Integer; + TOnGetNameAndLink = function(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; + Module: TModuleContainer): Integer; + TOnGetInfo = function(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; Module: TModuleContainer): Integer; + + TOnGetPageNumber = function(var Container: TTaskContainer; + const URL: String; Module: TModuleContainer): Boolean; + TOnGetImageURL = function(var Container: TTaskContainer; const URL: String; + Module: TModuleContainer): Boolean; + + TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, + MMGetPageNumber, MMGetImageURL); + + { TModuleContainer } + + TModuleContainer = class + public + Website, RootURL: String; + SortedList, InformationAvailable: Boolean; + OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; + OnGetNameAndLink: TOnGetNameAndLink; + OnGetInfo: TOnGetInfo; + OnGetPageNumber: TOnGetPageNumber; + OnGetImageURL: TOnGetImageURL; + constructor Create; + end; + + { TWebsiteModules } + + TWebsiteModules = class(TObject) + private + FCSModules: TRTLCriticalSection; + FModuleList: TFPList; + public + constructor Create; + destructor Destroy; override; + + function AddModule: TModuleContainer; + function LocateModule(const Website: String): Integer; + function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; + var OutIndex: Integer): Boolean; overload; + function ModuleAvailable(const Website: String; + ModuleMethod: TModuleMethod): Boolean; overload; + + function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Cardinal; const ModuleIndex: Integer): Integer; overload; + function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Cardinal; const Website: String): Integer; overload; + + function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; + const ModuleIndex: Integer): Integer; + overload; + function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL, Website: String): Integer; overload; + + function GetInfo(var MangaInfo: TMangaInformation; + const Website, URL: String; const Reconnect: Cardinal): Integer; + + function GetPageNumber(var Container: TTaskContainer; const URL: String): Boolean; + function GetImageURL(var Container: TTaskContainer; const URL: String): Boolean; + + procedure LockModules; + procedure UnlockModules; + + function Items(const Index: Integer): TModuleContainer; + end; + +var + Modules: TWebsiteModules; + +procedure doInitialize; +function AddModule: TModuleContainer; + +implementation + +{$I ModuleList.inc} + +{ TModuleContainer } + +constructor TModuleContainer.Create; +begin + SortedList := False; + InformationAvailable := True; +end; + +{ TWebsiteModules } + +constructor TWebsiteModules.Create; +begin + InitCriticalSection(FCSModules); + FModuleList := TFPList.Create; +end; + +destructor TWebsiteModules.Destroy; +var + i: Integer; +begin + if FModuleList.Count > 0 then + for i := 0 to FModuleList.Count - 1 do + TModuleContainer(FModuleList[i]).Free; + FModuleList.Free; + DoneCriticalsection(FCSModules); + inherited Destroy; +end; + +function TWebsiteModules.AddModule: TModuleContainer; +begin + EnterCriticalsection(FCSModules); + try + FModuleList.Add(TModuleContainer.Create); + Result := TModuleContainer(FModuleList.Last); + finally + LeaveCriticalsection(FCSModules); + end; +end; + +function TWebsiteModules.LocateModule(const Website: String): Integer; +var + i: Integer; +begin + Result := -1; + if FModuleList.Count > 0 then + begin + EnterCriticalsection(FCSModules); + try + for i := 0 to FModuleList.Count - 1 do + begin + if SameText(TModuleContainer(FModuleList[i]).Website, Website) then + begin + Result := i; + Break; + end; + end; + finally + LeaveCriticalsection(FCSModules); + end; + end; +end; + +function TWebsiteModules.ModuleAvailable(const Website: String; + ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; +var + p: Integer; +begin + Result := False; + p := LocateModule(Website); + OutIndex := p; + if p >= 0 then + begin + with TModuleContainer(FModuleList[p]) do + begin + case ModuleMethod of + MMGetDirectoryPageNumber: Result := Assigned(OnGetDirectoryPageNumber); + MMGetNameAndLink: Result := Assigned(OnGetNameAndLink); + MMGetInfo: Result := Assigned(OnGetInfo); + MMGetPageNumber: Result := Assigned(OnGetPageNumber); + MMGetImageURL: Result := Assigned(OnGetImageURL); + else + Result := False; + end; + end; + end; +end; + +function TWebsiteModules.ModuleAvailable(const Website: String; + ModuleMethod: TModuleMethod): Boolean; +var + p: Integer; +begin + Result := ModuleAvailable(Website, ModuleMethod, p); +end; + +function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Cardinal; const ModuleIndex: Integer): Integer; +begin + Result := MODULE_NOT_FOUND; + if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + Exit; + if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetDirectoryPageNumber) then + Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetDirectoryPageNumber( + MangaInfo, Page, TModuleContainer(FModuleList[ModuleIndex])); +end; + +function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Cardinal; const Website: String): Integer; +begin + Result := GetDirectoryPageNumber(MangaInfo, Page, LocateModule(Website)); +end; + +function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; + const ModuleIndex: Integer): Integer; +begin + Result := MODULE_NOT_FOUND; + if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + Exit; + if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetNameAndLink) then + Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetNameAndLink( + MangaInfo, Names, Links, URL, TModuleContainer(FModuleList[ModuleIndex])); +end; + +function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL, Website: String): Integer; +begin + Result := GetNameAndLink(MangaInfo, Names, Links, URL, LocateModule(Website)); +end; + +function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; + const Website, URL: String; const Reconnect: Cardinal): Integer; +var + p: Integer; +begin + Result := MODULE_NOT_FOUND; +end; + +function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; + const URL: String): Boolean; +begin + Result := False; +end; + +function TWebsiteModules.GetImageURL(var Container: TTaskContainer; + const URL: String): Boolean; +begin + Result := False; +end; + +procedure TWebsiteModules.LockModules; +begin + EnterCriticalsection(FCSModules); +end; + +procedure TWebsiteModules.UnlockModules; +begin + LeaveCriticalsection(FCSModules); +end; + +function TWebsiteModules.Items(const Index: Integer): TModuleContainer; +begin + Result := TModuleContainer(FModuleList[Index]); +end; + +procedure doInitialize; +begin + if Modules = nil then + Modules := TWebsiteModules.Create; +end; + +function AddModule: TModuleContainer; +begin + if Modules = nil then + doInitialize; + Result := Modules.AddModule; +end; + +initialization + doInitialize; + +finalization + if Assigned(Modules) then + FreeAndNil(Modules); + +end. From 89be56a788b973021f2ad06e5f4724fedc1dab50 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 21:03:53 +0800 Subject: [PATCH 0125/2794] baseunit, add incstr for easier inc, return invalid mangasiteid if not exist --- baseunits/uBaseUnit.pas | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f8aa21c2d..a4867ef2a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -913,6 +913,8 @@ function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): String; procedure AddCommaString(var Dest: string; S: string); +function IncStr(const S: String; N: Integer = 1): String; + //get heaader value from THTTPSend.Headers function GetHeaderValue(const AHeaders: TStrings; HName: String): String; @@ -1218,7 +1220,7 @@ function GetMangaSiteID(const Name: String): Integer; var i: Integer; begin - Result := -1; + Result := High(WebsiteRoots) + 1; for i := Low(WebsiteRoots) to High(WebsiteRoots) do if Name = WebsiteRoots[i, 0] then Exit(i); @@ -2003,6 +2005,19 @@ function CorrectPathSys(const Path: String): String; end; end; +function IncStr(const S: String; N: Integer): String; +var + i: Integer; +begin + Result := S; + i := StrToIntDef(S, -1); + if i > -1 then + begin + Inc(i, N); + Result := IntToStr(i); + end; +end; + function GetHeaderValue(const AHeaders: TStrings; HName: String): String; var i, p: Integer; From 22221ffabc221f5b1c8406f283a86f18edc1427c Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 21:05:20 +0800 Subject: [PATCH 0126/2794] add foolslide unit used in websitemodules as module --- baseunits/ModuleList.inc | 2 + baseunits/modules/FoOlSlide.pas | 109 ++++++++++++++++++++++++++++++++ mangadownloader/md.lpi | 2 +- 3 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 baseunits/ModuleList.inc create mode 100644 baseunits/modules/FoOlSlide.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc new file mode 100644 index 000000000..34d4b1222 --- /dev/null +++ b/baseunits/ModuleList.inc @@ -0,0 +1,2 @@ +uses + FoOlSlide; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas new file mode 100644 index 000000000..8ca80ebec --- /dev/null +++ b/baseunits/modules/FoOlSlide.pas @@ -0,0 +1,109 @@ +unit FoOlSlide; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, USimpleLogger, HTMLUtil, + RegExpr; + +implementation + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Cardinal; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + i: Integer; +begin + Result := INFORMATION_NOT_FOUND; + Page := 1; + if MangaInfo = nil then + Exit; + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/directory/', 3) then + begin + Result := NO_ERROR; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + begin + for i := 0 to Parse.Count - 1 do + begin + if GetVal(Parse[i], 'class') = 'next' then + if GetTagName(Parse[i + 2]) = 'a' then + begin + Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', + GetVal(Parse[i + 2], 'href'), '$1', True), 1); + Break; + end; + end; + end; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + i: Integer; +begin + Result := INFORMATION_NOT_FOUND; + if MangaInfo = nil then + Exit; + if MangaInfo = nil then + Exit; + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/directory/' + + IncStr(URL), 3) then + begin + Result := NO_ERROR; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + begin + for i := 0 to Parse.Count - 1 do + begin + if (GetTagName(Parse[i]) = 'a') and (Pos('/series/', Parse[i]) > 0) then + begin + Links.Add(GetVal(Parse[i], 'href')); + Names.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + end; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Shoujosense'; + RootURL := 'http://reader.shoujosense.com'; + SortedList := False; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 42c6d6e05..2be03a0f1 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -173,7 +173,7 @@ - + From 7ebcdaa793197bca3138241fbe5df7d4c6001501 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 21:06:11 +0800 Subject: [PATCH 0127/2794] udata, adapt to use websitemodules --- baseunits/uData.pas | 847 ++++++++++++++++++++++---------------------- 1 file changed, 429 insertions(+), 418 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 72117937f..8e5813f28 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -223,7 +223,7 @@ implementation uses Dialogs, fpJSON, JSONParser, IniFiles, jsHTMLUtil, FastHTMLParser, HTMLUtil, - SynaCode, uMisc, frmMain; + SynaCode, uMisc, frmMain, WebsiteModules; function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; @@ -1918,162 +1918,166 @@ function TMangaInformation.GetDirectoryPage(var Page: Cardinal; else begin BROWSER_INVERT := False; - - Source := TStringList.Create; - if website = WebsiteRoots[ANIMEA_ID, 0] then - Result := GetAnimeADirectoryPageNumber - else - if website = WebsiteRoots[KISSMANGA_ID, 0] then - Result := GetKissMangaDirectoryPageNumber - else - if website = WebsiteRoots[BATOTO_ID, 0] then - Result := GetBatotoDirectoryPageNumber - else - if website = WebsiteRoots[MANGA24H_ID, 0] then - Result := GetManga24hDirectoryPageNumber - else - if website = WebsiteRoots[VNSHARING_ID, 0] then - Result := GetVnSharingDirectoryPageNumber - else - if website = WebsiteRoots[HENTAI2READ_ID, 0] then - Result := GetHentai2ReadDirectoryPageNumber - else - if website = WebsiteRoots[FAKKU_ID, 0] then - Result := GetFakkuDirectoryPageNumber - else - if website = WebsiteRoots[MANGAPARK_ID, 0] then - Result := GetMangaParkDirectoryPageNumber - else - //if website = WebsiteRoots[MANGAFOX_ID, 0] then - // Result := GetMangaFoxDirectoryPageNumber - //else - //if website = WebsiteRoots[MANGATRADERS_ID, 0] then - // Result := GetMangaTradersDirectoryPageNumber - //else - if website = WebsiteRoots[MANGAGO_ID, 0] then - Result := GetMangaGoDirectoryPageNumber - else - if website = WebsiteRoots[MANGAEDEN_ID, 0] then - Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[MANGAEDEN_ID, 1]) - else - if website = WebsiteRoots[PERVEDEN_ID, 0] then - Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[PERVEDEN_ID, 1]) - else - if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then - Result := GetBlogTruyenDirectoryPageNumber - else - if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then - Result := GetRedHawkScansDirectoryPageNumber - else - if website = WebsiteRoots[S2SCAN_ID,0] then - Result:= GetS2ScanDirectoryPageNumber - else - if website = WebsiteRoots[SENMANGA_ID, 0] then - Result := GetSenMangaDirectoryPageNumber - else - if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then - Result := GetLectureEnLigneDirectoryPageNumber - else - if website = WebsiteRoots[MANGAAE_ID, 0] then - Result := GetMangaAeDirectoryPageNumber - else - if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then - Result := GetCentralDeMangasDirectoryPageNumber - else - if website = WebsiteRoots[MANGA2U_ID, 0] then - Result := GetManga2uDirectoryPageNumber - else - if website = WebsiteRoots[DM5_ID, 0] then - Result := GetDM5DirectoryPageNumber - else - if website = WebsiteRoots[PURURIN_ID, 0] then - Result := GetPururinDirectoryPageNumber - else - if website = WebsiteRoots[EHENTAI_ID, 0] then - Result := GetEHentaiDirectoryPageNumber - else - if (website = WebsiteRoots[NINEMANGA_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then - Result := GetNineMangaDirectoryPageNumber - else - if website = WebsiteRoots[JAPANSHIN_ID, 0] then - Result := GetJapanShinDirectoryPageNumber - else - if website = WebsiteRoots[MANGACOW_ID, 0] then - Result := GetMangaCowDirectoryPageNumber - else - if website = WebsiteRoots[ONEMANGA_ID, 0] then - Result := GetOneMangaDirectoryPageNumber - else - if website = WebsiteRoots[MANGATOWN_ID, 0] then - Result := GetMangaTownDirectoryPageNumber - else - if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then - Result := GetReadHentaiMangaDirectoryPageNumber - else - if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then - Result := GetMyReadingMangaInfoDirectoryPageNumber - else - if website = WebsiteRoots[IKOMIK_ID, 0] then - Result := GetIKomikDirectoryPageNumber - else - if website = WebsiteRoots[NHENTAI_ID, 0] then - Result := GetNHentaiDirectoryPageNumber - else - if website = GetMangaSiteName(UNIONMANGAS_ID) then - Result := GetUnionMangasDirectoryPageNumber - else - if website = WebsiteRoots[MANGAMINT_ID, 0] then - Result := GetMangaMintDirectoryPageNumber - else - if website = WebsiteRoots[HAKIHOME_ID, 0] then - Result := GetHakiHomeDirectoryPageNumber - else - if website = WebsiteRoots[MANGAFRAME_ID, 0] then - Result := GetMangaFrameDirectoryPageNumber - else - if website = WebsiteRoots[MANGAHOST_ID, 0] then - Result := GetMangaHostDirectoryPageNumber - else - if (website = WebsiteRoots[PORNCOMIX_ID, 0]) or - (website = WebsiteRoots[XXCOMICS_ID, 0]) or - (website = WebsiteRoots[XXCOMICSMT_ID, 0]) or - (website = WebsiteRoots[XXCOMICS3D_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXRE_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXIC_ID, 0]) or - (website = WebsiteRoots[PORNXXXCOMICS_ID, 0]) then - Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(website)) - else - if website = WebsiteRoots[MANGASEE_ID, 0] then - Result := GetMangaSeeDirectoryPageNumber - else - if website = WebsiteRoots[ACADEMYVN_ID, 0] then - Result := GetAcademyVNDirectoryPageNumber - else - if website = WebsiteRoots[MANGAAT_ID, 0] then - Result := GetMangaAtDirectoryPageNumber - else - if website = WebsiteRoots[READMANGATODAY_ID, 0] then - Result := GetReadMangaTodayDirectoryPageNumber - else - if website = WebsiteRoots[DYNASTYSCANS_ID, 0] then - Result := GetDynastyScansDirectoryPageNumber - else - if website = WebsiteRoots[MADOKAMI_ID, 0] then - Result := GetMadokamiDirectoryPageNumber - else - if SitesIsWPManga(WebsiteID) then - Result := GetWPMangaDirectoryPageNumber + if Modules.ModuleAvailable(website, MMGetDirectoryPageNumber, p) then + Result := Modules.GetDirectoryPageNumber(Self, Page, p) else begin - Result := NO_ERROR; - Page := 1; - Source.Free; + Source := TStringList.Create; + if website = WebsiteRoots[ANIMEA_ID, 0] then + Result := GetAnimeADirectoryPageNumber + else + if website = WebsiteRoots[KISSMANGA_ID, 0] then + Result := GetKissMangaDirectoryPageNumber + else + if website = WebsiteRoots[BATOTO_ID, 0] then + Result := GetBatotoDirectoryPageNumber + else + if website = WebsiteRoots[MANGA24H_ID, 0] then + Result := GetManga24hDirectoryPageNumber + else + if website = WebsiteRoots[VNSHARING_ID, 0] then + Result := GetVnSharingDirectoryPageNumber + else + if website = WebsiteRoots[HENTAI2READ_ID, 0] then + Result := GetHentai2ReadDirectoryPageNumber + else + if website = WebsiteRoots[FAKKU_ID, 0] then + Result := GetFakkuDirectoryPageNumber + else + if website = WebsiteRoots[MANGAPARK_ID, 0] then + Result := GetMangaParkDirectoryPageNumber + else + //if website = WebsiteRoots[MANGAFOX_ID, 0] then + // Result := GetMangaFoxDirectoryPageNumber + //else + //if website = WebsiteRoots[MANGATRADERS_ID, 0] then + // Result := GetMangaTradersDirectoryPageNumber + //else + if website = WebsiteRoots[MANGAGO_ID, 0] then + Result := GetMangaGoDirectoryPageNumber + else + if website = WebsiteRoots[MANGAEDEN_ID, 0] then + Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[MANGAEDEN_ID, 1]) + else + if website = WebsiteRoots[PERVEDEN_ID, 0] then + Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[PERVEDEN_ID, 1]) + else + if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then + Result := GetBlogTruyenDirectoryPageNumber + else + if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then + Result := GetRedHawkScansDirectoryPageNumber + else + if website = WebsiteRoots[S2SCAN_ID,0] then + Result:= GetS2ScanDirectoryPageNumber + else + if website = WebsiteRoots[SENMANGA_ID, 0] then + Result := GetSenMangaDirectoryPageNumber + else + if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then + Result := GetLectureEnLigneDirectoryPageNumber + else + if website = WebsiteRoots[MANGAAE_ID, 0] then + Result := GetMangaAeDirectoryPageNumber + else + if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then + Result := GetCentralDeMangasDirectoryPageNumber + else + if website = WebsiteRoots[MANGA2U_ID, 0] then + Result := GetManga2uDirectoryPageNumber + else + if website = WebsiteRoots[DM5_ID, 0] then + Result := GetDM5DirectoryPageNumber + else + if website = WebsiteRoots[PURURIN_ID, 0] then + Result := GetPururinDirectoryPageNumber + else + if website = WebsiteRoots[EHENTAI_ID, 0] then + Result := GetEHentaiDirectoryPageNumber + else + if (website = WebsiteRoots[NINEMANGA_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then + Result := GetNineMangaDirectoryPageNumber + else + if website = WebsiteRoots[JAPANSHIN_ID, 0] then + Result := GetJapanShinDirectoryPageNumber + else + if website = WebsiteRoots[MANGACOW_ID, 0] then + Result := GetMangaCowDirectoryPageNumber + else + if website = WebsiteRoots[ONEMANGA_ID, 0] then + Result := GetOneMangaDirectoryPageNumber + else + if website = WebsiteRoots[MANGATOWN_ID, 0] then + Result := GetMangaTownDirectoryPageNumber + else + if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then + Result := GetReadHentaiMangaDirectoryPageNumber + else + if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then + Result := GetMyReadingMangaInfoDirectoryPageNumber + else + if website = WebsiteRoots[IKOMIK_ID, 0] then + Result := GetIKomikDirectoryPageNumber + else + if website = WebsiteRoots[NHENTAI_ID, 0] then + Result := GetNHentaiDirectoryPageNumber + else + if website = GetMangaSiteName(UNIONMANGAS_ID) then + Result := GetUnionMangasDirectoryPageNumber + else + if website = WebsiteRoots[MANGAMINT_ID, 0] then + Result := GetMangaMintDirectoryPageNumber + else + if website = WebsiteRoots[HAKIHOME_ID, 0] then + Result := GetHakiHomeDirectoryPageNumber + else + if website = WebsiteRoots[MANGAFRAME_ID, 0] then + Result := GetMangaFrameDirectoryPageNumber + else + if website = WebsiteRoots[MANGAHOST_ID, 0] then + Result := GetMangaHostDirectoryPageNumber + else + if (website = WebsiteRoots[PORNCOMIX_ID, 0]) or + (website = WebsiteRoots[XXCOMICS_ID, 0]) or + (website = WebsiteRoots[XXCOMICSMT_ID, 0]) or + (website = WebsiteRoots[XXCOMICS3D_ID, 0]) or + (website = WebsiteRoots[PORNCOMIXRE_ID, 0]) or + (website = WebsiteRoots[PORNCOMIXIC_ID, 0]) or + (website = WebsiteRoots[PORNXXXCOMICS_ID, 0]) then + Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(website)) + else + if website = WebsiteRoots[MANGASEE_ID, 0] then + Result := GetMangaSeeDirectoryPageNumber + else + if website = WebsiteRoots[ACADEMYVN_ID, 0] then + Result := GetAcademyVNDirectoryPageNumber + else + if website = WebsiteRoots[MANGAAT_ID, 0] then + Result := GetMangaAtDirectoryPageNumber + else + if website = WebsiteRoots[READMANGATODAY_ID, 0] then + Result := GetReadMangaTodayDirectoryPageNumber + else + if website = WebsiteRoots[DYNASTYSCANS_ID, 0] then + Result := GetDynastyScansDirectoryPageNumber + else + if website = WebsiteRoots[MADOKAMI_ID, 0] then + Result := GetMadokamiDirectoryPageNumber + else + if SitesIsWPManga(WebsiteID) then + Result := GetWPMangaDirectoryPageNumber + else + begin + Result := NO_ERROR; + Page := 1; + Source.Free; + end; end; if page < 1 then @@ -2087,6 +2091,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; Source: TStringList; Parser: THTMLParser; WebsiteID: Cardinal; + p: Integer; {$I includes/Manga2u/names_and_links.inc} @@ -2259,271 +2264,277 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website <> '' then FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); - Source := TStringList.Create; - if website = WebsiteRoots[ANIMEA_ID, 0] then - Result := AnimeAGetNamesAndLinks - else - if website = WebsiteRoots[MANGAHERE_ID, 0] then - Result := MangaHereGetNamesAndLinks - else - if website = WebsiteRoots[MANGAINN_ID, 0] then - Result := MangaInnGetNamesAndLinks - else - if website = WebsiteRoots[KISSMANGA_ID, 0] then - Result := KissMangaGetNamesAndLinks - else - if website = WebsiteRoots[BATOTO_ID, 0] then - Result := BatotoGetNamesAndLinks - else - if website = WebsiteRoots[MANGA24H_ID, 0] then - Result := Manga24hGetNamesAndLinks - else - if website = WebsiteRoots[VNSHARING_ID, 0] then - Result := VnSharingGetNamesAndLinks - else - if website = WebsiteRoots[HENTAI2READ_ID, 0] then - Result := Hentai2ReadGetNamesAndLinks - else - if website = WebsiteRoots[FAKKU_ID, 0] then - Result := FakkuGetNamesAndLinks - else - if website = WebsiteRoots[MANGAREADER_ID, 0] then - Result := MangaReaderGetNamesAndLinks - else - if website = WebsiteRoots[MANGAPARK_ID, 0] then - Result := MangaParkGetNamesAndLinks - else - if website = WebsiteRoots[MANGAFOX_ID, 0] then - Result := MangaFoxGetNamesAndLinks - else - if website = WebsiteRoots[MANGATRADERS_ID, 0] then - Result := MangaTradersGetNamesAndLinks - else - if website = WebsiteRoots[STARKANA_ID, 0] then - Result := StarkanaGetNamesAndLinks - else - if website = WebsiteRoots[EATMANGA_ID, 0] then - Result := EatMangaGetNamesAndLinks - else - if website = WebsiteRoots[MANGAPANDA_ID, 0] then - Result := MangaPandaGetNamesAndLinks - else - if website = WebsiteRoots[MANGAGO_ID, 0] then - Result := MangaGoGetNamesAndLinks - else - if website = WebsiteRoots[MANGASTREAM_ID, 0] then - Result := MangaStreamGetNamesAndLinks - else - if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then - Result := RedHawkScansGetNamesAndLinks - else - if website = WebsiteRoots[S2SCAN_ID, 0] then - Result := S2ScanGetNamesAndLinks - else - if website = WebsiteRoots[EGSCANS_ID, 0] then - Result := EGScansGetNamesAndLinks - else - if website = WebsiteRoots[MANGAEDEN_ID, 0] then - Result := MangaEdenGetNamesAndLinks(WebsiteRoots[MANGAEDEN_ID, 1]) - else - if website = WebsiteRoots[PERVEDEN_ID, 0] then - Result := MangaEdenGetNamesAndLinks(WebsiteRoots[PERVEDEN_ID, 1]) - else - if website = WebsiteRoots[MEINMANGA_ID, 0] then - Result := MeinMangaGetNamesAndLinks - else - if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then - Result := BlogTruyenGetNamesAndLinks - else - if website = WebsiteRoots[TRUYENTRANHTUAN_ID, 0] then - Result := TruyenTranhTuanGetNamesAndLinks - else - if website = WebsiteRoots[SUBMANGA_ID, 0] then - Result := SubMangaGetNamesAndLinks - else - if website = WebsiteRoots[ESMANGAHERE_ID, 0] then - Result := EsMangaHereGetNamesAndLinks - else - if website = WebsiteRoots[ANIMEEXTREMIST_ID, 0] then - Result := AnimeExtremistGetNamesAndLinks - else - if website = WebsiteRoots[KOMIKID_ID, 0] then - Result := KomikidGetNamesAndLinks - else - if website = WebsiteRoots[PECINTAKOMIK_ID, 0] then - Result := PecintaKomikGetNamesAndLinks - else - if website = WebsiteRoots[MABUNS_ID, 0] then - Result := MabunsGetNamesAndLinks - else - if website = WebsiteRoots[MANGAESTA_ID, 0] then - Result := MangaEstaGetNamesAndLinks - else - if website = WebsiteRoots[PURURIN_ID, 0] then - Result := PururinGetNamesAndLinks - else - if website = WebsiteRoots[HUGEMANGA_ID, 0] then - Result := HugeMangaGetNamesAndLinks - else - if website = WebsiteRoots[ANIMESTORY_ID, 0] then - Result := AnimeStoryGetNamesAndLinks - else - if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then - Result := LectureEnLigneGetNamesAndLinks - else - if website = WebsiteRoots[SCANMANGA_ID, 0] then - Result := ScanMangaGetNamesAndLinks - else - if website = WebsiteRoots[MANGAAR_ID, 0] then - Result := MangaArGetNamesAndLinks - else - if website = WebsiteRoots[MANGAAE_ID, 0] then - Result := MangaAeGetNamesAndLinks - else - if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then - Result := CentralDeMangasGetNamesAndLinks - else - if website = WebsiteRoots[IMANHUA_ID, 0] then - Result := imanhuaGetNamesAndLinks - else - if website = WebsiteRoots[TURKCRAFT_ID, 0] then - Result := TurkcraftGetNamesAndLinks - else - if website = WebsiteRoots[MANGAVADISI_ID, 0] then - Result := MangaVadisiGetNamesAndLinks - else - if website = WebsiteRoots[MANGAFRAME_ID, 0] then - Result := MangaFrameNamesAndLinks - else - if website = WebsiteRoots[MANGACOW_ID, 0] then - Result := MangaCowGetNamesAndLinks - else - if website = WebsiteRoots[SENMANGA_ID, 0] then - Result := SenMangaGetNamesAndLinks - else - if website = WebsiteRoots[KIVMANGA_ID, 0] then - Result := KivmangaGetNamesAndLinks - else - if website = WebsiteRoots[MANGACAN_ID, 0] then - Result := MangacanGetNamesAndLinks - else - if website = WebsiteRoots[MANGASPROJECT_ID, 0] then - Result := MangasPROJECTGetNamesAndLinks - else - if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then - Result := MangaREADER_PORGetNamesAndLinks - else - if website = WebsiteRoots[MANGA2U_ID, 0] then - Result := Manga2uGetNamesAndLinks - else - if website = WebsiteRoots[EHENTAI_ID, 0] then - Result := EHentaiGetNamesAndLinks - else - if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then - Result := MangaStreamToGetNamesAndLinks - else - if (website = WebsiteRoots[NINEMANGA_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then - Result := NineMangaGetNamesAndLinks - else - if website = WebsiteRoots[JAPANSHIN_ID, 0] then - Result := JapanShinGetNamesAndLinks - else - if website = WebsiteRoots[JAPSCAN_ID, 0] then - Result := JapscanNamesAndLinks - else - if website = WebsiteRoots[CENTRUMMANGI_PL_ID, 0] then - Result := CentrumMangi_PLGetNamesAndLinks - else - if website = WebsiteRoots[MANGALIB_PL_ID, 0] then - Result := MangaLib_PLGetNamesAndLinks - else - if website = WebsiteRoots[ONEMANGA_ID, 0] then - Result := OneMangaGetNamesAndLinks - else - if website = WebsiteRoots[MANGATOWN_ID, 0] then - Result := MangaTownGetNamesAndLinks - else - if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then - Result := ReadHentaiMangaGetNamesAndLinks - else - if website = WebsiteRoots[MANGAOKU_ID, 0] then - Result := MangaOkuGetNamesAndLinks - else - if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then - Result := MyReadingMangaInfoNamesAndLinks - else - if website = WebsiteRoots[IKOMIK_ID, 0] then - Result := IKomikNamesAndLinks - else - if website = WebsiteRoots[NHENTAI_ID, 0] then - Result := NHentaiNamesAndLinks - else - if website = WebsiteRoots[UNIONMANGAS_ID, 0] then - Result := UnionMangasNamesAndLinks - else - if website = WebsiteRoots[MANGAMINT_ID, 0] then - Result := MangaMintGetNamesAndLinks - else - if website = WebsiteRoots[UNIXMANGA_ID, 0] then - Result := UnixMangaNamesAndLinks - else - if website = WebsiteRoots[HAKIHOME_ID, 0] then - Result := HakiHomeNamesAndLinks - else - if website = WebsiteRoots[EXTREMEMANGAS_ID, 0] then - Result := ExtremeMangasNamesAndLinks - else - if website = WebsiteRoots[MANGAHOST_ID, 0] then - Result := MangaHostGetNamesAndLinks - else - if (website = WebsiteRoots[PORNCOMIX_ID, 0]) or - (website = WebsiteRoots[XXCOMICS_ID, 0]) or - (website = WebsiteRoots[XXCOMICSMT_ID, 0]) or - (website = WebsiteRoots[XXCOMICS3D_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXRE_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXIC_ID, 0]) or - (website = WebsiteRoots[PORNXXXCOMICS_ID, 0]) then - Result := PornComixGetNamesAndLinks(GetMangaSiteID(website)) - else - if website = WebsiteRoots[MANGASEE_ID, 0] then - Result := MangaSeeGetNamesAndLinks - else - if website = WebsiteRoots[MANGAKU_ID, 0] then - Result := MangaKuGetNamesAndLinks - else - if website = WebsiteRoots[ACADEMYVN_ID, 0] then - Result := AcademyVNGetNamesAndLinks - else - if website = WebsiteRoots[MANGAAT_ID, 0] then - Result := MangaAtGetNamesAndLinks - else - if website = WebsiteRoots[SENMANGARAW_ID, 0] then - Result := SenMangaRAWGetNamesAndLinks - else - if website = WebsiteRoots[READMANGATODAY_ID, 0] then - Result := ReadMangaTodayGetNamesAndLinks - else - if website = WebsiteRoots[LONEMANGA_ID, 0] then - Result := LoneMangaGetNamesAndLinks - else - if website = WebsiteRoots[DYNASTYSCANS_ID, 0] then - Result := DynastyScansGetNamesAndLinks - else - if website = WebsiteRoots[MADOKAMI_ID, 0] then - Result := MadokamiGetNamesAndLinks - else - if SitesIsWPManga(WebsiteID) then - Result := GetWPMangaNamesAndLinks + p := -1; + if Modules.ModuleAvailable(website, MMGetNameAndLink, p) then + Result := Modules.GetNameAndLink(Self, names, links, URL, p) else begin - Result := INFORMATION_NOT_FOUND; - Source.Free; + Source := TStringList.Create; + if website = WebsiteRoots[ANIMEA_ID, 0] then + Result := AnimeAGetNamesAndLinks + else + if website = WebsiteRoots[MANGAHERE_ID, 0] then + Result := MangaHereGetNamesAndLinks + else + if website = WebsiteRoots[MANGAINN_ID, 0] then + Result := MangaInnGetNamesAndLinks + else + if website = WebsiteRoots[KISSMANGA_ID, 0] then + Result := KissMangaGetNamesAndLinks + else + if website = WebsiteRoots[BATOTO_ID, 0] then + Result := BatotoGetNamesAndLinks + else + if website = WebsiteRoots[MANGA24H_ID, 0] then + Result := Manga24hGetNamesAndLinks + else + if website = WebsiteRoots[VNSHARING_ID, 0] then + Result := VnSharingGetNamesAndLinks + else + if website = WebsiteRoots[HENTAI2READ_ID, 0] then + Result := Hentai2ReadGetNamesAndLinks + else + if website = WebsiteRoots[FAKKU_ID, 0] then + Result := FakkuGetNamesAndLinks + else + if website = WebsiteRoots[MANGAREADER_ID, 0] then + Result := MangaReaderGetNamesAndLinks + else + if website = WebsiteRoots[MANGAPARK_ID, 0] then + Result := MangaParkGetNamesAndLinks + else + if website = WebsiteRoots[MANGAFOX_ID, 0] then + Result := MangaFoxGetNamesAndLinks + else + if website = WebsiteRoots[MANGATRADERS_ID, 0] then + Result := MangaTradersGetNamesAndLinks + else + if website = WebsiteRoots[STARKANA_ID, 0] then + Result := StarkanaGetNamesAndLinks + else + if website = WebsiteRoots[EATMANGA_ID, 0] then + Result := EatMangaGetNamesAndLinks + else + if website = WebsiteRoots[MANGAPANDA_ID, 0] then + Result := MangaPandaGetNamesAndLinks + else + if website = WebsiteRoots[MANGAGO_ID, 0] then + Result := MangaGoGetNamesAndLinks + else + if website = WebsiteRoots[MANGASTREAM_ID, 0] then + Result := MangaStreamGetNamesAndLinks + else + if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then + Result := RedHawkScansGetNamesAndLinks + else + if website = WebsiteRoots[S2SCAN_ID, 0] then + Result := S2ScanGetNamesAndLinks + else + if website = WebsiteRoots[EGSCANS_ID, 0] then + Result := EGScansGetNamesAndLinks + else + if website = WebsiteRoots[MANGAEDEN_ID, 0] then + Result := MangaEdenGetNamesAndLinks(WebsiteRoots[MANGAEDEN_ID, 1]) + else + if website = WebsiteRoots[PERVEDEN_ID, 0] then + Result := MangaEdenGetNamesAndLinks(WebsiteRoots[PERVEDEN_ID, 1]) + else + if website = WebsiteRoots[MEINMANGA_ID, 0] then + Result := MeinMangaGetNamesAndLinks + else + if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then + Result := BlogTruyenGetNamesAndLinks + else + if website = WebsiteRoots[TRUYENTRANHTUAN_ID, 0] then + Result := TruyenTranhTuanGetNamesAndLinks + else + if website = WebsiteRoots[SUBMANGA_ID, 0] then + Result := SubMangaGetNamesAndLinks + else + if website = WebsiteRoots[ESMANGAHERE_ID, 0] then + Result := EsMangaHereGetNamesAndLinks + else + if website = WebsiteRoots[ANIMEEXTREMIST_ID, 0] then + Result := AnimeExtremistGetNamesAndLinks + else + if website = WebsiteRoots[KOMIKID_ID, 0] then + Result := KomikidGetNamesAndLinks + else + if website = WebsiteRoots[PECINTAKOMIK_ID, 0] then + Result := PecintaKomikGetNamesAndLinks + else + if website = WebsiteRoots[MABUNS_ID, 0] then + Result := MabunsGetNamesAndLinks + else + if website = WebsiteRoots[MANGAESTA_ID, 0] then + Result := MangaEstaGetNamesAndLinks + else + if website = WebsiteRoots[PURURIN_ID, 0] then + Result := PururinGetNamesAndLinks + else + if website = WebsiteRoots[HUGEMANGA_ID, 0] then + Result := HugeMangaGetNamesAndLinks + else + if website = WebsiteRoots[ANIMESTORY_ID, 0] then + Result := AnimeStoryGetNamesAndLinks + else + if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then + Result := LectureEnLigneGetNamesAndLinks + else + if website = WebsiteRoots[SCANMANGA_ID, 0] then + Result := ScanMangaGetNamesAndLinks + else + if website = WebsiteRoots[MANGAAR_ID, 0] then + Result := MangaArGetNamesAndLinks + else + if website = WebsiteRoots[MANGAAE_ID, 0] then + Result := MangaAeGetNamesAndLinks + else + if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then + Result := CentralDeMangasGetNamesAndLinks + else + if website = WebsiteRoots[IMANHUA_ID, 0] then + Result := imanhuaGetNamesAndLinks + else + if website = WebsiteRoots[TURKCRAFT_ID, 0] then + Result := TurkcraftGetNamesAndLinks + else + if website = WebsiteRoots[MANGAVADISI_ID, 0] then + Result := MangaVadisiGetNamesAndLinks + else + if website = WebsiteRoots[MANGAFRAME_ID, 0] then + Result := MangaFrameNamesAndLinks + else + if website = WebsiteRoots[MANGACOW_ID, 0] then + Result := MangaCowGetNamesAndLinks + else + if website = WebsiteRoots[SENMANGA_ID, 0] then + Result := SenMangaGetNamesAndLinks + else + if website = WebsiteRoots[KIVMANGA_ID, 0] then + Result := KivmangaGetNamesAndLinks + else + if website = WebsiteRoots[MANGACAN_ID, 0] then + Result := MangacanGetNamesAndLinks + else + if website = WebsiteRoots[MANGASPROJECT_ID, 0] then + Result := MangasPROJECTGetNamesAndLinks + else + if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then + Result := MangaREADER_PORGetNamesAndLinks + else + if website = WebsiteRoots[MANGA2U_ID, 0] then + Result := Manga2uGetNamesAndLinks + else + if website = WebsiteRoots[EHENTAI_ID, 0] then + Result := EHentaiGetNamesAndLinks + else + if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then + Result := MangaStreamToGetNamesAndLinks + else + if (website = WebsiteRoots[NINEMANGA_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then + Result := NineMangaGetNamesAndLinks + else + if website = WebsiteRoots[JAPANSHIN_ID, 0] then + Result := JapanShinGetNamesAndLinks + else + if website = WebsiteRoots[JAPSCAN_ID, 0] then + Result := JapscanNamesAndLinks + else + if website = WebsiteRoots[CENTRUMMANGI_PL_ID, 0] then + Result := CentrumMangi_PLGetNamesAndLinks + else + if website = WebsiteRoots[MANGALIB_PL_ID, 0] then + Result := MangaLib_PLGetNamesAndLinks + else + if website = WebsiteRoots[ONEMANGA_ID, 0] then + Result := OneMangaGetNamesAndLinks + else + if website = WebsiteRoots[MANGATOWN_ID, 0] then + Result := MangaTownGetNamesAndLinks + else + if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then + Result := ReadHentaiMangaGetNamesAndLinks + else + if website = WebsiteRoots[MANGAOKU_ID, 0] then + Result := MangaOkuGetNamesAndLinks + else + if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then + Result := MyReadingMangaInfoNamesAndLinks + else + if website = WebsiteRoots[IKOMIK_ID, 0] then + Result := IKomikNamesAndLinks + else + if website = WebsiteRoots[NHENTAI_ID, 0] then + Result := NHentaiNamesAndLinks + else + if website = WebsiteRoots[UNIONMANGAS_ID, 0] then + Result := UnionMangasNamesAndLinks + else + if website = WebsiteRoots[MANGAMINT_ID, 0] then + Result := MangaMintGetNamesAndLinks + else + if website = WebsiteRoots[UNIXMANGA_ID, 0] then + Result := UnixMangaNamesAndLinks + else + if website = WebsiteRoots[HAKIHOME_ID, 0] then + Result := HakiHomeNamesAndLinks + else + if website = WebsiteRoots[EXTREMEMANGAS_ID, 0] then + Result := ExtremeMangasNamesAndLinks + else + if website = WebsiteRoots[MANGAHOST_ID, 0] then + Result := MangaHostGetNamesAndLinks + else + if (website = WebsiteRoots[PORNCOMIX_ID, 0]) or + (website = WebsiteRoots[XXCOMICS_ID, 0]) or + (website = WebsiteRoots[XXCOMICSMT_ID, 0]) or + (website = WebsiteRoots[XXCOMICS3D_ID, 0]) or + (website = WebsiteRoots[PORNCOMIXRE_ID, 0]) or + (website = WebsiteRoots[PORNCOMIXIC_ID, 0]) or + (website = WebsiteRoots[PORNXXXCOMICS_ID, 0]) then + Result := PornComixGetNamesAndLinks(GetMangaSiteID(website)) + else + if website = WebsiteRoots[MANGASEE_ID, 0] then + Result := MangaSeeGetNamesAndLinks + else + if website = WebsiteRoots[MANGAKU_ID, 0] then + Result := MangaKuGetNamesAndLinks + else + if website = WebsiteRoots[ACADEMYVN_ID, 0] then + Result := AcademyVNGetNamesAndLinks + else + if website = WebsiteRoots[MANGAAT_ID, 0] then + Result := MangaAtGetNamesAndLinks + else + if website = WebsiteRoots[SENMANGARAW_ID, 0] then + Result := SenMangaRAWGetNamesAndLinks + else + if website = WebsiteRoots[READMANGATODAY_ID, 0] then + Result := ReadMangaTodayGetNamesAndLinks + else + if website = WebsiteRoots[LONEMANGA_ID, 0] then + Result := LoneMangaGetNamesAndLinks + else + if website = WebsiteRoots[DYNASTYSCANS_ID, 0] then + Result := DynastyScansGetNamesAndLinks + else + if website = WebsiteRoots[MADOKAMI_ID, 0] then + Result := MadokamiGetNamesAndLinks + else + if SitesIsWPManga(WebsiteID) then + Result := GetWPMangaNamesAndLinks + else + begin + Result := INFORMATION_NOT_FOUND; + Source.Free; + end; end; //remove host from url From 28885bebac81658d149052363bdcea337673c5ca Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 17 Jul 2015 21:31:24 +0800 Subject: [PATCH 0128/2794] Fix r e a d m a n g a . t o d a y Fix #72 --- baseunits/includes/ReadMangaToday/chapter_page_number.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/includes/ReadMangaToday/chapter_page_number.inc b/baseunits/includes/ReadMangaToday/chapter_page_number.inc index 379b6fcc6..75f72c4d7 100644 --- a/baseunits/includes/ReadMangaToday/chapter_page_number.inc +++ b/baseunits/includes/ReadMangaToday/chapter_page_number.inc @@ -17,7 +17,7 @@ manager.container.PageLinks.Clear; for i := 0 to parse.Count-1 do if (GetTagName(parse[i]) = 'img') and - (Pos('img-responsive-2', GetVal(parse[i], 'class')) <> 0) then + (Pos('img-responsive-', parse[i]) <> 0) then manager.container.PageLinks.Add(GetVal(parse[i], 'src')); manager.container.PageNumber := manager.container.PageLinks.Count; end; From 0cedda0d4a433b3a760d979e16655a7c40a8db56 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 00:52:44 +0800 Subject: [PATCH 0129/2794] fix freeze on exit counter create and launch exit counter dialog in mainthread --- baseunits/uDownloadsManager.pas | 50 +++---------------- baseunits/uFavoritesManager.pas | 6 +-- baseunits/uSubThread.pas | 6 +-- mangadownloader/forms/frmMain.pas | 81 +++++++++++++++++++++++-------- 4 files changed, 76 insertions(+), 67 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 15cfc59f4..4107ffd0c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -16,9 +16,9 @@ interface uses lazutf8classes, LazFileUtils, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, - Controls, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, - Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, - uPacker, uFMDThread, uMisc, USimpleLogger, dateutils, frmShutdownCounter; + RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, + ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, + uFMDThread, uMisc, USimpleLogger, dateutils; type TDownloadManager = class; @@ -144,7 +144,6 @@ TDownloadManager = class FSortDirection: Boolean; FSortColumn: Integer; DownloadManagerFile: TIniFile; - FisDlgCounter: Boolean; protected function GetTaskCount: Integer; function GetTransferRate: Integer; @@ -222,7 +221,6 @@ TDownloadManager = class property SortDirection: Boolean read FSortDirection write FSortDirection; property SortColumn: Integer read FSortColumn write FSortColumn; property TransferRate: Integer read GetTransferRate; - property isDlgCounter: Boolean read FisDlgCounter; end; resourcestring @@ -1771,7 +1769,6 @@ constructor TDownloadManager.Create; isRunningBackup := False; isRunningBackupDownloadedChaptersList := False; isReadyForExit := False; - FisDlgCounter := False; end; destructor TDownloadManager.Destroy; @@ -2125,7 +2122,6 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; procedure ShowExitCounter; begin if OptionLetFMDDo in [DO_NOTHING, DO_UPDATE] then Exit; - Self.Backup; if ThreadID <> MainThreadID then begin {$IFDEF FPC271} @@ -2181,19 +2177,17 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; if Count > 0 then begin - //MainForm.vtDownload.Repaint; if not MainForm.itRefreshDLInfo.Enabled then MainForm.itRefreshDLInfo.Enabled := True; end else - begin - //MainForm.vtDownload.Repaint; MainForm.itRefreshDLInfo.Enabled := False; - end; + + Self.Backup; + MainForm.vtDownloadFilters; if (Count = 0) and (isCheckForFMDDo) then ShowExitCounter; - MainForm.vtDownloadFilters; except on E: Exception do MainForm.ExceptionHandler(Self, E); @@ -2438,36 +2432,8 @@ procedure TDownloadManager.RemoveAllFinishedTasks; procedure TDownloadManager.doExitWaitCounter; begin - FisDlgCounter := True; - with TShutdownCounterForm.Create(MainForm) do try - case OptionLetFMDDo of - DO_POWEROFF: - begin - WaitTimeout := 60; - LabelMessage := RS_LblMessageShutdown; - end; - DO_HIBERNATE: - begin - WaitTimeout := 30; - LabelMessage := RS_LblMessageHibernate; - end; - DO_EXIT: - begin - WaitTimeout := 5; - LabelMessage := RS_LblMessageExit; - end; - end; - ExitWaitOK := (ShowModal = mrOK); - finally - Free; - end; - - if ExitWaitOK then - begin - frmMain.DoAfterFMD := OptionLetFMDDo; - MainForm.itMonitor.Enabled := True; - end; - FisDlgCounter := False; + frmMain.DoAfterFMD := OptionLetFMDDo; + MainForm.itMonitor.Enabled := True; end; function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolean; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 17a7a639b..994fb9270 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -341,7 +341,7 @@ procedure TFavoriteTask.Execute; Sleep(100); end; - if (not Terminated) and (not manager.DLManager.isDlgCounter) then + if (not Terminated) and (not isDlgCounter) then Synchronize(SyncShowResult); except on E: Exception do @@ -436,7 +436,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); var i: Integer; begin - if DLManager.isDlgCounter then Exit; + if isDlgCounter then Exit; try if FavoriteIndex > -1 then TFavoriteContainer(FFavorites[FavoriteIndex]).Status := STATUS_CHECK @@ -510,7 +510,7 @@ procedure TFavoriteManager.ShowResult; removeListStr : String = ''; favDelete : Boolean; begin - if DLManager.isDlgCounter then Exit; + if isDlgCounter then Exit; try CS_Favorites.Acquire; dlChapters := TStringList.Create; diff --git a/baseunits/uSubThread.pas b/baseunits/uSubThread.pas index 5e111eab2..643982080 100644 --- a/baseunits/uSubThread.pas +++ b/baseunits/uSubThread.pas @@ -59,7 +59,7 @@ implementation procedure TCheckUpdateThread.MainThreadUpdate; begin - if MainForm.DLManager.isDlgCounter then Exit; + if IsDlgCounter then Exit; with TUpdateDialogForm.Create(MainForm) do try Caption := Application.Title + ' - ' + RS_NewVersionFound; with mmLog.Lines do @@ -130,7 +130,7 @@ procedure TCheckUpdateThread.Execute; FHTTP.Free; l.Free; end; - if not Terminated and updateFound and (not MainForm.DLManager.isDlgCounter) then + if not Terminated and updateFound and (not isDlgCounter) then Synchronize(MainThreadUpdate); end; @@ -159,7 +159,7 @@ procedure TSubThread.Execute; while not Terminated do begin if CheckUpdate and (not FCheckUpdateRunning) and - (not MainForm.DLManager.isDlgCounter) then + (not isDlgCounter) then begin FCheckUpdateThread := TCheckUpdateThread.Create(True); FCheckUpdateThread.CheckStatus := @CheckUpdate; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 02e20b0c6..0f9b33224 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -624,10 +624,13 @@ TMainForm = class(TForm) // openwith procedure OpenWithExternalProgram(const dirPath, Filename: String); - //transfer rate graph + // transfer rate graph procedure TransferRateGraphInit(xCount: Integer = 10); procedure TransferRateGraphAddItem(TransferRate: Integer); + // exit counter + function ShowExitCounter: Boolean; + // exception handle procedure ExceptionHandler(Sender: TObject; E: Exception); { public declarations } @@ -642,6 +645,7 @@ TMainForm = class(TForm) // update fmd through main thread DoAfterFMD: TFMDDo; + IsDlgCounter: Boolean = False; FUpdateURL: String; const @@ -705,7 +709,8 @@ implementation {$R *.lfm} uses - frmImportFavorites, RegExpr, Clipbrd, LazFileUtils, LazUTF8; + frmImportFavorites, frmShutdownCounter, RegExpr, Clipbrd, LazFileUtils, + LazUTF8; { TMainForm } @@ -978,36 +983,74 @@ procedure TMainForm.itAnimateTimer(Sender: TObject); procedure TMainForm.itCheckForChaptersTimer(Sender: TObject); begin - if DLManager.isDlgCounter then Exit; + if IsDlgCounter then Exit; if options.ReadBool('update', 'AutoCheckUpdate', True) then SubThread.CheckUpdate := True; FavoriteManager.isAuto := True; FavoriteManager.CheckForNewChapter; end; +function TMainForm.ShowExitCounter: Boolean; +begin + IsDlgCounter := True; + with TShutdownCounterForm.Create(nil) do try + case DoAfterFMD of + DO_POWEROFF: + begin + WaitTimeout := 60; + LabelMessage := RS_LblMessageShutdown; + end; + DO_HIBERNATE: + begin + WaitTimeout := 30; + LabelMessage := RS_LblMessageHibernate; + end; + DO_EXIT: + begin + WaitTimeout := 5; + LabelMessage := RS_LblMessageExit; + end; + end; + Result := (ShowModal = mrOK); + finally + Free; + end; + IsDlgCounter := False; +end; + procedure TMainForm.itMonitorTimer(Sender: TObject); begin + itMonitor.Enabled := False; if DoAfterFMD <> DO_NOTHING then begin - itMonitor.Enabled := False; - Self.CloseNow(False); - case DoAfterFMD of - DO_POWEROFF: fmdPowerOff; - DO_HIBERNATE: fmdHibernate; - DO_UPDATE: + if DoAfterFMD in [DO_POWEROFF, DO_HIBERNATE, DO_EXIT] then + begin + if ShowExitCounter then begin - if FileExistsUTF8(fmdDirectory + 'updater.exe') then - CopyFile(fmdDirectory + 'updater.exe', fmdDirectory + 'old_updater.exe'); - if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then - begin - RunExternalProcess(fmdDirectory + 'old_updater.exe', - ['-x', '-r', '3', '-a', FUpdateURL, '-l', Application.ExeName, - '--lang', uTranslation.LastSelected], True, False); - Self.Close; - end; + Self.CloseNow(False); + if DoAfterFMD = DO_POWEROFF then + fmdPowerOff + else + if DoAfterFMD = DO_HIBERNATE then + fmdHibernate; + Self.Close; + end; + end + else + if DoAfterFMD = DO_UPDATE then + begin + if FileExistsUTF8(fmdDirectory + 'updater.exe') then + CopyFile(fmdDirectory + 'updater.exe', fmdDirectory + 'old_updater.exe'); + if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then + begin + Self.CloseNow(False); + RunExternalProcess(fmdDirectory + 'old_updater.exe', + ['-x', '-r', '3', '-a', FUpdateURL, '-l', Application.ExeName, + '--lang', uTranslation.LastSelected], True, False); + Self.Close; end; end; - Self.Close; + DoAfterFMD := DO_NOTHING; end; end; From dce1e41a21084ffc92d54b2aac3f05a436c21383 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 02:33:00 +0800 Subject: [PATCH 0130/2794] fix range check error if no languages file found #74 --- mangadownloader/forms/frmMain.pas | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0f9b33224..ac7086036 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -857,8 +857,6 @@ procedure TMainForm.FormCreate(Sender: TObject); FavoriteManager.Sort(vtFavorites.Header.SortColumn); vtFavorites.Repaint; end; - uTranslation.LangDir := GetCurrentDirUTF8 + PathDelim + 'languages'; - uTranslation.LangAppName := 'fmd'; LoadLanguage; end; @@ -3942,8 +3940,9 @@ procedure TMainForm.btOptionApplyClick(Sender: TObject); end; end; - options.WriteString('languages', 'Selected', - AvailableLanguages.Names[cbLanguages.ItemIndex]); + if cbLanguages.ItemIndex > -1 then + options.WriteString('languages', 'Selected', + AvailableLanguages.Names[cbLanguages.ItemIndex]); options.WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); options.WriteInteger('general', 'NewMangaTime', seOptionNewMangaTime.Value); options.WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); @@ -4587,13 +4586,16 @@ procedure TMainForm.LoadOptions; options.ReadBool('misc', 'MangafoxRemoveWatermarks', False); cbLanguages.Items.Clear; + uTranslation.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; + uTranslation.LangAppName := 'fmd'; uTranslation.CollectLanguagesFiles; if uTranslation.AvailableLanguages.Count > 0 then + begin for i := 0 to AvailableLanguages.Count - 1 do cbLanguages.Items.Add(uTranslation.AvailableLanguages.ValueFromIndex[i]); - - cbLanguages.ItemIndex := uTranslation.AvailableLanguages.IndexOfName( + cbLanguages.ItemIndex := uTranslation.AvailableLanguages.IndexOfName( options.ReadString('languages', 'Selected', 'en')); + end; end; procedure TMainForm.LoadMangaOptions; @@ -4879,6 +4881,7 @@ procedure TMainForm.LoadLanguage; idxOptionProxyType, idxDropTargetMode: Integer; begin + if AvailableLanguages.Count = 0 then Exit; if uTranslation.LastSelected <> AvailableLanguages.Names[cbLanguages.ItemIndex] then begin idxLanguages := cbLanguages.ItemIndex; From b03d8166fc976d9c3992910b0f8f99d975eaa59c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 02:38:10 +0800 Subject: [PATCH 0131/2794] added missing modules search path --- mangadownloader/md.lpi | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2be03a0f1..288371742 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -38,7 +38,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -129,7 +129,7 @@ - + @@ -212,9 +212,10 @@ - + + @@ -349,7 +350,7 @@ - + From 85ebef2548736709ae095b610765df88b8f4bfa6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 02:39:25 +0800 Subject: [PATCH 0132/2794] remove unused variable --- baseunits/uUpdateThread.pas | 2 -- 1 file changed, 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 4d642b6d2..f0f56fbf3 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -119,8 +119,6 @@ procedure TUpdateMangaThread.MainThreadUpdateNamesAndLinks; end; procedure TUpdateMangaThread.Execute; -var - iPos: Integer; begin try case CheckStyle of From f6733d75a656d98af265d10534fb77883203bd3f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 02:58:11 +0800 Subject: [PATCH 0133/2794] convert to UTF8 without BOM --- 3rd/synapse/source/synautil.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/3rd/synapse/source/synautil.pas b/3rd/synapse/source/synautil.pas index b275d70ca..6b39d31c9 100644 --- a/3rd/synapse/source/synautil.pas +++ b/3rd/synapse/source/synautil.pas @@ -395,16 +395,16 @@ implementation 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //English 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), - ('jan', 'f�v', 'mar', 'avr', 'mai', 'jun', //French - 'jul', 'ao�', 'sep', 'oct', 'nov', 'd�c'), + ('jan', 'fév', 'mar', 'avr', 'mai', 'jun', //French + 'jul', 'aoû', 'sep', 'oct', 'nov', 'déc'), ('jan', 'fev', 'mar', 'avr', 'mai', 'jun', //French#2 'jul', 'aou', 'sep', 'oct', 'nov', 'dec'), ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', //German 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), - ('Jan', 'Feb', 'M�r', 'Apr', 'Mai', 'Jun', //German#2 + ('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', //German#2 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), - ('Led', '�no', 'B�e', 'Dub', 'Kv�', '�en', //Czech - '�ec', 'Srp', 'Z��', '��j', 'Lis', 'Pro') + ('Led', 'Úno', 'Bøe', 'Dub', 'Kvì', 'Èen', //Czech + 'Èec', 'Srp', 'Záø', 'Øíj', 'Lis', 'Pro') ); From af468f63c81ca870fb12c961b32159f942ff386a Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:08:51 +0800 Subject: [PATCH 0134/2794] utranslations, fix some issue #74 --- baseunits/utranslation.pas | 54 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/baseunits/utranslation.pas b/baseunits/utranslation.pas index abd96361d..07cd4b9cc 100644 --- a/baseunits/utranslation.pas +++ b/baseunits/utranslation.pas @@ -25,8 +25,8 @@ interface uses - Classes, SysUtils, strutils, gettext, LazFileUtils, LazUTF8, - LCLTranslator, Translations, LResources, Forms; + Classes, SysUtils, strutils, gettext, LazFileUtils, LazUTF8, LCLTranslator, + Translations, LResources, Forms; type TLanguageItem = record @@ -671,11 +671,12 @@ TLanguageItem = record LangDir: string = ''; LangAppName: string = ''; - procedure CollectLanguagesFiles(appname: string = ''; dir: string = ''; useNativeName: Boolean = True); - function GetLangName(lcode: string; useNativeName: Boolean = True): string; + procedure CollectLanguagesFiles(const appname: string = ''; const dir: string = ''; + useNativeName: Boolean = True); + function GetLangName(const lcode: string; useNativeName: Boolean = True): string; - function SetLang(lang: string; appname: string = ''): Boolean; - function SetLangByIndex(Idx: Integer): Boolean; + function SetLang(const lang: string; appname: string = ''): Boolean; + function SetLangByIndex(const Index: Integer): Boolean; function GetDefaultLang: string; implementation @@ -685,7 +686,7 @@ function SortValue(List: TStringList; Index1, Index2: Integer): Integer; Result := CompareStr(List.ValueFromIndex[Index1], List.ValueFromIndex[Index2]); end; -procedure CollectLanguagesFiles(appname: string; dir: string; +procedure CollectLanguagesFiles(const appname: string; const dir: string; useNativeName: Boolean); procedure searchLangDir(adir, aname: string); @@ -718,46 +719,49 @@ procedure CollectLanguagesFiles(appname: string; dir: string; end; until FindNextUTF8(SR) <> 0; FindCloseUTF8(SR); - if AvailableLanguages.Count > 0 then - AvailableLanguages.CustomSort(@SortValue); end; end; var - sdir: string; + sdir, tdir, tappname: string; lauto: Boolean = False; i: Integer; begin - if dir = '' then + tdir := dir; + if tdir = '' then begin if LangDir <> '' then - dir := LangDir + tdir := LangDir else begin - dir := GetCurrentDirUTF8 + PathDelim; + tdir := CleanAndExpandDirectory(GetCurrentDirUTF8); lauto := True; end; end; - if appname = '' then + tappname := appname; + if tappname = '' then begin if LangAppName <> '' then - appname := LangAppName + tappname := LangAppName else - appname := ExtractFileNameOnly(ParamStrUTF8(0)); + tappname := ExtractFileNameOnly(ParamStrUTF8(0)); end; AvailableLanguages.Clear; if lauto then for i := Low(ldir) to High(ldir) do begin - sdir := dir + ldir[i] + PathDelim; - searchLangDir(sdir, appname); + sdir := tdir + ldir[i] + PathDelim; + searchLangDir(sdir, tappname); end else - searchLangDir(dir, appname); + searchLangDir(tdir, tappname); + + if AvailableLanguages.Count > 0 then + AvailableLanguages.CustomSort(@SortValue); end; -function GetLangName(lcode: string; useNativeName: Boolean): string; +function GetLangName(const lcode: string; useNativeName: Boolean): string; function GetLang(const l: string): string; var @@ -897,7 +901,7 @@ function TranslateLCL(Lang: string): Boolean; end; end; -function SetLang(lang: string; appname: string): Boolean; +function SetLang(const lang: string; appname: string): Boolean; var lfile: string; ltrans: TUpdateTranslator; @@ -946,12 +950,12 @@ function SetLang(lang: string; appname: string): Boolean; end; end; -function SetLangByIndex(Idx: Integer): Boolean; +function SetLangByIndex(const Index: Integer): Boolean; begin Result := False; - if Idx < 0 then Exit; - if LastSelected <> AvailableLanguages.Names[idx] then - Result := SetLang(AvailableLanguages.Names[idx]); + if Index < 0 then Exit; + if LastSelected <> AvailableLanguages.Names[Index] then + Result := SetLang(AvailableLanguages.Names[Index]); end; function GetDefaultLang: string; From 59e88a80a0235156f0d795ce87c42f77e719a867 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:10:09 +0800 Subject: [PATCH 0135/2794] set UTF8 for all build modes fix #74 --- mangadownloader/md.lpi | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 288371742..f484d5b03 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -68,7 +68,8 @@ +-dRELEASEWIN64 +-FcUTF8"/> @@ -115,7 +116,8 @@ +-dDEBUGWIN32 +-FcUTF8"/> @@ -159,7 +161,8 @@ +-dDEBUGWIN64 +-FcUTF8"/> @@ -205,7 +208,8 @@ -dSELFUPDATE -dLOGACTIVE -dDEBUGWIN32 --dDEBUGLEAKS"/> +-dDEBUGLEAKS +-FcUTF8"/> @@ -215,7 +219,7 @@ - + @@ -383,7 +387,8 @@ +-dRELEASEWIN32 +-FcUTF8"/> From 1ed2d2ee1823a69604f04886a7098a9c5314d799 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:35:11 +0800 Subject: [PATCH 0136/2794] updater, set UTF8 in RTL --- updater/updater.lpi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/updater/updater.lpi b/updater/updater.lpi index bbae49445..c43fc39ee 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -57,8 +57,14 @@ + + + + + + @@ -129,6 +135,9 @@ + + + From f3908fe0e786363b41451adcac2758a225897661 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:35:26 +0800 Subject: [PATCH 0137/2794] updater, clean up --- updater/uMain.pas | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 7b6f377bf..990f3a35c 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -9,9 +9,10 @@ interface cthreads, cmem, {$endif} - Classes, SysUtils, zipper, FileUtil, UTF8Process, Forms, Dialogs, ComCtrls, - StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, RegExpr, IniFiles, process, - USimpleException, uMisc, uTranslation, httpsend, blcksock, ssl_openssl; + Classes, SysUtils, zipper, FileUtil, UTF8Process, LazFileUtils, LazUTF8, + Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, + RegExpr, IniFiles, process, USimpleException, uMisc, uTranslation, httpsend, + blcksock, ssl_openssl; type @@ -616,7 +617,7 @@ procedure TfrmMain.FormCreate(Sender :TObject); begin Randomize; InitSimpleExceptionHandler(ChangeFileExt(Application.ExeName, '.log')); - uTranslation.LangDir := GetCurrentDirUTF8 + PathDelim + 'languages'; + uTranslation.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; uTranslation.LangAppName := 'updater'; uTranslation.CollectLanguagesFiles; InitCriticalSection(CS_ReadCount); From cb11ccdcc58e1947fbee3c55b168bc38354917cb Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:55:32 +0800 Subject: [PATCH 0138/2794] clean up --- baseunits/uData.pas | 1 - baseunits/uDownloadsManager.pas | 1 - 2 files changed, 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8e5813f28..7477e2de5 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1335,7 +1335,6 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; Result := True; end; -// TODO: load from all files - this function is for "Filter all sites" function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; var id, j, i: Cardinal; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4107ffd0c..2181d1db6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1310,7 +1310,6 @@ procedure TTaskThread.CheckOut; mt: Integer; begin if Terminated then Exit; - // TODO: Ugly code, need to be fixed later //load advanced config if any mt := INIAdvanced.ReadInteger('DownloadMaxThreadsPerTask', From d1480a9b98d61cd946acf8636e616800b12f1802 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:56:06 +0800 Subject: [PATCH 0139/2794] add resourcestring --- mangadownloader/forms/frmMain.pas | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ac7086036..ccabb0788 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -703,6 +703,7 @@ TMainForm = class(TForm) RS_InfoGenres = 'Genre(s):'; RS_InfoStatus = 'Status:'; RS_InfoSummary = 'Summary:'; + RS_FMDAlreadyRunning = 'Free Manga Downloader already running!'; implementation @@ -1717,9 +1718,7 @@ procedure TMainForm.DisableAddToFavorites(webs: String); procedure TMainForm.FMDInstanceReceiveMsg(Sender: TObject); begin - { TODO 5 -oCholif : Need translation } - MessageDlg('Free Manga Downloader', 'Free Manga Downloader already running!', - mtWarning, [mbOK], 0); + MessageDlg(Application.Title, RS_FMDAlreadyRunning, mtWarning, [mbOK], 0); if WindowState = wsMinimized then WindowState := wsNormal; Show; From 600c788d41cc80e216af32d257e7479a0c8d6de0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:56:24 +0800 Subject: [PATCH 0140/2794] update translations --- mangadownloader/languages/fmd.en.po | 8 +++++--- mangadownloader/languages/fmd.po | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 80449dbe8..5258c28ff 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -112,6 +112,10 @@ msgstr "" "Ongoing\n" "\n" +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader already running!" + #: frmmain.rs_hintfavoriteproblem msgid "" "There is a problem with this data!\n" @@ -1184,7 +1188,6 @@ msgid "Change \"Save to\"" msgstr "Change \"Save to\"" #: tmainform.mifavoriteschecknewchapter.caption -#, fuzzy msgctxt "tmainform.mifavoriteschecknewchapter.caption" msgid "Check for new chapter" msgstr "Check for new chapter" @@ -1211,7 +1214,7 @@ msgstr "Open ..." #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" -msgstr "" +msgstr "Stop check for new chapter" #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" @@ -1631,4 +1634,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c5189ee99..12a52666b 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -94,6 +94,10 @@ msgid "" "\n" msgstr "" +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "" + #: frmmain.rs_hintfavoriteproblem msgid "" "There is a problem with this data!\n" From 23d40d2c09c3010679e3fabb8e50558134f78d80 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 03:56:37 +0800 Subject: [PATCH 0141/2794] update Indonesian translations --- mangadownloader/languages/fmd.id_ID.po | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index ecbb6350c..e4ee41e98 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -112,6 +112,10 @@ msgstr "" "Bersambung\n" "\n" +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader sudah berjalan!" + #: frmmain.rs_hintfavoriteproblem msgid "" "There is a problem with this data!\n" @@ -1621,4 +1625,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - From 93e15a7a706de96fcf2425a1d4b610aa2a8803b8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 04:14:48 +0800 Subject: [PATCH 0142/2794] updater, increase version number --- updater/updater.lpi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/updater.lpi b/updater/updater.lpi index c43fc39ee..2dd277225 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -19,7 +19,7 @@ - + From 4f7d249cfe3e53afefbf5ec7f5fc1ee0e528a48c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 05:06:46 +0800 Subject: [PATCH 0143/2794] baseunit, move runexternalprocess to umisc --- baseunits/uBaseUnit.pas | 275 +------------------------- baseunits/uMisc.pas | 357 ++++++++++++++++++++++++++++++++++ baseunits/uUpdateDBThread.pas | 2 +- baseunits/uUpdateThread.pas | 2 +- 4 files changed, 360 insertions(+), 276 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a4867ef2a..e916074ba 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -14,7 +14,7 @@ interface uses {$ifdef windows} - ShellApi, windows, + windows, {$else} UTF8Process, {$endif} @@ -871,13 +871,6 @@ procedure ParseHTML(const aRaw: string; var aOutput: TStringList); function QuotedStrd(const S: string): string; overload; function QuotedStrd(const S: Integer): string; overload; function BracketStr(const S: string): string; -procedure ParseCommandLine(const cmd: string; var Output: TStrings; - AStripQuotes: Boolean = False); -function ParsedCommandLine(const cmd: String): TArrayOfString; -function StringsToArray(const S: TStrings): TArrayOfString; -function StringsToCommandLine(const S: TStrings): string; overload; -function StringsToCommandLine(const S: array of string): string; overload; -procedure DeleteArrayOfString(Var TheStrings: TArrayOfString;Index: Integer); function RandomString(SLength: Integer; ONumber: Boolean = False; OSymbol: Boolean = False; OSpace: Boolean = False): string; function GetValuesFromString(Str: String; Sepr: Char): String; @@ -978,14 +971,6 @@ function fmdGetTempPath: String; function fmdGetTickCount: Cardinal; procedure fmdPowerOff; procedure fmdHibernate; -function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean = True; - isPersistent: Boolean = True): Boolean; -function RunExternalProcess(Exe: String; Params: array of string; ShowWind: Boolean = True; - isPersistent: Boolean = True): Boolean; overload; -function RunExternalProcess(Exe, Params: String; ShowWind: Boolean = True; - isPersistent: Boolean = True): Boolean; overload; -function RunExternalProcess(CommandLine: String; ShowWind: Boolean = True; - isPersistent: Boolean = True): Boolean; overload; implementation @@ -1615,81 +1600,6 @@ procedure ParseCommandLine(const cmd: string; var Output: TStrings; end; end; -function ParsedCommandLine(const cmd: String): TArrayOfString; -var - ts: TStrings; -begin - if cmd = '' then Exit; - ts := TStringList.Create; - try - ParseCommandLine(cmd, ts, True); - Result := StringsToArray(ts); - finally - ts.Free; - end; -end; - -function StringsToArray(const S: TStrings): TArrayOfString; -var - i: Integer; -begin - SetLength(Result, 0); - if not Assigned(S) then Exit; - if S.Count = 0 then Exit; - SetLength(Result, S.Count); - for i := 0 to S.Count - 1 do - Result[i] := S[i]; -end; - -function StringsToCommandLine(const S: TStrings): string; -var - i: Integer; -begin - Result := ''; - if S.Count>0 then - begin - for i := 0 to S.Count-1 do - begin - if Pos(' ', S[i]) <> 0 then - Result := Result + '"' + S[i] + '" ' - else - Result := Result + S[i] + ' '; - end; - Result := Trim(Result); - end; -end; - -function StringsToCommandLine(const S: array of string): string; -var - i: Integer; -begin - Result := ''; - if Length(S)>0 then - begin - for i := Low(S) to High(S) do - begin - if (Pos(' ', S[i]) <> 0) and - ((LeftStr(S[i], 1) <> '"') and (RightStr(S[i], 1) <> '"')) then - Result := Result + '"' + S[i] + '" ' - else - Result := Result + S[i] + ' '; - end; - Result := Trim(Result); - end; -end; - -procedure DeleteArrayOfString(var TheStrings: TArrayOfString;Index: Integer); - var - i: Integer; - begin - if Length(TheStrings) > 0 then - begin - for i := Low(TheStrings) to High(TheStrings) -1 do - TheStrings[i] := TheStrings[i + 1]; - SetLength(TheStrings, Length(TheStrings) - 1); - end; - end; - function RandomString(SLength: Integer; ONumber: Boolean; OSymbol: Boolean; OSpace: Boolean): string; var @@ -3620,189 +3530,6 @@ procedure fmdHibernate; {$ENDIF} end; -function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean; - isPersistent: Boolean): Boolean; -var - {$IFDEF WINDOWS} - SEInfo: TSHELLEXECUTEINFOW; - {$ELSE} - Process: TProcessUTF8; - pr: TStringList; - {$ENDIF} -begin - {$IFDEF WINDOWS} - Initialize(SEInfo); - FillChar(SEInfo, SizeOf(SEInfo), 0); - SEInfo.cbSize := SizeOf(SEInfo); - with SEInfo do begin - wnd := 0; - fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; - if isPersistent then - fMask := fMask or SEE_MASK_NOCLOSEPROCESS; - lpVerb := 'runas'; - lpFile := PWideChar(UTF8Decode(Exe)); - lpParameters := PWideChar(UTF8Decode(Params)); - if ShowWind then - nShow := SW_SHOWNORMAL - else - nShow := SW_HIDE; - end; - Result := ShellExecuteExW(@SEInfo); - if isPersistent then - WaitForSingleObject(SEInfo.hProcess, INFINITE); - {$ELSE} - Process := TProcessUTF8.Create(nil); - try - Process.Executable := Exe; - pr := TStringList.Create; - try - ParseCommandLine(Params, TStrings(pr), True); - Process.Parameters.Assign(pr); - finally - pr.Free; - end; - Process.Execute; - finally - Process.Free; - end; - {$ENDIF} -end; - -{$ifdef windows} -function WinRunProcessA(Exe, Params: string; ShowWind: Boolean; isPersistent: Boolean): Boolean; -var - SEInfo: TSHELLEXECUTEINFOA; -begin - Initialize(SEInfo); - FillChar(SEInfo, SizeOf(SEInfo), 0); - SEInfo.cbSize := SizeOf(TSHELLEXECUTEINFOA); - with SEInfo do begin - wnd := 0; - fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; - if isPersistent then - fMask := fMask or SEE_MASK_NOCLOSEPROCESS; - lpFile := PChar(Utf8ToAnsi(Exe)); - lpParameters := PChar(Utf8ToAnsi(Params)); - if ShowWind then - nShow := SW_SHOWNORMAL - else - nShow := SW_HIDE; - end; - Result := ShellExecuteExA(@SEInfo); - if isPersistent then - WaitForSingleObject(SEInfo.hProcess, INFINITE); -end; - -function WinRunProcessW(Exe, Params: string; ShowWind: Boolean; isPersistent: Boolean): Boolean; -var - SEInfo: TSHELLEXECUTEINFOW; -begin - Initialize(SEInfo); - FillChar(SEInfo, SizeOf(SEInfo), 0); - SEInfo.cbSize := SizeOf(TSHELLEXECUTEINFOW); - with SEInfo do begin - wnd := 0; - fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; - if isPersistent then - fMask := fMask or SEE_MASK_NOCLOSEPROCESS; - lpFile := PWideChar(UTF8Decode(Exe)); - lpParameters := PWideChar(UTF8Decode(Params)); - if ShowWind then - nShow := SW_SHOWNORMAL - else - nShow := SW_HIDE; - end; - Result := ShellApi.ShellExecuteExW(@SEInfo); - if isPersistent then - WaitForSingleObject(SEInfo.hProcess, INFINITE); -end; -{$endif} - -function RunExternalProcess(Exe: String; Params: array of string; - ShowWind: Boolean; isPersistent: Boolean): Boolean; -{$ifndef windows} -var - Process: TProcessUTF8; - I: Integer; -{$endif} -begin - if Trim(Exe) = '' then Exit(False); - Result := True; - {$ifdef windows} - if Win32Platform = VER_PLATFORM_WIN32_NT then - Result := WinRunProcessW(Exe, StringsToCommandLine(Params), ShowWind, isPersistent) - else - Result := WinRunProcessA(Exe, StringsToCommandLine(Params), ShowWind, isPersistent); - {$else} - Process := TProcessUTF8.Create(nil); - try - Process.InheritHandles := isPersistent; - Process.Executable := Exe; - Process.Parameters.AddStrings(Params); - if isPersistent then - Process.Options := Process.Options + [poWaitOnExit] - else - Process.Options := []; - if ShowWind then - Process.ShowWindow := swoShow - else - Process.ShowWindow := swoHIDE; - // Copy default environment variables including DISPLAY variable for GUI application to work - for I := 0 to GetEnvironmentVariableCount - 1 do - Process.Environment.Add(GetEnvironmentString(I)); - Process.Execute; - except - on E: Exception do - begin - WriteLog_E('RunExternalProcess.Error '#13#10+ - 'Executable: '+Exe+#13#10+ - 'Parameters: '+StringsToCommandLine(Params)+#13#10+ - 'Message : '+E.Message+#13#10+ - GetStackTraceInfo); - end; - end; - Process.Free; - {$endif} -end; - -function RunExternalProcess(Exe, Params: String; ShowWind: Boolean; - isPersistent: Boolean): Boolean; -begin - if Trim(Exe) = '' then Exit(False); - {$ifdef windows} - if Win32Platform = VER_PLATFORM_WIN32_NT then - Result := WinRunProcessW(Exe, Params, ShowWind, isPersistent) - else - Result := WinRunProcessA(Exe, Params, ShowWind, isPersistent); - {$else} - Result := RunExternalProcess(Exe, ParsedCommandLine(Params), ShowWind, isPersistent); - {$endif} -end; - -function RunExternalProcess(CommandLine: String; ShowWind: Boolean; - isPersistent: Boolean): Boolean; -var - s: string; - sa: TArrayOfString; -begin - if Trim(CommandLine) = '' then Exit(False); - try - sa := ParsedCommandLine(CommandLine); - s := sa[Low(sa)]; - DeleteArrayOfString(sa, Low(sa)); - {$ifdef windows} - if Win32Platform = VER_PLATFORM_WIN32_NT then - Result := WinRunProcessW(s, StringsToCommandLine(sa), ShowWind, isPersistent) - else - Result := WinRunProcessA(s, StringsToCommandLine(sa), ShowWind, isPersistent); - {$else} - Result := RunExternalProcess(s, sa, ShowWind, isPersistent); - {$endif} - finally - SetLength(sa, 0); - end; -end; - function HeaderByName(const AHeaders: TStrings; const AHeaderName: String): String; var i, p: Integer; diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index ac05e7ccc..8e33b04b8 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -5,10 +5,17 @@ interface uses + {$ifdef windows} + ShellApi, windows, + {$else} + UTF8Process, + {$endif} Classes, SysUtils, Graphics, strutils, syncobjs, IniFiles, NaturalSortUnit; type + TArrayOfString = array of String; + TIniFileR = class(TMemIniFile) private FCSReload: TCriticalSection; @@ -48,6 +55,25 @@ function FormatByteSize(const bytes :longint; persecond: boolean = False) :strin //sorting function NaturalCompareStr(Str1, Str2: string): integer; +//run external process +function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean = True; + isPersistent: Boolean = True): Boolean; +function RunExternalProcess(Exe: String; Params: array of string; ShowWind: Boolean = True; + isPersistent: Boolean = True): Boolean; overload; +function RunExternalProcess(Exe, Params: String; ShowWind: Boolean = True; + isPersistent: Boolean = True): Boolean; overload; +function RunExternalProcess(CommandLine: String; ShowWind: Boolean = True; + isPersistent: Boolean = True): Boolean; overload; + +//stringutils +procedure ParseCommandLine(const cmd: string; var Output: TStrings; + AStripQuotes: Boolean = False); +function ParsedCommandLine(const cmd: String): TArrayOfString; +function StringsToArray(const S: TStrings): TArrayOfString; +function StringsToCommandLine(const S: TStrings): string; overload; +function StringsToCommandLine(const S: array of string): string; overload; +procedure DeleteArrayOfString(Var TheStrings: TArrayOfString; Index: Integer); + const UA_CURL = 'curl/7.42.1'; UA_MSIE = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; @@ -467,4 +493,335 @@ function FormatByteSize(const bytes :longint; persecond: boolean = False) :strin Result := Result + 'ps'; end; + +function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean; + isPersistent: Boolean): Boolean; +var + {$IFDEF WINDOWS} + SEInfo: TSHELLEXECUTEINFOW; + {$ELSE} + Process: TProcessUTF8; + pr: TStringList; + {$ENDIF} +begin + {$IFDEF WINDOWS} + Initialize(SEInfo); + FillChar(SEInfo, SizeOf(SEInfo), 0); + SEInfo.cbSize := SizeOf(SEInfo); + with SEInfo do begin + wnd := 0; + fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; + if isPersistent then + fMask := fMask or SEE_MASK_NOCLOSEPROCESS; + lpVerb := 'runas'; + lpFile := PWideChar(UTF8Decode(Exe)); + lpParameters := PWideChar(UTF8Decode(Params)); + if ShowWind then + nShow := SW_SHOWNORMAL + else + nShow := SW_HIDE; + end; + Result := ShellExecuteExW(@SEInfo); + if isPersistent then + WaitForSingleObject(SEInfo.hProcess, INFINITE); + {$ELSE} + Process := TProcessUTF8.Create(nil); + try + Process.Executable := Exe; + pr := TStringList.Create; + try + ParseCommandLine(Params, TStrings(pr), True); + Process.Parameters.Assign(pr); + finally + pr.Free; + end; + Process.Execute; + finally + Process.Free; + end; + {$ENDIF} +end; + +{$ifdef windows} +function WinRunProcessA(Exe, Params: string; ShowWind: Boolean; isPersistent: Boolean): Boolean; +var + SEInfo: TSHELLEXECUTEINFOA; +begin + Initialize(SEInfo); + FillChar(SEInfo, SizeOf(SEInfo), 0); + SEInfo.cbSize := SizeOf(TSHELLEXECUTEINFOA); + with SEInfo do begin + wnd := 0; + fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; + if isPersistent then + fMask := fMask or SEE_MASK_NOCLOSEPROCESS; + lpFile := PChar(Utf8ToAnsi(Exe)); + lpParameters := PChar(Utf8ToAnsi(Params)); + if ShowWind then + nShow := SW_SHOWNORMAL + else + nShow := SW_HIDE; + end; + Result := ShellExecuteExA(@SEInfo); + if isPersistent then + WaitForSingleObject(SEInfo.hProcess, INFINITE); +end; + +function WinRunProcessW(Exe, Params: string; ShowWind: Boolean; isPersistent: Boolean): Boolean; +var + SEInfo: TSHELLEXECUTEINFOW; +begin + Initialize(SEInfo); + FillChar(SEInfo, SizeOf(SEInfo), 0); + SEInfo.cbSize := SizeOf(TSHELLEXECUTEINFOW); + with SEInfo do begin + wnd := 0; + fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI; + if isPersistent then + fMask := fMask or SEE_MASK_NOCLOSEPROCESS; + lpFile := PWideChar(UTF8Decode(Exe)); + lpParameters := PWideChar(UTF8Decode(Params)); + if ShowWind then + nShow := SW_SHOWNORMAL + else + nShow := SW_HIDE; + end; + Result := ShellApi.ShellExecuteExW(@SEInfo); + if isPersistent then + WaitForSingleObject(SEInfo.hProcess, INFINITE); +end; +{$endif} + +function RunExternalProcess(Exe: String; Params: array of string; + ShowWind: Boolean; isPersistent: Boolean): Boolean; +{$ifndef windows} +var + Process: TProcessUTF8; + I: Integer; +{$endif} +begin + if Trim(Exe) = '' then Exit(False); + Result := True; + {$ifdef windows} + if Win32Platform = VER_PLATFORM_WIN32_NT then + Result := WinRunProcessW(Exe, StringsToCommandLine(Params), ShowWind, isPersistent) + else + Result := WinRunProcessA(Exe, StringsToCommandLine(Params), ShowWind, isPersistent); + {$else} + Process := TProcessUTF8.Create(nil); + try + Process.InheritHandles := isPersistent; + Process.Executable := Exe; + Process.Parameters.AddStrings(Params); + if isPersistent then + Process.Options := Process.Options + [poWaitOnExit] + else + Process.Options := []; + if ShowWind then + Process.ShowWindow := swoShow + else + Process.ShowWindow := swoHIDE; + // Copy default environment variables including DISPLAY variable for GUI application to work + for I := 0 to GetEnvironmentVariableCount - 1 do + Process.Environment.Add(GetEnvironmentString(I)); + Process.Execute; + except + on E: Exception do + begin + WriteLog_E('RunExternalProcess.Error '#13#10+ + 'Executable: '+Exe+#13#10+ + 'Parameters: '+StringsToCommandLine(Params)+#13#10+ + 'Message : '+E.Message+#13#10+ + GetStackTraceInfo); + end; + end; + Process.Free; + {$endif} +end; + +function RunExternalProcess(Exe, Params: String; ShowWind: Boolean; + isPersistent: Boolean): Boolean; +begin + if Trim(Exe) = '' then Exit(False); + {$ifdef windows} + if Win32Platform = VER_PLATFORM_WIN32_NT then + Result := WinRunProcessW(Exe, Params, ShowWind, isPersistent) + else + Result := WinRunProcessA(Exe, Params, ShowWind, isPersistent); + {$else} + Result := RunExternalProcess(Exe, ParsedCommandLine(Params), ShowWind, isPersistent); + {$endif} +end; + +function RunExternalProcess(CommandLine: String; ShowWind: Boolean; + isPersistent: Boolean): Boolean; +var + s: string; + sa: TArrayOfString; +begin + if Trim(CommandLine) = '' then Exit(False); + try + sa := ParsedCommandLine(CommandLine); + s := sa[Low(sa)]; + DeleteArrayOfString(sa, Low(sa)); + {$ifdef windows} + if Win32Platform = VER_PLATFORM_WIN32_NT then + Result := WinRunProcessW(s, StringsToCommandLine(sa), ShowWind, isPersistent) + else + Result := WinRunProcessA(s, StringsToCommandLine(sa), ShowWind, isPersistent); + {$else} + Result := RunExternalProcess(s, sa, ShowWind, isPersistent); + {$endif} + finally + SetLength(sa, 0); + end; +end; + +procedure ParseCommandLine(const cmd: string; var Output: TStrings; + AStripQuotes: Boolean = False); +var + s, cl: string; + cq: Integer; + acl, lq: Boolean; + + procedure Addcl; + begin + if cl <> '' then + begin + if AStripQuotes and (Length(cl) > 1) then + begin + if cl[1] = '"' then + Delete(cl, 1, 1); + if cl[Length(cl)] = '"' then + Delete(cl, Length(cl), 1); + end; + Output.Add(cl); + cl := ''; + acl := False; + end; + end; + +begin + if not Assigned(Output) then Exit; + Output.Clear; + Output.BeginUpdate; + try + s := cmd; + cl := ''; + cq := 0; + lq := False; + while s <> '' do + begin + acl := True; + if s[1] = '"' then + begin + Inc(cq); + lq := True; + end + else + begin + if s[1] = ' ' then + begin + if cq > 0 then + begin + if (not odd(cq)) and lq then + begin + cq := 0; + Addcl; + end; + end + else + Addcl; + end; + lq := False; + end; + if acl then + cl := cl + s[1]; + Delete(s, 1, 1); + end; + Addcl; + finally + Output.EndUpdate; + end; +end; + +function ParsedCommandLine(const cmd: String): TArrayOfString; +var + ts: TStrings; +begin + if cmd = '' then Exit; + ts := TStringList.Create; + try + ParseCommandLine(cmd, ts, True); + Result := StringsToArray(ts); + finally + ts.Free; + end; +end; + +function StringsToArray(const S: TStrings): TArrayOfString; +var + i: Integer; +begin + SetLength(Result, 0); + if not Assigned(S) then Exit; + if S.Count = 0 then Exit; + SetLength(Result, S.Count); + for i := 0 to S.Count - 1 do + Result[i] := S[i]; +end; + +function StringsToCommandLine(const S: TStrings): string; +var + i: Integer; +begin + Result := ''; + if S.Count>0 then + begin + for i := 0 to S.Count-1 do + begin + if Pos(' ', S[i]) <> 0 then + Result := Result + '"' + S[i] + '" ' + else + Result := Result + S[i] + ' '; + end; + Result := Trim(Result); + end; +end; + +function StringsToCommandLine(const S: array of string): string; +var + i: Integer; +begin + Result := ''; + if Length(S)>0 then + begin + for i := Low(S) to High(S) do + begin + if (Pos(' ', S[i]) <> 0) and + ((LeftStr(S[i], 1) <> '"') and (RightStr(S[i], 1) <> '"')) then + Result := Result + '"' + S[i] + '" ' + else + Result := Result + S[i] + ' '; + end; + Result := Trim(Result); + end; +end; + +procedure DeleteArrayOfString(var TheStrings: TArrayOfString; Index: Integer); +var + i: Integer; +begin + if (Index < Low(TheStrings)) and (Index > High(TheStrings)) then Exit; + if Length(TheStrings) > 0 then + begin + if Index < High(TheStrings) then + begin + for i := Index to High(TheStrings) - 1 do + TheStrings[i] := TheStrings[i + 1]; + end; + SetLength(TheStrings, Length(TheStrings) - 1); + end; +end; + end. diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 98d363455..9f32e9a0c 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, uData, uBaseUnit, uTranslation; + Classes, SysUtils, uData, uBaseUnit, uTranslation, uMisc; type TUpdateDBThread = class(TThread) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index f0f56fbf3..f61a14ee4 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, - uBaseUnit, uFMDThread, uTranslation; + uBaseUnit, uFMDThread, uTranslation, uMisc; type TUpdateMangaManagerThread = class; From 1f30f6e5bdb78ade403fd65db8833ae5e1dccaec Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 05:07:18 +0800 Subject: [PATCH 0144/2794] updater, fix working with unicode path --- updater/uMain.pas | 52 +++++++++++++---------------------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 990f3a35c..7e4a7c7a6 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -9,10 +9,10 @@ interface cthreads, cmem, {$endif} - Classes, SysUtils, zipper, FileUtil, UTF8Process, LazFileUtils, LazUTF8, + Classes, SysUtils, zipper, FileUtil,LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, - RegExpr, IniFiles, process, USimpleException, uMisc, uTranslation, httpsend, - blcksock, ssl_openssl; + RegExpr, IniFiles, USimpleException, uMisc, uTranslation, + httpsend, blcksock, ssl_openssl; type @@ -153,36 +153,6 @@ function RemoveSymbols(const input: String): String; end; end; -function RunExternalProcess(Exe: String; Params: array of String; ShowWind: Boolean = True; - Detached: Boolean = False): Boolean; -var - Process: TProcessUTF8; - I: Integer; -begin - Result := True; - Process := TProcessUTF8.Create(nil); - try - Process.InheritHandles := False; - Process.Executable := Exe; - Process.Parameters.AddStrings(Params); - if Detached then - Process.Options := [] - else - Process.Options := Process.Options + [poWaitOnExit]; - if ShowWind then - Process.ShowWindow := swoShow - else - Process.ShowWindow := swoHIDE; - // Copy default environment variables including DISPLAY variable for GUI application to work - for I := 0 to GetEnvironmentVariableCount - 1 do - Process.Environment.Add(GetEnvironmentString(I)); - Process.Execute; - except - Result := False; - end; - Process.Free; -end; - procedure IncReadCount(const ACount: Int64); begin EnterCriticalsection(CS_ReadCount); @@ -367,7 +337,7 @@ procedure TDownloadThread.Execute; sdir, sfile : String; st, HTTPHeaders: TStringList; - + filestream : TFileStreamUTF8; begin URL := Trim(URL); HTTPHeaders := TStringList.Create; @@ -529,7 +499,12 @@ procedure TDownloadThread.Execute; if ForceDirectoriesUTF8(DirPath) then begin UpdateStatus(RS_SaveFile); - FHTTP.Document.SaveToFile(fname); + filestream := TFileStreamUTF8.Create(fname, fmCreate); + try + FHTTP.Document.SaveToStream(filestream); + finally + filestream.Free; + end; end; if not FileExistsUTF8(fname) then ShowErrorMessage(RS_ErrorCheckAntiVirus); @@ -709,9 +684,10 @@ procedure TfrmMain.FormShow(Sender :TObject); dl.isSFURL := (Pos('sourceforge.net/', LowerCase(dl.URL)) <> 0) or (Pos('sf.net/', dl.URL) <> 0); dl.MaxRetry := _MaxRetry; - dl.DirPath := GetCurrentDirUTF8; - if not _UpdApp then - dl.DirPath := dl.DirPath + DirectorySeparator + 'data'; + if _UpdApp then + dl.DirPath := GetCurrentDirUTF8 + else + dl.DirPath := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'data'; dl.Extract := _Extract; dl.Start; itMonitor.Enabled := True; From c1072f28c11a25e7e8de10c64720623ba101c4d1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 05:15:09 +0800 Subject: [PATCH 0145/2794] updatedb, don't need to free --- baseunits/uUpdateDBThread.pas | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 9f32e9a0c..5e44c9dea 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -39,11 +39,9 @@ procedure TUpdateDBThread.MainThreadRefreshList; if MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex] = websiteName then begin MainForm.edSearch.Clear; + MainForm.vtMangaList.Clear; MainForm.dataProcess.RemoveFilter; - MainForm.dataProcess.Free; - MainForm.dataProcess := TDBDataProcess.Create; MainForm.dataProcess.Open(websiteName); - MainForm.vtMangaList.Clear; MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.RecordCount; MainForm.lbMode.Caption := Format(RS_ModeAll, [MainForm.dataProcess.RecordCount]); From 42505471dee92f85c1177a01c6c141c4d57723ab Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 05:31:15 +0800 Subject: [PATCH 0146/2794] updatedb, fix replace current db extract manually within fmd --- baseunits/uUpdateDBThread.pas | 41 ++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 5e44c9dea..2dfc29b54 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -11,15 +11,19 @@ interface uses - Classes, SysUtils, uData, uBaseUnit, uTranslation, uMisc; + Classes, SysUtils, uBaseUnit, uTranslation, uMisc, LazFileUtils; type + + { TUpdateDBThread } + TUpdateDBThread = class(TThread) protected procedure MainThreadShowGetting; procedure MainThreadShowEndGetting; procedure MainThreadCannotConnectToServer; procedure MainThreadRefreshList; + procedure ExtractFile; procedure Execute; override; public websiteName: String; @@ -40,11 +44,18 @@ procedure TUpdateDBThread.MainThreadRefreshList; begin MainForm.edSearch.Clear; MainForm.vtMangaList.Clear; - MainForm.dataProcess.RemoveFilter; + MainForm.dataProcess.Close; + ExtractFile; MainForm.dataProcess.Open(websiteName); MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.RecordCount; MainForm.lbMode.Caption := Format(RS_ModeAll, [MainForm.dataProcess.RecordCount]); + end + else + begin + if MainForm.dataProcess.WebsiteLoaded(websiteName) then + MainForm.dataProcess.RemoveFilter; + ExtractFile; end; except on E: Exception do @@ -54,6 +65,30 @@ procedure TUpdateDBThread.MainThreadRefreshList; MainThreadShowEndGetting; end; +procedure TUpdateDBThread.ExtractFile; +var + Sza, datapath, filepath: String; +begin + Sza := fmdDirectory + '7za.exe'; + if not FileExistsUTF8(Sza) then Exit; + + datapath := fmdDirectory + DATA_FOLDER; + filepath := datapath + websiteName; + if FileExistsUTF8(filepath + '.7z') then + filepath += '.7z' + else + if FileExistsUTF8(filepath + '.zip') then + filepath += '.zip'; + + if FileExistsUTF8(filepath) then + begin + RunExternalProcess(Sza, ['x', filepath, '-o' + + AnsiQuotedStr(datapath, '"'), '-aoa'], False, False); + Sleep(250); + DeleteFileUTF8(filepath); + end +end; + constructor TUpdateDBThread.Create; begin inherited Create(True); @@ -97,7 +132,7 @@ procedure TUpdateDBThread.Execute; begin try Synchronize(MainThreadShowGetting); - RunExternalProcess(fmdDirectory + 'updater.exe', ['-x', '-r' , '3', '-d', + RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', GetMangaDatabaseURL(websiteName), '--lang', uTranslation.LastSelected]); if FileExists(fmdDirectory + DATA_FOLDER + websiteName + '.dat') then begin From d93c6aa05c9193257ac197677e656edfa0ae5ac1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 06:00:46 +0800 Subject: [PATCH 0147/2794] updatedb, fix replace current db --- baseunits/uUpdateDBThread.pas | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 2dfc29b54..21ea8f38a 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -11,7 +11,8 @@ interface uses - Classes, SysUtils, uBaseUnit, uTranslation, uMisc, LazFileUtils; + Classes, SysUtils, uBaseUnit, uTranslation, uMisc, + LazFileUtils; type @@ -82,6 +83,10 @@ procedure TUpdateDBThread.ExtractFile; if FileExistsUTF8(filepath) then begin + if FileExistsUTF8(datapath + websiteName + DBDATA_EXT) then + DeleteFileUTF8(datapath + websiteName + DBDATA_EXT); + if FileExistsUTF8(datapath + websiteName + DATA_EXT) then + DeleteFileUTF8(datapath + websiteName + DATA_EXT); RunExternalProcess(Sza, ['x', filepath, '-o' + AnsiQuotedStr(datapath, '"'), '-aoa'], False, False); Sleep(250); @@ -134,14 +139,11 @@ procedure TUpdateDBThread.Execute; Synchronize(MainThreadShowGetting); RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', GetMangaDatabaseURL(websiteName), '--lang', uTranslation.LastSelected]); - if FileExists(fmdDirectory + DATA_FOLDER + websiteName + '.dat') then - begin - Synchronize(MainThreadRefreshList); - end + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + websiteName + '.7z') or + FileExistsUTF8(fmdDirectory + DATA_FOLDER + websiteName + '.zip') then + Synchronize(MainThreadRefreshList) else - begin Synchronize(MainThreadShowEndGetting); - end; except on E: Exception do MainForm.ExceptionHandler(Self, E); From 75db55f2934f0cec1a5275613cf5688637d868e8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 06:09:00 +0800 Subject: [PATCH 0148/2794] updater, wait for external process --- updater/uMain.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 7e4a7c7a6..2559a5673 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -548,8 +548,7 @@ procedure TDownloadThread.Execute; if FileExistsUTF8(Sza) then begin RunExternalProcess(Sza, ['x', fname, '-o' + - AnsiQuotedStr(DirPath, '"'), '-aoa'], False, False); - Sleep(250); + AnsiQuotedStr(DirPath, '"'), '-aoa'], False, True); DeleteFileUTF8(fname); end else From efe82fdcb09627358661abab50c9ce3cc4161ef9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 07:13:14 +0800 Subject: [PATCH 0149/2794] update translations --- mangadownloader/forms/frmMain.lfm | 2 +- mangadownloader/languages/fmd.en.po | 5 +++-- mangadownloader/languages/fmd.id_ID.po | 4 ++-- mangadownloader/languages/fmd.po | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index ab0e3716d..6aeb24390 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3097,7 +3097,7 @@ object MainForm: TMainForm Top = 68 Width = 157 Anchors = [akTop, akLeft, akRight] - Caption = 'Mode: Show all manga' + Caption = 'Mode: Show all (0)' Font.Style = [fsBold] ParentColor = False ParentFont = False diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 5258c28ff..5bc9fe441 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -955,8 +955,9 @@ msgid "Title" msgstr "Title" #: tmainform.lbmode.caption -msgid "Mode: Show all manga" -msgstr "Mode: Show all manga" +#| msgid "Mode: Show All (0)" +msgid "Mode: Show all (0)" +msgstr "Mode: Show all (0)" #: tmainform.lboptionautocheckminutes.caption msgctxt "tmainform.lboptionautocheckminutes.caption" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index e4ee41e98..45a351069 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -946,8 +946,8 @@ msgid "Title" msgstr "Judul" #: tmainform.lbmode.caption -msgid "Mode: Show all manga" -msgstr "Mode: Tampilkan semua komik" +msgid "Mode: Show all (0)" +msgstr "Mode: Tampilkan semua (0)" #: tmainform.lboptionautocheckminutes.caption msgctxt "tmainform.lboptionautocheckminutes.caption" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 12a52666b..1003d5d1b 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -907,7 +907,7 @@ msgid "Title" msgstr "" #: tmainform.lbmode.caption -msgid "Mode: Show all manga" +msgid "Mode: Show all (0)" msgstr "" #: tmainform.lboptionautocheckminutes.caption From b1d537cff97c1397a43bdbb96f969d826c3f7ff5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 07:21:18 +0800 Subject: [PATCH 0150/2794] tdbdataprocess, ignore conflict on insert/update --- baseunits/uData.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 7477e2de5..b5c18dcca 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -602,7 +602,6 @@ destructor TDBDataProcess.Destroy; if FConn.Connected then begin FQuery.Close; - DetachAllSites; Commit; Close; end; @@ -774,7 +773,7 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, begin if FConn.Connected then try - FConn.ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName) + + FConn.ExecuteDirect('INSERT OR IGNORE INTO ' + QuotedStr(FTableName) + #13#10'(' + DBDataProcessParam + ')' + #13#10'VALUES (' + QuotedStr(Title) + ',' + @@ -825,10 +824,10 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, AddSQL('summary', Summary); AddSQL('numchapter', IntToStr(NumChapter)); if (AWebsite <> '') and (AWebsite <> FWebsite) and FAllSitesAttached then - sql := 'UPDATE ' + AWebsite + '.' + QuotedStrd(FTableName) + + sql := 'UPDATE OR IGNORE ' + AWebsite + '.' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql else - sql := 'UPDATE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; + sql := 'UPDATE OR IGNORE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; sql += #13#10'WHERE link=' + QuotedStr(Link) + ';'; FConn.ExecuteDirect(sql); except From 0a10648a9a83d47a56a2afadaef79d9f938cff69 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 07:26:01 +0800 Subject: [PATCH 0151/2794] updatedb, wait for extract to finish --- baseunits/uUpdateDBThread.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 21ea8f38a..ce4cce5be 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -88,8 +88,7 @@ procedure TUpdateDBThread.ExtractFile; if FileExistsUTF8(datapath + websiteName + DATA_EXT) then DeleteFileUTF8(datapath + websiteName + DATA_EXT); RunExternalProcess(Sza, ['x', filepath, '-o' + - AnsiQuotedStr(datapath, '"'), '-aoa'], False, False); - Sleep(250); + AnsiQuotedStr(datapath, '"'), '-aoa'], False, True); DeleteFileUTF8(filepath); end end; From fb6720d1522bf9abdaf68df5a66a7f5e9b7516c0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 18 Jul 2015 07:36:28 +0800 Subject: [PATCH 0152/2794] updatethread, do extract manually --- baseunits/uUpdateThread.pas | 44 ++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index f61a14ee4..f8ad7ed21 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -50,6 +50,7 @@ TUpdateMangaManagerThread = class(TFMDThread) procedure MainThreadShowGetting; procedure MainThreadEndGetting; procedure MainThreadRemoveFilter; + procedure ExtractFile; procedure RefreshList; procedure DlgReport; procedure GetInfo(const limit: Cardinal; const cs: TCheckStyleType); @@ -281,6 +282,33 @@ procedure TUpdateMangaManagerThread.MainThreadRemoveFilter; MainForm.btRemoveFilterClick(MainForm.btRemoveFilter); end; +procedure TUpdateMangaManagerThread.ExtractFile; +var + Sza, datapath, filepath: String; +begin + Sza := fmdDirectory + '7za.exe'; + if not FileExistsUTF8(Sza) then Exit; + + datapath := fmdDirectory + DATA_FOLDER; + filepath := datapath + website; + if FileExistsUTF8(filepath + '.7z') then + filepath += '.7z' + else + if FileExistsUTF8(filepath + '.zip') then + filepath += '.zip'; + + if FileExistsUTF8(filepath) then + begin + if FileExistsUTF8(datapath + website + DBDATA_EXT) then + DeleteFileUTF8(datapath + website + DBDATA_EXT); + if FileExistsUTF8(datapath + website + DATA_EXT) then + DeleteFileUTF8(datapath + website + DATA_EXT); + RunExternalProcess(Sza, ['x', filepath, '-o' + + AnsiQuotedStr(datapath, '"'), '-aoa'], False, True); + DeleteFileUTF8(filepath); + end +end; + constructor TUpdateMangaManagerThread.Create; begin inherited Create(True); @@ -340,7 +368,10 @@ procedure TUpdateMangaManagerThread.RefreshList; dataProcess := TDBDataProcess.Create else dataProcess.Close; - OverwriteDBDataProcess(website, twebsite); + if isDownloadFromServer then + ExtractFile + else + OverwriteDBDataProcess(website, twebsite); dataProcess.Open(website); vtMangaList.RootNodeCount := dataProcess.RecordCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); @@ -349,7 +380,14 @@ procedure TUpdateMangaManagerThread.RefreshList; end; end else - OverwriteDBDataProcess(website, twebsite); + begin + if dataProcess.WebsiteLoaded(website) then + dataProcess.RemoveFilter; + if isDownloadFromServer then + ExtractFile + else + OverwriteDBDataProcess(website, twebsite); + end; end; except on E: Exception do @@ -522,7 +560,7 @@ procedure TUpdateMangaManagerThread.Execute; Inc(websitePtr); FStatus := RS_GettingListFor + ' ' + website + ' ...'; Synchronize(MainThreadShowGetting); - RunExternalProcess(fmdDirectory + 'updater.exe', ['-x', '-r' , '3', '-d', + RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', GetMangaDatabaseURL(website), '--lang', uTranslation.LastSelected]); Synchronize(RefreshList); end; From 3bdc2bee9462d3f872520f31a917bf19589b5d0f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 01:37:39 +0800 Subject: [PATCH 0153/2794] baseunit, add function fillhost --- baseunits/uBaseUnit.pas | 22 ++++++++++++++++++++++ mangadownloader/languages/fmd.en.po | 1 + mangadownloader/languages/fmd.id_ID.po | 1 + 3 files changed, 24 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e916074ba..6a660cd87 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -857,6 +857,7 @@ function SitesIsWPManga(const website: String): Boolean; overload; // Fill in website host if it's not present function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; +function FillHost(const Host, URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(Const URLs: TStringList); procedure RemoveHostFromURLsPair(Const URLs, Names : TStringList); @@ -1410,6 +1411,27 @@ function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; end; end; +function FillHost(const Host, URL: String): String; +var + th, tu: string; +begin + Result := URL; + if Host = '' then Exit; + with TRegExpr.Create do + try + ModifierI := True; + ModifierG := True; + Expression := '^((https?|ftp)://)?([^/]*\.\w+)?(/?.*)$'; + th := Replace(Host, '$3', True); + tu := Replace(Host, '$4', True); + if (tu <> '') and (tu[1] <> '/') then + tu := '/' + tu; + Result := th + tu; + finally + Free; + end; +end; + function RemoveHostFromURL(URL : String) : String; var regx: TRegExpr; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 5bc9fe441..24aa13ea6 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1635,3 +1635,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 45a351069..33a43d28a 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1625,3 +1625,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + From 77d8ab48feae08c278772001024e832f1c487cdc Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 01:55:37 +0800 Subject: [PATCH 0154/2794] baseunit, fix fillhost --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6a660cd87..a4fdc3f50 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1423,7 +1423,7 @@ function FillHost(const Host, URL: String): String; ModifierG := True; Expression := '^((https?|ftp)://)?([^/]*\.\w+)?(/?.*)$'; th := Replace(Host, '$3', True); - tu := Replace(Host, '$4', True); + tu := Replace(URL, '$4', True); if (tu <> '') and (tu[1] <> '/') then tu := '/' + tu; Result := th + tu; From cd20310dd0a6b8c580f618de52bc0e107d777819 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 01:56:14 +0800 Subject: [PATCH 0155/2794] websitemodules, add getinfo --- baseunits/WebsiteModules.pas | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 56d9aae2c..47238e49a 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -76,8 +76,10 @@ TWebsiteModules = class(TObject) function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL, Website: String): Integer; overload; - function GetInfo(var MangaInfo: TMangaInformation; - const Website, URL: String; const Reconnect: Cardinal): Integer; + function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; const ModuleIndex: Integer): Integer; overload; + function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; const Website: String): Integer; overload; function GetPageNumber(var Container: TTaskContainer; const URL: String): Boolean; function GetImageURL(var Container: TTaskContainer; const URL: String): Boolean; @@ -229,11 +231,20 @@ function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const Website, URL: String; const Reconnect: Cardinal): Integer; -var - p: Integer; + const URL: String; const Reconnect: Cardinal; const ModuleIndex: Integer): Integer; begin Result := MODULE_NOT_FOUND; + if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + Exit; + if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetInfo) then + Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetInfo( + MangaInfo, URL, Reconnect, TModuleContainer(FModuleList[ModuleIndex])); +end; + +function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; + const URL: String; const Reconnect: Cardinal; const Website: String): Integer; +begin + Result := GetInfo(MangaInfo, URL, Reconnect, LocateModule(Website)); end; function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; From 7d4fee4f323dc7c0117f48dee9a4343c3e9d7a05 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 02:31:12 +0800 Subject: [PATCH 0156/2794] udata, getinfo with websitemodules --- baseunits/uData.pas | 547 ++++++++++++++++++++++---------------------- 1 file changed, 278 insertions(+), 269 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b5c18dcca..8fa3a5664 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2720,281 +2720,288 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; begin if Trim(URL) = '' then Exit(INFORMATION_NOT_FOUND); - WebsiteID := GetMangaSiteID(website); - if WebsiteID > High(WebsiteRoots) then Exit(INFORMATION_NOT_FOUND); //load User-Agent from INIAdvanced if website <> '' then FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); - Source := TStringList.Create; mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; mangaInfo.chapterName.Clear; mangaInfo.chapterLinks.Clear; - if website = WebsiteRoots[ANIMEA_ID, 0] then - Result := GetAnimeAInfoFromURL - else - if website = WebsiteRoots[MANGAHERE_ID, 0] then - Result := GetMangaHereInfoFromURL - else - if website = WebsiteRoots[MANGAINN_ID, 0] then - Result := GetMangaInnInfoFromURL - else - if website = WebsiteRoots[KISSMANGA_ID, 0] then - Result := GetKissMangaInfoFromURL - else - if website = WebsiteRoots[BATOTO_ID, 0] then - Result := GetBatotoInfoFromURL - else - if website = WebsiteRoots[MANGA24H_ID, 0] then - Result := GetManga24hInfoFromURL - else - if website = WebsiteRoots[VNSHARING_ID, 0] then - Result := GetVnSharingInfoFromURL - else - if website = WebsiteRoots[HENTAI2READ_ID, 0] then - Result := GetHentai2ReadInfoFromURL - else - if website = WebsiteRoots[FAKKU_ID, 0] then - Result := GetFakkuInfoFromURL - else - if website = WebsiteRoots[MANGAREADER_ID, 0] then - Result := GetMangaReaderInfoFromURL - else - if website = WebsiteRoots[MANGAPARK_ID, 0] then - Result := GetMangaParkInfoFromURL - else - if website = WebsiteRoots[MANGAFOX_ID, 0] then - Result := GetMangaFoxInfoFromURL - else - if website = WebsiteRoots[MANGATRADERS_ID, 0] then - Result := GetMangaTradersInfoFromURL - else - if website = WebsiteRoots[STARKANA_ID, 0] then - Result := GetStarkanaInfoFromURL - else - if website = WebsiteRoots[EATMANGA_ID, 0] then - Result := GetEatMangaInfoFromURL - else - if website = WebsiteRoots[MANGAPANDA_ID, 0] then - Result := GetMangaPandaInfoFromURL - else - if website = WebsiteRoots[MANGAGO_ID, 0] then - Result := GetMangaGoInfoFromURL - else - if website = WebsiteRoots[MANGASTREAM_ID, 0] then - Result := GetMangaStreamInfoFromURL - else - if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then - Result := GetRedHawkScansInfoFromURL - else - if website = WebsiteRoots[S2SCAN_ID, 0] then - Result := GetS2scanInfoFromURL - else - if website = WebsiteRoots[EGSCANS_ID, 0] then - Result := GetEGScansInfoFromURL - else - if website = WebsiteRoots[TRUYENTRANHTUAN_ID, 0] then - Result := GetTruyenTranhTuanInfoFromURL - else - if website = WebsiteRoots[MANGAEDEN_ID, 0] then - Result := GetMangaEdenInfoFromURL(WebsiteRoots[MANGAEDEN_ID, 1]) - else - if website = WebsiteRoots[PERVEDEN_ID, 0] then - Result := GetMangaEdenInfoFromURL(WebsiteRoots[PERVEDEN_ID, 1]) - else - if website = WebsiteRoots[MEINMANGA_ID, 0] then - Result := GetMeinMangaInfoFromURL - else - if website = WebsiteRoots[MANGA2U_ID, 0] then - Result := GetManga2uInfoFromURL - else - if website = WebsiteRoots[SUBMANGA_ID, 0] then - Result := GetSubMangaInfoFromURL - else - if website = WebsiteRoots[ESMANGAHERE_ID, 0] then - Result := GetEsMangaHereInfoFromURL - else - if website = WebsiteRoots[ANIMEEXTREMIST_ID, 0] then - Result := GetAnimeExtremistInfoFromURL - else - if website = WebsiteRoots[KOMIKID_ID, 0] then - Result := GetKomikidInfoFromURL - else - if website = WebsiteRoots[PECINTAKOMIK_ID, 0] then - Result := GetPecintaKomikInfoFromURL - else - if website = WebsiteRoots[MABUNS_ID, 0] then - Result := GetMabunsInfoFromURL - else - if website = WebsiteRoots[MANGAESTA_ID, 0] then - Result := GetMangaEstaInfoFromURL - else - if website = WebsiteRoots[PURURIN_ID, 0] then - Result := GetPururinInfoFromURL - else - if website = WebsiteRoots[HUGEMANGA_ID, 0] then - Result := GetHugeMangaInfoFromURL - else - if website = WebsiteRoots[ANIMESTORY_ID, 0] then - Result := GetAnimeStoryInfoFromURL - else - if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then - Result := GetLectureEnLigneInfoFromURL - else - if website = WebsiteRoots[SCANMANGA_ID, 0] then - Result := GetScanMangaInfoFromURL - else - if website = WebsiteRoots[TURKCRAFT_ID, 0] then - Result := GetTurkcraftInfoFromURL - else - if website = WebsiteRoots[MANGAFRAME_ID, 0] then - Result := GetMangaframeInfoFromURL - else - if website = WebsiteRoots[MANGAVADISI_ID, 0] then - Result := GetMangaVadisiInfoFromURL - else - if website = WebsiteRoots[MANGAAR_ID, 0] then - Result := GetMangaArInfoFromURL - else - if website = WebsiteRoots[MANGAAE_ID, 0] then - Result := GetMangaAeInfoFromURL - else - if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then - Result := GetCentralDeMangasInfoFromURL - else - if website = WebsiteRoots[MANGACOW_ID, 0] then - Result := GetMangaCowInfoFromURL - else - if website = WebsiteRoots[SENMANGA_ID, 0] then - Result := GetSenMangaInfoFromURL - else - if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then - Result := GetBlogTruyenInfoFromURL - else - if website = WebsiteRoots[KIVMANGA_ID, 0] then - Result := GetKivmangaInfoFromURL - else - if website = WebsiteRoots[MANGACAN_ID, 0] then - Result := GetMangacanInfoFromURL - else - if website = WebsiteRoots[MANGASPROJECT_ID, 0] then - Result := GetMangasPROJECTInfoFromURL - else - if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then - Result := GetMangaREADER_PORInfoFromURL - else - if website = WebsiteRoots[EHENTAI_ID, 0] then - Result := GetEHentaiInfoFromURL - else - if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then - Result := GetMangaStreamToInfoFromURL - else - if (website = WebsiteRoots[NINEMANGA_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then - Result := GetNineMangaInfoFromURL - else - if website = WebsiteRoots[JAPANSHIN_ID, 0] then - Result := GetJapanShinInfoFromURL - else - if website = WebsiteRoots[JAPSCAN_ID, 0] then - Result := GetJapscanInfoFromURL - else - if website = WebsiteRoots[CENTRUMMANGI_PL_ID, 0] then - Result := GetCentrumMangi_PLInfoFromURL - else - if website = WebsiteRoots[MANGALIB_PL_ID, 0] then - Result := GetMangaLib_PLInfoFromURL - else - if website = WebsiteRoots[ONEMANGA_ID, 0] then - Result := GetOneMangaInfoFromURL - else - if website = WebsiteRoots[MANGATOWN_ID, 0] then - Result := GetMangaTownInfoFromURL - else - if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then - Result := GetReadHentaiMangaInfoFromURL - else - if website = WebsiteRoots[MANGAOKU_ID, 0] then - Result := GetMangaOkuInfoFromURL - else - if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then - Result := GetMyReadingMangaInfoInfoFromURL - else - if website = WebsiteRoots[IKOMIK_ID, 0] then - Result := GetIKomikInfoFromURL - else - if website = WebsiteRoots[NHENTAI_ID, 0] then - Result := GetNHentaiInfoFromURL - else - if website = WebsiteRoots[UNIONMANGAS_ID, 0] then - Result := GetUnionMangasInfoFromURL - else - if website = WebsiteRoots[MANGAMINT_ID, 0] then - Result := GetMangaMintInfoFromURL - else - if website = WebsiteRoots[UNIXMANGA_ID, 0] then - Result := GetUnixMangaInfoFromURL - else - if website = WebsiteRoots[HAKIHOME_ID, 0] then - Result := GetHakiHomeInfoFromURL - else - if website = WebsiteRoots[EXTREMEMANGAS_ID, 0] then - Result := GetExtremeMangasInfoFromURL - else - if website = GetMangaSiteName(MANGAHOST_ID) then - Result := GetMangaHostInfoFromURL - else - if (website = GetMangaSiteName(PORNCOMIX_ID)) or - (website = GetMangaSiteName(XXCOMICS_ID)) or - (website = GetMangaSiteName(XXCOMICSMT_ID)) or - (website = GetMangaSiteName(XXCOMICS3D_ID)) or - (website = GetMangaSiteName(PORNCOMIXRE_ID)) or - (website = GetMangaSiteName(PORNCOMIXIC_ID)) or - (website = GetMangaSiteName(PORNXXXCOMICS_ID)) then - Result := GetPornComixInfoFromURL(GetMangaSiteID(website)) - else - if website = GetMangaSiteName(MANGASEE_ID) then - Result := GetMangaSeeInfoFromURL - else - if website = GetMangaSiteName(MANGAKU_ID) then - Result := GetMangaKuInfoFromURL - else - if website = GetMangaSiteName(ACADEMYVN_ID) then - Result := GetAcademyVNInfoFromURL - else - if website = GetMangaSiteName(MANGAAT_ID) then - Result := GetMangaAtInfoFromURL - else - if website = GetMangaSiteName(SENMANGARAW_ID) then - Result := GetSenMangaRAWInfoFromURL - else - if website = GetMangaSiteName(READMANGATODAY_ID) then - Result := GetReadMangaTodayInfoFromURL - else - if website = GetMangaSiteName(LONEMANGA_ID) then - Result := GetLoneMangaInfoFromURL - else - if website = GetMangaSiteName(DYNASTYSCANS_ID) then - Result := GetDynastyScansInfoFromURL - else - if website = GetMangaSiteName(MADOKAMI_ID) then - Result := GetMadokamiInfoFromURL - else - if SitesIsWPManga(WebsiteID) then - Result := GetWPMangaInfoFromURL + j := -1; + if Modules.ModuleAvailable(website, MMGetInfo, j) then + Result := Modules.GetInfo(Self, URL, Reconnect, j) else begin - Source.Free; - Result := INFORMATION_NOT_FOUND; - Exit; + WebsiteID := GetMangaSiteID(website); + if WebsiteID > High(WebsiteRoots) then Exit(INFORMATION_NOT_FOUND); + + Source := TStringList.Create; + if website = WebsiteRoots[ANIMEA_ID, 0] then + Result := GetAnimeAInfoFromURL + else + if website = WebsiteRoots[MANGAHERE_ID, 0] then + Result := GetMangaHereInfoFromURL + else + if website = WebsiteRoots[MANGAINN_ID, 0] then + Result := GetMangaInnInfoFromURL + else + if website = WebsiteRoots[KISSMANGA_ID, 0] then + Result := GetKissMangaInfoFromURL + else + if website = WebsiteRoots[BATOTO_ID, 0] then + Result := GetBatotoInfoFromURL + else + if website = WebsiteRoots[MANGA24H_ID, 0] then + Result := GetManga24hInfoFromURL + else + if website = WebsiteRoots[VNSHARING_ID, 0] then + Result := GetVnSharingInfoFromURL + else + if website = WebsiteRoots[HENTAI2READ_ID, 0] then + Result := GetHentai2ReadInfoFromURL + else + if website = WebsiteRoots[FAKKU_ID, 0] then + Result := GetFakkuInfoFromURL + else + if website = WebsiteRoots[MANGAREADER_ID, 0] then + Result := GetMangaReaderInfoFromURL + else + if website = WebsiteRoots[MANGAPARK_ID, 0] then + Result := GetMangaParkInfoFromURL + else + if website = WebsiteRoots[MANGAFOX_ID, 0] then + Result := GetMangaFoxInfoFromURL + else + if website = WebsiteRoots[MANGATRADERS_ID, 0] then + Result := GetMangaTradersInfoFromURL + else + if website = WebsiteRoots[STARKANA_ID, 0] then + Result := GetStarkanaInfoFromURL + else + if website = WebsiteRoots[EATMANGA_ID, 0] then + Result := GetEatMangaInfoFromURL + else + if website = WebsiteRoots[MANGAPANDA_ID, 0] then + Result := GetMangaPandaInfoFromURL + else + if website = WebsiteRoots[MANGAGO_ID, 0] then + Result := GetMangaGoInfoFromURL + else + if website = WebsiteRoots[MANGASTREAM_ID, 0] then + Result := GetMangaStreamInfoFromURL + else + if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then + Result := GetRedHawkScansInfoFromURL + else + if website = WebsiteRoots[S2SCAN_ID, 0] then + Result := GetS2scanInfoFromURL + else + if website = WebsiteRoots[EGSCANS_ID, 0] then + Result := GetEGScansInfoFromURL + else + if website = WebsiteRoots[TRUYENTRANHTUAN_ID, 0] then + Result := GetTruyenTranhTuanInfoFromURL + else + if website = WebsiteRoots[MANGAEDEN_ID, 0] then + Result := GetMangaEdenInfoFromURL(WebsiteRoots[MANGAEDEN_ID, 1]) + else + if website = WebsiteRoots[PERVEDEN_ID, 0] then + Result := GetMangaEdenInfoFromURL(WebsiteRoots[PERVEDEN_ID, 1]) + else + if website = WebsiteRoots[MEINMANGA_ID, 0] then + Result := GetMeinMangaInfoFromURL + else + if website = WebsiteRoots[MANGA2U_ID, 0] then + Result := GetManga2uInfoFromURL + else + if website = WebsiteRoots[SUBMANGA_ID, 0] then + Result := GetSubMangaInfoFromURL + else + if website = WebsiteRoots[ESMANGAHERE_ID, 0] then + Result := GetEsMangaHereInfoFromURL + else + if website = WebsiteRoots[ANIMEEXTREMIST_ID, 0] then + Result := GetAnimeExtremistInfoFromURL + else + if website = WebsiteRoots[KOMIKID_ID, 0] then + Result := GetKomikidInfoFromURL + else + if website = WebsiteRoots[PECINTAKOMIK_ID, 0] then + Result := GetPecintaKomikInfoFromURL + else + if website = WebsiteRoots[MABUNS_ID, 0] then + Result := GetMabunsInfoFromURL + else + if website = WebsiteRoots[MANGAESTA_ID, 0] then + Result := GetMangaEstaInfoFromURL + else + if website = WebsiteRoots[PURURIN_ID, 0] then + Result := GetPururinInfoFromURL + else + if website = WebsiteRoots[HUGEMANGA_ID, 0] then + Result := GetHugeMangaInfoFromURL + else + if website = WebsiteRoots[ANIMESTORY_ID, 0] then + Result := GetAnimeStoryInfoFromURL + else + if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then + Result := GetLectureEnLigneInfoFromURL + else + if website = WebsiteRoots[SCANMANGA_ID, 0] then + Result := GetScanMangaInfoFromURL + else + if website = WebsiteRoots[TURKCRAFT_ID, 0] then + Result := GetTurkcraftInfoFromURL + else + if website = WebsiteRoots[MANGAFRAME_ID, 0] then + Result := GetMangaframeInfoFromURL + else + if website = WebsiteRoots[MANGAVADISI_ID, 0] then + Result := GetMangaVadisiInfoFromURL + else + if website = WebsiteRoots[MANGAAR_ID, 0] then + Result := GetMangaArInfoFromURL + else + if website = WebsiteRoots[MANGAAE_ID, 0] then + Result := GetMangaAeInfoFromURL + else + if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then + Result := GetCentralDeMangasInfoFromURL + else + if website = WebsiteRoots[MANGACOW_ID, 0] then + Result := GetMangaCowInfoFromURL + else + if website = WebsiteRoots[SENMANGA_ID, 0] then + Result := GetSenMangaInfoFromURL + else + if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then + Result := GetBlogTruyenInfoFromURL + else + if website = WebsiteRoots[KIVMANGA_ID, 0] then + Result := GetKivmangaInfoFromURL + else + if website = WebsiteRoots[MANGACAN_ID, 0] then + Result := GetMangacanInfoFromURL + else + if website = WebsiteRoots[MANGASPROJECT_ID, 0] then + Result := GetMangasPROJECTInfoFromURL + else + if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then + Result := GetMangaREADER_PORInfoFromURL + else + if website = WebsiteRoots[EHENTAI_ID, 0] then + Result := GetEHentaiInfoFromURL + else + if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then + Result := GetMangaStreamToInfoFromURL + else + if (website = WebsiteRoots[NINEMANGA_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or + (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then + Result := GetNineMangaInfoFromURL + else + if website = WebsiteRoots[JAPANSHIN_ID, 0] then + Result := GetJapanShinInfoFromURL + else + if website = WebsiteRoots[JAPSCAN_ID, 0] then + Result := GetJapscanInfoFromURL + else + if website = WebsiteRoots[CENTRUMMANGI_PL_ID, 0] then + Result := GetCentrumMangi_PLInfoFromURL + else + if website = WebsiteRoots[MANGALIB_PL_ID, 0] then + Result := GetMangaLib_PLInfoFromURL + else + if website = WebsiteRoots[ONEMANGA_ID, 0] then + Result := GetOneMangaInfoFromURL + else + if website = WebsiteRoots[MANGATOWN_ID, 0] then + Result := GetMangaTownInfoFromURL + else + if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then + Result := GetReadHentaiMangaInfoFromURL + else + if website = WebsiteRoots[MANGAOKU_ID, 0] then + Result := GetMangaOkuInfoFromURL + else + if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then + Result := GetMyReadingMangaInfoInfoFromURL + else + if website = WebsiteRoots[IKOMIK_ID, 0] then + Result := GetIKomikInfoFromURL + else + if website = WebsiteRoots[NHENTAI_ID, 0] then + Result := GetNHentaiInfoFromURL + else + if website = WebsiteRoots[UNIONMANGAS_ID, 0] then + Result := GetUnionMangasInfoFromURL + else + if website = WebsiteRoots[MANGAMINT_ID, 0] then + Result := GetMangaMintInfoFromURL + else + if website = WebsiteRoots[UNIXMANGA_ID, 0] then + Result := GetUnixMangaInfoFromURL + else + if website = WebsiteRoots[HAKIHOME_ID, 0] then + Result := GetHakiHomeInfoFromURL + else + if website = WebsiteRoots[EXTREMEMANGAS_ID, 0] then + Result := GetExtremeMangasInfoFromURL + else + if website = GetMangaSiteName(MANGAHOST_ID) then + Result := GetMangaHostInfoFromURL + else + if (website = GetMangaSiteName(PORNCOMIX_ID)) or + (website = GetMangaSiteName(XXCOMICS_ID)) or + (website = GetMangaSiteName(XXCOMICSMT_ID)) or + (website = GetMangaSiteName(XXCOMICS3D_ID)) or + (website = GetMangaSiteName(PORNCOMIXRE_ID)) or + (website = GetMangaSiteName(PORNCOMIXIC_ID)) or + (website = GetMangaSiteName(PORNXXXCOMICS_ID)) then + Result := GetPornComixInfoFromURL(GetMangaSiteID(website)) + else + if website = GetMangaSiteName(MANGASEE_ID) then + Result := GetMangaSeeInfoFromURL + else + if website = GetMangaSiteName(MANGAKU_ID) then + Result := GetMangaKuInfoFromURL + else + if website = GetMangaSiteName(ACADEMYVN_ID) then + Result := GetAcademyVNInfoFromURL + else + if website = GetMangaSiteName(MANGAAT_ID) then + Result := GetMangaAtInfoFromURL + else + if website = GetMangaSiteName(SENMANGARAW_ID) then + Result := GetSenMangaRAWInfoFromURL + else + if website = GetMangaSiteName(READMANGATODAY_ID) then + Result := GetReadMangaTodayInfoFromURL + else + if website = GetMangaSiteName(LONEMANGA_ID) then + Result := GetLoneMangaInfoFromURL + else + if website = GetMangaSiteName(DYNASTYSCANS_ID) then + Result := GetDynastyScansInfoFromURL + else + if website = GetMangaSiteName(MADOKAMI_ID) then + Result := GetMadokamiInfoFromURL + else + if SitesIsWPManga(WebsiteID) then + Result := GetWPMangaInfoFromURL + else + begin + Source.Free; + Result := INFORMATION_NOT_FOUND; + Exit; + end; end; s := mangaInfo.artists; @@ -3012,12 +3019,14 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; mangaInfo.authors := TrimRightChar(Trim(mangaInfo.authors), [',']); mangaInfo.artists := TrimRightChar(Trim(mangaInfo.artists), [',']); mangaInfo.genres := TrimRightChar(Trim(mangaInfo.genres), [',']); - mangaInfo.summary := StringBreaks(mangaInfo.summary); - mangaInfo.summary := Trim(TrimChar(mangaInfo.summary, [#13, #10])); - mangaInfo.summary := BreaksString(mangaInfo.summary); - // strip double CR - mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\n\r\n\r', '\n\r', [rfReplaceAll])); - mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\r\n\r\n', '\r\n', [rfReplaceAll])); + + //// strip + //mangaInfo.summary := StringBreaks(mangaInfo.summary); + //mangaInfo.summary := Trim(TrimChar(mangaInfo.summary, [#13, #10])); + //mangaInfo.summary := BreaksString(mangaInfo.summary); + //// strip double CR + //mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\n\r\n\r', '\n\r', [rfReplaceAll])); + //mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\r\n\r\n', '\r\n', [rfReplaceAll])); // fix info rex := TRegExpr.Create; From 65b427cc998158f3455db7f45ab210dac3e89efc Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:01:42 +0800 Subject: [PATCH 0157/2794] add fool#slide module #70 --- baseunits/modules/FoOlSlide.pas | 152 +++++++++++++++++++++++++++----- 1 file changed, 129 insertions(+), 23 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 8ca80ebec..7dc7f1051 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -14,7 +14,21 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Cardinal; Module: TModuleContainer): Integer; var Source, Parse: TStringList; - i: Integer; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if GetVal(Parse[i], 'class') = 'next' then + if GetTagName(Parse[i + 2]) = 'a' then + begin + Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', + GetVal(Parse[i + 2], 'href'), '$1', True), 1); + Break; + end; + end; + begin Result := INFORMATION_NOT_FOUND; Page := 1; @@ -29,18 +43,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; try ParseHTML(Source.Text, Parse); if Parse.Count > 0 then - begin - for i := 0 to Parse.Count - 1 do - begin - if GetVal(Parse[i], 'class') = 'next' then - if GetTagName(Parse[i + 2]) = 'a' then - begin - Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', - GetVal(Parse[i + 2], 'href'), '$1', True), 1); - Break; - end; - end; - end; + ScanParse; finally Parse.Free; end; @@ -54,11 +57,21 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var Source, Parse: TStringList; - i: Integer; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'a') and (Pos('/series/', Parse[i]) > 0) then + begin + Links.Add(GetVal(Parse[i], 'href')); + Names.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + begin Result := INFORMATION_NOT_FOUND; - if MangaInfo = nil then - Exit; if MangaInfo = nil then Exit; Source := TStringList.Create; @@ -71,16 +84,108 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; try ParseHTML(Source.Text, Parse); if Parse.Count > 0 then - begin - for i := 0 to Parse.Count - 1 do + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + g: String = ''; + begin + with MangaInfo.mangaInfo do + begin + for i := StartIndex to Parse.Count - 1 do + begin + if Parse[i] = '' then + Break; + if GetVal(Parse[i], 'class') = 'group' then + if GetVal(Parse[i + 1], 'class') = 'title' then begin - if (GetTagName(Parse[i]) = 'a') and (Pos('/series/', Parse[i]) > 0) then - begin - Links.Add(GetVal(Parse[i], 'href')); - Names.Add(CommonStringFilter(Parse[i + 1])); - end; + g := Trim(Parse[i + 2]); + if g = 'Chapters' then + g := '' + else + g += ' '; end; + if GetTagName(Parse[i]) = 'a' then + begin + chapterLinks.Add(GetVal(Parse[i], 'href')); + chapterName.Add(Trim(g + Trim(Parse[i + 1]))); + end; + end; + //invert chapters + if MangaInfo.mangaInfo.chapterLinks.Count > 0 then + InvertStrings([chapterLinks, chapterName]); + end; + end; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + with MangaInfo.mangaInfo do + begin + //title + if title = '' then + if (GetTagName(Parse[i]) = 'h1') and (GetVal(Parse[i], 'class') = 'title') then + title := CommonStringFilter(Parse[i]); + + //cover + if coverLink = '' then + if GetVal(Parse[i], 'class') = 'thumbnail' then + if GetTagName(Parse[i + 2]) = 'img' then + coverLink := GetVal(Parse[i + 2], 'src'); + + //author + if (Parse[i] = 'Author') and (Parse[i + 1] = '') then + authors := Trim(TrimLeftChar(Parse[i + 2], [':'])); + + //artist + if (Parse[i] = 'Artist') and (Parse[i + 1] = '') then + artists := Trim(TrimLeftChar(Parse[i + 2], [':'])); + + //summary + if (Parse[i] = 'Synopsis') and (Parse[i + 1] = '') then + summary := Trim(TrimLeftChar(Parse[i + 2], [':'])); + + //chapters + if GetVal(Parse[i], 'class') = 'list' then + begin + ScanChapters(i); + Break; end; + end; + end; + +begin + Result := INFORMATION_NOT_FOUND; + if MangaInfo = nil then + Exit; + MangaInfo.mangaInfo.website := Module.Website; + MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + begin + Result := NO_ERROR; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; finally Parse.Free; end; @@ -100,6 +205,7 @@ procedure RegisterModule; InformationAvailable := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; end; end; From 21a03ac0bd56e5650dd2645fddcd454598b5cc80 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:06:14 +0800 Subject: [PATCH 0158/2794] fool$slide, tiny changes --- baseunits/modules/FoOlSlide.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 7dc7f1051..ee66ba879 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -122,7 +122,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if GetTagName(Parse[i]) = 'a' then begin chapterLinks.Add(GetVal(Parse[i], 'href')); - chapterName.Add(Trim(g + Trim(Parse[i + 1]))); + chapterName.Add(g + Trim(Parse[i + 1])); end; end; //invert chapters From 0f273fffa25ac5ead81b0a7995ab503684d2a843 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:19:11 +0800 Subject: [PATCH 0159/2794] websitemodules, add getpagenumber and getimageurl --- baseunits/WebsiteModules.pas | 37 ++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 47238e49a..7915a54ed 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -81,8 +81,15 @@ TWebsiteModules = class(TObject) function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; const Website: String): Integer; overload; - function GetPageNumber(var Container: TTaskContainer; const URL: String): Boolean; - function GetImageURL(var Container: TTaskContainer; const URL: String): Boolean; + function GetPageNumber(var Container: TTaskContainer; const URL: String; + const ModuleIndex: Integer): Boolean; overload; + function GetPageNumber(var Container: TTaskContainer; + const URL, Website: String): Boolean; overload; + + function GetImageURL(var Container: TTaskContainer; const URL: String; + const ModuleIndex: Integer): Boolean; overload; + function GetImageURL(var Container: TTaskContainer; + const URL, Website: String): Boolean; overload; procedure LockModules; procedure UnlockModules; @@ -248,15 +255,37 @@ function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; - const URL: String): Boolean; + const URL: String; const ModuleIndex: Integer): Boolean; begin Result := False; + if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + Exit; + if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber) then + Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber( + Container, URL, TModuleContainer(FModuleList[ModuleIndex])); +end; + +function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; + const URL, Website: String): Boolean; +begin + Result := GetPageNumber(Container, URL, LocateModule(Website)); end; function TWebsiteModules.GetImageURL(var Container: TTaskContainer; - const URL: String): Boolean; + const URL: String; const ModuleIndex: Integer): Boolean; begin Result := False; + if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + Exit; + if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL) then + Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL( + Container, URL, TModuleContainer(FModuleList[ModuleIndex])); +end; + +function TWebsiteModules.GetImageURL(var Container: TTaskContainer; + const URL, Website: String): Boolean; +begin + Result := GetImageURL(Container, URL, LocateModule(Website)); end; procedure TWebsiteModules.LockModules; From 4b31a8f0bc3e8ceaf4f50f4cd1f6ec7878d558dc Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:25:37 +0800 Subject: [PATCH 0160/2794] downloadmanager, use websitemodules --- baseunits/uDownloadsManager.pas | 867 ++++++++++++++++---------------- 1 file changed, 441 insertions(+), 426 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2181d1db6..f972db93c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -237,7 +237,7 @@ TDownloadManager = class implementation uses - frmMain; + frmMain, WebsiteModules; function IntToStr(Value: Cardinal): string; begin @@ -372,6 +372,7 @@ procedure TDownloadThread.DoTerminate; function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; var Parser: THTMLParser; + i: Integer; {$I includes/AnimeStory/chapter_page_number.inc} @@ -512,227 +513,235 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/WPManga/chapter_page_number.inc} begin + Result := False; manager.container.PageNumber := 0; - if manager.container.MangaSiteID = ANIMEA_ID then - Result := GetAnimeAPageNumber - else - if manager.container.MangaSiteID = MANGAHERE_ID then - Result := GetMangaHerePageNumber - else - if manager.container.MangaSiteID = MANGAINN_ID then - Result := GetMangaInnPageNumber - else - if manager.container.MangaSiteID = BATOTO_ID then - Result := GetBatotoPageNumber - else - if manager.container.MangaSiteID = MANGAFOX_ID then - Result := GetMangaFoxPageNumber - else - if manager.container.MangaSiteID = MANGAREADER_ID then - Result := GetMangaReaderPageNumber - else - if manager.container.MangaSiteID = MANGATRADERS_ID then - Result := GetMangaTradersPageNumber - else - if manager.container.MangaSiteID = STARKANA_ID then - Result := GetStarkanaPageNumber - else - if manager.container.MangaSiteID = EATMANGA_ID then - Result := GetEatMangaPageNumber - else - if manager.container.MangaSiteID = MANGAPANDA_ID then - Result := GetMangaPandaPageNumber - else - if manager.container.MangaSiteID = MANGAPARK_ID then - Result := GetMangaParkPageNumber - else - if manager.container.MangaSiteID = MANGAGO_ID then - Result := GetMangaGoPageNumber - else - if manager.container.MangaSiteID = MANGASTREAM_ID then - Result := GetMangaStreamPageNumber - else - if manager.container.MangaSiteID = REDHAWKSCANS_ID then - Result := GetRedHawkScansPageNumber - else - if manager.container.MangaSiteID = S2SCAN_ID then - Result := GetS2scanPageNumber - else - if manager.container.MangaSiteID = MEINMANGA_ID then - Result := GetMeinMangaPageNumber - else - if manager.container.MangaSiteID = MANGA2U_ID then - Result := GetManga2uPageNumber - else - if manager.container.MangaSiteID = ESMANGAHERE_ID then - Result := GetEsMangaHerePageNumber - else - if manager.container.MangaSiteID = SUBMANGA_ID then - Result := GetSubMangaPageNumber - else - if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then - Result := GetAnimeExtremistPageNumber - else - if manager.container.MangaSiteID = KOMIKID_ID then - Result := GetKomikidPageNumber - else - if manager.container.MangaSiteID = PECINTAKOMIK_ID then - Result := GetPecintaKomikPageNumber - else - if manager.container.MangaSiteID = PURURIN_ID then - Result := GetPururinPageNumber - else - if manager.container.MangaSiteID = HUGEMANGA_ID then - Result := GetHugeMangaPageNumber - else - if manager.container.MangaSiteID = ANIMESTORY_ID then - Result := GetAnimeStoryPageNumber - else - if manager.container.MangaSiteID = TURKCRAFT_ID then - Result := GetTurkcraftPageNumber - else - if manager.container.MangaSiteID = MANGAVADISI_ID then - Result := GetMangaVadisiPageNumber - else - if manager.container.MangaSiteID = MANGAFRAME_ID then - Result := GetMangaFramePageNumber - else - if manager.container.MangaSiteID = MANGAAE_ID then - Result := GetMangaAePageNumber - else - if manager.container.MangaSiteID = MANGACOW_ID then - Result := GetMangaCowPageNumber - else - if manager.container.MangaSiteID = SENMANGA_ID then - Result := GetSenMangaPageNumber - else - if (manager.container.MangaSiteID = MANGAEDEN_ID) or - (manager.container.MangaSiteID = PERVEDEN_ID) then - Result := GetMangaEdenPageNumber - else - if manager.container.MangaSiteID = KISSMANGA_ID then - Result := GetKissMangaPageNumber - else - if manager.container.MangaSiteID = KIVMANGA_ID then - Result := GetKivmangaPageNumber - else - if manager.container.MangaSiteID = HENTAI2READ_ID then - Result := GetHentai2ReadPageNumber - else - if manager.container.MangaSiteID = EHENTAI_ID then - Result := GetEHentaiPageNumber - else - if manager.container.MangaSiteID = MANGASTREAMTO_ID then - Result := GetMangaStreamToPageNumber - else - if (manager.container.MangaSiteID = NINEMANGA_ID) or - (manager.container.MangaSiteID = NINEMANGA_ES_ID) or - (manager.container.MangaSiteID = NINEMANGA_CN_ID) or - (manager.container.MangaSiteID = NINEMANGA_RU_ID) or - (manager.container.MangaSiteID = NINEMANGA_DE_ID) or - (manager.container.MangaSiteID = NINEMANGA_IT_ID) or - (manager.container.MangaSiteID = NINEMANGA_BR_ID) then - Result := GetNineMangaPageNumber - else - if manager.container.MangaSiteID = LECTUREENLIGNE_ID then - Result := GetLectureEnLignePageNumber - else - if manager.container.MangaSiteID = JAPANSHIN_ID then - Result := GetJapanShinPageNumber - else - if manager.container.MangaSiteID = JAPSCAN_ID then - Result := GetJapscanPageNumber - else - if manager.container.MangaSiteID = CENTRUMMANGI_PL_ID then - Result := GetCentrumMangi_PLPageNumber - else - if manager.container.MangaSiteID = MANGALIB_PL_ID then - Result := GetMangaLib_PLPageNumber - else - if manager.container.MangaSiteID = ONEMANGA_ID then - Result := GetOneMangaPageNumber - else - if manager.container.MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownPageNumber - else - if manager.container.MangaSiteID = READHENTAIMANGA_ID then - Result := GetReadHentaiMangaPageNumber - else - if manager.container.MangaSiteID = MANGAOKU_ID then - Result := GetMangaOkuPageNumber - else - if manager.container.MangaSiteID = MYREADINGMANGAINFO_ID then - Result := GetMyReadingMangaInfoPageNumber - else - if manager.container.MangaSiteID = IKOMIK_ID then - Result := GetIKomikPageNumber - else - if manager.container.MangaSiteID = NHENTAI_ID then - Result := GetNHentaiPageNumber - else - if manager.container.MangaSiteID = UNIONMANGAS_ID then - Result := GetUnionMangasPageNumber - else - if manager.container.MangaSiteID = MANGAMINT_ID then - Result := GetMangaMintPageNumber - else - if manager.container.MangaSiteID = UNIXMANGA_ID then - Result := GetUnixMangaPageNumber - else - if manager.container.MangaSiteID = HAKIHOME_ID then - Result := GetHakiHomePageNumber - else - if manager.container.MangaSiteID = EXTREMEMANGAS_ID then - Result := GetExtremeMangasPageNumber - else - if manager.container.MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostPageNumber - else - if (manager.container.MangaSiteID = PORNCOMIX_ID) or - (manager.container.MangaSiteID = XXCOMICS_ID) or - (manager.container.MangaSiteID = XXCOMICSMT_ID) or - (manager.container.MangaSiteID = XXCOMICS3D_ID) or - (manager.container.MangaSiteID = PORNCOMIXRE_ID) or - (manager.container.MangaSiteID = PORNCOMIXIC_ID) or - (manager.container.MangaSiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixPageNumber(manager.container.MangaSiteID) - else - if manager.container.MangaSiteID = MANGASEE_ID then - Result := GetMangaSeePageNumber - else - if manager.container.MangaSiteID = MANGAKU_ID then - Result := GetMangaKuPageNumber - else - if manager.container.MangaSiteID = ACADEMYVN_ID then - Result := GetAcademyVNPageNumber - else - if manager.container.MangaSiteID = MANGAAT_ID then - Result := GetMangaAtPageNumber - else - if manager.container.MangaSiteID = SENMANGARAW_ID then - Result := GetSenMangaRAWPageNumber - else - if manager.container.MangaSiteID = READMANGATODAY_ID then - Result := GetReadMangaTodayPageNumber - else - if manager.container.MangaSiteID = LONEMANGA_ID then - Result := GetLoneMangaPageNumber - else - if manager.container.MangaSiteID = DYNASTYSCANS_ID then - Result := GetDynastyScansPageNumber - else - if manager.container.MangaSiteID = MADOKAMI_ID then - Result := GetMadokamiPageNumber - else - if SitesIsWPManga(manager.container.MangaSiteID) then - Result := GetWPMangaPageNumber + + i := -1; + if Modules.ModuleAvailable(Self.manager.container.DownloadInfo.Website, + MMGetPageNumber, i) then + Result := Modules.GetPageNumber(Self.manager.container, URL, i) else - Result := False; + begin + if manager.container.MangaSiteID = ANIMEA_ID then + Result := GetAnimeAPageNumber + else + if manager.container.MangaSiteID = MANGAHERE_ID then + Result := GetMangaHerePageNumber + else + if manager.container.MangaSiteID = MANGAINN_ID then + Result := GetMangaInnPageNumber + else + if manager.container.MangaSiteID = BATOTO_ID then + Result := GetBatotoPageNumber + else + if manager.container.MangaSiteID = MANGAFOX_ID then + Result := GetMangaFoxPageNumber + else + if manager.container.MangaSiteID = MANGAREADER_ID then + Result := GetMangaReaderPageNumber + else + if manager.container.MangaSiteID = MANGATRADERS_ID then + Result := GetMangaTradersPageNumber + else + if manager.container.MangaSiteID = STARKANA_ID then + Result := GetStarkanaPageNumber + else + if manager.container.MangaSiteID = EATMANGA_ID then + Result := GetEatMangaPageNumber + else + if manager.container.MangaSiteID = MANGAPANDA_ID then + Result := GetMangaPandaPageNumber + else + if manager.container.MangaSiteID = MANGAPARK_ID then + Result := GetMangaParkPageNumber + else + if manager.container.MangaSiteID = MANGAGO_ID then + Result := GetMangaGoPageNumber + else + if manager.container.MangaSiteID = MANGASTREAM_ID then + Result := GetMangaStreamPageNumber + else + if manager.container.MangaSiteID = REDHAWKSCANS_ID then + Result := GetRedHawkScansPageNumber + else + if manager.container.MangaSiteID = S2SCAN_ID then + Result := GetS2scanPageNumber + else + if manager.container.MangaSiteID = MEINMANGA_ID then + Result := GetMeinMangaPageNumber + else + if manager.container.MangaSiteID = MANGA2U_ID then + Result := GetManga2uPageNumber + else + if manager.container.MangaSiteID = ESMANGAHERE_ID then + Result := GetEsMangaHerePageNumber + else + if manager.container.MangaSiteID = SUBMANGA_ID then + Result := GetSubMangaPageNumber + else + if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then + Result := GetAnimeExtremistPageNumber + else + if manager.container.MangaSiteID = KOMIKID_ID then + Result := GetKomikidPageNumber + else + if manager.container.MangaSiteID = PECINTAKOMIK_ID then + Result := GetPecintaKomikPageNumber + else + if manager.container.MangaSiteID = PURURIN_ID then + Result := GetPururinPageNumber + else + if manager.container.MangaSiteID = HUGEMANGA_ID then + Result := GetHugeMangaPageNumber + else + if manager.container.MangaSiteID = ANIMESTORY_ID then + Result := GetAnimeStoryPageNumber + else + if manager.container.MangaSiteID = TURKCRAFT_ID then + Result := GetTurkcraftPageNumber + else + if manager.container.MangaSiteID = MANGAVADISI_ID then + Result := GetMangaVadisiPageNumber + else + if manager.container.MangaSiteID = MANGAFRAME_ID then + Result := GetMangaFramePageNumber + else + if manager.container.MangaSiteID = MANGAAE_ID then + Result := GetMangaAePageNumber + else + if manager.container.MangaSiteID = MANGACOW_ID then + Result := GetMangaCowPageNumber + else + if manager.container.MangaSiteID = SENMANGA_ID then + Result := GetSenMangaPageNumber + else + if (manager.container.MangaSiteID = MANGAEDEN_ID) or + (manager.container.MangaSiteID = PERVEDEN_ID) then + Result := GetMangaEdenPageNumber + else + if manager.container.MangaSiteID = KISSMANGA_ID then + Result := GetKissMangaPageNumber + else + if manager.container.MangaSiteID = KIVMANGA_ID then + Result := GetKivmangaPageNumber + else + if manager.container.MangaSiteID = HENTAI2READ_ID then + Result := GetHentai2ReadPageNumber + else + if manager.container.MangaSiteID = EHENTAI_ID then + Result := GetEHentaiPageNumber + else + if manager.container.MangaSiteID = MANGASTREAMTO_ID then + Result := GetMangaStreamToPageNumber + else + if (manager.container.MangaSiteID = NINEMANGA_ID) or + (manager.container.MangaSiteID = NINEMANGA_ES_ID) or + (manager.container.MangaSiteID = NINEMANGA_CN_ID) or + (manager.container.MangaSiteID = NINEMANGA_RU_ID) or + (manager.container.MangaSiteID = NINEMANGA_DE_ID) or + (manager.container.MangaSiteID = NINEMANGA_IT_ID) or + (manager.container.MangaSiteID = NINEMANGA_BR_ID) then + Result := GetNineMangaPageNumber + else + if manager.container.MangaSiteID = LECTUREENLIGNE_ID then + Result := GetLectureEnLignePageNumber + else + if manager.container.MangaSiteID = JAPANSHIN_ID then + Result := GetJapanShinPageNumber + else + if manager.container.MangaSiteID = JAPSCAN_ID then + Result := GetJapscanPageNumber + else + if manager.container.MangaSiteID = CENTRUMMANGI_PL_ID then + Result := GetCentrumMangi_PLPageNumber + else + if manager.container.MangaSiteID = MANGALIB_PL_ID then + Result := GetMangaLib_PLPageNumber + else + if manager.container.MangaSiteID = ONEMANGA_ID then + Result := GetOneMangaPageNumber + else + if manager.container.MangaSiteID = MANGATOWN_ID then + Result := GetMangaTownPageNumber + else + if manager.container.MangaSiteID = READHENTAIMANGA_ID then + Result := GetReadHentaiMangaPageNumber + else + if manager.container.MangaSiteID = MANGAOKU_ID then + Result := GetMangaOkuPageNumber + else + if manager.container.MangaSiteID = MYREADINGMANGAINFO_ID then + Result := GetMyReadingMangaInfoPageNumber + else + if manager.container.MangaSiteID = IKOMIK_ID then + Result := GetIKomikPageNumber + else + if manager.container.MangaSiteID = NHENTAI_ID then + Result := GetNHentaiPageNumber + else + if manager.container.MangaSiteID = UNIONMANGAS_ID then + Result := GetUnionMangasPageNumber + else + if manager.container.MangaSiteID = MANGAMINT_ID then + Result := GetMangaMintPageNumber + else + if manager.container.MangaSiteID = UNIXMANGA_ID then + Result := GetUnixMangaPageNumber + else + if manager.container.MangaSiteID = HAKIHOME_ID then + Result := GetHakiHomePageNumber + else + if manager.container.MangaSiteID = EXTREMEMANGAS_ID then + Result := GetExtremeMangasPageNumber + else + if manager.container.MangaSiteID = MANGAHOST_ID then + Result := GetMangaHostPageNumber + else + if (manager.container.MangaSiteID = PORNCOMIX_ID) or + (manager.container.MangaSiteID = XXCOMICS_ID) or + (manager.container.MangaSiteID = XXCOMICSMT_ID) or + (manager.container.MangaSiteID = XXCOMICS3D_ID) or + (manager.container.MangaSiteID = PORNCOMIXRE_ID) or + (manager.container.MangaSiteID = PORNCOMIXIC_ID) or + (manager.container.MangaSiteID = PORNXXXCOMICS_ID) then + Result := GetPornComixPageNumber(manager.container.MangaSiteID) + else + if manager.container.MangaSiteID = MANGASEE_ID then + Result := GetMangaSeePageNumber + else + if manager.container.MangaSiteID = MANGAKU_ID then + Result := GetMangaKuPageNumber + else + if manager.container.MangaSiteID = ACADEMYVN_ID then + Result := GetAcademyVNPageNumber + else + if manager.container.MangaSiteID = MANGAAT_ID then + Result := GetMangaAtPageNumber + else + if manager.container.MangaSiteID = SENMANGARAW_ID then + Result := GetSenMangaRAWPageNumber + else + if manager.container.MangaSiteID = READMANGATODAY_ID then + Result := GetReadMangaTodayPageNumber + else + if manager.container.MangaSiteID = LONEMANGA_ID then + Result := GetLoneMangaPageNumber + else + if manager.container.MangaSiteID = DYNASTYSCANS_ID then + Result := GetDynastyScansPageNumber + else + if manager.container.MangaSiteID = MADOKAMI_ID then + Result := GetMadokamiPageNumber + else + if SitesIsWPManga(manager.container.MangaSiteID) then + Result := GetWPMangaPageNumber; + end; end; function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; var Parser: THTMLParser; + i: Integer; {$I includes/AnimeStory/image_url.inc} @@ -867,222 +876,228 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/WPManga/image_url.inc} begin + Result := False; if (manager.container.PageLinks.Count > 0) and (manager.container.PageLinks.Strings[workCounter] <> 'W') then Exit; - if manager.container.MangaSiteID = ANIMEA_ID then - Result := GetAnimeAImageURL - else - if manager.container.MangaSiteID = MANGATRADERS_ID then - Result := GetMangaTradersImageURL - else - if manager.container.MangaSiteID = MANGAHERE_ID then - Result := GetMangaHereImageURL - else - if manager.container.MangaSiteID = MANGAINN_ID then - Result := GetMangaInnImageURL - else - if manager.container.MangaSiteID = BATOTO_ID then - Result := GetBatotoImageURL - else - if manager.container.MangaSiteID = MANGA2U_ID then - Result := GetManga2uImageURL - else - if manager.container.MangaSiteID = MANGA24H_ID then - Result := GetManga24hImageURL - else - if manager.container.MangaSiteID = VNSHARING_ID then - Result := GetVnSharingImageURL - else - if manager.container.MangaSiteID = HENTAI2READ_ID then - Result := GetHentai2ReadImageURL - else - if manager.container.MangaSiteID = FAKKU_ID then - Result := GetFakkuImageURL - else - if manager.container.MangaSiteID = MANGAREADER_ID then - Result := GetMangaReaderImageURL - else - //if manager.container.MangaSiteID = MANGAPARK_ID then - // Result := GetMangaParkImageURL - //else - if manager.container.MangaSiteID = MANGAFOX_ID then - Result := GetMangaFoxImageURL - else - if manager.container.MangaSiteID = STARKANA_ID then - Result := GetStarkanaImageURL - else - if manager.container.MangaSiteID = EATMANGA_ID then - Result := GetEatMangaImageURL - else - if manager.container.MangaSiteID = MANGAPANDA_ID then - Result := GetMangaPandaImageURL - else - if manager.container.MangaSiteID = MANGAGO_ID then - Result := GetMangaGoImageURL - else - if manager.container.MangaSiteID = MANGASTREAM_ID then - Result := GetMangaStreamImageURL - else - if manager.container.MangaSiteID = REDHAWKSCANS_ID then - Result := GetRedHawkScansImageURL - else - if manager.container.MangaSiteID = EGSCANS_ID then - Result := GetEGScansImageURL - else - if manager.container.MangaSiteID = ESMANGAHERE_ID then - Result := GetEsMangaHereImageURL - else - if manager.container.MangaSiteID = SUBMANGA_ID then - Result := GetSubMangaImageURL - else - if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then - Result := GetAnimeExtremistImageURL - else - if manager.container.MangaSiteID = KOMIKID_ID then - Result := GetKomikidImageURL - else - if manager.container.MangaSiteID = PECINTAKOMIK_ID then - Result := GetPecintaKomikImageURL - else - if manager.container.MangaSiteID = MABUNS_ID then - Result := GetMabunsImageURL - else - if manager.container.MangaSiteID = MANGAESTA_ID then - Result := GetMangaEstaImageURL - else - if manager.container.MangaSiteID = PURURIN_ID then - Result := GetPururinImageURL - else - if manager.container.MangaSiteID = HUGEMANGA_ID then - Result := GetHugeMangaImageURL - else - if manager.container.MangaSiteID = ANIMESTORY_ID then - Result := GetAnimeStoryImageURL - else - if manager.container.MangaSiteID = SCANMANGA_ID then - Result := GetScanMangaImageURL - else - if manager.container.MangaSiteID = TURKCRAFT_ID then - Result := GetTurkcraftImageURL - else - if manager.container.MangaSiteID = MANGAVADISI_ID then - Result := GetMangaVadisiImageURL - else - if manager.container.MangaSiteID = MANGAFRAME_ID then - Result := GetMangaFrameImageURL - else - if manager.container.MangaSiteID = MANGAAR_ID then - Result := GetMangaArImageURL - else - if manager.container.MangaSiteID = MANGAAE_ID then - Result := GetMangaAeImageURL - else - if manager.container.MangaSiteID = CENTRALDEMANGAS_ID then - Result := GetCentralDeMangasImageURL - else - if manager.container.MangaSiteID = MANGACOW_ID then - Result := GetMangaCowImageURL - else - if manager.container.MangaSiteID = SENMANGA_ID then - Result := GetSenMangaImageURL - else - if manager.container.MangaSiteID = TRUYENTRANHTUAN_ID then - Result := GetTruyenTranhTuanImageURL - else - if manager.container.MangaSiteID = BLOGTRUYEN_ID then - Result := GetBlogTruyenImageURL - else - if (manager.container.MangaSiteID = MANGAEDEN_ID) or - (manager.container.MangaSiteID = PERVEDEN_ID) then - Result := GetMangaEdenImageURL - else - if manager.container.MangaSiteID = KIVMANGA_ID then - Result := GetKivmangaImageURL - else - if manager.container.MangaSiteID = MANGACAN_ID then - Result := GetMangacanImageURL - else - if manager.container.MangaSiteID = MANGASPROJECT_ID then - Result := GetMangasPROJECTImageURL - else - if manager.container.MangaSiteID = MANGAREADER_POR_ID then - Result := GetMangaREADER_PORImageURL - else - if manager.container.MangaSiteID = MANGASTREAMTO_ID then - Result := GetMangaStreamToImageURL - else - if (manager.container.MangaSiteID = NINEMANGA_ID) or - (manager.container.MangaSiteID = NINEMANGA_ES_ID) or - (manager.container.MangaSiteID = NINEMANGA_CN_ID) or - (manager.container.MangaSiteID = NINEMANGA_RU_ID) or - (manager.container.MangaSiteID = NINEMANGA_DE_ID) or - (manager.container.MangaSiteID = NINEMANGA_IT_ID) or - (manager.container.MangaSiteID = NINEMANGA_BR_ID) then - Result := GetNineMangaImageURL - else - if manager.container.MangaSiteID = LECTUREENLIGNE_ID then - Result := GeLectureEnligneImageURL - else - if manager.container.MangaSiteID = JAPANSHIN_ID then - Result := GetJapanShinImageURL - else - if manager.container.MangaSiteID = JAPSCAN_ID then - Result := GetJapscanImageURL - else - if manager.container.MangaSiteID = CENTRUMMANGI_PL_ID then - Result := GetCentrumMangi_PLImageURL - else - if manager.container.MangaSiteID = MANGALIB_PL_ID then - Result := GetMangaLib_PLImageURL - else - if manager.container.MangaSiteID = ONEMANGA_ID then - Result := GetOneMangaImageURL - else - if manager.container.MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownImageURL - else - if manager.container.MangaSiteID = READHENTAIMANGA_ID then - Result := GetReadHentaiMangaImageURL - else - if manager.container.MangaSiteID = MANGAOKU_ID then - Result := GetMangaOkuImageURL - else - if manager.container.MangaSiteID = IKOMIK_ID then - Result := GetIKomikImageURL - else - if manager.container.MangaSiteID = NHENTAI_ID then - Result := GetNHentaiImageURL - else - if manager.container.MangaSiteID = MANGAMINT_ID then - Result := GetMangaMintImageURL - else - if manager.container.MangaSiteID = UNIXMANGA_ID then - Result := GetUnixMangaImageURL - else - if manager.container.MangaSiteID = HAKIHOME_ID then - Result := GetHakiHomeImageURL - else - if manager.container.MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostImageURL - else - if (manager.container.MangaSiteID = PORNCOMIX_ID) or - (manager.container.MangaSiteID = XXCOMICS_ID) or - (manager.container.MangaSiteID = XXCOMICSMT_ID) or - (manager.container.MangaSiteID = XXCOMICS3D_ID) or - (manager.container.MangaSiteID = PORNCOMIXRE_ID) or - (manager.container.MangaSiteID = PORNCOMIXIC_ID) or - (manager.container.MangaSiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixImageURL - else - if manager.container.MangaSiteID = MANGAAT_ID then - Result := GetMangaAtImageURL + i := -1; + if Modules.ModuleAvailable(Self.manager.container.DownloadInfo.Website, + MMGetImageURL, i) then + Result := Modules.GetImageURL(Self.manager.container, URL, i) else - if SitesIsWPManga(manager.container.MangaSiteID) then - Result := GetWPMangaImageURL - else - Result := False; + begin + if manager.container.MangaSiteID = ANIMEA_ID then + Result := GetAnimeAImageURL + else + if manager.container.MangaSiteID = MANGATRADERS_ID then + Result := GetMangaTradersImageURL + else + if manager.container.MangaSiteID = MANGAHERE_ID then + Result := GetMangaHereImageURL + else + if manager.container.MangaSiteID = MANGAINN_ID then + Result := GetMangaInnImageURL + else + if manager.container.MangaSiteID = BATOTO_ID then + Result := GetBatotoImageURL + else + if manager.container.MangaSiteID = MANGA2U_ID then + Result := GetManga2uImageURL + else + if manager.container.MangaSiteID = MANGA24H_ID then + Result := GetManga24hImageURL + else + if manager.container.MangaSiteID = VNSHARING_ID then + Result := GetVnSharingImageURL + else + if manager.container.MangaSiteID = HENTAI2READ_ID then + Result := GetHentai2ReadImageURL + else + if manager.container.MangaSiteID = FAKKU_ID then + Result := GetFakkuImageURL + else + if manager.container.MangaSiteID = MANGAREADER_ID then + Result := GetMangaReaderImageURL + else + //if manager.container.MangaSiteID = MANGAPARK_ID then + // Result := GetMangaParkImageURL + //else + if manager.container.MangaSiteID = MANGAFOX_ID then + Result := GetMangaFoxImageURL + else + if manager.container.MangaSiteID = STARKANA_ID then + Result := GetStarkanaImageURL + else + if manager.container.MangaSiteID = EATMANGA_ID then + Result := GetEatMangaImageURL + else + if manager.container.MangaSiteID = MANGAPANDA_ID then + Result := GetMangaPandaImageURL + else + if manager.container.MangaSiteID = MANGAGO_ID then + Result := GetMangaGoImageURL + else + if manager.container.MangaSiteID = MANGASTREAM_ID then + Result := GetMangaStreamImageURL + else + if manager.container.MangaSiteID = REDHAWKSCANS_ID then + Result := GetRedHawkScansImageURL + else + if manager.container.MangaSiteID = EGSCANS_ID then + Result := GetEGScansImageURL + else + if manager.container.MangaSiteID = ESMANGAHERE_ID then + Result := GetEsMangaHereImageURL + else + if manager.container.MangaSiteID = SUBMANGA_ID then + Result := GetSubMangaImageURL + else + if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then + Result := GetAnimeExtremistImageURL + else + if manager.container.MangaSiteID = KOMIKID_ID then + Result := GetKomikidImageURL + else + if manager.container.MangaSiteID = PECINTAKOMIK_ID then + Result := GetPecintaKomikImageURL + else + if manager.container.MangaSiteID = MABUNS_ID then + Result := GetMabunsImageURL + else + if manager.container.MangaSiteID = MANGAESTA_ID then + Result := GetMangaEstaImageURL + else + if manager.container.MangaSiteID = PURURIN_ID then + Result := GetPururinImageURL + else + if manager.container.MangaSiteID = HUGEMANGA_ID then + Result := GetHugeMangaImageURL + else + if manager.container.MangaSiteID = ANIMESTORY_ID then + Result := GetAnimeStoryImageURL + else + if manager.container.MangaSiteID = SCANMANGA_ID then + Result := GetScanMangaImageURL + else + if manager.container.MangaSiteID = TURKCRAFT_ID then + Result := GetTurkcraftImageURL + else + if manager.container.MangaSiteID = MANGAVADISI_ID then + Result := GetMangaVadisiImageURL + else + if manager.container.MangaSiteID = MANGAFRAME_ID then + Result := GetMangaFrameImageURL + else + if manager.container.MangaSiteID = MANGAAR_ID then + Result := GetMangaArImageURL + else + if manager.container.MangaSiteID = MANGAAE_ID then + Result := GetMangaAeImageURL + else + if manager.container.MangaSiteID = CENTRALDEMANGAS_ID then + Result := GetCentralDeMangasImageURL + else + if manager.container.MangaSiteID = MANGACOW_ID then + Result := GetMangaCowImageURL + else + if manager.container.MangaSiteID = SENMANGA_ID then + Result := GetSenMangaImageURL + else + if manager.container.MangaSiteID = TRUYENTRANHTUAN_ID then + Result := GetTruyenTranhTuanImageURL + else + if manager.container.MangaSiteID = BLOGTRUYEN_ID then + Result := GetBlogTruyenImageURL + else + if (manager.container.MangaSiteID = MANGAEDEN_ID) or + (manager.container.MangaSiteID = PERVEDEN_ID) then + Result := GetMangaEdenImageURL + else + if manager.container.MangaSiteID = KIVMANGA_ID then + Result := GetKivmangaImageURL + else + if manager.container.MangaSiteID = MANGACAN_ID then + Result := GetMangacanImageURL + else + if manager.container.MangaSiteID = MANGASPROJECT_ID then + Result := GetMangasPROJECTImageURL + else + if manager.container.MangaSiteID = MANGAREADER_POR_ID then + Result := GetMangaREADER_PORImageURL + else + if manager.container.MangaSiteID = MANGASTREAMTO_ID then + Result := GetMangaStreamToImageURL + else + if (manager.container.MangaSiteID = NINEMANGA_ID) or + (manager.container.MangaSiteID = NINEMANGA_ES_ID) or + (manager.container.MangaSiteID = NINEMANGA_CN_ID) or + (manager.container.MangaSiteID = NINEMANGA_RU_ID) or + (manager.container.MangaSiteID = NINEMANGA_DE_ID) or + (manager.container.MangaSiteID = NINEMANGA_IT_ID) or + (manager.container.MangaSiteID = NINEMANGA_BR_ID) then + Result := GetNineMangaImageURL + else + if manager.container.MangaSiteID = LECTUREENLIGNE_ID then + Result := GeLectureEnligneImageURL + else + if manager.container.MangaSiteID = JAPANSHIN_ID then + Result := GetJapanShinImageURL + else + if manager.container.MangaSiteID = JAPSCAN_ID then + Result := GetJapscanImageURL + else + if manager.container.MangaSiteID = CENTRUMMANGI_PL_ID then + Result := GetCentrumMangi_PLImageURL + else + if manager.container.MangaSiteID = MANGALIB_PL_ID then + Result := GetMangaLib_PLImageURL + else + if manager.container.MangaSiteID = ONEMANGA_ID then + Result := GetOneMangaImageURL + else + if manager.container.MangaSiteID = MANGATOWN_ID then + Result := GetMangaTownImageURL + else + if manager.container.MangaSiteID = READHENTAIMANGA_ID then + Result := GetReadHentaiMangaImageURL + else + if manager.container.MangaSiteID = MANGAOKU_ID then + Result := GetMangaOkuImageURL + else + if manager.container.MangaSiteID = IKOMIK_ID then + Result := GetIKomikImageURL + else + if manager.container.MangaSiteID = NHENTAI_ID then + Result := GetNHentaiImageURL + else + if manager.container.MangaSiteID = MANGAMINT_ID then + Result := GetMangaMintImageURL + else + if manager.container.MangaSiteID = UNIXMANGA_ID then + Result := GetUnixMangaImageURL + else + if manager.container.MangaSiteID = HAKIHOME_ID then + Result := GetHakiHomeImageURL + else + if manager.container.MangaSiteID = MANGAHOST_ID then + Result := GetMangaHostImageURL + else + if (manager.container.MangaSiteID = PORNCOMIX_ID) or + (manager.container.MangaSiteID = XXCOMICS_ID) or + (manager.container.MangaSiteID = XXCOMICSMT_ID) or + (manager.container.MangaSiteID = XXCOMICS3D_ID) or + (manager.container.MangaSiteID = PORNCOMIXRE_ID) or + (manager.container.MangaSiteID = PORNCOMIXIC_ID) or + (manager.container.MangaSiteID = PORNXXXCOMICS_ID) then + Result := GetPornComixImageURL + else + if manager.container.MangaSiteID = MANGAAT_ID then + Result := GetMangaAtImageURL + else + if SitesIsWPManga(manager.container.MangaSiteID) then + Result := GetWPMangaImageURL; + end; end; procedure TDownloadThread.MainThreadMessageDialog; From 446edf17218e250885a81eaf9518318b993588cc Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:38:45 +0800 Subject: [PATCH 0161/2794] downloadmanager, remove advanced config Doesn't really needed. --- baseunits/uDownloadsManager.pas | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index f972db93c..934952dc2 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1322,30 +1322,17 @@ procedure TTaskThread.CheckOut; var currentMaxThread: Integer; s: String; - mt: Integer; begin if Terminated then Exit; - //load advanced config if any - mt := INIAdvanced.ReadInteger('DownloadMaxThreadsPerTask', - WebsiteRoots[container.MangaSiteID, 0], -1); - if (mt > 0) then - begin - if (mt > 32) then - mt := 32; - currentMaxThread := mt; - end - else - begin - case container.MangaSiteID of - PECINTAKOMIK_ID : currentMaxThread := 1; - EHENTAI_ID : currentMaxThread := 2; - else - currentMaxThread := container.Manager.maxDLThreadsPerTask; - end; - if currentMaxThread > container.Manager.maxDLThreadsPerTask then + case container.MangaSiteID of + PECINTAKOMIK_ID : currentMaxThread := 1; + EHENTAI_ID : currentMaxThread := 2; + else currentMaxThread := container.Manager.maxDLThreadsPerTask; end; + if currentMaxThread > container.Manager.maxDLThreadsPerTask then + currentMaxThread := container.Manager.maxDLThreadsPerTask; if container.PageLinks.Count > 0 then begin From 22aff68ca93f3072c000687dacd4f214bf0476de Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:42:35 +0800 Subject: [PATCH 0162/2794] downloadmanager, re-add advanced config In case someone needed for testing purpose. --- baseunits/uDownloadsManager.pas | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 934952dc2..acbceabac 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1322,17 +1322,30 @@ procedure TTaskThread.CheckOut; var currentMaxThread: Integer; s: String; + mt: Integer; begin if Terminated then Exit; - case container.MangaSiteID of - PECINTAKOMIK_ID : currentMaxThread := 1; - EHENTAI_ID : currentMaxThread := 2; - else + //load advanced config if any + mt := INIAdvanced.ReadInteger('DownloadMaxThreadsPerTask', + container.DownloadInfo.Website, 0], -1); + if (mt > 0) then + begin + if (mt > 32) then + mt := 32; + currentMaxThread := mt; + end + else + begin + case container.MangaSiteID of + PECINTAKOMIK_ID : currentMaxThread := 1; + EHENTAI_ID : currentMaxThread := 2; + else + currentMaxThread := container.Manager.maxDLThreadsPerTask; + end; + if currentMaxThread > container.Manager.maxDLThreadsPerTask then currentMaxThread := container.Manager.maxDLThreadsPerTask; end; - if currentMaxThread > container.Manager.maxDLThreadsPerTask then - currentMaxThread := container.Manager.maxDLThreadsPerTask; if container.PageLinks.Count > 0 then begin From 79507fe8307eb3325635882228fcbb4d1e21e52f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 03:43:57 +0800 Subject: [PATCH 0163/2794] downloadmanager, fix typo --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index acbceabac..29cdbcd3e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1328,7 +1328,7 @@ procedure TTaskThread.CheckOut; //load advanced config if any mt := INIAdvanced.ReadInteger('DownloadMaxThreadsPerTask', - container.DownloadInfo.Website, 0], -1); + container.DownloadInfo.Website, -1); if (mt > 0) then begin if (mt > 32) then From a46cb3586cea840ad9d429f25d79c38978d0ad6e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 04:52:55 +0800 Subject: [PATCH 0164/2794] downloadmanager, fix range check error --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 29cdbcd3e..3f55641af 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1510,7 +1510,7 @@ procedure TTaskThread.Execute; if container.PageLinks.Count = 0 then container.PageLinks.Add('W'); container.PageNumber := container.PageLinks.Count; - if not SitesWithoutPageLink(WebsiteRoots[container.MangaSiteID, 0]) and + if not SitesWithoutPageLink(container.DownloadInfo.Website) and CheckForPrepare then begin Flag := CS_GETPAGELINK; From 8954fe99013fc4caacbc7f4289c79e2d0af6b333 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 04:55:49 +0800 Subject: [PATCH 0165/2794] websitemodules, change getpagenumber and getimageurl param --- baseunits/WebsiteModules.pas | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 7915a54ed..74781183b 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -25,10 +25,10 @@ TModuleContainer = class; TOnGetInfo = function(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; Module: TModuleContainer): Integer; - TOnGetPageNumber = function(var Container: TTaskContainer; + TOnGetPageNumber = function(var DownloadThread: TDownloadThread; + const URL: String; Module: TModuleContainer): Boolean; + TOnGetImageURL = function(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; - TOnGetImageURL = function(var Container: TTaskContainer; const URL: String; - Module: TModuleContainer): Boolean; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, MMGetPageNumber, MMGetImageURL); @@ -81,14 +81,14 @@ TWebsiteModules = class(TObject) function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; const Website: String): Integer; overload; - function GetPageNumber(var Container: TTaskContainer; const URL: String; - const ModuleIndex: Integer): Boolean; overload; - function GetPageNumber(var Container: TTaskContainer; + function GetPageNumber(var DownloadThread: TDownloadThread; + const URL: String; const ModuleIndex: Integer): Boolean; overload; + function GetPageNumber(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; overload; - function GetImageURL(var Container: TTaskContainer; const URL: String; - const ModuleIndex: Integer): Boolean; overload; - function GetImageURL(var Container: TTaskContainer; + function GetImageURL(var DownloadThread: TDownloadThread; + const URL: String; const ModuleIndex: Integer): Boolean; overload; + function GetImageURL(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; overload; procedure LockModules; @@ -254,7 +254,7 @@ function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; Result := GetInfo(MangaInfo, URL, Reconnect, LocateModule(Website)); end; -function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; +function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; const ModuleIndex: Integer): Boolean; begin Result := False; @@ -262,16 +262,16 @@ function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber( - Container, URL, TModuleContainer(FModuleList[ModuleIndex])); + DownloadThread, URL, TModuleContainer(FModuleList[ModuleIndex])); end; -function TWebsiteModules.GetPageNumber(var Container: TTaskContainer; +function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; begin - Result := GetPageNumber(Container, URL, LocateModule(Website)); + Result := GetPageNumber(DownloadThread, URL, LocateModule(Website)); end; -function TWebsiteModules.GetImageURL(var Container: TTaskContainer; +function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; const URL: String; const ModuleIndex: Integer): Boolean; begin Result := False; @@ -279,13 +279,13 @@ function TWebsiteModules.GetImageURL(var Container: TTaskContainer; Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL( - Container, URL, TModuleContainer(FModuleList[ModuleIndex])); + DownloadThread, URL, TModuleContainer(FModuleList[ModuleIndex])); end; -function TWebsiteModules.GetImageURL(var Container: TTaskContainer; +function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; begin - Result := GetImageURL(Container, URL, LocateModule(Website)); + Result := GetImageURL(DownloadThread, URL, LocateModule(Website)); end; procedure TWebsiteModules.LockModules; From a10381968219bcab8d86ec5aaaea656f6a528745 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 04:56:18 +0800 Subject: [PATCH 0166/2794] downloadmanager, reveal protected variable used in modules --- baseunits/uDownloadsManager.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 3f55641af..ae0ce6769 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -28,9 +28,10 @@ TTaskThread = class; { TDownloadThread } TDownloadThread = class(TFMDThread) - protected + private parse: TStringList; checkStyle: TFlagType; + public workCounter: Cardinal; FSortColumn: Cardinal; FMessage, FAnotherURL: String; From b6bb3b9f862a4da0adc91f222f62ada1bf4bfab5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 04:57:42 +0800 Subject: [PATCH 0167/2794] downloadmanager, change param --- baseunits/uDownloadsManager.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ae0ce6769..b04649022 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -520,7 +520,7 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; i := -1; if Modules.ModuleAvailable(Self.manager.container.DownloadInfo.Website, MMGetPageNumber, i) then - Result := Modules.GetPageNumber(Self.manager.container, URL, i) + Result := Modules.GetPageNumber(Self, URL, i) else begin if manager.container.MangaSiteID = ANIMEA_ID then @@ -885,7 +885,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; i := -1; if Modules.ModuleAvailable(Self.manager.container.DownloadInfo.Website, MMGetImageURL, i) then - Result := Modules.GetImageURL(Self.manager.container, URL, i) + Result := Modules.GetImageURL(Self, URL, i) else begin if manager.container.MangaSiteID = ANIMEA_ID then From 0d10ab2c58b1bfebcce121e90a92ce31eadac282 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 05:00:04 +0800 Subject: [PATCH 0168/2794] fool#$slide, add getpagenumber and getimageurl closes #70 --- baseunits/modules/FoOlSlide.pas | 106 +++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index ee66ba879..a136019c5 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -5,8 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, USimpleLogger, HTMLUtil, - RegExpr; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, RegExpr; implementation @@ -195,6 +195,106 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source, Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i, p: Integer; + begin + p := -1; + for i := 0 to Parse.Count - 1 do + if (GetVal(Parse[i], 'class') = 'dropdown') and (Pos('style=', Parse[i]) > 0) then + begin + p := i + 1; + Break; + end; + if p > -1 then + for i := p to Parse.Count - 1 do + begin + if Pos('', Parse[i]) <> 0 then + Break; + if GetTagName(Parse[i]) = 'a' then + Inc(Container.PageNumber); + end; + end; + +begin + Result := False; + if DownloadThread = nil then + Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), + Container.Manager.retryConnect) then + begin + Result := True; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source, Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'open') then + begin + if DownloadThread.workCounter < Container.PageLinks.Count then + Container.PageLinks[DownloadThread.workCounter] := GetVal(Parse[i], 'src'); + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then + Exit; + Container := DownloadThread.manager.container; + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL) + + 'page/' + IntToStr(DownloadThread.workCounter + 1), + Container.Manager.retryConnect) then + begin + Result := True; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + procedure RegisterModule; begin with AddModule do @@ -206,6 +306,8 @@ procedure RegisterModule; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; end; From 864903dd161d9353c997f1e3e8c408184885f42c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 05:08:15 +0800 Subject: [PATCH 0169/2794] fool#@slide, fix wrong chapter links --- baseunits/modules/FoOlSlide.pas | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index a136019c5..cfa5cd9ca 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -120,10 +120,11 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; g += ' '; end; if GetTagName(Parse[i]) = 'a' then - begin - chapterLinks.Add(GetVal(Parse[i], 'href')); - chapterName.Add(g + Trim(Parse[i + 1])); - end; + if GetVal(Parse[i - 1], 'class') = 'title' then + begin + chapterLinks.Add(GetVal(Parse[i], 'href')); + chapterName.Add(g + Trim(Parse[i + 1])); + end; end; //invert chapters if MangaInfo.mangaInfo.chapterLinks.Count > 0 then From 0f5c61b9d097e4d9aa4ba34799354ebd27c857a2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 05:32:09 +0800 Subject: [PATCH 0170/2794] websitemodule, various correction --- baseunits/WebsiteModules.pas | 65 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 74781183b..1603a9852 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -59,10 +59,12 @@ TWebsiteModules = class(TObject) function AddModule: TModuleContainer; function LocateModule(const Website: String): Integer; - function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; - var OutIndex: Integer): Boolean; overload; + function ModuleAvailable(const ModuleIndex: Integer; + ModuleMethod: TModuleMethod): Boolean; overload; function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod): Boolean; overload; + function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; + var OutIndex: Integer): Boolean; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Cardinal; const ModuleIndex: Integer): Integer; overload; @@ -169,44 +171,47 @@ function TWebsiteModules.LocateModule(const Website: String): Integer; end; end; -function TWebsiteModules.ModuleAvailable(const Website: String; - ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; -var - p: Integer; +function TWebsiteModules.ModuleAvailable(const ModuleIndex: Integer; + ModuleMethod: TModuleMethod): Boolean; begin Result := False; - p := LocateModule(Website); - OutIndex := p; - if p >= 0 then + if (ModuleIndex < 0) or (FModuleList.Count = 0) or + (ModuleIndex >= FModuleList.Count) then + Exit; + with TModuleContainer(FModuleList[ModuleIndex]) do begin - with TModuleContainer(FModuleList[p]) do - begin - case ModuleMethod of - MMGetDirectoryPageNumber: Result := Assigned(OnGetDirectoryPageNumber); - MMGetNameAndLink: Result := Assigned(OnGetNameAndLink); - MMGetInfo: Result := Assigned(OnGetInfo); - MMGetPageNumber: Result := Assigned(OnGetPageNumber); - MMGetImageURL: Result := Assigned(OnGetImageURL); - else - Result := False; - end; + case ModuleMethod of + MMGetDirectoryPageNumber: Result := Assigned(OnGetDirectoryPageNumber); + MMGetNameAndLink: Result := Assigned(OnGetNameAndLink); + MMGetInfo: Result := Assigned(OnGetInfo); + MMGetPageNumber: Result := Assigned(OnGetPageNumber); + MMGetImageURL: Result := Assigned(OnGetImageURL); + else + Result := False; end; end; end; function TWebsiteModules.ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod): Boolean; -var - p: Integer; begin - Result := ModuleAvailable(Website, ModuleMethod, p); + Result := ModuleAvailable(LocateModule(Website), ModuleMethod); +end; + +function TWebsiteModules.ModuleAvailable(const Website: String; + ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; +begin + Result := False; + OutIndex := LocateModule(Website); + Result := ModuleAvailable(OutIndex, ModuleMethod); end; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Cardinal; const ModuleIndex: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + if (ModuleIndex < 0) or (FModuleList.Count = 0) or + (ModuleIndex >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetDirectoryPageNumber) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetDirectoryPageNumber( @@ -224,7 +229,8 @@ function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; const ModuleIndex: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + if (ModuleIndex < 0) or (FModuleList.Count = 0) or + (ModuleIndex >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetNameAndLink) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetNameAndLink( @@ -241,7 +247,8 @@ function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; const ModuleIndex: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + if (ModuleIndex < 0) or (FModuleList.Count = 0) or + (ModuleIndex >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetInfo) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetInfo( @@ -258,7 +265,8 @@ function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; const ModuleIndex: Integer): Boolean; begin Result := False; - if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + if (ModuleIndex < 0) or (FModuleList.Count = 0) or + (ModuleIndex >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber( @@ -275,7 +283,8 @@ function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; const URL: String; const ModuleIndex: Integer): Boolean; begin Result := False; - if (ModuleIndex = -1) or (ModuleIndex >= FModuleList.Count) then + if (ModuleIndex < 0) or (FModuleList.Count = 0) or + (ModuleIndex >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL) then Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL( From 907cb34b00a72c1672956680b77f26ac3313ff5d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 05:38:40 +0800 Subject: [PATCH 0171/2794] downloadmanager, store moduleid to avoid repeated check --- baseunits/uDownloadsManager.pas | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b04649022..88890f727 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -31,6 +31,7 @@ TDownloadThread = class(TFMDThread) private parse: TStringList; checkStyle: TFlagType; + ModuleId: Integer; public workCounter: Cardinal; FSortColumn: Cardinal; @@ -79,6 +80,8 @@ TDownloadThread = class(TFMDThread) { TTaskThread } TTaskThread = class(TFMDThread) + private + ModuleId: Integer; protected FMessage, FAnotherURL: String; procedure CheckOut; @@ -270,6 +273,7 @@ constructor TDownloadThread.Create; FHTTP := THTTPSendThread.Create(Self); FHTTP.Headers.NameValueSeparator := ':'; FHTTP.Sock.OnStatus := SockOnStatus; + ModuleId := -1; end; destructor TDownloadThread.Destroy; @@ -373,7 +377,6 @@ procedure TDownloadThread.DoTerminate; function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; var Parser: THTMLParser; - i: Integer; {$I includes/AnimeStory/chapter_page_number.inc} @@ -517,10 +520,8 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := False; manager.container.PageNumber := 0; - i := -1; - if Modules.ModuleAvailable(Self.manager.container.DownloadInfo.Website, - MMGetPageNumber, i) then - Result := Modules.GetPageNumber(Self, URL, i) + if Modules.ModuleAvailable(ModuleId, MMGetPageNumber) then + Result := Modules.GetPageNumber(Self, URL, ModuleId) else begin if manager.container.MangaSiteID = ANIMEA_ID then @@ -742,7 +743,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; var Parser: THTMLParser; - i: Integer; {$I includes/AnimeStory/image_url.inc} @@ -882,10 +882,8 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; (manager.container.PageLinks.Strings[workCounter] <> 'W') then Exit; - i := -1; - if Modules.ModuleAvailable(Self.manager.container.DownloadInfo.Website, - MMGetImageURL, i) then - Result := Modules.GetImageURL(Self, URL, i) + if Modules.ModuleAvailable(ModuleId, MMGetImageURL) then + Result := Modules.GetImageURL(Self, URL, ModuleId) else begin if manager.container.MangaSiteID = ANIMEA_ID then @@ -1195,6 +1193,7 @@ constructor TTaskThread.Create; inherited Create(True); CS_threads := TCriticalSection.Create; threads := TFPList.Create; + ModuleId := -1; anotherURL := ''; httpCookies := ''; end; @@ -1374,6 +1373,7 @@ procedure TTaskThread.CheckOut; threads.Add(TDownloadThread.Create); with TDownloadThread(threads.Last) do begin manager := Self; + ModuleId := Self.ModuleId; workCounter := container.WorkCounter; checkStyle := Flag; //load User-Agent from INIAdvanced @@ -1440,6 +1440,7 @@ procedure TTaskThread.Execute; S, P: String; begin INIAdvanced.Reload; + ModuleId := Modules.LocateModule(container.DownloadInfo.Website); container.ThreadState := True; container.DownloadInfo.TransferRate := ''; try From f93bfb4b274dd04c60c550d97990ecd2dbf5698e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 05:39:16 +0800 Subject: [PATCH 0172/2794] mainform, decrease itmonitor interval --- mangadownloader/forms/frmMain.lfm | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 6aeb24390..df674f972 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -5693,7 +5693,6 @@ object MainForm: TMainForm end object itMonitor: TTimer Enabled = False - Interval = 1500 OnTimer = itMonitorTimer left = 760 top = 296 From 3b0a649093b729c5b0661d9566f631e8472d6567 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 06:00:00 +0800 Subject: [PATCH 0173/2794] websitemodules, minor changes --- baseunits/WebsiteModules.pas | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 1603a9852..f93471212 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -65,6 +65,7 @@ TWebsiteModules = class(TObject) ModuleMethod: TModuleMethod): Boolean; overload; function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; overload; + function ModuleAvailable(const Website: String): Boolean; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Cardinal; const ModuleIndex: Integer): Integer; overload; @@ -96,7 +97,7 @@ TWebsiteModules = class(TObject) procedure LockModules; procedure UnlockModules; - function Items(const Index: Integer): TModuleContainer; + function Module(const Index: Integer): TModuleContainer; end; var @@ -206,6 +207,11 @@ function TWebsiteModules.ModuleAvailable(const Website: String; Result := ModuleAvailable(OutIndex, ModuleMethod); end; +function TWebsiteModules.ModuleAvailable(const Website: String): Boolean; +begin + Result := (LocateModule(Website) > -1); +end; + function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Cardinal; const ModuleIndex: Integer): Integer; begin @@ -307,7 +313,7 @@ procedure TWebsiteModules.UnlockModules; LeaveCriticalsection(FCSModules); end; -function TWebsiteModules.Items(const Index: Integer): TModuleContainer; +function TWebsiteModules.Module(const Index: Integer): TModuleContainer; begin Result := TModuleContainer(FModuleList[Index]); end; From 4d6d6ed36874814291630a308789794c3178503b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 06:02:09 +0800 Subject: [PATCH 0174/2794] mainform, fix showing url from mangalist --- mangadownloader/forms/frmMain.pas | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ccabb0788..494843430 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -710,8 +710,8 @@ implementation {$R *.lfm} uses - frmImportFavorites, frmShutdownCounter, RegExpr, Clipbrd, LazFileUtils, - LazUTF8; + frmImportFavorites, frmShutdownCounter, WebsiteModules, RegExpr, Clipbrd, + LazFileUtils, LazUTF8; { TMainForm } @@ -2714,14 +2714,19 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); GetInfosThread.Link := link; GetInfosThread.Start; - //ShowInformation; - for i := 0 to High(WebsiteRoots) do - if Pos(website, WebsiteRoots[i, 0]) > 0 then - begin - link := StringReplace(link, WebsiteRoots[i, 1], '', []); - edURL.Text := FixURL(FillMangaSiteHost(i, link)); - Break; - end; + i := Modules.LocateModule(website); + if i > -1 then + edURL.Text := FillHost(Modules.Module(i).RootURL, link) + else + begin + for i := 0 to High(WebsiteRoots) do + if Pos(website, WebsiteRoots[i, 0]) > 0 then + begin + link := StringReplace(link, WebsiteRoots[i, 1], '', []); + edURL.Text := FixURL(FillMangaSiteHost(i, link)); + Break; + end; + end; if Assigned(gifWaiting) then begin From 9f6b108e57f608384f0cc8027198769e7a9eaef4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 06:05:51 +0800 Subject: [PATCH 0175/2794] baseunit, include protocol in fillhost --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a4fdc3f50..33171a834 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1422,7 +1422,7 @@ function FillHost(const Host, URL: String): String; ModifierI := True; ModifierG := True; Expression := '^((https?|ftp)://)?([^/]*\.\w+)?(/?.*)$'; - th := Replace(Host, '$3', True); + th := Replace(Host, '$1$3', True); tu := Replace(URL, '$4', True); if (tu <> '') and (tu[1] <> '/') then tu := '/' + tu; From d148f639ce0d3ad554c5f600282aeee6db22bd61 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 16:55:14 +0800 Subject: [PATCH 0176/2794] baseunit, fix various url manipulation method --- baseunits/uBaseUnit.pas | 86 ++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 57 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 33171a834..c29b19ed7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -259,6 +259,9 @@ interface SEPERATOR = '!%~'; SEPERATOR2 = '~%!'; + // common regex to split host/url + REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(/?.*)$'; + ANIMEA_ID = 0; MANGAHERE_ID = 1; MANGAINN_ID = 2; @@ -856,7 +859,8 @@ function SitesIsWPManga(const websiteid: Cardinal): Boolean; overload; function SitesIsWPManga(const website: String): Boolean; overload; // Fill in website host if it's not present -function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; +function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; +function FillMangaSiteHost(const Website, URL: String): String; overload; function FillHost(const Host, URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(Const URLs: TStringList); @@ -1208,12 +1212,13 @@ function GetMangaSiteID(const Name: String): Integer; begin Result := High(WebsiteRoots) + 1; for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Name = WebsiteRoots[i, 0] then + if SameText(Name, WebsiteRoots[i, 0]) then Exit(i); end; function GetMangaSiteName(const ID: Cardinal): String; begin + if ID >= High(WebsiteRoots) then Exit(''); Result := WebsiteRoots[ID, 0]; end; @@ -1388,27 +1393,16 @@ function SitesIsWPManga(const website: String): Boolean; end; function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; -var - regx: TRegExpr; begin Result := URL; - if Length(URL) < 3 then - Exit; if MangaID <= High(WebsiteRoots) then - regx := TRegExpr.Create; - try - regx.ModifierI := True; - regx.Expression := '^([a-z]+\:)?(//)?[^/]*\w+\.\w+(\:\d+)?/?'; - if Pos('//', Result) = 1 then - Delete(Result, 1, 2); - if not regx.Exec(URL) then - Result := TrimRightChar(WebsiteRoots[MangaID, 1], ['/']) + - '/' + TrimLeftChar(URL, ['/']); - regx.Expression := '([^:])[/]{2,}(\b|\Z)'; - Result := regx.Replace(Result, '$1/', True); - finally - regx.Free - end; + Result := FillHost(WebsiteRoots[MangaID, 1], URL); +end; + +function FillMangaSiteHost(const Website, URL: String): String; +begin + if Website = '' then Exit(URL); + Result := FillMangaSiteHost(GetMangaSiteID(Website), URL); end; function FillHost(const Host, URL: String): String; @@ -1419,11 +1413,9 @@ function FillHost(const Host, URL: String): String; if Host = '' then Exit; with TRegExpr.Create do try - ModifierI := True; - ModifierG := True; - Expression := '^((https?|ftp)://)?([^/]*\.\w+)?(/?.*)$'; - th := Replace(Host, '$1$3', True); - tu := Replace(URL, '$4', True); + Expression := REGEX_HOST; + th := Replace(Host, '$1$2', True); + tu := Replace(URL, '$3', True); if (tu <> '') and (tu[1] <> '/') then tu := '/' + tu; Result := th + tu; @@ -1433,41 +1425,24 @@ function FillHost(const Host, URL: String): String; end; function RemoveHostFromURL(URL : String) : String; -var - regx: TRegExpr; begin - Result := URL; - regx := TRegExpr.Create; - try - regx.ModifierI := True; - regx.Expression := '^([a-z]+\:)?(//)?[^/]*\w+\.\w+(\:\d+)?/?'; - if regx.Exec(URL) then - Result := regx.Replace(URL, '/', False); - finally - regx.Free - end; + Result := ReplaceRegExpr(REGEX_HOST, URL, '$3', True); end; procedure RemoveHostFromURLs(const URLs : TStringList); var i: Integer; - regx: TRegExpr; begin + if URLs = nil then Exit; if URLs.Count > 0 then - begin - regx := TRegExpr.Create; + with TRegExpr.Create do try - regx.ModifierI := True; - regx.Expression := '^([a-z]+\:)?(//)?[^/]*\w+\.\w+(\:\d+)?/?'; + Expression := REGEX_HOST; for i := 0 to URLs.Count - 1 do - begin - if regx.Exec(URLs[i]) then - URLs[i] := regx.Replace(URLs[i], '/', False); - end; + URLs[i] := Replace(URLs[i], '$3', True); finally - regx.Free + Free; end; - end; end; procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); @@ -1475,18 +1450,16 @@ procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); i: Integer; regx: TRegExpr; begin + if (URLs = nil) or (Names = nil) then Exit; + if (URLs.Count <> Names.Count) then Exit; if URLs.Count > 0 then - begin - regx := TRegExpr.Create; + with TRegExpr.Create do try - regx.ModifierI := True; - regx.Expression := '^([a-z]+\:)?(//)?[^/]*\w+\.\w+(\:\d+)?/?'; i := 0; while i < URLs.Count do begin - if regx.Exec(URLs[i]) then - URLs[i] := regx.Replace(URLs[i], '/', False); - if URLs[i] = '/' then + URLs[i] := Replace(URLs[i], '$3', True); + if (URLs[i] = '') or (URLs[i] = '/') then begin URLs.Delete(i); Names.Delete(i); @@ -1495,9 +1468,8 @@ procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); Inc(i); end; finally - regx.Free + Free; end; - end; end; procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); From 50e62fab0236d433a071ebafada12c206e90fc82 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 16:56:12 +0800 Subject: [PATCH 0177/2794] mainform, minor changes --- mangadownloader/forms/frmMain.pas | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 494843430..bde7afc6d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2718,15 +2718,7 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); if i > -1 then edURL.Text := FillHost(Modules.Module(i).RootURL, link) else - begin - for i := 0 to High(WebsiteRoots) do - if Pos(website, WebsiteRoots[i, 0]) > 0 then - begin - link := StringReplace(link, WebsiteRoots[i, 1], '', []); - edURL.Text := FixURL(FillMangaSiteHost(i, link)); - Break; - end; - end; + edURL.Text := FillMangaSiteHost(website, link); if Assigned(gifWaiting) then begin From f6f45336c768e8275a760a7628d71e636b298b25 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 17:11:01 +0800 Subject: [PATCH 0178/2794] baseunit, fix missing regex expression in removehost --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c29b19ed7..e979e225a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1455,6 +1455,7 @@ procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); if URLs.Count > 0 then with TRegExpr.Create do try + Expression := REGEX_HOST; i := 0; while i < URLs.Count do begin From 74b0403ee35209f063a1080a0fdb10b5c4ff865e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 17:12:37 +0800 Subject: [PATCH 0179/2794] clean up --- baseunits/uBaseUnit.pas | 1 - mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e979e225a..11a8236cb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1448,7 +1448,6 @@ procedure RemoveHostFromURLs(const URLs : TStringList); procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); var i: Integer; - regx: TRegExpr; begin if (URLs = nil) or (Names = nil) then Exit; if (URLs.Count <> Names.Count) then Exit; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bde7afc6d..776f95753 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2718,7 +2718,7 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); if i > -1 then edURL.Text := FillHost(Modules.Module(i).RootURL, link) else - edURL.Text := FillMangaSiteHost(website, link); + edURL.Text := FillMangaSiteHost(website, link); if Assigned(gifWaiting) then begin From 8a898cba1f34679a805bc5684c5698f453d8fb25 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:18:22 +0800 Subject: [PATCH 0180/2794] websitemodules, add locatemodulebyhost --- baseunits/WebsiteModules.pas | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index f93471212..f331adcf4 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -59,6 +59,7 @@ TWebsiteModules = class(TObject) function AddModule: TModuleContainer; function LocateModule(const Website: String): Integer; + function LocateModuleByHost(const Host: String): Integer; function ModuleAvailable(const ModuleIndex: Integer; ModuleMethod: TModuleMethod): Boolean; overload; function ModuleAvailable(const Website: String; @@ -155,21 +156,24 @@ function TWebsiteModules.LocateModule(const Website: String): Integer; begin Result := -1; if FModuleList.Count > 0 then - begin - EnterCriticalsection(FCSModules); - try - for i := 0 to FModuleList.Count - 1 do + for i := 0 to FModuleList.Count - 1 do + if SameText(TModuleContainer(FModuleList[i]).Website, Website) then begin - if SameText(TModuleContainer(FModuleList[i]).Website, Website) then - begin - Result := i; - Break; - end; + Result := i; + Break; + end; +end; + +function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; +begin + Result := -1; + if FModuleList.Count > 0 then + for i := 0 to FModuleList.Count - 1 do + if Pos(Host, TModuleContainer(FModuleList[i]).Website) <> 0 then + begin + Result := i; + Break; end; - finally - LeaveCriticalsection(FCSModules); - end; - end; end; function TWebsiteModules.ModuleAvailable(const ModuleIndex: Integer; From 25ed12ca3e80234b8a718aa12e13b5e2a54068c1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:21:35 +0800 Subject: [PATCH 0181/2794] websitemodules, fix missing var --- baseunits/WebsiteModules.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index f331adcf4..cc8e21c90 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -165,6 +165,8 @@ function TWebsiteModules.LocateModule(const Website: String): Integer; end; function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; +var + i: Integer; begin Result := -1; if FModuleList.Count > 0 then From b9fa3c28273a3079e330bdb4de65c1e855e31362 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:31:37 +0800 Subject: [PATCH 0182/2794] websitemodules, return nil if not available --- baseunits/WebsiteModules.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index cc8e21c90..904d0af63 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -321,6 +321,8 @@ procedure TWebsiteModules.UnlockModules; function TWebsiteModules.Module(const Index: Integer): TModuleContainer; begin + if (Index < 0) or (Index >= FModuleList.Count) then + Exit(nil); Result := TModuleContainer(FModuleList[Index]); end; From 55fe59fb58dc8cb75924fe24ee3c4477d171948c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:37:57 +0800 Subject: [PATCH 0183/2794] websitemodules, fix locatebyhost --- baseunits/WebsiteModules.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 904d0af63..a7c70cf34 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -171,11 +171,13 @@ function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; Result := -1; if FModuleList.Count > 0 then for i := 0 to FModuleList.Count - 1 do - if Pos(Host, TModuleContainer(FModuleList[i]).Website) <> 0 then + begin + if Pos(Host, TModuleContainer(FModuleList[i]).RootURL) <> 0 then begin Result := i; Break; end; + end; end; function TWebsiteModules.ModuleAvailable(const ModuleIndex: Integer; From d17f9dc4895437a8ff4229e3a94cddbd23a81049 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:43:25 +0800 Subject: [PATCH 0184/2794] mainform, fix url detection --- mangadownloader/forms/frmMain.pas | 37 +++++++++++++------------------ 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 776f95753..f9c7ce72a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1746,52 +1746,47 @@ procedure TMainForm.btURLClick(Sender: TObject); website := ''; webs := ''; link := ''; + edURL.Text := FixURL(edURL.Text); regx := TRegExpr.Create; try regx.Expression := '^https?\://'; if not (regx.Exec(edURL.Text)) then edURL.Text := 'http://' + edURL.Text; - regx.Expression := '^https?\:(//[^/]*\w+\.\w+)(\:\d+)?(/|\Z)(.*)$'; + regx.Expression := REGEX_HOST; if regx.Exec(edURL.Text) then begin - link := regx.Replace(edURL.Text, '$4', True); - webs := regx.Replace(edURL.Text, '$1', True); + webs := regx.Replace(edURL.Text, '$2', True); + link := regx.Replace(edURL.Text, '$3', True); end; if (webs <> '') and (link <> '') then begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(webs, WebsiteRoots[i, 1]) > 0 then - begin - webid := i; - website := WebsiteRoots[i, 0]; - Break; - end; - if website = '' then + webs := LowerCase(webs); + i := Modules.LocateModuleByHost(webs); + if i > -1 then + begin + website := Modules.Module(i).Website; + edURL.Text := FillHost(Modules.Module(i).RootURL, link); + end + else begin - webs := TrimLeftChar(webs, ['/']); for i := Low(WebsiteRoots) to High(WebsiteRoots) do - begin if Pos(webs, WebsiteRoots[i, 1]) > 0 then begin webid := i; website := WebsiteRoots[i, 0]; Break; end; - end; - end; - if website <> '' then - begin - link := '/' + link; - edURL.Text := FixURL(WebsiteRoots[webid, 1] + link); - DisableAddToFavorites(website); + if website <> '' then + edURL.Text := FillMangaSiteHost(webid, link); end; end; finally regx.Free; end; - + + DisableAddToFavorites(website); if (website = '') or (link = '') then begin MessageDlg('', RS_DlgURLNotSupport, mtInformation, [mbYes], 0); From 0d611eb4d84101dc1affa463fa0526cba876cb8e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:46:41 +0800 Subject: [PATCH 0185/2794] baseunit, change variable name of proxy config --- baseunits/uBaseUnit.pas | 90 +++++++++++++++---------------- mangadownloader/forms/frmMain.pas | 30 +++++------ 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 11a8236cb..5e057f01a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -678,11 +678,11 @@ interface currentWebsite: String; - ProxyType: String = ''; - Host: String = ''; - Port: String = ''; - User: String = ''; - Pass: String = ''; + OptionProxyType: String = ''; + OptionProxyHost: String = ''; + OptionProxyPort: String = ''; + OptionProxyUser: String = ''; + OptionProxyPass: String = ''; fmdDirectory: String; @@ -2688,36 +2688,36 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; globReturn: - if ProxyType = 'HTTP' then + if OptionProxyType = 'HTTP' then begin - HTTP.ProxyHost := Host; - HTTP.ProxyPort := Port; - HTTP.ProxyUser := User; - HTTP.ProxyPass := Pass; + HTTP.ProxyHost := OptionProxyHost; + HTTP.ProxyPort := OptionProxyPort; + HTTP.ProxyUser := OptionProxyUser; + HTTP.ProxyPass := OptionProxyPass; end else - if (ProxyType = 'SOCKS4') or (ProxyType = 'SOCKS5') then + if (OptionProxyType = 'SOCKS4') or (OptionProxyType = 'SOCKS5') then begin - if ProxyType = 'SOCKS4' then + if OptionProxyType = 'SOCKS4' then HTTP.Sock.SocksType := ST_Socks4 else - if ProxyType = 'SOCKS5' then + if OptionProxyType = 'SOCKS5' then HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := Host; - HTTP.Sock.SocksPort := Port; - HTTP.Sock.SocksUsername := User; - http.Sock.SocksPassword := Pass; + HTTP.Sock.SocksIP := OptionProxyHost; + HTTP.Sock.SocksPort := OptionProxyPort; + HTTP.Sock.SocksUsername := OptionProxyUser; + http.Sock.SocksPassword := OptionProxyPass; end else begin - HTTP.Sock.SocksIP := Host; - HTTP.Sock.SocksPort := Port; - HTTP.Sock.SocksUsername := User; - http.Sock.SocksPassword := Pass; - HTTP.ProxyHost := Host; - HTTP.ProxyPort := Port; - HTTP.ProxyUser := User; - HTTP.ProxyPass := Pass; + HTTP.Sock.SocksIP := OptionProxyHost; + HTTP.Sock.SocksPort := OptionProxyPort; + HTTP.Sock.SocksUsername := OptionProxyUser; + http.Sock.SocksPassword := OptionProxyPass; + HTTP.ProxyHost := OptionProxyHost; + HTTP.ProxyPort := OptionProxyPort; + HTTP.ProxyUser := OptionProxyUser; + HTTP.ProxyPass := OptionProxyPass; end; HTTPHeader.Values['DNT'] := ' 1'; @@ -2963,36 +2963,36 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP := THTTPSend.Create; HTTP.Headers.NameValueSeparator := ':'; - if ProxyType = 'HTTP' then + if OptionProxyType = 'HTTP' then begin - HTTP.ProxyHost := Host; - HTTP.ProxyPort := Port; - HTTP.ProxyUser := User; - HTTP.ProxyPass := Pass; + HTTP.ProxyHost := OptionProxyHost; + HTTP.ProxyPort := OptionProxyPort; + HTTP.ProxyUser := OptionProxyUser; + HTTP.ProxyPass := OptionProxyPass; end else - if (ProxyType = 'SOCKS4') or (ProxyType = 'SOCKS5') then + if (OptionProxyType = 'SOCKS4') or (OptionProxyType = 'SOCKS5') then begin - if ProxyType = 'SOCKS4' then + if OptionProxyType = 'SOCKS4' then HTTP.Sock.SocksType := ST_Socks4 else - if ProxyType = 'SOCKS5' then + if OptionProxyType = 'SOCKS5' then HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := Host; - HTTP.Sock.SocksPort := Port; - HTTP.Sock.SocksUsername := User; - http.Sock.SocksPassword := Pass; + HTTP.Sock.SocksIP := OptionProxyHost; + HTTP.Sock.SocksPort := OptionProxyPort; + HTTP.Sock.SocksUsername := OptionProxyUser; + http.Sock.SocksPassword := OptionProxyPass; end else begin - HTTP.Sock.SocksIP := Host; - HTTP.Sock.SocksPort := Port; - HTTP.Sock.SocksUsername := User; - http.Sock.SocksPassword := Pass; - HTTP.ProxyHost := Host; - HTTP.ProxyPort := Port; - HTTP.ProxyUser := User; - HTTP.ProxyPass := Pass; + HTTP.Sock.SocksIP := OptionProxyHost; + HTTP.Sock.SocksPort := OptionProxyPort; + HTTP.Sock.SocksUsername := OptionProxyUser; + http.Sock.SocksPassword := OptionProxyPass; + HTTP.ProxyHost := OptionProxyHost; + HTTP.ProxyPort := OptionProxyPort; + HTTP.ProxyUser := OptionProxyUser; + HTTP.ProxyPass := OptionProxyPass; end; HTTPHeader.Values['DNT'] := ' 1'; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f9c7ce72a..cb11222f8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4041,19 +4041,19 @@ procedure TMainForm.btOptionApplyClick(Sender: TObject); if cbOptionUseProxy.Checked then begin - ProxyType := cbOptionProxyType.Text; - Host := edOptionHost.Text; - Pass := edOptionPass.Text; - Port := edOptionPort.Text; - User := edOptionUser.Text; + OptionProxyType := cbOptionProxyType.Text; + OptionProxyHost := edOptionHost.Text; + OptionProxyPass := edOptionPass.Text; + OptionProxyPort := edOptionPort.Text; + OptionProxyUser := edOptionUser.Text; end else begin - ProxyType := ''; - Host := ''; - Pass := ''; - Port := ''; - User := ''; + OptionProxyType := ''; + OptionProxyHost := ''; + OptionProxyPass := ''; + OptionProxyPort := ''; + OptionProxyUser := ''; end; DLManager.maxDLTasks := seOptionMaxParallel.Value; @@ -4514,11 +4514,11 @@ procedure TMainForm.LoadOptions; OptionCustomRename := edOptionCustomRename.Text; if options.ReadBool('connections', 'UseProxy', False) then begin - ProxyType := options.ReadString('connections', 'ProxyType', 'HTTP'); - Host := options.ReadString('connections', 'Host', ''); - Pass := options.ReadString('connections', 'Pass', ''); - Port := options.ReadString('connections', 'Port', ''); - User := options.ReadString('connections', 'User', ''); + OptionProxyType := options.ReadString('connections', 'ProxyType', 'HTTP'); + OptionProxyHost := options.ReadString('connections', 'Host', ''); + OptionProxyPass := options.ReadString('connections', 'Pass', ''); + OptionProxyPort := options.ReadString('connections', 'Port', ''); + OptionProxyUser := options.ReadString('connections', 'User', ''); end; // update From 95a6fd0a06fb72ad8f457f8b2bccc95724b13c58 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:47:17 +0800 Subject: [PATCH 0186/2794] mainform, change var name --- mangadownloader/forms/frmMain.pas | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index cb11222f8..db48a528c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1739,12 +1739,12 @@ procedure TMainForm.btURLClick(Sender: TObject); i: Integer; webid: Cardinal; website, - webs, + host, link: String; regx: TRegExpr; begin website := ''; - webs := ''; + host := ''; link := ''; edURL.Text := FixURL(edURL.Text); regx := TRegExpr.Create; @@ -1756,14 +1756,14 @@ procedure TMainForm.btURLClick(Sender: TObject); regx.Expression := REGEX_HOST; if regx.Exec(edURL.Text) then begin - webs := regx.Replace(edURL.Text, '$2', True); + host := regx.Replace(edURL.Text, '$2', True); link := regx.Replace(edURL.Text, '$3', True); end; - if (webs <> '') and (link <> '') then + if (host <> '') and (link <> '') then begin - webs := LowerCase(webs); - i := Modules.LocateModuleByHost(webs); + host := LowerCase(host); + i := Modules.LocateModuleByHost(host); if i > -1 then begin website := Modules.Module(i).Website; @@ -1772,7 +1772,7 @@ procedure TMainForm.btURLClick(Sender: TObject); else begin for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(webs, WebsiteRoots[i, 1]) > 0 then + if Pos(host, WebsiteRoots[i, 1]) > 0 then begin webid := i; website := WebsiteRoots[i, 0]; From 06bda8944e51af6210013fded2c21c4a2b83fdbb Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:57:20 +0800 Subject: [PATCH 0187/2794] fool$$slide, fix wrong title --- baseunits/modules/FoOlSlide.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index cfa5cd9ca..10f862c3b 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -142,7 +142,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; //title if title = '' then if (GetTagName(Parse[i]) = 'h1') and (GetVal(Parse[i], 'class') = 'title') then - title := CommonStringFilter(Parse[i]); + title := CommonStringFilter(Parse[i + 1]); //cover if coverLink = '' then From 509ebd24e97bd1a34634cef267d9d9edc6b9c390 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 18:57:36 +0800 Subject: [PATCH 0188/2794] mainform, fix view info from favorites --- mangadownloader/forms/frmMain.pas | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index db48a528c..8d95241d7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1344,6 +1344,7 @@ procedure TMainForm.miFavoritesStopCheckNewChapterClick(Sender: TObject); procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); var title, website, link: String; + i: Integer; begin if (not vtFavorites.Focused) then Exit; @@ -1380,7 +1381,13 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); if ExecRegExpr('^https?://', link) then edURL.Text := link else - edURL.Text := WebsiteRoots[GetMangaSiteID(website), 1] + link; + begin + i := Modules.LocateModule(website); + if i > -1 then + edURL.Text := FillHost(Modules.Module(i).RootURL, link) + else + edURL.Text := FillMangaSiteHost(website, link); + end; btDownload.Enabled := (clbChapterList.RootNodeCount > 0); btReadOnline.Enabled := (edURL.Text <> ''); From 3a9eaf89aaab054a57f07a3493875c804fbe7945 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 19:08:20 +0800 Subject: [PATCH 0189/2794] mainform, fix view info from download list --- mangadownloader/forms/frmMain.pas | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8d95241d7..fbb41c90a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1147,10 +1147,17 @@ procedure TMainForm.medURLUndoClick(Sender: TObject); end; procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); +var + i: Integer; begin if vtDownload.Focused then - with DLManager.TaskItem(vtDownload.FocusedNode^.Index) do begin - edURL.Text := FillMangaSiteHost(MangaSiteID, DownloadInfo.Link); + with DLManager.TaskItem(vtDownload.FocusedNode^.Index) do + begin + i := Modules.LocateModule(DownloadInfo.Website); + if i > -1 then + edURL.Text := FillHost(Modules.Module(i).RootURL, DownloadInfo.Link) + else + edURL.Text := FillMangaSiteHost(DownloadInfo.Website, DownloadInfo.Link); btURLClick(btURL); pcMain.ActivePage := tsInformation; end; From 295eb400632b85b8404dd6f38db76c442a2cd612 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 19:29:36 +0800 Subject: [PATCH 0190/2794] change some param from cardinal to integer --- baseunits/WebsiteModules.pas | 10 +++++----- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/uData.pas | 4 ++-- baseunits/uUpdateThread.pas | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index a7c70cf34..8d78ca76d 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -18,7 +18,7 @@ interface TModuleContainer = class; TOnGetDirectoryPageNumber = function(var MangaInfo: TMangaInformation; - var Page: Cardinal; Module: TModuleContainer): Integer; + var Page: Integer; Module: TModuleContainer): Integer; TOnGetNameAndLink = function(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; @@ -69,9 +69,9 @@ TWebsiteModules = class(TObject) function ModuleAvailable(const Website: String): Boolean; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Cardinal; const ModuleIndex: Integer): Integer; overload; + var Page: Integer; const ModuleIndex: Integer): Integer; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Cardinal; const Website: String): Integer; overload; + var Page: Integer; const Website: String): Integer; overload; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; @@ -221,7 +221,7 @@ function TWebsiteModules.ModuleAvailable(const Website: String): Boolean; end; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Cardinal; const ModuleIndex: Integer): Integer; + var Page: Integer; const ModuleIndex: Integer): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleIndex < 0) or (FModuleList.Count = 0) or @@ -233,7 +233,7 @@ function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation end; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Cardinal; const Website: String): Integer; + var Page: Integer; const Website: String): Integer; begin Result := GetDirectoryPageNumber(MangaInfo, Page, LocateModule(Website)); end; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 10f862c3b..01f170d20 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -11,7 +11,7 @@ interface implementation function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Cardinal; Module: TModuleContainer): Integer; + var Page: Integer; Module: TModuleContainer): Integer; var Source, Parse: TStringList; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8fa3a5664..d89a4832f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -175,7 +175,7 @@ TMangaInformation = class(TObject) constructor Create(AOwnerThread: TFMDThread = nil); destructor Destroy; override; procedure ClearInfo; - function GetDirectoryPage(var Page: Cardinal; const website: String): Byte; + function GetDirectoryPage(var Page: Integer; const website: String): Byte; function GetNameAndLink(const names, links: TStringList; const website, URL: String): Byte; function GetInfoFromURL(const website, URL: String; const Reconnect: Cardinal): Byte; @@ -1798,7 +1798,7 @@ procedure TMangaInformation.OnText(Text: String); parse.Add(Text); end; -function TMangaInformation.GetDirectoryPage(var Page: Cardinal; +function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: String): Byte; var s: String; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index f8ad7ed21..7820f26ee 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -53,7 +53,7 @@ TUpdateMangaManagerThread = class(TFMDThread) procedure ExtractFile; procedure RefreshList; procedure DlgReport; - procedure GetInfo(const limit: Cardinal; const cs: TCheckStyleType); + procedure GetInfo(const limit: Integer; const cs: TCheckStyleType); procedure DoTerminate; override; public CS_AddInfoToData, CS_AddNamesAndLinks: TCriticalSection; @@ -63,7 +63,7 @@ TUpdateMangaManagerThread = class(TFMDThread) website, twebsite: String; workPtr, directoryCount, // for fakku's doujinshi only - directoryCount2, numberOfThreads, websitePtr: Cardinal; + directoryCount2, numberOfThreads, websitePtr: Integer; threads: TFPList; CS_threads: TCriticalSection; constructor Create; @@ -401,7 +401,7 @@ procedure TUpdateMangaManagerThread.DlgReport; mtInformation, [mbYes], 0); end; -procedure TUpdateMangaManagerThread.GetInfo(const limit: Cardinal; +procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; const cs: TCheckStyleType); procedure WaitForThreads; From 6e484d552e1dcdf0e847e942c26104b2f60f417f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 19:41:24 +0800 Subject: [PATCH 0191/2794] updatethread, fix range check error with websitemodules --- baseunits/uUpdateThread.pas | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 7820f26ee..9699ea36f 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -505,9 +505,8 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; if cs = CS_DIRECTORY_PAGE_2 then s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; if cs = CS_INFO then - s := s + ' | ' + RS_GettingInfo + ' "' + names.Strings[workPtr - 1] + - '" "' + WebsiteRoots[GetMangaSiteID(website), 1] + - links.Strings[workPtr - 1] + '"'; + s := Format('%s | %s "%s" "%s"', [s, RS_GettingInfo, names[workPtr - 1], + links[workPtr - 1]]); FStatus := s; Synchronize(MainThreadShowGetting); finally From 5122dbf0d2ddb0cebd523120ebe80d9464b70ab5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 19:46:45 +0800 Subject: [PATCH 0192/2794] websitemodules, overload moduleavailable method --- baseunits/WebsiteModules.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 8d78ca76d..57346c3f5 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -67,6 +67,8 @@ TWebsiteModules = class(TObject) function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; overload; function ModuleAvailable(const Website: String): Boolean; overload; + function ModuleAvailable(const Website: String; var OutIndex: Integer): Boolean; + overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; const ModuleIndex: Integer): Integer; overload; @@ -220,6 +222,13 @@ function TWebsiteModules.ModuleAvailable(const Website: String): Boolean; Result := (LocateModule(Website) > -1); end; +function TWebsiteModules.ModuleAvailable(const Website: String; + var OutIndex: Integer): Boolean; +begin + OutIndex := LocateModule(Website); + Result := OutIndex > -1; +end; + function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; const ModuleIndex: Integer): Integer; begin From 2551ffb68afdef50e321a9ebbb5b0636c2e0227f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 20:01:51 +0800 Subject: [PATCH 0193/2794] baseunit, get prop from websitemodules too --- baseunits/uBaseUnit.pas | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5e057f01a..e216e1c4a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -980,7 +980,7 @@ procedure fmdHibernate; implementation uses - {$IFDEF DOWNLOADER}frmMain;{$ENDIF} + {$IFDEF DOWNLOADER}frmMain, WebsiteModules;{$ENDIF} {$IFDEF WINDOWS} // thanks Leledumbo for the code @@ -1257,7 +1257,15 @@ function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): end; function SitesWithSortedList(const website : String) : Boolean; +var + i: Integer; begin + if Modules.ModuleAvailable(website, i) then + begin + Result := Modules.Module(i).SortedList; + Exit; + end; + Result := SitesIsWPManga(website); if not Result then Result := SitesMemberOf(website, [ From 7252f91705beaa3f4741f617dca53e0585ddf225 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 20:08:10 +0800 Subject: [PATCH 0194/2794] websitemodules, minor changes --- baseunits/WebsiteModules.pas | 16 +++++++++++++--- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.pas | 10 +++++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 57346c3f5..31fd6f8d9 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -38,7 +38,7 @@ TModuleContainer = class; TModuleContainer = class public Website, RootURL: String; - SortedList, InformationAvailable: Boolean; + SortedList, InformationAvailable, FavoriteAvailable: Boolean; OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; OnGetNameAndLink: TOnGetNameAndLink; OnGetInfo: TOnGetInfo; @@ -53,6 +53,9 @@ TWebsiteModules = class(TObject) private FCSModules: TRTLCriticalSection; FModuleList: TFPList; + protected + function GetModule(const Index: Integer): TModuleContainer; + function GetCount: Integer; public constructor Create; destructor Destroy; override; @@ -100,7 +103,8 @@ TWebsiteModules = class(TObject) procedure LockModules; procedure UnlockModules; - function Module(const Index: Integer): TModuleContainer; + property Module[const Index: Integer]: TModuleContainer read GetModule; + property Count: Integer read GetCount; end; var @@ -119,6 +123,7 @@ constructor TModuleContainer.Create; begin SortedList := False; InformationAvailable := True; + FavoriteAvailable := True; end; { TWebsiteModules } @@ -330,13 +335,18 @@ procedure TWebsiteModules.UnlockModules; LeaveCriticalsection(FCSModules); end; -function TWebsiteModules.Module(const Index: Integer): TModuleContainer; +function TWebsiteModules.GetModule(const Index: Integer): TModuleContainer; begin if (Index < 0) or (Index >= FModuleList.Count) then Exit(nil); Result := TModuleContainer(FModuleList[Index]); end; +function TWebsiteModules.GetCount: Integer; +begin + Result := FModuleList.Count; +end; + procedure doInitialize; begin if Modules = nil then diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e216e1c4a..531f68b24 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1262,7 +1262,7 @@ function SitesWithSortedList(const website : String) : Boolean; begin if Modules.ModuleAvailable(website, i) then begin - Result := Modules.Module(i).SortedList; + Result := Modules.Module[i].SortedList; Exit; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fbb41c90a..e38b2cf01 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1155,7 +1155,7 @@ procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); begin i := Modules.LocateModule(DownloadInfo.Website); if i > -1 then - edURL.Text := FillHost(Modules.Module(i).RootURL, DownloadInfo.Link) + edURL.Text := FillHost(Modules.Module[i].RootURL, DownloadInfo.Link) else edURL.Text := FillMangaSiteHost(DownloadInfo.Website, DownloadInfo.Link); btURLClick(btURL); @@ -1391,7 +1391,7 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); begin i := Modules.LocateModule(website); if i > -1 then - edURL.Text := FillHost(Modules.Module(i).RootURL, link) + edURL.Text := FillHost(Modules.Module[i].RootURL, link) else edURL.Text := FillMangaSiteHost(website, link); end; @@ -1780,8 +1780,8 @@ procedure TMainForm.btURLClick(Sender: TObject); i := Modules.LocateModuleByHost(host); if i > -1 then begin - website := Modules.Module(i).Website; - edURL.Text := FillHost(Modules.Module(i).RootURL, link); + website := Modules.Module[i].Website; + edURL.Text := FillHost(Modules.Module[i].RootURL, link); end else begin @@ -2725,7 +2725,7 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); i := Modules.LocateModule(website); if i > -1 then - edURL.Text := FillHost(Modules.Module(i).RootURL, link) + edURL.Text := FillHost(Modules.Module[i].RootURL, link) else edURL.Text := FillMangaSiteHost(website, link); From b3f12f79ea9b92748b927da4609dea371ae6cbce Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 20:13:04 +0800 Subject: [PATCH 0195/2794] baseunits, get prop from websitemodules --- baseunits/uBaseUnit.pas | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 531f68b24..a721dec28 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1245,7 +1245,7 @@ function GetMangaDatabaseURL(const Name: String): String; function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; var - i: Cardinal; + i: Integer; begin Result := False; for i := Low(MangaSiteIDs) to High(MangaSiteIDs) do @@ -1258,14 +1258,13 @@ function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): function SitesWithSortedList(const website : String) : Boolean; var - i: Integer; + i: Integer = -1; begin if Modules.ModuleAvailable(website, i) then begin Result := Modules.Module[i].SortedList; Exit; end; - Result := SitesIsWPManga(website); if not Result then Result := SitesMemberOf(website, [ @@ -1299,7 +1298,14 @@ function SitesWithSortedList(const website : String) : Boolean; end; function SitesWithoutFavorites(const website : String) : Boolean; +var + i: Integer = -1; begin + if Modules.ModuleAvailable(website, i) then + begin + Result := not Modules.Module[i].FavoriteAvailable; + Exit; + end; Result := False; Result := SitesMemberOf(website, [ EHENTAI_ID, @@ -1318,7 +1324,14 @@ function SitesWithoutFavorites(const website : String) : Boolean; end; function SitesWithoutInformation(const website: String): Boolean; +var + i: Integer = -1; begin + if Modules.ModuleAvailable(website, i) then + begin + Result := not Modules.Module[i].InformationAvailable; + Exit; + end; Result := False; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, From bd6ed5f1198e610c50167c10b9f58685f3a5a9a1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 20:16:10 +0800 Subject: [PATCH 0196/2794] updatethread, decrease checkcommit limit --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 9699ea36f..27f370d3b 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -216,7 +216,7 @@ procedure TUpdateMangaThread.Execute; try Info.AddInfoToData(manager.names[workPtr], manager.links[workPtr], manager.mainDataProcess); - manager.CheckCommit; + manager.CheckCommit(16); finally manager.CS_AddInfoToData.Release; end; From d50ef1f6449e228d414f15d584503e6b53d9919b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 22:42:18 +0800 Subject: [PATCH 0197/2794] mainform, use separate thread to open database --- mangadownloader/forms/frmMain.lfm | 2 +- mangadownloader/forms/frmMain.pas | 135 ++++++++++++++++++++++++------ 2 files changed, 112 insertions(+), 25 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index df674f972..f67db89e3 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3103,7 +3103,6 @@ object MainForm: TMainForm ParentFont = False end object vtMangaList: TVirtualStringTree - Cursor = crHourGlass Left = 2 Height = 383 Top = 92 @@ -3133,6 +3132,7 @@ object MainForm: TMainForm OnColumnDblClick = vtMangaListColumnDblClick OnDragAllowed = vtMangaListDragAllowed OnDragOver = vtMangaListDragOver + OnGetCursor = vtMangaListGetCursor OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e38b2cf01..c3571e374 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -503,6 +503,8 @@ TMainForm = class(TForm) procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure vtMangaListGetCursor(Sender: TBaseVirtualTree; + var ACursor: TCursor); procedure vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -573,7 +575,6 @@ TMainForm = class(TForm) procedure CloseNow(WaitFor: Boolean = True); - procedure CheckForTopPanel; // en: Too lazy to add it one by one procedure InitCheckboxes; @@ -631,11 +632,28 @@ TMainForm = class(TForm) // exit counter function ShowExitCounter: Boolean; + // open db with thread + procedure OpenDataDB(const AWebsite: String); + // exception handle procedure ExceptionHandler(Sender: TObject; E: Exception); { public declarations } end; + { TOpenDBThread } + + TOpenDBThread = class(TThread) + private + FWebsite: String; + protected + procedure SyncOpenStart; + procedure SyncOpenFinish; + procedure Execute; override; + public + constructor Create(const AWebsite: String); + destructor Destroy; override; + end; + var //Instance FMDInstance: TSimpleIPCServer; @@ -713,6 +731,79 @@ implementation frmImportFavorites, frmShutdownCounter, WebsiteModules, RegExpr, Clipbrd, LazFileUtils, LazUTF8; +var + // thread to open db + OpenDBThread: TOpenDBThread; + +procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); +var + i: Integer; +begin + if ParentControl = nil then Exit; + ParentControl.Cursor := Cur; + if ParentControl.ControlCount > 0 then + for i := 0 to ParentControl.ControlCount - 1 do + ParentControl.Controls[i].Cursor := Cur; +end; + +{ TOpenDBThread } + +procedure TOpenDBThread.SyncOpenStart; +begin + with MainForm do + begin + ChangeAllCursor(tsMangaList, crHourGlass); + lbMode.Caption := RS_Loading; + tsMangaList.Enabled := False; + vtMangaList.Clear; + end; +end; + +procedure TOpenDBThread.SyncOpenFinish; +begin + with MainForm do + begin + currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; + LastSearchStr := upcase(edSearch.Text); + LastSearchWeb := currentWebsite; + vtMangaList.RootNodeCount := dataProcess.RecordCount; + tsMangaList.Enabled := True; + if dataProcess.Filtered then + lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + else + lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); + ChangeAllCursor(tsMangaList, crDefault); + end; +end; + +procedure TOpenDBThread.Execute; +begin + if (FWebsite <> '') and (MainForm.dataProcess <> nil) then + begin + Synchronize(@SyncOpenStart); + if MainForm.dataProcess <> nil then + begin + MainForm.dataProcess.Open(FWebsite); + if MainForm.edSearch.Text <> '' then + MainForm.dataProcess.Search(MainForm.edSearch.Text); + end; + Synchronize(@SyncOpenFinish); + end; +end; + +constructor TOpenDBThread.Create(const AWebsite: String); +begin + inherited Create(False); + FreeOnTerminate := True; + FWebsite := AWebsite; +end; + +destructor TOpenDBThread.Destroy; +begin + OpenDBThread := nil; + inherited Destroy; +end; + { TMainForm } procedure TMainForm.FormCreate(Sender: TObject); @@ -801,7 +892,6 @@ procedure TMainForm.FormCreate(Sender: TObject); pcMain.ActivePage := tsDownload; - CheckForTopPanel; DLManager.CheckAndActiveTaskAtStartup; TrayIcon.Show; @@ -937,6 +1027,8 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(SilentThreadManager); FreeAndNil(FavoriteManager); FreeAndNil(dataProcess); + if Assigned(OpenDBThread) then + OpenDBThread.WaitFor; FreeAndNil(gifWaiting); FreeAndNil(mangaCover); @@ -1017,6 +1109,12 @@ function TMainForm.ShowExitCounter: Boolean; IsDlgCounter := False; end; +procedure TMainForm.OpenDataDB(const AWebsite: String); +begin + if OpenDBThread = nil then + OpenDBThread := TOpenDBThread.Create(AWebsite); +end; + procedure TMainForm.itMonitorTimer(Sender: TObject); begin itMonitor.Enabled := False; @@ -1407,11 +1505,6 @@ procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); vtMangaList.Repaint; end; -procedure TMainForm.CheckForTopPanel; -begin - -end; - procedure TMainForm.LoadAbout; var fs: TFileStream; @@ -1901,28 +1994,16 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); begin if cbSelectManga.ItemIndex < 0 then Exit; - if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then begin - Screen.Cursor := crHourGlass; - try if dataProcess = nil then dataProcess := TDBDataProcess.Create; - vtMangaList.Clear; - lbMode.Caption := Format(RS_ModeAll, [0]); - if not dataProcess.Open( - cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]) then + if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then + begin + OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); + end + else RunGetList; - vtMangaList.RootNodeCount := dataProcess.RecordCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); - currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; - dataProcess.website := cbSelectManga.Items[cbSelectManga.ItemIndex]; - CheckForTopPanel; - LastSearchStr := ''; - edSearchChange(cbSelectManga); - finally - Screen.Cursor := crDefault; - end; end; end; @@ -4107,6 +4188,12 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; end; end; +procedure TMainForm.vtMangaListGetCursor(Sender: TBaseVirtualTree; + var ACursor: TCursor); +begin + ACursor := Sender.Cursor; +end; + procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); From 110361c3f2ee157c05f70257e41f1f65a79aeaa6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 22:58:34 +0800 Subject: [PATCH 0198/2794] mainform, clear list before open another --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c3571e374..bf762f881 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1998,6 +1998,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); begin if dataProcess = nil then dataProcess := TDBDataProcess.Create; + vtMangaList.Clear; if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then begin OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); From 9da4487d1f4188d08165798e14da90451ed0a896 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 23:04:51 +0800 Subject: [PATCH 0199/2794] update db, refreshlist use opendatadb with separate thread --- baseunits/uUpdateDBThread.pas | 5 +---- baseunits/uUpdateThread.pas | 28 ++++++++++------------------ 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index ce4cce5be..1ec11a18b 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -47,10 +47,7 @@ procedure TUpdateDBThread.MainThreadRefreshList; MainForm.vtMangaList.Clear; MainForm.dataProcess.Close; ExtractFile; - MainForm.dataProcess.Open(websiteName); - MainForm.vtMangaList.RootNodeCount := MainForm.dataProcess.RecordCount; - MainForm.lbMode.Caption := - Format(RS_ModeAll, [MainForm.dataProcess.RecordCount]); + MainForm.OpenDataDB(websiteName); end else begin diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 27f370d3b..236e69700 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -360,24 +360,16 @@ procedure TUpdateMangaManagerThread.RefreshList; begin if dataProcess.WebsiteLoaded(website) then begin - Screen.Cursor := crHourGlass; - try - edSearch.Clear; - vtMangaList.Clear; - if dataProcess = nil then - dataProcess := TDBDataProcess.Create - else - dataProcess.Close; - if isDownloadFromServer then - ExtractFile - else - OverwriteDBDataProcess(website, twebsite); - dataProcess.Open(website); - vtMangaList.RootNodeCount := dataProcess.RecordCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); - finally - Screen.Cursor := crDefault; - end; + vtMangaList.Clear; + if dataProcess = nil then + dataProcess := TDBDataProcess.Create + else + dataProcess.Close; + if isDownloadFromServer then + ExtractFile + else + OverwriteDBDataProcess(website, twebsite); + OpenDataDB(website); end else begin From c81d1260800d33919032869d66c2cf9b225b7f17 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 23:05:18 +0800 Subject: [PATCH 0200/2794] udata, change function name --- baseunits/uData.pas | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d89a4832f..9f1859ec9 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -214,7 +214,7 @@ TMangaInformation = class(TObject) function DBDataFilePath(const AWebsite: string): string; procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); - function DBDataProcessExist(const AWebsite: string): Boolean; + function DataFileExist(const AWebsite: string): Boolean; procedure CopyDBDataProcess(const AWebsite, NWebsite: string); function DeleteDBDataProcess(const AWebsite: string): Boolean; procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); @@ -323,16 +323,17 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); end; end; -function DBDataProcessExist(const AWebsite: string): Boolean; +function DataFileExist(const AWebsite: string): Boolean; begin if AWebsite = '' then Exit(False); - Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DATA_EXT) or + FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; procedure CopyDBDataProcess(const AWebsite, NWebsite: string); begin if NWebsite = '' then Exit; - if DBDataProcessExist(AWebsite) then + if DataFileExist(AWebsite) then begin try CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, From 20a3e40d0ea4ef40d7162081f8c53e08fc81e0db Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 23:16:57 +0800 Subject: [PATCH 0201/2794] mainform, fix opendbthread --- mangadownloader/forms/frmMain.pas | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bf762f881..f7e0120ce 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -646,6 +646,7 @@ TOpenDBThread = class(TThread) private FWebsite: String; protected + procedure SetControlEnabled(const Value: Boolean); procedure SyncOpenStart; procedure SyncOpenFinish; procedure Execute; override; @@ -748,13 +749,25 @@ procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); { TOpenDBThread } +procedure TOpenDBThread.SetControlEnabled(const Value: Boolean); +begin + with MainForm do + begin + cbSelectManga.Enabled := Value; + btUpdateList.Enabled := Value; + edSearch.Enabled := Value; + btSearchClear.Enabled := Value; + btRemoveFilter.Enabled := Value; + end; +end; + procedure TOpenDBThread.SyncOpenStart; begin - with MainForm do + with MainForm do begin ChangeAllCursor(tsMangaList, crHourGlass); + SetControlEnabled(False); lbMode.Caption := RS_Loading; - tsMangaList.Enabled := False; vtMangaList.Clear; end; end; @@ -767,11 +780,11 @@ procedure TOpenDBThread.SyncOpenFinish; LastSearchStr := upcase(edSearch.Text); LastSearchWeb := currentWebsite; vtMangaList.RootNodeCount := dataProcess.RecordCount; - tsMangaList.Enabled := True; if dataProcess.Filtered then lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) else lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); + SetControlEnabled(True); ChangeAllCursor(tsMangaList, crDefault); end; end; From c82d840e4d2f60d068f1740df55f7be532f5bb50 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 23:22:31 +0800 Subject: [PATCH 0202/2794] mainform, minor changes --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f7e0120ce..f4b7642fa 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -806,9 +806,9 @@ procedure TOpenDBThread.Execute; constructor TOpenDBThread.Create(const AWebsite: String); begin - inherited Create(False); FreeOnTerminate := True; FWebsite := AWebsite; + inherited Create(False); end; destructor TOpenDBThread.Destroy; From 0fb29671f7f16356a411fb54c04505bbff5ff96c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 23:27:21 +0800 Subject: [PATCH 0203/2794] mainform, load db at startup with separate thread too --- mangadownloader/forms/frmMain.pas | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f4b7642fa..4d7c8364b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1200,20 +1200,8 @@ procedure TMainForm.itStartupTimer(Sender: TObject); itStartup.Enabled := False; if not isStartup then begin - Screen.Cursor := crHourGlass; - isStartup := True; - try - if cbSelectManga.ItemIndex > -1 then - begin - vtMangaList.Clear; - dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); - end; - vtMangaList.RootNodeCount := dataProcess.RecordCount; - lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); - dataProcess.Refresh; - finally - Screen.Cursor := crDefault; - end; + if cbSelectManga.ItemIndex > -1 then + OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if cbOptionAutoCheckUpdate.Checked then SubThread.CheckUpdate := True; SubThread.Start; From 3af7c1b261be00844819ac7e2ee89d389e9e943d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 19 Jul 2015 23:57:19 +0800 Subject: [PATCH 0204/2794] mainform, create another thread for search db --- mangadownloader/forms/frmMain.pas | 120 +++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 4d7c8364b..ac4b9c8bb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -635,6 +635,9 @@ TMainForm = class(TForm) // open db with thread procedure OpenDataDB(const AWebsite: String); + // search db with thread + procedure SearchDataDB(const ATitle: String); + // exception handle procedure ExceptionHandler(Sender: TObject; E: Exception); { public declarations } @@ -655,6 +658,22 @@ TOpenDBThread = class(TThread) destructor Destroy; override; end; + { TSearchDBThread } + + TSearchDBThread = class(TThread) + private + FSearchStr: String; + FNewSearch: Boolean; + protected + procedure SyncBeforeSearch; + procedure SyncAfterSearch; + procedure Execute; override; + public + constructor Create(const ASearchStr: String); + destructor Destroy; override; + procedure NewSearch(const ASearchStr: String); + end; + var //Instance FMDInstance: TSimpleIPCServer; @@ -733,9 +752,12 @@ implementation LazFileUtils, LazUTF8; var - // thread to open db + // thread for open db OpenDBThread: TOpenDBThread; + // thread for search db + SearchDBThread: TSearchDBThread; + procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); var i: Integer; @@ -747,6 +769,69 @@ procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); ParentControl.Controls[i].Cursor := Cur; end; +{ TSearchDBThread } + +procedure TSearchDBThread.SyncBeforeSearch; +begin + with MainForm do + begin + vtMangaList.Clear; + lbMode.Caption := RS_Loading; + end; +end; + +procedure TSearchDBThread.SyncAfterSearch; +begin + with MainForm do + begin + vtMangaList.RootNodeCount := dataProcess.RecordCount; + if dataProcess.Filtered then + lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + else + lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); + LastSearchWeb := dataProcess.Website; + LastSearchStr := UpCase(FSearchStr); + end; +end; + +procedure TSearchDBThread.Execute; +begin + if MainForm.dataProcess <> nil then + begin + Synchronize(@SyncBeforeSearch); + while FNewSearch do + begin + FNewSearch := False; + if MainForm.dataProcess <> nil then + MainForm.dataProcess.Search(FSearchStr); + end; + Synchronize(@SyncAfterSearch); + end; +end; + +constructor TSearchDBThread.Create(const ASearchStr: String); +begin + FreeOnTerminate := True; + FSearchStr := ASearchStr; + FNewSearch := True; + inherited Create(False); +end; + +destructor TSearchDBThread.Destroy; +begin + SearchDBThread := nil; + inherited Destroy; +end; + +procedure TSearchDBThread.NewSearch(const ASearchStr: String); +begin + if ASearchStr <> FSearchStr then + begin + FSearchStr := ASearchStr; + FNewSearch := True; + end; +end; + { TOpenDBThread } procedure TOpenDBThread.SetControlEnabled(const Value: Boolean); @@ -980,6 +1065,10 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow(WaitFor: Boolean); begin + if Assigned(OpenDBThread) then + OpenDBThread.WaitFor; + if Assigned(SearchDBThread) then + SearchDBThread.WaitFor; if Assigned(FormDropTarget) then FormDropTarget.Close; tmBackup.Enabled := False; @@ -1040,8 +1129,6 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(SilentThreadManager); FreeAndNil(FavoriteManager); FreeAndNil(dataProcess); - if Assigned(OpenDBThread) then - OpenDBThread.WaitFor; FreeAndNil(gifWaiting); FreeAndNil(mangaCover); @@ -1128,6 +1215,16 @@ procedure TMainForm.OpenDataDB(const AWebsite: String); OpenDBThread := TOpenDBThread.Create(AWebsite); end; +procedure TMainForm.SearchDataDB(const ATitle: String); +begin + if SearchDBThread = nil then + SearchDBThread := TSearchDBThread.Create(ATitle) + else + begin + SearchDBThread.NewSearch(ATitle); + end; +end; + procedure TMainForm.itMonitorTimer(Sender: TObject); begin itMonitor.Enabled := False; @@ -4826,16 +4923,15 @@ procedure TMainForm.edSearchChange(Sender: TObject); if (upcase(edSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb) then Exit; - LastSearchWeb := currentWebsite; - LastSearchStr := UpCase(edSearch.Text); + SearchDataDB(edSearch.Text); - vtMangaList.Clear; - dataProcess.Search(edSearch.Text); - vtMangaList.RootNodeCount := dataProcess.RecordCount; - if dataProcess.Filtered then - lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) - else - lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); + //vtMangaList.Clear; + //dataProcess.Search(edSearch.Text); + //vtMangaList.RootNodeCount := dataProcess.RecordCount; + //if dataProcess.Filtered then + // lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + //else + // lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); end; procedure TMainForm.edSearchKeyDown(Sender: TObject; var Key: Word; From 7bcc2e00621d3e16b50130427113b137d08983c1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 00:00:12 +0800 Subject: [PATCH 0205/2794] mainform, add resourcestring for search --- mangadownloader/forms/frmMain.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ac4b9c8bb..af38e3876 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -742,6 +742,7 @@ TSearchDBThread = class(TThread) RS_InfoStatus = 'Status:'; RS_InfoSummary = 'Summary:'; RS_FMDAlreadyRunning = 'Free Manga Downloader already running!'; + RS_Searching = 'Searching...'; implementation @@ -776,7 +777,7 @@ procedure TSearchDBThread.SyncBeforeSearch; with MainForm do begin vtMangaList.Clear; - lbMode.Caption := RS_Loading; + lbMode.Caption := RS_Searching; end; end; From 00de25c08b276570c723a1d77a56c8c704bb1721 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 00:02:50 +0800 Subject: [PATCH 0206/2794] updates translations --- mangadownloader/languages/fmd.en.po | 4 ++++ mangadownloader/languages/fmd.id_ID.po | 4 ++++ mangadownloader/languages/fmd.po | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 24aa13ea6..6deb0ffeb 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -218,6 +218,10 @@ msgstr "" "Shutdown\n" "Hibernate\n" +#: frmmain.rs_searching +msgid "Searching..." +msgstr "Searching..." + #: frmmain.rs_selected msgid "Selected: %d" msgstr "Selected: %d" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 33a43d28a..8f538303e 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -213,6 +213,10 @@ msgstr "" "Matikan komputer\n" "Tidurkan komputer\n" +#: frmmain.rs_searching +msgid "Searching..." +msgstr "Mencari..." + #: frmmain.rs_selected msgid "Selected: %d" msgstr "Dipilih: %d" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 1003d5d1b..279f21d32 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -185,6 +185,10 @@ msgid "" "Hibernate\n" msgstr "" +#: frmmain.rs_searching +msgid "Searching..." +msgstr "" + #: frmmain.rs_selected msgid "Selected: %d" msgstr "" From 3efa63aa621982aba493b795442afbfc2827c98e Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 00:13:38 +0800 Subject: [PATCH 0207/2794] mainform, change search info --- mangadownloader/forms/frmMain.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index af38e3876..a0bdf9846 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -742,7 +742,7 @@ TSearchDBThread = class(TThread) RS_InfoStatus = 'Status:'; RS_InfoSummary = 'Summary:'; RS_FMDAlreadyRunning = 'Free Manga Downloader already running!'; - RS_Searching = 'Searching...'; + RS_ModeSearching = 'Mode: Searching...'; implementation @@ -776,8 +776,9 @@ procedure TSearchDBThread.SyncBeforeSearch; begin with MainForm do begin + vtMangaList.Cursor := crHourGlass; vtMangaList.Clear; - lbMode.Caption := RS_Searching; + lbMode.Caption := RS_ModeSearching; end; end; @@ -792,6 +793,7 @@ procedure TSearchDBThread.SyncAfterSearch; lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); LastSearchWeb := dataProcess.Website; LastSearchStr := UpCase(FSearchStr); + vtMangaList.Cursor := crDefault; end; end; From 08f41e469a7afa8246e10a3e54e74c905790126a Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 00:14:03 +0800 Subject: [PATCH 0208/2794] update translations --- mangadownloader/languages/fmd.en.po | 12 +++++++----- mangadownloader/languages/fmd.id_ID.po | 11 ++++++----- mangadownloader/languages/fmd.po | 9 +++++---- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6deb0ffeb..9a223145b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_US\n" -"X-Generator: Poedit 1.8.1\n" +"X-Generator: Poedit 1.8.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: frmimportfavorites.rs_importcompleted @@ -198,6 +198,12 @@ msgstr "Mode: Show all (%d)" msgid "Mode: Filtered (%d)" msgstr "Mode: Filtered (%d)" +#: frmmain.rs_modesearching +#| msgid "Searching..." +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Mode: Searching..." + #: frmmain.rs_onemonth msgid "One month" msgstr "One month" @@ -218,10 +224,6 @@ msgstr "" "Shutdown\n" "Hibernate\n" -#: frmmain.rs_searching -msgid "Searching..." -msgstr "Searching..." - #: frmmain.rs_selected msgid "Selected: %d" msgstr "Selected: %d" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 8f538303e..738f46b76 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.8.1\n" +"X-Generator: Poedit 1.8.2\n" "Plural-Forms: nplurals=1; plural=0;\n" #: frmimportfavorites.rs_importcompleted @@ -193,6 +193,11 @@ msgstr "Mode: Tampilkan semua (%d)" msgid "Mode: Filtered (%d)" msgstr "Mode: Disaring (%d)" +#: frmmain.rs_modesearching +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Mode: Mencari..." + #: frmmain.rs_onemonth msgid "One month" msgstr "Satu bulan" @@ -213,10 +218,6 @@ msgstr "" "Matikan komputer\n" "Tidurkan komputer\n" -#: frmmain.rs_searching -msgid "Searching..." -msgstr "Mencari..." - #: frmmain.rs_selected msgid "Selected: %d" msgstr "Dipilih: %d" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 279f21d32..e5df927e4 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -169,6 +169,11 @@ msgstr "" msgid "Mode: Filtered (%d)" msgstr "" +#: frmmain.rs_modesearching +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "" + #: frmmain.rs_onemonth msgid "One month" msgstr "" @@ -185,10 +190,6 @@ msgid "" "Hibernate\n" msgstr "" -#: frmmain.rs_searching -msgid "Searching..." -msgstr "" - #: frmmain.rs_selected msgid "Selected: %d" msgstr "" From a7c418f7ea6ad52d4adb1f75184ac7b2055a22b3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 00:34:45 +0800 Subject: [PATCH 0209/2794] mainform, opendbthread, searchdbthread, use terminated flag to skip synchronize to avoid blocking mainthread on close --- mangadownloader/forms/frmMain.pas | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a0bdf9846..55d45ed0a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -805,10 +805,10 @@ procedure TSearchDBThread.Execute; while FNewSearch do begin FNewSearch := False; - if MainForm.dataProcess <> nil then - MainForm.dataProcess.Search(FSearchStr); + MainForm.dataProcess.Search(FSearchStr); end; - Synchronize(@SyncAfterSearch); + if not Terminated then + Synchronize(@SyncAfterSearch); end; end; @@ -888,6 +888,7 @@ procedure TOpenDBThread.Execute; if MainForm.edSearch.Text <> '' then MainForm.dataProcess.Search(MainForm.edSearch.Text); end; + if not Terminated then Synchronize(@SyncOpenFinish); end; end; @@ -1068,10 +1069,16 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow(WaitFor: Boolean); begin - if Assigned(OpenDBThread) then - OpenDBThread.WaitFor; if Assigned(SearchDBThread) then + begin + SearchDBThread.Terminate; SearchDBThread.WaitFor; + end; + if Assigned(OpenDBThread) then + begin + OpenDBThread.Terminate; + OpenDBThread.WaitFor; + end; if Assigned(FormDropTarget) then FormDropTarget.Close; tmBackup.Enabled := False; From 5ad08c6e073551f7696e8aae6a141cabafa82b1d Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 01:21:45 +0800 Subject: [PATCH 0210/2794] update threads, only save if links>0 --- baseunits/uUpdateThread.pas | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 236e69700..980a6325b 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -699,28 +699,25 @@ procedure TUpdateMangaManagerThread.Execute; end; WaitForThreads; mainDataProcess.Commit; - end; - mainDataProcess.Refresh; - names.Clear; - links.Clear; + names.Clear; + links.Clear; - if (not Terminated) or (not SitesWithSortedList(website)) then - begin - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; - Synchronize(MainThreadShowGetting); - mainDataProcess.CloseTable; - mainDataProcess.Sort; - mainDataProcess.Close; - Synchronize(RefreshList); - end - else - begin - mainDataProcess.Close; - DeleteDBDataProcess(twebsite); + if (not Terminated) or (not SitesWithSortedList(website)) then + begin + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; + Synchronize(MainThreadShowGetting); + mainDataProcess.CloseTable; + mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); + end; end; + mainDataProcess.Close; + DeleteDBDataProcess(twebsite); + if Terminated then Break; websites[websitePtr - 1] := From 6d60094ddfa67432ebeafc1282e35f1833eafb57 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 01:25:35 +0800 Subject: [PATCH 0211/2794] downloadmanager, change some var from cardinal to integer --- baseunits/includes/MangaReader/image_url.inc | 20 ++++++++++---------- baseunits/uDownloadsManager.pas | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/baseunits/includes/MangaReader/image_url.inc b/baseunits/includes/MangaReader/image_url.inc index 9d2b0f208..394f584b3 100644 --- a/baseunits/includes/MangaReader/image_url.inc +++ b/baseunits/includes/MangaReader/image_url.inc @@ -7,24 +7,24 @@ procedure BreakURL; var isSlashed: Boolean = False; - i, oldI: Cardinal; + j, oldI: Integer; begin if Pos('.html', URL) = 0 then begin realURL := URL + '/' + IntToStr(workCounter + 1); Exit; end; - i := 2; + j := 2; realURL := '/'; - while i <= Length(URL) do + while j <= Length(URL) do begin - if (not isSlashed) and (URL[i] = '/') then + if (not isSlashed) and (URL[j] = '/') then begin isSlashed := True; - oldI := i; - for i := i - 1 downto 1 do + oldI := j; + for j := j - 1 downto 1 do begin - if URL[i] <> '-' then + if URL[j] <> '-' then begin SetLength(realURL, Length(realURL) - 1); end @@ -34,13 +34,13 @@ Break; end; end; - i := oldI; + j := oldI; // realURL:= realURL + '/'; end else begin - realURL := realURL + URL[i]; - Inc(i); + realURL := realURL + URL[j]; + Inc(j); end; end; end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 88890f727..ab7eb466f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -33,7 +33,7 @@ TDownloadThread = class(TFMDThread) checkStyle: TFlagType; ModuleId: Integer; public - workCounter: Cardinal; + workCounter: Integer; FSortColumn: Cardinal; FMessage, FAnotherURL: String; FHTTP: THTTPSend; @@ -74,7 +74,7 @@ TDownloadThread = class(TFMDThread) property SortColumn: Cardinal read FSortColumn write FSortColumn; property AnotherURL: String read FAnotherURL write FAnotherURL; - property GetworkCounter: Cardinal read workCounter; + property GetworkCounter: Integer read workCounter; end; { TTaskThread } @@ -2131,8 +2131,8 @@ function TDownloadManager.AddTask : Integer; procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; SenderThread : TThread); var - EHENTAI_Count: Cardinal = 0; - Count: Cardinal = 0; + EHENTAI_Count: Integer = 0; + Count: Integer = 0; i: Integer; procedure ShowExitCounter; From 4460466ce31839dfb8d031c6f5129a1b4b6461e7 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 01:40:09 +0800 Subject: [PATCH 0212/2794] updatethread, only save if there is getinfo executed --- baseunits/uUpdateThread.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 980a6325b..08ad62810 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -672,10 +672,12 @@ procedure TUpdateMangaManagerThread.Execute; //get manga info if links.Count > 0 then begin + workPtr := 0; FCommitCount := 0; if (SitesWithoutInformation(website)) or OptionUpdateListNoMangaInfo then begin + Inc(workPtr); for k := 0 to links.Count - 1 do begin mainDataProcess.AddData( @@ -693,17 +695,14 @@ procedure TUpdateMangaManagerThread.Execute; end; end else - begin - workPtr := 0; GetInfo(links.Count, CS_INFO); - end; WaitForThreads; mainDataProcess.Commit; names.Clear; links.Clear; - if (not Terminated) or (not SitesWithSortedList(website)) then + if (workPtr > 0) and ((not Terminated) or (not SitesWithSortedList(website))) then begin FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; From deb3589c601377d674550bcb669c6279d64ebae0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 01:41:03 +0800 Subject: [PATCH 0213/2794] updatethreads, increase checkcommit limit to 5000 --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 08ad62810..16908f685 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -691,7 +691,7 @@ procedure TUpdateMangaManagerThread.Execute; 0, Now ); - CheckCommit(2000); + CheckCommit(5000); end; end else From ff2e681ab1596eca79d846ffdfa90af1670938c9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 02:00:42 +0800 Subject: [PATCH 0214/2794] mainform, repaint list after db change --- mangadownloader/forms/frmMain.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 55d45ed0a..a9294fbf7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -787,6 +787,7 @@ procedure TSearchDBThread.SyncAfterSearch; with MainForm do begin vtMangaList.RootNodeCount := dataProcess.RecordCount; + vtMangaList.Repaint; if dataProcess.Filtered then lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) else @@ -868,6 +869,7 @@ procedure TOpenDBThread.SyncOpenFinish; LastSearchStr := upcase(edSearch.Text); LastSearchWeb := currentWebsite; vtMangaList.RootNodeCount := dataProcess.RecordCount; + vtMangaList.Repaint; if dataProcess.Filtered then lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) else From dc00c9eed0c760c0e47671e3b50e9a121e0c0434 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 04:53:32 +0800 Subject: [PATCH 0215/2794] mainform, minor changes --- mangadownloader/forms/frmMain.pas | 39 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a9294fbf7..ddc25fff7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -532,7 +532,7 @@ TMainForm = class(TForm) procedure FMDInstanceReceiveMsg(Sender: TObject); procedure ClearChapterListState; public - ulTotalPtr, ulWorkPtr: Cardinal; + ulTotalPtr, ulWorkPtr: Integer; optionMangaSiteSelectionNodes: array of PVirtualNode; LastSearchStr: String; LastSearchWeb: String; @@ -759,6 +759,9 @@ implementation // thread for search db SearchDBThread: TSearchDBThread; + // ... + UpdateStatusTextStyle: TTextStyle; + procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); var i: Integer; @@ -1053,6 +1056,22 @@ procedure TMainForm.FormCreate(Sender: TObject); vtFavorites.Repaint; end; LoadLanguage; + + //textstyle for updatestatusbar + with UpdateStatusTextStyle do + begin + Alignment := taLeftJustify; + Layout := tlCenter; + SingleLine := True; + Clipping := False; + ExpandTabs := False; + ShowPrefix := False; + Wordbreak := False; + Opaque := True; + SystemFont := False; + RightToLeft := False; + EndEllipsis := True; + end; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -3345,7 +3364,6 @@ procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; var ClRect, TxtRect, BarRect, ProgressBarRect: TRect; Percents: double; - tStyle: TTextStyle; begin if Panel.Index = 0 then begin @@ -3395,23 +3413,8 @@ procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; //Brush.Color := RGB(233, 112, 24); Rectangle(ProgressBarRect); end; - //TTextStyle get messed up if all record not assigned? - with tStyle do - begin - Alignment := taLeftJustify; - Layout := tlCenter; - SingleLine := True; - Clipping := False; - ExpandTabs := False; - ShowPrefix := False; - Wordbreak := False; - Opaque := True; - SystemFont := False; - RightToLeft := False; - EndEllipsis := True; - end; Brush.Style := bsClear; - TextRect(txtRect, 5, 0, Panel.Text, tStyle); + TextRect(txtRect, 5, 0, Panel.Text, UpdateStatusTextStyle); end; end; end; From a0d02e99991a954a5939eda67d4faaade618d29e Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 04:56:34 +0800 Subject: [PATCH 0216/2794] mainform, fix list not updated --- mangadownloader/forms/frmMain.pas | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ddc25fff7..927ed2261 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -789,14 +789,15 @@ procedure TSearchDBThread.SyncAfterSearch; begin with MainForm do begin - vtMangaList.RootNodeCount := dataProcess.RecordCount; - vtMangaList.Repaint; if dataProcess.Filtered then - lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]) else - lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); LastSearchWeb := dataProcess.Website; LastSearchStr := UpCase(FSearchStr); + vtMangaList.BeginUpdate; + vtMangaList.RootNodeCount := dataProcess.RecordCount; + vtMangaList.EndUpdate; vtMangaList.Cursor := crDefault; end; end; @@ -871,13 +872,14 @@ procedure TOpenDBThread.SyncOpenFinish; currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; LastSearchStr := upcase(edSearch.Text); LastSearchWeb := currentWebsite; - vtMangaList.RootNodeCount := dataProcess.RecordCount; - vtMangaList.Repaint; if dataProcess.Filtered then - lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) + lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]) else - lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); SetControlEnabled(True); + vtMangaList.BeginUpdate; + vtMangaList.RootNodeCount := dataProcess.RecordCount; + vtMangaList.EndUpdate; ChangeAllCursor(tsMangaList, crDefault); end; end; From 49822c6d0eef6a6165b26db8913c961c3bb1c2c5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 04:58:27 +0800 Subject: [PATCH 0217/2794] mainform, hide remove duplicate local data checkbox Doesn't needed since db with primary key --- mangadownloader/forms/frmMain.lfm | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f67db89e3..b56d55a1e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2664,6 +2664,7 @@ object MainForm: TMainForm Caption = 'Remove duplicate local data when updating manga list' ParentFont = False TabOrder = 3 + Visible = False end end object tsDialogs: TTabSheet From 26577f41165f35cd43b4690462fd1615346c5b81 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 05:25:50 +0800 Subject: [PATCH 0218/2794] mainform, minor changes --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 927ed2261..8c0360f45 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2130,6 +2130,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); if dataProcess = nil then dataProcess := TDBDataProcess.Create; vtMangaList.Clear; + lbMode.Caption := Format(RS_ModeAll, [0]); if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then begin OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); From dab6991b2d547b9b6b8a037f77a578a4ebb181d4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 06:21:09 +0800 Subject: [PATCH 0219/2794] updatethread, show progress when removing duplicate --- baseunits/uUpdateThread.pas | 61 ++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 16908f685..b18a6183f 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -47,6 +47,7 @@ TUpdateMangaManagerThread = class(TFMDThread) procedure ConsoleReport; procedure SaveCurrentDatabase; {$ENDIF} + procedure MainThreadStatusRepaint; procedure MainThreadShowGetting; procedure MainThreadEndGetting; procedure MainThreadRemoveFilter; @@ -253,6 +254,11 @@ procedure TUpdateMangaThread.DoTerminate; { TUpdateMangaManagerThread } +procedure TUpdateMangaManagerThread.MainThreadStatusRepaint; +begin + MainForm.sbUpdateList.Repaint; +end; + procedure TUpdateMangaManagerThread.MainThreadShowGetting; begin if MainForm.sbUpdateList.Visible = False then @@ -486,19 +492,24 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; Inc(workPtr); s := RS_UpdatingList + Format(' [%d/%d] %s | [T:%d] [%d/%d]', [websitePtr, websites.Count, website, threads.Count, workPtr, limit]); - if cs = CS_DIRECTORY_COUNT then - if limit = 1 then - s := RS_UpdatingList + Format(' [%d/%d] ', [websitePtr, websites.Count]) + - website + ' | ' + RS_GettingDirectory + '...' - else - s := s + ' | ' + RS_GettingDirectory + '...'; - if cs = CS_DIRECTORY_PAGE then - s := s + ' | ' + RS_LookingForNewTitle + '...'; - if cs = CS_DIRECTORY_PAGE_2 then - s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; - if cs = CS_INFO then - s := Format('%s | %s "%s" "%s"', [s, RS_GettingInfo, names[workPtr - 1], - links[workPtr - 1]]); + + case cs of + CS_DIRECTORY_COUNT: + begin + if limit = 1 then + s := RS_UpdatingList + Format(' [%d/%d] ', [websitePtr, websites.Count]) + + website + ' | ' + RS_GettingDirectory + '...' + else + s := s + ' | ' + RS_GettingDirectory + '...'; + end; + CS_DIRECTORY_PAGE: + s := s + ' | ' + RS_LookingForNewTitle + '...'; + CS_DIRECTORY_PAGE_2: + s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; + CS_INFO: + s := Format('%s | %s "%s" "%s"', [s, RS_GettingInfo, names[workPtr - 1], + links[workPtr - 1]]); + end; FStatus := s; Synchronize(MainThreadShowGetting); finally @@ -536,7 +547,7 @@ procedure TUpdateMangaManagerThread.Execute; end; var - j, k: Integer; + c, j, k: Integer; del: Boolean; begin if websites.Count = 0 then @@ -619,14 +630,25 @@ procedure TUpdateMangaManagerThread.Execute; // remove duplicate if links.Count > 0 then begin + MainForm.ulTotalPtr := links.Count; + MainForm.ulWorkPtr := j; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromNewTitle + '...'; Synchronize(MainThreadShowGetting); + c := 0; j := 0; while j < (links.Count - 1) do begin if Terminated then Break; + Inc(c); + if c > 499 then + begin + c := 0; + MainForm.ulTotalPtr := links.Count; + MainForm.ulWorkPtr := j; + Synchronize(MainThreadStatusRepaint); + end; del := False; if (j + 1) < links.Count then for k := j + 1 to links.Count - 1 do @@ -650,14 +672,25 @@ procedure TUpdateMangaManagerThread.Execute; // remove duplicate found<>current database if links.Count > 0 then begin + MainForm.ulTotalPtr := links.Count; + MainForm.ulWorkPtr := j; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromCurrentData + '...'; Synchronize(MainThreadShowGetting); + c := 0; j := 0; while j < links.Count do begin if Terminated then Break; + Inc(c); + if c > 499 then + begin + c := 0; + MainForm.ulTotalPtr := links.Count; + MainForm.ulWorkPtr := j; + Synchronize(MainThreadStatusRepaint); + end; if mainDataProcess.LocateByLink(links[j]) then begin links.Delete(j); From 220e9e081e6bda9e2aca817200cb7e5052751952 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 13:25:12 +0800 Subject: [PATCH 0220/2794] baseunit, getpage, add default request header --- baseunits/uBaseUnit.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a721dec28..4c55b7425 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2742,6 +2742,9 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; end; HTTPHeader.Values['DNT'] := ' 1'; + HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; + HTTPHeader.Values['Accept-Charset'] := ' UTF-8'; + HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.Timeout := OptionConnectionTimeout; From 2581cf34ba4641e05c9b2eb510feeb82e1e54244 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 13:52:39 +0800 Subject: [PATCH 0221/2794] tdbdataprocess, fix and clean up --- baseunits/uData.pas | 335 ++++++++++++++++++++++++-------------------- 1 file changed, 184 insertions(+), 151 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9f1859ec9..797d0f9b6 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, - sqlite3backup, sqlite3dyn, sqldb, db, USimpleLogger, strutils, dateutils, + sqlite3backup, sqlite3dyn, sqldb, DB, USimpleLogger, strutils, dateutils, RegExpr, httpsend; type @@ -48,8 +48,8 @@ TDBDataProcess = class(TObject) procedure CreateTable; procedure VacuumTable; procedure GetRecordCount; - procedure AddSQLCond(const sqltext: string; useOR: Boolean = False); - procedure AddSQLSimpleFilter(const fieldname, value: string; + procedure AddSQLCond(const sqltext: String; useOR: Boolean = False); + procedure AddSQLSimpleFilter(const fieldname, Value: String; useNOT: Boolean = False; useOR: Boolean = False; useRegexp: Boolean = False); function GetConnected: Boolean; function InternalOpen(const FilePath: String = ''): Boolean; @@ -63,12 +63,14 @@ TDBDataProcess = class(TObject) function Connect(AWebsite: String): Boolean; function Open(AWebsite: String = ''): Boolean; - function OpenTable(const ATableName: String = ''; CheckRecordCount: Boolean = False): Boolean; + function OpenTable(const ATableName: String = ''; + CheckRecordCount: Boolean = False): Boolean; function TableExist(const ATableName: String): Boolean; function Search(ATitle: String): Boolean; function CanFilter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const {%H-}minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; + const {%H-}minusDay: Cardinal; + const haveAllChecked, searchNewManga: Boolean): Boolean; function Filter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; @@ -109,7 +111,7 @@ TDBDataProcess = class(TObject) TDataProcess = class(TObject) private function GetInfo(const index: Cardinal): TStringList; - function GetParam(const index, paramNo : Integer) : String; + function GetParam(const index, paramNo: Integer): String; public website, Filename: String; isFilterAllSites, isFiltered: Boolean; @@ -170,7 +172,7 @@ TMangaInformation = class(TObject) isRemoveUnicode: Boolean; FHTTP: THTTPSend; - procedure OnTag(NoCaseTag, ActualTag: string); + procedure OnTag(NoCaseTag, ActualTag: String); procedure OnText(Text: String); constructor Create(AOwnerThread: TFMDThread = nil); destructor Destroy; override; @@ -179,7 +181,8 @@ TMangaInformation = class(TObject) function GetNameAndLink(const names, links: TStringList; const website, URL: String): Byte; function GetInfoFromURL(const website, URL: String; const Reconnect: Cardinal): Byte; - procedure SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); overload; + procedure SyncInfoToData(const DataProcess: TDataProcess; + const index: Cardinal); overload; procedure SyncInfoToData(const DataProcess: TDBDataProcess); overload; procedure SyncMinorInfoToData(const DataProcess: TDataProcess; const index: Cardinal); @@ -188,11 +191,14 @@ TMangaInformation = class(TObject) procedure AddInfoToDataWithoutBreak(const Name, link: String; const DataProcess: TDataProcess); // Only use this function for update manga list - procedure AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); overload; + procedure AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); + overload; // to add data to TDBDataProcess - procedure AddInfoToData(const Title, Link: string; const DataProcess: TDBDataProcess); overload; + procedure AddInfoToData(const Title, Link: String; + const DataProcess: TDBDataProcess); overload; //wrapper - function GetPage(var output: TObject; URL: String; const Reconnect: Cardinal): Boolean; overload; + function GetPage(var output: TObject; URL: String; + const Reconnect: Cardinal): Boolean; overload; end; var @@ -201,23 +207,26 @@ TMangaInformation = class(TObject) const DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; DBDataProcessParams: array [0..8] of ShortString = - ('title', 'link', 'authors', 'artists', 'genres', 'status', 'summary', 'numchapter', 'jdn'); - DBDataProccesCreateParam = '(title TEXT,'+ - 'link STRING NOT NULL PRIMARY KEY,'+ - 'authors TEXT,'+ - 'artists TEXT,'+ - 'genres TEXT,'+ - 'status TEXT,'+ - 'summary TEXT,'+ - 'numchapter INTEGER,'+ - 'jdn INTEGER);'; - - function DBDataFilePath(const AWebsite: string): string; - procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); - function DataFileExist(const AWebsite: string): Boolean; - procedure CopyDBDataProcess(const AWebsite, NWebsite: string); - function DeleteDBDataProcess(const AWebsite: string): Boolean; - procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); + ('title', 'link', 'authors', 'artists', 'genres', 'status', + 'summary', 'numchapter', 'jdn'); + DBDataProccesCreateParam = '('#13#10 + + '"title" VARCHAR,'#13#10 + + '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + + '"authors" VARCHAR,'#13#10 + + '"artists" VARCHAR,'#13#10 + + '"genres" VARCHAR,'#13#10 + + '"status" VARCHAR,'#13#10 + + '"summary" VARCHAR,'#13#10 + + '"numchapter" INTEGER,'#13#10 + + '"jdn" INTEGER'#13#10 + + ');'; + +function DBDataFilePath(const AWebsite: String): String; +procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); +function DataFileExist(const AWebsite: String): Boolean; +procedure CopyDBDataProcess(const AWebsite, NWebsite: String); +function DeleteDBDataProcess(const AWebsite: String): Boolean; +procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); implementation @@ -225,8 +234,8 @@ implementation Dialogs, fpJSON, JSONParser, IniFiles, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, uMisc, frmMain, WebsiteModules; -function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; - len2: longint; data2: pointer): longint; cdecl; +function NaturalCompareCallback({%H-}user: pointer; len1: longint; + data1: pointer; len2: longint; data2: pointer): longint; cdecl; var s1, s2: String; begin @@ -267,12 +276,12 @@ procedure RegexCallback(context: PSqlite3_Context; argc: longint; end; end; -function QuotedLike(const S: string): string; +function QuotedLike(const S: String): String; begin - Result := QuotedStr(AnsiQuotedStr(S, '%')); + Result := QuotedStrd(AnsiQuotedStr(S, '%')); end; -function DBDataFilePath(const AWebsite: string): string; +function DBDataFilePath(const AWebsite: String): String; begin Result := fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT; end; @@ -296,23 +305,24 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); rawdata.LoadFromFile(AWebsite); dbdata.CreateDatabase(AWebsite); if rawdata.Data.Count > 0 then - with rawdata do - begin - rcount := 0; - for i := 0 to Data.Count-1 do + with rawdata do begin - dbdata.AddData(Title[i], Link[i], Authors[i], Artists[i], Genres[i], - Status[i], StringBreaks(Summary[i]), StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), - {%H-}Integer(JDN[i])-3); - Inc(rcount); - if rcount >= 5000 then + rcount := 0; + for i := 0 to Data.Count - 1 do begin - rcount := 0; - dbdata.Commit; + dbdata.AddData(Title[i], Link[i], Authors[i], Artists[i], Genres[i], + Status[i], StringBreaks(Summary[i]), + StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), + {%H-}integer(JDN[i]) - 3); + Inc(rcount); + if rcount >= 5000 then + begin + rcount := 0; + dbdata.Commit; + end; end; + dbdata.Commit; end; - dbdata.Commit; - end; dbdata.Sort; finally rawdata.Free; @@ -323,22 +333,24 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); end; end; -function DataFileExist(const AWebsite: string): Boolean; +function DataFileExist(const AWebsite: String): Boolean; begin - if AWebsite = '' then Exit(False); + if AWebsite = '' then + Exit(False); Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DATA_EXT) or FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); end; -procedure CopyDBDataProcess(const AWebsite, NWebsite: string); +procedure CopyDBDataProcess(const AWebsite, NWebsite: String); begin - if NWebsite = '' then Exit; + if NWebsite = '' then + Exit; if DataFileExist(AWebsite) then begin try - CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, - [cffPreserveTime, cffOverwriteFile], True); + CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + [cffPreserveTime, cffOverwriteFile], True); except on E: Exception do Writelog_E('CopyDBDataProcess.Error!', E); @@ -346,7 +358,7 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: string); end; end; -function DeleteDBDataProcess(const AWebsite: string): Boolean; +function DeleteDBDataProcess(const AWebsite: String): Boolean; var tryc: Integer; begin @@ -365,7 +377,7 @@ function DeleteDBDataProcess(const AWebsite: string): Boolean; end; end; -procedure OverwriteDBDataProcess(const AWebsite, NWebsite: string); +procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); begin if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then begin @@ -381,7 +393,8 @@ procedure TDBDataProcess.CreateTable; begin if FConn.Connected then begin - FConn.ExecuteDirect('CREATE TABLE ' + QuotedStr(FTableName) + + FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName) + ';'); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + DBDataProccesCreateParam); FTrans.Commit; end; @@ -423,13 +436,13 @@ procedure TDBDataProcess.GetRecordCount; FRecordCount := 0; end; -procedure TDBDataProcess.AddSQLCond(const sqltext: string; useOR: Boolean); +procedure TDBDataProcess.AddSQLCond(const sqltext: String; useOR: Boolean); begin with FQuery.SQL do begin if Count > 0 then - if (Strings[Count-1] <> '(') and - (UpCase(Trim(Strings[Count-1])) <> 'WHERE') then + if (Strings[Count - 1] <> '(') and + (UpCase(Trim(Strings[Count - 1])) <> 'WHERE') then begin if useOR then Add('OR') @@ -440,20 +453,21 @@ procedure TDBDataProcess.AddSQLCond(const sqltext: string; useOR: Boolean); end; end; -procedure TDBDataProcess.AddSQLSimpleFilter(const fieldname, value: string; +procedure TDBDataProcess.AddSQLSimpleFilter(const fieldname, Value: String; useNOT: Boolean; useOR: Boolean; useRegexp: Boolean); var - svalue: string; - scond: string; + svalue: String; + scond: String; begin - svalue := LowerCase(Trim(value)); - if (fieldname = '') or (svalue = '') then Exit; + svalue := LowerCase(Trim(Value)); + if (fieldname = '') or (svalue = '') then + Exit; if useNOT then scond := ' NOT' else scond := ''; if useRegexp then - AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue), useOR) + AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStrd(svalue), useOR) else AddSQLCond(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); end; @@ -471,6 +485,7 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; if FConn.DatabaseName = '' then Exit; try + FConn.CharSet := 'UTF8'; FConn.Connected := True; sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, NaturalCompareCallback); @@ -492,7 +507,7 @@ function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; Result := FWebsite; if FQuery.Active and (FAttachedSites.Count > 0) then try - FQuery.RecNo := RecIndex+1; + FQuery.RecNo := RecIndex + 1; Result := FQuery.FieldByName('website').AsString; except on E: Exception do @@ -527,7 +542,7 @@ procedure TDBDataProcess.AttachAllSites; j: Integer; begin if SitesList.Count > 0 then - for j := 0 to SitesList.Count-1 do + for j := 0 to SitesList.Count - 1 do if SitesList[j] = FWebsite then begin SitesList.Delete(j); @@ -541,14 +556,15 @@ procedure TDBDataProcess.AttachAllSites; if FConn.Connected and (SitesList.Count > 0) then begin RemoveCurrentSite; - if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then Exit; + if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then + Exit; DetachAllSites; FConn.ExecuteDirect('END TRANSACTION'); - for i := 0 to SitesList.Count-1 do + for i := 0 to SitesList.Count - 1 do if FileExistsUTF8(DBDataFilePath(SitesList[i])) then begin - FConn.ExecuteDirect('ATTACH ' + QuotedStrd(DBDataFilePath(SitesList[i])) - + ' AS ' + QuotedStrd(SitesList[i])); + FConn.ExecuteDirect('ATTACH ' + + QuotedStrd(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); FAttachedSites.Add(SitesList[i]); end; FConn.ExecuteDirect('BEGIN TRANSACTION'); @@ -563,13 +579,15 @@ procedure TDBDataProcess.DetachAllSites; FConn.ExecuteDirect('END TRANSACTION'); repeat try - FConn.ExecuteDirect('DETACH '+ QuotedStrd(FAttachedSites[FAttachedSites.Count-1])); + FConn.ExecuteDirect('DETACH ' + + QuotedStrd(FAttachedSites[FAttachedSites.Count - 1])); except on E: Exception do - Writelog_E('TDBDataProcess.DetachAllSites:'+FAttachedSites[FAttachedSites.Count-1], + Writelog_E('TDBDataProcess.DetachAllSites:' + + FAttachedSites[FAttachedSites.Count - 1], E, Self); end; - FAttachedSites.Delete(FAttachedSites.Count-1); + FAttachedSites.Delete(FAttachedSites.Count - 1); until FAttachedSites.Count = 0; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := False; @@ -583,6 +601,7 @@ constructor TDBDataProcess.Create; FTrans := TSQLTransaction.Create(nil); FQuery := TSQLQuery.Create(nil); FConn.Transaction := FTrans; + FQuery.PacketRecords := 25; FQuery.DataBase := FTrans.DataBase; FQuery.Transaction := FTrans; FRegxp := TRegExpr.Create; @@ -621,7 +640,7 @@ destructor TDBDataProcess.Destroy; function TDBDataProcess.Connect(AWebsite: String): Boolean; var - filepath: string; + filepath: String; begin Result := False; if AWebsite <> '' then @@ -629,7 +648,8 @@ function TDBDataProcess.Connect(AWebsite: String): Boolean; if FWebsite = '' then Exit; filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; - if not FileExistsUTF8(filepath) Then Exit; + if not FileExistsUTF8(filepath) then + Exit; Result := InternalOpen(filepath); end; @@ -771,21 +791,26 @@ procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer); +var + s: String; begin if FConn.Connected then try - FConn.ExecuteDirect('INSERT OR IGNORE INTO ' + QuotedStr(FTableName) + + FConn.ExecuteDirect( + 'INSERT OR IGNORE INTO ' + QuotedStrd(FTableName) + #13#10'(' + DBDataProcessParam + ')' + - #13#10'VALUES (' + - QuotedStr(Title) + ',' + - QuotedStr(Link) + ',' + - QuotedStr(Authors) + ',' + - QuotedStr(Artists) + ',' + - QuotedStr(Genres) + ',' + - QuotedStr(Status) + ',' + - QuotedStr(Summary) + ',' + - QuotedStr(IntToStr(NumChapter)) + ',' + - QuotedStr(IntToStr(JDN)) + ');'); + #13#10'VALUES' + + #13#10'('#13#10 + + QuotedStrd(Title) + ','#13#10 + + QuotedStrd(Link) + ','#13#10 + + QuotedStrd(Authors) + ','#13#10 + + QuotedStrd(Artists) + ','#13#10 + + QuotedStrd(Genres) + ','#13#10 + + QuotedStrd(Status) + ','#13#10 + + QuotedStrd(Summary) + ','#13#10 + + QuotedStrd(IntToStr(NumChapter)) + ','#13#10 + + QuotedStrd(IntToStr(JDN)) + + #13#10');'); except on E: Exception do WriteLog_E('TDBDataProcess.AddData.Error!', E, Self); @@ -799,8 +824,8 @@ procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, NumChapter, DateToJDN(JDN)); end; -procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, - Status, Summary: String; NumChapter: Integer; AWebsite: String); +procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, + Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String); var sql: String; @@ -808,11 +833,12 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, begin if sql <> '' then sql += ','#13#10; - sql += field + '=' + QuotedStr(Value); + sql += QuotedStrd(field) + '=' + QuotedStrd(Value); end; begin - if Link = '' then Exit; + if Link = '' then + Exit; if FConn.Connected then begin try @@ -829,7 +855,7 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, Genres, #13#10'SET'#13#10 + sql else sql := 'UPDATE OR IGNORE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; - sql += #13#10'WHERE link=' + QuotedStr(Link) + ';'; + sql += #13#10'WHERE "link"=' + QuotedStrd(Link) + ';'; FConn.ExecuteDirect(sql); except on E: Exception do @@ -884,7 +910,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; if (SQL[i] = 'UNION ALL') or (SQL[i] = ')') then begin SQL.Insert(i, 'AND'); - SQL.Insert(i+1, '"title" LIKE ' + QuotedLike(ATitle)); + SQL.Insert(i + 1, '"title" LIKE ' + QuotedLike(ATitle)); Inc(i, 3); end else @@ -904,7 +930,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; except on E: Exception do WriteLog_E('TDBDataProcess.Search.Error!'#13#10 + - 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); end; end; Result := FQuery.Active; @@ -920,7 +946,8 @@ function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringL const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; begin Result := False; - if not FQuery.Active then Exit; + if not FQuery.Active then + Exit; if ((stTitle = '') and (stAuthors = '') and (stArtists = '') and @@ -939,59 +966,61 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean): Boolean; - var - tsql: string; - i: Integer; - filtersingle: Boolean = True; +var + tsql: String; + i: Integer; + filtersingle: Boolean = True; procedure GenerateSQLFilter; var j: Integer; begin // filter new manga based on date - if searchNewManga then - AddSQLCond('"jdn" > ' + QuotedStr(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); + if searchNewManga then + AddSQLCond('"jdn" > ' + + QuotedStrd(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); - // filter title - AddSQLSimpleFilter('title', stTitle, False, False, useRegExpr); + // filter title + AddSQLSimpleFilter('title', stTitle, False, False, useRegExpr); - // filter authors - AddSQLSimpleFilter('authors', stAuthors, False, False, useRegExpr); + // filter authors + AddSQLSimpleFilter('authors', stAuthors, False, False, useRegExpr); - // filter artists - AddSQLSimpleFilter('artists', stArtists, False, False, useRegExpr); + // filter artists + AddSQLSimpleFilter('artists', stArtists, False, False, useRegExpr); - // filter summary - AddSQLSimpleFilter('summary', stSummary, False, False, useRegExpr); + // filter summary + AddSQLSimpleFilter('summary', stSummary, False, False, useRegExpr); - // filter status - if stStatus <> '2' then - AddSQLCond('"status"='+ QuotedStr(stStatus)); + // filter status + if stStatus <> '2' then + AddSQLCond('"status"=' + QuotedStrd(stStatus)); - //filter checked genres - if checkedGenres.Count > 0 then - begin - AddSQLCond('('); - for j := 0 to checkedGenres.Count-1 do - AddSQLSimpleFilter('genres', checkedGenres[j], False, - (not haveAllChecked), useRegExpr); - FQuery.SQL.Add(')'); - end; + //filter checked genres + if checkedGenres.Count > 0 then + begin + AddSQLCond('('); + for j := 0 to checkedGenres.Count - 1 do + AddSQLSimpleFilter('genres', checkedGenres[j], False, + (not haveAllChecked), useRegExpr); + FQuery.SQL.Add(')'); + end; - //filter unchecked genres - if uncheckedGenres.Count > 0 then - begin - AddSQLCond('('); - for j := 0 to uncheckedGenres.Count-1 do - AddSQLSimpleFilter('genres', uncheckedGenres[j], True, - (not haveAllChecked), useRegExpr); - FQuery.SQL.Add(')'); - end; + //filter unchecked genres + if uncheckedGenres.Count > 0 then + begin + AddSQLCond('('); + for j := 0 to uncheckedGenres.Count - 1 do + AddSQLSimpleFilter('genres', uncheckedGenres[j], True, + (not haveAllChecked), useRegExpr); + FQuery.SQL.Add(')'); + end; end; begin Result := False; - if FQuery.Active = False then Exit; + if FQuery.Active = False then + Exit; if not CanFilter(checkedGenres, uncheckedGenres, stTitle, stAuthors, stArtists, stStatus, stSummary, minusDay, haveAllChecked, searchNewManga) then Exit; @@ -1013,10 +1042,11 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList QuotedStrd(FTableName)); SQL.Add('WHERE'); GenerateSQLFilter; - for i := 0 to FAttachedSites.Count-1 do + for i := 0 to FAttachedSites.Count - 1 do begin SQL.Add('UNION ALL'); - SQL.Add('SELECT *, ' + QuotedStrd(FAttachedSites[i]) + ' AS "website" FROM ' + + SQL.Add('SELECT *, ' + QuotedStrd(FAttachedSites[i]) + + ' AS "website" FROM ' + FAttachedSites[i] + '.' + QuotedStrd(FTableName)); SQL.Add('WHERE'); GenerateSQLFilter; @@ -1045,7 +1075,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList on E: Exception do begin WriteLog_E('TDBDataProcess.Filter.Error!'#13#10 + - 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); FQuery.Close; SQL.Text := tsql; FQuery.Open; @@ -1118,15 +1148,15 @@ procedure TDBDataProcess.Sort; FQuery.Close; with FConn do begin - ExecuteDirect('CREATE TABLE ' + QuotedStr(FTableName + '_ordered') + + ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO ' + QuotedStr(FTableName + '_ordered') + ' ' + + ExecuteDirect('INSERT INTO ' + QuotedStrd(FTableName + '_ordered') + ' ' + BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + - ' FROM ' + QuotedStr(FTableName) + 'ORDER BY title COLLATE NATCMP'); + ' FROM ' + QuotedStrd(FTableName) + 'ORDER BY "title" COLLATE NATCMP'); FTrans.Commit; - ExecuteDirect('DROP TABLE ' + QuotedStr(FTableName)); - ExecuteDirect('ALTER TABLE ' + QuotedStr(FTableName + '_ordered') + - 'RENAME TO ' + QuotedStr(FTableName)); + ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + + 'RENAME TO ' + QuotedStrd(FTableName)); FTrans.Commit; VacuumTable; end; @@ -1140,9 +1170,10 @@ function TDBDataProcess.WebsiteLoaded(const AWebsite: String): Boolean; i: Integer; begin Result := False; - if FWebsite = AWebsite then Exit(True); + if FWebsite = AWebsite then + Exit(True); if FAllSitesAttached then - for i := 0 to FAttachedSites.Count-1 do + for i := 0 to FAttachedSites.Count - 1 do if FAttachedSites[i] = AWebsite then begin Result := True; @@ -1267,7 +1298,7 @@ procedure TDataProcess.BreakDataToParts(const i: Cardinal); Genres.Strings[i] := GetParam(i, DATA_PARAM_GENRES); Status.Strings[i] := GetParam(i, DATA_PARAM_STATUS); Summary.Strings[i] := GetParam(i, DATA_PARAM_SUMMARY); - JDN.Items[i] := Pointer(StrToIntDef(GetParam(i, DATA_PARAM_JDN),0)); + JDN.Items[i] := Pointer(StrToIntDef(GetParam(i, DATA_PARAM_JDN), 0)); end; end; @@ -1389,7 +1420,7 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; l.Clear; try GetParams(l, Data.Strings[i]); - While l.Count < 10 do + while l.Count < 10 do l.Add(''); title.Add(l.Strings[DATA_PARAM_TITLE]); link.Add(l.Strings[DATA_PARAM_LINK]); @@ -1482,7 +1513,7 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; for i := 0 to filterPos.Count - 1 do begin fpos := filterPos.Items[i]; - if (currentJDN - {%H-}Integer(jdn.Items[fpos]) >= minusDay) and + if (currentJDN - {%H-}integer(jdn.Items[fpos]) >= minusDay) and (filterMark.Items[fpos] = FILTER_SHOW) then filterMark.Items[fpos] := FILTER_HIDE; end; @@ -1789,7 +1820,7 @@ procedure TMangaInformation.ClearInfo; mangaInfo.chapterLinks.Clear; end; -procedure TMangaInformation.OnTag(NoCaseTag, ActualTag : string); +procedure TMangaInformation.OnTag(NoCaseTag, ActualTag: String); begin parse.Add(ActualTag); end; @@ -1967,8 +1998,8 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then Result := GetRedHawkScansDirectoryPageNumber else - if website = WebsiteRoots[S2SCAN_ID,0] then - Result:= GetS2ScanDirectoryPageNumber + if website = WebsiteRoots[S2SCAN_ID, 0] then + Result := GetS2ScanDirectoryPageNumber else if website = WebsiteRoots[SENMANGA_ID, 0] then Result := GetSenMangaDirectoryPageNumber @@ -2720,7 +2751,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/WPManga/manga_information.inc} begin - if Trim(URL) = '' then Exit(INFORMATION_NOT_FOUND); + if Trim(URL) = '' then + Exit(INFORMATION_NOT_FOUND); //load User-Agent from INIAdvanced if website <> '' then @@ -2737,7 +2769,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; else begin WebsiteID := GetMangaSiteID(website); - if WebsiteID > High(WebsiteRoots) then Exit(INFORMATION_NOT_FOUND); + if WebsiteID > High(WebsiteRoots) then + Exit(INFORMATION_NOT_FOUND); Source := TStringList.Create; if website = WebsiteRoots[ANIMEA_ID, 0] then @@ -3215,7 +3248,7 @@ procedure TMangaInformation.AddInfoToData(const Name, link: String; l.Free; end; -procedure TMangaInformation.AddInfoToData(const Title, Link: string; +procedure TMangaInformation.AddInfoToData(const Title, Link: String; const DataProcess: TDBDataProcess); begin if Assigned(DataProcess) then From 96b6d2273d338f374af12db63e581ee3a8dc3dde Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 17:15:06 +0800 Subject: [PATCH 0222/2794] baseunit, add convertcharsettoutf8 function guessencoding with meta tag (html file) --- baseunits/uBaseUnit.pas | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4c55b7425..18bd52682 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -19,9 +19,9 @@ interface UTF8Process, {$endif} SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, - strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, RegExpr, - synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, uMisc, - USimpleException, USimpleLogger; + LConvEncoding, strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, + RegExpr, synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, + uMisc, USimpleException, USimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); @@ -872,6 +872,9 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); //HTML procedure ParseHTML(const aRaw: string; var aOutput: TStringList); +//convert charset to utf8 +function ConvertCharsetToUTF8(const S: String): String; + // StringUtils function QuotedStrd(const S: string): string; overload; function QuotedStrd(const S: Integer): string; overload; @@ -1532,6 +1535,34 @@ procedure ParseHTML(const aRaw: string; var aOutput: TStringList); end; end; +function ConvertCharsetToUTF8(const S: String): String; +var + cs: String; +begin + Result := S; + if S = '' then + Exit; + with TRegExpr.Create do + try + Expression := '(?ig)^.* '' then + Result := ConvertEncoding(S, cs, 'utf8'); +end; + function QuotedStrd(const S: string): string; begin Result := AnsiQuotedStr(S, '"'); From d087947e8a6e58a361426deb75d2372a7e58bdc7 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 17:53:52 +0800 Subject: [PATCH 0223/2794] added m#h160 #59 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/mh160com.pas | 224 +++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/mh160com.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 34d4b1222..1aeef126f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,2 +1,3 @@ uses - FoOlSlide; + FoOlSlide, + mh160com; diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas new file mode 100644 index 000000000..b21182c87 --- /dev/null +++ b/baseunits/modules/mh160com.pas @@ -0,0 +1,224 @@ +unit mh160com; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, sysutils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, base64, RegExpr; + +implementation + +const + diralpha = 'abcdefghijklmnopqrstuvwxyz'; + +function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; + var Page: Integer; {%H-}Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := Length(diralpha); +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + begin + if Parse[i] = '
' then + if GetTagName(Parse[i + 1]) = 'a' then + begin + Links.Add(GetVal(Parse[i + 1], 'href')); + Names.Add(CommonStringFilter(Parse[i + 2])); + end; + end; + end; + +begin + Result := INFORMATION_NOT_FOUND; + if MangaInfo = nil then + Exit; + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/kanmanhua/' + + diralpha[StrToInt(URL) + 1] + '.html', 3) then + begin + Result := NO_ERROR; + Source.Text := ConvertCharsetToUTF8(Source.Text); + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + g: String = ''; + begin + with MangaInfo.mangaInfo do + begin + for i := StartIndex to Parse.Count - 1 do + begin + if Parse[i] = '' then + Break; + if GetTagName(Parse[i]) = 'a' then + begin + chapterLinks.Add(GetVal(Parse[i], 'href')); + chapterName.Add(g + Trim(Parse[i + 1])); + end; + end; + //invert chapters + if MangaInfo.mangaInfo.chapterLinks.Count > 0 then + InvertStrings([chapterLinks, chapterName]); + end; + end; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + with MangaInfo.mangaInfo do + begin + //title + if title = '' then + if GetVal(Parse[i], 'class') = 'intro_l' then + if GetVal(Parse[i + 2], 'class') = 'title' then + title := CommonStringFilter(Parse[i + 5]); + + //cover + if coverLink = '' then + if GetVal(Parse[i], 'class') = 'cover' then + if GetTagName(Parse[i + 1]) = 'img' then + begin + coverLink := GetVal(Parse[i + 1], 'src'); + if Pos('http', coverLink) <> 1 then + coverLink := Module.RootURL + coverLink; + end; + + //author + if (Pos('原著作者:', Parse[i]) <> 0) and + (Parse[i + 1] = '') then + authors := CommonStringFilter(Parse[i + 2]); + + //genres + if (Pos('剧情类别:', Parse[i]) <> 0) and + (Parse[i + 1] = '') then + genres := Trim(Parse[i + 3]); + + //summary + if Pos('class="introduction"', Parse[i]) <> 0 then + summary := Trim(Parse[i + 2]); + + //chapters + if GetVal(Parse[i], 'class') = 'plist pnormal' then + ScanChapters(i); + end; + end; + +begin + Result := INFORMATION_NOT_FOUND; + if MangaInfo = nil then + Exit; + MangaInfo.mangaInfo.website := Module.Website; + MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + begin + Result := NO_ERROR; + Source.Text := ConvertCharsetToUTF8(Source.Text); + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + s: String; + begin + s := ReplaceRegExpr('(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$', + Source.Text, '$1', True); + if s <> '' then + begin + s := DecodeStringBase64(s); + s := StringReplace(s, '$qingtiandy$', #13#10, [rfReplaceAll]); + Container.PageLinks.AddText(s); + end; + end; + +begin + Result := False; + if DownloadThread = nil then + Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), + Container.Manager.retryConnect) then + begin + Result := True; + ScanParse; + end; + finally + Source.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'mh160'; + RootURL := 'http://www.mh160.com'; + SortedList := False; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From ce29e8ad4db5a80890e3cdcb648c8f02779c0d10 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 19:40:19 +0800 Subject: [PATCH 0224/2794] m%h16O#com, transform to real urls #59 --- baseunits/modules/mh160com.pas | 96 ++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index b21182c87..ec06b95a7 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -5,7 +5,7 @@ interface uses - Classes, sysutils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, HTMLUtil, base64, RegExpr; implementation @@ -167,18 +167,84 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; var Source: TStringList; Container: TTaskContainer; + Regx: TRegExpr; + picTree: String; - procedure ScanParse; + procedure GetURLs; var - s: String; + realurls: TStringList; + i, j: Integer; + r, u: String; begin - s := ReplaceRegExpr('(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$', - Source.Text, '$1', True); - if s <> '' then + realurls := TStringList.Create; + try + realurls.NameValueSeparator := '='; + Regx.Expression := '(?ig)^.*realurl\.replace\("(.+)","(.+)".*$'; + for i := 0 to Source.Count - 1 do + begin + if Regx.Exec(Source[i]) then + begin + r := Trim(LowerCase(Regx.Replace(Source[i], '$1', True))); + u := Trim(LowerCase(Regx.Replace(Source[i], '$2', True))); + if (r <> '') and (u <> '') then + realurls.Values[r] := u; + end; + end; + + if (realurls.Count > 0) and (Container.PageLinks.Count > 0) then + begin + for i := 0 to Container.PageLinks.Count - 1 do + begin + for j := 0 to realurls.Count - 1 do + begin + if Pos(realurls.Names[j], LowerCase(Container.PageLinks[i])) <> 0 then + Container.PageLinks[i] := StringReplace(Container.PageLinks[i], + realurls.Names[j], realurls.ValueFromIndex[j], [rfIgnoreCase]); + end; + end; + end; + finally + realurls.Free; + end; + end; + + function ScanSource: Boolean; + var + i: Integer; + jsurl: String = ''; + begin + Result := False; + Regx.Expression := '(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$'; + picTree := Regx.Replace(Source.Text, '$1', True); + + if picTree <> '' then begin - s := DecodeStringBase64(s); - s := StringReplace(s, '$qingtiandy$', #13#10, [rfReplaceAll]); - Container.PageLinks.AddText(s); + picTree := DecodeStringBase64(picTree); + picTree := StringReplace(picTree, '$qingtiandy$', #13#10, [rfReplaceAll]); + Container.PageLinks.AddText(picTree); + + if Container.PageLinks.Count > 0 then + begin + for i := 0 to Source.Count - 1 do + if (Pos(' 0) and + (Pos('/base64.js', Source[i]) <> 0) then + begin + jsurl := GetVal(Source[i], 'src'); + jsurl := StringReplace(jsurl, '../..', Module.RootURL, []); + Break; + end; + if jsurl <> '' then + begin + Source.Clear; + if DownloadThread.GetPage(TObject(Source), jsurl, + Container.Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + GetURLs; + end; + end; + end; end; end; @@ -195,8 +261,16 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), Container.Manager.retryConnect) then begin - Result := True; - ScanParse; + if Source.Count > 0 then + begin + Regx := TRegExpr.Create; + try + Source.Text := ConvertCharsetToUTF8(Source.Text); + Result := ScanSource; + finally + Regx.Free; + end; + end; end; finally Source.Free; From 850542d329a86cd34a2e9529b2dede931f79c1a9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 19:42:41 +0800 Subject: [PATCH 0225/2794] add m%16O com to list closes #59 --- config/mangalist.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/mangalist.ini b/config/mangalist.ini index 00a964747..b3249292e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,6 +3,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt +Chinese=mh160 English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans From 52817acc12fd575191776f52ec3f35fad4b3f75a Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 19:44:48 +0800 Subject: [PATCH 0226/2794] add shouj osense to list --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index b3249292e..45aabf291 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt Chinese=mh160 -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From e43ba35f1231d0a4431ecbd1dc6feab07b94846f Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 19:48:20 +0800 Subject: [PATCH 0227/2794] updatethread, minor changes --- baseunits/uUpdateThread.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index b18a6183f..6638e96da 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -630,13 +630,13 @@ procedure TUpdateMangaManagerThread.Execute; // remove duplicate if links.Count > 0 then begin + c := 0; + j := 0; MainForm.ulTotalPtr := links.Count; MainForm.ulWorkPtr := j; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromNewTitle + '...'; Synchronize(MainThreadShowGetting); - c := 0; - j := 0; while j < (links.Count - 1) do begin if Terminated then @@ -672,13 +672,13 @@ procedure TUpdateMangaManagerThread.Execute; // remove duplicate found<>current database if links.Count > 0 then begin + c := 0; + j := 0; MainForm.ulTotalPtr := links.Count; MainForm.ulWorkPtr := j; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromCurrentData + '...'; Synchronize(MainThreadShowGetting); - c := 0; - j := 0; while j < links.Count do begin if Terminated then From 31bfb10ab1e1d3a31590c634a809a09e785a5856 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 19:53:11 +0800 Subject: [PATCH 0228/2794] updatethread, clean up --- baseunits/uUpdateThread.pas | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 6638e96da..9d064759c 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -23,7 +23,7 @@ TUpdateMangaThread = class(TFMDThread) protected checkStyle: TCheckStyleType; names, links: TStringList; - workPtr: Cardinal; + workPtr: Integer; manager: TUpdateMangaManagerThread; Info: TMangaInformation; @@ -181,9 +181,8 @@ procedure TUpdateMangaThread.Execute; begin Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); end; - //Synchronize(MainThreadUpdateNamesAndLinks); - // For Fakku and Pururin only, reduce the number of page we have to visit - // in order to search for new series. + //if website has sorted list by latest added + //we will stop at first found against current db if SitesWithSortedList(manager.website) then begin if links.Count > 0 then @@ -753,7 +752,7 @@ procedure TUpdateMangaManagerThread.Execute; if Terminated then Break; websites[websitePtr - 1] := - UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); + UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); end; except on E: Exception do From a17d24c3a749994f257da4536030b9aa41e19a5c Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 23:05:59 +0800 Subject: [PATCH 0229/2794] baseunit, change convertcharsettoutf8 for tstringlist only heavy cpu usage on long list. --- baseunits/uBaseUnit.pas | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 18bd52682..aa574eed0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -873,7 +873,7 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); procedure ParseHTML(const aRaw: string; var aOutput: TStringList); //convert charset to utf8 -function ConvertCharsetToUTF8(const S: String): String; +procedure ConvertCharsetToUTF8(var TheStrings: TStringList); // StringUtils function QuotedStrd(const S: string): string; overload; @@ -1535,19 +1535,32 @@ procedure ParseHTML(const aRaw: string; var aOutput: TStringList); end; end; -function ConvertCharsetToUTF8(const S: String): String; +procedure ConvertCharsetToUTF8(var TheStrings: TStringList); var cs: String; + i: Integer; begin - Result := S; - if S = '' then - Exit; + if TheStrings = nil then Exit; + if TheStrings.Count = 0 then Exit; with TRegExpr.Create do try + cs := ''; Expression := '(?ig)^.* 0 then + begin + if Exec(TheStrings[i]) then + cs := Replace(TheStrings[i], '$1', True); + if cs <> '' then + begin + cs := LowerCase(cs); + Break; + end; + end; + end; + if cs <> '' then begin - cs := LowerCase(Replace(S, '$1', True)); if cs = 'gb2312' then cs := EncodingCP936 else @@ -1555,12 +1568,12 @@ function ConvertCharsetToUTF8(const S: String): String; cs := EncodingCP950; end else - cs := GuessEncoding(S); + cs := GuessEncoding(TheStrings.Text); finally Free; end; if cs <> '' then - Result := ConvertEncoding(S, cs, 'utf8'); + TheStrings.Text := ConvertEncoding(TheStrings.Text, cs, 'utf8'); end; function QuotedStrd(const S: string): string; From 2418d8688b5b0275cb79a8d4d5a5372a55feb724 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 23:09:48 +0800 Subject: [PATCH 0230/2794] m&h160, convert from cp936 --- baseunits/modules/mh160com.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index ec06b95a7..8348d92b6 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, base64, RegExpr; + LConvEncoding, HTMLUtil, base64, RegExpr; implementation @@ -50,7 +50,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; diralpha[StrToInt(URL) + 1] + '.html', 3) then begin Result := NO_ERROR; - Source.Text := ConvertCharsetToUTF8(Source.Text); + Source.Text := CP936ToUTF8(Source.Text); Parse := TStringList.Create; try ParseHTML(Source.Text, Parse); @@ -147,7 +147,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then begin Result := NO_ERROR; - Source.Text := ConvertCharsetToUTF8(Source.Text); + Source.Text := CP936ToUTF8(Source.Text); Parse := TStringList.Create; try ParseHTML(Source.Text, Parse); @@ -265,7 +265,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin Regx := TRegExpr.Create; try - Source.Text := ConvertCharsetToUTF8(Source.Text); + Source.Text := CP936ToUTF8(Source.Text); Result := ScanSource; finally Regx.Free; From 3fff86d4ec74ff412a98123ee926c3c835e1cd35 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Jul 2015 23:10:01 +0800 Subject: [PATCH 0231/2794] updatethread, minor changes --- baseunits/uUpdateThread.pas | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 9d064759c..1b05a985a 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -181,6 +181,7 @@ procedure TUpdateMangaThread.Execute; begin Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); end; + //if website has sorted list by latest added //we will stop at first found against current db if SitesWithSortedList(manager.website) then @@ -190,9 +191,6 @@ procedure TUpdateMangaThread.Execute; manager.isFinishSearchingForNewManga := True; end; - //**removing hostname in links - RemoveHostFromURLs(links); - if links.Count > 0 then begin manager.CS_AddNamesAndLinks.Acquire; @@ -471,7 +469,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; TerminateThreads; Break; end; - Sleep(200); //waiting for empty slot / slowing down the circle + Sleep(250); //waiting for empty slot / slowing down the circle end; if Terminated then From 0caff76172a3d597d3c633c1667ed261f1c92028 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 14:12:39 +0800 Subject: [PATCH 0232/2794] baseunit, change regex_host expression --- baseunits/uBaseUnit.pas | 10 +++++----- mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index aa574eed0..27db6b639 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -260,7 +260,7 @@ interface SEPERATOR2 = '~%!'; // common regex to split host/url - REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(/?.*)$'; + REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; ANIMEA_ID = 0; MANGAHERE_ID = 1; @@ -1439,7 +1439,7 @@ function FillHost(const Host, URL: String): String; try Expression := REGEX_HOST; th := Replace(Host, '$1$2', True); - tu := Replace(URL, '$3', True); + tu := Replace(URL, '$4', True); if (tu <> '') and (tu[1] <> '/') then tu := '/' + tu; Result := th + tu; @@ -1450,7 +1450,7 @@ function FillHost(const Host, URL: String): String; function RemoveHostFromURL(URL : String) : String; begin - Result := ReplaceRegExpr(REGEX_HOST, URL, '$3', True); + Result := ReplaceRegExpr(REGEX_HOST, URL, '$4', True); end; procedure RemoveHostFromURLs(const URLs : TStringList); @@ -1463,7 +1463,7 @@ procedure RemoveHostFromURLs(const URLs : TStringList); try Expression := REGEX_HOST; for i := 0 to URLs.Count - 1 do - URLs[i] := Replace(URLs[i], '$3', True); + URLs[i] := Replace(URLs[i], '$4', True); finally Free; end; @@ -1482,7 +1482,7 @@ procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); i := 0; while i < URLs.Count do begin - URLs[i] := Replace(URLs[i], '$3', True); + URLs[i] := Replace(URLs[i], '$4', True); if (URLs[i] = '') or (URLs[i] = '/') then begin URLs.Delete(i); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8c0360f45..b7be85beb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1995,7 +1995,7 @@ procedure TMainForm.btURLClick(Sender: TObject); if regx.Exec(edURL.Text) then begin host := regx.Replace(edURL.Text, '$2', True); - link := regx.Replace(edURL.Text, '$3', True); + link := regx.Replace(edURL.Text, '$4', True); end; if (host <> '') and (link <> '') then From d86d099d1dcbe88f8ef428bc57c88fe862162ae3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 14:20:17 +0800 Subject: [PATCH 0233/2794] fix url redirection with empty host --- baseunits/uBaseUnit.pas | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 27db6b639..df8f90ced 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2875,17 +2875,17 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; end; counter := 0; - while (HTTP.ResultCode = 302) or (HTTP.ResultCode = 301) do + while (HTTP.ResultCode > 300) and (HTTP.ResultCode < 400) do begin if checkTerminate then Exit; HTTPHeader.Values['Referer'] := ' ' + URL; s := Trim(HTTP.Headers.Values['Location']); - s := TrimLeftChar(s, ['/', ':']); if s <> '' then begin - if LowerCase(Copy(s, 1, 4)) <> 'http' then - s := 'http://' + s; - URL := s; + if s[1] = '/' then + URL := ReplaceRegExpr(REGEX_HOST, URL, '$1$2$3', True) + s + else + URL := s; end; if Pos(HENTAI2READ_ROOT, URL) <> 0 then @@ -3124,7 +3124,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; counter := 0; - while (HTTP.ResultCode = 302) or (HTTP.ResultCode = 301) do + while (HTTP.ResultCode > 300) and (HTTP.ResultCode < 400) do begin {$IFDEF DOWNLOADER} if checkTerminate then Exit; @@ -3132,12 +3132,12 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTPHeader.Values['Referer'] := ' ' + URL; s := Trim(HTTP.Headers.Values['Location']); - s := TrimLeftChar(s, ['/', ':']); if s <> '' then begin - if LowerCase(Copy(s, 1, 4)) <> 'http' then - s := 'http://' + s; - URL := s; + if s[1] = '/' then + URL := ReplaceRegExpr(REGEX_HOST, URL, '$1$2$3', True) + s + else + URL := s; end; HTTP.Clear; From e1ffd576964fcd79ea14803bc375fc39cf576c9f Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 14:30:29 +0800 Subject: [PATCH 0234/2794] updatethread, remove duplicate only if there is record in database --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 1b05a985a..629feb5b5 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -667,7 +667,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.OpenTable('', True); // remove duplicate found<>current database - if links.Count > 0 then + if (links.Count > 0) and (mainDataProcess.RecordCount > 0) then begin c := 0; j := 0; From 77e0aae1995f01f80bfa129f6368a3b4f3ef393a Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 14:40:55 +0800 Subject: [PATCH 0235/2794] updatethread, increase checkcommit to 32 --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 629feb5b5..1da31b761 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -214,7 +214,7 @@ procedure TUpdateMangaThread.Execute; try Info.AddInfoToData(manager.names[workPtr], manager.links[workPtr], manager.mainDataProcess); - manager.CheckCommit(16); + manager.CheckCommit(32); finally manager.CS_AddInfoToData.Release; end; From 5798f4d9007af602756eae1820123669db6649d8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 14:49:42 +0800 Subject: [PATCH 0236/2794] updatethread, minor changes --- baseunits/uUpdateThread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 1da31b761..c037d3dbf 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -665,8 +665,8 @@ procedure TUpdateMangaManagerThread.Execute; end; end; - mainDataProcess.OpenTable('', True); // remove duplicate found<>current database + mainDataProcess.OpenTable('', True); if (links.Count > 0) and (mainDataProcess.RecordCount > 0) then begin c := 0; @@ -681,7 +681,7 @@ procedure TUpdateMangaManagerThread.Execute; if Terminated then Break; Inc(c); - if c > 499 then + if c > 249 then begin c := 0; MainForm.ulTotalPtr := links.Count; From 59be9b7527349acd4b4809596068fa01b6c6e905 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 16:30:23 +0800 Subject: [PATCH 0237/2794] updtethread, tdbdataprocess, faster way to locate link --- baseunits/uData.pas | 38 ++++++++++++++++++++++++++++++++++++- baseunits/uUpdateThread.pas | 6 ++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 797d0f9b6..bd5c80f86 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -44,6 +44,7 @@ TDBDataProcess = class(TObject) FAttachedSites: TStringList; FSQLSelect: String; FFilterSQL: String; + FLinks: TStringList; protected procedure CreateTable; procedure VacuumTable; @@ -76,7 +77,11 @@ TDBDataProcess = class(TObject) const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; function LocateByLink(ALink: String): Boolean; + function WebsiteLoaded(const AWebsite: String): Boolean; + function LinkExist(ALink: String): Boolean; + procedure InitLocateLink; + procedure DoneLocateLink; procedure CreateDatabase(AWebsite: String = ''); procedure GetFieldNames(List: TStringList); procedure Close; @@ -93,7 +98,6 @@ TDBDataProcess = class(TObject) procedure Commit; procedure RemoveFilter; procedure Sort; - function WebsiteLoaded(const AWebsite: String): Boolean; property Website: String read FWebsite write FWebsite; property TableName: String read FTableName write FTableName; @@ -629,6 +633,7 @@ destructor TDBDataProcess.Destroy; on E: Exception do WriteLog_E('TDBDataProcess.Destroy.Error!', E, Self); end; + DoneLocateLink; FAttachedSites.Free; FSitesList.Free; FQuery.Free; @@ -1181,6 +1186,37 @@ function TDBDataProcess.WebsiteLoaded(const AWebsite: String): Boolean; end; end; +function TDBDataProcess.LinkExist(ALink: String): Boolean; +var + i: Integer; +begin + Result := FLinks.Find(ALink, i); +end; + +procedure TDBDataProcess.InitLocateLink; +begin + if Assigned(FLinks) then + FLinks.Clear + else + FLinks := TStringList.Create; + if FQuery.Active then + begin + FQuery.First; + repeat + FLinks.Add(FQuery.Fields[1].AsString); + FQuery.Next; + until FQuery.EOF; + if FLinks.Count > 0 then + FLinks.Sort; + end; +end; + +procedure TDBDataProcess.DoneLocateLink; +begin + if Assigned(FLinks) then + FreeAndNil(FLinks); +end; + // ----- TDataProcess ----- constructor TDataProcess.Create; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index c037d3dbf..e75523267 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -676,19 +676,20 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromCurrentData + '...'; Synchronize(MainThreadShowGetting); + mainDataProcess.InitLocateLink; while j < links.Count do begin if Terminated then Break; Inc(c); - if c > 249 then + if c > 999 then begin c := 0; MainForm.ulTotalPtr := links.Count; MainForm.ulWorkPtr := j; Synchronize(MainThreadStatusRepaint); end; - if mainDataProcess.LocateByLink(links[j]) then + if mainDataProcess.LinkExist(links[j]) then begin links.Delete(j); names.Delete(j); @@ -696,6 +697,7 @@ procedure TUpdateMangaManagerThread.Execute; else Inc(j); end; + mainDataProcess.DoneLocateLink; end; mainDataProcess.CloseTable; From 392e667292e41f9bce6172021caab7759506fdcf Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 18:09:38 +0800 Subject: [PATCH 0238/2794] baseunit, move data_folder to var --- baseunits/uBaseUnit.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index df8f90ced..ba44d36cd 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -202,7 +202,6 @@ interface DOWNLOADEDCHAPTERS_FILE = 'downloadedchapters.ini'; FAVORITES_FILE = 'favorites.ini'; IMAGE_FOLDER = 'images' + PathDelim; - DATA_FOLDER = 'data' + PathDelim; DATA_EXT = '.dat'; DBDATA_EXT = '.db'; CONFIG_FOLDER = 'config' + PathDelim; @@ -650,8 +649,10 @@ interface var FMD_VERSION_NUMBER: String = ''; + DATA_FOLDER: String = 'data' + PathDelim; + {$IFDEF WINDOWS} - DEFAULT_PATH : string = '/downloads'; + DEFAULT_PATH : string = '\downloads'; {$ELSE} DEFAULT_PATH: string = '/downloads'; {$ENDIF} From eedbf50fa3643fe659cbdf6f2ca22a1f283cfa10 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 18:15:44 +0800 Subject: [PATCH 0239/2794] dataprocess, fix path --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index bd5c80f86..5d8bb384e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1344,7 +1344,7 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; l: TStringList; Filename: String; begin - Filename := DATA_FOLDER + website; + Filename := fmdDirectory + DATA_FOLDER + website; Data.Clear; searchPos.Clear; From 18ddf9af34e64004c926a6f71494686ac0c0ddb5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 23 Jul 2015 18:23:37 +0800 Subject: [PATCH 0240/2794] baseunit, change data url to db --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ba44d36cd..dfb5e7ae5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1244,7 +1244,7 @@ function GetMangaSiteRoot(const MangaID : Cardinal) : String; // bad coding.. but this is how FMD works function GetMangaDatabaseURL(const Name: String): String; begin - Result := 'https://bintray.com/artifact/download/riderkick/FMD/data/' + Name + '.7z'; + Result := 'https://bintray.com/artifact/download/riderkick/FMD/db/' + Name + '.7z'; end; function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; From 7f33011ac045694146a286df9a0f842f99172391 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 24 Jul 2015 16:14:21 +0800 Subject: [PATCH 0241/2794] getmangainfo, fix sometimes thumbnail can't be loaded --- baseunits/uGetMangaInfosThread.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 5ca2531b2..9548001d9 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -140,7 +140,10 @@ procedure TGetMangaInfosThread.DoGetInfos; FCover.Clear; // If there's cover then we will load it to the TPicture component. if OptionEnableLoadCover and (Trim(FInfo.mangaInfo.coverLink) <> '') then + begin + FInfo.FHTTP.Document.Clear; FIsHasMangaCover := GetPage(FInfo.FHTTP, TObject(FCover), FInfo.mangaInfo.coverLink, 3) + end else FIsHasMangaCover := False; Synchronize(MainThreadShowCover); From 9375258739c3c44f402f927de4a244cb5fa90542 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 24 Jul 2015 16:26:01 +0800 Subject: [PATCH 0242/2794] baseunit, fix getpage and saveimage redirection --- baseunits/uBaseUnit.pas | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dfb5e7ae5..d86b7b13c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2883,10 +2883,20 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; s := Trim(HTTP.Headers.Values['Location']); if s <> '' then begin - if s[1] = '/' then - URL := ReplaceRegExpr(REGEX_HOST, URL, '$1$2$3', True) + s - else - URL := s; + with TRegExpr.Create do + try + Expression := REGEX_HOST; + if Replace(s, '$1', True) = '' then + begin + if s[1] <> '/' then + s := '/' + s; + URL := Replace(URL, '$1$2$3', True) + s; + end + else + URL := s; + finally + Free; + end; end; if Pos(HENTAI2READ_ROOT, URL) <> 0 then @@ -3135,10 +3145,20 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; s := Trim(HTTP.Headers.Values['Location']); if s <> '' then begin - if s[1] = '/' then - URL := ReplaceRegExpr(REGEX_HOST, URL, '$1$2$3', True) + s - else - URL := s; + with TRegExpr.Create do + try + Expression := REGEX_HOST; + if Replace(s, '$1', True) = '' then + begin + if s[1] <> '/' then + s := '/' + s; + URL := Replace(URL, '$1$2$3', True) + s; + end + else + URL := s; + finally + Free; + end; end; HTTP.Clear; From 81ba61924e9362e55ff7ada2cdebb0f1ed7ee504 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 24 Jul 2015 16:29:56 +0800 Subject: [PATCH 0243/2794] baseunit, saveimage add common default request header --- baseunits/uBaseUnit.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d86b7b13c..c24bc6489 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3075,6 +3075,9 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; HTTPHeader.Values['DNT'] := ' 1'; + HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; + HTTPHeader.Values['Accept-Charset'] := ' UTF-8'; + HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.Timeout := OptionConnectionTimeout; From b6c323a17b37666f0836762acb681028ed8989db Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 24 Jul 2015 16:31:34 +0800 Subject: [PATCH 0244/2794] m#h#160 add getcurpic function convert from js --- baseunits/modules/mh160com.pas | 108 ++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 8348d92b6..7534289a4 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - LConvEncoding, HTMLUtil, base64, RegExpr; + synacode, synautil, LConvEncoding, HTMLUtil, base64, RegExpr; implementation @@ -162,6 +162,105 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; +function padZero(const S: String; len: Integer): String; +begin + Result := S; + while Length(Result) < len do + Result := '0' + Result; +end; + +function getcurpic_skin4_20110501(const URL: String): String; + + function getrealurl(const S: String): String; + begin + Result := S; + if Pos('img1.fshmy.com', S) <> 0 then + Result := StringReplace(S, 'img1.fshmy.com', 'img1.hgysxz.cn', []) + else if Pos('imgs.k6188.com', S) <> 0 then + Result := StringReplace(S, 'imgs.k6188.com', 'imgs.zhujios.com', []) + else if Pos('073.k6188.com', S) <> 0 then + Result := StringReplace(S, '073.k6188.com', 'cartoon.zhujios.com', []) + else if Pos('cartoon.jide123.cc', S) <> 0 then + Result := StringReplace(S, 'cartoon.jide123.cc', + 'cartoon.shhh88.com', []) + else if Pos('www.jide123.com', S) <> 0 then + Result := StringReplace(S, 'www.jide123.com', 'cartoon.shhh88.com', []) + else if Pos('cartoon.chuixue123.com', S) <> 0 then + Result := StringReplace(S, 'cartoon.chuixue123.com', + 'cartoon.shhh88.com', []) + else if Pos('p10.tuku.cc:8899', S) <> 0 then + Result := StringReplace(S, 'p10.tuku.cc:8899', 'tkpic.tukucc.com', []); + end; + + function getkekerealurl(const S: String): String; + var + i: Integer; + sn: String; + begin + Result := S; + for i := 1 to 15 do + begin + sn := '/dm' + padZero(IntToStr(i), 2) + '/'; + if Pos(sn, S) <> 0 then + begin + Result := 'http://2.cococomic.com:9115' + sn + SeparateRight(S, sn); + Break; + end; + end; + end; + + function getremoteqqurl(const S: String): String; + var + qqfilename: String; + begin + Result := S; + qqfilename := SeparateRight(S, 'dir_path=/'); + qqfilename := StringReplace(qqfilename, '&name', '', []); + qqfilename := StringReplace(qqfilename, 'mif2', 'jpg', []); + qqfilename := StringReplace(qqfilename, '/', '_', [rfReplaceAll]); + Result := 'http://img11.aoyuanba.com/pictmdown.php?p=' + + EncodeStringBase64(S) + '$sf=' + qqfilename + + '&ym=' + 'http://img11.hgysxz.cn'; + end; + +begin + Result := URL; + if Pos('qq.com/store_file_download', URL) <> 0 then + Result := getremoteqqurl(URL) + else + if Pos('/ok-comic', URL) <> 0 then + Result := getkekerealurl(URL) + else if Pos('mangafiles.com', URL) <> 0 then + Result := 'http://img6.aoyuanba.com:8056/pictmdown.php?p=' + EncodeStringBase64(URL) + else if Pos('imgs.gengxin123.com', URL) <> 0 then + begin + Result := StringReplace(URL, 'imgs.gengxin123.com', 'imgs1.ysryd.com', + [rfIgnoreCase]); + Result := 'http://imgsty1.aoyuanba.com/pictmdown.php?bu=' + 'http://www.kxdm.com/' + + '&p=' + EncodeStringBase64(Result); + end + else if Pos('imgs1.ysryd.com', URL) <> 0 then + Result := 'http://imgsty1.aoyuanba.com/pictmdown.php?bu=' + + 'http://www.kxdm.com/' + '&p=' + EncodeStringBase64(URL) + else if Pos('dmzj.com', URL) <> 0 then + Result := 'http://imgsty.aoyuanba.com:8056/pictmdown.php?bu=' + + 'http://manhua.dmzj.com/' + '&p=' + EncodeStringBase64(EncodeURL(URL)) + else if Pos('imgsrc.baidu.com', URL) <> 0 then + Result := 'http://img7.aoyuanba.com:8056/picinc/qTcms.Pic.FangDao.asp?p=' + + EncodeStringBase64(URL) + else if Pos('sinaimg.cn', URL) <> 0 then + Result := 'http://img7.aoyuanba.com:8056/picinc/qTcms.Pic.FangDao.asp?p=' + + EncodeStringBase64(URL) + else if Pos('jumpcn.cc', URL) <> 0 then + Result := 'http://img7.aoyuanba.com:8056/picinc/qTcms.Pic.FangDao.asp?p=' + + EncodeStringBase64(URL) + else if Pos('JLmh160', URL) <> 0 then + Result := 'http://img3.aoyuanba.com/picinc/qTcms.Pic.FangDao.asp?p=' + + EncodeStringBase64(URL) + else + Result := getrealurl(URL); +end; + function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var @@ -211,7 +310,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; function ScanSource: Boolean; var i: Integer; - jsurl: String = ''; + //jsurl: String = ''; begin Result := False; Regx.Expression := '(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$'; @@ -222,7 +321,11 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; picTree := DecodeStringBase64(picTree); picTree := StringReplace(picTree, '$qingtiandy$', #13#10, [rfReplaceAll]); Container.PageLinks.AddText(picTree); + if Container.PageLinks.Count > 0 then + for i := 0 to Container.PageLinks.Count - 1 do + Container.PageLinks[i] := getcurpic_skin4_20110501(Container.PageLinks[i]); + { if Container.PageLinks.Count > 0 then begin for i := 0 to Source.Count - 1 do @@ -245,6 +348,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; end; + } end; end; From 384c3f25fc1faab831d4ae6756e92e08c03ff250 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 24 Jul 2015 16:57:15 +0800 Subject: [PATCH 0245/2794] mh#160, clean up --- baseunits/modules/mh160com.pas | 65 ---------------------------------- 1 file changed, 65 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 7534289a4..834712fba 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -269,53 +269,13 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Regx: TRegExpr; picTree: String; - procedure GetURLs; - var - realurls: TStringList; - i, j: Integer; - r, u: String; - begin - realurls := TStringList.Create; - try - realurls.NameValueSeparator := '='; - Regx.Expression := '(?ig)^.*realurl\.replace\("(.+)","(.+)".*$'; - for i := 0 to Source.Count - 1 do - begin - if Regx.Exec(Source[i]) then - begin - r := Trim(LowerCase(Regx.Replace(Source[i], '$1', True))); - u := Trim(LowerCase(Regx.Replace(Source[i], '$2', True))); - if (r <> '') and (u <> '') then - realurls.Values[r] := u; - end; - end; - - if (realurls.Count > 0) and (Container.PageLinks.Count > 0) then - begin - for i := 0 to Container.PageLinks.Count - 1 do - begin - for j := 0 to realurls.Count - 1 do - begin - if Pos(realurls.Names[j], LowerCase(Container.PageLinks[i])) <> 0 then - Container.PageLinks[i] := StringReplace(Container.PageLinks[i], - realurls.Names[j], realurls.ValueFromIndex[j], [rfIgnoreCase]); - end; - end; - end; - finally - realurls.Free; - end; - end; - function ScanSource: Boolean; var i: Integer; - //jsurl: String = ''; begin Result := False; Regx.Expression := '(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$'; picTree := Regx.Replace(Source.Text, '$1', True); - if picTree <> '' then begin picTree := DecodeStringBase64(picTree); @@ -324,31 +284,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; if Container.PageLinks.Count > 0 then for i := 0 to Container.PageLinks.Count - 1 do Container.PageLinks[i] := getcurpic_skin4_20110501(Container.PageLinks[i]); - - { - if Container.PageLinks.Count > 0 then - begin - for i := 0 to Source.Count - 1 do - if (Pos(' 0) and - (Pos('/base64.js', Source[i]) <> 0) then - begin - jsurl := GetVal(Source[i], 'src'); - jsurl := StringReplace(jsurl, '../..', Module.RootURL, []); - Break; - end; - if jsurl <> '' then - begin - Source.Clear; - if DownloadThread.GetPage(TObject(Source), jsurl, - Container.Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - GetURLs; - end; - end; - end; - } end; end; From dc575d35ef1d9cb71174773d70ee01c2e7f8209e Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 24 Jul 2015 17:02:11 +0800 Subject: [PATCH 0246/2794] update changelog --- changelog.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/changelog.txt b/changelog.txt index 20dc3f8c5..0238d9cf3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,18 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.0 (xx-07-2015) +[+] Mangalist data now using sqlite3, existing data will be automatically converted. + BUGS EXPECTED! +[*] Opening mangalist will be executed in separated thread, access to mangalist will be blocked until the process finish +[*] Search mangalist will be executed in separated thread, eleminate lag when searching large mangalist +[+] Added Soujosense (EN) +[+] Added mh160 (CN) +[*] Fix freeze in the middle of shutdown counter +[*] Fix Readmanga.today +[*] Fix various issue with unicode path +[*] Various changes and bug fixes + 0.9.18.2 (05-07-2015) [*] Minor bug fixes From 800dec4af26794dac4d58bc578e65455654eaadf Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 00:17:46 +0800 Subject: [PATCH 0247/2794] mainform, disable panning and other chart mouse action fix #78 --- mangadownloader/forms/frmMain.lfm | 5 +++++ mangadownloader/forms/frmMain.pas | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b56d55a1e..d3971966d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -186,6 +186,7 @@ object MainForm: TMainForm Title.Text.Strings = ( 'TAChart' ) + Toolset = TransferRateToolset Align = alClient BorderSpacing.Bottom = 2 Visible = False @@ -5705,4 +5706,8 @@ object MainForm: TMainForm left = 648 top = 72 end + object TransferRateToolset: TChartToolset + left = 608 + top = 72 + end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b7be85beb..decbebf56 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -19,7 +19,7 @@ interface Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, - FileUtil, TAGraph, TASources, TASeries, AnimatedGif, + FileUtil, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, USimpleException, USimpleLogger; @@ -60,6 +60,7 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + TransferRateToolset: TChartToolset; miFavoritesStopCheckNewChapter: TMenuItem; miFavoritesCheckNewChapter: TMenuItem; pnDownloadToolbarLeft: TPanel; From ea9f3b0b768509152ef6608a65265155ab8fabc2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 00:34:32 +0800 Subject: [PATCH 0248/2794] m$h160, various changes for efficiency --- baseunits/modules/mh160com.pas | 52 ++++++++++++++++------------------ 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 834712fba..4e818fbb1 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -50,10 +50,9 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; diralpha[StrToInt(URL) + 1] + '.html', 3) then begin Result := NO_ERROR; - Source.Text := CP936ToUTF8(Source.Text); Parse := TStringList.Create; try - ParseHTML(Source.Text, Parse); + ParseHTML(CP936ToUTF8(Source.Text), Parse); if Parse.Count > 0 then ScanParse; finally @@ -147,10 +146,9 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then begin Result := NO_ERROR; - Source.Text := CP936ToUTF8(Source.Text); Parse := TStringList.Create; try - ParseHTML(Source.Text, Parse); + ParseHTML(CP936ToUTF8(Source.Text), Parse); if Parse.Count > 0 then ScanParse; finally @@ -264,27 +262,29 @@ function getcurpic_skin4_20110501(const URL: String): String; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; + Source, Parse: TStringList; Container: TTaskContainer; - Regx: TRegExpr; - picTree: String; - function ScanSource: Boolean; + procedure ScanParse; var i: Integer; + picTree: String; begin - Result := False; - Regx.Expression := '(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$'; - picTree := Regx.Replace(Source.Text, '$1', True); - if picTree <> '' then + for i := 0 to Parse.Count - 1 do begin - picTree := DecodeStringBase64(picTree); - picTree := StringReplace(picTree, '$qingtiandy$', #13#10, [rfReplaceAll]); - Container.PageLinks.AddText(picTree); - if Container.PageLinks.Count > 0 then - for i := 0 to Container.PageLinks.Count - 1 do - Container.PageLinks[i] := getcurpic_skin4_20110501(Container.PageLinks[i]); + if Pos('var picTree', Parse[i]) <> 0 then + begin + picTree := ReplaceRegExpr('(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$', + Parse[i], '$1', True); + picTree := DecodeStringBase64(picTree); + picTree := StringReplace(picTree, '$qingtiandy$', #13#10, [rfReplaceAll]); + Container.PageLinks.AddText(picTree); + Break; + end; end; + if Container.PageLinks.Count > 0 then + for i := 0 to Container.PageLinks.Count - 1 do + Container.PageLinks[i] := getcurpic_skin4_20110501(Container.PageLinks[i]); end; begin @@ -300,15 +300,13 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), Container.Manager.retryConnect) then begin - if Source.Count > 0 then - begin - Regx := TRegExpr.Create; - try - Source.Text := CP936ToUTF8(Source.Text); - Result := ScanSource; - finally - Regx.Free; - end; + Parse := TStringList.Create; + try + ParseHTML(CP936ToUTF8(Source.Text), Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; end; end; finally From 43b430400b776802a3e78e387949006fdd9fbd06 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 00:40:30 +0800 Subject: [PATCH 0249/2794] mainform, always save selected website --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index decbebf56..922c59f93 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2126,6 +2126,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); begin if cbSelectManga.ItemIndex < 0 then Exit; + options.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then begin if dataProcess = nil then From 5dd0aeb9346e64858bd04a8947f1e5f6f17fb16e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 00:50:38 +0800 Subject: [PATCH 0250/2794] mainform, always save active website --- mangadownloader/forms/frmMain.pas | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 922c59f93..31c7ecb9f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -870,7 +870,6 @@ procedure TOpenDBThread.SyncOpenFinish; begin with MainForm do begin - currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; LastSearchStr := upcase(edSearch.Text); LastSearchWeb := currentWebsite; if dataProcess.Filtered then @@ -2129,16 +2128,17 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); options.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then begin - if dataProcess = nil then - dataProcess := TDBDataProcess.Create; - vtMangaList.Clear; - lbMode.Caption := Format(RS_ModeAll, [0]); - if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then - begin - OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); - end - else - RunGetList; + currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; + if dataProcess = nil then + dataProcess := TDBDataProcess.Create; + vtMangaList.Clear; + lbMode.Caption := Format(RS_ModeAll, [0]); + if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then + begin + OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); + end + else + RunGetList; end; end; From 327d1329a14f1e28d5a83393e7759704342e65f4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 00:55:22 +0800 Subject: [PATCH 0251/2794] m^h160, minor changes --- baseunits/modules/mh160com.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 4e818fbb1..341b0c120 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -300,6 +300,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), Container.Manager.retryConnect) then begin + Result := True; Parse := TStringList.Create; try ParseHTML(CP936ToUTF8(Source.Text), Parse); From eba9097c7711373d5b90dbab4f53579eaf4edb8d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 01:07:05 +0800 Subject: [PATCH 0252/2794] updatethread, use locatelink --- baseunits/uData.pas | 15 ++++++++++++++- baseunits/uUpdateThread.pas | 15 ++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5d8bb384e..a504359d6 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -45,6 +45,7 @@ TDBDataProcess = class(TObject) FSQLSelect: String; FFilterSQL: String; FLinks: TStringList; + function GetLinkCount: Integer; protected procedure CreateTable; procedure VacuumTable; @@ -108,6 +109,7 @@ TDBDataProcess = class(TObject) property SitesList: TStringList read FSitesList write FSitesList; property WebsiteName[RecIndex: Integer]: String read GetWebsiteName; property Value[RecIndex, ParamNo: Integer]: String read GetValue; + property LinkCount: Integer read GetLinkCount; end; { TDataProcess } @@ -393,6 +395,14 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); { TDBDataProcess } +function TDBDataProcess.GetLinkCount: Integer; +begin + if Assigned(FLinks) then + Result := FLinks.Count + else + Result := 0; +end; + procedure TDBDataProcess.CreateTable; begin if FConn.Connected then @@ -1190,7 +1200,10 @@ function TDBDataProcess.LinkExist(ALink: String): Boolean; var i: Integer; begin - Result := FLinks.Find(ALink, i); + if Assigned(FLinks) then + Result := FLinks.Find(ALink, i) + else + Result := False; end; procedure TDBDataProcess.InitLocateLink; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e75523267..cd6daaf0a 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -187,7 +187,7 @@ procedure TUpdateMangaThread.Execute; if SitesWithSortedList(manager.website) then begin if links.Count > 0 then - if manager.mainDataProcess.LocateByLink(links.Strings[0]) then + if manager.mainDataProcess.LinkExist(links.Strings[0]) then manager.isFinishSearchingForNewManga := True; end; @@ -588,6 +588,10 @@ procedure TUpdateMangaManagerThread.Execute; if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); + mainDataProcess.OpenTable; + mainDataProcess.InitLocateLink; + mainDataProcess.CloseTable; + //get directory page count INIAdvanced.Reload; directoryCount := 0; @@ -666,8 +670,7 @@ procedure TUpdateMangaManagerThread.Execute; end; // remove duplicate found<>current database - mainDataProcess.OpenTable('', True); - if (links.Count > 0) and (mainDataProcess.RecordCount > 0) then + if (links.Count > 0) and (mainDataProcess.LinkCount > 0) then begin c := 0; j := 0; @@ -676,7 +679,6 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromCurrentData + '...'; Synchronize(MainThreadShowGetting); - mainDataProcess.InitLocateLink; while j < links.Count do begin if Terminated then @@ -697,9 +699,9 @@ procedure TUpdateMangaManagerThread.Execute; else Inc(j); end; - mainDataProcess.DoneLocateLink; end; - mainDataProcess.CloseTable; + + mainDataProcess.DoneLocateLink; //get manga info if links.Count > 0 then @@ -739,7 +741,6 @@ procedure TUpdateMangaManagerThread.Execute; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); - mainDataProcess.CloseTable; mainDataProcess.Sort; mainDataProcess.Close; Synchronize(RefreshList); From d178ceef476fd891927e9ffd28cee6319ce4891b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 01:09:56 +0800 Subject: [PATCH 0253/2794] updatethread, save on terminate --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index cd6daaf0a..38a61ca1b 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -736,7 +736,7 @@ procedure TUpdateMangaManagerThread.Execute; names.Clear; links.Clear; - if (workPtr > 0) and ((not Terminated) or (not SitesWithSortedList(website))) then + if (workPtr > 0) and (not SitesWithSortedList(website)) then begin FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; From 89e32883265da3a316e7170a7662398bcc4a8b31 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 01:42:24 +0800 Subject: [PATCH 0254/2794] updatethread, minor changes --- baseunits/uUpdateThread.pas | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 38a61ca1b..269fa94df 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -402,7 +402,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; procedure WaitForThreads; begin while threads.Count > 0 do - Sleep(200); + Sleep(SOCKHEARTBEATRATE); end; procedure TerminateThreads; @@ -469,7 +469,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; TerminateThreads; Break; end; - Sleep(250); //waiting for empty slot / slowing down the circle + Sleep(SOCKHEARTBEATRATE); //waiting for empty slot / slowing down the circle end; if Terminated then @@ -524,7 +524,7 @@ procedure TUpdateMangaManagerThread.DoTerminate; begin Synchronize(MainThreadEndGetting); while threads.Count > 0 do - Sleep(200); + Sleep(SOCKHEARTBEATRATE); inherited DoTerminate; end; @@ -537,9 +537,16 @@ procedure TUpdateMangaManagerThread.Execute; while threads.Count > 0 do begin if Terminated then - for i := threads.Count - 1 downto 0 do - TUpdateMangaThread(threads[i]).Terminate; - Sleep(200); + begin + CS_threads.Acquire; + try + for i := threads.Count - 1 downto 0 do + TUpdateMangaThread(threads[i]).Terminate; + finally + CS_threads.Release; + end; + end; + Sleep(SOCKHEARTBEATRATE); end; end; From 51fc6ff0977224a96e623048ffdc1a101d99d34d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 02:11:53 +0800 Subject: [PATCH 0255/2794] updatethread, create object if needed only --- baseunits/uData.pas | 15 +++-- baseunits/uUpdateThread.pas | 124 ++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a504359d6..a74158186 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -180,7 +180,7 @@ TMangaInformation = class(TObject) procedure OnTag(NoCaseTag, ActualTag: String); procedure OnText(Text: String); - constructor Create(AOwnerThread: TFMDThread = nil); + constructor Create(AOwnerThread: TFMDThread = nil; CreateInfo: Boolean = True); destructor Destroy; override; procedure ClearInfo; function GetDirectoryPage(var Page: Integer; const website: String): Byte; @@ -1834,21 +1834,24 @@ procedure TDataProcess.Sort; { TMangaInformation } -constructor TMangaInformation.Create(AOwnerThread: TFMDThread); +constructor TMangaInformation.Create(AOwnerThread: TFMDThread; + CreateInfo: Boolean); begin inherited Create; FHTTP := THTTPSendThread.Create(AOwnerThread); FHTTP.Headers.NameValueSeparator := ':'; parse := TStringList.Create; - mangaInfo := TMangaInfo.Create; + if CreateInfo then + mangaInfo := TMangaInfo.Create; isGetByUpdater := False; end; destructor TMangaInformation.Destroy; begin - ClearInfo; - mangaInfo.Free; - parse.Free; + if Assigned(mangaInfo) then + mangaInfo.Free; + if Assigned(parse) then + parse.Free; FHTTP.Free; inherited Destroy; end; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 269fa94df..d5ba563e2 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -21,13 +21,11 @@ TUpdateMangaManagerThread = class; TUpdateMangaThread = class(TFMDThread) protected + Info: TMangaInformation; checkStyle: TCheckStyleType; - names, links: TStringList; workPtr: Integer; manager: TUpdateMangaManagerThread; - Info: TMangaInformation; - procedure MainThreadUpdateNamesAndLinks; procedure Execute; override; procedure DoTerminate; override; public @@ -93,36 +91,31 @@ implementation uses frmMain, Dialogs, ComCtrls, Forms, Controls, USimpleLogger; -// ----- TUpdateMangaThread ----- +{ TUpdateMangaThread } constructor TUpdateMangaThread.Create; begin inherited Create(True); - names := TStringList.Create; - links := TStringList.Create; - Info := TMangaInformation.Create(Self); - info.isGetByUpdater := True; end; destructor TUpdateMangaThread.Destroy; begin - links.Free; - names.Free; - Info.Free; + if Assigned(Info) then + Info.Free; inherited Destroy; end; -procedure TUpdateMangaThread.MainThreadUpdateNamesAndLinks; -begin - if names.Count = 0 then - Exit; - manager.links.AddStrings(links); - manager.names.AddStrings(names); -end; - procedure TUpdateMangaThread.Execute; +var + names, links: TStringList; begin try + if checkStyle = CS_INFO then + Info := TMangaInformation.Create(Self, True) + else + Info := TMangaInformation.Create(Self, False); + Info.isGetByUpdater := True; + case CheckStyle of CS_DIRECTORY_COUNT: begin @@ -148,58 +141,65 @@ procedure TUpdateMangaThread.Execute; //get names and links CS_DIRECTORY_PAGE, CS_DIRECTORY_PAGE_2: begin - if BROWSER_INVERT then - begin - if checkStyle = CS_DIRECTORY_PAGE then - workPtr := manager.directoryCount - workPtr - 1 - else - if checkStyle = CS_DIRECTORY_PAGE_2 then - workPtr := manager.directoryCount2 - workPtr - 1; - end; - if SitesMemberOf(manager.website, - [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then - begin - if checkStyle = CS_DIRECTORY_PAGE then + names := TStringList.Create; + links := TStringList.Create; + try + if BROWSER_INVERT then begin - BATOTO_BROWSER := BATOTO_BROWSER_1; - FAKKU_BROWSER := FAKKU_BROWSER_1; - MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_1; - PERVEDEN_BROWSER := PERVEDEN_BROWSER_1; - Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); + if checkStyle = CS_DIRECTORY_PAGE then + workPtr := manager.directoryCount - workPtr - 1 + else + if checkStyle = CS_DIRECTORY_PAGE_2 then + workPtr := manager.directoryCount2 - workPtr - 1; + end; + if SitesMemberOf(manager.website, + [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then + begin + if checkStyle = CS_DIRECTORY_PAGE then + begin + BATOTO_BROWSER := BATOTO_BROWSER_1; + FAKKU_BROWSER := FAKKU_BROWSER_1; + MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_1; + PERVEDEN_BROWSER := PERVEDEN_BROWSER_1; + Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); + end + else + if checkStyle = CS_DIRECTORY_PAGE_2 then + begin + BATOTO_BROWSER := BATOTO_BROWSER_2; + FAKKU_BROWSER := FAKKU_BROWSER_2; + MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_2; + PERVEDEN_BROWSER := PERVEDEN_BROWSER_2; + Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); + end; end else - if checkStyle = CS_DIRECTORY_PAGE_2 then begin - BATOTO_BROWSER := BATOTO_BROWSER_2; - FAKKU_BROWSER := FAKKU_BROWSER_2; - MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_2; - PERVEDEN_BROWSER := PERVEDEN_BROWSER_2; Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); end; - end - else - begin - Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); - end; - //if website has sorted list by latest added - //we will stop at first found against current db - if SitesWithSortedList(manager.website) then - begin - if links.Count > 0 then - if manager.mainDataProcess.LinkExist(links.Strings[0]) then - manager.isFinishSearchingForNewManga := True; - end; + //if website has sorted list by latest added + //we will stop at first found against current db + if SitesWithSortedList(manager.website) then + begin + if links.Count > 0 then + if manager.mainDataProcess.LinkExist(links.Strings[0]) then + manager.isFinishSearchingForNewManga := True; + end; - if links.Count > 0 then - begin - manager.CS_AddNamesAndLinks.Acquire; - try - manager.links.AddStrings(links); - manager.names.AddStrings(names); - finally - manager.CS_AddNamesAndLinks.Release; + if links.Count > 0 then + begin + manager.CS_AddNamesAndLinks.Acquire; + try + manager.links.AddStrings(links); + manager.names.AddStrings(names); + finally + manager.CS_AddNamesAndLinks.Release; + end; end; + finally + names.Free; + links.Free; end; end; From 4b2c0357e89cd3f27e762c0b55fd564d10d5931e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 02:29:53 +0800 Subject: [PATCH 0256/2794] updatethread, minor changes --- baseunits/uUpdateThread.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index d5ba563e2..091e9c68a 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -468,8 +468,9 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; begin TerminateThreads; Break; - end; - Sleep(SOCKHEARTBEATRATE); //waiting for empty slot / slowing down the circle + end + else + Sleep(SOCKHEARTBEATRATE); //waiting for empty slot / slowing down the circle end; if Terminated then From 296c5d309a67ef501a66927487fba1c13cf5df78 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 03:23:04 +0800 Subject: [PATCH 0257/2794] clean up --- baseunits/uData.pas | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a74158186..57eddd05c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2630,7 +2630,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; s: String; j, k: Integer; del: Boolean; - rex: TRegExpr; Source: TStringList; Parser: THTMLParser; WebsiteID: Cardinal; @@ -3115,21 +3114,12 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; //mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\r\n\r\n', '\r\n', [rfReplaceAll])); // fix info - rex := TRegExpr.Create; - try - rex.Expression := '^[\-\:]$'; - if rex.Exec(mangaInfo.authors) then - mangaInfo.authors := ''; - if rex.Exec(mangaInfo.artists) then - mangaInfo.artists := ''; - if rex.Exec(mangaInfo.summary) then - mangaInfo.summary := ''; - rex.Expression := '\<\/?\w\>'; - if rex.Exec(LowerCase(mangaInfo.summary)) then - mangaInfo.summary := ''; - finally - rex.Free; - end; + if (mangaInfo.authors = '-') or (mangaInfo.authors = ':') then + mangaInfo.authors := ''; + if (mangaInfo.artists = '-') or (mangaInfo.artists = ':') then + mangaInfo.artists := ''; + if (mangaInfo.summary = '-') or (mangaInfo.summary = ':') then + mangaInfo.summary := ''; // remove duplicate chapter if mangaInfo.chapterLinks.Count > 0 then From 2ba1c22ebd95d72680cc1ee2cefb1e5105968f0c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 03:43:18 +0800 Subject: [PATCH 0258/2794] mh%160, fix infinite loop --- baseunits/modules/mh160com.pas | 89 ++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 341b0c120..4ccc0b553 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -68,77 +68,80 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; Module: TModuleContainer): Integer; var Source, Parse: TStringList; + info: TMangaInfo; procedure ScanChapters(const StartIndex: Integer); var i: Integer; g: String = ''; begin - with MangaInfo.mangaInfo do + if (StartIndex = -1) or (StartIndex >= Parse.Count) then + Exit; + for i := StartIndex to Parse.Count - 1 do begin - for i := StartIndex to Parse.Count - 1 do + if Parse[i] = '' then + Break; + if GetTagName(Parse[i]) = 'a' then begin - if Parse[i] = '' then - Break; - if GetTagName(Parse[i]) = 'a' then - begin - chapterLinks.Add(GetVal(Parse[i], 'href')); - chapterName.Add(g + Trim(Parse[i + 1])); - end; + info.chapterLinks.Add(GetVal(Parse[i], 'href')); + info.chapterName.Add(g + Trim(Parse[i + 1])); end; - //invert chapters - if MangaInfo.mangaInfo.chapterLinks.Count > 0 then - InvertStrings([chapterLinks, chapterName]); end; + //invert chapters + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); end; procedure ScanParse; var i: Integer; + chapterinfopos: Integer = -1; begin for i := 0 to Parse.Count - 1 do - with MangaInfo.mangaInfo do - begin - //title - if title = '' then - if GetVal(Parse[i], 'class') = 'intro_l' then - if GetVal(Parse[i + 2], 'class') = 'title' then - title := CommonStringFilter(Parse[i + 5]); + begin + //title + if info.title = '' then + if GetVal(Parse[i], 'class') = 'intro_l' then + if GetVal(Parse[i + 2], 'class') = 'title' then + info.title := CommonStringFilter(Parse[i + 5]); - //cover - if coverLink = '' then - if GetVal(Parse[i], 'class') = 'cover' then - if GetTagName(Parse[i + 1]) = 'img' then - begin - coverLink := GetVal(Parse[i + 1], 'src'); - if Pos('http', coverLink) <> 1 then - coverLink := Module.RootURL + coverLink; - end; + //cover + if info.coverLink = '' then + if GetVal(Parse[i], 'class') = 'cover' then + if GetTagName(Parse[i + 1]) = 'img' then + begin + info.coverLink := GetVal(Parse[i + 1], 'src'); + if Pos('http', info.coverLink) <> 1 then + info.coverLink := Module.RootURL + info.coverLink; + end; - //author - if (Pos('原著作者:', Parse[i]) <> 0) and - (Parse[i + 1] = '') then - authors := CommonStringFilter(Parse[i + 2]); + //author + if (Pos('原著作者:', Parse[i]) <> 0) and + (Parse[i + 1] = '') then + info.authors := CommonStringFilter(Parse[i + 2]); - //genres - if (Pos('剧情类别:', Parse[i]) <> 0) and - (Parse[i + 1] = '') then - genres := Trim(Parse[i + 3]); + //genres + if (Pos('剧情类别:', Parse[i]) <> 0) and + (Parse[i + 1] = '') then + info.genres := Trim(Parse[i + 3]); - //summary - if Pos('class="introduction"', Parse[i]) <> 0 then - summary := Trim(Parse[i + 2]); + //summary + if Pos('class="introduction"', Parse[i]) <> 0 then + info.summary := Trim(Parse[i + 2]); - //chapters - if GetVal(Parse[i], 'class') = 'plist pnormal' then - ScanChapters(i); - end; + //chapters + if GetVal(Parse[i], 'class') = 'plist pnormal' then + if chapterinfopos = -1 then + chapterinfopos := i; + end; + ScanChapters(chapterinfopos); end; begin Result := INFORMATION_NOT_FOUND; if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; MangaInfo.mangaInfo.website := Module.Website; MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); Source := TStringList.Create; From 06022e9bb7fe849e9358ed559a6c6f2e37c0999b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 13:35:17 +0800 Subject: [PATCH 0259/2794] mh$160, fix qq url --- baseunits/modules/mh160com.pas | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 4ccc0b553..83d723958 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -211,17 +211,14 @@ function getcurpic_skin4_20110501(const URL: String): String; end; function getremoteqqurl(const S: String): String; - var - qqfilename: String; begin - Result := S; - qqfilename := SeparateRight(S, 'dir_path=/'); - qqfilename := StringReplace(qqfilename, '&name', '', []); - qqfilename := StringReplace(qqfilename, 'mif2', 'jpg', []); - qqfilename := StringReplace(qqfilename, '/', '_', [rfReplaceAll]); + Result := SeparateRight(S, 'dir_path=/'); + Result := StringReplace(Result, '&name=', '', []); + Result := StringReplace(Result, 'mif2', 'jpg', []); + Result := StringReplace(Result, '/', '_', [rfReplaceAll]); Result := 'http://img11.aoyuanba.com/pictmdown.php?p=' + - EncodeStringBase64(S) + '$sf=' + qqfilename + - '&ym=' + 'http://img11.hgysxz.cn'; + EncodeStringBase64(S) + '$sf=' + Result + + '&ym=http://img11.hgysxz.cn'; end; begin From 48241e37071916c599969d7535e02f66d767fdd2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 13:38:23 +0800 Subject: [PATCH 0260/2794] mainform, fix startup command always executed --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 31c7ecb9f..b0f441a0c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1330,6 +1330,7 @@ procedure TMainForm.itStartupTimer(Sender: TObject); itStartup.Enabled := False; if not isStartup then begin + isStartup := True; if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if cbOptionAutoCheckUpdate.Checked then From a08a661a48a6aae56cc2a4419bd893bf29142b03 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 13:39:01 +0800 Subject: [PATCH 0261/2794] updatethread, store some prop --- baseunits/uUpdateThread.pas | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 091e9c68a..2c51481e9 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -65,6 +65,7 @@ TUpdateMangaManagerThread = class(TFMDThread) directoryCount2, numberOfThreads, websitePtr: Integer; threads: TFPList; CS_threads: TCriticalSection; + SortedList, NoMangaInfo: Boolean; constructor Create; destructor Destroy; override; procedure CheckCommit(const CommitCount: Integer = 32); @@ -180,7 +181,7 @@ procedure TUpdateMangaThread.Execute; //if website has sorted list by latest added //we will stop at first found against current db - if SitesWithSortedList(manager.website) then + if manager.SortedList then begin if links.Count > 0 then if manager.mainDataProcess.LinkExist(links.Strings[0]) then @@ -327,6 +328,8 @@ constructor TUpdateMangaManagerThread.Create; mainDataProcess := TDBDataProcess.Create; threads := TFPList.Create; + SortedList := False; + NoMangaInfo := False; end; destructor TUpdateMangaManagerThread.Destroy; @@ -576,6 +579,8 @@ procedure TUpdateMangaManagerThread.Execute; while websitePtr < websites.Count do begin website := websites.Strings[websitePtr]; + SortedList := SitesWithSortedList(website); + NoMangaInfo := SitesWithoutInformation(website); Inc(websitePtr); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; @@ -716,7 +721,7 @@ procedure TUpdateMangaManagerThread.Execute; begin workPtr := 0; FCommitCount := 0; - if (SitesWithoutInformation(website)) or + if NoMangaInfo or OptionUpdateListNoMangaInfo then begin Inc(workPtr); @@ -744,7 +749,7 @@ procedure TUpdateMangaManagerThread.Execute; names.Clear; links.Clear; - if (workPtr > 0) and (not SitesWithSortedList(website)) then + if (workPtr > 0) and (not SortedList) then begin FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; From 09689f51647c50655ee8b1ced193e6baf30c57d1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 25 Jul 2015 14:09:05 +0800 Subject: [PATCH 0262/2794] mh%160, fix qq url --- baseunits/modules/mh160com.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 83d723958..ace150e93 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -216,9 +216,10 @@ function getcurpic_skin4_20110501(const URL: String): String; Result := StringReplace(Result, '&name=', '', []); Result := StringReplace(Result, 'mif2', 'jpg', []); Result := StringReplace(Result, '/', '_', [rfReplaceAll]); - Result := 'http://img11.aoyuanba.com/pictmdown.php?p=' + - EncodeStringBase64(S) + '$sf=' + Result + - '&ym=http://img11.hgysxz.cn'; + //Result := 'http://img11.aoyuanba.com/pictmdown.php?p=' + + // EncodeStringBase64(S) + '$sf=' + Result + + // '&ym=http://img11.hgysxz.cn'; + Result := 'http://img11.hgysxz.cn/Pic/' + Result; end; begin From f178d472f2899984d2145264f7958e38adeb612a Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 00:44:57 +0800 Subject: [PATCH 0263/2794] tmanginformation, store moduleid for faster locate module in batch update --- baseunits/uData.pas | 28 ++++++++++++++++------------ baseunits/uUpdateThread.pas | 6 +++++- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 57eddd05c..fe12e9e7f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -177,6 +177,7 @@ TMangaInformation = class(TObject) isGenerateFolderChapterName: Boolean; isRemoveUnicode: Boolean; FHTTP: THTTPSend; + ModuleId: Integer; procedure OnTag(NoCaseTag, ActualTag: String); procedure OnText(Text: String); @@ -1844,6 +1845,7 @@ constructor TMangaInformation.Create(AOwnerThread: TFMDThread; if CreateInfo then mangaInfo := TMangaInfo.Create; isGetByUpdater := False; + ModuleId := -2; end; destructor TMangaInformation.Destroy; @@ -1983,7 +1985,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; begin Page := 0; - WebsiteID := GetMangaSiteID(website); //load User-Agent from INIAdvanced if website <> '' then @@ -2000,10 +2001,13 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; else begin BROWSER_INVERT := False; - if Modules.ModuleAvailable(website, MMGetDirectoryPageNumber, p) then - Result := Modules.GetDirectoryPageNumber(Self, Page, p) + if ModuleId <> -1 then + ModuleId := Modules.LocateModule(website); + if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then + Result := Modules.GetDirectoryPageNumber(Self, Page, ModuleId) else begin + WebsiteID := GetMangaSiteID(website); Source := TStringList.Create; if website = WebsiteRoots[ANIMEA_ID, 0] then Result := GetAnimeADirectoryPageNumber @@ -2173,7 +2177,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; Source: TStringList; Parser: THTMLParser; WebsiteID: Cardinal; - p: Integer; {$I includes/Manga2u/names_and_links.inc} @@ -2340,17 +2343,17 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/WPManga/names_and_links.inc} begin - WebsiteID := GetMangaSiteID(website); - //load User-Agent from INIAdvanced if website <> '' then FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); - p := -1; - if Modules.ModuleAvailable(website, MMGetNameAndLink, p) then - Result := Modules.GetNameAndLink(Self, names, links, URL, p) + if ModuleId <> -1 then + ModuleId := Modules.LocateModule(website); + if Modules.ModuleAvailable(ModuleId, MMGetNameAndLink) then + Result := Modules.GetNameAndLink(Self, names, links, URL, ModuleId) else begin + WebsiteID := GetMangaSiteID(website); Source := TStringList.Create; if website = WebsiteRoots[ANIMEA_ID, 0] then Result := AnimeAGetNamesAndLinks @@ -2814,9 +2817,10 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; mangaInfo.chapterName.Clear; mangaInfo.chapterLinks.Clear; - j := -1; - if Modules.ModuleAvailable(website, MMGetInfo, j) then - Result := Modules.GetInfo(Self, URL, Reconnect, j) + if ModuleId <> -1 then + ModuleId := Modules.LocateModule(website); + if Modules.ModuleAvailable(ModuleId, MMGetInfo) then + Result := Modules.GetInfo(Self, URL, Reconnect, ModuleId) else begin WebsiteID := GetMangaSiteID(website); diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 2c51481e9..0922eb762 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, - uBaseUnit, uFMDThread, uTranslation, uMisc; + uBaseUnit, uFMDThread, uTranslation, uMisc, WebsiteModules; type TUpdateMangaManagerThread = class; @@ -60,6 +60,7 @@ TUpdateMangaManagerThread = class(TFMDThread) mainDataProcess: TDBDataProcess; names, links, websites: TStringList; website, twebsite: String; + ModuleId: Integer; workPtr, directoryCount, // for fakku's doujinshi only directoryCount2, numberOfThreads, websitePtr: Integer; @@ -116,6 +117,7 @@ procedure TUpdateMangaThread.Execute; else Info := TMangaInformation.Create(Self, False); Info.isGetByUpdater := True; + info.ModuleId := manager.ModuleId; case CheckStyle of CS_DIRECTORY_COUNT: @@ -330,6 +332,7 @@ constructor TUpdateMangaManagerThread.Create; threads := TFPList.Create; SortedList := False; NoMangaInfo := False; + ModuleId := -1; end; destructor TUpdateMangaManagerThread.Destroy; @@ -579,6 +582,7 @@ procedure TUpdateMangaManagerThread.Execute; while websitePtr < websites.Count do begin website := websites.Strings[websitePtr]; + ModuleId := Modules.LocateModule(website); SortedList := SitesWithSortedList(website); NoMangaInfo := SitesWithoutInformation(website); Inc(websitePtr); From e7e38156747d9b5acc6b490883975eb9001e6897 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 01:07:44 +0800 Subject: [PATCH 0264/2794] Bump version 0.9.19.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0238d9cf3..930b8b22e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,7 +8,7 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.19.0 (xx-07-2015) +0.9.19.0 (26-07-2015) [+] Mangalist data now using sqlite3, existing data will be automatically converted. BUGS EXPECTED! [*] Opening mangalist will be executed in separated thread, access to mangalist will be blocked until the process finish diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f484d5b03..626e6071f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ - - + diff --git a/update b/update index 6835a1a4b..df3475af5 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.18.2 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.18.2/fmd_0.9.18.2.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.18.2/fmd_0.9.18.2_Win64.7z +VERSION=0.9.19.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.0/fmd_0.9.19.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.0/fmd_0.9.19.0_Win64.7z From f6a2535e9b78ce5c5fc0dd47c1799028d4b3c524 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 01:27:14 +0800 Subject: [PATCH 0265/2794] updater, fix updater not closing after launching external process --- updater/uMain.pas | 2 +- updater/updater.lpi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 2559a5673..5b95957b0 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -564,7 +564,7 @@ procedure TDownloadThread.Execute; end; UpdateStatus(RS_Finished); if (not Self.Terminated) and _UpdApp and (_LaunchApp <> '') then - RunExternalProcess(_LaunchApp, [''], True, True); + RunExternalProcess(_LaunchApp, [''], True, False); except on E: Exception do frmMain.ExceptionHandler(Self, E); diff --git a/updater/updater.lpi b/updater/updater.lpi index 2dd277225..4ae2ddcb8 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -19,7 +19,7 @@ - + From acbb46824a57a920c05484d3aff365b1ce32603f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 01:27:29 +0800 Subject: [PATCH 0266/2794] updater, update Indonesian translations --- updater/languages/updater.id_ID.po | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 73c55a716..3b4f6c71e 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.7.6\n" +"X-Generator: Poedit 1.8.2\n" #: tfrmmain.caption msgid "Free Manga Downloader - Updater" @@ -49,7 +49,7 @@ msgstr "Gagal mengunduh berkas!" #: umain.rs_failedloadpage msgid "Failed loading page!" -msgstr "Gagal mengambil halaman!" +msgstr "Gagal memuat halaman!" #: umain.rs_filenotfound msgid "File not found!" @@ -82,7 +82,7 @@ msgstr "URL tidak valid!" #: umain.rs_loadingpage msgid "Loading page..." -msgstr "Mebuka halaman..." +msgstr "Memuat halaman..." #: umain.rs_redirected msgid "Redirected..." @@ -98,7 +98,7 @@ msgstr "Mencoba mengunduh[%d] [%s]..." #: umain.rs_retryloadpage msgid "Retry loading page[%d]..." -msgstr "Mencoba mebuka halaman[%d]..." +msgstr "Mencoba memuat halaman[%d]..." #: umain.rs_savefile msgid "Saving file... " @@ -119,4 +119,3 @@ msgstr "Membuka berkas [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Menunggu aplikasi utama untuk berhenti..." - From f03ee3e7cc985753d0e4628738a2d7774974dab2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 01:34:05 +0800 Subject: [PATCH 0267/2794] Bump version 0.9.19.1 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 930b8b22e..aa4681ee5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.1 (26-07-2015) +[*] Fix updater not closed after launching fmd. + For previous version just close FMD after update, it will also close the updater. + 0.9.19.0 (26-07-2015) [+] Mangalist data now using sqlite3, existing data will be automatically converted. BUGS EXPECTED! diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 626e6071f..8656276a3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ + diff --git a/update b/update index df3475af5..33cb001af 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.0/fmd_0.9.19.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.0/fmd_0.9.19.0_Win64.7z +VERSION=0.9.19.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.1/fmd_0.9.19.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.1/fmd_0.9.19.1_Win64.7z From 61155c110a494fad0382f32cf992b2ad097d6109 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 01:56:15 +0800 Subject: [PATCH 0268/2794] modules, replace default result with net_problem --- baseunits/modules/FoOlSlide.pas | 6 +++--- baseunits/modules/mh160com.pas | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 01f170d20..8c50bec60 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -30,7 +30,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; begin - Result := INFORMATION_NOT_FOUND; + Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit; @@ -71,7 +71,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; begin - Result := INFORMATION_NOT_FOUND; + Result := NET_PROBLEM; if MangaInfo = nil then Exit; Source := TStringList.Create; @@ -172,7 +172,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; begin - Result := INFORMATION_NOT_FOUND; + Result := NET_PROBLEM; if MangaInfo = nil then Exit; MangaInfo.mangaInfo.website := Module.Website; diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index ace150e93..b53e926de 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -41,7 +41,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; begin - Result := INFORMATION_NOT_FOUND; + Result := NET_PROBLEM; if MangaInfo = nil then Exit; Source := TStringList.Create; @@ -138,7 +138,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; begin - Result := INFORMATION_NOT_FOUND; + Result := NET_PROBLEM; if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; From 1c2fab69f054b5b1933088c98bcc14594ff5b864 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 04:42:24 +0800 Subject: [PATCH 0269/2794] baseunit, getpage, clear document if it's not post before send --- baseunits/uBaseUnit.pas | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c24bc6489..e1a4b8e7c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2858,6 +2858,13 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.MimeType := 'application/x-www-form-urlencoded'; end; + if meth <> 'POST' then + begin + HTTP.Document.Clear; + HTTP.RangeStart := 0; + HTTP.RangeEnd := 0; + end; + counter := 0; HTTP.Headers.Text := HTTPHeader.Text; while (not HTTP.HTTPMethod(meth, URL)) or @@ -3115,6 +3122,10 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; end; + HTTP.Document.Clear; + HTTP.RangeStart := 0; + HTTP.RangeEnd := 0; + {$IFDEF DOWNLOADER} if checkTerminate then Exit; {$ENDIF} From 99aff48d3f474aa9cc52f156b7cefe7554a082fd Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 06:11:10 +0800 Subject: [PATCH 0270/2794] websitemodules, add more prop --- baseunits/WebsiteModules.pas | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 31fd6f8d9..1c7d3ca31 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -36,15 +36,23 @@ TModuleContainer = class; { TModuleContainer } TModuleContainer = class + private + FTotalDirectory: Integer; + procedure SetTotalDirectory(AValue: Integer); public Website, RootURL: String; SortedList, InformationAvailable, FavoriteAvailable: Boolean; + TotalDirectoryPage: array of Integer; + CurrentDirectoryIndex: Integer; OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; OnGetNameAndLink: TOnGetNameAndLink; OnGetInfo: TOnGetInfo; OnGetPageNumber: TOnGetPageNumber; OnGetImageURL: TOnGetImageURL; constructor Create; + destructor Destroy; override; + public + property TotalDirectory: Integer read FTotalDirectory write SetTotalDirectory; end; { TWebsiteModules } @@ -119,11 +127,31 @@ implementation { TModuleContainer } +procedure TModuleContainer.SetTotalDirectory(AValue: Integer); +var + i: Integer; +begin + if FTotalDirectory = AValue then Exit; + FTotalDirectory := AValue; + SetLength(TotalDirectoryPage, FTotalDirectory); + if Length(TotalDirectoryPage) > 0 then + for i := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do + TotalDirectoryPage[i] := 1; +end; + constructor TModuleContainer.Create; begin SortedList := False; InformationAvailable := True; FavoriteAvailable := True; + TotalDirectory := 1; + CurrentDirectoryIndex := 0; +end; + +destructor TModuleContainer.Destroy; +begin + SetLength(TotalDirectoryPage, 0); + inherited Destroy; end; { TWebsiteModules } From 2f579f40cd7b157b418a26ad2f6ba40076ea1b08 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 06:28:00 +0800 Subject: [PATCH 0271/2794] updatethread, adapt websitemodules changes --- baseunits/uUpdateThread.pas | 41 ++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 0922eb762..978e31be1 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -110,6 +110,7 @@ destructor TUpdateMangaThread.Destroy; procedure TUpdateMangaThread.Execute; var names, links: TStringList; + i: Integer; begin try if checkStyle = CS_INFO then @@ -122,6 +123,16 @@ procedure TUpdateMangaThread.Execute; case CheckStyle of CS_DIRECTORY_COUNT: begin + if manager.ModuleId <> -1 then + begin + with Modules.Module[manager.ModuleId] do + for i := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do + begin + CurrentDirectoryIndex := i; + info.GetDirectoryPage(TotalDirectoryPage[i], manager.website); + end; + end + else if SitesMemberOf(manager.website, [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then begin @@ -183,15 +194,12 @@ procedure TUpdateMangaThread.Execute; //if website has sorted list by latest added //we will stop at first found against current db - if manager.SortedList then + if links.Count > 0 then begin - if links.Count > 0 then + if manager.SortedList then if manager.mainDataProcess.LinkExist(links.Strings[0]) then manager.isFinishSearchingForNewManga := True; - end; - if links.Count > 0 then - begin manager.CS_AddNamesAndLinks.Acquire; try manager.links.AddStrings(links); @@ -507,7 +515,13 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; s := s + ' | ' + RS_GettingDirectory + '...'; end; CS_DIRECTORY_PAGE: - s := s + ' | ' + RS_LookingForNewTitle + '...'; + begin + s += ' | ' + RS_LookingForNewTitle; + if ModuleId <> -1 then + with Modules.Module[ModuleId] do + s += Format(' %d/%d', [CurrentDirectoryIndex + 1, TotalDirectory]); + s += '...'; + end; CS_DIRECTORY_PAGE_2: s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; CS_INFO: @@ -539,7 +553,7 @@ procedure TUpdateMangaManagerThread.Execute; procedure WaitForThreads; var - i: Cardinal; + i: Integer; begin while threads.Count > 0 do begin @@ -623,6 +637,19 @@ procedure TUpdateMangaManagerThread.Execute; INIAdvanced.Reload; workPtr := 0; isFinishSearchingForNewManga := False; + if ModuleId <> -1 then + begin + with Modules.Module[ModuleId] do + for j := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do + begin + workPtr := 0; + isFinishSearchingForNewManga := False; + CurrentDirectoryIndex := j; + GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); + WaitForThreads; + end; + end + else if SitesMemberOf(website, [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then begin From b8460e041a9b7f22a5017592c185e986d0978d2e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 06:58:29 +0800 Subject: [PATCH 0272/2794] remove ba to to manga info script --- .../includes/Batoto/directory_page_number.inc | 37 ------------ baseunits/includes/Batoto/names_and_links.inc | 58 ------------------- baseunits/uBaseUnit.pas | 5 -- baseunits/uData.pas | 15 ----- baseunits/uUpdateThread.pas | 10 +--- 5 files changed, 3 insertions(+), 122 deletions(-) delete mode 100644 baseunits/includes/Batoto/directory_page_number.inc delete mode 100644 baseunits/includes/Batoto/names_and_links.inc diff --git a/baseunits/includes/Batoto/directory_page_number.inc b/baseunits/includes/Batoto/directory_page_number.inc deleted file mode 100644 index 68b3b372e..000000000 --- a/baseunits/includes/Batoto/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetBatotoDirectoryPageNumber: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[BATOTO_ID, 1] + - BATOTO_BROWSER + '?per_page=750&st=0', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('Page 1 of ', parse.Strings[i]) > 0) then - begin - s := GetString(parse.Strings[i] + '~!@', 'Page 1 of ', '~!@'); - Page := StrToInt(TrimLeft(TrimRight(s))); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Batoto/names_and_links.inc b/baseunits/includes/Batoto/names_and_links.inc deleted file mode 100644 index 1a08e08a0..000000000 --- a/baseunits/includes/Batoto/names_and_links.inc +++ /dev/null @@ -1,58 +0,0 @@ - function BatotoGetNamesAndLinks: Byte; - var - i: Cardinal; - //s : String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[BATOTO_ID, 1] + - BATOTO_BROWSER + '?per_page=750&st=' + IntToStr(StrToInt(URL) * 750), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - regx := TRegExpr.Create; - regx.ModifierI := True; - //regx.Expression:='^.*(/comics?/_/\w+/[^''"\?]+).*$'; - regx.Expression := '^.*(/comics?/_/(sp|comics?)/[^''"\?]+).*$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos(' 0) then - if regx.Exec(Trim(parse[i])) then - begin - links.Add(regx.Replace(Trim(parse[i]), '$1', True)); - names.Add(Trim(StringFilter(Trim(parse[i + 1])))); - end; - //if (GetTagName(parse.Strings[i]) = 'a') AND - // (Pos('/comic/', parse.Strings[i])>0) AND - // (Pos('/comics/''', parse.Strings[i])=0) AND - // (Pos('/comics/"', parse.Strings[i])=0) AND - // (Pos('/comics/?', parse.Strings[i])=0) then - //begin - // Result:= NO_ERROR; - // s:= StringFilter(TrimLeft(TrimRight(parse.Strings[i+1]))); - // if (Pos('bloody-rose-r8162', parse.Strings[i]) = 0) AND - // (Pos('dragon-and-weed-origins-outbreak-r6901', parse.Strings[i]) = 0) AND - // (Pos('dragon-and-weed-origins-the-fallen-r8180', parse.Strings[i]) = 0) then - // begin - // names.Add(s); - // s:= GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - // links.Add(StringReplace(s, WebsiteRoots[BATOTO_ID,1], '', [])); - // end; - //end; - end; - regx.Free; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e1a4b8e7c..196ebff78 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -480,9 +480,6 @@ interface KISSMANGA_BROWSER = '/MangaList'; - BATOTO_BROWSER_1 = '/comic/_/sp/'; - BATOTO_BROWSER_2 = '/comic/_/comics/'; - MANGA24H_BROWSER = '/manga/update/page/'; VNSHARING_BROWSER = '/DanhSach'; @@ -660,8 +657,6 @@ interface // Sites var BROWSER_INVERT: Boolean = False; - BATOTO_BROWSER: string = '/search'; - FAKKU_BROWSER: string = '/manga/newest'; MANGAEDEN_BROWSER: string = '/en-directory/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fe12e9e7f..c81068a65 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1897,8 +1897,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/KissManga/directory_page_number.inc} - {$I includes/Batoto/directory_page_number.inc} - {$I includes/Manga24h/directory_page_number.inc} {$I includes/VnSharing/directory_page_number.inc} @@ -2015,9 +2013,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[KISSMANGA_ID, 0] then Result := GetKissMangaDirectoryPageNumber else - if website = WebsiteRoots[BATOTO_ID, 0] then - Result := GetBatotoDirectoryPageNumber - else if website = WebsiteRoots[MANGA24H_ID, 0] then Result := GetManga24hDirectoryPageNumber else @@ -2192,8 +2187,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/KissManga/names_and_links.inc} - {$I includes/Batoto/names_and_links.inc} - {$I includes/Manga24h/names_and_links.inc} {$I includes/VnSharing/names_and_links.inc} @@ -2367,9 +2360,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[KISSMANGA_ID, 0] then Result := KissMangaGetNamesAndLinks else - if website = WebsiteRoots[BATOTO_ID, 0] then - Result := BatotoGetNamesAndLinks - else if website = WebsiteRoots[MANGA24H_ID, 0] then Result := Manga24hGetNamesAndLinks else @@ -2654,8 +2644,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/KissManga/manga_information.inc} - {$I includes/Batoto/manga_information.inc} - {$I includes/Manga24h/manga_information.inc} {$I includes/VnSharing/manga_information.inc} @@ -2840,9 +2828,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[KISSMANGA_ID, 0] then Result := GetKissMangaInfoFromURL else - if website = WebsiteRoots[BATOTO_ID, 0] then - Result := GetBatotoInfoFromURL - else if website = WebsiteRoots[MANGA24H_ID, 0] then Result := GetManga24hInfoFromURL else diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 978e31be1..fca53697a 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -134,15 +134,13 @@ procedure TUpdateMangaThread.Execute; end else if SitesMemberOf(manager.website, - [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then + [FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then begin - BATOTO_BROWSER := BATOTO_BROWSER_1; FAKKU_BROWSER := FAKKU_BROWSER_1; MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_1; PERVEDEN_BROWSER := PERVEDEN_BROWSER_1; info.GetDirectoryPage(manager.directoryCount, manager.website); - BATOTO_BROWSER := BATOTO_BROWSER_2; FAKKU_BROWSER := FAKKU_BROWSER_2; MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_2; PERVEDEN_BROWSER := PERVEDEN_BROWSER_2; @@ -167,11 +165,10 @@ procedure TUpdateMangaThread.Execute; workPtr := manager.directoryCount2 - workPtr - 1; end; if SitesMemberOf(manager.website, - [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then + [FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then begin if checkStyle = CS_DIRECTORY_PAGE then begin - BATOTO_BROWSER := BATOTO_BROWSER_1; FAKKU_BROWSER := FAKKU_BROWSER_1; MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_1; PERVEDEN_BROWSER := PERVEDEN_BROWSER_1; @@ -180,7 +177,6 @@ procedure TUpdateMangaThread.Execute; else if checkStyle = CS_DIRECTORY_PAGE_2 then begin - BATOTO_BROWSER := BATOTO_BROWSER_2; FAKKU_BROWSER := FAKKU_BROWSER_2; MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_2; PERVEDEN_BROWSER := PERVEDEN_BROWSER_2; @@ -650,7 +646,7 @@ procedure TUpdateMangaManagerThread.Execute; end; end else - if SitesMemberOf(website, [BATOTO_ID, FAKKU_ID, MANGAEDEN_ID, + if SitesMemberOf(website, [FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then begin if directoryCount = 0 then From 62c1ed75d8dc14a454d88f0828b1aba748e965c4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 07:05:46 +0800 Subject: [PATCH 0273/2794] updatethread, fix not saving for website withour sorted list --- baseunits/uUpdateThread.pas | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index fca53697a..e65612ee3 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -776,15 +776,16 @@ procedure TUpdateMangaManagerThread.Execute; names.Clear; links.Clear; - if (workPtr > 0) and (not SortedList) then - begin - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; - Synchronize(MainThreadShowGetting); - mainDataProcess.Sort; - mainDataProcess.Close; - Synchronize(RefreshList); - end; + if workPtr > 0 then + if not (Terminated and SortedList) then + begin + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; + Synchronize(MainThreadShowGetting); + mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); + end; end; mainDataProcess.Close; From f367ddd9bf44b9973f5a4846fca557e94836941f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 07:15:53 +0800 Subject: [PATCH 0274/2794] fools lide, minor changes --- baseunits/modules/FoOlSlide.pas | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 8c50bec60..e2a07cf27 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -7,7 +7,6 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, HTMLUtil, RegExpr; - implementation function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; @@ -136,8 +135,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; var i: Integer; begin - for i := 0 to Parse.Count - 1 do - with MangaInfo.mangaInfo do + with MangaInfo.mangaInfo do + for i := 0 to Parse.Count - 1 do begin //title if title = '' then From 8dec2bc98e85ac255635b89d886d2638e694a2fd Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 08:22:36 +0800 Subject: [PATCH 0275/2794] udata, trim summary --- baseunits/uData.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c81068a65..96b5418f0 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -3090,10 +3090,13 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; mangaInfo.authors := Trim(RemoveStringBreaks(Trim(mangaInfo.authors))); mangaInfo.artists := Trim(RemoveStringBreaks(Trim(mangaInfo.artists))); mangaInfo.genres := Trim(RemoveStringBreaks(Trim(mangaInfo.genres))); + mangaInfo.authors := TrimRightChar(Trim(mangaInfo.authors), [',']); mangaInfo.artists := TrimRightChar(Trim(mangaInfo.artists), [',']); mangaInfo.genres := TrimRightChar(Trim(mangaInfo.genres), [',']); + mangaInfo.summary := Trim(mangaInfo.summary); + //// strip //mangaInfo.summary := StringBreaks(mangaInfo.summary); //mangaInfo.summary := Trim(TrimChar(mangaInfo.summary, [#13, #10])); From 9307c7209c1b917eebef7f76aad7e23b64833144 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 08:24:58 +0800 Subject: [PATCH 0276/2794] remove ba to to get manga info --- .../includes/Batoto/manga_information.inc | 198 ------------------ 1 file changed, 198 deletions(-) delete mode 100644 baseunits/includes/Batoto/manga_information.inc diff --git a/baseunits/includes/Batoto/manga_information.inc b/baseunits/includes/Batoto/manga_information.inc deleted file mode 100644 index 7b1bcab1c..000000000 --- a/baseunits/includes/Batoto/manga_information.inc +++ /dev/null @@ -1,198 +0,0 @@ - function GetBatotoInfoFromURL: Byte; - var - patchURL, s: String; - i, j: Cardinal; - - begin - patchURL := URL; - //if Pos('comic/_/comics', patchURL) = 0 then - //patchURL:= StringReplace(URL, 'comic/_', 'comic/_/comics', []); - mangaInfo.url := FillMangaSiteHost(BATOTO_ID, patchURL); - - Source.Clear; - if not GetPage(TObject(Source), TrimLeft(TrimRight(mangaInfo.url)), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source using our own HTML parser - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - Source.Free; - mangaInfo.website := WebsiteRoots[BATOTO_ID, 0]; - - mangaInfo.genres := ''; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover link - if (GetTagName(parse.Strings[i]) = 'img') and - (Pos('max-height:500px', parse.Strings[i]) > 0) then - begin - mangaInfo.coverLink := - CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - end; - - // get title - if (Pos('ipsType_pagetitle', parse[i]) > 0) then - mangaInfo.title := Trim(StringFilter(Trim(parse[i + 1]))); - - // get summary - if (Pos('Description:', parse.Strings[i]) <> 0) then - begin - j := i + 3; - mangaInfo.summary := ''; - while (Pos('', parse.Strings[j]) = 0) and (j < parse.Count - 1) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := StringFilter(parse.Strings[j] + #10#13); - parse.Strings[j] := - StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := - StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + StringFilter(parse.Strings[j]); - end; - Inc(j); - end; - end; - - // get chapter name and links (bad code) - //mulai - if OptionShowAllLang then - begin - if (GetTagName(parse.Strings[i]) = 'a') and - (Pos('/read/_/', parse.Strings[i]) > 0) and - (i + 8 < parse.Count - 1) and - (Pos('title=', parse.Strings[i + 8]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - (StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[BATOTO_ID, 1], '', [rfReplaceAll]))); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #10, '', [rfReplaceAll]); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #13, '', [rfReplaceAll]); - parse.Strings[i + 2] := StringFilter(TrimLeft(parse.Strings[i + 2])); - s := StringFilter(TrimRight(RemoveSymbols(parse.Strings[i + 2]))); - if OptionShowBatotoSG then - s := s + ' [by ' + StringFilter( - TrimRight(RemoveSymbols(parse.Strings[i + 15]))) + ']' + ' [' + - GetAttributeValue(GetTagAttribute(parse.Strings[i + 8], 'title=')) + ']'; - mangaInfo.chapterName.Add(s); - end - else - if (GetTagName(parse.Strings[i]) = 'a') and - (Pos('/read/_/', parse.Strings[i]) > 0) and - (i + 2 < parse.Count - 1) and - (Pos('title=', parse.Strings[i - 3]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - (StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[BATOTO_ID, 1], '', [rfReplaceAll]))); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #10, '', [rfReplaceAll]); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #13, '', [rfReplaceAll]); - parse.Strings[i + 2] := StringFilter(TrimLeft(parse.Strings[i + 2])); - mangaInfo.chapterName.Add(TrimRight(RemoveSymbols(parse.Strings[i + 2]))); - end; - end - else - begin - if (GetTagName(parse.Strings[i]) = 'a') and - (Pos('/read/_/', parse.Strings[i]) > 0) and - (i + 8 < parse.Count - 1) and - (Pos('English', parse.Strings[i + 8]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - (StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[BATOTO_ID, 1], '', [rfReplaceAll]))); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #10, '', [rfReplaceAll]); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #13, '', [rfReplaceAll]); - parse.Strings[i + 2] := StringFilter(TrimLeft(parse.Strings[i + 2])); - s := StringFilter(TrimRight(RemoveSymbols(parse.Strings[i + 2]))); - if OptionShowBatotoSG then - s := s + ' [by ' + StringFilter( - TrimRight(RemoveSymbols(parse.Strings[i + 15]))) + ']'; - mangaInfo.chapterName.Add(s); - end - else - if (GetTagName(parse.Strings[i]) = 'a') and - (Pos('/read/_/', parse.Strings[i]) > 0) and - (i + 2 < parse.Count - 1) and - (Pos('English', parse.Strings[i - 3]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - (StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[BATOTO_ID, 1], '', [rfReplaceAll]))); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #10, '', [rfReplaceAll]); - parse.Strings[i + 2] := - StringReplace(parse.Strings[i + 2], #13, '', [rfReplaceAll]); - parse.Strings[i + 2] := StringFilter(TrimLeft(parse.Strings[i + 2])); - mangaInfo.chapterName.Add(TrimRight(RemoveSymbols(parse.Strings[i + 2]))); - end; - end; - - // get authors - if (i + 5 < parse.Count - 1) and - (Pos('Author:', parse.Strings[i]) > 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 5]); - - // get artists - if (i + 5 < parse.Count - 1) and - (Pos('Artist:', parse.Strings[i]) > 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 5]); - - // get genres - if Pos('/search?genres=', parse.Strings[i]) > 0 then - begin - if Pos(' 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse.Strings[i + 3]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + parse.Strings[i + 3]; - end; - - // get status - if (Pos('Status:', parse.Strings[i]) > 0) then - begin - if (i + 4 < parse.Count - 1) and - (Pos('Ongoing', parse.Strings[i + 4]) > 0) then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; From 87f30c563e4c9e95e703be4d92b481892d132e04 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 08:26:32 +0800 Subject: [PATCH 0277/2794] downloadmanager, remove ba to to --- .../includes/Batoto/chapter_page_number.inc | 69 ------------------- baseunits/includes/Batoto/image_url.inc | 45 ------------ baseunits/uDownloadsManager.pas | 10 --- 3 files changed, 124 deletions(-) delete mode 100644 baseunits/includes/Batoto/chapter_page_number.inc delete mode 100644 baseunits/includes/Batoto/image_url.inc diff --git a/baseunits/includes/Batoto/chapter_page_number.inc b/baseunits/includes/Batoto/chapter_page_number.inc deleted file mode 100644 index 30358a317..000000000 --- a/baseunits/includes/Batoto/chapter_page_number.inc +++ /dev/null @@ -1,69 +0,0 @@ - function GetBatotoPageNumber: Boolean; - var - isWebtoon: Boolean = True; - i, j: Cardinal; - l: TStringList; - s: String; - begin - l := TStringList.Create; - parse := TStringList.Create; - - parse.Clear; - l.Clear; - s := FillMangaSiteHost(BATOTO_ID, URL); - Result := GetPage(TObject(l), s + '/1', manager.container.manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - manager.container.PageNumber := 0; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (Pos('page_select', parse.Strings[i]) > 0) then - begin - isWebtoon := False; - Break; - end; - end; - - if isWebtoon then - begin - //grab image directly - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos(' 0 then - if Pos('
', parse.Strings[i + 1]) > 0 then - manager.container.pageLinks.Add(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - end; - end; - if manager.container.PageLinks.Count > 0 then - manager.container.PageNumber := manager.container.PageLinks.Count - 1; - end - else - begin - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if Pos('page_select', parse.Strings[i]) <> 0 then - begin - j := i + 2; - while GetTagName(parse.Strings[j]) = 'option' do - begin - Inc(manager.container.PageNumber); - Inc(j, 3); - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Batoto/image_url.inc b/baseunits/includes/Batoto/image_url.inc deleted file mode 100644 index de9afa768..000000000 --- a/baseunits/includes/Batoto/image_url.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetBatotoImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(BATOTO_ID, URL); - Result := GetPage(TObject(l), s + '/' + IntToStr(workCounter + 1), - manager.container.manager.retryConnect); - - if l.Count > 0 then - begin - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - end; - - if Self.Terminated then - begin - parse.Free; - l.Free; - Exit; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos(' 0) and - (Pos('id="comic_page"', parse.Strings[i]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - manager.container.PageLinks.Strings[workCounter] := s; - Break; - end; - end; - end; - - parse.Free; - l.Free; - end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ab7eb466f..b21743a48 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -382,8 +382,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/chapter_page_number.inc} - {$I includes/Batoto/chapter_page_number.inc} - {$I includes/EatManga/chapter_page_number.inc} {$I includes/EGScans/chapter_page_number.inc} @@ -533,9 +531,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnPageNumber else - if manager.container.MangaSiteID = BATOTO_ID then - Result := GetBatotoPageNumber - else if manager.container.MangaSiteID = MANGAFOX_ID then Result := GetMangaFoxPageNumber else @@ -748,8 +743,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/image_url.inc} - {$I includes/Batoto/image_url.inc} - {$I includes/BlogTruyen/image_url.inc} {$I includes/CentralDeMangas/image_url.inc} @@ -898,9 +891,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnImageURL else - if manager.container.MangaSiteID = BATOTO_ID then - Result := GetBatotoImageURL - else if manager.container.MangaSiteID = MANGA2U_ID then Result := GetManga2uImageURL else From 4697b9dfd1e5ddd34cd6fddef679cabb926904a2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 08:29:08 +0800 Subject: [PATCH 0278/2794] websitemodules, add ba to to module --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Batoto.pas | 392 +++++++++++++++++++++++++++++++++++ 2 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Batoto.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 1aeef126f..4bebd7ff2 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,3 +1,4 @@ uses FoOlSlide, - mh160com; + mh160com, + Batoto; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas new file mode 100644 index 000000000..398501f41 --- /dev/null +++ b/baseunits/modules/Batoto.pas @@ -0,0 +1,392 @@ +unit Batoto; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, RegExpr; +implementation + +const + dirurls: array [0..1] of String = ( + '/comic/_/sp/', + '/comic/_/comics/'); + perpage = 500; + dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + + procedure ScanParse; + var + i: Integer; + s: String; + begin + if Parse.Count > 0 then + for i := 0 to Parse.Count - 1 do + if (Pos('Page 1 of ', parse.Strings[i]) > 0) then + begin + s := GetString(parse.Strings[i] + '~!@', 'Page 1 of ', '~!@'); + Page := StrToInt(TrimLeft(TrimRight(s))); + Break; + end; + end; + +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit; + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), + Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + + dirparam + IntToStr(perpage), 3) then + begin + Result := NO_ERROR; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + s: String; + p: Integer; + + procedure ScanParse; + var + i, j: Integer; + begin + j := -1; + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'table') and + (GetVal(Parse[i], 'class') = 'ipb_table topic_list hover_rows') then + begin + j := i; + Break; + end; + if (j > -1) and (j < Parse.Count) then + for i := j to Parse.Count - 1 do + if Pos(' 0 then + Break + else + if GetTagName(Parse[i]) = 'a' then + begin + Links.Add(GetVal(Parse[i], 'href')); + Names.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + + dirparam + IntToStr(perpage); + p := StrToIntDef(URL, 0); + if p > 0 then + s += '&st=' + (IntToStr(p * perpage)); + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), s, 3) then + begin + Result := NO_ERROR; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; Module: TModuleContainer): Integer; +var + Source, Parse: TStringList; + info: TMangaInfo; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + addchap: Boolean; + s: String; + begin + for i := StartIndex to Parse.Count - 1 do + begin + if Pos(' 0 then + Break + else + if (GetTagName(Parse[i]) = 'tr') and (Pos(' chapter_row', Parse[i]) <> 0) then + begin + addchap := True; + s := CommonStringFilter(Parse[i + 6]); + if (not OptionShowAllLang) then + addchap := (Pos(' lang_English ', Parse[i]) <> 0) + else + s += Format(' [%s]', [Trim(GetVal(Parse[i + 12], 'title'))]); + if addchap then + begin + if OptionShowBatotoSG then + s += Format(' [%s]', [Trim(Parse[i + 19])]); + info.chapterLinks.Add(GetVal(Parse[i + 4], 'href')); + info.chapterName.Add(s); + end; + end; + end; + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); + end; + + procedure ScanParse; + var + i, j: Integer; + begin + info := MangaInfo.mangaInfo; + info.genres := ''; + info.summary := ''; + for i := 0 to Parse.Count - 1 do + begin + //title + if info.title = '' then + if (Pos('ipsType_pagetitle', Parse[i]) > 0) then + info.title := CommonStringFilter(Parse[i + 1]); + + //cover + if info.coverLink = '' then + if (GetTagName(Parse[i]) = 'img') and + (Pos('max-height:500px', Parse[i]) > 0) then + info.coverLink := GetVal(Parse[i], 'src'); + + //author + if (Pos('Author:', Parse[i]) > 0) then + info.authors := Trim(Parse[i + 5]); + + //artist + if (Pos('Artist:', parse[i]) > 0) then + info.artists := Trim(Parse[i + 5]); + + //genres + if Pos('/search?genres=', Parse[i]) > 0 then + begin + if Pos(' 0 then + if info.genres = '' then + info.genres := Trim(Parse[i + 3]) + else + info.genres := info.genres + ', ' + Parse[i + 3]; + end; + + //summary + if (Pos('Description:', Parse[i]) <> 0) then + begin + info.summary := ''; + for j := i + 3 to Parse.Count - 1 do + begin + if Pos('', Parse[j]) <> 0 then + Break + else + if Pos('<', Parse[j]) <> 1 then + begin + if info.summary <> '' then + info.summary += LineEnding; + info.summary += StringFilter(Parse[j]); + end; + end; + end; + + //status + if (Pos('Status:', Parse[i]) > 0) then + begin + if (i + 4 < Parse.Count - 1) and + (Pos('Ongoing', Parse[i + 4]) > 0) then + info.status := '1' // ongoing + else + info.status := '0'; // completed + end; + + //chapters + if (GetTagName(Parse[i]) = 'table') and + (GetVal(Parse[i], 'class') = 'ipb_table chapters_list') then + begin + ScanChapters(i); + Break; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + MangaInfo.mangaInfo.website := Module.Website; + MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + begin + Result := NO_ERROR; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source, Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i, j: Integer; + isWebtoon: Boolean; + begin + for i := 0 to Parse.Count - 1 do + if (Pos('page_select', Parse[i]) > 0) then + begin + isWebtoon := False; + Break; + end; + + //webtoon + if isWebtoon then + for i := 0 to Parse.Count - 1 do + begin + if Pos(' 0 then + if Pos('
', Parse[i + 1]) > 0 then + Container.pageLinks.Add(GetVal(Parse[i], 'src')); + end + else + for i := 0 to Parse.Count - 1 do + begin + if Pos('page_select', Parse[i]) <> 0 then + begin + j := i + 2; + while GetTagName(Parse[j]) = 'option' do + begin + Inc(Container.PageNumber); + Inc(j, 3); + end; + Break; + end; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL) + '/1', + Container.Manager.retryConnect) then + begin + Result := True; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source, Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'id') = 'comic_page') then + begin + if DownloadThread.workCounter < Container.PageLinks.Count then + Container.PageLinks[DownloadThread.workCounter] := GetVal(Parse[i], 'src'); + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL) + + '/' + IntToStr(DownloadThread.workCounter + 1), + Container.Manager.retryConnect) then + begin + Result := True; + Parse := TStringList.Create; + try + ParseHTML(Source.Text, Parse); + if Parse.Count > 0 then + ScanParse; + finally + Parse.Free; + end; + end; + finally + Source.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Batoto'; + RootURL := 'http://bato.to'; + SortedList := True; + InformationAvailable := True; + TotalDirectory := Length(dirurls); + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 7ae282a8eccfd305f9d0d5a3d7924899b4b530de Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 08:44:29 +0800 Subject: [PATCH 0279/2794] Bump version 0.9.19.2 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index aa4681ee5..2e652481b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.2 (26-07-2015) +[*] Batoto: rewrite all script +[*] Various changes and bug fixes + 0.9.19.1 (26-07-2015) [*] Fix updater not closed after launching fmd. For previous version just close FMD after update, it will also close the updater. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8656276a3..2957dcd9c 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 33cb001af..059613435 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.1/fmd_0.9.19.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.1/fmd_0.9.19.1_Win64.7z +VERSION=0.9.19.2 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.2/fmd_0.9.19.2.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.2/fmd_0.9.19.2_Win64.7z From 115338f2a5738801f39e7a66f3971202fa129d08 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 17:40:13 +0800 Subject: [PATCH 0280/2794] ba to to, change perpage to 50 --- baseunits/modules/Batoto.pas | 3 ++- baseunits/modules/FoOlSlide.pas | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 398501f41..c4e48ba3a 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -7,13 +7,14 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, HTMLUtil, RegExpr; + implementation const dirurls: array [0..1] of String = ( '/comic/_/sp/', '/comic/_/comics/'); - perpage = 500; + perpage = 50; dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index e2a07cf27..e40826a40 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -7,6 +7,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, HTMLUtil, RegExpr; + implementation function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; From 65b1a96f854b1043aab9cadb1b4de538505ef795 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 26 Jul 2015 17:46:17 +0800 Subject: [PATCH 0281/2794] updatethread, fix browser_invert for websitemodules --- baseunits/uUpdateThread.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e65612ee3..e40504f50 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -158,6 +158,10 @@ procedure TUpdateMangaThread.Execute; try if BROWSER_INVERT then begin + if manager.ModuleId <> -1 then + with Modules.Module[manager.ModuleId] do + workPtr := TotalDirectoryPage[CurrentDirectoryIndex] - workPtr -1 + else if checkStyle = CS_DIRECTORY_PAGE then workPtr := manager.directoryCount - workPtr - 1 else From b91c145ed051c1839dd0b75ee4b2550d53962378 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 08:42:17 +0800 Subject: [PATCH 0282/2794] modules, minor changes, reduce memory usage --- baseunits/modules/Batoto.pas | 115 ++++++++++++++--------------- baseunits/modules/FoOlSlide.pas | 123 ++++++++++++++------------------ baseunits/modules/mh160com.pas | 78 +++++++++----------- 3 files changed, 139 insertions(+), 177 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index c4e48ba3a..630619c49 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -20,7 +20,7 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; procedure ScanParse; var @@ -29,9 +29,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; begin if Parse.Count > 0 then for i := 0 to Parse.Count - 1 do - if (Pos('Page 1 of ', parse.Strings[i]) > 0) then + if (Pos('Page 1 of ', Parse.Strings[i]) > 0) then begin - s := GetString(parse.Strings[i] + '~!@', 'Page 1 of ', '~!@'); + s := GetString(Parse.Strings[i] + '~!@', 'Page 1 of ', '~!@'); Page := StrToInt(TrimLeft(TrimRight(s))); Break; end; @@ -41,30 +41,29 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit; - Source := TStringList.Create; + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + dirparam + IntToStr(perpage), 3) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; ScanParse; - finally - Parse.Free; end; end; finally - Source.Free; + Parse.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; s: String; p: Integer; @@ -100,29 +99,27 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; p := StrToIntDef(URL, 0); if p > 0 then s += '&st=' + (IntToStr(p * perpage)); - Source := TStringList.Create; + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), s, 3) then + if MangaInfo.GetPage(TObject(Parse), s, 3) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; info: TMangaInfo; procedure ScanChapters(const StartIndex: Integer); @@ -161,7 +158,6 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; var i, j: Integer; begin - info := MangaInfo.mangaInfo; info.genres := ''; info.summary := ''; for i := 0 to Parse.Count - 1 do @@ -236,31 +232,30 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; - MangaInfo.mangaInfo.website := Module.Website; - MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); - Source := TStringList.Create; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source, Parse: TStringList; + Parse: TStringList; Container: TTaskContainer; procedure ScanParse; @@ -306,30 +301,27 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Container.PageLinks.Clear; Container.PageContainerLinks.Clear; Container.PageNumber := 0; - Source := TStringList.Create; + Parse := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL) + '/1', + if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL) + '/1', Container.Manager.retryConnect) then begin - Result := True; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source, Parse: TStringList; + Parse: TStringList; Container: TTaskContainer; procedure ScanParse; @@ -349,24 +341,21 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Result := False; if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; - Source := TStringList.Create; + Parse := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL) + + if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL) + '/' + IntToStr(DownloadThread.workCounter + 1), Container.Manager.retryConnect) then begin - Result := True; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index e40826a40..c1b013433 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -13,7 +13,7 @@ implementation function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; procedure ScanParse; var @@ -32,31 +32,28 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; Page := 1; - if MangaInfo = nil then - Exit; - Source := TStringList.Create; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/directory/', 3) then + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/directory/', 3) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; procedure ScanParse; var @@ -72,32 +69,29 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; - if MangaInfo = nil then - Exit; - Source := TStringList.Create; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/directory/' + + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/directory/' + IncStr(URL), 3) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; procedure ScanChapters(const StartIndex: Integer); var @@ -173,33 +167,30 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin Result := NET_PROBLEM; - if MangaInfo = nil then - Exit; + if MangaInfo = nil then Exit; MangaInfo.mangaInfo.website := Module.Website; MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); - Source := TStringList.Create; + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source, Parse: TStringList; + Parse: TStringList; Container: TTaskContainer; procedure ScanParse; @@ -225,36 +216,32 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin Result := False; - if DownloadThread = nil then - Exit; + if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; Container.PageLinks.Clear; Container.PageContainerLinks.Clear; Container.PageNumber := 0; - Source := TStringList.Create; + Parse := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), + if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL), Container.Manager.retryConnect) then begin - Result := True; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source, Parse: TStringList; + Parse: TStringList; Container: TTaskContainer; procedure ScanParse; @@ -272,27 +259,23 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; begin Result := False; - if DownloadThread = nil then - Exit; + if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; - Source := TStringList.Create; + Parse := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL) + + if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL) + 'page/' + IntToStr(DownloadThread.workCounter + 1), Container.Manager.retryConnect) then begin - Result := True; - Parse := TStringList.Create; - try - ParseHTML(Source.Text, Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index b53e926de..cc3ffc858 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -23,7 +23,7 @@ function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; procedure ScanParse; var @@ -42,32 +42,29 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; - if MangaInfo = nil then - Exit; - Source := TStringList.Create; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/kanmanhua/' + + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/kanmanhua/' + diralpha[StrToInt(URL) + 1] + '.html', 3) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(CP936ToUTF8(Source.Text), Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(CP936ToUTF8(Parse.Text), Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; Module: TModuleContainer): Integer; var - Source, Parse: TStringList; + Parse: TStringList; info: TMangaInfo; procedure ScanChapters(const StartIndex: Integer); @@ -139,27 +136,24 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin Result := NET_PROBLEM; - if MangaInfo = nil then - Exit; + if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; - MangaInfo.mangaInfo.website := Module.Website; - MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); - Source := TStringList.Create; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then begin - Result := NO_ERROR; - Parse := TStringList.Create; - try - ParseHTML(CP936ToUTF8(Source.Text), Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + Result := INFORMATION_NOT_FOUND; + ParseHTML(CP936ToUTF8(Parse.Text), Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; @@ -263,7 +257,7 @@ function getcurpic_skin4_20110501(const URL: String): String; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source, Parse: TStringList; + Parse: TStringList; Container: TTaskContainer; procedure ScanParse; @@ -290,29 +284,25 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin Result := False; - if DownloadThread = nil then - Exit; + if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; Container.PageLinks.Clear; Container.PageContainerLinks.Clear; Container.PageNumber := 0; - Source := TStringList.Create; + Parse := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), + if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL), Container.Manager.retryConnect) then begin - Result := True; - Parse := TStringList.Create; - try - ParseHTML(CP936ToUTF8(Source.Text), Parse); - if Parse.Count > 0 then - ScanParse; - finally - Parse.Free; + ParseHTML(CP936ToUTF8(Parse.Text), Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; end; end; finally - Source.Free; + Parse.Free; end; end; From d102ac9b672b859f8c6c2d19f95edb3d624212c5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 08:42:33 +0800 Subject: [PATCH 0283/2794] baseunit, parsehtml, minor changes --- baseunits/uBaseUnit.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 196ebff78..be537f153 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3534,6 +3534,7 @@ function TParseHTML.Exec(const Raw: string): string; if FRaw = '' then Exit(''); Output.Clear; + Output.BeginUpdate; parser := THTMLParser.Create(PChar(FRaw)); try parser.OnFoundTag := FoundTag; @@ -3542,6 +3543,7 @@ function TParseHTML.Exec(const Raw: string): string; finally parser.Free; end; + Output.EndUpdate; end; { TMangaInfo } From c5477070350faa2d2ad7100461262df340042161 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 09:30:30 +0800 Subject: [PATCH 0284/2794] tdbdataprocess, add function executedirect to catch exception --- baseunits/uData.pas | 49 +++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 96b5418f0..d30d92d81 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -59,6 +59,7 @@ TDBDataProcess = class(TObject) function GetValue(RecIndex, FieldIndex: Integer): String; procedure AttachAllSites; procedure DetachAllSites; + function ExecuteDirect(SQL: String): Boolean; public constructor Create; destructor Destroy; override; @@ -408,7 +409,7 @@ procedure TDBDataProcess.CreateTable; begin if FConn.Connected then begin - FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName) + ';'); + FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + DBDataProccesCreateParam); FTrans.Commit; @@ -609,6 +610,20 @@ procedure TDBDataProcess.DetachAllSites; end; end; +function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; +begin + Result := False; + if FConn.Connected then + try + FConn.ExecuteDirect(SQL); + Result := True; + except + on E: Exception do + WriteLog_E('TDBDataProcess.ExecuteDirect.Error!'#13#10 + + 'SQL: ' + SQL, E, Self); + end; +end; + constructor TDBDataProcess.Create; begin inherited Create; @@ -1163,21 +1178,25 @@ procedure TDBDataProcess.Sort; queryactive := FQuery.Active; FQuery.Close; with FConn do - begin - ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + - DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO ' + QuotedStrd(FTableName + '_ordered') + ' ' + - BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + - ' FROM ' + QuotedStrd(FTableName) + 'ORDER BY "title" COLLATE NATCMP'); - FTrans.Commit; - ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + - 'RENAME TO ' + QuotedStrd(FTableName)); - FTrans.Commit; - VacuumTable; - end; + try + ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName + '_ordered')); + ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + + DBDataProccesCreateParam); + ExecuteDirect('INSERT INTO ' + QuotedStrd(FTableName + '_ordered') + ' ' + + BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + + ' FROM ' + QuotedStrd(FTableName) + 'ORDER BY "title" COLLATE NATCMP'); + FTrans.Commit; + ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + + 'RENAME TO ' + QuotedStrd(FTableName)); + FTrans.Commit; + VacuumTable; + except + on E: Exception do + WriteLog_E('TDBDataProcess.Sort.Error!', E, Self); + end; if FQuery.Active <> queryactive then - FQuery.Open; + FQuery.Active := queryactive; end; end; From 57e1a10e76cdba78bdeabfc3cc08ccc9b14b1085 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 09:32:05 +0800 Subject: [PATCH 0285/2794] tdbdataprocess, fix sort --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d30d92d81..7634323fb 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1184,7 +1184,7 @@ procedure TDBDataProcess.Sort; DBDataProccesCreateParam); ExecuteDirect('INSERT INTO ' + QuotedStrd(FTableName + '_ordered') + ' ' + BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + - ' FROM ' + QuotedStrd(FTableName) + 'ORDER BY "title" COLLATE NATCMP'); + ' FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); FTrans.Commit; ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + From 30264c2efdec3c1b80463ba4f20cb4a284efc441 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 09:35:57 +0800 Subject: [PATCH 0286/2794] tdbdataprocess, minor changes to sort --- baseunits/uData.pas | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 7634323fb..dfe5c32dc 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1182,10 +1182,8 @@ procedure TDBDataProcess.Sort; ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName + '_ordered')); ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO ' + QuotedStrd(FTableName + '_ordered') + ' ' + - BracketStr(DBDataProcessParam) + ' SELECT ' + DBDataProcessParam + - ' FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); - FTrans.Commit; + ExecuteDirect('INSERT INTO '+QuotedStrd(FTableName + '_ordered') + + ' SELECT * FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + 'RENAME TO ' + QuotedStrd(FTableName)); From 930395b8aa5d9c0bb1cf6362d0a107fd1b76b8cc Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 09:39:50 +0800 Subject: [PATCH 0287/2794] mainform, always close dataprocess when selected website changed --- mangadownloader/forms/frmMain.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b0f441a0c..c15d705e2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2130,9 +2130,12 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then begin currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; - if dataProcess = nil then - dataProcess := TDBDataProcess.Create; vtMangaList.Clear; + if dataProcess = nil then + dataProcess := TDBDataProcess.Create + else + if dataProcess.Connected then + dataProcess.Close; lbMode.Caption := Format(RS_ModeAll, [0]); if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then begin From fe0a0b8f33ffdf78b5ad2146dbf424e422137d3e Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 09:56:57 +0800 Subject: [PATCH 0288/2794] updatethread, fix not reopen database after update --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e40504f50..759445fd2 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -375,7 +375,7 @@ procedure TUpdateMangaManagerThread.RefreshList; try with MainForm do begin - if dataProcess.WebsiteLoaded(website) then + if cbSelectManga.Items[cbSelectManga.ItemIndex] = website then begin vtMangaList.Clear; if dataProcess = nil then From 3762083a87aa964045412f4e1fc1374ed296e174 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 11:03:33 +0800 Subject: [PATCH 0289/2794] mainform, save all column width fix #79 --- mangadownloader/forms/frmMain.pas | 69 +++++++++++-------------------- 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c15d705e2..de4a71836 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4993,6 +4993,8 @@ procedure TMainForm.UpdateVtFavorites; end; procedure TMainForm.LoadFormInformation; +var + i: Integer; begin pcLeft.Width := options.ReadInteger('form', 'MainSplitter', 195); sbMain.Panels[0].Width := pcLeft.Width + 4; @@ -5010,59 +5012,34 @@ procedure TMainForm.LoadFormInformation; PrevWindowState := wsNormal; WindowState := PrevWindowState; - vtDownload.Header.Columns.Items[0].Width := - options.ReadInteger('form', 'vtDownload0Width', 50); - vtDownload.Header.Columns.Items[1].Width := - options.ReadInteger('form', 'vtDownload1Width', 50); - vtDownload.Header.Columns.Items[2].Width := - options.ReadInteger('form', 'vtDownload2Width', 50); - vtDownload.Header.Columns.Items[3].Width := - options.ReadInteger('form', 'vtDownload3Width', 50); - vtDownload.Header.Columns.Items[4].Width := - options.ReadInteger('form', 'vtDownload4Width', 50); - vtDownload.Header.Columns.Items[5].Width := - options.ReadInteger('form', 'vtDownload5Width', 50); - - vtFavorites.Header.Columns.Items[0].Width := - options.ReadInteger('form', 'vtFavorites0Width', 50); - vtFavorites.Header.Columns.Items[1].Width := - options.ReadInteger('form', 'vtFavorites1Width', 50); - vtFavorites.Header.Columns.Items[2].Width := - options.ReadInteger('form', 'vtFavorites2Width', 50); - vtFavorites.Header.Columns.Items[3].Width := - options.ReadInteger('form', 'vtFavorites3Width', 50); - vtFavorites.Header.Columns.Items[4].Width := - options.ReadInteger('form', 'vtFavorites4Width', 50); + if vtDownload.Header.Columns.Count > 0 then + with vtDownload.Header.Columns do + for i := 0 to Count - 1 do + Items[i].Width := options.ReadInteger('form', 'vtDownload' + IntToStr(i) + 'Width', 50); + + if vtFavorites.Header.Columns.Count > 0 then + with vtFavorites.Header.Columns do + for i := 0 to Count - 1 do + Items[i].Width := options.ReadInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', 50); end; procedure TMainForm.SaveFormInformation; +var + i: Integer; begin options.WriteInteger('form', 'MainSplitter', pcLeft.Width); options.WriteInteger('form', 'pcMainPageIndex', pcMain.PageIndex); - options.WriteInteger('form', 'vtDownload0Width', - vtDownload.Header.Columns.Items[0].Width); - options.WriteInteger('form', 'vtDownload1Width', - vtDownload.Header.Columns.Items[1].Width); - options.WriteInteger('form', 'vtDownload2Width', - vtDownload.Header.Columns.Items[2].Width); - options.WriteInteger('form', 'vtDownload3Width', - vtDownload.Header.Columns.Items[3].Width); - options.WriteInteger('form', 'vtDownload4Width', - vtDownload.Header.Columns.Items[4].Width); - options.WriteInteger('form', 'vtDownload5Width', - vtDownload.Header.Columns.Items[5].Width); - - options.WriteInteger('form', 'vtFavorites0Width', - vtFavorites.Header.Columns.Items[0].Width); - options.WriteInteger('form', 'vtFavorites1Width', - vtFavorites.Header.Columns.Items[1].Width); - options.WriteInteger('form', 'vtFavorites2Width', - vtFavorites.Header.Columns.Items[2].Width); - options.WriteInteger('form', 'vtFavorites3Width', - vtFavorites.Header.Columns.Items[3].Width); - options.WriteInteger('form', 'vtFavorites4Width', - vtFavorites.Header.Columns.Items[4].Width); + if vtDownload.Header.Columns.Count > 0 then + with vtDownload.Header.Columns do + for i := 0 to Count - 1 do + options.WriteInteger('form', 'vtDownload' + IntToStr(i) + 'Width', Items[i].Width); + + if vtFavorites.Header.Columns.Count > 0 then + with vtFavorites.Header.Columns do + for i := 0 to Count - 1 do + options.WriteInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', Items[i].Width); + options.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); options.WriteBool('form', 'MainFormMaximized', (WindowState = wsMaximized)); From f6414425754236c1a3d30634b67910acb714835b Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 12:13:30 +0800 Subject: [PATCH 0290/2794] Bump version 0.9.19.3 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2e652481b..d3bd64b44 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.3 (27-07-2015) +[*] Various changes and bug fixes + 0.9.19.2 (26-07-2015) [*] Batoto: rewrite all script [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2957dcd9c..b3e046dba 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 059613435..a8615004e 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.2 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.2/fmd_0.9.19.2.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.2/fmd_0.9.19.2_Win64.7z +VERSION=0.9.19.3 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.3/fmd_0.9.19.3.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.3/fmd_0.9.19.3_Win64.7z From e86df9ea312785d55b6be19e9cac5cf2c4abb794 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 13:05:21 +0800 Subject: [PATCH 0291/2794] mainform, add changelog tab --- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.lfm | 80 +++++++++++++++++++++++-------- mangadownloader/forms/frmMain.pas | 8 ++++ 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index be537f153..bccfce83e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -211,7 +211,7 @@ interface UPDATE_FILE = 'updates.ini'; MANGALIST_FILE = 'mangalist.ini'; LANGUAGE_FILE = 'languages.ini'; - LOG_FILE = 'changelog.txt'; + CHANGELOG_FILE = 'changelog.txt'; UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/'; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index d3971966d..b7de5dd80 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2952,25 +2952,6 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 2 ClientHeight = 480 ClientWidth = 606 - object rmAbout: TRichMemo - Left = 2 - Height = 409 - Top = 4 - Width = 600 - Align = alTop - Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Around = 2 - Color = clWhite - Font.Style = [fsBold] - HideSelection = False - ParentFont = False - ReadOnly = True - ScrollBars = ssVertical - TabOrder = 0 - ZoomFactor = 1 - end object btCheckVersion: TBitBtn Left = 25 Height = 40 @@ -3015,7 +2996,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btCheckVersionClick - TabOrder = 1 + TabOrder = 0 end object btVisitMyBlog: TBitBtn Left = 249 @@ -3061,7 +3042,66 @@ object MainForm: TMainForm 80668080806680808066808080668080804D7F7F7F007F7F7F00 } OnClick = btVisitMyBlogClick + TabOrder = 1 + end + object pcAbout: TPageControl + Left = 2 + Height = 416 + Top = 2 + Width = 602 + ActivePage = tsAboutText + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + TabIndex = 0 TabOrder = 2 + object tsAboutText: TTabSheet + Caption = 'About FMD' + ClientHeight = 388 + ClientWidth = 594 + object rmAbout: TRichMemo + Left = 2 + Height = 382 + Top = 4 + Width = 588 + Align = alClient + BorderSpacing.Top = 2 + BorderSpacing.Right = 2 + BorderSpacing.Around = 2 + Color = clWhite + Font.Style = [fsBold] + HideSelection = False + ParentFont = False + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 0 + ZoomFactor = 1 + end + end + object tsChangelogText: TTabSheet + Caption = 'Changelog' + ClientHeight = 388 + ClientWidth = 594 + object mmChangelog: TMemo + Left = 2 + Height = 380 + Top = 4 + Width = 588 + Align = alClient + BorderSpacing.Top = 2 + BorderSpacing.Right = 2 + BorderSpacing.Bottom = 2 + BorderSpacing.Around = 2 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqDraft + ParentFont = False + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 0 + end + end end end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index de4a71836..819834cc0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -60,6 +60,10 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + mmChangelog: TMemo; + pcAbout: TPageControl; + tsAboutText: TTabSheet; + tsChangelogText: TTabSheet; TransferRateToolset: TChartToolset; miFavoritesStopCheckNewChapter: TMenuItem; miFavoritesCheckNewChapter: TMenuItem; @@ -955,6 +959,10 @@ procedure TMainForm.FormCreate(Sender: TObject); end; end; + //load changelog + if FileExistsUTF8(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE) then + mmChangelog.Lines.LoadFromFile(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE); + dataProcess := TDBDataProcess.Create; DLManager := TDownloadManager.Create; DLManager.Restore; From 33ee7f954393fc3beb3e647ab0fc5c9317ce36ef Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 13:10:39 +0800 Subject: [PATCH 0292/2794] update translations --- mangadownloader/languages/fmd.en.po | 8 ++++++++ mangadownloader/languages/fmd.id_ID.po | 8 ++++++++ mangadownloader/languages/fmd.po | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 9a223145b..9df5e5446 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1308,6 +1308,14 @@ msgstr "Expand All" msgid "About" msgstr "About" +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "About FMD" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Changelog" + #: tmainform.tsconnections.caption msgid "Connections" msgstr "Connections" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 738f46b76..d7b3c63bd 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1297,6 +1297,14 @@ msgstr "Bentangkan semua" msgid "About" msgstr "Tentang" +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "Tentang FMD" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Catatan perubahan" + #: tmainform.tsconnections.caption msgid "Connections" msgstr "Koneksi" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index e5df927e4..6e662adfa 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1249,6 +1249,14 @@ msgstr "" msgid "About" msgstr "" +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "" + #: tmainform.tsconnections.caption msgid "Connections" msgstr "" From b8aa5173efe0a1b43653f1b6bb5c47aa189f39a3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 13:43:24 +0800 Subject: [PATCH 0293/2794] minor changes --- baseunits/modules/FoOlSlide.pas | 104 ++++++++++++++++---------------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index c1b013433..ccba338ef 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -92,84 +92,82 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Cardinal; Module: TModuleContainer): Integer; var Parse: TStringList; + info: TMangaInfo; procedure ScanChapters(const StartIndex: Integer); var i: Integer; g: String = ''; begin - with MangaInfo.mangaInfo do + for i := StartIndex to Parse.Count - 1 do begin - for i := StartIndex to Parse.Count - 1 do - begin - if Parse[i] = '' then - Break; - if GetVal(Parse[i], 'class') = 'group' then - if GetVal(Parse[i + 1], 'class') = 'title' then - begin - g := Trim(Parse[i + 2]); - if g = 'Chapters' then - g := '' - else - g += ' '; - end; - if GetTagName(Parse[i]) = 'a' then - if GetVal(Parse[i - 1], 'class') = 'title' then - begin - chapterLinks.Add(GetVal(Parse[i], 'href')); - chapterName.Add(g + Trim(Parse[i + 1])); - end; - end; - //invert chapters - if MangaInfo.mangaInfo.chapterLinks.Count > 0 then - InvertStrings([chapterLinks, chapterName]); + if Parse[i] = '' then + Break; + if GetVal(Parse[i], 'class') = 'group' then + if GetVal(Parse[i + 1], 'class') = 'title' then + begin + g := Trim(Parse[i + 2]); + if g = 'Chapters' then + g := '' + else + g += ' '; + end; + if GetTagName(Parse[i]) = 'a' then + if GetVal(Parse[i - 1], 'class') = 'title' then + begin + info.chapterLinks.Add(GetVal(Parse[i], 'href')); + info.chapterName.Add(g + Trim(Parse[i + 1])); + end; end; + //invert chapters + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); end; procedure ScanParse; var i: Integer; begin - with MangaInfo.mangaInfo do - for i := 0 to Parse.Count - 1 do - begin - //title - if title = '' then - if (GetTagName(Parse[i]) = 'h1') and (GetVal(Parse[i], 'class') = 'title') then - title := CommonStringFilter(Parse[i + 1]); + for i := 0 to Parse.Count - 1 do + begin + //title + if info.title = '' then + if (GetTagName(Parse[i]) = 'h1') and (GetVal(Parse[i], 'class') = 'title') then + info.title := CommonStringFilter(Parse[i + 1]); - //cover - if coverLink = '' then - if GetVal(Parse[i], 'class') = 'thumbnail' then - if GetTagName(Parse[i + 2]) = 'img' then - coverLink := GetVal(Parse[i + 2], 'src'); + //cover + if info.coverLink = '' then + if GetVal(Parse[i], 'class') = 'thumbnail' then + if GetTagName(Parse[i + 2]) = 'img' then + info.coverLink := GetVal(Parse[i + 2], 'src'); - //author - if (Parse[i] = 'Author') and (Parse[i + 1] = '') then - authors := Trim(TrimLeftChar(Parse[i + 2], [':'])); + //author + if (Parse[i] = 'Author') and (Parse[i + 1] = '') then + info.authors := Trim(TrimLeftChar(Parse[i + 2], [':'])); - //artist - if (Parse[i] = 'Artist') and (Parse[i + 1] = '') then - artists := Trim(TrimLeftChar(Parse[i + 2], [':'])); + //artist + if (Parse[i] = 'Artist') and (Parse[i + 1] = '') then + info.artists := Trim(TrimLeftChar(Parse[i + 2], [':'])); - //summary - if (Parse[i] = 'Synopsis') and (Parse[i + 1] = '') then - summary := Trim(TrimLeftChar(Parse[i + 2], [':'])); + //summary + if (Parse[i] = 'Synopsis') and (Parse[i + 1] = '') then + info.summary := Trim(TrimLeftChar(Parse[i + 2], [':'])); - //chapters - if GetVal(Parse[i], 'class') = 'list' then - begin - ScanChapters(i); - Break; - end; + //chapters + if GetVal(Parse[i], 'class') = 'list' then + begin + ScanChapters(i); + Break; end; + end; end; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; - MangaInfo.mangaInfo.website := Module.Website; - MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); Parse := TStringList.Create; try if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then From 0e709bebdda3326c3c58edc7ec2bc687184a6530 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 15:30:25 +0800 Subject: [PATCH 0294/2794] remove wpmanga --- .../includes/WPManga/chapter_page_number.inc | 46 ---- .../WPManga/directory_page_number.inc | 27 --- baseunits/includes/WPManga/image_url.inc | 38 ---- .../includes/WPManga/manga_information.inc | 210 ------------------ .../includes/WPManga/names_and_links.inc | 60 ----- baseunits/uBaseUnit.pas | 18 -- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 14 +- 8 files changed, 2 insertions(+), 426 deletions(-) delete mode 100644 baseunits/includes/WPManga/chapter_page_number.inc delete mode 100644 baseunits/includes/WPManga/directory_page_number.inc delete mode 100644 baseunits/includes/WPManga/image_url.inc delete mode 100644 baseunits/includes/WPManga/manga_information.inc delete mode 100644 baseunits/includes/WPManga/names_and_links.inc diff --git a/baseunits/includes/WPManga/chapter_page_number.inc b/baseunits/includes/WPManga/chapter_page_number.inc deleted file mode 100644 index 42bb51f82..000000000 --- a/baseunits/includes/WPManga/chapter_page_number.inc +++ /dev/null @@ -1,46 +0,0 @@ - function GetWPMangaPageNumber: Boolean; - var - s: String; - i, j: Integer; - Source: TStringList; - begin - s := FillMangaSiteHost(manager.container.MangaSiteID, URL); - if RightStr(s, 1) <> '/' then - s += '/'; - s += '1/'; - - Source := TStringList.Create; - Result := GetPage(TObject(Source), s, manager.container.manager.retryConnect); - - if not Result then - begin - Source.Free; - Exit; - end; - - parse := TStringList.Create; - ParseHTML(Source.Text, parse); - Source.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count-1 do - begin - if (GetTagName(parse[i]) = 'select') and - (GetVal(parse[i], 'class') = 'cbo_wpm_pag') then - begin - for j := i+1 to parse.Count-1 do - begin - s := GetTagName(parse[j]); - if s = '/select' then - Break - else - if s = 'option' then - Inc(manager.container.PageNumber); - end; - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/WPManga/directory_page_number.inc b/baseunits/includes/WPManga/directory_page_number.inc deleted file mode 100644 index 49343d4ba..000000000 --- a/baseunits/includes/WPManga/directory_page_number.inc +++ /dev/null @@ -1,27 +0,0 @@ - function GetWPMangaDirectoryPageNumber: Byte; - var - i: Integer; - const - dirURL = '/manga-list/all/any/last-added/'; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[WebsiteID, 1] + - dirURL, 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - - if parse.Count > 0 then - for i := parse.Count-1 downto 0 do - if Pos(dirURL, parse[i]) <> 0 then - begin - Page := StrToIntDef(ReplaceRegExpr('^.*'+dirURL+'(\d+)/$', - GetVal(parse[i], 'href'), '$1', True), 1); - Break; - end; - end; diff --git a/baseunits/includes/WPManga/image_url.inc b/baseunits/includes/WPManga/image_url.inc deleted file mode 100644 index 08b024371..000000000 --- a/baseunits/includes/WPManga/image_url.inc +++ /dev/null @@ -1,38 +0,0 @@ - function GetWPMangaImageURL: Boolean; - var - s: String; - i, j: Integer; - Source: TStringList; - begin - s := FillMangaSiteHost(manager.container.MangaSiteID, URL); - if RightStr(s, 1) <> '/' then - s += '/'; - s += IntToStr(QWord(workCounter)+1) + '/'; - - Source := TStringList.Create; - Result := GetPage(TObject(Source), s, manager.container.Manager.retryConnect); - - if not Result then - begin - Source.Free; - Exit; - end; - - parse := TStringList.Create; - ParseHTML(Source.Text, parse); - Source.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetVal(parse[i], 'class') = 'wpm_pag mng_rdr') then - begin - for j := i+1 to parse.Count-1 do - if GetTagName(parse[j]) = 'img' then - begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[j], 'src'); - Break; - end; - Break; - end; - parse.Free; - end; diff --git a/baseunits/includes/WPManga/manga_information.inc b/baseunits/includes/WPManga/manga_information.inc deleted file mode 100644 index e66003fcd..000000000 --- a/baseunits/includes/WPManga/manga_information.inc +++ /dev/null @@ -1,210 +0,0 @@ - function GetWPMangaInfoFromURL: Byte; - var - s: String; - i, j: Integer; - isSummaryDone: Boolean = False; - isInfo: Boolean = False; - isInvertChapters: Boolean = True; - pnumber: Integer = 1; - - procedure FindChapters; - var - x, y: Integer; - StartFindPage: Boolean = False; - begin - if parse.Count > 0 then - for x := 0 to parse.Count-1 do - begin - s := LowerCase(GetVal(parse[x], 'class')); - if (GetTagName(parse[x]) = 'ul') and - (AnsiIndexText(s, ['lst', 'chp_lst']) > -1) then - begin - StartFindPage := True; - if s = 'chp_lst' then - isInvertChapters := False; - end; - if StartFindPage then - begin - if GetTagName(parse[x]) = '/ul' then - Break - else - if GetTagName(parse[x]) = 'a' then - begin - if Pos('class="c4', parse[x]) = 0 then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[x], 'href')); - s := ''; - for y := x+1 to parse.Count-1 do - begin - s := Trim(parse[y]); - if (s <> '') and (Pos('<', s) <> 1) then - Break; - end; - mangaInfo.chapterName.Add(CommonStringFilter(s)); - end; - end; - end; - end; - end; - - begin - mangaInfo.website := WebsiteRoots[WebsiteID, 0]; - mangaInfo.url := FillMangaSiteHost(WebsiteID, URL); - - if RightStr(mangaInfo.url, 1) <> '/' then - mangaInfo.url += '/'; - - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count-1 do - begin - //cover - if mangaInfo.coverLink = '' then - begin - if (Pos(' 0) and - (Pos('class="cvr', parse[i]) <> 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - end; - - //title - if mangaInfo.title = '' then - begin - if (Pos('class="ttl"', parse[i]) <> 0) or - (Pos('itemprop="itemreviewed"', parse[i]) <> 0) - then - mangaInfo.title := CommonStringFilter(parse[i+1]) - end; - - //details - s := GetVal(parse[i], 'class'); - if (GetTagName(parse[i]) = 'div') and - (AnsiIndexText(s, ['det', 'lts_chp fr', 'mng_ifo']) > -1) then - isInfo := True; - if isInfo then - begin - if GetTagName(parse[i]) = 'h2' then - isInfo := False - else - begin - s := Trim(parse[i]); - //author - if s = 'Author' then - mangaInfo.authors := CommonStringFilter( - TrimLeftChar(parse[i+2], [':', ' '])) - else - if Pos('/author/', s) <> 0 then - mangaInfo.authors := CommonStringFilter(parse[i+1]) - //artist - else - if s = 'Artist' then - mangaInfo.artists := CommonStringFilter( - TrimLeftChar(parse[i+2], [':', ' '])) - //status - else - if s = 'Status' then - begin - if Pos('completed', LowerCase(parse[i+2])) <> 0 then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end - //genres - else - if (s = 'Category') or (s = 'Genres') then - begin - for j := i+3 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - AddCommaString(mangaInfo.genres, CommonStringFilter(parse[j])); - end; - end - else - if s = 'Type' then - AddCommaString(mangaInfo.genres, - CommonStringFilter(TrimLeftChar(parse[i+2], [':', ' ']))) - else - //summary - if (not isSummaryDone) and (s = 'Summary') then - begin - isSummaryDone := True; - for j := i+2 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := Trim(mangaInfo.summary + LineEnding + - CommonStringFilter(parse[j])); - end; - end; - //summary - if (not isSummaryDone) and (GetTagName(parse[i]) = 'p') then - begin - s := Trim(parse[i+1]); - if (s <> '') and (Pos('<', s) = 0) then - begin - isSummaryDone := True; - for j := i+1 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := Trim(mangaInfo.summary + LineEnding + - CommonStringFilter(parse[j])); - end; - end; - end; - end; - end; - end; - - //chapters - FindChapters; - for i := parse.Count-1 downto 0 do - begin - if (Pos(' 0) and - (Pos('/chapter-list/', parse[i]) <> 0) then - begin - s := GetVal(parse[i], 'href'); - pnumber := StrToIntDef( - ReplaceRegExpr('^.*/chapter-list/(\d+)/$', s, '$1', True), 1); - Break; - end; - end; - if pnumber > 1 then - begin - Source := TStringList.Create; - for i := 2 to pnumber do - begin - if GetPage(TObject(Source), - mangaInfo.url+IntToStr(i)+'/', Reconnect) then - begin - ParseHTML(Source.Text, parse); - FindChapters; - end; - end; - Source.Free; - end; - - //invert chapters - if isInvertChapters then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end; - end; diff --git a/baseunits/includes/WPManga/names_and_links.inc b/baseunits/includes/WPManga/names_and_links.inc deleted file mode 100644 index c9596d202..000000000 --- a/baseunits/includes/WPManga/names_and_links.inc +++ /dev/null @@ -1,60 +0,0 @@ - function GetWPMangaNamesAndLinks: Byte; - var - i, j, k: Integer; - s: String; - const - dirURL = '/manga-list/all/any/last-added/'; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[WebsiteID, 1] + dirURL + - IntToStr(StrToIntDef(URL, -1) + 1) + '/', 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - - if WebsiteID = EYEONMANGA_ID then - begin - for i := 0 to parse.Count-1 do - if GetVal(parse[i], 'class') = 'cvr' then try - if GetTagName(parse[i-4]) = 'a' then - begin - names.Add(CommonStringFilter(parse[i-3])); - links.Add(GetVal(parse[i-4], 'href')); - end; - except - end; - end - else - for i := 0 to parse.Count-1 do - begin - //thumbnail mode - if GetVal(parse[i], 'id') = 'sct_content' then - begin - for j := i+1 to parse.Count-1 do - begin - s := GetTagName(parse[j]); - if (s = 'sct_sidebar') or (s = 'sct_wid_bot') then - Break - else - if GetVal(parse[j], 'class') = 'det' then - begin - for k := j+1 to parse.Count-1 do - begin - if GetTagName(parse[k]) = 'a' then - begin - links.Add(GetVal(parse[k], 'href')); - names.Add(CommonStringFilter(parse[k+1])); - Break; - end; - end; - end; - end; - Break; - end; - end; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bccfce83e..29726a4f4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -851,8 +851,6 @@ function SitesWithoutPageLink(const website: String): Boolean; function SitesWithoutReferer(const website: String): Boolean; function SitesRefererisURL(const website: String): Boolean; function SitesWithSingleChapter(const website: String): Boolean; -function SitesIsWPManga(const websiteid: Cardinal): Boolean; overload; -function SitesIsWPManga(const website: String): Boolean; overload; // Fill in website host if it's not present function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; @@ -1264,7 +1262,6 @@ function SitesWithSortedList(const website : String) : Boolean; Result := Modules.Module[i].SortedList; Exit; end; - Result := SitesIsWPManga(website); if not Result then Result := SitesMemberOf(website, [ FAKKU_ID, @@ -1397,21 +1394,6 @@ function SitesWithSingleChapter(const website : String) : Boolean; ]); end; -function SitesIsWPManga(const websiteid: Cardinal): Boolean; -begin - Result := websiteid in [ - MANGACAP_ID, - MANGABOOM_ID, - AUTHRONE_ID, - EYEONMANGA_ID - ]; -end; - -function SitesIsWPManga(const website: String): Boolean; -begin - Result := SitesIsWPManga(GetMangaSiteID(website)); -end; - function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; begin Result := URL; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index dfe5c32dc..e70b22bef 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1996,8 +1996,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/Madokami/directory_page_number.inc} - {$I includes/WPManga/directory_page_number.inc} - begin Page := 0; @@ -2168,9 +2166,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[MADOKAMI_ID, 0] then Result := GetMadokamiDirectoryPageNumber else - if SitesIsWPManga(WebsiteID) then - Result := GetWPMangaDirectoryPageNumber - else begin Result := NO_ERROR; Page := 1; @@ -2350,8 +2345,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Madokami/names_and_links.inc} - {$I includes/WPManga/names_and_links.inc} - begin //load User-Agent from INIAdvanced if website <> '' then @@ -2620,9 +2613,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[MADOKAMI_ID, 0] then Result := MadokamiGetNamesAndLinks else - if SitesIsWPManga(WebsiteID) then - Result := GetWPMangaNamesAndLinks - else begin Result := INFORMATION_NOT_FOUND; Source.Free; @@ -2807,8 +2797,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/Madokami/manga_information.inc} - {$I includes/WPManga/manga_information.inc} - begin if Trim(URL) = '' then Exit(INFORMATION_NOT_FOUND); @@ -3085,9 +3073,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = GetMangaSiteName(MADOKAMI_ID) then Result := GetMadokamiInfoFromURL else - if SitesIsWPManga(WebsiteID) then - Result := GetWPMangaInfoFromURL - else begin Source.Free; Result := INFORMATION_NOT_FOUND; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b21743a48..ff9f9a0dd 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -512,8 +512,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Madokami/chapter_page_number.inc} - {$I includes/WPManga/chapter_page_number.inc} - begin Result := False; manager.container.PageNumber := 0; @@ -728,10 +726,7 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := GetDynastyScansPageNumber else if manager.container.MangaSiteID = MADOKAMI_ID then - Result := GetMadokamiPageNumber - else - if SitesIsWPManga(manager.container.MangaSiteID) then - Result := GetWPMangaPageNumber; + Result := GetMadokamiPageNumber; end; end; @@ -867,8 +862,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaAt/image_url.inc} - {$I includes/WPManga/image_url.inc} - begin Result := False; if (manager.container.PageLinks.Count > 0) and @@ -1082,10 +1075,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; Result := GetPornComixImageURL else if manager.container.MangaSiteID = MANGAAT_ID then - Result := GetMangaAtImageURL - else - if SitesIsWPManga(manager.container.MangaSiteID) then - Result := GetWPMangaImageURL; + Result := GetMangaAtImageURL; end; end; From 7d857e390d486fcfe26412531e968e01f10847e2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 15:31:04 +0800 Subject: [PATCH 0295/2794] add wpmanga module --- baseunits/ModuleList.inc | 3 +- baseunits/modules/WPManga.pas | 522 ++++++++++++++++++++++++++++++++++ 2 files changed, 524 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/WPManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 4bebd7ff2..1a1035470 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,4 +1,5 @@ uses FoOlSlide, mh160com, - Batoto; + Batoto, + WPManga; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas new file mode 100644 index 000000000..571126307 --- /dev/null +++ b/baseunits/modules/WPManga.pas @@ -0,0 +1,522 @@ +unit WPManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, RegExpr, strutils; + +implementation + +const + dirURL = '/manga-list/all/any/last-added/'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + Parse: TStringList; + + procedure ScanParse; + var + i: Integer; + begin + for i := Parse.Count - 1 downto 0 do + if Pos(dirURL, Parse[i]) <> 0 then + begin + Page := StrToIntDef(ReplaceRegExpr('^.*' + dirURL + '(\d+)/$', + GetVal(Parse[i], 'href'), '$1', True), 1); + Break; + end; + end; + +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Parse: TStringList; + + procedure ScanNamesEyeOnManga; + var + i: Integer; + begin + for i := 0 to parse.Count - 1 do + if GetVal(parse[i], 'class') = 'cvr' then + try + if GetTagName(parse[i - 4]) = 'a' then + begin + names.Add(CommonStringFilter(parse[i - 3])); + links.Add(GetVal(parse[i - 4], 'href')); + end; + except + end; + end; + + procedure ScanNamesWPManga; + var + i, j, k: Integer; + s: String; + begin + for i := 0 to parse.Count - 1 do + begin + //thumbnail mode + if GetVal(parse[i], 'id') = 'sct_content' then + begin + for j := i + 1 to parse.Count - 1 do + begin + s := GetTagName(parse[j]); + if (s = 'sct_sidebar') or (s = 'sct_wid_bot') then + Break + else + if GetVal(parse[j], 'class') = 'det' then + begin + for k := j + 1 to parse.Count - 1 do + begin + if GetTagName(parse[k]) = 'a' then + begin + links.Add(GetVal(parse[k], 'href')); + names.Add(CommonStringFilter(parse[k + 1])); + Break; + end; + end; + end; + end; + Break; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL + + IncStr(URL) + '/', 3) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + if Module.Website = 'EyeOnManga' then + ScanNamesEyeOnManga + else + ScanNamesWPManga; + end; + end; + finally + Parse.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; Module: TModuleContainer): Integer; +var + Parse: TStringList; + info: TMangaInfo; + isInvertChapters: Boolean; + + procedure ScanChapters; + var + i, j: Integer; + s: String; + StartFindPage: Boolean; + begin + StartFindPage := False; + for i := 0 to parse.Count - 1 do + begin + if not StartFindPage then + begin + s := LowerCase(GetVal(parse[i], 'class')); + if (GetTagName(parse[i]) = 'ul') and + (AnsiIndexText(s, ['lst', 'chp_lst']) > -1) then + begin + StartFindPage := True; + if s = 'chp_lst' then + isInvertChapters := False; + end; + end + else + begin + if GetTagName(parse[i]) = '/ul' then + Break + else + if GetTagName(parse[i]) = 'a' then + begin + if Pos('class="c4', parse[i]) = 0 then + begin + s := ''; + for j := i + 1 to parse.Count - 1 do + begin + s := Trim(parse[j]); + if (s <> '') and (Pos('<', s) <> 1) then + Break; + end; + info.chapterLinks.Add(GetVal(parse[i], 'href')); + info.chapterName.Add(CommonStringFilter(s)); + end; + end; + end; + end; + end; + + procedure ScanParse; + var + i, j, pnumber: Integer; + s: String; + isInfo: Boolean; + isSummaryDone: Boolean; + begin + info.genres := ''; + info.summary := ''; + isInvertChapters := True; + isInfo := False; + isSummaryDone := False; + for i := 0 to parse.Count - 1 do + begin + //cover + if info.coverLink = '' then + begin + if (Pos(' 0) and + (Pos('class="cvr', parse[i]) <> 0) then + info.coverLink := GetVal(parse[i], 'src'); + end; + + //title + if info.title = '' then + begin + if (Pos('class="ttl"', parse[i]) <> 0) or + (Pos('itemprop="itemreviewed"', parse[i]) <> 0) then + info.title := CommonStringFilter(parse[i + 1]); + end; + + //details + s := GetVal(parse[i], 'class'); + if (GetTagName(parse[i]) = 'div') and + (AnsiIndexText(s, ['det', 'lts_chp fr', 'mng_ifo']) > -1) then + isInfo := True; + if isInfo then + begin + if GetTagName(parse[i]) = 'h2' then + isInfo := False + else + begin + s := Trim(parse[i]); + //author + if s = 'Author' then + info.authors := CommonStringFilter( + TrimLeftChar(parse[i + 2], [':', ' '])) + else + if Pos('/author/', s) <> 0 then + info.authors := CommonStringFilter(parse[i + 1]) + //artist + else + if s = 'Artist' then + info.artists := CommonStringFilter( + TrimLeftChar(parse[i + 2], [':', ' '])) + //status + else + if s = 'Status' then + begin + if Pos('completed', LowerCase(parse[i + 2])) <> 0 then + info.status := '0' + else + info.status := '1'; + end + //genres + else + if (s = 'Category') or (s = 'Genres') then + begin + for j := i + 3 to parse.Count - 1 do + begin + if GetTagName(parse[j]) = '/p' then + Break + else + if Pos('<', parse[j]) = 0 then + AddCommaString(info.genres, CommonStringFilter(parse[j])); + end; + end + else + if s = 'Type' then + AddCommaString(info.genres, + CommonStringFilter(TrimLeftChar(parse[i + 2], [':', ' ']))) + else + //summary + if (not isSummaryDone) and (s = 'Summary') then + begin + isSummaryDone := True; + for j := i + 2 to parse.Count - 1 do + begin + if GetTagName(parse[j]) = '/p' then + Break + else + if Pos('<', parse[j]) = 0 then + info.summary := Trim(info.summary + LineEnding + + CommonStringFilter(parse[j])); + end; + end; + //summary + if (not isSummaryDone) and (GetTagName(parse[i]) = 'p') then + begin + s := Trim(parse[i + 1]); + if (s <> '') and (Pos('<', s) = 0) then + begin + isSummaryDone := True; + for j := i + 1 to parse.Count - 1 do + begin + if GetTagName(parse[j]) = '/p' then + Break + else + if Pos('<', parse[j]) = 0 then + info.summary := Trim(info.summary + LineEnding + + CommonStringFilter(parse[j])); + end; + end; + end; + end; + end; + end; + + //chapters + ScanChapters; + pnumber := 1; + for i := parse.Count - 1 downto 0 do + begin + if (Pos(' 0) and + (Pos('/chapter-list/', parse[i]) <> 0) then + begin + s := GetVal(parse[i], 'href'); + pnumber := StrToIntDef( + ReplaceRegExpr('^.*/chapter-list/(\d+)/$', s, '$1', True), 1); + Break; + end; + end; + if pnumber > 1 then + begin + for i := 2 to pnumber do + begin + if MangaInfo.GetPage(TObject(Parse), + info.url + 'chapter-list/' + IntToStr(i) + '/', Reconnect) then + begin + ParseHTML(Parse.Text, parse); + if Parse.Count > 0 then + ScanChapters; + end; + end; + end; + + //invert chapters + if isInvertChapters then + InvertStrings([info.chapterName, info.chapterLinks]); + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Parse := TStringList.Create; + try + if Length(info.url) > 0 then + if RightStr(info.url, 1) <> '/' then + info.url += '/'; + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + s: String; + + procedure ScanParse; + var + i, j: Integer; + s: String; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(parse[i]) = 'select') and + (GetVal(parse[i], 'class') = 'cbo_wpm_pag') then + begin + for j := i + 1 to parse.Count - 1 do + begin + s := GetTagName(parse[j]); + if s = '/select' then + Break + else + if s = 'option' then + Inc(Container.PageNumber); + end; + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Parse := TStringList.Create; + try + s := FillHost(Module.RootURL, URL); + if Length(s) > 0 then + if RightStr(s, 1) <> '/' then + s += '/'; + s += '1/'; + if DownloadThread.GetPage(TObject(Parse), s, Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + s: String; + + procedure ScanParse; + var + i, j: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetVal(Parse[i], 'class') = 'wpm_pag mng_rdr') then + begin + for j := i + 1 to Parse.Count - 1 do + if GetTagName(Parse[j]) = 'img' then + begin + Container.PageLinks[DownloadThread.WorkCounter] := GetVal(Parse[j], 'src'); + Break; + end; + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Parse := TStringList.Create; + try + s := FillHost(Module.RootURL, URL); + if Length(s) > 0 then + if RightStr(s, 1) <> '/' then + s += '/'; + s += IntToStr(DownloadThread.workCounter + 1) + '/'; + if DownloadThread.GetPage(TObject(Parse), s, Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaCap'; + RootURL := 'http://www.mangacap.com'; + SortedList := True; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + with AddModule do + begin + Website := 'MangaBoom'; + RootURL := 'http://www.mangaboom.com'; + SortedList := True; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + with AddModule do + begin + Website := 'Authrone'; + RootURL := 'http://www.authrone.com'; + SortedList := True; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + with AddModule do + begin + Website := 'EyeOnManga'; + RootURL := 'http://www.eyeonmanga.com'; + SortedList := True; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 18e840ad24fd55faf6b6292711d84da6d89c0861 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 15:39:07 +0800 Subject: [PATCH 0296/2794] remove wpmanga --- baseunits/uBaseUnit.pas | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 29726a4f4..c5f4f4907 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -358,12 +358,8 @@ interface LONEMANGA_ID = 94; DYNASTYSCANS_ID = 95; MADOKAMI_ID = 96; - MANGACAP_ID = 97; - MANGABOOM_ID = 98; - AUTHRONE_ID = 99; - EYEONMANGA_ID = 100; - WebsiteRoots: array [0..100] of array [0..1] of string = ( + WebsiteRoots: array [0..96] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -460,11 +456,7 @@ interface ('ReadMangaToday', 'http://www.readmanga.today'), ('LoneManga', 'http://lonemanga.com'), ('Dynasty-Scans', 'http://dynasty-scans.com'), - ('Madokami', 'https://manga.madokami.com'), - ('MangaCap', 'http://www.mangacap.com'), - ('MangaBoom', 'http://www.mangaboom.com'), - ('Authrone', 'http://www.authrone.com'), - ('EyeOnManga', 'http://www.eyeonmanga.com') + ('Madokami', 'https://manga.madokami.com') ); ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; @@ -1288,8 +1280,7 @@ function SitesWithSortedList(const website : String) : Boolean; PORNCOMIXIC_ID, PORNXXXCOMICS_ID, MANGAPARK_ID, - SENMANGA_ID, - MANGACAP_ID + SENMANGA_ID ]); end; From 9aaa1d180bc617a7b65063010f053449a939ca60 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 15:45:35 +0800 Subject: [PATCH 0297/2794] remove batoto residual var --- baseunits/uBaseUnit.pas | 188 +++++++++---------- mangadownloader/forms/frmImportFavorites.pas | 2 - 2 files changed, 93 insertions(+), 97 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c5f4f4907..f6394b836 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -266,106 +266,104 @@ interface MANGAINN_ID = 2; OURMANGA_ID = 3; KISSMANGA_ID = 4; - BATOTO_ID = 5; - MANGA24H_ID = 6; - VNSHARING_ID = 7; - HENTAI2READ_ID = 8; - FAKKU_ID = 9; - TRUYEN18_ID = 10; - MANGAREADER_ID = 11; - MANGAPARK_ID = 12; - EHENTAI_ID = 13; - MANGAFOX_ID = 14; - MANGATRADERS_ID = 15; - MANGASTREAM_ID = 16; - MANGAEDEN_ID = 17; - PERVEDEN_ID = 18; - TRUYENTRANHTUAN_ID = 19; - TURKCRAFT_ID = 20; - MANGAVADISI_ID = 21; - MANGAFRAME_ID = 22; - EATMANGA_ID = 23; - STARKANA_ID = 24; - MANGAPANDA_ID = 25; - REDHAWKSCANS_ID = 26; - BLOGTRUYEN_ID = 27; - KOMIKID_ID = 28; - SUBMANGA_ID = 29; - ESMANGAHERE_ID = 30; - ANIMEEXTREMIST_ID = 31; - PECINTAKOMIK_ID = 32; - HUGEMANGA_ID = 33; - S2SCAN_ID = 34; - SENMANGA_ID = 35; - IMANHUA_ID = 36; - MABUNS_ID = 37; - MANGAESTA_ID = 38; - CENTRALDEMANGAS_ID = 39; - EGSCANS_ID = 40; - MANGAAR_ID = 41; - MANGAAE_ID = 42; - ANIMESTORY_ID = 43; - LECTUREENLIGNE_ID = 44; - SCANMANGA_ID = 45; - MANGAGO_ID = 46; - DM5_ID = 47; - PURURIN_ID = 48; - MANGACOW_ID = 49; - KIVMANGA_ID = 50; - MANGACAN_ID = 51; - MEINMANGA_ID = 52; - MANGASPROJECT_ID = 53; - MANGAREADER_POR_ID = 54; - MANGA2U_ID = 55; - MANGASTREAMTO_ID = 56; - NINEMANGA_ID = 57; - NINEMANGA_ES_ID = 58; - NINEMANGA_CN_ID = 59; - NINEMANGA_RU_ID = 60; - NINEMANGA_DE_ID = 61; - NINEMANGA_IT_ID = 62; - NINEMANGA_BR_ID = 63; - JAPANSHIN_ID = 64; - JAPSCAN_ID = 65; - CENTRUMMANGI_PL_ID = 66; - MANGALIB_PL_ID = 67; - ONEMANGA_ID = 68; - MANGATOWN_ID = 69; - READHENTAIMANGA_ID = 70; - MANGAOKU_ID = 71; - MYREADINGMANGAINFO_ID = 72; - IKOMIK_ID = 73; - NHENTAI_ID = 74; - UNIONMANGAS_ID = 75; - MANGAMINT_ID = 76; - UNIXMANGA_ID = 77; - HAKIHOME_ID = 78; - EXTREMEMANGAS_ID = 79; - MANGAHOST_ID = 80; - PORNCOMIX_ID = 81; - PORNCOMIXRE_ID = 82; - PORNCOMIXIC_ID = 83; - XXCOMICS_ID = 84; - XXCOMICSMT_ID = 85; - XXCOMICS3D_ID = 86; - PORNXXXCOMICS_ID = 87; - MANGASEE_ID = 88; - MANGAKU_ID = 89; - ACADEMYVN_ID = 90; - MANGAAT_ID = 91; - SENMANGARAW_ID = 92; - READMANGATODAY_ID = 93; - LONEMANGA_ID = 94; - DYNASTYSCANS_ID = 95; - MADOKAMI_ID = 96; - - WebsiteRoots: array [0..96] of array [0..1] of string = ( + MANGA24H_ID = 5; + VNSHARING_ID = 6; + HENTAI2READ_ID = 7; + FAKKU_ID = 8; + TRUYEN18_ID = 9; + MANGAREADER_ID = 10; + MANGAPARK_ID = 11; + EHENTAI_ID = 12; + MANGAFOX_ID = 13; + MANGATRADERS_ID = 14; + MANGASTREAM_ID = 15; + MANGAEDEN_ID = 16; + PERVEDEN_ID = 17; + TRUYENTRANHTUAN_ID = 18; + TURKCRAFT_ID = 19; + MANGAVADISI_ID = 20; + MANGAFRAME_ID = 21; + EATMANGA_ID = 22; + STARKANA_ID = 23; + MANGAPANDA_ID = 24; + REDHAWKSCANS_ID = 25; + BLOGTRUYEN_ID = 26; + KOMIKID_ID = 27; + SUBMANGA_ID = 28; + ESMANGAHERE_ID = 29; + ANIMEEXTREMIST_ID = 30; + PECINTAKOMIK_ID = 31; + HUGEMANGA_ID = 32; + S2SCAN_ID = 33; + SENMANGA_ID = 34; + IMANHUA_ID = 35; + MABUNS_ID = 36; + MANGAESTA_ID = 37; + CENTRALDEMANGAS_ID = 38; + EGSCANS_ID = 39; + MANGAAR_ID = 40; + MANGAAE_ID = 41; + ANIMESTORY_ID = 42; + LECTUREENLIGNE_ID = 43; + SCANMANGA_ID = 44; + MANGAGO_ID = 45; + DM5_ID = 46; + PURURIN_ID = 47; + MANGACOW_ID = 48; + KIVMANGA_ID = 49; + MANGACAN_ID = 50; + MEINMANGA_ID = 51; + MANGASPROJECT_ID = 52; + MANGAREADER_POR_ID = 53; + MANGA2U_ID = 54; + MANGASTREAMTO_ID = 55; + NINEMANGA_ID = 56; + NINEMANGA_ES_ID = 57; + NINEMANGA_CN_ID = 58; + NINEMANGA_RU_ID = 59; + NINEMANGA_DE_ID = 60; + NINEMANGA_IT_ID = 61; + NINEMANGA_BR_ID = 62; + JAPANSHIN_ID = 63; + JAPSCAN_ID = 64; + CENTRUMMANGI_PL_ID = 65; + MANGALIB_PL_ID = 66; + ONEMANGA_ID = 67; + MANGATOWN_ID = 68; + READHENTAIMANGA_ID = 69; + MANGAOKU_ID = 70; + MYREADINGMANGAINFO_ID = 71; + IKOMIK_ID = 72; + NHENTAI_ID = 73; + UNIONMANGAS_ID = 74; + MANGAMINT_ID = 75; + UNIXMANGA_ID = 76; + HAKIHOME_ID = 77; + EXTREMEMANGAS_ID = 78; + MANGAHOST_ID = 79; + PORNCOMIX_ID = 80; + PORNCOMIXRE_ID = 81; + PORNCOMIXIC_ID = 82; + XXCOMICS_ID = 83; + XXCOMICSMT_ID = 84; + XXCOMICS3D_ID = 85; + PORNXXXCOMICS_ID = 86; + MANGASEE_ID = 87; + MANGAKU_ID = 88; + ACADEMYVN_ID = 89; + MANGAAT_ID = 90; + SENMANGARAW_ID = 91; + READMANGATODAY_ID = 92; + LONEMANGA_ID = 93; + DYNASTYSCANS_ID = 94; + MADOKAMI_ID = 95; + + WebsiteRoots: array [0..95] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), ('KissManga', 'http://kissmanga.com'), - ('Batoto', 'http://bato.to'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Hentai2Read', 'http://hentai2read.com'), diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index a1f5ab083..c1ce7800d 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -95,8 +95,6 @@ procedure TImportFavorites.DMDHandle; StringReplace(urlList.Strings[i], 'http://mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); urlList.Strings[i]:= StringReplace(urlList.Strings[i], 'http://www.mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); - urlList.Strings[i]:= - StringReplace(urlList.Strings[i], 'http://www.batoto.com', WebsiteRoots[BATOTO_ID,1], []); isUnimported:= TRUE; for j:= 0 to High(WebsiteRoots) do begin From 226840e452c34ede423c211ff06d9778bbc556ef Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 16:01:28 +0800 Subject: [PATCH 0298/2794] importfavorites, adapt with websitemodules untested --- mangadownloader/forms/frmImportFavorites.pas | 62 +++++++++++++------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index c1ce7800d..66a625d3d 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -12,7 +12,8 @@ interface uses Classes, SysUtils, Forms, Dialogs, StdCtrls, Buttons, DefaultTranslator, - lazutf8classes, LazFileUtils, uBaseUnit, frmNewChapter; + lazutf8classes, LazFileUtils, uBaseUnit, WebsiteModules, RegExpr, + frmNewChapter; type @@ -61,9 +62,11 @@ procedure TImportFavorites.DMDHandle; list, urlList, mangaList: TStringList; + host, + webs, path: String; - i, j: Cardinal; - isUnimported: Boolean; + i, j, m: Integer; + regx: TRegExpr; begin if NOT FileExistsUTF8(CorrectFilePath(edPath.Text) + 'Config/Bookmarks') then exit; @@ -89,31 +92,46 @@ procedure TImportFavorites.DMDHandle; if urlList.Count > 0 then begin path:= CorrectFilePath(MainForm.options.ReadString('saveto', 'SaveTo', '')); - for i:= 0 to urlList.Count-1 do - begin - urlList.Strings[i]:= - StringReplace(urlList.Strings[i], 'http://mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); - urlList.Strings[i]:= - StringReplace(urlList.Strings[i], 'http://www.mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); - isUnimported:= TRUE; - for j:= 0 to High(WebsiteRoots) do + regx := TRegExpr.Create; + try + regx.Expression := REGEX_HOST; + for i:= 0 to urlList.Count-1 do begin - if (Pos(UpCase(WebsiteRoots[j,1]), UpCase(urlList.Strings[i])) > 0) AND - (Pos('comic/_/comics/double-marriage-r3713', urlList.Strings[i]) = 0) then + urlList.Strings[i]:= + StringReplace(urlList.Strings[i], 'http://mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); + urlList.Strings[i]:= + StringReplace(urlList.Strings[i], 'http://www.mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); + + host := ''; + webs := ''; + host := LowerCase(regx.Replace(urlList[i], '$2', True)); + if host <> '' then + begin + m := Modules.LocateModuleByHost(host); + if m > -1 then + webs := Modules.Module[m].Website; + if webs = '' then + begin + for j := Low(WebsiteRoots) to High(WebsiteRoots) do + if Pos(host, LowerCase(WebsiteRoots[j, 1])) <> 0 then + webs := WebsiteRoots[j, 0]; + end; + end; + + if webs <> '' then begin MainForm.SilentThreadManager.Add( MD_AddToFavorites, - WebsiteRoots[j,0], - mangaList.Strings[i], - StringReplace(urlList.Strings[i], WebsiteRoots[j,1], '', []), + webs, + mangaList[i], + RemoveHostFromURL(urlList[i]), path); - Sleep(16); - isUnimported:= FALSE; - break; - end; + end + else + unimportedMangas.Add(mangaList.Strings[i] + ' <' + urlList.Strings[i] + '>'); end; - if isUnimported then - unimportedMangas.Add(mangaList.Strings[i] + ' <' + urlList.Strings[i] + '>'); + finally + regx.Free; end; end; From e28c20c93a8567ccaffa2c5a55c4d573fd526f86 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 16:13:39 +0800 Subject: [PATCH 0299/2794] wpmanga, simplify add module --- baseunits/modules/WPManga.pas | 67 +++++++++++------------------------ 1 file changed, 20 insertions(+), 47 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 571126307..6a1a4c674 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -465,55 +465,28 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; end; procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaCap'; - RootURL := 'http://www.mangacap.com'; - SortedList := True; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; - with AddModule do - begin - Website := 'MangaBoom'; - RootURL := 'http://www.mangaboom.com'; - SortedList := True; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; - with AddModule do - begin - Website := 'Authrone'; - RootURL := 'http://www.authrone.com'; - SortedList := True; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; - with AddModule do + + procedure AddWebsiteModule(AWebsite, ARootURL: String); begin - Website := 'EyeOnManga'; - RootURL := 'http://www.eyeonmanga.com'; - SortedList := True; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; + with AddModule do + begin + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; end; + +begin + AddWebsiteModule('MangaCap', 'http://www.mangacap.com'); + AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com'); + AddWebsiteModule('Authrone', 'http://www.authrone.com'); + AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); end; initialization From 1a36e4be99e77123d9210ed081e7366b6f5ed35e Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 27 Jul 2015 16:21:11 +0800 Subject: [PATCH 0300/2794] wpmanga, minor changes --- baseunits/modules/WPManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 6a1a4c674..b5a5eec42 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -372,7 +372,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin for i := 0 to Parse.Count - 1 do if (GetTagName(parse[i]) = 'select') and - (GetVal(parse[i], 'class') = 'cbo_wpm_pag') then + (Pos('cbo_wpm_pag', Parse[i]) <> 0) then begin for j := i + 1 to parse.Count - 1 do begin From 3e4d5e907c9854a86521a607f2ad05cd5a282334 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 03:48:01 +0800 Subject: [PATCH 0301/2794] frmdroptarget, get html format clipboard to parse multiple url --- mangadownloader/forms/frmDropTarget.pas | 210 +++++++++++++++++++----- 1 file changed, 172 insertions(+), 38 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 15ee8460e..b6c3490bb 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -5,8 +5,8 @@ interface uses - Classes, Windows, SysUtils, ActiveX, comobj, Forms, Controls, - ExtCtrls, Menus, LCLType, DefaultTranslator; + Classes, Windows, SysUtils, ActiveX, comobj, HTMLUtil, Forms, Controls, + ExtCtrls, Menus, LCLType, DefaultTranslator, uBaseUnit; type @@ -34,14 +34,26 @@ TFormDropTarget = class(TForm, IDropTarget) { private declarations } md: Boolean; x0, y0: Integer; + FCanDrop: Boolean; // IDropTarget + function MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; + function CursorEffect(const AllowedEffects: LongInt; + const KeyState: Integer): LongInt; + function CanDrop(const DataObj: IDataObject): Boolean; + function GetTextFromObj(const DataObj: IDataObject; + const Fmt: TClipFormat): String; + function GetWideTextFromObj(const DataObj: IDataObject; + const Fmt: TClipFormat): String; + function GetURLsFromHTML(const S: String): String; + function ParseDataObj(const DataObj: IDataObject; + const Fmt: TClipboardFormat): String; function DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; - pt: TPoint; var dwEffect: DWORD): HResult; stdcall; - function {%H-}DragOver(grfKeyState: DWORD; pt: TPoint; + {%H-}pt: TPoint; var dwEffect: DWORD): HResult; stdcall; + function {%H-}DragOver(grfKeyState: DWORD; {%H-}pt: TPoint; var dwEffect: DWORD): HResult; stdcall; function DragLeave: HResult; stdcall; - function Drop(const dataObj: IDataObject; grfKeyState: DWORD; - pt: TPoint; var dwEffect: DWORD): HResult; stdcall; + function Drop(const dataObj: IDataObject; {%H-}grfKeyState: DWORD; + {%H-}pt: TPoint; var {%H-}dwEffect: DWORD): HResult; stdcall; protected procedure CreateParams(var Params: TCreateParams); override; public @@ -62,6 +74,9 @@ implementation uses frmMain; +var + CF_HTML: TClipFormat; + {$R *.lfm} { TFormDropTarget } @@ -151,17 +166,150 @@ procedure TFormDropTarget.miCloseClick(Sender: TObject); Self.Close; end; +function TFormDropTarget.MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; +begin + Result.cfFormat := Fmt; + Result.ptd := nil; + Result.dwAspect := DVASPECT_CONTENT; + Result.lindex := -1; + Result.tymed := TYMED_HGLOBAL; +end; + +function TFormDropTarget.CursorEffect(const AllowedEffects: LongInt; + const KeyState: Integer): LongInt; +begin + Result := DROPEFFECT_NONE; + if FCanDrop then + begin + if (KeyState and MK_SHIFT = MK_SHIFT) and + (DROPEFFECT_MOVE and AllowedEffects = DROPEFFECT_MOVE) then + Result := DROPEFFECT_MOVE + else if (DROPEFFECT_COPY and AllowedEffects = DROPEFFECT_COPY) then + Result := DROPEFFECT_COPY; + end; +end; + +function TFormDropTarget.CanDrop(const DataObj: IDataObject): Boolean; +begin + Result := DataObj.QueryGetData(MakeFormatEtc(CF_HTML)) = S_OK; + if not Result then + Result := DataObj.QueryGetData(MakeFormatEtc(CF_UNICODETEXT)) = S_OK; + if not Result then + Result := DataObj.QueryGetData(MakeFormatEtc(CF_TEXT)) = S_OK; +end; + +function TFormDropTarget.GetTextFromObj(const DataObj: IDataObject; + const Fmt: TClipFormat): String; +var + Medium: TStgMedium; + PText: PChar; +begin + if DataObj.GetData(MakeFormatEtc(Fmt), Medium) = S_OK then + begin + Assert(Medium.tymed = MakeFormatEtc(Fmt).tymed); + try + PText := GlobalLock(Medium.hGlobal); + try + Result := PText; + finally + GlobalUnlock(Medium.hGlobal); + end; + finally + ReleaseStgMedium(Medium); + end; + end + else + Result := ''; +end; + +function TFormDropTarget.GetWideTextFromObj(const DataObj: IDataObject; + const Fmt: TClipFormat): String; +var + Medium: TStgMedium; + PwText: PWideChar; +begin + if DataObj.GetData(MakeFormatEtc(Fmt), Medium) = S_OK then + begin + Assert(Medium.tymed = MakeFormatEtc(Fmt).tymed); + try + PwText := GlobalLock(Medium.hGlobal); + try + Result := PwText; + finally + GlobalUnlock(Medium.hGlobal); + end; + finally + ReleaseStgMedium(Medium); + end; + end + else + Result := ''; +end; + +function TFormDropTarget.GetURLsFromHTML(const S: String): String; +var + Parse, URls: TStringList; + i: Integer; + t: String; +begin + Result := S; + if S = '' then Exit; + Parse:= TStringList.Create; + try + ParseHTML(S, Parse); + if Parse.Count > 0 then + begin + URls := TStringList.Create; + try + for i := 0 to Parse.Count -1 do + begin + if LowerCase(GetTagName(Parse[i])) = 'a' then + t := GetVal(Parse[i], 'href'); + if Pos('javascript', t) <> 1 then + URls.Add(t); + end; + if URls.Count > 0 then + begin + RemoveDuplicateStrings(URls); + Result := URls.Text; + end; + finally + URls.Free; + end; + end; + finally + Parse.Free; + end; +end; + +function TFormDropTarget.ParseDataObj(const DataObj: IDataObject; + const Fmt: TClipboardFormat): String; +begin + if Fmt = CF_HTML then + Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) + else + if Fmt = CF_UNICODETEXT then + Result := GetWideTextFromObj(DataObj, Fmt) + else + if Fmt = CF_TEXT then + Result := GetTextFromObj(DataObj, Fmt) + else + Result := ''; + Result := Trim(Result); +end; + function TFormDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; begin - dwEffect := DROPEFFECT_COPY; + FCanDrop := CanDrop(dataObj); + dwEffect := CursorEffect(dwEffect, grfKeyState); Result := S_OK; end; function TFormDropTarget.DragOver(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; begin - dwEffect := DROPEFFECT_COPY; + dwEffect := CursorEffect(dwEffect, grfKeyState); Result := S_OK; end; @@ -173,36 +321,19 @@ function TFormDropTarget.DragLeave: HResult; stdcall; function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; var - aFmtEtc: TFORMATETC; - aStgMed: TSTGMEDIUM; - pData: PChar; -begin - // Support dropping text on edit control - // Make certain the data rendering is available - if (dataObj = nil) then - raise Exception.Create('IDataObject Pointer is not valid!'); - with aFmtEtc do - begin - cfFormat := CF_TEXT; - ptd := nil; - dwAspect := DVASPECT_CONTENT; - lindex := -1; - tymed := TYMED_HGLOBAL; - end; - // Get the data - OleCheck(dataObj.GetData(aFmtEtc, aStgMed)); - try - // Lock the global memory handle to get a pointer to the data - pData := GlobalLock(aStgMed.hGlobal); - // Replace Text in the control you want - if Assigned(OnDropChekout) then - OnDropChekout(pData); - finally - // Finished with the pointer - GlobalUnlock(aStgMed.hGlobal); - // Free the memory - ReleaseStgMedium(aStgMed); - end; + Enum: IEnumFORMATETC; + FmtEtc: TFORMATETC; +begin + OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); + while Enum.Next(1, FmtEtc, nil) = S_OK do + if (FmtEtc.CfFormat = CF_HTML) or + (FmtEtc.CfFormat = CF_UNICODETEXT) or + (FmtEtc.CfFormat = CF_TEXT) then + begin + if Assigned(OnDropChekout) then + OnDropChekout(ParseDataObj(dataObj, FmtEtc.CfFormat)); + Break; + end; Result := S_OK; end; @@ -213,4 +344,7 @@ procedure TFormDropTarget.CreateParams(var Params: TCreateParams); Params.WndParent := GetDesktopWindow; end; +initialization + CF_HTML := RegisterClipboardFormat('HTML Format'); + end. From cf463daba6a842ca233328e48c4628416b7b477f Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 03:48:29 +0800 Subject: [PATCH 0302/2794] mainform, addsiltentthread, support multiple url --- mangadownloader/forms/frmMain.pas | 89 +++++++++++++------------------ 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 819834cc0..8624b5fa7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4494,69 +4494,56 @@ procedure TMainForm.AddChapterNameToList; procedure TMainForm.AddSilentThread(URL: string); var + i, j, m: Integer; + host, link, webs: String; + URls: TStringList; mt: TMetaDataType; - i: Integer; - webid: Cardinal; - website, - webs, - link: String; - regx: TRegExpr; begin - website := ''; - webs := ''; - link := ''; - regx := TRegExpr.Create; + if Trim(URL) = '' then Exit; + URLs := TStringList.Create; try - regx.Expression := '^https?\://'; - if not (regx.Exec(URL)) then - URL := 'http://' + URL; - - regx.Expression := '^https?\:(//[^/]*\w+\.\w+)(\:\d+)?(/|\Z)(.*)$'; - if regx.Exec(URL) then - begin - link := regx.Replace(URL, '$4', True); - webs := regx.Replace(URL, '$1', True); - end; - - if (webs <> '') and (link <> '') then + URls.Text := URL; + if URls.Count > 0 then begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(webs, WebsiteRoots[i, 1]) > 0 then - begin - webid := i; - website := WebsiteRoots[i, 0]; - Break; - end; - if website = '' then - begin - webs := TrimLeftChar(webs, ['/']); - for i := Low(WebsiteRoots) to High(WebsiteRoots) do + with TRegExpr.Create do + try + Expression := REGEX_HOST; + for i := 0 to URls.Count - 1 do begin - if Pos(webs, WebsiteRoots[i, 1]) > 0 then + host := ''; + link := ''; + webs := ''; + host := LowerCase(Replace(URls[i], '$2', True)); + link := Replace(URls[i], '$4', True); + if (host <> '') and (link <> '') then begin - webid := i; - website := WebsiteRoots[i, 0]; - Break; + m := Modules.LocateModuleByHost(host); + if m > -1 then + webs := Modules.Module[m].Website; + if webs = '' then + begin + for j := Low(WebsiteRoots) to High(WebsiteRoots) do + if Pos(host, LowerCase(WebsiteRoots[j, 1])) <> 0 then + webs := WebsiteRoots[j, 0]; + end; + if webs <> '' then + begin + if rgDropTargetMode.ItemIndex = 0 then + mt := MD_DownloadAll + else + mt := MD_AddToFavorites; + if not ((mt = MD_AddToFavorites) and SitesWithoutFavorites(webs)) then + SilentThreadManager.Add(mt, webs, '', link); + end; end; end; - end; - if website <> '' then - begin - link := '/' + link; - URL := FixURL(WebsiteRoots[webid, 1] + link); - DisableAddToFavorites(website); + finally + Free; end; end; finally - regx.Free; + URls.Free; end; - if (website = '') or (link = '') then Exit; - if rgDropTargetMode.ItemIndex = 0 then - mt := MD_DownloadAll - else - mt := MD_AddToFavorites; - if (mt = MD_AddToFavorites) and (SitesWithoutFavorites(website)) then Exit; - SilentThreadManager.Add(mt, website, '', link); end; procedure TMainForm.AddTextToInfo(title, infoText: String); From 5c9ee5a06e34034ebe0ce84c54503800b653fb9f Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 03:58:25 +0800 Subject: [PATCH 0303/2794] frmdroptarget, save show dropbox checkbox if closing manually --- mangadownloader/forms/frmDropTarget.pas | 2 +- mangadownloader/forms/frmMain.pas | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index b6c3490bb..01ac41205 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -104,7 +104,6 @@ procedure TFormDropTarget.FormDestroy(Sender: TObject); RevokeDragDrop(Handle); OleUninitialize; FormDropTarget := nil; - MainForm.ckDropTarget.Checked := False; end; procedure TFormDropTarget.FormMouseDown(Sender: TObject; Button: TMouseButton; @@ -163,6 +162,7 @@ procedure TFormDropTarget.ImResizeMouseMove(Sender: TObject; procedure TFormDropTarget.miCloseClick(Sender: TObject); begin + MainForm.ckDropTarget.Checked := False; Self.Close; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8624b5fa7..1318e54ed 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5050,6 +5050,7 @@ procedure TMainForm.SaveDropTargetFormInformation; begin with options do begin + WriteBool('droptarget', 'Show', ckDropTarget.Checked); WriteInteger('droptarget', 'Opacity', frmDropTarget.FAlphaBlendValue); WriteInteger('droptarget', 'Width', frmDropTarget.FWidth); WriteInteger('droptarget', 'Heigth', frmDropTarget.FHeight); From 9f788078c65ee36787ce0d0580dd1966cb810a6d Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 05:15:14 +0800 Subject: [PATCH 0304/2794] frmdroptarget, try to look at another clipboard format if url empty --- mangadownloader/forms/frmDropTarget.pas | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 01ac41205..fce0c1533 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -250,7 +250,7 @@ function TFormDropTarget.GetURLsFromHTML(const S: String): String; var Parse, URls: TStringList; i: Integer; - t: String; + url: String; begin Result := S; if S = '' then Exit; @@ -261,12 +261,12 @@ function TFormDropTarget.GetURLsFromHTML(const S: String): String; begin URls := TStringList.Create; try - for i := 0 to Parse.Count -1 do + for i := 0 to Parse.Count - 1 do begin if LowerCase(GetTagName(Parse[i])) = 'a' then - t := GetVal(Parse[i], 'href'); - if Pos('javascript', t) <> 1 then - URls.Add(t); + url := GetVal(Parse[i], 'href'); + if Pos('javascript', url) <> 1 then + URls.Add(url); end; if URls.Count > 0 then begin @@ -323,6 +323,7 @@ function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; var Enum: IEnumFORMATETC; FmtEtc: TFORMATETC; + url: String; begin OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); while Enum.Next(1, FmtEtc, nil) = S_OK do @@ -331,8 +332,14 @@ function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; (FmtEtc.CfFormat = CF_TEXT) then begin if Assigned(OnDropChekout) then - OnDropChekout(ParseDataObj(dataObj, FmtEtc.CfFormat)); - Break; + begin + url := ParseDataObj(dataObj, FmtEtc.CfFormat); + if url <> '' then + begin + OnDropChekout(url); + Break; + end; + end; end; Result := S_OK; end; From 6b11a31651a13743daf85d595373a2581ff6cca5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 05:41:07 +0800 Subject: [PATCH 0305/2794] frmdroptarget, add menu to change mode on drop box --- mangadownloader/forms/frmDropTarget.lfm | 14 +++++++++++++ mangadownloader/forms/frmDropTarget.pas | 26 +++++++++++++++++++++++++ mangadownloader/forms/frmMain.pas | 1 + 3 files changed, 41 insertions(+) diff --git a/mangadownloader/forms/frmDropTarget.lfm b/mangadownloader/forms/frmDropTarget.lfm index 8c163d9f0..6363101b5 100644 --- a/mangadownloader/forms/frmDropTarget.lfm +++ b/mangadownloader/forms/frmDropTarget.lfm @@ -146,8 +146,22 @@ object FormDropTarget: TFormDropTarget Stretch = True end object pmDropTarget: TPopupMenu + OnPopup = pmDropTargetPopup left = 188 top = 120 + object miDownloadAll: TMenuItem + Caption = 'Download all' + RadioItem = True + OnClick = miDownloadAllClick + end + object miAddToFavorites: TMenuItem + Caption = 'Add to favorites' + RadioItem = True + OnClick = miAddToFavoritesClick + end + object MenuItem1: TMenuItem + Caption = '-' + end object miClose: TMenuItem Caption = '&Close' OnClick = miCloseClick diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index fce0c1533..513f3ddc2 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -15,6 +15,9 @@ interface TFormDropTarget = class(TForm, IDropTarget) ImResize: TImage; ImDropIcon: TImage; + MenuItem1: TMenuItem; + miDownloadAll: TMenuItem; + miAddToFavorites: TMenuItem; miClose: TMenuItem; pmDropTarget: TPopupMenu; shBorder: TShape; @@ -29,7 +32,10 @@ TFormDropTarget = class(TForm, IDropTarget) procedure FormShow(Sender: TObject); procedure ImResizeMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); + procedure miAddToFavoritesClick(Sender: TObject); procedure miCloseClick(Sender: TObject); + procedure miDownloadAllClick(Sender: TObject); + procedure pmDropTargetPopup(Sender: TObject); private { private declarations } md: Boolean; @@ -160,12 +166,32 @@ procedure TFormDropTarget.ImResizeMouseMove(Sender: TObject; end; end; +procedure TFormDropTarget.miAddToFavoritesClick(Sender: TObject); +begin + miAddToFavorites.Checked := True; + MainForm.rgDropTargetMode.ItemIndex := 1; + MainForm.SaveDropTargetFormInformation; +end; + procedure TFormDropTarget.miCloseClick(Sender: TObject); begin MainForm.ckDropTarget.Checked := False; Self.Close; end; +procedure TFormDropTarget.miDownloadAllClick(Sender: TObject); +begin + miDownloadAll.Checked := True; + MainForm.rgDropTargetMode.ItemIndex := 0; + MainForm.SaveDropTargetFormInformation; +end; + +procedure TFormDropTarget.pmDropTargetPopup(Sender: TObject); +begin + miDownloadAll.Checked := MainForm.rgDropTargetMode.ItemIndex = 0; + miAddToFavorites.Checked := not miDownloadAll.Checked; +end; + function TFormDropTarget.MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; begin Result.cfFormat := Fmt; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1318e54ed..390c95787 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5051,6 +5051,7 @@ procedure TMainForm.SaveDropTargetFormInformation; with options do begin WriteBool('droptarget', 'Show', ckDropTarget.Checked); + WriteInteger('droptarget', 'Mode', rgDropTargetMode.ItemIndex); WriteInteger('droptarget', 'Opacity', frmDropTarget.FAlphaBlendValue); WriteInteger('droptarget', 'Width', frmDropTarget.FWidth); WriteInteger('droptarget', 'Heigth', frmDropTarget.FHeight); From 83b20620b0a6a782011f04b7360161511f17b43e Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 05:42:59 +0800 Subject: [PATCH 0306/2794] update translations --- mangadownloader/languages/fmd.en.po | 11 +++++++++++ mangadownloader/languages/fmd.id_ID.po | 11 +++++++++++ mangadownloader/languages/fmd.po | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 9df5e5446..a105ceaf0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -257,10 +257,20 @@ msgstr "System will hibernate in %d second." msgid "System will shutdown in %d second." msgstr "System will shutdown in %d second." +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Add to favorites" + #: tformdroptarget.miclose.caption msgid "&Close" msgstr "&Close" +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Download all" + #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" msgid "Cancel" @@ -293,6 +303,7 @@ msgid "Abort update list" msgstr "Abort update list" #: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" msgid "Add to favorites" msgstr "Add to favorites" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index d7b3c63bd..106588af0 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -251,10 +251,20 @@ msgstr "Komputer akan dihibernasi dalam %d detik" msgid "System will shutdown in %d second." msgstr "Komputer akan dimatikan dalam %d detik" +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Tambahkan ke kesukaan" + #: tformdroptarget.miclose.caption msgid "&Close" msgstr "&Tutup" +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Unduh semua" + #: timportfavorites.btcancel.caption msgctxt "timportfavorites.btcancel.caption" msgid "Cancel" @@ -287,6 +297,7 @@ msgid "Abort update list" msgstr "Batalkan pembaruan daftar komik" #: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" msgid "Add to favorites" msgstr "Tambahkan ke kesukaan" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 6e662adfa..ef2b3b19f 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -223,10 +223,20 @@ msgstr "" msgid "System will shutdown in %d second." msgstr "" +#: tformdroptarget.miaddtofavorites.caption +msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" +msgid "Add to favorites" +msgstr "" + #: tformdroptarget.miclose.caption msgid "&Close" msgstr "" +#: tformdroptarget.midownloadall.caption +msgctxt "TFORMDROPTARGET.MIDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "" + #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" msgid "Cancel" @@ -259,6 +269,7 @@ msgid "Abort update list" msgstr "" #: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" msgid "Add to favorites" msgstr "" From 93f6db391db25a6296c820da014e2a5ac865caa0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 05:51:37 +0800 Subject: [PATCH 0307/2794] mainform, add menu to abort all silentthread process on sbmain.popup --- mangadownloader/forms/frmMain.lfm | 10 ++++++++++ mangadownloader/forms/frmMain.pas | 21 +++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b7de5dd80..0cfc04c1d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3427,6 +3427,7 @@ object MainForm: TMainForm item Width = 100 end> + PopupMenu = pmSbMain SimplePanel = False end object spMainSplitter: TSplitter @@ -5750,4 +5751,13 @@ object MainForm: TMainForm left = 608 top = 72 end + object pmSbMain: TPopupMenu + OnPopup = pmSbMainPopup + left = 283 + top = 416 + object miAbortSilentThread: TMenuItem + Caption = 'Abort' + OnClick = miAbortSilentThreadClick + end + end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 390c95787..a1d26ff6b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -60,8 +60,10 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + miAbortSilentThread: TMenuItem; mmChangelog: TMemo; pcAbout: TPageControl; + pmSbMain: TPopupMenu; tsAboutText: TTabSheet; tsChangelogText: TTabSheet; TransferRateToolset: TChartToolset; @@ -398,6 +400,7 @@ TMainForm = class(TForm) procedure medtURLDeleteClick(Sender: TObject); procedure medURLSelectAllClick(Sender: TObject); procedure medURLUndoClick(Sender: TObject); + procedure miAbortSilentThreadClick(Sender: TObject); procedure miDownloadViewMangaInfoClick(Sender: TObject); procedure miChapterListHighlightClick(Sender: TObject); procedure miDownloadDeleteTaskClick(Sender: TObject); @@ -436,6 +439,7 @@ TMainForm = class(TForm) procedure pmEditURLPopup(Sender: TObject); procedure pmFavoritesPopup(Sender: TObject); procedure pmMangaListPopup(Sender: TObject); + procedure pmSbMainPopup(Sender: TObject); procedure sbUpdateListDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); procedure seOptionCheckMinutesChange(Sender: TObject); @@ -1384,6 +1388,12 @@ procedure TMainForm.medURLUndoClick(Sender: TObject); edURL.Undo; end; +procedure TMainForm.miAbortSilentThreadClick(Sender: TObject); +begin + if Assigned(SilentThreadManager) then + SilentThreadManager.StopAll(False); +end; + procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); var i: Integer; @@ -3376,6 +3386,17 @@ procedure TMainForm.pmMangaListPopup(Sender: TObject); pmMangaList.Items[2].Enabled := not SitesWithoutFavorites(cbSelectManga.Text); end; +procedure TMainForm.pmSbMainPopup(Sender: TObject); +begin + if Assigned(SilentThreadManager) then + begin + if SilentThreadManager.ItemCount = 0 then + Abort; + end + else + Abort; +end; + procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); var From dfed674c2d00fa927c71e420328362a02d0c3a39 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 05:52:47 +0800 Subject: [PATCH 0308/2794] update translations --- mangadownloader/languages/fmd.en.po | 4 ++++ mangadownloader/languages/fmd.id_ID.po | 4 ++++ mangadownloader/languages/fmd.po | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index a105ceaf0..e67a94ac9 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1132,6 +1132,10 @@ msgstr "Select all" msgid "Undo" msgstr "Undo" +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Abort" + #: tmainform.michapterlistcheckall.caption msgid "Check all" msgstr "Check all" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 106588af0..8cb250d82 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1121,6 +1121,10 @@ msgstr "Pilih semua" msgid "Undo" msgstr "Urungkan" +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Batalkan" + #: tmainform.michapterlistcheckall.caption msgid "Check all" msgstr "Centang semua" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index ef2b3b19f..99ad326d1 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1073,6 +1073,10 @@ msgstr "" msgid "Undo" msgstr "" +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "" + #: tmainform.michapterlistcheckall.caption msgid "Check all" msgstr "" From 9764b07ad453003edcb8e51d247f3b30b4846a3c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 28 Jul 2015 05:59:14 +0800 Subject: [PATCH 0309/2794] Bump version 0.9.19.4 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index d3bd64b44..909bd1c39 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,13 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.4 (28-07-2015) +[+] Added changelog tab +[+] Support multiple url on drop box +[+] Added popup menu to change drop box mode +[+] Added popup menu to abort loading thread (download all/add to favorites) +[*] Various changes and bug fixes + 0.9.19.3 (27-07-2015) [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b3e046dba..71ebc9a8e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index a8615004e..543e326c1 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.3 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.3/fmd_0.9.19.3.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.3/fmd_0.9.19.3_Win64.7z +VERSION=0.9.19.4 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.4/fmd_0.9.19.4.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.4/fmd_0.9.19.4_Win64.7z From 15adca036320e85cdc92bf028b4fe17f9b7ff03f Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 04:14:57 +0800 Subject: [PATCH 0310/2794] clean up --- mangadownloader/md.lpi | 50 +----------------------------------------- mangadownloader/md.lpr | 3 ++- 2 files changed, 3 insertions(+), 50 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 71ebc9a8e..9a7ba2ce1 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -248,7 +248,7 @@ - + @@ -295,54 +295,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index cbba90ab0..652e4205d 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -24,7 +24,8 @@ {$R *.res} begin - with TIniFile.Create(CorrectFilePath(GetCurrentDirUTF8) + CONFIG_FOLDER + CONFIG_FILE) do + with TIniFile.Create(CleanAndExpandDirectory(GetCurrentDirUTF8) + + CONFIG_FOLDER + CONFIG_FILE) do try CheckInstance := ReadBool('general', 'OneInstanceOnly', True); finally From ce0bce589aff41695a9c666d04dc808e19803b44 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 05:11:49 +0800 Subject: [PATCH 0311/2794] baseunit, add function to clean and append url delim --- baseunits/uBaseUnit.pas | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f6394b836..744891885 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -880,6 +880,9 @@ function HTMLDecode(const AStr: String): String; function RemoveSymbols(const input: String): String; function CorrectPathSys(const Path: String): String; +function CleanAndExpandURL(const URL: String): String; +function CleanURL(const URL: String): String; +function AppendURLDelim(const URL: String): String; function FixURL(const URL: String): String; function FixPath(const path: String): String; function GetLastDir(const path: String): String; @@ -2220,6 +2223,39 @@ function SetParams(const input: array of String): String; Result := Result + input[i] + SEPERATOR; end; +function CleanAndExpandURL(const URL: String): String; +begin + Result := AppendURLDelim(CleanURL(URL)); +end; + +function CleanURL(const URL: String): String; +var + host, link: String; +begin + Result := URL; + with TRegExpr.Create do + try + Expression := REGEX_HOST; + host := Replace(URL, '$1$2$3', True); + link := Replace(URL, '$4', True); + if link <> '' then + begin + while Pos('//', link) <> 0 do + link := StringReplace(link, '//', '/', [rfReplaceAll]); + Result := host + URL; + end; + finally + Free; + end; +end; + +function AppendURLDelim(const URL: String): String; +begin + Result := URL; + if (URL <> '') and (URL[Length(URL)] <> '/') then + Result := URL + '/'; +end; + function FixURL(const URL : String) : String; begin Result := URL; From ae63685548247fff5d575a0a57f235870a3b8080 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 05:14:30 +0800 Subject: [PATCH 0312/2794] baseunit, overload incstr --- baseunits/uBaseUnit.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 744891885..f4fda00e7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -901,7 +901,8 @@ function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): String; procedure AddCommaString(var Dest: string; S: string); -function IncStr(const S: String; N: Integer = 1): String; +function IncStr(const S: String; N: Integer = 1): String; overload; +function IncStr(const I: Integer; N: Integer = 1): String; overload; //get heaader value from THTTPSend.Headers function GetHeaderValue(const AHeaders: TStrings; HName: String): String; @@ -1957,6 +1958,11 @@ function IncStr(const S: String; N: Integer): String; end; end; +function IncStr(const I: Integer; N: Integer): String; +begin + Result := IntToStr(I + N); +end; + function GetHeaderValue(const AHeaders: TStrings; HName: String): String; var i, p: Integer; From 6e53c953e770ef8a5ebac0890a8b64666fb11ad2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 05:42:35 +0800 Subject: [PATCH 0313/2794] remove mangafox --- .../includes/MangaFox/chapter_page_number.inc | 32 ---- .../MangaFox/directory_page_number.inc | 35 ---- baseunits/includes/MangaFox/image_url.inc | 30 --- .../includes/MangaFox/manga_information.inc | 117 ------------ .../includes/MangaFox/names_and_links.inc | 36 ---- baseunits/uBaseUnit.pas | 173 +++++++++--------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 - mangadownloader/forms/frmImportFavorites.pas | 5 - 9 files changed, 84 insertions(+), 369 deletions(-) delete mode 100644 baseunits/includes/MangaFox/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaFox/directory_page_number.inc delete mode 100644 baseunits/includes/MangaFox/image_url.inc delete mode 100644 baseunits/includes/MangaFox/manga_information.inc delete mode 100644 baseunits/includes/MangaFox/names_and_links.inc diff --git a/baseunits/includes/MangaFox/chapter_page_number.inc b/baseunits/includes/MangaFox/chapter_page_number.inc deleted file mode 100644 index 7e7250359..000000000 --- a/baseunits/includes/MangaFox/chapter_page_number.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetMangaFoxPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(URL + '/1.html'); - s := FillMangaSiteHost(MANGAFOX_ID, s); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('option value="0"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 3]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaFox/directory_page_number.inc b/baseunits/includes/MangaFox/directory_page_number.inc deleted file mode 100644 index 296f2551d..000000000 --- a/baseunits/includes/MangaFox/directory_page_number.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetMangaFoxDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAFOX_ID, 1] + - MANGAFOX_BROWSER + '?az', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := parse.Count - 1 downto 0 do - begin - if (GetTagName(parse.Strings[i]) = 'span') and - (i <= parse.Count) and - (Pos('span class="next"', parse.Strings[i]) <> 0) then - begin - s := GetString(parse.Strings[i - 6], 'href="', '.htm'); - Page := StrToInt(s); - Result := NO_ERROR; - Break; - end; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/MangaFox/image_url.inc b/baseunits/includes/MangaFox/image_url.inc deleted file mode 100644 index 01b575095..000000000 --- a/baseunits/includes/MangaFox/image_url.inc +++ /dev/null @@ -1,30 +0,0 @@ - function GetMangaFoxImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(URL + '/' + IntToStr(workCounter + 1) + '.html'); - s := FillMangaSiteHost(MANGAFOX_ID, s); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('onclick="return enlarge()"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'src=')); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaFox/manga_information.inc b/baseunits/includes/MangaFox/manga_information.inc deleted file mode 100644 index 469c5aa4a..000000000 --- a/baseunits/includes/MangaFox/manga_information.inc +++ /dev/null @@ -1,117 +0,0 @@ -function GetMangaFoxInfoFromURL: Byte; -var - i, j: Integer; - s: String; - isAvailable: Boolean = True; -begin - mangaInfo.website := WebsiteRoots[MANGAFOX_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAFOX_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count = 0 then - Exit; - - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if GetVal(parse[i], 'property') = 'og:title' then - mangaInfo.title := CommonStringFilter(ReplaceRegExpr( - '^(.+)\s(Manga|Manhwa)$', GetVal(parse[i], 'content'), '$1', True)); - - //cover - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'cover') then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); - - //author - if Pos('/search/author/', parse[i]) > 0 then - mangaInfo.authors := Trim(parse[i + 1]); - - //artist - if Pos('/search/artist/', parse[i]) > 0 then - mangaInfo.artists := Trim(parse[i + 1]); - - //genres - if (GetTagName(parse[i]) = 'td') and (GetVal(parse[i], 'valign') = 'top') then - if Pos('/genres/', parse[i + 2]) > 0 then - begin - mangaInfo.genres := ''; - for j := i + 1 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/td' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.genres := mangaInfo.genres + parse[j]; - end; - end; - - //summary - if (GetTagName(parse[i]) = 'p') and (GetVal(parse[i], 'class') = 'summary') then - begin - mangaInfo.summary := ''; - for j := i + 1 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := mangaInfo.summary + #13#10 + CommonStringFilter(parse[j]); - end; - end; - - //status - if GetTagName(parse[i]) = 'h5' then - if UpperCase(Trim(parse[i + 1])) = 'STATUS:' then - begin - if Pos('ONGOING', UpperCase(parse[i + 5])) > 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - - //check if it's licensed - if GetVal(parse[i], 'class') = 'warning' then - if Pos('it is not available in', parse[i + 1]) > 0 then - begin - isAvailable := False; - mangaInfo.numChapter := 0; - mangaInfo.chapterName.Clear; - mangaInfo.chapterLinks.Clear; - end; - - //chapters - if isAvailable then - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'tips') then - begin - Inc(mangaInfo.numChapter); - s := Trim(parse[i + 1]) + ' ' + Trim(parse[i + 5]); - mangaInfo.chapterName.Add(CommonStringFilter(s)); - s := GetVal(parse[i], 'href'); - if RightStr(s, 6) = '1.html' then - SetLength(s, Length(s) - 6); - mangaInfo.chapterLinks.Add(s); - end; - end; - - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; -end; diff --git a/baseunits/includes/MangaFox/names_and_links.inc b/baseunits/includes/MangaFox/names_and_links.inc deleted file mode 100644 index c35a70393..000000000 --- a/baseunits/includes/MangaFox/names_and_links.inc +++ /dev/null @@ -1,36 +0,0 @@ - function MangaFoxGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - //if NOT GetPage(TObject(source), WebsiteRoots[MANGAFOX_ID,1] + MANGAFOX_BROWSER + IntToStr(StrToInt(URL)+1) + '.htm?az', 0) then - if not GetPage(TObject(Source), WebsiteRoots[MANGAFOX_ID, 1] + - MANGAFOX_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos(' 0) and - (Pos('class="series_preview manga_', parse[i]) > 0) then - begin - Result := NO_ERROR; - links.Add(StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MANGAFOX_ID, 1], '', [rfIgnoreCase])); - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - end; - end; - - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f4fda00e7..cc8fae59e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -274,91 +274,90 @@ interface MANGAREADER_ID = 10; MANGAPARK_ID = 11; EHENTAI_ID = 12; - MANGAFOX_ID = 13; - MANGATRADERS_ID = 14; - MANGASTREAM_ID = 15; - MANGAEDEN_ID = 16; - PERVEDEN_ID = 17; - TRUYENTRANHTUAN_ID = 18; - TURKCRAFT_ID = 19; - MANGAVADISI_ID = 20; - MANGAFRAME_ID = 21; - EATMANGA_ID = 22; - STARKANA_ID = 23; - MANGAPANDA_ID = 24; - REDHAWKSCANS_ID = 25; - BLOGTRUYEN_ID = 26; - KOMIKID_ID = 27; - SUBMANGA_ID = 28; - ESMANGAHERE_ID = 29; - ANIMEEXTREMIST_ID = 30; - PECINTAKOMIK_ID = 31; - HUGEMANGA_ID = 32; - S2SCAN_ID = 33; - SENMANGA_ID = 34; - IMANHUA_ID = 35; - MABUNS_ID = 36; - MANGAESTA_ID = 37; - CENTRALDEMANGAS_ID = 38; - EGSCANS_ID = 39; - MANGAAR_ID = 40; - MANGAAE_ID = 41; - ANIMESTORY_ID = 42; - LECTUREENLIGNE_ID = 43; - SCANMANGA_ID = 44; - MANGAGO_ID = 45; - DM5_ID = 46; - PURURIN_ID = 47; - MANGACOW_ID = 48; - KIVMANGA_ID = 49; - MANGACAN_ID = 50; - MEINMANGA_ID = 51; - MANGASPROJECT_ID = 52; - MANGAREADER_POR_ID = 53; - MANGA2U_ID = 54; - MANGASTREAMTO_ID = 55; - NINEMANGA_ID = 56; - NINEMANGA_ES_ID = 57; - NINEMANGA_CN_ID = 58; - NINEMANGA_RU_ID = 59; - NINEMANGA_DE_ID = 60; - NINEMANGA_IT_ID = 61; - NINEMANGA_BR_ID = 62; - JAPANSHIN_ID = 63; - JAPSCAN_ID = 64; - CENTRUMMANGI_PL_ID = 65; - MANGALIB_PL_ID = 66; - ONEMANGA_ID = 67; - MANGATOWN_ID = 68; - READHENTAIMANGA_ID = 69; - MANGAOKU_ID = 70; - MYREADINGMANGAINFO_ID = 71; - IKOMIK_ID = 72; - NHENTAI_ID = 73; - UNIONMANGAS_ID = 74; - MANGAMINT_ID = 75; - UNIXMANGA_ID = 76; - HAKIHOME_ID = 77; - EXTREMEMANGAS_ID = 78; - MANGAHOST_ID = 79; - PORNCOMIX_ID = 80; - PORNCOMIXRE_ID = 81; - PORNCOMIXIC_ID = 82; - XXCOMICS_ID = 83; - XXCOMICSMT_ID = 84; - XXCOMICS3D_ID = 85; - PORNXXXCOMICS_ID = 86; - MANGASEE_ID = 87; - MANGAKU_ID = 88; - ACADEMYVN_ID = 89; - MANGAAT_ID = 90; - SENMANGARAW_ID = 91; - READMANGATODAY_ID = 92; - LONEMANGA_ID = 93; - DYNASTYSCANS_ID = 94; - MADOKAMI_ID = 95; - - WebsiteRoots: array [0..95] of array [0..1] of string = ( + MANGATRADERS_ID = 13; + MANGASTREAM_ID = 14; + MANGAEDEN_ID = 15; + PERVEDEN_ID = 16; + TRUYENTRANHTUAN_ID = 17; + TURKCRAFT_ID = 18; + MANGAVADISI_ID = 19; + MANGAFRAME_ID = 20; + EATMANGA_ID = 21; + STARKANA_ID = 22; + MANGAPANDA_ID = 23; + REDHAWKSCANS_ID = 24; + BLOGTRUYEN_ID = 25; + KOMIKID_ID = 26; + SUBMANGA_ID = 27; + ESMANGAHERE_ID = 28; + ANIMEEXTREMIST_ID = 29; + PECINTAKOMIK_ID = 30; + HUGEMANGA_ID = 31; + S2SCAN_ID = 32; + SENMANGA_ID = 33; + IMANHUA_ID = 34; + MABUNS_ID = 35; + MANGAESTA_ID = 36; + CENTRALDEMANGAS_ID = 37; + EGSCANS_ID = 38; + MANGAAR_ID = 39; + MANGAAE_ID = 40; + ANIMESTORY_ID = 41; + LECTUREENLIGNE_ID = 42; + SCANMANGA_ID = 43; + MANGAGO_ID = 44; + DM5_ID = 45; + PURURIN_ID = 46; + MANGACOW_ID = 47; + KIVMANGA_ID = 48; + MANGACAN_ID = 49; + MEINMANGA_ID = 50; + MANGASPROJECT_ID = 51; + MANGAREADER_POR_ID = 52; + MANGA2U_ID = 53; + MANGASTREAMTO_ID = 54; + NINEMANGA_ID = 55; + NINEMANGA_ES_ID = 56; + NINEMANGA_CN_ID = 57; + NINEMANGA_RU_ID = 58; + NINEMANGA_DE_ID = 59; + NINEMANGA_IT_ID = 60; + NINEMANGA_BR_ID = 61; + JAPANSHIN_ID = 62; + JAPSCAN_ID = 63; + CENTRUMMANGI_PL_ID = 64; + MANGALIB_PL_ID = 65; + ONEMANGA_ID = 66; + MANGATOWN_ID = 67; + READHENTAIMANGA_ID = 68; + MANGAOKU_ID = 69; + MYREADINGMANGAINFO_ID = 70; + IKOMIK_ID = 71; + NHENTAI_ID = 72; + UNIONMANGAS_ID = 73; + MANGAMINT_ID = 74; + UNIXMANGA_ID = 75; + HAKIHOME_ID = 76; + EXTREMEMANGAS_ID = 77; + MANGAHOST_ID = 78; + PORNCOMIX_ID = 79; + PORNCOMIXRE_ID = 80; + PORNCOMIXIC_ID = 81; + XXCOMICS_ID = 82; + XXCOMICSMT_ID = 83; + XXCOMICS3D_ID = 84; + PORNXXXCOMICS_ID = 85; + MANGASEE_ID = 86; + MANGAKU_ID = 87; + ACADEMYVN_ID = 88; + MANGAAT_ID = 89; + SENMANGARAW_ID = 90; + READMANGATODAY_ID = 91; + LONEMANGA_ID = 92; + DYNASTYSCANS_ID = 93; + MADOKAMI_ID = 94; + + WebsiteRoots: array [0..94] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -372,7 +371,6 @@ interface ('MangaReader', 'http://www.mangareader.net'), ('MangaPark', 'http://mangapark.me'), ('E-Hentai', 'http://g.e-hentai.org'), - ('MangaFox', 'http://mangafox.me'), ('MangaTraders', 'http://mangatraders.org'), ('MangaStream', 'http://mangastream.com'), ('MangaEden', 'http://www.mangaeden.com'), @@ -486,9 +484,6 @@ interface MANGAREADER_BROWSER = '/alphabetical'; - //MANGAFOX_BROWSER :string = '/directory/'; - MANGAFOX_BROWSER = '/manga/'; - MANGATRADERS_BROWSER = '/directory/'; MANGASTREAM_ROOT = 'http://mangastream.com'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index e70b22bef..c9fb0e52a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1926,8 +1926,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/MangaPark/directory_page_number.inc} - {$I includes/MangaFox/directory_page_number.inc} - //{$I includes/MangaTraders/directory_page_number.inc} {$I includes/SenManga/directory_page_number.inc} @@ -2043,9 +2041,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[MANGAPARK_ID, 0] then Result := GetMangaParkDirectoryPageNumber else - //if website = WebsiteRoots[MANGAFOX_ID, 0] then - // Result := GetMangaFoxDirectoryPageNumber - //else //if website = WebsiteRoots[MANGATRADERS_ID, 0] then // Result := GetMangaTradersDirectoryPageNumber //else @@ -2211,8 +2206,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaPark/names_and_links.inc} - {$I includes/MangaFox/names_and_links.inc} - {$I includes/MangaTraders/names_and_links.inc} {$I includes/TruyenTranhTuan/names_and_links.inc} @@ -2388,9 +2381,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[MANGAPARK_ID, 0] then Result := MangaParkGetNamesAndLinks else - if website = WebsiteRoots[MANGAFOX_ID, 0] then - Result := MangaFoxGetNamesAndLinks - else if website = WebsiteRoots[MANGATRADERS_ID, 0] then Result := MangaTradersGetNamesAndLinks else @@ -2663,8 +2653,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaPark/manga_information.inc} - {$I includes/MangaFox/manga_information.inc} - {$I includes/MangaTraders/manga_information.inc} {$I includes/MangaStream/manga_information.inc} @@ -2851,9 +2839,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[MANGAPARK_ID, 0] then Result := GetMangaParkInfoFromURL else - if website = WebsiteRoots[MANGAFOX_ID, 0] then - Result := GetMangaFoxInfoFromURL - else if website = WebsiteRoots[MANGATRADERS_ID, 0] then Result := GetMangaTradersInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ff9f9a0dd..f6463d80f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -410,8 +410,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaEden/chapter_page_number.inc} - {$I includes/MangaFox/chapter_page_number.inc} - {$I includes/MangaFrame/chapter_page_number.inc} {$I includes/MangaGo/chapter_page_number.inc} @@ -529,9 +527,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnPageNumber else - if manager.container.MangaSiteID = MANGAFOX_ID then - Result := GetMangaFoxPageNumber - else if manager.container.MangaSiteID = MANGAREADER_ID then Result := GetMangaReaderPageNumber else @@ -776,8 +771,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaEsta/image_url.inc} - {$I includes/MangaFox/image_url.inc} - {$I includes/MangaFrame/image_url.inc} {$I includes/MangaGo/image_url.inc} @@ -905,9 +898,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; //if manager.container.MangaSiteID = MANGAPARK_ID then // Result := GetMangaParkImageURL //else - if manager.container.MangaSiteID = MANGAFOX_ID then - Result := GetMangaFoxImageURL - else if manager.container.MangaSiteID = STARKANA_ID then Result := GetStarkanaImageURL else diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index 66a625d3d..04324f585 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -97,11 +97,6 @@ procedure TImportFavorites.DMDHandle; regx.Expression := REGEX_HOST; for i:= 0 to urlList.Count-1 do begin - urlList.Strings[i]:= - StringReplace(urlList.Strings[i], 'http://mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); - urlList.Strings[i]:= - StringReplace(urlList.Strings[i], 'http://www.mangafox.com', WebsiteRoots[MANGAFOX_ID,1], []); - host := ''; webs := ''; host := LowerCase(regx.Replace(urlList[i], '$2', True)); From 878e21fd86ae0c4e8db22532b1efaa814c1e5858 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 05:45:32 +0800 Subject: [PATCH 0314/2794] rewrite mangafox as module fixes #81 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaFox.pas | 317 +++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaFox.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 1a1035470..c268b6dc9 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -2,4 +2,5 @@ uses FoOlSlide, mh160com, Batoto, - WPManga; + WPManga, + MangaFox; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas new file mode 100644 index 000000000..1f9863ad7 --- /dev/null +++ b/baseunits/modules/MangaFox.pas @@ -0,0 +1,317 @@ +unit MangaFox; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, RegExpr; + +implementation + +function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; + var Page: Integer; {%H-}Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := 1; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const {%H-}URL: String; Module: TModuleContainer): Integer; +var + Parse: TStringList; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'a') and + (Pos('series_preview manga_', Parse[i]) > 0) then + begin + Links.Add(GetVal(Parse[i], 'href')); + Names.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/manga/', 3) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Cardinal; Module: TModuleContainer): Integer; +var + Parse: TStringList; + info: TMangaInfo; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + s: String = ''; + begin + for i := StartIndex to Parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'tips') then + begin + Inc(info.numChapter); + s := Trim(parse[i + 1]) + ' ' + Trim(parse[i + 5]); + info.chapterName.Add(CommonStringFilter(s)); + s := GetVal(parse[i], 'href'); + if RightStr(s, 6) = '1.html' then + SetLength(s, Length(s) - 6); + info.chapterLinks.Add(s); + end; + end; + + //invert chapters + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); + end; + + procedure ScanParse; + var + i, j: Integer; + begin + info.authors := ''; + info.artists := ''; + info.genres := ''; + info.summary := ''; + info.status := ''; + for i := 0 to Parse.Count - 1 do + begin + //title + if info.title = '' then + if GetVal(parse[i], 'id') = 'title' then + info.title := CommonStringFilter(Parse[i + 3]); + + //cover + if info.coverLink = '' then + if (GetTagName(parse[i]) = 'div') and + (GetVal(parse[i], 'class') = 'cover') then + info.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); + + //author + if info.authors = '' then + if Pos('/search/author/', parse[i]) > 0 then + info.authors := Trim(parse[i + 1]); + + //artist + if info.artists = '' then + if Pos('/search/artist/', parse[i]) > 0 then + info.artists := Trim(parse[i + 1]); + + //genres + if info.genres = '' then + if (GetTagName(parse[i]) = 'td') and (GetVal(parse[i], 'valign') = 'top') then + if Pos('/genres/', parse[i + 2]) > 0 then + begin + + for j := i + 1 to parse.Count - 1 do + begin + if GetTagName(parse[j]) = '/td' then + Break + else + if Pos('<', parse[j]) = 0 then + info.genres := info.genres + parse[j]; + end; + end; + + //summary + if info.summary = '' then + if (GetTagName(parse[i]) = 'p') and (GetVal(parse[i], 'class') = 'summary') then + begin + for j := i + 1 to parse.Count - 1 do + begin + if GetTagName(parse[j]) = '/p' then + Break + else + if Pos('<', parse[j]) = 0 then + info.summary := info.summary + #13#10 + CommonStringFilter(parse[j]); + end; + end; + + //status + if info.status = '' then + if GetTagName(parse[i]) = 'h5' then + if UpperCase(Trim(parse[i + 1])) = 'STATUS:' then + begin + if Pos('ONGOING', UpperCase(parse[i + 5])) > 0 then + info.status := '1' // ongoing + else + info.status := '0'; // completed + end; + + //check if it's licensed + if GetVal(parse[i], 'class') = 'warning' then + if Pos('it is not available in', parse[i + 1]) > 0 then + begin + info.numChapter := 0; + info.chapterName.Clear; + info.chapterLinks.Clear; + info.summary := Trim(Parse[i + 1]); + Break; + end; + + //chapters + if GetVal(Parse[i], 'id') = 'chapters' then + begin + ScanChapters(i); + Break; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i, j: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'onchange') = 'change_page(this)') then + begin + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if (GetTagName(Parse[j]) = 'option') and + (GetVal(Parse[j], 'value') <> '0') then + Inc(Container.PageNumber); + end; + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + AppendURLDelim(FillHost(Module.RootURL, URL)) + '1.html', + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'id') = 'image') then + begin + if DownloadThread.workCounter < Container.PageLinks.Count then + Container.PageLinks[DownloadThread.workCounter] := GetVal(Parse[i], 'src'); + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + AppendURLDelim(FillHost(Module.RootURL, URL)) + + IncStr(DownloadThread.workCounter) + '.html', + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaFox'; + RootURL := 'http://mangafox.me'; + SortedList := False; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 3848990d64a71573cb2223792d0a1fce712a5b81 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 06:26:00 +0800 Subject: [PATCH 0315/2794] fix drop box range check error --- mangadownloader/forms/frmDropTarget.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 513f3ddc2..79bc423a3 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -43,8 +43,8 @@ TFormDropTarget = class(TForm, IDropTarget) FCanDrop: Boolean; // IDropTarget function MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; - function CursorEffect(const AllowedEffects: LongInt; - const KeyState: Integer): LongInt; + function CursorEffect(const AllowedEffects: Cardinal; + const KeyState: Integer): Cardinal; function CanDrop(const DataObj: IDataObject): Boolean; function GetTextFromObj(const DataObj: IDataObject; const Fmt: TClipFormat): String; @@ -201,8 +201,8 @@ function TFormDropTarget.MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; Result.tymed := TYMED_HGLOBAL; end; -function TFormDropTarget.CursorEffect(const AllowedEffects: LongInt; - const KeyState: Integer): LongInt; +function TFormDropTarget.CursorEffect(const AllowedEffects: Cardinal; + const KeyState: Integer): Cardinal; begin Result := DROPEFFECT_NONE; if FCanDrop then From e73b567629c6223050c3285db41faed387d529ec Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 07:08:14 +0800 Subject: [PATCH 0316/2794] Bump version 0.9.19.5 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 909bd1c39..ad08b384b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.5 (30-07-2015) +[*] MangaFox: rewrite all script +[*] Fix drop box range check error + 0.9.19.4 (28-07-2015) [+] Added changelog tab [+] Support multiple url on drop box diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9a7ba2ce1..29d02c4af 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 543e326c1..1d7fcc8c6 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.4 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.4/fmd_0.9.19.4.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.4/fmd_0.9.19.4_Win64.7z +VERSION=0.9.19.5 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.5/fmd_0.9.19.5.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.5/fmd_0.9.19.5_Win64.7z From b2e11fee16f6839a97f6aaf992c14da2925c160c Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 08:02:28 +0800 Subject: [PATCH 0317/2794] silentthread, fix empty title which result to empty folder name #80 --- baseunits/uSilentThread.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 41d1ad2f8..3b5e46b94 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -369,6 +369,8 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; try with MainForm do begin + if Trim(title) = '' then + title := Info.mangaInfo.title; if FSavePath = '' then begin if Trim(edSaveTo.Text) = '' then From 2110d7d7ac837e10355b7c04a3901e2283a2f197 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 09:11:30 +0800 Subject: [PATCH 0318/2794] droptarget, add clipboard format text/html and arrange its priority should fix dropping from chrome, #80 --- mangadownloader/forms/frmDropTarget.pas | 68 +++++++++++++++++-------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 79bc423a3..d96af1922 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -42,14 +42,14 @@ TFormDropTarget = class(TForm, IDropTarget) x0, y0: Integer; FCanDrop: Boolean; // IDropTarget - function MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; + function MakeFormatEtc(const Fmt: TCLIPFORMAT): TFormatEtc; function CursorEffect(const AllowedEffects: Cardinal; const KeyState: Integer): Cardinal; function CanDrop(const DataObj: IDataObject): Boolean; function GetTextFromObj(const DataObj: IDataObject; - const Fmt: TClipFormat): String; + const Fmt: TCLIPFORMAT): String; function GetWideTextFromObj(const DataObj: IDataObject; - const Fmt: TClipFormat): String; + const Fmt: TCLIPFORMAT): String; function GetURLsFromHTML(const S: String): String; function ParseDataObj(const DataObj: IDataObject; const Fmt: TClipboardFormat): String; @@ -81,7 +81,8 @@ implementation frmMain; var - CF_HTML: TClipFormat; + CF_HTML: TCLIPFORMAT; + CF_TEXTHTML: TCLIPFORMAT; {$R *.lfm} @@ -192,7 +193,7 @@ procedure TFormDropTarget.pmDropTargetPopup(Sender: TObject); miAddToFavorites.Checked := not miDownloadAll.Checked; end; -function TFormDropTarget.MakeFormatEtc(const Fmt: TClipFormat): TFormatEtc; +function TFormDropTarget.MakeFormatEtc(const Fmt: TCLIPFORMAT): TFormatEtc; begin Result.cfFormat := Fmt; Result.ptd := nil; @@ -225,7 +226,7 @@ function TFormDropTarget.CanDrop(const DataObj: IDataObject): Boolean; end; function TFormDropTarget.GetTextFromObj(const DataObj: IDataObject; - const Fmt: TClipFormat): String; + const Fmt: TCLIPFORMAT): String; var Medium: TStgMedium; PText: PChar; @@ -249,7 +250,7 @@ function TFormDropTarget.GetTextFromObj(const DataObj: IDataObject; end; function TFormDropTarget.GetWideTextFromObj(const DataObj: IDataObject; - const Fmt: TClipFormat): String; + const Fmt: TCLIPFORMAT): String; var Medium: TStgMedium; PwText: PWideChar; @@ -311,7 +312,7 @@ function TFormDropTarget.GetURLsFromHTML(const S: String): String; function TFormDropTarget.ParseDataObj(const DataObj: IDataObject; const Fmt: TClipboardFormat): String; begin - if Fmt = CF_HTML then + if (Fmt = CF_TEXTHTML) or (Fmt = CF_HTML) then Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) else if Fmt = CF_UNICODETEXT then @@ -350,23 +351,45 @@ function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; Enum: IEnumFORMATETC; FmtEtc: TFORMATETC; url: String; -begin - OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); - while Enum.Next(1, FmtEtc, nil) = S_OK do - if (FmtEtc.CfFormat = CF_HTML) or - (FmtEtc.CfFormat = CF_UNICODETEXT) or - (FmtEtc.CfFormat = CF_TEXT) then - begin - if Assigned(OnDropChekout) then + + Function GetDataObjectFormat(Fmt: TCLIPFORMAT): Boolean; + begin + Result := False; + Enum.Reset; + while Enum.Next(1, FmtEtc, nil) = S_OK do + if FmtEtc.CfFormat = Fmt then begin - url := ParseDataObj(dataObj, FmtEtc.CfFormat); + url := ParseDataObj(dataObj, Fmt); if url <> '' then - begin - OnDropChekout(url); - Break; - end; + Result := True; + Break; end; - end; + end; + + function GetDataObjectFormats(Fmts: array of TCLIPFORMAT): Boolean; + var + i: Integer; + begin + Result := False; + if Length(Fmts) = 0 then Exit; + for i := Low(Fmts) to High(Fmts) do + if GetDataObjectFormat(Fmts[i]) then + begin + Result := True; + Break; + end; + end; + +begin + OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); + if Assigned(OnDropChekout) then + if GetDataObjectFormats([ + CF_TEXTHTML, + CF_HTML, + CF_UNICODETEXT, + CF_TEXT + ]) then + OnDropChekout(url); Result := S_OK; end; @@ -379,5 +402,6 @@ procedure TFormDropTarget.CreateParams(var Params: TCreateParams); initialization CF_HTML := RegisterClipboardFormat('HTML Format'); + CF_TEXTHTML := RegisterClipboardFormat('text/html'); end. From 895a261ddc1620b3569cdc7008dcc1808bae65ba Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 09:49:42 +0800 Subject: [PATCH 0319/2794] droptarget, parse text/html as widestring firefox only give utf-16 while chrome give both ansi and utf-16 --- mangadownloader/forms/frmDropTarget.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index d96af1922..b4c069a48 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -312,7 +312,9 @@ function TFormDropTarget.GetURLsFromHTML(const S: String): String; function TFormDropTarget.ParseDataObj(const DataObj: IDataObject; const Fmt: TClipboardFormat): String; begin - if (Fmt = CF_TEXTHTML) or (Fmt = CF_HTML) then + if Fmt = CF_TEXTHTML then + Result := GetURLsFromHTML(GetWideTextFromObj(DataObj, Fmt)); + if Fmt = CF_HTML then Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) else if Fmt = CF_UNICODETEXT then @@ -352,7 +354,7 @@ function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; FmtEtc: TFORMATETC; url: String; - Function GetDataObjectFormat(Fmt: TCLIPFORMAT): Boolean; + function GetDataObjectFormat(Fmt: TCLIPFORMAT): Boolean; begin Result := False; Enum.Reset; From 09f2df7c3796154f91507dcb315d6bcdc5db2f6d Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 10:05:45 +0800 Subject: [PATCH 0320/2794] Bump version 0.9.19.6 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index ad08b384b..b2511a72b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.6 (30-07-2015) +[*] Fix no manga folder when adding favorites from drop box +[*] Fix drop box issue with chrome + 0.9.19.5 (30-07-2015) [*] MangaFox: rewrite all script [*] Fix drop box range check error diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 29d02c4af..f25c82b65 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 1d7fcc8c6..299e04676 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.5 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.5/fmd_0.9.19.5.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.5/fmd_0.9.19.5_Win64.7z +VERSION=0.9.19.6 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.6/fmd_0.9.19.6.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.6/fmd_0.9.19.6_Win64.7z From a3c1b6ec2fa75e44ee80dc4b5c9423404b5ce956 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 13:42:51 +0800 Subject: [PATCH 0321/2794] droptarget, minor changes --- mangadownloader/forms/frmDropTarget.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index b4c069a48..ed6ec7931 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -313,7 +313,8 @@ function TFormDropTarget.ParseDataObj(const DataObj: IDataObject; const Fmt: TClipboardFormat): String; begin if Fmt = CF_TEXTHTML then - Result := GetURLsFromHTML(GetWideTextFromObj(DataObj, Fmt)); + Result := GetURLsFromHTML(GetWideTextFromObj(DataObj, Fmt)) + else if Fmt = CF_HTML then Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) else @@ -383,6 +384,7 @@ function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; end; begin + url := ''; OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); if Assigned(OnDropChekout) then if GetDataObjectFormats([ From 8a5fca248fad19a032fd457342f74b8cc2015d49 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 15:01:39 +0800 Subject: [PATCH 0322/2794] droptarget, minor changes --- mangadownloader/forms/frmDropTarget.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index ed6ec7931..b13744d5f 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -218,7 +218,9 @@ function TFormDropTarget.CursorEffect(const AllowedEffects: Cardinal; function TFormDropTarget.CanDrop(const DataObj: IDataObject): Boolean; begin - Result := DataObj.QueryGetData(MakeFormatEtc(CF_HTML)) = S_OK; + Result := DataObj.QueryGetData(MakeFormatEtc(CF_TEXTHTML)) = S_OK; + if not Result then + Result := DataObj.QueryGetData(MakeFormatEtc(CF_HTML)) = S_OK; if not Result then Result := DataObj.QueryGetData(MakeFormatEtc(CF_UNICODETEXT)) = S_OK; if not Result then From 0ecae4216939a7023be184b49ec5280dfaab8c3a Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 16:56:04 +0800 Subject: [PATCH 0323/2794] droptarget, drop text/html format Firefox send utf16 while Chrome send utf8, and there is no way to identify which one is correct. It seems HTML Format always in utf8 or ansi, so we will use it. --- mangadownloader/forms/frmDropTarget.pas | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index b13744d5f..a044aeb1a 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -82,7 +82,6 @@ implementation var CF_HTML: TCLIPFORMAT; - CF_TEXTHTML: TCLIPFORMAT; {$R *.lfm} @@ -218,9 +217,7 @@ function TFormDropTarget.CursorEffect(const AllowedEffects: Cardinal; function TFormDropTarget.CanDrop(const DataObj: IDataObject): Boolean; begin - Result := DataObj.QueryGetData(MakeFormatEtc(CF_TEXTHTML)) = S_OK; - if not Result then - Result := DataObj.QueryGetData(MakeFormatEtc(CF_HTML)) = S_OK; + Result := DataObj.QueryGetData(MakeFormatEtc(CF_HTML)) = S_OK; if not Result then Result := DataObj.QueryGetData(MakeFormatEtc(CF_UNICODETEXT)) = S_OK; if not Result then @@ -314,9 +311,6 @@ function TFormDropTarget.GetURLsFromHTML(const S: String): String; function TFormDropTarget.ParseDataObj(const DataObj: IDataObject; const Fmt: TClipboardFormat): String; begin - if Fmt = CF_TEXTHTML then - Result := GetURLsFromHTML(GetWideTextFromObj(DataObj, Fmt)) - else if Fmt = CF_HTML then Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) else @@ -390,7 +384,6 @@ function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); if Assigned(OnDropChekout) then if GetDataObjectFormats([ - CF_TEXTHTML, CF_HTML, CF_UNICODETEXT, CF_TEXT @@ -408,6 +401,5 @@ procedure TFormDropTarget.CreateParams(var Params: TCreateParams); initialization CF_HTML := RegisterClipboardFormat('HTML Format'); - CF_TEXTHTML := RegisterClipboardFormat('text/html'); end. From 95784f2f8b4b14f1293304d3c0c29ac9de08f31f Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 30 Jul 2015 17:52:10 +0800 Subject: [PATCH 0324/2794] Bump version 0.9.19.7 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index b2511a72b..ec9017d66 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.19.7 (30-07-2015) +[*] Minor bug fixes + 0.9.19.6 (30-07-2015) [*] Fix no manga folder when adding favorites from drop box [*] Fix drop box issue with chrome diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f25c82b65..23bbaf330 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 299e04676..33bd5b158 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.6 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.6/fmd_0.9.19.6.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.6/fmd_0.9.19.6_Win64.7z +VERSION=0.9.19.7 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.7/fmd_0.9.19.7.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.7/fmd_0.9.19.7_Win64.7z From 46a35e639848586c877031cb6092a50b521ec9fc Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 31 Jul 2015 22:33:25 +0800 Subject: [PATCH 0325/2794] udata, udownloadmanager: use thttpsendthread --- baseunits/uData.pas | 2 +- baseunits/uDownloadsManager.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c9fb0e52a..6c0cf4fb7 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -177,7 +177,7 @@ TMangaInformation = class(TObject) parse: TStringList; isGenerateFolderChapterName: Boolean; isRemoveUnicode: Boolean; - FHTTP: THTTPSend; + FHTTP: THTTPSendThread; ModuleId: Integer; procedure OnTag(NoCaseTag, ActualTag: String); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index f6463d80f..70eb04cbc 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -36,7 +36,7 @@ TDownloadThread = class(TFMDThread) workCounter: Integer; FSortColumn: Cardinal; FMessage, FAnotherURL: String; - FHTTP: THTTPSend; + FHTTP: THTTPSendThread; procedure MainThreadMessageDialog; // Helper method allows to merge 2 images into 1 image. From d25ca2791691cb0bd63c73da19407b8f10992203 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 31 Jul 2015 23:53:01 +0800 Subject: [PATCH 0326/2794] save max connection retry to global variable --- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.pas | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cc8fae59e..6dfb2134e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -673,7 +673,7 @@ interface OptionCheckMinutes: Cardinal = 0; OptionPDFQuality: Cardinal = 95; - OptionMaxRetry: Cardinal = 0; + OptionMaxRetry: Integer = 0; OptionConnectionTimeout: Integer = 15000; OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a1d26ff6b..009ff19fc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4303,6 +4303,7 @@ procedure TMainForm.btOptionApplyClick(Sender: TObject); OptionProxyUser := ''; end; + OptionMaxRetry := seOptionMaxRetry.Value; DLManager.maxDLTasks := seOptionMaxParallel.Value; DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; DLManager.retryConnect := seOptionMaxRetry.Value; @@ -4730,6 +4731,7 @@ procedure TMainForm.LoadOptions; seOptionMaxParallel.Value := options.ReadInteger('connections', 'NumberOfTasks', 1); seOptionMaxThread.Value := options.ReadInteger('connections', 'NumberOfThreadsPerTask', 1); seOptionMaxRetry.Value := options.ReadInteger('connections', 'Retry', 3);; + OptionMaxRetry := seOptionMaxRetry.Value; DLManager.maxDLTasks := seOptionMaxParallel.Value; DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; DLManager.retryConnect := seOptionMaxRetry.Value; From c4cdad15b6d0bd4f06043445dcc03cce85406235 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 03:28:18 +0800 Subject: [PATCH 0327/2794] mainform, optimize and clean up codes --- mangadownloader/forms/frmMain.lfm | 4 +- mangadownloader/forms/frmMain.pas | 1031 ++++++++++-------------- mangadownloader/languages/fmd.en.po | 18 +- mangadownloader/languages/fmd.id_ID.po | 18 +- mangadownloader/languages/fmd.po | 18 +- 5 files changed, 476 insertions(+), 613 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0cfc04c1d..3946608e9 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2868,7 +2868,7 @@ object MainForm: TMainForm ClientHeight = 329 ClientWidth = 552 TabOrder = 0 - object cbOptionShowAllLang: TCheckBox + object cbOptionBatotoShowAllLang: TCheckBox Left = 16 Height = 19 Top = 40 @@ -2877,7 +2877,7 @@ object MainForm: TMainForm ParentFont = False TabOrder = 1 end - object cbOptionShowBatotoSG: TCheckBox + object cbOptionBatotoShowScanGroup: TCheckBox Left = 16 Height = 19 Top = 16 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 009ff19fc..36b2dc149 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -19,7 +19,7 @@ interface Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, - FileUtil, TAGraph, TASources, TASeries, TATools, AnimatedGif, + FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, USimpleException, USimpleLogger; @@ -128,8 +128,8 @@ TMainForm = class(TForm) btRemoveFilterLarge: TBitBtn; cbOptionAutoCheckUpdate: TCheckBox; cbOptionShowDeleteTaskDialog: TCheckBox; - cbOptionShowBatotoSG: TCheckBox; - cbOptionShowAllLang: TCheckBox; + cbOptionBatotoShowScanGroup: TCheckBox; + cbOptionBatotoShowAllLang: TCheckBox; cbOptionUseProxy: TCheckBox; cbSelectManga: TComboBox; ckFilterAction: TCheckBox; @@ -577,7 +577,7 @@ TMainForm = class(TForm) procedure tvDownloadFilterRepaint; // generate >> nodes - procedure GenerateNodes; + procedure GeneratetvDownloadFilterNodes; // load about information procedure LoadAbout; @@ -613,6 +613,8 @@ TMainForm = class(TForm) // Load config from config.ini procedure LoadOptions; + procedure SaveOptions; + procedure ApplyOptions; // Load config from mangalist.ini procedure LoadMangaOptions; @@ -628,8 +630,9 @@ TMainForm = class(TForm) procedure SaveFormInformation; procedure SaveDropTargetFormInformation; - // load language file - procedure LoadLanguage; + // load language from file + procedure CollectLanguagesFromFiles; + procedure ApplyLanguage; // openwith procedure OpenWithExternalProgram(const dirPath, Filename: String); @@ -924,8 +927,6 @@ destructor TOpenDBThread.Destroy; { TMainForm } procedure TMainForm.FormCreate(Sender: TObject); -var - fs: TFileStream; begin Randomize; fmdDirectory := CleanAndExpandDirectory(GetCurrentDirUTF8); @@ -951,31 +952,25 @@ procedure TMainForm.FormCreate(Sender: TObject); TrayIcon.Icon.Assign(Application.Icon); PrevWindowState := wsNormal; - // Load readme.rtf to rmAbout - rmAbout.Clear; - if FileExistsUTF8(README_FILE) then - begin - fs := TFileStream.Create(README_FILE, fmOpenRead or fmShareDenyNone); - try - rmAbout.LoadRichText(fs); - finally - fs.free; - end; - end; - - //load changelog - if FileExistsUTF8(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE) then - mmChangelog.Lines.LoadFromFile(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE); - + //main dataprocess dataProcess := TDBDataProcess.Create; + + // downloadmanager DLManager := TDownloadManager.Create; DLManager.Restore; + // favorites FavoriteManager := TFavoriteManager.Create; FavoriteManager.OnUpdateFavorite := @UpdateVtFavorites; FavoriteManager.OnUpdateDownload := @UpdateVtDownload; FavoriteManager.DLManager := DLManager; + // subthread + SubThread := TSubThread.Create; + + // ShowInformation + mangaInfo := TMangaInfo.Create; + // Load config.ini options := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_FILE); options.CacheUpdates := True; @@ -993,16 +988,18 @@ procedure TMainForm.FormCreate(Sender: TObject); mangalistIni := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + MANGALIST_FILE); mangalistIni.CacheUpdates := True; - LoadOptions; + // generate tvDownloadFilter nodes + GeneratetvDownloadFilterNodes; + isStartup := False; + CollectLanguagesFromFiles; + LoadOptions; + ApplyOptions; LoadMangaOptions; LoadFormInformation; if cbFilterStatus.Items.Count > 2 then cbFilterStatus.ItemIndex := 2; - // ShowInformation; - mangaInfo := TMangaInfo.Create; - vtDownload.NodeDataSize := SizeOf(TDownloadInfo) - 4; vtDownload.RootNodeCount := DLManager.Count; @@ -1020,13 +1017,6 @@ procedure TMainForm.FormCreate(Sender: TObject); Revision := revisionIni.ReadInteger('general', 'Revision', 0); revisionIni.Free; - seOptionNewMangaTime.Value := options.ReadInteger('general', 'NewMangaTime', 3); - miHighLightNewManga.Checked := options.ReadBool('general', 'HighlightNewManga', True); - miChapterListHighlight.Checked := - options.ReadBool('general', 'HighlightDownloadedChapters', True); - cbOptionShowQuitDialog.Checked := options.ReadBool('dialogs', 'ShowQuitDialog', True); - cbOptionShowDeleteTaskDialog.Checked := - options.ReadBool('dialogs', 'ShowDeleteDldTaskDialog', True); currentJDN := GetCurrentJDN; // read online @@ -1034,11 +1024,6 @@ procedure TMainForm.FormCreate(Sender: TObject); btReadOnline.Enabled := False; btAddToFavorites.Enabled := False; - // subthread - SubThread := TSubThread.Create; - - cbOptionLetFMDDo.ItemIndex := options.ReadInteger('general', 'LetFMDDo', 0); - // waiting gif if FileExists(IMAGE_FOLDER + 'waiting.gif') then begin @@ -1053,10 +1038,6 @@ procedure TMainForm.FormCreate(Sender: TObject); mangaCover := TPicture.Create; - // generate nodes - GenerateNodes; - tvDownloadFilterRepaint; - // refresh sort if DLManager.Count > 1 then begin @@ -1069,7 +1050,6 @@ procedure TMainForm.FormCreate(Sender: TObject); FavoriteManager.Sort(vtFavorites.Header.SortColumn); vtFavorites.Repaint; end; - LoadLanguage; //textstyle for updatestatusbar with UpdateStatusTextStyle do @@ -1159,8 +1139,8 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); DLManager.BackupDownloadedChaptersList; isExiting := True; FavoriteManager.Backup; + SaveOptions; SaveFormInformation; - options.UpdateFile; SetLength(optionMangaSiteSelectionNodes, 0); end; @@ -1657,16 +1637,21 @@ procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); procedure TMainForm.LoadAbout; var - fs: TFileStream; + fs: TFileStreamUTF8; begin - try - rmAbout.Clear; - fs := TFileStream.Create(README_FILE, fmOpenRead or fmShareDenyNone); - rmAbout.LoadRichText(fs); - fs.Free; - except - on E: Exception do ; + // load readme.rtf + if FileExistsUTF8(CleanAndExpandDirectory(GetCurrentDirUTF8) + README_FILE) then + begin + fs := TFileStreamUTF8.Create(README_FILE, fmOpenRead or fmShareDenyNone); + try + rmAbout.LoadRichText(fs); + finally + fs.free; + end; end; + // load changelog.txt + if FileExistsUTF8(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE) then + mmChangelog.Lines.LoadFromFile(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE); end; procedure TMainForm.tvDownloadFilterRepaint; @@ -1708,7 +1693,7 @@ procedure TMainForm.tvDownloadFilterRepaint; tvDownloadFilter.Items[9].Text := RS_OneMonth; end; -procedure TMainForm.GenerateNodes; +procedure TMainForm.GeneratetvDownloadFilterNodes; begin with tvDownloadFilter do begin Items.Clear; @@ -2250,7 +2235,7 @@ procedure TMainForm.edWebsitesSearchChange(Sender: TObject); var s: String; lcount: Integer; - data: PMangaListItem; + data: PSingleItem; xNode, lNode: PVirtualNode; begin if Length(optionMangaSiteSelectionNodes) < 1 then Exit; @@ -2337,13 +2322,6 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); Screen.Cursor := crHourGlass; try dataProcess.RemoveFilter; - if dataProcess.FilterAllSites then - begin - dataProcess.FilterAllSites := False; - dataProcess.Free; - dataProcess := TDBDataProcess.Create; - dataProcess.Open(cbSelectManga.Items[cbSelectManga.ItemIndex]); - end; vtMangaList.RootNodeCount := dataProcess.RecordCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); edSearch.Tag := -1; @@ -2414,11 +2392,9 @@ procedure TMainForm.btFilterClick(Sender: TObject); rbAll.Checked, cbOnlyNew.Checked) then begin + dataProcess.FilterAllSites := cbSearchFromAllSites.Checked; if cbSearchFromAllSites.Checked then - begin dataProcess.SitesList.Assign(cbSelectManga.Items); - dataProcess.FilterAllSites := True; - end; edSearch.Tag := -1; edSearch.Clear; @@ -3076,114 +3052,13 @@ procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); end; procedure TMainForm.pcMainChange(Sender: TObject); - - procedure UpdateOptions; - var - l: TStringList; - s: String; - i, j: Cardinal; - Data: PMangaListItem; - begin - l := TStringList.Create; - - cbOptionMinimizeToTray.Checked := - options.ReadBool('general', 'MinimizeToTray', False); - seOptionNewMangaTime.Value := options.ReadInteger('general', 'NewMangaTime', 3); - cbOptionLetFMDDo.ItemIndex := options.ReadInteger('general', 'LetFMDDo', 0); - cbOptionEnableLoadCover.Checked := - options.ReadBool('general', 'LoadMangaCover', True); - OptionLetFMDDo := TFMDDo(cbOptionLetFMDDo.ItemIndex); - edOptionExternalPath.FileName := options.ReadString('general', 'ExternalProgramPath', ''); - edOptionExternalParams.Text := options.ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); - - cbOptionShowDownloadToolbar.Checked := options.ReadBool('view', 'ShowDownloadsToolbar', True); - - seOptionMaxParallel.Value := options.ReadInteger('connections', 'NumberOfTasks', 1); - seOptionMaxThread.Value := - options.ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - seOptionMaxRetry.Value := options.ReadInteger('connections', 'Retry', 3); - seOptionConnectionTimeout.Value := options.ReadInteger('connections', 'ConnectionTimeout', 15); - cbOptionUseProxy.Checked := options.ReadBool('connections', 'UseProxy', False); - cbOptionProxyType.Text := options.ReadString('connections', 'ProxyType', 'HTTP'); - edOptionHost.Text := options.ReadString('connections', 'Host', ''); - edOptionPass.Text := options.ReadString('connections', 'Pass', ''); - edOptionPort.Text := options.ReadString('connections', 'Port', ''); - edOptionUser.Text := options.ReadString('connections', 'User', ''); - edOptionDefaultPath.Text := options.ReadString('saveto', 'SaveTo', DEFAULT_PATH); - if Trim(edOptionDefaultPath.Text) = '' then - edOptionDefaultPath.Text := DEFAULT_PATH; - edOptionDefaultPath.Text := CorrectPathSys(edOptionDefaultPath.Text); - rgOptionCompress.ItemIndex := options.ReadInteger('saveto', 'Compress', 0); - - edOptionCustomRename.Text := - options.ReadString('saveto', 'CustomRename', DEFAULT_CUSTOM_RENAME); - if Trim(edOptionCustomRename.Text) = '' then - edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; - - cbOptionShowQuitDialog.Checked := - options.ReadBool('dialogs', 'ShowQuitDialog', True); - cbOptionShowDeleteTaskDialog.Checked := - options.ReadBool('dialogs', 'ShowDeleteDldTaskDialog', True); - - cbOptionPathConvert.Checked := options.ReadBool('saveto', 'PathConv', False); - cbOptionGenerateChapterName.Checked := - options.ReadBool('saveto', 'GenChapName', False); - cbOptionGenerateMangaFolderName.Checked := - options.ReadBool('saveto', 'GenMangaName', True); - cbOptionAutoNumberChapter.Checked := - options.ReadBool('saveto', 'AutoNumberChapter', True); - OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; - seOptionPDFQuality.Value := options.ReadInteger('saveto', 'PDFQuality', 95); - - cbOptionAutoRemoveCompletedManga.Checked := - options.ReadBool('update', 'AutoRemoveCompletedManga', True); - cbOptionAutoCheckFavStartup.Checked := - options.ReadBool('update', 'AutoCheckFavStartup', False); - seOptionCheckMinutes.Value := options.ReadInteger('update', 'AutoCheckMinutes', 0); - lbOptionAutoCheckMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, - [seOptionCheckMinutes.Value]); - - cbOptionShowBatotoSG.Checked := OptionShowBatotoSG; - cbOptionShowAllLang.Checked := OptionShowAllLang; - cbOptionAutoDlFav.Checked := OptionAutoDlFav; - - if Length(optionMangaSiteSelectionNodes) > 0 then - for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do - optionMangaSiteSelectionNodes[i]^.CheckState := csUncheckedNormal; - - s := options.ReadString('general', 'MangaListSelect', - mangalistIni.ReadString('general', 'DefaultSelect', DEFAULT_LIST)); - if Pos(SEPERATOR, S) > 0 then - GetParams(l, s) //for old config - else - ExtractStrings([','], [], PChar(s), l); - - if l.Count > 0 then - for i := 0 to l.Count - 1 do - begin - if Length(optionMangaSiteSelectionNodes) > 0 then - for j := 0 to Length(optionMangaSiteSelectionNodes) - 1 do - begin - Data := vtOptionMangaSiteSelection.GetNodeData( - optionMangaSiteSelectionNodes[j]); - if Data^.Text = l.Strings[i] then - begin - optionMangaSiteSelectionNodes[j]^.CheckState := csCheckedNormal; - Break; - end; - end; - end; - - l.Free; - end; - begin if pcMain.ActivePage = tsAbout then LoadAbout else if pcMain.ActivePage = tsFavorites then vtFavorites.Repaint; - UpdateOptions; + LoadOptions; end; procedure TMainForm.pmDownloadPopup(Sender: TObject); @@ -3866,8 +3741,6 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); vtDownload.Header.SortColumn := Column; DLManager.Sort(Column); - options.WriteInteger('misc', 'SortDownloadColumn', vtDownload.Header.SortColumn); - options.WriteBool('misc', 'SortDownloadDirection', DLManager.SortDirection); vtDownload.Repaint; end; @@ -4037,8 +3910,6 @@ procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; vtFavorites.Header.SortColumn := Column; vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); FavoriteManager.Sort(Column); - options.WriteInteger('misc', 'SortFavoritesColumn', vtFavorites.Header.SortColumn); - options.WriteBool('misc', 'SortFavoritesDirection', FavoriteManager.sortDirection); finally UpdateVtFavorites; FavoriteManager.isRunning := False; @@ -4098,221 +3969,9 @@ procedure TMainForm.vtMangaListDragOver(Sender : TBaseVirtualTree; // options procedure TMainForm.btOptionApplyClick(Sender: TObject); -var - i: Cardinal; - s: String; - isStillHaveCurrentWebsite: Boolean = False; - Data: PMangaListItem; begin - try - s := SaveMangaOptions; - if s = '' then - begin - MessageDlg('', RS_DlgMangaListSelect, - mtConfirmation, [mbYes], 0); - Exit; - end; - - // general - options.WriteString('general', 'MangaListSelect', s); - mangalistIni.UpdateFile; - - cbSelectManga.Clear; - for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do - begin - Data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); - if (optionMangaSiteSelectionNodes[i]^.CheckState = csCheckedNormal) and - (Data^.Text <> '') then - begin - cbSelectManga.Items.Add(Data^.Text); - end; - end; - - for i := 0 to cbSelectManga.Items.Count - 1 do - begin - if cbSelectManga.Items[i] = currentWebsite then - begin - cbSelectManga.ItemIndex := i; - isStillHaveCurrentWebsite := True; - Break; - end; - end; - - if not isStillHaveCurrentWebsite then - begin - if cbSelectManga.Items.Count > 0 then - begin - cbSelectManga.ItemIndex := 0; - cbSelectMangaChange(Sender); - end - else - begin - cbSelectManga.ItemIndex := -1; - cbSelectManga.Text := ''; - currentWebsite := ''; - FreeAndNil(dataProcess); - vtMangaList.Clear; - lbMode.Caption := Format(RS_ModeAll, [0]); - end; - end; - options.WriteBool('general', 'LiveSearch', cbOptionLiveSearch.Checked); - options.WriteBool('general', 'OneInstanceOnly', cbOptionOneInstanceOnly.Checked); - //FMDInstace - if cbOptionOneInstanceOnly.Checked then - begin - if FMDInstance = nil then - begin - FMDInstance := TSimpleIPCServer.Create(Self); - FMDInstance.ServerID := FMD_INSTANCE; - FMDInstance.Global := True; - FMDInstance.OnMessage := @FMDInstanceReceiveMsg; - FMDInstance.StartServer; - end; - end - else - begin - if FMDInstance <> nil then - begin - FMDInstance.StopServer; - FreeAndNil(FMDInstance); - end; - end; - - if cbLanguages.ItemIndex > -1 then - options.WriteString('languages', 'Selected', - AvailableLanguages.Names[cbLanguages.ItemIndex]); - options.WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); - options.WriteInteger('general', 'NewMangaTime', seOptionNewMangaTime.Value); - options.WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); - OptionLetFMDDo := TFMDDo(cbOptionLetFMDDo.ItemIndex); - options.WriteBool('general', 'LoadMangaCover', cbOptionEnableLoadCover.Checked); - OptionEnableLoadCover := cbOptionEnableLoadCover.Checked; - options.WriteString('general', 'ExternalProgramPath', edOptionExternalPath.FileName); - options.WriteString('general', 'ExternalProgramParams', edOptionExternalParams.Text); - - // view - options.WriteBool('droptarget', 'Show', ckDropTarget.Checked); - options.WriteInteger('droptarget', 'Mode', rgDropTargetMode.ItemIndex); - options.WriteInteger('droptarget', 'Opacity', tbDropTargetOpacity.Position); - options.WriteInteger('droptarget', 'Width', frmDropTarget.FWidth); - options.WriteInteger('droptarget', 'Heigth', frmDropTarget.FHeight); - options.WriteInteger('droptarget', 'Top', frmDropTarget.FTop); - options.WriteInteger('droptarget', 'Left', frmDropTarget.FLeft); - options.WriteBool('view', 'ShowDownloadsToolbar', cbOptionShowDownloadToolbar.Checked); - ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; - - // connections - options.WriteInteger('connections', 'NumberOfTasks', seOptionMaxParallel.Value); - options.WriteInteger('connections', 'NumberOfThreadsPerTask', - seOptionMaxThread.Value); - options.WriteInteger('connections', 'Retry', seOptionMaxRetry.Value); - DLManager.retryConnect := seOptionMaxRetry.Value; - options.WriteInteger('connections', 'ConnectionTimeout', seOptionConnectionTimeout.Value); - OptionConnectionTimeout := seOptionConnectionTimeout.Value*1000; - options.WriteBool('connections', 'UseProxy', cbOptionUseProxy.Checked); - options.WriteString('connections', 'ProxyType', cbOptionProxyType.Text); - options.WriteString('connections', 'Host', edOptionHost.Text); - options.WriteString('connections', 'Pass', edOptionPass.Text); - options.WriteString('connections', 'Port', edOptionPort.Text); - options.WriteString('connections', 'User', edOptionUser.Text); - - // saveto - if Trim(edOptionDefaultPath.Text) = '' then - edOptionDefaultPath.Text := DEFAULT_PATH; - edOptionDefaultPath.Text := CorrectPathSys(edOptionDefaultPath.Text); - options.WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); - options.WriteBool('saveto', 'PathConv', cbOptionPathConvert.Checked); - options.WriteBool('saveto', 'GenChapName', cbOptionGenerateChapterName.Checked); - options.WriteBool('saveto', 'GenMangaName', cbOptionGenerateMangaFolderName.Checked); - options.WriteInteger('saveto', 'Compress', rgOptionCompress.ItemIndex); - options.WriteBool('saveto', 'AutoNumberChapter', cbOptionAutoNumberChapter.Checked); - OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; - options.WriteInteger('saveto', 'PDFQuality', seOptionPDFQuality.Value); - OptionPDFQuality := seOptionPDFQuality.Value; - if Trim(edOptionCustomRename.Text) = '' then - edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; - options.WriteString('saveto', 'CustomRename', edOptionCustomRename.Text); - OptionCustomRename := edOptionCustomRename.Text; - options.WriteBool('saveto', 'ConvertDigitVolume', cbOptionDigitVolume.Checked); - options.WriteBool('saveto', 'ConvertDigitChapter', cbOptionDigitChapter.Checked); - options.WriteInteger('saveto', 'DigitVolumeLength', seOptionDigitVolume.Value); - options.WriteInteger('saveto', 'DigitChapterLength', seOptionDigitChapter.Value); - - // update - options.WriteBool('update', 'AutoRemoveCompletedManga', - cbOptionAutoRemoveCompletedManga.Checked); - OptionAutoRemoveCompletedManga := cbOptionAutoRemoveCompletedManga.Checked; - options.WriteBool('update', 'AutoCheckUpdate', - cbOptionAutoCheckUpdate.Checked); - options.WriteBool('update', 'AutoCheckFavStartup', - cbOptionAutoCheckFavStartup.Checked); - OptionAutoCheckFavStartup := cbOptionAutoCheckFavStartup.Checked; - options.WriteInteger('update', 'AutoCheckMinutes', seOptionCheckMinutes.Value); - OptionCheckMinutes := seOptionCheckMinutes.Value; - lbOptionAutoCheckMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, - [seOptionCheckMinutes.Value]); - options.WriteBool('update', 'UpdateListNoMangaInfo', - cbOptionUpdateListNoMangaInfo.Checked); - OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; - options.WriteBool('update', 'UpdateListRemoveDuplicateLocalData', - cbOptionUpdateListRemoveDuplicateLocalData.Checked); - OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; - - DLManager.compress := rgOptionCompress.ItemIndex; - - // dialogs - options.WriteBool('dialogs', 'ShowQuitDialog', cbOptionShowQuitDialog.Checked); - options.WriteBool('dialogs', 'ShowDeleteDldTaskDialog', - cbOptionShowDeleteTaskDialog.Checked); - - // misc - options.WriteBool('misc', 'ShowBatotoSG', cbOptionShowBatotoSG.Checked); - options.WriteBool('misc', 'ShowAllLang', cbOptionShowAllLang.Checked); - options.WriteBool('misc', 'AutoDlFav', cbOptionAutoDlFav.Checked); - OptionShowBatotoSG := cbOptionShowBatotoSG.Checked; - OptionShowAllLang := cbOptionShowAllLang.Checked; - OptionAutoDlFav := cbOptionAutoDlFav.Checked; - options.WriteBool('misc', 'MangafoxRemoveWatermarks', - cbOptionMangaFoxRemoveWatermarks.Checked); - - - options.UpdateFile; - - if OptionCheckMinutes = 0 then - itCheckForChapters.Enabled := False - else - begin - itCheckForChapters.Interval := OptionCheckMinutes * 60000; - itCheckForChapters.Enabled := True; - end; - - if cbOptionUseProxy.Checked then - begin - OptionProxyType := cbOptionProxyType.Text; - OptionProxyHost := edOptionHost.Text; - OptionProxyPass := edOptionPass.Text; - OptionProxyPort := edOptionPort.Text; - OptionProxyUser := edOptionUser.Text; - end - else - begin - OptionProxyType := ''; - OptionProxyHost := ''; - OptionProxyPass := ''; - OptionProxyPort := ''; - OptionProxyUser := ''; - end; - - OptionMaxRetry := seOptionMaxRetry.Value; - DLManager.maxDLTasks := seOptionMaxParallel.Value; - DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; - DLManager.retryConnect := seOptionMaxRetry.Value; - - LoadLanguage; - finally - //Recheck download thread - DLManager.CheckAndActiveTask; - end; + SaveOptions; + ApplyOptions; end; procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); @@ -4325,8 +3984,6 @@ procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); -var - data: PMangaListItem; begin if (isExiting) or (dataProcess.RecordCount = 0) then Exit; @@ -4674,160 +4331,326 @@ procedure TMainForm.RunGetList; procedure TMainForm.LoadOptions; var - i: Integer; + l: TStringList; + i, j: Integer; + s: String; + data: PSingleItem; +begin + with options do begin + // general + cbOptionOneInstanceOnly.Checked := ReadBool('general', 'OneInstanceOnly', True); + cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); + cbOptionMinimizeToTray.Checked := ReadBool('general', 'MinimizeToTray', False); + cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); + cbOptionAutoNumberChapter.Checked := ReadBool('general', 'AutoNumberChapter', True); + edOptionExternalPath.FileName := ReadString('general', 'ExternalProgramPath', ''); + edOptionExternalParams.Text := ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); + cbAddAsStopped.Checked := ReadBool('general', 'AddAsStopped', False); + miHighLightNewManga.Checked := ReadBool('general', 'HighlightNewManga', True); + miChapterListHighlight.Checked := ReadBool('general', 'HighlightDownloadedChapters', True); + + // view + cbOptionShowDownloadToolbar.Checked := ReadBool('view', 'ShowDownloadsToolbar', True); + cbOptionEnableLoadCover.Checked := ReadBool('view', 'LoadMangaCover', True); + ckDropTarget.Checked := ReadBool('droptarget', 'Show', False); + frmDropTarget.FWidth := ReadInteger('droptarget', 'Width', frmDropTarget.FWidth); + frmDropTarget.FHeight := ReadInteger('droptarget', 'Heigth', frmDropTarget.FHeight); + frmDropTarget.FTop := ReadInteger('droptarget', 'Top', frmDropTarget.FTop); + frmDropTarget.FLeft := ReadInteger('droptarget', 'Left', frmDropTarget.FLeft); + rgDropTargetMode.ItemIndex := ReadInteger('droptarget', 'Mode', 0); + tbDropTargetOpacity.Position := ReadInteger('droptarget', 'Opacity', 255); + + // connection + seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', 1); + seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', 1); + seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', 3);; + seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', 15); + cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); + cbOptionProxyType.Text := ReadString('connections', 'ProxyType', 'HTTP'); + edOptionHost.Text := ReadString('connections', 'Host', ''); + edOptionPass.Text := ReadString('connections', 'Pass', ''); + edOptionPort.Text := ReadString('connections', 'Port', ''); + edOptionUser.Text := ReadString('connections', 'User', ''); + + // saveto + edOptionDefaultPath.Text := ReadString('saveto', 'SaveTo', DEFAULT_PATH); + if Trim(edOptionDefaultPath.Text) = '' then + edOptionDefaultPath.Text := DEFAULT_PATH; + rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); + cbOptionPathConvert.Checked := ReadBool('saveto', 'PathConvert', False); + cbOptionGenerateChapterName.Checked := ReadBool('saveto', 'GenerateChapterName', False); + cbOptionGenerateMangaFolderName.Checked := ReadBool('saveto', 'GenerateMangaName', True); + cbOptionAutoNumberChapter.Checked := ReadBool('saveto', 'AutoNumberChapter', True); + seOptionPDFQuality.Value := ReadInteger('saveto', 'PDFQuality', 100); + edOptionCustomRename.Text := ReadString('saveto', 'CustomRename', DEFAULT_CUSTOM_RENAME); + if Trim(edOptionCustomRename.Text) = '' then + edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; + cbOptionDigitVolume.Checked := ReadBool('saveto', 'ConvertDigitVolume', True); + seOptionDigitVolume.Value := ReadInteger('saveto', 'DigitVolumeLength', 2); + seOptionDigitVolume.Enabled := cbOptionDigitVolume.Checked; + cbOptionDigitChapter.Checked := ReadBool('saveto', 'ConvertDigitChapter', True); + seOptionDigitChapter.Value := ReadInteger('saveto', 'DigitChapterLength', 3); + seOptionDigitChapter.Enabled := cbOptionDigitChapter.Checked; + + // update + cbOptionAutoCheckUpdate.Checked := ReadBool('update', 'AutoCheckUpdate', True); + cbOptionAutoCheckFavStartup.Checked := ReadBool('update', 'AutoCheckFavStartup', True); + seOptionCheckMinutes.Value := ReadInteger('update', 'AutoCheckMinutes', 60); + lbOptionAutoCheckMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionCheckMinutes.Value]); + cbOptionAutoDlFav.Checked := ReadBool('update', 'AutoDownloadFavorites', False); + cbOptionAutoRemoveCompletedManga.Checked := ReadBool('update', 'AutoRemoveCompletedManga', False); + cbOptionUpdateListNoMangaInfo.Checked := ReadBool('update', 'UpdateListNoMangaInfo', False); + cbOptionUpdateListRemoveDuplicateLocalData.Checked := ReadBool('update', 'UpdateListRemoveDuplicateLocalData', False); + + // dialogs + cbOptionShowQuitDialog.Checked := ReadBool('dialogs', 'ShowQuitDialog', True); + cbOptionShowDeleteTaskDialog.Checked := ReadBool('dialogs', 'ShowDeleteDldTaskDialog', True); + + // misc + cbOptionBatotoShowScanGroup.Checked := ReadBool('misc', 'BatotoShowScanGroup', True); + cbOptionBatotoShowAllLang.Checked := ReadBool('misc', 'BatotoShowAllLang', False); + cbOptionMangaFoxRemoveWatermarks.Checked := ReadBool('misc', 'MangafoxRemoveWatermarks', False); + + // websites + if Length(optionMangaSiteSelectionNodes) > 0 then + for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + optionMangaSiteSelectionNodes[i]^.CheckState := csUncheckedNormal; + l := TStringList.Create; + try + s := options.ReadString('general', 'MangaListSelect', + mangalistIni.ReadString('general', 'DefaultSelect', DEFAULT_LIST)); + if Pos(SEPERATOR, s) > 0 then + GetParams(l, s) //for old config + else + ExtractStrings([','], [], PChar(s), l); + if l.Count > 0 then + for i := 0 to l.Count - 1 do + begin + if Length(optionMangaSiteSelectionNodes) > 0 then + for j := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + begin + data := vtOptionMangaSiteSelection.GetNodeData( + optionMangaSiteSelectionNodes[j]); + if data^.Text = l.Strings[i] then + begin + optionMangaSiteSelectionNodes[j]^.CheckState := csCheckedNormal; + Break; + end; + end; + end; + finally + l.Free; + end; + end; +end; + +procedure TMainForm.SaveOptions; +var + s: String; begin - // general - cbOptionOneInstanceOnly.Checked := - options.ReadBool('general', 'OneInstanceOnly', True); - //FMDInstance - if cbOptionOneInstanceOnly.Checked then + s := SaveMangaOptions; + if s = '' then begin - if FMDInstance = nil then + MessageDlg('', RS_DlgMangaListSelect, + mtConfirmation, [mbYes], 0); + Exit; + end; + + with options do + try + // general + WriteString('general', 'MangaListSelect', s); + WriteBool('general', 'LiveSearch', cbOptionLiveSearch.Checked); + WriteBool('general', 'OneInstanceOnly', cbOptionOneInstanceOnly.Checked); + if cbLanguages.ItemIndex > -1 then + WriteString('languages', 'Selected', AvailableLanguages.Names[cbLanguages.ItemIndex]); + WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); + WriteInteger('general', 'NewMangaTime', seOptionNewMangaTime.Value); + WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); + WriteString('general', 'ExternalProgramPath', edOptionExternalPath.FileName); + WriteString('general', 'ExternalProgramParams', edOptionExternalParams.Text); + WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); + WriteBool('general', 'HighlightNewManga', miHighlightNewManga.Checked); + WriteBool('general', 'HighlightDownloadedChapters', miChapterListHighlight.Checked); + + // view + WriteBool('view', 'ShowDownloadsToolbar', cbOptionShowDownloadToolbar.Checked); + WriteBool('view', 'LoadMangaCover', cbOptionEnableLoadCover.Checked); + SaveDropTargetFormInformation; + + // connections + WriteInteger('connections', 'NumberOfTasks', seOptionMaxParallel.Value); + WriteInteger('connections', 'NumberOfThreadsPerTask', seOptionMaxThread.Value); + WriteInteger('connections', 'Retry', seOptionMaxRetry.Value); + WriteInteger('connections', 'ConnectionTimeout', seOptionConnectionTimeout.Value); + WriteBool('connections', 'UseProxy', cbOptionUseProxy.Checked); + WriteString('connections', 'ProxyType', cbOptionProxyType.Text); + WriteString('connections', 'Host', edOptionHost.Text); + WriteString('connections', 'Pass', edOptionPass.Text); + WriteString('connections', 'Port', edOptionPort.Text); + WriteString('connections', 'User', edOptionUser.Text); + + // saveto + if Trim(edOptionDefaultPath.Text) = '' then + edOptionDefaultPath.Text := DEFAULT_PATH; + edOptionDefaultPath.Text := CorrectPathSys(edOptionDefaultPath.Text); + WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); + WriteBool('saveto', 'PathConvert', cbOptionPathConvert.Checked); + WriteBool('saveto', 'GenerateChapterName', cbOptionGenerateChapterName.Checked); + WriteBool('saveto', 'GenerateMangaName', cbOptionGenerateMangaFolderName.Checked); + WriteInteger('saveto', 'Compress', rgOptionCompress.ItemIndex); + WriteBool('saveto', 'AutoNumberChapter', cbOptionAutoNumberChapter.Checked); + OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; + WriteInteger('saveto', 'PDFQuality', seOptionPDFQuality.Value); + if Trim(edOptionCustomRename.Text) = '' then + edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; + WriteString('saveto', 'CustomRename', edOptionCustomRename.Text); + WriteBool('saveto', 'ConvertDigitVolume', cbOptionDigitVolume.Checked); + WriteBool('saveto', 'ConvertDigitChapter', cbOptionDigitChapter.Checked); + WriteInteger('saveto', 'DigitVolumeLength', seOptionDigitVolume.Value); + WriteInteger('saveto', 'DigitChapterLength', seOptionDigitChapter.Value); + + // update + WriteBool('update', 'AutoCheckUpdate', cbOptionAutoCheckUpdate.Checked); + WriteBool('update', 'AutoCheckFavStartup', cbOptionAutoCheckFavStartup.Checked); + WriteInteger('update', 'AutoCheckMinutes', seOptionCheckMinutes.Value); + WriteBool('update', 'AutoDownloadFavorites', cbOptionAutoDlFav.Checked); + WriteBool('update', 'AutoRemoveCompletedManga', cbOptionAutoRemoveCompletedManga.Checked); + WriteBool('update', 'UpdateListNoMangaInfo', cbOptionUpdateListNoMangaInfo.Checked); + WriteBool('update', 'UpdateListRemoveDuplicateLocalData', cbOptionUpdateListRemoveDuplicateLocalData.Checked); + + // dialogs + WriteBool('dialogs', 'ShowQuitDialog', cbOptionShowQuitDialog.Checked); + WriteBool('dialogs', 'ShowDeleteDldTaskDialog', cbOptionShowDeleteTaskDialog.Checked); + + // misc + WriteBool('misc', 'BatotoShowScanGroup', cbOptionBatotoShowScanGroup.Checked); + WriteBool('misc', 'BatotoShowAllLang', cbOptionBatotoShowAllLang.Checked); + WriteBool('misc', 'MangafoxRemoveWatermarks', cbOptionMangaFoxRemoveWatermarks.Checked); + finally + UpdateFile; + end; +end; + +procedure TMainForm.ApplyOptions; +var + i: Integer; + isStillHaveCurrentWebsite: Boolean = False; + data: PSingleItem; +begin + try + // general + cbSelectManga.Clear; + for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do begin - FMDInstance := TSimpleIPCServer.Create(Self); - FMDInstance.ServerID := FMD_INSTANCE; - FMDInstance.Global := True; - FMDInstance.OnMessage := @FMDInstanceReceiveMsg; - FMDInstance.StartServer; + data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); + if (optionMangaSiteSelectionNodes[i]^.CheckState = csCheckedNormal) and + (Data^.Text <> '') then + cbSelectManga.Items.Add(data^.Text); end; - end - else - begin - if FMDInstance <> nil then + for i := 0 to cbSelectManga.Items.Count - 1 do begin - FMDInstance.StopServer; - FreeAndNil(FMDInstance); + if cbSelectManga.Items[i] = currentWebsite then + begin + cbSelectManga.ItemIndex := i; + isStillHaveCurrentWebsite := True; + Break; + end; end; - end; - cbOptionLiveSearch.Checked := options.ReadBool('general', 'LiveSearch', True); - cbOptionMinimizeToTray.Checked := options.ReadBool('general', 'MinimizeToTray', False); - OptionEnableLoadCover := options.ReadBool('general', 'LoadMangaCover', True); - cbOptionEnableLoadCover.Checked := OptionEnableLoadCover; - cbOptionLetFMDDo.ItemIndex := options.ReadInteger('general', 'LetFMDDo', 0); - OptionLetFMDDo := TFMDDo(cbOptionLetFMDDo.ItemIndex); - cbOptionAutoNumberChapter.Checked := - options.ReadBool('general', 'AutoNumberChapter', True); - edOptionExternalPath.FileName := options.ReadString('general', 'ExternalProgramPath', ''); - edOptionExternalParams.Text := options.ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); - OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; - cbAddAsStopped.Checked := options.ReadBool('general', 'AddAsStopped', False); - - // view - frmDropTarget.FWidth := options.ReadInteger('droptarget', 'Width', - frmDropTarget.FWidth); - frmDropTarget.FHeight := options.ReadInteger('droptarget', 'Heigth', - frmDropTarget.FHeight); - frmDropTarget.FTop := options.ReadInteger('droptarget', 'Top', - frmDropTarget.FTop); - frmDropTarget.FLeft := options.ReadInteger('droptarget', 'Left', - frmDropTarget.FLeft); - rgDropTargetMode.ItemIndex := options.ReadInteger('droptarget', 'Mode', 0); - tbDropTargetOpacity.Position := options.ReadInteger('droptarget', 'Opacity', 255); - ckDropTarget.Checked := options.ReadBool('droptarget', 'Show', False); - cbOptionShowDownloadToolbar.Checked := options.ReadBool('view', 'ShowDownloadsToolbar', True); - ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; - - // connection - seOptionMaxParallel.Value := options.ReadInteger('connections', 'NumberOfTasks', 1); - seOptionMaxThread.Value := options.ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - seOptionMaxRetry.Value := options.ReadInteger('connections', 'Retry', 3);; - OptionMaxRetry := seOptionMaxRetry.Value; - DLManager.maxDLTasks := seOptionMaxParallel.Value; - DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; - DLManager.retryConnect := seOptionMaxRetry.Value; - seOptionConnectionTimeout.Value := options.ReadInteger('connections', 'ConnectionTimeout', 15); - OptionConnectionTimeout := seOptionConnectionTimeout.Value*1000; - - // saveto - DLManager.compress := options.ReadInteger('saveto', 'Compress', 0); - cbOptionPathConvert.Checked := options.ReadBool('saveto', 'PathConv', False); - cbOptionGenerateChapterName.Checked := - options.ReadBool('saveto', 'GenChapName', False); - cbOptionGenerateMangaFolderName.Checked := - options.ReadBool('saveto', 'GenMangaName', True); - cbOptionAutoNumberChapter.Checked := - options.ReadBool('saveto', 'AutoNumberChapter', True); - seOptionPDFQuality.Value := options.ReadInteger('saveto', 'PDFQuality', 100); - OptionPDFQuality := seOptionPDFQuality.Value; - edOptionCustomRename.Text := - options.ReadString('saveto', 'CustomRename', DEFAULT_CUSTOM_RENAME); - if Trim(edOptionCustomRename.Text) = '' then - edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; - OptionCustomRename := edOptionCustomRename.Text; - if options.ReadBool('connections', 'UseProxy', False) then - begin - OptionProxyType := options.ReadString('connections', 'ProxyType', 'HTTP'); - OptionProxyHost := options.ReadString('connections', 'Host', ''); - OptionProxyPass := options.ReadString('connections', 'Pass', ''); - OptionProxyPort := options.ReadString('connections', 'Port', ''); - OptionProxyUser := options.ReadString('connections', 'User', ''); - end; + if not isStillHaveCurrentWebsite then + begin + if cbSelectManga.Items.Count > 0 then + begin + cbSelectManga.ItemIndex := 0; + cbSelectMangaChange(cbSelectManga); + end + else + begin + cbSelectManga.ItemIndex := -1; + cbSelectManga.Text := ''; + currentWebsite := ''; + vtMangaList.Clear; + lbMode.Caption := Format(RS_ModeAll, [0]); + end; + end; + //FMDInstace + if cbOptionOneInstanceOnly.Checked then + begin + if FMDInstance = nil then + begin + FMDInstance := TSimpleIPCServer.Create(Self); + FMDInstance.ServerID := FMD_INSTANCE; + FMDInstance.Global := True; + FMDInstance.OnMessage := @FMDInstanceReceiveMsg; + FMDInstance.StartServer; + end; + end + else + begin + if FMDInstance <> nil then + begin + FMDInstance.StopServer; + FreeAndNil(FMDInstance); + end; + end; + OptionLetFMDDo := TFMDDo(cbOptionLetFMDDo.ItemIndex); + OptionEnableLoadCover := cbOptionEnableLoadCover.Checked; + OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; - // update - cbOptionAutoCheckUpdate.Checked := - options.ReadBool('update', 'AutoCheckUpdate', True); - cbOptionAutoRemoveCompletedManga.Checked := - options.ReadBool('update', 'AutoRemoveCompletedManga', False); - OptionAutoRemoveCompletedManga := cbOptionAutoRemoveCompletedManga.Checked; - cbOptionAutoCheckFavStartup.Checked := - options.ReadBool('update', 'AutoCheckFavStartup', True); - OptionAutoCheckFavStartup := cbOptionAutoCheckFavStartup.Checked; - seOptionCheckMinutes.Value := options.ReadInteger('update', 'AutoCheckMinutes', 60); - lbOptionAutoCheckMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, - [seOptionCheckMinutes.Value]); - OptionCheckMinutes := seOptionCheckMinutes.Value; - cbOptionUpdateListNoMangaInfo.Checked := - options.ReadBool('update', 'UpdateListNoMangaInfo', False); - OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; - cbOptionUpdateListRemoveDuplicateLocalData.Checked := - options.ReadBool('update', 'UpdateListRemoveDuplicateLocalData', False); - OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; - - // misc - cbOptionShowBatotoSG.Checked := options.ReadBool('misc', 'ShowBatotoSG', True); - OptionShowBatotoSG := cbOptionShowBatotoSG.Checked; - cbOptionShowAllLang.Checked := options.ReadBool('misc', 'ShowAllLang', False); - OptionShowAllLang := cbOptionShowAllLang.Checked; - cbOptionAutoDlFav.Checked := options.ReadBool('misc', 'AutoDlFav', False); - OptionAutoDlFav := cbOptionAutoDlFav.Checked; - - vtFavorites.Header.SortColumn := options.ReadInteger('misc', 'SortFavoritesColumn', 1); - FavoriteManager.sortDirection := options.ReadBool('misc', 'SortFavoritesDirection', False); - - vtDownload.Header.SortColumn := options.ReadInteger('misc', 'SortDownloadColumn', 0); - DLManager.SortDirection := options.ReadBool('misc', 'SortDownloadDirection', False); - vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); - vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); + //view + ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; - if OptionCheckMinutes = 0 then - itCheckForChapters.Enabled := False - else - begin - itCheckForChapters.Interval := OptionCheckMinutes * 60000; - itCheckForChapters.Enabled := True; - end; + //connection + OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; + OptionMaxRetry := seOptionMaxRetry.Value; + DLManager.maxDLTasks := seOptionMaxParallel.Value; + DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; + DLManager.retryConnect := OptionMaxRetry; + if cbOptionUseProxy.Checked then + begin + OptionProxyType := cbOptionProxyType.Text; + OptionProxyHost := edOptionHost.Text; + OptionProxyPass := edOptionPass.Text; + OptionProxyPort := edOptionPort.Text; + OptionProxyUser := edOptionUser.Text; + end + else + begin + OptionProxyType := ''; + OptionProxyHost := ''; + OptionProxyPass := ''; + OptionProxyPort := ''; + OptionProxyUser := ''; + end; - cbOptionDigitVolume.Checked := options.ReadBool('saveto', 'ConvertDigitVolume', True); - seOptionDigitVolume.Value := options.ReadInteger('saveto', 'DigitVolumeLength', 2); - seOptionDigitVolume.Enabled := cbOptionDigitVolume.Checked; - cbOptionDigitChapter.Checked := - options.ReadBool('saveto', 'ConvertDigitChapter', True); - seOptionDigitChapter.Value := options.ReadInteger('saveto', 'DigitChapterLength', 3); - seOptionDigitChapter.Enabled := cbOptionDigitChapter.Checked; + //saveto + OptionPDFQuality := seOptionPDFQuality.Value; + OptionCustomRename := edOptionCustomRename.Text; + DLManager.compress := rgOptionCompress.ItemIndex; - cbOptionMangaFoxRemoveWatermarks.Checked := - options.ReadBool('misc', 'MangafoxRemoveWatermarks', False); + //update + OptionAutoRemoveCompletedManga := cbOptionAutoRemoveCompletedManga.Checked; + OptionAutoCheckFavStartup := cbOptionAutoCheckFavStartup.Checked; + OptionCheckMinutes := seOptionCheckMinutes.Value; + if OptionCheckMinutes = 0 then + itCheckForChapters.Enabled := False + else + begin + itCheckForChapters.Interval := OptionCheckMinutes * 60000; + itCheckForChapters.Enabled := True; + end; + OptionAutoDlFav := cbOptionAutoDlFav.Checked; + OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; + OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; - cbLanguages.Items.Clear; - uTranslation.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; - uTranslation.LangAppName := 'fmd'; - uTranslation.CollectLanguagesFiles; - if uTranslation.AvailableLanguages.Count > 0 then - begin - for i := 0 to AvailableLanguages.Count - 1 do - cbLanguages.Items.Add(uTranslation.AvailableLanguages.ValueFromIndex[i]); - cbLanguages.ItemIndex := uTranslation.AvailableLanguages.IndexOfName( - options.ReadString('languages', 'Selected', 'en')); + //misc + OptionShowBatotoSG := cbOptionBatotoShowScanGroup.Checked; + OptionShowAllLang := cbOptionBatotoShowAllLang.Checked; + + //languages + ApplyLanguage; + finally + DLManager.CheckAndActiveTask; end; end; @@ -4838,7 +4661,7 @@ procedure TMainForm.LoadMangaOptions; lang: TStringList; s, currentLanguage: String; ANode, currentRootNode: PVirtualNode; - Data: PMangaListItem; + data: PSingleItem; wName, wLang: TStringList; begin wName := TStringList.Create; @@ -4867,14 +4690,14 @@ procedure TMainForm.LoadMangaOptions; begin currentLanguage := wLang[i]; currentRootNode := AddChild(nil); - Data := GetNodeData(currentRootNode); - Data^.Text := currentLanguage; + data := GetNodeData(currentRootNode); + data^.Text := currentLanguage; ValidateNode(currentRootNode, False); end; ANode := AddChild(currentRootNode); ANode^.CheckState := csUncheckedNormal; - Data := GetNodeData(ANode); - Data^.Text := wName[i]; + data := GetNodeData(ANode); + data^.Text := wName[i]; ValidateNode(ANode, False); optionMangaSiteSelectionNodes[i] := ANode; end; @@ -4920,8 +4743,7 @@ procedure TMainForm.LoadMangaOptions; if sel > cbSelectManga.Items.Count - 1 then sel := cbSelectManga.Items.Count - 1; cbSelectManga.ItemIndex := sel; - currentWebsite := cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]; - dataProcess.website := cbSelectManga.Items.Strings[cbSelectManga.ItemIndex]; + currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; end; finally lang.Free; @@ -4933,7 +4755,7 @@ procedure TMainForm.LoadMangaOptions; function TMainForm.SaveMangaOptions: String; var i: Cardinal; - Data: PMangaListItem; + data: PSingleItem; begin Result := ''; if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4941,11 +4763,11 @@ function TMainForm.SaveMangaOptions: String; begin if optionMangaSiteSelectionNodes[i]^.CheckState = csCheckedNormal then begin - Data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); + data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); if Result = '' then - Result := Data^.Text + Result := data^.Text else - Result := Result + ',' + Data^.Text; + Result := Result + ',' + data^.Text; end; end; end; @@ -5014,59 +4836,77 @@ procedure TMainForm.LoadFormInformation; var i: Integer; begin - pcLeft.Width := options.ReadInteger('form', 'MainSplitter', 195); - sbMain.Panels[0].Width := pcLeft.Width + 4; + with options do + begin + pcLeft.Width := ReadInteger('form', 'MainSplitter', 195); + sbMain.Panels[0].Width := pcLeft.Width + 4; - pcMain.PageIndex := options.ReadInteger('form', 'pcMainPageIndex', 0); + pcMain.PageIndex := ReadInteger('form', 'pcMainPageIndex', 0); - Left := options.ReadInteger('form', 'MainFormLeft', MainForm.Left); - Top := options.ReadInteger('form', 'MainFormTop', MainForm.Top); - Width := options.ReadInteger('form', 'MainFormWidth', 640); - Height := options.ReadInteger('form', 'MainFormHeight', 480); + Left := ReadInteger('form', 'MainFormLeft', MainForm.Left); + Top := ReadInteger('form', 'MainFormTop', MainForm.Top); + Width := ReadInteger('form', 'MainFormWidth', 640); + Height := ReadInteger('form', 'MainFormHeight', 480); - if options.ReadBool('form', 'MainFormMaximized', False) then - PrevWindowState := wsMaximized - else - PrevWindowState := wsNormal; - WindowState := PrevWindowState; + if ReadBool('form', 'MainFormMaximized', False) then + PrevWindowState := wsMaximized + else + PrevWindowState := wsNormal; + WindowState := PrevWindowState; - if vtDownload.Header.Columns.Count > 0 then - with vtDownload.Header.Columns do - for i := 0 to Count - 1 do - Items[i].Width := options.ReadInteger('form', 'vtDownload' + IntToStr(i) + 'Width', 50); + if vtDownload.Header.Columns.Count > 0 then + with vtDownload.Header.Columns do + for i := 0 to Count - 1 do + Items[i].Width := ReadInteger('form', 'vtDownload' + IntToStr(i) + 'Width', 50); - if vtFavorites.Header.Columns.Count > 0 then - with vtFavorites.Header.Columns do - for i := 0 to Count - 1 do - Items[i].Width := options.ReadInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', 50); + if vtFavorites.Header.Columns.Count > 0 then + with vtFavorites.Header.Columns do + for i := 0 to Count - 1 do + Items[i].Width := ReadInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', 50); + + FavoriteManager.sortDirection := ReadBool('misc', 'SortFavoritesDirection', False); + vtFavorites.Header.SortColumn := ReadInteger('misc', 'SortFavoritesColumn', 1); + vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); + + DLManager.SortDirection := ReadBool('misc', 'SortDownloadDirection', False); + vtDownload.Header.SortColumn := ReadInteger('misc', 'SortDownloadColumn', 0); + vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); + end; end; procedure TMainForm.SaveFormInformation; var i: Integer; begin - options.WriteInteger('form', 'MainSplitter', pcLeft.Width); - options.WriteInteger('form', 'pcMainPageIndex', pcMain.PageIndex); - - if vtDownload.Header.Columns.Count > 0 then - with vtDownload.Header.Columns do - for i := 0 to Count - 1 do - options.WriteInteger('form', 'vtDownload' + IntToStr(i) + 'Width', Items[i].Width); - - if vtFavorites.Header.Columns.Count > 0 then - with vtFavorites.Header.Columns do - for i := 0 to Count - 1 do - options.WriteInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', Items[i].Width); - - options.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); - - options.WriteBool('form', 'MainFormMaximized', (WindowState = wsMaximized)); - if WindowState = wsMaximized then - WindowState := wsNormal; - options.WriteInteger('form', 'MainFormLeft', Left); - options.WriteInteger('form', 'MainFormTop', Top); - options.WriteInteger('form', 'MainFormWidth', Width); - options.WriteInteger('form', 'MainFormHeight', Height); + with options do + begin + WriteInteger('form', 'MainSplitter', pcLeft.Width); + WriteInteger('form', 'pcMainPageIndex', pcMain.PageIndex); + WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); + WriteBool('form', 'MainFormMaximized', (WindowState = wsMaximized)); + if WindowState = wsMaximized then + WindowState := wsNormal; + WriteInteger('form', 'MainFormLeft', Left); + WriteInteger('form', 'MainFormTop', Top); + WriteInteger('form', 'MainFormWidth', Width); + WriteInteger('form', 'MainFormHeight', Height); + + if vtDownload.Header.Columns.Count > 0 then + with vtDownload.Header.Columns do + for i := 0 to Count - 1 do + WriteInteger('form', 'vtDownload' + IntToStr(i) + 'Width', Items[i].Width); + + if vtFavorites.Header.Columns.Count > 0 then + with vtFavorites.Header.Columns do + for i := 0 to Count - 1 do + WriteInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', Items[i].Width); + + WriteInteger('misc', 'SortDownloadColumn', vtDownload.Header.SortColumn); + WriteBool('misc', 'SortDownloadDirection', DLManager.SortDirection); + + WriteInteger('misc', 'SortFavoritesColumn', vtFavorites.Header.SortColumn); + WriteBool('misc', 'SortFavoritesDirection', FavoriteManager.sortDirection); + end; end; procedure TMainForm.SaveDropTargetFormInformation; @@ -5084,7 +4924,24 @@ procedure TMainForm.SaveDropTargetFormInformation; end; end; -procedure TMainForm.LoadLanguage; +procedure TMainForm.CollectLanguagesFromFiles; +var + i: Integer; +begin + cbLanguages.Items.Clear; + uTranslation.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; + uTranslation.LangAppName := 'fmd'; + uTranslation.CollectLanguagesFiles; + if uTranslation.AvailableLanguages.Count > 0 then + begin + for i := 0 to AvailableLanguages.Count - 1 do + cbLanguages.Items.Add(uTranslation.AvailableLanguages.ValueFromIndex[i]); + cbLanguages.ItemIndex := uTranslation.AvailableLanguages.IndexOfName( + options.ReadString('languages', 'Selected', 'en')); + end; +end; + +procedure TMainForm.ApplyLanguage; var idxLanguages, idxFilterStatus, @@ -5204,7 +5061,7 @@ procedure TMainForm.vtOptionMangaSiteSelectionFocusChanged( procedure TMainForm.vtOptionMangaSiteSelectionFreeNode( Sender : TBaseVirtualTree; Node : PVirtualNode); var - Data: PMangaListItem; + Data: PSingleItem; begin Data := vtOptionMangaSiteSelection.GetNodeData(Node); if Assigned(Data) then @@ -5221,7 +5078,7 @@ procedure TMainForm.vtOptionMangaSiteSelectionGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); var - Data: PMangaListItem; + Data: PSingleItem; begin Data := vtOptionMangaSiteSelection.GetNodeData(Node); if Assigned(Data) then diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index e67a94ac9..73733fc0b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -399,6 +399,16 @@ msgstr "Auto number chapter" msgid "Automatic remove completed manga from Favorites" msgstr "Automatic remove completed manga from Favorites" +#: tmainform.cboptionbatotoshowalllang.caption +msgctxt "tmainform.cboptionbatotoshowalllang.caption" +msgid "[Batoto] Show All Language" +msgstr "[Batoto] Show All Language" + +#: tmainform.cboptionbatotoshowscangroup.caption +msgctxt "tmainform.cboptionbatotoshowscangroup.caption" +msgid "[Batoto] Show scan group name" +msgstr "[Batoto] Show scan group name" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Chapter" @@ -443,14 +453,6 @@ msgstr "Change all all unicode symbols to \"_\" (choose this when you have probl msgid "HTTP" msgstr "HTTP" -#: tmainform.cboptionshowalllang.caption -msgid "[Batoto] Show All Language" -msgstr "[Batoto] Show All Language" - -#: tmainform.cboptionshowbatotosg.caption -msgid "[Batoto] Show scan group name" -msgstr "[Batoto] Show scan group name" - #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Delete task/favorite" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 8cb250d82..d64fd0217 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -393,6 +393,16 @@ msgstr "Otomatis nomor bab" msgid "Automatic remove completed manga from Favorites" msgstr "Otomatis hapus komik yang sudah tamat dari daftar kesukaan" +#: tmainform.cboptionbatotoshowalllang.caption +msgctxt "tmainform.cboptionbatotoshowalllang.caption" +msgid "[Batoto] Show All Language" +msgstr "[Batoto] Tampilkan semua bahasa" + +#: tmainform.cboptionbatotoshowscangroup.caption +msgctxt "tmainform.cboptionbatotoshowscangroup.caption" +msgid "[Batoto] Show scan group name" +msgstr "[Batoto] Tampilkan nama grup scan" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Bab" @@ -437,14 +447,6 @@ msgstr "Ubah semua simbol unicode menjadi \"_\" (pilih ini ketika Anda memiliki msgid "HTTP" msgstr "HTTP" -#: tmainform.cboptionshowalllang.caption -msgid "[Batoto] Show All Language" -msgstr "[Batoto] Tampilkan semua bahasa" - -#: tmainform.cboptionshowbatotosg.caption -msgid "[Batoto] Show scan group name" -msgstr "[Batoto] Tampilkan nama grup scan" - #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Hapus unduhan/kesukaan" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 99ad326d1..8ba4f2631 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -365,6 +365,16 @@ msgstr "" msgid "Automatic remove completed manga from Favorites" msgstr "" +#: tmainform.cboptionbatotoshowalllang.caption +msgctxt "TMAINFORM.CBOPTIONBATOTOSHOWALLLANG.CAPTION" +msgid "[Batoto] Show All Language" +msgstr "" + +#: tmainform.cboptionbatotoshowscangroup.caption +msgctxt "TMAINFORM.CBOPTIONBATOTOSHOWSCANGROUP.CAPTION" +msgid "[Batoto] Show scan group name" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "" @@ -409,14 +419,6 @@ msgstr "" msgid "HTTP" msgstr "" -#: tmainform.cboptionshowalllang.caption -msgid "[Batoto] Show All Language" -msgstr "" - -#: tmainform.cboptionshowbatotosg.caption -msgid "[Batoto] Show scan group name" -msgstr "" - #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "" From ad99faadde73ef849831fca9356fc8eb1e237a22 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 03:46:04 +0800 Subject: [PATCH 0328/2794] baseunit, getpage: set sock connectiontimeout --- baseunits/uBaseUnit.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6dfb2134e..5d186c5de 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2796,6 +2796,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.Timeout := OptionConnectionTimeout; + HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; HTTP.Sock.SetTimeout(OptionConnectionTimeout); //User-Agent @@ -3091,6 +3092,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.Timeout := OptionConnectionTimeout; + HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; HTTP.Sock.SetTimeout(OptionConnectionTimeout); //User-Agent From 5db139fb0c327d58a333d0c92ca387736efe9c0a Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 04:42:01 +0800 Subject: [PATCH 0329/2794] cleanup and optimize, change maxretry = -1 = infinite --- baseunits/WebsiteModules.pas | 11 ++-- baseunits/modules/Batoto.pas | 2 +- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/modules/MangaFox.pas | 2 +- baseunits/modules/WPManga.pas | 2 +- baseunits/modules/mh160com.pas | 2 +- baseunits/uBaseUnit.pas | 74 +++++++++++++++----------- baseunits/uData.pas | 8 +-- baseunits/uDownloadsManager.pas | 8 +-- mangadownloader/forms/frmMain.lfm | 7 +-- mangadownloader/languages/fmd.en.po | 5 +- mangadownloader/languages/fmd.id_ID.po | 4 +- mangadownloader/languages/fmd.po | 2 +- 13 files changed, 72 insertions(+), 57 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 1c7d3ca31..0224d50d1 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -23,7 +23,7 @@ TModuleContainer = class; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; TOnGetInfo = function(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; Module: TModuleContainer): Integer; + const Reconnect: Integer; Module: TModuleContainer): Integer; TOnGetPageNumber = function(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; @@ -94,9 +94,9 @@ TWebsiteModules = class(TObject) const Names, Links: TStringList; const URL, Website: String): Integer; overload; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; const ModuleIndex: Integer): Integer; overload; + const Reconnect: Integer; const ModuleIndex: Integer): Integer; overload; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; const Website: String): Integer; overload; + const Reconnect: Integer; const Website: String): Integer; overload; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; const ModuleIndex: Integer): Boolean; overload; @@ -300,7 +300,8 @@ function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const URL: String; const Reconnect: Cardinal; const ModuleIndex: Integer): Integer; + const URL: String; const Reconnect: Integer; const ModuleIndex: Integer + ): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleIndex < 0) or (FModuleList.Count = 0) or @@ -312,7 +313,7 @@ function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const URL: String; const Reconnect: Cardinal; const Website: String): Integer; + const URL: String; const Reconnect: Integer; const Website: String): Integer; begin Result := GetInfo(MangaInfo, URL, Reconnect, LocateModule(Website)); end; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 630619c49..7341db472 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -117,7 +117,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; Module: TModuleContainer): Integer; + const Reconnect: Integer; Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index ccba338ef..2813625a3 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -89,7 +89,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; Module: TModuleContainer): Integer; + const Reconnect: Integer; Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 1f9863ad7..480106045 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -56,7 +56,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; Module: TModuleContainer): Integer; + const Reconnect: Integer; Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index b5a5eec42..c3563d36b 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -132,7 +132,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; Module: TModuleContainer): Integer; + const Reconnect: Integer; Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index cc3ffc858..4608e6e12 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -62,7 +62,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Cardinal; Module: TModuleContainer): Integer; + const Reconnect: Integer; Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5d186c5de..80f72d562 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -222,7 +222,7 @@ interface NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; - SOCKHEARTBEATRATE = 300; + SOCKHEARTBEATRATE = 1000; DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_CUSTOM_RENAME = '%NUMBERING% - %CHAPTER%'; @@ -802,12 +802,12 @@ TParseHTML = class { THTTPSendThread } THTTPSendThread = class(THTTPSend) - protected - FOwner: TFMDThread; - procedure CloseConnection(SendTerminateTag: Boolean = True); - procedure SockOnHeartBeat(Sender: TObject); - public - constructor Create(AOwner: TFMDThread); + protected + FOwner: TFMDThread; + procedure CloseConnection(SendTerminateTag: Boolean = True); + procedure SockOnHeartBeat(Sender: TObject); + public + constructor Create(AOwner: TFMDThread); end; // Get current binary version @@ -930,16 +930,16 @@ procedure CustomGenres(var output: TStringList; input: String); function SourceForgeURL(URL: String): String; // Get HTML source code from a URL. function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; - const Reconnect: Cardinal): Boolean; overload; -function GetPage(var output: TObject; URL: String; const Reconnect: Cardinal): Boolean; + const Reconnect: Integer = 0): Boolean; overload; +function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; overload; inline; // Get url from a bitly url. function GetURLFromBitly(const URL: String): String; // Download an image from url and save it to a specific location. function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Cardinal): Boolean; overload; + const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Cardinal): Boolean; overload; inline; + const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; inline; procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); @@ -2690,14 +2690,14 @@ function SourceForgeURL(URL: String): String; end; function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; - const Reconnect: Cardinal): Boolean; + const Reconnect: Integer): Boolean; // If AHTTP <> nil, we will use it as http sender. Otherwise we create a new // instance. var //i: Cardinal; HTTP: THTTPSend; HTTPHeader: TStringList; - counter: Cardinal = 0; + counter, counter2: Integer; s: String; meth: String = 'GET'; //zstream: TGZFileStream; @@ -2723,9 +2723,9 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Free; end; - function checkTerminate: boolean; + function checkTerminate: Boolean; begin - Result := HTTP.Sock.Tag = 1; //terminated via OnHeartBeat + Result := HTTP.Sock.Tag = 1; //terminated via OnHeartBeat if Result then begin HTTP.Sock.Tag := 0; @@ -2876,7 +2876,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; (HTTP.ResultCode = 451) do begin if checkTerminate then Exit; - if (Reconnect <> 0) and (Reconnect <= counter) then + if (Reconnect > -1) and (Reconnect <= counter) then begin preTerminate; Exit; @@ -2890,6 +2890,12 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; while (HTTP.ResultCode > 300) and (HTTP.ResultCode < 400) do begin if checkTerminate then Exit; + if (Reconnect > -1) and (Reconnect <= counter) then + begin + preTerminate; + Exit; + end; + Inc(counter); HTTPHeader.Values['Referer'] := ' ' + URL; s := Trim(HTTP.Headers.Values['Location']); if s <> '' then @@ -2913,19 +2919,19 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; if Pos(HENTAI2READ_ROOT, URL) <> 0 then HTTP.Headers.Insert(0, 'Referer:' + HENTAI2READ_ROOT + '/'); - counter := 0; + counter2 := 0; HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) do //500 for abort begin if checkTerminate then Exit; - if (Reconnect <> 0) and (Reconnect <= counter) then + if (Reconnect > -1) and (Reconnect <= counter2) then begin preTerminate; Exit; end; - Inc(Counter); + Inc(counter2); HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; end; @@ -2970,7 +2976,8 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; preTerminate; end; -function GetPage(var output: TObject; URL: String; const Reconnect: Cardinal): Boolean; +function GetPage(var output: TObject; URL: String; const Reconnect: Integer + ): Boolean; begin Result := GetPage(nil, output, URL, Reconnect); end; @@ -2994,7 +3001,7 @@ function GetURLFromBitly(const URL: String): String; end; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; - URL: String; const Path, Name, prefix: String; const Reconnect: Cardinal + URL: String; const Path, Name, prefix: String; const Reconnect: Integer ): Boolean; // prefix: For example: 000.jpg. var @@ -3003,7 +3010,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; ext, lpath, fpath: String; HTTPHeader: TStringList; HTTP: THTTPSend; - counter: Cardinal; + counter, counter2: Integer; s: String; //source : TPicture; fstream: TFileStreamUTF8; @@ -3015,7 +3022,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Free; end; - function checkTerminate: boolean; + function checkTerminate: Boolean; begin Result := HTTP.Sock.Tag = 1; //terminated via OnHeartBeat if Result then @@ -3143,12 +3150,12 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; {$IFDEF DOWNLOADER} if checkTerminate then Exit; {$ENDIF} - if (Reconnect <> 0) and (Reconnect <= counter) then + if (Reconnect > -1) and (Reconnect <= counter) then begin preTerminate; Exit; end; - Inc(Counter); + Inc(counter); HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; end; @@ -3159,7 +3166,12 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; {$IFDEF DOWNLOADER} if checkTerminate then Exit; {$ENDIF} - + if (Reconnect > -1) and (Reconnect <= counter) then + begin + preTerminate; + Exit; + end; + Inc(counter); HTTPHeader.Values['Referer'] := ' ' + URL; s := Trim(HTTP.Headers.Values['Location']); if s <> '' then @@ -3181,7 +3193,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; HTTP.Clear; - counter := 0; + counter2 := 0; HTTP.Headers.Text := HTTPHeader.Text; while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) or //500 for abort @@ -3190,12 +3202,12 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; {$IFDEF DOWNLOADER} if checkTerminate then Exit; {$ENDIF} - if (Reconnect <> 0) and (Reconnect <= counter) then + if (Reconnect > -1) and (Reconnect <= counter2) then begin preTerminate; Exit; end; - Inc(Counter); + Inc(counter2); HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; Sleep(500); @@ -3276,8 +3288,8 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; Result := (fpath <> '') and FileExistsUTF8(fpath); end; -function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Cardinal): Boolean; +function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name, + prefix: String; const Reconnect: Integer): Boolean; begin Result := SaveImage(nil, mangaSiteID, URL, Path, Name, prefix, Reconnect); end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 6c0cf4fb7..9e41d567f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -188,7 +188,7 @@ TMangaInformation = class(TObject) function GetDirectoryPage(var Page: Integer; const website: String): Byte; function GetNameAndLink(const names, links: TStringList; const website, URL: String): Byte; - function GetInfoFromURL(const website, URL: String; const Reconnect: Cardinal): Byte; + function GetInfoFromURL(const website, URL: String; const Reconnect: Integer = 0): Byte; procedure SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); overload; procedure SyncInfoToData(const DataProcess: TDBDataProcess); overload; @@ -206,7 +206,7 @@ TMangaInformation = class(TObject) const DataProcess: TDBDataProcess); overload; //wrapper function GetPage(var output: TObject; URL: String; - const Reconnect: Cardinal): Boolean; overload; + const Reconnect: Integer = 0): Boolean; overload; end; var @@ -2615,7 +2615,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; end; function TMangaInformation.GetInfoFromURL(const website, URL: String; - const Reconnect: Cardinal): Byte; + const Reconnect: Integer): Byte; var s: String; j, k: Integer; @@ -3285,7 +3285,7 @@ procedure TMangaInformation.AddInfoToData(const Title, Link: String; end; function TMangaInformation.GetPage(var output: TObject; URL: String; - const Reconnect: Cardinal): Boolean; + const Reconnect: Integer): Boolean; begin Result := uBaseUnit.GetPage(FHTTP, output, URL, Reconnect); end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 70eb04cbc..71da4716c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -59,10 +59,10 @@ TDownloadThread = class(TFMDThread) const Value: String); procedure SockOnHeartBeat(Sender: TObject); function GetPage(var output: TObject; URL: String; - const Reconnect: Cardinal): Boolean; overload; + const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Cardinal): Boolean; overload; + const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; procedure Execute; override; procedure DoTerminate; override; @@ -293,7 +293,7 @@ procedure TDownloadThread.SockOnHeartBeat(Sender: TObject); end; function TDownloadThread.GetPage(var output: TObject; URL: String; - const Reconnect: Cardinal): Boolean; + const Reconnect: Integer): Boolean; begin if FHTTP.Sock.Tag <> 100 then FHTTP.Clear; @@ -301,7 +301,7 @@ function TDownloadThread.GetPage(var output: TObject; URL: String; end; function TDownloadThread.SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Cardinal): Boolean; + const Path, Name, prefix: String; const Reconnect: Integer): Boolean; begin Result := uBaseUnit.SaveImage(FHTTP, mangaSiteID, URL, Path, Name, prefix, Reconnect); end; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 3946608e9..f91317f2b 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2093,7 +2093,7 @@ object MainForm: TMainForm Height = 375 Top = 0 Width = 579 - HorzScrollBar.Page = 455 + HorzScrollBar.Page = 457 VertScrollBar.Page = 179 Align = alClient BorderStyle = bsNone @@ -2283,6 +2283,7 @@ object MainForm: TMainForm Height = 23 Top = 90 Width = 48 + MinValue = -1 ParentFont = False ParentShowHint = False TabOrder = 4 @@ -2291,8 +2292,8 @@ object MainForm: TMainForm Left = 66 Height = 15 Top = 93 - Width = 386 - Caption = 'Number of retry times if tasks have download problems (0 = always retry)' + Width = 391 + Caption = 'Number of retry times if tasks have download problems (-1 = always retry)' ParentColor = False ParentFont = False end diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 73733fc0b..5fe159ade 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1061,8 +1061,9 @@ msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Number of downloaded tasks at the same time (Max: 8)" #: tmainform.lboptionmaxretry.caption -msgid "Number of retry times if tasks have download problems (0 = always retry)" -msgstr "Number of retry times if tasks have download problems (0 = always retry)" +#| msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Number of retry times if tasks have download problems (-1 = always retry)" #: tmainform.lboptionmaxthread.caption msgid "Number of downloaded files per task at the same time (Max: 32)" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index d64fd0217..a82b2b508 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1050,8 +1050,8 @@ msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Jumlah unduhan aktif pada waktu yang sama (Max: 8)" #: tmainform.lboptionmaxretry.caption -msgid "Number of retry times if tasks have download problems (0 = always retry)" -msgstr "Jumlah pengulangan jika unduhan memiliki masalah (0 = selalu coba lagi)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Jumlah pengulangan jika unduhan memiliki masalah (-1 = selalu coba lagi)" #: tmainform.lboptionmaxthread.caption msgid "Number of downloaded files per task at the same time (Max: 32)" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 8ba4f2631..a4f743a7a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1002,7 +1002,7 @@ msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "" #: tmainform.lboptionmaxretry.caption -msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" msgstr "" #: tmainform.lboptionmaxthread.caption From 498dda4b244c8ad34e53dede1922ff7087a20ef3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 04:55:54 +0800 Subject: [PATCH 0330/2794] downloadmanager, clean up --- baseunits/uDownloadsManager.pas | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 71da4716c..9f7114799 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -57,7 +57,6 @@ TDownloadThread = class(TFMDThread) procedure SockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); - procedure SockOnHeartBeat(Sender: TObject); function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; overload; @@ -282,16 +281,6 @@ destructor TDownloadThread.Destroy; inherited Destroy; end; -procedure TDownloadThread.SockOnHeartBeat(Sender: TObject); -begin - if Terminated then - begin - TBlockSocket(Sender).Tag := 1; - TBlockSocket(Sender).StopFlag := True; - TBlockSocket(Sender).AbortSocket; - end; -end; - function TDownloadThread.GetPage(var output: TObject; URL: String; const Reconnect: Integer): Boolean; begin From 16465c0b12bfee4311397d354dd552de4231f6ce Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 05:29:03 +0800 Subject: [PATCH 0331/2794] tfmdthread, add oncustomterminater --- baseunits/uFMDThread.pas | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/baseunits/uFMDThread.pas b/baseunits/uFMDThread.pas index 6fe741358..657f4bb0b 100644 --- a/baseunits/uFMDThread.pas +++ b/baseunits/uFMDThread.pas @@ -11,36 +11,36 @@ interface uses - Classes, SysUtils, USimpleException; + Classes, SysUtils, USimpleLogger; type { TFMDThread } TFMDThread = class(TThread) - protected + private + FOnCustomTerminate: TNotifyEvent; function GetTerminated: Boolean; + protected procedure DoTerminate; override; public constructor Create(CreateSuspended: Boolean = True); property IsTerminated: Boolean read GetTerminated; + procedure Terminate; + property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; end; implementation function TFMDThread.GetTerminated: Boolean; begin - Result := Terminated; + Result := Self.Terminated; end; procedure TFMDThread.DoTerminate; begin if (FatalException <> nil) and (FatalException is Exception) then - begin - Exception(FatalException).Message := - 'FatalException, ' + Exception(FatalException).Message; - USimpleException.ExceptionHandle(Self, Exception(FatalException)); - end; + WriteLog_E('TFMDThread.FatalException!', Exception(FatalException), Self); inherited DoTerminate; end; @@ -50,4 +50,11 @@ constructor TFMDThread.Create(CreateSuspended: Boolean = True); FreeOnTerminate := True; end; +procedure TFMDThread.Terminate; +begin + inherited Terminate; + if Assigned(FOnCustomTerminate) then + FOnCustomTerminate(Self); +end; + end. From ffd0582edf52db6e73c456434dabeefc3e687f47 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 05:30:02 +0800 Subject: [PATCH 0332/2794] use oncustomterminate to break connection --- baseunits/uBaseUnit.pas | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 80f72d562..bdc062fa6 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -222,7 +222,7 @@ interface NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; - SOCKHEARTBEATRATE = 1000; + SOCKHEARTBEATRATE = 300; DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_CUSTOM_RENAME = '%NUMBERING% - %CHAPTER%'; @@ -805,7 +805,7 @@ THTTPSendThread = class(THTTPSend) protected FOwner: TFMDThread; procedure CloseConnection(SendTerminateTag: Boolean = True); - procedure SockOnHeartBeat(Sender: TObject); + procedure OnOwnerTerminate(Sender: TObject); public constructor Create(AOwner: TFMDThread); end; @@ -3507,11 +3507,9 @@ procedure THTTPSendThread.CloseConnection(SendTerminateTag: Boolean); end; end; -procedure THTTPSendThread.SockOnHeartBeat(Sender: TObject); +procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); begin - if Assigned(FOwner) then - if FOwner.IsTerminated then - CloseConnection; + CloseConnection; end; constructor THTTPSendThread.Create(AOwner: TFMDThread); @@ -3519,9 +3517,8 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); inherited Create; if Assigned(AOwner) then begin - FOwner := TFMDThread(AOwner); - Sock.OnHeartbeat := SockOnHeartBeat; - Sock.HeartbeatRate := SOCKHEARTBEATRATE; + FOwner := AOwner; + FOwner.OnCustomTerminate := OnOwnerTerminate; end; end; From 49222e9fb9da15c131c6325419fec253f9f25221 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 05:31:11 +0800 Subject: [PATCH 0333/2794] lower minimum connection timeout to 1 --- mangadownloader/forms/frmMain.lfm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f91317f2b..f503cbd8e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2303,7 +2303,7 @@ object MainForm: TMainForm Top = 120 Width = 48 MaxValue = 300 - MinValue = 3 + MinValue = 1 ParentFont = False ParentShowHint = False TabOrder = 5 From f66a0642be0d7d100c0050cbc3517a24113e0874 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 05:32:33 +0800 Subject: [PATCH 0334/2794] getmangainfothread, lower max retry to 0 = no retry --- baseunits/uGetMangaInfosThread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 9548001d9..062496e3a 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -88,7 +88,7 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.isRemoveUnicode := MainForm.cbOptionPathConvert.Checked; infob := INFORMATION_NOT_FOUND; - infob := FInfo.GetInfoFromURL(Website, Link, 2); + infob := FInfo.GetInfoFromURL(Website, Link, 0); if Self.Terminated then Exit; if infob <> NO_ERROR then Exit; @@ -142,7 +142,7 @@ procedure TGetMangaInfosThread.DoGetInfos; if OptionEnableLoadCover and (Trim(FInfo.mangaInfo.coverLink) <> '') then begin FInfo.FHTTP.Document.Clear; - FIsHasMangaCover := GetPage(FInfo.FHTTP, TObject(FCover), FInfo.mangaInfo.coverLink, 3) + FIsHasMangaCover := GetPage(FInfo.FHTTP, TObject(FCover), FInfo.mangaInfo.coverLink, 0) end else FIsHasMangaCover := False; From 3ff6d1e73af3cad187e338a40259efdd89ac32e6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 06:46:25 +0800 Subject: [PATCH 0335/2794] websitemodules, do reverse search on host --- baseunits/WebsiteModules.pas | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 0224d50d1..e40893706 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -5,13 +5,14 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager; + Classes, SysUtils, uData, uDownloadsManager, RegExpr; const MODULE_NOT_FOUND = -1; NO_ERROR = 0; NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; + REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; type @@ -202,17 +203,35 @@ function TWebsiteModules.LocateModule(const Website: String): Integer; function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; var i: Integer; + h: String; begin Result := -1; if FModuleList.Count > 0 then + begin + h := LowerCase(Host); for i := 0 to FModuleList.Count - 1 do - begin - if Pos(Host, TModuleContainer(FModuleList[i]).RootURL) <> 0 then + if Pos(h, LowerCase(TModuleContainer(FModuleList[i]).RootURL)) <> 0 then begin Result := i; Break; end; + if Result = -1 then + begin + with TRegExpr.Create do + try + Expression := REGEX_HOST; + for i := 0 to FModuleList.Count - 1 do + if Pos(LowerCase(Replace(TModuleContainer(FModuleList[i]).RootURL, + '$2', True)), h) <> 0 then + begin + Result := i; + Break; + end; + finally + Free; + end; end; + end; end; function TWebsiteModules.ModuleAvailable(const ModuleIndex: Integer; @@ -300,8 +319,7 @@ function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const URL: String; const Reconnect: Integer; const ModuleIndex: Integer - ): Integer; + const URL: String; const Reconnect: Integer; const ModuleIndex: Integer): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleIndex < 0) or (FModuleList.Count = 0) or From 7cce6182aeea498cb51aa12baf9af8ee4be2fb99 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 07:20:05 +0800 Subject: [PATCH 0336/2794] fix load options --- mangadownloader/forms/frmMain.pas | 32 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 36b2dc149..a9f667ddd 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -993,10 +993,11 @@ procedure TMainForm.FormCreate(Sender: TObject); isStartup := False; CollectLanguagesFromFiles; + LoadFormInformation; + LoadMangaOptions; LoadOptions; ApplyOptions; - LoadMangaOptions; - LoadFormInformation; + if cbFilterStatus.Items.Count > 2 then cbFilterStatus.ItemIndex := 2; @@ -4423,21 +4424,18 @@ procedure TMainForm.LoadOptions; GetParams(l, s) //for old config else ExtractStrings([','], [], PChar(s), l); - if l.Count > 0 then + if (l.Count > 0) and (Length(optionMangaSiteSelectionNodes) > 0) then for i := 0 to l.Count - 1 do - begin - if Length(optionMangaSiteSelectionNodes) > 0 then - for j := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + for j := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + begin + data := vtOptionMangaSiteSelection.GetNodeData( + optionMangaSiteSelectionNodes[j]); + if SameText(l[i], data^.Text) then begin - data := vtOptionMangaSiteSelection.GetNodeData( - optionMangaSiteSelectionNodes[j]); - if data^.Text = l.Strings[i] then - begin - optionMangaSiteSelectionNodes[j]^.CheckState := csCheckedNormal; - Break; - end; + optionMangaSiteSelectionNodes[j]^.CheckState := csCheckedNormal; + Break; end; - end; + end; finally l.Free; end; @@ -4754,16 +4752,16 @@ procedure TMainForm.LoadMangaOptions; function TMainForm.SaveMangaOptions: String; var - i: Cardinal; + i: Integer; data: PSingleItem; begin Result := ''; if Length(optionMangaSiteSelectionNodes) > 0 then - for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + for i := Low(optionMangaSiteSelectionNodes) to High(optionMangaSiteSelectionNodes) do begin + data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); if optionMangaSiteSelectionNodes[i]^.CheckState = csCheckedNormal then begin - data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); if Result = '' then Result := data^.Text else From ca08106608ddc6f799086bf44ca0e7870c20950f Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 07:35:31 +0800 Subject: [PATCH 0337/2794] change regex_host --- baseunits/WebsiteModules.pas | 4 +++- baseunits/uBaseUnit.pas | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index e40893706..6bf79a856 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -12,7 +12,6 @@ interface NO_ERROR = 0; NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; - REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; type @@ -124,6 +123,9 @@ function AddModule: TModuleContainer; implementation +const + REGEX_HOST = '(?ig)(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; + {$I ModuleList.inc} { TModuleContainer } diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bdc062fa6..bd51f40cf 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -259,7 +259,7 @@ interface SEPERATOR2 = '~%!'; // common regex to split host/url - REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; + REGEX_HOST = '(?ig)(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; ANIMEA_ID = 0; MANGAHERE_ID = 1; From 6060997388afbbd5c1cbad1cc731757ec238af24 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 07:36:24 +0800 Subject: [PATCH 0338/2794] change regex_host --- baseunits/WebsiteModules.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 6bf79a856..9790fb6a8 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -123,11 +123,11 @@ function AddModule: TModuleContainer; implementation +{$I ModuleList.inc} + const REGEX_HOST = '(?ig)(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; -{$I ModuleList.inc} - { TModuleContainer } procedure TModuleContainer.SetTotalDirectory(AValue: Integer); From cfd10030a9860b4d1e5cae7eba4d7b9e364fdb2b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 08:36:54 +0800 Subject: [PATCH 0339/2794] fix removehostfromurls --- baseunits/WebsiteModules.pas | 2 +- baseunits/uBaseUnit.pas | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 9790fb6a8..5a4fa2bb4 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -126,7 +126,7 @@ implementation {$I ModuleList.inc} const - REGEX_HOST = '(?ig)(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; + REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; { TModuleContainer } diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bd51f40cf..fc0f2913a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -259,7 +259,7 @@ interface SEPERATOR2 = '~%!'; // common regex to split host/url - REGEX_HOST = '(?ig)(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; + REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; ANIMEA_ID = 0; MANGAHERE_ID = 1; @@ -1422,6 +1422,7 @@ function RemoveHostFromURL(URL : String) : String; procedure RemoveHostFromURLs(const URLs : TStringList); var i: Integer; + s: String; begin if URLs = nil then Exit; if URLs.Count > 0 then @@ -1429,7 +1430,14 @@ procedure RemoveHostFromURLs(const URLs : TStringList); try Expression := REGEX_HOST; for i := 0 to URLs.Count - 1 do - URLs[i] := Replace(URLs[i], '$4', True); + begin + s := Replace(URLs[i], '$4', True); + if s = '' then + s := URLs[i]; + if (s <> '') and (s[1] <> '/') then + s := '/' + s; + URLs[i] := s; + end; finally Free; end; @@ -1438,6 +1446,7 @@ procedure RemoveHostFromURLs(const URLs : TStringList); procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); var i: Integer; + s: String; begin if (URLs = nil) or (Names = nil) then Exit; if (URLs.Count <> Names.Count) then Exit; @@ -1448,7 +1457,12 @@ procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); i := 0; while i < URLs.Count do begin - URLs[i] := Replace(URLs[i], '$4', True); + s := Replace(URLs[i], '$4', True); + if s = '' then + s := URLs[i]; + if (s <> '') and (s[1] <> '/') then + s := '/' + s; + URLs[i] := s; if (URLs[i] = '') or (URLs[i] = '/') then begin URLs.Delete(i); From 936a469fa552bfc54c33061483a8730e9cef7112 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 08:49:33 +0800 Subject: [PATCH 0340/2794] fix removehostfromurl --- baseunits/uBaseUnit.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fc0f2913a..8c173eab7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1417,6 +1417,10 @@ function FillHost(const Host, URL: String): String; function RemoveHostFromURL(URL : String) : String; begin Result := ReplaceRegExpr(REGEX_HOST, URL, '$4', True); + if Result = '' then + Result := URL; + if (Result <> '') and (Result[1] <> '/') then + Result := '/' + Result; end; procedure RemoveHostFromURLs(const URLs : TStringList); From 8dc960de307be571505b944c49553b732d4427cc Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 09:39:49 +0800 Subject: [PATCH 0341/2794] thttpsend, add connectiontimeout, incase we need timeout that differ from global timeout --- baseunits/uBaseUnit.pas | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8c173eab7..57a7a41b6 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -802,12 +802,15 @@ TParseHTML = class { THTTPSendThread } THTTPSendThread = class(THTTPSend) - protected + private FOwner: TFMDThread; + procedure SetTimeout(AValue: Integer); + protected procedure CloseConnection(SendTerminateTag: Boolean = True); procedure OnOwnerTerminate(Sender: TObject); public constructor Create(AOwner: TFMDThread); + property Timeout: Integer read FTimeout write SetTimeout; end; // Get current binary version @@ -2770,7 +2773,12 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPClear; end else + begin HTTP := THTTPSend.Create; + HTTP.Timeout := OptionConnectionTimeout; + HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; + HTTP.Sock.SetTimeout(OptionConnectionTimeout); + end; HTTP.Headers.NameValueSeparator := ':'; globReturn: @@ -2813,9 +2821,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; - HTTP.Timeout := OptionConnectionTimeout; - HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; - HTTP.Sock.SetTimeout(OptionConnectionTimeout); //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then @@ -3075,7 +3080,12 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Clear; end else + begin HTTP := THTTPSend.Create; + HTTP.Timeout := OptionConnectionTimeout; + HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; + HTTP.Sock.SetTimeout(OptionConnectionTimeout); + end; HTTP.Headers.NameValueSeparator := ':'; if OptionProxyType = 'HTTP' then @@ -3116,9 +3126,6 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; - HTTP.Timeout := OptionConnectionTimeout; - HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; - HTTP.Sock.SetTimeout(OptionConnectionTimeout); //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then @@ -3514,6 +3521,14 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); { THTTPSendThread } +procedure THTTPSendThread.SetTimeout(AValue: Integer); +begin + if FTimeout = AValue then Exit; + FTimeout := AValue; + Sock.ConnectionTimeout := FTimeout; + Sock.SetTimeout(FTimeout); +end; + procedure THTTPSendThread.CloseConnection(SendTerminateTag: Boolean); begin with Self.Sock do @@ -3533,6 +3548,7 @@ procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); constructor THTTPSendThread.Create(AOwner: TFMDThread); begin inherited Create; + SetTimeout(OptionConnectionTimeout); if Assigned(AOwner) then begin FOwner := AOwner; From b54d9cacdec8af3621fe2b44006c4baa3232c49a Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 09:42:39 +0800 Subject: [PATCH 0342/2794] downloadmanager, remove empty pagelinks if it's come from single page view --- baseunits/uDownloadsManager.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9f7114799..93d42fc7c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -712,6 +712,8 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MADOKAMI_ID then Result := GetMadokamiPageNumber; end; + if manager.container.PageLinks.Count > 0 then + TrimStrings(manager.container.PageLinks); end; function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; From f1db8be7380755bfae579327c7af2697b7572d32 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 09:45:57 +0800 Subject: [PATCH 0343/2794] remove mangacan --- baseunits/uBaseUnit.pas | 99 ++++++++++++++++----------------- baseunits/uData.pas | 10 ---- baseunits/uDownloadsManager.pas | 5 -- 3 files changed, 47 insertions(+), 67 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 57a7a41b6..118a75755 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -310,54 +310,53 @@ interface PURURIN_ID = 46; MANGACOW_ID = 47; KIVMANGA_ID = 48; - MANGACAN_ID = 49; - MEINMANGA_ID = 50; - MANGASPROJECT_ID = 51; - MANGAREADER_POR_ID = 52; - MANGA2U_ID = 53; - MANGASTREAMTO_ID = 54; - NINEMANGA_ID = 55; - NINEMANGA_ES_ID = 56; - NINEMANGA_CN_ID = 57; - NINEMANGA_RU_ID = 58; - NINEMANGA_DE_ID = 59; - NINEMANGA_IT_ID = 60; - NINEMANGA_BR_ID = 61; - JAPANSHIN_ID = 62; - JAPSCAN_ID = 63; - CENTRUMMANGI_PL_ID = 64; - MANGALIB_PL_ID = 65; - ONEMANGA_ID = 66; - MANGATOWN_ID = 67; - READHENTAIMANGA_ID = 68; - MANGAOKU_ID = 69; - MYREADINGMANGAINFO_ID = 70; - IKOMIK_ID = 71; - NHENTAI_ID = 72; - UNIONMANGAS_ID = 73; - MANGAMINT_ID = 74; - UNIXMANGA_ID = 75; - HAKIHOME_ID = 76; - EXTREMEMANGAS_ID = 77; - MANGAHOST_ID = 78; - PORNCOMIX_ID = 79; - PORNCOMIXRE_ID = 80; - PORNCOMIXIC_ID = 81; - XXCOMICS_ID = 82; - XXCOMICSMT_ID = 83; - XXCOMICS3D_ID = 84; - PORNXXXCOMICS_ID = 85; - MANGASEE_ID = 86; - MANGAKU_ID = 87; - ACADEMYVN_ID = 88; - MANGAAT_ID = 89; - SENMANGARAW_ID = 90; - READMANGATODAY_ID = 91; - LONEMANGA_ID = 92; - DYNASTYSCANS_ID = 93; - MADOKAMI_ID = 94; - - WebsiteRoots: array [0..94] of array [0..1] of string = ( + MEINMANGA_ID = 49; + MANGASPROJECT_ID = 50; + MANGAREADER_POR_ID = 51; + MANGA2U_ID = 52; + MANGASTREAMTO_ID = 53; + NINEMANGA_ID = 54; + NINEMANGA_ES_ID = 55; + NINEMANGA_CN_ID = 56; + NINEMANGA_RU_ID = 57; + NINEMANGA_DE_ID = 58; + NINEMANGA_IT_ID = 59; + NINEMANGA_BR_ID = 60; + JAPANSHIN_ID = 61; + JAPSCAN_ID = 62; + CENTRUMMANGI_PL_ID = 63; + MANGALIB_PL_ID = 64; + ONEMANGA_ID = 65; + MANGATOWN_ID = 66; + READHENTAIMANGA_ID = 67; + MANGAOKU_ID = 68; + MYREADINGMANGAINFO_ID = 69; + IKOMIK_ID = 70; + NHENTAI_ID = 71; + UNIONMANGAS_ID = 72; + MANGAMINT_ID = 73; + UNIXMANGA_ID = 74; + HAKIHOME_ID = 75; + EXTREMEMANGAS_ID = 76; + MANGAHOST_ID = 77; + PORNCOMIX_ID = 78; + PORNCOMIXRE_ID = 79; + PORNCOMIXIC_ID = 80; + XXCOMICS_ID = 81; + XXCOMICSMT_ID = 82; + XXCOMICS3D_ID = 83; + PORNXXXCOMICS_ID = 84; + MANGASEE_ID = 85; + MANGAKU_ID = 86; + ACADEMYVN_ID = 87; + MANGAAT_ID = 88; + SENMANGARAW_ID = 89; + READMANGATODAY_ID = 90; + LONEMANGA_ID = 91; + DYNASTYSCANS_ID = 92; + MADOKAMI_ID = 93; + + WebsiteRoots: array [0..93] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -407,7 +406,6 @@ interface ('Pururin', 'http://pururin.com'), ('Mangacow', 'http://mangacow.co'), ('KivManga', 'http://www.kivmanga.com'), - ('Mangacan', 'http://mangacanblog.com'), ('MeinManga', 'http://www.meinmanga.com/'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), @@ -562,8 +560,6 @@ interface KIVMANGA_BROWSER = '/'; - MANGACAN_BROWSER = '/daftar-komik-manga-bahasa-indonesia.html'; - MEINMANGA_BROWSER = '/directory/all/'; MANGASPROJECT_BROWSER = '/AJAX/listaMangas/all'; @@ -1328,7 +1324,6 @@ function SitesWithoutInformation(const website: String): Boolean; TURKCRAFT_ID, HUGEMANGA_ID, KIVMANGA_ID, - MANGACAN_ID, MANGASTREAMTO_ID, MANGAOKU_ID, UNIXMANGA_ID diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9e41d567f..386c74064 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2270,8 +2270,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Kivmanga/names_and_links.inc} - {$I includes/Mangacan/names_and_links.inc} - {$I includes/MeinManga/names_and_links.inc} {$I includes/MangasPROJECT/names_and_links.inc} @@ -2489,9 +2487,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[KIVMANGA_ID, 0] then Result := KivmangaGetNamesAndLinks else - if website = WebsiteRoots[MANGACAN_ID, 0] then - Result := MangacanGetNamesAndLinks - else if website = WebsiteRoots[MANGASPROJECT_ID, 0] then Result := MangasPROJECTGetNamesAndLinks else @@ -2719,8 +2714,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/KivManga/manga_information.inc} - {$I includes/Mangacan/manga_information.inc} - {$I includes/MangasPROJECT/manga_information.inc} {$I includes/MangaREADER_POR/manga_information.inc} @@ -2947,9 +2940,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[KIVMANGA_ID, 0] then Result := GetKivmangaInfoFromURL else - if website = WebsiteRoots[MANGACAN_ID, 0] then - Result := GetMangacanInfoFromURL - else if website = WebsiteRoots[MANGASPROJECT_ID, 0] then Result := GetMangasPROJECTInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 93d42fc7c..4b580736b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -754,8 +754,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaAr/image_url.inc} - {$I includes/Mangacan/image_url.inc} - {$I includes/Mangacow/image_url.inc} {$I includes/MangaEden/image_url.inc} @@ -980,9 +978,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaImageURL else - if manager.container.MangaSiteID = MANGACAN_ID then - Result := GetMangacanImageURL - else if manager.container.MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTImageURL else From fa43065f4ae468072d0ab3868f86dd16d055999c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 09:46:44 +0800 Subject: [PATCH 0344/2794] add mangacan module #83 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Mangacan.pas | 205 +++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Mangacan.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index c268b6dc9..7f8d2b809 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -3,4 +3,5 @@ uses mh160com, Batoto, WPManga, - MangaFox; + MangaFox, + Mangacan; diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas new file mode 100644 index 000000000..4edcd4a03 --- /dev/null +++ b/baseunits/modules/Mangacan.pas @@ -0,0 +1,205 @@ +unit Mangacan; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, synautil; + +implementation + +const + dirURL = '/daftar-komik-manga-bahasa-indonesia.html'; + +function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; + var Page: Integer; {%H-}Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := 1; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const {%H-}URL: String; + Module: TModuleContainer): Integer; +var + Parse: TStringList; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'a') and (Pos('baca-komik-', Parse[i]) <> 0) then + begin + Links.Add(GetVal(Parse[i], 'href')); + Names.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Parse: TStringList; + info: TMangaInfo; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + s: String = ''; + begin + for i := StartIndex to Parse.Count - 1 do + begin + if GetTagName(Parse[i]) = '/table' then + Break + else + if GetTagName(parse[i]) = 'a' then + begin + s := GetVal(Parse[i], 'href'); + if (Length(s) > 7) and (RightStr(s, 7) = '-1.html') then + s := SeparateLeft(s, '-1.html') + '.html'; + info.chapterLinks.Add(s); + info.chapterName.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + + //invert chapters + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); + end; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + begin + //title + if info.title = '' then + if Pos(' Indonesia|Baca ', Parse[i]) <> 0 then + info.title := CommonStringFilter(SeparateLeft(Parse[i], ' Indonesia|Baca ')); + + //chapters + if (GetTagName(Parse[i]) = 'table') and + (GetVal(Parse[i], 'class') = 'updates') then + begin + ScanChapters(i); + Break; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i: Integer; + s: String; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'img') and + (GetVal(Parse[i], 'class') = 'picture') then + begin + s := GetVal(Parse[i], 'src'); + if (Length(s) > 4) and (not SameText(LeftStr(s, 4), 'http')) then + begin + if s[1] <> '/' then + s := '/' + s; + s := FillHost(Module.RootURL, s); + end; + Container.PageLinks.Add(s); + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + FillHost(Module.RootURL, URL), + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Mangacan'; + RootURL := 'http://mangacanblog.com'; + SortedList := False; + InformationAvailable := False; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From 6179fc0d11ff79fd22698499e8cee0cfb0ead8e2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 10:17:06 +0800 Subject: [PATCH 0345/2794] remove mangacan --- baseunits/includes/Mangacan/image_url.inc | 33 ----- .../includes/Mangacan/manga_information.inc | 133 ------------------ .../includes/Mangacan/names_and_links.inc | 40 ------ 3 files changed, 206 deletions(-) delete mode 100644 baseunits/includes/Mangacan/image_url.inc delete mode 100644 baseunits/includes/Mangacan/manga_information.inc delete mode 100644 baseunits/includes/Mangacan/names_and_links.inc diff --git a/baseunits/includes/Mangacan/image_url.inc b/baseunits/includes/Mangacan/image_url.inc deleted file mode 100644 index d7492ca5c..000000000 --- a/baseunits/includes/Mangacan/image_url.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangacanImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGACAN_ID, '/' + StringReplace(URL, '-1.html', '.html', [])); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - if (Pos(', parse.Strings[i]) > 0) then
-        begin
-          s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 0) then //asli class="lng - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse.Strings[i], 'href="', '"'), - WebsiteRoots[MANGACAN_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); //ASLI 5 - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('seemore', parse.Strings[i]) > 0) then - isExtractChapter := False; //bermasalah - - // get summary - if (Pos('
', parse.Strings[i]) <> 0) then - begin - j := i + 2; - while (j < parse.Count) and (Pos('', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter( - StringFilter(TrimLeft(parse.Strings[j]))); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - Break; - end; - Inc(j); - end; - end; - - // get authors - if (Pos('Author', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(StringFilter(parse.Strings[i + 2])); - - // get artists - if (Pos('Artist', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(StringFilter(parse.Strings[i + 2])); - - // get genres - if (Pos('Category', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('manga-list/category/', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('

', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Mangacan/names_and_links.inc b/baseunits/includes/Mangacan/names_and_links.inc deleted file mode 100644 index 99cd08cb6..000000000 --- a/baseunits/includes/Mangacan/names_and_links.inc +++ /dev/null @@ -1,40 +0,0 @@ - function MangacanGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGACAN_ID, 1] + - MANGACAN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'a') and - (Pos('baca-komik-', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 1]); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[MANGACAN_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file From a7ff8aa5601af7e75d6906560d6ec95928d407a9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 12:36:14 +0800 Subject: [PATCH 0346/2794] baseunit, fix redirection and clean up code --- baseunits/uBaseUnit.pas | 82 +++++++++++------------------------------ 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 118a75755..2984a061a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2713,7 +2713,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; //i: Cardinal; HTTP: THTTPSend; HTTPHeader: TStringList; - counter, counter2: Integer; + counter: Integer; s: String; meth: String = 'GET'; //zstream: TGZFileStream; @@ -2741,7 +2741,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; function checkTerminate: Boolean; begin - Result := HTTP.Sock.Tag = 1; //terminated via OnHeartBeat + Result := HTTP.Sock.Tag = 1; //terminate via THTTPSendThread; if Result then begin HTTP.Sock.Tag := 0; @@ -2887,11 +2887,10 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.RangeEnd := 0; end; - counter := 0; + if checkTerminate then Exit; HTTP.Headers.Text := HTTPHeader.Text; - while (not HTTP.HTTPMethod(meth, URL)) or - (HTTP.ResultCode >= 500) or - (HTTP.ResultCode = 451) do + counter := 0; + while (not HTTP.HTTPMethod(meth, URL)) or (HTTP.ResultCode > 500) do begin if checkTerminate then Exit; if (Reconnect > -1) and (Reconnect <= counter) then @@ -2904,16 +2903,9 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Headers.Text := HTTPHeader.Text; end; - counter := 0; while (HTTP.ResultCode > 300) and (HTTP.ResultCode < 400) do begin if checkTerminate then Exit; - if (Reconnect > -1) and (Reconnect <= counter) then - begin - preTerminate; - Exit; - end; - Inc(counter); HTTPHeader.Values['Referer'] := ' ' + URL; s := Trim(HTTP.Headers.Values['Location']); if s <> '' then @@ -2937,19 +2929,18 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; if Pos(HENTAI2READ_ROOT, URL) <> 0 then HTTP.Headers.Insert(0, 'Referer:' + HENTAI2READ_ROOT + '/'); - counter2 := 0; HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; - while (not HTTP.HTTPMethod('GET', URL)) or - (HTTP.ResultCode > 500) do //500 for abort + counter := 0; + while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) do begin if checkTerminate then Exit; - if (Reconnect > -1) and (Reconnect <= counter2) then + if (Reconnect > -1) and (Reconnect <= counter) then begin preTerminate; Exit; end; - Inc(counter2); + Inc(counter); HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; end; @@ -2981,10 +2972,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Document.SaveToStream(TStream(output)); except on E: Exception do - begin - E.Message := 'GetPage.WriteOutput error: '#13#10 + E.Message; - USimpleException.ExceptionHandleSaveLogOnly(nil, E); - end; + WriteLog_E('GetPage.WriteOutput.Error!', E); end; Result := True; end @@ -3028,7 +3016,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; ext, lpath, fpath: String; HTTPHeader: TStringList; HTTP: THTTPSend; - counter, counter2: Integer; + counter: Integer; s: String; //source : TPicture; fstream: TFileStreamUTF8; @@ -3042,7 +3030,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; function checkTerminate: Boolean; begin - Result := HTTP.Sock.Tag = 1; //terminated via OnHeartBeat + Result := HTTP.Sock.Tag = 1; //terminate via THTTPSendThread if Result then begin HTTP.Sock.Tag := 0; @@ -3158,18 +3146,12 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.RangeStart := 0; HTTP.RangeEnd := 0; - {$IFDEF DOWNLOADER} if checkTerminate then Exit; - {$ENDIF} - counter := 0; HTTP.Headers.Text := HTTPHeader.Text; - while (not HTTP.HTTPMethod('GET', URL)) or - (HTTP.ResultCode >= 500) or //500 for abort - (HTTP.ResultCode = 403) do + counter := 0; + while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) do begin - {$IFDEF DOWNLOADER} if checkTerminate then Exit; - {$ENDIF} if (Reconnect > -1) and (Reconnect <= counter) then begin preTerminate; @@ -3180,18 +3162,9 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Headers.Text := HTTPHeader.Text; end; - counter := 0; while (HTTP.ResultCode > 300) and (HTTP.ResultCode < 400) do begin - {$IFDEF DOWNLOADER} if checkTerminate then Exit; - {$ENDIF} - if (Reconnect > -1) and (Reconnect <= counter) then - begin - preTerminate; - Exit; - end; - Inc(counter); HTTPHeader.Values['Referer'] := ' ' + URL; s := Trim(HTTP.Headers.Values['Location']); if s <> '' then @@ -3213,24 +3186,19 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; HTTP.Clear; - counter2 := 0; HTTP.Headers.Text := HTTPHeader.Text; - while (not HTTP.HTTPMethod('GET', URL)) or - (HTTP.ResultCode > 500) or //500 for abort - (HTTP.ResultCode = 403) do + counter := 0; + while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) do begin - {$IFDEF DOWNLOADER} if checkTerminate then Exit; - {$ENDIF} - if (Reconnect > -1) and (Reconnect <= counter2) then + if (Reconnect > -1) and (Reconnect <= counter) then begin preTerminate; Exit; end; - Inc(counter2); + Inc(counter); HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; - Sleep(500); end; end; HTTP.Document.Seek(0, soBeginning); @@ -3257,9 +3225,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; // If the error still persists, break the loop. repeat try - {$IFDEF DOWNLOADER} if checkTerminate then Exit; - {$ENDIF} lpath := CleanAndExpandDirectory(CorrectPathSys(Path)); if not DirectoryExistsUTF8(lpath) then ForceDirectoriesUTF8(lpath); @@ -3282,12 +3248,9 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; except on E: Exception do begin - E.Message := 'SaveImage.SavetoFile.Error'#13#10 + E.Message + #13#10 + - (CorrectPathSys(Path) + '/' + Name + prefix + ext); - USimpleException.ExceptionHandleSaveLogOnly(nil, E); - {$IFDEF DOWNLOADER} + WriteLog_E('SaveImage.SavetoFile.Error!'+ LineEnding + + CorrectPathSys(Path) + '/' + Name + prefix + ext, E); if checkTerminate then Exit; - {$ENDIF} if not retryToSave then begin CheckPath(Path); @@ -3300,10 +3263,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; until False; end else - begin - s := 'SaveImage.ExtEmpty'#13#10'URL: ' + URL; - USimpleException.ExceptionHandleSaveLogOnly(nil, Exception.Create(s)); - end; + Writelog_E('SaveImage.ExtEmpty!' + LineEnding + URL); preTerminate; Result := (fpath <> '') and FileExistsUTF8(fpath); end; From 3758ab9694528ed40e4f7d6816c04f63516e0ad5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 12:37:37 +0800 Subject: [PATCH 0347/2794] minor changes to modules --- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/modules/MangaFox.pas | 2 +- baseunits/modules/Mangacan.pas | 2 +- baseunits/modules/mh160com.pas | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 2813625a3..2ddd8c331 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -170,7 +170,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.url := FillHost(Module.RootURL, URL); Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then begin Result := INFORMATION_NOT_FOUND; ParseHTML(Parse.Text, Parse); diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 480106045..3358e08f5 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -186,7 +186,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.url := FillHost(Module.RootURL, URL); Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then begin Result := INFORMATION_NOT_FOUND; ParseHTML(Parse.Text, Parse); diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index 4edcd4a03..aae626969 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -118,7 +118,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.url := FillHost(Module.RootURL, URL); Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then begin Result := INFORMATION_NOT_FOUND; ParseHTML(Parse.Text, Parse); diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas index 4608e6e12..63d04e96f 100644 --- a/baseunits/modules/mh160com.pas +++ b/baseunits/modules/mh160com.pas @@ -142,7 +142,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.url := FillHost(Module.RootURL, URL); Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then begin Result := INFORMATION_NOT_FOUND; ParseHTML(CP936ToUTF8(Parse.Text), Parse); From 6cf1baf1916e9542ec8f181c6350cc7db83980e1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 12:39:00 +0800 Subject: [PATCH 0348/2794] add appendurldelimleft function --- baseunits/uBaseUnit.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2984a061a..d7ee27a1d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -877,6 +877,7 @@ function CorrectPathSys(const Path: String): String; function CleanAndExpandURL(const URL: String): String; function CleanURL(const URL: String): String; function AppendURLDelim(const URL: String): String; +function AppendURLDelimLeft(const URL: String): String; function FixURL(const URL: String): String; function FixPath(const path: String): String; function GetLastDir(const path: String): String; @@ -2273,6 +2274,13 @@ function AppendURLDelim(const URL: String): String; Result := URL + '/'; end; +function AppendURLDelimLeft(const URL: String): String; +begin + Result := URL; + if (URL <> '') and (URL[1] <> '/') then + Result := '/' + URL; +end; + function FixURL(const URL : String) : String; begin Result := URL; From 29afb201f3b2e6487a4a150f6385cb7344065d11 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 12:48:02 +0800 Subject: [PATCH 0349/2794] baseunit, fix fillhost --- baseunits/uBaseUnit.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d7ee27a1d..c802e583d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1403,8 +1403,10 @@ function FillHost(const Host, URL: String): String; with TRegExpr.Create do try Expression := REGEX_HOST; - th := Replace(Host, '$1$2', True); + th := Replace(Host, '$1$2$3', True); tu := Replace(URL, '$4', True); + if tu = '' then + tu := URL; if (tu <> '') and (tu[1] <> '/') then tu := '/' + tu; Result := th + tu; From efd354e2215b4967eb2eba339e1e876e909fda43 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 13:30:55 +0800 Subject: [PATCH 0350/2794] baseunit, add maybefillhost function --- baseunits/uBaseUnit.pas | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c802e583d..bd4675b6c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -840,6 +840,7 @@ function SitesWithSingleChapter(const website: String): Boolean; function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; function FillMangaSiteHost(const Website, URL: String): String; overload; function FillHost(const Host, URL: String): String; +function MaybeFillHost(const Host, URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(Const URLs: TStringList); procedure RemoveHostFromURLsPair(Const URLs, Names : TStringList); @@ -1415,6 +1416,30 @@ function FillHost(const Host, URL: String): String; end; end; +function MaybeFillHost(const Host, URL: String): String; +var + th, tu: string; +begin + Result := URL; + if Host = '' then Exit; + with TRegExpr.Create do + try + Expression := REGEX_HOST; + if Replace(URL, '$1', True) = '' then + begin + th := Replace(Host, '$1$2$3', True); + tu := Replace(URL, '$4', True); + if tu = '' then + tu := URL; + if (tu <> '') and (tu[1] <> '/') then + tu := '/' + tu; + Result := th + tu; + end; + finally + Free; + end; +end; + function RemoveHostFromURL(URL : String) : String; begin Result := ReplaceRegExpr(REGEX_HOST, URL, '$4', True); From 070d9ad5288a612710ebd1777feec17d0bdeeed5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 13:34:49 +0800 Subject: [PATCH 0351/2794] mangacan, minor changes --- baseunits/modules/Mangacan.pas | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index aae626969..eb7fbd6d4 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -142,21 +142,11 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; procedure ScanParse; var i: Integer; - s: String; begin for i := 0 to Parse.Count - 1 do if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'picture') then - begin - s := GetVal(Parse[i], 'src'); - if (Length(s) > 4) and (not SameText(LeftStr(s, 4), 'http')) then - begin - if s[1] <> '/' then - s := '/' + s; - s := FillHost(Module.RootURL, s); - end; - Container.PageLinks.Add(s); - end; + Container.PageLinks.Add(MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src'))); end; begin From 35a66a1fb197f38a6f14c169919c3237094604de Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 13:38:24 +0800 Subject: [PATCH 0352/2794] remove pecinta.komik --- .../PecintaKomik/chapter_page_number.inc | 33 ----- baseunits/includes/PecintaKomik/image_url.inc | 35 ----- .../PecintaKomik/manga_information.inc | 132 ----------------- .../includes/PecintaKomik/names_and_links.inc | 50 ------- baseunits/uBaseUnit.pas | 135 +++++++++--------- baseunits/uData.pas | 12 -- baseunits/uDownloadsManager.pas | 11 -- 7 files changed, 65 insertions(+), 343 deletions(-) delete mode 100644 baseunits/includes/PecintaKomik/chapter_page_number.inc delete mode 100644 baseunits/includes/PecintaKomik/image_url.inc delete mode 100644 baseunits/includes/PecintaKomik/manga_information.inc delete mode 100644 baseunits/includes/PecintaKomik/names_and_links.inc diff --git a/baseunits/includes/PecintaKomik/chapter_page_number.inc b/baseunits/includes/PecintaKomik/chapter_page_number.inc deleted file mode 100644 index 35c134750..000000000 --- a/baseunits/includes/PecintaKomik/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetPecintaKomikPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(PECINTAKOMIK_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 1]; - manager.container.pageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/PecintaKomik/image_url.inc b/baseunits/includes/PecintaKomik/image_url.inc deleted file mode 100644 index ee222d0d5..000000000 --- a/baseunits/includes/PecintaKomik/image_url.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetPecintaKomikImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(PECINTAKOMIK_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('mangas/', parse.Strings[i]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - if Pos('/manga/', s) = 0 then - s := WebsiteRoots[PECINTAKOMIK_ID, 1] + '/manga/' + s - else - s := WebsiteRoots[PECINTAKOMIK_ID, 1] + PECINTAKOMIK_BROWSER + s; - manager.container.PageLinks.Strings[workCounter] := EncodeURL(s); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/PecintaKomik/manga_information.inc b/baseunits/includes/PecintaKomik/manga_information.inc deleted file mode 100644 index da5626be9..000000000 --- a/baseunits/includes/PecintaKomik/manga_information.inc +++ /dev/null @@ -1,132 +0,0 @@ - function GetPecintaKomikInfoFromURL: Byte; - var - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - s: String; - i, j: Cardinal; - k: Integer; - begin - mangaInfo.url := FillMangaSiteHost(PECINTAKOMIK_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[PECINTAKOMIK_ID, 0]; - mangaInfo.status := '1'; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - if Pos('/manga/', URL) = 0 then - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('id="mangaimg"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := WebsiteRoots[PECINTAKOMIK_ID, 1] + - CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'src='))); - - // get summary - if (Pos('Himbauan:', parse.Strings[i]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get title - if (Pos('Nama:', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := StringFilter(TrimRight(TrimLeft(parse.Strings[i + 6]))); - - // get chapter name and links - if (not isExtractChapter) and - (Pos('id="chapterlist"', parse.Strings[i]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('/manga/', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse.Strings[i], 'href="', '"'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Autor:', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimRight(TrimLeft(parse.Strings[i + 4])); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist:', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimRight(TrimLeft(parse.Strings[i + 4])); - - // get genres - if (Pos('Genre:', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('class="genretags"', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - end - else - for i := 0 to parse.Count - 1 do - begin - if Pos('name="chapter"', parse.Strings[i]) > 0 then - begin - if TryStrToInt(TrimRight(TrimLeft(parse.Strings[i + 2])), k) then - for j := k downto 1 do - begin - Inc(mangaInfo.numChapter); - s := URL + IntToStr(j); - mangaInfo.chapterLinks.Add(s); - s := 'Chapter ' + IntToStr(j); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - Break; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/PecintaKomik/names_and_links.inc b/baseunits/includes/PecintaKomik/names_and_links.inc deleted file mode 100644 index 006b63ccc..000000000 --- a/baseunits/includes/PecintaKomik/names_and_links.inc +++ /dev/null @@ -1,50 +0,0 @@ - function PecintaKomikGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[PECINTAKOMIK_ID, 1] + - PECINTAKOMIK_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class=''screenshot''', parse.Strings[i]) > 0) or - (Pos('class="screenshot"', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'title='))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - if s[Length(s)] <> '/' then - s := s + '/'; - links.Add(s); - end; - if (Pos('/manga/', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - if s[Length(s)] <> '/' then - s := s + '/'; - links.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bd4675b6c..f7acd4900 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -291,72 +291,71 @@ interface SUBMANGA_ID = 27; ESMANGAHERE_ID = 28; ANIMEEXTREMIST_ID = 29; - PECINTAKOMIK_ID = 30; - HUGEMANGA_ID = 31; - S2SCAN_ID = 32; - SENMANGA_ID = 33; - IMANHUA_ID = 34; - MABUNS_ID = 35; - MANGAESTA_ID = 36; - CENTRALDEMANGAS_ID = 37; - EGSCANS_ID = 38; - MANGAAR_ID = 39; - MANGAAE_ID = 40; - ANIMESTORY_ID = 41; - LECTUREENLIGNE_ID = 42; - SCANMANGA_ID = 43; - MANGAGO_ID = 44; - DM5_ID = 45; - PURURIN_ID = 46; - MANGACOW_ID = 47; - KIVMANGA_ID = 48; - MEINMANGA_ID = 49; - MANGASPROJECT_ID = 50; - MANGAREADER_POR_ID = 51; - MANGA2U_ID = 52; - MANGASTREAMTO_ID = 53; - NINEMANGA_ID = 54; - NINEMANGA_ES_ID = 55; - NINEMANGA_CN_ID = 56; - NINEMANGA_RU_ID = 57; - NINEMANGA_DE_ID = 58; - NINEMANGA_IT_ID = 59; - NINEMANGA_BR_ID = 60; - JAPANSHIN_ID = 61; - JAPSCAN_ID = 62; - CENTRUMMANGI_PL_ID = 63; - MANGALIB_PL_ID = 64; - ONEMANGA_ID = 65; - MANGATOWN_ID = 66; - READHENTAIMANGA_ID = 67; - MANGAOKU_ID = 68; - MYREADINGMANGAINFO_ID = 69; - IKOMIK_ID = 70; - NHENTAI_ID = 71; - UNIONMANGAS_ID = 72; - MANGAMINT_ID = 73; - UNIXMANGA_ID = 74; - HAKIHOME_ID = 75; - EXTREMEMANGAS_ID = 76; - MANGAHOST_ID = 77; - PORNCOMIX_ID = 78; - PORNCOMIXRE_ID = 79; - PORNCOMIXIC_ID = 80; - XXCOMICS_ID = 81; - XXCOMICSMT_ID = 82; - XXCOMICS3D_ID = 83; - PORNXXXCOMICS_ID = 84; - MANGASEE_ID = 85; - MANGAKU_ID = 86; - ACADEMYVN_ID = 87; - MANGAAT_ID = 88; - SENMANGARAW_ID = 89; - READMANGATODAY_ID = 90; - LONEMANGA_ID = 91; - DYNASTYSCANS_ID = 92; - MADOKAMI_ID = 93; - - WebsiteRoots: array [0..93] of array [0..1] of string = ( + HUGEMANGA_ID = 30; + S2SCAN_ID = 31; + SENMANGA_ID = 32; + IMANHUA_ID = 33; + MABUNS_ID = 34; + MANGAESTA_ID = 35; + CENTRALDEMANGAS_ID = 36; + EGSCANS_ID = 37; + MANGAAR_ID = 38; + MANGAAE_ID = 39; + ANIMESTORY_ID = 40; + LECTUREENLIGNE_ID = 41; + SCANMANGA_ID = 42; + MANGAGO_ID = 43; + DM5_ID = 44; + PURURIN_ID = 45; + MANGACOW_ID = 46; + KIVMANGA_ID = 47; + MEINMANGA_ID = 48; + MANGASPROJECT_ID = 49; + MANGAREADER_POR_ID = 50; + MANGA2U_ID = 51; + MANGASTREAMTO_ID = 52; + NINEMANGA_ID = 53; + NINEMANGA_ES_ID = 54; + NINEMANGA_CN_ID = 55; + NINEMANGA_RU_ID = 56; + NINEMANGA_DE_ID = 57; + NINEMANGA_IT_ID = 58; + NINEMANGA_BR_ID = 59; + JAPANSHIN_ID = 60; + JAPSCAN_ID = 61; + CENTRUMMANGI_PL_ID = 62; + MANGALIB_PL_ID = 63; + ONEMANGA_ID = 64; + MANGATOWN_ID = 65; + READHENTAIMANGA_ID = 66; + MANGAOKU_ID = 67; + MYREADINGMANGAINFO_ID = 68; + IKOMIK_ID = 69; + NHENTAI_ID = 70; + UNIONMANGAS_ID = 71; + MANGAMINT_ID = 72; + UNIXMANGA_ID = 73; + HAKIHOME_ID = 74; + EXTREMEMANGAS_ID = 75; + MANGAHOST_ID = 76; + PORNCOMIX_ID = 77; + PORNCOMIXRE_ID = 78; + PORNCOMIXIC_ID = 79; + XXCOMICS_ID = 80; + XXCOMICSMT_ID = 81; + XXCOMICS3D_ID = 82; + PORNXXXCOMICS_ID = 83; + MANGASEE_ID = 84; + MANGAKU_ID = 85; + ACADEMYVN_ID = 86; + MANGAAT_ID = 87; + SENMANGARAW_ID = 88; + READMANGATODAY_ID = 89; + LONEMANGA_ID = 90; + DYNASTYSCANS_ID = 91; + MADOKAMI_ID = 92; + + WebsiteRoots: array [0..92] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -387,7 +386,6 @@ interface ('SubManga', 'http://submanga.com'), ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), - ('PecintaKomik', 'http://www.pecintakomik.com'), ('HugeManga', 'http://hugemanga.com'), ('S2Scans', 'http://reader.s2smanga.com'), ('SenManga', 'http://www.senmanga.com'), @@ -523,8 +521,6 @@ interface ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; - PECINTAKOMIK_BROWSER = '/directory/'; - HUGEMANGA_BROWSER = '/'; SENMANGA_BROWSER = '/Manga/'; @@ -1345,7 +1341,6 @@ function SitesWithoutReferer(const website : String) : Boolean; Result := False; Result:= SitesMemberOf(website, [ MEINMANGA_ID, - PECINTAKOMIK_ID, IKOMIK_ID, PORNCOMIX_ID, XXCOMICS_ID, diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 386c74064..5fd67526c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2214,8 +2214,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Komikid/names_and_links.inc} - {$I includes/PecintaKomik/names_and_links.inc} - {$I includes/Mabuns/names_and_links.inc} {$I includes/MangaEsta/names_and_links.inc} @@ -2433,9 +2431,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[KOMIKID_ID, 0] then Result := KomikidGetNamesAndLinks else - if website = WebsiteRoots[PECINTAKOMIK_ID, 0] then - Result := PecintaKomikGetNamesAndLinks - else if website = WebsiteRoots[MABUNS_ID, 0] then Result := MabunsGetNamesAndLinks else @@ -2672,10 +2667,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/Komikid/manga_information.inc} - // this site have 2 kind of cover page - - {$I includes/PecintaKomik/manga_information.inc} - {$I includes/Mabuns/manga_information.inc} {$I includes/MangaEsta/manga_information.inc} @@ -2886,9 +2877,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[KOMIKID_ID, 0] then Result := GetKomikidInfoFromURL else - if website = WebsiteRoots[PECINTAKOMIK_ID, 0] then - Result := GetPecintaKomikInfoFromURL - else if website = WebsiteRoots[MABUNS_ID, 0] then Result := GetMabunsInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4b580736b..87b38c7e4 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -423,8 +423,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MeinManga/chapter_page_number.inc} - {$I includes/PecintaKomik/chapter_page_number.inc} - {$I includes/Pururin/chapter_page_number.inc} {$I includes/RedHawkScans/chapter_page_number.inc} @@ -564,9 +562,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = KOMIKID_ID then Result := GetKomikidPageNumber else - if manager.container.MangaSiteID = PECINTAKOMIK_ID then - Result := GetPecintaKomikPageNumber - else if manager.container.MangaSiteID = PURURIN_ID then Result := GetPururinPageNumber else @@ -786,8 +781,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaVadisi/image_url.inc} - {$I includes/PecintaKomik/image_url.inc} - {$I includes/Pururin/image_url.inc} {$I includes/RedHawkScans/image_url.inc} @@ -920,9 +913,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = KOMIKID_ID then Result := GetKomikidImageURL else - if manager.container.MangaSiteID = PECINTAKOMIK_ID then - Result := GetPecintaKomikImageURL - else if manager.container.MangaSiteID = MABUNS_ID then Result := GetMabunsImageURL else @@ -1294,7 +1284,6 @@ procedure TTaskThread.CheckOut; else begin case container.MangaSiteID of - PECINTAKOMIK_ID : currentMaxThread := 1; EHENTAI_ID : currentMaxThread := 2; else currentMaxThread := container.Manager.maxDLThreadsPerTask; From b28149e89084432ef42592cb12c50a1770c145e3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 13:43:40 +0800 Subject: [PATCH 0353/2794] add pecintakomik module closes #83 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/PecintaKomik.pas | 320 +++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/PecintaKomik.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 7f8d2b809..c8a329a7a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -4,4 +4,5 @@ uses Batoto, WPManga, MangaFox, - Mangacan; + Mangacan, + PecintaKomik; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas new file mode 100644 index 000000000..53b32b139 --- /dev/null +++ b/baseunits/modules/PecintaKomik.pas @@ -0,0 +1,320 @@ +unit PecintaKomik; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, synautil; + +implementation + +const + dirURL = '/directory/'; + +function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; + var Page: Integer; {%H-}Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := 1; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const {%H-}URL: String; + Module: TModuleContainer): Integer; +var + Parse: TStringList; + + procedure ScanParse; + var + i, j: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'section') and + (GetVal(Parse[i], 'class') = 'cols') then + begin + for j := i + 1 to Parse.Count - 1 do + if GetTagName(Parse[j]) = '/section' then + Break + else + if (GetTagName(Parse[j]) = 'a') and + (GetVal(Parse[j], 'class') = 'screenshot') then + begin + Links.Add(AppendURLDelim(GetVal(Parse[j], 'href'))); + Names.Add(CommonStringFilter(Parse[j + 1])); + end; + Break; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Parse: TStringList; + info: TMangaInfo; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + begin + for i := StartIndex to Parse.Count - 1 do + begin + if GetTagName(Parse[i]) = '/div' then + Break + else + if GetTagName(parse[i]) = 'a' then + begin + info.chapterLinks.Add(AppendURLDelim(GetVal(Parse[i], 'href'))); + info.chapterName.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + + //invert chapters + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); + end; + + procedure ScanParse; + var + i, j: Integer; + begin + if Pos('/manga/', URL) = 0 then + begin + for i := 0 to Parse.Count - 1 do + begin + //cover + if info.coverLink = '' then + if (GetTagName(Parse[i]) = 'img') and + (GetVal(Parse[i], 'class') = 'pecintakomik') then + info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); + + //title + if info.title = '' then + if GetVal(Parse[i], 'class') = 'post-cnt' then + if GetTagName(Parse[i + 2]) = 'h2' then + info.title := CommonStringFilter(Parse[i + 3]); + + if GetTagName(Parse[i]) = 'li' then + begin + //authors + if Pos('Author(s):', Parse[i + 1]) = 1 then + info.authors := CommonStringFilter(SeparateRight(Parse[i + 1], + 'Author(s):')); + //artist + if Pos('Artist(s):', Parse[i + 1]) = 1 then + info.artists := CommonStringFilter(SeparateRight(Parse[i + 1], + 'Artist(s):')); + //genres + if Pos('Genre:', Parse[i + 1]) = 1 then + info.genres := CommonStringFilter(SeparateRight(Parse[i + 1], 'Genre:')); + //summary + if Pos('Sinopsis:', Parse[i + 1]) = 1 then + info.summary := CommonStringFilter(SeparateRight(Parse[i + 1], 'Sinopsis:')); + end; + + // chapters + if Parse[i] = 'List Chapter(s)' then + begin + ScanChapters(i); + Break; + end; + end; + end + else + //no info + for i := 0 to Parse.Count - 1 do + begin + //title + if info.title = '' then + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'name') = 'manga') then + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if (GetTagName(Parse[j]) = 'option') and + (GetVal(Parse[j], 'selected') = 'selected') then + begin + info.title := CommonStringFilter(Parse[j + 1]); + Break; + end; + end; + //chapters + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'name') = 'chapter') then + begin + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if GetTagName(Parse[j]) = 'option' then + begin + Inc(info.numChapter); + info.chapterLinks.Add(AppendURLDelim(URL) + IntToStr(info.numChapter)); + info.chapterName.Add('Chapter ' + IntToStr(info.numChapter)); + end; + end; + Break; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i, j: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'name') = 'page') then + begin + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if GetTagName(Parse[j]) = 'option' then + Inc(Container.PageNumber); + end; + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + FillHost(Module.RootURL, URL), + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'picture') then + begin + if DownloadThread.workCounter < Container.PageLinks.Count then + Container.PageLinks[DownloadThread.workCounter] := + MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + AppendURLDelim(FillHost(Module.RootURL, URL)) + IncStr(DownloadThread.workCounter), + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'PecintaKomik'; + RootURL := 'http://www.pecintakomik.com'; + SortedList := False; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From a3d1917f4709189eb1ffee77014fc1adf60a5b19 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 23:18:34 +0800 Subject: [PATCH 0354/2794] baseunit, some clean up --- baseunits/uBaseUnit.pas | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f7acd4900..6a570666d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1403,9 +1403,7 @@ function FillHost(const Host, URL: String): String; tu := Replace(URL, '$4', True); if tu = '' then tu := URL; - if (tu <> '') and (tu[1] <> '/') then - tu := '/' + tu; - Result := th + tu; + Result := th + AppendURLDelimLeft(tu); finally Free; end; @@ -1426,9 +1424,7 @@ function MaybeFillHost(const Host, URL: String): String; tu := Replace(URL, '$4', True); if tu = '' then tu := URL; - if (tu <> '') and (tu[1] <> '/') then - tu := '/' + tu; - Result := th + tu; + Result := th + AppendURLDelimLeft(tu); end; finally Free; From 99167ebb150d96903b6ab5aab915e5cf43584352 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 1 Aug 2015 23:51:55 +0800 Subject: [PATCH 0355/2794] pencinta.komik, add another layout variant and some clean up --- baseunits/modules/PecintaKomik.pas | 126 +++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 33 deletions(-) diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 53b32b139..f13ccc57d 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -77,13 +77,15 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; procedure ScanChapters(const StartIndex: Integer); var i: Integer; + s: String; begin - for i := StartIndex to Parse.Count - 1 do + for i := StartIndex + 1 to Parse.Count - 1 do begin - if GetTagName(Parse[i]) = '/div' then + s := GetTagName(Parse[i]); + if s = '/div' then Break else - if GetTagName(parse[i]) = 'a' then + if s = 'a' then begin info.chapterLinks.Add(AppendURLDelim(GetVal(Parse[i], 'href'))); info.chapterName.Add(CommonStringFilter(Parse[i + 1])); @@ -95,6 +97,72 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; InvertStrings([info.chapterLinks, info.chapterName]); end; + procedure ScanInfo(const StartIndex: Integer); + var + i: Integer; + s: String; + begin + for i := StartIndex + 1 to Parse.Count - 1 do + begin + s := GetTagName(Parse[i]); + if s = '/div' then + Break + else + if s = 'li' then + begin + //authors + if Pos('Author(s):', Parse[i + 1]) = 1 then + info.authors := CommonStringFilter(SeparateRight(Parse[i + 1], + 'Author(s):')) + else + //artist + if Pos('Artist(s):', Parse[i + 1]) = 1 then + info.artists := CommonStringFilter(SeparateRight(Parse[i + 1], + 'Artist(s):')) + else + //genres + if Pos('Genre:', Parse[i + 1]) = 1 then + info.genres := CommonStringFilter(SeparateRight(Parse[i + 1], 'Genre:')) + else + //summary + if Pos('Sinopsis:', Parse[i + 1]) = 1 then + info.summary := CommonStringFilter(SeparateRight(Parse[i + 1], 'Sinopsis:')); + end; + end; + end; + + procedure ScanInfo2(const StartIndex: Integer); + var + i: Integer; + s: String; + begin + for i := StartIndex + 1 to Parse.Count - 1 do + begin + s := GetTagName(Parse[i]); + if s = '/div' then + Break + else + if s = 'li' then + begin + //authors + if Pos('Author(s):', Parse[i + 2]) = 1 then + info.authors := CommonStringFilter(Parse[i + 4]) + else + //artist + if Pos('Artist(s):', Parse[i + 2]) = 1 then + info.artists := CommonStringFilter(Parse[i + 4]) + else + //genres + if Pos('Genre:', Parse[i + 2]) = 1 then + info.genres := CommonStringFilter(Parse[i + 4]) + else + //summary + if Pos('Sinopsis:', Parse[i + 2]) = 1 then + info.summary := CommonStringFilter(Parse[i + 4]); + end; + end; + end; + procedure ScanParse; var i, j: Integer; @@ -109,36 +177,28 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; (GetVal(Parse[i], 'class') = 'pecintakomik') then info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); - //title - if info.title = '' then - if GetVal(Parse[i], 'class') = 'post-cnt' then - if GetTagName(Parse[i + 2]) = 'h2' then - info.title := CommonStringFilter(Parse[i + 3]); - - if GetTagName(Parse[i]) = 'li' then - begin - //authors - if Pos('Author(s):', Parse[i + 1]) = 1 then - info.authors := CommonStringFilter(SeparateRight(Parse[i + 1], - 'Author(s):')); - //artist - if Pos('Artist(s):', Parse[i + 1]) = 1 then - info.artists := CommonStringFilter(SeparateRight(Parse[i + 1], - 'Artist(s):')); - //genres - if Pos('Genre:', Parse[i + 1]) = 1 then - info.genres := CommonStringFilter(SeparateRight(Parse[i + 1], 'Genre:')); - //summary - if Pos('Sinopsis:', Parse[i + 1]) = 1 then - info.summary := CommonStringFilter(SeparateRight(Parse[i + 1], 'Sinopsis:')); - end; - - // chapters - if Parse[i] = 'List Chapter(s)' then - begin - ScanChapters(i); - Break; - end; + if GetVal(Parse[i], 'class') = 'post-cnt' then + if GetTagName(Parse[i + 2]) = 'h2' then + begin + //chapters + if Pos('List Chapter(s)', Parse[i + 3]) <> 0 then + begin + ScanChapters(i); + Break; + end + else + begin + //title + if info.title = '' then + info.title := CommonStringFilter(Parse[i + 3]); + //info + if (GetTagName(Parse[i + 8]) = 'li') and + (GetTagName(Parse[i + 9]) <> 'strong') then + ScanInfo(i) + else + ScanInfo2(i); + end; + end; end; end else From 2d972cea2f1c249cc1b1e189971232288ff229a5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 00:40:27 +0800 Subject: [PATCH 0356/2794] pecinta.komik, add another layout --- baseunits/modules/PecintaKomik.pas | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index f13ccc57d..57206ae3d 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -163,6 +163,61 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; + //broken layout + procedure ScanInfo3; + var + i, j: Integer; + begin + info.genres := ''; + info.summary := ''; + for i := 0 to Parse.Count - 1 do + begin + //cover + if info.coverLink = '' then + if (GetTagName(Parse[i]) = 'img') and + (GetVal(Parse[i], 'class') = 'pecintakomik') then + info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); + //title + if info.title = '' then + if GetVal(Parse[i], 'class') = 'aname' then + info.title := CommonStringFilter(Parse[i + 1]); + if GetVal(Parse[i], 'class') = 'propertytitle' then + begin + //author + if Pos('Autor:', Parse[i + 1]) = 1 then + info.authors := CommonStringFilter(Parse[i + 6]) + else + //artist + if Pos('Artist:', Parse[i + 1]) = 1 then + info.artists := CommonStringFilter(Parse[i + 6]); + //summary + if Pos('Ringkasan Cerita:', Parse[i + 1]) = 1 then + for j := i + 3 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/td' then + Break + else + if (Parse[j] <> '') and (Parse[j][1] <> '<') then + begin + if info.summary <> '' then + info.summary += LineEnding; + info.summary += CommonStringFilter(Parse[j]); + end; + end; + //genre + if GetVal(Parse[i], 'class') = 'genretags' then + AddCommaString(info.genres, CommonStringFilter(Parse[i + 1])); + end; + //chapters + if (GetTagName(Parse[i]) = 'ul') and + (GetVal(Parse[i], 'class') = 'series_alpha') then + begin + ScanChapters(i); + Break; + end; + end; + end; + procedure ScanParse; var i, j: Integer; @@ -171,6 +226,12 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin for i := 0 to Parse.Count - 1 do begin + if GetVal(Parse[i], 'http-equiv') = 'x-ua-compatible' then + begin + ScanInfo3; + Break; + end; + //cover if info.coverLink = '' then if (GetTagName(Parse[i]) = 'img') and From 4a8fe4ec26475ad0860c6274188e8580bf354da6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 00:49:31 +0800 Subject: [PATCH 0357/2794] baseunit, add removeurldelim function --- baseunits/uBaseUnit.pas | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6a570666d..2bfe380e2 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -875,6 +875,8 @@ function CleanAndExpandURL(const URL: String): String; function CleanURL(const URL: String): String; function AppendURLDelim(const URL: String): String; function AppendURLDelimLeft(const URL: String): String; +function RemoveURLDelim(const URL: String): String; +function RemoveURLDelimLeft(const URL: String): String; function FixURL(const URL: String): String; function FixPath(const path: String): String; function GetLastDir(const path: String): String; @@ -2299,6 +2301,20 @@ function AppendURLDelimLeft(const URL: String): String; Result := '/' + URL; end; +function RemoveURLDelim(const URL: String): String; +begin + Result := URL; + if (URL <> '') and (URL[Length(URL)] = '/') then + SetLength(Result, Length(Result) - 1); +end; + +function RemoveURLDelimLeft(const URL: String): String; +begin + Result := URL; + if (URL <> '') and (URL[1] = '/') then + Delete(Result, 1, 1); +end; + function FixURL(const URL : String) : String; begin Result := URL; From 27c3706b10f9bf450317422d17ee48454e0e1462 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 00:53:34 +0800 Subject: [PATCH 0358/2794] baseunit, don't strip host on fillhost --- baseunits/uBaseUnit.pas | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2bfe380e2..ff4c4bfc0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1394,18 +1394,17 @@ function FillMangaSiteHost(const Website, URL: String): String; function FillHost(const Host, URL: String): String; var - th, tu: string; + tu: string; begin Result := URL; if Host = '' then Exit; with TRegExpr.Create do try Expression := REGEX_HOST; - th := Replace(Host, '$1$2$3', True); tu := Replace(URL, '$4', True); if tu = '' then tu := URL; - Result := th + AppendURLDelimLeft(tu); + Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); finally Free; end; @@ -1413,7 +1412,7 @@ function FillHost(const Host, URL: String): String; function MaybeFillHost(const Host, URL: String): String; var - th, tu: string; + tu: string; begin Result := URL; if Host = '' then Exit; @@ -1422,11 +1421,10 @@ function MaybeFillHost(const Host, URL: String): String; Expression := REGEX_HOST; if Replace(URL, '$1', True) = '' then begin - th := Replace(Host, '$1$2$3', True); tu := Replace(URL, '$4', True); if tu = '' then tu := URL; - Result := th + AppendURLDelimLeft(tu); + Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); end; finally Free; From 97aa82db20dd0b98c644d4ec980f9a1406cc36f0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 00:55:10 +0800 Subject: [PATCH 0359/2794] pecinta.komik, fix getimageurl --- baseunits/modules/PecintaKomik.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 57206ae3d..f28661839 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -386,15 +386,21 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; procedure ScanParse; var i: Integer; + baseurl: String; begin + baseurl := Module.RootURL; for i := 0 to Parse.Count - 1 do + begin + if GetTagName(Parse[i]) = 'base' then + baseurl := GetVal(Parse[i], 'href'); if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'picture') then begin if DownloadThread.workCounter < Container.PageLinks.Count then Container.PageLinks[DownloadThread.workCounter] := - MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); + MaybeFillHost(baseurl, GetVal(Parse[i], 'src')); Break; end; + end; end; begin From e07fe8a20fedadbbbbaf0ed060dd806d2d0d8f9b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 01:25:40 +0800 Subject: [PATCH 0360/2794] Bump version 0.9.20.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index ec9017d66..925b499fd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,11 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.20.0 (02-08-2015) +[*] Mangacan: rewrite all script +[*] PecintaKomik: rewrite all script +[*] Various changes and bug fixes + 0.9.19.7 (30-07-2015) [*] Minor bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 23bbaf330..0753854d3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ - - + diff --git a/update b/update index 33bd5b158..885298cc0 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.19.7 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.19.7/fmd_0.9.19.7.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.19.7/fmd_0.9.19.7_Win64.7z +VERSION=0.9.20.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.20.0/fmd_0.9.20.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.20.0/fmd_0.9.20.0_Win64.7z From 3532646f0160936d7bf77d2d0e4bfcd445aaf28e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 02:00:15 +0800 Subject: [PATCH 0361/2794] updater, use tfmdthread and break connection via oncustomterminate --- updater/languages/updater.id_ID.po | 1 + updater/uMain.pas | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 3b4f6c71e..09436326b 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -119,3 +119,4 @@ msgstr "Membuka berkas [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Menunggu aplikasi utama untuk berhenti..." + diff --git a/updater/uMain.pas b/updater/uMain.pas index 5b95957b0..6e285ffda 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -12,7 +12,7 @@ interface Classes, SysUtils, zipper, FileUtil,LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, RegExpr, IniFiles, USimpleException, uMisc, uTranslation, - httpsend, blcksock, ssl_openssl; + httpsend, blcksock, ssl_openssl, uFMDThread; type @@ -40,7 +40,7 @@ TfrmMain = class(TForm) { TDownloadThread } - TDownloadThread = class(TThread) + TDownloadThread = class(TFMDThread) private FTotalSize, FCurrentSize :integer; FHTTP :THTTPSend; @@ -51,7 +51,6 @@ TDownloadThread = class(TThread) protected procedure SockOnStatus(Sender :TObject; Reason :THookSocketReason; const Value :string); - procedure SockOnHeartBeat(Sender :TObject); procedure UZipOnStartFile(Sender :TObject; const AFileName :string); procedure MainThreadUpdateStatus; procedure MainThreadUpdateProgress; @@ -60,6 +59,7 @@ TDownloadThread = class(TThread) procedure UpdateStatus(AStatus :string); procedure ShowErrorMessage(AMessage :string); procedure Execute; override; + procedure OnThreadTerminate(Sender: TObject); public URL :string; isSFURL :boolean; @@ -169,12 +169,10 @@ constructor TDownloadThread.Create; begin inherited Create(True); isDownload := True; - FreeOnTerminate := True; FHTTP := THTTPSend.Create; FHTTP.Headers.NameValueSeparator := ':'; FHTTP.Sock.OnStatus := @SockOnStatus; - FHTTP.Sock.OnHeartbeat := @SockOnHeartBeat; - FHTTP.Sock.HeartbeatRate := 250; + OnCustomTerminate := @OnThreadTerminate; FTotalSize := 0; FCurrentSize := 0; URL := ''; @@ -208,15 +206,6 @@ procedure TDownloadThread.ShowErrorMessage(AMessage: string); Synchronize(@MainThreadErrorGetting); end; -procedure TDownloadThread.SockOnHeartBeat(Sender :TObject); -begin - if Self.Terminated then - begin - TBlockSocket(Sender).StopFlag := True; - TBlockSocket(Sender).AbortSocket; - end; -end; - procedure TDownloadThread.MainThreadUpdateProgress; var barPos: Integer; @@ -573,6 +562,15 @@ procedure TDownloadThread.Execute; HTTPHeaders.Free; end; +procedure TDownloadThread.OnThreadTerminate(Sender: TObject); +begin + with FHTTP.Sock do + begin + StopFlag := True; + AbortSocket; + end; +end; + { TfrmMain } procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); From cfa81ab98c04592127ebb5cd6f1cae9ade4826ae Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 02:01:39 +0800 Subject: [PATCH 0362/2794] updater, set connection timeout to 10 seconds --- updater/uMain.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/updater/uMain.pas b/updater/uMain.pas index 6e285ffda..422c4bfd4 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -172,6 +172,9 @@ constructor TDownloadThread.Create; FHTTP := THTTPSend.Create; FHTTP.Headers.NameValueSeparator := ':'; FHTTP.Sock.OnStatus := @SockOnStatus; + FHTTP.Timeout := 10000; + FHTTP.Sock.ConnectionTimeout := FHTTP.Timeout; + FHTTP.Sock.SetTimeout(FHTTP.Timeout); OnCustomTerminate := @OnThreadTerminate; FTotalSize := 0; FCurrentSize := 0; From c063f097ca69bfd7d50a7741f5f069f9a2da256c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 02:02:14 +0800 Subject: [PATCH 0363/2794] updater, increase version number --- updater/updater.lpi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/updater/updater.lpi b/updater/updater.lpi index 4ae2ddcb8..78441cdc6 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -18,8 +18,7 @@ - - + From b7a1b0d0e07b0f084d7f0257602ee0275339ff36 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 14:05:38 +0800 Subject: [PATCH 0364/2794] mainform, add button to abort check update --- baseunits/uSubThread.pas | 71 +++++++++++++++++++++---------- mangadownloader/forms/frmMain.lfm | 45 ++++++++++++++++++++ mangadownloader/forms/frmMain.pas | 7 +++ 3 files changed, 101 insertions(+), 22 deletions(-) diff --git a/baseunits/uSubThread.pas b/baseunits/uSubThread.pas index 643982080..3ec06d231 100644 --- a/baseunits/uSubThread.pas +++ b/baseunits/uSubThread.pas @@ -15,33 +15,37 @@ interface type + TSubThread = class; + { TCheckUpdateThread } TCheckUpdateThread = class(TFMDThread) protected + FHTTP: THTTPSendThread; fNewVersionNumber, fUpdateURL, fChangelog, FBtnCheckCaption: String; procedure MainThreadUpdate; - procedure MainThreadSetButton; + procedure SyncStartUpdate; + procedure SyncEndUpdate; procedure Execute; override; public - CheckStatus: ^Boolean; - ThreadStatus: ^Boolean; + Manager: TSubThread; + constructor Create; destructor Destroy; override; end; { TSubThread } TSubThread = class(TFMDThread) protected - FCheckUpdateRunning: Boolean; FCheckUpdateThread: TCheckUpdateThread; procedure Execute; override; public CheckUpdate: Boolean; constructor Create; destructor Destroy; override; + procedure AbortCheckUpdate; end; resourcestring @@ -87,25 +91,36 @@ procedure TCheckUpdateThread.MainThreadUpdate; end; end; -procedure TCheckUpdateThread.MainThreadSetButton; +procedure TCheckUpdateThread.SyncStartUpdate; begin - MainForm.btCheckVersion.Caption := FBtnCheckCaption; + with MainForm.btCheckVersion do + begin + MainForm.btAbortCheckVersion.Visible := True; + Width := Width - MainForm.btAbortCheckVersion.Width - 6; + Caption := RS_Checking; + end; +end; + +procedure TCheckUpdateThread.SyncEndUpdate; +begin + with MainForm.btCheckVersion do + begin + MainForm.btAbortCheckVersion.Visible := False; + Width := Width + MainForm.btAbortCheckVersion.Width + 6; + Caption := RS_BtnCheckUpdates; + end; end; procedure TCheckUpdateThread.Execute; var l: TStringList; - FHTTP: THTTPSendThread; updateFound: Boolean = False; begin - ThreadStatus^ := True; + Synchronize(SyncStartUpdate); l := TStringList.Create; - FHTTP := THTTPSendThread.Create(Self); try fNewVersionNumber := FMD_VERSION_NUMBER; fUpdateURL := ''; - FBtnCheckCaption := RS_Checking; - Synchronize(MainThreadSetButton); if not Terminated and GetPage(FHTTP, TObject(l), UPDATE_URL + 'update', 3) then if l.Count > 1 then @@ -123,21 +138,26 @@ procedure TCheckUpdateThread.Execute; GetPage(FHTTP, TObject(l), UPDATE_URL + 'changelog.txt', 3) then fChangelog := l.Text; end; - FBtnCheckCaption := RS_BtnCheckUpdates; - Synchronize(MainThreadSetButton); end; finally - FHTTP.Free; l.Free; end; + Synchronize(SyncEndUpdate); if not Terminated and updateFound and (not isDlgCounter) then Synchronize(MainThreadUpdate); end; +constructor TCheckUpdateThread.Create; +begin + inherited Create(True); + FHTTP := THTTPSendThread.Create(Self); +end; + destructor TCheckUpdateThread.Destroy; begin - CheckStatus^ := False; - ThreadStatus^ := False; + FHTTP.Free; + Manager.CheckUpdate := False; + Manager.FCheckUpdateThread := nil; inherited Destroy; end; @@ -158,12 +178,11 @@ procedure TSubThread.Execute; while not Terminated do begin - if CheckUpdate and (not FCheckUpdateRunning) and + if CheckUpdate and (FCheckUpdateThread = nil) and (not isDlgCounter) then begin - FCheckUpdateThread := TCheckUpdateThread.Create(True); - FCheckUpdateThread.CheckStatus := @CheckUpdate; - FCheckUpdateThread.ThreadStatus := @FCheckUpdateRunning; + FCheckUpdateThread := TCheckUpdateThread.Create; + FCheckUpdateThread.Manager := Self; FCheckUpdateThread.Start; end; @@ -175,7 +194,7 @@ procedure TSubThread.Execute; end; Sleep(500); end; - if FCheckUpdateRunning then + if Assigned(FCheckUpdateThread) then begin FCheckUpdateThread.Terminate; FCheckUpdateThread.WaitFor; @@ -190,7 +209,6 @@ constructor TSubThread.Create; begin inherited Create(True); CheckUpdate := False; - FCheckUpdateRunning := CheckUpdate; end; destructor TSubThread.Destroy; @@ -199,4 +217,13 @@ destructor TSubThread.Destroy; inherited Destroy; end; +procedure TSubThread.AbortCheckUpdate; +begin + if Assigned(FCheckUpdateThread) then + begin + FCheckUpdateThread.Terminate; + FCheckUpdateThread.WaitFor; + end; +end; + end. diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f503cbd8e..869eb3e85 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2999,6 +2999,51 @@ object MainForm: TMainForm OnClick = btCheckVersionClick TabOrder = 0 end + object btAbortCheckVersion: TSpeedButton + Left = 193 + Height = 40 + Top = 429 + Width = 40 + Anchors = [akLeft, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + Visible = False + OnClick = btAbortCheckVersionClick + end object btVisitMyBlog: TBitBtn Left = 249 Height = 40 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a9f667ddd..3632ded70 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -34,6 +34,7 @@ TMainForm = class(TForm) btAddToFavorites: TBitBtn; btBrowse: TSpeedButton; btCancelFavoritesCheck: TSpeedButton; + btAbortCheckVersion: TSpeedButton; btOptionBrowse: TSpeedButton; btChecks: TSpeedButton; btDonate: TImage; @@ -335,6 +336,7 @@ TMainForm = class(TForm) var CanShow: Boolean; var HintInfo: THintInfo); procedure btAddToFavoritesClick(Sender: TObject); procedure btAbortUpdateListClick(Sender: TObject); + procedure btAbortCheckVersionClick(Sender: TObject); procedure btCancelFavoritesCheckClick(Sender: TObject); procedure btChecksClick(Sender: TObject); procedure btCheckVersionClick(Sender: TObject); @@ -1870,6 +1872,11 @@ procedure TMainForm.btAbortUpdateListClick(Sender: TObject); updateList.Terminate; end; +procedure TMainForm.btAbortCheckVersionClick(Sender: TObject); +begin + SubThread.AbortCheckUpdate; +end; + procedure TMainForm.btCancelFavoritesCheckClick(Sender: TObject); begin FavoriteManager.StopChekForNewChapter(False); From 16f5cfda335eaf20fbe1f72aeaf225b96a5c51e3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 14:38:09 +0800 Subject: [PATCH 0365/2794] separate checkupdatethread from subthread --- baseunits/CheckUpdate.pas | 138 ++++++++++++++++++++++++ baseunits/uSubThread.pas | 167 +----------------------------- mangadownloader/forms/frmMain.lfm | 4 +- mangadownloader/forms/frmMain.pas | 27 +++-- 4 files changed, 162 insertions(+), 174 deletions(-) create mode 100644 baseunits/CheckUpdate.pas diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas new file mode 100644 index 000000000..00d1fed8c --- /dev/null +++ b/baseunits/CheckUpdate.pas @@ -0,0 +1,138 @@ +unit CheckUpdate; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, uFMDThread, uBaseUnit; + +type + + TCheckUpdateThread = class(TFMDThread) + private + FHTTP: THTTPSendThread; + fNewVersionNumber, fUpdateURL, fChangelog: String; + procedure MainThreadUpdate; + procedure SyncStartUpdate; + procedure SyncEndUpdate; + protected + procedure Execute; override; + public + constructor Create; + destructor Destroy; override; + end; + +resourcestring + RS_NewVersionFound = 'New Version found!'; + RS_CurrentVersion = 'Installed Version'; + RS_LatestVersion = 'Latest Version '; + RS_BtnCheckUpdates = 'Check for new version'; + +implementation + +uses + frmMain, frmUpdateDialog; + +{ TCheckUpdateThread } + +procedure TCheckUpdateThread.MainThreadUpdate; +begin + if IsDlgCounter then Exit; + with TUpdateDialogForm.Create(MainForm) do try + Caption := Application.Title + ' - ' + RS_NewVersionFound; + with mmLog.Lines do + begin + BeginUpdate; + try + Clear; + Add(RS_CurrentVersion + ' : ' + FMD_VERSION_NUMBER); + Add(RS_LatestVersion + ' : ' + fNewVersionNumber + LineEnding); + AddText(fChangelog); + finally + EndUpdate; + end; + end; + if ShowModal = mrYes then + begin + frmMain.FUpdateURL := fUpdateURL; + DoAfterFMD := DO_UPDATE; + MainForm.itMonitor.Enabled := True; + end + else + MainForm.btCheckVersion.Caption := RS_BtnCheckUpdates; + finally + Free; + end; +end; + +procedure TCheckUpdateThread.SyncStartUpdate; +begin + with MainForm.btCheckVersion do + begin + MainForm.btAbortCheckVersion.Visible := True; + Width := Width - MainForm.btAbortCheckVersion.Width - 4; + Caption := RS_Checking; + end; +end; + +procedure TCheckUpdateThread.SyncEndUpdate; +begin + with MainForm.btCheckVersion do + begin + MainForm.btAbortCheckVersion.Visible := False; + Width := Width + MainForm.btAbortCheckVersion.Width + 4; + Caption := RS_BtnCheckUpdates; + end; +end; + +procedure TCheckUpdateThread.Execute; +var + l: TStringList; + updateFound: Boolean = False; +begin + Synchronize(@SyncStartUpdate); + l := TStringList.Create; + try + fNewVersionNumber := FMD_VERSION_NUMBER; + fUpdateURL := ''; + if not Terminated and + GetPage(FHTTP, TObject(l), UPDATE_URL + 'update', 3) then + if l.Count > 1 then + begin + l.NameValueSeparator := '='; + if Trim(l.Values['VERSION']) <> FMD_VERSION_NUMBER then + begin + fNewVersionNumber := Trim(l.Values['VERSION']); + fUpdateURL := Trim(l.Values[UpperCase(FMD_TARGETOS)]); + if fUpdateURL <> '' then + updateFound := True; + FHTTP.Clear; + l.Clear; + if not Terminated and + GetPage(FHTTP, TObject(l), UPDATE_URL + 'changelog.txt', 3) then + fChangelog := l.Text; + end; + end; + finally + l.Free; + end; + Synchronize(@SyncEndUpdate); + if not Terminated and updateFound and (not isDlgCounter) then + Synchronize(@MainThreadUpdate); +end; + +constructor TCheckUpdateThread.Create; +begin + inherited Create(False); + FHTTP := THTTPSendThread.Create(Self); +end; + +destructor TCheckUpdateThread.Destroy; +begin + FHTTP.Free; + MainForm.CheckUpdateThread := nil; + inherited Destroy; +end; + +end. diff --git a/baseunits/uSubThread.pas b/baseunits/uSubThread.pas index 3ec06d231..dcf018a90 100644 --- a/baseunits/uSubThread.pas +++ b/baseunits/uSubThread.pas @@ -15,151 +15,19 @@ interface type - TSubThread = class; - - { TCheckUpdateThread } - - TCheckUpdateThread = class(TFMDThread) - protected - FHTTP: THTTPSendThread; - fNewVersionNumber, - fUpdateURL, - fChangelog, - FBtnCheckCaption: String; - procedure MainThreadUpdate; - procedure SyncStartUpdate; - procedure SyncEndUpdate; - procedure Execute; override; - public - Manager: TSubThread; - constructor Create; - destructor Destroy; override; - end; - { TSubThread } + TSubThread = class(TFMDThread) protected - FCheckUpdateThread: TCheckUpdateThread; procedure Execute; override; public - CheckUpdate: Boolean; - constructor Create; destructor Destroy; override; - procedure AbortCheckUpdate; end; - -resourcestring - RS_NewVersionFound = 'New Version found!'; - RS_CurrentVersion = 'Installed Version'; - RS_LatestVersion = 'Latest Version '; - RS_BtnCheckUpdates = 'Check for new version'; implementation uses - frmMain, frmUpdateDialog; - -{ TCheckUpdateThread } - -procedure TCheckUpdateThread.MainThreadUpdate; -begin - if IsDlgCounter then Exit; - with TUpdateDialogForm.Create(MainForm) do try - Caption := Application.Title + ' - ' + RS_NewVersionFound; - with mmLog.Lines do - begin - BeginUpdate; - try - Clear; - Add(RS_CurrentVersion + ' : ' + FMD_VERSION_NUMBER); - Add(RS_LatestVersion + ' : ' + fNewVersionNumber + LineEnding); - AddText(fChangelog); - finally - EndUpdate; - end; - end; - if ShowModal = mrYes then - begin - frmMain.FUpdateURL := fUpdateURL; - DoAfterFMD := DO_UPDATE; - MainForm.itMonitor.Enabled := True; - end - else - MainForm.btCheckVersion.Caption := RS_BtnCheckUpdates; - finally - Free; - end; -end; - -procedure TCheckUpdateThread.SyncStartUpdate; -begin - with MainForm.btCheckVersion do - begin - MainForm.btAbortCheckVersion.Visible := True; - Width := Width - MainForm.btAbortCheckVersion.Width - 6; - Caption := RS_Checking; - end; -end; - -procedure TCheckUpdateThread.SyncEndUpdate; -begin - with MainForm.btCheckVersion do - begin - MainForm.btAbortCheckVersion.Visible := False; - Width := Width + MainForm.btAbortCheckVersion.Width + 6; - Caption := RS_BtnCheckUpdates; - end; -end; - -procedure TCheckUpdateThread.Execute; -var - l: TStringList; - updateFound: Boolean = False; -begin - Synchronize(SyncStartUpdate); - l := TStringList.Create; - try - fNewVersionNumber := FMD_VERSION_NUMBER; - fUpdateURL := ''; - if not Terminated and - GetPage(FHTTP, TObject(l), UPDATE_URL + 'update', 3) then - if l.Count > 1 then - begin - l.NameValueSeparator := '='; - if Trim(l.Values['VERSION']) <> FMD_VERSION_NUMBER then - begin - fNewVersionNumber := Trim(l.Values['VERSION']); - fUpdateURL := Trim(l.Values[UpperCase(FMD_TARGETOS)]); - if fUpdateURL <> '' then - updateFound := True; - FHTTP.Clear; - l.Clear; - if not Terminated and - GetPage(FHTTP, TObject(l), UPDATE_URL + 'changelog.txt', 3) then - fChangelog := l.Text; - end; - end; - finally - l.Free; - end; - Synchronize(SyncEndUpdate); - if not Terminated and updateFound and (not isDlgCounter) then - Synchronize(MainThreadUpdate); -end; - -constructor TCheckUpdateThread.Create; -begin - inherited Create(True); - FHTTP := THTTPSendThread.Create(Self); -end; - -destructor TCheckUpdateThread.Destroy; -begin - FHTTP.Free; - Manager.CheckUpdate := False; - Manager.FCheckUpdateThread := nil; - inherited Destroy; -end; + frmMain; { TSubThread } @@ -167,9 +35,6 @@ procedure TSubThread.Execute; begin MainForm.isSubthread := True; try - if FileExists(fmdDirectory + 'old_updater.exe') then - DeleteFile(fmdDirectory + 'old_updater.exe'); - if OptionAutoCheckFavStartup then begin MainForm.FavoriteManager.isAuto := True; @@ -178,14 +43,6 @@ procedure TSubThread.Execute; while not Terminated do begin - if CheckUpdate and (FCheckUpdateThread = nil) and - (not isDlgCounter) then - begin - FCheckUpdateThread := TCheckUpdateThread.Create; - FCheckUpdateThread.Manager := Self; - FCheckUpdateThread.Start; - end; - with MainForm do begin while (SilentThreadManager.MetaData.Count > 0) and @@ -194,36 +51,16 @@ procedure TSubThread.Execute; end; Sleep(500); end; - if Assigned(FCheckUpdateThread) then - begin - FCheckUpdateThread.Terminate; - FCheckUpdateThread.WaitFor; - end; except on E: Exception do MainForm.ExceptionHandler(Self, E); end; end; -constructor TSubThread.Create; -begin - inherited Create(True); - CheckUpdate := False; -end; - destructor TSubThread.Destroy; begin MainForm.isSubthread := False; inherited Destroy; end; -procedure TSubThread.AbortCheckUpdate; -begin - if Assigned(FCheckUpdateThread) then - begin - FCheckUpdateThread.Terminate; - FCheckUpdateThread.WaitFor; - end; -end; - end. diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 869eb3e85..d410063c0 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -35,13 +35,13 @@ object MainForm: TMainForm Height = 508 Top = 11 Width = 614 - ActivePage = tsDownload + ActivePage = tsAbout Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 5 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3632ded70..c2c275c86 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,7 +22,7 @@ interface FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, - uTranslation, frmDropTarget, USimpleException, USimpleLogger; + uTranslation, frmDropTarget, CheckUpdate, USimpleException, USimpleLogger; type @@ -575,6 +575,9 @@ TMainForm = class(TForm) GetInfosThread: TGetMangaInfosThread; isGetMangaInfos: Boolean; + // check update + CheckUpdateThread: TCheckUpdateThread; + // repaint treeview procedure tvDownloadFilterRepaint; @@ -950,6 +953,10 @@ procedure TMainForm.FormCreate(Sender: TObject); Application.HintHidePause := 10000; sbUpdateList.DoubleBuffered := True; + // remove old updater + if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then + DeleteFileUTF8(fmdDirectory + 'old_updater.exe'); + // TrayIcon TrayIcon.Icon.Assign(Application.Icon); PrevWindowState := wsNormal; @@ -1087,6 +1094,11 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow(WaitFor: Boolean); begin + if Assigned(CheckUpdateThread) then + begin + CheckUpdateThread.Terminate; + CheckUpdateThread.WaitFor; + end; if Assigned(SearchDBThread) then begin SearchDBThread.Terminate; @@ -1203,8 +1215,8 @@ procedure TMainForm.itAnimateTimer(Sender: TObject); procedure TMainForm.itCheckForChaptersTimer(Sender: TObject); begin if IsDlgCounter then Exit; - if options.ReadBool('update', 'AutoCheckUpdate', True) then - SubThread.CheckUpdate := True; + if cbOptionAutoCheckUpdate.Checked then + btCheckVersionClick(btCheckVersion); FavoriteManager.isAuto := True; FavoriteManager.CheckForNewChapter; end; @@ -1329,7 +1341,7 @@ procedure TMainForm.itStartupTimer(Sender: TObject); if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if cbOptionAutoCheckUpdate.Checked then - SubThread.CheckUpdate := True; + btCheckVersionClick(btCheckVersion); SubThread.Start; end; end; @@ -1874,7 +1886,8 @@ procedure TMainForm.btAbortUpdateListClick(Sender: TObject); procedure TMainForm.btAbortCheckVersionClick(Sender: TObject); begin - SubThread.AbortCheckUpdate; + if Assigned(CheckUpdateThread) then + CheckUpdateThread.Terminate; end; procedure TMainForm.btCancelFavoritesCheckClick(Sender: TObject); @@ -2102,10 +2115,10 @@ procedure TMainForm.btSearchClearClick(Sender: TObject); procedure TMainForm.btCheckVersionClick(Sender: TObject); begin - if SubThread.CheckUpdate then + if Assigned(CheckUpdateThread) then MessageDlg('', RS_DlgUpdaterIsRunning, mtInformation, [mbYes], 0) else - SubThread.CheckUpdate := True; + CheckUpdateThread := TCheckUpdateThread.Create; end; procedure TMainForm.btDonateClick(Sender: TObject); From 3b4aacc3cd9712bcb62b1e123487066f8c5a71d0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 14:47:50 +0800 Subject: [PATCH 0366/2794] use utf8 fileutils --- baseunits/SimpleException/USimpleLogger.pas | 4 ++-- baseunits/includes/EHentai/image_url.inc | 6 +++--- baseunits/includes/MeinManga/image_url.inc | 6 +++--- baseunits/uBaseUnit.pas | 2 +- baseunits/uData.pas | 4 ++-- baseunits/uDownloadsManager.pas | 2 +- baseunits/uMisc.pas | 10 +++++----- mangadownloader/forms/frmMain.pas | 2 +- mangadownloader/md.lpr | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index de4495637..ed90adcb8 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -60,7 +60,7 @@ procedure ForceLogFile(const logfilename: string); if f <> '' then begin if _LOG_ACTIVE and (not DirectoryExists(f)) then - ForceDirectories(f); + ForceDirectoriesUTF8(f); f := f + PathDelim + ExtractFileName(logfilename); end else @@ -82,7 +82,7 @@ procedure WriteLog(const msg: String; LogType: TLogType = DEBUG); s := s + '[' + _LOG_SYMBOL[Integer(logType)+1] + ']'; AssignFile(f, _FLOGFILE); try - if FileExists(_FLOGFILE) then + if FileExistsUTF8(_FLOGFILE) then Append(f) else begin diff --git a/baseunits/includes/EHentai/image_url.inc b/baseunits/includes/EHentai/image_url.inc index 2572e5ffa..397102d7e 100644 --- a/baseunits/includes/EHentai/image_url.inc +++ b/baseunits/includes/EHentai/image_url.inc @@ -14,9 +14,9 @@ // Format('%.3d', [workCounter + 1]); // Check to see if a file with similar name was already exist. If so then we // skip the download process. - //if (FileExists(s + '.jpg')) or - // (FileExists(s + '.png')) or - // (FileExists(s + '.gif')) then + //if (FileExistsUTF8(s + '.jpg')) or + // (FileExistsUTF8(s + '.png')) or + // (FileExistsUTF8(s + '.gif')) then //begin // Result := 'D'; // Exit; diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index a40c02b38..c14918caf 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -12,9 +12,9 @@ Format('%.3d', [workCounter + 1]); // Check to see if a file with similar name was already exist. If so then we // skip the download process. - if (FileExists(s + '.jpg')) or - (FileExists(s + '.png')) or - (FileExists(s + '.gif')) then + if (FileExistsUTF8(s + '.jpg')) or + (FileExistsUTF8(s + '.png')) or + (FileExistsUTF8(s + '.gif')) then begin Result := True; Exit; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ff4c4bfc0..b2b311361 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3273,7 +3273,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; begin fpath := CleanAndExpandFilename(lpath + Name + prefix + ext); if FileExistsUTF8(fpath) then - DeleteFile(fpath); + DeleteFileUTF8(fpath); fstream := TFileStreamUTF8.Create(fpath, fmCreate); try HTTP.Document.SaveToStream(fstream); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5fd67526c..015b98019 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1391,7 +1391,7 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; summary.Clear; jdn.Clear; - if not FileExists(Filename + DATA_EXT) then + if not FileExistsUTF8(Filename + DATA_EXT) then Exit(False); l := TStringList.Create; try @@ -1461,7 +1461,7 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; begin Filename := DATA_FOLDER + websiteList.Strings[i]; id := GetMangaSiteID(websiteList.Strings[i]); - if not FileExists(Filename + DATA_EXT) then + if not FileExistsUTF8(Filename + DATA_EXT) then continue; l.Clear; l.LoadFromFile(Filename + DATA_EXT); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 87b38c7e4..12d9f1594 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1722,7 +1722,7 @@ constructor TDownloadManager.Create; DownloadedChaptersListFile := TStringList.Create; - if FileExists(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE) then + if FileExistsUTF8(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE) then DownloadedChaptersListFile.LoadFromFile(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE); Containers := TFPList.Create; diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index 8e33b04b8..36c03a18f 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -10,7 +10,7 @@ interface {$else} UTF8Process, {$endif} - Classes, SysUtils, Graphics, strutils, syncobjs, IniFiles, + Classes, SysUtils, Graphics, LazFileUtils, strutils, syncobjs, IniFiles, NaturalSortUnit; type @@ -106,8 +106,8 @@ procedure TIniFileR.Reload; slLines: TStringList; begin if FCSReload.TryEnter then try - if FileExists(FileName) then - if FileAge(FileName) <> FFileAge then + if FileExistsUTF8(FileName) then + if FileAgeUTF8(FileName) <> FFileAge then begin slLines := TStringList.Create; try @@ -343,8 +343,8 @@ function MangaFoxRemoveWatermarks(const Filename: String): Boolean; if fpic.Bitmap.Height < 100 then Exit; fpic.Bitmap.Height := fpic.Bitmap.Height - 90;// crop by 90px - if FileExists(Filename) then - DeleteFile(Filename); + if FileExistsUTF8(Filename) then + DeleteFileUTF8(Filename); fpic.SaveToFile(Filename); Result := True; finally diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c2c275c86..e260cebe8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1035,7 +1035,7 @@ procedure TMainForm.FormCreate(Sender: TObject); btAddToFavorites.Enabled := False; // waiting gif - if FileExists(IMAGE_FOLDER + 'waiting.gif') then + if FileExistsUTF8(IMAGE_FOLDER + 'waiting.gif') then begin gifWaiting := TAnimatedGif.Create(IMAGE_FOLDER + 'waiting.gif'); gifWaiting.EraseColor := Self.Color; diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 652e4205d..120a9ef8d 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -51,8 +51,8 @@ if AllowedToRun then begin {$IFDEF DEBUGLEAKS} - if FileExists(ChangeFileExt(Application.ExeName, '.trc')) then - DeleteFile(ChangeFileExt(Application.ExeName, '.trc')); + if FileExistsUTF8(ChangeFileExt(Application.ExeName, '.trc')) then + DeleteFileUTF8(ChangeFileExt(Application.ExeName, '.trc')); SetHeapTraceOutput(ChangeFileExt(Application.ExeName, '.trc')); {$ENDIF DEBUGLEAKS} Application.Title := 'Free Manga Downloader'; From 5215e0d0219e956f526c92fdc014cf93ddf1fe9e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 17:23:22 +0800 Subject: [PATCH 0367/2794] better layout and naming of options --- baseunits/CheckUpdate.pas | 16 ++--- baseunits/modules/Batoto.pas | 4 +- baseunits/uBaseUnit.pas | 18 +++--- baseunits/uFavoritesManager.pas | 4 +- mangadownloader/forms/frmMain.lfm | 90 +++++++++++++++------------- mangadownloader/forms/frmMain.pas | 98 +++++++++++++++++-------------- 6 files changed, 126 insertions(+), 104 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 00d1fed8c..dff1aca0e 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -27,7 +27,7 @@ TCheckUpdateThread = class(TFMDThread) RS_NewVersionFound = 'New Version found!'; RS_CurrentVersion = 'Installed Version'; RS_LatestVersion = 'Latest Version '; - RS_BtnCheckUpdates = 'Check for new version'; + RS_BtnCheckUpdates = 'Check for latest version'; implementation @@ -60,7 +60,7 @@ procedure TCheckUpdateThread.MainThreadUpdate; MainForm.itMonitor.Enabled := True; end else - MainForm.btCheckVersion.Caption := RS_BtnCheckUpdates; + MainForm.btCheckLatestVersion.Caption := RS_BtnCheckUpdates; finally Free; end; @@ -68,20 +68,20 @@ procedure TCheckUpdateThread.MainThreadUpdate; procedure TCheckUpdateThread.SyncStartUpdate; begin - with MainForm.btCheckVersion do + with MainForm.btCheckLatestVersion do begin - MainForm.btAbortCheckVersion.Visible := True; - Width := Width - MainForm.btAbortCheckVersion.Width - 4; + MainForm.btAbortCheckLatestVersion.Visible := True; + Width := Width - MainForm.btAbortCheckLatestVersion.Width - 4; Caption := RS_Checking; end; end; procedure TCheckUpdateThread.SyncEndUpdate; begin - with MainForm.btCheckVersion do + with MainForm.btCheckLatestVersion do begin - MainForm.btAbortCheckVersion.Visible := False; - Width := Width + MainForm.btAbortCheckVersion.Width + 4; + MainForm.btAbortCheckLatestVersion.Visible := False; + Width := Width + MainForm.btAbortCheckLatestVersion.Width + 4; Caption := RS_BtnCheckUpdates; end; end; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 7341db472..0c498b93a 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -137,13 +137,13 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin addchap := True; s := CommonStringFilter(Parse[i + 6]); - if (not OptionShowAllLang) then + if (not OptionBatotoShowAllLang) then addchap := (Pos(' lang_English ', Parse[i]) <> 0) else s += Format(' [%s]', [Trim(GetVal(Parse[i + 12], 'title'))]); if addchap then begin - if OptionShowBatotoSG then + if OptionBatotoShowScanGroup then s += Format(' [%s]', [Trim(Parse[i + 19])]); info.chapterLinks.Add(GetVal(Parse[i + 4], 'href')); info.chapterName.Add(s); diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b2b311361..ce48e6a67 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -662,21 +662,25 @@ interface OptionLetFMDDo: TFMDDo = DO_NOTHING; OptionCustomRename: String; + OptionAutoNumberChapterChecked: Boolean = True; - OptionCheckMinutes: Cardinal = 0; OptionPDFQuality: Cardinal = 95; OptionMaxRetry: Integer = 0; OptionConnectionTimeout: Integer = 15000; OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; - OptionShowBatotoSG: Boolean = True; - OptionShowAllLang: Boolean = True; - OptionAutoDlFav: Boolean = True; OptionEnableLoadCover: Boolean = False; - OptionAutoNumberChapterChecked: Boolean = True; - OptionAutoRemoveCompletedManga: Boolean = True; - OptionAutoCheckFavStartup: Boolean = False; + + OptionAutoCheckLatestVersion: Boolean = True; + OptionAutoCheckFavStartup: Boolean = True; + OptionAutoCheckFavInterval: Boolean = True; + OptionAutoCheckFavIntervalMinutes: Cardinal = 0; + OptionAutoCheckFavDownload: Boolean = False; + OptionAutoCheckFavRemoveCompletedManga: Boolean = False; + + OptionBatotoShowScanGroup: Boolean = True; + OptionBatotoShowAllLang: Boolean = True; type TArrayOfString = array of string; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 994fb9270..fccd8efb0 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -555,7 +555,7 @@ procedure TFavoriteManager.ShowResult; end; //add completed manga - if (OptionAutoRemoveCompletedManga) and (NewMangaInfo.status = '0') then + if (OptionAutoCheckFavRemoveCompletedManga) and (NewMangaInfo.status = '0') then begin removeListStr := removeListStr + LineEnding + Format('- %s <%s>', [FavoriteInfo.Title, FavoriteInfo.Website]); @@ -617,7 +617,7 @@ procedure TFavoriteManager.ShowResult; else begin //if there's new chapters - if OptionAutoDlFav then + if OptionAutoCheckFavDownload then begin if MainForm.cbAddAsStopped.Checked then LNCResult := ncrQueue diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index d410063c0..384442ce2 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -35,13 +35,13 @@ object MainForm: TMainForm Height = 508 Top = 11 Width = 614 - ActivePage = tsAbout + ActivePage = tsOption Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 5 + TabIndex = 4 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1829,10 +1829,10 @@ object MainForm: TMainForm Height = 403 Top = 8 Width = 587 - ActivePage = tsGeneral + ActivePage = tsUpdate Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 4 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2585,83 +2585,93 @@ object MainForm: TMainForm Caption = 'Updates' ClientHeight = 375 ClientWidth = 579 - object cbOptionAutoCheckUpdate: TCheckBox - Left = 24 + object cbOptionAutoCheckLatestVersion: TCheckBox + Left = 16 Height = 19 - Top = 24 - Width = 140 - Caption = 'Check for new version ' + Top = 16 + Width = 173 + Caption = 'Auto check for latest version ' ParentFont = False TabOrder = 0 end object gbOptionFavorites: TGroupBox - Left = 25 - Height = 138 - Top = 56 + Left = 17 + Height = 178 + Top = 48 Width = 520 Anchors = [akTop, akLeft, akRight] Caption = 'Favorites' - ClientHeight = 118 + ClientHeight = 158 ClientWidth = 516 ParentFont = False TabOrder = 1 object cbOptionAutoCheckFavStartup: TCheckBox Left = 16 Height = 19 - Top = 40 - Width = 249 - Caption = 'Automatic check for new chapter at startup' + Top = 8 + Width = 219 + Caption = 'Auto check for new chapter at startup' ParentFont = False - TabOrder = 0 + TabOrder = 3 end - object seOptionCheckMinutes: TSpinEdit + object seOptionAutoCheckFavIntervalMinutes: TSpinEdit Left = 16 Height = 23 - Top = 8 + Top = 56 Width = 58 MaxValue = 1440 - OnChange = seOptionCheckMinutesChange - TabOrder = 1 + OnChange = seOptionAutoCheckFavIntervalMinutesChange + TabOrder = 0 end - object lbOptionAutoCheckMinutes: TLabel + object lbOptionAutoCheckFavIntervalMinutes: TLabel Left = 82 Height = 15 - Top = 12 + Top = 60 Width = 243 Caption = 'Auto check for new chapter every %d minutes' ParentColor = False end - object cbOptionAutoRemoveCompletedManga: TCheckBox + object cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox Left = 16 Height = 19 - Top = 88 + Top = 120 Width = 298 Caption = 'Automatic remove completed manga from Favorites' - TabOrder = 2 + TabOrder = 1 end - object cbOptionAutoDlFav: TCheckBox + object cbOptionAutoCheckFavDownload: TCheckBox Left = 16 Height = 19 - Top = 64 + Top = 96 Width = 242 Caption = 'Automatic download after finish checking' ParentFont = False - TabOrder = 3 + TabOrder = 2 + end + object cbOptionAutoCheckFavInterval: TCheckBox + Left = 16 + Height = 19 + Top = 32 + Width = 237 + Caption = 'Auto check for new chapter in an interval' + OnChange = cbOptionAutoCheckFavIntervalChange + ParentFont = False + TabOrder = 4 end end object cbOptionUpdateListNoMangaInfo: TCheckBox - Left = 24 + Left = 17 Height = 19 - Top = 202 + Top = 242 Width = 407 Caption = 'Don''t load manga information when updating list (filter will be not work!)' ParentFont = False TabOrder = 2 end object cbOptionUpdateListRemoveDuplicateLocalData: TCheckBox - Left = 24 + Left = 17 Height = 19 - Top = 226 + Top = 266 Width = 310 Caption = 'Remove duplicate local data when updating manga list' ParentFont = False @@ -2953,13 +2963,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 2 ClientHeight = 480 ClientWidth = 606 - object btCheckVersion: TBitBtn + object btCheckLatestVersion: TBitBtn Left = 25 Height = 40 Top = 429 Width = 208 Anchors = [akLeft, akBottom] - Caption = 'Check for new version' + Caption = 'Check for latest version' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 @@ -2996,10 +3006,10 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btCheckVersionClick + OnClick = btCheckLatestVersionClick TabOrder = 0 end - object btAbortCheckVersion: TSpeedButton + object btAbortCheckLatestVersion: TSpeedButton Left = 193 Height = 40 Top = 429 @@ -3042,7 +3052,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } Visible = False - OnClick = btAbortCheckVersionClick + OnClick = btAbortCheckLatestVersionClick end object btVisitMyBlog: TBitBtn Left = 249 @@ -4327,10 +4337,10 @@ object MainForm: TMainForm left = 752 top = 72 end - object itCheckForChapters: TIdleTimer + object itCheckFav: TIdleTimer Enabled = False Interval = 600000 - OnTimer = itCheckForChaptersTimer + OnTimer = itCheckFavTimer left = 760 top = 256 end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e260cebe8..a98ba7778 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -34,7 +34,7 @@ TMainForm = class(TForm) btAddToFavorites: TBitBtn; btBrowse: TSpeedButton; btCancelFavoritesCheck: TSpeedButton; - btAbortCheckVersion: TSpeedButton; + btAbortCheckLatestVersion: TSpeedButton; btOptionBrowse: TSpeedButton; btChecks: TSpeedButton; btDonate: TImage; @@ -48,8 +48,10 @@ TMainForm = class(TForm) btWebsitesSearchClear: TSpeedButton; btUpdateList: TSpeedButton; btURL: TSpeedButton; - cbOptionAutoDlFav: TCheckBox; - cbOptionAutoRemoveCompletedManga: TCheckBox; + cbOptionAutoCheckFavStartup: TCheckBox; + cbOptionAutoCheckFavInterval: TCheckBox; + cbOptionAutoCheckFavDownload: TCheckBox; + cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; @@ -123,11 +125,11 @@ TMainForm = class(TForm) pnThumbContainer: TPanel; pnMainTop: TPanel; btVisitMyBlog: TBitBtn; - btCheckVersion: TBitBtn; + btCheckLatestVersion: TBitBtn; btFavoritesCheckNewChapter: TBitBtn; btDownload: TBitBtn; btRemoveFilterLarge: TBitBtn; - cbOptionAutoCheckUpdate: TCheckBox; + cbOptionAutoCheckLatestVersion: TCheckBox; cbOptionShowDeleteTaskDialog: TCheckBox; cbOptionBatotoShowScanGroup: TCheckBox; cbOptionBatotoShowAllLang: TCheckBox; @@ -174,7 +176,6 @@ TMainForm = class(TForm) cbOptionGenerateMangaFolderName: TCheckBox; cbOptionMinimizeToTray: TCheckBox; cbOptionAutoNumberChapter: TCheckBox; - cbOptionAutoCheckFavStartup: TCheckBox; cbSearchFromAllSites: TCheckBox; ckFilterDoujinshi: TCheckBox; ckFilterDrama: TCheckBox; @@ -203,12 +204,12 @@ TMainForm = class(TForm) IconList: TImageList; itSaveDownloadedList: TIdleTimer; itRefreshDLInfo: TIdleTimer; - itCheckForChapters: TIdleTimer; + itCheckFav: TIdleTimer; itAnimate: TIdleTimer; imCover: TImage; lbOptionCustomRename: TLabel; lbOptionPDFQuality: TLabel; - lbOptionAutoCheckMinutes: TLabel; + lbOptionAutoCheckFavIntervalMinutes: TLabel; lbOptionLetFMDDo: TLabel; lbOptionNewMangaTime: TLabel; lbOptionLanguage: TLabel; @@ -288,7 +289,7 @@ TMainForm = class(TForm) seOptionConnectionTimeout: TSpinEdit; seOptionMaxThread: TSpinEdit; seOptionNewMangaTime: TSpinEdit; - seOptionCheckMinutes: TSpinEdit; + seOptionAutoCheckFavIntervalMinutes: TSpinEdit; seOptionPDFQuality: TSpinEdit; seOptionDigitVolume: TSpinEdit; seOptionDigitChapter: TSpinEdit; @@ -336,10 +337,10 @@ TMainForm = class(TForm) var CanShow: Boolean; var HintInfo: THintInfo); procedure btAddToFavoritesClick(Sender: TObject); procedure btAbortUpdateListClick(Sender: TObject); - procedure btAbortCheckVersionClick(Sender: TObject); + procedure btAbortCheckLatestVersionClick(Sender: TObject); procedure btCancelFavoritesCheckClick(Sender: TObject); procedure btChecksClick(Sender: TObject); - procedure btCheckVersionClick(Sender: TObject); + procedure btCheckLatestVersionClick(Sender: TObject); procedure btDonateClick(Sender: TObject); procedure btFavoritesImportClick(Sender: TObject); procedure btReadOnlineClick(Sender: TObject); @@ -348,6 +349,7 @@ TMainForm = class(TForm) procedure btURLClick(Sender: TObject); procedure btVisitMyBlogClick(Sender: TObject); procedure btWebsitesSearchClearClick(Sender: TObject); + procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); @@ -388,7 +390,7 @@ TMainForm = class(TForm) procedure FormShow(Sender: TObject); procedure FormWindowStateChange(Sender: TObject); procedure itAnimateTimer(Sender: TObject); - procedure itCheckForChaptersTimer(Sender: TObject); + procedure itCheckFavTimer(Sender: TObject); procedure itMonitorTimer(Sender: TObject); procedure itRefreshDLInfoStartTimer(Sender: TObject); procedure itRefreshDLInfoStopTimer(Sender: TObject); @@ -444,7 +446,7 @@ TMainForm = class(TForm) procedure pmSbMainPopup(Sender: TObject); procedure sbUpdateListDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); - procedure seOptionCheckMinutesChange(Sender: TObject); + procedure seOptionAutoCheckFavIntervalMinutesChange(Sender: TObject); procedure spMainSplitterMoved(Sender: TObject); procedure tbDownloadDeleteCompletedClick(Sender: TObject); procedure tbDownloadResumeAllClick(Sender: TObject); @@ -1114,7 +1116,7 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); tmBackup.Enabled := False; itSaveDownloadedList.Enabled := False; itRefreshDLInfo.Enabled := False; - itCheckForChapters.Enabled := False; + itCheckFav.Enabled := False; itAnimate.Enabled := False; itStartup.Enabled := False; itMonitor.Enabled := False; @@ -1212,11 +1214,11 @@ procedure TMainForm.itAnimateTimer(Sender: TObject); gifWaiting.Update(pbWait.Canvas, gifWaitingRect); end; -procedure TMainForm.itCheckForChaptersTimer(Sender: TObject); +procedure TMainForm.itCheckFavTimer(Sender: TObject); begin if IsDlgCounter then Exit; - if cbOptionAutoCheckUpdate.Checked then - btCheckVersionClick(btCheckVersion); + if OptionAutoCheckLatestVersion then + btCheckLatestVersionClick(btCheckLatestVersion); FavoriteManager.isAuto := True; FavoriteManager.CheckForNewChapter; end; @@ -1340,8 +1342,8 @@ procedure TMainForm.itStartupTimer(Sender: TObject); isStartup := True; if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); - if cbOptionAutoCheckUpdate.Checked then - btCheckVersionClick(btCheckVersion); + if OptionAutoCheckLatestVersion then + btCheckLatestVersionClick(btCheckLatestVersion); SubThread.Start; end; end; @@ -1884,7 +1886,7 @@ procedure TMainForm.btAbortUpdateListClick(Sender: TObject); updateList.Terminate; end; -procedure TMainForm.btAbortCheckVersionClick(Sender: TObject); +procedure TMainForm.btAbortCheckLatestVersionClick(Sender: TObject); begin if Assigned(CheckUpdateThread) then CheckUpdateThread.Terminate; @@ -2092,6 +2094,12 @@ procedure TMainForm.btWebsitesSearchClearClick(Sender: TObject); edWebsitesSearch.Clear; end; +procedure TMainForm.cbOptionAutoCheckFavIntervalChange(Sender: TObject); +begin + seOptionAutoCheckFavIntervalMinutes.Enabled := cbOptionAutoCheckFavInterval.Checked; + lbOptionAutoCheckFavIntervalMinutes.Enabled := cbOptionAutoCheckFavInterval.Checked; +end; + procedure TMainForm.cbOptionDigitChapterChange(Sender: TObject); begin seOptionDigitChapter.Enabled := cbOptionDigitChapter.Checked; @@ -2113,7 +2121,7 @@ procedure TMainForm.btSearchClearClick(Sender: TObject); edSearch.Clear; end; -procedure TMainForm.btCheckVersionClick(Sender: TObject); +procedure TMainForm.btCheckLatestVersionClick(Sender: TObject); begin if Assigned(CheckUpdateThread) then MessageDlg('', RS_DlgUpdaterIsRunning, mtInformation, [mbYes], 0) @@ -3353,10 +3361,10 @@ procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; end; end; -procedure TMainForm.seOptionCheckMinutesChange(Sender: TObject); +procedure TMainForm.seOptionAutoCheckFavIntervalMinutesChange(Sender: TObject); begin - lbOptionAutoCheckMinutes.Caption := - Format(RS_LblAutoCheckNewChapterMinute, [seOptionCheckMinutes.Value]); + lbOptionAutoCheckFavIntervalMinutes.Caption := + Format(RS_LblAutoCheckNewChapterMinute, [seOptionAutoCheckFavIntervalMinutes.Value]); end; procedure TMainForm.spMainSplitterMoved(Sender: TObject); @@ -4414,12 +4422,13 @@ procedure TMainForm.LoadOptions; seOptionDigitChapter.Enabled := cbOptionDigitChapter.Checked; // update - cbOptionAutoCheckUpdate.Checked := ReadBool('update', 'AutoCheckUpdate', True); + cbOptionAutoCheckLatestVersion.Checked := ReadBool('update', 'AutoCheckLatestVersion', True); cbOptionAutoCheckFavStartup.Checked := ReadBool('update', 'AutoCheckFavStartup', True); - seOptionCheckMinutes.Value := ReadInteger('update', 'AutoCheckMinutes', 60); - lbOptionAutoCheckMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionCheckMinutes.Value]); - cbOptionAutoDlFav.Checked := ReadBool('update', 'AutoDownloadFavorites', False); - cbOptionAutoRemoveCompletedManga.Checked := ReadBool('update', 'AutoRemoveCompletedManga', False); + cbOptionAutoCheckFavInterval.Checked := ReadBool('update', 'AutoCheckFavInterval', True); + seOptionAutoCheckFavIntervalMinutes.Value := ReadInteger('update', 'AutoCheckFavIntervalMinutes', 60); + lbOptionAutoCheckFavIntervalMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionAutoCheckFavIntervalMinutes.Value]); + cbOptionAutoCheckFavDownload.Checked := ReadBool('update', 'AutoCheckFavAutoDownload', False); + cbOptionAutoCheckFavRemoveCompletedManga.Checked := ReadBool('update', 'AutoCheckFavAutoRemoveCompletedManga', False); cbOptionUpdateListNoMangaInfo.Checked := ReadBool('update', 'UpdateListNoMangaInfo', False); cbOptionUpdateListRemoveDuplicateLocalData.Checked := ReadBool('update', 'UpdateListRemoveDuplicateLocalData', False); @@ -4529,11 +4538,12 @@ procedure TMainForm.SaveOptions; WriteInteger('saveto', 'DigitChapterLength', seOptionDigitChapter.Value); // update - WriteBool('update', 'AutoCheckUpdate', cbOptionAutoCheckUpdate.Checked); + WriteBool('update', 'AutoCheckLatestVersion', cbOptionAutoCheckLatestVersion.Checked); WriteBool('update', 'AutoCheckFavStartup', cbOptionAutoCheckFavStartup.Checked); - WriteInteger('update', 'AutoCheckMinutes', seOptionCheckMinutes.Value); - WriteBool('update', 'AutoDownloadFavorites', cbOptionAutoDlFav.Checked); - WriteBool('update', 'AutoRemoveCompletedManga', cbOptionAutoRemoveCompletedManga.Checked); + WriteBool('update', 'AutoCheckFavInterval', cbOptionAutoCheckFavInterval.Checked); + WriteInteger('update', 'AutoCheckFavIntervalMinutes', seOptionAutoCheckFavIntervalMinutes.Value); + WriteBool('update', 'AutoCheckFavAutoDownloadFavorites', cbOptionAutoCheckFavDownload.Checked); + WriteBool('update', 'AutoCheckFavAutoRemoveCompletedManga', cbOptionAutoCheckFavRemoveCompletedManga.Checked); WriteBool('update', 'UpdateListNoMangaInfo', cbOptionUpdateListNoMangaInfo.Checked); WriteBool('update', 'UpdateListRemoveDuplicateLocalData', cbOptionUpdateListRemoveDuplicateLocalData.Checked); @@ -4647,23 +4657,21 @@ procedure TMainForm.ApplyOptions; DLManager.compress := rgOptionCompress.ItemIndex; //update - OptionAutoRemoveCompletedManga := cbOptionAutoRemoveCompletedManga.Checked; + OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; OptionAutoCheckFavStartup := cbOptionAutoCheckFavStartup.Checked; - OptionCheckMinutes := seOptionCheckMinutes.Value; - if OptionCheckMinutes = 0 then - itCheckForChapters.Enabled := False - else - begin - itCheckForChapters.Interval := OptionCheckMinutes * 60000; - itCheckForChapters.Enabled := True; - end; - OptionAutoDlFav := cbOptionAutoDlFav.Checked; + OptionAutoCheckFavInterval := cbOptionAutoCheckFavInterval.Checked; + OptionAutoCheckFavIntervalMinutes := seOptionAutoCheckFavIntervalMinutes.Value; + OptionAutoCheckFavDownload := cbOptionAutoCheckFavDownload.Checked; + OptionAutoCheckFavRemoveCompletedManga := cbOptionAutoCheckFavRemoveCompletedManga.Checked; + if OptionAutoCheckFavIntervalMinutes <> 0 then + itCheckFav.Interval := OptionAutoCheckFavIntervalMinutes * 60000; + itCheckFav.Enabled := OptionAutoCheckLatestVersion and (OptionAutoCheckFavIntervalMinutes <> 0); OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; //misc - OptionShowBatotoSG := cbOptionBatotoShowScanGroup.Checked; - OptionShowAllLang := cbOptionBatotoShowAllLang.Checked; + OptionBatotoShowScanGroup := cbOptionBatotoShowScanGroup.Checked; + OptionBatotoShowAllLang := cbOptionBatotoShowAllLang.Checked; //languages ApplyLanguage; From d3bdddb6cded6bbd505eb16f5f806790b4313125 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 17:34:36 +0800 Subject: [PATCH 0368/2794] move auto check fav at startup from subthread to startup timer --- baseunits/uSubThread.pas | 6 ------ mangadownloader/forms/frmMain.pas | 8 +++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/uSubThread.pas b/baseunits/uSubThread.pas index dcf018a90..20c99d965 100644 --- a/baseunits/uSubThread.pas +++ b/baseunits/uSubThread.pas @@ -35,12 +35,6 @@ procedure TSubThread.Execute; begin MainForm.isSubthread := True; try - if OptionAutoCheckFavStartup then - begin - MainForm.FavoriteManager.isAuto := True; - MainForm.FavoriteManager.CheckForNewChapter; - end; - while not Terminated do begin with MainForm do diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a98ba7778..fcd174f2e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1344,7 +1344,13 @@ procedure TMainForm.itStartupTimer(Sender: TObject); OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if OptionAutoCheckLatestVersion then btCheckLatestVersionClick(btCheckLatestVersion); - SubThread.Start; + if OptionAutoCheckFavStartup then + begin + MainForm.FavoriteManager.isAuto := True; + MainForm.FavoriteManager.CheckForNewChapter; + end; + if Assigned(SubThread) then + SubThread.Start; end; end; From 3f1736e740b7963caf9924aa94610907dec36062 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 17:38:09 +0800 Subject: [PATCH 0369/2794] update translations --- mangadownloader/languages/fmd.en.po | 48 ++++++++++++++++---------- mangadownloader/languages/fmd.id_ID.po | 43 +++++++++++++---------- mangadownloader/languages/fmd.po | 37 ++++++++++++-------- 3 files changed, 76 insertions(+), 52 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 5fe159ade..b645e99d6 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -307,10 +307,11 @@ msgctxt "tmainform.btaddtofavorites.caption" msgid "Add to favorites" msgstr "Add to favorites" -#: tmainform.btcheckversion.caption -msgctxt "tmainform.btcheckversion.caption" -msgid "Check for new version" -msgstr "Check for new version" +#: tmainform.btchecklatestversion.caption +#| msgid "Check for new version" +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Check for latest version" #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" @@ -379,26 +380,35 @@ msgstr "" msgid "Search only new manga" msgstr "Search only new manga" -#: tmainform.cboptionautocheckfavstartup.caption -msgid "Automatic check for new chapter at startup" -msgstr "Automatic check for new chapter at startup" - -#: tmainform.cboptionautocheckupdate.caption -msgid "Check for new version " -msgstr "Check for new version " - -#: tmainform.cboptionautodlfav.caption +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" msgid "Automatic download after finish checking" msgstr "Automatic download after finish checking" -#: tmainform.cboptionautonumberchapter.caption -msgid "Auto number chapter" -msgstr "Auto number chapter" +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Auto check for new chapter in an interval" -#: tmainform.cboptionautoremovecompletedmanga.caption +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" msgid "Automatic remove completed manga from Favorites" msgstr "Automatic remove completed manga from Favorites" +#: tmainform.cboptionautocheckfavstartup.caption +#| msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" +msgstr "Auto check for new chapter at startup" + +#: tmainform.cboptionautochecklatestversion.caption +#| msgid "Check for new version " +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Auto check for latest version " + +#: tmainform.cboptionautonumberchapter.caption +msgid "Auto number chapter" +msgstr "Auto number chapter" + #: tmainform.cboptionbatotoshowalllang.caption msgctxt "tmainform.cboptionbatotoshowalllang.caption" msgid "[Batoto] Show All Language" @@ -978,8 +988,8 @@ msgstr "Title" msgid "Mode: Show all (0)" msgstr "Mode: Show all (0)" -#: tmainform.lboptionautocheckminutes.caption -msgctxt "tmainform.lboptionautocheckminutes.caption" +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index a82b2b508..fe750fc48 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -301,10 +301,10 @@ msgctxt "tmainform.btaddtofavorites.caption" msgid "Add to favorites" msgstr "Tambahkan ke kesukaan" -#: tmainform.btcheckversion.caption -msgctxt "tmainform.btcheckversion.caption" -msgid "Check for new version" -msgstr "Periksa versi baru" +#: tmainform.btchecklatestversion.caption +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Periksa versi terbaru" #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" @@ -373,26 +373,33 @@ msgstr "" msgid "Search only new manga" msgstr "Cari hanya komik baru" +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Otomatis mengunduh setelah selesai memeriksa" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Otomatis periksa bab baru dalam interval" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Otomatis hapus komik yang sudah tamat dari daftar kesukaan" + #: tmainform.cboptionautocheckfavstartup.caption -msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" msgstr "Otomatis periksa bab baru saat program dimulai" -#: tmainform.cboptionautocheckupdate.caption -msgid "Check for new version " -msgstr "Periksa versi baru" - -#: tmainform.cboptionautodlfav.caption -msgid "Automatic download after finish checking" -msgstr "Otomatis mengunduh setelah selesai memeriksa" +#: tmainform.cboptionautochecklatestversion.caption +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Periksa versi terbaru" #: tmainform.cboptionautonumberchapter.caption msgid "Auto number chapter" msgstr "Otomatis nomor bab" -#: tmainform.cboptionautoremovecompletedmanga.caption -msgid "Automatic remove completed manga from Favorites" -msgstr "Otomatis hapus komik yang sudah tamat dari daftar kesukaan" - #: tmainform.cboptionbatotoshowalllang.caption msgctxt "tmainform.cboptionbatotoshowalllang.caption" msgid "[Batoto] Show All Language" @@ -967,8 +974,8 @@ msgstr "Judul" msgid "Mode: Show all (0)" msgstr "Mode: Tampilkan semua (0)" -#: tmainform.lboptionautocheckminutes.caption -msgctxt "tmainform.lboptionautocheckminutes.caption" +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" msgid "Auto check for new chapter every %d minutes" msgstr "Otomatis periksa bab baru setiap %d menit" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index a4f743a7a..2a54235ba 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -273,9 +273,9 @@ msgctxt "tmainform.btaddtofavorites.caption" msgid "Add to favorites" msgstr "" -#: tmainform.btcheckversion.caption -msgctxt "tmainform.btcheckversion.caption" -msgid "Check for new version" +#: tmainform.btchecklatestversion.caption +msgctxt "TMAINFORM.BTCHECKLATESTVERSION.CAPTION" +msgid "Check for latest version" msgstr "" #: tmainform.btdownload.caption @@ -345,24 +345,31 @@ msgstr "" msgid "Search only new manga" msgstr "" -#: tmainform.cboptionautocheckfavstartup.caption -msgid "Automatic check for new chapter at startup" +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVDOWNLOAD.CAPTION" +msgid "Automatic download after finish checking" msgstr "" -#: tmainform.cboptionautocheckupdate.caption -msgid "Check for new version " +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" msgstr "" -#: tmainform.cboptionautodlfav.caption -msgid "Automatic download after finish checking" +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVREMOVECOMPLETEDMANGA.CAPTION" +msgid "Automatic remove completed manga from Favorites" msgstr "" -#: tmainform.cboptionautonumberchapter.caption -msgid "Auto number chapter" +#: tmainform.cboptionautocheckfavstartup.caption +msgid "Auto check for new chapter at startup" msgstr "" -#: tmainform.cboptionautoremovecompletedmanga.caption -msgid "Automatic remove completed manga from Favorites" +#: tmainform.cboptionautochecklatestversion.caption +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" +msgid "Auto check for latest version " +msgstr "" + +#: tmainform.cboptionautonumberchapter.caption +msgid "Auto number chapter" msgstr "" #: tmainform.cboptionbatotoshowalllang.caption @@ -928,8 +935,8 @@ msgstr "" msgid "Mode: Show all (0)" msgstr "" -#: tmainform.lboptionautocheckminutes.caption -msgctxt "tmainform.lboptionautocheckminutes.caption" +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "TMAINFORM.LBOPTIONAUTOCHECKFAVINTERVALMINUTES.CAPTION" msgid "Auto check for new chapter every %d minutes" msgstr "" From cdac5ca525fbec8dd3a55cb99a36ca04798114de Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 20:45:29 +0800 Subject: [PATCH 0370/2794] update translations --- mangadownloader/languages/fmd.id_ID.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index fe750fc48..987281719 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -394,7 +394,7 @@ msgstr "Otomatis periksa bab baru saat program dimulai" #: tmainform.cboptionautochecklatestversion.caption msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " -msgstr "Periksa versi terbaru" +msgstr "Otomatis periksa versi terbaru" #: tmainform.cboptionautonumberchapter.caption msgid "Auto number chapter" From 9cdaa9db5943098bb13aa829280fb8dbd4d40d3e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 21:28:26 +0800 Subject: [PATCH 0371/2794] remove subthread and do checkout silentthread inside silentthreadmanager itself --- baseunits/uSilentThread.pas | 100 ++++++++++++++++++++++++++---- baseunits/uSubThread.pas | 60 ------------------ mangadownloader/forms/frmMain.pas | 23 +++---- 3 files changed, 94 insertions(+), 89 deletions(-) delete mode 100644 baseunits/uSubThread.pas diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 3b5e46b94..6a5cd9281 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -16,7 +16,7 @@ interface uses Classes, SysUtils, uBaseUnit, uData, uFMDThread, uDownloadsManager, - blcksock, syncobjs; + syncobjs; type @@ -26,8 +26,8 @@ TSilentThreadMetaData = class public MetaDataType: TMetaDataType; Website, Title, URL, SaveTo: String; - constructor Create(const AType: TMetaDataType; const AWebsite, AManga, - AURL, APath: String); + constructor Create(const AType: TMetaDataType; + const AWebsite, AManga, AURL, APath: String); end; TSilentThreadManager = class; @@ -58,11 +58,24 @@ TSilentAddToFavThread = class(TSilentThread) procedure MainThreadAfterChecking; override; end; + { TSilentThreadManagerThread } + + TSilentThreadManagerThread = class(TFMDThread) + protected + procedure Execute; override; + public + Manager: TSilentThreadManager; + destructor Destroy; override; + end; + { TSilentThreadManager } TSilentThreadManager = class - protected + private + FLockAdd: Boolean; + FManagerThread: TSilentThreadManagerThread; function GetItemCount: Integer; + procedure StartManagerThread; public CS_Threads: TCriticalSection; DLManager: TDownloadManager; @@ -73,6 +86,8 @@ TSilentThreadManager = class procedure CheckOut; procedure StopAll(WaitFor: Boolean = True); procedure UpdateLoadStatus; + procedure BeginAdd; + procedure EndAdd; property ItemCount: Integer read GetItemCount; constructor Create; destructor Destroy; override; @@ -86,6 +101,28 @@ implementation uses frmMain; +{ TSilentThreadManagerThread } + +procedure TSilentThreadManagerThread.Execute; +begin + if Manager = nil then Exit; + while (not Terminated) and (Manager.MetaData.Count > 0) do + begin + while Manager.Threads.Count >= Manager.DLManager.maxDLThreadsPerTask do + begin + if Terminated then Exit; + Sleep(500); + end; + Manager.CheckOut; + end; +end; + +destructor TSilentThreadManagerThread.Destroy; +begin + Manager.FManagerThread := nil; + inherited Destroy; +end; + { TSilentThreadManager } function TSilentThreadManager.GetItemCount: Integer; @@ -98,8 +135,18 @@ function TSilentThreadManager.GetItemCount: Integer; end; end; -procedure TSilentThreadManager.Add(AType: TMetaDataType; AWebsite, AManga, - AURL: String; ASavePath: String = ''); +procedure TSilentThreadManager.StartManagerThread; +begin + if FManagerThread = nil then + begin + FManagerThread := TSilentThreadManagerThread.Create; + FManagerThread.Manager := Self; + FManagerThread.Start; + end; +end; + +procedure TSilentThreadManager.Add(AType: TMetaDataType; + AWebsite, AManga, AURL: String; ASavePath: String = ''); begin if not ((AType = MD_AddToFavorites) and (MainForm.FavoriteManager.IsMangaExist(AManga, AWebsite))) then @@ -111,7 +158,11 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; AWebsite, AManga, finally CS_Threads.Release; end; - UpdateLoadStatus; + if not FLockAdd then + begin + StartManagerThread; + UpdateLoadStatus; + end; end; end; @@ -126,7 +177,8 @@ procedure TSilentThreadManager.CheckOut; MD_DownloadAll: Threads.Add(TSilentThread.Create); MD_AddToFavorites: Threads.Add(TSilentAddToFavThread.Create); end; - with TSilentThread(Threads.Last) do begin + with TSilentThread(Threads.Last) do + begin Manager := Self; website := TSilentThreadMetaData(MetaData.First).Website; title := TSilentThreadMetaData(MetaData.First).Title; @@ -155,6 +207,12 @@ procedure TSilentThreadManager.StopAll(WaitFor: Boolean); TSilentThreadMetaData(MetaData.Last).Free; MetaData.Remove(MetaData.Last); end; + if Assigned(FManagerThread) then + begin + FManagerThread.Terminate; + if WaitFor then + FManagerThread.WaitFor; + end; if Threads.Count > 0 then for i := 0 to Threads.Count - 1 do TSilentThread(Threads[i]).Terminate; @@ -162,10 +220,8 @@ procedure TSilentThreadManager.StopAll(WaitFor: Boolean); CS_Threads.Release; end; if WaitFor then - begin while ItemCount > 0 do Sleep(100); - end; end; end; @@ -178,12 +234,28 @@ procedure TSilentThreadManager.UpdateLoadStatus; MainForm.sbMain.Panels[1].Text := ''; end; +procedure TSilentThreadManager.BeginAdd; +begin + FLockAdd := True; +end; + +procedure TSilentThreadManager.EndAdd; +begin + FLockAdd := False; + if (MetaData.Count > 0) then + begin + StartManagerThread; + UpdateLoadStatus; + end; +end; + constructor TSilentThreadManager.Create; begin inherited Create; CS_Threads := TCriticalSection.Create; MetaData := TFPList.Create; Threads := TFPList.Create; + FLockAdd := False; end; destructor TSilentThreadManager.Destroy; @@ -305,8 +377,10 @@ procedure TSilentThread.MainThreadAfterChecking; // save downloaded chapters if Info.mangaInfo.chapterLinks.Count > 0 then begin - DLManager.AddToDownloadedChaptersList(Info.mangaInfo.website + URL, Info.mangaInfo.chapterLinks); - FavoriteManager.AddToDownloadedChaptersList(Info.mangaInfo.website, URL, Info.mangaInfo.chapterLinks); + DLManager.AddToDownloadedChaptersList(Info.mangaInfo.website + + URL, Info.mangaInfo.chapterLinks); + FavoriteManager.AddToDownloadedChaptersList(Info.mangaInfo.website, + URL, Info.mangaInfo.chapterLinks); end; end; except @@ -373,7 +447,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; title := Info.mangaInfo.title; if FSavePath = '' then begin - if Trim(edSaveTo.Text) = '' then + if Trim(edSaveTo.Text) = '' then edSaveTo.Text := options.ReadString('saveto', 'SaveTo', DEFAULT_PATH); if Trim(edSaveTo.Text) = '' then edSaveTo.Text := DEFAULT_PATH; diff --git a/baseunits/uSubThread.pas b/baseunits/uSubThread.pas deleted file mode 100644 index 20c99d965..000000000 --- a/baseunits/uSubThread.pas +++ /dev/null @@ -1,60 +0,0 @@ -{ - File: uSubThread.pas - License: GPLv2 - This unit is a part of Free Manga Downloader -} - -unit uSubThread; - -{$mode delphi} - -interface - -uses - Classes, SysUtils, Controls, Forms, uBaseUnit, uFMDThread; - -type - - { TSubThread } - - TSubThread = class(TFMDThread) - protected - procedure Execute; override; - public - destructor Destroy; override; - end; - -implementation - -uses - frmMain; - -{ TSubThread } - -procedure TSubThread.Execute; -begin - MainForm.isSubthread := True; - try - while not Terminated do - begin - with MainForm do - begin - while (SilentThreadManager.MetaData.Count > 0) and - (SilentThreadManager.Threads.Count < DLManager.maxDLThreadsPerTask) do - SilentThreadManager.CheckOut; - end; - Sleep(500); - end; - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); - end; -end; - -destructor TSubThread.Destroy; -begin - MainForm.isSubthread := False; - inherited Destroy; -end; - -end. diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fcd174f2e..441410bc7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -21,7 +21,7 @@ interface simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, - uUpdateDBThread, uSubThread, uSilentThread, uMisc, uGetMangaInfosThread, + uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, CheckUpdate, USimpleException, USimpleLogger; type @@ -572,8 +572,6 @@ TMainForm = class(TForm) gifWaitingRect: TRect; // doing stuff like get manga info, compress, ... - SubThread: TSubThread; - isSubthread: Boolean; GetInfosThread: TGetMangaInfosThread; isGetMangaInfos: Boolean; @@ -943,13 +941,10 @@ procedure TMainForm.FormCreate(Sender: TObject); InitSimpleExceptionHandler; AddIgnoredException('EImagingError'); AddIgnoredException('ERegExpr'); - SilentThreadManager := TSilentThreadManager.Create; btAbortUpdateList.Parent := sbUpdateList; - INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_ADVANCED); isRunDownloadFilter := False; isUpdating := False; isExiting := False; - isSubthread := False; isGetMangaInfos := False; DoAfterFMD := DO_NOTHING; Application.HintHidePause := 10000; @@ -963,6 +958,9 @@ procedure TMainForm.FormCreate(Sender: TObject); TrayIcon.Icon.Assign(Application.Icon); PrevWindowState := wsNormal; + // advanced settings + INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_ADVANCED); + //main dataprocess dataProcess := TDBDataProcess.Create; @@ -976,8 +974,9 @@ procedure TMainForm.FormCreate(Sender: TObject); FavoriteManager.OnUpdateDownload := @UpdateVtDownload; FavoriteManager.DLManager := DLManager; - // subthread - SubThread := TSubThread.Create; + // download all / add to favorites + SilentThreadManager := TSilentThreadManager.Create; + SilentThreadManager.DLManager := Self.DLManager; // ShowInformation mangaInfo := TMangaInfo.Create; @@ -1129,12 +1128,6 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); if WaitFor then GetInfosThread.WaitFor; end; - if isSubthread then - begin - SubThread.Terminate; - if WaitFor then - SubThread.WaitFor; - end; if isUpdating then begin updateList.Terminate; @@ -1349,8 +1342,6 @@ procedure TMainForm.itStartupTimer(Sender: TObject); MainForm.FavoriteManager.isAuto := True; MainForm.FavoriteManager.CheckForNewChapter; end; - if Assigned(SubThread) then - SubThread.Start; end; end; From ac59198be5a337150aa1876a64f9c3a624032076 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 21:37:19 +0800 Subject: [PATCH 0372/2794] mainform, use batch when adding silentthread --- mangadownloader/forms/frmMain.pas | 39 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 441410bc7..a8468adcf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1555,8 +1555,8 @@ procedure TMainForm.miFavoritesDownloadAllClick(Sender: TObject); i: Integer; xNode: PVirtualNode; begin - if vtFavorites.SelectedCount = 0 then - Exit; + if vtFavorites.SelectedCount = 0 then Exit; + SilentThreadManager.BeginAdd; try xNode := vtFavorites.GetFirstSelected; for i := 0 to vtFavorites.SelectedCount - 1 do @@ -1570,6 +1570,7 @@ procedure TMainForm.miFavoritesDownloadAllClick(Sender: TObject); on E: Exception do ExceptionHandler(Self, E); end; + SilentThreadManager.EndAdd; end; procedure TMainForm.miFavoritesStopCheckNewChapterClick(Sender: TObject); @@ -2475,19 +2476,23 @@ procedure TMainForm.miMangaListAddToFavoritesClick(Sender: TObject); i: Cardinal; xNode: PVirtualNode; begin - if vtMangaList.SelectedCount = 0 then - Exit; - xNode := vtMangaList.GetFirstSelected; - for i := 0 to vtMangaList.SelectedCount - 1 do - begin - if vtMangaList.Selected[xNode] then + if vtMangaList.SelectedCount = 0 then Exit; + SilentThreadManager.BeginAdd; + try + xNode := vtMangaList.GetFirstSelected; + for i := 0 to vtMangaList.SelectedCount - 1 do begin - SilentThreadManager.Add(MD_AddToFavorites, - dataProcess.WebsiteName[xNode^.Index], - DataProcess.Value[xNode^.Index, DATA_PARAM_TITLE], - DataProcess.Value[xNode^.Index, DATA_PARAM_LINK]); + if vtMangaList.Selected[xNode] then + begin + SilentThreadManager.Add(MD_AddToFavorites, + dataProcess.WebsiteName[xNode^.Index], + DataProcess.Value[xNode^.Index, DATA_PARAM_TITLE], + DataProcess.Value[xNode^.Index, DATA_PARAM_LINK]); + end; + xNode := vtMangaList.GetNextSelected(xNode); end; - xNode := vtMangaList.GetNextSelected(xNode); + finally + SilentThreadManager.EndAdd; end; end; @@ -2865,8 +2870,9 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); mResult: TModalResult; mBtns: TMsgDlgButtons; begin - if vtMangaList.SelectedCount = 0 then - Exit; + if vtMangaList.SelectedCount = 0 then Exit; + + SilentThreadManager.BeginAdd; try YesAll := False; NoAll := False; @@ -2928,6 +2934,7 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); on E: Exception do ExceptionHandler(Self, E); end; + SilentThreadManager.EndAdd; end; procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); @@ -4210,6 +4217,7 @@ procedure TMainForm.AddSilentThread(URL: string); URls.Text := URL; if URls.Count > 0 then begin + SilentThreadManager.BeginAdd; with TRegExpr.Create do try Expression := REGEX_HOST; @@ -4245,6 +4253,7 @@ procedure TMainForm.AddSilentThread(URL: string); finally Free; end; + SilentThreadManager.EndAdd; end; finally URls.Free; From 769ad2576f5bad88163254366d51201178843c78 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 21:42:38 +0800 Subject: [PATCH 0373/2794] rename optionmaxretry --- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.pas | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ce48e6a67..082b4f7b3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -665,7 +665,7 @@ interface OptionAutoNumberChapterChecked: Boolean = True; OptionPDFQuality: Cardinal = 95; - OptionMaxRetry: Integer = 0; + OptionConnectionMaxRetry: Integer = 0; OptionConnectionTimeout: Integer = 15000; OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a8468adcf..fff550d53 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4636,10 +4636,10 @@ procedure TMainForm.ApplyOptions; //connection OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; - OptionMaxRetry := seOptionMaxRetry.Value; + OptionConnectionMaxRetry := seOptionMaxRetry.Value; DLManager.maxDLTasks := seOptionMaxParallel.Value; DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; - DLManager.retryConnect := OptionMaxRetry; + DLManager.retryConnect := OptionConnectionMaxRetry; if cbOptionUseProxy.Checked then begin OptionProxyType := cbOptionProxyType.Text; From c833fa2c6ecec29b8d5a29cda6565cad3a509f1e Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 21:42:52 +0800 Subject: [PATCH 0374/2794] use global maxretry --- baseunits/uSilentThread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 6a5cd9281..3d6dfcf7f 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -242,7 +242,7 @@ procedure TSilentThreadManager.BeginAdd; procedure TSilentThreadManager.EndAdd; begin FLockAdd := False; - if (MetaData.Count > 0) then + if MetaData.Count > 0 then begin StartManagerThread; UpdateLoadStatus; @@ -403,7 +403,7 @@ procedure TSilentThread.Execute; try Synchronize(MainThreadUpdateStatus); Info.mangaInfo.title := title; - if Info.GetInfoFromURL(website, URL, Freconnect) = NO_ERROR then + if Info.GetInfoFromURL(website, URL, OptionConnectionMaxRetry) = NO_ERROR then if not Terminated then Synchronize(MainThreadAfterChecking); except From bea1a6fc75ca62824a0d5a47cb9fd6f14de4fc19 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 22:05:16 +0800 Subject: [PATCH 0375/2794] store maxthreads and use it instead dlmanager.maxdlthreads --- baseunits/uBaseUnit.pas | 2 ++ baseunits/uSilentThread.pas | 3 +-- mangadownloader/forms/frmMain.pas | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 082b4f7b3..b7197d1dd 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -670,6 +670,8 @@ interface OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; + OptionMaxThreads: Integer = 1; + OptionEnableLoadCover: Boolean = False; OptionAutoCheckLatestVersion: Boolean = True; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 3d6dfcf7f..9e21a9591 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -78,7 +78,6 @@ TSilentThreadManager = class procedure StartManagerThread; public CS_Threads: TCriticalSection; - DLManager: TDownloadManager; MetaData: TFPList; Threads: TFPList; procedure Add(AType: TMetaDataType; AWebsite, AManga, AURL: String; @@ -108,7 +107,7 @@ procedure TSilentThreadManagerThread.Execute; if Manager = nil then Exit; while (not Terminated) and (Manager.MetaData.Count > 0) do begin - while Manager.Threads.Count >= Manager.DLManager.maxDLThreadsPerTask do + while Manager.Threads.Count >= OptionMaxThreads do begin if Terminated then Exit; Sleep(500); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fff550d53..a9a163edb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -972,11 +972,9 @@ procedure TMainForm.FormCreate(Sender: TObject); FavoriteManager := TFavoriteManager.Create; FavoriteManager.OnUpdateFavorite := @UpdateVtFavorites; FavoriteManager.OnUpdateDownload := @UpdateVtDownload; - FavoriteManager.DLManager := DLManager; // download all / add to favorites SilentThreadManager := TSilentThreadManager.Create; - SilentThreadManager.DLManager := Self.DLManager; // ShowInformation mangaInfo := TMangaInfo.Create; @@ -4637,6 +4635,7 @@ procedure TMainForm.ApplyOptions; //connection OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; OptionConnectionMaxRetry := seOptionMaxRetry.Value; + OptionMaxThreads := seOptionMaxThread.Value; DLManager.maxDLTasks := seOptionMaxParallel.Value; DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; DLManager.retryConnect := OptionConnectionMaxRetry; From ec8ae2c3744b6e38397db9e842148a74f0a3ac83 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 22:08:28 +0800 Subject: [PATCH 0376/2794] use global maxretry --- baseunits/uFavoritesManager.pas | 4 ++-- baseunits/uUpdateThread.pas | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index fccd8efb0..775138b75 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -188,7 +188,7 @@ procedure TFavoriteThread.Execute; Synchronize(SyncStatus); getInfo.mangaInfo.title := container.FavoriteInfo.Title; getInfo.GetInfoFromURL(container.FavoriteInfo.Website, - container.FavoriteInfo.Link, container.Manager.DLManager.retryConnect); + container.FavoriteInfo.Link, OptionConnectionMaxRetry); if container.MangaInfo = nil then container.MangaInfo := TMangaInfo.Create; TransferMangaInfo(container.MangaInfo, getInfo.mangaInfo); @@ -320,7 +320,7 @@ procedure TFavoriteTask.Execute; CheckOut; while statuscheck > 0 do begin - while (not Terminated) and (threads.Count >= manager.DLManager.maxDLThreadsPerTask) do + while (not Terminated) and (threads.Count >= OptionMaxThreads) do Sleep(SOCKHEARTBEATRATE); if Terminated then Break; CheckOut; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 759445fd2..833e28f4e 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -218,7 +218,7 @@ procedure TUpdateMangaThread.Execute; begin Info.mangaInfo.title := manager.names[workPtr]; Info.GetInfoFromURL(manager.website, manager.links[workPtr], - MainForm.DLManager.retryConnect); + OptionConnectionMaxRetry); if not Terminated then begin manager.CS_AddInfoToData.Acquire; From 2800fc0a02b7985fcbad89c65c35495520557217 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 22:10:54 +0800 Subject: [PATCH 0377/2794] restore default view --- mangadownloader/forms/frmMain.lfm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 384442ce2..9787e513f 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -35,13 +35,13 @@ object MainForm: TMainForm Height = 508 Top = 11 Width = 614 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1829,10 +1829,10 @@ object MainForm: TMainForm Height = 403 Top = 8 Width = 587 - ActivePage = tsUpdate + ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2705,7 +2705,7 @@ object MainForm: TMainForm Left = 16 Height = 15 Top = 8 - Width = 165 + Width = 158 Caption = 'Show dialog confirmation for:' ParentColor = False end From 54caeb62cd97f5d82c7a3f4c6c43f37fefb0afc7 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 2 Aug 2015 22:13:30 +0800 Subject: [PATCH 0378/2794] only loadoptions if changing to tab options --- mangadownloader/forms/frmMain.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a9a163edb..008741083 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3089,7 +3089,8 @@ procedure TMainForm.pcMainChange(Sender: TObject); else if pcMain.ActivePage = tsFavorites then vtFavorites.Repaint; - LoadOptions; + if pcMain.ActivePage = tsOption then + LoadOptions; end; procedure TMainForm.pmDownloadPopup(Sender: TObject); From 5953b4c15e0db078a6dfa44172c4cb4b45f472ea Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:33:53 +0800 Subject: [PATCH 0379/2794] update user agent --- baseunits/uMisc.pas | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index 36c03a18f..d06bf9ed9 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -76,14 +76,17 @@ procedure DeleteArrayOfString(Var TheStrings: TArrayOfString; Index: Integer); const UA_CURL = 'curl/7.42.1'; - UA_MSIE = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; - UA_FIREFOX = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0'; - UA_CHROME = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36'; - UA_OPERA = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0'; UA_GOOGLEBOT = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; + UA_MSIE = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; + UA_FIREFOX = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0'; + UA_CHROME = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36'; + UA_OPERA = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36 OPR/30.0.1835.125'; RANDOM_SLEEP = 3000; +var + DEFAULT_UA: String = UA_CHROME; + implementation { TIniFileR } From 1a1df3470c160ab2b57fcc6055420127c0ecc565 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:40:27 +0800 Subject: [PATCH 0380/2794] updater, change default user agent --- updater/uMain.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 422c4bfd4..98b27cb28 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -282,7 +282,10 @@ procedure TDownloadThread.Execute; FHTTP.Clear; FHTTP.Cookies.Clear; FHTTP.Protocol := '1.1'; - FHTTP.UserAgent := UA_FIREFOX; + if isSFURL then + FHTTP.UserAgent := UA_CURL + else + FHTTP.UserAgent := DEFAULT_UA; FHTTP.Timeout := 30000; if ProxyType = 'HTTP' then @@ -340,7 +343,6 @@ procedure TDownloadThread.Execute; regx.ModifierI := True; if isSFURL then begin - FHTTP.UserAgent := UA_CURL; regx.Expression := '/download$'; URL := Trim(regx.Replace(URL, '', False)); //**parsing SF url From 535c2a14be357037aca697cce684a4c4ad26266c Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:43:48 +0800 Subject: [PATCH 0381/2794] updater, minor changes --- updater/uMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 98b27cb28..c2e844d2f 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -338,8 +338,8 @@ procedure TDownloadThread.Execute; HTTPHeaders := TStringList.Create; regx := TRegExpr.Create; try - PrepareHTTP(FHTTP); HTTPHeaders.NameValueSeparator := ':'; + PrepareHTTP(FHTTP); regx.ModifierI := True; if isSFURL then begin From 6547b5c12c995b996c3dc39df4fa0dc6a89e0927 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:45:31 +0800 Subject: [PATCH 0382/2794] updater, set connection timeout to 10 seconds --- updater/uMain.pas | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index c2e844d2f..570085ba7 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -286,7 +286,12 @@ procedure TDownloadThread.Execute; FHTTP.UserAgent := UA_CURL else FHTTP.UserAgent := DEFAULT_UA; - FHTTP.Timeout := 30000; + with FHTTP do + begin + Timeout := 10000; + Sock.ConnectionTimeout := Timeout; + Sock.SetTimeout(Timeout); + end; if ProxyType = 'HTTP' then begin From b0d912d236017a42fa6fb77d38888d5532fa02b4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:47:52 +0800 Subject: [PATCH 0383/2794] baseunit, change default user agent and some clean up --- baseunits/uBaseUnit.pas | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b7197d1dd..a4e14f680 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2862,25 +2862,21 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; + HTTP.UserAgent := DEFAULT_UA; + HTTP.MimeType := ''; //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then begin HTTP.UserAgent := Trim(HTTPHeader.Values['User-Agent']); HTTPHeader.Delete(HTTPHeader.IndexOfName('User-Agent')); - end - else - if Trim(HTTP.UserAgent) = '' then - HTTP.UserAgent := UA_FIREFOX; + end; //MimeType if Trim(HTTPHeader.Values['Content-Type']) <> '' then begin HTTP.MimeType := Trim(HTTPHeader.Values['Content-Type']); HTTPHeader.Delete(HTTPHeader.IndexOfName('Content-Type')); - end - else - if Trim(HTTP.MimeType) = '' then - HTTP.MimeType := ''; + end; if isGZip then begin @@ -3155,25 +3151,21 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; + HTTP.UserAgent := DEFAULT_UA; + HTTP.MimeType := ''; //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then begin HTTP.UserAgent := Trim(HTTPHeader.Values['User-Agent']); HTTPHeader.Delete(HTTPHeader.IndexOfName('User-Agent')); - end - else - if Trim(HTTP.UserAgent) = '' then - HTTP.UserAgent := UA_FIREFOX; + end; //MimeType if Trim(HTTPHeader.Values['Content-Type']) <> '' then begin HTTP.MimeType := Trim(HTTPHeader.Values['Content-Type']); HTTPHeader.Delete(HTTPHeader.IndexOfName('Content-Type')); - end - else - if Trim(HTTP.MimeType) = '' then - HTTP.MimeType := ''; + end; if Pos('.imgur.com/', LowerCase(URL)) = 0 then if ((mangaSiteID >= 0) and (mangaSiteID <= High(WebsiteRoots))) then From fd16c759e03205f59a4c293b9f649d8fdcc91c97 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:54:02 +0800 Subject: [PATCH 0384/2794] store httusegzip as global variable --- baseunits/uBaseUnit.pas | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a4e14f680..656dab0ea 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -684,6 +684,8 @@ interface OptionBatotoShowScanGroup: Boolean = True; OptionBatotoShowAllLang: Boolean = True; + OptionHTTPUseGzip: Boolean = True; + type TArrayOfString = array of string; @@ -2756,14 +2758,11 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; // If AHTTP <> nil, we will use it as http sender. Otherwise we create a new // instance. var - //i: Cardinal; HTTP: THTTPSend; HTTPHeader: TStringList; counter: Integer; s: String; meth: String = 'GET'; - //zstream: TGZFileStream; - isGZip: Boolean = True; mstream: TMemoryStream; procedure HTTPClear; @@ -2865,6 +2864,9 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.UserAgent := DEFAULT_UA; HTTP.MimeType := ''; + if OptionHTTPUseGzip then + HTTPHeader.Values['Accept-Encoding'] := ' gzip, deflate'; + //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then begin @@ -2878,12 +2880,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPHeader.Delete(HTTPHeader.IndexOfName('Content-Type')); end; - if isGZip then - begin - //HTTP.MimeType := 'application/x-www-form-urlencoded'; - HTTPHeader.Values['Accept-Encoding'] := ' gzip, deflate'; - end; - if Pos(WebsiteRoots[MEINMANGA_ID, 1], URL) > 0 then HTTPHeader.Values['Accept-Charset'] := ' utf8' else From d1070bb8e2ed6677cf38dfc9d10cce6645c07290 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 3 Aug 2015 23:57:18 +0800 Subject: [PATCH 0385/2794] some clean up --- baseunits/uBaseUnit.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 656dab0ea..df62b538e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2862,7 +2862,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.UserAgent := DEFAULT_UA; - HTTP.MimeType := ''; + HTTP.MimeType := 'text/html'; if OptionHTTPUseGzip then HTTPHeader.Values['Accept-Encoding'] := ' gzip, deflate'; @@ -3056,7 +3056,6 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP: THTTPSend; counter: Integer; s: String; - //source : TPicture; fstream: TFileStreamUTF8; procedure preTerminate; @@ -3148,7 +3147,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.UserAgent := DEFAULT_UA; - HTTP.MimeType := ''; + HTTP.MimeType := 'text/html'; //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then @@ -3235,6 +3234,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Headers.Text := HTTPHeader.Text; end; end; + Initialize(header); HTTP.Document.Seek(0, soBeginning); HTTP.Document.Read(header[0], 4); if (header[0] = JPG_HEADER[0]) and From 61a7b42299f27c4d2465c69d8f41a57469698c1f Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 01:00:20 +0800 Subject: [PATCH 0386/2794] websitemodules, add maxtasklimit and maxconnectionlimit --- baseunits/WebsiteModules.pas | 54 +++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 5a4fa2bb4..24f8eb8be 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -40,8 +40,14 @@ TModuleContainer = class FTotalDirectory: Integer; procedure SetTotalDirectory(AValue: Integer); public - Website, RootURL: String; - SortedList, InformationAvailable, FavoriteAvailable: Boolean; + Website: String; + RootURL: String; + MaxTaskLimit: Integer; + MaxConnectionLimit: Integer; + ActiveConnectionCount: Integer; + SortedList: Boolean; + InformationAvailable: Boolean; + FavoriteAvailable: Boolean; TotalDirectoryPage: array of Integer; CurrentDirectoryIndex: Integer; OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; @@ -57,13 +63,15 @@ TModuleContainer = class { TWebsiteModules } - TWebsiteModules = class(TObject) + TWebsiteModules = class private FCSModules: TRTLCriticalSection; FModuleList: TFPList; - protected - function GetModule(const Index: Integer): TModuleContainer; + function GetModule(const ModuleId: Integer): TModuleContainer; function GetCount: Integer; + function GetMaxTaskLimit(const ModuleId: Integer): Integer; + function GetMaxConnectionLimit(const ModuleId: Integer): Integer; + function GetActiveConnectionLimit(const ModuleId: Integer): Integer; public constructor Create; destructor Destroy; override; @@ -111,8 +119,14 @@ TWebsiteModules = class(TObject) procedure LockModules; procedure UnlockModules; - property Module[const Index: Integer]: TModuleContainer read GetModule; + property Module[const ModuleId: Integer]: TModuleContainer read GetModule; property Count: Integer read GetCount; + + property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; + property MaxConnectionLimit[const ModuleId: Integer]: Integer + read GetMaxConnectionLimit; + property ActiveConnectionCount[const ModuleId: Integer]: Integer + read GetActiveConnectionLimit; end; var @@ -144,6 +158,9 @@ procedure TModuleContainer.SetTotalDirectory(AValue: Integer); constructor TModuleContainer.Create; begin + MaxTaskLimit := 0; + MaxConnectionLimit := 0; + ActiveConnectionCount := 0; SortedList := False; InformationAvailable := True; FavoriteAvailable := True; @@ -384,11 +401,10 @@ procedure TWebsiteModules.UnlockModules; LeaveCriticalsection(FCSModules); end; -function TWebsiteModules.GetModule(const Index: Integer): TModuleContainer; +function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; begin - if (Index < 0) or (Index >= FModuleList.Count) then - Exit(nil); - Result := TModuleContainer(FModuleList[Index]); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(nil); + Result := TModuleContainer(FModuleList[ModuleId]); end; function TWebsiteModules.GetCount: Integer; @@ -396,6 +412,24 @@ function TWebsiteModules.GetCount: Integer; Result := FModuleList.Count; end; +function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); + Result := TModuleContainer(FModuleList[ModuleId]).MaxTaskLimit; +end; + +function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); + Result := TModuleContainer(FModuleList[ModuleId]).MaxConnectionLimit; +end; + +function TWebsiteModules.GetActiveConnectionLimit(const ModuleId: Integer): Integer; +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); + Result := TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount; +end; + procedure doInitialize; begin if Modules = nil then From 84cbbe10d08e590a012e52a8dda04f2fbfb8bb5a Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 01:06:09 +0800 Subject: [PATCH 0387/2794] downloadmanager, applied connection limit from websitemodules --- baseunits/uDownloadsManager.pas | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 12d9f1594..d90dbadb4 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1283,10 +1283,15 @@ procedure TTaskThread.CheckOut; end else begin - case container.MangaSiteID of - EHENTAI_ID : currentMaxThread := 2; - else - currentMaxThread := container.Manager.maxDLThreadsPerTask; + if Modules.MaxConnectionLimit[ModuleId] > 0 then + currentMaxThread := Modules.MaxConnectionLimit[ModuleId] + else + begin + case container.MangaSiteID of + EHENTAI_ID : currentMaxThread := 2; + else + currentMaxThread := container.Manager.maxDLThreadsPerTask; + end; end; if currentMaxThread > container.Manager.maxDLThreadsPerTask then currentMaxThread := container.Manager.maxDLThreadsPerTask; @@ -1307,8 +1312,16 @@ procedure TTaskThread.CheckOut; Exit; end; - while (not Terminated) and (threads.Count >= currentMaxThread) do - Sleep(SOCKHEARTBEATRATE); + if ModuleId > -1 then + begin + while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do + Sleep(SOCKHEARTBEATRATE); + end + else + begin + while (not Terminated) and (threads.Count >= currentMaxThread) do + Sleep(SOCKHEARTBEATRATE); + end; end; if (not Terminated) and (threads.Count < currentMaxThread) then From e2dfe58c6817150a03d0d3da11e33f78298b4767 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 01:17:31 +0800 Subject: [PATCH 0388/2794] websitemodules, add activetaskcount --- baseunits/WebsiteModules.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 24f8eb8be..f9313e3d6 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -44,6 +44,7 @@ TModuleContainer = class RootURL: String; MaxTaskLimit: Integer; MaxConnectionLimit: Integer; + ActiveTaskCount: Integer; ActiveConnectionCount: Integer; SortedList: Boolean; InformationAvailable: Boolean; @@ -160,6 +161,7 @@ constructor TModuleContainer.Create; begin MaxTaskLimit := 0; MaxConnectionLimit := 0; + ActiveTaskCount := 0; ActiveConnectionCount := 0; SortedList := False; InformationAvailable := True; From 2cf40310acf661f34fea44d8deb207540a0ff789 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 01:26:18 +0800 Subject: [PATCH 0389/2794] websitemodules, add activetaskcount --- baseunits/WebsiteModules.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index f9313e3d6..a660db39c 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -72,6 +72,7 @@ TWebsiteModules = class function GetCount: Integer; function GetMaxTaskLimit(const ModuleId: Integer): Integer; function GetMaxConnectionLimit(const ModuleId: Integer): Integer; + function GetActiveTaskCount(const ModuleId: Integer): Integer; function GetActiveConnectionLimit(const ModuleId: Integer): Integer; public constructor Create; @@ -126,6 +127,8 @@ TWebsiteModules = class property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; property MaxConnectionLimit[const ModuleId: Integer]: Integer read GetMaxConnectionLimit; + property ActiveTaskCOunt[const ModuleId: Integer]: Integer + read GetActiveTaskCount; property ActiveConnectionCount[const ModuleId: Integer]: Integer read GetActiveConnectionLimit; end; @@ -426,6 +429,12 @@ function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer Result := TModuleContainer(FModuleList[ModuleId]).MaxConnectionLimit; end; +function TWebsiteModules.GetActiveTaskCount(const ModuleId: Integer): Integer; +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); + Result := TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount; +end; + function TWebsiteModules.GetActiveConnectionLimit(const ModuleId: Integer): Integer; begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); From df4346e1c3340756d8be5b780b5d994355dab206 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 02:35:23 +0800 Subject: [PATCH 0390/2794] websitemodules, clean up --- baseunits/WebsiteModules.pas | 113 ++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index a660db39c..ac6e1ec60 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -81,7 +81,7 @@ TWebsiteModules = class function AddModule: TModuleContainer; function LocateModule(const Website: String): Integer; function LocateModuleByHost(const Host: String): Integer; - function ModuleAvailable(const ModuleIndex: Integer; + function ModuleAvailable(const ModuleId: Integer; ModuleMethod: TModuleMethod): Boolean; overload; function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod): Boolean; overload; @@ -92,29 +92,29 @@ TWebsiteModules = class overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; const ModuleIndex: Integer): Integer; overload; + var Page: Integer; const ModuleId: Integer): Integer; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; const Website: String): Integer; overload; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; - const ModuleIndex: Integer): Integer; + const ModuleId: Integer): Integer; overload; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL, Website: String): Integer; overload; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; const ModuleIndex: Integer): Integer; overload; + const Reconnect: Integer; const ModuleId: Integer): Integer; overload; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Integer; const Website: String): Integer; overload; function GetPageNumber(var DownloadThread: TDownloadThread; - const URL: String; const ModuleIndex: Integer): Boolean; overload; + const URL: String; const ModuleId: Integer): Boolean; overload; function GetPageNumber(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; overload; function GetImageURL(var DownloadThread: TDownloadThread; - const URL: String; const ModuleIndex: Integer): Boolean; overload; + const URL: String; const ModuleId: Integer): Boolean; overload; function GetImageURL(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; overload; @@ -127,10 +127,13 @@ TWebsiteModules = class property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; property MaxConnectionLimit[const ModuleId: Integer]: Integer read GetMaxConnectionLimit; - property ActiveTaskCOunt[const ModuleId: Integer]: Integer - read GetActiveTaskCount; + property ActiveTaskCOunt[const ModuleId: Integer]: Integer read GetActiveTaskCount; property ActiveConnectionCount[const ModuleId: Integer]: Integer read GetActiveConnectionLimit; + procedure IncActiveTaskCount(ModuleId: Integer); + procedure DecActiveTaskCount(ModuleId: Integer); + procedure IncActiveConnectionCount(ModuleId: Integer); + procedure DecActiveConnectionCount(ModuleId: Integer); end; var @@ -258,14 +261,12 @@ function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; end; end; -function TWebsiteModules.ModuleAvailable(const ModuleIndex: Integer; +function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; ModuleMethod: TModuleMethod): Boolean; begin Result := False; - if (ModuleIndex < 0) or (FModuleList.Count = 0) or - (ModuleIndex >= FModuleList.Count) then - Exit; - with TModuleContainer(FModuleList[ModuleIndex]) do + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + with TModuleContainer(FModuleList[ModuleId]) do begin case ModuleMethod of MMGetDirectoryPageNumber: Result := Assigned(OnGetDirectoryPageNumber); @@ -306,15 +307,13 @@ function TWebsiteModules.ModuleAvailable(const Website: String; end; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; const ModuleIndex: Integer): Integer; + var Page: Integer; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleIndex < 0) or (FModuleList.Count = 0) or - (ModuleIndex >= FModuleList.Count) then - Exit; - if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetDirectoryPageNumber) then - Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetDirectoryPageNumber( - MangaInfo, Page, TModuleContainer(FModuleList[ModuleIndex])); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber) then + Result := TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber( + MangaInfo, Page, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; @@ -325,15 +324,13 @@ function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; - const ModuleIndex: Integer): Integer; + const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleIndex < 0) or (FModuleList.Count = 0) or - (ModuleIndex >= FModuleList.Count) then - Exit; - if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetNameAndLink) then - Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetNameAndLink( - MangaInfo, Names, Links, URL, TModuleContainer(FModuleList[ModuleIndex])); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink) then + Result := TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink( + MangaInfo, Names, Links, URL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; @@ -343,15 +340,13 @@ function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const URL: String; const Reconnect: Integer; const ModuleIndex: Integer): Integer; + const URL: String; const Reconnect: Integer; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleIndex < 0) or (FModuleList.Count = 0) or - (ModuleIndex >= FModuleList.Count) then - Exit; - if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetInfo) then - Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetInfo( - MangaInfo, URL, Reconnect, TModuleContainer(FModuleList[ModuleIndex])); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetInfo) then + Result := TModuleContainer(FModuleList[ModuleId]).OnGetInfo( + MangaInfo, URL, Reconnect, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; @@ -361,15 +356,13 @@ function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; end; function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; - const URL: String; const ModuleIndex: Integer): Boolean; + const URL: String; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleIndex < 0) or (FModuleList.Count = 0) or - (ModuleIndex >= FModuleList.Count) then - Exit; - if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber) then - Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetPageNumber( - DownloadThread, URL, TModuleContainer(FModuleList[ModuleIndex])); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetPageNumber) then + Result := TModuleContainer(FModuleList[ModuleId]).OnGetPageNumber( + DownloadThread, URL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; @@ -379,15 +372,13 @@ function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; end; function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; - const URL: String; const ModuleIndex: Integer): Boolean; + const URL: String; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleIndex < 0) or (FModuleList.Count = 0) or - (ModuleIndex >= FModuleList.Count) then - Exit; - if Assigned(TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL) then - Result := TModuleContainer(FModuleList[ModuleIndex]).OnGetImageURL( - DownloadThread, URL, TModuleContainer(FModuleList[ModuleIndex])); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetImageURL) then + Result := TModuleContainer(FModuleList[ModuleId]).OnGetImageURL( + DownloadThread, URL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; @@ -406,6 +397,32 @@ procedure TWebsiteModules.UnlockModules; LeaveCriticalsection(FCSModules); end; +procedure TWebsiteModules.IncActiveTaskCount(ModuleId: Integer); +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + InterLockedIncrement(TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount); +end; + +procedure TWebsiteModules.DecActiveTaskCount(ModuleId: Integer); +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount > 0 then + InterLockedDecrement(TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount); +end; + +procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + InterLockedIncrement(TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount); +end; + +procedure TWebsiteModules.DecActiveConnectionCount(ModuleId: Integer); +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount > 0 then + InterLockedDecrement(TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount); +end; + function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(nil); From 136fc92e3fdb985240bcd802ae70e67e9964aac0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 02:35:57 +0800 Subject: [PATCH 0391/2794] udata, minor changes --- baseunits/uData.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 015b98019..2b28cb826 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1862,7 +1862,7 @@ constructor TMangaInformation.Create(AOwnerThread: TFMDThread; if CreateInfo then mangaInfo := TMangaInfo.Create; isGetByUpdater := False; - ModuleId := -2; + ModuleId := -1; end; destructor TMangaInformation.Destroy; @@ -2012,7 +2012,7 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; else begin BROWSER_INVERT := False; - if ModuleId <> -1 then + if ModuleId < 0 then ModuleId := Modules.LocateModule(website); if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then Result := Modules.GetDirectoryPageNumber(Self, Page, ModuleId) @@ -2339,7 +2339,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website <> '' then FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); - if ModuleId <> -1 then + if ModuleId < 0 then ModuleId := Modules.LocateModule(website); if Modules.ModuleAvailable(ModuleId, MMGetNameAndLink) then Result := Modules.GetNameAndLink(Self, names, links, URL, ModuleId) @@ -2782,7 +2782,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; mangaInfo.chapterName.Clear; mangaInfo.chapterLinks.Clear; - if ModuleId <> -1 then + if ModuleId < 0 then ModuleId := Modules.LocateModule(website); if Modules.ModuleAvailable(ModuleId, MMGetInfo) then Result := Modules.GetInfo(Self, URL, Reconnect, ModuleId) From 8600933181e0b5fb666dd0b857eebd759d601ede Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 02:48:52 +0800 Subject: [PATCH 0392/2794] typo --- baseunits/WebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index ac6e1ec60..2d3c1cd9d 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -127,7 +127,7 @@ TWebsiteModules = class property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; property MaxConnectionLimit[const ModuleId: Integer]: Integer read GetMaxConnectionLimit; - property ActiveTaskCOunt[const ModuleId: Integer]: Integer read GetActiveTaskCount; + property ActiveTaskCount[const ModuleId: Integer]: Integer read GetActiveTaskCount; property ActiveConnectionCount[const ModuleId: Integer]: Integer read GetActiveConnectionLimit; procedure IncActiveTaskCount(ModuleId: Integer); From 5f7aab02971ac5334039eeb74ee65cf526bae633 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 03:02:28 +0800 Subject: [PATCH 0393/2794] websitemodules, add cancreatetask and cancreateconnection function --- baseunits/WebsiteModules.pas | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 2d3c1cd9d..7d56a8443 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -132,8 +132,10 @@ TWebsiteModules = class read GetActiveConnectionLimit; procedure IncActiveTaskCount(ModuleId: Integer); procedure DecActiveTaskCount(ModuleId: Integer); + function CanCreateTask(ModuleId: Integer): Boolean; procedure IncActiveConnectionCount(ModuleId: Integer); procedure DecActiveConnectionCount(ModuleId: Integer); + function CanCreateConnection(ModuleId: Integer): Boolean; end; var @@ -410,6 +412,14 @@ procedure TWebsiteModules.DecActiveTaskCount(ModuleId: Integer); InterLockedDecrement(TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount); end; +function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; +begin + Result := True; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + with TModuleContainer(FModuleList[ModuleId]) do + Result := ActiveTaskCount < MaxTaskLimit; +end; + procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; @@ -423,6 +433,14 @@ procedure TWebsiteModules.DecActiveConnectionCount(ModuleId: Integer); InterLockedDecrement(TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount); end; +function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; +begin + Result := True; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + with TModuleContainer(FModuleList[ModuleId]) do + Result := ActiveConnectionCount < MaxConnectionLimit; +end; + function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(nil); From 1d28a1ffeebd651357a8d322cd1105746e5b8c0e Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 03:41:36 +0800 Subject: [PATCH 0394/2794] implement task and connection limit, and clean up --- baseunits/uDownloadsManager.pas | 174 ++++++++++-------------------- baseunits/uFavoritesManager.pas | 2 +- baseunits/uSilentThread.pas | 2 +- mangadownloader/forms/frmMain.pas | 12 ++- 4 files changed, 68 insertions(+), 122 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d90dbadb4..f156735a1 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -112,6 +112,8 @@ TTaskContainer = class private FReadCount: Integer; CS_FReadCount: TCriticalSection; + FWebsite: String; + procedure SetWebsite(AValue: String); public // task thread of this container Thread: TTaskThread; @@ -126,6 +128,7 @@ TTaskContainer = class DownCounter, PageNumber: Integer; MangaSiteID: Cardinal; + ModuleId: Integer; Status: TDownloadStatusType; ThreadState: Boolean; ChapterName, @@ -137,6 +140,7 @@ TTaskContainer = class procedure IncReadCount(const ACount: Integer); constructor Create; destructor Destroy; override; + property Website: String read FWebsite write SetWebsite; end; { TDownloadManager } @@ -196,8 +200,6 @@ TDownloadManager = class // Check and active waiting tasks. procedure CheckAndActiveTask(const isCheckForFMDDo: Boolean = False; {%H-}SenderThread: TThread = nil); - // Check if we can active another wating task or not. - function CanActiveTask(const pos : Integer) : Boolean; // Active a stopped task. procedure ActiveTask(const taskID : Integer); // Stop a download/wait task. @@ -299,6 +301,7 @@ procedure TDownloadThread.Execute; var Reslt: Boolean = False; begin + Modules.IncActiveConnectionCount(ModuleId); try case checkStyle of // Get number of images. @@ -356,6 +359,7 @@ procedure TDownloadThread.DoTerminate; begin manager.CS_threads.Acquire; try + Modules.DecActiveConnectionCount(ModuleId); manager.threads.Remove(Self); finally manager.CS_threads.Release; @@ -1398,7 +1402,8 @@ procedure TTaskThread.Execute; S, P: String; begin INIAdvanced.Reload; - ModuleId := Modules.LocateModule(container.DownloadInfo.Website); + ModuleId := container.ModuleId; + Modules.IncActiveTaskCount(ModuleId); container.ThreadState := True; container.DownloadInfo.TransferRate := ''; try @@ -1609,6 +1614,8 @@ procedure TTaskThread.DoTerminate; Stop; container.DownloadInfo.TransferRate := ''; container.ThreadState := False; + container.Thread := nil; + Modules.DecActiveTaskCount(ModuleId); inherited DoTerminate; end; @@ -1643,6 +1650,14 @@ procedure TTaskThread.Stop(const check: Boolean = True); { TTaskContainer } +procedure TTaskContainer.SetWebsite(AValue: String); +begin + if FWebsite = AValue then Exit; + FWebsite := AValue; + MangaSiteID := GetMangaSiteID(AValue); + ModuleId := Modules.LocateModule(AValue); +end; + procedure TTaskContainer.IncReadCount(const ACount: Integer); begin CS_FReadCount.Acquire; @@ -1853,7 +1868,7 @@ procedure TDownloadManager.Restore; end; if DownloadInfo.dateTime > Now then DownloadInfo.dateTime := Now; - MangaSiteID := GetMangaSiteID(DownloadInfo.website); + Website := DownloadInfo.Website; ThreadState := False; //validating @@ -2089,8 +2104,7 @@ function TDownloadManager.AddTask : Integer; procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; SenderThread : TThread); var - EHENTAI_Count: Integer = 0; - Count: Integer = 0; + tcount: Integer; i: Integer; procedure ShowExitCounter; @@ -2110,141 +2124,71 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; end; begin - if Containers.Count = 0 then - Exit; + if Containers.Count = 0 then Exit; CS_DownloadManager_Task.Acquire; try - try - for i := 0 to Containers.Count - 1 do - begin - if (TaskItem(i).Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_COMPRESS]) then - begin - Inc(Count); - if TaskItem(i).MangaSiteID = EHENTAI_ID then - Inc(EHENTAI_Count); - end; - end; + tcount := 0; + for i := 0 to Containers.Count - 1 do + if TTaskContainer(Containers[i]).ThreadState then + Inc(tcount); - if Count < maxDLTasks then - begin - for i := 0 to Containers.Count - 1 do - begin - if Count >= maxDLTasks then - Break; - if (TaskItem(i).Status = STATUS_WAIT) then - begin - if (TaskItem(i).MangaSiteID = EHENTAI_ID) and - (EHENTAI_Count < EHENTAI_maxDLTask) then - begin - Inc(EHENTAI_Count); - Inc(Count); - ActiveTask(i); - end - else + if tcount < maxDLTasks then + for i := 0 to Containers.Count - 1 do + with TTaskContainer(Containers[i]) do + if (tcount < maxDLTasks) and + (Status = STATUS_WAIT) and + Modules.CanCreateTask(ModuleId) then begin ActiveTask(i); - Inc(Count); + Inc(tcount); end; - end; - end; - end; - - if Count > 0 then - begin - if not MainForm.itRefreshDLInfo.Enabled then - MainForm.itRefreshDLInfo.Enabled := True; - end - else - MainForm.itRefreshDLInfo.Enabled := False; - - Self.Backup; - MainForm.vtDownloadFilters; - - if (Count = 0) and (isCheckForFMDDo) then - ShowExitCounter; - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); - end; finally CS_DownloadManager_Task.Release; end; -end; -function TDownloadManager.CanActiveTask(const pos: Integer): Boolean; -var - EHENTAI_Count: Integer = 0; - i: Integer; - Count: Integer = 0; -begin - Result := True; + try + if tcount > 0 then + begin + if not MainForm.itRefreshDLInfo.Enabled then + MainForm.itRefreshDLInfo.Enabled := True; + end + else + MainForm.itRefreshDLInfo.Enabled := False; - if (Containers.Count = 0) or (pos >= Containers.Count) then - Exit(False); + Self.Backup; + MainForm.vtDownloadFilters; - for i := 0 to Containers.Count - 1 do - begin - if (TaskItem(i).Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_COMPRESS]) and - (i <> pos) then - begin - Inc(Count); - if (TaskItem(i).MangaSiteID = EHENTAI_ID) then - Inc(EHENTAI_Count); - end; + if (Count = 0) and (isCheckForFMDDo) then + ShowExitCounter; + except + on E: Exception do + MainForm.ExceptionHandler(Self, E); end; - - if (TaskItem(pos).MangaSiteID = EHENTAI_ID) and - (EHENTAI_Count >= EHENTAI_maxDLTask) then - Result := False - else - if Count >= maxDLTasks then - Result := False; end; procedure TDownloadManager.CheckAndActiveTaskAtStartup; - - procedure ActiveTaskAtStartup(const taskID: Integer); - begin - if taskID >= Containers.Count then - Exit; - if (not Assigned(TaskItem(taskID))) then - Exit; - if (TaskItem(taskID).Status = STATUS_WAIT) or - (TaskItem(taskID).Status = STATUS_STOP) or - (TaskItem(taskID).Status = STATUS_FINISH) then - Exit; - TaskItem(taskID).Status := STATUS_DOWNLOAD; - TaskItem(taskID).Thread := TTaskThread.Create; - TaskItem(taskID).Thread.container := TaskItem(taskID); - TaskItem(taskID).Thread.Start; - end; - var - i: Integer; - Count: Integer = 0; + i, tcount: Integer; begin - if Containers.Count = 0 then - Exit; + if Containers.Count = 0 then Exit; + tcount := 0; for i := 0 to Containers.Count - 1 do - begin - if (TaskItem(i).Status = STATUS_DOWNLOAD) or - (TaskItem(i).Status = STATUS_PREPARE) then - begin - if Count < maxDLTasks then + with TTaskContainer(Containers[i]) do + if (tcount < maxDLTasks) and + (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) and + Modules.CanCreateTask(ModuleId) then begin - ActiveTaskAtStartup(i); - Inc(Count); + ActiveTask(i); + Inc(tcount); end else begin - TaskItem(i).Status := STATUS_WAIT; - TaskItem(i).DownloadInfo.Status := RS_Waiting; + Status := STATUS_WAIT; + DownloadInfo.Status := RS_Waiting; end; - end; - end; - MainForm.vtDownloadFilters; //force to check task if all task loaded is STATUS_WAIT CheckAndActiveTask; + MainForm.vtDownloadFilters; end; procedure TDownloadManager.ActiveTask(const taskID: Integer); diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 775138b75..50b053c0b 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -661,7 +661,7 @@ procedure TFavoriteManager.ShowResult; with TTaskContainer(DLManager.Containers.Last) do begin Manager := DLManager; CurrentDownloadChapterPtr := 0; - MangaSiteID := GetMangaSiteID(FavoriteInfo.Website); + Website := Website; with DownloadInfo do begin Website := FavoriteInfo.Website; Link := FavoriteInfo.Link; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 9e21a9591..447cf62d0 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -312,7 +312,7 @@ procedure TSilentThread.MainThreadAfterChecking; begin // add a new download task p := DLManager.AddTask; - DLManager.TaskItem(p).mangaSiteID := GetMangaSiteID(website); + DLManager.TaskItem(p).Website := website; if Trim(title) = '' then title := Info.mangaInfo.title; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 008741083..f35a3b11e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1315,6 +1315,10 @@ procedure TMainForm.itRefreshDLInfoStopTimer(Sender: TObject); procedure TMainForm.itRefreshDLInfoTimer(Sender: TObject); begin + //Writelog_D('BatotoMaxTaskLimit: '+IntToStr(Modules.MaxTaskLimit[2])); + Writelog_D('BatotoActiveTaskCount: '+IntToStr(Modules.ActiveTaskCOunt[2])); + //Writelog_D('BatotoMaxConnectionLimit: '+IntToStr(Modules.MaxConnectionLimit[2])); + //Writelog_D('BatotoActiveConnectionCount: '+IntToStr(Modules.ActiveConnectionCount[2])); if Assigned(DLManager) then TransferRateGraphAddItem(DLManager.TransferRate); vtDownload.Repaint; @@ -1783,7 +1787,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); pos := DLManager.AddTask; isCreate := True; end; - DLManager.TaskItem(pos).MangaSiteID := GetMangaSiteID(mangaInfo.website); + DLManager.TaskItem(pos).Website := mangaInfo.website; // generate folder name s := CustomRename(OptionCustomRename, mangaInfo.website, @@ -2814,8 +2818,7 @@ procedure TMainForm.miDownloadResumeClick(Sender: TObject); DLManager.TaskItem(vtDownload.FocusedNode^.Index).Status := STATUS_WAIT; DLManager.TaskItem(vtDownload.FocusedNode^.Index).DownloadInfo.Status := RS_Waiting; - if DLManager.CanActiveTask(vtDownload.FocusedNode^.Index) then - DLManager.ActiveTask(vtDownload.FocusedNode^.Index); + DLManager.CheckAndActiveTask; vtDownload.Repaint; DLManager.Backup; end; @@ -2832,8 +2835,7 @@ procedure TMainForm.miDownloadResumeClick(Sender: TObject); begin DLManager.TaskItem(xNode^.Index).Status := STATUS_WAIT; DLManager.TaskItem(xNode^.Index).DownloadInfo.Status := RS_Waiting; - if DLManager.CanActiveTask(xNode^.Index) then - DLManager.ActiveTask(xNode^.Index); + DLManager.CheckAndActiveTask; end; xNode := vtDownload.GetNextSelected(xNode); end; From eb59e0554e77da5b51da12d5a391d2cfacd118ce Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 03:45:58 +0800 Subject: [PATCH 0395/2794] some clean up --- mangadownloader/forms/frmMain.pas | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f35a3b11e..299959482 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1315,10 +1315,6 @@ procedure TMainForm.itRefreshDLInfoStopTimer(Sender: TObject); procedure TMainForm.itRefreshDLInfoTimer(Sender: TObject); begin - //Writelog_D('BatotoMaxTaskLimit: '+IntToStr(Modules.MaxTaskLimit[2])); - Writelog_D('BatotoActiveTaskCount: '+IntToStr(Modules.ActiveTaskCOunt[2])); - //Writelog_D('BatotoMaxConnectionLimit: '+IntToStr(Modules.MaxConnectionLimit[2])); - //Writelog_D('BatotoActiveConnectionCount: '+IntToStr(Modules.ActiveConnectionCount[2])); if Assigned(DLManager) then TransferRateGraphAddItem(DLManager.TransferRate); vtDownload.Repaint; From f1c08ad700506612e384d045df26f314a2c42580 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 04:05:11 +0800 Subject: [PATCH 0396/2794] store maxtask and maxconnection limit --- baseunits/WebsiteModules.pas | 7 +++++-- baseunits/uDownloadsManager.pas | 7 +++---- baseunits/uUpdateThread.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 4 ++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 7d56a8443..e8a380946 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -13,6 +13,9 @@ interface NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; + MAX_TASKLIMIT = 8; + MAX_CONNECTIONLIMIT = 32; + type TModuleContainer = class; @@ -167,8 +170,8 @@ procedure TModuleContainer.SetTotalDirectory(AValue: Integer); constructor TModuleContainer.Create; begin - MaxTaskLimit := 0; - MaxConnectionLimit := 0; + MaxTaskLimit := MAX_TASKLIMIT; + MaxConnectionLimit := MAX_CONNECTIONLIMIT; ActiveTaskCount := 0; ActiveConnectionCount := 0; SortedList := False; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index f156735a1..600a480d6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1281,8 +1281,8 @@ procedure TTaskThread.CheckOut; container.DownloadInfo.Website, -1); if (mt > 0) then begin - if (mt > 32) then - mt := 32; + if mt > MAX_CONNECTIONLIMIT then + mt := MAX_CONNECTIONLIMIT; currentMaxThread := mt; end else @@ -2104,8 +2104,7 @@ function TDownloadManager.AddTask : Integer; procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; SenderThread : TThread); var - tcount: Integer; - i: Integer; + i, tcount: Integer; procedure ShowExitCounter; begin diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 833e28f4e..75dff270d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -447,8 +447,8 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; mt := INIAdvanced.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then begin - if mt > 32 then //32 is max | be carefull, there's still memory leak problems - mt := 32; + if mt > MAX_CONNECTIONLIMIT then //32 is max | be carefull, there's still memory leak problems + mt := MAX_CONNECTIONLIMIT; numberOfThreads := mt; end else diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 299959482..2daea0647 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -999,6 +999,10 @@ procedure TMainForm.FormCreate(Sender: TObject); // generate tvDownloadFilter nodes GeneratetvDownloadFilterNodes; + // set connection limit + seOptionMaxThread.MaxValue := MAX_TASKLIMIT; + seOptionMaxParallel.MaxValue := MAX_CONNECTIONLIMIT; + isStartup := False; CollectLanguagesFromFiles; LoadFormInformation; From ae4a8e553fb5c0eaf5414209987fb5c4281199a2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 04:32:46 +0800 Subject: [PATCH 0397/2794] websitemodules, return default max limit --- baseunits/WebsiteModules.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index e8a380946..4fa94eb74 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -457,13 +457,13 @@ function TWebsiteModules.GetCount: Integer; function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(MAX_TASKLIMIT); Result := TModuleContainer(FModuleList[ModuleId]).MaxTaskLimit; end; function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(MAX_CONNECTIONLIMIT); Result := TModuleContainer(FModuleList[ModuleId]).MaxConnectionLimit; end; From 0b1ee6944bfbf5464de8c88b43ab3868da683257 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 05:00:58 +0800 Subject: [PATCH 0398/2794] downloadmanager, some changes --- baseunits/uDownloadsManager.pas | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 600a480d6..fb3d0b18e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1317,19 +1317,16 @@ procedure TTaskThread.CheckOut; end; if ModuleId > -1 then - begin while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do - Sleep(SOCKHEARTBEATRATE); - end + Sleep(SOCKHEARTBEATRATE) else - begin while (not Terminated) and (threads.Count >= currentMaxThread) do Sleep(SOCKHEARTBEATRATE); - end; end; if (not Terminated) and (threads.Count < currentMaxThread) then begin + if currentMaxThread < Modules.ActiveConnectionCount[ModuleId] then Exit; CS_threads.Acquire; try threads.Add(TDownloadThread.Create); From 4f5bf0317462399eebd5be0a6ec6c339525c11d8 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 05:16:10 +0800 Subject: [PATCH 0399/2794] downloadmanager, fix check task at startup --- baseunits/uDownloadsManager.pas | 53 +++++++++++++++++---------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index fb3d0b18e..ab9b8bfe4 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2170,18 +2170,18 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; tcount := 0; for i := 0 to Containers.Count - 1 do with TTaskContainer(Containers[i]) do - if (tcount < maxDLTasks) and - (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) and - Modules.CanCreateTask(ModuleId) then - begin - ActiveTask(i); - Inc(tcount); - end - else - begin - Status := STATUS_WAIT; - DownloadInfo.Status := RS_Waiting; - end; + if Status in [STATUS_DOWNLOAD, STATUS_PREPARE] then + if (tcount < maxDLTasks) and + Modules.CanCreateTask(ModuleId) then + begin + ActiveTask(i); + Inc(tcount); + end + else + begin + Status := STATUS_WAIT; + DownloadInfo.Status := RS_Waiting; + end; //force to check task if all task loaded is STATUS_WAIT CheckAndActiveTask; MainForm.vtDownloadFilters; @@ -2189,26 +2189,27 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; procedure TDownloadManager.ActiveTask(const taskID: Integer); begin - if taskID < Containers.Count then - begin - if Assigned(TaskItem(taskID)) then + if taskID >= Containers.Count then Exit; + if Assigned(Containers[taskID]) then + with TTaskContainer(Containers[taskID]) do begin - if not((TaskItem(taskID).Status = STATUS_DOWNLOAD) or - (TaskItem(taskID).Status = STATUS_PREPARE) or - (TaskItem(taskID).Status = STATUS_FINISH)) then + if Status = STATUS_FINISH then Exit; + if ThreadState = False then begin - TaskItem(taskID).Status := STATUS_DOWNLOAD; - TaskItem(taskID).DownloadInfo.Status := RS_Downloading; - TaskItem(taskID).Thread := TTaskThread.Create; - TaskItem(taskID).Thread.container := TaskItem(taskID); - TaskItem(taskID).Thread.Start; + if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then + begin + Status := STATUS_DOWNLOAD; + DownloadInfo.Status := RS_Downloading; + end; + Thread := TTaskThread.Create; + Thread.container := TaskItem(taskID); + Thread.Start; MainForm.vtDownload.Repaint; MainForm.vtDownloadFilters; + if not MainForm.itRefreshDLInfo.Enabled then + MainForm.itRefreshDLInfo.Enabled := True; end; end; - if not MainForm.itRefreshDLInfo.Enabled then - MainForm.itRefreshDLInfo.Enabled := True; - end; end; procedure TDownloadManager.StopTask(const taskID: Integer; From c0cdd319c184c87b81bdbecd38fb5f454d727225 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 06:17:49 +0800 Subject: [PATCH 0400/2794] downloadmanager, fix start task at startup --- baseunits/uDownloadsManager.pas | 30 ++++++++++++++---------------- mangadownloader/forms/frmMain.pas | 9 ++++++--- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ab9b8bfe4..9c7cca8d8 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1326,9 +1326,9 @@ procedure TTaskThread.CheckOut; if (not Terminated) and (threads.Count < currentMaxThread) then begin - if currentMaxThread < Modules.ActiveConnectionCount[ModuleId] then Exit; CS_threads.Acquire; try + if Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread then Exit; threads.Add(TDownloadThread.Create); with TDownloadThread(threads.Last) do begin manager := Self; @@ -2174,8 +2174,8 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; if (tcount < maxDLTasks) and Modules.CanCreateTask(ModuleId) then begin - ActiveTask(i); Inc(tcount); + ActiveTask(i); end else begin @@ -2183,7 +2183,8 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; DownloadInfo.Status := RS_Waiting; end; //force to check task if all task loaded is STATUS_WAIT - CheckAndActiveTask; + if tcount = 0 then + CheckAndActiveTask; MainForm.vtDownloadFilters; end; @@ -2194,21 +2195,18 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); with TTaskContainer(Containers[taskID]) do begin if Status = STATUS_FINISH then Exit; - if ThreadState = False then + if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then begin - if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then - begin - Status := STATUS_DOWNLOAD; - DownloadInfo.Status := RS_Downloading; - end; - Thread := TTaskThread.Create; - Thread.container := TaskItem(taskID); - Thread.Start; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; - if not MainForm.itRefreshDLInfo.Enabled then - MainForm.itRefreshDLInfo.Enabled := True; + Status := STATUS_DOWNLOAD; + DownloadInfo.Status := RS_Downloading; end; + Thread := TTaskThread.Create; + Thread.container := TaskItem(taskID); + Thread.Start; + MainForm.vtDownload.Repaint; + MainForm.vtDownloadFilters; + if not MainForm.itRefreshDLInfo.Enabled then + MainForm.itRefreshDLInfo.Enabled := True; end; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2daea0647..1d5ab4de7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1023,7 +1023,6 @@ procedure TMainForm.FormCreate(Sender: TObject); pcMain.ActivePage := tsDownload; - DLManager.CheckAndActiveTaskAtStartup; TrayIcon.Show; // load some necessary options at startup @@ -1344,6 +1343,7 @@ procedure TMainForm.itStartupTimer(Sender: TObject); MainForm.FavoriteManager.isAuto := True; MainForm.FavoriteManager.CheckForNewChapter; end; + DLManager.CheckAndActiveTaskAtStartup; end; end; @@ -4683,9 +4683,12 @@ procedure TMainForm.ApplyOptions; //languages ApplyLanguage; - finally - DLManager.CheckAndActiveTask; + except + on E: Exception do + ExceptionHandle(Self, E); end; + if isStartup then + DLManager.CheckAndActiveTask; end; procedure TMainForm.LoadMangaOptions; From 15afd4d09787c3cb8612091192d90fe7cfcae8e9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 06:24:22 +0800 Subject: [PATCH 0401/2794] websitemodules, add critical section for connection --- baseunits/WebsiteModules.pas | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 4fa94eb74..3c7a4a9f5 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -147,6 +147,9 @@ TWebsiteModules = class procedure doInitialize; function AddModule: TModuleContainer; +procedure LockCreateConnection; +procedure UnlockCreateConnection; + implementation {$I ModuleList.inc} @@ -154,6 +157,9 @@ implementation const REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; +var + CS_Connection: TRTLCriticalSection; + { TModuleContainer } procedure TModuleContainer.SetTotalDirectory(AValue: Integer); @@ -492,11 +498,23 @@ function AddModule: TModuleContainer; Result := Modules.AddModule; end; +procedure LockCreateConnection; +begin + EnterCriticalsection(CS_Connection); +end; + +procedure UnlockCreateConnection; +begin + LeaveCriticalsection(CS_Connection); +end; + initialization + InitCriticalSection(CS_Connection); doInitialize; finalization if Assigned(Modules) then FreeAndNil(Modules); + DoneCriticalsection(CS_Connection); end. From d9ec6c88179d9982ff3289e902876a871516898b Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 06:25:22 +0800 Subject: [PATCH 0402/2794] downloadmanager, use global lock connection --- baseunits/uDownloadsManager.pas | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9c7cca8d8..be0f67a38 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -100,7 +100,6 @@ TTaskThread = class(TFMDThread) container: TTaskContainer; // download threads threads: TFPList; - CS_threads: TCriticalSection; constructor Create; destructor Destroy; override; property AnotherURL: String read FAnotherURL write FAnotherURL; @@ -357,12 +356,12 @@ procedure TDownloadThread.Execute; procedure TDownloadThread.DoTerminate; begin - manager.CS_threads.Acquire; + LockCreateConnection; try Modules.DecActiveConnectionCount(ModuleId); manager.threads.Remove(Self); finally - manager.CS_threads.Release; + UnlockCreateConnection; end; inherited DoTerminate; end; @@ -1141,7 +1140,6 @@ procedure TDownloadThread.SetChangeDirectoryTrue; constructor TTaskThread.Create; begin inherited Create(True); - CS_threads := TCriticalSection.Create; threads := TFPList.Create; ModuleId := -1; anotherURL := ''; @@ -1151,7 +1149,6 @@ constructor TTaskThread.Create; destructor TTaskThread.Destroy; begin threads.Free; - CS_threads.Free; inherited Destroy; end; @@ -1326,7 +1323,7 @@ procedure TTaskThread.CheckOut; if (not Terminated) and (threads.Count < currentMaxThread) then begin - CS_threads.Acquire; + LockCreateConnection; try if Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread then Exit; threads.Add(TDownloadThread.Create); @@ -1345,7 +1342,7 @@ procedure TTaskThread.CheckOut; if Flag = CS_GETPAGELINK then container.CurrentPageNumber := InterLockedIncrement(container.CurrentPageNumber); finally - CS_threads.Release; + UnlockCreateConnection; end; end; end; @@ -1598,12 +1595,12 @@ procedure TTaskThread.DoTerminate; begin if threads.Count > 0 then begin - CS_threads.Acquire; + LockCreateConnection; try for i := 0 to threads.Count - 1 do TDownloadThread(threads[i]).Terminate; finally - CS_threads.Release; + UnlockCreateConnection; end; while threads.Count > 0 do Sleep(100); From 7225039e21d1600fe94c76a241ddc02be47d0e98 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 06:54:32 +0800 Subject: [PATCH 0403/2794] websitemodules, rename some variable --- baseunits/WebsiteModules.pas | 6 +++--- baseunits/uDownloadsManager.pas | 4 ++-- baseunits/uUpdateThread.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 3c7a4a9f5..8ce21fce1 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -14,7 +14,7 @@ interface INFORMATION_NOT_FOUND = 2; MAX_TASKLIMIT = 8; - MAX_CONNECTIONLIMIT = 32; + MAX_CONNECTIONPERHOSTLIMIT = 32; type @@ -177,7 +177,7 @@ procedure TModuleContainer.SetTotalDirectory(AValue: Integer); constructor TModuleContainer.Create; begin MaxTaskLimit := MAX_TASKLIMIT; - MaxConnectionLimit := MAX_CONNECTIONLIMIT; + MaxConnectionLimit := MAX_CONNECTIONPERHOSTLIMIT; ActiveTaskCount := 0; ActiveConnectionCount := 0; SortedList := False; @@ -469,7 +469,7 @@ function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(MAX_CONNECTIONLIMIT); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(MAX_CONNECTIONPERHOSTLIMIT); Result := TModuleContainer(FModuleList[ModuleId]).MaxConnectionLimit; end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index be0f67a38..5ca1df004 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1278,8 +1278,8 @@ procedure TTaskThread.CheckOut; container.DownloadInfo.Website, -1); if (mt > 0) then begin - if mt > MAX_CONNECTIONLIMIT then - mt := MAX_CONNECTIONLIMIT; + if mt > MAX_CONNECTIONPERHOSTLIMIT then + mt := MAX_CONNECTIONPERHOSTLIMIT; currentMaxThread := mt; end else diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 75dff270d..9a9136b0c 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -447,8 +447,8 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; mt := INIAdvanced.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then begin - if mt > MAX_CONNECTIONLIMIT then //32 is max | be carefull, there's still memory leak problems - mt := MAX_CONNECTIONLIMIT; + if mt > MAX_CONNECTIONPERHOSTLIMIT then //32 is max | be carefull, there's still memory leak problems + mt := MAX_CONNECTIONPERHOSTLIMIT; numberOfThreads := mt; end else diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1d5ab4de7..d37b6ddfc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1001,7 +1001,7 @@ procedure TMainForm.FormCreate(Sender: TObject); // set connection limit seOptionMaxThread.MaxValue := MAX_TASKLIMIT; - seOptionMaxParallel.MaxValue := MAX_CONNECTIONLIMIT; + seOptionMaxParallel.MaxValue := MAX_CONNECTIONPERHOSTLIMIT; isStartup := False; CollectLanguagesFromFiles; From 5e0fd9219468ed5175eb23159fbf949ca722d0f5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 07:03:50 +0800 Subject: [PATCH 0404/2794] downloadmanager, clean up --- baseunits/uDownloadsManager.pas | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5ca1df004..45cb35349 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1287,13 +1287,7 @@ procedure TTaskThread.CheckOut; if Modules.MaxConnectionLimit[ModuleId] > 0 then currentMaxThread := Modules.MaxConnectionLimit[ModuleId] else - begin - case container.MangaSiteID of - EHENTAI_ID : currentMaxThread := 2; - else - currentMaxThread := container.Manager.maxDLThreadsPerTask; - end; - end; + currentMaxThread := container.Manager.maxDLThreadsPerTask; if currentMaxThread > container.Manager.maxDLThreadsPerTask then currentMaxThread := container.Manager.maxDLThreadsPerTask; end; From 8cb7c2285e3f9e5b2b2ad8a9c3bdeeb3786cf728 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 07:06:19 +0800 Subject: [PATCH 0405/2794] websitemodules, getmaxconnectionlimit return 0 if it's not in moduleslist --- baseunits/WebsiteModules.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 8ce21fce1..48224226e 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -463,13 +463,13 @@ function TWebsiteModules.GetCount: Integer; function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(MAX_TASKLIMIT); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); Result := TModuleContainer(FModuleList[ModuleId]).MaxTaskLimit; end; function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(MAX_CONNECTIONPERHOSTLIMIT); + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); Result := TModuleContainer(FModuleList[ModuleId]).MaxConnectionLimit; end; From 4bf186a19f0dd9cf8f7da198f4fa35e609f72cb4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 07:33:08 +0800 Subject: [PATCH 0406/2794] updatethread, check for max connection limit on websitemodules should be synched with downloadmanager --- baseunits/uUpdateThread.pas | 57 ++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 9a9136b0c..380d1f20d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -65,7 +65,6 @@ TUpdateMangaManagerThread = class(TFMDThread) // for fakku's doujinshi only directoryCount2, numberOfThreads, websitePtr: Integer; threads: TFPList; - CS_threads: TCriticalSection; SortedList, NoMangaInfo: Boolean; constructor Create; destructor Destroy; override; @@ -112,6 +111,7 @@ procedure TUpdateMangaThread.Execute; names, links: TStringList; i: Integer; begin + Modules.IncActiveConnectionCount(manager.ModuleId); try if checkStyle = CS_INFO then Info := TMangaInformation.Create(Self, True) @@ -123,7 +123,7 @@ procedure TUpdateMangaThread.Execute; case CheckStyle of CS_DIRECTORY_COUNT: begin - if manager.ModuleId <> -1 then + if manager.ModuleId > -1 then begin with Modules.Module[manager.ModuleId] do for i := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do @@ -188,9 +188,7 @@ procedure TUpdateMangaThread.Execute; end; end else - begin Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); - end; //if website has sorted list by latest added //we will stop at first found against current db @@ -251,11 +249,12 @@ procedure TUpdateMangaThread.Execute; procedure TUpdateMangaThread.DoTerminate; begin - manager.CS_threads.Acquire; + LockCreateConnection; try + Modules.DecActiveConnectionCount(manager.ModuleId); manager.threads.Remove(Self); finally - manager.CS_threads.Release; + UnlockCreateConnection end; inherited DoTerminate; end; @@ -326,7 +325,6 @@ procedure TUpdateMangaManagerThread.ExtractFile; constructor TUpdateMangaManagerThread.Create; begin inherited Create(True); - CS_threads := TCriticalSection.Create; CS_AddInfoToData := TCriticalSection.Create; CS_AddNamesAndLinks := TCriticalSection.Create; FreeOnTerminate := True; @@ -355,7 +353,6 @@ destructor TUpdateMangaManagerThread.Destroy; MainForm.isUpdating := False; CS_AddInfoToData.Free; CS_AddNamesAndLinks.Free; - CS_threads.Free; inherited Destroy; end; @@ -437,7 +434,6 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; try while workPtr < limit do begin - MainForm.ulWorkPtr := workPtr + 1; if Terminated then begin TerminateThreads; @@ -453,22 +449,18 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; end else begin - mt := MainForm.options.ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - case GetMangaSiteID(website) of - EATMANGA_ID : numberOfThreads := 1; - SCANMANGA_ID : numberOfThreads := 1; - EHENTAI_ID : numberOfThreads := 3; + if Modules.MaxConnectionLimit[ModuleId] > 0 then + numberOfThreads := Modules.MaxConnectionLimit[ModuleId] else - numberOfThreads := mt; - end; - if numberOfThreads > mt then - numberOfThreads := mt; + numberOfThreads := OptionMaxThreads; + if numberOfThreads > OptionMaxThreads then + numberOfThreads := OptionMaxThreads; end; if numberOfThreads < 1 then numberOfThreads := 1; //default // Finish searching for new series - if ((cs = CS_DIRECTORY_PAGE) or (cs = CS_DIRECTORY_PAGE_2)) and + if (cs in [CS_DIRECTORY_PAGE, CS_DIRECTORY_PAGE_2]) and (isFinishSearchingForNewManga) then begin WaitForThreads; @@ -476,26 +468,24 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; Break; end; - while threads.Count >= numberOfThreads do - begin - if Terminated then - begin - TerminateThreads; - Break; - end - else - Sleep(SOCKHEARTBEATRATE); //waiting for empty slot / slowing down the circle - end; + if ModuleId > -1 then + while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads) do + Sleep(SOCKHEARTBEATRATE) + else + while (not Terminated) and (threads.Count >= numberOfThreads) do + Sleep(SOCKHEARTBEATRATE); if Terminated then begin TerminateThreads; Break; end; + if threads.Count < numberOfThreads then begin - CS_threads.Acquire; + LockCreateConnection; try + if Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads then Exit; threads.Add(TUpdateMangaThread.Create); TUpdateMangaThread(threads.Last).checkStyle := cs; TUpdateMangaThread(threads.Last).manager := Self; @@ -529,9 +519,10 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; links[workPtr - 1]]); end; FStatus := s; + MainForm.ulWorkPtr := workPtr + 1; Synchronize(MainThreadShowGetting); finally - CS_threads.Release; + UnlockCreateConnection; end; end; end; @@ -559,12 +550,12 @@ procedure TUpdateMangaManagerThread.Execute; begin if Terminated then begin - CS_threads.Acquire; + LockCreateConnection; try for i := threads.Count - 1 downto 0 do TUpdateMangaThread(threads[i]).Terminate; finally - CS_threads.Release; + UnlockCreateConnection; end; end; Sleep(SOCKHEARTBEATRATE); From 674d4b1d7809574f7dc9d5010897225bafe881f6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 08:35:11 +0800 Subject: [PATCH 0407/2794] updatethread, wait and terminate threads on getinfo only to avoid overflow --- baseunits/uUpdateThread.pas | 47 ++++++++----------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 380d1f20d..665e2be50 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -418,7 +418,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; procedure TerminateThreads; var - i: Cardinal; + i: Integer; begin if threads.Count > 0 then for i := threads.Count - 1 downto 0 do @@ -481,7 +481,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; Break; end; - if threads.Count < numberOfThreads then + if (not Terminated) and (threads.Count < numberOfThreads) then begin LockCreateConnection; try @@ -530,6 +530,9 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; on E: Exception do MainForm.ExceptionHandler(Self, E); end; + while (not Terminated) and (threads.Count > 0) do + Sleep(SOCKHEARTBEATRATE); + if Terminated then TerminateThreads; end; procedure TUpdateMangaManagerThread.DoTerminate; @@ -541,27 +544,6 @@ procedure TUpdateMangaManagerThread.DoTerminate; end; procedure TUpdateMangaManagerThread.Execute; - - procedure WaitForThreads; - var - i: Integer; - begin - while threads.Count > 0 do - begin - if Terminated then - begin - LockCreateConnection; - try - for i := threads.Count - 1 downto 0 do - TUpdateMangaThread(threads[i]).Terminate; - finally - UnlockCreateConnection; - end; - end; - Sleep(SOCKHEARTBEATRATE); - end; - end; - var c, j, k: Integer; del: Boolean; @@ -620,9 +602,7 @@ procedure TUpdateMangaManagerThread.Execute; directoryCount2 := 0; workPtr := 0; GetInfo(1, CS_DIRECTORY_COUNT); - WaitForThreads; - if Terminated then - Break; + if Terminated then Break; //get names and links INIAdvanced.Reload; @@ -637,7 +617,6 @@ procedure TUpdateMangaManagerThread.Execute; isFinishSearchingForNewManga := False; CurrentDirectoryIndex := j; GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); - WaitForThreads; end; end else @@ -655,9 +634,7 @@ procedure TUpdateMangaManagerThread.Execute; end else GetInfo(directoryCount, CS_DIRECTORY_PAGE); - WaitForThreads; - if Terminated then - Break; + if Terminated then Break; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; @@ -675,8 +652,7 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(MainThreadShowGetting); while j < (links.Count - 1) do begin - if Terminated then - Break; + if Terminated then Break; Inc(c); if c > 499 then begin @@ -689,8 +665,7 @@ procedure TUpdateMangaManagerThread.Execute; if (j + 1) < links.Count then for k := j + 1 to links.Count - 1 do begin - if Terminated then - Break; + if Terminated then Break; if SameText(links[j], links[k]) then begin links.Delete(j); @@ -716,8 +691,7 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(MainThreadShowGetting); while j < links.Count do begin - if Terminated then - Break; + if Terminated then Break; Inc(c); if c > 999 then begin @@ -765,7 +739,6 @@ procedure TUpdateMangaManagerThread.Execute; end else GetInfo(links.Count, CS_INFO); - WaitForThreads; mainDataProcess.Commit; names.Clear; From 84d9962d9e6f3171a8a60470aaad68a0e2ddb5b5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 08:40:47 +0800 Subject: [PATCH 0408/2794] updater, break connection with closesocket --- updater/uMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 570085ba7..ba07fc1fa 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -576,8 +576,8 @@ procedure TDownloadThread.OnThreadTerminate(Sender: TObject); begin with FHTTP.Sock do begin - StopFlag := True; - AbortSocket; + //StopFlag := True; + CloseSocket; end; end; From fd49fb8f6a6a4787457cf670880fa10d1a9fd485 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 08:52:17 +0800 Subject: [PATCH 0409/2794] updater, clean up --- updater/uMain.pas | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index ba07fc1fa..f10b2796e 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -574,11 +574,7 @@ procedure TDownloadThread.Execute; procedure TDownloadThread.OnThreadTerminate(Sender: TObject); begin - with FHTTP.Sock do - begin - //StopFlag := True; - CloseSocket; - end; + FHTTP.Sock.AbortSocket; end; { TfrmMain } From 2c3b1c3e1077bd61f576bf7ed136756e81eb8411 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 09:07:17 +0800 Subject: [PATCH 0410/2794] fix wrong limit --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d37b6ddfc..57e63d74a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1000,8 +1000,8 @@ procedure TMainForm.FormCreate(Sender: TObject); GeneratetvDownloadFilterNodes; // set connection limit - seOptionMaxThread.MaxValue := MAX_TASKLIMIT; - seOptionMaxParallel.MaxValue := MAX_CONNECTIONPERHOSTLIMIT; + seOptionMaxParallel.MaxValue := MAX_TASKLIMIT; + seOptionMaxThread.MaxValue := MAX_CONNECTIONPERHOSTLIMIT; isStartup := False; CollectLanguagesFromFiles; From 4c312c2e5a5df7c22563a125a997b151fa2cfffe Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 09:10:06 +0800 Subject: [PATCH 0411/2794] mainform, fix checkbox not changed on load --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 57e63d74a..5c6e52504 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4434,6 +4434,7 @@ procedure TMainForm.LoadOptions; cbOptionAutoCheckFavInterval.Checked := ReadBool('update', 'AutoCheckFavInterval', True); seOptionAutoCheckFavIntervalMinutes.Value := ReadInteger('update', 'AutoCheckFavIntervalMinutes', 60); lbOptionAutoCheckFavIntervalMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionAutoCheckFavIntervalMinutes.Value]); + cbOptionAutoCheckFavIntervalChange(cbOptionAutoCheckFavInterval); cbOptionAutoCheckFavDownload.Checked := ReadBool('update', 'AutoCheckFavAutoDownload', False); cbOptionAutoCheckFavRemoveCompletedManga.Checked := ReadBool('update', 'AutoCheckFavAutoRemoveCompletedManga', False); cbOptionUpdateListNoMangaInfo.Checked := ReadBool('update', 'UpdateListNoMangaInfo', False); From 4080cbcacb3fbfacd1bf5518d451b27b8801cb19 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 09:25:37 +0800 Subject: [PATCH 0412/2794] updatethread, terminate child threads on doterminate --- baseunits/uUpdateThread.pas | 48 +++++++++++++++---------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 665e2be50..ce03767c9 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -412,20 +412,10 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; procedure WaitForThreads; begin - while threads.Count > 0 do + while (not Terminated) and (threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); end; - procedure TerminateThreads; - var - i: Integer; - begin - if threads.Count > 0 then - for i := threads.Count - 1 downto 0 do - TUpdateMangaThread(threads[i]).Terminate; - WaitForThreads; - end; - var mt: Integer; s: String; @@ -434,11 +424,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; try while workPtr < limit do begin - if Terminated then - begin - TerminateThreads; - Break; - end; + if Terminated then Exit; mt := INIAdvanced.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then @@ -465,7 +451,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; begin WaitForThreads; workPtr := limit; - Break; + Exit; end; if ModuleId > -1 then @@ -475,12 +461,6 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; while (not Terminated) and (threads.Count >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE); - if Terminated then - begin - TerminateThreads; - Break; - end; - if (not Terminated) and (threads.Count < numberOfThreads) then begin LockCreateConnection; @@ -530,16 +510,25 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; on E: Exception do MainForm.ExceptionHandler(Self, E); end; - while (not Terminated) and (threads.Count > 0) do - Sleep(SOCKHEARTBEATRATE); - if Terminated then TerminateThreads; + WaitForThreads; end; procedure TUpdateMangaManagerThread.DoTerminate; +var + i: Integer; begin - Synchronize(MainThreadEndGetting); - while threads.Count > 0 do - Sleep(SOCKHEARTBEATRATE); + if threads.Count > 0 then + begin + LockCreateConnection; + try + for i := 0 to threads.Count - 1 do + TUpdateMangaThread(threads[i]).Terminate; + finally + UnlockCreateConnection; + end; + while threads.Count > 0 do + Sleep(SOCKHEARTBEATRATE); + end; inherited DoTerminate; end; @@ -768,6 +757,7 @@ procedure TUpdateMangaManagerThread.Execute; on E: Exception do MainForm.ExceptionHandler(Self, E); end; + Synchronize(MainThreadEndGetting); end; end. From c7fbcac057d1e6afa463f7eb07f748f880d3a28b Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 11:30:12 +0800 Subject: [PATCH 0413/2794] thttpsendthread, clean up --- baseunits/uBaseUnit.pas | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index df62b538e..f0fc1a599 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -805,8 +805,6 @@ THTTPSendThread = class(THTTPSend) private FOwner: TFMDThread; procedure SetTimeout(AValue: Integer); - protected - procedure CloseConnection(SendTerminateTag: Boolean = True); procedure OnOwnerTerminate(Sender: TObject); public constructor Create(AOwner: TFMDThread); @@ -3518,20 +3516,10 @@ procedure THTTPSendThread.SetTimeout(AValue: Integer); Sock.SetTimeout(FTimeout); end; -procedure THTTPSendThread.CloseConnection(SendTerminateTag: Boolean); -begin - with Self.Sock do - begin - if SendTerminateTag then - Tag := 1; - StopFlag := True; - AbortSocket; - end; -end; - procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); begin - CloseConnection; + Sock.Tag := 1; + Sock.AbortSocket; end; constructor THTTPSendThread.Create(AOwner: TFMDThread); From ce402bf9ee4d82cd421a7045031da7f399fc6c95 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 11:31:09 +0800 Subject: [PATCH 0414/2794] websitemodules, some fix --- baseunits/WebsiteModules.pas | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 48224226e..dd35e6445 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -176,8 +176,8 @@ procedure TModuleContainer.SetTotalDirectory(AValue: Integer); constructor TModuleContainer.Create; begin - MaxTaskLimit := MAX_TASKLIMIT; - MaxConnectionLimit := MAX_CONNECTIONPERHOSTLIMIT; + MaxTaskLimit := 0; + MaxConnectionLimit := 0; ActiveTaskCount := 0; ActiveConnectionCount := 0; SortedList := False; @@ -321,7 +321,7 @@ function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation var Page: Integer; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber( MangaInfo, Page, TModuleContainer(FModuleList[ModuleId])); @@ -334,11 +334,10 @@ function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation end; function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; - const ModuleId: Integer): Integer; + const Names, Links: TStringList; const URL: String; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink( MangaInfo, Names, Links, URL, TModuleContainer(FModuleList[ModuleId])); @@ -411,14 +410,17 @@ procedure TWebsiteModules.UnlockModules; procedure TWebsiteModules.IncActiveTaskCount(ModuleId: Integer); begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - InterLockedIncrement(TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount); + with TModuleContainer(FModuleList[ModuleId]) do + if MaxTaskLimit > 0 then + InterLockedIncrement(ActiveTaskCount); end; procedure TWebsiteModules.DecActiveTaskCount(ModuleId: Integer); begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount > 0 then - InterLockedDecrement(TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount); + with TModuleContainer(FModuleList[ModuleId]) do + if ActiveTaskCount > 0 then + InterLockedDecrement(ActiveTaskCount); end; function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; @@ -426,20 +428,24 @@ function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; Result := True; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do - Result := ActiveTaskCount < MaxTaskLimit; + if MaxTaskLimit > 0 then + Result := ActiveTaskCount < MaxTaskLimit; end; procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - InterLockedIncrement(TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount); + with TModuleContainer(FModuleList[ModuleId]) do + if MaxConnectionLimit > 0 then + InterLockedIncrement(ActiveConnectionCount); end; procedure TWebsiteModules.DecActiveConnectionCount(ModuleId: Integer); begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount > 0 then - InterLockedDecrement(TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount); + with TModuleContainer(FModuleList[ModuleId]) do + if ActiveConnectionCount > 0 then + InterLockedDecrement(ActiveConnectionCount); end; function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; @@ -447,7 +453,8 @@ function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; Result := True; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do - Result := ActiveConnectionCount < MaxConnectionLimit; + if MaxConnectionLimit > 0 then + Result := ActiveConnectionCount < MaxConnectionLimit; end; function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; From 0a116f0ffdfd2cbdec060fbb7d946e815b39982c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 12:49:04 +0800 Subject: [PATCH 0415/2794] favoritemanager, applied connection limit from websitemodules should be synced with downloadthread and updatethread --- baseunits/uFavoritesManager.pas | 219 +++++++++++++++++--------------- 1 file changed, 120 insertions(+), 99 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 50b053c0b..392c4be6e 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, - uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, USimpleLogger; + uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules; type TFavoriteManager = class; @@ -25,6 +25,7 @@ TFavoriteThread = class(TFMDThread) protected procedure SyncStatus; procedure Execute; override; + procedure DoTerminate; override; public workCounter: Cardinal; getInfo: TMangaInformation; @@ -41,26 +42,28 @@ TFavoriteTask = class(TFMDThread) FBtnCaption: String; statuscheck: Integer; protected - function GetThreadCount: Integer; procedure SyncStartChecking; procedure SyncFinishChecking; procedure SyncUpdateBtnCaption; procedure SyncShowResult; + procedure Checkout; procedure Execute; override; public - CS_Threads: TCriticalSection; manager: TFavoriteManager; threads: TFPList; procedure PushNewCheck; procedure UpdateBtnCaption(Cap: String); constructor Create; destructor Destroy; override; - property ThreadCount: Integer read GetThreadCount; end; { TFavoriteContainer } TFavoriteContainer = Class + private + FModuleId: Integer; + FWebsite: String; + procedure SetWebsite(AValue: String); public FavoriteInfo: TFavoriteInfo; MangaInfo: TMangaInfo; @@ -69,7 +72,10 @@ TFavoriteTask = class(TFMDThread) Thread: TFavoriteThread; Manager: TFavoriteManager; Status: TFavoriteStatusType; + constructor Create; destructor Destroy; override; + property ModuleId: Integer read FModuleId; + property Website: String read FWebsite write SetWebsite; end; { TFavoriteManager } @@ -107,11 +113,11 @@ TFavoriteManager = class function IsMangaExist(const title, website: String): Boolean; function IsMangaExistURL(const website, URL: String): Boolean; // Add new manga to the list - procedure Add(const title, currentChapter, downloadedChapterList, - website, saveTo, link: String); + procedure Add(const Atitle, AcurrentChapter, AdownloadedChapterList, + Awebsite, AsaveTo, Alink: String); // Merge manga information with a title that already exist in FFavorites - procedure AddMerge(const title, currentChapter, downloadedChapterList, - website, saveTo, link: String); + procedure AddMerge(const Atitle, AcurrentChapter, AdownloadedChapterList, + Awebsite, AsaveTo, Alink: String); // Merge a FFavorites.ini with another FFavorites.ini procedure MergeWith(const APath: String); // Remove a manga from FFavorites @@ -156,6 +162,18 @@ implementation { TFavoriteContainer } +procedure TFavoriteContainer.SetWebsite(AValue: String); +begin + if FWebsite = AValue then Exit; + FWebsite := AValue; + FModuleId := Modules.LocateModule(FavoriteInfo.Website); +end; + +constructor TFavoriteContainer.Create; +begin + FModuleId := -1; +end; + destructor TFavoriteContainer.Destroy; begin if Assigned(Thread) then @@ -184,6 +202,7 @@ procedure TFavoriteThread.SyncStatus; procedure TFavoriteThread.Execute; begin if (container.FavoriteInfo.Link) = '' then Exit; + //Modules.IncActiveConnectionCount(container.ModuleId); try Synchronize(SyncStatus); getInfo.mangaInfo.title := container.FavoriteInfo.Title; @@ -196,6 +215,24 @@ procedure TFavoriteThread.Execute; on E: Exception do MainForm.ExceptionHandler(Self, E); end; + if Self.Terminated then + container.Status := STATUS_IDLE + else + container.Status := STATUS_CHECKED; + Synchronize(SyncStatus); +end; + +procedure TFavoriteThread.DoTerminate; +begin + LockCreateConnection; + try + Modules.DecActiveConnectionCount(container.ModuleId); + container.Thread := nil; + task.threads.Remove(Self); + finally + UnlockCreateConnection; + end; + inherited DoTerminate; end; constructor TFavoriteThread.Create; @@ -207,34 +244,12 @@ constructor TFavoriteThread.Create; destructor TFavoriteThread.Destroy; begin - if Self.Terminated then - container.Status := STATUS_IDLE - else - container.Status := STATUS_CHECKED; - task.CS_Threads.Acquire; - try - container.Thread := nil; - task.threads.Remove(Self); - Synchronize(SyncStatus); - finally - task.CS_Threads.Release; - end; getInfo.Free; inherited Destroy; end; { TFavoriteTask } -function TFavoriteTask.GetThreadCount: Integer; -begin - CS_Threads.Acquire; - try - Result := threads.Count; - finally - CS_Threads.Release; - end; -end; - procedure TFavoriteTask.SyncStartChecking; begin with MainForm do begin @@ -266,76 +281,80 @@ procedure TFavoriteTask.SyncShowResult; manager.ShowResult; end; -procedure TFavoriteTask.Execute; +procedure TFavoriteTask.Checkout; var i: Integer; - - procedure CheckOut; - var - j: Integer; - started: Boolean; - begin - manager.CS_Favorites.Acquire; - try - statuscheck := 0; - started := False; - for j := 0 to manager.FFavorites.Count-1 do - begin - with TFavoriteContainer(manager.FFavorites[j]) do +begin + if Terminated then Exit; + manager.CS_Favorites.Acquire; + try + statuscheck := 0; + for i := 0 to manager.FFavorites.Count - 1 do + with TFavoriteContainer(manager.FFavorites[i]) do + if Status = STATUS_CHECK then begin - if (Status = STATUS_CHECK) and - (Trim(FavoriteInfo.Link) <> '') then - begin - if not started then + LockCreateConnection; + try + if (threads.Count < OptionMaxThreads) and + Modules.CanCreateConnection(ModuleId) then begin - CS_Threads.Acquire; - try - if Thread = nil then - begin - Status := STATUS_CHECKING; - Thread := TFavoriteThread.Create; - Thread.task := Self; - Thread.container := manager.FavoriteItem(j); - Thread.workCounter := j; - threads.Add(Thread); - Thread.Start; - end; - finally - CS_Threads.Release; + Modules.IncActiveConnectionCount(ModuleId); + Thread := TFavoriteThread.Create; + threads.Add(Thread); + Status := STATUS_CHECKING; + with thread do + begin + task := Self; + container := manager.FavoriteItem(i); + workCounter := i; + Start; end; - started := True; - end; - Inc(statuscheck); + end + else + Inc(statuscheck); + finally + UnlockCreateConnection; end; end; - end; - finally - manager.CS_Favorites.Release; - end; + finally + manager.CS_Favorites.Release; end; +end; + +procedure TFavoriteTask.Execute; +var + i, cthread: Integer; begin manager.isRunning := True; Synchronize(SyncStartChecking); try - CheckOut; - while statuscheck > 0 do + Checkout; + while (not Terminated) and (statuscheck > 0) do begin + Sleep(SOCKHEARTBEATRATE); + // if current thread count > max threads allowed we wait until thread count decreased while (not Terminated) and (threads.Count >= OptionMaxThreads) do Sleep(SOCKHEARTBEATRATE); - if Terminated then Break; - CheckOut; + Checkout; + // if there is concurent connection limit applied and no more possible item to check + // we will wait until thread count decresed + cthread := threads.Count; + while (not Terminated) and (threads.Count > 0) and (threads.Count = cthread) do + Sleep(SOCKHEARTBEATRATE); + // if there is no more item need to be checked, but thread count still > 0 we will wait for it + // we will also wait if there is new item pushed, so we will check it after it while (not Terminated) and (statuscheck = 0) and (threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); end; - if Terminated and (ThreadCount > 0) then + if Terminated and (threads.Count > 0) then begin - CS_Threads.Acquire; + LockCreateConnection; try - for i := 0 to ThreadCount - 1 do + for i := 0 to threads.Count - 1 do TFavoriteThread(threads[i]).Terminate; finally - CS_Threads.Release; + UnlockCreateConnection; end; while threads.Count > 0 do Sleep(100); @@ -372,7 +391,6 @@ procedure TFavoriteTask.UpdateBtnCaption(Cap: String); constructor TFavoriteTask.Create; begin inherited Create(True); - CS_Threads := TCriticalSection.Create; threads := TFPList.Create; end; @@ -381,7 +399,6 @@ destructor TFavoriteTask.Destroy; manager.taskthread := nil; manager.isRunning := False; threads.Free; - CS_Threads.Free; inherited Destroy; end; @@ -452,8 +469,9 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); CS_Favorites.Acquire; try for i := 0 to FFavorites.Count-1 do - if TFavoriteContainer(FFavorites[i]).Status = STATUS_IDLE then - TFavoriteContainer(FFavorites[i]).Status := STATUS_CHECK; + with TFavoriteContainer(FFavorites[i]) do + if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then + Status := STATUS_CHECK; finally CS_Favorites.Release; end; @@ -768,21 +786,22 @@ function TFavoriteManager.IsMangaExistURL(const website, URL : String): Boolean; Result := False; end; -procedure TFavoriteManager.Add( - const title, currentChapter, downloadedChapterList, website, saveTo, link: String); +procedure TFavoriteManager.Add(const Atitle, AcurrentChapter, + AdownloadedChapterList, Awebsite, AsaveTo, Alink: String); begin - if IsMangaExist(title, website) then Exit; + if IsMangaExist(Atitle, Awebsite) then Exit; CS_Favorites.Acquire; try FFavorites.Add(TFavoriteContainer.Create); with TFavoriteContainer(FFavorites.Last) do begin Manager := Self; - FavoriteInfo.Title := title; - FavoriteInfo.currentChapter := currentChapter; - FavoriteInfo.website := website; - FavoriteInfo.saveTo := saveTo; - FavoriteInfo.Link := Link; - FavoriteInfo.downloadedChapterList := downloadedChapterList; + FavoriteInfo.Title := Atitle; + FavoriteInfo.currentChapter := AcurrentChapter; + FavoriteInfo.website := Awebsite; + FavoriteInfo.saveTo := AsaveTo; + FavoriteInfo.Link := ALink; + FavoriteInfo.downloadedChapterList := AdownloadedChapterList; + Website := AWebsite; Status := STATUS_IDLE; end; if not isRunning then @@ -795,22 +814,23 @@ procedure TFavoriteManager.Add( end; end; -procedure TFavoriteManager.AddMerge( - const title, currentChapter, downloadedChapterList, website, saveTo, link: String); +procedure TFavoriteManager.AddMerge(const Atitle, AcurrentChapter, + AdownloadedChapterList, Awebsite, AsaveTo, Alink: String); begin - if IsMangaExist(title, website) then + if IsMangaExist(Atitle, Awebsite) then Exit; CS_Favorites.Acquire; try FFavorites.Add(TFavoriteContainer.Create); with TFavoriteContainer(FFavorites.Last) do begin Manager := Self; - FavoriteInfo.Title := title; - FavoriteInfo.currentChapter := currentChapter; - FavoriteInfo.website := website; - FavoriteInfo.saveTo := saveTo; - FavoriteInfo.Link := Link; - FavoriteInfo.downloadedChapterList := downloadedChapterList; + FavoriteInfo.Title := Atitle; + FavoriteInfo.currentChapter := AcurrentChapter; + FavoriteInfo.website := Awebsite; + FavoriteInfo.saveTo := AsaveTo; + FavoriteInfo.Link := Alink; + FavoriteInfo.downloadedChapterList := AdownloadedChapterList; + Website := Awebsite; end; except CS_Favorites.Release; @@ -901,6 +921,7 @@ procedure TFavoriteManager.Restore; FavoriteInfo.SaveTo := CorrectPathSys(favoritesFile.ReadString(IntToStr(i), 'SaveTo', '')); FavoriteInfo.link := favoritesFile.ReadString(IntToStr(i), 'Link', ''); + Website := FavoriteInfo.Website; Status := STATUS_IDLE; end; end; From ac0874ef3e63eaebb6df7b08be2e7421ad10739a Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 12:55:47 +0800 Subject: [PATCH 0416/2794] increment task/connection count when creating thread there is delay between thread execution, even if they started in sequential order, the first thread not always the first to be executed. --- baseunits/uDownloadsManager.pas | 4 ++-- baseunits/uUpdateThread.pas | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 45cb35349..c16e199b6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -300,7 +300,6 @@ procedure TDownloadThread.Execute; var Reslt: Boolean = False; begin - Modules.IncActiveConnectionCount(ModuleId); try case checkStyle of // Get number of images. @@ -1320,6 +1319,7 @@ procedure TTaskThread.CheckOut; LockCreateConnection; try if Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread then Exit; + Modules.IncActiveConnectionCount(ModuleId); threads.Add(TDownloadThread.Create); with TDownloadThread(threads.Last) do begin manager := Self; @@ -1391,7 +1391,6 @@ procedure TTaskThread.Execute; begin INIAdvanced.Reload; ModuleId := container.ModuleId; - Modules.IncActiveTaskCount(ModuleId); container.ThreadState := True; container.DownloadInfo.TransferRate := ''; try @@ -2191,6 +2190,7 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); Status := STATUS_DOWNLOAD; DownloadInfo.Status := RS_Downloading; end; + Modules.IncActiveTaskCount(ModuleId); Thread := TTaskThread.Create; Thread.container := TaskItem(taskID); Thread.Start; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index ce03767c9..6b95527c3 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -111,7 +111,6 @@ procedure TUpdateMangaThread.Execute; names, links: TStringList; i: Integer; begin - Modules.IncActiveConnectionCount(manager.ModuleId); try if checkStyle = CS_INFO then Info := TMangaInformation.Create(Self, True) @@ -466,6 +465,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; LockCreateConnection; try if Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads then Exit; + Modules.IncActiveConnectionCount(ModuleId); threads.Add(TUpdateMangaThread.Create); TUpdateMangaThread(threads.Last).checkStyle := cs; TUpdateMangaThread(threads.Last).manager := Self; From c47c643c0f56a39cc6426c9ee97b9e8eba7d71ee Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 12:58:20 +0800 Subject: [PATCH 0417/2794] increase sockheartbeatrate this value doesn't used anymore in sock.onheartbeat, but still used for sleep parameter. --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f0fc1a599..1b13bc520 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -222,7 +222,7 @@ interface NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; - SOCKHEARTBEATRATE = 300; + SOCKHEARTBEATRATE = 400; DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_CUSTOM_RENAME = '%NUMBERING% - %CHAPTER%'; From b349c139c40636615abde8031347ead6c1e923cd Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 13:19:53 +0800 Subject: [PATCH 0418/2794] ba to to, set limit closes #85 --- baseunits/modules/Batoto.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 0c498b93a..425575cc5 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -365,6 +365,8 @@ procedure RegisterModule; begin Website := 'Batoto'; RootURL := 'http://bato.to'; + MaxTaskLimit := 2; + MaxConnectionLimit := 4; SortedList := True; InformationAvailable := True; TotalDirectory := Length(dirurls); From cd82483cf7aac2a3c6732b1397410542b2aa1ced Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 13:33:49 +0800 Subject: [PATCH 0419/2794] downloadmanager, minor fix --- baseunits/uDownloadsManager.pas | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c16e199b6..84af05b4a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2180,25 +2180,24 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; procedure TDownloadManager.ActiveTask(const taskID: Integer); begin - if taskID >= Containers.Count then Exit; - if Assigned(Containers[taskID]) then - with TTaskContainer(Containers[taskID]) do + if (taskID < 0) or (taskID >= Containers.Count) then Exit; + with TTaskContainer(Containers[taskID]) do + begin + if Status = STATUS_FINISH then Exit; + if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then begin - if Status = STATUS_FINISH then Exit; - if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then - begin - Status := STATUS_DOWNLOAD; - DownloadInfo.Status := RS_Downloading; - end; - Modules.IncActiveTaskCount(ModuleId); - Thread := TTaskThread.Create; - Thread.container := TaskItem(taskID); - Thread.Start; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; - if not MainForm.itRefreshDLInfo.Enabled then - MainForm.itRefreshDLInfo.Enabled := True; + Status := STATUS_DOWNLOAD; + DownloadInfo.Status := RS_Downloading; end; + Modules.IncActiveTaskCount(ModuleId); + Thread := TTaskThread.Create; + Thread.container := TaskItem(taskID); + Thread.Start; + MainForm.vtDownload.Repaint; + MainForm.vtDownloadFilters; + if not MainForm.itRefreshDLInfo.Enabled then + MainForm.itRefreshDLInfo.Enabled := True; + end; end; procedure TDownloadManager.StopTask(const taskID: Integer; From 8816045cda1aa3c0126e516d0ec480509203b99f Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 13:43:32 +0800 Subject: [PATCH 0420/2794] favoritemanager, some fix --- baseunits/uFavoritesManager.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 392c4be6e..e8bebde52 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -286,10 +286,13 @@ procedure TFavoriteTask.Checkout; i: Integer; begin if Terminated then Exit; + if manager.FFavorites.Count = 0 then Exit; manager.CS_Favorites.Acquire; try statuscheck := 0; for i := 0 to manager.FFavorites.Count - 1 do + begin + if Terminated then Break; with TFavoriteContainer(manager.FFavorites[i]) do if Status = STATUS_CHECK then begin @@ -316,6 +319,7 @@ procedure TFavoriteTask.Checkout; UnlockCreateConnection; end; end; + end; finally manager.CS_Favorites.Release; end; From aef6aca905b3d8bb78f4076e73fb099070789b4d Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 15:12:57 +0800 Subject: [PATCH 0421/2794] silentthread, implement connection limit --- baseunits/uSilentThread.pas | 194 +++++++++++++++++++----------------- 1 file changed, 100 insertions(+), 94 deletions(-) diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 447cf62d0..cdd5702a2 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -16,13 +16,15 @@ interface uses Classes, SysUtils, uBaseUnit, uData, uFMDThread, uDownloadsManager, - syncobjs; + WebsiteModules; type TMetaDataType = (MD_DownloadAll, MD_AddToFavorites); TSilentThreadMetaData = class + private + ModuleId: Integer; public MetaDataType: TMetaDataType; Website, Title, URL, SaveTo: String; @@ -41,8 +43,9 @@ TSilentThread = class(TFMDThread) Freconnect: Cardinal; // manga information from main thread title, website, URL: String; + ModuleId: Integer; procedure MainThreadAfterChecking; virtual; - procedure MainThreadUpdateStatus; + procedure DoTerminate; override; procedure Execute; override; public Manager: TSilentThreadManager; @@ -62,6 +65,7 @@ TSilentAddToFavThread = class(TSilentThread) TSilentThreadManagerThread = class(TFMDThread) protected + procedure Checkout; procedure Execute; override; public Manager: TSilentThreadManager; @@ -76,13 +80,12 @@ TSilentThreadManager = class FManagerThread: TSilentThreadManagerThread; function GetItemCount: Integer; procedure StartManagerThread; + procedure Checkout(Index: Integer); public - CS_Threads: TCriticalSection; MetaData: TFPList; Threads: TFPList; procedure Add(AType: TMetaDataType; AWebsite, AManga, AURL: String; ASavePath: String = ''); - procedure CheckOut; procedure StopAll(WaitFor: Boolean = True); procedure UpdateLoadStatus; procedure BeginAdd; @@ -102,20 +105,50 @@ implementation { TSilentThreadManagerThread } -procedure TSilentThreadManagerThread.Execute; +procedure TSilentThreadManagerThread.Checkout; +var + i: Integer; begin - if Manager = nil then Exit; - while (not Terminated) and (Manager.MetaData.Count > 0) do + if Terminated then Exit; + if Manager.MetaData.Count = 0 then Exit; + with Manager do begin - while Manager.Threads.Count >= OptionMaxThreads do + i := 0; + while i < MetaData.Count do begin - if Terminated then Exit; - Sleep(500); + if Terminated then Break; + with TSilentThreadMetaData(MetaData[i]) do + if (Threads.Count < OptionMaxThreads) and + Modules.CanCreateConnection(ModuleId) then + begin + LockCreateConnection; + try + if Modules.CanCreateConnection(ModuleId) then + Manager.Checkout(i); + finally + UnlockCreateConnection; + end; + end + else + Inc(i); end; - Manager.CheckOut; end; end; +procedure TSilentThreadManagerThread.Execute; +begin + if Manager = nil then Exit; + Self.Checkout; + with manager do + while (not Terminated) and (MetaData.Count > 0) do + begin + Sleep(SOCKHEARTBEATRATE); + while (not Terminated) and (Threads.Count >= OptionMaxThreads) do + Sleep(SOCKHEARTBEATRATE); + Self.Checkout; + end; +end; + destructor TSilentThreadManagerThread.Destroy; begin Manager.FManagerThread := nil; @@ -126,12 +159,7 @@ destructor TSilentThreadManagerThread.Destroy; function TSilentThreadManager.GetItemCount: Integer; begin - CS_Threads.Acquire; - try - Result := MetaData.Count + Threads.Count; - finally - CS_Threads.Release; - end; + Result := MetaData.Count + Threads.Count; end; procedure TSilentThreadManager.StartManagerThread; @@ -150,13 +178,8 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; if not ((AType = MD_AddToFavorites) and (MainForm.FavoriteManager.IsMangaExist(AManga, AWebsite))) then begin - CS_Threads.Acquire; - try - MetaData.Add(TSilentThreadMetaData.Create( - AType, AWebsite, AManga, AURL, ASavePath)); - finally - CS_Threads.Release; - end; + MetaData.Add(TSilentThreadMetaData.Create( + AType, AWebsite, AManga, AURL, ASavePath)); if not FLockAdd then begin StartManagerThread; @@ -165,31 +188,26 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; end; end; -procedure TSilentThreadManager.CheckOut; +procedure TSilentThreadManager.Checkout(Index: Integer); begin - CS_Threads.Acquire; - try - INIAdvanced.Reload; - if MetaData.Count > 0 then - begin - case TSilentThreadMetaData(MetaData.First).MetaDataType of - MD_DownloadAll: Threads.Add(TSilentThread.Create); - MD_AddToFavorites: Threads.Add(TSilentAddToFavThread.Create); - end; - with TSilentThread(Threads.Last) do - begin - Manager := Self; - website := TSilentThreadMetaData(MetaData.First).Website; - title := TSilentThreadMetaData(MetaData.First).Title; - URL := TSilentThreadMetaData(MetaData.First).URL; - SavePath := TSilentThreadMetaData(MetaData.First).SaveTo; - Start; - TSilentThreadMetaData(MetaData.First).Free; - MetaData.Remove(MetaData.First); - end; - end; - finally - CS_Threads.Release; + if (Index < 0) or (Index >= MetaData.Count) then Exit; + INIAdvanced.Reload; + Modules.IncActiveConnectionCount(TSilentThreadMetaData(MetaData[Index]).ModuleId); + case TSilentThreadMetaData(MetaData[Index]).MetaDataType of + MD_DownloadAll: Threads.Add(TSilentThread.Create); + MD_AddToFavorites: Threads.Add(TSilentAddToFavThread.Create); + end; + with TSilentThread(Threads.Last) do + begin + Manager := Self; + website := TSilentThreadMetaData(MetaData[Index]).Website; + title := TSilentThreadMetaData(MetaData[Index]).Title; + URL := TSilentThreadMetaData(MetaData[Index]).URL; + SavePath := TSilentThreadMetaData(MetaData[Index]).SaveTo; + ModuleId := TSilentThreadMetaData(MetaData[Index]).ModuleId; + Start; + TSilentThreadMetaData(MetaData[Index]).Free; + MetaData.Delete(Index); end; end; @@ -199,25 +217,20 @@ procedure TSilentThreadManager.StopAll(WaitFor: Boolean); begin if MetaData.Count or Threads.Count > 0 then begin - CS_Threads.Acquire; - try - while MetaData.Count > 0 do - begin - TSilentThreadMetaData(MetaData.Last).Free; - MetaData.Remove(MetaData.Last); - end; - if Assigned(FManagerThread) then - begin - FManagerThread.Terminate; - if WaitFor then - FManagerThread.WaitFor; - end; - if Threads.Count > 0 then - for i := 0 to Threads.Count - 1 do - TSilentThread(Threads[i]).Terminate; - finally - CS_Threads.Release; + while MetaData.Count > 0 do + begin + TSilentThreadMetaData(MetaData.Last).Free; + MetaData.Remove(MetaData.Last); + end; + if Assigned(FManagerThread) then + begin + FManagerThread.Terminate; + if WaitFor then + FManagerThread.WaitFor; end; + if Threads.Count > 0 then + for i := 0 to Threads.Count - 1 do + TSilentThread(Threads[i]).Terminate; if WaitFor then while ItemCount > 0 do Sleep(100); @@ -251,7 +264,6 @@ procedure TSilentThreadManager.EndAdd; constructor TSilentThreadManager.Create; begin inherited Create; - CS_Threads := TCriticalSection.Create; MetaData := TFPList.Create; Threads := TFPList.Create; FLockAdd := False; @@ -263,25 +275,19 @@ destructor TSilentThreadManager.Destroy; begin if ItemCount > 0 then begin - CS_Threads.Acquire; - try - while MetaData.Count > 0 do - begin - TSilentThreadMetaData(MetaData.Last).Free; - MetaData.Remove(MetaData.Last); - end; - if Threads.Count > 0 then - for i := 0 to Threads.Count - 1 do - TSilentThread(Threads[i]).Terminate; - finally - CS_Threads.Release; + while MetaData.Count > 0 do + begin + TSilentThreadMetaData(MetaData.Last).Free; + MetaData.Remove(MetaData.Last); end; + if Threads.Count > 0 then + for i := 0 to Threads.Count - 1 do + TSilentThread(Threads[i]).Terminate; while ItemCount > 0 do Sleep(100); end; MetaData.Free; Threads.Free; - CS_Threads.Free; inherited Destroy; end; @@ -296,6 +302,7 @@ constructor TSilentThreadMetaData.Create(const AType: TMetaDataType; Title := AManga; URL := AURL; SaveTo := APath; + ModuleId := Modules.LocateModule(Website); end; { TSilentThread } @@ -388,19 +395,24 @@ procedure TSilentThread.MainThreadAfterChecking; end; end; -procedure TSilentThread.MainThreadUpdateStatus; +procedure TSilentThread.DoTerminate; begin - if Manager.ItemCount > 0 then - MainForm.sbMain.Panels[1].Text := - Format(RS_SilentThreadLoadStatus, [Manager.Threads.Count, Manager.ItemCount]) - else - MainForm.sbMain.Panels[1].Text := ''; + LockCreateConnection; + try + Modules.DecActiveConnectionCount(ModuleId); + Manager.Threads.Remove(Self); + finally + UnlockCreateConnection; + end; + Synchronize(Manager.UpdateLoadStatus); + inherited DoTerminate; end; procedure TSilentThread.Execute; begin + Synchronize(Manager.UpdateLoadStatus); try - Synchronize(MainThreadUpdateStatus); + Info.ModuleId := Self.ModuleId; Info.mangaInfo.title := title; if Info.GetInfoFromURL(website, URL, OptionConnectionMaxRetry) = NO_ERROR then if not Terminated then @@ -409,13 +421,6 @@ procedure TSilentThread.Execute; on E: Exception do MainForm.ExceptionHandler(Self, E); end; - Manager.CS_Threads.Acquire; - try - Manager.Threads.Remove(Self); - finally - Manager.CS_Threads.Release; - end; - Synchronize(MainThreadUpdateStatus); end; constructor TSilentThread.Create; @@ -424,6 +429,7 @@ constructor TSilentThread.Create; Freconnect := 3; SavePath := ''; Info := TMangaInformation.Create(Self); + ModuleId := -1; end; destructor TSilentThread.Destroy; From 768ff15e6b120c2f963ac1884c7d9e6c6bb7c58d Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 4 Aug 2015 15:26:27 +0800 Subject: [PATCH 0422/2794] ba to to, change task limit --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 425575cc5..c66082426 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -365,7 +365,7 @@ procedure RegisterModule; begin Website := 'Batoto'; RootURL := 'http://bato.to'; - MaxTaskLimit := 2; + MaxTaskLimit := 1; MaxConnectionLimit := 4; SortedList := True; InformationAvailable := True; From 2800e1042618aa42ae6b9ade2ee897bc25761ca2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 01:43:05 +0800 Subject: [PATCH 0423/2794] baseunit, add getpageandparse function --- baseunits/uBaseUnit.pas | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1b13bc520..7cd1e5739 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -851,7 +851,7 @@ procedure RemoveHostFromURLsPair(Const URLs, Names : TStringList); procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); //HTML -procedure ParseHTML(const aRaw: string; var aOutput: TStringList); +procedure ParseHTML(const aRaw: string; aOutput: TStrings); //convert charset to utf8 procedure ConvertCharsetToUTF8(var TheStrings: TStringList); @@ -934,6 +934,8 @@ procedure CustomGenres(var output: TStringList; input: String); // deal with sourceforge URL. function SourceForgeURL(URL: String): String; // Get HTML source code from a URL. +function GetPageAndParse(const AHTTP: THTTPSend; Output: TStrings; URL: String; + const Reconnect: Integer = 0): Integer; function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; overload; function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; @@ -1531,7 +1533,7 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); OutArray.EndUpdate; end; -procedure ParseHTML(const aRaw: string; var aOutput: TStringList); +procedure ParseHTML(const aRaw: string; aOutput: TStrings); begin if not Assigned(aOutput) then Exit; with TParseHTML.Create(aRaw) do try @@ -2751,6 +2753,24 @@ function SourceForgeURL(URL: String): String; Result := URL; end; +function GetPageAndParse(const AHTTP: THTTPSend; Output: TStrings; URL: String; + const Reconnect: Integer): Integer; +begin + if Output = nil then Exit(INFORMATION_NOT_FOUND); + if GetPage(AHTTP, TObject(Output), URL, Reconnect) then + begin + if Output.Count > 0 then + begin + Result := NO_ERROR; + ParseHTML(Output.Text, Output); + end + else + Result := INFORMATION_NOT_FOUND; + end + else + Result := NET_PROBLEM; +end; + function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; const Reconnect: Integer): Boolean; // If AHTTP <> nil, we will use it as http sender. Otherwise we create a new From 713be58d036875d3e579d4580207f0e7e3982c51 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 01:54:43 +0800 Subject: [PATCH 0424/2794] baseunit, some changes --- baseunits/uBaseUnit.pas | 79 +++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7cd1e5739..15c3916f5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -854,7 +854,8 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); procedure ParseHTML(const aRaw: string; aOutput: TStrings); //convert charset to utf8 -procedure ConvertCharsetToUTF8(var TheStrings: TStringList); +function ConvertCharsetToUTF8(S: String): String; overload; +procedure ConvertCharsetToUTF8(S: TStrings); overload; // StringUtils function QuotedStrd(const S: string): string; overload; @@ -1544,45 +1545,55 @@ procedure ParseHTML(const aRaw: string; aOutput: TStrings); end; end; -procedure ConvertCharsetToUTF8(var TheStrings: TStringList); +function ConvertCharsetToUTF8(S: String): String; var cs: String; - i: Integer; begin - if TheStrings = nil then Exit; - if TheStrings.Count = 0 then Exit; + Result := S; + if Trim(S) = '' then Exit; with TRegExpr.Create do - try - cs := ''; - Expression := '(?ig)^.* 0 then - begin - if Exec(TheStrings[i]) then - cs := Replace(TheStrings[i], '$1', True); - if cs <> '' then - begin - cs := LowerCase(cs); - Break; - end; - end; + try + Expression := '(?ig)^.* '' then - begin - if cs = 'gb2312' then - cs := EncodingCP936 - else - if (cs = 'big5') or (cs = 'big5-hkscs') then - cs := EncodingCP950; - end - else - cs := GuessEncoding(TheStrings.Text); - finally - Free; + if cs <> '' then Result := ConvertEncoding(S, cs, 'utf8'); +end; + +procedure ConvertCharsetToUTF8(S: TStrings); +var + cs: String; + i: Integer; +begin + if Trim(S.Text) = '' then Exit; + cs := ''; + if S.Count > 1 then + begin + with TRegExpr.Create do + try + Expression := '(?ig)^.* 0 then Break + else if Pos(' 0 then + if Exec(S[i]) then + begin + cs := LowerCase(Replace(S[i], '$1', True)); + if cs = 'gb2312' then cs := EncodingCP936 + else if (cs = 'big5') or (cs = 'big5-hkscs') then cs := EncodingCP950; + Break; + end; + finally + Free; + end; end; - if cs <> '' then - TheStrings.Text := ConvertEncoding(TheStrings.Text, cs, 'utf8'); + if cs = '' then cs := GuessEncoding(S.Text); + if cs <> '' then S.Text := ConvertEncoding(S.Text, cs, 'utf8'); end; function QuotedStrd(const S: string): string; From 7ab30bf8774c1f706f81972f622d0b1b39daef6f Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 07:29:26 +0800 Subject: [PATCH 0425/2794] fix not saving drop target position and size on close --- mangadownloader/forms/frmDropTarget.pas | 5 ++++ mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.pas | 32 ++++++++++--------------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index a044aeb1a..ce84bd147 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -101,6 +101,11 @@ procedure TFormDropTarget.FormCreate(Sender: TObject); procedure TFormDropTarget.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin + FAlphaBlendValue := AlphaBlendValue; + FWidth := Width; + FHeight := Height; + FLeft := Left; + FTop := Top; MainForm.SaveDropTargetFormInformation; CloseAction := caFree; end; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9787e513f..d55956ec8 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2023,7 +2023,6 @@ object MainForm: TMainForm Top = 9 Width = 100 Caption = 'Show Drop Box' - OnChange = ckDropTargetChange ParentFont = False TabOrder = 0 end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5c6e52504..ee20f1a6c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -353,7 +353,6 @@ TMainForm = class(TForm) procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); - procedure ckDropTargetChange(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -2178,23 +2177,6 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); end; end; -procedure TMainForm.ckDropTargetChange(Sender: TObject); -begin - if ckDropTarget.Checked then - begin - if FormDropTarget = nil then - Application.CreateForm(TFormDropTarget, FormDropTarget); - frmDropTarget.OnDropChekout := @AddSilentThread; - frmDropTarget.FAlphaBlendValue := tbDropTargetOpacity.Position; - FormDropTarget.Show; - end - else - begin - if Assigned(FormDropTarget) then - FormDropTarget.Close; - end; -end; - procedure TMainForm.clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -4635,6 +4617,19 @@ procedure TMainForm.ApplyOptions; //view ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; + if ckDropTarget.Checked then + begin + if FormDropTarget = nil then + Application.CreateForm(TFormDropTarget, FormDropTarget); + frmDropTarget.OnDropChekout := @AddSilentThread; + frmDropTarget.FAlphaBlendValue := tbDropTargetOpacity.Position; + FormDropTarget.Show; + end + else + begin + if Assigned(FormDropTarget) then + FormDropTarget.Close; + end; //connection OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; @@ -4958,7 +4953,6 @@ procedure TMainForm.SaveDropTargetFormInformation; WriteInteger('droptarget', 'Heigth', frmDropTarget.FHeight); WriteInteger('droptarget', 'Top', frmDropTarget.FTop); WriteInteger('droptarget', 'Left', frmDropTarget.FLeft); - UpdateFile; end; end; From d2c990f1ba7290fb43ab4043c386457c404b6620 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 07:53:26 +0800 Subject: [PATCH 0426/2794] downloadmanager, fix high cpu usage while download using websitemodules --- baseunits/uDownloadsManager.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 84af05b4a..01ff37502 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1258,7 +1258,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; Format('%.3d', [workCounter + 1]), prefix, manager.container.Manager.retryConnect); - if Terminated then Exit(False); if Result then manager.container.PageLinks[workCounter] := 'D'; @@ -1306,7 +1305,7 @@ procedure TTaskThread.CheckOut; Exit; end; - if ModuleId > -1 then + if Modules.MaxConnectionLimit[ModuleId] > 0 then while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do Sleep(SOCKHEARTBEATRATE) else From ab426e87eed0f3c93319582cb93ce5d63b08be1d Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 10:03:02 +0800 Subject: [PATCH 0427/2794] fix range check error when trying to check empty selected node fix #87 --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ee20f1a6c..b58ffc2e1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2582,7 +2582,7 @@ procedure TMainForm.miChapterListCheckSelectedClick(Sender: TObject); i: Cardinal; xNode: PVirtualNode; begin - if clbChapterList.RootNodeCount > 0 then + if clbChapterList.SelectedCount > 0 then begin xNode := clbChapterList.GetFirstSelected; for i := 0 to clbChapterList.SelectedCount - 1 do From ecee7a7ca87b3eef02b14db60c43729d2456fb53 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 11:12:28 +0800 Subject: [PATCH 0428/2794] downloadmanager, taskthread call stop with synchronize, rename some procedure --- baseunits/uDownloadsManager.pas | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 01ff37502..d21956ab0 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -90,8 +90,8 @@ TTaskThread = class(TFMDThread) procedure DoTerminate; override; procedure Compress; // show notification when download completed - procedure ShowBaloon; - procedure Stop(const check: Boolean = True); + procedure SyncShowBaloon; + procedure SyncStop; public //additional parameter httpCookies: String; @@ -1190,7 +1190,7 @@ procedure TTaskThread.Compress; end; end; -procedure TTaskThread.ShowBaloon; +procedure TTaskThread.SyncShowBaloon; begin if container.Status = STATUS_FAILED then begin @@ -1574,7 +1574,7 @@ procedure TTaskThread.Execute; container.DownloadInfo.Status := RS_Finish; container.DownloadInfo.Progress := ''; end; - Synchronize(ShowBaloon); + Synchronize(SyncShowBaloon); except on E: Exception do MainForm.ExceptionHandler(Self, E); @@ -1597,19 +1597,19 @@ procedure TTaskThread.DoTerminate; while threads.Count > 0 do Sleep(100); end; - Stop; container.DownloadInfo.TransferRate := ''; container.ThreadState := False; container.Thread := nil; Modules.DecActiveTaskCount(ModuleId); + Synchronize(SyncStop); inherited DoTerminate; end; -procedure TTaskThread.Stop(const check: Boolean = True); +procedure TTaskThread.SyncStop; begin if container.Status = STATUS_STOP then Exit; - if check and not (container.Manager.isReadyForExit) then + if not container.Manager.isReadyForExit then begin if (container.WorkCounter >= container.PageLinks.Count) and (container.CurrentDownloadChapterPtr >= container.ChapterLinks.Count) @@ -1618,18 +1618,18 @@ procedure TTaskThread.Stop(const check: Boolean = True); container.Status := STATUS_FINISH; container.DownloadInfo.Status := RS_Finish; container.DownloadInfo.Progress := ''; - container.Manager.CheckAndActiveTask(True, Self); + container.Manager.CheckAndActiveTask(True); end else if (container.Status in [STATUS_PROBLEM, STATUS_FAILED]) then - container.Manager.CheckAndActiveTask(True, Self) + container.Manager.CheckAndActiveTask(True) else begin container.Status := STATUS_STOP; container.DownloadInfo.Status := Format('%s (%d/%d)', [RS_Stopped, container.CurrentDownloadChapterPtr + 1, container.ChapterLinks.Count]); - container.Manager.CheckAndActiveTask(False, Self); + container.Manager.CheckAndActiveTask(False); end; end; end; @@ -2206,7 +2206,6 @@ procedure TDownloadManager.StopTask(const taskID: Integer; begin if TaskItem(taskID).Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT] then begin - isReadyForExit := False; if TaskItem(taskID).Status = STATUS_WAIT then begin TaskItem(taskID).Status := STATUS_STOP; @@ -2256,7 +2255,6 @@ procedure TDownloadManager.StopAllTasks; begin if Containers.Count > 0 then begin - isReadyForExit := False; for i := 0 to Containers.Count - 1 do begin if TaskItem(i).Status = STATUS_WAIT then From f6f7b6898efa656e918961f7fc615df5a4de9f00 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 11:52:34 +0800 Subject: [PATCH 0429/2794] remove ehentai script will be replaced by ehentai module --- .../includes/EHentai/chapter_page_number.inc | 148 --------------- .../EHentai/directory_page_number.inc | 44 ----- baseunits/includes/EHentai/image_url.inc | 98 ---------- .../includes/EHentai/manga_information.inc | 156 ---------------- .../includes/EHentai/names_and_links.inc | 61 ------ baseunits/uBaseUnit.pas | 175 ++++++++---------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 17 +- baseunits/uGetMangaInfosThread.pas | 4 +- 9 files changed, 91 insertions(+), 627 deletions(-) delete mode 100644 baseunits/includes/EHentai/chapter_page_number.inc delete mode 100644 baseunits/includes/EHentai/directory_page_number.inc delete mode 100644 baseunits/includes/EHentai/image_url.inc delete mode 100644 baseunits/includes/EHentai/manga_information.inc delete mode 100644 baseunits/includes/EHentai/names_and_links.inc diff --git a/baseunits/includes/EHentai/chapter_page_number.inc b/baseunits/includes/EHentai/chapter_page_number.inc deleted file mode 100644 index 3438541a1..000000000 --- a/baseunits/includes/EHentai/chapter_page_number.inc +++ /dev/null @@ -1,148 +0,0 @@ - function GetEHentaiPageNumber: Boolean; - var - s: String; - i, j, g, p: Cardinal; - l: TStringList; - regx: TRegExpr; - cw: Boolean; - begin - regx := TRegExpr.Create; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(EHENTAI_ID, URL); - regx.Expression := '^(.*)/\?p=\d.*$'; - s := regx.Replace(s, '$1', True); - s := ReplaceRegExpr('\?nw=.+$', s, '', False); - if not ExecRegExpr('/$', s) then - s := s + '/'; - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - // check if content warning - cw := False; - if l.Count > 0 then - begin - for i := 0 to l.Count - 1 do - begin - if Pos('>Content Warning 0 then - begin - cw := True; - Break; - end; - end; - if cw then - begin - s := s + '?nw=session'; - //s := s + '?nw=always'; - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - end; - end; - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - g := 0; - p := 0; - //get images page count method 1 - regx.Expression := '^.*onclick="sp\((\d+)\).*$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('onclick="sp(', parse.Strings[i]) > 0) then - begin - g := StrToIntDef(regx.Replace(parse.Strings[i], '$1', True), 0); - if g > p then - p := g; - end; - end; - - {//get images page count method 2 - for i := 0 to parse.Count - 1 do - begin - if (Pos('Images:', parse.Strings[i])>0) then - if (Pos('class="gdt1"', parse.Strings[i-1])>0) AND - (Pos('', parse.Strings[i+1])>0) AND - (Pos('class="gdt2"', parse.Strings[i+2])>0) then //to make sure not getting false line - begin - g := Pos('@', parse.Strings[i+3]); - if (g>0) then - begin - try - s := Trim(Copy(parse.Strings[i+3], 1, g-1)); - g := StrToInt(s); - p := g div 40; // per pages contain max 40 images - if g mod 40 > 0 then - p := p+1; - except - p := 2; - end; - end - else - p := 2; - - Dec(p); //1 is page 2 - Break; - end; - end; } - - //manager.container.PageNumber := 0; - //manager.container.PageContainerLinks.Clear; - - //get images page in first page container - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="gdtm"', parse.Strings[i]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 2], 'href=')); - s := StringReplace(s, WebsiteRoots[EHENTAI_ID, 1] + '/s/', '', []); - manager.container.PageContainerLinks.Add(s); - end; - end; - - //get all images page for the rest of page container - if p > 0 then - begin - for i := 1 to p do - begin - parse.Clear; - l.Clear; - s := StringReplace(URL, WebsiteRoots[EHENTAI_ID, 1], '', []); - s := StringReplace(s, '?nw=session', '', [rfReplaceAll]); - s := StringReplace(s, '?nw=always', '', [rfReplaceAll]); - s := WebsiteRoots[EHENTAI_ID, 1] + s; - //if s[Length(s)]='/' then - //SetLength(s, Length(s)-1); - if s[Length((s))] <> '/' then - s := s + '/'; - s := s + '?p=' + IntToStr(i); - //s:= s+'?nw=session'; - - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for j := 0 to parse.Count - 1 do - if (Pos('class="gdtm"', parse.Strings[j]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[j + 2], 'href=')); - s := StringReplace(s, WebsiteRoots[EHENTAI_ID, 1] + '/s/', '', []); - manager.container.PageContainerLinks.Add(s); - end; - end; - end; - manager.container.PageNumber := manager.container.PageContainerLinks.Count; - manager.container.PageLinks.Clear; - while manager.container.PageLinks.Count < manager.container.PageContainerLinks.Count do - manager.container.PageLinks.Add('G') - end; - parse.Free; - l.Free; - regx.Free; - end; diff --git a/baseunits/includes/EHentai/directory_page_number.inc b/baseunits/includes/EHentai/directory_page_number.inc deleted file mode 100644 index bd911103a..000000000 --- a/baseunits/includes/EHentai/directory_page_number.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetEHentaiDirectoryPageNumber: Byte; - var - i, g: Cardinal; - regx: TRegExpr; - begin - - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[EHENTAI_ID, 1] + '/?' + EHENTAI_BROWSER; - //s:= s+'?nw=session'; - - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - Page := 0; - g := 0; - regx := TRegExpr.Create; - regx.Expression := '^.*onclick="sp\((\d+)\).*$'; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (Pos('onclick="sp(', parse.Strings[i]) > 0) then - begin - g := StrToIntDef(regx.Replace(parse.Strings[i], '$1', True), 0); - if g > Page then - Page := g; - end; - end; - regx.Free; - - Page := Page + 1; //page1=0 - - Source.Free; - Result := NO_ERROR; - end; \ No newline at end of file diff --git a/baseunits/includes/EHentai/image_url.inc b/baseunits/includes/EHentai/image_url.inc deleted file mode 100644 index 397102d7e..000000000 --- a/baseunits/includes/EHentai/image_url.inc +++ /dev/null @@ -1,98 +0,0 @@ - function getEHentaiImageURL: Boolean; - var - i, RetryCount: Integer; - prs: TStringList; - hparser: THTMLParser; - {s, }purl, iurl, base_url, startkey, gid, startpage, nl: String; - begin - Result := False; - - //Result := 'W'; - //s := manager.container.DownloadInfo.SaveTo + - // '/' + manager.container.ChapterName.Strings[ - // manager.container.CurrentDownloadChapterPtr] + '/' + - // Format('%.3d', [workCounter + 1]); - // Check to see if a file with similar name was already exist. If so then we - // skip the download process. - //if (FileExistsUTF8(s + '.jpg')) or - // (FileExistsUTF8(s + '.png')) or - // (FileExistsUTF8(s + '.gif')) then - //begin - // Result := 'D'; - // Exit; - //end; - - purl := manager.container.PageContainerLinks[workCounter]; - purl := FillMangaSiteHost(EHENTAI_ID, '/s/' + purl); - RetryCount := 0; - while not Result do - begin - iurl := ''; - prs := TStringList.Create; - GetPage(TObject(prs), purl, - manager.container.Manager.retryConnect); - if Self.Terminated then - begin - prs.Free; - Exit; - end; - - parse := TStringList.Create; - hparser := THTMLParser.Create(PChar(prs.Text)); - hparser.OnFoundTag := OnTag; - hparser.OnFoundText := OnText; - hparser.Exec; - hparser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (Pos(' 0) and - ((Pos(' style=', parse[i]) > 0) or - (Pos(' id="img"', parse[i]) > 0) or - (Pos('/keystamp=', parse.Strings[i]) > 0)) then - begin - iurl := GetAttributeValue(GetTagAttribute(parse[i], 'src=')); - iurl := StringReplace(iurl, '&', '&', [rfReplaceAll, rfIgnoreCase]); - end; - if Pos('onclick="return nl(', parse[i]) > 0 then - nl := ReplaceRegExpr('^.*nl\((\d+)\).*$', parse[i], '$1', True); - end; - - //new reload link - if prs.Count > 0 then - begin - for i := 0 to prs.Count - 1 do - begin - if Pos('var base_url=', prs[i]) > 0 then - base_url := GetValuesFromString(prs[i], '='); - if Pos('var startkey=', prs[i]) > 0 then - startkey := GetValuesFromString(prs[i], '='); - if Pos('var gid=', prs[i]) > 0 then - gid := GetValuesFromString(prs[i], '='); - if Pos('var startpage=', prs[i]) > 0 then - startpage := GetValuesFromString(prs[i], '='); - end; - if nl <> '' then - purl := base_url + '/s/' + startkey + '/' + gid + '-' + startpage + '?nl=' + nl; - end; - parse.Free; - prs.Free; - - //save image - Result := SaveImage( - manager.container.MangaSiteID, - iurl, - lpath, - Format('%.3d', [workCounter + 1]), - prefix, - 1); - - if (manager.container.Manager.retryConnect <> 0) and - (manager.container.Manager.retryConnect <= RetryCount) then - Break; - - if not Result then - Inc(RetryCount); - end; - end; diff --git a/baseunits/includes/EHentai/manga_information.inc b/baseunits/includes/EHentai/manga_information.inc deleted file mode 100644 index 29e8833ab..000000000 --- a/baseunits/includes/EHentai/manga_information.inc +++ /dev/null @@ -1,156 +0,0 @@ - function GetEHentaiInfoFromURL: Byte; - var - i: Cardinal; - s: String; - rgex: TRegExpr; - ava: Boolean = False; - cw: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[EHENTAI_ID, 0]; - mangaInfo.url := FillMangaSiteHost(EHENTAI_ID, URL); - mangaInfo.url := ReplaceRegExpr('\?nw=.+$', mangaInfo.url, '', False); - if not ExecRegExpr('/$', mangaInfo.url) then - mangaInfo.url := mangaInfo.url + '/'; - s := mangaInfo.url; - mangaInfo.summary := ''; - if not GetPage(TObject(Source), s, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - if Source.Count > 0 then - begin - // check if banned - if Source.Count = 1 then - begin - //if mangaInfo.genres = '' then - mangaInfo.summary := Source.Text; - Result := NO_ERROR; - Source.Free; - Exit; - end; - - // check if content warning - cw := False; - for i := 0 to Source.Count - 1 do - begin - if Pos('>Content Warning 0 then - begin - cw := True; - Break; - end; - end; - if cw then - begin - s := s + '?nw=session'; - //s := s + '?nw=always'; - if not GetPage(TObject(Source), s, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - end; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count < 1 then - begin - Result := INFORMATION_NOT_FOUND; - Exit; - end - else - begin - // check availability - for i := 0 to parse.Count - 1 do - begin - if Pos('id="gn"', parse.Strings[i]) > 0 then - begin - ava := True; - Break; - end; - end; - // not available - if not ava then - begin - for i := 0 to parse.Count - 1 do - if Pos('

', parse.Strings[i]) > 0 then - begin - mangaInfo.summary := Trim(parse.Strings[i + 1]); - Break; - end; - mangaInfo.status := '0'; - parse.Clear; - Result := NO_ERROR; - Exit; - end; - end; - - mangaInfo.title := ''; - mangaInfo.authors :=' '; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - if parse.Count > 1 then - begin - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('id="gd1"', parse.Strings[i]) > 0) and - (Pos(' 0) then - mangaInfo.coverLink := - GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'src=')); - - // get title - if (Pos('id="gn"', parse.Strings[i]) <> 0) then - begin - s := Trim(HTMLEntitiesFilter(StringFilter(parse.Strings[i + 1]))); - if s <> '' then - mangaInfo.title := s; - end; - - // get artists - if (Pos('id="td_artist:', parse.Strings[i]) > 0) then - if mangaInfo.artists = '' then - mangaInfo.artists := parse.Strings[i + 2] - else - mangaInfo.artists := mangaInfo.artists + ', ' + parse.Strings[i + 2]; - - // get misc genres (language, parodi, character, etc) - if (Pos('id="td_', parse.Strings[i]) > 0) and - (Pos('id="td_artist:', parse.Strings[i]) = 0) then //exclude artist - if mangaInfo.genres = '' then - mangaInfo.genres := parse.Strings[i + 2] - else - mangaInfo.genres := mangaInfo.genres + ', ' + parse.Strings[i + 2]; - end; - end; - parse.Clear; - mangaInfo.numChapter := 1; - mangaInfo.chapterName.Add(mangaInfo.title); - mangaInfo.chapterLinks.Add(mangaInfo.url); - - //status - rgex := TRegExpr.Create; - rgex.ModifierI := True; - rgex.Expression := '[\[\(\{](wip|ongoing)[\}\)\]]'; - if rgex.Exec(LowerCase(mangaInfo.title)) then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - rgex.Free; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/EHentai/names_and_links.inc b/baseunits/includes/EHentai/names_and_links.inc deleted file mode 100644 index 71e8d7bfe..000000000 --- a/baseunits/includes/EHentai/names_and_links.inc +++ /dev/null @@ -1,61 +0,0 @@ - function EHentaiGetNamesAndLinks: Byte; - var - i: Cardinal; - s, posc: String; - isThumbnailsON: Boolean = False; - - begin - - Result := INFORMATION_NOT_FOUND; - //s:='http://g.e-hentai.org/?page=5377&f_doujinshi=on&f_manga=on&f_western=on&f_search=Search+Keywords&f_apply=Apply+Filter'; - if URL = '0' then - s := WebsiteRoots[EHENTAI_ID, 1] + '/?' + EHENTAI_BROWSER - else - s := WebsiteRoots[EHENTAI_ID, 1] + '/?page=' + URL + '&' + EHENTAI_BROWSER; - - //s:= s+'?nw=session'; - - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('/?inline_set=dm_l', parse.Strings[i]) > 0) then - begin - isThumbnailsON := True; - Break; - end; - end; - - if isThumbnailsON then - posc := 'class="id2"' - else - posc := 'class="it5"'; - - for i := 0 to parse.Count - 1 do - begin - if (Pos(posc, parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 2]); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')); - s := StringReplace(s, WebsiteRoots[EHENTAI_ID, 1], '', []); - links.Add(s); - end; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 15c3916f5..3fe75b8af 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -273,89 +273,88 @@ interface TRUYEN18_ID = 9; MANGAREADER_ID = 10; MANGAPARK_ID = 11; - EHENTAI_ID = 12; - MANGATRADERS_ID = 13; - MANGASTREAM_ID = 14; - MANGAEDEN_ID = 15; - PERVEDEN_ID = 16; - TRUYENTRANHTUAN_ID = 17; - TURKCRAFT_ID = 18; - MANGAVADISI_ID = 19; - MANGAFRAME_ID = 20; - EATMANGA_ID = 21; - STARKANA_ID = 22; - MANGAPANDA_ID = 23; - REDHAWKSCANS_ID = 24; - BLOGTRUYEN_ID = 25; - KOMIKID_ID = 26; - SUBMANGA_ID = 27; - ESMANGAHERE_ID = 28; - ANIMEEXTREMIST_ID = 29; - HUGEMANGA_ID = 30; - S2SCAN_ID = 31; - SENMANGA_ID = 32; - IMANHUA_ID = 33; - MABUNS_ID = 34; - MANGAESTA_ID = 35; - CENTRALDEMANGAS_ID = 36; - EGSCANS_ID = 37; - MANGAAR_ID = 38; - MANGAAE_ID = 39; - ANIMESTORY_ID = 40; - LECTUREENLIGNE_ID = 41; - SCANMANGA_ID = 42; - MANGAGO_ID = 43; - DM5_ID = 44; - PURURIN_ID = 45; - MANGACOW_ID = 46; - KIVMANGA_ID = 47; - MEINMANGA_ID = 48; - MANGASPROJECT_ID = 49; - MANGAREADER_POR_ID = 50; - MANGA2U_ID = 51; - MANGASTREAMTO_ID = 52; - NINEMANGA_ID = 53; - NINEMANGA_ES_ID = 54; - NINEMANGA_CN_ID = 55; - NINEMANGA_RU_ID = 56; - NINEMANGA_DE_ID = 57; - NINEMANGA_IT_ID = 58; - NINEMANGA_BR_ID = 59; - JAPANSHIN_ID = 60; - JAPSCAN_ID = 61; - CENTRUMMANGI_PL_ID = 62; - MANGALIB_PL_ID = 63; - ONEMANGA_ID = 64; - MANGATOWN_ID = 65; - READHENTAIMANGA_ID = 66; - MANGAOKU_ID = 67; - MYREADINGMANGAINFO_ID = 68; - IKOMIK_ID = 69; - NHENTAI_ID = 70; - UNIONMANGAS_ID = 71; - MANGAMINT_ID = 72; - UNIXMANGA_ID = 73; - HAKIHOME_ID = 74; - EXTREMEMANGAS_ID = 75; - MANGAHOST_ID = 76; - PORNCOMIX_ID = 77; - PORNCOMIXRE_ID = 78; - PORNCOMIXIC_ID = 79; - XXCOMICS_ID = 80; - XXCOMICSMT_ID = 81; - XXCOMICS3D_ID = 82; - PORNXXXCOMICS_ID = 83; - MANGASEE_ID = 84; - MANGAKU_ID = 85; - ACADEMYVN_ID = 86; - MANGAAT_ID = 87; - SENMANGARAW_ID = 88; - READMANGATODAY_ID = 89; - LONEMANGA_ID = 90; - DYNASTYSCANS_ID = 91; - MADOKAMI_ID = 92; - - WebsiteRoots: array [0..92] of array [0..1] of string = ( + MANGATRADERS_ID = 12; + MANGASTREAM_ID = 13; + MANGAEDEN_ID = 14; + PERVEDEN_ID = 15; + TRUYENTRANHTUAN_ID = 16; + TURKCRAFT_ID = 17; + MANGAVADISI_ID = 18; + MANGAFRAME_ID = 19; + EATMANGA_ID = 20; + STARKANA_ID = 21; + MANGAPANDA_ID = 22; + REDHAWKSCANS_ID = 23; + BLOGTRUYEN_ID = 24; + KOMIKID_ID = 25; + SUBMANGA_ID = 26; + ESMANGAHERE_ID = 27; + ANIMEEXTREMIST_ID = 28; + HUGEMANGA_ID = 29; + S2SCAN_ID = 30; + SENMANGA_ID = 31; + IMANHUA_ID = 32; + MABUNS_ID = 33; + MANGAESTA_ID = 34; + CENTRALDEMANGAS_ID = 35; + EGSCANS_ID = 36; + MANGAAR_ID = 37; + MANGAAE_ID = 38; + ANIMESTORY_ID = 39; + LECTUREENLIGNE_ID = 40; + SCANMANGA_ID = 41; + MANGAGO_ID = 42; + DM5_ID = 43; + PURURIN_ID = 44; + MANGACOW_ID = 45; + KIVMANGA_ID = 46; + MEINMANGA_ID = 47; + MANGASPROJECT_ID = 48; + MANGAREADER_POR_ID = 49; + MANGA2U_ID = 50; + MANGASTREAMTO_ID = 51; + NINEMANGA_ID = 52; + NINEMANGA_ES_ID = 53; + NINEMANGA_CN_ID = 54; + NINEMANGA_RU_ID = 55; + NINEMANGA_DE_ID = 56; + NINEMANGA_IT_ID = 57; + NINEMANGA_BR_ID = 58; + JAPANSHIN_ID = 59; + JAPSCAN_ID = 60; + CENTRUMMANGI_PL_ID = 61; + MANGALIB_PL_ID = 62; + ONEMANGA_ID = 63; + MANGATOWN_ID = 64; + READHENTAIMANGA_ID = 65; + MANGAOKU_ID = 66; + MYREADINGMANGAINFO_ID = 67; + IKOMIK_ID = 68; + NHENTAI_ID = 69; + UNIONMANGAS_ID = 70; + MANGAMINT_ID = 71; + UNIXMANGA_ID = 72; + HAKIHOME_ID = 73; + EXTREMEMANGAS_ID = 74; + MANGAHOST_ID = 75; + PORNCOMIX_ID = 76; + PORNCOMIXRE_ID = 77; + PORNCOMIXIC_ID = 78; + XXCOMICS_ID = 79; + XXCOMICSMT_ID = 80; + XXCOMICS3D_ID = 81; + PORNXXXCOMICS_ID = 82; + MANGASEE_ID = 83; + MANGAKU_ID = 84; + ACADEMYVN_ID = 85; + MANGAAT_ID = 86; + SENMANGARAW_ID = 87; + READMANGATODAY_ID = 88; + LONEMANGA_ID = 89; + DYNASTYSCANS_ID = 90; + MADOKAMI_ID = 91; + + WebsiteRoots: array [0..91] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -368,7 +367,6 @@ interface ('Truyen18', 'http://www.truyen18.org'), ('MangaReader', 'http://www.mangareader.net'), ('MangaPark', 'http://mangapark.me'), - ('E-Hentai', 'http://g.e-hentai.org'), ('MangaTraders', 'http://mangatraders.org'), ('MangaStream', 'http://mangastream.com'), ('MangaEden', 'http://www.mangaeden.com'), @@ -565,9 +563,6 @@ interface //MANGA2U_BROWSER = '/list/all/any/most-popular/'; MANGA2U_BROWSER = '/manga_list/all/any/last-added/'; - EHENTAI_BROWSER = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; - EHENTAI_maxDLTask: Integer = 2; - MANGASTREAMTO_BROWSER = '/series.html'; NINEMANGA_BROWSER = @@ -1263,7 +1258,6 @@ function SitesWithSortedList(const website : String) : Boolean; Result := SitesMemberOf(website, [ FAKKU_ID, PURURIN_ID, - EHENTAI_ID, NINEMANGA_ID, NINEMANGA_ES_ID, NINEMANGA_CN_ID, @@ -1300,7 +1294,6 @@ function SitesWithoutFavorites(const website : String) : Boolean; end; Result := False; Result := SitesMemberOf(website, [ - EHENTAI_ID, FAKKU_ID, PURURIN_ID, MYREADINGMANGAINFO_ID, @@ -1342,9 +1335,6 @@ function SitesWithoutInformation(const website: String): Boolean; function SitesWithoutPageLink(const website : String) : Boolean; begin Result := False; - Result := SitesMemberOf(website, [ - EHENTAI_ID - ]); end; function SitesWithoutReferer(const website : String) : Boolean; @@ -1377,7 +1367,6 @@ function SitesWithSingleChapter(const website : String) : Boolean; Result := SitesMemberOf(website, [ FAKKU_ID, PURURIN_ID, - EHENTAI_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID, PORNCOMIX_ID, diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2b28cb826..2939e5420 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1950,8 +1950,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/DM5/directory_page_number.inc} - {$I includes/EHentai/directory_page_number.inc} - {$I includes/NineManga/directory_page_number.inc} {$I includes/JapanShin/directory_page_number.inc} @@ -2083,9 +2081,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[PURURIN_ID, 0] then Result := GetPururinDirectoryPageNumber else - if website = WebsiteRoots[EHENTAI_ID, 0] then - Result := GetEHentaiDirectoryPageNumber - else if (website = WebsiteRoots[NINEMANGA_ID, 0]) or (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or @@ -2274,8 +2269,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaREADER_POR/names_and_links.inc} - {$I includes/EHentai/names_and_links.inc} - {$I includes/MangaStreamTo/names_and_links.inc} {$I includes/NineManga/names_and_links.inc} @@ -2491,9 +2484,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[MANGA2U_ID, 0] then Result := Manga2uGetNamesAndLinks else - if website = WebsiteRoots[EHENTAI_ID, 0] then - Result := EHentaiGetNamesAndLinks - else if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then Result := MangaStreamToGetNamesAndLinks else @@ -2709,8 +2699,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaREADER_POR/manga_information.inc} - {$I includes/EHentai/manga_information.inc} - {$I includes/MangaStreamTo/manga_information.inc} {$I includes/NineManga/manga_information.inc} @@ -2934,9 +2922,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then Result := GetMangaREADER_PORInfoFromURL else - if website = WebsiteRoots[EHENTAI_ID, 0] then - Result := GetEHentaiInfoFromURL - else if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then Result := GetMangaStreamToInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d21956ab0..d7abaf152 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -377,8 +377,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/EGScans/chapter_page_number.inc} - {$I includes/EHentai/chapter_page_number.inc} - {$I includes/EsMangaHere/chapter_page_number.inc} {$I includes/Hentai2Read/chapter_page_number.inc} @@ -604,9 +602,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = HENTAI2READ_ID then Result := GetHentai2ReadPageNumber else - if manager.container.MangaSiteID = EHENTAI_ID then - Result := GetEHentaiPageNumber - else if manager.container.MangaSiteID = MANGASTREAMTO_ID then Result := GetMangaStreamToPageNumber else @@ -1212,8 +1207,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; var TURL, lpath: String; - {$I includes/EHentai/image_url.inc} - {$I includes/MeinManga/image_url.inc} {$I includes/SenMangaRAW/image_url.inc} @@ -1244,8 +1237,14 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; TURL := DecodeURL(TURL); //decode first to avoid double encoded TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); - if manager.container.MangaSiteID = EHENTAI_ID then - Result := getEHentaiImageURL + if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then + Result := Modules.DownloadImage( + Self, + manager.container.PageContainerLinks[workCounter], + lpath, + Format('%.3d', [workCounter + 1]), + prefix, + ModuleId) else if manager.container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 062496e3a..0b4e66e28 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -78,10 +78,8 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.mangaInfo.status := MainForm.dataProcess.Value[filterPos, DATA_PARAM_STATUS]; FInfo.mangaInfo.summary := MainForm.dataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; FInfo.mangaInfo.numChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); + FInfo.mangaInfo.genres := MainForm.dataProcess.Value[filterPos, DATA_PARAM_GENRES]; FNumChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); - if SitesWithoutInformation(website) or - (website = WebsiteRoots[EHENTAI_ID, 0]) then - FInfo.mangaInfo.genres := MainForm.dataProcess.Value[filterPos, DATA_PARAM_GENRES]; end; FInfo.isGenerateFolderChapterName := MainForm.cbOptionGenerateChapterName.Checked; From 4da66f11ae317afc77c9d7713bd5319f2c697e1a Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 11:53:34 +0800 Subject: [PATCH 0430/2794] add internettools to dependency internettools by benibela --- mangadownloader/md.lpi | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0753854d3..d9ae2bfea 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -233,19 +233,22 @@ - + - + - + - + - + + + + From 414839f9f5a976ed4e08e5a5435578964af9d17c Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 11:54:23 +0800 Subject: [PATCH 0431/2794] websitemodules, add downloadimage function to let module handle downloading image --- baseunits/WebsiteModules.pas | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index dd35e6445..be7af570e 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -33,8 +33,11 @@ TModuleContainer = class; TOnGetImageURL = function(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; + TOnDownloadImage = function(var DownloadThread: TDownloadThread; + const URL, Path, Name, Prefix: String; Module: TModuleContainer): Boolean; + TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, - MMGetPageNumber, MMGetImageURL); + MMGetPageNumber, MMGetImageURL, MMDownloadImage); { TModuleContainer } @@ -59,6 +62,7 @@ TModuleContainer = class OnGetInfo: TOnGetInfo; OnGetPageNumber: TOnGetPageNumber; OnGetImageURL: TOnGetImageURL; + OnDownloadImage: TOnDownloadImage; constructor Create; destructor Destroy; override; public @@ -121,6 +125,11 @@ TWebsiteModules = class function GetImageURL(var DownloadThread: TDownloadThread; const URL, Website: String): Boolean; overload; + function DownloadImage(var DownloadThread: TDownloadThread; + const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; + function DownloadImage(var DownloadThread: TDownloadThread; + const URL, Path, Name, Prefix, Website: String): Boolean; + procedure LockModules; procedure UnlockModules; @@ -285,6 +294,7 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; MMGetInfo: Result := Assigned(OnGetInfo); MMGetPageNumber: Result := Assigned(OnGetPageNumber); MMGetImageURL: Result := Assigned(OnGetImageURL); + MMDownloadImage: Result := Assigned(OnDownloadImage) else Result := False; end; @@ -397,6 +407,23 @@ function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; Result := GetImageURL(DownloadThread, URL, LocateModule(Website)); end; +function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; + const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnDownloadImage) then + Result := TModuleContainer(FModuleList[ModuleId]).OnDownloadImage( + DownloadThread, URL, Path, Name, Prefix, TModuleContainer(FModuleList[ModuleId])); +end; + +function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; + const URL, Path, Name, Prefix, Website: String): Boolean; +begin + Result := DownloadImage(DownloadThread, URL, Path, Name, Prefix, + LocateModule(Website)); +end; + procedure TWebsiteModules.LockModules; begin EnterCriticalsection(FCSModules); From 603c4c4f1ba37e50a0f6f34184bb31ec42e3c499 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 11:58:15 +0800 Subject: [PATCH 0432/2794] baseunit add common xpath/css selector --- baseunits/uBaseUnit.pas | 68 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3fe75b8af..878265304 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -21,7 +21,7 @@ interface SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, - uMisc, USimpleException, USimpleLogger; + uMisc, simplehtmltreeparser, xquery, USimpleException, USimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); @@ -848,6 +848,13 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); //HTML procedure ParseHTML(const aRaw: string; aOutput: TStrings); +// XPath / CSS Selector +procedure ParseHTMLTree(var tp: TTreeParser; const S: String); +function SelectXPathString(Expression: String; TP: TTreeParser): String; +function SelectXPathIX(Expression: String; TP: TTreeParser): IXQValue; +function SelectCSSString(Expression: String; TP: TTreeParser): String; +function SelectCSSIX(Expression: String; TP: TTreeParser): IXQValue; + //convert charset to utf8 function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; @@ -1534,6 +1541,65 @@ procedure ParseHTML(const aRaw: string; aOutput: TStrings); end; end; +procedure ParseHTMLTree(var tp: TTreeParser; const S: String); +begin + if tp = nil then tp := TTreeParser.Create; + with tp do begin + parsingModel := pmHTML; + repairMissingStartTags := True; + repairMissingEndTags := True; + trimText := False; + readComments := False; + readProcessingInstructions := False; + autoDetectHTMLEncoding := False; + if S <> '' then parseTree(S); + end; +end; + +function SelectXPathString(Expression: String; TP: TTreeParser): String; +begin + Result := ''; + if TP = nil then Exit; + if TP.getLastTree = nil then Exit; + try + Result := TXQueryEngine.evaluateStaticXPath3(Expression, TP.getLastTree).toString; + except + end; +end; + +function SelectXPathIX(Expression: String; TP: TTreeParser): IXQValue; +begin + Result := xqvalue(); + if TP = nil then Exit; + if TP.getLastTree = nil then Exit; + try + Result := TXQueryEngine.evaluateStaticXPath3(Expression, TP.getLastTree); + except + end; +end; + +function SelectCSSString(Expression: String; TP: TTreeParser): String; +begin + Result := ''; + if TP = nil then Exit; + if TP.getLastTree = nil then Exit; + try + Result := TXQueryEngine.evaluateStaticCSS3(Expression, TP.getLastTree).toString; + except + end; +end; + +function SelectCSSIX(Expression: String; TP: TTreeParser): IXQValue; +begin + Result := xqvalue(); + if TP = nil then Exit; + if TP.getLastTree = nil then Exit; + try + Result := TXQueryEngine.evaluateStaticCSS3(Expression, TP.getLastTree); + except + end; +end; + function ConvertCharsetToUTF8(S: String): String; var cs: String; From 1366cab577f46bbbb8d7713445e8dac4c710ce37 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 11:59:39 +0800 Subject: [PATCH 0433/2794] add e.hentai module --- baseunits/ModuleList.inc | 3 +- baseunits/modules/EHentai.pas | 362 ++++++++++++++++++++++++++++++++++ 2 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/EHentai.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index c8a329a7a..63ab5283b 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -5,4 +5,5 @@ uses WPManga, MangaFox, Mangacan, - PecintaKomik; + PecintaKomik, + EHentai; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas new file mode 100644 index 000000000..03ed961ce --- /dev/null +++ b/baseunits/modules/EHentai.pas @@ -0,0 +1,362 @@ +unit EHentai; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr; + +implementation + +uses + simplehtmltreeparser, xquery; + +const + dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + Source: TStringList; + Parser: TTreeParser; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit; + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/?' + dirURL, 3) then + begin + if Source.Count > 0 then + begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + Page := StrToIntDef(SelectCSSString( + 'table.ptt>tbody>tr>td:nth-last-child(2)>a', Parser), 1) + 1; + finally + Parser.Free; + end; + end + else Result := INFORMATION_NOT_FOUND; + end; + finally + Source.Free; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Parser: TTreeParser; + rurl: String; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Source := TStringList.Create; + try + if URL = '0' then rurl := Module.RootURL + '/?' + dirURL + else rurl := Module.RootURL + '/?page=' + IncStr(URL) + '&' + dirURL; + if MangaInfo.GetPage(TObject(Source), rurl, 3) then + begin + Result := INFORMATION_NOT_FOUND; + if Source.Count > 0 then + begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + for v in SelectXPathIX('//table[@class="itg"]/tbody/tr/td/div/div/a', + Parser) do + begin + Names.Add(v.toString); + Links.Add(v.toNode.getAttribute('href')); + end; + finally + Parser.Free; + end; + end; + end; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + info: TMangaInfo; + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; + + procedure ScanParse; + var + getOK: Boolean; + begin + getOK := True; + // check content warning + if Pos('Content Warning', SelectXPathString('//div/h1', Parser)) > 0 then + begin + getOK := MangaInfo.GetPage(TObject(Source), info.url + '?nw=session', Reconnect); + if getOK then + ParseHTMLTree(Parser, Source.Text); + end; + if getOK then + begin + with info do begin + //title + title := SelectXPathString('//*[@id="gn"]', Parser); + //cover + coverLink := SelectXPathString('//*[@id="gd1"]/img/@src', Parser); + //artists + artists := ''; + for v in SelectXPathIX('//a[starts-with(@id,"ta_artist")]', Parser) do + AddCommaString(artists, v.toString); + //genres + genres := ''; + for v in SelectXPathIX( + '//a[starts-with(@id,"ta_")and(not(starts-with(@id,"ta_artist")))]', + Parser) do + AddCommaString(genres, v.toString); + //chapter + chapterLinks.Add(url); + chapterName.Add(title); + //status + with TRegExpr.Create do + try + Expression := '(?i)[\[\(\{](wip|ongoing)[\]\)\}]'; + if Exec(title) then + status := '1' + else + begin + Expression := '(?i)[\[\(\{]completed[\]\)\}]'; + if Exec(title) then + status := '0'; + end; + finally + Free; + end; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), info.url, Reconnect) then + begin + if Source.Count > 0 then + begin + Result := NO_ERROR; + // if there is only 1 line, it's banned message! + if Source.Count = 1 then + info.summary := Source.Text + else + begin + ParseHTMLTree(Parser, Source.Text); + try + ScanParse; + finally + Parser.Free; + end; + end; + end + else + Result := INFORMATION_NOT_FOUND; + end; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Container: TTaskContainer; + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; + rurl: String; + + procedure GetImageLink; + begin + for v in SelectXPathIX('//*[@class="gdtm"]/div/a/@href', Parser) do + begin + Container.PageLinks.Add('G'); + Container.PageContainerLinks.Add(v.toString); + end; + end; + + procedure ScanParse; + var + getOK: Boolean; + i, p: Integer; + //s: String; + begin + getOK := True; + //check content warning + if Pos('Content Warning', SelectXPathString('//div/h1', Parser)) > 0 then + begin + rurl += '?nw=session'; + getOK := DownloadThread.GetPage(TObject(Source), rurl, + Container.Manager.retryConnect); + if getOK then + ParseHTMLTree(Parser, Source.Text); + end; + if getOK then + begin + GetImageLink; + //get page count + p := StrToIntDef(SelectCSSString('table.ptt>tbody>tr>td:nth-last-child(2)>a', + Parser), 1) - 1; + if p > 0 then + for i := 1 to p do + if DownloadThread.GetPage(TObject(Source), rurl + '?p=' + IntToStr(i), + Container.Manager.retryConnect) then + GetImageLink; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Source := TStringList.Create; + try + rurl := FillHost(Module.RootURL, URL); + if DownloadThread.GetPage(TObject(Source), rurl, + Container.Manager.retryConnect) then + begin + if Source.Count > 0 then + begin + Result := True; + ParseHTMLTree(Parser, Source.Text); + try + ScanParse; + finally + Parser.Free; + end; + end; + end; + finally + Source.Free; + end; +end; + +function DownloadImage(var DownloadThread: TDownloadThread; + const URL, Path, Name, Prefix: String; Module: TModuleContainer): Boolean; +var + Source: TStringList; + Container: TTaskContainer; + Parser: TTreeParser; + iurl: String; + reconnect: Integer; + + function DoDownloadImage: Boolean; + var + i, rcount: Integer; + base_url, startkey, gid, startpage, nl: String; + begin + rcount := 0; + Result := False; + while (not Result) and (not DownloadThread.IsTerminated) do begin + ParseHTMLTree(Parser, Source.Text); + iurl := SelectXPathString('/html/body/div/a/img/@src', Parser); + Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, Name, Prefix, reconnect); + if DownloadThread.IsTerminated then Break; + if not Result then + begin + base_url := ''; + startkey := ''; + gid := ''; + startpage := ''; + nl := ''; + //get url param + for i := 0 to Source.Count - 1 do begin + if Pos('var base_url=', Source[i]) > 0 then + base_url := GetValuesFromString(Source[i], '=') + else if Pos('var startkey=', Source[i]) > 0 then + startkey := GetValuesFromString(Source[i], '=') + else if Pos('var gid=', Source[i]) > 0 then + gid := GetValuesFromString(Source[i], '=') + else if Pos('var startpage=', Source[i]) > 0 then + startpage := GetValuesFromString(Source[i], '=') + else if Pos('return nl(', Source[i]) > 0 then + nl := ReplaceRegExpr('(?i)^.*nl\([''"](.*)[''"]\).*$', + Source[i], '$1', True); + end; + if (base_url <> '') and (startkey <> '') and (gid <> '') and + (startpage <> '') then + iurl := base_url + '/s/' + startkey + '/' + gid + '-' + startpage + else iurl := FillHost(Module.RootURL, URL); + if nl <> '' then begin + iurl := iurl + '?nl=' + nl; + if not DownloadThread.GetPage(TObject(Source), iurl, reconnect) then Break; + end else Break; + if rcount >= reconnect then Break + else Inc(rcount); + end; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + reconnect := Container.Manager.retryConnect; + iurl := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), iurl, reconnect) then + begin + if Source.Count > 0 then + begin + Parser := TTreeParser.Create; + try + Result := DoDownloadImage; + finally + Parser.Free; + end; + end; + end; + finally + Source.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'E-Hentai'; + RootURL := 'http://g.e-hentai.org'; + MaxTaskLimit := 2; + MaxConnectionLimit := 4; + SortedList := True; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + end; +end; + +initialization + RegisterModule; + +end. From 2eb6ddf61f3edf68d084d35a9972dec3f4b2a65c Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 12:09:20 +0800 Subject: [PATCH 0434/2794] e/hentai, minor changes --- baseunits/modules/EHentai.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 03ed961ce..c7b72063d 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -164,8 +164,9 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.summary := Source.Text else begin - ParseHTMLTree(Parser, Source.Text); + Parser := TTreeParser.Create; try + ParseHTMLTree(Parser, Source.Text); ScanParse; finally Parser.Free; @@ -244,8 +245,9 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; if Source.Count > 0 then begin Result := True; - ParseHTMLTree(Parser, Source.Text); + Parser := TTreeParser.Create; try + ParseHTMLTree(Parser, Source.Text); ScanParse; finally Parser.Free; From 5aa4a91ff9edf870e872d8773f6fb5103996c309 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 12:10:21 +0800 Subject: [PATCH 0435/2794] getinfosthread, also check connection limit should be synched with other thread --- baseunits/uGetMangaInfosThread.pas | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 0b4e66e28..529ec986e 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -34,6 +34,7 @@ TGetMangaInfosThread = class(TFMDThread) // Flush this thread, means that the result will not be shown. FIsFlushed: Boolean; + procedure DoTerminate; override; procedure Execute; override; procedure DoGetInfos; @@ -54,7 +55,7 @@ TGetMangaInfosThread = class(TFMDThread) implementation uses - frmMain; + frmMain, WebsiteModules; procedure TGetMangaInfosThread.DoGetInfos; @@ -67,6 +68,7 @@ procedure TGetMangaInfosThread.DoGetInfos; try FInfo.mangaInfo.website := Website; FInfo.mangaInfo.link := Link; + FInfo.ModuleId := Modules.LocateModule(Website); if (FMangaListPos >= 0) and (website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex]) then begin @@ -86,6 +88,15 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.isRemoveUnicode := MainForm.cbOptionPathConvert.Checked; infob := INFORMATION_NOT_FOUND; + + //wait if there is concurrent connection limit + if Modules.MaxConnectionLimit[FInfo.ModuleId] > 0 then + begin + while not Modules.CanCreateConnection(FInfo.ModuleId) do + Sleep(SOCKHEARTBEATRATE); + Modules.IncActiveConnectionCount(FInfo.ModuleId); + end; + infob := FInfo.GetInfoFromURL(Website, Link, 0); if Self.Terminated then Exit; @@ -152,6 +163,12 @@ procedure TGetMangaInfosThread.DoGetInfos; end; end; +procedure TGetMangaInfosThread.DoTerminate; +begin + Modules.DecActiveConnectionCount(FInfo.ModuleId); + inherited DoTerminate; +end; + procedure TGetMangaInfosThread.Execute; begin MainForm.isGetMangaInfos := True; From 0ff96490f4be9b6d68ca892d37d6ca1a18bdff91 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 12:31:25 +0800 Subject: [PATCH 0436/2794] e.hentai, minor changes --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index c7b72063d..222bccc47 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -290,7 +290,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; //get url param for i := 0 to Source.Count - 1 do begin if Pos('var base_url=', Source[i]) > 0 then - base_url := GetValuesFromString(Source[i], '=') + base_url := RemoveURLDelim(GetValuesFromString(Source[i], '=')) else if Pos('var startkey=', Source[i]) > 0 then startkey := GetValuesFromString(Source[i], '=') else if Pos('var gid=', Source[i]) > 0 then From 59c2d4da18d587f2e1362b0372376fce1adcacf6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 12:34:29 +0800 Subject: [PATCH 0437/2794] check file size after file saved to disk closes #86 --- baseunits/uBaseUnit.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 878265304..787e5a43b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3358,7 +3358,8 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; finally fstream.Free; end; - Result := FileExistsUTF8(fpath); + if FileExistsUTF8(fpath) then + Result := HTTP.Document.Size = FileSizeUtf8(fpath); end else Result := False; From f459e39aceb23edfb12a08508e6d9f29ae80796f Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 12:39:28 +0800 Subject: [PATCH 0438/2794] update readme --- readme.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/readme.txt b/readme.txt index 835adad88..1ed2ce7ce 100644 --- a/readme.txt +++ b/readme.txt @@ -4,9 +4,9 @@ The Free Manga Downloader. --------------------------------- Content: - 1.) About FMD - 2.) Build instructions - 3.) Localization +1.) About FMD +2.) Build instructions +3.) Localization --------------------------------- @@ -21,10 +21,11 @@ The Free Manga Downloader is a free open source application written in Object Pa 2.) Build instructions In order to build FMD from the source code, you must install Lazarus latest version and Free Pascal Compiler v2.6.4. Then you must install the following 3rd party libraries and components: - - RichMemo. - - Virtual TreeView. - - Synapse. - - Vampyre Imaging Library. + - RichMemo, + - Virtual TreeView, + - Synapse, + - Vampyre Imaging Library, + - InternetTools. After everything is installed, open the file md.lpi by using Lazarus IDE, select Run->Build to build the source code. If everything is ok, the binary file should be in FMD_source_code_folder/bin From aa007c4f0af02c7431a17ff35d3b38b9e54c22d0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 6 Aug 2015 12:43:13 +0800 Subject: [PATCH 0439/2794] update readme --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 1ed2ce7ce..e97a36e1b 100644 --- a/readme.txt +++ b/readme.txt @@ -35,4 +35,4 @@ Translations are stored inside "languages" folder with .po extension. In order t --------------------------------- -Last update 25-05-2015 +Last update 06-08-2015 From 2dda78d3f75745930d9f1e49f30ac4f0449b3b71 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 02:22:50 +0800 Subject: [PATCH 0440/2794] simplelogger, minor changes --- baseunits/SimpleException/USimpleLogger.pas | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index ed90adcb8..735b382e4 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -199,13 +199,12 @@ function GetStackTraceInfo(const MaxStackCount: Integer): string; else maxStack := ExceptFrameCount - 1; for i := 0 to maxStack do - Result := Result + ' ' + SimpleBackTraceStr(ExceptFrames[i]) + - LineEnding; + Result := Result + ' ' + SimpleBackTraceStr(ExceptFrames[i]) + LineEnding; end else begin - //cf := get_caller_frame(get_frame); - cf := get_caller_frame(get_caller_frame(get_frame)); + cf := get_caller_frame(get_frame); + //cf := get_caller_frame(get_caller_frame(get_frame)); if cf <> nil then begin Result := @@ -219,15 +218,14 @@ function GetStackTraceInfo(const MaxStackCount: Integer): string; cFrame := get_caller_frame(cf); if cAddress = nil then Break; + Result := Result + ' ' + SimpleBackTraceStr(cAddress) + LineEnding; Inc(i); - if i > MaxStackCount then + if (i >= MaxStackCount) or (cFrame = nil) then Break; - Result := Result + ' ' + SimpleBackTraceStr(cAddress) + - LineEnding; pcf := cf; cf := cFrame; end; - finally + except end; end; end; From ff63aea26ac5684d07cae2dc29e1dd7d58f6e61b Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 04:41:22 +0800 Subject: [PATCH 0441/2794] add doujin moe us --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Doujinmoeus.pas | 119 ++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Doujinmoeus.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 63ab5283b..ddd50b2d9 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -6,4 +6,5 @@ uses MangaFox, Mangacan, PecintaKomik, - EHentai; + EHentai, + Doujinmoeus; diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas new file mode 100644 index 000000000..67c967874 --- /dev/null +++ b/baseunits/modules/Doujinmoeus.pas @@ -0,0 +1,119 @@ +unit Doujinmoeus; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +uses + simplehtmltreeparser, xquery; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + info: TMangaInfo; + Source: TStringList; + Parser: TTreeParser; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Source), info.url, Reconnect) then + begin + if Source.Count > 0 then + begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + with info do + begin + //title + title := SelectXPathString('//div[@class="title"]/a[last()]', Parser); + //cover + coverLink := SelectXPathString('//div[@id="gallery"]/djm/@thumb', Parser); + //artist + artists := SelectXPathString('//*[@id="page_info"]/div[@class="right"]/table/tbody/tr/td/a', Parser); + //summary + summary := SelectXPathString('//*[@id="page_info"]/div/div[@class="message"]', Parser); + //chapter + if title <> '' then + begin + chapterLinks.Add(info.url); + chapterName.Add(title); + end; + end; + finally + Parser.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + end; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Container: TTaskContainer; + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), + Container.Manager.retryConnect) then + begin + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + for v in SelectXPathIX('//div[@id="gallery"]/djm/@file', Parser) do + Container.PageLinks.Add(v.toString); + finally + Parser.Free; + end; + end; + end; + finally + Source.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Doujin-Moe'; + RootURL := 'http://www.doujin-moe.us'; + InformationAvailable := True; + FavoriteAvailable := False; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From b550fde4ce6784f48bb9f9fb7e5276a09b600d5e Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 16:09:00 +0800 Subject: [PATCH 0442/2794] baseunit, add method parameter to getpage --- baseunits/uBaseUnit.pas | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 787e5a43b..876cd0364 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -940,7 +940,7 @@ function SourceForgeURL(URL: String): String; function GetPageAndParse(const AHTTP: THTTPSend; Output: TStrings; URL: String; const Reconnect: Integer = 0): Integer; function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; - const Reconnect: Integer = 0): Boolean; overload; + const Reconnect: Integer = 0; Method: String = 'GET'): Boolean; overload; function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; overload; inline; // Get url from a bitly url. @@ -2838,7 +2838,7 @@ function GetPageAndParse(const AHTTP: THTTPSend; Output: TStrings; URL: String; end; function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; - const Reconnect: Integer): Boolean; + const Reconnect: Integer; Method: String): Boolean; // If AHTTP <> nil, we will use it as http sender. Otherwise we create a new // instance. var @@ -2846,7 +2846,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPHeader: TStringList; counter: Integer; s: String; - meth: String = 'GET'; + meth: String; mstream: TMemoryStream; procedure HTTPClear; @@ -2857,7 +2857,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; RangeStart := 0; RangeEnd := 0; Headers.Clear; - MimeType := 'text/html'; end; end; @@ -2946,11 +2945,23 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; HTTP.UserAgent := DEFAULT_UA; - HTTP.MimeType := 'text/html'; - if OptionHTTPUseGzip then HTTPHeader.Values['Accept-Encoding'] := ' gzip, deflate'; + //Method + if Method <> '' then meth := Method + else meth := 'GET'; + if HTTP.Sock.Tag = 100 then //POST form + meth := 'POST'; + if meth = 'POST' then + HTTP.MimeType := 'application/x-www-form-urlencoded; charset=UTF-8' + else + begin + HTTP.Document.Clear; + HTTP.RangeStart := 0; + HTTP.RangeEnd := 0; + end; + //User-Agent if Trim(HTTPHeader.Values['User-Agent']) <> '' then begin @@ -2996,19 +3007,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.MimeType := 'application/x-www-form-urlencoded'; end; - if HTTP.Sock.Tag = 100 then //POST - begin - meth := 'POST'; - HTTP.MimeType := 'application/x-www-form-urlencoded'; - end; - - if meth <> 'POST' then - begin - HTTP.Document.Clear; - HTTP.RangeStart := 0; - HTTP.RangeEnd := 0; - end; - if checkTerminate then Exit; HTTP.Headers.Text := HTTPHeader.Text; counter := 0; From fe438817e4e884be549ace8b93d06d91c9cf0813 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 18:26:43 +0800 Subject: [PATCH 0443/2794] udata, save new title --- baseunits/uData.pas | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2939e5420..1c40ed71c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -3237,10 +3237,8 @@ procedure TMangaInformation.AddInfoToData(const Title, Link: String; begin if Assigned(DataProcess) then begin - if Title <> '' then - mangaInfo.title := Title; - if Link <> '' then - mangaInfo.link := Link; + if (mangaInfo.title = '') and (Title <> '') then mangaInfo.title := Title; + if (mangaInfo.link = '') and (Link <> '') then mangaInfo.link := Link; with mangaInfo do DataProcess.AddData(title, link, authors, artists, genres, status, StringBreaks(summary), numChapter, Now); From 046c4a878cfaf63e4e1ea273d79bb96e9a08ac2c Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 18:27:29 +0800 Subject: [PATCH 0444/2794] getinfosthread, show new title --- baseunits/uGetMangaInfosThread.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 529ec986e..ffd2ee208 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -102,6 +102,10 @@ procedure TGetMangaInfosThread.DoGetInfos; if Self.Terminated then Exit; if infob <> NO_ERROR then Exit; + //set back if title changed + if (FInfo.mangaInfo.title <> '') and (FInfo.mangaInfo.title <> FTitle) then + FTitle := FInfo.mangaInfo.title; + if FMangaListPos >= 0 then begin if MainForm.dataProcess.WebsiteLoaded(Website) then From 3604a2e01c082011df3c7ef35b0ff2a194771b46 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 18:27:59 +0800 Subject: [PATCH 0445/2794] baseunit, use xquery_json --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 876cd0364..1c88e6b6a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -21,7 +21,7 @@ interface SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, - uMisc, simplehtmltreeparser, xquery, USimpleException, USimpleLogger; + uMisc, simplehtmltreeparser, xquery, xquery_json, USimpleException, USimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); From 9b16c00039ea7ac2151398bee41f6f9adffa34e6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 18:33:21 +0800 Subject: [PATCH 0446/2794] doujin!moe, add getdirectorypagenumber and getnameandlink --- baseunits/modules/Doujinmoeus.pas | 62 +++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index 67c967874..91c16902f 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -12,6 +12,58 @@ implementation uses simplehtmltreeparser, xquery; +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +begin + Page := 100; + Result := NO_ERROR; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Parser: TTreeParser; + s: String; + v:IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Source := TStringList.Create; + try + s := 'get=' + IncStr(URL); + with MangaInfo.FHTTP.Document do begin + Clear; + Write(PChar(s)^, Length(s)); + end; + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/ajax/newest.php', + 3, 'POST') then + begin + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + if SelectXPathString('json(*)("success")', Parser) = 'true' then + begin + s := SelectXPathString('json(*)("top")("token")', Parser); + if s <> '' then + begin + Links.Add(s); + names.Add(SelectXPathString('json(*)("top")("name")', Parser)); + end; + for v in SelectXPathIX('json(*)("newest")()("token")', Parser) do + Links.Add(v.toString); + for v in SelectXPathIX('json(*)("newest")()("name")', Parser) do + Names.Add(v.toString); + end; + finally + Parser.Free; + end; + end; + finally + Source.Free; + end; +end; + function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var @@ -41,9 +93,11 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; //cover coverLink := SelectXPathString('//div[@id="gallery"]/djm/@thumb', Parser); //artist - artists := SelectXPathString('//*[@id="page_info"]/div[@class="right"]/table/tbody/tr/td/a', Parser); + artists := SelectXPathString( + '//*[@id="page_info"]/div[@class="right"]/table/tbody/tr/td/a', Parser); //summary - summary := SelectXPathString('//*[@id="page_info"]/div/div[@class="message"]', Parser); + summary := SelectXPathString( + '//*[@id="page_info"]/div/div[@class="message"]', Parser); //chapter if title <> '' then begin @@ -106,8 +160,10 @@ procedure RegisterModule; begin Website := 'Doujin-Moe'; RootURL := 'http://www.doujin-moe.us'; - InformationAvailable := True; + SortedList := True; FavoriteAvailable := False; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; end; From 7a4aa74eda6b44c0835b3ef75aaed3476b828f4b Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 18:46:12 +0800 Subject: [PATCH 0447/2794] doujin%moe, don't add top item It will break getnameandlink process unexpectedly. because top item can be somewhere between. This behavior only occur on sorted list. --- baseunits/modules/Doujinmoeus.pas | 6 ------ 1 file changed, 6 deletions(-) diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index 91c16902f..6f6ec7908 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -44,12 +44,6 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; ParseHTMLTree(Parser, Source.Text); if SelectXPathString('json(*)("success")', Parser) = 'true' then begin - s := SelectXPathString('json(*)("top")("token")', Parser); - if s <> '' then - begin - Links.Add(s); - names.Add(SelectXPathString('json(*)("top")("name")', Parser)); - end; for v in SelectXPathIX('json(*)("newest")()("token")', Parser) do Links.Add(v.toString); for v in SelectXPathIX('json(*)("newest")()("name")', Parser) do From f0523a39d17f0d65d9c7890e029cc143ef391320 Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 7 Aug 2015 20:55:14 +0800 Subject: [PATCH 0448/2794] doujin*.moe, minor changes --- baseunits/modules/Doujinmoeus.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index 6f6ec7908..a06de7db7 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -93,7 +93,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; summary := SelectXPathString( '//*[@id="page_info"]/div/div[@class="message"]', Parser); //chapter - if title <> '' then + if coverLink <> '' then begin chapterLinks.Add(info.url); chapterName.Add(title); From 60673bdfea81ffd6f38fe436c4bae188264e353d Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 03:54:08 +0800 Subject: [PATCH 0449/2794] add doujin#moe to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 45aabf291..af25e79b9 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -19,4 +19,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=E-Hentai,Fakku,HakiHome,Hentai2Read,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,Fakku,HakiHome,Hentai2Read,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From c64fb975da60839de6e0daeb1d085f99b32527d0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 05:45:52 +0800 Subject: [PATCH 0450/2794] fool slide, some changes and clean up --- baseunits/modules/FoOlSlide.pas | 307 +++++++++++++------------------- 1 file changed, 125 insertions(+), 182 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 2ddd8c331..d86d66711 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -5,275 +5,220 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, RegExpr; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; implementation +uses + simplehtmltreeparser, xquery, RegExpr; + +const + dirurl = '/directory/'; + function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if GetVal(Parse[i], 'class') = 'next' then - if GetTagName(Parse[i + 2]) = 'a' then - begin - Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', - GetVal(Parse[i + 2], 'href'), '$1', True), 1); - Break; - end; - end; - + Source: TStringList; + Parser: TTreeParser; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit; - Parse := TStringList.Create; + Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/directory/', 3) then + if GetPage(TObject(Source), Module.RootURL + dirurl, 3) then begin Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + if Source.Count > 0 then begin Result := NO_ERROR; - ScanParse; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', + SelectXPathString('//a[contains(text(),"Last »»")]/@href', Parser), + '$1', True), 1); + finally + Parser.Free; + end; end; end; finally - Parse.Free; + Source.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'a') and (Pos('/series/', Parse[i]) > 0) then - begin - Links.Add(GetVal(Parse[i], 'href')); - Names.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; - Parse := TStringList.Create; + Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/directory/' + - IncStr(URL), 3) then + if GetPage(TObject(Source), Module.RootURL + dirurl + IncStr(URL), 3) then begin Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + if Source.Count > 0 then begin Result := NO_ERROR; - ScanParse; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + for v in SelectXPathIX('//*[@class="list series"]/*/*[@class="title"]/a', + Parser) do + begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end; + finally + Parser.Free; + end; end; end; finally - Parse.Free; + Source.Free; end; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - g: String = ''; - begin - for i := StartIndex to Parse.Count - 1 do - begin - if Parse[i] = '' then - Break; - if GetVal(Parse[i], 'class') = 'group' then - if GetVal(Parse[i + 1], 'class') = 'title' then - begin - g := Trim(Parse[i + 2]); - if g = 'Chapters' then - g := '' - else - g += ' '; - end; - if GetTagName(Parse[i]) = 'a' then - if GetVal(Parse[i - 1], 'class') = 'title' then - begin - info.chapterLinks.Add(GetVal(Parse[i], 'href')); - info.chapterName.Add(g + Trim(Parse[i + 1])); - end; - end; - //invert chapters - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; + Source: TStringList; + Parser: TTreeParser; - procedure ScanParse; + procedure ScanInfo; var - i: Integer; + v: IXQValue; begin - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if (GetTagName(Parse[i]) = 'h1') and (GetVal(Parse[i], 'class') = 'title') then - info.title := CommonStringFilter(Parse[i + 1]); - + with MangaInfo.mangaInfo do begin //cover - if info.coverLink = '' then - if GetVal(Parse[i], 'class') = 'thumbnail' then - if GetTagName(Parse[i + 2]) = 'img' then - info.coverLink := GetVal(Parse[i + 2], 'src'); - + coverLink := SelectXPathString( + '//*[@id="content"]//*[@class="thumbnail"]/img/@src', Parser); + //title + title := SelectXPathString('//*[@id="content"]//h1[@class="title"]', Parser); //author - if (Parse[i] = 'Author') and (Parse[i + 1] = '') then - info.authors := Trim(TrimLeftChar(Parse[i + 2], [':'])); - + authors := TrimLeftChar(SelectXPathString( + '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]', + Parser), [':', ' ']); //artist - if (Parse[i] = 'Artist') and (Parse[i + 1] = '') then - info.artists := Trim(TrimLeftChar(Parse[i + 2], [':'])); - + artists := TrimLeftChar(SelectXPathString( + '//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]', + Parser), [':', ' ']); //summary - if (Parse[i] = 'Synopsis') and (Parse[i + 1] = '') then - info.summary := Trim(TrimLeftChar(Parse[i + 2], [':'])); - + summary := TrimLeftChar(SelectXPathString( + '//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]', + Parser), [':', ' ']); //chapters - if GetVal(Parse[i], 'class') = 'list' then + for v in SelectXPathIX('//*[@class="list"]//*[@class="title"]/a', Parser) do begin - ScanChapters(i); - Break; + chapterLinks.Add(v.toNode.getAttribute('href')); + if v.toNode.getAttribute('title') <> '' then + chapterName.Add(v.toNode.getAttribute('title')) + else chapterName.Add(v.toString); end; + if chapterLinks.Count > 0 then + InvertStrings([chapterLinks, chapterName]); end; end; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); - Parse := TStringList.Create; + MangaInfo.mangaInfo.website := Module.Website; + MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then + if GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then begin Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + if Source.Count > 0 then begin Result := NO_ERROR; - ScanParse; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + ScanInfo; + finally + Parser.Free; + end; end; end; finally - Parse.Free; + Source.Free; end; end; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i, p: Integer; - begin - p := -1; - for i := 0 to Parse.Count - 1 do - if (GetVal(Parse[i], 'class') = 'dropdown') and (Pos('style=', Parse[i]) > 0) then - begin - p := i + 1; - Break; - end; - if p > -1 then - for i := p to Parse.Count - 1 do - begin - if Pos('', Parse[i]) <> 0 then - Break; - if GetTagName(Parse[i]) = 'a' then - Inc(Container.PageNumber); - end; - end; - + Source: TStringList; + Parser: TTreeParser; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + with DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + Source := TStringList.Create; + try + if GetPage(TObject(Source), FillHost(Module.RootURL, URL), + Manager.retryConnect) then begin - Result := True; - ScanParse; + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + PageNumber := SelectXPathIX( + '//*[@class="topbar_right"]//ul[@class="dropdown"]/li', Parser).Count; + finally + Parser.Free; + end; + end; end; + finally + Source.Free; end; - finally - Parse.Free; end; end; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'open') then - begin - if DownloadThread.workCounter < Container.PageLinks.Count then - Container.PageLinks[DownloadThread.workCounter] := GetVal(Parse[i], 'src'); - Break; - end; - end; - + Source: TStringList; + Parser: TTreeParser; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL) + - 'page/' + IntToStr(DownloadThread.workCounter + 1), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + with DownloadThread.manager.container do begin + Source := TStringList.Create; + try + if GetPage(TObject(Source), FillHost(Module.RootURL, URL) + + 'page/' + IncStr(DownloadThread.workCounter), + Manager.retryConnect) then begin - Result := True; - ScanParse; + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + PageLinks[DownloadThread.workCounter] := + SelectXPathString('//*[@id="page"]//img/@src', Parser); + finally + Parser.Free; + end; + end; end; + finally + Source.Free; end; - finally - Parse.Free; end; end; @@ -283,8 +228,6 @@ procedure RegisterModule; begin Website := 'Shoujosense'; RootURL := 'http://reader.shoujosense.com'; - SortedList := False; - InformationAvailable := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 51ea13566f490a937e6f2fcac275ebac0ac3d242 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 05:46:41 +0800 Subject: [PATCH 0451/2794] fix extra char on mangalist gethint --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b58ffc2e1..911e4d69f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4055,7 +4055,7 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; end; if Trim(Value[LPos, DATA_PARAM_SUMMARY]) <> '' then //s := s + LineEndingLineEnding + infoSummary + ':' + LineEnding + PrepareSummaryForHint(dataProcess.Value[LPos, DATA_PARAM_SUMMARY], 80); - s := s + LineEnding + LineEnding + RS_InfoSummary + ':' + LineEnding + + s := s + LineEnding + LineEnding + RS_InfoSummary + LineEnding + StringBreaks(dataProcess.Value[LPos, DATA_PARAM_SUMMARY]); end; HintText := s; From 5828fb73cd354f70a185bd58e03d4c03c246dd25 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 05:53:21 +0800 Subject: [PATCH 0452/2794] mainform, clean up --- mangadownloader/forms/frmMain.pas | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 911e4d69f..a718c62e0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -546,15 +546,8 @@ TMainForm = class(TForm) public ulTotalPtr, ulWorkPtr: Integer; optionMangaSiteSelectionNodes: array of PVirtualNode; - LastSearchStr: String; - LastSearchWeb: String; - isStartup, isExiting: Boolean; - // for manga website that available for visible on selection list - //websiteName :TStringList; - //websiteLanguage :TStringList; - - isRunDownloadFilter: Boolean; - isUpdating: Boolean; + LastSearchStr, LastSearchWeb: String; + isStartup, isExiting, isRunDownloadFilter, isUpdating: Boolean; revisionIni, updates, mangalistIni, options: TIniFile; FavoriteManager: TFavoriteManager; dataProcess: TDBDataProcess; @@ -564,8 +557,6 @@ TMainForm = class(TForm) updateDB: TUpdateDBThread; updateList: TUpdateMangaManagerThread; SilentThreadManager: TSilentThreadManager; - ticks: Cardinal; - backupTicks: Cardinal; // animation gif gifWaiting: TAnimatedGif; gifWaitingRect: TRect; @@ -4054,7 +4045,6 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; s := s + cbFilterStatus.Items[1]; end; if Trim(Value[LPos, DATA_PARAM_SUMMARY]) <> '' then - //s := s + LineEndingLineEnding + infoSummary + ':' + LineEnding + PrepareSummaryForHint(dataProcess.Value[LPos, DATA_PARAM_SUMMARY], 80); s := s + LineEnding + LineEnding + RS_InfoSummary + LineEnding + StringBreaks(dataProcess.Value[LPos, DATA_PARAM_SUMMARY]); end; @@ -4852,7 +4842,6 @@ procedure TMainForm.UpdateVtChapter; procedure TMainForm.UpdateVtDownload; begin - //vtDownload.Clear; vtDownload.RootNodeCount := DLManager.Count; // the reason we put vtDownloadFilters in here instead of in DLManager because // the size of download list can change while this method is running From 05e5af1c3fcafb0e9eec176615c45dbb328bee19 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 07:19:00 +0800 Subject: [PATCH 0453/2794] Bump version 0.9.21.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 925b499fd..40d9b4e1f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,13 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.0 (08-08-2015) +[+] Add button to abort check new version +[*] Minor UI changes +[*] Batoto: limit task to 1 and concurrent connection to 4 +[+] Added Doujin-Moe (H) +[*] Various changes and bug fixes + 0.9.20.0 (02-08-2015) [*] Mangacan: rewrite all script [*] PecintaKomik: rewrite all script diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index d9ae2bfea..686cdc02a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ - + diff --git a/update b/update index 885298cc0..c704b1348 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.20.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.20.0/fmd_0.9.20.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.20.0/fmd_0.9.20.0_Win64.7z +VERSION=0.9.21.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.0/fmd_0.9.21.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.0/fmd_0.9.21.0_Win64.7z From e914ccdd6e5c910da00eae667d5e2c9768e944e9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 08:05:41 +0800 Subject: [PATCH 0454/2794] fix warning message about empty website selection on close --- mangadownloader/forms/frmMain.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a718c62e0..7969ae2f7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1142,12 +1142,11 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); FavoriteManager.Backup; SaveOptions; SaveFormInformation; - - SetLength(optionMangaSiteSelectionNodes, 0); end; procedure TMainForm.FormDestroy(Sender: TObject); begin + SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); From 971d2eaf7b29efaf148d24cbe009c2e4b2a258d6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 08:08:19 +0800 Subject: [PATCH 0455/2794] mainform, always wait when for threads on close --- mangadownloader/forms/frmMain.pas | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7969ae2f7..5287ca590 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -577,7 +577,7 @@ TMainForm = class(TForm) // load about information procedure LoadAbout; - procedure CloseNow(WaitFor: Boolean = True); + procedure CloseNow; // en: Too lazy to add it one by one procedure InitCheckboxes; @@ -1084,7 +1084,7 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); CloseAction := caFree; end; -procedure TMainForm.CloseNow(WaitFor: Boolean); +procedure TMainForm.CloseNow; begin if Assigned(CheckUpdateThread) then begin @@ -1116,17 +1116,15 @@ procedure TMainForm.CloseNow(WaitFor: Boolean); begin GetInfosThread.IsFlushed := True; GetInfosThread.Terminate; - if WaitFor then - GetInfosThread.WaitFor; + GetInfosThread.WaitFor; end; if isUpdating then begin updateList.Terminate; - if WaitFor then - updateList.WaitFor; + updateList.WaitFor; end; - FavoriteManager.StopChekForNewChapter(WaitFor); - SilentThreadManager.StopAll(WaitFor); + FavoriteManager.StopChekForNewChapter(True); + SilentThreadManager.StopAll(True); DLManager.StopAllDownloadTasksForExit; if FMDInstance <> nil then @@ -1259,7 +1257,7 @@ procedure TMainForm.itMonitorTimer(Sender: TObject); begin if ShowExitCounter then begin - Self.CloseNow(False); + Self.CloseNow; if DoAfterFMD = DO_POWEROFF then fmdPowerOff else @@ -1275,7 +1273,7 @@ procedure TMainForm.itMonitorTimer(Sender: TObject); CopyFile(fmdDirectory + 'updater.exe', fmdDirectory + 'old_updater.exe'); if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then begin - Self.CloseNow(False); + Self.CloseNow; RunExternalProcess(fmdDirectory + 'old_updater.exe', ['-x', '-r', '3', '-a', FUpdateURL, '-l', Application.ExeName, '--lang', uTranslation.LastSelected], True, False); From b35dbbad1c335a902048c8bf11194cfec9ad4c2b Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 08:22:50 +0800 Subject: [PATCH 0456/2794] mainform, minor fixes --- mangadownloader/forms/frmMain.pas | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5287ca590..f550f8d1f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4452,12 +4452,15 @@ procedure TMainForm.SaveOptions; var s: String; begin - s := SaveMangaOptions; - if s = '' then + if Length(optionMangaSiteSelectionNodes) > 0 then begin - MessageDlg('', RS_DlgMangaListSelect, - mtConfirmation, [mbYes], 0); - Exit; + s := SaveMangaOptions; + if s = '' then + begin + MessageDlg('', RS_DlgMangaListSelect, + mtConfirmation, [mbYes], 0); + Exit; + end; end; with options do From a42c917aac20b5a9936c99362812f52998362472 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 08:26:14 +0800 Subject: [PATCH 0457/2794] Bump version 0.9.21.1 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 40d9b4e1f..1a884aa10 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.1 (08-08-2015) +[*] Minor bug fixes + 0.9.21.0 (08-08-2015) [+] Add button to abort check new version [*] Minor UI changes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 686cdc02a..b4fbc0278 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ + diff --git a/update b/update index c704b1348..36d9d36d9 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.0/fmd_0.9.21.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.0/fmd_0.9.21.0_Win64.7z +VERSION=0.9.21.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.1/fmd_0.9.21.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.1/fmd_0.9.21.1_Win64.7z From 028207c21f9dad640b87638a01a70abfa8c0c120 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 17:17:05 +0800 Subject: [PATCH 0458/2794] downloadmanager, minor changes --- baseunits/uDownloadsManager.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d7abaf152..7644d6417 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1874,8 +1874,8 @@ procedure TDownloadManager.Backup; if isRunningBackup then Exit; - CS_DownloadManager_Task.Acquire; isRunningBackup := True; + CS_DownloadManager_Task.Acquire; try DownloadManagerFile.CacheUpdates := True; // Erase all sections @@ -1917,9 +1917,9 @@ procedure TDownloadManager.Backup; end; DownloadManagerFile.UpdateFile; finally - isRunningBackup := False; CS_DownloadManager_Task.Release; end; + isRunningBackup := False; end; procedure TDownloadManager.ClearTransferRate; From 883b0cb8f7839f5ad440da417e7f7e73eb51ca90 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 17:23:51 +0800 Subject: [PATCH 0459/2794] favoritesmanager, clean up --- baseunits/uFavoritesManager.pas | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index e8bebde52..8795a7113 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, - uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules; + uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, USimpleException; type TFavoriteManager = class; @@ -45,7 +45,6 @@ TFavoriteTask = class(TFMDThread) procedure SyncStartChecking; procedure SyncFinishChecking; procedure SyncUpdateBtnCaption; - procedure SyncShowResult; procedure Checkout; procedure Execute; override; public @@ -213,7 +212,7 @@ procedure TFavoriteThread.Execute; TransferMangaInfo(container.MangaInfo, getInfo.mangaInfo); except on E: Exception do - MainForm.ExceptionHandler(Self, E); + ExceptionHandle(Self, E); end; if Self.Terminated then container.Status := STATUS_IDLE @@ -276,11 +275,6 @@ procedure TFavoriteTask.SyncUpdateBtnCaption; MainForm.btFavoritesCheckNewChapter.Caption := FBtnCaption; end; -procedure TFavoriteTask.SyncShowResult; -begin - manager.ShowResult; -end; - procedure TFavoriteTask.Checkout; var i: Integer; @@ -365,10 +359,10 @@ procedure TFavoriteTask.Execute; end; if (not Terminated) and (not isDlgCounter) then - Synchronize(SyncShowResult); + Synchronize(manager.ShowResult); except on E: Exception do - MainForm.ExceptionHandler(Self, E); + ExceptionHandle(Self, E); end; manager.CS_Favorites.Acquire; try @@ -491,7 +485,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); taskthread.PushNewCheck; except on E: Exception do - MainForm.ExceptionHandler(Self, E); + ExceptionHandle(Self, E); end; end; @@ -761,7 +755,7 @@ procedure TFavoriteManager.ShowResult; end; except on E: Exception do - MainForm.ExceptionHandler(Self, E); + ExceptionHandle(Self, E); end; end; From 5c037d19642f7729c45d0d0f68aee5a2d434697c Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 17:28:02 +0800 Subject: [PATCH 0460/2794] fix access violation after favorites check closes #90 --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f550f8d1f..9ea6e7abf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -960,6 +960,7 @@ procedure TMainForm.FormCreate(Sender: TObject); // favorites FavoriteManager := TFavoriteManager.Create; + FavoriteManager.DLManager := Self.DLManager; FavoriteManager.OnUpdateFavorite := @UpdateVtFavorites; FavoriteManager.OnUpdateDownload := @UpdateVtDownload; From be5781ca9cd186f72c36295032281ea4b24ce03a Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 17:38:47 +0800 Subject: [PATCH 0461/2794] fix option "Automatic download after finish checking" (favorites) doesn't stored properly --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9ea6e7abf..a96c08ffe 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4523,7 +4523,7 @@ procedure TMainForm.SaveOptions; WriteBool('update', 'AutoCheckFavStartup', cbOptionAutoCheckFavStartup.Checked); WriteBool('update', 'AutoCheckFavInterval', cbOptionAutoCheckFavInterval.Checked); WriteInteger('update', 'AutoCheckFavIntervalMinutes', seOptionAutoCheckFavIntervalMinutes.Value); - WriteBool('update', 'AutoCheckFavAutoDownloadFavorites', cbOptionAutoCheckFavDownload.Checked); + WriteBool('update', 'AutoCheckFavAutoDownload', cbOptionAutoCheckFavDownload.Checked); WriteBool('update', 'AutoCheckFavAutoRemoveCompletedManga', cbOptionAutoCheckFavRemoveCompletedManga.Checked); WriteBool('update', 'UpdateListNoMangaInfo', cbOptionUpdateListNoMangaInfo.Checked); WriteBool('update', 'UpdateListRemoveDuplicateLocalData', cbOptionUpdateListRemoveDuplicateLocalData.Checked); From b9a6dc9917971ea8a32d955291d0aa2054f95f99 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 18:14:58 +0800 Subject: [PATCH 0462/2794] simpleexception, check another windows os version --- baseunits/SimpleException/USimpleException.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/SimpleException/USimpleException.pas b/baseunits/SimpleException/USimpleException.pas index 56d2133e2..2b00df468 100644 --- a/baseunits/SimpleException/USimpleException.pas +++ b/baseunits/SimpleException/USimpleException.pas @@ -184,6 +184,16 @@ function TSimpleException.OSVer: String; {$IFDEF WINDOWS} var wdir: array [0..MAX_PATH] of Char; + function WinLater: String; + begin + if (Win32MajorVersion = 6) and (Win32MinorVersion = 3) then + Result := 'Windows 8.1' + else if (Win32MajorVersion = 10) and (Win32MinorVersion = 0) then + Result := 'Windows 10' + else + Result := Format('Windows %d.%d', [Win32MajorVersion, Win32MinorVersion]); + end; + {$ENDIF} begin {$IFDEF LCLcarbon} @@ -208,7 +218,7 @@ function TSimpleException.OSVer: String; wv7: Result := 'Windows 7'; wv8: Result := 'Windows 8'; else - Result := 'Windows'; + Result := WinLater; end; Initialize(wdir); GetWindowsDirectory(PChar(wdir), MAX_PATH); From 27482f59eafb8add8b9394677c5308663dca92bf Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 18:33:27 +0800 Subject: [PATCH 0463/2794] favoritesmanager, check dlmanager availability before showing check result --- baseunits/uFavoritesManager.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 8795a7113..ebb98e7eb 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -527,6 +527,9 @@ procedure TFavoriteManager.ShowResult; favDelete : Boolean; begin if isDlgCounter then Exit; + if (Self.DLManager = nil) and Assigned(MainForm.DLManager) then + Self.DLManager := MainForm.DLManager + else Exit; try CS_Favorites.Acquire; dlChapters := TStringList.Create; From dfe4b68f2fb826136f5962a14b86654d3d6729ac Mon Sep 17 00:00:00 2001 From: riderkick Date: Sat, 8 Aug 2015 18:45:47 +0800 Subject: [PATCH 0464/2794] Bump version 0.9.21.2 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1a884aa10..cf4854aa1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.2 (08-08-2015) +[*] Fix access violation when trying to download new chapter from favorites +[*] Fix option "Automatic download after finish checking" (favorites) doesn't stored properly + 0.9.21.1 (08-08-2015) [*] Minor bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b4fbc0278..6c3eb9137 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 36d9d36d9..5d00c5cb4 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.1/fmd_0.9.21.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.1/fmd_0.9.21.1_Win64.7z +VERSION=0.9.21.2 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.2/fmd_0.9.21.2.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.2/fmd_0.9.21.2_Win64.7z From 19e6aab0a7b6d475743f6431d221b8ee9a1595ec Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 9 Aug 2015 11:18:58 +0800 Subject: [PATCH 0465/2794] some fix --- baseunits/WebsiteModules.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index be7af570e..e5afc8c8a 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -439,7 +439,7 @@ procedure TWebsiteModules.IncActiveTaskCount(ModuleId: Integer); if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if MaxTaskLimit > 0 then - InterLockedIncrement(ActiveTaskCount); + ActiveTaskCount := InterLockedIncrement(ActiveTaskCount); end; procedure TWebsiteModules.DecActiveTaskCount(ModuleId: Integer); @@ -447,7 +447,7 @@ procedure TWebsiteModules.DecActiveTaskCount(ModuleId: Integer); if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if ActiveTaskCount > 0 then - InterLockedDecrement(ActiveTaskCount); + ActiveTaskCount := InterLockedDecrement(ActiveTaskCount); end; function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; @@ -464,7 +464,7 @@ procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if MaxConnectionLimit > 0 then - InterLockedIncrement(ActiveConnectionCount); + ActiveConnectionCount := InterLockedIncrement(ActiveConnectionCount); end; procedure TWebsiteModules.DecActiveConnectionCount(ModuleId: Integer); @@ -472,7 +472,7 @@ procedure TWebsiteModules.DecActiveConnectionCount(ModuleId: Integer); if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if ActiveConnectionCount > 0 then - InterLockedDecrement(ActiveConnectionCount); + ActiveConnectionCount := InterLockedDecrement(ActiveConnectionCount); end; function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; From 9d13dc6140f7f5e01b1767898d1f8c84f51994c7 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 9 Aug 2015 11:29:42 +0800 Subject: [PATCH 0466/2794] fix favoritemanager not showing result fix #91 --- baseunits/uFavoritesManager.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index ebb98e7eb..6050c16b4 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -528,8 +528,8 @@ procedure TFavoriteManager.ShowResult; begin if isDlgCounter then Exit; if (Self.DLManager = nil) and Assigned(MainForm.DLManager) then - Self.DLManager := MainForm.DLManager - else Exit; + Self.DLManager := MainForm.DLManager; + if Self.DLManager = nil then Exit; try CS_Favorites.Acquire; dlChapters := TStringList.Create; From 0eeea9330946d002fddf12e2ccc89247b8f75dba Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 9 Aug 2015 11:56:02 +0800 Subject: [PATCH 0467/2794] fix per item favorite check --- baseunits/uFavoritesManager.pas | 36 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 6050c16b4..1e85e4006 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -46,11 +46,11 @@ TFavoriteTask = class(TFMDThread) procedure SyncFinishChecking; procedure SyncUpdateBtnCaption; procedure Checkout; + procedure DoTerminate; override; procedure Execute; override; public manager: TFavoriteManager; threads: TFPList; - procedure PushNewCheck; procedure UpdateBtnCaption(Cap: String); constructor Create; destructor Destroy; override; @@ -319,6 +319,13 @@ procedure TFavoriteTask.Checkout; end; end; +procedure TFavoriteTask.DoTerminate; +begin + manager.isRunning := False; + manager.taskthread := nil; + inherited DoTerminate; +end; + procedure TFavoriteTask.Execute; var i, cthread: Integer; @@ -326,16 +333,14 @@ procedure TFavoriteTask.Execute; manager.isRunning := True; Synchronize(SyncStartChecking); try - Checkout; - while (not Terminated) and (statuscheck > 0) do + while not Terminated do begin - Sleep(SOCKHEARTBEATRATE); // if current thread count > max threads allowed we wait until thread count decreased while (not Terminated) and (threads.Count >= OptionMaxThreads) do Sleep(SOCKHEARTBEATRATE); Checkout; // if there is concurent connection limit applied and no more possible item to check - // we will wait until thread count decresed + // we will wait until thread count decreased cthread := threads.Count; while (not Terminated) and (threads.Count > 0) and (threads.Count = cthread) do Sleep(SOCKHEARTBEATRATE); @@ -343,6 +348,7 @@ procedure TFavoriteTask.Execute; // we will also wait if there is new item pushed, so we will check it after it while (not Terminated) and (statuscheck = 0) and (threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); + if statuscheck = 0 then Break; end; if Terminated and (threads.Count > 0) then @@ -375,11 +381,6 @@ procedure TFavoriteTask.Execute; Synchronize(SyncFinishChecking); end; -procedure TFavoriteTask.PushNewCheck; -begin - Inc(statuscheck); -end; - procedure TFavoriteTask.UpdateBtnCaption(Cap: String); begin FBtnCaption := Cap; @@ -394,8 +395,6 @@ constructor TFavoriteTask.Create; destructor TFavoriteTask.Destroy; begin - manager.taskthread := nil; - manager.isRunning := False; threads.Free; inherited Destroy; end; @@ -454,7 +453,14 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); if isDlgCounter then Exit; try if FavoriteIndex > -1 then - TFavoriteContainer(FFavorites[FavoriteIndex]).Status := STATUS_CHECK + begin + if TFavoriteContainer(FFavorites[FavoriteIndex]).Status = STATUS_IDLE then + begin + TFavoriteContainer(FFavorites[FavoriteIndex]).Status := STATUS_CHECK; + if Assigned(taskthread) then + taskthread.statuscheck := InterLockedIncrement(taskthread.statuscheck); + end; + end else begin if isRunning then @@ -480,9 +486,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); taskthread := TFavoriteTask.Create; taskthread.manager := Self; taskthread.Start; - end - else - taskthread.PushNewCheck; + end; except on E: Exception do ExceptionHandle(Self, E); From 8f48f2e41d55e0324940c51b83da8440c4eea812 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 9 Aug 2015 12:44:44 +0800 Subject: [PATCH 0468/2794] Bump version 0.9.21.3 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index cf4854aa1..420a7372d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,10 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.3 (09-08-2015) +[*] Fix favoritemanager doesn't showing the result when new chapter found +[*] Fix per item favorite check + 0.9.21.2 (08-08-2015) [*] Fix access violation when trying to download new chapter from favorites [*] Fix option "Automatic download after finish checking" (favorites) doesn't stored properly diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6c3eb9137..23f613fd9 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 5d00c5cb4..fb9f43dee 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.2 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.2/fmd_0.9.21.2.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.2/fmd_0.9.21.2_Win64.7z +VERSION=0.9.21.3 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.3/fmd_0.9.21.3.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.3/fmd_0.9.21.3_Win64.7z From 3f2d8691bcb6cf77e4d48057591a8c4d962b03d2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Sun, 9 Aug 2015 13:17:56 +0800 Subject: [PATCH 0469/2794] favoritemanager, fix create new threads when max threads changed in option, and safely wait for threads before terminated --- baseunits/uFavoritesManager.pas | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 1e85e4006..35b3d0ef3 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -328,21 +328,24 @@ procedure TFavoriteTask.DoTerminate; procedure TFavoriteTask.Execute; var - i, cthread: Integer; + i, cthread, cmaxthreads: Integer; begin manager.isRunning := True; Synchronize(SyncStartChecking); try while not Terminated do begin + cmaxthreads := OptionMaxThreads; // if current thread count > max threads allowed we wait until thread count decreased - while (not Terminated) and (threads.Count >= OptionMaxThreads) do + while (not Terminated) and (threads.Count >= cmaxthreads) do Sleep(SOCKHEARTBEATRATE); Checkout; // if there is concurent connection limit applied and no more possible item to check // we will wait until thread count decreased + // break wait if OptionMaxThreads changed cthread := threads.Count; - while (not Terminated) and (threads.Count > 0) and (threads.Count = cthread) do + while (not Terminated) and (threads.Count > 0) and (threads.Count = cthread) and + (cmaxthreads = OptionMaxThreads) do Sleep(SOCKHEARTBEATRATE); // if there is no more item need to be checked, but thread count still > 0 we will wait for it // we will also wait if there is new item pushed, so we will check it after it @@ -351,6 +354,9 @@ procedure TFavoriteTask.Execute; if statuscheck = 0 then Break; end; + while (not Terminated) and (threads.Count > 0) do + Sleep(SOCKHEARTBEATRATE); + if Terminated and (threads.Count > 0) then begin LockCreateConnection; From d6b3d03c01afcde2ee3fc4b46bab9e408230d7d1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 02:25:56 +0800 Subject: [PATCH 0470/2794] updater, unload OpenSSL library before extract, fix OpenSSL library doesn't replaced with the new one --- updater/uMain.pas | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index f10b2796e..624066410 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -12,7 +12,7 @@ interface Classes, SysUtils, zipper, FileUtil,LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, RegExpr, IniFiles, USimpleException, uMisc, uTranslation, - httpsend, blcksock, ssl_openssl, uFMDThread; + httpsend, blcksock, ssl_openssl, ssl_openssl_lib, uFMDThread; type @@ -187,7 +187,7 @@ constructor TDownloadThread.Create; destructor TDownloadThread.Destroy; begin - FHTTP.Free; + if FHTTP <> nil then FHTTP.Free; isDownload := False; inherited Destroy; end; @@ -510,6 +510,11 @@ procedure TDownloadThread.Execute; if Extract and FileExistsUTF8(fname) then begin + FHTTP.Free; + FHTTP := nil; + SSLImplementation := TSSLNone; + ssl_openssl_lib.DestroySSLInterface; + UpdateStatus(Format(RS_UnpackFile, [fname])); Sza := GetCurrentDirUTF8 + DirectorySeparator + '7za.exe'; if _UpdApp and From eda78164d988986a7213f5c39ce434a77bb9ff97 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 02:26:53 +0800 Subject: [PATCH 0471/2794] updater, increase version number --- updater/updater.lpi | 1 + 1 file changed, 1 insertion(+) diff --git a/updater/updater.lpi b/updater/updater.lpi index 78441cdc6..0efaaf586 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -19,6 +19,7 @@ + From 8022db2b69959696ebd71c61e0178928d3ee6402 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 02:42:23 +0800 Subject: [PATCH 0472/2794] update .gitattibutes --- .gitattributes | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.gitattributes b/.gitattributes index c8de2ea05..9cf75dd3a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,9 @@ -*.txt eol=crlf -*.pas eol=lf -*.lpr eol=lf -*.lpi eol=lf -*.po eol=lf +# Autodetect text files +* text=auto + +# Text files +*.txt text +*.pas text +*.lpr text +*.lpi text +*.po text From b6c6c6994b09026bfc754a16c96226fe5f052ef2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 03:37:56 +0800 Subject: [PATCH 0473/2794] update .gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 9cf75dd3a..56f995dfd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,6 +4,7 @@ # Text files *.txt text *.pas text +*.lfm text *.lpr text *.lpi text *.po text From 28cdedff2cf658391a2796f7f5b89b5a170091b1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 03:38:20 +0800 Subject: [PATCH 0474/2794] mainform, minor changes --- mangadownloader/forms/frmMain.pas | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a96c08ffe..a1ca09640 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1087,6 +1087,7 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin + //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin CheckUpdateThread.Terminate; @@ -1102,17 +1103,6 @@ procedure TMainForm.CloseNow; OpenDBThread.Terminate; OpenDBThread.WaitFor; end; - if Assigned(FormDropTarget) then - FormDropTarget.Close; - tmBackup.Enabled := False; - itSaveDownloadedList.Enabled := False; - itRefreshDLInfo.Enabled := False; - itCheckFav.Enabled := False; - itAnimate.Enabled := False; - itStartup.Enabled := False; - itMonitor.Enabled := False; - - //Terminating all threads and wait for it if isGetMangaInfos then begin GetInfosThread.IsFlushed := True; @@ -1128,6 +1118,17 @@ procedure TMainForm.CloseNow; SilentThreadManager.StopAll(True); DLManager.StopAllDownloadTasksForExit; + tmBackup.Enabled := False; + itSaveDownloadedList.Enabled := False; + itRefreshDLInfo.Enabled := False; + itCheckFav.Enabled := False; + itAnimate.Enabled := False; + itStartup.Enabled := False; + itMonitor.Enabled := False; + + if Assigned(FormDropTarget) then + FormDropTarget.Close; + if FMDInstance <> nil then begin FMDInstance.StopServer; From e4ff74e4efad0bfb420d061a50cebed059f2a2fa Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 03:49:02 +0800 Subject: [PATCH 0475/2794] new line ending --- mangadownloader/forms/frmImportFavorites.lfm | 368 +- mangadownloader/forms/frmMain.lfm | 11636 ++++++++--------- mangadownloader/forms/frmMain.pas | 1 + mangadownloader/forms/frmNewChapter.lfm | 392 +- mangadownloader/forms/mainunit.lrs | 664 +- 5 files changed, 6531 insertions(+), 6530 deletions(-) diff --git a/mangadownloader/forms/frmImportFavorites.lfm b/mangadownloader/forms/frmImportFavorites.lfm index aff022c9e..177f67f5c 100644 --- a/mangadownloader/forms/frmImportFavorites.lfm +++ b/mangadownloader/forms/frmImportFavorites.lfm @@ -1,184 +1,184 @@ -object ImportFavorites: TImportFavorites - Left = 480 - Height = 171 - Top = 298 - Width = 406 - BorderIcons = [biSystemMenu] - BorderStyle = bsDialog - Caption = 'Import list ...' - ClientHeight = 171 - ClientWidth = 406 - OnCreate = FormCreate - Position = poDesktopCenter - LCLVersion = '1.5' - object cbSoftware: TComboBox - Left = 16 - Height = 23 - Top = 32 - Width = 371 - ItemHeight = 15 - ItemIndex = 0 - Items.Strings = ( - 'Domdomsoft Manga Downloader' - 'Free Manga Downloader' - ) - Style = csDropDownList - TabOrder = 0 - Text = 'Domdomsoft Manga Downloader' - end - object edPath: TEdit - Left = 16 - Height = 23 - Top = 72 - Width = 344 - TabOrder = 1 - Text = 'Path to the software (e.g. C:\MangaDownloader)' - end - object btImport: TBitBtn - Left = 152 - Height = 24 - Top = 128 - Width = 104 - Caption = '&OK' - Default = True - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000900000012010E - 0033024A0083025D00BC025D00CC025D00CC025D00CC025D00CC025D00CC025D - 00CC025D00CC025D00CC025D00BC024A0083010E003300000012021D0000066D - 0073129208DD20CC10F922D911FF22D911FF22D911FF22D911FF22D911FF22D9 - 11FF22D911FF22D911FF1FCC0FF9109207DD066D0073021D00000A7D00000A7D - 00BA25CA15F922D111FF22D111FF22D111FF22B611FF22D111FF22D111FF22D1 - 11FF22D111FF22D111FF22D111FF20C80FF90A7D00BA0A7D00000C8400000C84 - 00CC2BCC1AFF22C811FF22C811FF22B211FFE6E6E6FF22B211FF22C811FF22C8 - 11FF22C811FF22C811FF22C811FF22C811FF0C8400CC0C8400000D8900000D89 - 00CC31C620FF22BE11FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE - 11FF22BE11FF22BE11FF22BE11FF23BE12FF0D8900CC0D8900000E8D00000E8D - 00CC41C330FF23AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 - 11FF22B411FF22B411FF22B411FF25B514FF0E8D00CC0E8D00000F9200000F92 - 00CC52C941FFA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 - E6FF22A311FF22AA11FF22AA11FF28AF17FF0F9200CC0F920000109600001096 - 00CC55CC44FF3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 - E2FFE6E6E6FF229E11FF22A111FF2CAA1BFF109600CC10960000119A0000119A - 00CC5AD149FF47BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 - E2FFE3E3E3FFE7E7E7FF269E15FF39B128FF119A00CC119A0000129E0000129E - 00CC60D74FFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB - 33FFFFFFFFFFA7E29EFF4EC53DFF58CF47FF129E00CC129E000013A2000013A2 - 00CC67DE56FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE - 46FF4AC139FF51C840FF57CE46FF60D74FFF13A200CC13A2000014A5000014A5 - 00BA64DE53F95FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD6 - 4EFF5FD64EFF5FD64EFF5FD64EFF60DA4FF914A500BA14A5000014A8000014A8 - 007337C124DD66E054F96EE55DFF6EE55DFF6EE55DFF6EE55DFF6DE45CFF6DE4 - 5CFF6DE45CFF6DE45CFF64DF53F936BF23DD14A8007314A8000014A8000015A9 - 000C15AA007315AA00BA15AA00CC15AA00CC15AA00CC15AA00CC15AA00CC15AA - 00CC15AA00CC15AA00CC15AA00BA15AA007315A9000C14A80000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ModalResult = 1 - OnClick = btImportClick - TabOrder = 2 - end - object btCancel: TBitBtn - Left = 272 - Height = 24 - Top = 128 - Width = 104 - Caption = 'Cancel' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ModalResult = 2 - TabOrder = 3 - end - object lbSelectSoftware: TLabel - Left = 16 - Height = 15 - Top = 16 - Width = 49 - Caption = 'Software:' - ParentColor = False - end - object btBrowse: TSpeedButton - Left = 364 - Height = 23 - Top = 72 - Width = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btBrowseClick - end - object dlgPath: TSelectDirectoryDialog - left = 224 - top = 8 - end -end +object ImportFavorites: TImportFavorites + Left = 480 + Height = 171 + Top = 298 + Width = 406 + BorderIcons = [biSystemMenu] + BorderStyle = bsDialog + Caption = 'Import list ...' + ClientHeight = 171 + ClientWidth = 406 + OnCreate = FormCreate + Position = poDesktopCenter + LCLVersion = '1.5' + object cbSoftware: TComboBox + Left = 16 + Height = 23 + Top = 32 + Width = 371 + ItemHeight = 15 + ItemIndex = 0 + Items.Strings = ( + 'Domdomsoft Manga Downloader' + 'Free Manga Downloader' + ) + Style = csDropDownList + TabOrder = 0 + Text = 'Domdomsoft Manga Downloader' + end + object edPath: TEdit + Left = 16 + Height = 23 + Top = 72 + Width = 344 + TabOrder = 1 + Text = 'Path to the software (e.g. C:\MangaDownloader)' + end + object btImport: TBitBtn + Left = 152 + Height = 24 + Top = 128 + Width = 104 + Caption = '&OK' + Default = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000900000012010E + 0033024A0083025D00BC025D00CC025D00CC025D00CC025D00CC025D00CC025D + 00CC025D00CC025D00CC025D00BC024A0083010E003300000012021D0000066D + 0073129208DD20CC10F922D911FF22D911FF22D911FF22D911FF22D911FF22D9 + 11FF22D911FF22D911FF1FCC0FF9109207DD066D0073021D00000A7D00000A7D + 00BA25CA15F922D111FF22D111FF22D111FF22B611FF22D111FF22D111FF22D1 + 11FF22D111FF22D111FF22D111FF20C80FF90A7D00BA0A7D00000C8400000C84 + 00CC2BCC1AFF22C811FF22C811FF22B211FFE6E6E6FF22B211FF22C811FF22C8 + 11FF22C811FF22C811FF22C811FF22C811FF0C8400CC0C8400000D8900000D89 + 00CC31C620FF22BE11FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE + 11FF22BE11FF22BE11FF22BE11FF23BE12FF0D8900CC0D8900000E8D00000E8D + 00CC41C330FF23AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 + 11FF22B411FF22B411FF22B411FF25B514FF0E8D00CC0E8D00000F9200000F92 + 00CC52C941FFA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 + E6FF22A311FF22AA11FF22AA11FF28AF17FF0F9200CC0F920000109600001096 + 00CC55CC44FF3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 + E2FFE6E6E6FF229E11FF22A111FF2CAA1BFF109600CC10960000119A0000119A + 00CC5AD149FF47BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 + E2FFE3E3E3FFE7E7E7FF269E15FF39B128FF119A00CC119A0000129E0000129E + 00CC60D74FFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB + 33FFFFFFFFFFA7E29EFF4EC53DFF58CF47FF129E00CC129E000013A2000013A2 + 00CC67DE56FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE + 46FF4AC139FF51C840FF57CE46FF60D74FFF13A200CC13A2000014A5000014A5 + 00BA64DE53F95FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD6 + 4EFF5FD64EFF5FD64EFF5FD64EFF60DA4FF914A500BA14A5000014A8000014A8 + 007337C124DD66E054F96EE55DFF6EE55DFF6EE55DFF6EE55DFF6DE45CFF6DE4 + 5CFF6DE45CFF6DE45CFF64DF53F936BF23DD14A8007314A8000014A8000015A9 + 000C15AA007315AA00BA15AA00CC15AA00CC15AA00CC15AA00CC15AA00CC15AA + 00CC15AA00CC15AA00CC15AA00BA15AA007315A9000C14A80000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ModalResult = 1 + OnClick = btImportClick + TabOrder = 2 + end + object btCancel: TBitBtn + Left = 272 + Height = 24 + Top = 128 + Width = 104 + Caption = 'Cancel' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ModalResult = 2 + TabOrder = 3 + end + object lbSelectSoftware: TLabel + Left = 16 + Height = 15 + Top = 16 + Width = 49 + Caption = 'Software:' + ParentColor = False + end + object btBrowse: TSpeedButton + Left = 364 + Height = 23 + Top = 72 + Width = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btBrowseClick + end + object dlgPath: TSelectDirectoryDialog + left = 224 + top = 8 + end +end diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index d55956ec8..1743cc17a 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,5818 +1,5818 @@ -object MainForm: TMainForm - Left = 273 - Height = 575 - Top = 96 - Width = 819 - Align = alBottom - Caption = 'Free Manga Downloader' - ClientHeight = 575 - ClientWidth = 819 - OnClose = FormClose - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - OnWindowStateChange = FormWindowStateChange - LCLVersion = '1.5' - object sbUpdateList: TStatusBar - Left = 0 - Height = 30 - Top = 545 - Width = 819 - AutoSize = False - Panels = < - item - Width = 50 - end> - ParentShowHint = False - SimplePanel = False - SizeGrip = False - ShowHint = True - Visible = False - OnDrawPanel = sbUpdateListDrawPanel - end - object pcMain: TPageControl - Left = 201 - Height = 508 - Top = 11 - Width = 614 - ActivePage = tsDownload - Align = alClient - BorderSpacing.Top = 3 - BorderSpacing.Right = 4 - BorderSpacing.Bottom = 3 - ParentFont = False - TabIndex = 0 - TabOrder = 0 - OnChange = pcMainChange - object tsDownload: TTabSheet - Caption = 'Downloads' - ClientHeight = 480 - ClientWidth = 606 - object vtDownload: TVirtualStringTree - Left = 2 - Height = 445 - Top = 32 - Width = 600 - Align = alClient - BorderSpacing.Left = 2 - BorderSpacing.Right = 4 - BorderSpacing.Bottom = 3 - DefaultText = 'Node' - DragOperations = [doMove] - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Manga' - Width = 100 - end - item - Position = 1 - Text = 'Status' - Width = 200 - end - item - Position = 2 - Text = 'Progress' - Width = 55 - end - item - Position = 3 - Text = 'Transfer rate' - end - item - Position = 4 - Text = 'Website' - Width = 65 - end - item - Position = 5 - Text = 'Save to' - Width = 150 - end - item - Position = 6 - Text = 'Added' - Width = 80 - end> - Header.DefaultHeight = 17 - Header.Height = 25 - Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] - HintMode = hmHintAndDefault - Images = IconDL - IncrementalSearch = isVisibleOnly - Margin = 2 - ParentFont = False - ParentShowHint = False - PopupMenu = pmDownload - ShowHint = True - TabOrder = 0 - TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnAfterCellPaint = vtDownloadAfterCellPaint - OnColumnDblClick = vtDownloadColumnDblClick - OnDragAllowed = vtDownloadDragAllowed - OnDragOver = vtDownloadDragOver - OnDragDrop = vtDownloadDragDrop - OnFreeNode = vtDownloadFreeNode - OnGetText = vtDownloadGetText - OnGetImageIndex = vtDownloadGetImageIndex - OnGetHint = vtDownloadGetHint - OnHeaderClick = vtDownloadHeaderClick - OnInitNode = vtDownloadInitNode - OnKeyDown = vtDownloadKeyDown - OnKeyUp = vtDownloadKeyUp - end - object pnDownloadToolbar: TPanel - Left = 2 - Height = 28 - Top = 4 - Width = 600 - Align = alTop - BorderSpacing.Left = 2 - BorderSpacing.Top = 4 - BorderSpacing.Right = 4 - BevelOuter = bvNone - ClientHeight = 28 - ClientWidth = 600 - TabOrder = 1 - object TransferRateGraph: TChart - Left = 323 - Height = 26 - Top = 0 - Width = 277 - AllowZoom = False - AxisList = < - item - Minors = <> - Title.LabelFont.Orientation = 900 - end - item - Alignment = calBottom - Minors = <> - end> - AxisVisible = False - BackColor = clDefault - Extent.UseXMin = True - Extent.UseYMin = True - Extent.XMin = 1 - Extent.YMin = 1 - Foot.Brush.Color = clBtnFace - Foot.Font.Color = clBlue - Frame.Color = clGreen - Frame.Visible = False - Legend.Alignment = laCenterRight - Legend.BackgroundBrush.Style = bsClear - Legend.Frame.Visible = False - Legend.MarginX = 0 - Legend.MarginY = 0 - Legend.Spacing = 0 - Legend.SymbolWidth = 0 - Legend.UseSidebar = False - Legend.Visible = True - Margins.Left = 0 - Margins.Top = 0 - Margins.Right = 0 - Margins.Bottom = 0 - MarginsExternal.Left = 0 - MarginsExternal.Top = 0 - MarginsExternal.Right = 0 - MarginsExternal.Bottom = 0 - Title.Brush.Color = clBtnFace - Title.Font.Color = clBlue - Title.Text.Strings = ( - 'TAChart' - ) - Toolset = TransferRateToolset - Align = alClient - BorderSpacing.Bottom = 2 - Visible = False - object TransferRateGraphArea: TAreaSeries - Transparency = 125 - AreaBrush.Color = 8453888 - AreaContourPen.Color = 5481984 - AreaLinesPen.Style = psClear - Source = TransferRateGraphList - end - end - object pnDownloadToolbarLeft: TPanel - Left = 0 - Height = 28 - Top = 0 - Width = 323 - Align = alLeft - AutoSize = True - BevelOuter = bvNone - ClientHeight = 28 - ClientWidth = 323 - TabOrder = 1 - object ToolBarDownload: TToolBar - Left = 0 - Height = 25 - Top = 0 - Width = 321 - AutoSize = True - BorderSpacing.Right = 2 - ButtonHeight = 25 - EdgeBorders = [] - Images = IconList - List = True - ParentFont = False - ShowCaptions = True - TabOrder = 0 - TabStop = True - Transparent = True - object tbDownloadResumeAll: TToolButton - Left = 1 - Top = 0 - AutoSize = True - Caption = 'Resume All' - ImageIndex = 12 - OnClick = tbDownloadResumeAllClick - end - object tbDownloadStopAll: TToolButton - Left = 86 - Top = 0 - AutoSize = True - Caption = 'Stop All' - ImageIndex = 7 - OnClick = tbDownloadStopAllClick - end - object ToolButton1: TToolButton - Left = 153 - Height = 25 - Top = 0 - Width = 5 - Style = tbsDivider - end - object tbDownloadDeleteCompleted: TToolButton - Left = 158 - Top = 0 - AutoSize = True - Caption = 'Delete all completed tasks' - ImageIndex = 9 - OnClick = tbDownloadDeleteCompletedClick - end - end - end - end - end - object tsInformation: TTabSheet - Caption = 'Manga Info' - ClientHeight = 480 - ClientWidth = 606 - object sbInformation: TScrollBox - Left = 0 - Height = 480 - Top = 0 - Width = 606 - HorzScrollBar.Page = 214 - VertScrollBar.Page = 317 - Align = alClient - BorderStyle = bsNone - ClientHeight = 480 - ClientWidth = 606 - TabOrder = 0 - object pnInfomation: TPanel - Left = 0 - Height = 262 - Top = 0 - Width = 606 - Align = alTop - BevelOuter = bvNone - ClientHeight = 262 - ClientWidth = 606 - ParentFont = False - TabOrder = 0 - object rmInformation: TRichMemo - Left = 165 - Height = 222 - Top = 38 - Width = 436 - Anchors = [akTop, akLeft, akRight, akBottom] - Color = clWhite - HideSelection = False - ParentFont = False - ReadOnly = True - ScrollBars = ssVertical - TabOrder = 1 - ZoomFactor = 1 - end - object edURL: TEdit - Left = 4 - Height = 23 - Top = 6 - Width = 554 - Anchors = [akTop, akLeft, akRight] - OnKeyPress = edURLKeyPress - PopupMenu = pmEditURL - TabOrder = 0 - TextHint = 'Input URL here' - end - object btDonate: TImage - Cursor = crHandPoint - Left = 2 - Height = 21 - Top = 14 - Width = 75 - Anchors = [akTop, akRight] - OnClick = btDonateClick - Stretch = True - Visible = False - end - object btURL: TSpeedButton - Left = 561 - Height = 23 - Top = 6 - Width = 40 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0001000000070000000E000000150000001A0000001A0000001A0000001A0000 - 001A0000001A000000160000000F0000000800000002FFFFFF00FFFFFF000000 - 00020000000E0000001C0000002A000000330000003300000033733A02A66332 - 0274000000330000002B0000001D0000000F00000003FFFFFF00FFFFFF000000 - 00000000000000000000000000000000000000000000281502009D5206CC9D52 - 06CC763E055C29160300000000000000000000000000FFFFFF00FFFFFF005933 - 0B0058320A0058320A0058320A0058320A0058320A00A3580B00A3580BCCFFBA - 18FFA3580BCCA4590C5C7F470C002C19050000000000FFFFFF00FFFFFF00B166 - 1600AF641400AF641400AF641400AF641400AF641400AE631300AA5F10CCFFB9 - 12FFFFBC1EFFAA5F10CCAB60115CB1661600B96E1C00FFFFFF00FFFFFF00B267 - 1799B16616CCB16616CCB16616CCB16616CCB16616CCB16616CCB16616CCF7B5 - 25FFF5AB0EFFF7BA32FFB16616CCB267175CB96E1C00FFFFFF00FFFFFF00B96E - 1CCCF7CD81FFF4C276FFF3C071FFEEB85BFFE8B049FFE7AE45FFE6AD43FFE3A5 - 35FFE19E29FFE19E29FFEBB54DFFB96E1CCCBA6F1D5CFFFFFF00FFFFFF00C277 - 22CCF5C77BFFEEB266FFEEB266FFEEB266FFEAAE60FFE1A453FFD89B49FFD396 - 44FFD09341FFD09341FFD39644FFE8B868FFC27722CCFFFFFF00FFFFFF00CA7F - 28CCFAD589FFF6C97DFFF6C87CFFF5C77BFFF5C77BFFF5C67AFFF5C579FFF2BC - 70FFEFB468FFEFB468FFF8CF83FFCA7F28CCC97E275CFFFFFF00FFFFFF00D186 - 2D99D2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCF8CD - 81FFF4BE72FFFCD98DFFD2872ECCD1862D5CCA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00D3882F00D3882F00D58A3100D98E33CCFCD5 - 89FFFEE094FFD98E33CCD88D335CD2872E00CA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00D3882F00D78C3200E0953800E09538CCFFE4 - 98FFE09538CCDF94385CD98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00D88D3300E59A3C00E59A3C00E59A3CCCE59A - 3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00E89D3F00E89D3F00E89D3F00E99E4099E99E - 405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btURLClick - end - object pnThumbContainer: TPanel - Left = 4 - Height = 216 - Top = 38 - Width = 154 - BevelOuter = bvNone - BorderStyle = bsSingle - ClientHeight = 212 - ClientWidth = 150 - Color = clWhite - ParentColor = False - TabOrder = 2 - object imCover: TImage - Left = 0 - Height = 212 - Top = 0 - Width = 150 - AntialiasingMode = amOn - Align = alClient - Center = True - Proportional = True - Stretch = True - end - object pbWait: TPaintBox - Left = 0 - Height = 212 - Top = 0 - Width = 150 - Align = alClient - end - end - end - object spInfos: TSplitter - Cursor = crVSplit - Left = 0 - Height = 5 - Top = 262 - Width = 606 - Align = alTop - ResizeAnchor = akTop - end - object pnChapterList: TPanel - Left = 0 - Height = 213 - Top = 267 - Width = 606 - Align = alClient - BevelOuter = bvNone - ClientHeight = 213 - ClientWidth = 606 - TabOrder = 2 - object btDownload: TBitBtn - Left = 387 - Height = 30 - Top = 145 - Width = 101 - Anchors = [akRight, akBottom] - Caption = 'Download' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 - } - OnClick = btDownloadClick - TabOrder = 1 - end - object cbAddAsStopped: TCheckBox - Left = 4 - Height = 19 - Top = 182 - Width = 214 - Anchors = [akLeft, akBottom] - Caption = 'Add to download list as stopped task' - OnChange = cbAddAsStoppedChange - ParentFont = False - TabOrder = 3 - end - object clbChapterList: TVirtualStringTree - Left = 4 - Height = 125 - Top = 0 - Width = 563 - Anchors = [akTop, akLeft, akRight, akBottom] - Colors.UnfocusedSelectionColor = clHighlight - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = <> - Header.DefaultHeight = 17 - Header.MainColumn = -1 - IncrementalSearch = isVisibleOnly - Margin = 2 - ParentFont = False - PopupMenu = pmChapterList - TabOrder = 0 - TextMargin = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnBeforeCellPaint = clbChapterListBeforeCellPaint - OnFreeNode = clbChapterListFreeNode - OnGetText = clbChapterListGetText - OnGetNodeDataSize = clbChapterListGetNodeDataSize - OnInitNode = clbChapterListInitNode - end - object btReadOnline: TBitBtn - Left = 493 - Height = 30 - Top = 145 - Width = 108 - Anchors = [akRight, akBottom] - Caption = 'Read online' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0A0A0A660C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C - 0C770C0C0C770C0C0C776C3A07C94E2A06970000002C00000012000000090000 - 00161F1F1F74EBEBEBFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 - E6FFE6E6E6FFE6E6E6FFB47839FF99560FE3723F0A6E00000009000000002A2A - 2A0036363671E8E8E8FFB4B4B4FFBDBDBDFFC5C5C5FFBDBDBDFFBF9261FFBD81 - 40FFBD8140FFBD8140FFBF8342FFFFC538FFB56A18CCB76C195C343434004545 - 45004545456FEAEAEAFFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFC68A46FFFFE3 - 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC4B4B4B004B4B - 4B004B4B4B6EECECECFF8E8E8EFFA5A5A5FFA5A5A5FF8E8E8EFFD2A56FFFD599 - 53FFCF934CFFCD914AFFD79B55FFFFE597FFD2872ECCD0852D5C515151005151 - 51005151516DEEEEEEFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 - E8FFD5D5D5FFD5D5D5FFE3A75CFFD18E3AE2DE93375CD2872E00575757005757 - 57005757576CF0F0F0FFBFBFBFFFC7C7C7FFD0D0D0FFC7C7C7FFD8D8D8FFEAEA - EAFFBFBFBFFFC7C7C7FFEABD85FF9E794BA29C764800957043005D5D5D005D5D - 5D005D5D5D6BF2F2F2FFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFEDED - EDFFDBDBDBFFDBDBDBFFF2F2F2FF5D5D5D6B5D5D5D005D5D5D00626262006262 - 62006262626BF5F5F5FF919191FFC4C4C4FFAAAAAAFFAAAAAAFF919191FFF1F1 - F1FFBBBBBBFFCCCCCCFFF5F5F5FF6262626B6262620062626200676767006767 - 67006767676AF7F7F7FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 - F4FFF4F4F4FFF4F4F4FFF7F7F7FF6767676A67676700676767006C6C6C006C6C - 6C006C6C6C69F9F9F9FF03599DFF0961A5FF1A77BBFF2587CBFF1976BAFF2587 - CBFF1570B4FF055CA0FFF9F9F9FF6C6C6C696C6C6C006C6C6C00717171007171 - 710071717168FBFBFBFF03599DFFC2D8E9FF89B9DBFF90C3E5FFB6CFE0FF2587 - CBFF1570B4FF055CA0FFFBFBFBFF717171687171710071717100757575007575 - 750075757568FDFDFDFF03599DFF126CB0FF2484C8FF3096DAFF3196DAFF2587 - CBFF1570B4FF055CA0FFFDFDFDFF757575687575750075757500797979007979 - 790079797967FEFEFEFF02579BFF0961A5FF126DB1FF1876BAFF1976BAFF136E - B2FF0B63A7FF03599DFFFEFEFEFF7979796779797900797979007D7D7D007D7D - 7D007D7D7D67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFF7D7D7D677D7D7D007D7D7D007F7F7F007F7F - 7F008080804D8080806680808066808080668080806680808066808080668080 - 80668080806680808066808080668080804D7F7F7F007F7F7F00 - } - OnClick = btReadOnlineClick - TabOrder = 2 - end - object btBrowse: TSpeedButton - Left = 360 - Height = 23 - Top = 148 - Width = 23 - Anchors = [akRight, akBottom] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btBrowseClick - end - object btChecks: TSpeedButton - Left = 571 - Height = 30 - Top = 0 - Width = 30 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000900000012010E - 0033024A0083025D00BC025D00CC025D00CC025D00CC025D00CC025D00CC025D - 00CC025D00CC025D00CC025D00BC024A0083010E003300000012021D0000066D - 0073129208DD20CC10F922D911FF22D911FF22D911FF22D911FF22D911FF22D9 - 11FF22D911FF22D911FF1FCC0FF9109207DD066D0073021D00000A7D00000A7D - 00BA25CA15F922D111FF22D111FF22D111FF22B611FF22D111FF22D111FF22D1 - 11FF22D111FF22D111FF22D111FF20C80FF90A7D00BA0A7D00000C8400000C84 - 00CC2BCC1AFF22C811FF22C811FF22B211FFE6E6E6FF22B211FF22C811FF22C8 - 11FF22C811FF22C811FF22C811FF22C811FF0C8400CC0C8400000D8900000D89 - 00CC31C620FF22BE11FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE - 11FF22BE11FF22BE11FF22BE11FF23BE12FF0D8900CC0D8900000E8D00000E8D - 00CC41C330FF23AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 - 11FF22B411FF22B411FF22B411FF25B514FF0E8D00CC0E8D00000F9200000F92 - 00CC52C941FFA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 - E6FF22A311FF22AA11FF22AA11FF28AF17FF0F9200CC0F920000109600001096 - 00CC55CC44FF3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 - E2FFE6E6E6FF229E11FF22A111FF2CAA1BFF109600CC10960000119A0000119A - 00CC5AD149FF47BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 - E2FFE3E3E3FFE7E7E7FF269E15FF39B128FF119A00CC119A0000129E0000129E - 00CC60D74FFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB - 33FFFFFFFFFFA7E29EFF4EC53DFF58CF47FF129E00CC129E000013A2000013A2 - 00CC67DE56FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE - 46FF4AC139FF51C840FF57CE46FF60D74FFF13A200CC13A2000014A5000014A5 - 00BA64DE53F95FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD6 - 4EFF5FD64EFF5FD64EFF5FD64EFF60DA4FF914A500BA14A5000014A8000014A8 - 007337C124DD66E054F96EE55DFF6EE55DFF6EE55DFF6EE55DFF6DE45CFF6DE4 - 5CFF6DE45CFF6DE45CFF64DF53F936BF23DD14A8007314A8000014A8000015A9 - 000C15AA007315AA00BA15AA00CC15AA00CC15AA00CC15AA00CC15AA00CC15AA - 00CC15AA00CC15AA00CC15AA00BA15AA007315A9000C14A80000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btChecksClick - end - object btAddToFavorites: TBitBtn - Left = 387 - Height = 30 - Top = 179 - Width = 214 - Anchors = [akRight, akBottom] - Caption = 'Add to favorites' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000050000 - 001E0000003200009CC9000054630000002E0000002B00000026000000220000 - 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 - 000F000000190000A8C50000A8C500006D580000001600000013000000110000 - 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 - 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D - 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 - BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 - 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 - C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C - 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 - C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 - 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 - C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 - CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 - C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 - FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 - C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 - F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 - C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A - F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 - C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C - F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 - C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E - FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 - 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 - DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 - 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 - E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 - 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 - E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 - 0000000000000000990000002B00000000000000000001016E000101DE000101 - E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 - } - OnClick = btAddToFavoritesClick - TabOrder = 4 - end - object edSaveTo: TEdit - Left = 4 - Height = 23 - Top = 148 - Width = 353 - Anchors = [akLeft, akRight, akBottom] - ParentFont = False - TabOrder = 5 - TextHint = 'Save to' - end - object lbSaveTo: TLabel - Left = 4 - Height = 15 - Top = 130 - Width = 41 - Anchors = [akLeft, akBottom] - Caption = 'Save to:' - ParentColor = False - ParentFont = False - end - end - end - end - object tsFilter: TTabSheet - Caption = 'Filter' - ClientHeight = 480 - ClientWidth = 606 - object sbFilter: TScrollBox - Left = 0 - Height = 480 - Top = 0 - Width = 606 - HorzScrollBar.Page = 568 - VertScrollBar.Page = 424 - Align = alClient - BorderStyle = bsNone - ClientHeight = 480 - ClientWidth = 606 - TabOrder = 0 - object pnGenres: TPanel - Left = 24 - Height = 180 - Top = 10 - Width = 582 - Align = alTop - AutoSize = True - BorderSpacing.Left = 24 - BorderSpacing.Top = 10 - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 10 - ChildSizing.VerticalSpacing = 4 - ChildSizing.Layout = cclTopToBottomThenLeftToRight - ChildSizing.ControlsPerLine = 8 - ClientHeight = 180 - ClientWidth = 582 - TabOrder = 0 - object ckFilterAction: TCheckBox - Left = 0 - Height = 19 - Hint = 'A work typically depicting fighting, violence, chaos, and fast paced motion.' - Top = 0 - Width = 75 - AllowGrayed = True - Caption = 'Action' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 0 - end - object ckFilterAdult: TCheckBox - Left = 0 - Height = 19 - Hint = 'Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity.' - Top = 23 - Width = 75 - AllowGrayed = True - Caption = 'Adult' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 1 - end - object ckFilterAdventure: TCheckBox - Left = 0 - Height = 19 - Hint = 'If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it''s up to your personal prejudice on this case.' - Top = 46 - Width = 75 - AllowGrayed = True - Caption = 'Adventure' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 2 - end - object ckFilterComedy: TCheckBox - Left = 0 - Height = 19 - Hint = 'A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict.' - Top = 69 - Width = 75 - AllowGrayed = True - Caption = 'Comedy' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 3 - end - object ckFilterDoujinshi: TCheckBox - Left = 0 - Height = 19 - Hint = 'Fan based work inpspired by official manga/anime.' - Top = 92 - Width = 75 - AllowGrayed = True - Caption = 'Doujinshi' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 4 - end - object ckFilterDrama: TCheckBox - Left = 0 - Height = 19 - Hint = 'A work meant to bring on an emotional response, such as instilling sadness or tension.' - Top = 115 - Width = 75 - AllowGrayed = True - Caption = 'Drama' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 5 - end - object ckFilterEchi: TCheckBox - Left = 0 - Height = 19 - Hint = 'Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans.' - Top = 138 - Width = 75 - AllowGrayed = True - Caption = 'Ecchi' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 6 - end - object ckFilterFantasy: TCheckBox - Left = 0 - Height = 19 - Hint = 'Anything that involves, but not limited to, magic, dream world, and fairy tales.' - Top = 161 - Width = 75 - AllowGrayed = True - Caption = 'Fantasy' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 7 - end - object ckFilterGenderBender: TCheckBox - Left = 85 - Height = 19 - Hint = 'Girls dressing up as guys, guys dressing up as girls.'#13#10'Guys turning into girls, girls turning into guys.' - Top = 0 - Width = 98 - AllowGrayed = True - Caption = 'Gender Bender' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 8 - end - object ckFilterHarem: TCheckBox - Left = 85 - Height = 19 - Hint = 'A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed.' - Top = 23 - Width = 98 - AllowGrayed = True - Caption = 'Harem' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 9 - end - object ckFilterHentai: TCheckBox - Left = 85 - Height = 19 - Hint = 'Hentai' - Top = 46 - Width = 98 - AllowGrayed = True - Caption = 'Hentai' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 10 - end - object ckFilterHistorical: TCheckBox - Left = 85 - Height = 19 - Hint = 'Having to do with old or ancient times.' - Top = 69 - Width = 98 - AllowGrayed = True - Caption = 'Historical' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 11 - end - object ckFilterHorror: TCheckBox - Left = 85 - Height = 19 - Hint = 'A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking.' - Top = 92 - Width = 98 - AllowGrayed = True - Caption = 'Horror' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 12 - end - object ckFilterJosei: TCheckBox - Left = 85 - Height = 19 - Hint = 'Literally "Woman". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature.' - Top = 115 - Width = 98 - AllowGrayed = True - Caption = 'Josei' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 13 - end - object ckFilterLolicon: TCheckBox - Left = 85 - Height = 19 - Hint = 'Representing a sexual attraction to young or under-age girls.' - Top = 138 - Width = 98 - AllowGrayed = True - Caption = 'Lolicon' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 14 - end - object ckFilterMartialArts: TCheckBox - Left = 85 - Height = 19 - Hint = 'As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth.' - Top = 161 - Width = 98 - AllowGrayed = True - Caption = 'Martial Arts' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 15 - end - object ckFilterMature: TCheckBox - Left = 193 - Height = 19 - Hint = 'Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language.' - Top = 0 - Width = 93 - AllowGrayed = True - Caption = 'Mature' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 16 - end - object ckFilterMecha: TCheckBox - Left = 193 - Height = 19 - Hint = 'A work involving and usually concentrating on all types of large robotic machines.' - Top = 23 - Width = 93 - AllowGrayed = True - Caption = 'Mecha' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 17 - end - object ckFilterMusical: TCheckBox - Left = 193 - Height = 19 - Hint = 'Musical' - Top = 46 - Width = 93 - AllowGrayed = True - Caption = 'Musical' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 18 - end - object ckFilterMystery: TCheckBox - Left = 193 - Height = 19 - Hint = 'Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it.' - Top = 69 - Width = 93 - AllowGrayed = True - Caption = 'Mystery' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 19 - end - object ckFilterPsychological: TCheckBox - Left = 193 - Height = 19 - Hint = 'Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology.' - Top = 92 - Width = 93 - AllowGrayed = True - Caption = 'Psychological' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 20 - end - object ckFilterRomance: TCheckBox - Left = 193 - Height = 19 - Hint = 'Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is.' - Top = 115 - Width = 93 - AllowGrayed = True - Caption = 'Romance' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 21 - end - object ckFilterSchoolLife: TCheckBox - Left = 193 - Height = 19 - Hint = 'Having a major setting of the story deal with some type of school.' - Top = 138 - Width = 93 - AllowGrayed = True - Caption = 'School Life' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 22 - end - object ckFilterSciFi: TCheckBox - Left = 193 - Height = 19 - Hint = 'Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world.' - Top = 161 - Width = 93 - AllowGrayed = True - Caption = 'Sci-Fi' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 23 - end - object ckFilterSeinen: TCheckBox - Left = 296 - Height = 19 - Hint = 'From Google: Seinen means ''young Man''. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood.' - Top = 0 - Width = 81 - AllowGrayed = True - Caption = 'Seinen' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 24 - end - object ckFilterShotacon: TCheckBox - Left = 296 - Height = 19 - Hint = 'Representing a sexual attraction to young or under-age boys.' - Top = 23 - Width = 81 - AllowGrayed = True - Caption = 'Shotacon' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 25 - end - object ckFilterShoujo: TCheckBox - Left = 296 - Height = 19 - Hint = 'A work intended and primarily written for females. Usually involves a lot of romance and strong character development.' - Top = 46 - Width = 81 - AllowGrayed = True - Caption = 'Shoujo' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 26 - end - object ckFilterShoujoAi: TCheckBox - Left = 296 - Height = 19 - Hint = 'Often synonymous with yuri, this can be thought of as somewhat less extreme. "Girl''''s Love", so to speak.' - Top = 69 - Width = 81 - AllowGrayed = True - Caption = 'Shoujo Ai' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 27 - end - object ckFilterShounen: TCheckBox - Left = 296 - Height = 19 - Hint = 'A work intended and primarily written for males. These works usually involve fighting and/or violence.' - Top = 92 - Width = 81 - AllowGrayed = True - Caption = 'Shounen' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 28 - end - object ckFilterShounenAi: TCheckBox - Left = 296 - Height = 19 - Hint = 'Often synonymous with yaoi, this can be thought of as somewhat less extreme. "Boy''''s Love", so to speak' - Top = 115 - Width = 81 - AllowGrayed = True - Caption = 'Shounen Ai' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 29 - end - object ckFilterSliceofLife: TCheckBox - Left = 296 - Height = 19 - Hint = 'As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own.' - Top = 138 - Width = 81 - AllowGrayed = True - Caption = 'Slice of Life' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 30 - end - object ckFilterSmut: TCheckBox - Left = 296 - Height = 19 - Hint = 'Deals with series that are considered profane or offensive, particularly with regards to sexual content.' - Top = 161 - Width = 81 - HelpType = htKeyword - AllowGrayed = True - Caption = 'Smut' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 31 - end - object ckFilterSports: TCheckBox - Left = 387 - Height = 19 - Hint = 'As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few.' - Top = 0 - Width = 87 - AllowGrayed = True - Caption = 'Sports' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 32 - end - object ckFilterSupernatural: TCheckBox - Left = 387 - Height = 19 - Hint = 'Usually entails amazing and unexplained powers or events which defy the laws of physics.' - Top = 23 - Width = 87 - AllowGrayed = True - Caption = 'Supernatural' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 33 - end - object ckFilterTragedy: TCheckBox - Left = 387 - Height = 19 - Hint = 'Contains events resulting in great loss and misfortune.' - Top = 46 - Width = 87 - AllowGrayed = True - Caption = 'Tragedy' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 34 - end - object ckFilterYaoi: TCheckBox - Left = 387 - Height = 19 - Hint = 'This work usually involves intimate relationships between men.' - Top = 69 - Width = 87 - AllowGrayed = True - Caption = 'Yaoi' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 35 - end - object ckFilterYuri: TCheckBox - Left = 387 - Height = 19 - Hint = 'This work usually involves intimate relationships between women.' - Top = 92 - Width = 87 - AllowGrayed = True - Caption = 'Yuri' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 36 - end - object ckFilterWeebtons: TCheckBox - Left = 387 - Height = 19 - Hint = 'Weebtoons' - Top = 115 - Width = 87 - AllowGrayed = True - Caption = 'Weebtoons' - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 37 - end - end - object pnFilter: TPanel - Left = 0 - Height = 192 - Top = 232 - Width = 606 - Align = alTop - BevelOuter = bvNone - ClientHeight = 192 - ClientWidth = 606 - ParentFont = False - TabOrder = 1 - object rbOne: TRadioButton - Left = 323 - Height = 19 - Top = 32 - Width = 169 - Caption = 'Have one of genres checked' - ParentFont = False - TabOrder = 1 - end - object rbAll: TRadioButton - Left = 323 - Height = 19 - Top = 8 - Width = 142 - Caption = 'Have all genre checked' - Checked = True - ParentFont = False - TabOrder = 0 - TabStop = True - end - object cbOnlyNew: TCheckBox - Left = 323 - Height = 19 - Top = 56 - Width = 146 - Caption = 'Search only new manga' - ParentFont = False - TabOrder = 2 - end - object edFilterTitle: TEdit - Left = 135 - Height = 23 - Top = 8 - Width = 175 - TabOrder = 3 - TextHint = 'Title' - end - object edFilterArtists: TEdit - Left = 135 - Height = 23 - Top = 56 - Width = 175 - TabOrder = 4 - TextHint = 'Artist' - end - object edFilterAuthors: TEdit - Left = 135 - Height = 23 - Top = 32 - Width = 175 - TabOrder = 5 - TextHint = 'Author' - end - object lbFilterTitle: TLabel - Left = 23 - Height = 17 - Top = 8 - Width = 28 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Title' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object lbFilterAuthors: TLabel - Left = 23 - Height = 17 - Top = 32 - Width = 43 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Author' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object lbFilterArtists: TLabel - Left = 23 - Height = 17 - Top = 56 - Width = 34 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Artist' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object cbFilterStatus: TComboBox - Left = 135 - Height = 23 - Top = 80 - Width = 175 - ItemHeight = 15 - ItemIndex = 2 - Items.Strings = ( - 'Completed' - 'Ongoing' - '' - ) - Style = csDropDownList - TabOrder = 6 - Text = '' - end - object lbFilterStatus: TLabel - Left = 23 - Height = 17 - Top = 80 - Width = 38 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Status' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object lbFilterSummary: TLabel - Left = 23 - Height = 17 - Top = 104 - Width = 59 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Summary' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edFilterSummary: TEdit - Left = 135 - Height = 23 - Top = 104 - Width = 175 - TabOrder = 7 - TextHint = 'Part of summary' - end - object btRemoveFilterLarge: TBitBtn - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 191 - Height = 37 - Hint = 'Remove filter' - Top = 139 - Width = 136 - Caption = 'Remove filter' - Font.Height = -13 - Font.Style = [fsBold] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000080000000000005A000000770000008000000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A000000110000000400005A00000077000000770000008000000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578040426000000 - 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 - 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 - A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 - A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C - 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 250027275200101090000000AA000000AA000000AA000000A700363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535004343430035355F00121291000000AA000000A700363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A43434300464646004646460035355F0023237700363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btRemoveFilterClick - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 8 - end - object cbSearchFromAllSites: TCheckBox - Left = 323 - Height = 19 - Top = 80 - Width = 149 - Caption = 'Search in all manga sites' - TabOrder = 9 - end - object btFilter: TBitBtn - Left = 39 - Height = 37 - Top = 139 - Width = 130 - Caption = 'Filter' - Font.Height = -13 - Font.Style = [fsBold] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000089C5106999C51065CA75C0D00B56A1800000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A0000001100000004A75C0DCCA75C0DCCA95E0E5CB56A1800000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578B76C1999B56A - 18CCB56A18CCB56A18CCB56A18CCFFC538FFB56A18CCB76C195C000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097EC37923CCFFE3 - 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87D0852D99D287 - 2ECCD2872ECCD2872ECCD2872ECCFFE597FFD2872ECCD0852D5C000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B89714C1F00D58A - 3100D58A3100D98E3400DF9438CCDF9438CCDE93375CD2872E001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B8912121200A870 - 2D00D58A3100E69B3D00E79C3E99E79C3E5CDF943800D2872E00363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 25005C4A3300E69B3D00E89D3F00E89D3F00DF943800D2872E00363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535006B594100E89D3F00E89D3F00DF943800D2872E00363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A434343006F5D450097724300936D3F008C673A00363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btFilterClick - ParentFont = False - TabOrder = 10 - end - object btFilterReset: TBitBtn - Left = 345 - Height = 37 - Top = 139 - Width = 128 - Caption = 'Reset value' - Font.Height = -13 - Font.Style = [fsBold] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000050000001E000000320000003300000082000000830101014E0000 - 003300000033000000220000000800000000FFFFFF00FFFFFF00FFFFFF000000 - 0000000000030000000F000000190000001A00000078D1C2C2FF0303037A0000 - 001A0000001A000000110000000400000000FFFFFF00FFFFFF00FFFFFF000000 - 00000000000000000000000000000202020002020272C4B5B5FF050505780505 - 050000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 00000000000000000000010101000101010001010174C4B5B5FF0909097E0A0A - 0A0008080800000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000007AC4B5B5FF0B0B0B870D0D - 0D000D0D0D000A0A0A000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D - 0D000D0D0D000D0D0D000A0A0A0007070700FFFFFF00FFFFFF00FFFFFF001B1B - 1B00161616000404040000000000000000000000007BC4B5B5FF0B0B0B891212 - 12001919190021212100282828002A2A2A00FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717 - 172F25252500353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF1717 - 17852525252D353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7 - C7FF2525257E3535352A4343430046464600FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBC - BCFFDFCDCDFF353535774343432846464600FFFFFF00FFFFFF00FFFFFF004B4B - 4B002C2C2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5 - B5FFDCCACAFFEBDADAFF4343436F4E4E4E00FFFFFF00FFFFFF00FFFFFF004F4F - 4F662C2C2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C - 9CFFB6ADADFFC5BCBCFF4343436F4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F - 4F66EAEAEAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4 - C4FFE4D2D2FFF0DFDFFFF9E8E8FF4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F - 4F4D2C2C2C6608080866000000660000006A0000007B020202890B0B0B891717 - 17852525257E353535774343436F4F4F4F4FFFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btFilterResetClick - ParentFont = False - TabOrder = 11 - end - object cbUseRegExpr: TCheckBox - Left = 323 - Height = 19 - Top = 104 - Width = 118 - Caption = 'Regular Expression' - TabOrder = 12 - end - end - object pnCustomGenre: TPanel - Left = 0 - Height = 42 - Top = 190 - Width = 606 - Align = alTop - BevelOuter = bvNone - ClientHeight = 42 - ClientWidth = 606 - TabOrder = 2 - object lbFilterCustomGenres: TLabel - Left = 23 - Height = 17 - Top = 10 - Width = 93 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Custom Genres' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edCustomGenres: TEdit - Left = 135 - Height = 23 - Top = 10 - Width = 416 - ParentFont = False - TabOrder = 0 - TextHint = 'Input custom genres, separated by comma' - end - object lbFilterHint: TLabel - Left = 555 - Height = 15 - Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''''!'''' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' - Top = 13 - Width = 13 - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object Bevel1: TBevel - Left = 0 - Height = 5 - Top = 37 - Width = 606 - Align = alBottom - Shape = bsBottomLine - end - end - end - end - object tsFavorites: TTabSheet - Caption = 'Favorites' - ClientHeight = 480 - ClientWidth = 606 - object btFavoritesCheckNewChapter: TBitBtn - Left = 33 - Height = 40 - Top = 400 - Width = 545 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Check for new chapter' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 - 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 - 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB - E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 - 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 - E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 - 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 - D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 - 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 - BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 - 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 - 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 - 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F - 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 - 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D - 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 - 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F - 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 - 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 - 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 - 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 - 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 - 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 - 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 - 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 - 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 - 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 - 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 - E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 - 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550073AA550000AA550000 - } - OnClick = btFavoritesCheckNewChapterClick - TabOrder = 1 - end - object vtFavorites: TVirtualStringTree - Left = 2 - Height = 389 - Top = 4 - Width = 600 - Align = alTop - Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Left = 2 - BorderSpacing.Top = 4 - BorderSpacing.Right = 4 - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Alignment = taRightJustify - Position = 0 - Text = '#' - end - item - Position = 1 - Text = 'Title' - Width = 150 - end - item - Position = 2 - Text = 'Current chapter' - Width = 100 - end - item - Position = 3 - Text = 'Website' - Width = 65 - end - item - Position = 4 - Text = 'Save to' - Width = 200 - end> - Header.DefaultHeight = 24 - Header.Height = 24 - Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] - HintMode = hmHintAndDefault - Images = IconList - IncrementalSearch = isVisibleOnly - Margin = 0 - ParentFont = False - ParentShowHint = False - PopupMenu = pmFavorites - ShowHint = True - TabOrder = 0 - TextMargin = 2 - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnBeforeCellPaint = vtFavoritesBeforeCellPaint - OnColumnDblClick = vtFavoritesColumnDblClick - OnFreeNode = vtFavoritesFreeNode - OnGetText = vtFavoritesGetText - OnGetImageIndex = vtFavoritesGetImageIndex - OnGetHint = vtFavoritesGetHint - OnHeaderClick = vtFavoritesHeaderClick - OnInitNode = vtFavoritesInitNode - end - object btFavoritesImport: TBitBtn - Left = 33 - Height = 24 - Top = 446 - Width = 545 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Import list' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF000000001600000032000076A40000764D0000002D000000330000002D0000 - 764D000076A4000000330000001AFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000000000B000000190000A8C50000A8C500007F450000590000007F450000 - A8C50000A8C50000001A0000000DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000000000000008A000000B6BF6868FFFF0000B6BF0000B6720000B6BF6868 - FFFF0000B6BF00008A0000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00010190000101BF000101BFBB6262F8FF6A6AFFFF0101BFBB6A6AFFFF6262 - F8FF0101BFBB0101BF0001019000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101C3000101C3000101C3B96464F8FF5B5BF1FF6C6CFFFF5B5BF1FF6464 - F8FF0101C3B90101C3000101C300FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101B7000101C7000101C7B86767F9FF2727BFFF1919B2FF4949DEFF6767 - F9FF0101C7B80101C7000101C700FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000000A8000101AF000101CBB66A6AFAFF1A1AB3FFA6A6FFFF3636CDFF6161 - F2FF0101CBB60101CB000101CB00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000000A9930000A8C40000A8C42121BAFF2121BAFF8484EEFF8E8EFBFF5E5E - EEFF0101CEB50101CE000101CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000000B1C1AAAAFFFFAAAAFFFFAAAAFFFFAAAAFFFFA6A6FFFF9090FCFF7D7D - FCFF0101D2B30101D2000101D200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101BA8E0101BBBD0101BBBD3131CAFF3131CAFF8888F1FF9191FDFF6666 - F3FF0101D5B20101D5000101D500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101BB000101C4000101D9B17676FDFF3939D2FFA7A7FFFF4E4EE2FF7070 - F9FF0101D9B10101D9000101D900FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101CC000101DC000101DCAF7979FEFF4D4DE3FF4545DDFF6363F2FF7979 - FEFF0101DCAF0101DC000101DC00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101DE000101DE000101DEAE7C7CFEFF7373FDFF7373FDFF7373FDFF7C7C - FEFF0101DEAE0101DE000101DE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101E1000101E1000101E1AD7E7EFFFF7575FEFF7575FEFF7575FEFF7E7E - FFFF0101E1AD0101E1000101E100FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101E3000101E3000101E3AC8484FFFF7F7FFFFF7F7FFFFF7F7FFFFF8484 - FFFF0101E3AC0101E3000101E300FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000101E4000101E4000101E5810101E5AB0101E5AB0101E5AB0101E5AB0101 - E5AB0101E5810101E4000101E400FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btFavoritesImportClick - ParentFont = False - TabOrder = 2 - end - object btCancelFavoritesCheck: TSpeedButton - Left = 538 - Height = 40 - Top = 400 - Width = 40 - Anchors = [akRight, akBottom] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - Visible = False - OnClick = btCancelFavoritesCheckClick - end - end - object tsOption: TTabSheet - Caption = 'Options' - ClientHeight = 480 - ClientWidth = 606 - object pnOptions: TPageControl - Left = 9 - Height = 403 - Top = 8 - Width = 587 - ActivePage = tsGeneral - Anchors = [akTop, akLeft, akRight, akBottom] - ParentFont = False - TabIndex = 0 - TabOrder = 0 - object tsGeneral: TTabSheet - Caption = 'General' - ClientHeight = 375 - ClientWidth = 579 - object cbLanguages: TComboBox - Left = 20 - Height = 23 - Top = 34 - Width = 212 - ItemHeight = 15 - Items.Strings = ( - 'English' - ) - ParentFont = False - Style = csDropDownList - TabOrder = 0 - end - object lbOptionLanguage: TLabel - Left = 20 - Height = 15 - Top = 18 - Width = 55 - Caption = 'Language:' - ParentColor = False - end - object seOptionNewMangaTime: TSpinEdit - Left = 20 - Height = 23 - Top = 112 - Width = 58 - MaxValue = 365 - MinValue = 1 - ParentFont = False - TabOrder = 1 - Value = 1 - end - object lbOptionNewMangaTime: TLabel - Left = 86 - Height = 15 - Top = 115 - Width = 238 - Caption = 'New manga based on it''s update time (days)' - ParentColor = False - ParentFont = False - end - object cbOptionMinimizeToTray: TCheckBox - Left = 20 - Height = 19 - Top = 200 - Width = 106 - Caption = 'Minimize to tray' - ParentFont = False - TabOrder = 2 - end - object cbOptionLetFMDDo: TComboBox - Left = 20 - Height = 23 - Top = 80 - Width = 212 - ItemHeight = 15 - Items.Strings = ( - 'Do nothing' - 'Exit FMD' - 'Shutdown' - 'Hibernate' - ) - ParentFont = False - Style = csDropDownList - TabOrder = 3 - end - object lbOptionLetFMDDo: TLabel - Left = 20 - Height = 15 - Top = 64 - Width = 117 - Caption = 'After download finish:' - ParentColor = False - end - object gbOptionExternal: TGroupBox - Left = 20 - Height = 132 - Top = 228 - Width = 520 - Anchors = [akTop, akLeft, akRight] - Caption = 'External program' - ClientHeight = 112 - ClientWidth = 516 - ParentFont = False - TabOrder = 4 - object edOptionExternalParams: TEdit - Left = 13 - Height = 23 - Top = 74 - Width = 467 - Anchors = [akTop, akLeft, akRight] - TabOrder = 0 - TextHint = 'External program parameters' - end - object lbOptionExternal: TLabel - Left = 13 - Height = 15 - Top = 6 - Width = 213 - Caption = 'Open manga by using external program:' - ParentColor = False - end - object lbOptionExternalParamsHint: TLabel - Left = 485 - Height = 15 - Top = 77 - Width = 13 - Anchors = [akTop, akRight] - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object lbOptionExternalParams: TLabel - Left = 13 - Height = 15 - Top = 56 - Width = 62 - Caption = 'Parameters:' - ParentColor = False - end - object edOptionExternalPath: TFileNameEdit - Left = 13 - Height = 23 - Top = 24 - Width = 491 - FilterIndex = 0 - HideDirectories = False - ButtonWidth = 23 - NumGlyphs = 1 - Anchors = [akTop, akLeft, akRight] - MaxLength = 0 - TabOrder = 1 - TextHint = 'External program path' - end - end - object cbOptionOneInstanceOnly: TCheckBox - Left = 20 - Height = 19 - Top = 176 - Width = 177 - Caption = 'Permit only one FMD running' - ParentFont = False - TabOrder = 5 - end - object cbOptionLiveSearch: TCheckBox - Left = 20 - Height = 19 - Top = 152 - Width = 210 - Caption = 'Enable live search (slow on long list)' - ParentFont = False - TabOrder = 6 - end - end - object tsView: TTabSheet - Caption = 'View' - ClientHeight = 375 - ClientWidth = 579 - object cbOptionShowDownloadToolbar: TCheckBox - Left = 16 - Height = 19 - Top = 232 - Width = 151 - Caption = 'Show downloads toolbar' - ParentFont = False - TabOrder = 0 - end - object gbDropTarget: TGroupBox - Left = 16 - Height = 200 - Top = 16 - Width = 312 - Caption = 'Drop Box' - ClientHeight = 180 - ClientWidth = 308 - TabOrder = 1 - object ckDropTarget: TCheckBox - Left = 16 - Height = 19 - Top = 9 - Width = 100 - Caption = 'Show Drop Box' - ParentFont = False - TabOrder = 0 - end - object tbDropTargetOpacity: TTrackBar - Left = 16 - Height = 33 - Top = 128 - Width = 280 - Frequency = 15 - Max = 255 - Min = 5 - OnChange = tbDropTargetOpacityChange - Position = 200 - TabOrder = 1 - end - object lbDropTargetOpacity: TLabel - Left = 16 - Height = 15 - Top = 112 - Width = 41 - Caption = 'Opacity' - ParentColor = False - ParentFont = False - end - object rgDropTargetMode: TRadioGroup - Left = 16 - Height = 58 - Top = 40 - Width = 120 - AutoFill = True - AutoSize = True - Caption = 'Mode' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.EnlargeVertical = crsHomogenousChildResize - ChildSizing.ShrinkHorizontal = crsScaleChilds - ChildSizing.ShrinkVertical = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 38 - ClientWidth = 116 - ItemIndex = 0 - Items.Strings = ( - 'Download all' - 'Add to favorites' - ) - ParentFont = False - TabOrder = 2 - end - end - object cbOptionEnableLoadCover: TCheckBox - Left = 16 - Height = 19 - Top = 256 - Width = 153 - Caption = 'Enable load manga cover' - ParentFont = False - TabOrder = 2 - end - end - object tsConnections: TTabSheet - Caption = 'Connections' - ClientHeight = 375 - ClientWidth = 579 - object sbDownloadConnections: TScrollBox - Left = 0 - Height = 375 - Top = 0 - Width = 579 - HorzScrollBar.Page = 457 - VertScrollBar.Page = 179 - Align = alClient - BorderStyle = bsNone - ClientHeight = 375 - ClientWidth = 579 - TabOrder = 0 - object cbOptionUseProxy: TCheckBox - Left = 12 - Height = 19 - Top = 160 - Width = 71 - Caption = 'Use proxy' - OnChange = cbOptionUseProxyChange - ParentFont = False - TabOrder = 0 - end - object gbOptionProxy: TGroupBox - Left = 12 - Height = 120 - Top = 184 - Width = 561 - Anchors = [akTop, akLeft, akRight] - Caption = 'Proxy config' - ClientHeight = 100 - ClientWidth = 557 - Enabled = False - ParentFont = False - TabOrder = 1 - object lbOptionHost: TLabel - Left = 16 - Height = 15 - Top = 40 - Width = 25 - Caption = 'Host' - ParentColor = False - ParentFont = False - end - object lbOptionPort: TLabel - Left = 16 - Height = 15 - Top = 72 - Width = 22 - Caption = 'Port' - ParentColor = False - end - object edOptionHost: TEdit - Left = 57 - Height = 23 - Top = 38 - Width = 154 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Default' - ParentFont = False - TabOrder = 0 - TextHint = 'Proxy host/IP' - end - object edOptionPort: TEdit - Left = 57 - Height = 23 - Top = 70 - Width = 154 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Default' - ParentFont = False - TabOrder = 1 - TextHint = 'Proxy Port' - end - object lbOptionUser: TLabel - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 232 - Height = 15 - Top = 40 - Width = 53 - Caption = 'Username' - ParentColor = False - end - object lbOptionPass: TLabel - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 233 - Height = 15 - Top = 72 - Width = 50 - Caption = 'Password' - ParentColor = False - end - object edOptionUser: TEdit - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 297 - Height = 23 - Top = 38 - Width = 154 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Default' - ParentFont = False - TabOrder = 2 - TextHint = 'Proxy username' - end - object edOptionPass: TEdit - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 297 - Height = 23 - Top = 70 - Width = 154 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Default' - ParentFont = False - TabOrder = 3 - TextHint = 'Proxy password' - end - object cbOptionProxyType: TComboBox - Left = 57 - Height = 23 - Top = 6 - Width = 154 - ItemHeight = 15 - ItemIndex = 0 - Items.Strings = ( - 'HTTP' - 'SOCKS4' - 'SOCKS5' - ) - Style = csDropDownList - TabOrder = 4 - Text = 'HTTP' - end - object lbOptionProxyType: TLabel - Left = 15 - Height = 15 - Top = 8 - Width = 26 - Caption = 'Type' - ParentColor = False - end - end - object seOptionMaxParallel: TSpinEdit - Left = 12 - Height = 23 - Top = 26 - Width = 48 - MaxValue = 8 - MinValue = 1 - ParentFont = False - ParentShowHint = False - TabOrder = 2 - Value = 1 - end - object lbOptionMaxParallel: TLabel - Left = 66 - Height = 15 - Top = 29 - Width = 292 - Caption = 'Number of downloaded tasks at the same time (Max: 8)' - ParentColor = False - ParentFont = False - end - object lbOptionMaxThread: TLabel - Left = 66 - Height = 15 - Top = 61 - Width = 337 - Caption = 'Number of downloaded files per task at the same time (Max: 32)' - ParentColor = False - ParentFont = False - end - object seOptionMaxThread: TSpinEdit - Left = 12 - Height = 23 - Top = 58 - Width = 48 - MaxValue = 32 - MinValue = 1 - ParentFont = False - ParentShowHint = False - TabOrder = 3 - Value = 1 - end - object seOptionMaxRetry: TSpinEdit - Left = 12 - Height = 23 - Top = 90 - Width = 48 - MinValue = -1 - ParentFont = False - ParentShowHint = False - TabOrder = 4 - end - object lbOptionMaxRetry: TLabel - Left = 66 - Height = 15 - Top = 93 - Width = 391 - Caption = 'Number of retry times if tasks have download problems (-1 = always retry)' - ParentColor = False - ParentFont = False - end - object seOptionConnectionTimeout: TSpinEdit - Left = 12 - Height = 23 - Top = 120 - Width = 48 - MaxValue = 300 - MinValue = 1 - ParentFont = False - ParentShowHint = False - TabOrder = 5 - Value = 30 - end - object lbOptionConnectionTimeout: TLabel - Left = 66 - Height = 15 - Top = 123 - Width = 161 - Caption = 'Connection timeout (seconds)' - ParentColor = False - ParentFont = False - end - end - end - object tsSaveTo: TTabSheet - Caption = 'Save to' - ClientHeight = 375 - ClientWidth = 579 - object rgOptionCompress: TRadioGroup - Left = 20 - Height = 60 - Top = 66 - Width = 520 - Anchors = [akTop, akLeft, akRight] - AutoFill = True - Caption = 'Save downloaded chapters as' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.EnlargeVertical = crsHomogenousChildResize - ChildSizing.ShrinkHorizontal = crsScaleChilds - ChildSizing.ShrinkVertical = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 4 - ClientHeight = 40 - ClientWidth = 516 - Columns = 4 - ItemIndex = 0 - Items.Strings = ( - 'None' - 'ZIP' - 'CBZ' - 'PDF' - ) - ParentFont = False - TabOrder = 0 - end - object gbOptionRenaming: TGroupBox - Left = 20 - Height = 196 - Top = 170 - Width = 520 - Anchors = [akTop, akLeft, akRight] - Caption = 'Renaming' - ClientHeight = 176 - ClientWidth = 516 - ParentFont = False - TabOrder = 1 - object cbOptionGenerateMangaFolderName: TCheckBox - Left = 22 - Height = 19 - Top = 36 - Width = 261 - Caption = 'Auto generate folder based on manga''s name' - ParentFont = False - TabOrder = 0 - end - object cbOptionGenerateChapterName: TCheckBox - Left = 294 - Height = 19 - Top = 52 - Width = 246 - Caption = 'Generate chapter folder with chapter name' - ParentFont = False - TabOrder = 1 - Visible = False - end - object cbOptionPathConvert: TCheckBox - Left = 22 - Height = 19 - Top = 14 - Width = 517 - Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' - ParentFont = False - TabOrder = 2 - end - object cbOptionAutoNumberChapter: TCheckBox - Left = 294 - Height = 19 - Top = 36 - Width = 134 - Caption = 'Auto number chapter' - TabOrder = 3 - Visible = False - end - object edOptionCustomRename: TEdit - Left = 22 - Height = 23 - Top = 140 - Width = 434 - Anchors = [akTop, akLeft, akRight] - TabOrder = 4 - TextHint = 'Custom rename' - end - object lbOptionCustomRename: TLabel - Left = 22 - Height = 15 - Top = 124 - Width = 112 - Caption = 'Chapter folder name:' - ParentColor = False - end - object lbOptionCustomRenameHint: TLabel - Left = 462 - Height = 15 - Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' - Top = 142 - Width = 13 - Anchors = [akTop, akRight] - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object lbOptionRenameDigits: TLabel - Left = 22 - Height = 15 - Top = 68 - Width = 78 - Caption = 'Rename digits' - ParentColor = False - end - object seOptionDigitVolume: TSpinEdit - Left = 94 - Height = 23 - Top = 90 - Width = 50 - MaxValue = 10 - MinValue = 1 - TabOrder = 5 - Value = 1 - end - object seOptionDigitChapter: TSpinEdit - Left = 230 - Height = 23 - Top = 90 - Width = 50 - MaxValue = 10 - MinValue = 1 - TabOrder = 6 - Value = 1 - end - object cbOptionDigitVolume: TCheckBox - Left = 25 - Height = 19 - Top = 92 - Width = 61 - Caption = 'Volume' - OnChange = cbOptionDigitVolumeChange - TabOrder = 7 - end - object cbOptionDigitChapter: TCheckBox - Left = 158 - Height = 19 - Top = 92 - Width = 62 - Caption = 'Chapter' - OnChange = cbOptionDigitChapterChange - TabOrder = 8 - end - end - object seOptionPDFQuality: TSpinEdit - Left = 44 - Height = 23 - Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 132 - Width = 50 - MinValue = 5 - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 2 - Value = 100 - end - object lbOptionPDFQuality: TLabel - Left = 103 - Height = 15 - Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 135 - Width = 119 - Caption = 'PDF compression level' - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object lbOptionCustomRenameHint1: TLabel - Left = 260 - Height = 15 - Hint = '100: FlateEncode (lossless), lower: DCTEncode (lossy)' - Top = 135 - Width = 13 - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object btOptionBrowse: TSpeedButton - Left = 512 - Height = 23 - Top = 34 - Width = 23 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btOptionBrowseClick - end - object edOptionDefaultPath: TEdit - Left = 20 - Height = 23 - Top = 34 - Width = 490 - Anchors = [akTop, akLeft, akRight] - ParentFont = False - TabOrder = 3 - TextHint = 'Default download path' - end - object lbDefaultDownloadPath: TLabel - Left = 20 - Height = 15 - Top = 15 - Width = 186 - Caption = 'Choose the default download path:' - ParentColor = False - ParentFont = False - end - end - object tsUpdate: TTabSheet - Caption = 'Updates' - ClientHeight = 375 - ClientWidth = 579 - object cbOptionAutoCheckLatestVersion: TCheckBox - Left = 16 - Height = 19 - Top = 16 - Width = 173 - Caption = 'Auto check for latest version ' - ParentFont = False - TabOrder = 0 - end - object gbOptionFavorites: TGroupBox - Left = 17 - Height = 178 - Top = 48 - Width = 520 - Anchors = [akTop, akLeft, akRight] - Caption = 'Favorites' - ClientHeight = 158 - ClientWidth = 516 - ParentFont = False - TabOrder = 1 - object cbOptionAutoCheckFavStartup: TCheckBox - Left = 16 - Height = 19 - Top = 8 - Width = 219 - Caption = 'Auto check for new chapter at startup' - ParentFont = False - TabOrder = 3 - end - object seOptionAutoCheckFavIntervalMinutes: TSpinEdit - Left = 16 - Height = 23 - Top = 56 - Width = 58 - MaxValue = 1440 - OnChange = seOptionAutoCheckFavIntervalMinutesChange - TabOrder = 0 - end - object lbOptionAutoCheckFavIntervalMinutes: TLabel - Left = 82 - Height = 15 - Top = 60 - Width = 243 - Caption = 'Auto check for new chapter every %d minutes' - ParentColor = False - end - object cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox - Left = 16 - Height = 19 - Top = 120 - Width = 298 - Caption = 'Automatic remove completed manga from Favorites' - TabOrder = 1 - end - object cbOptionAutoCheckFavDownload: TCheckBox - Left = 16 - Height = 19 - Top = 96 - Width = 242 - Caption = 'Automatic download after finish checking' - ParentFont = False - TabOrder = 2 - end - object cbOptionAutoCheckFavInterval: TCheckBox - Left = 16 - Height = 19 - Top = 32 - Width = 237 - Caption = 'Auto check for new chapter in an interval' - OnChange = cbOptionAutoCheckFavIntervalChange - ParentFont = False - TabOrder = 4 - end - end - object cbOptionUpdateListNoMangaInfo: TCheckBox - Left = 17 - Height = 19 - Top = 242 - Width = 407 - Caption = 'Don''t load manga information when updating list (filter will be not work!)' - ParentFont = False - TabOrder = 2 - end - object cbOptionUpdateListRemoveDuplicateLocalData: TCheckBox - Left = 17 - Height = 19 - Top = 266 - Width = 310 - Caption = 'Remove duplicate local data when updating manga list' - ParentFont = False - TabOrder = 3 - Visible = False - end - end - object tsDialogs: TTabSheet - Caption = 'Dialogs' - ClientHeight = 375 - ClientWidth = 579 - object gbDialogs: TGroupBox - Left = 10 - Height = 346 - Top = 14 - Width = 556 - Anchors = [akTop, akLeft, akRight, akBottom] - ClientHeight = 326 - ClientWidth = 552 - TabOrder = 0 - object cbOptionShowQuitDialog: TCheckBox - Left = 24 - Height = 19 - Top = 32 - Width = 66 - Caption = 'Exit FMD' - ParentFont = False - TabOrder = 0 - end - object lbOptionDialogs: TLabel - Left = 16 - Height = 15 - Top = 8 - Width = 158 - Caption = 'Show dialog confirmation for:' - ParentColor = False - end - object cbOptionShowDeleteTaskDialog: TCheckBox - Left = 24 - Height = 19 - Top = 56 - Width = 122 - Caption = 'Delete task/favorite' - ParentFont = False - TabOrder = 1 - end - end - end - object tsWebsites: TTabSheet - Caption = 'Websites' - ClientHeight = 375 - ClientWidth = 579 - object vtOptionMangaSiteSelection: TVirtualStringTree - Left = 2 - Height = 336 - Top = 35 - Width = 573 - Align = alClient - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Bottom = 2 - BorderSpacing.Around = 2 - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = <> - Header.DefaultHeight = 17 - Header.MainColumn = -1 - IncrementalSearch = isVisibleOnly - Margin = 0 - ParentFont = False - TabOrder = 0 - TextMargin = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] - OnChange = vtOptionMangaSiteSelectionChange - OnFocusChanged = vtOptionMangaSiteSelectionFocusChanged - OnFreeNode = vtOptionMangaSiteSelectionFreeNode - OnGetText = vtOptionMangaSiteSelectionGetText - OnGetNodeDataSize = vtOptionMangaSiteSelectionGetNodeDataSize - OnInitNode = vtOptionMangaSiteSelectionInitNode - end - object pnlWebsitesTool: TPanel - Left = 2 - Height = 23 - Top = 6 - Width = 573 - Align = alTop - BorderSpacing.Top = 4 - BorderSpacing.Right = 2 - BorderSpacing.Bottom = 4 - BorderSpacing.Around = 2 - BevelOuter = bvNone - ClientHeight = 23 - ClientWidth = 573 - TabOrder = 1 - object edWebsitesSearch: TEdit - Left = 0 - Height = 23 - Top = 0 - Width = 184 - Align = alLeft - BorderSpacing.Right = 2 - OnChange = edWebsitesSearchChange - TabOrder = 0 - TextHint = 'Search website...' - end - object btWebsitesSearchClear: TSpeedButton - Left = 186 - Height = 23 - Top = 0 - Width = 22 - Align = alLeft - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btWebsitesSearchClearClick - end - object pnlWebsitesToolRight: TPanel - Left = 403 - Height = 23 - Top = 0 - Width = 170 - Align = alRight - AutoSize = True - BevelOuter = bvNone - ClientHeight = 23 - ClientWidth = 170 - TabOrder = 1 - object ToolBarWebsites: TToolBar - Left = 0 - Height = 22 - Top = 0 - Width = 170 - AutoSize = True - EdgeBorders = [] - Images = IconList - List = True - ParentFont = False - ShowCaptions = True - TabOrder = 0 - Transparent = True - object tbWebsitesExpandAll: TToolButton - Left = 1 - Top = 0 - AutoSize = True - Caption = 'Expand All' - ImageIndex = 17 - OnClick = tbWebsitesExpandAllClick - end - object tbWebsitesCollapseAll: TToolButton - Left = 82 - Top = 0 - AutoSize = True - Caption = 'Collapse All' - ImageIndex = 18 - OnClick = tbWebsitesCollapseAllClick - end - end - end - end - end - object tsMisc: TTabSheet - Caption = 'Misc' - ClientHeight = 375 - ClientWidth = 579 - object gbMisc: TGroupBox - Left = 12 - Height = 349 - Top = 12 - Width = 556 - Anchors = [akTop, akLeft, akRight, akBottom] - ClientHeight = 329 - ClientWidth = 552 - TabOrder = 0 - object cbOptionBatotoShowAllLang: TCheckBox - Left = 16 - Height = 19 - Top = 40 - Width = 167 - Caption = '[Batoto] Show All Language' - ParentFont = False - TabOrder = 1 - end - object cbOptionBatotoShowScanGroup: TCheckBox - Left = 16 - Height = 19 - Top = 16 - Width = 190 - Caption = '[Batoto] Show scan group name' - ParentFont = False - TabOrder = 0 - end - object cbOptionMangaFoxRemoveWatermarks: TCheckBox - Left = 16 - Height = 19 - Top = 88 - Width = 317 - Caption = '[Mangafox] Remove watermarks (Beware! Experimental!)' - ParentFont = False - TabOrder = 2 - Visible = False - end - end - end - end - object btOptionApply: TBitBtn - Left = 8 - Height = 41 - Top = 425 - Width = 128 - Anchors = [akLeft, akBottom] - Caption = 'Apply' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 - 0004000000170000002B011A004302440080025A00AB025D00C4025D00C4025A - 00AB02440080011A00430000002D0000001800000004FFFFFF00FFFFFF000000 - 0000031F00000553004D087402BF139D08E31DC40EF521D411FD21D411FD1DC4 - 0EF5139D08E3087402BF0553004D031F000000000000FFFFFF00FFFFFF000B83 - 00000B7F004D0E8804CD21C411F623D112FF22B611FF22D111FF22D111FF22D1 - 11FF22D111FF1EC20FF60D8803CD0B7F004D0B830000FFFFFF00FFFFFF000C85 - 001A0F8A03BF27C017F623C812FF22B211FFE6E6E6FF22B211FF22C811FF22C8 - 11FF22C811FF22C811FF1FBC0FF60D8902BF0C85001AFFFFFF00FFFFFF000D89 - 006C22A813E326C015FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE - 11FF22BE11FF22BE11FF22BE11FF17A109E30D89006CFFFFFF00FFFFFF000E8D - 00A73BBD2BF523AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 - 11FF22B411FF22B411FF22B411FF21AF11F50E8D00A7FFFFFF00FFFFFF000F92 - 00C450C83FFDA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 - E6FF22A311FF22AA11FF22AA11FF28AE17FD0F9200C4FFFFFF00FFFFFF001096 - 00C453CB42FD3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 - E2FFE6E6E6FF229E11FF22A111FF2CAA1BFD109600C4FFFFFF00FFFFFF00119A - 00A751CB40F547BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 - E2FFE3E3E3FFE7E7E7FF269E15FF34B023F5119A00A7FFFFFF00FFFFFF00129E - 006C3DBF2CE354CB43FF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB - 33FFFFFFFFFFA7E29EFF52C941FF36B925E3129E006CFFFFFF00FFFFFF0013A1 - 001A1AA707BF5CD74BF658CF47FF57CE46FF57CE46FF57CE46FF57CE46FF57CE - 46FF4AC139FF52C941FF57D245F619A606BF13A1001AFFFFFF00FFFFFF0013A2 - 000014A5004D21AF0ECD5FDA4EF663DA52FF5FD64EFF5FD64EFF5FD64EFF5FD6 - 4EFF62D951FF5DD94BF620AE0DCD14A5004D13A20000FFFFFF00FFFFFF0013A2 - 000014A5000014A8004D1BAD08BF42C82FE35FDC4EF56BE35AFD6BE359FD5FDB - 4EF541C72EE31BAD07BF14A8004D14A5000013A20000FFFFFF00FFFFFF0013A2 - 000014A5000014A8000015A9001A15AA006C15AA00A615AA00C415AA00C415AA - 00A615AA006C15A9001A14A8000014A5000013A20000FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btOptionApplyClick - TabOrder = 1 - end - end - object tsAbout: TTabSheet - Caption = 'About' - ChildSizing.LeftRightSpacing = 2 - ChildSizing.TopBottomSpacing = 2 - ClientHeight = 480 - ClientWidth = 606 - object btCheckLatestVersion: TBitBtn - Left = 25 - Height = 40 - Top = 429 - Width = 208 - Anchors = [akLeft, akBottom] - Caption = 'Check for latest version' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 00000000000600000010000000190000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A000000190000001500000010FFFFFF000000 - 00000000000B0000002011090133391E013E532A014345240240733A02A6984D - 02CC984D02CC984D02CC984D02CC984D02CC733A02A30000001FFFFFFF000000 - 000028160200763D0419A2580842C47E174EE4A01C54FCB9203F9C5105CCFDBC - 28FFFCB81DFFFCB81DFFFDC033FF9C5105CC9C51055C00000000FFFFFF00A65B - 0D00A3580B22AB62105FF8BA346DF6B01C6DF7B11E6BF8B52740A2570ACCF8B6 - 2AFFF6AC14FFF8BA35FFA2570ACCA2570A84A15609002A170400FFFFFF00A95E - 0F10AD641378F3B84390EFAB2A90E7A83691BF7A2078A85D0E33A85D0ECCF2B3 - 39FFF3B943FFEEA824FFF2B339FFAD6210BFA95E0F1AAA5F1000FFFFFF00AF64 - 144DCC8B33A6E8A83BB4E4A845B2AF641488AE631332AC611100AF6414CCF0BD - 5CFFAF6414CCECB148FFE8A83BFFCD8D34E3AF64146CAF641400FFFFFF00B66B - 198CE0A751CFE3A84ED6C98734BBB56A194AAF641400B66B1900B66B19CCB66B - 19CCB66B1994C98734DCE3A84EFFE0A851F5B66B19A7B66B1900FFFFFF00BE73 - 1FC1E7B466F1E5B061F1BE731FC1BB701D00C0752100C0752000BD721E99BD72 - 1E5CBA6F1C00BE731FCCE5B061FFE7B466FFBE731FCCBE731F00FFFFFF00C57A - 25CCE8B86FFFE6B46CFFC57A25CCC97E2700C67B265CC67B2699C1762100BE73 - 1F00C87D2700C57A25C1E6B46CF1E8B86FF1C57A25C1C57A2500FFFFFF00CD82 - 2AA7E8B66CF5E8B570FFDA9B48DCCD822A94CD822ACCCD822ACCCD822A00CF84 - 2C00CE832B4ADA9B47BBE8B570D6E8B66CCFCD822A8CCD822A00FFFFFF00D489 - 306CE4AB59E3EDBC76FFF1C67EFFD48930CCF7D38AFFD48930CCD88D3200D58A - 3132D4893088EEBF75B2EDBC76B4E4A958A6D489304DD4893000FFFFFF00DA8F - 341ADC9339BFF7CD85FFF2C27AFFF9D38AFFF7CD85FFDB9034CCDB903433E4A5 - 4F78F3C67991F4C57D90F8D28990DD953A78DA8F3410D98E3300FFFFFF00E196 - 3900E1963984E19639CCFCD88EFFF9CC82FFFCD58AFFE19639CCFCD48940FBD0 - 866BFACF856DFCD88D6DE49E435FE0953922DC913500DC913500FFFFFF00E69B - 3D5CE59A3DCCFFE094FFFED98DFFFED98DFFFFDC91FFE59A3DCCFEDA8E3FF8CB - 7B54F0B7604EE79F4242E59A3D19E1963900DC913500DC913500FFFFFF00E99E - 4099E99E40CCE99E40CCE99E40CCE99E40CCE99E40CCE99E4099E99E4020E99E - 4025E99E4019E89D3F06E59A3D00E1963900DC913500DC913500FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btCheckLatestVersionClick - TabOrder = 0 - end - object btAbortCheckLatestVersion: TSpeedButton - Left = 193 - Height = 40 - Top = 429 - Width = 40 - Anchors = [akLeft, akBottom] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - Visible = False - OnClick = btAbortCheckLatestVersionClick - end - object btVisitMyBlog: TBitBtn - Left = 249 - Height = 40 - Top = 429 - Width = 208 - Anchors = [akLeft, akBottom] - Caption = 'Visit my blog' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0A0A0A660C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C - 0C770C0C0C770C0C0C770C0C0C770A0A0A660000002C00000012000000090000 - 00161F1F1F74EBEBEBFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 - E6FFE6E6E6FFE6E6E6FFEBEBEBFF1F1F1F740000001600000009000000002A2A - 2A0036363671E8E8E8FFB4B4B4FFBDBDBDFFC5C5C5FFBDBDBDFFCECECEFFE0E0 - E0FFE0E0E0FFE0E0E0FFE8E8E8FF363636712A2A2A0000000000343434004545 - 45004545456FEAEAEAFFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFE2E2 - E2FFE2E2E2FFE2E2E2FFEAEAEAFF4545456F45454500343434004B4B4B004B4B - 4B004B4B4B6EECECECFF8E8E8EFFA5A5A5FFA5A5A5FF8E8E8EFFD3D3D3FFE5E5 - E5FFC2C2C2FFB9B9B9FFECECECFF4B4B4B6E4B4B4B004B4B4B00515151005151 - 51005151516DEEEEEEFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 - E8FFD5D5D5FFD5D5D5FFEEEEEEFF5151516D5151510051515100575757005757 - 57005757576CF0F0F0FFBFBFBFFFC7C7C7FFD0D0D0FFC7C7C7FFD8D8D8FFEAEA - EAFFBFBFBFFFC7C7C7FFF0F0F0FF5757576C57575700575757005D5D5D005D5D - 5D005D5D5D6BF2F2F2FFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFEDED - EDFFDBDBDBFFDBDBDBFFF2F2F2FF5D5D5D6B5D5D5D005D5D5D00626262006262 - 62006262626BF5F5F5FF919191FFC4C4C4FFAAAAAAFFAAAAAAFF919191FFF1F1 - F1FFBBBBBBFFCCCCCCFFF5F5F5FF6262626B6262620062626200676767006767 - 67006767676AF7F7F7FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 - F4FFF4F4F4FFF4F4F4FFF7F7F7FF6767676A67676700676767006C6C6C006C6C - 6C006C6C6C69F9F9F9FFAE7B26FFB6832EFFCC9944FFDCA954FFCB9843FFDCA9 - 54FFC5923DFFB17E29FFF9F9F9FF6C6C6C696C6C6C006C6C6C00717171007171 - 710071717168FBFBFBFFAE7B26FFEDE0CBFFE3CA9FFFEED4AAFFE5D8C3FFDCA9 - 54FFC5923DFFB17E29FFFBFBFBFF717171687171710071717100757575007575 - 750075757568FDFDFDFFAE7B26FFC18E39FFD9A651FFEBB863FFEBB863FFDCA9 - 54FFC5923DFFB17E29FFFDFDFDFF757575687575750075757500797979007979 - 790079797967FEFEFEFFAC7924FFB6832EFFC28F3AFFCB9843FFCB9843FFC390 - 3BFFB88530FFAE7B26FFFEFEFEFF7979796779797900797979007D7D7D007D7D - 7D007D7D7D67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFF7D7D7D677D7D7D007D7D7D007F7F7F007F7F - 7F008080804D8080806680808066808080668080806680808066808080668080 - 80668080806680808066808080668080804D7F7F7F007F7F7F00 - } - OnClick = btVisitMyBlogClick - TabOrder = 1 - end - object pcAbout: TPageControl - Left = 2 - Height = 416 - Top = 2 - Width = 602 - ActivePage = tsAboutText - Align = alTop - Anchors = [akTop, akLeft, akRight, akBottom] - TabIndex = 0 - TabOrder = 2 - object tsAboutText: TTabSheet - Caption = 'About FMD' - ClientHeight = 388 - ClientWidth = 594 - object rmAbout: TRichMemo - Left = 2 - Height = 382 - Top = 4 - Width = 588 - Align = alClient - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Around = 2 - Color = clWhite - Font.Style = [fsBold] - HideSelection = False - ParentFont = False - ReadOnly = True - ScrollBars = ssVertical - TabOrder = 0 - ZoomFactor = 1 - end - end - object tsChangelogText: TTabSheet - Caption = 'Changelog' - ClientHeight = 388 - ClientWidth = 594 - object mmChangelog: TMemo - Left = 2 - Height = 380 - Top = 4 - Width = 588 - Align = alClient - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Bottom = 2 - BorderSpacing.Around = 2 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Courier New' - Font.Pitch = fpFixed - Font.Quality = fqDraft - ParentFont = False - ReadOnly = True - ScrollBars = ssAutoBoth - TabOrder = 0 - end - end - end - end - end - object pnMainTop: TPanel - Left = 0 - Height = 8 - Top = 0 - Width = 819 - Align = alTop - TabOrder = 1 - Visible = False - end - object pcLeft: TPageControl - Left = 4 - Height = 506 - Top = 12 - Width = 195 - ActivePage = tsMangaList - Align = alLeft - BorderSpacing.Left = 4 - BorderSpacing.Top = 4 - BorderSpacing.Bottom = 4 - Images = IconList - TabIndex = 0 - TabOrder = 4 - object tsMangaList: TTabSheet - Caption = 'Manga List' - ChildSizing.LeftRightSpacing = 2 - ChildSizing.TopBottomSpacing = 3 - ClientHeight = 478 - ClientWidth = 187 - object lbMode: TLabel - Left = 3 - Height = 15 - Top = 68 - Width = 157 - Anchors = [akTop, akLeft, akRight] - Caption = 'Mode: Show all (0)' - Font.Style = [fsBold] - ParentColor = False - ParentFont = False - end - object vtMangaList: TVirtualStringTree - Left = 2 - Height = 383 - Top = 92 - Width = 181 - Align = alBottom - Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Right = 2 - BorderSpacing.Around = 2 - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = <> - Header.DefaultHeight = 17 - Header.MainColumn = -1 - HintMode = hmHint - IncrementalSearch = isAll - Margin = 0 - ParentShowHint = False - PopupMenu = pmMangaList - ShowHint = True - TabOrder = 0 - TextMargin = 3 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] - OnBeforeCellPaint = vtMangaListBeforeCellPaint - OnChange = vtMangaListChange - OnColumnDblClick = vtMangaListColumnDblClick - OnDragAllowed = vtMangaListDragAllowed - OnDragOver = vtMangaListDragOver - OnGetCursor = vtMangaListGetCursor - OnGetText = vtMangaListGetText - OnGetHint = vtMangaListGetHint - end - object edSearch: TEdit - Left = 3 - Height = 23 - Top = 36 - Width = 157 - Anchors = [akTop, akLeft, akRight] - OnChange = edSearchChange - OnKeyDown = edSearchKeyDown - TabOrder = 1 - TextHint = 'Search title...' - end - object cbSelectManga: TComboBox - Left = 3 - Height = 23 - Hint = 'For more manga sites, please go to Options->Manga sites' - Top = 8 - Width = 157 - Anchors = [akTop, akLeft, akRight] - ItemHeight = 15 - ItemIndex = 0 - Items.Strings = ( - '' - ) - OnChange = cbSelectMangaChange - ParentShowHint = False - ShowHint = True - Sorted = True - Style = csDropDownList - TabOrder = 2 - end - object btUpdateList: TSpeedButton - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 162 - Height = 23 - Hint = 'Update manga list' - Top = 8 - Width = 22 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 20000000000000040000640000006400000000000000000000000000001F0000 - 0084000000E4733100C5733100C5733100C5733100C5733100C5733100C57331 - 00C5582500A00000002200000000000000000000000000000000000000100101 - 01D1606060FFCA9764FFC69360FFC69360FFC69360FFC69360FFC69360FFCA97 - 64FF803A00BE0000002B0000001A000000110000000000000000010101000101 - 01C8646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFFBE8B58FFCA97 - 64FF9C5E28F7733100C5582500A0000000220000000000000000010101000101 - 01C3696969FFCF9C69FFBF8C59FFC69360FFC69360FFC69360FFBF8C59FFCF9C - 69FFAD713AFFCA9764FF803A00BE0000001A0000001A00000011010101000101 - 01BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFBF8C59FFD4A1 - 6EFFB0733BFFCA9764FF9C5E28F7733100C5582500A000000022010101000101 - 01BA737373FFD9A673FFBF8C59FFD09D6AFFD09D6AFFD09D6AFFBF8C59FFD9A6 - 73FFB4783EFFCF9C69FFAD713AFFCA9764FF853D00B623100000010101000101 - 01B5787878FFDEAB78FFBE8B58FFE1AE7BFFE1AE7BFFE1AE7BFFBE8B58FFDEAB - 78FFB87B40FFD4A16EFFB0733BFFCA9764FF8E4200B08E420000010101000101 - 01B27C7C7CFFE2AF7CFFBC8956FFBC8956FFBC8956FFBC8956FFBC8956FFE2AF - 7CFFBB7E42FFD9A673FFB4783EFFCF9C69FF934600AC93460000010101000101 - 01AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 - 84FFBD8043FFDEAB78FFB87B40FFD4A16EFF984900A898490000010101000101 - 01AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFBF8144FFE2AF7CFFBB7E42FFD9A673FF9C4C00A49C4C0000040404000404 - 048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFB - FAFFB4A484FFEAB784FFBD8043FFDEAB78FFA04F00A1A04F0000040404000404 - 04460404048AA16A33EEAA7744FFC28548FFC28548FFC28548FFC28548FFC285 - 48FFC28548FFCC9966FFBF8144FFE2AF7CFFA451009EA4510000040404000404 - 0400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEA - E5FFF3F3F1FFFBFBFAFFB4A484FFEAB784FFA753009CA7530000040404000404 - 040004040400040404460404048AA16A33EEAA7744FFC28548FFC28548FFC285 - 48FFC28548FFC28548FFC28548FFCC9966FFAA55009AAA550000040404000404 - 04000404040004040400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6 - CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFBFAFF55552B6655552B00000000000202 - 0200040404000404040004040400040404460404048AAA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550099AA550073AA550000 - } - OnClick = btUpdateListClick - end - object btRemoveFilter: TSpeedButton - Left = 162 - Height = 23 - Top = 63 - Width = 22 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000080000000000005A000000770000008000000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A000000110000000400005A00000077000000770000008000000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578040426000000 - 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 - 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 - A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 - A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C - 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 250027275200101090000000AA000000AA000000AA000000A700363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535004343430035355F00121291000000AA000000A700363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A43434300464646004646460035355F0023237700363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btRemoveFilterClick - end - object btSearchClear: TSpeedButton - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 162 - Height = 23 - Top = 36 - Width = 22 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btSearchClearClick - end - object btAbortUpdateList: TSpeedButton - Left = 136 - Height = 22 - Hint = 'Abort update list' - Top = 64 - Width = 23 - Flat = True - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 - 0004000000170000002B00001A430000448000005AAB00005DC400005DC40000 - 5AAB0000448000001A430000002D0000001800000004FFFFFF00FFFFFF000000 - 000000001F000000534D020274BF08089DE30E0EC4F51111D4FD1111D4FD0E0E - C4F508089DE3020274BF0000534D00001F0000000000FFFFFF00FFFFFF000000 - 830000007F4D040488CD1212C4F61212B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF0F0FC2F6030388CD00007F4D00008300FFFFFF00FFFFFF000000 - 851A03038ABF1818C1F61212B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF0F0FBCF6020289BF0000851AFFFFFF00FFFFFF000000 - 896C1616AAE21616C1FFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF0909A1E30000896CFFFFFF00FFFFFF000000 - 8DA72E2EC0F51212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1212AFF500008DA7FFFFFF00FFFFFF000000 - 92C44444CDFD2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818AFFD000092C4FFFFFF00FFFFFF000000 - 96C44949D1FD3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFD000096C4FFFFFF00FFFFFF000000 - 9AA74747D3F53737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2727B4F500009AA7FFFFFF00FFFFFF000000 - 9E6C3232C6E34949D1FFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4747CFFF2A2ABDE300009E6CFFFFFF00FFFFFF000000 - A11A0808A8BF5656E2F65151D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF5050D8FF4F4FDCF60707A7BF0000A11AFFFFFF00FFFFFF000000 - A2000000A54D1010B1CD5B5BE8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5F5FE7FF5858E4F60F0FB0CD0000A54D0000A200FFFFFF00FFFFFF000000 - A2000000A5000000A84D0909AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5B - E9F53636CFE30909AEBF0000A84D0000A5000000A200FFFFFF00FFFFFF000000 - A2000000A5000000A8000000A91A0000AA6C0000AAA60000AAC40000AAC40000 - AAA60000AA6C0000A91A0000A8000000A5000000A200FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btAbortUpdateListClick - ShowCaption = False - ShowHint = True - ParentShowHint = False - end - end - object tsDownloadFilter: TTabSheet - Caption = '>>' - ClientHeight = 478 - ClientWidth = 187 - ImageIndex = 4 - object tvDownloadFilter: TTreeView - Left = 0 - Height = 478 - Top = 0 - Width = 187 - Align = alClient - AutoExpand = True - DefaultItemHeight = 18 - Images = IconList - ReadOnly = True - TabOrder = 0 - OnSelectionChanged = tvDownloadFilterSelectionChanged - Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] - end - end - end - object sbMain: TStatusBar - Left = 0 - Height = 23 - Top = 522 - Width = 819 - Panels = < - item - Width = 195 - end - item - Width = 100 - end> - PopupMenu = pmSbMain - SimplePanel = False - end - object spMainSplitter: TSplitter - Left = 199 - Height = 514 - Top = 8 - Width = 2 - OnMoved = spMainSplitterMoved - end - object dlgSaveTo: TSelectDirectoryDialog - left = 80 - top = 408 - end - object pmDownload: TPopupMenu - Images = IconList - OnPopup = pmDownloadPopup - left = 616 - top = 360 - object miDownloadStop: TMenuItem - Caption = 'Stop' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 - 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 - 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF - FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 - C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 - C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 - C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 - C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A - C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B - C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B - D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 - DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 - E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 7 - OnClick = miDownloadStopClick - end - object miDownloadResume: TMenuItem - Caption = 'Resume' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 - 000000000001000000070000000E000000150000001A0000001A0000001A0000 - 001A0000001A0000001A000000160000000F0000000800000002000000000000 - 0000000000020000000E0000001C0000002A000000330000003300000033733A - 02A663320274000000330000002B0000001D0000000F00000003000000000000 - 0000000000000000000000000000000000000000000000000000281502009D52 - 06CC9D5206CC763E055C29160300000000000000000000000000B0651400A85D - 0E00A85D0E00553008007F470C00A85D0E007F470C00A85D0E00A65B0D00A358 - 0BCCFFB914FFA3580BCCA4590C5C7F470C002C19050000000000B4691700AA5F - 1000AA5F10CCAB601100AB601199AA5F10CCAB601199AA5F10CCAB601199AA5F - 10CCFFB810FFFFBB1BFFAA5F10CCAB60115CB1661600B96E1C00B76C1A00AF64 - 1400AF641400B3681700B16616CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B4 - 24FFF5AF18FFF5AB0EFFF7B92EFFB16616CCB267175CB96E1C00B96E1CCCBA6F - 1D00BA6F1D99B96E1CCCB96E1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA96 - 27F5E19E29FFE19E29FFE19E29FFEAB349FFB96E1CCCBA6F1D5CBF742000C378 - 2300C27722CCF8D084FFC27722CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D396 - 44FFD09341FFD09341FFD39644FFD89B49FFECBB6CFFC27722CCCB802999CA7F - 28CCCA7F28CCCA7F28CCCA7F28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE - 61FAEEB266FFEEB266FFEEB266FFF7CC80FFCA7F28CCC97E275CD2872ECCFBD9 - 8DFFD2872ECCD0852C00D2872ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C9 - 7DFFF4C175FFF2B96DFFFAD68AFFD2872ECCD1862D5CCA7F2800D88D3399D98E - 33CCD88D3399D78C3200D88D3399D98E33CCD88D3399D98E33CCD98E33CCD98E - 33CCFBD488FFFEDF93FFD98E33CCD88D335CD2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DA8F3400DC913600E095 - 38CCFFE498FFE09538CCDF94385CD98E3300D2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DD923700E59A3C00E59A - 3CCCE59A3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300E89D3F00E89D3F00E99E - 4099E99E405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 12 - OnClick = miDownloadResumeClick - end - object miDownloadDelete: TMenuItem - Caption = 'Delete' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 9 - object miDownloadDeleteTask: TMenuItem - Caption = 'Task only' - Enabled = False - OnClick = miDownloadDeleteTaskClick - end - object miDownloadDeleteTaskData: TMenuItem - Caption = 'Task + Data' - Enabled = False - OnClick = miDownloadDeleteTaskClick - end - end - object miDownloadDeleteCompleted: TMenuItem - Caption = 'Delete all completed tasks' - Enabled = False - OnClick = miDownloadDeleteCompletedClick - end - object MenuItem4: TMenuItem - Caption = '-' - end - object miDownloadMergeCompleted: TMenuItem - Caption = 'Merge completed tasks' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 - 000200000005000000090000000D0000001100000015000000180000001A0000 - 001A0000001A0000001A0000001A000000170000000F00000005000000000000 - 00040000000A0000001100000019000000220000002A00000030000000330000 - 003300000033733B03A6633303740000002E0000001D0000000A532E0700522D - 0600522D0600522D0600522D0600522D0600522D0600522D0600522D0600522D - 0600522D06009F5408CC9F5408CC783F065C2917030000000000A75C0E99A65B - 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B - 0DCCA65B0DCCA65B0DCCFFB508FFA65B0DCCA75C0E5C824A0E00AF6414CCF9C6 - 60FFFFBE23FFFFBD1FFFFFBC1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB7 - 0FFFFFB70DFFFFB60BFFFFB200FFFFB609FFAF6414CCAF641448B96E1BCCF6CB - 7FFFF8C051FFF9BD36FFF8B92CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B5 - 23FFF7B523FFF7B421FFF5AB0EFFF6B11BFFB96E1BCCB96E1B48C1762199C277 - 22CCC27722CCC27722CCD5973FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C - 26CFC27722CCC27722CCE6A93CFFC27722CCC176215CBB701C00C2772200C479 - 2400CC812A2BD38E38CEF0BF71FBE0A856FFDCA04CE4CC8129AACB80283FC97E - 270FC77C2600CC8129CCCC8129CCCB80285CC2772200BB701C00CD822A00D58A - 3000D58A307BEBB865E8F7C579FFF0C070EFD58A30AAD0852D13CC812900C97E - 2700D2872E00D4892F99D4892F5CCC812900C2772200BB701C00DD923600DD92 - 3600DD9236AAF8D081F6FCD185FFE7A951D9DC91363FDB903500CC812900C97E - 2700D2872E00D58A3000D58A3000CC812900C2772200BB701C00E4993B00E499 - 3B00E4993BC5FEDF92FDFFDF93FFE69E42CFE4993B0FE4993B00E4993B00D085 - 2D00D2872E00D58A3000D58A3000CC812900C2772200BB701C00E89D3E00E89D - 3E00E99E3F99E99E3FCCE99E3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C - 3200D2872E00D58A3000D58A3000CC812900C2772200BB701C00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 10 - OnClick = miDownloadMergeCompletedClick - end - object MenuItem1: TMenuItem - Caption = '-' - end - object miDownloadViewMangaInfo: TMenuItem - Caption = 'View manga info' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000030000 - 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B - 0B7A090909650505054200000032000000270000001300000003000000020000 - 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA - DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 - 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 - 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F - 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 - 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 - 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 - 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA - AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 - 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF - CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 - 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC - CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B - 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF - CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 - 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC - DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 - 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF - BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 - 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C - 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F - 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E - 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E - 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 - 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C - 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 - 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA - EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 - 50005252520053535300545454155555553E5555555555555563555555635555 - 55555555553E545454155353530052525200505050004F4F4F00 - } - ImageIndex = 0 - OnClick = miDownloadViewMangaInfoClick - end - object miDownloadOpenFolder: TMenuItem - Caption = 'Open Folder' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 4 - OnClick = miDownloadOpenFolderClick - end - object miDownloadOpenWith: TMenuItem - Caption = 'Open ...' - Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00000000000000000000000000100000001A0000001000000000000000000000 - 00000000000000000000000000000000000000000000000000001007000F220E - 00352A110048000000620000008F000000ED0000008F000000622A110048200D - 003A130800300703002A050200290502002906030023020100095322009A8550 - 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 - 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 - B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 - B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF - FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 - EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B - A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 - DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 - D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE - FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 - F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF - E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F - 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F - 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D - } - ImageIndex = 11 - OnClick = miDownloadOpenWithClick - end - end - object pmChapterList: TPopupMenu - left = 616 - top = 392 - object miChapterListCheckSelected: TMenuItem - Caption = 'Check selected' - OnClick = miChapterListCheckSelectedClick - end - object miChapterListUncheckSelected: TMenuItem - Caption = 'Uncheck selected' - OnClick = miChapterListUncheckSelectedClick - end - object miI1: TMenuItem - Caption = '-' - end - object miChapterListCheckAll: TMenuItem - Caption = 'Check all' - OnClick = miChapterListCheckAllClick - end - object miChapterListUncheckAll: TMenuItem - Caption = 'Uncheck all' - OnClick = miChapterListUncheckAllClick - end - object MenuItem6: TMenuItem - Caption = '-' - end - object miChapterListHighlight: TMenuItem - Caption = 'Highlight download chapters' - OnClick = miChapterListHighlightClick - end - end - object pmFavorites: TPopupMenu - Images = IconList - OnPopup = pmFavoritesPopup - left = 616 - top = 432 - object miFavoritesCheckNewChapter: TMenuItem - Caption = 'Check for new chapter' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 - 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 - 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB - E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 - 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 - E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 - 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 - D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 - 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 - BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 - 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 - 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 - 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F - 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 - 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D - 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 - 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F - 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 - 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 - 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 - 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 - 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 - 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 - 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 - 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 - 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 - 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 - 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 - E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 - 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550073AA550000AA550000 - } - ImageIndex = 21 - OnClick = miFavoritesCheckNewChapterClick - end - object miFavoritesStopCheckNewChapter: TMenuItem - Caption = 'Stop check for new chapter' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 - 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 - 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF - FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 - C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 - C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 - C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 - C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A - C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B - C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B - D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 - DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 - E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 7 - OnClick = miFavoritesStopCheckNewChapterClick - end - object miFavoritesViewInfos: TMenuItem - Caption = 'View manga info' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0001000000050000000A0000000E0000001120140D214936273544312233160C - 061E000000110000000F0000000B000000060000000200000000B87E51000503 - 02000000000200000004301C0F0C91745D62BBA087C4CFB59EE6CFB7A2E3BBA4 - 91BC9278645C321E0F0D000000040000000200000000000000007B55391F825F - 44305E423304421A0005A9896D7CDABC9DF4F1D3B5FFF4DBC1FFEBD5C0FDE0CC - BAF6D2BEAEF0B0978389734B2E0B8562470000000000000000007B573C2AAD8A - 69CAB6916D9D9E7D617DD7B696F1F0D0ADFFF0D4B6FFD5BCA4DFAB8F796E9778 - 6137AE958058B09784BB92725A760600000178523500000000001E000005B48E - 69A8DEAF7DFFDBB58CFDECC9A3FEEFD0AEFFD6BBA1E69C7D6643FFFADF004422 - 1100A281650086654C187F5A3F88775134307852350000000000B69372009D78 - 5961D8AC7BFDEBC295FFEDCAA5FFEED1B1FFC8AE95D99E7F674E805D410DC5B0 - 9E0077513400754F3100744D3019765033407A54370178523500845F4300805C - 4025C9A37BE2EDC69CFFEECDA9FFEFD2B3FFE8CFB6FFCAB29DE891725987693F - 20120600000178563D1697775D3D8A674C3F5D33140277513400754E31002400 - 0005B39272AAD9B895FBCFB193DCC1A58BAFAF927A799A7B63599A7B6356AF92 - 7A71C1A58BA4CEB194D3D9B897F6B99778B34720060776503300775134000000 - 000089664A4098785D4A7F5D441E3B1B0B046339190C8F6F5679C9B19CE3E7CF - B7FFEFD3B5FFEFCEABFFEDC89EFFCEA880E68763462B8A66480078523500653C - 1E0076503339744D301E754F32007751340096765D007E5A3E099E7F6745C7AD - 95D1EED1B2FFEECCA7FFEBC498FFDBAE7EFEA27D5D66C39F7C00000000007852 - 350077503324805C40888A6A511EB3947800371A0D00EFD6BC009B7D663AD5BA - A1DFF0D1B0FFEDCBA5FEDEB890FDDFB17EFFB8916BAA27060005000000007852 - 3500FFFFFF0094745C67B29A87BEB39A875E9B7D6638AD927B6AD6BDA6DAF0D4 - B8FFF1D1AEFFDBBA9AF3A5836783BA95709FB38F6ECC7E5A3F2A000000000000 - 0000815D4200663D1D07B096827CD3BFAFEEE1CDBCF7EBD5C1FDF4DBC2FFF1D4 - B6FFDCBEA0F5AE8E72814F280E0665493905866449347C573A21000000000000 - 000000000000704A2F00532A0E04A3877049C5AD99ABD5BDA8D8D6BCA4DDC7AA - 91B9A5856C59603C230776533900785235007852350078523500000000000000 - 000000000000000000000000000089542E004F2B15077C583E1D826046216341 - 290CFFFFFF000901000000000000000000000000000000000000 - } - ImageIndex = 0 - SubMenuImages = IconList - OnClick = miFavoritesViewInfosClick - end - object miFavoritesDownloadAll: TMenuItem - Caption = 'Download all' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 - } - ImageIndex = 1 - OnClick = miFavoritesDownloadAllClick - end - object MenuItem7: TMenuItem - Caption = '-' - end - object miFavoritesDelete: TMenuItem - Caption = 'Delete' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 9 - SubMenuImages = IconList - OnClick = miFavoritesDeleteClick - end - object miFavoritesChangeCurrentChapter: TMenuItem - Caption = 'Change "Current chapter"' - Visible = False - OnClick = miFavoritesChangeCurrentChapterClick - end - object miFavoritesChangeSaveTo: TMenuItem - Caption = 'Change "Save to"' - OnClick = miFavoritesChangeSaveToClick - end - object MenuItem3: TMenuItem - Caption = '-' - end - object miFavoritesOpenFolder: TMenuItem - Caption = 'Open Folder' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00478BE6FF5191E5FF5191E5FF5191E5FF5191E5FF5191E5FF5191E5FF5191 - E5FF5191E5FF5191E5FF5191E5FF478BE6FFFFFFFF00FFFFFF00FFFFFF002784 - F7FF429BFFFF469DFFFF469DFFFF469DFFFF469DFFFF469DFFFF469DFFFF469D - FFFF469DFFFF469DFFFF469DFFFF429BFFFF2784F7FFFFFFFF00FFFFFF002479 - FFFF387AFFFF377BFFFF377BFFFF377BFFFF377BFFFF377BFFFF377BFFFF377B - FFFF377BFFFF377BFFFF377BFFFF387AFFFF2479FFFFFFFFFF00FFFFFF002173 - FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87 - FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF2172FFFFFFFFFF00FFFFFF002279 - FFFF3D8DFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8C - FFFF3B8CFFFF3B8CFFFF3B8CFFFF3D8DFFFF2279FFFFFFFFFF00FFFFFF002482 - FFFF3E95FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94 - FFFF3D94FFFF3D94FFFF3D94FFFF3E95FFFF2482FFFFFFFFFF00FFFFFF002488 - FFFF3E9BFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9A - FFFF3D9AFFFF3D9AFFFF3D9AFFFF3E9BFFFF2488FFFFFFFFFF00FFFFFF002690 - FFFF40A2FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1 - FFFF3FA1FFFF3FA1FFFF3FA1FFFF40A2FFFF2690FFFFFFFFFF00FFFFFF002697 - FFFF40A9FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8 - FFFF3FA8FFFF3FA8FFFF3FA7FFFF40A8FFFF2697FFFFFFFFFF00FFFFFF0029A0 - FFFF42B0FFFF41AFFFFF41AFFFFF41AFFFFF41B0FFFF41B0FFFF41AFFFFF41B0 - FFFF41B0FFFF41B0FFFF41B1FFFF43B2FFFF26A2FFFFFFFFFF00FFFFFF002AA6 - FFFF42B6FFFF41B5FFFF41B5FFFF41B6FFFF41B7FFFF45BAFFFF3EBBFFFF3FBD - FFFF3FBEFFFF3FBEFFFF3FBEFFFF3BBEFFFF2BA8FFFFFFFFFF00FFFFFF002BAD - FFFF43BDFFFF43BCFFFF43BCFFFF42BCFFFF45C1FFFF2CB1FFFF73CDFFFF6DCC - FFFF6DCCFFFF6DCCFFFF6DCCFFFF61C9FFFFFFFFFF00FFFFFF00FFFFFF002BB4 - FFFF44C2FFFF43BFFFFF43BFFFFF43C1FFFF46C6FFFF1CB0FFFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002ABC - FFFF47D0FFFF47CEFFFF47CEFFFF49CFFFFF3FCBFFFF2BB8FFFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002EC9FFFF3BCCFFFF3BCCFFFF38CCFFFF45CCFFFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 4 - SubMenuImages = IconList - OnClick = miFavoritesOpenFolderClick - end - object miFavoritesOpenWith: TMenuItem - Caption = 'Open ...' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00000000000000000000000000100000001A0000001000000000000000000000 - 00000000000000000000000000000000000000000000000000001007000F220E - 00352A110048000000620000008F000000ED0000008F000000622A110048200D - 003A130800300703002A050200290502002906030023020100095322009A8550 - 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 - 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 - B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 - B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF - FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 - EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B - A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 - DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 - D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE - FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 - F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF - E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F - 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F - 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D - } - ImageIndex = 11 - OnClick = miFavoritesOpenWithClick - end - end - object pmMangaList: TPopupMenu - Images = IconList - OnPopup = pmMangaListPopup - left = 128 - top = 272 - object miMangaListViewInfos: TMenuItem - Caption = 'View manga infos' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 - 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 - 0000000000040000001B481F1546B24C3399E96443D4EE6644F5EE6644F5E964 - 43D4B24C3399471F15470000001F0000000600000000FFFFFF00FFFFFF007432 - 210077332200B34D3360EF6F4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1 - C9FFF4A18EFFEF6E4EEBB34D33603C1A110000000000FFFFFF00FFFFFF00E863 - 4100EE664460EF7659F9F7D4CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8 - E8FFF7E9E9FFF6D1CAFFEF7658F9EE664460E8634100FFFFFF00FFFFFF00E360 - 3E20E66A4AEBF3D3CDFFF0E5E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4 - E4FFEFE4E4FFEFE4E4FFEFCDC7FFE66A4AEBE3603E20FFFFFF00FFFFFF00D659 - 3787E59D8AFFEAE2E2FFE7DFDFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DF - DFFFE7DFDFFFE7DFDFFFE8E0E0FFE19784FFD6593787FFFFFF00FFFFFF00C550 - 2ED0EAD0C8FFE1DADAFFE0D9D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9 - D9FFE0D9D9FFE0D9D9FFE0D9D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00B748 - 26F5F4EEEDFFE7E5E5FFDAD6D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4 - D4FFD8D4D4FFD8D4D4FFD8D4D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00AD44 - 22F5F4EFEDFFEEEEEEFFEAEAEAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0 - D0FFD2D0D0FFD2D0D0FFD2D0D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00AB46 - 24D0EAD5CDFFF0F0F0FFF0F0F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1 - D1FFCECECEFFCECECEFFD2D1D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00B34F - 2D87D49D8AFFF5F5F5FFF3F3F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3 - F3FFF3F3F3FFF3F3F3FFF5F5F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00BF5C - 3A20C56747EBF2DFD9FFF8F8F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7 - F7FFF7F7F7FFF8F8F8FFF2DFD9FFC56747EBBF5C3A20FFFFFF00FFFFFF00C461 - 3F00CF6B4960D77F61F9F6E3DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB - FBFFFCFCFCFFF6E3DCFFD77F61F9CF6B4960C4613F00FFFFFF00FFFFFF00C461 - 3F00D16D4B00DF7A5860E38464EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4 - DDFFEFB7A4FFE38464EBDF7A5860D16D4B00C4613F00FFFFFF00FFFFFF00C461 - 3F00D16D4B00E17C5A00EA846220EC866487EC8664D0EC8664F5EC8664F5EC86 - 64D0EC866487EA846220E17C5A00D16D4B00C4613F00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 13 - SubMenuImages = IconList - OnClick = miMangaListViewInfosClick - end - object miMangaListDownloadAll: TMenuItem - Caption = 'Download all' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000818181007F7F - 7FFF7C7C7CFF7A7A7AFF787878FF777777FF757575FF767676FFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00868686FFBFBF - BFFFBDBDBDFFBCBCBCFFBBBBBBFFBBBBBBFFBABABAFF81818100FFFFFF00FFFF - FF002A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008A8A8AFFC0C0 - C0FFB0B0B0FFB0B0B0FFB0B0B0FFB1B1B1FFC0C0C0FF989898FFFFFFFF002A89 - 27FF3F993CFF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF008E8E8EFFC2C2 - C2FFD2D2D2FFD2D2D2FFD3D3D3FFD6D6D6FFCCCCCCFFD7D7D7FF2A8927FF419B - 3DFF61B45DFF419B3DFF2A8927FFFFFFFF00FFFFFF00FFFFFF00939393FFC4C4 - C4FFD2D2D2FFD3D3D3FFD6D6D6FFDDDDDDFFDDDDDDFF2A8927FF429C3FFF65B8 - 61FF65B861FF65B861FF429C3FFF2A8927FFFFFFFF00FFFFFF00979797FFC6C6 - C6FFD2D2D2FFD4D4D4FFDADADAFFE6E6E6FF2A8927FF449E41FF6ABB66FF69BB - 65FF69BB65FF69BB65FF6ABB66FF449E41FF2A8927FFFFFFFF009C9C9CFFC9C9 - C9FFC7C7C7FFCACACAFFD4D4D4FF2A8927FF5DAA5BFFA7D9A5FFA7D9A5FF8FCE - 8CFF6DBF69FF8FCE8CFFA7D9A5FFA7D9A5FF5DAA5BFF2A8927FFA0A0A0FFCBCB - CBFFC9C9C9FFCBCBCBFFD4D4D4FF2A8927FF2A8927FF2A8927FF2A8927FF5FAB - 5CFF72C36EFF5FAB5CFF2A8927FF2A8927FF2A8927FF2A8927FFA4A4A4FFCCCC - CCFFCBCBCBFFCCCCCCFFD1D1D1FFD7D7D7FFDCDCDCFFC9C9C9FFFFFFFF002A89 - 27FF76C772FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00A8A8A8FFCECE - CEFFB0B0B0FFB1B1B1FFB4B4B4FFB7B7B7FFCECECEFFB1B1B1FFFFFFFF002A89 - 27FF79CA75FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00ACACACFFD0D0 - D0FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFCACACAFFA7A7A7FFFFFFFF002A89 - 27FF7CCE79FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00AFAFAFFFD2D2 - D2FFB0B0B0FFB0B0B0FFB0B0B0FFB0B0B0FFCCCCCCFFABABABFFFFFFFF002A89 - 27FF7FD17BFF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2B2FFD2D2 - D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFCDCDCDFFADADADFFFFFFFF002A89 - 27FFB3E5B1FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFD4D4 - D4FFD3D3D3FFD2D2D2FFD2D2D2FFD1D1D1FFD0D0D0FFAEAEAEFFFFFFFF002A89 - 27FF2A8927FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFD4D4 - D4FFD4D4D4FFD4D4D4FFD2D2D2FFD2D2D2FFD1D1D1FFAEAEAEFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFB4B4 - B4FFB4B4B4FFB4B4B4FFB2B2B2FFB1B1B1FFAFAFAFFFAEAEAEFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ImageIndex = 1 - SubMenuImages = IconList - OnClick = miMangaListDownloadAllClick - end - object miMangaListAddToFavorites: TMenuItem - Caption = 'Add to Favorites' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF0058B754FF5AB856FFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF001DB31BFF04C302FF03C200FF1EB31EFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF0041BB42FF08BF09FF1EB720FF1EB720FF06BE08FF42BB44FFFFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF0020B828FF08C313FF20B929FF1EBD28FF1EBB27FF20BA29FF08C313FF21B8 - 29FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0045C1 - 50FF0AC71CFF20BD2EFF1FBF2DFF1FC02FFF1FC02EFF1FBE2EFF20BE2EFF0AC6 - 1BFF43BF4FFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0003BF - 1CFF23C238FF21C337FF21C338FF21C338FF21C338FF21C437FF21C137FF23BF - 38FF0CCA25FF23BE37FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0027BF - 42FF11C331FF24CA42FF22C63FFF21C53FFF21C63FFF21C63FFF21C63FFF21C4 - 3EFF22C33FFF0CCE2FFF43C45BFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF0022C547FF11C73BFF26CE4DFF24CB49FF23CA49FF23C949FF23CA49FF23CA - 4AFF24CB4AFF26C74BFF10D23CFF22C346FFFFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF0023C84FFF14CD45FF27D152FF25CD50FF25CD50FF25CF51FF28D5 - 55FF14D045FF00C032FF16C644FF11D644FF4DCD6EFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF0025CB59FF16CE4EFF29D45DFF27D15AFF29D75FFF0AC8 - 45FF79E19AFFFFFFFF006FDC90FF18C34CFF11CC4AFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF0027CF60FF19D357FF2AD865FF21D35DFF2BC8 - 60FFFFFFFF00FFFFFF00FFFFFF004DD27AFF11C24DFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0028D168FF19D660FF20D465FF35BD - 69FFFFFFFF00FFFFFF00FFFFFF0056C880FF14C557FFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0029D46DFF1AD464FF11CF - 5CFF9BCEAFFFFFFFFF0091CFAAFF1BC960FF19C75EFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0029D674FF15D5 - 69FF04E765FF00EC63FF07E767FF19DE6FFF1FD16BFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0075E7 - A8FF5CE79AFF60ED9FFF5FE89CFF5AE598FFFFFFFF00FFFFFF00 - } - ImageIndex = 2 - SubMenuImages = IconList - OnClick = miMangaListAddToFavoritesClick - end - object miI2: TMenuItem - Caption = '-' - end - object miHighlightNewManga: TMenuItem - Caption = 'Highlight new manga' - OnClick = miHighlightNewMangaClick - end - end - object TrayIcon: TTrayIcon - BalloonFlags = bfInfo - BalloonTimeout = 5000 - BalloonTitle = 'Free Manga Downloader' - Hint = 'Free Manga Downloader' - OnDblClick = TrayIconDblClick - left = 32 - top = 448 - end - object pmUpdate: TPopupMenu - ParentBidiMode = False - left = 128 - top = 144 - object mnUpdateList: TMenuItem - Caption = 'Update manga list' - OnClick = mnUpdateListClick - end - object mnUpdateDownFromServer: TMenuItem - Caption = 'Download manga list from server' - OnClick = mnUpdateDownFromServerClick - end - object MenuItem5: TMenuItem - Caption = '-' - end - object mnUpdate1Click: TMenuItem - Caption = 'Update all lists at once' - OnClick = mnUpdate1ClickClick - end - object mnDownload1Click: TMenuItem - Caption = 'Download all lists from server at once' - OnClick = mnDownload1ClickClick - end - end - object itAnimate: TIdleTimer - Enabled = False - Interval = 48 - OnTimer = itAnimateTimer - left = 752 - top = 72 - end - object itCheckFav: TIdleTimer - Enabled = False - Interval = 600000 - OnTimer = itCheckFavTimer - left = 760 - top = 256 - end - object itRefreshDLInfo: TIdleTimer - Enabled = False - OnTimer = itRefreshDLInfoTimer - OnStartTimer = itRefreshDLInfoStartTimer - OnStopTimer = itRefreshDLInfoStopTimer - left = 696 - top = 168 - end - object IconList: TImageList - left = 24 - top = 136 - Bitmap = { - 4C691600000010000000100000004F4F4F005050500052525200535353005454 - 54155555553E555555555555556355555563555555555555553E545454155353 - 530052525200505050004F4F4F004F4F4F0050505000525252075353533D7373 - 7378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEAEAFFC7C7C7D2727272785353 - 533D52525207505050004F4F4F004F4F4F00505050075151514D9F9F9FA1E6E6 - E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C75FFD6AFA2FFE3E4E4FF9D9D - 9DA15151514D505050074F4F4F004E4E4E004E4E4E3F9D9D9DA2DFDFDFFFCB79 - 5EFFDB7A58FFEE906EFFF49674FFF49573FFED8E6CFFDA7856FFCB795EFFDBDC - DCFF999999A24E4E4E3F4E4E4E004B4B4B176C6C6C7CDFE0E0FFC8755AFFE283 - 61FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F4DFFEA8866FFDF7E5CFFC875 - 5AFFD8D8D8FF6969697C4B4B4B1748484842BEBFBFD4C9A295FFD57452FFE281 - 5FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD6745FFD87250FFDF7C5AFFD16E - 4CFFC7A194FFB2B3B3D4484848424545455CDBDCDCFFC07C65FFDF805EFFCF69 - 47FFCF6947FFCA6442FFAE4826FFAC4523FFB04927FFAD4624FFAD4624FFC360 - 3EFFC07C65FFCBCCCCFF4545455C4242426CCFCFCFFFBC5B3BFFDD7D5BFFC962 - 40FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB14824FFB34925FFB34925FFBD55 - 32FFBC5B3BFFC3C3C3FF4242426C3E3E3E6ECCCCCCFFB95737FFD5714DFFBF50 - 2AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B26FFBD4E27FFBD4E27FFC154 - 2EFFB95737FFC0C0C0FF3E3E3E6E3A3A3A61D0CFCFFFB9745DFFCF643EFFC954 - 2AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC25028FFC9542AFFC9542AFFC554 - 2CFFB9745DFFC2C0C0FF3A3A3A6137373747ACAAAAD7C09789FFBF5631FFD85F - 33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB542AFFD55A2DFFD55A2DFFBC4F - 29FFBF9588FFA29F9FD7373737473434341953515186D4CECEFFB35F44FFC957 - 2FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD3592DFFE15F30FFC8532AFFB35F - 44FFD0C9C9FF5150508634343419303030002F2F2F48827E7EACDBD1D1FFAC57 - 3CFFB6461FFFD6592AFFE56230FFE56230FFD6592AFFB6461FFFAC573CFFDACF - CFFF817C7CAC2F2F2F483030300017171700212121092626265C807979AFE4D6 - D6FFC69689FFAD644EFF943312FF943312FFAD644EFFC69689FFE3D6D6FF7F79 - 79AF2626265C2121210917171700000000020000000A0707071C1313135D3D3A - 3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDADAFFB2A6A6DC3D3A3A931313 - 135D0707071D0000000A00000002000000030000001300000026000000320505 - 0542090909650B0B0B7A0B0B0B880B0B0B880B0B0B7A09090965050505420000 - 0032000000270000001300000003E99E3F00E99E3F00E99E3F00E99E3F00E99E - 3F00E99E3F00E99E3F33FFE39E40FED18540E99E3F33E99E3F00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00D2872E00D2872E00D2872E00D3892F00E297 - 3A00E2973A00E2973A6AFCDC9884F5BF7385E2973A6AE2973A00E2973A00D389 - 2F00D2872E00D2872E00D2872E00BF752000BF752000BF752000C2782200CB80 - 2900D98E3300D98E33ABF9D591D5EEB367D5D98E33AAD98E3300CB802900C278 - 2200BF752000BF752000BF752000BF752000BF752000BF752000C2782200C57A - 2400C87D2700CE832BCCF1CA83FFD89B4AFFCE832BCCC87D2700C57A2400C278 - 2200BF752000BF752000BF752000BF752000BF752000BF752000C177218FC278 - 22B8C27822B8C27822CCEEC26AFFDE9C2CFFC27822CCC27822B8C27822B8C177 - 218FBF752000BF752000BF752000BA6F1C00BA6F1C00BA6F1C00B96E1B5CC27B - 23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD3FFFF7C554FFC0781FD4B96E - 1B5CBA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F1C00B76C1A00AD62 - 125CB97117D4FECB4DFFFEB714FFFEB102FFFEC02CFFB86F15D4AD62125CB76C - 1A00BA6F1C00BA6F1C00BA6F1C00855F3600855F3600866037009E662800AC61 - 1100A3580B5CB0670ED4FFC53AFFFFBD20FFB0660DD4A3580B5CAC6111009E66 - 280086603700855F3600855F36004F4F4F004F4F4F0051515100555555006A58 - 44008E561D009B50055CA95F07D3A95F06D39B50055C8E561D006A5844005555 - 5500515151004F4F4F004F4F4F004F4F4F004F4F4F0051515100555555005555 - 5500555555006653410075502B1F75502B1F6653410055555500555555005555 - 5500515151004F4F4F004F4F4F004F4F4F004F4F4F005151510D5454545A5454 - 5467545454675454546754545467545454675454546754545467545454675454 - 545A5151510D4F4F4F004F4F4F004D4D4D004D4D4D004D4D4D5DC3C3C3DAD1D1 - D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3B3FFB9B3B3FFBFB3B3FFB5A9 - A9DA4D4D4D5D4D4D4D004D4D4D0033333300434343004343436EFAFAFAFFF8F8 - F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDDDDFFE2DDDDFFD7CCCCFFE8D9 - D9FF4343436E4343430033333300000000002B2B2B0038383873E9E9E9FFB0B0 - B0FF858585FF7E7F7FFF787979FF787777FF7E7777FF857777FF66FF66FFD7C8 - C8FF383838732B2B2B000000000000000009000000162A2A2A7AB3B3B3DFDBDB - DBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4C4FFC9C4C4FFC6BBBBFFA59A - 9ADF2A2A2A7A0000001600000009000000120000002C0D0D0D58121212851212 - 1285121212851212128512121285121212851212128512121285121212851212 - 12850D0D0D580000002C00000012000000000000000000000000000099000000 - 2B00000000000000000001016E000101DE000101E1000101E3000101E53C0101 - E5AB0101E53C0101E3000101E100000000000000000000000000000099000000 - 2B0001016B000101D9000101DC000101DE000101E1000101E33C0101E3AC8686 - FFFF0101E3AC0101E33C0101E1000000000000000000000000000101B4000101 - D2000101D5000101D9000101DC000101DE000101E13D0101E1AD8484FFFF7474 - FDFF8686FFFF0101E1AD0101E13D00000000010164000101CB000101CE000101 - D2000101D5000101D9000101DC000101DE3E0101DEAE8181FFFF7171FCFF7373 - FDFF7474FDFF8686FFFF0101DEAE0101C3000101C7000101CB000101CE000101 - D2000101D5000101D9000101DC3E0101DCAF7E7EFFFF6F6FFBFF7070FCFF7171 - FCFF8484FFFF0101DCAF0101DC3E0101C3000101C7000101CB000101CE000101 - D2000101D5000101D93E0101D9B17B7BFFFF6C6CF9FF6D6DFAFF6F6FFBFF8181 - FFFF0101D9B10101D93E0101DC000101C3000101C7000101CB000101CE000101 - D2000101D53F0101D5B27878FFFF6868F8FF6A6AF9FF6C6CF9FF7E7EFFFF0101 - D5B20101D63E0101D9000101DC000101C3000101C7000101CB000101CE000101 - D23F0101D2B37575FFFF6565F6FF6767F7FF6868F8FF7B7BFFFF0101D2B30101 - D33F0101D5000101D9000101DC000101C3000101C7000101CB000101CE400101 - CEB57171FFFF6262F4FF6464F5FF6565F6FF7878FFFF0101CEB5062C9B3F1080 - 350015A9000014A80000129D00000101C3000101C7000101CB400101CBB66E6E - FFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101CBB60101CC4015A9009915A9 - 00CC15A9009914A80000129D00000101C3000101C7410101C7B86C6CFFFF5C5C - F1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B8062996410F79330014A400CC75EE - 64FF14A400CC13A10000129D00000101C3410101C3B96969FFFF6262F8FF5F5F - F5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C0099129D00CC129D00CC66EB - 55FF129D00CC129D00CC129C00990101BFBB0101BFBB0101BFBB0101BFBB6262 - F8FF6C6CFFFF0101BFBB0101C042094B6100109500CC52E741FF52E741FF52E7 - 41FF52E741FF52E741FF109500CC01018F0001015F0001018C000000B6BF6969 - FFFF0000B6BF0000B84301016000074700000E8D00990E8C00CC0E8C00CC3DE2 - 2CFF0E8C00CC0E8C00CC0E8D0099000000030000000F000000190000A8C50000 - A8C500006D580000001600000013000000110000000F0000000C0C8200CE2BDF - 1AFF0C8200CD0000000300000001000000050000001E0000003200009CC90000 - 54630000002E0000002B00000026000000220000001D00000018054F00A10568 - 00CF0550009D0000000500000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 - A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 - A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 - AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 - A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B - E8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5F5FE7FF5858E4F60F0F - B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 - D9FF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FF5050D8FF4F4F - DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 - CAFF4242CAFF4242CAFF4242CAFF4242CAFF4242CAFF4242CAFF4242CAFF4747 - CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 - BFFF3737BFFF3232BAFF2727B0FF1C1CA6FF1616A0FF12129CFF12129CFF1616 - A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFFF8F8 - F8FFDEDEDEFFCECECEFFD1D1D1FFDCDCDCFFE8E8E8FFEEEEEEFFEEEEEEFF1111 - A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FFD0D0 - D0FFCCCCCCFFD1D1D1FFDCDCDCFFE8E8E8FFEEEEEEFFEEEEEEFFEEEEEEFF1111 - AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 - A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111 - B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 - BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111 - BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 - C8FF1111C8FF1111C8FF1111C8FF1111C8FF1111C8FF1111C8FF1111C8FF0F0F - BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 - C4F61212D1FF1111D1FF1111D1FF1111D1FF1111D1FF1111D1FF0F0FC2F60303 - 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 - 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 - 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 - 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 - 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF000087CA000087CA000087CA000087CA000087 - CA000087CA000087CA000088CC2E0088CC810088CC810088CC810088CC810088 - CC810088CC810088CC2E0087CA000087CA630087CA830087CA830087CA830087 - CA830087CA830087CA830087CA83FEFEFDFFF8F8F3FFF0F0E6FFE9E9DBFFFEC9 - 41FFF4B62EFF0087CA830087CA630085C785AEF3FFFFABF0FEFFABF0FEFFABF0 - FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0FEFFABF0FEFFABF0FEFFABF0 - FEFFABF0FEFFAEF3FFFF0085C7850083C488A8EDFDFFA2E7FBFFA2E7FBFFA2E7 - FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BCDEFF78BCDEFF78BCDEFF78BC - DEFF78BCDEFF78BCDEFF0083C4880081C18BA3E9FBFF9DE3F9FF9DE3F9FF9DE3 - F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9 - FAFFA3E9FAFFA6ECFBFF0081C18B007FBD8E9FE5F9FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF9FE5F9FF007FBD8E007CBA9299E0F6FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF99E0F6FF007CBA920079B69594DBF4FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF94DBF4FF0079B6950076B2998FD7F2FF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF8FD7F2FF0076B2990074AD9D8AD3F0FF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF8AD3F0FF0074AD9D0070A9A286CFEEFF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF86CFEEFF0070A9A200679AB086CFF0FF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF86CFF0FF00679AB000476A91005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD00476A9100000006000000160000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001600000006FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA - 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE - 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2 - 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5 - 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B - 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7 - 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197 - 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197 - 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1 - 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094 - 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC - 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094 - 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA - 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A - 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82 - 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000 - 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657 - 0048077200CC16A60AE8087601C406570029021E000000000000000000000000 - 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000 - 002D02330066025F00CC012B005500000029000000220000001A000000130000 - 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000 - 00170000001A000000190000001700000015000000110000000D0000000A0000 - 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E99E3F00E99E3F00E99E3F00EA9F - 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398 - 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B - 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398 - 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398 - 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297 - 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92 - 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91 - 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C - 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B - 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287 - 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287 - 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F - 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E - 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A - 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72 - 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73 - 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E - 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D - 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D - 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF - 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166 - 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3 - 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61 - 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A - 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60 - 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156 - 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000 - 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 - 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000 - 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 - 00320000003363320274974C02CC633202740000003300000033000000220000 - 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002B2BCF992B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002424CCCC8686E6FF8080 - E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8484E5FF2424 - CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C1CC9CC7878E4FF6767 - DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF7575E2FF1C1C - C9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001414C6CC6F6FE1FF5555 - DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3BD3FF3838D3FF5252DAFF1414 - C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001010B9CC6767DFFF4B4B - D8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1BC9FF1B1BC9FF3434D1FF1010 - B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000F0FA5CC5555DAFF2020 - CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF2E2ED0FF0F0F - A5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000D0D95CC3636D1FF1717 - C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF2727CDFF0D0D - 95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000B0B84CC2C2CCFFF1414 - C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1E1ECAFF0B0B - 84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000A0A75CC2525CDFF1212 - C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1919C8FF0A0A - 75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0009096ACC2727CDFF1C1C - C9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717C8FF1717C8FF1919C8FF0909 - 6ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF000000000306063EA0080860CC0808 - 60CC080860CC080860CC080860CC080860CC080860CC080860CC080860CC0606 - 3EA100000004FFFFFF00FFFFFF00FFFFFF0000000003000000110000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001300000004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A480 - 0000A984004AA98400A6A98400CCA98400A6A984004AA4800000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A37F - 004AB18E11D0E5C657F3EFD166FDE4C556F3B08D10D0A37F004AFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009D7B - 00A6D9BA4DF3CAAC42FFBFA137FFBA9C32FFC4A537F39D7B00A6FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009574 - 00CCCAAB3DFDA98916FFA58511FFA58511FFB0901DFD957400CCFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C6D - 00A6BD9A1FF3BC9712FFBB9611FFBB9612FFB38F10F38C6D00A6FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008467 - 004A8E7004D0C09910F3CEA511FDBF980EF38D6F03D0634D004AFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000941330061654F00AB695200CC654F00AB4032006500000013FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0005000000170000001A0000001A0000001A000000190000000AFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A8000000A9480000A9CC0000 - A9CC0000A9930000A7000000A20000009A0000009E000000A4000000A82B0000 - A97E0000A9B00000A966FFFFFF00FFFFFF000000A4000000A4CC7474FCFF6B6B - F4FE3636CDE50000A4CC0000A10000009A0000009E000000A3890606A8CF0000 - A4BD0000A54A0000A501FFFFFF00FFFFFF0000009F0000009F6600009ECC3737 - C9E56262EAFF5858E3FA1616AFD600009A330E0EA99F2828BEDD00009EB40000 - 9F1F0000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098330000 - 968A000096CC4141CDEE5151D9FD2727B7E32F2FBEE3000096B100009A180000 - 9F000000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098000000 - 900000008D3300008ECC3131BCF33333BCFA090997D400008E0000008F000000 - 8E0000008E000000A500FFFFFF00FFFFFF000000800000008000000080000000 - 8215000086B01A1AA8E72222B4F907078ED214149FE105058DD2000082000000 - 7C000000780000007800FFFFFF00FFFFFF00000078000000780000007B000000 - 7E911515A6E51D1DBEFD07078AD400007F6300007EAE0A0A94DC00007EB60000 - 7A000000780000007800FFFFFF00FFFFFF000000700000007000000075670D0D - 96DC1717CCFF0F0FA2E50000777500007E0000007A000000769104048AD50000 - 76860000730000007200FFFFFF00FFFFFF0000006C0000006D1F00006ECC1515 - D1FB1111C3F400006EB40000701100007000000078000000720000006E820000 - 6EB800006D4100006C00FFFFFF00FFFFFF00000066000000668C0A0A9FE51212 - DDFF030378D3000067330000510000000000000000000000380000006A000000 - 66840000668900006404FFFFFF00FFFFFF000000180000005FCC1111DBFE0C0C - AFEC00005F8B0000190000000000000000000000000000000000000000000000 - 320000005F7300004832FFFFFF00FFFFFF000000001C0000325E000059CC0000 - 57BC0000164200000020000000160000000F0000000D00000010000000150000 - 001B00001D3800002D4CFFFFFF00FFFFFF000000000E00000014000000190000 - 001900000016000000100000000B0000000800000007000000080000000B0000 - 000E0000001100000013FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00E89D3E00E89D3E00E99E3F99E99E3FCCE99E - 3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C3200D2872E00D58A3000D58A - 3000CC812900C2772200BB701C00E4993B00E4993B00E4993BC5FEDF92FDFFDF - 93FFE69E42CFE4993B0FE4993B00E4993B00D0852D00D2872E00D58A3000D58A - 3000CC812900C2772200BB701C00DD923600DD923600DD9236AAF8D081F6FCD1 - 85FFE7A951D9DC91363FDB903500CC812900C97E2700D2872E00D58A3000D58A - 3000CC812900C2772200BB701C00CD822A00D58A3000D58A307BEBB865E8F7C5 - 79FFF0C070EFD58A30AAD0852D13CC812900C97E2700D2872E00D4892F99D489 - 2F5CCC812900C2772200BB701C00C2772200C4792400CC812A2BD38E38CEF0BF - 71FBE0A856FFDCA04CE4CC8129AACB80283FC97E270FC77C2600CC8129CCCC81 - 29CCCB80285CC2772200BB701C00C1762199C27722CCC27722CCC27722CCD597 - 3FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C26CFC27722CCC27722CCE6A9 - 3CFFC27722CCC176215CBB701C00B96E1BCCF6CB7FFFF8C051FFF9BD36FFF8B9 - 2CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B523FFF7B523FFF7B421FFF5AB - 0EFFF6B11BFFB96E1BCCB96E1B48AF6414CCF9C660FFFFBE23FFFFBD1FFFFFBC - 1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB70FFFFFB70DFFFFB60BFFFFB2 - 00FFFFB609FFAF6414CCAF641448A75C0E99A65B0DCCA65B0DCCA65B0DCCA65B - 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCFFB5 - 08FFA65B0DCCA75C0E5C824A0E00532E0700522D0600522D0600522D0600522D - 0600522D0600522D0600522D0600522D0600522D0600522D06009F5408CC9F54 - 08CC783F065C291703000000000000000000000000040000000A000000110000 - 0019000000220000002A00000030000000330000003300000033733B03A66333 - 03740000002E0000001D0000000A000000000000000200000005000000090000 - 000D0000001100000015000000180000001A0000001A0000001A0000001A0000 - 001A000000170000000F00000005FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF007F7F55497F7F55577F7F55497F7F552E7F7F - 550E7F7F55007F7F550E7F7F552E7F7F55497F7F55577F7F55617F7F55667F7F - 55667F7F55667F7F55667F7F554DAA55009AF6F6F3EBE8E8DDD7C9C9B2B49C9C - 78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEFE2EBF6F6ECF9FBFBF4FFFCFC - F7FFFEFEFBFFFFFFFEFFAA55009AA854009BFEFEFDFFF8F8F3FFF1F1E7FFE9E9 - D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFFBFB - F6FFFDFDFAFFFFFFFEFFA854009BA652009DFEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBEADFFD2D2C1FFCDCDBCFFFBFB - F6FFFDFDFAFFFFFFFEFFA652009DA351009FFEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFFBFB - F6FFFDFDFAFFFFFFFEFFA351009FA04E00A2FEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1D3FF18B2D3FFF9F9F2FFD9D9 - C8FFD4D4C3FFFFFFFEFFA04E00A29C4C00A4FEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6DFFF49E0F1FFF9F9F2FFEAEA - D9FFEDEDDCFFFFFFFEFF9C4C00A4994A00A7FEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168BA9FF1EA8C0FFF9F9F2FFD9D9 - C8FFD4D4C3FFFFFFFEFF994A00A7954700AAFEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFEAEA - D9FFEDEDDCFFFFFFFEFF954700AA914500ADFEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBEADFFD2D2C1FFC4C4B3FFD9D9 - C8FFDCDCCBFFFFFFFEFF914500AD8D4200B0FEFEFDFFF8F8F3FFF0F0E6FFE9E9 - DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFFBFB - F6FFFDFDFAFFFFFFFEFF8D4200B0873E00B5FFFFFEFFF9F9F4FFF1F1E7FFE9E9 - DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6EAFFF8F8EFFFFBFBF4FFFCFC - F7FFFEFEFBFFFFFFFEFF873E00B5793400C0C5C5B7FFCECEC1FFDDDDD0FFE7E7 - D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5B4FFBEBEAEFFBBBBAAFFBBBB - AAFFBBBBAAFFBBBBAAFF793400C05322009A855027D78E623DDF67655AF7ACAA - 9AFD9B9B8AFFACAA9AFD67655AF78E623DDF855027D7793D12D0703104CC6F2F - 02CB6F2F02CB6F2F02CB5322009A1007000F220E00352A110048000000620000 - 008F000000ED0000008F000000622A110048200D003A130800300703002A0502 - 0029050200290603002302010009000000000000000000000000000000000000 - 00100000001A0000001000000000000000000000000000000000000000000000 - 0000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00D98E3300DA8F3400D98E3300D78C3200D98E - 3300DA8F3400D98E3300E89D3F00E89D3F00E99E4099E99E405CE59A3C00E095 - 3800D98E3300D2872E00CA7F2800D98E3300DA8F3400D98E3300D78C3200D98E - 3300DA8F3400D98E3300DD923700E59A3C00E59A3CCCE59A3CCCE59A3C5CE095 - 3800D98E3300D2872E00CA7F2800D98E3300DA8F3400D98E3300D78C3200D98E - 3300DA8F3400D98E3300DA8F3400DC913600E09538CCFFE498FFE09538CCDF94 - 385CD98E3300D2872E00CA7F2800D88D3399D98E33CCD88D3399D78C3200D88D - 3399D98E33CCD88D3399D98E33CCD98E33CCD98E33CCFBD488FFFEDF93FFD98E - 33CCD88D335CD2872E00CA7F2800D2872ECCFBD98DFFD2872ECCD0852C00D287 - 2ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C97DFFF4C175FFF2B96DFFFAD6 - 8AFFD2872ECCD1862D5CCA7F2800CB802999CA7F28CCCA7F28CCCA7F28CCCA7F - 28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE61FAEEB266FFEEB266FFEEB2 - 66FFF7CC80FFCA7F28CCC97E275CBF742000C3782300C27722CCF8D084FFC277 - 22CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D39644FFD09341FFD09341FFD396 - 44FFD89B49FFECBB6CFFC27722CCB96E1CCCBA6F1D00BA6F1D99B96E1CCCB96E - 1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA9627F5E19E29FFE19E29FFE19E - 29FFEAB349FFB96E1CCCBA6F1D5CB76C1A00AF641400AF641400B3681700B166 - 16CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B424FFF5AF18FFF5AB0EFFF7B9 - 2EFFB16616CCB267175CB96E1C00B4691700AA5F1000AA5F10CCAB601100AB60 - 1199AA5F10CCAB601199AA5F10CCAB601199AA5F10CCFFB810FFFFBB1BFFAA5F - 10CCAB60115CB1661600B96E1C00B0651400A85D0E00A85D0E00553008007F47 - 0C00A85D0E007F470C00A85D0E00A65B0D00A3580BCCFFB914FFA3580BCCA459 - 0C5C7F470C002C19050000000000000000000000000000000000000000000000 - 0000000000000000000000000000281502009D5206CC9D5206CC763E055C2916 - 03000000000000000000000000000000000000000000000000020000000E0000 - 001C0000002A000000330000003300000033733A02A663320274000000330000 - 002B0000001D0000000F00000003000000000000000000000001000000070000 - 000E000000150000001A0000001A0000001A0000001A0000001A0000001A0000 - 00160000000F0000000800000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C4613F00D16D4B00E17C5A00EA84 - 6220EC866487EC8664D0EC8664F5EC8664F5EC8664D0EC866487EA846220E17C - 5A00D16D4B00C4613F00FFFFFF00FFFFFF00C4613F00D16D4B00DF7A5860E384 - 64EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4DDFFEFB7A4FFE38464EBDF7A - 5860D16D4B00C4613F00FFFFFF00FFFFFF00C4613F00CF6B4960D77F61F9F6E3 - DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFCFCFCFFF6E3DCFFD77F - 61F9CF6B4960C4613F00FFFFFF00FFFFFF00BF5C3A20C56747EBF2DFD9FFF8F8 - F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7F7FFF7F7F7FFF8F8F8FFF2DF - D9FFC56747EBBF5C3A20FFFFFF00FFFFFF00B34F2D87D49D8AFFF5F5F5FFF3F3 - F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3F3FFF3F3F3FFF3F3F3FFF5F5 - F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00AB4624D0EAD5CDFFF0F0F0FFF0F0 - F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1D1FFCECECEFFCECECEFFD2D1 - D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00AD4422F5F4EFEDFFEEEEEEFFEAEA - EAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0D0FFD2D0D0FFD2D0D0FFD2D0 - D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00B74826F5F4EEEDFFE7E5E5FFDAD6 - D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4D4FFD8D4D4FFD8D4D4FFD8D4 - D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00C5502ED0EAD0C8FFE1DADAFFE0D9 - D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9D9FFE0D9D9FFE0D9D9FFE0D9 - D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00D6593787E59D8AFFEAE2E2FFE7DF - DFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DFDFFFE7DFDFFFE7DFDFFFE8E0 - E0FFE19784FFD6593787FFFFFF00FFFFFF00E3603E20E66A4AEBF3D3CDFFF0E5 - E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4E4FFEFE4E4FFEFE4E4FFEFCD - C7FFE66A4AEBE3603E20FFFFFF00FFFFFF00E8634100EE664460EF7659F9F7D4 - CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8E8FFF7E9E9FFF6D1CAFFEF76 - 58F9EE664460E8634100FFFFFF00FFFFFF007432210077332200B34D3360EF6F - 4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1C9FFF4A18EFFEF6E4EEBB34D - 33603C1A110000000000FFFFFF00FFFFFF0000000000000000040000001B481F - 1546B24C3399E96443D4EE6644F5EE6644F5E96443D4B24C3399471F15470000 - 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000 - 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000 - 00100000000300000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00B82F0300B92F030BBA30036ABA3003ACBA30 - 03BDBA3003BDBA3003BDBA3003BDBA3003BDBA3003BDBA3003BDBA3003BDBA30 - 03ACBA30036AB92F030BB82F0300B82F0300B82F036BD25B33D3F1916EF7F698 - 76FFF69876FFF69876FFF69876FFF59876FFF59775FFF59775FFF59674FFF08E - 6BF7D15931D3B82F036BB82F0300B52D0300B52D03ADF08F6CF7E7815FFFE781 - 5FFFE7815FFFE7815FFFD87250FFD87250FFE7815FFFE7815FFFE7815FFFE781 - 5FFFEB8865F7B52D03ADB52D0300B22C0300B22C03BFEF906EFFDF7957FFDF79 - 57FFDF7957FFD26C4AFFFFFFFFFFFFFFFFFFD26C4AFFDF7957FFDF7957FFDF79 - 57FFE88765FFB22C03BFB22C0300AF2A0300AF2A03BFE88A68FFD6704EFFD670 - 4EFFD6704EFFCC6644FFFFFFFFFFFFFFFFFFCC6644FFD6704EFFD6704EFFD670 - 4EFFE07E5CFFAF2A03BFAF2A0300AB270200AB2702C0E28260FFCF6947FFCF69 - 47FFCF6947FFCA6442FFAE4826FFAC4523FFB04A27FFAD4624FFAD4624FFB04A - 27FFC25F3CFFAB2702C0AB270200A7250200A72502C1DD7D5BFFCC6644FFC962 - 40FFBD5431FFB24926FFCCCCCCFFCDCDCDFFB14825FFB44A26FFB44A26FFB44A - 26FFBD5532FFA72502C1A7250200A3230200A32302C1DA7957FFC85F3BFFC052 - 2CFFBE502AFFB94E28FFCDCDCDFFD6D6D6FFB94E28FFBE502AFFBE502AFFBE50 - 2AFFC35631FFA32302C1A32302009F2002009F2002C2D86F4BFFCB5930FFCB58 - 2FFFCB582FFFC3542CFFD6D6D6FFE2E2E2FFC3542CFFCB582FFFCB582FFFCB58 - 2FFFCC5B32FF9F2002C29F2002009B1E02009B1E02C3DE6C42FFD86035FFD860 - 35FFD86035FFCD5930FFE2E2E2FFEDEDEDFFCD5930FFD86035FFD86035FFD860 - 35FFD86035FF9B1E02C39B1E0200961B0200961B02C4E86E42FFE5673AFFE567 - 3AFFE5673AFFD75F34FFEDEDEDFFEEEEEEFFD75F34FFE5673AFFE5673AFFE567 - 3AFFE5673AFF961B02C4961B020090170200901702B3E7693CF8F16F3EFFF16F - 3EFFF16F3EFFF16F3EFFCF5A31FFCF5A31FFF16F3EFFF16F3EFFF16F3EFFF16F - 3EFFE66538F8901702B39017020021040100800E0170AB331ADBEC693CF8FA74 - 42FFFA7442FFFA7442FFFA7442FFFA7442FFFA7442FFFA7442FFFA7442FFEC69 - 3BF8AB3218DB800E01702104010000000012120100335A040082710500BA7205 - 00CB720500CB720500CB720500CB720500CB720500CB720500CB720500CB7105 - 00BA5A040082120100330000001200000009000000160000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A00000016000000090404040004040400040404460404048AAA55 - 0099AA550099AA550099AA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550073AA550000AA55000004040400040404000404048ABCBCABFFC1C1 - B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8E2FFEFEFECFFF7F7F4FFFCFC - FCFF55552B6655552B0055552B000101010001010100010101AC555555FFCC99 - 66FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFAA55009AAA550000AA5500000101010001010100010101AE808080FFEAB7 - 84FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 - 84FFA854009BA8540000A85400000101010001010100010101B07E7E7EFFE4B1 - 7EFFD7A674FFCF9F6FFFCC9D6DFFCC9D6DFFCF9F6EFFD7A573FFDBA875FFE4B1 - 7EFFA653009DA6530000A65300000101010001010100010101B27C7C7CFFE2AF - 7CFFD09F6EFFFFEEDDFFFFEEDDFFFFEEDDFFFFEEDDFFD7AF87FFD7A472FFE2AF - 7CFFA451009FA4510000A45100000101010001010100010101B5797979FFDFAC - 79FFD19F6DFFD4AC84FFCFA982FFD2B293FFFBEAD9FFDEBF9FFFD3A16EFFDFAC - 79FFA14F00A1A14F0000A14F00000101010001010100010101B8757575FFDBA8 - 75FFD29F6CFFD19E6CFFC99968FFD2B291FFF7E6D5FFD5B18EFFD09E6BFFDBA8 - 75FF9E4D00A39E4D00009E4D00000101010001010100010101BB727272FFD8A5 - 72FFCF9C69FFCB9967FFCCA681FFF1E0CEFFE4CCB4FFC59564FFCF9C69FFD8A5 - 72FF9B4B00A59B4B00009B4B00000101010001010100010101BE6E6E6EFFD4A1 - 6EFFCB9865FFC39261FFEDDCCBFFEDDCCBFFBC8D5EFFCA9765FFCB9865FFD4A1 - 6EFF984900A898490000984900000101010001010100010101C16B6B6BFFD19E - 6BFFC89562FFC2915FFFB38658FFB38658FFC2915FFFC89562FFC89562FFD19E - 6BFF954700AB95470000954700000101010001010100010101C5676767FFCD9A - 67FFC4915EFFBA8A5AFFF8E7D6FFEAD9C8FFBA8A5AFFC4915EFFC4915EFFCD9A - 67FF914500AD91450000914500000101010001010100010101C9646464FFCA97 - 64FFC18E5BFFB78757FFE7D6C5FFDFCEBDFFB78757FFC18E5BFFC18E5BFFCA97 - 64FF8D4200B08D4200006A3200000000000001010100010101CE626262FFC895 - 62FFBF8C59FFBC8A58FFB58554FFB58554FFBC8A58FFBF8C59FFBF8C59FFC895 - 62FF893F00B467300000000000000000000900000016000000DB606060FFCA97 - 64FFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFCA97 - 64FF7C3600BE0000001600000009000000120000002C00000087000000E7702E - 00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E - 00C7552300A20000002C00000012FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 - A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 - A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 - AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 - A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B - E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F - B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 - D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F - DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 - CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747 - CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 - BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616 - A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E - B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111 - A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 - ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111 - AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 - B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111 - B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 - BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111 - BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 - C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F - BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 - C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303 - 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 - 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 - 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 - 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 - 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00E7815F00E983610FED876590ED8765E8ED87 - 65FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED87 - 65E8ED876590E983610FE7815F00E47F5D00E47F5D90EEA992FFFCEFEAFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCEF - EAFFEEA992FFE47F5D90E47F5D00D9745200D97452E8F9ECE8FFFBFBFBFFFBFB - FBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB - FBFFF8EBE7FFD97452E8D9745200CC674500CC6745FFFBFBFBFFF7F7F7FFF7F7 - F7FFF7F7F7FFF7F7F7FFCC6745FFCC6745FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7 - F7FFFAFAFAFFCC6745FFCC674500BE5B3900BE5B39FFF9F9F9FFF3F3F3FFF3F3 - F3FFF3F3F3FFF3F3F3FFBE5B39FFBE5B39FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3 - F3FFF6F6F6FFBE5B39FFBE5B3900B4502E00B4502EFFF6F6F6FFF0F0F0FFF0F0 - F0FFF0F0F0FFEBEBEBFFB4502EFFB4502EFFD2D1D1FFCECECEFFCECECEFFD2D1 - D1FFDEDDDDFFB4502EFFB4502E00AC482600AC4826FFF4F4F4FFEEEEEEFFAC48 - 26FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFD2D0 - D0FFD7D6D6FFAC4826FFAC482600AB442200AB4422FFF3F3F3FFE7E5E5FFEE66 - 44FFEE6644FFEE6644FFAB4422FFAB4422FFEE6644FFEE6644FFEE6644FFD8D4 - D4FFDBD8D8FFAB4422FFAB442200AF452300AF4523FFEDEAEAFFE1DADAFFF1ED - EDFFF1EDEDFFF1EDEDFFAF4523FFAF4523FFF1EDEDFFF1EDEDFFF1EDEDFFE0D9 - D9FFE1DBDBFFAF4523FFAF452300B8492700B84927FFEBE4E4FFE7DFDFFFE7DF - DFFFE7DFDFFFE7DFDFFFB84927FFB84927FFE7DFDFFFE7DFDFFFE7DFDFFFE7DF - DFFFE7DFDFFFB84927FFB8492700C54F2D00C54F2DFFF1E7E7FFEFE4E4FFEFE4 - E4FFEFE4E4FFEFE4E4FFEE6644FFEE6644FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4 - E4FFEFE4E4FFC54F2DFFC54F2D00D2563400D25634E8F3D7D3FFF7E8E8FFF7E8 - E8FFF7E8E8FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8 - E8FFF2D5D1FFD25634E8D256340037170F00DF5E3C90E98D76FFF9DAD6FFFCEC - ECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFF9DA - D6FFE98C75FFDF5E3C9037170F000000001226100B36BF51359FE86341E9E963 - 41FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE863 - 41E9BF51359F26100B360000001200000000000000160000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001600000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00E7815F00E983610FED876590ED8765E8ED87 - 65FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED87 - 65E8ED876590E983610FE7815F00E47F5D00E47F5D90EEA992FFFCEFEAFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCEF - EAFFEEA992FFE47F5D90E47F5D00D9745200D97452E8F9ECE8FFFBFBFBFFFBFB - FBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB - FBFFF8EBE7FFD97452E8D9745200CC674500CC6745FFFBFBFBFFF7F7F7FFF7F7 - F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7 - F7FFFAFAFAFFCC6745FFCC674500BE5B3900BE5B39FFF9F9F9FFF3F3F3FFF3F3 - F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3 - F3FFF6F6F6FFBE5B39FFBE5B3900B4502E00B4502EFFF6F6F6FFF0F0F0FFF0F0 - F0FFF0F0F0FFEBEBEBFFE0E0E0FFD7D6D6FFD2D1D1FFCECECEFFCECECEFFD2D1 - D1FFDEDDDDFFB4502EFFB4502E00AC482600AC4826FFF4F4F4FFEEEEEEFFAC48 - 26FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFD2D0 - D0FFD7D6D6FFAC4826FFAC482600AB442200AB4422FFF3F3F3FFE7E5E5FFEE66 - 44FFEE6644FFEE6644FFEE6644FFEE6644FFEE6644FFEE6644FFEE6644FFD8D4 - D4FFDBD8D8FFAB4422FFAB442200AF452300AF4523FFEDEAEAFFE1DADAFFF1ED - EDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFE0D9 - D9FFE1DBDBFFAF4523FFAF452300B8492700B84927FFEBE4E4FFE7DFDFFFE7DF - DFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DF - DFFFE7DFDFFFB84927FFB8492700C54F2D00C54F2DFFF1E7E7FFEFE4E4FFEFE4 - E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4 - E4FFEFE4E4FFC54F2DFFC54F2D00D2563400D25634E8F3D7D3FFF7E8E8FFF7E8 - E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8 - E8FFF2D5D1FFD25634E8D256340037170F00DF5E3C90E98D76FFF9DAD6FFFCEC - ECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFF9DA - D6FFE98C75FFDF5E3C9037170F000000001226100B36BF51359FE86341E9E963 - 41FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE863 - 41E9BF51359F26100B360000001200000000000000160000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A00000016000000001975BA001975BA001770B7900B56A4C60142 - 96CC003F94CC002A80CC00166BCC021C70CB072D7DC80D4390C51259A3C1176C - B290186FB500186FB500FFFFFF0098763200987632009876325BF5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29876 - 325B9876320098763200FFFFFF0097753100977531009775315CF5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29775 - 315C9775310097753100FFFFFF0096743000967430009674305DF5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29674 - 305D9674300096743000FFFFFF0095732F0095732F0095732F5FF8F0E9DCCCCB - C3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391AFF9C7C6BDCEF7EEE5DC9573 - 2F5F95732F0095732F00FFFFFF0094722E0094722E0094722E3094722E60F1E3 - D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3BBCEF1E2D3D394722E609472 - 2E3094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D319371 - 2D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3D5D293712D6293712D319472 - 2E0094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D00916F - 2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F2B63916F2B3293712D009472 - 2E0094722E0094722E00FFFFFF008C6A26008C6A26008D6B27008E6C2800906E - 2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E2A65906E2A338E6C28008D6B - 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27008E6C28348E6C - 2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3D5D28E6C28678E6C28348D6B - 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27358D6B2769F1E3 - D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFF1E2D3D38D6B27698D6B - 27358C6A26008C6A2600FFFFFF008B6925008B6925008B69256AF8F0E9DCEAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F7EEE5DC8B69 - 256A8B6925008B692500FFFFFF00674E1B00896723008967236CF5EAE0D276AF - CBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F65B95B0F66BA4BFF6F3E7DBD28967 - 236C89672300674E1B00FFFFFF0000000000654B180085631F70F5EAE0D299BB - C7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E386A8B5E391B3BFE3F3E7DBD28563 - 1F70654B180000000000FFFFFF000000000A000000177F5D1977F5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD27F5D - 1977000000170000000AFFFFFF00000000000000002D002C6CA600277CCC0016 - 6BCC001569CC000955CC000041CC000546CC001155CC001F68CC002E7CCC002B - 69A60000002E00000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001FA4 - 000020A9004A20A900A620A900CC20A900A620A9004A1FA40000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001FA3 - 004A2FB111D072E557F380EF66FD71E456F32EB010D01FA3004AFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001D9D - 00A667D94DF35BCA42FF50BF37FF4BBA32FF51C437F31D9D00A6FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C95 - 00CC57CA3DFD32A916FF2CA511FF2CA511FF39B01DFD1C9500CCFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001A8C - 00A63DBD1FF331BC12FF30BB11FF32BB12FF2FB310F31A8C00A6FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001984 - 004A1D8E04D032C010F334CE11FD2FBF0EF31C8D03D01363004AFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 00090C410061136500AB146900CC136500AB0C40006500000013FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0005000000170000001A0000001A0000001A000000190000000AFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF000404040004040400040404460404048AAA55 - 0099AA550099AA550099AA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550073AA550000AA55000004040400040404000404048ABCBCABFFC1C1 - B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8E2FFEFEFECFFF7F7F4FFFCFC - FCFF55552B6655552B0055552B000101010001010100010101AC555555FFCC99 - 66FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFAA55009AAA550000AA5500000101010001010100010101AE808080FFEAB7 - 84FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 - 84FFA854009BA8540000A85400000101010001010100010101B07E7E7EFFE4B1 - 7EFFBB8855FFBB8855FFBB8855FFBB8855FFBB8855FFBB8855FFBB8855FFE4B1 - 7EFFA653009DA6530000A65300000101010001010100010101B27C7C7CFFE2AF - 7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B07DFFE3B07DFFBC8956FFE2AF - 7CFFA451009FA4510000A45100000101010001010100010101B5797979FFDFAC - 79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A370FFD6A370FFBE8B58FFDFAC - 79FFA14F00A1A14F0000A14F00000101010001010100010101B8757575FFDBA8 - 75FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F6CFF84A791FF3FA6A6FF8CAF - 99FF9E4D00A39E4D00009E4D00000101010001010100010101BB727272FFD8A5 - 72FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D6CFF50ACA8FFA2E5E7FF53AF - ABFF94500AA89B4B00009B4B00000101010001010100010101BE6E6E6EFFD4A1 - 6EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F83FF6BC5C6FFABF5FCFF6CC7 - C8FF636E48C38F4F0D008F4F0D000101010001010100010101C16B6B6BFFD19E - 6BFFBF8C59FFC89562FFC89562FFC59563FF4FA39FFF90E3E9FF555555FF88E1 - E9FF2E8E8ADE01ABC40401ABC4000101010001010100010101C5676767FFCD9A - 67FFBF8C59FFC4915EFFC4915EFF919778FF56B6BAFF7CE4F1FF000000FF68D8 - E7FF38A6ABEE01A8C04301A7BF000101010001010100010101C9646464FFCA97 - 64FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1D7FF46D3D7FF75B4B5FF40D0 - D2FF40C3C6F901A4BC9801A2BA010000000001010100010101CE626262FFC895 - 62FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9E0FF33D5DDFF000000FF33D5 - DDFF34D5DDFF0DACC1C7019EB63A0000000900000016000000DB606060FFCA97 - 64FFC5925FFFC5925FFF4C9590FF32C6D1FF29DBE9FF28DAE9FF79EDF5FF28DA - E9FF28DAE9FF1CC7D8EA0198AF9F000000000000002C00000087000000E7702E - 00C7702E00C7702E00C72C6662E8157882F2157882F2157882F2157882F21578 - 82F2107B87EA008398D00066779A - } - end - object itSaveDownloadedList: TIdleTimer - Interval = 300000 - OnTimer = itSaveDownloadedListTimer - left = 752 - top = 120 - end - object IconDL: TImageList - left = 24 - top = 184 - Bitmap = { - 4C69080000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002B2BCF992B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002424CCCC8686E6FF8080 - E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8484E5FF2424 - CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C1CC9CC7878E4FF6767 - DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF7575E2FF1C1C - C9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001414C6CC6F6FE1FF5555 - DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3BD3FF3838D3FF5252DAFF1414 - C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001010B9CC6767DFFF4B4B - D8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1BC9FF1B1BC9FF3434D1FF1010 - B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000F0FA5CC5555DAFF2020 - CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF2E2ED0FF0F0F - A5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000D0D95CC3636D1FF1717 - C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF2727CDFF0D0D - 95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000B0B84CC2C2CCFFF1414 - C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1E1ECAFF0B0B - 84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000A0A75CC2525CDFF1212 - C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1919C8FF0A0A - 75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0009096ACC2727CDFF1C1C - C9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717C8FF1717C8FF1919C8FF0909 - 6ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF000000000306063EA0080860CC0808 - 60CC080860CC080860CC080860CC080860CC080860CC080860CC080860CC0606 - 3EA100000004FFFFFF00FFFFFF00FFFFFF0000000003000000110000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001300000004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF001975BA001975BA001770B7900B56A4C60142 - 96CC003F94CC002A80CC00166BCC021C70CB072D7DC80D4390C51259A3C1176C - B290186FB500186FB500FFFFFF0098763200987632009876325BF5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29876 - 325B9876320098763200FFFFFF0097753100977531009775315CF5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29775 - 315C9775310097753100FFFFFF0096743000967430009674305DF5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29674 - 305D9674300096743000FFFFFF0095732F0095732F0095732F5FF8F0E9DCCCCB - C3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391AFF9C7C6BDCEF7EEE5DC9573 - 2F5F95732F0095732F00FFFFFF0094722E0094722E0094722E3094722E60F1E3 - D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3BBCEF1E2D3D394722E609472 - 2E3094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D319371 - 2D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3D5D293712D6293712D319472 - 2E0094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D00916F - 2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F2B63916F2B3293712D009472 - 2E0094722E0094722E00FFFFFF008C6A26008C6A26008D6B27008E6C2800906E - 2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E2A65906E2A338E6C28008D6B - 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27008E6C28348E6C - 2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3D5D28E6C28678E6C28348D6B - 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27358D6B2769F1E3 - D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFF1E2D3D38D6B27698D6B - 27358C6A26008C6A2600FFFFFF008B6925008B6925008B69256AF8F0E9DCEAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F7EEE5DC8B69 - 256A8B6925008B692500FFFFFF00674E1B00896723008967236CF5EAE0D276AF - CBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F65B95B0F66BA4BFF6F3E7DBD28967 - 236C89672300674E1B00FFFFFF0000000000654B180085631F70F5EAE0D299BB - C7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E386A8B5E391B3BFE3F3E7DBD28563 - 1F70654B180000000000FFFFFF000000000A000000177F5D1977F5EAE0D2EAD4 - BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD27F5D - 1977000000170000000AFFFFFF00000000130000002D002C6CA600277CCC0016 - 6BCC001569CC000955CC000041CC000546CC001155CC001F68CC002E7CCC002B - 69A60000002E00000013FFFFFF00FFFFFF0043DBE50043DBE50043DBE50044DC - E69944DCE6CC44DCE69944DCE60044DCE6CC44DCE60041D8E1003FD6DF003FD6 - DF003FD6DF00FFFFFF00FFFFFF00FFFFFF0041D9E20041D9E20041D9E20041D9 - E2CC97E6FCFF41D9E2CC40D7E00041D9E20040D7E0003FD6DF003FD6DF003FD6 - DF003FD6DF00FFFFFF00FFFFFF00FFFFFF003FD6DF003FD6DF003FD6DF003FD6 - DF993ED5DECC3ED5DECC3ED5DECC3ED5DE993ED5DE003ED5DECC3ED5DE003ED5 - DE003ED5DE00FFFFFF00FFFFFF00FFFFFF003AD1D9003AD1D9003AD1D9003AD1 - D9003AD1D9003AD1D9CC92E7FBFF3AD1D9CC38CFD7003AD1D90039D0D80039D0 - D80039D0D800FFFFFF00FFFFFF00FFFFFF0035CBD20035CBD20035CBD20036CC - D39936CCD4CC36CCD4CC36CCD4CC36CCD4CC36CCD4CC36CCD39935CBD20035CB - D20035CBD200FFFFFF00FFFFFF00FFFFFF0032C7CE0032C7CE0032C7CE0032C7 - CECC8BE6F8FF34C8CFCE8AE5F7FF32C7CECC88E6F7FF32C7CECC32C7CE0032C7 - CE0032C7CE00FFFFFF00FFFFFF00FFFFFF001DB0B4002BBFC5002BBFC5002CC0 - C6993CCAD1D73CCAD1D734C5CCD22DC1C7CC2DC1C7CC2CC0C6992BBFC5002BBF - C5001DB0B400FFFFFF00FFFFFF00FFFFFF001DB0B40021B4B90028BCC10028BC - C1CC83E4F4FF48CFD6E381E3F3FF2CBFC4CF80E4F3FF28BCC1CC28BCC10021B4 - B9001DB0B400FFFFFF00FFFFFF00FFFFFF001DB0B4001EB1B50020B3B70022B5 - BACC6FDEEAF856D6DDEF4CD0D7E842C9D0E142C9D0E122B5B9991EB1B5001EB1 - B5001DB0B400FFFFFF00FFFFFF00FFFFFF001DAFB3991DB0B4CC1DB0B4CC1DB0 - B4CC77E4F0FF63DFE6FA69E3EBFF5CD9E0F574E4EFFF1DB0B4CC1DB0B4CC1DB0 - B4CC1DAFB399FFFFFF00FFFFFF00FFFFFF0019ABAE5C18AAADCC82E4F4FF76E3 - EFFF6FE3EDFF64DEE6FF5AD4DCFF50CAD2FF52C8D1FF57C8D3FF62CDDAFF18AA - ADCC19ABAE5CFFFFFF00FFFFFF00FFFFFF0018AAAD0014A5A85C13A4A7CC7AE1 - EFFF4FCDD7FF44C2CCFF43C1CBFF43C1CBFF43C1CBFF5BCBD9FF13A4A7CC14A5 - A85C18AAAD00FFFFFF00FFFFFF00FFFFFF0018AAAD0013A4A70010A0A25C0F9F - A1CC4ECEE6FF2DC3DBFF2DC3DBFF2DC3DBFF47CDE4FF0F9FA1CC10A0A25C13A4 - A70018AAAD00FFFFFF00FFFFFF00FFFFFF000000000000000000085051000C9C - 9D5C0B9B9CCC32CDF2FF13C7EFFF2ECDF2FF0B9B9CCC0C9C9D5C085051000000 - 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 - 001906696A6E089796CC1ECCF9FF089796CC06696A6E0000001A000000110000 - 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 - 00320000003304605F74059392CC04605F740000003300000033000000220000 - 000800000000FFFFFF00FFFFFF00FFFFFF00E99E3F00E99E3F00E99E3F00EA9F - 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398 - 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B - 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398 - 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398 - 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297 - 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92 - 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91 - 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C - 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B - 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287 - 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287 - 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F - 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E - 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A - 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72 - 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73 - 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E - 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D - 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D - 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF - 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166 - 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3 - 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61 - 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A - 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60 - 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156 - 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000 - 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 - 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000 - 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 - 00320000003363320274974C02CC633202740000003300000033000000220000 - 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA - 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE - 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2 - 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B - 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5 - 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B - 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7 - 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197 - 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197 - 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1 - 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094 - 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC - 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094 - 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA - 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A - 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82 - 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000 - 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657 - 0048077200CC16A60AE8087601C406570029021E000000000000000000000000 - 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000 - 002D02330066025F00CC012B005500000029000000220000001A000000130000 - 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000 - 00170000001A000000190000001700000015000000110000000D0000000A0000 - 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF000462BF000462BF040462C0680462C08B0462 - C08B0462C08B004080CC004080CC004080CC004080CC0462C08B0462C08B0462 - C08B0462C0680462BF040462BF000461BE000461BE232A7CCCA589BCEFFF88BB - EEFF88BBEEFF35689BFF35689BFF35689BFF35689BFF88BBEEFF88BBEEFF89BC - EFFF2A7CCCA50461BE230461BE00045FBB000460BC474D94D9C489BCEFFF88BB - EEFF88BBEEFF4174A7FF4174A7FF4174A7FF3E71A4FF88BBEEFF88BBEEFF89BC - EFFF4D94D9C40460BC47045FBB00045FB900045FB96D6BA6DFE080B3E6FF80B3 - E6FF80B3E6FF4E81B4FF4E81B4FF4E81B4FF487BAEFF80B3E6FF80B3E6FF80B3 - E6FF6BA6DFE0045FB96D045FB900035DB600035DB695A7DBFEFDAADDFFFFAADD - FFFFAADDFFFF77AADDFF77AADDFF77AADDFF6699CCFFAADDFFFFAADDFFFFAADD - FFFFA7DBFEFD035DB695035DB600035BB300035BB3989FD2F9FF95C8F3FF95C8 - F3FF95C8F3FF5588BBFF4477AAFF5588BBFF4073A6FF95C8F3FF95C8F3FF95C8 - F3FF9FD2F9FF035BB398035BB300035AB000035AB09B9BCEF6FF91C4F0FF91C4 - F0FF91C4F0FF4477AAFF91C4F0FF4477AAFF91C4F0FF91C4F0FF91C4F0FF91C4 - F0FF9BCEF6FF035AB09B035AB0000358AC000358AC9F96C9F2FF8CBFECFF8CBF - ECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBF - ECFF96C9F2FF0358AC9F0358AC000356A8000356A8A38FC2EEFFBBBBBBFF87BA - E9FFBBBBBBFF87BAE9FFBBBBBBFF999999FFBBBBBBFFBBBBBBFFBBBBBBFFBBBB - BBFF999999FF02417F940356A800040404000404048ABBBBBBFF777777FFBBBB - BBFF777777FFBBBBBBFF777777FF82B5E5FF999999FFEEEEEEFFDDDDDDFFCCCC - CCFFBBBBBBFF00000066000000000251A0000251A0AB777777FF7DB0E1FF7777 - 77FF7DB0E1FF777777FF999999FF777777FF777777FF777777FF777777FF7777 - 77FF999999FF023D789B0251A00001132600014A94B87BAEE0FF7AADDFFF7AAD - DFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AAD - DFFF7BAEE0FF014A94B8011326000000001E0133669E014487C5014487C50144 - 87C5014487C5014487C5014487C5014487C5014487C5014487C5014487C50144 - 87C5014487C50133669E0000001E0000000F000000170000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A000000170000000FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0001B0C90001B2CB0001B3CC0001B3 - CC1601B3CC5B01B3CC8B01B3CCA401B3CCA401B3CC8B01B3CC5B01B3CC1601B3 - CC0001B2CB0001B0C900FFFFFF00FFFFFF0001B0C90001B2CB0001B3CC4011B9 - D0A361D8E5D097EEF7EEA5F5FDFBA5F4FDFB95EDF7EE5DD6E5D011B9D0A301B3 - CC4001B2CB0001B0C900FFFFFF00FFFFFF0001B0C90001B2CB411EBDD2B297EE - F6F08DEDFCFF81EAFBFF81EAFBFF81EAFBFF81EAFBFF8BEDFCFF8FEBF6F01BBC - D2B201B2CB4101B0C900FFFFFF00FFFFFF0001B0C91611B6CDA593EBF5F07DE8 - F8FF79E6F7FF79E6F7FF757575FF757575FF79E6F7FF79E6F7FF7CE7F8FF84E7 - F3F00EB5CDA501B0C916FFFFFF00FFFFFF0001AEC75D5AD2E1D27DE6F5FF70E2 - F3FF70E2F3FF70E2F3FF666666FF666666FF70E2F3FF70E2F3FF70E2F3FF78E5 - F5FF49CDDFD201AEC75DFFFFFF00FFFFFF0001ABC49082E4EFEF69DFF0FF69DF - F0FF69DFF0FF63DCEBFF303030FF181818FF48CCD4FF45C9D2FF45C9D2FF48CC - D4FF58D3DCEF01ABC490FFFFFF00FFFFFF0001A8C1AB85E7F3FC66DDEEFF61DB - EAFF4DD4DAFF42CFD0FF000000FF000000FF40CFCFFF40CFCFFF40CFCFFF40CF - CFFF4FD4D4FC01A8C1ABFFFFFF00FFFFFF0001A5BEAD80E5F1FC56D9E5FF3FD2 - D6FF3CD1D4FF3CD1D4FF000000FF000000FF3CD1D4FF3CD1D4FF3CD1D4FF3CD1 - D4FF44D2D6FC01A5BEADFFFFFF00FFFFFF0001A2BA945DD8E2F038D4D9FF37D4 - D9FF37D4D9FF37D4D9FF81EAEDFF81EAEDFF37D4D9FF37D4D9FF37D4D9FF37D4 - D9FF32CDD5F001A2BA94FFFFFF00FFFFFF00019FB7622DBFCED739D8DFFF32D6 - DEFF32D6DEFF32D6DEFF000000FF000000FF32D6DEFF32D6DEFF32D6DEFF32D6 - DEFF19BAC9D7019FB762FFFFFF00FFFFFF00019CB41807A1B7B136D3DEF22ED9 - E4FF2DD9E3FF2DD9E3FF000000FF000000FF2DD9E3FF2DD9E3FF2DD9E3FF26CF - DCF205A0B7B1019CB418FFFFFF00FFFFFF00019AB2000097AE47089EB4C127D0 - DFF329DBE8FF28DBE8FF7AEDF4FF7AEDF4FF28DBE8FF28DBE8FF22CFDEF3069E - B4C10097AE47019AB200FFFFFF00FFFFFF000000000000252A000067784A038E - A5BA12AFC2E01ECCDDF423D9E9FD23D9E9FD1ECCDDF412AFC2E0038EA5BA0067 - 784A00252A0000000000FFFFFF00FFFFFF0000000004000000170000002B0023 - 2943005D6D7F007C91AB008096C4008096C4007C91AB005D6D7F002329430000 - 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 - A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 - A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 - AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 - A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B - E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F - B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 - D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F - DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 - CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747 - CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 - BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616 - A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E - B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111 - A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 - ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111 - AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 - B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111 - B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 - BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111 - BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 - C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F - BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 - C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303 - 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 - 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 - 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 - 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 - 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 - 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 00170000000C00000002FFFFFF00 - } - end - object IconMed: TImageList - Height = 48 - Width = 48 - left = 27 - top = 268 - Bitmap = { - 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004D6BEC004D6BEC004D6BEC004D6B - EC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6B - EC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC104D6BEC4E4D6BEC8C4D6B - ECBA4D6BECD84D6BECEE4D6BECF94D6BECF94D6BECEE4D6BECD84D6BECBA4D6B - EC8C4D6BEC4F4D6BEC104D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6B - EC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6B - EC004D6BEC004D6BEC00FFFFFF00FFFFFF004D6AEB004D6AEB004D6AEB004D6A - EB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6A - EB004D6AEB004D6AEB074D6AEB5B4D6AEBB74D6AEBFC4D6AEBFF4D6AEBFF4D6A - EBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6A - EBFF4D6AEBFF4D6AEBFC4D6AEBB84D6AEB5B4D6AEB074D6AEB004D6AEB004D6A - EB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6A - EB004D6AEB004D6AEB00FFFFFF00FFFFFF004C6AEA004C6AEA004C6AEA004C6A - EA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6A - EA094C6AEA724C6AEAE44C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6A - EAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6A - EAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAE54C6AEA724C6AEA094C6A - EA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6A - EA004C6AEA004C6AEA00FFFFFF00FFFFFF004C69E9004C69E9004C69E9004C69 - E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69E9494C69 - E9DC4C69E9FF4C69E9FF4C69E9FF4C69E9FF4C69E9FF617BECFF8095F1FF92A4 - F4FF9DAEF6FFA6B5F7FFAAB8F8FFAAB8F8FFA6B5F7FF9DAEF6FF92A4F4FF8095 - F1FF617BECFF4C69E9FF4C69E9FF4C69E9FF4C69E9FF4C69E9FF4C69E9DC4C69 - E9494C69E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69 - E9004C69E9004C69E900FFFFFF00FFFFFF004B68E8004B68E8004B68E8004B68 - E8004B68E8004B68E8004B68E8004B68E8004B68E8084B68E8964B68E8FF4B68 - E8FF4B68E8FF4B68E8FF5872EAFF8498F1FFA7B5F7FFACB9F8FFACB9F8FFACB9 - F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9 - F8FFACB9F8FFA8B6F7FF8498F1FF5873EAFF4B68E8FF4B68E8FF4B68E8FF4B68 - E8FF4B68E8964B68E8084B68E8004B68E8004B68E8004B68E8004B68E8004B68 - E8004B68E8004B68E800FFFFFF00FFFFFF004A67E7004A67E7004A67E7004A67 - E7004A67E7004A67E7004A67E7004A67E7174A67E7CB4A67E7FF4A67E7FF4A67 - E7FF536FE9FF8C9FF3FFAAB9F8FFAAB9F8FFAAB9F8FF9FAFF7FF8DA0F5FF7C92 - F4FF748CF3FF6F88F3FF6C85F3FF6C85F3FF6F88F3FF748CF3FF7C92F4FF8DA0 - F5FF9FAFF7FFAAB9F8FFAAB9F8FFAAB9F8FF8C9FF3FF536FE9FF4A67E7FF4A67 - E7FF4A67E7FF4A67E7CD4A67E7174A67E7004A67E7004A67E7004A67E7004A67 - E7004A67E7004A67E700FFFFFF00FFFFFF004966E5004966E5004966E5004966 - E5004966E5004966E5004966E5224966E5DB4966E5FF4966E5FF4966E5FF7188 - ECFFA4B3F6FFAAB8F7FFAAB8F7FF91A3F5FF7189F2FF647EF1FF647EF1FF647E - F1FF647EF1FF647EF1FF647EF1FF647EF1FF647EF1FF647EF1FF647EF1FF647E - F1FF647EF1FF7189F2FF91A3F5FFAAB8F7FFAAB8F7FFA4B3F6FF7188ECFF4966 - E5FF4966E5FF4966E5FF4966E5DB4966E5214966E5004966E5004966E5004966 - E5004966E5004966E500FFFFFF00FFFFFF004965E4004965E4004965E4004965 - E4004965E4004965E41C4965E4DF4965E4FF4965E4FF4965E4FF8599F0FFA9B8 - F7FFA9B8F7FF94A6F5FF6C84F1FF637DF0FF637DF0FF637DF0FF637DF0FF637D - F0FF637DF0FF637DF0FF637DF0FF637DF0FF637DF0FF637DF0FF637DF0FF637D - F0FF637DF0FF637DF0FF637DF0FF6C84F1FF94A6F5FFA9B8F7FFA9B8F7FF8699 - F0FF4965E4FF4965E4FF4965E4FF4965E4DF4965E41C4965E4004965E4004965 - E4004965E4004965E400FFFFFF00FFFFFF004864E2004864E2004864E2004864 - E2004864E20A4864E2CE4864E2FF4864E2FF4864E2FF8B9DF0FFA9B7F6FFA9B7 - F6FF7B91F2FF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627C - EFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627C - EFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF7B91F2FFA7B6F6FFA9B7 - F6FF8B9DF0FF4864E2FF4864E2FF4864E2FF4864E2CE4864E20A4864E2004864 - E2004864E2004864E200FFFFFF00FFFFFF004763E1004763E1004763E1004763 - E1004763E19A4763E1FF4763E1FF4763E1FF8B9DF0FFA8B6F6FFA3B2F5FF758B - F0FF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF617A - EEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF758BF0FFA3B2 - F5FFA8B6F6FF8B9DF0FF4763E1FF4763E1FF4763E1FF4763E19B4763E1004763 - E1004763E1004763E100FFFFFF00FFFFFF004662DF004662DF004662DF004662 - DF4A4662DFFF4662DFFF4662DFFF8497EDFFA7B5F5FFA0B0F4FF7188EFFF5F79 - EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F79 - EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF7188 - EFFFA0B0F4FFA7B5F5FF8497EDFF4662DFFF4662DFFF4662DFFF4662DF4A4662 - DF004662DF004662DF00FFFFFF00FFFFFF004561DE004561DE004561DE084561 - DEDC4561DEFF4561DEFF6F85E8FFA7B5F5FFA5B3F4FF7188EEFF5E78ECFF5E78 - ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E78 - ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78 - ECFF7188EEFFA5B3F4FFA7B5F5FF7086E8FF4561DEFF4561DEFF4561DEDD4561 - DE084561DE004561DE00FFFFFF00FFFFFF004460DC004460DC004460DC714460 - DCFF4460DCFF4E68DEFFA0AFF2FFA6B4F4FF768CEEFF5C76EBFF5C76EBFF5C76 - EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C76 - EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76 - EBFF5C76EBFF768CEEFFA6B4F4FFA0AFF2FF4E69DEFF4460DCFF4460DCFF4460 - DC714460DC004460DC00FFFFFF00FFFFFF00435EDA00435EDA07435EDAE5435E - DAFF435EDAFF8598EBFFA5B3F3FF8EA0F1FF5B74EAFF5B74EAFF5B74EAFF5B74 - EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B74 - EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74 - EAFF5B74EAFF5B74EAFF8EA0F1FFA5B3F3FF8598EBFF435EDAFF435EDAFF435E - DAE6435EDA08435EDA00FFFFFF00FFFFFF00425DD800425DD85B425DD8FF425D - D8FF4F68DBFFA4B2F2FFA4B2F2FF627BE9FF5973E8FF5973E8FF5973E8FF5973 - E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5973 - E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973 - E8FF5973E8FF5973E8FF627BE9FFA4B2F2FFA4B2F2FF4F69DCFF425DD8FF425D - D8FF425DD85B425DD800FFFFFF00FFFFFF00415CD700415CD7B8415CD7FF415C - D7FF7B8EE7FFA3B1F2FF889AEEFF5871E7FF5871E7FF5871E7FF5871E7FF5871 - E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5871 - E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871 - E7FF5871E7FF5871E7FF5871E7FF889AEEFFA3B1F2FF7B8EE7FF415CD7FF415C - D7FF415CD7B8415CD700FFFFFF00FFFFFF00405BD510405BD5FC405BD5FF405B - D5FF9EACF0FFA2B0F1FF657CE8FF5670E6FF5670E6FF5670E6FF5670E6FF5670 - E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FFFAFB - FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FAFEFF5670 - E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670 - E6FF5670E6FF5670E6FF5670E6FF657CE8FFA2B0F1FF9EACF0FF405BD5FF405B - D5FF405BD5FC405BD510FFFFFF00FFFFFF003F59D34F3F59D3FF3F59D3FF556C - DAFFA1AFF1FF94A5EFFF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546E - E5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FFE8EC - FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8ECFCFF546E - E5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546E - E5FF546EE5FF546EE5FF546EE5FF546EE5FF94A5EFFFA1AFF1FF556CDAFF3F59 - D3FF3F59D3FF3F59D34FFFFFFF00FFFFFF003E58D18B3E58D1FF3E58D1FF7487 - E2FFA1AEF0FF8092EAFF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536C - E3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FFD8DE - F9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8DEF9FF536C - E3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536C - E3FF536CE3FF536CE3FF536CE3FF536CE3FF8092EAFFA1AEF0FF7487E2FF3E58 - D1FF3E58D1FF3E58D18CFFFFFF00FFFFFF003D57CFB43D57CFFF3D57CFFF8294 - E6FF9FAEEFFF6D83E7FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516B - E2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FFC6CF - F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6CFF6FF516B - E2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516B - E2FF516BE2FF516BE2FF516BE2FF516BE2FF6D83E7FF9FAEEFFF8395E6FF3D57 - CFFF3D57CFFF3D57CFB5FFFFFF00FFFFFF003C55CDD93C55CDFF3C55CDFF8FA0 - EAFF9EADEFFF6078E4FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69 - E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FFB5C0 - F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4BFF2FF4F69 - E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69 - E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF6078E4FF9EADEFFF8FA0EAFF3C55 - CDFF3C55CDFF3C55CDD9FFFFFF00FFFFFF003B54CBF13B54CBFF3B54CBFF98A7 - ECFF9DACEEFF576FE2FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67 - E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FFA4B1 - EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4B1EFFF4D67 - E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67 - E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF5971E2FF9DACEEFF96A6ECFF3B54 - CBFF3B54CBFF3B54CBEDFFFFFF00FFFFFF003953C9FF3953C9FF3953C9FF9DAA - EDFF9DAAEDFF526ADFFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65 - DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF91A0 - EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91A0EBFF4C65 - DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65 - DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF546CDFFF9DAAEDFF9BA8ECFF3953 - C9FF3953C9FF3953C9F9FFFFFF00FFFFFF003851C7FF3851C7FF3851C7FF9CAA - ECFF9CAAECFF5069DEFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64 - DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF7E90 - E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F91E7FF4A64 - DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64 - DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF526BDEFF9CAAECFF9AA8EBFF3851 - C7FF3851C7FF3851C7F9FFFFFF00FFFFFF003750C6F13750C6FF3750C6FF96A4 - EAFF9BA9ECFF526BDEFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862 - DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF6D81 - E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D81E3FF4862 - DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862 - DCFF4862DCFF4862DCFF4862DCFF4862DCFF546CDEFF9BA9ECFF94A3E9FF3750 - C6FF3750C6FF3750C6EDFFFFFF00FFFFFF00364FC4D9364FC4FF364FC4FF8B9B - E5FF9AA8EBFF5970DEFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760 - DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF586F - DDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF586FDDFF4760 - DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760 - DAFF4760DAFF4760DAFF4760DAFF4760DAFF5970DEFF9AA8EBFF8B9BE5FF364F - C4FF364FC4FF364FC4D9FFFFFF00FFFFFF00354DC2B4354DC2FF354DC2FF7C8D - DEFF99A7EAFF6378DFFF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455E - D9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF4760 - D9FFFDFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFDFFFF4760D9FF455E - D9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455E - D9FF455ED9FF455ED9FF455ED9FF455ED9FF6378DFFF99A7EAFF7C8DDEFF354D - C2FF354DC2FF354DC2B5FFFFFF00FFFFFF00344CC08C344CC0FF344CC0FF6B7D - D7FF98A6EAFF7486E2FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435C - D8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435C - D8FFEDF0FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEF0FBFF435CD8FF435C - D8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435C - D8FF435CD8FF435CD8FF435CD8FF435CD8FF7486E2FF98A6EAFF6B7DD7FF344C - C0FF344CC0FF344CC08CFFFFFF00FFFFFF00334BBE4F334BBEFF334BBEFF495F - C8FF97A5E9FF8999E6FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415B - D7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415B - D7FFDADFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDADFF7FF415BD7FF415B - D7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415B - D7FF415BD7FF415BD7FF415BD7FF415BD7FF8999E6FF97A5E9FF495FC8FF334B - BEFF334BBEFF334BBE4FFFFFFF00FFFFFF00324ABC10324ABCFC324ABCFF324A - BCFF92A0E6FF96A4E8FF5067D9FF4059D5FF4059D5FF4059D5FF4059D5FF4059 - D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059 - D5FF677BDEFF7385E0FF7385E0FF7385E0FF7385E0FF677BDEFF4059D5FF4059 - D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059 - D5FF4059D5FF4059D5FF4059D5FF5067D9FF96A4E8FF92A0E6FF324ABCFF324A - BCFF324ABCFC324ABC11FFFFFF00FFFFFF003148BA003148BAB83148BAFF3148 - BAFF6C7ED5FF95A3E7FF7688E0FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 - D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 - D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 - D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 - D4FF3E57D4FF3E57D4FF3E57D4FF7688E0FF95A3E7FF6D7ED5FF3148BAFF3148 - BAFF3148BAB93148BA00FFFFFF00FFFFFF003047B8003047B85B3047B8FF3047 - B8FF3E53BEFF94A2E7FF94A2E7FF475FD5FF3C56D3FF3C56D3FF3C56D3FF3C56 - D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56 - D3FF92A0E6FF97A5E8FF97A5E8FF97A5E8FF97A5E8FF97A5E8FF475FD5FF3C56 - D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56 - D3FF3C56D3FF3C56D3FF475FD5FF94A2E7FF94A2E7FF3E53BEFF3047B8FF3047 - B8FF3047B85C3047B800FFFFFF00FFFFFF002F46B7002F46B7082F46B7E62F46 - B7FF2F46B7FF7384D7FF93A1E6FF788AE0FF3B54D2FF3B54D2FF3B54D2FF3B54 - D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54 - D2FFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5268D7FF3B54 - D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54 - D2FF3B54D2FF3B54D2FF788AE0FF93A1E6FF7384D7FF2F46B7FF2F46B7FF2F46 - B7E62F46B7082F46B700FFFFFF00FFFFFF002E45B5002E45B5002E45B5712E45 - B5FF2E45B5FF384EBAFF8C9BE2FF92A1E5FF576DD7FF3953D0FF3953D0FF3953 - D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953 - D0FFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5067D6FF3953 - D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953 - D0FF3953D0FF576DD7FF92A1E5FF8C9CE2FF384EBAFF2E45B5FF2E45B5FF2E45 - B5722E45B5002E45B500FFFFFF00FFFFFF002D43B3002D43B3002D43B3082D43 - B3DD2D43B3FF2D43B3FF596BC9FF929FE5FF8F9DE4FF4F65D5FF3851CFFF3851 - CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851 - CFFFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F65D5FF3851 - CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851 - CFFF4F65D5FF8F9DE4FF929FE5FF5A6CC9FF2D43B3FF2D43B3FF2D43B3DD2D43 - B3082D43B3002D43B300FFFFFF00FFFFFF002C42B1002C42B1002C42B1002C42 - B14A2C42B1FF2C42B1FF2C42B1FF6D7DD2FF919EE4FF8897E2FF4C62D3FF364F - CEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364F - CEFFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E64D4FF364F - CEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF4C62 - D3FF8897E2FF919EE4FF6D7DD2FF2C42B1FF2C42B1FF2C42B1FF2C42B14B2C42 - B1002C42B1002C42B100FFFFFF00FFFFFF002B41B0002B41B0002B41B0002B41 - B0002B41B09C2B41B0FF2B41B0FF2B41B0FF7283D5FF909EE4FF8A98E2FF4F65 - D3FF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354E - CDFFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D63D3FF354E - CDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF4F65D3FF8A98 - E2FF909EE4FF7283D5FF2B41B0FF2B41B0FF2B41B0FF2B41B09E2B41B0002B41 - B0002B41B0002B41B000FFFFFF00FFFFFF002A40AE002A40AE002A40AE002A40 - AE002A40AE0A2A40AECF2A40AEFF2A40AEFF2A40AEFF7081D3FF8F9DE3FF8D9B - E2FF546AD4FF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334D - CCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334D - CCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF546AD4FF8D9BE2FF8F9D - E3FF7081D3FF2A40AEFF2A40AEFF2A40AEFF2A40AECF2A40AE0A2A40AE002A40 - AE002A40AE002A40AE00FFFFFF00FFFFFF00293FAD00293FAD00293FAD00293F - AD00293FAD00293FAD1C293FADE0293FADFF293FADFF293FADFF697ACEFF8E9C - E2FF8E9CE2FF7283DBFF3D55CEFF324BCBFF324BCBFF324BCBFF324BCBFF324B - CBFF324BCBFF324BCBFF324BCBFF324BCBFF324BCBFF324BCBFF324BCBFF324B - CBFF324BCBFF324BCBFF324BCBFF3D55CEFF7283DBFF8E9CE2FF8E9CE2FF697A - CEFF293FADFF293FADFF293FADFF293FADE0293FAD1C293FAD00293FAD00293F - AD00293FAD00293FAD00FFFFFF00FFFFFF00283EAB00283EAB00283EAB00283E - AB00283EAB00283EAB00283EAB22283EABDD283EABFF283EABFF283EABFF5466 - C3FF8896DFFF8E9CE2FF8E9CE2FF6D7FD9FF435ACFFF314ACAFF314ACAFF314A - CAFF314ACAFF314ACAFF314ACAFF314ACAFF314ACAFF314ACAFF314ACAFF314A - CAFF314ACAFF435ACFFF6D7FD9FF8E9CE2FF8E9CE2FF8796DEFF5366C2FF283E - ABFF283EABFF283EABFF283EABDD283EAB22283EAB00283EAB00283EAB00283E - AB00283EAB00283EAB00FFFFFF00FFFFFF00273DAA00273DAA00273DAA00273D - AA00273DAA00273DAA00273DAA00273DAA18273DAACD273DAAFF273DAAFF273D - AAFF3146AFFF6D7DD0FF8D9BE1FF8D9BE1FF8D9BE1FF7E8EDDFF6678D7FF5166 - D2FF475DCFFF3E55CDFF3951CBFF3951CBFF3E55CDFF475DCFFF5166D2FF6678 - D7FF7E8EDDFF8D9BE1FF8D9BE1FF8D9BE1FF6D7DD0FF3146AFFF273DAAFF273D - AAFF273DAAFF273DAACD273DAA18273DAA00273DAA00273DAA00273DAA00273D - AA00273DAA00273DAA00FFFFFF00FFFFFF00273CA800273CA800273CA800273C - A800273CA800273CA800273CA800273CA800273CA808273CA899273CA8FF273C - A8FF273CA8FF273CA8FF3549B0FF6374CAFF8998DFFF8D9BE1FF8D9BE1FF8D9B - E1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9B - E1FF8D9BE1FF8998DFFF6374CAFF3549B0FF273CA8FF273CA8FF273CA8FF273C - A8FF273CA898273CA808273CA800273CA800273CA800273CA800273CA800273C - A800273CA800273CA800FFFFFF00FFFFFF00263BA700263BA700263BA700263B - A700263BA700263BA700263BA700263BA700263BA700263BA700263BA74A263B - A7DC263BA7FF263BA7FF263BA7FF263BA7FF263BA7FF3D50B4FF5E6FC7FF6E7E - D0FF7C8BD8FF8594DDFF8A98E0FF8A98E0FF8594DDFF7C8BD8FF6E7ED0FF5E6F - C7FF3D50B4FF263BA7FF263BA7FF263BA7FF263BA7FF263BA7FF263BA7DC263B - A749263BA700263BA700263BA700263BA700263BA700263BA700263BA700263B - A700263BA700263BA700FFFFFF00FFFFFF00253AA600253AA600253AA600253A - A600253AA600253AA600253AA600253AA600253AA600253AA600253AA600253A - A609253AA672253AA6E6253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253A - A6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253A - A6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6E6253AA672253AA609253A - A600253AA600253AA600253AA600253AA600253AA600253AA600253AA600253A - A600253AA600253AA600FFFFFF00FFFFFF002439A5002439A5002439A5002439 - A5002439A5002439A5002439A5002439A5002439A5002439A5002439A5002439 - A5002439A5002439A5072439A55B2439A5BA2439A5FC2439A5FF2439A5FF2439 - A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439 - A5FF2439A5FF2439A5FC2439A5BA2439A55B2439A5072439A5002439A5002439 - A5002439A5002439A5002439A5002439A5002439A5002439A5002439A5002439 - A5002439A5002439A500FFFFFF00FFFFFF002439A4002439A4002439A4002439 - A4002439A4002439A4002439A4002439A4002439A4002439A4002439A4002439 - A4002439A4002439A4002439A4002439A4002439A4112439A4502439A48B2439 - A4B52439A4D72439A4EE2439A4FA2439A4FA2439A4EE2439A4D72439A4B52439 - A48B2439A4502439A4112439A4002439A4002439A4002439A4002439A4002439 - A4002439A4002439A4002439A4002439A4002439A4002439A4002439A4002439 - A4002439A4002439A400FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00 - } - end - object IconSmall: TImageList - left = 27 - top = 328 - Bitmap = { - 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D898 - 5223D4964D7DD2924CDBCD8C45F3CB8B41F3C98B40DBC78B407DC5873D23FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D6974F53D191 - 49E6D0A06AFFE0BFA0FFE3C5AEFFE3C5AEFFDFBC9FFFC89762FFBD7D35E6BC7E - 3553FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D4964D53CF8D47F4D9B2 - 8CFFE6CDB8FFE0BA9DFFD7AB85FFD6A982FFD9B391FFE1C2ABFFD4AE86FFB16B - 35F4B16F3553FFFFFF00FFFFFF00FFFFFF00D2934C22CE8E47E5D9B28CFFE6CA - B3FFD6A97DFFD1A579FFE2C4A8FFE1C3A8FFD0A276FFD1A477FFDDBDA2FFD0AC - 85FFAB6635E5A9653522FFFFFF00FFFFFF00CE91477ECD9C68FFE7CBB4FFD4A5 - 7AFFD0A077FFCF9E74FFFBF8F5FFFBF8F5FFCB9E71FFCB9D71FFCDA177FFDFC0 - A5FFB98A5BFFA45C347EFFFFFF00FFFFFF00CB8E41DBE0BC9FFFDBB393FFCFA0 - 75FFCD9E72FFCB9C71FFDDBFA3FFDDBFA2FFC5996BFFC5996BFFC4986BFFD1AB - 85FFD8BA97FF9E5635DBFFFFFF00FFFFFF00C5853BF6E4C9B0FFD0A37AFFCC9D - 71FFC79A6CFFC5986BFFFFFFFFFFFFFFFEFFC39669FFC19468FFC29468FFC398 - 6DFFDFC5ABFF955334F6FFFFFF00FFFFFF00BF7E35F6E3C7AFFFD0A276FFC599 - 6BFFC4976AFFC49669FFEEE0D4FFFBF7F4FFBF9066FFBE8F65FFBE8F64FFBE92 - 69FFDFC6AAFF925034F6FFFFFF00FFFFFF00BC7E35DBDBBC9CFFD5AD89FFC798 - 6CFFC39569FFC19367FFEDDFD3FFFAF7F4FFBB8B63FFB98A63FFB88A62FFC59D - 78FFD2B893FF905135DBFFFFFF00FFFFFF00B878357EBF915EFFE0C2A8FFC596 - 6CFFC29169FFE1CBB8FFFEFDFCFFFFFFFEFFEADCD0FFB4855EFFB3855EFFD4B5 - 99FFAE7B56FF8F51357EFFFFFF00FFFFFF00AF703522AB6935E5CFAA81FFDABC - A2FFBE9166FFBA8C62FFB7895FFFB3845EFFB1835DFFB0835CFFCDAA8DFFC6A5 - 79FF895034E589503522FFFFFF00FFFFFF00FFFFFF00A76234539F5533F4CBA7 - 7DFFD8BB9FFFC39C77FFB68A62FFB48660FFBE9672FFD1B397FFC5A377FF844F - 35F489503553FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009F5634539955 - 34E6B28057FFD5B793FFDBC3A6FFDAC3A6FFD2B490FFAB7A52FF864F34E68850 - 3553FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009754 - 35239453347D925234DB8A5034F3884F34F3895035DB8950357D84503623FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006A85 - FC236984FA7D6782F9DB6580F7F3637EF5F3617CF3DB5F7AF17D5D77EF23FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006984FA536C85 - F9E76E83EEFF92A6F4FFA0B4F8FFA0B4F8FF91A6F3FF687DE9FF5D76EBE65671 - E953FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006883F953748DF9F58497 - F1FFA9BDFBFF8AA3F8FF6B89F6FF6B89F6FF89A2F8FFA8BCFAFF7F92ECFF6279 - E6F54F69E253FFFFFF00FFFFFF00FFFFFF006781F8226983F6E68397F0FFACBF - FBFF6382F5FF6382F5FF6382F5FF617EF3FF617EF3FF607CF3FFA6B9F9FF7B8D - EAFF4D66DFE54862DB22FFFFFF00FFFFFF00637EF57E6C81ECFFA9BDFBFF6382 - F5FF8099F7FFA4B6F9FF6280F4FF607BF1FFA5B4F7FF7B8FF3FF5D76EFFFA5B5 - F8FF5D70DDFF435DD77EFFFFFF00FFFFFF005F7AF1DB91A6F3FF88A1F8FF6280 - F4FFA4B5F8FFE7EBFDFFA8B8F8FFABB8F7FFE7EBFDFF9EACF5FF5B70ECFF8293 - F1FF8998ECFF3E58D2DBFFFFFF00FFFFFF005B76EDF6A1B6F8FF6784F4FF607C - F3FF5F7AF1FFA8B5F7FFE7EBFDFFE7EAFCFFA1ADF4FF5A6EEBFF596CEAFF5F6F - E9FF9BA8F1FF3A53CEF6FFFFFF00FFFFFF005771E9F6A0B3F7FF6580F2FF5F78 - F0FF5E77EFFFAAB6F6FFE7EAFCFFE6E9FCFFA5AFF4FF5869E8FF5767E7FF5D6C - E7FF99A5F1FF354FCAF6FFFFFF00FFFFFF00526DE5DB8E9FF0FF8499F4FF5C73 - EEFFA4AFF4FFE6E9FCFFA1ADF4FFA3ACF2FFE6E8FBFF9CA5F0FF5562E5FF7D89 - EBFF8591E7FF314AC6DBFFFFFF00FFFFFF004E68E17E6073E0FFA4B3F7FF5A6E - EBFF7685EEFF9BA5F1FF5869E8FF5562E5FF9CA3F0FF6F7AE8FF535FE2FF9FA9 - F2FF5061D1FF2D46C27EFFFFFF00FFFFFF004963DC224B64DBE67888E6FFA7B3 - F5FF5767E7FF5665E6FF5665E6FF535FE2FF535FE2FF525DE1FF9FA9F2FF6F7D - DDFF2D46C1E52942BE22FFFFFF00FFFFFF00FFFFFF00425CD5533F59D3F47584 - E3FFA1ACF4FF7F8BECFF5C67E4FF5B66E3FF7D87EAFF9FA8F1FF6F7CDDFF2943 - BFF42741BD53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003A54CF533852 - CCE65264D4FF8490E7FF95A0EEFF959FEDFF838EE5FF4C5DCEFF2841BDE6263F - BB53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00334D - C823314BC67D2F48C4DB2C46C2F32A44C0F32842BEDB2640BC7D243EBA23FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0040C9 - 62233BC55E7D39C25BDB31BD54F32DBB52F32BB952DB2BB7527D28B44E23FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003DC7605336C2 - 59E659C274FF96D7A3FFA5DCAEFFA5DCAEFF95D6A1FF50B96AFF1FAB42E61FA9 - 4253FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003BC55E5334C055F47FCE - 90FFAFE1B7FF92D89DFF77CE83FF77CE83FF92D89DFFAEE1B5FF78C88BFF1D9D - 32F41D9D3653FFFFFF00FFFFFF00FFFFFF0039C25C2234BE55E57FCE90FFAEE1 - B5FF6DCC7AFF6ACA76FF68C872FF68C874FF68C875FF6BC979FFACDFB4FF76C4 - 89FF1C962DE51C942D22FFFFFF00FFFFFF0034BE597E57BF70FFAFE1B7FF6DCC - 7AFF68C872FF65C770FF63C56EFF62C46EFF63C471FFB6E3BEFF6FC77EFFACDF - B5FF48A95EFF1C8F267EFFFFFF00FFFFFF002DBB54DB95D7A1FF91D79BFF69C9 - 76FF64C66FFF61C46EFF61C36FFF61C26FFFB9E4C0FFFFFFFFFFE3F4E6FF8BD1 - 99FF8BCE9DFF1C8820DBFFFFFF00FFFFFF0026B44BF6A7DDB1FF72CC80FF66C7 - 73FFB0E1B7FFD2EED6FF63C170FFB8E3BFFFFFFFFFFFFBFDFCFF8CD099FF69C1 - 7EFFA1D7AEFF1B7F1EF6FFFFFF00FFFFFF001FAD42F6A6DCAFFF70CA7FFF73CA - 80FFF0F9F1FFFFFFFFFFEBF7EDFFFFFFFFFFFBFDFCFF88CD96FF5BB971FF67BE - 7DFFA0D7AFFF1B7A1EF6FFFFFF00FFFFFF001FA942DB91D29FFF8DD49AFF64C3 - 74FF79C987FFF2FAF4FFFFFFFFFFFDFEFDFF86CB96FF57B76DFF5BB972FF85CC - 97FF87C79AFF1B781FDBFFFFFF00FFFFFF001EA43D7E4CB064FFAADDB4FF64C1 - 79FF5FBE71FF75C585FFD4ECD9FF8ACD99FF56B66CFF58B56EFF5CB774FFA6DA - B4FF419B4EFF1B771F7EFFFFFF00FFFFFF001D9B36221C962FE572C287FFA8DB - B2FF60BC77FF5CBA73FF59B870FF59B56FFF58B56FFF5BB774FFA5D9B3FF69B8 - 7FFF1A711EE51B711F22FFFFFF00FFFFFF00FFFFFF001C912B531B8A20F46DBE - 83FFA8DBB5FF87CC98FF66BC7DFF64BA7CFF86CB98FFA5D9B4FF66B77DFF1A6C - 1DF41B711F53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C8A21531B83 - 1FE642A052FF87CA9AFF9BD3ABFF9BD2ABFF83C796FF3D974CFF1A6E1EE61B70 - 1F53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C81 - 1F231B7E1F7D1B7A1FDB1A731EF31A701EF31B711FDB1B711F7D1B6C1F23FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00 - } - end - object pmEditURL: TPopupMenu - OnPopup = pmEditURLPopup - left = 592 - top = 136 - object medURLUndo: TMenuItem - Caption = 'Undo' - OnClick = medURLUndoClick - end - object MenuItem9: TMenuItem - Caption = '-' - end - object medURLCut: TMenuItem - Caption = 'Cut' - OnClick = medURLCutClick - end - object medURLCopy: TMenuItem - Caption = 'Copy' - OnClick = medURLCopyClick - end - object medURLPaste: TMenuItem - Caption = 'Paste' - OnClick = medURLPasteClick - end - object medURLPasteandgo: TMenuItem - Caption = 'Paste and go' - OnClick = medURLPasteandgoClick - end - object medtURLDelete: TMenuItem - Caption = 'Delete' - OnClick = medtURLDeleteClick - end - object MenuItem15: TMenuItem - Caption = '-' - end - object medURLSelectAll: TMenuItem - Caption = 'Select all' - OnClick = medURLSelectAllClick - end - end - object appPropertiesMain: TApplicationProperties - CaptureExceptions = False - OnShowHint = appPropertiesMainShowHint - left = 80 - top = 448 - end - object itStartup: TIdleTimer - Enabled = False - Interval = 500 - OnTimer = itStartupTimer - left = 696 - top = 72 - end - object tmBackup: TIdleTimer - Interval = 60000 - OnTimer = tmBackupTimer - left = 696 - top = 120 - end - object itMonitor: TTimer - Enabled = False - OnTimer = itMonitorTimer - left = 760 - top = 296 - end - object TransferRateGraphList: TListChartSource - DataPoints.Strings = ( - '1|0|?|' - ) - left = 648 - top = 72 - end - object TransferRateToolset: TChartToolset - left = 608 - top = 72 - end - object pmSbMain: TPopupMenu - OnPopup = pmSbMainPopup - left = 283 - top = 416 - object miAbortSilentThread: TMenuItem - Caption = 'Abort' - OnClick = miAbortSilentThreadClick - end - end -end +object MainForm: TMainForm + Left = 273 + Height = 575 + Top = 96 + Width = 819 + Align = alBottom + Caption = 'Free Manga Downloader' + ClientHeight = 575 + ClientWidth = 819 + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + OnWindowStateChange = FormWindowStateChange + LCLVersion = '1.5' + object sbUpdateList: TStatusBar + Left = 0 + Height = 30 + Top = 545 + Width = 819 + AutoSize = False + Panels = < + item + Width = 50 + end> + ParentShowHint = False + SimplePanel = False + SizeGrip = False + ShowHint = True + Visible = False + OnDrawPanel = sbUpdateListDrawPanel + end + object pcMain: TPageControl + Left = 201 + Height = 508 + Top = 11 + Width = 614 + ActivePage = tsDownload + Align = alClient + BorderSpacing.Top = 3 + BorderSpacing.Right = 4 + BorderSpacing.Bottom = 3 + ParentFont = False + TabIndex = 0 + TabOrder = 0 + OnChange = pcMainChange + object tsDownload: TTabSheet + Caption = 'Downloads' + ClientHeight = 480 + ClientWidth = 606 + object vtDownload: TVirtualStringTree + Left = 2 + Height = 445 + Top = 32 + Width = 600 + Align = alClient + BorderSpacing.Left = 2 + BorderSpacing.Right = 4 + BorderSpacing.Bottom = 3 + DefaultText = 'Node' + DragOperations = [doMove] + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Manga' + Width = 100 + end + item + Position = 1 + Text = 'Status' + Width = 200 + end + item + Position = 2 + Text = 'Progress' + Width = 55 + end + item + Position = 3 + Text = 'Transfer rate' + end + item + Position = 4 + Text = 'Website' + Width = 65 + end + item + Position = 5 + Text = 'Save to' + Width = 150 + end + item + Position = 6 + Text = 'Added' + Width = 80 + end> + Header.DefaultHeight = 17 + Header.Height = 25 + Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] + HintMode = hmHintAndDefault + Images = IconDL + IncrementalSearch = isVisibleOnly + Margin = 2 + ParentFont = False + ParentShowHint = False + PopupMenu = pmDownload + ShowHint = True + TabOrder = 0 + TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnAfterCellPaint = vtDownloadAfterCellPaint + OnColumnDblClick = vtDownloadColumnDblClick + OnDragAllowed = vtDownloadDragAllowed + OnDragOver = vtDownloadDragOver + OnDragDrop = vtDownloadDragDrop + OnFreeNode = vtDownloadFreeNode + OnGetText = vtDownloadGetText + OnGetImageIndex = vtDownloadGetImageIndex + OnGetHint = vtDownloadGetHint + OnHeaderClick = vtDownloadHeaderClick + OnInitNode = vtDownloadInitNode + OnKeyDown = vtDownloadKeyDown + OnKeyUp = vtDownloadKeyUp + end + object pnDownloadToolbar: TPanel + Left = 2 + Height = 28 + Top = 4 + Width = 600 + Align = alTop + BorderSpacing.Left = 2 + BorderSpacing.Top = 4 + BorderSpacing.Right = 4 + BevelOuter = bvNone + ClientHeight = 28 + ClientWidth = 600 + TabOrder = 1 + object TransferRateGraph: TChart + Left = 323 + Height = 26 + Top = 0 + Width = 277 + AllowZoom = False + AxisList = < + item + Minors = <> + Title.LabelFont.Orientation = 900 + end + item + Alignment = calBottom + Minors = <> + end> + AxisVisible = False + BackColor = clDefault + Extent.UseXMin = True + Extent.UseYMin = True + Extent.XMin = 1 + Extent.YMin = 1 + Foot.Brush.Color = clBtnFace + Foot.Font.Color = clBlue + Frame.Color = clGreen + Frame.Visible = False + Legend.Alignment = laCenterRight + Legend.BackgroundBrush.Style = bsClear + Legend.Frame.Visible = False + Legend.MarginX = 0 + Legend.MarginY = 0 + Legend.Spacing = 0 + Legend.SymbolWidth = 0 + Legend.UseSidebar = False + Legend.Visible = True + Margins.Left = 0 + Margins.Top = 0 + Margins.Right = 0 + Margins.Bottom = 0 + MarginsExternal.Left = 0 + MarginsExternal.Top = 0 + MarginsExternal.Right = 0 + MarginsExternal.Bottom = 0 + Title.Brush.Color = clBtnFace + Title.Font.Color = clBlue + Title.Text.Strings = ( + 'TAChart' + ) + Toolset = TransferRateToolset + Align = alClient + BorderSpacing.Bottom = 2 + Visible = False + object TransferRateGraphArea: TAreaSeries + Transparency = 125 + AreaBrush.Color = 8453888 + AreaContourPen.Color = 5481984 + AreaLinesPen.Style = psClear + Source = TransferRateGraphList + end + end + object pnDownloadToolbarLeft: TPanel + Left = 0 + Height = 28 + Top = 0 + Width = 323 + Align = alLeft + AutoSize = True + BevelOuter = bvNone + ClientHeight = 28 + ClientWidth = 323 + TabOrder = 1 + object ToolBarDownload: TToolBar + Left = 0 + Height = 25 + Top = 0 + Width = 321 + AutoSize = True + BorderSpacing.Right = 2 + ButtonHeight = 25 + EdgeBorders = [] + Images = IconList + List = True + ParentFont = False + ShowCaptions = True + TabOrder = 0 + TabStop = True + Transparent = True + object tbDownloadResumeAll: TToolButton + Left = 1 + Top = 0 + AutoSize = True + Caption = 'Resume All' + ImageIndex = 12 + OnClick = tbDownloadResumeAllClick + end + object tbDownloadStopAll: TToolButton + Left = 86 + Top = 0 + AutoSize = True + Caption = 'Stop All' + ImageIndex = 7 + OnClick = tbDownloadStopAllClick + end + object ToolButton1: TToolButton + Left = 153 + Height = 25 + Top = 0 + Width = 5 + Style = tbsDivider + end + object tbDownloadDeleteCompleted: TToolButton + Left = 158 + Top = 0 + AutoSize = True + Caption = 'Delete all completed tasks' + ImageIndex = 9 + OnClick = tbDownloadDeleteCompletedClick + end + end + end + end + end + object tsInformation: TTabSheet + Caption = 'Manga Info' + ClientHeight = 480 + ClientWidth = 606 + object sbInformation: TScrollBox + Left = 0 + Height = 480 + Top = 0 + Width = 606 + HorzScrollBar.Page = 214 + VertScrollBar.Page = 317 + Align = alClient + BorderStyle = bsNone + ClientHeight = 480 + ClientWidth = 606 + TabOrder = 0 + object pnInfomation: TPanel + Left = 0 + Height = 262 + Top = 0 + Width = 606 + Align = alTop + BevelOuter = bvNone + ClientHeight = 262 + ClientWidth = 606 + ParentFont = False + TabOrder = 0 + object rmInformation: TRichMemo + Left = 165 + Height = 222 + Top = 38 + Width = 436 + Anchors = [akTop, akLeft, akRight, akBottom] + Color = clWhite + HideSelection = False + ParentFont = False + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 1 + ZoomFactor = 1 + end + object edURL: TEdit + Left = 4 + Height = 23 + Top = 6 + Width = 554 + Anchors = [akTop, akLeft, akRight] + OnKeyPress = edURLKeyPress + PopupMenu = pmEditURL + TabOrder = 0 + TextHint = 'Input URL here' + end + object btDonate: TImage + Cursor = crHandPoint + Left = 2 + Height = 21 + Top = 14 + Width = 75 + Anchors = [akTop, akRight] + OnClick = btDonateClick + Stretch = True + Visible = False + end + object btURL: TSpeedButton + Left = 561 + Height = 23 + Top = 6 + Width = 40 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0001000000070000000E000000150000001A0000001A0000001A0000001A0000 + 001A0000001A000000160000000F0000000800000002FFFFFF00FFFFFF000000 + 00020000000E0000001C0000002A000000330000003300000033733A02A66332 + 0274000000330000002B0000001D0000000F00000003FFFFFF00FFFFFF000000 + 00000000000000000000000000000000000000000000281502009D5206CC9D52 + 06CC763E055C29160300000000000000000000000000FFFFFF00FFFFFF005933 + 0B0058320A0058320A0058320A0058320A0058320A00A3580B00A3580BCCFFBA + 18FFA3580BCCA4590C5C7F470C002C19050000000000FFFFFF00FFFFFF00B166 + 1600AF641400AF641400AF641400AF641400AF641400AE631300AA5F10CCFFB9 + 12FFFFBC1EFFAA5F10CCAB60115CB1661600B96E1C00FFFFFF00FFFFFF00B267 + 1799B16616CCB16616CCB16616CCB16616CCB16616CCB16616CCB16616CCF7B5 + 25FFF5AB0EFFF7BA32FFB16616CCB267175CB96E1C00FFFFFF00FFFFFF00B96E + 1CCCF7CD81FFF4C276FFF3C071FFEEB85BFFE8B049FFE7AE45FFE6AD43FFE3A5 + 35FFE19E29FFE19E29FFEBB54DFFB96E1CCCBA6F1D5CFFFFFF00FFFFFF00C277 + 22CCF5C77BFFEEB266FFEEB266FFEEB266FFEAAE60FFE1A453FFD89B49FFD396 + 44FFD09341FFD09341FFD39644FFE8B868FFC27722CCFFFFFF00FFFFFF00CA7F + 28CCFAD589FFF6C97DFFF6C87CFFF5C77BFFF5C77BFFF5C67AFFF5C579FFF2BC + 70FFEFB468FFEFB468FFF8CF83FFCA7F28CCC97E275CFFFFFF00FFFFFF00D186 + 2D99D2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCF8CD + 81FFF4BE72FFFCD98DFFD2872ECCD1862D5CCA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00D3882F00D3882F00D58A3100D98E33CCFCD5 + 89FFFEE094FFD98E33CCD88D335CD2872E00CA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00D3882F00D78C3200E0953800E09538CCFFE4 + 98FFE09538CCDF94385CD98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00D88D3300E59A3C00E59A3C00E59A3CCCE59A + 3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00E89D3F00E89D3F00E89D3F00E99E4099E99E + 405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btURLClick + end + object pnThumbContainer: TPanel + Left = 4 + Height = 216 + Top = 38 + Width = 154 + BevelOuter = bvNone + BorderStyle = bsSingle + ClientHeight = 212 + ClientWidth = 150 + Color = clWhite + ParentColor = False + TabOrder = 2 + object imCover: TImage + Left = 0 + Height = 212 + Top = 0 + Width = 150 + AntialiasingMode = amOn + Align = alClient + Center = True + Proportional = True + Stretch = True + end + object pbWait: TPaintBox + Left = 0 + Height = 212 + Top = 0 + Width = 150 + Align = alClient + end + end + end + object spInfos: TSplitter + Cursor = crVSplit + Left = 0 + Height = 5 + Top = 262 + Width = 606 + Align = alTop + ResizeAnchor = akTop + end + object pnChapterList: TPanel + Left = 0 + Height = 213 + Top = 267 + Width = 606 + Align = alClient + BevelOuter = bvNone + ClientHeight = 213 + ClientWidth = 606 + TabOrder = 2 + object btDownload: TBitBtn + Left = 387 + Height = 30 + Top = 145 + Width = 101 + Anchors = [akRight, akBottom] + Caption = 'Download' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } + OnClick = btDownloadClick + TabOrder = 1 + end + object cbAddAsStopped: TCheckBox + Left = 4 + Height = 19 + Top = 182 + Width = 214 + Anchors = [akLeft, akBottom] + Caption = 'Add to download list as stopped task' + OnChange = cbAddAsStoppedChange + ParentFont = False + TabOrder = 3 + end + object clbChapterList: TVirtualStringTree + Left = 4 + Height = 125 + Top = 0 + Width = 563 + Anchors = [akTop, akLeft, akRight, akBottom] + Colors.UnfocusedSelectionColor = clHighlight + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + IncrementalSearch = isVisibleOnly + Margin = 2 + ParentFont = False + PopupMenu = pmChapterList + TabOrder = 0 + TextMargin = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnBeforeCellPaint = clbChapterListBeforeCellPaint + OnFreeNode = clbChapterListFreeNode + OnGetText = clbChapterListGetText + OnGetNodeDataSize = clbChapterListGetNodeDataSize + OnInitNode = clbChapterListInitNode + end + object btReadOnline: TBitBtn + Left = 493 + Height = 30 + Top = 145 + Width = 108 + Anchors = [akRight, akBottom] + Caption = 'Read online' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0A0A0A660C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C + 0C770C0C0C770C0C0C776C3A07C94E2A06970000002C00000012000000090000 + 00161F1F1F74EBEBEBFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 + E6FFE6E6E6FFE6E6E6FFB47839FF99560FE3723F0A6E00000009000000002A2A + 2A0036363671E8E8E8FFB4B4B4FFBDBDBDFFC5C5C5FFBDBDBDFFBF9261FFBD81 + 40FFBD8140FFBD8140FFBF8342FFFFC538FFB56A18CCB76C195C343434004545 + 45004545456FEAEAEAFFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFC68A46FFFFE3 + 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC4B4B4B004B4B + 4B004B4B4B6EECECECFF8E8E8EFFA5A5A5FFA5A5A5FF8E8E8EFFD2A56FFFD599 + 53FFCF934CFFCD914AFFD79B55FFFFE597FFD2872ECCD0852D5C515151005151 + 51005151516DEEEEEEFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 + E8FFD5D5D5FFD5D5D5FFE3A75CFFD18E3AE2DE93375CD2872E00575757005757 + 57005757576CF0F0F0FFBFBFBFFFC7C7C7FFD0D0D0FFC7C7C7FFD8D8D8FFEAEA + EAFFBFBFBFFFC7C7C7FFEABD85FF9E794BA29C764800957043005D5D5D005D5D + 5D005D5D5D6BF2F2F2FFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFEDED + EDFFDBDBDBFFDBDBDBFFF2F2F2FF5D5D5D6B5D5D5D005D5D5D00626262006262 + 62006262626BF5F5F5FF919191FFC4C4C4FFAAAAAAFFAAAAAAFF919191FFF1F1 + F1FFBBBBBBFFCCCCCCFFF5F5F5FF6262626B6262620062626200676767006767 + 67006767676AF7F7F7FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 + F4FFF4F4F4FFF4F4F4FFF7F7F7FF6767676A67676700676767006C6C6C006C6C + 6C006C6C6C69F9F9F9FF03599DFF0961A5FF1A77BBFF2587CBFF1976BAFF2587 + CBFF1570B4FF055CA0FFF9F9F9FF6C6C6C696C6C6C006C6C6C00717171007171 + 710071717168FBFBFBFF03599DFFC2D8E9FF89B9DBFF90C3E5FFB6CFE0FF2587 + CBFF1570B4FF055CA0FFFBFBFBFF717171687171710071717100757575007575 + 750075757568FDFDFDFF03599DFF126CB0FF2484C8FF3096DAFF3196DAFF2587 + CBFF1570B4FF055CA0FFFDFDFDFF757575687575750075757500797979007979 + 790079797967FEFEFEFF02579BFF0961A5FF126DB1FF1876BAFF1976BAFF136E + B2FF0B63A7FF03599DFFFEFEFEFF7979796779797900797979007D7D7D007D7D + 7D007D7D7D67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFF7D7D7D677D7D7D007D7D7D007F7F7F007F7F + 7F008080804D8080806680808066808080668080806680808066808080668080 + 80668080806680808066808080668080804D7F7F7F007F7F7F00 + } + OnClick = btReadOnlineClick + TabOrder = 2 + end + object btBrowse: TSpeedButton + Left = 360 + Height = 23 + Top = 148 + Width = 23 + Anchors = [akRight, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btBrowseClick + end + object btChecks: TSpeedButton + Left = 571 + Height = 30 + Top = 0 + Width = 30 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000900000012010E + 0033024A0083025D00BC025D00CC025D00CC025D00CC025D00CC025D00CC025D + 00CC025D00CC025D00CC025D00BC024A0083010E003300000012021D0000066D + 0073129208DD20CC10F922D911FF22D911FF22D911FF22D911FF22D911FF22D9 + 11FF22D911FF22D911FF1FCC0FF9109207DD066D0073021D00000A7D00000A7D + 00BA25CA15F922D111FF22D111FF22D111FF22B611FF22D111FF22D111FF22D1 + 11FF22D111FF22D111FF22D111FF20C80FF90A7D00BA0A7D00000C8400000C84 + 00CC2BCC1AFF22C811FF22C811FF22B211FFE6E6E6FF22B211FF22C811FF22C8 + 11FF22C811FF22C811FF22C811FF22C811FF0C8400CC0C8400000D8900000D89 + 00CC31C620FF22BE11FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE + 11FF22BE11FF22BE11FF22BE11FF23BE12FF0D8900CC0D8900000E8D00000E8D + 00CC41C330FF23AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 + 11FF22B411FF22B411FF22B411FF25B514FF0E8D00CC0E8D00000F9200000F92 + 00CC52C941FFA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 + E6FF22A311FF22AA11FF22AA11FF28AF17FF0F9200CC0F920000109600001096 + 00CC55CC44FF3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 + E2FFE6E6E6FF229E11FF22A111FF2CAA1BFF109600CC10960000119A0000119A + 00CC5AD149FF47BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 + E2FFE3E3E3FFE7E7E7FF269E15FF39B128FF119A00CC119A0000129E0000129E + 00CC60D74FFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB + 33FFFFFFFFFFA7E29EFF4EC53DFF58CF47FF129E00CC129E000013A2000013A2 + 00CC67DE56FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE + 46FF4AC139FF51C840FF57CE46FF60D74FFF13A200CC13A2000014A5000014A5 + 00BA64DE53F95FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD6 + 4EFF5FD64EFF5FD64EFF5FD64EFF60DA4FF914A500BA14A5000014A8000014A8 + 007337C124DD66E054F96EE55DFF6EE55DFF6EE55DFF6EE55DFF6DE45CFF6DE4 + 5CFF6DE45CFF6DE45CFF64DF53F936BF23DD14A8007314A8000014A8000015A9 + 000C15AA007315AA00BA15AA00CC15AA00CC15AA00CC15AA00CC15AA00CC15AA + 00CC15AA00CC15AA00CC15AA00BA15AA007315A9000C14A80000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btChecksClick + end + object btAddToFavorites: TBitBtn + Left = 387 + Height = 30 + Top = 179 + Width = 214 + Anchors = [akRight, akBottom] + Caption = 'Add to favorites' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000050000 + 001E0000003200009CC9000054630000002E0000002B00000026000000220000 + 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 + 000F000000190000A8C50000A8C500006D580000001600000013000000110000 + 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 + 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D + 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 + BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 + 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 + C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C + 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 + C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 + 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 + C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 + CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 + C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 + FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 + C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 + F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A + F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C + F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E + FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 + 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 + DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 + 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 + E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 + 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 + E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 + 0000000000000000990000002B00000000000000000001016E000101DE000101 + E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 + } + OnClick = btAddToFavoritesClick + TabOrder = 4 + end + object edSaveTo: TEdit + Left = 4 + Height = 23 + Top = 148 + Width = 353 + Anchors = [akLeft, akRight, akBottom] + ParentFont = False + TabOrder = 5 + TextHint = 'Save to' + end + object lbSaveTo: TLabel + Left = 4 + Height = 15 + Top = 130 + Width = 41 + Anchors = [akLeft, akBottom] + Caption = 'Save to:' + ParentColor = False + ParentFont = False + end + end + end + end + object tsFilter: TTabSheet + Caption = 'Filter' + ClientHeight = 480 + ClientWidth = 606 + object sbFilter: TScrollBox + Left = 0 + Height = 480 + Top = 0 + Width = 606 + HorzScrollBar.Page = 568 + VertScrollBar.Page = 424 + Align = alClient + BorderStyle = bsNone + ClientHeight = 480 + ClientWidth = 606 + TabOrder = 0 + object pnGenres: TPanel + Left = 24 + Height = 180 + Top = 10 + Width = 582 + Align = alTop + AutoSize = True + BorderSpacing.Left = 24 + BorderSpacing.Top = 10 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 10 + ChildSizing.VerticalSpacing = 4 + ChildSizing.Layout = cclTopToBottomThenLeftToRight + ChildSizing.ControlsPerLine = 8 + ClientHeight = 180 + ClientWidth = 582 + TabOrder = 0 + object ckFilterAction: TCheckBox + Left = 0 + Height = 19 + Hint = 'A work typically depicting fighting, violence, chaos, and fast paced motion.' + Top = 0 + Width = 75 + AllowGrayed = True + Caption = 'Action' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 0 + end + object ckFilterAdult: TCheckBox + Left = 0 + Height = 19 + Hint = 'Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity.' + Top = 23 + Width = 75 + AllowGrayed = True + Caption = 'Adult' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 1 + end + object ckFilterAdventure: TCheckBox + Left = 0 + Height = 19 + Hint = 'If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it''s up to your personal prejudice on this case.' + Top = 46 + Width = 75 + AllowGrayed = True + Caption = 'Adventure' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 2 + end + object ckFilterComedy: TCheckBox + Left = 0 + Height = 19 + Hint = 'A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict.' + Top = 69 + Width = 75 + AllowGrayed = True + Caption = 'Comedy' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 3 + end + object ckFilterDoujinshi: TCheckBox + Left = 0 + Height = 19 + Hint = 'Fan based work inpspired by official manga/anime.' + Top = 92 + Width = 75 + AllowGrayed = True + Caption = 'Doujinshi' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 4 + end + object ckFilterDrama: TCheckBox + Left = 0 + Height = 19 + Hint = 'A work meant to bring on an emotional response, such as instilling sadness or tension.' + Top = 115 + Width = 75 + AllowGrayed = True + Caption = 'Drama' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 5 + end + object ckFilterEchi: TCheckBox + Left = 0 + Height = 19 + Hint = 'Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans.' + Top = 138 + Width = 75 + AllowGrayed = True + Caption = 'Ecchi' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 6 + end + object ckFilterFantasy: TCheckBox + Left = 0 + Height = 19 + Hint = 'Anything that involves, but not limited to, magic, dream world, and fairy tales.' + Top = 161 + Width = 75 + AllowGrayed = True + Caption = 'Fantasy' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 7 + end + object ckFilterGenderBender: TCheckBox + Left = 85 + Height = 19 + Hint = 'Girls dressing up as guys, guys dressing up as girls.'#13#10'Guys turning into girls, girls turning into guys.' + Top = 0 + Width = 98 + AllowGrayed = True + Caption = 'Gender Bender' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 8 + end + object ckFilterHarem: TCheckBox + Left = 85 + Height = 19 + Hint = 'A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed.' + Top = 23 + Width = 98 + AllowGrayed = True + Caption = 'Harem' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 9 + end + object ckFilterHentai: TCheckBox + Left = 85 + Height = 19 + Hint = 'Hentai' + Top = 46 + Width = 98 + AllowGrayed = True + Caption = 'Hentai' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 10 + end + object ckFilterHistorical: TCheckBox + Left = 85 + Height = 19 + Hint = 'Having to do with old or ancient times.' + Top = 69 + Width = 98 + AllowGrayed = True + Caption = 'Historical' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 11 + end + object ckFilterHorror: TCheckBox + Left = 85 + Height = 19 + Hint = 'A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking.' + Top = 92 + Width = 98 + AllowGrayed = True + Caption = 'Horror' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 12 + end + object ckFilterJosei: TCheckBox + Left = 85 + Height = 19 + Hint = 'Literally "Woman". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature.' + Top = 115 + Width = 98 + AllowGrayed = True + Caption = 'Josei' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 13 + end + object ckFilterLolicon: TCheckBox + Left = 85 + Height = 19 + Hint = 'Representing a sexual attraction to young or under-age girls.' + Top = 138 + Width = 98 + AllowGrayed = True + Caption = 'Lolicon' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 14 + end + object ckFilterMartialArts: TCheckBox + Left = 85 + Height = 19 + Hint = 'As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth.' + Top = 161 + Width = 98 + AllowGrayed = True + Caption = 'Martial Arts' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 15 + end + object ckFilterMature: TCheckBox + Left = 193 + Height = 19 + Hint = 'Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language.' + Top = 0 + Width = 93 + AllowGrayed = True + Caption = 'Mature' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 16 + end + object ckFilterMecha: TCheckBox + Left = 193 + Height = 19 + Hint = 'A work involving and usually concentrating on all types of large robotic machines.' + Top = 23 + Width = 93 + AllowGrayed = True + Caption = 'Mecha' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 17 + end + object ckFilterMusical: TCheckBox + Left = 193 + Height = 19 + Hint = 'Musical' + Top = 46 + Width = 93 + AllowGrayed = True + Caption = 'Musical' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 18 + end + object ckFilterMystery: TCheckBox + Left = 193 + Height = 19 + Hint = 'Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it.' + Top = 69 + Width = 93 + AllowGrayed = True + Caption = 'Mystery' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 19 + end + object ckFilterPsychological: TCheckBox + Left = 193 + Height = 19 + Hint = 'Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology.' + Top = 92 + Width = 93 + AllowGrayed = True + Caption = 'Psychological' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 20 + end + object ckFilterRomance: TCheckBox + Left = 193 + Height = 19 + Hint = 'Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is.' + Top = 115 + Width = 93 + AllowGrayed = True + Caption = 'Romance' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 21 + end + object ckFilterSchoolLife: TCheckBox + Left = 193 + Height = 19 + Hint = 'Having a major setting of the story deal with some type of school.' + Top = 138 + Width = 93 + AllowGrayed = True + Caption = 'School Life' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 22 + end + object ckFilterSciFi: TCheckBox + Left = 193 + Height = 19 + Hint = 'Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world.' + Top = 161 + Width = 93 + AllowGrayed = True + Caption = 'Sci-Fi' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 23 + end + object ckFilterSeinen: TCheckBox + Left = 296 + Height = 19 + Hint = 'From Google: Seinen means ''young Man''. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood.' + Top = 0 + Width = 81 + AllowGrayed = True + Caption = 'Seinen' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 24 + end + object ckFilterShotacon: TCheckBox + Left = 296 + Height = 19 + Hint = 'Representing a sexual attraction to young or under-age boys.' + Top = 23 + Width = 81 + AllowGrayed = True + Caption = 'Shotacon' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 25 + end + object ckFilterShoujo: TCheckBox + Left = 296 + Height = 19 + Hint = 'A work intended and primarily written for females. Usually involves a lot of romance and strong character development.' + Top = 46 + Width = 81 + AllowGrayed = True + Caption = 'Shoujo' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 26 + end + object ckFilterShoujoAi: TCheckBox + Left = 296 + Height = 19 + Hint = 'Often synonymous with yuri, this can be thought of as somewhat less extreme. "Girl''''s Love", so to speak.' + Top = 69 + Width = 81 + AllowGrayed = True + Caption = 'Shoujo Ai' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 27 + end + object ckFilterShounen: TCheckBox + Left = 296 + Height = 19 + Hint = 'A work intended and primarily written for males. These works usually involve fighting and/or violence.' + Top = 92 + Width = 81 + AllowGrayed = True + Caption = 'Shounen' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 28 + end + object ckFilterShounenAi: TCheckBox + Left = 296 + Height = 19 + Hint = 'Often synonymous with yaoi, this can be thought of as somewhat less extreme. "Boy''''s Love", so to speak' + Top = 115 + Width = 81 + AllowGrayed = True + Caption = 'Shounen Ai' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 29 + end + object ckFilterSliceofLife: TCheckBox + Left = 296 + Height = 19 + Hint = 'As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own.' + Top = 138 + Width = 81 + AllowGrayed = True + Caption = 'Slice of Life' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 30 + end + object ckFilterSmut: TCheckBox + Left = 296 + Height = 19 + Hint = 'Deals with series that are considered profane or offensive, particularly with regards to sexual content.' + Top = 161 + Width = 81 + HelpType = htKeyword + AllowGrayed = True + Caption = 'Smut' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 31 + end + object ckFilterSports: TCheckBox + Left = 387 + Height = 19 + Hint = 'As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few.' + Top = 0 + Width = 87 + AllowGrayed = True + Caption = 'Sports' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 32 + end + object ckFilterSupernatural: TCheckBox + Left = 387 + Height = 19 + Hint = 'Usually entails amazing and unexplained powers or events which defy the laws of physics.' + Top = 23 + Width = 87 + AllowGrayed = True + Caption = 'Supernatural' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 33 + end + object ckFilterTragedy: TCheckBox + Left = 387 + Height = 19 + Hint = 'Contains events resulting in great loss and misfortune.' + Top = 46 + Width = 87 + AllowGrayed = True + Caption = 'Tragedy' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 34 + end + object ckFilterYaoi: TCheckBox + Left = 387 + Height = 19 + Hint = 'This work usually involves intimate relationships between men.' + Top = 69 + Width = 87 + AllowGrayed = True + Caption = 'Yaoi' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 35 + end + object ckFilterYuri: TCheckBox + Left = 387 + Height = 19 + Hint = 'This work usually involves intimate relationships between women.' + Top = 92 + Width = 87 + AllowGrayed = True + Caption = 'Yuri' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 36 + end + object ckFilterWeebtons: TCheckBox + Left = 387 + Height = 19 + Hint = 'Weebtoons' + Top = 115 + Width = 87 + AllowGrayed = True + Caption = 'Weebtoons' + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 37 + end + end + object pnFilter: TPanel + Left = 0 + Height = 192 + Top = 232 + Width = 606 + Align = alTop + BevelOuter = bvNone + ClientHeight = 192 + ClientWidth = 606 + ParentFont = False + TabOrder = 1 + object rbOne: TRadioButton + Left = 323 + Height = 19 + Top = 32 + Width = 169 + Caption = 'Have one of genres checked' + ParentFont = False + TabOrder = 1 + end + object rbAll: TRadioButton + Left = 323 + Height = 19 + Top = 8 + Width = 142 + Caption = 'Have all genre checked' + Checked = True + ParentFont = False + TabOrder = 0 + TabStop = True + end + object cbOnlyNew: TCheckBox + Left = 323 + Height = 19 + Top = 56 + Width = 146 + Caption = 'Search only new manga' + ParentFont = False + TabOrder = 2 + end + object edFilterTitle: TEdit + Left = 135 + Height = 23 + Top = 8 + Width = 175 + TabOrder = 3 + TextHint = 'Title' + end + object edFilterArtists: TEdit + Left = 135 + Height = 23 + Top = 56 + Width = 175 + TabOrder = 4 + TextHint = 'Artist' + end + object edFilterAuthors: TEdit + Left = 135 + Height = 23 + Top = 32 + Width = 175 + TabOrder = 5 + TextHint = 'Author' + end + object lbFilterTitle: TLabel + Left = 23 + Height = 17 + Top = 8 + Width = 28 + Alignment = taRightJustify + BidiMode = bdRightToLeft + Caption = 'Title' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object lbFilterAuthors: TLabel + Left = 23 + Height = 17 + Top = 32 + Width = 43 + Alignment = taRightJustify + BidiMode = bdRightToLeft + Caption = 'Author' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object lbFilterArtists: TLabel + Left = 23 + Height = 17 + Top = 56 + Width = 34 + Alignment = taRightJustify + BidiMode = bdRightToLeft + Caption = 'Artist' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object cbFilterStatus: TComboBox + Left = 135 + Height = 23 + Top = 80 + Width = 175 + ItemHeight = 15 + ItemIndex = 2 + Items.Strings = ( + 'Completed' + 'Ongoing' + '' + ) + Style = csDropDownList + TabOrder = 6 + Text = '' + end + object lbFilterStatus: TLabel + Left = 23 + Height = 17 + Top = 80 + Width = 38 + Alignment = taRightJustify + BidiMode = bdRightToLeft + Caption = 'Status' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object lbFilterSummary: TLabel + Left = 23 + Height = 17 + Top = 104 + Width = 59 + Alignment = taRightJustify + BidiMode = bdRightToLeft + Caption = 'Summary' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterSummary: TEdit + Left = 135 + Height = 23 + Top = 104 + Width = 175 + TabOrder = 7 + TextHint = 'Part of summary' + end + object btRemoveFilterLarge: TBitBtn + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 191 + Height = 37 + Hint = 'Remove filter' + Top = 139 + Width = 136 + Caption = 'Remove filter' + Font.Height = -13 + Font.Style = [fsBold] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000080000000000005A000000770000008000000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A000000110000000400005A00000077000000770000008000000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578040426000000 + 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 + 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 + A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 + A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C + 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 250027275200101090000000AA000000AA000000AA000000A700363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535004343430035355F00121291000000AA000000A700363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A43434300464646004646460035355F0023237700363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btRemoveFilterClick + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 8 + end + object cbSearchFromAllSites: TCheckBox + Left = 323 + Height = 19 + Top = 80 + Width = 149 + Caption = 'Search in all manga sites' + TabOrder = 9 + end + object btFilter: TBitBtn + Left = 39 + Height = 37 + Top = 139 + Width = 130 + Caption = 'Filter' + Font.Height = -13 + Font.Style = [fsBold] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000089C5106999C51065CA75C0D00B56A1800000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A0000001100000004A75C0DCCA75C0DCCA95E0E5CB56A1800000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578B76C1999B56A + 18CCB56A18CCB56A18CCB56A18CCFFC538FFB56A18CCB76C195C000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097EC37923CCFFE3 + 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87D0852D99D287 + 2ECCD2872ECCD2872ECCD2872ECCFFE597FFD2872ECCD0852D5C000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B89714C1F00D58A + 3100D58A3100D98E3400DF9438CCDF9438CCDE93375CD2872E001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B8912121200A870 + 2D00D58A3100E69B3D00E79C3E99E79C3E5CDF943800D2872E00363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 25005C4A3300E69B3D00E89D3F00E89D3F00DF943800D2872E00363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535006B594100E89D3F00E89D3F00DF943800D2872E00363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A434343006F5D450097724300936D3F008C673A00363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btFilterClick + ParentFont = False + TabOrder = 10 + end + object btFilterReset: TBitBtn + Left = 345 + Height = 37 + Top = 139 + Width = 128 + Caption = 'Reset value' + Font.Height = -13 + Font.Style = [fsBold] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000050000001E000000320000003300000082000000830101014E0000 + 003300000033000000220000000800000000FFFFFF00FFFFFF00FFFFFF000000 + 0000000000030000000F000000190000001A00000078D1C2C2FF0303037A0000 + 001A0000001A000000110000000400000000FFFFFF00FFFFFF00FFFFFF000000 + 00000000000000000000000000000202020002020272C4B5B5FF050505780505 + 050000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 + 00000000000000000000010101000101010001010174C4B5B5FF0909097E0A0A + 0A0008080800000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 + 0000000000000000000000000000000000000000007AC4B5B5FF0B0B0B870D0D + 0D000D0D0D000A0A0A000000000000000000FFFFFF00FFFFFF00FFFFFF000000 + 0000000000000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D + 0D000D0D0D000D0D0D000A0A0A0007070700FFFFFF00FFFFFF00FFFFFF001B1B + 1B00161616000404040000000000000000000000007BC4B5B5FF0B0B0B891212 + 12001919190021212100282828002A2A2A00FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717 + 172F25252500353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF1717 + 17852525252D353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7 + C7FF2525257E3535352A4343430046464600FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBC + BCFFDFCDCDFF353535774343432846464600FFFFFF00FFFFFF00FFFFFF004B4B + 4B002C2C2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5 + B5FFDCCACAFFEBDADAFF4343436F4E4E4E00FFFFFF00FFFFFF00FFFFFF004F4F + 4F662C2C2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C + 9CFFB6ADADFFC5BCBCFF4343436F4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F + 4F66EAEAEAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4 + C4FFE4D2D2FFF0DFDFFFF9E8E8FF4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F + 4F4D2C2C2C6608080866000000660000006A0000007B020202890B0B0B891717 + 17852525257E353535774343436F4F4F4F4FFFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btFilterResetClick + ParentFont = False + TabOrder = 11 + end + object cbUseRegExpr: TCheckBox + Left = 323 + Height = 19 + Top = 104 + Width = 118 + Caption = 'Regular Expression' + TabOrder = 12 + end + end + object pnCustomGenre: TPanel + Left = 0 + Height = 42 + Top = 190 + Width = 606 + Align = alTop + BevelOuter = bvNone + ClientHeight = 42 + ClientWidth = 606 + TabOrder = 2 + object lbFilterCustomGenres: TLabel + Left = 23 + Height = 17 + Top = 10 + Width = 93 + Alignment = taRightJustify + BidiMode = bdRightToLeft + Caption = 'Custom Genres' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edCustomGenres: TEdit + Left = 135 + Height = 23 + Top = 10 + Width = 416 + ParentFont = False + TabOrder = 0 + TextHint = 'Input custom genres, separated by comma' + end + object lbFilterHint: TLabel + Left = 555 + Height = 15 + Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''''!'''' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' + Top = 13 + Width = 13 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object Bevel1: TBevel + Left = 0 + Height = 5 + Top = 37 + Width = 606 + Align = alBottom + Shape = bsBottomLine + end + end + end + end + object tsFavorites: TTabSheet + Caption = 'Favorites' + ClientHeight = 480 + ClientWidth = 606 + object btFavoritesCheckNewChapter: TBitBtn + Left = 33 + Height = 40 + Top = 400 + Width = 545 + Anchors = [akLeft, akRight, akBottom] + Caption = 'Check for new chapter' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 + 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 + 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB + E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 + 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 + E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 + 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 + D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 + 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 + BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 + 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 + 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 + 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F + 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 + 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D + 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 + 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F + 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 + 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 + 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 + 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 + 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 + 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 + 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 + 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 + 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 + 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 + 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 + E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 + 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550073AA550000AA550000 + } + OnClick = btFavoritesCheckNewChapterClick + TabOrder = 1 + end + object vtFavorites: TVirtualStringTree + Left = 2 + Height = 389 + Top = 4 + Width = 600 + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Left = 2 + BorderSpacing.Top = 4 + BorderSpacing.Right = 4 + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Alignment = taRightJustify + Position = 0 + Text = '#' + end + item + Position = 1 + Text = 'Title' + Width = 150 + end + item + Position = 2 + Text = 'Current chapter' + Width = 100 + end + item + Position = 3 + Text = 'Website' + Width = 65 + end + item + Position = 4 + Text = 'Save to' + Width = 200 + end> + Header.DefaultHeight = 24 + Header.Height = 24 + Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] + HintMode = hmHintAndDefault + Images = IconList + IncrementalSearch = isVisibleOnly + Margin = 0 + ParentFont = False + ParentShowHint = False + PopupMenu = pmFavorites + ShowHint = True + TabOrder = 0 + TextMargin = 2 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnBeforeCellPaint = vtFavoritesBeforeCellPaint + OnColumnDblClick = vtFavoritesColumnDblClick + OnFreeNode = vtFavoritesFreeNode + OnGetText = vtFavoritesGetText + OnGetImageIndex = vtFavoritesGetImageIndex + OnGetHint = vtFavoritesGetHint + OnHeaderClick = vtFavoritesHeaderClick + OnInitNode = vtFavoritesInitNode + end + object btFavoritesImport: TBitBtn + Left = 33 + Height = 24 + Top = 446 + Width = 545 + Anchors = [akLeft, akRight, akBottom] + Caption = 'Import list' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF000000001600000032000076A40000764D0000002D000000330000002D0000 + 764D000076A4000000330000001AFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000000000B000000190000A8C50000A8C500007F450000590000007F450000 + A8C50000A8C50000001A0000000DFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000000000000008A000000B6BF6868FFFF0000B6BF0000B6720000B6BF6868 + FFFF0000B6BF00008A0000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00010190000101BF000101BFBB6262F8FF6A6AFFFF0101BFBB6A6AFFFF6262 + F8FF0101BFBB0101BF0001019000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101C3000101C3000101C3B96464F8FF5B5BF1FF6C6CFFFF5B5BF1FF6464 + F8FF0101C3B90101C3000101C300FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101B7000101C7000101C7B86767F9FF2727BFFF1919B2FF4949DEFF6767 + F9FF0101C7B80101C7000101C700FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000000A8000101AF000101CBB66A6AFAFF1A1AB3FFA6A6FFFF3636CDFF6161 + F2FF0101CBB60101CB000101CB00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000000A9930000A8C40000A8C42121BAFF2121BAFF8484EEFF8E8EFBFF5E5E + EEFF0101CEB50101CE000101CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000000B1C1AAAAFFFFAAAAFFFFAAAAFFFFAAAAFFFFA6A6FFFF9090FCFF7D7D + FCFF0101D2B30101D2000101D200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101BA8E0101BBBD0101BBBD3131CAFF3131CAFF8888F1FF9191FDFF6666 + F3FF0101D5B20101D5000101D500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101BB000101C4000101D9B17676FDFF3939D2FFA7A7FFFF4E4EE2FF7070 + F9FF0101D9B10101D9000101D900FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101CC000101DC000101DCAF7979FEFF4D4DE3FF4545DDFF6363F2FF7979 + FEFF0101DCAF0101DC000101DC00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101DE000101DE000101DEAE7C7CFEFF7373FDFF7373FDFF7373FDFF7C7C + FEFF0101DEAE0101DE000101DE00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101E1000101E1000101E1AD7E7EFFFF7575FEFF7575FEFF7575FEFF7E7E + FFFF0101E1AD0101E1000101E100FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101E3000101E3000101E3AC8484FFFF7F7FFFFF7F7FFFFF7F7FFFFF8484 + FFFF0101E3AC0101E3000101E300FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000101E4000101E4000101E5810101E5AB0101E5AB0101E5AB0101E5AB0101 + E5AB0101E5810101E4000101E400FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btFavoritesImportClick + ParentFont = False + TabOrder = 2 + end + object btCancelFavoritesCheck: TSpeedButton + Left = 538 + Height = 40 + Top = 400 + Width = 40 + Anchors = [akRight, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + Visible = False + OnClick = btCancelFavoritesCheckClick + end + end + object tsOption: TTabSheet + Caption = 'Options' + ClientHeight = 480 + ClientWidth = 606 + object pnOptions: TPageControl + Left = 9 + Height = 403 + Top = 8 + Width = 587 + ActivePage = tsGeneral + Anchors = [akTop, akLeft, akRight, akBottom] + ParentFont = False + TabIndex = 0 + TabOrder = 0 + object tsGeneral: TTabSheet + Caption = 'General' + ClientHeight = 375 + ClientWidth = 579 + object cbLanguages: TComboBox + Left = 20 + Height = 23 + Top = 34 + Width = 212 + ItemHeight = 15 + Items.Strings = ( + 'English' + ) + ParentFont = False + Style = csDropDownList + TabOrder = 0 + end + object lbOptionLanguage: TLabel + Left = 20 + Height = 15 + Top = 18 + Width = 55 + Caption = 'Language:' + ParentColor = False + end + object seOptionNewMangaTime: TSpinEdit + Left = 20 + Height = 23 + Top = 112 + Width = 58 + MaxValue = 365 + MinValue = 1 + ParentFont = False + TabOrder = 1 + Value = 1 + end + object lbOptionNewMangaTime: TLabel + Left = 86 + Height = 15 + Top = 115 + Width = 238 + Caption = 'New manga based on it''s update time (days)' + ParentColor = False + ParentFont = False + end + object cbOptionMinimizeToTray: TCheckBox + Left = 20 + Height = 19 + Top = 200 + Width = 106 + Caption = 'Minimize to tray' + ParentFont = False + TabOrder = 2 + end + object cbOptionLetFMDDo: TComboBox + Left = 20 + Height = 23 + Top = 80 + Width = 212 + ItemHeight = 15 + Items.Strings = ( + 'Do nothing' + 'Exit FMD' + 'Shutdown' + 'Hibernate' + ) + ParentFont = False + Style = csDropDownList + TabOrder = 3 + end + object lbOptionLetFMDDo: TLabel + Left = 20 + Height = 15 + Top = 64 + Width = 117 + Caption = 'After download finish:' + ParentColor = False + end + object gbOptionExternal: TGroupBox + Left = 20 + Height = 132 + Top = 228 + Width = 520 + Anchors = [akTop, akLeft, akRight] + Caption = 'External program' + ClientHeight = 112 + ClientWidth = 516 + ParentFont = False + TabOrder = 4 + object edOptionExternalParams: TEdit + Left = 13 + Height = 23 + Top = 74 + Width = 467 + Anchors = [akTop, akLeft, akRight] + TabOrder = 0 + TextHint = 'External program parameters' + end + object lbOptionExternal: TLabel + Left = 13 + Height = 15 + Top = 6 + Width = 213 + Caption = 'Open manga by using external program:' + ParentColor = False + end + object lbOptionExternalParamsHint: TLabel + Left = 485 + Height = 15 + Top = 77 + Width = 13 + Anchors = [akTop, akRight] + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object lbOptionExternalParams: TLabel + Left = 13 + Height = 15 + Top = 56 + Width = 62 + Caption = 'Parameters:' + ParentColor = False + end + object edOptionExternalPath: TFileNameEdit + Left = 13 + Height = 23 + Top = 24 + Width = 491 + FilterIndex = 0 + HideDirectories = False + ButtonWidth = 23 + NumGlyphs = 1 + Anchors = [akTop, akLeft, akRight] + MaxLength = 0 + TabOrder = 1 + TextHint = 'External program path' + end + end + object cbOptionOneInstanceOnly: TCheckBox + Left = 20 + Height = 19 + Top = 176 + Width = 177 + Caption = 'Permit only one FMD running' + ParentFont = False + TabOrder = 5 + end + object cbOptionLiveSearch: TCheckBox + Left = 20 + Height = 19 + Top = 152 + Width = 210 + Caption = 'Enable live search (slow on long list)' + ParentFont = False + TabOrder = 6 + end + end + object tsView: TTabSheet + Caption = 'View' + ClientHeight = 375 + ClientWidth = 579 + object cbOptionShowDownloadToolbar: TCheckBox + Left = 16 + Height = 19 + Top = 232 + Width = 151 + Caption = 'Show downloads toolbar' + ParentFont = False + TabOrder = 0 + end + object gbDropTarget: TGroupBox + Left = 16 + Height = 200 + Top = 16 + Width = 312 + Caption = 'Drop Box' + ClientHeight = 180 + ClientWidth = 308 + TabOrder = 1 + object ckDropTarget: TCheckBox + Left = 16 + Height = 19 + Top = 9 + Width = 100 + Caption = 'Show Drop Box' + ParentFont = False + TabOrder = 0 + end + object tbDropTargetOpacity: TTrackBar + Left = 16 + Height = 33 + Top = 128 + Width = 280 + Frequency = 15 + Max = 255 + Min = 5 + OnChange = tbDropTargetOpacityChange + Position = 200 + TabOrder = 1 + end + object lbDropTargetOpacity: TLabel + Left = 16 + Height = 15 + Top = 112 + Width = 41 + Caption = 'Opacity' + ParentColor = False + ParentFont = False + end + object rgDropTargetMode: TRadioGroup + Left = 16 + Height = 58 + Top = 40 + Width = 120 + AutoFill = True + AutoSize = True + Caption = 'Mode' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 38 + ClientWidth = 116 + ItemIndex = 0 + Items.Strings = ( + 'Download all' + 'Add to favorites' + ) + ParentFont = False + TabOrder = 2 + end + end + object cbOptionEnableLoadCover: TCheckBox + Left = 16 + Height = 19 + Top = 256 + Width = 153 + Caption = 'Enable load manga cover' + ParentFont = False + TabOrder = 2 + end + end + object tsConnections: TTabSheet + Caption = 'Connections' + ClientHeight = 375 + ClientWidth = 579 + object sbDownloadConnections: TScrollBox + Left = 0 + Height = 375 + Top = 0 + Width = 579 + HorzScrollBar.Page = 457 + VertScrollBar.Page = 179 + Align = alClient + BorderStyle = bsNone + ClientHeight = 375 + ClientWidth = 579 + TabOrder = 0 + object cbOptionUseProxy: TCheckBox + Left = 12 + Height = 19 + Top = 160 + Width = 71 + Caption = 'Use proxy' + OnChange = cbOptionUseProxyChange + ParentFont = False + TabOrder = 0 + end + object gbOptionProxy: TGroupBox + Left = 12 + Height = 120 + Top = 184 + Width = 561 + Anchors = [akTop, akLeft, akRight] + Caption = 'Proxy config' + ClientHeight = 100 + ClientWidth = 557 + Enabled = False + ParentFont = False + TabOrder = 1 + object lbOptionHost: TLabel + Left = 16 + Height = 15 + Top = 40 + Width = 25 + Caption = 'Host' + ParentColor = False + ParentFont = False + end + object lbOptionPort: TLabel + Left = 16 + Height = 15 + Top = 72 + Width = 22 + Caption = 'Port' + ParentColor = False + end + object edOptionHost: TEdit + Left = 57 + Height = 23 + Top = 38 + Width = 154 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Default' + ParentFont = False + TabOrder = 0 + TextHint = 'Proxy host/IP' + end + object edOptionPort: TEdit + Left = 57 + Height = 23 + Top = 70 + Width = 154 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Default' + ParentFont = False + TabOrder = 1 + TextHint = 'Proxy Port' + end + object lbOptionUser: TLabel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 232 + Height = 15 + Top = 40 + Width = 53 + Caption = 'Username' + ParentColor = False + end + object lbOptionPass: TLabel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 233 + Height = 15 + Top = 72 + Width = 50 + Caption = 'Password' + ParentColor = False + end + object edOptionUser: TEdit + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 297 + Height = 23 + Top = 38 + Width = 154 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Default' + ParentFont = False + TabOrder = 2 + TextHint = 'Proxy username' + end + object edOptionPass: TEdit + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 297 + Height = 23 + Top = 70 + Width = 154 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Default' + ParentFont = False + TabOrder = 3 + TextHint = 'Proxy password' + end + object cbOptionProxyType: TComboBox + Left = 57 + Height = 23 + Top = 6 + Width = 154 + ItemHeight = 15 + ItemIndex = 0 + Items.Strings = ( + 'HTTP' + 'SOCKS4' + 'SOCKS5' + ) + Style = csDropDownList + TabOrder = 4 + Text = 'HTTP' + end + object lbOptionProxyType: TLabel + Left = 15 + Height = 15 + Top = 8 + Width = 26 + Caption = 'Type' + ParentColor = False + end + end + object seOptionMaxParallel: TSpinEdit + Left = 12 + Height = 23 + Top = 26 + Width = 48 + MaxValue = 8 + MinValue = 1 + ParentFont = False + ParentShowHint = False + TabOrder = 2 + Value = 1 + end + object lbOptionMaxParallel: TLabel + Left = 66 + Height = 15 + Top = 29 + Width = 292 + Caption = 'Number of downloaded tasks at the same time (Max: 8)' + ParentColor = False + ParentFont = False + end + object lbOptionMaxThread: TLabel + Left = 66 + Height = 15 + Top = 61 + Width = 337 + Caption = 'Number of downloaded files per task at the same time (Max: 32)' + ParentColor = False + ParentFont = False + end + object seOptionMaxThread: TSpinEdit + Left = 12 + Height = 23 + Top = 58 + Width = 48 + MaxValue = 32 + MinValue = 1 + ParentFont = False + ParentShowHint = False + TabOrder = 3 + Value = 1 + end + object seOptionMaxRetry: TSpinEdit + Left = 12 + Height = 23 + Top = 90 + Width = 48 + MinValue = -1 + ParentFont = False + ParentShowHint = False + TabOrder = 4 + end + object lbOptionMaxRetry: TLabel + Left = 66 + Height = 15 + Top = 93 + Width = 391 + Caption = 'Number of retry times if tasks have download problems (-1 = always retry)' + ParentColor = False + ParentFont = False + end + object seOptionConnectionTimeout: TSpinEdit + Left = 12 + Height = 23 + Top = 120 + Width = 48 + MaxValue = 300 + MinValue = 1 + ParentFont = False + ParentShowHint = False + TabOrder = 5 + Value = 30 + end + object lbOptionConnectionTimeout: TLabel + Left = 66 + Height = 15 + Top = 123 + Width = 161 + Caption = 'Connection timeout (seconds)' + ParentColor = False + ParentFont = False + end + end + end + object tsSaveTo: TTabSheet + Caption = 'Save to' + ClientHeight = 375 + ClientWidth = 579 + object rgOptionCompress: TRadioGroup + Left = 20 + Height = 60 + Top = 66 + Width = 520 + Anchors = [akTop, akLeft, akRight] + AutoFill = True + Caption = 'Save downloaded chapters as' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 4 + ClientHeight = 40 + ClientWidth = 516 + Columns = 4 + ItemIndex = 0 + Items.Strings = ( + 'None' + 'ZIP' + 'CBZ' + 'PDF' + ) + ParentFont = False + TabOrder = 0 + end + object gbOptionRenaming: TGroupBox + Left = 20 + Height = 196 + Top = 170 + Width = 520 + Anchors = [akTop, akLeft, akRight] + Caption = 'Renaming' + ClientHeight = 176 + ClientWidth = 516 + ParentFont = False + TabOrder = 1 + object cbOptionGenerateMangaFolderName: TCheckBox + Left = 22 + Height = 19 + Top = 36 + Width = 261 + Caption = 'Auto generate folder based on manga''s name' + ParentFont = False + TabOrder = 0 + end + object cbOptionGenerateChapterName: TCheckBox + Left = 294 + Height = 19 + Top = 52 + Width = 246 + Caption = 'Generate chapter folder with chapter name' + ParentFont = False + TabOrder = 1 + Visible = False + end + object cbOptionPathConvert: TCheckBox + Left = 22 + Height = 19 + Top = 14 + Width = 517 + Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' + ParentFont = False + TabOrder = 2 + end + object cbOptionAutoNumberChapter: TCheckBox + Left = 294 + Height = 19 + Top = 36 + Width = 134 + Caption = 'Auto number chapter' + TabOrder = 3 + Visible = False + end + object edOptionCustomRename: TEdit + Left = 22 + Height = 23 + Top = 140 + Width = 434 + Anchors = [akTop, akLeft, akRight] + TabOrder = 4 + TextHint = 'Custom rename' + end + object lbOptionCustomRename: TLabel + Left = 22 + Height = 15 + Top = 124 + Width = 112 + Caption = 'Chapter folder name:' + ParentColor = False + end + object lbOptionCustomRenameHint: TLabel + Left = 462 + Height = 15 + Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' + Top = 142 + Width = 13 + Anchors = [akTop, akRight] + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object lbOptionRenameDigits: TLabel + Left = 22 + Height = 15 + Top = 68 + Width = 78 + Caption = 'Rename digits' + ParentColor = False + end + object seOptionDigitVolume: TSpinEdit + Left = 94 + Height = 23 + Top = 90 + Width = 50 + MaxValue = 10 + MinValue = 1 + TabOrder = 5 + Value = 1 + end + object seOptionDigitChapter: TSpinEdit + Left = 230 + Height = 23 + Top = 90 + Width = 50 + MaxValue = 10 + MinValue = 1 + TabOrder = 6 + Value = 1 + end + object cbOptionDigitVolume: TCheckBox + Left = 25 + Height = 19 + Top = 92 + Width = 61 + Caption = 'Volume' + OnChange = cbOptionDigitVolumeChange + TabOrder = 7 + end + object cbOptionDigitChapter: TCheckBox + Left = 158 + Height = 19 + Top = 92 + Width = 62 + Caption = 'Chapter' + OnChange = cbOptionDigitChapterChange + TabOrder = 8 + end + end + object seOptionPDFQuality: TSpinEdit + Left = 44 + Height = 23 + Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' + Top = 132 + Width = 50 + MinValue = 5 + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 2 + Value = 100 + end + object lbOptionPDFQuality: TLabel + Left = 103 + Height = 15 + Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' + Top = 135 + Width = 119 + Caption = 'PDF compression level' + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object lbOptionCustomRenameHint1: TLabel + Left = 260 + Height = 15 + Hint = '100: FlateEncode (lossless), lower: DCTEncode (lossy)' + Top = 135 + Width = 13 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object btOptionBrowse: TSpeedButton + Left = 512 + Height = 23 + Top = 34 + Width = 23 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOptionBrowseClick + end + object edOptionDefaultPath: TEdit + Left = 20 + Height = 23 + Top = 34 + Width = 490 + Anchors = [akTop, akLeft, akRight] + ParentFont = False + TabOrder = 3 + TextHint = 'Default download path' + end + object lbDefaultDownloadPath: TLabel + Left = 20 + Height = 15 + Top = 15 + Width = 186 + Caption = 'Choose the default download path:' + ParentColor = False + ParentFont = False + end + end + object tsUpdate: TTabSheet + Caption = 'Updates' + ClientHeight = 375 + ClientWidth = 579 + object cbOptionAutoCheckLatestVersion: TCheckBox + Left = 16 + Height = 19 + Top = 16 + Width = 173 + Caption = 'Auto check for latest version ' + ParentFont = False + TabOrder = 0 + end + object gbOptionFavorites: TGroupBox + Left = 17 + Height = 178 + Top = 48 + Width = 520 + Anchors = [akTop, akLeft, akRight] + Caption = 'Favorites' + ClientHeight = 158 + ClientWidth = 516 + ParentFont = False + TabOrder = 1 + object cbOptionAutoCheckFavStartup: TCheckBox + Left = 16 + Height = 19 + Top = 8 + Width = 219 + Caption = 'Auto check for new chapter at startup' + ParentFont = False + TabOrder = 3 + end + object seOptionAutoCheckFavIntervalMinutes: TSpinEdit + Left = 16 + Height = 23 + Top = 56 + Width = 58 + MaxValue = 1440 + OnChange = seOptionAutoCheckFavIntervalMinutesChange + TabOrder = 0 + end + object lbOptionAutoCheckFavIntervalMinutes: TLabel + Left = 82 + Height = 15 + Top = 60 + Width = 243 + Caption = 'Auto check for new chapter every %d minutes' + ParentColor = False + end + object cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox + Left = 16 + Height = 19 + Top = 120 + Width = 298 + Caption = 'Automatic remove completed manga from Favorites' + TabOrder = 1 + end + object cbOptionAutoCheckFavDownload: TCheckBox + Left = 16 + Height = 19 + Top = 96 + Width = 242 + Caption = 'Automatic download after finish checking' + ParentFont = False + TabOrder = 2 + end + object cbOptionAutoCheckFavInterval: TCheckBox + Left = 16 + Height = 19 + Top = 32 + Width = 237 + Caption = 'Auto check for new chapter in an interval' + OnChange = cbOptionAutoCheckFavIntervalChange + ParentFont = False + TabOrder = 4 + end + end + object cbOptionUpdateListNoMangaInfo: TCheckBox + Left = 17 + Height = 19 + Top = 242 + Width = 407 + Caption = 'Don''t load manga information when updating list (filter will be not work!)' + ParentFont = False + TabOrder = 2 + end + object cbOptionUpdateListRemoveDuplicateLocalData: TCheckBox + Left = 17 + Height = 19 + Top = 266 + Width = 310 + Caption = 'Remove duplicate local data when updating manga list' + ParentFont = False + TabOrder = 3 + Visible = False + end + end + object tsDialogs: TTabSheet + Caption = 'Dialogs' + ClientHeight = 375 + ClientWidth = 579 + object gbDialogs: TGroupBox + Left = 10 + Height = 346 + Top = 14 + Width = 556 + Anchors = [akTop, akLeft, akRight, akBottom] + ClientHeight = 326 + ClientWidth = 552 + TabOrder = 0 + object cbOptionShowQuitDialog: TCheckBox + Left = 24 + Height = 19 + Top = 32 + Width = 66 + Caption = 'Exit FMD' + ParentFont = False + TabOrder = 0 + end + object lbOptionDialogs: TLabel + Left = 16 + Height = 15 + Top = 8 + Width = 158 + Caption = 'Show dialog confirmation for:' + ParentColor = False + end + object cbOptionShowDeleteTaskDialog: TCheckBox + Left = 24 + Height = 19 + Top = 56 + Width = 122 + Caption = 'Delete task/favorite' + ParentFont = False + TabOrder = 1 + end + end + end + object tsWebsites: TTabSheet + Caption = 'Websites' + ClientHeight = 375 + ClientWidth = 579 + object vtOptionMangaSiteSelection: TVirtualStringTree + Left = 2 + Height = 336 + Top = 35 + Width = 573 + Align = alClient + BorderSpacing.Top = 2 + BorderSpacing.Right = 2 + BorderSpacing.Bottom = 2 + BorderSpacing.Around = 2 + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + IncrementalSearch = isVisibleOnly + Margin = 0 + ParentFont = False + TabOrder = 0 + TextMargin = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] + OnChange = vtOptionMangaSiteSelectionChange + OnFocusChanged = vtOptionMangaSiteSelectionFocusChanged + OnFreeNode = vtOptionMangaSiteSelectionFreeNode + OnGetText = vtOptionMangaSiteSelectionGetText + OnGetNodeDataSize = vtOptionMangaSiteSelectionGetNodeDataSize + OnInitNode = vtOptionMangaSiteSelectionInitNode + end + object pnlWebsitesTool: TPanel + Left = 2 + Height = 23 + Top = 6 + Width = 573 + Align = alTop + BorderSpacing.Top = 4 + BorderSpacing.Right = 2 + BorderSpacing.Bottom = 4 + BorderSpacing.Around = 2 + BevelOuter = bvNone + ClientHeight = 23 + ClientWidth = 573 + TabOrder = 1 + object edWebsitesSearch: TEdit + Left = 0 + Height = 23 + Top = 0 + Width = 184 + Align = alLeft + BorderSpacing.Right = 2 + OnChange = edWebsitesSearchChange + TabOrder = 0 + TextHint = 'Search website...' + end + object btWebsitesSearchClear: TSpeedButton + Left = 186 + Height = 23 + Top = 0 + Width = 22 + Align = alLeft + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btWebsitesSearchClearClick + end + object pnlWebsitesToolRight: TPanel + Left = 403 + Height = 23 + Top = 0 + Width = 170 + Align = alRight + AutoSize = True + BevelOuter = bvNone + ClientHeight = 23 + ClientWidth = 170 + TabOrder = 1 + object ToolBarWebsites: TToolBar + Left = 0 + Height = 22 + Top = 0 + Width = 170 + AutoSize = True + EdgeBorders = [] + Images = IconList + List = True + ParentFont = False + ShowCaptions = True + TabOrder = 0 + Transparent = True + object tbWebsitesExpandAll: TToolButton + Left = 1 + Top = 0 + AutoSize = True + Caption = 'Expand All' + ImageIndex = 17 + OnClick = tbWebsitesExpandAllClick + end + object tbWebsitesCollapseAll: TToolButton + Left = 82 + Top = 0 + AutoSize = True + Caption = 'Collapse All' + ImageIndex = 18 + OnClick = tbWebsitesCollapseAllClick + end + end + end + end + end + object tsMisc: TTabSheet + Caption = 'Misc' + ClientHeight = 375 + ClientWidth = 579 + object gbMisc: TGroupBox + Left = 12 + Height = 349 + Top = 12 + Width = 556 + Anchors = [akTop, akLeft, akRight, akBottom] + ClientHeight = 329 + ClientWidth = 552 + TabOrder = 0 + object cbOptionBatotoShowAllLang: TCheckBox + Left = 16 + Height = 19 + Top = 40 + Width = 167 + Caption = '[Batoto] Show All Language' + ParentFont = False + TabOrder = 1 + end + object cbOptionBatotoShowScanGroup: TCheckBox + Left = 16 + Height = 19 + Top = 16 + Width = 190 + Caption = '[Batoto] Show scan group name' + ParentFont = False + TabOrder = 0 + end + object cbOptionMangaFoxRemoveWatermarks: TCheckBox + Left = 16 + Height = 19 + Top = 88 + Width = 317 + Caption = '[Mangafox] Remove watermarks (Beware! Experimental!)' + ParentFont = False + TabOrder = 2 + Visible = False + end + end + end + end + object btOptionApply: TBitBtn + Left = 8 + Height = 41 + Top = 425 + Width = 128 + Anchors = [akLeft, akBottom] + Caption = 'Apply' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 + 0004000000170000002B011A004302440080025A00AB025D00C4025D00C4025A + 00AB02440080011A00430000002D0000001800000004FFFFFF00FFFFFF000000 + 0000031F00000553004D087402BF139D08E31DC40EF521D411FD21D411FD1DC4 + 0EF5139D08E3087402BF0553004D031F000000000000FFFFFF00FFFFFF000B83 + 00000B7F004D0E8804CD21C411F623D112FF22B611FF22D111FF22D111FF22D1 + 11FF22D111FF1EC20FF60D8803CD0B7F004D0B830000FFFFFF00FFFFFF000C85 + 001A0F8A03BF27C017F623C812FF22B211FFE6E6E6FF22B211FF22C811FF22C8 + 11FF22C811FF22C811FF1FBC0FF60D8902BF0C85001AFFFFFF00FFFFFF000D89 + 006C22A813E326C015FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE + 11FF22BE11FF22BE11FF22BE11FF17A109E30D89006CFFFFFF00FFFFFF000E8D + 00A73BBD2BF523AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 + 11FF22B411FF22B411FF22B411FF21AF11F50E8D00A7FFFFFF00FFFFFF000F92 + 00C450C83FFDA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 + E6FF22A311FF22AA11FF22AA11FF28AE17FD0F9200C4FFFFFF00FFFFFF001096 + 00C453CB42FD3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 + E2FFE6E6E6FF229E11FF22A111FF2CAA1BFD109600C4FFFFFF00FFFFFF00119A + 00A751CB40F547BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 + E2FFE3E3E3FFE7E7E7FF269E15FF34B023F5119A00A7FFFFFF00FFFFFF00129E + 006C3DBF2CE354CB43FF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB + 33FFFFFFFFFFA7E29EFF52C941FF36B925E3129E006CFFFFFF00FFFFFF0013A1 + 001A1AA707BF5CD74BF658CF47FF57CE46FF57CE46FF57CE46FF57CE46FF57CE + 46FF4AC139FF52C941FF57D245F619A606BF13A1001AFFFFFF00FFFFFF0013A2 + 000014A5004D21AF0ECD5FDA4EF663DA52FF5FD64EFF5FD64EFF5FD64EFF5FD6 + 4EFF62D951FF5DD94BF620AE0DCD14A5004D13A20000FFFFFF00FFFFFF0013A2 + 000014A5000014A8004D1BAD08BF42C82FE35FDC4EF56BE35AFD6BE359FD5FDB + 4EF541C72EE31BAD07BF14A8004D14A5000013A20000FFFFFF00FFFFFF0013A2 + 000014A5000014A8000015A9001A15AA006C15AA00A615AA00C415AA00C415AA + 00A615AA006C15A9001A14A8000014A5000013A20000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOptionApplyClick + TabOrder = 1 + end + end + object tsAbout: TTabSheet + Caption = 'About' + ChildSizing.LeftRightSpacing = 2 + ChildSizing.TopBottomSpacing = 2 + ClientHeight = 480 + ClientWidth = 606 + object btCheckLatestVersion: TBitBtn + Left = 25 + Height = 40 + Top = 429 + Width = 208 + Anchors = [akLeft, akBottom] + Caption = 'Check for latest version' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 00000000000600000010000000190000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A000000190000001500000010FFFFFF000000 + 00000000000B0000002011090133391E013E532A014345240240733A02A6984D + 02CC984D02CC984D02CC984D02CC984D02CC733A02A30000001FFFFFFF000000 + 000028160200763D0419A2580842C47E174EE4A01C54FCB9203F9C5105CCFDBC + 28FFFCB81DFFFCB81DFFFDC033FF9C5105CC9C51055C00000000FFFFFF00A65B + 0D00A3580B22AB62105FF8BA346DF6B01C6DF7B11E6BF8B52740A2570ACCF8B6 + 2AFFF6AC14FFF8BA35FFA2570ACCA2570A84A15609002A170400FFFFFF00A95E + 0F10AD641378F3B84390EFAB2A90E7A83691BF7A2078A85D0E33A85D0ECCF2B3 + 39FFF3B943FFEEA824FFF2B339FFAD6210BFA95E0F1AAA5F1000FFFFFF00AF64 + 144DCC8B33A6E8A83BB4E4A845B2AF641488AE631332AC611100AF6414CCF0BD + 5CFFAF6414CCECB148FFE8A83BFFCD8D34E3AF64146CAF641400FFFFFF00B66B + 198CE0A751CFE3A84ED6C98734BBB56A194AAF641400B66B1900B66B19CCB66B + 19CCB66B1994C98734DCE3A84EFFE0A851F5B66B19A7B66B1900FFFFFF00BE73 + 1FC1E7B466F1E5B061F1BE731FC1BB701D00C0752100C0752000BD721E99BD72 + 1E5CBA6F1C00BE731FCCE5B061FFE7B466FFBE731FCCBE731F00FFFFFF00C57A + 25CCE8B86FFFE6B46CFFC57A25CCC97E2700C67B265CC67B2699C1762100BE73 + 1F00C87D2700C57A25C1E6B46CF1E8B86FF1C57A25C1C57A2500FFFFFF00CD82 + 2AA7E8B66CF5E8B570FFDA9B48DCCD822A94CD822ACCCD822ACCCD822A00CF84 + 2C00CE832B4ADA9B47BBE8B570D6E8B66CCFCD822A8CCD822A00FFFFFF00D489 + 306CE4AB59E3EDBC76FFF1C67EFFD48930CCF7D38AFFD48930CCD88D3200D58A + 3132D4893088EEBF75B2EDBC76B4E4A958A6D489304DD4893000FFFFFF00DA8F + 341ADC9339BFF7CD85FFF2C27AFFF9D38AFFF7CD85FFDB9034CCDB903433E4A5 + 4F78F3C67991F4C57D90F8D28990DD953A78DA8F3410D98E3300FFFFFF00E196 + 3900E1963984E19639CCFCD88EFFF9CC82FFFCD58AFFE19639CCFCD48940FBD0 + 866BFACF856DFCD88D6DE49E435FE0953922DC913500DC913500FFFFFF00E69B + 3D5CE59A3DCCFFE094FFFED98DFFFED98DFFFFDC91FFE59A3DCCFEDA8E3FF8CB + 7B54F0B7604EE79F4242E59A3D19E1963900DC913500DC913500FFFFFF00E99E + 4099E99E40CCE99E40CCE99E40CCE99E40CCE99E40CCE99E4099E99E4020E99E + 4025E99E4019E89D3F06E59A3D00E1963900DC913500DC913500FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btCheckLatestVersionClick + TabOrder = 0 + end + object btAbortCheckLatestVersion: TSpeedButton + Left = 193 + Height = 40 + Top = 429 + Width = 40 + Anchors = [akLeft, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + Visible = False + OnClick = btAbortCheckLatestVersionClick + end + object btVisitMyBlog: TBitBtn + Left = 249 + Height = 40 + Top = 429 + Width = 208 + Anchors = [akLeft, akBottom] + Caption = 'Visit my blog' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0A0A0A660C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C + 0C770C0C0C770C0C0C770C0C0C770A0A0A660000002C00000012000000090000 + 00161F1F1F74EBEBEBFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 + E6FFE6E6E6FFE6E6E6FFEBEBEBFF1F1F1F740000001600000009000000002A2A + 2A0036363671E8E8E8FFB4B4B4FFBDBDBDFFC5C5C5FFBDBDBDFFCECECEFFE0E0 + E0FFE0E0E0FFE0E0E0FFE8E8E8FF363636712A2A2A0000000000343434004545 + 45004545456FEAEAEAFFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFE2E2 + E2FFE2E2E2FFE2E2E2FFEAEAEAFF4545456F45454500343434004B4B4B004B4B + 4B004B4B4B6EECECECFF8E8E8EFFA5A5A5FFA5A5A5FF8E8E8EFFD3D3D3FFE5E5 + E5FFC2C2C2FFB9B9B9FFECECECFF4B4B4B6E4B4B4B004B4B4B00515151005151 + 51005151516DEEEEEEFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 + E8FFD5D5D5FFD5D5D5FFEEEEEEFF5151516D5151510051515100575757005757 + 57005757576CF0F0F0FFBFBFBFFFC7C7C7FFD0D0D0FFC7C7C7FFD8D8D8FFEAEA + EAFFBFBFBFFFC7C7C7FFF0F0F0FF5757576C57575700575757005D5D5D005D5D + 5D005D5D5D6BF2F2F2FFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFEDED + EDFFDBDBDBFFDBDBDBFFF2F2F2FF5D5D5D6B5D5D5D005D5D5D00626262006262 + 62006262626BF5F5F5FF919191FFC4C4C4FFAAAAAAFFAAAAAAFF919191FFF1F1 + F1FFBBBBBBFFCCCCCCFFF5F5F5FF6262626B6262620062626200676767006767 + 67006767676AF7F7F7FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 + F4FFF4F4F4FFF4F4F4FFF7F7F7FF6767676A67676700676767006C6C6C006C6C + 6C006C6C6C69F9F9F9FFAE7B26FFB6832EFFCC9944FFDCA954FFCB9843FFDCA9 + 54FFC5923DFFB17E29FFF9F9F9FF6C6C6C696C6C6C006C6C6C00717171007171 + 710071717168FBFBFBFFAE7B26FFEDE0CBFFE3CA9FFFEED4AAFFE5D8C3FFDCA9 + 54FFC5923DFFB17E29FFFBFBFBFF717171687171710071717100757575007575 + 750075757568FDFDFDFFAE7B26FFC18E39FFD9A651FFEBB863FFEBB863FFDCA9 + 54FFC5923DFFB17E29FFFDFDFDFF757575687575750075757500797979007979 + 790079797967FEFEFEFFAC7924FFB6832EFFC28F3AFFCB9843FFCB9843FFC390 + 3BFFB88530FFAE7B26FFFEFEFEFF7979796779797900797979007D7D7D007D7D + 7D007D7D7D67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFF7D7D7D677D7D7D007D7D7D007F7F7F007F7F + 7F008080804D8080806680808066808080668080806680808066808080668080 + 80668080806680808066808080668080804D7F7F7F007F7F7F00 + } + OnClick = btVisitMyBlogClick + TabOrder = 1 + end + object pcAbout: TPageControl + Left = 2 + Height = 416 + Top = 2 + Width = 602 + ActivePage = tsAboutText + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + TabIndex = 0 + TabOrder = 2 + object tsAboutText: TTabSheet + Caption = 'About FMD' + ClientHeight = 388 + ClientWidth = 594 + object rmAbout: TRichMemo + Left = 2 + Height = 382 + Top = 4 + Width = 588 + Align = alClient + BorderSpacing.Top = 2 + BorderSpacing.Right = 2 + BorderSpacing.Around = 2 + Color = clWhite + Font.Style = [fsBold] + HideSelection = False + ParentFont = False + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 0 + ZoomFactor = 1 + end + end + object tsChangelogText: TTabSheet + Caption = 'Changelog' + ClientHeight = 388 + ClientWidth = 594 + object mmChangelog: TMemo + Left = 2 + Height = 380 + Top = 4 + Width = 588 + Align = alClient + BorderSpacing.Top = 2 + BorderSpacing.Right = 2 + BorderSpacing.Bottom = 2 + BorderSpacing.Around = 2 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqDraft + ParentFont = False + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 0 + end + end + end + end + end + object pnMainTop: TPanel + Left = 0 + Height = 8 + Top = 0 + Width = 819 + Align = alTop + TabOrder = 1 + Visible = False + end + object pcLeft: TPageControl + Left = 4 + Height = 506 + Top = 12 + Width = 195 + ActivePage = tsMangaList + Align = alLeft + BorderSpacing.Left = 4 + BorderSpacing.Top = 4 + BorderSpacing.Bottom = 4 + Images = IconList + TabIndex = 0 + TabOrder = 4 + object tsMangaList: TTabSheet + Caption = 'Manga List' + ChildSizing.LeftRightSpacing = 2 + ChildSizing.TopBottomSpacing = 3 + ClientHeight = 478 + ClientWidth = 187 + object lbMode: TLabel + Left = 3 + Height = 15 + Top = 68 + Width = 157 + Anchors = [akTop, akLeft, akRight] + Caption = 'Mode: Show all (0)' + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + end + object vtMangaList: TVirtualStringTree + Left = 2 + Height = 383 + Top = 92 + Width = 181 + Align = alBottom + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Right = 2 + BorderSpacing.Around = 2 + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + HintMode = hmHint + IncrementalSearch = isAll + Margin = 0 + ParentShowHint = False + PopupMenu = pmMangaList + ShowHint = True + TabOrder = 0 + TextMargin = 3 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] + OnBeforeCellPaint = vtMangaListBeforeCellPaint + OnChange = vtMangaListChange + OnColumnDblClick = vtMangaListColumnDblClick + OnDragAllowed = vtMangaListDragAllowed + OnDragOver = vtMangaListDragOver + OnGetCursor = vtMangaListGetCursor + OnGetText = vtMangaListGetText + OnGetHint = vtMangaListGetHint + end + object edSearch: TEdit + Left = 3 + Height = 23 + Top = 36 + Width = 157 + Anchors = [akTop, akLeft, akRight] + OnChange = edSearchChange + OnKeyDown = edSearchKeyDown + TabOrder = 1 + TextHint = 'Search title...' + end + object cbSelectManga: TComboBox + Left = 3 + Height = 23 + Hint = 'For more manga sites, please go to Options->Manga sites' + Top = 8 + Width = 157 + Anchors = [akTop, akLeft, akRight] + ItemHeight = 15 + ItemIndex = 0 + Items.Strings = ( + '' + ) + OnChange = cbSelectMangaChange + ParentShowHint = False + ShowHint = True + Sorted = True + Style = csDropDownList + TabOrder = 2 + end + object btUpdateList: TSpeedButton + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 162 + Height = 23 + Hint = 'Update manga list' + Top = 8 + Width = 22 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000640000006400000000000000000000000000001F0000 + 0084000000E4733100C5733100C5733100C5733100C5733100C5733100C57331 + 00C5582500A00000002200000000000000000000000000000000000000100101 + 01D1606060FFCA9764FFC69360FFC69360FFC69360FFC69360FFC69360FFCA97 + 64FF803A00BE0000002B0000001A000000110000000000000000010101000101 + 01C8646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFFBE8B58FFCA97 + 64FF9C5E28F7733100C5582500A0000000220000000000000000010101000101 + 01C3696969FFCF9C69FFBF8C59FFC69360FFC69360FFC69360FFBF8C59FFCF9C + 69FFAD713AFFCA9764FF803A00BE0000001A0000001A00000011010101000101 + 01BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFBF8C59FFD4A1 + 6EFFB0733BFFCA9764FF9C5E28F7733100C5582500A000000022010101000101 + 01BA737373FFD9A673FFBF8C59FFD09D6AFFD09D6AFFD09D6AFFBF8C59FFD9A6 + 73FFB4783EFFCF9C69FFAD713AFFCA9764FF853D00B623100000010101000101 + 01B5787878FFDEAB78FFBE8B58FFE1AE7BFFE1AE7BFFE1AE7BFFBE8B58FFDEAB + 78FFB87B40FFD4A16EFFB0733BFFCA9764FF8E4200B08E420000010101000101 + 01B27C7C7CFFE2AF7CFFBC8956FFBC8956FFBC8956FFBC8956FFBC8956FFE2AF + 7CFFBB7E42FFD9A673FFB4783EFFCF9C69FF934600AC93460000010101000101 + 01AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 + 84FFBD8043FFDEAB78FFB87B40FFD4A16EFF984900A898490000010101000101 + 01AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFBF8144FFE2AF7CFFBB7E42FFD9A673FF9C4C00A49C4C0000040404000404 + 048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFB + FAFFB4A484FFEAB784FFBD8043FFDEAB78FFA04F00A1A04F0000040404000404 + 04460404048AA16A33EEAA7744FFC28548FFC28548FFC28548FFC28548FFC285 + 48FFC28548FFCC9966FFBF8144FFE2AF7CFFA451009EA4510000040404000404 + 0400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEA + E5FFF3F3F1FFFBFBFAFFB4A484FFEAB784FFA753009CA7530000040404000404 + 040004040400040404460404048AA16A33EEAA7744FFC28548FFC28548FFC285 + 48FFC28548FFC28548FFC28548FFCC9966FFAA55009AAA550000040404000404 + 04000404040004040400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6 + CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFBFAFF55552B6655552B00000000000202 + 0200040404000404040004040400040404460404048AAA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550099AA550073AA550000 + } + OnClick = btUpdateListClick + end + object btRemoveFilter: TSpeedButton + Left = 162 + Height = 23 + Top = 63 + Width = 22 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000080000000000005A000000770000008000000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A000000110000000400005A00000077000000770000008000000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578040426000000 + 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 + 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 + A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 + A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C + 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 250027275200101090000000AA000000AA000000AA000000A700363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535004343430035355F00121291000000AA000000A700363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A43434300464646004646460035355F0023237700363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btRemoveFilterClick + end + object btSearchClear: TSpeedButton + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 162 + Height = 23 + Top = 36 + Width = 22 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btSearchClearClick + end + object btAbortUpdateList: TSpeedButton + Left = 136 + Height = 22 + Hint = 'Abort update list' + Top = 64 + Width = 23 + Flat = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 + 0004000000170000002B00001A430000448000005AAB00005DC400005DC40000 + 5AAB0000448000001A430000002D0000001800000004FFFFFF00FFFFFF000000 + 000000001F000000534D020274BF08089DE30E0EC4F51111D4FD1111D4FD0E0E + C4F508089DE3020274BF0000534D00001F0000000000FFFFFF00FFFFFF000000 + 830000007F4D040488CD1212C4F61212B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF0F0FC2F6030388CD00007F4D00008300FFFFFF00FFFFFF000000 + 851A03038ABF1818C1F61212B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF0F0FBCF6020289BF0000851AFFFFFF00FFFFFF000000 + 896C1616AAE21616C1FFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF0909A1E30000896CFFFFFF00FFFFFF000000 + 8DA72E2EC0F51212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1212AFF500008DA7FFFFFF00FFFFFF000000 + 92C44444CDFD2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818AFFD000092C4FFFFFF00FFFFFF000000 + 96C44949D1FD3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFD000096C4FFFFFF00FFFFFF000000 + 9AA74747D3F53737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2727B4F500009AA7FFFFFF00FFFFFF000000 + 9E6C3232C6E34949D1FFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4747CFFF2A2ABDE300009E6CFFFFFF00FFFFFF000000 + A11A0808A8BF5656E2F65151D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF5050D8FF4F4FDCF60707A7BF0000A11AFFFFFF00FFFFFF000000 + A2000000A54D1010B1CD5B5BE8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5F5FE7FF5858E4F60F0FB0CD0000A54D0000A200FFFFFF00FFFFFF000000 + A2000000A5000000A84D0909AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5B + E9F53636CFE30909AEBF0000A84D0000A5000000A200FFFFFF00FFFFFF000000 + A2000000A5000000A8000000A91A0000AA6C0000AAA60000AAC40000AAC40000 + AAA60000AA6C0000A91A0000A8000000A5000000A200FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btAbortUpdateListClick + ShowCaption = False + ShowHint = True + ParentShowHint = False + end + end + object tsDownloadFilter: TTabSheet + Caption = '>>' + ClientHeight = 478 + ClientWidth = 187 + ImageIndex = 4 + object tvDownloadFilter: TTreeView + Left = 0 + Height = 478 + Top = 0 + Width = 187 + Align = alClient + AutoExpand = True + DefaultItemHeight = 18 + Images = IconList + ReadOnly = True + TabOrder = 0 + OnSelectionChanged = tvDownloadFilterSelectionChanged + Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] + end + end + end + object sbMain: TStatusBar + Left = 0 + Height = 23 + Top = 522 + Width = 819 + Panels = < + item + Width = 195 + end + item + Width = 100 + end> + PopupMenu = pmSbMain + SimplePanel = False + end + object spMainSplitter: TSplitter + Left = 199 + Height = 514 + Top = 8 + Width = 2 + OnMoved = spMainSplitterMoved + end + object dlgSaveTo: TSelectDirectoryDialog + left = 80 + top = 408 + end + object pmDownload: TPopupMenu + Images = IconList + OnPopup = pmDownloadPopup + left = 616 + top = 360 + object miDownloadStop: TMenuItem + Caption = 'Stop' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 7 + OnClick = miDownloadStopClick + end + object miDownloadResume: TMenuItem + Caption = 'Resume' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000000000001000000070000000E000000150000001A0000001A0000001A0000 + 001A0000001A0000001A000000160000000F0000000800000002000000000000 + 0000000000020000000E0000001C0000002A000000330000003300000033733A + 02A663320274000000330000002B0000001D0000000F00000003000000000000 + 0000000000000000000000000000000000000000000000000000281502009D52 + 06CC9D5206CC763E055C29160300000000000000000000000000B0651400A85D + 0E00A85D0E00553008007F470C00A85D0E007F470C00A85D0E00A65B0D00A358 + 0BCCFFB914FFA3580BCCA4590C5C7F470C002C19050000000000B4691700AA5F + 1000AA5F10CCAB601100AB601199AA5F10CCAB601199AA5F10CCAB601199AA5F + 10CCFFB810FFFFBB1BFFAA5F10CCAB60115CB1661600B96E1C00B76C1A00AF64 + 1400AF641400B3681700B16616CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B4 + 24FFF5AF18FFF5AB0EFFF7B92EFFB16616CCB267175CB96E1C00B96E1CCCBA6F + 1D00BA6F1D99B96E1CCCB96E1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA96 + 27F5E19E29FFE19E29FFE19E29FFEAB349FFB96E1CCCBA6F1D5CBF742000C378 + 2300C27722CCF8D084FFC27722CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D396 + 44FFD09341FFD09341FFD39644FFD89B49FFECBB6CFFC27722CCCB802999CA7F + 28CCCA7F28CCCA7F28CCCA7F28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE + 61FAEEB266FFEEB266FFEEB266FFF7CC80FFCA7F28CCC97E275CD2872ECCFBD9 + 8DFFD2872ECCD0852C00D2872ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C9 + 7DFFF4C175FFF2B96DFFFAD68AFFD2872ECCD1862D5CCA7F2800D88D3399D98E + 33CCD88D3399D78C3200D88D3399D98E33CCD88D3399D98E33CCD98E33CCD98E + 33CCFBD488FFFEDF93FFD98E33CCD88D335CD2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DA8F3400DC913600E095 + 38CCFFE498FFE09538CCDF94385CD98E3300D2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DD923700E59A3C00E59A + 3CCCE59A3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300E89D3F00E89D3F00E99E + 4099E99E405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 12 + OnClick = miDownloadResumeClick + end + object miDownloadDelete: TMenuItem + Caption = 'Delete' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 9 + object miDownloadDeleteTask: TMenuItem + Caption = 'Task only' + Enabled = False + OnClick = miDownloadDeleteTaskClick + end + object miDownloadDeleteTaskData: TMenuItem + Caption = 'Task + Data' + Enabled = False + OnClick = miDownloadDeleteTaskClick + end + end + object miDownloadDeleteCompleted: TMenuItem + Caption = 'Delete all completed tasks' + Enabled = False + OnClick = miDownloadDeleteCompletedClick + end + object MenuItem4: TMenuItem + Caption = '-' + end + object miDownloadMergeCompleted: TMenuItem + Caption = 'Merge completed tasks' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000200000005000000090000000D0000001100000015000000180000001A0000 + 001A0000001A0000001A0000001A000000170000000F00000005000000000000 + 00040000000A0000001100000019000000220000002A00000030000000330000 + 003300000033733B03A6633303740000002E0000001D0000000A532E0700522D + 0600522D0600522D0600522D0600522D0600522D0600522D0600522D0600522D + 0600522D06009F5408CC9F5408CC783F065C2917030000000000A75C0E99A65B + 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B + 0DCCA65B0DCCA65B0DCCFFB508FFA65B0DCCA75C0E5C824A0E00AF6414CCF9C6 + 60FFFFBE23FFFFBD1FFFFFBC1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB7 + 0FFFFFB70DFFFFB60BFFFFB200FFFFB609FFAF6414CCAF641448B96E1BCCF6CB + 7FFFF8C051FFF9BD36FFF8B92CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B5 + 23FFF7B523FFF7B421FFF5AB0EFFF6B11BFFB96E1BCCB96E1B48C1762199C277 + 22CCC27722CCC27722CCD5973FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C + 26CFC27722CCC27722CCE6A93CFFC27722CCC176215CBB701C00C2772200C479 + 2400CC812A2BD38E38CEF0BF71FBE0A856FFDCA04CE4CC8129AACB80283FC97E + 270FC77C2600CC8129CCCC8129CCCB80285CC2772200BB701C00CD822A00D58A + 3000D58A307BEBB865E8F7C579FFF0C070EFD58A30AAD0852D13CC812900C97E + 2700D2872E00D4892F99D4892F5CCC812900C2772200BB701C00DD923600DD92 + 3600DD9236AAF8D081F6FCD185FFE7A951D9DC91363FDB903500CC812900C97E + 2700D2872E00D58A3000D58A3000CC812900C2772200BB701C00E4993B00E499 + 3B00E4993BC5FEDF92FDFFDF93FFE69E42CFE4993B0FE4993B00E4993B00D085 + 2D00D2872E00D58A3000D58A3000CC812900C2772200BB701C00E89D3E00E89D + 3E00E99E3F99E99E3FCCE99E3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C + 3200D2872E00D58A3000D58A3000CC812900C2772200BB701C00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 10 + OnClick = miDownloadMergeCompletedClick + end + object MenuItem1: TMenuItem + Caption = '-' + end + object miDownloadViewMangaInfo: TMenuItem + Caption = 'View manga info' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000030000 + 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B + 0B7A090909650505054200000032000000270000001300000003000000020000 + 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA + DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 + 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 + 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F + 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 + 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 + 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 + 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA + AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 + 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF + CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 + 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC + CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B + 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF + CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 + 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC + DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 + 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF + BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 + 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C + 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F + 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E + 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E + 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 + 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C + 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 + 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA + EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 + 50005252520053535300545454155555553E5555555555555563555555635555 + 55555555553E545454155353530052525200505050004F4F4F00 + } + ImageIndex = 0 + OnClick = miDownloadViewMangaInfoClick + end + object miDownloadOpenFolder: TMenuItem + Caption = 'Open Folder' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 4 + OnClick = miDownloadOpenFolderClick + end + object miDownloadOpenWith: TMenuItem + Caption = 'Open ...' + Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000100000001A0000001000000000000000000000 + 00000000000000000000000000000000000000000000000000001007000F220E + 00352A110048000000620000008F000000ED0000008F000000622A110048200D + 003A130800300703002A050200290502002906030023020100095322009A8550 + 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 + 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 + B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 + B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF + FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 + EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B + A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 + DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 + D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE + FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 + F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF + E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F + 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F + 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D + } + ImageIndex = 11 + OnClick = miDownloadOpenWithClick + end + end + object pmChapterList: TPopupMenu + left = 616 + top = 392 + object miChapterListCheckSelected: TMenuItem + Caption = 'Check selected' + OnClick = miChapterListCheckSelectedClick + end + object miChapterListUncheckSelected: TMenuItem + Caption = 'Uncheck selected' + OnClick = miChapterListUncheckSelectedClick + end + object miI1: TMenuItem + Caption = '-' + end + object miChapterListCheckAll: TMenuItem + Caption = 'Check all' + OnClick = miChapterListCheckAllClick + end + object miChapterListUncheckAll: TMenuItem + Caption = 'Uncheck all' + OnClick = miChapterListUncheckAllClick + end + object MenuItem6: TMenuItem + Caption = '-' + end + object miChapterListHighlight: TMenuItem + Caption = 'Highlight download chapters' + OnClick = miChapterListHighlightClick + end + end + object pmFavorites: TPopupMenu + Images = IconList + OnPopup = pmFavoritesPopup + left = 616 + top = 432 + object miFavoritesCheckNewChapter: TMenuItem + Caption = 'Check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 + 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 + 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB + E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 + 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 + E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 + 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 + D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 + 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 + BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 + 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 + 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 + 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F + 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 + 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D + 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 + 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F + 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 + 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 + 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 + 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 + 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 + 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 + 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 + 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 + 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 + 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 + 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 + E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 + 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550073AA550000AA550000 + } + ImageIndex = 21 + OnClick = miFavoritesCheckNewChapterClick + end + object miFavoritesStopCheckNewChapter: TMenuItem + Caption = 'Stop check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 7 + OnClick = miFavoritesStopCheckNewChapterClick + end + object miFavoritesViewInfos: TMenuItem + Caption = 'View manga info' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0001000000050000000A0000000E0000001120140D214936273544312233160C + 061E000000110000000F0000000B000000060000000200000000B87E51000503 + 02000000000200000004301C0F0C91745D62BBA087C4CFB59EE6CFB7A2E3BBA4 + 91BC9278645C321E0F0D000000040000000200000000000000007B55391F825F + 44305E423304421A0005A9896D7CDABC9DF4F1D3B5FFF4DBC1FFEBD5C0FDE0CC + BAF6D2BEAEF0B0978389734B2E0B8562470000000000000000007B573C2AAD8A + 69CAB6916D9D9E7D617DD7B696F1F0D0ADFFF0D4B6FFD5BCA4DFAB8F796E9778 + 6137AE958058B09784BB92725A760600000178523500000000001E000005B48E + 69A8DEAF7DFFDBB58CFDECC9A3FEEFD0AEFFD6BBA1E69C7D6643FFFADF004422 + 1100A281650086654C187F5A3F88775134307852350000000000B69372009D78 + 5961D8AC7BFDEBC295FFEDCAA5FFEED1B1FFC8AE95D99E7F674E805D410DC5B0 + 9E0077513400754F3100744D3019765033407A54370178523500845F4300805C + 4025C9A37BE2EDC69CFFEECDA9FFEFD2B3FFE8CFB6FFCAB29DE891725987693F + 20120600000178563D1697775D3D8A674C3F5D33140277513400754E31002400 + 0005B39272AAD9B895FBCFB193DCC1A58BAFAF927A799A7B63599A7B6356AF92 + 7A71C1A58BA4CEB194D3D9B897F6B99778B34720060776503300775134000000 + 000089664A4098785D4A7F5D441E3B1B0B046339190C8F6F5679C9B19CE3E7CF + B7FFEFD3B5FFEFCEABFFEDC89EFFCEA880E68763462B8A66480078523500653C + 1E0076503339744D301E754F32007751340096765D007E5A3E099E7F6745C7AD + 95D1EED1B2FFEECCA7FFEBC498FFDBAE7EFEA27D5D66C39F7C00000000007852 + 350077503324805C40888A6A511EB3947800371A0D00EFD6BC009B7D663AD5BA + A1DFF0D1B0FFEDCBA5FEDEB890FDDFB17EFFB8916BAA27060005000000007852 + 3500FFFFFF0094745C67B29A87BEB39A875E9B7D6638AD927B6AD6BDA6DAF0D4 + B8FFF1D1AEFFDBBA9AF3A5836783BA95709FB38F6ECC7E5A3F2A000000000000 + 0000815D4200663D1D07B096827CD3BFAFEEE1CDBCF7EBD5C1FDF4DBC2FFF1D4 + B6FFDCBEA0F5AE8E72814F280E0665493905866449347C573A21000000000000 + 000000000000704A2F00532A0E04A3877049C5AD99ABD5BDA8D8D6BCA4DDC7AA + 91B9A5856C59603C230776533900785235007852350078523500000000000000 + 000000000000000000000000000089542E004F2B15077C583E1D826046216341 + 290CFFFFFF000901000000000000000000000000000000000000 + } + ImageIndex = 0 + SubMenuImages = IconList + OnClick = miFavoritesViewInfosClick + end + object miFavoritesDownloadAll: TMenuItem + Caption = 'Download all' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } + ImageIndex = 1 + OnClick = miFavoritesDownloadAllClick + end + object MenuItem7: TMenuItem + Caption = '-' + end + object miFavoritesDelete: TMenuItem + Caption = 'Delete' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 9 + SubMenuImages = IconList + OnClick = miFavoritesDeleteClick + end + object miFavoritesChangeCurrentChapter: TMenuItem + Caption = 'Change "Current chapter"' + Visible = False + OnClick = miFavoritesChangeCurrentChapterClick + end + object miFavoritesChangeSaveTo: TMenuItem + Caption = 'Change "Save to"' + OnClick = miFavoritesChangeSaveToClick + end + object MenuItem3: TMenuItem + Caption = '-' + end + object miFavoritesOpenFolder: TMenuItem + Caption = 'Open Folder' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00478BE6FF5191E5FF5191E5FF5191E5FF5191E5FF5191E5FF5191E5FF5191 + E5FF5191E5FF5191E5FF5191E5FF478BE6FFFFFFFF00FFFFFF00FFFFFF002784 + F7FF429BFFFF469DFFFF469DFFFF469DFFFF469DFFFF469DFFFF469DFFFF469D + FFFF469DFFFF469DFFFF469DFFFF429BFFFF2784F7FFFFFFFF00FFFFFF002479 + FFFF387AFFFF377BFFFF377BFFFF377BFFFF377BFFFF377BFFFF377BFFFF377B + FFFF377BFFFF377BFFFF377BFFFF387AFFFF2479FFFFFFFFFF00FFFFFF002173 + FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87 + FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF2172FFFFFFFFFF00FFFFFF002279 + FFFF3D8DFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8C + FFFF3B8CFFFF3B8CFFFF3B8CFFFF3D8DFFFF2279FFFFFFFFFF00FFFFFF002482 + FFFF3E95FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94 + FFFF3D94FFFF3D94FFFF3D94FFFF3E95FFFF2482FFFFFFFFFF00FFFFFF002488 + FFFF3E9BFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9A + FFFF3D9AFFFF3D9AFFFF3D9AFFFF3E9BFFFF2488FFFFFFFFFF00FFFFFF002690 + FFFF40A2FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1 + FFFF3FA1FFFF3FA1FFFF3FA1FFFF40A2FFFF2690FFFFFFFFFF00FFFFFF002697 + FFFF40A9FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8 + FFFF3FA8FFFF3FA8FFFF3FA7FFFF40A8FFFF2697FFFFFFFFFF00FFFFFF0029A0 + FFFF42B0FFFF41AFFFFF41AFFFFF41AFFFFF41B0FFFF41B0FFFF41AFFFFF41B0 + FFFF41B0FFFF41B0FFFF41B1FFFF43B2FFFF26A2FFFFFFFFFF00FFFFFF002AA6 + FFFF42B6FFFF41B5FFFF41B5FFFF41B6FFFF41B7FFFF45BAFFFF3EBBFFFF3FBD + FFFF3FBEFFFF3FBEFFFF3FBEFFFF3BBEFFFF2BA8FFFFFFFFFF00FFFFFF002BAD + FFFF43BDFFFF43BCFFFF43BCFFFF42BCFFFF45C1FFFF2CB1FFFF73CDFFFF6DCC + FFFF6DCCFFFF6DCCFFFF6DCCFFFF61C9FFFFFFFFFF00FFFFFF00FFFFFF002BB4 + FFFF44C2FFFF43BFFFFF43BFFFFF43C1FFFF46C6FFFF1CB0FFFFFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002ABC + FFFF47D0FFFF47CEFFFF47CEFFFF49CFFFFF3FCBFFFF2BB8FFFFFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002EC9FFFF3BCCFFFF3BCCFFFF38CCFFFF45CCFFFFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 4 + SubMenuImages = IconList + OnClick = miFavoritesOpenFolderClick + end + object miFavoritesOpenWith: TMenuItem + Caption = 'Open ...' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000100000001A0000001000000000000000000000 + 00000000000000000000000000000000000000000000000000001007000F220E + 00352A110048000000620000008F000000ED0000008F000000622A110048200D + 003A130800300703002A050200290502002906030023020100095322009A8550 + 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 + 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 + B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 + B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF + FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 + EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B + A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 + DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 + D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE + FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 + F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF + E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F + 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F + 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D + } + ImageIndex = 11 + OnClick = miFavoritesOpenWithClick + end + end + object pmMangaList: TPopupMenu + Images = IconList + OnPopup = pmMangaListPopup + left = 128 + top = 272 + object miMangaListViewInfos: TMenuItem + Caption = 'View manga infos' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 + 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 + 0000000000040000001B481F1546B24C3399E96443D4EE6644F5EE6644F5E964 + 43D4B24C3399471F15470000001F0000000600000000FFFFFF00FFFFFF007432 + 210077332200B34D3360EF6F4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1 + C9FFF4A18EFFEF6E4EEBB34D33603C1A110000000000FFFFFF00FFFFFF00E863 + 4100EE664460EF7659F9F7D4CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8 + E8FFF7E9E9FFF6D1CAFFEF7658F9EE664460E8634100FFFFFF00FFFFFF00E360 + 3E20E66A4AEBF3D3CDFFF0E5E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4 + E4FFEFE4E4FFEFE4E4FFEFCDC7FFE66A4AEBE3603E20FFFFFF00FFFFFF00D659 + 3787E59D8AFFEAE2E2FFE7DFDFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DF + DFFFE7DFDFFFE7DFDFFFE8E0E0FFE19784FFD6593787FFFFFF00FFFFFF00C550 + 2ED0EAD0C8FFE1DADAFFE0D9D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9 + D9FFE0D9D9FFE0D9D9FFE0D9D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00B748 + 26F5F4EEEDFFE7E5E5FFDAD6D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4 + D4FFD8D4D4FFD8D4D4FFD8D4D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00AD44 + 22F5F4EFEDFFEEEEEEFFEAEAEAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0 + D0FFD2D0D0FFD2D0D0FFD2D0D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00AB46 + 24D0EAD5CDFFF0F0F0FFF0F0F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1 + D1FFCECECEFFCECECEFFD2D1D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00B34F + 2D87D49D8AFFF5F5F5FFF3F3F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3 + F3FFF3F3F3FFF3F3F3FFF5F5F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00BF5C + 3A20C56747EBF2DFD9FFF8F8F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7 + F7FFF7F7F7FFF8F8F8FFF2DFD9FFC56747EBBF5C3A20FFFFFF00FFFFFF00C461 + 3F00CF6B4960D77F61F9F6E3DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB + FBFFFCFCFCFFF6E3DCFFD77F61F9CF6B4960C4613F00FFFFFF00FFFFFF00C461 + 3F00D16D4B00DF7A5860E38464EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4 + DDFFEFB7A4FFE38464EBDF7A5860D16D4B00C4613F00FFFFFF00FFFFFF00C461 + 3F00D16D4B00E17C5A00EA846220EC866487EC8664D0EC8664F5EC8664F5EC86 + 64D0EC866487EA846220E17C5A00D16D4B00C4613F00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 13 + SubMenuImages = IconList + OnClick = miMangaListViewInfosClick + end + object miMangaListDownloadAll: TMenuItem + Caption = 'Download all' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000818181007F7F + 7FFF7C7C7CFF7A7A7AFF787878FF777777FF757575FF767676FFFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00868686FFBFBF + BFFFBDBDBDFFBCBCBCFFBBBBBBFFBBBBBBFFBABABAFF81818100FFFFFF00FFFF + FF002A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008A8A8AFFC0C0 + C0FFB0B0B0FFB0B0B0FFB0B0B0FFB1B1B1FFC0C0C0FF989898FFFFFFFF002A89 + 27FF3F993CFF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF008E8E8EFFC2C2 + C2FFD2D2D2FFD2D2D2FFD3D3D3FFD6D6D6FFCCCCCCFFD7D7D7FF2A8927FF419B + 3DFF61B45DFF419B3DFF2A8927FFFFFFFF00FFFFFF00FFFFFF00939393FFC4C4 + C4FFD2D2D2FFD3D3D3FFD6D6D6FFDDDDDDFFDDDDDDFF2A8927FF429C3FFF65B8 + 61FF65B861FF65B861FF429C3FFF2A8927FFFFFFFF00FFFFFF00979797FFC6C6 + C6FFD2D2D2FFD4D4D4FFDADADAFFE6E6E6FF2A8927FF449E41FF6ABB66FF69BB + 65FF69BB65FF69BB65FF6ABB66FF449E41FF2A8927FFFFFFFF009C9C9CFFC9C9 + C9FFC7C7C7FFCACACAFFD4D4D4FF2A8927FF5DAA5BFFA7D9A5FFA7D9A5FF8FCE + 8CFF6DBF69FF8FCE8CFFA7D9A5FFA7D9A5FF5DAA5BFF2A8927FFA0A0A0FFCBCB + CBFFC9C9C9FFCBCBCBFFD4D4D4FF2A8927FF2A8927FF2A8927FF2A8927FF5FAB + 5CFF72C36EFF5FAB5CFF2A8927FF2A8927FF2A8927FF2A8927FFA4A4A4FFCCCC + CCFFCBCBCBFFCCCCCCFFD1D1D1FFD7D7D7FFDCDCDCFFC9C9C9FFFFFFFF002A89 + 27FF76C772FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00A8A8A8FFCECE + CEFFB0B0B0FFB1B1B1FFB4B4B4FFB7B7B7FFCECECEFFB1B1B1FFFFFFFF002A89 + 27FF79CA75FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00ACACACFFD0D0 + D0FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFCACACAFFA7A7A7FFFFFFFF002A89 + 27FF7CCE79FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00AFAFAFFFD2D2 + D2FFB0B0B0FFB0B0B0FFB0B0B0FFB0B0B0FFCCCCCCFFABABABFFFFFFFF002A89 + 27FF7FD17BFF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2B2FFD2D2 + D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFCDCDCDFFADADADFFFFFFFF002A89 + 27FFB3E5B1FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFD4D4 + D4FFD3D3D3FFD2D2D2FFD2D2D2FFD1D1D1FFD0D0D0FFAEAEAEFFFFFFFF002A89 + 27FF2A8927FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFD4D4 + D4FFD4D4D4FFD4D4D4FFD2D2D2FFD2D2D2FFD1D1D1FFAEAEAEFFFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFB4B4 + B4FFB4B4B4FFB4B4B4FFB2B2B2FFB1B1B1FFAFAFAFFFAEAEAEFFFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ImageIndex = 1 + SubMenuImages = IconList + OnClick = miMangaListDownloadAllClick + end + object miMangaListAddToFavorites: TMenuItem + Caption = 'Add to Favorites' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0058B754FF5AB856FFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF001DB31BFF04C302FF03C200FF1EB31EFFFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0041BB42FF08BF09FF1EB720FF1EB720FF06BE08FF42BB44FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF0020B828FF08C313FF20B929FF1EBD28FF1EBB27FF20BA29FF08C313FF21B8 + 29FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0045C1 + 50FF0AC71CFF20BD2EFF1FBF2DFF1FC02FFF1FC02EFF1FBE2EFF20BE2EFF0AC6 + 1BFF43BF4FFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0003BF + 1CFF23C238FF21C337FF21C338FF21C338FF21C338FF21C437FF21C137FF23BF + 38FF0CCA25FF23BE37FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0027BF + 42FF11C331FF24CA42FF22C63FFF21C53FFF21C63FFF21C63FFF21C63FFF21C4 + 3EFF22C33FFF0CCE2FFF43C45BFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF0022C547FF11C73BFF26CE4DFF24CB49FF23CA49FF23C949FF23CA49FF23CA + 4AFF24CB4AFF26C74BFF10D23CFF22C346FFFFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF0023C84FFF14CD45FF27D152FF25CD50FF25CD50FF25CF51FF28D5 + 55FF14D045FF00C032FF16C644FF11D644FF4DCD6EFFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF0025CB59FF16CE4EFF29D45DFF27D15AFF29D75FFF0AC8 + 45FF79E19AFFFFFFFF006FDC90FF18C34CFF11CC4AFFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0027CF60FF19D357FF2AD865FF21D35DFF2BC8 + 60FFFFFFFF00FFFFFF00FFFFFF004DD27AFF11C24DFFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0028D168FF19D660FF20D465FF35BD + 69FFFFFFFF00FFFFFF00FFFFFF0056C880FF14C557FFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0029D46DFF1AD464FF11CF + 5CFF9BCEAFFFFFFFFF0091CFAAFF1BC960FF19C75EFFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0029D674FF15D5 + 69FF04E765FF00EC63FF07E767FF19DE6FFF1FD16BFFFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0075E7 + A8FF5CE79AFF60ED9FFF5FE89CFF5AE598FFFFFFFF00FFFFFF00 + } + ImageIndex = 2 + SubMenuImages = IconList + OnClick = miMangaListAddToFavoritesClick + end + object miI2: TMenuItem + Caption = '-' + end + object miHighlightNewManga: TMenuItem + Caption = 'Highlight new manga' + OnClick = miHighlightNewMangaClick + end + end + object TrayIcon: TTrayIcon + BalloonFlags = bfInfo + BalloonTimeout = 5000 + BalloonTitle = 'Free Manga Downloader' + Hint = 'Free Manga Downloader' + OnDblClick = TrayIconDblClick + left = 32 + top = 448 + end + object pmUpdate: TPopupMenu + ParentBidiMode = False + left = 128 + top = 144 + object mnUpdateList: TMenuItem + Caption = 'Update manga list' + OnClick = mnUpdateListClick + end + object mnUpdateDownFromServer: TMenuItem + Caption = 'Download manga list from server' + OnClick = mnUpdateDownFromServerClick + end + object MenuItem5: TMenuItem + Caption = '-' + end + object mnUpdate1Click: TMenuItem + Caption = 'Update all lists at once' + OnClick = mnUpdate1ClickClick + end + object mnDownload1Click: TMenuItem + Caption = 'Download all lists from server at once' + OnClick = mnDownload1ClickClick + end + end + object itAnimate: TIdleTimer + Enabled = False + Interval = 48 + OnTimer = itAnimateTimer + left = 752 + top = 72 + end + object itCheckFav: TIdleTimer + Enabled = False + Interval = 600000 + OnTimer = itCheckFavTimer + left = 760 + top = 256 + end + object itRefreshDLInfo: TIdleTimer + Enabled = False + OnTimer = itRefreshDLInfoTimer + OnStartTimer = itRefreshDLInfoStartTimer + OnStopTimer = itRefreshDLInfoStopTimer + left = 696 + top = 168 + end + object IconList: TImageList + left = 24 + top = 136 + Bitmap = { + 4C691600000010000000100000004F4F4F005050500052525200535353005454 + 54155555553E555555555555556355555563555555555555553E545454155353 + 530052525200505050004F4F4F004F4F4F0050505000525252075353533D7373 + 7378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEAEAFFC7C7C7D2727272785353 + 533D52525207505050004F4F4F004F4F4F00505050075151514D9F9F9FA1E6E6 + E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C75FFD6AFA2FFE3E4E4FF9D9D + 9DA15151514D505050074F4F4F004E4E4E004E4E4E3F9D9D9DA2DFDFDFFFCB79 + 5EFFDB7A58FFEE906EFFF49674FFF49573FFED8E6CFFDA7856FFCB795EFFDBDC + DCFF999999A24E4E4E3F4E4E4E004B4B4B176C6C6C7CDFE0E0FFC8755AFFE283 + 61FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F4DFFEA8866FFDF7E5CFFC875 + 5AFFD8D8D8FF6969697C4B4B4B1748484842BEBFBFD4C9A295FFD57452FFE281 + 5FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD6745FFD87250FFDF7C5AFFD16E + 4CFFC7A194FFB2B3B3D4484848424545455CDBDCDCFFC07C65FFDF805EFFCF69 + 47FFCF6947FFCA6442FFAE4826FFAC4523FFB04927FFAD4624FFAD4624FFC360 + 3EFFC07C65FFCBCCCCFF4545455C4242426CCFCFCFFFBC5B3BFFDD7D5BFFC962 + 40FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB14824FFB34925FFB34925FFBD55 + 32FFBC5B3BFFC3C3C3FF4242426C3E3E3E6ECCCCCCFFB95737FFD5714DFFBF50 + 2AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B26FFBD4E27FFBD4E27FFC154 + 2EFFB95737FFC0C0C0FF3E3E3E6E3A3A3A61D0CFCFFFB9745DFFCF643EFFC954 + 2AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC25028FFC9542AFFC9542AFFC554 + 2CFFB9745DFFC2C0C0FF3A3A3A6137373747ACAAAAD7C09789FFBF5631FFD85F + 33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB542AFFD55A2DFFD55A2DFFBC4F + 29FFBF9588FFA29F9FD7373737473434341953515186D4CECEFFB35F44FFC957 + 2FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD3592DFFE15F30FFC8532AFFB35F + 44FFD0C9C9FF5150508634343419303030002F2F2F48827E7EACDBD1D1FFAC57 + 3CFFB6461FFFD6592AFFE56230FFE56230FFD6592AFFB6461FFFAC573CFFDACF + CFFF817C7CAC2F2F2F483030300017171700212121092626265C807979AFE4D6 + D6FFC69689FFAD644EFF943312FF943312FFAD644EFFC69689FFE3D6D6FF7F79 + 79AF2626265C2121210917171700000000020000000A0707071C1313135D3D3A + 3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDADAFFB2A6A6DC3D3A3A931313 + 135D0707071D0000000A00000002000000030000001300000026000000320505 + 0542090909650B0B0B7A0B0B0B880B0B0B880B0B0B7A09090965050505420000 + 0032000000270000001300000003E99E3F00E99E3F00E99E3F00E99E3F00E99E + 3F00E99E3F00E99E3F33FFE39E40FED18540E99E3F33E99E3F00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00D2872E00D2872E00D2872E00D3892F00E297 + 3A00E2973A00E2973A6AFCDC9884F5BF7385E2973A6AE2973A00E2973A00D389 + 2F00D2872E00D2872E00D2872E00BF752000BF752000BF752000C2782200CB80 + 2900D98E3300D98E33ABF9D591D5EEB367D5D98E33AAD98E3300CB802900C278 + 2200BF752000BF752000BF752000BF752000BF752000BF752000C2782200C57A + 2400C87D2700CE832BCCF1CA83FFD89B4AFFCE832BCCC87D2700C57A2400C278 + 2200BF752000BF752000BF752000BF752000BF752000BF752000C177218FC278 + 22B8C27822B8C27822CCEEC26AFFDE9C2CFFC27822CCC27822B8C27822B8C177 + 218FBF752000BF752000BF752000BA6F1C00BA6F1C00BA6F1C00B96E1B5CC27B + 23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD3FFFF7C554FFC0781FD4B96E + 1B5CBA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F1C00B76C1A00AD62 + 125CB97117D4FECB4DFFFEB714FFFEB102FFFEC02CFFB86F15D4AD62125CB76C + 1A00BA6F1C00BA6F1C00BA6F1C00855F3600855F3600866037009E662800AC61 + 1100A3580B5CB0670ED4FFC53AFFFFBD20FFB0660DD4A3580B5CAC6111009E66 + 280086603700855F3600855F36004F4F4F004F4F4F0051515100555555006A58 + 44008E561D009B50055CA95F07D3A95F06D39B50055C8E561D006A5844005555 + 5500515151004F4F4F004F4F4F004F4F4F004F4F4F0051515100555555005555 + 5500555555006653410075502B1F75502B1F6653410055555500555555005555 + 5500515151004F4F4F004F4F4F004F4F4F004F4F4F005151510D5454545A5454 + 5467545454675454546754545467545454675454546754545467545454675454 + 545A5151510D4F4F4F004F4F4F004D4D4D004D4D4D004D4D4D5DC3C3C3DAD1D1 + D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3B3FFB9B3B3FFBFB3B3FFB5A9 + A9DA4D4D4D5D4D4D4D004D4D4D0033333300434343004343436EFAFAFAFFF8F8 + F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDDDDFFE2DDDDFFD7CCCCFFE8D9 + D9FF4343436E4343430033333300000000002B2B2B0038383873E9E9E9FFB0B0 + B0FF858585FF7E7F7FFF787979FF787777FF7E7777FF857777FF66FF66FFD7C8 + C8FF383838732B2B2B000000000000000009000000162A2A2A7AB3B3B3DFDBDB + DBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4C4FFC9C4C4FFC6BBBBFFA59A + 9ADF2A2A2A7A0000001600000009000000120000002C0D0D0D58121212851212 + 1285121212851212128512121285121212851212128512121285121212851212 + 12850D0D0D580000002C00000012000000000000000000000000000099000000 + 2B00000000000000000001016E000101DE000101E1000101E3000101E53C0101 + E5AB0101E53C0101E3000101E100000000000000000000000000000099000000 + 2B0001016B000101D9000101DC000101DE000101E1000101E33C0101E3AC8686 + FFFF0101E3AC0101E33C0101E1000000000000000000000000000101B4000101 + D2000101D5000101D9000101DC000101DE000101E13D0101E1AD8484FFFF7474 + FDFF8686FFFF0101E1AD0101E13D00000000010164000101CB000101CE000101 + D2000101D5000101D9000101DC000101DE3E0101DEAE8181FFFF7171FCFF7373 + FDFF7474FDFF8686FFFF0101DEAE0101C3000101C7000101CB000101CE000101 + D2000101D5000101D9000101DC3E0101DCAF7E7EFFFF6F6FFBFF7070FCFF7171 + FCFF8484FFFF0101DCAF0101DC3E0101C3000101C7000101CB000101CE000101 + D2000101D5000101D93E0101D9B17B7BFFFF6C6CF9FF6D6DFAFF6F6FFBFF8181 + FFFF0101D9B10101D93E0101DC000101C3000101C7000101CB000101CE000101 + D2000101D53F0101D5B27878FFFF6868F8FF6A6AF9FF6C6CF9FF7E7EFFFF0101 + D5B20101D63E0101D9000101DC000101C3000101C7000101CB000101CE000101 + D23F0101D2B37575FFFF6565F6FF6767F7FF6868F8FF7B7BFFFF0101D2B30101 + D33F0101D5000101D9000101DC000101C3000101C7000101CB000101CE400101 + CEB57171FFFF6262F4FF6464F5FF6565F6FF7878FFFF0101CEB5062C9B3F1080 + 350015A9000014A80000129D00000101C3000101C7000101CB400101CBB66E6E + FFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101CBB60101CC4015A9009915A9 + 00CC15A9009914A80000129D00000101C3000101C7410101C7B86C6CFFFF5C5C + F1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B8062996410F79330014A400CC75EE + 64FF14A400CC13A10000129D00000101C3410101C3B96969FFFF6262F8FF5F5F + F5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C0099129D00CC129D00CC66EB + 55FF129D00CC129D00CC129C00990101BFBB0101BFBB0101BFBB0101BFBB6262 + F8FF6C6CFFFF0101BFBB0101C042094B6100109500CC52E741FF52E741FF52E7 + 41FF52E741FF52E741FF109500CC01018F0001015F0001018C000000B6BF6969 + FFFF0000B6BF0000B84301016000074700000E8D00990E8C00CC0E8C00CC3DE2 + 2CFF0E8C00CC0E8C00CC0E8D0099000000030000000F000000190000A8C50000 + A8C500006D580000001600000013000000110000000F0000000C0C8200CE2BDF + 1AFF0C8200CD0000000300000001000000050000001E0000003200009CC90000 + 54630000002E0000002B00000026000000220000001D00000018054F00A10568 + 00CF0550009D0000000500000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 + A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 + A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 + AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 + A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B + E8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5F5FE7FF5858E4F60F0F + B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 + D9FF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FF5050D8FF4F4F + DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 + CAFF4242CAFF4242CAFF4242CAFF4242CAFF4242CAFF4242CAFF4242CAFF4747 + CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 + BFFF3737BFFF3232BAFF2727B0FF1C1CA6FF1616A0FF12129CFF12129CFF1616 + A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFFF8F8 + F8FFDEDEDEFFCECECEFFD1D1D1FFDCDCDCFFE8E8E8FFEEEEEEFFEEEEEEFF1111 + A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FFD0D0 + D0FFCCCCCCFFD1D1D1FFDCDCDCFFE8E8E8FFEEEEEEFFEEEEEEFFEEEEEEFF1111 + AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 + A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111A8FF1111 + B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 + BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111BEFF1111 + BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 + C8FF1111C8FF1111C8FF1111C8FF1111C8FF1111C8FF1111C8FF1111C8FF0F0F + BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 + C4F61212D1FF1111D1FF1111D1FF1111D1FF1111D1FF1111D1FF0F0FC2F60303 + 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 + 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 + 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 + 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF000087CA000087CA000087CA000087CA000087 + CA000087CA000087CA000088CC2E0088CC810088CC810088CC810088CC810088 + CC810088CC810088CC2E0087CA000087CA630087CA830087CA830087CA830087 + CA830087CA830087CA830087CA83FEFEFDFFF8F8F3FFF0F0E6FFE9E9DBFFFEC9 + 41FFF4B62EFF0087CA830087CA630085C785AEF3FFFFABF0FEFFABF0FEFFABF0 + FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0FEFFABF0FEFFABF0FEFFABF0 + FEFFABF0FEFFAEF3FFFF0085C7850083C488A8EDFDFFA2E7FBFFA2E7FBFFA2E7 + FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BCDEFF78BCDEFF78BCDEFF78BC + DEFF78BCDEFF78BCDEFF0083C4880081C18BA3E9FBFF9DE3F9FF9DE3F9FF9DE3 + F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9 + FAFFA3E9FAFFA6ECFBFF0081C18B007FBD8E9FE5F9FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF9FE5F9FF007FBD8E007CBA9299E0F6FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF99E0F6FF007CBA920079B69594DBF4FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF94DBF4FF0079B6950076B2998FD7F2FF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF8FD7F2FF0076B2990074AD9D8AD3F0FF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF8AD3F0FF0074AD9D0070A9A286CFEEFF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF86CFEEFF0070A9A200679AB086CFF0FF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF86CFF0FF00679AB000476A91005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD00476A9100000006000000160000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001600000006FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA + 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE + 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2 + 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5 + 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B + 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7 + 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197 + 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197 + 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1 + 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094 + 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC + 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094 + 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA + 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A + 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82 + 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000 + 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657 + 0048077200CC16A60AE8087601C406570029021E000000000000000000000000 + 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000 + 002D02330066025F00CC012B005500000029000000220000001A000000130000 + 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000 + 00170000001A000000190000001700000015000000110000000D0000000A0000 + 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E99E3F00E99E3F00E99E3F00EA9F + 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398 + 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B + 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398 + 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398 + 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297 + 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92 + 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91 + 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C + 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B + 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287 + 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287 + 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F + 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E + 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A + 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72 + 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73 + 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E + 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D + 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D + 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF + 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166 + 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3 + 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61 + 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A + 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60 + 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156 + 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000 + 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 + 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000 + 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 + 00320000003363320274974C02CC633202740000003300000033000000220000 + 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002B2BCF992B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002424CCCC8686E6FF8080 + E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8484E5FF2424 + CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C1CC9CC7878E4FF6767 + DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF7575E2FF1C1C + C9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001414C6CC6F6FE1FF5555 + DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3BD3FF3838D3FF5252DAFF1414 + C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001010B9CC6767DFFF4B4B + D8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1BC9FF1B1BC9FF3434D1FF1010 + B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000F0FA5CC5555DAFF2020 + CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF2E2ED0FF0F0F + A5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000D0D95CC3636D1FF1717 + C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF2727CDFF0D0D + 95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000B0B84CC2C2CCFFF1414 + C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1E1ECAFF0B0B + 84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000A0A75CC2525CDFF1212 + C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1919C8FF0A0A + 75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0009096ACC2727CDFF1C1C + C9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717C8FF1717C8FF1919C8FF0909 + 6ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF000000000306063EA0080860CC0808 + 60CC080860CC080860CC080860CC080860CC080860CC080860CC080860CC0606 + 3EA100000004FFFFFF00FFFFFF00FFFFFF0000000003000000110000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001300000004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A480 + 0000A984004AA98400A6A98400CCA98400A6A984004AA4800000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A37F + 004AB18E11D0E5C657F3EFD166FDE4C556F3B08D10D0A37F004AFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009D7B + 00A6D9BA4DF3CAAC42FFBFA137FFBA9C32FFC4A537F39D7B00A6FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009574 + 00CCCAAB3DFDA98916FFA58511FFA58511FFB0901DFD957400CCFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008C6D + 00A6BD9A1FF3BC9712FFBB9611FFBB9612FFB38F10F38C6D00A6FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008467 + 004A8E7004D0C09910F3CEA511FDBF980EF38D6F03D0634D004AFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000941330061654F00AB695200CC654F00AB4032006500000013FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0005000000170000001A0000001A0000001A000000190000000AFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A8000000A9480000A9CC0000 + A9CC0000A9930000A7000000A20000009A0000009E000000A4000000A82B0000 + A97E0000A9B00000A966FFFFFF00FFFFFF000000A4000000A4CC7474FCFF6B6B + F4FE3636CDE50000A4CC0000A10000009A0000009E000000A3890606A8CF0000 + A4BD0000A54A0000A501FFFFFF00FFFFFF0000009F0000009F6600009ECC3737 + C9E56262EAFF5858E3FA1616AFD600009A330E0EA99F2828BEDD00009EB40000 + 9F1F0000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098330000 + 968A000096CC4141CDEE5151D9FD2727B7E32F2FBEE3000096B100009A180000 + 9F000000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098000000 + 900000008D3300008ECC3131BCF33333BCFA090997D400008E0000008F000000 + 8E0000008E000000A500FFFFFF00FFFFFF000000800000008000000080000000 + 8215000086B01A1AA8E72222B4F907078ED214149FE105058DD2000082000000 + 7C000000780000007800FFFFFF00FFFFFF00000078000000780000007B000000 + 7E911515A6E51D1DBEFD07078AD400007F6300007EAE0A0A94DC00007EB60000 + 7A000000780000007800FFFFFF00FFFFFF000000700000007000000075670D0D + 96DC1717CCFF0F0FA2E50000777500007E0000007A000000769104048AD50000 + 76860000730000007200FFFFFF00FFFFFF0000006C0000006D1F00006ECC1515 + D1FB1111C3F400006EB40000701100007000000078000000720000006E820000 + 6EB800006D4100006C00FFFFFF00FFFFFF00000066000000668C0A0A9FE51212 + DDFF030378D3000067330000510000000000000000000000380000006A000000 + 66840000668900006404FFFFFF00FFFFFF000000180000005FCC1111DBFE0C0C + AFEC00005F8B0000190000000000000000000000000000000000000000000000 + 320000005F7300004832FFFFFF00FFFFFF000000001C0000325E000059CC0000 + 57BC0000164200000020000000160000000F0000000D00000010000000150000 + 001B00001D3800002D4CFFFFFF00FFFFFF000000000E00000014000000190000 + 001900000016000000100000000B0000000800000007000000080000000B0000 + 000E0000001100000013FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00E89D3E00E89D3E00E99E3F99E99E3FCCE99E + 3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C3200D2872E00D58A3000D58A + 3000CC812900C2772200BB701C00E4993B00E4993B00E4993BC5FEDF92FDFFDF + 93FFE69E42CFE4993B0FE4993B00E4993B00D0852D00D2872E00D58A3000D58A + 3000CC812900C2772200BB701C00DD923600DD923600DD9236AAF8D081F6FCD1 + 85FFE7A951D9DC91363FDB903500CC812900C97E2700D2872E00D58A3000D58A + 3000CC812900C2772200BB701C00CD822A00D58A3000D58A307BEBB865E8F7C5 + 79FFF0C070EFD58A30AAD0852D13CC812900C97E2700D2872E00D4892F99D489 + 2F5CCC812900C2772200BB701C00C2772200C4792400CC812A2BD38E38CEF0BF + 71FBE0A856FFDCA04CE4CC8129AACB80283FC97E270FC77C2600CC8129CCCC81 + 29CCCB80285CC2772200BB701C00C1762199C27722CCC27722CCC27722CCD597 + 3FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C26CFC27722CCC27722CCE6A9 + 3CFFC27722CCC176215CBB701C00B96E1BCCF6CB7FFFF8C051FFF9BD36FFF8B9 + 2CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B523FFF7B523FFF7B421FFF5AB + 0EFFF6B11BFFB96E1BCCB96E1B48AF6414CCF9C660FFFFBE23FFFFBD1FFFFFBC + 1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB70FFFFFB70DFFFFB60BFFFFB2 + 00FFFFB609FFAF6414CCAF641448A75C0E99A65B0DCCA65B0DCCA65B0DCCA65B + 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCFFB5 + 08FFA65B0DCCA75C0E5C824A0E00532E0700522D0600522D0600522D0600522D + 0600522D0600522D0600522D0600522D0600522D0600522D06009F5408CC9F54 + 08CC783F065C291703000000000000000000000000040000000A000000110000 + 0019000000220000002A00000030000000330000003300000033733B03A66333 + 03740000002E0000001D0000000A000000000000000200000005000000090000 + 000D0000001100000015000000180000001A0000001A0000001A0000001A0000 + 001A000000170000000F00000005FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF007F7F55497F7F55577F7F55497F7F552E7F7F + 550E7F7F55007F7F550E7F7F552E7F7F55497F7F55577F7F55617F7F55667F7F + 55667F7F55667F7F55667F7F554DAA55009AF6F6F3EBE8E8DDD7C9C9B2B49C9C + 78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEFE2EBF6F6ECF9FBFBF4FFFCFC + F7FFFEFEFBFFFFFFFEFFAA55009AA854009BFEFEFDFFF8F8F3FFF1F1E7FFE9E9 + D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFFBFB + F6FFFDFDFAFFFFFFFEFFA854009BA652009DFEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBEADFFD2D2C1FFCDCDBCFFFBFB + F6FFFDFDFAFFFFFFFEFFA652009DA351009FFEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFFBFB + F6FFFDFDFAFFFFFFFEFFA351009FA04E00A2FEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1D3FF18B2D3FFF9F9F2FFD9D9 + C8FFD4D4C3FFFFFFFEFFA04E00A29C4C00A4FEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6DFFF49E0F1FFF9F9F2FFEAEA + D9FFEDEDDCFFFFFFFEFF9C4C00A4994A00A7FEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168BA9FF1EA8C0FFF9F9F2FFD9D9 + C8FFD4D4C3FFFFFFFEFF994A00A7954700AAFEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFEAEA + D9FFEDEDDCFFFFFFFEFF954700AA914500ADFEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBEADFFD2D2C1FFC4C4B3FFD9D9 + C8FFDCDCCBFFFFFFFEFF914500AD8D4200B0FEFEFDFFF8F8F3FFF0F0E6FFE9E9 + DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4E8FFF6F6EDFFF9F9F2FFFBFB + F6FFFDFDFAFFFFFFFEFF8D4200B0873E00B5FFFFFEFFF9F9F4FFF1F1E7FFE9E9 + DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6EAFFF8F8EFFFFBFBF4FFFCFC + F7FFFEFEFBFFFFFFFEFF873E00B5793400C0C5C5B7FFCECEC1FFDDDDD0FFE7E7 + D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5B4FFBEBEAEFFBBBBAAFFBBBB + AAFFBBBBAAFFBBBBAAFF793400C05322009A855027D78E623DDF67655AF7ACAA + 9AFD9B9B8AFFACAA9AFD67655AF78E623DDF855027D7793D12D0703104CC6F2F + 02CB6F2F02CB6F2F02CB5322009A1007000F220E00352A110048000000620000 + 008F000000ED0000008F000000622A110048200D003A130800300703002A0502 + 0029050200290603002302010009000000000000000000000000000000000000 + 00100000001A0000001000000000000000000000000000000000000000000000 + 0000000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00D98E3300DA8F3400D98E3300D78C3200D98E + 3300DA8F3400D98E3300E89D3F00E89D3F00E99E4099E99E405CE59A3C00E095 + 3800D98E3300D2872E00CA7F2800D98E3300DA8F3400D98E3300D78C3200D98E + 3300DA8F3400D98E3300DD923700E59A3C00E59A3CCCE59A3CCCE59A3C5CE095 + 3800D98E3300D2872E00CA7F2800D98E3300DA8F3400D98E3300D78C3200D98E + 3300DA8F3400D98E3300DA8F3400DC913600E09538CCFFE498FFE09538CCDF94 + 385CD98E3300D2872E00CA7F2800D88D3399D98E33CCD88D3399D78C3200D88D + 3399D98E33CCD88D3399D98E33CCD98E33CCD98E33CCFBD488FFFEDF93FFD98E + 33CCD88D335CD2872E00CA7F2800D2872ECCFBD98DFFD2872ECCD0852C00D287 + 2ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C97DFFF4C175FFF2B96DFFFAD6 + 8AFFD2872ECCD1862D5CCA7F2800CB802999CA7F28CCCA7F28CCCA7F28CCCA7F + 28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE61FAEEB266FFEEB266FFEEB2 + 66FFF7CC80FFCA7F28CCC97E275CBF742000C3782300C27722CCF8D084FFC277 + 22CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D39644FFD09341FFD09341FFD396 + 44FFD89B49FFECBB6CFFC27722CCB96E1CCCBA6F1D00BA6F1D99B96E1CCCB96E + 1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA9627F5E19E29FFE19E29FFE19E + 29FFEAB349FFB96E1CCCBA6F1D5CB76C1A00AF641400AF641400B3681700B166 + 16CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B424FFF5AF18FFF5AB0EFFF7B9 + 2EFFB16616CCB267175CB96E1C00B4691700AA5F1000AA5F10CCAB601100AB60 + 1199AA5F10CCAB601199AA5F10CCAB601199AA5F10CCFFB810FFFFBB1BFFAA5F + 10CCAB60115CB1661600B96E1C00B0651400A85D0E00A85D0E00553008007F47 + 0C00A85D0E007F470C00A85D0E00A65B0D00A3580BCCFFB914FFA3580BCCA459 + 0C5C7F470C002C19050000000000000000000000000000000000000000000000 + 0000000000000000000000000000281502009D5206CC9D5206CC763E055C2916 + 03000000000000000000000000000000000000000000000000020000000E0000 + 001C0000002A000000330000003300000033733A02A663320274000000330000 + 002B0000001D0000000F00000003000000000000000000000001000000070000 + 000E000000150000001A0000001A0000001A0000001A0000001A0000001A0000 + 00160000000F0000000800000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C4613F00D16D4B00E17C5A00EA84 + 6220EC866487EC8664D0EC8664F5EC8664F5EC8664D0EC866487EA846220E17C + 5A00D16D4B00C4613F00FFFFFF00FFFFFF00C4613F00D16D4B00DF7A5860E384 + 64EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4DDFFEFB7A4FFE38464EBDF7A + 5860D16D4B00C4613F00FFFFFF00FFFFFF00C4613F00CF6B4960D77F61F9F6E3 + DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFCFCFCFFF6E3DCFFD77F + 61F9CF6B4960C4613F00FFFFFF00FFFFFF00BF5C3A20C56747EBF2DFD9FFF8F8 + F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7F7FFF7F7F7FFF8F8F8FFF2DF + D9FFC56747EBBF5C3A20FFFFFF00FFFFFF00B34F2D87D49D8AFFF5F5F5FFF3F3 + F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3F3FFF3F3F3FFF3F3F3FFF5F5 + F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00AB4624D0EAD5CDFFF0F0F0FFF0F0 + F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1D1FFCECECEFFCECECEFFD2D1 + D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00AD4422F5F4EFEDFFEEEEEEFFEAEA + EAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0D0FFD2D0D0FFD2D0D0FFD2D0 + D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00B74826F5F4EEEDFFE7E5E5FFDAD6 + D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4D4FFD8D4D4FFD8D4D4FFD8D4 + D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00C5502ED0EAD0C8FFE1DADAFFE0D9 + D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9D9FFE0D9D9FFE0D9D9FFE0D9 + D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00D6593787E59D8AFFEAE2E2FFE7DF + DFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DFDFFFE7DFDFFFE7DFDFFFE8E0 + E0FFE19784FFD6593787FFFFFF00FFFFFF00E3603E20E66A4AEBF3D3CDFFF0E5 + E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4E4FFEFE4E4FFEFE4E4FFEFCD + C7FFE66A4AEBE3603E20FFFFFF00FFFFFF00E8634100EE664460EF7659F9F7D4 + CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8E8FFF7E9E9FFF6D1CAFFEF76 + 58F9EE664460E8634100FFFFFF00FFFFFF007432210077332200B34D3360EF6F + 4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1C9FFF4A18EFFEF6E4EEBB34D + 33603C1A110000000000FFFFFF00FFFFFF0000000000000000040000001B481F + 1546B24C3399E96443D4EE6644F5EE6644F5E96443D4B24C3399471F15470000 + 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000 + 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000 + 00100000000300000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00B82F0300B92F030BBA30036ABA3003ACBA30 + 03BDBA3003BDBA3003BDBA3003BDBA3003BDBA3003BDBA3003BDBA3003BDBA30 + 03ACBA30036AB92F030BB82F0300B82F0300B82F036BD25B33D3F1916EF7F698 + 76FFF69876FFF69876FFF69876FFF59876FFF59775FFF59775FFF59674FFF08E + 6BF7D15931D3B82F036BB82F0300B52D0300B52D03ADF08F6CF7E7815FFFE781 + 5FFFE7815FFFE7815FFFD87250FFD87250FFE7815FFFE7815FFFE7815FFFE781 + 5FFFEB8865F7B52D03ADB52D0300B22C0300B22C03BFEF906EFFDF7957FFDF79 + 57FFDF7957FFD26C4AFFFFFFFFFFFFFFFFFFD26C4AFFDF7957FFDF7957FFDF79 + 57FFE88765FFB22C03BFB22C0300AF2A0300AF2A03BFE88A68FFD6704EFFD670 + 4EFFD6704EFFCC6644FFFFFFFFFFFFFFFFFFCC6644FFD6704EFFD6704EFFD670 + 4EFFE07E5CFFAF2A03BFAF2A0300AB270200AB2702C0E28260FFCF6947FFCF69 + 47FFCF6947FFCA6442FFAE4826FFAC4523FFB04A27FFAD4624FFAD4624FFB04A + 27FFC25F3CFFAB2702C0AB270200A7250200A72502C1DD7D5BFFCC6644FFC962 + 40FFBD5431FFB24926FFCCCCCCFFCDCDCDFFB14825FFB44A26FFB44A26FFB44A + 26FFBD5532FFA72502C1A7250200A3230200A32302C1DA7957FFC85F3BFFC052 + 2CFFBE502AFFB94E28FFCDCDCDFFD6D6D6FFB94E28FFBE502AFFBE502AFFBE50 + 2AFFC35631FFA32302C1A32302009F2002009F2002C2D86F4BFFCB5930FFCB58 + 2FFFCB582FFFC3542CFFD6D6D6FFE2E2E2FFC3542CFFCB582FFFCB582FFFCB58 + 2FFFCC5B32FF9F2002C29F2002009B1E02009B1E02C3DE6C42FFD86035FFD860 + 35FFD86035FFCD5930FFE2E2E2FFEDEDEDFFCD5930FFD86035FFD86035FFD860 + 35FFD86035FF9B1E02C39B1E0200961B0200961B02C4E86E42FFE5673AFFE567 + 3AFFE5673AFFD75F34FFEDEDEDFFEEEEEEFFD75F34FFE5673AFFE5673AFFE567 + 3AFFE5673AFF961B02C4961B020090170200901702B3E7693CF8F16F3EFFF16F + 3EFFF16F3EFFF16F3EFFCF5A31FFCF5A31FFF16F3EFFF16F3EFFF16F3EFFF16F + 3EFFE66538F8901702B39017020021040100800E0170AB331ADBEC693CF8FA74 + 42FFFA7442FFFA7442FFFA7442FFFA7442FFFA7442FFFA7442FFFA7442FFEC69 + 3BF8AB3218DB800E01702104010000000012120100335A040082710500BA7205 + 00CB720500CB720500CB720500CB720500CB720500CB720500CB720500CB7105 + 00BA5A040082120100330000001200000009000000160000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A00000016000000090404040004040400040404460404048AAA55 + 0099AA550099AA550099AA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550073AA550000AA55000004040400040404000404048ABCBCABFFC1C1 + B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8E2FFEFEFECFFF7F7F4FFFCFC + FCFF55552B6655552B0055552B000101010001010100010101AC555555FFCC99 + 66FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFAA55009AAA550000AA5500000101010001010100010101AE808080FFEAB7 + 84FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 + 84FFA854009BA8540000A85400000101010001010100010101B07E7E7EFFE4B1 + 7EFFD7A674FFCF9F6FFFCC9D6DFFCC9D6DFFCF9F6EFFD7A573FFDBA875FFE4B1 + 7EFFA653009DA6530000A65300000101010001010100010101B27C7C7CFFE2AF + 7CFFD09F6EFFFFEEDDFFFFEEDDFFFFEEDDFFFFEEDDFFD7AF87FFD7A472FFE2AF + 7CFFA451009FA4510000A45100000101010001010100010101B5797979FFDFAC + 79FFD19F6DFFD4AC84FFCFA982FFD2B293FFFBEAD9FFDEBF9FFFD3A16EFFDFAC + 79FFA14F00A1A14F0000A14F00000101010001010100010101B8757575FFDBA8 + 75FFD29F6CFFD19E6CFFC99968FFD2B291FFF7E6D5FFD5B18EFFD09E6BFFDBA8 + 75FF9E4D00A39E4D00009E4D00000101010001010100010101BB727272FFD8A5 + 72FFCF9C69FFCB9967FFCCA681FFF1E0CEFFE4CCB4FFC59564FFCF9C69FFD8A5 + 72FF9B4B00A59B4B00009B4B00000101010001010100010101BE6E6E6EFFD4A1 + 6EFFCB9865FFC39261FFEDDCCBFFEDDCCBFFBC8D5EFFCA9765FFCB9865FFD4A1 + 6EFF984900A898490000984900000101010001010100010101C16B6B6BFFD19E + 6BFFC89562FFC2915FFFB38658FFB38658FFC2915FFFC89562FFC89562FFD19E + 6BFF954700AB95470000954700000101010001010100010101C5676767FFCD9A + 67FFC4915EFFBA8A5AFFF8E7D6FFEAD9C8FFBA8A5AFFC4915EFFC4915EFFCD9A + 67FF914500AD91450000914500000101010001010100010101C9646464FFCA97 + 64FFC18E5BFFB78757FFE7D6C5FFDFCEBDFFB78757FFC18E5BFFC18E5BFFCA97 + 64FF8D4200B08D4200006A3200000000000001010100010101CE626262FFC895 + 62FFBF8C59FFBC8A58FFB58554FFB58554FFBC8A58FFBF8C59FFBF8C59FFC895 + 62FF893F00B467300000000000000000000900000016000000DB606060FFCA97 + 64FFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFCA97 + 64FF7C3600BE0000001600000009000000120000002C00000087000000E7702E + 00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E + 00C7552300A20000002C00000012FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 + A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 + A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 + AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 + A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B + E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F + B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 + D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F + DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 + CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747 + CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 + BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616 + A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E + B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111 + A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 + ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111 + AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 + B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111 + B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 + BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111 + BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 + C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F + BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 + C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303 + 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 + 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 + 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 + 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00E7815F00E983610FED876590ED8765E8ED87 + 65FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED87 + 65E8ED876590E983610FE7815F00E47F5D00E47F5D90EEA992FFFCEFEAFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCEF + EAFFEEA992FFE47F5D90E47F5D00D9745200D97452E8F9ECE8FFFBFBFBFFFBFB + FBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB + FBFFF8EBE7FFD97452E8D9745200CC674500CC6745FFFBFBFBFFF7F7F7FFF7F7 + F7FFF7F7F7FFF7F7F7FFCC6745FFCC6745FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7 + F7FFFAFAFAFFCC6745FFCC674500BE5B3900BE5B39FFF9F9F9FFF3F3F3FFF3F3 + F3FFF3F3F3FFF3F3F3FFBE5B39FFBE5B39FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3 + F3FFF6F6F6FFBE5B39FFBE5B3900B4502E00B4502EFFF6F6F6FFF0F0F0FFF0F0 + F0FFF0F0F0FFEBEBEBFFB4502EFFB4502EFFD2D1D1FFCECECEFFCECECEFFD2D1 + D1FFDEDDDDFFB4502EFFB4502E00AC482600AC4826FFF4F4F4FFEEEEEEFFAC48 + 26FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFD2D0 + D0FFD7D6D6FFAC4826FFAC482600AB442200AB4422FFF3F3F3FFE7E5E5FFEE66 + 44FFEE6644FFEE6644FFAB4422FFAB4422FFEE6644FFEE6644FFEE6644FFD8D4 + D4FFDBD8D8FFAB4422FFAB442200AF452300AF4523FFEDEAEAFFE1DADAFFF1ED + EDFFF1EDEDFFF1EDEDFFAF4523FFAF4523FFF1EDEDFFF1EDEDFFF1EDEDFFE0D9 + D9FFE1DBDBFFAF4523FFAF452300B8492700B84927FFEBE4E4FFE7DFDFFFE7DF + DFFFE7DFDFFFE7DFDFFFB84927FFB84927FFE7DFDFFFE7DFDFFFE7DFDFFFE7DF + DFFFE7DFDFFFB84927FFB8492700C54F2D00C54F2DFFF1E7E7FFEFE4E4FFEFE4 + E4FFEFE4E4FFEFE4E4FFEE6644FFEE6644FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4 + E4FFEFE4E4FFC54F2DFFC54F2D00D2563400D25634E8F3D7D3FFF7E8E8FFF7E8 + E8FFF7E8E8FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8 + E8FFF2D5D1FFD25634E8D256340037170F00DF5E3C90E98D76FFF9DAD6FFFCEC + ECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFF9DA + D6FFE98C75FFDF5E3C9037170F000000001226100B36BF51359FE86341E9E963 + 41FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE863 + 41E9BF51359F26100B360000001200000000000000160000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001600000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00E7815F00E983610FED876590ED8765E8ED87 + 65FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED8765FFED87 + 65E8ED876590E983610FE7815F00E47F5D00E47F5D90EEA992FFFCEFEAFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCEF + EAFFEEA992FFE47F5D90E47F5D00D9745200D97452E8F9ECE8FFFBFBFBFFFBFB + FBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB + FBFFF8EBE7FFD97452E8D9745200CC674500CC6745FFFBFBFBFFF7F7F7FFF7F7 + F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7F7FFF7F7 + F7FFFAFAFAFFCC6745FFCC674500BE5B3900BE5B39FFF9F9F9FFF3F3F3FFF3F3 + F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3F3FFF3F3 + F3FFF6F6F6FFBE5B39FFBE5B3900B4502E00B4502EFFF6F6F6FFF0F0F0FFF0F0 + F0FFF0F0F0FFEBEBEBFFE0E0E0FFD7D6D6FFD2D1D1FFCECECEFFCECECEFFD2D1 + D1FFDEDDDDFFB4502EFFB4502E00AC482600AC4826FFF4F4F4FFEEEEEEFFAC48 + 26FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFAC4826FFD2D0 + D0FFD7D6D6FFAC4826FFAC482600AB442200AB4422FFF3F3F3FFE7E5E5FFEE66 + 44FFEE6644FFEE6644FFEE6644FFEE6644FFEE6644FFEE6644FFEE6644FFD8D4 + D4FFDBD8D8FFAB4422FFAB442200AF452300AF4523FFEDEAEAFFE1DADAFFF1ED + EDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFF1EDEDFFE0D9 + D9FFE1DBDBFFAF4523FFAF452300B8492700B84927FFEBE4E4FFE7DFDFFFE7DF + DFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DFDFFFE7DF + DFFFE7DFDFFFB84927FFB8492700C54F2D00C54F2DFFF1E7E7FFEFE4E4FFEFE4 + E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4E4FFEFE4 + E4FFEFE4E4FFC54F2DFFC54F2D00D2563400D25634E8F3D7D3FFF7E8E8FFF7E8 + E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8E8FFF7E8 + E8FFF2D5D1FFD25634E8D256340037170F00DF5E3C90E98D76FFF9DAD6FFFCEC + ECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFFCECECFFF9DA + D6FFE98C75FFDF5E3C9037170F000000001226100B36BF51359FE86341E9E963 + 41FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE96341FFE863 + 41E9BF51359F26100B360000001200000000000000160000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A00000016000000001975BA001975BA001770B7900B56A4C60142 + 96CC003F94CC002A80CC00166BCC021C70CB072D7DC80D4390C51259A3C1176C + B290186FB500186FB500FFFFFF0098763200987632009876325BF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29876 + 325B9876320098763200FFFFFF0097753100977531009775315CF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29775 + 315C9775310097753100FFFFFF0096743000967430009674305DF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29674 + 305D9674300096743000FFFFFF0095732F0095732F0095732F5FF8F0E9DCCCCB + C3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391AFF9C7C6BDCEF7EEE5DC9573 + 2F5F95732F0095732F00FFFFFF0094722E0094722E0094722E3094722E60F1E3 + D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3BBCEF1E2D3D394722E609472 + 2E3094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D319371 + 2D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3D5D293712D6293712D319472 + 2E0094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D00916F + 2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F2B63916F2B3293712D009472 + 2E0094722E0094722E00FFFFFF008C6A26008C6A26008D6B27008E6C2800906E + 2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E2A65906E2A338E6C28008D6B + 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27008E6C28348E6C + 2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3D5D28E6C28678E6C28348D6B + 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27358D6B2769F1E3 + D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFF1E2D3D38D6B27698D6B + 27358C6A26008C6A2600FFFFFF008B6925008B6925008B69256AF8F0E9DCEAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F7EEE5DC8B69 + 256A8B6925008B692500FFFFFF00674E1B00896723008967236CF5EAE0D276AF + CBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F65B95B0F66BA4BFF6F3E7DBD28967 + 236C89672300674E1B00FFFFFF0000000000654B180085631F70F5EAE0D299BB + C7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E386A8B5E391B3BFE3F3E7DBD28563 + 1F70654B180000000000FFFFFF000000000A000000177F5D1977F5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD27F5D + 1977000000170000000AFFFFFF00000000000000002D002C6CA600277CCC0016 + 6BCC001569CC000955CC000041CC000546CC001155CC001F68CC002E7CCC002B + 69A60000002E00000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001FA4 + 000020A9004A20A900A620A900CC20A900A620A9004A1FA40000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001FA3 + 004A2FB111D072E557F380EF66FD71E456F32EB010D01FA3004AFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001D9D + 00A667D94DF35BCA42FF50BF37FF4BBA32FF51C437F31D9D00A6FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C95 + 00CC57CA3DFD32A916FF2CA511FF2CA511FF39B01DFD1C9500CCFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001A8C + 00A63DBD1FF331BC12FF30BB11FF32BB12FF2FB310F31A8C00A6FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001984 + 004A1D8E04D032C010F334CE11FD2FBF0EF31C8D03D01363004AFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 00090C410061136500AB146900CC136500AB0C40006500000013FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0005000000170000001A0000001A0000001A000000190000000AFFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF000404040004040400040404460404048AAA55 + 0099AA550099AA550099AA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550073AA550000AA55000004040400040404000404048ABCBCABFFC1C1 + B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8E2FFEFEFECFFF7F7F4FFFCFC + FCFF55552B6655552B0055552B000101010001010100010101AC555555FFCC99 + 66FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFAA55009AAA550000AA5500000101010001010100010101AE808080FFEAB7 + 84FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 + 84FFA854009BA8540000A85400000101010001010100010101B07E7E7EFFE4B1 + 7EFFBB8855FFBB8855FFBB8855FFBB8855FFBB8855FFBB8855FFBB8855FFE4B1 + 7EFFA653009DA6530000A65300000101010001010100010101B27C7C7CFFE2AF + 7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B07DFFE3B07DFFBC8956FFE2AF + 7CFFA451009FA4510000A45100000101010001010100010101B5797979FFDFAC + 79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A370FFD6A370FFBE8B58FFDFAC + 79FFA14F00A1A14F0000A14F00000101010001010100010101B8757575FFDBA8 + 75FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F6CFF84A791FF3FA6A6FF8CAF + 99FF9E4D00A39E4D00009E4D00000101010001010100010101BB727272FFD8A5 + 72FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D6CFF50ACA8FFA2E5E7FF53AF + ABFF94500AA89B4B00009B4B00000101010001010100010101BE6E6E6EFFD4A1 + 6EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F83FF6BC5C6FFABF5FCFF6CC7 + C8FF636E48C38F4F0D008F4F0D000101010001010100010101C16B6B6BFFD19E + 6BFFBF8C59FFC89562FFC89562FFC59563FF4FA39FFF90E3E9FF555555FF88E1 + E9FF2E8E8ADE01ABC40401ABC4000101010001010100010101C5676767FFCD9A + 67FFBF8C59FFC4915EFFC4915EFF919778FF56B6BAFF7CE4F1FF000000FF68D8 + E7FF38A6ABEE01A8C04301A7BF000101010001010100010101C9646464FFCA97 + 64FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1D7FF46D3D7FF75B4B5FF40D0 + D2FF40C3C6F901A4BC9801A2BA010000000001010100010101CE626262FFC895 + 62FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9E0FF33D5DDFF000000FF33D5 + DDFF34D5DDFF0DACC1C7019EB63A0000000900000016000000DB606060FFCA97 + 64FFC5925FFFC5925FFF4C9590FF32C6D1FF29DBE9FF28DAE9FF79EDF5FF28DA + E9FF28DAE9FF1CC7D8EA0198AF9F000000000000002C00000087000000E7702E + 00C7702E00C7702E00C72C6662E8157882F2157882F2157882F2157882F21578 + 82F2107B87EA008398D00066779A + } + end + object itSaveDownloadedList: TIdleTimer + Interval = 300000 + OnTimer = itSaveDownloadedListTimer + left = 752 + top = 120 + end + object IconDL: TImageList + left = 24 + top = 184 + Bitmap = { + 4C69080000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002B2BCF992B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002424CCCC8686E6FF8080 + E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8484E5FF2424 + CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C1CC9CC7878E4FF6767 + DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF7575E2FF1C1C + C9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001414C6CC6F6FE1FF5555 + DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3BD3FF3838D3FF5252DAFF1414 + C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001010B9CC6767DFFF4B4B + D8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1BC9FF1B1BC9FF3434D1FF1010 + B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000F0FA5CC5555DAFF2020 + CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF2E2ED0FF0F0F + A5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000D0D95CC3636D1FF1717 + C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF2727CDFF0D0D + 95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000B0B84CC2C2CCFFF1414 + C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1E1ECAFF0B0B + 84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000A0A75CC2525CDFF1212 + C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1919C8FF0A0A + 75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0009096ACC2727CDFF1C1C + C9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717C8FF1717C8FF1919C8FF0909 + 6ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF000000000306063EA0080860CC0808 + 60CC080860CC080860CC080860CC080860CC080860CC080860CC080860CC0606 + 3EA100000004FFFFFF00FFFFFF00FFFFFF0000000003000000110000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001300000004FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF001975BA001975BA001770B7900B56A4C60142 + 96CC003F94CC002A80CC00166BCC021C70CB072D7DC80D4390C51259A3C1176C + B290186FB500186FB500FFFFFF0098763200987632009876325BF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29876 + 325B9876320098763200FFFFFF0097753100977531009775315CF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29775 + 315C9775310097753100FFFFFF0096743000967430009674305DF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29674 + 305D9674300096743000FFFFFF0095732F0095732F0095732F5FF8F0E9DCCCCB + C3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391AFF9C7C6BDCEF7EEE5DC9573 + 2F5F95732F0095732F00FFFFFF0094722E0094722E0094722E3094722E60F1E3 + D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3BBCEF1E2D3D394722E609472 + 2E3094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D319371 + 2D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3D5D293712D6293712D319472 + 2E0094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D00916F + 2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F2B63916F2B3293712D009472 + 2E0094722E0094722E00FFFFFF008C6A26008C6A26008D6B27008E6C2800906E + 2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E2A65906E2A338E6C28008D6B + 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27008E6C28348E6C + 2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3D5D28E6C28678E6C28348D6B + 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27358D6B2769F1E3 + D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFF1E2D3D38D6B27698D6B + 27358C6A26008C6A2600FFFFFF008B6925008B6925008B69256AF8F0E9DCEAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F7EEE5DC8B69 + 256A8B6925008B692500FFFFFF00674E1B00896723008967236CF5EAE0D276AF + CBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F65B95B0F66BA4BFF6F3E7DBD28967 + 236C89672300674E1B00FFFFFF0000000000654B180085631F70F5EAE0D299BB + C7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E386A8B5E391B3BFE3F3E7DBD28563 + 1F70654B180000000000FFFFFF000000000A000000177F5D1977F5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD27F5D + 1977000000170000000AFFFFFF00000000130000002D002C6CA600277CCC0016 + 6BCC001569CC000955CC000041CC000546CC001155CC001F68CC002E7CCC002B + 69A60000002E00000013FFFFFF00FFFFFF0043DBE50043DBE50043DBE50044DC + E69944DCE6CC44DCE69944DCE60044DCE6CC44DCE60041D8E1003FD6DF003FD6 + DF003FD6DF00FFFFFF00FFFFFF00FFFFFF0041D9E20041D9E20041D9E20041D9 + E2CC97E6FCFF41D9E2CC40D7E00041D9E20040D7E0003FD6DF003FD6DF003FD6 + DF003FD6DF00FFFFFF00FFFFFF00FFFFFF003FD6DF003FD6DF003FD6DF003FD6 + DF993ED5DECC3ED5DECC3ED5DECC3ED5DE993ED5DE003ED5DECC3ED5DE003ED5 + DE003ED5DE00FFFFFF00FFFFFF00FFFFFF003AD1D9003AD1D9003AD1D9003AD1 + D9003AD1D9003AD1D9CC92E7FBFF3AD1D9CC38CFD7003AD1D90039D0D80039D0 + D80039D0D800FFFFFF00FFFFFF00FFFFFF0035CBD20035CBD20035CBD20036CC + D39936CCD4CC36CCD4CC36CCD4CC36CCD4CC36CCD4CC36CCD39935CBD20035CB + D20035CBD200FFFFFF00FFFFFF00FFFFFF0032C7CE0032C7CE0032C7CE0032C7 + CECC8BE6F8FF34C8CFCE8AE5F7FF32C7CECC88E6F7FF32C7CECC32C7CE0032C7 + CE0032C7CE00FFFFFF00FFFFFF00FFFFFF001DB0B4002BBFC5002BBFC5002CC0 + C6993CCAD1D73CCAD1D734C5CCD22DC1C7CC2DC1C7CC2CC0C6992BBFC5002BBF + C5001DB0B400FFFFFF00FFFFFF00FFFFFF001DB0B40021B4B90028BCC10028BC + C1CC83E4F4FF48CFD6E381E3F3FF2CBFC4CF80E4F3FF28BCC1CC28BCC10021B4 + B9001DB0B400FFFFFF00FFFFFF00FFFFFF001DB0B4001EB1B50020B3B70022B5 + BACC6FDEEAF856D6DDEF4CD0D7E842C9D0E142C9D0E122B5B9991EB1B5001EB1 + B5001DB0B400FFFFFF00FFFFFF00FFFFFF001DAFB3991DB0B4CC1DB0B4CC1DB0 + B4CC77E4F0FF63DFE6FA69E3EBFF5CD9E0F574E4EFFF1DB0B4CC1DB0B4CC1DB0 + B4CC1DAFB399FFFFFF00FFFFFF00FFFFFF0019ABAE5C18AAADCC82E4F4FF76E3 + EFFF6FE3EDFF64DEE6FF5AD4DCFF50CAD2FF52C8D1FF57C8D3FF62CDDAFF18AA + ADCC19ABAE5CFFFFFF00FFFFFF00FFFFFF0018AAAD0014A5A85C13A4A7CC7AE1 + EFFF4FCDD7FF44C2CCFF43C1CBFF43C1CBFF43C1CBFF5BCBD9FF13A4A7CC14A5 + A85C18AAAD00FFFFFF00FFFFFF00FFFFFF0018AAAD0013A4A70010A0A25C0F9F + A1CC4ECEE6FF2DC3DBFF2DC3DBFF2DC3DBFF47CDE4FF0F9FA1CC10A0A25C13A4 + A70018AAAD00FFFFFF00FFFFFF00FFFFFF000000000000000000085051000C9C + 9D5C0B9B9CCC32CDF2FF13C7EFFF2ECDF2FF0B9B9CCC0C9C9D5C085051000000 + 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 + 001906696A6E089796CC1ECCF9FF089796CC06696A6E0000001A000000110000 + 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 + 00320000003304605F74059392CC04605F740000003300000033000000220000 + 000800000000FFFFFF00FFFFFF00FFFFFF00E99E3F00E99E3F00E99E3F00EA9F + 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398 + 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B + 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398 + 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398 + 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297 + 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92 + 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91 + 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C + 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B + 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287 + 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287 + 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F + 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E + 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A + 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72 + 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73 + 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E + 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D + 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D + 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF + 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166 + 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3 + 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61 + 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A + 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60 + 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156 + 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000 + 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 + 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000 + 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 + 00320000003363320274974C02CC633202740000003300000033000000220000 + 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA + 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE + 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2 + 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5 + 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B + 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7 + 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197 + 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197 + 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1 + 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094 + 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC + 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094 + 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA + 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A + 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82 + 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000 + 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657 + 0048077200CC16A60AE8087601C406570029021E000000000000000000000000 + 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000 + 002D02330066025F00CC012B005500000029000000220000001A000000130000 + 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000 + 00170000001A000000190000001700000015000000110000000D0000000A0000 + 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF000462BF000462BF040462C0680462C08B0462 + C08B0462C08B004080CC004080CC004080CC004080CC0462C08B0462C08B0462 + C08B0462C0680462BF040462BF000461BE000461BE232A7CCCA589BCEFFF88BB + EEFF88BBEEFF35689BFF35689BFF35689BFF35689BFF88BBEEFF88BBEEFF89BC + EFFF2A7CCCA50461BE230461BE00045FBB000460BC474D94D9C489BCEFFF88BB + EEFF88BBEEFF4174A7FF4174A7FF4174A7FF3E71A4FF88BBEEFF88BBEEFF89BC + EFFF4D94D9C40460BC47045FBB00045FB900045FB96D6BA6DFE080B3E6FF80B3 + E6FF80B3E6FF4E81B4FF4E81B4FF4E81B4FF487BAEFF80B3E6FF80B3E6FF80B3 + E6FF6BA6DFE0045FB96D045FB900035DB600035DB695A7DBFEFDAADDFFFFAADD + FFFFAADDFFFF77AADDFF77AADDFF77AADDFF6699CCFFAADDFFFFAADDFFFFAADD + FFFFA7DBFEFD035DB695035DB600035BB300035BB3989FD2F9FF95C8F3FF95C8 + F3FF95C8F3FF5588BBFF4477AAFF5588BBFF4073A6FF95C8F3FF95C8F3FF95C8 + F3FF9FD2F9FF035BB398035BB300035AB000035AB09B9BCEF6FF91C4F0FF91C4 + F0FF91C4F0FF4477AAFF91C4F0FF4477AAFF91C4F0FF91C4F0FF91C4F0FF91C4 + F0FF9BCEF6FF035AB09B035AB0000358AC000358AC9F96C9F2FF8CBFECFF8CBF + ECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBFECFF8CBF + ECFF96C9F2FF0358AC9F0358AC000356A8000356A8A38FC2EEFFBBBBBBFF87BA + E9FFBBBBBBFF87BAE9FFBBBBBBFF999999FFBBBBBBFFBBBBBBFFBBBBBBFFBBBB + BBFF999999FF02417F940356A800040404000404048ABBBBBBFF777777FFBBBB + BBFF777777FFBBBBBBFF777777FF82B5E5FF999999FFEEEEEEFFDDDDDDFFCCCC + CCFFBBBBBBFF00000066000000000251A0000251A0AB777777FF7DB0E1FF7777 + 77FF7DB0E1FF777777FF999999FF777777FF777777FF777777FF777777FF7777 + 77FF999999FF023D789B0251A00001132600014A94B87BAEE0FF7AADDFFF7AAD + DFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AADDFFF7AAD + DFFF7BAEE0FF014A94B8011326000000001E0133669E014487C5014487C50144 + 87C5014487C5014487C5014487C5014487C5014487C5014487C5014487C50144 + 87C5014487C50133669E0000001E0000000F000000170000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A000000170000000FFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0001B0C90001B2CB0001B3CC0001B3 + CC1601B3CC5B01B3CC8B01B3CCA401B3CCA401B3CC8B01B3CC5B01B3CC1601B3 + CC0001B2CB0001B0C900FFFFFF00FFFFFF0001B0C90001B2CB0001B3CC4011B9 + D0A361D8E5D097EEF7EEA5F5FDFBA5F4FDFB95EDF7EE5DD6E5D011B9D0A301B3 + CC4001B2CB0001B0C900FFFFFF00FFFFFF0001B0C90001B2CB411EBDD2B297EE + F6F08DEDFCFF81EAFBFF81EAFBFF81EAFBFF81EAFBFF8BEDFCFF8FEBF6F01BBC + D2B201B2CB4101B0C900FFFFFF00FFFFFF0001B0C91611B6CDA593EBF5F07DE8 + F8FF79E6F7FF79E6F7FF757575FF757575FF79E6F7FF79E6F7FF7CE7F8FF84E7 + F3F00EB5CDA501B0C916FFFFFF00FFFFFF0001AEC75D5AD2E1D27DE6F5FF70E2 + F3FF70E2F3FF70E2F3FF666666FF666666FF70E2F3FF70E2F3FF70E2F3FF78E5 + F5FF49CDDFD201AEC75DFFFFFF00FFFFFF0001ABC49082E4EFEF69DFF0FF69DF + F0FF69DFF0FF63DCEBFF303030FF181818FF48CCD4FF45C9D2FF45C9D2FF48CC + D4FF58D3DCEF01ABC490FFFFFF00FFFFFF0001A8C1AB85E7F3FC66DDEEFF61DB + EAFF4DD4DAFF42CFD0FF000000FF000000FF40CFCFFF40CFCFFF40CFCFFF40CF + CFFF4FD4D4FC01A8C1ABFFFFFF00FFFFFF0001A5BEAD80E5F1FC56D9E5FF3FD2 + D6FF3CD1D4FF3CD1D4FF000000FF000000FF3CD1D4FF3CD1D4FF3CD1D4FF3CD1 + D4FF44D2D6FC01A5BEADFFFFFF00FFFFFF0001A2BA945DD8E2F038D4D9FF37D4 + D9FF37D4D9FF37D4D9FF81EAEDFF81EAEDFF37D4D9FF37D4D9FF37D4D9FF37D4 + D9FF32CDD5F001A2BA94FFFFFF00FFFFFF00019FB7622DBFCED739D8DFFF32D6 + DEFF32D6DEFF32D6DEFF000000FF000000FF32D6DEFF32D6DEFF32D6DEFF32D6 + DEFF19BAC9D7019FB762FFFFFF00FFFFFF00019CB41807A1B7B136D3DEF22ED9 + E4FF2DD9E3FF2DD9E3FF000000FF000000FF2DD9E3FF2DD9E3FF2DD9E3FF26CF + DCF205A0B7B1019CB418FFFFFF00FFFFFF00019AB2000097AE47089EB4C127D0 + DFF329DBE8FF28DBE8FF7AEDF4FF7AEDF4FF28DBE8FF28DBE8FF22CFDEF3069E + B4C10097AE47019AB200FFFFFF00FFFFFF000000000000252A000067784A038E + A5BA12AFC2E01ECCDDF423D9E9FD23D9E9FD1ECCDDF412AFC2E0038EA5BA0067 + 784A00252A0000000000FFFFFF00FFFFFF0000000004000000170000002B0023 + 2943005D6D7F007C91AB008096C4008096C4007C91AB005D6D7F002329430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 + A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 + A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 + AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 + A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B + E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F + B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 + D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F + DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 + CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747 + CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 + BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616 + A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E + B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111 + A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 + ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111 + AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 + B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111 + B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 + BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111 + BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 + C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F + BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 + C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303 + 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 + 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 + 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 + 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00 + } + end + object IconMed: TImageList + Height = 48 + Width = 48 + left = 27 + top = 268 + Bitmap = { + 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004D6BEC004D6BEC004D6BEC004D6B + EC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6B + EC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC104D6BEC4E4D6BEC8C4D6B + ECBA4D6BECD84D6BECEE4D6BECF94D6BECF94D6BECEE4D6BECD84D6BECBA4D6B + EC8C4D6BEC4F4D6BEC104D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6B + EC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6BEC004D6B + EC004D6BEC004D6BEC00FFFFFF00FFFFFF004D6AEB004D6AEB004D6AEB004D6A + EB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6A + EB004D6AEB004D6AEB074D6AEB5B4D6AEBB74D6AEBFC4D6AEBFF4D6AEBFF4D6A + EBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6AEBFF4D6A + EBFF4D6AEBFF4D6AEBFC4D6AEBB84D6AEB5B4D6AEB074D6AEB004D6AEB004D6A + EB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6AEB004D6A + EB004D6AEB004D6AEB00FFFFFF00FFFFFF004C6AEA004C6AEA004C6AEA004C6A + EA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6A + EA094C6AEA724C6AEAE44C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6A + EAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6A + EAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAFF4C6AEAE54C6AEA724C6AEA094C6A + EA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6AEA004C6A + EA004C6AEA004C6AEA00FFFFFF00FFFFFF004C69E9004C69E9004C69E9004C69 + E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69E9494C69 + E9DC4C69E9FF4C69E9FF4C69E9FF4C69E9FF4C69E9FF617BECFF8095F1FF92A4 + F4FF9DAEF6FFA6B5F7FFAAB8F8FFAAB8F8FFA6B5F7FF9DAEF6FF92A4F4FF8095 + F1FF617BECFF4C69E9FF4C69E9FF4C69E9FF4C69E9FF4C69E9FF4C69E9DC4C69 + E9494C69E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69E9004C69 + E9004C69E9004C69E900FFFFFF00FFFFFF004B68E8004B68E8004B68E8004B68 + E8004B68E8004B68E8004B68E8004B68E8004B68E8084B68E8964B68E8FF4B68 + E8FF4B68E8FF4B68E8FF5872EAFF8498F1FFA7B5F7FFACB9F8FFACB9F8FFACB9 + F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9F8FFACB9 + F8FFACB9F8FFA8B6F7FF8498F1FF5873EAFF4B68E8FF4B68E8FF4B68E8FF4B68 + E8FF4B68E8964B68E8084B68E8004B68E8004B68E8004B68E8004B68E8004B68 + E8004B68E8004B68E800FFFFFF00FFFFFF004A67E7004A67E7004A67E7004A67 + E7004A67E7004A67E7004A67E7004A67E7174A67E7CB4A67E7FF4A67E7FF4A67 + E7FF536FE9FF8C9FF3FFAAB9F8FFAAB9F8FFAAB9F8FF9FAFF7FF8DA0F5FF7C92 + F4FF748CF3FF6F88F3FF6C85F3FF6C85F3FF6F88F3FF748CF3FF7C92F4FF8DA0 + F5FF9FAFF7FFAAB9F8FFAAB9F8FFAAB9F8FF8C9FF3FF536FE9FF4A67E7FF4A67 + E7FF4A67E7FF4A67E7CD4A67E7174A67E7004A67E7004A67E7004A67E7004A67 + E7004A67E7004A67E700FFFFFF00FFFFFF004966E5004966E5004966E5004966 + E5004966E5004966E5004966E5224966E5DB4966E5FF4966E5FF4966E5FF7188 + ECFFA4B3F6FFAAB8F7FFAAB8F7FF91A3F5FF7189F2FF647EF1FF647EF1FF647E + F1FF647EF1FF647EF1FF647EF1FF647EF1FF647EF1FF647EF1FF647EF1FF647E + F1FF647EF1FF7189F2FF91A3F5FFAAB8F7FFAAB8F7FFA4B3F6FF7188ECFF4966 + E5FF4966E5FF4966E5FF4966E5DB4966E5214966E5004966E5004966E5004966 + E5004966E5004966E500FFFFFF00FFFFFF004965E4004965E4004965E4004965 + E4004965E4004965E41C4965E4DF4965E4FF4965E4FF4965E4FF8599F0FFA9B8 + F7FFA9B8F7FF94A6F5FF6C84F1FF637DF0FF637DF0FF637DF0FF637DF0FF637D + F0FF637DF0FF637DF0FF637DF0FF637DF0FF637DF0FF637DF0FF637DF0FF637D + F0FF637DF0FF637DF0FF637DF0FF6C84F1FF94A6F5FFA9B8F7FFA9B8F7FF8699 + F0FF4965E4FF4965E4FF4965E4FF4965E4DF4965E41C4965E4004965E4004965 + E4004965E4004965E400FFFFFF00FFFFFF004864E2004864E2004864E2004864 + E2004864E20A4864E2CE4864E2FF4864E2FF4864E2FF8B9DF0FFA9B7F6FFA9B7 + F6FF7B91F2FF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627C + EFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF627C + EFFF627CEFFF627CEFFF627CEFFF627CEFFF627CEFFF7B91F2FFA7B6F6FFA9B7 + F6FF8B9DF0FF4864E2FF4864E2FF4864E2FF4864E2CE4864E20A4864E2004864 + E2004864E2004864E200FFFFFF00FFFFFF004763E1004763E1004763E1004763 + E1004763E19A4763E1FF4763E1FF4763E1FF8B9DF0FFA8B6F6FFA3B2F5FF758B + F0FF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF617A + EEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF617AEEFF758BF0FFA3B2 + F5FFA8B6F6FF8B9DF0FF4763E1FF4763E1FF4763E1FF4763E19B4763E1004763 + E1004763E1004763E100FFFFFF00FFFFFF004662DF004662DF004662DF004662 + DF4A4662DFFF4662DFFF4662DFFF8497EDFFA7B5F5FFA0B0F4FF7188EFFF5F79 + EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F79 + EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF5F79EDFF7188 + EFFFA0B0F4FFA7B5F5FF8497EDFF4662DFFF4662DFFF4662DFFF4662DF4A4662 + DF004662DF004662DF00FFFFFF00FFFFFF004561DE004561DE004561DE084561 + DEDC4561DEFF4561DEFF6F85E8FFA7B5F5FFA5B3F4FF7188EEFF5E78ECFF5E78 + ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E78 + ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78ECFF5E78 + ECFF7188EEFFA5B3F4FFA7B5F5FF7086E8FF4561DEFF4561DEFF4561DEDD4561 + DE084561DE004561DE00FFFFFF00FFFFFF004460DC004460DC004460DC714460 + DCFF4460DCFF4E68DEFFA0AFF2FFA6B4F4FF768CEEFF5C76EBFF5C76EBFF5C76 + EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C76 + EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76EBFF5C76 + EBFF5C76EBFF768CEEFFA6B4F4FFA0AFF2FF4E69DEFF4460DCFF4460DCFF4460 + DC714460DC004460DC00FFFFFF00FFFFFF00435EDA00435EDA07435EDAE5435E + DAFF435EDAFF8598EBFFA5B3F3FF8EA0F1FF5B74EAFF5B74EAFF5B74EAFF5B74 + EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B74 + EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74EAFF5B74 + EAFF5B74EAFF5B74EAFF8EA0F1FFA5B3F3FF8598EBFF435EDAFF435EDAFF435E + DAE6435EDA08435EDA00FFFFFF00FFFFFF00425DD800425DD85B425DD8FF425D + D8FF4F68DBFFA4B2F2FFA4B2F2FF627BE9FF5973E8FF5973E8FF5973E8FF5973 + E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5973 + E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973E8FF5973 + E8FF5973E8FF5973E8FF627BE9FFA4B2F2FFA4B2F2FF4F69DCFF425DD8FF425D + D8FF425DD85B425DD800FFFFFF00FFFFFF00415CD700415CD7B8415CD7FF415C + D7FF7B8EE7FFA3B1F2FF889AEEFF5871E7FF5871E7FF5871E7FF5871E7FF5871 + E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5871 + E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871E7FF5871 + E7FF5871E7FF5871E7FF5871E7FF889AEEFFA3B1F2FF7B8EE7FF415CD7FF415C + D7FF415CD7B8415CD700FFFFFF00FFFFFF00405BD510405BD5FC405BD5FF405B + D5FF9EACF0FFA2B0F1FF657CE8FF5670E6FF5670E6FF5670E6FF5670E6FF5670 + E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FFFAFB + FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FAFEFF5670 + E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670E6FF5670 + E6FF5670E6FF5670E6FF5670E6FF657CE8FFA2B0F1FF9EACF0FF405BD5FF405B + D5FF405BD5FC405BD510FFFFFF00FFFFFF003F59D34F3F59D3FF3F59D3FF556C + DAFFA1AFF1FF94A5EFFF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546E + E5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FFE8EC + FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8ECFCFF546E + E5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546EE5FF546E + E5FF546EE5FF546EE5FF546EE5FF546EE5FF94A5EFFFA1AFF1FF556CDAFF3F59 + D3FF3F59D3FF3F59D34FFFFFFF00FFFFFF003E58D18B3E58D1FF3E58D1FF7487 + E2FFA1AEF0FF8092EAFF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536C + E3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FFD8DE + F9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8DEF9FF536C + E3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536CE3FF536C + E3FF536CE3FF536CE3FF536CE3FF536CE3FF8092EAFFA1AEF0FF7487E2FF3E58 + D1FF3E58D1FF3E58D18CFFFFFF00FFFFFF003D57CFB43D57CFFF3D57CFFF8294 + E6FF9FAEEFFF6D83E7FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516B + E2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FFC6CF + F6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6CFF6FF516B + E2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516BE2FF516B + E2FF516BE2FF516BE2FF516BE2FF516BE2FF6D83E7FF9FAEEFFF8395E6FF3D57 + CFFF3D57CFFF3D57CFB5FFFFFF00FFFFFF003C55CDD93C55CDFF3C55CDFF8FA0 + EAFF9EADEFFF6078E4FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69 + E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FFB5C0 + F2FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4BFF2FF4F69 + E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF4F69 + E1FF4F69E1FF4F69E1FF4F69E1FF4F69E1FF6078E4FF9EADEFFF8FA0EAFF3C55 + CDFF3C55CDFF3C55CDD9FFFFFF00FFFFFF003B54CBF13B54CBFF3B54CBFF98A7 + ECFF9DACEEFF576FE2FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67 + E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FFA4B1 + EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4B1EFFF4D67 + E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF4D67 + E0FF4D67E0FF4D67E0FF4D67E0FF4D67E0FF5971E2FF9DACEEFF96A6ECFF3B54 + CBFF3B54CBFF3B54CBEDFFFFFF00FFFFFF003953C9FF3953C9FF3953C9FF9DAA + EDFF9DAAEDFF526ADFFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65 + DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF91A0 + EBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91A0EBFF4C65 + DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF4C65 + DEFF4C65DEFF4C65DEFF4C65DEFF4C65DEFF546CDFFF9DAAEDFF9BA8ECFF3953 + C9FF3953C9FF3953C9F9FFFFFF00FFFFFF003851C7FF3851C7FF3851C7FF9CAA + ECFF9CAAECFF5069DEFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64 + DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF7E90 + E7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F91E7FF4A64 + DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF4A64 + DDFF4A64DDFF4A64DDFF4A64DDFF4A64DDFF526BDEFF9CAAECFF9AA8EBFF3851 + C7FF3851C7FF3851C7F9FFFFFF00FFFFFF003750C6F13750C6FF3750C6FF96A4 + EAFF9BA9ECFF526BDEFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862 + DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF6D81 + E3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D81E3FF4862 + DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862DCFF4862 + DCFF4862DCFF4862DCFF4862DCFF4862DCFF546CDEFF9BA9ECFF94A3E9FF3750 + C6FF3750C6FF3750C6EDFFFFFF00FFFFFF00364FC4D9364FC4FF364FC4FF8B9B + E5FF9AA8EBFF5970DEFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760 + DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF586F + DDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF586FDDFF4760 + DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760DAFF4760 + DAFF4760DAFF4760DAFF4760DAFF4760DAFF5970DEFF9AA8EBFF8B9BE5FF364F + C4FF364FC4FF364FC4D9FFFFFF00FFFFFF00354DC2B4354DC2FF354DC2FF7C8D + DEFF99A7EAFF6378DFFF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455E + D9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF4760 + D9FFFDFDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDFDFFFF4760D9FF455E + D9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455ED9FF455E + D9FF455ED9FF455ED9FF455ED9FF455ED9FF6378DFFF99A7EAFF7C8DDEFF354D + C2FF354DC2FF354DC2B5FFFFFF00FFFFFF00344CC08C344CC0FF344CC0FF6B7D + D7FF98A6EAFF7486E2FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435C + D8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435C + D8FFEDF0FBFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEF0FBFF435CD8FF435C + D8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435CD8FF435C + D8FF435CD8FF435CD8FF435CD8FF435CD8FF7486E2FF98A6EAFF6B7DD7FF344C + C0FF344CC0FF344CC08CFFFFFF00FFFFFF00334BBE4F334BBEFF334BBEFF495F + C8FF97A5E9FF8999E6FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415B + D7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415B + D7FFDADFF7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDADFF7FF415BD7FF415B + D7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415BD7FF415B + D7FF415BD7FF415BD7FF415BD7FF415BD7FF8999E6FF97A5E9FF495FC8FF334B + BEFF334BBEFF334BBE4FFFFFFF00FFFFFF00324ABC10324ABCFC324ABCFF324A + BCFF92A0E6FF96A4E8FF5067D9FF4059D5FF4059D5FF4059D5FF4059D5FF4059 + D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059 + D5FF677BDEFF7385E0FF7385E0FF7385E0FF7385E0FF677BDEFF4059D5FF4059 + D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059D5FF4059 + D5FF4059D5FF4059D5FF4059D5FF5067D9FF96A4E8FF92A0E6FF324ABCFF324A + BCFF324ABCFC324ABC11FFFFFF00FFFFFF003148BA003148BAB83148BAFF3148 + BAFF6C7ED5FF95A3E7FF7688E0FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 + D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 + D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 + D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57D4FF3E57 + D4FF3E57D4FF3E57D4FF3E57D4FF7688E0FF95A3E7FF6D7ED5FF3148BAFF3148 + BAFF3148BAB93148BA00FFFFFF00FFFFFF003047B8003047B85B3047B8FF3047 + B8FF3E53BEFF94A2E7FF94A2E7FF475FD5FF3C56D3FF3C56D3FF3C56D3FF3C56 + D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56 + D3FF92A0E6FF97A5E8FF97A5E8FF97A5E8FF97A5E8FF97A5E8FF475FD5FF3C56 + D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56D3FF3C56 + D3FF3C56D3FF3C56D3FF475FD5FF94A2E7FF94A2E7FF3E53BEFF3047B8FF3047 + B8FF3047B85C3047B800FFFFFF00FFFFFF002F46B7002F46B7082F46B7E62F46 + B7FF2F46B7FF7384D7FF93A1E6FF788AE0FF3B54D2FF3B54D2FF3B54D2FF3B54 + D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54 + D2FFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5268D7FF3B54 + D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54D2FF3B54 + D2FF3B54D2FF3B54D2FF788AE0FF93A1E6FF7384D7FF2F46B7FF2F46B7FF2F46 + B7E62F46B7082F46B700FFFFFF00FFFFFF002E45B5002E45B5002E45B5712E45 + B5FF2E45B5FF384EBAFF8C9BE2FF92A1E5FF576DD7FF3953D0FF3953D0FF3953 + D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953 + D0FFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5067D6FF3953 + D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953D0FF3953 + D0FF3953D0FF576DD7FF92A1E5FF8C9CE2FF384EBAFF2E45B5FF2E45B5FF2E45 + B5722E45B5002E45B500FFFFFF00FFFFFF002D43B3002D43B3002D43B3082D43 + B3DD2D43B3FF2D43B3FF596BC9FF929FE5FF8F9DE4FF4F65D5FF3851CFFF3851 + CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851 + CFFFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F65D5FF3851 + CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851CFFF3851 + CFFF4F65D5FF8F9DE4FF929FE5FF5A6CC9FF2D43B3FF2D43B3FF2D43B3DD2D43 + B3082D43B3002D43B300FFFFFF00FFFFFF002C42B1002C42B1002C42B1002C42 + B14A2C42B1FF2C42B1FF2C42B1FF6D7DD2FF919EE4FF8897E2FF4C62D3FF364F + CEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364F + CEFFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E64D4FF364F + CEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF364FCEFF4C62 + D3FF8897E2FF919EE4FF6D7DD2FF2C42B1FF2C42B1FF2C42B1FF2C42B14B2C42 + B1002C42B1002C42B100FFFFFF00FFFFFF002B41B0002B41B0002B41B0002B41 + B0002B41B09C2B41B0FF2B41B0FF2B41B0FF7283D5FF909EE4FF8A98E2FF4F65 + D3FF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354E + CDFFF3F5FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D63D3FF354E + CDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF354ECDFF4F65D3FF8A98 + E2FF909EE4FF7283D5FF2B41B0FF2B41B0FF2B41B0FF2B41B09E2B41B0002B41 + B0002B41B0002B41B000FFFFFF00FFFFFF002A40AE002A40AE002A40AE002A40 + AE002A40AE0A2A40AECF2A40AEFF2A40AEFF2A40AEFF7081D3FF8F9DE3FF8D9B + E2FF546AD4FF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334D + CCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF334D + CCFF334DCCFF334DCCFF334DCCFF334DCCFF334DCCFF546AD4FF8D9BE2FF8F9D + E3FF7081D3FF2A40AEFF2A40AEFF2A40AEFF2A40AECF2A40AE0A2A40AE002A40 + AE002A40AE002A40AE00FFFFFF00FFFFFF00293FAD00293FAD00293FAD00293F + AD00293FAD00293FAD1C293FADE0293FADFF293FADFF293FADFF697ACEFF8E9C + E2FF8E9CE2FF7283DBFF3D55CEFF324BCBFF324BCBFF324BCBFF324BCBFF324B + CBFF324BCBFF324BCBFF324BCBFF324BCBFF324BCBFF324BCBFF324BCBFF324B + CBFF324BCBFF324BCBFF324BCBFF3D55CEFF7283DBFF8E9CE2FF8E9CE2FF697A + CEFF293FADFF293FADFF293FADFF293FADE0293FAD1C293FAD00293FAD00293F + AD00293FAD00293FAD00FFFFFF00FFFFFF00283EAB00283EAB00283EAB00283E + AB00283EAB00283EAB00283EAB22283EABDD283EABFF283EABFF283EABFF5466 + C3FF8896DFFF8E9CE2FF8E9CE2FF6D7FD9FF435ACFFF314ACAFF314ACAFF314A + CAFF314ACAFF314ACAFF314ACAFF314ACAFF314ACAFF314ACAFF314ACAFF314A + CAFF314ACAFF435ACFFF6D7FD9FF8E9CE2FF8E9CE2FF8796DEFF5366C2FF283E + ABFF283EABFF283EABFF283EABDD283EAB22283EAB00283EAB00283EAB00283E + AB00283EAB00283EAB00FFFFFF00FFFFFF00273DAA00273DAA00273DAA00273D + AA00273DAA00273DAA00273DAA00273DAA18273DAACD273DAAFF273DAAFF273D + AAFF3146AFFF6D7DD0FF8D9BE1FF8D9BE1FF8D9BE1FF7E8EDDFF6678D7FF5166 + D2FF475DCFFF3E55CDFF3951CBFF3951CBFF3E55CDFF475DCFFF5166D2FF6678 + D7FF7E8EDDFF8D9BE1FF8D9BE1FF8D9BE1FF6D7DD0FF3146AFFF273DAAFF273D + AAFF273DAAFF273DAACD273DAA18273DAA00273DAA00273DAA00273DAA00273D + AA00273DAA00273DAA00FFFFFF00FFFFFF00273CA800273CA800273CA800273C + A800273CA800273CA800273CA800273CA800273CA808273CA899273CA8FF273C + A8FF273CA8FF273CA8FF3549B0FF6374CAFF8998DFFF8D9BE1FF8D9BE1FF8D9B + E1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9BE1FF8D9B + E1FF8D9BE1FF8998DFFF6374CAFF3549B0FF273CA8FF273CA8FF273CA8FF273C + A8FF273CA898273CA808273CA800273CA800273CA800273CA800273CA800273C + A800273CA800273CA800FFFFFF00FFFFFF00263BA700263BA700263BA700263B + A700263BA700263BA700263BA700263BA700263BA700263BA700263BA74A263B + A7DC263BA7FF263BA7FF263BA7FF263BA7FF263BA7FF3D50B4FF5E6FC7FF6E7E + D0FF7C8BD8FF8594DDFF8A98E0FF8A98E0FF8594DDFF7C8BD8FF6E7ED0FF5E6F + C7FF3D50B4FF263BA7FF263BA7FF263BA7FF263BA7FF263BA7FF263BA7DC263B + A749263BA700263BA700263BA700263BA700263BA700263BA700263BA700263B + A700263BA700263BA700FFFFFF00FFFFFF00253AA600253AA600253AA600253A + A600253AA600253AA600253AA600253AA600253AA600253AA600253AA600253A + A609253AA672253AA6E6253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253A + A6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6FF253A + A6FF253AA6FF253AA6FF253AA6FF253AA6FF253AA6E6253AA672253AA609253A + A600253AA600253AA600253AA600253AA600253AA600253AA600253AA600253A + A600253AA600253AA600FFFFFF00FFFFFF002439A5002439A5002439A5002439 + A5002439A5002439A5002439A5002439A5002439A5002439A5002439A5002439 + A5002439A5002439A5072439A55B2439A5BA2439A5FC2439A5FF2439A5FF2439 + A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439A5FF2439 + A5FF2439A5FF2439A5FC2439A5BA2439A55B2439A5072439A5002439A5002439 + A5002439A5002439A5002439A5002439A5002439A5002439A5002439A5002439 + A5002439A5002439A500FFFFFF00FFFFFF002439A4002439A4002439A4002439 + A4002439A4002439A4002439A4002439A4002439A4002439A4002439A4002439 + A4002439A4002439A4002439A4002439A4002439A4112439A4502439A48B2439 + A4B52439A4D72439A4EE2439A4FA2439A4FA2439A4EE2439A4D72439A4B52439 + A48B2439A4502439A4112439A4002439A4002439A4002439A4002439A4002439 + A4002439A4002439A4002439A4002439A4002439A4002439A4002439A4002439 + A4002439A4002439A400FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 + } + end + object IconSmall: TImageList + left = 27 + top = 328 + Bitmap = { + 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D898 + 5223D4964D7DD2924CDBCD8C45F3CB8B41F3C98B40DBC78B407DC5873D23FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D6974F53D191 + 49E6D0A06AFFE0BFA0FFE3C5AEFFE3C5AEFFDFBC9FFFC89762FFBD7D35E6BC7E + 3553FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D4964D53CF8D47F4D9B2 + 8CFFE6CDB8FFE0BA9DFFD7AB85FFD6A982FFD9B391FFE1C2ABFFD4AE86FFB16B + 35F4B16F3553FFFFFF00FFFFFF00FFFFFF00D2934C22CE8E47E5D9B28CFFE6CA + B3FFD6A97DFFD1A579FFE2C4A8FFE1C3A8FFD0A276FFD1A477FFDDBDA2FFD0AC + 85FFAB6635E5A9653522FFFFFF00FFFFFF00CE91477ECD9C68FFE7CBB4FFD4A5 + 7AFFD0A077FFCF9E74FFFBF8F5FFFBF8F5FFCB9E71FFCB9D71FFCDA177FFDFC0 + A5FFB98A5BFFA45C347EFFFFFF00FFFFFF00CB8E41DBE0BC9FFFDBB393FFCFA0 + 75FFCD9E72FFCB9C71FFDDBFA3FFDDBFA2FFC5996BFFC5996BFFC4986BFFD1AB + 85FFD8BA97FF9E5635DBFFFFFF00FFFFFF00C5853BF6E4C9B0FFD0A37AFFCC9D + 71FFC79A6CFFC5986BFFFFFFFFFFFFFFFEFFC39669FFC19468FFC29468FFC398 + 6DFFDFC5ABFF955334F6FFFFFF00FFFFFF00BF7E35F6E3C7AFFFD0A276FFC599 + 6BFFC4976AFFC49669FFEEE0D4FFFBF7F4FFBF9066FFBE8F65FFBE8F64FFBE92 + 69FFDFC6AAFF925034F6FFFFFF00FFFFFF00BC7E35DBDBBC9CFFD5AD89FFC798 + 6CFFC39569FFC19367FFEDDFD3FFFAF7F4FFBB8B63FFB98A63FFB88A62FFC59D + 78FFD2B893FF905135DBFFFFFF00FFFFFF00B878357EBF915EFFE0C2A8FFC596 + 6CFFC29169FFE1CBB8FFFEFDFCFFFFFFFEFFEADCD0FFB4855EFFB3855EFFD4B5 + 99FFAE7B56FF8F51357EFFFFFF00FFFFFF00AF703522AB6935E5CFAA81FFDABC + A2FFBE9166FFBA8C62FFB7895FFFB3845EFFB1835DFFB0835CFFCDAA8DFFC6A5 + 79FF895034E589503522FFFFFF00FFFFFF00FFFFFF00A76234539F5533F4CBA7 + 7DFFD8BB9FFFC39C77FFB68A62FFB48660FFBE9672FFD1B397FFC5A377FF844F + 35F489503553FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009F5634539955 + 34E6B28057FFD5B793FFDBC3A6FFDAC3A6FFD2B490FFAB7A52FF864F34E68850 + 3553FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009754 + 35239453347D925234DB8A5034F3884F34F3895035DB8950357D84503623FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006A85 + FC236984FA7D6782F9DB6580F7F3637EF5F3617CF3DB5F7AF17D5D77EF23FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006984FA536C85 + F9E76E83EEFF92A6F4FFA0B4F8FFA0B4F8FF91A6F3FF687DE9FF5D76EBE65671 + E953FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006883F953748DF9F58497 + F1FFA9BDFBFF8AA3F8FF6B89F6FF6B89F6FF89A2F8FFA8BCFAFF7F92ECFF6279 + E6F54F69E253FFFFFF00FFFFFF00FFFFFF006781F8226983F6E68397F0FFACBF + FBFF6382F5FF6382F5FF6382F5FF617EF3FF617EF3FF607CF3FFA6B9F9FF7B8D + EAFF4D66DFE54862DB22FFFFFF00FFFFFF00637EF57E6C81ECFFA9BDFBFF6382 + F5FF8099F7FFA4B6F9FF6280F4FF607BF1FFA5B4F7FF7B8FF3FF5D76EFFFA5B5 + F8FF5D70DDFF435DD77EFFFFFF00FFFFFF005F7AF1DB91A6F3FF88A1F8FF6280 + F4FFA4B5F8FFE7EBFDFFA8B8F8FFABB8F7FFE7EBFDFF9EACF5FF5B70ECFF8293 + F1FF8998ECFF3E58D2DBFFFFFF00FFFFFF005B76EDF6A1B6F8FF6784F4FF607C + F3FF5F7AF1FFA8B5F7FFE7EBFDFFE7EAFCFFA1ADF4FF5A6EEBFF596CEAFF5F6F + E9FF9BA8F1FF3A53CEF6FFFFFF00FFFFFF005771E9F6A0B3F7FF6580F2FF5F78 + F0FF5E77EFFFAAB6F6FFE7EAFCFFE6E9FCFFA5AFF4FF5869E8FF5767E7FF5D6C + E7FF99A5F1FF354FCAF6FFFFFF00FFFFFF00526DE5DB8E9FF0FF8499F4FF5C73 + EEFFA4AFF4FFE6E9FCFFA1ADF4FFA3ACF2FFE6E8FBFF9CA5F0FF5562E5FF7D89 + EBFF8591E7FF314AC6DBFFFFFF00FFFFFF004E68E17E6073E0FFA4B3F7FF5A6E + EBFF7685EEFF9BA5F1FF5869E8FF5562E5FF9CA3F0FF6F7AE8FF535FE2FF9FA9 + F2FF5061D1FF2D46C27EFFFFFF00FFFFFF004963DC224B64DBE67888E6FFA7B3 + F5FF5767E7FF5665E6FF5665E6FF535FE2FF535FE2FF525DE1FF9FA9F2FF6F7D + DDFF2D46C1E52942BE22FFFFFF00FFFFFF00FFFFFF00425CD5533F59D3F47584 + E3FFA1ACF4FF7F8BECFF5C67E4FF5B66E3FF7D87EAFF9FA8F1FF6F7CDDFF2943 + BFF42741BD53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003A54CF533852 + CCE65264D4FF8490E7FF95A0EEFF959FEDFF838EE5FF4C5DCEFF2841BDE6263F + BB53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00334D + C823314BC67D2F48C4DB2C46C2F32A44C0F32842BEDB2640BC7D243EBA23FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0040C9 + 62233BC55E7D39C25BDB31BD54F32DBB52F32BB952DB2BB7527D28B44E23FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003DC7605336C2 + 59E659C274FF96D7A3FFA5DCAEFFA5DCAEFF95D6A1FF50B96AFF1FAB42E61FA9 + 4253FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003BC55E5334C055F47FCE + 90FFAFE1B7FF92D89DFF77CE83FF77CE83FF92D89DFFAEE1B5FF78C88BFF1D9D + 32F41D9D3653FFFFFF00FFFFFF00FFFFFF0039C25C2234BE55E57FCE90FFAEE1 + B5FF6DCC7AFF6ACA76FF68C872FF68C874FF68C875FF6BC979FFACDFB4FF76C4 + 89FF1C962DE51C942D22FFFFFF00FFFFFF0034BE597E57BF70FFAFE1B7FF6DCC + 7AFF68C872FF65C770FF63C56EFF62C46EFF63C471FFB6E3BEFF6FC77EFFACDF + B5FF48A95EFF1C8F267EFFFFFF00FFFFFF002DBB54DB95D7A1FF91D79BFF69C9 + 76FF64C66FFF61C46EFF61C36FFF61C26FFFB9E4C0FFFFFFFFFFE3F4E6FF8BD1 + 99FF8BCE9DFF1C8820DBFFFFFF00FFFFFF0026B44BF6A7DDB1FF72CC80FF66C7 + 73FFB0E1B7FFD2EED6FF63C170FFB8E3BFFFFFFFFFFFFBFDFCFF8CD099FF69C1 + 7EFFA1D7AEFF1B7F1EF6FFFFFF00FFFFFF001FAD42F6A6DCAFFF70CA7FFF73CA + 80FFF0F9F1FFFFFFFFFFEBF7EDFFFFFFFFFFFBFDFCFF88CD96FF5BB971FF67BE + 7DFFA0D7AFFF1B7A1EF6FFFFFF00FFFFFF001FA942DB91D29FFF8DD49AFF64C3 + 74FF79C987FFF2FAF4FFFFFFFFFFFDFEFDFF86CB96FF57B76DFF5BB972FF85CC + 97FF87C79AFF1B781FDBFFFFFF00FFFFFF001EA43D7E4CB064FFAADDB4FF64C1 + 79FF5FBE71FF75C585FFD4ECD9FF8ACD99FF56B66CFF58B56EFF5CB774FFA6DA + B4FF419B4EFF1B771F7EFFFFFF00FFFFFF001D9B36221C962FE572C287FFA8DB + B2FF60BC77FF5CBA73FF59B870FF59B56FFF58B56FFF5BB774FFA5D9B3FF69B8 + 7FFF1A711EE51B711F22FFFFFF00FFFFFF00FFFFFF001C912B531B8A20F46DBE + 83FFA8DBB5FF87CC98FF66BC7DFF64BA7CFF86CB98FFA5D9B4FF66B77DFF1A6C + 1DF41B711F53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C8A21531B83 + 1FE642A052FF87CA9AFF9BD3ABFF9BD2ABFF83C796FF3D974CFF1A6E1EE61B70 + 1F53FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF001C81 + 1F231B7E1F7D1B7A1FDB1A731EF31A701EF31B711FDB1B711F7D1B6C1F23FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 + } + end + object pmEditURL: TPopupMenu + OnPopup = pmEditURLPopup + left = 592 + top = 136 + object medURLUndo: TMenuItem + Caption = 'Undo' + OnClick = medURLUndoClick + end + object MenuItem9: TMenuItem + Caption = '-' + end + object medURLCut: TMenuItem + Caption = 'Cut' + OnClick = medURLCutClick + end + object medURLCopy: TMenuItem + Caption = 'Copy' + OnClick = medURLCopyClick + end + object medURLPaste: TMenuItem + Caption = 'Paste' + OnClick = medURLPasteClick + end + object medURLPasteandgo: TMenuItem + Caption = 'Paste and go' + OnClick = medURLPasteandgoClick + end + object medtURLDelete: TMenuItem + Caption = 'Delete' + OnClick = medtURLDeleteClick + end + object MenuItem15: TMenuItem + Caption = '-' + end + object medURLSelectAll: TMenuItem + Caption = 'Select all' + OnClick = medURLSelectAllClick + end + end + object appPropertiesMain: TApplicationProperties + CaptureExceptions = False + OnShowHint = appPropertiesMainShowHint + left = 80 + top = 448 + end + object itStartup: TIdleTimer + Enabled = False + Interval = 500 + OnTimer = itStartupTimer + left = 696 + top = 72 + end + object tmBackup: TIdleTimer + Interval = 60000 + OnTimer = tmBackupTimer + left = 696 + top = 120 + end + object itMonitor: TTimer + Enabled = False + OnTimer = itMonitorTimer + left = 760 + top = 296 + end + object TransferRateGraphList: TListChartSource + DataPoints.Strings = ( + '1|0|?|' + ) + left = 648 + top = 72 + end + object TransferRateToolset: TChartToolset + left = 608 + top = 72 + end + object pmSbMain: TPopupMenu + OnPopup = pmSbMainPopup + left = 283 + top = 416 + object miAbortSilentThread: TMenuItem + Caption = 'Abort' + OnClick = miAbortSilentThreadClick + end + end +end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a1ca09640..21b6787b0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1936,6 +1936,7 @@ procedure TMainForm.btUpdateListClick(Sender: TObject); i: Cardinal; {$ENDIF} begin + CloseNow; {$IFDEF SELFUPDATE} pmUpdate.Items[0].Enabled := True; pmUpdate.Items[3].Enabled := True; diff --git a/mangadownloader/forms/frmNewChapter.lfm b/mangadownloader/forms/frmNewChapter.lfm index 301983f37..d6df897ce 100644 --- a/mangadownloader/forms/frmNewChapter.lfm +++ b/mangadownloader/forms/frmNewChapter.lfm @@ -1,196 +1,196 @@ -object NewChapter: TNewChapter - Left = 486 - Height = 290 - Top = 239 - Width = 394 - BorderIcons = [] - BorderStyle = bsSizeToolWin - Caption = 'New Chapter Notification' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ClientHeight = 290 - ClientWidth = 394 - OnCreate = FormCreate - Position = poDesktopCenter - LCLVersion = '1.5' - object mmMemo: TMemo - Left = 6 - Height = 235 - Top = 17 - Width = 382 - Align = alClient - BorderSpacing.Bottom = 6 - ReadOnly = True - ScrollBars = ssAutoBoth - TabOrder = 0 - end - object lbNotification: TLabel - Left = 6 - Height = 1 - Top = 6 - Width = 382 - Align = alTop - BorderSpacing.Bottom = 10 - Font.Style = [fsBold] - ParentColor = False - ParentFont = False - end - object pnBottom: TPanel - Left = 6 - Height = 26 - Top = 258 - Width = 382 - Align = alBottom - AutoSize = True - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 6 - ClientHeight = 26 - ClientWidth = 382 - TabOrder = 1 - object btDownload: TBitBtn - Left = 0 - Height = 26 - Top = 0 - Width = 100 - Align = alLeft - AutoSize = True - Caption = '&Download' - Default = True - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 - } - ModalResult = 1 - OnClick = btDownloadClick - TabOrder = 0 - end - object btQueue: TBitBtn - Left = 106 - Height = 26 - Top = 0 - Width = 118 - Align = alLeft - AutoSize = True - Caption = '&Add to queue' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000130000 - 002D002C6CA600277CCC00166BCC001569CC000955CC000041CC000546CC0011 - 55CC001F68CC04542EEB056112EE054E00AB00000013000000000000000A0000 - 00177F5D1977F5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 - C0BFE9D3BDC0349426F62BDF1AFF0C8000D10000000A0746000000000000654B - 180085631F70F5EAE0D299BBC7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E33F99 - 46F3269323F9359C26F63DE22CFF0E8C00CC0E8C00CC0E8D0099674E1B008967 - 23008967236CF5EAE0D276AFCBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F61F95 - 23FD52E741FF52E741FF52E741FF52E741FF52E741FF109500CC8B6925008B69 - 25008B69256AF8F0E9DCEAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BE61B2 - 47E634A61EF23BAC29F866EB55FF129D00CC129D00CC129C00998C6A26008C6A - 26008D6B27358D6B2769F1E3D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 - C0BFF1E2D3D31F9F04E175EE64FF14A400CC13A10000129D00008C6A26008C6A - 26008D6B27008E6C28348E6C2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3 - D5D28E6C286738980CAE15A900CC15A9009914A80000129D00008C6A26008C6A - 26008D6B27008E6C2800906E2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E - 2A65906E2A33528B140015AA000015A9000014A80000129D000094722E009472 - 2E0094722E0093712D00916F2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F - 2B63916F2B32747F2200359C0C0015A9000014A80000129D000094722E009472 - 2E0094722E0093712D3193712D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3 - D5D293712D6293712D3194722E0094722E0094722E0094722E0094722E009472 - 2E0094722E3094722E60F1E3D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3 - BBCEF1E2D3D394722E6094722E3094722E0094722E0094722E0095732F009573 - 2F0095732F5FF8F0E9DCCCCBC3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391 - AFF9C7C6BDCEF7EEE5DC95732F5F95732F0095732F0095732F00967430009674 - 30009674305DF5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 - C0BFE9D3BDC0F3E7DBD29674305D967430009674300096743000977531009775 - 31009775315CF5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 - C0BFE9D3BDC0F3E7DBD29775315C977531009775310097753100987632009876 - 32009876325BF5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 - C0BFE9D3BDC0F3E7DBD29876325B9876320098763200987632001975BA001975 - BA001770B7900B56A4C6014296CC003F94CC002A80CC00166BCC021C70CB072D - 7DC80D4390C51259A3C1176CB290186FB500186FB500186FB500 - } - ModalResult = 4 - OnClick = btQueueClick - TabOrder = 2 - end - object btCancel: TBitBtn - Left = 300 - Height = 26 - Top = 0 - Width = 82 - Align = alRight - AutoSize = True - Caption = '&Cancel' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ModalResult = 2 - OnClick = btCancelClick - TabOrder = 1 - end - end -end +object NewChapter: TNewChapter + Left = 486 + Height = 290 + Top = 239 + Width = 394 + BorderIcons = [] + BorderStyle = bsSizeToolWin + Caption = 'New Chapter Notification' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ClientHeight = 290 + ClientWidth = 394 + OnCreate = FormCreate + Position = poDesktopCenter + LCLVersion = '1.5' + object mmMemo: TMemo + Left = 6 + Height = 235 + Top = 17 + Width = 382 + Align = alClient + BorderSpacing.Bottom = 6 + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 0 + end + object lbNotification: TLabel + Left = 6 + Height = 1 + Top = 6 + Width = 382 + Align = alTop + BorderSpacing.Bottom = 10 + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + end + object pnBottom: TPanel + Left = 6 + Height = 26 + Top = 258 + Width = 382 + Align = alBottom + AutoSize = True + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 6 + ClientHeight = 26 + ClientWidth = 382 + TabOrder = 1 + object btDownload: TBitBtn + Left = 0 + Height = 26 + Top = 0 + Width = 100 + Align = alLeft + AutoSize = True + Caption = '&Download' + Default = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } + ModalResult = 1 + OnClick = btDownloadClick + TabOrder = 0 + end + object btQueue: TBitBtn + Left = 106 + Height = 26 + Top = 0 + Width = 118 + Align = alLeft + AutoSize = True + Caption = '&Add to queue' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000130000 + 002D002C6CA600277CCC00166BCC001569CC000955CC000041CC000546CC0011 + 55CC001F68CC04542EEB056112EE054E00AB00000013000000000000000A0000 + 00177F5D1977F5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 + C0BFE9D3BDC0349426F62BDF1AFF0C8000D10000000A0746000000000000654B + 180085631F70F5EAE0D299BBC7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E33F99 + 46F3269323F9359C26F63DE22CFF0E8C00CC0E8C00CC0E8D0099674E1B008967 + 23008967236CF5EAE0D276AFCBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F61F95 + 23FD52E741FF52E741FF52E741FF52E741FF52E741FF109500CC8B6925008B69 + 25008B69256AF8F0E9DCEAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BE61B2 + 47E634A61EF23BAC29F866EB55FF129D00CC129D00CC129C00998C6A26008C6A + 26008D6B27358D6B2769F1E3D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 + C0BFF1E2D3D31F9F04E175EE64FF14A400CC13A10000129D00008C6A26008C6A + 26008D6B27008E6C28348E6C2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3 + D5D28E6C286738980CAE15A900CC15A9009914A80000129D00008C6A26008C6A + 26008D6B27008E6C2800906E2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E + 2A65906E2A33528B140015AA000015A9000014A80000129D000094722E009472 + 2E0094722E0093712D00916F2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F + 2B63916F2B32747F2200359C0C0015A9000014A80000129D000094722E009472 + 2E0094722E0093712D3193712D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3 + D5D293712D6293712D3194722E0094722E0094722E0094722E0094722E009472 + 2E0094722E3094722E60F1E3D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3 + BBCEF1E2D3D394722E6094722E3094722E0094722E0094722E0095732F009573 + 2F0095732F5FF8F0E9DCCCCBC3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391 + AFF9C7C6BDCEF7EEE5DC95732F5F95732F0095732F0095732F00967430009674 + 30009674305DF5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 + C0BFE9D3BDC0F3E7DBD29674305D967430009674300096743000977531009775 + 31009775315CF5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 + C0BFE9D3BDC0F3E7DBD29775315C977531009775310097753100987632009876 + 32009876325BF5EAE0D2EAD4BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5 + C0BFE9D3BDC0F3E7DBD29876325B9876320098763200987632001975BA001975 + BA001770B7900B56A4C6014296CC003F94CC002A80CC00166BCC021C70CB072D + 7DC80D4390C51259A3C1176CB290186FB500186FB500186FB500 + } + ModalResult = 4 + OnClick = btQueueClick + TabOrder = 2 + end + object btCancel: TBitBtn + Left = 300 + Height = 26 + Top = 0 + Width = 82 + Align = alRight + AutoSize = True + Caption = '&Cancel' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ModalResult = 2 + OnClick = btCancelClick + TabOrder = 1 + end + end +end diff --git a/mangadownloader/forms/mainunit.lrs b/mangadownloader/forms/mainunit.lrs index 9f0280a35..caf37ef20 100644 --- a/mangadownloader/forms/mainunit.lrs +++ b/mangadownloader/forms/mainunit.lrs @@ -1,332 +1,332 @@ -{ This is an automatically generated lazarus resource file } - -LazarusResources.Add('TMainForm','FORMDATA',[ - 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3#172#0#6'Height'#3#210#1#3'Top'#2'6' - +#5'Width'#3#238#2#5'Align'#7#8'alBottom'#7'Caption'#6#21'Free Manga Download' - +'er'#12'ClientHeight'#3#210#1#11'ClientWidth'#3#238#2#8'OnCreate'#7#10'FormC' - +'reate'#9'OnDestroy'#7#11'FormDestroy'#10'LCLVersion'#6#3'1.1'#0#6'TPanel'#10 - +'pnMainLeft'#23'AnchorSideRight.Control'#7#14'spMainSplitter'#4'Left'#2#0#6 - +'Height'#3#210#1#3'Top'#2#0#5'Width'#3#195#0#5'Align'#7#6'alLeft'#7'Anchors' - +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#12'ClientHeight'#3#210#1#11 - +'ClientWidth'#3#195#0#8'TabOrder'#2#0#0#9'TComboBox'#13'cbSelectManga'#4'Lef' - +'t'#2#8#6'Height'#2#21#3'Top'#2#8#5'Width'#3#144#0#7'Anchors'#11#5'akTop'#6 - +'akLeft'#7'akRight'#0#10'ItemHeight'#2#13#13'Items.Strings'#1#6#0#0#8'TabOrd' - +'er'#2#0#0#0#5'TEdit'#8'edSearch'#4'Left'#2#8#6'Height'#2#21#3'Top'#2'$'#5'W' - +'idth'#3#144#0#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#10'OnKeyPress'#7 - +#16'edSearchKeyPress'#8'TabOrder'#2#1#4'Text'#6#9'Search...'#0#0#18'TVirtual' - +'StringTree'#11'vtMangaList'#4'Left'#2#8#6'Height'#3'q'#1#3'Top'#2'X'#5'Widt' - +'h'#3#176#0#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#11'Def' - +'aultText'#6#4'Node'#20'Header.AutoSizeIndex'#2#0#14'Header.Columns'#14#0#20 - +'Header.DefaultHeight'#2#17#17'Header.MainColumn'#2#255#14'ParentShowHint'#8 - +#8'ShowHint'#9#8'TabOrder'#2#2#24'TreeOptions.PaintOptions'#11#13'toShowButt' - +'ons'#14'toShowDropmark'#10'toShowRoot'#12'toThemeAware'#18'toUseBlendedImag' - +'es'#0#28'TreeOptions.SelectionOptions'#11#15'toFullRowSelect'#0#10'OnDblCli' - +'ck'#7#19'vtMangaListDblClick'#10'OnFreeNode'#7#19'vtMangaListFreeNode'#9'On' - +'GetText'#7#18'vtMangaListGetText'#9'OnGetHint'#7#18'vtMangaListGetHint'#10 - +'OnInitNode'#7#19'vtMangaListInitNode'#0#0#7'TBitBtn'#8'btSearch'#19'AnchorS' - +'ideLeft.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3 - +#160#0#6'Height'#2#21#4'Hint'#6#22'Search manga from list'#3'Top'#2'$'#5'Wid' - +'th'#2#24#7'Anchors'#11#5'akTop'#7'akRight'#0#7'OnClick'#7#13'btSearchClick' - +#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#3#0#0#6'TLabel'#6'lbMode'#4 - +'Left'#2#8#6'Height'#2#13#3'Top'#2'@'#5'Width'#2'}'#7'Caption'#6#20'Mode: Sh' - +'ow all manga'#10'Font.Style'#11#6'fsBold'#0#11'ParentColor'#8#10'ParentFont' - +#8#0#0#7'TBitBtn'#14'btRemoveFilter'#19'AnchorSideLeft.Side'#7#9'asrBottom' - +#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3#160#0#6'Height'#2#21#4'Hint' - +#6#13'Remove filter'#3'Top'#2'@'#5'Width'#2#24#7'Anchors'#11#5'akTop'#7'akRi' - +'ght'#0#7'OnClick'#7#19'btRemoveFilterClick'#14'ParentShowHint'#8#8'ShowHint' - +#9#8'TabOrder'#2#4#0#0#0#12'TPageControl'#6'pcMain'#4'Left'#3#195#0#6'Height' - +#3#210#1#3'Top'#2#0#5'Width'#3'+'#2#10'ActivePage'#7#11'tsFavorites'#5'Align' - +#7#8'alClient'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabIndex'#2#3 - +#8'TabOrder'#2#1#8'OnChange'#7#12'pcMainChange'#0#9'TTabSheet'#10'tsDownload' - +#7'Caption'#6#8'Download'#12'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0 - +#18'TVirtualStringTree'#10'vtDownload'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2 - +#0#5'Width'#3'#'#2#5'Align'#7#8'alClient'#11'DefaultText'#6#4'Node'#20'Heade' - +'r.AutoSizeIndex'#2#0#14'Header.Columns'#14#1#8'Position'#2#0#4'Text'#6#5'Ma' - +'nga'#5'Width'#2'd'#0#1#8'Position'#2#1#4'Text'#6#6'Status'#5'Width'#3#200#0 - +#0#1#8'Position'#2#2#4'Text'#6#8'Progress'#5'Width'#2'7'#0#1#8'Position'#2#3 - +#4'Text'#6#7'Website'#5'Width'#2'A'#0#1#8'Position'#2#4#4'Text'#6#7'Save to' - +#5'Width'#3#150#0#0#1#8'Position'#2#5#4'Text'#6#5'Added'#5'Width'#2'P'#0#0#20 - +'Header.DefaultHeight'#2#17#13'Header.Height'#2#25#14'Header.Options'#11#14 - +'hoColumnResize'#6'hoDrag'#16'hoShowSortGlyphs'#9'hoVisible'#0#12'Header.Sty' - +'le'#7#9'hsXPStyle'#10'ParentFont'#8#9'PopupMenu'#7#10'pmDownload'#8'TabOrde' - +'r'#2#0#24'TreeOptions.PaintOptions'#11#13'toShowButtons'#14'toShowDropmark' - +#10'toShowRoot'#12'toThemeAware'#18'toUseBlendedImages'#0#28'TreeOptions.Sel' - +'ectionOptions'#11#15'toFullRowSelect'#0#10'OnFreeNode'#7#18'vtDownloadFreeN' - +'ode'#9'OnGetText'#7#17'vtDownloadGetText'#10'OnInitNode'#7#18'vtDownloadIni' - +'tNode'#0#0#0#9'TTabSheet'#13'tsInformation'#7'Caption'#6#11'Manga Infos'#12 - +'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0#10'TScrollBox'#13'sbInformat' - +'ion'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2#0#5'Width'#3'#'#2#18'HorzScroll' - +'Bar.Page'#3#31#2#18'VertScrollBar.Page'#3#180#1#5'Align'#7#8'alClient'#12'C' - +'lientHeight'#3#180#1#11'ClientWidth'#3#31#2#8'TabOrder'#2#0#0#6'TPanel'#12 - +'pnInfomation'#4'Left'#2#0#6'Height'#3#234#0#3'Top'#2#0#5'Width'#3#31#2#5'Al' - +'ign'#7#5'alTop'#12'ClientHeight'#3#234#0#11'ClientWidth'#3#31#2#10'ParentFo' - +'nt'#8#8'TabOrder'#2#0#0#6'TImage'#7'imCover'#18'AnchorSideTop.Side'#7#9'asr' - +'Center'#21'AnchorSideBottom.Side'#7#9'asrCenter'#4'Left'#2#8#6'Height'#3#216 - +#0#3'Top'#2#8#5'Width'#3#154#0#7'Stretch'#9#0#0#9'TRichMemo'#13'rmInformatio' - +'n'#4'Left'#3#175#0#6'Height'#3#216#0#3'Top'#2#8#5'Width'#3'k'#1#7'Anchors' - +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#13'HideSelection'#8#10'Paren' - ,'tFont'#8#8'ReadOnly'#9#10'ScrollBars'#7#10'ssVertical'#8'TabOrder'#2#0#0#0#0 - +#9'TSplitter'#7'spInfos'#6'Cursor'#7#8'crVSplit'#4'Left'#2#0#6'Height'#2#5#3 - +'Top'#3#234#0#5'Width'#3#31#2#5'Align'#7#5'alTop'#12'ResizeAnchor'#7#5'akTop' - +#0#0#6'TPanel'#13'pnChapterList'#4'Left'#2#0#6'Height'#3#197#0#3'Top'#3#239#0 - +#5'Width'#3#31#2#5'Align'#7#8'alClient'#12'ClientHeight'#3#197#0#11'ClientWi' - +'dth'#3#31#2#8'TabOrder'#2#2#0#13'TCheckListBox'#14'clbChapterList'#18'Ancho' - +'rSideTop.Side'#7#9'asrBottom'#4'Left'#2#8#6'Height'#2'h'#3'Top'#2#9#5'Width' - +#3#15#2#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#10'ItemHei' - +'ght'#2#0#11'MultiSelect'#9#10'OnKeyPress'#7#22'clbChapterListKeyPress'#10'P' - +'arentFont'#8#9'PopupMenu'#7#13'pmChapterList'#8'TabOrder'#2#0#0#0#12'TLabel' - +'edEdit'#8'edSaveTo'#4'Left'#2#8#6'Height'#2#21#3'Top'#3#137#0#5'Width'#3#31 - +#1#7'Anchors'#11#6'akLeft'#8'akBottom'#0' EditLabel.AnchorSideLeft.Control'#7 - +#8'edSaveTo!EditLabel.AnchorSideRight.Control'#7#8'edSaveTo'#30'EditLabel.An' - +'chorSideRight.Side'#7#9'asrBottom"EditLabel.AnchorSideBottom.Control'#7#8'e' - +'dSaveTo'#14'EditLabel.Left'#2#8#16'EditLabel.Height'#2#13#13'EditLabel.Top' - +#2'y'#15'EditLabel.Width'#3#31#1#17'EditLabel.Caption'#6#7'Save to'#21'EditL' - +'abel.ParentColor'#8#20'EditLabel.ParentFont'#8#10'ParentFont'#8#8'TabOrder' - +#2#1#0#0#7'TBitBtn'#10'btDownload'#4'Left'#3#159#1#6'Height'#2#30#3'Top'#3 - +#128#0#5'Width'#2'['#7'Anchors'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#8'Do' - +'wnload'#7'OnClick'#7#15'btDownloadClick'#8'TabOrder'#2#2#0#0#7'TBitBtn'#8'b' - +'tBrowse'#4'Left'#3'7'#1#6'Height'#2#30#3'Top'#3#128#0#5'Width'#2'['#7'Ancho' - +'rs'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#6'Browse'#7'OnClick'#7#13'btBro' - +'wseClick'#8'TabOrder'#2#3#0#0#9'TCheckBox'#14'cbAddAsStopped'#4'Left'#2#8#6 - +'Height'#2#17#3'Top'#3#168#0#5'Width'#3#196#0#7'Caption'#6'$Add to download ' - +'list as stopped task'#8'OnChange'#7#20'cbAddAsStoppedChange'#10'ParentFont' - +#8#8'TabOrder'#2#4#0#0#9'TCheckBox'#16'cbAddToFavorites'#4'Left'#3'7'#1#6'He' - +'ight'#2#17#3'Top'#3#168#0#5'Width'#2'd'#7'Caption'#6#16'Add to Favorites'#10 - +'ParentFont'#8#8'TabOrder'#2#5#0#0#0#0#0#9'TTabSheet'#8'tsFilter'#7'Caption' - +#6#6'Filter'#12'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0#10'TScrollBox' - +#8'sbFilter'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2#0#5'Width'#3'#'#2#18'Hor' - +'zScrollBar.Page'#3#31#2#18'VertScrollBar.Page'#3#180#1#5'Align'#7#8'alClien' - +'t'#12'ClientHeight'#3#180#1#11'ClientWidth'#3#31#2#8'TabOrder'#2#0#0#6'TPan' - +'el'#8'pnGenres'#4'Left'#2#0#6'Height'#3#216#0#3'Top'#2#0#5'Width'#3#31#2#5 - +'Align'#7#5'alTop'#12'ClientHeight'#3#216#0#11'ClientWidth'#3#31#2#8'TabOrde' - +'r'#2#0#0#9'TCheckBox'#9'CheckBox1'#4'Left'#2#23#6'Height'#2#17#3'Top'#2#16#5 - +'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'Tab' - +'Order'#2#0#0#0#9'TCheckBox'#9'CheckBox2'#4'Left'#2#23#6'Height'#2#17#3'Top' - +#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8 - +#8'TabOrder'#2#1#0#0#9'TCheckBox'#9'CheckBox3'#4'Left'#2#23#6'Height'#2#17#3 - +'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentF' - +'ont'#8#8'TabOrder'#2#2#0#0#9'TCheckBox'#9'CheckBox4'#4'Left'#2#23#6'Height' - +#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10 - +'ParentFont'#8#8'TabOrder'#2#3#0#0#9'TCheckBox'#9'CheckBox5'#4'Left'#2#23#6 - +'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Act' - +'ion'#10'ParentFont'#8#8'TabOrder'#2#4#0#0#9'TCheckBox'#9'CheckBox6'#4'Left' - +#2#23#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Captio' - +'n'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#5#0#0#9'TCheckBox'#9'CheckBox' - +'7'#4'Left'#2#23#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed' - +#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#6#0#0#9'TCheckBox'#9 - +'CheckBox8'#4'Left'#2#23#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'Allo' - +'wGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#7#0#0#9'TC' - +'heckBox'#9'CheckBox9'#4'Left'#2#127#6'Height'#2#17#3'Top'#2#16#5'Width'#2'2' - +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#8#0 - +#0#9'TCheckBox'#10'CheckBox10'#4'Left'#2#127#6'Height'#2#17#3'Top'#2'('#5'Wi' - +'dth'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOr' - +'der'#2#9#0#0#9'TCheckBox'#10'CheckBox11'#4'Left'#2#127#6'Height'#2#17#3'Top' - +#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8 - +#8'TabOrder'#2#10#0#0#9'TCheckBox'#10'CheckBox12'#4'Left'#2#127#6'Height'#2 - +#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Pa' - +'rentFont'#8#8'TabOrder'#2#11#0#0#9'TCheckBox'#10'CheckBox13'#4'Left'#2#127#6 - +'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Act' - +'ion'#10'ParentFont'#8#8'TabOrder'#2#12#0#0#9'TCheckBox'#10'CheckBox14'#4'Le' - +'ft'#2#127#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'C' - +'aption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#13#0#0#9'TCheckBox'#10'C' - ,'heckBox15'#4'Left'#2#127#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'All' - +'owGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#14#0#0#9 - +'TCheckBox'#10'CheckBox16'#4'Left'#2#127#6'Height'#2#17#3'Top'#3#184#0#5'Wid' - +'th'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrd' - +'er'#2#15#0#0#9'TCheckBox'#10'CheckBox17'#4'Left'#3#223#0#6'Height'#2#17#3'T' - +'op'#2#16#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFo' - +'nt'#8#8'TabOrder'#2#16#0#0#9'TCheckBox'#10'CheckBox18'#4'Left'#3#223#0#6'He' - +'ight'#2#17#3'Top'#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Actio' - +'n'#10'ParentFont'#8#8'TabOrder'#2#17#0#0#9'TCheckBox'#10'CheckBox19'#4'Left' - +#3#223#0#6'Height'#2#17#3'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Captio' - +'n'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#18#0#0#9'TCheckBox'#10'CheckB' - +'ox20'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGray' - +'ed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#19#0#0#9'TCheck' - +'Box'#10'CheckBox21'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#2'p'#5'Width'#2'2' - +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#20#0 - +#0#9'TCheckBox'#10'CheckBox22'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#3#136#0 - +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' - +'abOrder'#2#21#0#0#9'TCheckBox'#10'CheckBox23'#4'Left'#3#223#0#6'Height'#2#17 - +#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Pa' - +'rentFont'#8#8'TabOrder'#2#22#0#0#9'TCheckBox'#10'CheckBox24'#4'Left'#3#223#0 - +#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6 - +'Action'#10'ParentFont'#8#8'TabOrder'#2#23#0#0#9'TCheckBox'#10'CheckBox25'#4 - +'Left'#3'?'#1#6'Height'#2#17#3'Top'#2#16#5'Width'#2'2'#11'AllowGrayed'#9#7'C' - +'aption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#24#0#0#9'TCheckBox'#10'C' - +'heckBox26'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'('#5'Width'#2'2'#11'Allow' - +'Grayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#25#0#0#9'TC' - +'heckBox'#10'CheckBox27'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'@'#5'Width'#2 - +'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2 - +#26#0#0#9'TCheckBox'#10'CheckBox28'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'X' - +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' - +'abOrder'#2#27#0#0#9'TCheckBox'#10'CheckBox29'#4'Left'#3'?'#1#6'Height'#2#17 - +#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Paren' - +'tFont'#8#8'TabOrder'#2#28#0#0#9'TCheckBox'#10'CheckBox30'#4'Left'#3'?'#1#6 - +'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6 - +'Action'#10'ParentFont'#8#8'TabOrder'#2#29#0#0#9'TCheckBox'#10'CheckBox31'#4 - +'Left'#3'?'#1#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed'#9#7 - +'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#30#0#0#9'TCheckBox'#10 - +'CheckBox32'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'A' - +'llowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#31#0#0#9 - +'TCheckBox'#10'CheckBox33'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#2#16#5'Widt' - +'h'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrde' - +'r'#2' '#0#0#9'TCheckBox'#10'CheckBox34'#4'Left'#3#167#1#6'Height'#2#17#3'To' - +'p'#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFon' - +'t'#8#8'TabOrder'#2'!'#0#0#9'TCheckBox'#10'CheckBox35'#4'Left'#3#167#1#6'Hei' - +'ght'#2#17#3'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action' - +#10'ParentFont'#8#8'TabOrder'#2'"'#0#0#9'TCheckBox'#10'CheckBox36'#4'Left'#3 - +#167#1#6'Height'#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption' - +#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'#'#0#0#9'TCheckBox'#10'CheckBox3' - +'7'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed' - +#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'$'#0#0#9'TCheckBox' - +#10'CheckBox38'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2' - +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'%'#0 - +#0#9'TCheckBox'#10'CheckBox39'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#3#160#0 - +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' - +'abOrder'#2'&'#0#0#0#6'TPanel'#8'pnFilter'#4'Left'#2#0#6'Height'#3#192#0#3'T' - +'op'#3#216#0#5'Width'#3#31#2#5'Align'#7#5'alTop'#12'ClientHeight'#3#192#0#11 - +'ClientWidth'#3#31#2#10'ParentFont'#8#8'TabOrder'#2#1#0#12'TRadioButton'#5'r' - +'bOne'#4'Left'#3'C'#1#6'Height'#2#17#3'Top'#2' '#5'Width'#3#157#0#7'Caption' - +#6#26'Have one of genres checked'#10'ParentFont'#8#8'TabOrder'#2#1#0#0#12'TR' - +'adioButton'#5'rbAll'#4'Left'#3'C'#1#6'Height'#2#17#3'Top'#2#8#5'Width'#3#131 - +#0#7'Caption'#6#22'Have all genre checked'#7'Checked'#9#10'ParentFont'#8#8'T' - +'abOrder'#2#0#7'TabStop'#9#0#0#9'TCheckBox'#9'cbOnlyNew'#4'Left'#3'C'#1#6'He' - +'ight'#2#17#3'Top'#2'8'#5'Width'#3#134#0#7'Caption'#6#21'Search only new man' - +'ga'#10'ParentFont'#8#8'TabOrder'#2#2#0#0#5'TEdit'#13'edFilterTitle'#4'Left' - ,#2'~'#6'Height'#2#21#3'Top'#2#8#5'Width'#3#146#0#8'TabOrder'#2#3#0#0#5'TEdit' - +#15'edFilterArtists'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2'8'#5'Width'#3#146#0 - +#8'TabOrder'#2#4#0#0#5'TEdit'#15'edFilterAuthors'#4'Left'#2'~'#6'Height'#2#21 - +#3'Top'#2' '#5'Width'#3#146#0#8'TabOrder'#2#5#0#0#6'TLabel'#13'lbFilterTitle' - +#4'Left'#2''''#6'Height'#2#16#3'Top'#2#8#5'Width'#2#27#9'Alignment'#7#14'taR' - +'ightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#5'Title'#11'Font.' - +'Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentC' - +'olor'#8#10'ParentFont'#8#0#0#6'TLabel'#15'lbFilterAuthors'#4'Left'#2''''#6 - +'Height'#2#16#3'Top'#2' '#5'Width'#2'5'#9'Alignment'#7#14'taRightJustify'#8 - +'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#7'Authors'#11'Font.Height'#2#243 - +#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentColor'#8#10'Par' - +'entFont'#8#0#0#6'TLabel'#15'lbFilterArtists'#4'Left'#2''''#6'Height'#2#16#3 - +'Top'#2'8'#5'Width'#2'-'#9'Alignment'#7#14'taRightJustify'#8'BidiMode'#7#13 - +'bdRightToLeft'#7'Caption'#6#7'Artists'#11'Font.Height'#2#243#10'Font.Style' - +#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#9 - +'TComboBox'#14'cbFilterStatus'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2'P'#5'Wid' - +'th'#3#146#0#10'ItemHeight'#2#13#9'ItemIndex'#2#2#13'Items.Strings'#1#6#9'Co' - +'mpleted'#6#7'Ongoing'#6#6''#0#8'TabOrder'#2#6#4'Text'#6#6''#0#0 - +#6'TLabel'#14'lbFilterStatus'#4'Left'#2''''#6'Height'#2#16#3'Top'#2'P'#5'Wid' - +'th'#2'+'#9'Alignment'#7#14'taRightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7 - +'Caption'#6#6'Status'#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14 - +'ParentBidiMode'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#6'TLabel'#15'lbFil' - +'terSummary'#4'Left'#2''''#6'Height'#2#16#3'Top'#2'h'#5'Width'#2'<'#9'Alignm' - +'ent'#7#14'taRightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#7'Su' - +'mmary'#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMod' - +'e'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#5'TEdit'#15'edFilterSummary'#4 - +'Left'#2'~'#6'Height'#2#21#3'Top'#2'h'#5'Width'#3'a'#1#8'TabOrder'#2#7#0#0#7 - +'TButton'#8'btFilter'#4'Left'#2''''#6'Height'#2'%'#3'Top'#3#139#0#5'Width'#3 - +#130#0#7'Caption'#6#6'Filter'#10'Font.Color'#7#11'clHighlight'#11'Font.Heigh' - +'t'#2#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#13'btFilterClick'#10'Pa' - +'rentFont'#8#8'TabOrder'#2#8#0#0#7'TButton'#13'btFilterReset'#4'Left'#3'_'#1 - +#6'Height'#2'%'#3'Top'#3#139#0#5'Width'#3#128#0#7'Caption'#6#11'Reset value' - +#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#18'btFilte' - +'rResetClick'#10'ParentFont'#8#8'TabOrder'#2#9#0#0#7'TBitBtn'#19'btRemoveFil' - +'terLarge'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9 - +'asrBottom'#4'Left'#3#191#0#6'Height'#2'%'#4'Hint'#6#13'Remove filter'#3'Top' - +#3#139#0#5'Width'#3#136#0#7'Caption'#6#13'Remove filter'#11'Font.Height'#2 - +#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#19'btRemoveFilterClick'#10'P' - +'arentFont'#8#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#10#0#0#0#0#0#9 - +'TTabSheet'#11'tsFavorites'#7'Caption'#6#9'Favorites'#12'ClientHeight'#3#184 - +#1#11'ClientWidth'#3'#'#2#0#18'TVirtualStringTree'#11'vtFavorites'#4'Left'#2 - +#0#6'Height'#3't'#1#3'Top'#2#0#5'Width'#3'#'#2#5'Align'#7#5'alTop'#7'Anchors' - +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#11'DefaultText'#6#4'Node'#20 - +'Header.AutoSizeIndex'#2#0#14'Header.Columns'#14#1#8'Position'#2#0#4'Text'#6 - +#5'Title'#5'Width'#3#150#0#0#1#8'Position'#2#1#4'Text'#6#15'Current chapter' - +#5'Width'#2'd'#0#1#8'Position'#2#2#4'Text'#6#7'Website'#5'Width'#2'A'#0#1#8 - +'Position'#2#3#4'Text'#6#7'Save to'#5'Width'#3#200#0#0#0#20'Header.DefaultHe' - +'ight'#2#24#13'Header.Height'#2#24#14'Header.Options'#11#14'hoColumnResize'#6 - +'hoDrag'#16'hoShowSortGlyphs'#9'hoVisible'#0#12'Header.Style'#7#9'hsXPStyle' - +#8'TabOrder'#2#0#0#0#0#9'TTabSheet'#8'tsOption'#7'Caption'#6#7'Options'#12'C' - +'lientHeight'#3#160#1#11'ClientWidth'#3'!'#2#0#12'TPageControl'#9'pnOptions' - +#4'Left'#2#9#6'Height'#3'C'#1#3'Top'#2#26#5'Width'#3#14#2#10'ActivePage'#7#19 - +'tsOptionConnections'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom' - +#0#8'TabIndex'#2#0#8'TabOrder'#2#0#0#9'TTabSheet'#19'tsOptionConnections'#7 - +'Caption'#6#11'Connections'#12'ClientHeight'#3')'#1#11'ClientWidth'#3#6#2#0 - +#10'TScrollBox'#21'sbDownloadConnections'#4'Left'#2#0#6'Height'#3')'#1#3'Top' - +#2#0#5'Width'#3#6#2#18'HorzScrollBar.Page'#3#2#2#18'VertScrollBar.Page'#3'%' - +#1#5'Align'#7#8'alClient'#12'ClientHeight'#3'%'#1#11'ClientWidth'#3#2#2#8'Ta' - +'bOrder'#2#0#0#9'TCheckBox'#16'cbOptionUseProxy'#4'Left'#2' '#6'Height'#2#17 - +#3'Top'#3#154#0#5'Width'#2'E'#7'Caption'#6#9'Use proxy'#8'OnChange'#7#22'cbO' - +'ptionUseProxyChange'#10'ParentFont'#8#8'TabOrder'#2#0#0#0#9'TGroupBox'#13'g' - +'bOptionProxy'#4'Left'#2#12#6'Height'#2'h'#3'Top'#3#178#0#5'Width'#3#240#1#7 - +'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#12'Proxy config'#12 - +'ClientHeight'#2'T'#11'ClientWidth'#3#236#1#7'Enabled'#8#8'TabOrder'#2#1#0#6 - ,'TLabel'#12'lbOptionHost'#4'Left'#2#14#6'Height'#2#13#3'Top'#2#14#5'Width'#2 - +#26#7'Caption'#6#4'Host'#10'Font.Style'#11#6'fsBold'#0#11'ParentColor'#8#10 - +'ParentFont'#8#0#0#6'TLabel'#12'lbOptionPort'#4'Left'#2#14#6'Height'#2#13#3 - +'Top'#2'.'#5'Width'#2#24#7'Caption'#6#4'Port'#11'ParentColor'#8#0#0#5'TEdit' - +#12'edOptionHost'#4'Left'#2'7'#6'Height'#2#23#3'Top'#2#7#5'Width'#3#154#0#12 - +'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name'#6#7'Def' - +'ault'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#0#0#0#5 - +'TEdit'#12'edOptionPort'#4'Left'#2'7'#6'Height'#2#23#3'Top'#2''''#5'Width'#3 - +#154#0#12'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name' - +#6#7'Default'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#1 - +#0#0#6'TLabel'#12'lbOptionUser'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'An' - +'chorSideTop.Side'#7#9'asrBottom'#4'Left'#3#230#0#6'Height'#2#13#3'Top'#2#14 - +#5'Width'#2':'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Caption'#6#8'Username' - +#11'ParentColor'#8#0#0#6'TLabel'#12'lbOptionPass'#19'AnchorSideLeft.Side'#7#9 - +'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3#234#0#6'Height'#2 - +#13#3'Top'#2'.'#5'Width'#2'6'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Caption' - +#6#8'Password'#11'ParentColor'#8#0#0#5'TEdit'#12'edOptionUser'#19'AnchorSide' - +'Left.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3',' - +#1#6'Height'#2#23#3'Top'#2#7#5'Width'#3#154#0#7'Anchors'#11#5'akTop'#7'akRig' - +'ht'#0#12'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name' - +#6#7'Default'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#2 - +#0#0#5'TEdit'#12'edOptionPass'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'Anc' - +'horSideTop.Side'#7#9'asrBottom'#4'Left'#3','#1#6'Height'#2#23#3'Top'#2''''#5 - +'Width'#3#154#0#7'Anchors'#11#5'akTop'#7'akRight'#0#12'Font.CharSet'#7#12'AN' - +'SI_CHARSET'#11'Font.Height'#2#244#9'Font.Name'#6#7'Default'#10'ParentFont'#8 - +#8'TabOrder'#2#3#0#0#0#9'TSpinEdit'#19'seOptionMaxParallel'#4'Left'#2#12#6'H' - +'eight'#2#21#3'Top'#2#26#5'Width'#2'0'#8'MaxValue'#2#8#8'MinValue'#2#1#10'Pa' - +'rentFont'#8#14'ParentShowHint'#8#8'TabOrder'#2#2#5'Value'#2#1#0#0#6'TLabel' - +#19'lbOptionMaxParallel'#4'Left'#2'L'#6'Height'#2#13#3'Top'#2#26#5'Width'#3 - +#10#1#7'Caption'#6'4Number of downloaded tasks at the same time (Max: 8)'#11 - +'ParentColor'#8#10'ParentFont'#8#0#0#6'TLabel'#17'lbOptionMaxThread'#4'Left' - +#2'L'#6'Height'#2#13#3'Top'#2':'#5'Width'#3'.'#1#7'Caption'#6'=Number of dow' - +'nloaded files per task at the same time (Max: 8)'#11'ParentColor'#8#10'Pare' - +'ntFont'#8#0#0#9'TSpinEdit'#17'seOptionMaxThread'#4'Left'#2#12#6'Height'#2#21 - +#3'Top'#2':'#5'Width'#2'0'#8'MaxValue'#2#8#8'MinValue'#2#1#10'ParentFont'#8 - +#14'ParentShowHint'#8#8'TabOrder'#2#3#5'Value'#2#1#0#0#9'TSpinEdit'#16'seOpt' - +'ionMaxRetry'#4'Left'#2#12#6'Height'#2#21#3'Top'#2'Z'#5'Width'#2'0'#8'MaxVal' - +'ue'#2#0#10'ParentFont'#8#14'ParentShowHint'#8#8'TabOrder'#2#4#0#0#6'TLabel' - +#16'lbOptionMaxRetry'#4'Left'#2'L'#6'Height'#2#13#3'Top'#2'Z'#5'Width'#3'c'#1 - +#7'Caption'#6'HNumber of retry times if tasks have download problems (0 = al' - +'ways retry)'#11'ParentColor'#8#10'ParentFont'#8#0#0#0#0#9'TTabSheet'#8'tsSa' - +'veTo'#7'Caption'#6#7'Save to'#12'ClientHeight'#3')'#1#11'ClientWidth'#3#6#2 - +#0#12'TLabeledEdit'#19'edOptionDefaultPath'#4'Left'#2#28#6'Height'#2#21#3'To' - +'p'#2'*'#5'Width'#3#198#1#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0' Edi' - +'tLabel.AnchorSideLeft.Control'#7#19'edOptionDefaultPath!EditLabel.AnchorSid' - +'eRight.Control'#7#19'edOptionDefaultPath'#30'EditLabel.AnchorSideRight.Side' - +#7#9'asrBottom"EditLabel.AnchorSideBottom.Control'#7#19'edOptionDefaultPath' - +#14'EditLabel.Left'#2#28#16'EditLabel.Height'#2#13#13'EditLabel.Top'#2#26#15 - +'EditLabel.Width'#3#198#1#17'EditLabel.Caption'#6#29'Choose default download' - +' path:'#21'EditLabel.ParentColor'#8#20'EditLabel.ParentFont'#8#10'ParentFon' - +'t'#8#8'TabOrder'#2#0#0#0#0#0#7'TButton'#13'btOptionApply'#4'Left'#2'&'#6'He' - +'ight'#2'!'#3'Top'#3'm'#1#5'Width'#2'c'#7'Anchors'#11#8'akBottom'#0#7'Captio' - +'n'#6#5'Apply'#7'OnClick'#7#18'btOptionApplyClick'#8'TabOrder'#2#1#0#0#0#0#9 - +'TSplitter'#14'spMainSplitter'#23'AnchorSideRight.Control'#7#6'pcMain'#4'Lef' - +'t'#3#195#0#6'Height'#3#210#1#3'Top'#2#8#5'Width'#2#5#5'Align'#7#6'alNone'#7 - +'Anchors'#11#5'akTop'#6'akLeft'#8'akBottom'#0#0#0#22'TSelectDirectoryDialog' - +#9'dlgSaveTo'#4'left'#2'P'#3'top'#3#184#0#0#0#10'TPopupMenu'#10'pmDownload'#4 - +'left'#2'P'#3'top'#3#239#0#0#9'TMenuItem'#14'miDownloadStop'#7'Caption'#6#4 - +'Stop'#7'OnClick'#7#19'miDownloadStopClick'#0#0#9'TMenuItem'#16'miDownloadRe' - +'muse'#7'Caption'#6#6'Resume'#7'OnClick'#7#21'miDownloadResumeClick'#0#0#9'T' - +'MenuItem'#16'miDownloadRemove'#7'Caption'#6#6'Remove'#7'OnClick'#7#21'miDow' - +'nloadRemoveClick'#0#0#9'TMenuItem'#29'miDownloadRemoveFinishedTasks'#7'Capt' - +'ion'#6#21'Remove finished tasks'#7'OnClick'#7'"miDownloadRemoveFinishedTask' - +'sClick'#0#0#0#10'TPopupMenu'#13'pmChapterList'#4'left'#2'P'#3'top'#3'('#1#0 - ,#9'TMenuItem'#26'miChapterListCheckSelected'#7'Caption'#6#14'Check selected' - +#7'OnClick'#7#31'miChapterListCheckSelectedClick'#0#0#9'TMenuItem'#28'miChap' - +'terListUncheckSelected'#7'Caption'#6#16'Uncheck selected'#7'OnClick'#7'!miC' - +'hapterListUncheckSelectedClick'#0#0#9'TMenuItem'#4'miI1'#7'Caption'#6#1'-'#0 - +#0#9'TMenuItem'#21'miChapterListCheckAll'#7'Caption'#6#9'Check all'#7'OnClic' - +'k'#7#26'miChapterListCheckAllClick'#0#0#9'TMenuItem'#23'miChapterListUnchec' - +'kAll'#7'Caption'#6#11'Uncheck all'#7'OnClick'#7#28'miChapterListUncheckAllC' - +'lick'#0#0#0#0 -]); +{ This is an automatically generated lazarus resource file } + +LazarusResources.Add('TMainForm','FORMDATA',[ + 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3#172#0#6'Height'#3#210#1#3'Top'#2'6' + +#5'Width'#3#238#2#5'Align'#7#8'alBottom'#7'Caption'#6#21'Free Manga Download' + +'er'#12'ClientHeight'#3#210#1#11'ClientWidth'#3#238#2#8'OnCreate'#7#10'FormC' + +'reate'#9'OnDestroy'#7#11'FormDestroy'#10'LCLVersion'#6#3'1.1'#0#6'TPanel'#10 + +'pnMainLeft'#23'AnchorSideRight.Control'#7#14'spMainSplitter'#4'Left'#2#0#6 + +'Height'#3#210#1#3'Top'#2#0#5'Width'#3#195#0#5'Align'#7#6'alLeft'#7'Anchors' + +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#12'ClientHeight'#3#210#1#11 + +'ClientWidth'#3#195#0#8'TabOrder'#2#0#0#9'TComboBox'#13'cbSelectManga'#4'Lef' + +'t'#2#8#6'Height'#2#21#3'Top'#2#8#5'Width'#3#144#0#7'Anchors'#11#5'akTop'#6 + +'akLeft'#7'akRight'#0#10'ItemHeight'#2#13#13'Items.Strings'#1#6#0#0#8'TabOrd' + +'er'#2#0#0#0#5'TEdit'#8'edSearch'#4'Left'#2#8#6'Height'#2#21#3'Top'#2'$'#5'W' + +'idth'#3#144#0#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#10'OnKeyPress'#7 + +#16'edSearchKeyPress'#8'TabOrder'#2#1#4'Text'#6#9'Search...'#0#0#18'TVirtual' + +'StringTree'#11'vtMangaList'#4'Left'#2#8#6'Height'#3'q'#1#3'Top'#2'X'#5'Widt' + +'h'#3#176#0#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#11'Def' + +'aultText'#6#4'Node'#20'Header.AutoSizeIndex'#2#0#14'Header.Columns'#14#0#20 + +'Header.DefaultHeight'#2#17#17'Header.MainColumn'#2#255#14'ParentShowHint'#8 + +#8'ShowHint'#9#8'TabOrder'#2#2#24'TreeOptions.PaintOptions'#11#13'toShowButt' + +'ons'#14'toShowDropmark'#10'toShowRoot'#12'toThemeAware'#18'toUseBlendedImag' + +'es'#0#28'TreeOptions.SelectionOptions'#11#15'toFullRowSelect'#0#10'OnDblCli' + +'ck'#7#19'vtMangaListDblClick'#10'OnFreeNode'#7#19'vtMangaListFreeNode'#9'On' + +'GetText'#7#18'vtMangaListGetText'#9'OnGetHint'#7#18'vtMangaListGetHint'#10 + +'OnInitNode'#7#19'vtMangaListInitNode'#0#0#7'TBitBtn'#8'btSearch'#19'AnchorS' + +'ideLeft.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3 + +#160#0#6'Height'#2#21#4'Hint'#6#22'Search manga from list'#3'Top'#2'$'#5'Wid' + +'th'#2#24#7'Anchors'#11#5'akTop'#7'akRight'#0#7'OnClick'#7#13'btSearchClick' + +#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#3#0#0#6'TLabel'#6'lbMode'#4 + +'Left'#2#8#6'Height'#2#13#3'Top'#2'@'#5'Width'#2'}'#7'Caption'#6#20'Mode: Sh' + +'ow all manga'#10'Font.Style'#11#6'fsBold'#0#11'ParentColor'#8#10'ParentFont' + +#8#0#0#7'TBitBtn'#14'btRemoveFilter'#19'AnchorSideLeft.Side'#7#9'asrBottom' + +#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3#160#0#6'Height'#2#21#4'Hint' + +#6#13'Remove filter'#3'Top'#2'@'#5'Width'#2#24#7'Anchors'#11#5'akTop'#7'akRi' + +'ght'#0#7'OnClick'#7#19'btRemoveFilterClick'#14'ParentShowHint'#8#8'ShowHint' + +#9#8'TabOrder'#2#4#0#0#0#12'TPageControl'#6'pcMain'#4'Left'#3#195#0#6'Height' + +#3#210#1#3'Top'#2#0#5'Width'#3'+'#2#10'ActivePage'#7#11'tsFavorites'#5'Align' + +#7#8'alClient'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabIndex'#2#3 + +#8'TabOrder'#2#1#8'OnChange'#7#12'pcMainChange'#0#9'TTabSheet'#10'tsDownload' + +#7'Caption'#6#8'Download'#12'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0 + +#18'TVirtualStringTree'#10'vtDownload'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2 + +#0#5'Width'#3'#'#2#5'Align'#7#8'alClient'#11'DefaultText'#6#4'Node'#20'Heade' + +'r.AutoSizeIndex'#2#0#14'Header.Columns'#14#1#8'Position'#2#0#4'Text'#6#5'Ma' + +'nga'#5'Width'#2'd'#0#1#8'Position'#2#1#4'Text'#6#6'Status'#5'Width'#3#200#0 + +#0#1#8'Position'#2#2#4'Text'#6#8'Progress'#5'Width'#2'7'#0#1#8'Position'#2#3 + +#4'Text'#6#7'Website'#5'Width'#2'A'#0#1#8'Position'#2#4#4'Text'#6#7'Save to' + +#5'Width'#3#150#0#0#1#8'Position'#2#5#4'Text'#6#5'Added'#5'Width'#2'P'#0#0#20 + +'Header.DefaultHeight'#2#17#13'Header.Height'#2#25#14'Header.Options'#11#14 + +'hoColumnResize'#6'hoDrag'#16'hoShowSortGlyphs'#9'hoVisible'#0#12'Header.Sty' + +'le'#7#9'hsXPStyle'#10'ParentFont'#8#9'PopupMenu'#7#10'pmDownload'#8'TabOrde' + +'r'#2#0#24'TreeOptions.PaintOptions'#11#13'toShowButtons'#14'toShowDropmark' + +#10'toShowRoot'#12'toThemeAware'#18'toUseBlendedImages'#0#28'TreeOptions.Sel' + +'ectionOptions'#11#15'toFullRowSelect'#0#10'OnFreeNode'#7#18'vtDownloadFreeN' + +'ode'#9'OnGetText'#7#17'vtDownloadGetText'#10'OnInitNode'#7#18'vtDownloadIni' + +'tNode'#0#0#0#9'TTabSheet'#13'tsInformation'#7'Caption'#6#11'Manga Infos'#12 + +'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0#10'TScrollBox'#13'sbInformat' + +'ion'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2#0#5'Width'#3'#'#2#18'HorzScroll' + +'Bar.Page'#3#31#2#18'VertScrollBar.Page'#3#180#1#5'Align'#7#8'alClient'#12'C' + +'lientHeight'#3#180#1#11'ClientWidth'#3#31#2#8'TabOrder'#2#0#0#6'TPanel'#12 + +'pnInfomation'#4'Left'#2#0#6'Height'#3#234#0#3'Top'#2#0#5'Width'#3#31#2#5'Al' + +'ign'#7#5'alTop'#12'ClientHeight'#3#234#0#11'ClientWidth'#3#31#2#10'ParentFo' + +'nt'#8#8'TabOrder'#2#0#0#6'TImage'#7'imCover'#18'AnchorSideTop.Side'#7#9'asr' + +'Center'#21'AnchorSideBottom.Side'#7#9'asrCenter'#4'Left'#2#8#6'Height'#3#216 + +#0#3'Top'#2#8#5'Width'#3#154#0#7'Stretch'#9#0#0#9'TRichMemo'#13'rmInformatio' + +'n'#4'Left'#3#175#0#6'Height'#3#216#0#3'Top'#2#8#5'Width'#3'k'#1#7'Anchors' + +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#13'HideSelection'#8#10'Paren' + ,'tFont'#8#8'ReadOnly'#9#10'ScrollBars'#7#10'ssVertical'#8'TabOrder'#2#0#0#0#0 + +#9'TSplitter'#7'spInfos'#6'Cursor'#7#8'crVSplit'#4'Left'#2#0#6'Height'#2#5#3 + +'Top'#3#234#0#5'Width'#3#31#2#5'Align'#7#5'alTop'#12'ResizeAnchor'#7#5'akTop' + +#0#0#6'TPanel'#13'pnChapterList'#4'Left'#2#0#6'Height'#3#197#0#3'Top'#3#239#0 + +#5'Width'#3#31#2#5'Align'#7#8'alClient'#12'ClientHeight'#3#197#0#11'ClientWi' + +'dth'#3#31#2#8'TabOrder'#2#2#0#13'TCheckListBox'#14'clbChapterList'#18'Ancho' + +'rSideTop.Side'#7#9'asrBottom'#4'Left'#2#8#6'Height'#2'h'#3'Top'#2#9#5'Width' + +#3#15#2#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#10'ItemHei' + +'ght'#2#0#11'MultiSelect'#9#10'OnKeyPress'#7#22'clbChapterListKeyPress'#10'P' + +'arentFont'#8#9'PopupMenu'#7#13'pmChapterList'#8'TabOrder'#2#0#0#0#12'TLabel' + +'edEdit'#8'edSaveTo'#4'Left'#2#8#6'Height'#2#21#3'Top'#3#137#0#5'Width'#3#31 + +#1#7'Anchors'#11#6'akLeft'#8'akBottom'#0' EditLabel.AnchorSideLeft.Control'#7 + +#8'edSaveTo!EditLabel.AnchorSideRight.Control'#7#8'edSaveTo'#30'EditLabel.An' + +'chorSideRight.Side'#7#9'asrBottom"EditLabel.AnchorSideBottom.Control'#7#8'e' + +'dSaveTo'#14'EditLabel.Left'#2#8#16'EditLabel.Height'#2#13#13'EditLabel.Top' + +#2'y'#15'EditLabel.Width'#3#31#1#17'EditLabel.Caption'#6#7'Save to'#21'EditL' + +'abel.ParentColor'#8#20'EditLabel.ParentFont'#8#10'ParentFont'#8#8'TabOrder' + +#2#1#0#0#7'TBitBtn'#10'btDownload'#4'Left'#3#159#1#6'Height'#2#30#3'Top'#3 + +#128#0#5'Width'#2'['#7'Anchors'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#8'Do' + +'wnload'#7'OnClick'#7#15'btDownloadClick'#8'TabOrder'#2#2#0#0#7'TBitBtn'#8'b' + +'tBrowse'#4'Left'#3'7'#1#6'Height'#2#30#3'Top'#3#128#0#5'Width'#2'['#7'Ancho' + +'rs'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#6'Browse'#7'OnClick'#7#13'btBro' + +'wseClick'#8'TabOrder'#2#3#0#0#9'TCheckBox'#14'cbAddAsStopped'#4'Left'#2#8#6 + +'Height'#2#17#3'Top'#3#168#0#5'Width'#3#196#0#7'Caption'#6'$Add to download ' + +'list as stopped task'#8'OnChange'#7#20'cbAddAsStoppedChange'#10'ParentFont' + +#8#8'TabOrder'#2#4#0#0#9'TCheckBox'#16'cbAddToFavorites'#4'Left'#3'7'#1#6'He' + +'ight'#2#17#3'Top'#3#168#0#5'Width'#2'd'#7'Caption'#6#16'Add to Favorites'#10 + +'ParentFont'#8#8'TabOrder'#2#5#0#0#0#0#0#9'TTabSheet'#8'tsFilter'#7'Caption' + +#6#6'Filter'#12'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0#10'TScrollBox' + +#8'sbFilter'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2#0#5'Width'#3'#'#2#18'Hor' + +'zScrollBar.Page'#3#31#2#18'VertScrollBar.Page'#3#180#1#5'Align'#7#8'alClien' + +'t'#12'ClientHeight'#3#180#1#11'ClientWidth'#3#31#2#8'TabOrder'#2#0#0#6'TPan' + +'el'#8'pnGenres'#4'Left'#2#0#6'Height'#3#216#0#3'Top'#2#0#5'Width'#3#31#2#5 + +'Align'#7#5'alTop'#12'ClientHeight'#3#216#0#11'ClientWidth'#3#31#2#8'TabOrde' + +'r'#2#0#0#9'TCheckBox'#9'CheckBox1'#4'Left'#2#23#6'Height'#2#17#3'Top'#2#16#5 + +'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'Tab' + +'Order'#2#0#0#0#9'TCheckBox'#9'CheckBox2'#4'Left'#2#23#6'Height'#2#17#3'Top' + +#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8 + +#8'TabOrder'#2#1#0#0#9'TCheckBox'#9'CheckBox3'#4'Left'#2#23#6'Height'#2#17#3 + +'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentF' + +'ont'#8#8'TabOrder'#2#2#0#0#9'TCheckBox'#9'CheckBox4'#4'Left'#2#23#6'Height' + +#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10 + +'ParentFont'#8#8'TabOrder'#2#3#0#0#9'TCheckBox'#9'CheckBox5'#4'Left'#2#23#6 + +'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Act' + +'ion'#10'ParentFont'#8#8'TabOrder'#2#4#0#0#9'TCheckBox'#9'CheckBox6'#4'Left' + +#2#23#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Captio' + +'n'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#5#0#0#9'TCheckBox'#9'CheckBox' + +'7'#4'Left'#2#23#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed' + +#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#6#0#0#9'TCheckBox'#9 + +'CheckBox8'#4'Left'#2#23#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'Allo' + +'wGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#7#0#0#9'TC' + +'heckBox'#9'CheckBox9'#4'Left'#2#127#6'Height'#2#17#3'Top'#2#16#5'Width'#2'2' + +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#8#0 + +#0#9'TCheckBox'#10'CheckBox10'#4'Left'#2#127#6'Height'#2#17#3'Top'#2'('#5'Wi' + +'dth'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOr' + +'der'#2#9#0#0#9'TCheckBox'#10'CheckBox11'#4'Left'#2#127#6'Height'#2#17#3'Top' + +#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8 + +#8'TabOrder'#2#10#0#0#9'TCheckBox'#10'CheckBox12'#4'Left'#2#127#6'Height'#2 + +#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Pa' + +'rentFont'#8#8'TabOrder'#2#11#0#0#9'TCheckBox'#10'CheckBox13'#4'Left'#2#127#6 + +'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Act' + +'ion'#10'ParentFont'#8#8'TabOrder'#2#12#0#0#9'TCheckBox'#10'CheckBox14'#4'Le' + +'ft'#2#127#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'C' + +'aption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#13#0#0#9'TCheckBox'#10'C' + ,'heckBox15'#4'Left'#2#127#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'All' + +'owGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#14#0#0#9 + +'TCheckBox'#10'CheckBox16'#4'Left'#2#127#6'Height'#2#17#3'Top'#3#184#0#5'Wid' + +'th'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrd' + +'er'#2#15#0#0#9'TCheckBox'#10'CheckBox17'#4'Left'#3#223#0#6'Height'#2#17#3'T' + +'op'#2#16#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFo' + +'nt'#8#8'TabOrder'#2#16#0#0#9'TCheckBox'#10'CheckBox18'#4'Left'#3#223#0#6'He' + +'ight'#2#17#3'Top'#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Actio' + +'n'#10'ParentFont'#8#8'TabOrder'#2#17#0#0#9'TCheckBox'#10'CheckBox19'#4'Left' + +#3#223#0#6'Height'#2#17#3'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Captio' + +'n'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#18#0#0#9'TCheckBox'#10'CheckB' + +'ox20'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGray' + +'ed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#19#0#0#9'TCheck' + +'Box'#10'CheckBox21'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#2'p'#5'Width'#2'2' + +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#20#0 + +#0#9'TCheckBox'#10'CheckBox22'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#3#136#0 + +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' + +'abOrder'#2#21#0#0#9'TCheckBox'#10'CheckBox23'#4'Left'#3#223#0#6'Height'#2#17 + +#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Pa' + +'rentFont'#8#8'TabOrder'#2#22#0#0#9'TCheckBox'#10'CheckBox24'#4'Left'#3#223#0 + +#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6 + +'Action'#10'ParentFont'#8#8'TabOrder'#2#23#0#0#9'TCheckBox'#10'CheckBox25'#4 + +'Left'#3'?'#1#6'Height'#2#17#3'Top'#2#16#5'Width'#2'2'#11'AllowGrayed'#9#7'C' + +'aption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#24#0#0#9'TCheckBox'#10'C' + +'heckBox26'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'('#5'Width'#2'2'#11'Allow' + +'Grayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#25#0#0#9'TC' + +'heckBox'#10'CheckBox27'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'@'#5'Width'#2 + +'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2 + +#26#0#0#9'TCheckBox'#10'CheckBox28'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'X' + +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' + +'abOrder'#2#27#0#0#9'TCheckBox'#10'CheckBox29'#4'Left'#3'?'#1#6'Height'#2#17 + +#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Paren' + +'tFont'#8#8'TabOrder'#2#28#0#0#9'TCheckBox'#10'CheckBox30'#4'Left'#3'?'#1#6 + +'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6 + +'Action'#10'ParentFont'#8#8'TabOrder'#2#29#0#0#9'TCheckBox'#10'CheckBox31'#4 + +'Left'#3'?'#1#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed'#9#7 + +'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#30#0#0#9'TCheckBox'#10 + +'CheckBox32'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'A' + +'llowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#31#0#0#9 + +'TCheckBox'#10'CheckBox33'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#2#16#5'Widt' + +'h'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrde' + +'r'#2' '#0#0#9'TCheckBox'#10'CheckBox34'#4'Left'#3#167#1#6'Height'#2#17#3'To' + +'p'#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFon' + +'t'#8#8'TabOrder'#2'!'#0#0#9'TCheckBox'#10'CheckBox35'#4'Left'#3#167#1#6'Hei' + +'ght'#2#17#3'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action' + +#10'ParentFont'#8#8'TabOrder'#2'"'#0#0#9'TCheckBox'#10'CheckBox36'#4'Left'#3 + +#167#1#6'Height'#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption' + +#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'#'#0#0#9'TCheckBox'#10'CheckBox3' + +'7'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed' + +#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'$'#0#0#9'TCheckBox' + +#10'CheckBox38'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2' + +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'%'#0 + +#0#9'TCheckBox'#10'CheckBox39'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#3#160#0 + +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' + +'abOrder'#2'&'#0#0#0#6'TPanel'#8'pnFilter'#4'Left'#2#0#6'Height'#3#192#0#3'T' + +'op'#3#216#0#5'Width'#3#31#2#5'Align'#7#5'alTop'#12'ClientHeight'#3#192#0#11 + +'ClientWidth'#3#31#2#10'ParentFont'#8#8'TabOrder'#2#1#0#12'TRadioButton'#5'r' + +'bOne'#4'Left'#3'C'#1#6'Height'#2#17#3'Top'#2' '#5'Width'#3#157#0#7'Caption' + +#6#26'Have one of genres checked'#10'ParentFont'#8#8'TabOrder'#2#1#0#0#12'TR' + +'adioButton'#5'rbAll'#4'Left'#3'C'#1#6'Height'#2#17#3'Top'#2#8#5'Width'#3#131 + +#0#7'Caption'#6#22'Have all genre checked'#7'Checked'#9#10'ParentFont'#8#8'T' + +'abOrder'#2#0#7'TabStop'#9#0#0#9'TCheckBox'#9'cbOnlyNew'#4'Left'#3'C'#1#6'He' + +'ight'#2#17#3'Top'#2'8'#5'Width'#3#134#0#7'Caption'#6#21'Search only new man' + +'ga'#10'ParentFont'#8#8'TabOrder'#2#2#0#0#5'TEdit'#13'edFilterTitle'#4'Left' + ,#2'~'#6'Height'#2#21#3'Top'#2#8#5'Width'#3#146#0#8'TabOrder'#2#3#0#0#5'TEdit' + +#15'edFilterArtists'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2'8'#5'Width'#3#146#0 + +#8'TabOrder'#2#4#0#0#5'TEdit'#15'edFilterAuthors'#4'Left'#2'~'#6'Height'#2#21 + +#3'Top'#2' '#5'Width'#3#146#0#8'TabOrder'#2#5#0#0#6'TLabel'#13'lbFilterTitle' + +#4'Left'#2''''#6'Height'#2#16#3'Top'#2#8#5'Width'#2#27#9'Alignment'#7#14'taR' + +'ightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#5'Title'#11'Font.' + +'Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentC' + +'olor'#8#10'ParentFont'#8#0#0#6'TLabel'#15'lbFilterAuthors'#4'Left'#2''''#6 + +'Height'#2#16#3'Top'#2' '#5'Width'#2'5'#9'Alignment'#7#14'taRightJustify'#8 + +'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#7'Authors'#11'Font.Height'#2#243 + +#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentColor'#8#10'Par' + +'entFont'#8#0#0#6'TLabel'#15'lbFilterArtists'#4'Left'#2''''#6'Height'#2#16#3 + +'Top'#2'8'#5'Width'#2'-'#9'Alignment'#7#14'taRightJustify'#8'BidiMode'#7#13 + +'bdRightToLeft'#7'Caption'#6#7'Artists'#11'Font.Height'#2#243#10'Font.Style' + +#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#9 + +'TComboBox'#14'cbFilterStatus'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2'P'#5'Wid' + +'th'#3#146#0#10'ItemHeight'#2#13#9'ItemIndex'#2#2#13'Items.Strings'#1#6#9'Co' + +'mpleted'#6#7'Ongoing'#6#6''#0#8'TabOrder'#2#6#4'Text'#6#6''#0#0 + +#6'TLabel'#14'lbFilterStatus'#4'Left'#2''''#6'Height'#2#16#3'Top'#2'P'#5'Wid' + +'th'#2'+'#9'Alignment'#7#14'taRightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7 + +'Caption'#6#6'Status'#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14 + +'ParentBidiMode'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#6'TLabel'#15'lbFil' + +'terSummary'#4'Left'#2''''#6'Height'#2#16#3'Top'#2'h'#5'Width'#2'<'#9'Alignm' + +'ent'#7#14'taRightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#7'Su' + +'mmary'#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMod' + +'e'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#5'TEdit'#15'edFilterSummary'#4 + +'Left'#2'~'#6'Height'#2#21#3'Top'#2'h'#5'Width'#3'a'#1#8'TabOrder'#2#7#0#0#7 + +'TButton'#8'btFilter'#4'Left'#2''''#6'Height'#2'%'#3'Top'#3#139#0#5'Width'#3 + +#130#0#7'Caption'#6#6'Filter'#10'Font.Color'#7#11'clHighlight'#11'Font.Heigh' + +'t'#2#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#13'btFilterClick'#10'Pa' + +'rentFont'#8#8'TabOrder'#2#8#0#0#7'TButton'#13'btFilterReset'#4'Left'#3'_'#1 + +#6'Height'#2'%'#3'Top'#3#139#0#5'Width'#3#128#0#7'Caption'#6#11'Reset value' + +#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#18'btFilte' + +'rResetClick'#10'ParentFont'#8#8'TabOrder'#2#9#0#0#7'TBitBtn'#19'btRemoveFil' + +'terLarge'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9 + +'asrBottom'#4'Left'#3#191#0#6'Height'#2'%'#4'Hint'#6#13'Remove filter'#3'Top' + +#3#139#0#5'Width'#3#136#0#7'Caption'#6#13'Remove filter'#11'Font.Height'#2 + +#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#19'btRemoveFilterClick'#10'P' + +'arentFont'#8#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#10#0#0#0#0#0#9 + +'TTabSheet'#11'tsFavorites'#7'Caption'#6#9'Favorites'#12'ClientHeight'#3#184 + +#1#11'ClientWidth'#3'#'#2#0#18'TVirtualStringTree'#11'vtFavorites'#4'Left'#2 + +#0#6'Height'#3't'#1#3'Top'#2#0#5'Width'#3'#'#2#5'Align'#7#5'alTop'#7'Anchors' + +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#11'DefaultText'#6#4'Node'#20 + +'Header.AutoSizeIndex'#2#0#14'Header.Columns'#14#1#8'Position'#2#0#4'Text'#6 + +#5'Title'#5'Width'#3#150#0#0#1#8'Position'#2#1#4'Text'#6#15'Current chapter' + +#5'Width'#2'd'#0#1#8'Position'#2#2#4'Text'#6#7'Website'#5'Width'#2'A'#0#1#8 + +'Position'#2#3#4'Text'#6#7'Save to'#5'Width'#3#200#0#0#0#20'Header.DefaultHe' + +'ight'#2#24#13'Header.Height'#2#24#14'Header.Options'#11#14'hoColumnResize'#6 + +'hoDrag'#16'hoShowSortGlyphs'#9'hoVisible'#0#12'Header.Style'#7#9'hsXPStyle' + +#8'TabOrder'#2#0#0#0#0#9'TTabSheet'#8'tsOption'#7'Caption'#6#7'Options'#12'C' + +'lientHeight'#3#160#1#11'ClientWidth'#3'!'#2#0#12'TPageControl'#9'pnOptions' + +#4'Left'#2#9#6'Height'#3'C'#1#3'Top'#2#26#5'Width'#3#14#2#10'ActivePage'#7#19 + +'tsOptionConnections'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom' + +#0#8'TabIndex'#2#0#8'TabOrder'#2#0#0#9'TTabSheet'#19'tsOptionConnections'#7 + +'Caption'#6#11'Connections'#12'ClientHeight'#3')'#1#11'ClientWidth'#3#6#2#0 + +#10'TScrollBox'#21'sbDownloadConnections'#4'Left'#2#0#6'Height'#3')'#1#3'Top' + +#2#0#5'Width'#3#6#2#18'HorzScrollBar.Page'#3#2#2#18'VertScrollBar.Page'#3'%' + +#1#5'Align'#7#8'alClient'#12'ClientHeight'#3'%'#1#11'ClientWidth'#3#2#2#8'Ta' + +'bOrder'#2#0#0#9'TCheckBox'#16'cbOptionUseProxy'#4'Left'#2' '#6'Height'#2#17 + +#3'Top'#3#154#0#5'Width'#2'E'#7'Caption'#6#9'Use proxy'#8'OnChange'#7#22'cbO' + +'ptionUseProxyChange'#10'ParentFont'#8#8'TabOrder'#2#0#0#0#9'TGroupBox'#13'g' + +'bOptionProxy'#4'Left'#2#12#6'Height'#2'h'#3'Top'#3#178#0#5'Width'#3#240#1#7 + +'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#12'Proxy config'#12 + +'ClientHeight'#2'T'#11'ClientWidth'#3#236#1#7'Enabled'#8#8'TabOrder'#2#1#0#6 + ,'TLabel'#12'lbOptionHost'#4'Left'#2#14#6'Height'#2#13#3'Top'#2#14#5'Width'#2 + +#26#7'Caption'#6#4'Host'#10'Font.Style'#11#6'fsBold'#0#11'ParentColor'#8#10 + +'ParentFont'#8#0#0#6'TLabel'#12'lbOptionPort'#4'Left'#2#14#6'Height'#2#13#3 + +'Top'#2'.'#5'Width'#2#24#7'Caption'#6#4'Port'#11'ParentColor'#8#0#0#5'TEdit' + +#12'edOptionHost'#4'Left'#2'7'#6'Height'#2#23#3'Top'#2#7#5'Width'#3#154#0#12 + +'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name'#6#7'Def' + +'ault'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#0#0#0#5 + +'TEdit'#12'edOptionPort'#4'Left'#2'7'#6'Height'#2#23#3'Top'#2''''#5'Width'#3 + +#154#0#12'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name' + +#6#7'Default'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#1 + +#0#0#6'TLabel'#12'lbOptionUser'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'An' + +'chorSideTop.Side'#7#9'asrBottom'#4'Left'#3#230#0#6'Height'#2#13#3'Top'#2#14 + +#5'Width'#2':'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Caption'#6#8'Username' + +#11'ParentColor'#8#0#0#6'TLabel'#12'lbOptionPass'#19'AnchorSideLeft.Side'#7#9 + +'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3#234#0#6'Height'#2 + +#13#3'Top'#2'.'#5'Width'#2'6'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Caption' + +#6#8'Password'#11'ParentColor'#8#0#0#5'TEdit'#12'edOptionUser'#19'AnchorSide' + +'Left.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3',' + +#1#6'Height'#2#23#3'Top'#2#7#5'Width'#3#154#0#7'Anchors'#11#5'akTop'#7'akRig' + +'ht'#0#12'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name' + +#6#7'Default'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#2 + +#0#0#5'TEdit'#12'edOptionPass'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'Anc' + +'horSideTop.Side'#7#9'asrBottom'#4'Left'#3','#1#6'Height'#2#23#3'Top'#2''''#5 + +'Width'#3#154#0#7'Anchors'#11#5'akTop'#7'akRight'#0#12'Font.CharSet'#7#12'AN' + +'SI_CHARSET'#11'Font.Height'#2#244#9'Font.Name'#6#7'Default'#10'ParentFont'#8 + +#8'TabOrder'#2#3#0#0#0#9'TSpinEdit'#19'seOptionMaxParallel'#4'Left'#2#12#6'H' + +'eight'#2#21#3'Top'#2#26#5'Width'#2'0'#8'MaxValue'#2#8#8'MinValue'#2#1#10'Pa' + +'rentFont'#8#14'ParentShowHint'#8#8'TabOrder'#2#2#5'Value'#2#1#0#0#6'TLabel' + +#19'lbOptionMaxParallel'#4'Left'#2'L'#6'Height'#2#13#3'Top'#2#26#5'Width'#3 + +#10#1#7'Caption'#6'4Number of downloaded tasks at the same time (Max: 8)'#11 + +'ParentColor'#8#10'ParentFont'#8#0#0#6'TLabel'#17'lbOptionMaxThread'#4'Left' + +#2'L'#6'Height'#2#13#3'Top'#2':'#5'Width'#3'.'#1#7'Caption'#6'=Number of dow' + +'nloaded files per task at the same time (Max: 8)'#11'ParentColor'#8#10'Pare' + +'ntFont'#8#0#0#9'TSpinEdit'#17'seOptionMaxThread'#4'Left'#2#12#6'Height'#2#21 + +#3'Top'#2':'#5'Width'#2'0'#8'MaxValue'#2#8#8'MinValue'#2#1#10'ParentFont'#8 + +#14'ParentShowHint'#8#8'TabOrder'#2#3#5'Value'#2#1#0#0#9'TSpinEdit'#16'seOpt' + +'ionMaxRetry'#4'Left'#2#12#6'Height'#2#21#3'Top'#2'Z'#5'Width'#2'0'#8'MaxVal' + +'ue'#2#0#10'ParentFont'#8#14'ParentShowHint'#8#8'TabOrder'#2#4#0#0#6'TLabel' + +#16'lbOptionMaxRetry'#4'Left'#2'L'#6'Height'#2#13#3'Top'#2'Z'#5'Width'#3'c'#1 + +#7'Caption'#6'HNumber of retry times if tasks have download problems (0 = al' + +'ways retry)'#11'ParentColor'#8#10'ParentFont'#8#0#0#0#0#9'TTabSheet'#8'tsSa' + +'veTo'#7'Caption'#6#7'Save to'#12'ClientHeight'#3')'#1#11'ClientWidth'#3#6#2 + +#0#12'TLabeledEdit'#19'edOptionDefaultPath'#4'Left'#2#28#6'Height'#2#21#3'To' + +'p'#2'*'#5'Width'#3#198#1#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0' Edi' + +'tLabel.AnchorSideLeft.Control'#7#19'edOptionDefaultPath!EditLabel.AnchorSid' + +'eRight.Control'#7#19'edOptionDefaultPath'#30'EditLabel.AnchorSideRight.Side' + +#7#9'asrBottom"EditLabel.AnchorSideBottom.Control'#7#19'edOptionDefaultPath' + +#14'EditLabel.Left'#2#28#16'EditLabel.Height'#2#13#13'EditLabel.Top'#2#26#15 + +'EditLabel.Width'#3#198#1#17'EditLabel.Caption'#6#29'Choose default download' + +' path:'#21'EditLabel.ParentColor'#8#20'EditLabel.ParentFont'#8#10'ParentFon' + +'t'#8#8'TabOrder'#2#0#0#0#0#0#7'TButton'#13'btOptionApply'#4'Left'#2'&'#6'He' + +'ight'#2'!'#3'Top'#3'm'#1#5'Width'#2'c'#7'Anchors'#11#8'akBottom'#0#7'Captio' + +'n'#6#5'Apply'#7'OnClick'#7#18'btOptionApplyClick'#8'TabOrder'#2#1#0#0#0#0#9 + +'TSplitter'#14'spMainSplitter'#23'AnchorSideRight.Control'#7#6'pcMain'#4'Lef' + +'t'#3#195#0#6'Height'#3#210#1#3'Top'#2#8#5'Width'#2#5#5'Align'#7#6'alNone'#7 + +'Anchors'#11#5'akTop'#6'akLeft'#8'akBottom'#0#0#0#22'TSelectDirectoryDialog' + +#9'dlgSaveTo'#4'left'#2'P'#3'top'#3#184#0#0#0#10'TPopupMenu'#10'pmDownload'#4 + +'left'#2'P'#3'top'#3#239#0#0#9'TMenuItem'#14'miDownloadStop'#7'Caption'#6#4 + +'Stop'#7'OnClick'#7#19'miDownloadStopClick'#0#0#9'TMenuItem'#16'miDownloadRe' + +'muse'#7'Caption'#6#6'Resume'#7'OnClick'#7#21'miDownloadResumeClick'#0#0#9'T' + +'MenuItem'#16'miDownloadRemove'#7'Caption'#6#6'Remove'#7'OnClick'#7#21'miDow' + +'nloadRemoveClick'#0#0#9'TMenuItem'#29'miDownloadRemoveFinishedTasks'#7'Capt' + +'ion'#6#21'Remove finished tasks'#7'OnClick'#7'"miDownloadRemoveFinishedTask' + +'sClick'#0#0#0#10'TPopupMenu'#13'pmChapterList'#4'left'#2'P'#3'top'#3'('#1#0 + ,#9'TMenuItem'#26'miChapterListCheckSelected'#7'Caption'#6#14'Check selected' + +#7'OnClick'#7#31'miChapterListCheckSelectedClick'#0#0#9'TMenuItem'#28'miChap' + +'terListUncheckSelected'#7'Caption'#6#16'Uncheck selected'#7'OnClick'#7'!miC' + +'hapterListUncheckSelectedClick'#0#0#9'TMenuItem'#4'miI1'#7'Caption'#6#1'-'#0 + +#0#9'TMenuItem'#21'miChapterListCheckAll'#7'Caption'#6#9'Check all'#7'OnClic' + +'k'#7#26'miChapterListCheckAllClick'#0#0#9'TMenuItem'#23'miChapterListUnchec' + +'kAll'#7'Caption'#6#11'Uncheck all'#7'OnClick'#7#28'miChapterListUncheckAllC' + +'lick'#0#0#0#0 +]); From a4b53e3f1d0ae2236ae177dc43d358aa6ff087b0 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 03:49:32 +0800 Subject: [PATCH 0476/2794] downloadmanager, set back readyforexit, backup manually --- baseunits/uDownloadsManager.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 7644d6417..2159358b2 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2276,8 +2276,8 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; begin if Containers.Count > 0 then begin + isReadyForExit := True; try - isReadyForExit := True; for i := 0 to Containers.Count - 1 do if TaskItem(i).ThreadState then TaskItem(i).Thread.Terminate; @@ -2285,7 +2285,7 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; if TaskItem(i).ThreadState then TaskItem(i).Thread.WaitFor; finally - Backup; + isReadyForExit := False; end; end; end; From f47949cdd640555be92b68c16f88fb1523602d83 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:08:07 +0800 Subject: [PATCH 0477/2794] downloadmanager, add function to settaskactive --- baseunits/uDownloadsManager.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2159358b2..dbefcf14b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -200,6 +200,7 @@ TDownloadManager = class procedure CheckAndActiveTask(const isCheckForFMDDo: Boolean = False; {%H-}SenderThread: TThread = nil); // Active a stopped task. + procedure SetTaskActive(const taskID: Integer); procedure ActiveTask(const taskID : Integer); // Stop a download/wait task. procedure StopTask(const taskID : Integer; const isCheckForActive : Boolean = @@ -2150,6 +2151,17 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; end; end; +procedure TDownloadManager.SetTaskActive(const taskID: Integer); +begin + if (taskID < 0) or (taskID >= Containers.Count) then Exit; + with TTaskContainer(Containers[taskID]) do + if not ThreadState then + begin + Status := STATUS_WAIT; + DownloadInfo.Status := RS_Waiting; + end; +end; + procedure TDownloadManager.CheckAndActiveTaskAtStartup; var i, tcount: Integer; From 65a9b2ae80b2cd05df6429e7c3b2379223be807b Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:22:43 +0800 Subject: [PATCH 0478/2794] downloadmanager, clean up and correcting start stop task --- baseunits/uDownloadsManager.pas | 56 ++++++++++++--------------------- 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index dbefcf14b..dcd11a862 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2191,51 +2191,35 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; procedure TDownloadManager.ActiveTask(const taskID: Integer); begin if (taskID < 0) or (taskID >= Containers.Count) then Exit; - with TTaskContainer(Containers[taskID]) do - begin + with TTaskContainer(Containers[taskID]) do begin if Status = STATUS_FINISH then Exit; - if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then - begin - Status := STATUS_DOWNLOAD; - DownloadInfo.Status := RS_Downloading; + if not ThreadState then begin + if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then begin + Status := STATUS_DOWNLOAD; + DownloadInfo.Status := RS_Downloading; + end; + Modules.IncActiveTaskCount(ModuleId); + Thread := TTaskThread.Create; + Thread.container := TaskItem(taskID); + Thread.Start; end; - Modules.IncActiveTaskCount(ModuleId); - Thread := TTaskThread.Create; - Thread.container := TaskItem(taskID); - Thread.Start; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; - if not MainForm.itRefreshDLInfo.Enabled then - MainForm.itRefreshDLInfo.Enabled := True; end; end; procedure TDownloadManager.StopTask(const taskID: Integer; const isCheckForActive: Boolean; isWaitFor: Boolean); begin - if taskID < Containers.Count then - begin - if TaskItem(taskID).Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT] then - begin - if TaskItem(taskID).Status = STATUS_WAIT then - begin - TaskItem(taskID).Status := STATUS_STOP; - TaskItem(taskID).DownloadInfo.Status := RS_Stopped; - end; - if TaskItem(taskID).ThreadState then - begin - TaskItem(taskID).Thread.Terminate; - if isWaitFor then - TaskItem(taskID).Thread.WaitFor; - end; - if isCheckForActive then - begin - Backup; - CheckAndActiveTask; - end; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; + if (taskID < 0) or (taskID >= Containers.Count) then Exit; + with TTaskContainer(Containers[taskID]) do begin + if Status = STATUS_WAIT then begin + Status := STATUS_STOP; + DownloadInfo.Status := RS_Stopped; + end + else if ThreadState then begin + Thread.Terminate; + if isWaitFor then Thread.WaitFor; end; + if isCheckForActive then CheckAndActiveTask(); end; end; From 1a4b4e9fd76453745a098bee7b39a90ce5b8ab05 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:26:39 +0800 Subject: [PATCH 0479/2794] mainform, clean up and fix start stop task --- mangadownloader/forms/frmMain.pas | 53 ++++++++----------------------- 1 file changed, 14 insertions(+), 39 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 21b6787b0..f296275cb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2780,59 +2780,34 @@ procedure TMainForm.miDownloadDeleteCompletedClick(Sender: TObject); procedure TMainForm.miDownloadResumeClick(Sender: TObject); var - i: Cardinal; xNode: PVirtualNode; begin - if (vtDownload.SelectedCount = 1) and (Assigned(vtDownload.FocusedNode)) then - begin - if DLManager.TaskItem(vtDownload.FocusedNode^.Index).Status in - [STATUS_STOP, STATUS_PROBLEM, STATUS_FAILED] then - begin - DLManager.TaskItem(vtDownload.FocusedNode^.Index).Status := STATUS_WAIT; - DLManager.TaskItem(vtDownload.FocusedNode^.Index).DownloadInfo.Status := - RS_Waiting; - DLManager.CheckAndActiveTask; - vtDownload.Repaint; - DLManager.Backup; - end; - end - else - if (vtDownload.SelectedCount > 1) then - begin - xNode := vtDownload.GetFirstSelected; - for i := 0 to vtDownload.SelectedCount - 1 do - begin - if vtDownload.Selected[xNode] and - (DLManager.TaskItem(xNode^.Index).Status in - [STATUS_STOP, STATUS_PROBLEM, STATUS_FAILED]) then - begin - DLManager.TaskItem(xNode^.Index).Status := STATUS_WAIT; - DLManager.TaskItem(xNode^.Index).DownloadInfo.Status := RS_Waiting; - DLManager.CheckAndActiveTask; - end; + if vtDownload.SelectedCount > 0 then begin + xNode := vtDownload.GetFirstSelected(); + while Assigned(xNode) do begin + DLManager.SetTaskActive(xNode^.Index); xNode := vtDownload.GetNextSelected(xNode); end; - vtDownload.Repaint; + DLManager.CheckAndActiveTask(); DLManager.Backup; + vtDownload.Repaint; end; end; procedure TMainForm.miDownloadStopClick(Sender: TObject); var - i: Cardinal; xNode: PVirtualNode; begin - if not Assigned(vtDownload.FocusedNode) then exit; - xNode := vtDownload.GetFirstSelected; - for i := 0 to vtDownload.SelectedCount - 1 do - begin - if vtDownload.Selected[xNode] then + if vtDownload.SelectedCount > 0 then begin + xNode := vtDownload.GetFirstSelected(); + while Assigned(xNode) do begin DLManager.StopTask(xNode^.Index, False); - xNode := vtDownload.GetNextSelected(xNode); + xNode := vtDownload.GetNextSelected(xNode); + end; + DLManager.CheckAndActiveTask(); + DLManager.Backup; + vtDownload.Repaint; end; - DLManager.Backup; - DLManager.CheckAndActiveTask; - vtDownload.Repaint; end; procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); From cd871c869ce1bb6301e78b100079cca3c9063058 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:35:28 +0800 Subject: [PATCH 0480/2794] downloadmanager, clean up startall/stopall --- baseunits/uDownloadsManager.pas | 40 ++++++++++++--------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index dcd11a862..5cee9fff7 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2227,20 +2227,14 @@ procedure TDownloadManager.StartAllTasks; var i: Integer; begin - if Containers.Count > 0 then - begin + if Containers.Count > 0 then begin for i := 0 to Containers.Count - 1 do - begin - if TaskItem(i).Status in [STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM] then - begin - TaskItem(i).Status := STATUS_WAIT; - TaskItem(i).DownloadInfo.Status := RS_Waiting; - end; - end; - Backup; + with TTaskContainer(Containers[i]) do + if not ThreadState then begin + Status := STATUS_WAIT; + DownloadInfo.Status := RS_Waiting; + end; CheckAndActiveTask; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; end; end; @@ -2248,21 +2242,15 @@ procedure TDownloadManager.StopAllTasks; var i: Integer; begin - if Containers.Count > 0 then - begin + if Containers.Count > 0 then begin for i := 0 to Containers.Count - 1 do - begin - if TaskItem(i).Status = STATUS_WAIT then - begin - TaskItem(i).Status := STATUS_STOP; - TaskItem(i).DownloadInfo.Status := RS_Stopped; - end; - if TaskItem(i).ThreadState then - TaskItem(i).Thread.Terminate; - end; - Backup; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; + with TTaskContainer(Containers[i]) do + if ThreadState then + Thread.Terminate + else begin + Status := STATUS_STOP; + DownloadInfo.Status := RS_Stopped; + end; end; end; From 2c43ead783cd8cc305b70d38fedf4fed047ad578 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:36:14 +0800 Subject: [PATCH 0481/2794] mainform, update vtdownloadafter start/stop --- mangadownloader/forms/frmMain.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f296275cb..21f0145b8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3334,11 +3334,13 @@ procedure TMainForm.tbDownloadDeleteCompletedClick(Sender: TObject); procedure TMainForm.tbDownloadResumeAllClick(Sender: TObject); begin DLManager.StartAllTasks; + UpdateVtDownload; end; procedure TMainForm.tbDownloadStopAllClick(Sender: TObject); begin DLManager.StopAllTasks; + UpdateVtDownload; end; procedure TMainForm.tbDropTargetOpacityChange(Sender: TObject); From 7725244d49d06922de94919d5e94e9c6e399bfdc Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:41:18 +0800 Subject: [PATCH 0482/2794] mainform, updatevtdownload, do repaint --- mangadownloader/forms/frmMain.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 21f0145b8..86cff4064 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4822,10 +4822,12 @@ procedure TMainForm.UpdateVtChapter; procedure TMainForm.UpdateVtDownload; begin - vtDownload.RootNodeCount := DLManager.Count; + if vtDownload.RootNodeCount <> DLManager.Count then + vtDownload.RootNodeCount := DLManager.Count; // the reason we put vtDownloadFilters in here instead of in DLManager because // the size of download list can change while this method is running vtDownloadFilters; + vtDownload.Repaint; end; procedure TMainForm.UpdateVtFavorites; From ddcc8e0b0409a601dbd01e536fb5558153e620b3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 04:44:31 +0800 Subject: [PATCH 0483/2794] mainform, start/stop refresh list --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 86cff4064..29cac97c0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2790,7 +2790,7 @@ procedure TMainForm.miDownloadResumeClick(Sender: TObject); end; DLManager.CheckAndActiveTask(); DLManager.Backup; - vtDownload.Repaint; + UpdateVtDownload; end; end; @@ -2806,7 +2806,7 @@ procedure TMainForm.miDownloadStopClick(Sender: TObject); end; DLManager.CheckAndActiveTask(); DLManager.Backup; - vtDownload.Repaint; + UpdateVtDownload; end; end; From 7cec53adfe8bbc8fa6431e7b3d9498d5cc6e7992 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:00:00 +0800 Subject: [PATCH 0484/2794] mainform, fix not showing waiting task as in progress --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 29cac97c0..9e4f79840 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4137,7 +4137,7 @@ procedure TMainForm.vtDownloadFilters; case tvDownloadFilter.Selected.AbsoluteIndex of 0, 5: ShowTasks; 1: ShowTasks([STATUS_FINISH]); - 2: ShowTasks([STATUS_PREPARE, STATUS_DOWNLOAD, STATUS_COMPRESS]); + 2: ShowTasks([STATUS_WAIT, STATUS_PREPARE, STATUS_DOWNLOAD, STATUS_COMPRESS]); 3: ShowTasks([STATUS_STOP]); 4: ShowTasks([STATUS_PROBLEM, STATUS_FAILED]); 6: ShowTodayTasks; From 9d615d091a2090916c7be794ba0aa0121c903420 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:00:31 +0800 Subject: [PATCH 0485/2794] downloadmanager, clean up and fix --- baseunits/uDownloadsManager.pas | 62 ++++++++++++++------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5cee9fff7..d26b11d42 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2140,9 +2140,6 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; else MainForm.itRefreshDLInfo.Enabled := False; - Self.Backup; - MainForm.vtDownloadFilters; - if (Count = 0) and (isCheckForFMDDo) then ShowExitCounter; except @@ -2258,16 +2255,17 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; var i: Integer; begin - if Containers.Count > 0 then - begin + if Containers.Count > 0 then begin isReadyForExit := True; try for i := 0 to Containers.Count - 1 do - if TaskItem(i).ThreadState then - TaskItem(i).Thread.Terminate; + with TTaskContainer(Containers[i]) do + if ThreadState then + Thread.Terminate; for i := 0 to Containers.Count - 1 do - if TaskItem(i).ThreadState then - TaskItem(i).Thread.WaitFor; + with TTaskContainer(Containers[i]) do + if ThreadState then + Thread.WaitFor; finally isReadyForExit := False; end; @@ -2276,41 +2274,33 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; procedure TDownloadManager.RemoveTask(const taskID: Integer); begin - if taskID < Containers.Count then - begin - CS_DownloadManager_Task.Acquire; - try - if TaskItem(taskID).ThreadState then - begin - TaskItem(taskID).Status := STATUS_STOP; - TaskItem(taskID).Thread.Terminate; - TaskItem(taskID).Thread.WaitFor; + if (taskID < 0) or (taskID >= Containers.Count) then Exit; + CS_DownloadManager_Task.Acquire; + try + with TTaskContainer(Containers[taskID]) do + if ThreadState then begin + Thread.Terminate; + Thread.WaitFor; end; - TaskItem(taskID).Free; - Containers.Delete(taskID); - finally - CS_DownloadManager_Task.Release; - end; - CheckAndActiveTask; + TTaskContainer(Containers[taskID]).Free; + Containers.Delete(taskID); + finally + CS_DownloadManager_Task.Release; end; + CheckAndActiveTask; end; procedure TDownloadManager.RemoveAllFinishedTasks; var i: Integer; begin - if Containers.Count = 0 then - Exit; - // remove - i := 0; - repeat - if TaskItem(i).Status = STATUS_FINISH then - begin - Containers.Delete(i); - end - else - Inc(i); - until i >= Containers.Count; + if Containers.Count > 0 then begin + i := 0; + while i < Containers.Count do + if TTaskContainer(Containers[i]).Status = STATUS_FINISH then + Containers.Delete(i) + else Inc(i); + end; end; procedure TDownloadManager.doExitWaitCounter; From 7e82cc74b43e7461a902a5eed55b36cabf171ec3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:04:29 +0800 Subject: [PATCH 0486/2794] downloadmanager, clean up and fix --- baseunits/uDownloadsManager.pas | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d26b11d42..95c699d65 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1891,7 +1891,7 @@ procedure TDownloadManager.Backup; for i := 0 to Containers.Count - 1 do begin tid := 'task' + IntToStr(i); - with DownloadManagerFile, TTaskContainer(TaskItem(i)) do begin + with DownloadManagerFile, TTaskContainer(Containers[i]) do begin WriteString(tid, 'Website', DownloadInfo.Website); WriteString(tid, 'Link', DownloadInfo.Link); WriteString(tid, 'Title', DownloadInfo.Title); @@ -2197,7 +2197,7 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); end; Modules.IncActiveTaskCount(ModuleId); Thread := TTaskThread.Create; - Thread.container := TaskItem(taskID); + Thread.container := TTaskContainer(Containers[taskID]); Thread.Start; end; end; @@ -2319,13 +2319,10 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea CS_DownloadManager_Task.Acquire; try for i := 0 to Containers.Count - 1 do - begin - if TaskItem(i).Status in Stats then - begin + if TTaskContainer(Containers[i]).Status in Stats then begin Result := True; Break; end; - end; finally CS_DownloadManager_Task.Release; end; From 3536843f243477bd6a592c8a4e658decfa3294ed Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:13:08 +0800 Subject: [PATCH 0487/2794] downloadmanager, checkandactive, repaint after all done --- baseunits/uDownloadsManager.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 95c699d65..28b295a96 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2138,7 +2138,10 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; MainForm.itRefreshDLInfo.Enabled := True; end else + begin MainForm.itRefreshDLInfo.Enabled := False; + MainForm.UpdateVtDownload; + end; if (Count = 0) and (isCheckForFMDDo) then ShowExitCounter; From c2478d9034a6cf34c0c96d1ee00bdcc7ae6b2339 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:18:29 +0800 Subject: [PATCH 0488/2794] downloadmanager, fix not showing exit counter after all task finished --- baseunits/uDownloadsManager.pas | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 28b295a96..3343dfd9f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2141,10 +2141,9 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; begin MainForm.itRefreshDLInfo.Enabled := False; MainForm.UpdateVtDownload; + if isCheckForFMDDo then + ShowExitCounter; end; - - if (Count = 0) and (isCheckForFMDDo) then - ShowExitCounter; except on E: Exception do MainForm.ExceptionHandler(Self, E); From 72e9b4fb4dcc5cb8b698612d4531d1841c951cb4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:27:36 +0800 Subject: [PATCH 0489/2794] downloadmanager, fix startall/stopall ignoring status_finish --- baseunits/uDownloadsManager.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 3343dfd9f..c9e5d741c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2229,7 +2229,7 @@ procedure TDownloadManager.StartAllTasks; if Containers.Count > 0 then begin for i := 0 to Containers.Count - 1 do with TTaskContainer(Containers[i]) do - if not ThreadState then begin + if (Status <> STATUS_FINISH) and (not ThreadState) then begin Status := STATUS_WAIT; DownloadInfo.Status := RS_Waiting; end; @@ -2246,7 +2246,7 @@ procedure TDownloadManager.StopAllTasks; with TTaskContainer(Containers[i]) do if ThreadState then Thread.Terminate - else begin + else if Status <> STATUS_FINISH then begin Status := STATUS_STOP; DownloadInfo.Status := RS_Stopped; end; From d2ac83e4db83ca57e6418764797542be0b289340 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 05:42:43 +0800 Subject: [PATCH 0490/2794] downloadmanager, do checkandactivetask in thread synchronize --- baseunits/uDownloadsManager.pas | 25 +++---------------------- baseunits/uSilentThread.pas | 2 +- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c9e5d741c..859cd1e56 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -197,8 +197,7 @@ TDownloadManager = class // Check and active previous work-in-progress tasks. procedure CheckAndActiveTaskAtStartup; // Check and active waiting tasks. - procedure CheckAndActiveTask(const isCheckForFMDDo: Boolean = False; - {%H-}SenderThread: TThread = nil); + procedure CheckAndActiveTask(const isCheckForFMDDo: Boolean = False); // Active a stopped task. procedure SetTaskActive(const taskID: Integer); procedure ActiveTask(const taskID : Integer); @@ -2087,27 +2086,9 @@ function TDownloadManager.AddTask : Integer; end; end; -procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; - SenderThread : TThread); +procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); var i, tcount: Integer; - - procedure ShowExitCounter; - begin - if OptionLetFMDDo in [DO_NOTHING, DO_UPDATE] then Exit; - if ThreadID <> MainThreadID then - begin - {$IFDEF FPC271} - TThread.Synchronize(TThread.CurrentThread, doExitWaitCounter); - {$ELSE} - if SenderThread <> nil then - TThread.Synchronize(SenderThread, doExitWaitCounter); - {$ENDIF} - end - else - doExitWaitCounter; - end; - begin if Containers.Count = 0 then Exit; CS_DownloadManager_Task.Acquire; @@ -2142,7 +2123,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo : Boolean; MainForm.itRefreshDLInfo.Enabled := False; MainForm.UpdateVtDownload; if isCheckForFMDDo then - ShowExitCounter; + doExitWaitCounter; end; except on E: Exception do diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index cdd5702a2..e45aea6c8 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -378,7 +378,7 @@ procedure TSilentThread.MainThreadAfterChecking; UpdateVtDownload; DLManager.Backup; - DLManager.CheckAndActiveTask(False, Self); + DLManager.CheckAndActiveTask(False); // save downloaded chapters if Info.mangaInfo.chapterLinks.Count > 0 then From b3a5d3267bb0e36b34cd64117ad79257e11b2092 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 06:40:00 +0800 Subject: [PATCH 0491/2794] mainform, change version number in readme.rtf with the actual version number --- mangadownloader/forms/frmMain.pas | 42 +++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9e4f79840..b1bc6a6a6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -940,6 +940,9 @@ procedure TMainForm.FormCreate(Sender: TObject); Application.HintHidePause := 10000; sbUpdateList.DoubleBuffered := True; + // load about + LoadAbout; + // remove old updater if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then DeleteFileUTF8(fmdDirectory + 'old_updater.exe'); @@ -1643,12 +1646,34 @@ procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); procedure TMainForm.LoadAbout; var + i: Integer; + s: string; fs: TFileStreamUTF8; + st: TStringList; + regx: TRegExpr; begin // load readme.rtf - if FileExistsUTF8(CleanAndExpandDirectory(GetCurrentDirUTF8) + README_FILE) then - begin - fs := TFileStreamUTF8.Create(README_FILE, fmOpenRead or fmShareDenyNone); + s := fmdDirectory + README_FILE; + if FileExistsUTF8(s) then begin + regx := TRegExpr.Create; + st := TStringList.Create; + try + regx.ModifierI := True; + regx.Expression := '(version.*)(\d+\.){3}\d+'; + st.LoadFromFile(s); + if st.Count > 0 then + for i := 0 to st.Count - 1 do + if regx.Exec(st[i]) then + begin + st[i] := regx.Replace(st[i], '$1\' + FMD_VERSION_NUMBER, True); + st.SaveToFile(s); + Break; + end; + finally + st.Free; + regx.Free; + end; + fs := TFileStreamUTF8.Create(s, fmOpenRead or fmShareDenyNone); try rmAbout.LoadRichText(fs); finally @@ -1656,8 +1681,8 @@ procedure TMainForm.LoadAbout; end; end; // load changelog.txt - if FileExistsUTF8(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE) then - mmChangelog.Lines.LoadFromFile(CleanAndExpandDirectory(GetCurrentDirUTF8) + CHANGELOG_FILE); + s := CleanAndExpandDirectory(fmdDirectory) + CHANGELOG_FILE; + if FileExistsUTF8(s) then mmChangelog.Lines.LoadFromFile(s); end; procedure TMainForm.tvDownloadFilterRepaint; @@ -3034,12 +3059,9 @@ procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); procedure TMainForm.pcMainChange(Sender: TObject); begin - if pcMain.ActivePage = tsAbout then - LoadAbout - else if pcMain.ActivePage = tsFavorites then - vtFavorites.Repaint; - if pcMain.ActivePage = tsOption then + vtFavorites.Repaint + else if pcMain.ActivePage = tsOption then LoadOptions; end; From 25d2a0851a8ac913fc7026452cb1d2cb164773a6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 07:28:03 +0800 Subject: [PATCH 0492/2794] Bump version 0.9.21.4 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 420a7372d..3045ab4ee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.4 (10-08-2015) +[*] Various changes and bug fixes + 0.9.21.3 (09-08-2015) [*] Fix favoritemanager doesn't showing the result when new chapter found [*] Fix per item favorite check diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 23f613fd9..a32f3c5ee 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index fb9f43dee..eb898a55a 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.3 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.3/fmd_0.9.21.3.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.3/fmd_0.9.21.3_Win64.7z +VERSION=0.9.21.4 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.4/fmd_0.9.21.4.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.4/fmd_0.9.21.4_Win64.7z From 2e9bd37e97dd92823906b630d2717e881c8bd640 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 14:18:48 +0800 Subject: [PATCH 0493/2794] fix remove multiple task at once --- mangadownloader/forms/frmMain.pas | 51 +++++++++---------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b1bc6a6a6..711121038 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1417,11 +1417,9 @@ procedure TMainForm.miChapterListHighlightClick(Sender: TObject); procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); var - i, j: Integer; xNode: PVirtualNode; + i: Integer; f: String; - finfo: TSearchRec; - fs: TStringList; begin if vtDownload.SelectedCount = 0 then Exit; if DLManager.Count = 0 then Exit; @@ -1431,21 +1429,14 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); Exit; DLManager.CS_DownloadManager_Task.Acquire; try - i:=0; - xNode := vtDownload.GetFirst; - while i < DLManager.Count do - begin - if vtDownload.Selected[xNode] then - begin - if Sender = miDownloadDeleteTaskData then - begin - DLManager.StopTask(i, True, False); - if DLManager.TaskItem(i).ChapterName.Count > 0 then - begin - for j := 0 to DLManager.TaskItem(i).ChapterName.Count-1 do - begin - f := CleanAndExpandDirectory(DLManager.TaskItem(i).DownloadInfo.SaveTo) + - DLManager.TaskItem(i).ChapterName[j]; + xNode := vtDownload.GetLast(); + while Assigned(xNode) do begin + if vtDownload.Selected[xNode] then begin + DLManager.StopTask(xNode^.Index, False, True); + with TTaskContainer(DLManager.Containers[xNode^.Index]) do begin + if (Sender = miDownloadDeleteTaskData) and (ChapterName.Count > 0) then begin + for i := 0 to ChapterName.Count - 1 do begin + f := CleanAndExpandDirectory(DownloadInfo.SaveTo) + ChapterName[i]; if FileExistsUTF8(f + '.zip') then DeleteFileUTF8(f + '.zip') else if FileExistsUTF8(f + '.cbz') then @@ -1455,31 +1446,17 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); else if DirectoryExistsUTF8(f) then DeleteDirectory(f, False); end; + RemoveDirUTF8(CleanAndExpandDirectory(DownloadInfo.SaveTo)); end; - f := CleanAndExpandDirectory(DLManager.TaskItem(i).DownloadInfo.SaveTo); - fs := TStringList.Create; - try - if FindFirstUTF8(f + '*', faAnyFile and faDirectory, finfo) = 0 then - repeat - fs.Add(finfo.Name); - until FindNextUTF8(finfo) <> 0; - FindCloseUTF8(finfo); - if fs.Count = 2 then - DeleteDirectory(f, False); - finally - fs.Free; - end; + TTaskContainer(DLManager.Containers[xNode^.Index]).Free; + DLManager.Containers.Delete(xNode^.Index); end; - DLManager.RemoveTask(i); - end - else - Inc(i); - xNode := vtDownload.GetNext(xNode); + end; + xNode := vtDownload.GetPreviousSelected(xNode); end; finally DLManager.CS_DownloadManager_Task.Release; end; - vtDownload.ClearSelection; DLManager.CheckAndActiveTask; UpdateVtDownload; DLManager.Backup; From 5be93d2449a37d383331b55f7ee6c4f68ad6a689 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 14:21:25 +0800 Subject: [PATCH 0494/2794] favoritemanager, always download if favautodownload --- baseunits/uFavoritesManager.pas | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 35b3d0ef3..02e5867ec 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -647,12 +647,7 @@ procedure TFavoriteManager.ShowResult; begin //if there's new chapters if OptionAutoCheckFavDownload then - begin - if MainForm.cbAddAsStopped.Checked then - LNCResult := ncrQueue - else - LNCResult := ncrDownload; - end + LNCResult := ncrDownload else begin with TNewChapter.Create(MainForm) do try From 1c75d28b973aa1d499b78369ef77aa1f966ee94f Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 14:39:28 +0800 Subject: [PATCH 0495/2794] fix timer auto check favorites on interval not enabled if auto check new version not enabled --- mangadownloader/forms/frmMain.pas | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 711121038..fa62cd8ce 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4636,11 +4636,10 @@ procedure TMainForm.ApplyOptions; OptionAutoCheckFavIntervalMinutes := seOptionAutoCheckFavIntervalMinutes.Value; OptionAutoCheckFavDownload := cbOptionAutoCheckFavDownload.Checked; OptionAutoCheckFavRemoveCompletedManga := cbOptionAutoCheckFavRemoveCompletedManga.Checked; - if OptionAutoCheckFavIntervalMinutes <> 0 then - itCheckFav.Interval := OptionAutoCheckFavIntervalMinutes * 60000; - itCheckFav.Enabled := OptionAutoCheckLatestVersion and (OptionAutoCheckFavIntervalMinutes <> 0); OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; + itCheckFav.Interval := OptionAutoCheckFavIntervalMinutes * 60000; + itCheckFav.Enabled := OptionAutoCheckFavInterval and (itCheckFav.Interval > 0); //misc OptionBatotoShowScanGroup := cbOptionBatotoShowScanGroup.Checked; From 63912a4bf1f4a2f6c8fb76722cdec06aa688c340 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 15:08:02 +0800 Subject: [PATCH 0496/2794] websitemodules, add website property --- baseunits/WebsiteModules.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index e5afc8c8a..b1edb1237 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -81,6 +81,7 @@ TWebsiteModules = class function GetMaxConnectionLimit(const ModuleId: Integer): Integer; function GetActiveTaskCount(const ModuleId: Integer): Integer; function GetActiveConnectionLimit(const ModuleId: Integer): Integer; + function GetWebsite(const ModuleId: Integer): String; public constructor Create; destructor Destroy; override; @@ -135,6 +136,7 @@ TWebsiteModules = class property Module[const ModuleId: Integer]: TModuleContainer read GetModule; property Count: Integer read GetCount; + property Website[const ModuleId: Integer]: String read GetWebsite; property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; property MaxConnectionLimit[const ModuleId: Integer]: Integer @@ -519,6 +521,12 @@ function TWebsiteModules.GetActiveConnectionLimit(const ModuleId: Integer): Inte Result := TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount; end; +function TWebsiteModules.GetWebsite(const ModuleId: Integer): String; +begin + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(''); + Result := TModuleContainer(FModuleList[ModuleId]).Website; +end; + procedure doInitialize; begin if Modules = nil then From cebd24b544a0d16388e6b7e6bc43da4128382fcc Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 15:28:22 +0800 Subject: [PATCH 0497/2794] downloadmanager, set downloadinfo.website too --- baseunits/uDownloadsManager.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 859cd1e56..49bc7664c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1639,6 +1639,7 @@ procedure TTaskContainer.SetWebsite(AValue: String); begin if FWebsite = AValue then Exit; FWebsite := AValue; + DownloadInfo.Website := AValue; MangaSiteID := GetMangaSiteID(AValue); ModuleId := Modules.LocateModule(AValue); end; From 7591d99889a81bc51cd736b443934534a4fef498 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 15:36:51 +0800 Subject: [PATCH 0498/2794] fix auto download new chapter in favorites set wrong website fix #92 --- baseunits/uFavoritesManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 02e5867ec..c8e775f75 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -685,7 +685,7 @@ procedure TFavoriteManager.ShowResult; with TTaskContainer(DLManager.Containers.Last) do begin Manager := DLManager; CurrentDownloadChapterPtr := 0; - Website := Website; + Website := FavoriteInfo.Website; with DownloadInfo do begin Website := FavoriteInfo.Website; Link := FavoriteInfo.Link; From 7669b735344848ec18b15bc3deb298bde5d21ae3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 19:37:32 +0800 Subject: [PATCH 0499/2794] clean up --- baseunits/uBaseUnit.pas | 6 +- baseunits/uFavoritesManager.pas | 560 +++++++++++++++----------------- 2 files changed, 273 insertions(+), 293 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1c88e6b6a..e06110a8e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -762,9 +762,9 @@ TFavoriteInfo = record Title, Link, SaveTo, - numbering, - downloadedChapterList, - currentChapter: String; + Numbering, + DownloadedChapterList, + CurrentChapter: String; end; TCardinalList = TFPGList; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index c8e775f75..7d9a5002c 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -12,7 +12,8 @@ interface uses Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, - uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, USimpleException; + uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, + USimpleException; type TFavoriteManager = class; @@ -58,7 +59,7 @@ TFavoriteTask = class(TFMDThread) { TFavoriteContainer } - TFavoriteContainer = Class + TFavoriteContainer = class private FModuleId: Integer; FWebsite: String; @@ -81,11 +82,9 @@ TFavoriteTask = class(TFMDThread) TFavoriteManager = class private - CS_Favorites : TCriticalSection; + CS_Favorites: TCriticalSection; FSortColumn: Integer; - FSortDirection, - FIsAuto, - FIsRunning: Boolean; + FSortDirection, FIsAuto, FIsRunning: Boolean; FFavorites: TFPList; protected function GetFavoritesCount: Integer; @@ -103,20 +102,18 @@ TFavoriteManager = class //Check favorites procedure CheckForNewChapter(FavoriteIndex: Integer = -1); - procedure StopChekForNewChapter(WaitFor: Boolean = True; - FavoriteIndex: Integer = -1); + procedure StopChekForNewChapter(WaitFor: Boolean = True; FavoriteIndex: Integer = -1); // Show notification form after checking completed procedure ShowResult; // Return true if a manga exist in FFavorites - function IsMangaExist(const title, website: String): Boolean; - function IsMangaExistURL(const website, URL: String): Boolean; + function IsMangaExist(const ATitle, AWebsite: String): Boolean; + function IsMangaExistURL(const AWebsite, AURL: String): Boolean; // Add new manga to the list - procedure Add(const Atitle, AcurrentChapter, AdownloadedChapterList, - Awebsite, AsaveTo, Alink: String); + procedure Add(const ATitle, ACurrentChapter, ADownloadedChapterList, AWebsite, ASaveTo, ALink: String); // Merge manga information with a title that already exist in FFavorites - procedure AddMerge(const Atitle, AcurrentChapter, AdownloadedChapterList, - Awebsite, AsaveTo, Alink: String); + procedure AddMerge(const ATitle, ACurrentChapter, ADownloadedChapterList, AWebsite, + ASaveTo, ALink: String); // Merge a FFavorites.ini with another FFavorites.ini procedure MergeWith(const APath: String); // Remove a manga from FFavorites @@ -126,7 +123,8 @@ TFavoriteManager = class // Backup to FFavorites.ini procedure Backup; // Add FFavorites downloadedchapterlist - procedure AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); overload; + procedure AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); + overload; procedure AddToDownloadedChaptersList(const AWebsite, Alink: String; AValue: TStrings); overload; // sorting procedure Sort(const AColumn: Integer); @@ -367,7 +365,7 @@ procedure TFavoriteTask.Execute; UnlockCreateConnection; end; while threads.Count > 0 do - Sleep(100); + Sleep(100); end; if (not Terminated) and (not isDlgCounter) then @@ -378,7 +376,7 @@ procedure TFavoriteTask.Execute; end; manager.CS_Favorites.Acquire; try - for i := 0 to manager.FFavorites.Count-1 do + for i := 0 to manager.FFavorites.Count - 1 do if TFavoriteContainer(manager.FFavorites[i]).Status <> STATUS_IDLE then TFavoriteContainer(manager.FFavorites[i]).Status := STATUS_IDLE; finally @@ -460,31 +458,30 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); try if FavoriteIndex > -1 then begin - if TFavoriteContainer(FFavorites[FavoriteIndex]).Status = STATUS_IDLE then - begin - TFavoriteContainer(FFavorites[FavoriteIndex]).Status := STATUS_CHECK; - if Assigned(taskthread) then - taskthread.statuscheck := InterLockedIncrement(taskthread.statuscheck); - end; + with TFavoriteContainer(FFavorites[FavoriteIndex]) do + if Status = STATUS_IDLE then + begin + Status := STATUS_CHECK; + if Assigned(taskthread) then + taskthread.statuscheck := InterLockedIncrement(taskthread.statuscheck); + end; end else + if isRunning then begin - if isRunning then - begin - if not isAuto then - MessageDlg('', RS_DlgFavoritesCheckIsRunning, mtInformation, [mbOK], 0); - end - else - begin - CS_Favorites.Acquire; - try - for i := 0 to FFavorites.Count-1 do - with TFavoriteContainer(FFavorites[i]) do - if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then - Status := STATUS_CHECK; - finally - CS_Favorites.Release; - end; + if not isAuto then + MessageDlg('', RS_DlgFavoritesCheckIsRunning, mtInformation, [mbOK], 0); + end + else + begin + CS_Favorites.Acquire; + try + for i := 0 to FFavorites.Count - 1 do + with TFavoriteContainer(FFavorites[i]) do + if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then + Status := STATUS_CHECK; + finally + CS_Favorites.Release; end; end; if taskthread = nil then @@ -499,21 +496,21 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); end; end; -procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; - FavoriteIndex: Integer); +procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; FavoriteIndex: Integer); begin if isRunning then - begin if FavoriteIndex > -1 then begin - if TFavoriteContainer(FFavorites[FavoriteIndex]).Thread <> nil then - begin - TFavoriteContainer(FFavorites[FavoriteIndex]).Thread.Terminate; - if WaitFor then - TFavoriteContainer(FFavorites[FavoriteIndex]).Thread.WaitFor; + with TFavoriteContainer(FFavorites[FavoriteIndex]) do begin + if Thread <> nil then + begin + Thread.Terminate; + if WaitFor then + Thread.WaitFor; + end; + if Status <> STATUS_IDLE then + Status := STATUS_IDLE; end; - if TFavoriteContainer(FFavorites[FavoriteIndex]).Status <> STATUS_IDLE then - TFavoriteContainer(FFavorites[FavoriteIndex]).Status := STATUS_IDLE; end else begin @@ -521,20 +518,16 @@ procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; if WaitFor then taskthread.WaitFor; end; - end; end; procedure TFavoriteManager.ShowResult; var - i, p, counter, - numOfNewChapters, - numOfMangaNewChapters, - numOfCompleted : Integer; - dlChapters : TStringList; - LNCResult : TNewChapterResult = ncrCancel; - newChapterListStr : String = ''; - removeListStr : String = ''; - favDelete : Boolean; + i, p, counter, numOfNewChapters, numOfMangaNewChapters, numOfCompleted: Integer; + dlChapters: TStringList; + LNCResult: TNewChapterResult = ncrCancel; + newChapterListStr: String = ''; + removeListStr: String = ''; + favDelete: Boolean; begin if isDlgCounter then Exit; if (Self.DLManager = nil) and Assigned(MainForm.DLManager) then @@ -549,53 +542,50 @@ procedure TFavoriteManager.ShowResult; numOfCompleted := 0; counter := 0; while counter < FFavorites.Count do - begin - //compare new mangainfo's chapters with downloadedchapter from favorites with FavoriteItem(counter) do try - if Assigned(MangaInfo) then - begin - if MangaInfo.chapterLinks.Count > 0 then - begin - NewMangaInfo := TMangaInfo.Create; - NewMangaInfoChaptersPos := TCardinalList.Create; - TransferMangaInfo(NewMangaInfo, MangaInfo); - NewMangaInfo.chapterLinks.Clear; - NewMangaInfo.chapterName.Clear; - dlChapters.Clear; - GetParams(dlChapters, FavoriteInfo.downloadedChapterList); - dlChapters.Sort; - for i := 0 to MangaInfo.chapterLinks.Count - 1 do - if not dlChapters.Find(MangaInfo.chapterLinks[i], p) then + if Assigned(MangaInfo) then + if MangaInfo.chapterLinks.Count > 0 then + begin + NewMangaInfo := TMangaInfo.Create; + NewMangaInfoChaptersPos := TCardinalList.Create; + TransferMangaInfo(NewMangaInfo, MangaInfo); + NewMangaInfo.chapterLinks.Clear; + NewMangaInfo.chapterName.Clear; + dlChapters.Clear; + GetParams(dlChapters, FavoriteInfo.downloadedChapterList); + dlChapters.Sort; + for i := 0 to MangaInfo.chapterLinks.Count - 1 do + if not dlChapters.Find(MangaInfo.chapterLinks[i], p) then + begin + NewMangaInfo.chapterLinks.Add(MangaInfo.chapterLinks[i]); + NewMangaInfo.chapterName.Add(MangaInfo.chapterName[i]); + NewMangaInfoChaptersPos.Add(i); + Inc(numOfNewChapters); + end; + + //add to notification + if NewMangaInfo.chapterLinks.Count > 0 then begin - NewMangaInfo.chapterLinks.Add(MangaInfo.chapterLinks[i]); - NewMangaInfo.chapterName.Add(MangaInfo.chapterName[i]); - NewMangaInfoChaptersPos.Add(i); - Inc(numOfNewChapters); + newChapterListStr := newChapterListStr + LineEnding + '- ' + + Format(RS_FavoriteHasNewChapter, + [FavoriteInfo.Title, FavoriteItem(counter).FavoriteInfo.Website, + NewMangaInfo.chapterLinks.Count]); + Inc(numOfMangaNewChapters); end; - //add to notification - if NewMangaInfo.chapterLinks.Count > 0 then - begin - newChapterListStr := newChapterListStr + LineEnding + '- ' + - Format(RS_FavoriteHasNewChapter, - [FavoriteInfo.Title, FavoriteItem(counter).FavoriteInfo.Website, - NewMangaInfo.chapterLinks.Count]); - Inc(numOfMangaNewChapters); - end; - - //add completed manga - if (OptionAutoCheckFavRemoveCompletedManga) and (NewMangaInfo.status = '0') then - begin - removeListStr := removeListStr + LineEnding + - Format('- %s <%s>', [FavoriteInfo.Title, FavoriteInfo.Website]); - Inc(numOfCompleted); + //add completed manga + if (OptionAutoCheckFavRemoveCompletedManga) and + (NewMangaInfo.status = '0') then + begin + removeListStr := removeListStr + LineEnding + + Format('- %s <%s>', [FavoriteInfo.Title, FavoriteInfo.Website]); + Inc(numOfCompleted); + end; end; - end; - end; - finally - Inc(counter); - end; - end; + finally + Inc(counter); + end//compare new mangainfo's chapters with downloadedchapter from favorites + ; dlChapters.Clear; if numOfNewChapters = 0 then @@ -604,19 +594,19 @@ procedure TFavoriteManager.ShowResult; if numOfCompleted > 0 then begin with TNewChapter.Create(MainForm) do try - Caption := Format(RS_DlgCompletedMangaCaption, [numOfCompleted]); - lbNotification.Caption := RS_LblMangaWillBeRemoved; - mmMemo.Lines.Text := Trim(removeListStr); - btDownload.Caption := RS_BtnRemove; - btCancel.Caption := RS_BtnCancel; - btDownload.Show; - btCancel.Show; - btQueue.Hide; - ShowModal; - LNCResult := FormResult; - finally - Free; - end; + Caption := Format(RS_DlgCompletedMangaCaption, [numOfCompleted]); + lbNotification.Caption := RS_LblMangaWillBeRemoved; + mmMemo.Lines.Text := Trim(removeListStr); + btDownload.Caption := RS_BtnRemove; + btCancel.Caption := RS_BtnCancel; + btDownload.Show; + btCancel.Show; + btQueue.Hide; + ShowModal; + LNCResult := FormResult; + finally + Free; + end; //delete complete FFavorites if LNCResult = ncrDownload then @@ -625,15 +615,14 @@ procedure TFavoriteManager.ShowResult; while counter < FFavorites.Count do begin favDelete := False; - with FavoriteItem(counter) do begin - if Assigned(NewMangaInfo) then - if (NewMangaInfo.chapterLinks.Count = 0) and (NewMangaInfo.status = '0') then + with FavoriteItem(counter) do if Assigned(NewMangaInfo) then + if (NewMangaInfo.chapterLinks.Count = 0) and + (NewMangaInfo.status = '0') then begin FavoriteItem(counter).Free; FFavorites.Delete(counter); favDelete := True; end; - end; if not favDelete then Inc(counter); end; @@ -647,36 +636,34 @@ procedure TFavoriteManager.ShowResult; begin //if there's new chapters if OptionAutoCheckFavDownload then - LNCResult := ncrDownload + LNCResult := ncrDownload else - begin with TNewChapter.Create(MainForm) do try - Caption := Format(RS_DlgNewChapterCaption, [numOfNewChapters]); - lbNotification.Caption := Format(RS_LblNewChapterFound, [numOfNewChapters, numOfMangaNewChapters]); - mmMemo.Lines.Text := Trim(newChapterListStr); - btDownload.Caption := RS_BtnDownload; - btQueue.Caption := RS_BtnAddToQueue; - btCancel.Caption := RS_BtnCancel; - btDownload.Show; - btQueue.Show; - btCancel.Show; - ShowModal; - LNCResult := FormResult; - finally - Free; - end; - end; + Caption := Format(RS_DlgNewChapterCaption, [numOfNewChapters]); + lbNotification.Caption := + Format(RS_LblNewChapterFound, [numOfNewChapters, numOfMangaNewChapters]); + mmMemo.Lines.Text := Trim(newChapterListStr); + btDownload.Caption := RS_BtnDownload; + btQueue.Caption := RS_BtnAddToQueue; + btCancel.Caption := RS_BtnCancel; + btDownload.Show; + btQueue.Show; + btCancel.Show; + ShowModal; + LNCResult := FormResult; + finally + Free; + end; if LNCResult <> ncrCancel then - //generate new download task + //generate new download task begin while DLManager.isRunningBackup do Sleep(100); counter := 0; while counter < FFavorites.Count do begin - with FavoriteItem(counter) do begin - if Assigned(NewMangaInfo) then + with FavoriteItem(counter) do if Assigned(NewMangaInfo) then if NewMangaInfo.chapterLinks.Count > 0 then begin DLManager.CS_DownloadManager_Task.Acquire; @@ -687,14 +674,13 @@ procedure TFavoriteManager.ShowResult; CurrentDownloadChapterPtr := 0; Website := FavoriteInfo.Website; with DownloadInfo do begin - Website := FavoriteInfo.Website; Link := FavoriteInfo.Link; Title := FavoriteInfo.Title; SaveTo := FavoriteInfo.SaveTo; dateTime := Now; end; ChapterLinks.Assign(NewMangaInfo.chapterLinks); - for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do begin + for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do ChapterName.Add(CustomRename( OptionCustomRename, FavoriteInfo.Website, @@ -704,7 +690,6 @@ procedure TFavoriteManager.ShowResult; NewMangaInfo.chapterName[i], Format('%.4d', [NewMangaInfoChaptersPos[i] + 1]), MainForm.cbOptionPathConvert.Checked)); - end; if LNCResult = ncrDownload then begin DownloadInfo.Status := RS_Waiting; @@ -716,18 +701,19 @@ procedure TFavoriteManager.ShowResult; Status := STATUS_STOP; end; end; - FavoriteInfo.currentChapter := IntToStr(MangaInfo.chapterLinks.Count); + FavoriteInfo.currentChapter := + IntToStr(MangaInfo.chapterLinks.Count); finally DLManager.CS_DownloadManager_Task.Release; end; //mark downloaded FavoriteInfo.downloadedChapterList := - FavoriteInfo.downloadedChapterList + SetParams(NewMangaInfo.chapterLinks); + FavoriteInfo.downloadedChapterList + + SetParams(NewMangaInfo.chapterLinks); //save to downloaded chapter list from dlmanager. DLManager.AddToDownloadedChaptersList( FavoriteInfo.Website + FavoriteInfo.Link, NewMangaInfo.chapterLinks); end; - end; Inc(counter); end; Backup; @@ -756,7 +742,7 @@ procedure TFavoriteManager.ShowResult; if Assigned(NewMangaInfoChaptersPos) then FreeAndNil(NewMangaInfoChaptersPos); end; - Inc(counter) + Inc(counter); end; FreeAndNil(dlChapters); CS_Favorites.Release; @@ -767,47 +753,47 @@ procedure TFavoriteManager.ShowResult; end; end; -function TFavoriteManager.IsMangaExist(const title, website: String): Boolean; +function TFavoriteManager.IsMangaExist(const ATitle, AWebsite: String): Boolean; var i: Integer; begin + Result := False; if FFavorites.Count > 0 then for i := 0 to FFavorites.Count - 1 do - if (CompareText(FavoriteItem(i).FavoriteInfo.Title, title) = 0) and - (CompareText(FavoriteItem(i).FavoriteInfo.website, website) = 0) then - Exit(True); - Result := False; + with TFavoriteContainer(FFavorites[i]).FavoriteInfo do + if SameText(ATitle, Title) and SameText(AWebsite, Website) then + Exit(True); end; -function TFavoriteManager.IsMangaExistURL(const website, URL : String): Boolean; -Var +function TFavoriteManager.IsMangaExistURL(const AWebsite, AURL: String): Boolean; +var i: Integer; begin Result := False; if FFavorites.Count > 0 then for i := 0 to FFavorites.Count - 1 do - if SameText(website, FavoriteItem(i).FavoriteInfo.Website) and - SameText(URL, FavoriteItem(i).FavoriteInfo.Link) then - Exit(True); - Result := False; + with TFavoriteContainer(FFavorites[i]).FavoriteInfo do + if SameText(AWebsite, Website) and SameText(AURL, Link) then + Exit(True); end; -procedure TFavoriteManager.Add(const Atitle, AcurrentChapter, - AdownloadedChapterList, Awebsite, AsaveTo, Alink: String); +procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapterList, + AWebsite, ASaveTo, ALink: String); begin - if IsMangaExist(Atitle, Awebsite) then Exit; + if IsMangaExist(ATitle, AWebsite) then Exit; CS_Favorites.Acquire; try FFavorites.Add(TFavoriteContainer.Create); with TFavoriteContainer(FFavorites.Last) do begin Manager := Self; - FavoriteInfo.Title := Atitle; - FavoriteInfo.currentChapter := AcurrentChapter; - FavoriteInfo.website := Awebsite; - FavoriteInfo.saveTo := AsaveTo; - FavoriteInfo.Link := ALink; - FavoriteInfo.downloadedChapterList := AdownloadedChapterList; Website := AWebsite; + with FavoriteInfo do begin + Title := ATitle; + CurrentChapter := ACurrentChapter; + SaveTo := ASaveTo; + Link := ALink; + DownloadedChapterList := ADownloadedChapterList; + end; Status := STATUS_IDLE; end; if not isRunning then @@ -820,23 +806,25 @@ procedure TFavoriteManager.Add(const Atitle, AcurrentChapter, end; end; -procedure TFavoriteManager.AddMerge(const Atitle, AcurrentChapter, - AdownloadedChapterList, Awebsite, AsaveTo, Alink: String); +procedure TFavoriteManager.AddMerge(const ATitle, ACurrentChapter, ADownloadedChapterList, + AWebsite, ASaveTo, ALink: String); begin - if IsMangaExist(Atitle, Awebsite) then + if IsMangaExist(ATitle, AWebsite) then Exit; CS_Favorites.Acquire; try FFavorites.Add(TFavoriteContainer.Create); with TFavoriteContainer(FFavorites.Last) do begin Manager := Self; - FavoriteInfo.Title := Atitle; - FavoriteInfo.currentChapter := AcurrentChapter; - FavoriteInfo.website := Awebsite; - FavoriteInfo.saveTo := AsaveTo; - FavoriteInfo.Link := Alink; - FavoriteInfo.downloadedChapterList := AdownloadedChapterList; - Website := Awebsite; + Website := AWebsite; + with FavoriteInfo do begin + Title := ATitle; + CurrentChapter := ACurrentChapter; + Website := AWebsite; + SaveTo := ASaveTo; + Link := ALink; + DownloadedChapterList := ADownloadedChapterList; + end; end; except CS_Favorites.Release; @@ -858,36 +846,32 @@ procedure TFavoriteManager.MergeWith(const APath: String); fstream := TFileStreamUTF8.Create(APath, fmOpenRead); mergeFile := TIniFile.Create(fstream); - - l := mergeFile.ReadInteger('general', 'NumberOfFavorites', 0); - if l > 0 then - begin - SetLength(infos, l); - for i := 0 to l - 1 do - begin - infos[i].Title := mergeFile.ReadString(IntToStr(i), 'Title', ''); - infos[i].currentChapter := - mergeFile.ReadString(IntToStr(i), 'CurrentChapter', '0'); - infos[i].downloadedChapterList := - mergeFile.ReadString(IntToStr(i), 'DownloadedChapterList', ''); - infos[i].website := mergeFile.ReadString(IntToStr(i), 'Website', ''); - infos[i].SaveTo := mergeFile.ReadString(IntToStr(i), 'SaveTo', ''); - infos[i].link := mergeFile.ReadString(IntToStr(i), 'Link', ''); - - AddMerge(infos[i].Title, - infos[i].currentChapter, - infos[i].downloadedChapterList, - infos[i].website, - infos[i].SaveTo, - infos[i].link); + try + with mergeFile do begin + l := mergeFile.ReadInteger('general', 'NumberOfFavorites', 0); + if l > 0 then + begin + SetLength(infos, l); + for i := 0 to l - 1 do + with infos[i] do begin + Title := ReadString(IntToStr(i), 'Title', ''); + currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); + downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); + Website := ReadString(IntToStr(i), 'Website', ''); + SaveTo := ReadString(IntToStr(i), 'SaveTo', ''); + Link := ReadString(IntToStr(i), 'Link', ''); + + AddMerge(Title, currentChapter, downloadedChapterList, Website, SaveTo, Link); + end; + end; end; + Sort(SortColumn); + Backup; + finally + fStream.Free; + mergeFile.Free; end; - Sort(SortColumn); - Backup; - SetLength(infos, 0); - fStream.Free; - mergeFile.Free; isRunning := False; end; @@ -897,7 +881,7 @@ procedure TFavoriteManager.Remove(const pos: Integer; const isBackup: Boolean); begin CS_Favorites.Acquire; try - FavoriteItem(pos).Free; + TFavoriteContainer(FFavorites[pos]).Free; FFavorites.Delete(pos); if isBackup then Backup; @@ -918,17 +902,16 @@ procedure TFavoriteManager.Restore; FFavorites.Add(TFavoriteContainer.Create); with TFavoriteContainer(FFavorites.Last) do begin Manager := Self; - FavoriteInfo.Title := favoritesFile.ReadString(IntToStr(i), 'Title', ''); - FavoriteInfo.currentChapter := - favoritesFile.ReadString(IntToStr(i), 'CurrentChapter', '0'); - FavoriteInfo.downloadedChapterList := - favoritesFile.ReadString(IntToStr(i), 'DownloadedChapterList', ''); - FavoriteInfo.website := favoritesFile.ReadString(IntToStr(i), 'Website', ''); - FavoriteInfo.SaveTo := - CorrectPathSys(favoritesFile.ReadString(IntToStr(i), 'SaveTo', '')); - FavoriteInfo.link := favoritesFile.ReadString(IntToStr(i), 'Link', ''); - Website := FavoriteInfo.Website; - Status := STATUS_IDLE; + with favoritesFile, FavoriteInfo do begin + Title := ReadString(IntToStr(i), 'Title', ''); + currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); + downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); + Website := ReadString(IntToStr(i), 'Website', ''); + SaveTo := CorrectPathSys(ReadString(IntToStr(i), 'SaveTo', '')); + Link := ReadString(IntToStr(i), 'Link', ''); + Website := Website; + Status := STATUS_IDLE; + end; end; end; end; @@ -937,29 +920,28 @@ procedure TFavoriteManager.Backup; var i: Integer; begin - // delete old info - if favoritesFile.ReadInteger('general', 'NumberOfFavorites', 0) > 0 then - for i := 0 to favoritesFile.ReadInteger('general', 'NumberOfFavorites', 0) - 1 do - favoritesFile.EraseSection(IntToStr(i)); - - favoritesFile.WriteInteger('general', 'NumberOfFavorites', FFavorites.Count); - if FFavorites.Count > 0 then - for i := 0 to FFavorites.Count - 1 do - begin - favoritesFile.WriteString(IntToStr(i), 'Title', FavoriteItem(i).FavoriteInfo.Title); - favoritesFile.WriteString(IntToStr(i), 'CurrentChapter', - FavoriteItem(i).FavoriteInfo.currentChapter); - favoritesFile.WriteString(IntToStr(i), 'DownloadedChapterList', - FavoriteItem(i).FavoriteInfo.downloadedChapterList); - favoritesFile.WriteString(IntToStr(i), 'Website', FavoriteItem(i).FavoriteInfo.Website); - favoritesFile.WriteString(IntToStr(i), 'SaveTo', FavoriteItem(i).FavoriteInfo.SaveTo); - favoritesFile.WriteString(IntToStr(i), 'Link', FavoriteItem(i).FavoriteInfo.link); - end; - favoritesFile.UpdateFile; + with favoritesFile do begin + // delete old info + if ReadInteger('general', 'NumberOfFavorites', 0) > 0 then + for i := 0 to ReadInteger('general', 'NumberOfFavorites', 0) - 1 do + EraseSection(IntToStr(i)); + + WriteInteger('general', 'NumberOfFavorites', FFavorites.Count); + if FFavorites.Count > 0 then + for i := 0 to FFavorites.Count - 1 do + with TFavoriteContainer(FFavorites[i]).FavoriteInfo do begin + WriteString(IntToStr(i), 'Title', Title); + WriteString(IntToStr(i), 'CurrentChapter', currentChapter); + WriteString(IntToStr(i), 'DownloadedChapterList', downloadedChapterList); + WriteString(IntToStr(i), 'Website', Website); + WriteString(IntToStr(i), 'SaveTo', SaveTo); + WriteString(IntToStr(i), 'Link', Link); + end; + UpdateFile; + end; end; -procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, ALink, - AValue: String); +procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); var st: TStringList; begin @@ -975,31 +957,30 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, ALink, end; end; -procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, - Alink: String; AValue: TStrings); +procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: String; AValue: TStrings); var i, p, q: Integer; Ch, dlCh: TStringList; begin if Count = 0 then Exit; - if (AWebsite <> '') and (Alink <> '') and (AValue.Count > 0) then + if (AWebsite <> '') and (Alink <> '') and (AValue.Count > 0) then begin - CS_Favorites.Acquire; Ch := TStringList.Create; dlCh := TStringList.Create; + CS_Favorites.Acquire; try p := -1; //locate the link if FFavorites.Count > 1 then for i := 0 to FFavorites.Count - 1 do - if SameText(AWebsite, FavoriteItem(i).FavoriteInfo.Website) and - SameText(Alink, FavoriteItem(i).FavoriteInfo.Link) then - begin - p := i; - GetParams(dlCh, FavoriteItem(i).FavoriteInfo.downloadedChapterList); - Break; - end; + with TFavoriteContainer(FFavorites[i]).FavoriteInfo do + if SameText(AWebsite, Website) and SameText(Alink, Link) then + begin + p := i; + GetParams(dlCh, downloadedChapterList); + Break; + end; //if found the FavoriteItem if p > -1 then @@ -1011,26 +992,24 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, dlCh.Sort; i := 0; while i < Ch.Count do - begin if dlCh.Find(Ch[i], q) then Ch.Delete(i) else Inc(i); - end; end; //merge the links - with FavoriteItem(p).FavoriteInfo do begin + with TFavoriteContainer(FFavorites[p]).FavoriteInfo do begin downloadedChapterList := downloadedChapterList + SetParams(ch); currentChapter := IntToStr(dlCh.Count + ch.Count); end; MainForm.UpdateVtFavorites; end; finally - dlCh.Free; - Ch.Free; CS_Favorites.Release; end; + dlCh.Free; + Ch.Free; end; end; @@ -1038,12 +1017,13 @@ procedure TFavoriteManager.Sort(const AColumn: Integer); function GetStr(ARow: Pointer): String; begin - case AColumn of - 1: Result := TFavoriteContainer(ARow).FavoriteInfo.Title; - 2: Result := TFavoriteContainer(ARow).FavoriteInfo.currentChapter; - 3: Result := TFavoriteContainer(ARow).FavoriteInfo.website; - 4: Result := TFavoriteContainer(ARow).FavoriteInfo.SaveTo; - end; + with TFavoriteContainer(ARow).FavoriteInfo do + case AColumn of + 1: Result := Title; + 2: Result := currentChapter; + 3: Result := website; + 4: Result := SaveTo; + end; end; function Compare(Item1, Item2: Pointer): Integer; @@ -1061,40 +1041,40 @@ procedure TFavoriteManager.Sort(const AColumn: Integer); procedure QSort(FList: TFPList; L, R: Integer); var - I, J : Longint; - P, Q : Pointer; + I, J: longint; + P, Q: Pointer; begin - repeat - I := L; - J := R; - P := FList[ (L + R) div 2 ]; - repeat - while Compare(P, FList[i]) > 0 do - I := I + 1; - while Compare(P, FList[J]) < 0 do - J := J - 1; - If I <= J then - begin - Q := FList[I]; - Flist[I] := FList[J]; - FList[J] := Q; - I := I + 1; - J := J - 1; - end; - until I > J; - if J - L < R - I then - begin - if L < J then - QSort(FList, L, J); - L := I; - end - else - begin - if I < R then - QSort(FList, I, R); - R := J; - end; - until L >= R; + repeat + I := L; + J := R; + P := FList[(L + R) div 2]; + repeat + while Compare(P, FList[i]) > 0 do + I := I + 1; + while Compare(P, FList[J]) < 0 do + J := J - 1; + if I <= J then + begin + Q := FList[I]; + Flist[I] := FList[J]; + FList[J] := Q; + I := I + 1; + J := J - 1; + end; + until I > J; + if J - L < R - I then + begin + if L < J then + QSort(FList, L, J); + L := I; + end + else + begin + if I < R then + QSort(FList, I, R); + R := J; + end; + until L >= R; end; begin From 89585db432a6ffabc1351ac9d3573d309d17a834 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 19:54:56 +0800 Subject: [PATCH 0500/2794] umisc, set inline for naturalsortcomparestr --- baseunits/uMisc.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index d06bf9ed9..564554dc5 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -53,7 +53,7 @@ function FindStrLinearPos(aList: TStrings; aValue: String): Integer; function FormatByteSize(const bytes :longint; persecond: boolean = False) :string; //sorting -function NaturalCompareStr(Str1, Str2: string): integer; +function NaturalCompareStr(Str1, Str2: string): integer; inline; //run external process function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean = True; From 7fc9580abad43e1a78f1553147e2b44b00eb1533 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 19:55:29 +0800 Subject: [PATCH 0501/2794] favoritemanager, clean up sort method --- baseunits/uFavoritesManager.pas | 66 ++++++++------------------------- 1 file changed, 15 insertions(+), 51 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 7d9a5002c..694c05856 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -1013,76 +1013,40 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St end; end; -procedure TFavoriteManager.Sort(const AColumn: Integer); +function CompareFavoriteContainer(Item1, Item2: Pointer): Integer; function GetStr(ARow: Pointer): String; begin with TFavoriteContainer(ARow).FavoriteInfo do - case AColumn of + case TFavoriteContainer(ARow).Manager.SortColumn of 1: Result := Title; 2: Result := currentChapter; 3: Result := website; 4: Result := SaveTo; + else + Result := ''; end; end; - function Compare(Item1, Item2: Pointer): Integer; - var - ItemT: Pointer; - begin - if SortDirection then - begin - ItemT := Item1; - Item1 := Item2; - Item2 := ItemT; - end; - Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); - end; - - procedure QSort(FList: TFPList; L, R: Integer); - var - I, J: longint; - P, Q: Pointer; +var + ItemT: Pointer; +begin + if TFavoriteContainer(Item1).Manager.SortDirection then begin - repeat - I := L; - J := R; - P := FList[(L + R) div 2]; - repeat - while Compare(P, FList[i]) > 0 do - I := I + 1; - while Compare(P, FList[J]) < 0 do - J := J - 1; - if I <= J then - begin - Q := FList[I]; - Flist[I] := FList[J]; - FList[J] := Q; - I := I + 1; - J := J - 1; - end; - until I > J; - if J - L < R - I then - begin - if L < J then - QSort(FList, L, J); - L := I; - end - else - begin - if I < R then - QSort(FList, I, R); - R := J; - end; - until L >= R; + ItemT := Item1; + Item1 := Item2; + Item2 := ItemT; end; + Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); +end; +procedure TFavoriteManager.Sort(const AColumn: Integer); begin if FFavorites.Count < 2 then Exit; CS_Favorites.Acquire; try SortColumn := AColumn; - QSort(FFavorites, 0, FFavorites.Count - 1); + FFavorites.Sort(CompareFavoriteContainer); finally CS_Favorites.Release; end; From b7ad5bd725e56905a0f43c2b6345a991a9348567 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 20:27:13 +0800 Subject: [PATCH 0502/2794] downloadmanager, clean up sort method --- baseunits/uDownloadsManager.pas | 93 ++++++++++----------------------- 1 file changed, 27 insertions(+), 66 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 49bc7664c..8c0f3e8c9 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2313,92 +2313,53 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea end; end; -procedure TDownloadManager.Sort(const AColumn: Integer); +function CompareTaskContainer(Item1, Item2: Pointer): Integer; function GetStr(ARow: Pointer): String; begin - case AColumn of - 0: Result := TTaskContainer(ARow).DownloadInfo.title; - 1: Result := TTaskContainer(ARow).DownloadInfo.Status; - 2: Result := TTaskContainer(ARow).DownloadInfo.Progress; - 3: Result := TTaskContainer(ARow).DownloadInfo.TransferRate; - 4: Result := TTaskContainer(ARow).DownloadInfo.Website; - 5: Result := TTaskContainer(ARow).DownloadInfo.SaveTo; - 6: Result := FloatToStr(TTaskContainer(ARow).DownloadInfo.dateTime, FMDFormatSettings); - end; + with TTaskContainer(ARow).DownloadInfo do + case TTaskContainer(ARow).Manager.SortColumn of + 0: Result := Title; + 1: Result := Status; + 2: Result := Progress; + 3: Result := TransferRate; + 4: Result := Website; + 5: Result := SaveTo; + else + Result := ''; + end; end; - function GetAddedDate(ARow: Pointer): TDateTime; + function GetDateTime(ARow: Pointer): TDateTime; begin Result := TTaskContainer(ARow).DownloadInfo.DateTime; end; - function Compare(Item1, Item2: Pointer): Integer; - var - ItemT: Pointer; - begin - if SortDirection then - begin - ItemT := Item1; - Item1 := Item2; - Item2 := ItemT; - end; - case AColumn of - 6 : Result := CompareDateTime(GetAddedDate(Item1), GetAddedDate(Item2)); - else - Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); - end; - end; - - procedure QSort(FList: TFPList; L, R: Integer); - var - I, J : Longint; - P, Q : Pointer; +var + ItemT: Pointer; +begin + if TTaskContainer(Item1).Manager.SortDirection then begin - repeat - I := L; - J := R; - P := FList[ (L + R) div 2 ]; - repeat - while Compare(P, FList[i]) > 0 do - I := I + 1; - while Compare(P, FList[J]) < 0 do - J := J - 1; - If I <= J then - begin - Q := FList[I]; - Flist[I] := FList[J]; - FList[J] := Q; - I := I + 1; - J := J - 1; - end; - until I > J; - if J - L < R - I then - begin - if L < J then - QSort(FList, L, J); - L := I; - end - else - begin - if I < R then - QSort(FList, I, R); - R := J; - end; - until L >= R; + ItemT := Item1; + Item1 := Item2; + Item2 := ItemT; end; + if TTaskContainer(Item1).Manager.SortColumn = 6 then + Result := CompareDateTime(GetDateTime(Item1), GetDateTime(Item2)) + else + Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); +end; +procedure TDownloadManager.Sort(const AColumn: Integer); begin if Containers.Count < 2 then Exit; CS_DownloadManager_Task.Acquire; try SortColumn := AColumn; - QSort(Containers, 0, Containers.Count - 1); + Containers.Sort(CompareTaskContainer); finally CS_DownloadManager_Task.Release; end; - MainForm.vtDownload.Repaint; - MainForm.vtDownloadFilters; end; end. From 6367c1d96a8d4cd4da76737ec0274ab0dc8fb9a9 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 20:33:19 +0800 Subject: [PATCH 0503/2794] clean up --- mangadownloader/forms/frmMain.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fa62cd8ce..dca466544 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1938,7 +1938,6 @@ procedure TMainForm.btUpdateListClick(Sender: TObject); i: Cardinal; {$ENDIF} begin - CloseNow; {$IFDEF SELFUPDATE} pmUpdate.Items[0].Enabled := True; pmUpdate.Items[3].Enabled := True; From 32dceb89f7c3396667165f3a288c4370f4b340fe Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 10 Aug 2015 20:39:55 +0800 Subject: [PATCH 0504/2794] Bump version 0.9.21.5 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3045ab4ee..f954710da 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,12 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.5 (10-08-2015) +[*] Fix remove multiple task +[*] Fix timer auto check favorites on interval not enabled if auto check new version not enabled +[*] Fix auto download new chapters in favorites always failed +[*] Various changes and bug fixes + 0.9.21.4 (10-08-2015) [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index a32f3c5ee..b7f6a7288 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index eb898a55a..44cc2cf32 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.4 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.4/fmd_0.9.21.4.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.4/fmd_0.9.21.4_Win64.7z +VERSION=0.9.21.5 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.5/fmd_0.9.21.5.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.5/fmd_0.9.21.5_Win64.7z From 2e4ec0c21e7bd97eb59617fcf2a509f212a956c6 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 05:53:48 +0800 Subject: [PATCH 0505/2794] websitemodules add ontaskstart --- baseunits/WebsiteModules.pas | 41 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index b1edb1237..d76767d54 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -28,6 +28,7 @@ TModuleContainer = class; TOnGetInfo = function(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; + TOnTaskStart = function(var Task: TTaskContainer; Module: TModuleContainer): Boolean; TOnGetPageNumber = function(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; TOnGetImageURL = function(var DownloadThread: TDownloadThread; @@ -37,7 +38,7 @@ TModuleContainer = class; const URL, Path, Name, Prefix: String; Module: TModuleContainer): Boolean; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, - MMGetPageNumber, MMGetImageURL, MMDownloadImage); + MMTaskStart, MMGetPageNumber, MMGetImageURL, MMDownloadImage); { TModuleContainer } @@ -60,6 +61,7 @@ TModuleContainer = class OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; OnGetNameAndLink: TOnGetNameAndLink; OnGetInfo: TOnGetInfo; + OnTaskStart: TOnTaskStart; OnGetPageNumber: TOnGetPageNumber; OnGetImageURL: TOnGetImageURL; OnDownloadImage: TOnDownloadImage; @@ -90,9 +92,11 @@ TWebsiteModules = class function LocateModule(const Website: String): Integer; function LocateModuleByHost(const Host: String): Integer; function ModuleAvailable(const ModuleId: Integer; - ModuleMethod: TModuleMethod): Boolean; overload; + ModuleMethod: TModuleMethod): Boolean; + overload; function ModuleAvailable(const Website: String; - ModuleMethod: TModuleMethod): Boolean; overload; + ModuleMethod: TModuleMethod): Boolean; + overload; function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; overload; function ModuleAvailable(const Website: String): Boolean; overload; @@ -116,15 +120,22 @@ TWebsiteModules = class function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Integer; const Website: String): Integer; overload; + function TaskStart(var Task: TTaskContainer; const ModuleId: Integer): Boolean; + overload; + function TaskStart(var Task: TTaskContainer; const Website: String): Boolean; + overload; + function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; const ModuleId: Integer): Boolean; overload; function GetPageNumber(var DownloadThread: TDownloadThread; - const URL, Website: String): Boolean; overload; + const URL, Website: String): Boolean; + overload; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; const ModuleId: Integer): Boolean; overload; function GetImageURL(var DownloadThread: TDownloadThread; - const URL, Website: String): Boolean; overload; + const URL, Website: String): Boolean; + overload; function DownloadImage(var DownloadThread: TDownloadThread; const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; @@ -265,7 +276,6 @@ function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; Break; end; if Result = -1 then - begin with TRegExpr.Create do try Expression := REGEX_HOST; @@ -279,7 +289,6 @@ function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; finally Free; end; - end; end; end; @@ -289,7 +298,6 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do - begin case ModuleMethod of MMGetDirectoryPageNumber: Result := Assigned(OnGetDirectoryPageNumber); MMGetNameAndLink: Result := Assigned(OnGetNameAndLink); @@ -300,7 +308,6 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; else Result := False; end; - end; end; function TWebsiteModules.ModuleAvailable(const Website: String; @@ -377,6 +384,22 @@ function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; Result := GetInfo(MangaInfo, URL, Reconnect, LocateModule(Website)); end; +function TWebsiteModules.TaskStart(var Task: TTaskContainer; + const ModuleId: Integer): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnTaskStart) then + Result := TModuleContainer(FModuleList[ModuleId]).OnTaskStart( + Task, TModuleContainer(FModuleList[ModuleId])); +end; + +function TWebsiteModules.TaskStart(var Task: TTaskContainer; + const Website: String): Boolean; +begin + TaskStart(Task, LocateModule(Website)); +end; + function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; const ModuleId: Integer): Boolean; begin From 66b61763282bef2911b6434d383f005bfbe40bfc Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:05:01 +0800 Subject: [PATCH 0506/2794] downloadmanager, add modules.taskstart at starting task --- baseunits/uDownloadsManager.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8c0f3e8c9..4ece009cd 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1415,6 +1415,8 @@ procedure TTaskThread.Execute; //if no total page number found, we reset pagelinks here if container.MangaSiteID = SUBMANGA_ID then container.PageLinks.Clear; + if ModuleId > -1 then + Modules.TaskStart(container, ModuleId); // Get page number. if container.PageLinks.Count = 0 then From deed6c57a51fbd11365203bccf6d6ce6fc1392a3 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:05:23 +0800 Subject: [PATCH 0507/2794] doujin.moe, reset image url, has timeout --- baseunits/modules/Doujinmoeus.pas | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index a06de7db7..0ae591074 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -25,7 +25,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Source: TStringList; Parser: TTreeParser; s: String; - v:IXQValue; + v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; @@ -73,7 +73,6 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Source := TStringList.Create; try if MangaInfo.GetPage(TObject(Source), info.url, Reconnect) then - begin if Source.Count > 0 then begin Result := NO_ERROR; @@ -105,12 +104,19 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end else Result := INFORMATION_NOT_FOUND; - end; finally Source.Free; end; end; +function TaskStart(var Task: TTaskContainer; Module: TModuleContainer): Boolean; +begin + Result := True; + if Task = nil then Exit; + Task.PageLinks.Clear; + Task.PageNumber := 0; +end; + function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var @@ -129,7 +135,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; try if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), Container.Manager.retryConnect) then - begin if Source.Count > 0 then begin Result := True; @@ -142,7 +147,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Parser.Free; end; end; - end; finally Source.Free; end; @@ -159,6 +163,7 @@ procedure RegisterModule; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; + OnTaskStart := @TaskStart; OnGetPageNumber := @GetPageNumber; end; end; From db42f45bb2f77e5eee386f058ca90109c0c51737 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:08:18 +0800 Subject: [PATCH 0508/2794] remove backup at every downloadmanager operation, too many IO --- baseunits/uFavoritesManager.pas | 1 - baseunits/uSilentThread.pas | 1 - mangadownloader/forms/frmMain.pas | 5 ----- 3 files changed, 7 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 694c05856..0bd4296c3 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -717,7 +717,6 @@ procedure TFavoriteManager.ShowResult; Inc(counter); end; Backup; - DLManager.Backup; if Assigned(OnUpdateDownload) then OnUpdateDownload; if LNCResult = ncrDownload then diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index e45aea6c8..325e484d3 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -377,7 +377,6 @@ procedure TSilentThread.MainThreadAfterChecking; DLManager.TaskItem(p).downloadInfo.SaveTo := FSavePath; UpdateVtDownload; - DLManager.Backup; DLManager.CheckAndActiveTask(False); // save downloaded chapters diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index dca466544..1a161ee38 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1459,7 +1459,6 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); end; DLManager.CheckAndActiveTask; UpdateVtDownload; - DLManager.Backup; end; procedure TMainForm.miDownloadMergeCompletedClick(Sender: TObject); @@ -1827,7 +1826,6 @@ procedure TMainForm.btDownloadClick(Sender: TObject); DLManager.TaskItem(pos).DownloadInfo.SaveTo := s; UpdateVtDownload; - DLManager.Backup; DLManager.CheckAndActiveTask; DLManager.AddToDownloadedChaptersList( mangaInfo.website + mangaInfo.link, DLManager.TaskItem(pos).ChapterLinks); @@ -2774,7 +2772,6 @@ procedure TMainForm.miDownloadDeleteCompletedClick(Sender: TObject); Exit; DLManager.RemoveAllFinishedTasks; UpdateVtDownload; - DLManager.Backup; // the reason we put it in here instead of in DLManager because of the size of // download list will change during this method end; @@ -2790,7 +2787,6 @@ procedure TMainForm.miDownloadResumeClick(Sender: TObject); xNode := vtDownload.GetNextSelected(xNode); end; DLManager.CheckAndActiveTask(); - DLManager.Backup; UpdateVtDownload; end; end; @@ -2806,7 +2802,6 @@ procedure TMainForm.miDownloadStopClick(Sender: TObject); xNode := vtDownload.GetNextSelected(xNode); end; DLManager.CheckAndActiveTask(); - DLManager.Backup; UpdateVtDownload; end; end; From 79f0b54c7e21e13179b6f00a46ef627e57cd467c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:14:38 +0800 Subject: [PATCH 0509/2794] favoritemanager, assign favoriteinfo.website fix #94 --- baseunits/uFavoritesManager.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 0bd4296c3..141e113bc 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -163,6 +163,7 @@ procedure TFavoriteContainer.SetWebsite(AValue: String); begin if FWebsite = AValue then Exit; FWebsite := AValue; + FavoriteInfo.Website := AValue; FModuleId := Modules.LocateModule(FavoriteInfo.Website); end; From 0c2e968e6cb9d4396ddaeeda9149f7b528abf024 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:16:25 +0800 Subject: [PATCH 0510/2794] favoritemanager, don't need to set website again --- baseunits/uFavoritesManager.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 141e113bc..db4fa0821 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -820,7 +820,6 @@ procedure TFavoriteManager.AddMerge(const ATitle, ACurrentChapter, ADownloadedCh with FavoriteInfo do begin Title := ATitle; CurrentChapter := ACurrentChapter; - Website := AWebsite; SaveTo := ASaveTo; Link := ALink; DownloadedChapterList := ADownloadedChapterList; From e6fe2f6077453139d04d6d22f08359812c77aeef Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:21:34 +0800 Subject: [PATCH 0511/2794] mainform, set minimum autheck favorites to 1 minutes, enabled/disabled via checkbox only --- mangadownloader/forms/frmMain.lfm | 2 ++ mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 1743cc17a..96fd42b74 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2619,8 +2619,10 @@ object MainForm: TMainForm Top = 56 Width = 58 MaxValue = 1440 + MinValue = 1 OnChange = seOptionAutoCheckFavIntervalMinutesChange TabOrder = 0 + Value = 1 end object lbOptionAutoCheckFavIntervalMinutes: TLabel Left = 82 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1a161ee38..326e22438 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4633,7 +4633,7 @@ procedure TMainForm.ApplyOptions; OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; itCheckFav.Interval := OptionAutoCheckFavIntervalMinutes * 60000; - itCheckFav.Enabled := OptionAutoCheckFavInterval and (itCheckFav.Interval > 0); + itCheckFav.Enabled := OptionAutoCheckFavInterval; //misc OptionBatotoShowScanGroup := cbOptionBatotoShowScanGroup.Checked; From a6adb77bf95f541e60195b18f2a94f08d954b1f5 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:37:08 +0800 Subject: [PATCH 0512/2794] mainform, validate checkbox genres dynamicall --- mangadownloader/forms/frmMain.pas | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 326e22438..fa2a6c2a2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2372,14 +2372,16 @@ procedure TMainForm.btFilterClick(Sender: TObject); Inc(i); end; end; - for i := 0 to 37 do - begin - if TCheckBox(pnGenres.Controls[i]).State = cbChecked then - checkGenres.Add(TCheckBox(pnGenres.Controls[i]).Caption) - else - if TCheckBox(pnGenres.Controls[i]).State = cbUnchecked then - uncheckGenres.Add(TCheckBox(pnGenres.Controls[i]).Caption); - end; + + if pnGenres.ControlCount > 0 then + for i := 0 to pnGenres.ControlCount - 1 do + if pnGenres.Controls[i] is TCheckBox then begin + if TCheckBox(pnGenres.Controls[i]).State = cbChecked then + checkGenres.Add(TCheckBox(pnGenres.Controls[i]).Caption) + else + if TCheckBox(pnGenres.Controls[i]).State = cbUnchecked then + uncheckGenres.Add(TCheckBox(pnGenres.Controls[i]).Caption); + end; if dataProcess.CanFilter( checkGenres, From d98ac773bd5b2804b51a8f9f306b0133a3a1801c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:50:42 +0800 Subject: [PATCH 0513/2794] baseunit, clean up trimstrings function --- baseunits/uBaseUnit.pas | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e06110a8e..7f36fd974 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1960,15 +1960,10 @@ procedure TrimStrings(const Str : TStringList); if Str.Count > 0 then begin i := 0; - while i < Str.Count do - begin - if Trim(Str[i]) = '' then - Str.Delete(i) - else - begin - Str[i] := Trim(Str[i]); - Inc(i); - end; + while i < Str.Count do begin + Str[i] := Trim(Str[i]); + if Str[i] = '' then Str.Delete(i) + else Inc(i); end; end; end; From a755f157892a833a09d352093ffd31c0467c3291 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 06:54:30 +0800 Subject: [PATCH 0514/2794] mainform, filter genres, don't treat whitespace as separator fix #93 --- mangadownloader/forms/frmMain.pas | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fa2a6c2a2..602f2a109 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2348,28 +2348,22 @@ procedure TMainForm.btFilterClick(Sender: TObject); checkGenres := TStringList.Create; uncheckGenres := TStringList.Create; try - if cbUseRegExpr.Checked and (Trim(edCustomGenres.Text) <> '') then - checkGenres.Add(Trim(edCustomGenres.Text)) + edCustomGenres.Text := Trim(edCustomGenres.Text); + if cbUseRegExpr.Checked and (edCustomGenres.Text <> '') then + checkGenres.Add(edCustomGenres.Text) else begin - checkGenres.Delimiter := ','; - checkGenres.DelimitedText := edCustomGenres.Text; + ExtractStrings([','], [], PChar(edCustomGenres.Text), checkGenres); TrimStrings(checkGenres); i := 0; - while i < checkGenres.Count do - begin - s := checkGenres.Strings[i]; - if (s[1] = '-') or (s[1] = '!') then - begin - if (s[1] = '-') then - s := StringReplace(s, '-', '', []) - else - s := StringReplace(s, '!', '', []); + while i < checkGenres.Count do begin + s := Trim(checkGenres.Strings[i]); + if (s <> '') and (s[1] = '-') or (s[1] = '!') then begin + Delete(s, 1, 1); uncheckGenres.Add(s); checkGenres.Delete(i); end - else - Inc(i); + else Inc(i); end; end; From 8d296cede3a88a849e23ef87cd0f8991aae8dde2 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 07:01:14 +0800 Subject: [PATCH 0515/2794] mainform, custom genres, update hint to reflect the actual code --- mangadownloader/forms/frmMain.lfm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 96fd42b74..9bbed75e5 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1594,7 +1594,7 @@ object MainForm: TMainForm object lbFilterHint: TLabel Left = 555 Height = 15 - Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''''!'''' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' + Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' Top = 13 Width = 13 Caption = '[?]' From d8a8621b56ea6b5bc938e43bdefc36faa2dd78b4 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 07:04:23 +0800 Subject: [PATCH 0516/2794] update translations --- mangadownloader/languages/fmd.en.po | 14 ++++++++++++-- mangadownloader/languages/fmd.id_ID.po | 4 ++-- mangadownloader/languages/fmd.po | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index b645e99d6..5ffd27fb7 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -948,6 +948,16 @@ msgid "[?]" msgstr "[?]" #: tmainform.lbfilterhint.hint +#| msgid "" +#| "Genres:\n" +#| "- Checked: Include this genre.\n" +#| "- Unchecked: Exclude this genre.\n" +#| "- Grayed: Doesn't matter.\n" +#| "\n" +#| "Custom Genres:\n" +#| "- Separate multiple genres with ','.\n" +#| "- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.\n" +#| "- Example: Adventure,!Ecchi,Comedy.\n" msgid "" "Genres:\n" "- Checked: Include this genre.\n" @@ -956,7 +966,7 @@ msgid "" "\n" "Custom Genres:\n" "- Separate multiple genres with ','.\n" -"- Exclude a genre by placing ''!'' at the beginning of a genre.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" msgstr "" "Genres:\n" @@ -966,7 +976,7 @@ msgstr "" "\n" "Custom Genres:\n" "- Separate multiple genres with ','.\n" -"- Exclude a genre by placing ''!'' at the beginning of a genre.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" #: tmainform.lbfilterstatus.caption diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 987281719..45152b62d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -943,7 +943,7 @@ msgid "" "\n" "Custom Genres:\n" "- Separate multiple genres with ','.\n" -"- Exclude a genre by placing ''!'' at the beginning of a genre.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" msgstr "" "Genre: \n" @@ -953,7 +953,7 @@ msgstr "" "\n" "Genre pilihan: \n" "- Pisahkan beberapa genre dengan ','. \n" -"- Kecualikan genre dengan menempatkan ''!'' pada permulaan genre. \n" +"- Kecualikan genre dengan menempatkan '!' atau '-' pada permulaan genre. \n" "- Contoh: petualangan,! Ecchi, komedi.\n" #: tmainform.lbfilterstatus.caption diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 2a54235ba..93942c78a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -913,7 +913,7 @@ msgid "" "\n" "Custom Genres:\n" "- Separate multiple genres with ','.\n" -"- Exclude a genre by placing ''!'' at the beginning of a genre.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" msgstr "" From ede77fe9b100b8e7f215b7c42e11237348bf13ea Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 07:19:47 +0800 Subject: [PATCH 0517/2794] misc, set inline for short method --- baseunits/uMisc.pas | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index 564554dc5..a4a853387 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -29,13 +29,13 @@ TIniFileR = class(TMemIniFile) //String utils procedure padZero(var S: String; VolLength, ChapLength: Integer); -function padZeros(const S: String; VolLength, ChapLength: Integer): String; -function BrackText(const S: String): String; overload; -function BrackText(const S: Integer): String; overload; -function BrackSquareText(const S: String): String; overload; -function BrackSquareText(const S: Integer): String; overload; -function BrackTextQuoted(const S: String): String; overload; -function BrackTextQuoted(const S: Integer): String; overload; +function padZeros(const S: String; VolLength, ChapLength: Integer): String; inline; +function BrackText(const S: String): String; overload; inline; +function BrackText(const S: Integer): String; overload; inline; +function BrackSquareText(const S: String): String; overload; inline; +function BrackSquareText(const S: Integer): String; overload; inline; +function BrackTextQuoted(const S: String): String; overload; inline; +function BrackTextQuoted(const S: Integer): String; overload; inline; function StringToASCII(S: String): String; function StringToHex(S: String): String; From 69671c57ff72dd4e823c87467ba1d4a402e7f937 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 07:20:09 +0800 Subject: [PATCH 0518/2794] simplelogger, set inline for short method --- baseunits/SimpleException/USimpleLogger.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index 735b382e4..eedb5f158 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -41,12 +41,12 @@ interface _LOG_SYMBOL = 'EWIDV'; procedure SetLogFile(const LogFileName: String); - procedure WriteLog_E(const msg: String); overload; + procedure WriteLog_E(const msg: String); overload; inline; procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject = nil); overload; - procedure Writelog_W(const msg: String); - procedure Writelog_I(const msg: String); - procedure Writelog_D(const msg: String); - procedure Writelog_V(const msg: String); + procedure Writelog_W(const msg: String); inline; + procedure Writelog_I(const msg: String); inline; + procedure Writelog_D(const msg: String); inline; + procedure Writelog_V(const msg: String); inline; function SimpleBackTraceStr(const Addr: Pointer): String; function GetStackTraceInfo(const MaxStackCount: Integer = 20): string; From 72015517bd12b14ae70b29351cc6c432316c1479 Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 07:21:28 +0800 Subject: [PATCH 0519/2794] Bump version 0.9.21.6 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index f954710da..62b73dfe3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,12 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.6 (11-08-2015) +[*] Doujin-Mode: reset image url every task start, fix expired url +[*] Fix empty website when adding a favorite +[*] Fix filter custom genres incorrectly treats whitespaces as separator +[*] Various changes + 0.9.21.5 (10-08-2015) [*] Fix remove multiple task [*] Fix timer auto check favorites on interval not enabled if auto check new version not enabled diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b7f6a7288..0a3135535 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ - + diff --git a/update b/update index 44cc2cf32..2b9272d47 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.5 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.5/fmd_0.9.21.5.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.5/fmd_0.9.21.5_Win64.7z +VERSION=0.9.21.6 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.6/fmd_0.9.21.6.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.6/fmd_0.9.21.6_Win64.7z From 9f74b78a178ba5d4138b79717b6070095a93caff Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 16:55:48 +0800 Subject: [PATCH 0520/2794] missing whitespaces :smile: --- updater/uMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 624066410..9e30afeec 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -215,7 +215,7 @@ procedure TDownloadThread.MainThreadUpdateProgress; prgText: string; begin if Terminated then Exit; - if FCurrentSize > 0then + if FCurrentSize > 0 then begin if FTotalSize > 0 then begin From 7279bd40b4688b9e3ce57346a25d81d83d0d766c Mon Sep 17 00:00:00 2001 From: riderkick Date: Tue, 11 Aug 2015 17:17:43 +0800 Subject: [PATCH 0521/2794] mainform, clean up delete favorites method --- mangadownloader/forms/frmMain.pas | 46 ++++++++----------------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 602f2a109..99127efbc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2470,50 +2470,26 @@ procedure TMainForm.miMangaListAddToFavoritesClick(Sender: TObject); procedure TMainForm.miFavoritesDeleteClick(Sender: TObject); var - i: Cardinal; xNode: PVirtualNode; - delList: array of Cardinal; begin - if (cbOptionShowDeleteTaskDialog.Checked) and (vtFavorites.SelectedCount > 0) then - if MessageDlg('', RS_DlgRemoveFavorite, - mtConfirmation, [mbYes, mbNo], 0) = mrNo then - Exit; - if FavoriteManager.isRunning then - begin + if vtFavorites.SelectedCount = 0 then Exit; + if FavoriteManager.isRunning then begin MessageDlg('', RS_DlgFavoritesCheckIsRunning, - mtInformation, [mbYes, mbNo], 0); + mtInformation, [mbOK], 0); Exit; end; - if vtFavorites.SelectedCount = 1 then - begin - if not Assigned(vtFavorites.FocusedNode) then + if cbOptionShowDeleteTaskDialog.Checked then + if MessageDlg('', RS_DlgRemoveFavorite, mtConfirmation, [mbYes, mbNo], 0) = mrNo then Exit; - FavoriteManager.Remove(vtFavorites.FocusedNode^.Index); - end - else - begin - xNode := vtFavorites.GetFirst; - SetLength(delList, 0); - i := 0; - while i < FavoriteManager.Count do - begin - if vtFavorites.Selected[xNode] then - begin - SetLength(delList, Length(delList) + 1); - delList[Length(delList) - 1] := i; - end; - Inc(i); - xNode := vtFavorites.GetNext(xNode); - end; - - if Length(delList) > 0 then - for i := Length(delList) - 1 downto 0 do - FavoriteManager.Remove(delList[i], False); - FavoriteManager.Backup; + xNode := vtFavorites.GetLast(); + while Assigned(xNode) do begin + if vtFavorites.Selected[xNode] then + FavoriteManager.Remove(xNode^.Index, False); + xNode := vtFavorites.GetPreviousSelected(xNode); end; + FavoriteManager.Backup; UpdateVtFavorites; - SetLength(delList, 0); end; procedure TMainForm.miFavoritesChangeCurrentChapterClick(Sender: TObject); From c61a55bb14937fae2949452d9ea69b73cb013a5e Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 13 Aug 2015 13:02:17 +0800 Subject: [PATCH 0522/2794] rename some var --- baseunits/uBaseUnit.pas | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7f36fd974..efe59fb47 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -868,7 +868,7 @@ function RandomString(SLength: Integer; ONumber: Boolean = False; function GetValuesFromString(Str: String; Sepr: Char): String; procedure InvertStrings(Const St: TStringList); overload; procedure InvertStrings(const Sts: array of TStringList); overload; -procedure TrimStrings(Const Str: TStringList); +procedure TrimStrings(TheStrings: TStrings); procedure RemoveDuplicateStrings(Strs: Array of TStringList; RemIndex: Cardinal = 0); procedure CleanHTMLComments(Const Str: TStringList); @@ -1953,16 +1953,17 @@ procedure InvertStrings(const Sts: array of TStringList); InvertStrings(Sts[i]); end; -procedure TrimStrings(const Str : TStringList); +procedure TrimStrings(TheStrings: TStrings); var i: Integer; begin - if Str.Count > 0 then + if TheStrings = nil then Exit; + if TheStrings.Count > 0 then begin i := 0; - while i < Str.Count do begin - Str[i] := Trim(Str[i]); - if Str[i] = '' then Str.Delete(i) + while i < TheStrings.Count do begin + TheStrings[i] := Trim(TheStrings[i]); + if TheStrings[i] = '' then TheStrings.Delete(i) else Inc(i); end; end; From c99b1cbe1e652a0f11c010efcb8d6bc09a5ba1b1 Mon Sep 17 00:00:00 2001 From: riderkick Date: Thu, 13 Aug 2015 13:03:24 +0800 Subject: [PATCH 0523/2794] mainform, minor changes --- mangadownloader/forms/frmMain.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 99127efbc..e37a41851 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4636,11 +4636,14 @@ procedure TMainForm.LoadMangaOptions; lang := TStringList.Create; try mangalistIni.ReadSection('available', lang); + TrimStrings(lang); if lang.Count > 0 then for i := 0 to lang.Count - 1 do begin - s := mangalistIni.ReadString('available', lang[i], ''); - ExtractParam(wName, s, ',', False); + s := Trim(mangalistIni.ReadString('available', lang[i], '')); + if s <> '' then + ExtractStrings([','], [], PChar(s), wName); + TrimStrings(wName); while wlang.Count < wName.Count do wLang.Add(lang[i]); end; From 768cbec70eb2df5be5050c23366ef0edffb9dffe Mon Sep 17 00:00:00 2001 From: riderkick Date: Fri, 14 Aug 2015 07:54:20 +0800 Subject: [PATCH 0524/2794] remove mangapanda, mangareader script --- .../MangaPanda/chapter_page_number.inc | 36 ---- baseunits/includes/MangaPanda/image_url.inc | 39 ---- .../includes/MangaPanda/manga_information.inc | 113 ------------ .../includes/MangaPanda/names_and_links.inc | 48 ----- .../MangaReader/chapter_page_number.inc | 33 ---- baseunits/includes/MangaReader/image_url.inc | 78 -------- .../MangaReader/manga_information.inc | 120 ------------ .../includes/MangaReader/names_and_links.inc | 43 ----- baseunits/uBaseUnit.pas | 173 +++++++++--------- baseunits/uData.pas | 20 -- baseunits/uDownloadsManager.pas | 20 -- 11 files changed, 82 insertions(+), 641 deletions(-) delete mode 100644 baseunits/includes/MangaPanda/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaPanda/image_url.inc delete mode 100644 baseunits/includes/MangaPanda/manga_information.inc delete mode 100644 baseunits/includes/MangaPanda/names_and_links.inc delete mode 100644 baseunits/includes/MangaReader/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaReader/image_url.inc delete mode 100644 baseunits/includes/MangaReader/manga_information.inc delete mode 100644 baseunits/includes/MangaReader/names_and_links.inc diff --git a/baseunits/includes/MangaPanda/chapter_page_number.inc b/baseunits/includes/MangaPanda/chapter_page_number.inc deleted file mode 100644 index 68ace6b10..000000000 --- a/baseunits/includes/MangaPanda/chapter_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetMangaPandaPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAPANDA_ID, URL)); - if (Pos('.html', URL) > 0) and (Pos(SEPERATOR2, URL) > 0) then - s := StringReplace(s, SEPERATOR2, '-1/', []); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 1 to parse.Count - 1 do - begin - if (Pos(' of ', parse.Strings[i]) > 0) and - (Pos('select', parse.Strings[i - 1]) > 0) then - begin - s := GetString(parse.Strings[i] + '~!@', ' of ', '~!@'); - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaPanda/image_url.inc b/baseunits/includes/MangaPanda/image_url.inc deleted file mode 100644 index df18cef09..000000000 --- a/baseunits/includes/MangaPanda/image_url.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetMangaPandaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - - if (Pos('.html', URL) > 0) and (Pos(SEPERATOR2, URL) > 0) then - begin - s := DecodeUrl(FillMangaSiteHost(MANGAPANDA_ID, URL)); - s := StringReplace(s, SEPERATOR2, '-' + IntToStr(workCounter + 1) + '/', []); - end - else - s := DecodeUrl(FillMangaSiteHost(MANGAPANDA_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos(' 0) and - (Pos('id="img"', parse[i]) > 0) and - (Pos('name="img"', parse[i]) > 0) then - begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaPanda/manga_information.inc b/baseunits/includes/MangaPanda/manga_information.inc deleted file mode 100644 index f5e9440c8..000000000 --- a/baseunits/includes/MangaPanda/manga_information.inc +++ /dev/null @@ -1,113 +0,0 @@ - function GetMangaPandaInfoFromURL: Byte; - var - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - s: String; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAPANDA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAPANDA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (GetTagName(parse.Strings[i]) = 'img') and - (Pos('div id="mangaimg"', parse.Strings[i - 1]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('div id="readmangasum"', parse.Strings[i]) <> 0) then - begin - j := i + 7; - mangaInfo.title := TrimLeft(StringFilter(GetString(parse.Strings[i + 3], - 'Read ', ' Manga Online'))); - while (j < parse.Count) and (Pos('

', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get title - // if (Pos(', Read ', parse.Strings[i])<>0) AND (mangaInfo.title = '') then - // mangaInfo.title:= TrimLeft(StringFilter(GetString(parse.Strings[i], ', Read ', ' English Scan Online'))); - - if (not isExtractChapter) and - (Pos('Chapter Name', parse.Strings[i]) > 0) and - (Pos('class="leftgap"', parse.Strings[i - 1]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('class="chico_manga"', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse.Strings[i + 3], 'href="', '"'); - if (Pos('.html', s) > 0) and (Pos('-1/', s) > 0) then - s := StringReplace(s, '-1/', SEPERATOR2, []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 4])) + - Trim(parse.Strings[i + 6])); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Author:', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist:', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 4]); - - // get genres - if (Pos('Genre:', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('class="genretags"', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 4 < parse.Count) and (Pos('Status:', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaPanda/names_and_links.inc b/baseunits/includes/MangaPanda/names_and_links.inc deleted file mode 100644 index 0ba213c74..000000000 --- a/baseunits/includes/MangaPanda/names_and_links.inc +++ /dev/null @@ -1,48 +0,0 @@ - function MangaPandaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - isExtractInfo: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAPANDA_ID, 1] + - MANGAPANDA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (not isExtractInfo) and - (Pos('ul class="series_alpha"', parse.Strings[i]) > 0) then - isExtractInfo := True; - if (isExtractInfo) and - (Pos('
  • ', parse.Strings[i]) > 0) and - (Pos(' 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href="')); - s := StringReplace(s, WebsiteRoots[MANGAPANDA_ID, 1], '', []); - links.Add(s); - end - else - if (isExtractInfo) and - (Pos('div id="wrapper_footer"', parse.Strings[i]) > 0) then - Break; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/MangaReader/chapter_page_number.inc b/baseunits/includes/MangaReader/chapter_page_number.inc deleted file mode 100644 index d10218e21..000000000 --- a/baseunits/includes/MangaReader/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangaReaderPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAREADER_ID, URL); - Result := GetPage(TObject(l), s, manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('', parse.Strings[i]) > 0) and - (Pos('
  • ', parse.Strings[i + 2]) > 0) then - begin - s := parse.Strings[i + 1]; - Delete(s, Pos(' of ', s), 4); - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaReader/image_url.inc b/baseunits/includes/MangaReader/image_url.inc deleted file mode 100644 index 394f584b3..000000000 --- a/baseunits/includes/MangaReader/image_url.inc +++ /dev/null @@ -1,78 +0,0 @@ - function GetMangaReaderImageURL: Boolean; - var - realURL: String; - i: Integer; - l: TStringList; - - procedure BreakURL; - var - isSlashed: Boolean = False; - j, oldI: Integer; - begin - if Pos('.html', URL) = 0 then - begin - realURL := URL + '/' + IntToStr(workCounter + 1); - Exit; - end; - j := 2; - realURL := '/'; - while j <= Length(URL) do - begin - if (not isSlashed) and (URL[j] = '/') then - begin - isSlashed := True; - oldI := j; - for j := j - 1 downto 1 do - begin - if URL[j] <> '-' then - begin - SetLength(realURL, Length(realURL) - 1); - end - else - begin - realURL := realURL + IntToStr(workCounter + 1); - Break; - end; - end; - j := oldI; - // realURL:= realURL + '/'; - end - else - begin - realURL := realURL + URL[j]; - Inc(j); - end; - end; - end; - - begin - l := TStringList.Create; - BreakURL; - Result := GetPage(TObject(l), FillMangaSiteHost(MANGAREADER_ID, realURL), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - // manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if GetTagName(parse.Strings[i]) = 'img' then - begin - if //(Pos(realURL, parse.Strings[i])>0) AND - (Pos('alt=', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - Break; - end; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaReader/manga_information.inc b/baseunits/includes/MangaReader/manga_information.inc deleted file mode 100644 index 598b18072..000000000 --- a/baseunits/includes/MangaReader/manga_information.inc +++ /dev/null @@ -1,120 +0,0 @@ - function GetMangaReaderInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[MANGAREADER_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAREADER_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('', parse.Strings[i]) > 0) then - mangaInfo.title := TrimLeft(TrimRight(GetString(parse.Strings[i + 1], - ' Manga - Read ', ' Online For '))); - - // get cover - if (GetTagName(parse.Strings[i]) = 'img') and - (Pos('alt=', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('<h2>', parse.Strings[i]) <> 0) and - (Pos('Read ', parse.Strings[i + 1]) <> 0) and - (isExtractSummary) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // allow get chapter name and links - if (Pos('Chapter Name', parse.Strings[i]) > 0) and - (Pos('leftgap', parse.Strings[i - 1]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (i + 1 < parse.Count) and - (isExtractChapter) and - (Pos('<a href=', parse.Strings[i]) > 0) and - (Pos(' : ', parse.Strings[i + 3]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - EncodeUrl(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')))); - parse.Strings[i + 1] := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))) + - RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 3]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(parse.Strings[i + 1]))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Author:', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist:', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 4]); - - // get genres - if (Pos('Genre:', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if Pos('"genretags"', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</tr>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status:', parse.Strings[i]) <> 0) then - begin - if (Pos('Ongoing', parse.Strings[i + 2]) <> 0) or - (Pos('Ongoing', parse.Strings[i + 4]) <> 0) then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaReader/names_and_links.inc b/baseunits/includes/MangaReader/names_and_links.inc deleted file mode 100644 index d46c9b9b4..000000000 --- a/baseunits/includes/MangaReader/names_and_links.inc +++ /dev/null @@ -1,43 +0,0 @@ - function MangaReaderGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAREADER_ID, 1] + - MANGAREADER_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<li>', parse.Strings[i]) > 0) and - (Pos('</a>', parse.Strings[i + 3]) > 0) and - (Length(GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href='))) > - 2) then - begin - Result := NO_ERROR; - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')); - links.Add(s); - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); - end; - if Pos('Network', parse.Strings[i]) > 0 then - Break; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index efe59fb47..aa4b7ca6a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -271,90 +271,88 @@ interface HENTAI2READ_ID = 7; FAKKU_ID = 8; TRUYEN18_ID = 9; - MANGAREADER_ID = 10; - MANGAPARK_ID = 11; - MANGATRADERS_ID = 12; - MANGASTREAM_ID = 13; - MANGAEDEN_ID = 14; - PERVEDEN_ID = 15; - TRUYENTRANHTUAN_ID = 16; - TURKCRAFT_ID = 17; - MANGAVADISI_ID = 18; - MANGAFRAME_ID = 19; - EATMANGA_ID = 20; - STARKANA_ID = 21; - MANGAPANDA_ID = 22; - REDHAWKSCANS_ID = 23; - BLOGTRUYEN_ID = 24; - KOMIKID_ID = 25; - SUBMANGA_ID = 26; - ESMANGAHERE_ID = 27; - ANIMEEXTREMIST_ID = 28; - HUGEMANGA_ID = 29; - S2SCAN_ID = 30; - SENMANGA_ID = 31; - IMANHUA_ID = 32; - MABUNS_ID = 33; - MANGAESTA_ID = 34; - CENTRALDEMANGAS_ID = 35; - EGSCANS_ID = 36; - MANGAAR_ID = 37; - MANGAAE_ID = 38; - ANIMESTORY_ID = 39; - LECTUREENLIGNE_ID = 40; - SCANMANGA_ID = 41; - MANGAGO_ID = 42; - DM5_ID = 43; - PURURIN_ID = 44; - MANGACOW_ID = 45; - KIVMANGA_ID = 46; - MEINMANGA_ID = 47; - MANGASPROJECT_ID = 48; - MANGAREADER_POR_ID = 49; - MANGA2U_ID = 50; - MANGASTREAMTO_ID = 51; - NINEMANGA_ID = 52; - NINEMANGA_ES_ID = 53; - NINEMANGA_CN_ID = 54; - NINEMANGA_RU_ID = 55; - NINEMANGA_DE_ID = 56; - NINEMANGA_IT_ID = 57; - NINEMANGA_BR_ID = 58; - JAPANSHIN_ID = 59; - JAPSCAN_ID = 60; - CENTRUMMANGI_PL_ID = 61; - MANGALIB_PL_ID = 62; - ONEMANGA_ID = 63; - MANGATOWN_ID = 64; - READHENTAIMANGA_ID = 65; - MANGAOKU_ID = 66; - MYREADINGMANGAINFO_ID = 67; - IKOMIK_ID = 68; - NHENTAI_ID = 69; - UNIONMANGAS_ID = 70; - MANGAMINT_ID = 71; - UNIXMANGA_ID = 72; - HAKIHOME_ID = 73; - EXTREMEMANGAS_ID = 74; - MANGAHOST_ID = 75; - PORNCOMIX_ID = 76; - PORNCOMIXRE_ID = 77; - PORNCOMIXIC_ID = 78; - XXCOMICS_ID = 79; - XXCOMICSMT_ID = 80; - XXCOMICS3D_ID = 81; - PORNXXXCOMICS_ID = 82; - MANGASEE_ID = 83; - MANGAKU_ID = 84; - ACADEMYVN_ID = 85; - MANGAAT_ID = 86; - SENMANGARAW_ID = 87; - READMANGATODAY_ID = 88; - LONEMANGA_ID = 89; - DYNASTYSCANS_ID = 90; - MADOKAMI_ID = 91; - - WebsiteRoots: array [0..91] of array [0..1] of string = ( + MANGAPARK_ID = 10; + MANGATRADERS_ID = 11; + MANGASTREAM_ID = 12; + MANGAEDEN_ID = 13; + PERVEDEN_ID = 14; + TRUYENTRANHTUAN_ID = 15; + TURKCRAFT_ID = 16; + MANGAVADISI_ID = 17; + MANGAFRAME_ID = 18; + EATMANGA_ID = 19; + STARKANA_ID = 20; + REDHAWKSCANS_ID = 21; + BLOGTRUYEN_ID = 22; + KOMIKID_ID = 23; + SUBMANGA_ID = 24; + ESMANGAHERE_ID = 25; + ANIMEEXTREMIST_ID = 26; + HUGEMANGA_ID = 27; + S2SCAN_ID = 28; + SENMANGA_ID = 29; + IMANHUA_ID = 30; + MABUNS_ID = 31; + MANGAESTA_ID = 32; + CENTRALDEMANGAS_ID = 33; + EGSCANS_ID = 34; + MANGAAR_ID = 35; + MANGAAE_ID = 36; + ANIMESTORY_ID = 37; + LECTUREENLIGNE_ID = 38; + SCANMANGA_ID = 39; + MANGAGO_ID = 40; + DM5_ID = 41; + PURURIN_ID = 42; + MANGACOW_ID = 43; + KIVMANGA_ID = 44; + MEINMANGA_ID = 45; + MANGASPROJECT_ID = 46; + MANGAREADER_POR_ID = 47; + MANGA2U_ID = 48; + MANGASTREAMTO_ID = 49; + NINEMANGA_ID = 50; + NINEMANGA_ES_ID = 51; + NINEMANGA_CN_ID = 52; + NINEMANGA_RU_ID = 53; + NINEMANGA_DE_ID = 54; + NINEMANGA_IT_ID = 55; + NINEMANGA_BR_ID = 56; + JAPANSHIN_ID = 57; + JAPSCAN_ID = 58; + CENTRUMMANGI_PL_ID = 59; + MANGALIB_PL_ID = 60; + ONEMANGA_ID = 61; + MANGATOWN_ID = 62; + READHENTAIMANGA_ID = 63; + MANGAOKU_ID = 64; + MYREADINGMANGAINFO_ID = 65; + IKOMIK_ID = 66; + NHENTAI_ID = 67; + UNIONMANGAS_ID = 68; + MANGAMINT_ID = 69; + UNIXMANGA_ID = 70; + HAKIHOME_ID = 71; + EXTREMEMANGAS_ID = 72; + MANGAHOST_ID = 73; + PORNCOMIX_ID = 74; + PORNCOMIXRE_ID = 75; + PORNCOMIXIC_ID = 76; + XXCOMICS_ID = 77; + XXCOMICSMT_ID = 78; + XXCOMICS3D_ID = 79; + PORNXXXCOMICS_ID = 80; + MANGASEE_ID = 81; + MANGAKU_ID = 82; + ACADEMYVN_ID = 83; + MANGAAT_ID = 84; + SENMANGARAW_ID = 85; + READMANGATODAY_ID = 86; + LONEMANGA_ID = 87; + DYNASTYSCANS_ID = 88; + MADOKAMI_ID = 89; + + WebsiteRoots: array [0..89] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -365,7 +363,6 @@ interface ('Hentai2Read', 'http://hentai2read.com'), ('Fakku', 'https://www.fakku.net'), ('Truyen18', 'http://www.truyen18.org'), - ('MangaReader', 'http://www.mangareader.net'), ('MangaPark', 'http://mangapark.me'), ('MangaTraders', 'http://mangatraders.org'), ('MangaStream', 'http://mangastream.com'), @@ -377,7 +374,6 @@ interface ('MangaFrame', 'http://www.mangaframe.com'), ('EatManga', 'http://eatmanga.com'), ('Starkana', 'http://starkana.jp'), - ('MangaPanda', 'http://www.mangapanda.com'), ('RedHawkScans', 'http://manga.redhawkscans.com'), ('BlogTruyen', 'http://blogtruyen.com'), ('Komikid', 'http://www.komikid.com'), @@ -476,8 +472,6 @@ interface TRUYEN18_ROOT = 'http://www.truyen18.org'; TRUYEN18_BROWSER = '/moi-dang/danhsach'; - MANGAREADER_BROWSER = '/alphabetical'; - MANGATRADERS_BROWSER = '/directory/'; MANGASTREAM_ROOT = 'http://mangastream.com'; @@ -502,9 +496,6 @@ interface STARKANA_BROWSER = '/manga/list'; - MANGAPANDA_ROOT = 'http://www.mangapanda.com'; - MANGAPANDA_BROWSER = '/alphabetical'; - REDHAWKSCANS_BROWSER = '/reader/list/'; BLOGTRUYEN_BROWSER = '/danhsach/tatca'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1c40ed71c..2dc7baeff 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2197,8 +2197,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Fakku/names_and_links.inc} - {$I includes/MangaReader/names_and_links.inc} - {$I includes/MangaPark/names_and_links.inc} {$I includes/MangaTraders/names_and_links.inc} @@ -2245,8 +2243,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/EatManga/names_and_links.inc} - {$I includes/MangaPanda/names_and_links.inc} - {$I includes/MangaGo/names_and_links.inc} {$I includes/MangaStream/names_and_links.inc} @@ -2364,9 +2360,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[FAKKU_ID, 0] then Result := FakkuGetNamesAndLinks else - if website = WebsiteRoots[MANGAREADER_ID, 0] then - Result := MangaReaderGetNamesAndLinks - else if website = WebsiteRoots[MANGAPARK_ID, 0] then Result := MangaParkGetNamesAndLinks else @@ -2379,9 +2372,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[EATMANGA_ID, 0] then Result := EatMangaGetNamesAndLinks else - if website = WebsiteRoots[MANGAPANDA_ID, 0] then - Result := MangaPandaGetNamesAndLinks - else if website = WebsiteRoots[MANGAGO_ID, 0] then Result := MangaGoGetNamesAndLinks else @@ -2629,8 +2619,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/Fakku/manga_information.inc} - {$I includes/MangaReader/manga_information.inc} - {$I includes/MangaPark/manga_information.inc} {$I includes/MangaTraders/manga_information.inc} @@ -2649,8 +2637,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/EGScans/manga_information.inc} - {$I includes/MangaPanda/manga_information.inc} - {$I includes/MangaGo/manga_information.inc} {$I includes/TruyenTranhTuan/manga_information.inc} @@ -2805,9 +2791,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[FAKKU_ID, 0] then Result := GetFakkuInfoFromURL else - if website = WebsiteRoots[MANGAREADER_ID, 0] then - Result := GetMangaReaderInfoFromURL - else if website = WebsiteRoots[MANGAPARK_ID, 0] then Result := GetMangaParkInfoFromURL else @@ -2820,9 +2803,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[EATMANGA_ID, 0] then Result := GetEatMangaInfoFromURL else - if website = WebsiteRoots[MANGAPANDA_ID, 0] then - Result := GetMangaPandaInfoFromURL - else if website = WebsiteRoots[MANGAGO_ID, 0] then Result := GetMangaGoInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4ece009cd..10c37fff5 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -407,12 +407,8 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaInn/chapter_page_number.inc} - {$I includes/MangaPanda/chapter_page_number.inc} - {$I includes/MangaPark/chapter_page_number.inc} - {$I includes/MangaReader/chapter_page_number.inc} - {$I includes/MangaStream/chapter_page_number.inc} {$I includes/MangaStreamTo/chapter_page_number.inc} @@ -514,9 +510,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnPageNumber else - if manager.container.MangaSiteID = MANGAREADER_ID then - Result := GetMangaReaderPageNumber - else if manager.container.MangaSiteID = MANGATRADERS_ID then Result := GetMangaTradersPageNumber else @@ -526,9 +519,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaPageNumber else - if manager.container.MangaSiteID = MANGAPANDA_ID then - Result := GetMangaPandaPageNumber - else if manager.container.MangaSiteID = MANGAPARK_ID then Result := GetMangaParkPageNumber else @@ -760,12 +750,8 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaInn/image_url.inc} - {$I includes/MangaPanda/image_url.inc} - //{$I includes/MangaPark/image_url.inc} - {$I includes/MangaReader/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -871,9 +857,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = FAKKU_ID then Result := GetFakkuImageURL else - if manager.container.MangaSiteID = MANGAREADER_ID then - Result := GetMangaReaderImageURL - else //if manager.container.MangaSiteID = MANGAPARK_ID then // Result := GetMangaParkImageURL //else @@ -883,9 +866,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaImageURL else - if manager.container.MangaSiteID = MANGAPANDA_ID then - Result := GetMangaPandaImageURL - else if manager.container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoImageURL else From 6afae9740679250f5ec187f12df8dc9d2993f5f2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 14 Aug 2015 07:58:55 +0800 Subject: [PATCH 0525/2794] rewrite mangapanda/mangareader script --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaReader.pas | 219 ++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaReader.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ddd50b2d9..1a8a89eea 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -7,4 +7,5 @@ uses Mangacan, PecintaKomik, EHentai, - Doujinmoeus; + Doujinmoeus, + MangaReader; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas new file mode 100644 index 000000000..ef462100d --- /dev/null +++ b/baseunits/modules/MangaReader.pas @@ -0,0 +1,219 @@ +unit MangaReader; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +uses + simplehtmltreeparser, xquery, RegExpr; + +const + dirurl = '/alphabetical'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := 1; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Source := TStringList.Create; + try + if GetPage(TObject(Source), Module.RootURL + dirurl, 3) then + begin + Result := INFORMATION_NOT_FOUND; + if Source.Count > 0 then + begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + for v in SelectXPathIX('//ul[@class="series_alpha"]/li/a', Parser) do + begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end; + finally + Parser.Free; + end; + end; + end; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Source: TStringList; + Parser: TTreeParser; + + procedure ScanInfo; + var + v: IXQValue; + s: String; + begin + with MangaInfo.mangaInfo do begin + //cover + coverLink := SelectXPathString('//*[@id="mangaimg"]/img/@src', Parser); + //title + title := SelectXPathString('//*[@id="mangaproperties"]//h2', Parser); + //author + authors := SelectXPathString( + '//*[@id="mangaproperties"]//td[contains(text(),"Author:")]/following-sibling::td', + Parser); + //artist + artists := SelectXPathString( + '//*[@id="mangaproperties"]//td[contains(text(),"Artist:")]/following-sibling::td', + Parser); + //status + s := SelectXPathString( + '//*[@id="mangaproperties"]//td[contains(text(),"Status:")]/following-sibling::td', + Parser); + if s <> '' then begin + s := LowerCase(s); + if Pos('ongoing', s) > 0 then status := '1' + else if Pos('completed', s) > 0 then status := '0'; + end; + //summary + summary := SelectXPathString('//*[@id="readmangasum"]/p', Parser); + //chapters + for v in SelectXPathIX('//table[@id="listing"]/tbody/tr/td[1]/a', Parser) do + chapterLinks.Add(v.toNode.getAttribute('href')); + for v in SelectXPathIX('//table[@id="listing"]/tbody/tr/td[1]', Parser) do + chapterName.Add(v.toString); + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + MangaInfo.mangaInfo.website := Module.Website; + MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + begin + Result := INFORMATION_NOT_FOUND; + if Source.Count > 0 then + begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + ScanInfo; + finally + Parser.Free; + end; + end; + end; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Parser: TTreeParser; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + Source := TStringList.Create; + try + if GetPage(TObject(Source), FillHost(Module.RootURL, URL), + Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + PageNumber := SelectXPathIX( + '//select[@id="pageMenu"]/option', Parser).Count; + finally + Parser.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Parser: TTreeParser; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do begin + Source := TStringList.Create; + try + if GetPage(TObject(Source), AppendURLDelim(FillHost(Module.RootURL, URL)) + + IncStr(DownloadThread.workCounter), Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + PageLinks[DownloadThread.workCounter] := + SelectXPathString('//*[@id="img"]/@src', Parser); + finally + Parser.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +procedure RegisterModule; + + procedure AddWebsiteModule(AWebsite, ARootURL: String); + begin + with AddModule do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + end; + +begin + AddWebsiteModule('MangaReader', 'http://www.mangareader.net'); + AddWebsiteModule('MangaPanda', 'http://www.mangapanda.com'); +end; + +initialization + RegisterModule; + +end. From 5ae91f9d7faff9251d1510c3c96455bdfa3ae539 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 15 Aug 2015 18:15:59 +0800 Subject: [PATCH 0526/2794] mangareader, minor changes --- baseunits/modules/MangaReader.pas | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index ef462100d..8cc82946d 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -33,7 +33,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if MangaInfo = nil then Exit; Source := TStringList.Create; try - if GetPage(TObject(Source), Module.RootURL + dirurl, 3) then + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirurl, 3) then begin Result := INFORMATION_NOT_FOUND; if Source.Count > 0 then @@ -107,7 +107,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); Source := TStringList.Create; try - if GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + if GetPage(MangaInfo.FHTTP, TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then begin Result := INFORMATION_NOT_FOUND; if Source.Count > 0 then @@ -141,7 +141,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; PageNumber := 0; Source := TStringList.Create; try - if GetPage(TObject(Source), FillHost(Module.RootURL, URL), + if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(Module.RootURL, URL), Manager.retryConnect) then if Source.Count > 0 then begin @@ -172,7 +172,8 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; with DownloadThread.manager.container do begin Source := TStringList.Create; try - if GetPage(TObject(Source), AppendURLDelim(FillHost(Module.RootURL, URL)) + + if GetPage(DownloadThread.FHTTP, TObject(Source), + AppendURLDelim(FillHost(Module.RootURL, URL)) + IncStr(DownloadThread.workCounter), Manager.retryConnect) then if Source.Count > 0 then begin @@ -181,7 +182,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; try ParseHTMLTree(Parser, Source.Text); PageLinks[DownloadThread.workCounter] := - SelectXPathString('//*[@id="img"]/@src', Parser); + SelectXPathString('//img[@id="img"]/@src', Parser); finally Parser.Free; end; From b947ab83f86cd03c57e889ab14145c84fdd30732 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 15 Aug 2015 18:17:17 +0800 Subject: [PATCH 0527/2794] minor changes --- baseunits/uData.pas | 2 +- baseunits/uDownloadsManager.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2dc7baeff..db9988172 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -206,7 +206,7 @@ TMangaInformation = class(TObject) const DataProcess: TDBDataProcess); overload; //wrapper function GetPage(var output: TObject; URL: String; - const Reconnect: Integer = 0): Boolean; overload; + const Reconnect: Integer = 0): Boolean; inline; end; var diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 10c37fff5..af4222717 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -58,7 +58,7 @@ TDownloadThread = class(TFMDThread) procedure SockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); function GetPage(var output: TObject; URL: String; - const Reconnect: Integer = 0): Boolean; overload; + const Reconnect: Integer = 0): Boolean; inline; function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; From 51df71ae683779911cb22d4608fb05f0805c35d8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 15 Aug 2015 18:28:28 +0800 Subject: [PATCH 0528/2794] remove mangastream --- .../MangaStream/chapter_page_number.inc | 39 ---- baseunits/includes/MangaStream/image_url.inc | 37 ---- .../MangaStream/manga_information.inc | 65 ------- .../includes/MangaStream/names_and_links.inc | 43 ----- baseunits/uBaseUnit.pas | 169 +++++++++--------- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 10 -- 7 files changed, 81 insertions(+), 292 deletions(-) delete mode 100644 baseunits/includes/MangaStream/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaStream/image_url.inc delete mode 100644 baseunits/includes/MangaStream/manga_information.inc delete mode 100644 baseunits/includes/MangaStream/names_and_links.inc diff --git a/baseunits/includes/MangaStream/chapter_page_number.inc b/baseunits/includes/MangaStream/chapter_page_number.inc deleted file mode 100644 index 8dea08457..000000000 --- a/baseunits/includes/MangaStream/chapter_page_number.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetMangaStreamPageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGASTREAM_ID, URL); - if RightStr(s, 2) = '/1' then - s := ReplaceRegExpr('(/\d+)/1$', s, '$1', True); - Result := GetPage(TObject(l), - s + '/1', - manager.container.manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free - end; - - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - if Pos('Last Page (', parse[i]) > 0 then - begin - manager.container.PageNumber := StrToIntDef(ReplaceRegExpr( - '^.*Last\s*Page\s*\((\d+)\).*$', parse[i], '$1', True), 1); - Break; - end; - end; - - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaStream/image_url.inc b/baseunits/includes/MangaStream/image_url.inc deleted file mode 100644 index d29829c84..000000000 --- a/baseunits/includes/MangaStream/image_url.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetMangaStreamImageURL: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - s := URL; - if Pos('http', LowerCase(s)) <> 1 then - s := MANGASTREAM_ROOT2 + s; - if RightStr(s, 2) = '/1' then - s := ReplaceRegExpr('(/\d+)/1$', s, '$1', True); - s := s + '/' + IntToStr(QWord(workCounter) + 1); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - parse := TStringList.Create; - try - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'manga-page') then - begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaStream/manga_information.inc b/baseunits/includes/MangaStream/manga_information.inc deleted file mode 100644 index 781e2a0f2..000000000 --- a/baseunits/includes/MangaStream/manga_information.inc +++ /dev/null @@ -1,65 +0,0 @@ - function GetMangaStreamInfoFromURL: Byte; - var - i: Integer; - s: String; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGASTREAM_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGASTREAM_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.status := '1'; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if GetTagName(parse[i]) = 'h1' then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //chapters - if (GetTagName(parse[i]) = 'table') and (GetVal(parse[i], 'class') = 'table table-striped') then - isExtractChapter := True; - if isExtractChapter then - begin - if GetTagName(parse[i]) = '/table' then - Break - else - if GetTagName(parse[i]) = 'a' then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterName.Add(parse[i + 1]); - s := GetVal(parse[i], 'href'); - if Pos('http', LowerCase(s)) <> 1 then - s := MANGASTREAM_ROOT2 + s; - if RightStr(s, 2) = '/1' then - s := ReplaceRegExpr('(/\d+)/1$', s, '$1', True); - mangaInfo.chapterLinks.Add(s); - end; - end; - end; - - // invert chapters - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaStream/names_and_links.inc b/baseunits/includes/MangaStream/names_and_links.inc deleted file mode 100644 index d6c2602a9..000000000 --- a/baseunits/includes/MangaStream/names_and_links.inc +++ /dev/null @@ -1,43 +0,0 @@ - function MangaStreamGetNamesAndLinks: Byte; - var - i: Integer; - isExtractNames: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), MANGASTREAM_ROOT + '/manga', 3) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'table') and (GetVal(parse[i], 'class') = 'table table-striped') then - isExtractNames := True; - if isExtractNames then - begin - if GetTagName(parse[i]) = '/table' then - Break - else - if GetTagName(parse[i]) = 'a' then - if GetVal(parse[i], 'class') <> 'chapter-link' then - begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter(parse[i + 1])); - end; - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index aa4b7ca6a..c33bd01f5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -273,86 +273,85 @@ interface TRUYEN18_ID = 9; MANGAPARK_ID = 10; MANGATRADERS_ID = 11; - MANGASTREAM_ID = 12; - MANGAEDEN_ID = 13; - PERVEDEN_ID = 14; - TRUYENTRANHTUAN_ID = 15; - TURKCRAFT_ID = 16; - MANGAVADISI_ID = 17; - MANGAFRAME_ID = 18; - EATMANGA_ID = 19; - STARKANA_ID = 20; - REDHAWKSCANS_ID = 21; - BLOGTRUYEN_ID = 22; - KOMIKID_ID = 23; - SUBMANGA_ID = 24; - ESMANGAHERE_ID = 25; - ANIMEEXTREMIST_ID = 26; - HUGEMANGA_ID = 27; - S2SCAN_ID = 28; - SENMANGA_ID = 29; - IMANHUA_ID = 30; - MABUNS_ID = 31; - MANGAESTA_ID = 32; - CENTRALDEMANGAS_ID = 33; - EGSCANS_ID = 34; - MANGAAR_ID = 35; - MANGAAE_ID = 36; - ANIMESTORY_ID = 37; - LECTUREENLIGNE_ID = 38; - SCANMANGA_ID = 39; - MANGAGO_ID = 40; - DM5_ID = 41; - PURURIN_ID = 42; - MANGACOW_ID = 43; - KIVMANGA_ID = 44; - MEINMANGA_ID = 45; - MANGASPROJECT_ID = 46; - MANGAREADER_POR_ID = 47; - MANGA2U_ID = 48; - MANGASTREAMTO_ID = 49; - NINEMANGA_ID = 50; - NINEMANGA_ES_ID = 51; - NINEMANGA_CN_ID = 52; - NINEMANGA_RU_ID = 53; - NINEMANGA_DE_ID = 54; - NINEMANGA_IT_ID = 55; - NINEMANGA_BR_ID = 56; - JAPANSHIN_ID = 57; - JAPSCAN_ID = 58; - CENTRUMMANGI_PL_ID = 59; - MANGALIB_PL_ID = 60; - ONEMANGA_ID = 61; - MANGATOWN_ID = 62; - READHENTAIMANGA_ID = 63; - MANGAOKU_ID = 64; - MYREADINGMANGAINFO_ID = 65; - IKOMIK_ID = 66; - NHENTAI_ID = 67; - UNIONMANGAS_ID = 68; - MANGAMINT_ID = 69; - UNIXMANGA_ID = 70; - HAKIHOME_ID = 71; - EXTREMEMANGAS_ID = 72; - MANGAHOST_ID = 73; - PORNCOMIX_ID = 74; - PORNCOMIXRE_ID = 75; - PORNCOMIXIC_ID = 76; - XXCOMICS_ID = 77; - XXCOMICSMT_ID = 78; - XXCOMICS3D_ID = 79; - PORNXXXCOMICS_ID = 80; - MANGASEE_ID = 81; - MANGAKU_ID = 82; - ACADEMYVN_ID = 83; - MANGAAT_ID = 84; - SENMANGARAW_ID = 85; - READMANGATODAY_ID = 86; - LONEMANGA_ID = 87; - DYNASTYSCANS_ID = 88; - MADOKAMI_ID = 89; - - WebsiteRoots: array [0..89] of array [0..1] of string = ( + MANGAEDEN_ID = 12; + PERVEDEN_ID = 13; + TRUYENTRANHTUAN_ID = 14; + TURKCRAFT_ID = 15; + MANGAVADISI_ID = 16; + MANGAFRAME_ID = 17; + EATMANGA_ID = 18; + STARKANA_ID = 19; + REDHAWKSCANS_ID = 20; + BLOGTRUYEN_ID = 21; + KOMIKID_ID = 22; + SUBMANGA_ID = 23; + ESMANGAHERE_ID = 24; + ANIMEEXTREMIST_ID = 25; + HUGEMANGA_ID = 26; + S2SCAN_ID = 27; + SENMANGA_ID = 28; + IMANHUA_ID = 29; + MABUNS_ID = 30; + MANGAESTA_ID = 31; + CENTRALDEMANGAS_ID = 32; + EGSCANS_ID = 33; + MANGAAR_ID = 34; + MANGAAE_ID = 35; + ANIMESTORY_ID = 36; + LECTUREENLIGNE_ID = 37; + SCANMANGA_ID = 38; + MANGAGO_ID = 39; + DM5_ID = 40; + PURURIN_ID = 41; + MANGACOW_ID = 42; + KIVMANGA_ID = 43; + MEINMANGA_ID = 44; + MANGASPROJECT_ID = 45; + MANGAREADER_POR_ID = 46; + MANGA2U_ID = 47; + MANGASTREAMTO_ID = 48; + NINEMANGA_ID = 49; + NINEMANGA_ES_ID = 50; + NINEMANGA_CN_ID = 51; + NINEMANGA_RU_ID = 52; + NINEMANGA_DE_ID = 53; + NINEMANGA_IT_ID = 54; + NINEMANGA_BR_ID = 55; + JAPANSHIN_ID = 56; + JAPSCAN_ID = 57; + CENTRUMMANGI_PL_ID = 58; + MANGALIB_PL_ID = 59; + ONEMANGA_ID = 60; + MANGATOWN_ID = 61; + READHENTAIMANGA_ID = 62; + MANGAOKU_ID = 63; + MYREADINGMANGAINFO_ID = 64; + IKOMIK_ID = 65; + NHENTAI_ID = 66; + UNIONMANGAS_ID = 67; + MANGAMINT_ID = 68; + UNIXMANGA_ID = 69; + HAKIHOME_ID = 70; + EXTREMEMANGAS_ID = 71; + MANGAHOST_ID = 72; + PORNCOMIX_ID = 73; + PORNCOMIXRE_ID = 74; + PORNCOMIXIC_ID = 75; + XXCOMICS_ID = 76; + XXCOMICSMT_ID = 77; + XXCOMICS3D_ID = 78; + PORNXXXCOMICS_ID = 79; + MANGASEE_ID = 80; + MANGAKU_ID = 81; + ACADEMYVN_ID = 82; + MANGAAT_ID = 83; + SENMANGARAW_ID = 84; + READMANGATODAY_ID = 85; + LONEMANGA_ID = 86; + DYNASTYSCANS_ID = 87; + MADOKAMI_ID = 88; + + WebsiteRoots: array [0..88] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -365,7 +364,6 @@ interface ('Truyen18', 'http://www.truyen18.org'), ('MangaPark', 'http://mangapark.me'), ('MangaTraders', 'http://mangatraders.org'), - ('MangaStream', 'http://mangastream.com'), ('MangaEden', 'http://www.mangaeden.com'), ('PervEden', 'http://www.perveden.com'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), @@ -474,9 +472,6 @@ interface MANGATRADERS_BROWSER = '/directory/'; - MANGASTREAM_ROOT = 'http://mangastream.com'; - MANGASTREAM_ROOT2 = 'http://readms.com'; - MANGAEDEN_BROWSER_1 = '/en-directory/'; MANGAEDEN_BROWSER_2 = '/it-directory/'; @@ -2102,8 +2097,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, Result := StringReplace(Result, '%AUTHOR%', AAuthor, [rfReplaceAll]); Result := StringReplace(Result, '%ARTIST%', AArtist, [rfReplaceAll]); Result := StringReplace(Result, '%CHAPTER%', chap, [rfReplaceAll]); - if (AWebsite = WebsiteRoots[FAKKU_ID, 0]) or - (AWebsite = WebsiteRoots[MANGASTREAM_ID, 0]) then + if AWebsite = WebsiteRoots[FAKKU_ID, 0] then begin if Pos('%NUMBERING% - ', Result) > 0 then Result := StringReplace(Result, '%NUMBERING% - ', '', [rfReplaceAll]) @@ -2116,8 +2110,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, Result := StringReplace(Result, '\', '', [rfReplaceAll]); if Result = '' then begin - if (AWebsite = WebsiteRoots[FAKKU_ID, 0]) or - (AWebsite = WebsiteRoots[MANGASTREAM_ID, 0]) then + if AWebsite = WebsiteRoots[FAKKU_ID, 0] then Result := chap else Result := ANumbering; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index db9988172..59f4a93f6 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2245,8 +2245,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaGo/names_and_links.inc} - {$I includes/MangaStream/names_and_links.inc} - {$I includes/RedHawkScans/names_and_links.inc} {$I includes/S2Scans/names_and_links.inc} @@ -2375,9 +2373,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[MANGAGO_ID, 0] then Result := MangaGoGetNamesAndLinks else - if website = WebsiteRoots[MANGASTREAM_ID, 0] then - Result := MangaStreamGetNamesAndLinks - else if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then Result := RedHawkScansGetNamesAndLinks else @@ -2623,8 +2618,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaTraders/manga_information.inc} - {$I includes/MangaStream/manga_information.inc} - {$I includes/MangaEden/manga_information.inc} {$I includes/Starkana/manga_information.inc} @@ -2806,9 +2799,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[MANGAGO_ID, 0] then Result := GetMangaGoInfoFromURL else - if website = WebsiteRoots[MANGASTREAM_ID, 0] then - Result := GetMangaStreamInfoFromURL - else if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then Result := GetRedHawkScansInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index af4222717..b9980f35a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -409,8 +409,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaPark/chapter_page_number.inc} - {$I includes/MangaStream/chapter_page_number.inc} - {$I includes/MangaStreamTo/chapter_page_number.inc} {$I includes/MangaTraders/chapter_page_number.inc} @@ -525,9 +523,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoPageNumber else - if manager.container.MangaSiteID = MANGASTREAM_ID then - Result := GetMangaStreamPageNumber - else if manager.container.MangaSiteID = REDHAWKSCANS_ID then Result := GetRedHawkScansPageNumber else @@ -756,8 +751,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangasPROJECT/image_url.inc} - {$I includes/MangaStream/image_url.inc} - {$I includes/MangaStreamTo/image_url.inc} {$I includes/MangaTraders/image_url.inc} @@ -869,9 +862,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoImageURL else - if manager.container.MangaSiteID = MANGASTREAM_ID then - Result := GetMangaStreamImageURL - else if manager.container.MangaSiteID = REDHAWKSCANS_ID then Result := GetRedHawkScansImageURL else From 354a088c502ae74fc7e01afa3dbb0cfc9dc7ccb7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 15 Aug 2015 18:28:38 +0800 Subject: [PATCH 0529/2794] add mangastream module --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaStream.pas | 192 ++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaStream.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 1a8a89eea..982a08b16 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -8,4 +8,5 @@ uses PecintaKomik, EHentai, Doujinmoeus, - MangaReader; + MangaReader, + MangaStream; diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas new file mode 100644 index 000000000..687b19407 --- /dev/null +++ b/baseunits/modules/MangaStream.pas @@ -0,0 +1,192 @@ +unit MangaStream; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +uses + simplehtmltreeparser, xquery, RegExpr; + +const + readURL = 'http://readms.com'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +begin + Page := 1; + Result := NO_ERROR; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/manga', 3) then + begin + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + for v in SelectXPathIX('//table//tr/td[1]//a', Parser) do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end + finally + Parser.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + info: TMangaInfo; + Source: TStringList; + Parser: TTreeParser; + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := FillHost(Module.RootURL, URL); + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + with info do begin + //title + title := SelectXPathString('//h1', Parser); + //chapters + for v in SelectXPathIX('//table//td/a', Parser) do begin + s := v.toNode.getAttribute('href'); + if (Length(s) > 2) and (RightStr(s, 2) = '/1') then + SetLength(s, Length(s) - 2); + chapterLinks.Add(s); + chapterName.Add(v.toString); + end; + //invert chapters + if chapterLinks.Count > 0 then + InvertStrings([chapterLinks, chapterName]); + end; + finally + Parser.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Container: TTaskContainer; + Source: TStringList; + Parser: TTreeParser; + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Source := TStringList.Create; + try + if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(readURL, URL + '/1'), + Container.Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + s := SelectXPathString( + '//div[@class="controls"]/div[2]/ul[@class="dropdown-menu"]/li[last()]/a', + Parser); + if s <> '' then begin + s := ReplaceRegExpr('^.*\((\d+)\).*$', s, '$1', True); + Container.PageNumber := StrToIntDef(s, 0); + end; + finally + Parser.Free; + end; + end; + finally + Source.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Parser: TTreeParser; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do begin + Source := TStringList.Create; + try + if GetPage(DownloadThread.FHTTP, TObject(Source), + AppendURLDelim(FillHost(readURL, URL)) + + IncStr(DownloadThread.workCounter), Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + PageLinks[DownloadThread.workCounter] := + SelectXPathString('//img[@id="manga-page"]/@src', Parser); + finally + Parser.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaStream'; + RootURL := 'http://mangastream.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From e9b286e137ce0366a53925785d30ffb5cd58faa0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 16 Aug 2015 17:12:02 +0800 Subject: [PATCH 0530/2794] baseunit, fix some function --- baseunits/uBaseUnit.pas | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c33bd01f5..ccaa1eec4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1746,26 +1746,18 @@ function RandomString(SLength: Integer; ONumber: Boolean; OSymbol: Boolean; function GetValuesFromString(Str: String; Sepr: Char): String; var - i: Integer; + p: Integer; + s: String; begin Result := ''; - if Str = '' then - Exit; - if Pos(Sepr, Str) > 0 then - begin - for i := 1 to Length(Str) do - if (Str[i] = Sepr) and (i < Length(Str)) then - begin - Result := Copy(Str, i + 1, Length(Str) - i); - Break; - end; - if Result <> '' then - begin - while (Result <> '') and (Result[Length(Result)] in [' ', '"', '''', ';']) do - Delete(Result, Length(Result), 1); - while (Result <> '') and (Result[1] in [' ', '"', '''']) do - Delete(Result, 1, 1); - end; + if Str = '' then Exit; + p := Pos(Sepr, Str); + if p > 0 then + begin + p := p + Length(Sepr); + s := Trim(Copy(Str, p, Length(Str))); + if s <> '' then s := TrimChar(s, ['''', '"', ';', ' ']); + Result := s; end; end; From 05377d8d68edf20682ccc395e58578f5264f376f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 16 Aug 2015 17:12:19 +0800 Subject: [PATCH 0531/2794] minor fix --- baseunits/includes/SenMangaRAW/image_url.inc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/baseunits/includes/SenMangaRAW/image_url.inc b/baseunits/includes/SenMangaRAW/image_url.inc index cede60a50..abe177b85 100644 --- a/baseunits/includes/SenMangaRAW/image_url.inc +++ b/baseunits/includes/SenMangaRAW/image_url.inc @@ -9,26 +9,22 @@ try s := manager.container.ChapterLinks[manager.container.CurrentDownloadChapterPtr] + '/' + IntToStr(QWord(workCounter) + 1); - s := FillMangaSiteHost(SENMANGARAW_ID, s); + s := FillHost(WebsiteRoots[SENMANGARAW_ID, 1], s); if GetPage(TObject(l), s, manager.container.Manager.retryConnect) then begin TURL := ''; if l.Count > 0 then for i := 0 to l.Count - 1 do begin - if Pos('var new_image =', l[i]) <> 0 then - begin - TURL := StringReplace(l[i], 'var new_image = ''', '', [rfIgnoreCase]); - TURL := Trim(TrimChar(TURL, ['''', ';'])); - if (Length(TURL) > 0) and (TURL[1] = '/') then - TURL := WebsiteRoots[SENMANGARAW_ID, 1] + TURL; - Break; - end; + if Pos('var new_image =', l[i]) > 0 then begin + TURL := GetValuesFromString(l[i], '='); + TURL := MaybeFillHost(WebsiteRoots[SENMANGARAW_ID, 1], TURL); + Break; + end; end; Result := (TURL <> ''); FHTTP.Clear; FHTTP.Headers.Values['Referer'] := ' ' + s; - FHTTP.UserAgent := RandomString(10, True) + RandomString(25 + Random(65), True, False, True); end else Result := False; From a5cd16c4e09581f87cbef680939ce7534da51d8c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 16 Aug 2015 17:18:49 +0800 Subject: [PATCH 0532/2794] Bump version 0.9.21.7 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 62b73dfe3..91550cb96 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.7 (16-08-2015) +[*] Various changes and bug fixes + 0.9.21.6 (11-08-2015) [*] Doujin-Mode: reset image url every task start, fix expired url [*] Fix empty website when adding a favorite diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0a3135535..2c2b5e717 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="21"/> - <BuildNr Value="6"/> + <BuildNr Value="7"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 2b9272d47..710ddcc17 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.6 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.6/fmd_0.9.21.6.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.6/fmd_0.9.21.6_Win64.7z +VERSION=0.9.21.7 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.7/fmd_0.9.21.7.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.7/fmd_0.9.21.7_Win64.7z From 972750dafec054ac53e63dadc8e4864ad76dc2ac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 16 Aug 2015 18:13:45 +0800 Subject: [PATCH 0533/2794] updatethread, fix high cpu usage while updating list --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 6b95527c3..e16477708 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -453,7 +453,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; Exit; end; - if ModuleId > -1 then + if Modules.MaxConnectionLimit[ModuleId] > 0 then while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE) else From ff7b9300aa908382ad13a9b50e461e1b704aac37 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 16 Aug 2015 18:14:43 +0800 Subject: [PATCH 0534/2794] updatethread, minor changes --- baseunits/uUpdateThread.pas | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e16477708..53b8f4634 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -421,10 +421,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; begin MainForm.ulTotalPtr := limit; try - while workPtr < limit do - begin - if Terminated then Exit; - + while (not Terminated) and (workPtr < limit) do begin mt := INIAdvanced.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then begin From f2fb843541da14f5b074085aae11bb4183e5229c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 16 Aug 2015 18:29:46 +0800 Subject: [PATCH 0535/2794] Bump version 0.9.21.8 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 91550cb96..9ffc871bf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.21.8 (16-08-2015) +[*] Fix high cpu usage while updating manga list + 0.9.21.7 (16-08-2015) [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2c2b5e717..233ceb775 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="21"/> - <BuildNr Value="7"/> + <BuildNr Value="8"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 710ddcc17..258b20c7a 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.7 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.7/fmd_0.9.21.7.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.7/fmd_0.9.21.7_Win64.7z +VERSION=0.9.21.8 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.8/fmd_0.9.21.8.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.8/fmd_0.9.21.8_Win64.7z From 829e98ef6ab19792af551c76d6847682bdbee2ca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 17 Aug 2015 01:22:50 +0800 Subject: [PATCH 0536/2794] baseunit add uknown_error --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ccaa1eec4..ab1384c38 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -218,6 +218,7 @@ interface OPTION_MANGALIST = 0; OPTION_RECONNECT = 1; + UNKNOWN_ERROR = -1; NO_ERROR = 0; NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; From e6336b74be51479c32f46167266625d0689cfb13 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 17 Aug 2015 01:22:59 +0800 Subject: [PATCH 0537/2794] mangastream, clean up --- baseunits/modules/MangaStream.pas | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 687b19407..75ec24f0e 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -29,23 +29,26 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Parser: TTreeParser; v: IXQValue; begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - if MangaInfo = nil then Exit; Source := TStringList.Create; try if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/manga', 3) then - begin - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - for v in SelectXPathIX('//table//tr/td[1]//a', Parser) do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); - end - finally - Parser.Free; - end; - end; + if Source.Count > 0 then begin + Result := NO_ERROR; + Parser := TTreeParser.Create; + try + ParseHTMLTree(Parser, Source.Text); + for v in SelectXPathIX('//table//tr/td[1]//a', Parser) do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end + finally + Parser.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; finally Source.Free; end; @@ -60,8 +63,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; v: IXQValue; s: String; begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; info.website := Module.Website; info.url := FillHost(Module.RootURL, URL); From 79362ccded116713f0b2df8148369d43defb1f16 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 17 Aug 2015 03:48:56 +0800 Subject: [PATCH 0538/2794] baseunit add class TXQueryEngineHTML for xpath/css selector --- baseunits/uBaseUnit.pas | 80 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ab1384c38..4fe861c38 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -793,6 +793,25 @@ THTTPSendThread = class(THTTPSend) property Timeout: Integer read FTimeout write SetTimeout; end; + { TXQueryEngineHTML } + + TXQueryEngineHTML = class + private + FEngine: TXQueryEngine; + FTreeParser: TTreeParser; + function Eval(Expression: String; isCSS: Boolean = False): IXQValue; + public + constructor Create(HTML: String = ''); + destructor Destroy; override; + procedure ParseTree(HTML: String); + function XPath(Expression: String): IXQValue; inline; + function XPathString(Expression: String): String; inline; + function CSS(Expression: String): IXQValue; inline; + function CSSString(Expression: String): String; inline; + end; + + IXQValue = xquery.IXQValue; + // Get current binary version function GetCurrentBinVersion: String; // Remove Unicode @@ -3564,6 +3583,67 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); dest.chapterLinks.Assign(Source.chapterLinks); end; +{ TXQueryEngineHTML } + +function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean): IXQValue; +begin + Result := xqvalue(); + if Expression = '' then Exit; + try + if isCSS then Result := FEngine.evaluateXPath3(Expression, FTreeParser.getLastTree) + else Result := FEngine.evaluateCSS3(Expression, FTreeParser.getLastTree); + except + end; +end; + +constructor TXQueryEngineHTML.Create(HTML: String); +begin + FEngine := TXQueryEngine.create; + FTreeParser := TTreeParser.Create; + with FTreeParser do begin + parsingModel := pmHTML; + repairMissingStartTags := True; + repairMissingEndTags := True; + trimText := False; + readComments := False; + readProcessingInstructions := False; + autoDetectHTMLEncoding := False; + if HTML <> '' then parseTree(HTML); + end; +end; + +destructor TXQueryEngineHTML.Destroy; +begin + FEngine.Free; + FTreeParser.Free; + inherited Destroy; +end; + +procedure TXQueryEngineHTML.ParseTree(HTML: String); +begin + if HTML <> '' then FTreeParser.parseTree(HTML); +end; + +function TXQueryEngineHTML.XPath(Expression: String): IXQValue; +begin + Result := Eval(Expression); +end; + +function TXQueryEngineHTML.XPathString(Expression: String): String; +begin + Result := Eval(Expression).toString; +end; + +function TXQueryEngineHTML.CSS(Expression: String): IXQValue; +begin + Result := Eval(Expression, True); +end; + +function TXQueryEngineHTML.CSSString(Expression: String): String; +begin + Result := Eval(Expression, True).toString; +end; + { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); From 47cf56e2c57024f9fcaa66fa74f44a5ab9b5ec48 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 17 Aug 2015 04:07:27 +0800 Subject: [PATCH 0539/2794] baseunit, fix eval --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4fe861c38..c35ec6e00 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3590,8 +3590,8 @@ function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean): IXQValue; Result := xqvalue(); if Expression = '' then Exit; try - if isCSS then Result := FEngine.evaluateXPath3(Expression, FTreeParser.getLastTree) - else Result := FEngine.evaluateCSS3(Expression, FTreeParser.getLastTree); + if isCSS then Result := FEngine.evaluateCSS3(Expression, FTreeParser.getLastTree) + else Result := FEngine.evaluateXPath3(Expression, FTreeParser.getLastTree); except end; end; From d1736fa48e47bc7a022b5b76f2291a06478735a2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 17 Aug 2015 05:03:19 +0800 Subject: [PATCH 0540/2794] simplelogger, overload writelog with array --- baseunits/SimpleException/USimpleLogger.pas | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/USimpleLogger.pas index eedb5f158..c363545c7 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/USimpleLogger.pas @@ -40,13 +40,20 @@ interface const _LOG_SYMBOL = 'EWIDV'; + function ArrayToString(Args: array of const): String; procedure SetLogFile(const LogFileName: String); procedure WriteLog_E(const msg: String); overload; inline; + procedure WriteLog_E(msg: array of const); overload; inline; procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject = nil); overload; + procedure WriteLog_E(msg: array of const; Exc: Exception; Sender: TObject = nil); overload; inline; procedure Writelog_W(const msg: String); inline; + procedure WriteLog_W(msg: array of const); overload; inline; procedure Writelog_I(const msg: String); inline; + procedure WriteLog_I(msg: array of const); overload; inline; procedure Writelog_D(const msg: String); inline; + procedure WriteLog_D(msg: array of const); overload; inline; procedure Writelog_V(const msg: String); inline; + procedure WriteLog_V(msg: array of const); overload; inline; function SimpleBackTraceStr(const Addr: Pointer): String; function GetStackTraceInfo(const MaxStackCount: Integer = 20): string; @@ -111,11 +118,52 @@ procedure SetLogFile(const LogFileName: String); end; end; +function VarRecToString(AVarRec: TVarRec): String; +begin + case AVarRec.VType of + vtInteger : Result := IntToStr(AVarRec.VInteger); + vtBoolean : Result := BoolToStr(AVarRec.VBoolean, True); + vtChar : Result := AVarRec.VChar; + vtWideChar : Result := WideString(AVarRec.VWideChar); + vtExtended : Result := FloatToStr(AVarRec.VExtended^); + vtString : Result := AVarRec.VString^; + vtPointer : Result := hexStr(AVarRec.VPointer); + vtPChar : Result := AVarRec.VPChar; + vtObject : Result := AVarRec.VObject.ClassName; + vtClass : Result := AVarRec.VClass.ClassName; + vtPWideChar : Result := AVarRec.VPWideChar; + vtAnsiString : Result := AnsiString(AVarRec.VAnsiString); + vtCurrency : Result := CurrToStr(AVarRec.VCurrency^); + vtVariant : Result := String(AVarRec.VVariant); + vtWideString : Result := WideString(AVarRec.VWideString); + vtInt64 : Result := IntToStr(AVarRec.VInt64^); + vtUnicodeString : Result := UnicodeString(AVarRec.VUnicodeString); + vtQWord : Result := IntToStr(AVarRec.VQWord^); + else + Result := ''; + end; +end; + +function ArrayToString(Args: array of const): String; +var + i: Integer; +begin + Result := ''; + if High(Args) < 0 then Exit; + for i := Low(Args) to High(Args) do + Result += VarRecToString(Args[i]); +end; + procedure WriteLog_E(const msg: String); begin WriteLog(msg, ERROR); end; +procedure WriteLog_E(msg: array of const); +begin + WriteLog(ArrayToString(msg), ERROR); +end; + procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); var s: string; @@ -134,26 +182,51 @@ procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); WriteLog_E(msg + s); end; +procedure WriteLog_E(msg: array of const; Exc: Exception; Sender: TObject); +begin + WriteLog_E(ArrayToString(msg), Exc, Sender); +end; + procedure Writelog_W(const msg: String); begin WriteLog(msg, WARNING); end; +procedure WriteLog_W(msg: array of const); +begin + WriteLog(ArrayToString(msg), WARNING); +end; + procedure Writelog_I(const msg: String); begin WriteLog(msg, INFO); end; +procedure WriteLog_I(msg: array of const); +begin + WriteLog(ArrayToString(msg), INFO); +end; + procedure Writelog_D(const msg: String); begin WriteLog(msg, DEBUG); end; +procedure WriteLog_D(msg: array of const); +begin + WriteLog(ArrayToString(msg), DEBUG); +end; + procedure Writelog_V(const msg: String); begin WriteLog(msg, VERBOSE); end; +procedure WriteLog_V(msg: array of const); +begin + WriteLog(ArrayToString(msg), VERBOSE); +end; + function SimpleBackTraceStr(const Addr: Pointer): String; var func, Source: ShortString; From 562e52c5028172929b70c58fac7332335e197e86 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 00:51:41 +0800 Subject: [PATCH 0541/2794] fix attach detach database #97 --- baseunits/uData.pas | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 59f4a93f6..a516d5261 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -569,13 +569,12 @@ procedure TDBDataProcess.AttachAllSites; var i: Integer; begin - if FConn.Connected and (SitesList.Count > 0) then - begin - RemoveCurrentSite; - if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then - Exit; - DetachAllSites; - FConn.ExecuteDirect('END TRANSACTION'); + RemoveCurrentSite; + if (not FConn.Connected) or (SitesList.Count = 0) then Exit; + if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then Exit; + DetachAllSites; + FConn.ExecuteDirect('END TRANSACTION'); + try for i := 0 to SitesList.Count - 1 do if FileExistsUTF8(DBDataFilePath(SitesList[i])) then begin @@ -583,31 +582,30 @@ procedure TDBDataProcess.AttachAllSites; QuotedStrd(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); FAttachedSites.Add(SitesList[i]); end; - FConn.ExecuteDirect('BEGIN TRANSACTION'); - FAllSitesAttached := FAttachedSites.Count > 0; + except + on E: Exception do + Writelog_E('TDBDataProcess.AttachAllSites.Error!', E, Self) end; + FConn.ExecuteDirect('BEGIN TRANSACTION'); + FAllSitesAttached := FAttachedSites.Count > 0; end; procedure TDBDataProcess.DetachAllSites; begin - if FConn.Connected and FAllSitesAttached then - begin - FConn.ExecuteDirect('END TRANSACTION'); + if (not FConn.Connected) or (FAttachedSites.Count = 0) then Exit; + FConn.ExecuteDirect('END TRANSACTION'); + try repeat - try - FConn.ExecuteDirect('DETACH ' + - QuotedStrd(FAttachedSites[FAttachedSites.Count - 1])); - except - on E: Exception do - Writelog_E('TDBDataProcess.DetachAllSites:' + - FAttachedSites[FAttachedSites.Count - 1], - E, Self); - end; + FConn.ExecuteDirect('DETACH ' + + QuotedStrd(FAttachedSites[FAttachedSites.Count - 1])); FAttachedSites.Delete(FAttachedSites.Count - 1); until FAttachedSites.Count = 0; - FConn.ExecuteDirect('BEGIN TRANSACTION'); - FAllSitesAttached := False; + except + on E: Exception do + Writelog_E('TDBDataProcess.DetachAllSites.Error!', E, Self); end; + FConn.ExecuteDirect('BEGIN TRANSACTION'); + FAllSitesAttached := FAttachedSites.Count > 0; end; function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; From 8cde1973263cdfd3a279376e725953f7a1359b28 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 01:24:20 +0800 Subject: [PATCH 0542/2794] tdbdataprocess, filter, wrap database name in quote #97 --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a516d5261..b0857ea85 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1076,7 +1076,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList SQL.Add('UNION ALL'); SQL.Add('SELECT *, ' + QuotedStrd(FAttachedSites[i]) + ' AS "website" FROM ' + - FAttachedSites[i] + '.' + QuotedStrd(FTableName)); + QuotedStrd(FAttachedSites[i]) + '.' + QuotedStrd(FTableName)); SQL.Add('WHERE'); GenerateSQLFilter; end; From d2c1ca7c9a167d42235b82644e2559e2505b7488 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 01:28:40 +0800 Subject: [PATCH 0543/2794] baseunit, inline some quick function --- baseunits/uBaseUnit.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c35ec6e00..126ed28b4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -866,9 +866,9 @@ function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; // StringUtils -function QuotedStrd(const S: string): string; overload; -function QuotedStrd(const S: Integer): string; overload; -function BracketStr(const S: string): string; +function QuotedStrd(const S: string): string; overload; inline; +function QuotedStrd(const S: Integer): string; overload; inline; +function BracketStr(const S: string): string; inline; function RandomString(SLength: Integer; ONumber: Boolean = False; OSymbol: Boolean = False; OSpace: Boolean = False): string; function GetValuesFromString(Str: String; Sepr: Char): String; From 59aba70eb44f8d0653851b2083e3df973353e677 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 01:38:35 +0800 Subject: [PATCH 0544/2794] tdbdataprocess, try to detach all db without break --- baseunits/uData.pas | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b0857ea85..c0d5da1bd 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -591,18 +591,19 @@ procedure TDBDataProcess.AttachAllSites; end; procedure TDBDataProcess.DetachAllSites; +var + i: Integer; begin if (not FConn.Connected) or (FAttachedSites.Count = 0) then Exit; FConn.ExecuteDirect('END TRANSACTION'); - try - repeat - FConn.ExecuteDirect('DETACH ' + - QuotedStrd(FAttachedSites[FAttachedSites.Count - 1])); - FAttachedSites.Delete(FAttachedSites.Count - 1); - until FAttachedSites.Count = 0; - except - on E: Exception do - Writelog_E('TDBDataProcess.DetachAllSites.Error!', E, Self); + for i := FAttachedSites.Count - 1 downto 0 do begin + try + FConn.ExecuteDirect('DETACH ' + QuotedStrd(FAttachedSites[i])); + FAttachedSites.Delete(i); + except + on E: Exception do + Writelog_E('TDBDataProcess.DetachAllSites.Error!', E, Self); + end; end; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := FAttachedSites.Count > 0; From 668dd24cda10b0907990599b6263ee1091c439ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 01:45:41 +0800 Subject: [PATCH 0545/2794] tdbdataprocess, only attach unattached db --- baseunits/uData.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c0d5da1bd..45f6680bb 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -576,7 +576,8 @@ procedure TDBDataProcess.AttachAllSites; FConn.ExecuteDirect('END TRANSACTION'); try for i := 0 to SitesList.Count - 1 do - if FileExistsUTF8(DBDataFilePath(SitesList[i])) then + if (FAttachedSites.IndexOf(SitesList[i]) = -1) and + (FileExistsUTF8(DBDataFilePath(SitesList[i]))) then begin FConn.ExecuteDirect('ATTACH ' + QuotedStrd(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); From aa4f37b003f28edf6ff6c799937aac77f3d4975b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 03:53:37 +0800 Subject: [PATCH 0546/2794] tdbdataprocess, commit before detach and reset some value on remove filter fix #97 --- baseunits/uData.pas | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 45f6680bb..2d579719b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -594,8 +594,12 @@ procedure TDBDataProcess.AttachAllSites; procedure TDBDataProcess.DetachAllSites; var i: Integer; + queryactive: Boolean; begin if (not FConn.Connected) or (FAttachedSites.Count = 0) then Exit; + queryactive := FQuery.Active; + if FQuery.Active then FQuery.Close; + FTrans.Commit; FConn.ExecuteDirect('END TRANSACTION'); for i := FAttachedSites.Count - 1 downto 0 do begin try @@ -608,6 +612,7 @@ procedure TDBDataProcess.DetachAllSites; end; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := FAttachedSites.Count > 0; + if FQuery.Active <> queryactive then FQuery.Active := queryactive; end; function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; @@ -902,7 +907,7 @@ procedure TDBDataProcess.Commit; if FConn.Connected then try queryactive := FQuery.Active; - FQuery.Close; + if FQuery.Active then FQuery.Close; FTrans.Commit; if FQuery.Active <> queryactive then FQuery.Active := queryactive; @@ -1160,6 +1165,8 @@ procedure TDBDataProcess.RemoveFilter; FFiltered := False; FFilterApplied := False; FFilterSQL := ''; + FQuery.SQL.Text := FSQLSelect; + FRecordCount := 0; DetachAllSites; if FQuery.Active then begin From 9b29efd6aa8d54f3c0f9e47ffdd206bfa9e12e69 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 04:03:30 +0800 Subject: [PATCH 0547/2794] tdbdataprocess, getvalue, validate params --- baseunits/uData.pas | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2d579719b..bb957ce79 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -537,17 +537,15 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; Result := '0' else Result := ''; - if FQuery.Active and - (FieldIndex < Length(DBDataProcessParams)) and - (RecIndex < FRecordCount) then - begin - try - FQuery.RecNo := RecIndex + 1; - Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; - except - on E: Exception do - WriteLog_E('TDBDataProcess.GetParam.Error!', E, Self); - end; + if not FQuery.Active then Exit; + if FieldIndex >= Length(DBDataProcessParams) then Exit; + if (RecIndex < 0) and (RecIndex > FRecordCount) then Exit; + try + FQuery.RecNo := RecIndex + 1; + Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; + except + on E: Exception do + WriteLog_E('TDBDataProcess.GetParam.Error!', E, Self); end; end; From 68722af6b59217c8f13a9bd2ca0f9d45219bd2bb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 07:14:56 +0800 Subject: [PATCH 0548/2794] rewrite all wp-manga script --- baseunits/modules/WPManga.pas | 553 +++++++++++----------------------- 1 file changed, 177 insertions(+), 376 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index c3563d36b..851527a93 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -5,462 +5,263 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, RegExpr, strutils; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; implementation +uses + RegExpr, synautil; + const dirURL = '/manga-list/all/any/last-added/'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - begin - for i := Parse.Count - 1 downto 0 do - if Pos(dirURL, Parse[i]) <> 0 then - begin - Page := StrToIntDef(ReplaceRegExpr('^.*' + dirURL + '(\d+)/$', - GetVal(Parse[i], 'href'), '$1', True), 1); - Break; - end; - end; - + Source: TStringList; + Query: TXQueryEngineHTML; + s: String; begin - Result := NET_PROBLEM; Page := 1; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL, 3) then + if Source.Count > 0 then begin Result := NO_ERROR; - ScanParse; - end; - end; + Query := TXQueryEngineHTML.Create(Source.Text); + try + s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); + s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); + Page := StrToIntDef(s, 1); + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; finally - Parse.Free; + Source.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanNamesEyeOnManga; - var - i: Integer; - begin - for i := 0 to parse.Count - 1 do - if GetVal(parse[i], 'class') = 'cvr' then - try - if GetTagName(parse[i - 4]) = 'a' then - begin - names.Add(CommonStringFilter(parse[i - 3])); - links.Add(GetVal(parse[i - 4], 'href')); - end; - except - end; - end; - - procedure ScanNamesWPManga; - var - i, j, k: Integer; - s: String; - begin - for i := 0 to parse.Count - 1 do - begin - //thumbnail mode - if GetVal(parse[i], 'id') = 'sct_content' then - begin - for j := i + 1 to parse.Count - 1 do - begin - s := GetTagName(parse[j]); - if (s = 'sct_sidebar') or (s = 'sct_wid_bot') then - Break - else - if GetVal(parse[j], 'class') = 'det' then - begin - for k := j + 1 to parse.Count - 1 do - begin - if GetTagName(parse[k]) = 'a' then - begin - links.Add(GetVal(parse[k], 'href')); - names.Add(CommonStringFilter(parse[k + 1])); - Break; - end; - end; - end; - end; - Break; - end; - end; - end; - + Source: TStringList; + Query: TXQueryEngineHTML; + v: IXQValue; + i: Integer; begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; + Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL + + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL + IncStr(URL) + '/', 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + if Source.Count > 0 then begin Result := NO_ERROR; - if Module.Website = 'EyeOnManga' then - ScanNamesEyeOnManga - else - ScanNamesWPManga; - end; - end; + Query := TXQueryEngineHTML.Create(Source.Text); + try + if (Module.Website = 'EyeOnManga') or + (Module.Website = 'MangaBoom') then + v := Query.XPath('//*[@id="sct_content"]//h2/a[1]') + else + v := Query.XPath('//*[@id="sct_content"]//div[@class="det"]/a[1]'); + if v.Count > 0 then + for i := 0 to v.Count - 1 do begin + Links.Add(v.get(i).toNode.getAttribute('href')); + Names.Add(v.get(i).toString); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; finally - Parse.Free; + Source.Free; end; end; function GetInfo(var MangaInfo: TMangaInformation; const URL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - Parse: TStringList; + Source: TStringList; + Query: TXQueryEngineHTML; info: TMangaInfo; - isInvertChapters: Boolean; + v: IXQValue; + s: String; + i, pagecount: Integer; - procedure ScanChapters; - var - i, j: Integer; - s: String; - StartFindPage: Boolean; + procedure scanchapters; begin - StartFindPage := False; - for i := 0 to parse.Count - 1 do - begin - if not StartFindPage then - begin - s := LowerCase(GetVal(parse[i], 'class')); - if (GetTagName(parse[i]) = 'ul') and - (AnsiIndexText(s, ['lst', 'chp_lst']) > -1) then - begin - StartFindPage := True; - if s = 'chp_lst' then - isInvertChapters := False; - end; - end - else - begin - if GetTagName(parse[i]) = '/ul' then - Break - else - if GetTagName(parse[i]) = 'a' then - begin - if Pos('class="c4', parse[i]) = 0 then - begin - s := ''; - for j := i + 1 to parse.Count - 1 do - begin - s := Trim(parse[j]); - if (s <> '') and (Pos('<', s) <> 1) then - Break; - end; - info.chapterLinks.Add(GetVal(parse[i], 'href')); - info.chapterName.Add(CommonStringFilter(s)); - end; - end; + if Module.Website = 'MangaBoom' then begin + for v in Query.XPath('//ul[@class="lst"]//a[1]') do begin + info.chapterLinks.Add(v.toNode.getAttribute('href')); + info.chapterName.Add(v.toNode.Next.toString()); + end; + end + else if module.Website = 'EyeOnManga' then begin + for v in Query.XPath('//ul[@class="chp_lst"]//a[1]') do begin + info.chapterLinks.Add(v.toNode.getAttribute('href')); + info.chapterName.Add(v.toString); end; + end + else begin + for v in Query.XPath('//ul[@class="lst"]//a[1]/@href') do + info.chapterLinks.Add(v.toString); + for v in Query.XPath('//ul[@class="lst"]//a[1]/b[1]') do + info.chapterName.Add(v.toString); end; end; - procedure ScanParse; - var - i, j, pnumber: Integer; - s: String; - isInfo: Boolean; - isSummaryDone: Boolean; + procedure scaninfo; begin - info.genres := ''; - info.summary := ''; - isInvertChapters := True; - isInfo := False; - isSummaryDone := False; - for i := 0 to parse.Count - 1 do - begin - //cover - if info.coverLink = '' then - begin - if (Pos('<img ', parse[i]) <> 0) and - (Pos('class="cvr', parse[i]) <> 0) then - info.coverLink := GetVal(parse[i], 'src'); - end; - - //title - if info.title = '' then - begin - if (Pos('class="ttl"', parse[i]) <> 0) or - (Pos('itemprop="itemreviewed"', parse[i]) <> 0) then - info.title := CommonStringFilter(parse[i + 1]); - end; - - //details - s := GetVal(parse[i], 'class'); - if (GetTagName(parse[i]) = 'div') and - (AnsiIndexText(s, ['det', 'lts_chp fr', 'mng_ifo']) > -1) then - isInfo := True; - if isInfo then - begin - if GetTagName(parse[i]) = 'h2' then - isInfo := False - else - begin - s := Trim(parse[i]); - //author - if s = 'Author' then - info.authors := CommonStringFilter( - TrimLeftChar(parse[i + 2], [':', ' '])) - else - if Pos('/author/', s) <> 0 then - info.authors := CommonStringFilter(parse[i + 1]) - //artist - else - if s = 'Artist' then - info.artists := CommonStringFilter( - TrimLeftChar(parse[i + 2], [':', ' '])) - //status - else - if s = 'Status' then - begin - if Pos('completed', LowerCase(parse[i + 2])) <> 0 then - info.status := '0' - else - info.status := '1'; - end - //genres - else - if (s = 'Category') or (s = 'Genres') then - begin - for j := i + 3 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - AddCommaString(info.genres, CommonStringFilter(parse[j])); - end; - end - else - if s = 'Type' then - AddCommaString(info.genres, - CommonStringFilter(TrimLeftChar(parse[i + 2], [':', ' ']))) - else - //summary - if (not isSummaryDone) and (s = 'Summary') then - begin - isSummaryDone := True; - for j := i + 2 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - info.summary := Trim(info.summary + LineEnding + - CommonStringFilter(parse[j])); - end; - end; - //summary - if (not isSummaryDone) and (GetTagName(parse[i]) = 'p') then - begin - s := Trim(parse[i + 1]); - if (s <> '') and (Pos('<', s) = 0) then - begin - isSummaryDone := True; - for j := i + 1 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - info.summary := Trim(info.summary + LineEnding + - CommonStringFilter(parse[j])); - end; - end; - end; - end; - end; - end; - - //chapters - ScanChapters; - pnumber := 1; - for i := parse.Count - 1 downto 0 do - begin - if (Pos('<a', parse[i]) <> 0) and - (Pos('/chapter-list/', parse[i]) <> 0) then - begin - s := GetVal(parse[i], 'href'); - pnumber := StrToIntDef( - ReplaceRegExpr('^.*/chapter-list/(\d+)/$', s, '$1', True), 1); - Break; - end; - end; - if pnumber > 1 then - begin - for i := 2 to pnumber do - begin - if MangaInfo.GetPage(TObject(Parse), - info.url + 'chapter-list/' + IntToStr(i) + '/', Reconnect) then - begin - ParseHTML(Parse.Text, parse); - if Parse.Count > 0 then - ScanChapters; - end; + with info, Query do begin + coverLink := XPathString('//img[starts-with(@class,"cvr")]/@src'); + title := Query.XPathString('//*[@itemprop="itemreviewed"]'); + if Module.Website = 'EyeOnManga' then + summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]') + else + summary := XPathString('//*[@class="det"]/p[1]'); + authors := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Author")]'); + artists := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Artist")]'); + genres := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Category")]'); + status := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Status")]'); + if summary <> '' then summary := + TrimChar(SeparateRight(summary, 'Summary'), [':', ' ']); + if authors <> '' then authors := + TrimChar(SeparateRight(authors, 'Author'), [':', ' ']); + if artists <> '' then artists := + TrimChar(SeparateRight(artists, 'Artist'), [':', ' ']); + if genres <> '' then genres := + TrimChar(SeparateRight(genres, 'Category'), [':', ' ']); + if status <> '' then begin + status := LowerCase(status); + if Pos('ongoing', status) > 0 then status := '1' + else if Pos('completed', status) > 0 then status := '0' + else status := ''; end; + scanchapters; end; - - //invert chapters - if isInvertChapters then - InvertStrings([info.chapterName, info.chapterLinks]); end; begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); - Parse := TStringList.Create; + info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + Source := TStringList.Create; try - if Length(info.url) > 0 then - if RightStr(info.url, 1) <> '/' then - info.url += '/'; - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if Source.Count > 0 then begin Result := NO_ERROR; - ScanParse; - end; - end; + Query := TXQueryEngineHTML.Create(Source.Text); + try + scaninfo; + s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); + if s <> '' then begin + s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); + pagecount := StrToIntDef(s, 1); + if pagecount > 1 then + for i := 2 to pagecount do + if GetPage(MangaInfo.FHTTP, TObject(Source), + info.url + 'chapter-list/' + IntToStr(i) + '/', + Reconnect) then + begin + Query.ParseTree(Source.Text); + scanchapters; + end; + end; + if Module.Website <> 'EyeOnManga' then + InvertStrings([info.chapterLinks, info.chapterName]); + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; finally - Parse.Free; + Source.Free; end; end; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; + Source: TStringList; + Query: TXQueryEngineHTML; Container: TTaskContainer; - s: String; - - procedure ScanParse; - var - i, j: Integer; - s: String; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(parse[i]) = 'select') and - (Pos('cbo_wpm_pag', Parse[i]) <> 0) then - begin - for j := i + 1 to parse.Count - 1 do - begin - s := GetTagName(parse[j]); - if s = '/select' then - Break - else - if s = 'option' then - Inc(Container.PageNumber); - end; - Break; - end; - end; - begin Result := False; if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - s := FillHost(Module.RootURL, URL); - if Length(s) > 0 then - if RightStr(s, 1) <> '/' then - s += '/'; - s += '1/'; - if DownloadThread.GetPage(TObject(Parse), s, Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; + with Container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + Source := TStringList.Create; + try + if GetPage(DownloadThread.FHTTP, TObject(Source), + AppendURLDelim(FillHost(Module.RootURL, URL)) + '1', + Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + PageNumber := + Query.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; + finally + Query.Free; + end; + end; + finally + Source.Free; end; - finally - Parse.Free; end; end; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; + Source: TStringList; + Query: TXQueryEngineHTML; Container: TTaskContainer; - s: String; - - procedure ScanParse; - var - i, j: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetVal(Parse[i], 'class') = 'wpm_pag mng_rdr') then - begin - for j := i + 1 to Parse.Count - 1 do - if GetTagName(Parse[j]) = 'img' then - begin - Container.PageLinks[DownloadThread.WorkCounter] := GetVal(Parse[j], 'src'); - Break; - end; - Break; - end; - end; - begin Result := False; if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; - Parse := TStringList.Create; - try - s := FillHost(Module.RootURL, URL); - if Length(s) > 0 then - if RightStr(s, 1) <> '/' then - s += '/'; - s += IntToStr(DownloadThread.workCounter + 1) + '/'; - if DownloadThread.GetPage(TObject(Parse), s, Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then + with Container do begin + Source := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Source), + AppendURLDelim(FillHost(Module.RootURL, URL)) + + IncStr(DownloadThread.workCounter) + '/', + Manager.retryConnect) then begin - Result := True; - ScanParse; + ParseHTML(Source.Text, Source); + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + Container.PageLinks[DownloadThread.WorkCounter] := + Query.XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); + finally + Query.Free; + end; + end; end; + finally + Source.Free; end; - finally - Parse.Free; end; end; From e6b1756983598fad14744d4da7853658cd9f684e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 07:24:51 +0800 Subject: [PATCH 0549/2794] tdbdataprocess, reset filterstatus on db open and removefilter --- baseunits/uData.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index bb957ce79..b2abfb132 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -644,6 +644,8 @@ constructor TDBDataProcess.Create; FTableName := 'masterlist'; FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FRecordCount := 0; + FFiltered := False; + FFilterAllSites := False; FFilterApplied := False; FFilterSQL := ''; FAllSitesAttached := False; @@ -1113,6 +1115,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList FQuery.Close; SQL.Text := tsql; FQuery.Open; + FFilterAllSites := False; FFiltered := False; FFilterApplied := False; FFilterSQL := ''; @@ -1160,6 +1163,7 @@ procedure TDBDataProcess.RemoveFilter; begin if FFiltered then begin + FFilterAllSites := False; FFiltered := False; FFilterApplied := False; FFilterSQL := ''; From 661486a9f43d874d505d9e15c79ad3eade37fc52 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 07:53:08 +0800 Subject: [PATCH 0550/2794] wp-manga, minor changes --- baseunits/modules/WPManga.pas | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 851527a93..1896bd4fa 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -53,7 +53,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Source: TStringList; Query: TXQueryEngineHTML; v: IXQValue; - i: Integer; + s: String; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; @@ -68,14 +68,13 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; try if (Module.Website = 'EyeOnManga') or (Module.Website = 'MangaBoom') then - v := Query.XPath('//*[@id="sct_content"]//h2/a[1]') + s := '//*[@id="sct_content"]//h2/a[1]' else - v := Query.XPath('//*[@id="sct_content"]//div[@class="det"]/a[1]'); - if v.Count > 0 then - for i := 0 to v.Count - 1 do begin - Links.Add(v.get(i).toNode.getAttribute('href')); - Names.Add(v.get(i).toString); - end; + s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; + for v in Query.XPath(s) do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end; finally Query.Free; end; From 33410ec40063d95142216aadd9cfbf78c6c72ce6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 08:01:37 +0800 Subject: [PATCH 0551/2794] rename function --- baseunits/modules/WPManga.pas | 2 +- baseunits/uBaseUnit.pas | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 1896bd4fa..8795b0fcd 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -174,7 +174,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.url + 'chapter-list/' + IntToStr(i) + '/', Reconnect) then begin - Query.ParseTree(Source.Text); + Query.ParseHTML(Source.Text); scanchapters; end; end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 126ed28b4..6ae596260 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -803,7 +803,7 @@ TXQueryEngineHTML = class public constructor Create(HTML: String = ''); destructor Destroy; override; - procedure ParseTree(HTML: String); + procedure ParseHTML(HTML: String); function XPath(Expression: String): IXQValue; inline; function XPathString(Expression: String): String; inline; function CSS(Expression: String): IXQValue; inline; @@ -3619,7 +3619,7 @@ destructor TXQueryEngineHTML.Destroy; inherited Destroy; end; -procedure TXQueryEngineHTML.ParseTree(HTML: String); +procedure TXQueryEngineHTML.ParseHTML(HTML: String); begin if HTML <> '' then FTreeParser.parseTree(HTML); end; From a59e02a7982ca3e1e7e38620974618ce931e1e0a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 08:56:34 +0800 Subject: [PATCH 0552/2794] baseunit, inline some quick function --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6ae596260..335298ca8 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -911,7 +911,7 @@ function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): procedure AddCommaString(var Dest: string; S: string); function IncStr(const S: String; N: Integer = 1): String; overload; -function IncStr(const I: Integer; N: Integer = 1): String; overload; +function IncStr(const I: Integer; N: Integer = 1): String; overload; inline; //get heaader value from THTTPSend.Headers function GetHeaderValue(const AHeaders: TStrings; HName: String): String; From df2f936baef727765d24ccc681ad386976c41959 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 08:58:13 +0800 Subject: [PATCH 0553/2794] wp-manga, clean up and add mangaindo close #96 --- baseunits/modules/WPManga.pas | 94 +++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 8795b0fcd..b4d15e71a 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -14,6 +14,7 @@ implementation const dirURL = '/manga-list/all/any/last-added/'; + dirURLmangaindo = '/daftar-manga/all/any/last-added/'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; @@ -27,7 +28,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result := NET_PROBLEM; Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL, 3) then + if Module.Website = 'MangaIndo' then s := dirURLmangaindo + else s := dirURL; + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + s, 3) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -59,21 +62,32 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Result := NET_PROBLEM; Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL + + if Module.Website = 'MangaIndo' then s := dirURLmangaindo + else s := dirURL; + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + s + IncStr(URL) + '/', 3) then if Source.Count > 0 then begin Result := NO_ERROR; Query := TXQueryEngineHTML.Create(Source.Text); try - if (Module.Website = 'EyeOnManga') or - (Module.Website = 'MangaBoom') then - s := '//*[@id="sct_content"]//h2/a[1]' - else - s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; - for v in Query.XPath(s) do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); + if Module.Website = 'MangaIndo' then begin + for v in Query.XPath( + '//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do + Links.Add(v.toString); + for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do + Names.Add(v.toString); + end + else begin + if (Module.Website = 'EyeOnManga') or + (Module.Website = 'MangaBoom') then + s := '//*[@id="sct_content"]//h2/a[1]' + else + s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; + for v in Query.XPath(s) do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end; end; finally Query.Free; @@ -104,7 +118,9 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.chapterName.Add(v.toNode.Next.toString()); end; end - else if module.Website = 'EyeOnManga' then begin + else if (Module.Website = 'EyeOnManga') or + (Module.Website = 'MangaIndo') then + begin for v in Query.XPath('//ul[@class="chp_lst"]//a[1]') do begin info.chapterLinks.Add(v.toNode.getAttribute('href')); info.chapterName.Add(v.toString); @@ -118,27 +134,26 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; + function getwpmangavalue(aname: String): String; + begin + Result := Query.XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"' + + aname + '")]'); + if Result <> '' then Result := TrimChar(SeparateRight(Result, aname), [':', ' ']); + end; + procedure scaninfo; begin with info, Query do begin - coverLink := XPathString('//img[starts-with(@class,"cvr")]/@src'); - title := Query.XPathString('//*[@itemprop="itemreviewed"]'); if Module.Website = 'EyeOnManga' then summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]') else summary := XPathString('//*[@class="det"]/p[1]'); - authors := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Author")]'); - artists := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Artist")]'); - genres := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Category")]'); - status := XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"Status")]'); - if summary <> '' then summary := - TrimChar(SeparateRight(summary, 'Summary'), [':', ' ']); - if authors <> '' then authors := - TrimChar(SeparateRight(authors, 'Author'), [':', ' ']); - if artists <> '' then artists := - TrimChar(SeparateRight(artists, 'Artist'), [':', ' ']); - if genres <> '' then genres := - TrimChar(SeparateRight(genres, 'Category'), [':', ' ']); + if summary <> '' then + summary := TrimChar(SeparateRight(summary, 'Summary'), [':', ' ']); + authors := getwpmangavalue('Author'); + artists := getwpmangavalue('Artist'); + genres := getwpmangavalue('Category'); + status := getwpmangavalue('Status'); if status <> '' then begin status := LowerCase(status); if Pos('ongoing', status) > 0 then status := '1' @@ -149,6 +164,24 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; + procedure scaninfomangaindo; + begin + with info, Query do begin + summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]'); + authors := getwpmangavalue('Penulis'); + artists := getwpmangavalue('Seniman'); + genres := getwpmangavalue('Kategori'); + status := getwpmangavalue('Status'); + if status <> '' then begin + status := LowerCase(status); + if Pos('berjalan', status) > 0 then status := '1' + else if Pos('tamat', status) > 0 then status := '0' + else status := ''; + end; + end; + scanchapters; + end; + begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; @@ -163,7 +196,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NO_ERROR; Query := TXQueryEngineHTML.Create(Source.Text); try - scaninfo; + info.coverLink := Query.XPathString('//img[starts-with(@class,"cvr")]/@src'); + info.title := Query.XPathString('//*[@itemprop="itemreviewed"]'); + if Module.Website = 'MangaIndo' then scaninfomangaindo + else scaninfo; s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); if s <> '' then begin s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); @@ -180,6 +216,11 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; if Module.Website <> 'EyeOnManga' then InvertStrings([info.chapterLinks, info.chapterName]); + if (Module.Website = 'EyeOnManga') or + (Module.Website = 'MangaIndo') and + (info.chapterName.Count > 0) then + for i := 0 to info.chapterName.Count - 1 do + info.chapterName[i] := 'Ch.' + IncStr(i) + ' ' + info.chapterName[i]; finally Query.Free; end; @@ -287,6 +328,7 @@ procedure RegisterModule; AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com'); AddWebsiteModule('Authrone', 'http://www.authrone.com'); AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); + AddWebsiteModule('MangaIndo', 'http://mangaindo.id'); end; initialization From 0a6dcff89c89306a925e56799c65855444f865de Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Aug 2015 09:01:09 +0800 Subject: [PATCH 0554/2794] updatethread, don't need to show link while getinfo --- baseunits/uUpdateThread.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 53b8f4634..afd09939d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -492,8 +492,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; CS_DIRECTORY_PAGE_2: s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; CS_INFO: - s := Format('%s | %s "%s" "%s"', [s, RS_GettingInfo, names[workPtr - 1], - links[workPtr - 1]]); + s := Format('%s | %s "%s"', [s, RS_GettingInfo, names[workPtr - 1]]); end; FStatus := s; MainForm.ulWorkPtr := workPtr + 1; From e653726f4c30a6609584e0942567fa1b1cd3d79f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 19 Aug 2015 00:30:47 +0800 Subject: [PATCH 0555/2794] add mangaindo to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index af25e79b9..11ff936a0 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE -Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaKu,PecintaKomik +Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas From 4c02f30e98270e439089f4bed9a8ee7acb4d1cca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 19 Aug 2015 00:34:02 +0800 Subject: [PATCH 0556/2794] Bump version 0.9.22.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9ffc871bf..a5280a899 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,12 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.22.0 (19-08-2015) +[*] Fix various bug on filter +[*] WP-Manga: rewrite all script +[*] Added MangaIndo(ID) +[*] Various changes and bug fixes + 0.9.21.8 (16-08-2015) [*] Fix high cpu usage while updating manga list diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 233ceb775..df3d57e13 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="21"/> - <BuildNr Value="8"/> + <RevisionNr Value="22"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 258b20c7a..1d06ae6e8 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.21.8 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.21.8/fmd_0.9.21.8.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.21.8/fmd_0.9.21.8_Win64.7z +VERSION=0.9.22.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.22.0/fmd_0.9.22.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.22.0/fmd_0.9.22.0_Win64.7z From 80c79ed8eb9351e099836069e4f50def81b4035c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 05:18:04 +0800 Subject: [PATCH 0557/2794] ehentai, fix image url and some changes --- baseunits/modules/EHentai.pas | 96 +++++++++++++++++------------------ 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 222bccc47..3a4ebdcb8 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -20,25 +20,24 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var Source: TStringList; - Parser: TTreeParser; + Query: TXQueryEngineHTML; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit; Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), Module.RootURL + '/?' + dirURL, 3) then + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/?' + dirURL, 3) then begin if Source.Count > 0 then begin Result := NO_ERROR; - Parser := TTreeParser.Create; + Query := TXQueryEngineHTML.Create(Source.Text); try - ParseHTMLTree(Parser, Source.Text); - Page := StrToIntDef(SelectCSSString( - 'table.ptt>tbody>tr>td:nth-last-child(2)>a', Parser), 1) + 1; + Page := StrToIntDef(Query.CSSString( + 'table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) + 1; finally - Parser.Free; + Query.Free; end; end else Result := INFORMATION_NOT_FOUND; @@ -52,7 +51,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; var Source: TStringList; - Parser: TTreeParser; + Query: TXQueryEngineHTML; rurl: String; v: IXQValue; begin @@ -62,23 +61,21 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; try if URL = '0' then rurl := Module.RootURL + '/?' + dirURL else rurl := Module.RootURL + '/?page=' + IncStr(URL) + '&' + dirURL; - if MangaInfo.GetPage(TObject(Source), rurl, 3) then + if GetPage(MangaInfo.FHTTP, TObject(Source), rurl, 3) then begin Result := INFORMATION_NOT_FOUND; if Source.Count > 0 then begin Result := NO_ERROR; - Parser := TTreeParser.Create; + Query := TXQueryEngineHTML.Create(Source.Text); try - ParseHTMLTree(Parser, Source.Text); - for v in SelectXPathIX('//table[@class="itg"]/tbody/tr/td/div/div/a', - Parser) do + for v in Query.XPath('//table[@class="itg"]/tbody/tr/td/div/div/a') do begin Names.Add(v.toString); Links.Add(v.toNode.getAttribute('href')); end; finally - Parser.Free; + Query.Free; end; end; end; @@ -92,7 +89,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; var info: TMangaInfo; Source: TStringList; - Parser: TTreeParser; + Query: TXQueryEngineHTML; v: IXQValue; procedure ScanParse; @@ -101,28 +98,28 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin getOK := True; // check content warning - if Pos('Content Warning', SelectXPathString('//div/h1', Parser)) > 0 then + if Pos('Content Warning', Query.XPathString('//div/h1')) > 0 then begin - getOK := MangaInfo.GetPage(TObject(Source), info.url + '?nw=session', Reconnect); + getOK := GetPage(MangaInfo.FHTTP, TObject(Source), info.url + + '?nw=session', Reconnect); if getOK then - ParseHTMLTree(Parser, Source.Text); + Query.ParseHTML(Source.Text); end; if getOK then begin with info do begin //title - title := SelectXPathString('//*[@id="gn"]', Parser); + title := Query.XPathString('//*[@id="gn"]'); //cover - coverLink := SelectXPathString('//*[@id="gd1"]/img/@src', Parser); + coverLink := Query.XPathString('//*[@id="gd1"]/img/@src'); //artists artists := ''; - for v in SelectXPathIX('//a[starts-with(@id,"ta_artist")]', Parser) do + for v in Query.XPath('//a[starts-with(@id,"ta_artist")]') do AddCommaString(artists, v.toString); //genres genres := ''; - for v in SelectXPathIX( - '//a[starts-with(@id,"ta_")and(not(starts-with(@id,"ta_artist")))]', - Parser) do + for v in Query.XPath( + '//a[starts-with(@id,"ta_")and(not(starts-with(@id,"ta_artist")))]') do AddCommaString(genres, v.toString); //chapter chapterLinks.Add(url); @@ -154,7 +151,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.url := FillHost(Module.RootURL, URL); Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), info.url, Reconnect) then + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then begin if Source.Count > 0 then begin @@ -164,12 +161,11 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info.summary := Source.Text else begin - Parser := TTreeParser.Create; + Query := TXQueryEngineHTML.Create(Source.Text); try - ParseHTMLTree(Parser, Source.Text); ScanParse; finally - Parser.Free; + Query.Free; end; end; end @@ -186,13 +182,13 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; var Container: TTaskContainer; Source: TStringList; - Parser: TTreeParser; + Query: TXQueryEngineHTML; v: IXQValue; rurl: String; procedure GetImageLink; begin - for v in SelectXPathIX('//*[@class="gdtm"]/div/a/@href', Parser) do + for v in Query.XPath('//*[@class="gdtm"]/div/a/@href') do begin Container.PageLinks.Add('G'); Container.PageContainerLinks.Add(v.toString); @@ -207,23 +203,23 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin getOK := True; //check content warning - if Pos('Content Warning', SelectXPathString('//div/h1', Parser)) > 0 then + if Pos('Content Warning', Query.XPathString('//div/h1')) > 0 then begin rurl += '?nw=session'; - getOK := DownloadThread.GetPage(TObject(Source), rurl, + getOK := GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Container.Manager.retryConnect); if getOK then - ParseHTMLTree(Parser, Source.Text); + Query.ParseHTML(Source.Text); end; if getOK then begin GetImageLink; //get page count - p := StrToIntDef(SelectCSSString('table.ptt>tbody>tr>td:nth-last-child(2)>a', - Parser), 1) - 1; + p := StrToIntDef(Query.CSSString( + 'table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) - 1; if p > 0 then for i := 1 to p do - if DownloadThread.GetPage(TObject(Source), rurl + '?p=' + IntToStr(i), + if GetPage(DownloadThread.FHTTP, TObject(Source), rurl + '?p=' + IntToStr(i), Container.Manager.retryConnect) then GetImageLink; end; @@ -239,18 +235,17 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Source := TStringList.Create; try rurl := FillHost(Module.RootURL, URL); - if DownloadThread.GetPage(TObject(Source), rurl, + if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Container.Manager.retryConnect) then begin if Source.Count > 0 then begin Result := True; - Parser := TTreeParser.Create; + Query := TXQueryEngineHTML.Create(Source.Text); try - ParseHTMLTree(Parser, Source.Text); ScanParse; finally - Parser.Free; + Query.Free; end; end; end; @@ -264,7 +259,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; var Source: TStringList; Container: TTaskContainer; - Parser: TTreeParser; + Query: TXQueryEngineHTML; iurl: String; reconnect: Integer; @@ -276,9 +271,11 @@ function DownloadImage(var DownloadThread: TDownloadThread; rcount := 0; Result := False; while (not Result) and (not DownloadThread.IsTerminated) do begin - ParseHTMLTree(Parser, Source.Text); - iurl := SelectXPathString('/html/body/div/a/img/@src', Parser); - Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, Name, Prefix, reconnect); + Query.ParseHTML(Source.Text); + iurl := Query.XPathString('//*[@id="img"]/@src'); + if iurl = '' then iurl := Query.XPathString('//body/div/div/a/img/@src'); + if iurl <> '' then + Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, Name, Prefix, reconnect); if DownloadThread.IsTerminated then Break; if not Result then begin @@ -307,7 +304,8 @@ function DownloadImage(var DownloadThread: TDownloadThread; else iurl := FillHost(Module.RootURL, URL); if nl <> '' then begin iurl := iurl + '?nl=' + nl; - if not DownloadThread.GetPage(TObject(Source), iurl, reconnect) then Break; + if not GetPage(DownloadThread.FHTTP, TObject(Source), iurl, reconnect) then + Break; end else Break; if rcount >= reconnect then Break else Inc(rcount); @@ -323,15 +321,15 @@ function DownloadImage(var DownloadThread: TDownloadThread; iurl := FillHost(Module.RootURL, URL); Source := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), iurl, reconnect) then + if GetPage(DownloadThread.FHTTP, TObject(Source), iurl, reconnect) then begin if Source.Count > 0 then begin - Parser := TTreeParser.Create; + Query := TXQueryEngineHTML.Create(Source.Text); try Result := DoDownloadImage; finally - Parser.Free; + Query.Free; end; end; end; @@ -346,7 +344,7 @@ procedure RegisterModule; begin Website := 'E-Hentai'; RootURL := 'http://g.e-hentai.org'; - MaxTaskLimit := 2; + MaxTaskLimit := 1; MaxConnectionLimit := 4; SortedList := True; InformationAvailable := True; From 8ab33bfdc3f763c574c04e5cccd7380913105012 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 05:18:39 +0800 Subject: [PATCH 0558/2794] wp-manga don't need to add missing chapter number --- baseunits/modules/WPManga.pas | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index b4d15e71a..c9610f0f1 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -216,11 +216,12 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; if Module.Website <> 'EyeOnManga' then InvertStrings([info.chapterLinks, info.chapterName]); - if (Module.Website = 'EyeOnManga') or - (Module.Website = 'MangaIndo') and - (info.chapterName.Count > 0) then - for i := 0 to info.chapterName.Count - 1 do - info.chapterName[i] := 'Ch.' + IncStr(i) + ' ' + info.chapterName[i]; + { add missing chapter number } + //if (Module.Website = 'EyeOnManga') or + // (Module.Website = 'MangaIndo') and + // (info.chapterName.Count > 0) then + // for i := 0 to info.chapterName.Count - 1 do + // info.chapterName[i] := 'Ch.' + IncStr(i) + ' ' + info.chapterName[i]; finally Query.Free; end; From c752bed5fbd2e3771f605ed7a2703b8cb211d5a0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 05:33:19 +0800 Subject: [PATCH 0559/2794] ehentai, fix image url and some clean up --- baseunits/modules/EHentai.pas | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 3a4ebdcb8..38f6a3ea5 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -10,9 +10,6 @@ interface implementation -uses - simplehtmltreeparser, xquery; - const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; @@ -273,9 +270,11 @@ function DownloadImage(var DownloadThread: TDownloadThread; while (not Result) and (not DownloadThread.IsTerminated) do begin Query.ParseHTML(Source.Text); iurl := Query.XPathString('//*[@id="img"]/@src'); - if iurl = '' then iurl := Query.XPathString('//body/div/div/a/img/@src'); + if iurl = '' then + iurl := Query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, Name, Prefix, reconnect); + Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, + Name, Prefix, reconnect); if DownloadThread.IsTerminated then Break; if not Result then begin From 9abb3d5276dac9a2968d170dfd92120b77b50c05 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 06:59:49 +0800 Subject: [PATCH 0560/2794] remove readhentaimanga script --- .../ReadHentaiManga/chapter_page_number.inc | 68 --------- .../ReadHentaiManga/directory_page_number.inc | 38 ----- .../includes/ReadHentaiManga/image_url.inc | 48 ------ .../ReadHentaiManga/manga_information.inc | 142 ------------------ .../ReadHentaiManga/names_and_links.inc | 38 ----- baseunits/uBaseUnit.pas | 61 ++++---- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- 8 files changed, 28 insertions(+), 392 deletions(-) delete mode 100644 baseunits/includes/ReadHentaiManga/chapter_page_number.inc delete mode 100644 baseunits/includes/ReadHentaiManga/directory_page_number.inc delete mode 100644 baseunits/includes/ReadHentaiManga/image_url.inc delete mode 100644 baseunits/includes/ReadHentaiManga/manga_information.inc delete mode 100644 baseunits/includes/ReadHentaiManga/names_and_links.inc diff --git a/baseunits/includes/ReadHentaiManga/chapter_page_number.inc b/baseunits/includes/ReadHentaiManga/chapter_page_number.inc deleted file mode 100644 index dfa623527..000000000 --- a/baseunits/includes/ReadHentaiManga/chapter_page_number.inc +++ /dev/null @@ -1,68 +0,0 @@ - function GetReadHentaiMangaPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - isExtractPage: Boolean = False; - isGetDirect: Boolean = True; - begin - manager.container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(READHENTAIMANGA_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - if isGetDirect then - begin - if l.Count > 0 then - begin - for i := 0 to l.Count - 1 do - begin - if Pos('var wpm_mng_rdr_img_lst', l[i]) > 0 then - begin - s := Trim(l[i]); - s := GetString(s, '(''', ''')'); - s := Trim(URLDecode(s)); - s := TrimChar(s, ['[', ']', '"']); - s := StringReplace(s, '\', '' , [rfReplaceAll]); - s := StringReplace(s, '","', '\', [rfReplaceAll]); - manager.container.PageLinks.Clear; - manager.container.PageLinks.Delimiter := '\'; - manager.container.PageLinks.DelimitedText := s; - manager.container.PageNumber := manager.container.PageLinks.Count; - Break; - end; - end; - end; - end - else - begin - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and - (Pos('class="cbo_wpm_pag"', parse[i]) > 0) then - isExtractPage := True; - if isExtractPage and - (Pos('</select', parse[i]) > 0) then - begin - isExtractPage := False; - Break; - end; - if isExtractPage and - (Pos('<option', parse[i]) > 0) then - begin - Inc(manager.container.PageNumber); - end; - end; - end; - end; - l.Free; - parse.Free; - end; diff --git a/baseunits/includes/ReadHentaiManga/directory_page_number.inc b/baseunits/includes/ReadHentaiManga/directory_page_number.inc deleted file mode 100644 index 09db3c175..000000000 --- a/baseunits/includes/ReadHentaiManga/directory_page_number.inc +++ /dev/null @@ -1,38 +0,0 @@ - function GetReadHentaiMangaDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Page := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[READHENTAIMANGA_ID, 1] + - READHENTAIMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos(READHENTAIMANGA_BROWSER, parse[i]) > 0) and (i + 1 < parse.Count -1) then - if Pos('Last', parse[i + 1]) > 0 then - begin - s := GetVal(parse[i], 'href'); - s := ReplaceRegExpr('^.*\/(\d+)\/$', s, '$1', True); - Page := StrToIntDef(s, 1); - Result := NO_ERROR; - Break; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/ReadHentaiManga/image_url.inc b/baseunits/includes/ReadHentaiManga/image_url.inc deleted file mode 100644 index dec2bf4ee..000000000 --- a/baseunits/includes/ReadHentaiManga/image_url.inc +++ /dev/null @@ -1,48 +0,0 @@ - function GetReadHentaiMangaImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(READHENTAIMANGA_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - s := s + IntToStr(workCounter + 1) + '/'; - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', parse[i]) > 0) and (Pos('id="main_img"', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'src'); - if (s <> '') and (Pos('&#x', parse[i]) > 0) then - begin - s := StringReplace(s, '&#x', '%', [rfIgnoreCase, rfReplaceAll]); - s := StringReplace(s, ';', '', [rfReplaceAll]); - end; - s := URLDecode(s); - manager.container.PageLinks[workCounter] := s; - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/ReadHentaiManga/manga_information.inc b/baseunits/includes/ReadHentaiManga/manga_information.inc deleted file mode 100644 index e9c87507a..000000000 --- a/baseunits/includes/ReadHentaiManga/manga_information.inc +++ /dev/null @@ -1,142 +0,0 @@ - function GetReadHentaiMangaInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[READHENTAIMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(READHENTAIMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - - if parse.Count = 0 then - Exit; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (Pos('class="cvr"', parse[i]) > 0) and (Pos('<img', parse[i]) > 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // get title - if (i + 1 < parse.Count - 1) then - if (Pos('class="ttl"', parse[i]) > 0) and (Pos('<h1 ', parse[i]) > 0) then - mangaInfo.title := Trim(StringFilter(parse[i + 1])); - - //get authors - if (i + 1 < parse.Count - 1) then - if (Pos('Author', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - j := i + 1; - while j < parse.Count do - begin - if (Pos('</p', parse[j]) > 0) then - Break; - if (Pos('<', parse[j]) = 0) and (Trim(parse[j]) <> ':') then - mangaInfo.authors := mangaInfo.authors + parse[j]; - Inc(j); - end; - end; - - //get artists - if (i + 1 < parse.Count - 1) then - if (Pos('Artist', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - j := i + 1; - while j < parse.Count do - begin - if (Pos('</p', parse[j]) > 0) then - Break; - if (Pos('<', parse[j]) = 0) and (Trim(parse[j]) <> ':') then - mangaInfo.artists := mangaInfo.artists + parse[j]; - Inc(j); - end; - end; - - //get genres - if (i + 1 < parse.Count - 1) then - if (Pos('Category', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - j := i + 1; - s := ''; - while j < parse.Count do - begin - if (Pos('</p', parse[j]) > 0) then - Break; - if (Pos('<', parse[j]) = 0) and (Trim(parse[j]) <> ':') then - s := s + parse[j]; - Inc(j); - end; - if (mangaInfo.genres <> '') and (s <> '') then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(s) - else - if s <> '' then - mangaInfo.genres := Trim(s); - end; - if (i + 1 < parse.Count - 1) then - if (Pos('Tagged as', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - j := i + 1; - s := ''; - while j < parse.Count do - begin - if (Pos('</p', parse[j]) > 0) then - Break; - if (Pos('<', parse[j]) = 0) and (Trim(parse[j]) <> ':') then - s := s + parse[j]; - Inc(j); - end; - if (mangaInfo.genres <> '') and (s <> '') then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(s) - else - if s <> '' then - mangaInfo.genres := Trim(s); - end; - - //get status - if (i + 4 < parse.Count - 1) then - if (Pos('Status', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - if Pos('Completed', parse[i + 4]) > 0 then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end; - - //get chapters - if (Pos('<a ', parse[i]) > 0) and (Pos('class="lst"', parse[i]) > 0) then - begin - mangaInfo.chapterName.Add(Trim(GetVal(parse[i], 'title'))); - s := GetVal(parse[i], 'href'); - s := StringReplace(s, WebsiteRoots[READHENTAIMANGA_ID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - end; - end; - - if mangaInfo.chapterName.Count = 1 then - mangaInfo.chapterName[0] := mangaInfo.title - else if mangaInfo.chapterName.Count > 1 then - begin - // invert chapter - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/ReadHentaiManga/names_and_links.inc b/baseunits/includes/ReadHentaiManga/names_and_links.inc deleted file mode 100644 index 1956a127f..000000000 --- a/baseunits/includes/ReadHentaiManga/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function ReadHentaiMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[READHENTAIMANGA_ID, 1] + - READHENTAIMANGA_BROWSER + IntToStr(StrToInt(URL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a ', parse[i]) > 0) and (Pos('class="lst mng_det_pop"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := Trim(HTMLEntitiesFilter(StringFilter(GetVal(parse[i], 'title')))); - names.Add(s); - s := GetVal(parse[i], 'href'); - s := StringReplace(s, WebsiteRoots[READHENTAIMANGA_ID, 1], '', [rfIgnoreCase]); - links.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 335298ca8..c3bd2db43 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -324,35 +324,34 @@ interface MANGALIB_PL_ID = 59; ONEMANGA_ID = 60; MANGATOWN_ID = 61; - READHENTAIMANGA_ID = 62; - MANGAOKU_ID = 63; - MYREADINGMANGAINFO_ID = 64; - IKOMIK_ID = 65; - NHENTAI_ID = 66; - UNIONMANGAS_ID = 67; - MANGAMINT_ID = 68; - UNIXMANGA_ID = 69; - HAKIHOME_ID = 70; - EXTREMEMANGAS_ID = 71; - MANGAHOST_ID = 72; - PORNCOMIX_ID = 73; - PORNCOMIXRE_ID = 74; - PORNCOMIXIC_ID = 75; - XXCOMICS_ID = 76; - XXCOMICSMT_ID = 77; - XXCOMICS3D_ID = 78; - PORNXXXCOMICS_ID = 79; - MANGASEE_ID = 80; - MANGAKU_ID = 81; - ACADEMYVN_ID = 82; - MANGAAT_ID = 83; - SENMANGARAW_ID = 84; - READMANGATODAY_ID = 85; - LONEMANGA_ID = 86; - DYNASTYSCANS_ID = 87; - MADOKAMI_ID = 88; - - WebsiteRoots: array [0..88] of array [0..1] of string = ( + MANGAOKU_ID = 62; + MYREADINGMANGAINFO_ID = 63; + IKOMIK_ID = 64; + NHENTAI_ID = 65; + UNIONMANGAS_ID = 66; + MANGAMINT_ID = 67; + UNIXMANGA_ID = 68; + HAKIHOME_ID = 69; + EXTREMEMANGAS_ID = 70; + MANGAHOST_ID = 71; + PORNCOMIX_ID = 72; + PORNCOMIXRE_ID = 73; + PORNCOMIXIC_ID = 74; + XXCOMICS_ID = 75; + XXCOMICSMT_ID = 76; + XXCOMICS3D_ID = 77; + PORNXXXCOMICS_ID = 78; + MANGASEE_ID = 79; + MANGAKU_ID = 80; + ACADEMYVN_ID = 81; + MANGAAT_ID = 82; + SENMANGARAW_ID = 83; + READMANGATODAY_ID = 84; + LONEMANGA_ID = 85; + DYNASTYSCANS_ID = 86; + MADOKAMI_ID = 87; + + WebsiteRoots: array [0..87] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), @@ -415,7 +414,6 @@ interface ('Manga-Lib_PL', 'http://www.manga-lib.pl/index.php'), ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), - ('ReadHentaiManga', 'http://readhentaimanga.com'), ('MangaOku', 'http://www.mangaoku.net'), ('MyReadingMangaInfo', 'http://myreadingmanga.info'), ('I-Komik', 'http://www.i-komik.com'), @@ -566,8 +564,6 @@ interface MANGATOWN_BROWSER = '/directory/'; - READHENTAIMANGA_BROWSER = '/hentai-manga-list/all/any/last-added/'; - IKOMIK_BROWSER = '/manga-directory/'; UNIONMANGAS_BROWSER = '/mangas'; @@ -1280,7 +1276,6 @@ function SitesWithSortedList(const website : String) : Boolean; NINEMANGA_BR_ID, MANGACOW_ID, ONEMANGA_ID, - READHENTAIMANGA_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID, MANGA2U_ID, diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b2abfb132..ccab6d36e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1969,8 +1969,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/MangaTown/directory_page_number.inc} - {$I includes/ReadHentaiManga/directory_page_number.inc} - {$I includes/MyReadingMangaInfo/directory_page_number.inc} {$I includes/IKomik/directory_page_number.inc} @@ -2111,9 +2109,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[MANGATOWN_ID, 0] then Result := GetMangaTownDirectoryPageNumber else - if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then - Result := GetReadHentaiMangaDirectoryPageNumber - else if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then Result := GetMyReadingMangaInfoDirectoryPageNumber else @@ -2288,8 +2283,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaTown/names_and_links.inc} - {$I includes/ReadHentaiManga/names_and_links.inc} - {$I includes/MangaOku/names_and_links.inc} {$I includes/MyReadingMangaInfo/names_and_links.inc} @@ -2508,9 +2501,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[MANGATOWN_ID, 0] then Result := MangaTownGetNamesAndLinks else - if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then - Result := ReadHentaiMangaGetNamesAndLinks - else if website = WebsiteRoots[MANGAOKU_ID, 0] then Result := MangaOkuGetNamesAndLinks else @@ -2703,8 +2693,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaTown/manga_information.inc} - {$I includes/ReadHentaiManga/manga_information.inc} - {$I includes/MangaOku/manga_information.inc} {$I includes/MyReadingMangaInfo/manga_information.inc} @@ -2931,9 +2919,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[MANGATOWN_ID, 0] then Result := GetMangaTownInfoFromURL else - if website = WebsiteRoots[READHENTAIMANGA_ID, 0] then - Result := GetReadHentaiMangaInfoFromURL - else if website = WebsiteRoots[MANGAOKU_ID, 0] then Result := GetMangaOkuInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b9980f35a..d07a6b44a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -449,8 +449,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaTown/chapter_page_number.inc} - {$I includes/ReadHentaiManga/chapter_page_number.inc} - {$I includes/MangaOku/chapter_page_number.inc} {$I includes/MyReadingMangaInfo/chapter_page_number.inc} @@ -620,9 +618,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownPageNumber else - if manager.container.MangaSiteID = READHENTAIMANGA_ID then - Result := GetReadHentaiMangaPageNumber - else if manager.container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuPageNumber else @@ -793,8 +788,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaTown/image_url.inc} - {$I includes/ReadHentaiManga/image_url.inc} - {$I includes/MangaOku/image_url.inc} {$I includes/IKomik/image_url.inc} @@ -974,9 +967,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownImageURL else - if manager.container.MangaSiteID = READHENTAIMANGA_ID then - Result := GetReadHentaiMangaImageURL - else if manager.container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuImageURL else From 4ffd3e984bc34b5f7f23687709b0d969c5300297 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 07:07:43 +0800 Subject: [PATCH 0561/2794] add readhentaimanga to wp-manga, fix image url decoding fix #98 --- baseunits/modules/WPManga.pas | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index c9610f0f1..67bbc3367 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -15,6 +15,7 @@ implementation const dirURL = '/manga-list/all/any/last-added/'; dirURLmangaindo = '/daftar-manga/all/any/last-added/'; + dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; @@ -29,6 +30,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Source := TStringList.Create; try if Module.Website = 'MangaIndo' then s := dirURLmangaindo + else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else s := dirURL; if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + s, 3) then if Source.Count > 0 then @@ -63,6 +65,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Source := TStringList.Create; try if Module.Website = 'MangaIndo' then s := dirURLmangaindo + else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else s := dirURL; if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + s + IncStr(URL) + '/', 3) then @@ -78,6 +81,12 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do Names.Add(v.toString); end + else if Module.Website = 'ReadHentaiManga' then begin + for v in Query.XPath('//*[@id="content"]//*[@id="center"]/a') do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toNode.getAttribute('title')); + end; + end else begin if (Module.Website = 'EyeOnManga') or (Module.Website = 'MangaBoom') then @@ -275,6 +284,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Source: TStringList; Query: TXQueryEngineHTML; Container: TTaskContainer; + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -293,8 +303,11 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Result := True; Query := TXQueryEngineHTML.Create(Source.Text); try - Container.PageLinks[DownloadThread.WorkCounter] := - Query.XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); + if Module.Website = 'ReadHentaiManga' then + s := HTMLDecode(Query.XPathString('//img[@id="main_img"]/@src')) + else + s := Query.XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); + Container.PageLinks[DownloadThread.WorkCounter] := s; finally Query.Free; end; @@ -330,6 +343,7 @@ procedure RegisterModule; AddWebsiteModule('Authrone', 'http://www.authrone.com'); AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); AddWebsiteModule('MangaIndo', 'http://mangaindo.id'); + AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); end; initialization From 136060318c114cca9f713cb901f64981d818f2e9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 07:19:06 +0800 Subject: [PATCH 0562/2794] baseunit, remove webp from content accepted content type on getpage tpicture doesn't support this format, hopefully the server will reply with jpeg format. should fix cover image that sometimes failed to load. --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c3bd2db43..1a1cc9c38 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2926,7 +2926,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; end; HTTPHeader.Values['DNT'] := ' 1'; - HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; + HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; HTTPHeader.Values['Accept-Charset'] := ' UTF-8'; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; @@ -3210,7 +3210,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; HTTPHeader.Values['DNT'] := ' 1'; - HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'; + HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; HTTPHeader.Values['Accept-Charset'] := ' UTF-8'; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; From 3c0c49fb4ce4fa72b9921e3569f984b8a849909d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Aug 2015 07:29:44 +0800 Subject: [PATCH 0563/2794] Bump version 0.9.22.1 --- changelog.txt | 8 +++++++- mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index a5280a899..b6be395a3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,12 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.22.1 (21-08-2015) +[*] E-Hentai: fix image url +[*] MangaIndo: remove automatically added chapter number +[*] ReadHentaiManga: fix image url +[*] Fix cover image sometimes failed to load + 0.9.22.0 (19-08-2015) [*] Fix various bug on filter [*] WP-Manga: rewrite all script @@ -21,7 +27,7 @@ Changelog: [*] Various changes and bug fixes 0.9.21.6 (11-08-2015) -[*] Doujin-Mode: reset image url every task start, fix expired url +[*] Doujin-Moe: reset image url every task start, fix expired url [*] Fix empty website when adding a favorite [*] Fix filter custom genres incorrectly treats whitespaces as separator [*] Various changes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index df3d57e13..389954bfa 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="22"/> + <BuildNr Value="1"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 1d06ae6e8..dfa6d0d5d 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.22.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.22.0/fmd_0.9.22.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.22.0/fmd_0.9.22.0_Win64.7z +VERSION=0.9.22.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.22.1/fmd_0.9.22.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.22.1/fmd_0.9.22.1_Win64.7z From c74268074308c0025c47509192762abf9c23147c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 04:54:35 +0800 Subject: [PATCH 0564/2794] e-hentai, multi page images --- baseunits/modules/EHentai.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 38f6a3ea5..49cccf66c 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -218,7 +218,10 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; for i := 1 to p do if GetPage(DownloadThread.FHTTP, TObject(Source), rurl + '?p=' + IntToStr(i), Container.Manager.retryConnect) then + begin + Query.ParseHTML(Source.Text); GetImageLink; + end; end; end; @@ -231,7 +234,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Container.PageNumber := 0; Source := TStringList.Create; try - rurl := FillHost(Module.RootURL, URL); + rurl := AppendURLDelim(FillHost(Module.RootURL, URL)); if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Container.Manager.retryConnect) then begin From 9b5f567f8c30a0a403d0124f0605847ad1e9a837 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 05:01:17 +0800 Subject: [PATCH 0565/2794] e-hentai, fix multi page with content warning --- baseunits/modules/EHentai.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 49cccf66c..5c49ca840 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -202,8 +202,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; //check content warning if Pos('Content Warning', Query.XPathString('//div/h1')) > 0 then begin - rurl += '?nw=session'; - getOK := GetPage(DownloadThread.FHTTP, TObject(Source), rurl, + getOK := GetPage(DownloadThread.FHTTP, TObject(Source), rurl + '?nw=session', Container.Manager.retryConnect); if getOK then Query.ParseHTML(Source.Text); From 4664b87dadaafe5fc5ec85e3161942514253bd13 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 05:23:35 +0800 Subject: [PATCH 0566/2794] websitemodules, add dynamicpagelink --- baseunits/WebsiteModules.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index d76767d54..141a0453e 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -56,6 +56,7 @@ TModuleContainer = class SortedList: Boolean; InformationAvailable: Boolean; FavoriteAvailable: Boolean; + DynamicPageLink: Boolean; TotalDirectoryPage: array of Integer; CurrentDirectoryIndex: Integer; OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; @@ -205,6 +206,7 @@ constructor TModuleContainer.Create; SortedList := False; InformationAvailable := True; FavoriteAvailable := True; + DynamicPageLink := False; TotalDirectory := 1; CurrentDirectoryIndex := 0; end; From c9e2fa8159ec076e0c0d092f378a1a859b5f7fe1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 05:23:55 +0800 Subject: [PATCH 0567/2794] e-hentai, set true dynamicpagelink --- baseunits/modules/EHentai.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 5c49ca840..5baed6ed2 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -349,6 +349,7 @@ procedure RegisterModule; MaxConnectionLimit := 4; SortedList := True; InformationAvailable := True; + DynamicPageLink := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 07853cffe9b186d4b553f541fd0024720c6ab2dc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 05:25:16 +0800 Subject: [PATCH 0568/2794] downloadmanager, fix range check error when downloaded files doesn't exist, fix dynamicpagelink check --- baseunits/uDownloadsManager.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d07a6b44a..a9df0ed2a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1346,12 +1346,18 @@ procedure TTaskThread.Execute; var j: Integer; S, P: String; + DynamicPageLink: Boolean; begin INIAdvanced.Reload; ModuleId := container.ModuleId; container.ThreadState := True; container.DownloadInfo.TransferRate := ''; try + if container.ModuleId > -1 then + DynamicPageLink := Modules.Module[ModuleId].DynamicPageLink + else + DynamicPageLink := False; + while container.CurrentDownloadChapterPtr < container.ChapterLinks.Count do begin WaitForThreads; @@ -1410,11 +1416,12 @@ procedure TTaskThread.Execute; (FileExistsUTF8(P + '.gif')) then container.PageLinks[j] := 'D' else - if container.PageLinks[j] = 'D' then - if SitesWithoutPageLink(WebsiteRoots[container.MangaSiteID, 0]) then + begin + if DynamicPageLink then container.PageLinks[j] := 'G' else container.PageLinks[j] := 'W'; + end; end; end; @@ -1422,8 +1429,7 @@ procedure TTaskThread.Execute; if container.PageLinks.Count = 0 then container.PageLinks.Add('W'); container.PageNumber := container.PageLinks.Count; - if not SitesWithoutPageLink(container.DownloadInfo.Website) and - CheckForPrepare then + if (not DynamicPageLink) and CheckForPrepare then begin Flag := CS_GETPAGELINK; container.WorkCounter := 0; From 6c3d504f44eebebf0f42fb4e999d90721ece2466 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 05:25:40 +0800 Subject: [PATCH 0569/2794] baseunit, clean up unused function --- baseunits/uBaseUnit.pas | 6 ------ 1 file changed, 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1a1cc9c38..4d1957ba2 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -830,7 +830,6 @@ function SitesWithSortedList(const website:String): Boolean; function SitesWithoutFavorites(const website:String): Boolean; // Return true if the website doesn't contain manga information function SitesWithoutInformation(const website: String): Boolean; -function SitesWithoutPageLink(const website: String): Boolean; function SitesWithoutReferer(const website: String): Boolean; function SitesRefererisURL(const website: String): Boolean; function SitesWithSingleChapter(const website: String): Boolean; @@ -1340,11 +1339,6 @@ function SitesWithoutInformation(const website: String): Boolean; ]); end; -function SitesWithoutPageLink(const website : String) : Boolean; -begin - Result := False; -end; - function SitesWithoutReferer(const website : String) : Boolean; begin Result := False; From e3dd55ebfca1a8ec619169aa89b62397b765bbf5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 05:44:33 +0800 Subject: [PATCH 0570/2794] remove senmangaraw from mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 11ff936a0..310ab0a85 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -13,7 +13,7 @@ Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,Pecinta Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint,SenMangaRAW +Raw=MangaMint Russian=NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom From a4de4b5af53e3ee1829058dd3ce7be0fa5bf1f7c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 06:44:24 +0800 Subject: [PATCH 0571/2794] websitemodules, set default pagenumber --- baseunits/WebsiteModules.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 141a0453e..b6a664901 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -341,6 +341,7 @@ function TWebsiteModules.ModuleAvailable(const Website: String; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer): Integer; begin + Page := 1; Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber) then From e714598fdaeb1189676b3dd46de977c8a4cec222 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 10:22:51 +0800 Subject: [PATCH 0572/2794] downloadmanager, fix always reset single pagelink --- baseunits/uDownloadsManager.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a9df0ed2a..0ae42e65a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1416,6 +1416,7 @@ procedure TTaskThread.Execute; (FileExistsUTF8(P + '.gif')) then container.PageLinks[j] := 'D' else + if container.PageLinks[j] = 'D' then begin if DynamicPageLink then container.PageLinks[j] := 'G' From 151175cf2c3cba948660d45011741c1ddff700fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 10:25:36 +0800 Subject: [PATCH 0573/2794] add mangalife close #99 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaLife.pas | 167 ++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaLife.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 982a08b16..3b7ef8eb4 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -9,4 +9,5 @@ uses EHentai, Doujinmoeus, MangaReader, - MangaStream; + MangaStream, + MangaLife; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas new file mode 100644 index 000000000..b96bc3ffc --- /dev/null +++ b/baseunits/modules/MangaLife.pas @@ -0,0 +1,167 @@ +unit MangaLife; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +uses + synautil; + +const + dirURL = '/directory/'; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + v: IXQValue; +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL, 3) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + for v in Query.XPath('//*[@id="content"]/p/a') do begin + Links.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); + Names.Add(v.toString, ['.']); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + info: TMangaInfo; + v: IXQValue; + s: String; + + function getpropvalue(aname: String): String; + begin + Result := Query.XPathString( + '(/html/body/div[3]/div/div[1]/div/div[2]/div)[contains(.,"' + + aname + '")]'); + if Result <> '' then + Result := Trim(TrimChar(SeparateRight(Result, aname), [':', ' '])); + end; + +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + with info do begin + coverLink := Query.XPathString( + '//div[@class="col-lg-3 col-md-3 col-sm-3 col-xs-3"]/img/@src'); + if coverLink <> '' then + coverLink := MaybeFillHost(Module.RootURL, coverLink); + title := Query.XPathString('//h1'); + authors := getpropvalue('Author'); + genres := getpropvalue('Genre'); + summary := getpropvalue('Description'); + s := LowerCase(getpropvalue('Scanlation Status')); + if s <> '' then begin + if Pos('ongoing', s) > 0 then status := '1' + else if Pos('completed', s) > 0 then status := '0' + end; + //chapters + for v in Query.XPath('/html/body/div[3]/div/div/div/a') do begin + s := v.toNode.getAttribute('href'); + if RightStr(s, 6) = 'page-1' then SetLength(s, Length(s) - 6); + chapterLinks.Add(s); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Query: TXQueryEngineHTML; + Container: TTaskContainer; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + with Container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + Source := TStringList.Create; + try + if GetPage(DownloadThread.FHTTP, TObject(Source), + AppendURLDelim(FillHost(Module.RootURL, URL)), Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + for v in Query.XPath('//*[@class="imagePage"]/img/@src') do + Container.PageLinks.Add(v.toString); + finally + Query.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaLife'; + RootURL := 'http://manga.life'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From db27f884be798ac14da10e4ced051ef40a0beb54 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 10:26:53 +0800 Subject: [PATCH 0574/2794] add mangalife to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 310ab0a85..afaa99622 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt Chinese=mh160 -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 60c8f2f4de715a9b931c1b63bcb90d152b96a30f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 13:05:45 +0800 Subject: [PATCH 0575/2794] mangalife, fix and clean up --- baseunits/modules/MangaLife.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index b96bc3ffc..6289b81d0 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -34,7 +34,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; try for v in Query.XPath('//*[@id="content"]/p/a') do begin Links.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); - Names.Add(v.toString, ['.']); + Names.Add(v.toString); end; finally Query.Free; @@ -86,6 +86,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; coverLink := MaybeFillHost(Module.RootURL, coverLink); title := Query.XPathString('//h1'); authors := getpropvalue('Author'); + artists := getpropvalue('Artist'); genres := getpropvalue('Genre'); summary := getpropvalue('Description'); s := LowerCase(getpropvalue('Scanlation Status')); From ef452d8824bb7b63e4773a6aa8595aefb6503ca0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 13:07:06 +0800 Subject: [PATCH 0576/2794] add luscious --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Luscious.pas | 207 +++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Luscious.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 3b7ef8eb4..729502575 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -10,4 +10,5 @@ uses Doujinmoeus, MangaReader, MangaStream, - MangaLife; + MangaLife, + Luscious; diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas new file mode 100644 index 000000000..530d75d55 --- /dev/null +++ b/baseunits/modules/Luscious.pas @@ -0,0 +1,207 @@ +unit Luscious; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +uses + synautil, RegExpr; + +const + dirURL = '/c/-/albums/t/manga/sorted/new/page/'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +begin + Page := 100; + Result := NO_ERROR; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + v: IXQValue; +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), + Module.RootURL + dirURL + IncStr(URL) + '/', 3) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + for v in Query.XPath('//*[@id="albums_wrapper"]//*[@class="caption"]//a') do begin + Links.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); + Names.Add(v.toString); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + info: TMangaInfo; + v: IXQValue; + s: String; + regx: TRegExpr; +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + Source := TStringList.Create; + regx := TRegExpr.Create; + try + regx.ModifierI := True; + regx.Expression := '/page/\d+/?$'; + if regx.Exec(info.url) then + info.url := regx.Replace(info.url, '/', False); + if RightStr(info.url, 5) <> 'view/' then info.url += 'view/'; + if Pos('/pictures/album/', info.url) > 0 then + info.url := StringReplace(info.url, '/pictures/album/', '/albums/', []); + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + with info do begin + coverLink := Query.XPathString('//*[@class="album_cover_item"]//img/@src'); + if coverLink <> '' then + coverLink := TrimLeftChar(coverLink, ['/']); + title := Query.XPathString('//*[@class="album_cover"]/h2'); + genres := ''; + for v in Query.XPath('//*[@id="tag_section"]//li') do begin + s := v.toString; + if LeftStr(s, 7) = 'author:' then + authors := SeparateRight(s, ':') + else if LeftStr(s, 7) = 'artist:' then + artists := SeparateRight(s, ':') + else + AddCommaString(genres, s); + end; + //section, languge + for v in Query.XPath('//*[@class="content_info"]//p/*') do + AddCommaString(genres, v.toString); + //chapter + s := info.url; + if RightStr(s, 5) = 'view/' then SetLength(s, Length(s) - 5); + chapterLinks.Add(s); + chapterName.Add(title); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + regx.Free; + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Query: TXQueryEngineHTML; + Container: TTaskContainer; + v: IXQValue; + rurl: String; + p: Integer; + nextpage: Boolean; + regx: TRegExpr; + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + with Container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + rurl := AppendURLDelim(FillHost(Module.RootURL, URL)); + Source := TStringList.Create; + regx:=TRegExpr.Create; + try + regx.ModifierI := True; + regx.Expression := '/page/\d+/?$'; + if regx.Exec(rurl) then rurl := regx.Replace(rurl, '/', False); + if RightStr(rurl, 5) = 'view/' then SetLength(rurl, Length(rurl) - 5); + if RightStr(rurl, 5) <> 'page/' then rurl += 'page/'; + if Pos('/albums/', rurl) > 0 then + rurl := StringReplace(rurl, '/albums/', '/pictures/album/', []); + Query := TXQueryEngineHTML.Create; + try + regx.Expression := '\.\d+x\d+(\.\w+)$'; + p := 1; + nextpage := True; + while nextpage do begin + nextpage := False; + if GetPage(DownloadThread.FHTTP, TObject(Source), rurl + IntToStr(p) + '/', + Manager.retryConnect) then + begin + Result := True; + Query.ParseHTML(Source.Text); + for v in Query.XPath('//*[@class="picture_page"]//img/@src') do begin + s := TrimLeftChar(v.toString, ['/']); + if regx.Exec(s) then s := regx.Replace(s, '$1', True); + Container.PageLinks.Add(s); + end; + if Query.XPathString('//*[@id="next_page"]//a/@href') <> '' then begin + Inc(p); + nextpage := True; + end; + end; + end; + finally + Query.Free; + end; + finally + regx.Free; + Source.Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Luscious'; + RootURL := 'http://luscious.net/'; + SortedList := True; + FavoriteAvailable := False; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From 495e476faf8362525ff4d96abcd99ebe53c1f790 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 13:08:50 +0800 Subject: [PATCH 0577/2794] add luscious to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index afaa99622..91aa98b51 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -19,4 +19,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,Fakku,HakiHome,Hentai2Read,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,Fakku,HakiHome,Hentai2Read,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From b86c788f40a4bef2f4723f2f71d0d3ab43be651d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 13:22:55 +0800 Subject: [PATCH 0578/2794] downloadmanager, reset pagelink thread terminated during getpagenumber, in case not all page loaded for multi paged view --- baseunits/uDownloadsManager.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 0ae42e65a..40fbf0d28 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1402,7 +1402,11 @@ procedure TTaskThread.Execute; container.Status := STATUS_PREPARE; CheckOut; WaitForThreads; - if Terminated then Exit; + if Terminated then begin + container.PageLinks.Clear; + container.PageNumber := 0; + Exit; + end; end; //Check file, if exist set mark 'D', otherwise 'W' or 'G' for dynamic image url From 63e5d011cb5a15a7e9aa3fd01c942185044f981a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Aug 2015 13:34:20 +0800 Subject: [PATCH 0579/2794] Bump version 0.9.23.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index b6be395a3..4e5db25b4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,13 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.23.0 (26-08-2015) +[*] E-Hentai: fix image URL on multiple page +[-] Drop support for SenMangaRAW +[+] Added MangaLife(EN) +[+] Added Luscious(H) +[*] Various changes and bug fixes + 0.9.22.1 (21-08-2015) [*] E-Hentai: fix image url [*] MangaIndo: remove automatically added chapter number diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 389954bfa..8e63121dc 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="22"/> - <BuildNr Value="1"/> + <RevisionNr Value="23"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index dfa6d0d5d..9d0fec49b 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.22.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.22.1/fmd_0.9.22.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.22.1/fmd_0.9.22.1_Win64.7z +VERSION=0.9.23.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.23.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.23.0_Win64.7z From 3ad1e52dea1b9152a509c914dc4f88458a68ad95 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 10 Nov 2015 21:20:00 +0800 Subject: [PATCH 0580/2794] cleanup --- mangadownloader/md.lpi | 8 -------- mangadownloader/md.lpr | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8e63121dc..7f7817e18 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,9 +22,6 @@ <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> - <MacroValues Count="1"> - <Macro1 Name="LCLWidgetType" Value="win32"/> - </MacroValues> <BuildModes Count="5"> <Item1 Name="Win32" Default="True"/> <Item2 Name="Win64"> @@ -215,11 +212,6 @@ </Other> </CompilerOptions> </Item5> - <SharedMatrixOptions Count="3"> - <Item1 ID="004106748078" Modes="Win32" Type="IDEMacro" MacroName="LCLWidgetType" Value="win32"/> - <Item2 ID="255873403449" Type="IDEMacro" MacroName="LCLWidgetType" Value="gtk2"/> - <Item3 ID="733756013539" Modes="Win32 Debug Leaks,Win64 Debug,Win32,Win64,Win32 Debug" Value="-dEnableUTF8RTL"/> - </SharedMatrixOptions> </BuildModes> <PublishOptions> <Version Value="2"/> diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 120a9ef8d..614257f16 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -14,7 +14,7 @@ cthreads, {$ENDIF} {$ENDIF} - Forms, LazFileUtils, TAChartLazarusPkg, Interfaces, simpleipc, IniFiles, + Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, uBaseUnit, frmMain; var From c097bdcf710a105d8fad12a4f8f41cfcabc384d7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Nov 2015 09:55:00 +0800 Subject: [PATCH 0581/2794] fix check table exist --- baseunits/uData.pas | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index ccab6d36e..27a0879a8 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -758,8 +758,13 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; ts := TStringList.Create; try FConn.GetTableNames(ts); - ts.Sort; - Result := ts.Find(ATableName, i); + if ts.Count > 0 then + for i := 0 to ts.Count - 1 do + if SameText(ts[i], ATableName) then + begin + Result := True; + Break; + end; finally ts.Free; end; From 1c25cc1be837ee984da655163a312a814b9b732c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Nov 2015 10:35:36 +0800 Subject: [PATCH 0582/2794] fix new manga time not saved fix #109 --- baseunits/uBaseUnit.pas | 3 ++- mangadownloader/forms/frmMain.pas | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4d1957ba2..48f081865 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -655,7 +655,8 @@ interface OptionAutoCheckLatestVersion: Boolean = True; OptionAutoCheckFavStartup: Boolean = True; OptionAutoCheckFavInterval: Boolean = True; - OptionAutoCheckFavIntervalMinutes: Cardinal = 0; + OptionAutoCheckFavIntervalMinutes: Cardinal = 60; + OptionNewMangaTime: Cardinal = 1; OptionAutoCheckFavDownload: Boolean = False; OptionAutoCheckFavRemoveCompletedManga: Boolean = False; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e37a41851..75ac768bf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2385,7 +2385,7 @@ procedure TMainForm.btFilterClick(Sender: TObject); edFilterArtists.Text, IntToStr(cbFilterStatus.ItemIndex), edFilterSummary.Text, - seOptionNewMangaTime.Value, + OptionNewMangaTime, rbAll.Checked, cbOnlyNew.Checked) then begin @@ -2405,7 +2405,7 @@ procedure TMainForm.btFilterClick(Sender: TObject); edFilterArtists.Text, IntToStr(cbFilterStatus.ItemIndex), edFilterSummary.Text, - seOptionNewMangaTime.Value, + OptionNewMangaTime, rbAll.Checked, cbOnlyNew.Checked, cbUseRegExpr.Checked); @@ -3939,7 +3939,7 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; if miHighlightNewManga.Checked then begin if Assigned(Node) then - if StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - seOptionNewMangaTime.Value) then + if StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - OptionNewMangaTime) then begin TargetCanvas.Brush.Color := CL_HLBlueMarks; TargetCanvas.FillRect(CellRect); @@ -4349,6 +4349,7 @@ procedure TMainForm.LoadOptions; seOptionAutoCheckFavIntervalMinutes.Value := ReadInteger('update', 'AutoCheckFavIntervalMinutes', 60); lbOptionAutoCheckFavIntervalMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionAutoCheckFavIntervalMinutes.Value]); cbOptionAutoCheckFavIntervalChange(cbOptionAutoCheckFavInterval); + seOptionNewMangaTime.Value := ReadInteger('update', 'NewMangaTime', 1); cbOptionAutoCheckFavDownload.Checked := ReadBool('update', 'AutoCheckFavAutoDownload', False); cbOptionAutoCheckFavRemoveCompletedManga.Checked := ReadBool('update', 'AutoCheckFavAutoRemoveCompletedManga', False); cbOptionUpdateListNoMangaInfo.Checked := ReadBool('update', 'UpdateListNoMangaInfo', False); @@ -4417,7 +4418,6 @@ procedure TMainForm.SaveOptions; if cbLanguages.ItemIndex > -1 then WriteString('languages', 'Selected', AvailableLanguages.Names[cbLanguages.ItemIndex]); WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); - WriteInteger('general', 'NewMangaTime', seOptionNewMangaTime.Value); WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); WriteString('general', 'ExternalProgramPath', edOptionExternalPath.FileName); WriteString('general', 'ExternalProgramParams', edOptionExternalParams.Text); @@ -4467,6 +4467,7 @@ procedure TMainForm.SaveOptions; WriteBool('update', 'AutoCheckFavStartup', cbOptionAutoCheckFavStartup.Checked); WriteBool('update', 'AutoCheckFavInterval', cbOptionAutoCheckFavInterval.Checked); WriteInteger('update', 'AutoCheckFavIntervalMinutes', seOptionAutoCheckFavIntervalMinutes.Value); + WriteInteger('update', 'NewMangaTime', seOptionNewMangaTime.Value); WriteBool('update', 'AutoCheckFavAutoDownload', cbOptionAutoCheckFavDownload.Checked); WriteBool('update', 'AutoCheckFavAutoRemoveCompletedManga', cbOptionAutoCheckFavRemoveCompletedManga.Checked); WriteBool('update', 'UpdateListNoMangaInfo', cbOptionUpdateListNoMangaInfo.Checked); @@ -4600,6 +4601,7 @@ procedure TMainForm.ApplyOptions; OptionAutoCheckFavStartup := cbOptionAutoCheckFavStartup.Checked; OptionAutoCheckFavInterval := cbOptionAutoCheckFavInterval.Checked; OptionAutoCheckFavIntervalMinutes := seOptionAutoCheckFavIntervalMinutes.Value; + OptionNewMangaTime := seOptionNewMangaTime.Value; OptionAutoCheckFavDownload := cbOptionAutoCheckFavDownload.Checked; OptionAutoCheckFavRemoveCompletedManga := cbOptionAutoCheckFavRemoveCompletedManga.Checked; OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; From 6c510d7011eb9e70484fb9b73178bf5b16e34e08 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 09:25:14 +0800 Subject: [PATCH 0583/2794] ehentai, fix get new imageurl when failed --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 5baed6ed2..1f3a1c9d4 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -276,7 +276,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; iurl := Query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, - Name, Prefix, reconnect); + Name, Prefix); if DownloadThread.IsTerminated then Break; if not Result then begin From eee0b380f1b72aee505070344685d57fb8f2ba01 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 11:39:57 +0800 Subject: [PATCH 0584/2794] baseunits, add cleanstring function --- baseunits/uBaseUnit.pas | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 48f081865..288168d86 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -882,6 +882,7 @@ function HTMLDecode(const AStr: String): String; function RemoveSymbols(const input: String): String; function CorrectPathSys(const Path: String): String; +function CleanString(const S: String): String; function CleanAndExpandURL(const URL: String): String; function CleanURL(const URL: String): String; function AppendURLDelim(const URL: String): String; @@ -2315,6 +2316,15 @@ function SetParams(const input: array of String): String; Result := Result + input[i] + SEPERATOR; end; +function CleanString(const S: String): String; +begin + Result := Trim(S); + Result := StringReplace(Result, #13, '', [rfReplaceAll]); + Result := StringReplace(Result, #10, '', [rfReplaceAll]); + while Pos(' ', Result) > 0 do + Result := StringReplace(Result, ' ', ' ', [rfReplaceAll]); +end; + function CleanAndExpandURL(const URL: String): String; begin Result := AppendURLDelim(CleanURL(URL)); From f098f6cbbd680ac167cdeec437d7cf135a68f3ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 12:44:33 +0800 Subject: [PATCH 0585/2794] websitemodules, fix taskstart doesn't return valid value --- baseunits/WebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index b6a664901..a4112960b 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -400,7 +400,7 @@ function TWebsiteModules.TaskStart(var Task: TTaskContainer; function TWebsiteModules.TaskStart(var Task: TTaskContainer; const Website: String): Boolean; begin - TaskStart(Task, LocateModule(Website)); + Result := TaskStart(Task, LocateModule(Website)); end; function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; From e955dd97014a42b7ea52b9c6c349f70b80cd35e2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 13:02:20 +0800 Subject: [PATCH 0586/2794] remove mangahere #115 --- .../MangaHere/chapter_page_number.inc | 35 ---- baseunits/includes/MangaHere/image_url.inc | 45 ----- .../includes/MangaHere/manga_information.inc | 100 ---------- .../includes/MangaHere/names_and_links.inc | 35 ---- baseunits/uBaseUnit.pas | 180 +++++++++--------- baseunits/uData.pas | 10 - baseunits/uDownloadsManager.pas | 10 - 7 files changed, 88 insertions(+), 327 deletions(-) delete mode 100644 baseunits/includes/MangaHere/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaHere/image_url.inc delete mode 100644 baseunits/includes/MangaHere/manga_information.inc delete mode 100644 baseunits/includes/MangaHere/names_and_links.inc diff --git a/baseunits/includes/MangaHere/chapter_page_number.inc b/baseunits/includes/MangaHere/chapter_page_number.inc deleted file mode 100644 index 494ba9677..000000000 --- a/baseunits/includes/MangaHere/chapter_page_number.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetMangaHerePageNumber: Boolean; - var - i, j: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAHERE_ID, URL), - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if GetTagName(parse.Strings[i]) = 'option' then - begin - j := i; - while GetTagName(parse.Strings[j]) = 'option' do - begin - Inc(manager.container.pageNumber); - Inc(j, 4); - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaHere/image_url.inc b/baseunits/includes/MangaHere/image_url.inc deleted file mode 100644 index 95e2ef991..000000000 --- a/baseunits/includes/MangaHere/image_url.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetMangaHereImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - if workCounter > 0 then - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAHERE_ID, URL) + - IntToStr(workCounter + 1) + '.html', - manager.container.Manager.retryConnect) - else - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAHERE_ID, URL), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if Pos('class="read_img"', parse.Strings[i]) <> 0 then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i + 4], 'src')); - parse.Free; - l.Free; - Exit; - end; - //for c:= 'a' to 'z' do - // if (Pos('http://'+c+'.mhcdn.net/store/', parse.Strings[i])<>0) then - // begin - // manager.container.PageLinks.Strings[workCounter]:= GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - // parse.Free; - // l.Free; - // exit; - // end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaHere/manga_information.inc b/baseunits/includes/MangaHere/manga_information.inc deleted file mode 100644 index 5cc5f3413..000000000 --- a/baseunits/includes/MangaHere/manga_information.inc +++ /dev/null @@ -1,100 +0,0 @@ - function GetMangaHereInfoFromURL: Byte; - var - i, j: LongInt; - isGetChapters: Boolean = False; - begin - mangaInfo.url := FillMangaSiteHost(MANGAHERE_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAHERE_ID, 0]; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i + 1], 'Manga - Read ', ' Online at '); - - // get cover link - if GetTagName(parse[i]) = 'img' then - if (GetAttributeValue(GetTagAttribute(parse[i], 'class=')) = 'img') then - mangaInfo.coverLink := - GetAttributeValue(GetTagAttribute(parse[i], 'src')); - - // get summary - if (Pos('id="show"', parse[i])) <> 0 then - begin - parse[i + 1] := StringFilter(parse[i + 1]); - parse[i + 1] := StringReplace(parse[i + 1], #10, '\n', [rfReplaceAll]); - parse[i + 1] := StringReplace(parse[i + 1], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse[i + 1]; - end; - - // get authors - if (Pos('Author(s):', parse[i]) <> 0) then - mangaInfo.authors := parse[i + 3]; - - // get artists - if (Pos('Artist(s):', parse[i]) <> 0) then - mangaInfo.artists := parse[i + 3]; - - // get genres - if (Pos('Genre(s):', parse[i]) <> 0) then - mangaInfo.genres := Trim(parse[i + 2]); - - // get status - if (Pos('Status:', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - if Pos('Completed', parse[i + 2]) <> 0 then - mangaInfo.status := '0'; // completed - end; - - // get chapters - if (Pos('<div', parse[i]) <> 0) and (Pos('class="detail_list', parse[i]) <> 0) then - isGetChapters := True; - if isGetChapters and (Pos('class="tab_comment clearfix', parse[i]) <> 0) then - isGetChapters := False; - if isGetChapters and - (Pos('<a', parse[i]) <> 0) and (Pos('class="color_', parse[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - for j := i + 2 to parse.Count - 1 do - begin - if (Pos('class="right', parse[j]) <> 0) or (Pos('class="new', parse[j]) <> 0) then - Break; - if Pos('<', parse[j]) = 0 then - parse[i + 1] := Trim(parse[i + 1]) + ' ' + Trim(parse[j]); - end; - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - - // invert chapters - if mangainfo.ChapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaHere/names_and_links.inc b/baseunits/includes/MangaHere/names_and_links.inc deleted file mode 100644 index 25ff05685..000000000 --- a/baseunits/includes/MangaHere/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function MangaHereGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAHERE_ID, 1] + - MANGAHERE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('manga_info', parse.Strings[i]) <> 0 then - begin - Result := NO_ERROR; - names.Add(StringFilter(GetString(parse.Strings[i], 'rel="', '" href'))); - links.Add(StringReplace(GetString(parse.Strings[i], 'href="', '">'), - WebsiteRoots[MANGAHERE_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 288168d86..f3efea35a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -263,97 +263,95 @@ interface REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; ANIMEA_ID = 0; - MANGAHERE_ID = 1; - MANGAINN_ID = 2; - OURMANGA_ID = 3; - KISSMANGA_ID = 4; - MANGA24H_ID = 5; - VNSHARING_ID = 6; - HENTAI2READ_ID = 7; - FAKKU_ID = 8; - TRUYEN18_ID = 9; - MANGAPARK_ID = 10; - MANGATRADERS_ID = 11; - MANGAEDEN_ID = 12; - PERVEDEN_ID = 13; - TRUYENTRANHTUAN_ID = 14; - TURKCRAFT_ID = 15; - MANGAVADISI_ID = 16; - MANGAFRAME_ID = 17; - EATMANGA_ID = 18; - STARKANA_ID = 19; - REDHAWKSCANS_ID = 20; - BLOGTRUYEN_ID = 21; - KOMIKID_ID = 22; - SUBMANGA_ID = 23; - ESMANGAHERE_ID = 24; - ANIMEEXTREMIST_ID = 25; - HUGEMANGA_ID = 26; - S2SCAN_ID = 27; - SENMANGA_ID = 28; - IMANHUA_ID = 29; - MABUNS_ID = 30; - MANGAESTA_ID = 31; - CENTRALDEMANGAS_ID = 32; - EGSCANS_ID = 33; - MANGAAR_ID = 34; - MANGAAE_ID = 35; - ANIMESTORY_ID = 36; - LECTUREENLIGNE_ID = 37; - SCANMANGA_ID = 38; - MANGAGO_ID = 39; - DM5_ID = 40; - PURURIN_ID = 41; - MANGACOW_ID = 42; - KIVMANGA_ID = 43; - MEINMANGA_ID = 44; - MANGASPROJECT_ID = 45; - MANGAREADER_POR_ID = 46; - MANGA2U_ID = 47; - MANGASTREAMTO_ID = 48; - NINEMANGA_ID = 49; - NINEMANGA_ES_ID = 50; - NINEMANGA_CN_ID = 51; - NINEMANGA_RU_ID = 52; - NINEMANGA_DE_ID = 53; - NINEMANGA_IT_ID = 54; - NINEMANGA_BR_ID = 55; - JAPANSHIN_ID = 56; - JAPSCAN_ID = 57; - CENTRUMMANGI_PL_ID = 58; - MANGALIB_PL_ID = 59; - ONEMANGA_ID = 60; - MANGATOWN_ID = 61; - MANGAOKU_ID = 62; - MYREADINGMANGAINFO_ID = 63; - IKOMIK_ID = 64; - NHENTAI_ID = 65; - UNIONMANGAS_ID = 66; - MANGAMINT_ID = 67; - UNIXMANGA_ID = 68; - HAKIHOME_ID = 69; - EXTREMEMANGAS_ID = 70; - MANGAHOST_ID = 71; - PORNCOMIX_ID = 72; - PORNCOMIXRE_ID = 73; - PORNCOMIXIC_ID = 74; - XXCOMICS_ID = 75; - XXCOMICSMT_ID = 76; - XXCOMICS3D_ID = 77; - PORNXXXCOMICS_ID = 78; - MANGASEE_ID = 79; - MANGAKU_ID = 80; - ACADEMYVN_ID = 81; - MANGAAT_ID = 82; - SENMANGARAW_ID = 83; - READMANGATODAY_ID = 84; - LONEMANGA_ID = 85; - DYNASTYSCANS_ID = 86; - MADOKAMI_ID = 87; - - WebsiteRoots: array [0..87] of array [0..1] of string = ( + MANGAINN_ID = 1; + OURMANGA_ID = 2; + KISSMANGA_ID = 3; + MANGA24H_ID = 4; + VNSHARING_ID = 5; + HENTAI2READ_ID = 6; + FAKKU_ID = 7; + TRUYEN18_ID = 8; + MANGAPARK_ID = 9; + MANGATRADERS_ID = 10; + MANGAEDEN_ID = 11; + PERVEDEN_ID = 12; + TRUYENTRANHTUAN_ID = 13; + TURKCRAFT_ID = 14; + MANGAVADISI_ID = 15; + MANGAFRAME_ID = 16; + EATMANGA_ID = 17; + STARKANA_ID = 18; + REDHAWKSCANS_ID = 19; + BLOGTRUYEN_ID = 20; + KOMIKID_ID = 21; + SUBMANGA_ID = 22; + ESMANGAHERE_ID = 23; + ANIMEEXTREMIST_ID = 24; + HUGEMANGA_ID = 25; + S2SCAN_ID = 26; + SENMANGA_ID = 27; + IMANHUA_ID = 28; + MABUNS_ID = 29; + MANGAESTA_ID = 30; + CENTRALDEMANGAS_ID = 31; + EGSCANS_ID = 32; + MANGAAR_ID = 33; + MANGAAE_ID = 34; + ANIMESTORY_ID = 35; + LECTUREENLIGNE_ID = 36; + SCANMANGA_ID = 37; + MANGAGO_ID = 38; + DM5_ID = 39; + PURURIN_ID = 40; + MANGACOW_ID = 41; + KIVMANGA_ID = 42; + MEINMANGA_ID = 43; + MANGASPROJECT_ID = 44; + MANGAREADER_POR_ID = 45; + MANGA2U_ID = 46; + MANGASTREAMTO_ID = 47; + NINEMANGA_ID = 48; + NINEMANGA_ES_ID = 49; + NINEMANGA_CN_ID = 50; + NINEMANGA_RU_ID = 51; + NINEMANGA_DE_ID = 52; + NINEMANGA_IT_ID = 53; + NINEMANGA_BR_ID = 54; + JAPANSHIN_ID = 55; + JAPSCAN_ID = 56; + CENTRUMMANGI_PL_ID = 57; + MANGALIB_PL_ID = 58; + ONEMANGA_ID = 59; + MANGATOWN_ID = 60; + MANGAOKU_ID = 61; + MYREADINGMANGAINFO_ID = 62; + IKOMIK_ID = 63; + NHENTAI_ID = 64; + UNIONMANGAS_ID = 65; + MANGAMINT_ID = 66; + UNIXMANGA_ID = 67; + HAKIHOME_ID = 68; + EXTREMEMANGAS_ID = 69; + MANGAHOST_ID = 70; + PORNCOMIX_ID = 71; + PORNCOMIXRE_ID = 72; + PORNCOMIXIC_ID = 73; + XXCOMICS_ID = 74; + XXCOMICSMT_ID = 75; + XXCOMICS3D_ID = 76; + PORNXXXCOMICS_ID = 77; + MANGASEE_ID = 78; + MANGAKU_ID = 79; + ACADEMYVN_ID = 80; + MANGAAT_ID = 81; + SENMANGARAW_ID = 82; + READMANGATODAY_ID = 83; + LONEMANGA_ID = 84; + DYNASTYSCANS_ID = 85; + MADOKAMI_ID = 86; + + WebsiteRoots: array [0..86] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), - ('MangaHere', 'http://www.mangahere.co'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), ('KissManga', 'http://kissmanga.com'), @@ -447,8 +445,6 @@ interface ANIMEA_BROWSER = '/browse.html?page='; ANIMEA_SKIP = '?skip=1'; - MANGAHERE_BROWSER = '/mangalist/'; - MANGAINN_BROWSER = '/mangalist/'; OURMANGA_BROWSER = '/directory/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 27a0879a8..276e69bfc 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2188,8 +2188,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/AnimeA/names_and_links.inc} - {$I includes/MangaHere/names_and_links.inc} - {$I includes/EsMangaHere/names_and_links.inc} {$I includes/AnimExtremist/names_and_links.inc} @@ -2344,9 +2342,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[ANIMEA_ID, 0] then Result := AnimeAGetNamesAndLinks else - if website = WebsiteRoots[MANGAHERE_ID, 0] then - Result := MangaHereGetNamesAndLinks - else if website = WebsiteRoots[MANGAINN_ID, 0] then Result := MangaInnGetNamesAndLinks else @@ -2595,8 +2590,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/AnimeA/manga_information.inc} - {$I includes/MangaHere/manga_information.inc} - // due to its weird designs, this will take a lot of work (and time) for it to // work property @@ -2765,9 +2758,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[ANIMEA_ID, 0] then Result := GetAnimeAInfoFromURL else - if website = WebsiteRoots[MANGAHERE_ID, 0] then - Result := GetMangaHereInfoFromURL - else if website = WebsiteRoots[MANGAINN_ID, 0] then Result := GetMangaInnInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 40fbf0d28..fe3cc0e1a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -403,8 +403,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaGo/chapter_page_number.inc} - {$I includes/MangaHere/chapter_page_number.inc} - {$I includes/MangaInn/chapter_page_number.inc} {$I includes/MangaPark/chapter_page_number.inc} @@ -500,9 +498,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAPageNumber else - if manager.container.MangaSiteID = MANGAHERE_ID then - Result := GetMangaHerePageNumber - else if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnPageNumber else @@ -736,8 +731,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaGo/image_url.inc} - {$I includes/MangaHere/image_url.inc} - {$I includes/MangaInn/image_url.inc} //{$I includes/MangaPark/image_url.inc} @@ -822,9 +815,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGATRADERS_ID then Result := GetMangaTradersImageURL else - if manager.container.MangaSiteID = MANGAHERE_ID then - Result := GetMangaHereImageURL - else if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnImageURL else From 687dc03d9126546689a69c01a6a26b262be50cc9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 13:02:40 +0800 Subject: [PATCH 0587/2794] rewrite mangahere script fix #115 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaHere.pas | 181 ++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaHere.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 729502575..cf32e0aa8 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -11,4 +11,5 @@ uses MangaReader, MangaStream, MangaLife, - Luscious; + Luscious, + MangaHere; diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas new file mode 100644 index 000000000..f1ecac3e5 --- /dev/null +++ b/baseunits/modules/MangaHere.pas @@ -0,0 +1,181 @@ +unit MangaHere; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, synautil; + +implementation + +const + dirURL = '/mangalist/'; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + v: IXQValue; +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + for v in Query.XPath('//a[@class="manga_info"]') do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + info: TMangaInfo; + v: IXQValue; + s: String; +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + with info do begin + coverLink := Query.XPathString('//*[@class="manga_detail"]//img[@class="img"]/@src'); + title := Query.XPathString('//h1[@class="title"]'); + for v in Query.XPath('//*[@class="detail_topText"]/li') do begin + s := v.toString; + if Pos('Author(s):', s) = 1 then authors := SeparateRight(s, ':') + else if Pos('Artist(s):', s) = 1 then artists := SeparateRight(s, ':') + else if Pos('Genre(s):', s) = 1 then artists := SeparateRight(s, ':') + else if Pos('Status:', s) = 1 then begin + if Pos('Ongoing', s) > 0 then status := '1' + else status := '0'; + end; + end; + summary := Query.XPathString('//*[@class="detail_topText"]/li/p[@id="show"]/text()'); + for v in Query.XPath('//*[@class="detail_list"]/ul/li/span[@class="left"]/a/@href') do + chapterLinks.Add(v.toString); + for v in Query.XPath('//*[@class="detail_list"]/ul/li/span[@class="left"]') do + chapterName.Add(CleanString(v.toString)); + InvertStrings([chapterLinks, chapterName]); + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Query: TXQueryEngineHTML; + Container: TTaskContainer; +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + with Container do begin + Source := TStringList.Create; + try + if GetPage(DownloadThread.FHTTP, TObject(Source), + AppendURLDelim(FillHost(Module.RootURL, URL)), Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + PageNumber := + Query.XPath('//section[@class="readpage_top"]//span[@class="right"]/select/option').Count; + finally + Query.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Query: TXQueryEngineHTML; + rurl: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do begin + Source := TStringList.Create; + try + rurl := AppendURLDelim(FillHost(Module.RootURL, URL)); + if DownloadThread.workCounter > 0 then + rurl += IncStr(DownloadThread.workCounter) + '.html'; + if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + PageLinks[DownloadThread.workCounter] := + Query.XPathString('//*[@id="viewer"]//img[@id="image"]/@src'); + finally + Query.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaHere'; + RootURL := 'http://www.mangahere.co/'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From c6cf1da328d7988d8e28d11c01ff2d20da0aa5f1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 13:48:19 +0800 Subject: [PATCH 0588/2794] added option to remove manga name from chapter close #111 --- baseunits/uBaseUnit.pas | 1 + baseunits/uData.pas | 18 +- mangadownloader/forms/frmMain.lfm | 516 +++++++++++++------------ mangadownloader/forms/frmMain.pas | 5 + mangadownloader/languages/fmd.en.po | 9 +- mangadownloader/languages/fmd.id_ID.po | 10 +- mangadownloader/languages/fmd.po | 9 +- 7 files changed, 305 insertions(+), 263 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f3efea35a..25bd272c1 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -661,6 +661,7 @@ interface OptionHTTPUseGzip: Boolean = True; + OptionRemoveMangaNameFromChapter: Boolean = False; type TArrayOfString = array of string; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 276e69bfc..764980a53 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2581,7 +2581,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reconnect: Integer): Byte; var - s: String; + s, s2: String; j, k: Integer; del: Boolean; Source: TStringList; @@ -3055,6 +3055,22 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; mangaInfo.chapterName.Strings[j] := Trim(RemoveStringBreaks( CommonStringFilter(mangaInfo.chapterName[j]))); end; + + //remove manga name from chapter + if OptionRemoveMangaNameFromChapter and (mangaInfo.title <> '') then + begin + s := LowerCase(mangaInfo.title); + j := Length(s); + for k := 0 to mangaInfo.chapterName.Count - 1 do begin + s2 := LowerCase(mangaInfo.chapterName[k]); + if Length(s2) > j then + if Pos(s, s2) = 1 then begin + s2 := mangaInfo.chapterName[k]; + Delete(s2, 1, j); + mangaInfo.chapterName[k] := Trim(s2); + end; + end; + end; end; mangaInfo.numChapter := mangaInfo.chapterLinks.Count; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9bbed75e5..76f653b69 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,11 +1,12 @@ object MainForm: TMainForm Left = 273 - Height = 575 + Height = 616 Top = 96 Width = 819 + ActiveControl = pcMain Align = alBottom Caption = 'Free Manga Downloader' - ClientHeight = 575 + ClientHeight = 616 ClientWidth = 819 OnClose = FormClose OnCreate = FormCreate @@ -13,10 +14,11 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange LCLVersion = '1.5' + Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 - Top = 545 + Top = 586 Width = 819 AutoSize = False Panels = < @@ -32,7 +34,7 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 508 + Height = 549 Top = 11 Width = 614 ActivePage = tsDownload @@ -46,11 +48,11 @@ object MainForm: TMainForm OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 object vtDownload: TVirtualStringTree Left = 2 - Height = 445 + Height = 486 Top = 32 Width = 600 Align = alClient @@ -269,7 +271,7 @@ object MainForm: TMainForm Height = 480 Top = 0 Width = 606 - HorzScrollBar.Page = 214 + HorzScrollBar.Page = 218 VertScrollBar.Page = 317 Align = alClient BorderStyle = bsNone @@ -1822,11 +1824,11 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 object pnOptions: TPageControl Left = 9 - Height = 403 + Height = 444 Top = 8 Width = 587 ActivePage = tsGeneral @@ -1836,7 +1838,7 @@ object MainForm: TMainForm TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 object cbLanguages: TComboBox Left = 20 @@ -2093,7 +2095,7 @@ object MainForm: TMainForm Top = 0 Width = 579 HorzScrollBar.Page = 457 - VertScrollBar.Page = 179 + VertScrollBar.Page = 304 Align = alClient BorderStyle = bsNone ClientHeight = 375 @@ -2321,109 +2323,215 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 - object rgOptionCompress: TRadioGroup - Left = 20 - Height = 60 - Top = 66 - Width = 520 - Anchors = [akTop, akLeft, akRight] - AutoFill = True - Caption = 'Save downloaded chapters as' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.EnlargeVertical = crsHomogenousChildResize - ChildSizing.ShrinkHorizontal = crsScaleChilds - ChildSizing.ShrinkVertical = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 4 - ClientHeight = 40 - ClientWidth = 516 - Columns = 4 - ItemIndex = 0 - Items.Strings = ( - 'None' - 'ZIP' - 'CBZ' - 'PDF' - ) - ParentFont = False + object sbSaveTo: TScrollBox + Left = 0 + Height = 416 + Top = 0 + Width = 579 + HorzScrollBar.Page = 544 + VertScrollBar.Page = 400 + Align = alClient + BorderStyle = bsNone + ClientHeight = 416 + ClientWidth = 579 TabOrder = 0 - end - object gbOptionRenaming: TGroupBox - Left = 20 - Height = 196 - Top = 170 - Width = 520 - Anchors = [akTop, akLeft, akRight] - Caption = 'Renaming' - ClientHeight = 176 - ClientWidth = 516 - ParentFont = False - TabOrder = 1 - object cbOptionGenerateMangaFolderName: TCheckBox - Left = 22 - Height = 19 - Top = 36 - Width = 261 - Caption = 'Auto generate folder based on manga''s name' + object rgOptionCompress: TRadioGroup + Left = 20 + Height = 60 + Top = 66 + Width = 520 + Anchors = [akTop, akLeft, akRight] + AutoFill = True + Caption = 'Save downloaded chapters as' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 4 + ClientHeight = 40 + ClientWidth = 516 + Columns = 4 + ItemIndex = 0 + Items.Strings = ( + 'None' + 'ZIP' + 'CBZ' + 'PDF' + ) ParentFont = False TabOrder = 0 end - object cbOptionGenerateChapterName: TCheckBox - Left = 294 - Height = 19 - Top = 52 - Width = 246 - Caption = 'Generate chapter folder with chapter name' + object gbOptionRenaming: TGroupBox + Left = 20 + Height = 230 + Top = 170 + Width = 520 + Anchors = [akTop, akLeft, akRight] + Caption = 'Renaming' + ClientHeight = 210 + ClientWidth = 516 ParentFont = False TabOrder = 1 - Visible = False + object cbOptionRemoveMangaNameFromChapter: TCheckBox + Left = 22 + Height = 19 + Top = 10 + Width = 208 + Caption = 'Remove manga name from chapter' + ParentFont = False + TabOrder = 9 + end + object cbOptionGenerateMangaFolderName: TCheckBox + Left = 22 + Height = 19 + Top = 54 + Width = 261 + Caption = 'Auto generate folder based on manga''s name' + ParentFont = False + TabOrder = 0 + end + object cbOptionGenerateChapterName: TCheckBox + Left = 294 + Height = 19 + Top = 70 + Width = 246 + Caption = 'Generate chapter folder with chapter name' + ParentFont = False + TabOrder = 1 + Visible = False + end + object cbOptionPathConvert: TCheckBox + Left = 22 + Height = 19 + Top = 32 + Width = 517 + Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' + ParentFont = False + TabOrder = 2 + end + object cbOptionAutoNumberChapter: TCheckBox + Left = 294 + Height = 19 + Top = 54 + Width = 134 + Caption = 'Auto number chapter' + TabOrder = 3 + Visible = False + end + object edOptionCustomRename: TEdit + Left = 22 + Height = 23 + Top = 158 + Width = 434 + Anchors = [akTop, akLeft, akRight] + TabOrder = 4 + TextHint = 'Custom rename' + end + object lbOptionCustomRename: TLabel + Left = 22 + Height = 15 + Top = 142 + Width = 112 + Caption = 'Chapter folder name:' + ParentColor = False + end + object lbOptionCustomRenameHint: TLabel + Left = 462 + Height = 15 + Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' + Top = 160 + Width = 13 + Anchors = [akTop, akRight] + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object lbOptionRenameDigits: TLabel + Left = 22 + Height = 15 + Top = 86 + Width = 78 + Caption = 'Rename digits' + ParentColor = False + end + object seOptionDigitVolume: TSpinEdit + Left = 94 + Height = 23 + Top = 108 + Width = 50 + MaxValue = 10 + MinValue = 1 + TabOrder = 5 + Value = 1 + end + object seOptionDigitChapter: TSpinEdit + Left = 230 + Height = 23 + Top = 108 + Width = 50 + MaxValue = 10 + MinValue = 1 + TabOrder = 6 + Value = 1 + end + object cbOptionDigitVolume: TCheckBox + Left = 25 + Height = 19 + Top = 110 + Width = 61 + Caption = 'Volume' + OnChange = cbOptionDigitVolumeChange + TabOrder = 7 + end + object cbOptionDigitChapter: TCheckBox + Left = 158 + Height = 19 + Top = 110 + Width = 62 + Caption = 'Chapter' + OnChange = cbOptionDigitChapterChange + TabOrder = 8 + end end - object cbOptionPathConvert: TCheckBox - Left = 22 - Height = 19 - Top = 14 - Width = 517 - Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' + object seOptionPDFQuality: TSpinEdit + Left = 44 + Height = 23 + Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' + Top = 132 + Width = 50 + MinValue = 5 ParentFont = False + ParentShowHint = False + ShowHint = True TabOrder = 2 + Value = 100 end - object cbOptionAutoNumberChapter: TCheckBox - Left = 294 - Height = 19 - Top = 36 - Width = 134 - Caption = 'Auto number chapter' - TabOrder = 3 - Visible = False - end - object edOptionCustomRename: TEdit - Left = 22 - Height = 23 - Top = 140 - Width = 434 - Anchors = [akTop, akLeft, akRight] - TabOrder = 4 - TextHint = 'Custom rename' - end - object lbOptionCustomRename: TLabel - Left = 22 + object lbOptionPDFQuality: TLabel + Left = 103 Height = 15 - Top = 124 - Width = 112 - Caption = 'Chapter folder name:' + Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' + Top = 135 + Width = 119 + Caption = 'PDF compression level' ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True end - object lbOptionCustomRenameHint: TLabel - Left = 462 + object lbOptionCustomRenameHint1: TLabel + Left = 260 Height = 15 - Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' - Top = 142 + Hint = '100: FlateEncode (lossless), lower: DCTEncode (lossy)' + Top = 135 Width = 13 - Anchors = [akTop, akRight] Caption = '[?]' Font.Color = clBlue ParentColor = False @@ -2431,154 +2539,70 @@ object MainForm: TMainForm ParentShowHint = False ShowHint = True end - object lbOptionRenameDigits: TLabel - Left = 22 - Height = 15 - Top = 68 - Width = 78 - Caption = 'Rename digits' - ParentColor = False - end - object seOptionDigitVolume: TSpinEdit - Left = 94 + object btOptionBrowse: TSpeedButton + Left = 512 Height = 23 - Top = 90 - Width = 50 - MaxValue = 10 - MinValue = 1 - TabOrder = 5 - Value = 1 + Top = 34 + Width = 23 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOptionBrowseClick end - object seOptionDigitChapter: TSpinEdit - Left = 230 + object edOptionDefaultPath: TEdit + Left = 20 Height = 23 - Top = 90 - Width = 50 - MaxValue = 10 - MinValue = 1 - TabOrder = 6 - Value = 1 - end - object cbOptionDigitVolume: TCheckBox - Left = 25 - Height = 19 - Top = 92 - Width = 61 - Caption = 'Volume' - OnChange = cbOptionDigitVolumeChange - TabOrder = 7 + Top = 34 + Width = 490 + Anchors = [akTop, akLeft, akRight] + ParentFont = False + TabOrder = 3 + TextHint = 'Default download path' end - object cbOptionDigitChapter: TCheckBox - Left = 158 - Height = 19 - Top = 92 - Width = 62 - Caption = 'Chapter' - OnChange = cbOptionDigitChapterChange - TabOrder = 8 + object lbDefaultDownloadPath: TLabel + Left = 20 + Height = 15 + Top = 15 + Width = 186 + Caption = 'Choose the default download path:' + ParentColor = False + ParentFont = False end end - object seOptionPDFQuality: TSpinEdit - Left = 44 - Height = 23 - Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 132 - Width = 50 - MinValue = 5 - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 2 - Value = 100 - end - object lbOptionPDFQuality: TLabel - Left = 103 - Height = 15 - Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 135 - Width = 119 - Caption = 'PDF compression level' - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object lbOptionCustomRenameHint1: TLabel - Left = 260 - Height = 15 - Hint = '100: FlateEncode (lossless), lower: DCTEncode (lossy)' - Top = 135 - Width = 13 - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object btOptionBrowse: TSpeedButton - Left = 512 - Height = 23 - Top = 34 - Width = 23 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btOptionBrowseClick - end - object edOptionDefaultPath: TEdit - Left = 20 - Height = 23 - Top = 34 - Width = 490 - Anchors = [akTop, akLeft, akRight] - ParentFont = False - TabOrder = 3 - TextHint = 'Default download path' - end - object lbDefaultDownloadPath: TLabel - Left = 20 - Height = 15 - Top = 15 - Width = 186 - Caption = 'Choose the default download path:' - ParentColor = False - ParentFont = False - end end object tsUpdate: TTabSheet Caption = 'Updates' @@ -2914,7 +2938,7 @@ object MainForm: TMainForm object btOptionApply: TBitBtn Left = 8 Height = 41 - Top = 425 + Top = 466 Width = 128 Anchors = [akLeft, akBottom] Caption = 'Apply' @@ -3173,7 +3197,7 @@ object MainForm: TMainForm end object pcLeft: TPageControl Left = 4 - Height = 506 + Height = 547 Top = 12 Width = 195 ActivePage = tsMangaList @@ -3188,7 +3212,7 @@ object MainForm: TMainForm Caption = 'Manga List' ChildSizing.LeftRightSpacing = 2 ChildSizing.TopBottomSpacing = 3 - ClientHeight = 478 + ClientHeight = 519 ClientWidth = 187 object lbMode: TLabel Left = 3 @@ -3203,7 +3227,7 @@ object MainForm: TMainForm end object vtMangaList: TVirtualStringTree Left = 2 - Height = 383 + Height = 424 Top = 92 Width = 181 Align = alBottom @@ -3475,7 +3499,7 @@ object MainForm: TMainForm object sbMain: TStatusBar Left = 0 Height = 23 - Top = 522 + Top = 563 Width = 819 Panels = < item @@ -3489,7 +3513,7 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 514 + Height = 555 Top = 8 Width = 2 OnMoved = spMainSplitterMoved diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 75ac768bf..7d4efb3a0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -53,6 +53,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; + cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; cbOptionDigitVolume: TCheckBox; @@ -67,6 +68,7 @@ TMainForm = class(TForm) mmChangelog: TMemo; pcAbout: TPageControl; pmSbMain: TPopupMenu; + sbSaveTo: TScrollBox; tsAboutText: TTabSheet; tsChangelogText: TTabSheet; TransferRateToolset: TChartToolset; @@ -4328,6 +4330,7 @@ procedure TMainForm.LoadOptions; edOptionDefaultPath.Text := DEFAULT_PATH; rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); cbOptionPathConvert.Checked := ReadBool('saveto', 'PathConvert', False); + cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', True); cbOptionGenerateChapterName.Checked := ReadBool('saveto', 'GenerateChapterName', False); cbOptionGenerateMangaFolderName.Checked := ReadBool('saveto', 'GenerateMangaName', True); cbOptionAutoNumberChapter.Checked := ReadBool('saveto', 'AutoNumberChapter', True); @@ -4454,6 +4457,7 @@ procedure TMainForm.SaveOptions; WriteBool('saveto', 'AutoNumberChapter', cbOptionAutoNumberChapter.Checked); OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; WriteInteger('saveto', 'PDFQuality', seOptionPDFQuality.Value); + WriteBool('saveto', 'RemoveMangaNameFromChapter', cbOptionRemoveMangaNameFromChapter.Checked); if Trim(edOptionCustomRename.Text) = '' then edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; WriteString('saveto', 'CustomRename', edOptionCustomRename.Text); @@ -4595,6 +4599,7 @@ procedure TMainForm.ApplyOptions; OptionPDFQuality := seOptionPDFQuality.Value; OptionCustomRename := edOptionCustomRename.Text; DLManager.compress := rgOptionCompress.ItemIndex; + OptionRemoveMangaNameFromChapter := cbOptionRemoveMangaNameFromChapter.Checked; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 5ffd27fb7..d34b37dd2 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -363,11 +363,6 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" @@ -463,6 +458,10 @@ msgstr "Change all all unicode symbols to \"_\" (choose this when you have probl msgid "HTTP" msgstr "HTTP" +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Delete task/favorite" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 45152b62d..6e4f39563 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -356,11 +356,6 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" @@ -454,6 +449,10 @@ msgstr "Ubah semua simbol unicode menjadi \"_\" (pilih ini ketika Anda memiliki msgid "HTTP" msgstr "HTTP" +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Hapus nama komik dari bab" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Hapus unduhan/kesukaan" @@ -1662,4 +1661,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 93942c78a..56a6076a7 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -328,11 +328,6 @@ msgstr "" msgid "Visit my blog" msgstr "" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" @@ -426,6 +421,10 @@ msgstr "" msgid "HTTP" msgstr "" +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "" From 76b0eb4c7de975abe4590700e11771aed147b7a0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 13:50:38 +0800 Subject: [PATCH 0589/2794] mangahere, only grab title if empty all title in manga info capitalized --- baseunits/modules/MangaHere.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index f1ecac3e5..4c8d87741 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -68,7 +68,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; try with info do begin coverLink := Query.XPathString('//*[@class="manga_detail"]//img[@class="img"]/@src'); - title := Query.XPathString('//h1[@class="title"]'); + if title = '' then + title := Query.XPathString('//h1[@class="title"]'); for v in Query.XPath('//*[@class="detail_topText"]/li') do begin s := v.toString; if Pos('Author(s):', s) = 1 then authors := SeparateRight(s, ':') From df01fb97d297a9e360d722ce0605ff2880385ee9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 22 Nov 2015 14:45:03 +0800 Subject: [PATCH 0590/2794] fix find on tstringlist following fpc changes. issue 28774 --- baseunits/uBaseUnit.pas | 2 +- baseunits/uData.pas | 12 ++++-------- baseunits/uDownloadsManager.pas | 4 ++-- baseunits/uFavoritesManager.pas | 10 ++++++---- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 25bd272c1..d05a69f8a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2167,7 +2167,7 @@ function FindStrQuick(const s: String; var AStrings: TStringList): Boolean; if AStrings.Count > 0 then begin if not AStrings.Sorted then - AStrings.Sort; + AStrings.Sorted := True; Result := AStrings.Find(s, p); end else diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 764980a53..d4350adff 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -758,13 +758,8 @@ function TDBDataProcess.TableExist(const ATableName: String): Boolean; ts := TStringList.Create; try FConn.GetTableNames(ts); - if ts.Count > 0 then - for i := 0 to ts.Count - 1 do - if SameText(ts[i], ATableName) then - begin - Result := True; - Break; - end; + ts.Sorted := True; + Result := ts.Find(ATableName, i); finally ts.Free; end; @@ -1244,6 +1239,7 @@ procedure TDBDataProcess.InitLocateLink; FLinks.Clear else FLinks := TStringList.Create; + FLinks.Sorted := False; if FQuery.Active then begin FQuery.First; @@ -1252,7 +1248,7 @@ procedure TDBDataProcess.InitLocateLink; FQuery.Next; until FQuery.EOF; if FLinks.Count > 0 then - FLinks.Sort; + FLinks.Sorted := True; end; end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index fe3cc0e1a..0726f84bc 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1956,7 +1956,7 @@ procedure TDownloadManager.AddToDownloadedChaptersList(const Alink: String; Ch.Assign(AValue); if dlCh.Count > 0 then begin - dlCh.Sort; + dlCh.Sorted := True; i := 0; while i < Ch.Count do begin @@ -2019,7 +2019,7 @@ procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; GetParams(dlCh, DownloadedChaptersListFile[p]); if dlCh.Count > 0 then begin - dlCh.Sort; + dlCh.Sorted := True; for i := Low(Chapters) to High(Chapters) do Chapters[i].Downloaded := dlCh.Find(Chapters[i].Link, q); end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index db4fa0821..27bbf62ea 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -547,14 +547,16 @@ procedure TFavoriteManager.ShowResult; if Assigned(MangaInfo) then if MangaInfo.chapterLinks.Count > 0 then begin + //compare new mangainfo's chapters with downloadedchapter from favorites NewMangaInfo := TMangaInfo.Create; NewMangaInfoChaptersPos := TCardinalList.Create; TransferMangaInfo(NewMangaInfo, MangaInfo); NewMangaInfo.chapterLinks.Clear; NewMangaInfo.chapterName.Clear; dlChapters.Clear; + dlChapters.Sorted := False; GetParams(dlChapters, FavoriteInfo.downloadedChapterList); - dlChapters.Sort; + dlChapters.Sorted := True; for i := 0 to MangaInfo.chapterLinks.Count - 1 do if not dlChapters.Find(MangaInfo.chapterLinks[i], p) then begin @@ -585,8 +587,8 @@ procedure TFavoriteManager.ShowResult; end; finally Inc(counter); - end//compare new mangainfo's chapters with downloadedchapter from favorites - ; + end; + dlChapters.Clear; if numOfNewChapters = 0 then @@ -988,7 +990,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St Ch.Assign(AValue); if dlCh.Count > 0 then begin - dlCh.Sort; + dlCh.Sorted := True; i := 0; while i < Ch.Count do if dlCh.Find(Ch[i], q) then From b39f65f44d647bfe9229bf12470c7836ade0b447 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 08:39:32 +0800 Subject: [PATCH 0591/2794] add method load http config from ini add cookies --- baseunits/uData.pas | 9 +++------ baseunits/uDownloadsManager.pas | 4 +--- mangadownloader/forms/frmMain.pas | 10 ++++++++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d4350adff..bbb5125df 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2004,8 +2004,7 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; Page := 0; //load User-Agent from INIAdvanced - if website <> '' then - FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); + AdvanceLoadHTTPConfig(FHTTP, website); //load pagenumber_config if available p := INIAdvanced.ReadInteger('UpdateListDirectoryPageNumber', website, -1); @@ -2324,8 +2323,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; begin //load User-Agent from INIAdvanced - if website <> '' then - FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); + AdvanceLoadHTTPConfig(FHTTP, website); if ModuleId < 0 then ModuleId := Modules.LocateModule(website); @@ -2732,8 +2730,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; Exit(INFORMATION_NOT_FOUND); //load User-Agent from INIAdvanced - if website <> '' then - FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', website, ''); + AdvanceLoadHTTPConfig(FHTTP, website); mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 0726f84bc..9bde10643 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1275,9 +1275,7 @@ procedure TTaskThread.CheckOut; workCounter := container.WorkCounter; checkStyle := Flag; //load User-Agent from INIAdvanced - if container.DownloadInfo.Website <> '' then - FHTTP.UserAgent := INIAdvanced.ReadString('UserAgent', - container.DownloadInfo.Website, ''); + AdvanceLoadHTTPConfig(FHTTP, container.DownloadInfo.Website); Start; container.WorkCounter := InterLockedIncrement(container.WorkCounter); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7d4efb3a0..bf0f5dac2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -683,6 +683,8 @@ TSearchDBThread = class(TThread) procedure NewSearch(const ASearchStr: String); end; + procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); + var //Instance FMDInstance: TSimpleIPCServer; @@ -782,6 +784,14 @@ procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); ParentControl.Controls[i].Cursor := Cur; end; +procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); +begin + if HTTP = nil then Exit; + if Website = '' then Exit; + HTTP.UserAgent := INIAdvanced.ReadString('UserAgent', Website, ''); + HTTP.Cookies.Text := INIAdvanced.ReadString('Cookies', Website, ''); +end; + { TSearchDBThread } procedure TSearchDBThread.SyncBeforeSearch; From daeee9a8c1d058071a7b87c2f8c4ea1113a2c454 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 10:52:37 +0800 Subject: [PATCH 0592/2794] batoto, rewrite getimageurl #114 --- baseunits/modules/Batoto.pas | 138 +++++++++++++---------------------- 1 file changed, 51 insertions(+), 87 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index c66082426..4755daf4d 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, RegExpr; + synautil, HTMLUtil, RegExpr; implementation @@ -255,107 +255,71 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; + Source: TStringList; + Query: TXQueryEngineHTML; Container: TTaskContainer; - - procedure ScanParse; - var - i, j: Integer; - isWebtoon: Boolean; - begin - for i := 0 to Parse.Count - 1 do - if (Pos('page_select', Parse[i]) > 0) then - begin - isWebtoon := False; - Break; - end; - - //webtoon - if isWebtoon then - for i := 0 to Parse.Count - 1 do - begin - if Pos('<img ', Parse[i]) > 0 then - if Pos('<br/>', Parse[i + 1]) > 0 then - Container.pageLinks.Add(GetVal(Parse[i], 'src')); - end - else - for i := 0 to Parse.Count - 1 do - begin - if Pos('page_select', Parse[i]) <> 0 then - begin - j := i + 2; - while GetTagName(Parse[j]) = 'option' do - begin - Inc(Container.PageNumber); - Inc(j, 3); - end; - Break; - end; - end; - end; - + v: IXQValue; + cid: String; begin Result := False; if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL) + '/1', - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; + with Container, DownloadThread.FHTTP do begin + Source := TStringList.Create; + try + cid := SeparateRight(URL, '/reader#'); + Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; + if GetPage(DownloadThread.FHTTP, TObject(Source), + Module.RootURL + '/areader?id=' + cid + '&p=1', Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + v := Query.XPath('//div[1]/ul/li/select[@id="page_select"]/option/@value'); + PageNumber := v.Count; + PageContainerLinks.Text := cid; + finally + Query.Free; + end; + end; + finally + Source.Free; end; - finally - Parse.Free; end; end; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'id') = 'comic_page') then - begin - if DownloadThread.workCounter < Container.PageLinks.Count then - Container.PageLinks[DownloadThread.workCounter] := GetVal(Parse[i], 'src'); - Break; - end; - end; - + Source: TStringList; + Query: TXQueryEngineHTML; + rurl: String; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL) + - '/' + IntToStr(DownloadThread.workCounter + 1), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + if PageContainerLinks.Text = '' then Exit; + Source := TStringList.Create; + try + rurl := Module.RootURL + '/areader?id=' + PageContainerLinks[0] + '&p=' + + IntToStr(DownloadThread.WorkCounter + 1); + Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; + if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + PageLinks[DownloadThread.workCounter] := + Query.XPathString('//div[@id="full_image"]//img/@src'); + finally + Query.Free; + end; + end; + finally + Source.Free; end; - finally - Parse.Free; end; end; @@ -366,7 +330,7 @@ procedure RegisterModule; Website := 'Batoto'; RootURL := 'http://bato.to'; MaxTaskLimit := 1; - MaxConnectionLimit := 4; + MaxConnectionLimit := 3; SortedList := True; InformationAvailable := True; TotalDirectory := Length(dirurls); From 295f875899463f4b9a3a80debac7b72162147ff6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 11:29:19 +0800 Subject: [PATCH 0593/2794] small fix --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d05a69f8a..f32ffa8af 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1415,6 +1415,7 @@ function MaybeFillHost(const Host, URL: String): String; begin Result := URL; if Host = '' then Exit; + if URL = '' then Exit; with TRegExpr.Create do try Expression := REGEX_HOST; From 4e15a9dcbf9d70fb5a6a24068a2514ed891689fc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 11:35:12 +0800 Subject: [PATCH 0594/2794] mangalife, fix mangainfo fix #105 --- baseunits/modules/MangaLife.pas | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 6289b81d0..cb80007c1 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -55,16 +55,6 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; info: TMangaInfo; v: IXQValue; s: String; - - function getpropvalue(aname: String): String; - begin - Result := Query.XPathString( - '(/html/body/div[3]/div/div[1]/div/div[2]/div)[contains(.,"' + - aname + '")]'); - if Result <> '' then - Result := Trim(TrimChar(SeparateRight(Result, aname), [':', ' '])); - end; - begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; @@ -80,22 +70,23 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Query := TXQueryEngineHTML.Create(Source.Text); try with info do begin - coverLink := Query.XPathString( - '//div[@class="col-lg-3 col-md-3 col-sm-3 col-xs-3"]/img/@src'); + coverLink := Query.XPathString('//div[@class="well"]/div[1]/div/img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); title := Query.XPathString('//h1'); - authors := getpropvalue('Author'); - artists := getpropvalue('Artist'); - genres := getpropvalue('Genre'); - summary := getpropvalue('Description'); - s := LowerCase(getpropvalue('Scanlation Status')); - if s <> '' then begin - if Pos('ongoing', s) > 0 then status := '1' - else if Pos('completed', s) > 0 then status := '0' + for v in Query.XPath('//span[@class="details hidden-xs"]/div') do begin + s := v.toString; + if Pos('Author:', s) = 1 then authors := SeparateRight(s, ':') + else if Pos('Artist:', s) = 1 then artists := SeparateRight(s, ':') + else if Pos('Genre:', s) = 1 then artists := SeparateRight(s, ':') + else if Pos('Scanlation Status:', s) = 1 then begin + if Pos('Ongoing', s) > 0 then status := '1' + else status := '0'; + end; end; + summary := Query.XPathString('//span[@class="details hidden-xs"]/div/div/div'); //chapters - for v in Query.XPath('/html/body/div[3]/div/div/div/a') do begin + for v in Query.XPath('//div[@class="list"]/div/div/a') do begin s := v.toNode.getAttribute('href'); if RightStr(s, 6) = 'page-1' then SetLength(s, Length(s) - 6); chapterLinks.Add(s); From 8eba5180c98ebec340fb8b1242dfb05b3540430c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 11:42:10 +0800 Subject: [PATCH 0595/2794] nhentai, fix imageurl fix #104 --- baseunits/includes/NHentai/image_url.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/includes/NHentai/image_url.inc b/baseunits/includes/NHentai/image_url.inc index 2faa7f6b7..a19dd9d5f 100644 --- a/baseunits/includes/NHentai/image_url.inc +++ b/baseunits/includes/NHentai/image_url.inc @@ -30,7 +30,7 @@ begin for i := 0 to parse.Count - 1 do begin - if (Pos('<div', parse[i]) > 0) and (Pos('id="image-container"', parse[i]) > 0) then + if Pos('id="image-container"', parse[i]) > 0 then begin for j := i + 1 to parse.Count - 1 do begin From f697819ecc6da8ef2ddcea3cd9225de971beffaf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 11:54:42 +0800 Subject: [PATCH 0596/2794] mangatown, fix imageurl fix #102 --- baseunits/includes/MangaTown/image_url.inc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index 8293fdff2..b9827649b 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -5,11 +5,9 @@ s: String; begin l := TStringList.Create; - s := FillMangaSiteHost(MANGATOWN_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - s := s + IntToStr(workCounter + 1) + '.html'; + s := AppendURLDelim(FillMangaSiteHost(MANGATOWN_ID, URL)); + if workCounter > 0 then + s := s + IncStr(workCounter) + '.html'; Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); if Self.Terminated then From 0db1dc9c0b00c1f1063c750149ac411dcd71cdae Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 12:14:38 +0800 Subject: [PATCH 0597/2794] baseunit, fix removeurldelim --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f32ffa8af..b2ef70654 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2366,14 +2366,14 @@ function AppendURLDelimLeft(const URL: String): String; function RemoveURLDelim(const URL: String): String; begin Result := URL; - if (URL <> '') and (URL[Length(URL)] = '/') then + while (URL <> '') and (URL[Length(URL)] = '/') do SetLength(Result, Length(Result) - 1); end; function RemoveURLDelimLeft(const URL: String): String; begin Result := URL; - if (URL <> '') and (URL[1] = '/') then + while (URL <> '') and (URL[1] = '/') do Delete(Result, 1, 1); end; From c69e27baf7e8a5d25811e5375ac3db88a156b0b0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 12:15:43 +0800 Subject: [PATCH 0598/2794] fakku, fix imageurl fix #103 --- baseunits/includes/Fakku/image_url.inc | 131 ++++++++++++------------- 1 file changed, 64 insertions(+), 67 deletions(-) diff --git a/baseunits/includes/Fakku/image_url.inc b/baseunits/includes/Fakku/image_url.inc index 40aba5a77..29287e549 100644 --- a/baseunits/includes/Fakku/image_url.inc +++ b/baseunits/includes/Fakku/image_url.inc @@ -1,67 +1,64 @@ - function GetFakkuImageURL: Boolean; - var - i, totalPages: Cardinal; - l: TStringList; - imgURL, imgExt, s: String; - - begin - totalPages := 0; - manager.container.PageLinks.Clear; - l := TStringList.Create; - s := FillMangaSiteHost(FAKKU_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - if l.Count > 0 then - begin - //Get total pages - for i := 0 to l.Count - 1 do - begin - if (Pos('window.params.thumbs = ', l.strings[i]) > 0) then - begin - s := GetString(l.Strings[i], '= [', '];'); - with TStringList.Create do - try - DelimitedText := s; - totalPages := Count; - finally - Free; - end; - Break; - end; - end; - - if totalPages = 0 then - begin - Result := False; - end; - - //Get imgurl - for i := 0 to l.Count - 1 do - begin - if (Pos('return ''//', l.Strings[i]) > 0) then - begin - imgURL := GetString(l.Strings[i], 'return ''//', ''' +'); - imgExt := GetString(l.Strings[i], 'x + ''', ''';'); - Break; - end; - end; - - //Build image links - if imgExt = '' then - imgExt := '.jpg'; - - if imgURL <> '' then - begin - imgURL := TrimLeftChar(imgURL, ['/', '\', ':']); - imgURL := 'http://' + imgURL; - for i := 1 to totalPages do - begin - s := IntToStr(i); - while Length(s) < 3 do - s := '0' + s; - manager.container.PageLinks.Add(imgURL + s + imgExt); - end; - end; - end; - l.Free; - end; + function GetFakkuImageURL: Boolean; + var + i, totalPages: Cardinal; + l: TStringList; + imgURL, imgExt, s: String; + + begin + totalPages := 0; + manager.container.PageLinks.Clear; + l := TStringList.Create; + s := FillMangaSiteHost(FAKKU_ID, URL); + Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + + if l.Count > 0 then + begin + //Get total pages + for i := 0 to l.Count - 1 do + begin + if (Pos('window.params.thumbs = ', l.strings[i]) > 0) then + begin + s := GetString(l.Strings[i], '= [', '];'); + with TStringList.Create do + try + DelimitedText := s; + totalPages := Count; + finally + Free; + end; + Break; + end; + end; + + if totalPages = 0 then + Result := False; + + //Get imgurl + for i := 0 to l.Count - 1 do + begin + if (Pos('return ''', l.Strings[i]) > 0) then + begin + imgURL := GetString(l.Strings[i], 'return ''', ''' +'); + imgExt := GetString(l.Strings[i], 'x + ''', ''';'); + Break; + end; + end; + + //Build image links + if imgExt = '' then + imgExt := '.jpg'; + + if imgURL <> '' then + begin + imgURL := TrimLeftChar(imgURL, ['/', '\', ':']); + for i := 1 to totalPages do + begin + s := IntToStr(i); + while Length(s) < 3 do + s := '0' + s; + manager.container.PageLinks.Add(imgURL + s + imgExt); + end; + end; + end; + l.Free; + end; From 247365a65a749055a6eac5e6b27ef9d57366b37e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 12:31:32 +0800 Subject: [PATCH 0599/2794] mangaeden, fix page number fix #110 --- .../MangaEden/chapter_page_number.inc | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/baseunits/includes/MangaEden/chapter_page_number.inc b/baseunits/includes/MangaEden/chapter_page_number.inc index 81e9678ad..f8a7cc2da 100644 --- a/baseunits/includes/MangaEden/chapter_page_number.inc +++ b/baseunits/includes/MangaEden/chapter_page_number.inc @@ -1,36 +1,40 @@ - function GetMangaEdenPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - if manager.container.MangaSiteID = MANGAEDEN_ID then - s := FillMangaSiteHost(MANGAEDEN_ID, URL) + '1/' - else - s := FillMangaSiteHost(PERVEDEN_ID, URL) + '1/'; - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('span class="next"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 3]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaEdenPageNumber: Boolean; + var + s: String; + i, j: Integer; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + if manager.container.MangaSiteID = MANGAEDEN_ID then + s := FillMangaSiteHost(MANGAEDEN_ID, URL) + '1/' + else + s := FillMangaSiteHost(PERVEDEN_ID, URL) + '1/'; + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.pageNumber := 0; + for i := 0 to parse.Count - 1 do + if (Pos('<select', parse[i]) > 0) and + (GetVal(parse[i], 'id') = 'pageSelect') then + begin + for j := i to parse.Count - 1 do + begin + if Pos('</select', parse[j]) > 0 then + Break + else if Pos('<option', parse[j]) > 0 then + Inc(manager.container.PageNumber); + end; + Break; + end; + end; + parse.Free; + l.Free; + end; From cebccacc844b881f69d6e16840340fd9072f6861 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 12:39:13 +0800 Subject: [PATCH 0600/2794] drop support for mh160 website is dead. close #106 --- config/mangalist.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 91aa98b51..892bbd18d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,6 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt -Chinese=mh160 English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans From 45567c1f8a6327c27bad05547978d2e2e83cb932 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 13:05:09 +0800 Subject: [PATCH 0601/2794] Bump version 0.9.24.0 --- changelog.txt | 11 +++++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4e5db25b4..9f9af3dc4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,17 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.24.0 (25-11-2015) +[*] E-Hentai: get new image url if failed +[*] MangaHere: rewrite all script +[+] Added option to remove manga name in chapter name +[*] MangaLife: fix manga info +[*] NHentai: fix image url +[*] MangaTown: fix image url +[*] Fakku: fix image url +[*] MangaEden: fix page number +[*] Various changes and bug fixes + 0.9.23.0 (26-08-2015) [*] E-Hentai: fix image URL on multiple page [-] Drop support for SenMangaRAW diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 7f7817e18..783309224 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="23"/> + <RevisionNr Value="24"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 9d0fec49b..6c0006353 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.23.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.23.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.23.0_Win64.7z +VERSION=0.9.24.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.0_Win64.7z From a62776f54a940cbd7d35cf12f3649162bf313ae0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 14:05:31 +0800 Subject: [PATCH 0602/2794] fix, critical error, removeurldelim --- baseunits/uBaseUnit.pas | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b2ef70654..b4639c5e7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -884,8 +884,8 @@ function CleanAndExpandURL(const URL: String): String; function CleanURL(const URL: String): String; function AppendURLDelim(const URL: String): String; function AppendURLDelimLeft(const URL: String): String; -function RemoveURLDelim(const URL: String): String; -function RemoveURLDelimLeft(const URL: String): String; +function RemoveURLDelim(const URL: String): String; inline; +function RemoveURLDelimLeft(const URL: String): String; inline; function FixURL(const URL: String): String; function FixPath(const path: String): String; function GetLastDir(const path: String): String; @@ -2365,16 +2365,12 @@ function AppendURLDelimLeft(const URL: String): String; function RemoveURLDelim(const URL: String): String; begin - Result := URL; - while (URL <> '') and (URL[Length(URL)] = '/') do - SetLength(Result, Length(Result) - 1); + Result := TrimRightChar(URL, ['/']); end; function RemoveURLDelimLeft(const URL: String): String; begin - Result := URL; - while (URL <> '') and (URL[1] = '/') do - Delete(Result, 1, 1); + Result := TrimLeftChar(URL, ['/']); end; function FixURL(const URL : String) : String; From 26615344133d8d6d3c1e8824ead8e9bb12fe591f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 14:21:13 +0800 Subject: [PATCH 0603/2794] add back enableutf8rtl --- mangadownloader/md.lpi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 783309224..555c3a59b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -212,6 +212,9 @@ </Other> </CompilerOptions> </Item5> + <SharedMatrixOptions Count="1"> + <Item1 ID="178609478703" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dEnableUTF8RTL"/> + </SharedMatrixOptions> </BuildModes> <PublishOptions> <Version Value="2"/> From 8d48c15b674c57e25de1987d9ae63a7be7c019fb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 14:35:39 +0800 Subject: [PATCH 0604/2794] Bump version 0.9.24.1 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9f9af3dc4..c79a13b35 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,9 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.24.1 (25-11-2015) +[*] Fix fmd freeze + 0.9.24.0 (25-11-2015) [*] E-Hentai: get new image url if failed [*] MangaHere: rewrite all script diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 555c3a59b..e176ee771 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="24"/> + <BuildNr Value="1"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 6c0006353..ad359f0ea 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.24.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.0_Win64.7z +VERSION=0.9.24.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.1_Win64.7z From bd50a01c195cbd96414654f414007ba3c1866d8d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 Nov 2015 14:52:43 +0800 Subject: [PATCH 0605/2794] fix update url --- update | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update b/update index ad359f0ea..7951307d7 100644 --- a/update +++ b/update @@ -4,5 +4,5 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated VERSION=0.9.24.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.23.0/fmd_0.9.24.1_Win64.7z +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.24.1/fmd_0.9.24.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.24.1/fmd_0.9.24.1_Win64.7z From f17c9ebceeb3445d9c67eb838e10c87a234e2deb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 13 Dec 2015 04:20:19 +0800 Subject: [PATCH 0606/2794] added eightmuses --- baseunits/ModuleList.inc | 3 +- baseunits/modules/EightMuses.pas | 146 +++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/EightMuses.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index cf32e0aa8..cfc0c79b6 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -12,4 +12,5 @@ uses MangaStream, MangaLife, Luscious, - MangaHere; + MangaHere, + EightMuses; diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas new file mode 100644 index 000000000..b5124dfe2 --- /dev/null +++ b/baseunits/modules/EightMuses.pas @@ -0,0 +1,146 @@ +unit EightMuses; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Source: TStringList; + Query: TXQueryEngineHTML; + info: TMangaInfo; + v: IXQValue; + s: String; +begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + Result := NET_PROBLEM; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := RemoveURLDelim(FillHost(Module.RootURL, URL)); + Source := TStringList.Create; + try + if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if Source.Count > 0 then + begin + Result := NO_ERROR; + Query := TXQueryEngineHTML.Create(Source.Text); + try + with info do begin + coverLink := Query.XPathString('//div[@class="holder"]/a/img/@src'); + if Pos('//', coverLink) = 1 then coverLink := 'https:' + coverLink; + if title = '' then + title := Query.XPathString('//ul[@class="breadcrumbs"]/li[last()]'); + //multi + if Query.XPathString('//div[@class="holder"]/a') <> '' then begin + for v in Query.XPath('//div[@class="holder"]/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + s := v.toString; + if (title <> '') and (Pos('Issue', s) = 1) then s := title + ' ' + s; + chapterName.Add(s); + end; + end + else begin + chapterLinks.Add(info.url); + chapterName.Add(title); + end; + end; + finally + Query.Free; + end; + end + else + Result := INFORMATION_NOT_FOUND; + finally + Source.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Query: TXQueryEngineHTML; + Container: TTaskContainer; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + with Container do begin + Source := TStringList.Create; + try + if GetPage(DownloadThread.FHTTP, TObject(Source), + RemoveURLDelim(FillHost(Module.RootURL, URL)), Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + for v in Query.XPath('//div[@class="holder"]/a/@href') do begin + PageContainerLinks.Add(v.toString); + Inc(PageNumber); + end; + finally + Query.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + Query: TXQueryEngineHTML; + rurl: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do begin + Source := TStringList.Create; + try + rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkCounter])); + if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then + if Source.Count > 0 then + begin + Result := True; + Query := TXQueryEngineHTML.Create(Source.Text); + try + rurl := Query.XPathString('//img[@id="image"]/@src'); + if Pos('//', rurl) = 1 then rurl := 'https:' + rurl; + PageLinks[DownloadThread.workCounter] := rurl; + finally + Query.Free; + end; + end; + finally + Source.Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := '8Muses'; + RootURL := 'https://www.8muses.com'; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 802b09f3b169c2bf914b5a5356ba863aa9944bab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 13:03:38 +0800 Subject: [PATCH 0607/2794] rewrite httpsendthread --- baseunits/httpsendthread.pas | 266 +++++++++++++++++++++++++++++++++++ baseunits/uBaseUnit.pas | 50 ++----- 2 files changed, 281 insertions(+), 35 deletions(-) create mode 100644 baseunits/httpsendthread.pas diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas new file mode 100644 index 000000000..eedeced42 --- /dev/null +++ b/baseunits/httpsendthread.pas @@ -0,0 +1,266 @@ +unit httpsendthread; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, + uFMDThread, GZIPUtils, Graphics, USimpleLogger, RegExpr; + +type + + { THTTPSendThread } + + THTTPSendThread = class(THTTPSend) + private + FOwner: TFMDThread; + procedure SetTimeout(AValue: integer); + procedure OnOwnerTerminate(Sender: TObject); + public + RetryCount: Integer; + GZip: Boolean; + constructor Create(AOwner: TFMDThread = nil); + property Timeout: integer read FTimeout write SetTimeout; + function HTTPRequest(const Method, URL: String; Response: TObject = nil): Boolean; + function GET(const URL: String; Response: TObject = nil): Boolean; + function POST(const URL: String; URLData: String = ''; Response: TObject = nil): Boolean; + function GetCookies: String; + procedure RemoveCookie(const CookieName: string); + procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); + procedure SetNoProxy; + procedure Reset; + end; + +implementation + +{ THTTPSendThread } + +procedure THTTPSendThread.SetTimeout(AValue: integer); +begin + if FTimeout = AValue then Exit; + FTimeout := AValue; + Sock.ConnectionTimeout := FTimeout; + Sock.SetTimeout(FTimeout); +end; + +procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); +begin + Sock.Tag := 1; + Sock.AbortSocket; +end; + +constructor THTTPSendThread.Create(AOwner: TFMDThread); +begin + inherited Create; + KeepAlive := True; + UserAgent := 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36'; + Protocol := '1.1'; + Headers.NameValueSeparator := ':'; + Cookies.NameValueSeparator := '='; + GZip := True; + RetryCount := 0; + SetTimeout(15000); + if Assigned(AOwner) then + begin + FOwner := AOwner; + FOwner.OnCustomTerminate := @OnOwnerTerminate; + end; + Reset; +end; + +function THTTPSendThread.HTTPRequest(const Method, URL: String; + Response: TObject): Boolean; + + function CheckTerminate: Boolean; + begin + Result := Sock.Tag = 1; + if Result then Sock.Tag := 0; + end; + +var + counter: Integer = 0; + rurl, s: String; + HTTPHeader: TStringList; + mstream: TMemoryStream; +begin + Result := False; + rurl := URL; + if Pos('HTTP/', Headers.Text) = 1 then Reset; + HTTPHeader:= TStringList.Create; + HTTPHeader.Assign(Headers); + try + // first request + while (not HTTPMethod(Method, rurl)) or (ResultCode > 500) do begin + if CheckTerminate then Exit; + if (RetryCount > -1) and (RetryCount <= counter) then Exit; + Inc(Counter); + Headers.Assign(HTTPHeader); + end; + + // redirection + while (ResultCode > 300) and (ResultCode < 400) do begin + if CheckTerminate then Exit; + HTTPHeader.Values['Referer'] := ' ' + rurl; + s := Trim(Headers.Values['Location']); + if s <> '' then begin + with TRegExpr.Create do + try + Expression := '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; + if Replace(s, '$1', True) = '' then begin + if s[1] <> '/' then s := '/' + s; + rurl := Replace(rurl, '$1$2$3', True) + s; + end else rurl := s; + finally + Free; + end; + end; + + Clear; + Headers.Assign(HTTPHeader); + counter := 0; + while (not HTTPMethod('GET', rurl)) or (ResultCode > 500) do begin + if checkTerminate then Exit; + if (RetryCount > -1) and (RetryCount <= counter) then Exit; + Inc(counter); + Clear; + Headers.Assign(HTTPHeader); + end; + end; + + // response + if ResultCode <> 404 then begin + // decompress data + s := LowerCase(Headers.Values['Content-Encoding']); + if (Pos('gzip', s) <> 0) or (Pos('deflate', s) <> 0) then + begin + mstream := TMemoryStream.Create; + try + ZUncompressStream(Document, mstream); + Document.Clear; + Document.LoadFromStream(mstream); + except + end; + mstream.Free; + end; + if Assigned(Response) then + try + if Response is TStringList then + TStringList(Response).LoadFromStream(Document) + else + if Response is TPicture then + TPicture(Response).LoadFromStream(Document) + else + if Response is TStream then + Document.SaveToStream(TStream(Response)); + except + on E: Exception do + WriteLog_E('HTTPRequest.WriteOutput.Error!', E); + end; + Result := True; + end + else + Result := False; + finally + HTTPHeader.Free; + end; +end; + +function THTTPSendThread.GET(const URL: String; Response: TObject): Boolean; +begin + Result := HTTPRequest('GET', URL, Response); +end; + +function THTTPSendThread.POST(const URL: String; URLData: String; + Response: TObject): Boolean; +begin + if URLData <> '' then begin + Document.Clear; + WriteStrToStream(Document, URLData); + end; + MimeType := 'application/x-www-form-urlencoded'; + Result := HTTPRequest('POST', URL, Response); +end; + +function THTTPSendThread.GetCookies: String; +var + i: Integer; +begin + Result := ''; + if Cookies.Count > 0 then + for i := 0 to Cookies.Count - 1 do begin + if Result = '' then Result := Cookies.Strings[i] + else Result := Result + '; ' + Cookies.Strings[i]; + end; +end; + +procedure THTTPSendThread.RemoveCookie(const CookieName: string); +var + i: Integer; +begin + if CookieName = '' then Exit; + if Cookies.Count > 0 then begin + i := Cookies.IndexOfName(CookieName); + if i > -1 then Cookies.Delete(i); + end; +end; + +procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, + Pass: String); +var + pt: String; +begin + pt := upcase(ProxyType); + with Sock do begin + if pt = 'HTTP' then + begin + ProxyHost := Host; + ProxyPort := Port; + ProxyUser := User; + ProxyPass := Pass; + end + else + if (pt = 'SOCKS4') or (pt = 'SOCKS5') then + begin + if pt = 'SOCKS4' then + SocksType := ST_Socks4 + else + if pt = 'SOCKS5' then + SocksType := ST_Socks5; + SocksIP := Host; + SocksPort := Port; + SocksUsername := User; + SocksPassword := Pass; + end + else + begin + SocksIP := ''; + SocksPort := '1080'; + SocksType := ST_Socks5; + SocksUsername := ''; + SocksPassword := ''; + ProxyHost := ''; + ProxyPort := ''; + ProxyUser := ''; + ProxyPass := ''; + end; + end; +end; + +procedure THTTPSendThread.SetNoProxy; +begin + SetProxy('', '', '', '' ,''); +end; + +procedure THTTPSendThread.Reset; +begin + Clear; + Headers.Values['DNT'] := ' 1'; + Headers.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; + Headers.Values['Accept-Charset'] := ' utf8'; + Headers.Values['Accept-Language'] := ' en-US,en;q=0.8'; + if GZip then Headers.Values['Accept-Encoding'] := ' gzip, deflate'; +end; + +end. + diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b4639c5e7..1f6450c92 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -21,7 +21,8 @@ interface SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, - uMisc, simplehtmltreeparser, xquery, xquery_json, USimpleException, USimpleLogger; + uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, + USimpleException, USimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); @@ -212,6 +213,7 @@ interface MANGALIST_FILE = 'mangalist.ini'; LANGUAGE_FILE = 'languages.ini'; CHANGELOG_FILE = 'changelog.txt'; + ACCOUNTS_FILE = 'accounts.db'; UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/'; @@ -777,14 +779,9 @@ TParseHTML = class { THTTPSendThread } - THTTPSendThread = class(THTTPSend) - private - FOwner: TFMDThread; - procedure SetTimeout(AValue: Integer); - procedure OnOwnerTerminate(Sender: TObject); + THTTPSendThread = class(httpsendthread.THTTPSendThread) public - constructor Create(AOwner: TFMDThread); - property Timeout: Integer read FTimeout write SetTimeout; + constructor Create(AOwner: TFMDThread = nil); end; { TXQueryEngineHTML } @@ -3577,6 +3574,16 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); dest.chapterLinks.Assign(Source.chapterLinks); end; +{ THTTPSendThread } + +constructor THTTPSendThread.Create(AOwner: TFMDThread); +begin + inherited Create(AOwner); + RetryCount := OptionConnectionMaxRetry; + Timeout := OptionConnectionTimeout; + SetProxy(OptionProxyType, OptionProxyHost, OptionProxyPort, OptionProxyUser, OptionProxyPass); +end; + { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean): IXQValue; @@ -3638,33 +3645,6 @@ function TXQueryEngineHTML.CSSString(Expression: String): String; Result := Eval(Expression, True).toString; end; -{ THTTPSendThread } - -procedure THTTPSendThread.SetTimeout(AValue: Integer); -begin - if FTimeout = AValue then Exit; - FTimeout := AValue; - Sock.ConnectionTimeout := FTimeout; - Sock.SetTimeout(FTimeout); -end; - -procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); -begin - Sock.Tag := 1; - Sock.AbortSocket; -end; - -constructor THTTPSendThread.Create(AOwner: TFMDThread); -begin - inherited Create; - SetTimeout(OptionConnectionTimeout); - if Assigned(AOwner) then - begin - FOwner := AOwner; - FOwner.OnCustomTerminate := OnOwnerTerminate; - end; -end; - { TParseHTML } procedure TParseHTML.FoundTag(NoCaseTag, ActualTag: string); From bc545fc57c5ed348a898f5d511965d289cfc29c8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 13:03:58 +0800 Subject: [PATCH 0608/2794] add accountmanager --- baseunits/accountmanager.pas | 121 ++++++++++++++++++++++++++++++ mangadownloader/forms/frmMain.lfm | 2 +- mangadownloader/forms/frmMain.pas | 9 ++- 3 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 baseunits/accountmanager.pas diff --git a/baseunits/accountmanager.pas b/baseunits/accountmanager.pas new file mode 100644 index 000000000..9abfb5955 --- /dev/null +++ b/baseunits/accountmanager.pas @@ -0,0 +1,121 @@ +unit accountmanager; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, IniFiles, base64; + +type + + { TAccountManager } + + TAccountManager = class + private + fstorage: TIniFile; + function GetUsername(Name: string): string; + function GetPassword(Name: string): string; + function GetCookies(Name: string): string; + function GetStatus(Name: string): string; + procedure SetUsername(Name: string; AValue: string); + procedure SetPassword(Name: string; AValue: string); + procedure SetCookies(Name: string; AValue: string); + procedure SetStatus(Name: string; AValue: string); + public + constructor Create(const Filename: string); + destructor Destroy; override; + procedure Save; + property Username[Name: string]: string read GetUsername write SetUsername; + property Password[Name: string]: string read GetPassword write SetPassword; + property Cookies[Name: string]: string read GetCookies write SetCookies; + property Status[Name: string]: string read GetStatus write SetStatus; + end; + + procedure InitAccountManager(const Filename: string); + +var + Account: TAccountManager; + +implementation + +procedure InitAccountManager(const Filename: string); +begin + Account := TAccountManager.Create(Filename); +end; + +function encode(const s: string): string; +begin + if s = '' then Exit(''); + Result := EncodeStringBase64(s); +end; + +function decode(const s: string): string; +begin + if s = '' then Exit(''); + Result := DecodeStringBase64(s); +end; + +{ TAccountManager } + +function TAccountManager.GetUsername(Name: string): string; +begin + Result := decode(fstorage.ReadString(Name, 'username', '')); +end; + +function TAccountManager.GetPassword(Name: string): string; +begin + Result := decode(fstorage.ReadString(Name, 'password', '')); +end; + +function TAccountManager.GetCookies(Name: string): string; +begin + Result := decode(fstorage.ReadString(Name, 'cookies', '')); +end; + +function TAccountManager.GetStatus(Name: string): string; +begin + Result := decode(fstorage.ReadString(Name, 'status', '')); +end; + +procedure TAccountManager.SetUsername(Name: string; AValue: string); +begin + fstorage.WriteString(Name, 'username', encode(AValue)); +end; + +procedure TAccountManager.SetPassword(Name: string; AValue: string); +begin + fstorage.WriteString(Name, 'password', encode(AValue)); +end; + +procedure TAccountManager.SetCookies(Name: string; AValue: string); +begin + fstorage.WriteString(Name, 'cookies', encode(AValue)); +end; + +procedure TAccountManager.SetStatus(Name: string; AValue: string); +begin + fstorage.WriteString(Name, 'status', encode(AValue)); +end; + +constructor TAccountManager.Create(const Filename: string); +begin + fstorage := TIniFile.Create(Filename); +end; + +destructor TAccountManager.Destroy; +begin + fstorage.Free; + inherited Destroy; +end; + +procedure TAccountManager.Save; +begin + fstorage.UpdateFile; +end; + +finalization + if Assigned(Account) then Account.Free; + +end. + diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 76f653b69..13b713e3c 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,7 +13,7 @@ object MainForm: TMainForm OnDestroy = FormDestroy OnShow = FormShow OnWindowStateChange = FormWindowStateChange - LCLVersion = '1.5' + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bf0f5dac2..9bdc326ac 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -21,8 +21,8 @@ interface simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, - uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, - uTranslation, frmDropTarget, CheckUpdate, USimpleException, USimpleLogger; + uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, + frmDropTarget, CheckUpdate, accountmanager, USimpleException, USimpleLogger; type @@ -963,10 +963,13 @@ procedure TMainForm.FormCreate(Sender: TObject); TrayIcon.Icon.Assign(Application.Icon); PrevWindowState := wsNormal; + // account + accountmanager.InitAccountManager(fmdDirectory + CONFIG_FOLDER + ACCOUNTS_FILE); + // advanced settings INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_ADVANCED); - //main dataprocess + // main dataprocess dataProcess := TDBDataProcess.Create; // downloadmanager From 193f9cc0da5bc38580232670432f433769c67e55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 13:32:21 +0800 Subject: [PATCH 0609/2794] add getrigthvalue --- baseunits/uBaseUnit.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1f6450c92..c56668da9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -856,6 +856,7 @@ function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; // StringUtils +function GetRightValue(const name, s: string): string; function QuotedStrd(const S: string): string; overload; inline; function QuotedStrd(const S: Integer): string; overload; inline; function BracketStr(const S: string): string; inline; @@ -1643,6 +1644,17 @@ procedure ConvertCharsetToUTF8(S: TStrings); if cs <> '' then S.Text := ConvertEncoding(S.Text, cs, 'utf8'); end; +function GetRightValue(const name, s: string): string; +var + i: Integer; +begin + if s = '' then Exit(''); + if name = '' then Exit(s); + i := Pos(name, s); + if i > 0 then + Result := Trim(Copy(s, i + Length(name), Length(s))); +end; + function QuotedStrd(const S: string): string; begin Result := AnsiQuotedStr(S, '"'); From a3ff35366dcc42faa61ccc2cdb1f4757ae2cd9e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 13:42:01 +0800 Subject: [PATCH 0610/2794] rewrite bato to getinfo and add login --- baseunits/modules/Batoto.pas | 250 ++++++++++++++++++----------------- 1 file changed, 127 insertions(+), 123 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 4755daf4d..6ed9c9d6d 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,17 +6,24 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil, HTMLUtil, RegExpr; + accountmanager, synautil, HTMLUtil, RegExpr; implementation const + modulename = 'Batoto'; + urlroot = 'http://bato.to'; + urllogin = 'https://bato.to/forums/index.php?app=core&module=global§ion=login&do=process'; dirurls: array [0..1] of String = ( '/comic/_/sp/', '/comic/_/comics/'); perpage = 50; dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; +var + locklogin: TRTLCriticalSection; + onlogin: Boolean = False; + function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var @@ -116,140 +123,133 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; -var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - addchap: Boolean; - s: String; - begin - for i := StartIndex to Parse.Count - 1 do - begin - if Pos('</table', Parse[i]) <> 0 then - Break - else - if (GetTagName(Parse[i]) = 'tr') and (Pos(' chapter_row', Parse[i]) <> 0) then - begin - addchap := True; - s := CommonStringFilter(Parse[i + 6]); - if (not OptionBatotoShowAllLang) then - addchap := (Pos(' lang_English ', Parse[i]) <> 0) - else - s += Format(' [%s]', [Trim(GetVal(Parse[i + 12], 'title'))]); - if addchap then - begin - if OptionBatotoShowScanGroup then - s += Format(' [%s]', [Trim(Parse[i + 19])]); - info.chapterLinks.Add(GetVal(Parse[i + 4], 'href')); - info.chapterName.Add(s); - end; - end; - end; - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; - - procedure ScanParse; - var - i, j: Integer; - begin - info.genres := ''; - info.summary := ''; - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if (Pos('ipsType_pagetitle', Parse[i]) > 0) then - info.title := CommonStringFilter(Parse[i + 1]); - - //cover - if info.coverLink = '' then - if (GetTagName(Parse[i]) = 'img') and - (Pos('max-height:500px', Parse[i]) > 0) then - info.coverLink := GetVal(Parse[i], 'src'); - - //author - if (Pos('Author:', Parse[i]) > 0) then - info.authors := Trim(Parse[i + 5]); - - //artist - if (Pos('Artist:', parse[i]) > 0) then - info.artists := Trim(Parse[i + 5]); +function CheckLogin(const source: string): Boolean; +begin + if source = '' then Exit(False); + Result := (Pos('class=''logged_in''', source) > 0) or (Pos('class="logged_in"', source) > 0); +end; - //genres - if Pos('/search?genres=', Parse[i]) > 0 then - begin - if Pos('</span', Parse[i + 4]) > 0 then - if info.genres = '' then - info.genres := Trim(Parse[i + 3]) - else - info.genres := info.genres + ', ' + Parse[i + 3]; - end; +function Login(http: THTTPSendThread): Boolean; +var + query: TXQueryEngineHTML; + source: TStringList; + s, key, user, pass: string; +begin + Result := False; + if http = nil then Exit; + if Account.Username[modulename] = '' then Exit; - //summary - if (Pos('Description:', Parse[i]) <> 0) then - begin - info.summary := ''; - for j := i + 3 to Parse.Count - 1 do - begin - if Pos('</td>', Parse[j]) <> 0 then - Break - else - if Pos('<', Parse[j]) <> 1 then - begin - if info.summary <> '' then - info.summary += LineEnding; - info.summary += StringFilter(Parse[j]); + if TryEnterCriticalsection(locklogin) > 0 then + with http do begin + onlogin := True; + Reset; + Cookies.Clear; + if Get(urlroot) then begin + source := TStringList.Create; + query := TXQueryEngineHTML.Create; + try + source.LoadFromStream(Document); + query.ParseHTML(source.Text); + key := query.XPathString('//input[@name="auth_key"]/@value'); + if key <> '' then begin + user:= Account.Username[modulename]; + pass:= Account.Password[modulename]; + s := 'auth_key='+key+'&referer=https%3A%2F%2Fbato.to%2F'+'&ips_username='+user+'&ips_password='+pass+'&rememberMe=1'; + Clear; + Headers.Values['Referer'] := ' https://bato.to/'; + if Post(urllogin, s) then begin + if ResultCode = 200 then begin + Result := Cookies.Values['pass_hash'] <> ''; + if Result then begin + Account.Cookies[modulename] := GetCookies; + Account.Status[modulename] := 'OK'; + end else begin + Account.Status[modulename] := 'Invalid user/password!'; + end; + Account.Save; + end; + end; end; + finally + query.Free; + source.Free end; end; - - //status - if (Pos('Status:', Parse[i]) > 0) then - begin - if (i + 4 < Parse.Count - 1) and - (Pos('Ongoing', Parse[i + 4]) > 0) then - info.status := '1' // ongoing - else - info.status := '0'; // completed - end; - - //chapters - if (GetTagName(Parse[i]) = 'table') and - (GetVal(Parse[i], 'class') = 'ipb_table chapters_list') then - begin - ScanChapters(i); - Break; - end; - end; + onlogin := False + end + else + begin + while onlogin do Sleep(1000); + if Result then http.Cookies.Text := Account.Cookies[modulename]; end; +end; +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + source: TStringList; + query: TXQueryEngineHTML; + info: TMangaInfo; + v: IXQValue; + s: String; + i: Integer; begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; info.website := Module.Website; info.url := FillHost(Module.RootURL, URL); - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; + while onlogin do Sleep(1000); + MangaInfo.FHTTP.Cookies.Text := Account.Cookies[modulename]; + if MangaInfo.FHTTP.GET(info.url) then begin + Result := NO_ERROR; + source := TStringList.Create; + query := TXQueryEngineHTML.Create; + try + source.LoadFromStream(MangaInfo.FHTTP.Document); + if not CheckLogin(source.Text) then begin + if Login(MangaInfo.FHTTP) then begin + MangaInfo.FHTTP.GET(info.url, source); + end; + end; + + query.ParseHTML(source.Text); + with info do begin + coverLink := Query.XPathString('//div[@class="ipsBox"]//img/@src'); + if title = '' then + title := Query.XPathString('//h1[@class="ipsType_pagetitle"]'); + + for v in query.XPath('//table[@class="ipb_table"]//tr') do begin + s := v.toString; + if Pos('Author:', s) > 0 then authors:= GetRightValue('Author:', s) + else if Pos('Artist:', s) > 0 then artists:= GetRightValue('Artist:', s) + else if Pos('Description:', s) > 0 then summary:= GetRightValue('Description:', s) + else if Pos('Status:', s) > 0 then begin + if Pos('Ongoing', s) > 0 then status := '1' + else status := '0'; + end; + end; + v := query.XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); + if v.Count > 0 then begin + genres := ''; + for i := 0 to v.Count do AddCommaString(genres, v.get(i).toString); + end; + + if OptionBatotoShowAllLang then + s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]/td[1]/a' + else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]/td[1]/a'; + + for v in query.XPath(s) do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]) end; + finally + query.Free; + source.Free; end; - finally - Parse.Free; - end; + end else Result := INFORMATION_NOT_FOUND; end; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; @@ -327,8 +327,8 @@ procedure RegisterModule; begin with AddModule do begin - Website := 'Batoto'; - RootURL := 'http://bato.to'; + Website := modulename; + RootURL := urlroot; MaxTaskLimit := 1; MaxConnectionLimit := 3; SortedList := True; @@ -343,6 +343,10 @@ procedure RegisterModule; end; initialization + InitCriticalSection(locklogin); RegisterModule; +finalization + DoneCriticalsection(locklogin); + end. From c32100fd1bea0934512e7037fd6e77af91107a79 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 13:53:17 +0800 Subject: [PATCH 0611/2794] ba toto use cookies --- baseunits/modules/Batoto.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 6ed9c9d6d..37bbdaacd 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -50,6 +50,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; if MangaInfo = nil then Exit; Parse := TStringList.Create; try + MangaInfo.FHTTP.Cookies.Text := Account.Cookies[modulename]; if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + dirparam + IntToStr(perpage), 3) then @@ -108,6 +109,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; s += '&st=' + (IntToStr(p * perpage)); Parse := TStringList.Create; try + MangaInfo.FHTTP.Cookies.Text := Account.Cookies[modulename]; if MangaInfo.GetPage(TObject(Parse), s, 3) then begin Result := INFORMATION_NOT_FOUND; @@ -265,6 +267,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; if DownloadThread = nil then Exit; Container := DownloadThread.manager.container; with Container, DownloadThread.FHTTP do begin + Cookies.Text := Account.Cookies[modulename]; Source := TStringList.Create; try cid := SeparateRight(URL, '/reader#'); @@ -300,6 +303,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; if DownloadThread = nil then Exit; with DownloadThread.manager.container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; + Cookies.Text := Account.Cookies[modulename]; Source := TStringList.Create; try rurl := Module.RootURL + '/areader?id=' + PageContainerLinks[0] + '&p=' + From f664def42abda03cbec4a7dd3f258905ab01a629 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 14:41:20 +0800 Subject: [PATCH 0612/2794] ba toto fix long-strip view #114 --- baseunits/modules/Batoto.pas | 46 +++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 37bbdaacd..7ead18c84 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -257,37 +257,35 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; + source: TStringList; + query: TXQueryEngineHTML; v: IXQValue; cid: String; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - with Container, DownloadThread.FHTTP do begin + with DownloadThread.manager.container, DownloadThread.FHTTP do begin Cookies.Text := Account.Cookies[modulename]; - Source := TStringList.Create; - try - cid := SeparateRight(URL, '/reader#'); - Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; - if GetPage(DownloadThread.FHTTP, TObject(Source), - Module.RootURL + '/areader?id=' + cid + '&p=1', Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - v := Query.XPath('//div[1]/ul/li/select[@id="page_select"]/option/@value'); - PageNumber := v.Count; - PageContainerLinks.Text := cid; - finally - Query.Free; - end; + Headers.Values['Referer'] := ' ' + urlroot + '/reader'; + cid := SeparateRight(URL, '/reader#'); + if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin + source := TStringList.Create; + query := TXQueryEngineHTML.Create; + try + source.LoadFromStream(Document); + query.ParseHTML(source.Text); + PageContainerLinks.Text := cid; + if query.XPathString('//select[@id="page_select"]') <> '' then + PageNumber := Query.XPath('//div[1]/ul/li/select[@id="page_select"]/option/@value').Count + else begin + // long-strip view + PageLinks.Clear; + for v in query.XPath('//div/img/@src') do + PageLinks.Add(v.toString); end; - finally - Source.Free; + finally + source.Free; + end; end; end; end; From de19392e98d08bf26963d3b11ffa335476037dc2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Dec 2015 14:59:54 +0800 Subject: [PATCH 0613/2794] bato to fix and cleanup #114 --- baseunits/modules/Batoto.pas | 135 +++++++++++++++++------------------ 1 file changed, 65 insertions(+), 70 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 7ead18c84..748c0bc1b 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -191,67 +191,65 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; var source: TStringList; query: TXQueryEngineHTML; - info: TMangaInfo; v: IXQValue; s: String; i: Integer; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); - while onlogin do Sleep(1000); - MangaInfo.FHTTP.Cookies.Text := Account.Cookies[modulename]; - if MangaInfo.FHTTP.GET(info.url) then begin - Result := NO_ERROR; - source := TStringList.Create; - query := TXQueryEngineHTML.Create; - try - source.LoadFromStream(MangaInfo.FHTTP.Document); - if not CheckLogin(source.Text) then begin - if Login(MangaInfo.FHTTP) then begin - MangaInfo.FHTTP.GET(info.url, source); - end; - end; - - query.ParseHTML(source.Text); - with info do begin - coverLink := Query.XPathString('//div[@class="ipsBox"]//img/@src'); - if title = '' then - title := Query.XPathString('//h1[@class="ipsType_pagetitle"]'); - - for v in query.XPath('//table[@class="ipb_table"]//tr') do begin - s := v.toString; - if Pos('Author:', s) > 0 then authors:= GetRightValue('Author:', s) - else if Pos('Artist:', s) > 0 then artists:= GetRightValue('Artist:', s) - else if Pos('Description:', s) > 0 then summary:= GetRightValue('Description:', s) - else if Pos('Status:', s) > 0 then begin - if Pos('Ongoing', s) > 0 then status := '1' - else status := '0'; + with MangaInfo do begin + mangaInfo.website := modulename; + mangaInfo.url := FillHost(urlroot, URL); + while onlogin do Sleep(1000); + FHTTP.Cookies.Text := Account.Cookies[modulename]; + if FHTTP.GET(mangaInfo.url) then begin + Result := NO_ERROR; + source := TStringList.Create; + query := TXQueryEngineHTML.Create; + try + source.LoadFromStream(FHTTP.Document); + if not CheckLogin(source.Text) then begin + if Login(FHTTP) then begin + FHTTP.GET(mangaInfo.url, source); end; end; - v := query.XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); - if v.Count > 0 then begin - genres := ''; - for i := 0 to v.Count do AddCommaString(genres, v.get(i).toString); - end; - if OptionBatotoShowAllLang then - s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]/td[1]/a' - else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]/td[1]/a'; + query.ParseHTML(source.Text); + with mangaInfo do begin + coverLink := Query.XPathString('//div[@class="ipsBox"]//img/@src'); + if title = '' then + title := Query.XPathString('//h1[@class="ipsType_pagetitle"]'); + for v in query.XPath('//table[@class="ipb_table"]//tr') do begin + s := v.toString; + if Pos('Author:', s) > 0 then authors:= GetRightValue('Author:', s) + else if Pos('Artist:', s) > 0 then artists:= GetRightValue('Artist:', s) + else if Pos('Description:', s) > 0 then summary:= GetRightValue('Description:', s) + else if Pos('Status:', s) > 0 then begin + if Pos('Ongoing', s) > 0 then status := '1' + else status := '0'; + end; + end; + v := query.XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); + if v.Count > 0 then begin + genres := ''; + for i := 0 to v.Count do AddCommaString(genres, v.get(i).toString); + end; - for v in query.XPath(s) do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + if OptionBatotoShowAllLang then + s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]/td[1]/a' + else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]/td[1]/a'; + for v in query.XPath(s) do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]) end; - InvertStrings([chapterLinks, chapterName]) + finally + query.Free; + source.Free; end; - finally - query.Free; - source.Free; - end; - end else Result := INFORMATION_NOT_FOUND; + end else Result := INFORMATION_NOT_FOUND; + end; end; function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; @@ -269,6 +267,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Headers.Values['Referer'] := ' ' + urlroot + '/reader'; cid := SeparateRight(URL, '/reader#'); if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin + Result := True; source := TStringList.Create; query := TXQueryEngineHTML.Create; try @@ -284,6 +283,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; PageLinks.Add(v.toString); end; finally + query.Free; source.Free; end; end; @@ -293,8 +293,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; + source: TStringList; + query: TXQueryEngineHTML; rurl: String; begin Result := False; @@ -302,25 +302,20 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; with DownloadThread.manager.container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; Cookies.Text := Account.Cookies[modulename]; - Source := TStringList.Create; - try - rurl := Module.RootURL + '/areader?id=' + PageContainerLinks[0] + '&p=' + - IntToStr(DownloadThread.WorkCounter + 1); - Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; - if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - PageLinks[DownloadThread.workCounter] := - Query.XPathString('//div[@id="full_image"]//img/@src'); - finally - Query.Free; - end; - end; - finally - Source.Free; + rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + IntToStr(DownloadThread.WorkCounter + 1); + Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; + if GET(rurl) then begin + Result := True; + source := TStringList.Create; + query := TXQueryEngineHTML.Create; + try + source.LoadFromStream(Document); + query.ParseHTML(source.Text); + PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@id="full_image"]//img/@src'); + finally + query.Free; + source.Free; + end; end; end; end; From 165d1fd3d9e91ea727686348b42eb6edf5cc2166 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Dec 2015 10:22:36 +0800 Subject: [PATCH 0614/2794] ba toto fix locked login --- baseunits/modules/Batoto.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 748c0bc1b..579e57f5d 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -177,7 +177,8 @@ function Login(http: THTTPSendThread): Boolean; source.Free end; end; - onlogin := False + onlogin := False; + LeaveCriticalsection(locklogin); end else begin From 3bef6307c127078f72c17cd0dfe7dd5094c0ec45 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Dec 2015 10:23:22 +0800 Subject: [PATCH 0615/2794] set sqlite dll on before app init --- baseunits/uData.pas | 4 ---- mangadownloader/md.lpr | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index bbb5125df..9676d7d8f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -3219,8 +3219,4 @@ function TMangaInformation.GetPage(var output: TObject; URL: String; Result := uBaseUnit.GetPage(FHTTP, output, URL, Reconnect); end; -initialization - sqlite3dyn.SQLiteDefaultLibrary := - CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; - end. diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 614257f16..9db8a6226 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -14,7 +14,7 @@ cthreads, {$ENDIF} {$ENDIF} - Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, + Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, sqlite3dyn, uBaseUnit, frmMain; var @@ -55,6 +55,7 @@ DeleteFileUTF8(ChangeFileExt(Application.ExeName, '.trc')); SetHeapTraceOutput(ChangeFileExt(Application.ExeName, '.trc')); {$ENDIF DEBUGLEAKS} + sqlite3dyn.SQLiteDefaultLibrary := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; Application.Title := 'Free Manga Downloader'; RequireDerivedFormResource := True; Application.Initialize; From 34a4244c04e4d3bd77e7d7e9dd25a1c66e37c726 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Dec 2015 12:19:06 +0800 Subject: [PATCH 0616/2794] added accountmanagerdb with sqlite3 database --- baseunits/accountmanagerdb.pas | 372 ++++++++++++++++++++++++++++++ baseunits/modules/Batoto.pas | 3 +- mangadownloader/forms/frmMain.pas | 5 +- 3 files changed, 377 insertions(+), 3 deletions(-) create mode 100644 baseunits/accountmanagerdb.pas diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas new file mode 100644 index 000000000..1a2df774d --- /dev/null +++ b/baseunits/accountmanagerdb.pas @@ -0,0 +1,372 @@ +unit accountmanagerdb; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, LazFileUtils, USimpleLogger, base64, sqlite3conn, + sqldb; + +type + + { TAccountManager } + + TAccountManager = class + private + locklocate: TRTLCriticalSection; + fconn: TSQLite3Connection; + ftrans: TSQLTransaction; + fquery: TSQLQuery; + ffilename: String; + frecordcount: Integer; + + function GetUsername(AName: string): string; + function GetEnabled(AName: string): boolean; + function GetPassword(AName: string): string; + function GetCookies(AName: string): string; + function GetStatus(AName: string): string; + procedure SetUsername(AName: string; AValue: string); + procedure SetEnabled(AName: string; AValue: boolean); + procedure SetPassword(AName: string; AValue: string); + procedure SetCookies(AName: string; AValue: string); + procedure SetStatus(AName: string; AValue: string); + + function CreateDB: Boolean; + function InternalOpenDB: Boolean; + function CreateDBTable: Boolean; + function OpenDBTable: Boolean; + function GetValueString(const AName, AField: string): string; + function GetValueBoolean(const AName, AField: string): boolean; + procedure SetValueString(const AName, AField, AValue: string); + procedure SetValueBoolean(const AName, AField: string; AValue: boolean); + procedure GetRecordCount; + procedure Vacuum; + public + constructor Create(const AFilename: string); + destructor Destroy; override; + procedure Save; + function AddAccount(const AName, AUsername, APassword: string): Boolean; + function DeleteAccount(const AName: string): Boolean; + property Enabled[AName: string]: boolean read GetEnabled write SetEnabled; + property Username[AName: string]: string read GetUsername write SetUsername; + property Password[AName: string]: string read GetPassword write SetPassword; + property Cookies[AName: string]: string read GetCookies write SetCookies; + property Status[AName: string]: string read GetStatus write SetStatus; + property Count: Integer read frecordcount; + end; + + procedure InitAccountManager(const AFilename: string); + +var + Account: TAccountManager; + +implementation + +const + ctablename = 'accounts'; + ctbaccountscreateparams = '('#13#10 + + '"aname" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + + '"enabled" BOOL,'#13#10 + + '"username" VARCHAR,'#13#10 + + '"password" VARCHAR,'#13#10 + + '"cookies" VARCHAR,'#13#10 + + '"status" VARCHAR'#13#10 + + ');'; + +procedure InitAccountManager(const AFilename: string); +begin + Account := TAccountManager.Create(AFilename); +end; + +function encode(const s: string): string; +begin + if s = '' then Exit(''); + Result := EncodeStringBase64(s); +end; + +function decode(const s: string): string; +begin + if s = '' then Exit(''); + Result := DecodeStringBase64(s); +end; + +{ TAccountManager } + +function TAccountManager.GetUsername(AName: string): string; +begin + Result := GetValueString(AName, 'username'); +end; + +function TAccountManager.GetEnabled(AName: string): boolean; +begin + Result := GetValueBoolean(AName, 'enabled'); +end; + +function TAccountManager.GetPassword(AName: string): string; +begin + Result := decode(GetValueString(AName, 'password')); +end; + +function TAccountManager.GetCookies(AName: string): string; +begin + Result := GetValueString(AName, 'cookies'); +end; + +function TAccountManager.GetStatus(AName: string): string; +begin + Result := GetValueString(AName, 'status'); +end; + +procedure TAccountManager.SetUsername(AName: string; AValue: string); +begin + SetValueString(AName, 'username', AValue); +end; + +procedure TAccountManager.SetEnabled(AName: string; AValue: boolean); +begin + SetValueBoolean(AName, 'enabled', AValue); +end; + +procedure TAccountManager.SetPassword(AName: string; AValue: string); +begin + SetValueString(AName, 'password', encode(AValue)); +end; + +procedure TAccountManager.SetCookies(AName: string; AValue: string); +begin + SetValueString(AName, 'cookies', AValue); +end; + +procedure TAccountManager.SetStatus(AName: string; AValue: string); +begin + SetValueString(AName, 'status', AValue); +end; + +function TAccountManager.CreateDB: Boolean; +begin + Result := False; + if ffilename = '' then Exit; + if FileExistsUTF8(ffilename) then DeleteFileUTF8(ffilename); + if InternalOpenDB then Result := CreateDBTable; +end; + +function TAccountManager.InternalOpenDB: Boolean; +begin + Result := False; + if ffilename = '' then Exit; + try + fconn.DatabaseName := ffilename; + fconn.Connected := True; + ftrans.Active := True; + Result := fconn.Connected; + except + on E: Exception do + WriteLog_E('TAccountManager.InternalOpenDB.Failed, ' + ffilename, E, Self); + end; +end; + +function TAccountManager.CreateDBTable: Boolean; +begin + Result := False; + if InternalOpenDB = False then Exit; + try + fconn.ExecuteDirect('DROP TABLE IF EXISTS ' + AnsiQuotedStr(ctablename, '"')); + fconn.ExecuteDirect('CREATE TABLE ' + AnsiQuotedStr(ctablename, '"') + #13#10 + ctbaccountscreateparams); + ftrans.Commit; + OpenDBTable; + Result := True; + except + on E: Exception do + WriteLog_E('TAccountManager.CreateDBTable.Failed, ' + ffilename, E, Self); + end; +end; + +function TAccountManager.OpenDBTable: Boolean; +begin + Result := False; + if InternalOpenDB = False then Exit; + try + if fquery.Active then fquery.Close; + fquery.SQL.Text := 'SELECT * FROM ' + AnsiQuotedStr(ctablename, '"'); + fquery.Open; + GetRecordCount; + Result := fquery.Active; + except + on E: Exception do + WriteLog_E('TAccountManager.OpenDBTable.Failed, ' + ffilename, E, Self); + end; +end; + +function TAccountManager.GetValueString(const AName, AField: string): string; +begin + if fquery.Active = False then Exit(''); + EnterCriticalsection(locklocate); + try + if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsString + else Result := ''; + finally + LeaveCriticalsection(locklocate); + end; +end; + +function TAccountManager.GetValueBoolean(const AName, AField: string): boolean; +begin + if fquery.Active = False then Exit(False); + EnterCriticalsection(locklocate); + try + if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsBoolean + else Result := False; + finally + LeaveCriticalsection(locklocate); + end; +end; + +procedure TAccountManager.SetValueString(const AName, AField, AValue: string); +begin + if fquery.Active = False then Exit; + EnterCriticalsection(locklocate); + try + if fquery.Locate('aname', AName, []) then begin + fquery.Edit; + fquery.FieldByName(AField).AsString := AValue; + fquery.Post; + end; + finally + LeaveCriticalsection(locklocate); + end; +end; + +procedure TAccountManager.SetValueBoolean(const AName, AField: string; + AValue: boolean); +begin + if fquery.Active = False then Exit; + EnterCriticalsection(locklocate); + try + if fquery.Locate('aname', AName, []) then begin + fquery.Edit; + fquery.FieldByName(AField).AsBoolean := AValue; + fquery.Post; + end; + finally + LeaveCriticalsection(locklocate); + end; +end; + +procedure TAccountManager.GetRecordCount; +begin + if fquery.Active then begin + fquery.Last; + frecordcount := fquery.RecordCount; + fquery.Refresh; + end + else frecordcount := 0; +end; + +procedure TAccountManager.Vacuum; +begin + if fconn.Connected = False then Exit; + fquery.Close; + fconn.ExecuteDirect('END TRANSACTION'); + try + fconn.ExecuteDirect('VACUUM'); + except + on E: Exception do + WriteLog_E('TAccountManager.Vacuum.Failed!', E, Self); + end; + fconn.ExecuteDirect('BEGIN TRANSACTION'); + fquery.Open; +end; + +constructor TAccountManager.Create(const AFilename: string); +begin + InitCriticalSection(locklocate); + fconn := TSQLite3Connection.Create(nil); + ftrans := TSQLTransaction.Create(nil); + fquery := TSQLQuery.Create(nil); + fconn.CharSet := 'UTF8'; + fconn.Transaction := ftrans; + fquery.DataBase := ftrans.DataBase; + fquery.Transaction := ftrans; + fquery.Options := fquery.Options + [sqoAutoApplyUpdates]; + frecordcount := 0; + + ffilename := AFilename; + if not FileExistsUTF8(ffilename) then CreateDBTable + else OpenDBTable; +end; + +destructor TAccountManager.Destroy; +begin + if fconn.Connected then begin + Save; + Vacuum; + fquery.Close; + fconn.Close; + end; + fconn.Free; + fquery.Free; + ftrans.Free; + DoneCriticalsection(locklocate); + inherited Destroy; +end; + +procedure TAccountManager.Save; +begin + if fconn.Connected = False then Exit; + try + if fquery.Active then fquery.Close; + ftrans.Commit; + fquery.Open; + GetRecordCount; + except + on E: Exception do + WriteLog_E('TAccountManager.Save.Failed, ' + ffilename, E, Self); + end; +end; + +function TAccountManager.AddAccount(const AName, AUsername, APassword: string + ): Boolean; +begin + Result := False; + if fconn.Connected = False then Exit; + try + with fquery do begin + Append; + FieldByName('aname').AsString := AName; + FieldByName('enabled').AsBoolean := True; + FieldByName('username').AsString := AUsername; + FieldByName('password').AsString := encode(APassword); + FieldByName('status').AsString := 'Unknown'; + Post; + end; + GetRecordCount; + Result := True; + except + on E: Exception do + WriteLog_E('TAccountManager.AddAccount.Failed, ' + AName, E, Self); + end; +end; + +function TAccountManager.DeleteAccount(const AName: string): Boolean; +begin + Result := False; + if fconn.Connected = False then Exit; + try + with fquery do begin + if Locate('aname', AName, []) then begin + Delete; + GetRecordCount; + Result := True; + end; + end; + except + on E: Exception do + WriteLog_E('TAccountManager.DeleteAccount.Failed, ' + AName, E, Self); + end; +end; + +finalization + if Assigned(Account) then Account.Free; + +end. diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 579e57f5d..4aaf19d5c 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanager, synautil, HTMLUtil, RegExpr; + accountmanagerdb, synautil, HTMLUtil, RegExpr; implementation @@ -139,6 +139,7 @@ function Login(http: THTTPSendThread): Boolean; begin Result := False; if http = nil then Exit; + if Account.Enabled[modulename] = False then Exit; if Account.Username[modulename] = '' then Exit; if TryEnterCriticalsection(locklogin) > 0 then diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9bdc326ac..a3cc7b42b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,7 +22,8 @@ interface FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, - frmDropTarget, CheckUpdate, accountmanager, USimpleException, USimpleLogger; + frmDropTarget, CheckUpdate, accountmanager, accountmanagerdb, + USimpleException, USimpleLogger; type @@ -964,7 +965,7 @@ procedure TMainForm.FormCreate(Sender: TObject); PrevWindowState := wsNormal; // account - accountmanager.InitAccountManager(fmdDirectory + CONFIG_FOLDER + ACCOUNTS_FILE); + accountmanagerdb.InitAccountManager(fmdDirectory + CONFIG_FOLDER + ACCOUNTS_FILE); // advanced settings INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_ADVANCED); From 5dde3337fce7da23e4a45cb984826170f91e02ce Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Dec 2015 12:29:54 +0800 Subject: [PATCH 0617/2794] add accountsupport property --- baseunits/WebsiteModules.pas | 2 ++ baseunits/modules/Batoto.pas | 1 + 2 files changed, 3 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index a4112960b..47cbdc2e6 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -53,6 +53,7 @@ TModuleContainer = class MaxConnectionLimit: Integer; ActiveTaskCount: Integer; ActiveConnectionCount: Integer; + AccountSupport: Boolean; SortedList: Boolean; InformationAvailable: Boolean; FavoriteAvailable: Boolean; @@ -203,6 +204,7 @@ constructor TModuleContainer.Create; MaxConnectionLimit := 0; ActiveTaskCount := 0; ActiveConnectionCount := 0; + AccountSupport := False; SortedList := False; InformationAvailable := True; FavoriteAvailable := True; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 4aaf19d5c..9839e46cd 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -330,6 +330,7 @@ procedure RegisterModule; RootURL := urlroot; MaxTaskLimit := 1; MaxConnectionLimit := 3; + AccountSupport := True; SortedList := True; InformationAvailable := True; TotalDirectory := Length(dirurls); From b2de7dd71359b1b44ac362b93bc7458999751d91 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Dec 2015 13:23:12 +0800 Subject: [PATCH 0618/2794] accountmanager, encode cookies --- baseunits/accountmanagerdb.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 1a2df774d..bc7ebb4ee 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -110,7 +110,7 @@ function TAccountManager.GetPassword(AName: string): string; function TAccountManager.GetCookies(AName: string): string; begin - Result := GetValueString(AName, 'cookies'); + Result := decode(GetValueString(AName, 'cookies')); end; function TAccountManager.GetStatus(AName: string): string; @@ -135,7 +135,7 @@ procedure TAccountManager.SetPassword(AName: string; AValue: string); procedure TAccountManager.SetCookies(AName: string; AValue: string); begin - SetValueString(AName, 'cookies', AValue); + SetValueString(AName, 'cookies', encode(AValue)); end; procedure TAccountManager.SetStatus(AName: string; AValue: string); From 465ebc1c715b6a642fda007a5fad6e84b9dfc947 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Dec 2015 23:37:29 +0800 Subject: [PATCH 0619/2794] accountmanagerdb, add more property --- baseunits/accountmanagerdb.pas | 126 +++++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 14 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index bc7ebb4ee..0e923eafb 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -10,6 +10,8 @@ interface type + TAccountStatus = (asUnknown, asValid, asInvalid); + { TAccountManager } TAccountManager = class @@ -20,7 +22,15 @@ TAccountManager = class fquery: TSQLQuery; ffilename: String; frecordcount: Integer; - + function CreateDB: Boolean; + function InternalOpenDB: Boolean; + function CreateDBTable: Boolean; + function OpenDBTable: Boolean; + function GetValueString(const AName, AField: string): string; + function GetValueBoolean(const AName, AField: string): boolean; + function GetValueStr(const RecIndex, FieldIndex: Integer): string; + function GetValueBool(const RecIndex, FieldIndex: Integer): boolean; + function GetValueInt(const RecIndex, FieldIndex: Integer): Integer; function GetUsername(AName: string): string; function GetEnabled(AName: string): boolean; function GetPassword(AName: string): string; @@ -31,15 +41,11 @@ TAccountManager = class procedure SetPassword(AName: string; AValue: string); procedure SetCookies(AName: string; AValue: string); procedure SetStatus(AName: string; AValue: string); - - function CreateDB: Boolean; - function InternalOpenDB: Boolean; - function CreateDBTable: Boolean; - function OpenDBTable: Boolean; - function GetValueString(const AName, AField: string): string; - function GetValueBoolean(const AName, AField: string): boolean; procedure SetValueString(const AName, AField, AValue: string); procedure SetValueBoolean(const AName, AField: string; AValue: boolean); + procedure SetValueStr(const RecIndex, FieldIndex: Integer; AValue: string); + procedure SetValueBool(const RecIndex, FieldIndex: Integer; AValue: boolean); + procedure SetValueInt(const RecIndex, FieldIndex: Integer; AValue: Integer); procedure GetRecordCount; procedure Vacuum; public @@ -53,6 +59,9 @@ TAccountManager = class property Password[AName: string]: string read GetPassword write SetPassword; property Cookies[AName: string]: string read GetCookies write SetCookies; property Status[AName: string]: string read GetStatus write SetStatus; + property ValueStr[const RecIndex, FieldIndex: Integer]: string read GetValueStr write SetValueStr; + property ValueBool[const RecIndex, FieldIndex: Integer]: boolean read GetValueBool write SetValueBool; + property ValueInt[const RecIndex, FieldIndex: Integer]: Integer read GetValueInt write SetValueInt; property Count: Integer read frecordcount; end; @@ -66,12 +75,12 @@ implementation const ctablename = 'accounts'; ctbaccountscreateparams = '('#13#10 + - '"aname" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + '"enabled" BOOL,'#13#10 + + '"aname" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + '"username" VARCHAR,'#13#10 + '"password" VARCHAR,'#13#10 + '"cookies" VARCHAR,'#13#10 + - '"status" VARCHAR'#13#10 + + '"status" INTEGER'#13#10 + ');'; procedure InitAccountManager(const AFilename: string); @@ -118,6 +127,45 @@ function TAccountManager.GetStatus(AName: string): string; Result := GetValueString(AName, 'status'); end; +function TAccountManager.GetValueStr(const RecIndex, FieldIndex: Integer + ): string; +begin + Result := ''; + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + try + fquery.RecNo := RecIndex + 1; + Result := fquery.Fields[FieldIndex].AsString; + except + end; +end; + +function TAccountManager.GetValueBool(const RecIndex, FieldIndex: Integer + ): boolean; +begin + Result := False; + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + try + fquery.RecNo := RecIndex + 1; + Result := fquery.Fields[FieldIndex].AsBoolean; + except + end; +end; + +function TAccountManager.GetValueInt(const RecIndex, FieldIndex: Integer + ): Integer; +begin + Result := 0; + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + try + fquery.RecNo := RecIndex + 1; + Result := fquery.Fields[FieldIndex].AsInteger; + except + end; +end; + procedure TAccountManager.SetUsername(AName: string; AValue: string); begin SetValueString(AName, 'username', AValue); @@ -200,7 +248,8 @@ function TAccountManager.OpenDBTable: Boolean; function TAccountManager.GetValueString(const AName, AField: string): string; begin - if fquery.Active = False then Exit(''); + Result := ''; + if fquery.Active = False then Exit; EnterCriticalsection(locklocate); try if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsString @@ -212,7 +261,8 @@ function TAccountManager.GetValueString(const AName, AField: string): string; function TAccountManager.GetValueBoolean(const AName, AField: string): boolean; begin - if fquery.Active = False then Exit(False); + Result := False; + if fquery.Active = False then Exit; EnterCriticalsection(locklocate); try if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsBoolean @@ -222,6 +272,54 @@ function TAccountManager.GetValueBoolean(const AName, AField: string): boolean; end; end; +procedure TAccountManager.SetValueStr(const RecIndex, FieldIndex: Integer; + AValue: string); +begin + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + EnterCriticalsection(locklocate); + try + fquery.RecNo := RecIndex + 1; + fquery.Edit; + fquery.Fields[FieldIndex].AsString := AValue; + fquery.Post; + finally + LeaveCriticalsection(locklocate); + end; +end; + +procedure TAccountManager.SetValueBool(const RecIndex, FieldIndex: Integer; + AValue: boolean); +begin + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + EnterCriticalsection(locklocate); + try + fquery.RecNo := RecIndex + 1; + fquery.Edit; + fquery.Fields[FieldIndex].AsBoolean := AValue; + fquery.Post; + finally + LeaveCriticalsection(locklocate); + end; +end; + +procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex: Integer; + AValue: Integer); +begin + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + EnterCriticalsection(locklocate); + try + fquery.RecNo := RecIndex + 1; + fquery.Edit; + fquery.Fields[FieldIndex].AsInteger := AValue; + fquery.Post; + finally + LeaveCriticalsection(locklocate); + end; +end; + procedure TAccountManager.SetValueString(const AName, AField, AValue: string); begin if fquery.Active = False then Exit; @@ -333,11 +431,11 @@ function TAccountManager.AddAccount(const AName, AUsername, APassword: string try with fquery do begin Append; - FieldByName('aname').AsString := AName; FieldByName('enabled').AsBoolean := True; + FieldByName('aname').AsString := AName; FieldByName('username').AsString := AUsername; FieldByName('password').AsString := encode(APassword); - FieldByName('status').AsString := 'Unknown'; + FieldByName('status').AsInteger := Integer(asUnknown); Post; end; GetRecordCount; From 76278f3e0acf9a360218238c2cd1e0f0c28c3d35 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 17 Dec 2015 19:06:24 +0800 Subject: [PATCH 0620/2794] accountmanager, add delete fucntion --- baseunits/accountmanagerdb.pas | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 0e923eafb..d18cc038c 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -10,7 +10,7 @@ interface type - TAccountStatus = (asUnknown, asValid, asInvalid); + TAccountStatus = (asUnknown, asChecking, asValid, asInvalid); { TAccountManager } @@ -54,6 +54,7 @@ TAccountManager = class procedure Save; function AddAccount(const AName, AUsername, APassword: string): Boolean; function DeleteAccount(const AName: string): Boolean; + function DeleteAccount(const RecIndex: Integer): Boolean; overload; property Enabled[AName: string]: boolean read GetEnabled write SetEnabled; property Username[AName: string]: string read GetUsername write SetUsername; property Password[AName: string]: string read GetPassword write SetPassword; @@ -449,7 +450,7 @@ function TAccountManager.AddAccount(const AName, AUsername, APassword: string function TAccountManager.DeleteAccount(const AName: string): Boolean; begin Result := False; - if fconn.Connected = False then Exit; + if fquery.Active = False then Exit; try with fquery do begin if Locate('aname', AName, []) then begin @@ -464,6 +465,24 @@ function TAccountManager.DeleteAccount(const AName: string): Boolean; end; end; +function TAccountManager.DeleteAccount(const RecIndex: Integer): Boolean; +begin + Result := False; + if fquery.Active = False then Exit; + if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; + try + with fquery do begin + RecNo := RecIndex + 1; + Delete; + GetRecordCount; + Result := True; + end; + except + on E: Exception do + WriteLog_E('TAccountManager.DeleteAccount.Failed, ' + IntToStr(RecIndex), E, Self); + end; +end; + finalization if Assigned(Account) then Account.Free; From dc5f6c7ff03fb181e1f90b4a245ee0d013eb40b2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 17 Dec 2015 19:40:19 +0800 Subject: [PATCH 0621/2794] add account manager settings --- mangadownloader/forms/frmAccountManager.lfm | 268 +++++++++++++++++++ mangadownloader/forms/frmAccountManager.pas | 272 ++++++++++++++++++++ mangadownloader/forms/frmAccountSet.lfm | 186 +++++++++++++ mangadownloader/forms/frmAccountSet.pas | 56 ++++ mangadownloader/forms/frmMain.lfm | 43 ++-- mangadownloader/forms/frmMain.pas | 17 +- mangadownloader/languages/fmd.en.po | 137 +++++++++- mangadownloader/languages/fmd.id_ID.po | 141 ++++++++++ mangadownloader/languages/fmd.po | 96 +++++++ mangadownloader/md.lpi | 15 +- 10 files changed, 1207 insertions(+), 24 deletions(-) create mode 100644 mangadownloader/forms/frmAccountManager.lfm create mode 100644 mangadownloader/forms/frmAccountManager.pas create mode 100644 mangadownloader/forms/frmAccountSet.lfm create mode 100644 mangadownloader/forms/frmAccountSet.pas diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm new file mode 100644 index 000000000..7b8cdbba7 --- /dev/null +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -0,0 +1,268 @@ +object AccountManagerForm: TAccountManagerForm + Left = 0 + Height = 316 + Top = 0 + Width = 392 + ActiveControl = vtAccountList + BorderStyle = bsNone + Caption = 'AccountManagerForm' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ClientHeight = 316 + ClientWidth = 392 + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + LCLVersion = '1.7' + Visible = False + object pnBtContainer: TPanel + Left = 295 + Height = 304 + Top = 6 + Width = 91 + Align = alRight + AutoSize = True + BevelOuter = bvNone + ChildSizing.VerticalSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 304 + ClientWidth = 91 + TabOrder = 1 + object btDelete: TBitBtn + Left = 6 + Height = 26 + Top = 64 + Width = 85 + Align = alTop + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Delete' + Enabled = False + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000E0000 + 0012000000170000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A00000017000000120000000E0000001C0000 + 5DA2000078CC000078CC000078CC000078CC000078CC000078CC000078CC0000 + 78CC000078CC000078CC000078CC000078CC00005DA20000001C000025000000 + 8FCC5F5FE7FF5252DAFF4C4CD4FF4646CEFF4141C9FF3E3EC6FF3D3DC5FF3C3C + C4FF3B3BC3FF3A3AC2FF3939C1FF3A3AC2FF00008FCC0000250000009E000000 + 9ECC6666EEFF5B5BE3FF5555DDFF4F4FD7FF4A4AD2FF4545CDFF4343CBFF4141 + C9FF4040C8FF3F3FC7FF3E3EC6FF4040C8FF00009ECC00009E000000A6000000 + A7990000A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000 + A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000A7990000A600FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btDeleteClick + TabOrder = 0 + end + object btEdit: TBitBtn + Left = 6 + Height = 26 + Top = 32 + Width = 85 + Align = alTop + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Edit' + Enabled = False + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000FF014B + 649A012E3C63010A0D350000002D0000002A00000026000000210000001D0000 + 001900000014000000100000000B000000080000000500000002015E7B85C2E6 + F2FF5591A5D1014C649A013141500000001500000013000000110000000F0000 + 000D0000000A0000000800000006000000040000000300000001016B8E3962A5 + BBC0C2E6F2FFA0CEDDF501596FC30060764701343E0000000000000000000000 + 000000000000000000000000000000000000000000000000000000759B060072 + 976CC0E4F1EF44BBCCFF58CEDFFF016379CA01687D47016F8500013C47000000 + 0000000000000000000000000000000000000000000000000000007CA500007C + A527018DA8A688EEFFFF5DD1E2FF5BD0E1FF016B80C80170864601788E000281 + 9700014550000000000000000000000000000000000000000000007CA500007D + A600019AB2400195ADB788EEFFFF63D5E6FF5FD3E4FF017389C701798F450281 + 97000289A0000291A800024D5800000000000000000000000000007CA500007D + A600019BB200019AB2400195ADB788EEFFFF69DAEBFF60D3E4FF027C92C50282 + 98450289A0000291A8000399AF000A0A0A000505050000000000007CA500007D + A600019BB200019BB200019AB2400195ADB788EEFFFF71DEEFFF60D3E4FF0285 + 9BC3028AA1450291A8000399AF000A0A0A000A0A0A000A0A0A00007CA500007D + A600019BB200019BB200019BB200019AB2400195ADB788EEFFFF78E3F4FF5DD2 + E3FF028DA4C20292A9440399AF000A0A0A000A0A0A000A0A0A00007CA500007D + A600019BB200019BB200019BB200019BB200019AB2400195ADB788EEFFFF7EE7 + F8FF5ACFE0FF0395ACC0039AB0430A0A0A000A0A0A000A0A0A00007CA500007D + A600019BB200019BB200019BB200019BB200019BB200019AB2400195ADB788EE + FFFF83EBFCFF56CDDEFF087A8CB00C0C0C2F0A0A0A000A0A0A00001F2A00005E + 7D00019BB200019BB200019BB200019BB200019BB200019BB200019AB2400195 + ADB788EEFFFF33AABBFFDDDDDDFF171717830909312905055500000000000000 + 000001272D0001758600019BB200019BB200019BB200019BB200019BB200019A + B240158395A3F6F6F6FFCCCCCCFFDDDDDDFF060683B50000A032000000000000 + 0000000000000000000001272D0001758600019BB200019BB200019BB200019B + B2005555552450505069F6F6F6FF6868F8FF5C5CF2FF0000A8B1000000000000 + 00000000000000000000000000000000000001272D0001758600019BB200019B + B200555555005555551F1515BC9D8888FFFF0101C5B90101B443000000000000 + 000000000000000000000000000000000000000000000000000001272D000175 + 860055555500555555000101E42B0101E09D0101D23F0101B600 + } + OnClick = btEditClick + TabOrder = 1 + end + object btAdd: TBitBtn + Left = 6 + Height = 26 + Top = 0 + Width = 85 + Align = alTop + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Add' + Default = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 + 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 + 0000000000040000001B0000003000000033024700A6025D00CC025D00CC0247 + 00A600000033000000310000001F0000000600000000FFFFFF00FFFFFF000000 + 0000000000000000000000000000021D0000066D00CC22D811FF22D811FF066D + 00CC021D000000000000000000000000000000000000FFFFFF00FFFFFF000747 + 00000000000000000000032000000A7D00000A7D00CC23CD12FF22CC11FF0A7D + 00CC0A7D000003200000000000000000000000000000FFFFFF00FFFFFF000E8D + 00000E8C00000E8C00000E8A00000C8400000C8400CC25C014FF24C013FF0C84 + 00CC0C8400000E8A00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8D + 00000E8C00000E8C00000E8C00000E8B00000D8900CC29B618FF27B416FF0D89 + 00CC0E8B00000E8C00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8E + 00990E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D + 00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000F92 + 00CC59D048FF50C73FFF50C73FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A9 + 20FF2CA51BFF2BA31AFF2DA51CFF33AB22FF0F9200CCFFFFFF00FFFFFF001096 + 00CC5ED54DFF55CC44FF54CB43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC6 + 3EFF4EC53DFF4DC43CFF4CC33BFF4EC53DFF109600CCFFFFFF00FFFFFF00119A + 0099119A00CC119A00CC119A00CC119A00CC119A00CC54CB43FF52C941FF119A + 00CC119A00CC119A00CC119A00CC119A00CC119A0099FFFFFF00FFFFFF00119A + 0000119B0000119B0000119B0000129C0000129E00CC5AD149FF59D048FF129E + 00CC129C0000119B0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A + 0000119B0000119B0000129D000013A2000013A200CC62D951FF61D850FF13A2 + 00CC13A20000129D0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A + 0000119B0000129E000014A5000014A5000014A500CC69E058FF69E058FF14A5 + 00CC14A5000014A50000129E0000119B0000119A0000FFFFFF00FFFFFF00119A + 0000129F000014A8000014A8000014A8000014A800CC72E961FF71E860FF14A8 + 00CC14A8000014A8000014A80000129F0000119A0000FFFFFF00FFFFFF003B7F + 320015A9000015A9000015A9000015A9000015AA009915AA00CC15AA00CC15AA + 009915A9000015A9000015A9000015A90000094D0000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btAddClick + TabOrder = 2 + end + object btRefresh: TBitBtn + Left = 6 + Height = 26 + Top = 96 + Width = 85 + Align = alTop + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Refresh' + Enabled = False + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 00000000000600000010000000190000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A000000190000001500000010FFFFFF000000 + 00000000000B0000002011090133391E013E532A014345240240733A02A6984D + 02CC984D02CC984D02CC984D02CC984D02CC733A02A30000001FFFFFFF000000 + 000028160200763D0419A2580842C47E174EE4A01C54FCB9203F9C5105CCFDBC + 28FFFCB81DFFFCB81DFFFDC033FF9C5105CC9C51055C00000000FFFFFF00A65B + 0D00A3580B22AB62105FF8BA346DF6B01C6DF7B11E6BF8B52740A2570ACCF8B6 + 2AFFF6AC14FFF8BA35FFA2570ACCA2570A84A15609002A170400FFFFFF00A95E + 0F10AD641378F3B84390EFAB2A90E7A83691BF7A2078A85D0E33A85D0ECCF2B3 + 39FFF3B943FFEEA824FFF2B339FFAD6210BFA95E0F1AAA5F1000FFFFFF00AF64 + 144DCC8B33A6E8A83BB4E4A845B2AF641488AE631332AC611100AF6414CCF0BD + 5CFFAF6414CCECB148FFE8A83BFFCD8D34E3AF64146CAF641400FFFFFF00B66B + 198CE0A751CFE3A84ED6C98734BBB56A194AAF641400B66B1900B66B19CCB66B + 19CCB66B1994C98734DCE3A84EFFE0A851F5B66B19A7B66B1900FFFFFF00BE73 + 1FC1E7B466F1E5B061F1BE731FC1BB701D00C0752100C0752000BD721E99BD72 + 1E5CBA6F1C00BE731FCCE5B061FFE7B466FFBE731FCCBE731F00FFFFFF00C57A + 25CCE8B86FFFE6B46CFFC57A25CCC97E2700C67B265CC67B2699C1762100BE73 + 1F00C87D2700C57A25C1E6B46CF1E8B86FF1C57A25C1C57A2500FFFFFF00CD82 + 2AA7E8B66CF5E8B570FFDA9B48DCCD822A94CD822ACCCD822ACCCD822A00CF84 + 2C00CE832B4ADA9B47BBE8B570D6E8B66CCFCD822A8CCD822A00FFFFFF00D489 + 306CE4AB59E3EDBC76FFF1C67EFFD48930CCF7D38AFFD48930CCD88D3200D58A + 3132D4893088EEBF75B2EDBC76B4E4A958A6D489304DD4893000FFFFFF00DA8F + 341ADC9339BFF7CD85FFF2C27AFFF9D38AFFF7CD85FFDB9034CCDB903433E4A5 + 4F78F3C67991F4C57D90F8D28990DD953A78DA8F3410D98E3300FFFFFF00E196 + 3900E1963984E19639CCFCD88EFFF9CC82FFFCD58AFFE19639CCFCD48940FBD0 + 866BFACF856DFCD88D6DE49E435FE0953922DC913500DC913500FFFFFF00E69B + 3D5CE59A3DCCFFE094FFFED98DFFFED98DFFFFDC91FFE59A3DCCFEDA8E3FF8CB + 7B54F0B7604EE79F4242E59A3D19E1963900DC913500DC913500FFFFFF00E99E + 4099E99E40CCE99E40CCE99E40CCE99E40CCE99E40CCE99E4099E99E4020E99E + 4025E99E4019E89D3F06E59A3D00E1963900DC913500DC913500FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + TabOrder = 3 + end + end + object vtAccountList: TVirtualStringTree + Left = 6 + Height = 304 + Top = 6 + Width = 289 + Align = alClient + Header.AutoSizeIndex = 0 + Header.Columns = < + item + MinWidth = 25 + Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Position = 0 + Width = 25 + end + item + Position = 1 + Text = 'Website' + end + item + Position = 2 + Text = 'Username' + end + item + Position = 3 + Text = 'Status' + end> + Header.DefaultHeight = 17 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + NodeDataSize = 1 + TabOrder = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnChange = vtAccountListChange + OnChecked = vtAccountListChecked + OnGetText = vtAccountListGetText + OnPaintText = vtAccountListPaintText + OnInitNode = vtAccountListInitNode + end +end diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas new file mode 100644 index 000000000..933b79794 --- /dev/null +++ b/mangadownloader/forms/frmAccountManager.pas @@ -0,0 +1,272 @@ +unit frmAccountManager; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, + Buttons, ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, + frmAccountSet, USimpleLogger; + +type + + { TAccountManagerForm } + + TAccountManagerForm = class(TForm) + btDelete: TBitBtn; + btRefresh: TBitBtn; + btEdit: TBitBtn; + btAdd: TBitBtn; + pnBtContainer: TPanel; + vtAccountList: TVirtualStringTree; + procedure btAddClick(Sender: TObject); + procedure btDeleteClick(Sender: TObject); + procedure btEditClick(Sender: TObject); + procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure vtAccountListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vtAccountListChecked(Sender: TBaseVirtualTree; Node: PVirtualNode + ); + procedure vtAccountListGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); + procedure vtAccountListInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure vtAccountListPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); + private + { private declarations } + public + { public declarations } + procedure RefreshList; + procedure SaveForm; + procedure LoadForm; + procedure RefreshWebsiteAvailable; + end; + +var + AccountManagerForm: TAccountManagerForm; + +resourcestring + RS_Unknown = 'Unknown'; + RS_Checking = 'Checking'; + RS_Valid = 'OK'; + RS_Invalid = 'Invalid'; + RS_AccountDeleteConfirmation = 'Are you sure you want to delete this account?'; + +implementation + +uses frmMain; + +var + Websites, WebsitesAvailable: TStringlist; + +{$R *.lfm} + +{ TAccountManagerForm } + +procedure TAccountManagerForm.vtAccountListInitNode(Sender: TBaseVirtualTree; + ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +begin + if Assigned(Node) then + Node^.CheckType := ctCheckBox; +end; + +procedure TAccountManagerForm.vtAccountListPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + if Node^.CheckState = csUncheckedNormal then TargetCanvas.Font.Color := clGrayText + else TargetCanvas.Font.Color := clDefault; +end; + +procedure TAccountManagerForm.RefreshList; +begin + vtAccountList.RootNodeCount := Account.Count; +end; + +procedure TAccountManagerForm.SaveForm; +var + i: Integer; +begin + with MainForm.options, vtAccountList.Header.Columns do begin + if Count > 0 then + for i := 0 to Count - 1 do + WriteInteger('form', 'vtAccountList' + IntToStr(i) + 'Width', Items[i].Width); + end; +end; + +procedure TAccountManagerForm.LoadForm; +var + i: Integer; +begin + with MainForm.options, vtAccountList.Header.Columns do begin + if Count > 0 then + for i := 0 to Count - 1 do + Items[i].Width := ReadInteger('form', 'vtAccountList' + IntToStr(i) + 'Width', 50); + end; +end; + +procedure TAccountManagerForm.RefreshWebsiteAvailable; +var + i, p: Integer; +begin + WebsitesAvailable.Clear; + if Websites.Count = 0 then Exit; + WebsitesAvailable.Assign(Websites); + WebsitesAvailable.Sorted := True; + if Account.Count > 0 then + for i := 0 to Account.Count - 1 do begin + if WebsitesAvailable.Find(Account.ValueStr[i, 1], p) then + WebsitesAvailable.Delete(p); + end; + btAdd.Enabled := WebsitesAvailable.Count > 0; +end; + +procedure TAccountManagerForm.vtAccountListGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +begin + if Assigned(Node) then begin + case Column of + 0: if Account.ValueBool[Node^.Index, 0] then + Node^.CheckState := csCheckedNormal + else + Node^.CheckState := csUncheckedNormal; + 1: CellText := Account.ValueStr[Node^.Index, 1]; + 2: CellText := Account.ValueStr[Node^.Index, 2]; + 3: case Account.ValueInt[Node^.Index, 5] of + Integer(asUnknown): CellText := RS_Unknown; + Integer(asValid) : CellText := RS_Valid; + Integer(asInvalid): CellText := RS_Invalid; + end; + end; + end; +end; + +procedure TAccountManagerForm.FormShow(Sender: TObject); +begin + LoadForm; + RefreshList; + RefreshWebsiteAvailable; +end; + +procedure TAccountManagerForm.vtAccountListChange(Sender: TBaseVirtualTree; + Node: PVirtualNode); +begin + if Sender.SelectedCount > 0 then begin + btEdit.Enabled := True; + btDelete.Enabled := True; + btRefresh.Enabled := True; + end + else begin + btEdit.Enabled := False; + btDelete.Enabled := False; + btRefresh.Enabled := False; + end; +end; + +procedure TAccountManagerForm.FormClose(Sender: TObject; + var CloseAction: TCloseAction); +begin + SaveForm; +end; + +procedure TAccountManagerForm.FormCreate(Sender: TObject); +var + i: Integer; +begin + Websites := TStringList.Create; + WebsitesAvailable := TStringList.Create; + if Modules.Count > 0 then begin + for i := 0 to Modules.Count - 1 do + if Modules.Module[i].AccountSupport then + Websites.Add(Modules.Module[i].Website); + Websites.Sorted := True; + end; +end; + +procedure TAccountManagerForm.FormDestroy(Sender: TObject); +begin + if Assigned(Websites) then Websites.Free; + if Assigned(WebsitesAvailable) then WebsitesAvailable.Free; +end; + +procedure TAccountManagerForm.btDeleteClick(Sender: TObject); +var + node: PVirtualNode; +begin + if vtAccountList.SelectedCount > 0 then + if MessageDlg(RS_AccountDeleteConfirmation, mtConfirmation, mbYesNo, 0, mbNo) = mrYes then + begin + node := vtAccountList.GetFirstSelected; + if Assigned(node) then begin + Account.DeleteAccount(node^.Index); + RefreshList; + RefreshWebsiteAvailable; + vtAccountList.Repaint; + vtAccountListChange(vtAccountList, nil); + end; + end; +end; + +procedure TAccountManagerForm.btEditClick(Sender: TObject); +var + node: PVirtualNode; +begin + if vtAccountList.SelectedCount > 0 then begin + node := vtAccountList.GetFirstSelected; + if Assigned(node) then begin + with TAccountSetForm.Create(Self) do + try + cbWebsiteName.Items.Add(Account.ValueStr[node^.Index, 1]); + cbWebsiteName.ItemIndex := 0; + cbWebsiteName.Enabled := False; + edUsername.Text := Account.ValueStr[node^.Index, 2]; + edPassword.Text := Account.ValueStr[node^.Index, 3]; + if ShowModal = mrOK then + begin + Account.Username[cbWebsiteName.Text] := edUsername.Text; + Account.Password[cbWebsiteName.Text] := edPassword.Text; + vtAccountList.Repaint; + end; + finally + Free; + end; + end; + end; +end; + +procedure TAccountManagerForm.btAddClick(Sender: TObject); +begin + if Websites.Count = 0 then Exit; + with TAccountSetForm.Create(Self) do + try + cbWebsiteName.Items.Assign(WebsitesAvailable); + if cbWebsiteName.Items.Count > 0 then + cbWebsiteName.ItemIndex := 0; + if ShowModal = mrOK then + if Account.AddAccount(cbWebsiteName.Text, edUsername.Text, edPassword.Text) then + begin + Account.Save; + RefreshList; + RefreshWebsiteAvailable; + end; + finally + Free; + end; +end; + +procedure TAccountManagerForm.vtAccountListChecked(Sender: TBaseVirtualTree; + Node: PVirtualNode); +begin + if Assigned(Node) then + Account.ValueBool[Node^.Index, 0] := Node^.CheckState = csCheckedNormal; +end; + +end. + diff --git a/mangadownloader/forms/frmAccountSet.lfm b/mangadownloader/forms/frmAccountSet.lfm new file mode 100644 index 000000000..6ebf27740 --- /dev/null +++ b/mangadownloader/forms/frmAccountSet.lfm @@ -0,0 +1,186 @@ +object AccountSetForm: TAccountSetForm + Left = 0 + Height = 224 + Top = 0 + Width = 269 + ActiveControl = cbWebsiteName + Caption = 'Account' + ChildSizing.LeftRightSpacing = 8 + ChildSizing.TopBottomSpacing = 8 + ClientHeight = 224 + ClientWidth = 269 + Position = poMainFormCenter + LCLVersion = '1.7' + Visible = False + object cbWebsiteName: TComboBox + Left = 8 + Height = 23 + Top = 29 + Width = 253 + Align = alTop + BorderSpacing.Bottom = 20 + ItemHeight = 15 + Style = csDropDownList + TabOrder = 0 + end + object Label1: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 253 + Align = alTop + BorderSpacing.Bottom = 6 + Caption = 'Website' + ParentColor = False + end + object Label2: TLabel + Left = 8 + Height = 15 + Top = 72 + Width = 253 + Align = alTop + BorderSpacing.Bottom = 6 + Caption = 'Username' + ParentColor = False + end + object Label3: TLabel + Left = 8 + Height = 15 + Top = 126 + Width = 253 + Align = alTop + BorderSpacing.Bottom = 6 + Caption = 'Password' + ParentColor = False + end + object edUsername: TEdit + Left = 8 + Height = 23 + Top = 93 + Width = 253 + Align = alTop + BorderSpacing.Bottom = 10 + TabOrder = 1 + TextHint = 'Username' + end + object edPassword: TEdit + Left = 8 + Height = 23 + Top = 147 + Width = 253 + Align = alTop + EchoMode = emPassword + PasswordChar = '*' + TabOrder = 2 + TextHint = 'Password' + end + object pnButtons: TPanel + Left = 8 + Height = 26 + Top = 190 + Width = 253 + Align = alBottom + AutoSize = True + BevelOuter = bvNone + ClientHeight = 26 + ClientWidth = 253 + TabOrder = 3 + object btOk: TBitBtn + Left = 104 + Height = 26 + Top = 0 + Width = 61 + Align = alRight + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Ok' + Default = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 00010000000800000010000000170000001A0000001900000017000000150000 + 00110000000D0000000A000000060000000300000001FFFFFF00FFFFFF000000 + 00020000000F0000001F0000002D02330066025F00CC012B0055000000290000 + 00220000001A000000130000000C0000000600000001FFFFFF00FFFFFF000000 + 0000000000000320000006570048077200CC16A60AE8087601C406570029021E + 00000000000000000000000000000000000000000000FFFFFF00FFFFFF000747 + 00000A6500000B8300480B8200CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85 + 001B0745000000000000000000000000000000000000FFFFFF00FFFFFF000E8D + 00000D8800480D8700CC43CA33F629C318FF39CC28FF28C217FF1EAA0FEA0D87 + 00AE0D8A00100F8F0000084A00000000000000000000FFFFFF00FFFFFF000E8E + 00480E8D00CC5FD94FF933BC22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA2 + 0FE40E8D009E0F8F00081094000010950000084B0000FFFFFF00FFFFFF000F92 + 00CC6DE55CFA59D048FF69E158FC0F9200CC0F92006D139504CB34B423F832B2 + 21FF1F9F0FDF0F92008C109400021095000010950000FFFFFF00FFFFFF001196 + 0048119700CC73EA62FD119700CC119600480F9300001196004C189D08D33DB6 + 2CFB37AF26FE1FA00EDA1197007B11980000129B0000FFFFFF00FFFFFF001197 + 0000129B0048129B00CC129B0048119700000F93000011970000129B006924AA + 13D857CF46FE55CD44FD21A710D6129C006313A00000FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000113A0 + 008533B820DE61D850FF5CD54BFA1EA80CD213A1004CFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000614A3009E43C631E56BE25AFF70E95FFB14A300CCFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000014A5001014A700B077EE66FF14A700CC14A70048FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000013A2000014A5000014A5000014A6 + 000015A8000015A9001F15AA00CC15AA004814A70000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOkClick + TabOrder = 0 + end + object btCancel: TBitBtn + Left = 171 + Height = 26 + Top = 0 + Width = 82 + Align = alRight + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Cancel' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000013000000190000001900000016000000120000000F0000000E0000 + 0011000000150000001900000019000000140000000EFFFFFF00FFFFFF000000 + 001C000000260000346400005FCC00003561000000240000001D0000001B0000 + 00210000366000005FCC00003464000000270000001CFFFFFF00FFFFFF000000 + 1E0000005748000072CC1111D8FF000072CC0000574800002000000020000000 + 5748000072CC1111D8FF000072CC0000574800001E00FFFFFF00FFFFFF000000 + 8200000082CC1111D0FF1111D0FF1111D0FF000082CC00008348000083480000 + 82CC1111D0FF1111D0FF1111D0FF000082CC00008200FFFFFF00FFFFFF000000 + 860000008748000087CC1111C4FF1111C4FF1111C4FF000087CC000087CC1111 + C4FF1111C4FF1111C4FF000087CC0000874800008600FFFFFF00FFFFFF000000 + 86000000870000008C4800008DCC1111B8FF1111B8FF1111B8FF1111B8FF1111 + B8FF1111B8FF00008DCC00008C480000870000008600FFFFFF00FFFFFF000000 + 86000000870000008D0000009148000092CC1515AFFF1111ACFF1111ACFF1111 + ACFF000092CC0000914800008D000000870000008600FFFFFF00FFFFFF000000 + A1000000A00000009B0000009848000097CC2525B4FF1111A2FF1111A2FF1414 + A5FF000097CC0000984800009B000000A0000000A100FFFFFF00FFFFFF000000 + A1000000A00000009C4800009BCC5353DBFF2E2EB7FF3D3DC6FF3131BAFF1515 + 9FFF1E1EA8FF00009BCC00009C480000A0000000A100FFFFFF00FFFFFF000000 + A1000000A1480000A0CC6767EFFF3636BEFF5E5EE6FF0000A0CC0000A0CC4F4F + D7FF3636BEFF4545CDFF0000A0CC0000A1480000A100FFFFFF00FFFFFF000000 + A3000000A3CC7676FEFF4C4CD4FF7272FAFF0000A3CC0000A3480000A3480000 + A3CC6262EAFF4C4CD4FF5C5CE4FF0000A3CC0000A300FFFFFF00FFFFFF000000 + A6000000A7480000A7CC7777FFFF0000A7CC0000A7480000A3000000A3000000 + A7480000A7CC7070F8FF0000A7CC0000A7480000A600FFFFFF00FFFFFF000000 + A6000000A7000000AA480000AACC0000AA480000A7000000A3000000A3000000 + A7000000AA480000AACC0000AA480000A7000000A600FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ModalResult = 2 + TabOrder = 1 + end + end +end diff --git a/mangadownloader/forms/frmAccountSet.pas b/mangadownloader/forms/frmAccountSet.pas new file mode 100644 index 000000000..3119bddad --- /dev/null +++ b/mangadownloader/forms/frmAccountSet.pas @@ -0,0 +1,56 @@ +unit frmAccountSet; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, + ExtCtrls, Buttons; + +type + + { TAccountSetForm } + + TAccountSetForm = class(TForm) + btOk: TBitBtn; + btCancel: TBitBtn; + cbWebsiteName: TComboBox; + edUsername: TEdit; + edPassword: TEdit; + Label1: TLabel; + Label2: TLabel; + Label3: TLabel; + pnButtons: TPanel; + procedure btOkClick(Sender: TObject); + private + { private declarations } + public + { public declarations } + end; + +var + AccountSetForm: TAccountSetForm; + +resourcestring + RS_CantBeEmpty = 'Username or password can''t be empty!'; + +implementation + +{$R *.lfm} + +{ TAccountSetForm } + +procedure TAccountSetForm.btOkClick(Sender: TObject); +begin + if (edUsername.Text = '') or (edPassword.Text = '') then begin + MessageDlg(RS_CantBeEmpty, mtError, [mbOK], 0); + if edUsername.Text = '' then edUsername.SetFocus + else edPassword.SetFocus; + end + else + ModalResult := mrOK; +end; + +end. + diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 13b713e3c..ee9698317 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -264,18 +264,18 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 object sbInformation: TScrollBox Left = 0 - Height = 480 + Height = 521 Top = 0 Width = 606 HorzScrollBar.Page = 218 VertScrollBar.Page = 317 Align = alClient BorderStyle = bsNone - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 TabOrder = 0 object pnInfomation: TPanel @@ -412,18 +412,18 @@ object MainForm: TMainForm end object pnChapterList: TPanel Left = 0 - Height = 213 + Height = 254 Top = 267 Width = 606 Align = alClient BevelOuter = bvNone - ClientHeight = 213 + ClientHeight = 254 ClientWidth = 606 TabOrder = 2 object btDownload: TBitBtn Left = 387 Height = 30 - Top = 145 + Top = 186 Width = 101 Anchors = [akRight, akBottom] Caption = 'Download' @@ -469,7 +469,7 @@ object MainForm: TMainForm object cbAddAsStopped: TCheckBox Left = 4 Height = 19 - Top = 182 + Top = 223 Width = 214 Anchors = [akLeft, akBottom] Caption = 'Add to download list as stopped task' @@ -479,7 +479,7 @@ object MainForm: TMainForm end object clbChapterList: TVirtualStringTree Left = 4 - Height = 125 + Height = 166 Top = 0 Width = 563 Anchors = [akTop, akLeft, akRight, akBottom] @@ -507,7 +507,7 @@ object MainForm: TMainForm object btReadOnline: TBitBtn Left = 493 Height = 30 - Top = 145 + Top = 186 Width = 108 Anchors = [akRight, akBottom] Caption = 'Read online' @@ -553,7 +553,7 @@ object MainForm: TMainForm object btBrowse: TSpeedButton Left = 360 Height = 23 - Top = 148 + Top = 189 Width = 23 Anchors = [akRight, akBottom] Glyph.Data = { @@ -641,7 +641,7 @@ object MainForm: TMainForm object btAddToFavorites: TBitBtn Left = 387 Height = 30 - Top = 179 + Top = 220 Width = 214 Anchors = [akRight, akBottom] Caption = 'Add to favorites' @@ -687,7 +687,7 @@ object MainForm: TMainForm object edSaveTo: TEdit Left = 4 Height = 23 - Top = 148 + Top = 189 Width = 353 Anchors = [akLeft, akRight, akBottom] ParentFont = False @@ -697,7 +697,7 @@ object MainForm: TMainForm object lbSaveTo: TLabel Left = 4 Height = 15 - Top = 130 + Top = 171 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' @@ -1619,12 +1619,12 @@ object MainForm: TMainForm end object tsFavorites: TTabSheet Caption = 'Favorites' - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 object btFavoritesCheckNewChapter: TBitBtn Left = 33 Height = 40 - Top = 400 + Top = 441 Width = 545 Anchors = [akLeft, akRight, akBottom] Caption = 'Check for new chapter' @@ -1669,7 +1669,7 @@ object MainForm: TMainForm end object vtFavorites: TVirtualStringTree Left = 2 - Height = 389 + Height = 430 Top = 4 Width = 600 Align = alTop @@ -1732,7 +1732,7 @@ object MainForm: TMainForm object btFavoritesImport: TBitBtn Left = 33 Height = 24 - Top = 446 + Top = 487 Width = 545 Anchors = [akLeft, akRight, akBottom] Caption = 'Import list' @@ -1779,7 +1779,7 @@ object MainForm: TMainForm object btCancelFavoritesCheck: TSpeedButton Left = 538 Height = 40 - Top = 400 + Top = 441 Width = 40 Anchors = [akRight, akBottom] Glyph.Data = { @@ -2747,11 +2747,11 @@ object MainForm: TMainForm end object tsWebsites: TTabSheet Caption = 'Websites' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 2 - Height = 336 + Height = 377 Top = 35 Width = 573 Align = alClient @@ -2891,6 +2891,9 @@ object MainForm: TMainForm end end end + object tsAccounts: TTabSheet + Caption = 'Accounts' + end object tsMisc: TTabSheet Caption = 'Misc' ClientHeight = 375 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a3cc7b42b..a58d00c3c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,8 +22,8 @@ interface FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, - frmDropTarget, CheckUpdate, accountmanager, accountmanagerdb, - USimpleException, USimpleLogger; + frmDropTarget, frmAccountManager, CheckUpdate, accountmanager, + accountmanagerdb, USimpleException, USimpleLogger; type @@ -70,6 +70,7 @@ TMainForm = class(TForm) pcAbout: TPageControl; pmSbMain: TPopupMenu; sbSaveTo: TScrollBox; + tsAccounts: TTabSheet; tsAboutText: TTabSheet; tsChangelogText: TTabSheet; TransferRateToolset: TChartToolset; @@ -1088,6 +1089,14 @@ procedure TMainForm.FormCreate(Sender: TObject); RightToLeft := False; EndEllipsis := True; end; + + // embed form + AccountManagerForm := TAccountManagerForm.Create(Self); + with AccountManagerForm do begin + Parent := tsAccounts; + Align := alClient; + Show; + end; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -1161,6 +1170,10 @@ procedure TMainForm.CloseNow; FavoriteManager.Backup; SaveOptions; SaveFormInformation; + + //embed form + if Assigned(AccountManagerForm) then + AccountManagerForm.Close; end; procedure TMainForm.FormDestroy(Sender: TObject); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d34b37dd2..d49844794 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -12,6 +12,30 @@ msgstr "" "X-Generator: Poedit 1.8.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "" + #: frmimportfavorites.rs_importcompleted msgid "Import completed." msgstr "Import completed." @@ -67,6 +91,10 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" #: frmmain.rs_dlgtitleexistindllist +#, fuzzy +#| msgid "" +#| "This title are already in download list.\n" +#| "Do you want to download it anyway?\n" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" @@ -95,6 +123,10 @@ msgid "URL not supported!" msgstr "URL not supported!" #: frmmain.rs_droptargetmodeitems +#, fuzzy +#| msgid "" +#| "Download all\n" +#| "Add to favorites\n" msgid "" "Download all\n" "Add to favorites\n" @@ -103,6 +135,11 @@ msgstr "" "Add to favorites\n" #: frmmain.rs_filterstatusitems +#, fuzzy +#| msgid "" +#| "Completed\n" +#| "Ongoing\n" +#| "<none>\n" msgid "" "Completed\n" "Ongoing\n" @@ -117,6 +154,10 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader already running!" #: frmmain.rs_hintfavoriteproblem +#, fuzzy +#| msgid "" +#| "There is a problem with this data!\n" +#| "Removing and re-adding this data may fix the problem.\n" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" @@ -170,11 +211,12 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" #: frmmain.rs_lbloptionexternalparamshint +#, fuzzy #| msgid "" #| "%s : Path to the manga\n" #| "%s : Chapter filename\n" #| "\n" -#| "Example : %s%s\n" +#| "Example : \"%s%s\"\n" msgid "" "%s : Path to the manga\n" "%s : Chapter filename\n" @@ -213,6 +255,12 @@ msgid "One week" msgstr "One week" #: frmmain.rs_optionfmddoitems +#, fuzzy +#| msgid "" +#| "Do nothing\n" +#| "Exit FMD\n" +#| "Shutdown\n" +#| "Hibernate\n" msgid "" "Do nothing\n" "Exit FMD\n" @@ -257,6 +305,87 @@ msgstr "System will hibernate in %d second." msgid "System will shutdown in %d second." msgstr "System will shutdown in %d second." +#: taccountmanagerform.btadd.caption +msgid "Add" +msgstr "" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "" + +#: taccountmanagerform.btedit.caption +msgid "Edit" +msgstr "" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#, fuzzy +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Username" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#, fuzzy +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Status" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#, fuzzy +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Status" + +#: taccountsetform.btcancel.caption +#, fuzzy +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Cancel" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "" + +#: taccountsetform.edpassword.texthint +#, fuzzy +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Password" + +#: taccountsetform.edusername.texthint +#, fuzzy +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Status" + +#: taccountsetform.label1.caption +#, fuzzy +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Username" + +#: taccountsetform.label2.caption +#, fuzzy +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Status" + +#: taccountsetform.label3.caption +#, fuzzy +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Password" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1093,6 +1222,7 @@ msgid "New manga based on it's update time (days)" msgstr "New manga based on it's update time (days)" #: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" msgid "Password" msgstr "Password" @@ -1118,6 +1248,7 @@ msgid "Rename digits" msgstr "Rename digits" #: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Username" @@ -1349,6 +1480,10 @@ msgstr "About" msgid "About FMD" msgstr "About FMD" +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "" + #: tmainform.tschangelogtext.caption msgid "Changelog" msgstr "Changelog" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 6e4f39563..2bafe7d7c 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -12,6 +12,30 @@ msgstr "" "X-Generator: Poedit 1.8.2\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "" + #: frmimportfavorites.rs_importcompleted msgid "Import completed." msgstr "Selesai mengimpor." @@ -67,6 +91,10 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Apakah Anda yakin ingin menghapus unduhan ini?" #: frmmain.rs_dlgtitleexistindllist +#, fuzzy +#| msgid "" +#| "This title are already in download list.\n" +#| "Do you want to download it anyway?\n" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" @@ -95,6 +123,10 @@ msgid "URL not supported!" msgstr "URL tidak didukung!" #: frmmain.rs_droptargetmodeitems +#, fuzzy +#| msgid "" +#| "Download all\n" +#| "Add to favorites\n" msgid "" "Download all\n" "Add to favorites\n" @@ -103,6 +135,11 @@ msgstr "" "Tambahkan ke kesukaan\n" #: frmmain.rs_filterstatusitems +#, fuzzy +#| msgid "" +#| "Completed\n" +#| "Ongoing\n" +#| "<none>\n" msgid "" "Completed\n" "Ongoing\n" @@ -117,6 +154,10 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader sudah berjalan!" #: frmmain.rs_hintfavoriteproblem +#, fuzzy +#| msgid "" +#| "There is a problem with this data!\n" +#| "Removing and re-adding this data may fix the problem.\n" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" @@ -170,6 +211,12 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Otomatis periksa bab baru setiap %d menit" #: frmmain.rs_lbloptionexternalparamshint +#, fuzzy +#| msgid "" +#| "%s : Path to the manga\n" +#| "%s : Chapter filename\n" +#| "\n" +#| "Example : \"%s%s\"\n" msgid "" "%s : Path to the manga\n" "%s : Chapter filename\n" @@ -207,6 +254,12 @@ msgid "One week" msgstr "Satu minggu" #: frmmain.rs_optionfmddoitems +#, fuzzy +#| msgid "" +#| "Do nothing\n" +#| "Exit FMD\n" +#| "Shutdown\n" +#| "Hibernate\n" msgid "" "Do nothing\n" "Exit FMD\n" @@ -251,6 +304,87 @@ msgstr "Komputer akan dihibernasi dalam %d detik" msgid "System will shutdown in %d second." msgstr "Komputer akan dimatikan dalam %d detik" +#: taccountmanagerform.btadd.caption +msgid "Add" +msgstr "" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "" + +#: taccountmanagerform.btedit.caption +msgid "Edit" +msgstr "" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#, fuzzy +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Nama user" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#, fuzzy +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Status" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#, fuzzy +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Status" + +#: taccountsetform.btcancel.caption +#, fuzzy +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Batal" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "" + +#: taccountsetform.edpassword.texthint +#, fuzzy +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Kata kunci" + +#: taccountsetform.edusername.texthint +#, fuzzy +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Status" + +#: taccountsetform.label1.caption +#, fuzzy +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Nama user" + +#: taccountsetform.label2.caption +#, fuzzy +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Status" + +#: taccountsetform.label3.caption +#, fuzzy +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Kata kunci" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1068,6 +1202,7 @@ msgid "New manga based on it's update time (days)" msgstr "Komik baru berdasarkan waktu pembaruan (hari)" #: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" msgid "Password" msgstr "Kata kunci" @@ -1093,6 +1228,7 @@ msgid "Rename digits" msgstr "Ganti nama digit" #: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Nama user" @@ -1324,6 +1460,10 @@ msgstr "Tentang" msgid "About FMD" msgstr "Tentang FMD" +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "" + #: tmainform.tschangelogtext.caption msgid "Changelog" msgstr "Catatan perubahan" @@ -1661,3 +1801,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 56a6076a7..e33769c81 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1,6 +1,30 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "" + #: frmimportfavorites.rs_importcompleted msgid "Import completed." msgstr "" @@ -223,6 +247,72 @@ msgstr "" msgid "System will shutdown in %d second." msgstr "" +#: taccountmanagerform.btadd.caption +msgid "Add" +msgstr "" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "" + +#: taccountmanagerform.btedit.caption +msgid "Edit" +msgstr "" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" +msgid "Website" +msgstr "" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[2].TEXT" +msgid "Username" +msgstr "" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[3].TEXT" +msgid "Status" +msgstr "" + +#: taccountsetform.btcancel.caption +msgctxt "TACCOUNTSETFORM.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "" + +#: taccountsetform.edpassword.texthint +msgctxt "TACCOUNTSETFORM.EDPASSWORD.TEXTHINT" +msgid "Password" +msgstr "" + +#: taccountsetform.edusername.texthint +msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" +msgid "Username" +msgstr "" + +#: taccountsetform.label1.caption +msgctxt "TACCOUNTSETFORM.LABEL1.CAPTION" +msgid "Website" +msgstr "" + +#: taccountsetform.label2.caption +msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" +msgid "Username" +msgstr "" + +#: taccountsetform.label3.caption +msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" +msgid "Password" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" @@ -1020,6 +1110,7 @@ msgid "New manga based on it's update time (days)" msgstr "" #: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" msgid "Password" msgstr "" @@ -1045,6 +1136,7 @@ msgid "Rename digits" msgstr "" #: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "" @@ -1276,6 +1368,10 @@ msgstr "" msgid "About FMD" msgstr "" +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "" + #: tmainform.tschangelogtext.caption msgid "Changelog" msgstr "" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e176ee771..a980b881b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -246,7 +246,7 @@ <PackageName Value="LCL"/> </Item5> </RequiredPackages> - <Units Count="7"> + <Units Count="9"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -293,6 +293,19 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit6> + <Unit7> + <Filename Value="forms\frmAccountManager.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="AccountManagerForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit7> + <Unit8> + <Filename Value="forms\frmAccountSet.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="AccountSetForm"/> + <ResourceBaseClass Value="Form"/> + </Unit8> </Units> </ProjectOptions> <CompilerOptions> From bf05c9007dfe362c42dfe0915851283cbe9f816a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 08:23:16 +0800 Subject: [PATCH 0622/2794] accountmanagerdb, add more property and fix --- baseunits/accountmanagerdb.pas | 49 +++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index d18cc038c..09b78d5a6 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -28,6 +28,7 @@ TAccountManager = class function OpenDBTable: Boolean; function GetValueString(const AName, AField: string): string; function GetValueBoolean(const AName, AField: string): boolean; + function GetValueInteger(const AName, AField: string): Integer; function GetValueStr(const RecIndex, FieldIndex: Integer): string; function GetValueBool(const RecIndex, FieldIndex: Integer): boolean; function GetValueInt(const RecIndex, FieldIndex: Integer): Integer; @@ -35,17 +36,18 @@ TAccountManager = class function GetEnabled(AName: string): boolean; function GetPassword(AName: string): string; function GetCookies(AName: string): string; - function GetStatus(AName: string): string; + function GetStatus(AName: string): TAccountStatus; procedure SetUsername(AName: string; AValue: string); procedure SetEnabled(AName: string; AValue: boolean); procedure SetPassword(AName: string; AValue: string); procedure SetCookies(AName: string; AValue: string); - procedure SetStatus(AName: string; AValue: string); + procedure SetStatus(AName: string; AValue: TAccountStatus); procedure SetValueString(const AName, AField, AValue: string); procedure SetValueBoolean(const AName, AField: string; AValue: boolean); + procedure SetValueInteger(const AName, AField: string; AValue: Integer); procedure SetValueStr(const RecIndex, FieldIndex: Integer; AValue: string); procedure SetValueBool(const RecIndex, FieldIndex: Integer; AValue: boolean); - procedure SetValueInt(const RecIndex, FieldIndex: Integer; AValue: Integer); + procedure SetValueInt(const RecIndex, FieldIndex, AValue: Integer); procedure GetRecordCount; procedure Vacuum; public @@ -59,7 +61,7 @@ TAccountManager = class property Username[AName: string]: string read GetUsername write SetUsername; property Password[AName: string]: string read GetPassword write SetPassword; property Cookies[AName: string]: string read GetCookies write SetCookies; - property Status[AName: string]: string read GetStatus write SetStatus; + property Status[AName: string]: TAccountStatus read GetStatus write SetStatus; property ValueStr[const RecIndex, FieldIndex: Integer]: string read GetValueStr write SetValueStr; property ValueBool[const RecIndex, FieldIndex: Integer]: boolean read GetValueBool write SetValueBool; property ValueInt[const RecIndex, FieldIndex: Integer]: Integer read GetValueInt write SetValueInt; @@ -123,9 +125,9 @@ function TAccountManager.GetCookies(AName: string): string; Result := decode(GetValueString(AName, 'cookies')); end; -function TAccountManager.GetStatus(AName: string): string; +function TAccountManager.GetStatus(AName: string): TAccountStatus; begin - Result := GetValueString(AName, 'status'); + Result := TAccountStatus(GetValueInteger(AName, 'status')); end; function TAccountManager.GetValueStr(const RecIndex, FieldIndex: Integer @@ -187,9 +189,9 @@ procedure TAccountManager.SetCookies(AName: string; AValue: string); SetValueString(AName, 'cookies', encode(AValue)); end; -procedure TAccountManager.SetStatus(AName: string; AValue: string); +procedure TAccountManager.SetStatus(AName: string; AValue: TAccountStatus); begin - SetValueString(AName, 'status', AValue); + SetValueInteger(AName, 'status', Integer(AValue)); end; function TAccountManager.CreateDB: Boolean; @@ -273,6 +275,18 @@ function TAccountManager.GetValueBoolean(const AName, AField: string): boolean; end; end; +function TAccountManager.GetValueInteger(const AName, AField: string): Integer; +begin + Result := 0; + if fquery.Active = False then Exit; + EnterCriticalsection(locklocate); + try + if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsInteger; + finally + LeaveCriticalsection(locklocate); + end; +end; + procedure TAccountManager.SetValueStr(const RecIndex, FieldIndex: Integer; AValue: string); begin @@ -305,8 +319,7 @@ procedure TAccountManager.SetValueBool(const RecIndex, FieldIndex: Integer; end; end; -procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex: Integer; - AValue: Integer); +procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex, AValue: Integer); begin if fquery.Active = False then Exit; if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; @@ -352,6 +365,22 @@ procedure TAccountManager.SetValueBoolean(const AName, AField: string; end; end; +procedure TAccountManager.SetValueInteger(const AName, AField: string; + AValue: Integer); +begin + if fquery.Active = False then Exit; + EnterCriticalsection(locklocate); + try + if fquery.Locate('aname', AName, []) then begin + fquery.Edit; + fquery.FieldByName(AField).AsInteger := AValue; + fquery.Post; + end; + finally + LeaveCriticalsection(locklocate); + end; +end; + procedure TAccountManager.GetRecordCount; begin if fquery.Active then begin From b96d7843c197ddd3067b1535bcb2babfd3bd3c37 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 08:23:34 +0800 Subject: [PATCH 0623/2794] websitemodules, add login function --- baseunits/WebsiteModules.pas | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 47cbdc2e6..4614d1eab 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager, RegExpr; + Classes, SysUtils, uData, uDownloadsManager, uBaseUnit, RegExpr; const MODULE_NOT_FOUND = -1; @@ -37,8 +37,10 @@ TModuleContainer = class; TOnDownloadImage = function(var DownloadThread: TDownloadThread; const URL, Path, Name, Prefix: String; Module: TModuleContainer): Boolean; + TOnLogin = function(var AHTTP: THTTPSendThread): Boolean; + TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, - MMTaskStart, MMGetPageNumber, MMGetImageURL, MMDownloadImage); + MMTaskStart, MMGetPageNumber, MMGetImageURL, MMDownloadImage, MMLogin); { TModuleContainer } @@ -67,6 +69,7 @@ TModuleContainer = class OnGetPageNumber: TOnGetPageNumber; OnGetImageURL: TOnGetImageURL; OnDownloadImage: TOnDownloadImage; + OnLogin: TOnLogin; constructor Create; destructor Destroy; override; public @@ -140,9 +143,12 @@ TWebsiteModules = class overload; function DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; + const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; overload; function DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix, Website: String): Boolean; + const URL, Path, Name, Prefix, Website: String): Boolean; overload; + + function Login(var AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; overload; + function Login(var AHTTP: THTTPSendThread; const Website: String): Boolean; overload; procedure LockModules; procedure UnlockModules; @@ -308,7 +314,8 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; MMGetInfo: Result := Assigned(OnGetInfo); MMGetPageNumber: Result := Assigned(OnGetPageNumber); MMGetImageURL: Result := Assigned(OnGetImageURL); - MMDownloadImage: Result := Assigned(OnDownloadImage) + MMDownloadImage: Result := Assigned(OnDownloadImage); + MMLogin: Result := Assigned(OnLogin); else Result := False; end; @@ -454,6 +461,21 @@ function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; LocateModule(Website)); end; +function TWebsiteModules.Login(var AHTTP: THTTPSendThread; + const ModuleId: Integer): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnLogin) then + Result := TModuleContainer(FModuleList[ModuleId]).OnLogin(AHTTP); +end; + +function TWebsiteModules.Login(var AHTTP: THTTPSendThread; const Website: String + ): Boolean; +begin + Result := Login(AHTTP, LocateModule(Website)); +end; + procedure TWebsiteModules.LockModules; begin EnterCriticalsection(FCSModules); From 7df4db745f32f426472135e1a33480ab1207a6d5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 09:17:01 +0800 Subject: [PATCH 0624/2794] accountmanagerdb, fix status on open --- baseunits/accountmanagerdb.pas | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 09b78d5a6..996216412 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -26,6 +26,7 @@ TAccountManager = class function InternalOpenDB: Boolean; function CreateDBTable: Boolean; function OpenDBTable: Boolean; + function FixStatus: Boolean; function GetValueString(const AName, AField: string): string; function GetValueBoolean(const AName, AField: string): boolean; function GetValueInteger(const AName, AField: string): Integer; @@ -241,6 +242,7 @@ function TAccountManager.OpenDBTable: Boolean; if fquery.Active then fquery.Close; fquery.SQL.Text := 'SELECT * FROM ' + AnsiQuotedStr(ctablename, '"'); fquery.Open; + FixStatus; GetRecordCount; Result := fquery.Active; except @@ -249,6 +251,28 @@ function TAccountManager.OpenDBTable: Boolean; end; end; +function TAccountManager.FixStatus: Boolean; +begin + Result := False; + if fquery.Active = False then Exit; + EnterCriticalsection(locklocate); + try + if fquery.RecordCount > 0 then begin + fquery.First; + while not fquery.EOF do begin + if fquery.FieldByName('status').AsInteger = Integer(asChecking) then begin + fquery.Edit; + fquery.FieldByName('status').AsInteger := Integer(asUnknown); + fquery.Post; + end; + fquery.Next; + end; + end; + finally + LeaveCriticalsection(locklocate); + end; +end; + function TAccountManager.GetValueString(const AName, AField: string): string; begin Result := ''; From d54654430acfc4e3077359620743af4a10d6c2fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 09:18:52 +0800 Subject: [PATCH 0625/2794] ba to to, fix login --- baseunits/modules/Batoto.pas | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 9839e46cd..cb02c482f 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -131,20 +131,21 @@ function CheckLogin(const source: string): Boolean; Result := (Pos('class=''logged_in''', source) > 0) or (Pos('class="logged_in"', source) > 0); end; -function Login(http: THTTPSendThread): Boolean; +function Login(var AHTTP: THTTPSendThread): Boolean; var query: TXQueryEngineHTML; source: TStringList; s, key, user, pass: string; begin Result := False; - if http = nil then Exit; + if AHTTP = nil then Exit; if Account.Enabled[modulename] = False then Exit; if Account.Username[modulename] = '' then Exit; if TryEnterCriticalsection(locklogin) > 0 then - with http do begin + with AHTTP do begin onlogin := True; + Account.Status[modulename] := asChecking; Reset; Cookies.Clear; if Get(urlroot) then begin @@ -165,10 +166,9 @@ function Login(http: THTTPSendThread): Boolean; Result := Cookies.Values['pass_hash'] <> ''; if Result then begin Account.Cookies[modulename] := GetCookies; - Account.Status[modulename] := 'OK'; - end else begin - Account.Status[modulename] := 'Invalid user/password!'; - end; + Account.Status[modulename] := asValid; + end else + Account.Status[modulename] := asInvalid; Account.Save; end; end; @@ -179,12 +179,14 @@ function Login(http: THTTPSendThread): Boolean; end; end; onlogin := False; + if Account.Status[modulename] = asChecking then + Account.Status[modulename] := asUnknown; LeaveCriticalsection(locklogin); end else begin while onlogin do Sleep(1000); - if Result then http.Cookies.Text := Account.Cookies[modulename]; + if Result then AHTTP.Cookies.Text := Account.Cookies[modulename]; end; end; @@ -339,6 +341,7 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; + OnLogin := @Login; end; end; From a669ab70531e571888520902b56a6df2dd205222 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 09:38:39 +0800 Subject: [PATCH 0626/2794] formaccountmanager, fix and add refresh function --- mangadownloader/forms/frmAccountManager.lfm | 2 + mangadownloader/forms/frmAccountManager.pas | 183 +++++++++++++++++++- mangadownloader/md.lpi | 1 + 3 files changed, 179 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 7b8cdbba7..0528c3caa 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -223,6 +223,7 @@ object AccountManagerForm: TAccountManagerForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } + OnClick = btRefreshClick TabOrder = 3 end end @@ -259,6 +260,7 @@ object AccountManagerForm: TAccountManagerForm TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect] + OnBeforeCellPaint = vtAccountListBeforeCellPaint OnChange = vtAccountListChange OnChecked = vtAccountListChecked OnGetText = vtAccountListGetText diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 933b79794..981850736 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -5,9 +5,9 @@ interface uses - Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, - Buttons, ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, - frmAccountSet, USimpleLogger; + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons, + ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, uFMDThread, + uBaseUnit, frmAccountSet, USimpleLogger, USimpleException; type @@ -23,10 +23,14 @@ TAccountManagerForm = class(TForm) procedure btAddClick(Sender: TObject); procedure btDeleteClick(Sender: TObject); procedure btEditClick(Sender: TObject); + procedure btRefreshClick(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); + procedure vtAccountListBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); procedure vtAccountListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtAccountListChecked(Sender: TBaseVirtualTree; Node: PVirtualNode ); @@ -48,9 +52,41 @@ TAccountManagerForm = class(TForm) procedure RefreshWebsiteAvailable; end; + TAccountCheck = class; + + { TAccountCheckThread } + + TAccountCheckThread = class(TFMDThread) + private + fwebsite: String; + fhttp: THTTPSendThread; + fthreadlist: TAccountCheck; + procedure SyncStatus; + protected + procedure Execute; override; + public + constructor Create(const AWebsite: String; ThreadList: TAccountCheck); + destructor Destroy; override; + end; + + TAccountCheck = class + private + fthreads: TFPList; + fthreadslock: TRTLCriticalSection; + public + constructor Create; + destructor Destroy; override; + procedure AddThread(const t: TAccountCheckThread); + procedure DeleteThread(const t: TAccountCheckThread); + procedure StopAll; + end; + var AccountManagerForm: TAccountManagerForm; +const + CL_HLRedMarks = $008080FF; + resourcestring RS_Unknown = 'Unknown'; RS_Checking = 'Checking'; @@ -64,9 +100,107 @@ implementation var Websites, WebsitesAvailable: TStringlist; + AccountThreadList: TAccountCheck; {$R *.lfm} +{ TAccountCheck } + +constructor TAccountCheck.Create; +begin + fthreads := TFPList.Create; + InitCriticalSection(fthreadslock); +end; + +destructor TAccountCheck.Destroy; +begin + if fthreads.Count > 0 then + StopAll; + while fthreads.Count > 0 do Sleep(250); + fthreads.Free; + DoneCriticalsection(fthreadslock); + inherited Destroy; +end; + +procedure TAccountCheck.AddThread(const t: TAccountCheckThread); +begin + EnterCriticalsection(fthreadslock); + try + fthreads.Add(t); + finally + LeaveCriticalsection(fthreadslock); + end; +end; + +procedure TAccountCheck.DeleteThread(const t: TAccountCheckThread); +begin + EnterCriticalsection(fthreadslock); + try + fthreads.Remove(t); + finally + LeaveCriticalsection(fthreadslock); + end; +end; + +procedure TAccountCheck.StopAll; +var + i: Integer; +begin + EnterCriticalsection(fthreadslock); + try + if fthreads.Count > 0 then + for i := 0 to fthreads.Count - 1 do + TAccountCheckThread(fthreads[i]).Terminate; + finally + LeaveCriticalsection(fthreadslock); + end; +end; + +{ TAccountCheckThread } + +procedure TAccountCheckThread.SyncStatus; +begin + if Assigned(AccountManagerForm) then + AccountManagerForm.vtAccountList.Repaint; +end; + +procedure TAccountCheckThread.Execute; +var + p: Integer; +begin + if fwebsite = '' then Exit; + try + p := Modules.LocateModule(fwebsite); + if p > -1 then + Modules.Login(fhttp, p); + Synchronize(@SyncStatus); + except + on E: Exception do + ExceptionHandle(Self, E); + end; +end; + +constructor TAccountCheckThread.Create(const AWebsite: String; + ThreadList: TAccountCheck); +begin + inherited Create(False); + if AWebsite <> '' then fwebsite := AWebsite + else fwebsite := ''; + fhttp := THTTPSendThread.Create(Self); + if Assigned(ThreadList) then begin + fthreadlist := ThreadList; + fthreadlist.AddThread(Self); + end + else fthreadlist := nil; +end; + +destructor TAccountCheckThread.Destroy; +begin + if Assigned(fthreadlist) then fthreadlist.DeleteThread(Self); + if Assigned(fhttp) then fhttp.Free; + inherited Destroy; +end; + { TAccountManagerForm } procedure TAccountManagerForm.vtAccountListInitNode(Sender: TBaseVirtualTree; @@ -80,6 +214,7 @@ procedure TAccountManagerForm.vtAccountListPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); begin + if node = nil then Exit; if Node^.CheckState = csUncheckedNormal then TargetCanvas.Font.Color := clGrayText else TargetCanvas.Font.Color := clDefault; end; @@ -140,9 +275,10 @@ procedure TAccountManagerForm.vtAccountListGetText(Sender: TBaseVirtualTree; 1: CellText := Account.ValueStr[Node^.Index, 1]; 2: CellText := Account.ValueStr[Node^.Index, 2]; 3: case Account.ValueInt[Node^.Index, 5] of - Integer(asUnknown): CellText := RS_Unknown; - Integer(asValid) : CellText := RS_Valid; - Integer(asInvalid): CellText := RS_Invalid; + Integer(asUnknown) : CellText := RS_Unknown; + Integer(asChecking): CellText := RS_Checking; + Integer(asValid) : CellText := RS_Valid; + Integer(asInvalid) : CellText := RS_Invalid; end; end; end; @@ -155,6 +291,18 @@ procedure TAccountManagerForm.FormShow(Sender: TObject); RefreshWebsiteAvailable; end; +procedure TAccountManagerForm.vtAccountListBeforeCellPaint( + Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; + Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +begin + if Node = nil then Exit; + if Account.ValueInt[Node^.Index, 5] = Integer(asInvalid) then begin + TargetCanvas.Brush.Color := CL_HLRedMarks; + TargetCanvas.FillRect(CellRect); + end; +end; + procedure TAccountManagerForm.vtAccountListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); begin @@ -174,6 +322,7 @@ procedure TAccountManagerForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin SaveForm; + AccountThreadList.StopAll; end; procedure TAccountManagerForm.FormCreate(Sender: TObject); @@ -182,6 +331,7 @@ procedure TAccountManagerForm.FormCreate(Sender: TObject); begin Websites := TStringList.Create; WebsitesAvailable := TStringList.Create; + AccountThreadList := TAccountCheck.Create; if Modules.Count > 0 then begin for i := 0 to Modules.Count - 1 do if Modules.Module[i].AccountSupport then @@ -194,6 +344,7 @@ procedure TAccountManagerForm.FormDestroy(Sender: TObject); begin if Assigned(Websites) then Websites.Free; if Assigned(WebsitesAvailable) then WebsitesAvailable.Free; + if Assigned(AccountThreadList) then AccountThreadList.Free; end; procedure TAccountManagerForm.btDeleteClick(Sender: TObject); @@ -232,7 +383,7 @@ procedure TAccountManagerForm.btEditClick(Sender: TObject); begin Account.Username[cbWebsiteName.Text] := edUsername.Text; Account.Password[cbWebsiteName.Text] := edPassword.Text; - vtAccountList.Repaint; + btRefreshClick(btRefresh); end; finally Free; @@ -241,6 +392,22 @@ procedure TAccountManagerForm.btEditClick(Sender: TObject); end; end; +procedure TAccountManagerForm.btRefreshClick(Sender: TObject); +var + node: PVirtualNode; + web: String; +begin + if vtAccountList.SelectedCount = 0 then Exit; + node := vtAccountList.GetFirstSelected; + if node = nil then Exit; + if Account.ValueInt[node^.Index, 5] = Integer(asChecking) then Exit; + web := Account.ValueStr[node^.Index, 1]; + if web <> '' then begin + TAccountCheckThread.Create(web, AccountThreadList); + vtAccountList.Repaint; + end; +end; + procedure TAccountManagerForm.btAddClick(Sender: TObject); begin if Websites.Count = 0 then Exit; @@ -255,6 +422,8 @@ procedure TAccountManagerForm.btAddClick(Sender: TObject); Account.Save; RefreshList; RefreshWebsiteAvailable; + vtAccountList.Selected[vtAccountList.GetLast] := True; + btRefreshClick(btRefresh); end; finally Free; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index a980b881b..ac98b055d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -304,6 +304,7 @@ <Filename Value="forms\frmAccountSet.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="AccountSetForm"/> + <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit8> </Units> From 78ddb355bb28b30480cdf98ca3a1d52f74bb1800 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 10:10:30 +0800 Subject: [PATCH 0627/2794] accountmanagerdb, encode pass and cookies --- baseunits/accountmanagerdb.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 996216412..ad0455855 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -140,6 +140,7 @@ function TAccountManager.GetValueStr(const RecIndex, FieldIndex: Integer try fquery.RecNo := RecIndex + 1; Result := fquery.Fields[FieldIndex].AsString; + if (FieldIndex = 3) or (FieldIndex = 4) then Result := decode(Result); except end; end; @@ -320,7 +321,10 @@ procedure TAccountManager.SetValueStr(const RecIndex, FieldIndex: Integer; try fquery.RecNo := RecIndex + 1; fquery.Edit; - fquery.Fields[FieldIndex].AsString := AValue; + if (FieldIndex = 3) or (FieldIndex = 4) then + fquery.Fields[FieldIndex].AsString := encode(AValue) + else + fquery.Fields[FieldIndex].AsString := decode(AValue); fquery.Post; finally LeaveCriticalsection(locklocate); From 623faab0e7af2d6842fae05c874bf8918f1f735d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Dec 2015 10:14:22 +0800 Subject: [PATCH 0628/2794] frmaccountmanager, only refresh if changed --- mangadownloader/forms/frmAccountManager.pas | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 981850736..72d60f364 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -368,6 +368,7 @@ procedure TAccountManagerForm.btDeleteClick(Sender: TObject); procedure TAccountManagerForm.btEditClick(Sender: TObject); var node: PVirtualNode; + u, p: String; begin if vtAccountList.SelectedCount > 0 then begin node := vtAccountList.GetFirstSelected; @@ -377,14 +378,16 @@ procedure TAccountManagerForm.btEditClick(Sender: TObject); cbWebsiteName.Items.Add(Account.ValueStr[node^.Index, 1]); cbWebsiteName.ItemIndex := 0; cbWebsiteName.Enabled := False; - edUsername.Text := Account.ValueStr[node^.Index, 2]; - edPassword.Text := Account.ValueStr[node^.Index, 3]; + u := Account.ValueStr[node^.Index, 2]; + p := Account.ValueStr[node^.Index, 3]; + edUsername.Text := u; + edPassword.Text := p; if ShowModal = mrOK then - begin - Account.Username[cbWebsiteName.Text] := edUsername.Text; - Account.Password[cbWebsiteName.Text] := edPassword.Text; - btRefreshClick(btRefresh); - end; + if (edUsername.Text <> u) or (edPassword.Text <> p) then begin + Account.Username[cbWebsiteName.Text] := edUsername.Text; + Account.Password[cbWebsiteName.Text] := edPassword.Text; + btRefreshClick(btRefresh); + end; finally Free; end; From 0f9caf28eac95fa9b1fd832edaf26a7a6bd13cb3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 12:18:33 +0800 Subject: [PATCH 0629/2794] fix some function result close #122 --- baseunits/uBaseUnit.pas | 59 +++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c56668da9..bb3c46259 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1254,49 +1254,49 @@ function SitesWithSortedList(const website : String) : Boolean; var i: Integer = -1; begin + Result := False; if Modules.ModuleAvailable(website, i) then begin Result := Modules.Module[i].SortedList; Exit; end; - if not Result then - Result := SitesMemberOf(website, [ - FAKKU_ID, - PURURIN_ID, - NINEMANGA_ID, - NINEMANGA_ES_ID, - NINEMANGA_CN_ID, - NINEMANGA_RU_ID, - NINEMANGA_DE_ID, - NINEMANGA_IT_ID, - NINEMANGA_BR_ID, - MANGACOW_ID, - ONEMANGA_ID, - MYREADINGMANGAINFO_ID, - NHENTAI_ID, - MANGA2U_ID, - PORNCOMIX_ID, - XXCOMICS_ID, - XXCOMICSMT_ID, - XXCOMICS3D_ID, - PORNCOMIXRE_ID, - PORNCOMIXIC_ID, - PORNXXXCOMICS_ID, - MANGAPARK_ID, - SENMANGA_ID - ]); + Result := SitesMemberOf(website, [ + FAKKU_ID, + PURURIN_ID, + NINEMANGA_ID, + NINEMANGA_ES_ID, + NINEMANGA_CN_ID, + NINEMANGA_RU_ID, + NINEMANGA_DE_ID, + NINEMANGA_IT_ID, + NINEMANGA_BR_ID, + MANGACOW_ID, + ONEMANGA_ID, + MYREADINGMANGAINFO_ID, + NHENTAI_ID, + MANGA2U_ID, + PORNCOMIX_ID, + XXCOMICS_ID, + XXCOMICSMT_ID, + XXCOMICS3D_ID, + PORNCOMIXRE_ID, + PORNCOMIXIC_ID, + PORNXXXCOMICS_ID, + MANGAPARK_ID, + SENMANGA_ID + ]); end; function SitesWithoutFavorites(const website : String) : Boolean; var i: Integer = -1; begin + Result := False; if Modules.ModuleAvailable(website, i) then begin Result := not Modules.Module[i].FavoriteAvailable; Exit; end; - Result := False; Result := SitesMemberOf(website, [ FAKKU_ID, PURURIN_ID, @@ -1316,12 +1316,12 @@ function SitesWithoutInformation(const website: String): Boolean; var i: Integer = -1; begin + Result := False; if Modules.ModuleAvailable(website, i) then begin Result := not Modules.Module[i].InformationAvailable; Exit; end; - Result := False; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, MANGAVADISI_ID, @@ -1385,7 +1385,8 @@ function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; function FillMangaSiteHost(const Website, URL: String): String; begin - if Website = '' then Exit(URL); + Result := URL; + if Website = '' then Exit; Result := FillMangaSiteHost(GetMangaSiteID(Website), URL); end; From 7bb7dab279d22aeb170bc8d30c8ff272cfceda18 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 13:09:08 +0800 Subject: [PATCH 0630/2794] baseunit, add streamtostring --- baseunits/uBaseUnit.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bb3c46259..2c6fa6453 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -856,6 +856,7 @@ function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; // StringUtils +function StreamToString(const M: TMemoryStream): string; inline; function GetRightValue(const name, s: string): string; function QuotedStrd(const S: string): string; overload; inline; function QuotedStrd(const S: Integer): string; overload; inline; @@ -1386,7 +1387,7 @@ function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; function FillMangaSiteHost(const Website, URL: String): String; begin Result := URL; - if Website = '' then Exit; + if Website = '' then Exit(URL); Result := FillMangaSiteHost(GetMangaSiteID(Website), URL); end; @@ -1645,6 +1646,11 @@ procedure ConvertCharsetToUTF8(S: TStrings); if cs <> '' then S.Text := ConvertEncoding(S.Text, cs, 'utf8'); end; +function StreamToString(const M: TMemoryStream): string; +begin + SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char)); +end; + function GetRightValue(const name, s: string): string; var i: Integer; From 1b41fb57c3bacc426e858796684c830da2e73730 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 13:56:25 +0800 Subject: [PATCH 0631/2794] rewrite wpmanga --- baseunits/modules/WPManga.pas | 319 ++++++++++++++-------------------- 1 file changed, 133 insertions(+), 186 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 67bbc3367..24bc6ea78 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -20,139 +20,123 @@ implementation function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; s: String; begin Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - Source := TStringList.Create; - try + with MangaInfo.FHTTP do begin if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else s := dirURL; - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + s, 3) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); - s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); - Page := StrToIntDef(s, 1); - finally - Query.Free; - end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + if GET(Module.RootURL + s) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); + s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); + Page := StrToIntDef(s, 1); + finally + query.Free; + end; + end; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; + const Names, Links: TStringList; const AURL: String; Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; v: IXQValue; s: String; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - Source := TStringList.Create; - try + with MangaInfo.FHTTP do begin if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else s := dirURL; - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + s + - IncStr(URL) + '/', 3) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - if Module.Website = 'MangaIndo' then begin - for v in Query.XPath( - '//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do - Links.Add(v.toString); - for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do - Names.Add(v.toString); - end - else if Module.Website = 'ReadHentaiManga' then begin - for v in Query.XPath('//*[@id="content"]//*[@id="center"]/a') do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toNode.getAttribute('title')); - end; - end - else begin - if (Module.Website = 'EyeOnManga') or - (Module.Website = 'MangaBoom') then - s := '//*[@id="sct_content"]//h2/a[1]' - else - s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; - for v in Query.XPath(s) do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); - end; + if GET(Module.RootURL + s + IncStr(AURL) + '/') then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + if Module.Website = 'MangaIndo' then begin + for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do + Links.Add(v.toString); + for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do + Names.Add(v.toString); + end + else if Module.Website = 'ReadHentaiManga' then begin + for v in Query.XPath('//*[@id="content"]//*[@id="center"]/a') do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toNode.getAttribute('title')); + end; + end + else begin + if (Module.Website = 'EyeOnManga') or + (Module.Website = 'MangaBoom') then + s := '//*[@id="sct_content"]//h2/a[1]' + else + s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; + for v in Query.XPath(s) do begin + Links.Add(v.toNode.getAttribute('href')); + Names.Add(v.toString); end; - finally - Query.Free; end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + finally + query.Free; + end; + end; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; - info: TMangaInfo; + query: TXQueryEngineHTML; v: IXQValue; s: String; i, pagecount: Integer; procedure scanchapters; begin - if Module.Website = 'MangaBoom' then begin - for v in Query.XPath('//ul[@class="lst"]//a[1]') do begin - info.chapterLinks.Add(v.toNode.getAttribute('href')); - info.chapterName.Add(v.toNode.Next.toString()); - end; - end - else if (Module.Website = 'EyeOnManga') or - (Module.Website = 'MangaIndo') then - begin - for v in Query.XPath('//ul[@class="chp_lst"]//a[1]') do begin - info.chapterLinks.Add(v.toNode.getAttribute('href')); - info.chapterName.Add(v.toString); + with MangaInfo.mangaInfo, query do begin + if Module.Website = 'MangaBoom' then begin + for v in XPath('//ul[@class="lst"]//a[1]') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toNode.Next.toString()); + end; + end + else if (Module.Website = 'EyeOnManga') or + (Module.Website = 'MangaIndo') then + begin + for v in XPath('//ul[@class="chp_lst"]//a[1]') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + end + else begin + for v in XPath('//ul[@class="lst"]//a[1]/@href') do + chapterLinks.Add(v.toString); + for v in XPath('//ul[@class="lst"]//a[1]/b[1]') do + chapterName.Add(v.toString); end; - end - else begin - for v in Query.XPath('//ul[@class="lst"]//a[1]/@href') do - info.chapterLinks.Add(v.toString); - for v in Query.XPath('//ul[@class="lst"]//a[1]/b[1]') do - info.chapterName.Add(v.toString); end; end; function getwpmangavalue(aname: String): String; begin - Result := Query.XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"' + + Result := query.XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"' + aname + '")]'); if Result <> '' then Result := TrimChar(SeparateRight(Result, aname), [':', ' ']); end; procedure scaninfo; begin - with info, Query do begin + with MangaInfo.mangaInfo, query do begin if Module.Website = 'EyeOnManga' then summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]') else @@ -175,7 +159,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; procedure scaninfomangaindo; begin - with info, Query do begin + with MangaInfo.mangaInfo, query do begin summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]'); authors := getwpmangavalue('Penulis'); artists := getwpmangavalue('Seniman'); @@ -194,127 +178,90 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - info.coverLink := Query.XPathString('//img[starts-with(@class,"cvr")]/@src'); - info.title := Query.XPathString('//*[@itemprop="itemreviewed"]'); - if Module.Website = 'MangaIndo' then scaninfomangaindo - else scaninfo; - s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); - if s <> '' then begin - s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); - pagecount := StrToIntDef(s, 1); - if pagecount > 1 then - for i := 2 to pagecount do - if GetPage(MangaInfo.FHTTP, TObject(Source), - info.url + 'chapter-list/' + IntToStr(i) + '/', - Reconnect) then - begin - Query.ParseHTML(Source.Text); - scanchapters; - end; - end; - if Module.Website <> 'EyeOnManga' then - InvertStrings([info.chapterLinks, info.chapterName]); - { add missing chapter number } - //if (Module.Website = 'EyeOnManga') or - // (Module.Website = 'MangaIndo') and - // (info.chapterName.Count > 0) then - // for i := 0 to info.chapterName.Count - 1 do - // info.chapterName[i] := 'Ch.' + IncStr(i) + ' ' + info.chapterName[i]; - finally - Query.Free; + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + website := Module.Website; + url := AppendURLDelim(FillHost(Module.RootURL, AURL)); + if GET(MangaInfo.mangaInfo.url) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + coverLink := query.XPathString('//img[starts-with(@class,"cvr")]/@src'); + title := query.XPathString('//*[@itemprop="itemreviewed"]'); + if Module.Website = 'MangaIndo' then scaninfomangaindo + else scaninfo; + s := query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); + if s <> '' then begin + s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); + pagecount := StrToIntDef(s, 1); + if pagecount > 1 then + for i := 2 to pagecount do + if GET(url + 'chapter-list/' + IntToStr(i) + '/') then begin + query.ParseHTML(StreamToString(Document)); + scanchapters; + end; end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + if Module.Website <> 'EyeOnManga' then + InvertStrings([chapterLinks, chapterName]); + { add missing chapter number } + //if (Module.Website = 'EyeOnManga') or + // (Module.Website = 'MangaIndo') and + // (chapterName.Count > 0) then + // for i := 0 to chapterName.Count - 1 do + // chapterName[i] := 'Ch.' + IncStr(i) + ' ' + chapterName[i]; + finally + query.Free; + end; + end; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; + query: TXQueryEngineHTML; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - with Container do begin + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, URL)) + '1', - Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - PageNumber := - Query.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; - finally - Query.Free; - end; - end; - finally - Source.Free; + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1') then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber := query.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; + finally + query.Free; + end; end; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; + query: TXQueryEngineHTML; s: String; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - with Container do begin - Source := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, URL)) + - IncStr(DownloadThread.workCounter) + '/', - Manager.retryConnect) then - begin - ParseHTML(Source.Text, Source); - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - if Module.Website = 'ReadHentaiManga' then - s := HTMLDecode(Query.XPathString('//img[@id="main_img"]/@src')) - else - s := Query.XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); - Container.PageLinks[DownloadThread.WorkCounter] := s; - finally - Query.Free; - end; - end; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + if Module.Website = 'ReadHentaiManga' then + s := HTMLDecode(query.XPathString('//img[@id="main_img"]/@src')) + else + s := query.XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); + PageLinks[DownloadThread.WorkCounter] := s; + finally + query.Free; end; - finally - Source.Free; end; end; end; From 2ae78dd2a47260ef6ac8836dc8d6aa0e89d60097 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 14:03:42 +0800 Subject: [PATCH 0632/2794] remove manga2u, and add mangahen as replacement close #118 --- .../includes/Manga2u/chapter_page_number.inc | 39 ---- .../Manga2u/directory_page_number.inc | 28 --- baseunits/includes/Manga2u/image_url.inc | 31 ---- .../includes/Manga2u/manga_information.inc | 172 ------------------ .../includes/Manga2u/names_and_links.inc | 31 ---- baseunits/modules/WPManga.pas | 4 + baseunits/uBaseUnit.pas | 90 +++++---- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 - config/mangalist.ini | 2 +- 10 files changed, 47 insertions(+), 375 deletions(-) delete mode 100644 baseunits/includes/Manga2u/chapter_page_number.inc delete mode 100644 baseunits/includes/Manga2u/directory_page_number.inc delete mode 100644 baseunits/includes/Manga2u/image_url.inc delete mode 100644 baseunits/includes/Manga2u/manga_information.inc delete mode 100644 baseunits/includes/Manga2u/names_and_links.inc diff --git a/baseunits/includes/Manga2u/chapter_page_number.inc b/baseunits/includes/Manga2u/chapter_page_number.inc deleted file mode 100644 index efbb62329..000000000 --- a/baseunits/includes/Manga2u/chapter_page_number.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetManga2uPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - isStartGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGA2U_ID, URL) + '1/'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="cbo_wpm_pag"', parse.Strings[i]) > 0) then - isStartGetPageNumber := True; - - if (isStartGetPageNumber) and - (Pos('</select>', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 3]; - manager.container.PageNumber := - StrToInt(GetAttributeValue(GetTagAttribute(s, 'value='))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Manga2u/directory_page_number.inc b/baseunits/includes/Manga2u/directory_page_number.inc deleted file mode 100644 index ba764cada..000000000 --- a/baseunits/includes/Manga2u/directory_page_number.inc +++ /dev/null @@ -1,28 +0,0 @@ - function GetManga2uDirectoryPageNumber: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGA2U_ID, 1] + MANGA2U_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count > 0 then - for i := parse.Count - 1 downto 2 do - if (Pos('<a', parse[i]) > 0) and (Pos(MANGA2U_BROWSER, parse[i]) > 0) - and (Pos('Last', parse[i + 1]) > 0) then - begin - page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', GetVal(parse[i], 'href'), '$1', True), 1); - Result := NO_ERROR; - Break; - end; - end; diff --git a/baseunits/includes/Manga2u/image_url.inc b/baseunits/includes/Manga2u/image_url.inc deleted file mode 100644 index d2adf0aa1..000000000 --- a/baseunits/includes/Manga2u/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetManga2uImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGA2U_ID, URL) + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="manga-page', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - EncodeURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Manga2u/manga_information.inc b/baseunits/includes/Manga2u/manga_information.inc deleted file mode 100644 index d273b51ba..000000000 --- a/baseunits/includes/Manga2u/manga_information.inc +++ /dev/null @@ -1,172 +0,0 @@ - function GetManga2uInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - i, j, n: Cardinal; - numberOfPage: Cardinal = 1; - - procedure ExtractChapter; - begin - if (not isExtractChapter) and (Pos('name="IL_IN_TAG', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('class="val', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i - 2], 'href')), - WebsiteRoots[MANGA2U_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('sct_wid_bot', parse.Strings[i]) > 0) then - isExtractChapter := False; - end; - - begin - mangaInfo.url := FillMangaSiteHost(MANGA2U_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[MANGA2U_ID, 0]; - mangaInfo.status := ''; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="sel', parse.Strings[i]) > 0 then - numberOfPage := StrToInt(GetString(parse.Strings[i + 10], '-list/', '/">')); - - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class="cvr_ara', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i + 2], 'src='))); - - // get title - if (Pos('class="cvr_ara', parse.Strings[i]) > 0) then - mangaInfo.title := GetAttributeValue(GetTagAttribute(parse.Strings[i + 2], 'alt=')); - - ExtractChapter; - - // get summary - if (Pos('Author', parse.Strings[i]) <> 0) then - begin - j := i - 6; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter( - StringFilter(TrimLeft(parse.Strings[j]))); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - Break; - end; - Inc(j); - end; - end; - - // get authors - if (Pos('Author', parse.Strings[i]) <> 0) then - mangaInfo.authors := StringReplace(TrimLeft(StringFilter(parse.Strings[i + 2])), - ': ', '', []); - - // get artists - if (Pos('Author', parse.Strings[i]) <> 0) then - mangaInfo.artists := StringReplace(TrimLeft(StringFilter(parse.Strings[i + 2])), - ': ', '', []); - - // get genres - if (Pos('Category', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('list/category/', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</p>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - if numberOfPage > 1 then - begin - for n := 2 to numberOfPage do - begin - Source.Clear; - s := mangaInfo.url + 'chapter-list/' + IntToStr(n); - if not GetPage(TObject(Source), mangaInfo.url + 'chapter-list/' + - IntToStr(n), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - isExtractChapter := False; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - ExtractChapter; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Manga2u/names_and_links.inc b/baseunits/includes/Manga2u/names_and_links.inc deleted file mode 100644 index b2b171752..000000000 --- a/baseunits/includes/Manga2u/names_and_links.inc +++ /dev/null @@ -1,31 +0,0 @@ - function Manga2uGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGA2U_ID, 1] + - MANGA2U_BROWSER + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if i + 3 < parse.Count - 1 then - if (Pos('class="det"', parse[i]) > 0) and (Pos('<a', parse[i + 2]) > 0) - and (Pos('<', parse[i + 3]) = 0) then - begin - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 3]))))); - links.Add(Trim(StringReplace(GetVal(parse[i + 2], 'href'), - WebsiteRoots[MANGA2U_ID, 1], '', [rfIgnoreCase]))); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 24bc6ea78..cb968d09e 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -16,6 +16,7 @@ implementation dirURL = '/manga-list/all/any/last-added/'; dirURLmangaindo = '/daftar-manga/all/any/last-added/'; dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; + dirURLmangahen = '/manga_list/all/any/last-added/'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; @@ -29,6 +30,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; with MangaInfo.FHTTP do begin if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga + else if Module.Website = 'MangaHen' then s := dirURLmangahen else s := dirURL; if GET(Module.RootURL + s) then begin Result := NO_ERROR; @@ -57,6 +59,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; with MangaInfo.FHTTP do begin if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga + else if Module.Website = 'MangaHen' then s := dirURLmangahen else s := dirURL; if GET(Module.RootURL + s + IncStr(AURL) + '/') then begin Result := NO_ERROR; @@ -291,6 +294,7 @@ procedure RegisterModule; AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); AddWebsiteModule('MangaIndo', 'http://mangaindo.id'); AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); + AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); end; initialization diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2c6fa6453..81f2c6677 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -310,49 +310,48 @@ interface MEINMANGA_ID = 43; MANGASPROJECT_ID = 44; MANGAREADER_POR_ID = 45; - MANGA2U_ID = 46; - MANGASTREAMTO_ID = 47; - NINEMANGA_ID = 48; - NINEMANGA_ES_ID = 49; - NINEMANGA_CN_ID = 50; - NINEMANGA_RU_ID = 51; - NINEMANGA_DE_ID = 52; - NINEMANGA_IT_ID = 53; - NINEMANGA_BR_ID = 54; - JAPANSHIN_ID = 55; - JAPSCAN_ID = 56; - CENTRUMMANGI_PL_ID = 57; - MANGALIB_PL_ID = 58; - ONEMANGA_ID = 59; - MANGATOWN_ID = 60; - MANGAOKU_ID = 61; - MYREADINGMANGAINFO_ID = 62; - IKOMIK_ID = 63; - NHENTAI_ID = 64; - UNIONMANGAS_ID = 65; - MANGAMINT_ID = 66; - UNIXMANGA_ID = 67; - HAKIHOME_ID = 68; - EXTREMEMANGAS_ID = 69; - MANGAHOST_ID = 70; - PORNCOMIX_ID = 71; - PORNCOMIXRE_ID = 72; - PORNCOMIXIC_ID = 73; - XXCOMICS_ID = 74; - XXCOMICSMT_ID = 75; - XXCOMICS3D_ID = 76; - PORNXXXCOMICS_ID = 77; - MANGASEE_ID = 78; - MANGAKU_ID = 79; - ACADEMYVN_ID = 80; - MANGAAT_ID = 81; - SENMANGARAW_ID = 82; - READMANGATODAY_ID = 83; - LONEMANGA_ID = 84; - DYNASTYSCANS_ID = 85; - MADOKAMI_ID = 86; - - WebsiteRoots: array [0..86] of array [0..1] of string = ( + MANGASTREAMTO_ID = 46; + NINEMANGA_ID = 47; + NINEMANGA_ES_ID = 48; + NINEMANGA_CN_ID = 49; + NINEMANGA_RU_ID = 50; + NINEMANGA_DE_ID = 51; + NINEMANGA_IT_ID = 52; + NINEMANGA_BR_ID = 53; + JAPANSHIN_ID = 54; + JAPSCAN_ID = 55; + CENTRUMMANGI_PL_ID = 56; + MANGALIB_PL_ID = 57; + ONEMANGA_ID = 58; + MANGATOWN_ID = 59; + MANGAOKU_ID = 60; + MYREADINGMANGAINFO_ID = 61; + IKOMIK_ID = 62; + NHENTAI_ID = 63; + UNIONMANGAS_ID = 64; + MANGAMINT_ID = 65; + UNIXMANGA_ID = 66; + HAKIHOME_ID = 67; + EXTREMEMANGAS_ID = 68; + MANGAHOST_ID = 69; + PORNCOMIX_ID = 70; + PORNCOMIXRE_ID = 71; + PORNCOMIXIC_ID = 72; + XXCOMICS_ID = 73; + XXCOMICSMT_ID = 74; + XXCOMICS3D_ID = 75; + PORNXXXCOMICS_ID = 76; + MANGASEE_ID = 77; + MANGAKU_ID = 78; + ACADEMYVN_ID = 79; + MANGAAT_ID = 80; + SENMANGARAW_ID = 81; + READMANGATODAY_ID = 82; + LONEMANGA_ID = 83; + DYNASTYSCANS_ID = 84; + MADOKAMI_ID = 85; + + WebsiteRoots: array [0..85] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -399,7 +398,6 @@ interface ('MeinManga', 'http://www.meinmanga.com/'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), - ('Manga2u', 'http://www.mangakaka.com'), ('MangaStreamTo', 'http://www.mangastream.to'), ('NineManga', 'http://www.ninemanga.com'), ('NineManga_ES', 'http://es.ninemanga.com'), @@ -543,9 +541,6 @@ interface MANGAREADER_POR_BROWSER = '/AJAX/listaMangas/all'; - //MANGA2U_BROWSER = '/list/all/any/most-popular/'; - MANGA2U_BROWSER = '/manga_list/all/any/last-added/'; - MANGASTREAMTO_BROWSER = '/series.html'; NINEMANGA_BROWSER = @@ -1275,7 +1270,6 @@ function SitesWithSortedList(const website : String) : Boolean; ONEMANGA_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID, - MANGA2U_ID, PORNCOMIX_ID, XXCOMICS_ID, XXCOMICSMT_ID, diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9676d7d8f..27c289620 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1956,8 +1956,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/CentralDeMangas/directory_page_number.inc} - {$I includes/Manga2u/directory_page_number.inc} - {$I includes/DM5/directory_page_number.inc} {$I includes/NineManga/directory_page_number.inc} @@ -2079,9 +2077,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then Result := GetCentralDeMangasDirectoryPageNumber else - if website = WebsiteRoots[MANGA2U_ID, 0] then - Result := GetManga2uDirectoryPageNumber - else if website = WebsiteRoots[DM5_ID, 0] then Result := GetDM5DirectoryPageNumber else @@ -2179,8 +2174,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; Parser: THTMLParser; WebsiteID: Cardinal; - {$I includes/Manga2u/names_and_links.inc} - {$I includes/AnimeA/names_and_links.inc} {$I includes/EsMangaHere/names_and_links.inc} @@ -2462,9 +2455,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then Result := MangaREADER_PORGetNamesAndLinks else - if website = WebsiteRoots[MANGA2U_ID, 0] then - Result := Manga2uGetNamesAndLinks - else if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then Result := MangaStreamToGetNamesAndLinks else @@ -2661,8 +2651,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MeinManga/manga_information.inc} - {$I includes/Manga2u/manga_information.inc} - {$I includes/KivManga/manga_information.inc} {$I includes/MangasPROJECT/manga_information.inc} @@ -2805,9 +2793,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if website = WebsiteRoots[MEINMANGA_ID, 0] then Result := GetMeinMangaInfoFromURL else - if website = WebsiteRoots[MANGA2U_ID, 0] then - Result := GetManga2uInfoFromURL - else if website = WebsiteRoots[SUBMANGA_ID, 0] then Result := GetSubMangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9bde10643..4e66088d5 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -389,8 +389,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Komikid/chapter_page_number.inc} - {$I includes/Manga2u/chapter_page_number.inc} - {$I includes/MangaAe/chapter_page_number.inc} {$I includes/MangaAr/chapter_page_number.inc} @@ -525,9 +523,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaPageNumber else - if manager.container.MangaSiteID = MANGA2U_ID then - Result := GetManga2uPageNumber - else if manager.container.MangaSiteID = ESMANGAHERE_ID then Result := GetEsMangaHerePageNumber else @@ -715,8 +710,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Manga24h/image_url.inc} - {$I includes/Manga2u/image_url.inc} - {$I includes/MangaAe/image_url.inc} {$I includes/MangaAr/image_url.inc} @@ -818,9 +811,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnImageURL else - if manager.container.MangaSiteID = MANGA2U_ID then - Result := GetManga2uImageURL - else if manager.container.MangaSiteID = MANGA24H_ID then Result := GetManga24hImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 892bbd18d..a581de8ea 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,Manga2u,MangaCap,MangaFox,MangaGo,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 36c120437875a7d8cc3c47cb35f57d8d9c7089ce Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 15:33:34 +0800 Subject: [PATCH 0633/2794] rewrite ehentai --- baseunits/modules/EHentai.pas | 317 ++++++++++++++-------------------- 1 file changed, 134 insertions(+), 183 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 1f3a1c9d4..40fdceb44 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -5,88 +5,66 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; implementation +uses RegExpr; + const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; begin Result := NET_PROBLEM; Page := 1; - if MangaInfo = nil then Exit; - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/?' + dirURL, 3) then - begin - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - Page := StrToIntDef(Query.CSSString( - 'table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) + 1; - finally - Query.Free; - end; - end - else Result := INFORMATION_NOT_FOUND; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/?' + dirURL) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + Page := StrToIntDef(query.CSSString('table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) + 1; + finally + query.Free; end; - finally - Source.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; + const Names, Links: TStringList; const AURL: String; Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; rurl: String; v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Source := TStringList.Create; - try - if URL = '0' then rurl := Module.RootURL + '/?' + dirURL - else rurl := Module.RootURL + '/?page=' + IncStr(URL) + '&' + dirURL; - if GetPage(MangaInfo.FHTTP, TObject(Source), rurl, 3) then - begin - Result := INFORMATION_NOT_FOUND; - if Source.Count > 0 then + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if AURL = '0' then rurl := Module.RootURL + '/?' + dirURL + else rurl := Module.RootURL + '/?page=' + IncStr(AURL) + '&' + dirURL; + if MangaInfo.FHTTP.GET(rurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@class="itg"]/tbody/tr/td/div/div/a') do begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - for v in Query.XPath('//table[@class="itg"]/tbody/tr/td/div/div/a') do - begin - Names.Add(v.toString); - Links.Add(v.toNode.getAttribute('href')); - end; - finally - Query.Free; - end; + Names.Add(v.toString); + Links.Add(v.toNode.getAttribute('href')); end; + finally + query.Free; end; - finally - Source.Free; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - info: TMangaInfo; - Source: TStringList; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; v: IXQValue; procedure ScanParse; @@ -95,16 +73,15 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin getOK := True; // check content warning - if Pos('Content Warning', Query.XPathString('//div/h1')) > 0 then + if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then begin - getOK := GetPage(MangaInfo.FHTTP, TObject(Source), info.url + - '?nw=session', Reconnect); + getOK := MangaInfo.FHTTP.GET(MangaInfo.mangaInfo.url + '?nw=session'); if getOK then - Query.ParseHTML(Source.Text); + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); end; if getOK then begin - with info do begin + with MangaInfo.mangaInfo do begin //title title := Query.XPathString('//*[@id="gn"]'); //cover @@ -143,53 +120,41 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + website := Module.Website; + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin - if Source.Count > 0 then - begin - Result := NO_ERROR; - // if there is only 1 line, it's banned message! - if Source.Count = 1 then - info.summary := Source.Text - else - begin - Query := TXQueryEngineHTML.Create(Source.Text); - try - ScanParse; - finally - Query.Free; - end; - end; - end - else - Result := INFORMATION_NOT_FOUND; + Result := NO_ERROR; + // if there is only 1 line, it's banned message! + //if Source.Count = 1 then + // info.summary := Source.Text + //else + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + ScanParse; + finally + query.Free; + end; end; - finally - Source.Free; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Container: TTaskContainer; - Source: TStringList; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; v: IXQValue; rurl: String; procedure GetImageLink; begin - for v in Query.XPath('//*[@class="gdtm"]/div/a/@href') do - begin - Container.PageLinks.Add('G'); - Container.PageContainerLinks.Add(v.toString); - end; + for v in query.XPath('//*[@class="gdtm"]/div/a/@href') do + with DownloadThread.manager.container do begin + PageLinks.Add('G'); + PageContainerLinks.Add(v.toString); + end; end; procedure ScanParse; @@ -200,25 +165,23 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin getOK := True; //check content warning - if Pos('Content Warning', Query.XPathString('//div/h1')) > 0 then + if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then begin - getOK := GetPage(DownloadThread.FHTTP, TObject(Source), rurl + '?nw=session', - Container.Manager.retryConnect); + getOK := DownloadThread.FHTTP.GET(rurl + '?nw=session'); if getOK then - Query.ParseHTML(Source.Text); + query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); end; if getOK then begin GetImageLink; //get page count - p := StrToIntDef(Query.CSSString( + p := StrToIntDef(query.CSSString( 'table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) - 1; if p > 0 then for i := 1 to p do - if GetPage(DownloadThread.FHTTP, TObject(Source), rurl + '?p=' + IntToStr(i), - Container.Manager.retryConnect) then + if DownloadThread.FHTTP.GET(rurl + '?p=' + IntToStr(i)) then begin - Query.ParseHTML(Source.Text); + query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); GetImageLink; end; end; @@ -227,38 +190,28 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Source := TStringList.Create; - try - rurl := AppendURLDelim(FillHost(Module.RootURL, URL)); - if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, - Container.Manager.retryConnect) then - begin - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - ScanParse; - finally - Query.Free; - end; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); + if GET(rurl) then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + ScanParse; + finally + query.Free; end; end; - finally - Source.Free; end; end; function DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix: String; Module: TModuleContainer): Boolean; + const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Container: TTaskContainer; - Query: TXQueryEngineHTML; + query: TXQueryEngineHTML; iurl: String; reconnect: Integer; @@ -266,76 +219,74 @@ function DownloadImage(var DownloadThread: TDownloadThread; var i, rcount: Integer; base_url, startkey, gid, startpage, nl: String; + source: TStringList; + s: String; begin rcount := 0; Result := False; - while (not Result) and (not DownloadThread.IsTerminated) do begin - Query.ParseHTML(Source.Text); - iurl := Query.XPathString('//*[@id="img"]/@src'); - if iurl = '' then - iurl := Query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); - if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, -1, iurl, Path, - Name, Prefix); - if DownloadThread.IsTerminated then Break; - if not Result then - begin - base_url := ''; - startkey := ''; - gid := ''; - startpage := ''; - nl := ''; - //get url param - for i := 0 to Source.Count - 1 do begin - if Pos('var base_url=', Source[i]) > 0 then - base_url := RemoveURLDelim(GetValuesFromString(Source[i], '=')) - else if Pos('var startkey=', Source[i]) > 0 then - startkey := GetValuesFromString(Source[i], '=') - else if Pos('var gid=', Source[i]) > 0 then - gid := GetValuesFromString(Source[i], '=') - else if Pos('var startpage=', Source[i]) > 0 then - startpage := GetValuesFromString(Source[i], '=') - else if Pos('return nl(', Source[i]) > 0 then - nl := ReplaceRegExpr('(?i)^.*nl\([''"](.*)[''"]\).*$', - Source[i], '$1', True); + source := TStringList.Create; + try + while (not Result) and (not DownloadThread.IsTerminated) do begin + source.LoadFromStream(DownloadThread.FHTTP.Document); + query.ParseHTML(source.Text); + iurl := query.XPathString('//*[@id="img"]/@src'); + if iurl = '' then + iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); + if iurl <> '' then + Result := SaveImage(DownloadThread.FHTTP, -1, iurl, APath, AName, APrefix); + if DownloadThread.IsTerminated then Break; + if rcount >= reconnect then Break; + if not Result then begin + base_url := ''; + startkey := ''; + gid := ''; + startpage := ''; + nl := ''; + //get AURL param + if source.Count > 0 then + for i := 0 to source.Count - 1 do begin + if Pos('var base_url=', source[i]) > 0 then + base_url := RemoveURLDelim(GetValuesFromString(source[i], '=')) + else if Pos('var startkey=', source[i]) > 0 then + startkey := GetValuesFromString(source[i], '=') + else if Pos('var gid=', source[i]) > 0 then + gid := GetValuesFromString(source[i], '=') + else if Pos('var startpage=', source[i]) > 0 then + startpage := GetValuesFromString(source[i], '=') + else if Pos('return nl(', source[i]) > 0 then + nl := ReplaceRegExpr('(?i)^.*nl\([''"](.*)[''"]\).*$', + source[i], '$1', True); + end; + if (base_url <> '') and (startkey <> '') and (gid <> '') and + (startpage <> '') then + iurl := base_url + '/s/' + startkey + '/' + gid + '-' + startpage + else iurl := FillHost(Module.RootURL, AURL); + if nl <> '' then begin + iurl := iurl + '?nl=' + nl; + if not DownloadThread.FHTTP.GET(iurl) then Break; + end else Break; + if rcount >= reconnect then Break + else Inc(rcount); end; - if (base_url <> '') and (startkey <> '') and (gid <> '') and - (startpage <> '') then - iurl := base_url + '/s/' + startkey + '/' + gid + '-' + startpage - else iurl := FillHost(Module.RootURL, URL); - if nl <> '' then begin - iurl := iurl + '?nl=' + nl; - if not GetPage(DownloadThread.FHTTP, TObject(Source), iurl, reconnect) then - Break; - end else Break; - if rcount >= reconnect then Break - else Inc(rcount); end; + finally + source.Free; end; end; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - reconnect := Container.Manager.retryConnect; - iurl := FillHost(Module.RootURL, URL); - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), iurl, reconnect) then - begin - if Source.Count > 0 then - begin - Query := TXQueryEngineHTML.Create(Source.Text); - try - Result := DoDownloadImage; - finally - Query.Free; - end; - end; + reconnect := DownloadThread.FHTTP.RetryCount; + iurl := FillHost(Module.RootURL, AURL); + if DownloadThread.FHTTP.GET(iurl) then begin + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); + Result := DoDownloadImage; + finally + query.Free; end; - finally - Source.Free; end; end; From 0aeb34139f8facc96a014ef807dad3c9e53c2556 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 15:43:16 +0800 Subject: [PATCH 0634/2794] websitemodules, rename some var name --- baseunits/WebsiteModules.pas | 128 +++++++++++++++++----------------- baseunits/modules/Batoto.pas | 18 ++--- baseunits/modules/EHentai.pas | 6 +- baseunits/modules/WPManga.pas | 14 ++-- 4 files changed, 83 insertions(+), 83 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 4614d1eab..61ca06ea1 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -23,19 +23,19 @@ TModuleContainer = class; TOnGetDirectoryPageNumber = function(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; TOnGetNameAndLink = function(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; - TOnGetInfo = function(var MangaInfo: TMangaInformation; const URL: String; + TOnGetInfo = function(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; TOnTaskStart = function(var Task: TTaskContainer; Module: TModuleContainer): Boolean; TOnGetPageNumber = function(var DownloadThread: TDownloadThread; - const URL: String; Module: TModuleContainer): Boolean; + const AURL: String; Module: TModuleContainer): Boolean; TOnGetImageURL = function(var DownloadThread: TDownloadThread; - const URL: String; Module: TModuleContainer): Boolean; + const AURL: String; Module: TModuleContainer): Boolean; TOnDownloadImage = function(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix: String; Module: TModuleContainer): Boolean; + const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; TOnLogin = function(var AHTTP: THTTPSendThread): Boolean; @@ -94,61 +94,61 @@ TWebsiteModules = class destructor Destroy; override; function AddModule: TModuleContainer; - function LocateModule(const Website: String): Integer; - function LocateModuleByHost(const Host: String): Integer; + function LocateModule(const AWebsite: String): Integer; + function LocateModuleByHost(const AHost: String): Integer; function ModuleAvailable(const ModuleId: Integer; ModuleMethod: TModuleMethod): Boolean; overload; - function ModuleAvailable(const Website: String; + function ModuleAvailable(const AWebsite: String; ModuleMethod: TModuleMethod): Boolean; overload; - function ModuleAvailable(const Website: String; ModuleMethod: TModuleMethod; + function ModuleAvailable(const AWebsite: String; ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; overload; - function ModuleAvailable(const Website: String): Boolean; overload; - function ModuleAvailable(const Website: String; var OutIndex: Integer): Boolean; + function ModuleAvailable(const AWebsite: String): Boolean; overload; + function ModuleAvailable(const AWebsite: String; var OutIndex: Integer): Boolean; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer): Integer; overload; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; const Website: String): Integer; overload; + var Page: Integer; const AWebsite: String): Integer; overload; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; + const ANames, ALinks: TStringList; const AURL: String; const ModuleId: Integer): Integer; overload; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL, Website: String): Integer; overload; + const ANames, ALinks: TStringList; const AURL, AWebsite: String): Integer; overload; - function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; const ModuleId: Integer): Integer; overload; - function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; const Website: String): Integer; overload; + function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; const AWebsite: String): Integer; overload; function TaskStart(var Task: TTaskContainer; const ModuleId: Integer): Boolean; overload; - function TaskStart(var Task: TTaskContainer; const Website: String): Boolean; + function TaskStart(var Task: TTaskContainer; const AWebsite: String): Boolean; overload; function GetPageNumber(var DownloadThread: TDownloadThread; - const URL: String; const ModuleId: Integer): Boolean; overload; + const AURL: String; const ModuleId: Integer): Boolean; overload; function GetPageNumber(var DownloadThread: TDownloadThread; - const URL, Website: String): Boolean; + const AURL, AWebsite: String): Boolean; overload; function GetImageURL(var DownloadThread: TDownloadThread; - const URL: String; const ModuleId: Integer): Boolean; overload; + const AURL: String; const ModuleId: Integer): Boolean; overload; function GetImageURL(var DownloadThread: TDownloadThread; - const URL, Website: String): Boolean; + const AURL, AWebsite: String): Boolean; overload; function DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; overload; + const AURL, APath, AName, APrefix: String; ModuleId: Integer): Boolean; overload; function DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix, Website: String): Boolean; overload; + const AURL, APath, AName, APrefix, AWebsite: String): Boolean; overload; function Login(var AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; overload; - function Login(var AHTTP: THTTPSendThread; const Website: String): Boolean; overload; + function Login(var AHTTP: THTTPSendThread; const AWebsite: String): Boolean; overload; procedure LockModules; procedure UnlockModules; @@ -256,21 +256,21 @@ function TWebsiteModules.AddModule: TModuleContainer; end; end; -function TWebsiteModules.LocateModule(const Website: String): Integer; +function TWebsiteModules.LocateModule(const AWebsite: String): Integer; var i: Integer; begin Result := -1; if FModuleList.Count > 0 then for i := 0 to FModuleList.Count - 1 do - if SameText(TModuleContainer(FModuleList[i]).Website, Website) then + if SameText(TModuleContainer(FModuleList[i]).Website, AWebsite) then begin Result := i; Break; end; end; -function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; +function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; var i: Integer; h: String; @@ -278,7 +278,7 @@ function TWebsiteModules.LocateModuleByHost(const Host: String): Integer; Result := -1; if FModuleList.Count > 0 then begin - h := LowerCase(Host); + h := LowerCase(AHost); for i := 0 to FModuleList.Count - 1 do if Pos(h, LowerCase(TModuleContainer(FModuleList[i]).RootURL)) <> 0 then begin @@ -321,29 +321,29 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; end; end; -function TWebsiteModules.ModuleAvailable(const Website: String; +function TWebsiteModules.ModuleAvailable(const AWebsite: String; ModuleMethod: TModuleMethod): Boolean; begin - Result := ModuleAvailable(LocateModule(Website), ModuleMethod); + Result := ModuleAvailable(LocateModule(AWebsite), ModuleMethod); end; -function TWebsiteModules.ModuleAvailable(const Website: String; +function TWebsiteModules.ModuleAvailable(const AWebsite: String; ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; begin Result := False; - OutIndex := LocateModule(Website); + OutIndex := LocateModule(AWebsite); Result := ModuleAvailable(OutIndex, ModuleMethod); end; -function TWebsiteModules.ModuleAvailable(const Website: String): Boolean; +function TWebsiteModules.ModuleAvailable(const AWebsite: String): Boolean; begin - Result := (LocateModule(Website) > -1); + Result := (LocateModule(AWebsite) > -1); end; -function TWebsiteModules.ModuleAvailable(const Website: String; +function TWebsiteModules.ModuleAvailable(const AWebsite: String; var OutIndex: Integer): Boolean; begin - OutIndex := LocateModule(Website); + OutIndex := LocateModule(AWebsite); Result := OutIndex > -1; end; @@ -359,41 +359,41 @@ function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation end; function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; const Website: String): Integer; + var Page: Integer; const AWebsite: String): Integer; begin - Result := GetDirectoryPageNumber(MangaInfo, Page, LocateModule(Website)); + Result := GetDirectoryPageNumber(MangaInfo, Page, LocateModule(AWebsite)); end; function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; const ModuleId: Integer): Integer; + const ANames, ALinks: TStringList; const AURL: String; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink( - MangaInfo, Names, Links, URL, TModuleContainer(FModuleList[ModuleId])); + MangaInfo, ANames, ALinks, AURL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL, Website: String): Integer; + const ANames, ALinks: TStringList; const AURL, AWebsite: String): Integer; begin - Result := GetNameAndLink(MangaInfo, Names, Links, URL, LocateModule(Website)); + Result := GetNameAndLink(MangaInfo, ANames, ALinks, AURL, LocateModule(AWebsite)); end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const URL: String; const Reconnect: Integer; const ModuleId: Integer): Integer; + const AURL: String; const Reconnect: Integer; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetInfo) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetInfo( - MangaInfo, URL, Reconnect, TModuleContainer(FModuleList[ModuleId])); + MangaInfo, AURL, Reconnect, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const URL: String; const Reconnect: Integer; const Website: String): Integer; + const AURL: String; const Reconnect: Integer; const AWebsite: String): Integer; begin - Result := GetInfo(MangaInfo, URL, Reconnect, LocateModule(Website)); + Result := GetInfo(MangaInfo, AURL, Reconnect, LocateModule(AWebsite)); end; function TWebsiteModules.TaskStart(var Task: TTaskContainer; @@ -407,58 +407,58 @@ function TWebsiteModules.TaskStart(var Task: TTaskContainer; end; function TWebsiteModules.TaskStart(var Task: TTaskContainer; - const Website: String): Boolean; + const AWebsite: String): Boolean; begin - Result := TaskStart(Task, LocateModule(Website)); + Result := TaskStart(Task, LocateModule(AWebsite)); end; function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; - const URL: String; const ModuleId: Integer): Boolean; + const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetPageNumber) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetPageNumber( - DownloadThread, URL, TModuleContainer(FModuleList[ModuleId])); + DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; - const URL, Website: String): Boolean; + const AURL, AWebsite: String): Boolean; begin - Result := GetPageNumber(DownloadThread, URL, LocateModule(Website)); + Result := GetPageNumber(DownloadThread, AURL, LocateModule(AWebsite)); end; function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; - const URL: String; const ModuleId: Integer): Boolean; + const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetImageURL) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetImageURL( - DownloadThread, URL, TModuleContainer(FModuleList[ModuleId])); + DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; - const URL, Website: String): Boolean; + const AURL, AWebsite: String): Boolean; begin - Result := GetImageURL(DownloadThread, URL, LocateModule(Website)); + Result := GetImageURL(DownloadThread, AURL, LocateModule(AWebsite)); end; function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix: String; ModuleId: Integer): Boolean; + const AURL, APath, AName, APrefix: String; ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnDownloadImage) then Result := TModuleContainer(FModuleList[ModuleId]).OnDownloadImage( - DownloadThread, URL, Path, Name, Prefix, TModuleContainer(FModuleList[ModuleId])); + DownloadThread, AURL, APath, AName, APrefix, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; - const URL, Path, Name, Prefix, Website: String): Boolean; + const AURL, APath, AName, APrefix, AWebsite: String): Boolean; begin - Result := DownloadImage(DownloadThread, URL, Path, Name, Prefix, - LocateModule(Website)); + Result := DownloadImage(DownloadThread, AURL, APath, AName, APrefix, + LocateModule(AWebsite)); end; function TWebsiteModules.Login(var AHTTP: THTTPSendThread; @@ -470,10 +470,10 @@ function TWebsiteModules.Login(var AHTTP: THTTPSendThread; Result := TModuleContainer(FModuleList[ModuleId]).OnLogin(AHTTP); end; -function TWebsiteModules.Login(var AHTTP: THTTPSendThread; const Website: String +function TWebsiteModules.Login(var AHTTP: THTTPSendThread; const AWebsite: String ): Boolean; begin - Result := Login(AHTTP, LocateModule(Website)); + Result := Login(AHTTP, LocateModule(AWebsite)); end; procedure TWebsiteModules.LockModules; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index cb02c482f..837b76680 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -69,7 +69,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; var Parse: TStringList; s: String; @@ -94,8 +94,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; else if GetTagName(Parse[i]) = 'a' then begin - Links.Add(GetVal(Parse[i], 'href')); - Names.Add(CommonStringFilter(Parse[i + 1])); + ALinks.Add(GetVal(Parse[i], 'href')); + ANames.Add(CommonStringFilter(Parse[i + 1])); end; end; @@ -104,7 +104,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if MangaInfo = nil then Exit; s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + dirparam + IntToStr(perpage); - p := StrToIntDef(URL, 0); + p := StrToIntDef(AURL, 0); if p > 0 then s += '&st=' + (IntToStr(p * perpage)); Parse := TStringList.Create; @@ -190,7 +190,7 @@ function Login(var AHTTP: THTTPSendThread): Boolean; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var source: TStringList; @@ -203,7 +203,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; with MangaInfo do begin mangaInfo.website := modulename; - mangaInfo.url := FillHost(urlroot, URL); + mangaInfo.url := FillHost(urlroot, AURL); while onlogin do Sleep(1000); FHTTP.Cookies.Text := Account.Cookies[modulename]; if FHTTP.GET(mangaInfo.url) then begin @@ -256,7 +256,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var source: TStringList; @@ -269,7 +269,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; with DownloadThread.manager.container, DownloadThread.FHTTP do begin Cookies.Text := Account.Cookies[modulename]; Headers.Values['Referer'] := ' ' + urlroot + '/reader'; - cid := SeparateRight(URL, '/reader#'); + cid := SeparateRight(AURL, '/reader#'); if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin Result := True; source := TStringList.Create; @@ -294,7 +294,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var source: TStringList; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 40fdceb44..bdc84380c 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -35,7 +35,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const AURL: String; Module: TModuleContainer): Integer; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; rurl: String; @@ -52,8 +52,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//table[@class="itg"]/tbody/tr/td/div/div/a') do begin - Names.Add(v.toString); - Links.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); end; finally query.Free; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index cb968d09e..5cb17aecc 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -48,7 +48,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const AURL: String; Module: TModuleContainer): Integer; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -68,14 +68,14 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; query.ParseHTML(StreamToString(Document)); if Module.Website = 'MangaIndo' then begin for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do - Links.Add(v.toString); + ALinks.Add(v.toString); for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do - Names.Add(v.toString); + ANames.Add(v.toString); end else if Module.Website = 'ReadHentaiManga' then begin for v in Query.XPath('//*[@id="content"]//*[@id="center"]/a') do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toNode.getAttribute('title')); + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toNode.getAttribute('title')); end; end else begin @@ -85,8 +85,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; else s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; for v in Query.XPath(s) do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; end; finally From 4e20930574a051c92b9a9acb7cc31e321ac70d9d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 15:50:16 +0800 Subject: [PATCH 0635/2794] ehentai, fix pagelink --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index bdc84380c..712158afb 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -150,7 +150,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; procedure GetImageLink; begin - for v in query.XPath('//*[@class="gdtm"]/div/a/@href') do + for v in query.XPath('//div[@id="gdt"]//a/@href') do with DownloadThread.manager.container do begin PageLinks.Add('G'); PageContainerLinks.Add(v.toString); From df2b9b29913076434f1a6c9e6e6f433b8d2c7674 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 15:54:53 +0800 Subject: [PATCH 0636/2794] ehentai, don't add chapter if invalid page --- baseunits/modules/EHentai.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 712158afb..652bc7d79 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -96,8 +96,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; '//a[starts-with(@id,"ta_")and(not(starts-with(@id,"ta_artist")))]') do AddCommaString(genres, v.toString); //chapter - chapterLinks.Add(url); - chapterName.Add(title); + if title <> '' then begin + chapterLinks.Add(url); + chapterName.Add(title); + end; //status with TRegExpr.Create do try @@ -220,7 +222,6 @@ function DownloadImage(var DownloadThread: TDownloadThread; i, rcount: Integer; base_url, startkey, gid, startpage, nl: String; source: TStringList; - s: String; begin rcount := 0; Result := False; From 6cb347f2b93ff9657f99844aa2375ffe80101216 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 16:06:09 +0800 Subject: [PATCH 0637/2794] httpsendthread, add redirection property and fix --- baseunits/httpsendthread.pas | 80 +++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index eedeced42..ab7d20ef8 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -14,14 +14,14 @@ interface THTTPSendThread = class(THTTPSend) private - FOwner: TFMDThread; + fowner: TFMDThread; + fretrycount: Integer; + fgzip: Boolean; + ffollowredirection: Boolean; procedure SetTimeout(AValue: integer); procedure OnOwnerTerminate(Sender: TObject); public - RetryCount: Integer; - GZip: Boolean; constructor Create(AOwner: TFMDThread = nil); - property Timeout: integer read FTimeout write SetTimeout; function HTTPRequest(const Method, URL: String; Response: TObject = nil): Boolean; function GET(const URL: String; Response: TObject = nil): Boolean; function POST(const URL: String; URLData: String = ''; Response: TObject = nil): Boolean; @@ -30,6 +30,10 @@ THTTPSendThread = class(THTTPSend) procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); procedure SetNoProxy; procedure Reset; + property Timeout: integer read FTimeout write SetTimeout; + property RetryCount: Integer read fretrycount write fretrycount; + property GZip: Boolean read fgzip write fgzip; + property FollowRedirection: Boolean read ffollowredirection write ffollowredirection; end; implementation @@ -58,15 +62,16 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); Protocol := '1.1'; Headers.NameValueSeparator := ':'; Cookies.NameValueSeparator := '='; - GZip := True; - RetryCount := 0; + fgzip := True; + fretrycount := 0; + ffollowredirection := True; SetTimeout(15000); + Reset; if Assigned(AOwner) then begin - FOwner := AOwner; - FOwner.OnCustomTerminate := @OnOwnerTerminate; + fowner := AOwner; + fowner.OnCustomTerminate := @OnOwnerTerminate; end; - Reset; end; function THTTPSendThread.HTTPRequest(const Method, URL: String; @@ -93,43 +98,44 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; // first request while (not HTTPMethod(Method, rurl)) or (ResultCode > 500) do begin if CheckTerminate then Exit; - if (RetryCount > -1) and (RetryCount <= counter) then Exit; + if (fretrycount > -1) and (fretrycount <= counter) then Exit; Inc(Counter); Headers.Assign(HTTPHeader); end; - // redirection - while (ResultCode > 300) and (ResultCode < 400) do begin - if CheckTerminate then Exit; - HTTPHeader.Values['Referer'] := ' ' + rurl; - s := Trim(Headers.Values['Location']); - if s <> '' then begin - with TRegExpr.Create do - try - Expression := '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - if Replace(s, '$1', True) = '' then begin - if s[1] <> '/' then s := '/' + s; - rurl := Replace(rurl, '$1$2$3', True) + s; - end else rurl := s; - finally - Free; - end; - end; + // redirection ' + if ffollowredirection then + while (ResultCode > 300) and (ResultCode < 400) do begin + if CheckTerminate then Exit; + HTTPHeader.Values['Referer'] := ' ' + rurl; + s := Trim(Headers.Values['Location']); + if s <> '' then begin + with TRegExpr.Create do + try + Expression := '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; + if Replace(s, '$1', True) = '' then begin + if s[1] <> '/' then s := '/' + s; + rurl := Replace(rurl, '$1$2$3', True) + s; + end else rurl := s; + finally + Free; + end; + end; - Clear; - Headers.Assign(HTTPHeader); - counter := 0; - while (not HTTPMethod('GET', rurl)) or (ResultCode > 500) do begin - if checkTerminate then Exit; - if (RetryCount > -1) and (RetryCount <= counter) then Exit; - Inc(counter); Clear; Headers.Assign(HTTPHeader); + counter := 0; + while (not HTTPMethod('GET', rurl)) or (ResultCode > 500) do begin + if checkTerminate then Exit; + if (fretrycount > -1) and (fretrycount <= counter) then Exit; + Inc(counter); + Clear; + Headers.Assign(HTTPHeader); + end; end; - end; // response - if ResultCode <> 404 then begin + if ResultCode < 500 then begin // decompress data s := LowerCase(Headers.Values['Content-Encoding']); if (Pos('gzip', s) <> 0) or (Pos('deflate', s) <> 0) then @@ -259,7 +265,7 @@ procedure THTTPSendThread.Reset; Headers.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; Headers.Values['Accept-Charset'] := ' utf8'; Headers.Values['Accept-Language'] := ' en-US,en;q=0.8'; - if GZip then Headers.Values['Accept-Encoding'] := ' gzip, deflate'; + if fgzip then Headers.Values['Accept-Encoding'] := ' gzip, deflate'; end; end. From 1543d0139955244a6934e4a299e194494e0f1ec1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 17:15:25 +0800 Subject: [PATCH 0638/2794] added exhentai with login close #121 --- baseunits/modules/EHentai.pas | 114 ++++++++++++++++++++++++++++++---- config/mangalist.ini | 2 +- 2 files changed, 102 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 652bc7d79..77f125022 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + accountmanagerdb; implementation @@ -13,6 +14,73 @@ implementation const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; + exhentaiurllogin = 'https://forums.e-hentai.org/index.php?act=Login&CODE=01'; + +var + onlogin: Boolean = False; + locklogin: TRTLCriticalSection; + +function ExHentaiLogin(var AHTTP: THTTPSendThread): Boolean; +var + s: String; +const + acc = 'ExHentai'; +begin + Result := False; + if AHTTP = nil then Exit; + if Account.Enabled[acc] = False then Exit; + if Account.Username[acc] = '' then Exit; + + if TryEnterCriticalsection(locklogin) > 0 then + with AHTTP do begin + onlogin := True; + Account.Status[acc] := asChecking; + Reset; + Cookies.Clear; + s := 'returntype=8&CookieDate=1&b=d&bt=pone&UserName=' + +Account.Username[acc]+ + '&PassWord=' + +Account.Password[acc]+ + '&ipb_login_submit=Login%21'; + if POST(exhentaiurllogin, s) then begin + if ResultCode = 200 then begin + Result := Cookies.Values['ipb_pass_hash'] <> ''; + if Result then begin + Account.Cookies[acc] := GetCookies; + Account.Status[acc] := asValid; + end + else Account.Status[acc] := asInvalid; + Account.Save; + end; + end; + onlogin := False; + if Account.Status[acc] = asChecking then + Account.Status[acc] := asUnknown; + LeaveCriticalsection(locklogin); + end + else + begin + while onlogin do Sleep(1000); + if Result then AHTTP.Cookies.Text := Account.Cookies[acc]; + end; +end; + +function GETWithLogin(var AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; +begin + Result := False; + if AWebsite = 'ExHentai' then begin + AHTTP.FollowRedirection := False; + AHTTP.Cookies.Text := Account.Cookies[AWebsite]; + Result := AHTTP.GET(AURL); + if Result and (AHTTP.ResultCode > 300) then begin + Result := ExHentaiLogin(AHTTP); + if Result then + Result := AHTTP.GET(AURL); + end; + end + else + Result := AHTTP.GET(AURL); +end; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; @@ -22,7 +90,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/?' + dirURL) then begin + if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/?' + dirURL, Module.Website) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try @@ -45,7 +113,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if AURL = '0' then rurl := Module.RootURL + '/?' + dirURL else rurl := Module.RootURL + '/?page=' + IncStr(AURL) + '&' + dirURL; - if MangaInfo.FHTTP.GET(rurl) then begin + if GETWithLogin(MangaInfo.FHTTP, rurl, Module.Website) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try @@ -75,7 +143,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; // check content warning if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then begin - getOK := MangaInfo.FHTTP.GET(MangaInfo.mangaInfo.url + '?nw=session'); + getOK := GETWithLogin(MangaInfo.FHTTP, MangaInfo.mangaInfo.url + '?nw=session', Module.Website); if getOK then query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); end; @@ -122,11 +190,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit; - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + with MangaInfo.mangaInfo do begin website := Module.Website; url := FillHost(Module.RootURL, AURL); - if GET(url) then - begin + if GETWithLogin(MangaInfo.FHTTP, url, Module.Website) then begin Result := NO_ERROR; // if there is only 1 line, it's banned message! //if Source.Count = 1 then @@ -134,7 +201,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; //else query := TXQueryEngineHTML.Create; try - query.ParseHTML(StreamToString(Document)); + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); ScanParse; finally query.Free; @@ -169,7 +236,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; //check content warning if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then begin - getOK := DownloadThread.FHTTP.GET(rurl + '?nw=session'); + getOK := GETWithLogin(DownloadThread.FHTTP, rurl + '?nw=session', Module.Website); if getOK then query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); end; @@ -181,7 +248,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; 'table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) - 1; if p > 0 then for i := 1 to p do - if DownloadThread.FHTTP.GET(rurl + '?p=' + IntToStr(i)) then + if GETWithLogin(DownloadThread.FHTTP, rurl + '?p' + IntToStr(i), Module.Website) then begin query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); GetImageLink; @@ -197,7 +264,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; PageContainerLinks.Clear; PageNumber := 0; rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if GET(rurl) then begin + if GETWithLogin(DownloadThread.FHTTP, rurl, Module.Website) then begin Result := True; query := TXQueryEngineHTML.Create; try @@ -264,7 +331,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; else iurl := FillHost(Module.RootURL, AURL); if nl <> '' then begin iurl := iurl + '?nl=' + nl; - if not DownloadThread.FHTTP.GET(iurl) then Break; + if not GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then Break; end else Break; if rcount >= reconnect then Break else Inc(rcount); @@ -280,7 +347,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; reconnect := DownloadThread.FHTTP.RetryCount; iurl := FillHost(Module.RootURL, AURL); - if DownloadThread.FHTTP.GET(iurl) then begin + if GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then begin query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); @@ -308,9 +375,30 @@ procedure RegisterModule; OnGetPageNumber := @GetPageNumber; OnDownloadImage := @DownloadImage; end; + with AddModule do + begin + Website := 'ExHentai'; + RootURL := 'http://exhentai.org'; + MaxTaskLimit := 1; + MaxConnectionLimit := 4; + SortedList := True; + InformationAvailable := True; + DynamicPageLink := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + AccountSupport := True; + OnLogin := @ExHentaiLogin; + end; end; initialization + InitCriticalSection(locklogin); RegisterModule; +finalization + DoneCriticalsection(locklogin); + end. diff --git a/config/mangalist.ini b/config/mangalist.ini index a581de8ea..42bfcdfd8 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -18,4 +18,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,Fakku,HakiHome,Hentai2Read,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From 0686ca96fcfdcbe211e094589c11d497c4d369fd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 17:19:50 +0800 Subject: [PATCH 0639/2794] frmaccountmanager, fix column width not loaded properly --- mangadownloader/forms/frmAccountManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 72d60f364..202a3eeb9 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -286,7 +286,6 @@ procedure TAccountManagerForm.vtAccountListGetText(Sender: TBaseVirtualTree; procedure TAccountManagerForm.FormShow(Sender: TObject); begin - LoadForm; RefreshList; RefreshWebsiteAvailable; end; @@ -338,6 +337,7 @@ procedure TAccountManagerForm.FormCreate(Sender: TObject); Websites.Add(Modules.Module[i].Website); Websites.Sorted := True; end; + LoadForm; end; procedure TAccountManagerForm.FormDestroy(Sender: TObject); From f4b5b67b21e73b018fcaa01d0c674a64d3666822 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 17:28:14 +0800 Subject: [PATCH 0640/2794] added mangabug --- baseunits/modules/WPManga.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 5cb17aecc..a023e0340 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -295,6 +295,7 @@ procedure RegisterModule; AddWebsiteModule('MangaIndo', 'http://mangaindo.id'); AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); + AddWebsiteModule('MangaBug', 'http://www.mangabug.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 42bfcdfd8..855745032 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 07c70c8162bee6b6cfb77774106206ce5e7b143d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 17:45:33 +0800 Subject: [PATCH 0641/2794] update translations --- mangadownloader/languages/fmd.en.po | 52 ++++++----------- mangadownloader/languages/fmd.id_ID.po | 79 ++++++-------------------- 2 files changed, 35 insertions(+), 96 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d49844794..9ceef3057 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -14,27 +14,27 @@ msgstr "" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" -msgstr "" +msgstr "Are you sure you want to delete this account?" #: frmaccountmanager.rs_checking msgid "Checking" -msgstr "" +msgstr "Checking" #: frmaccountmanager.rs_invalid msgid "Invalid" -msgstr "" +msgstr "Invalid" #: frmaccountmanager.rs_unknown msgid "Unknown" -msgstr "" +msgstr "Unknown" #: frmaccountmanager.rs_valid msgid "OK" -msgstr "" +msgstr "OK" #: frmaccountset.rs_cantbeempty msgid "Username or password can't be empty!" -msgstr "" +msgstr "Username or password can't be empty!" #: frmimportfavorites.rs_importcompleted msgid "Import completed." @@ -91,7 +91,6 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" #: frmmain.rs_dlgtitleexistindllist -#, fuzzy #| msgid "" #| "This title are already in download list.\n" #| "Do you want to download it anyway?\n" @@ -123,7 +122,6 @@ msgid "URL not supported!" msgstr "URL not supported!" #: frmmain.rs_droptargetmodeitems -#, fuzzy #| msgid "" #| "Download all\n" #| "Add to favorites\n" @@ -135,7 +133,6 @@ msgstr "" "Add to favorites\n" #: frmmain.rs_filterstatusitems -#, fuzzy #| msgid "" #| "Completed\n" #| "Ongoing\n" @@ -154,7 +151,6 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader already running!" #: frmmain.rs_hintfavoriteproblem -#, fuzzy #| msgid "" #| "There is a problem with this data!\n" #| "Removing and re-adding this data may fix the problem.\n" @@ -211,7 +207,6 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" #: frmmain.rs_lbloptionexternalparamshint -#, fuzzy #| msgid "" #| "%s : Path to the manga\n" #| "%s : Chapter filename\n" @@ -255,7 +250,6 @@ msgid "One week" msgstr "One week" #: frmmain.rs_optionfmddoitems -#, fuzzy #| msgid "" #| "Do nothing\n" #| "Exit FMD\n" @@ -307,81 +301,72 @@ msgstr "System will shutdown in %d second." #: taccountmanagerform.btadd.caption msgid "Add" -msgstr "" +msgstr "Add" #: taccountmanagerform.btdelete.caption msgctxt "taccountmanagerform.btdelete.caption" msgid "Delete" -msgstr "" +msgstr "Delete" #: taccountmanagerform.btedit.caption msgid "Edit" -msgstr "" +msgstr "Edit" #: taccountmanagerform.btrefresh.caption msgid "Refresh" -msgstr "" +msgstr "Refresh" #: taccountmanagerform.vtaccountlist.header.columns[1].text -#, fuzzy #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" -msgstr "Username" +msgstr "Website" #: taccountmanagerform.vtaccountlist.header.columns[2].text -#, fuzzy #| msgid "Status" msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" msgid "Username" -msgstr "Status" +msgstr "Username" #: taccountmanagerform.vtaccountlist.header.columns[3].text -#, fuzzy #| msgid "Status" msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" msgid "Status" msgstr "Status" #: taccountsetform.btcancel.caption -#, fuzzy msgctxt "taccountsetform.btcancel.caption" msgid "Cancel" msgstr "Cancel" #: taccountsetform.btok.caption msgid "Ok" -msgstr "" +msgstr "Ok" #: taccountsetform.edpassword.texthint -#, fuzzy msgctxt "taccountsetform.edpassword.texthint" msgid "Password" msgstr "Password" #: taccountsetform.edusername.texthint -#, fuzzy #| msgid "Status" msgctxt "taccountsetform.edusername.texthint" msgid "Username" -msgstr "Status" +msgstr "Username" #: taccountsetform.label1.caption -#, fuzzy #| msgid "Username" msgctxt "taccountsetform.label1.caption" msgid "Website" -msgstr "Username" +msgstr "Website" #: taccountsetform.label2.caption -#, fuzzy #| msgid "Status" msgctxt "taccountsetform.label2.caption" msgid "Username" -msgstr "Status" +msgstr "Username" #: taccountsetform.label3.caption -#, fuzzy msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Password" @@ -589,7 +574,7 @@ msgstr "HTTP" #: tmainform.cboptionremovemanganamefromchapter.caption msgid "Remove manga name from chapter" -msgstr "" +msgstr "Remove manga name from chapter" #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" @@ -1482,7 +1467,7 @@ msgstr "About FMD" #: tmainform.tsaccounts.caption msgid "Accounts" -msgstr "" +msgstr "Accounts" #: tmainform.tschangelogtext.caption msgid "Changelog" @@ -1821,4 +1806,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 2bafe7d7c..6cd9c834d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -14,27 +14,27 @@ msgstr "" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" -msgstr "" +msgstr "Apakah anda yakin ingin menghapus akun ini?" #: frmaccountmanager.rs_checking msgid "Checking" -msgstr "" +msgstr "Memerika" #: frmaccountmanager.rs_invalid msgid "Invalid" -msgstr "" +msgstr "Tidak valid" #: frmaccountmanager.rs_unknown msgid "Unknown" -msgstr "" +msgstr "Tidak diketahui" #: frmaccountmanager.rs_valid msgid "OK" -msgstr "" +msgstr "OK" #: frmaccountset.rs_cantbeempty msgid "Username or password can't be empty!" -msgstr "" +msgstr "Nama user atau kata kunci tidak boleh kosong!" #: frmimportfavorites.rs_importcompleted msgid "Import completed." @@ -91,10 +91,6 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Apakah Anda yakin ingin menghapus unduhan ini?" #: frmmain.rs_dlgtitleexistindllist -#, fuzzy -#| msgid "" -#| "This title are already in download list.\n" -#| "Do you want to download it anyway?\n" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" @@ -123,10 +119,6 @@ msgid "URL not supported!" msgstr "URL tidak didukung!" #: frmmain.rs_droptargetmodeitems -#, fuzzy -#| msgid "" -#| "Download all\n" -#| "Add to favorites\n" msgid "" "Download all\n" "Add to favorites\n" @@ -135,11 +127,6 @@ msgstr "" "Tambahkan ke kesukaan\n" #: frmmain.rs_filterstatusitems -#, fuzzy -#| msgid "" -#| "Completed\n" -#| "Ongoing\n" -#| "<none>\n" msgid "" "Completed\n" "Ongoing\n" @@ -154,10 +141,6 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader sudah berjalan!" #: frmmain.rs_hintfavoriteproblem -#, fuzzy -#| msgid "" -#| "There is a problem with this data!\n" -#| "Removing and re-adding this data may fix the problem.\n" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" @@ -211,12 +194,6 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Otomatis periksa bab baru setiap %d menit" #: frmmain.rs_lbloptionexternalparamshint -#, fuzzy -#| msgid "" -#| "%s : Path to the manga\n" -#| "%s : Chapter filename\n" -#| "\n" -#| "Example : \"%s%s\"\n" msgid "" "%s : Path to the manga\n" "%s : Chapter filename\n" @@ -254,12 +231,6 @@ msgid "One week" msgstr "Satu minggu" #: frmmain.rs_optionfmddoitems -#, fuzzy -#| msgid "" -#| "Do nothing\n" -#| "Exit FMD\n" -#| "Shutdown\n" -#| "Hibernate\n" msgid "" "Do nothing\n" "Exit FMD\n" @@ -306,81 +277,66 @@ msgstr "Komputer akan dimatikan dalam %d detik" #: taccountmanagerform.btadd.caption msgid "Add" -msgstr "" +msgstr "Tambah" #: taccountmanagerform.btdelete.caption msgctxt "taccountmanagerform.btdelete.caption" msgid "Delete" -msgstr "" +msgstr "Hapus" #: taccountmanagerform.btedit.caption msgid "Edit" -msgstr "" +msgstr "Ubah" #: taccountmanagerform.btrefresh.caption msgid "Refresh" -msgstr "" +msgstr "Segarkan" #: taccountmanagerform.vtaccountlist.header.columns[1].text -#, fuzzy -#| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" -msgstr "Nama user" +msgstr "Situs web" #: taccountmanagerform.vtaccountlist.header.columns[2].text -#, fuzzy -#| msgid "Status" msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" msgid "Username" -msgstr "Status" +msgstr "Nama user" #: taccountmanagerform.vtaccountlist.header.columns[3].text -#, fuzzy -#| msgid "Status" msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" msgid "Status" msgstr "Status" #: taccountsetform.btcancel.caption -#, fuzzy msgctxt "taccountsetform.btcancel.caption" msgid "Cancel" msgstr "Batal" #: taccountsetform.btok.caption msgid "Ok" -msgstr "" +msgstr "Akun" #: taccountsetform.edpassword.texthint -#, fuzzy msgctxt "taccountsetform.edpassword.texthint" msgid "Password" msgstr "Kata kunci" #: taccountsetform.edusername.texthint -#, fuzzy -#| msgid "Status" msgctxt "taccountsetform.edusername.texthint" msgid "Username" -msgstr "Status" +msgstr "Nama user" #: taccountsetform.label1.caption -#, fuzzy -#| msgid "Username" msgctxt "taccountsetform.label1.caption" msgid "Website" -msgstr "Nama user" +msgstr "Situs web" #: taccountsetform.label2.caption -#, fuzzy -#| msgid "Status" msgctxt "taccountsetform.label2.caption" msgid "Username" -msgstr "Status" +msgstr "Nama user" #: taccountsetform.label3.caption -#, fuzzy msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Kata kunci" @@ -1462,7 +1418,7 @@ msgstr "Tentang FMD" #: tmainform.tsaccounts.caption msgid "Accounts" -msgstr "" +msgstr "Akun" #: tmainform.tschangelogtext.caption msgid "Changelog" @@ -1801,4 +1757,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - From 312b764bb2490379b7c715372aa042e72cb7e1b8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 17:49:57 +0800 Subject: [PATCH 0642/2794] remove unused units --- baseunits/accountmanager.pas | 121 ------------------------------ mangadownloader/forms/frmMain.pas | 4 +- 2 files changed, 2 insertions(+), 123 deletions(-) delete mode 100644 baseunits/accountmanager.pas diff --git a/baseunits/accountmanager.pas b/baseunits/accountmanager.pas deleted file mode 100644 index 9abfb5955..000000000 --- a/baseunits/accountmanager.pas +++ /dev/null @@ -1,121 +0,0 @@ -unit accountmanager; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, IniFiles, base64; - -type - - { TAccountManager } - - TAccountManager = class - private - fstorage: TIniFile; - function GetUsername(Name: string): string; - function GetPassword(Name: string): string; - function GetCookies(Name: string): string; - function GetStatus(Name: string): string; - procedure SetUsername(Name: string; AValue: string); - procedure SetPassword(Name: string; AValue: string); - procedure SetCookies(Name: string; AValue: string); - procedure SetStatus(Name: string; AValue: string); - public - constructor Create(const Filename: string); - destructor Destroy; override; - procedure Save; - property Username[Name: string]: string read GetUsername write SetUsername; - property Password[Name: string]: string read GetPassword write SetPassword; - property Cookies[Name: string]: string read GetCookies write SetCookies; - property Status[Name: string]: string read GetStatus write SetStatus; - end; - - procedure InitAccountManager(const Filename: string); - -var - Account: TAccountManager; - -implementation - -procedure InitAccountManager(const Filename: string); -begin - Account := TAccountManager.Create(Filename); -end; - -function encode(const s: string): string; -begin - if s = '' then Exit(''); - Result := EncodeStringBase64(s); -end; - -function decode(const s: string): string; -begin - if s = '' then Exit(''); - Result := DecodeStringBase64(s); -end; - -{ TAccountManager } - -function TAccountManager.GetUsername(Name: string): string; -begin - Result := decode(fstorage.ReadString(Name, 'username', '')); -end; - -function TAccountManager.GetPassword(Name: string): string; -begin - Result := decode(fstorage.ReadString(Name, 'password', '')); -end; - -function TAccountManager.GetCookies(Name: string): string; -begin - Result := decode(fstorage.ReadString(Name, 'cookies', '')); -end; - -function TAccountManager.GetStatus(Name: string): string; -begin - Result := decode(fstorage.ReadString(Name, 'status', '')); -end; - -procedure TAccountManager.SetUsername(Name: string; AValue: string); -begin - fstorage.WriteString(Name, 'username', encode(AValue)); -end; - -procedure TAccountManager.SetPassword(Name: string; AValue: string); -begin - fstorage.WriteString(Name, 'password', encode(AValue)); -end; - -procedure TAccountManager.SetCookies(Name: string; AValue: string); -begin - fstorage.WriteString(Name, 'cookies', encode(AValue)); -end; - -procedure TAccountManager.SetStatus(Name: string; AValue: string); -begin - fstorage.WriteString(Name, 'status', encode(AValue)); -end; - -constructor TAccountManager.Create(const Filename: string); -begin - fstorage := TIniFile.Create(Filename); -end; - -destructor TAccountManager.Destroy; -begin - fstorage.Free; - inherited Destroy; -end; - -procedure TAccountManager.Save; -begin - fstorage.UpdateFile; -end; - -finalization - if Assigned(Account) then Account.Free; - -end. - diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a58d00c3c..1ee99399f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,8 +22,8 @@ interface FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, - frmDropTarget, frmAccountManager, CheckUpdate, accountmanager, - accountmanagerdb, USimpleException, USimpleLogger; + frmDropTarget, frmAccountManager, CheckUpdate, accountmanagerdb, + USimpleException, USimpleLogger; type From 4f8c0434d50d2be4c3fd676767fc8459009f1606 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Dec 2015 18:01:38 +0800 Subject: [PATCH 0643/2794] bump version 0.9.25.0 --- changelog.txt | 10 ++++++++++ mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index c79a13b35..78239bb05 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,16 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.25.0 (21-12-2015) +[+] Added 8Muses[H] (no list, use drop box) +[+] Added Account Manager, Options > Accounts +[+] Batoto, add account support +[-] Drop support for Manga2u +[+] Added MangaHen[EN] +[+] Added ExHentai[H] with account support +[+] Added MangaBug[EN] +[*] Various changes and bug fixes + 0.9.24.1 (25-11-2015) [*] Fix fmd freeze diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ac98b055d..f965f212b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="24"/> - <BuildNr Value="1"/> + <RevisionNr Value="25"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 7951307d7..7daefa96e 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.24.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.24.1/fmd_0.9.24.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.24.1/fmd_0.9.24.1_Win64.7z +VERSION=0.9.25.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.25.0/fmd_0.9.25.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.25.0/fmd_0.9.25.0_Win64.7z From 425f6ab9838ed3df98a1eabf171f7a0002af734e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 02:27:01 +0800 Subject: [PATCH 0644/2794] fix translations --- mangadownloader/languages/fmd.en.po | 23 ----------------------- mangadownloader/languages/fmd.id_ID.po | 2 +- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 9ceef3057..1ff976ec9 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -91,9 +91,6 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" #: frmmain.rs_dlgtitleexistindllist -#| msgid "" -#| "This title are already in download list.\n" -#| "Do you want to download it anyway?\n" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" @@ -122,9 +119,6 @@ msgid "URL not supported!" msgstr "URL not supported!" #: frmmain.rs_droptargetmodeitems -#| msgid "" -#| "Download all\n" -#| "Add to favorites\n" msgid "" "Download all\n" "Add to favorites\n" @@ -133,10 +127,6 @@ msgstr "" "Add to favorites\n" #: frmmain.rs_filterstatusitems -#| msgid "" -#| "Completed\n" -#| "Ongoing\n" -#| "<none>\n" msgid "" "Completed\n" "Ongoing\n" @@ -151,9 +141,6 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader already running!" #: frmmain.rs_hintfavoriteproblem -#| msgid "" -#| "There is a problem with this data!\n" -#| "Removing and re-adding this data may fix the problem.\n" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" @@ -207,11 +194,6 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" #: frmmain.rs_lbloptionexternalparamshint -#| msgid "" -#| "%s : Path to the manga\n" -#| "%s : Chapter filename\n" -#| "\n" -#| "Example : \"%s%s\"\n" msgid "" "%s : Path to the manga\n" "%s : Chapter filename\n" @@ -250,11 +232,6 @@ msgid "One week" msgstr "One week" #: frmmain.rs_optionfmddoitems -#| msgid "" -#| "Do nothing\n" -#| "Exit FMD\n" -#| "Shutdown\n" -#| "Hibernate\n" msgid "" "Do nothing\n" "Exit FMD\n" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 6cd9c834d..807e5ba73 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -314,7 +314,7 @@ msgstr "Batal" #: taccountsetform.btok.caption msgid "Ok" -msgstr "Akun" +msgstr "Ok" #: taccountsetform.edpassword.texthint msgctxt "taccountsetform.edpassword.texthint" From 21b4c8ade8a5696ecd7c40b4def72ec6c9dfd876 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 02:27:30 +0800 Subject: [PATCH 0645/2794] baseunit, add thtmlform --- baseunits/uBaseUnit.pas | 64 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 81f2c6677..2dfc49874 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -20,8 +20,8 @@ interface {$endif} SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, - RegExpr, synautil, httpsend, blcksock, ssl_openssl, GZIPUtils, uFMDThread, - uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, + RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, + uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, USimpleException, USimpleLogger; Type @@ -798,6 +798,24 @@ TXQueryEngineHTML = class IXQValue = xquery.IXQValue; + { THTMLForm } + + THTMLForm = class + private + fdata: TStringList; + fvalueseparator: String; + fdelimiter: String; + public + constructor Create; + destructor Destroy; override; + procedure Put(const AName, AValue: String); + procedure Remove(const AName: String); + function GetData: String; + property ValueSeparator: String read fvalueseparator write fvalueseparator; + property Delimiter: String read fdelimiter write fdelimiter; + property Data: TStringList read fdata; + end; + // Get current binary version function GetCurrentBinVersion: String; // Remove Unicode @@ -3587,6 +3605,48 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); dest.chapterLinks.Assign(Source.chapterLinks); end; +{ THTMLForm } + +constructor THTMLForm.Create; +begin + fdata := TStringList.Create; + fdata.NameValueSeparator := '='; + fdata.Delimiter := '&'; + fvalueseparator := '='; + fdelimiter := '&'; +end; + +destructor THTMLForm.Destroy; +begin + fdata.Free; + inherited Destroy; +end; + +procedure THTMLForm.Put(const AName, AValue: String); +begin + fdata.Values[AName] := AValue; +end; + +procedure THTMLForm.Remove(const AName: String); +var + i: Integer; +begin + i := fdata.IndexOfName(AName); + if i > -1 then fdata.Delete(i); +end; + +function THTMLForm.GetData: String; +var + i: Integer; +begin + Result := ''; + if fdata.Count > 0 then + for i := 0 to fdata.Count - 1 do begin + if Result <> '' then Result := Result + fdelimiter; + Result := Result + fdata.Names[i] + fvalueseparator + EncodeURLElement(fdata.ValueFromIndex[i]); + end; +end; + { THTTPSendThread } constructor THTTPSendThread.Create(AOwner: TFMDThread); From 9165e79cd982aa5067a21dee094054845bfdb945 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 02:32:03 +0800 Subject: [PATCH 0646/2794] fix ba to to login, encode form data fix #132 --- baseunits/modules/Batoto.pas | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 837b76680..b540a50e0 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -134,8 +134,8 @@ function CheckLogin(const source: string): Boolean; function Login(var AHTTP: THTTPSendThread): Boolean; var query: TXQueryEngineHTML; - source: TStringList; - s, key, user, pass: string; + loginform: THTMLForm; + key: string; begin Result := False; if AHTTP = nil then Exit; @@ -148,20 +148,23 @@ function Login(var AHTTP: THTTPSendThread): Boolean; Account.Status[modulename] := asChecking; Reset; Cookies.Clear; - if Get(urlroot) then begin - source := TStringList.Create; + if GET(urlroot) then begin + loginform := THTMLForm.Create; query := TXQueryEngineHTML.Create; try - source.LoadFromStream(Document); - query.ParseHTML(source.Text); + query.ParseHTML(StreamToString(Document)); key := query.XPathString('//input[@name="auth_key"]/@value'); if key <> '' then begin - user:= Account.Username[modulename]; - pass:= Account.Password[modulename]; - s := 'auth_key='+key+'&referer=https%3A%2F%2Fbato.to%2F'+'&ips_username='+user+'&ips_password='+pass+'&rememberMe=1'; + with loginform do begin + Put('auth_key', key); + Put('referer', 'https://bato.to/'); + Put('ips_username', Account.Username[modulename]); + Put('ips_password', Account.Password[modulename]); + Put('rememberMe', '1'); + end; Clear; Headers.Values['Referer'] := ' https://bato.to/'; - if Post(urllogin, s) then begin + if POST(urllogin, loginform.GetData) then begin if ResultCode = 200 then begin Result := Cookies.Values['pass_hash'] <> ''; if Result then begin @@ -175,7 +178,7 @@ function Login(var AHTTP: THTTPSendThread): Boolean; end; finally query.Free; - source.Free + loginform.Free end; end; onlogin := False; From 19dd63e94c96cd0a4410670f871f0ab65e64717c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 02:36:30 +0800 Subject: [PATCH 0647/2794] exhentai, encode login form --- baseunits/modules/EHentai.pas | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 77f125022..a5355db41 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb; + accountmanagerdb, synacode; implementation @@ -37,10 +37,9 @@ function ExHentaiLogin(var AHTTP: THTTPSendThread): Boolean; Account.Status[acc] := asChecking; Reset; Cookies.Clear; - s := 'returntype=8&CookieDate=1&b=d&bt=pone&UserName=' - +Account.Username[acc]+ - '&PassWord=' - +Account.Password[acc]+ + s := 'returntype=8&CookieDate=1&b=d&bt=pone'+ + '&UserName=' + EncodeURLElement(Account.Username[acc]) + + '&PassWord=' + EncodeURLElement(Account.Password[acc]) + '&ipb_login_submit=Login%21'; if POST(exhentaiurllogin, s) then begin if ResultCode = 200 then begin From 0e69bfa11620e6bcfb3288ae517760eafeb7204f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 03:00:46 +0800 Subject: [PATCH 0648/2794] httpsendthread, process all response code --- baseunits/httpsendthread.pas | 60 +++++++++++++++++------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index ab7d20ef8..b9035e98c 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -96,7 +96,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; HTTPHeader.Assign(Headers); try // first request - while (not HTTPMethod(Method, rurl)) or (ResultCode > 500) do begin + while (not HTTPMethod(Method, rurl)) or (ResultCode = 500) do begin if CheckTerminate then Exit; if (fretrycount > -1) and (fretrycount <= counter) then Exit; Inc(Counter); @@ -135,38 +135,34 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; end; // response - if ResultCode < 500 then begin - // decompress data - s := LowerCase(Headers.Values['Content-Encoding']); - if (Pos('gzip', s) <> 0) or (Pos('deflate', s) <> 0) then - begin - mstream := TMemoryStream.Create; - try - ZUncompressStream(Document, mstream); - Document.Clear; - Document.LoadFromStream(mstream); - except - end; - mstream.Free; + // decompress data + s := LowerCase(Headers.Values['Content-Encoding']); + if (Pos('gzip', s) <> 0) or (Pos('deflate', s) <> 0) then + begin + mstream := TMemoryStream.Create; + try + ZUncompressStream(Document, mstream); + Document.Clear; + Document.LoadFromStream(mstream); + except end; - if Assigned(Response) then - try - if Response is TStringList then - TStringList(Response).LoadFromStream(Document) - else - if Response is TPicture then - TPicture(Response).LoadFromStream(Document) - else - if Response is TStream then - Document.SaveToStream(TStream(Response)); - except - on E: Exception do - WriteLog_E('HTTPRequest.WriteOutput.Error!', E); - end; - Result := True; - end - else - Result := False; + mstream.Free; + end; + if Assigned(Response) then + try + if Response is TStringList then + TStringList(Response).LoadFromStream(Document) + else + if Response is TPicture then + TPicture(Response).LoadFromStream(Document) + else + if Response is TStream then + Document.SaveToStream(TStream(Response)); + except + on E: Exception do + WriteLog_E('HTTPRequest.WriteOutput.Error!', E); + end; + Result := ResultCode < 500; finally HTTPHeader.Free; end; From 223268773efe7aecb0f2455d6806a7c881751616 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 14:10:22 +0800 Subject: [PATCH 0649/2794] baseunit, add fillurlprotocol --- baseunits/uBaseUnit.pas | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2dfc49874..2af45ba58 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -842,6 +842,9 @@ function SitesWithoutReferer(const website: String): Boolean; function SitesRefererisURL(const website: String): Boolean; function SitesWithSingleChapter(const website: String): Boolean; +// url +function FillURLProtocol(const AProtocol, AURL: String): String; + // Fill in website host if it's not present function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; function FillMangaSiteHost(const Website, URL: String): String; overload; @@ -1389,6 +1392,16 @@ function SitesWithSingleChapter(const website : String) : Boolean; ]); end; +function FillURLProtocol(const AProtocol, AURL: String): String; +begin + Result := AURL; + if AURL <> '' then begin + Result := ReplaceRegExpr('^\w*:?//', AURL, '', False); + if AProtocol <> '' then + Result := AProtocol + Result; + end; +end; + function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; begin Result := URL; From 709ad2633c960dd19dd37337e0b4ed67b4929970 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 14:26:50 +0800 Subject: [PATCH 0650/2794] added hitomila close #123 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/HitomiLa.pas | 140 +++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/HitomiLa.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index cfc0c79b6..65592881a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -13,4 +13,5 @@ uses MangaLife, Luscious, MangaHere, - EightMuses; + EightMuses, + HitomiLa; diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas new file mode 100644 index 000000000..84b0d2a16 --- /dev/null +++ b/baseunits/modules/HitomiLa.pas @@ -0,0 +1,140 @@ +unit HitomiLa; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + source: TStringList; + i: Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL) then begin + Result := NO_ERROR; + source := TStringList.Create; + try + source.LoadFromStream(MangaInfo.FHTTP.Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do begin + if Pos('insert_paging(', source[i]) > 0 then begin + Page := StrToIntDef(GetString(source[i], ', 1, ', ');'), 1); + Break; + end; + end; + finally + source.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/index-all-'+ AURL +'.html') then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//div[@class="gallery-content"]/div/h1/a') do + begin + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.mangaInfo.website := Module.Website; + if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + with MangaInfo.mangaInfo, query do begin + coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src')); + title := XPathString('//div/h1'); + for v in XPath('//div[@class="gallery-info"]/table//tr/td[2]//a') do + AddCommaString(genres, v.toString); + s := XPathString('//div[@class="cover-column"]/a/@href'); + if (s <> '') and (title <> '') then begin + chapterLinks.Add(s); + chapterName.Add(title); + end; + end; + finally + query.Free; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + for v in query.XPath('//div[@class="img-url"]') do + PageLinks.Add(FillURLProtocol('https://', v.toString)); + PageNumber := PageLinks.Count + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'HitomiLa'; + RootURL := 'https://hitomi.la'; + SortedList := True; + FavoriteAvailable := False; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 855745032..5efefd28e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -18,4 +18,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From 17ec5d15ab5e8d935baf584f2006c215b65237f1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Dec 2015 15:02:14 +0800 Subject: [PATCH 0651/2794] added hentaicafe close #124 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/HentaiCafe.pas | 146 +++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/HentaiCafe.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 65592881a..89df29565 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -14,4 +14,5 @@ uses Luscious, MangaHere, EightMuses, - HitomiLa; + HitomiLa, + HentaiCafe; diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas new file mode 100644 index 000000000..c95ac1bad --- /dev/null +++ b/baseunits/modules/HentaiCafe.pas @@ -0,0 +1,146 @@ +unit HentaiCafe; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +uses synautil; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + Page := StrToIntDef(query.XPathString('//a[@class="last"]'), 1); + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/page/'+ AURL +'/') then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//h2[@class="entry-title"]/a') do + begin + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.mangaInfo.website := Module.Website; + if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + with MangaInfo.mangaInfo, query do begin + coverLink := XPathString('//div[@class="entry-content content"]//img/@src'); + title := XPathString('//div[@class="entry-content content"]//h3'); + for v in XPath('//div[@class="entry-content content"]//a') do begin + s := v.toNode.getAttribute('href'); + if Pos('/artist/', s) > 0 then AddCommaString(artists, v.toString) + else if Pos('/read/', s) > 0 then begin + if title <> '' then begin + chapterLinks.Add(s); + chapterName.Add(title); + end; + end + else AddCommaString(genres, v.toString); + end; + end; + finally + query.Free; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + source: TStringList; + i: Integer; + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + source := TStringList.Create; + try + source.LoadFromStream(DownloadThread.FHTTP.Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do + if Pos('var pages = ', source[i]) > 0 then begin + s := SeparateRight(source[i], 'var pages = '); + s := Trim(TrimRightChar(s, [';'])); + ParseJSONArray(s, 'url', PageLinks); + Break; + end; + PageNumber := PageLinks.Count; + finally + source.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'HentaiCafe'; + RootURL := 'https://hentai.cafe'; + SortedList := True; + FavoriteAvailable := False; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 5efefd28e..0d5a0dbe8 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -18,4 +18,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From 13b1ab9822918206efd9de3f0cacf5f99871169f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 08:23:19 +0800 Subject: [PATCH 0652/2794] small fix, 1 based index --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index b540a50e0..3d1d17046 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -239,7 +239,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; v := query.XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); if v.Count > 0 then begin genres := ''; - for i := 0 to v.Count do AddCommaString(genres, v.get(i).toString); + for i := 1 to v.Count do AddCommaString(genres, v.get(i).toString); end; if OptionBatotoShowAllLang then From 7810990c76a6e26593bde8e6be48f289448cd751 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 09:09:02 +0800 Subject: [PATCH 0653/2794] added manga-tr close #129 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaTr.pas | 169 ++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaTr.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 89df29565..a2a2691c6 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -15,4 +15,5 @@ uses MangaHere, EightMuses, HitomiLa, - HentaiCafe; + HentaiCafe, + MangaTr; diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas new file mode 100644 index 000000000..eacfddaac --- /dev/null +++ b/baseunits/modules/MangaTr.pas @@ -0,0 +1,169 @@ +unit MangaTr; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + +implementation + +var + mangatrcookie: String = ''; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list.html') then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//span[starts-with(@class, "manga")]//a') do + begin + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.mangaInfo.website := Module.Website; + if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + with MangaInfo.mangaInfo, query do begin + coverLink := XPathString('//img[@class="thumbnail"]/@src'); + if coverLink <> '' then coverLink := FillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1'); + authors := XPathString('//table[2]/tbody/tr[2]/td[1]'); + artists := XPathString('//table[2]/tbody/tr[2]/td[2]'); + genres := TrimRightChar(Trim(XPathString('//table[2]/tbody/tr[2]/td[3]')), [',']); + summary := XPathString('//div[@class="well"]/p'); + v := XPath('//table[4]/tbody/tr/td/a'); + if v.Count = 0 then v := XPath('//table[3]/tbody/tr/td/a'); + if v.Count > 0 then + for i := 1 to v.Count do begin + chapterLinks.Add(v.get(i).toNode.getAttribute('href')); + chapterName.Add(v.get(i).toString); + end; + end; + finally + query.Free; + end; + end; +end; + +function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; +var + s: String; +begin + Result := False; + if mangatrcookie <> '' then begin + AHTTP.Cookies.Text := mangatrcookie; + if AHTTP.GET(AURL) then begin + s := StreamToString(AHTTP.Document); + if (Pos('class="chapter-content"', s) > 0) or (Pos('class=''chapter-content''', s) > 0) then + Result := True; + end; + end; + if not Result then begin + AHTTP.Reset; + if AHTTP.GET(AURL) then begin + if AHTTP.Cookies.Values['PHPSESSID'] <> '' then begin + mangatrcookie := AHTTP.GetCookies; + AHTTP.Reset; + AHTTP.Headers.Values['Referer'] := ' ' + AURL; + Result := AHTTP.GET(AURL); + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + for v in query.XPath('//div[@class="chapter-content"]/select[2]/option') do + if StrToIntDef(v.toString, 0) > 0 then + PageContainerLinks.Add(v.toNode.getAttribute('value')); + PageNumber := PageContainerLinks.Count; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + Headers.Values['Referer'] := ' ' + AURL; + if DownloadThread.workCounter > PageContainerLinks.Count then Exit; + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, PageContainerLinks[DownloadThread.workCounter])) then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@class="chapter-content"]//img/@src'); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Manga-Tr'; + RootURL := 'http://manga-tr.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 0d5a0dbe8..52f2f685a 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,6 +16,6 @@ Raw=MangaMint Russian=NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom -Turkish=MangaFrame,MangaOku,MangaVadisi +Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From b7ef3a97d5ad1a250565cde3e52b58abbf54ccfb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 09:39:38 +0800 Subject: [PATCH 0654/2794] fill known mangainfo properties, fix, empty link on downloadinfo --- baseunits/uData.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 27c289620..6795efa11 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2720,6 +2720,9 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; //load User-Agent from INIAdvanced AdvanceLoadHTTPConfig(FHTTP, website); + mangaInfo.website := website; + if mangaInfo.url = '' then mangaInfo.url := URL; + if mangaInfo.link = '' then mangaInfo.link := URL; mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; mangaInfo.chapterName.Clear; From c391f423b3bf1f605605086384746ab622d36d00 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 09:56:24 +0800 Subject: [PATCH 0655/2794] fix mangainfo.url --- baseunits/uData.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 6795efa11..4f1a129cc 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2721,7 +2721,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; AdvanceLoadHTTPConfig(FHTTP, website); mangaInfo.website := website; - if mangaInfo.url = '' then mangaInfo.url := URL; if mangaInfo.link = '' then mangaInfo.link := URL; mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; @@ -2730,14 +2729,16 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if ModuleId < 0 then ModuleId := Modules.LocateModule(website); - if Modules.ModuleAvailable(ModuleId, MMGetInfo) then + if Modules.ModuleAvailable(ModuleId, MMGetInfo) then begin + mangaInfo.url := FillHost(Modules.Module[ModuleId].RootURL, URL); Result := Modules.GetInfo(Self, URL, Reconnect, ModuleId) + end else begin WebsiteID := GetMangaSiteID(website); if WebsiteID > High(WebsiteRoots) then Exit(INFORMATION_NOT_FOUND); - + mangaInfo.url := FillMangaSiteHost(WebsiteID, URL); Source := TStringList.Create; if website = WebsiteRoots[ANIMEA_ID, 0] then Result := GetAnimeAInfoFromURL From a75ceb65978ef9ba2a233afd19fbd28e77eb3bbb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 10:32:29 +0800 Subject: [PATCH 0656/2794] fix getmangasitename causing last id unrecognized fix #134 --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2af45ba58..cd49f3950 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1229,7 +1229,7 @@ function GetMangaSiteID(const Name: String): Integer; function GetMangaSiteName(const ID: Cardinal): String; begin - if ID >= High(WebsiteRoots) then Exit(''); + if ID > High(WebsiteRoots) then Exit(''); Result := WebsiteRoots[ID, 0]; end; From cb1811d59ad6c89962f8457a3a740dd22342e716 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 11:46:50 +0800 Subject: [PATCH 0657/2794] don't modify image url --- baseunits/uDownloadsManager.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4e66088d5..8bd10fb28 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1174,8 +1174,8 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; if manager.container.MangaSiteID = SENMANGARAW_ID then Result := GetSenMangaRAWImageURL; - TURL := DecodeURL(TURL); //decode first to avoid double encoded - TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); + //TURL := DecodeURL(TURL); //decode first to avoid double encoded + //TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then Result := Modules.DownloadImage( From 02ea76e6046afec39b5327176eb7ac9f373fb5a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 11:47:11 +0800 Subject: [PATCH 0658/2794] fix madokami image url --- baseunits/includes/Madokami/chapter_page_number.inc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/includes/Madokami/chapter_page_number.inc b/baseunits/includes/Madokami/chapter_page_number.inc index b93fef5ff..0f47a598f 100644 --- a/baseunits/includes/Madokami/chapter_page_number.inc +++ b/baseunits/includes/Madokami/chapter_page_number.inc @@ -29,6 +29,7 @@ if (datapath_ <> '') and (datafiles_ <> '') then begin + datapath_ := EncodeURLElement(CommonStringFilter(datapath_)); datafiles_ := Trim(TrimChar(datafiles_, ['[', ']'])); datafiles_ := StringReplace(datafiles_, '"', '"', [rfIgnoreCase, rfReplaceAll]); datafiles_ := StringReplace(datafiles_, '\', '', [rfReplaceAll]); @@ -38,8 +39,8 @@ PageLinks.DelimitedText := datafiles_; if PageLinks.Count > 0 then for i := 0 to PageLinks.Count-1 do - PageLinks[i] := EncodeURL(WebsiteRoots[MADOKAMI_ID, 1] + '/reader/image?path=' + - datapath_ + '&file=' + PageLinks[i]); + PageLinks[i] := WebsiteRoots[MADOKAMI_ID, 1] + '/reader/image?path=' + + datapath_ + '&file=' + EncodeURLElement(PageLinks[i]); end; end; end; From d77090e9d8e6e224a30ecdd703d8b92827b591cc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 11:58:48 +0800 Subject: [PATCH 0659/2794] udata, cleanup --- baseunits/uData.pas | 432 ++++++++++++++++++++++---------------------- 1 file changed, 216 insertions(+), 216 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 4f1a129cc..02a0ad6d8 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2023,136 +2023,136 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; begin WebsiteID := GetMangaSiteID(website); Source := TStringList.Create; - if website = WebsiteRoots[ANIMEA_ID, 0] then + if WebsiteID = ANIMEA_ID then Result := GetAnimeADirectoryPageNumber else - if website = WebsiteRoots[KISSMANGA_ID, 0] then + if WebsiteID = KISSMANGA_ID then Result := GetKissMangaDirectoryPageNumber else - if website = WebsiteRoots[MANGA24H_ID, 0] then + if WebsiteID = MANGA24H_ID then Result := GetManga24hDirectoryPageNumber else - if website = WebsiteRoots[VNSHARING_ID, 0] then + if WebsiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if website = WebsiteRoots[HENTAI2READ_ID, 0] then + if WebsiteID = HENTAI2READ_ID then Result := GetHentai2ReadDirectoryPageNumber else - if website = WebsiteRoots[FAKKU_ID, 0] then + if WebsiteID = FAKKU_ID then Result := GetFakkuDirectoryPageNumber else - if website = WebsiteRoots[MANGAPARK_ID, 0] then + if WebsiteID = MANGAPARK_ID then Result := GetMangaParkDirectoryPageNumber else - //if website = WebsiteRoots[MANGATRADERS_ID, 0] then + //if WebsiteID = MANGATRADERS_ID then // Result := GetMangaTradersDirectoryPageNumber //else - if website = WebsiteRoots[MANGAGO_ID, 0] then + if WebsiteID = MANGAGO_ID then Result := GetMangaGoDirectoryPageNumber else - if website = WebsiteRoots[MANGAEDEN_ID, 0] then + if WebsiteID = MANGAEDEN_ID then Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[MANGAEDEN_ID, 1]) else - if website = WebsiteRoots[PERVEDEN_ID, 0] then + if WebsiteID = PERVEDEN_ID then Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[PERVEDEN_ID, 1]) else - if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then + if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenDirectoryPageNumber else - if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then + if WebsiteID = REDHAWKSCANS_ID then Result := GetRedHawkScansDirectoryPageNumber else - if website = WebsiteRoots[S2SCAN_ID, 0] then + if WebsiteID = S2SCAN_ID then Result := GetS2ScanDirectoryPageNumber else - if website = WebsiteRoots[SENMANGA_ID, 0] then + if WebsiteID = SENMANGA_ID then Result := GetSenMangaDirectoryPageNumber else - if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then + if WebsiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLigneDirectoryPageNumber else - if website = WebsiteRoots[MANGAAE_ID, 0] then + if WebsiteID = MANGAAE_ID then Result := GetMangaAeDirectoryPageNumber else - if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then + if WebsiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasDirectoryPageNumber else - if website = WebsiteRoots[DM5_ID, 0] then + if WebsiteID = DM5_ID then Result := GetDM5DirectoryPageNumber else - if website = WebsiteRoots[PURURIN_ID, 0] then + if WebsiteID = PURURIN_ID then Result := GetPururinDirectoryPageNumber else - if (website = WebsiteRoots[NINEMANGA_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then + if (WebsiteID = NINEMANGA_ID) or + (WebsiteID = NINEMANGA_ES_ID) or + (WebsiteID = NINEMANGA_CN_ID) or + (WebsiteID = NINEMANGA_RU_ID) or + (WebsiteID = NINEMANGA_DE_ID) or + (WebsiteID = NINEMANGA_IT_ID) or + (WebsiteID = NINEMANGA_BR_ID) then Result := GetNineMangaDirectoryPageNumber else - if website = WebsiteRoots[JAPANSHIN_ID, 0] then + if WebsiteID = JAPANSHIN_ID then Result := GetJapanShinDirectoryPageNumber else - if website = WebsiteRoots[MANGACOW_ID, 0] then + if WebsiteID = MANGACOW_ID then Result := GetMangaCowDirectoryPageNumber else - if website = WebsiteRoots[ONEMANGA_ID, 0] then + if WebsiteID = ONEMANGA_ID then Result := GetOneMangaDirectoryPageNumber else - if website = WebsiteRoots[MANGATOWN_ID, 0] then + if WebsiteID = MANGATOWN_ID then Result := GetMangaTownDirectoryPageNumber else - if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then + if WebsiteID = MYREADINGMANGAINFO_ID then Result := GetMyReadingMangaInfoDirectoryPageNumber else - if website = WebsiteRoots[IKOMIK_ID, 0] then + if WebsiteID = IKOMIK_ID then Result := GetIKomikDirectoryPageNumber else - if website = WebsiteRoots[NHENTAI_ID, 0] then + if WebsiteID = NHENTAI_ID then Result := GetNHentaiDirectoryPageNumber else if website = GetMangaSiteName(UNIONMANGAS_ID) then Result := GetUnionMangasDirectoryPageNumber else - if website = WebsiteRoots[MANGAMINT_ID, 0] then + if WebsiteID = MANGAMINT_ID then Result := GetMangaMintDirectoryPageNumber else - if website = WebsiteRoots[HAKIHOME_ID, 0] then + if WebsiteID = HAKIHOME_ID then Result := GetHakiHomeDirectoryPageNumber else - if website = WebsiteRoots[MANGAFRAME_ID, 0] then + if WebsiteID = MANGAFRAME_ID then Result := GetMangaFrameDirectoryPageNumber else - if website = WebsiteRoots[MANGAHOST_ID, 0] then + if WebsiteID = MANGAHOST_ID then Result := GetMangaHostDirectoryPageNumber else - if (website = WebsiteRoots[PORNCOMIX_ID, 0]) or - (website = WebsiteRoots[XXCOMICS_ID, 0]) or - (website = WebsiteRoots[XXCOMICSMT_ID, 0]) or - (website = WebsiteRoots[XXCOMICS3D_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXRE_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXIC_ID, 0]) or - (website = WebsiteRoots[PORNXXXCOMICS_ID, 0]) then + if (WebsiteID = PORNCOMIX_ID) or + (WebsiteID = XXCOMICS_ID) or + (WebsiteID = XXCOMICSMT_ID) or + (WebsiteID = XXCOMICS3D_ID) or + (WebsiteID = PORNCOMIXRE_ID) or + (WebsiteID = PORNCOMIXIC_ID) or + (WebsiteID = PORNXXXCOMICS_ID) then Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(website)) else - if website = WebsiteRoots[MANGASEE_ID, 0] then + if WebsiteID = MANGASEE_ID then Result := GetMangaSeeDirectoryPageNumber else - if website = WebsiteRoots[ACADEMYVN_ID, 0] then + if WebsiteID = ACADEMYVN_ID then Result := GetAcademyVNDirectoryPageNumber else - if website = WebsiteRoots[MANGAAT_ID, 0] then + if WebsiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber else - if website = WebsiteRoots[READMANGATODAY_ID, 0] then + if WebsiteID = READMANGATODAY_ID then Result := GetReadMangaTodayDirectoryPageNumber else - if website = WebsiteRoots[DYNASTYSCANS_ID, 0] then + if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansDirectoryPageNumber else - if website = WebsiteRoots[MADOKAMI_ID, 0] then + if WebsiteID = MADOKAMI_ID then Result := GetMadokamiDirectoryPageNumber else begin @@ -2326,229 +2326,229 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; begin WebsiteID := GetMangaSiteID(website); Source := TStringList.Create; - if website = WebsiteRoots[ANIMEA_ID, 0] then + if WebsiteID = ANIMEA_ID then Result := AnimeAGetNamesAndLinks else - if website = WebsiteRoots[MANGAINN_ID, 0] then + if WebsiteID = MANGAINN_ID then Result := MangaInnGetNamesAndLinks else - if website = WebsiteRoots[KISSMANGA_ID, 0] then + if WebsiteID = KISSMANGA_ID then Result := KissMangaGetNamesAndLinks else - if website = WebsiteRoots[MANGA24H_ID, 0] then + if WebsiteID = MANGA24H_ID then Result := Manga24hGetNamesAndLinks else - if website = WebsiteRoots[VNSHARING_ID, 0] then + if WebsiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else - if website = WebsiteRoots[HENTAI2READ_ID, 0] then + if WebsiteID = HENTAI2READ_ID then Result := Hentai2ReadGetNamesAndLinks else - if website = WebsiteRoots[FAKKU_ID, 0] then + if WebsiteID = FAKKU_ID then Result := FakkuGetNamesAndLinks else - if website = WebsiteRoots[MANGAPARK_ID, 0] then + if WebsiteID = MANGAPARK_ID then Result := MangaParkGetNamesAndLinks else - if website = WebsiteRoots[MANGATRADERS_ID, 0] then + if WebsiteID = MANGATRADERS_ID then Result := MangaTradersGetNamesAndLinks else - if website = WebsiteRoots[STARKANA_ID, 0] then + if WebsiteID = STARKANA_ID then Result := StarkanaGetNamesAndLinks else - if website = WebsiteRoots[EATMANGA_ID, 0] then + if WebsiteID = EATMANGA_ID then Result := EatMangaGetNamesAndLinks else - if website = WebsiteRoots[MANGAGO_ID, 0] then + if WebsiteID = MANGAGO_ID then Result := MangaGoGetNamesAndLinks else - if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then + if WebsiteID = REDHAWKSCANS_ID then Result := RedHawkScansGetNamesAndLinks else - if website = WebsiteRoots[S2SCAN_ID, 0] then + if WebsiteID = S2SCAN_ID then Result := S2ScanGetNamesAndLinks else - if website = WebsiteRoots[EGSCANS_ID, 0] then + if WebsiteID = EGSCANS_ID then Result := EGScansGetNamesAndLinks else - if website = WebsiteRoots[MANGAEDEN_ID, 0] then + if WebsiteID = MANGAEDEN_ID then Result := MangaEdenGetNamesAndLinks(WebsiteRoots[MANGAEDEN_ID, 1]) else - if website = WebsiteRoots[PERVEDEN_ID, 0] then + if WebsiteID = PERVEDEN_ID then Result := MangaEdenGetNamesAndLinks(WebsiteRoots[PERVEDEN_ID, 1]) else - if website = WebsiteRoots[MEINMANGA_ID, 0] then + if WebsiteID = MEINMANGA_ID then Result := MeinMangaGetNamesAndLinks else - if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then + if WebsiteID = BLOGTRUYEN_ID then Result := BlogTruyenGetNamesAndLinks else - if website = WebsiteRoots[TRUYENTRANHTUAN_ID, 0] then + if WebsiteID = TRUYENTRANHTUAN_ID then Result := TruyenTranhTuanGetNamesAndLinks else - if website = WebsiteRoots[SUBMANGA_ID, 0] then + if WebsiteID = SUBMANGA_ID then Result := SubMangaGetNamesAndLinks else - if website = WebsiteRoots[ESMANGAHERE_ID, 0] then + if WebsiteID = ESMANGAHERE_ID then Result := EsMangaHereGetNamesAndLinks else - if website = WebsiteRoots[ANIMEEXTREMIST_ID, 0] then + if WebsiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else - if website = WebsiteRoots[KOMIKID_ID, 0] then + if WebsiteID = KOMIKID_ID then Result := KomikidGetNamesAndLinks else - if website = WebsiteRoots[MABUNS_ID, 0] then + if WebsiteID = MABUNS_ID then Result := MabunsGetNamesAndLinks else - if website = WebsiteRoots[MANGAESTA_ID, 0] then + if WebsiteID = MANGAESTA_ID then Result := MangaEstaGetNamesAndLinks else - if website = WebsiteRoots[PURURIN_ID, 0] then + if WebsiteID = PURURIN_ID then Result := PururinGetNamesAndLinks else - if website = WebsiteRoots[HUGEMANGA_ID, 0] then + if WebsiteID = HUGEMANGA_ID then Result := HugeMangaGetNamesAndLinks else - if website = WebsiteRoots[ANIMESTORY_ID, 0] then + if WebsiteID = ANIMESTORY_ID then Result := AnimeStoryGetNamesAndLinks else - if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then + if WebsiteID = LECTUREENLIGNE_ID then Result := LectureEnLigneGetNamesAndLinks else - if website = WebsiteRoots[SCANMANGA_ID, 0] then + if WebsiteID = SCANMANGA_ID then Result := ScanMangaGetNamesAndLinks else - if website = WebsiteRoots[MANGAAR_ID, 0] then + if WebsiteID = MANGAAR_ID then Result := MangaArGetNamesAndLinks else - if website = WebsiteRoots[MANGAAE_ID, 0] then + if WebsiteID = MANGAAE_ID then Result := MangaAeGetNamesAndLinks else - if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then + if WebsiteID = CENTRALDEMANGAS_ID then Result := CentralDeMangasGetNamesAndLinks else - if website = WebsiteRoots[IMANHUA_ID, 0] then + if WebsiteID = IMANHUA_ID then Result := imanhuaGetNamesAndLinks else - if website = WebsiteRoots[TURKCRAFT_ID, 0] then + if WebsiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else - if website = WebsiteRoots[MANGAVADISI_ID, 0] then + if WebsiteID = MANGAVADISI_ID then Result := MangaVadisiGetNamesAndLinks else - if website = WebsiteRoots[MANGAFRAME_ID, 0] then + if WebsiteID = MANGAFRAME_ID then Result := MangaFrameNamesAndLinks else - if website = WebsiteRoots[MANGACOW_ID, 0] then + if WebsiteID = MANGACOW_ID then Result := MangaCowGetNamesAndLinks else - if website = WebsiteRoots[SENMANGA_ID, 0] then + if WebsiteID = SENMANGA_ID then Result := SenMangaGetNamesAndLinks else - if website = WebsiteRoots[KIVMANGA_ID, 0] then + if WebsiteID = KIVMANGA_ID then Result := KivmangaGetNamesAndLinks else - if website = WebsiteRoots[MANGASPROJECT_ID, 0] then + if WebsiteID = MANGASPROJECT_ID then Result := MangasPROJECTGetNamesAndLinks else - if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then + if WebsiteID = MANGAREADER_POR_ID then Result := MangaREADER_PORGetNamesAndLinks else - if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then + if WebsiteID = MANGASTREAMTO_ID then Result := MangaStreamToGetNamesAndLinks else - if (website = WebsiteRoots[NINEMANGA_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then + if (WebsiteID = NINEMANGA_ID) or + (WebsiteID = NINEMANGA_ES_ID) or + (WebsiteID = NINEMANGA_CN_ID) or + (WebsiteID = NINEMANGA_RU_ID) or + (WebsiteID = NINEMANGA_DE_ID) or + (WebsiteID = NINEMANGA_IT_ID) or + (WebsiteID = NINEMANGA_BR_ID) then Result := NineMangaGetNamesAndLinks else - if website = WebsiteRoots[JAPANSHIN_ID, 0] then + if WebsiteID = JAPANSHIN_ID then Result := JapanShinGetNamesAndLinks else - if website = WebsiteRoots[JAPSCAN_ID, 0] then + if WebsiteID = JAPSCAN_ID then Result := JapscanNamesAndLinks else - if website = WebsiteRoots[CENTRUMMANGI_PL_ID, 0] then + if WebsiteID = CENTRUMMANGI_PL_ID then Result := CentrumMangi_PLGetNamesAndLinks else - if website = WebsiteRoots[MANGALIB_PL_ID, 0] then + if WebsiteID = MANGALIB_PL_ID then Result := MangaLib_PLGetNamesAndLinks else - if website = WebsiteRoots[ONEMANGA_ID, 0] then + if WebsiteID = ONEMANGA_ID then Result := OneMangaGetNamesAndLinks else - if website = WebsiteRoots[MANGATOWN_ID, 0] then + if WebsiteID = MANGATOWN_ID then Result := MangaTownGetNamesAndLinks else - if website = WebsiteRoots[MANGAOKU_ID, 0] then + if WebsiteID = MANGAOKU_ID then Result := MangaOkuGetNamesAndLinks else - if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then + if WebsiteID = MYREADINGMANGAINFO_ID then Result := MyReadingMangaInfoNamesAndLinks else - if website = WebsiteRoots[IKOMIK_ID, 0] then + if WebsiteID = IKOMIK_ID then Result := IKomikNamesAndLinks else - if website = WebsiteRoots[NHENTAI_ID, 0] then + if WebsiteID = NHENTAI_ID then Result := NHentaiNamesAndLinks else - if website = WebsiteRoots[UNIONMANGAS_ID, 0] then + if WebsiteID = UNIONMANGAS_ID then Result := UnionMangasNamesAndLinks else - if website = WebsiteRoots[MANGAMINT_ID, 0] then + if WebsiteID = MANGAMINT_ID then Result := MangaMintGetNamesAndLinks else - if website = WebsiteRoots[UNIXMANGA_ID, 0] then + if WebsiteID = UNIXMANGA_ID then Result := UnixMangaNamesAndLinks else - if website = WebsiteRoots[HAKIHOME_ID, 0] then + if WebsiteID = HAKIHOME_ID then Result := HakiHomeNamesAndLinks else - if website = WebsiteRoots[EXTREMEMANGAS_ID, 0] then + if WebsiteID = EXTREMEMANGAS_ID then Result := ExtremeMangasNamesAndLinks else - if website = WebsiteRoots[MANGAHOST_ID, 0] then + if WebsiteID = MANGAHOST_ID then Result := MangaHostGetNamesAndLinks else - if (website = WebsiteRoots[PORNCOMIX_ID, 0]) or - (website = WebsiteRoots[XXCOMICS_ID, 0]) or - (website = WebsiteRoots[XXCOMICSMT_ID, 0]) or - (website = WebsiteRoots[XXCOMICS3D_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXRE_ID, 0]) or - (website = WebsiteRoots[PORNCOMIXIC_ID, 0]) or - (website = WebsiteRoots[PORNXXXCOMICS_ID, 0]) then + if (WebsiteID = PORNCOMIX_ID) or + (WebsiteID = XXCOMICS_ID) or + (WebsiteID = XXCOMICSMT_ID) or + (WebsiteID = XXCOMICS3D_ID) or + (WebsiteID = PORNCOMIXRE_ID) or + (WebsiteID = PORNCOMIXIC_ID) or + (WebsiteID = PORNXXXCOMICS_ID) then Result := PornComixGetNamesAndLinks(GetMangaSiteID(website)) else - if website = WebsiteRoots[MANGASEE_ID, 0] then + if WebsiteID = MANGASEE_ID then Result := MangaSeeGetNamesAndLinks else - if website = WebsiteRoots[MANGAKU_ID, 0] then + if WebsiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks else - if website = WebsiteRoots[ACADEMYVN_ID, 0] then + if WebsiteID = ACADEMYVN_ID then Result := AcademyVNGetNamesAndLinks else - if website = WebsiteRoots[MANGAAT_ID, 0] then + if WebsiteID = MANGAAT_ID then Result := MangaAtGetNamesAndLinks else - if website = WebsiteRoots[SENMANGARAW_ID, 0] then + if WebsiteID = SENMANGARAW_ID then Result := SenMangaRAWGetNamesAndLinks else - if website = WebsiteRoots[READMANGATODAY_ID, 0] then + if WebsiteID = READMANGATODAY_ID then Result := ReadMangaTodayGetNamesAndLinks else - if website = WebsiteRoots[LONEMANGA_ID, 0] then + if WebsiteID = LONEMANGA_ID then Result := LoneMangaGetNamesAndLinks else - if website = WebsiteRoots[DYNASTYSCANS_ID, 0] then + if WebsiteID = DYNASTYSCANS_ID then Result := DynastyScansGetNamesAndLinks else - if website = WebsiteRoots[MADOKAMI_ID, 0] then + if WebsiteID = MADOKAMI_ID then Result := MadokamiGetNamesAndLinks else begin @@ -2740,226 +2740,226 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; Exit(INFORMATION_NOT_FOUND); mangaInfo.url := FillMangaSiteHost(WebsiteID, URL); Source := TStringList.Create; - if website = WebsiteRoots[ANIMEA_ID, 0] then + if WebsiteID = ANIMEA_ID then Result := GetAnimeAInfoFromURL else - if website = WebsiteRoots[MANGAINN_ID, 0] then + if WebsiteID = MANGAINN_ID then Result := GetMangaInnInfoFromURL else - if website = WebsiteRoots[KISSMANGA_ID, 0] then + if WebsiteID = KISSMANGA_ID then Result := GetKissMangaInfoFromURL else - if website = WebsiteRoots[MANGA24H_ID, 0] then + if WebsiteID = MANGA24H_ID then Result := GetManga24hInfoFromURL else - if website = WebsiteRoots[VNSHARING_ID, 0] then + if WebsiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else - if website = WebsiteRoots[HENTAI2READ_ID, 0] then + if WebsiteID = HENTAI2READ_ID then Result := GetHentai2ReadInfoFromURL else - if website = WebsiteRoots[FAKKU_ID, 0] then + if WebsiteID = FAKKU_ID then Result := GetFakkuInfoFromURL else - if website = WebsiteRoots[MANGAPARK_ID, 0] then + if WebsiteID = MANGAPARK_ID then Result := GetMangaParkInfoFromURL else - if website = WebsiteRoots[MANGATRADERS_ID, 0] then + if WebsiteID = MANGATRADERS_ID then Result := GetMangaTradersInfoFromURL else - if website = WebsiteRoots[STARKANA_ID, 0] then + if WebsiteID = STARKANA_ID then Result := GetStarkanaInfoFromURL else - if website = WebsiteRoots[EATMANGA_ID, 0] then + if WebsiteID = EATMANGA_ID then Result := GetEatMangaInfoFromURL else - if website = WebsiteRoots[MANGAGO_ID, 0] then + if WebsiteID = MANGAGO_ID then Result := GetMangaGoInfoFromURL else - if website = WebsiteRoots[REDHAWKSCANS_ID, 0] then + if WebsiteID = REDHAWKSCANS_ID then Result := GetRedHawkScansInfoFromURL else - if website = WebsiteRoots[S2SCAN_ID, 0] then + if WebsiteID = S2SCAN_ID then Result := GetS2scanInfoFromURL else - if website = WebsiteRoots[EGSCANS_ID, 0] then + if WebsiteID = EGSCANS_ID then Result := GetEGScansInfoFromURL else - if website = WebsiteRoots[TRUYENTRANHTUAN_ID, 0] then + if WebsiteID = TRUYENTRANHTUAN_ID then Result := GetTruyenTranhTuanInfoFromURL else - if website = WebsiteRoots[MANGAEDEN_ID, 0] then + if WebsiteID = MANGAEDEN_ID then Result := GetMangaEdenInfoFromURL(WebsiteRoots[MANGAEDEN_ID, 1]) else - if website = WebsiteRoots[PERVEDEN_ID, 0] then + if WebsiteID = PERVEDEN_ID then Result := GetMangaEdenInfoFromURL(WebsiteRoots[PERVEDEN_ID, 1]) else - if website = WebsiteRoots[MEINMANGA_ID, 0] then + if WebsiteID = MEINMANGA_ID then Result := GetMeinMangaInfoFromURL else - if website = WebsiteRoots[SUBMANGA_ID, 0] then + if WebsiteID = SUBMANGA_ID then Result := GetSubMangaInfoFromURL else - if website = WebsiteRoots[ESMANGAHERE_ID, 0] then + if WebsiteID = ESMANGAHERE_ID then Result := GetEsMangaHereInfoFromURL else - if website = WebsiteRoots[ANIMEEXTREMIST_ID, 0] then + if WebsiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else - if website = WebsiteRoots[KOMIKID_ID, 0] then + if WebsiteID = KOMIKID_ID then Result := GetKomikidInfoFromURL else - if website = WebsiteRoots[MABUNS_ID, 0] then + if WebsiteID = MABUNS_ID then Result := GetMabunsInfoFromURL else - if website = WebsiteRoots[MANGAESTA_ID, 0] then + if WebsiteID = MANGAESTA_ID then Result := GetMangaEstaInfoFromURL else - if website = WebsiteRoots[PURURIN_ID, 0] then + if WebsiteID = PURURIN_ID then Result := GetPururinInfoFromURL else - if website = WebsiteRoots[HUGEMANGA_ID, 0] then + if WebsiteID = HUGEMANGA_ID then Result := GetHugeMangaInfoFromURL else - if website = WebsiteRoots[ANIMESTORY_ID, 0] then + if WebsiteID = ANIMESTORY_ID then Result := GetAnimeStoryInfoFromURL else - if website = WebsiteRoots[LECTUREENLIGNE_ID, 0] then + if WebsiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLigneInfoFromURL else - if website = WebsiteRoots[SCANMANGA_ID, 0] then + if WebsiteID = SCANMANGA_ID then Result := GetScanMangaInfoFromURL else - if website = WebsiteRoots[TURKCRAFT_ID, 0] then + if WebsiteID = TURKCRAFT_ID then Result := GetTurkcraftInfoFromURL else - if website = WebsiteRoots[MANGAFRAME_ID, 0] then + if WebsiteID = MANGAFRAME_ID then Result := GetMangaframeInfoFromURL else - if website = WebsiteRoots[MANGAVADISI_ID, 0] then + if WebsiteID = MANGAVADISI_ID then Result := GetMangaVadisiInfoFromURL else - if website = WebsiteRoots[MANGAAR_ID, 0] then + if WebsiteID = MANGAAR_ID then Result := GetMangaArInfoFromURL else - if website = WebsiteRoots[MANGAAE_ID, 0] then + if WebsiteID = MANGAAE_ID then Result := GetMangaAeInfoFromURL else - if website = WebsiteRoots[CENTRALDEMANGAS_ID, 0] then + if WebsiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else - if website = WebsiteRoots[MANGACOW_ID, 0] then + if WebsiteID = MANGACOW_ID then Result := GetMangaCowInfoFromURL else - if website = WebsiteRoots[SENMANGA_ID, 0] then + if WebsiteID = SENMANGA_ID then Result := GetSenMangaInfoFromURL else - if website = WebsiteRoots[BLOGTRUYEN_ID, 0] then + if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenInfoFromURL else - if website = WebsiteRoots[KIVMANGA_ID, 0] then + if WebsiteID = KIVMANGA_ID then Result := GetKivmangaInfoFromURL else - if website = WebsiteRoots[MANGASPROJECT_ID, 0] then + if WebsiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTInfoFromURL else - if website = WebsiteRoots[MANGAREADER_POR_ID, 0] then + if WebsiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORInfoFromURL else - if website = WebsiteRoots[MANGASTREAMTO_ID, 0] then + if WebsiteID = MANGASTREAMTO_ID then Result := GetMangaStreamToInfoFromURL else - if (website = WebsiteRoots[NINEMANGA_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_ES_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_CN_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_RU_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_DE_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_IT_ID, 0]) or - (website = WebsiteRoots[NINEMANGA_BR_ID, 0]) then + if (WebsiteID = NINEMANGA_ID) or + (WebsiteID = NINEMANGA_ES_ID) or + (WebsiteID = NINEMANGA_CN_ID) or + (WebsiteID = NINEMANGA_RU_ID) or + (WebsiteID = NINEMANGA_DE_ID) or + (WebsiteID = NINEMANGA_IT_ID) or + (WebsiteID = NINEMANGA_BR_ID) then Result := GetNineMangaInfoFromURL else - if website = WebsiteRoots[JAPANSHIN_ID, 0] then + if WebsiteID = JAPANSHIN_ID then Result := GetJapanShinInfoFromURL else - if website = WebsiteRoots[JAPSCAN_ID, 0] then + if WebsiteID = JAPSCAN_ID then Result := GetJapscanInfoFromURL else - if website = WebsiteRoots[CENTRUMMANGI_PL_ID, 0] then + if WebsiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLInfoFromURL else - if website = WebsiteRoots[MANGALIB_PL_ID, 0] then + if WebsiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLInfoFromURL else - if website = WebsiteRoots[ONEMANGA_ID, 0] then + if WebsiteID = ONEMANGA_ID then Result := GetOneMangaInfoFromURL else - if website = WebsiteRoots[MANGATOWN_ID, 0] then + if WebsiteID = MANGATOWN_ID then Result := GetMangaTownInfoFromURL else - if website = WebsiteRoots[MANGAOKU_ID, 0] then + if WebsiteID = MANGAOKU_ID then Result := GetMangaOkuInfoFromURL else - if website = WebsiteRoots[MYREADINGMANGAINFO_ID, 0] then + if WebsiteID = MYREADINGMANGAINFO_ID then Result := GetMyReadingMangaInfoInfoFromURL else - if website = WebsiteRoots[IKOMIK_ID, 0] then + if WebsiteID = IKOMIK_ID then Result := GetIKomikInfoFromURL else - if website = WebsiteRoots[NHENTAI_ID, 0] then + if WebsiteID = NHENTAI_ID then Result := GetNHentaiInfoFromURL else - if website = WebsiteRoots[UNIONMANGAS_ID, 0] then + if WebsiteID = UNIONMANGAS_ID then Result := GetUnionMangasInfoFromURL else - if website = WebsiteRoots[MANGAMINT_ID, 0] then + if WebsiteID = MANGAMINT_ID then Result := GetMangaMintInfoFromURL else - if website = WebsiteRoots[UNIXMANGA_ID, 0] then + if WebsiteID = UNIXMANGA_ID then Result := GetUnixMangaInfoFromURL else - if website = WebsiteRoots[HAKIHOME_ID, 0] then + if WebsiteID = HAKIHOME_ID then Result := GetHakiHomeInfoFromURL else - if website = WebsiteRoots[EXTREMEMANGAS_ID, 0] then + if WebsiteID = EXTREMEMANGAS_ID then Result := GetExtremeMangasInfoFromURL else - if website = GetMangaSiteName(MANGAHOST_ID) then + if WebsiteID = MANGAHOST_ID then Result := GetMangaHostInfoFromURL else - if (website = GetMangaSiteName(PORNCOMIX_ID)) or - (website = GetMangaSiteName(XXCOMICS_ID)) or - (website = GetMangaSiteName(XXCOMICSMT_ID)) or - (website = GetMangaSiteName(XXCOMICS3D_ID)) or - (website = GetMangaSiteName(PORNCOMIXRE_ID)) or - (website = GetMangaSiteName(PORNCOMIXIC_ID)) or - (website = GetMangaSiteName(PORNXXXCOMICS_ID)) then + if (WebsiteID = PORNCOMIX_ID) or + (WebsiteID = XXCOMICS_ID) or + (WebsiteID = XXCOMICSMT_ID) or + (WebsiteID = XXCOMICS3D_ID) or + (WebsiteID = PORNCOMIXRE_ID) or + (WebsiteID = PORNCOMIXIC_ID) or + (WebsiteID = PORNXXXCOMICS_ID) then Result := GetPornComixInfoFromURL(GetMangaSiteID(website)) else - if website = GetMangaSiteName(MANGASEE_ID) then + if WebsiteID = MANGASEE_ID then Result := GetMangaSeeInfoFromURL else - if website = GetMangaSiteName(MANGAKU_ID) then + if WebsiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL else - if website = GetMangaSiteName(ACADEMYVN_ID) then + if WebsiteID = ACADEMYVN_ID then Result := GetAcademyVNInfoFromURL else - if website = GetMangaSiteName(MANGAAT_ID) then + if WebsiteID = MANGAAT_ID then Result := GetMangaAtInfoFromURL else - if website = GetMangaSiteName(SENMANGARAW_ID) then + if WebsiteID = SENMANGARAW_ID then Result := GetSenMangaRAWInfoFromURL else - if website = GetMangaSiteName(READMANGATODAY_ID) then + if WebsiteID = READMANGATODAY_ID then Result := GetReadMangaTodayInfoFromURL else - if website = GetMangaSiteName(LONEMANGA_ID) then + if WebsiteID = LONEMANGA_ID then Result := GetLoneMangaInfoFromURL else - if website = GetMangaSiteName(DYNASTYSCANS_ID) then + if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansInfoFromURL else - if website = GetMangaSiteName(MADOKAMI_ID) then + if WebsiteID = MADOKAMI_ID then Result := GetMadokamiInfoFromURL else begin From 440a354be0474f8df7dff93d92f3b10aaf4d8be1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 12:09:28 +0800 Subject: [PATCH 0660/2794] frmmain, keep windows focus on apply button --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1ee99399f..2806eaaf1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3950,6 +3950,7 @@ procedure TMainForm.btOptionApplyClick(Sender: TObject); begin SaveOptions; ApplyOptions; + if not Self.Focused then Self.SetFocus; end; procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); From 2a51ea2628a2cc60e97b2446694086c53323822a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Dec 2015 15:32:24 +0800 Subject: [PATCH 0661/2794] Bump version 0.9.26.0 --- changelog.txt | 9 +++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 78239bb05..c0c30060a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,15 @@ https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.26.0 (23-12-2015) +[*] Batoto: fix login +[*] ExHentai: fix login +[+] Added HitomiLa[H] +[+] Added HentaiCafe[H] +[+] Added Manga-Tr[TR] +[*] Madokami: fix image url +[*] Various changes and bug fixes + 0.9.25.0 (21-12-2015) [+] Added 8Muses[H] (no list, use drop box) [+] Added Account Manager, Options > Accounts diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f965f212b..aa41ede82 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="25"/> + <RevisionNr Value="26"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 7daefa96e..733ee4518 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.25.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.25.0/fmd_0.9.25.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.25.0/fmd_0.9.25.0_Win64.7z +VERSION=0.9.26.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.26.0/fmd_0.9.26.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.26.0/fmd_0.9.26.0_Win64.7z From 6e6c70448e27527e0bc30284ba109f49efbc9f74 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Dec 2015 21:32:43 +0800 Subject: [PATCH 0662/2794] change data url --- changelog.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index c0c30060a..7699394ad 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,8 +2,7 @@ Free Manga Downloader Project page: https://github.com/riderkick/FMD For manga list data check: -https://bintray.com/riderkick/FMD/data/all/#files -https://www.mediafire.com/folder/3ccy2c7g36hp3/Fmd +https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) From 011bba9868f9b75ca133f952b89d5741a1055f70 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 16:12:35 +0800 Subject: [PATCH 0663/2794] add manga fox watermark remover --- baseunits/extras/mangafoxwatermarkremover.pas | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 baseunits/extras/mangafoxwatermarkremover.pas diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas new file mode 100644 index 000000000..c64784d01 --- /dev/null +++ b/baseunits/extras/mangafoxwatermarkremover.pas @@ -0,0 +1,159 @@ +unit mangafoxwatermarkremover; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, ImagingCompare, ImagingExtras, ImagingBinary, + ImagingClasses, ImagingTypes, ImagingCanvases, Imaging, FileUtil, + LazFileUtils; + +function LoadTemplate(const TempDir: String): Integer; +function RemoveWatermark(const AFilename: String): Boolean; +procedure ClearTemplate; + +var + minwhiteborder: Integer = 4; + +implementation + +var + imgtemplate: TDynImageDataArray; + lockproc: TRTLCriticalSection; + +function LoadTemplate(const TempDir: String): Integer; +var + flist: TStringList; + i: Integer; +begin + Result := 0; + if DirectoryExists(TempDir) = False then Exit; + EnterCriticalsection(lockproc); + flist := TStringList.Create; + try + FreeImagesInArray(imgtemplate); + // load all images in template folder + FindAllFiles(flist, CleanAndExpandDirectory(TempDir), '*.*', False); + if flist.Count > 0 then + for i := 0 to flist.Count - 1 do begin + SetLength(imgtemplate, Length(imgtemplate) + 1); + InitImage(imgtemplate[High(imgtemplate)]); + if LoadImageFromFile(flist.Strings[i], imgtemplate[High(imgtemplate)]) then begin + // convert to grayscale and do thresholding + ConvertImage(imgtemplate[High(imgtemplate)], ifGray8); + OtsuThresholding(imgtemplate[High(imgtemplate)], True); + end + else begin + FreeImage(imgtemplate[High(imgtemplate)]); + SetLength(imgtemplate, Length(imgtemplate) - 1); + end; + end; + finally + Result := Length(imgtemplate); + flist.Free; + LeaveCriticalsection(lockproc); + end; +end; + +procedure ClearTemplate; +begin + FreeImagesInArray(imgtemplate); +end; + +function ColorIsWhite(const Color: TColor32Rec): Boolean; +begin + Result := (Color.R = 255) and (Color.G = 255) and (Color.B = 255); +end; + +function RemoveWatermark(const AFilename: String): Boolean; +var + imgbase, imgproc: TImageData; + i, x, y: Integer; + nh, bmi: Integer; + bmv, PSNR, MSE, RMSE, PAE, MAE: single; + invalidborder: Boolean; +begin + Result := False; + if not FileExistsUTF8(AFilename) then Exit; + if Length(imgtemplate) = 0 then Exit; + + EnterCriticalsection(lockproc); + InitImage(imgbase); + InitImage(imgproc); + try + // not supported image file + if not LoadImageFromFile(AFilename, imgbase) then Exit; + + // probably doesn't have watermark / 728px is default mangafox image width + if imgbase.Width <> 728 then Exit; + + bmi := -1; + bmv := 0; + // compare image to all template + for i := Low(imgtemplate) to High(imgtemplate) do + if imgbase.Height > imgtemplate[i].Height then begin + invalidborder := False; + // crop image to match template + NewImage(imgtemplate[i].Width, imgtemplate[i].Height, imgtemplate[i].Format, imgproc); + CopyRect(imgbase, 0, imgbase.Height - imgtemplate[i].Height, imgbase.Width, imgbase.Height - imgtemplate[i].Height, imgproc, 0, 0); + // do thresholding + OtsuThresholding(imgproc, True); + + // check minimal white border + for y := 1 to minwhiteborder do begin + for x := 1 to imgproc.Width do begin + if not ColorIsWhite(GetPixel32(imgproc, x, y)) then begin + invalidborder := True; + Break; + end; + end; + if invalidborder then Break; + end; + + if not invalidborder then begin + // compute error metrics + ComputeErrorMetrics(imgtemplate[i], imgproc, PSNR, MSE, RMSE, PAE, MAE); + if PSNR > bmv then begin + bmi := i; + bmv := PSNR; + end; + end; + FreeImage(imgproc); + end; + + // save cropped image + if bmi > -1 then begin + nh := imgbase.Height - imgtemplate[bmi].Height; + NewImage(imgbase.Width, nh, imgbase.Format, imgproc); + CopyRect(imgbase, 0, 0, imgbase.Width, nh, imgproc, 0, 0); + if DeleteFileUTF8(AFilename) then + Result := SaveImageToFile(AFilename, imgproc); + end; + finally + FreeImage(imgbase); + FreeImage(imgproc); + LeaveCriticalsection(lockproc); + end; +end; + +procedure doInitialize; +begin + InitCriticalSection(lockproc); + Initialize(imgtemplate); +end; + +procedure doFinalize; +begin + FreeImagesInArray(imgtemplate); + DoneCriticalsection(lockproc); +end; + +initialization + doInitialize; + +finalization + doFinalize; + +end. + From f6d4534592d3fcae54b12d0291ca0d1f892c3d95 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 17:07:05 +0800 Subject: [PATCH 0664/2794] baseunit, return savedfilename on saveimage --- baseunits/uBaseUnit.pas | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cd49f3950..790ea4a03 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -655,6 +655,8 @@ interface OptionBatotoShowScanGroup: Boolean = True; OptionBatotoShowAllLang: Boolean = True; + OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; + OptionMangaFoxRemoveWatermark: Boolean = False; OptionHTTPUseGzip: Boolean = True; @@ -961,10 +963,12 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0) // Get url from a bitly url. function GetURLFromBitly(const URL: String): String; // Download an image from url and save it to a specific location. +function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; + const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; inline; + const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); @@ -3154,7 +3158,7 @@ function GetURLFromBitly(const URL: String): String; end; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; - URL: String; const Path, Name, prefix: String; const Reconnect: Integer + URL: String; const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer ): Boolean; // prefix: For example: 000<our prefix>.jpg. var @@ -3410,12 +3414,23 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; Writelog_E('SaveImage.ExtEmpty!' + LineEnding + URL); preTerminate; Result := (fpath <> '') and FileExistsUTF8(fpath); + if Result then SavedFilename := fpath + else SavedFilename := ''; +end; + +function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; + URL: String; const Path, Name, prefix: String; const Reconnect: Integer + ): Boolean; +var + f: String; +begin + Result := SaveImage(AHTTP, mangaSiteID, URL, Path, Name, prefix, f, Reconnect); end; function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name, - prefix: String; const Reconnect: Integer): Boolean; + prefix: String; var SavedFilename: String; const Reconnect: Integer): Boolean; begin - Result := SaveImage(nil, mangaSiteID, URL, Path, Name, prefix, Reconnect); + Result := SaveImage(nil, mangaSiteID, URL, Path, Name, prefix, SavedFilename, Reconnect); end; procedure QuickSortChapters(var chapterList, linkList: TStringList); From d8bd1fc4fc0001b0269fbe461fded18805c7ebc8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 17:07:52 +0800 Subject: [PATCH 0665/2794] downloadmanager, remove watermark after download --- baseunits/uDownloadsManager.pas | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8bd10fb28..a62084561 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface lazutf8classes, LazFileUtils, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, - uFMDThread, uMisc, USimpleLogger, dateutils; + uFMDThread, uMisc, mangafoxwatermarkremover, USimpleLogger, dateutils; type TDownloadManager = class; @@ -1145,13 +1145,14 @@ procedure TTaskThread.SyncShowBaloon; function TDownloadThread.DownloadImage(const prefix: String): Boolean; var - TURL, lpath: String; + TURL, lpath, sfilename: String; {$I includes/MeinManga/image_url.inc} {$I includes/SenMangaRAW/image_url.inc} begin + sfilename := ''; lpath := CleanAndExpandDirectory(CorrectPathSys(manager.container.DownloadInfo.SaveTo + manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr])); if not DirectoryExistsUTF8(lpath) then @@ -1190,16 +1191,24 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; Result := GetMeinMangaImageURL else if Result then - Result := SaveImage( + Result := uBaseUnit.SaveImage( + FHTTP, manager.container.MangaSiteID, TURL, lpath, Format('%.3d', [workCounter + 1]), prefix, + sfilename, manager.container.Manager.retryConnect); if Terminated then Exit(False); - if Result then + if Result then begin manager.container.PageLinks[workCounter] := 'D'; + + // remove mangafox watermark + if manager.container.ModuleId > -1 then + if Modules.Module[ModuleId].Website = 'MangaFox' then + mangafoxwatermarkremover.RemoveWatermark(sfilename); + end; end; procedure TTaskThread.CheckOut; From 1c82aba1fb27aafb10d0ee4f162d5aa19265085a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 17:09:16 +0800 Subject: [PATCH 0666/2794] add remove mangafox watermark option --- mangadownloader/forms/frmMain.lfm | 43 +++++++++++++------------- mangadownloader/forms/frmMain.pas | 13 +++++--- mangadownloader/languages/fmd.en.po | 31 +++++++++++++++++-- mangadownloader/languages/fmd.id_ID.po | 7 +++-- mangadownloader/languages/fmd.po | 5 +-- 5 files changed, 65 insertions(+), 34 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index ee9698317..55aefc104 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -709,18 +709,18 @@ object MainForm: TMainForm end object tsFilter: TTabSheet Caption = 'Filter' - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 object sbFilter: TScrollBox Left = 0 - Height = 480 + Height = 521 Top = 0 Width = 606 HorzScrollBar.Page = 568 VertScrollBar.Page = 424 Align = alClient BorderStyle = bsNone - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 TabOrder = 0 object pnGenres: TPanel @@ -1827,7 +1827,7 @@ object MainForm: TMainForm ClientHeight = 521 ClientWidth = 606 object pnOptions: TPageControl - Left = 9 + Left = 8 Height = 444 Top = 8 Width = 587 @@ -1999,7 +1999,7 @@ object MainForm: TMainForm end object tsView: TTabSheet Caption = 'View' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 object cbOptionShowDownloadToolbar: TCheckBox Left = 16 @@ -2087,18 +2087,18 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 object sbDownloadConnections: TScrollBox Left = 0 - Height = 375 + Height = 416 Top = 0 Width = 579 HorzScrollBar.Page = 457 VertScrollBar.Page = 304 Align = alClient BorderStyle = bsNone - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 TabOrder = 0 object cbOptionUseProxy: TCheckBox @@ -2896,15 +2896,15 @@ object MainForm: TMainForm end object tsMisc: TTabSheet Caption = 'Misc' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 object gbMisc: TGroupBox Left = 12 - Height = 349 + Height = 390 Top = 12 Width = 556 Anchors = [akTop, akLeft, akRight, akBottom] - ClientHeight = 329 + ClientHeight = 370 ClientWidth = 552 TabOrder = 0 object cbOptionBatotoShowAllLang: TCheckBox @@ -2925,15 +2925,14 @@ object MainForm: TMainForm ParentFont = False TabOrder = 0 end - object cbOptionMangaFoxRemoveWatermarks: TCheckBox + object cbOptionMangaFoxRemoveWatermark: TCheckBox Left = 16 Height = 19 Top = 88 - Width = 317 - Caption = '[Mangafox] Remove watermarks (Beware! Experimental!)' + Width = 312 + Caption = '[Mangafox] Remove watermark' ParentFont = False TabOrder = 2 - Visible = False end end end @@ -2989,12 +2988,12 @@ object MainForm: TMainForm Caption = 'About' ChildSizing.LeftRightSpacing = 2 ChildSizing.TopBottomSpacing = 2 - ClientHeight = 480 + ClientHeight = 521 ClientWidth = 606 object btCheckLatestVersion: TBitBtn Left = 25 Height = 40 - Top = 429 + Top = 470 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Check for latest version' @@ -3040,7 +3039,7 @@ object MainForm: TMainForm object btAbortCheckLatestVersion: TSpeedButton Left = 193 Height = 40 - Top = 429 + Top = 470 Width = 40 Anchors = [akLeft, akBottom] Glyph.Data = { @@ -3085,7 +3084,7 @@ object MainForm: TMainForm object btVisitMyBlog: TBitBtn Left = 249 Height = 40 - Top = 429 + Top = 470 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Visit my blog' @@ -3130,7 +3129,7 @@ object MainForm: TMainForm end object pcAbout: TPageControl Left = 2 - Height = 416 + Height = 457 Top = 2 Width = 602 ActivePage = tsAboutText @@ -3140,11 +3139,11 @@ object MainForm: TMainForm TabOrder = 2 object tsAboutText: TTabSheet Caption = 'About FMD' - ClientHeight = 388 + ClientHeight = 429 ClientWidth = 594 object rmAbout: TRichMemo Left = 2 - Height = 382 + Height = 423 Top = 4 Width = 588 Align = alClient diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2806eaaf1..218814f98 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, frmAccountManager, CheckUpdate, accountmanagerdb, - USimpleException, USimpleLogger; + mangafoxwatermarkremover, USimpleException, USimpleLogger; type @@ -54,12 +54,12 @@ TMainForm = class(TForm) cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; + cbOptionMangaFoxRemoveWatermark: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; cbOptionDigitVolume: TCheckBox; cbOptionDigitChapter: TCheckBox; - cbOptionMangaFoxRemoveWatermarks: TCheckBox; cbOptionLiveSearch: TCheckBox; cbOptionUpdateListRemoveDuplicateLocalData : TCheckBox; cbUseRegExpr: TCheckBox; @@ -4393,7 +4393,7 @@ procedure TMainForm.LoadOptions; // misc cbOptionBatotoShowScanGroup.Checked := ReadBool('misc', 'BatotoShowScanGroup', True); cbOptionBatotoShowAllLang.Checked := ReadBool('misc', 'BatotoShowAllLang', False); - cbOptionMangaFoxRemoveWatermarks.Checked := ReadBool('misc', 'MangafoxRemoveWatermarks', False); + cbOptionMangaFoxRemoveWatermark.Checked := ReadBool('misc', 'MangafoxRemoveWatermark', False); // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4512,7 +4512,7 @@ procedure TMainForm.SaveOptions; // misc WriteBool('misc', 'BatotoShowScanGroup', cbOptionBatotoShowScanGroup.Checked); WriteBool('misc', 'BatotoShowAllLang', cbOptionBatotoShowAllLang.Checked); - WriteBool('misc', 'MangafoxRemoveWatermarks', cbOptionMangaFoxRemoveWatermarks.Checked); + WriteBool('misc', 'MangafoxRemoveWatermark', cbOptionMangaFoxRemoveWatermark.Checked); finally UpdateFile; end; @@ -4645,6 +4645,11 @@ procedure TMainForm.ApplyOptions; //misc OptionBatotoShowScanGroup := cbOptionBatotoShowScanGroup.Checked; OptionBatotoShowAllLang := cbOptionBatotoShowAllLang.Checked; + OptionMangaFoxRemoveWatermark := cbOptionMangaFoxRemoveWatermark.Checked; + if OptionMangaFoxRemoveWatermark then + mangafoxwatermarkremover.LoadTemplate(CleanAndExpandDirectory(GetCurrentDirUTF8) + OptionMangaFoxTemplateFolder) + else + mangafoxwatermarkremover.ClearTemplate; //languages ApplyLanguage; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 1ff976ec9..c48bf97be 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -91,6 +91,9 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" #: frmmain.rs_dlgtitleexistindllist +#| msgid "" +#| "This title are already in download list.\n" +#| "Do you want to download it anyway?\n" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" @@ -119,6 +122,9 @@ msgid "URL not supported!" msgstr "URL not supported!" #: frmmain.rs_droptargetmodeitems +#| msgid "" +#| "Download all\n" +#| "Add to favorites\n" msgid "" "Download all\n" "Add to favorites\n" @@ -127,6 +133,10 @@ msgstr "" "Add to favorites\n" #: frmmain.rs_filterstatusitems +#| msgid "" +#| "Completed\n" +#| "Ongoing\n" +#| "<none>\n" msgid "" "Completed\n" "Ongoing\n" @@ -141,6 +151,9 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader already running!" #: frmmain.rs_hintfavoriteproblem +#| msgid "" +#| "There is a problem with this data!\n" +#| "Removing and re-adding this data may fix the problem.\n" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" @@ -194,6 +207,11 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" #: frmmain.rs_lbloptionexternalparamshint +#| msgid "" +#| "%s : Path to the manga\n" +#| "%s : Chapter filename\n" +#| "\n" +#| "Example : \"%s%s\"\n" msgid "" "%s : Path to the manga\n" "%s : Chapter filename\n" @@ -232,6 +250,11 @@ msgid "One week" msgstr "One week" #: frmmain.rs_optionfmddoitems +#| msgid "" +#| "Do nothing\n" +#| "Exit FMD\n" +#| "Shutdown\n" +#| "Hibernate\n" msgid "" "Do nothing\n" "Exit FMD\n" @@ -529,9 +552,11 @@ msgstr "Auto generate folder based on manga's name" msgid "Enable live search (slow on long list)" msgstr "Enable live search (slow on long list)" -#: tmainform.cboptionmangafoxremovewatermarks.caption -msgid "[Mangafox] Remove watermarks (Beware! Experimental!)" -msgstr "[Mangafox] Remove watermarks (Beware! Experimental!)" +#: tmainform.cboptionmangafoxremovewatermark.caption +#| msgid "[Mangafox] Remove watermark (Beware! Experimental!)" +msgctxt "tmainform.cboptionmangafoxremovewatermark.caption" +msgid "[Mangafox] Remove watermark" +msgstr "[Mangafox] Remove watermark" #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 807e5ba73..4d513f833 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -519,9 +519,10 @@ msgstr "Buat otomatis folder berdasarkan nama komik" msgid "Enable live search (slow on long list)" msgstr "Aktifkan pencarian langsung (lambat dengan daftar yang panjang)" -#: tmainform.cboptionmangafoxremovewatermarks.caption -msgid "[Mangafox] Remove watermarks (Beware! Experimental!)" -msgstr "[Mangafox] Menghapus Watermark (Waspadalah! Eksperimental!)" +#: tmainform.cboptionmangafoxremovewatermark.caption +msgctxt "tmainform.cboptionmangafoxremovewatermark.caption" +msgid "[Mangafox] Remove watermark" +msgstr "[Mangafox] Hapus watermark" #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index e33769c81..7f1e45813 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -491,8 +491,9 @@ msgstr "" msgid "Enable live search (slow on long list)" msgstr "" -#: tmainform.cboptionmangafoxremovewatermarks.caption -msgid "[Mangafox] Remove watermarks (Beware! Experimental!)" +#: tmainform.cboptionmangafoxremovewatermark.caption +msgctxt "TMAINFORM.CBOPTIONMANGAFOXREMOVEWATERMARK.CAPTION" +msgid "[Mangafox] Remove watermark" msgstr "" #: tmainform.cboptionminimizetotray.caption From df382f7c38aedb4526a4a18bd295a32c17e1e0e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 17:09:35 +0800 Subject: [PATCH 0667/2794] add extras to unit path --- mangadownloader/md.lpi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index aa41ede82..e9a76ef61 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -34,7 +34,7 @@ <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -79,7 +79,7 @@ <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -127,7 +127,7 @@ <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -172,7 +172,7 @@ <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -317,7 +317,7 @@ <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 32722debd2c1e2bf43cf84b352b663edca1c6fea Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 18:25:20 +0800 Subject: [PATCH 0668/2794] fix manga fox remove watermark --- baseunits/extras/mangafoxwatermarkremover.pas | 140 ++++++++++-------- 1 file changed, 81 insertions(+), 59 deletions(-) diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas index c64784d01..00a37405a 100644 --- a/baseunits/extras/mangafoxwatermarkremover.pas +++ b/baseunits/extras/mangafoxwatermarkremover.pas @@ -15,43 +15,46 @@ procedure ClearTemplate; var minwhiteborder: Integer = 4; + minpsnr: Single = 9.0; implementation var imgtemplate: TDynImageDataArray; lockproc: TRTLCriticalSection; + colorwhite: TColor32Rec = (Color: $FFFFFFFF); function LoadTemplate(const TempDir: String): Integer; var flist: TStringList; i: Integer; begin - Result := 0; + Result := Length(imgtemplate); if DirectoryExists(TempDir) = False then Exit; - EnterCriticalsection(lockproc); - flist := TStringList.Create; - try - FreeImagesInArray(imgtemplate); - // load all images in template folder - FindAllFiles(flist, CleanAndExpandDirectory(TempDir), '*.*', False); - if flist.Count > 0 then - for i := 0 to flist.Count - 1 do begin - SetLength(imgtemplate, Length(imgtemplate) + 1); - InitImage(imgtemplate[High(imgtemplate)]); - if LoadImageFromFile(flist.Strings[i], imgtemplate[High(imgtemplate)]) then begin - // convert to grayscale and do thresholding - ConvertImage(imgtemplate[High(imgtemplate)], ifGray8); - OtsuThresholding(imgtemplate[High(imgtemplate)], True); - end - else begin - FreeImage(imgtemplate[High(imgtemplate)]); - SetLength(imgtemplate, Length(imgtemplate) - 1); + if TryEnterCriticalsection(lockproc) > 0 then begin + flist := TStringList.Create; + try + FreeImagesInArray(imgtemplate); + // load all images in template folder + FindAllFiles(flist, CleanAndExpandDirectory(TempDir), '*.*', False); + if flist.Count > 0 then + for i := 0 to flist.Count - 1 do begin + SetLength(imgtemplate, Length(imgtemplate) + 1); + InitImage(imgtemplate[High(imgtemplate)]); + if LoadImageFromFile(flist.Strings[i], imgtemplate[High(imgtemplate)]) then begin + // convert to grayscale and do thresholding + ConvertImage(imgtemplate[High(imgtemplate)], ifGray8); + OtsuThresholding(imgtemplate[High(imgtemplate)], True); + end + else begin + FreeImage(imgtemplate[High(imgtemplate)]); + SetLength(imgtemplate, Length(imgtemplate) - 1); + end; end; - end; - finally + finally + flist.Free; + end; Result := Length(imgtemplate); - flist.Free; LeaveCriticalsection(lockproc); end; end; @@ -68,10 +71,9 @@ function ColorIsWhite(const Color: TColor32Rec): Boolean; function RemoveWatermark(const AFilename: String): Boolean; var - imgbase, imgproc: TImageData; - i, x, y: Integer; - nh, bmi: Integer; - bmv, PSNR, MSE, RMSE, PAE, MAE: single; + imgbase, imgproc, imgtemp: TImageData; + i, x, y, bmi: Integer; + bmv, PSNR, MSE, RMSE, PAE, MAE: Single; invalidborder: Boolean; begin Result := False; @@ -80,59 +82,79 @@ function RemoveWatermark(const AFilename: String): Boolean; EnterCriticalsection(lockproc); InitImage(imgbase); - InitImage(imgproc); try // not supported image file if not LoadImageFromFile(AFilename, imgbase) then Exit; - // probably doesn't have watermark / 728px is default mangafox image width - if imgbase.Width <> 728 then Exit; - bmi := -1; bmv := 0; // compare image to all template for i := Low(imgtemplate) to High(imgtemplate) do if imgbase.Height > imgtemplate[i].Height then begin - invalidborder := False; - // crop image to match template - NewImage(imgtemplate[i].Width, imgtemplate[i].Height, imgtemplate[i].Format, imgproc); - CopyRect(imgbase, 0, imgbase.Height - imgtemplate[i].Height, imgbase.Width, imgbase.Height - imgtemplate[i].Height, imgproc, 0, 0); - // do thresholding - OtsuThresholding(imgproc, True); - - // check minimal white border - for y := 1 to minwhiteborder do begin - for x := 1 to imgproc.Width do begin - if not ColorIsWhite(GetPixel32(imgproc, x, y)) then begin - invalidborder := True; - Break; + InitImage(imgproc); + InitImage(imgtemp); + try + invalidborder := False; + + // crop image to match template + NewImage(imgbase.Width, imgtemplate[i].Height, imgtemplate[i].Format, imgproc); + CopyRect(imgbase, 0, imgbase.Height - imgtemplate[i].Height, imgbase.Width, imgbase.Height - imgtemplate[i].Height, imgproc, 0, 0); + // do thresholding + OtsuThresholding(imgproc, True); + + // check minimal white border + for y := 1 to minwhiteborder do begin + for x := 1 to imgproc.Width do begin + if not ColorIsWhite(GetPixel32(imgproc, x, y)) then begin + invalidborder := True; + Break; + end; end; + if invalidborder then Break; end; - if invalidborder then Break; - end; - if not invalidborder then begin - // compute error metrics - ComputeErrorMetrics(imgtemplate[i], imgproc, PSNR, MSE, RMSE, PAE, MAE); - if PSNR > bmv then begin - bmi := i; - bmv := PSNR; + if not invalidborder then begin + // adjust imagetemp width + if imgbase.Width <> imgtemplate[i].Width then begin + NewImage(imgbase.Width, imgtemplate[i].Height, imgtemplate[i].Format, imgtemp); + FillRect(imgtemp, 0, 0, imgtemp.Width, imgtemp.Height, @colorwhite); + if imgbase.Width > imgtemplate[i].Width then begin + CopyRect(imgtemplate[i], 0, 0, imgtemplate[i].Width, imgtemp.Height, imgtemp, round((imgtemp.Width - imgtemplate[i].Width) / 2), 0); + end + else begin + CopyRect(imgtemplate[i], round((imgtemplate[i].Width-imgtemp.Width) / 2), 0, imgtemp.Width, imgtemp.Height, imgtemp, 0, 0); + end; + end + else + CloneImage(imgtemplate[i], imgtemp); + + // compute error metrics + ComputeErrorMetrics(imgtemp, imgproc, PSNR, MSE, RMSE, PAE, MAE); + if PSNR > bmv then begin + bmi := i; + bmv := PSNR; + end; end; + finally + FreeImage(imgproc); + FreeImage(imgtemp); end; - FreeImage(imgproc); end; // save cropped image - if bmi > -1 then begin - nh := imgbase.Height - imgtemplate[bmi].Height; - NewImage(imgbase.Width, nh, imgbase.Format, imgproc); - CopyRect(imgbase, 0, 0, imgbase.Width, nh, imgproc, 0, 0); - if DeleteFileUTF8(AFilename) then - Result := SaveImageToFile(AFilename, imgproc); + if (bmi > -1) and (bmv > minpsnr) then begin + InitImage(imgproc); + try + NewImage(imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgbase.Format, imgproc); + CopyRect(imgbase, 0, 0, imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgproc, 0, 0); + if DeleteFileUTF8(AFilename) then + Result := SaveImageToFile(AFilename, imgproc); + finally + FreeImage(imgproc); + end; end; finally FreeImage(imgbase); - FreeImage(imgproc); LeaveCriticalsection(lockproc); end; end; From 2f5963cb9a86d3492db6192cb0b2b99014c449b3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 18:29:36 +0800 Subject: [PATCH 0669/2794] add manga fox template --- extras/mangafoxtemplate/728-01.png | Bin 0 -> 50465 bytes extras/mangafoxtemplate/728-02.png | Bin 0 -> 18576 bytes extras/mangafoxtemplate/728-03.png | Bin 0 -> 12787 bytes extras/mangafoxtemplate/728-04.png | Bin 0 -> 16618 bytes extras/mangafoxtemplate/728-05.png | Bin 0 -> 23361 bytes extras/mangafoxtemplate/728-06.png | Bin 0 -> 9991 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 extras/mangafoxtemplate/728-01.png create mode 100644 extras/mangafoxtemplate/728-02.png create mode 100644 extras/mangafoxtemplate/728-03.png create mode 100644 extras/mangafoxtemplate/728-04.png create mode 100644 extras/mangafoxtemplate/728-05.png create mode 100644 extras/mangafoxtemplate/728-06.png diff --git a/extras/mangafoxtemplate/728-01.png b/extras/mangafoxtemplate/728-01.png new file mode 100644 index 0000000000000000000000000000000000000000..5d24c8f4fdac1020b59e7e64d7b9a18f748e6222 GIT binary patch literal 50465 zcmXt91y~hKu%){j<fjEenoD<w(%s#i(%mUt(j9_;G?LQN9ZG|ABh6dh`ySsXD%{we zojG&PnY~d;3exB(Bq&f&Q0THU5-LzoFpJ>dI!G|DKhbC^2Y(?u$!NPmL80Ql{(*+d z`a%SLi0CFOFNydYjQ|rHE{<%S4ho6_N>)Nt&2#z4?^BBU+>e(}c`k>m`)Kav)5UV? z<PvD1MltZBc0}lJNq*ko1<0v|TH&d1)<BX|tqNPjKIRH?!KDgaF>uJR^v$j)u5<|t zaTs##jh{g#h`bUSw5s|4<u*+GS$jIRj|shkP*LfAhRFOaMy8?~qm3EDE1roOrL8Z< z<wA>#q>-h6n^=Y{pM<x)K`W~wcOfuwDL`-j4lCt0q`2l#%qsVaaTEn!Jc$My87HZD z&r1wR-iqjFa&AgeWGL3H6mGAFz5W8{w7>;qI&#RvUNo!VP3{%xARAgpq~5}uyFM<? z1gD|_B%s?4o>MUc=@Xws7M&!mDX~=dB&>>@Je~7q53c4VQr_u^nQD-Th^;pc%XPhW zLL@|f#$DfvB%#)eOjZzIQ4-}M@{3zNGZvC{7G>y%F;?q)3W<|P1-)Ks;voyYu}Sn~ zJ!{=eyLWhFItr{rcr<zwZ>jWWqK2;Z^e-dbs6y;MSTQdVPt)v&#~xCNNywtWsl*eo zUJTQUCrPH&9JbZqVtbH|I_uMCF;h_?yCtf;LwY-#=_4jru@CbNUqXZHKUUb{x5J#W zBs7B4b~t3p`E^s{ENCB+azBXu^^Ch3x*WnyD|kbuoTew5#rz|%C|Od1#C*n#2M>!K zuYQPP6xk-csH~V34nA^-8U-uSty)5yLPLUmi}uh>Uxnu*o}4m7UX4+oQfJY7!M!9U zch5QtL4by8&{+nzZ4%CFyH!Q5;0=wNEX~kcDn+?LcfpC|EC-TOij6k<L1!4L$w~Qz z)Ha7CnuT*W@uo;M?a?W>2?%6?nldDw`af>ssJ~>bDCahGtcJ@O0l3OI)>)<2Z8Syr zs|w3C#wCp+6j(@DiN{{ku3@FbBPTYo5h{xk+g{941R#<P_PR+0hi%40B*^soe4@WM zX%6fL3^$N*f<qTVxmA*8L$T5<_r*A31MOGZYHYL8#+Jc@vnZ$rDSz8h*-^?OB_)OC zSId_!!6DH%WSvEZUTDyl*yW<--b6yE;)*S_6)3RA`L0Dd79so#)SoL4ld$bg;+yOP zLrZ9=aN1Htd^C|nvnVc#Q%KB9QnE^Ya^II!9U`Pv*(K+f#^FkAC%qq%H^(7Srop4c zk;tNfj<wJ2w9ri>M#92w9SiYFiX6gH`Mj67$3+xQ8Cn{wEk~av;(W2wN`s>FlUsIp zSG4%BZG8pgc8qq~*F;wNkjUa=6dW_FV!G6_#?mJWstM}uk;}+(<lJ0oZ?Z&jGu_N$ zYq&7%G&4^L65imUWaf;hGc@^y5@`nEI|jqt?+{}wYZ^rzw;U-^J}dL`cWM?h#_7vu zN8c<|eo>zj)1YyL*$pJBAfTyoN5b{L!L54~NMg1&L<=l-(|t663~L8N9I4c)B0>+% z-8Qnkm5Q(uX-nRl>&#FwB_xM!Q{ceG!9^prPEUn82Typ{q|{6bgour7%Z$+CCH30g z!K<ipLT45cevym3zp2lBoI^fyxbt`KppE?24ZAX%<+wX|K7remGVNYs4L8>#xSyEd z0Ya^B#iW?Djf@~4nq86-UdmmiG3~Ao0%je*MdY22-x!7@FhZmGc>#^60e`)v#<5O* ztt>fis-q*>o&7ZQY$&HIXZ~YyC~e8N5{fvQM4Ag4csS&Rv|ef^83}gV%<#{kc5h9h zH0DH;w{40K$%vDRzYn=ziG<Q5?&dI><6kAJ$RuTbi*lp-{kAg364j(sfh6&(@<^k* zenu`K4RwVzLgJoTaZY?Fb<)QONW$Mp@i2r;3FwQVMu@S@*ymZA8uM{@`r|%a`I)S+ z*oE%_!I6-JVmCYanS5_KDuV<Cg$9QF^J%>Zw<7#PC)pW6s%#lLYlt;YuZ#Xs3@u!2 z2yM!IqlQsUPJWR^#YYu6@d+$=SsNOoXitf@J>o2@RNsO<$cL*^^;_hwJI8&_H>`#G z0UbKF1Z8wlY*fur+Sq-nCJJ1MJ1x_5;-b^pXw<T1mK+5}L(T&9CDsQ`rl^!|qGCi0 z%j|T{q==*3Xhn5wiR7cyg=!=562H<~ldUrUt3XW~YxW}B4<?O33(-r5#D!9<&{E1Q zD4JB#Wc!cV$VVf86Jyu1x6$}iXFf*lIo1{_MI$5U0+(oIayZsDh5XQuM|XA&2aDb7 zs`yQne%L*m%o-i@>2o68ZfORU{IuqmVz^v1DcLx52mc_2U>VO$y8$#wnnY0r4qr|p zCb1a>7Rk`!QtPpU&V>$m=R%~`c)Zd{x3apP@q|!W>OHeSv0^0AT-y*Vk>6+{@}B|; z_ucqNF>t*!xZWTkWb@8<DPUuNUByK4fU~A)q&08He;X7Tdbqr~J!Z#l6DB3mltX#( zO9W~F8iKQW$}wuc5TrlCVOwA2`J9DSErjjG8;mQ}KpUFkZ(pQ6?_FAfEE+GKC6(o| z83JlJ(HKIX-S+3_!e2b!zJCOwW6aS1F%z%2gork%cl#*_%E?^lY5pZi38$@1G9mkB z4^4!eK2#i=`nk=RgtBAG-A>%mOD>CNZiR{eZE@+Ls6H;u&?TunhhDR+R<F>2!QU*3 zl|(b2tdj%iNQuFEdLx7=w|#Stcx((U4B}ok_m#`wZsKx{=$hTeVk8uL_<&mfNl2Vy z17l1iOi&<=T(a%w8tnZ^)ZrTed8@WF1)`0QbSiSw@*_HJAMj9Q;_7p8r_nBkrXy*V zw5_vX_^Xq5&Hm#kQI?<%K}tC~@Q|N|^r_`1(@Z2~G0RXVNyJMxiQffH6bkdkQ-@Bv z|B!VWN!AmtNhzh4LF&J<pVolji<kWL%w3>KQp6&(Z6iaD(_`6c%dL<WNPy&oIw`PH zkmvfKEJc?Zme5Q;Ni0;Ct^|KP!<HpTl%A%k$Xget`(Uz)tPjV`DnCOZnf;4aQI4Jy zN6d;&IdMWMktV9xO~z9UDTySJS<uB@R^=cGQs7l{D5uCFpHOTpYivamS?s2-$&D_% z-4cJe+#@oXOvclCD62msm|@pDs3MExBB<%8fx=Gwo(K)1Ts~7z>P}A?8W=KvPAWeG zXWe9r_#H~NS-aL|8a7I1NMQ5=209MCjFy%{XO}{I0`)J+dxQAH)?hdN8Tz*}-y9cH zo0#3GT!tqVNIoua%NFLxc87#4)ctW4qgKPiE5MGj8%0RK-CoHOnX;SaO4x$7ElG*r zf{R_;!}T0XZk|cQhJ@De(x_&-`M=xdi?2a+irABrC#3PS7}C_iH%2VB5i%G2@DB!| z>Ll1~vgTj;H+9AE!EqS(bCtF<bNCR^L1(>v_+Ouo7fX%(ow-bG`9kNTjnT&Xs1%Xd zIgMJJblMGNCay8*vbI<e62C<;QpE{`2qX&>2BPyzK`0riKRb)v@oyYlL98qL+NS#y zy+4d3(g}L>-Tov>90<?a;>jxIJS~sN7MuVSNN&Ha#`ueqna?!tW@vNk5?!x}_?|4P zB%!llI>=tJYyJw9G%NRZg$ujOkls{zzONJusq0L+(pe|pvHm7bCuNoLlJO>mDp0a~ zfL6t7rFrHb!KFK_6Kno&WwwMFk`!*6?9lyqBe3t4Yxx&pLiIDngcXV!a+3Ue_n`)v zg(3GynC&nbLgECp5V*JQ(e+f*RGar=c3)jF5+aK~h|OrxE;ZR&#nT4U&}X}cU@uy< zy>0w9t6;J=M(a6{NI6E6J~X02^B2iwD7og%ys8AH3#>$NXu3RIaH20&y~K2J;Ah$r z!3ty)<QTh%YAXiG0winE2(%a(M=th8i@33712}URuLN<G<SdHb_&y;ISrUWfqGH(x z0-A!ap1qd>zh|?)%F2q#ByDpRBrseHDz?QV!HL!c7f;bBgcez|N@T&9NEBNK!}0dw zyWwbTDef<gB|-|GX=IXXEcmBc!%CMVa%qx_X+z8GYPPk$hJOyq$0fr?4mw75hgT{1 zjB6v;aLp)_E)cn?ow$v3AyDDPy!Dl?n8rnxIw`oAS&%ZDTgFC(M`D{N%{oJZ%CxnO z*iE099qtV;-Dxpw13M9#O%`oQ%C?P|Ey`dd?$mqPZCS-KsBGMN?dUdUVln(HGHWpu zstYW-DVd3>xO(|j(I^U^X$~2>>0#$#d@~Xn0UVWR+BH2|(=ah;UnDqmc`E|!zbo#= zSYq5m_%u;y``bMBpa@F_xI}71OTy*xZk14Pljk_WVeWG#MoVvdn_1P2lw`Yoq>6*g zZSEA1?*A3LB-P|bL!15lQL@M@oQB^%vmnsk$3n!_&YEbm_-t9z0GpC(p#i(r4xw7K zo-3Q)qi<W8c7=#xn0gvRg>M2qER!hp3*yq3ANicF-toJt;^H0o6!YJ0NwAf<J|wPp zX<=LUH~fh`=1P>BgbtNv7pIzyrlQ)}uTNHDj~rr+Rb#-9`Vz^doraGDht(j_3Ez9O zWXDB{fl67wWJiI;BZ&o#x!i=#?PF?c>hJF#GreQzRx-0MLJ^qR_rqd^O9Q<*KwMm0 zRJ11@?W}b5Klu-|$s0~uGmvmu_RLtRBDZ_JBda>b4@kyYv`>aVL|7!?1RP}(9xErl z2u4bz44a7+q!E9yUpbKS$=&0@u;lcsIb2gn$lDRCBqfU6;)&n-j*wY9WM`~0KR1Vu zj}Nw${kG7ERYv06Q-C1mElyNN>G}ns6Pu7{E@E;j8~LVqf0`XvOy>49YVKGV$7Fqf zMnC<4uxk!ibYwyS6fb+`M;aVweQqK&b_Q{k-TEk1r}yLurXAK(8n?Y+ezeKR5q%v} z>)u@1obtF_+6<}p?2`WRm|Ml~Q{{-mp+$0}LQ|@^DBrBVWbwfq74Cj<cnnznDpqo$ zH$ItFSbNyUlDgMm_#)-~xOZDTGUjWsqA5}Eo$);jOTsnUN|QFzkQsZaHM@m>U3C4P zSCjq2k;>d}jB!lXCMlLY!tt+h0lR#Sd5`ZuWtL{jl>|cXyOEUI`}+%NzQe=E@81Hu zuCdmkO{RbM4!n?rnyM=7Hh<%got+&T91M7@qiFu#2UgrLtjPapagg&Z3=DGZS9*-F zM)AZ%0+Li{lZRR436(k3CN6QJ;5wrusLqJ$He7V{0*%41EE=F%jEP<ly+pxLvuCEL zfR~80T>oSJ9Zrec=jh{1b#1M1<C46@h7%7Kk{LVk<DFM+0E?hMvryC+IvmXP_4Rs? zAtw{u>KiVaz<r*0>nt&(Z)-~LXhNYplZUqnhawW=3D6MON)G{un>Q@E@#PGgF^*2V z3lgFAQV78R@HOCR=6cRNgj_}{H7rc+{Rwo9y`I<O&bqgAl{yb_<TL#|VP)qRR5f}n zE=SK6$Fk%VucN169`+waN$lX(-Q8W2{YujlzL`^*R(z>7t5y9HW1)|imsi;bnN8I1 z5=(*n%FC|zp%$cr=K`1vlJD?bNC%saRk7S@lY_2@mG$rQB=KMLuWnmEA}zRs#yB33 zdA>6tnUK2&4qqtbs`Ddl$Si5<O5T^PJK-OTC5gjk0u!pdMCE}!@ShxQuf)bGVDkPO zXNnJyg6AC*pxSp^W<@LZqo_x!K_P>iill)u(q%{$V@-%WI5^Nk7w&(5bGoJ|F=d5k zY&2T0b$X|H8GnE8-GO?7MgO)otU-5r-%Wt*1&0W30_6vr(i8NVi*>AZmLY~yC#%E) z#5064&P_j|-=r*&;8{}t^Pq&=<E`@%ZS=5W`kkv5D;|nDJ2B_LS{5DJb_jnE)JrJA z#cAPSfS7W~rn<iVm<#q2lOYqT7Sfq(@f9?3Vi<x|2=?(xvtq@E+f9A;{74C^AOTEP z6dvK=o_zb2uT!IYVXn4YdCH;+!U;&&a|;WE1O)8TNC+XHQ$RA|L|J8dJl>v9PpfE{ zCJzJlD)T7N=m?9TAwZTORb*HX4gEG}&rUndeq}wiLJeiOY1MoCgDbx?CC<ywAg|(w z0<lv_eQ{=yv%#6=`RAw8c9)s5&W{soFRMi%t1wy<L*l|==KEe`AJerMOI7ZL|J|_U zk-bF4Kqq~qrA|b8;Oq*%lt|!ra!fmEvNsKR#utJ$i>-gI^j=aw%{mZuj5E*)ZO9VO z84cDUeTgM-;q#J68V0g6EG+Ekj|c?2r?sO);0p0Q6BB$cwlY;>q*M{eb+QEN;!n|M ztV+TxESOn5c*a~I&+ddI5~V5?A{6UhWM(wFcKH($REc92#xnt#tb6_yadB}`5{3Es zP~Dd7&q;fi!rzN~Xhk0Nl&=Hg)*F@>O$izB7)SZyT+CsDpaz+jbOame7)deqc6NgF z%Z0iEHt+vUZ&`L^gh&=m&4+Gk{^UhWhq4oX=Mgz|dqbE>Y>1~Q&I-RI7Kz@!<-EP# zFn~}d$wMjxDu{qb{I6Ep-14oZ+UJ>%*ilkN-BUt-_jq`C+k1PT4rVLL%gdz`$O@E( znvTb^xg*31)EMBuc#tBl=&7o@4!=$BCiX-b&2MV*xcWQgL<GQ}=Aq2>Nch1#Yqvl= zg1PN4)w{Rv5JI?vPmvKq5@pQhD%B0eYJ}dC3k0b#sO#$L>gXKsU>qc6g!m$#-NDqt zqY|W~ryKg7_Ya%l*sQ&X24f<Ggc}EHLF7Xa&@g=3^eWUw+<(I&Vo+=;B02ZK6Mhjp z4^Ffp8kkWO&dJLQ*e^+co|%3cEdzNwg%;6=h)G7u@4?7fHv8y$*ZN`ud(<5SYrp(m zmNpq6&|a<&a|UL;hW1PMxPK7LoAUU3`aahBr6cfazndM`-q*Ag*3`uJz4fG)Bh@KR zpI<+kkx`;K;!*g&ye_vZ8x2c=*URR1l(K?KH`ji{W%usgJ06cCq7)^1bFS=bK@8+* zVUA3+ZNd79S$<{8U}H86huy?EL%+4H4=DuHwYiojKAiQ;zR4fUW;!44E&(Q$x2|gH z<8`&w)nR|?eTvlHSWsi=j{)m3tTp&?`{NzmR)N~Lb+U=e`5JxH!hS2yFh22W632?l z%7d9Q%-WQK(67cB<)0O4leKsp2GTQ#9JY#LZkaln`tmy7t@fSDmCek}%}IQBKhz-m zQlPJ^JKDV+wgv0Z4S!P9i3hc}Vq~#1Ue<qIxwTGDwt6YBnlFYwad9gIx%}<4J(Nf$ z=v{7=Ic#=@TX?G5WJk};JkYB=R<01(981qkmhjN2d>*<MjL8bE{u3(U27QN`d^LZX z$1o7eKR7^FuGMCaLB)mRd;^>V01r*WP-0LT;6Ovg3gX^yUu@$>!G(+MHnusRbyecR zBAl#sb(s#vx48C4<6D_ouW-#sGQaOW%qRiyZ&Z2iN&2opp^>xA*2>Dr&AieYT{x(1 z(Hp<Vv+_2a7j`Wc-z&FloP5|zD6OiV)7OcVE_=*jrHM&cxT~f{!S8pjpwIoyG3s4h zzsZKs_V#eOquCHmvTSNsh0z|Gz+=GCA{*8651(cR5)o{WN=K`$9DlBd>GD|XH@Hek zc(m)JEQ$q$x(KV*pUi!g`r%aHbwxVDHg${bvSr?JG^jLB(0%RPT(GW<G;7eN_!*A= zrkuAd=N$PW!MT4BCZ0^NG9Gi)oV3?Ib_Y<YR5?)@)<NTa08oBBgIBw_I<e#eac1lw z*uK>f$l+m6X-vA4-{Yp#{+k(`J;O`>F|w;sYcLjQ5@fv6l)zDcvf1XKu8!}?%u%i9 zw%2TAOFC#gSu$gtR}Id*RSq`Ufh$`b8I!yGAYYNNN0mZ(!95eZ>Y?3ylwkX(EWNFb zjc@F*GpYLmk(X0lY4E3tFNDM~3=k3$l8oP9On!8Ht#k=lnLVG&KF?f=W3W<RpPiqt z(W(<$aG!-Q$J+JLsMgvrt!C6z(<i+?^HsFBXR?TaP9PT^&(mHrpGRIb{W*XHQcq^g zBCFnBHz!vSQ9Z0pardikGc!pX%(B3qd^VS4k+ORiARHP$EXJ~Wd&S_0)s@OiVRnCA zR#a3dySGSC)j4ksJU;qX7uMI~2<ec|nbuXuRYd;Weq7pE=fOyBRSd9CJed{T;jI5Q z(XaT6A$zQHl`}`73MTtsiu6F>FE!N)ycR0V7|$9MsnL4hOG|Y?^w`bjYYh`vMEe=& z{;}CCxO)ZV?rkvH@t@}$$j#{w{CmUg5b6^i2c5fpFju9#O;w`T?!n|+t}-GXfl=WC zXIei#_%Jk2a!RYK&1mAg+{7oC%5-}xu!Y=UHKzbu0_EMQ`9)dcxsfb!U_ff(65~HU z35gGBjKo5|o-{c73$<(a*N1@il;!zH!zC6;Cn)3!w1T|<kI(J)&%e&WpT4(e#`NZr zl9Dty)^>K)m6g+w<C1iPgT*@2W{2MZ34C6j{t@Eg0U+M`@$XNc>M8gRYHS4n$`7A^ zpZ<77M6_*2zo$x+DO1StzbYbEcHICd*t!+Z-{x_=-0Am#j7xjV(|Fj%|LFt}M3s>c zM9e=<edqu!+2k*K5XsGu5g84;{QX#od=I}iBcPK=NSF@9YB$>8U;Gf9Xulli_xX1c zH}^Z><%y!~{{H?0b8E4FyN9{C`An&NvP$RE4KSOfsS=gmL0or#Eida#T%LeM*66pV zrKKrkvWHb1-kxu18hDvoTU+mq=a75<rL<8nH1Aa?QTdS0{GX67&-&TG8^_|A{k^<^ z&f?<G$mK>`Zuf&(5UBH~Dvhtx5c~7Z{+5@b1fly4%m5;ch|$r}HLtxKH3oC-d1-P# zh|BiScn<%+liv@ing)p~4!_$tv5-3McC*1|nVFc5XUZnP??wNBV(&O<JG{8OoZ#L2 z^7>3t3=YKC)3UbS4}^wIW7JL>Hp>lozLTLb$+A#Zo?2~nbzV7IYT$SKJ6S59-P_yi zb-5d)&8YL;>SrW&{$qa(VV?WE_N2u(+bD_6*1g<Auy{s-!|9UIhtsZv0y3}d#FO9c zgoK3BMN?s@gcp#DiwhmyTE$G*Q76*9%Bq_C9hLy()PEZh<lu4KO<Q0Gyr&(P-Lqt# z>p>kI9fgI3!^w1mTh1Chfy1>O7joHL_L1*|g#$)X=+V*9-)mG8aoVUsNSIhy0xrk6 zdrn00Ko0~*0n*P9<OK~*h1x;;+LHqaKO+Hna@GNN@X=DIA3rveVW;onH{&1?qoL1~ zAV18i+@2rrpcFuY2Hf_M!&v=N@fz-WzOF^YAhpV}0P#&{G3>OQ$TecUJ!+V^IbQkq z{BRm!*7k7HUdKOErfAuvV{d=#zMyYOBn4h1&;Q<feVZ=N*MulM<zgq@P>L4h(r=co zM;CS8hq+q+xjIv6s)NabzCKK0Jwrpsm76cTuHM%N_%Z$AXv7zbrU}NGRhqRJ5q%TF zFTM{q$K-xj%I*mU{&(gyOdk8wJJIiJw3;3M!~OwQ07@2Ku*TpA34<C}_S3}6;{+%Y zlLWxB)hzq=g8M=+g@|JM3#b0hR;X50RTZo;>NZt#w#D?D;L<5P{w+#~j*ix%)M{}u zw!OVOX+OmvW-o4O@w`3Tc&}NbCMmS*^>?yhkUXG6F;6I~)O~+C%veQP893=PdC#+r zwwk^bSt^S?ASmf6DZZyZYax0-EF}zXr5pNt@sJLv0)|<kW&<i<NXY-ZpD-pSrY`!8 zV~6unz4_v%`{6t?CD_*vAXsUssp#ZFzN2YOo~G{Z*PwbpzEAKSR_8q(SyslBl$M64 zb6Ad(DtQAK=z4iN-5TwB++lh9_AQV(psqp6NvjdR6p=rbgP4RHr=+Ip`(4igtb@p3 zer^79u+(7rS}WIw%`Q7~^gD;OT^M{ec6M+q3=9le9F`dG;U>!&-oGz60f`?GNx)*T zTJj+sG}RiN#)BY4GN@rj!%k9CqrPzT5Cn7vdU|>$Ccm9j%?w}W_M>_&Mhy*(n})on z*sKROTAZj%4$CITHL^>yxts6p&*`BSdJFmu7V;3195z!azMLBY$AMVly)UluDK20; zk#E=h{{3FNpKmsbQBzm1un~eYpuqvU6e#~5Bd4iC$@ndSiy`Wgl9B}BXC9?i09_(6 z00%8WzUA&c-3|(qL9CPn$P~+Fz_E7RA5;}U`)<8iLkbhiI78=Nb-LS0Cl~e?$R1P3 zg6ub~I9v)~O1)V;1Wh~?tI7WL-3bjmDR&$EpS<%7&~%LfUpB%@rj-Xv>V)TBuhwqp zJdblE<#qX4U!BAM2|)g9(F`V#zW_u>R8ASQ02C9$qdULv3bZ;-<6bxcAMl<Nxq@#R z+5q^_D(1#|Q4J3eqR5ubfHT$w9f#%|AP4F)s6|*fSbiFj&w0KVQCKE_I=oayT3z=D z2nj<11fOrWp6;*va>#wpdO%y*I=?NHi~&3+d(2{?S{oM)!Leln;o~#^+THj!<G%Ha z94`Cix9NHS&_JiB{g{D;66Q3q_I%R}l45Rl_Hi9in268qomBWfY~AwWqUVI*zu5oy zZ`ON4a`yl#w*<UAFPcwWN+po}u$rP;aE|~Ld9&gOE0<<IH$Ts;^=<u&>v%<VwHxW) zWPvy+Y<E)2`D$&D6%SW4iUo2vAjRqi$v~-9RaR0Js@4)dpvuDpA8>cwje!NSCWF>; zTHP?d-2MreCJmMo2H%W=%(cN;?q#r<8uh=PPdxw0*-{KAC+AADBhU<wPw#6x>ir%( zR+<9tXYzn>CSSy`J^j@6pbvlz90gp_K~4J!iLk#fZ88XNx`Fq8EHQ`H_ip<pzlR$c z8kaH71rg0`0j~@27ETiY38dpmpH{CU|NkxkawsUr4=>M80ne9tA*4nO-CgdWEn*O{ z8i53h-}<?A-qzLz%Hg0*$nj4{csK&j_mhsxaa5L$Z%s{21qH^NKckvgT~LkO!CUEh z?W7Vp^@bu_u_FYbEX)SMB7RmVS9s%ed%KmOPTC0~Fc|kn6Og-vLD28{oYuP|$h_a> zD4edg&OpYb$-LlT`Ql-V<!F<EoGd?!7=g*Ln=Y1Jtgfo<ygxL2;S&O2^i)5}41x@N zH;~?azcM-0x1L>ljDKaY#c!!;YOZ;1#r^x^!-8;k)`zJm`swp(kO-8<2tZnepu7bG zA0`4G^O2NSno#&TcMqhj?a^W#2ziq|Ij_q$!1-L^03j_a3M|jF9>gAHXd71bm8LSl z>A<r<DgiGrhNaUJ6!Bt;^-QV0_kPJ_8J)rx(53|^R$5)@vh8)79n7;WFL%fK`}?69 zORWKTRRf|<n+(c|gxw5jm)Cl_7~lk%fG2DAnE%tEAtJT<j-;vSRvh;qPk@!;GN-@W zKdpBMz1BRb-QoOK4tZQZ#-&_12aZ82JG<5I*2&gc>v5SM5v&|nxT@FG7~CI@n*$DY z*MbfA0PsUGEzHe9{{u`GJ5GvHFVbqGH*DDKVoI7EXoSnXiDr8rP{d$2Va?Zoe}R-_ zNhtuQgNX-mSZ%SbX{F6k&`oo{p3?+w2k^wcg^e<|SJ%}|)mH;GX>xP4q*TT@x`{MJ zEV(_ZB*D`Z!D=8t7LnkvGm@$##%;G4NC3eUI1}mee*z5xkqyCat0TJ6b^+!XYZKZg z*b5r}`8*-O?PzhzUH=v>zYVYzLPb!dKTYZ?D;Yfh1UeaMfm6HpVb6R7r`YasJd$V~ z3mYF!i~)kS*69aYz7s>Gap}%zdY=PSc6X@Y1V{-EG}EntIMQ#1^=7i*K_w|54^BT* zii5(LV6W)x^asV7C<FJas;P;Kg~bv4@Ai5tK{%YU(Q&O)ghEMMJ4&-wrx68tyP7D- zE9kTuGytHJfCATI;n!S(lelsN`67c7&MPSa64c$@eKeg#dXVsj?)1-(*NDCgtgNn{ zg`nfTE79xp^?HW~!;0P)`01zf7fhjBD1*20Ur#_~zdjJdjns0XMn6#|v=6JT=5)C+ zW@<kn;L$Ws$nOj^=4e2U);w11oBw!Mv0#~I(UKaG5>(XGFf%j%X>)(izqlctsB-e> z$HVMl80;7Q7EfhyaacY62uyM^KDWQu3x+R%0x8Jx0vcyNnpPlX2O8jFC&;cM;1(X` z2a6?-S!6c&<PKKw0`;r?%?LWu1T04^5)eFa<YYp=L`0pRP7SEQetr)4flAof+3A!Z zW`q-X`a4wwx)ZQd>Z<`BQ1SWRvYHO%y*%y#{!tn4?28d52G9v+hYJEJR;ggpZ2}hA z_7L_e_?GCz<GbDs{dfm>)TjMv_zg7q8IRLHV|?#DUi*KwakasZEX7VWefcJP028UH zsnDhgq`YDhlh@9dpzIbKEEQu#By1SP8xb|W>V&0x=Qab{EJM?qSP%AzOv#>!#%J+L zKp)!O_NVLX*|nr?Sa&#jjX^)Uy*v$g@d3FM*qz@=u#dq5HJZJGE&8o7GA|OLbjJFK zF@<LC4+Yg3V(jC^C<|EMTe5@@+nz<GqAI1UFsyv}BO{<X@)6)edH}jY<3+v>3f#gh zHFNF&{bv<_M`d>c>%%lEh7FSM0ZQe}*RYbjUNsRu_+KX==Ku{n%>XJq%7}}H*yI2O zkDi*LGV&k42i6pL{`!edm;VoAB9PjEn@Vh)=zsdnY4Q`Pdub0|f)ajO4U`pVJP}!0 zSrSyxsi;t9YnX@unl*ZNv#N@s1Dp^@Mk(?~nGzLJ&Hm{#KTtXAA(-A*e|y+^W@Jzk zRY=Nw>Y2DBUTvK$aXdmoOLpRvyAqX(!a}NTVn(fR`2frT#|NV1IT#+5qB8NH0}(== zYKX6e+NBg#q84K~<KOuI_(A<C%|QBC$pRkFC1VKWzwji!!65~Wl`H`e0WwMM@>zB? zQ&3vq`UVN7+`={B^kB(W5E~+d^7tw>r{91t$8Vv%;X3L?Wzhrl)60u@)}F?5Z*Nb$ zREi3Fw0`}q6kEX-53o}t+<o|RPJmw#dkvbyPxs%(ec?Gkt~6MT-QO>C87L{`AM%le zf-bc+m_UaU1vGV7--ZO0vZm%jr=Jg8?0<vM4<dy24xB-A1?I;b69Si8<S)0jh7UT7 z1mf)+G@-6h0-BrFS!wC%gh+6p?k2-&NHGvYdPFE*^$$?Fq%%%Hgmzv{e*k-W|L&a# zBBd6-)p>9v=1?ubDx4@NiQGN+zmw1vP8&|Q6=k{JkLQE0a;ql<(KM#Oxm1N7@8~~3 zpWI)48nID`yesH892UPsd`eu$c`awlm1785!W$*VB2LxR)LLrzJ&v@#^oM!iHU94x z$h7`Prct2R7r-VH3B)D7eoa>#7R%P0Rcx)v&dXZ^VSoD}t($JDE8qp-#o=ZQi;(~0 zEhy6-EJQS-$qLmnAjJ!pNn<ugg25cigK)7rDJcnv^m|0%+a4e+LFMy*iB{6o1Tk>< zaXs&I`lA_W-c^!<;$kzfz|4<Q3+~~(BXC&M-0~d4!sI&E+S*IcPY=#WqoCO2XBe57 zc6uQ#m{SxHhe)71BoCWWAaTmW5)|ZdUwxp23v|6%vMkELeW4y3z3c$q8?ZC0!B>7h z1rZt-7gu2ck~eSucj%qO@{4{9i-x6vfdNq01(fQ1Im`?U2WwrzRP;SY-vI0Cjs`G; zgIzB>i3jxv{eyY-JP{Jk5cQFErsM<R6^5|e-_KYkK;LC>+5Dc0!jFR%CM0EUSq}zK z#fp1Eb-S|m>;bwV)AWCQx}-piV<FAX&gNSI+ByDpgN|E!klw+HJ=}|m7Yxj(2x1d~ z68@}Ewh>GPj2iYD=!&W;piVgCT>)pxDwWS*Eof>Y_<}V9>Tb!dsiTARz(re|xG$M^ z1Dsat9~wNA0xNhUvl<t0=vs`sZOkKUBcr2<C4^BDKpB7QvI>T3M%f(I`+^<Q-@Czz zr(uU4Sk$x;-UZ!~K4zh8j~b7S1ov?!w%-IE9v<M~P>lEOMg$?F7OT}{KB$JLZ93uo zwXOhrdwXYRHVqve9TaxVFtG@X|A4rG84r8|d<Nh@N#FxpMpaSp8f?D_Xb3<rB4SVr zelY8|LCJ#mb@<cjT2^WuiAI2j2SB^6jgRy%(#aLRfa%`=`#ChaDk`{;ZMp5z)U>os z*fiw#gZ0&bzyQko2HG7-M}paDWhC`|4=P~ZElT~)q~COkBgN308EyBcOMp&WvLjep z0NFfr|EfEU=!5m<Ob{D+;5`tiBG1NJYIIdqIc(>vfq`?5=G<U&M;U-ZO%4oiA~XP! zaRI^D0}NgascnFuY$T_vI4pmUvKJz%M<d24>L%dzJfk4<db(b?o6}Q*T4269e{HoZ z#@h3M+41OyFrfj9xmr8K(*{hTI#K<BN5o(Kt1kjGyA+w6-E#I7hW#m49|1QC(kw(N zt*ODFPX-lFW(n*g=!{fgL7?brg4G3ObCV?$N#6oOqn?1&`_`!$=)7mpD5M#Q>kK?| zgL^1^5_nA2kk0qZ^6LL<H5<m^!2x;)LBhuQhlmdIMXwdq5w4;D8{pAEg8G9g0`M~| zbKK`ICxnIVmmzqD0F@h>16?=Q3!n$pa#YgH0dCOXM0G!1&g(h`^;7@t1R;{4xmdQX zH9p)xc-0+qBv^C*!5q8;hh1aAo|*by6JRx%N*EgErKclKkSjR=FA21mtCHR$&=%vx zIUUadL43!^Xx4Xsw$b-)%0v-UquJ-5gZ=`q^J(LPK_5xtY{_O*tr?U!bP4a+=Qu>W z)mIq><VN6#C!|APA7=HswE&ANt0d*&-zk`K2`DZiQ$Ua3-yb=N7(`~l`T&=YQo`0P z;;2y2=f=q4>@~>8c(+j%z^-Wf_KlS+p^CQ*;2aVh3{ZZ^gtAXhrvaxc&8JgE(*I7^ zFy}HGTF;|D(yD4|(uJ-UD~t#9CW-*d)$`!@r?t0*;o;$cjypRbUP!K^?cT%g_7Ua% z=f5~JG9q_0mF?ImJ7%f+ExEL*DJ>F%l&AZl#q-=GrOz{0Q&|~WM07@dlqpEFJ75iN zT~K8SFXSA^GE#`u=PYJ)Vdjf}&Gst@6)AEhO%A_N%#qaX&YoUJFL)@&Yh8wNcL!Cq zCJs(FfL$A#0OJ!|tUCbqZ312QHGk)QCr3dh3%xX)01Oq1?r3yBfNX3Q!$zAquq&of zoq99mWuGdc?_fS)(hY_NeY#KvA!?W_O|8MUfSna6SpgW%{AdAuu5aMp2Izi3ve2@p z0mX#4@;>t;@KW#6bRD2=$atLAK^)X!7r)TO{Kf3;WBGA~13|u#67yW=3az1ZK0i#M zS7q)v>jh15r3v_^fGGOB0K)y<{^9B08lo5Y6)Gsp$!g<TQXVHLj6aV4m)W2tK`j7+ zH38O5`3neWR_ke+lsW)$&=zcaRc$r8+Th|C?Exi_Vm3nTSY>D@fVI+-ACct-__hM` zoq$Uw5gL=K5bO;&4!%Gb0t?9I7tzx5>mhH4nrnkSbzINuvK_}Tw;?Gn0=E)p3iyZm z3qNj_Z3{3eovm1}fcf`2IRlvmERFV0rzgP7tPOaw{bdQr$*cPV_~0~X0br8XK+|OJ z1Hwh9@1_hi<?Sr!NZ_@A>F_xp_WRLV*9-ac8RCLFFb2tE`W5Q_n6XFw5^a12q6<W% zU9;BUY|&T<C<Y$@9|dftUHRj{%kjUOlD0YFpjiXzHMnOTP#(Pn$@-f%_e1u~U-I0) z0bvJK2(Nkyh=epFfe#Q~J;C6Rxc%<ke(fbI3cc!1UMBL$pEY**C%a?WtuEVbhc$0N zNPu8qNagc9TL-2?p5KkOVQc+i+p8!P_J0IP!jbt4@J8T7iB?w9c>x&>_&POWtkCnV zsZ4z$we)xfTM-c5b#>0GEzUhgU>m_v;woZLfGIm~;FDf}+YsiedN=N)OwD?3Q<7)F zb}LO^fwFmZ%L@AN2?$)CSu_oxI%HxO8*Ray4|u6if+lf5UYaTaE5rj>KS*A{11l>m z>`j-vUD|L00wl;CbS_w*xQ@{Izb9a#*l6zqY?;r#DkDG%!pIsiZPIncm{N64$Lcz? znuEsz-=M+X2Yd%++5OUl|A4twXBJD1*DHnUdiZ?`WC0ik0qqHt0h$)X<Yy!xC}QGm zASchIEOyh(dl-O$GGfLK3_LW1kj#(anY<pxKplWf9UP>rM%}=Y+C2Akcjpvn*V7u^ zi2z0{Ifn&W#tVpb*G*%s;N>q4Ptq}?7AvHLGhHK78XV+M3iT4)0)lNc(f)|ACIAOU zVLE9qK-&E@VcX7HHxfpoC4ESjEAcp53}TL9wE`Kl1}vgJbZ(JIk(O28%dwh6FvAM~ zIZetz!tJnX-~3wxK&)H|NRKAtK7>-vJa#uJ?7Lp(#=r-V1EQi8b|<<@>gwiMw2rWU z;W9~CrCyCJVAX^9cCFvB?aQ^{%iGjSfQ*Up;8rz)A6NG8I#a|d{(Sq-lfZ^Ity|Q# z%xMHx)KvoFB`~Nw{r#T-U>kaFz?TA(_rSLHM^kw@aK>K>W0<{xb)fbia8f{X;l+u9 zKp+C=KXE}NvM@3NmUFA?_@jh&vAw3<c}oflwxbkSk0F=nL;)aq{~ax<E?kR-AOw|^ z&g_HP^>^Ea8o>Ly1EKXcK^wi=pMeeP25Ir;%^NUVb7<X3vw|!GAp!_)*UR&RQ4c_J zB3>6Wa3u<?FVE+sRfMA34}LND<<*pae0-!752w%=g9rcv#R_ttbLty`TBgi}h667O z=>B$ldFjEc3yFq6iGTJM58LiN&Ji}5l+Fnturblm<AVQI*B*DdWqh4U_rTPEnUV1b zaN&u7XV-c8_Y4dabouFkG=l*E;4-gE2So1G&1W43*3#c#RA!OF36QpNDLJoEUt}4r zx0uNN4PdUmz8>5Xpcn`M!zNzWT_6`rz*9lUUVu{%F9ODS7?BH`-oVuPZmkO3s#!T< zt{s4-V^M_(f;U<a5_uXNEM-8+UYldlloc4ML}F9Vf7OjBe#gmh<n;%bIa+#pzBBUN zOHF>jXze$tGx*{Cnw>nynDb<;XP5!EA=X)7C^Tl#0H6U>yQ#6Uv8?RyP$ISP?Rv=k zUyO-h?aSIvtIpEE>SiT+g|u4#>-UDn95t1dm4LGX-7;uW2apQbHqO@vbFqthn!?VT zKLJ4Q?!8L6JK#_t%DkFwU}yxk+%O^ZpcrtE3j^n*<f`|$o9#G0I@%5(b5;ST^^r1F z?ziiNAn<wP`%NqXM1jWeM&U9voxhoxu(suV;LYXbWtn1Lr^OfvQT5~~cwG`Sgt~2z zj<U(LU`7D1+@)#gH@8Rec;uA9=WfG8%1lpB416v;>;?DJ_S4S!zaY1^N8Z=2wz=Di zib6LHUv{iGc0J+UE>Zd3E(0wCizzT!XF3RE<7?NtDiel(2b^6vahW;E#Z+L1-e@;i zgozbwZf=5=egXsa7JC3TK;d8@giuSz`<}G!<$F?^N8q3HpLPIO@r^?Zv^JxW9~39T zQj0S+Uk@xSK<jiMoN5ib2n~I)6>Pm+P~(=Dm%#+9>-+cbEiEnJx(JxS2ym|}XC|<; z76Zh+zXCU6f%)hM(DGXV)O&xFC5D>A=f^!^%!oeVsr<)g@^h4>t9ltB5dXxonb<8K z+^fmo1R8R3WV*f@k=&OR%&<TULnUPXnP~Y9<yDh_+5mMV^l;SRIoWg!R5EbhN?Tfp zY7IJlc?;FRo^I4l!N9dM<AXcl7HoavTqlXsNd=Rj8kJ~W`$#Pq0jHbnaXA{{CL^jf zocn2w+T*kKf%_mQtF9Aafy%_0%U9tmpNGEuu{~n!dBaPI@nQE5k0;?9-Cu(0cxt-I z=Vsp^opB!)y@YHGIniP?xw*JpV9~1MvuoG68g-#M!Dv-)cRWe<tHpM!a|pdg(=4-i z>oHvM^wVZPp&==k9TDRj2g{!iC0qhVPYHyP#$L;4iVoKU2kFt0Epg4VJL{{1Q4u5h zwJ8^bUAOSj2y+Nft8PK<_~%bY+nVaG>Wi-Z6wiAM2#rWz()$j=PU&v9&0HTM=Kqd2 ztKd(#{+B7Uq?-7JZoLosnk=^3q`Fo-9aE@vVqoiB^$ZcC{q{@(Jz12iyiTq0$7ea| z*zMNeems@E^*63PJqrbJo^vF>o#hxE1#jv&AMMb=CUL!7-cu-)?T`@Xzh@DB`qf;J z5)xDz{^(1;0elxBkDjqmwXDteWC>f6K$Y)8L7M-q6FM)5Hjd`i`u`b3@PkJevVdt1 z)~DBd4@F06@N>9JZ=|Y_nV`fYds|&R3hwVBWyFi2-?e(pT8f-BXXsq<wDMUj)dh>1 zv`hP8Inv<Tw+zj8-I3j1Z-=gecv$&fx-M;aV~d~18h0Eh^8nDWI$qr)00FPVzZ2B$ z4~&}q$kOq114=>zl^&#<(CS`+{BxF+v3~N=zI`sLGNn{Q{zPk?w0;bSSLo#!qf~=* z?9d*c%TZ8LZL9Q6{956MfJHv3GV;m;z)(^Ao88%Z&&%n{ldvHYW-R`?`hTgN9*UJM zJ3o<fi5%Txpp?Dd1&H7>S=cbuG}qOg1J<eC>SE52dLfFl8qFc>a?QF8eJjCYDSZcp zR4rwTxMpGO(E3A2nEH1`CiE{A_0GJiED_4fC1gE|ikkj~MW%mZ%59Y~-2`^ZX?qul zc?T1vNT{sy|J}W5tVvZjBU57fUYA{~H+Og08w88q3ezsxrkak>wrgO_v}tL3W}NwT z{^Slzea_SOziBPH8|?a8*P7*b^Mf>g3h<3Ma82lGXA51=_#ce`0>UDoX?-&itwG*6 z96sbo-X3PsX0un9G(~d#CuX=NBQR}JbgbuX)~oy`eM8$~pMmZt1j`I4RnQRuJ@p0R z8W?!$9hk+xDkiB9z{$ZIwt8UNl+2#Y0#s1{m-_F|g7^_$edrQfKwl1-i#~<W)CCY? zpMV7<=(;<eGfGWSCrrqq&JjEa_f|ylqLB?W3cIWIG9aoO+sT(hc0KN{okPJ`MK6^% zeXu|#=oqsx?Cqu12}ca{oK!?5X1IMKfjQJEDyrC-n}hhKE;cu_?{20g0w&oi@CkvM zXQgOT_7&7><tVKTs>><kS{}?<ohNY}x4)bC561Tfm&4D?Me)!4VpX)Y&_K_~+Yi_d z&&P*_Uo8mlv3`{a!LV1Fsek=Q@I^*Q{U2NUi4HZQy3A$XA|XP$PD*?x2kMP1=Nt=? zx3cM7B}Py2@#wKtobWg0#C8!Rt_sLE&~z#(tD@C?%d4tXpUgT$>^>`gden0oy0&YS z`gF9ewu1|`Naf#zKt5073vGf$|NY&X!L7kT!{0!Bo13<YhN@1<YqRYU3-`0Nm*;;u zeD2XwML;M@(6PlYG^c&rzpN;4i>yp9VvxHYDPQfgG+I9gMx47-UT5J=^fk5-RicqX z{LW=V#sruMM#sbeyA%+nJ%F*3%~VI#a*U+If<=+OJ?YE00t?eBye$XEp)#s(*;azB z7XI>^2JgU~Mdf_%jKmE6e(>><&CtS?ffw8_QVZKTIBMN&;vD1q_hBvMi&MAzrID79 z+yHl!1WY{2+<T}m<L+)%rz3v!sx2tSsp&xj-EXy9D)m3{L>7_6*yMTcnpEneUfl3z zvWm}RQ!1&?2Y|b&d2Ac5NmWeA=e8%x7&ee%&f})W>)=z09;QT@Gm36|i;vyk3Fw1; z^6$oRgMOJRzPUHAsQ#?oH4$mKl)vd~>sF@Y=vm=y6}dbhKDVeA`0xcwD6mSprrdJu zR?C+!N8_&j;PB>0Rb!k~qh$<#l@z(lF_6dzQ1Uys)oqR8M0tc5Hbq|v1W|<ARP*3p ztP>+{(GmzYlB?8jA!J?`UJw;tYl59ICKuLJH0^)t6JIWR;?$uTaleMnb(bjCX*ee^ zsi^m@vuRt4B-|1F=E`6?(VP<%qLzwVe<+vD^-W4&{w1rvG=-V`B>w0DWD~=x*4PET zZh5b&zM&;vV!&|!2;8OZE~=i!$mSrOg_`qW@}USJr`XY@+SU?SDLHOW`|K9OEDW>} z@@MMwN^P=o1cE$@t%f|T9c9ikU<BT2as3_p1QV0sy!EE>u1>M*{J*il5Aq8}B!R0Y zu!0L!+x%Z91}Eo4G8m9~=DviCbY3}jBbq3dh@Y(Ppt9YPMLe$OY*u6E^=$Lgi7{AC zmP?DV-Zz$Wmv;;|8*mwBXzsQhwj7gj(5pjjpHSFRGU3Ft*oSeGtd&F4T778!-Rb9+ zUNu(EOT3=#i-2|5^7ZX~d3d8@etq?Y7vJ3+YrbnAbLFR>gXAul$R_Tp45^<xStBNR z&cozf6-`w7F}HpRLnBsv-vhD+iS)b7r`F6-mEpHG=)$_&d8BtLngv<E_3}}#-)rit zif-Gk(xr+cy3+mf!dw;Yrt9_d(m(PwNBE0+e<mmZ^FE+cRfm-=!?KbrHaGg{PN^c5 z8v~}dY@xC(%X|L6zD#1&myrR=cB3HobI&hx4u(?sBNaL^m3gl`BIb9$(8#ZyYj7>B zL2>b+*R%5`rc;aFRq%|$u-I^ikik+d0n2vE5*E8k>aDAIF~fst!CTk*OJB?7iZ3z9 zzceGur!j*^Y(j_VrhQA3DmN-3bSkFt!ps;v)oo!<RW8?kEw?t_<YD60hVK`Rljo~C zT0A6FWCdK8pxpiPUed#3O0CXWm9GZSk^GQvdv9lwckB{<egAlDa{@0lKDMXMhA2fD z`okNcTJfuzUq8c7-wTyv_=?g6fGvSs(w!MmRd-TC&`06|bFAw_*kvR4kAGqnY($`+ zE!C&soGWf*Z68I|Pkl3GV>vqYsMMW<Hp{))eLqU6hfiKLNg_Y3^@^ISe)Zy1YcsWP zm$c4_$tw%Tbft8E1{C~j&P8-$4>{5CMqY@g#X#X^wql+Vw<gef2WanQI}8u*Tp4oi zvpO|3H6O-_HR68gX@PmLUK4dTCbJb&dsu^(Zx+^VY$a0#qAa_7#dborcE3a|y>EDM zAv^bE?ZojXpb^vcY<R{jpQ;ps!M%51qmS4Bsr?mKvRLY*7FUnHrmT{i5L(u-Rnb9P zsS>sFXsGgn70Mon(5kdm;3UOPns9e4uQSfW)yhH6-u3<dJ>h+Y<<F{k3Bx9x8nR^D za}L=mQ8!MswL*Jn=0145qhj^uk8=vMzm`^uNr_xz1v<1VW6xzx<^_B|E2|G6(EU>Q z|GNMLIRppZUJq&uRo+VNeCVl;Fh{YDO!vaG9!NrO*}2_ve9&BMd)!k`0wsm!2Dypz zaobB3H_EOm%qw9P|I_F{AUK!zYpiAN8zlG5^>tU&_OEIg%MwhNzw7X`sT8%%1lRpu zmNvQ<H|aHP-S%83E7$U1gk3lKGO-SrtBT=nSrsp}c`8jAHO-APs<e({6fV+*XshqP zdLffiou@LMqjx^vw=$|-4^>W4<&9_QzF~A7_t{hU(D~K!TlrU*xuXYyeP(V643F&( zmzwUK1UVlK&p!<9(ym(8%xqo=V9F;>9cOekGolI(PDT-<r%pA)#&Lt&=viWgA0R^D zZmayvBoSHB`RyYg#7er)loGBB1}}_Y{E?6JA8t(l8PBKX8~2NT>U>fMmjwDC#=ea+ z;Mz<%X0t%@1}s0qR)bF;6o~U$sVulN5<g`)3wx8f7I{Mkq~06I&$wvDNx`=e<8Jw! zp*$w!on=zO8U$jjSvmL2Kw)kQ`*8;nIXe-yWt%QDTsehcQV6K~4mAATh&$E@>gMSt zypPW=wbmxkk+@_&6F67-!~X}yH_8E}gI|EWBT;m4t*YCN6cL@t3BwS43aQ_uC1?ug zG`OuB3fgd29DmY|%+<*5r%8d=x&Y#1XlA~kKw7B-uFkTla(BQw6T$?%kG#CRtSoY; z<~~MWVb}kC_DSd@D6mH?0|g7)G~;sq@~2wTL=Nnq7-WtUw$;gC4xFfRRx>o{Oz~KF z7-%wq%#Scu3>B5N7G?w9Q?ul7k#|*2O42vbq<t<$pU9=yO4(QoC=2|ai3`rU)~Ck< z*T3`YBI<<@Ly(BRI%=VU*)~Emd;xopIE-k`V$*+U2=X)4;HqpRRtBLGJ?UVO41#M< zA}-JNM<g&1p->Q*=v(UN>3x%v9fcJ4DQTEykzfMRrV|T>0fXE<D7$aNNr21|+>vJ3 zuQO0L4S$p=o8iHMm+k?d4xxl=VIZFjNlYH5@hr5?;?bXh$V194>QMS6=aRoUK`|u{ zpCuA&k??7fg!e@Ft-Cu71P1j^ONxKGYUYy1jc9`E(DJ9i>OR*;dVAK&;k%374L=NR zh;$N4`?DU-Bh@-9gCTy;3f$$s1)ntl%;gHwm;T5%195I5P>66Qr6a{KEs14aWEnSr zsfRwwc*DqnhLnzvD!`a2$sdiWjoQOzEh2oCABr>J0)|k91)Suun>-k$p$i)+1VXi7 zAYc@vRc%a!RSpnKM9l~$g~o_q;cs_Zoky^1@HeL=-*D0xl_O6uI-{o#!ia#agu;a* z1bH6buS~0y$foONEG5l@_68#Y+qxH<6^f(-BM{*MC*P(#Ifx**W-@lVI!r4Ko(Yci zml-<`5`r#l2%Hprd??(mbdj=e_e(V!l$?mgPmS9SA`J|&f=Mvw!WK5UH)jY(fc?1D zccXROjig1*3YSHIfXHPsGa(cD@-|(-H7A#_eV5{nCveQZnx|0?y}kTI4uWxk&+{!? zInE)Um1luvELY_x<D81%4M!EF6KC45uX-($uU_d9xyFiCg@J=%8ad&|`Zbm7$bl_q z&cu?&ZmhEK^9Ijoe)R29x+-McgCQHP*jg)XhGW^5!SI6*6FEehj*VJ)-Fbd&cAO>g zxSn%-NR5KwBr7VYW-c6bY8f&mxnW!8UxqeO>0K<|^Vj&zDIVcVGp1tJ50BLb7jCVn z2F6r<<|%%coxL%#o7B9jq!VNBKTAwyzX>iauZC%JeNsO+#!LU{s$=D_O!2&Z)wr4w zM)G_KKko8BG<|nC*6sU0viBw{J4r%Fk`<C9Bq2$tkPs5G_ue8~b`nBnp$JJKLgX<k zN=6hRzt{cw9>4y0j_2qo-S_)_UFUV4uXR;_>L>1ccB{5#BK2{rfm!tVOP9(fa<#O) z3wau*7?j@qx*GcG+nasN5gIp#6z%1M(hnDY?6!XQf}Gm$fEUHh)oV{O8}z<^j}~-E zzpPC=tAgQB_AHz_i>NvP1M6CLZkZ5ttnH=Mj~ETBDIai@tWFF+O1ZREb^U|YtYHd; zcS+ccLgv<&GwEtB_oDV%d>^hj72Lt0{rlQB%xK`M#Th9HqAiK-H0wvFLt<wjh5u_9 z;vI3gnVlylA>*T@>tD^k19o{UHC>*rzeZf6N{*c%`!SY!wY5+TT`_e|y5FOsH?F+7 z;sYi#Q`etL2=l)hB!WS5&-Zh-r#^ooHnV?LTOrMHaNqcfZtr+tcJM<h$-fsaNNXL@ zJH1j%ozg3pxlMiNxHD%#`e4V5YxlJ$>ign4Dd@O_&pA4GFJ9mjxTLGHcB`yHnyT)g z&9&4d1Cv?TXGw=C_OTW$?4@OVGH$%TwQ0Vm`gPtRrGvGSZ!gNdF1@HMR(hJj{!Q{H z;_#^FLy-)V+y_e=N~I>xH26e&uh(R<FXqo38HRZ2?fO!K(f1pe8x<Cg@Wt%|wE~TD zy5gNjGYas-V7t>(=`sFV(NAM#q&?(*m?-s++~)OX-wqnj{tjFqKJnroi+9>_Zi{7S z=R!%n)K-FY_!|)PxAX1MIkIOlRC1>VNL?{*N}LVUs~x@&G%|cLy``eO{LsOJziQ=P z)xy4#X|-^W{X$QXcbHRYVYR)$m8ho2?u`!8LMdauHMU&SOxiL}<X^sC#E%7K@#67G z?+LhQKp7E}X2#{mMhNDor*lm*r^d`aB)&2pa&Gb6#I%e4<&-fMowIE{i|Rcm{*3&2 zeM3|F_oME(g%{3Q$rb8j7wG~77shGt+8AyHOR5wa_stgBRTt|F#Vec}A5PF7TJS!h z)o|YQ=Rx<M<D-x*>vuw<#dPv*M?AX$ut$4{(@aR}lHT76|9Ph1nhzPhO6}nn)L+Nl zF0Y%PuH_p4x_kcK5r`81%fjLNS20P*<?rRbL-C@9#>SzuF97ZVIG+H3N6;Nk#aG@s z&J|;y9vWT&1D(amu6--k?Jt=;JKEy3y=lT;J<u&GDWNQ7)|O};0|4nWUs(C2O=h|N z(Kmjt7{<fuGmK}#PYd;-qMiMqvF~K?h}_xZP$lUpX-V)DaT~+3sQckZe?EoQyZ7%; z)o>?R3rlJUG6`GwU%mZgk0Xu-PzzBn+rfhej>4Gu-^_^acH~l?l0adr6s_0=?KW$t zhO3;Yw%U%9(LCOgVq!!lFd=H?YZp&$91Su$YcxB4qF{XHV*B9b;f~dyHvZxQ=Xzcb zLqo$rs!4Lv+xGVMu*pRJ(58K8$2Fj4Sjwt*^$@fq52;9xG0Dlx!#coh0RFy`<bg<L zTVw{HcIlH!Y%y91IqeMtnK4nDmXAzI?b3k)Z$zA7ysct1W+~P6fF<5lJv=awWcW_i zaTEG4=0--rv<$OR{QJbXV({#LoDpX3zr$O~JaT?81x$yqApad!yMvkC?VeP5`jn33 zMO-%9{4>;){_E2vCI!cd5}`53><LU}6;_?(JX4^upP9;^?93~nB0Iqp>SK~cc6?A0 zvqzOSXf%^;#OLI^FFj;J_Lkwb$T)jk=j{PlX+iRX4QNfn4;ndMV14pHJM9W_DW7^c zkXip<!Ri99b^FM&$wrR(hmg4lvf36`R>nv0mUR4@ZQgQI<c-jvrlA>nn{s6M0Z+n_ z;g(L`L~Y>>^Hb*FTIWC2mL<CY?`4dyZ2a=}0ZW9&%c*5pFKB*ACUrwP1EQiBsuf73 z6<8D!w9W4=)@lqwx(YQ*>T%-}Ykeodae+}9zT$V{$C3ZKZ#>Zb0zthP3M%Xi&^)CD zX&)e9)X?cXWZL@Evg@Pt0)&mW@KcA;r-1I+U`(0+a067-0tslC5V#}s#aQXXmg;Bd z=_??#fRdUxA`D77un~5)wk1!V_^x*EhhBt+np#Ik$9FX;CwEr|R3+2%jp-<#ziZG? z(3{a)25^`=6I;G)-U4z9CmJY@O!-?}vHb+eEA@rPAT?M-b@h)YJ_kp(0SWRC2mmyb zYTz_@3PJ*lf}kQe?7I?$QMu|M36(Tdz7OPYnHdm%^)J@_7b|q>K})gW0e4C@Zj(kg zJBU}Xj}ABekQvztKTdFtKoH_I{Nyua!X82c^K1C>J77mB1>OOjCRjjbAouD_(4O7= znsXS=i|L5{U_Dv_hQU5S%<uyK!t${z+tVByrJ#;rhy}M8-eCnZ!%uK&{EVF7pdjLA zVyTk&4lTp2|6ZIRS3BoctM&m3iEvwJ6c#_#5?my!b3Hj8(-F`o>18QC2jSo`1F1Ux z>P2iO3yT+S^M>tv!AF7S_k?m9^a~xAYzaJ6#&?wXKm+RHX~1)k<F#<0>(GHYXg~;m z*T`s)U?2L=XZTk$G_{<?FLe$O=s3L8#gVF$It^fde0Tm5WT2p9Ku0`VvMnAeyC@`D z5B2pcDf~-WgayFHMsO;8ZoFgfPWjJoDuhETh6}qCXK=Iq&?B%QV2!8+CO~IFUkooG zlpTIhi~=}}(GUcmIlERmFfah>+Eqa)qZexJLeK%EXLpvvRD!ur>TD9$9JEV@Z=h=h z`!brRUxJd4&*Ogi@@4RAfd4or`)vs-RQvS7Gl!p(`c$1S)+6Ykp}(Pf<?-k9U7SE8 zU=@h>kV{!YQ80#g0ImdFN()}|q(IkEyuX%(M`a^7jL)BEiP3_`<=q72ea~<dJ-*f! zNQR|w_`rerkL3g-5V44ZSalSh*~tFeBSST|{SUz)HC0wtLgb81nPB)2f;#BxOYG9W zX5F2DPCH#&7-z<5jU|wSe%qaXw(0U<yuqvGBv9T^KXT)V-=%cQEp;r5D@I17c6C@? z=x5$T0UWT0XZWY*1Qgu_%|pdJoFGn3i}KL~^^4l}?zdAau!hFXC_w$!IGcEeUjbi_ zM(Y?XAZS55XI5-v(8^rY%Tc}@!!h}*;B-=v?gPV1momC-VAPOd6;q5o0;?DPEY#IU zGkPIItHINSA~UJC^J=x(5qPkqtzT~_x>lG}kvvt4p|D=W0ZtR5{==mOh8u#|McEP? zj<8fA<Pj(gzW*Cszbiv0WcsTpCGm!Q;6XtWTSm>hc|mnVATIl_tP)xZX>0N?EuO!w zv!35zZL^VSfOZ_Tmb1Avn5BHJ7=k}D*#%z+aHtoGhR=Zmp#3`Gj*93tgXJe!diz4= zfBtVM#fafULt&55u=+n8A&xJUT&c6DIS*`aDT4^iaBQS9n}<Z?1mvUNNFnf@2V;s) zoS;)kv~c`qeb62{LMJH4;;lK(N%zk?IjsIk6h%eD7p}Lr@age!NOZ=bK8Byb?#`Xs zubz<2FJdwH6#Gp@Z@|{|>DdVo%}_%9ha=qZ4fw;GU{Up(E&O)Yp~5*Z$Kbmhg!(b^ zjBfoq92$B)KF_b25`Iek?U~#Ikg|9}Z17D?5g%~lzC@1~Y<~hY`{3lkvb9`vHd2D@ zo4`M!6ie+A>@N7yhHpSluPu&U6z9F^Fcuo`dbtkTRUY~)_(w+wx{<iOM_zLX;dx-6 z;+Nr@&0k+<+K0hrl9L4Bc?$@v;U(2Whd^8h#<w+S9W+@Cr?k5G{tWE{_}5IE1ygil z_)aup!=kd>zt;QU$k)6uzCbM(NSd0<u;vZle1Fmud-WfD0yxpldh1#T2zDQ!0~25Y z$w&gAf*_Nu0+IJ+``7!<TNRMDVDFuHp8;2aVBREOiOGuQX-DXR!8Y!r+}`?cH{0$v z7C5h*{UB&h)Ly7qz|tJ|`{y0KXP3@-Pbl$uX)EY02s9}yD5Fs7C9lF139<JxiSIZ7 zUrn4?Zr$U*j6z8g&<cr4vaTrXGQCItqpi<scqb-^Jy)&x6si@RSf~XM9^$zw@2q{; zs72+JW!U|S!m_-B5@KDI#wGBiq{IVD@MNC8U_u&d8;W0@->$D@eo1L*cTdly7T*(& zzKgZPa9l3jywBiwcq9C)CqXi2{?z%ky53|0)(w>>8<toY1?Sr}nBCePM!U`w8bW)$ zI+tF#_yQ_~V2{3Oc}7Zyk;;JLwbYhvGN*vuN$8t5_~xGC*_&)Vx=^+}0M6v{FyQ?N zo)AdBYHy9P2RV&CEzHgJ&+oV2@(!1jnuZ!omA}$!-9Gkj3tlaX^Z6|`=$f%(ouFMM zVwI%4cmF@Ux{hRdr-|rq<jrSsf`1>Wf)pM)b!PSDQU@3i^&stLJoM)M`ztUg-RN$H z1ROugm4{-J7#shq3+E*H#lDiw|81PhvdTi<L>DF@ra}^hvm9PKxTDr0KUim=XWD;G zIf_l3KbE{*lHi-V^BGNudf4RUi5j~P)^R67KL>ZvZq6#a!&wJ)slN#`Q{LEJD6Ffm z)0w@jyzm^SIEo@x@aVJWka)s<Sgf*B3g$cB##vO2+zFox#;|RLug9ck34~#}s-^Ab z>RhH+{<CfMuni~!utlv_O=OySb9LZLm%I5fIXQW<#~@$pkm=L*VKcrwf`$&}RxCAw zp$5hSJdE9(=S#71kKX>xd23@|RG{ZYd7vPHG0|U8n}hh`JmY+zPJ$*GtC0;`2N`j~ z(-#lJBd_((4b=*SuVphP#s|j}oz^BPxZ#!4(4z7}<=xlO<5XJ<(}GRoDjT#($Nwlp z6MgKt+tLK@C-JVs;KK1OO1j^_f6u_c(D@#E)xVJAEGOFWKdTaYc+g%CvJ8WEeab6v znh{hgb1ui|ErC$|?Q_;W!P<QGa-*Bt@3j(xe1c?0){w___3!r5?ms6htB2h-;)f6K z=LjElQ1<($)Uo$Keve~a&z#G*aEE6stKB+h&Y<ek&2f^RK5`sgkb(MpPZ7$yAESQ% zTyJ{ry+mI8v%c*4b6%y3;wkpBT+`Jq4Ll9^{{8!R=+L2WP9OXFkXZ?h0bhvvRaveR zd<?7P-rn9Yu<t-ip^SaV74!OfHF8;?TX8KfFNY14L1lXxr)EZ0me1lRxuovoj0`AV zS@`%QQ*@-ypOj2}b=^gQ2l_^I?V_UOYUZ_OF)wI14qLc2n8PkU=zc&%gskJR_B<se zCDAX#vY}<+^M8aJ%=N0g3rGd?f}8s588;clQx*ma&(McKHNZDmd{9ZLxwQ0j#c<h> z{R3TgK0f+-JhJYY75=^F`5F0X)$-^(K9P~Ap)j|!sH|J|eP6F<$vV=PrvcM!?{z;v zzt(2>eWsjeXJ_>-w7tER#@}h%t9|N)3xi;WrRSEHICgB4&|8LwOL4`xG>mt4hBZ2D z{{3q;W7|!nf2ME%orhsr)wgf9i2q2@*|TR)MtZupj}M%nbmS-9-R0LsXz1u5T-LmZ zafFkLE3#gBO@*IQnDh?y0j?2I;WBMu^`A^$nxy39B%<i5>BEHN<k-3?{Hcg@q{LXM zcXoD;#qOEz%aD|jF{~Koj?pSKY=8+7T0A&@RAgkB<#YrD1eha)rKA`S$S_CDVspYF z5~;1NO_`q9b}B^qI-x$-{pZWg&VD~RnKZ;uGIeb6H%=aR3>s*j`Qj)>*-$0So_nps z#FwliGT=sO8lHP+@zaIk4|%)UhNT*k;dp|DOOyKr6S^Ga3A+=A75<Aam(nwrwo)`? zug2hCJ+^qiXAZx8Mpt(ng&qa``}glK83tZd%{f^#h&p}`%6Uk12uhm8Pj}G8HZ(LC zm(}8Zk_1?y6M+aB2l+)eH`&45$B!lOW&L*lL9GHY(?2lK3jb^^)ZZ76OJJ_~`juk1 z)Lin<uU{vNQeRDtG<*KS=@81WFZM}jS7_U%%JUH#fy<F`ap&M%5@GJfAR;IvM5qNT zo%@7-sCV-CoQD(JUm-Zg?9!z@BqXfVWQG^Qjr!IL8XG^^*S<Uz!V)Ie0!22VImOSo zAkOyGCf=@~-!{H2h;^T{0Diu5<lrWqo5!EV3?Y|4f6q#qlqKJYUEox(v?C(!OwP$| z4UU$2L>It~g~s$+lA5kWmyp(S`t)g@&bEw5VL#hrtfKpqSR3ir1X6p@n=5<BEPVgY zM%{sP-R=TGWZ~k1(5@FQbJVprk*p+@QW78RLK#oh(-^+;8~P1$Qqo)%FLZ!-K@O*? zM;{M=_xn4)f4LUH3k~M<Gee8+b#-+@`#F5*2{yIfqQXM5m@Xob-*=q(Dl<g(Gn(Ej z`OFrff%C}bz0cqIVk#=Cah2ayp$(%SKR$C9l`*O5dQB$3?sdX56tc|(7435;Z_h)i z*>xsZH>AB?BUvmgI5_jfz55><&^Hba8fEmNH$JAKqVj0`*{A~?K>+~)nHM)@zbl>M zq%`CA%*!P<Z*-%Y&uMlaHZqGC=XjKN;_go#S@G&ob8~arD?aDXCus<lmY3I#E!Nx| zKOK^emhsgeY$8&+vY|%ExJwiuWI^)8)u^4VKSF0~>+4NQjR?y_=D`oh^PD&RC;Ak= z0#q$=xIuGmDv)I8bfKZV3Bs^c<BitbcK+VkC?jIuW-L%|KiPfBy=eyvGXv~ALCwrR z^RFr-v}eu>#(R_}*h**7Q9zQ4BJt-xKR=iv`QnPvBy@IC+=CN?v2w{-0YYj;G^J3c zBV;3xD~x6PtSAe;f}`jX<uNt2J6&I%l$D*-BahwFY&)pSzC#o-<$zs+b`tZF#zx{y zJ<zQHRsR}C?`qetdZg!7)yHEV)nMwmy7R*hXB{;yt%Rgx(F3(E-~0)GbWX4K2Iqt} z_1h9n9A7%7eD`B?O4IP?zPDLk22}gT2L}%aHyLDq8XP1gBfFvuYc=GfVRf6B5()j( z*dmA!!Gx0f`Vq&vIPRnLiw}_eLC?^JueXnxnS>nL&w2>Z+EmOhUWA71{kxF1KlAhR z7)b&j`+Um_6PsO`O*%)<B}=)WXKHF{XgC1r<=l$L6Y~ajk`xl%ah3a&fk_{Shl6I0 z%F627l4mCW%#^zN5}N$*;2?-X-oAZ{dX&LNF6`v>`^PcIaRq-z$aNU^%V*qz6&9Hg zV!tn4xNv8>o$5zfL4hzoe{M}pa+Xc#6G#2^c*^eE<B*@i6fp^Mv4F<r`gMZqR%v|& z-rw*?-WcMEiHS#?oSm1^@)5lsA2(0Fqk800t^I{FXU?2Ie_l)LHBOPK<<xE)3={#G zu=o5y<9XJW3o7_TBRHfU=I2AD_jARAnwq-x#c7U!>F_lzix1+-KVam~v!YZ9zWEg} z3FX3Vo<Eq5-e(+Tum#LVP`Zu0GolX*%3O}`lPX<w-$IvSB%bowv7({^#v|vhIKC5H z?W%1u=6DlD=Jzu*A%Op)>Kn%;M_qRr(>H^3M(_C|-L_Qc$&(H^U!bsS`aCf{F2P6% zo&Th>g6P?F4SUkl$~GPzO4$%|3UrXNsdm*`CEx_Izj?F6Y6X)f&K^fcNsEj6`u@iS zDDzTtUp7=#Nh>HQ$jd)N)Ij5V1E!|V8Myp00bepUW|!^2hK3<}63Ebu!josujQJU1 z)VL&ZA0r2g_nMcFjg1Y2kSI+FhOeY&5^l+lVX?Pc-S+fs_%Pq>JVjF8yXZbVIM`Zi zeDUHbwIP-5DFz%vtg%b)b5!1EtWnX)C@U);I#mAXQ6%deA{V@&6Z9Y~A7kT>SN^SX zw5sLldqbA4a2utbe0Hk8;O{StvAakI!O^RgU)9+77Yi7r;Me;43D4Dno;g6+;+Y3+ zo?Bi(k;y$s-OL=Q$bH}KPh(m5_;bfz&9Hr6)a~pJcxnH#;o~*S?;n|%!04z@Xt<Y` zmk`p#+Qlz-A-})9qk~}ntlxxY^gJ^6aB}MEzD3*ErmSzr%*|b9Tvq+`DL^|r6V~T- zfCYe{pripp*oEc0Kaa<849#z7aIkHyS-J7n(8ViP=KxNv{Q8x@UzNnbP+X1zFnhMP zuvxvczz)^fi)VCn^euJW7pFU-f&v38U2KWuGs<DBs-m*D);Bhmhh;oB7pLE2I&OJ> z4jBK;pL^Xw-O(wO;pgW+etZkIHj<WK9!hxqL$<Pn?cy|2G3wyEP+H7N-GNyo`kE3Z zA2dS-WkWb?00R+s)`W))dSar{HyJFuc-a49#V}wV1w}>0<Hzq|Aa-hAA-^UbuJI6^ z#dRASG1f>(Yx$n!CnjPH$E1`K91@~=>J;AQzR%su+sK>feEqtpxVRHf52uFIbc~iz zjjkYHe!l`XRa#ma6z_)QM0XxTN}g$4wgU*I9>*Jwq&^tY(Fk^<TfG5y5DXk~FdB!4 ze}g#&%gr>s#;hEbm((=9_qy<h)(K5HI{j^!Qgnn9p<KnFOp#brS;=TeJworR?e2=s z6mRVM^)F%jd?~+%b<UVRb9i7_ic$V6#PS!!Q-<s{twb|T&|I7^{p+fTiv|AgjsT<o z{B}=>X_O6JzkZ$Iw@NH+;7$t53qZb;amcENlGLBlJoZf~c1iP+A$zzqUO)pc@d6;d zFr5{$!&)y@rlLy5@El7#+8QVN+EXbzI5-%fmXP!u%*n&Hvf%+PJateJ=jo><B~=4@ z`kjX4f+8#*S(p1;oxdN;XDs5u4%*kEw2Dhev<t2@!n7r%`DtcFX?Ob<-nWtxAtELI zdsoK;nQJ<zXtUi(rg^c|@}8?U1)YgU9~Kq@4zh@djHITg*VEDQ!iXwH_7$`pVRO&V z!+xU06<KEr1qX1~1}rPAUrdcl&|c~lyJDi^iYWs2iaC~pIt1qea*M=MA`R2K)CNXI z!pASUPyf7p`u0VphI>0-I9^)@9*z&tRHVN4w(7{CeuIQX54v~ip)zz0mSfoiV$_it z{6rd`TgM%bDsW7^b6>q4c4>fX#J$jD54XX?8hv}VkRRHgL@VwcP*QDvak}}PwL^Va zN-Ds-@aX6Q_xP-s7dFGX&l_yFoQJEco$YEwcOr$UBaS{x<=Tl@tiAJh&92ZeBA0n5 zep-T*(SpO>;e)NLV0OruNA>3w)tUs$EjNSIb3e7}T)5b&H}r+PWfX78bBB|f<i9H) ziTd-H=r`M-T#E0zo2sW2I^LW1ui`bq0UgrRpU)5@GV)+vqBNdF?Pz81@aP65!@BUG z=gh4ty=NKsM;)%G7(J`wyuN32kpS2DA~e8(S!7IOA4iBU<=yd^kF5^H%7#{6e||oP zp*;J3YrcEtS@&XI_oSJBw|y1v92e=U`W1uTm+EZRphC$b3C~K~LTXRryKTh9^B**X zH;DdD@t#)HpEQ!l^n5UUx1uSs>+|=z=gpVIRt0w^NZ1x@Oby;BQy-EX`EQ_-*+Q9m zZ|}rT%9K*>QpEm&WlCFahbXN|T4S9RBgO^yH(vzxU3H)3i)fOL@cl0NGMD!A2YPJ0 z{D%)o@&dZLy0FJrJ&s0uI6bGB4kpsRBdK(bD8s$=Rmk0RdOp3;r(&M1N4i~Ab@uax zw6nV3S1gZDzhfnhP}avUJE<=wQVfQCzFu9mQTXJkkz(5iPLtLAcBW4p#7T}fZ`}$> zeB;g=GH~)wU(>e=)ImZcXI731jWG|Yd#&$H$wDYo`g)%v$yytC^IxO?E_@;4C|#Ih z;nQ@|1>ez$uMT1QjiZirkT#Sfn8;sc`cd;!dcpqt_t`(y{&D6h{%|@%0lWDmGxO{T zfn;+D3Fl8^V=LawQzo>ELr+7*l{Q>=6_{Q+$S=XwGh{OR?rK7h{McNYI3M5BZ*@wv zaMq3!-Ac_1>FfQ`%r{U@b@=X3!vCK5(Uz{5ws%!CRC)_UXR~$Xp*^;7x261kWh(7o z?<9>)LSIwg`IKv^!iBajbhmGCdOzN3yHvXRC6DKP(;1%^rcBzBEU^d5g%#qLh<6=F zDg|IrRZ>zC75xI!VSY^C$8aZgv!sju7xG3nZ?t!g2FN|W9BZO*T=@MZs})9#!X6^g zgG28!j|K72WIt;ARY4^4jb)+!c9qM^Dd%_+o#nyr>%sy2WT%DoE4*IPpJOWc*!W}O zc_-u35`oIf39|PwQD0wS4st~wt*WZ(;P3--ecc`{agnkUGe-{U%(Fetox7%xcrc1B zeuD4cJF{m=Lh+$f2E@&VrEj~tkD&`MOG#wze)3@dBTq-Ak15~2eof8Fx@=+b&OTta zX7a2sKV6zn;N4ZZrF(oG>c1(-$ku<1vP4WZ@2~XYD;s{A8E`^F<D$|qD--AUps9b- zg`ul+qpS`V3u~Xhzia%rOKQJF6JoNVx+gWjgDW!Tuz{yXu@P0CtJEWQgB49Or<R}U zd--bnirVH{reErms2pun$bS>7^(3EnHOnQhR*7Uln<wx0^6uY|X_HpcoL$Y0|Fpo- z3mR=Q8{j-4igEvYCFIJqifwN!gV^9U!;`Ck7fSwUMf_W`xgc?+F~n_TYEyGaF?}xR zK3Foda`LLSvy@x_2E^X}{IT`ln6K0EeL(}{E4Sn`q+j@ZL}BuZk$aydF8E`i|Es^2 zS*t~RG?C${pO0x?>4e+;i@dB_OVQv@^C4ifkVB8YoR~CVm-+T~)Te=#T|u=#_6xQa zE<L3opPbTqugh}QSFbT}omW4i@XhAxV{&FbyT12+Y`$4~#T`~^m$-i4*-hYRHr6Rj z)Kg4<Gp?2RGyd@BPZ!-heEV%lb*KbBJJuoBinEnHD#UnT^iRwCoe6eja;E=AkMzgU zJ8P8{{Ff>is4t?(7;jAZ-{ZR7ncw2)TS(@9ko&Dqubi~vv9-}~nM*ZO|Mp<YrJ=7N zfa_%5Y}>q>;JuZ1PdBQB;6bwxO}l!VhE5Knn;}KskN->?Da-f1cuoJA3Ph`D(hmKd zg#TDuv^B{59B$sEp{135pquvoPtKz#eOc1Qf4&TyOVNjSioT|b2nVa>rGFTkk`U<4 zuU_(V+IoK3`^Rpla@q~S9njNpFE)pa*IK%T0wanxbm>iMev*H1aCD@nqH3ttJMOWU zcipd_EbQyHeH>Y`zEUuqi+~e-0O!Y>cW<m1f7HPIvfT7ftAfAoH!tyCL6vM*`ZoIN zQCe4h3HIIWm46x2sq*i#6Lu{Rk-l;`EppB0$?m_hBQMs*5*V|tsLS#MD=qTu6;3|1 ze6D5p`Qjh<73n@UzBBro)Cp$gT3Um*bgLNueHhA*ksLHk+v-!#ZBwOb2zo8OhlTa> zqw?~dA(K-iqVH&5r|y1GxJZ$n8^@r!;H;oZVS5#PMc)-l_Wep>cNwk8+We(pc8UM8 zdT`S9S6OW>+w;mk_8oe|!IB<15zea~&*S14{w8m2Zcg!SocTwyLUWiVeYEb`vwsvf z1zKeqUkZJFjqzb)V_fUcjT_$cb;>Q2+Ek<@iZsd2XSsqj1Xos8)NbFq@!ziUpRJ{@ z*6oU7YMlC-ic+hZ{G(1wn+t<Nfnr3VGWzu}QNp+%oS-U}#=l&)-siX5;l=f@Bc4+! zz`?lU!~FK0CrYem`<zT?7<l&0|G8`aRGd}$fv$T`ujx|`(<_7JXG3?&53^@9^H6RC zM=1N%?PYG^^|kA<Ie>0Ax_tB8kY-n5Fh8qk<L8N;iQvOKT3<OH9TUjf?=QhlqqU%F zAQbQ!%Qa_bLQ>hC<qz|<^@qYF>3xfdGcPml(ZjfCq?a~hUz^VP5b+ydN<Pg0%xzWL zbn$l@X!M<T)t~ogveiC{%)1tKnl>)|M2d8{(Apg6-`)|5BW%y08b;e`=7@HL7W)br zc}%EBot0p(e&C~^clRM_px$9dO3UurXU`1Za$9cm{`_9|`Y=~DN&h!<$<&_R>MX&^ z1X7ZKoSYnevF(eb3x`Z~!~XZIzeUmv-c#Z$HHx(J-e6lh;#SK<9WqNlj~emb*N?%Q zHg4TRi984-*VQKq8nhelEBwcto`hQ_HtCBcYYU^p1&o4$2XCoQvCd(XnTbi-c~Uj( zRe-?o-8XhOVra{T6fIkc0#ug|n&(<oZ2+|s(uyWp*FW;(iW-l;nE~k)z^80%bM8&R z`E^BKE$_c_<-d;~KVnduP;=HI&i*hDf$<0XTFR!0mwUdrHz6CyU^@J2ad^dlYJn7C z`>5V=e%%_qkrNUcstl%yQJXr1Wap4?SY($|%$4{P?I)r2(AQ^-{=92+sD0iI<2rC0 z)Tu1JyJ#XOEXZoGX`B>V)bki=N9}9>Zfpz=4aIQDMV|O%SZb7~pQ-G_Rm;ljyL)eJ zX>r=Rz`O5=w3w`d0_U&yrgR(fjh91qlMNy}rbk8yCTRS1%f$2d?rp(Q+zC$@rYCES z`a0zhcV5O!O36M?7O8-PYWp`uHZUTcbF{Y?ycS4j@M}$>nQPw&<zB~=TAVLvsj2@0 zx|^rEUj5*)VdL`t!SeXOffkBPOiXC4+K5$24lmH!?bOqf@42;?&fAuQe+?NMX=$9o zm)bbgonQ4Gj_P2Bz5$fRFHY$RP3t#yGx}FZkBX~DOnZ9KJ`7djP9;0erTo-S#K@|a zlu^c%=s6G_0-kS|rkEA`_v$je{Ks=q1ufGp!7|MpO*ifA`t552xj&3dC7sl%?Y(~T znDQ;+vO?uQf!xSf;*QSkb&c-V>+ZYZ>h?{~pX+F~n>Ne)mHm_9Ps8K6L{oGOat|hG z_sRPr6%Jjn!tH6&HD*d{-HW0d{>8aM;!BKGraBTuq(>J%kL*7E8q1YR<tSW>D)9ET z_3g7#7`tB{?l`O#O;4$MDntG5;ZJ9Le0;87FM^t5Y>_J_)HcIHt#fZBnaRi<YR9)1 z^E0|%waZ*<OyY~p={vEeb$@atpwi!Ic><6OP!>V*--VPX{1?8FKPHyEAlyz$N{U#3 z=ugR2PWu&FX}+H=`*F{cQ-H+Mj_;i4&-S0OZ<KF8j#ocZwq7Jnd-^)D=GHY+Mm@2| z=1Rmr_q{o*RTMt97^=*~#np(Oc;QY!wNu^Lt5>gXFCU97LyBT#BngvMR<QCm>3*j2 z-yW*g4I)&OHQcXVOVT4k1lFCc_q}{0=k?+b_sYS?r-YdWPP40tIeR$Vcb;`q#9C)z zVWIjoq37d}^f}zWRIbfp`BIfhbgW;WM{A%n_sZ2zl#Rwuc|u3X-1{GR3sZ+#eLYLt zqRKS?qY(j#XpWqnr9?)V&+QK<syE>Yr+v)mE5Di@kXpqPpfqG$#>V?x`#d&R+QF&s z-)Tzy`E*cX7TsS7T&*=LHGP1X=TX&zhDxLftk2jYd#}IB>7xl2?}WPNC&gXHs1D8? zat`S)QfNsWNNpW&-RiIkFK_znI4c}v*kL98@}R0pfgMoJQHM}o)#)&q%!KfuMEO?i zvT1q!0`)xqN>bs3@yL%|T@x>jxb(R<l~!ydxVfZj4%%!_YC>6cSN(PVG|!f%W7edW zo3Ui-NiyO!fHX*Du^-sp*}1wh<3DAYv`iFSdW3Hx>T{dj=>o75(iwb@J00sNNJ%+q z$t}ZN#>KosW`bj8G^Hy0B-tIM^l3`(R=(<@3AvJIGl<S0JF;cEjy+1V)aYeA$*uDj zjrCc7a0^<NuqtNJ6SdvSwLzYP6lbvdRWK*vqwn8W6c&bfP;9U=3b0c5+XmAkvkIax zlKRTyQs<SZPa72I7`7csPo{A!$k|ibnxM*0Nkb!aHT3eN0e{z($SY586H|*<wo4OV zYQO!u0x2(V-n{Yu2ygF)QjKih03$J0aaQU|*4$PbnSiMpVA`+I$RJ1(nQJ9Cc?K*4 z%qRQNTtup16BsmUFqs&Vsu_%+XM#4atEk}RnYyvheSHW(J00{#jAhiSO8=uuJ-d;t zvq7yHT`$91I`Rmd$=uYZw4`SDjgU1y`%s$PGnZWP`bhW+3lW7VOCN|R^+TCnB@vb_ z8wcy_K0BuN%z-^wV|dzWq#5>#iIbCZJfdUz<40pNqR}Ij-r;k&yNOZY^p#1HbNr>m ze~D*a=8EL$i>2sHMV^c!B(&xChyQvwWMAb#L~IipX^Rz{V!h(Qp+L?^{7jeY(2KC_ zV7bbL16i!kE#mr)aguHRvJ6aA65Nw^C^cwL^nGHF#A)q5MoQ9D$;&TqlQT=ZkxX{T ztC{uo_T~os{_U<WbM7t#5$sW9Sr;Kp<7DbrlDkMsbl@P3I&qGgIO=%C@Lkb;IAJsd z+eih&tNju;T#}xYIXHa*?z3EaPGyH+H+SAo2;CecsxK`)prB9>X1d7Yv~VJ#p|;mU zI4l5{0mFc;8^OMT^cEHtPmIg(2fsWzd8zpR08gh6xJ|&_!0i?xxB)I?E_w0VwL-J< z35YI%Y2fVZzvhh^7!eVHg9au3RK~4^{2wbGuVZ<)pkFYE`Uzz93Eb*$S^rDZExM8I zDJm!^C?(|#v=}0ruL{6#>`<!PS1llq0S7U@4dw8mW5*hbipZOD!4HVB5~MJIUfSB) zKvx2Adcr*nK)R&g7O5A{+!xJS<9T~4fv91LOj<#(g1kdKSc2B|b5orvKb-ofu3i=B zybal(sxcyQ0o+<yTZ5@d6gks(E8WZ(na(9fk3eh}78jQdEg;M*SoAQ+abffUfL>3W z@PVGy|D2D{4mk2b`#Ux^v(QH{@CE-;ahgynH!d?0M+9Th@b}S)Zt@`FiY-89X_=Xi z^~C}M10l58<4+L#gXVi{g_JqY%6~Y=ioxcPks;?KB{lU!K3xC2JUl#XY;wry@Frw% zO-@b%9@H*3ZdrYE(Ba@8rx%;Z&cP)kF<M9L2TSmEH#au6q2j2js>;jD189_X|EIG; zEW%BY9opXBE-WH)HPg$~^nr#TAir~f%AB2@U0h^}?l+lB>PL0Xv<0VvEfoZgC@J|9 zY9@jxE;bf~DN(zdA|^)*Al~@=Pphk2{w^HUO(py7>f%yhNRa1&Bn7bBdmV`jTyplv zqXD_w1B`dR-UnJ4h}rIU+u##%hHe8TQ~ii=;A=?olzNG0krW>fikg{)<>F(L0M``& zT3VW##6DM$BCMlBeTN6qC-$goh&{o(#`l_<n!52Wvn>m;kV^xFG({{Gmz&s+oRV_b zfr2O|IyyQo4)G)#5G(YP?AyBbwS<Wn`79iL*1k->SO?+rM_NAtngk4tYKLb4RM}~@ z6{1T*bYyCe99J)>hr<@lVvLl?iyEuAqEc(dyKi5d<P3U5`&voUr^3R*q@5of>*{K1 zx@?|8DXM?hwaNr))^@!;&I&wG^zGfd7pO7-@m6bW4#fR=npatce3+Nzq=jB@$i9{< z<~mmS;QnkP3sck0zLN}yp0TU_1S~ys1`@vCn1e&q1(Ld<kqYv>gV$#cFdJ_ROaR}s zo1!0Vzc5|v6b=BU+~>QIS6WKtvom`7Bo+`>C=^C_+})oUmn{yJaaf}5%*e<HqvK}h z<;{wZuY{PT*6eK7s&p?!j`Y^2|Nc|K+eY|9>)&6itE5Lo+1pw|h6CaV1TSD71uxmB zxs8on-lf2A>}$QS5W(L0zal`w=g$N4#+LgH-Qah(My$Znp#^k<f4&c&D;pBszu%gX z`LAm<&oRS7Lx7Rx2!CGU1tSG+E@0<EnX!nd=zw(hyLY0tBM#4g|Nae{S)4V}-`^im zE0bFlE&sT*)KLu)aZ6|X0F8Z0N};}3Vp7t%Oa-;`lp|`?X_BS-V$cbtWMv&<j(8oz zeWQ9bTFY8fGej$2?YwuE-XBo^p<!V+Wzzxg;`%*@Z6M)@=!pZU4BkjhE#SkvgOgK^ zv~{RfKE?vPokBYz2n8czV(1tc2&j72fro;+`o(QDQS65zqodc>*CEi7T>Av+Zb(=d zO~}jea6%%?(}$aYsnJ=0Y~G)cni`hv05t_@KRPNZAon=>Zp2lhyWp;BLgMr>lrt=4 zNC)w{fL;3_@6pHG8<uH;D0+X>=bvl`jj?4nHaA6tg&&(YF#k#fYw+QL_uH;6{=fpY z%SRtXZbz{(MIQ=L4tXTL`budXv5HD7q^jGP6F@f5X5I!l4R^Wity^~#v#>C*9PvmM zv#E4mlIDX^mhp?YGU)*MP|Qp{o{F-N&?~DdTtNb+3i*6}8g<~i5TeCO{}pq}yBw9A zFA9^ozF_2T-@cuuNG#ItARp9zdm!6up%h9TxuZw#DP<F=B0NJ3RDcH|qE)axDkLN% zAdm+Ze%|c`P9BIXlz~kd%^;qx%0vnI%h4`bQdiZ%$yfbDoh8T-{og~oV5wO7G&7va zySktN1L0ll1pihb=1Y*WWb_*2DN#=$x?>%QsU2=Q%!R>4N&C-HlLitrbel;0>FMq5 zcmfG2H?sYtIOQEi;?vS7E2BB31&<!(cy$Mk4N}c9xULXy0-XL-vnBF)ku@U0e>$mK ziSIq$<*691p^=fU+vE6=9|i^xPD^ab&d&bwgulq?!U6my2vLQsclaMv?tn%lP%U=} z#kG16qBW4x>R4rhriYZI4cWs)-EU&YoE5Vm3ehQKzJi|u0t7YK`ZPW?pOhuhPbKdS z=c`xq`fbhY953tWM1FRp=+(_qWIG5p-d#_R-aw&#k6;`W6~s&Ew6=cb>^fABLW?YK z+s8j%jk6GEd|YR>RYxSDlKr^E�TJz_cch6cuPhC#%33BMijr-o2)tIRZ8MmcQxq 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 literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728-02.png b/extras/mangafoxtemplate/728-02.png new file mode 100644 index 0000000000000000000000000000000000000000..56326c39a497eb41bd717b71023cbe20933f2671 GIT binary patch literal 18576 zcmV)(K#RYLP)<h;3K|Lk000e1NJLTq00P(m002e^00000(@VU=00009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-ss77rE`sP9%1001BWNkl<Zc-ri}cid%Fb@;t*FHf6i zX6OtIMLI~4js=Yh3PA&i2Cya;5RHn8q9(?YNYKPYNq#Yj`fB_oF$PUuI|fjMVS4Y4 zY0S*iZaL@dzQ6Au=iUdHflp*4YVxu_AIf?5zU!P-_S$RjRdxY+wmsYa_qF1)BzU$x zE7;GrXWO%a{cL--JuBGHwrAV3g8giJwmmD@&$ed;``Pwv`~SUQ2a(`K@DhTEvx1<d zBUVI25S9O*vx1035hqb36EQ(t5FZdDf)&I#5#vQt5d<N4B!nOcl87@RUc`wg5i8;& zUL=YYFHDGZM7+yE2Q6NSh!-bTg#0rN5(47HN{k{Rl8O_=N+wREEzwIRT0#^-#EZlr z0dXQhqz`YpsT_h8$?`u~5igL41kqwdv`EBBjN%X{A&M0vnUnmJMCgi$iC&xpBUU5` z9&r-Ii}6AfB~HXk6eGRg8j%<z=A;bKi4B4hkqA*lj0h6;gB$X1jMH?IDG|X(u}J<q zCm|EbkSIaKdl3;GL_}1S9Ce%Xz=#jxjp#%~BoPrSUc_0^;zdM)kt7Hb5iw#SVnnP+ zPTI_fh&3W0Na97Jh`9Vef;fpz93m2p#H{}<2i7>y7E&OB_e|0S3xEO~))*X7TLOtA zpiwx7CIkr4=7UWO6bYC~fPnD?91uKU&@DXCYlF`KYgGzBj5=uOLf4Q%M#MVfL8CMd zG<fYuQ6A9H!2v2n*KK1g-~nsKu|$u>gEmBB&_rN@0Fyihj~;@`I1hB8HAOTKg0jFA zw21@)-~%>*vrJ&f!Fv~N3?XFTql<v@U^N*y@D>P;kme99C{jGpLx!j2A&nl_0YfWd zEG=?+MGXqHe-gNvfiO*{PX6tT=lFRdnjZTSVhXJU3&wc`ofx7IgrHG5+uInR6RjeI zNw6U?XdG4%Bfwq)(MG1gctS1`5i+dSDFh3s2#zTN&ZF8sr?AF?&nyJ629g66&jS|h zB%+|BP=F_aG-V=UpcTP%X@et-gK+>IPXtr|K&NCWU>L*YQsX=w1)eq;C^8FJCc%Lv zYv+@}cx%8yf-?9Jf<`Ow9(+as&?aYI0>lKy*$Y0fCl>=C(=M{N4MYdtVA?6*a6ro$ zA|%cdrr|xVMVxNuGUW|XgC#?Ez!SSzoTo<}x{%UAE1V<t#EXOo9Uuk=T_%HxL>IxN zU>t2S(g5hdl%kc3o>h<n8K7}E4~`BQ1Ts%F`@uy!a3S>RWMHEA{=_>1%7C(&BU-@F z*$a+<_Mi+9AOe;wk|+q!wYe1L)CN*a1eIXAE_m+&Cc4nZLR2b=28(gMAEYTRP9#C$ zT_h&tG7vM;T!+N2GxP=HS1Z_%)Q@h;(E}&2Y(!=FHrZKt=mzL`CSC@(m=lJO7y`5a zT4a3<Z$Kw6!sD}?+>eyAz6?zQSmlT+pYC8C3E&OsdYSAArOm+_NE0H#5wl#R4KNm= z+rp9VB~B0msU~XycO3j82pI{f%Rh3;5$XL-I}~&XkAnw5$F&I=fqcaP2ntUCBHqJ- zBAJ6M2Sj4Qrhs!0Jh2;zDZ~It2DU>m`4SZg9@I~2=u315Fabi!R~nbn@%hUfd&zZf zTM^faGX1}kdNBLKH4ft->(eQ+?otBS9KRTdt_u!D#7z((#VRy8h8~+EvP8n<%Oc)- zzx!%*TfroXjD$VlLF;@Ow4lB?_<RS}qXPGj=2Y5wA!G{d7%=|Q{IfM4>wMSyBzSDZ zIQHh!AF}+PU$J0&4e8>UsSPZWTuj^87=j@NgEuf9$zU&x174B3d?ieKjA(ldWF9+h z!^{_eaV8>QXoJN<ch}K5bpu8_AXzGePET!M^&^L<)IhGcbJf8lo;}cskcCcvT_Gdl zF<VN@ebTden8Z8X22c)deVBv{S|s%0J+7%pibmsG=r{@BH=j%lbRdmuX1Jax!vy*N zX2v;~@N^TvTAas5ppzR#JBh)0z!Boc#vTPs9vn#^&?+nonusI8CG<2k+m5BRya_PI zL~af_*cUF~`+CsoM-B-F=%7fUO@bnj1x3gSoJGcaGu0-bh(z#^E^W|qWZO<g(TM;Z zhz2r9QDo4uI(Umw<E3Sq0D9_ZSX`vl#e3*DAQCa4$-1ZxCgux*&zHh1*D*OSdz$c9 ztg$^lY!aAYbu;yJF*-mD0TS>`<)(nbLI{xrtnGNZpr_Y%;}SfX$3Pm1YleJ6Cs&)X zi&KgeZ&}g|8cc8iMq#%W$e`tbv<n*sQJ^!Fr|TdR4L&!32!@`9B8JEm9ut-~6|@ye zPv-}C6f|)v|1#UtxP5rjTZ^398j=j3D_#vNB)5Y#VU>7*G-ir?HJ=D*Vh1`zj54$V zpX5uecN$`h(6xr>9SfTP`r$#qo4`+tfH#iG-pbzw(_(D_R*Fk#10nyG)a?s5F}Wh? z(<$Ox3Wu3qQR1FHR5u3EgR^wegf>_lx%@7X2(Vl{Dau7Gs*CdqrRbSReLAg^o{0Q( zG^+IjfYHQ&3R85^STfMKi0!SqSx{XfiFS|#6h;#){?{Pb&N;naNMK>{hnEarG@lLi zWc%;UKI9z<bXZwrLFw;KIe7l3hmZXx@n;t{XWi=pSB;$Z=@}Wk|A^Z431h$(!Ts*& ztoJJvERcn#R?c76QT|hNXP$T)A-#TN;Qf5PA%|R-@!o?Dzp>qB_dDdcJDO2@;6KkE zoU_D!Wl)BGzvbYe#y5|8&O?7TW6lrY;nSNZf0s4odrlZVcaf)c{fwjjR0xZnJL}LN z^3NlM#vgUvCyqVn#M>NydkTDejv>W<;go|$f9&|+Ni*ku82+>P7`(h){ts>b@F=+Z zEX;e3FW#8YF(h9;s6O-6%scnsx%aYg#Bs|hdoUk8Xz-04pv{8n&(5m7cyXZnxnm3G zegwKOMf~)+wc~!izV_84K0xc%!NyHG`qs5GPW-HJU&;L2sLZ`=9Qdol3rF1Q+#Sab z9{<I?VYPg1^b;ER;tZMfvWJG|pISY4Nmtu<95!_QHah#kz2%fy*G;i|exFXWuUK6t z3m-pm=FuO9drS9RFzd86Xh=|Zo<8HSk6RvWetpho2q7iC<)G5Lr>uJPrqbb`tA&S3 ze07%0`kmDkv$}ToSqGi6$ujlo8OQ%+flf*{o%rxEBXd3iUpYcX|0v1eUuManH{34| zoH20T2D7k0c;yMhANDBEQemxp^N`aY_{^*$zi(N3YV-7;cxztvoa62knE0dNx!3QZ zn_Hm2V!>9xyjj-MTGe>NlzziGak+5YOWC`HNnn+z<)u5h{n&T&k+U5?Sjwl*Fudq` zJ@G1m*S)fvzWVnak+8DFTYnp~1hCnL%J0VbnirsNId?qUc-n_}`<2cwBdlzCc-wDT zb>(~T*IXU!%L|d{t^Ub+J~tN@HFy*oSW^5Xw~c->e)Jr}_jbD5&)16^*K1z$BDn6= zllt-@7k;>g&zubNhtb^p{9UX%^HYus{@fpZZ?yQ2oV2^Od(6G-(jE4ZGe7J$OCMez z?QdKF7aX?Ny#Eh*(@T=<s&^_Jut);tfo1;BPE9w6zw5Y1NZ$J5EWPF(w83tcH+AjR zFOTjIp0_=2Job+uIJo894RL()s?tZul6PFThs$sAyz07c_LA9dZ4JMoq=8^rBoTi9 zl8vlC@(xy1Zo_z@V_lK3R<47qFTvb&#aMjZyBu*}xUU@VzUuugelSfZwW6wc_r=@I z)-ylsx5(?$)*D`wFKKVMXs3JRgwJGa<=tcfNZ)m-<FZ@eEtkgRsuIg8*hN*CUtx*- z!DRaSmwEr1*JjB}8&i<MO)q-XuRH6bj%7jy&ak?G+ERFJXx(^$Upb=Rer;k`W{|O} zp%+&_#UIXmAMbg-iQn7Ahfcu0`ptWimo>V)^Tmm|?0so&2mOi#+hK641SVJ~yV3JT zSUR9ScGe>vq9ZPDvQ#>8L2)k+HbJ$weo|;x))~Ghq_PgaJ2&95s~gFO&f19abYOmc z%5mR_$;xXXe(PvHaKSo72&*MBQP>{%>EV7)eVb;!<mV2g%RXOJtdxiaR?A-IOP2?0 z2Hf&b9O4#BN4uXjX%{zp?kz=&U2<oguu38=*`m<jI+1L{!MA)c;^+)K43VkAQc&MI z!EBy}hXxB~*WhI5)Hi(Hp0+^ACd_?DVL`j~1t9IN{gXyqDR&>f7FyL6aPJ`sja@I3 zG5mCh9nJL$zI}v;!1%~A=TRF<JE2ot4?jNMjyKj5e^zHfiO$NADRAs&r4Z8Ud{X}9 zn7BgrVnYmpB{jto88_TJq*ZlCmmeOA-w*DlF8?_P>-%)VuaGH9tETab+*bh&6ZQ3; zc=s`WU3t3$LswUq!~KUaR^0~QZ8E=1Tu}~wMcJ&8am-JLLt8e(y)_4TU0Z>Q-#pf` zT09C9Ss|8%g+~cL9ZgpZB)6Zs3u4S*$xwH>=&(d~hx<l=Y{i|z-hs8K`DMEDDDlC= zTfdBrT|UtB?~;@ysAF0)X3F@$!Ma}UN-*`ePMmzzhfgzg2{SSos0>NHFe*(Y;cx%q z#AAkKyFWqv8De+I3#SgNjhRL%R?2GNeck6@@cB7vD3k_Fqijc2b+tc1x<ki}^I`kK z3qF2^#Cky{3a1Zs2iv8VKC~jGnyb`JZRk(F^t_>ZJ+@|ahfBWflHx(GGE|lst~&X( z&z=38J>@|eEXa&Z9<3hYN~NJf<&VC6an*<^S8ZwMj3X+o8Aq;@#__NC`jS{G%T9lu zGQ-C5TuBFxT3>B9`|v_-e0C)is)wDlc;_{jeChJZb2iBZrEIuMC27=byJGd=7e4=z zVw@Z-{@%xqPX>0{S0vSRv@Ss^Q-?{x9h!>I=2l{M#NJXY#^Rpz<g(a$8V>IcZL7U7 zYt~w&z3Mqps?N>E)?#~xn3_IBCT6?JcKbXj%W<8kj|#353k6dVQ>QdESamaPZH+x; z*w!*%mVMzqZ{|d;E0sI%>d{F;V_?RHaLP1(!48f%HLMyfcbqE~4w)!*i-(j$sLJ44 zchS+iD=nF_b9DWP%*{Y!o7td=RV}kR!!tU?y_I8H!$+C2EmPcXPL{fy+^S5t;gZy) zD!y1PtGXOIH9Di!tmuJTJEvXv+2cYZxJGxdJZNgRdWam+?hbzD^XCr_nKYd%^@ew? z(#h3gC=QAr`87Cb5=?K)w5kAhNs|?22kyPIJw#TDS};gwQ^~t^)v&d?H(4xkr#y=J zQHd!@i7k(Jm{k=F=}m`sGGMW!u%wV}8d?SMpH5Nu)@{f8?kXYdm8pP*?J^EOu2_v? zQnvCP39J(g-o;1Cn3YZKRtwu?cXHpLTUv9lux`gB;(l1^>@Ke3hckEcU<JlxgCqIT zS(B_f>e|~A(2vSyfC*WR=08qjUZD@Ko9}?E`OK}?EZlj>x89z$Dmwybx|n>s^hh}y zyI)u%_s_To#>Im71g6*|;O=j-x46Z?k4`5*9G|feP-_KrOS&dxj<Ld+VM!@nUw}>G z9ca?^MbuPjy@szJ&jx`MEOE1-){2H@CB3nkIy`8<A6%k^N2clIm|tSDxvr0&hxq~) zJ2tos_}(dc`9LHRyX+7@P8Yp(bSM6vx?f(1Y?jD^8G1z-7nhgq4%tR_Uo8XJG`f5W z^`oJ{D!~OGh#Q1#YZ2NjN<1utsNP=#1<Qu@YJp8+(q(1#R=2T0^tfy%JS6Ory%1E$ z!hx&o0~YKQ$ktV32&^5no>jtnY5!dDg}J0UV{MVef>~XKm4j@RMO-%;Ipg(7`z1p6 zb=Oa^eSweou&l!OQQsbdn6Yex4i7isHJ7(obJ7=iAoX853U<m$_^r3^Vap=Vh1c@v zE6M<2eQ8m8!)(l6S({?ur*+G6f#prsmsjvRMV8m_omDmTi>`6It}WU1@@VUZ2J93M zZ+gLm*>L)2ap!;KkrNhVIQu)7ZnirYa>Hehu>SBbwYQa~;k7>AB@)!eqb`D%Uie+q z)i-z8vdAXD#75aRxkKi~8-;nocgjCbdEK>LyZasmq^qm6SzRJrf9WHvKlJZ2jD}ZS zySck#=fWWc@rpNEcFj}Sx!17!ydtY)iWQ?PErva;Eo*q|i+8Z@%)3}F1Tu7Fd2^N7 zP^1$d9)c_1v4_?7Ww0;YH}7HH1KG|(pH5riHi_YPuIl4Q#umwN5nleg+gfYq{6kz+ zBoY*wE8o&#{lhA|<V~H{MHSWxZj)?av9P#o@N3F&$y-u&v7mKKx#r4lXT#jPVNERr z@Gh>C<tz{%{JN4`U-9!E<y%K~Eh;V(R*H7>o0zpjW```Fx>^Wl-MY7PaRXlYt_l6< zLy);&%W+>Y%bS{ztQ1SOwqhP0=97))i|_UTizTccjx3kJ&uYYvjhyy5L9KlLj0^t0 z?%4U-xx;5KF&NF_vitLq=6Mg10Q1U*@$Iz<+HW16b^4bAA0ImYoPT8x*U!EpwqG^- z$kV>-*m`dDC0{9aX$SoKXP<IMZ3_3+!CSg$77DDcIJZQ`xlK;{>jJ9<;#LXFzxc3= z{<;ExC`bQ;Xm@{=3CwLrj$HT`aQn+NpFU&aeBgt#55Hu2YCdqpp{IX2@=&1<j~&Mv zVg~71Z`JPOwF#qly{>WCIX{6k1Kw7+S>HZ<#-9l*W@7$v_-E|6e(oXXJcNx=FREF_ z77La?m^<^VFQ?$JnBPC*q_Y>y7cx!j#?isk9)Ok4JL0^57&Z%PWby4IuS@Z8Um3c| zyN@0|@$a#VX1GM<KKrW=zU9Xa&))5gDRy5o_wb7!%3Xa=fP38$N1eAI@_{~`YOh-; z;C`=<pQiouL5Kw6n-4nnxnHN%Ef~5H+G^~&Lz`#(9F`w@_(lIJ%%80T?`^(uVP$Ol z0DD+ipu76wk@LPWOb4*7TW212&Swqja>3^z3-1_x{rZLpEU1JBXJ&ssIC|<mWMJ3V z{H6vhC`__a=zP5T+`pbZ;WwT>`+5H`)QNkp9~gPTcf;7_*{@!(HCcYDK0%<<C8DrX z`N40ntq7n(h&T+Et_?tp5dP(?uon`TKskKGr=W}hWynyp9e6w{CBp@5KM*BB<;O7= zN6&d5z!T7+8^O>EhEPC?#pXxR(Gy{ce>*)3w&w`WAUb784Ea&7wWK5j<62-X#y=jO zx$C2Jz)bZ#+7Ux!GRFzq_TAo@y`|HINDIalo!+6h&fSHMly<({*$yEv4r~LA_ZcpC zj*thd7}J527KAJWM|7x8&&Q|;4!m^%O(%dhI%5j8A6z;ic5=_CC!mQL(Rlj!F@?os z;96K1i;8jjj`@HB+7WaY@EMK?5}@1aX*U%5Cr3<RyjHY8_o5bDOvnkOa)*mTrC{(5 zj{*`}8cpu|4?gQ1w}0bAa4M&3#@Mf3V@Ksl2^ro`fc2KHg|yrA2lzDiZCRg@p}@d6 z_w8oQ>7RsP@qspw5?$}OQsu!iT}|kM@_o<K-kuzSaxrL_z~O>VBD7o%9l(vjSPW!N z)742%KSu(N%=~<Z-*WOtK@;1MU}^On3Z0(U$HxE)JdA<s5NOkf#~UA}?+s1JV4O@t z*1@!TQ)P^hd(~(IuIFC19hi#P-SnK(iWD;ANm5)Mq~#|_a=F()3!GPYFb0!5D|_Bl zjK`WhXvym~5J?O%?UN|o7jDlv8~Sw80kVLf#*ay2j%S+Y!CC|+h@{YgfFolnKs(0^ zmxl?E>PcMu!5BLa`aAD^P6Usq<(SA_S!sX_Jr11|15A)P@NFy@o5$EN5sd|i{y!cy zTaUVHEZ{tmadqG^P``}E?!{`Lq3d%Wd&odxHCZ0`)ItFPiy{Ofe|6-HL+?z}o;WGI z#q_*eU3$w`9-R=dv?B%$MgvR{E#8C9V{3r4Mf3!`%4azfz0kEz9(e(&&4V=HbH@)I z{pl<wDDV*n(c{So;5#`ZLmnd+Eos{K;rHN04c2=ME+g7JTq?n1A|WBo19mKd6iW;? zk7gqU6Z^(n26Tz0?<(v^0ML`Tpm0P|0@1sGLC0R$gn>3r5e<QWrEQ2l`hY{n-oloJ z{ouNuKYf}`9!rj`0YVIss8JE0&np$IwI~7|aFHx`JjNEzkWXd}o^I|Q|J%a`=YFc2 zho|Kc017muL<1^%643bq>l1A52hR14j`%zjF-C96_`Bi55B_YsPmrDlIj~lE#_Njs zST2g_nyZSf3R$BVi;@mJ>4{7%6iuZVi=jl}mwYW!$m&H2r33uEEf+&cI>S#J-Lh(U zU!Q)C1<6qfu_7X-w*Q-|(iz?#-&oZ3SX8y5quLpc#m7d6qJ&s|n%@=of%6N|@NxVI z`{1>2a}^PZzEs+W{)OIqL&cYDO?3U&lxXmb3%03=m`YK^)ND0JKPy+Cgu(O#K!<^d zlz!<KcZS86pG1zHhJ==?Pyc7GBDN}$HTOlYAU+f;PxhIi^rX`-Yr1r#Ahs$Zp*Su0 zE*mb`1Ng9g;rs%c;qm-<D!d-oo=C4g{d@0~LOLMH;QyY~uv&CdD`Z~Px>c8zB|)0i zj?|v)1YJa;t~Xl6QsI|=uO9B|vORFQ7A1|U*ZS%HtU^+4Y1xneO50Mc(%EnPa7rRd zlKnc8hN{efPE}<RA0tR$q%c`c;?thz`@s1{JQ|PZ$5Y|;m?DryRr~$u-+ymGnqqqS zM*k}`wn&tsD;Gp;xhSe3LU-7?CnHd#D6ym(BHf__(MkI&&vd{auq)M<h4}Or4hWT4 ze3BKPLM%SXLS?HWP<%4ei-P!KQ6wF(Rabe;rVvv*Ahezc=NDky<M~l}D!lrFT&x5s zKf%WA(?1=sRabO%(e?Oi%c*_FU+koaRAM`$YDG1ivxTBm%1<KxLZDEJH4zz-UtX@a zOND`O!1%bbq=izjPkTNTD`Q1@d{SiZ?_P?D)ZCNgijEhG;Ys9rqCi?M%61u`Y9Aw5 zv76Q=$_GM^C&KwJ)zK6A@l<&ATfJH+7px5INB`b?OLgPx(*CuXBG0_Ww&h~304ao$ zh_pw<mkRr7sK*p!)=UOe`InXKShU4ZJ8%tQs}w|+Do^`|rY32V;$xe~9;V(k#FtfL z-|_8{>Alwz)U|FTgCfDzy9321YIq8w%1`&h^geKY@dc~LkA3jkkKV=)$>a8hefmG{ zy<YU-|DMgG=(;53x~)#m6eShR;MC}ooeuc2P>`4mQhE|LAJDEf7DFr^@GjK5Ml2Ne z7sUV4HgANIJT`A*p&&wtzG-UGnz8?9mdg3QdcXJUL2-q$2%#KGj}6duF@E3xPL1|~ z^9u;}6Zo+YUQYsFH6OpXoTh*NUZ{&NKly3c|436r$`S_a|2FjRGevd|m)FnsqY~Wy zrbbC(6v-xs)WmP8C)s2@-M07;Rg{uD@Y9uILsVh=RZn|9HFmy4e4O4z6$&B}gMZaj z%}GP{+w|4SE9%9pYW6cxwv0+Bm*eE~3uPA{N3U{_EwjSYmh1iC{1<Ise(a0aet5@1 z`3u8W>_`9pdu#PX$`h~n^;N0nnQuPE*PZ+tU|}(?s#<Iwi{GYKTfu8^I(JGh9Bct> zI6fnR6y3`Q)i^wkkkCs_!kWCK!R~{>qe0=o2h5J6i7U#4Jo`3A0@1l%>JuacGRQp; zxwF{hj$ccNy#z2r=mE7jd<eUa%yU^CXq@ej>-T#|;E`h#^c;VVG^I<h*gP{g_v0lf zn|myrCWgq;dIru#$Y>Ez1ceW)3m#Hy^EAxh3C?2KekyvGcsv+F3QG4Qb+86UbUsh} z%|ls8Vbck!pPWfXw7G|M4=H{cZyWRcd~EFD_(Xny4Rm|K2ayh42$6^dhbB6<$rc~? zr9T?0u(<=?1iZ%*97Ga)KoRp01_RDO?E9*o;r5Jc><p1Y>s#OWk11iWtc$iHm3q)# z!f*^oS(KDYUX^REpsFx48S%l1-rDF4*w~bs50Xkn*92YiB7Q(5N}(#)O0{S!64jVh zCP*!vtV>y>6eUjTsX~;j*pVTjSSaWyQZ7eZRTI*2GSDq%4Y5*6%c@rB$WTkFK?+gF ziYgXtwJl<#8YqRDNL?hvq!if`tqitH-LgnobfrJ8-(M02oOh4Zy-1<i@-f7$+1xwm zO~sc=#*0V9m9z{<y`n{Q)0b;Pv5?k6!%Deau+oSlX>qddbX`itV!33bP^qY*iIY|k zQ?7(4<EvbG(~wBXNmYtXMZM<eNc6?3s)#C!DJP;@Rq@qMp`n6lCgL~Ny^|@a7mPHd z;6$wU=3w8HD1E#uCR0(eqOBB4zHBG=<p-`(Yz;b*mNazChRk4)q7o+sBV}8&g`#Yp zF<dI_OMfY(mAb2t=~82|TJ)uoRK%7g7R-Q@5?|LLR$UEU7AYgz1}TJ6jKBFB+ZeJh zy~@7yFAYn}tSq7&5dP}e!w#CiQT~0-C!@J}&g|EA3FEJxebmQld)L<a$6=ZAI!&g0 z>&6);{bjYy#O+7SIre?v^-U+$e@FW*uQ_JutvCz+G$3<cLHZ|ik2wBApq1m>L-L$! zmdel0I{frymezX?8+mg}Su)46^Jks%1D445Pj6hmnHBZ#oL9X%bBktu{_sDB4?XAL zLqFx(Ylpsf(#XpL>*XuQer%p(_UGpxb>e^Uok1CXh37qU54$V@MSonse_7>QLm&NG zr8s)k@;X!8dhGBUx=g+KpwSOvBkfI+ZIPdzH{*FLdFgwBi~rhoJ~?~lA%AM(Rxww6 z*!%ViK8tzRoLM)wX?3q^9Qlc1ETl^t$*S`G=N@$CN-*%Zhc-rT*dRZ=Wcav6bkwZ} z9ehozm%;QWC(M|=y!q|Q001BWNkl<Ze!kp2`g!j@bi}M1)5v|#AD;7o`n%zJ`Rero z+;+n3!{4L$x%}{jvoBZ|TQJqfJ6qZK&WRtupp|;}Q8RDemmecnudYvRtp4caImfQR zn=408y|Wy=rh~il&{-#a%9(E*EYJCHvM>GD2;s_E2i*iohn2z#`9Eh5t+;c>kw5VK z<fJ1{`Zi2nbLe4z(SY{bPM5ctz6O7W+cPfMIzYVW8~)1|qc;vrt`RJ_?2pe}!^GNU z2frl??#)-W?N#rx{O)Ted8M#HNLH4-C4+F)Yqlqs3GTKRw%n!@KWf}fFWVcgxrtkU zyUjWvbl4#<cI$InaqV#*%Ok_rOP7t+8+7uHlhN;cNupo%b|9GWf7f&SIh}Qd-&d{k zZjJNGH)qKuH^#+-pHeQn;e``!(b=D5p1e1my8L(j{GpHTW?c#HU(&tvWRtCG8vL7n zd)!=mQ=G*1$MySH%iFMQXvVl&;N}a)!j(7krYkaczh)}(P%|u&x9knCc`^TVdSGY$ zQEqzWHnz?ALl)Qh+DXJ+hwS2wFX^aPyw&o1SLpP$Ld3ADrZx@UkhI?PvWQ3Xu%H%K z-#)=xE`+ze*w|OSi_8Yg2hU#-lZ`9uA9EA#%~$R;m%kJKZ4I9}0Tx#RYXok*aIC%U z%)e-@tGw&c^tUerr<lfjzI>#eMaJQ6mrlCh+Ls@&Sa`Vb_TAYVUWB{u>Q3vW0v`Mg zFWAoJV?PS>3OejZ{|AS-_Bu1UhS0&SXs}l9<o4M&^O1AlyRGgYp97a&(doXlLh{CI zvT)UVI-oJX`GO5wSYHM+vYH19Y!W<<y@Lxej+LSUW6f1DyJwVb)lI~Qhq7fOhJ^y5 zi_*=lp2b2U3($P~a5C8*vIQgR=8HEtZz7;p4P~^88%W~6A4gjQD+XYZBsN*rq*L0O z#Ro?<laS)({pF0Xw6O*5p3BO@HsX)x@=)y&55?tZzI}MIw6Fv7gQHj}+fW<oIP}I( z%#JK>V3Wpb(g)@`9Mj`^{Y&LhjCoKzYh}{QPW(M{+{d0bksFV0g|K93QnB!$M2$Rb z|LpZ7vKYtRCz<5}r3b?u*X!;fOW@uk*;(5b{rwe91}lX7Wzz6{q2-z4k(x70M>o=1 zGUSuOcAegToVQr^HkV=Ate3q3C!1l(!QP@*{YAmCOmK^uw2E6n|G#t82H64+%&-AH zjdy#qY|Mj=b~ZO_7VgUr&x&TcUADtRjY-v9g<nxJpw(1$Ga>uo33S%ZR(X8d<LSRj zxaopzkV0&)s<qb2xLHzFdO?j2ddVGSxA*Y1uvo~ND>~eBq$f4gwTGU$R(_^U8(p6p zzECQN$d^AgI$O2tLa^m#a*|Y?Al2g3-t5wHtkzBNM-nS(t=z75XI8Cm4oaBH4l5;% za(haiCn3y@dPC*pnQ?r${O9j}$*EsBHfw4<Lv$l+$HV=A%-JQwnW#cYMFvL8m5R?~ zPq?sP1{yUPHPz-vzk0Ees4GXQ#;IGSQajYU8M|dhJhU{mrhK~8<oL<POb#}Mqqjxd zoFg%HS@Zq>^1PApg4j~1EUjKt8k`s?`zZZ!{r*yIq&*^sNvRVXqf3ithsr=&{=l9i zFaGn>CTB)7Tcq3_6{(Ch<1PPu-q-JtaXD4W;W>}!x`=(}4=()jU8N0sUOLn%W|EmX zu{5($>kLOJi9Mw-T<V-zwIh<ukX@xhm8s+0$Vj)eg-c>Nn<|xbJu~j)WU%UNz3!{4 z>Sqk^9VmtBpWboVD0)yIB+|f*#iKjT+U%sB%G|Utt5qyg3lI139^O@*D;1=mUG}21 z+8)`5A0;!8H8;tT$~PF@kewn^l~9)MU}38}Mm1z`yBSKx>z)1RAEoofcb;|8C!U)O z7KWQ<WXsSjF?nFv&_}-d{JNAnyABoYo3bIhtdf+Iso70w4GsRr+t@ac96is$kB*+) zB5I=mG3+R9vmWMENJ;B0+C<jNPWYa%yh5^C$Z+0olU<m9o)ucM4D>(Ep(7opAbQ5% zcS>FwZFR%3yS@XfzISYXin3lj%Ox<m;$W@B8B|D>!%xbjStNeFOcMX^NjxAKeCsH` zPS7ChowomU3ip?d<;!QYqC6Q`Rp8OeR^|(=5zM$`V1w5%J+9Zkc-X?^Cc$m2w$0F1 zR3{^N{@}Tj06(j$^~LCUxDlB@u;64=R@>+t-#mi_)r^%xi%xWOi!Q<9TQU~9|0xjz z4-WI7fS)HsM`l+KW`1cISk+Ktv$iQZ3T0rIjJF|KCIlvA4_MeMw)>M&(yfv(uWF}e zE&~4j80I$vtY}~o9>aT4(SwN{reu<^A3wS*tFlBCakIFsg>4z%7l<$^D^s}p6vbAt z`2o%2>A#{u7J1L{8l`!-k}Q{~menmAWTGP*nJ;Fd)Y0+5Qr41Gqcuqz4!q35uh0}p ze>yARy_@x)i-mb*q9umwU$B?$>sAdK441xXina3-F1yz4ysX(;Ra9&(Y*3)!l()57 zSBc_=%QuFt&;5$#${SLaEY?4>?wg|ujAONIbN+@)x3cxr|I;Ogz^c-YY*iIlDsc66 zhHVdm$89MuS65fUGPyn7b^2%Y4*4)!pL-{3%AU}E*Kh4%-5Gzw3c1biI`h+di$Hg6 zfpxNG{OTDYZkMf=SHE$R9X|mb`s4cjOG*J)SzYHBR4^}p+g`S;>O9!B|J($P*&uea z5W}hhCY*i6pTguDUcQ}O$K9nj2|AvA`DZ=)#W!{IuAjzu-s?$TQih0IGT2=?vjxi! zY6l{0kxg#hKnnB9aOrzn+1{loOu}nlu$Q&FR+rJlSG;w~ub$7k;?i(!8NXe2>h*%U z_P4k3$PxcfSY7kctQhJ-n?BxQrR3q`)?f9Oan|k2kM%69uw=BCt9|^<apx693>oI8 z3%YK_S$Dybh9T@r|Ah@dubchzOfp>DB&;i^tPqlAW!9BeC0AFOI_Di>^3oFFWj9ZS zo%8adqwY6fuw#77TVe$N!7G=SSS|))h}j<;e8h3v7794Fy?*fUv+s?pJ%8lfuL-LJ z^xGOY5;EeZ^9RoT*P3VQy>o_7{34!-D-JvAjC=Xxg9k7D4%nCw-q5^W)9(jE>&>&T zT_q{mx`Ji<)kn`b=OF`%@V@%o&sA6|e|^MZ?@w7e`1ym6cyDy8>u8v`{ivbS|Aw%x z@wsD0Z&zxi#Jp132Wlt(jlkr4DmOB9&FJvu-v={2uHV0)37GhMGhe-O(5cQfvj?7k zuluuuW}bI9DD3j0TU%6^m30z6)f|V^-9BUHDR)_x3(nlt+zyzlX3f0dA;a3|*Dn0K zrncagHq45$vvJW#?@;>9LpQD|5qNNfPW$?yffxS(tMDXmpF4EP&o>qWj^y&$qvzkl z<OgRRbyqQJZX9^aYJtgj9zXl!zxR4|4e!^N@sZHSd;0k)_%ZZ`HNsi}mNq?WE*L%a z9|y2Z<AJxED=GWYe|g>BanQkM{s>2O8)|-O!}=u+<5t$N?;kz+uPTuhmyBHe)f$Z5 zFgSeiee8ZYNiT8aH(Ibg-s6dQMQo#)iVgxkXbqYPO(b`P1hPD9CMBZ{p-Yy)7tU*W z$cUbH>}5(q%#%rac`cLuenVbQ(e>6dl^4VI7N0@@rPd1G5?L;w8N;^$i*xwY@^CG$ z%M=wc#f8Lyi-CSAI;#S~$NsqK{xnbc%cXA;k2S;uA7b<_qI>CZsl$7srHcz_z-SkP z$skVAfrQMW@I-Je0xr+M(geKqBpnpk=m}&54A_9}<gSy+kXI1~hql<fR3wa<9N-j5 zUP&3(1?wKeyZ8K5{Lm(MwUOcpjy7LCHR~mA1~dWO6sg~r{?TLe;*Ad6STBDwLL02b zqXH@ZYo{uod&*)^{|!#UXI`)s0RpNE87}9N>DPm8=cPckM}@@psvjFVq~JOl&yNht zF8VlhqV5;qG(bWJg7yS#VsVOof6p&D4q0Bq+++G3Swwl<BNdGy3rkCR#vYNW07*{J z6-@_dqevjj>#sV<Y+eyE>sJEpjqCS&5_H=;EMzf~f)B*l8;zqUI5;pNpOhBkdr56R zw=DBAoB7x5!9(=XL+S#?X##PqS5VVp6^77BLxhO&#uLdOn23gu*HrIdavUvqT!b+k zF{7KKlH=WfeoB7ed?4g_xO>J}cJ?Rf7sR$0Fsf%jJc0f>kWK)f^vI3(&WF6HJ9Kzp zD{IcYBY@6V44e)8PcTKSjS+}}1QJCGD)^KTAZiFM_B_5V^7<9fNx)#zznwLF+{e0o z&%6%?<9iiRf#9N>E*#kFZ}*C!>Yn#k0c47HuV6X)XM@I(;MUjCZI5#vNCIGjXRY8> zUI5$W8PiO$hhE|Ro|M|qA2;2ftKUfKZH%~lIQ<gs&On-9Heh;RoQ7b)5hkXSIP-}c zT#|eK@pN(E+Ifz7#0PM_%LGDxHvzp>Bu^Z*0orH>mZ*|64>WKIJPL&1eV%gJfpKE; zIJ|q$PsNXzmt5A28I<|*+@YgB2yOIZco_B=?7sA8GEa&$VBisA$kUp6lsssH@cC0@ z&Yw&M4O)}Jp8tlu<9~x-cYFWp*j|W6Y+-Zdm|0AI2ZhDi(93C!WHzt=oKIp6mQ?3) z4ZaHm??88B{{;$9zaQ|{II_HowFB>a^FPZ%bWB2?8%qn_CR*+2Vz4oqyoB{67)KhW z07Dw1_K><fw;PoNe0bcryx$YE7Wq%S@hA_<k%G(R(RVRf<}i3oO0Kg_iuVv43g@BK zn>o=jL5SApS+aSZ2}^==1P3OAR))hxOxm-PypQ0MNYtjke8reoroz&}_AXP&@<jXy zE==Rye|`#nXgU#-k^+GpfewBW9>XJ-X16c>W3LK@&eMpoXboAe!F%b^j;MQ*qI<P8 z{BOKq2S`&05$~BIc6}cIWYG%W!gvohm&g!8?BH{MY6i|`5$jE^3^N_UhuH2yk8#na z+V+E+@_tK*;CeS8bn<W})zg2309Lob=7CPMO+OsV<T>^^Fr6FTX|D!|$!x$UhTc^j zc-J5ISbv}!NhWfpH~<|Xs=Tm&8{Z4VN^(0q5LB>`kV0NB!xF*uGR#e0_#>!1229aW z7$Bvc(+@PA&|Cez#rGEprt+HV#(~j{L$qkRKo;_%;tskoBaivY@$Nl8B|i*#HFw%= zP(<Z(0`>90q=63m(%*P|UU1%F(%go0-Co&-mL__F&meV}5FiH66!AA-u=|TpZe7|u zmMk~?dbP$)grMkEu|Wk;Bry;}zLa-ByQCN6Mg&4MfXla!y4wal-5*ke4?xER)iVNZ z%$ey7?8v{sN1ungO>`VKzp*HvKtYAx<|%W4%4HlM!B`@gywX;0T)&^hpozpuB3(i^ zp?BR*?0K3A4x?3XIymnk8cQJP1R{(>LX1jBkI5%MH!rX-MSg`(&k9j=NHP<1?G|mm zV&r!ls6<Vdk<J3%)5-GKx=y!ePccCXDRwG84)6T=srW%YKU-ac*DkM))B)Yc!$4kH zXCL~bdgb<7L`cwN#t>~#xp|hC$8j+afppI0S5o~CFhvY8_7=l{!bLnj&FgS<ee@Bm z2d9XrNQfb4JfU|7OE(WV@%V@hJ_Z-^Li0e(86EX>f5_Lfyof(B<Q&hfV+YaV+u&lq zL{WYNn8|Nl!Q{0!JVc-0IpHHduPqa80FTRyx%9_9*6;HXY2UugZ`>jFEFqKQh9UGK zY<oL}p3&LcPsUylYK&+)xwHfbF_H%Gw8Qik+D9}Y1`h_4*QX&6BbJ!k(mwxt@BWLB zVbHlb9(u<fJ-qwRPstCL$E(tDcswq82>Nk&SdYy``tkHPpz}MVpi2liLa*+PLmBXR z+q*>#7h`Uwx@TOppSiHrAWnh=SG5H#RgaXVsOwTLNKhq_awuEdDEU%BY^4-qxuObE zH&W~tsfDtLEt*1FED=SdPz+K^eIbNmsZcBzx+1Y4BJDzcQ({&_qLi#uiUo;MmQb#= zM4U)L@CBqRwj`8AVo~gXm~x<&N<plYQ>jI%N-W2^NHvy4q+Bv0C07vBl#-VqwOALC zQqfC+G9q3I^(aCq#6rQ9TqCJVESZ87#Wn@0Nf0Yih(Tf@6t#%grGk$ICsNhLAmvaL zF;c-<i6T-Gie8HmiQ=8aShNLSlp!xNAX3y)C={d|L`u>uin9gnM5GjbEf!6&D6tZ% zh&Lr4i?L9UO6=!yP%H*3g&<ahVpU2~^9?~H#JUSoH)ZPhYLueXLs1&Vf=ETc*F~i6 zrAR?)Qu9(4Ta<zhLuDyRq+Do8C<ZAbI#!%Wr&96~OGQLVUZ{C5B`Mgdk(#UevJ<kw zkQSxnig7@^AmyZ94WT5(ij<|~M5HVQDn$`rF8s#2)D57B5$AFX!FEy5wfSW^#`yrm z5EAh1yy{={ggg-5VZiq;_?hyW{xO^F-;3DSTKR>IDFLJVOK_GK^y-GZ9+b;h&HSFn z-u;2WN3!1GQyO!nXz~+sA47<+7aoma`aa0slGC^S!u0)$Mr&|cAdoQW`|rtf3sN-1 z{8macZAPOZ=#25)AZ~fOuKzygdwafdP+g)T3x;mbre?B#k0L=wlONahG=2YwY#NVg zd=uNVt<ZVJG7SM0BF53O1_MbTuTmVX(hdkV3p)7xj8^xyCmsI3_Rjp>&Z^4u>&)le zA-M^eNEi|b7KAATQ7|YNaG=^^D$Ah}C;>qMQJ^gJ(UKO_uCfY?>T1gN!M1s-gwpC7 zu(YwoE>Woj2xPeT=H8p!gplcy<c{aO=N<R-=^yraPx=qwc`DUU_CK)pUT2^E?!DG` ztq*Y=qb$V!C)Nt>+x~U9k<$?!ev{`zqCJ>r){sDGQvV?_I`&7sXF$a!%40zJ)9iS? zikK#jqYz`9|5&wgKx6|=X0d7NjP<eo5T8GA8c-Rt{ywJ@z_z_}k_?q#b1ouTOiG$H zvD#>zf4hQ=76$ZO+IgpC33<yjLZGEH-?t1fKAu8mHG#!K5aMz`Qs;%^d61dyM9LjT zV_eQxOgb%;o$2&$&g~?cL=nOiZAc6maT9##GYb8mC1;=NWA@Sxm&k8e-|j5~Y?3i| ztZ8%Xz$wq6%+zd$97d3@BcF%AKkF{{(d2K3Sx_^U*mf==#zN*gWk}2_hw@i#pXO1< z`y>GZPa!pmHW`sM398H2gd|3VIUmvy@9!)V7y4DI%(uc+C}UF}i-Ev)+9!Jd9<LkQ zSweSUpt1s<SaGqBoW_J&;UR;jb4N|Eek)o+GN#)mBkY{RuJd3=Yg(q$YqG;dOnj5K zp#^i`!M;gGkildp-hozjM3jG&C8o1IrW7!<y=GJ6GIZwLa1HVhiT^W9v$-d7E}CQd zJzXB;c+CWmSpQ?WV|+!GD1t2YM|qSV%~QiAras_duB1NihX0CK9|8TdlRkJDP$ZUD zdu?vd`JR7a=7P($mtY6rZ`P0|$2f|39HmZ@JZNFqG|*i~XC9Ui>*H{q`)Dj}oMY-r z|EG?pE>T$Pyp}3+s23Od8?Q?ue0EEzPBh+Vqhb<o*?2G~<HgQByV(f`b#C<$Dna?r zVWP>H1=UnKg-w0RpW`TqNn(z!N1=E#_wRALu`O+k8W+u!4EtbPK<uy_?$B~|ghlzz zkpbwW`yEmi3uYFLJ$#A@6KuvCD<JkYk4m9KkKr7u#aPS?kpksNwVfjjKw}cd3cg+k zx|~Nx6UGY$n6c66m@NfbO8MLyO`RBEsLx|oo$GRjw+ne9(prBQYP7+SFxQF3DtFAz zU_F6k>fq_dV0=zZC9a#Gi6`atgm#*;XBF%!&E@u77Y!JL>eNfBS(wCFusKK3g#LM* zrC?L#d|YI=<m>2iEtRGPCg(o-PTUwv22Fp)Y7U&^b6jTMMKcT)iIlMx-RTpmeD!Gl z^E6Q$wJ0pa8Oe~OKEtTe{Yw)JE+y>pAzSSL>pG1n)6U;>mk=3WeF_O!MH>#Cdd$Da z?c=c^eeF^u?JesAeJiD5q-6S}?o5$oQj`g4)rw^)HY+01r=*{_T#w5(lt8ppic%C| zft?YvKXtuzQB|6Av(m_ly((3eM9RHYEA67GW(_GyX`%EKgknJ?F7`yd{i4gQQr*Q! zy&Oi;lAxj%*pe)17xes4l__PREG!Q0cQSu|T&Q3rE;N+%mg`1D3ZWDtiHZeV*OHc` z7gv!~nMNwbk}eiAalIntpj=W$iZY-xCr8U74(ZxS>#5Wi%^fV3OsQQfn4&Ax3t}Xy ziV3B5aQ-PpDc5Qey&*2N1G&9|sZ~T&97rQ`6{J#<390l*wpd(I!lF$ZY1)(4OT98v zlv$}(g``r6lr2diGlhH|`8-6*GEc%%u~HF=u~B6yscKRxN;%5rn_3Mm<(Xj2SW&i6 zN{8l2p)Ng@Qn9GYVk<$ZBuNqajV{M6Nixaii^vkBB1JpXkm-7*QIK*?;;>RvQC$jR zMS8`aB(5Y$Hm|Q=OCii^WffIxA`(iiRuw6h64fgOn@Yh2#ftP9GdUwuxqpveJ+^U{ z=%q^V_b189hafxByL*bHZ>#0=XUt#oFzGA(Off3VLGY1BnEK-t@Z)uCI`!;R{};oR z=ic5}H$C^G`Ev5_wNkQY2KrWf2>pdF7cpYrN0zVsYK5fr=&1|O_#@mc57PRJ3ugJ{ zx{dPlvzM)EX2WGT`q+hX=A-1C#}@Bhals=3*yNdoh2=MFm(3TK*KW%Q9$YwZM;jpC ze)<pJ-nVu%eWgs!gB%@rZvCQD4@E=|^)$W^xGrDOg;y^*{hRakgd`+;CAag2Fevu# z1}Y0bT;B+jOJ4#rN%+-u<+HyG-(M&LU$M+3Pc12~xOPnbcW!U)#+A$OPJm>vrVq$d zC$0SDw@zE}i;%6SEIISn*)fjdJxdncd!$q2&%X{l|L)QU53s3xY#n|c(|0bGKWr1{ z+(*L|4+HOf{M9Pzrjtrv3wDY7$-;8&bF+^0ZyR#j^?T&Gi{`)M*Tj6jvg*?Z31K?< z#IoK;nzWxdYuTcW{Cr*Qv{$A^3jgxK`fqP`6QaYHa&Bbp6N!EJtm=v`ACi#wKMLPE zi{xh)Gkg0P3vWNjOD8>h(V|<9aF~>RH=n!U58}-|@sIlD)Q{%=J&xnp3hZuyp+5h5 zzxgxp)CRcoeG|#V>PH!=rr4n>BxKKAN&N0JUsn%(HGSdm+@GA|cF1R2(ao1)2j@jT zgSbOd;``U<TttPv;p54^j|tiR>kqK|{4ev=`%*3&2=v`w8|}L-j&Hj#J1p?~SMBED zsz-9pBOm^7F!!N`wm8gKHR091o9Fn*dXjrTkVQA%Nk+h!d^X_54GdLm&VwA3dync{ z-j2KLYGdDjcbBi2^3hv^_<G^B-UNoKxt(n#y|V(_OU~Z(0O>zm>KRD)Z5U>B)nCrC zQ#vu6t#!xtzFTv9pS^a@Z6|gaBjR2wKE{KmeZ@U=G1+rd>Ko_B<Q&DjuW9qX&tVK` z%dp%zlWw?6@2KbN$menQbt$8$yK?R$Ge5bY#oh%+M{D|?>tnXCql9_2ObbXE>qWg< z`_z=Z^&RlZD{0?&FD`L>>Kc`9CHj*!`_rj6%y0I&N6%wd^^V#2cRmyj_Q3O9ZlvYT zD-N(H=R=}g`ok*{-nHPcd*Dm@p6jO4Yaevua(}b6{`L$<@`VjeGsH;2G1AlO`uF(X z*x6u@1*Q3yGurN|r)^dq!SZ*j^>9Ox4GLt~*?Oya-lzUrpSQ)DWcN3Ooiau8N*M+l zO5wom6yjFjmYj<S)1^`D##-AnwmHkQXXw_V$zbj8|9$gao5p00_@y%2sy3`{2lqc# z=bXo&wi|xYZ$gOJQGk~V&4lOrnJev5?V&D*k!*8;;fBh2klUn{n1AgdlyP{upPa8~ zRN(-2V}aLtH4IjAJ7dD`Ld;;v@SCNItNtNIL#sRl*-uw$Mg&7j%9cK|vBG3-?}2mP z^dJp8CTy)9ahofL*jTZa=EyhdG-V(BrW`uigL&@U(06TTOeRu(xzucJ<m<@iasP#f zNXR7TJ`z#i!Xux^d73eU;@DcizvQ;mG(!^4@^XXe`Uv({OTl37yJ)|KNVfP8N<8$Z zb%tabe$!`mloTrGMyAa64+A+L(m*^raJYHy?N4*=CaOE(|D2*nYHyOgune%=|L#$6 z+Zzd^jjZcm0*p0p-7E5~t9i6#S4^iXt}3xe)aztJ?Zr#BUsv31)`+g0bEsTODy{jw zJ#kN!!oZrXBOhJ$!;d8wy2t<9Im=7Zt}L>3R~2ztMTxFTtfk#QkzG{ia1q;mnLS6M z1zF#CvR2~W<wweL>hRv*IsYf`*?HMc8PJUdNRKM+FP%TTu&{0}=RA&ASG)MUw)7g; zBUMB%onNno>)KOrd9NHA$T^Hudn!^&DtkLT$Uf;S%0Mhf<efcjcar3MMR|jhC0yJv zHCH~mw9(~B+N#V|8m`ok;N2&0Tsn4j-Ic`!X0@dC<!?%oE)OfEg4B|F824l>&h0%` zSbfdI=NF@DMT_lKODW2VX02S5ul-<c)yhQuWQmuX-fg{?C-usq-lP%RT2)NXa&Zf$ zO8rT`j(i^9{`~4IpIrXZ!kqgkJ?XvQzvyqjm-96L%VOy(9GX{^g4j|;`m=IWs}vT* zjYPuis$~A;lC(rA`}UXDZ20CW?czEqW;OZN6YnZF!fZ*y*~Lj#lZyNHcRSq3S~lB0 z7hB5tkVZ<4`e}!@-E!e~uPR)&Nxf(OzGb#3*~wY0Pw9#(7QguD`!D(WnsQo~prk9g zE`?wR000OVNkl<Zf8&0os}(66cXw<790=q0-(hK}mzg)_dAd&a7oU9KQ8?5y3jE`5 z={<!e{J5$hfp0$eAGgh({p79gaBWP#TA$ioAYyBeabwcSU~g`~lpN@C5u<&Lal`Y% zgiOX{|MTpaC;#ZW9n%Z{>2pU0=Yif;jJNjawj74`)2HQ}$3PCj&#NA~v8{r6O=vS# zVOm;k--pO^7}L>ewz)>mgB+|W*wV-j6+O|r%U9gnH*5I0Fjg?wpY`N+UMllSiEKzv z=85aS_9Y)vJX}5q$q&|G_lhq^V6-=Fk5<y$o^#xGu1m3MsJA^_G3=H}c8i&jJ^ZTg zU`zJEvkT{@W#(Az18gp(L_fYDc)i+PM`s=i9yldKa_(c0siD=I&+76tSJ@qsu~&Rx z(!AWCvQ5YsE_1LRl8|`NO_2TJ=}c4(fJtU$G9DCO7YCc?g@ZN5%Q-jFn#sOB32B!P ziBbAXU%qzp!PU>)9EFWZP|6GqxP%{E(vdaTyH{pg%CXy5fZV@6v}WStHrxlJl0cN8 z7`SkMz}%hhJ<7;$eLrF8k97LU60||@eA_yg{`M6=VL}e7TZOFx>=6iLe>O=9`(<0m zomb^t#3|gRw>H(~)r^n5^QaoT=&#^~Gp=s4;fiP3SxE_ph2awBrYjGtvCE#!Igfh% zr{lTxLPk5~)yj@|=YYd(mni+{$1Qs|<s3$mQDL;&<v|YDFu`aIuDvBl5C1yL`HHyn zZciq!>S>zB)1<dcZf9H=7t6l-CRA(Xs@J{x#oTqpIK!8GCu2nX!!H}|dA&W{+qL)N z1kcn7(0ZpZE{d&-G%q$dC=<bLMY!y)W^|?CuDeOG?Pm#JNkB6we~?XF@>O<q*OAZT z*Fo~n{hHs+xsSli1y}u7oAWdmw?-F-j2Fjeu|{)5_Uhq&6S$oMSKbqF=!Hyc*qGU; zPYJo<iZ|@^(H+(8@yCQMH8k6L7!eLi&W+qb`=;wB8O`~S2^tQbbqQR2-9KA4+!e6r z6}HG1)0uZZfK|+Go1FP+h2i<c`wN3M_phO8f^MGdI84x-HM?U`;>$Bzw_gsHsfQLX zS@MsdpFe%=d%jaX0_Ztbe<jslpFfrHpX6<i3tI+g^I9o2&HDyEsUcC(eTzPx#P@W$ zh%j<>&$_2d1blJjyo<gUJKE>nLG<UnAukt!?Ui`D0C)7Ceg0!Q=RE4s3zlE{qj{k( z;JCm4&dp+BcNsTvYu|#4pYL)Q87{Pk#pOK6F#-0AY0v#`->K_=M$T8HHTmB1rQa*T z3umtVz~i;t&WOZY7Q`gC4ctg@>oo>qXfyfHip6jH?~e9s3kU<i@R|BuTZG)+*H<i9 z|GcFIJEXNuaGM3aqwaWAR{doO{px>Mc=q2cLQQ{se(n7)r+dy1RSIMBo#m&027c9- zuOpwwxB6DT?H5c;<lM(u;6FD)oAWe($u1!^pRU|D3!&k&_21i42D`am)4FEa$rro` zC>|bIc<HmCzi`UpbGFzoE?)EJb+-3rgxkdq_woO5BX3~tf#R|?IUf>CmLwP4k?L<( zj7r-#F6qDMC59G$cg3Oy0cd@5+39OuNq32cI~L!N`*-f`yrnw7w?3s#m=U5Jq?i3v z<1#X@`O8%cGaW&sm&^qnDc)R1Z0=k@hvha)ipjZ%5i#29%@ShTA<TI>hC>q(`uwvZ zvoxDN4XscamUiN_^X#>tBfCzBI_-yY4rA(-95&}c=9xYRSyK_^e8mJe4daqEbw}Zl z^CYbaQ|mEjXZ|9CR1sTZaDh+hTTJSF`X?Z_hfN%`NKMmc!aLqfR43J*D*kEBj870H z?yo+NwIn+P674`o-8M>o9uW~PhA#K<O|SLKd73_Ji$gPGKr2X@LxE|LVI3;5apnby zDsY;BBxH^#qSYzoX=`6ffhDEwvu-&b(kcUZ_FvS|nfs!e1lpR|``Z`?YL=|)-^^h- z4mWl#f|@16kYp)5d4};w#dL-&!UZ(JL=d&XGVKzK^AgY&jw2pS?#oFNUx#sooQs$T zUI<iTI<)~wM|NQ#BgO4U!<2Vv&UtL73g?SWb*>pQ9o;2q)a5V|!XZ*}9;ES8i7;)5 zAm=MuVgj}c8X{}EcJvW|G=*01#5*#)_S|F;IUKRYq>)!}rnLO_KGbO{n`yuDql8YO zl*Som9kH{~i{l(P`*D|`EGFa=8;KP0NL?o>TD80D$mikrhVCd^h(hLwL3MeW##a=p z%s()g^;AaP`Ezv2l3Fx@W{v}FV>|;>yC&L`HamPx=VGieIUh1Jxn^Y!662YJ%JX9* zNNDShrnpnt(eZCU(;c7TK7-0ZjVVA@S-Z{4J`%jxMT65F%~7WOR#Ohz7}cTb0+~hY zPAA?7opTW*FY?bd@>$GGhi~d%qt;VBZQ_4~DCazSbfGW7Ng&2+{8LN-4wZ8lmB!#u zIS*2kS4r3u$hv&R6cpRasaGwTt{s%`3Y@X<!a;lN_(^<)nZG^iyr@uh?Pb2XuC~51 z-r)7?jx58%W9JN<^k<<WBlYLG2GnS!Q-zb|>*&rS(<nS#lQ>s*1>`(UgTm>=9|bl7 zM+;Kzn57c}O#Hc$SV&yfecEZ~!KIF@O*7|4>P};TE+5jX*iw~aCP@QQi_&0xA&0U! z=T9GW?q5ttj{g>o!oOW-?i1t0`1eFKI5AF)6C3-)I5AFa>=Wa}II*!$j1wFC#5ghj bzZ?G-jJBY=aY=i-00000NkvXXu0mjfWxaQF literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728-03.png b/extras/mangafoxtemplate/728-03.png new file mode 100644 index 0000000000000000000000000000000000000000..4b9d3f2b695bccb9af2d61ae675167d04ba75d0e GIT binary patch literal 12787 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 FV1oCHL6-mk literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728-04.png b/extras/mangafoxtemplate/728-04.png new file mode 100644 index 0000000000000000000000000000000000000000..ca39841a62df9296a6fdd1fd4bbcc88345840587 GIT binary patch literal 16618 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 literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728-05.png b/extras/mangafoxtemplate/728-05.png new file mode 100644 index 0000000000000000000000000000000000000000..f2b4a54550da9845cd69d0244b62e21ba95550f0 GIT binary patch literal 23361 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 literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728-06.png b/extras/mangafoxtemplate/728-06.png new file mode 100644 index 0000000000000000000000000000000000000000..0899d7243da90e5e565561896bd71d22043c1a58 GIT binary patch literal 9991 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 RuYv#o002ovPDHLkV1hsJVblNs literal 0 HcmV?d00001 From 68ef316a9aa285cdda8b092b22c5a38b9fcb8aac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 20:27:32 +0800 Subject: [PATCH 0670/2794] fix translations --- mangadownloader/languages/fmd.id_ID.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 4d513f833..91d311c17 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -18,7 +18,7 @@ msgstr "Apakah anda yakin ingin menghapus akun ini?" #: frmaccountmanager.rs_checking msgid "Checking" -msgstr "Memerika" +msgstr "Memeriksa" #: frmaccountmanager.rs_invalid msgid "Invalid" From c6df248d718a524a77529d76a0a615a8599e764f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 20:32:02 +0800 Subject: [PATCH 0671/2794] batoto, fix login --- baseunits/modules/Batoto.pas | 164 ++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 80 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 3d1d17046..f63f8d906 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -24,6 +24,88 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; locklogin: TRTLCriticalSection; onlogin: Boolean = False; +function Login(var AHTTP: THTTPSendThread): Boolean; +var + query: TXQueryEngineHTML; + loginform: THTMLForm; + key: string; +begin + Result := False; + if AHTTP = nil then Exit; + if Account.Enabled[modulename] = False then Exit; + if Account.Username[modulename] = '' then Exit; + + if TryEnterCriticalsection(locklogin) > 0 then + with AHTTP do begin + onlogin := True; + Account.Status[modulename] := asChecking; + Reset; + Cookies.Clear; + if GET(urlroot) then begin + loginform := THTMLForm.Create; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + key := query.XPathString('//input[@name="auth_key"]/@value'); + if key <> '' then begin + with loginform do begin + Put('auth_key', key); + Put('referer', 'https://bato.to/'); + Put('ips_username', Account.Username[modulename]); + Put('ips_password', Account.Password[modulename]); + Put('rememberMe', '1'); + end; + Clear; + Headers.Values['Referer'] := ' https://bato.to/'; + if POST(urllogin, loginform.GetData) then begin + if ResultCode = 200 then begin + Result := Cookies.Values['pass_hash'] <> ''; + if Result then begin + Account.Cookies[modulename] := GetCookies; + Account.Status[modulename] := asValid; + end else + Account.Status[modulename] := asInvalid; + Account.Save; + end; + end; + end; + finally + query.Free; + loginform.Free + end; + end; + onlogin := False; + if Account.Status[modulename] = asChecking then + Account.Status[modulename] := asUnknown; + LeaveCriticalsection(locklogin); + end + else + begin + while onlogin do Sleep(1000); + if Result then AHTTP.Cookies.Text := Account.Cookies[modulename]; + end; +end; + +function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; +var + s: String; +begin + Result := False; + s := ''; + AHTTP.Cookies.Text := Account.Cookies['Batoto']; + if AHTTP.GET(AURL) then begin + s := StreamToString(AHTTP.Document); + Result := (Pos('class=''logged_in''', s) > 0) or (Pos('class="logged_in"', s) > 0); + if not Result then + if Login(AHTTP) then + Result := AHTTP.GET(AURL); + if not Result then begin + AHTTP.Document.Clear; + WriteStrToStream(AHTTP.Document, s); + end; + end; +end; + function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var @@ -125,78 +207,9 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function CheckLogin(const source: string): Boolean; -begin - if source = '' then Exit(False); - Result := (Pos('class=''logged_in''', source) > 0) or (Pos('class="logged_in"', source) > 0); -end; - -function Login(var AHTTP: THTTPSendThread): Boolean; -var - query: TXQueryEngineHTML; - loginform: THTMLForm; - key: string; -begin - Result := False; - if AHTTP = nil then Exit; - if Account.Enabled[modulename] = False then Exit; - if Account.Username[modulename] = '' then Exit; - - if TryEnterCriticalsection(locklogin) > 0 then - with AHTTP do begin - onlogin := True; - Account.Status[modulename] := asChecking; - Reset; - Cookies.Clear; - if GET(urlroot) then begin - loginform := THTMLForm.Create; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - key := query.XPathString('//input[@name="auth_key"]/@value'); - if key <> '' then begin - with loginform do begin - Put('auth_key', key); - Put('referer', 'https://bato.to/'); - Put('ips_username', Account.Username[modulename]); - Put('ips_password', Account.Password[modulename]); - Put('rememberMe', '1'); - end; - Clear; - Headers.Values['Referer'] := ' https://bato.to/'; - if POST(urllogin, loginform.GetData) then begin - if ResultCode = 200 then begin - Result := Cookies.Values['pass_hash'] <> ''; - if Result then begin - Account.Cookies[modulename] := GetCookies; - Account.Status[modulename] := asValid; - end else - Account.Status[modulename] := asInvalid; - Account.Save; - end; - end; - end; - finally - query.Free; - loginform.Free - end; - end; - onlogin := False; - if Account.Status[modulename] = asChecking then - Account.Status[modulename] := asUnknown; - LeaveCriticalsection(locklogin); - end - else - begin - while onlogin do Sleep(1000); - if Result then AHTTP.Cookies.Text := Account.Cookies[modulename]; - end; -end; - function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - source: TStringList; query: TXQueryEngineHTML; v: IXQValue; s: String; @@ -209,19 +222,11 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; mangaInfo.url := FillHost(urlroot, AURL); while onlogin do Sleep(1000); FHTTP.Cookies.Text := Account.Cookies[modulename]; - if FHTTP.GET(mangaInfo.url) then begin + if GETWithLogin(FHTTP, mangaInfo.url) then begin Result := NO_ERROR; - source := TStringList.Create; query := TXQueryEngineHTML.Create; try - source.LoadFromStream(FHTTP.Document); - if not CheckLogin(source.Text) then begin - if Login(FHTTP) then begin - FHTTP.GET(mangaInfo.url, source); - end; - end; - - query.ParseHTML(source.Text); + query.ParseHTML(StreamToString(FHTTP.Document)); with mangaInfo do begin coverLink := Query.XPathString('//div[@class="ipsBox"]//img/@src'); if title = '' then @@ -253,7 +258,6 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; finally query.Free; - source.Free; end; end else Result := INFORMATION_NOT_FOUND; end; From 3b36fa39bcd7622603a045ebe5a949c8dca196b0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 22:17:57 +0800 Subject: [PATCH 0672/2794] txqueryenginehtml, add property engine --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 790ea4a03..daf517d75 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -796,6 +796,7 @@ TXQueryEngineHTML = class function XPathString(Expression: String): String; inline; function CSS(Expression: String): IXQValue; inline; function CSSString(Expression: String): String; inline; + property Engine: TXQueryEngine read FEngine; end; IXQValue = xquery.IXQValue; From 43c9d55f7d64cb93169a1f0ee11e901a616bd0d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 22:20:25 +0800 Subject: [PATCH 0673/2794] batoto, fix show scan group --- baseunits/modules/Batoto.pas | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index f63f8d906..442c27e7f 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -211,8 +211,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; - v: IXQValue; - s: String; + v, w: IXQValue; + s, t: String; i: Integer; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -248,11 +248,17 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; if OptionBatotoShowAllLang then - s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]/td[1]/a' - else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]/td[1]/a'; + s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]' + else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]'; for v in query.XPath(s) do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + w := query.Engine.evaluateXPath3('td[1]/a', v.toNode); + chapterLinks.Add(w.toNode.getAttribute('href')); + t := ''; + if OptionBatotoShowScanGroup then begin + t := query.Engine.evaluateXPath3('td[3]', v.toNode).toString; + if t <> '' then t := ' ['+ t +']' else t := ''; + end; + chapterName.Add(w.toString + t); end; InvertStrings([chapterLinks, chapterName]) end; From 596c30eedd37db4fdf81eff7097d86dbd4483dfe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 22:31:34 +0800 Subject: [PATCH 0674/2794] batoto, fix add language and scangroup to chapter title fix #138 --- baseunits/modules/Batoto.pas | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 442c27e7f..32cc377e8 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -212,7 +212,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; var query: TXQueryEngineHTML; v, w: IXQValue; - s, t: String; + s, t, l: String; i: Integer; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -253,12 +253,16 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; for v in query.XPath(s) do begin w := query.Engine.evaluateXPath3('td[1]/a', v.toNode); chapterLinks.Add(w.toNode.getAttribute('href')); - t := ''; + t := w.toString; + if OptionBatotoShowAllLang then begin + l := query.Engine.evaluateXPath3('td[2]/div', v.toNode).toNode.getAttribute('title'); + if l <> '' then t += ' ['+ l +']'; + end; if OptionBatotoShowScanGroup then begin - t := query.Engine.evaluateXPath3('td[3]', v.toNode).toString; - if t <> '' then t := ' ['+ t +']' else t := ''; + l := query.Engine.evaluateXPath3('td[3]', v.toNode).toString; + if l <> '' then t += ' ['+ l +']'; end; - chapterName.Add(w.toString + t); + chapterName.Add(t); end; InvertStrings([chapterLinks, chapterName]) end; From 84a5019613f389614b20e89aa9c1969b88b1c47e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Dec 2015 23:01:48 +0800 Subject: [PATCH 0675/2794] Bump version 0.9.27.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7699394ad..2950cd6bc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,11 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.27.0 (26-12-2015) +[+] Added Remove MangaFox watermark feature. Options > Misc +[*] Batoto: fix add language and scan group to chapter title +[*] Various changes and bug fixes + 0.9.26.0 (23-12-2015) [*] Batoto: fix login [*] ExHentai: fix login diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e9a76ef61..953c1c368 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="26"/> + <RevisionNr Value="27"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 733ee4518..3c5be1e7b 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.26.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.26.0/fmd_0.9.26.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.26.0/fmd_0.9.26.0_Win64.7z +VERSION=0.9.27.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.27.0/fmd_0.9.27.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.27.0/fmd_0.9.27.0_Win64.7z From 0396dcc19097905ec4b22ee7f9ca7a4242a6a92b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 05:23:36 +0800 Subject: [PATCH 0676/2794] batoto, fix access without account fix #140 --- baseunits/modules/Batoto.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 32cc377e8..dd2c9ef4a 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -91,9 +91,10 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; s: String; begin Result := False; - s := ''; AHTTP.Cookies.Text := Account.Cookies['Batoto']; if AHTTP.GET(AURL) then begin + Result := True; + if (Account.Enabled[modulename] = False) or (Account.Username[modulename] = '') then Exit; s := StreamToString(AHTTP.Document); Result := (Pos('class=''logged_in''', s) > 0) or (Pos('class="logged_in"', s) > 0); if not Result then From 928fc759dd8f682f1a2c2ceffe465342d662c13c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 06:45:42 +0800 Subject: [PATCH 0677/2794] baseunit, corrected xpath/css --- baseunits/modules/Batoto.pas | 6 +++--- baseunits/uBaseUnit.pas | 38 +++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index dd2c9ef4a..22b27c28d 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -252,15 +252,15 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]' else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]'; for v in query.XPath(s) do begin - w := query.Engine.evaluateXPath3('td[1]/a', v.toNode); + w := query.XPath('td[1]/a', v.toNode); chapterLinks.Add(w.toNode.getAttribute('href')); t := w.toString; if OptionBatotoShowAllLang then begin - l := query.Engine.evaluateXPath3('td[2]/div', v.toNode).toNode.getAttribute('title'); + l := query.XPath('td[2]/div', v.toNode).toNode.getAttribute('title'); if l <> '' then t += ' ['+ l +']'; end; if OptionBatotoShowScanGroup then begin - l := query.Engine.evaluateXPath3('td[3]', v.toNode).toString; + l := query.XPath('td[3]', v.toNode).toString; if l <> '' then t += ' ['+ l +']'; end; chapterName.Add(t); diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index daf517d75..f66d40bce 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -787,15 +787,15 @@ TXQueryEngineHTML = class private FEngine: TXQueryEngine; FTreeParser: TTreeParser; - function Eval(Expression: String; isCSS: Boolean = False): IXQValue; + function Eval(Expression: String; isCSS: Boolean = False; Tree: TTreeNode = nil): IXQValue; public constructor Create(HTML: String = ''); destructor Destroy; override; procedure ParseHTML(HTML: String); - function XPath(Expression: String): IXQValue; inline; - function XPathString(Expression: String): String; inline; - function CSS(Expression: String): IXQValue; inline; - function CSSString(Expression: String): String; inline; + function XPath(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; + function XPathString(Expression: String; Tree: TTreeNode = nil): String; inline; + function CSS(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; + function CSSString(Expression: String; Tree: TTreeNode = nil): String; inline; property Engine: TXQueryEngine read FEngine; end; @@ -3688,13 +3688,17 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); { TXQueryEngineHTML } -function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean): IXQValue; +function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean; Tree: TTreeNode): IXQValue; +var + t: TTreeNode; begin Result := xqvalue(); + t := Tree; + if t = nil then t := FTreeParser.getLastTree; if Expression = '' then Exit; try - if isCSS then Result := FEngine.evaluateCSS3(Expression, FTreeParser.getLastTree) - else Result := FEngine.evaluateXPath3(Expression, FTreeParser.getLastTree); + if isCSS then Result := FEngine.evaluateCSS3(Expression, t) + else Result := FEngine.evaluateXPath3(Expression, t); except end; end; @@ -3727,24 +3731,26 @@ procedure TXQueryEngineHTML.ParseHTML(HTML: String); if HTML <> '' then FTreeParser.parseTree(HTML); end; -function TXQueryEngineHTML.XPath(Expression: String): IXQValue; +function TXQueryEngineHTML.XPath(Expression: String; Tree: TTreeNode): IXQValue; begin - Result := Eval(Expression); + Result := Eval(Expression, False, Tree); end; -function TXQueryEngineHTML.XPathString(Expression: String): String; +function TXQueryEngineHTML.XPathString(Expression: String; Tree: TTreeNode + ): String; begin - Result := Eval(Expression).toString; + Result := Eval(Expression, False, Tree).toString; end; -function TXQueryEngineHTML.CSS(Expression: String): IXQValue; +function TXQueryEngineHTML.CSS(Expression: String; Tree: TTreeNode): IXQValue; begin - Result := Eval(Expression, True); + Result := Eval(Expression, True, Tree); end; -function TXQueryEngineHTML.CSSString(Expression: String): String; +function TXQueryEngineHTML.CSSString(Expression: String; Tree: TTreeNode + ): String; begin - Result := Eval(Expression, True).toString; + Result := Eval(Expression, True, Tree).toString; end; { TParseHTML } From 77ae9ed084f80b55bb72f117f0976cd47ec1a060 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 09:31:26 +0800 Subject: [PATCH 0678/2794] baseunit, add stringreplacebrackets function --- baseunits/uBaseUnit.pas | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f66d40bce..d11640b6e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -875,6 +875,7 @@ function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; // StringUtils +function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; function StreamToString(const M: TMemoryStream): string; inline; function GetRightValue(const name, s: string): string; function QuotedStrd(const S: string): string; overload; inline; @@ -2116,6 +2117,32 @@ function GetHeaderValue(const AHeaders: TStrings; HName: String): String; end; end; +function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; +var + b1, b2: Char; + p, r: String; + i: Integer; +begin + Result := Trim(S); + if OldPattern = '' then Exit; + p := Trim(OldPattern); + r := Trim(NewPattern); + b1 := #0; + b2 := #0; + i := Pos(p, Result); + if i > 0 then begin + if i > 1 then b1 := Result[i - 1]; + if i + Length(p) <= Length(Result) then b2 := Result[i + Length(p)]; + if b1 in ['(', '[', '{'] then p := b1 + p else b1 := #0; + if b2 in [')', ']', '}'] then p := p + b2 else b2 := #0; + if r <> '' then begin + if b1 <> #0 then r := b1 + r; + if b2 <> #0 then r := r + b2; + end; + Result := StringReplace(Result, p, r, Flags); + end; +end; + function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, ANumbering : String; const AIsUnicodeRemove : Boolean) : String; var From 5bb1faff66dd4f4337b1e87449fcc5dbc3765532 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 09:31:58 +0800 Subject: [PATCH 0679/2794] baseunit, fix customrename --- baseunits/uBaseUnit.pas | 93 +++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d11640b6e..c4b73e41e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2148,52 +2148,71 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, var chap: String; begin - Result := ''; - chap := Trim(AChapter); - //Convert Digit in chapter name - if MainForm.options.ReadBool('saveto', 'ConvertDigitVolume', True) then - if MainForm.options.ReadBool('saveto', 'ConvertDigitChapter', True) then - padZero(chap, MainForm.options.ReadInteger('saveto', 'DigitVolumeLength', 2), - MainForm.options.ReadInteger('saveto', 'DigitChapterLength', 3)) - else - padZero(chap, MainForm.options.ReadInteger('saveto', 'DigitVolumeLength', 2), 0) - else if MainForm.options.ReadBool('saveto', 'ConvertDigitChapter', True) then - padZero(chap, 0, MainForm.options.ReadInteger('saveto', 'DigitChapterLength', 3)); - - if (Pos('%NUMBERING%', AString) = 0) and (Pos('%CHAPTER%', AString) = 0) then - Result := ANumbering + AString - else - Result := AString; + Result := Trim(AString); - Result := TrimLeft(TrimRight(Result)); - Result := StringReplace(Result, '%WEBSITE%', AWebsite, [rfReplaceAll]); - Result := StringReplace(Result, '%MANGA%', AMangaName, [rfReplaceAll]); - Result := StringReplace(Result, '%AUTHOR%', AAuthor, [rfReplaceAll]); - Result := StringReplace(Result, '%ARTIST%', AArtist, [rfReplaceAll]); - Result := StringReplace(Result, '%CHAPTER%', chap, [rfReplaceAll]); - if AWebsite = WebsiteRoots[FAKKU_ID, 0] then - begin - if Pos('%NUMBERING% - ', Result) > 0 then - Result := StringReplace(Result, '%NUMBERING% - ', '', [rfReplaceAll]) + // for rename chapter only + if AChapter <> '' then begin + // numbering/index + if (Pos('%NUMBERING%', Result) = 0) and (Pos('%CHAPTER%', Result) = 0) then + Result := ANumbering + Result else - Result := StringReplace(Result, '%NUMBERING%', '', [rfReplaceAll]) - end - else - Result := StringReplace(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); - Result := StringReplace(Result, '/', '', [rfReplaceAll]); - Result := StringReplace(Result, '\', '', [rfReplaceAll]); - if Result = '' then - begin + Result := Result; if AWebsite = WebsiteRoots[FAKKU_ID, 0] then - Result := chap + begin + if Pos('%NUMBERING% - ', Result) > 0 then + Result := StringReplaceBrackets(Result, '%NUMBERING% - ', '', [rfReplaceAll]) + else + Result := StringReplaceBrackets(Result, '%NUMBERING%', '', [rfReplaceAll]) + end else - Result := ANumbering; + Result := StringReplaceBrackets(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); + // pad number + chap := Trim(AChapter); + with MainForm.options do begin + if ReadBool('saveto', 'ConvertDigitVolume', False) then begin + if ReadBool('saveto', 'ConvertDigitChapter', False) then + padZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), + ReadInteger('saveto', 'DigitChapterLength', 3)) + else + padZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), 0); + end + else if ReadBool('saveto', 'ConvertDigitChapter', False) then + padZero(chap, 0, ReadInteger('saveto', 'DigitChapterLength', 3)); + end; + Result := StringReplaceBrackets(Result, '%CHAPTER%', chap, [rfReplaceAll]); + + if Result = '' then begin + if AWebsite = WebsiteRoots[FAKKU_ID, 0] then + Result := chap + else + Result := ANumbering; + end; end; + + Result := StringReplaceBrackets(Result, '%WEBSITE%', AWebsite, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%MANGA%', AMangaName, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%AUTHOR%', AAuthor, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%ARTIST%', AArtist, [rfReplaceAll]); + + if Result = '' then Result := AMangaName; + + if Result = '' then Exit; + + // strip unicode character if AIsUnicodeRemove then Result := UnicodeRemove(Result); + // replace htmlentities + Result := HTMLEntitiesFilter(StringFilter(Result)); + + // remove unaccepted character (Windows) + Result := RemoveSymbols(Result); + + // remove pathdelim + Result := StringReplace(Result, '/', '', [rfReplaceAll]); + Result := StringReplace(Result, '\', '', [rfReplaceAll]); + Result := Trim(Result); - Result := RemoveSymbols(HTMLEntitiesFilter(StringFilter(Result))); end; function GetString(const Source, sStart, sEnd: String): String; From 6a0b02daa8fab8a94db71f23ce0f6a11703a749b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 09:41:33 +0800 Subject: [PATCH 0680/2794] fix and cleanup --- baseunits/uBaseUnit.pas | 2 +- baseunits/uGetMangaInfosThread.pas | 2 +- baseunits/uSilentThread.pas | 4 +-- mangadownloader/forms/frmMain.lfm | 47 +++++++++--------------------- mangadownloader/forms/frmMain.pas | 14 ++------- 5 files changed, 21 insertions(+), 48 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c4b73e41e..9dc0d0aa9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -632,8 +632,8 @@ interface OptionLetFMDDo: TFMDDo = DO_NOTHING; + OptionGenerateMangaFolderName: Boolean = False; OptionCustomRename: String; - OptionAutoNumberChapterChecked: Boolean = True; OptionPDFQuality: Cardinal = 95; OptionConnectionMaxRetry: Integer = 0; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index ffd2ee208..0eec9b2ad 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -84,7 +84,7 @@ procedure TGetMangaInfosThread.DoGetInfos; FNumChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); end; - FInfo.isGenerateFolderChapterName := MainForm.cbOptionGenerateChapterName.Checked; + FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolderName; FInfo.isRemoveUnicode := MainForm.cbOptionPathConvert.Checked; infob := INFORMATION_NOT_FOUND; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 325e484d3..b5a5ef072 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -365,7 +365,7 @@ procedure TSilentThread.MainThreadAfterChecking; edSaveTo.Text := CorrectPathSys(edSaveTo.Text); FSavePath := edSaveTo.Text; // save to - if cbOptionGenerateMangaFolderName.Checked then + if OptionGenerateMangaFolderName then begin if not cbOptionPathConvert.Checked then FSavePath := FSavePath + RemoveSymbols(Info.mangaInfo.title) @@ -461,7 +461,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; else s := CorrectPathSys(FSavePath); - if cbOptionGenerateMangaFolderName.Checked then + if OptionGenerateMangaFolderName then begin if not cbOptionPathConvert.Checked then s := s + RemoveSymbols(title) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 55aefc104..b16aa33ed 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,13 +37,13 @@ object MainForm: TMainForm Height = 549 Top = 11 Width = 614 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 4 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1831,10 +1831,10 @@ object MainForm: TMainForm Height = 444 Top = 8 Width = 587 - ActivePage = tsGeneral + ActivePage = tsSaveTo Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 3 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2330,7 +2330,7 @@ object MainForm: TMainForm Height = 416 Top = 0 Width = 579 - HorzScrollBar.Page = 544 + HorzScrollBar.Page = 543 VertScrollBar.Page = 400 Align = alClient BorderStyle = bsNone @@ -2384,7 +2384,7 @@ object MainForm: TMainForm Width = 208 Caption = 'Remove manga name from chapter' ParentFont = False - TabOrder = 9 + TabOrder = 7 end object cbOptionGenerateMangaFolderName: TCheckBox Left = 22 @@ -2395,16 +2395,6 @@ object MainForm: TMainForm ParentFont = False TabOrder = 0 end - object cbOptionGenerateChapterName: TCheckBox - Left = 294 - Height = 19 - Top = 70 - Width = 246 - Caption = 'Generate chapter folder with chapter name' - ParentFont = False - TabOrder = 1 - Visible = False - end object cbOptionPathConvert: TCheckBox Left = 22 Height = 19 @@ -2412,16 +2402,7 @@ object MainForm: TMainForm Width = 517 Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' ParentFont = False - TabOrder = 2 - end - object cbOptionAutoNumberChapter: TCheckBox - Left = 294 - Height = 19 - Top = 54 - Width = 134 - Caption = 'Auto number chapter' - TabOrder = 3 - Visible = False + TabOrder = 1 end object edOptionCustomRename: TEdit Left = 22 @@ -2429,7 +2410,7 @@ object MainForm: TMainForm Top = 158 Width = 434 Anchors = [akTop, akLeft, akRight] - TabOrder = 4 + TabOrder = 2 TextHint = 'Custom rename' end object lbOptionCustomRename: TLabel @@ -2469,7 +2450,7 @@ object MainForm: TMainForm Width = 50 MaxValue = 10 MinValue = 1 - TabOrder = 5 + TabOrder = 3 Value = 1 end object seOptionDigitChapter: TSpinEdit @@ -2479,7 +2460,7 @@ object MainForm: TMainForm Width = 50 MaxValue = 10 MinValue = 1 - TabOrder = 6 + TabOrder = 4 Value = 1 end object cbOptionDigitVolume: TCheckBox @@ -2489,7 +2470,7 @@ object MainForm: TMainForm Width = 61 Caption = 'Volume' OnChange = cbOptionDigitVolumeChange - TabOrder = 7 + TabOrder = 5 end object cbOptionDigitChapter: TCheckBox Left = 158 @@ -2498,7 +2479,7 @@ object MainForm: TMainForm Width = 62 Caption = 'Chapter' OnChange = cbOptionDigitChapterChange - TabOrder = 8 + TabOrder = 6 end end object seOptionPDFQuality: TSpinEdit @@ -4369,7 +4350,7 @@ object MainForm: TMainForm Interval = 600000 OnTimer = itCheckFavTimer left = 760 - top = 256 + top = 200 end object itRefreshDLInfo: TIdleTimer Enabled = False @@ -5821,7 +5802,7 @@ object MainForm: TMainForm Enabled = False OnTimer = itMonitorTimer left = 760 - top = 296 + top = 240 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 218814f98..427da4704 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -176,10 +176,8 @@ TMainForm = class(TForm) cbAddAsStopped: TCheckBox; cbOptionShowQuitDialog: TCheckBox; cbOptionPathConvert: TCheckBox; - cbOptionGenerateChapterName: TCheckBox; cbOptionGenerateMangaFolderName: TCheckBox; cbOptionMinimizeToTray: TCheckBox; - cbOptionAutoNumberChapter: TCheckBox; cbSearchFromAllSites: TCheckBox; ckFilterDoujinshi: TCheckBox; ckFilterDrama: TCheckBox; @@ -1844,7 +1842,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); s := CorrectPathSys(edSaveTo.Text); // save to - if cbOptionGenerateMangaFolderName.Checked then + if OptionGenerateMangaFolderName then begin if not cbOptionPathConvert.Checked then s := s + RemoveSymbols(mangaInfo.title) @@ -1874,7 +1872,7 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); s := CorrectPathSys(edSaveTo.Text); // save to - if cbOptionGenerateMangaFolderName.Checked then + if OptionGenerateMangaFolderName then begin if not cbOptionPathConvert.Checked then s := s + RemoveSymbols(mangaInfo.title) @@ -4322,7 +4320,6 @@ procedure TMainForm.LoadOptions; cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); cbOptionMinimizeToTray.Checked := ReadBool('general', 'MinimizeToTray', False); cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); - cbOptionAutoNumberChapter.Checked := ReadBool('general', 'AutoNumberChapter', True); edOptionExternalPath.FileName := ReadString('general', 'ExternalProgramPath', ''); edOptionExternalParams.Text := ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); cbAddAsStopped.Checked := ReadBool('general', 'AddAsStopped', False); @@ -4359,9 +4356,7 @@ procedure TMainForm.LoadOptions; rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); cbOptionPathConvert.Checked := ReadBool('saveto', 'PathConvert', False); cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', True); - cbOptionGenerateChapterName.Checked := ReadBool('saveto', 'GenerateChapterName', False); cbOptionGenerateMangaFolderName.Checked := ReadBool('saveto', 'GenerateMangaName', True); - cbOptionAutoNumberChapter.Checked := ReadBool('saveto', 'AutoNumberChapter', True); seOptionPDFQuality.Value := ReadInteger('saveto', 'PDFQuality', 100); edOptionCustomRename.Text := ReadString('saveto', 'CustomRename', DEFAULT_CUSTOM_RENAME); if Trim(edOptionCustomRename.Text) = '' then @@ -4479,11 +4474,8 @@ procedure TMainForm.SaveOptions; edOptionDefaultPath.Text := CorrectPathSys(edOptionDefaultPath.Text); WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); WriteBool('saveto', 'PathConvert', cbOptionPathConvert.Checked); - WriteBool('saveto', 'GenerateChapterName', cbOptionGenerateChapterName.Checked); WriteBool('saveto', 'GenerateMangaName', cbOptionGenerateMangaFolderName.Checked); WriteInteger('saveto', 'Compress', rgOptionCompress.ItemIndex); - WriteBool('saveto', 'AutoNumberChapter', cbOptionAutoNumberChapter.Checked); - OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; WriteInteger('saveto', 'PDFQuality', seOptionPDFQuality.Value); WriteBool('saveto', 'RemoveMangaNameFromChapter', cbOptionRemoveMangaNameFromChapter.Checked); if Trim(edOptionCustomRename.Text) = '' then @@ -4581,7 +4573,6 @@ procedure TMainForm.ApplyOptions; end; OptionLetFMDDo := TFMDDo(cbOptionLetFMDDo.ItemIndex); OptionEnableLoadCover := cbOptionEnableLoadCover.Checked; - OptionAutoNumberChapterChecked := cbOptionAutoNumberChapter.Checked; //view ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; @@ -4628,6 +4619,7 @@ procedure TMainForm.ApplyOptions; OptionCustomRename := edOptionCustomRename.Text; DLManager.compress := rgOptionCompress.ItemIndex; OptionRemoveMangaNameFromChapter := cbOptionRemoveMangaNameFromChapter.Checked; + OptionGenerateMangaFolderName := cbOptionGenerateMangaFolderName.Checked; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; From 189c86e0b1e00263ef49c6343f8b1840609dbad0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 09:44:31 +0800 Subject: [PATCH 0681/2794] fix translations --- mangadownloader/languages/fmd.en.po | 8 -------- mangadownloader/languages/fmd.id_ID.po | 10 +--------- mangadownloader/languages/fmd.po | 8 -------- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index c48bf97be..15d610d8b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -514,10 +514,6 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Auto check for latest version " -#: tmainform.cboptionautonumberchapter.caption -msgid "Auto number chapter" -msgstr "Auto number chapter" - #: tmainform.cboptionbatotoshowalllang.caption msgctxt "tmainform.cboptionbatotoshowalllang.caption" msgid "[Batoto] Show All Language" @@ -540,10 +536,6 @@ msgstr "Volume" msgid "Enable load manga cover" msgstr "Enable load manga cover" -#: tmainform.cboptiongeneratechaptername.caption -msgid "Generate chapter folder with chapter name" -msgstr "Generate chapter folder with chapter name" - #: tmainform.cboptiongeneratemangafoldername.caption msgid "Auto generate folder based on manga's name" msgstr "Auto generate folder based on manga's name" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 91d311c17..f777b7e36 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -481,10 +481,6 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Otomatis periksa versi terbaru" -#: tmainform.cboptionautonumberchapter.caption -msgid "Auto number chapter" -msgstr "Otomatis nomor bab" - #: tmainform.cboptionbatotoshowalllang.caption msgctxt "tmainform.cboptionbatotoshowalllang.caption" msgid "[Batoto] Show All Language" @@ -507,10 +503,6 @@ msgstr "Volume" msgid "Enable load manga cover" msgstr "Aktifkan sampul komik" -#: tmainform.cboptiongeneratechaptername.caption -msgid "Generate chapter folder with chapter name" -msgstr "Buat folder dengan nama bab" - #: tmainform.cboptiongeneratemangafoldername.caption msgid "Auto generate folder based on manga's name" msgstr "Buat otomatis folder berdasarkan nama komik" @@ -1075,7 +1067,7 @@ msgstr "Batas waktu koneksi (detik)" #: tmainform.lboptioncustomrename.caption msgid "Chapter folder name:" -msgstr "Nama folder:" +msgstr "Nama folder bab:" #: tmainform.lboptioncustomrenamehint.caption msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT.CAPTION" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 7f1e45813..232a30c6f 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -453,10 +453,6 @@ msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" msgid "Auto check for latest version " msgstr "" -#: tmainform.cboptionautonumberchapter.caption -msgid "Auto number chapter" -msgstr "" - #: tmainform.cboptionbatotoshowalllang.caption msgctxt "TMAINFORM.CBOPTIONBATOTOSHOWALLLANG.CAPTION" msgid "[Batoto] Show All Language" @@ -479,10 +475,6 @@ msgstr "" msgid "Enable load manga cover" msgstr "" -#: tmainform.cboptiongeneratechaptername.caption -msgid "Generate chapter folder with chapter name" -msgstr "" - #: tmainform.cboptiongeneratemangafoldername.caption msgid "Auto generate folder based on manga's name" msgstr "" From 3d850157faa5904b63633ac1edd0ea926c12abc2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 10:55:29 +0800 Subject: [PATCH 0682/2794] add manga info to manga folder with custom rename close #141 change customrename variable, old config will be lost --- baseunits/uBaseUnit.pas | 7 +- baseunits/uFavoritesManager.pas | 4 +- baseunits/uGetMangaInfosThread.pas | 2 +- baseunits/uSilentThread.pas | 52 +++++++------ mangadownloader/forms/frmMain.lfm | 117 ++++++++++++++++++----------- mangadownloader/forms/frmMain.pas | 73 +++++++++++------- 6 files changed, 157 insertions(+), 98 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9dc0d0aa9..10316a0ae 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -228,7 +228,8 @@ interface SOCKHEARTBEATRATE = 400; DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; - DEFAULT_CUSTOM_RENAME = '%NUMBERING% - %CHAPTER%'; + DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; + DEFAULT_CHAPTER_CUSTOMRENAME = '%NUMBERING% - %CHAPTER%'; FMDFormatSettings :TFormatSettings = ( CurrencyFormat :1; @@ -632,8 +633,10 @@ interface OptionLetFMDDo: TFMDDo = DO_NOTHING; + OptionChangeUnicodeCharacter: Boolean = False; OptionGenerateMangaFolderName: Boolean = False; - OptionCustomRename: String; + OptionMangaCustomRename: String; + OptionChapterCustomRename: String; OptionPDFQuality: Cardinal = 95; OptionConnectionMaxRetry: Integer = 0; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 27bbf62ea..885546486 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -685,14 +685,14 @@ procedure TFavoriteManager.ShowResult; ChapterLinks.Assign(NewMangaInfo.chapterLinks); for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do ChapterName.Add(CustomRename( - OptionCustomRename, + OptionChapterCustomRename, FavoriteInfo.Website, FavoriteInfo.Title, NewMangaInfo.authors, NewMangaInfo.artists, NewMangaInfo.chapterName[i], Format('%.4d', [NewMangaInfoChaptersPos[i] + 1]), - MainForm.cbOptionPathConvert.Checked)); + OptionChangeUnicodeCharacter)); if LNCResult = ncrDownload then begin DownloadInfo.Status := RS_Waiting; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 0eec9b2ad..40f993250 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -85,7 +85,7 @@ procedure TGetMangaInfosThread.DoGetInfos; end; FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolderName; - FInfo.isRemoveUnicode := MainForm.cbOptionPathConvert.Checked; + FInfo.isRemoveUnicode := OptionChangeUnicodeCharacter; infob := INFORMATION_NOT_FOUND; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index b5a5ef072..d08ea1dd3 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -16,7 +16,7 @@ interface uses Classes, SysUtils, uBaseUnit, uData, uFMDThread, uDownloadsManager, - WebsiteModules; + WebsiteModules, LazFileUtils; type @@ -326,14 +326,14 @@ procedure TSilentThread.MainThreadAfterChecking; for i := 0 to Info.mangaInfo.numChapter - 1 do begin // generate folder name - s := CustomRename(OptionCustomRename, - website, - title, - info.mangaInfo.authors, - Info.mangaInfo.artists, - Info.mangaInfo.chapterName.Strings[i], - Format('%.4d', [i + 1]), - cbOptionPathConvert.Checked); + s := CustomRename(OptionChapterCustomRename, + website, + title, + info.mangaInfo.authors, + Info.mangaInfo.artists, + Info.mangaInfo.chapterName.Strings[i], + Format('%.4d', [i + 1]), + OptionChangeUnicodeCharacter); DLManager.TaskItem(p).chapterName.Add(s); DLManager.TaskItem(p).chapterLinks.Add( Info.mangaInfo.chapterLinks.Strings[i]); @@ -362,16 +362,19 @@ procedure TSilentThread.MainThreadAfterChecking; edSaveTo.Text := options.ReadString('saveto', 'SaveTo', DEFAULT_PATH); if Trim(edSaveTo.Text) = '' then edSaveTo.Text := DEFAULT_PATH; - edSaveTo.Text := CorrectPathSys(edSaveTo.Text); + edSaveTo.Text := CleanAndExpandDirectory(CorrectPathSys(edSaveTo.Text)); FSavePath := edSaveTo.Text; // save to if OptionGenerateMangaFolderName then - begin - if not cbOptionPathConvert.Checked then - FSavePath := FSavePath + RemoveSymbols(Info.mangaInfo.title) - else - FSavePath := FSavePath + RemoveSymbols(UnicodeRemove(Info.mangaInfo.title)); - end; + FSavePath := FSavePath + CustomRename( + OptionMangaCustomRename, + website, + title, + info.mangaInfo.authors, + info.mangaInfo.artists, + '', + '', + OptionChangeUnicodeCharacter); FSavePath := CorrectPathSys(FSavePath); end; DLManager.TaskItem(p).downloadInfo.SaveTo := FSavePath; @@ -461,13 +464,18 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; else s := CorrectPathSys(FSavePath); + s := CleanAndExpandDirectory(s); + if OptionGenerateMangaFolderName then - begin - if not cbOptionPathConvert.Checked then - s := s + RemoveSymbols(title) - else - s := s + RemoveSymbols(UnicodeRemove(title)); - end; + s := s + CustomRename( + OptionMangaCustomRename, + website, + title, + info.mangaInfo.authors, + info.mangaInfo.artists, + '', + '', + OptionChangeUnicodeCharacter); s := CorrectPathSys(s); s2 := ''; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b16aa33ed..8ed0b90be 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,13 +37,13 @@ object MainForm: TMainForm Height = 549 Top = 11 Width = 614 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1831,10 +1831,10 @@ object MainForm: TMainForm Height = 444 Top = 8 Width = 587 - ActivePage = tsSaveTo + ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 3 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2330,18 +2330,18 @@ object MainForm: TMainForm Height = 416 Top = 0 Width = 579 - HorzScrollBar.Page = 543 - VertScrollBar.Page = 400 + HorzScrollBar.Page = 537 + VertScrollBar.Page = 416 Align = alClient BorderStyle = bsNone ClientHeight = 416 - ClientWidth = 579 + ClientWidth = 562 TabOrder = 0 object rgOptionCompress: TRadioGroup Left = 20 Height = 60 Top = 66 - Width = 520 + Width = 503 Anchors = [akTop, akLeft, akRight] AutoFill = True Caption = 'Save downloaded chapters as' @@ -2354,7 +2354,7 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 40 - ClientWidth = 516 + ClientWidth = 499 Columns = 4 ItemIndex = 0 Items.Strings = ( @@ -2368,64 +2368,64 @@ object MainForm: TMainForm end object gbOptionRenaming: TGroupBox Left = 20 - Height = 230 + Height = 254 Top = 170 - Width = 520 + Width = 503 Anchors = [akTop, akLeft, akRight] Caption = 'Renaming' - ClientHeight = 210 - ClientWidth = 516 + ClientHeight = 234 + ClientWidth = 499 ParentFont = False TabOrder = 1 object cbOptionRemoveMangaNameFromChapter: TCheckBox - Left = 22 + Left = 16 Height = 19 - Top = 10 + Top = 104 Width = 208 Caption = 'Remove manga name from chapter' ParentFont = False TabOrder = 7 end object cbOptionGenerateMangaFolderName: TCheckBox - Left = 22 + Left = 16 Height = 19 - Top = 54 + Top = 30 Width = 261 Caption = 'Auto generate folder based on manga''s name' ParentFont = False TabOrder = 0 end - object cbOptionPathConvert: TCheckBox - Left = 22 + object cbOptionChangeUnicodeCharacter: TCheckBox + Left = 16 Height = 19 - Top = 32 + Top = 8 Width = 517 Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' ParentFont = False TabOrder = 1 end - object edOptionCustomRename: TEdit - Left = 22 + object edOptionChapterCustomRename: TEdit + Left = 16 Height = 23 - Top = 158 - Width = 434 + Top = 200 + Width = 417 Anchors = [akTop, akLeft, akRight] TabOrder = 2 TextHint = 'Custom rename' end object lbOptionCustomRename: TLabel - Left = 22 + Left = 16 Height = 15 - Top = 142 + Top = 184 Width = 112 Caption = 'Chapter folder name:' ParentColor = False end - object lbOptionCustomRenameHint: TLabel - Left = 462 + object lbOptionChapterCustomRenameHint: TLabel + Left = 436 Height = 15 Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' - Top = 160 + Top = 203 Width = 13 Anchors = [akTop, akRight] Caption = '[?]' @@ -2436,17 +2436,17 @@ object MainForm: TMainForm ShowHint = True end object lbOptionRenameDigits: TLabel - Left = 22 + Left = 16 Height = 15 - Top = 86 + Top = 128 Width = 78 Caption = 'Rename digits' ParentColor = False end object seOptionDigitVolume: TSpinEdit - Left = 94 + Left = 88 Height = 23 - Top = 108 + Top = 150 Width = 50 MaxValue = 10 MinValue = 1 @@ -2454,9 +2454,9 @@ object MainForm: TMainForm Value = 1 end object seOptionDigitChapter: TSpinEdit - Left = 230 + Left = 224 Height = 23 - Top = 108 + Top = 150 Width = 50 MaxValue = 10 MinValue = 1 @@ -2464,23 +2464,54 @@ object MainForm: TMainForm Value = 1 end object cbOptionDigitVolume: TCheckBox - Left = 25 + Left = 19 Height = 19 - Top = 110 + Top = 152 Width = 61 Caption = 'Volume' OnChange = cbOptionDigitVolumeChange TabOrder = 5 end object cbOptionDigitChapter: TCheckBox - Left = 158 + Left = 152 Height = 19 - Top = 110 + Top = 152 Width = 62 Caption = 'Chapter' OnChange = cbOptionDigitChapterChange TabOrder = 6 end + object edOptionMangaCustomRename: TEdit + Left = 16 + Height = 23 + Top = 72 + Width = 417 + Anchors = [akTop, akLeft, akRight] + TabOrder = 8 + TextHint = 'Custom rename' + end + object lbOptionMangaRename: TLabel + Left = 16 + Height = 15 + Top = 56 + Width = 107 + Caption = 'Manga folder name:' + ParentColor = False + end + object lbOptionMangaCustomRenameHint: TLabel + Left = 436 + Height = 15 + Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10#13#10'Note:'#13#10'Manga folder name must have at least %MANGA%.' + Top = 75 + Width = 13 + Anchors = [akTop, akRight] + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end end object seOptionPDFQuality: TSpinEdit Left = 44 @@ -2521,7 +2552,7 @@ object MainForm: TMainForm ShowHint = True end object btOptionBrowse: TSpeedButton - Left = 512 + Left = 495 Height = 23 Top = 34 Width = 23 @@ -2568,7 +2599,7 @@ object MainForm: TMainForm Left = 20 Height = 23 Top = 34 - Width = 490 + Width = 473 Anchors = [akTop, akLeft, akRight] ParentFont = False TabOrder = 3 @@ -5817,8 +5848,8 @@ object MainForm: TMainForm end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - left = 283 - top = 416 + left = 152 + top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 427da4704..c81fc807c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -65,6 +65,9 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + edOptionMangaCustomRename: TEdit; + lbOptionMangaCustomRenameHint: TLabel; + lbOptionMangaRename: TLabel; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; pcAbout: TPageControl; @@ -103,7 +106,7 @@ TMainForm = class(TForm) lbOptionRenameDigits: TLabel; lbFilterHint: TLabel; lbOptionExternal: TLabel; - lbOptionCustomRenameHint: TLabel; + lbOptionChapterCustomRenameHint: TLabel; lbOptionCustomRenameHint1: TLabel; lbOptionExternalParamsHint: TLabel; TransferRateGraphList: TListChartSource; @@ -175,7 +178,7 @@ TMainForm = class(TForm) cbOnlyNew: TCheckBox; cbAddAsStopped: TCheckBox; cbOptionShowQuitDialog: TCheckBox; - cbOptionPathConvert: TCheckBox; + cbOptionChangeUnicodeCharacter: TCheckBox; cbOptionGenerateMangaFolderName: TCheckBox; cbOptionMinimizeToTray: TCheckBox; cbSearchFromAllSites: TCheckBox; @@ -192,7 +195,7 @@ TMainForm = class(TForm) edFilterAuthors: TEdit; edFilterArtists: TEdit; edCustomGenres: TEdit; - edOptionCustomRename: TEdit; + edOptionChapterCustomRename: TEdit; edOptionHost: TEdit; edOptionPass: TEdit; edOptionPort: TEdit; @@ -1806,14 +1809,14 @@ procedure TMainForm.btDownloadClick(Sender: TObject); end; DLManager.TaskItem(pos).Website := mangaInfo.website; // generate folder name - s := CustomRename(OptionCustomRename, + s := CustomRename(OptionChapterCustomRename, mangaInfo.website, mangaInfo.title, mangaInfo.authors, mangaInfo.artists, mangaInfo.chapterName.Strings[xNode^.Index], Format('%.4d', [xNode^.Index + 1]), - cbOptionPathConvert.Checked); + OptionChangeUnicodeCharacter); DLManager.TaskItem(pos).ChapterName.Add(s); DLManager.TaskItem(pos).ChapterLinks.Add( mangaInfo.chapterLinks.Strings[xNode^.Index]); @@ -1840,15 +1843,18 @@ procedure TMainForm.btDownloadClick(Sender: TObject); DLManager.TaskItem(pos).DownloadInfo.Title := mangaInfo.title; DLManager.TaskItem(pos).DownloadInfo.DateTime := Now; - s := CorrectPathSys(edSaveTo.Text); + s := CorrectPathSys(CleanAndExpandDirectory(edSaveTo.Text)); // save to if OptionGenerateMangaFolderName then - begin - if not cbOptionPathConvert.Checked then - s := s + RemoveSymbols(mangaInfo.title) - else - s := s + RemoveSymbols(UnicodeRemove(mangaInfo.title)); - end; + s := s + CustomRename( + OptionMangaCustomRename, + mangaInfo.website, + mangaInfo.title, + mangaInfo.authors, + mangaInfo.artists, + '', + '', + OptionChangeUnicodeCharacter); s := CorrectPathSys(s); DLManager.TaskItem(pos).DownloadInfo.SaveTo := s; UpdateVtDownload; @@ -1873,12 +1879,15 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); // save to if OptionGenerateMangaFolderName then - begin - if not cbOptionPathConvert.Checked then - s := s + RemoveSymbols(mangaInfo.title) - else - s := s + RemoveSymbols(UnicodeRemove(mangaInfo.title)); - end; + s := s + CustomRename( + OptionMangaCustomRename, + mangaInfo.website, + mangaInfo.title, + mangaInfo.authors, + mangaInfo.artists, + '', + '', + OptionChangeUnicodeCharacter); s := CorrectPathSys(s); s2 := ''; @@ -4353,14 +4362,17 @@ procedure TMainForm.LoadOptions; edOptionDefaultPath.Text := ReadString('saveto', 'SaveTo', DEFAULT_PATH); if Trim(edOptionDefaultPath.Text) = '' then edOptionDefaultPath.Text := DEFAULT_PATH; + seOptionPDFQuality.Value := ReadInteger('saveto', 'PDFQuality', 100); rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); - cbOptionPathConvert.Checked := ReadBool('saveto', 'PathConvert', False); + cbOptionChangeUnicodeCharacter.Checked := ReadBool('saveto', 'ChangeUnicodeCharacter', False); cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', True); cbOptionGenerateMangaFolderName.Checked := ReadBool('saveto', 'GenerateMangaName', True); - seOptionPDFQuality.Value := ReadInteger('saveto', 'PDFQuality', 100); - edOptionCustomRename.Text := ReadString('saveto', 'CustomRename', DEFAULT_CUSTOM_RENAME); - if Trim(edOptionCustomRename.Text) = '' then - edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; + edOptionMangaCustomRename.Text := ReadString('saveto', 'MangaCustomRename', DEFAULT_MANGA_CUSTOMRENAME); + if Trim(edOptionMangaCustomRename.Text) = '' then + edOptionMangaCustomRename.Text := DEFAULT_MANGA_CUSTOMRENAME; + edOptionChapterCustomRename.Text := ReadString('saveto', 'ChapterCustomRename', DEFAULT_CHAPTER_CUSTOMRENAME); + if Trim(edOptionChapterCustomRename.Text) = '' then + edOptionChapterCustomRename.Text := DEFAULT_CHAPTER_CUSTOMRENAME; cbOptionDigitVolume.Checked := ReadBool('saveto', 'ConvertDigitVolume', True); seOptionDigitVolume.Value := ReadInteger('saveto', 'DigitVolumeLength', 2); seOptionDigitVolume.Enabled := cbOptionDigitVolume.Checked; @@ -4473,14 +4485,17 @@ procedure TMainForm.SaveOptions; edOptionDefaultPath.Text := DEFAULT_PATH; edOptionDefaultPath.Text := CorrectPathSys(edOptionDefaultPath.Text); WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); - WriteBool('saveto', 'PathConvert', cbOptionPathConvert.Checked); + WriteBool('saveto', 'ChangeUnicodeCharacter', cbOptionChangeUnicodeCharacter.Checked); WriteBool('saveto', 'GenerateMangaName', cbOptionGenerateMangaFolderName.Checked); + if Trim(edOptionMangaCustomRename.Text) = '' then + edOptionMangaCustomRename.Text := DEFAULT_MANGA_CUSTOMRENAME; + WriteString('saveto', 'MangaCustomRename', edOptionMangaCustomRename.Text); WriteInteger('saveto', 'Compress', rgOptionCompress.ItemIndex); WriteInteger('saveto', 'PDFQuality', seOptionPDFQuality.Value); WriteBool('saveto', 'RemoveMangaNameFromChapter', cbOptionRemoveMangaNameFromChapter.Checked); - if Trim(edOptionCustomRename.Text) = '' then - edOptionCustomRename.Text := DEFAULT_CUSTOM_RENAME; - WriteString('saveto', 'CustomRename', edOptionCustomRename.Text); + if Trim(edOptionChapterCustomRename.Text) = '' then + edOptionChapterCustomRename.Text := DEFAULT_CHAPTER_CUSTOMRENAME; + WriteString('saveto', 'ChapterCustomRename', edOptionChapterCustomRename.Text); WriteBool('saveto', 'ConvertDigitVolume', cbOptionDigitVolume.Checked); WriteBool('saveto', 'ConvertDigitChapter', cbOptionDigitChapter.Checked); WriteInteger('saveto', 'DigitVolumeLength', seOptionDigitVolume.Value); @@ -4616,10 +4631,12 @@ procedure TMainForm.ApplyOptions; //saveto OptionPDFQuality := seOptionPDFQuality.Value; - OptionCustomRename := edOptionCustomRename.Text; DLManager.compress := rgOptionCompress.ItemIndex; + OptionChangeUnicodeCharacter := cbOptionChangeUnicodeCharacter.Checked; OptionRemoveMangaNameFromChapter := cbOptionRemoveMangaNameFromChapter.Checked; OptionGenerateMangaFolderName := cbOptionGenerateMangaFolderName.Checked; + OptionMangaCustomRename := edOptionMangaCustomRename.Text; + OptionChapterCustomRename := edOptionChapterCustomRename.Text; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; From 61f77dd3b71cd5974804e628b6fefe129b2e85a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 10:59:35 +0800 Subject: [PATCH 0683/2794] only enabled custom rename for manga folder if generate manga folder is enabled --- mangadownloader/forms/frmMain.lfm | 3 ++- mangadownloader/forms/frmMain.pas | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 8ed0b90be..746a23caf 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2392,6 +2392,7 @@ object MainForm: TMainForm Top = 30 Width = 261 Caption = 'Auto generate folder based on manga''s name' + OnChange = cbOptionGenerateMangaFolderNameChange ParentFont = False TabOrder = 0 end @@ -2490,7 +2491,7 @@ object MainForm: TMainForm TabOrder = 8 TextHint = 'Custom rename' end - object lbOptionMangaRename: TLabel + object lbOptionMangaCustomRename: TLabel Left = 16 Height = 15 Top = 56 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c81fc807c..b10456563 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -67,7 +67,7 @@ TMainForm = class(TForm) cbOptionOneInstanceOnly: TCheckBox; edOptionMangaCustomRename: TEdit; lbOptionMangaCustomRenameHint: TLabel; - lbOptionMangaRename: TLabel; + lbOptionMangaCustomRename: TLabel; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; pcAbout: TPageControl; @@ -357,6 +357,7 @@ TMainForm = class(TForm) procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); + procedure cbOptionGenerateMangaFolderNameChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; @@ -2135,6 +2136,13 @@ procedure TMainForm.cbOptionDigitVolumeChange(Sender: TObject); seOptionDigitVolume.Enabled := cbOptionDigitVolume.Checked; end; +procedure TMainForm.cbOptionGenerateMangaFolderNameChange(Sender: TObject); +begin + lbOptionMangaCustomRename.Enabled := cbOptionGenerateMangaFolderName.Checked; + edOptionMangaCustomRename.Enabled := cbOptionGenerateMangaFolderName.Checked; + lbOptionMangaCustomRenameHint.Enabled := cbOptionGenerateMangaFolderName.Checked; +end; + procedure TMainForm.btReadOnlineClick(Sender: TObject); begin OpenURL(mangaInfo.url); From f4f5fad4ad1b2c1b0ee3b0f09ca40fcde004cf2a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 11:00:13 +0800 Subject: [PATCH 0684/2794] update translations --- mangadownloader/languages/fmd.en.po | 76 ++++++++++++++++++++------ mangadownloader/languages/fmd.id_ID.po | 68 +++++++++++++++++------ mangadownloader/languages/fmd.po | 61 +++++++++++++++------ 3 files changed, 157 insertions(+), 48 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 15d610d8b..b0ecdd0d3 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -524,6 +524,11 @@ msgctxt "tmainform.cboptionbatotoshowscangroup.caption" msgid "[Batoto] Show scan group name" msgstr "[Batoto] Show scan group name" +#: tmainform.cboptionchangeunicodecharacter.caption +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" +msgstr "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Chapter" @@ -558,10 +563,6 @@ msgstr "Minimize to tray" msgid "Permit only one FMD running" msgstr "Permit only one FMD running" -#: tmainform.cboptionpathconvert.caption -msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" -msgstr "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" - #: tmainform.cboptionproxytype.text msgid "HTTP" msgstr "HTTP" @@ -949,7 +950,8 @@ msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" msgid "Title" msgstr "Title" -#: tmainform.edoptioncustomrename.texthint +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" msgid "Custom rename" msgstr "Custom rename" @@ -973,6 +975,11 @@ msgstr "External program path" msgid "Proxy host/IP" msgstr "Proxy host/IP" +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Custom rename" + #: tmainform.edoptionpass.texthint msgid "Proxy password" msgstr "Proxy password" @@ -1110,20 +1117,13 @@ msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" -#: tmainform.lboptionconnectiontimeout.caption -msgid "Connection timeout (seconds)" -msgstr "Connection timeout (seconds)" - -#: tmainform.lboptioncustomrename.caption -msgid "Chapter folder name:" -msgstr "Chapter folder name:" - -#: tmainform.lboptioncustomrenamehint.caption -msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT.CAPTION" +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" msgid "[?]" msgstr "[?]" -#: tmainform.lboptioncustomrenamehint.hint +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" msgid "" "%WEBSITE% : Website name\n" "%MANGA% : Manga title\n" @@ -1145,6 +1145,14 @@ msgstr "" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Connection timeout (seconds)" + +#: tmainform.lboptioncustomrename.caption +msgid "Chapter folder name:" +msgstr "Chapter folder name:" + #: tmainform.lboptioncustomrenamehint1.caption msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT1.CAPTION" msgid "[?]" @@ -1183,6 +1191,42 @@ msgstr "Language:" msgid "After download finish:" msgstr "After download finish:" +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Manga folder name:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +#| msgid "" +#| "%WEBSITE% : Website name\n" +#| "%MANGA% : Chapter title\n" +#| "%AUTHOR% : Author\n" +#| "%ARTIST% : Artist\n" +#| "\n" +#| "Note:\n" +#| "Manga folder name must have at least %MANGA%.\n" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" + #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Number of downloaded tasks at the same time (Max: 8)" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index f777b7e36..eeb7221f7 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -491,6 +491,11 @@ msgctxt "tmainform.cboptionbatotoshowscangroup.caption" msgid "[Batoto] Show scan group name" msgstr "[Batoto] Tampilkan nama grup scan" +#: tmainform.cboptionchangeunicodecharacter.caption +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" +msgstr "Ubah semua simbol unicode menjadi \"_\" (pilih ini ketika Anda memiliki masalah dengan lokasi unicode)" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Bab" @@ -524,10 +529,6 @@ msgstr "Perkecil ke penampan" msgid "Permit only one FMD running" msgstr "Hanya ijinkan satu FMD berjalan" -#: tmainform.cboptionpathconvert.caption -msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" -msgstr "Ubah semua simbol unicode menjadi \"_\" (pilih ini ketika Anda memiliki masalah dengan lokasi unicode)" - #: tmainform.cboptionproxytype.text msgid "HTTP" msgstr "HTTP" @@ -915,7 +916,8 @@ msgctxt "tmainform.edfiltertitle.texthint" msgid "Title" msgstr "Judul" -#: tmainform.edoptioncustomrename.texthint +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" msgid "Custom rename" msgstr "Ubah nama kustom" @@ -937,6 +939,11 @@ msgstr "Parameter program" msgid "Proxy host/IP" msgstr "Host/IP" +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Ubah nama kustom" + #: tmainform.edoptionpass.texthint msgid "Proxy password" msgstr "Kata kunci" @@ -1061,20 +1068,13 @@ msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" msgid "Auto check for new chapter every %d minutes" msgstr "Otomatis periksa bab baru setiap %d menit" -#: tmainform.lboptionconnectiontimeout.caption -msgid "Connection timeout (seconds)" -msgstr "Batas waktu koneksi (detik)" - -#: tmainform.lboptioncustomrename.caption -msgid "Chapter folder name:" -msgstr "Nama folder bab:" - -#: tmainform.lboptioncustomrenamehint.caption -msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT.CAPTION" +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" msgid "[?]" msgstr "[?]" -#: tmainform.lboptioncustomrenamehint.hint +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" msgid "" "%WEBSITE% : Website name\n" "%MANGA% : Manga title\n" @@ -1096,6 +1096,14 @@ msgstr "" "Catatan:\n" "Nama folder harus memiliki setidaknya %CHAPTER% atau %NUMBERING%.\n" +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Batas waktu koneksi (detik)" + +#: tmainform.lboptioncustomrename.caption +msgid "Chapter folder name:" +msgstr "Nama folder bab:" + #: tmainform.lboptioncustomrenamehint1.caption msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT1.CAPTION" msgid "[?]" @@ -1134,6 +1142,34 @@ msgstr "Bahasa:" msgid "After download finish:" msgstr "Tugas setelah unduhan selesai:" +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Nama folder komik:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nama situs\n" +"%MANGA% : Judul komik\n" +"%AUTHOR% : Penulis\n" +"%ARTIST% : Seniman\n" +"\n" +"Catatan:\n" +"Nama folder harus memiliki setidaknya %MANGA%\n" + #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Jumlah unduhan aktif pada waktu yang sama (Max: 8)" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 232a30c6f..3c68b8155 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -463,6 +463,11 @@ msgctxt "TMAINFORM.CBOPTIONBATOTOSHOWSCANGROUP.CAPTION" msgid "[Batoto] Show scan group name" msgstr "" +#: tmainform.cboptionchangeunicodecharacter.caption +msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" +msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "" @@ -496,10 +501,6 @@ msgstr "" msgid "Permit only one FMD running" msgstr "" -#: tmainform.cboptionpathconvert.caption -msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" -msgstr "" - #: tmainform.cboptionproxytype.text msgid "HTTP" msgstr "" @@ -885,7 +886,8 @@ msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" msgid "Title" msgstr "" -#: tmainform.edoptioncustomrename.texthint +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "TMAINFORM.EDOPTIONCHAPTERCUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "" @@ -907,6 +909,11 @@ msgstr "" msgid "Proxy host/IP" msgstr "" +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "TMAINFORM.EDOPTIONMANGACUSTOMRENAME.TEXTHINT" +msgid "Custom rename" +msgstr "" + #: tmainform.edoptionpass.texthint msgid "Proxy password" msgstr "" @@ -1022,20 +1029,13 @@ msgctxt "TMAINFORM.LBOPTIONAUTOCHECKFAVINTERVALMINUTES.CAPTION" msgid "Auto check for new chapter every %d minutes" msgstr "" -#: tmainform.lboptionconnectiontimeout.caption -msgid "Connection timeout (seconds)" -msgstr "" - -#: tmainform.lboptioncustomrename.caption -msgid "Chapter folder name:" -msgstr "" - -#: tmainform.lboptioncustomrenamehint.caption -msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT.CAPTION" +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "" -#: tmainform.lboptioncustomrenamehint.hint +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.HINT" msgid "" "%WEBSITE% : Website name\n" "%MANGA% : Manga title\n" @@ -1048,6 +1048,14 @@ msgid "" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" msgstr "" +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "" + +#: tmainform.lboptioncustomrename.caption +msgid "Chapter folder name:" +msgstr "" + #: tmainform.lboptioncustomrenamehint1.caption msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT1.CAPTION" msgid "[?]" @@ -1086,6 +1094,27 @@ msgstr "" msgid "After download finish:" msgstr "" +#: tmainform.lboptionmangacustomrename.caption +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAME.CAPTION" +msgid "Manga folder name:" +msgstr "" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAMEHINT.CAPTION" +msgid "[?]" +msgstr "" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" + #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "" From a2f2ea97d03f64876eb10cd18c4dc9ebf9b190c7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 11:04:39 +0800 Subject: [PATCH 0685/2794] update translations --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b10456563..651bf1de5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1809,7 +1809,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); isCreate := True; end; DLManager.TaskItem(pos).Website := mangaInfo.website; - // generate folder name + // generate chapter folder name s := CustomRename(OptionChapterCustomRename, mangaInfo.website, mangaInfo.title, From bcee39c678c960eb1a2382ceeb7ca809fcd142d1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 11:37:47 +0800 Subject: [PATCH 0686/2794] remove madokami --- .../includes/Madokami/chapter_page_number.inc | 46 --------- .../Madokami/directory_page_number.inc | 6 -- .../includes/Madokami/manga_information.inc | 93 ------------------- .../includes/Madokami/names_and_links.inc | 46 --------- baseunits/uBaseUnit.pas | 21 +---- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 7 +- 7 files changed, 3 insertions(+), 231 deletions(-) delete mode 100644 baseunits/includes/Madokami/chapter_page_number.inc delete mode 100644 baseunits/includes/Madokami/directory_page_number.inc delete mode 100644 baseunits/includes/Madokami/manga_information.inc delete mode 100644 baseunits/includes/Madokami/names_and_links.inc diff --git a/baseunits/includes/Madokami/chapter_page_number.inc b/baseunits/includes/Madokami/chapter_page_number.inc deleted file mode 100644 index 0f47a598f..000000000 --- a/baseunits/includes/Madokami/chapter_page_number.inc +++ /dev/null @@ -1,46 +0,0 @@ - function GetMadokamiPageNumber: Boolean; - var - i: Integer; - l: TStringList; - datapath_, datafiles_: string; - begin - l := TStringList.Create; - - Result := GetPage(TObject(l), - FillMangaSiteHost(MADOKAMI_ID, URL), - manager.container.manager.retryConnect); - - parse := TStringList.Create; - ParseHTML(l.Text, parse); - l.Free; - datapath_ := ''; - datafiles_ := ''; - if parse.Count > 0 then - begin - for i := 0 to parse.Count-1 do - if GetVal(parse[i], 'id') = 'reader' then - begin - datapath_ := GetVal(parse[i], 'data-path'); - datafiles_ := GetVal(parse[i], 'data-files'); - Break; - end; - end; - parse.Free; - - if (datapath_ <> '') and (datafiles_ <> '') then - begin - datapath_ := EncodeURLElement(CommonStringFilter(datapath_)); - datafiles_ := Trim(TrimChar(datafiles_, ['[', ']'])); - datafiles_ := StringReplace(datafiles_, '"', '"', [rfIgnoreCase, rfReplaceAll]); - datafiles_ := StringReplace(datafiles_, '\', '', [rfReplaceAll]); - with manager.container do - begin - PageLinks.Delimiter := ','; - PageLinks.DelimitedText := datafiles_; - if PageLinks.Count > 0 then - for i := 0 to PageLinks.Count-1 do - PageLinks[i] := WebsiteRoots[MADOKAMI_ID, 1] + '/reader/image?path=' + - datapath_ + '&file=' + EncodeURLElement(PageLinks[i]); - end; - end; - end; diff --git a/baseunits/includes/Madokami/directory_page_number.inc b/baseunits/includes/Madokami/directory_page_number.inc deleted file mode 100644 index 8cce97d8d..000000000 --- a/baseunits/includes/Madokami/directory_page_number.inc +++ /dev/null @@ -1,6 +0,0 @@ - function GetMadokamiDirectoryPageNumber: Byte; - begin - Source.Free; - Page := Length(MADOKAMI_BROWSER); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Madokami/manga_information.inc b/baseunits/includes/Madokami/manga_information.inc deleted file mode 100644 index 29751680d..000000000 --- a/baseunits/includes/Madokami/manga_information.inc +++ /dev/null @@ -1,93 +0,0 @@ - function GetMadokamiInfoFromURL: Byte; - var - i, j: Integer; - s: String = ''; - regx: TRegExpr; - begin - mangaInfo.website := WebsiteRoots[MADOKAMI_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MADOKAMI_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.authors := ''; - - //title - if mangaInfo.title = '' then - for i := parse.Count-1 downto 0 do - if GetVal(parse[i], 'itemprop') = 'title' then - begin - mangaInfo.title := CommonStringFilter(parse[i+1]); - Break; - end; - - regx := TRegExpr.Create; - regx.Expression := '^(.+)\.\w+$'; - for i := 0 to parse.Count-1 do - begin - //cover - if mangaInfo.coverLink = '' then - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'itemprop') = 'image') then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //authors - if GetVal(parse[i], 'itemprop') = 'author' then - AddCommaString(mangaInfo.authors, CommonStringFilter(parse[i+1])); - - //genre - if (GetTagName(parse[i]) = 'span') and - (GetVal(parse[i], 'itemprop') = 'title') then - begin - s := CommonStringFilter(parse[i+1]); - s := TrimLeftChar(s, ['_']); - if AnsiIndexText(s, [mangaInfo.title, '/', 'Manga','# - F', 'G - M', 'N - Z', - 'Non-English', 'AutoUploads']) = -1 then - AddCommaString(mangaInfo.genres, s); - end; - if AnsiIndexStr(GetVal(parse[i], 'class'), ['tag', 'tag tag-category']) > -1 then - AddCommaString(mangaInfo.genres, CommonStringFilter(parse[i+1])); - - //summary - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'description') then - begin - mangaInfo.summary := ''; - for j := i+1 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/div' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := mangaInfo.summary + LineEnding + CommonStringFilter(parse[j]); - end; - mangaInfo.summary := Trim(mangaInfo.summary); - end; - - //chapters - if (GetTagName(parse[i]) = 'a') and - (Pos('/reader/', parse[i]) <> 0) then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - for j := i-10 downto 0 do - if GetTagName(parse[j]) = 'a' then - begin - s := CommonStringFilter(parse[j+1]); - s := regx.Replace(s, '$1', True); - mangaInfo.chapterName.Add(s); - Break; - end; - end; - end; - regx.Free; - Result := NO_ERROR; - end; - end; diff --git a/baseunits/includes/Madokami/names_and_links.inc b/baseunits/includes/Madokami/names_and_links.inc deleted file mode 100644 index 3e92f48c3..000000000 --- a/baseunits/includes/Madokami/names_and_links.inc +++ /dev/null @@ -1,46 +0,0 @@ - function MadokamiGetNamesAndLinks: Byte; - var - i: Integer; - s: string; - j: Integer; - begin - Result := INFORMATION_NOT_FOUND; - i := StrToIntDef(URL, 0); - if i >= Length(MADOKAMI_BROWSER) then - begin - Source.Free; - Exit; - end; - - s := WebsiteRoots[MADOKAMI_ID, 1] + MADOKAMI_BROWSER[i]; - if not GetPage(TObject(Source), s, 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'tr') and - (Pos('data-record=', parse[i]) <> 0)then - begin - for j := i+2 to parse.Count-1 do - if GetTagName(parse[j]) = 'a' then - begin - s := Trim(parse[j+1]); - if RightStr(s, 1) = '/' then - Delete(s, Length(s), 1); - if AnsiIndexText(s, ['', '</span>', '_Unsorted']) = -1 then - begin - names.Add(CommonStringFilter(s)); - links.Add(GetVal(parse[j], 'href')); - end; - Break; - end; - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 10316a0ae..1a8a29d82 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -350,9 +350,8 @@ interface READMANGATODAY_ID = 82; LONEMANGA_ID = 83; DYNASTYSCANS_ID = 84; - MADOKAMI_ID = 85; - WebsiteRoots: array [0..85] of array [0..1] of string = ( + WebsiteRoots: array [0..84] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -437,8 +436,7 @@ interface ('SenMangaRAW', 'http://raw.senmanga.com'), ('ReadMangaToday', 'http://www.readmanga.today'), ('LoneManga', 'http://lonemanga.com'), - ('Dynasty-Scans', 'http://dynasty-scans.com'), - ('Madokami', 'https://manga.madokami.com') + ('Dynasty-Scans', 'http://dynasty-scans.com') ); ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; @@ -577,21 +575,6 @@ interface '/series' ); - MADOKAMI_BROWSER: array [0..11] of string = ( - '/Manga/%23%20-%20F', - '/Manga/G%20-%20M', - '/Manga/N%20-%20Z', - '/Manga/_Autouploads/AutoUploaded%20from%20Assorted%20Sources', - '/Manga/_Autouploads/ComicWalker', - '/Manga/Non-English/Bahasa%20Indonesia', - '/Manga/Non-English/Brazilian%20Portuguese', - '/Manga/Non-English/Fran%C3%A7ais', - '/Manga/Non-English/Italian', - '/Manga/Non-English/Spanish', - '/Manga/_Doujinshi', - '/Raws' - ); - var FMD_VERSION_NUMBER: String = ''; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 02a0ad6d8..38ff75243 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1996,8 +1996,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/Dynasty-Scans/directory_page_number.inc} - {$I includes/Madokami/directory_page_number.inc} - begin Page := 0; @@ -2152,9 +2150,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansDirectoryPageNumber else - if WebsiteID = MADOKAMI_ID then - Result := GetMadokamiDirectoryPageNumber - else begin Result := NO_ERROR; Page := 1; @@ -2312,8 +2307,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Dynasty-Scans/names_and_links.inc} - {$I includes/Madokami/names_and_links.inc} - begin //load User-Agent from INIAdvanced AdvanceLoadHTTPConfig(FHTTP, website); @@ -2548,9 +2541,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = DYNASTYSCANS_ID then Result := DynastyScansGetNamesAndLinks else - if WebsiteID = MADOKAMI_ID then - Result := MadokamiGetNamesAndLinks - else begin Result := INFORMATION_NOT_FOUND; Source.Free; @@ -2711,8 +2701,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/Dynasty-Scans/manga_information.inc} - {$I includes/Madokami/manga_information.inc} - begin if Trim(URL) = '' then Exit(INFORMATION_NOT_FOUND); @@ -2959,9 +2947,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansInfoFromURL else - if WebsiteID = MADOKAMI_ID then - Result := GetMadokamiInfoFromURL - else begin Source.Free; Result := INFORMATION_NOT_FOUND; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a62084561..5769fc9fa 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -483,8 +483,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Dynasty-Scans/chapter_page_number.inc} - {$I includes/Madokami/chapter_page_number.inc} - begin Result := False; manager.container.PageNumber := 0; @@ -669,10 +667,7 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := GetLoneMangaPageNumber else if manager.container.MangaSiteID = DYNASTYSCANS_ID then - Result := GetDynastyScansPageNumber - else - if manager.container.MangaSiteID = MADOKAMI_ID then - Result := GetMadokamiPageNumber; + Result := GetDynastyScansPageNumber; end; if manager.container.PageLinks.Count > 0 then TrimStrings(manager.container.PageLinks); From e373462abaa69c8683dd6e5370146ef1f5553028 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 28 Dec 2015 12:59:24 +0800 Subject: [PATCH 0687/2794] fix load user-agent from advanced.ini --- baseunits/uBaseUnit.pas | 6 ++++-- baseunits/uMisc.pas | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1a8a29d82..aadd1ab65 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3008,7 +3008,8 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; - HTTP.UserAgent := DEFAULT_UA; + if (HTTP.UserAgent = '') or (HTTP.UserAgent = UA_SYNAPSE) then + HTTP.UserAgent := DEFAULT_UA; if OptionHTTPUseGzip then HTTPHeader.Values['Accept-Encoding'] := ' gzip, deflate'; @@ -3292,7 +3293,8 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; HTTP.Protocol := '1.1'; HTTP.KeepAlive := False; - HTTP.UserAgent := DEFAULT_UA; + if (HTTP.UserAgent = '') or (HTTP.UserAgent = UA_SYNAPSE) then + HTTP.UserAgent := DEFAULT_UA; HTTP.MimeType := 'text/html'; //User-Agent diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index a4a853387..bd7be1400 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -75,6 +75,7 @@ function StringsToCommandLine(const S: array of string): string; overload; procedure DeleteArrayOfString(Var TheStrings: TArrayOfString; Index: Integer); const + UA_SYNAPSE = 'Mozilla/4.0 (compatible; Synapse)'; UA_CURL = 'curl/7.42.1'; UA_GOOGLEBOT = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; UA_MSIE = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; From da733e866e71e6a340e6fde9c52a3ef6a0296bad Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 02:48:29 +0800 Subject: [PATCH 0688/2794] cleanup translations --- mangadownloader/languages/fmd.en.po | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index b0ecdd0d3..6efc4856f 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1062,16 +1062,6 @@ msgid "[?]" msgstr "[?]" #: tmainform.lbfilterhint.hint -#| msgid "" -#| "Genres:\n" -#| "- Checked: Include this genre.\n" -#| "- Unchecked: Exclude this genre.\n" -#| "- Grayed: Doesn't matter.\n" -#| "\n" -#| "Custom Genres:\n" -#| "- Separate multiple genres with ','.\n" -#| "- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.\n" -#| "- Example: Adventure,!Ecchi,Comedy.\n" msgid "" "Genres:\n" "- Checked: Include this genre.\n" @@ -1202,14 +1192,6 @@ msgid "[?]" msgstr "[?]" #: tmainform.lboptionmangacustomrenamehint.hint -#| msgid "" -#| "%WEBSITE% : Website name\n" -#| "%MANGA% : Chapter title\n" -#| "%AUTHOR% : Author\n" -#| "%ARTIST% : Artist\n" -#| "\n" -#| "Note:\n" -#| "Manga folder name must have at least %MANGA%.\n" msgid "" "%WEBSITE% : Website name\n" "%MANGA% : Manga title\n" From ba522250d6022d2443547b76c79a21b6148028b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 10:09:57 +0800 Subject: [PATCH 0689/2794] accountmanaferdb, convert field data type to text can only read 256 character of undefined varchar, cookies need longer --- baseunits/accountmanagerdb.pas | 47 +++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index ad0455855..9c84e1638 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, LazFileUtils, USimpleLogger, base64, sqlite3conn, - sqldb; + sqldb, db; type @@ -27,6 +27,7 @@ TAccountManager = class function CreateDBTable: Boolean; function OpenDBTable: Boolean; function FixStatus: Boolean; + procedure ConvertNewTable; function GetValueString(const AName, AField: string): string; function GetValueBoolean(const AName, AField: string): boolean; function GetValueInteger(const AName, AField: string): Integer; @@ -48,7 +49,7 @@ TAccountManager = class procedure SetValueInteger(const AName, AField: string; AValue: Integer); procedure SetValueStr(const RecIndex, FieldIndex: Integer; AValue: string); procedure SetValueBool(const RecIndex, FieldIndex: Integer; AValue: boolean); - procedure SetValueInt(const RecIndex, FieldIndex, AValue: Integer); + procedure SetValueInt(const RecIndex, FieldIndex: Integer; AValue: Integer); procedure GetRecordCount; procedure Vacuum; public @@ -81,12 +82,17 @@ implementation ctbaccountscreateparams = '('#13#10 + '"enabled" BOOL,'#13#10 + '"aname" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + - '"username" VARCHAR,'#13#10 + - '"password" VARCHAR,'#13#10 + - '"cookies" VARCHAR,'#13#10 + + '"username" TEXT,'#13#10 + + '"password" TEXT,'#13#10 + + '"cookies" TEXT,'#13#10 + '"status" INTEGER'#13#10 + ');'; +function QuotedStrd(const S: string): string; +begin + Result := AnsiQuotedStr(S, '"'); +end; + procedure InitAccountManager(const AFilename: string); begin Account := TAccountManager.Create(AFilename); @@ -201,7 +207,7 @@ function TAccountManager.CreateDB: Boolean; Result := False; if ffilename = '' then Exit; if FileExistsUTF8(ffilename) then DeleteFileUTF8(ffilename); - if InternalOpenDB then Result := CreateDBTable; + CreateDBTable; end; function TAccountManager.InternalOpenDB: Boolean; @@ -250,6 +256,7 @@ function TAccountManager.OpenDBTable: Boolean; on E: Exception do WriteLog_E('TAccountManager.OpenDBTable.Failed, ' + ffilename, E, Self); end; + if Result then ConvertNewTable; end; function TAccountManager.FixStatus: Boolean; @@ -274,6 +281,31 @@ function TAccountManager.FixStatus: Boolean; end; end; +procedure TAccountManager.ConvertNewTable; +begin + EnterCriticalsection(locklocate); + try + if (FieldTypeNames[fquery.FieldByName('username').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[fquery.FieldByName('password').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[fquery.FieldByName('cookies').DataType] <> Fieldtypenames[ftMemo]) then + begin + fquery.Close; + with fconn do begin + ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+ctablename)); + ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+ctablename)+ctbaccountscreateparams); + ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+ctablename)+' SELECT * FROM '+QuotedStrd(ctablename)); + ExecuteDirect('DROP TABLE '+QuotedStrd(ctablename)); + ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+ctablename)+' RENAME TO '+QuotedStrd(ctablename)); + end; + ftrans.Commit; + fquery.Open; + end; + except + ftrans.Rollback; + end; + LeaveCriticalsection(locklocate); +end; + function TAccountManager.GetValueString(const AName, AField: string): string; begin Result := ''; @@ -347,7 +379,8 @@ procedure TAccountManager.SetValueBool(const RecIndex, FieldIndex: Integer; end; end; -procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex, AValue: Integer); +procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex: Integer; + AValue: Integer); begin if fquery.Active = False then Exit; if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; From c3a80f1ad794af402efe342caa7e064bce155a3c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 10:15:39 +0800 Subject: [PATCH 0690/2794] accountmanagerdb, fix convertnewtable --- baseunits/accountmanagerdb.pas | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 9c84e1638..3393478c6 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -283,27 +283,29 @@ function TAccountManager.FixStatus: Boolean; procedure TAccountManager.ConvertNewTable; begin + if fquery.Active = False then Exit; EnterCriticalsection(locklocate); try if (FieldTypeNames[fquery.FieldByName('username').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[fquery.FieldByName('password').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[fquery.FieldByName('cookies').DataType] <> Fieldtypenames[ftMemo]) then - begin - fquery.Close; - with fconn do begin - ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+ctablename)); - ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+ctablename)+ctbaccountscreateparams); - ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+ctablename)+' SELECT * FROM '+QuotedStrd(ctablename)); - ExecuteDirect('DROP TABLE '+QuotedStrd(ctablename)); - ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+ctablename)+' RENAME TO '+QuotedStrd(ctablename)); + try + fquery.Close; + with fconn do begin + ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+ctablename)); + ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+ctablename)+ctbaccountscreateparams); + ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+ctablename)+' SELECT * FROM '+QuotedStrd(ctablename)); + ExecuteDirect('DROP TABLE '+QuotedStrd(ctablename)); + ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+ctablename)+' RENAME TO '+QuotedStrd(ctablename)); + end; + ftrans.Commit; + fquery.Open; + except + ftrans.Rollback; end; - ftrans.Commit; - fquery.Open; - end; - except - ftrans.Rollback; + finally + LeaveCriticalsection(locklocate); end; - LeaveCriticalsection(locklocate); end; function TAccountManager.GetValueString(const AName, AField: string): string; From a11dde87e9f39bd76108fa65f343560bee1b84d4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 10:18:36 +0800 Subject: [PATCH 0691/2794] accountmanagerdb, fix missing new line --- baseunits/accountmanagerdb.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 3393478c6..b9b0bd4e3 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -293,7 +293,7 @@ procedure TAccountManager.ConvertNewTable; fquery.Close; with fconn do begin ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+ctablename)); - ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+ctablename)+ctbaccountscreateparams); + ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+ctablename)+#13#10+ctbaccountscreateparams); ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+ctablename)+' SELECT * FROM '+QuotedStrd(ctablename)); ExecuteDirect('DROP TABLE '+QuotedStrd(ctablename)); ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+ctablename)+' RENAME TO '+QuotedStrd(ctablename)); From deb8281f5219db01830159ed811d0efaa737f9e4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 10:25:41 +0800 Subject: [PATCH 0692/2794] tdbdataprocess, convert some data type to "text" undefined varchar datasize fall to 256, while we need longer for summary etc --- baseunits/uData.pas | 46 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 38ff75243..b0bb87b70 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -48,6 +48,7 @@ TDBDataProcess = class(TObject) function GetLinkCount: Integer; protected procedure CreateTable; + procedure ConvertNewTable; procedure VacuumTable; procedure GetRecordCount; procedure AddSQLCond(const sqltext: String; useOR: Boolean = False); @@ -218,13 +219,13 @@ TMangaInformation = class(TObject) ('title', 'link', 'authors', 'artists', 'genres', 'status', 'summary', 'numchapter', 'jdn'); DBDataProccesCreateParam = '('#13#10 + - '"title" VARCHAR,'#13#10 + + '"title" TEXT,'#13#10 + '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + - '"authors" VARCHAR,'#13#10 + - '"artists" VARCHAR,'#13#10 + - '"genres" VARCHAR,'#13#10 + - '"status" VARCHAR,'#13#10 + - '"summary" VARCHAR,'#13#10 + + '"authors" TEXT,'#13#10 + + '"artists" TEXT,'#13#10 + + '"genres" TEXT,'#13#10 + + '"status" TEXT,'#13#10 + + '"summary" TEXT,'#13#10 + '"numchapter" INTEGER,'#13#10 + '"jdn" INTEGER'#13#10 + ');'; @@ -416,6 +417,38 @@ procedure TDBDataProcess.CreateTable; end; end; +procedure TDBDataProcess.ConvertNewTable; +begin + //'"title" TEXT,'#13#10 + + // '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + + // '"authors" TEXT,'#13#10 + + // '"artists" TEXT,'#13#10 + + // '"genres" TEXT,'#13#10 + + // '"status" TEXT,'#13#10 + + // '"summary" TEXT,'#13#10 + + if FQuery.Active = False then Exit; + if (FieldTypeNames[FQuery.FieldByName('title').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('authors').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('artists').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('genres').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('status').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('summary').DataType] <> Fieldtypenames[ftMemo]) then + try + FQuery.Close; + with fconn do begin + ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+FTableName)); + ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+FTableName)+#13#10+DBDataProccesCreateParam); + ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+FTableName)+' SELECT * FROM '+QuotedStrd(FTableName)); + ExecuteDirect('DROP TABLE '+QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+FTableName)+' RENAME TO '+QuotedStrd(FTableName)); + end; + FTrans.Commit; + FQuery.Open; + except + FTrans.Rollback; + end; +end; + procedure TDBDataProcess.VacuumTable; var queryactive: Boolean; @@ -745,6 +778,7 @@ function TDBDataProcess.OpenTable(const ATableName: String; end; end; Result := FQuery.Active; + if Result then ConvertNewTable; end; function TDBDataProcess.TableExist(const ATableName: String): Boolean; From 7407d64a8c7e040e3624c4707a152c268d3f77fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 11:57:17 +0800 Subject: [PATCH 0693/2794] baseunit, add base64 encode/decode --- baseunits/uBaseUnit.pas | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index aadd1ab65..c9e1eef61 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -19,8 +19,8 @@ interface UTF8Process, {$endif} SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, - LConvEncoding, strutils, fileinfo, fpjson, jsonparser, FastHTMLParser, fgl, - RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, + LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, FastHTMLParser, + fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, USimpleException, USimpleLogger; @@ -860,6 +860,10 @@ function SelectCSSIX(Expression: String; TP: TTreeParser): IXQValue; function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; +// encode/decode +function Base64Encode(const s: string): string; +function Base64Decode(const s: string): string; + // StringUtils function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; function StreamToString(const M: TMemoryStream): string; inline; @@ -2103,6 +2107,18 @@ function GetHeaderValue(const AHeaders: TStrings; HName: String): String; end; end; +function Base64Encode(const s: string): string; +begin + if s = '' then Exit(s); + Result := EncodeStringBase64(s); +end; + +function Base64Decode(const s: string): string; +begin + if s = '' then Exit(s); + Result := DecodeStringBase64(s); +end; + function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; var b1, b2: Char; From 71ef7181f7558ccf5603e9fa4411081449622fc6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 11:58:07 +0800 Subject: [PATCH 0694/2794] websitemodules, add onbeforedownloadimage --- baseunits/WebsiteModules.pas | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 61ca06ea1..f904e0681 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -34,13 +34,17 @@ TModuleContainer = class; TOnGetImageURL = function(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; + TOnBeforeDownloadImage = function(var DownloadThread: TDownloadThread; + AURL: String; Module: TModuleContainer): Boolean; + TOnDownloadImage = function(var DownloadThread: TDownloadThread; const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; TOnLogin = function(var AHTTP: THTTPSendThread): Boolean; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, - MMTaskStart, MMGetPageNumber, MMGetImageURL, MMDownloadImage, MMLogin); + MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, + MMDownloadImage, MMLogin); { TModuleContainer } @@ -68,6 +72,7 @@ TModuleContainer = class OnTaskStart: TOnTaskStart; OnGetPageNumber: TOnGetPageNumber; OnGetImageURL: TOnGetImageURL; + OnBeforeDownloadImage: TOnBeforeDownloadImage; OnDownloadImage: TOnDownloadImage; OnLogin: TOnLogin; constructor Create; @@ -142,6 +147,11 @@ TWebsiteModules = class const AURL, AWebsite: String): Boolean; overload; + function BeforeDownloadImage(var DownloadThread: TDownloadThread; + AURL: String; const ModuleId: Integer): Boolean; overload; + function BeforeDownloadImage(var DownloadThread: TDownloadThread; + AURL: String; const AWebsite: String): Boolean; overload; + function DownloadImage(var DownloadThread: TDownloadThread; const AURL, APath, AName, APrefix: String; ModuleId: Integer): Boolean; overload; function DownloadImage(var DownloadThread: TDownloadThread; @@ -444,6 +454,24 @@ function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; Result := GetImageURL(DownloadThread, AURL, LocateModule(AWebsite)); end; +function TWebsiteModules.BeforeDownloadImage( + var DownloadThread: TDownloadThread; AURL: String; const ModuleId: Integer + ): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnBeforeDownloadImage) then + Result := TModuleContainer(FModuleList[ModuleId]).OnBeforeDownloadImage( + DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); +end; + +function TWebsiteModules.BeforeDownloadImage( + var DownloadThread: TDownloadThread; AURL: String; const AWebsite: String + ): Boolean; +begin + Result := BeforeDownloadImage(DownloadThread, AURL, LocateModule(AWebsite)); +end; + function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; const AURL, APath, AName, APrefix: String; ModuleId: Integer): Boolean; begin From 0f1659c1f65b09e0dd420aa7fcd53e2e4cb0269b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 13:35:23 +0800 Subject: [PATCH 0695/2794] downloadmanager, use pagelinks if pagecontainterlinks doesn't exist --- baseunits/uDownloadsManager.pas | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5769fc9fa..1cbe58966 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1140,7 +1140,7 @@ procedure TTaskThread.SyncShowBaloon; function TDownloadThread.DownloadImage(const prefix: String): Boolean; var - TURL, lpath, sfilename: String; + s, TURL, lpath, sfilename: String; {$I includes/MeinManga/image_url.inc} @@ -1173,14 +1173,21 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; //TURL := DecodeURL(TURL); //decode first to avoid double encoded //TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); - if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then - Result := Modules.DownloadImage( - Self, - manager.container.PageContainerLinks[workCounter], - lpath, - Format('%.3d', [workCounter + 1]), - prefix, - ModuleId) + if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin + s := ''; + if workCounter < manager.container.PageContainerLinks.Count then + s := manager.container.PageContainerLinks[workCounter] + else if workCounter < manager.container.PageLinks.Count then + s := manager.container.PageLinks[workCounter]; + if s <> '' then + Result := Modules.DownloadImage( + Self, + s, + lpath, + Format('%.3d', [workCounter + 1]), + prefix, + ModuleId); + end else if manager.container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL From 9539e79ade13d8c323b9f0f84bc5e99b35cb474a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 13:38:19 +0800 Subject: [PATCH 0696/2794] baseunit, add saveimagetreamtofile, fix saveimage use vampyre imaging utility to determine stream format / image format --- baseunits/uBaseUnit.pas | 119 ++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 77 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c9e1eef61..815852984 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -22,7 +22,7 @@ interface LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, - USimpleException, USimpleLogger; + Imaging, ImagingExtras, USimpleException, USimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); @@ -954,6 +954,10 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0) overload; inline; // Get url from a bitly url. function GetURLFromBitly(const URL: String): String; + +// try to save tmemorystream to file, return the saved filename if success, otherwise return empty string +function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String): String; + // Download an image from url and save it to a specific location. function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; @@ -3207,19 +3211,46 @@ function GetURLFromBitly(const URL: String): String; httpSource.Free; end; +function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String + ): String; +var + p, f: String; + fs: TFileStreamUTF8; +begin + Result := ''; + if Stream = nil then Exit; + if Stream.Size = 0 then Exit; + p := CleanAndExpandDirectory(Path); + if not DirectoryExistsUTF8(p) then ForceDirectoriesUTF8(p); + if DirectoryExistsUTF8(p) then begin + f := DetermineStreamFormat(Stream); + if f = '' then f := 'dat'; + f := p + FileName + '.' + f; + if FileExistsUTF8(f) then DeleteFileUTF8(f); + try + fs := TFileStreamUTF8.Create(f, fmCreate); + try + Stream.SaveToStream(fs); + finally + fs.Free; + end; + except + on E: Exception do + WriteLog_E('SaveImageStreamToFile.Failed!', E); + end; + if FileExistsUTF8(f) then Result := f + end; +end; + function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer ): Boolean; // prefix: For example: 000<our prefix>.jpg. var - retryToSave: Boolean = False; - header: array [0..3] of Byte; - ext, lpath, fpath: String; HTTPHeader: TStringList; HTTP: THTTPSend; counter: Integer; s: String; - fstream: TFileStreamUTF8; procedure preTerminate; begin @@ -3241,14 +3272,14 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; begin Result := False; if Trim(URL) = '' then Exit; - fpath := ''; - s := Path + '/' + Name; + // Check to see if a file with similar name was already exist. If so then we // skip the download process. + if Trim(URL) = 'D' then Exit(True); + s := CleanAndExpandDirectory(Path) + Name + prefix; if (FileExistsUTF8(s + '.jpg')) or (FileExistsUTF8(s + '.png')) or - (FileExistsUTF8(s + '.gif')) or - (Trim(URL) = 'D') then + (FileExistsUTF8(s + '.gif')) then Exit(True); URL := FixURL(URL); @@ -3398,75 +3429,9 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Headers.Text := HTTPHeader.Text; end; end; - Initialize(header); - HTTP.Document.Seek(0, soBeginning); - HTTP.Document.Read(header[0], 4); - if (header[0] = JPG_HEADER[0]) and - (header[1] = JPG_HEADER[1]) and - (header[2] = JPG_HEADER[2]) then - ext := '.jpg' - else - if (header[0] = PNG_HEADER[0]) and - (header[1] = PNG_HEADER[1]) and - (header[2] = PNG_HEADER[2]) then - ext := '.png' - else - if (header[0] = GIF_HEADER[0]) and - (header[1] = GIF_HEADER[1]) and - (header[2] = GIF_HEADER[2]) then - ext := '.gif' - else - ext := ''; - if ext <> '' then - begin - // If an error occured, verify the path and redo the job. - // If the error still persists, break the loop. - repeat - try - if checkTerminate then Exit; - lpath := CleanAndExpandDirectory(CorrectPathSys(Path)); - if not DirectoryExistsUTF8(lpath) then - ForceDirectoriesUTF8(lpath); - if DirectoryExistsUTF8(lpath) then - begin - fpath := CleanAndExpandFilename(lpath + Name + prefix + ext); - if FileExistsUTF8(fpath) then - DeleteFileUTF8(fpath); - fstream := TFileStreamUTF8.Create(fpath, fmCreate); - try - HTTP.Document.SaveToStream(fstream); - finally - fstream.Free; - end; - if FileExistsUTF8(fpath) then - Result := HTTP.Document.Size = FileSizeUtf8(fpath); - end - else - Result := False; - Break; - except - on E: Exception do - begin - WriteLog_E('SaveImage.SavetoFile.Error!'+ LineEnding + - CorrectPathSys(Path) + '/' + Name + prefix + ext, E); - if checkTerminate then Exit; - if not retryToSave then - begin - CheckPath(Path); - retryToSave := True; - end - else - Break; - end; - end; - until False; - end - else - Writelog_E('SaveImage.ExtEmpty!' + LineEnding + URL); + SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name + prefix); preTerminate; - Result := (fpath <> '') and FileExistsUTF8(fpath); - if Result then SavedFilename := fpath - else SavedFilename := ''; + Result := SavedFilename <> ''; end; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; From 232173cb6aff7e05b100e18226dd4ee6f54c256d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 13:46:00 +0800 Subject: [PATCH 0697/2794] added madokami with account support fix #139 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Madokami.pas | 245 +++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Madokami.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a2a2691c6..086e9ada4 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -16,4 +16,5 @@ uses EightMuses, HitomiLa, HentaiCafe, - MangaTr; + MangaTr, + Madokami; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas new file mode 100644 index 000000000..71e1e3498 --- /dev/null +++ b/baseunits/modules/Madokami.pas @@ -0,0 +1,245 @@ +unit Madokami; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + accountmanagerdb, LazFileUtils, LazUTF8Classes, synacode, Imaging, RegExpr, + fpjson; + +implementation + +const + modulename = 'Madokami'; + urlroot = 'https://manga.madokami.com'; + madokamidirlist: array [0..12] of string = ( + '/Manga/%23%20-%20F', + '/Manga/G%20-%20M', + '/Manga/N%20-%20Z', + '/Manga/_Autouploads/AutoUploaded%20from%20Assorted%20Sources', + '/Manga/_Autouploads/ComicWalker', + '/Manga/Non-English/Bahasa%20Indonesia', + '/Manga/Non-English/Brazilian%20Portuguese', + '/Manga/Non-English/Fran%C3%A7ais', + '/Manga/Non-English/Italian', + '/Manga/Non-English/Russian', + '/Manga/Non-English/Spanish', + '/Manga/_Doujinshi', + '/Raws' + ); + +var + locklogin: TRTLCriticalSection; + onlogin: Boolean = False; + +function Login(var AHTTP: THTTPSendThread): Boolean; +begin + Result := False; + if Account.Enabled[modulename] = False then Exit; + if Account.Username[modulename] = '' then Exit; + if TryEnterCriticalsection(locklogin) > 0 then + try + onlogin := True; + Account.Status[modulename] := asChecking; + AHTTP.Reset; + AHTTP.Cookies.Clear; + AHTTP.Headers.Values['Authorization'] := + ' Basic ' + Base64Encode(Account.Username[modulename] + + ':' + Account.Password[modulename]); + if AHTTP.GET(urlroot + '/login') then begin + Result := AHTTP.Cookies.Values['laravel_session'] <> ''; + if Result then begin + Account.Cookies[modulename] := AHTTP.GetCookies; + Account.Status[modulename] := asValid; + end + else begin + Account.Cookies[modulename] := ''; + Account.Status[modulename] := asInvalid; + end; + Account.Save; + end; + finally + onlogin := False; + LeaveCriticalsection(locklogin); + end + else + while onlogin do Sleep(1000); + AHTTP.Reset; + if Result then begin + AHTTP.Cookies.Text := Account.Cookies[modulename]; + end; +end; + +function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; +begin + Result := False; + AHTTP.Cookies.Text := Account.Cookies[modulename]; + AHTTP.FollowRedirection := False; + Result := AHTTP.GET(AURL); + if (AHTTP.ResultCode > 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ' Basic') then + begin + if Login(AHTTP) then + Result := AHTTP.GET(AURL); + end; +end; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := Length(madokamidirlist); +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + currentdir: Integer; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + currentdir := StrToIntDef(AURL, 0); + if currentdir > Length(madokamidirlist) then Exit; + if MangaInfo.FHTTP.GET(Module.RootURL + madokamidirlist[currentdir]) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do + begin + s := v.toString; + if Length(s) > 1 then begin + if s[Length(s)] = '/' then SetLength(s, Length(s) - 1); + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + end; + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + with MangaInfo.mangaInfo, query do begin + coverLink := XPathString('//img[@itemprop="image"]/@src'); + if title = '' then title := XPathString('//*[@class="title"]'); + authors := XPathString('//*[@itemprop="author"]'); + v := XPath('//div[@class="genres"]/a'); + if v.Count > 0 then begin + genres := ''; + for i := 0 to v.Count - 1 do + AddCommaString(genres, v.get(i).toString); + end; + for v in XPath('//table[@id="index-table"]/tbody/tr') do begin + chapterLinks.Add(XPathString('td/a[contains(text(),"Read")]/@href', v.toNode)); + chapterName.Add(XPathString('td[1]/a', v.toNode)); + end; + if chapterName.Count > 0 then + with TRegExpr.Create do + try + Expression := '\.\w+'; + for i := 0 to chapterName.Count - 1 do + chapterName[i] := Replace(chapterName[i], '', False); + finally + Free; + end; + end; + finally + query.Free; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + datapath, datafiles: String; + i: Integer; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + datapath := query.XPathString('//div[@id="reader"]/@data-path'); + datapath := EncodeURLElement(datapath); + datafiles := query.XPathString('//div[@id="reader"]/@data-files'); + datafiles := Trim(TrimChar(datafiles, ['[', ']'])); + datafiles := JSONStringToString(datafiles); + PageLinks.Delimiter := ','; + PageLinks.DelimitedText := datafiles; + if PageLinks.Count > 0 then + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := Module.RootURL + '/reader/image?path=' + + datapath + '&file=' + EncodeURLElement(PageLinks[i]); + finally + query.Free; + end; + end; + end; +end; + +function DownloadImage(var DownloadThread: TDownloadThread; + const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; +var + ext, s: String; + fs: TFileStreamUTF8; +begin + Result := False; + if DownloadThread = nil then Exit; + if GETWithLogin(DownloadThread.FHTTP, AURL) then begin + SaveImageStreamToFile(DownloadThread.FHTTP.Document, APath, AName + APrefix); + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := modulename; + RootURL := urlroot; + AccountSupport := True; + MaxTaskLimit := 1; + MaxConnectionLimit := 4; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + OnLogin := @Login; + end; +end; + +initialization + InitCriticalSection(locklogin); + RegisterModule; + +finalization + DoneCriticalsection(locklogin); + +end. From 41e72fdac0d06c3fd24fb6a0bbde6bf083779631 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 15:08:31 +0800 Subject: [PATCH 0698/2794] remove prefix parameter. doesn't really usable, just append to filename if needed --- baseunits/includes/MeinManga/image_url.inc | 182 ++++++++++----------- baseunits/modules/EHentai.pas | 2 +- baseunits/uBaseUnit.pas | 26 ++- baseunits/uDownloadsManager.pas | 7 +- 4 files changed, 107 insertions(+), 110 deletions(-) diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index c14918caf..e75290e21 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -1,91 +1,91 @@ - function GetMeinMangaImageURL: Boolean; - var - s, imageName: String; - prefix: Cardinal = 0; - i: Cardinal; - l: TStringList; - Parser: THTMLParser; - begin - s := manager.container.DownloadInfo.SaveTo + - '/' + manager.container.ChapterName.Strings[ - manager.container.CurrentDownloadChapterPtr] + '/' + - Format('%.3d', [workCounter + 1]); - // Check to see if a file with similar name was already exist. If so then we - // skip the download process. - if (FileExistsUTF8(s + '.jpg')) or - (FileExistsUTF8(s + '.png')) or - (FileExistsUTF8(s + '.gif')) then - begin - Result := True; - Exit; - end; - - l := TStringList.Create; - - FHTTP.Headers.Values['Accept'] := ' image/png,image/*;q=0.8,*/*;q=0.5'; - FHTTP.Headers.Values['Accept-Encoding'] := ' gzip, deflate'; - FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; - - Result := GetPage(TObject(l), - manager.container.PageLinks.Strings[workCounter], - manager.container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - FHTTP.Free; - Exit; - end; - - parse := TStringList.Create; - try - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="pic_fragment"', parse.Strings[i]) > 0) then - begin - FHTTP.Clear; - - SaveImage( - manager.container.MangaSiteID, - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')), - CorrectPathSys(manager.container.DownloadInfo.SaveTo + - manager.container.ChapterName.Strings[ - manager.container.CurrentDownloadChapterPtr]), - Format('%.3d', [workCounter + 1]), - '_' + IntToStr(prefix), - manager.container.Manager.retryConnect); - - Inc(prefix); - - if Self.Terminated then - begin - l.Free; - parse.Free; - //HTTP.Free; - Exit; - end; - end; - end; - // If prefix = 2 then there're 2 separate images. We need to merge them into one ... - if prefix = 2 then - begin - imageName := Format('%.3d', [workCounter + 1]); - Merge2Images( - CorrectPathSys(manager.container.DownloadInfo.SaveTo + '/' + - manager.container.ChapterName.Strings[manager.container.CurrentDownloadChapterPtr]), - imageName + '_' + IntToStr(prefix - 2) + '.jpg', - imageName + '_' + IntToStr(prefix - 1) + '.jpg', - imageName + '.jpg'); - end; // Merging. - parse.Free; - l.Free; - end; + function GetMeinMangaImageURL: Boolean; + var + s, imageName: String; + prefix: Cardinal = 0; + i: Cardinal; + l: TStringList; + Parser: THTMLParser; + begin + s := manager.container.DownloadInfo.SaveTo + + '/' + manager.container.ChapterName.Strings[ + manager.container.CurrentDownloadChapterPtr] + '/' + + Format('%.3d', [workCounter + 1]); + // Check to see if a file with similar name was already exist. If so then we + // skip the download process. + if (FileExistsUTF8(s + '.jpg')) or + (FileExistsUTF8(s + '.png')) or + (FileExistsUTF8(s + '.gif')) then + begin + Result := True; + Exit; + end; + + l := TStringList.Create; + + FHTTP.Headers.Values['Accept'] := ' image/png,image/*;q=0.8,*/*;q=0.5'; + FHTTP.Headers.Values['Accept-Encoding'] := ' gzip, deflate'; + FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; + + Result := GetPage(TObject(l), + manager.container.PageLinks.Strings[workCounter], + manager.container.Manager.retryConnect); + + if Self.Terminated then + begin + l.Free; + FHTTP.Free; + Exit; + end; + + parse := TStringList.Create; + try + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="pic_fragment"', parse.Strings[i]) > 0) then + begin + FHTTP.Clear; + + SaveImage( + manager.container.MangaSiteID, + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')), + CorrectPathSys(manager.container.DownloadInfo.SaveTo + + manager.container.ChapterName.Strings[ + manager.container.CurrentDownloadChapterPtr]), + Format('%.3d', [workCounter + 1]) + + '_' + IntToStr(prefix), + manager.container.Manager.retryConnect); + + Inc(prefix); + + if Self.Terminated then + begin + l.Free; + parse.Free; + //HTTP.Free; + Exit; + end; + end; + end; + // If prefix = 2 then there're 2 separate images. We need to merge them into one ... + if prefix = 2 then + begin + imageName := Format('%.3d', [workCounter + 1]); + Merge2Images( + CorrectPathSys(manager.container.DownloadInfo.SaveTo + '/' + + manager.container.ChapterName.Strings[manager.container.CurrentDownloadChapterPtr]), + imageName + '_' + IntToStr(prefix - 2) + '.jpg', + imageName + '_' + IntToStr(prefix - 1) + '.jpg', + imageName + '.jpg'); + end; // Merging. + parse.Free; + l.Free; + end; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index a5355db41..1cfff7961 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -300,7 +300,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, -1, iurl, APath, AName, APrefix); + Result := SaveImage(DownloadThread.FHTTP, -1, iurl, APath, AName); if DownloadThread.IsTerminated then Break; if rcount >= reconnect then Break; if not Result then begin diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 815852984..037dc9e2e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -960,11 +960,11 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String): S // Download an image from url and save it to a specific location. function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; + const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; + const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; + const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); @@ -3243,9 +3243,8 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String end; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; - URL: String; const Path, Name, prefix: String; var SavedFilename: String; const Reconnect: Integer - ): Boolean; - // prefix: For example: 000<our prefix>.jpg. + URL: String; const Path, Name: String; var SavedFilename: String; + const Reconnect: Integer): Boolean; var HTTPHeader: TStringList; HTTP: THTTPSend; @@ -3276,7 +3275,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; // Check to see if a file with similar name was already exist. If so then we // skip the download process. if Trim(URL) = 'D' then Exit(True); - s := CleanAndExpandDirectory(Path) + Name + prefix; + s := CleanAndExpandDirectory(Path) + Name; if (FileExistsUTF8(s + '.jpg')) or (FileExistsUTF8(s + '.png')) or (FileExistsUTF8(s + '.gif')) then @@ -3429,24 +3428,23 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Headers.Text := HTTPHeader.Text; end; end; - SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name + prefix); + SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name); preTerminate; Result := SavedFilename <> ''; end; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; - URL: String; const Path, Name, prefix: String; const Reconnect: Integer - ): Boolean; + URL: String; const Path, Name: String; const Reconnect: Integer): Boolean; var f: String; begin - Result := SaveImage(AHTTP, mangaSiteID, URL, Path, Name, prefix, f, Reconnect); + Result := SaveImage(AHTTP, mangaSiteID, URL, Path, Name, f, Reconnect); end; -function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name, - prefix: String; var SavedFilename: String; const Reconnect: Integer): Boolean; +function SaveImage(const mangaSiteID: Integer; URL: String; const Path, + Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; begin - Result := SaveImage(nil, mangaSiteID, URL, Path, Name, prefix, SavedFilename, Reconnect); + Result := SaveImage(nil, mangaSiteID, URL, Path, Name, SavedFilename, Reconnect); end; procedure QuickSortChapters(var chapterList, linkList: TStringList); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 1cbe58966..5eaaeeb3a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -61,7 +61,7 @@ TDownloadThread = class(TFMDThread) const Reconnect: Integer = 0): Boolean; inline; function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Integer = 0): Boolean; overload; + const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; procedure Execute; override; procedure DoTerminate; override; @@ -291,9 +291,9 @@ function TDownloadThread.GetPage(var output: TObject; URL: String; end; function TDownloadThread.SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name, prefix: String; const Reconnect: Integer): Boolean; + const Path, Name: String; const Reconnect: Integer): Boolean; begin - Result := uBaseUnit.SaveImage(FHTTP, mangaSiteID, URL, Path, Name, prefix, Reconnect); + Result := uBaseUnit.SaveImage(FHTTP, mangaSiteID, URL, Path, Name, Reconnect); end; procedure TDownloadThread.Execute; @@ -1199,7 +1199,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; TURL, lpath, Format('%.3d', [workCounter + 1]), - prefix, sfilename, manager.container.Manager.retryConnect); if Terminated then Exit(False); From d60f979558d4f38c92b4a7a589fcabe8731d64b3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 22:30:47 +0800 Subject: [PATCH 0699/2794] tdbdataprocess, property table --- baseunits/uData.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b0bb87b70..a73ba957f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -112,6 +112,7 @@ TDBDataProcess = class(TObject) property WebsiteName[RecIndex: Integer]: String read GetWebsiteName; property Value[RecIndex, ParamNo: Integer]: String read GetValue; property LinkCount: Integer read GetLinkCount; + property Table: TSQLQuery read FQuery; end; { TDataProcess } From 74ce18013f8e3dad518be895bb427bc75bbde1e2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 22:31:34 +0800 Subject: [PATCH 0700/2794] tfbdataprocess, close db on createdatabase --- baseunits/uData.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a73ba957f..8d52340b8 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1177,10 +1177,9 @@ procedure TDBDataProcess.CreateDatabase(AWebsite: String); var filepath: String; begin - if AWebsite <> '' then - FWebsite := AWebsite; - if FWebsite = '' then - Exit; + if AWebsite <> '' then FWebsite := AWebsite; + if FWebsite = '' then Exit; + Close; filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; if FileExistsUTF8(filepath) then DeleteFileUTF8(filepath); From 148c3a6e983d28d259683c8a29c81145c0e5aa69 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 23:12:35 +0800 Subject: [PATCH 0701/2794] updatelistmanager, use database file to store temp links fix #145 --- baseunits/uUpdateThread.pas | 141 +++++++++++++----------------------- 1 file changed, 51 insertions(+), 90 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index afd09939d..7cf015c07 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -58,7 +58,8 @@ TUpdateMangaManagerThread = class(TFMDThread) CS_AddInfoToData, CS_AddNamesAndLinks: TCriticalSection; isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; mainDataProcess: TDBDataProcess; - names, links, websites: TStringList; + tempDataProcess: TDBDataProcess; + websites: TStringList; website, twebsite: String; ModuleId: Integer; workPtr, directoryCount, @@ -109,6 +110,7 @@ destructor TUpdateMangaThread.Destroy; procedure TUpdateMangaThread.Execute; var names, links: TStringList; + name, link: String; i: Integer; begin try @@ -194,13 +196,14 @@ procedure TUpdateMangaThread.Execute; if links.Count > 0 then begin if manager.SortedList then - if manager.mainDataProcess.LinkExist(links.Strings[0]) then + if manager.mainDataProcess.LinkExist(links[0]) then manager.isFinishSearchingForNewManga := True; manager.CS_AddNamesAndLinks.Acquire; try - manager.links.AddStrings(links); - manager.names.AddStrings(names); + for i := 0 to links.Count - 1 do + manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); + manager.tempDataProcess.Commit; finally manager.CS_AddNamesAndLinks.Release; end; @@ -213,14 +216,15 @@ procedure TUpdateMangaThread.Execute; CS_INFO: begin - Info.mangaInfo.title := manager.names[workPtr]; - Info.GetInfoFromURL(manager.website, manager.links[workPtr], - OptionConnectionMaxRetry); + name := manager.tempDataProcess.Value[workPtr,0]; + link := manager.tempDataProcess.Value[workPtr,1]; + Info.mangaInfo.title := name; + Info.GetInfoFromURL(manager.website, link,OptionConnectionMaxRetry); if not Terminated then begin manager.CS_AddInfoToData.Acquire; try - Info.AddInfoToData(manager.names[workPtr], manager.links[workPtr], + Info.AddInfoToData(name, link, manager.mainDataProcess); manager.CheckCommit(32); finally @@ -238,8 +242,8 @@ procedure TUpdateMangaThread.Execute; if checkStyle = CS_INFO then begin E.Message := E.Message + - ' Title : ' + manager.names[workPtr] + LineEnding + - ' URL : ' + manager.links[workPtr] + LineEnding; + ' Title : ' + name + LineEnding + + ' URL : ' + link + LineEnding; end; MainForm.ExceptionHandler(Self, E); end; @@ -329,10 +333,9 @@ constructor TUpdateMangaManagerThread.Create; FreeOnTerminate := True; websites := TStringList.Create; - names := TStringList.Create; - links := TStringList.Create; mainDataProcess := TDBDataProcess.Create; + tempDataProcess := TDBDataProcess.Create; threads := TFPList.Create; SortedList := False; @@ -342,12 +345,13 @@ constructor TUpdateMangaManagerThread.Create; destructor TUpdateMangaManagerThread.Destroy; begin + websites.Free; mainDataProcess.Close; DeleteDBDataProcess(twebsite); - websites.Free; - names.Free; - links.Free; + tempDataProcess.Close; + DeleteDBDataProcess('__tempupdatelist'); mainDataProcess.Free; + tempDataProcess.Free; threads.Free; MainForm.isUpdating := False; CS_AddInfoToData.Free; @@ -402,7 +406,7 @@ procedure TUpdateMangaManagerThread.RefreshList; procedure TUpdateMangaManagerThread.DlgReport; begin - MessageDlg('', Format(RS_DlgHasNewManga, [website, links.Count]), + MessageDlg('', Format(RS_DlgHasNewManga, [website, tempDataProcess.RecordCount]), mtInformation, [mbYes], 0); end; @@ -492,7 +496,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; CS_DIRECTORY_PAGE_2: s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; CS_INFO: - s := Format('%s | %s "%s"', [s, RS_GettingInfo, names[workPtr - 1]]); + s := Format('%s | %s "%s"', [s, RS_GettingInfo, tempDataProcess.Value[workPtr-1,0]]); end; FStatus := s; MainForm.ulWorkPtr := workPtr + 1; @@ -531,7 +535,6 @@ procedure TUpdateMangaManagerThread.DoTerminate; procedure TUpdateMangaManagerThread.Execute; var c, j, k: Integer; - del: Boolean; begin if websites.Count = 0 then Exit; @@ -551,6 +554,7 @@ procedure TUpdateMangaManagerThread.Execute; end; end else + tempDataProcess.CreateDatabase('__tempupdatelist'); while websitePtr < websites.Count do begin website := websites.Strings[websitePtr]; @@ -581,7 +585,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.InitLocateLink; mainDataProcess.CloseTable; - //get directory page count + // get directory page count INIAdvanced.Reload; directoryCount := 0; directoryCount2 := 0; @@ -589,7 +593,7 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; - //get names and links + // get names and links INIAdvanced.Reload; workPtr := 0; isFinishSearchingForNewManga := False; @@ -625,80 +629,40 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; Synchronize(MainThreadShowGetting); - // remove duplicate - if links.Count > 0 then - begin - c := 0; - j := 0; - MainForm.ulTotalPtr := links.Count; - MainForm.ulWorkPtr := j; - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromNewTitle + '...'; - Synchronize(MainThreadShowGetting); - while j < (links.Count - 1) do - begin - if Terminated then Break; - Inc(c); - if c > 499 then - begin - c := 0; - MainForm.ulTotalPtr := links.Count; - MainForm.ulWorkPtr := j; - Synchronize(MainThreadStatusRepaint); - end; - del := False; - if (j + 1) < links.Count then - for k := j + 1 to links.Count - 1 do - begin - if Terminated then Break; - if SameText(links[j], links[k]) then - begin - links.Delete(j); - names.Delete(j); - del := True; - Break; - end; - end; - if not del then - Inc(j); - end; - end; + tempDataProcess.OpenTable('', True); // remove duplicate found<>current database - if (links.Count > 0) and (mainDataProcess.LinkCount > 0) then - begin - c := 0; - j := 0; - MainForm.ulTotalPtr := links.Count; - MainForm.ulWorkPtr := j; + if (mainDataProcess.LinkCount>0) and (tempDataProcess.RecordCount>0) then begin + MainForm.ulTotalPtr:=tempDataProcess.RecordCount; + MainForm.ulWorkPtr:=0; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromCurrentData + '...'; Synchronize(MainThreadShowGetting); - while j < links.Count do - begin - if Terminated then Break; - Inc(c); - if c > 999 then - begin - c := 0; - MainForm.ulTotalPtr := links.Count; - MainForm.ulWorkPtr := j; - Synchronize(MainThreadStatusRepaint); + with tempDataProcess.Table do begin + c:=0; + First; + while not tempDataProcess.Table.EOF do begin + if Terminated then Break; + Inc(c); + Inc(MainForm.ulWorkPtr); + if c>750 then begin + c:=0; + Synchronize(MainThreadStatusRepaint); + end; + if mainDataProcess.LinkExist(Fields[1].AsString) then + Delete + else + Next; end; - if mainDataProcess.LinkExist(links[j]) then - begin - links.Delete(j); - names.Delete(j); - end - else - Inc(j); + ApplyUpdates; end; end; + tempDataProcess.Refresh(True); mainDataProcess.DoneLocateLink; - //get manga info - if links.Count > 0 then + // get manga info + if tempDataProcess.RecordCount>0 then begin workPtr := 0; FCommitCount := 0; @@ -706,11 +670,11 @@ procedure TUpdateMangaManagerThread.Execute; OptionUpdateListNoMangaInfo then begin Inc(workPtr); - for k := 0 to links.Count - 1 do + for k:=0 to tempDataProcess.RecordCount-1 do begin mainDataProcess.AddData( - names[k], - links[k], + tempDataProcess.Value[k,0], + tempDataProcess.Value[k,1], '', '', '', @@ -723,12 +687,9 @@ procedure TUpdateMangaManagerThread.Execute; end; end else - GetInfo(links.Count, CS_INFO); + GetInfo(tempDataProcess.RecordCount, CS_INFO); mainDataProcess.Commit; - names.Clear; - links.Clear; - if workPtr > 0 then if not (Terminated and SortedList) then begin From d86548d8670803d901ba9cc8d92755567c26d209 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Dec 2015 23:28:43 +0800 Subject: [PATCH 0702/2794] Bump version 0.9.28.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2950cd6bc..0ade2b4ef 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,13 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.28.0 (29-12-2015) +[+] Added Manga folder custom rename. Options > Save to +[*] Madokami: rewrite and add account support +[*] Fix load user-agent from advanced.ini +[*] Fix "Run out of memory" when updating long manga list +[*] Various changes and bug fixes + 0.9.27.0 (26-12-2015) [+] Added Remove MangaFox watermark feature. Options > Misc [*] Batoto: fix add language and scan group to chapter title diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 953c1c368..884f25216 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="27"/> + <RevisionNr Value="28"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 3c5be1e7b..9a6576613 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.27.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.27.0/fmd_0.9.27.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.27.0/fmd_0.9.27.0_Win64.7z +VERSION=0.9.28.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.28.0/fmd_0.9.28.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.28.0/fmd_0.9.28.0_Win64.7z From 25c51d520d99562521d9d5a445c2ea58b4d92849 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 13:36:09 +0800 Subject: [PATCH 0703/2794] madokami, clean up --- baseunits/modules/Madokami.pas | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 71e1e3498..4a37b0a4f 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -6,8 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, LazFileUtils, LazUTF8Classes, synacode, Imaging, RegExpr, - fpjson; + accountmanagerdb, synacode, RegExpr, fpjson; implementation @@ -206,9 +205,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; function DownloadImage(var DownloadThread: TDownloadThread; const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; -var - ext, s: String; - fs: TFileStreamUTF8; begin Result := False; if DownloadThread = nil then Exit; From caf585733a3b58d43e42a1b1079ed09f3e91d160 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 15:44:51 +0800 Subject: [PATCH 0704/2794] baseunit, saveimage, don't save to file if thread interrupted --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 037dc9e2e..62982036d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3428,6 +3428,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; HTTP.Headers.Text := HTTPHeader.Text; end; end; + if checkTerminate then Exit; SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name); preTerminate; Result := SavedFilename <> ''; From 078179bc2cc8e915e1c5dcfe44ce554328632b65 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:10:11 +0800 Subject: [PATCH 0705/2794] websitemodules, add missing check onbeforedownloadimage --- baseunits/WebsiteModules.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index f904e0681..20501ec70 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -324,6 +324,7 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; MMGetInfo: Result := Assigned(OnGetInfo); MMGetPageNumber: Result := Assigned(OnGetPageNumber); MMGetImageURL: Result := Assigned(OnGetImageURL); + MMBeforeDownloadImage: Result := Assigned(OnBeforeDownloadImage); MMDownloadImage: Result := Assigned(OnDownloadImage); MMLogin: Result := Assigned(OnLogin); else From 1fa22f9a8989948a25271cd9574e7e91de46860a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:10:59 +0800 Subject: [PATCH 0706/2794] downloadmanager, implement onbeforedownloadimage --- baseunits/uDownloadsManager.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5eaaeeb3a..31a840771 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1173,6 +1173,10 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; //TURL := DecodeURL(TURL); //decode first to avoid double encoded //TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); + if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then begin + Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); + end; + if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin s := ''; if workCounter < manager.container.PageContainerLinks.Count then From 87587967fb892974699e904d0b7cf6c0092467b2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:23:41 +0800 Subject: [PATCH 0707/2794] websitemodules, add onafterimagesaved --- baseunits/WebsiteModules.pas | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 20501ec70..fbc04b225 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -40,11 +40,13 @@ TModuleContainer = class; TOnDownloadImage = function(var DownloadThread: TDownloadThread; const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; + TOnAfterImageSaved = function(const AFilename: String; Module: TModuleContainer): Boolean; + TOnLogin = function(var AHTTP: THTTPSendThread): Boolean; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, - MMDownloadImage, MMLogin); + MMDownloadImage, MMAfterImageSaved, MMLogin); { TModuleContainer } @@ -74,6 +76,7 @@ TModuleContainer = class OnGetImageURL: TOnGetImageURL; OnBeforeDownloadImage: TOnBeforeDownloadImage; OnDownloadImage: TOnDownloadImage; + OnAfterImageSaved: TOnAfterImageSaved; OnLogin: TOnLogin; constructor Create; destructor Destroy; override; @@ -157,6 +160,9 @@ TWebsiteModules = class function DownloadImage(var DownloadThread: TDownloadThread; const AURL, APath, AName, APrefix, AWebsite: String): Boolean; overload; + function AfterImageSaved(const AFilename: String; ModuleId: Integer): Boolean; overload; + function AfterImageSaved(const AFilename: String; AWebsite: String): Boolean; overload; + function Login(var AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; overload; function Login(var AHTTP: THTTPSendThread; const AWebsite: String): Boolean; overload; @@ -326,6 +332,7 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; MMGetImageURL: Result := Assigned(OnGetImageURL); MMBeforeDownloadImage: Result := Assigned(OnBeforeDownloadImage); MMDownloadImage: Result := Assigned(OnDownloadImage); + MMAfterImageSaved: Result := Assigned(OnAfterImageSaved); MMLogin: Result := Assigned(OnLogin); else Result := False; @@ -490,6 +497,21 @@ function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; LocateModule(AWebsite)); end; +function TWebsiteModules.AfterImageSaved(const AFilename: String; + ModuleId: Integer): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved) then + Result := TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved(AFilename, TModuleContainer(FModuleList[ModuleId])); +end; + +function TWebsiteModules.AfterImageSaved(const AFilename: String; + AWebsite: String): Boolean; +begin + Result := AfterImageSaved(AFilename, LocateModule(AWebsite)); +end; + function TWebsiteModules.Login(var AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; begin From 799b81b9dbb076eb7b0eceac9d524efa8747a01d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:24:26 +0800 Subject: [PATCH 0708/2794] downloadmanager, implement onafterimagesaved --- baseunits/uDownloadsManager.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 31a840771..a5f294a14 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1173,9 +1173,8 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; //TURL := DecodeURL(TURL); //decode first to avoid double encoded //TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); - if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then begin + if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); - end; if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin s := ''; @@ -1209,6 +1208,9 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; if Result then begin manager.container.PageLinks[workCounter] := 'D'; + if Modules.ModuleAvailable(ModuleId, MMAfterImageSaved) then + Modules.AfterImageSaved(sfilename, ModuleId); + // remove mangafox watermark if manager.container.ModuleId > -1 then if Modules.Module[ModuleId].Website = 'MangaFox' then From 9d06fff735dbe3d314554042feb1f89d94dacdd0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:40:58 +0800 Subject: [PATCH 0709/2794] mangafox, move remove watermark to onafterimagesaved --- baseunits/modules/MangaFox.pas | 8 +++++++- baseunits/uDownloadsManager.pas | 7 +------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 3358e08f5..5e2af03c1 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, RegExpr; + mangafoxwatermarkremover, HTMLUtil, RegExpr; implementation @@ -295,6 +295,11 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; end; end; +function AfterImageSaved(const AFilename: String; Module: TModuleContainer): Boolean; +begin + Result := mangafoxwatermarkremover.RemoveWatermark(AFilename); +end; + procedure RegisterModule; begin with AddModule do @@ -308,6 +313,7 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; + OnAfterImageSaved := @AfterImageSaved; end; end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a5f294a14..38e75d2fb 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface lazutf8classes, LazFileUtils, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, - uFMDThread, uMisc, mangafoxwatermarkremover, USimpleLogger, dateutils; + uFMDThread, uMisc, USimpleLogger, dateutils; type TDownloadManager = class; @@ -1210,11 +1210,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; if Modules.ModuleAvailable(ModuleId, MMAfterImageSaved) then Modules.AfterImageSaved(sfilename, ModuleId); - - // remove mangafox watermark - if manager.container.ModuleId > -1 then - if Modules.Module[ModuleId].Website = 'MangaFox' then - mangafoxwatermarkremover.RemoveWatermark(sfilename); end; end; From 0374db75737bcf2ea1ff1bc94f45c35a17949521 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:42:21 +0800 Subject: [PATCH 0710/2794] downloadmanager, fix downloadimage --- baseunits/uDownloadsManager.pas | 56 ++++++++++++++++----------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 38e75d2fb..0c04bf64f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1170,40 +1170,38 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; if manager.container.MangaSiteID = SENMANGARAW_ID then Result := GetSenMangaRAWImageURL; - //TURL := DecodeURL(TURL); //decode first to avoid double encoded - //TURL := EncodeTriplet(TURL, '%', URLSpecialChar + ['#']); - if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); - if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin - s := ''; - if workCounter < manager.container.PageContainerLinks.Count then - s := manager.container.PageContainerLinks[workCounter] - else if workCounter < manager.container.PageLinks.Count then - s := manager.container.PageLinks[workCounter]; - if s <> '' then - Result := Modules.DownloadImage( - Self, - s, + if Result then begin + if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin + s := ''; + if workCounter < manager.container.PageContainerLinks.Count then + s := manager.container.PageContainerLinks[workCounter] + else if workCounter < manager.container.PageLinks.Count then + s := manager.container.PageLinks[workCounter]; + if s <> '' then + Result := Modules.DownloadImage( + Self, + s, + lpath, + Format('%.3d', [workCounter + 1]), + prefix, + ModuleId); + end + else + if manager.container.MangaSiteID = MEINMANGA_ID then + Result := GetMeinMangaImageURL + else + Result := uBaseUnit.SaveImage( + FHTTP, + manager.container.MangaSiteID, + TURL, lpath, Format('%.3d', [workCounter + 1]), - prefix, - ModuleId); - end - else - if manager.container.MangaSiteID = MEINMANGA_ID then - Result := GetMeinMangaImageURL - else - if Result then - Result := uBaseUnit.SaveImage( - FHTTP, - manager.container.MangaSiteID, - TURL, - lpath, - Format('%.3d', [workCounter + 1]), - sfilename, - manager.container.Manager.retryConnect); + sfilename, + manager.container.Manager.retryConnect); + end; if Terminated then Exit(False); if Result then begin manager.container.PageLinks[workCounter] := 'D'; From 421b2c53e600b0fdf228d4a23a250f62a4657a9c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:52:17 +0800 Subject: [PATCH 0711/2794] remove deprecated senmagaraw #146 --- .../SenMangaRAW/chapter_page_number.inc | 48 -------- baseunits/includes/SenMangaRAW/image_url.inc | 35 ------ .../SenMangaRAW/manga_information.inc | 115 ------------------ .../includes/SenMangaRAW/names_and_links.inc | 47 ------- baseunits/uBaseUnit.pas | 10 +- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 9 -- 7 files changed, 4 insertions(+), 270 deletions(-) delete mode 100644 baseunits/includes/SenMangaRAW/chapter_page_number.inc delete mode 100644 baseunits/includes/SenMangaRAW/image_url.inc delete mode 100644 baseunits/includes/SenMangaRAW/manga_information.inc delete mode 100644 baseunits/includes/SenMangaRAW/names_and_links.inc diff --git a/baseunits/includes/SenMangaRAW/chapter_page_number.inc b/baseunits/includes/SenMangaRAW/chapter_page_number.inc deleted file mode 100644 index ab9c676fc..000000000 --- a/baseunits/includes/SenMangaRAW/chapter_page_number.inc +++ /dev/null @@ -1,48 +0,0 @@ - function GetSenMangaRAWPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isExtractPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - try - if GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(SENMANGARAW_ID, URL + '/1')), - manager.container.manager.retryConnect) then - begin - Result := True; - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'name') = 'page') then - isExtractPageNumber := True; - if isExtractPageNumber then - begin - if GetTagName(parse[i]) = '/select' then - Break - else - if GetTagName(parse[i]) = 'option' then - manager.container.PageLinks.Add('G'); - end; - end; - end; - end - else - Result := False; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/SenMangaRAW/image_url.inc b/baseunits/includes/SenMangaRAW/image_url.inc deleted file mode 100644 index abe177b85..000000000 --- a/baseunits/includes/SenMangaRAW/image_url.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetSenMangaRAWImageURL: Boolean; - var - i: Integer; - s: String; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - try - s := manager.container.ChapterLinks[manager.container.CurrentDownloadChapterPtr] + - '/' + IntToStr(QWord(workCounter) + 1); - s := FillHost(WebsiteRoots[SENMANGARAW_ID, 1], s); - if GetPage(TObject(l), s, manager.container.Manager.retryConnect) then - begin - TURL := ''; - if l.Count > 0 then - for i := 0 to l.Count - 1 do - begin - if Pos('var new_image =', l[i]) > 0 then begin - TURL := GetValuesFromString(l[i], '='); - TURL := MaybeFillHost(WebsiteRoots[SENMANGARAW_ID, 1], TURL); - Break; - end; - end; - Result := (TURL <> ''); - FHTTP.Clear; - FHTTP.Headers.Values['Referer'] := ' ' + s; - end - else - Result := False; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/SenMangaRAW/manga_information.inc b/baseunits/includes/SenMangaRAW/manga_information.inc deleted file mode 100644 index 6523228c9..000000000 --- a/baseunits/includes/SenMangaRAW/manga_information.inc +++ /dev/null @@ -1,115 +0,0 @@ -function GetSenMangaRAWInfoFromURL: Byte; -var - i, j: Integer; - isExtractChapters: Boolean = False; -begin - mangaInfo.website := WebsiteRoots[SENMANGARAW_ID, 0]; - mangaInfo.url := FillMangaSiteHost(SENMANGARAW_ID, URL); - if GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if (GetTagName(parse[i]) = 'h1') then - if (GetTagName(parse[i + 1]) = 'a') then - mangaInfo.title := parse[i + 2]; - //cover - if mangaInfo.coverLink = '' then - if (GetTagName(parse[i]) = 'img') and (Pos('this.src =''/no_preview.jpg'';', parse[i]) > 0) then - begin - mangaInfo.coverLink := FixURL(GetVal(parse[i], 'src')); - if Pos('http', mangaInfo.coverLink) <> 1 then - begin - if LeftStr(mangaInfo.coverLink, 1) <> '/' then - mangaInfo.coverLink := '/' + mangaInfo.coverLink; - mangaInfo.coverLink := WebsiteRoots[SENMANGARAW_ID, 1] + mangaInfo.coverLink; - end; - end; - - if (GetTagName(parse[i]) = 'strong') and (GetVal(parse[i], 'class') = 'data') then - begin - //author - if Trim(parse[i + 1]) = 'Author:' then - mangaInfo.authors := parse[i + 5]; - //artist - if Trim(parse[i + 1]) = 'Artist:' then - mangaInfo.artists := parse[i + 5]; - //status - if Trim(parse[i + 1]) = 'Status:' then - begin - mangaInfo.status := Trim(parse[i + 5]); - if mangaInfo.status = 'Complete' then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end; - //genres - if Trim(parse[i + 1]) = 'Categorize in:' then - for j := i + 3 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = 'strong' then - Break - else - if GetTagName(parse[j]) = 'a' then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[j + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[j + 1]); - end; - end; - //summary - if Trim(parse[i + 1]) = 'Summary:' then - for j := i + 3 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = 'div' then - Break - else - if LeftStr(Trim(parse[j]), 1) <> '<' then - mangaInfo.summary := mangaInfo.summary + LineEnding + Trim(parse[j]); - end; - end; - - //chapters - if (GetTagName(parse[i]) = 'table') and (GetVal(parse[i], 'width') = '100%') then - isExtractChapters := True; - if isExtractChapters then - begin - if GetTagName(parse[i]) = '/table' then - isExtractChapters := False - else - if GetTagName(parse[i]) = 'a' then - begin - s := GetVal(parse[i], 'href'); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - mangaInfo.chapterLinks.Add(s); - mangaInfo.chapterName.Add(parse[i + 1]); - end; - end; - end; - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end - else - Result := INFORMATION_NOT_FOUND; - end - else - Result := NET_PROBLEM; -end; diff --git a/baseunits/includes/SenMangaRAW/names_and_links.inc b/baseunits/includes/SenMangaRAW/names_and_links.inc deleted file mode 100644 index 26a6c8247..000000000 --- a/baseunits/includes/SenMangaRAW/names_and_links.inc +++ /dev/null @@ -1,47 +0,0 @@ - function SenMangaRAWGetNamesAndLinks: Byte; - var - i: Integer; - isExtractNames: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SENMANGARAW_ID, 1] + - '/Manga/?order=text-version', 3) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(FixHTMLTagQuote(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'id') = 'content') then - isExtractNames := True; - if isExtractNames then - begin - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'col-xm-12 col-sm-4 col-md-4') then - Break - else - if GetTagName(parse[i]) = 'a' then - if GetTagName(parse[i + 4]) = 'td' then - begin - names.Add(parse[i + 1]); - links.Add(GetVal(parse[i], 'href')); - end; - end; - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 62982036d..e1781738f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -346,12 +346,11 @@ interface MANGAKU_ID = 78; ACADEMYVN_ID = 79; MANGAAT_ID = 80; - SENMANGARAW_ID = 81; - READMANGATODAY_ID = 82; - LONEMANGA_ID = 83; - DYNASTYSCANS_ID = 84; + READMANGATODAY_ID = 81; + LONEMANGA_ID = 82; + DYNASTYSCANS_ID = 83; - WebsiteRoots: array [0..84] of array [0..1] of string = ( + WebsiteRoots: array [0..83] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -433,7 +432,6 @@ interface ('MangaKu', 'http://mangaku.web.id'), ('AcademyVN', 'http://truyen.academyvn.com'), ('MangaAt', 'http://www.mangaat.com'), - ('SenMangaRAW', 'http://raw.senmanga.com'), ('ReadMangaToday', 'http://www.readmanga.today'), ('LoneManga', 'http://lonemanga.com'), ('Dynasty-Scans', 'http://dynasty-scans.com') diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8d52340b8..11ffe723f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2333,8 +2333,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaAt/names_and_links.inc} - {$I includes/SenMangaRAW/names_and_links.inc} - {$I includes/ReadMangaToday/names_and_links.inc} {$I includes/LoneManga/names_and_links.inc} @@ -2563,9 +2561,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGAAT_ID then Result := MangaAtGetNamesAndLinks else - if WebsiteID = SENMANGARAW_ID then - Result := SenMangaRAWGetNamesAndLinks - else if WebsiteID = READMANGATODAY_ID then Result := ReadMangaTodayGetNamesAndLinks else @@ -2727,8 +2722,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaAt/manga_information.inc} - {$I includes/SenMangaRAW/manga_information.inc} - {$I includes/ReadMangaToday/manga_information.inc} {$I includes/LoneManga/manga_information.inc} @@ -2969,9 +2962,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGAAT_ID then Result := GetMangaAtInfoFromURL else - if WebsiteID = SENMANGARAW_ID then - Result := GetSenMangaRAWInfoFromURL - else if WebsiteID = READMANGATODAY_ID then Result := GetReadMangaTodayInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 0c04bf64f..939bfb62e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -475,8 +475,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaAt/chapter_page_number.inc} - {$I includes/SenMangaRAW/chapter_page_number.inc} - {$I includes/ReadMangaToday/chapter_page_number.inc} {$I includes/LoneManga/chapter_page_number.inc} @@ -657,9 +655,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAAT_ID then Result := GetMangaAtPageNumber else - if manager.container.MangaSiteID = SENMANGARAW_ID then - Result := GetSenMangaRAWPageNumber - else if manager.container.MangaSiteID = READMANGATODAY_ID then Result := GetReadMangaTodayPageNumber else @@ -1144,8 +1139,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; {$I includes/MeinManga/image_url.inc} - {$I includes/SenMangaRAW/image_url.inc} - begin sfilename := ''; lpath := CleanAndExpandDirectory(CorrectPathSys(manager.container.DownloadInfo.SaveTo + @@ -1167,8 +1160,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; Exit; FHTTP.Clear; - if manager.container.MangaSiteID = SENMANGARAW_ID then - Result := GetSenMangaRAWImageURL; if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); From 54010f45d6a881979e0c0cff17680d78d72a8c3c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:53:03 +0800 Subject: [PATCH 0712/2794] added raws enmanga close #146 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/RawSenManga.pas | 202 ++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/RawSenManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 086e9ada4..860172a70 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -17,4 +17,5 @@ uses HitomiLa, HentaiCafe, MangaTr, - Madokami; + Madokami, + RawSenManga; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas new file mode 100644 index 000000000..4825cd661 --- /dev/null +++ b/baseunits/modules/RawSenManga.pas @@ -0,0 +1,202 @@ +unit RawSenManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr, synautil; + +implementation + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+'/Manga/?order=text-version') then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table//tr/td[2]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + i: Integer; + s: String; + cu: Boolean; + cl: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=RemoveURLDelim(AURL); + cl:=''; + with TRegExpr.Create do + try + Expression:='/\d+(/\d+)?$'; + cu:=Exec(s); + if cu then begin + cl:=s; + s:=Replace(s,'',False); + end; + finally + Free; + end; + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + url:=AppendURLDelim(FillHost(Module.RootURL,s)); + if GET(url) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//img[@class="series-cover"]/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=query.XPathString('//h1[@itemprop="name"]'); + v:=query.XPath('//div[@class="series_desc"]/*'); + if v.Count > 0 then begin + i:=0; + while i<v.Count-2 do begin + s:=v.get(i).toString; + if Pos('Categorize in:',s)=1 then genres:=v.get(i+1).toString else + if Pos('Author:',s)=1 then authors:=v.get(i+1).toString else + if Pos('Artist:',s)=1 then artists:=Trim(SeparateRight(v.get(i).toString,':')) else + if Pos('Status:',s)=1 then if Pos('ongoing',LowerCase(v.get(i).toString))>0 then status:='1' else status:='0'; + Inc(i); + end; + end; + summary:=query.XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); + if cu and (cl<>'') then + if GET(FillHost(Module.RootURL,cl)) then + begin + query.ParseHTML(StreamToString(Document)); + s:=query.XPathString('//select[@name="chapter"]/option[@selected="selected"]'); + if s<>'' then begin + chapterLinks.Add(cl); + chapterName.Add(s); + end; + end; + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + s:=RemoveURLDelim(ChapterLinks[CurrentDownloadChapterPtr]); + with TRegExpr.Create do + try + Expression:='/\d+/\d+$'; + if Exec(s) then begin + Expression:='/\d+$'; + s:=Replace(s,'',False); + end; + ChapterLinks[CurrentDownloadChapterPtr]:=s; + finally + Free; + end; + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,s+'/1')) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('//select[@name="page"]/option').Count; + if PageNumber>0 then begin + s:=MaybeFillHost(Module.RootURL,query.XPathString('//img[@id="picture"]/@src')); + if Pos('/raw-viewer.php?',LowerCase(s))>0 then begin + if LowerCase(RightStr(s,7))='&page=1' then begin + SetLength(s,Length(s)-1); + while PageLinks.Count<PageNumber do PageLinks.Add(s+IncStr(PageLinks.Count)); + end; + end; + end; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + if GET(FillHost(Module.RootURL,AURL)+'/'+IncStr(DownloadThread.WorkCounter)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + s:=MaybeFillHost(Module.RootURL,query.XPathString('//img[@id="picture"]/@src')); + if s<>'' then + PageLinks[DownloadThread.workCounter]:=s; + finally + query.Free; + end; + end; + end; +end; + +function BeforeDownloadImage(var DownloadThread: TDownloadThread; + AURL: String; Module: TModuleContainer): Boolean; +begin + Result:=False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do + if CurrentDownloadChapterPtr<ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer']:=' '+FillHost(Module.RootURL,ChapterLinks[CurrentDownloadChapterPtr]); + Result:=True; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='RawSenManga'; + RootURL:='http://raw.senmanga.com'; + MaxTaskLimit:=1; + MaxConnectionLimit:=4; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + OnBeforeDownloadImage:=@BeforeDownloadImage; + end; +end; + +initialization + RegisterModule; + +end. From fb871566032414927b327fda4e4c8efa33019fc9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 16:57:50 +0800 Subject: [PATCH 0713/2794] baseunit, saveimagestreamtofile, don't save if image format unknown #147 --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e1781738f..ebe3b8eb2 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3222,7 +3222,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String if not DirectoryExistsUTF8(p) then ForceDirectoriesUTF8(p); if DirectoryExistsUTF8(p) then begin f := DetermineStreamFormat(Stream); - if f = '' then f := 'dat'; + if f = '' then Exit; f := p + FileName + '.' + f; if FileExistsUTF8(f) then DeleteFileUTF8(f); try From 059ef35980a2138ff3f1f557ad70ca5bde94033f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 31 Dec 2015 18:23:07 +0800 Subject: [PATCH 0714/2794] add to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 52f2f685a..87ca92eab 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -12,7 +12,7 @@ Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,Pecinta Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint +Raw=MangaMint,RawSenManga Russian=NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom From b2c8fb88cc52a1fc6266f3b69a89f9105cf57ed3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jan 2016 02:30:25 +0800 Subject: [PATCH 0715/2794] add besen library and cleanup project options https://github.com/BeRo1985/besen --- 3rd/besen/LICENSE | 505 ++ 3rd/besen/copying.besen | 31 + 3rd/besen/copying.txt | 504 ++ 3rd/besen/src/BESEN.inc | 263 + 3rd/besen/src/BESEN.pas | 1866 +++++ 3rd/besen/src/BESENASTNodes.pas | 2191 ++++++ 3rd/besen/src/BESENArrayUtils.pas | 123 + 3rd/besen/src/BESENBaseObject.pas | 59 + 3rd/besen/src/BESENCharset.pas | 421 ++ 3rd/besen/src/BESENCode.pas | 699 ++ 3rd/besen/src/BESENCodeContext.pas | 4011 ++++++++++ 3rd/besen/src/BESENCodeGeneratorContext.pas | 531 ++ 3rd/besen/src/BESENCodeJIT.pas | 89 + 3rd/besen/src/BESENCodeJITx64.pas | 2229 ++++++ 3rd/besen/src/BESENCodeJITx86.pas | 2552 +++++++ 3rd/besen/src/BESENCodeSnapshot.pas | 1387 ++++ 3rd/besen/src/BESENCollector.pas | 73 + 3rd/besen/src/BESENCollectorObject.pas | 80 + 3rd/besen/src/BESENCompiler.pas | 6597 +++++++++++++++++ 3rd/besen/src/BESENConstants.pas | 103 + 3rd/besen/src/BESENContext.pas | 452 ++ 3rd/besen/src/BESENDateUtils.pas | 1368 ++++ .../src/BESENDeclarativeEnvironmentRecord.pas | 612 ++ 3rd/besen/src/BESENDecompiler.pas | 1017 +++ 3rd/besen/src/BESENDoubleList.pas | 229 + 3rd/besen/src/BESENEnvironmentRecord.pas | 201 + 3rd/besen/src/BESENErrors.pas | 630 ++ 3rd/besen/src/BESENEvalCache.pas | 142 + 3rd/besen/src/BESENEvalCacheItem.pas | 85 + 3rd/besen/src/BESENGarbageCollector.pas | 991 +++ 3rd/besen/src/BESENGlobals.pas | 42 + 3rd/besen/src/BESENHashMap.pas | 308 + 3rd/besen/src/BESENHashUtils.pas | 159 + 3rd/besen/src/BESENInt64SelfBalancedTree.pas | 632 ++ 3rd/besen/src/BESENIntegerList.pas | 230 + 3rd/besen/src/BESENKeyIDManager.pas | 120 + 3rd/besen/src/BESENLexer.pas | 1416 ++++ 3rd/besen/src/BESENLexicalEnvironment.pas | 80 + 3rd/besen/src/BESENLocale.pas | 225 + .../src/BESENNativeCodeMemoryManager.pas | 335 + 3rd/besen/src/BESENNativeObject.pas | 612 ++ 3rd/besen/src/BESENNumberUtils.pas | 4419 +++++++++++ 3rd/besen/src/BESENObject.pas | 2513 +++++++ .../src/BESENObjectArgGetterFunction.pas | 94 + .../src/BESENObjectArgSetterFunction.pas | 99 + 3rd/besen/src/BESENObjectArray.pas | 362 + 3rd/besen/src/BESENObjectArrayConstructor.pas | 123 + 3rd/besen/src/BESENObjectArrayPrototype.pas | 1330 ++++ 3rd/besen/src/BESENObjectBindingFunction.pas | 191 + 3rd/besen/src/BESENObjectBoolean.pas | 74 + .../src/BESENObjectBooleanConstructor.pas | 103 + 3rd/besen/src/BESENObjectBooleanPrototype.pas | 101 + 3rd/besen/src/BESENObjectConsole.pas | 155 + 3rd/besen/src/BESENObjectConstructor.pas | 457 ++ 3rd/besen/src/BESENObjectDate.pas | 95 + 3rd/besen/src/BESENObjectDateConstructor.pas | 231 + 3rd/besen/src/BESENObjectDatePrototype.pas | 1082 +++ 3rd/besen/src/BESENObjectDeclaredFunction.pas | 235 + .../src/BESENObjectEnvironmentRecord.pas | 168 + 3rd/besen/src/BESENObjectError.pas | 74 + 3rd/besen/src/BESENObjectErrorConstructor.pas | 108 + 3rd/besen/src/BESENObjectErrorPrototype.pas | 99 + 3rd/besen/src/BESENObjectFunction.pas | 122 + .../src/BESENObjectFunctionArguments.pas | 230 + .../src/BESENObjectFunctionConstructor.pas | 124 + .../src/BESENObjectFunctionPrototype.pas | 237 + 3rd/besen/src/BESENObjectGlobal.pas | 516 ++ 3rd/besen/src/BESENObjectJSON.pas | 439 ++ 3rd/besen/src/BESENObjectMath.pas | 524 ++ 3rd/besen/src/BESENObjectNativeFunction.pas | 102 + 3rd/besen/src/BESENObjectNumber.pas | 75 + .../src/BESENObjectNumberConstructor.pas | 130 + 3rd/besen/src/BESENObjectNumberPrototype.pas | 281 + .../src/BESENObjectPropertyDescriptor.pas | 146 + 3rd/besen/src/BESENObjectPrototype.pas | 223 + 3rd/besen/src/BESENObjectRegExp.pas | 199 + .../src/BESENObjectRegExpConstructor.pas | 188 + 3rd/besen/src/BESENObjectRegExpPrototype.pas | 228 + 3rd/besen/src/BESENObjectString.pas | 133 + .../src/BESENObjectStringConstructor.pas | 119 + 3rd/besen/src/BESENObjectStringPrototype.pas | 1108 +++ .../src/BESENObjectThrowTypeErrorFunction.pas | 74 + 3rd/besen/src/BESENOpcodes.pas | 365 + 3rd/besen/src/BESENParser.pas | 2698 +++++++ 3rd/besen/src/BESENPointerList.pas | 230 + .../src/BESENPointerSelfBalancedTree.pas | 630 ++ 3rd/besen/src/BESENRandomGenerator.pas | 274 + 3rd/besen/src/BESENRegExp.pas | 2550 +++++++ 3rd/besen/src/BESENRegExpCache.pas | 152 + 3rd/besen/src/BESENScope.pas | 83 + 3rd/besen/src/BESENSelfBalancedTree.pas | 678 ++ 3rd/besen/src/BESENShell.cfg | 38 + 3rd/besen/src/BESENShell.dof | 136 + 3rd/besen/src/BESENShell.dpr | 942 +++ 3rd/besen/src/BESENShell.dproj | 214 + 3rd/besen/src/BESENShell.lpi | 113 + 3rd/besen/src/BESENShell.lpr | 942 +++ 3rd/besen/src/BESENStringList.pas | 231 + 3rd/besen/src/BESENStringTree.pas | 356 + 3rd/besen/src/BESENStringUtils.pas | 2618 +++++++ 3rd/besen/src/BESENTypes.pas | 200 + 3rd/besen/src/BESENUnicodeTables.pas | 1274 ++++ 3rd/besen/src/BESENUtils.pas | 76 + 3rd/besen/src/BESENValue.pas | 705 ++ 3rd/besen/src/BESENValueContainer.pas | 77 + 3rd/besen/src/BESENVersionConstants.pas | 42 + mangadownloader/md.lpi | 20 +- 107 files changed, 67145 insertions(+), 10 deletions(-) create mode 100644 3rd/besen/LICENSE create mode 100644 3rd/besen/copying.besen create mode 100644 3rd/besen/copying.txt create mode 100644 3rd/besen/src/BESEN.inc create mode 100644 3rd/besen/src/BESEN.pas create mode 100644 3rd/besen/src/BESENASTNodes.pas create mode 100644 3rd/besen/src/BESENArrayUtils.pas create mode 100644 3rd/besen/src/BESENBaseObject.pas create mode 100644 3rd/besen/src/BESENCharset.pas create mode 100644 3rd/besen/src/BESENCode.pas create mode 100644 3rd/besen/src/BESENCodeContext.pas create mode 100644 3rd/besen/src/BESENCodeGeneratorContext.pas create mode 100644 3rd/besen/src/BESENCodeJIT.pas create mode 100644 3rd/besen/src/BESENCodeJITx64.pas create mode 100644 3rd/besen/src/BESENCodeJITx86.pas create mode 100644 3rd/besen/src/BESENCodeSnapshot.pas create mode 100644 3rd/besen/src/BESENCollector.pas create mode 100644 3rd/besen/src/BESENCollectorObject.pas create mode 100644 3rd/besen/src/BESENCompiler.pas create mode 100644 3rd/besen/src/BESENConstants.pas create mode 100644 3rd/besen/src/BESENContext.pas create mode 100644 3rd/besen/src/BESENDateUtils.pas create mode 100644 3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas create mode 100644 3rd/besen/src/BESENDecompiler.pas create mode 100644 3rd/besen/src/BESENDoubleList.pas create mode 100644 3rd/besen/src/BESENEnvironmentRecord.pas create mode 100644 3rd/besen/src/BESENErrors.pas create mode 100644 3rd/besen/src/BESENEvalCache.pas create mode 100644 3rd/besen/src/BESENEvalCacheItem.pas create mode 100644 3rd/besen/src/BESENGarbageCollector.pas create mode 100644 3rd/besen/src/BESENGlobals.pas create mode 100644 3rd/besen/src/BESENHashMap.pas create mode 100644 3rd/besen/src/BESENHashUtils.pas create mode 100644 3rd/besen/src/BESENInt64SelfBalancedTree.pas create mode 100644 3rd/besen/src/BESENIntegerList.pas create mode 100644 3rd/besen/src/BESENKeyIDManager.pas create mode 100644 3rd/besen/src/BESENLexer.pas create mode 100644 3rd/besen/src/BESENLexicalEnvironment.pas create mode 100644 3rd/besen/src/BESENLocale.pas create mode 100644 3rd/besen/src/BESENNativeCodeMemoryManager.pas create mode 100644 3rd/besen/src/BESENNativeObject.pas create mode 100644 3rd/besen/src/BESENNumberUtils.pas create mode 100644 3rd/besen/src/BESENObject.pas create mode 100644 3rd/besen/src/BESENObjectArgGetterFunction.pas create mode 100644 3rd/besen/src/BESENObjectArgSetterFunction.pas create mode 100644 3rd/besen/src/BESENObjectArray.pas create mode 100644 3rd/besen/src/BESENObjectArrayConstructor.pas create mode 100644 3rd/besen/src/BESENObjectArrayPrototype.pas create mode 100644 3rd/besen/src/BESENObjectBindingFunction.pas create mode 100644 3rd/besen/src/BESENObjectBoolean.pas create mode 100644 3rd/besen/src/BESENObjectBooleanConstructor.pas create mode 100644 3rd/besen/src/BESENObjectBooleanPrototype.pas create mode 100644 3rd/besen/src/BESENObjectConsole.pas create mode 100644 3rd/besen/src/BESENObjectConstructor.pas create mode 100644 3rd/besen/src/BESENObjectDate.pas create mode 100644 3rd/besen/src/BESENObjectDateConstructor.pas create mode 100644 3rd/besen/src/BESENObjectDatePrototype.pas create mode 100644 3rd/besen/src/BESENObjectDeclaredFunction.pas create mode 100644 3rd/besen/src/BESENObjectEnvironmentRecord.pas create mode 100644 3rd/besen/src/BESENObjectError.pas create mode 100644 3rd/besen/src/BESENObjectErrorConstructor.pas create mode 100644 3rd/besen/src/BESENObjectErrorPrototype.pas create mode 100644 3rd/besen/src/BESENObjectFunction.pas create mode 100644 3rd/besen/src/BESENObjectFunctionArguments.pas create mode 100644 3rd/besen/src/BESENObjectFunctionConstructor.pas create mode 100644 3rd/besen/src/BESENObjectFunctionPrototype.pas create mode 100644 3rd/besen/src/BESENObjectGlobal.pas create mode 100644 3rd/besen/src/BESENObjectJSON.pas create mode 100644 3rd/besen/src/BESENObjectMath.pas create mode 100644 3rd/besen/src/BESENObjectNativeFunction.pas create mode 100644 3rd/besen/src/BESENObjectNumber.pas create mode 100644 3rd/besen/src/BESENObjectNumberConstructor.pas create mode 100644 3rd/besen/src/BESENObjectNumberPrototype.pas create mode 100644 3rd/besen/src/BESENObjectPropertyDescriptor.pas create mode 100644 3rd/besen/src/BESENObjectPrototype.pas create mode 100644 3rd/besen/src/BESENObjectRegExp.pas create mode 100644 3rd/besen/src/BESENObjectRegExpConstructor.pas create mode 100644 3rd/besen/src/BESENObjectRegExpPrototype.pas create mode 100644 3rd/besen/src/BESENObjectString.pas create mode 100644 3rd/besen/src/BESENObjectStringConstructor.pas create mode 100644 3rd/besen/src/BESENObjectStringPrototype.pas create mode 100644 3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas create mode 100644 3rd/besen/src/BESENOpcodes.pas create mode 100644 3rd/besen/src/BESENParser.pas create mode 100644 3rd/besen/src/BESENPointerList.pas create mode 100644 3rd/besen/src/BESENPointerSelfBalancedTree.pas create mode 100644 3rd/besen/src/BESENRandomGenerator.pas create mode 100644 3rd/besen/src/BESENRegExp.pas create mode 100644 3rd/besen/src/BESENRegExpCache.pas create mode 100644 3rd/besen/src/BESENScope.pas create mode 100644 3rd/besen/src/BESENSelfBalancedTree.pas create mode 100644 3rd/besen/src/BESENShell.cfg create mode 100644 3rd/besen/src/BESENShell.dof create mode 100644 3rd/besen/src/BESENShell.dpr create mode 100644 3rd/besen/src/BESENShell.dproj create mode 100644 3rd/besen/src/BESENShell.lpi create mode 100644 3rd/besen/src/BESENShell.lpr create mode 100644 3rd/besen/src/BESENStringList.pas create mode 100644 3rd/besen/src/BESENStringTree.pas create mode 100644 3rd/besen/src/BESENStringUtils.pas create mode 100644 3rd/besen/src/BESENTypes.pas create mode 100644 3rd/besen/src/BESENUnicodeTables.pas create mode 100644 3rd/besen/src/BESENUtils.pas create mode 100644 3rd/besen/src/BESENValue.pas create mode 100644 3rd/besen/src/BESENValueContainer.pas create mode 100644 3rd/besen/src/BESENVersionConstants.pas diff --git a/3rd/besen/LICENSE b/3rd/besen/LICENSE new file mode 100644 index 000000000..40c8ae627 --- /dev/null +++ b/3rd/besen/LICENSE @@ -0,0 +1,505 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +(This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.) + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + {signature of Ty Coon}, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/3rd/besen/copying.besen b/3rd/besen/copying.besen new file mode 100644 index 000000000..1b5999b7b --- /dev/null +++ b/3rd/besen/copying.besen @@ -0,0 +1,31 @@ + +This is the file copying.besen, it applies to the BESEN ecmascript engine +library distributed by Benjamin 'BeRo' Rosseaux. + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2014, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + + + diff --git a/3rd/besen/copying.txt b/3rd/besen/copying.txt new file mode 100644 index 000000000..b1e3f5a26 --- /dev/null +++ b/3rd/besen/copying.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/3rd/besen/src/BESEN.inc b/3rd/besen/src/BESEN.inc new file mode 100644 index 000000000..3fb68545a --- /dev/null +++ b/3rd/besen/src/BESEN.inc @@ -0,0 +1,263 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +{$ifdef fpc} + {$mode delphi} + {$ifdef cpui386} + {$define cpu386} + {$endif} + {$ifdef cpu386} + {$asmmode intel} + {$endif} + {$ifdef cpuamd64} + {$asmmode intel} + {$endif} + {$ifdef FPC_LITTLE_ENDIAN} + {$define LITTLE_ENDIAN} + {$else} + {$ifdef FPC_BIG_ENDIAN} + {$define BIG_ENDIAN} + {$endif} + {$endif} + {$pic off} + {$define caninline} + {$ifdef FPC_HAS_TYPE_EXTENDED} + {$define HAS_TYPE_EXTENDED} + {$else} + {$undef HAS_TYPE_EXTENDED} + {$endif} + {$ifdef FPC_HAS_TYPE_DOUBLE} + {$define HAS_TYPE_DOUBLE} + {$else} + {$undef HAS_TYPE_DOUBLE} + {$endif} + {$ifdef FPC_HAS_TYPE_SINGLE} + {$define HAS_TYPE_SINGLE} + {$else} + {$undef HAS_TYPE_SINGLE} + {$endif} +{$else} + {$realcompatibility off} + {$localsymbols on} + {$define LITTLE_ENDIAN} + {$ifndef cpu64} + {$define cpu32} + {$endif} + {$define HAS_TYPE_EXTENDED} + {$define HAS_TYPE_DOUBLE} + {$define HAS_TYPE_SINGLE} + {$ifndef BCB} + {$ifdef ver120} + {$define Delphi4or5} + {$endif} + {$ifdef ver130} + {$define Delphi4or5} + {$endif} + {$ifdef ver140} + {$define Delphi6} + {$endif} + {$ifdef ver150} + {$define Delphi7} + {$endif} + {$ifdef ver170} + {$define Delphi2005} + {$endif} + {$else} + {$ifdef ver120} + {$define Delphi4or5} + {$define BCB4} + {$endif} + {$ifdef ver130} + {$define Delphi4or5} + {$endif} + {$endif} + {$ifdef ver180} + {$define BDS2006} + {$define Delphi2006} + {$endif} + {$ifdef ver185} + {$define Delphi2007} + {$endif} + {$ifdef ver190} + {$define Delphi2007Net} + {$endif} + {$ifdef ver200} + {$define Delphi2009} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver210} + {$define Delphi2010} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver220} + {$define DelphiXE} + {$define DelphiXEAndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver230} + {$define DelphiXE2} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver240} + {$define DelphiXE3} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver250} + {$define DelphiXE4} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver260} + {$define DelphiXE5} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver270} + {$define DelphiXE6} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver280} + {$define DelphiXE7} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define DelphiXE7AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifndef Delphi4or5} + {$ifndef BCB} + {$define Delphi6AndUp} + {$endif} + {$ifndef Delphi6} + {$define BCB6OrDelphi7AndUp} + {$ifndef BCB} + {$define Delphi7AndUp} + {$endif} + {$ifndef BCB} + {$ifndef Delphi7} + {$ifndef Delphi2005} + {$define BDS2006AndUp} + {$endif} + {$endif} + {$endif} + {$endif} + {$endif} + {$ifdef Delphi6AndUp} + {$warn symbol_platform off} + {$warn symbol_deprecated off} + {$endif} +{$endif} +{$ifdef win32} + {$define windows} +{$endif} +{$ifdef win64} + {$define windows} +{$endif} +{$ifdef wince} + {$define windows} +{$endif} +{$rangechecks off} +{$extendedsyntax on} +{$writeableconst on} +{$hints off} +{$booleval off} +{$typedaddress off} +{$stackframes off} +{$varstringchecks on} +{$typeinfo on} +{$overflowchecks off} +{$longstrings on} +{$openstrings on} +{$undef UseSafeStringEquals} +{$define strictutf8} +{$define UseOptimizedHashing} +{$define UseAssert} +{$define UseSafeOperations} +{$undef HasJIT} +{$ifdef cpu386} + {$define UseRegister} + {$define HasJIT} + {$undef UseSafeOperations} +{$endif} +{$ifdef cpuamd64} + {$define UseRegister} + {$ifndef windows} + {$define HasJIT} + {$endif} +{$endif} +{$ifdef NextGen} + {$define BESENEmbarcaderoNextGen} + {$define BESENSingleStringType} + {$define PurePascal} + {$ZeroBasedStrings off} +{$endif} +{$ifdef PurePascal} + {$define DisableJIT} + {$undef ForceJIT} +{$endif} +{$ifdef DisableJIT} + {$undef HasJIT} +{$endif} +{$ifdef ForceJIT} + {$define HasJIT} +{$endif} +{$ifdef ForceUseSafeOperations} + {$define UseSafeOperations} +{$endif} +{$ifndef HAS_TYPE_DOUBLE} + {$error No double floating point precision } +{$endif} +{$ifdef DelphiXE2AndUp} + {$ifdef MacOS} + {$define BESENDelphiHasNoSystemTimeMore} + {$endif} +{$endif} + diff --git a/3rd/besen/src/BESEN.pas b/3rd/besen/src/BESEN.pas new file mode 100644 index 000000000..25e28909e --- /dev/null +++ b/3rd/besen/src/BESEN.pas @@ -0,0 +1,1866 @@ +(******************************************************************************* + B E S E N +******************************************************************************** + Version: See at line in BESENVersionConstants.pas, which contains "BESENVersion" +-------------------------------------------------------------------------------- + + Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux <benjamin@rosseaux.com> + + Website: www.rosseaux.com + +******************************************************************************** + +BESEN is an acronym for "Bero's EcmaScript Engine", and it is a complete +ECMAScript Fifth Edition Implemention in Object Pascal, which is compilable +with Delphi >=7 and FreePascal >= 2.5.1 (maybe also 2.4.1). + +BESEN contains the following features: + +- Complete implementation of the ECMAScript Fifth Edition standard +- Own bytecode-based ECMA262-complaint Regular Expression Engine +- Incremental praise/exact mark-and-sweep garbage collector +- Unicode UTF8/UCS2/UTF16/UCS4/UTF32 support (on ECMAScript level, UCS2/UTF16) +- Compatibility modes, for example also a facile JavaScript compatibility mode +- Bytecode compiler +- Call-Subroutine-Threaded Register-based virtual machine +- Context-Threaded 32-bit x86 and 64-bit x64/AMD64 Just-in-Time Compiler +- Constant folding +- Dead code elimination +- Abstract-Syntax-Tree based optimizations +- Type inference (both exact and speculative) +- Polymorphic Inline Cache based on object structure and property key IDs +- Perfomance optimized hash maps +- Self balanced trees + +To-Do: + +- Bytecode peephole optimization +- Aggressive bytecode copy propagation (for less read/write register access) +- Optimizing bytecode opcode set, adding more specialized combined superopcodes +- Implement ARM EABI VFPv3 Just-In-time Compiler +- Regular Expression Just-In-Compiler +- Checking/testing the code +- Fix bugs :-) + +******************************************************************************** + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESEN; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,Math,SyncObjs,TypInfo,Variants,BESENVersionConstants, + BESENConstants,BESENTypes,BESENCharset,BESENStringUtils,BESENOpcodes, + BESENNativeCodeMemoryManager,BESENValueContainer,BESENObject, + BESENSelfBalancedTree,BESENGlobals,BESENErrors, + BESENPointerSelfBalancedTree,BESENInt64SelfBalancedTree, + BESENPointerList,BESENStringList,BESENIntegerList,BESENHashUtils, + BESENHashMap,BESENBaseObject,BESENCollectorObject,BESENCollector, + BESENGarbageCollector,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp,BESENCode,BESENCodeContext,BESENContext, + BESENEnvironmentRecord,BESENDeclarativeEnvironmentRecord, + BESENObjectEnvironmentRecord,BESENLexicalEnvironment, + BESENASTNodes,BESENCodeGeneratorContext,BESENParser, + BESENObjectPrototype,BESENObjectFunction, + BESENObjectConstructor,BESENObjectGlobal, + BESENObjectJSON,BESENObjectMath,BESENObjectFunctionArguments, + BESENObjectFunctionPrototype,BESENObjectFunctionConstructor, + BESENObjectDeclaredFunction,BESENObjectThrowTypeErrorFunction, + BESENObjectArgGetterFunction,BESENObjectArgSetterFunction, + BESENObjectBindingFunction,BESENObjectBoolean, + BESENObjectBooleanPrototype,BESENObjectBooleanConstructor, + BESENObjectRegExp,BESENObjectRegExpPrototype, + BESENObjectRegExpConstructor,BESENObjectDate, + BESENObjectDatePrototype,BESENObjectDateConstructor, + BESENObjectError,BESENObjectErrorPrototype, + BESENObjectErrorConstructor,BESENObjectNumber, + BESENObjectNumberPrototype,BESENObjectNumberConstructor, + BESENObjectString,BESENObjectStringPrototype, + BESENObjectStringConstructor,BESENObjectArray, + BESENObjectArrayPrototype,BESENObjectArrayConstructor, + BESENNativeObject,BESENRandomGenerator,BESENKeyIDManager, + BESENRegExpCache,BESENEvalCacheItem,BESENEvalCache, + BESENCompiler,BESENDecompiler,BESENLocale, + BESENCodeSnapshot; + +type TBESEN=class; + + TBESENTransitSecurityDomain=procedure(const Instance:TBESEN;const NewSecurityDomain:pointer) of object; + + TBESENTraceHook=function(const Instance:TBESEN;const Context:TBESENContext;const FunctionBody:TBESENASTNodeFunctionBody;PC:TBESENUINT32;const TraceType:TBESENTraceType):boolean of object; + + TBESENPeriodicHook=function(const Instance:TBESEN):boolean of object; + + TBESENRegExpDebugOutputHook=procedure(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN) of object; + + TBESEN=class + public + CriticalSection:TCriticalSection; + Collector:TBESENCollector; + GarbageCollector:TBESENGarbageCollector; + KeyIDManager:TBESENKeyIDManager; + ObjectStructureIDManager:TBESENObjectStructureIDManager; + RegExpCache:TBESENRegExpCache; + DefaultRegExp:TBESENRegExp; + EvalCache:TBESENEvalCache; + Compiler:TBESENCompiler; + Decompiler:TBESENDecompiler; + CodeSnapshot:TBESENCodeSnapshot; + NativeCodeMemoryManager:TBESENNativeCodeMemoryManager; + InlineCacheEnabled:TBESENBoolean; + ContextFirst,ContextLast:TBESENContext; + CodeFirst,CodeLast:TBESENCode; + ProgramNodes:TBESENPointerSelfBalancedTree; + IsStrict:longbool; + Compatibility:longword; + RecursionLimit:integer; + SecurityDomain:pointer; + TransitSecurityDomain:TBESENTransitSecurityDomain; + UseSecurity:TBESENBoolean; + CodeLineInfo:TBESENBoolean; + CodeTracable:TBESENBoolean; + RegExpDebug:TBESENUINT32; + RegExpTimeOutSteps:TBESENINT64; + TraceHook:TBESENTraceHook; + PeriodicHook:TBESENPeriodicHook; + RegExpDebugOutputHook:TBESENRegExpDebugOutputHook; + LineNumber:TBESENUINT32; + RandomGenerator:TBESENRandomGenerator; + RegExpMaxStatesHoldInMemory:integer; + JITLoopCompileThreshold:longword; + MaxCountOfFreeCodeContexts:integer; + MaxCountOfFreeContexts:integer; + ObjectPrototype:TBESENObjectPrototype; + ObjectConstructor:TBESENObjectConstructor; + ObjectFunctionPrototype:TBESENObjectFunctionPrototype; + ObjectFunctionConstructor:TBESENObjectFunctionConstructor; + ObjectBooleanPrototype:TBESENObjectBooleanPrototype; + ObjectBooleanConstructor:TBESENObjectBooleanConstructor; + ObjectRegExpPrototype:TBESENObjectRegExpPrototype; + ObjectRegExpConstructor:TBESENObjectRegExpConstructor; + ObjectDatePrototype:TBESENObjectDatePrototype; + ObjectDateConstructor:TBESENObjectDateConstructor; + ObjectErrorPrototype:TBESENObjectErrorPrototype; + ObjectEvalErrorPrototype:TBESENObjectErrorPrototype; + ObjectRangeErrorPrototype:TBESENObjectErrorPrototype; + ObjectReferenceErrorPrototype:TBESENObjectErrorPrototype; + ObjectSyntaxErrorPrototype:TBESENObjectErrorPrototype; + ObjectTypeErrorPrototype:TBESENObjectErrorPrototype; + ObjectURIErrorPrototype:TBESENObjectErrorPrototype; + ObjectErrorConstructor:TBESENObjectErrorConstructor; + ObjectEvalErrorConstructor:TBESENObjectErrorConstructor; + ObjectRangeErrorConstructor:TBESENObjectErrorConstructor; + ObjectReferenceErrorConstructor:TBESENObjectErrorConstructor; + ObjectSyntaxErrorConstructor:TBESENObjectErrorConstructor; + ObjectTypeErrorConstructor:TBESENObjectErrorConstructor; + ObjectURIErrorConstructor:TBESENObjectErrorConstructor; + ObjectNumberConstructor:TBESENObjectNumberConstructor; + ObjectNumberPrototype:TBESENObjectNumberPrototype; + ObjectStringPrototype:TBESENObjectStringPrototype; + ObjectStringConstructor:TBESENObjectStringConstructor; + ObjectArrayPrototype:TBESENObjectArrayPrototype; + ObjectArrayConstructor:TBESENObjectArrayConstructor; + ObjectJSON:TBESENObjectJSON; + ObjectMath:TBESENObjectMath; + ObjectEmpty:TBESENObject; + ObjectThrowTypeErrorFunction:TBESENObjectThrowTypeErrorFunction; + ObjectGlobal:TBESENObjectGlobal; + ObjectGlobalEval:TBESENObjectFunction; + GlobalLexicalEnvironment:TBESENLexicalEnvironment; + ObjectNumberConstructorValue:TBESENValue; + ObjectStringConstructorValue:TBESENValue; + constructor Create(ACompatibility:longword=0); overload; + destructor Destroy; override; + procedure Lock; + procedure Unlock; + procedure LockObject(Obj:TBESENGarbageCollectorObject); + procedure UnlockObject(Obj:TBESENGarbageCollectorObject); + procedure LockValue(const Value:TBESENValue); + procedure UnlockValue(const Value:TBESENValue); + function GetRandom:longword; + procedure RegisterNativeObject(const AName:TBESENString;const AClass:TBESENNativeObjectClass;const Attributes:TBESENObjectPropertyDescriptorAttributes=[bopaWRITABLE,bopaCONFIGURABLE]); + procedure FunctionCall(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); + procedure FunctionConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); + function MakeError(const Name:TBESENString;var ConstructorObject:TBESENObjectErrorConstructor;const ProtoProto:TBESENObject):TBESENObjectErrorPrototype; + function LoadFromStream(const Stream:TStream):TBESENASTNode; + procedure SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); + function Compile(InputSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const Parameters:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; + function Decompile(RootNode:TBESENASTNode):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; + function ObjectInstanceOf(const v:TBESENValue;Obj:TBESENObject):boolean; + function MakeFunction(Node:TBESENASTNodeFunctionLiteral;Name:TBESENString;ParentLexicalEnvironment:TBESENLexicalEnvironment=nil):TBESENObjectDeclaredFunction; + function Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; overload; + function Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; overload; + function Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; + function Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; + function JSONEval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; + function JSONStringify(const Value:TBESENValue):TBESENValue; overload; + function JSONStringify(const Value,Replacer:TBESENValue):TBESENValue; overload; + function JSONStringify(const Value,Replacer,Space:TBESENValue):TBESENValue; overload; + procedure InjectObject(Name,Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); + function NewDeclarativeEnvironment(const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; + function NewObjectEnvironment(const BindingObject:TBESENObject;const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; + function ParseNumber(const s:TBESENString):TBESENNumber; + procedure ToPrimitiveValue(const AValue,AType:TBESENValue;var AResult:TBESENValue); overload; + procedure ToPrimitiveValue(const AValue:TBESENValue;var AResult:TBESENValue); overload; + procedure ToBooleanValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToNumberValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToIntegerValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToStringValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToObjectValue(const AValue:TBESENValue;var AResult:TBESENValue); + function ToInt(const AValue:TBESENValue):int64; + function ToInt32(const AValue:TBESENValue):TBESENINT32; + function ToUInt32(const AValue:TBESENValue):TBESENUINT32; + function ToInt16(const AValue:TBESENValue):TBESENINT16; + function ToUInt16(const AValue:TBESENValue):TBESENUINT16; + function ToBool(const AValue:TBESENValue):TBESENBoolean; + function ToNum(const AValue:TBESENValue):TBESENNumber; + function ToStr(const AValue:TBESENValue):TBESENString; + function ToObj(const AValue:TBESENValue):TBESENObject; + procedure EqualityExpressionSub(const a,b:TBESENValue;var AResult:TBESENValue); + function EqualityExpressionEquals(const a,b:TBESENValue):boolean; + function EqualityExpressionCompare(const a,b:TBESENValue):integer; + procedure FromPropertyDescriptor(const Descriptor:TBESENObjectPropertyDescriptor;var AResult:TBESENValue); + procedure ToPropertyDescriptor(const v:TBESENValue;var AResult:TBESENObjectPropertyDescriptor); + function SameValue(const va,vb:TBESENValue):TBESENBoolean; overload; + function SameValue(const oa,ob:TBESENObject):TBESENBoolean; overload; + function SameObject(const oa,ob:TBESENObject):TBESENBoolean; + procedure AddProgramNode(Node:TBESENASTNodeProgram); + procedure RemoveProgramNode(Node:TBESENASTNodeProgram); + procedure GlobalEval(const Context:TBESENContext;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;const DirectCall:boolean;var AResult:TBESENValue); + procedure ObjectCallConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;Construct:boolean;var AResult:TBESENValue); + procedure ObjectCall(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + procedure ObjectConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + property PropertyCacheEnabled:TBESENBoolean read InlineCacheEnabled write InlineCacheEnabled; + end; + +implementation + +uses BESENLexer,BESENNumberUtils,BESENUtils,BESENStringTree,BESENDateUtils,BESENArrayUtils; + +constructor TBESEN.Create(ACompatibility:longword=0); +var v:TBESENValue; +begin + inherited Create; + InlineCacheEnabled:=true; + ContextFirst:=nil; + ContextLast:=nil; + CodeFirst:=nil; + CodeLast:=nil; + CriticalSection:=TCriticalSection.Create; + Collector:=TBESENCollector.Create(self); + GarbageCollector:=TBESENGarbageCollector.Create(self); + KeyIDManager:=TBESENKeyIDManager.Create(self); + ObjectStructureIDManager:=TBESENObjectStructureIDManager.Create(self); + Compiler:=TBESENCompiler.Create(self); + Decompiler:=TBESENDecompiler.Create(self); + CodeSnapshot:=TBESENCodeSnapshot.Create(self); + NativeCodeMemoryManager:=TBESENNativeCodeMemoryManager.Create; + ProgramNodes:=TBESENPointerSelfBalancedTree.Create; + IsStrict:=false; + Compatibility:=ACompatibility; + RecursionLimit:=-1; + SecurityDomain:=nil; + TransitSecurityDomain:=nil; + UseSecurity:=false; + CodeLineInfo:=true; + CodeTracable:=false; + RegExpDebug:=0; + RegExpTimeOutSteps:=0; + TraceHook:=nil; + PeriodicHook:=nil; + RegExpDebugOutputHook:=nil; + LineNumber:=0; + RandomGenerator:=TBESENRandomGenerator.Create(self); + RegExpMaxStatesHoldInMemory:=breMAXSTATESHOLDINMEMORY; + JITLoopCompileThreshold:=BESEN_JIT_LOOPCOMPILETHRESHOLD; + MaxCountOfFreeCodeContexts:=BESENMaxCountOfFreeCodeContexts; + MaxCountOfFreeContexts:=BESENMaxCountOfFreeContexts; + + RegExpCache:=TBESENRegExpCache.Create(self); + DefaultRegExp:=TBESENRegExp.Create(selF); + + EvalCache:=TBESENEvalCache.Create(self); + + v:=BESENEmptyValue; + + ObjectPrototype:=nil; + + begin + ObjectFunctionPrototype:=TBESENObjectFunctionPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectFunctionPrototype); + ObjectFunctionPrototype.RegisterNativeFunction('toString',ObjectFunctionPrototype.NativeToString,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + ObjectFunctionPrototype.RegisterNativeFunction('apply',ObjectFunctionPrototype.NativeApply,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + ObjectFunctionPrototype.RegisterNativeFunction('call',ObjectFunctionPrototype.NativeCall,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + ObjectFunctionPrototype.RegisterNativeFunction('bind',ObjectFunctionPrototype.NativeBind,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + + ObjectPrototype:=TBESENObjectPrototype.Create(self,nil,false); + GarbageCollector.AddRoot(ObjectPrototype); + + ObjectFunctionPrototype.Prototype:=ObjectPrototype; + + ObjectFunctionConstructor:=TBESENObjectFunctionConstructor.Create(self,ObjectFunctionPrototype,true); + GarbageCollector.AddRoot(ObjectFunctionConstructor); + + ObjectFunctionPrototype.OverwriteData('constructor',BESENObjectValue(ObjectFunctionConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectBooleanPrototype:=TBESENObjectBooleanPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectBooleanPrototype); + + ObjectBooleanConstructor:=TBESENObjectBooleanConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectBooleanConstructor); + + ObjectBooleanConstructor.OverwriteData('prototype',BESENObjectValue(ObjectBooleanPrototype),[]); + + ObjectBooleanPrototype.OverwriteData('constructor',BESENObjectValue(ObjectBooleanConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectRegExpPrototype:=TBESENObjectRegExpPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectRegExpPrototype); + + ObjectRegExpConstructor:=TBESENObjectRegExpConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectRegExpConstructor); + + ObjectRegExpConstructor.OverwriteData('prototype',BESENObjectValue(ObjectRegExpPrototype),[]); + + ObjectRegExpPrototype.OverwriteData('constructor',BESENObjectValue(ObjectRegExpConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectDatePrototype:=TBESENObjectDatePrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectDatePrototype); + + ObjectDateConstructor:=TBESENObjectDateConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectDateConstructor); + + ObjectDateConstructor.OverwriteData('prototype',BESENObjectValue(ObjectDatePrototype),[]); + + ObjectDatePrototype.OverwriteData('constructor',BESENObjectValue(ObjectDateConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectErrorPrototype:=TBESENObjectErrorPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectErrorPrototype); + + ObjectErrorConstructor:=TBESENObjectErrorConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectErrorConstructor); + ObjectErrorConstructor.OverwriteData('prototype',BESENObjectValueEx(ObjectErrorPrototype),[]); + v:=BESENStringValue('Error'); + ObjectErrorConstructor.OverwriteData('name',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectErrorConstructor); + ObjectErrorPrototype.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + ObjectEvalErrorPrototype:=MakeError('EvalError',ObjectEvalErrorConstructor,ObjectErrorPrototype); + ObjectRangeErrorPrototype:=MakeError('RangeError',ObjectRangeErrorConstructor,ObjectErrorPrototype); + ObjectReferenceErrorPrototype:=MakeError('ReferenceError',ObjectReferenceErrorConstructor,ObjectErrorPrototype); + ObjectSyntaxErrorPrototype:=MakeError('SyntaxError',ObjectSyntaxErrorConstructor,ObjectErrorPrototype); + ObjectTypeErrorPrototype:=MakeError('TypeError',ObjectTypeErrorConstructor,ObjectErrorPrototype); + ObjectURIErrorPrototype:=MakeError('URIError',ObjectURIErrorConstructor,ObjectErrorPrototype); + + GarbageCollector.AddRoot(ObjectEvalErrorPrototype); + GarbageCollector.AddRoot(ObjectRangeErrorPrototype); + GarbageCollector.AddRoot(ObjectReferenceErrorPrototype); + GarbageCollector.AddRoot(ObjectSyntaxErrorPrototype); + GarbageCollector.AddRoot(ObjectTypeErrorPrototype); + GarbageCollector.AddRoot(ObjectURIErrorPrototype); + + GarbageCollector.AddRoot(ObjectEvalErrorConstructor); + GarbageCollector.AddRoot(ObjectRangeErrorConstructor); + GarbageCollector.AddRoot(ObjectReferenceErrorConstructor); + GarbageCollector.AddRoot(ObjectSyntaxErrorConstructor); + GarbageCollector.AddRoot(ObjectTypeErrorConstructor); + GarbageCollector.AddRoot(ObjectURIErrorConstructor); + end; + + begin + ObjectNumberPrototype:=TBESENObjectNumberPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectNumberPrototype); + + ObjectNumberConstructor:=TBESENObjectNumberConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectNumberConstructor); + + ObjectNumberConstructor.OverwriteData('prototype',BESENObjectValue(ObjectNumberPrototype),[]); + + ObjectNumberPrototype.OverwriteData('constructor',BESENObjectValue(ObjectNumberConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectStringPrototype:=TBESENObjectStringPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectStringPrototype); + + ObjectStringConstructor:=TBESENObjectStringConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectStringConstructor); + + ObjectStringConstructor.OverwriteData('prototype',BESENObjectValue(ObjectStringPrototype),[]); + + ObjectStringPrototype.OverwriteData('constructor',BESENObjectValue(ObjectStringConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectArrayPrototype:=TBESENObjectArrayPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectArrayPrototype); + + ObjectArrayConstructor:=TBESENObjectArrayConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectArrayConstructor); + + ObjectArrayConstructor.OverwriteData('prototype',BESENObjectValue(ObjectArrayPrototype),[]); + + ObjectArrayPrototype.OverwriteData('constructor',BESENObjectValue(ObjectArrayConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectJSON:=TBESENObjectJSON.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectJSON); + end; + + begin + ObjectMath:=TBESENObjectMath.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectMath); + end; + + begin + ObjectEmpty:=TBESENObject.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectEmpty); + end; + + begin + ObjectThrowTypeErrorFunction:=TBESENObjectThrowTypeErrorFunction.Create(self,ObjectFunctionPrototype,true); + GarbageCollector.AddRoot(ObjectThrowTypeErrorFunction); + end; + + begin + ObjectConstructor:=TBESENObjectConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectConstructor); + + ObjectConstructor.OverwriteData('prototype',BESENObjectValue(ObjectPrototype),[]); + + ObjectPrototype.OverwriteData('constructor',BESENObjectValue(ObjectConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + if (Compatibility and COMPAT_JS)<>0 then begin + ObjectGlobal:=TBESENObjectGlobal.Create(self,ObjectPrototype,true); + end else begin + ObjectGlobal:=TBESENObjectGlobal.Create(self,nil,false); + end; + GarbageCollector.AddRoot(ObjectGlobal); + + ObjectGlobal.Get('eval',v); + if v.ValueType=bvtOBJECT then begin + ObjectGlobalEval:=TBESENObjectFunction(TBESENObject(v.Obj)); + end else begin + ObjectGlobalEval:=nil; + end; + if (Compatibility and COMPAT_JS)<>0 then begin + ObjectPrototype.OverwriteData('eval',v,[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + v:=BESENObjectValue(ObjectConstructor); + ObjectGlobal.OverwriteData('Object',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectFunctionConstructor); + ObjectGlobal.OverwriteData('Function',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectBooleanConstructor); + ObjectGlobal.OverwriteData('Boolean',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectRegExpConstructor); + ObjectGlobal.OverwriteData('RegExp',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectDateConstructor); + ObjectGlobal.OverwriteData('Date',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectNumberConstructor); + ObjectGlobal.OverwriteData('Number',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectStringConstructor); + ObjectGlobal.OverwriteData('String',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectArrayConstructor); + ObjectGlobal.OverwriteData('Array',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectJSON); + ObjectGlobal.OverwriteData('JSON',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectMath); + ObjectGlobal.OverwriteData('Math',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectErrorConstructor); + ObjectGlobal.OverwriteData('Error',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectEvalErrorConstructor); + ObjectGlobal.OverwriteData('EvalError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectRangeErrorConstructor); + ObjectGlobal.OverwriteData('RangeError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectReferenceErrorConstructor); + ObjectGlobal.OverwriteData('ReferenceError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectSyntaxErrorConstructor); + ObjectGlobal.OverwriteData('SyntaxError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectTypeErrorConstructor); + ObjectGlobal.OverwriteData('TypeError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectURIErrorConstructor); + ObjectGlobal.OverwriteData('URIError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + GlobalLexicalEnvironment:=NewObjectEnvironment(ObjectGlobal,nil,false,false); + GarbageCollector.AddRoot(GlobalLexicalEnvironment); + + ObjectNumberConstructorValue:=BESENObjectValue(ObjectNumberConstructor); + ObjectStringConstructorValue:=BESENObjectValue(ObjectStringConstructor); +end; + +destructor TBESEN.Destroy; +begin + TBESENObjectEnvironmentRecord(GlobalLexicalEnvironment.EnvironmentRecord).BindingObject:=nil; + + EvalCache.Free; + + GarbageCollector.Free; + + ProgramNodes.Free; + + DefaultRegExp.Free; + + RegExpCache.Free; + + Collector.Free; + + NativeCodeMemoryManager.Free; + + CodeSnapshot.Free; + + Decompiler.Free; + + Compiler.Free; + + ObjectStructureIDManager.Free; + + KeyIDManager.Free; + + CriticalSection.Free; + + inherited Destroy; +end; + +procedure TBESEN.Lock; +begin + CriticalSection.Enter; +end; + +procedure TBESEN.Unlock; +begin + CriticalSection.Leave; +end; + +procedure TBESEN.LockObject(Obj:TBESENGarbageCollectorObject); +begin + GarbageCollector.LockObject(Obj); +end; + +procedure TBESEN.UnlockObject(Obj:TBESENGarbageCollectorObject); +begin + GarbageCollector.UnlockObject(Obj); +end; + +procedure TBESEN.LockValue(const Value:TBESENValue); +begin + GarbageCollector.LockValue(Value); +end; + +procedure TBESEN.UnlockValue(const Value:TBESENValue); +begin + GarbageCollector.UnlockValue(Value); +end; + +function TBESEN.GetRandom:longword; +begin + result:=RandomGenerator.Get; +end; + +procedure TBESEN.RegisterNativeObject(const AName:TBESENString;const AClass:TBESENNativeObjectClass;const Attributes:TBESENObjectPropertyDescriptorAttributes=[bopaWRITABLE,bopaCONFIGURABLE]); +var v:TBESENValue; +begin + v.ValueType:=bvtOBJECT; + TBESENObject(v.Obj):=AClass.Create(self,ObjectPrototype); + GarbageCollector.AddRoot(TBESENObject(v.Obj)); + ObjectGlobal.OverwriteData(AName,v,Attributes); +end; + +function TBESEN.MakeError(const Name:TBESENString;var ConstructorObject:TBESENObjectErrorConstructor;const ProtoProto:TBESENObject):TBESENObjectErrorPrototype; +var v:TBESENValue; +begin + result:=TBESENObjectErrorPrototype.Create(self,ProtoProto,false); + + ConstructorObject:=TBESENObjectErrorConstructor.Create(self,ObjectFunctionPrototype,false); + ConstructorObject.OverwriteData('prototype',BESENObjectValueEx(result),[]); + + v:=BESENEmptyValue; + v:=BESENObjectValue(ConstructorObject); + result.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENStringValue(Name); + result.OverwriteData('name',v,[bopaWRITABLE,bopaCONFIGURABLE]); + result.OverwriteData('message',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENNumberValue(1); + result.OverwriteData('length',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(result); + ConstructorObject.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); +end; + +function TBESEN.LoadFromStream(const Stream:TStream):TBESENASTNode; +begin + result:=CodeSnapshot.LoadFromStream(Stream); +end; + +procedure TBESEN.SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); +begin + CodeSnapshot.SaveToStream(Stream,RootNode); +end; + +function TBESEN.Compile(InputSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const Parameters:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; +begin + result:=Compiler.Compile(InputSource,Parameters,IsFunction,IsJSON); +end; + +function TBESEN.Decompile(RootNode:TBESENASTNode):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; +begin + result:=Decompiler.Decompile(RootNode); +end; + +function TBESEN.ObjectInstanceOf(const v:TBESENValue;Obj:TBESENObject):boolean; +var vp:TBESENValue; + o:TBESENObject; +begin + if not assigned(Obj) then begin + raise EBESENTypeError.Create('Null object'); + end; + if Obj.HasHasInstance then begin + result:=Obj.HasInstance(v); + end else if (Compatibility and COMPAT_JS)<>0 then begin + if (v.ValueType<>bvtOBJECT) or not assigned(TBESENObject(v.Obj)) then begin + result:=false; + end else begin + Obj.Get('prototype',vp); + result:=false; + if (vp.ValueType=bvtOBJECT) and assigned(vp.Obj) then begin + o:=TBESENObject(v.Obj); + while assigned(o) do begin + if o.Prototype=vp.Obj then begin + result:=true; + break; + end; + o:=o.Prototype; + end; + end; + end; + end else begin + raise EBESENTypeError.Create('No hasInstance'); + end; +end; + +procedure TBESEN.ObjectCallConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;Construct:boolean;var AResult:TBESENValue); +var OldRecursionLimit:integer; + OldSecurityDomain:pointer; +begin + if not assigned(Obj) then begin + BESENThrowTypeError('Null object'); + end; + OldRecursionLimit:=RecursionLimit; + OldSecurityDomain:=SecurityDomain; + if RecursionLimit=0 then begin + BESENThrowRecursionLimitReached; + end else if RecursionLimit>0 then begin + dec(RecursionLimit); + end; + if UseSecurity and assigned(TransitSecurityDomain) and Obj.HasGetSecurityDomain then begin + SecurityDomain:=Obj.GetSecurityDomain; + if SecurityDomain<>OldSecurityDomain then begin + TransitSecurityDomain(self,SecurityDomain); + end; + end; + try + if Construct then begin + if Obj.HasConstruct then begin + Obj.Construct(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No constructable'); + end; + end else begin + if Obj.HasCall then begin + Obj.Call(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No callable'); + end; + end; + finally + SecurityDomain:=OldSecurityDomain; + RecursionLimit:=OldRecursionLimit; + end; +end; + +procedure TBESEN.ObjectCall(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if UseSecurity or (RecursionLimit>=0) then begin + ObjectCallConstruct(Obj,ThisArgument,Arguments,CountArguments,false,AResult); + end else begin + if assigned(Obj) then begin + if Obj.HasCall then begin + Obj.Call(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No callable'); + end; + end else begin + BESENThrowTypeError('Null object'); + end; + end; +end; + +procedure TBESEN.ObjectConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if UseSecurity or (RecursionLimit>=0) then begin + ObjectCallConstruct(Obj,ThisArgument,Arguments,CountArguments,true,AResult); + end else begin + if assigned(Obj) then begin + if Obj.HasConstruct then begin + Obj.Construct(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No constructable'); + end; + end else begin + BESENThrowTypeError('Null object'); + end; + end; +end; + +procedure TBESEN.FunctionCall(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); +var pArguments:TBESENValuePointers; + i:integer; +begin + pArguments:=nil; + SetLength(pArguments,length(Arguments)); + try + for i:=0 to length(Arguments)-1 do begin + pArguments[i]:=@Arguments[i]; + end; + ObjectCallConstruct(Obj,ThisArgument,@pArguments[0],length(pArguments),false,AResult); + finally + SetLength(pArguments,0); + end; +end; + +procedure TBESEN.FunctionConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); +var pArguments:TBESENValuePointers; + i:integer; +begin + pArguments:=nil; + SetLength(pArguments,length(Arguments)); + try + for i:=0 to length(Arguments)-1 do begin + pArguments[i]:=@Arguments[i]; + end; + ObjectCallConstruct(Obj,ThisArgument,@pArguments[0],length(pArguments),true,AResult); + finally + SetLength(pArguments,0); + end; +end; + +function TBESEN.MakeFunction(Node:TBESENASTNodeFunctionLiteral;Name:TBESENString;ParentLexicalEnvironment:TBESENLexicalEnvironment=nil):TBESENObjectDeclaredFunction; +var i:integer; + Prototype:TBESENObject; + Body:TBESENASTNodeFunctionBody; +begin + if not assigned(ParentLexicalEnvironment) then begin + ParentLexicalEnvironment:=GlobalLexicalEnvironment; + end; + result:=TBESENObjectDeclaredFunction.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.Add(result); + result.GarbageCollectorLock; + try + result.SecurityDomain:=SecurityDomain; + result.Node:=Node; + result.Container:=Node.Container; + result.ObjectName:=Name; + result.LexicalEnvironment:=ParentLexicalEnvironment; + result.Extensible:=true; + + Body:=Node.Body; + SetLength(result.Parameters,length(Body.Parameters)); + for i:=0 to length(result.Parameters)-1 do begin + if assigned(Body.Parameters[i]) then begin + result.Parameters[i]:=Body.Parameters[i].Name; + end else begin + result.Parameters[i]:='param#'+inttostr(i); + end; + end; + + if (Compatibility and COMPAT_JS)<>0 then begin + result.OverwriteData('name',BESENStringValue(Name),[]); + end; + + result.OverwriteData('length',BESENNumberValue(length(result.Parameters)),[]); + + Prototype:=TBESENObject.Create(self,ObjectPrototype,false); + GarbageCollector.Add(Prototype); + + Prototype.OverwriteData('constructor',BESENObjectValue(result),[bopaWRITABLE,bopaCONFIGURABLE]); + + result.OverwriteData('prototype',BESENObjectValue(Prototype),[bopaWRITABLE]); + + if IsStrict then begin + result.OverwriteAccessor('caller',ObjectThrowTypeErrorFunction,ObjectThrowTypeErrorFunction,[],false); + result.OverwriteAccessor('arguments',ObjectThrowTypeErrorFunction,ObjectThrowTypeErrorFunction,[],false); + end else if (Compatibility and COMPAT_JS)<>0 then begin + result.OverwriteData('arguments',BESENNullValue,[]); + end; + finally + result.GarbageCollectorUnlock; + end; +end; + +procedure TBESEN.AddProgramNode(Node:TBESENASTNodeProgram); +var Value:TBESENPointerSelfBalancedTreeValue; +begin + if assigned(Node) then begin + if not ProgramNodes.Find(Node,Value) then begin + Value.p:=Node; + ProgramNodes.Insert(Node,Value); + end; + end; +end; + +procedure TBESEN.RemoveProgramNode(Node:TBESENASTNodeProgram); +begin + if assigned(Node) then begin + ProgramNodes.Remove(Node); + end; +end; + +procedure TBESEN.GlobalEval(const Context:TBESENContext;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;const DirectCall:boolean;var AResult:TBESENValue); +var Node:TBESENASTNode; + v:TBESENValue; + Lex:TBESENLexicalEnvironment; + NewContext:TBESENContext; + CacheItem:TBESENEvalCacheItem; + Source:TBESENString; + OldIsStrict:TBESENBoolean; +begin + AResult.ValueType:=bvtUNDEFINED; + v.ValueType:=bvtuNDEFINED; + if CountArguments>0 then begin + BESENCopyValue(v,Arguments^[0]^); + end; + if v.ValueType<>bvtSTRING then begin + BESENCopyValue(AResult,v); + end else begin + OldIsStrict:=IsStrict; + try + if not DirectCall then begin + IsStrict:=false; + end; + Source:=ToStr(v); + try + if (EvalCache.HashSize>0) and (length(Source)<=EvalCache.MaxSourceLength) then begin + CacheItem:=EvalCache.Get(Source,IsStrict); + end else begin + CacheItem:=nil; + end; + if assigned(CacheItem) then begin + CacheItem.IncRef; + Node:=TBESENASTNode(CacheItem.Node); + end else begin + Node:=Compile(BESENUTF16ToUTF8(Source)); + end; + finally + Source:=''; + end; + NewContext:=TBESENContext.Create(self); + try + if assigned(Node) then begin + try + if Node is TBESENASTNodeProgram then begin + AddProgramNode(TBESENASTNodeProgram(Node)); + if DirectCall then begin + NewContext.LexicalEnvironment:=Context.LexicalEnvironment; + NewContext.VariableEnvironment:=Context.VariableEnvironment; + BESENCopyValue(NewContext.ThisBinding,Context.ThisBinding); + end else begin + NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; + NewContext.VariableEnvironment:=GlobalLexicalEnvironment; + NewContext.ThisBinding.ValueType:=bvtOBJECT; + NewContext.ThisBinding.Obj:=ObjectGlobal; + end; + if IsStrict or TBESENASTNodeProgram(Node).Body.IsStrict then begin + Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,true,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + GarbageCollector.Add(Lex); + NewContext.LexicalEnvironment:=Lex; + NewContext.VariableEnvironment:=Lex; + end; + NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,true,nil,0,false); + Node.ExecuteCode(NewContext,AResult); + end; + finally + if not assigned(CacheItem) then begin + BesenFreeAndNil(Node); + end; + end; + end; + finally + if assigned(CacheItem) then begin + CacheItem.DecRef; + end; + NewContext.Free; + end; + finally + IsStrict:=OldIsStrict; + end; + end; + if (AResult.ValueType=bvtOBJECT) and assigned(AResult.Obj) then begin + TBESENObject(AResult.Obj).GarbageCollectorLock; + try + GarbageCollector.CollectAll; + finally + TBESENObject(AResult.Obj).GarbageCollectorUnlock; + end; + end else begin + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; +var Node:TBESENASTNode; + Lex:TBESENLexicalEnvironment; + NewContext:TBESENContext; +begin + result:=BESENEmptyValue; + if assigned(PrecompiledASTNode) then begin + Node:=PrecompiledASTNode; + end else begin + Node:=Compile(Source); + end; + NewContext:=TBESENContext.Create(self); + try + if assigned(Node) then begin + try + if Node is TBESENASTNodeProgram then begin + AddProgramNode(TBESENASTNodeProgram(Node)); + if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj)<>ObjectGlobal) then begin + NewContext.LexicalEnvironment:=NewObjectEnvironment(TBESENObject(ThisArgument.Obj),GlobalLexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + NewContext.VariableEnvironment:=NewDeclarativeEnvironment(GlobalLexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + BESENCopyValue(NewContext.ThisBinding,ThisArgument); + GarbageCollector.Add(NewContext.LexicalEnvironment); + GarbageCollector.Add(NewContext.VariableEnvironment); + end else begin + NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; + NewContext.VariableEnvironment:=GlobalLexicalEnvironment; + NewContext.ThisBinding.ValueType:=bvtOBJECT; + NewContext.ThisBinding.Obj:=ObjectGlobal; + end; + if IsEval and (IsStrict or TBESENASTNodeProgram(Node).Body.IsStrict) then begin + Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,true,(assigned(Node) and ((Node is TBESENASTNodeProgram) and assigned(TBESENASTNodeProgram(Node).Body) and TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval))); + GarbageCollector.Add(Lex); + NewContext.LexicalEnvironment:=Lex; + NewContext.VariableEnvironment:=Lex; + end; + NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,IsEval,nil,0,false); + Node.ExecuteCode(NewContext,result); + end; + finally + if not assigned(PrecompiledASTNode) then begin + BesenFreeAndNil(Node); + end; + end; + end; + finally + NewContext.Free; + end; + if (result.ValueType=bvtOBJECT) and assigned(result.Obj) then begin + TBESENObject(result.Obj).GarbageCollectorLock; + try + GarbageCollector.CollectAll; + finally + TBESENObject(result.Obj).GarbageCollectorUnlock; + end; + end else begin + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; +begin + BesenCopyValue(result,Execute(Source,BESENUndefinedValue,PrecompiledASTNode,IsEval)); +end; + +function TBESEN.Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; +begin + BesenCopyValue(result,Execute(Source,ThisArgument,PrecompiledASTNode,true)); +end; + +function TBESEN.Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; +begin + BesenCopyValue(result,Execute(Source,BESENUndefinedValue,PrecompiledASTNode,true)); +end; + +function TBESEN.JSONEval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; +var Node:TBESENASTNode; + Lex:TBESENLexicalEnvironment; + NewContext:TBESENContext; +begin + result:=BESENEmptyValue; + if assigned(PrecompiledASTNode) then begin + Node:=PrecompiledASTNode; + end else begin + Node:=Compile(Source,'',false,true); + end; + NewContext:=TBESENContext.Create(self); + try + if assigned(Node) then begin + try + if Node is TBESENASTNodeProgram then begin + AddProgramNode(TBESENASTNodeProgram(Node)); + NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; + NewContext.VariableEnvironment:=GlobalLexicalEnvironment; + NewContext.ThisBinding.ValueType:=bvtNULL; + Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + GarbageCollector.Add(Lex); + NewContext.LexicalEnvironment:=Lex; + NewContext.VariableEnvironment:=Lex; + NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,true,nil,0,false); + Node.ExecuteCode(NewContext,result); + end; + finally + if not assigned(PrecompiledASTNode) then begin + BesenFreeAndNil(Node); + end; + end; + end; + finally + NewContext.Free; + end; + if (result.ValueType=bvtOBJECT) and assigned(result.Obj) then begin + TBESENObject(result.Obj).GarbageCollectorLock; + try + GarbageCollector.CollectAll; + finally + TBESENObject(result.Obj).GarbageCollectorUnlock; + end; + end else begin + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.JSONStringify(const Value:TBESENValue):TBESENValue; +var Arguments:array[0..0] of TBESENValue; + ValuePointers:array[0..0] of PBESENValue; +begin + result:=BESENEmptyValue; + GarbageCollector.LockValue(Value); + try + Arguments[0]:=Value; + ValuePointers[0]:=@Arguments[0]; + ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],1,result); + finally + GarbageCollector.UnlockValue(Value); + end; +end; + +function TBESEN.JSONStringify(const Value,Replacer:TBESENValue):TBESENValue; +var Arguments:array[0..1] of TBESENValue; + ValuePointers:array[0..1] of PBESENValue; +begin + result:=BESENEmptyValue; + GarbageCollector.LockValue(Value); + GarbageCollector.LockValue(Replacer); + try + Arguments[0]:=Value; + Arguments[1]:=Replacer; + ValuePointers[0]:=@Arguments[0]; + ValuePointers[1]:=@Arguments[1]; + ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],2,result); + finally + GarbageCollector.UnlockValue(Value); + GarbageCollector.UnlockValue(Replacer); + end; +end; + +function TBESEN.JSONStringify(const Value,Replacer,Space:TBESENValue):TBESENValue; +var Arguments:array[0..2] of TBESENValue; + ValuePointers:array[0..2] of PBESENValue; +begin + result:=BESENEmptyValue; + GarbageCollector.LockValue(Value); + GarbageCollector.LockValue(Replacer); + GarbageCollector.LockValue(Space); + try + Arguments[0]:=Value; + Arguments[1]:=Replacer; + Arguments[2]:=Space; + ValuePointers[0]:=@Arguments[0]; + ValuePointers[1]:=@Arguments[1]; + ValuePointers[2]:=@Arguments[2]; + ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],3,result); + finally + GarbageCollector.UnlockValue(Value); + GarbageCollector.UnlockValue(Replacer); + GarbageCollector.UnlockValue(Space); + end; +end; + +procedure TBESEN.InjectObject(Name,Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); +var v:TBESENValue; +begin + Execute(Source); + v:=Execute(Name); + if v.ValueType=bvtOBJECT then begin + GarbageCollector.AddRoot(TBESENObject(v.Obj)); + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.NewDeclarativeEnvironment(const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; +begin + result:=TBESENLexicalEnvironment.Create(self); + result.EnvironmentRecord:=TBESENDeclarativeEnvironmentRecord.Create(self); + result.EnvironmentRecord.IsStrict:=IsItStrict; + result.EnvironmentRecord.HasMaybeDirectEval:=HasMaybeDirectEval; + result.EnvironmentRecord.UpdateImplicitThisValue; + result.Outer:=Environment; +end; + +function TBESEN.NewObjectEnvironment(const BindingObject:TBESENObject;const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; +begin + result:=TBESENLexicalEnvironment.Create(self); + result.EnvironmentRecord:=TBESENObjectEnvironmentRecord.Create(self); + result.EnvironmentRecord.IsStrict:=IsItStrict; + result.EnvironmentRecord.HasMaybeDirectEval:=HasMaybeDirectEval; + TBESENObjectEnvironmentRecord(result.EnvironmentRecord).BindingObject:=BindingObject; + result.EnvironmentRecord.UpdateImplicitThisValue; + result.Outer:=Environment; +end; + +function TBESEN.ParseNumber(const s:TBESENString):TBESENNumber; +begin + result:=BESENStringToNumber(s,true,true,true,false); +end; + +procedure TBESEN.ToPrimitiveValue(const AValue,AType:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad object'); + end; +begin + if AValue.ValueType=bvtOBJECT then begin + if assigned(AValue.Obj) then begin + TBESENObject(AValue.Obj).DefaultValue(AType,AResult); + end else begin + BESENThrowIt; + end; + end else if @AResult<>@AValue then begin + BESENCopyValue(AResult,AValue); + end; +end; + +procedure TBESEN.ToPrimitiveValue(const AValue:TBESENValue;var AResult:TBESENValue); +begin + ToPrimitiveValue(AValue,BESENUndefinedValue,AResult); +end; + +procedure TBESEN.ToBooleanValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to boolean conversation'); + end; +var bo:TBESENObject; + vo:TBESENValue; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end; + bvtNULL:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=AValue.Bool; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=BESENIsInfinite(AValue.Num) or not (BESENIsNaN(AValue.Num) or (abs(AValue.Num)=0)); + end; + bvtSTRING:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=length(AValue.Str)>0; + end; + bvtOBJECT:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=true; + if (Compatibility and COMPAT_JS)<>0 then begin + bo:=TBESENObject(AValue.Obj); + if bo is TBESENObjectBoolean then begin + vo:=BESENEmptyValue; + bo.Get('valueOf',vo); + if (vo.ValueType=bvtOBJECT) and assigned(TBESENObject(vo.Obj)) and (TBESENObject(vo.Obj).HasCall) then begin + ObjectCall(TBESENObject(vo.Obj),BESENObjectValue(bo),nil,0,AResult); + end; + end; + end; + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtBOOLEAN); +{$endif} +end; + +procedure TBESEN.ToNumberValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to number conversation'); + end; +const BooleanToNumber:array[boolean] of TBESENNumber=(0.0,1.0); +var v:TBESENValue; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + AResult.ValueType:=bvtNUMBER; + int64(pointer(@AResult.Num)^):=int64(pointer(@BESENDoubleNAN)^); + end; + bvtNULL:begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=0; + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=BooleanToNumber[boolean(AValue.Bool)]; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtNUMBER; + int64(pointer(@AResult.Num)^):=int64(pointer(@AValue.Num)^); + end; + bvtSTRING:begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=ParseNumber(AValue.Str); + end; + bvtOBJECT:begin + ToPrimitiveValue(AValue,ObjectNumberConstructorValue,v); + ToNumberValue(v,AResult); + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtNUMBER); +{$endif} +end; + +procedure TBESEN.ToIntegerValue(const AValue:TBESENValue;var AResult:TBESENValue); +var Sign:longword; +begin + ToNumberValue(AValue,AResult); + if BESENIsNaN(AResult.Num) then begin + AResult.Num:=0.0; + end else if not (BESENIsInfinite(AResult.Num) or BESENIsZero(AResult.Num)) then begin + Sign:=PBESENDoubleHiLo(@AResult.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@AResult.Num)^.Hi:=PBESENDoubleHiLo(@AResult.Num)^.Hi and $7fffffff; + AResult.Num:=BESENFloor(AResult.Num); + PBESENDoubleHiLo(@AResult.Num)^.Hi:=PBESENDoubleHiLo(@AResult.Num)^.Hi or Sign; + end; +end; + +procedure TBESEN.ToStringValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to string conversation'); + end; +var v:TBESENValue; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:='undefined'; + end; + bvtNULL:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:='null'; + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtSTRING; + if AValue.Bool then begin + AResult.Str:='true'; + end else begin + AResult.Str:='false'; + end; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:=BESENFloatToStr(AValue.Num); + end; + bvtSTRING:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:=AValue.Str; + end; + bvtOBJECT:begin + ToPrimitiveValue(AValue,ObjectStringConstructorValue,v); + ToStringValue(v,AResult); + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtSTRING); +{$endif} +end; + +procedure TBESEN.ToObjectValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to object conversation'); + end; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + raise EBESENTypeError.Create('ToObjectValue undefined'); + end; + bvtNULL:begin + raise EBESENTypeError.Create('ToObjectValue null'); + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObjectBoolean.Create(self,ObjectBooleanPrototype,false); + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObjectBoolean(AResult.Obj).Value:=AValue.Bool; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObjectNumber.Create(self,ObjectNumberPrototype,false); + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObjectNumber(AResult.Obj).Value:=AValue.Num; + end; + bvtSTRING:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObjectString.Create(self,ObjectStringPrototype,false); + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObjectString(AResult.Obj).Value:=AValue.Str; + TBESENObjectString(AResult.Obj).UpdateLength; + end; + bvtOBJECT:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=AValue.Obj; + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtOBJECT); +{$endif} +end; + +function TBESEN.ToInt(const AValue:TBESENValue):int64; +var v:TBESENValue; +begin + ToIntegerValue(AValue,v); + result:=trunc(v.Num); +end; + +function TBESEN.ToInt32(const AValue:TBESENValue):TBESENINT32; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),4294967296.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+4294967296.0; + end; + if v.Num>=2147483648.0 then begin + v.Num:=v.Num-4294967296.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToUInt32(const AValue:TBESENValue):TBESENUINT32; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),4294967296.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+4294967296.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToInt16(const AValue:TBESENValue):TBESENINT16; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),65536.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+65536.0; + end; + if v.Num>=32768.0 then begin + v.Num:=v.Num-65536.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToUInt16(const AValue:TBESENValue):TBESENUINT16; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),65536.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+65536.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToBool(const AValue:TBESENValue):TBESENBoolean; +var b:TBESENValue; +begin + ToBooleanValue(AValue,b); + result:=b.Bool; +end; + +function TBESEN.ToNum(const AValue:TBESENValue):TBESENNumber; +var n:TBESENValue; +begin + ToNumberValue(AValue,n); + result:=n.Num; +end; + +function TBESEN.ToStr(const AValue:TBESENValue):TBESENString; +var s:TBESENValue; +begin + ToStringValue(AValue,s); + result:=s.Str; +end; + +function TBESEN.ToObj(const AValue:TBESENValue):TBESENObject; +var o:TBESENValue; +begin + ToObjectValue(AValue,o); + result:=TBESENObject(o.Obj); +end; + +procedure TBESEN.EqualityExpressionSub(const a,b:TBESENValue;var AResult:TBESENValue); +var r1,r2:TBESENValue; + n1,n2:TBESENNumber; +begin + ToPrimitiveValue(a,ObjectNumberConstructorValue,r1); + ToPrimitiveValue(b,ObjectNumberConstructorValue,r2); + if (r1.ValueType=bvtSTRING) and (r2.ValueType=bvtSTRING) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=r1.Str<r2.Str; + end else begin + n1:=ToNum(r1); + n2:=ToNum(r2); + if BESENIsNaN(n1) or BESENIsNaN(n2) then begin + AResult.ValueType:=bvtUNDEFINED; + end else if n1=n2 then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else if BESENIsPosInfinite(n1) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else if BESENIsPosInfinite(n2) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=true; + end else if BESENIsNegInfinite(n1) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=true; + end else if BESENIsNegInfinite(n2) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=n1<n2; + end; + end; +end; + +function TBESEN.EqualityExpressionEquals(const a,b:TBESENValue):boolean; + function BooleanAgainstAllAnother:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(a,TempValue); + result:=EqualityExpressionEquals(TempValue,b); + end; + function AllAnotherAgainstBoolean:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(b,TempValue); + result:=EqualityExpressionEquals(a,TempValue); + end; + function NumberAgainstString:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(b,TempValue); + result:=EqualityExpressionEquals(a,TempValue); + end; + function StringAgainstNumber:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(a,TempValue); + result:=EqualityExpressionEquals(TempValue,b); + end; + function StringNumberAgainstObject:boolean; + var TempValue:TBESENValue; + begin + ToPrimitiveValue(b,BESENUndefinedValue,TempValue); + result:=EqualityExpressionEquals(a,TempValue); + end; + function ObjectAgainstStringNumber:boolean; + var TempValue:TBESENValue; + begin + ToPrimitiveValue(a,BESENUndefinedValue,TempValue); + result:=EqualityExpressionEquals(TempValue,b); + end; +begin + if a.ValueType=b.ValueType then begin + case a.ValueType of + bvtUNDEFINED:begin + result:=true; + end; + bvtNULL:begin + result:=true; + end; + bvtNUMBER:begin +{$ifdef UseSafeOperations} + if BESENIsNaN(a.Num) then begin + result:=false; + end else if BESENIsNaN(b.Num) then begin + result:=false; + end else begin + result:=(a.Num=b.Num) or (BESENIsZero(a.Num) and BESENIsZero(b.Num)); + end; +{$else} + result:=(not (BESENIsNaN(a.Num) or BESENIsNaN(b.Num))) and (a.Num=b.Num); +{$endif} + end; + bvtSTRING:begin + result:=a.Str=b.Str; + end; + bvtBOOLEAN:begin + result:=a.Bool=b.Bool; + end; + bvtOBJECT:begin + result:=a.Obj=b.Obj; + end; + else begin + result:=false; + end; + end; + end else begin + if (a.ValueType=bvtNULL) and (b.ValueType=bvtUNDEFINED) then begin + result:=true; + end else if (a.ValueType=bvtUNDEFINED) and (b.ValueType=bvtNULL) then begin + result:=true; + end else if (a.ValueType=bvtNUMBER) and (b.ValueType=bvtSTRING) then begin + result:=NumberAgainstString; + end else if (a.ValueType=bvtSTRING) and (b.ValueType=bvtNUMBER) then begin + result:=StringAgainstNumber; + end else if a.ValueType=bvtBOOLEAN then begin + result:=BooleanAgainstAllAnother; + end else if b.ValueType=bvtBOOLEAN then begin + result:=AllAnotherAgainstBoolean; + end else if ((a.ValueType=bvtSTRING) or (a.ValueType=bvtNUMBER)) and (b.ValueType=bvtOBJECT) then begin + result:=StringNumberAgainstObject; + end else if (a.ValueType=bvtOBJECT) and ((b.ValueType=bvtSTRING) or (b.ValueType=bvtNUMBER)) then begin + result:=ObjectAgainstStringNumber; + end else begin + result:=false; + end; + end; +end; + +function TBESEN.EqualityExpressionCompare(const a,b:TBESENValue):integer; + function DoItSafe:integer; + var v:TBESENValue; + begin + try + EqualityExpressionSub(a,b,v); + if (v.ValueType=bvtBOOLEAN) and v.Bool then begin + result:=-1; + end else begin + result:=1; + end; + except + result:=0; + end; + end; + function DoItForNumbers:integer; + var n1,n2:TBESENNumber; + begin + n1:=a.Num; + n2:=b.Num; + if BESENIsNaN(n1) or BESENIsNaN(n2) then begin + result:=1; + end else if BESENIsSameValue(n1,n2) then begin + result:=1; + end else if (BESENIsZero(n1) and BESENIsZero(n2)) and (BESENIsNegative(n1)<>BESENIsNegative(n2)) then begin + result:=1; + end else if BESENIsPosInfinite(n1) then begin + result:=1; + end else if BESENIsPosInfinite(n2) then begin + result:=-1; + end else if BESENIsNegInfinite(n1) then begin + result:=-1; + end else if BESENIsNegInfinite(n2) then begin + result:=1; + end else begin + if n1<n2 then begin + result:=-1; + end else begin + result:=1; + end; + end; + end; +begin + if EqualityExpressionEquals(a,b) then begin + result:=0; + end else begin + if (a.ValueType=bvtNUMBER) and (b.ValueType=bvtNUMBER) then begin + result:=DoItForNumbers; + end else begin + result:=DoItSafe; + end; + end; +end; + +procedure TBESEN.FromPropertyDescriptor(const Descriptor:TBESENObjectPropertyDescriptor;var AResult:TBESENValue); +var bv:TBESENValue; +begin + if Descriptor.Presents=[] then begin + AResult:=BESENUndefinedValue; + end else begin + AResult:=BESENObjectValue(TBESENObject.Create(self,ObjectPrototype)); + bv.ValueType:=bvtBOOLEAN; + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + TBESENObject(AResult.Obj).OverwriteData('value',Descriptor.Value,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + bv.Bool:=bopaWRITABLE in Descriptor.Attributes; + TBESENObject(AResult.Obj).OverwriteData('writable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if boppGETTER in Descriptor.Presents then begin + if assigned(Descriptor.Getter) then begin + TBESENObject(AResult.Obj).OverwriteData('get',BESENObjectValueEx(Descriptor.Getter),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end else begin + TBESENObject(AResult.Obj).OverwriteData('get',BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end; + end; + if boppSETTER in Descriptor.Presents then begin + if assigned(Descriptor.Setter) then begin + TBESENObject(AResult.Obj).OverwriteData('set',BESENObjectValueEx(Descriptor.Setter),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end else begin + TBESENObject(AResult.Obj).OverwriteData('set',BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end; + end; + end else begin + BESENFreeAndNil(AResult.Obj); + raise EBESENInternalError.Create('201003121938-0001'); + end; + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObject(AResult.Obj).GarbageCollectorLock; + try + bv.Bool:=bopaENUMERABLE in Descriptor.Attributes; + TBESENObject(AResult.Obj).OverwriteData('enumerable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + bv.Bool:=bopaCONFIGURABLE in Descriptor.Attributes; + TBESENObject(AResult.Obj).OverwriteData('configurable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + finally + TBESENObject(AResult.Obj).GarbageCollectorUnlock; + end; + end; +end; + +procedure TBESEN.ToPropertyDescriptor(const v:TBESENValue;var AResult:TBESENObjectPropertyDescriptor); +var t:TBESENValue; +begin + if not ((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj))) then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; + AResult:=BESENUndefinedPropertyDescriptor; + if TBESENObject(v.Obj).Get('enumerable',t) then begin + if ToBool(t) then begin + AResult.Attributes:=AResult.Attributes+[bopaENUMERABLE]; + end; + AResult.Presents:=AResult.Presents+[boppENUMERABLE]; + end; + if TBESENObject(v.Obj).Get('configurable',t) then begin + if ToBool(t) then begin + AResult.Attributes:=AResult.Attributes+[bopaCONFIGURABLE]; + end; + AResult.Presents:=AResult.Presents+[boppCONFIGURABLE]; + end; + if TBESENObject(v.Obj).Get('value',AResult.Value) then begin + AResult.Presents:=AResult.Presents+[boppVALUE]; + end; + if TBESENObject(v.Obj).Get('writable',t) then begin + if ToBool(t) then begin + AResult.Attributes:=AResult.Attributes+[bopaWRITABLE]; + end; + AResult.Presents:=AResult.Presents+[boppWRITABLE]; + end; + if TBESENObject(v.Obj).Get('get',t) then begin + if BESENIsCallable(t) then begin + AResult.Getter:=TBESENObject(t.Obj); + end else if t.ValueType<>bvtUNDEFINED then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; + AResult.Presents:=AResult.Presents+[boppGETTER]; + end; + if TBESENObject(v.Obj).Get('set',t) then begin + if BESENIsCallable(t) then begin + AResult.Setter:=TBESENObject(t.Obj); + end else if t.ValueType<>bvtUNDEFINED then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; + AResult.Presents:=AResult.Presents+[boppSETTER]; + end; + if BESENIsInconsistentDescriptor(AResult) then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; +end; + +function TBESEN.SameValue(const va,vb:TBESENValue):TBESENBoolean; +var vaNAN,vbNAN:boolean; +begin + if va.ValueType<>vb.ValueType then begin + result:=false; + end else begin + case va.ValueType of + bvtUNDEFINED:begin + result:=true; + end; + bvtNULL:begin + result:=true; + end; + bvtNUMBER:begin + vaNAN:=BESENIsNaN(va.Num); + vbNAN:=BESENIsNaN(vb.Num); + if vaNAN or vbNAN then begin + result:=vaNAN and vbNAN; + end else if (abs(va.Num)=0) and (abs(vb.Num)=0) then begin + result:=(int64(pointer(@va.Num)^) shr 63)=(int64(pointer(@vb.Num)^) shr 63); + end else begin + result:=(int64(pointer(@va.Num)^)=int64(pointer(@vb.Num)^)) or (va.Num=vb.Num); + end; + end; + bvtSTRING:begin + result:=va.Str=vb.Str; + end; + bvtBOOLEAN:begin + result:=va.Bool=vb.Bool; + end; + bvtOBJECT:begin + result:=va.Obj=vb.Obj; + end; + else begin + result:=false; + end; + end; + end; +end; + +function TBESEN.SameValue(const oa,ob:TBESENObject):TBESENBoolean; +begin + result:=oa=ob; +end; + +function TBESEN.SameObject(const oa,ob:TBESENObject):TBESENBoolean; +begin + result:=oa=ob; +end; + +procedure InitBESEN; +const BESENSignature:TBESENANSISTRING='BESEN - A ECMAScript 5th edition engine - Version '+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux - benjamin@rosseaux.com - http://www.rosseaux.com '; +begin + if length(BESENSignature)>0 then begin + BESENLengthHash:=BESENHashKey('length'); + end; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENASTNodes.pas b/3rd/besen/src/BESENASTNodes.pas new file mode 100644 index 000000000..b7ee609c1 --- /dev/null +++ b/3rd/besen/src/BESENASTNodes.pas @@ -0,0 +1,2191 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENASTNodes; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENGarbageCollector; + +const bntNONE=0; + bntEXPRESSION=1; + bntLITERAL=2; + bntIDENTIFIER=3; + bntVARIABLEDECLARATION=4; + bntVARIABLEEXPRESSION=5; + bntFUNCTIONBODY=6; + bntFUNCTIONLITERAL=7; + bntSTATEMENT=8; + bntVARIABLESTATEMENT=9; + bntFUNCTIONDECLARATION=10; + bntEXPRESSIONSTATEMENT=11; + bntEMPTYSTATEMENT=12; + bntBLOCKSTATEMENT=13; + bntDEBUGGERSTATEMENT=14; + bntBREAKSTATEMENT=15; + bntCONTINUESTATEMENT=16; + bntDOSTATEMENT=17; + bntWHILESTATEMENT=18; + bntWITHSTATEMENT=19; + bntFORSTATEMENT=20; + bntFORINSTATEMENT=21; + bntIFSTATEMENT=22; + bntLABELLEDSTATEMENT=23; + bntCASESTATEMENT=24; + bntSWITCHSTATEMENT=25; + bntTHROWSTATEMENT=26; + bntTRYSTATEMENT=27; + bntARRAYLITERAL=28; + bntBINARYEXPRESSION=29; + bntASSIGNMENTEXPRESSION=30; + bntASSIGNMENTOPERATOREXPRESSION=31; + bntASSIGNMENTMULTIPLYEXPRESSION=32; + bntASSIGNMENTDIVIDEEXPRESSION=33; + bntASSIGNMENTMODULOEXPRESSION=34; + bntASSIGNMENTPLUSEXPRESSION=35; + bntASSIGNMENTMINUSEXPRESSION=36; + bntASSIGNMENTSHIFTLEFTEXPRESSION=37; + bntASSIGNMENTSHIFTRIGHTEXPRESSION=38; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION=39; + bntASSIGNMENTBITWISEANDEXPRESSION=40; + bntASSIGNMENTBITWISEXOREXPRESSION=41; + bntASSIGNMENTBITWISEOREXPRESSION=42; + bntBINARYOPERATOREXPRESSION=43; + bntBINARYCOMMAEXPRESSION=44; + bntBINARYDIVIDEEXPRESSION=45; + bntBINARYMODULOEXPRESSION=46; + bntBINARYMULTIPLYEXPRESSION=47; + bntBINARYPLUSEXPRESSION=48; + bntBINARYMINUSEXPRESSION=49; + bntBINARYSHIFTLEFTEXPRESSION=50; + bntBINARYSHIFTRIGHTEXPRESSION=51; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION=52; + bntBINARYGREATERTHANEXPRESSION=53; + bntBINARYGREATERTHANOREQUALEXPRESSION=54; + bntBINARYLESSTHANEXPRESSION=55; + bntBINARYLESSTHANOREQUALEXPRESSION=56; + bntBINARYINSTANCEOFEXPRESSION=57; + bntBINARYINEXPRESSION=58; + bntBINARYEQUALEQUALEXPRESSION=59; + bntBINARYEQUALEQUALEQUALEXPRESSION=60; + bntBINARYNOTEQUALEXPRESSION=61; + bntBINARYNOTEQUALEQUALEXPRESSION=62; + bntBINARYBITWISEANDEXPRESSION=63; + bntBINARYBITWISEXOREXPRESSION=64; + bntBINARYBITWISEOREXPRESSION=65; + bntBOOLEANLITERAL=66; + bntCALLEXPRESSION=67; + bntNEWEXPRESSION=68; + bntCONDITIONALEXPRESSION=69; + bntUNARYEXPRESSION=70; + bntUNARYOPERATOREXPRESSION=71; + bntUNARYPLUSEXPRESSION=72; + bntUNARYMINUSEXPRESSION=73; + bntUNARYBITWISENOTEXPRESSION=74; + bntUNARYLOGICALNOTEXPRESSION=75; + bntUNARYVOIDEXPRESSION=76; + bntUNARYTYPEOFEXPRESSION=77; + bntPROPERTYEXPRESSION=78; + bntLOGICALANDEXPRESSION=79; + bntLOGICALOREXPRESSION=80; + bntDELETEEXPRESSION=81; + bntPOSTFIXINCEXPRESSION=82; + bntPOSTFIXDECEXPRESSION=83; + bntPREFIXINCEXPRESSION=84; + bntPREFIXDECEXPRESSION=85; + bntNULLLITERAL=86; + bntNUMBERLITERAL=87; + bntREGEXPLITERAL=88; + bntSTRINGLITERAL=89; + bntTHISLITERAL=90; + bntOBJECTLITERALPROPERTY=91; + bntOBJECTLITERAL=92; + bntRETURNSTATEMENT=93; + bntPROGRAM=94; + bntFUNCTIONEXPRESSION=95; + +type TBESENFunctionLiteralContainer=class; + + TBESENFunctionLiteralContainers=array of TBESENFunctionLiteralContainer; + + TBESENASTNodeFunctionLiteral=class; + + TBESENFunctionLiteralContainer=class(TBESENGarbageCollectorObject) + public + Literal:TBESENASTNodeFunctionLiteral; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + + TBESENASTNodeType=byte; + + TBESENASTNodeCodeGenData=record + RegNr:integer; + end; + + TBESENASTNode=class; + + TBESENASTNodes=array of TBESENASTNode; + + TBESENASTNode=class(TBESENCollectorObject) + public + NodeType:TBESENASTNodeType; + Target:TBESENTarget; + Location:TBESENLocation; + CodeGenData:TBESENASTNodeCodeGenData; + TrashNodes:TBESENASTNodes; + CountTrashNodes:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); virtual; + end; + + TBESENASTNodeClass=class of TBESENASTNode; + + TBESENASTNodeExpression=class(TBESENASTNode) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeExpressions=array of TBESENASTNodeExpression; + + TBESENASTNodeLiteral=class(TBESENASTNodeExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeIdentifier=class(TBESENASTNodeLiteral) + public + Name:TBESENString; + Index:integer; + ParameterIndex:integer; + ID:TBESENINT32; + IsParameter:longbool; + IsLocal:longbool; + IsReached:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeIdentifiers=array of TBESENASTNodeIdentifier; + + TBESENASTNodeVariableDeclaration=class(TBESENASTNodeExpression) + public + Identifier:TBESENASTNodeIdentifier; + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeVariableDeclarations=array of TBESENASTNodeVariableDeclaration; + + TBESENASTNodeVariableExpression=class(TBESENASTNodeExpression) + public + Declarations:TBESENASTNodeVariableDeclarations; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeStatement=class; + + TBESENASTNodeStatements=array of TBESENASTNodeStatement; + + TBESENASTNodeBlockStatement=class; + + TBESENASTNodeFunctionBody=class(TBESENASTNode) + public + Variables:TBESENASTNodeIdentifiers; + Parameters:TBESENASTNodeIdentifiers; + Functions:TBESENASTNodeStatements; + Statements:TBESENASTNodeStatements; + IsFunction:longbool; + IsEmpty:longbool; + EnableLocalsOptimization:longbool; + DisableArgumentsObject:longbool; + IsStrict:longbool; + Code:TObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; + end; + + TBESENASTNodeFunctionLiteral=class(TBESENASTNodeLiteral) + public + Name:TBESENASTNodeIdentifier; + Container:TBESENFunctionLiteralContainer; + Body:TBESENASTNodeFunctionBody; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; + end; + + TBESENASTNodeStatement=class(TBESENASTNode) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeVariableStatement=class(TBESENASTNodeStatement) + public + Declarations:TBESENASTNodeVariableDeclarations; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeFunctionDeclaration=class(TBESENASTNodeStatement) + public + Container:TBESENFunctionLiteralContainer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeFunctionExpression=class(TBESENASTNodeExpression) + public + Container:TBESENFunctionLiteralContainer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeExpressionStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeEmptyStatement=class(TBESENASTNodeStatement) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBlockStatement=class(TBESENASTNodeStatement) + public + Statements:TBESENASTNodeStatements; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeDebuggerStatement=class(TBESENASTNodeStatement) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBreakStatement=class(TBESENASTNodeStatement) + public + Identifier:TBESENASTNodeIdentifier; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeContinueStatement=class(TBESENASTNodeStatement) + public + Identifier:TBESENASTNodeIdentifier; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeDoStatement=class(TBESENASTNodeStatement) + public + Statement:TBESENASTNodeStatement; + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeWhileStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeWithStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeForStatement=class(TBESENASTNodeStatement) + public + Initial:TBESENASTNodeExpression; + Condition:TBESENASTNodeExpression; + Increment:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeForInStatement=class(TBESENASTNodeStatement) + public + Variable:TBESENASTNodeExpression; + Expression:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeIfStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + TrueStatement:TBESENASTNodeStatement; + FalseStatement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeLabelledStatement=class(TBESENASTNodeStatement) + public + Identifiers:TBESENASTNodeIdentifiers; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeCaseStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + Statements:TBESENASTNodeStatements; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeCaseStatements=array of TBESENASTNodeCaseStatement; + + TBESENASTNodeSwitchStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + CaseStatements:TBESENASTNodeCaseStatements; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeThrowStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeTryStatement=class(TBESENASTNodeStatement) + public + TryBlock:TBESENASTNodeStatement; + CatchIdentifier:TBESENASTNodeIdentifier; + CatchBlock:TBESENASTNodeStatement; + FinallyBlock:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeArrayLiteral=class(TBESENASTNodeLiteral) + public + Elements:TBESENASTNodeExpressions; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryExpression=class(TBESENASTNodeExpression) + public + LeftExpression:TBESENASTNodeExpression; + RightExpression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentOperatorExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentMultiplyExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentDivideExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentModuloExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentPlusExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentMinusExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentShiftLeftExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentShiftRightExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentShiftRightUnsignedExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentBitwiseAndExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentBitwiseXorExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentBitwiseOrExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryOperatorExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryCommaExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryDivideExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryModuloExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryMultiplyExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryPlusExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryMinusExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryShiftLeftExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryShiftRightExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryShiftRightUnsignedExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryGreaterThanExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryGreaterThanOrEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryLessThanExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryLessThanOrEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryInstanceOfExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryInExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryEqualEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryNotEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryNotEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryBitwiseAndExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryBitwiseXorExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryBitwiseOrExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBooleanLiteral=class(TBESENASTNodeLiteral) + public + Value:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeCallExpression=class(TBESENASTNodeExpression) + public + TheFunction:TBESENASTNodeExpression; + Arguments:TBESENASTNodeExpressions; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeNewExpression=class(TBESENASTNodeExpression) + public + TheFunction:TBESENASTNodeExpression; + Arguments:TBESENASTNodeExpressions; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeConditionalExpression=class(TBESENASTNodeExpression) + public + Expression:TBESENASTNodeExpression; + TrueExpression:TBESENASTNodeExpression; + FalseExpression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryExpression=class(TBESENASTNodeExpression) + public + SubExpression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryOperatorExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryPlusExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryMinusExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryBitwiseNotExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryLogicalNotExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryVoidExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryTypeOfExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePropertyExpression=class(TBESENASTNodeBinaryExpression) + public + Dot:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeLogicalAndExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeLogicalOrExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeDeleteExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePostfixIncExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePostfixDecExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePrefixIncExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePrefixDecExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeNullLiteral=class(TBESENASTNodeLiteral) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeNumberLiteral=class(TBESENASTNodeLiteral) + public + Value:double; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeRegExpLiteral=class(TBESENASTNodeLiteral) + public + Source,Flags:TBESENString; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeStringLiteral=class(TBESENASTNodeLiteral) + public + Value:TBESENString; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeThisLiteral=class(TBESENASTNodeLiteral) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeObjectLiteralPropertyType=(banolptNONE,banolptACCESSOR,banolptDATA); + + TBESENASTNodeObjectLiteralPropertyAccessorType=(banolpatNONE,banolpatGET,banolpatSET); + + TBESENASTNodeObjectLiteralProperty=class(TBESENASTNodeLiteral) + public + PropertyType:TBESENASTNodeObjectLiteralPropertyType; + PropertyAccessorType:TBESENASTNodeObjectLiteralPropertyAccessorType; + Name:TBESENString; + Value:TBESENASTNodeExpression; + Container:TBESENFunctionLiteralContainer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeObjectLiteralProperties=array of TBESENASTNodeObjectLiteralProperty; + + TBESENASTNodeObjectLiteral=class(TBESENASTNodeLiteral) + public + Properties:TBESENASTNodeObjectLiteralProperties; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeReturnStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeProgram=class(TBESENASTNode) + public + Body:TBESENASTNodeFunctionBody; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; + end; + +implementation + +uses BESEN,BESENUtils,BESENCode; + +constructor TBESENFunctionLiteralContainer.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Literal:=nil; +end; + +destructor TBESENFunctionLiteralContainer.Destroy; +begin + BESENFreeAndNil(Literal); + inherited Destroy; +end; + +procedure TBESENFunctionLiteralContainer.Finalize; +begin + if assigned(Literal) then begin + Literal.Container:=nil; + BESENFreeAndNil(Literal); + end; + inherited Finalize; +end; + +procedure TBESENFunctionLiteralContainer.Mark; +begin + inherited Mark; + if (assigned(Literal) and assigned(Literal.Body)) and assigned(Literal.Body.Code) then begin + TBESENCode(Literal.Body.Code).Mark; + end; +end; + +constructor TBESENASTNode.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNONE; + Target:=-1; + Location.LineNumber:=-1; + fillchar(CodeGenData,sizeof(TBESENASTNodeCodeGenData),#0); + TrashNodes:=nil; + CountTrashNodes:=0; +end; + +destructor TBESENASTNode.Destroy; +var i:integer; +begin + for i:=0 to CountTrashNodes-1 do begin + BESENFreeAndNil(TrashNodes[i]); + end; + SetLength(TrashNodes,0); + inherited Destroy; +end; + +procedure TBESENASTNode.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +constructor TBESENASTNodeExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntEXPRESSION; +end; + +destructor TBESENASTNodeExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLITERAL; +end; + +destructor TBESENASTNodeLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeIdentifier.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntIDENTIFIER; + Name:=''; + Index:=-1; + ParameterIndex:=-1; + ID:=-1; + IsParameter:=false; + IsLocal:=false; + IsReached:=false; +end; + +destructor TBESENASTNodeIdentifier.Destroy; +begin + Name:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeVariableDeclaration.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntVARIABLEDECLARATION; + Identifier:=nil; + Expression:=nil; +end; + +destructor TBESENASTNodeVariableDeclaration.Destroy; +begin + Identifier.Free; + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeVariableExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntVARIABLEEXPRESSION; + Declarations:=nil; +end; + +destructor TBESENASTNodeVariableExpression.Destroy; +var i:integer; +begin + for i:=0 to length(Declarations)-1 do begin + BESENFreeAndNil(Declarations[i]); + end; + SetLength(Declarations,0); + inherited Destroy; +end; + +constructor TBESENASTNodeVariableStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntVARIABLESTATEMENT; + Declarations:=nil; +end; + +destructor TBESENASTNodeVariableStatement.Destroy; +var i:integer; +begin + for i:=0 to length(Declarations)-1 do begin + BESENFreeAndNil(Declarations[i]); + end; + SetLength(Declarations,0); + inherited Destroy; +end; + +constructor TBESENASTNodeFunctionBody.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONBODY; + Variables:=nil; + Parameters:=nil; + Functions:=nil; + Statements:=nil; + IsFunction:=false; + IsEmpty:=false; + EnableLocalsOptimization:=false; + DisableArgumentsObject:=false; + IsStrict:=false; + Code:=TBESENCode.Create(Instance); + TBESENCode(Code).Body:=self; +end; + +destructor TBESENASTNodeFunctionBody.Destroy; +var i:integer; +begin +{$ifdef BESENEmbarcaderoNextGen} + Code:=nil; +{$else} + Code.Free; +{$endif} + for i:=0 to length(Parameters)-1 do begin + BESENFreeAndNil(Parameters[i]); + end; + for i:=0 to length(Functions)-1 do begin + BESENFreeAndNil(Functions[i]); + end; + for i:=0 to length(Statements)-1 do begin + BESENFreeAndNil(Statements[i]); + end; + SetLength(Parameters,0); + SetLength(Variables,0); + SetLength(Functions,0); + SetLength(Statements,0); + inherited Destroy; +end; + +procedure TBESENASTNodeFunctionBody.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + TBESENCode(Code).Execute(Context,AResult); +end; + +constructor TBESENASTNodeFunctionLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONLITERAL; + Name:=nil; + Container:=TBESENFunctionLiteralContainer.Create(Instance); + Container.Literal:=self; + Body:=TBESENASTNodeFunctionBody.Create(Instance); + Body.IsFunction:=true; + Index:=-1; +end; + +destructor TBESENASTNodeFunctionLiteral.Destroy; +begin + BESENFreeAndNil(Name); + BESENFreeAndNil(Body); + if assigned(Container) then begin + Container.Literal:=nil; + BESENFreeAndNil(Container); + end; + inherited Destroy; +end; + +procedure TBESENASTNodeFunctionLiteral.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + if assigned(Container) then begin + Container.GarbageCollectorLock; + try + Body.ExecuteCode(Context,AResult); + finally + Container.GarbageCollectorUnlock; + end; + end else begin + Body.ExecuteCode(Context,AResult); + end; +end; + +constructor TBESENASTNodeStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntSTATEMENT; +end; + +destructor TBESENASTNodeStatement.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeFunctionDeclaration.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONDECLARATION; + Container:=nil; +end; + +destructor TBESENASTNodeFunctionDeclaration.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeFunctionExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONEXPRESSION; + Container:=nil; +end; + +destructor TBESENASTNodeFunctionExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeExpressionStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntEXPRESSIONSTATEMENT; + Expression:=nil; +end; + +destructor TBESENASTNodeExpressionStatement.Destroy; +begin + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeEmptyStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntEMPTYSTATEMENT; +end; + +destructor TBESENASTNodeEmptyStatement.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBlockStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBLOCKSTATEMENT; + Statements:=nil; +end; + +destructor TBESENASTNodeBlockStatement.Destroy; +var i:integer; +begin + for i:=0 to length(Statements)-1 do begin + BESENFreeAndNil(Statements[i]); + end; + SetLength(Statements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeDebuggerStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntDEBUGGERSTATEMENT; +end; + +destructor TBESENASTNodeDebuggerStatement.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBreakStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBREAKSTATEMENT; + Identifier:=nil; +end; + +destructor TBESENASTNodeBreakStatement.Destroy; +begin + Identifier.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeContinueStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCONTINUESTATEMENT; + Identifier:=nil; +end; + +destructor TBESENASTNodeContinueStatement.Destroy; +begin + Identifier.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeDoStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntDOSTATEMENT; + Statement:=nil; + Expression:=nil; +end; + +destructor TBESENASTNodeDoStatement.Destroy; +begin + Statement.Free; + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeWhileStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntWHILESTATEMENT; + Expression:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeWhileStatement.Destroy; +begin + Expression.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeWithStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntWITHSTATEMENT; + Expression:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeWithStatement.Destroy; +begin + Expression.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeForStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFORSTATEMENT; + Initial:=nil; + Condition:=nil; + Increment:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeForStatement.Destroy; +begin + Initial.Free; + Condition.Free; + Increment.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeForInStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFORINSTATEMENT; + Variable:=nil; + Expression:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeForInStatement.Destroy; +begin + Variable.Free; + Expression.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeIfStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntIFSTATEMENT; + Expression:=nil; + TrueStatement:=nil; + FalseStatement:=nil; +end; + +destructor TBESENASTNodeIfStatement.Destroy; +begin + Expression.Free; + TrueStatement.Free; + FalseStatement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeLabelledStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLABELLEDSTATEMENT; + Identifiers:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeLabelledStatement.Destroy; +var i:integer; +begin + for i:=0 to length(Identifiers)-1 do begin + BESENFreeAndNil(Identifiers[i]); + end; + SetLength(Identifiers,0); + BESENFreeAndNil(Statement); + inherited Destroy; +end; + +constructor TBESENASTNodeCaseStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCASESTATEMENT; + Expression:=nil; + Statements:=nil; +end; + +destructor TBESENASTNodeCaseStatement.Destroy; +var i:integer; +begin + BESENFreeAndNil(Expression); + for i:=0 to length(Statements)-1 do begin + BESENFreeAndNil(Statements[i]); + end; + SetLength(Statements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeSwitchStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntSWITCHSTATEMENT; + Expression:=nil; + CaseStatements:=nil; +end; + +destructor TBESENASTNodeSwitchStatement.Destroy; +var i:integer; +begin + Expression.Free; + for i:=0 to length(CaseStatements)-1 do begin + BESENFreeAndNil(CaseStatements[i]); + end; + SetLength(CaseStatements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeThrowStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntTHROWSTATEMENT; + Expression:=nil; +end; + +destructor TBESENASTNodeThrowStatement.Destroy; +begin + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeTryStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntTRYSTATEMENT; + TryBlock:=nil; + CatchIdentifier:=nil; + CatchBlock:=nil; + FinallyBlock:=nil; +end; + +destructor TBESENASTNodeTryStatement.Destroy; +begin + TryBlock.Free; + CatchIdentifier.Free; + CatchBlock.Free; + FinallyBlock.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeArrayLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntARRAYLITERAL; + Elements:=nil; +end; + +destructor TBESENASTNodeArrayLiteral.Destroy; +var i:integer; +begin + for i:=0 to length(Elements)-1 do begin + BESENFreeAndNil(Elements[i]); + end; + SetLength(Elements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYEXPRESSION; + LeftExpression:=nil; + RightExpression:=nil; +end; + +destructor TBESENASTNodeBinaryExpression.Destroy; +begin + LeftExpression.Free; + RightExpression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentOperatorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTOPERATOREXPRESSION; +end; + +destructor TBESENASTNodeAssignmentOperatorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentMultiplyExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTMULTIPLYEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentMultiplyExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentDivideExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTDIVIDEEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentDivideExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentModuloExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTMODULOEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentModuloExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentPlusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTPLUSEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentPlusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentMinusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTMINUSEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentMinusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentShiftLeftExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTSHIFTLEFTEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentShiftLeftExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentShiftRightExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTSHIFTRIGHTEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentShiftRightExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentShiftRightUnsignedExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentShiftRightUnsignedExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentBitwiseAndExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTBITWISEANDEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentBitwiseAndExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentBitwiseXorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTBITWISEXOREXPRESSION; +end; + +destructor TBESENASTNodeAssignmentBitwiseXorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentBitwiseOrExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTBITWISEOREXPRESSION; +end; + +destructor TBESENASTNodeAssignmentBitwiseOrExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryOperatorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYOPERATOREXPRESSION; +end; + +destructor TBESENASTNodeBinaryOperatorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryCommaExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYCOMMAEXPRESSION; +end; + +destructor TBESENASTNodeBinaryCommaExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryDivideExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYDIVIDEEXPRESSION; +end; + +destructor TBESENASTNodeBinaryDivideExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryModuloExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYMODULOEXPRESSION; +end; + +destructor TBESENASTNodeBinaryModuloExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryMultiplyExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYMULTIPLYEXPRESSION; +end; + +destructor TBESENASTNodeBinaryMultiplyExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryPlusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYPLUSEXPRESSION; +end; + +destructor TBESENASTNodeBinaryPlusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryMinusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYMINUSEXPRESSION; +end; + +destructor TBESENASTNodeBinaryMinusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryShiftLeftExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYSHIFTLEFTEXPRESSION; +end; + +destructor TBESENASTNodeBinaryShiftLeftExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryShiftRightExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYSHIFTRIGHTEXPRESSION; +end; + +destructor TBESENASTNodeBinaryShiftRightExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryShiftRightUnsignedExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION; +end; + +destructor TBESENASTNodeBinaryShiftRightUnsignedExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryGreaterThanExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYGREATERTHANEXPRESSION; +end; + +destructor TBESENASTNodeBinaryGreaterThanExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryGreaterThanOrEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYGREATERTHANOREQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryGreaterThanOrEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryLessThanExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYLESSTHANEXPRESSION; +end; + +destructor TBESENASTNodeBinaryLessThanExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryLessThanOrEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYLESSTHANOREQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryLessThanOrEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryInstanceOfExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYINSTANCEOFEXPRESSION; +end; + +destructor TBESENASTNodeBinaryInstanceOfExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryInExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYINEXPRESSION; +end; + +destructor TBESENASTNodeBinaryInExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryEqualEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYEQUALEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryEqualEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryEqualEqualEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYEQUALEQUALEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryEqualEqualEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryNotEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYNOTEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryNotEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryNotEqualEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYNOTEQUALEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryNotEqualEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryBitwiseAndExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYBITWISEANDEXPRESSION; +end; + +destructor TBESENASTNodeBinaryBitwiseAndExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryBitwiseXorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYBITWISEXOREXPRESSION; +end; + +destructor TBESENASTNodeBinaryBitwiseXorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryBitwiseOrExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYBITWISEOREXPRESSION; +end; + +destructor TBESENASTNodeBinaryBitwiseOrExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBooleanLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBOOLEANLITERAL; + Value:=false; +end; + +destructor TBESENASTNodeBooleanLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeCallExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCALLEXPRESSION; + TheFunction:=nil; + Arguments:=nil; +end; + +destructor TBESENASTNodeCallExpression.Destroy; +var i:integer; +begin + TheFunction.Free; + for i:=0 to length(Arguments)-1 do begin + BESENFreeAndNil(Arguments[i]); + end; + SetLength(Arguments,0); + inherited Destroy; +end; + +constructor TBESENASTNodeNewExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNEWEXPRESSION; + TheFunction:=nil; + Arguments:=nil; +end; + +destructor TBESENASTNodeNewExpression.Destroy; +var i:integer; +begin + TheFunction.Free; + for i:=0 to length(Arguments)-1 do begin + BESENFreeAndNil(Arguments[i]); + end; + SetLength(Arguments,0); + inherited Destroy; +end; + +constructor TBESENASTNodeConditionalExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCONDITIONALEXPRESSION; + Expression:=nil; + TrueExpression:=nil; + FalseExpression:=nil; +end; + +destructor TBESENASTNodeConditionalExpression.Destroy; +begin + BESENFreeAndNil(Expression); + BESENFreeAndNil(TrueExpression); + BESENFreeAndNil(FalseExpression); + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYEXPRESSION; + SubExpression:=nil; +end; + +destructor TBESENASTNodeUnaryExpression.Destroy; +begin + SubExpression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryOperatorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYOPERATOREXPRESSION; +end; + +destructor TBESENASTNodeUnaryOperatorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryPlusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYPLUSEXPRESSION; +end; + +destructor TBESENASTNodeUnaryPlusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryMinusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYMINUSEXPRESSION; +end; + +destructor TBESENASTNodeUnaryMinusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryBitwiseNotExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYBITWISENOTEXPRESSION; +end; + +destructor TBESENASTNodeUnaryBitwiseNotExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryLogicalNotExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYLOGICALNOTEXPRESSION; +end; + +destructor TBESENASTNodeUnaryLogicalNotExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryVoidExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYVOIDEXPRESSION; +end; + +destructor TBESENASTNodeUnaryVoidExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryTypeOfExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYTYPEOFEXPRESSION; +end; + +destructor TBESENASTNodeUnaryTypeOfExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePropertyExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPROPERTYEXPRESSION; + Dot:=false; +end; + +destructor TBESENASTNodePropertyExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeLogicalAndExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLOGICALANDEXPRESSION; +end; + +destructor TBESENASTNodeLogicalAndExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeLogicalOrExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLOGICALOREXPRESSION; +end; + +destructor TBESENASTNodeLogicalOrExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeDeleteExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntDELETEEXPRESSION; +end; + +destructor TBESENASTNodeDeleteExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePostfixIncExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPOSTFIXINCEXPRESSION; +end; + +destructor TBESENASTNodePostfixIncExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePostfixDecExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPOSTFIXDECEXPRESSION; +end; + +destructor TBESENASTNodePostfixDecExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePrefixIncExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPREFIXINCEXPRESSION; +end; + +destructor TBESENASTNodePrefixIncExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePrefixDecExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPREFIXDECEXPRESSION; +end; + +destructor TBESENASTNodePrefixDecExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeNullLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNULLLITERAL; +end; + +destructor TBESENASTNodeNullLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeNumberLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNUMBERLITERAL; + Value:=0; + Index:=0; +end; + +destructor TBESENASTNodeNumberLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeRegExpLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntREGEXPLITERAL; + Source:=''; + Flags:=''; +end; + +destructor TBESENASTNodeRegExpLiteral.Destroy; +begin + Source:=''; + Flags:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeStringLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntSTRINGLITERAL; + Value:=''; +end; + +destructor TBESENASTNodeStringLiteral.Destroy; +begin + Value:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeThisLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntTHISLITERAL; +end; + +destructor TBESENASTNodeThisLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeObjectLiteralProperty.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntOBJECTLITERALPROPERTY; + PropertyType:=banolptNONE; + PropertyAccessorType:=banolpatNONE; + Name:=''; + Value:=nil; + Container:=nil; +end; + +destructor TBESENASTNodeObjectLiteralProperty.Destroy; +begin + BESENFreeAndNil(Value); + Name:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeObjectLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntOBJECTLITERAL; + Properties:=nil; +end; + +destructor TBESENASTNodeObjectLiteral.Destroy; +var i:integer; +begin + for i:=0 to length(Properties)-1 do begin + BESENFreeAndNil(Properties[i]); + end; + SetLength(Properties,0); + inherited Destroy; +end; + +constructor TBESENASTNodeReturnStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntRETURNSTATEMENT; + Expression:=nil; +end; + +destructor TBESENASTNodeReturnStatement.Destroy; +begin + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeProgram.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPROGRAM; + Body:=TBESENASTNodeFunctionBody.Create(Instance); + Body.IsFunction:=false; +end; + +destructor TBESENASTNodeProgram.Destroy; +begin + if assigned(Instance) then begin + TBESEN(Instance).RemoveProgramNode(self); + end; + BESENFreeAndNil(Body); + inherited Destroy; +end; + +procedure TBESENASTNodeProgram.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + Body.ExecuteCode(Context,AResult); +end; + +end. diff --git a/3rd/besen/src/BESENArrayUtils.pas b/3rd/besen/src/BESENArrayUtils.pas new file mode 100644 index 000000000..c8e8f1944 --- /dev/null +++ b/3rd/besen/src/BESENArrayUtils.pas @@ -0,0 +1,123 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENArrayUtils; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue; + +function BESENArrayToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; +function BESENArrayToIndexEx(AProp:TBESENString):int64; +function BESENArrayIndexToStr(v:TBESENUINT32):TBESENString; +procedure BESENArrayCheckTooLong(const a,b:TBESENUINT32); + +implementation + +uses BESEN,BESENUtils,BESENErrors; + +function BESENArrayToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; +var i:integer; +begin + if length(AProp)=0 then begin + result:=false; + end else if (length(AProp)>1) and (AProp[1]='0') then begin + result:=false; + end else begin + result:=true; + v:=0; + for i:=1 to length(AProp) do begin + if (word(widechar(AProp[i]))>=ord('0')) and (word(widechar(AProp[i]))<=ord('9')) then begin + v:=(v*10)+(word(widechar(AProp[i]))-ord('0')); + end else begin + result:=false; + break; + end; + end; + if result and ((IntToStr(v and $ffffffff)<>AProp) or (v>=$ffffffff)) then begin + result:=false; + end; + end; +end; + +function BESENArrayToIndexEx(AProp:TBESENString):int64; +var i:integer; +begin + if length(AProp)=0 then begin + result:=0; + end else if (length(AProp)>1) and (AProp[1]='0') then begin + result:=0; + end else begin + result:=0; + for i:=1 to length(AProp) do begin + if (word(widechar(AProp[i]))>=ord('0')) and (word(widechar(AProp[i]))<=ord('9')) then begin + result:=(result*10)+(word(widechar(AProp[i]))-ord('0')); + end else begin + result:=0; + break; + end; + end; + end; +end; + +function BESENArrayIndexToStr(v:TBESENUINT32):TBESENString; +var i:integer; + o:TBESENUINT32; +begin + if v=0 then begin + result:='0'; + end else begin + result:=''; + i:=0; + o:=v; + while o<>0 do begin + inc(i); + o:=o div 10; + end; + SetLength(result,i); + while (v<>0) and (i>0) do begin + result[i]:=widechar(word(v mod 10)+ord('0')); + dec(i); + v:=v div 10; + end; + end; +end; + +procedure BESENArrayCheckTooLong(const a,b:TBESENUINT32); +var c:TBESENUINT32; +begin + c:=TBESENUINT32(a+b) and $ffffffff; + if (c<a) or (c<b) then begin + BESENThrowRangeError('Array too long'); + end; +end; + +end. diff --git a/3rd/besen/src/BESENBaseObject.pas b/3rd/besen/src/BESENBaseObject.pas new file mode 100644 index 000000000..d98f92f57 --- /dev/null +++ b/3rd/besen/src/BESENBaseObject.pas @@ -0,0 +1,59 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENBaseObject; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type TBESENBaseObject=class(TObject) + public + Instance:TObject; + constructor Create(AInstance:TObject); overload; virtual; + destructor Destroy; override; + end; + +implementation + +constructor TBESENBaseObject.Create(AInstance:TObject); +begin + inherited Create; + Instance:=AInstance; +end; + +destructor TBESENBaseObject.Destroy; +begin + inherited Destroy; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENCharset.pas b/3rd/besen/src/BESENCharset.pas new file mode 100644 index 000000000..f4827ca15 --- /dev/null +++ b/3rd/besen/src/BESENCharset.pas @@ -0,0 +1,421 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCharset; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type TBESENCharBitmap=array[0..$f] of byte; + + TBESENCharset=(ISO_8859_1,ISO_8859_2,ISO_8859_3,ISO_8859_4,ISO_8859_5, + ISO_8859_6,ISO_8859_7,ISO_8859_8,ISO_8859_9,ISO_8859_10, + CP1250,CP1251,CP1252,CP1253,CP1254,CP1255,CP1256,CP1257,CP1258, + KOI8_R,UCS_2,UCS_4,UTF_32,UTF_16,UTF_8,UTF_7); + + TBESENCharsetSet=set of TBESENCharset; + + TBESENCharsetTable=array[128..255] of word; + + TBESENCharsetTableCasted=array[128..255] of widechar; + +const BESENAllCharsets:TBESENCharsetSet=[ISO_8859_1,ISO_8859_2,ISO_8859_3,ISO_8859_4, + ISO_8859_5,ISO_8859_6,ISO_8859_7,ISO_8859_8, + ISO_8859_9,ISO_8859_10,CP1250,CP1251,CP1252, + CP1253,CP1254,CP1255,CP1256,CP1257,CP1258, + KOI8_R,UCS_2,UCS_4,UTF_32,UTF_16,UTF_8,UTF_7]; + + BESENCharISO_8859_1:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, + $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, + $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, + $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, + $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, + $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, + $00D0,$00D1,$00D2,$00D3,$00D4,$00D5,$00D6,$00D7, + $00D8,$00D9,$00DA,$00DB,$00DC,$00DD,$00DE,$00DF, + $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, + $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, + $00F0,$00F1,$00F2,$00F3,$00F4,$00F5,$00F6,$00F7, + $00F8,$00F9,$00FA,$00FB,$00FC,$00FD,$00FE,$00FF); + + BESENCharISO_8859_2:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$02d8,$0141,$00a4,$013d,$015a,$00a7, + $00a8,$0160,$015e,$0164,$0179,$00ad,$017d,$017b, + $00b0,$0105,$02db,$0142,$00b4,$013e,$015b,$02c7, + $00b8,$0161,$015f,$0165,$017a,$02dd,$017e,$017c, + $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, + $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, + $0110,$0143,$0147,$00d3,$00d4,$0150,$00d6,$00d7, + $0158,$016e,$00da,$0170,$00dc,$00dd,$0162,$00df, + $0155,$00e1,$00e2,$0103,$00e4,$013a,$0107,$00e7, + $010d,$00e9,$0119,$00eb,$011b,$00ed,$00ee,$010f, + $0111,$0144,$0148,$00f3,$00f4,$0151,$00f6,$00f7, + $0159,$016f,$00fa,$0171,$00fc,$00fd,$0163,$02d9); + + BESENCharISO_8859_3:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0126,$02d8,$00a3,$00a4,$fffd,$0124,$00a7, + $00a8,$0130,$015e,$011e,$0134,$00ad,$fffd,$017b, + $00b0,$0127,$00b2,$00b3,$00b4,$00b5,$0125,$00b7, + $00b8,$0131,$015f,$011f,$0135,$00bd,$fffd,$017c, + $00c0,$00c1,$00c2,$fffd,$00c4,$010a,$0108,$00c7, + $00c8,$00c9,$00ca,$00cb,$00cc,$00cd,$00ce,$00cf, + $fffd,$00d1,$00d2,$00d3,$00d4,$0120,$00d6,$00d7, + $011c,$00d9,$00da,$00db,$00dc,$016c,$015c,$00df, + $00e0,$00e1,$00e2,$fffd,$00e4,$010b,$0109,$00e7, + $00e8,$00e9,$00ea,$00eb,$00ec,$00ed,$00ee,$00ef, + $fffd,$00f1,$00f2,$00f3,$00f4,$0121,$00f6,$00f7, + $011d,$00f9,$00fa,$00fb,$00fc,$016d,$015d,$02d9); + + BESENCharISO_8859_4:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$0138,$0156,$00a4,$0128,$013b,$00a7, + $00a8,$0160,$0112,$0122,$0166,$00ad,$017d,$00af, + $00b0,$0105,$02db,$0157,$00b4,$0129,$013c,$02c7, + $00b8,$0161,$0113,$0123,$0167,$014a,$017e,$014b, + $0100,$00c1,$00c2,$00c3,$00c4,$00c5,$00c6,$012e, + $010c,$00c9,$0118,$00cb,$0116,$00cd,$00ce,$012a, + $0110,$0145,$014c,$0136,$00d4,$00d5,$00d6,$00d7, + $00d8,$0172,$00da,$00db,$00dc,$0168,$016a,$00df, + $0101,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$012f, + $010d,$00e9,$0119,$00eb,$0117,$00ed,$00ee,$012b, + $0111,$0146,$014d,$0137,$00f4,$00f5,$00f6,$00f7, + $00f8,$0173,$00fa,$00fb,$00fc,$0169,$016b,$02d9); + + BESENCharISO_8859_5:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0401,$0402,$0403,$0404,$0405,$0406,$0407, + $0408,$0409,$040a,$040b,$040c,$00ad,$040e,$040f, + $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417, + $0418,$0419,$041a,$041b,$041c,$041d,$041e,$041f, + $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427, + $0428,$0429,$042a,$042b,$042c,$042d,$042e,$042f, + $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437, + $0438,$0439,$043a,$043b,$043c,$043d,$043e,$043f, + $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447, + $0448,$0449,$044a,$044b,$044c,$044d,$044e,$044f, + $2116,$0451,$0452,$0453,$0454,$0455,$0456,$0457, + $0458,$0459,$045a,$045b,$045c,$00a7,$045e,$045f); + + BESENCharISO_8859_6:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$fffd,$fffd,$fffd,$00a4,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$060c,$00ad,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$061b,$fffd,$fffd,$fffd,$061f, + $fffd,$0621,$0622,$0623,$0624,$0625,$0626,$0627, + $0628,$0629,$062a,$062b,$062c,$062d,$062e,$062f, + $0630,$0631,$0632,$0633,$0634,$0635,$0636,$0637, + $0638,$0639,$063a,$fffd,$fffd,$fffd,$fffd,$fffd, + $0640,$0641,$0642,$0643,$0644,$0645,$0646,$0647, + $0648,$0649,$064a,$064b,$064c,$064d,$064e,$064f, + $0650,$0651,$0652,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd); + + BESENCharISO_8859_7:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$2018,$2019,$00a3,$fffd,$fffd,$00a6,$00a7, + $00a8,$00a9,$fffd,$00ab,$00ac,$00ad,$fffd,$2015, + $00b0,$00b1,$00b2,$00b3,$0384,$0385,$0386,$00b7, + $0388,$0389,$038a,$00bb,$038c,$00bd,$038e,$038f, + $0390,$0391,$0392,$0393,$0394,$0395,$0396,$0397, + $0398,$0399,$039a,$039b,$039c,$039d,$039e,$039f, + $03a0,$03a1,$fffd,$03a3,$03a4,$03a5,$03a6,$03a7, + $03a8,$03a9,$03aa,$03ab,$03ac,$03ad,$03ae,$03af, + $03b0,$03b1,$03b2,$03b3,$03b4,$03b5,$03b6,$03b7, + $03b8,$03b9,$03ba,$03bb,$03bc,$03bd,$03be,$03bf, + $03c0,$03c1,$03c2,$03c3,$03c4,$03c5,$03c6,$03c7, + $03c8,$03c9,$03ca,$03cb,$03cc,$03cd,$03ce,$fffd); + + BESENCharISO_8859_8:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$fffd,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$00d7,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$00f7,$00bb,$00bc,$00bd,$00be,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$2017, + $05d0,$05d1,$05d2,$05d3,$05d4,$05d5,$05d6,$05d7, + $05d8,$05d9,$05da,$05db,$05dc,$05dd,$05de,$05df, + $05e0,$05e1,$05e2,$05e3,$05e4,$05e5,$05e6,$05e7, + $05e8,$05e9,$05ea,$fffd,$fffd,$200e,$200f,$fffd); + + BESENCharISO_8859_9:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$02d8,$0141,$00a4,$013d,$015a,$00a7, + $00a8,$0160,$015e,$0164,$0179,$00ad,$017d,$017b, + $00b0,$0105,$02db,$0142,$00b4,$013e,$015b,$02c7, + $00b8,$0161,$015f,$0165,$017a,$02dd,$017e,$017c, + $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, + $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, + $011e,$00d1,$00d2,$00d3,$00d4,$00d5,$00d6,$00d7, + $00d8,$00d9,$00da,$00db,$00dc,$0130,$015e,$00df, + $00e0,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$00e7, + $00e8,$00e9,$00ea,$00eb,$00ec,$00ed,$00ee,$00ef, + $011f,$00f1,$00f2,$00f3,$00f4,$00f5,$00f6,$00f7, + $00f8,$00f9,$00fa,$00fb,$00fc,$0131,$015f,$00ff); + + BESENCharISO_8859_10:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$0112,$0122,$012a,$0128,$0136,$00a7, + $013b,$0110,$0160,$0166,$017d,$00ad,$016a,$014a, + $00b0,$0105,$0113,$0123,$012b,$0129,$0137,$00b7, + $013c,$0111,$0161,$0167,$017e,$2015,$016b,$014b, + $0100,$00c1,$00c2,$00c3,$00c4,$00c5,$00c6,$012e, + $010c,$00c9,$0118,$00cb,$0116,$00cd,$00ce,$00cf, + $00d0,$0145,$014c,$00d3,$00d4,$00d5,$00d6,$0168, + $00d8,$0172,$00da,$00db,$00dc,$00dd,$00de,$00df, + $0101,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$012f, + $010d,$00e9,$0119,$00eb,$0117,$00ed,$00ee,$00ef, + $00f0,$0146,$014d,$00f3,$00f4,$00f5,$00f6,$0169, + $00f8,$0173,$00fa,$00fb,$00fc,$00fd,$00fe,$0138); + + BESENCharCP_1250:TBESENCharsetTable= + ($20ac,$fffd,$201a,$fffd,$201e,$2026,$2020,$2021, + $fffd,$2030,$0160,$2039,$015a,$0164,$017d,$0179, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$0161,$203a,$015b,$0165,$017e,$017a, + $00a0,$02c7,$02d8,$0141,$00a4,$0104,$00a6,$00a7, + $00a8,$00a9,$015e,$00ab,$00ac,$00ad,$00ae,$017b, + $00b0,$00b1,$02db,$0142,$00b4,$00b5,$00b6,$00b7, + $00b8,$0105,$015f,$00bb,$013d,$02dd,$013e,$017c, + $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, + $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, + $0110,$0143,$0147,$00d3,$00d4,$0150,$00d6,$00d7, + $0158,$016e,$00da,$0170,$00dc,$00dd,$0162,$00df, + $0155,$00e1,$00e2,$0103,$00e4,$013a,$0107,$00e7, + $010d,$00e9,$0119,$00eb,$011b,$00ed,$00ee,$010f, + $0111,$0144,$0148,$00f3,$00f4,$0151,$00f6,$00f7, + $0159,$016f,$00fa,$0171,$00fc,$00fd,$0163,$02d9); + + BESENCharCP_1251:TBESENCharsetTable= + ($0402,$0403,$201a,$0453,$201e,$2026,$2020,$2021, + $20ac,$2030,$0409,$2039,$040a,$040c,$040b,$040f, + $0452,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$0459,$203a,$045a,$045c,$045b,$045f, + $00a0,$040e,$045e,$0408,$00a4,$0490,$00a6,$00a7, + $0401,$00a9,$0404,$00ab,$00ac,$00ad,$00ae,$0407, + $00b0,$00b1,$0406,$0456,$0491,$00b5,$00b6,$00b7, + $0451,$2116,$0454,$00bb,$0458,$0405,$0455,$0457, + $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417, + $0418,$0419,$041a,$041b,$041c,$041d,$041e,$041f, + $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427, + $0428,$0429,$042a,$042b,$042c,$042d,$042e,$042f, + $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437, + $0438,$0439,$043a,$043b,$043c,$043d,$043e,$043f, + $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447, + $0448,$0449,$044a,$044b,$044c,$044d,$044e,$044f); + + BESENCharCP_1252:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$0160,$2039,$0152,$fffd,$017d,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$0161,$203a,$0153,$fffd,$017e,$0178, + $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, + $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, + $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, + $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, + $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, + $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, + $00D0,$00D1,$00D2,$00D3,$00D4,$00D5,$00D6,$00D7, + $00D8,$00D9,$00DA,$00DB,$00DC,$00DD,$00DE,$00DF, + $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, + $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, + $00F0,$00F1,$00F2,$00F3,$00F4,$00F5,$00F6,$00F7, + $00F8,$00F9,$00FA,$00FB,$00FC,$00FD,$00FE,$00FF); + + BESENCharCP_1253:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $fffd,$2030,$fffd,$2039,$fffd,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$fffd,$203a,$fffd,$fffd,$fffd,$fffd, + $00a0,$0385,$0386,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$fffd,$00ab,$00ac,$00ad,$00ae,$2015, + $00b0,$00b1,$00b2,$00b3,$0384,$00b5,$00b6,$00b7, + $0388,$0389,$038a,$00bb,$038c,$00bd,$038e,$038f, + $0390,$0391,$0392,$0393,$0394,$0395,$0396,$0397, + $0398,$0399,$039a,$039b,$039c,$039d,$039e,$039f, + $03a0,$03a1,$fffd,$03a3,$03a4,$03a5,$03a6,$03a7, + $03a8,$03a9,$03aa,$03ab,$03ac,$03ad,$03ae,$03af, + $03b0,$03b1,$03b2,$03b3,$03b4,$03b5,$03b6,$03b7, + $03b8,$03b9,$03ba,$03bb,$03bc,$03bd,$03be,$03bf, + $03c0,$03c1,$03c2,$03c3,$03c4,$03c5,$03c6,$03c7, + $03c8,$03c9,$03ca,$03cb,$03cc,$03cd,$03ce,$fffd); + + BESENCharCP_1254:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$0160,$2039,$0152,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$0161,$203a,$0153,$fffd,$fffd,$0178, + $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, + $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, + $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, + $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, + $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, + $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, + $011e,$00d1,$00d2,$00d3,$00d4,$00d5,$00d6,$00d7, + $00d8,$00d9,$00da,$00db,$00dc,$0130,$015e,$00df, + $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, + $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, + $011f,$00f1,$00f2,$00f3,$00f4,$00f5,$00f6,$00f7, + $00f8,$00f9,$00fa,$00fb,$00fc,$0131,$015f,$00ff); + + BESENCharCP_1255:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$fffd,$2039,$fffd,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$fffd,$203a,$fffd,$fffd,$fffd,$fffd, + $00a0,$00a1,$00a2,$00a3,$20aa,$00a5,$00a6,$00a7, + $00a8,$00a9,$00d7,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$00f7,$00bb,$00bc,$00bd,$00be,$00bf, + $05b0,$05b1,$05b2,$05b3,$05b4,$05b5,$05b6,$05b7, + $05b8,$05b9,$fffd,$05bb,$05bc,$05bd,$05be,$05bf, + $05c0,$05c1,$05c2,$05c3,$05f0,$05f1,$05f2,$05f3, + $05f4,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $05d0,$05d1,$05d2,$05d3,$05d4,$05d5,$05d6,$05d7, + $05d8,$05d9,$05da,$05db,$05dc,$05dd,$05de,$05df, + $05e0,$05e1,$05e2,$05e3,$05e4,$05e5,$05e6,$05e7, + $05e8,$05e9,$05ea,$fffd,$fffd,$200e,$200f,$fffd); + + BESENCharCP_1256:TBESENCharsetTable= + ($20ac,$067e,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$0679,$2039,$0152,$0686,$0698,$0688, + $06af,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $06a9,$2122,$0691,$203a,$0153,$200c,$200d,$06ba, + $00a0,$060c,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$06be,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$061b,$00bb,$00bc,$00bd,$00be,$061f, + $06c1,$0621,$0622,$0623,$0624,$0625,$0626,$0627, + $0628,$0629,$062a,$062b,$062c,$062d,$062e,$062f, + $0630,$0631,$0632,$0633,$0634,$0635,$0636,$00d7, + $0637,$0638,$0639,$063a,$0640,$0641,$0642,$0643, + $00e0,$0644,$00e2,$0645,$0646,$0647,$0648,$00e7, + $00e8,$00e9,$00ea,$00eb,$0649,$064a,$00ee,$00ef, + $064b,$064c,$064d,$064e,$00f4,$064f,$0650,$00f7, + $0651,$00f9,$0652,$00fb,$00fc,$200e,$200f,$06d2); + + BESENCharCP_1257:TBESENCharsetTable= + ($20ac,$fffd,$201a,$fffd,$201e,$2026,$2020,$2021, + $fffd,$2030,$fffd,$2039,$fffd,$00a8,$02c7,$00b8, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$fffd,$203a,$fffd,$00af,$02db,$fffd, + $00a0,$fffd,$00a2,$00a3,$00a4,$fffd,$00a6,$00a7, + $00d8,$00a9,$0156,$00ab,$00ac,$00ad,$00ae,$00c6, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00f8,$00b9,$0157,$00bb,$00bc,$00bd,$00be,$00e6, + $0104,$012e,$0100,$0106,$00c4,$00c5,$0118,$0112, + $010c,$00c9,$0179,$0116,$0122,$0136,$012a,$013b, + $0160,$0143,$0145,$00d3,$014c,$00d5,$00d6,$00d7, + $0172,$0141,$015a,$016a,$00dc,$017b,$017d,$00df, + $0105,$012f,$0101,$0107,$00e4,$00e5,$0119,$0113, + $010d,$00e9,$017a,$0117,$0123,$0137,$012b,$013c, + $0161,$0144,$0146,$00f3,$014d,$00f5,$00f6,$00f7, + $0173,$0142,$015b,$016b,$00fc,$017c,$017e,$02d9); + + BESENCharCP_1258:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$fffd,$2039,$0152,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$fffd,$203a,$0153,$fffd,$fffd,$0178, + $00a0,$00a1,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$00aa,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$00ba,$00bb,$00bc,$00bd,$00be,$00bf, + $00c0,$00c1,$00c2,$0102,$00c4,$00c5,$00c6,$00c7, + $00c8,$00c9,$00ca,$00cb,$0300,$00cd,$00ce,$00cf, + $0110,$00d1,$0309,$00d3,$00d4,$01a0,$00d6,$00d7, + $00d8,$00d9,$00da,$00db,$00dc,$01af,$0303,$00df, + $00e0,$00e1,$00e2,$0103,$00e4,$00e5,$00e6,$00e7, + $00e8,$00e9,$00ea,$00eb,$0301,$00ed,$00ee,$00ef, + $0111,$00f1,$0323,$00f3,$00f4,$01a1,$00f6,$00f7, + $00f8,$00f9,$00fa,$00fb,$00fc,$01b0,$20ab,$00ff); + + BESENCharKOI8_R:TBESENCharsetTable= + ($2500,$2502,$250c,$2510,$2514,$2518,$251c,$2524, + $252c,$2534,$253c,$2580,$2584,$2588,$258c,$2590, + $2591,$2592,$2593,$2320,$25a0,$2219,$221a,$2248, + $2264,$2265,$00a0,$2321,$00b0,$00b2,$00b7,$00f7, + $2550,$2551,$2552,$0451,$2553,$2554,$2555,$2556, + $2557,$2558,$2559,$255a,$255b,$255c,$255d,$255e, + $255f,$2560,$2561,$0401,$2562,$2563,$2564,$2565, + $2566,$2567,$2568,$2569,$256a,$256b,$256c,$00a9, + $044e,$0430,$0431,$0446,$0434,$0435,$0444,$0433, + $0445,$0438,$0439,$043a,$043b,$043c,$043d,$043e, + $043f,$044f,$0440,$0441,$0442,$0443,$0436,$0432, + $044c,$044b,$0437,$0448,$044d,$0449,$0447,$044a, + $042e,$0410,$0411,$0426,$0414,$0415,$0424,$0413, + $0425,$0418,$0419,$041a,$041b,$041c,$041d,$041e, + $041f,$042f,$0420,$0421,$0422,$0423,$0416,$0412, + $042c,$042b,$0417,$0428,$042d,$0429,$0427,$042a); + +var BESENLocaleCharset:TBESENCharset; + +implementation + +end. diff --git a/3rd/besen/src/BESENCode.pas b/3rd/besen/src/BESENCode.pas new file mode 100644 index 000000000..c233aedf3 --- /dev/null +++ b/3rd/besen/src/BESENCode.pas @@ -0,0 +1,699 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCode; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENASTNodes,BESENStringList, + BESENHashMap; + +type TBESENCodeVariable=record + Name:TBESENString; + IsParameter:longbool; + ParameterIndex:integer; + end; + + TBESENCodeVariables=array of TBESENCodeVariable; + + PBESENCodePolymorphicInlineCacheItem=^TBESENCodePolymorphicInlineCacheItem; + TBESENCodePolymorphicInlineCacheItem=record + StructureID:TBESENINT32; + Index:TBESENINT32; + ID:TBESENINT32; + NestedLevel:TBESENINT32; + end; + + TBESENCodePolymorphicInlineCacheItems=array[0..BESENPolymorphicInlineCacheSize-1] of TBESENCodePolymorphicInlineCacheItem; + + PBESENCodePolymorphicInlineCacheInstruction=^TBESENCodePolymorphicInlineCacheInstruction; + TBESENCodePolymorphicInlineCacheInstruction=record + CacheItems:TBESENCodePolymorphicInlineCacheItems; + CacheItemPositions:TBESENUINT32; + end; + + TBESENCodePolymorphicInlineCacheInstructions=array of PBESENCodePolymorphicInlineCacheInstruction; + + TBESENCode=class(TBESENBaseObject) + public + CodePrevious,CodeNext:TBESENCode; + ByteCode:TBESENUINT32s; + ByteCodeLen:integer; + NativeCode:pointer; + NativeCodeSize:ptruint; + NativeCodePCOffsets:TBESENNativeCodePCOffsets; + Body:TBESENASTNodeFunctionBody; + FunctionLiteralContainers:TBESENFunctionLiteralContainers; + Literals:TBESENValues; + Locations:TBESENLocations; + Variables:TBESENCodeVariables; + PolymorphicInlineCacheInstructions:TBESENCodePolymorphicInlineCacheInstructions; + CountFunctionLiteralContainers:integer; + CountLiterals:integer; + CountLocations:integer; + CountVariables:integer; + CountPolymorphicInlineCacheInstructions:integer; + MaxRegisters:integer; + MaxBlock:integer; + MaxParamArgs:integer; + MaxLoop:integer; + HasLocalDelete:TBESENBoolean; + IsComplexFunction:TBESENBoolean; + HasMaybeDirectEval:TBESENBoolean; + HoldLocalVariablesInRegisters:TBESENBoolean; + LastCodePos:integer; + LastOpcode:integer; + LastLine:integer; + LookupNames:TBESENStringList; + FreeCodeContexts:TObject; + CountOfFreeCodeContexts:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Mark; + procedure Finish; + procedure ResetPolymorphicInlineCacheInstructions; + function Put(v:TBESENUINT32):integer; + function Patch(Offset:integer;v:TBESENUINT32):boolean; + function GenOp(Opcode:TBESENUINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9,Operand10:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operands:array of TBESENINT32):integer; overload; + function GenLabel(Offset:TBESENUINT32):boolean; + function Here:integer; + procedure Restore(Pos:integer); + function GenLiteral(const v:TBESENValue;DestRegNr:integer):integer; + function GenFunction(const f:TBESENFunctionLiteralContainer;DestRegNr:integer):integer; + function GenLocation(const l:TBESENLocation):integer; + function GenVariable(const s:TBESENString;IsParameter:boolean;ParameterIndex:integer;const CodeGeneratorContext:TObject):integer; + function GenPolymorphicInlineCacheInstruction:integer; + function Disassemble:TBESENString; + procedure Execute(const Context:TObject;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENContext,BESENCodeContext,BESENUtils,BESENOpcodes,BESENCodeGeneratorContext; + +constructor TBESENCode.Create(AInstance:TObject); +begin + inherited Create(AInstance); + CodeNext:=nil; + if assigned(TBESEN(Instance).CodeLast) then begin + TBESEN(Instance).CodeLast.CodeNext:=self; + CodePrevious:=TBESEN(Instance).CodeLast; + TBESEN(Instance).CodeLast:=self; + end else begin + CodePrevious:=nil; + TBESEN(Instance).CodeFirst:=self; + TBESEN(Instance).CodeLast:=self; + end; + ByteCode:=nil; + ByteCodeLen:=0; + NativeCode:=nil; + NativeCodeSize:=0; + NativeCodePCOffsets:=nil; + Body:=nil; + FunctionLiteralContainers:=nil; + Literals:=nil; + Locations:=nil; + Variables:=nil; + PolymorphicInlineCacheInstructions:=nil; + CountFunctionLiteralContainers:=0; + CountLiterals:=0; + CountLocations:=0; + CountVariables:=0; + CountPolymorphicInlineCacheInstructions:=0; + MaxRegisters:=0; + MaxBlock:=0; + MaxLoop:=0; + MaxParamArgs:=0; + HasLocalDelete:=false; + IsComplexFunction:=false; + HasMaybeDirectEval:=false; + HoldLocalVariablesInRegisters:=false; + LastCodePos:=-1; + LastOpcode:=-1; + LastLine:=-1; + LookupNames:=TBESENStringList.Create; + FreeCodeContexts:=nil; + CountOfFreeCodeContexts:=0; +end; + +destructor TBESENCode.Destroy; +var i:integer; + NextCodeContext:TBESENCodeContext; +begin + while assigned(TBESENCodeContext(FreeCodeContexts)) do begin + NextCodeContext:=TBESENCodeContext(FreeCodeContexts).NextCodeContext; + TBESENCodeContext(FreeCodeContexts).NextCodeContext:=nil; + BESENFreeAndNil(FreeCodeContexts); + TBESENCodeContext(FreeCodeContexts):=NextCodeContext; + end; + BESENFreeAndNil(LookupNames); + for i:=0 to length(Literals)-1 do begin + Literals[i].Str:=''; + Literals[i].ReferenceBase.Str:=''; + Literals[i]:=BESENEmptyValue; + end; + for i:=0 to length(Variables)-1 do begin + Variables[i].Name:=''; + end; + SetLength(FunctionLiteralContainers,0); + SetLength(Literals,0); + SetLength(Locations,0); + SetLength(Variables,0); + for i:=0 to length(PolymorphicInlineCacheInstructions)-1 do begin + if assigned(PolymorphicInlineCacheInstructions[i]) then begin + Dispose(PolymorphicInlineCacheInstructions[i]); + PolymorphicInlineCacheInstructions[i]:=nil; + end; + end; + SetLength(PolymorphicInlineCacheInstructions,0); + SetLength(ByteCode,0); + SetLength(NativeCodePCOffsets,0); + if assigned(NativeCode) then begin + TBESEN(Instance).NativeCodeMemoryManager.FreeMemory(NativeCode); + NativeCode:=nil; + end; + if assigned(CodePrevious) then begin + CodePrevious.CodeNext:=CodeNext; + end else if TBESEN(Instance).CodeFirst=self then begin + TBESEN(Instance).CodeFirst:=CodeNext; + end; + if assigned(CodeNext) then begin + CodeNext.CodePrevious:=CodePrevious; + end else if TBESEN(Instance).CodeLast=self then begin + TBESEN(Instance).CodeLast:=CodePrevious; + end; + CodePrevious:=nil; + CodeNext:=nil; + inherited Destroy; +end; + +procedure TBESENCode.Mark; +var i:integer; +begin + for i:=0 to CountFunctionLiteralContainers-1 do begin + if assigned(FunctionLiteralContainers[i]) then begin + TBESEN(Instance).GarbageCollector.GrayIt(FunctionLiteralContainers[i]); + end; + end; + for i:=0 to CountLiterals-1 do begin + TBESEN(Instance).GarbageCollector.GrayValue(Literals[i]); + end; +end; + +procedure TBESENCode.Finish; +var i,j:integer; +begin + SetLength(ByteCode,ByteCodeLen); + SetLength(FunctionLiteralContainers,CountFunctionLiteralContainers); + SetLength(Literals,CountLiterals); + SetLength(Locations,CountLocations); + SetLength(Variables,CountVariables); + j:=length(PolymorphicInlineCacheInstructions); + SetLength(PolymorphicInlineCacheInstructions,CountPolymorphicInlineCacheInstructions); + for i:=j to length(PolymorphicInlineCacheInstructions)-1 do begin + PolymorphicInlineCacheInstructions[i]:=nil; + end; + for i:=0 to length(PolymorphicInlineCacheInstructions)-1 do begin + if not assigned(PolymorphicInlineCacheInstructions[i]) then begin + New(PolymorphicInlineCacheInstructions[i]); + end; + end; + ResetPolymorphicInlineCacheInstructions; +end; + +function TBESENCode.Put(v:TBESENUINT32):integer; +begin + result:=ByteCodeLen; + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4096) and not 4095); + end; + ByteCode[result]:=v; + inc(ByteCodeLen); +end; + +function TBESENCode.Patch(Offset:integer;v:TBESENUINT32):boolean; +begin + result:=Offset<=ByteCodeLen; + if result then begin + ByteCode[Offset]:=v; + end; +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32):integer; +begin + if (Opcode in [bopGC,bopSTRICTCHECKREF,bopDEBUGGER,bopCHECKOBJECTCOERCIBLE,bopTRACE]) and (TBESENUINT32(LastOpcode)=Opcode) then begin + result:=LastCodePos; + end else begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put(Opcode and $ff); + end; +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (1 shl 8)); + Put(Operand); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (2 shl 8)); + Put(Operand1); + Put(Operand2); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (3 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (4 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (5 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (6 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (7 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (8 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); + Put(Operand8); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (9 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); + Put(Operand8); + Put(Operand9); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9,Operand10:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (10 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); + Put(Operand8); + Put(Operand9); + Put(Operand10); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operands:array of TBESENINT32):integer; +var i:integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (longword(length(Operands)) shl 8)); + for i:=0 to length(Operands)-1 do begin + Put(Operands[i]); + end; +end; + +function TBESENCode.GenLabel(Offset:TBESENUINT32):boolean; +begin + result:=Patch(Offset,Here); +end; + +function TBESENCode.Here:integer; +begin + result:=ByteCodeLen; +end; + +procedure TBESENCode.Restore(Pos:integer); +begin + ByteCodeLen:=Pos; + LastCodePos:=-1; + LastOpcode:=-1; +end; + +function TBESENCode.GenLiteral(const v:TBESENValue;DestRegNr:integer):integer; +const BoolToInt:array[boolean] of longword=(0,$ffffffff); +var i:integer; + Okay:boolean; +begin + result:=-1; + for i:=0 to CountLiterals-1 do begin + if Literals[i].ValueType=v.ValueType then begin + case v.ValueType of + bvtUNDEFINED:begin + Okay:=true; + end; + bvtNULL:begin + Okay:=true; + end; + bvtBOOLEAN:begin + Okay:=Literals[i].Bool=v.Bool; + end; + bvtNUMBER:begin + Okay:=int64(pointer(@Literals[i].Num)^)=int64(pointer(@v.Num)^); + end; + bvtSTRING:begin + Okay:=Literals[i].Str=v.Str; + end; + bvtOBJECT:begin + Okay:=Literals[i].Obj=v.Obj; + end; + else begin + Okay:=false; + end; + end; + if Okay then begin + result:=i; + break; + end; + end; + end; + if result<0 then begin + result:=CountLiterals; + if CountLiterals>=length(Literals) then begin + SetLength(Literals,CountLiterals+256); + end; + Literals[result]:=v; + inc(CountLiterals); + end; + case v.ValueType of + bvtUNDEFINED:begin + GenOp(bopLITERALUNDEF,DestRegNr); + end; + bvtNULL:begin + GenOp(bopLITERALNULL,DestRegNr); + end; + bvtBOOLEAN:begin + if v.Bool then begin + GenOp(bopLITERALBOOL,DestRegNr,BoolToInt[true]); + end else begin + GenOp(bopLITERALBOOL,DestRegNr,BoolToInt[false]); + end; + end; + bvtNUMBER:begin + GenOp(bopLITERALNUM,DestRegNr,result); + end; + bvtSTRING:begin + GenOp(bopLITERALSTR,DestRegNr,result); + end; + bvtOBJECT:begin + GenOp(bopLITERALOBJ,DestRegNr,result); + end; + else begin + GenOp(bopLITERAL,DestRegNr,result); + end; + end; +end; + +function TBESENCode.GenFunction(const f:TBESENFunctionLiteralContainer;DestRegNr:integer):integer; +var i:integer; +begin + result:=-1; + for i:=0 to CountFunctionLiteralContainers-1 do begin + if FunctionLiteralContainers[i]=f then begin + result:=i; + break; + end; + end; + if result<0 then begin + result:=CountFunctionLiteralContainers; + if CountFunctionLiteralContainers>=length(FunctionLiteralContainers) then begin + SetLength(FunctionLiteralContainers,CountFunctionLiteralContainers+256); + end; + FunctionLiteralContainers[result]:=f; + inc(CountFunctionLiteralContainers); + end; + GenOp(bopFUNC,DestRegNr,result); +end; + +function TBESENCode.GenLocation(const l:TBESENLocation):integer; +var i:integer; + LastOpcodeWasLine:boolean; +begin + result:=-1; + if TBESEN(Instance).CodeLineInfo or TBESEN(Instance).CodeTracable then begin + for i:=0 to CountLocations-1 do begin + if Locations[i].LineNumber=l.LineNumber then begin + result:=i; + break; + end; + end; + if result<0 then begin + result:=CountLocations; + if CountLocations>=length(Locations) then begin + SetLength(Locations,CountLocations+256); + end; + Locations[result]:=l; + inc(CountLocations); + end; + LastOpcodeWasLine:=LastOpcode=bopLINE; + if LastLine<>result then begin + LastLine:=result; + if LastOpcodeWasLine then begin + ByteCode[LastCodePos+1]:=result; + end else begin + GenOp(bopLINE,result); + end; + end; + if TBESEN(Instance).CodeTracable and not LastOpcodeWasLine then begin + GenOp(bopTRACE); + end; + end; +end; + +function TBESENCode.GenVariable(const s:TBESENString;IsParameter:boolean;ParameterIndex:integer;const CodeGeneratorContext:TObject):integer; +var Item:PBESENHashMapItem; +begin + Item:=TBESENCodeGeneratorContext(CodeGeneratorContext).VariableNameHashMap.GetKey(s); + if assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; + if result<0 then begin + result:=CountVariables; + if CountVariables>=length(Variables) then begin + SetLength(Variables,CountVariables+256); + end; + Variables[result].Name:=s; + Variables[result].IsParameter:=IsParameter; + Variables[result].ParameterIndex:=ParameterIndex; + Item:=TBESENCodeGeneratorContext(CodeGeneratorContext).VariableNameHashMap.NewKey(s,true); + Item^.Value:=result; + inc(CountVariables); + end; +end; + +function TBESENCode.GenPolymorphicInlineCacheInstruction:integer; +begin + result:=CountPolymorphicInlineCacheInstructions; + inc(CountPolymorphicInlineCacheInstructions); +end; + +procedure TBESENCode.ResetPolymorphicInlineCacheInstructions; +var PC,OPC,Instruction:TBESENUINT32; + i,j:integer; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + CacheItem:PBESENCodePolymorphicInlineCacheItem; +begin + PC:=0; + while PC<TBESENUINT32(ByteCodeLen) do begin + Instruction:=ByteCode[PC]; + OPC:=PC+1; + inc(PC,1+(Instruction shr 8)); + case Instruction and $ff of + bopREF:begin + ByteCode[OPC+6]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+7]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+8]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+9]:=TBESENUINT32(TBESENINT32(-1)); + end; + bopVREF:begin + ByteCode[OPC+4]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+5]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+6]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+7]:=TBESENUINT32(TBESENINT32(-1)); + end; + end; + end; + for i:=0 to CountPolymorphicInlineCacheInstructions-1 do begin + PolymorphicInlineCacheInstruction:=PolymorphicInlineCacheInstructions[i]; + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENPolymorphicInlineCacheStartItemPositions; + for j:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[j]; + CacheItem^.StructureID:=-1; + CacheItem^.Index:=-1; + CacheItem^.ID:=-1; + CacheItem^.NestedLevel:=-1; + end; + end; +end; + +function TBESENCode.Disassemble:TBESENString; +var PC,OPC,Instruction,i:TBESENUINT32; + Output:TBESENString; + procedure Add(const s:TBESENString); + begin + Output:=Output+s; + end; +begin + Output:=''; + PC:=0; + while PC<TBESENUINT32(ByteCodeLen) do begin + Output:=Output+IntToHex(PC,8)+': '; + Instruction:=ByteCode[PC]; + OPC:=PC+1; + inc(PC,1+(Instruction shr 8)); + Add('0x'+IntToHex(Instruction and $ff,2)+' '); + if (Instruction and $ff)<longword(length(OpcodeNames)) then begin + Add(OpcodeNames[Instruction and $ff]); + end else begin + Add('UNKNOWN'); + end; + for i:=1 to Instruction shr 8 do begin + Add(' 0x'+IntToHex(ByteCode[OPC+(i-1)],8)); + end; + Output:=Output+#13#10; + end; + result:=Output; +end; + +procedure TBESENCode.Execute(const Context:TObject;var ResultValue:TBESENValue); +var CodeContext:TBESENCodeContext; +begin + if assigned(FreeCodeContexts) then begin + CodeContext:=TBESENCodeContext(FreeCodeContexts); + TBESENCodeContext(FreeCodeContexts):=TBESENCodeContext(FreeCodeContexts).NextCodeContext; + dec(CountOfFreeCodeContexts); + end else begin + CodeContext:=TBESENCodeContext.Create(Instance,self); + end; + TBESENCodeContext(TBESENContext(Context).CodeContext):=CodeContext; + try + TBESENCodeContext(TBESENContext(Context).CodeContext).Execute(TBESENContext(Context),ResultValue); + finally + TBESENContext(Context).CodeContext:=nil; + TBESENCodeContext(CodeContext).Context:=nil; + if CountOfFreeCodeContexts<TBESEN(Instance).MaxCountOfFreeCodeContexts then begin + CodeContext.NextCodeContext:=TBESENCodeContext(FreeCodeContexts); + TBESENCodeContext(FreeCodeContexts):=CodeContext; + inc(CountOfFreeCodeContexts); + end else begin + BESENFreeAndNil(CodeContext); + end; + end; +end; + +end. diff --git a/3rd/besen/src/BESENCodeContext.pas b/3rd/besen/src/BESENCodeContext.pas new file mode 100644 index 000000000..04f4cdb5f --- /dev/null +++ b/3rd/besen/src/BESENCodeContext.pas @@ -0,0 +1,4011 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeContext; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,Math,BESENConstants,BESENTypes,BESENValue, + BESENBaseObject,BESENCollectorObject,BESENObject,BESENLexicalEnvironment, + BESENStringList,BESENContext,BESENCode, + BESENObjectPropertyDescriptor; + +type TBESENCodeContextBlockType=(bccbtENUM,bccbtWITH,bccbtCATCH,bccbtCATCH2,bccbtFINALLY,bccbtFINALLY2); + + PBESENCodeContextBlock=^TBESENCodeContextBlock; + + TBESENCodeContextBlock=record + BlockType:TBESENCodeContextBlockType; + OldEnumBlock:PBESENCodeContextBlock; + PropertyEnumerator:TBESENObjectPropertyEnumerator; + OldPropertyEnumerator:TBESENObjectPropertyEnumerator; + LastTryBlock:longword; + Resume:longword; + Handler:longword; + Ident:TBESENString; + Obj:TBESENObject; + LexicalEnvironment:TBESENLexicalEnvironment; + Done:longbool; + Raised:longbool; + Value:TBESENValue; + end; + + TBESENCodeContextBlocks=array of TBESENCodeContextBlock; + + TBESENCodeContextOpcode=procedure(Operands:PBESENINT32Array) of object; {$ifdef UseRegister}register;{$endif} + + TBESENCodeContextOpcodePointers=array[byte] of pointer; + + TBESENCodeContextOpcodeArgs=array[byte] of longbool; + + TBESENCodeContextGetRefProc=procedure(const ARef:TBESENValue;var AResult:TBESENValue) of object; + + TBESENCodeContextGetRefProcs=array[byte] of TBESENCodeContextGetRefProc; + + TBESENCodeContextPutRefProc=procedure(const ARef,AValue:TBESENValue) of object; + + TBESENCodeContextPutRefProcs=array[byte] of TBESENCodeContextPutRefProc; + + TBESENCodeContextParameterIndices=array of integer; + + TBESENCodeContext=class(TBESENBaseObject) + private + LexicalEnvironment:TBESENLexicalEnvironment; + OldLexicalEnvironment:TBESENLexicalEnvironment; + GetRefProcs:TBESENCodeContextGetRefProcs; + PutRefProcs:TBESENCodeContextPutRefProcs; + LookupNames:PBESENStringArray; + procedure OpSTOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpVREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpAREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTHROW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTHIS(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpARRAY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpREGEXP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOKUP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDELETE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTYPEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTONUMBER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOBOOLEAN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOSTRING(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOPRIMITIVE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEG(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpINV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNOT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpMUL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDIV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpMOD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpADD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpADDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSUB(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpUSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpINSTANCEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpIN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBAND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBXOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSWITH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSCATCH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpENDF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJMP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJNZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOPENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRYC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRYF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpFUNC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLINE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRICT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRICTCHECKREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDEBUGGER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCHECKOBJECTCOERCIBLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTOBJVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTOBJGET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTOBJSET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpINC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDEC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYLOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOPINITCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOPADDCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTRACE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHLBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHRBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBANDBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBXORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHLNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpUSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBANDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBXORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTRACENEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTRACECALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJNZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + protected + function ConstructError(ConstructorObject:TBESENObject;const Msg:TBESENString;const Name:TBESENString=''):TBESENValue; + function Trace(const TraceType:TBESENTraceType):boolean; + procedure GetIdentifierReference(Lex:TBESENLexicalEnvironment;const Name:TBESENString;const IsStrict:TBESENBoolean;var AResult:TBESENValue); + procedure GetPrimitive(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetObject(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetEnvRec(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetUndefined(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure PutPrimitive(const ARef,AValue:TBESENValue); + procedure PutObject(const ARef,AValue:TBESENValue); + procedure PutEnvRec(const ARef,AValue:TBESENValue); + procedure PutUndefined(const ARef,AValue:TBESENValue); + procedure PutValue(const ARef,AValue:TBESENValue); + function AbstractRelational(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; + function AbstractRelationalNumber(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; + procedure Throw(const ThrowValue:TBESENValue); + function ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} + function ExecuteCode:TBESENBoolean; + procedure ExecuteTryBlockLevel; + public + NextCodeContext:TBESENCodeContext; + Code:TBESENCode; + Context:TBESENContext; + RegisterValues:TBESENValues; + PC:TBESENUINT32; + Blocks:TBESENCodeContextBlocks; + Block:PBESENCodeContextBlock; + LoopCounters:TBESENUINT32s; + ParamArgs:TBESENValuePointers; + PropertyEnumerator:TBESENObjectPropertyEnumerator; + EnumBlock:PBESENCodeContextBlock; + Temp,AnotherTemp:TBESENValue; + BlockLevel,NewBlockLevel:integer; + Obj:TBESENObject; + DontEnum,Running,BlockRunning:TBESENBoolean; + Str:TBESENString; + va,vb,vaa,vbb:TBESENValue; + Descriptor,Descriptor2:TBESENObjectPropertyDescriptor; + BaseValue:TBESENValue; + CallThisArg:TBESENValue; + ResultValue:TBESENValue; + constructor Create(AInstance:TObject;ACode:TBESENCode); overload; + destructor Destroy; override; + procedure Execute(const AContext:TBESENContext;var AResult:TBESENValue); + end; + +var BESENCodeContextOpcodes:TBESENCodeContextOpcodePointers; + +function BESENAdjustPolymorphicInlineCachePosition(Position,Index:TBESENUINT32):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} + +implementation + +uses BESEN,BESENEnvironmentRecord,BESENHashUtils,BESENUtils,BESENArrayUtils, + BESENObjectEnvironmentRecord,BESENDeclarativeEnvironmentRecord,BESENStringUtils, + BESENGarbageCollector,BESENASTNodes,BESENNumberUtils,BESENOpcodes,BESENErrors, + BESENObjectDeclaredFunction{$ifdef HasJIT}{$ifdef cpu386},BESENCodeJITx86{$endif}{$ifdef cpuamd64},BESENCodeJITx64{$endif}{$endif}; + +function sar(Value,Shift:integer):integer; +{$ifdef PurePascal}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$else} +{$ifdef HasSAR} inline; +begin +result:=SARLongint(Value,Shift); +end; +{$else} +{$ifdef cpu386} +{$ifdef fpc} assembler; register; //inline; +asm + mov ecx,edx + sar eax,cl +end;// ['eax','edx','ecx']; +{$else} assembler; register; +asm + mov ecx,edx + sar eax,cl +end; +{$endif} +{$else} +{$ifdef cpuarm} assembler; //inline; +asm + mov r0,r0,asr R1 +end;// ['r0','R1']; +{$else}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$endif} +{$endif} +{$endif} +{$endif} + +function BESENAdjustPolymorphicInlineCachePosition(Position,Index:TBESENUINT32):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + result:=((Position shr (Index shl 2)) and $f) or ((Position and ((1 shl (Index shl 2))-1)) shl 4) or ((Position and not ((1 shl ((Index+1) shl 2))-1)) and TBESENUINT32(0-ord(Index<7))); +end; + +constructor TBESENCodeContext.Create(AInstance:TObject;ACode:TBESENCode); +var i:integer; +begin + inherited Create(AInstance); + Context:=nil; + Code:=ACode; + NextCodeContext:=nil; + Blocks:=nil; + Block:=nil; + PropertyEnumerator:=nil; + EnumBlock:=nil; + Temp:=BESENUndefinedValue; + AnotherTemp:=BESENUndefinedValue; + BlockLevel:=0; + NewBlockLevel:=0; + PC:=0; + Running:=true; + BlockRunning:=true; + RegisterValues:=nil; + LoopCounters:=nil; + ParamArgs:=nil; + + Str:=''; + vaa:=BESENUndefinedValue; + vbb:=BESENUndefinedValue; + Descriptor:=BESENUndefinedPropertyDescriptor; + Descriptor2:=BESENUndefinedPropertyDescriptor; + + CallThisArg:=BESENUndefinedValue; + + GetRefProcs[brbvtUNDEFINED]:=GetUndefined; + GetRefProcs[brbvtBOOLEAN]:=GetPrimitive; + GetRefProcs[brbvtNUMBER]:=GetPrimitive; + GetRefProcs[brbvtSTRING]:=GetPrimitive; + GetRefProcs[brbvtOBJECT]:=GetObject; + GetRefProcs[brbvtENVREC]:=GetEnvRec; + + PutRefProcs[brbvtUNDEFINED]:=PutUndefined; + PutRefProcs[brbvtBOOLEAN]:=PutPrimitive; + PutRefProcs[brbvtNUMBER]:=PutPrimitive; + PutRefProcs[brbvtSTRING]:=PutPrimitive; + PutRefProcs[brbvtOBJECT]:=PutObject; + PutRefProcs[brbvtENVREC]:=PutEnvRec; + + SetLength(RegisterValues,Code.MaxRegisters); + if length(RegisterValues)>0 then begin + FillChar(RegisterValues[0],length(RegisterValues)*sizeof(TBESENValue),#0); + end; + + Temp:=BESENEmptyValue; + SetLength(Blocks,Code.MaxBlock+1); + SetLength(LoopCounters,Code.MaxLoop+1); + SetLength(ParamArgs,Code.MaxParamArgs+1); + for i:=0 to length(ParamArgs)-1 do begin + ParamArgs[i]:=nil; + end; + if length(Blocks)>0 then begin + fillchar(Blocks[0],length(Blocks)*sizeof(TBESENCodeContextBlock),#0); + end; +end; + +destructor TBESENCodeContext.Destroy; +var i:integer; +begin + SetLength(LoopCounters,0); + SetLength(ParamArgs,0); + SetLength(RegisterValues,0); + for i:=0 to length(Blocks)-1 do begin + Blocks[i].Ident:=''; + Blocks[i].Value.Str:=''; + Blocks[i].Value.ReferenceBase.Str:=''; + end; + SetLength(Blocks,0); + Str:=''; + inherited Destroy; +end; + +function TBESENCodeContext.ConstructError(ConstructorObject:TBESENObject;const Msg:TBESENString;const Name:TBESENString=''):TBESENValue; +var v:TBESENValue; + vv:array[0..0] of PBESENValue; +begin + v.ValueType:=bvtSTRING; + v.Str:=Msg; + vv[0]:=@v; + ConstructorObject.Construct(BESENUndefinedValue,@vv,1,result); + TBESEN(Instance).GarbageCollector.Add(TBESENObject(result.Obj)); + if length(Name)>0 then begin + TBESENObject(result.Obj).PutEx('name',BESENStringValue(Name),true,Descriptor,Descriptor2,AnotherTemp); + end; +end; + +function TBESENCodeContext.Trace(const TraceType:TBESENTraceType):boolean; +begin + result:=true; + if assigned(TBESEN(Instance).TraceHook) then begin + if not TBESEN(Instance).TraceHook(TBESEN(Instance),Context,Code.Body,PC,TraceType) then begin + Running:=false; + BlockRunning:=false; + result:=false; + end; + end; +end; + +procedure TBESENCodeContext.GetIdentifierReference(Lex:TBESENLexicalEnvironment;const Name:TBESENString;const IsStrict:TBESENBoolean;var AResult:TBESENValue); +var EnvRec:TBESENEnvironmentRecord; +begin + AResult.ValueType:=bvtREFERENCE; + AResult.ReferenceBase.ValueType:=brbvtUNDEFINED; + AResult.Str:=Name; + AResult.ReferenceIsStrict:=IsStrict; + AResult.ReferenceHash:=BESENHashKey(Name); + AResult.ReferenceIndex:=-1; + AResult.ReferenceID:=-1; + while assigned(Lex) do begin + EnvRec:=Lex.EnvironmentRecord; + if assigned(EnvRec) and EnvRec.HasBindingEx(Name,Descriptor) then begin + AResult.ReferenceBase.ValueType:=brbvtENVREC; + AResult.ReferenceBase.EnvRec:=EnvRec; + break; + end; + Lex:=Lex.Outer; + end; +end; + +procedure TBESENCodeContext.GetPrimitive(const ARef:TBESENValue;var AResult:TBESENValue); +var O:TBESENObject; + Hash:TBESENHash; +begin + AResult.ValueType:=bvtUNDEFINED; + BESENReferenceBaseValueToValue(ARef.ReferenceBase,BaseValue); + if BaseValue.ValueType=bvtOBJECT then begin + O:=TBESENObject(BaseValue.Obj); + end else begin + O:=TBESEN(Instance).ToObj(BaseValue); + TBESEN(Instance).GarbageCollector.Add(O); + end; + if not assigned(O) then begin + BESENThrowNotDefined(ARef); + end; + O.GarbageCollectorLock; + try + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + Str:=ARef.Str; + Hash:=ARef.ReferenceHash; + end else begin + Str:=BESENArrayIndexToStr(TBESENUINT32(ARef.ReferenceIndex)); + Hash:=BESENHashKey(Str); + end; + end else begin + Str:=TBESEN(Instance).KeyIDManager.List[ARef.ReferenceID]; + Hash:=BESENHashKey(Str); + end; + if O.GetProperty(Str,Descriptor,Hash) then begin + if Descriptor.Presents<>[] then begin + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + if boppVALUE in Descriptor.Presents then begin + BESENCopyValue(AResult,Descriptor.Value); + end; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if (boppGETTER in Descriptor.Presents) and assigned(Descriptor.Getter) then begin + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Getter),BaseValue,nil,0,AResult); + end; + end; + end; + end; + finally + O.GarbageCollectorUnlock; + end; +end; + +procedure TBESENCodeContext.GetObject(const ARef:TBESENValue;var AResult:TBESENValue); +begin + if not assigned(ARef.ReferenceBase.Obj) then begin + BESENThrowNotDefined(ARef); + end; + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENObject(ARef.ReferenceBase.Obj).GetEx(ARef.Str,AResult,Descriptor,TBESENObject(ARef.ReferenceBase.Obj),ARef.ReferenceHash); + end else begin + TBESENObject(ARef.ReferenceBase.Obj).GetArrayIndex(TBESENUINT32(ARef.ReferenceIndex),AResult,TBESENObject(ARef.ReferenceBase.Obj)); + end; + end else begin + TBESENObject(ARef.ReferenceBase.Obj).GetIndex(ARef.ReferenceIndex,ARef.ReferenceID,AResult,TBESENObject(ARef.ReferenceBase.Obj)); + end; +end; + +procedure TBESENCodeContext.GetEnvRec(const ARef:TBESENValue;var AResult:TBESENValue); +begin + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetBindingValueEx(ARef.Str,ARef.ReferenceIsStrict,AResult,Descriptor,ARef.ReferenceHash); + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetArrayIndexValue(TBESENUINT32(ARef.ReferenceIndex),ARef.ReferenceIsStrict,AResult); + end; + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetIndexValue(ARef.ReferenceIndex,ARef.ReferenceID,ARef.ReferenceIsStrict,AResult); + end; +end; + +procedure TBESENCodeContext.GetUndefined(const ARef:TBESENValue;var AResult:TBESENValue); +begin + BESENThrowNotDefined(ARef); +end; + +procedure TBESENCodeContext.GetValue(const AValue:TBESENValue;var AResult:TBESENValue); +begin + case AValue.ValueType of + bvtREFERENCE:begin + GetRefProcs[AValue.ReferenceBase.ValueType](AValue,AResult); + end; + bvtLOCAL:begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(AValue.LocalIndex,-1,TBESEN(Instance).IsStrict,AResult); + end; + else begin + if @AResult<>@AValue then begin + BESENCopyValue(AResult,AValue); + end; + end; + end; +end; + +procedure TBESENCodeContext.PutPrimitive(const ARef,AValue:TBESENValue); +var O:TBESENObject; + ValuePointers:array[0..0] of PBESENValue; + Done:boolean; + Hash:TBESENHash; +begin + BESENReferenceBaseValueToValue(ARef.ReferenceBase,BaseValue); + if BaseValue.ValueType=bvtOBJECT then begin + O:=TBESENObject(BaseValue.Obj); + end else begin + O:=TBESEN(Instance).ToObj(BaseValue); + TBESEN(Instance).GarbageCollector.Add(O); + end; + if not assigned(O) then begin + BESENThrowNotAccessable(ARef); + end; + O.GarbageCollectorLock; + try + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + Str:=ARef.Str; + Hash:=ARef.ReferenceHash; + end else begin + Str:=BESENArrayIndexToStr(TBESENUINT32(ARef.ReferenceIndex)); + Hash:=BESENHashKey(Str); + end; + end else begin + Str:=TBESEN(Instance).KeyIDManager.List[ARef.ReferenceID]; + Hash:=BESENHashKey(Str); + end; + Done:=false; + if not O.CanPut(Str,Descriptor,Descriptor2,Hash) then begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end else begin + Done:=true; + end; + end; + if not Done then begin + if ([boppVALUE,boppWRITABLE]*Descriptor2.Presents)<>[] then begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end else begin + Done:=true; + end; + end; + if not Done then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin + ValuePointers[0]:=@AValue; + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BaseValue,@ValuePointers,1,AnotherTemp); + end else begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end; + end; + end else begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end; + end; + end; + end; + finally + O.GarbageCollectorUnlock; + end; +end; + +procedure TBESENCodeContext.PutObject(const ARef,AValue:TBESENValue); +begin + if not assigned(ARef.ReferenceBase.Obj) then begin + BESENThrowNotAccessable(ARef); + end; + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENObject(ARef.ReferenceBase.Obj).PutEx(ARef.Str,AValue,ARef.ReferenceIsStrict,Descriptor,Descriptor2,AnotherTemp,ARef.ReferenceHash); + end else begin + TBESENObject(ARef.ReferenceBase.Obj).PutArrayIndex(TBESENUINT32(ARef.ReferenceIndex),AValue,ARef.ReferenceIsStrict); + end; + end else begin + TBESENObject(ARef.ReferenceBase.Obj).PutIndex(ARef.ReferenceIndex,ARef.ReferenceID,AValue,ARef.ReferenceIsStrict); + end; +end; + +procedure TBESENCodeContext.PutEnvRec(const ARef,AValue:TBESENValue); +begin + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetMutableBindingEx(ARef.Str,AValue,ARef.ReferenceIsStrict,Descriptor,Descriptor2,AnotherTemp,ARef.ReferenceHash); + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetArrayIndexValue(TBESENUINT32(ARef.ReferenceIndex),AValue,ARef.ReferenceIsStrict); + end; + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetIndexValue(ARef.ReferenceIndex,ARef.ReferenceID,AValue,ARef.ReferenceIsStrict); + end; +end; + +procedure TBESENCodeContext.PutUndefined(const ARef,AValue:TBESENValue); +begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end else begin + TBESEN(Instance).ObjectGlobal.PutEx(ARef.Str,AValue,false,Descriptor,Descriptor2,AnotherTemp); + end; +end; + +procedure TBESENCodeContext.PutValue(const ARef,AValue:TBESENValue); +begin + if (AValue.ValueType=bvtOBJECT) and assigned(AValue.Obj) then begin + TBESENObject(AValue.Obj).GarbageCollectorWriteBarrier; + end; + case ARef.ValueType of + bvtREFERENCE:begin + PutRefProcs[ARef.ReferenceBase.ValueType](ARef,AValue); + end; + bvtLOCAL:begin + Context.VariableEnvironment.EnvironmentRecord.SetIndexValue(ARef.LocalIndex,-1,AValue,TBESEN(Instance).IsStrict); + end; + else begin + BESENThrowReference; + end; + end; +end; + +function TBESENCodeContext.AbstractRelational(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; +{$ifndef UseSafeOperations} +{$ifdef cpu386} +var a,b:TBESENNumber; + br:TBESENBoolean; +{$else} +var Item:PBESENNumberCodeAbstractRelationalLookupTableItem; +{$endif} +{$endif} +begin + result:=true; + if eva^.ValueType=bvtOBJECT then begin + TBESEN(Instance).ToPrimitiveValue(eva^,TBESEN(Instance).ObjectNumberConstructorValue,vaa); + eva:=@vaa; + end; + if evb^.ValueType=bvtOBJECT then begin + TBESEN(Instance).ToPrimitiveValue(evb^,TBESEN(Instance).ObjectNumberConstructorValue,vbb); + evb:=@vbb; + end; + if (eva^.ValueType=bvtSTRING) and (evb^.ValueType=bvtSTRING) then begin + BoolRes:=eva^.Str<evb^.Str; + end else begin + if eva^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(eva^,va); + eva:=@va; + end; + if evb^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(evb^,vb); + evb:=@vb; + end; +{$ifdef UseSafeOperations} + if BESENIsNaN(eva^.Num) or BESENIsNaN(evb^.Num) then begin + result:=false; + BoolRes:=false; + end else if BESENIsSameValue(eva^.Num,evb^.Num) then begin + BoolRes:=false; + end else if (BESENIsZero(eva^.Num) and BESENIsZero(evb^.Num)) and (BESENIsNegative(eva^.Num)<>BESENIsNegative(evb^.Num)) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(eva^.Num) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(evb^.Num) then begin + BoolRes:=true; + end else if BESENIsNegInfinite(evb^.Num) then begin + BoolRes:=false; + end else if BESENIsNegInfinite(eva^.Num) then begin + BoolRes:=true; + end else begin + BoolRes:=eva^.Num<evb^.Num; + end; +{$else} +{$ifdef cpu386} + a:=eva^.Num; + b:=evb^.Num; + asm + fld qword ptr [a] + fcomp qword ptr [b] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov dword ptr br,eax + neg cl + sbb ecx,ecx + mov dword ptr result,ecx + end {$ifdef fpc}['eax','ecx']{$endif}; + BoolRes:=br; +{$else} + Item:=@BESENNumberCodeAbstractRelationalLookupTable[((BESENNumberCodeFlags(eva^.Num) shl 4) or BESENNumberCodeFlags(evb^.Num)) and $ff]; + result:=Item^.IsNotUndefined; + BoolRes:=result and (Item^.ResultBooleanValue or (Item^.DoCompare and (eva^.Num<evb^.Num))); +{$endif} +{$endif} + end; +end; + +function TBESENCodeContext.AbstractRelationalNumber(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; +{$ifndef UseSafeOperations} +{$ifdef cpu386} +var a,b:TBESENNumber; + br:TBESENBoolean; +{$else} +var Item:PBESENNumberCodeAbstractRelationalLookupTableItem; +{$endif} +{$endif} +begin +{$ifdef UseSafeOperations} + result:=true; + if BESENIsNaN(eva^.Num) or BESENIsNaN(evb^.Num) then begin + result:=false; + BoolRes:=false; + end else if BESENIsSameValue(eva^.Num,evb^.Num) then begin + BoolRes:=false; + end else if (BESENIsZero(eva^.Num) and BESENIsZero(evb^.Num)) and (BESENIsNegative(eva^.Num)<>BESENIsNegative(evb^.Num)) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(eva^.Num) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(evb^.Num) then begin + BoolRes:=true; + end else if BESENIsNegInfinite(evb^.Num) then begin + BoolRes:=false; + end else if BESENIsNegInfinite(eva^.Num) then begin + BoolRes:=true; + end else begin + BoolRes:=eva^.Num<evb^.Num; + end; +{$else} +{$ifdef cpu386} + a:=eva^.Num; + b:=evb^.Num; + asm + fld qword ptr [a] + fcomp qword ptr [b] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov dword ptr br,eax + neg cl + sbb ecx,ecx + mov dword ptr result,ecx + end {$ifdef fpc}['eax','ecx']{$endif}; + BoolRes:=br; +{$else} + Item:=@BESENNumberCodeAbstractRelationalLookupTable[((BESENNumberCodeFlags(eva^.Num) shl 4) or BESENNumberCodeFlags(evb^.Num)) and $ff]; + result:=Item^.IsNotUndefined; + BoolRes:=result and (Item^.ResultBooleanValue or (Item^.DoCompare and (eva^.Num<evb^.Num))); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.Throw(const ThrowValue:TBESENValue); +begin + raise EBESENThrowException.Create('Throw',ThrowValue); +end; + +procedure TBESENCodeContext.OpSTOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Running:=false; + BlockRunning:=false; +end; + +procedure TBESENCodeContext.OpNEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + ConstructorValue:PBESENValue; + OldIsStrict:boolean; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + ConstructorValue:=@RegisterValues[Operands^[1]]; + CountArguments:=Operands^[2]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+3]]; + end; + if ConstructorValue^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAConstructorObject; + end else if not TBESENObject(ConstructorValue^.Obj).HasConstruct then begin + BESENThrowTypeErrorObjectHasNoConstruct; + end; + TBESEN(Instance).GarbageCollector.TriggerCollect; + TBESEN(Instance).ObjectConstruct(TBESENObject(ConstructorValue^.Obj),BESENUndefinedValue,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpCALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + Ref,Func:PBESENValue; + OldIsStrict,DirectCall:boolean; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + Ref:=@RegisterValues[Operands^[1]]; + Func:=@RegisterValues[Operands^[2]]; + CountArguments:=Operands^[3]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+4]]; + end; + if Func^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAFunction; + end else if not (assigned(Func^.Obj) and TBESENObject(Func^.Obj).HasCall) then begin + BESENThrowTypeErrorNotCallable; + end; + if Ref^.ValueType=bvtREFERENCE then begin + BESENRefBaseValueToCallThisArgValueProcs[Ref^.ReferenceBase.ValueType](CallThisArg,Ref^.ReferenceBase); + end else begin + CallThisArg.ValueType:=bvtUNDEFINED; + end; + if Func^.Obj=TBESEN(Instance).ObjectGlobalEval then begin + DirectCall:=((Ref^.ValueType=bvtREFERENCE) and (Ref^.ReferenceBase.ValueType=brbvtENVREC)) and TBESENEnvironmentRecord(Ref^.ReferenceBase.EnvRec).HasBindingEx('eval',Descriptor); + TBESEN(Instance).GlobalEval(Context,CallThisArg,@ParamArgs[0],CountArguments,DirectCall,RegisterValues[Operands^[0]]); + end else begin + TBESEN(Instance).ObjectCall(TBESENObject(Func^.Obj),CallThisArg,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpEND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + NewBlockLevel:=Operands^[0]; + while Running and (BlockLevel>=NewBlockLevel) do begin + if BlockLevel=0 then begin + Running:=false; + BlockRunning:=false; + break; + end else begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + case Block^.BlockType of + bccbtENUM:begin + PropertyEnumerator:=Block^.OldPropertyEnumerator; + EnumBlock:=Block^.OldEnumBlock; + BESENFreeAndNil(Block^.PropertyEnumerator); + end; + bccbtWITH:begin + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + end; + bccbtCATCH:begin + Block^.Done:=true; + end; + bccbtCATCH2:begin + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + Block^.Ident:=''; + end; + bccbtFINALLY:begin + Block^.BlockType:=bccbtFINALLY2; + Block^.Done:=true; + Block^.Resume:=PC-2; + Block^.Raised:=false; + PC:=Block^.Handler; + inc(BlockLevel); + break; + end; + bccbtFINALLY2:begin + end; + end; + end; + end; +end; + +procedure TBESENCodeContext.OpVREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + EnvRec:TBESENEnvironmentRecord; + CurrentObject:TBESENObject; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + StructureID:integer; + CacheItem:PBESENCodePolymorphicInlineCacheItem; + CacheItemIndex:integer; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtREFERENCE; + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=Context.VariableEnvironment.EnvironmentRecord; + vp^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + vp^.ReferenceHash:=TBESENHash(Operands^[2]); + + if TBESEN(Instance).InlineCacheEnabled then begin + EnvRec:=Context.VariableEnvironment.EnvironmentRecord; + if assigned(EnvRec) and (EnvRec is TBESENObjectEnvironmentRecord) then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + if assigned(CurrentObject) then begin + PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[3]]; + + // Polymorphic lookup + if CurrentObject.StructureID<>0 then begin + for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; + if CurrentObject.StructureID=CacheItem^.StructureID then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + Operands^[4]:=CacheItem^.StructureID; + Operands^[5]:=BESENInt32BooleanValues[vp^.ReferenceIsStrict]; + Operands^[6]:=CacheItem^.Index; + Operands^[7]:=CacheItem^.ID; + end; + vp^.ReferenceIndex:=CacheItem^.Index; + vp^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end; + + // Megamorphic lookup + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; + if CurrentObject.StructureID=0 then begin + if not CurrentObject.RebuildStructure then begin + CurrentObject:=nil; + end; + end; + if assigned(CurrentObject) then begin + StructureID:=CurrentObject.StructureID; + while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin + if CurrentObject.GetOwnProperty(Code.Variables[Operands^[1]].Name,Descriptor,vp^.ReferenceHash) then begin + if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + vp^.ReferenceIndex:=CurrentObject.LastProp.Index; + vp^.ReferenceID:=CurrentObject.LastProp.ID; + CacheItem^.StructureID:=StructureID; + CacheItem^.Index:=vp^.ReferenceIndex; + CacheItem^.ID:=vp^.ReferenceID; + Operands^[4]:=CacheItem^.StructureID; + Operands^[5]:=BESENInt32BooleanValues[vp^.ReferenceIsStrict]; + Operands^[6]:=CacheItem^.Index; + Operands^[7]:=CacheItem^.ID; + exit; + end; + break; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end; + + end; + end; + end; + + // Normal lookup + Operands^[4]:=-1; + vp^.ReferenceIndex:=-1; + vp^.ReferenceID:=-1; + vp^.Str:=Code.Variables[Operands^[1]].Name; +end; + +procedure TBESENCodeContext.OpLREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtLOCAL; + vp^.LocalIndex:=Operands^[1]; +end; + +procedure TBESENCodeContext.OpNOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin +end; + +procedure TBESENCodeContext.OpCOPY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpNEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=not TBESEN(Instance).EqualityExpressionEquals(a^,b^); +end; + +procedure TBESENCodeContext.OpNSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=not BESENEqualityExpressionStrictEquals(a^,b^); +end; + +procedure TBESENCodeContext.OpAREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; + DoubleIndex:PBESENNumber; +begin + r:=@RegisterValues[Operands^[0]]; + BESENValueToReferenceBaseValue(RegisterValues[Operands^[1]],r^.ReferenceBase); + r^.ValueType:=bvtREFERENCE; + r^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + r^.ReferenceHash:=TBESENHash(Operands^[3]); + r^.ReferenceID:=-1; + DoubleIndex:=@RegisterValues[Operands^[2]].Num; + if (DoubleIndex^>=0) and (DoubleIndex^<2147483648.0) then begin // not 4294967296.0 due to ReferenceIndex<0 check ! + r^.ReferenceIndex:=TBESENINT32(TBESENUINT32(trunc(DoubleIndex^))); + end else begin + r^.ReferenceIndex:=-1; + r^.Str:=TBESEN(Instance).ToStr(RegisterValues[Operands^[2]]); + end; +end; + +procedure TBESENCodeContext.OpTHROW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if Trace(bttTHROW) then begin + Throw(RegisterValues[Operands^[0]]); + end; +end; + +procedure TBESENCodeContext.OpSETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(ResultValue,RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpGETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],ResultValue); +end; + +procedure TBESENCodeContext.OpTHIS(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],Context.ThisBinding); +end; + +procedure TBESENCodeContext.OpOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESEN(Instance).ObjectConstructor; +end; + +procedure TBESENCodeContext.OpARRAY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESEN(Instance).ObjectArrayConstructor; +end; + +procedure TBESENCodeContext.OpREGEXP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESEN(Instance).ObjectRegExpConstructor; +end; + +procedure TBESENCodeContext.OpREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; + CurrentObject:TBESENObject; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + CacheItemIndex:integer; + CacheItem:PBESENCodePolymorphicInlineCacheItem; + StructureID:integer; + StrReg:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + BESENValueToReferenceBaseValue(RegisterValues[Operands^[1]],r^.ReferenceBase); + r^.ValueType:=bvtREFERENCE; + r^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + r^.ReferenceHash:=TBESENHash(Operands^[4]); + + if TBESEN(Instance).InlineCacheEnabled and (TBESENUINT32(Operands^[3])<>$fefefefe) and (r^.ReferenceBase.ValueType=brbvtOBJECT) then begin + CurrentObject:=TBESENObject(r^.ReferenceBase.Obj); + if assigned(CurrentObject) then begin + PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[5]]; + + // Polymorphic lookup + if CurrentObject.StructureID<>0 then begin + for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; + if CurrentObject.StructureID=CacheItem^.StructureID then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + Operands^[6]:=CacheItem^.StructureID; + Operands^[7]:=BESENInt32BooleanValues[r^.ReferenceIsStrict]; + Operands^[8]:=CacheItem^.Index; + Operands^[9]:=CacheItem^.ID; + end; + r^.ReferenceIndex:=CacheItem^.Index; + r^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end; + + // Megamorphic lookup + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; + if CurrentObject.StructureID=0 then begin + if not CurrentObject.RebuildStructure then begin + CurrentObject:=nil; + end; + end; + if assigned(CurrentObject) then begin + StrReg:=@RegisterValues[Operands^[2]]; + StructureID:=CurrentObject.StructureID; + while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin + CurrentObject.LastProp:=nil; + if CurrentObject.GetOwnProperty(StrReg^.Str,Descriptor,r^.ReferenceHash) then begin + if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + r^.ReferenceIndex:=CurrentObject.LastProp.Index; + r^.ReferenceID:=CurrentObject.LastProp.ID; + CacheItem^.StructureID:=StructureID; + CacheItem^.Index:=r^.ReferenceIndex; + CacheItem^.ID:=r^.ReferenceID; + Operands^[6]:=CacheItem^.StructureID; + Operands^[7]:=BESENInt32BooleanValues[r^.ReferenceIsStrict]; + Operands^[8]:=r^.ReferenceIndex; + Operands^[9]:=r^.ReferenceID; + exit; + end; + break; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end; + + end; + end; + + // Normal lookup + Operands^[6]:=-1; + r^.ReferenceIndex:=-1; + r^.ReferenceID:=-1; + r^.Str:=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpGETVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + case RegisterValues[Operands^[1]].ValueType of + bvtREFERENCE:begin + GetRefProcs[RegisterValues[Operands^[1]].ReferenceBase.ValueType](RegisterValues[Operands^[1]],RegisterValues[Operands^[0]]); + end; + bvtLOCAL:begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(RegisterValues[Operands^[1]].LocalIndex,-1,TBESEN(Instance).IsStrict,RegisterValues[Operands^[0]]); + end; + else begin + BESENCopyValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); + end; + end; +end; + +procedure TBESENCodeContext.OpLOOKUP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + Lex:TBESENLexicalEnvironment; + EnvRec:TBESENEnvironmentRecord; + CurrentObject:TBESENObject; + Item:PBESENDeclarativeEnvironmentRecordHashItem; + CacheItem:PBESENCodePolymorphicInlineCacheItem; + CacheItemIndex,NestedLevel,StructureID:integer; + FirstObjectEnvRec,DoIt:boolean; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtREFERENCE; + vp^.ReferenceBase.ValueType:=brbvtUNDEFINED; + vp^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + vp^.ReferenceHash:=TBESENHash(Operands^[2]); + + if TBESEN(Instance).InlineCacheEnabled then begin + PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[3]]; + + // Polymorphic lookup + for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; + if CacheItem^.StructureID<>-1 then begin + NestedLevel:=CacheItem^.NestedLevel; + Lex:=Context.LexicalEnvironment; + while assigned(Lex) and (NestedLevel>0) do begin + dec(NestedLevel); + Lex:=Lex.Outer; + end; + if (NestedLevel=0) and assigned(Lex) then begin + EnvRec:=Lex.EnvironmentRecord; + if CacheItem^.StructureID>0 then begin + if EnvRec is TBESENObjectEnvironmentRecord then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + if assigned(CurrentObject) and ((CurrentObject.StructureID<>0) and (CurrentObject.StructureID=CacheItem^.StructureID)) then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + end; + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + vp^.ReferenceIndex:=CacheItem^.Index; + vp^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end else begin + if EnvRec is TBESENDeclarativeEnvironmentRecord then begin + if (CacheItem^.Index<TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs.Count) and (TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs[CacheItem^.Index]=CacheItem^.ID) then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + end; + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + vp^.ReferenceIndex:=CacheItem^.Index; + vp^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end; + end; + end; + end; + + // Megamorphic lookup + vp^.ReferenceIndex:=-1; + vp^.ReferenceID:=-1; + vp^.Str:=LookupNames^[Operands^[1]]; + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; + FirstObjectEnvRec:=true; + DoIt:=true; + NestedLevel:=0; + Lex:=Context.LexicalEnvironment; + while assigned(Lex) do begin + EnvRec:=Lex.EnvironmentRecord; + if DoIt and (EnvRec.HasMaybeDirectEval and not EnvRec.IsStrict) then begin + // If the direct eval is in an es5-strict-mode code body (top level or function), it can't create vars in + // that code lexical body's scope. But in an es5-non-strict code body (top level or function) we must disable + // here the caching, because a direct eval can create here vars in that code body's lexical scope. + DoIt:=false; + end; + if EnvRec is TBESENObjectEnvironmentRecord then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + if assigned(CurrentObject) then begin + if CurrentObject.StructureID=0 then begin + if not CurrentObject.RebuildStructure then begin + CurrentObject:=nil; + end; + end; + if assigned(CurrentObject) then begin + StructureID:=CurrentObject.StructureID; + while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin + if CurrentObject.GetOwnProperty(vp^.Str,Descriptor,vp^.ReferenceHash) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + if DoIt and FirstObjectEnvRec then begin + FirstObjectEnvRec:=false; + if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + vp^.ReferenceIndex:=CurrentObject.LastProp.Index; + vp^.ReferenceID:=CurrentObject.LastProp.ID; + CacheItem^.StructureID:=StructureID; + CacheItem^.Index:=vp^.ReferenceIndex; + CacheItem^.ID:=vp^.ReferenceID; + CacheItem^.NestedLevel:=NestedLevel; + end; + end; + exit; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end; + end; + end else begin + Item:=TBESENDeclarativeEnvironmentRecord(EnvRec).GetKey(vp^.Str); + if assigned(Item) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + if DoIt and (Item^.Index>=0) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + vp^.ReferenceIndex:=Item^.Index; + vp^.ReferenceID:=TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs[vp^.ReferenceIndex]; + CacheItem^.StructureID:=-2; + CacheItem^.Index:=vp^.ReferenceIndex; + CacheItem^.ID:=vp^.ReferenceID; + CacheItem^.NestedLevel:=NestedLevel; + end; + exit; + end; + end; + inc(NestedLevel); + Lex:=Lex.Outer; + end; + end else begin + // Normal lookup + vp^.ReferenceIndex:=-1; + vp^.ReferenceID:=-1; + vp^.Str:=LookupNames^[Operands^[1]]; + Lex:=Context.LexicalEnvironment; + while assigned(Lex) do begin + EnvRec:=Lex.EnvironmentRecord; + if assigned(EnvRec) then begin + if EnvRec is TBESENObjectEnvironmentRecord then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + while assigned(CurrentObject) do begin + if CurrentObject.GetOwnProperty(vp^.Str,Descriptor,vp^.ReferenceHash) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + exit; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end else if EnvRec is TBESENDeclarativeEnvironmentRecord then begin + Item:=TBESENDeclarativeEnvironmentRecord(EnvRec).GetKey(vp^.Str); + if assigned(Item) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + exit; + end; + end; + end; + Lex:=Lex.Outer; + end; + end; +end; + +procedure TBESENCodeContext.OpPUTVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + PutValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpDELETE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; + bv:TBESENBoolean; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + case up^.ValueType of + bvtREFERENCE:begin + case up^.ReferenceBase.ValueType of + brbvtBOOLEAN,brbvtNUMBER,brbvtSTRING:begin + BESENReferenceBaseValueToValue(up^.ReferenceBase,Temp); + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + bv:=TBESEN(Instance).ToObj(Temp).DeleteEx(up^.Str,up^.ReferenceIsStrict,Descriptor,up^.ReferenceHash); + end else begin + bv:=TBESEN(Instance).ToObj(Temp).DeleteArrayIndex(up^.ReferenceIndex,up^.ReferenceIsStrict); + end; + end else begin + bv:=TBESEN(Instance).ToObj(Temp).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID,up^.ReferenceIsStrict); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=bv; + end; + brbvtOBJECT:begin + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteEx(up^.Str,up^.ReferenceIsStrict,Descriptor,up^.ReferenceHash); + end else begin + bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteArrayIndex(up^.ReferenceIndex,up^.ReferenceIsStrict); + end; + end else begin + bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID,up^.ReferenceIsStrict); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=bv; + end; + brbvtENVREC:begin + if up^.ReferenceIsStrict then begin + BESENThrowSyntaxError('"delete" not allowed here'); + end; + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteBindingEx(up^.Str,Descriptor,up^.ReferenceHash); + end else begin + bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteArrayIndex(TBESENUINT32(up^.ReferenceIndex)); + end; + end else begin + bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=bv; + end; + else begin + if up^.ReferenceIsStrict then begin + BESENThrowSyntaxError('"delete" not allowed here'); + end else begin + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=true; + end; + end; + end; + end; + bvtLOCAL:begin + if TBESEN(Instance).IsStrict then begin + BESENThrowSyntaxError('"delete" not allowed here'); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=Context.VariableEnvironment.EnvironmentRecord.DeleteIndex(up^.LocalIndex,-1); + end; + else begin + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=true; + end; + end; +end; + +procedure TBESENCodeContext.OpTYPEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType=bvtREFERENCE then begin + if not (up^.ReferenceBase.ValueType in [brbvtBOOLEAN,brbvtNUMBER,brbvtSTRING,brbvtOBJECT,brbvtENVREC]) then begin + Temp.ValueType:=bvtUNDEFINED; + end else begin + GetValue(up^,Temp); + end; + end else if up^.ValueType=bvtLOCAL then begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(up^.LocalIndex,-1,TBESEN(Instance).IsStrict,Temp); + end else begin + BESENCopyValueProcs[up^.ValueType](Temp,up^); + end; + vp^.ValueType:=bvtSTRING; + case Temp.ValueType of + bvtUNDEFINED:begin + vp^.Str:='undefined'; + end; + bvtNULL:begin + vp^.Str:='object'; + end; + bvtBOOLEAN:begin + vp^.Str:='boolean'; + end; + bvtNUMBER:begin + vp^.Str:='number'; + end; + bvtSTRING:begin + vp^.Str:='string'; + end; + bvtOBJECT:begin + if assigned(Temp.Obj) and TBESENObject(Temp.Obj).HasCall then begin + vp^.Str:='function'; + end else begin + vp^.Str:='object'; + end; + end; + else begin + vp^.Str:='unknown'; + end; + end; +end; + +procedure TBESENCodeContext.OpTOOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtOBJECT then begin + TBESEN(Instance).ToObjectValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTONUMBER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTOBOOLEAN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtBOOLEAN then begin + TBESEN(Instance).ToBooleanValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTOSTRING(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtSTRING then begin + TBESEN(Instance).ToStringValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTOPRIMITIVE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType=bvtOBJECT then begin + TBESEN(Instance).ToPrimitiveValue(up^,BESENEmptyValue,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpNEG(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; +{$ifdef fpc} + PBESENQWORD(@r^.Num)^:=PBESENQWORD(@RegisterValues[Operands^[1]].Num)^ xor qword($8000000000000000); +{$else} + PBESENINT64(@r^.Num)^:=PBESENINT64(@RegisterValues[Operands^[1]].Num)^ xor int64($8000000000000000); +{$endif} +end; + +procedure TBESENCodeContext.OpINV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(not TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]])); +end; + +procedure TBESENCodeContext.OpNOT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=not RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpMUL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num*RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpDIV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num/RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpMOD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENModulo(RegisterValues[Operands^[1]].Num,RegisterValues[Operands^[2]].Num); +end; + +procedure TBESENCodeContext.OpADD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + if (a^.ValueType=bvtSTRING) or (b^.ValueType=bvtSTRING) then begin + if a^.ValueType<>bvtSTRING then begin + TBESEN(Instance).ToStringValue(a^,va); + a:=@va; + end; + if b^.ValueType<>bvtSTRING then begin + TBESEN(Instance).ToStringValue(b^,vb); + b:=@vb; + end; + r^.ValueType:=bvtSTRING; + r^.Str:=a^.Str+b^.Str; + end else begin + if a^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(a^,va); + a:=@va; + end; + if b^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(b^,vb); + b:=@vb; + end; + r^.ValueType:=bvtNUMBER; + r^.Num:=a^.Num+b^.Num; + end; +end; + +procedure TBESENCodeContext.OpADDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num+RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpSUB(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num-RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpSHL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) shl (TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); +end; + +procedure TBESENCodeContext.OpSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(sar(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]),TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); +end; + +procedure TBESENCodeContext.OpUSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENUINT32(TBESEN(Instance).ToUInt32(RegisterValues[Operands^[1]]) shr (TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); +end; + +procedure TBESENCodeContext.OpLT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + AbstractRelational(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool); +end; + +procedure TBESENCodeContext.OpGT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + AbstractRelational(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); +end; + +procedure TBESENCodeContext.OpLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + if AbstractRelational(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +end; + +procedure TBESENCodeContext.OpGE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + if AbstractRelational(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +end; + +procedure TBESENCodeContext.OpINSTANCEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + if b^.ValueType<>bvtOBJECT then begin + BESENThrowTypeError('Not a object'); + end else begin + r^.Bool:=TBESEN(Instance).ObjectInstanceOf(a^,TBESENObject(b^.Obj)); + end; +end; + +procedure TBESENCodeContext.OpIN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + if b^.ValueType<>bvtOBJECT then begin + BESENThrowTypeError('Not a object'); + end else begin + r^.Bool:=TBESENObject(b^.Obj).HasPropertyEx(TBESEN(Instance).ToStr(a^),Descriptor); + end; +end; + +procedure TBESENCodeContext.OpEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=TBESEN(Instance).EqualityExpressionEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +end; + +procedure TBESENCodeContext.OpSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +end; + +procedure TBESENCodeContext.OpBAND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) and TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); +end; + +procedure TBESENCodeContext.OpBXOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) xor TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); +end; + +procedure TBESENCodeContext.OpBOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) or TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); +end; + +procedure TBESENCodeContext.OpSENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + Obj:TBESENObject; +begin + vp:=@RegisterValues[Operands^[0]]; + case vp^.ValueType of + bvtNULL,bvtUNDEFINED:begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + Obj:=TBESEN(Instance).ObjectEmpty; + end else begin + Obj:=nil; + end; + end; + bvtOBJECT:begin + Obj:=TBESENObject(vp^.Obj); + end; + else begin + Obj:=nil; + end; + end; + if assigned(Obj) then begin + Block:=@Blocks[BlockLevel]; + Block^.BlockType:=bccbtENUM; + Block^.PropertyEnumerator:=Obj.Enumerator(false,false); + Block^.PropertyEnumerator.Reset; + Block^.OldPropertyEnumerator:=PropertyEnumerator; + PropertyEnumerator:=Block^.PropertyEnumerator; + Block^.OldEnumBlock:=EnumBlock; + EnumBlock:=Block; + inc(BlockLevel); + end else begin + BESENThrowTypeError('Not an object'); + end; +end; + +procedure TBESENCodeContext.OpSWITH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + Block:=@Blocks[BlockLevel]; + Block^.BlockType:=bccbtWITH; + Block^.LexicalEnvironment:=TBESEN(Instance).NewObjectEnvironment(TBESENObject(vp^.Obj),Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); + TBESEN(Instance).GarbageCollector.Add(Block^.LexicalEnvironment); + Context.LexicalEnvironment:=Block^.LexicalEnvironment; + TBESENObjectEnvironmentRecord(Block^.LexicalEnvironment.EnvironmentRecord).ProvideThis:=true; + Block^.LexicalEnvironment.EnvironmentRecord.UpdateImplicitThisValue; + inc(BlockLevel); +end; + +procedure TBESENCodeContext.OpSCATCH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Block:=@Blocks[BlockLevel-1]; + Block^.BlockType:=bccbtCATCH2; + Block^.LexicalEnvironment:=TBESEN(Instance).NewDeclarativeEnvironment(Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); + TBESEN(Instance).GarbageCollector.Add(Block^.LexicalEnvironment); + Context.LexicalEnvironment:=Block^.LexicalEnvironment; + Block^.LexicalEnvironment.EnvironmentRecord.CreateMutableBinding(Block^.Ident,false); + Block^.LexicalEnvironment.EnvironmentRecord.SetMutableBindingEx(Block^.Ident,Block^.Value,false,Descriptor,Descriptor2,AnotherTemp,BESENHashKey(Block^.Ident)); + Block^.Ident:=''; +end; + +procedure TBESENCodeContext.OpENDF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + if Block^.Raised or (Block^.Resume>=longword(Code.ByteCodeLen)) then begin + BlockRunning:=false; + end else begin + PC:=Block^.Resume; + end; +end; + +procedure TBESENCodeContext.OpJMP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + PC:=Operands^[0]; +end; + +procedure TBESENCodeContext.OpJZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if RegisterValues[Operands^[1]].Bool then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpJNZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if not RegisterValues[Operands^[1]].Bool then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpJNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[1]]; + if (vp^.ValueType in [bvtUNDEFINED,bvtNULL]) or ((vp^.ValueType=bvtOBJECT) and not assigned(vp^.Obj)) then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpLOOPENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + if PropertyEnumerator.GetNext(Str) then begin + vp:=@RegisterValues[Operands^[1]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=Str; + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpSTRYC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Block:=@Blocks[BlockLevel]; + inc(BlockLevel); + Block^.BlockType:=bccbtCATCH; + Block^.Handler:=Operands^[0]; + Block^.Ident:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpSTRYF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Block:=@Blocks[BlockLevel]; + inc(BlockLevel); + Block^.BlockType:=bccbtFINALLY; + Block^.Handler:=Operands^[0]; +end; + +procedure TBESENCodeContext.OpLITERAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],Code.Literals[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpLITERALUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + RegisterValues[Operands^[0]].ValueType:=bvtUNDEFINED; +end; + +procedure TBESENCodeContext.OpLITERALNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + RegisterValues[Operands^[0]].ValueType:=bvtNULL; +end; + +procedure TBESENCodeContext.OpLITERALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=Operands^[1]<>0; +end; + +procedure TBESENCodeContext.OpLITERALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtNUMBER; + vp^.Num:=Code.Literals[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpLITERALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=Code.Literals[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpLITERALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=Code.Literals[Operands^[1]].Obj; +end; + +procedure TBESENCodeContext.OpFUNC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + Arg:TBESENINT32; +begin + vp:=@RegisterValues[Operands^[0]]; + Arg:=Operands^[1]; + if assigned(Code.FunctionLiteralContainers[Arg].Literal.Name) and (length(Code.FunctionLiteralContainers[Arg].Literal.Name.Name)>0) then begin + LexicalEnvironment:=TBESEN(Instance).NewDeclarativeEnvironment(Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); + OldLexicalEnvironment:=Context.LexicalEnvironment; + Context.LexicalEnvironment:=LexicalEnvironment; + TBESEN(Instance).GarbageCollector.Add(LexicalEnvironment); + try + vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,Code.FunctionLiteralContainers[Arg].Literal.Name.Name,Context.LexicalEnvironment)); + LexicalEnvironment.EnvironmentRecord.CreateImmutableBinding(TBESENObjectDeclaredFunction(vp^.Obj).ObjectName); + LexicalEnvironment.EnvironmentRecord.InitializeImmutableBinding(TBESENObjectDeclaredFunction(vp^.Obj).ObjectName,vp^); + finally + Context.LexicalEnvironment:=OldLexicalEnvironment; + end; + end else begin + if assigned(Code.FunctionLiteralContainers[Arg].Literal.Name) then begin + vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,Code.FunctionLiteralContainers[Arg].Literal.Name.Name,Context.LexicalEnvironment)); + end else begin + vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,'',Context.LexicalEnvironment)); + end; + end; +end; + +procedure TBESENCodeContext.OpLINE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + TBESEN(Instance).LineNumber:=Code.Locations[Operands^[0]].LineNumber; +end; + +procedure TBESENCodeContext.OpGC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + TBESEN(Instance).GarbageCollector.TriggerCollect; +end; + +procedure TBESENCodeContext.OpSTRICT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + TBESEN(Instance).IsStrict:=Operands^[0]<>0; +end; + +procedure TBESENCodeContext.OpSTRICTCHECKREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up:PBESENValue; + der:TBESENDeclarativeEnvironmentRecord; + procedure ThrowIt(const s:TBESENSTRING); + begin + BESENThrowSyntaxError('"'+s+'" not allowed here'); + end; + procedure Check(const s:TBESENSTRING); + begin + if (s='eval') or (s='arguments') then begin + ThrowIt(s); + end; + end; +begin + up:=@RegisterValues[Operands^[0]]; + if up^.ReferenceIsStrict then begin + case up^.ValueType of + bvtREFERENCE:begin + case up^.ReferenceBase.ValueType of + brbvtENVREC:begin + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + Check(up^.Str); + end; + end else begin + if up^.ReferenceBase.EnvRec is TBESENDeclarativeEnvironmentRecord then begin + der:=TBESENDeclarativeEnvironmentRecord(up^.ReferenceBase.EnvRec); + if (up^.ReferenceIndex>=0) and (up^.ReferenceIndex<der.HashIndexNames.Count) then begin + Check(der.HashIndexNames.FList[up^.ReferenceIndex]); + end; + end else begin + if (up^.ReferenceIndex>=0) and (up^.ReferenceIndex<=TBESEN(Instance).KeyIDManager.List.Count) then begin + Check(TBESEN(Instance).KeyIDManager.List.FList[up^.ReferenceID]); + end; + end; + end; + end; + end; + end; + bvtLOCAL:begin + der:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord); + if (up^.LocalIndex>=0) and (up^.LocalIndex<der.HashIndexNames.Count) then begin + Check(der.HashIndexNames.FList[up^.LocalIndex]); + end; + end; + end; + end; +end; + +procedure TBESENCodeContext.OpDEBUGGER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Trace(bttDEBUGGER); +end; + +procedure TBESENCodeContext.OpCHECKOBJECTCOERCIBLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCheckObjectCoercible(RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpPUTOBJVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var ObjReg,StrReg,ValReg:PBESENValue; +begin + ObjReg:=@RegisterValues[Operands^[0]]; + StrReg:=@RegisterValues[Operands^[1]]; + ValReg:=@RegisterValues[Operands^[2]]; + TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENDataPropertyDescriptor(ValReg^,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); +end; + +procedure TBESENCodeContext.OpPUTOBJGET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var ObjReg,StrReg,ValReg:PBESENValue; +begin + ObjReg:=@RegisterValues[Operands^[0]]; + StrReg:=@RegisterValues[Operands^[1]]; + ValReg:=@RegisterValues[Operands^[2]]; + TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENAccessorPropertyDescriptor(TBESENObject(ValReg^.Obj),nil,[bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); +end; + +procedure TBESENCodeContext.OpPUTOBJSET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var ObjReg,StrReg,ValReg:PBESENValue; +begin + ObjReg:=@RegisterValues[Operands^[0]]; + StrReg:=@RegisterValues[Operands^[1]]; + ValReg:=@RegisterValues[Operands^[2]]; + TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENAccessorPropertyDescriptor(nil,TBESENObject(ValReg^.Obj),[bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); +end; + +procedure TBESENCodeContext.OpINC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num+1; +end; + +procedure TBESENCodeContext.OpDEC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num-1; +end; + +procedure TBESENCodeContext.OpCOPYBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpCOPYNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpCOPYSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtSTRING; + r^.Str:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpCOPYOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtOBJECT; + r^.Obj:=RegisterValues[Operands^[1]].Obj; +end; + +procedure TBESENCodeContext.OpCOPYREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + r^.ValueType:=bvtREFERENCE; + BESENCopyReferenceBaseValue(r^.ReferenceBase,a^.ReferenceBase); + r^.Str:=a^.Str; + r^.ReferenceIsStrict:=a^.ReferenceIsStrict; + r^.ReferenceHash:=a^.ReferenceHash; + r^.ReferenceIndex:=a^.ReferenceIndex; + r^.ReferenceID:=a^.ReferenceID; +end; + +procedure TBESENCodeContext.OpCOPYLOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtLOCAL; + r^.LocalIndex:=RegisterValues[Operands^[1]].LocalIndex; +end; + +procedure TBESENCodeContext.OpGETVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + GetRefProcs[RegisterValues[Operands^[1]].ReferenceBase.ValueType](RegisterValues[Operands^[1]],RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpPUTVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + PutRefProcs[RegisterValues[Operands^[0]].ReferenceBase.ValueType](RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpGETVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(RegisterValues[Operands^[1]].LocalIndex,-1,TBESEN(Instance).IsStrict,RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpPUTVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Context.VariableEnvironment.EnvironmentRecord.SetIndexValue(RegisterValues[Operands^[0]].LocalIndex,-1,RegisterValues[Operands^[1]],TBESEN(Instance).IsStrict); +end; + +procedure TBESENCodeContext.OpGETVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex]^); +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]^,RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpGETVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex]^.Bool; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtBOOLEAN; + hp^.Bool:=RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtNUMBER; + vp^.Num:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Num; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtNUMBER; + hp^.Num:=RegisterValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Str; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtSTRING; + hp^.Str:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Obj; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtOBJECT; + hp^.Obj:=RegisterValues[Operands^[1]].Obj; + if assigned(hp^.Obj) then begin + TBESENObject(hp^.Obj).GarbageCollectorWriteBarrier; + end; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]]^); +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]^,RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]]^.Bool; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtBOOLEAN; + hp^.Bool:=RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtNUMBER; + vp^.Num:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtNUMBER; + hp^.Num:=RegisterValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtSTRING; + hp^.Str:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Obj; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtOBJECT; + hp^.Obj:=RegisterValues[Operands^[1]].Obj; + if assigned(hp^.Obj) then begin + TBESENObject(hp^.Obj).GarbageCollectorWriteBarrier; + end; +end; + +procedure TBESENCodeContext.OpLOOPINITCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin +end; + +procedure TBESENCodeContext.OpLOOPADDCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin +end; + +procedure TBESENCodeContext.OpTRACE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Trace(bttSTATEMENT); + if assigned(TBESEN(Instance).PeriodicHook) then begin + if not TBESEN(Instance).PeriodicHook(TBESEN(Instance)) then begin + Running:=false; + BlockRunning:=false; + end; + end; +end; + +procedure TBESENCodeContext.OpLTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool<RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpGTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool>RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpLEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool<=RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpGEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool>=RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool=RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpNEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool<>RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpLTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool); +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); +{$else} +r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpLENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<=RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>=RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpNEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=not BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=not ((not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=RegisterValues[Operands^[2]].Num)); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpLTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str<RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpGTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str>RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpLESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str<=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpGESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str>=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpNEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str<>RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpSHLBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool] shl BESENNumberBooleanValues[RegisterValues[Operands^[2]].Bool]); +end; + +procedure TBESENCodeContext.OpSHRBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool] shr BESENNumberBooleanValues[RegisterValues[Operands^[2]].Bool]); +end; + +procedure TBESENCodeContext.OpBANDBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool and RegisterValues[Operands^[2]].Bool]; +end; + +procedure TBESENCodeContext.OpBXORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool xor RegisterValues[Operands^[2]].Bool]; +end; + +procedure TBESENCodeContext.OpBORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool or RegisterValues[Operands^[2]].Bool]; +end; + +procedure TBESENCodeContext.OpSHLNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) shl (BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31)); +end; + +procedure TBESENCodeContext.OpSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(sar(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num),(BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31))); +end; + +procedure TBESENCodeContext.OpUSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENUINT32(BESENToUInt32Fast(@RegisterValues[Operands^[1]].Num) shr (BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31)); +end; + +procedure TBESENCodeContext.OpBANDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) and BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); +end; + +procedure TBESENCodeContext.OpBXORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) xor BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); +end; + +procedure TBESENCodeContext.OpBORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) or BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); +end; + +procedure TBESENCodeContext.OpSETCUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtUNDEFINED; +end; + +procedure TBESENCodeContext.OpSETCNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtNULL; +end; + +procedure TBESENCodeContext.OpSETCBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=RegisterValues[Operands^[0]].Bool; +end; + +procedure TBESENCodeContext.OpSETCNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=RegisterValues[Operands^[0]].Num; +end; + +procedure TBESENCodeContext.OpSETCSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:=RegisterValues[Operands^[0]].Str; +end; + +procedure TBESENCodeContext.OpSETCOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtOBJECT; + ResultValue.Obj:=RegisterValues[Operands^[0]].Obj; +end; + +procedure TBESENCodeContext.OpTRACENEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + OldIsStrict:boolean; + ConstructorValue:PBESENValue; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + ConstructorValue:=@RegisterValues[Operands^[1]]; + CountArguments:=Operands^[2]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+3]]; + end; + if ConstructorValue^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAConstructorObject; + end else if not TBESENObject(ConstructorValue^.Obj).HasConstruct then begin + BESENThrowTypeErrorObjectHasNoConstruct; + end; + if Trace(bttCALL) then begin + TBESEN(Instance).GarbageCollector.TriggerCollect; + TBESEN(Instance).ObjectConstruct(TBESENObject(ConstructorValue^.Obj),BESENUndefinedValue,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + Trace(bttRETURN); + end else begin + RegisterValues[Operands^[0]].ValueType:=bvtUNDEFINED; + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpTRACECALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + Ref,Func:PBESENValue; + OldIsStrict,DirectCall:boolean; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + Ref:=@RegisterValues[Operands^[1]]; + Func:=@RegisterValues[Operands^[2]]; + CountArguments:=Operands^[3]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+4]]; + end; + if Func^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAFunction; + end else if not (assigned(Func^.Obj) and TBESENObject(Func^.Obj).HasCall) then begin + BESENThrowTypeErrorNotCallable; + end; + if Ref^.ValueType=bvtREFERENCE then begin + BESENRefBaseValueToCallThisArgValueProcs[Ref^.ReferenceBase.ValueType](CallThisArg,Ref^.ReferenceBase); + end else begin + CallThisArg.ValueType:=bvtUNDEFINED; + end; + if Trace(bttCALL) then begin + if Func^.Obj=TBESEN(Instance).ObjectGlobalEval then begin + DirectCall:=((Ref^.ValueType=bvtREFERENCE) and (Ref^.ReferenceBase.ValueType=brbvtENVREC)) and TBESENEnvironmentRecord(Ref^.ReferenceBase.EnvRec).HasBindingEx('eval',Descriptor); + TBESEN(Instance).GlobalEval(Context,CallThisArg,@ParamArgs[0],CountArguments,DirectCall,RegisterValues[Operands^[0]]); + end else begin + TBESEN(Instance).ObjectCall(TBESENObject(Func^.Obj),CallThisArg,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + end; + Trace(bttRETURN); + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpLTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@RegisterValues[Operands^[1]],@Code.Literals[Operands^[2]],r^.Bool); +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@Code.Literals[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@Code.Literals[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpLENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@Code.Literals[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@Code.Literals[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<=Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@RegisterValues[Operands^[1]],@Code.Literals[Operands^[2]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>=Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],Code.Literals[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpNEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=not BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],Code.Literals[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=not ((not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=Code.Literals[Operands^[2]].Num)); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpJZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if (not BESENIsNaN(RegisterValues[Operands^[1]].Num)) and (RegisterValues[Operands^[1]].Num=0) then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpJNZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if not ((not BESENIsNaN(RegisterValues[Operands^[1]].Num)) and (RegisterValues[Operands^[1]].Num=0)) then begin + PC:=Operands^[0]; + end; +end; + +{$ifndef PurePascal} +{$define PurePascalExecuteByteCode} + +{$ifdef cpu386} +{$undef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; assembler; {$ifdef UseRegister}register;{$endif} +asm + push ebx + push esi + push edi + mov esi,self + mov dword ptr [esi+TBESENCodeContext.BlockRunning],$ffffffff + mov edi,dword ptr [esi+TBESENCodeContext.Code] + mov edi,dword ptr [edi+TBESENCode.ByteCode] + jmp @LoopStart + @LoopBegin: + mov ebx,dword ptr [esi+TBESENCodeContext.PC] + lea edx,dword ptr [edi+ebx*4+4] + mov ebx,dword ptr [edi+ebx*4] + mov ecx,ebx + and ecx,$ff + shr ebx,8 + inc ebx + add dword ptr [esi+TBESENCodeContext.PC],ebx + mov eax,esi + call dword ptr [ecx*4+offset BESENCodeContextOpcodes] + @LoopStart: + cmp dword ptr [esi+TBESENCodeContext.BlockRunning],0 + jnz @LoopBegin + mov eax,dword ptr [esi+TBESENCodeContext.BlockRunning] + pop edi + pop esi + pop ebx +end; +{$endif} + +{$ifdef cpuamd64} +{$ifdef windows} +{$undef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} +begin + BlockRunning:=true; + asm + mov rsi,self + mov rdi,qword ptr [rsi+TBESENCodeContext.Code] + mov rdi,qword ptr [rdi+TBESENCode.ByteCode] + jmp @LoopStart + @LoopBegin: + xor rbx,rbx + mov ebx,dword ptr [rsi+TBESENCodeContext.PC] + lea rdx,qword ptr [rdi+rbx*4+4] + mov ebx,dword ptr [rdi+rbx*4] + mov rax,rbx + and eax,$ff + shr ebx,8 + inc ebx + add dword ptr [rsi+TBESENCodeContext.PC],ebx + mov rcx,rsi + mov rbx,offset BESENCodeContextOpcodes + call qword ptr [rbx+rax*8] + @LoopStart: + cmp dword ptr [rsi+TBESENCodeContext.BlockRunning],0 + jnz @LoopBegin + end ['rax','rbx','rcx','rdx','rsi','rdi']; + result:=BlockRunning; +end; +{$else} +{$undef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} +begin + BlockRunning:=true; + asm + mov r12,self + mov r13,qword ptr [r12+TBESENCodeContext.Code] + mov r13,qword ptr [r13+TBESENCode.ByteCode] + jmp @LoopStart + @LoopBegin: + xor rbx,rbx + mov ebx,dword ptr [r12+TBESENCodeContext.PC] + lea rsi,qword ptr [r13+rbx*4+4] + mov ebx,dword ptr [r13+rbx*4] + mov rax,rbx + and eax,$ff + shr ebx,8 + inc ebx + add dword ptr [r12+TBESENCodeContext.PC],ebx + mov rdi,r12 + mov rbx,offset BESENCodeContextOpcodes + call qword ptr [rbx+rax*8] + @LoopStart: + cmp dword ptr [r12+TBESENCodeContext.BlockRunning],0 + jnz @LoopBegin + end ['rax','rbx','rcx','rdx','rsi','rdi','r8','r9','r10','r11','r12','r13']; + result:=BlockRunning; +end; +{$endif} +{$endif} +{$endif} + +{$ifdef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; +var Handler:TBESENCodeContextOpcode; + Instruction:longword; + ByteCode:PBESENUINT32Array; + Operands:PBESENINT32Array; +begin + BlockRunning:=true; + ByteCode:=@Code.ByteCode[0]; + while BlockRunning do begin + Instruction:=ByteCode^[PC]; + Operands:=@ByteCode^[PC+1]; + inc(PC,1+(Instruction shr 8)); + TMethod(Handler).Code:=BESENCodeContextOpcodes[Instruction and $ff]; + TMethod(Handler).Data:=self; + Handler(Operands); + end; + result:=BlockRunning; +end; +{$endif} + +function TBESENCodeContext.ExecuteCode:TBESENBoolean; +begin + if PC<TBESENUINT32(Code.ByteCodeLen) then begin +{$ifdef HasJIT} + if assigned(Code.NativeCode) then begin + result:=BESENExecuteNativeCode(self); + end else begin + result:=ExecuteByteCode; + end; +{$else} + result:=ExecuteByteCode; +{$endif} + if assigned(TBESEN(Instance).PeriodicHook) then begin + if not TBESEN(Instance).PeriodicHook(TBESEN(Instance)) then begin + Running:=false; + BlockRunning:=false; + result:=false; + end; + end; + end else begin + result:=false; + end; +end; + +procedure TBESENCodeContext.ExecuteTryBlockLevel; +var Reraise:boolean; + ExceptionValue:TBESENValue; + function ProcessException:boolean; + begin + result:=true; + while BlockLevel>0 do begin + case Blocks[BlockLevel-1].BlockType of + bccbtENUM:begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + PropertyEnumerator:=Block^.OldPropertyEnumerator; + EnumBlock:=Block^.OldEnumBlock; + BESENFreeAndNil(Block.PropertyEnumerator); + end; + bccbtWITH:begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + end; + bccbtCATCH:begin + Block:=@Blocks[BlockLevel-1]; + Block^.Value:=ExceptionValue; + PC:=Block^.Handler; + result:=false; + break; + end; + bccbtCATCH2:begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + Block^.Ident:=''; + end; + bccbtFINALLY:begin + Block:=@Blocks[BlockLevel-1]; + Block^.BlockType:=bccbtFINALLY2; + Block^.Resume:=$ffffffff; + Block^.Raised:=true; + PC:=Block^.Handler; + ExecuteTryBlockLevel; + end; + bccbtFINALLY2:begin + dec(BlockLevel); + end; + end; + end; + end; +begin + ExceptionValue:=BESENEmptyValue; + Reraise:=false; + while Running do begin + try + if not ExecuteCode then begin + break; + end; + except + on e:EBESENThrowException do begin + ExceptionValue:=E.Value; + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENEvalError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectEvalErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENRangeError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectRangeErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENReferenceError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectReferenceErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENSyntaxError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectSyntaxErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENTypeError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectTypeErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENURIError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectURIErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,e.OriginalMessage,E.Name); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:Exception do begin +{$ifdef Delphi2009AndUp} + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,e.Message); +{$else} + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,BESENUTF8ToUTF16(BESENConvertToUTF8(e.Message))); +{$endif} + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + else begin + ExceptionValue:=BESENEmptyValue; + Reraise:=ProcessException; + if Reraise then begin + raise; + end; + end; + end; + end; +end; + +procedure TBESENCodeContext.Execute(const AContext:TBESENContext;var AResult:TBESENValue); +var i:integer; + IsDeclarativeEnvironmentRecord:boolean; + EnvironmentRecord:TBESENEnvironmentRecord; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin + Context:=AContext; + ResultValue.ValueType:=bvtUNDEFINED; + PropertyEnumerator:=nil; + EnumBlock:=nil; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(rmNearest); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + for i:=0 to length(RegisterValues)-1 do begin + RegisterValues[i].ValueType:=bvtUNDEFINED; + end; + if Code.Body.EnableLocalsOptimization then begin + EnvironmentRecord:=Context.VariableEnvironment.EnvironmentRecord; + IsDeclarativeEnvironmentRecord:=EnvironmentRecord is TBESENDeclarativeEnvironmentRecord; + if (IsDeclarativeEnvironmentRecord and not TBESENDeclarativeEnvironmentRecord(EnvironmentRecord).IndexInitialized) or not IsDeclarativeEnvironmentRecord then begin + if IsDeclarativeEnvironmentRecord then begin + TBESENDeclarativeEnvironmentRecord(EnvironmentRecord).IndexInitialized:=true; + end; + for i:=0 to length(Code.Variables)-1 do begin + if not EnvironmentRecord.SetBindingValueIndex(Code.Variables[i].Name,i) then begin + BESENThrowInternalError('Internal error: 201003160136-0000'); + end; + end; + end; + end; + Running:=true; + Str:=''; + PC:=0; + BlockLevel:=0; + Block:=@Blocks[0]; +{$ifdef HasJIT} + if not assigned(Code.NativeCode) then begin + if not BESENGenerateNativeCode(self) then begin + if assigned(Code.NativeCode) then begin + TBESEN(Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); + Code.NativeCode:=nil; + Code.NativeCodeSize:=0; + end; + end; + end; +{$endif} + LookupNames:=Code.LookupNames.FList; + ExecuteTryBlockLevel; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + Context:=nil; + end; + BesenCopyValue(AResult,ResultValue); +end; + +procedure InitOpcodes; +var i:integer; +begin + fillchar(BESENCodeContextOpcodes,sizeof(TBESENCodeContextOpcodePointers),#0); + for i:=0 to 255 do begin + BESENCodeContextOpcodes[i]:=@TBESENCodeContext.OpNOP; + end; + BESENCodeContextOpcodes[bopSTOP]:=@TBESENCodeContext.OpSTOP; + BESENCodeContextOpcodes[bopNEW]:=@TBESENCodeContext.OpNEW; + BESENCodeContextOpcodes[bopCALL]:=@TBESENCodeContext.OpCALL; + BESENCodeContextOpcodes[bopEND]:=@TBESENCodeContext.OpEND; + BESENCodeContextOpcodes[bopVREF]:=@TBESENCodeContext.OpVREF; + BESENCodeContextOpcodes[bopLREF]:=@TBESENCodeContext.OpLREF; + BESENCodeContextOpcodes[bopNOP]:=@TBESENCodeContext.OpNOP; + BESENCodeContextOpcodes[bopCOPY]:=@TBESENCodeContext.OpCOPY; + BESENCodeContextOpcodes[bopNEQ]:=@TBESENCodeContext.OpNEQ; + BESENCodeContextOpcodes[bopNSEQ]:=@TBESENCodeContext.OpNSEQ; + BESENCodeContextOpcodes[bopAREF]:=@TBESENCodeContext.OpAREF; + BESENCodeContextOpcodes[bopTHROW]:=@TBESENCodeContext.OpTHROW; + BESENCodeContextOpcodes[bopSETC]:=@TBESENCodeContext.OpSETC; + BESENCodeContextOpcodes[bopGETC]:=@TBESENCodeContext.OpGETC; + BESENCodeContextOpcodes[bopTHIS]:=@TBESENCodeContext.OpTHIS; + BESENCodeContextOpcodes[bopOBJECT]:=@TBESENCodeContext.OpOBJECT; + BESENCodeContextOpcodes[bopARRAY]:=@TBESENCodeContext.OpARRAY; + BESENCodeContextOpcodes[bopREGEXP]:=@TBESENCodeContext.OpREGEXP; + BESENCodeContextOpcodes[bopREF]:=@TBESENCodeContext.OpREF; + BESENCodeContextOpcodes[bopGETVALUE]:=@TBESENCodeContext.OpGETVALUE; + BESENCodeContextOpcodes[bopLOOKUP]:=@TBESENCodeContext.OpLOOKUP; + BESENCodeContextOpcodes[bopPUTVALUE]:=@TBESENCodeContext.OpPUTVALUE; + BESENCodeContextOpcodes[bopDELETE]:=@TBESENCodeContext.OpDELETE; + BESENCodeContextOpcodes[bopTYPEOF]:=@TBESENCodeContext.OpTYPEOF; + BESENCodeContextOpcodes[bopTOOBJECT]:=@TBESENCodeContext.OpTOOBJECT; + BESENCodeContextOpcodes[bopTONUMBER]:=@TBESENCodeContext.OpTONUMBER; + BESENCodeContextOpcodes[bopTOBOOLEAN]:=@TBESENCodeContext.OpTOBOOLEAN; + BESENCodeContextOpcodes[bopTOSTRING]:=@TBESENCodeContext.OpTOSTRING; + BESENCodeContextOpcodes[bopTOPRIMITIVE]:=@TBESENCodeContext.OpTOPRIMITIVE; + BESENCodeContextOpcodes[bopNEG]:=@TBESENCodeContext.OpNEG; + BESENCodeContextOpcodes[bopINV]:=@TBESENCodeContext.OpINV; + BESENCodeContextOpcodes[bopNOT]:=@TBESENCodeContext.OpNOT; + BESENCodeContextOpcodes[bopMUL]:=@TBESENCodeContext.OpMUL; + BESENCodeContextOpcodes[bopDIV]:=@TBESENCodeContext.OpDIV; + BESENCodeContextOpcodes[bopMOD]:=@TBESENCodeContext.OpMOD; + BESENCodeContextOpcodes[bopADD]:=@TBESENCodeContext.OpADD; + BESENCodeContextOpcodes[bopADDNUM]:=@TBESENCodeContext.OpADDNUM; + BESENCodeContextOpcodes[bopSUB]:=@TBESENCodeContext.OpSUB; + BESENCodeContextOpcodes[bopSHL]:=@TBESENCodeContext.OpSHL; + BESENCodeContextOpcodes[bopSHR]:=@TBESENCodeContext.OpSHR; + BESENCodeContextOpcodes[bopUSHR]:=@TBESENCodeContext.OpUSHR; + BESENCodeContextOpcodes[bopLT]:=@TBESENCodeContext.OpLT; + BESENCodeContextOpcodes[bopGT]:=@TBESENCodeContext.OpGT; + BESENCodeContextOpcodes[bopLE]:=@TBESENCodeContext.OpLE; + BESENCodeContextOpcodes[bopGE]:=@TBESENCodeContext.OpGE; + BESENCodeContextOpcodes[bopINSTANCEOF]:=@TBESENCodeContext.OpINSTANCEOF; + BESENCodeContextOpcodes[bopIN]:=@TBESENCodeContext.OpIN; + BESENCodeContextOpcodes[bopEQ]:=@TBESENCodeContext.OpEQ; + BESENCodeContextOpcodes[bopSEQ]:=@TBESENCodeContext.OpSEQ; + BESENCodeContextOpcodes[bopBAND]:=@TBESENCodeContext.OpBAND; + BESENCodeContextOpcodes[bopBXOR]:=@TBESENCodeContext.OpBXOR; + BESENCodeContextOpcodes[bopBOR]:=@TBESENCodeContext.OpBOR; + BESENCodeContextOpcodes[bopSENUM]:=@TBESENCodeContext.OpSENUM; + BESENCodeContextOpcodes[bopSWITH]:=@TBESENCodeContext.OpSWITH; + BESENCodeContextOpcodes[bopSCATCH]:=@TBESENCodeContext.OpSCATCH; + BESENCodeContextOpcodes[bopENDF]:=@TBESENCodeContext.OpENDF; + BESENCodeContextOpcodes[bopJMP]:=@TBESENCodeContext.OpJMP; + BESENCodeContextOpcodes[bopJZ]:=@TBESENCodeContext.OpJZ; + BESENCodeContextOpcodes[bopJNZ]:=@TBESENCodeContext.OpJNZ; + BESENCodeContextOpcodes[bopJNULL]:=@TBESENCodeContext.OpJNULL; + BESENCodeContextOpcodes[bopLOOPENUM]:=@TBESENCodeContext.OpLOOPENUM; + BESENCodeContextOpcodes[bopSTRYC]:=@TBESENCodeContext.OpSTRYC; + BESENCodeContextOpcodes[bopSTRYF]:=@TBESENCodeContext.OpSTRYF; + BESENCodeContextOpcodes[bopLITERAL]:=@TBESENCodeContext.OpLITERAL; + BESENCodeContextOpcodes[bopLITERALUNDEF]:=@TBESENCodeContext.OpLITERALUNDEF; + BESENCodeContextOpcodes[bopLITERALNULL]:=@TBESENCodeContext.OpLITERALNULL; + BESENCodeContextOpcodes[bopLITERALBOOL]:=@TBESENCodeContext.OpLITERALBOOL; + BESENCodeContextOpcodes[bopLITERALNUM]:=@TBESENCodeContext.OpLITERALNUM; + BESENCodeContextOpcodes[bopLITERALSTR]:=@TBESENCodeContext.OpLITERALSTR; + BESENCodeContextOpcodes[bopLITERALOBJ]:=@TBESENCodeContext.OpLITERALOBJ; + BESENCodeContextOpcodes[bopFUNC]:=@TBESENCodeContext.OpFUNC; + BESENCodeContextOpcodes[bopLINE]:=@TBESENCodeContext.OpLINE; + BESENCodeContextOpcodes[bopGC]:=@TBESENCodeContext.OpGC; + BESENCodeContextOpcodes[bopSTRICT]:=@TBESENCodeContext.OpSTRICT; + BESENCodeContextOpcodes[bopSTRICTCHECKREF]:=@TBESENCodeContext.OpSTRICTCHECKREF; + BESENCodeContextOpcodes[bopDEBUGGER]:=@TBESENCodeContext.OpDEBUGGER; + BESENCodeContextOpcodes[bopCHECKOBJECTCOERCIBLE]:=@TBESENCodeContext.OpCHECKOBJECTCOERCIBLE; + BESENCodeContextOpcodes[bopPUTOBJVALUE]:=@TBESENCodeContext.OpPUTOBJVALUE; + BESENCodeContextOpcodes[bopPUTOBJGET]:=@TBESENCodeContext.OpPUTOBJGET; + BESENCodeContextOpcodes[bopPUTOBJSET]:=@TBESENCodeContext.OpPUTOBJSET; + BESENCodeContextOpcodes[bopINC]:=@TBESENCodeContext.OpINC; + BESENCodeContextOpcodes[bopDEC]:=@TBESENCodeContext.OpDEC; + BESENCodeContextOpcodes[bopCOPYBOOL]:=@TBESENCodeContext.OpCOPYBOOL; + BESENCodeContextOpcodes[bopCOPYNUM]:=@TBESENCodeContext.OpCOPYNUM; + BESENCodeContextOpcodes[bopCOPYSTR]:=@TBESENCodeContext.OpCOPYSTR; + BESENCodeContextOpcodes[bopCOPYOBJ]:=@TBESENCodeContext.OpCOPYOBJ; + BESENCodeContextOpcodes[bopCOPYREF]:=@TBESENCodeContext.OpCOPYREF; + BESENCodeContextOpcodes[bopCOPYLOCAL]:=@TBESENCodeContext.OpCOPYLOCAL; + BESENCodeContextOpcodes[bopGETVALUEREF]:=@TBESENCodeContext.OpGETVALUEREF; + BESENCodeContextOpcodes[bopPUTVALUEREF]:=@TBESENCodeContext.OpPUTVALUEREF; + BESENCodeContextOpcodes[bopGETVALUELOCAL]:=@TBESENCodeContext.OpGETVALUELOCAL; + BESENCodeContextOpcodes[bopPUTVALUELOCAL]:=@TBESENCodeContext.OpPUTVALUELOCAL; + BESENCodeContextOpcodes[bopGETVALUELOCALFAST]:=@TBESENCodeContext.OpGETVALUELOCALFAST; + BESENCodeContextOpcodes[bopPUTVALUELOCALFAST]:=@TBESENCodeContext.OpPUTVALUELOCALFAST; + BESENCodeContextOpcodes[bopGETVALUELOCALBOOL]:=@TBESENCodeContext.OpGETVALUELOCALBOOL; + BESENCodeContextOpcodes[bopPUTVALUELOCALBOOL]:=@TBESENCodeContext.OpPUTVALUELOCALBOOL; + BESENCodeContextOpcodes[bopGETVALUELOCALNUM]:=@TBESENCodeContext.OpGETVALUELOCALNUM; + BESENCodeContextOpcodes[bopPUTVALUELOCALNUM]:=@TBESENCodeContext.OpPUTVALUELOCALNUM; + BESENCodeContextOpcodes[bopGETVALUELOCALSTR]:=@TBESENCodeContext.OpGETVALUELOCALSTR; + BESENCodeContextOpcodes[bopPUTVALUELOCALSTR]:=@TBESENCodeContext.OpPUTVALUELOCALSTR; + BESENCodeContextOpcodes[bopGETVALUELOCALOBJ]:=@TBESENCodeContext.OpGETVALUELOCALOBJ; + BESENCodeContextOpcodes[bopPUTVALUELOCALOBJ]:=@TBESENCodeContext.OpPUTVALUELOCALOBJ; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEX]:=@TBESENCodeContext.OpGETVALUELOCALINDEX; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEX]:=@TBESENCodeContext.OpPUTVALUELOCALINDEX; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXBOOL]:=@TBESENCodeContext.OpGETVALUELOCALINDEXBOOL; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXBOOL]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXBOOL; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXNUM]:=@TBESENCodeContext.OpGETVALUELOCALINDEXNUM; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXNUM]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXNUM; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXSTR]:=@TBESENCodeContext.OpGETVALUELOCALINDEXSTR; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXSTR]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXSTR; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXOBJ]:=@TBESENCodeContext.OpGETVALUELOCALINDEXOBJ; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXOBJ]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXOBJ; + BESENCodeContextOpcodes[bopLOOPINITCOUNT]:=@TBESENCodeContext.OpLOOPINITCOUNT; + BESENCodeContextOpcodes[bopLOOPADDCOUNT]:=@TBESENCodeContext.OpLOOPADDCOUNT; + BESENCodeContextOpcodes[bopTRACE]:=@TBESENCodeContext.OpTRACE; + BESENCodeContextOpcodes[bopLTBOOL]:=@TBESENCodeContext.OpLTBOOL; + BESENCodeContextOpcodes[bopGTBOOL]:=@TBESENCodeContext.OpGTBOOL; + BESENCodeContextOpcodes[bopLEBOOL]:=@TBESENCodeContext.OpLEBOOL; + BESENCodeContextOpcodes[bopGEBOOL]:=@TBESENCodeContext.OpGEBOOL; + BESENCodeContextOpcodes[bopEQBOOL]:=@TBESENCodeContext.OpEQBOOL; + BESENCodeContextOpcodes[bopNEQBOOL]:=@TBESENCodeContext.OpNEQBOOL; + BESENCodeContextOpcodes[bopLTNUM]:=@TBESENCodeContext.OpLTNUM; + BESENCodeContextOpcodes[bopGTNUM]:=@TBESENCodeContext.OpGTNUM; + BESENCodeContextOpcodes[bopLENUM]:=@TBESENCodeContext.OpLENUM; + BESENCodeContextOpcodes[bopGENUM]:=@TBESENCodeContext.OpGENUM; + BESENCodeContextOpcodes[bopEQNUM]:=@TBESENCodeContext.OpEQNUM; + BESENCodeContextOpcodes[bopNEQNUM]:=@TBESENCodeContext.OpNEQNUM; + BESENCodeContextOpcodes[bopLTSTR]:=@TBESENCodeContext.OpLTSTR; + BESENCodeContextOpcodes[bopGTSTR]:=@TBESENCodeContext.OpGTSTR; + BESENCodeContextOpcodes[bopLESTR]:=@TBESENCodeContext.OpLESTR; + BESENCodeContextOpcodes[bopGESTR]:=@TBESENCodeContext.OpGESTR; + BESENCodeContextOpcodes[bopEQSTR]:=@TBESENCodeContext.OpEQSTR; + BESENCodeContextOpcodes[bopNEQSTR]:=@TBESENCodeContext.OpNEQSTR; + BESENCodeContextOpcodes[bopSHLBOOL]:=@TBESENCodeContext.OpSHLBOOL; + BESENCodeContextOpcodes[bopSHRBOOL]:=@TBESENCodeContext.OpSHRBOOL; + BESENCodeContextOpcodes[bopBANDBOOL]:=@TBESENCodeContext.OpBANDBOOL; + BESENCodeContextOpcodes[bopBXORBOOL]:=@TBESENCodeContext.OpBXORBOOL; + BESENCodeContextOpcodes[bopBORBOOL]:=@TBESENCodeContext.OpBORBOOL; + BESENCodeContextOpcodes[bopSHLNUM]:=@TBESENCodeContext.OpSHLNUM; + BESENCodeContextOpcodes[bopSHRNUM]:=@TBESENCodeContext.OpSHRNUM; + BESENCodeContextOpcodes[bopUSHRNUM]:=@TBESENCodeContext.OpUSHRNUM; + BESENCodeContextOpcodes[bopBANDNUM]:=@TBESENCodeContext.OpBANDNUM; + BESENCodeContextOpcodes[bopBXORNUM]:=@TBESENCodeContext.OpBXORNUM; + BESENCodeContextOpcodes[bopBORNUM]:=@TBESENCodeContext.OpBORNUM; + BESENCodeContextOpcodes[bopSETCUNDEF]:=@TBESENCodeContext.OpSETCUNDEF; + BESENCodeContextOpcodes[bopSETCNULL]:=@TBESENCodeContext.OpSETCNULL; + BESENCodeContextOpcodes[bopSETCBOOL]:=@TBESENCodeContext.OpSETCBOOL; + BESENCodeContextOpcodes[bopSETCNUM]:=@TBESENCodeContext.OpSETCNUM; + BESENCodeContextOpcodes[bopSETCSTR]:=@TBESENCodeContext.OpSETCSTR; + BESENCodeContextOpcodes[bopSETCOBJ]:=@TBESENCodeContext.OpSETCOBJ; + BESENCodeContextOpcodes[bopTRACENEW]:=@TBESENCodeContext.OpTRACENEW; + BESENCodeContextOpcodes[bopTRACECALL]:=@TBESENCodeContext.OpTRACECALL; + BESENCodeContextOpcodes[bopLTNUMCONST]:=@TBESENCodeContext.OpLTNUMCONST; + BESENCodeContextOpcodes[bopGTNUMCONST]:=@TBESENCodeContext.OpGTNUMCONST; + BESENCodeContextOpcodes[bopLENUMCONST]:=@TBESENCodeContext.OpLENUMCONST; + BESENCodeContextOpcodes[bopGENUMCONST]:=@TBESENCodeContext.OpGENUMCONST; + BESENCodeContextOpcodes[bopEQNUMCONST]:=@TBESENCodeContext.OpEQNUMCONST; + BESENCodeContextOpcodes[bopNEQNUMCONST]:=@TBESENCodeContext.OpNEQNUMCONST; + BESENCodeContextOpcodes[bopJZERO]:=@TBESENCodeContext.OpJZERO; + BESENCodeContextOpcodes[bopJNZERO]:=@TBESENCodeContext.OpJNZERO; +end; + +procedure InitBESEN; +begin + InitOpcodes; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENCodeGeneratorContext.pas b/3rd/besen/src/BESENCodeGeneratorContext.pas new file mode 100644 index 000000000..efdb0aac7 --- /dev/null +++ b/3rd/besen/src/BESENCodeGeneratorContext.pas @@ -0,0 +1,531 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeGeneratorContext; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENHashMap; + +type TBESENCodeGeneratorContextVariableScope=record + Ident:TBESENString; + ID:integer; + InScope:longbool; + ValueType:TBESENValueType; + Initialized:longbool; + MutableOrDeletable:longbool; + RegNr:integer; + end; + + TBESENCodeGeneratorContextVariableScopes=array of TBESENCodeGeneratorContextVariableScope; + + TBESENCodeGeneratorContextPatchables=class(TBESENBaseObject) + public + Continues:TBESENIntegers; + Breaks:TBESENIntegers; + CountContinues:integer; + CountBreaks:integer; + Previous:TBESENCodeGeneratorContextPatchables; + Continuable:longbool; + BlockDepth:integer; + Target:integer; + ContinueValueTypesItems:TBESENValueTypesItems; + BreakValueTypesItems:TBESENValueTypesItems; + CountContinueValueTypesItems:integer; + CountBreakValueTypesItems:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure AddContinue(Address:integer;const ValueTypes:TBESENValueTypes); + procedure AddBreak(Address:integer;const ValueTypes:TBESENValueTypes); + end; + + TBESENCodeGeneratorContextRegister=record + IsWhat:longword; + IsLocal:longbool; + LocalIndex:longint; + ReferenceValueType:TBESENValueType; + InUse:longbool; + Variable:longint; + end; + + TBESENCodeGeneratorContextRegisters=array of TBESENCodeGeneratorContextRegister; + + TBESENCodeGeneratorContextRegisterStates=record + Registers:TBESENCodeGeneratorContextRegisters; + MaxRegisters:integer; + end; + + TBESENCodeGeneratorContext=class(TBESENBaseObject) + public + Next:TBESENCodeGeneratorContext; + Code:TObject; + BlockDepth:integer; + MaxBlockDepth:integer; + LoopDepth:integer; + MaxLoopDepth:integer; + MaxParamArgs:integer; + Patchables:TBESENCodeGeneratorContextPatchables; + VariableScopes:TBESENCodeGeneratorContextVariableScopes; + CountVariableScopes:integer; + InVariableScope:longbool; + VariableScopeHashMap:TBESENHashMap; + VariableNameHashMap:TBESENHashMap; + Registers:TBESENCodeGeneratorContextRegisters; + MaxRegisters:integer; + LookupHashMap:TBESENHashMap; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure PushPatchables(Target:integer;Continuable:boolean); + procedure PopPatchables(ContinueAddr,BreakAddr:integer); + function FindPatchables(Target:integer;Continuable:boolean):TBESENCodeGeneratorContextPatchables; + procedure BlockEnter; + procedure BlockLeave; + function BlockCurrent:integer; + function AllocateRegister:integer; + procedure DeallocateRegister(var RegNr:integer); + procedure GetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); + procedure SetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); + function VariableIndex(const Ident:TBESENString):integer; + function VariableGetInitialized(const Ident:TBESENString):TBESENBoolean; + function VariableGetMutableOrDeletable(const Ident:TBESENString):TBESENBoolean; + procedure VariableSetFlags(const Ident:TBESENString;const Initialized,MutableOrDeletable:boolean); + function VariableGetRegister(const Ident:TBESENString):integer; + procedure VariableSetRegister(const Ident:TBESENString;const RegNr:integer); + function VariableGetType(const Ident:TBESENString):TBESENValueType; + procedure VariableSetType(const Ident:TBESENString;const ValueType:TBESENValueType); + procedure VariableAllSetType(const ValueType:TBESENValueType); + function VariableGetTypes:TBESENValueTypes; + procedure VariableSetTypes(const ValueTypes:TBESENValueTypes); + function VariableGetIdent(const Index:integer):TBESENString; + function VariableID(const Ident:TBESENString):integer; + function IsVariableInScope(const Ident:TBESENString):boolean; + procedure VariableSetScope(const Ident:TBESENString;IsInScope,IsParameter:boolean;ParameterIndex:integer); + function VariableSetAllScope(IsInScope:boolean):boolean; + end; + +implementation + +uses BESEN,BESENUtils,BESENCode; + +constructor TBESENCodeGeneratorContextPatchables.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Continues:=nil; + Breaks:=nil; + CountContinues:=0; + CountBreaks:=0; + Previous:=nil; + Continuable:=false; + BlockDepth:=0; + Target:=0; + ContinueValueTypesItems:=nil; + BreakValueTypesItems:=nil; + CountContinueValueTypesItems:=0; + CountBreakValueTypesItems:=0; +end; + +destructor TBESENCodeGeneratorContextPatchables.Destroy; +begin + SetLength(Continues,0); + SetLength(Breaks,0); + SetLength(ContinueValueTypesItems,0); + SetLength(BreakValueTypesItems,0); + inherited Destroy; +end; + +procedure TBESENCodeGeneratorContextPatchables.AddContinue(Address:integer;const ValueTypes:TBESENValueTypes); +begin + if CountContinues>=length(Continues) then begin + SetLength(Continues,CountContinues+256); + end; + Continues[CountContinues]:=Address; + inc(CountContinues); + if CountContinueValueTypesItems>=length(ContinueValueTypesItems) then begin + SetLength(ContinueValueTypesItems,CountContinueValueTypesItems+256); + end; + ContinueValueTypesItems[CountContinueValueTypesItems]:=copy(ValueTypes,0,length(ValueTypes)); + inc(CountContinueValueTypesItems); +end; + +procedure TBESENCodeGeneratorContextPatchables.AddBreak(Address:integer;const ValueTypes:TBESENValueTypes); +begin + if CountBreaks>=length(Breaks) then begin + SetLength(Breaks,CountBreaks+256); + end; + Breaks[CountBreaks]:=Address; + inc(CountBreaks); + if CountBreakValueTypesItems>=length(BreakValueTypesItems) then begin + SetLength(BreakValueTypesItems,CountBreakValueTypesItems+256); + end; + BreakValueTypesItems[CountBreakValueTypesItems]:=copy(ValueTypes,0,length(ValueTypes)); + inc(CountBreakValueTypesItems); +end; + +constructor TBESENCodeGeneratorContext.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Next:=nil; + Code:=nil; + BlockDepth:=0; + MaxBlockDepth:=0; + LoopDepth:=0; + MaxLoopDepth:=0; + MaxParamArgs:=0; + Patchables:=nil; + VariableScopes:=nil; + CountVariableScopes:=0; + InVariableScope:=true; + VariableScopeHashMap:=TBESENHashMap.Create; + VariableNameHashMap:=TBESENHashMap.Create; + Registers:=nil; + MaxRegisters:=0; + LookupHashMap:=TBESENHashMap.Create; +end; + +destructor TBESENCodeGeneratorContext.Destroy; +var NextPatchables:TBESENCodeGeneratorContextPatchables; +begin + BESENFreeAndNil(LookupHashMap); + while assigned(Patchables) do begin + NextPatchables:=Patchables.Previous; + Patchables.Free; + Patchables:=NextPatchables; + end; + SetLength(Registers,0); + SetLength(VariableScopes,0); + VariableScopeHashMap.Free; + VariableNameHashMap.Free; + inherited Destroy; +end; + +procedure TBESENCodeGeneratorContext.PushPatchables(Target:integer;Continuable:boolean); +var p:TBESENCodeGeneratorContextPatchables; +begin + p:=TBESENCodeGeneratorContextPatchables.Create(Instance); + p.Target:=Target; + p.Continuable:=Continuable; + p.Previous:=Patchables; + p.BlockDepth:=BlockDepth; + Patchables:=p; +end; + +procedure TBESENCodeGeneratorContext.PopPatchables(ContinueAddr,BreakAddr:integer); +var i:integer; + p:TBESENCodeGeneratorContextPatchables; +begin + p:=Patchables; + if ContinueAddr>=0 then begin + for i:=0 to p.CountContinues-1 do begin + TBESENCode(Code).Patch(p.Continues[i],ContinueAddr); + end; + end; + if BreakAddr>=0 then begin + for i:=0 to p.CountBreaks-1 do begin + TBESENCode(Code).Patch(p.Breaks[i],BreakAddr); + end; + end; + Patchables:=p.Previous; + BESENFreeAndNil(p); +end; + +function TBESENCodeGeneratorContext.FindPatchables(Target:integer;Continuable:boolean):TBESENCodeGeneratorContextPatchables; +var p:TBESENCodeGeneratorContextPatchables; +begin + result:=nil; + if (Target=bcttNOTARGET) and Continuable then begin + p:=Patchables; + while assigned(p) do begin + if p.Continuable then begin + result:=p; + break; + end; + p:=p.Previous; + end; + end else if Target=bcttNOTARGET then begin + result:=Patchables; + end else begin + p:=Patchables; + while assigned(p) do begin + if p.Target=Target then begin + result:=p; + break; + end; + p:=p.Previous; + end; + end; +{$ifdef UseAssert} + Assert(assigned(result),'Lost patchable'); +{$endif} +end; + +procedure TBESENCodeGeneratorContext.BlockEnter; +begin + inc(BlockDepth); + if MaxBlockDepth<BlockDepth then begin + MaxBlockDepth:=BlockDepth; + end; +end; + +procedure TBESENCodeGeneratorContext.BlockLeave; +begin + dec(BlockDepth); +end; + +function TBESENCodeGeneratorContext.BlockCurrent:integer; +begin + result:=BlockDepth; +end; + +function TBESENCodeGeneratorContext.AllocateRegister:integer; +var i:integer; +begin + result:=-1; + for i:=0 to MaxRegisters-1 do begin + if not Registers[i].InUse then begin + result:=i; + break; + end; + end; + if result<0 then begin + result:=MaxRegisters; + inc(MaxRegisters); + if result>=length(Registers) then begin + SetLength(Registers,result+256); + end; + end; + Registers[result].InUse:=true; + Registers[result].IsWhat:=0; + Registers[result].IsLocal:=false; + Registers[result].LocalIndex:=-1; + Registers[result].Variable:=-1; +end; + +procedure TBESENCodeGeneratorContext.DeallocateRegister(var RegNr:integer); +begin + if ((RegNr>=0) and (RegNr<MaxRegisters)) and not (Registers[RegNr].Variable>=0) then begin + Registers[RegNr].InUse:=false; + Registers[RegNr].IsWhat:=0; + Registers[RegNr].IsLocal:=false; + Registers[RegNr].LocalIndex:=-1; + end; + RegNr:=-1; +end; + +procedure TBESENCodeGeneratorContext.GetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); +begin + RegisterStates.Registers:=copy(Registers,0,length(Registers)); + RegisterStates.MaxRegisters:=MaxRegisters; +end; + +procedure TBESENCodeGeneratorContext.SetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); +begin + Registers:=copy(RegisterStates.Registers,0,length(RegisterStates.Registers)); + MaxRegisters:=RegisterStates.MaxRegisters; +end; + +function TBESENCodeGeneratorContext.VariableIndex(const Ident:TBESENString):integer; +var Item:PBESENHashMapItem; +begin + Item:=VariableScopeHashMap.GetKey(Ident); + if assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetInitialized(const Ident:TBESENString):TBESENBoolean; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].Initialized; + end else begin + result:=false; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetMutableOrDeletable(const Ident:TBESENString):TBESENBoolean; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].MutableOrDeletable; + end else begin + result:=false; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetFlags(const Ident:TBESENString;const Initialized,MutableOrDeletable:boolean); +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].Initialized:=Initialized; + VariableScopes[i].MutableOrDeletable:=MutableOrDeletable; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetRegister(const Ident:TBESENString):integer; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].RegNr; + end else begin + result:=-1; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetRegister(const Ident:TBESENString;const RegNr:integer); +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].RegNr:=RegNr; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetType(const Ident:TBESENString):TBESENValueType; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].ValueType; + end else begin + result:=bvtUNDEFINED; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetType(const Ident:TBESENString;const ValueType:TBESENValueType); +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].ValueType:=ValueType; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableAllSetType(const ValueType:TBESENValueType); +var i:integer; +begin + for i:=0 to CountVariableScopes-1 do begin + VariableScopes[i].ValueType:=ValueType; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetTypes:TBESENValueTypes; +var i:integer; +begin + SetLength(result,CountVariableScopes); + for i:=0 to CountVariableScopes-1 do begin + result[i]:=VariableScopes[i].ValueType; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetTypes(const ValueTypes:TBESENValueTypes); +var i,j:integer; +begin + j:=CountVariableScopes; + if j>length(ValueTypes) then begin + j:=length(ValueTypes); + end; + for i:=0 to j-1 do begin + VariableScopes[i].ValueType:=ValueTypes[i]; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetIdent(const Index:integer):TBESENString; +begin + if (Index>=0) and (Index<CountVariableScopes) then begin + result:=VariableScopes[Index].Ident; + end else begin + result:=''; + end; +end; + +function TBESENCodeGeneratorContext.VariableID(const Ident:TBESENString):integer; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].ID; + end else begin + result:=-1; + end; +end; + +function TBESENCodeGeneratorContext.IsVariableInScope(const Ident:TBESENString):boolean; +var i:integer; +begin + result:=false; + if InVariableScope then begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].InScope; + end; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetScope(const Ident:TBESENString;IsInScope,IsParameter:boolean;ParameterIndex:integer); +var i:integer; + Item:PBESENHashMapItem; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].InScope:=IsInScope; + end else begin + if IsInScope then begin + if CountVariableScopes>=length(VariableScopes) then begin + SetLength(VariableScopes,CountVariableScopes+256); + end; + VariableScopes[CountVariableScopes].Ident:=Ident; + VariableScopes[CountVariableScopes].ID:=TBESENCode(Code).GenVariable(Ident,IsParameter,ParameterIndex,self); + VariableScopes[CountVariableScopes].InScope:=IsInScope; + VariableScopes[CountVariableScopes].Initialized:=false; + VariableScopes[CountVariableScopes].MutableOrDeletable:=false; + VariableScopes[CountVariableScopes].ValueType:=bvtUNDEFINED; + VariableScopes[CountVariableScopes].RegNr:=-1; + Item:=VariableScopeHashMap.NewKey(Ident,true); + Item^.Value:=CountVariableScopes; + inc(CountVariableScopes); + end; + end; +end; + +function TBESENCodeGeneratorContext.VariableSetAllScope(IsInScope:boolean):boolean; +begin + result:=InVariableScope; + InVariableScope:=IsInScope; +end; + +end. diff --git a/3rd/besen/src/BESENCodeJIT.pas b/3rd/besen/src/BESENCodeJIT.pas new file mode 100644 index 000000000..30634221f --- /dev/null +++ b/3rd/besen/src/BESENCodeJIT.pas @@ -0,0 +1,89 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeJIT; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}BESENConstants,BESENTypes; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} + +implementation + +{ + +Base JIT design concept: + + 1. It is mostly a damn simple method-based native-code-template-concatenation JIT mostly without any + fancy optimizations just as CSE, SSA, and so on. + + 2. The native code execution can be continued from any correspondent byte code instruction, so it + is possible to jump to any byte-code-instruction-mapped native-code-sub-block from any each + other in the same code context and in the same code instande. + + 3. The from the JIT generated native code can call the correspondent byte code instruction dispatcher + function from the byte code interpreter at every time, if it needed, for example, for complex byte + code instructions which are more trouble than it's worth to compile these to native code. + + 4. The virtual byte code interpreter VM registers are used instead the native platform target CPU + registers, for to keep the fallback-to-byte-code-instruction-dispatcher-function-stuff simple just + much as possible. + + 5. The from the JIT generated native code can be self-modifying, for example at the monomorphic and + polymorphic inline caching based byte code instructions, by modifying some index constant values + at some native code instruction opcode arguments. But this is optional, since the byte code itself + is also self-modifying in this monomorphic and polymorphic inline caching context. It's mostly a + trade-off, which way performs better on which target platform CPU architecture. + + 6. A byte-code-instruction-offset <-> native-code-instruction-offset map must be generated and used + for the jump-in-to-random-code-position-usage and for the effective use of the fallback-to-byte- + code-instruction-dispatcher-function-stuff. + +} + +uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, + BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, + BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +begin + result:=false; +end; + +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +begin + result:=false; +end; + +end. diff --git a/3rd/besen/src/BESENCodeJITx64.pas b/3rd/besen/src/BESENCodeJITx64.pas new file mode 100644 index 000000000..dabc5ff85 --- /dev/null +++ b/3rd/besen/src/BESENCodeJITx64.pas @@ -0,0 +1,2229 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeJITx64; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}BESENConstants,BESENTypes; + +{$ifdef HasJIT} +{$ifdef cpuamd64} +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +{$endif} +{$endif} + +implementation + +{ + +Register layout: + + rbx = Offset to instance + r12 = Offset to code context + r13 = Offset to byte code <-> native code offset mapping map array + r14 = Offset to virtual VM registers + r15 = Offset to local hash table (only at function code, not at global code!) + others = for various temporary usage + +} + +{$ifdef HasJIT} +{$ifdef cpuamd64} +uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, + BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, + BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +type TFixupKind=(fkPTR,fkRET,fkOFS); + TFixup=record + Kind:TFixupKind; + Ofs:integer; + Dest:pointer; + ToOfs:integer; + end; + TFixups=array of TFixup; +var Fixups:TFixups; + CountFixups,i:integer; + Offsets:array of longword; + Opcode:byte; + Instruction:TBESENUINT32; + CodeBuffer:TBESENBytes; + CodeBufferLen:integer; + CurrentPC,Temp,RetOfs,Literal:longword; + CodeBegin,CodeEnd:pointer; + ByteCode:PBESENUINT32Array; + Operands:PBESENINT32Array; + Code:TBESENCode; + CodeContext:TBESENCodeContext; + v:TBESENValue; + procedure Add(const s:TBESENANSISTRING); + begin + if length(s)>0 then begin + if (CodeBufferLen+length(s))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+length(s)+4096) and not 4095); + end; + move(s[1],CodeBuffer[CodeBufferLen],length(s)); + inc(CodeBufferLen,length(s)); + end; + end; + procedure AddCode(CodeBegin,CodeEnd:pointer); + var CodeLen:ptrint; +{$ifdef windows} + OldProtect,OldProtectDummy:longword; + OK:boolean; +{$endif} + begin + CodeLen:=ptrint(ptruint(CodeEnd)-ptruint(CodeBegin)); + if CodeLen>0 then begin +{$ifdef windows} + OK:=VirtualProtect(CodeBegin,CodeLen,PAGE_EXECUTE_READWRITE,OldProtect); +{$endif} +{$ifdef unix} + fpmprotect(CodeBegin,CodeLen,PROT_READ or PROT_WRITE or PROT_EXEC); +{$endif} + if (CodeBufferLen+CodeLen)>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+CodeLen+4096) and not 4095); + end; + move(CodeBegin^,CodeBuffer[CodeBufferLen],CodeLen); + inc(CodeBufferLen,CodeLen); +{$ifdef windows} + if OK then begin + VirtualProtect(CodeBegin,CodeLen,OldProtect,OldProtectDummy); + end; +{$endif} + end; + end; + procedure AddDWord(const v:longword); + begin + if (CodeBufferLen+sizeof(longword))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(longword)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(longword)); + inc(CodeBufferLen,sizeof(longword)); + end; + procedure AddQWord(const v:qword); + begin + if (CodeBufferLen+sizeof(qword))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(qword)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(qword)); + inc(CodeBufferLen,sizeof(qword)); + end; + procedure AddPtr(const v:pointer); + begin + if (CodeBufferLen+sizeof(ptruint))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(ptruint)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(ptruint)); + inc(CodeBufferLen,sizeof(ptruint)); + end; + procedure AddDispatcher; + var Temp:qword; + CodeBegin,CodeEnd:pointer; + begin + case Opcode of + bopEND,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopTRACE,bopJZERO,bopJNZERO:begin + Add(#$41#$c7#$84#$24); // mov dword ptr [r12+TBESENCodeContext.PC],CurrentPC + asm + push rax + mov rax,offset TBESENCodeContext.PC + mov qword ptr Temp,rax + pop rax + end; + AddDWord(Temp); + AddDWord(CurrentPC); + end; + end; + +{$ifdef windows} + Add(#$4c#$89#$e1); // mov rcx,r12 +{$else} + Add(#$4c#$89#$e7); // mov rdi,r12 +{$endif} + +{$ifdef windows} + Add(#$48#$ba); // mov rdx,Operands +{$else} + Add(#$48#$be); // mov rsi,Operands +{$endif} + AddPtr(Operands); + + // mov rax,OpcodeDispatcher + Add(#$48#$b8); + AddPtr(BESENCodeContextOpcodes[Opcode]); + + // call rax + Add(#$ff#$d0); + + case Opcode of + bopEND,bopTRACE,bopENDF:begin + if (Opcode<>bopEND) or (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + cmp dword ptr [r12+TBESENCodeContext.BlockRunning],0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$84); // jz RET + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + end; + + case Opcode of + bopEND,bopENDF,bopJMP,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopJZERO,bopJNZERO:begin + asm + jmp @Skip + @CodeBegin: + xor rax,rax + mov eax,dword ptr [r12+TBESENCodeContext.PC] + jmp qword ptr [r13+rax*8] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + end; + + end; +begin + result:=false; + try + CodeContext:=TBESENCodeContext(ACodeContext); + Code:=TBESENCode(CodeContext.Code); + if assigned(Code.NativeCode) then begin + TBESEN(CodeContext.Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); + Code.NativeCode:=nil; + Code.NativeCodeSize:=0; + end; + CodeBuffer:=nil; + CodeBufferLen:=0; + CurrentPC:=0; + Fixups:=nil; + CountFixups:=0; + Offsets:=nil; + ByteCode:=@Code.ByteCode[0]; + SetLength(Offsets,Code.ByteCodeLen); + while CurrentPC<TBESENUINT32(Code.ByteCodeLen) do begin + Offsets[CurrentPC]:=CodeBufferLen; + Instruction:=ByteCode^[CurrentPC]; + Operands:=@ByteCode^[CurrentPC+1]; + inc(CurrentPC,1+(Instruction shr 8)); + Opcode:=Instruction and $ff; + + case Opcode of + bopSTOP:begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [r12+TBESENCodeContext.BlockRunning],0 + mov dword ptr [r12+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + bopNEW:begin + AddDispatcher; + end; + bopCALL:begin + AddDispatcher; + end; + bopEND:begin + if (Code.MaxBlock=0) and (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [r12+TBESENCodeContext.BlockRunning],0 + mov dword ptr [r12+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end else begin + AddDispatcher; + end; + end; + bopVREF:begin + AddDispatcher; + end; + bopLREF:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex],LocalIndex + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + AddDWord(Operands^[1]); + end; + bopNOP:begin + end; + bopCOPY:begin + AddDispatcher; + end; + bopNEQ:begin + AddDispatcher; + end; + bopNSEQ:begin + AddDispatcher; + end; + bopAREF:begin + AddDispatcher; + end; + bopTHROW:begin + AddDispatcher; + end; + bopSETC:begin + AddDispatcher; + end; + bopGETC:begin + AddDispatcher; + end; + bopTHIS:begin + AddDispatcher; + end; + bopOBJECT:begin + asm + jmp @Skip + @CodeBegin: + mov rax,qword ptr [rbx+TBESEN.ObjectConstructor] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopARRAY:begin + asm + jmp @Skip + @CodeBegin: + mov rax,qword ptr [rbx+TBESEN.ObjectArrayConstructor] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopREGEXP:begin + asm + jmp @Skip + @CodeBegin: + mov rax,qword ptr [rbx+TBESEN.ObjectRegExpConstructor] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopREF:begin + AddDispatcher; + end; + bopGETVALUE:begin + AddDispatcher; + end; + bopLOOKUP:begin + AddDispatcher; + end; + bopPUTVALUE:begin + AddDispatcher; + end; + bopDELETE:begin + AddDispatcher; + end; + bopTYPEOF:begin + AddDispatcher; + end; + bopTOOBJECT:begin + AddDispatcher; + end; + bopTONUMBER:begin + AddDispatcher; + end; + bopTOBOOLEAN:begin + AddDispatcher; + end; + bopTOSTRING:begin + AddDispatcher; + end; + bopTOPRIMITIVE:begin + AddDispatcher; + end; + bopNEG:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$41#$81#$b6); // xor dword ptr [r14+RegisterOfs+TBESENValue.Num+4],$80000000 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+((ptruint(pointer(@v.Num))+4)-ptruint(pointer(@v)))); + AddDWord($80000000); + end; + bopINV:begin + AddDispatcher; + end; + bopNOT:begin + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,$01 + sbb eax,eax + neg eax + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + bopMUL:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$59#$86); // mulsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDIV:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$5e#$86); // divsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopMOD:begin + AddDispatcher; + end; + bopADD:begin + AddDispatcher; + end; + bopADDNUM:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$58#$86); // addsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSUB:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$5c#$86); // subsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSHL:begin + AddDispatcher; + end; + bopSHR:begin + AddDispatcher; + end; + bopUSHR:begin + AddDispatcher; + end; + bopLT:begin + AddDispatcher; + end; + bopGT:begin + AddDispatcher; + end; + bopLE:begin + AddDispatcher; + end; + bopGE:begin + AddDispatcher; + end; + bopINSTANCEOF:begin + AddDispatcher; + end; + bopIN:begin + AddDispatcher; + end; + bopEQ:begin + AddDispatcher; + end; + bopSEQ:begin + AddDispatcher; + end; + bopBAND:begin + AddDispatcher; + end; + bopBXOR:begin + AddDispatcher; + end; + bopBOR:begin + AddDispatcher; + end; + bopSENUM:begin + AddDispatcher; + end; + bopSWITH:begin + AddDispatcher; + end; + bopSCATCH:begin + AddDispatcher; + end; + bopENDF:begin + AddDispatcher; + end; + bopJMP:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$e9); // jmp Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$41#$83#$be); // cmp dword ptr [r14+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$85); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$41#$83#$be); // cmp dword ptr [r14+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$84); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNULL:begin + AddDispatcher; + end; + bopLOOPENUM:begin + AddDispatcher; + end; + bopSTRYC:begin + AddDispatcher; + end; + bopSTRYF:begin + AddDispatcher; + end; + bopLITERALUNDEF:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtUNDEFINED + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtUNDEFINED); + end; + bopLITERALNULL:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNULL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNULL); + end; + bopLITERALBOOL:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],Bool + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + if Operands^[1]<>0 then begin + AddDWord(longword(pointer(@BESENLongBooleanValues[true])^)); + end else begin + AddDWord(longword(pointer(@BESENLongBooleanValues[false])^)); + end; + end; + bopLITERALNUM:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[1]].Num); + + Add(#$f2#$0f#$10#$00); // movsd xmm0,qword ptr [rax] + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopLITERALSTR:begin + AddDispatcher; + end; + bopLITERALOBJ:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$48#$b8); // mov rax,Obj + AddPtr(Code.Literals[Operands^[1]].Obj); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopFUNC:begin + AddDispatcher; + end; + bopLINE:begin + Add(#$b8); // mov eax,Arg + AddDWord(Code.Locations[Operands^[0]].LineNumber); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rbx+TBESEN.LineNumber],eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGC:begin + AddDispatcher; + end; + bopSTRICT:begin + Add(#$b8); // mov eax,Arg + AddDWord(longword(BESENLongBooleanValues[Operands^[0]<>0])); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rbx+TBESEN.IsStrict],eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSTRICTCHECKREF:begin + if not Code.Body.IsStrict then begin + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.ReferenceIsStrict] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v)))); + + Add(#$85#$c0); // test eax,rax + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=CurrentPC; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + + AddDispatcher; + end; + bopDEBUGGER:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopCHECKOBJECTCOERCIBLE:begin + AddDispatcher; + end; + bopPUTOBJVALUE:begin + AddDispatcher; + end; + bopPUTOBJGET:begin + AddDispatcher; + end; + bopPUTOBJSET:begin + AddDispatcher; + end; + bopINC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$48#$b8); // mov rax,offset BESENDoubleOne + AddPtr(@BESENDoubleOne); + + Add(#$f2#$0f#$10#$00); // movsd xmm0,qword ptr [rax] + + Add(#$f2#$41#$0f#$58#$86); // addsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDEC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset BESENDoubleOne + AddPtr(@BESENDoubleOne); + + Add(#$f2#$0f#$5c#$00); // subsd xmm0,qword ptr [rax] + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopCOPYBOOL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + end; + bopCOPYNUM:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + end; + bopCOPYOBJ:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$8b#$86); // mov rax,dword ptr [r14+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + + Add(#$49#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + end; + bopCOPYREF:begin + if Operands^[0]<>Operands^[1] then begin + AddDispatcher; + end; + end; + bopCOPYLOCAL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + end; + end; + bopGETVALUEREF:begin + AddDispatcher; + end; + bopPUTVALUEREF:begin + AddDispatcher; + end; + bopGETVALUELOCAL:begin + AddDispatcher; + end; + bopPUTVALUELOCAL:begin + AddDispatcher; + end; + bopGETVALUELOCALFAST:begin + AddDispatcher; + end; + bopPUTVALUELOCALFAST:begin + AddDispatcher; + end; + bopGETVALUELOCALBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rdx+TBESENValue.Bool] + mov dword ptr [rax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rax+TBESENValue.Bool] + mov dword ptr [rdx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rax+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rdx+TBESENValue.Num] + movsd qword ptr [rax+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rax+TBESENValue.Num] + movsd qword ptr [rdx+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rax+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rdx+TBESENValue.Obj] + mov qword ptr [rax+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rax+TBESENValue.Obj] + mov qword ptr [rdx+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEX:begin + AddDispatcher; + end; + bopPUTVALUELOCALINDEX:begin + AddDispatcher; + end; + bopGETVALUELOCALINDEXBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[1]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rdx+TBESENValue.Bool] + mov dword ptr [rax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[0]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rax+TBESENValue.Bool] + mov dword ptr [rdx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[1]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rax+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rdx+TBESENValue.Num] + movsd qword ptr [rax+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[0]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rax+TBESENValue.Num] + movsd qword ptr [rdx+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALINDEXOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[1]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rax+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rdx+TBESENValue.Obj] + mov qword ptr [rax+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[0]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rax+TBESENValue.Obj] + mov qword ptr [rdx+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopLOOPINITCOUNT:begin + end; + bopLOOPADDCOUNT:begin + end; + bopTRACE:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopLTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setnz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTSTR:begin + AddDispatcher; + end; + bopGTSTR:begin + AddDispatcher; + end; + bopLESTR:begin + AddDispatcher; + end; + bopGESTR:begin + AddDispatcher; + end; + bopEQSTR:begin + AddDispatcher; + end; + bopNEQSTR:begin + AddDispatcher; + end; + bopSHLBOOL:begin + AddDispatcher; + end; + bopSHRBOOL:begin + AddDispatcher; + end; + bopBANDBOOL:begin + AddDispatcher; + end; + bopBXORBOOL:begin + AddDispatcher; + end; + bopBORBOOL:begin + AddDispatcher; + end; + bopSHLNUM:begin + AddDispatcher; + end; + bopSHRNUM:begin + AddDispatcher; + end; + bopUSHRNUM:begin + AddDispatcher; + end; + bopBANDNUM:begin + AddDispatcher; + end; + bopBXORNUM:begin + AddDispatcher; + end; + bopBORNUM:begin + AddDispatcher; + end; + bopSETCUNDEF:begin + asm + jmp @Skip + @CodeBegin: + lea rax,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rax+TBESENValue.ValueType],bvtUNDEFINED + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNULL:begin + asm + jmp @Skip + @CodeBegin: + lea rax,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rax+TBESENValue.ValueType],bvtNULL + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rax+TBESENValue.Bool] + mov dword ptr [rdx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rax+TBESENValue.Num] + movsd qword ptr [rdx+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCSTR:begin + AddDispatcher; + end; + bopSETCOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rax+TBESENValue.Obj] + mov qword ptr [rdx+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopTRACENEW:begin + AddDispatcher; + end; + bopTRACECALL:begin + AddDispatcher; + end; + bopLTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + else begin + AddDispatcher; + end; + end; + + end; + RetOfs:=CodeBufferLen; + Add(#$c3); // ret + SetLength(CodeBuffer,CodeBufferLen); + Code.NativeCodeSize:=CodeBufferLen; + Code.NativeCode:=TBESEN(CodeContext.Instance).NativeCodeMemoryManager.GetMemory(Code.NativeCodeSize); + move(CodeBuffer[0],Code.NativeCode^,Code.NativeCodeSize); + SetLength(Code.NativeCodePCOffsets,Code.ByteCodeLen); + for i:=0 to Code.ByteCodeLen-1 do begin + Code.NativeCodePCOffsets[i]:=pointer(@PBESENByteArray(Code.NativeCode)[Offsets[i]]); + end; + for i:=0 to CountFixups-1 do begin + case FixUps[i].Kind of + fkPTR:begin + longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(FixUps[i].Dest)-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkRET:begin + longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[RetOfs]))-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkOFS:begin + longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(Code.NativeCodePCOffsets[FixUps[i].ToOfs])-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + end; + end; + result:=true; + finally + SetLength(Fixups,0); + SetLength(Offsets,0); + SetLength(CodeBuffer,0); + end; +end; + +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +var CodeContext:TBESENCodeContext; +begin + CodeContext:=TBESENCodeContext(ACodeContext); + CodeContext.BlockRunning:=true; + asm + push rax + push rbx + mov r12,qword ptr CodeContext + mov rbx,qword ptr [r12+TBESENCodeContext.Instance] + mov r13,qword ptr [r12+TBESENCodeContext.Code] + mov rax,qword ptr [r13+TBESENCode.Body] + mov r13,qword ptr [r13+TBESENCode.NativeCodePCOffsets] + mov r14,qword ptr [r12+TBESENCodeContext.RegisterValues] + xor r15,r15 + mov eax,dword ptr [rax+TBESENASTNodeFunctionBody.IsFunction] + test eax,eax + jz @IsNoFunction + mov r15,qword ptr [r12+TBESENCodeContext.Context] + mov r15,qword ptr [r15+TBESENContext.VariableEnvironment] + mov r15,qword ptr [r15+TBESENLexicalEnvironment.EnvironmentRecord] + mov r15,qword ptr [r15+TBESENDeclarativeEnvironmentRecord.HashValues] + @IsNoFunction: + xor rax,rax + mov eax,dword ptr [r12+TBESENCodeContext.PC] + call qword ptr [r13+rax*8] + pop rbx + pop rax + end ['rax','rbx','r12','r13','r14','r15']; + result:=CodeContext.BlockRunning; +end; +{$endif} +{$endif} + +end. diff --git a/3rd/besen/src/BESENCodeJITx86.pas b/3rd/besen/src/BESENCodeJITx86.pas new file mode 100644 index 000000000..0f9a153ec --- /dev/null +++ b/3rd/besen/src/BESENCodeJITx86.pas @@ -0,0 +1,2552 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeJITx86; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}BESENConstants,BESENTypes; + +{$ifdef HasJIT} +{$ifdef cpu386} +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +{$endif} +{$endif} + +implementation + +{ + +Register layout: + + esi = Offset to code context + edi = Offset to virtual VM registers + ebp = Offset to byte code <-> native code offset mapping map array + others = for various temporary usage + +} + +{$ifdef HasJIT} +{$ifdef cpu386} +uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, + BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, + BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager, + BESENObject,BESENObjectEnvironmentRecord; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +const sizeofTBESENValue=sizeof(TBESENValue); +type TFixupKind=(fkPTR,fkRET,fkOFS); + TFixup=record + Kind:TFixupKind; + Ofs:integer; + Dest:pointer; + ToOfs:integer; + end; + TFixups=array of TFixup; +var Fixups:TFixups; + CountFixups,i:integer; + Offsets:array of longword; + Opcode:byte; + Instruction:TBESENUINT32; + CodeBuffer:TBESENBytes; + CodeBufferLen,OldCodeBufferLen:integer; + CurrentPC,Temp,RetOfs,Literal:longword; + CodeBegin,CodeEnd:pointer; + CodeVars:array[0..8] of pointer; + ByteCode:PBESENUINT32Array; + Operands:PBESENINT32Array; + Code:TBESENCode; + CodeContext:TBESENCodeContext; + v:TBESENValue; + procedure Add(const s:TBESENANSISTRING); + begin + if length(s)>0 then begin + if (CodeBufferLen+length(s))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+length(s)+4096) and not 4095); + end; + move(s[1],CodeBuffer[CodeBufferLen],length(s)); + inc(CodeBufferLen,length(s)); + end; + end; + procedure AddCode(CodeBegin,CodeEnd:pointer); + var CodeLen:ptrint; +{$ifdef windows} + OldProtect,OldProtectDummy:longword; + OK:boolean; +{$endif} + begin + CodeLen:=ptrint(ptruint(CodeEnd)-ptruint(CodeBegin)); + if CodeLen>0 then begin +{$ifdef windows} + OK:=VirtualProtect(CodeBegin,CodeLen,PAGE_EXECUTE_READWRITE,OldProtect); +{$endif} +{$ifdef unix} + fpmprotect(CodeBegin,CodeLen,PROT_READ or PROT_WRITE or PROT_EXEC); +{$endif} + if (CodeBufferLen+CodeLen)>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+CodeLen+4096) and not 4095); + end; + move(CodeBegin^,CodeBuffer[CodeBufferLen],CodeLen); + inc(CodeBufferLen,CodeLen); +{$ifdef windows} + if OK then begin + VirtualProtect(CodeBegin,CodeLen,OldProtect,OldProtectDummy); + end; +{$endif} + end; + end; + procedure AddDWord(const v:longword); + begin + if (CodeBufferLen+sizeof(longword))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(longword)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(longword)); + inc(CodeBufferLen,sizeof(longword)); + end; + procedure AddDispatcherPointer; + begin + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkPTR; + Fixups[CountFixups].Ofs:=CodeBufferLen-4; + Fixups[CountFixups].Dest:=BESENCodeContextOpcodes[Opcode]; + inc(CountFixups); + end; + procedure AddDispatcher; + var Temp:longword; + CodeBegin,CodeEnd:pointer; + begin + Add(#$89#$f0); // mov eax,esi + + case Opcode of + bopEND,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopTRACE,bopJZERO,bopJNZERO:begin + Add(#$c7#$80); // mov dword ptr [eax+TBESENCodeContext.PC],CurrentPC + asm + mov dword ptr Temp,offset TBESENCodeContext.PC + end; + AddDWord(Temp); + AddDWord(CurrentPC); + end; + end; + + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$e8); // call OpcodeDispatcher + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkPTR; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].Dest:=BESENCodeContextOpcodes[Opcode]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + + case Opcode of + bopEND,bopTRACE,bopENDF:begin + if (Opcode<>bopEND) or (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + cmp dword ptr [esi+TBESENCodeContext.BlockRunning],0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$84); // jz RET + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + end; + + case Opcode of + bopEND,bopENDF,bopJMP,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopJZERO,bopJNZERO:begin + asm + jmp @Skip + @CodeBegin: +// mov ebp,dword ptr [esi+TBESENCodeContext.Code] +// mov ebp,dword ptr [ebp+TBESENCode.NativeCodePCOffsets] + mov edx,dword ptr [esi+TBESENCodeContext.PC] + jmp dword ptr [ebp+edx*4] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + end; + + end; +begin + result:=false; + try + CodeContext:=TBESENCodeContext(ACodeContext); + Code:=TBESENCode(CodeContext.Code); + if assigned(Code.NativeCode) then begin + TBESEN(CodeContext.Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); + Code.NativeCode:=nil; + Code.NativeCodeSize:=0; + end; + CodeBuffer:=nil; + CodeBufferLen:=0; + CurrentPC:=0; + Fixups:=nil; + CountFixups:=0; + Offsets:=nil; + ByteCode:=@Code.ByteCode[0]; + SetLength(Offsets,Code.ByteCodeLen); + while CurrentPC<TBESENUINT32(Code.ByteCodeLen) do begin + Offsets[CurrentPC]:=CodeBufferLen; + Instruction:=ByteCode^[CurrentPC]; + Operands:=@ByteCode^[CurrentPC+1]; + inc(CurrentPC,1+(Instruction shr 8)); + Opcode:=Instruction and $ff; + + case Opcode of + bopSTOP:begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [esi+TBESENCodeContext.BlockRunning],0 + mov dword ptr [esi+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + bopNEW:begin + AddDispatcher; + end; + bopCALL:begin + AddDispatcher; + end; + bopEND:begin + if (Code.MaxBlock=0) and (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [esi+TBESENCodeContext.BlockRunning],0 + mov dword ptr [esi+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end else begin + AddDispatcher; + end; + end; + bopVREF:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + // Monomorphic precheck before the polymorphic/megamorphic checks in the opcode handler itself + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+4*4] + test ecx,ecx + js @DoDispatcher + mov eax,dword ptr [esi+TBESENCodeContext.Context] + mov eax,dword ptr [eax+TBESENContext.VariableEnvironment] + mov ecx,dword ptr [eax+TBESENLexicalEnvironment.EnvironmentRecord] + cmp dword ptr [ecx+TBESENObjectEnvironmentRecord.RecordType],0 + jz @DoDispatcher + mov eax,dword ptr [ecx+TBESENObjectEnvironmentRecord.BindingObject] + mov eax,dword ptr [eax+TBESENObject.StructureID] + cmp eax,dword ptr [edx+4*4] + jnz @DoDispatcher + + @CodeVars6: + mov dword ptr [edi+$1337c0de],brbvtENVREC + + @CodeVars0: + mov dword ptr [edi+$1337c0de],ecx + + @CodeVars5: + mov dword ptr [edi+$1337c0de],bvtREFERENCE + + mov eax,dword ptr [edx+5*4] + @CodeVars2: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+2*4] + @CodeVars1: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+6*4] + @CodeVars3: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+7*4] + @CodeVars4: + mov dword ptr [edi+$1337c0de],eax + + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + mov dword ptr [CodeVars+3*4],offset @CodeVars3+2 + mov dword ptr [CodeVars+4*4],offset @CodeVars4+2 + mov dword ptr [CodeVars+5*4],offset @CodeVars5+2 + mov dword ptr [CodeVars+6*4],offset @CodeVars6+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.EnvRec))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceHash))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[3])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIndex))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[4])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceID))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[5])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[6])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.ValueType))-ptruint(pointer(@v))); +{$endif} + end; + bopLREF:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex],LocalIndex + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + AddDWord(Operands^[1]); + end; + bopNOP:begin + end; + bopCOPY:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopNEQ:begin + AddDispatcher; + end; + bopNSEQ:begin + AddDispatcher; + end; + bopAREF:begin + AddDispatcher; + end; + bopTHROW:begin + AddDispatcher; + end; + bopSETC:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETC:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea edx,dword ptr [esi+TBESENCodeContext.ResultValue] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopTHIS:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov edx,dword ptr [esi+TBESENCodeContext.Context] + lea edx,dword ptr [edx+TBESENContext.ThisBinding] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopOBJECT:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.ObjectConstructor] + mov dword ptr [edx],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopARRAY:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.ObjectArrayConstructor] + mov dword ptr [edx],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopREGEXP:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.ObjectRegExpConstructor] + mov dword ptr [edx],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopREF:begin + if TBESENUINT32(Operands^[3])<>$fefefefe then begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + // Monomorphic precheck before the polymorphic/megamorphic checks in the opcode handler itself + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+6*4] + test ecx,ecx + js @DoDispatcher + @CodeVars0: + cmp dword ptr [edi+$1337c0de],bvtOBJECT + jnz @DoDispatcher + @CodeVars2: + mov eax,dword ptr [edi+$1337c0de] + cmp dword ptr [eax+TBESENObject.StructureID],ecx + jnz @DoDispatcher + + @CodeVars1: + mov dword ptr [edi+$1337c0de],brbvtOBJECT + + @CodeVars3: + mov dword ptr [edi+$1337c0de],eax + + @CodeVars8: + mov dword ptr [edi+$1337c0de],bvtREFERENCE + + mov eax,dword ptr [edx+7*4] + @CodeVars5: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+4*4] + @CodeVars4: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+8*4] + @CodeVars6: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+9*4] + @CodeVars7: + mov dword ptr [edi+$1337c0de],eax + + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + mov dword ptr [CodeVars+3*4],offset @CodeVars3+2 + mov dword ptr [CodeVars+4*4],offset @CodeVars4+2 + mov dword ptr [CodeVars+5*4],offset @CodeVars5+2 + mov dword ptr [CodeVars+6*4],offset @CodeVars6+2 + mov dword ptr [CodeVars+7*4],offset @CodeVars7+2 + mov dword ptr [CodeVars+8*4],offset @CodeVars8+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[3])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.Obj))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[4])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceHash))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[5])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[6])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIndex))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[7])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceID))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[8])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + end else begin + AddDispatcher; + end; + end; + bopGETVALUE:begin + AddDispatcher; + end; + bopLOOKUP:begin + AddDispatcher; + end; + bopPUTVALUE:begin + AddDispatcher; + end; + bopDELETE:begin + AddDispatcher; + end; + bopTYPEOF:begin + AddDispatcher; + end; + bopTOOBJECT:begin + AddDispatcher; + end; + bopTONUMBER:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if Operands^[0]=Operands^[1] then begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + asm + jmp @Skip + @CodeBegin: + jz @SkipDispatcher + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddDispatcherPointer; + end else begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + asm + jmp @Skip + @CodeBegin: + jnz @DoDispatcher + @CodeVars0: + mov dword ptr [edi+$1337c0d3],bvtNUMBER + @CodeVars1: + fld qword ptr [edi+$1337c0d3] + @CodeVars2: + fstp qword ptr [edi+$1337c0d3] + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v))); + end; +{$endif} + end; + bopTOBOOLEAN:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if Operands^[0]=Operands^[1] then begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + asm + jmp @Skip + @CodeBegin: + jz @SkipDispatcher + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddDispatcherPointer; + end else begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + asm + jmp @Skip + @CodeBegin: + jnz @DoDispatcher + @CodeVars0: + mov dword ptr [edi+$1337c0d3],bvtBOOLEAN + @CodeVars1: + mov eax,dword ptr [edi+$1337c0d3] + @CodeVars2: + mov dword ptr [edi+$1337c0d3],eax + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v))); + end; +{$endif} + end; + bopTOSTRING:begin + AddDispatcher; + end; + bopTOPRIMITIVE:begin + AddDispatcher; + end; + bopNEG:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$81#$b7); // xor dword ptr [edi+RegisterOfs+TBESENValue.Num+4],$80000000 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+((ptruint(pointer(@v.Num))+4)-ptruint(pointer(@v)))); + AddDWord($80000000); + end; + bopINV:begin + AddDispatcher; + end; + bopNOT:begin + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,$01 + sbb eax,eax + neg eax + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + bopMUL:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$8f); // fmul qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDIV:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$b7); // fdiv qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopMOD:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + @Repeat: + fprem + fstsw ax + sahf + jp @Repeat + fstp st(1) + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopADD:begin + AddDispatcher; + end; + bopADDNUM:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$87); // fadd qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSUB:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$a7); // fsub qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSHL:begin + AddDispatcher; + end; + bopSHR:begin + AddDispatcher; + end; + bopUSHR:begin + AddDispatcher; + end; + bopLT:begin + AddDispatcher; + end; + bopGT:begin + AddDispatcher; + end; + bopLE:begin + AddDispatcher; + end; + bopGE:begin + AddDispatcher; + end; + bopINSTANCEOF:begin + AddDispatcher; + end; + bopIN:begin + AddDispatcher; + end; + bopEQ:begin + AddDispatcher; + end; + bopSEQ:begin + AddDispatcher; + end; + bopBAND:begin + AddDispatcher; + end; + bopBXOR:begin + AddDispatcher; + end; + bopBOR:begin + AddDispatcher; + end; + bopSENUM:begin + AddDispatcher; + end; + bopSWITH:begin + AddDispatcher; + end; + bopSCATCH:begin + AddDispatcher; + end; + bopENDF:begin + AddDispatcher; + end; + bopJMP:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$e9); // jmp Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$83#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$85); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$83#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNULL:begin + AddDispatcher; + end; + bopLOOPENUM:begin + AddDispatcher; + end; + bopSTRYC:begin + AddDispatcher; + end; + bopSTRYF:begin + AddDispatcher; + end; + bopLITERALUNDEF:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtUNDEFINED + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtUNDEFINED); + end; + bopLITERALNULL:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNULL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNULL); + end; + bopLITERALBOOL:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],Bool + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + if Operands^[1]<>0 then begin + AddDWord(longword(pointer(@BESENLongBooleanValues[true])^)); + end else begin + AddDWord(longword(pointer(@BESENLongBooleanValues[false])^)); + end; + end; + bopLITERALNUM:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$dd#$05); // fld qword ptr [Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[1]].Num))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopLITERALSTR:begin + AddDispatcher; + end; + bopLITERALOBJ:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Obj],Obj + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + AddDWord(ptruint(pointer(Code.Literals[Operands^[1]].Obj))); + end; + bopFUNC:begin + AddDispatcher; + end; + bopLINE:begin + Add(#$b8); // mov eax,Arg + AddDWord(Code.Locations[Operands^[0]].LineNumber); + asm + jmp @Skip + @CodeBegin: + mov edx,dword ptr [esi+TBESENCodeContext.Instance] + mov dword ptr [edx+TBESEN.LineNumber],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGC:begin + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.GarbageCollector] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e8); // call TBESENGarbageCollector.TriggerCollect + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkPTR; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].Dest:=@TBESENGarbageCollector.TriggerCollect; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + bopSTRICT:begin + Add(#$b8); // mov eax,Arg + AddDWord(longword(BESENLongBooleanValues[Operands^[0]<>0])); + asm + jmp @Skip + @CodeBegin: + mov edx,dword ptr [esi+TBESENCodeContext.Instance] + mov dword ptr [edx+TBESEN.IsStrict],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSTRICTCHECKREF:begin + if not Code.Body.IsStrict then begin + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.ReferenceIsStrict] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v)))); + + Add(#$85#$c0); // test eax,rax + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=CurrentPC; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + + AddDispatcher; + end; + bopDEBUGGER:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopCHECKOBJECTCOERCIBLE:begin + AddDispatcher; + end; + bopPUTOBJVALUE:begin + AddDispatcher; + end; + bopPUTOBJGET:begin + AddDispatcher; + end; + bopPUTOBJSET:begin + AddDispatcher; + end; + bopINC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$d9#$e8); // fld1 + + Add(#$dc#$87); // fadd qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDEC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$25); // fsub qword ptr [BESENNumOne] + AddDWord(ptruint(pointer(@BESENNumOne))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopCOPYBOOL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + end; + bopCOPYNUM:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + end; + bopCOPYOBJ:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + + Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + end; + bopCOPYREF:begin + if Operands^[0]<>Operands^[1] then begin + AddDispatcher; + end; + end; + bopCOPYLOCAL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + + Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + end; + end; + bopGETVALUEREF:begin + AddDispatcher; + end; + bopPUTVALUEREF:begin + AddDispatcher; + end; + bopGETVALUELOCAL:begin + AddDispatcher; + end; + bopPUTVALUELOCAL:begin + AddDispatcher; + end; + bopGETVALUELOCALFAST:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALFAST:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + xchg eax,edx + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALBOOL:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALBOOL:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [edx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [eax+TBESENValue.Bool] + mov dword ptr [edx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALNUM:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALNUM:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [edx+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [eax+TBESENValue.Num] + fstp qword ptr [edx+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALOBJ:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALOBJ:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [edx+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [eax+TBESENValue.Obj] + mov dword ptr [edx+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEX:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEX:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXBOOL:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXBOOL:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXNUM:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXNUM:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALINDEXOBJ:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXOBJ:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopLOOPINITCOUNT:begin + end; + bopLOOPADDCOUNT:begin + end; + bopTRACE:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopLTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setnz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTSTR:begin + AddDispatcher; + end; + bopGTSTR:begin + AddDispatcher; + end; + bopLESTR:begin + AddDispatcher; + end; + bopGESTR:begin + AddDispatcher; + end; + bopEQSTR:begin + AddDispatcher; + end; + bopNEQSTR:begin + AddDispatcher; + end; + bopSHLBOOL:begin + AddDispatcher; + end; + bopSHRBOOL:begin + AddDispatcher; + end; + bopBANDBOOL:begin + AddDispatcher; + end; + bopBXORBOOL:begin + AddDispatcher; + end; + bopBORBOOL:begin + AddDispatcher; + end; + bopSHLNUM:begin + AddDispatcher; + end; + bopSHRNUM:begin + AddDispatcher; + end; + bopUSHRNUM:begin + AddDispatcher; + end; + bopBANDNUM:begin + AddDispatcher; + end; + bopBXORNUM:begin + AddDispatcher; + end; + bopBORNUM:begin + AddDispatcher; + end; + bopSETCUNDEF:begin + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtUNDEFINED + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNULL:begin + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtNULL + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCBOOL:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNUM:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCSTR:begin + AddDispatcher; + end; + bopSETCOBJ:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopTRACENEW:begin + AddDispatcher; + end; + bopTRACECALL:begin + AddDispatcher; + end; + bopLTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopJZERO:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if longword(Operands^[0])<>CurrentPC then begin + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [BESENDoubleZero] + AddDWord(ptruint(pointer(@BESENDoubleZero))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + cmp eax,0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$85); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; +{$endif} + end; + bopJNZERO:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if longword(Operands^[0])<>CurrentPC then begin + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [BESENDoubleZero] + AddDWord(ptruint(pointer(@BESENDoubleZero))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + cmp eax,0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; +{$endif} + end; + else begin + AddDispatcher; + end; + end; + + end; + RetOfs:=CodeBufferLen; + Add(#$c3); // ret + SetLength(CodeBuffer,CodeBufferLen); + Code.NativeCodeSize:=CodeBufferLen; + Code.NativeCode:=TBESEN(CodeContext.Instance).NativeCodeMemoryManager.GetMemory(Code.NativeCodeSize); + move(CodeBuffer[0],Code.NativeCode^,Code.NativeCodeSize); + SetLength(Code.NativeCodePCOffsets,Code.ByteCodeLen); + for i:=0 to Code.ByteCodeLen-1 do begin + Code.NativeCodePCOffsets[i]:=pointer(@PBESENByteArray(Code.NativeCode)[Offsets[i]]); + end; + for i:=0 to CountFixups-1 do begin + case FixUps[i].Kind of + fkPTR:begin + ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(FixUps[i].Dest)-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkRET:begin + ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[RetOfs]))-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkOFS:begin + ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(Code.NativeCodePCOffsets[FixUps[i].ToOfs])-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + end; + end; + result:=true; + finally + SetLength(Fixups,0); + SetLength(Offsets,0); + SetLength(CodeBuffer,0); + end; +end; + +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +asm + push ebp + push ebx + push esi + push edi + mov esi,eax //ACodeContext + mov dword ptr [esi+TBESENCodeContext.BlockRunning],$ffffffff + mov edi,dword ptr [esi+TBESENCodeContext.RegisterValues] + mov edx,dword ptr [esi+TBESENCodeContext.Code] + mov ebx,dword ptr [edx+TBESENCode.Body] + mov ebx,dword ptr [ebx+TBESENASTNodeFunctionBody.IsFunction] + test ebx,ebx + jz @IsNoFunction + mov ebx,dword ptr [esi+TBESENCodeContext.Context] + mov ebx,dword ptr [ebx+TBESENContext.VariableEnvironment] + mov ebx,dword ptr [ebx+TBESENLexicalEnvironment.EnvironmentRecord] + mov ebx,dword ptr [ebx+TBESENDeclarativeEnvironmentRecord.HashValues] + @IsNoFunction: + mov ebp,dword ptr [edx+TBESENCode.NativeCodePCOffsets] + mov edx,dword ptr [esi+TBESENCodeContext.PC] + call dword ptr [ebp+edx*4] + mov eax,dword ptr [esi+TBESENCodeContext.BlockRunning] + pop edi + pop esi + pop ebx + pop ebp +end; +{$endif} +{$endif} + +end. diff --git a/3rd/besen/src/BESENCodeSnapshot.pas b/3rd/besen/src/BESENCodeSnapshot.pas new file mode 100644 index 000000000..eac0acbec --- /dev/null +++ b/3rd/besen/src/BESENCodeSnapshot.pas @@ -0,0 +1,1387 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeSnapshot; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,BESENConstants,BESENTypes,BESENBaseObject,BESENASTNodes; + +type TBESENCodeSnapshot=class(TBESENBaseObject) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function LoadFromStream(const Stream:TStream):TBESENASTNode; + procedure SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); + end; + +implementation + +uses BESEN,BESENValue,BESENInt64SelfBalancedTree,BESENPointerSelfBalancedTree, + BESENCode,BESENOpcodes,BESENUtils,BESENKeyIDManager, + BESENVersionConstants; + +constructor TBESENCodeSnapshot.Create(AInstance:TObject); +begin + inherited Create(AInstance); +end; + +destructor TBESENCodeSnapshot.Destroy; +begin + inherited Destroy; +end; + +function TBESENCodeSnapshot.LoadFromStream(const Stream:TStream):TBESENASTNode; +type TLoadedKeyManagerID=packed record + ID:integer; + Key:TBESENString; + end; + TLoadedKeyManagerIDs=array of TLoadedKeyManagerID; +var VisitedNodes:TBESENInt64SelfBalancedTree; + LoadedKeyManagerIDs:TLoadedKeyManagerIDs; + procedure BESENThrowStream(const s:string); + begin + raise EStreamError.Create(s); + end; + function ReadByte:byte; + begin + if Stream.Read(result,sizeof(byte))<>sizeof(byte) then begin + BESENThrowStream('Couldn''t read byte'); + end; + end; + function ReadBool:boolean; + begin + result:=ReadByte<>0; + end; + function ReadInt32:integer; + begin + if Stream.Read(result,sizeof(integer))<>sizeof(integer) then begin + BESENThrowStream('Couldn''t read integer'); + end; + end; + function ReadInt64:int64; + begin + if Stream.Read(result,sizeof(int64))<>sizeof(int64) then begin + BESENThrowStream('Couldn''t read int64'); + end; + end; + function ReadDouble:double; + begin + if Stream.Read(result,sizeof(double))<>sizeof(double) then begin + BESENThrowStream('Couldn''t double double'); + end; + end; + function ReadWideString:widestring; + var l:integer; + begin + l:=ReadInt32; + SetLength(result,l); + if length(result)>0 then begin + if Stream.Read(result[1],sizeof(widechar)*length(result))<>(sizeof(widechar)*length(result)) then begin + BESENThrowStream('Couldn''t read widestring'); + end; + end; + end; + function ReadNode:TBESENASTNode; + var Counter,Target,LineNumber,i,j,k:integer; + VisitNodeValue:TBESENInt64SelfBalancedTreeValue; + v:PBESENValue; + Ptr:int64; + NodeType:TBESENASTNodeType; + Code:TBESENCode; + FunctionLiteral:TBESENASTNodeFunctionLiteral; + function CreateNode(c:TBESENASTNodeClass):TBESENASTNode; + var Counter:integer; + begin + result:=c.Create(Instance); + VisitNodeValue.p:=result; + VisitedNodes.Insert(Ptr,VisitNodeValue); + TBESENASTNode(result).NodeType:=NodeType; + TBESENASTNode(result).Target:=Target; + TBESENASTNode(result).Location.LineNumber:=LineNumber; + TBESENASTNode(result).CountTrashNodes:=ReadInt32; + SetLength(TBESENASTNode(result).TrashNodes,TBESENASTNode(result).CountTrashNodes); + for Counter:=0 to TBESENASTNode(result).CountTrashNodes-1 do begin + TBESENASTNode(result).TrashNodes[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + end; + begin + result:=nil; + try + Ptr:=ReadInt64; + if Ptr<>0 then begin + if VisitedNodes.Find(Ptr,VisitNodeValue) then begin + result:=VisitNodeValue.p; + end else begin + NodeType:=ReadByte; + Target:=ReadInt32; + LineNumber:=ReadInt32; + case NodeType of + bntNONE:begin + result:=CreateNode(TBESENASTNode); + end; + bntEXPRESSION:begin + result:=CreateNode(TBESENASTNodeExpression); + end; + bntLITERAL:begin + result:=CreateNode(TBESENASTNodeLiteral); + end; + bntIDENTIFIER:begin + result:=CreateNode(TBESENASTNodeIdentifier); + TBESENASTNodeIdentifier(result).Name:=ReadWideString; + TBESENASTNodeIdentifier(result).Index:=ReadInt32; + TBESENASTNodeIdentifier(result).ParameterIndex:=ReadInt32; + i:=ReadInt32; + if (i>=0) and (i<length(LoadedKeyManagerIDs)) then begin + TBESENASTNodeIdentifier(result).ID:=LoadedKeyManagerIDs[i].ID; + end else begin + TBESENASTNodeIdentifier(result).ID:=i; + end; + TBESENASTNodeIdentifier(result).IsParameter:=ReadBool; + TBESENASTNodeIdentifier(result).IsLocal:=ReadBool; + end; + bntVARIABLEDECLARATION:begin + result:=CreateNode(TBESENASTNodeVariableDeclaration); + TBESENASTNodeVariableDeclaration(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); + TBESENASTNodeVariableDeclaration(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntVARIABLEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeVariableExpression); + SetLength(TBESENASTNodeVariableExpression(result).Declarations,ReadInt32); + for Counter:=0 to length(TBESENASTNodeVariableExpression(result).Declarations)-1 do begin + TBESENASTNodeVariableExpression(result).Declarations[Counter]:=TBESENASTNodeVariableDeclaration(ReadNode); + end; + end; + bntFUNCTIONBODY:begin + result:=CreateNode(TBESENASTNodeFunctionBody); + TBESENASTNodeFunctionBody(result).IsFunction:=ReadBool; + TBESENASTNodeFunctionBody(result).IsEmpty:=ReadBool; + TBESENASTNodeFunctionBody(result).EnableLocalsOptimization:=ReadBool; + TBESENASTNodeFunctionBody(result).DisableArgumentsObject:=ReadBool; + SetLength(TBESENASTNodeFunctionBody(result).Variables,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Variables)-1 do begin + TBESENASTNodeFunctionBody(result).Variables[Counter]:=TBESENASTNodeIdentifier(ReadNode); + end; + SetLength(TBESENASTNodeFunctionBody(result).Parameters,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Parameters)-1 do begin + TBESENASTNodeFunctionBody(result).Parameters[Counter]:=TBESENASTNodeIdentifier(ReadNode); + end; + SetLength(TBESENASTNodeFunctionBody(result).Functions,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Functions)-1 do begin + TBESENASTNodeFunctionBody(result).Functions[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + SetLength(TBESENASTNodeFunctionBody(result).Statements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Statements)-1 do begin + TBESENASTNodeFunctionBody(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + if ReadBool then begin + Code:=TBESENCode(TBESENASTNodeFunctionBody(result).Code); + Code.Body:=TBESENASTNodeFunctionBody(ReadNode); + Code.MaxRegisters:=ReadInt32; + Code.MaxBlock:=ReadInt32; + Code.MaxParamArgs:=ReadInt32; + Code.MaxLoop:=ReadInt32; + Code.HasLocalDelete:=ReadBool; + Code.IsComplexFunction:=ReadBool; + Code.HasMaybeDirectEval:=ReadBool; + Code.HoldLocalVariablesInRegisters:=ReadBool; + Code.CountFunctionLiteralContainers:=ReadInt32; + SetLength(Code.FunctionLiteralContainers,Code.CountFunctionLiteralContainers); + for Counter:=0 to Code.CountFunctionLiteralContainers-1 do begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + Code.FunctionLiteralContainers[Counter]:=FunctionLiteral.Container; + end else begin + Code.FunctionLiteralContainers[Counter]:=nil; + end; + end; + Code.CountLiterals:=ReadInt32; + SetLength(Code.Literals,Code.CountLiterals); + for Counter:=0 to Code.CountLiterals-1 do begin + v:=@Code.Literals[Counter]; + v^.ValueType:=ReadByte; + case v^.ValueType of + bvtNONE:begin + end; + bvtUNDEFINED:begin + end; + bvtNULL:begin + end; + bvtBOOLEAN:begin + v^.Bool:=ReadBool; + end; + bvtNUMBER:begin + v^.Num:=ReadDouble; + end; + bvtSTRING:begin + v^.Str:=ReadWideString; + end; + else begin + BESENThrowStream('Couldn''t read value'); + end; + end; + end; + Code.CountLocations:=ReadInt32; + SetLength(Code.Locations,Code.CountLocations); + for Counter:=0 to Code.CountLocations-1 do begin + Code.Locations[Counter].LineNumber:=ReadInt32; + end; + Code.CountVariables:=ReadInt32; + SetLength(Code.Variables,Code.CountVariables); + for Counter:=0 to Code.CountVariables-1 do begin + Code.Variables[Counter].Name:=ReadWideString; + Code.Variables[Counter].IsParameter:=ReadBool; + Code.Variables[Counter].ParameterIndex:=ReadInt32; + end; + Code.CountPolymorphicInlineCacheInstructions:=ReadInt32; + k:=ReadInt32; + Code.LookupNames.Clear; + for Counter:=0 to k-1 do begin + Code.LookupNames.Add(ReadWideString); + end; + Code.ByteCodeLen:=ReadInt32; + SetLength(Code.ByteCode,Code.ByteCodeLen); + if Code.ByteCodeLen>0 then begin + if Stream.Read(Code.ByteCode[0],Code.ByteCodeLen*sizeof(TBESENUINT32))<>(Code.ByteCodeLen*sizeof(TBESENUINT32)) then begin + BESENThrowStream('Couldn''t read byte code'); + end; + i:=0; + while i<Code.ByteCodeLen do begin + j:=i; + inc(i,1+((Code.ByteCode[i] shr 8) and $ffffff)); + case Code.ByteCode[j] and $ff of + bopREF:begin + k:=Code.ByteCode[j+4]; + if (k>=0) and (k<length(LoadedKeyManagerIDs)) then begin + k:=LoadedKeyManagerIDs[k].ID; + end; + Code.ByteCode[j+4]:=k; + end; + end; + end; + end; + Code.Finish; + end; + end; + bntFUNCTIONLITERAL:begin + result:=CreateNode(TBESENASTNodeFunctionLiteral); + TBESENASTNodeFunctionLiteral(result).Name:=TBESENASTNodeIdentifier(ReadNode); + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeFunctionLiteral(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeFunctionLiteral(result).Container:=nil; + end; + TBESENASTNodeFunctionLiteral(result).Index:=ReadInt32; + TBESENASTNodeFunctionLiteral(result).Body:=TBESENASTNodeFunctionBody(ReadNode); + end; + bntSTATEMENT:begin + result:=CreateNode(TBESENASTNodeStatement); + end; + bntVARIABLESTATEMENT:begin + result:=CreateNode(TBESENASTNodeVariableStatement); + SetLength(TBESENASTNodeVariableStatement(result).Declarations,ReadInt32); + for Counter:=0 to length(TBESENASTNodeVariableStatement(result).Declarations)-1 do begin + TBESENASTNodeVariableStatement(result).Declarations[Counter]:=TBESENASTNodeVariableDeclaration(ReadNode); + end; + end; + bntFUNCTIONDECLARATION:begin + result:=CreateNode(TBESENASTNodeFunctionDeclaration); + if ReadBool then begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeFunctionDeclaration(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeFunctionDeclaration(result).Container:=nil; + end; + end else begin + TBESENASTNodeFunctionDeclaration(result).Container:=nil; + end; + end; + bntEXPRESSIONSTATEMENT:begin + result:=CreateNode(TBESENASTNodeExpressionStatement); + TBESENASTNodeExpressionStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntEMPTYSTATEMENT:begin + result:=CreateNode(TBESENASTNodeEmptyStatement); + end; + bntBLOCKSTATEMENT:begin + result:=CreateNode(TBESENASTNodeBlockStatement); + SetLength(TBESENASTNodeBlockStatement(result).Statements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeBlockStatement(result).Statements)-1 do begin + TBESENASTNodeBlockStatement(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + end; + bntDEBUGGERSTATEMENT:begin + result:=CreateNode(TBESENASTNodeDebuggerStatement); + end; + bntBREAKSTATEMENT:begin + result:=CreateNode(TBESENASTNodeBreakStatement); + TBESENASTNodeBreakStatement(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); + end; + bntCONTINUESTATEMENT:begin + result:=CreateNode(TBESENASTNodeContinueStatement); + TBESENASTNodeContinueStatement(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); + end; + bntDOSTATEMENT:begin + result:=CreateNode(TBESENASTNodeDoStatement); + TBESENASTNodeDoStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + TBESENASTNodeDoStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntWHILESTATEMENT:begin + result:=CreateNode(TBESENASTNodeWhileStatement); + TBESENASTNodeWhileStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeWhileStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntWITHSTATEMENT:begin + result:=CreateNode(TBESENASTNodeWithStatement); + TBESENASTNodeWithStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeWithStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntFORSTATEMENT:begin + result:=CreateNode(TBESENASTNodeForStatement); + TBESENASTNodeForStatement(result).Initial:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForStatement(result).Condition:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForStatement(result).Increment:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntFORINSTATEMENT:begin + result:=CreateNode(TBESENASTNodeForInStatement); + TBESENASTNodeForInStatement(result).Variable:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForInStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForInStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntIFSTATEMENT:begin + result:=CreateNode(TBESENASTNodeIfStatement); + TBESENASTNodeIfStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeIfStatement(result).TrueStatement:=TBESENASTNodeStatement(ReadNode); + TBESENASTNodeIfStatement(result).FalseStatement:=TBESENASTNodeStatement(ReadNode); + end; + bntLABELLEDSTATEMENT:begin + result:=CreateNode(TBESENASTNodeLabelledStatement); + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,ReadInt32); + for Counter:=0 to length(TBESENASTNodeLabelledStatement(result).Identifiers)-1 do begin + TBESENASTNodeLabelledStatement(result).Identifiers[Counter]:=TBESENASTNodeIdentifier(ReadNode); + end; + TBESENASTNodeLabelledStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntCASESTATEMENT:begin + result:=CreateNode(TBESENASTNodeCaseStatement); + TBESENASTNodeCaseStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeCaseStatement(result).Statements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeCaseStatement(result).Statements)-1 do begin + TBESENASTNodeCaseStatement(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + end; + bntSWITCHSTATEMENT:begin + result:=CreateNode(TBESENASTNodeSwitchStatement); + TBESENASTNodeSwitchStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeSwitchStatement(result).CaseStatements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(result).CaseStatements)-1 do begin + TBESENASTNodeSwitchStatement(result).CaseStatements[Counter]:=TBESENASTNodeCaseStatement(ReadNode); + end; + end; + bntTHROWSTATEMENT:begin + result:=CreateNode(TBESENASTNodeThrowStatement); + TBESENASTNodeThrowStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntTRYSTATEMENT:begin + result:=CreateNode(TBESENASTNodeTryStatement); + TBESENASTNodeTryStatement(result).TryBlock:=TBESENASTNodeBlockStatement(ReadNode); + TBESENASTNodeTryStatement(result).CatchIdentifier:=TBESENASTNodeIdentifier(ReadNode); + TBESENASTNodeTryStatement(result).CatchBlock:=TBESENASTNodeBlockStatement(ReadNode); + TBESENASTNodeTryStatement(result).FinallyBlock:=TBESENASTNodeBlockStatement(ReadNode); + end; + bntARRAYLITERAL:begin + result:=CreateNode(TBESENASTNodeArrayLiteral); + SetLength(TBESENASTNodeArrayLiteral(result).Elements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(result).Elements)-1 do begin + TBESENASTNodeArrayLiteral(result).Elements[Counter]:=TBESENASTNodeExpression(ReadNode); + end; + end; + bntBINARYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryExpression); + TBESENASTNodeBinaryExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentExpression); + TBESENASTNodeAssignmentExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentOperatorExpression); + TBESENASTNodeAssignmentOperatorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentOperatorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentMultiplyExpression); + TBESENASTNodeAssignmentMultiplyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentMultiplyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentDivideExpression); + TBESENASTNodeAssignmentDivideExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentDivideExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentModuloExpression); + TBESENASTNodeAssignmentModuloExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentModuloExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentPlusExpression); + TBESENASTNodeAssignmentPlusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentPlusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentMinusExpression); + TBESENASTNodeAssignmentMinusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentMinusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentShiftLeftExpression); + TBESENASTNodeAssignmentShiftLeftExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentShiftLeftExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentShiftRightExpression); + TBESENASTNodeAssignmentShiftRightExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentShiftRightExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentShiftRightUnsignedExpression); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentBitwiseAndExpression); + TBESENASTNodeAssignmentBitwiseAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentBitwiseAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentBitwiseXorExpression); + TBESENASTNodeAssignmentBitwiseXorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentBitwiseXorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentBitwiseOrExpression); + TBESENASTNodeAssignmentBitwiseOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentBitwiseOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYOPERATOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryOperatorExpression); + TBESENASTNodeBinaryOperatorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryOperatorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYCOMMAEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryCommaExpression); + TBESENASTNodeBinaryCommaExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryCommaExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYDIVIDEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryDivideExpression); + TBESENASTNodeBinaryDivideExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryDivideExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYMODULOEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryModuloExpression); + TBESENASTNodeBinaryModuloExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryModuloExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYMULTIPLYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryMultiplyExpression); + TBESENASTNodeBinaryMultiplyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryMultiplyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYPLUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryPlusExpression); + TBESENASTNodeBinaryPlusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryPlusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYMINUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryMinusExpression); + TBESENASTNodeBinaryMinusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryMinusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryShiftLeftExpression); + TBESENASTNodeBinaryShiftLeftExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryShiftLeftExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryShiftRightExpression); + TBESENASTNodeBinaryShiftRightExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryShiftRightExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryShiftRightUnsignedExpression); + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYGREATERTHANEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryGreaterThanExpression); + TBESENASTNodeBinaryGreaterThanExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryGreaterThanExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryGreaterThanOrEqualExpression); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYLESSTHANEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryLessThanExpression); + TBESENASTNodeBinaryLessThanExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryLessThanExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryLessThanOrEqualExpression); + TBESENASTNodeBinaryLessThanOrEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryLessThanOrEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryInstanceOfExpression); + TBESENASTNodeBinaryInstanceOfExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryInstanceOfExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYINEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryInExpression); + TBESENASTNodeBinaryInExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryInExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryEqualEqualExpression); + TBESENASTNodeBinaryEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryEqualEqualEqualExpression); + TBESENASTNodeBinaryEqualEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryEqualEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYNOTEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryNotEqualExpression); + TBESENASTNodeBinaryNotEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryNotEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryNotEqualEqualExpression); + TBESENASTNodeBinaryNotEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryNotEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYBITWISEANDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryBitwiseAndExpression); + TBESENASTNodeBinaryBitwiseAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryBitwiseAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYBITWISEXOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryBitwiseXorExpression); + TBESENASTNodeBinaryBitwiseXorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryBitwiseXorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYBITWISEOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryBitwiseOrExpression); + TBESENASTNodeBinaryBitwiseOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryBitwiseOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBOOLEANLITERAL:begin + result:=CreateNode(TBESENASTNodeBooleanLiteral); + TBESENASTNodeBooleanLiteral(result).Value:=ReadBool; + end; + bntCALLEXPRESSION:begin + result:=CreateNode(TBESENASTNodeCallExpression); + TBESENASTNodeCallExpression(result).TheFunction:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeCallExpression(result).Arguments,ReadInt32); + for Counter:=0 to length(TBESENASTNodeCallExpression(result).Arguments)-1 do begin + TBESENASTNodeCallExpression(result).Arguments[Counter]:=TBESENASTNodeExpression(ReadNode); + end; + end; + bntNEWEXPRESSION:begin + result:=CreateNode(TBESENASTNodeNewExpression); + TBESENASTNodeNewExpression(result).TheFunction:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeNewExpression(result).Arguments,ReadInt32); + for Counter:=0 to length(TBESENASTNodeNewExpression(result).Arguments)-1 do begin + TBESENASTNodeNewExpression(result).Arguments[Counter]:=TBESENASTNodeExpression(ReadNode); + end; + end; + bntCONDITIONALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeConditionalExpression); + TBESENASTNodeConditionalExpression(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeConditionalExpression(result).TrueExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeConditionalExpression(result).FalseExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryExpression); + TBESENASTNodeUnaryExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYOPERATOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryOperatorExpression); + TBESENASTNodeUnaryOperatorExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYPLUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryPlusExpression); + TBESENASTNodeUnaryPlusExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYMINUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryMinusExpression); + TBESENASTNodeUnaryMinusExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYBITWISENOTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryBitwiseNotExpression); + TBESENASTNodeUnaryBitwiseNotExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryLogicalNotExpression); + TBESENASTNodeUnaryLogicalNotExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYVOIDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryVoidExpression); + TBESENASTNodeUnaryVoidExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYTYPEOFEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryTypeOfExpression); + TBESENASTNodeUnaryTypeOfExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPROPERTYEXPRESSION:begin + result:=CreateNode(TBESENASTNodePropertyExpression); + TBESENASTNodePropertyExpression(result).Dot:=ReadBool; + TBESENASTNodePropertyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodePropertyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntLOGICALANDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeLogicalAndExpression); + TBESENASTNodeLogicalAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeLogicalAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntLOGICALOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeLogicalOrExpression); + TBESENASTNodeLogicalOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeLogicalOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntDELETEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeDeleteExpression); + TBESENASTNodeDeleteExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPOSTFIXINCEXPRESSION:begin + result:=CreateNode(TBESENASTNodePostfixIncExpression); + TBESENASTNodePostfixIncExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPOSTFIXDECEXPRESSION:begin + result:=CreateNode(TBESENASTNodePostfixDecExpression); + TBESENASTNodePostfixDecExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPREFIXINCEXPRESSION:begin + result:=CreateNode(TBESENASTNodePrefixIncExpression); + TBESENASTNodePrefixIncExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPREFIXDECEXPRESSION:begin + result:=CreateNode(TBESENASTNodePrefixDecExpression); + TBESENASTNodePrefixDecExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + result:=CreateNode(TBESENASTNodeNumberLiteral); + TBESENASTNodeNumberLiteral(result).Value:=ReadDouble; + end; + bntREGEXPLITERAL:begin + result:=CreateNode(TBESENASTNodeRegExpLiteral); + TBESENASTNodeRegExpLiteral(result).Source:=ReadWideString; + TBESENASTNodeRegExpLiteral(result).Flags:=ReadWideString; + end; + bntSTRINGLITERAL:begin + result:=CreateNode(TBESENASTNodeStringLiteral); + TBESENASTNodeStringLiteral(result).Value:=ReadWideString; + end; + bntTHISLITERAL:begin + result:=CreateNode(TBESENASTNodeThisLiteral); + end; + bntOBJECTLITERALPROPERTY:begin + result:=CreateNode(TBESENASTNodeObjectLiteralProperty); + TBESENASTNodeObjectLiteralProperty(result).Name:=ReadWideString; + TBESENASTNodeObjectLiteralProperty(result).PropertyType:=TBESENASTNodeObjectLiteralPropertyType(ReadInt32); + TBESENASTNodeObjectLiteralProperty(result).PropertyAccessorType:=TBESENASTNodeObjectLiteralPropertyAccessorType(ReadInt32); + TBESENASTNodeObjectLiteralProperty(result).Value:=TBESENASTNodeExpression(ReadNode); + if ReadBool then begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeObjectLiteralProperty(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeObjectLiteralProperty(result).Container:=nil; + end; + end else begin + TBESENASTNodeObjectLiteralProperty(result).Container:=nil; + end; + end; + bntOBJECTLITERAL:begin + result:=CreateNode(TBESENASTNodeObjectLiteral); + SetLength(TBESENASTNodeObjectLiteral(result).Properties,ReadInt32); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(result).Properties)-1 do begin + TBESENASTNodeObjectLiteral(result).Properties[Counter]:=TBESENASTNodeObjectLiteralProperty(ReadNode); + end; + end; + bntRETURNSTATEMENT:begin + result:=CreateNode(TBESENASTNodeReturnStatement); + TBESENASTNodeReturnStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntPROGRAM:begin + result:=CreateNode(TBESENASTNodeProgram); + TBESENASTNodeProgram(result).Body:=TBESENASTNodeFunctionBody(ReadNode); + end; + bntFUNCTIONEXPRESSION:begin + result:=CreateNode(TBESENASTNodeFunctionExpression); + if ReadBool then begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeFunctionExpression(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeFunctionExpression(result).Container:=nil; + end; + end else begin + TBESENASTNodeFunctionExpression(result).Container:=nil; + end; + end; + end; + end; + end; + except + BESENFreeAndNil(result); + end; + end; +var Count,Counter:integer; + Key:TBESENString; +begin + VisitedNodes:=TBESENInt64SelfBalancedTree.Create; + LoadedKeyManagerIDs:=nil; + try + result:=nil; + try + if ReadInt64<>BESENCodeFormatRevisionNumber then begin + BESENThrowStream('Bad format'); + end; + Count:=ReadInt32; + SetLength(LoadedKeyManagerIDs,Count); + for Counter:=0 to Count-1 do begin + Key:=ReadWideString; + LoadedKeyManagerIDs[Counter].Key:=Key; + LoadedKeyManagerIDs[Counter].ID:=TBESEN(Instance).KeyIDManager.Get(Key); + end; + result:=ReadNode; + except + BESENFreeAndNil(result); + end; + finally + BESENFreeAndNil(VisitedNodes); + SetLength(LoadedKeyManagerIDs,0); + Key:=''; + end; +end; + +procedure TBESENCodeSnapshot.SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); +var VisitedNodes:TBESENPointerSelfBalancedTree; + procedure BESENThrowStream(const s:string); + begin + raise EStreamError.Create(s); + end; + procedure WriteByte(const b:byte); + begin + if Stream.Write(b,sizeof(byte))<>sizeof(byte) then begin + BESENThrowStream('Couldn''t write byte'); + end; + end; + procedure WriteBool(const b:boolean); + begin + if b then begin + WriteByte($ff); + end else begin + WriteByte(0); + end; + end; + procedure WriteInt32(const i:integer); + begin + if Stream.Write(i,sizeof(integer))<>sizeof(integer) then begin + BESENThrowStream('Couldn''t write integer'); + end; + end; + procedure WriteInt64(const i:int64); + begin + if Stream.Write(i,sizeof(int64))<>sizeof(int64) then begin + BESENThrowStream('Couldn''t write int64'); + end; + end; + procedure WriteDouble(const d:double); + begin + if Stream.Write(d,sizeof(double))<>sizeof(double) then begin + BESENThrowStream('Couldn''t write double'); + end; + end; + procedure WriteWideString(const ws:widestring); + begin + WriteInt32(length(ws)); + if length(ws)>0 then begin + if Stream.Write(ws[1],sizeof(widechar)*length(ws))<>(sizeof(widechar)*length(ws)) then begin + BESENThrowStream('Couldn''t write widestring'); + end; + end; + end; + procedure Visit(ToVisit:TBESENASTNode); + var Counter:integer; + VisitNodeValue:TBESENPointerSelfBalancedTreeValue; + v:PBESENValue; + Code:TBESENCode; + begin + WriteInt64(ptrint(ToVisit)); + if assigned(ToVisit) and not VisitedNodes.Find(ToVisit,VisitNodeValue) then begin + VisitNodeValue.p:=ToVisit; + VisitedNodes.Insert(ToVisit,VisitNodeValue); + WriteByte(ToVisit.NodeType); + WriteInt32(TBESENASTNode(ToVisit).Target); + WriteInt32(TBESENASTNode(ToVisit).Location.LineNumber); + WriteInt32(TBESENASTNode(ToVisit).CountTrashNodes); + for Counter:=0 to TBESENASTNode(ToVisit).CountTrashNodes-1 do begin + Visit(TBESENASTNode(ToVisit).TrashNodes[Counter]); + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + WriteWideString(TBESENASTNodeIdentifier(ToVisit).Name); + WriteInt32(TBESENASTNodeIdentifier(ToVisit).Index); + WriteInt32(TBESENASTNodeIdentifier(ToVisit).ParameterIndex); + WriteInt32(TBESENASTNodeIdentifier(ToVisit).ID); + WriteBool(TBESENASTNodeIdentifier(ToVisit).IsParameter); + WriteBool(TBESENASTNodeIdentifier(ToVisit).IsLocal); + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); + end; + bntVARIABLEEXPRESSION:begin + WriteInt32(length(TBESENASTNodeVariableExpression(ToVisit).Declarations)); + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + WriteBool(TBESENASTNodeFunctionBody(ToVisit).IsFunction); + WriteBool(TBESENASTNodeFunctionBody(ToVisit).IsEmpty); + WriteBool(TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization); + WriteBool(TBESENASTNodeFunctionBody(ToVisit).DisableArgumentsObject); + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Variables)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]); + end; + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Parameters)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]); + end; + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Functions)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]); + end; + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Statements)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + WriteBool(assigned(TBESENASTNodeFunctionBody(ToVisit).Code)); + if assigned(TBESENASTNodeFunctionBody(ToVisit).Code) then begin + Code:=TBESENCode(TBESENASTNodeFunctionBody(ToVisit).Code); + Visit(Code.Body); + WriteInt32(Code.MaxRegisters); + WriteInt32(Code.MaxBlock); + WriteInt32(Code.MaxParamArgs); + WriteInt32(Code.MaxLoop); + WriteBool(Code.HasLocalDelete); + WriteBool(Code.IsComplexFunction); + WriteBool(Code.HasMaybeDirectEval); + WriteBool(Code.HoldLocalVariablesInRegisters); + WriteInt32(Code.CountFunctionLiteralContainers); + for Counter:=0 to Code.CountFunctionLiteralContainers-1 do begin + Visit(Code.FunctionLiteralContainers[Counter].Literal); + end; + WriteInt32(Code.CountLiterals); + for Counter:=0 to Code.CountLiterals-1 do begin + v:=@Code.Literals[Counter]; + WriteByte(v^.ValueType); + case v^.ValueType of + bvtNONE:begin + end; + bvtUNDEFINED:begin + end; + bvtNULL:begin + end; + bvtBOOLEAN:begin + WriteBool(v^.Bool); + end; + bvtNUMBER:begin + WriteDouble(v^.Num); + end; + bvtSTRING:begin + WriteWideString(v^.Str); + end; + else begin + BESENThrowStream('Couldn''t write value'); + end; + end; + end; + WriteInt32(Code.CountLocations); + for Counter:=0 to Code.CountLocations-1 do begin + WriteInt32(Code.Locations[Counter].LineNumber); + end; + WriteInt32(Code.CountVariables); + for Counter:=0 to Code.CountVariables-1 do begin + WriteWideString(Code.Variables[Counter].Name); + WriteBool(Code.Variables[Counter].IsParameter); + WriteInt32(Code.Variables[Counter].ParameterIndex); + end; + WriteInt32(Code.CountPolymorphicInlineCacheInstructions); + WriteInt32(Code.LookupNames.Count); + for Counter:=0 to Code.LookupNames.Count-1 do begin + WriteWideString(Code.LookupNames[Counter]); + end; + WriteInt32(Code.ByteCodeLen); + if Code.ByteCodeLen>0 then begin + if Stream.Write(Code.ByteCode[0],Code.ByteCodeLen*sizeof(TBESENUINT32))<>(Code.ByteCodeLen*sizeof(TBESENUINT32)) then begin + BESENThrowStream('Couldn''t write byte code'); + end; + end; + end; + end; + bntFUNCTIONLITERAL:begin + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Name); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Container.Literal); + WriteInt32(TBESENASTNodeFunctionLiteral(ToVisit).Index); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + WriteInt32(length(TBESENASTNodeVariableStatement(ToVisit).Declarations)); + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONDECLARATION:begin + WriteBool(assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container)); + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + WriteInt32(length(TBESENASTNodeBlockStatement(ToVisit).Statements)); + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + end; + bntCONTINUESTATEMENT:begin + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + end; + bntDOSTATEMENT:begin + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression); + end; + bntWHILESTATEMENT:begin + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + Visit(TBESENASTNodeWithStatement(ToVisit).Expression); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + Visit(TBESENASTNodeIfStatement(ToVisit).Expression); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + end; + bntLABELLEDSTATEMENT:begin + WriteInt32(length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)); + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); + WriteInt32(length(TBESENASTNodeCaseStatement(ToVisit).Statements)); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + end; + bntSWITCHSTATEMENT:begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); + WriteInt32(length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + end; + bntTHROWSTATEMENT:begin + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); + end; + bntTRYSTATEMENT:begin + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + end; + bntARRAYLITERAL:begin + WriteInt32(length(TBESENASTNodeArrayLiteral(ToVisit).Elements)); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBINARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + end; + bntBINARYCOMMAEXPRESSION:begin + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + end; + bntBINARYDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + end; + bntBINARYMODULOEXPRESSION:begin + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + end; + bntBINARYMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + end; + bntBINARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + end; + bntBINARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + end; + bntBINARYINEXPRESSION:begin + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBOOLEANLITERAL:begin + WriteBool(TBESENASTNodeBooleanLiteral(ToVisit).Value); + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + WriteInt32(length(TBESENASTNodeCallExpression(ToVisit).Arguments)); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + end; + bntNEWEXPRESSION:begin + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + WriteInt32(length(TBESENASTNodeNewExpression(ToVisit).Arguments)); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + end; + bntCONDITIONALEXPRESSION:begin + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + end; + bntUNARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + end; + bntUNARYBITWISENOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + end; + bntUNARYVOIDEXPRESSION:begin + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + WriteBool(TBESENASTNodePropertyExpression(ToVisit).Dot); + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + end; + bntLOGICALANDEXPRESSION:begin + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + end; + bntLOGICALOREXPRESSION:begin + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + end; + bntDELETEEXPRESSION:begin + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + end; + bntPOSTFIXINCEXPRESSION:begin + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + end; + bntPOSTFIXDECEXPRESSION:begin + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + end; + bntPREFIXINCEXPRESSION:begin + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + end; + bntPREFIXDECEXPRESSION:begin + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + WriteDouble(TBESENASTNodeNumberLiteral(ToVisit).Value); + end; + bntREGEXPLITERAL:begin + WriteWideString(TBESENASTNodeRegExpLiteral(ToVisit).Source); + WriteWideString(TBESENASTNodeRegExpLiteral(ToVisit).Flags); + end; + bntSTRINGLITERAL:begin + WriteWideString(TBESENASTNodeStringLiteral(ToVisit).Value); + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + WriteWideString(TBESENASTNodeObjectLiteralProperty(ToVisit).Name); + WriteInt32(integer(TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType)); + WriteInt32(integer(TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType)); + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + WriteBool(assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + bntOBJECTLITERAL:begin + WriteInt32(length(TBESENASTNodeObjectLiteral(ToVisit).Properties)); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + end; + bntRETURNSTATEMENT:begin + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); + end; + bntPROGRAM:begin + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + WriteBool(assigned(TBESENASTNodeFunctionExpression(ToVisit).Container)); + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; +var Counter:integer; +begin + VisitedNodes:=TBESENPointerSelfBalancedTree.Create; + try + WriteInt64(BESENCodeFormatRevisionNumber); + WriteInt32(TBESEN(Instance).KeyIDManager.List.Count); + for Counter:=0 to TBESEN(Instance).KeyIDManager.List.Count-1 do begin + WriteWideString(TBESEN(Instance).KeyIDManager.List[Counter]); + end; + Visit(RootNode); + finally + BESENFreeAndNil(VisitedNodes); + end; +end; + +end. diff --git a/3rd/besen/src/BESENCollector.pas b/3rd/besen/src/BESENCollector.pas new file mode 100644 index 000000000..7a9c8c7f5 --- /dev/null +++ b/3rd/besen/src/BESENCollector.pas @@ -0,0 +1,73 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCollector; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENBaseObject,BESENCollectorObject; + +type TBESENCollector=class(TBESENBaseObject) + public + First,Last:TBESENCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + end; + +implementation + +uses BESEN; + +constructor TBESENCollector.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; +end; + +destructor TBESENCollector.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENCollector.Clear; +begin + while assigned(First) do begin + First.Free; + end; + First:=nil; + Last:=nil; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENCollectorObject.pas b/3rd/besen/src/BESENCollectorObject.pas new file mode 100644 index 000000000..9c58e984c --- /dev/null +++ b/3rd/besen/src/BESENCollectorObject.pas @@ -0,0 +1,80 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCollectorObject; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENBaseObject; + +type TBESENCollectorObject=class(TBESENBaseObject) + public + CollectorPrevious,CollectorNext:TBESENCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + +implementation + +uses BESEN; + +constructor TBESENCollectorObject.Create(AInstance:TObject); +begin + inherited Create; + Instance:=AInstance; + CollectorPrevious:=TBESEN(Instance).Collector.Last; + CollectorNext:=nil; + if assigned(CollectorPrevious) then begin + CollectorPrevious.CollectorNext:=self; + end else begin + TBESEN(Instance).Collector.First:=self; + end; + TBESEN(Instance).Collector.Last:=self; +end; + +destructor TBESENCollectorObject.Destroy; +begin + if assigned(CollectorPrevious) then begin + CollectorPrevious.CollectorNext:=CollectorNext; + end else if TBESEN(Instance).Collector.First=self then begin + TBESEN(Instance).Collector.First:=CollectorNext; + end; + if assigned(CollectorNext) then begin + CollectorNext.CollectorPrevious:=CollectorPrevious; + end else if TBESEN(Instance).Collector.Last=self then begin + TBESEN(Instance).Collector.Last:=CollectorPrevious; + end; + CollectorNext:=nil; + CollectorPrevious:=nil; + inherited Destroy; +end; + +end. diff --git a/3rd/besen/src/BESENCompiler.pas b/3rd/besen/src/BESENCompiler.pas new file mode 100644 index 000000000..e735a4580 --- /dev/null +++ b/3rd/besen/src/BESENCompiler.pas @@ -0,0 +1,6597 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCompiler; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, + BESENEvalCacheItem; + +type TBESENCompiler=class(TBESENBaseObject) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Compile(InputSource:TBESENUTF8STRING;const Parameters:TBESENUTF8STRING='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; + end; + +implementation + +uses BESEN,BESENUtils,BESENPointerList,BESENHashMap,BESENErrors,BESENNumberUtils, + BESENCode,BESENCodeGeneratorContext,BESENOpcodes,BESENHashUtils,BESENGlobals, + BESENParser; + +const bcgtUNDEFINED=$01; + bcgtNULL=$02; + bcgtBOOLEAN=$04; + bcgtNUMBER=$08; + bcgtSTRING=$10; + bcgtOBJECT=$20; + bcgtREFERENCE=$40; + bcgtPRIMITIVE=bcgtUNDEFINED or bcgtNULL or bcgtBOOLEAN or bcgtNUMBER or bcgtSTRING; + bcgtVALUE=bcgtPRIMITIVE or bcgtOBJECT; + +function sar(Value,Shift:integer):integer; +{$ifdef PurePascal}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$else} +{$ifdef HasSAR} inline; +begin +result:=SARLongint(Value,Shift); +end; +{$else} +{$ifdef cpu386} +{$ifdef fpc} assembler; register; //inline; +asm + mov ecx,edx + sar eax,cl +end;// ['eax','edx','ecx']; +{$else} assembler; register; +asm + mov ecx,edx + sar eax,cl +end; +{$endif} +{$else} +{$ifdef cpuarm} assembler; //inline; +asm + mov r0,r0,asr R1 +end;// ['r0','R1']; +{$else}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$endif} +{$endif} +{$endif} +{$endif} + +constructor TBESENCompiler.Create(AInstance:TObject); +begin + inherited Create(AInstance); +end; + +destructor TBESENCompiler.Destroy; +begin + inherited Destroy; +end; + +function TBESENCompiler.Compile(InputSource:TBESENUTF8STRING;const Parameters:TBESENUTF8STRING='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; + function ConvertToValue(n:TBESENASTNode;var v:TBESENValue):boolean; + begin + case n.NodeType of + bntBOOLEANLITERAL:begin + v.ValueType:=bvtBOOLEAN; + v.Bool:=TBESENASTNodeBooleanLiteral(n).Value; + result:=true; + end; + bntNUMBERLITERAL:begin + v.ValueType:=bvtNUMBER; + v.Num:=TBESENASTNodeNumberLiteral(n).Value; + result:=true; + end; + bntSTRINGLITERAL:begin + v.ValueType:=bvtSTRING; + v.Str:=TBESENASTNodeStringLiteral(n).Value; + result:=true; + end; + else begin + v.ValueType:=bvtNONE; + result:=false; + end; + end; + end; + procedure TrimStuffAfterReturnBreakContinue(Node:TBESENASTNode;var Statements:TBESENASTNodeStatements); + var Counter,NewCount,TrimmedCounter:integer; + Statement:TBESENASTNodeStatement; + begin + NewCount:=length(Statements); + for Counter:=0 to length(Statements)-1 do begin + Statement:=Statements[Counter]; + if assigned(Statement) then begin + case Statement.NodeType of + bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT:begin + NewCount:=Counter+1; + break; + end; + end; + end; + end; + if NewCount<>length(Statements) then begin + TrimmedCounter:=Node.CountTrashNodes; + inc(Node.CountTrashNodes,length(Statements)-NewCount); + if Node.CountTrashNodes>=length(Node.TrashNodes) then begin + SetLength(Node.TrashNodes,Node.CountTrashNodes+256); + end; + for Counter:=NewCount to length(Statements)-1 do begin + Node.TrashNodes[TrimmedCounter]:=Statements[Counter]; + inc(TrimmedCounter); + end; + SetLength(Statements,NewCount); + end; + end; + procedure AddTrashNode(Node,TrashNode:TBESENASTNode); + var Index:integer; + begin + if assigned(Node) and assigned(TrashNode) then begin + Index:=Node.CountTrashNodes; + inc(Node.CountTrashNodes); + if Node.CountTrashNodes>=length(Node.TrashNodes) then begin + SetLength(Node.TrashNodes,Node.CountTrashNodes+256); + end; + Node.TrashNodes[Index]:=TrashNode; + TrashNode:=nil; + end; + end; + function IsLastNodeBreakContinueReturnNode(const Statements:TBESENASTNodeStatements):boolean; + var Counter:integer; + Statement:TBESENASTNodeStatement; + begin + result:=false; + for Counter:=length(Statements)-1 downto 0 do begin + Statement:=Statements[Counter]; + if assigned(Statement) then begin + result:=Statement.NodeType in [bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT]; + break; + end; + end; + end; + function IsBreakContinueReturnNode(Node:TBESENASTNode):boolean; + begin + result:=false; + if assigned(Node) then begin + case Node.NodeType of + bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT:begin + result:=true; + end; + bntBLOCKSTATEMENT:begin + result:=IsLastNodeBreakContinueReturnNode(TBESENASTNodeBlockStatement(Node).Statements); + end; + end; + end; + end; + function HasLabelBreakContinue(RootNode:TBESENASTNode):boolean; + var HasResult:boolean; + procedure Visit(ToVisit:TBESENASTNode); + var Counter:integer; + begin + if assigned(ToVisit) and not HasResult then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + end; + bntFUNCTIONLITERAL:begin + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + if assigned(TBESENASTNodeBreakStatement(ToVisit).Identifier) then begin + HasResult:=true; + end; + end; + bntCONTINUESTATEMENT:begin + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + if assigned(TBESENASTNodeContinueStatement(ToVisit).Identifier) then begin + HasResult:=true; + end; + end; + bntDOSTATEMENT:begin + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression); + end; + bntWHILESTATEMENT:begin + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + Visit(TBESENASTNodeWithStatement(ToVisit).Expression); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + Visit(TBESENASTNodeIfStatement(ToVisit).Expression); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + end; + bntLABELLEDSTATEMENT:begin + HasResult:=true; + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + end; + bntSWITCHSTATEMENT:begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + end; + bntTHROWSTATEMENT:begin + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); + end; + bntTRYSTATEMENT:begin + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + end; + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBINARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + end; + bntBINARYCOMMAEXPRESSION:begin + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + end; + bntBINARYDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + end; + bntBINARYMODULOEXPRESSION:begin + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + end; + bntBINARYMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + end; + bntBINARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + end; + bntBINARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + end; + bntBINARYINEXPRESSION:begin + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + end; + bntNEWEXPRESSION:begin + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + end; + bntCONDITIONALEXPRESSION:begin + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + end; + bntUNARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + end; + bntUNARYBITWISENOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + end; + bntUNARYVOIDEXPRESSION:begin + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + end; + bntLOGICALANDEXPRESSION:begin + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + end; + bntLOGICALOREXPRESSION:begin + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + end; + bntDELETEEXPRESSION:begin + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + end; + bntPOSTFIXINCEXPRESSION:begin + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + end; + bntPOSTFIXDECEXPRESSION:begin + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + end; + bntPREFIXINCEXPRESSION:begin + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + end; + bntPREFIXDECEXPRESSION:begin + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + end; + bntRETURNSTATEMENT:begin + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); + end; + bntPROGRAM:begin + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; + begin + HasResult:=false; + Visit(RootNode); + result:=HasResult; + end; + procedure CheckNodeForFeatures(RootNode:TBESENASTNode;var HasLocalDelete,IsComplexFunction,HasMaybeDirectEval,HasFunctions,HoldLocalVariablesInRegisters:boolean); + procedure Visit(ToVisit:TBESENASTNode); + var Counter:integer; + begin + if assigned(ToVisit) then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + if (TBESENASTNodeIdentifier(ToVisit).Name='eval') or (TBESENASTNodeIdentifier(ToVisit).Name='arguments') then begin + if TBESENASTNodeIdentifier(ToVisit).Name='eval' then begin + HasMaybeDirectEval:=true; + end; + IsComplexFunction:=true; + HoldLocalVariablesInRegisters:=false; + end; + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + IsComplexFunction:=true; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + end; + bntFUNCTIONLITERAL:begin + IsComplexFunction:=true; + HasFunctions:=true; + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + end; + bntCONTINUESTATEMENT:begin + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + end; + bntDOSTATEMENT:begin + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression); + end; + bntWHILESTATEMENT:begin + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + HoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeWithStatement(ToVisit).Expression); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + Visit(TBESENASTNodeIfStatement(ToVisit).Expression); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + end; + bntLABELLEDSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + end; + bntSWITCHSTATEMENT:begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + end; + bntTHROWSTATEMENT:begin + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); + end; + bntTRYSTATEMENT:begin + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + HoldLocalVariablesInRegisters:=false; + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + end; + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBINARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + end; + bntBINARYCOMMAEXPRESSION:begin + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + end; + bntBINARYDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + end; + bntBINARYMODULOEXPRESSION:begin + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + end; + bntBINARYMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + end; + bntBINARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + end; + bntBINARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + end; + bntBINARYINEXPRESSION:begin + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + end; + bntNEWEXPRESSION:begin + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + end; + bntCONDITIONALEXPRESSION:begin + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + end; + bntUNARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + end; + bntUNARYBITWISENOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + end; + bntUNARYVOIDEXPRESSION:begin + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + end; + bntLOGICALANDEXPRESSION:begin + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + end; + bntLOGICALOREXPRESSION:begin + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + end; + bntDELETEEXPRESSION:begin + IsComplexFunction:=true; + HoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + if assigned(TBESENASTNodeDeleteExpression(ToVisit).SubExpression) and (TBESENASTNodeDeleteExpression(ToVisit).SubExpression.NodeType=bntIDENTIFIER) then begin + HasLocalDelete:=true; + end; + end; + bntPOSTFIXINCEXPRESSION:begin + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + end; + bntPOSTFIXDECEXPRESSION:begin + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + end; + bntPREFIXINCEXPRESSION:begin + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + end; + bntPREFIXDECEXPRESSION:begin + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + end; + bntRETURNSTATEMENT:begin + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); + end; + bntPROGRAM:begin + IsComplexFunction:=true; + HoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + IsComplexFunction:=true; + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; + begin + Visit(RootNode); + end; + procedure ScanCollectAndPreprocess(RootNode:TBESENASTNode); + var Functions:TBESENPointerList; + Variables:TBESENPointerList; + VariableHashMap:TBESENHashMap; + AreLocalsOptimizable,IsFunction,IsMaybeArgumentsObjectUsed:boolean; + FunctionLiteral:TBESENASTNodeFunctionLiteral; + procedure AddVariable(Identifier:TBESENASTNodeIdentifier;IsParameter:boolean;ParameterIndex:integer); + var Item:PBESENHashMapItem; + begin + if assigned(Variables) then begin + Item:=VariableHashMap.GetKey(Identifier.Name); + if not assigned(Item) then begin + Item:=VariableHashMap.NewKey(Identifier.Name,true); + Item^.Value:=Variables.Add(Identifier); + Identifier.Index:=Item^.Value; + Identifier.IsParameter:=IsParameter; + Identifier.ParameterIndex:=ParameterIndex; + end; + end; + end; + function Visit(ToVisit:TBESENASTNode):TBESENASTNode; + var Counter,NonEmptyStatementCount:integer; + OldFunctions:TBESENPointerList; + OldVariables:TBESENPointerList; + OldVariableHashMap:TBESENHashMap; + OldAreLocalsOptimizable,OldIsFunction,OldIsMaybeArgumentsObjectUsed,OldIsStrict:boolean; + OldFunctionLiteral:TBESENASTNodeFunctionLiteral; + begin + result:=ToVisit; + if assigned(ToVisit) then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + TBESENASTNodeIdentifier(ToVisit).ID:=TBESEN(Instance).KeyIDManager.Get(TBESENASTNodeIdentifier(ToVisit).Name); + if (TBESENASTNodeIdentifier(ToVisit).Name='eval') or (TBESENASTNodeIdentifier(ToVisit).Name='arguments') then begin + IsMaybeArgumentsObjectUsed:=true; + end; + end; + bntVARIABLEDECLARATION:begin + TBESENASTNodeVariableDeclaration(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier)); + TBESENASTNodeVariableDeclaration(ToVisit).Expression:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression)); + AddVariable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,false,-1); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONBODY:begin + OldFunctions:=Functions; + OldVariables:=Variables; + OldVariableHashMap:=VariableHashMap; + OldAreLocalsOptimizable:=AreLocalsOptimizable; + OldIsStrict:=TBESEN(Instance).IsStrict; + Functions:=TBESENPointerList.Create; + Variables:=TBESENPointerList.Create; + VariableHashMap:=TBESENHashMap.Create; + try + TBESEN(Instance).IsStrict:=TBESENASTNodeFunctionBody(ToVisit).IsStrict; + AreLocalsOptimizable:=true; + if IsFunction and assigned(FunctionLiteral) then begin + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter])); + AddVariable(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter],true,Counter); + end; + end; + NonEmptyStatementCount:=0; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter])); + if assigned(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]) and (TBESENASTNodeFunctionBody(ToVisit).Statements[Counter].NodeType<>bntEMPTYSTATEMENT) then begin + inc(NonEmptyStatementCount); + end; + end; + SetLength(TBESENASTNodeFunctionBody(ToVisit).Functions,Functions.Count); + for Counter:=0 to Functions.Count-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]:=Functions[Counter]; + end; + SetLength(TBESENASTNodeFunctionBody(ToVisit).Variables,Variables.Count); + for Counter:=0 to Variables.Count-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]:=Variables[Counter]; + end; + TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization:=IsFunction and AreLocalsOptimizable; + TBESENASTNodeFunctionBody(ToVisit).DisableArgumentsObject:=not (IsFunction and IsMaybeArgumentsObjectUsed); + TBESENASTNodeFunctionBody(ToVisit).IsEmpty:=NonEmptyStatementCount=0; + finally + BESENFreeAndNil(Functions); + BESENFreeAndNil(Variables); + BESENFreeAndNil(VariableHashMap); + Functions:=OldFunctions; + Variables:=OldVariables; + VariableHashMap:=OldVariableHashMap; + TBESEN(Instance).IsStrict:=OldIsStrict; + AreLocalsOptimizable:=OldAreLocalsOptimizable; + end; + end; + bntFUNCTIONLITERAL:begin + OldIsFunction:=IsFunction; + OldFunctionLiteral:=FunctionLiteral; + OldIsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; + IsMaybeArgumentsObjectUsed:=false; + IsFunction:=true; + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ToVisit); + TBESENASTNodeFunctionLiteral(ToVisit).Body:=pointer(Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body)); + FunctionLiteral:=OldFunctionLiteral; + IsFunction:=OldIsFunction; + IsMaybeArgumentsObjectUsed:=OldIsMaybeArgumentsObjectUsed; + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal)); + end; + if assigned(Functions) then begin + Functions.Add(ToVisit); + result:=TBESENASTNodeEmptyStatement.Create(Instance); + TBESENASTNodeEmptyStatement(result).Location.LineNumber:=TBESENASTNodeFunctionDeclaration(ToVisit).Location.LineNumber; + end; + end; + bntEXPRESSIONSTATEMENT:begin + TBESENASTNodeExpressionStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression)); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter])); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + end; + bntCONTINUESTATEMENT:begin + TBESENASTNodeContinueStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier)); + end; + bntDOSTATEMENT:begin + TBESENASTNodeDoStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Statement)); + TBESENASTNodeDoStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Expression)); + end; + bntWHILESTATEMENT:begin + TBESENASTNodeWhileStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Expression)); + TBESENASTNodeWhileStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Statement)); + end; + bntWITHSTATEMENT:begin + if TBESEN(Instance).IsStrict then begin + raise EBESENSyntaxError.Create('"with" not allowed here'); + end; + TBESENASTNodeWithStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Expression)); + TBESENASTNodeWithStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Statement)); + end; + bntFORSTATEMENT:begin + TBESENASTNodeForStatement(ToVisit).Initial:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Initial)); + TBESENASTNodeForStatement(ToVisit).Condition:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Condition)); + TBESENASTNodeForStatement(ToVisit).Increment:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Increment)); + TBESENASTNodeForStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Statement)); + end; + bntFORINSTATEMENT:begin + TBESENASTNodeForInStatement(ToVisit).Variable:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Variable)); + TBESENASTNodeForInStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Expression)); + TBESENASTNodeForInStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Statement)); + end; + bntIFSTATEMENT:begin + TBESENASTNodeIfStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).Expression)); + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement)); + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement)); + end; + bntLABELLEDSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter])); + end; + TBESENASTNodeLabelledStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement)); + end; + bntCASESTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter])); + end; + end; + bntSWITCHSTATEMENT:begin + TBESENASTNodeSwitchStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression)); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter])); + end; + end; + bntTHROWSTATEMENT:begin + TBESENASTNodeThrowStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeThrowStatement(ToVisit).Expression)); + end; + bntTRYSTATEMENT:begin + TBESENASTNodeTryStatement(ToVisit).TryBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock)); + TBESENASTNodeTryStatement(ToVisit).CatchIdentifier:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier)); + TBESENASTNodeTryStatement(ToVisit).CatchBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock)); + TBESENASTNodeTryStatement(ToVisit).FinallyBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock)); + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]:=pointer(Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter])); + end; + end; + end; + bntBINARYEXPRESSION:begin + TBESENASTNodeBinaryExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTEXPRESSION:begin + TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression)); + end; + bntBINARYOPERATOREXPRESSION:begin + TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression)); + end; + bntBINARYCOMMAEXPRESSION:begin + TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression)); + end; + bntBINARYDIVIDEEXPRESSION:begin + TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression)); + end; + bntBINARYMODULOEXPRESSION:begin + TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression)); + end; + bntBINARYMULTIPLYEXPRESSION:begin + TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression)); + end; + bntBINARYPLUSEXPRESSION:begin + TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression)); + end; + bntBINARYMINUSEXPRESSION:begin + TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression)); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression)); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression)); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression)); + end; + bntBINARYGREATERTHANEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression)); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYLESSTHANEXPRESSION:begin + TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression)); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression)); + end; + bntBINARYINEXPRESSION:begin + TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression)); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYNOTEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYBITWISEANDEXPRESSION:begin + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression)); + end; + bntBINARYBITWISEXOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression)); + end; + bntBINARYBITWISEOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression)); + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + TBESENASTNodeCallExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter])); + end; + end; + bntNEWEXPRESSION:begin + TBESENASTNodeNewExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter])); + end; + end; + bntCONDITIONALEXPRESSION:begin + TBESENASTNodeConditionalExpression(ToVisit).Expression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression)); + TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression)); + TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression)); + end; + bntUNARYEXPRESSION:begin + TBESENASTNodeUnaryExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression)); + end; + bntUNARYOPERATOREXPRESSION:begin + TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression)); + end; + bntUNARYPLUSEXPRESSION:begin + TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression)); + end; + bntUNARYMINUSEXPRESSION:begin + TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression)); + end; + bntUNARYBITWISENOTEXPRESSION:begin + TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression)); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression)); + end; + bntUNARYVOIDEXPRESSION:begin + TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression)); + end; + bntUNARYTYPEOFEXPRESSION:begin + TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression)); + end; + bntPROPERTYEXPRESSION:begin + TBESENASTNodePropertyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression)); + TBESENASTNodePropertyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression)); + end; + bntLOGICALANDEXPRESSION:begin + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression)); + end; + bntLOGICALOREXPRESSION:begin + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression)); + end; + bntDELETEEXPRESSION:begin + TBESENASTNodeDeleteExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXINCEXPRESSION:begin + TBESENASTNodePostfixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXDECEXPRESSION:begin + TBESENASTNodePostfixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression)); + end; + bntPREFIXINCEXPRESSION:begin + TBESENASTNodePrefixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression)); + end; + bntPREFIXDECEXPRESSION:begin + TBESENASTNodePrefixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression)); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Value:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal)); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]:=pointer(Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter])); + end; + end; + bntRETURNSTATEMENT:begin + if not IsFunction then begin + raise EBESENSyntaxError.Create('Return outside a function'); + end; + TBESENASTNodeReturnStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeReturnStatement(ToVisit).Expression)); + end; + bntPROGRAM:begin + OldIsFunction:=IsFunction; + OldFunctionLiteral:=FunctionLiteral; + OldIsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; + IsFunction:=false; + IsMaybeArgumentsObjectUsed:=false; + FunctionLiteral:=nil; + TBESENASTNodeProgram(ToVisit).Body:=pointer(Visit(TBESENASTNodeProgram(ToVisit).Body)); + FunctionLiteral:=OldFunctionLiteral; + IsFunction:=OldIsFunction; + IsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + TBESENASTNodeFunctionExpression(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal)); + end; + end; + end; + end; + end; + begin + Functions:=nil; + Variables:=nil; + VariableHashMap:=nil; + AreLocalsOptimizable:=true; + IsFunction:=false; + IsMaybeArgumentsObjectUsed:=false; + FunctionLiteral:=nil; + Visit(RootNode); + end; + function Optimize(RootNode:TBESENASTNode):TBESENASTNode; + var vl,vr:TBESENValue; + function Visit(ToVisit:TBESENASTNode):TBESENASTNode; + var Counter,LastLineNumber:integer; + nr:TBESENNumber; + sr:TBESENString; + br,OldIsStrict:TBESENBoolean; + begin + result:=ToVisit; + if assigned(ToVisit) then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + end; + bntVARIABLEDECLARATION:begin + TBESENASTNodeVariableDeclaration(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier)); + TBESENASTNodeVariableDeclaration(ToVisit).Expression:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression)); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONBODY:begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + TBESEN(Instance).IsStrict:=TBESENASTNodeFunctionBody(ToVisit).IsStrict; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter])); + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter])); + end; + TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeFunctionBody(ToVisit).Statements); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter])); + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; + end; + bntFUNCTIONLITERAL:begin + TBESENASTNodeFunctionLiteral(ToVisit).Body:=pointer(Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body)); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal)); + end; + end; + bntEXPRESSIONSTATEMENT:begin + TBESENASTNodeExpressionStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression)); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeBlockStatement(ToVisit).Statements); + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter])); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + end; + bntCONTINUESTATEMENT:begin + TBESENASTNodeContinueStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier)); + end; + bntDOSTATEMENT:begin + TBESENASTNodeDoStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Statement)); + TBESENASTNodeDoStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Expression)); + if ConvertToValue(TBESENASTNodeDoStatement(ToVisit).Expression,vl) then begin + if not TBESEN(Instance).ToBool(vl) then begin + if assigned(TBESENASTNodeDoStatement(ToVisit).Statement) then begin + result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); + AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Statement); + TBESENASTNodeDoStatement(ToVisit).Statement:=nil; + TBESENASTNodeDoStatement(ToVisit).Expression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeDoStatement(ToVisit).Statement; + AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Expression); + TBESENASTNodeDoStatement(ToVisit).Statement:=nil; + TBESENASTNodeDoStatement(ToVisit).Expression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + if not assigned(result) then begin + result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); + end; + end; + bntWHILESTATEMENT:begin + TBESENASTNodeWhileStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Expression)); + TBESENASTNodeWhileStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Statement)); + if ConvertToValue(TBESENASTNodeWhileStatement(ToVisit).Expression,vl) then begin + if not TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + TBESENASTNodeEmptyStatement(result).Location.LineNumber:=TBESENASTNodeFunctionDeclaration(ToVisit).Location.LineNumber; + AddTrashNode(result,TBESENASTNodeWhileStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeWhileStatement(ToVisit).Statement); + TBESENASTNodeWhileStatement(ToVisit).Statement:=nil; + TBESENASTNodeWhileStatement(ToVisit).Expression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + if not assigned(result) then begin + result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); + end; + end; + bntWITHSTATEMENT:begin + TBESENASTNodeWithStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Expression)); + TBESENASTNodeWithStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Statement)); + end; + bntFORSTATEMENT:begin + TBESENASTNodeForStatement(ToVisit).Initial:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Initial)); + TBESENASTNodeForStatement(ToVisit).Condition:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Condition)); + TBESENASTNodeForStatement(ToVisit).Increment:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Increment)); + TBESENASTNodeForStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Statement)); + end; + bntFORINSTATEMENT:begin + TBESENASTNodeForInStatement(ToVisit).Variable:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Variable)); + TBESENASTNodeForInStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Expression)); + TBESENASTNodeForInStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Statement)); + end; + bntIFSTATEMENT:begin + LastLineNumber:=ToVisit.Location.LineNumber; + TBESENASTNodeIfStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).Expression)); + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement)); + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement)); + if ConvertToValue(TBESENASTNodeIfStatement(ToVisit).Expression,vl) then begin + if TBESEN(Instance).ToBool(vl) then begin + if assigned(TBESENASTNodeIfStatement(ToVisit).TrueStatement) then begin + result:=TBESENASTNodeIfStatement(ToVisit).TrueStatement; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + result.Location.LineNumber:=LastLineNumber; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end; + end else begin + if assigned(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin + result:=TBESENASTNodeIfStatement(ToVisit).FalseStatement; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + result.Location.LineNumber:=LastLineNumber; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + if not assigned(result) then begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + result.Location.LineNumber:=LastLineNumber; + end; + end; + bntLABELLEDSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter])); + end; + TBESENASTNodeLabelledStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement)); + end; + bntCASESTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeCaseStatement(ToVisit).Statements); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter])); + end; + end; + bntSWITCHSTATEMENT:begin + TBESENASTNodeSwitchStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression)); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter])); + end; + end; + bntTHROWSTATEMENT:begin + TBESENASTNodeThrowStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeThrowStatement(ToVisit).Expression)); + end; + bntTRYSTATEMENT:begin + TBESENASTNodeTryStatement(ToVisit).TryBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock)); + TBESENASTNodeTryStatement(ToVisit).CatchIdentifier:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier)); + TBESENASTNodeTryStatement(ToVisit).CatchBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock)); + TBESENASTNodeTryStatement(ToVisit).FinallyBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock)); + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]:=pointer(Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter])); + end; + end; + end; + bntBINARYEXPRESSION:begin + end; + bntASSIGNMENTEXPRESSION:begin + TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression)); + end; + bntBINARYOPERATOREXPRESSION:begin + TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression)); + end; + bntBINARYCOMMAEXPRESSION:begin + TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression)); + end; + bntBINARYDIVIDEEXPRESSION:begin + TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESEN(Instance).ToNum(vl)/TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYMODULOEXPRESSION:begin + TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression,vr) then begin + nr:=BESENModulo(TBESEN(Instance).ToNum(vl),TBESEN(Instance).ToNum(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYMULTIPLYEXPRESSION:begin + TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESEN(Instance).ToNum(vl)*TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYPLUSEXPRESSION:begin + TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression,vr) then begin + if (TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression is TBESENASTNodeStringLiteral) or (TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral) then begin + sr:=TBESEN(Instance).ToStr(vl)+TBESEN(Instance).ToStr(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeStringLiteral.Create(Instance); + TBESENASTNodeStringLiteral(result).Value:=sr; + end else begin + nr:=TBESEN(Instance).ToNum(vl)+TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + end; + bntBINARYMINUSEXPRESSION:begin + TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESEN(Instance).ToNum(vl)-TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) shl (TBESEN(Instance).ToUInt32(vr) and 31)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression,vr) then begin + nr:=sar(TBESEN(Instance).ToInt32(vl),(TBESEN(Instance).ToUInt32(vr) and 31)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENUINT32(TBESEN(Instance).ToUInt32(vl) shr (TBESEN(Instance).ToUInt32(vr) and 31)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYGREATERTHANEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)>0; + end; + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)>=0; + end; + end; + bntBINARYLESSTHANEXPRESSION:begin + TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)<0; + end; + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)<=0; + end; + end; + bntBINARYINSTANCEOFEXPRESSION:begin + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression)); + end; + bntBINARYINEXPRESSION:begin + TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression)); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionEquals(vl,vr); + end; + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=BESENEqualityExpressionStrictEquals(vl,vr); + end; + end; + bntBINARYNOTEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=not TBESEN(Instance).EqualityExpressionEquals(vl,vr); + end; + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=not BESENEqualityExpressionStrictEquals(vl,vr); + end; + end; + bntBINARYBITWISEANDEXPRESSION:begin + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) and TBESEN(Instance).ToInt32(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYBITWISEXOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) xor TBESEN(Instance).ToInt32(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYBITWISEOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) or TBESEN(Instance).ToInt32(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + TBESENASTNodeCallExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter])); + end; + end; + bntNEWEXPRESSION:begin + TBESENASTNodeNewExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter])); + end; + end; + bntCONDITIONALEXPRESSION:begin + TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression)); + TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression)); + if ConvertToValue(TBESENASTNodeConditionalExpression(ToVisit).Expression,vl) then begin + if TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeConditionalExpression(ToVisit).TrueExpression; + TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeConditionalExpression(ToVisit).FalseExpression; + TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + bntUNARYEXPRESSION:begin + TBESENASTNodeUnaryExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression)); + end; + bntUNARYOPERATOREXPRESSION:begin + TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression)); + end; + bntUNARYPLUSEXPRESSION:begin + TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,vl) then begin + nr:=TBESEN(Instance).ToNum(vl); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntUNARYMINUSEXPRESSION:begin + TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression,vl) then begin + nr:=TBESEN(Instance).ToNum(vl); + PBESENDoubleHiLo(@nr)^.Hi:=PBESENDoubleHiLo(@nr)^.Hi xor $80000000; + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntUNARYBITWISENOTEXPRESSION:begin + TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression,vl) then begin + nr:=TBESENINT32(not TBESEN(Instance).ToInt32(vl)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntUNARYLOGICALNOTEXPRESSION:begin + TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression,vl) then begin + br:=not TBESEN(Instance).ToBool(vl); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=br; + end; + end; + bntUNARYVOIDEXPRESSION:begin + TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression)); + end; + bntUNARYTYPEOFEXPRESSION:begin + TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression)); + end; + bntPROPERTYEXPRESSION:begin + TBESENASTNodePropertyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression)); + TBESENASTNodePropertyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression)); + end; + bntLOGICALANDEXPRESSION:begin + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,vl) then begin + ConvertToValue(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,vr); + if vl.ValueType=vr.ValueType then begin + if TBESEN(Instance).ToBool(vr) then begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end else begin + if TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + end; + bntLOGICALOREXPRESSION:begin + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression,vl) then begin + ConvertToValue(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression,vr); + if vl.ValueType=vr.ValueType then begin + if TBESEN(Instance).ToBool(vr) then begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end else begin + if TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + end; + bntDELETEEXPRESSION:begin + TBESENASTNodeDeleteExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXINCEXPRESSION:begin + TBESENASTNodePostfixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXDECEXPRESSION:begin + TBESENASTNodePostfixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression)); + end; + bntPREFIXINCEXPRESSION:begin + TBESENASTNodePrefixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression)); + end; + bntPREFIXDECEXPRESSION:begin + TBESENASTNodePrefixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression)); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Value:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal)); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]:=pointer(Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter])); + end; + end; + bntRETURNSTATEMENT:begin + TBESENASTNodeReturnStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeReturnStatement(ToVisit).Expression)); + end; + bntPROGRAM:begin + TBESENASTNodeProgram(ToVisit).Body:=pointer(Visit(TBESENASTNodeProgram(ToVisit).Body)); + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + TBESENASTNodeFunctionExpression(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal)); + end; + end; + end; + end; + end; + begin + result:=Visit(RootNode); + end; + procedure GenerateByteCode(RootNode:TBESENASTNode); + var Code:TBESENCode; + CodeGeneratorContext:TBESENCodeGeneratorContext; + OptimizeLocals,HasFunctions,DoHasLocalDelete,DoIsComplexFunction,DoHasMaybeDirectEval,DoHoldLocalVariablesInRegisters:boolean; + procedure Visit(ToVisit:TBESENASTNode;var DestRegNr:integer;CalleeNeedReturnedValue:boolean); + var Counter,L1,L2,L3,L3a,L3b,P1,P2,PR,PR2,r1,r2,r3,r4,r5,r6,v1:integer; + OldCode:TBESENCode; + OldCodeGeneratorContext:TBESENCodeGeneratorContext; + v:TBESENValue; + OldVarScope,OldDoHasLocalDelete,OldOptimizeLocals,OldHasFunctions,OldDoIsComplexFunction,OldDoHasMaybeDirectEval,OldDoHoldLocalVariablesInRegisters,DefaultCase,InScope:boolean; + Patchables:TBESENCodeGeneratorContextPatchables; + SwitchPatches:array of integer; + vta,vtb,vtc,vtd,vte,vtTemp,vtBegin,vtInner,vtEnd:TBESENValueTypes; + RegStates:array[0..3] of TBESENCodeGeneratorContextRegisterStates; + Operands:array of TBESENINT32; + hi:PBESENHashMapItem; + Hash:TBESENHash; + IsWhat1,IsWhat2:longword; + function IsValue(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)=0; + end; + function IsPrimitive(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat and (bcgtREFERENCE or bcgtOBJECT))=0; + end; + function IsLocalVariableReference(const r:integer):boolean; + begin + result:=DoHoldLocalVariablesInRegisters and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)); + end; + function IsValueBoolean(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtBOOLEAN) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtBOOLEAN)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtBOOLEAN; + end; + end; + function IsValueNumber(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtNUMBER) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtNUMBER)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtNUMBER; + end; + end; + function IsValueString(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtSTRING) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtSTRING)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtSTRING; + end; + end; + function IsValueObject(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtOBJECT) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtOBJECT)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtOBJECT; + end; + end; + function IsValuePrimitive(const r:integer):boolean; + begin + result:=((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType in [bvtBOOLEAN,bvtNUMBER,bvtSTRING])) or ((CodeGeneratorContext.Registers[r].IsWhat and (bcgtREFERENCE or bcgtOBJECT))=0); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name) in [bvtBOOLEAN,bvtNUMBER,bvtSTRING]; + end; + end; + function IsNodeLocalVarReg(Node:TBESENASTNode;var r:integer):boolean; + begin + if DoHoldLocalVariablesInRegisters and (assigned(Node) and ((Node is TBESENASTNodeIdentifier) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(Node).Name))) then begin + r:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(Node).Name); + end else begin + r:=-1; + end; + result:=r>=0; + end; + function IsNodeLocalVarRegister(Node:TBESENASTNode):boolean; + begin + result:=(DoHoldLocalVariablesInRegisters and (assigned(Node) and ((Node is TBESENASTNodeIdentifier) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(Node).Name)))) and (CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(Node).Name)>0); + end; + procedure GenSetC(const r:integer); + begin + if IsValueBoolean(r) then begin + Code.GenOp(bopSETCBOOL,r); + end else if IsValueNumber(r) then begin + Code.GenOp(bopSETCNUM,r); + end else if IsValueString(r) then begin + Code.GenOp(bopSETCSTR,r); + end else if IsValueObject(r) then begin + Code.GenOp(bopSETCOBJ,r); + end else begin + if IsLocalVariableReference(r) then begin + Code.GenOp(bopSETC,r); + end else if (CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType in [bvtUNDEFINED,bvtNULL]) then begin + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtNULL:begin + Code.GenOp(bopSETCNULL); + end; + else begin + Code.GenOp(bopSETC,r); + end; + end; + end else begin + Code.GenOp(bopSETC,r); + end; + end; + end; + procedure GenGetValueEx(const r,DestRegNr:integer); + begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopCOPY,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end else begin + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopGETVALUELOCALINDEXBOOL,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopGETVALUELOCALINDEXNUM,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopGETVALUELOCALINDEXSTR,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopGETVALUELOCALINDEXOBJ,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopGETVALUELOCALINDEX,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end; + end; + procedure GenPutValueEx(const r,SrcRegNr:integer;ValueType:TBESENValueType=bvtUNDEFINED); + begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,r,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,r,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,r,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,r,SrcRegNr); + end; + else begin + Code.GenOp(bopCOPY,r,SrcRegNr); + end; + end; + end else begin + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopPUTVALUELOCALINDEXBOOL,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopPUTVALUELOCALINDEXNUM,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopPUTVALUELOCALINDEXSTR,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopPUTVALUELOCALINDEXOBJ,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + else begin + Code.GenOp(bopPUTVALUELOCALINDEX,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + end; + end; + end; + procedure GenGetValue(const r,DestRegNr:integer); + begin + if (CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)<>0 then begin + if CodeGeneratorContext.Registers[r].IsLocal then begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopCOPY,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end else if (not DoHasLocalDelete) and CodeGeneratorContext.VariableGetInitialized(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex)) then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopGETVALUELOCALINDEXBOOL,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopGETVALUELOCALINDEXNUM,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopGETVALUELOCALINDEXSTR,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopGETVALUELOCALINDEXOBJ,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopGETVALUELOCALINDEX,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end else begin + Code.GenOp(bopGETVALUELOCAL,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end else begin + Code.GenOp(bopGETVALUEREF,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end else begin + Code.GenOp(bopGETVALUE,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + procedure GenPutValue(const r,SrcRegNr:integer;ValueType:TBESENValueType=bvtUNDEFINED); + begin + if (CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)<>0 then begin + if CodeGeneratorContext.Registers[r].IsLocal then begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,r,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,r,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,r,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,r,SrcRegNr); + end; + else begin + Code.GenOp(bopCOPY,r,SrcRegNr); + end; + end; + end else if (not DoHasLocalDelete) and (CodeGeneratorContext.VariableGetInitialized(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex)) and + CodeGeneratorContext.VariableGetMutableOrDeletable(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopPUTVALUELOCALINDEXBOOL,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopPUTVALUELOCALINDEXNUM,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopPUTVALUELOCALINDEXSTR,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopPUTVALUELOCALINDEXOBJ,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + else begin + Code.GenOp(bopPUTVALUELOCALINDEX,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + end; + end else begin + Code.GenOp(bopPUTVALUELOCAL,r,SrcRegNr); + end; + end else begin + Code.GenOp(bopPUTVALUEREF,r,SrcRegNr); + end; + end else begin + Code.GenOp(bopPUTVALUE,r,SrcRegNr); + end; + end; + procedure AssignSetType(const n:TBESENASTNode;const t:TBESENValueType); + begin + if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin + case n.NodeType of + bntIDENTIFIER:begin + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(n).Name) then begin + CodeGeneratorContext.VariableSetType(TBESENASTNodeIdentifier(n).Name,t); + end; + end; + end; + end; + end; + procedure AssignSetWhatType(const n:TBESENASTNode;const wt:longword); + begin + if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin + case wt of + bcgtBOOLEAN:begin + AssignSetType(n,bvtBOOLEAN); + end; + bcgtNUMBER:begin + AssignSetType(n,bvtNUMBER); + end; + bcgtSTRING:begin + AssignSetType(n,bvtSTRING); + end; + bcgtOBJECT:begin + AssignSetType(n,bvtOBJECT); + end; + else begin + AssignSetType(n,bvtUNDEFINED); + end; + end; + end; + end; + function AssignGetType(const n:TBESENASTNode):TBESENValueType; + begin + result:=bvtUNDEFINED; + if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin + case n.NodeType of + bntIDENTIFIER:begin + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(n).Name) then begin + result:=CodeGeneratorContext.VariableGetType(TBESENASTNodeIdentifier(n).Name); + end; + end; + end; + end; + end; + procedure AssignOpPre; + begin + if DestRegNr<0 then begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + end; + r1:=-1; + r2:=-1; + r3:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + if IsValueNumber(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r3,r1); + end; + end else begin + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r3:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValue(r1,r3); + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r4); + Code.GenOp(bopTONUMBER,r3,r4); + CodeGeneratorContext.DeallocateRegister(r4); + end; + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r5:=r2; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r5); + end; + if IsValueNumber(r2) then begin + r4:=r5; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r4,r5); + if r2<>r5 then begin + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end; + procedure AssignOpAddPre; + begin + if DestRegNr<0 then begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + end; + r1:=-1; + r2:=-1; + r3:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + if IsValuePrimitive(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r3,r1); + end; + end else begin + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r3:=CodeGeneratorContext.AllocateRegister; + if IsValuePrimitive(r1) then begin + GenGetValue(r1,r3); + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r4); + Code.GenOp(bopTOPRIMITIVE,r3,r4); + CodeGeneratorContext.DeallocateRegister(r4); + end; + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r5:=r2; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r5); + end; + if IsValuePrimitive(r2) then begin + r4:=r5; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r4,r5); + if r2<>r5 then begin + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end; + procedure AssignOpShiftPre; + begin + if DestRegNr<0 then begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r3:=r1; + end else begin + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end; + procedure AssignOpPost(Number,Str,FromRight:boolean); + begin + if IsLocalVariableReference(r1) then begin + if DestRegNr=r1 then begin + if Number then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtNUMBER); + end else if Str then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtSTRING); + end else if FromRight then begin + if IsValueBoolean(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtBOOLEAN); + end else if IsValueNumber(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtNUMBER); + end else if IsValueString(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtSTRING); + end else if IsValueObject(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtOBJECT); + end else begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtUNDEFINED); + end; + end else begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtUNDEFINED); + end; + end else begin + if Number then begin + Code.GenOp(bopCOPYNUM,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if Str then begin + Code.GenOp(bopCOPYSTR,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if FromRight then begin + if IsValueBoolean(r2) then begin + Code.GenOp(bopCOPYBOOL,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end else if IsValueNumber(r2) then begin + Code.GenOp(bopCOPYNUM,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if IsValueString(r2) then begin + Code.GenOp(bopCOPYSTR,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueObject(r2) then begin + Code.GenOp(bopCOPYOBJ,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end else begin + Code.GenOp(bopCOPY,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + end else begin + Code.GenOp(bopCOPY,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + end; + end else begin + if Number then begin + GenPutValue(r1,DestRegNr,bvtNUMBER); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if Str then begin + GenPutValue(r1,DestRegNr,bvtSTRING); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if FromRight then begin + if IsValueBoolean(r2) then begin + GenPutValue(r1,DestRegNr,bvtBOOLEAN); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end else if IsValueNumber(r2) then begin + GenPutValue(r1,DestRegNr,bvtNUMBER); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if IsValueString(r2) then begin + GenPutValue(r1,DestRegNr,bvtSTRING); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueObject(r2) then begin + GenPutValue(r1,DestRegNr,bvtOBJECT); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end else begin + GenPutValue(r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + end else begin + GenPutValue(r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + procedure BinaryPre; + begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + end; + procedure BinaryNumberPre; + begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + if IsValueNumber(r1) then begin + r5:=r3; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r5,r3); + if r1<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r3); + end; + r3:=r5; + r5:=-1; + end; + if not IsValueNumber(r2) then begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r5,r4); + if r2<>r4 then begin + CodeGeneratorContext.DeallocateRegister(r4); + end; + r4:=r5; + r5:=-1; + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + procedure BinaryPost; + begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + function AreStrictValueTypesEqual(const vtBefore,vtAfter:TBESENValueTypes):boolean; + var i,j:integer; + begin + if length(vtBefore)<>length(vtAfter) then begin + result:=false; + end else begin + result:=true; + j:=min(length(vtBefore),length(vtAfter)); + for i:=0 to j-1 do begin + if vtBefore[i]<>vtAfter[i] then begin + result:=false; + break; + end; + end; + end; + end; + procedure ResetDifferentValueTypes(var vtBefore:TBESENValueTypes;vtAfter:TBESENValueTypes); + var i,MinLength,MaxLength,BeforeLength,AfterLength:integer; + begin + BeforeLength:=length(vtBefore); + AfterLength:=length(vtAfter); + MinLength:=min(BeforeLength,AfterLength); + MaxLength:=max(BeforeLength,AfterLength); + SetLength(vtBefore,MaxLength); + for i:=0 to MinLength-1 do begin + if vtBefore[i]<>vtAfter[i] then begin + vtBefore[i]:=bvtUNDEFINED; + end; + end; + for i:=MinLength to MaxLength-1 do begin + vtBefore[i]:=bvtUNDEFINED; + end; + end; + procedure ResetDifferentMultiValueTypes(var vtBefore:TBESENValueTypes;const vtAfter:TBESENValueTypesItems); + var i:integer; + begin + for i:=0 to length(vtAfter)-1 do begin + ResetDifferentValueTypes(vtBefore,vtAfter[i]); + end; + end; + begin + SwitchPatches:=nil; + vta:=nil; + vtb:=nil; + vtc:=nil; + vtd:=nil; + vte:=nil; + vtTemp:=nil; + vtBegin:=nil; + vtInner:=nil; + vtEnd:=nil; + for Counter:=low(RegStates) to high(RegStates) do begin + RegStates[Counter].Registers:=nil; + RegStates[Counter].MaxRegisters:=0; + end; + Operands:=nil; + v:=BESENEmptyValue; + if assigned(ToVisit) then begin + r1:=-1; + r2:=-1; + r3:=-1; + r4:=-1; + r5:=-1; + r6:=-1; + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNullValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; + end; + bntLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNullValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; + end; + bntIDENTIFIER:begin + if DoHoldLocalVariablesInRegisters and OptimizeLocals and (DestRegNr<0) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(ToVisit).Name) then begin + p1:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(ToVisit).Name); + end else begin + p1:=-1; + end; + if p1>=0 then begin + DestRegNr:=p1; + CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name); + CodeGeneratorContext.Registers[DestRegNr].IsLocal:=true; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=AssignGetType(ToVisit); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=-1; + CodeGeneratorContext.Registers[DestRegNr].IsLocal:=false; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + Hash:=BESENHashKey(TBESENASTNodeIdentifier(ToVisit).Name); + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(ToVisit).Name) then begin + if OptimizeLocals then begin + CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name); + CodeGeneratorContext.Registers[DestRegNr].IsLocal:=true; + Code.GenOp(bopLREF,DestRegNr,CodeGeneratorContext.Registers[DestRegNr].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=AssignGetType(ToVisit); + end else begin + Code.GenOp(bopVREF,DestRegNr,CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end; + end else begin + hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeIdentifier(ToVisit).Name); + if not assigned(hi) then begin + hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeIdentifier(ToVisit).Name,true); + hi^.Value:=Code.LookupNames.Add(TBESENASTNodeIdentifier(ToVisit).Name); + end; + Code.GenOp(bopLOOKUP,DestRegNr,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; + end; + end; + bntVARIABLEDECLARATION:begin + if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Identifier) then begin + TBESENASTNodeVariableDeclaration(ToVisit).Identifier.IsReached:=true; + end; + if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Identifier) and assigned(TBESENASTNodeVariableDeclaration(ToVisit).Expression) then begin + if DoHoldLocalVariablesInRegisters and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + r1:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + end else begin + r1:=-1; + end; + if r1>=0 then begin + r2:=-1; + PR:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r2) then begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); + end else if IsValue(r2) then begin + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r1,true); + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r1].IsWhat); + end else begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); + end; + CodeGeneratorContext.Registers[r1].IsWhat:=bcgtREFERENCE; + if CodeGeneratorContext.VariableGetMutableOrDeletable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true,true); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + r1:=CodeGeneratorContext.AllocateRegister; + r2:=-1; + Hash:=BESENHashKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + if OptimizeLocals then begin + Code.GenOp(bopLREF,r1,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name)); + end else begin + Code.GenOp(bopVREF,r1,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end; + end else begin + hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + if not assigned(hi) then begin + hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true); + hi^.Value:=Code.LookupNames.Add(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + end; + Code.GenOp(bopLOOKUP,r1,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); + end; + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); + if IsValue(r2) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + end; + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + if OptimizeLocals then begin + Code.GenOp(bopPUTVALUELOCAL,r1,r3); + end else begin + Code.GenOp(bopPUTVALUEREF,r1,r3); + end; + end else begin + Code.GenOp(bopPUTVALUE,r1,r3); + end; + if CodeGeneratorContext.VariableGetMutableOrDeletable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true,true); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; +{ end else if CalleeNeedReturnedValue then begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,DestRegNr,true);} + end; + end; + bntVARIABLEEXPRESSION:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if DestRegNr<0 then begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + r1:=-1; + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter],DestRegNr,true); + end; + end; + end; + bntFUNCTIONBODY:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + OldCode:=Code; + OldCodeGeneratorContext:=CodeGeneratorContext; + Code:=TBESENCode(TBESENASTNodeFunctionBody(ToVisit).Code); + CodeGeneratorContext:=TBESENCodeGeneratorContext.Create(Instance); + CodeGeneratorContext.Code:=Code; + OldDoHasLocalDelete:=DoHasLocalDelete; + OldDoIsComplexFunction:=DoIsComplexFunction; + OldDoHasMaybeDirectEval:=DoHasMaybeDirectEval; + OldOptimizeLocals:=OptimizeLocals; + OldHasFunctions:=HasFunctions; + OldDoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; + HasFunctions:=false; + OptimizeLocals:=TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization; + try + DoHasLocalDelete:=false; + DoIsComplexFunction:=not TBESENASTNodeFunctionBody(ToVisit).IsFunction; + DoHasMaybeDirectEval:=false; + HasFunctions:=length(TBESENASTNodeFunctionBody(ToVisit).Functions)>0; + DoHoldLocalVariablesInRegisters:=TBESENASTNodeFunctionBody(ToVisit).IsFunction; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + CheckNodeForFeatures(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter],DoHasLocalDelete,DoIsComplexFunction,DoHasMaybeDirectEval,HasFunctions,DoHoldLocalVariablesInRegisters); + end; + DoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters and (OptimizeLocals and not (DoHasLocalDelete or DoIsComplexFunction or DoHasMaybeDirectEval or HasFunctions)); + if TBESENASTNodeFunctionBody(ToVisit).IsStrict then begin + Code.GenOp(bopSTRICT,1); + end else begin + Code.GenOp(bopSTRICT,0); + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + r1:=-1; + Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + if assigned(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]) and (TBESENASTNodeFunctionBody(ToVisit).Functions[Counter] is TBESENASTNodeFunctionDeclaration) then begin + if assigned(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal) and assigned(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name) then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,true,false,-1); + CodeGeneratorContext.VariableSetType(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,bvtUNDEFINED); + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,false,false); + end; + end; + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,true,TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter,TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].ParameterIndex); + CodeGeneratorContext.VariableSetType(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,bvtUNDEFINED); + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,false,not DoHasLocalDelete); + if DoHoldLocalVariablesInRegisters and not TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter then begin + r1:=CodeGeneratorContext.AllocateRegister; + CodeGeneratorContext.Registers[r1].Variable:=Counter; + CodeGeneratorContext.VariableSetRegister(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,r1); + end else begin + CodeGeneratorContext.VariableSetRegister(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,-1); + end; + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + r1:=-1; + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + if DoHoldLocalVariablesInRegisters then begin + for Counter:=0 to length(CodeGeneratorContext.Registers)-1 do begin + if CodeGeneratorContext.Registers[Counter].Variable>=0 then begin + CodeGeneratorContext.Registers[Counter].Variable:=-1; + r1:=Counter; + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + end; + if TBESENASTNodeFunctionBody(ToVisit).IsFunction then begin + Code.GenOp(bopSETCUNDEF); + end; + Code.GenOp(bopEND,0); + Code.HasLocalDelete:=DoHasLocalDelete; + Code.IsComplexFunction:=DoIsComplexFunction; + Code.HasMaybeDirectEval:=DoHasMaybeDirectEval; + Code.HoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; + Code.MaxBlock:=CodeGeneratorContext.MaxBlockDepth; + Code.MaxLoop:=CodeGeneratorContext.MaxLoopDepth; + Code.MaxParamArgs:=CodeGeneratorContext.MaxParamArgs; + Code.MaxRegisters:=CodeGeneratorContext.MaxRegisters; + finally + BESENFreeAndNil(CodeGeneratorContext); + Code:=OldCode; + CodeGeneratorContext:=OldCodeGeneratorContext; + DoHasLocalDelete:=OldDoHasLocalDelete; + DoIsComplexFunction:=OldDoIsComplexFunction; + DoHasMaybeDirectEval:=OldDoHasMaybeDirectEval; + OptimizeLocals:=OldOptimizeLocals; + HasFunctions:=OldHasFunctions; + DoHoldLocalVariablesInRegisters:=OldDoHoldLocalVariablesInRegisters; + end; + end; + bntFUNCTIONLITERAL:begin + r1:=-1; + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + if TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).ByteCodeLen=0 then begin + TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).GenOp(bopEND,0); + end; + TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).Finish; + end; + bntSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + end; + bntVARIABLESTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if DestRegNr<0 then begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + r1:=-1; + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter],DestRegNr,true); + end; + end; + end; + bntFUNCTIONDECLARATION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal,DestRegNr,true); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if Code.Body.IsFunction then begin + PR:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + vta:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + CodeGeneratorContext.VariableSetTypes(vta); + Code.Restore(PR); + r1:=-1; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + r1:=-1; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if not Code.Body.IsFunction then begin + GenSetC(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + bntEMPTYSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + end; + bntBLOCKSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if DestRegNr<0 then begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + r1:=-1; + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter],DestRegNr,true); + end; + end; + end; + bntDEBUGGERSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + Code.GenOp(bopDEBUGGER); + end; + bntBREAKSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + Patchables:=CodeGeneratorContext.FindPatchables(TBESENASTNodeBreakStatement(ToVisit).Target,false); + if assigned(Patchables) then begin + if Patchables.BlockDepth<CodeGeneratorContext.BlockDepth then begin + Code.GenOp(bopEND,Patchables.BlockDepth+1); + end; + Patchables.AddBreak(Code.GenOp(bopJMP,0)+1,CodeGeneratorContext.VariableGetTypes); + end; + end; + bntCONTINUESTATEMENT:begin + Code.GenLocation(ToVisit.Location); + Patchables:=CodeGeneratorContext.FindPatchables(TBESENASTNodeContinueStatement(ToVisit).Target,true); + if assigned(Patchables) then begin + if Patchables.BlockDepth<CodeGeneratorContext.BlockDepth then begin + Code.GenOp(bopEND,Patchables.BlockDepth+1); + end; + Patchables.AddContinue(Code.GenOp(bopJMP,0)+1,CodeGeneratorContext.VariableGetTypes); + end; + end; + bntDOSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeDoStatement(ToVisit).Statement) then begin + + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + + // Pass one - Collecting value type differences and generating final code if value types are static + // *** vta = Before do statement + // * vtb = After do statement and before do while expression + // * vtc = After do while expression + begin + CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); + + vta:=CodeGeneratorContext.VariableGetTypes; + L1:=Code.Here; + Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + vtb:=CodeGeneratorContext.VariableGetTypes; + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + + vtc:=CodeGeneratorContext.VariableGetTypes; + + vtInner:=copy(vta,0,length(vta)); + ResetDifferentValueTypes(vtInner,vtb); + ResetDifferentValueTypes(vtInner,vtc); + + if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); + ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); + end; + + vtEnd:=copy(vtInner,0,length(vtInner)); + if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); + ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); + end; + + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + + // Pass two - Generating final loop code if value types are different + if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); + + CodeGeneratorContext.VariableSetTypes(vtInner); + L1:=Code.Here; + Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + CodeGeneratorContext.VariableSetTypes(vtInner); + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + end else begin + // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop + CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); + L1:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + CodeGeneratorContext.PopPatchables(L2,L3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + dec(CodeGeneratorContext.LoopDepth); + end; + bntWHILESTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeWhileStatement(ToVisit).Statement) then begin + + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + + // Pass one - Collecting value type differences and generating final code if value types are static + // *** vta = Before first while expression execution and before while statement + // * vtb = Before while expression + // * vtc = After while expression + begin + Code.GenLocation(ToVisit.Location); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); + + vta:=CodeGeneratorContext.VariableGetTypes; + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + + vtb:=CodeGeneratorContext.VariableGetTypes; + Code.GenLabel(P1); + r1:=-1; + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + + vtc:=CodeGeneratorContext.VariableGetTypes; + + vtInner:=copy(vta,0,length(vta)); + ResetDifferentValueTypes(vtInner,vtb); + ResetDifferentValueTypes(vtInner,vtc); + + if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); + ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); + end; + + vtEnd:=copy(vtInner,0,length(vtInner)); + if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); + ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); + end; + + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + + // Pass two - Generating final loop code if value types are different + if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + + CodeGeneratorContext.VariableSetTypes(vtInner); + + Code.GenLocation(ToVisit.Location); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); + + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + CodeGeneratorContext.VariableSetTypes(vtInner); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + + Code.GenLabel(P1); + CodeGeneratorContext.VariableSetTypes(vtInner); + r1:=-1; + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + + CodeGeneratorContext.VariableSetTypes(vtEnd); + + CodeGeneratorContext.PopPatchables(L2,L3); + end; + end else begin + // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + Code.GenLabel(P1); + L2:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Code.GenLocation(ToVisit.Location); + + r1:=CodeGeneratorContext.AllocateRegister; + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + CodeGeneratorContext.PopPatchables(L2,L3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + dec(CodeGeneratorContext.LoopDepth); + end; + bntWITHSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeWithStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueObject(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOOBJECT,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + if r1<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r1); + end; + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + Code.GenOp(bopSWITH,r3); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.BlockEnter; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + OldVarScope:=CodeGeneratorContext.VariableSetAllScope(false); + OldOptimizeLocals:=OptimizeLocals; + OptimizeLocals:=false; + Visit(TBESENASTNodeWithStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + OptimizeLocals:=OldOptimizeLocals; + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.VariableSetAllScope(OldVarScope); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + bntFORSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeForStatement(ToVisit).Statement) then begin + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + + // Pass one - Collecting value type differences and generating final code if value types are static + // *** vta = Before initial expression + // * vtb = After conditional expression and before statement + // * vtc = After before statement and before increment expression + // * vtd = After increment expression and before conditional expression + // * vte = After conditional expression + begin + CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); + + vta:=CodeGeneratorContext.VariableGetTypes; + if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + vtTemp:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); + if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + Code.Restore(PR2); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + P1:=Code.GenOp(bopJMP,0)+1; + + vtb:=CodeGeneratorContext.VariableGetTypes; + L1:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin + Code.GenLocation(ToVisit.Location); + Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + + vtc:=CodeGeneratorContext.VariableGetTypes; + L2:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + vtTemp:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); + if r1>=0 then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + vtd:=CodeGeneratorContext.VariableGetTypes; + Code.GenLabel(P1); + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); + if r1>=0 then begin + if (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + Code.GenOp(bopJMP,L1); + end; + end else begin + Code.GenOp(bopJMP,L1); + end; + L3:=Code.Here; + + vte:=CodeGeneratorContext.VariableGetTypes; + + vtBegin:=copy(vta,0,length(vta)); + + vtInner:=copy(vtb,0,length(vtb)); + ResetDifferentValueTypes(vtInner,vtc); + ResetDifferentValueTypes(vtInner,vtd); + ResetDifferentValueTypes(vtInner,vte); + + if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); + ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); + end; + + vtEnd:=copy(vtInner,0,length(vtInner)); + if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); + ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); + end; + + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + + // Pass two - Generating final loop code if value types are different + if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtd) and AreStrictValueTypesEqual(vta,vte) and AreStrictValueTypesEqual(vta,vtBegin) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); + + CodeGeneratorContext.VariableSetTypes(vtBegin); + if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + vtTemp:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); + if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + P1:=Code.GenOp(bopJMP,0)+1; + + CodeGeneratorContext.VariableSetTypes(vtInner); + L1:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin + Code.GenLocation(ToVisit.Location); + Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + + CodeGeneratorContext.VariableSetTypes(vtInner); + L2:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + vtTemp:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); + if r1>=0 then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + CodeGeneratorContext.VariableSetTypes(vtInner); + Code.GenLabel(P1); + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); + if r1>=0 then begin + if (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + Code.GenOp(bopJMP,L1); + end; + end else begin + Code.GenOp(bopJMP,L1); + end; + L3:=Code.Here; + + CodeGeneratorContext.VariableSetTypes(vtEnd); + + CodeGeneratorContext.PopPatchables(L2,L3); + end; + end else begin + // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop + CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); + + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + + if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); + if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + + L2:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); + if r1>=0 then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + Code.GenLabel(P1); + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); + if r1>=0 then begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + Code.GenOp(bopJMP,L1); + end; + end else begin + Code.GenOp(bopJMP,L1); + end; + L3:=Code.Here; + + CodeGeneratorContext.PopPatchables(L2,L3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + dec(CodeGeneratorContext.LoopDepth); + end; + bntFORINSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + Code.GenLocation(ToVisit.Location); + if TBESENASTNodeForInStatement(ToVisit).Variable.NodeType=bntVARIABLEDECLARATION then begin + r1:=-1; + r2:=-1; + if assigned(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier) then begin + Visit(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier,r1,true); + end else begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable,r1,true); + end; + Visit(TBESENASTNodeForInStatement(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + end; + P2:=Code.GenOp(bopJNULL,0,r3)+1; + if IsValueObject(r2) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOOBJECT,r4,r3); + if r3<>r4 then begin + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + Code.GenOp(bopSENUM,r4); + r5:=CodeGeneratorContext.AllocateRegister; + CodeGeneratorContext.BlockEnter; + CodeGeneratorContext.PushPatchables(TBESENASTNodeForInStatement(ToVisit).Target,true); + P1:=Code.GenOp(bopJMP,0)+1; + L1:=Code.Here; + r3:=CodeGeneratorContext.AllocateRegister; + Hash:=BESENHashKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name) then begin + if IsLocalVariableReference(r1) then begin + Code.GenOp(bopCOPY,r1,r5); + end else if OptimizeLocals then begin + Code.GenOp(bopLREF,r3,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name)); + Code.GenOp(bopPUTVALUELOCAL,r3,r5); + end else begin + Code.GenOp(bopVREF,r3,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + Code.GenOp(bopPUTVALUEREF,r3,r5); + end; + end else begin + hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); + if not assigned(hi) then begin + hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name,true); + hi^.Value:=Code.LookupNames.Add(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); + end; + Code.GenOp(bopLOOKUP,r3,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); + Code.GenOp(bopPUTVALUEREF,r3,r5); + end; + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.Here; + Code.GenLabel(P1); + Code.GenOp(bopLOOPENUM,L1,r5); + L3:=Code.Here; + Code.GenLabel(P2); + CodeGeneratorContext.PopPatchables(L2,L3); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end else begin + r2:=-1; + Visit(TBESENASTNodeForInStatement(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + end; + P2:=Code.GenOp(bopJNULL,0,r3)+1; + if IsValueObject(r2) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOOBJECT,r4,r3); + if r3<>r4 then begin + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + Code.GenOp(bopSENUM,r4); + r5:=CodeGeneratorContext.AllocateRegister; + CodeGeneratorContext.BlockEnter; + CodeGeneratorContext.PushPatchables(TBESENASTNodeForInStatement(ToVisit).Target,true); + P1:=Code.GenOp(bopJMP,0)+1; + L1:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForInStatement(ToVisit).Variable,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + Code.GenOp(bopCOPY,r1,r5); + end else begin + Code.GenOp(bopPUTVALUE,r1,r5); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.Here; + Code.GenLabel(P1); + Code.GenOp(bopLOOPENUM,L1,r5); + L3:=Code.Here; + Code.GenLabel(P2); + CodeGeneratorContext.PopPatchables(L2,L3); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + dec(CodeGeneratorContext.LoopDepth); + end; + bntIFSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if OptimizeLocals and not (HasLabelBreakContinue(TBESENASTNodeIfStatement(ToVisit).TrueStatement) or HasLabelBreakContinue(TBESENASTNodeIfStatement(ToVisit).FalseStatement)) then begin + PR:=Code.Here; + + vta:=CodeGeneratorContext.VariableGetTypes; + + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeIfStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + L1:=Code.GenOp(bopJNZERO,0,r3)+1; + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + L1:=Code.GenOp(bopJZ,0,r3)+1; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + vtb:=CodeGeneratorContext.VariableGetTypes; + + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if IsBreakContinueReturnNode(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin + vtc:=copy(vtb,0,length(vtb)); + end else begin + vtc:=CodeGeneratorContext.VariableGetTypes; + end; + L2:=Code.GenOp(bopJMP,0)+1; + + Code.GenLabel(L1); + CodeGeneratorContext.VariableSetTypes(vtb); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if IsBreakContinueReturnNode(TBESENASTNodeIfStatement(ToVisit).TrueStatement) then begin + vtd:=copy(vtb,0,length(vtb)); + end else begin + vtd:=CodeGeneratorContext.VariableGetTypes; + end; + + Code.GenLabel(L2); + + vte:=copy(vtc,0,length(vtc)); + if not AreStrictValueTypesEqual(vte,vtd) then begin + ResetDifferentValueTypes(vte,vtd); + end; + + CodeGeneratorContext.VariableSetTypes(vte); + end else begin + // The if-statmente body contains break/continue or it's extremly type instable global code + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeIfStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + L1:=Code.GenOp(bopJNZERO,0,r3)+1; + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + L1:=Code.GenOp(bopJZ,0,r3)+1; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + Code.GenLabel(L2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + end; + bntLABELLEDSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.PushPatchables(TBESENASTNodeLabelledStatement(ToVisit).Target,false); + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L1:=Code.Here; + CodeGeneratorContext.PopPatchables(-1,L1); + end; + bntCASESTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Code.GenLocation(ToVisit.Location); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter],DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + end; + bntSWITCHSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + SetLength(SwitchPatches,length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)); + r1:=-1; + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + if assigned(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression) then begin + r3:=-1; + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression,r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r3,r4); + end; + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopSEQ,r5,r2,r4); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + SwitchPatches[Counter]:=Code.GenOp(bopJZ,0,r5)+1; + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + L1:=Code.GenOp(bopJMP,0)+1; + CodeGeneratorContext.PushPatchables(TBESENASTNodeSwitchStatement(ToVisit).Target,false); + DefaultCase:=false; + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + if assigned(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression) then begin + Code.GenLabel(SwitchPatches[Counter]); + end else begin + Code.GenLabel(L1); + DefaultCase:=true; + end; + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter],DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + if not DefaultCase then begin + Code.GenLabel(L1); + end; + SetLength(SwitchPatches,0); + CodeGeneratorContext.PopPatchables(-1,Code.Here); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end; + bntTHROWSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeThrowStatement(ToVisit).Expression) then begin + r1:=-1; + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Code.GenOp(bopTHROW,r2); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + bntTRYSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeTryStatement(ToVisit).TryBlock) then begin + if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) and assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin + L1:=Code.GenOp(bopSTRYF,0)+1; + CodeGeneratorContext.BlockEnter; + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name),r1); + L2:=Code.GenOp(bopSTRYC,0,r1)+1; + CodeGeneratorContext.BlockEnter; + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L3a:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L2); + InScope:=CodeGeneratorContext.IsVariableInScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,false,false,-1); + end; + Code.GenOp(bopSCATCH); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,true,false,-1); + CodeGeneratorContext.VariableSetType(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,bvtUNDEFINED); + end; + L3b:=Code.GenOp(bopJMP,0)+1; + CodeGeneratorContext.BlockLeave; + Code.GenLabel(L1); + if not Code.Body.IsFunction then begin + Code.GenOp(bopGETC,r1); + end; + if CodeGeneratorContext.MaxBlockDepth>CodeGeneratorContext.BlockCurrent then begin + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent+1); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if not Code.Body.IsFunction then begin + GenSetC(r1); + end; + Code.GenOp(bopENDF); + Code.GenLabel(L3a); + Code.GenLabel(L3b); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + end else if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) then begin + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name),r1); + L1:=Code.GenOp(bopSTRYC,0,r1)+1; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.BlockEnter; + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + InScope:=CodeGeneratorContext.IsVariableInScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,false,false,-1); + end; + Code.GenOp(bopSCATCH); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,true,false,-1); + CodeGeneratorContext.VariableSetType(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,bvtUNDEFINED); + end; + Code.GenLabel(L2); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + end else if assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin + L1:=Code.GenOp(bopSTRYF,0)+1; + CodeGeneratorContext.BlockEnter; + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + r1:=CodeGeneratorContext.AllocateRegister; + if not Code.Body.IsFunction then begin + Code.GenOp(bopGETC,r1); + end; + if CodeGeneratorContext.MaxBlockDepth>CodeGeneratorContext.BlockCurrent then begin + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent+1); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if not Code.Body.IsFunction then begin + GenSetC(r1); + end; + Code.GenOp(bopENDF); + Code.GenLabel(L2); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + end; + bntARRAYLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=CodeGeneratorContext.AllocateRegister; + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopARRAY,r1); + Code.GenOp(bopNEW,DestRegNr,r1,0); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(inttostr(Counter)),r3); + r4:=-1; + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter],r4,true); + if r4<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r4) or IsLocalVariableReference(r4) then begin + r5:=r4; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r4,r5); + end; + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r3,r5); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + r3:=CodeGeneratorContext.AllocateRegister; + v:=BESENStringValue('length'); + Code.GenLiteral(v,r3); + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopREF,r4,DestRegNr,r3,TBESEN(Instance).KeyIDManager.LengthID,BESENLengthHash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENNumberValue(length(TBESENASTNodeArrayLiteral(ToVisit).Elements)),r5); + Code.GenOp(bopPUTVALUEREF,r4,r5); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end; + bntBINARYEXPRESSION:begin + end; + bntASSIGNMENTEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1,true); + r2:=-1; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + P1:=Code.Here; + vtb:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r2) then begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r1].IsWhat); + end else if IsValue(r2) then begin + CodeGeneratorContext.DeallocateRegister(r2); + r2:=r1; + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(P1); + CodeGeneratorContext.VariableSetTypes(vtb); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r2].IsWhat); + end else begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r1].IsWhat); + end; + CodeGeneratorContext.Registers[r1].IsWhat:=bcgtREFERENCE; + if CalleeNeedReturnedValue or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,DestRegNr); + end; + end; + CodeGeneratorContext.DeallocateRegister(r2); + end else begin + r1:=-1; + end; + if r1<0 then begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + vta:=CodeGeneratorContext.VariableGetTypes; + PR:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r2:=-1; + P1:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + vtb:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + GenGetValue(r2,DestRegNr); + if not IsValue(DestRegNr) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + end else if IsValue(r2) then begin + CodeGeneratorContext.DeallocateRegister(r2); + Code.Restore(P1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + CodeGeneratorContext.VariableSetTypes(vtb); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,DestRegNr,true); + r2:=DestRegNr; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r2].IsWhat; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + GenGetValue(r2,DestRegNr); + if not IsValue(DestRegNr) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + end; + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + if (not DoHasLocalDelete) and (((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal) and + ((TBESENASTNodeAssignmentExpression(ToVisit).RightExpression.NodeType=bntIDENTIFIER) and + (((CodeGeneratorContext.Registers[r2].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r2].IsLocal)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + r2:=-1; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + GenGetValueEx(r2,DestRegNr); + if IsValueBoolean(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtBOOLEAN); + end else if IsValueNumber(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtNUMBER); + end else if IsValueString(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtSTRING); + end else if IsValueObject(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtOBJECT); + end else begin + GenPutValueEx(r1,DestRegNr); + end; + end else begin + if ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)=0) or not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + if IsValueBoolean(r2) then begin + GenPutValue(r1,DestRegNr,bvtBOOLEAN); + end else if IsValueNumber(r2) then begin + GenPutValue(r1,DestRegNr,bvtNUMBER); + end else if IsValueString(r2) then begin + GenPutValue(r1,DestRegNr,bvtSTRING); + end else if IsValueObject(r2) then begin + GenPutValue(r1,DestRegNr,bvtOBJECT); + end else begin + GenPutValue(r1,DestRegNr); + end; + end; + if r1<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r1); + end; + if r2<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r2:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + if IsValueBoolean(r2) then begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r2); + end else if IsValueNumber(r2) then begin + Code.GenOp(bopCOPYNUM,DestRegNr,r2); + end else if IsValueString(r2) then begin + Code.GenOp(bopCOPYSTR,DestRegNr,r2); + end else if IsValueObject(r2) then begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r2); + end else begin + Code.GenOp(bopCOPY,DestRegNr,r2); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r2].IsWhat; + end else begin + GenGetValue(r2,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + if ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)=0) or not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF); + end; + AssignOpPost(false,false,true); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopMUL,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopDIV,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopMOD,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + AssignOpAddPre; + if IsValueNumber(r1) and IsValueNumber(r2) then begin + Code.GenOp(bopADDNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopADD,DestRegNr,r3,r4); + end; + if IsValueString(r1) or IsValueString(r2) then begin + AssignOpPost(false,true,false); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueNumber(r1) and IsValueNumber(r2) then begin + AssignOpPost(true,false,false); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else begin + AssignOpPost(false,false,false); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING or bcgtNUMBER; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopSUB,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + AssignOpShiftPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHLBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHLNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHL,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + AssignOpShiftPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + AssignOpShiftPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopUSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopUSHR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + AssignOpPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBANDBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBANDNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBAND,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + AssignOpPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBXORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBXORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBXOR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + AssignOpPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBOR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntBINARYOPERATOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if not IsValue(r1) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + if IsValueBoolean(r1) then begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r1); + end else if IsValueNumber(r1) then begin + Code.GenOp(bopCOPYNUM,DestRegNr,r1); + end else if IsValueString(r1) then begin + Code.GenOp(bopCOPYSTR,DestRegNr,r1); + end else if IsValueObject(r1) then begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r1); + end else begin + Code.GenOp(bopCOPY,DestRegNr,r1); + end; + end else begin + GenGetValue(r1,DestRegNr); + end; + if IsValue(r1) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + CodeGeneratorContext.DeallocateRegister(r1); + end; + bntBINARYCOMMAEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if not IsValue(r1) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + PR:=Code.Here; + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,DestRegNr,true); + r1:=DestRegNr; + end else begin + GenGetValue(r1,DestRegNr); + CodeGeneratorContext.DeallocateRegister(r1); + end; + if IsValue(r1) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + end; + bntBINARYDIVIDEEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopDIV,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYMODULOEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopMOD,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYMULTIPLYEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopMUL,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYPLUSEXPRESSION:begin + BinaryPre; + if IsValuePrimitive(r1) then begin + r5:=r3; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r5,r3); + end; + if IsValuePrimitive(r2) then begin + r6:=r4; + end else begin + r6:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r6,r4); + end; + if IsValueNumber(r1) and IsValueNumber(r2) then begin + Code.GenOp(bopADDNUM,DestRegNr,r5,r6); + end else begin + Code.GenOp(bopADD,DestRegNr,r5,r6); + end; + if IsValueString(r1) or IsValueString(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueNumber(r1) and IsValueNumber(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING or bcgtNUMBER; + end; + BinaryPost; + end; + bntBINARYMINUSEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopSUB,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHLBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHLNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHL,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopUSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopUSHR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYGREATERTHANEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopGTBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopGTNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopGTNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopGTSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopGT,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopGEBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopGENUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopGENUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopGESTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopGE,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYLESSTHANEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopLTBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopLTNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopLTNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopLTSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopLT,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopLEBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopLENUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopLENUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopLESTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopLE,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYINSTANCEOFEXPRESSION:begin + BinaryPre; + Code.GenOp(bopINSTANCEOF,DestRegNr,r3,r4); + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYINEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + if IsValueString(r1) then begin + r5:=r3; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOSTRING,r5,r3); + end; + Code.GenOp(bopIN,DestRegNr,r5,r4); + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYEQUALEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopEQ,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSEQ,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYNOTEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopNEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopNEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopNEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopNEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopNEQ,DestRegNr,r3,r4); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopNEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopNEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopNEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopNEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopNSEQ,DestRegNr,r3,r4); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYBITWISEANDEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBANDBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBANDNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBAND,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYBITWISEXOREXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBXORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBXORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBXOR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYBITWISEOREXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBOR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBOOLEANLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + v.ValueType:=bvtBOOLEAN; + v.Bool:=TBESENASTNodeBooleanLiteral(ToVisit).Value; + Code.GenLiteral(v,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntCALLEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if CodeGeneratorContext.MaxParamArgs<length(TBESENASTNodeCallExpression(ToVisit).Arguments) then begin + CodeGeneratorContext.MaxParamArgs:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + end; + SetLength(Operands,4+length(TBESENASTNodeCallExpression(ToVisit).Arguments)); + Operands[0]:=DestRegNr; + Operands[1]:=r1; + Operands[2]:=r1; + Operands[3]:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Operands[4+Counter]:=CodeGeneratorContext.AllocateRegister; + end; + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r3:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) or IsLocalVariableReference(r3) then begin + if IsLocalVariableReference(r3) then begin + Operands[4+Counter]:=-1; + end; + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],Operands[4+Counter],true); + end else begin + GenGetValue(r3,Operands[4+Counter]); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Operands[2]:=r2; + if TBESEN(Instance).CodeTracable then begin + Code.GenOp(bopTRACECALL,Operands); + end else begin + Code.GenOp(bopCALL,Operands); + end; + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + for Counter:=4 to length(Operands)-1 do begin + CodeGeneratorContext.DeallocateRegister(Operands[Counter]); + end; + SetLength(Operands,0); + if (OptimizeLocals and HasFunctions) or not OptimizeLocals then begin + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + bntNEWEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if CodeGeneratorContext.MaxParamArgs<length(TBESENASTNodeCallExpression(ToVisit).Arguments) then begin + CodeGeneratorContext.MaxParamArgs:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + end; + SetLength(Operands,3+length(TBESENASTNodeCallExpression(ToVisit).Arguments)); + Operands[0]:=DestRegNr; + Operands[1]:=r1; + Operands[2]:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Operands[3+Counter]:=CodeGeneratorContext.AllocateRegister; + end; + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r3:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) or IsLocalVariableReference(r3) then begin + if IsLocalVariableReference(r3) then begin + Operands[3+Counter]:=-1; + end; + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],Operands[3+Counter],true); + end else begin + GenGetValue(r3,Operands[3+Counter]); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Operands[1]:=r2; + if TBESEN(Instance).CodeTracable then begin + Code.GenOp(bopTRACENEW,Operands); + end else begin + Code.GenOp(bopNEW,Operands); + end; + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + for Counter:=3 to length(Operands)-1 do begin + CodeGeneratorContext.DeallocateRegister(Operands[Counter]); + end; + SetLength(Operands,0); + if (OptimizeLocals and HasFunctions) or not OptimizeLocals then begin + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end; + bntCONDITIONALEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + end; + L1:=Code.GenOp(bopJZ,0,r3)+1; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + vta:=CodeGeneratorContext.VariableGetTypes; + + PR:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + vtb:=CodeGeneratorContext.VariableGetTypes; + + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + + CodeGeneratorContext.VariableSetTypes(vta); + + PR:=Code.Here; + r2:=-1; + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression,DestRegNr,true); + end else begin + GenGetValue(r2,DestRegNr); + end; + vtc:=CodeGeneratorContext.VariableGetTypes; + + vte:=copy(vtb,0,length(vtb)); + if not AreStrictValueTypesEqual(vte,vtc) then begin + ResetDifferentValueTypes(vte,vtc); + end; + CodeGeneratorContext.VariableSetTypes(vte); + + Code.GenLabel(L2); + if (not IsValue(r1)) or not IsValue(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat or CodeGeneratorContext.Registers[r2].IsWhat; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + bntUNARYEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression,DestRegNr,true); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + end; + bntUNARYOPERATOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression,DestRegNr,true); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + end; + bntUNARYPLUSEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + vta:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValueNumber(r1) then begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + end else begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Code.GenOp(bopTONUMBER,DestRegNr,r2); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntUNARYMINUSEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r3,r2); + end; + Code.GenOp(bopNEG,DestRegNr,r3); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntUNARYBITWISENOTEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r3,r2); + end; + Code.GenOp(bopINV,DestRegNr,r3); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntUNARYLOGICALNOTEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + end; + Code.GenOp(bopNOT,DestRegNr,r3); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntUNARYVOIDEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + Code.GenLiteral(BESENUndefinedValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + bntUNARYTYPEOFEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + Code.GenOp(bopTYPEOF,DestRegNr,r1); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end; + bntPROPERTYEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if TBESENASTNodePropertyExpression(ToVisit).Dot then begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral then begin + v:=BESENStringValue(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeNumberLiteral then begin + v:=BESENNumberValue(TBESENASTNodeNumberLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value); + v:=BESENStringValue(TBESEN(Instance).ToStr(v)); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeBooleanLiteral then begin + v.ValueType:=bvtBOOLEAN; + v.Bool:=TBESENASTNodeBooleanLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value; + v:=BESENStringValue(TBESEN(Instance).ToStr(v)); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeNullLiteral then begin + v:=BESENNullValue; + v:=BESENStringValue(TBESEN(Instance).ToStr(v)); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeIdentifier then begin + v:=BESENStringValue(TBESENASTNodeIdentifier(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Name); + Code.GenLiteral(v,r3); + end; + if not IsValueObject(r1) then begin + Code.GenOp(bopCHECKOBJECTCOERCIBLE,r2); + end; + Hash:=BESENHashKey(v.Str); + Code.GenOp(bopREF,DestRegNr,r2,r3,TBESEN(Instance).KeyIDManager.Get(v.Str,Hash),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + r3:=-1; + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression,r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r3,r4); + end; + if not IsValueObject(r1) then begin + Code.GenOp(bopCHECKOBJECTCOERCIBLE,r2); + end; + if IsValueNumber(r3) then begin + r5:=r4; + if TBESENASTNodePropertyExpression(ToVisit).RightExpression.NodeType=bntNUMBERLITERAL then begin + Code.GenOp(bopAREF,DestRegNr,r2,r4,BESENHashKey(TBESEN(Instance).ToStr(BESENNumberValue(TBESENASTNodeNumberLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value)))); + end else begin + Code.GenOp(bopAREF,DestRegNr,r2,r4,0); + end; + end else begin + if IsValueString(r3) then begin + r5:=r4; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOSTRING,r5,r4); + end; + if TBESENASTNodePropertyExpression(ToVisit).RightExpression.NodeType=bntSTRINGLITERAL then begin + Code.GenOp(bopREF,DestRegNr,r2,r5,TBESEN(Instance).KeyIDManager.Get(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value),BESENHashKey(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value),Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end else begin + Code.GenOp(bopREF,DestRegNr,r2,r5,TBESENINT32($fefefefe),0,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; + end; + bntLOGICALANDEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat1:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + if IsValueBoolean(DestRegNr) then begin + r2:=DestRegNr; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r2,DestRegNr); + end; + L1:=Code.GenOp(bopJZ,0,r2)+1; + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + CodeGeneratorContext.DeallocateRegister(r1); + if r2<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + r2:=-1; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat2:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + Code.GenLabel(L2); + CodeGeneratorContext.DeallocateRegister(r1); + + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=IsWhat1 or IsWhat2; + + end; + bntLOGICALOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat1:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + if IsValueBoolean(DestRegNr) then begin + r2:=DestRegNr; + end else begin + Code.GenOp(bopTOBOOLEAN,r2,DestRegNr); + end; + L1:=Code.GenOp(bopJZ,0,r2)+1; + CodeGeneratorContext.DeallocateRegister(r1); + if r2<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + r2:=-1; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat2:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + CodeGeneratorContext.DeallocateRegister(r1); + Code.GenLabel(L1); + + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=IsWhat1 or IsWhat2; + end; + bntDELETEEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if TBESENASTNodeDeleteExpression(ToVisit).SubExpression.NodeType=bntIDENTIFIER then begin + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeIdentifier(TBESENASTNodeDeleteExpression(ToVisit).SubExpression).Name,false,false); + end; + Code.GenOp(bopDELETE,DestRegNr,r1); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + AssignSetType(TBESENASTNodeDeleteExpression(ToVisit).SubExpression,bvtUNDEFINED); + end; + bntPOSTFIXINCEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenOp(bopCOPYNUM,DestRegNr,r2); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + Code.GenOp(bopINC,r1,r2); + AssignSetType(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + if IsValueNumber(r1) then begin + GenGetValueEx(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopINC,r3,DestRegNr); + GenPutValueEx(r1,r3,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + if IsValueNumber(r1) then begin + GenGetValue(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopINC,r3,DestRegNr); + GenPutValue(r1,r3,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntPOSTFIXDECEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenOp(bopCOPYNUM,DestRegNr,r2); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + Code.GenOp(bopDEC,r1,r2); + AssignSetType(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + if IsValueNumber(r1) then begin + GenGetValueEx(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopDEC,r3,DestRegNr); + GenPutValueEx(r1,r3,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + if IsValueNumber(r1) then begin + GenGetValue(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopDEC,r3,DestRegNr); + GenPutValue(r1,r3,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntPREFIXINCEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + Code.GenOp(bopINC,r1,r2); + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=r1; + end else begin + Code.GenOp(bopCOPYNUM,DestRegNr,r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + end; + AssignSetType(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValueEx(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopINC,DestRegNr,r2); + GenPutValueEx(r1,DestRegNr,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValue(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopINC,DestRegNr,r2); + GenPutValue(r1,DestRegNr,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntPREFIXDECEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + Code.GenOp(bopDEC,r1,r2); + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=r1; + end else begin + Code.GenOp(bopCOPYNUM,DestRegNr,r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + end; + AssignSetType(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValueEx(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopDEC,DestRegNr,r2); + GenPutValueEx(r1,DestRegNr,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValue(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopDEC,DestRegNr,r2); + GenPutValue(r1,DestRegNr,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntNULLLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNullValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; + end; + bntNUMBERLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNumberValue(TBESENASTNodeNumberLiteral(ToVisit).Value),DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntREGEXPLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if CodeGeneratorContext.MaxParamArgs<2 then begin + CodeGeneratorContext.MaxParamArgs:=2; + end; + r1:=CodeGeneratorContext.AllocateRegister; + r2:=CodeGeneratorContext.AllocateRegister; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopREGEXP,r1); + Code.GenLiteral(BESENStringValue(TBESENASTNodeRegExpLiteral(ToVisit).Source),r2); + Code.GenLiteral(BESENStringValue(TBESENASTNodeRegExpLiteral(ToVisit).Flags),r3); + Code.GenOp(bopNEW,DestRegNr,r1,2,r2,r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + bntSTRINGLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENStringValue(TBESENASTNodeStringLiteral(ToVisit).Value),DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end; + bntTHISLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenOp(bopTHIS,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + bntOBJECTLITERALPROPERTY:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType of + banolptACCESSOR:begin + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeObjectLiteralProperty(ToVisit).Name),r1); + r2:=-1; + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + CodeGeneratorContext.DeallocateRegister(r2); + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenFunction(TBESENASTNodeObjectLiteralProperty(ToVisit).Container,r2); + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType of + banolpatGET:begin + Code.GenOp(bopPUTOBJGET,DestRegNr,r1,r2); + end; + banolpatSET:begin + Code.GenOp(bopPUTOBJSET,DestRegNr,r1,r2); + end; + else begin + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r2); + end; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + banolptDATA:begin + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeObjectLiteralProperty(ToVisit).Name),r1); + r2:=-1; + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + end; + bntOBJECTLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopOBJECT,r1); + Code.GenOp(bopNEW,DestRegNr,r1,0); + CodeGeneratorContext.DeallocateRegister(r1); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter],DestRegNr,true); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end; + bntRETURNSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeReturnStatement(ToVisit).Expression) then begin + r1:=-1; + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + GenSetC(r1); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + GenSetC(r2); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + Code.GenOp(bopEND,0); + end else begin + Code.GenOp(bopSETCUNDEF); + Code.GenOp(bopEND,0); + end; + end; + bntPROGRAM:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + OldOptimizeLocals:=OptimizeLocals; + OldDoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; + OptimizeLocals:=false; + DoHoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeProgram(ToVisit).Body,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + OptimizeLocals:=OldOptimizeLocals; + DoHoldLocalVariablesInRegisters:=OldDoHoldLocalVariablesInRegisters; + if TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).ByteCodeLen=0 then begin + TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).GenOp(bopEND,0); + end; + TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).Finish; + end; + bntFUNCTIONEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + r1:=-1; + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + Code.GenFunction(TBESENASTNodeFunctionExpression(ToVisit).Container,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end; + end; + end; + end; + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopLITERALUNDEF,DestRegNr); + end; + for Counter:=low(RegStates) to high(RegStates) do begin + SetLength(RegStates[Counter].Registers,0); + end; + SetLength(vta,0); + SetLength(vtb,0); + SetLength(vtc,0); + SetLength(vtd,0); + SetLength(vte,0); + SetLength(vtTemp,0); + SetLength(vtBegin,0); + SetLength(vtInner,0); + SetLength(vtEnd,0); + SetLength(Operands,0); + end; + var tr:integer; + begin + Code:=TBESENCode.Create(Instance); + try + CodeGeneratorContext:=TBESENCodeGeneratorContext.Create(Instance); + try + CodeGeneratorContext.Code:=Code; + DoHasLocalDelete:=false; + DoIsComplexFunction:=false; + DoHasMaybeDirectEval:=false; + OptimizeLocals:=false; + HasFunctions:=false; + DoHoldLocalVariablesInRegisters:=false; + tr:=-1; + Visit(RootNode,tr,false); + finally + CodeGeneratorContext.Free; + end; + finally + Code.Free; + end; + end; +var Parser:TBESENParser; + RootNode:TBESENASTNode; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin + result:=nil; + Parser:=nil; + RootNode:=nil; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(rmNearest); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + try + // Parse the code + Parser:=TBESENParser.Create(Instance); + if IsFunction then begin + Parser.Lexer.Source:='function('+Parameters+'){'+InputSource+'}'; + end else begin + Parser.Lexer.Source:=InputSource; + end; + Parser.Init; + RootNode:=Parser.Parse(IsFunction,IsJSON); + BESENFreeAndNil(Parser); + + // Scan, collect variables/functions and preprocess the abstract syntax tree + ScanCollectAndPreprocess(RootNode); + + // Optimize the abstract syntax tree + RootNode:=Optimize(RootNode); + + // Generate the byte code + GenerateByteCode(RootNode); + + if assigned(RootNode) then begin + result:=RootNode; + end; + except + BESENFreeAndNil(RootNode); + BESENFreeAndNil(Parser); + raise; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + end; +end; + + +end. diff --git a/3rd/besen/src/BESENConstants.pas b/3rd/besen/src/BESENConstants.pas new file mode 100644 index 000000000..e1c510728 --- /dev/null +++ b/3rd/besen/src/BESENConstants.pas @@ -0,0 +1,103 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENConstants; +{$i BESEN.inc} + +interface + +uses Math; + +{$ifndef BESENNoFPU} +const BESENFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; + + BESENFPUPrecisionMode:TFPUPrecisionMode={$ifdef HAS_TYPE_EXTENDED}pmEXTENDED{$else}pmDOUBLE{$endif}; +{$endif} + +{$ifndef fpc} +const FPC_VERSION=2; + FPC_RELEASE=5; + FPC_PATCH=1; +{$endif} + +const COMPAT_UTF8_UNSAFE=1 shl 1; // accept 'valid but insecure' UTF8 + COMPAT_SGMLCOM=1 shl 2; // treat '<!--' as a '//' comment + COMPAT_BESEN=1 shl 3; // BESEN-specific extensions + COMPAT_JS=1 shl 4; // JavaScript-specific extensions + + BESEN_GC_MARKFACTOR:integer=25; + BESEN_GC_TRIGGERCOUNT_PER_COLLECT:integer=1; + + bimMAXIDENTS=1 shl 24; + + BESENHashItemsPerBucketsThreshold:longword=5; + BESENHashMaxSize:longword=1 shl 16; + + BESENMaxCountOfFreeCodeContexts:integer=16; + + BESENMaxCountOfFreeContexts:integer=16; + + BESEN_JIT_LOOPCOMPILETHRESHOLD:longword=1000; + + BESEN_CMWCRND_A=18782; + BESEN_CMWCRND_M=longword($fffffffe); + BESEN_CMWCRND_BITS=12; + BESEN_CMWCRND_SIZE=1 shl BESEN_CMWCRND_BITS; + BESEN_CMWCRND_MASK=BESEN_CMWCRND_SIZE-1; + + bncmmMINBLOCKCONTAINERSIZE=1048576; + + bcttNOTARGET=0; + + BESENEvalCacheSize:integer=256; + BESENEvalCacheMaxSourceLength:integer=256; + + bncfZERO=1 shl 0; + bncfNAN=1 shl 1; + bncfINFINITE=1 shl 2; + bncfNEGATIVE=1 shl 3; + + BESENObjectStructureIDManagerHashSize=65536; + BESENObjectStructureIDManagerHashSizeMask=BESENObjectStructureIDManagerHashSize-1; + + BESENPolymorphicInlineCacheSize=8; + BESENPolymorphicInlineCacheSizeMask=BESENPolymorphicInlineCacheSize-1; + + BESENPolymorphicInlineCacheStartItemPositions=longword((0 shl 0) or (1 shl 4) or (2 shl 8) or (3 shl 12) or (4 shl 16) or (5 shl 20) or (6 shl 24) or (7 shl 28)); + + BESENLongBooleanValues:array[boolean] of longbool=(false,true); + + BESENNumberBooleanValues:array[boolean] of integer=(0,1); + + BESENInt32BooleanValues:array[boolean] of integer=(0,longint(longword($ffffffff))); + +implementation + +end. diff --git a/3rd/besen/src/BESENContext.pas b/3rd/besen/src/BESENContext.pas new file mode 100644 index 000000000..dff5c26d9 --- /dev/null +++ b/3rd/besen/src/BESENContext.pas @@ -0,0 +1,452 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENContext; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENLexicalEnvironment,BESENASTNodes, + BESENEnvironmentRecord,BESENStringTree, + BESENObjectFunctionArguments; + +type TBESENContextCache=class; + + TBESENContext=class(TBESENCollectorObject) + private + Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; + Temp:TBESENValue; + public + Cache:TBESENContextCache; + CachePrevious,CacheNext:TBESENContext; + Previous,Next:TBESENContext; + CodeContext:TObject; + LexicalEnvironment:TBESENLexicalEnvironment; + VariableEnvironment:TBESENLexicalEnvironment; + ThisBinding:TBESENValue; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Reset; + function CreateArgumentsObject(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;Arguments:PPBESENValues;CountArguments:integer;const Env:TBESENEnvironmentRecord;const IsStrict:longbool):TBESENObjectFunctionArguments; + procedure InitializeDeclarationBindingInstantiation(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;const IsEval:boolean;Arguments:PPBESENValues;CountArguments:integer;const Reinitialize:boolean); + procedure Mark; + end; + + TBESENContextCacheItems=array of TBESENContext; + + TBESENContextCache=class(TBESENCollectorObject) + public + First,Last:TBESENContext; + Count:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure Cleanup; + procedure Push(Context:TBESENContext); + function Pop:TBESENContext; + procedure Mark; + end; + +implementation + +uses BESEN,BESENUtils,BESENDeclarativeEnvironmentRecord,BESENObject, + BESENArrayUtils,BESENCodeContext,BESENErrors, + BESENObjectDeclaredFunction,BESENObjectArgGetterFunction, + BESENObjectArgSetterFunction; + +constructor TBESENContext.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Cache:=nil; + CachePrevious:=nil; + CacheNext:=nil; + Previous:=TBESEN(Instance).ContextLast; + Next:=nil; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + TBESEN(Instance).ContextFirst:=self; + end; + TBESEN(Instance).ContextLast:=self; + CodeContext:=nil; + LexicalEnvironment:=nil; + VariableEnvironment:=nil; + ThisBinding.ValueType:=bvtUNDEFINED; +end; + +destructor TBESENContext.Destroy; +begin + if assigned(Instance) and assigned(TBESEN(Instance).GarbageCollector) and (TBESEN(Instance).GarbageCollector.CurrentContext=self) then begin + TBESEN(Instance).GarbageCollector.CurrentContext:=Next; + end; + if assigned(Previous) then begin + Previous.Next:=Next; + end else if TBESEN(Instance).ContextFirst=self then begin + TBESEN(Instance).ContextFirst:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if TBESEN(Instance).ContextLast=self then begin + TBESEN(Instance).ContextLast:=Previous; + end; + Next:=nil; + Previous:=nil; + BESENFreeAndNil(CodeContext); + if assigned(Cache) then begin + dec(Cache.Count); + if assigned(CachePrevious) then begin + CachePrevious.CacheNext:=CacheNext; + end else if Cache.First=self then begin + Cache.First:=CacheNext; + end; + if assigned(CacheNext) then begin + CacheNext.CachePrevious:=CachePrevious; + end else if Cache.Last=self then begin + Cache.Last:=CachePrevious; + end; + Cache:=nil; + CacheNext:=nil; + CachePrevious:=nil; + end; + inherited Destroy; +end; + +procedure TBESENContext.Reset; +begin + CodeContext:=nil; + ThisBinding.ValueType:=bvtUNDEFINED; + while assigned(VariableEnvironment) and assigned(VariableEnvironment.EnvironmentRecord) do begin + if VariableEnvironment.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord then begin + break; + end; + VariableEnvironment:=VariableEnvironment.Outer; + end; + if not (assigned(VariableEnvironment) and assigned(VariableEnvironment.EnvironmentRecord) and (VariableEnvironment.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord)) then begin + VariableEnvironment:=nil; + end; + LexicalEnvironment:=nil; +end; + +function TBESENContext.CreateArgumentsObject(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;Arguments:PPBESENValues;CountArguments:integer;const Env:TBESENEnvironmentRecord;const IsStrict:longbool):TBESENObjectFunctionArguments; +var Len,Index,NamesCount:integer; + Map:TBESENObject; + Val:TBESENValue; + Name:TBESENString; + MappedNames:TBESENStringTree; + MappedNamesCount:integer; + StringTreeData:TBESENStringTreeData; + function MakeArgGetter(const Name:TBESENString;const Env:TBESENEnvironmentRecord):TBESENObjectArgGetterFunction; + begin + result:=TBESENObjectArgGetterFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,true); + TBESEN(Instance).GarbageCollector.Add(result); + result.Env:=Env; + result.ArgName:=Name; + end; + function MakeArgSetter(const Name:TBESENString;const Env:TBESENEnvironmentRecord):TBESENObjectArgSetterFunction; + begin + result:=TBESENObjectArgSetterFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,true); + TBESEN(Instance).GarbageCollector.Add(result); + result.Env:=Env; + result.ArgName:=Name; + end; +begin + Len:=CountArguments; + NamesCount:=length(TBESENObjectDeclaredFunction(FunctionObject).Parameters); + result:=TBESENObjectFunctionArguments.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + result.GarbageCollectorLock; + try + result.IsStrict:=IsStrict; + result.OverwriteData('length',BESENNumberValue(Len),[bopaWRITABLE,bopaCONFIGURABLE],false); + Map:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + MappedNames:=TBESENStringTree.Create; + MappedNamesCount:=0; + try + for Index:=Len-1 downto 0 do begin + BESENCopyValue(Val,Arguments^[Index]^); + result.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENDataPropertyDescriptor(Val,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + if (not IsStrict) and (Index<NamesCount) then begin + Name:=TBESENObjectDeclaredFunction(FunctionObject).Parameters[Index]; + if not MappedNames.Find(Name,StringTreeData) then begin + StringTreeData.i:=Index; + MappedNames.Add(Name,StringTreeData,true); + inc(MappedNamesCount); + Map.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENAccessorPropertyDescriptor(MakeArgGetter(Name,Env),MakeArgSetter(Name,Env),[bopaCONFIGURABLE]),false); + end; + end; + end; + finally + MappedNames.Free; + end; + if MappedNamesCount>0 then begin + result.ParameterMap:=Map; + end; + if IsStrict then begin + result.OverwriteAccessor('caller',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + result.OverwriteAccessor('callee',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + end else begin + result.OverwriteData('callee',BESENObjectValueEx(TBESENObjectDeclaredFunction(FunctionObject)),[bopaWRITABLE,bopaCONFIGURABLE],false); + end; + finally + result.GarbageCollectorUnlock; + end; +end; + +procedure TBESENContext.InitializeDeclarationBindingInstantiation(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;const IsEval:boolean;Arguments:PPBESENValues;CountArguments:integer;const Reinitialize:boolean); + procedure SetParameters(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const IsStrict:boolean;const ParamCount:integer); + var i,j:integer; + ArgName:PBESENString; + v:PBESENValue; + begin + if (Env is TBESENDeclarativeEnvironmentRecord) and TBESENDeclarativeEnvironmentRecord(Env).IndexInitialized then begin + for i:=0 to ParamCount-1 do begin + j:=Body.Parameters[i].ParameterIndex; + if i<CountArguments then begin + BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Env).HashValues[j]^,Arguments^[i]^); + end else begin + TBESENDeclarativeEnvironmentRecord(Env).HashValues[j]^.ValueType:=bvtUNDEFINED; + end; + end; + end else begin + for i:=0 to ParamCount-1 do begin + ArgName:=@Body.Parameters[i].Name; + if i<CountArguments then begin + v:=Arguments^[i]; + end else begin + v:=@BESENUndefinedValue; + end; + if not Env.HasBindingEx(ArgName^,Descriptor) then begin + Env.CreateMutableBinding(ArgName^); + end; + Env.SetMutableBindingEx(ArgName^,v^,IsStrict,Descriptor,OwnDescriptor,Temp); + end; + end; + end; + procedure SetFunctions(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const ConfigurableBindings,IsStrict:boolean); + var i:integer; + fn:PBESENString; + fd:TBESENASTNodeFunctionDeclaration; + fo:TBESENObjectDeclaredFunction; + go:TBESENObject; + begin + for i:=0 to length(Body.Functions)-1 do begin + if assigned(Body.Functions[i]) and (Body.Functions[i] is TBESENASTNodeFunctionDeclaration) then begin + if assigned(TBESENASTNodeFunctionDeclaration(Body.Functions[i]).Container.Literal) and assigned(TBESENASTNodeFunctionDeclaration(Body.Functions[i]).Container.Literal.Name) then begin + fd:=TBESENASTNodeFunctionDeclaration(Body.Functions[i]); + fn:=@fd.Container.Literal.Name.Name; + fo:=TBESEN(Instance).MakeFunction(fd.Container.Literal,fd.Container.Literal.Name.Name,LexicalEnvironment); + if not Env.HasBindingEx(fn^,Descriptor) then begin + Env.CreateMutableBinding(fn^,ConfigurableBindings); + end else if Env=TBESEN(Instance).GlobalLexicalEnvironment.EnvironmentRecord then begin + // ES5-errata fix + go:=TBESEN(Instance).ObjectGlobal; + go.GetProperty(fn^,Descriptor); + if (boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes) then begin + if ConfigurableBindings then begin + go.DefineOwnPropertyEx(fn^,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true,Descriptor); + end else begin + go.DefineOwnPropertyEx(fn^,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE]),true,Descriptor); + end; + end else if (([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) or ((([boppWRITABLE,boppENUMERABLE]*Descriptor.Presents)<>[boppWRITABLE,boppENUMERABLE]) or (([bopaWRITABLE,bopaENUMERABLE]*Descriptor.Attributes)<>[bopaWRITABLE,bopaENUMERABLE])) then begin + BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(fn^); + end; + end; + Env.SetMutableBinding(fn^,BESENObjectValue(fo),IsStrict); + end; + end; + end; + end; + procedure SetArguments(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const IsStrict:boolean); + var ArgsObj:TBESENObjectFunctionArguments; + begin + ArgsObj:=CreateArgumentsObject(Body,TBESENObjectDeclaredFunction(FunctionObject),Arguments,CountArguments,Env,IsStrict); + if IsStrict then begin + Env.CreateImmutableBinding('arguments'); + Env.InitializeImmutableBinding('arguments',BESENObjectValue(ArgsObj)); + end else begin + Env.CreateMutableBinding('arguments'); + Env.SetMutableBindingEx('arguments',BESENObjectValue(ArgsObj),false,Descriptor,OwnDescriptor,Temp); + end; + end; + procedure SetVariables(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const ConfigurableBindings,IsStrict:boolean); + var i:integer; + d:TBESENASTNodeIdentifier; + dn:PBESENString; + begin + for i:=0 to length(Body.Variables)-1 do begin + d:=Body.Variables[i]; + if assigned(d) and (length(d.Name)>0) then begin + dn:=@d.Name; + if not Env.HasBindingEx(dn^,Descriptor) then begin + Env.CreateMutableBinding(dn^,ConfigurableBindings); + Env.SetMutableBindingEx(dn^,BESENUndefinedValue,IsStrict,Descriptor,OwnDescriptor,Temp); + end; + end; + end; + end; +var IsFunction:boolean; + ParamCount:integer; + Env:TBESENEnvironmentRecord; +begin + Env:=VariableEnvironment.EnvironmentRecord; + IsFunction:=assigned(TBESENObjectDeclaredFunction(FunctionObject)) and Body.IsFunction; + if IsFunction then begin + ParamCount:=length(Body.Parameters); + if ParamCount>0 then begin + SetParameters(Body,Env,Body.IsStrict,ParamCount); + end; + end; + if length(Body.Functions)>0 then begin + SetFunctions(Body,Env,IsEval,Body.IsStrict); + end; + if not Reinitialize then begin + if IsFunction and not (Body.DisableArgumentsObject or Env.HasBinding('arguments')) then begin + SetArguments(Body,Env,Body.IsStrict); + end; + SetVariables(Body,Env,IsEval,Body.IsStrict); + end; + if Env.RecordType=BESENEnvironmentRecordTypeDeclarative then begin + TBESENDeclarativeEnvironmentRecord(Env).Touched:=false; + end; +end; + +procedure TBESENContext.Mark; +var i:integer; +begin + if assigned(LexicalEnvironment) then begin + TBESEN(Instance).GarbageCollector.GrayIt(LexicalEnvironment); + end; + if assigned(VariableEnvironment) then begin + TBESEN(Instance).GarbageCollector.GrayIt(VariableEnvironment); + end; + TBESEN(Instance).GarbageCollector.GrayValue(ThisBinding); + if assigned(CodeContext) then begin + if assigned(TBESENCodeContext(CodeContext).Code) then begin + TBESENCodeContext(CodeContext).Code.Mark; + end; + for i:=0 to length(TBESENCodeContext(CodeContext).RegisterValues)-1 do begin + TBESEN(Instance).GarbageCollector.GrayValue(TBESENCodeContext(CodeContext).RegisterValues[i]); + end; + end; +end; + +constructor TBESENContextCache.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; + Count:=0; +end; + +destructor TBESENContextCache.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENContextCache.Clear; +var CurrentContext:TBESENContext; +begin + while true do begin + CurrentContext:=Pop; + if assigned(CurrentContext) then begin + BESENFreeAndNil(CurrentContext); + end else begin + break; + end; + end; +end; + +procedure TBESENContextCache.Cleanup; +var CurrentContext:TBESENContext; +begin + while Count>TBESEN(Instance).MaxCountOfFreeContexts do begin + CurrentContext:=Pop; + if assigned(CurrentContext) then begin + BESENFreeAndNil(CurrentContext); + end else begin + break; + end; + end; +end; + +procedure TBESENContextCache.Push(Context:TBESENContext); +begin + Context.Cache:=self; + if assigned(Last) then begin + Last.CacheNext:=Context; + Context.CachePrevious:=Last; + Context.CacheNext:=nil; + Last:=Context; + end else begin + First:=Context; + Last:=Context; + Context.CachePrevious:=nil; + Context.CacheNext:=nil; + end; + inc(Count); +end; + +function TBESENContextCache.Pop:TBESENContext; +begin + if assigned(Last) then begin + result:=Last; + if assigned(result.CachePrevious) then begin + result.CachePrevious.CacheNext:=result.CacheNext; + end else if First=result then begin + First:=result.CacheNext; + end; + if assigned(result.CacheNext) then begin + result.CacheNext.CachePrevious:=result.CachePrevious; + end else if Last=result then begin + Last:=result.CachePrevious; + end; + result.Cache:=nil; + result.CachePrevious:=nil; + result.CacheNext:=nil; + dec(Count); + end else begin + result:=nil; + Count:=0; + end; +end; + +procedure TBESENContextCache.Mark; +var CurrentContext:TBESENContext; +begin + CurrentContext:=First; + while assigned(CurrentContext) do begin + CurrentContext.Mark; + CurrentContext:=CurrentContext.CacheNext; + end; +end; + +end. diff --git a/3rd/besen/src/BESENDateUtils.pas b/3rd/besen/src/BESENDateUtils.pas new file mode 100644 index 000000000..c754585f5 --- /dev/null +++ b/3rd/besen/src/BESENDateUtils.pas @@ -0,0 +1,1368 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDateUtils; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,BESENConstants,BESENTypes; + +const BESENUnixDateDelta=25569.0; //1970/01/01 + + BESENmsPerDay=86400000.0; + + BESENmsPerY1=375*BESENmsPerDay; + BESENmsPerY4=(4*BESENmsPerY1)+BESENmsPerDay; + BESENmsPerY100=(25*BESENmsPerY4)-BESENmsPerDay; + BESENmsPerY400=(4*BESENmsPerY100)+BESENmsPerDay; + + BESENTime1970=(4*BESENmsPerY400)+(3*BESENmsPerY100)+(17*BESENmsPerY4)+(2*BESENmsPerY1); + + BESENmaxTime=BESENmsPerDay*100000000; + BESENminTime=-BESENmaxTime; + + BESENHoursPerDay=24.0; + BESENMinutesPerHour=60.0; + BESENSecondsPerMinute=60.0; + BESENmsPerSecond=1000.0; + BESENmsPerMinute=BESENmsPerSecond*BESENSecondsPerMinute; + BESENmsPerHour=BESENmsPerMinute*BESENMinutesPerHour; + +function BESENDay(t:TBESENNumber):TBESENNumber; + +function BESENTimeWithinDay(t:TBESENNumber):TBESENNumber; + +function BESENDaysInYear(y:TBESENNumber):TBESENNumber; +function BESENDayFromYear(y:TBESENNumber):TBESENNumber; +function BESENTimeFromYear(y:TBESENNumber):TBESENNumber; + +function BESENYearFromTime(t:TBESENNumber):TBESENNumber; + +function BESENDayWithinYear(t:TBESENNumber):TBESENNumber; + +function BESENWeekDay(t:TBESENNumber):TBESENNumber; + +function BESENIsLeapYear(t:TBESENNumber):boolean; + +function BESENMonthFromTime(t:TBESENNumber):TBESENNumber; +function BESENDayFromTime(t:TBESENNumber):TBESENNumber; +function BESENHourFromTime(t:TBESENNumber):TBESENNumber; +function BESENMinuteFromTime(t:TBESENNumber):TBESENNumber; +function BESENSecondFromTime(t:TBESENNumber):TBESENNumber; +function BESENMillisecondFromTime(t:TBESENNumber):TBESENNumber; +function BESENToIntegerForTime(Num:TBESENNumber):int64; +function BESENToIntForTime(Num:TBESENNumber):TBESENNumber; + +function BESENMakeTime(Hour,Minute,Second,Millisecond:TBESENNumber):TBESENNumber; +function BESENMakeDay(Year,Month,Date:TBESENNumber):TBESENNumber; + +function BESENMakeDate(Day,Time:TBESENNumber):TBESENNumber; + +function BESENTimeClip(const v:TBESENDate):TBESENDate; + +function BESENDateTimeToBESENDate(DateTime:TDateTime):TBESENDate; +function BESENDateToDateTime(BESENDate:TBESENDate):TDateTime; +function BESENSystemTimeToBESENDate(SystemTime:TSystemTime):TBESENDate; +function BESENDateToSystemTime(BESENDate:TBESENDate):TSystemTime; + +function BESENGetUTCDateTime:TDateTime; +function BESENGetUTCBESENDate:TBESENDate; +function BESENGetLocalDateTimeZone:TDateTime; +function BESENGetLocalTZA:TBESENDate; + +function BESENLocalTime(Date:TBESENDate):TBESENDate; +function BESENUTC(Date:TBESENDate):TBESENDate; + +function BESENLocalDateTimeToUTC(DateTime:TDateTime):TDateTime; +function BESENUTCToLocalDateTime(DateTime:TDateTime):TDateTime; + +function BESENGetDateTimeOffsetString(const Ofs:TDateTime):TBESENString; + +function BESENParseISOTime(s:TBESENString):TBESENDate; + +function BESENParseTime(s:TBESENString):TBESENDate; + +function BESENParseNetscapeTime(s:TBESENString):TBESENDate; + +function BESENFormatDateTime(const Format:TBESENSTRING;DateTime:TDateTime;const FormatSettings:TFormatSettings):TBESENSTRING; + +implementation + +uses {$ifdef BESENDelphiHasNoSystemTimeMore}System.DateUtils,{$endif}BESENNumberUtils,BESENStringUtils; + +const ParserMonthNames:array[0..11] of widestring=('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'); + ParserDayNames:array[0..6] of widestring=('sun','mon','tue','wed','thu','fri','sat'); + +function BESENDay(t:TBESENNumber):TBESENNumber; +begin + result:=BESENFloor(t/BESENmsPerDay); +end; + +function BESENTimeWithinDay(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(t,BESENmsPerDay); +end; + +function BESENDaysInYear(y:TBESENNumber):TBESENNumber; +var yi:integer; +begin + yi:=trunc(y); + if (yi mod 4)<>0 then begin + result:=365; + end else if (yi mod 100)<>0 then begin + result:=366; + end else if (yi mod 400)<>0 then begin + result:=365; + end else begin + result:=366; + end; +end; + +function BESENDayFromYear(y:TBESENNumber):TBESENNumber; +begin + result:=(365.0*(y-1970))+(BESENFloor((y-1969)/4)-BESENFloor((y-1901)/100))+BESENFloor((y-1601)/400); +end; + +function BESENTimeFromYear(y:TBESENNumber):TBESENNumber; +begin + result:=BESENDayFromYear(y)*BESENmsPerDay; +end; + +function BESENYearFromTime(t:TBESENNumber):TBESENNumber; +var y,t2:TBESENNumber; +begin + y:=BESENFloor(t/(BESENmsPerDay*365.2425))+1970; + t2:=BESENTimeFromYear(y); + if t2>t then begin + y:=y-1; + end else begin + if (t2+(BESENmsPerDay*BESENDaysInYear(y)))<=t then begin + y:=y+1; + end; + end; + result:=y; +end; + +function BESENDayWithinYear(t:TBESENNumber):TBESENNumber; +begin + result:=BESENDay(t)-BESENDayFromYear(BESENYearFromTime(t)); +end; + +function BESENWeekDay(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENDay(t)+4,7.0); +end; + +function BESENIsLeapYear(t:TBESENNumber):boolean; +begin + if BESENModuloPos(t,4)<>0 then begin + result:=false; + end else if BESENModuloPos(t,100)<>0 then begin + result:=true; + end else if BESENModuloPos(t,400)<>0 then begin + result:=false; + end else begin + result:=true; + end; +end; + +function BESENMonthFromTime(t:TBESENNumber):TBESENNumber; +var dwy,ily:TBESENNumber; +begin + dwy:=BESENDayWithinYear(t); + if BESENIsLeapYear(BESENYearFromTime(t)) then begin + ily:=1; + end else begin + ily:=0; + end; + if dwy<31 then begin + result:=0; + end else if dwy<(59+ily) then begin + result:=1; + end else if dwy<(90+ily) then begin + result:=2; + end else if dwy<(120+ily) then begin + result:=3; + end else if dwy<(151+ily) then begin + result:=4; + end else if dwy<(181+ily) then begin + result:=5; + end else if dwy<(212+ily) then begin + result:=6; + end else if dwy<(243+ily) then begin + result:=7; + end else if dwy<(273+ily) then begin + result:=8; + end else if dwy<(304+ily) then begin + result:=9; + end else if dwy<(334+ily) then begin + result:=10; + end else if dwy<(365+ily) then begin + result:=11; + end else begin + result:=-1; + end; +end; + +function BESENDayFromTime(t:TBESENNumber):TBESENNumber; +var dwy,ily:TBESENNumber; +begin + dwy:=BESENDayWithinYear(t); + if BESENIsLeapYear(BESENYearFromTime(t)) then begin + ily:=1; + end else begin + ily:=0; + end; + case trunc(BESENMonthFromTime(t)) of + 0:begin + result:=dwy+1; + end; + 1:begin + result:=dwy-30; + end; + 2:begin + result:=dwy-(58+ily); + end; + 3:begin + result:=dwy-(89+ily); + end; + 4:begin + result:=dwy-(119+ily); + end; + 5:begin + result:=dwy-(150+ily); + end; + 6:begin + result:=dwy-(180+ily); + end; + 7:begin + result:=dwy-(211+ily); + end; + 8:begin + result:=dwy-(242+ily); + end; + 9:begin + result:=dwy-(272+ily); + end; + 10:begin + result:=dwy-(303+ily); + end; + 11:begin + result:=dwy-(333+ily); + end; + else begin + result:=-1; + end; + end; +end; + +function BESENHourFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENFloor(t/BESENmsPerHour),BESENHoursPerDay); +end; + +function BESENMinuteFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENFloor(t/BESENmsPerMinute),BESENMinutesPerHour); +end; + +function BESENSecondFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENFloor(t/BESENmsPerSecond),BESENSecondsPerMinute); +end; + +function BESENMillisecondFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENFloor(BESENModuloPos(t,BESENmsPerSecond)); +end; + +function BESENToIntegerForTime(Num:TBESENNumber):int64; +begin + if BESENIsNaN(Num) then begin + result:=0; + end else if BESENIsFinite(Num) then begin + if BESENIsNegative(Num) then begin + result:=trunc(-BESENFloor(-Num)); + end else begin + result:=trunc(BESENFloor(Num)); + end; + end else begin + result:=trunc(Num); + end; +end; + +function BESENToIntForTime(Num:TBESENNumber):TBESENNumber; +begin + if BESENIsNaN(Num) then begin + result:=0; + end else if BESENIsFinite(Num) then begin + if BESENIsNegative(Num) then begin + result:=-BESENFloor(-Num); + end else begin + result:=BESENFloor(Num); + end; + end else begin + result:=Num; + end; +end; + +function BESENMakeTime(Hour,Minute,Second,Millisecond:TBESENNumber):TBESENNumber; +begin + if BESENIsFinite(Hour) and BESENIsFinite(Minute) and BESENIsFinite(Second) and BESENIsFinite(Millisecond) then begin + result:=(BESENToIntForTime(Hour)*BESENmsPerHour)+(BESENToIntForTime(Minute)*BESENmsPerMinute)+(BESENToIntForTime(Second)*BESENmsPerSecond)+BESENToIntForTime(Millisecond); + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENMakeDay(Year,Month,Date:TBESENNumber):TBESENNumber; +const Julian:array[boolean,0..11] of integer=((1,32,60,91,121,152,182,213,244,274,305,335),(1,32,61,92,122,153,183,214,245,275,306,336)); +var y,m:TBESENNumber; +begin + if not (BESENIsFinite(Year) and BESENIsFinite(Month) and BESENIsFinite(Date)) then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + month:=BESENToIntForTime(month); + y:=BESENToIntForTime(year)+BESENFloor(month/12); + m:=BESENModuloPos(month,12.0); + if (BESENDayFromYear(y)<-100000000) or (BESENDayFromYear(y)>100000000) then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + result:=BESENDay((BESENDayFromYear(y)+Julian[boolean(BESENIsLeapYear(BESENFloor(y)))][trunc(m)]-1)*BESENmsPerDay)+BESENToIntForTime(date)-1; + if (result<-100000000) or (result>100000000) then begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENMakeDate(Day,Time:TBESENNumber):TBESENNumber; +begin + if BESENIsFinite(Day) and BESENIsFinite(Time) then begin + result:=(Day*BESENmsPerDay)+Time; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENTimeClip(const v:TBESENDate):TBESENDate; +begin + if (not BESENIsFinite(v)) or ((v<-8.64e15) or (v>8.64e15)) then begin + result:=double(pointer(@BESENDoubleNaN)^); + end else begin + result:=BESENToIntForTime(v); + end; +end; + +function BESENDateTimeToBESENDate(DateTime:TDateTime):TBESENDate; +begin + result:=round((DateTime-BESENUnixDateDelta)*BESENmsPerDay); +end; + +function BESENDateToDateTime(BESENDate:TBESENDate):TDateTime; +begin + result:=(BESENDate/BESENmsPerDay)+BESENUnixDateDelta; +end; + +function BESENSystemTimeToBESENDate(SystemTime:TSystemTime):TBESENDate; +begin +{$ifdef BESENDelphiHasNoSystemTimeMore} + result:=EncodeDate(SystemTime.wYear,SystemTime.wMonth,SystemTime.wDay); + result:=result+(((ord(result<0) and 1)*(-1))*EncodeTime(SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond,SystemTime.wMilliSeconds)); +{$else} + result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); +{$endif} +end; + +function BESENDateToSystemTime(BESENDate:TBESENDate):TSystemTime; +{$ifdef BESENDelphiHasNoSystemTimeMore} +var DateTime:TDateTime; +{$endif} +begin +{$ifdef BESENDelphiHasNoSystemTimeMore} + DateTime:=BESENDateToDateTime(trunc(BESENDate)); + DecodeDateFully(DateTime,result.wYear,result.wMonth,result.wDay,result.wDayOfWeek); + dec(result.wDayOfWeek); + DecodeTime(DateTime,result.wHour,result.wMinute,result.wSecond,result.wMilliseconds); +{$else} + DateTimeToSystemTime(BESENDateToDateTime(trunc(BESENDate)),result); +{$endif} +end; + +function BESENGetLocalDateTime:TDateTime; +{$ifndef BESENDelphiHasNoSystemTimeMore} +var SystemTime:TSystemTime; +{$endif} +begin +{$ifdef BESENDelphiHasNoSystemTimeMore} + result:=Now; +{$else} + GetLocalTime(SystemTime); + result:=SystemTimeToDateTime(SystemTime); +{$endif} +end; + +function BESENGetUTCDateTime:TDateTime; +{$ifdef unix} +var TimeVal:TTimeVal; + ia,ib:int64; + fa,fb,fc:double; +begin + fpGetTimeOfDay(@TimeVal,nil); + ia:=TimeVal.tv_sec; + ib:=TimeVal.tv_usec; + fa:=ia*1000; + fb:=ib*0.001; + fc:=fa+fb; + result:=(fc/BESENmsPerDay)+BESENUnixDateDelta; +end; +{$else} +{$ifdef BESENEmbarcaderoNextGen} +begin + result:=TTimeZone.Local.ToUniversalTime(Now); +end; +{$else} +{$ifdef windows} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=SystemTimeToDateTime(SystemTime); +end; +{$else} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=SystemTimeToDateTime(SystemTime); +end; +{$endif} +{$endif} +{$endif} + +function BESENGetUTCBESENDate:TBESENDate; +{$ifdef unix} +var TimeVal:TTimeVal; + ia,ib:int64; + fa,fb:double; +begin + fpGetTimeOfDay(@TimeVal,nil); + ia:=TimeVal.tv_sec; + ib:=TimeVal.tv_usec; + fa:=ia*1000; + fb:=ib*0.001; + result:=fa+fb; +end; +{$else} +{$ifdef BESENDelphiHasNoSystemTimeMore} +begin + result:=BESENDateTimeToBESENDate(Now); +end; +{$else} +{$ifdef windows} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); +end; +{$else} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); +end; +{$endif} +{$endif} +{$endif} + +function BESENGetLocalDateTimeZone:TDateTime; +{$ifdef unix} +begin + result:=BESENGetLocalDateTime-BESENGetUTCDateTime; +end; +{$else} +{$ifdef windows} +var tz_info:TIME_ZONE_INFORMATION; +begin + case GetTimeZoneInformation(tz_info) of + TIME_ZONE_ID_STANDARD:result:=-(((tz_info.StandardBias+tz_info.Bias)*60000.0)/BESENmsPerDay); + TIME_ZONE_ID_DAYLIGHT:result:=-(((tz_info.DaylightBias+tz_info.Bias)*60000.0)/BESENmsPerDay); + else begin + result:=BESENGetLocalDateTime-BESENGetUTCDateTime; + end; + end; +end; +{$else} +begin + result:=BESENGetLocalDateTime-BESENGetUTCDateTime; +end; +{$endif} +{$endif} + +function BESENGetLocalTZA:TBESENDate; +{$ifdef unix} +var TimeVal:TTimeVal; + ia,ib:int64; + fa,fb,fc:double; +begin + fpGetTimeOfDay(@TimeVal,nil); + ia:=TimeVal.tv_sec; + ib:=TimeVal.tv_usec; + fa:=ia*1000; + fb:=ib*0.001; + fc:=fa+fb; + result:=BESENDateTimeToBESENDate(BESENGetLocalDateTime)-fc; +end; +{$else} +{$ifdef windows} +var tz_info:TIME_ZONE_INFORMATION; +begin + case GetTimeZoneInformation(tz_info) of + TIME_ZONE_ID_STANDARD:result:=-(tz_info.StandardBias+tz_info.Bias)*60000.0; + TIME_ZONE_ID_DAYLIGHT:result:=-(tz_info.DaylightBias+tz_info.Bias)*60000.0; + else begin + result:=(BESENGetLocalDateTime-BESENGetUTCDateTime)*BESENmsPerDay; + end; + end; +end; +{$else} +begin + result:=(BESENGetLocalDateTime-BESENGetUTCDateTime)*BESENmsPerDay; +end; +{$endif} +{$endif} + +function BESENLocalTime(Date:TBESENDate):TBESENDate; +begin + if BESENIsFinite(Date) then begin + result:=Date+BESENGetLocalTZA; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENUTC(Date:TBESENDate):TBESENDate; +begin + if BESENIsFinite(Date) then begin + result:=Date-BESENGetLocalTZA; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENLocalDateTimeToUTC(DateTime:TDateTime):TDateTime; +begin + result:=DateTime-BESENGetLocalDateTimeZone; +end; + +function BESENUTCToLocalDateTime(DateTime:TDateTime):TDateTime; +begin + result:=DateTime+BESENGetLocalDateTimeZone; +end; + +function BESENGetDateTimeOffsetString(const Ofs:TDateTime):TBESENString; +var i:int64; + a,b:TBESENString; +begin + i:=trunc(BESENFloor(Ofs*SecsPerDay)) div 60; + case i mod 60 of + 59:begin + inc(i); + end; + 1:begin + dec(i); + end; + end; + a:=IntToStr(i div 60); + b:=IntToStr(i mod 60); + if length(a)<2 then begin + a:='0'+a; + end; + if length(b)<2 then begin + b:='0'+b; + end; + if i<0 then begin + a:='-'+a; + end else begin + a:='+'+a; + end; + result:=a+b; +end; + +function BESENParseISOTime(s:TBESENString):TBESENDate; + function IsDigit(const w:widechar):boolean; + begin + result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); + end; + function ParseDay(const ss:TBESENString):TBESENDate; + var Offset:integer; + begin + if (length(ss)=10) and (IsDigit(ss[1]) and IsDigit(ss[2]) and IsDigit(ss[3]) and IsDigit(ss[4]) and (ss[5]='-') and IsDigit(ss[6]) and IsDigit(ss[7]) and (ss[8]='-') and IsDigit(ss[9]) and IsDigit(ss[10])) then begin + Offset:=1; + end else if (length(ss)=8) and (IsDigit(ss[1]) and IsDigit(ss[2]) and IsDigit(ss[3]) and IsDigit(ss[4]) and IsDigit(ss[5]) and IsDigit(ss[6]) and IsDigit(ss[7]) and IsDigit(ss[8])) then begin + Offset:=0; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + result:=BESENMakeDay(StrToIntDef(copy(ss,1,4),0),StrToIntDef(copy(ss,5+(1*Offset),2),0),StrToIntDef(copy(ss,7+(2*Offset),2),0)); + end; + function ParseTime(const ss:TBESENString):TBESENDate; + var s,ms:TBESENString; + i,Offset,Hours,Minutes,Seconds,Milliseconds:integer; + WithSeconds:boolean; + begin + i:=BESENPosChar(',',ss); + if i=0 then begin + i:=BESENPosChar('.',ss); + end; + if i=0 then begin + s:=ss; + ms:=''; + end else begin + s:=copy(ss,1,i-1); + ms:=copy(ms,i+1,(length(ss)-i)+1); + end; + if (length(s)=8) and (IsDigit(s[1]) and IsDigit(s[2]) and (s[3]=':') and IsDigit(s[4]) and IsDigit(s[5]) and (s[6]=':') and IsDigit(s[7]) and IsDigit(s[8])) then begin + Offset:=1; + WithSeconds:=true; + end else if (length(s)=6) and (IsDigit(s[1]) and IsDigit(s[2]) and IsDigit(s[3]) and IsDigit(s[4]) and IsDigit(s[5]) and IsDigit(s[6])) then begin + Offset:=0; + WithSeconds:=true; + end else if (length(s)=5) and (IsDigit(s[1]) and IsDigit(s[2]) and (s[3]=':') and IsDigit(s[4]) and IsDigit(s[5])) then begin + Offset:=1; + WithSeconds:=false; + end else if (length(s)=4) and (IsDigit(s[1]) and IsDigit(s[2]) and IsDigit(s[3]) and IsDigit(s[4])) then begin + Offset:=0; + WithSeconds:=false; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + Hours:=StrToIntDef(copy(s,1,2),100); + Minutes:=StrToIntDef(copy(s,3+(1*Offset),2),100); + if WithSeconds then begin + Seconds:=StrToIntDef(copy(s,5+(2*Offset),2),100); + end else begin + Seconds:=0; + if length(ms)>0 then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + end; + case length(ms) of + 0:Milliseconds:=0; + 3:Milliseconds:=StrToIntDef(ms,10000); + else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + end; + result:=BESENMakeTime(Hours,Minutes,Seconds,Milliseconds); + end; +var i,j,k:integer; + sz:TBESENString; + Delta:TBESENDate; +begin + i:=BESENPosChar('T',s); + if i=0 then begin + i:=BESENPosChar(' ',s); + end; + if i>0 then begin + j:=BESENPosChar('Z',s); + if j=0 then begin + j:=length(s)+1; + for k:=length(s) downto i+1 do begin + if (s[k]='-') or (s[k]='+') then begin + j:=k; + break; + end; + end; + end; + sz:=copy(s,j,(length(s)-j)+1); + s:=copy(s,1,j-1); + Delta:=0; + if (length(sz)=6) and ((sz[1]='-') or (sz[1]='+')) and IsDigit(sz[2]) and IsDigit(sz[3]) and (sz[4]=':') and IsDigit(sz[5]) and IsDigit(sz[6]) then begin + i:=StrToIntDef(copy(sz,2,2),-1); + j:=StrToIntDef(copy(sz,5,2),-1); + if ((i>=0) and (i<=24)) and ((j>=0) and (j<=60)) then begin + Delta:=(i*60)+j; + if sz[1]='-' then begin + Delta:=-Delta; + end; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + end else if (length(sz)>0) and (sz<>'Z') then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + result:=BESENTimeClip(BESENMakeDate(ParseDay(copy(s,1,i-1)),ParseTime(copy(s,i+1,(length(s)-i)+1)))-(Delta*BESENmsPerMinute)); + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENParseTime(s:TBESENString):TBESENDate; +var p:integer; + function IsWhite(const w:widechar):boolean; + begin + result:=BESENUnicodeIsStringWhiteSpace(word(w)); + end; + function IsLetter(const w:widechar):boolean; + begin + result:=((word(w)>=ord('a')) and (word(w)<=ord('z'))) or ((word(w)>=ord('Z')) and (word(w)<=ord('Z'))); + end; + function IsDigit(const w:widechar):boolean; + begin + result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); + end; + function ToLower(const w:widechar):widechar; + begin + result:=widechar(word(BESENUnicodeToLower(word(w)))); + end; + procedure SkipWhite; + begin + while p<length(s) do begin + if IsWhite(s[p]) then begin + inc(p); + end else begin + break; + end; + end; + end; +var i,d,m,y,hr,min,sec,ms,wd:integer; + t:TBESENString; + yneg:boolean; +begin + result:=double(pointer(@BESENDoubleNaN)^); + + p:=1; + + SkipWhite; + + if ((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2])) then begin + t:=BESENLowercase(copy(s,p,3)); + for wd:=low(ParserDayNames) to high(ParserDayNames) do begin + if t=ParserDayNames[wd] then begin + inc(p,3); + if (p<=length(s)) and (s[p]=',') then begin + inc(p); + end; + SkipWhite; + break; + end; + end; + end; + + if (p<=length(s)) and IsDigit(s[p]) then begin + d:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + d:=(d*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + if not ((p<=length(s)) and IsWhite(s[p])) then begin + exit; + end; + SkipWhite; + if not (((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2]))) then begin + exit; + end; + t:=BESENLowercase(copy(s,p,3)); + inc(p,3); + m:=0; + for i:=low(ParserMonthNames) to high(ParserMonthNames) do begin + if t=ParserMonthNames[i] then begin + m:=i; + break; + end; + end; + end else begin + if not (((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2]))) then begin + exit; + end; + t:=BESENLowercase(copy(s,p,3)); + inc(p,3); + m:=0; + for i:=low(ParserMonthNames) to high(ParserMonthNames) do begin + if t=ParserMonthNames[i] then begin + m:=i; + break; + end; + end; + if not ((p<=length(s)) and IsWhite(s[p])) then begin + exit; + end; + SkipWhite; + d:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + d:=(d*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + end; + if (m<0) or ((d<1) or (d>31)) then begin + exit; + end; + + if not ((p<=length(s)) and IsWhite(s[p])) then begin + exit; + end; + SkipWhite; + + yneg:=(p<=length(s)) and (s[p]='-'); + if yneg then begin + inc(p); + end; + if not ((p<=length(s)) and IsDigit(s[p])) then begin + exit; + end; + y:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + y:=(y*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + if yneg then begin + y:=-y; + end; + + hr:=0; + min:=0; + sec:=0; + ms:=0; + if (p<=length(s)) and IsWhite(s[p]) then begin + SkipWhite; + if ((p+4)<=length(s)) and (IsDigit(s[p]) and IsDigit(s[p+1]) and (s[p+2]=':') and IsDigit(s[p+3]) and IsDigit(s[p+4])) then begin + hr:=((word(widechar(s[p]))-ord('0'))*10)+(word(widechar(s[p+1]))-ord('0')); + min:=((word(widechar(s[p+3]))-ord('0'))*10)+(word(widechar(s[p+4]))-ord('0')); + inc(p,5); + if ((p+2)<=length(s)) and ((s[p]=':') and IsDigit(s[p+1]) and IsDigit(s[p+2])) then begin + sec:=((word(widechar(s[p+1]))-ord('0'))*10)+(word(widechar(s[p+2]))-ord('0')); + inc(p,3); + end; + if ((p+3)<=length(s)) and (((s[p]=':') or (s[p]='.')) and IsDigit(s[p+1]) and IsDigit(s[p+2]) and IsDigit(s[p+3])) then begin + ms:=((word(widechar(s[p+1]))-ord('0'))*100)+((word(widechar(s[p+2]))-ord('0'))*10)+(word(widechar(s[p+3]))-ord('0')); + inc(p,4); + end; + end; + end; + if ((hr<0) or (hr>=24)) or ((min<0) or (min>=60)) or ((sec<0) or (sec>=60)) or ((ms<0) or (ms>=1000)) then begin + exit; + end; + + result:=BESENMakeDate(BESENMakeDay(y,m,d),BESENMakeTime(hr,min,sec,ms)); + + SkipWhite; + if ((p+2)<=length(s)) and (((s[p]='G') and (s[p+1]='M') and (s[p+2]='T')) or ((s[p]='U') and (s[p+1]='T') and (s[p+2]='C'))) then begin + inc(p,3); + if ((p+4)<=length(s)) and (((s[p]='-') or (s[p]='+')) and IsDigit(s[p+1]) and IsDigit(s[p+2]) and IsDigit(s[p+3]) and IsDigit(s[p+4])) then begin + i:=((((word(widechar(s[p+1]))-ord('0'))*10)+((word(widechar(s[p+2]))-ord('0'))))*60)+(((word(widechar(s[p+3]))-ord('0'))*10)+(word(widechar(s[p+4]))-ord('0'))); + if s[p]='-' then begin + i:=-i; + end; + result:=result-(BESENmsPerMinute*i); + end; + end else begin + result:=result-(BESENGetLocalDateTimeZone*BESENmsPerDay); + end; + + result:=BESENTimeClip(result); +end; + +function BESENParseNetscapeTime(s:TBESENString):TBESENDate; +var p:integer; + function IsWhite(const w:widechar):boolean; + begin + result:=BESENUnicodeIsStringWhiteSpace(word(w)); + end; + function IsLetter(const w:widechar):boolean; + begin + result:=((word(w)>=ord('a')) and (word(w)<=ord('z'))) or ((word(w)>=ord('Z')) and (word(w)<=ord('Z'))); + end; + function IsDigit(const w:widechar):boolean; + begin + result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); + end; + function ToLower(const w:widechar):widechar; + begin + result:=widechar(word(BESENUnicodeToLower(word(w)))); + end; + procedure SkipWhite; + begin + while p<length(s) do begin + if IsWhite(s[p]) then begin + inc(p); + end else begin + break; + end; + end; + end; +var i,j,d,m,y,hr,min,sec,ms:integer; + neg:boolean; + n:array[0..2] of integer; +begin + result:=double(pointer(@BESENDoubleNaN)^); + + p:=1; + + SkipWhite; + + for j:=0 to 2 do begin + if j<>0 then begin + SkipWhite; + if (p<=length(s)) and (s[p]='/') then begin + inc(p); + end else begin + exit; + end; + SkipWhite; + end; + n[j]:=0; + neg:=(p<=length(s)) and (s[p]='-'); + if neg then begin + inc(p); + end; + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + if neg then begin + i:=-i; + end; + n[j]:=i; + end else begin + exit; + end; + end; + if (n[0]>=70) and (n[1]>=70) then begin + exit; + end; + if n[0]>=70 then begin + y:=n[0]+1900; + m:=n[1]; + d:=n[2]; + end else begin + m:=n[0]; + d:=n[1]; + y:=n[2]; + if y<100 then begin + y:=n[0]+1900; + end; + end; + if (m<0) or ((d<1) or (d>31)) then begin + exit; + end; + + hr:=0; + min:=0; + sec:=0; + ms:=0; + + if not ((p<=length(s)) and IsWhite(s[p])) then begin + SkipWhite; + + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + hr:=i; + SkipWhite; + if (p<=length(s)) and (s[p]=':') then begin + inc(p); + SkipWhite; + + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + min:=i; + SkipWhite; + if (p<=length(s)) and (s[p]=':') then begin + inc(p); + SkipWhite; + + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + sec:=i; + SkipWhite; + if (p<=length(s)) and ((s[p]=':') or (s[p]='.')) then begin + inc(p); + SkipWhite; + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + ms:=i; + SkipWhite; + end; + end; + end else begin + exit; + end; + + end; + + if ((p+1)<=length(s)) and (ToLower(s[p+1])='m') then begin + if ToLower(s[p])='a' then begin + if (hr<1) or (hr>12) then begin + exit; + end; + hr:=(hr mod 12)+12; + end else if ToLower(s[p])='p' then begin + if (hr<1) or (hr>12) then begin + exit; + end; + hr:=hr mod 12; + end else begin + exit; + end; + inc(p,2); + SkipWhite; + end; + + end else begin + exit; + end; + + end; + end; + + end; + + if ((hr<0) or (hr>=24)) or ((min<0) or (min>=60)) or ((sec<0) or (sec>=60)) or ((ms<0) or (ms>=1000)) then begin + exit; + end; + + result:=BESENTimeClip(BESENMakeDate(BESENMakeDay(y,m,d),BESENMakeTime(hr,min,sec,ms))-(BESENGetLocalDateTimeZone*BESENmsPerDay)); +end; + +{$warnings off} +function BESENFormatDateTime(const Format:TBESENSTRING;DateTime:TDateTime;const FormatSettings:TFormatSettings):TBESENSTRING; +var Year,Month,Day,DayOfWeek,Hour,Minute,Second,MilliSecond:word; + ResultString:TBESENSTRING; + procedure Add(const s:TBESENSTRING); + begin + ResultString:=ResultString+s; + end; + procedure AddInt(Value,Digits:integer); + var s:TBESENSTRING; + begin + s:=inttostr(Value); + while length(s)<Digits do begin + s:='0'+s; + end; + Add(s); + end; + procedure Process(const Format:TBESENSTRING;Nesting:integer;TimeFlag:boolean); + var FormatPos,PosA,PosB,Count,t:integer; + FormatUp:TBESENSTRING; + CurrentChar,LastChar:TBESENWIDECHAR; + Clock12:boolean; + begin + if Nesting>1 then begin + exit; + end; + Clock12:=false; + FormatUp:=uppercase(Format); + FormatPos:=1; + while FormatPos<=length(Format) do begin + CurrentChar:=FormatUp[FormatPos]; + case CurrentChar of + '''','"':begin + inc(FormatPos); + while (FormatPos<=length(Format)) and (CurrentChar<>Format[FormatPos]) do begin + inc(FormatPos); + end; + inc(FormatPos); + end; + 'A':begin + if (copy(FormatUp,FormatPos,3)='A/P') or (copy(FormatUp,FormatPos,4)='AMPM') or (copy(FormatUp,FormatPos,5)='AM/PM') then begin + Clock12:=true; + break; + end; + inc(FormatPos); + end; + else begin + inc(FormatPos); + end; + end; + end; + LastChar:=#0; + FormatPos:=1; + while FormatPos<=length(Format) do begin + CurrentChar:=FormatUp[FormatPos]; + case CurrentChar of + '''','"':begin + inc(FormatPos); + PosA:=FormatPos; + while (FormatPos<=length(Format)) and (CurrentChar<>FormatUp[FormatPos]) do begin + inc(FormatPos); + end; + PosB:=FormatPos; + inc(FormatPos); + Add(copy(Format,PosA,PosB-PosA)); + LastChar:=CurrentChar; + end; + 'A':begin + if copy(FormatUp,FormatPos,3)='A/P' then begin + if Hour<12 then begin + Add(Format[FormatPos]); + end else begin + Add(Format[FormatPos+2]); + end; + inc(FormatPos,3); + end else if copy(FormatUp,FormatPos,4)='AMPM' then begin + inc(FormatPos,4); + if Hour<12 then begin + Add(FormatSettings.TimeAMString); + end else begin + Add(FormatSettings.TimePMString); + end; + end else if copy(FormatUp,FormatPos,5)='AM/PM' then begin + if Hour<12 then begin + Add(copy(Format,FormatPos,2)); + end else begin + Add(copy(Format,FormatPos+3,2)); + end; + inc(FormatPos,5); + end else begin + raise EConvertError.Create('Illegal character in format string'); + end; + end; + '/':begin + Add(FormatSettings.DateSeparator); + inc(FormatPos); + end; + ':':begin + Add(FormatSettings.TimeSeparator); + inc(FormatPos); + end; + ' ':begin + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]=' ') do begin + Add(' '); + inc(FormatPos); + end; + end; + 'Y':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='Y') do begin + inc(Count); + inc(FormatPos); + end; + if Count>2 then begin + AddInt(Year,4); + end else begin + AddInt(Year mod 100,2); + end; + LastChar:=CurrentChar; + end; + 'M':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='M') do begin + inc(Count); + inc(FormatPos); + end; + if (LastChar='H') or TimeFlag then begin + if Count=1 then begin + AddInt(Minute,0); + end else begin + AddInt(Minute,2); + end; + end else begin + case Count of + 1:begin + AddInt(Month,0); + end; + 2:begin + AddInt(Month,2); + end; + 3:begin + Add(FormatSettings.ShortMonthNames[Month]); + end; + else begin + Add(FormatSettings.LongMonthNames[Month]); + end; + end; + end; + LastChar:=CurrentChar; + end; + 'D':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='D') do begin + inc(Count); + inc(FormatPos); + end; + case Count of + 1:begin + AddInt(Day,0); + end; + 2:begin + AddInt(Day,2); + end; + 3:begin + Add(FormatSettings.ShortDayNames[DayOfWeek]); + end; + 4:begin + Add(FormatSettings.LongDayNames[DayOfWeek]); + end; + 5:begin + Process(FormatSettings.ShortDateFormat,Nesting+1,false); + end; + else begin + Process(FormatSettings.LongDateFormat,Nesting+1,false); + end; + end; + LastChar:=CurrentChar; + end; + 'H':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='H') do begin + inc(Count); + inc(FormatPos); + end; + t:=Hour; + if Clock12 then begin + if t=0 then begin + t:=12; + end else if t>12 then begin + dec(t,12); + end else if t>24 then begin + t:=t mod 12; + if t=0 then begin + t:=12; + end; + end; + end; + if Count=1 then begin + AddInt(t,0); + end else begin + AddInt(t,2); + end; + LastChar:=CurrentChar; + end; + 'N':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='N') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + AddInt(Minute,0); + end else begin + AddInt(Minute,2); + end; + LastChar:=CurrentChar; + end; + 'S':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='S') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + AddInt(Second,0); + end else begin + AddInt(Second,2); + end; + LastChar:=CurrentChar; + end; + 'Z':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='Z') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + AddInt(MilliSecond,0); + end else begin + AddInt(MilliSecond,3); + end; + LastChar:=CurrentChar; + end; + 'T':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='T') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + Process(FormatSettings.ShortTimeFormat,Nesting+1,true); + end else begin + Process(FormatSettings.LongTimeFormat,Nesting+1,true); + end; + LastChar:=CurrentChar; + end; + 'C':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='C') do begin + inc(Count); + inc(FormatPos); + end; + Process(FormatSettings.ShortDateFormat,Nesting+1,false); + if (integer(Hour)+integer(Minute)+integer(Second))<>0 then begin + Add(' '); + Process(FormatSettings.LongTimeFormat,Nesting+1,true); + end; + LastChar:=CurrentChar; + end; + else begin + Add(Format[FormatPos]); + inc(FormatPos); + end; + end; + end; + end; +begin + DecodeDateFully(DateTime,Year,Month,Day,DayOfWeek); + DecodeTime(DateTime,Hour,Minute,Second,MilliSecond); + ResultString:=''; + if length(Format)>0 then begin + Process(Format,0,false); + end else begin + Process('C',0,false); + end; + result:=ResultString; +end; +{$warnings on} + +end. + diff --git a/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas b/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas new file mode 100644 index 000000000..eb6ecd072 --- /dev/null +++ b/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas @@ -0,0 +1,612 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDeclarativeEnvironmentRecord; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENValue, + BESENPointerList,BESENStringList,BESENIntegerList, + BESENObjectPropertyDescriptor,BESENStringUtils; + +type PBESENDeclarativeEnvironmentRecordHashItem=^TBESENDeclarativeEnvironmentRecordHashItem; + TBESENDeclarativeEnvironmentRecordHashItem=record + Previous,Next,HashPrevious,HashNext:PBESENDeclarativeEnvironmentRecordHashItem; + Hash:TBESENHash; + Mutable:TBESENBoolean; + Initialized:TBESENBoolean; + Deletion:TBESENBoolean; + Key:TBESENString; + Value:TBESENValue; + Index:integer; + end; + + TBESENDeclarativeEnvironmentRecordHashBucket=record + HashFirst,HashLast:PBESENDeclarativeEnvironmentRecordHashItem; + end; + + TBESENDeclarativeEnvironmentRecordHashBuckets=array of TBESENDeclarativeEnvironmentRecordHashBucket; + + TBESENDeclarativeEnvironmentRecordValues=array of PBESENValue; + + TBESENDeclarativeEnvironmentRecord=class(TBESENEnvironmentRecord) + private + LastUsedItem:PBESENDeclarativeEnvironmentRecordHashItem; + procedure Clear; + procedure GrowAndRehashIfNeeded; + public + First,Last:PBESENDeclarativeEnvironmentRecordHashItem; + HashBuckets:TBESENDeclarativeEnvironmentRecordHashBuckets; + HashSize:longword; + HashSizeMask:longword; + HashedItems:longword; + HashBucketsUsed:longword; + HashIndexes:TBESENPointerList; + HashIndexNames:TBESENStringList; + HashIndexIDs:TBESENIntegerList; + HashValues:TBESENDeclarativeEnvironmentRecordValues; + Touched:TBESENBoolean; + IndexInitialized:TBESENBoolean; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Reset; + function GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; + function NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; + function DeleteKey(const Item:PBESENDeclarativeEnvironmentRecordHashItem):TBESENBoolean; + function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; override; + function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; + procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); override; + function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure UpdateImplicitThisValue; override; + function CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; override; + function InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; + function SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; override; + function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; override; + procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); override; + function DeleteIndex(const I,ID:integer):TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENHashUtils,BESENErrors; + +constructor TBESENDeclarativeEnvironmentRecord.Create(AInstance:TObject); +var Hash:TBESENHash; +begin + inherited Create(AInstance); + FillChar(HashBuckets,sizeof(TBESENDeclarativeEnvironmentRecordHashBuckets),#0); + First:=nil; + Last:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashIndexes:=TBESENPointerList.Create; + HashIndexNames:=TBESENStringList.Create; + HashIndexIDs:=TBESENIntegerList.Create; + HashValues:=nil; + Touched:=false; + IndexInitialized:=false; + LastUsedItem:=nil; + RecordType:=BESENEnvironmentRecordTypeDeclarative; +end; + +destructor TBESENDeclarativeEnvironmentRecord.Destroy; +begin + Clear; + SetLength(HashValues,0); + SetLength(HashBuckets,0); + HashIndexes.Free; + HashIndexNames.Free; + HashIndexIDs.Free; + inherited Destroy; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Clear; +var Hash:TBESENHash; + Item,NextItem:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item^.Next; + Item^.Previous:=nil; + Item^.Next:=nil; + Item^.Key:=''; + Item^.Value.ValueType:=bvtUNDEFINED; + Dispose(Item); + Item:=NextItem; + end; + First:=nil; + Last:=nil; + LastUsedItem:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashIndexes.Clear; + HashIndexNames.Clear; + HashIndexIDs.Clear; + SetLength(HashValues,0); + Touched:=false; + IndexInitialized:=false; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Reset; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=First; + while assigned(Item) do begin + Item^.Value.ValueType:=bvtUNDEFINED; + Item^.Initialized:=Item^.Mutable; + Item:=Item^.Next; + end; + Touched:=false; +end; + +procedure TBESENDeclarativeEnvironmentRecord.GrowAndRehashIfNeeded; +var Hash:TBESENHash; + Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin + LastUsedItem:=nil; + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + inc(HashSize,HashSize); + if HashSize>BESENHashMaxSize then begin + HashSize:=BESENHashMaxSize; + end; + HashSizeMask:=HashSize-1; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashedItems:=0; + Item:=First; + while assigned(Item) do begin + inc(HashedItems); + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + Item:=Item^.Next; + end; + HashBucketsUsed:=0; + Item:=First; + while assigned(Item) do begin + Hash:=BESENHashKey(Item^.Key) and HashSizeMask; + Item^.Hash:=Hash; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=Item; + Item^.HashPrevious:=HashBuckets[Hash].HashLast; + HashBuckets[Hash].HashLast:=Item; + Item^.HashNext:=nil; + end else begin + inc(HashBucketsUsed); + HashBuckets[Hash].HashFirst:=Item; + HashBuckets[Hash].HashLast:=Item; + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + end; + Item:=Item^.Next; + end; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; +begin + if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + while assigned(result) and (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if assigned(result) then begin + LastUsedItem:=result; + if HashBuckets[Hash].HashFirst<>result then begin + if assigned(result.HashPrevious) then begin + result.HashPrevious.HashNext:=result.HashNext; + end; + if assigned(result.HashNext) then begin + result.HashNext.HashPrevious:=result.HashPrevious; + end else if HashBuckets[Hash].HashLast=result then begin + HashBuckets[Hash].HashLast:=result.HashPrevious; + end; + HashBuckets[Hash].HashFirst.HashPrevious:=result; + result.HashNext:=HashBuckets[Hash].HashFirst; + result.HashPrevious:=nil; + HashBuckets[Hash].HashFirst:=result; + end; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; +begin + if Force then begin + result:=nil; + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + end else if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + if not assigned(result) then begin + inc(HashBucketsUsed); + end; + while assigned(result) and (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if not assigned(result) then begin + inc(HashedItems); + New(result); + fillchar(result^,sizeof(TBESENDeclarativeEnvironmentRecordHashItem),#0); + result^.Hash:=Hash; + result^.Key:=Key; + result^.Index:=-1; + result^.Value.ValueType:=bvtUNDEFINED; + //result^.Value:=BESENUndefinedValue; + result^.Mutable:=false; + result^.Initialized:=false; + result^.Deletion:=false; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=result; + result^.HashPrevious:=HashBuckets[Hash].HashLast; + result^.HashNext:=nil; + HashBuckets[Hash].HashLast:=result; + end else begin + HashBuckets[Hash].HashFirst:=result; + HashBuckets[Hash].HashLast:=result; + result^.HashPrevious:=nil; + result^.HashNext:=nil; + end; + if assigned(Last) then begin + Last^.Next:=result; + result^.Previous:=Last; + result^.Next:=nil; + Last:=result; + end else begin + First:=result; + Last:=result; + result^.Previous:=nil; + result^.Next:=nil; + end; + LastUsedItem:=result; + end; + GrowAndRehashIfNeeded; + Touched:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.DeleteKey(const Item:PBESENDeclarativeEnvironmentRecordHashItem):TBESENBoolean; +begin + result:=assigned(Item); + if result then begin + Touched:=true; + if LastUsedItem=Item then begin + if assigned(Item^.Next) then begin + LastUsedItem:=Item^.Next; + end else begin + LastUsedItem:=Item^.Previous; + end; + end; + if assigned(Item^.Previous) then begin + Item^.Previous^.Next:=Item^.Next; + end else if First=Item then begin + First:=Item^.Next; + end; + if assigned(Item^.Next) then begin + Item^.Next^.Previous:=Item^.Previous; + end else if Last=Item then begin + Last:=Item^.Previous; + end; + Item^.Next:=nil; + Item^.Previous:=nil; + if assigned(Item^.HashPrevious) then begin + Item^.HashPrevious^.HashNext:=Item^.HashNext; + end else if HashBuckets[Item^.Hash].HashFirst=Item then begin + HashBuckets[Item^.Hash].HashFirst:=Item^.HashNext; + end; + if assigned(Item^.HashNext) then begin + Item^.HashNext^.HashPrevious:=Item^.HashPrevious; + end else if HashBuckets[Item^.Hash].HashLast=Item then begin + HashBuckets[Item^.Hash].HashLast:=Item^.HashPrevious; + end; + Item^.HashNext:=nil; + Item^.HashPrevious:=nil; + Item^.Key:=''; + Item^.Value:=BESENUndefinedValue; + if Item^.Index>=0 then begin + HashIndexes[Item^.Index]:=nil; + HashValues[Item^.Index]:=@BESENDummyValue; + end; + Dispose(Item); + end; +end; + +function TBESENDeclarativeEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=assigned(GetKey(N,Hash)); +end; + +function TBESENDeclarativeEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if assigned(GetKey(N,Hash)) then begin + BESENThrowTypeError('CreateMutableBinding for "'+N+'" failed'); + end; + Item:=NewKey(N,false,Hash); + Item^.Value.ValueType:=bvtUNDEFINED; + Item^.Mutable:=true; + Item^.Initialized:=false; + Item^.Deletion:=D; + result:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowIt; + begin + BESENThrowTypeError('SetMutableBinding for "'+N+'" failed'); + end; +begin + result:=false; + Item:=GetKey(N,Hash); + if not assigned(Item) then begin + ThrowIt; + end else if Item^.Mutable then begin + BESENCopyValue(Item^.Value,V); + Item^.Initialized:=true; + result:=true; + end else begin + if S then begin // will added/fixed in ES5 errata too + ThrowIt; + end; + end; +end; + +procedure TBESENDeclarativeEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowUninitialized; + begin + BESENThrowReferenceError('Uninitialized immutable binding "'+N+'"'); + end; + procedure ThrowIt; + begin + BESENThrowTypeError('GetBindingValue for "'+N+'" failed'); + end; +begin + Item:=GetKey(N,Hash); + if assigned(Item) then begin + if Item^.Mutable or Item^.Initialized then begin + BESENCopyValue(R,Item^.Value); + end else begin + if S then begin + ThrowUninitialized; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; + end else begin + ThrowIt; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=GetKey(N,Hash); + if assigned(Item) then begin + if Item^.Mutable and Item^.Deletion then begin + if Item^.Index>=0 then begin + HashIndexes[Item^.Index]:=nil; + HashValues[Item^.Index]:=@BESENDummyValue; + end; + DeleteKey(Item); + result:=true; + end else begin + result:=false; + end; + end else begin + result:=true; + end; +end; + +procedure TBESENDeclarativeEnvironmentRecord.UpdateImplicitThisValue; +begin + ImplicitThisValue.ValueType:=bvtUNDEFINED; + ImplicitThisValue.Obj:=nil; +end; + +function TBESENDeclarativeEnvironmentRecord.CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if assigned(GetKey(N,Hash)) then begin + BESENThrowTypeError('CreateImmutableBinding for "'+N+'" failed'); + end; + Item:=NewKey(N,false,Hash); + Item^.Value.ValueType:=bvtUNDEFINED; + Item^.Mutable:=false; + Item^.Initialized:=false; + Item^.Deletion:=false; + result:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=GetKey(N,Hash); + if assigned(Item) and not (Item^.Mutable or Item^.Initialized) then begin + BESENCopyValue(Item^.Value,v); + Item^.Initialized:=true; + end else begin + BESENThrowTypeError('InitializeImmutableBinding for "'+N+'" failed'); + end; + result:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=GetKey(N,Hash); + if assigned(Item) then begin + Item^.Index:=I; + HashIndexes.Insert(I,Item); + HashIndexNames.Insert(I,N); + HashIndexIDs.Insert(I,TBESEN(Instance).KeyIDManager.Get(N,Hash)); + if i>=length(HashValues) then begin + SetLength(HashValues,i+256); + end; + HashValues[i]:=@Item^.Value; + result:=true; + end else begin + result:=false; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowIt; + begin + BESENThrowTypeError('SetIndexValue for "'+inttostr(I)+'" failed'); + end; +begin + if (I>=0) and (I<HashIndexes.Count) then begin + Item:=HashIndexes[I]; + end else begin + Item:=nil; + end; + if assigned(Item) and Item^.Mutable then begin + BESENCopyValue(Item^.Value,v); + Item^.Initialized:=true; + end else begin + ThrowIt; + end; + result:=true; +end; + +procedure TBESENDeclarativeEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowUninitialized; + begin + BESENThrowReferenceError('Uninitialized immutable binding "'+Item^.Key+'"'); + end; + procedure ThrowIt; + begin + BESENThrowTypeError('GetIndexValue for "'+inttostr(I)+'" failed'); + end; +begin + if (I>=0) and (I<HashIndexes.Count) then begin + Item:=HashIndexes[I]; + end else begin + Item:=nil; + end; + if assigned(Item) then begin + if Item^.Mutable or Item^.Initialized then begin + BESENCopyValue(R,Item^.Value); + end else begin + if S then begin + ThrowUninitialized; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; + end else begin + ThrowIt; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if (I>=0) and (I<HashIndexes.Count) then begin + Item:=HashIndexes[I]; + end else begin + Item:=nil; + end; + if assigned(Item) then begin + if Item^.Mutable and Item^.Deletion then begin + HashIndexes[i]:=nil; + HashValues[i]:=@BESENDummyValue; + DeleteKey(Item); + result:=true; + end else begin + result:=false; + end; + end else begin + result:=true; + end; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Finalize; +begin + Clear; + inherited Finalize; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Mark; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=First; + while assigned(Item) do begin + TBESEN(Instance).GarbageCollector.GrayValue(Item^.Value); + Item:=Item^.Next; + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENDecompiler.pas b/3rd/besen/src/BESENDecompiler.pas new file mode 100644 index 000000000..2e7bd733b --- /dev/null +++ b/3rd/besen/src/BESENDecompiler.pas @@ -0,0 +1,1017 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDecompiler; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, + BESENEvalCacheItem; + +type TBESENDecompiler=class(TBESENBaseObject) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; + end; + +implementation + +uses BESEN,BESENUtils,BESENPointerList,BESENHashMap,BESENErrors,BESENNumberUtils, + BESENCode,BESENCodeGeneratorContext,BESENOpcodes,BESENHashUtils,BESENGlobals, + BESENParser,BESENStringUtils; + +constructor TBESENDecompiler.Create(AInstance:TObject); +begin + inherited Create(AInstance); +end; + +destructor TBESENDecompiler.Destroy; +begin + inherited Destroy; +end; + +function TBESENDecompiler.Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; +var Code,s:TBESENUTF8STRING; + Indent:integer; + procedure Add(s:TBESENUTF8STRING); + begin + if (((length(Code)>0) and (Code[length(Code)] in [' ',#13,#10])) or (length(Code)=0)) and ((length(s)>0) and (s[1]=' ')) then begin + delete(s,1,1); + end; + Code:=Code+s; + end; + procedure AddCRLF(s:TBESENUTF8STRING); + begin + Add(s); + Add(#13#10); + end; + procedure AddIndent; + var i:integer; + begin + if (length(Code)>0) and not (Code[length(Code)] in [' ',#13,#10]) then begin + Code:=Code+#13#10; + end; + for i:=1 to Indent do begin + Code:=Code+#9; + end; + end; + procedure Visit(ToVisit:TBESENASTNode;NeedParens:boolean=true); + var Counter:integer; + First:boolean; + begin + if assigned(ToVisit) then begin + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + Add(BESENUTF16ToUTF8(TBESENASTNodeIdentifier(ToVisit).Name)); + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Expression) then begin + Add(' = '); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,false); + end; + end; + bntVARIABLEEXPRESSION:begin + First:=true; + Add('var '); + First:=true; + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + if First then begin + First:=false; + end else begin + Add(', '); + end; + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + if length(TBESENASTNodeFunctionBody(ToVisit).Variables)>0 then begin + First:=true; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin + if not (TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter or TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsReached) then begin + if First then begin + AddIndent; + Add('var '); + First:=false; + end else begin + Add(', '); + end; + Visit(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]); + end; + end; + if not First then begin + Add(';'); + end; + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]); + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + end; + bntFUNCTIONLITERAL:begin + if assigned(TBESENASTNodeFunctionLiteral(ToVisit).Name) then begin + AddIndent; + Add('function '); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Name); + end else begin + Add('function'); + end; + Add('('); + for Counter:=0 to length(TBESENASTNodeFunctionLiteral(ToVisit).Body.Parameters)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body.Parameters[Counter]); + end; + AddCRLF(') {'); + inc(Indent); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + dec(Indent); + AddIndent; + Add('}'); + end; + bntSTATEMENT:begin + Add(';'); + end; + bntVARIABLESTATEMENT:begin + AddIndent; + Add('var '); + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + Add(';'); + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + AddIndent; + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + Add(';'); + end; + end; + bntEXPRESSIONSTATEMENT:begin + AddIndent; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,false); + Add(';'); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + AddIndent; + Add('{'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + dec(Indent); + AddIndent; + Add('}'); + end; + bntDEBUGGERSTATEMENT:begin + AddIndent; + Add('debugger;'); + end; + bntBREAKSTATEMENT:begin + AddIndent; + if assigned(TBESENASTNodeBreakStatement(ToVisit).Identifier) then begin + Add('break '); + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + AddCRLF(';'); + end else begin + Add('break;'); + end; + end; + bntCONTINUESTATEMENT:begin + AddIndent; + if assigned(TBESENASTNodeContinueStatement(ToVisit).Identifier) then begin + Add('continue '); + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + AddCRLF(';'); + end else begin + Add('continue;'); + end; + end; + bntDOSTATEMENT:begin + AddIndent; + Add('do'); + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Add('while('); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,false); + AddCRLF(');'); + end; + bntWHILESTATEMENT:begin + AddIndent; + Add('while('); + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,false); + Add(')'); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + AddIndent; + Add('with('); + Visit(TBESENASTNodeWithStatement(ToVisit).Expression,false); + Add(')'); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + AddIndent; + Add('for('); + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Add(';'); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Add(';'); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Add(')'); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + AddIndent; + Add('for('); + if assigned(TBESENASTNodeForInStatement(ToVisit).Variable) and (TBESENASTNodeForInStatement(ToVisit).Variable.NodeType=bntVARIABLEDECLARATION) then begin + Add('var '); + end; + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Add(' in '); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Add(')'); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + AddIndent; + Add('if('); + Visit(TBESENASTNodeIfStatement(ToVisit).Expression,false); + AddCRLF(')'); + inc(Indent); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + dec(Indent); + if assigned(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin + AddCRLF(''); + AddIndent; + Add('else'); + inc(Indent); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + dec(Indent); + AddCRLF(''); + end; + end; + bntLABELLEDSTATEMENT:begin + AddIndent; + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + AddCRLF(': '); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + AddIndent; + if assigned(TBESENASTNodeCaseStatement(ToVisit).Expression) then begin + Add('case '); + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression,false); + end else begin + Add('default'); + end; + AddCRLF(':'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + dec(Indent); + end; + bntSWITCHSTATEMENT:begin + AddIndent; + Add('switch('); + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression,false); + AddCRLF(') {'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + dec(Indent); + AddIndent; + Add('}'); + end; + bntTHROWSTATEMENT:begin + AddIndent; + Add('throw '); + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression,false); + AddCRLF(';'); + end; + bntTRYSTATEMENT:begin + AddIndent; + Add('try'); + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) then begin + AddIndent; + Add('catch('); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier,false); + Add(')'); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + end; + if assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin + AddIndent; + Add('finally'); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + end; + end; + bntARRAYLITERAL:begin + Add('['); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + Add(']'); + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Add(' = '); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Add(' *= '); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Add(' /= '); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTMODULOEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Add(' %= '); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTPLUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Add(' += '); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTMINUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Add(' -= '); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Add(' <<= '); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Add(' >>= '); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Add(' >>>= '); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Add(' &= '); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Add(' ^= '); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Add(' |= '); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYOPERATOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYCOMMAEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Add(', '); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYDIVIDEEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Add(' / '); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYMODULOEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Add(' % '); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYMULTIPLYEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Add(' * '); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYPLUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Add(' + '); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYMINUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Add(' - '); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Add(' << '); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Add(' >> '); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Add(' >>> '); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYGREATERTHANEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Add(' > '); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Add(' >= '); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYLESSTHANEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Add(' < '); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Add(' <= '); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYINSTANCEOFEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Add(' instanceof '); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYINEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Add(' in '); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYEQUALEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Add(' == '); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Add(' === '); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYNOTEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Add(' != '); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Add(' !== '); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYBITWISEANDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Add(' & '); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYBITWISEXOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Add(' ^ '); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYBITWISEOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Add(' | '); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBOOLEANLITERAL:begin + if TBESENASTNodeBooleanLiteral(ToVisit).Value then begin + Add('true'); + end else begin + Add('false'); + end; + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + Add('('); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + Add(')'); + end; + bntNEWEXPRESSION:begin + Add('new '); + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + Add('('); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + Add(')'); + end; + bntCONDITIONALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Add(' ? '); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Add(' : '); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('+'); + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYMINUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('-'); + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYBITWISENOTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('~'); + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYLOGICALNOTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('!'); + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYVOIDEXPRESSION:begin + Add('void'); + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Add('typeof'); + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + if TBESENASTNodePropertyExpression(ToVisit).Dot and assigned(TBESENASTNodePropertyExpression(ToVisit).RightExpression) and (TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral) then begin + Add('.'); + Add(BESENUTF16ToUTF8(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value)); + end else begin + Add('['); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + Add(']'); + end; + end; + bntLOGICALANDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Add(' && '); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntLOGICALOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Add(' || '); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntDELETEEXPRESSION:begin + Add('delete '); + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + end; + bntPOSTFIXINCEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + Add('++'); + if NeedParens then begin + Add(')'); + end; + end; + bntPOSTFIXDECEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + Add('--'); + if NeedParens then begin + Add(')'); + end; + end; + bntPREFIXINCEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('++'); + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntPREFIXDECEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('--'); + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntNULLLITERAL:begin + Add('null'); + end; + bntNUMBERLITERAL:begin + if TBESENASTNodeNumberLiteral(ToVisit).Value=trunc(TBESENASTNodeNumberLiteral(ToVisit).Value) then begin + str(trunc(TBESENASTNodeNumberLiteral(ToVisit).Value),s); + end else begin + str(TBESENASTNodeNumberLiteral(ToVisit).Value,s); + end; + Add(s); + end; + bntREGEXPLITERAL:begin + Add('/'+BESENUTF16ToUTF8(TBESENASTNodeRegExpLiteral(ToVisit).Source)+'/'+BESENUTF16ToUTF8(TBESENASTNodeRegExpLiteral(ToVisit).Flags)); + end; + bntSTRINGLITERAL:begin + Add(BESENUTF16ToUTF8(BESENJSONStringQuote(TBESENASTNodeStringLiteral(ToVisit).Value))); + end; + bntTHISLITERAL:begin + Add('this'); + end; + bntOBJECTLITERALPROPERTY:begin + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType of + banolptACCESSOR:begin + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType of + banolpatGET:begin + Add('get '); + end; + banolpatSET:begin + Add('set '); + end; + end; + Add(BESENUTF16ToUTF8(TBESENASTNodeObjectLiteralProperty(ToVisit).Name)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + banolptDATA:begin + Add(BESENUTF16ToUTF8(TBESENASTNodeObjectLiteralProperty(ToVisit).Name)); + Add(': '); + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + end; + end; + end; + bntOBJECTLITERAL:begin + Add('{'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + dec(Indent); + Add('}'); + end; + bntRETURNSTATEMENT:begin + AddIndent; + Add('return '); + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression,false); + AddCRLF(';'); + end; + bntPROGRAM:begin + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + AddIndent; + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; +begin + Code:=''; + Indent:=0; + Visit(RootNode); + result:=Code; +end; + +end. diff --git a/3rd/besen/src/BESENDoubleList.pas b/3rd/besen/src/BESENDoubleList.pas new file mode 100644 index 000000000..3b1e196af --- /dev/null +++ b/3rd/besen/src/BESENDoubleList.pas @@ -0,0 +1,229 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDoubleList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENDoubleArray=^TBESENDoubleArray; + TBESENDoubleArray=array[0..(2147483647 div sizeof(double))-1] of double; + + TBESENDoubleList=class + private + FList:PBESENDoubleArray; + FCount,FSize:integer; + function GetItem(index:integer):double; + procedure SetItem(index:integer;Value:double); + function GetItemPointer(index:integer):pointer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:double):integer; + procedure Insert(index:integer;Item:double); + procedure Delete(index:integer); + function Remove(Item:double):integer; + function Find(Item:double):integer; + function IndexOf(Item:double):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:double read GetItem write SetItem; default; + property Items[index:integer]:double read GetItem write SetItem; + property PItems[index:integer]:pointer read GetItemPointer; + end; + +implementation + +constructor TBESENDoubleList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENDoubleList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENDoubleList.Clear; +begin + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENDoubleList.SetCapacity(NewCapacity:integer); +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENDoubleArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + ReallocMem(FList,NewCapacity*sizeof(double)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(double),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENDoubleList.SetCount(NewCount:integer); +begin + if (NewCount>=0) and (NewCount<high(TBESENDoubleArray)) then begin + if NewCount<FCount then begin + FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(double),#0); + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENDoubleList.Add(Item:double):integer; +begin + result:=FCount; + SetCount(result+1); + FList^[result]:=Item; +end; + +procedure TBESENDoubleList.Insert(index:integer;Item:double); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENDoubleList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENDoubleList.Remove(Item:double):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENDoubleList.Find(Item:double):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENDoubleList.IndexOf(Item:double):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENDoubleList.Exchange(Index1,Index2:integer); +var TempDouble:double; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempDouble:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempDouble; + end; +end; + +function TBESENDoubleList.GetItem(index:integer):double; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=0; + end; +end; + +procedure TBESENDoubleList.SetItem(index:integer;Value:double); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +function TBESENDoubleList.GetItemPointer(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=@FList^[index]; + end else begin + result:=nil; + end; +end; + +end. diff --git a/3rd/besen/src/BESENEnvironmentRecord.pas b/3rd/besen/src/BESENEnvironmentRecord.pas new file mode 100644 index 000000000..8dd3fba6e --- /dev/null +++ b/3rd/besen/src/BESENEnvironmentRecord.pas @@ -0,0 +1,201 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENEnvironmentRecord; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENSelfBalancedTree,BESENHashMap, + BESENGarbageCollector; + +const BESENEnvironmentRecordTypeDeclarative=0; + BESENEnvironmentRecordTypeObject=longword($ffffffff); + +type TBESENEnvironmentRecord=class(TBESENGarbageCollectorObject) + public + IsStrict:TBESENBoolean; + HasMaybeDirectEval:TBESENBoolean; + ImplicitThisValue:TBESENValue; + RecordType:TBESENUINT32; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function HasBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; + function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; virtual; + function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; virtual; + procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); virtual; + function SetMutableBinding(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; virtual; + procedure GetBindingValue(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;Hash:TBESENHash=0); virtual; + function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function DeleteBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; + procedure UpdateImplicitThisValue; virtual; + function CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; + function InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; virtual; + function SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; virtual; + function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; virtual; + procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); virtual; + function DeleteIndex(const I,ID:integer):TBESENBoolean; virtual; + function SetArrayIndexValue(const I:TBESENUINT32;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; virtual; + procedure GetArrayIndexValue(const I:TBESENUINT32;const S:TBESENBoolean;var R:TBESENValue); virtual; + function DeleteArrayIndex(const I:TBESENUINT32):TBESENBoolean; virtual; + end; + +implementation + +uses BESEN,BESENArrayUtils,BESENHashUtils,BESENErrors; + +constructor TBESENEnvironmentRecord.Create(AInstance:TObject); +begin + inherited Create(AInstance); + IsStrict:=TBESEN(Instance).IsStrict; + HasMaybeDirectEval:=true; + ImplicitThisValue:=BESENUndefinedValue; +end; + +destructor TBESENEnvironmentRecord.Destroy; +begin + inherited Destroy; +end; + +{$warnings off} +function TBESENEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0000'); +end; + +function TBESENEnvironmentRecord.HasBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + result:=HasBindingEx(N,Descriptor,Hash); +end; + +function TBESENEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0001'); +end; + +function TBESENEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0002'); +end; + +procedure TBESENEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); +begin + raise EBESENInternalError.Create('201003160116-0003'); +end; + +function TBESENEnvironmentRecord.SetMutableBinding(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; + Temp:TBESENValue; +begin + result:=SetMutableBindingEx(N,V,S,Descriptor,OwnDescriptor,Temp,Hash); +end; + +procedure TBESENEnvironmentRecord.GetBindingValue(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;Hash:TBESENHash=0); +var Descriptor:TBESENObjectPropertyDescriptor; +begin + GetBindingValueEx(N,S,R,Descriptor,Hash); +end; + +function TBESENEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0004'); +end; + +function TBESENEnvironmentRecord.DeleteBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + result:=DeleteBindingEx(N,Descriptor,Hash); +end; + +procedure TBESENEnvironmentRecord.UpdateImplicitThisValue; +begin + raise EBESENInternalError.Create('201003160116-0005'); +end; + +function TBESENEnvironmentRecord.CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0006'); +end; + +function TBESENEnvironmentRecord.InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0007'); +end; + +function TBESENEnvironmentRecord.SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0008'); +end; + +function TBESENEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0009'); +end; + +procedure TBESENEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); +begin + raise EBESENInternalError.Create('201003160116-0010'); +end; + +function TBESENEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0011'); +end; + +function TBESENEnvironmentRecord.SetArrayIndexValue(const I:TBESENUINT32;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +var N:TBESENString; +begin + N:=BESENArrayIndexToStr(I); + result:=SetMutableBinding(N,V,S,BESENHashKey(N)); + N:=''; +end; + +procedure TBESENEnvironmentRecord.GetArrayIndexValue(const I:TBESENUINT32;const S:TBESENBoolean;var R:TBESENValue); +var N:TBESENString; +begin + N:=BESENArrayIndexToStr(I); + GetBindingValue(N,S,R,BESENHashKey(N)); + N:=''; +end; + +function TBESENEnvironmentRecord.DeleteArrayIndex(const I:TBESENUINT32):TBESENBoolean; +var N:TBESENString; +begin + N:=BESENArrayIndexToStr(I); + result:=DeleteBinding(N,BESENHashKey(N)); + N:=''; +end; +{$warnings on} + +end. diff --git a/3rd/besen/src/BESENErrors.pas b/3rd/besen/src/BESENErrors.pas new file mode 100644 index 000000000..0eb79a9a3 --- /dev/null +++ b/3rd/besen/src/BESENErrors.pas @@ -0,0 +1,630 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENErrors; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,BESENConstants,BESENTypes,BESENValue; + +type EBESENError=class(Exception) + public + OriginalMessage:TBESENString; + Name:TBESENString; + Value:TBESENValue; + constructor Create; overload; virtual; +// BEGIN - To avoid "Ambiguous overloaded call to" error + constructor Create(const Msg:string); overload; virtual; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; virtual; +// END - To avoid "Ambiguous overloaded call to" error + constructor Create(const AValue:TBESENValue); overload; virtual; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; virtual; + constructor Create(const AName,Msg:TBESENSTRING); overload; virtual; + constructor Create(const AName,Msg:TBESENSTRING;const AValue:TBESENValue); overload; virtual; + destructor Destroy; override; + end; + + EBESENUseStrict=class(EBESENError) + end; + + EBESENInternalError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENCompilerError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENEvalError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENRangeError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENReferenceError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENSyntaxError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENTypeError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENURIError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENThrowException=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + +procedure BESENThrowReferenceError(const Msg:TBESENString); +procedure BESENThrowSyntaxError(const Msg:TBESENString); +procedure BESENThrowTypeError(const Msg:TBESENString); +procedure BESENThrowRangeError(const Msg:TBESENString); +procedure BESENThrowInternalError(const Msg:TBESENString); +procedure BESENThrowError(const Msg:TBESENString); +procedure BESENThrowCodeGeneratorInvalidRegister; +procedure BESENThrowRecursionLimitReached; +procedure BESENThrowNotDefined(const ARef:TBESENValue); +procedure BESENThrowReference; +procedure BESENThrowNotAccessable(const ARef:TBESENValue); +procedure BESENThrowNotReadable(const P:TBESENString); +procedure BESENThrowNotWritable(const P:TBESENString); +procedure BESENThrowNoSetter(const P:TBESENString); +procedure BESENThrowRcursivePrototypeChain; +procedure BESENThrowPut(const P:TBESENString); +procedure BESENThrowPutRecursivePrototypeChain; +procedure BESENThrowPutInvalidPrototype; +procedure BESENThrowDefineOwnProperty(const P:TBESENString); +procedure BESENThrowCaller; +procedure BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(const fn:TBESENString); +procedure BESENThrowTypeErrorNotAConstructorObject; +procedure BESENThrowTypeErrorObjectHasNoConstruct; +procedure BESENThrowTypeErrorNotAFunction; +procedure BESENThrowTypeErrorNotCallable; + +implementation + +uses BESEN,BESENStringUtils; + +constructor EBESENError.Create; +begin + inherited Create(''); + OriginalMessage:=''; + Name:='Error'; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.Create(const Msg:string); +begin + inherited Create(Msg); + OriginalMessage:={$ifdef Delphi2009AndUp}Msg{$else}BESENConvertToUTF8(Msg){$endif}; + Name:='Error'; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:='Error'; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.Create(const AValue:TBESENValue); +begin + inherited Create(''); + OriginalMessage:=''; + Name:='Error'; + Value:=AValue; +end; + +constructor EBESENError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:='Error'; + Value:=AValue; +end; + +constructor EBESENError.Create(const AName,Msg:TBESENSTRING); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:=AName; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.Create(const AName,Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:=AName; + Value:=AValue; +end; + +destructor EBESENError.Destroy; +begin + OriginalMessage:=''; + Value.Str:=''; + Value.ReferenceBase.Str:=''; + Value:=BESENEmptyValue; + Name:=''; + inherited Destroy; +end; + +constructor EBESENInternalError.Create; +begin + inherited Create; + Name:='InternalError'; +end; + +constructor EBESENInternalError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='InternalError'; +end; + +constructor EBESENInternalError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='InternalError'; +end; + +constructor EBESENInternalError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='InternalError'; +end; + +constructor EBESENInternalError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='InternalError'; +end; + +constructor EBESENCompilerError.Create; +begin + inherited Create; + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='CompilerError'; +end; + +constructor EBESENEvalError.Create; +begin + inherited Create; + Name:='EvalError'; +end; + +constructor EBESENEvalError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='EvalError'; +end; + +constructor EBESENEvalError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='EvalError'; +end; + +constructor EBESENEvalError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='EvalError'; +end; + +constructor EBESENEvalError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='EvalError'; +end; + +constructor EBESENRangeError.Create; +begin + inherited Create; + Name:='RangeError'; +end; + +constructor EBESENRangeError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='RangeError'; +end; + +constructor EBESENRangeError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='RangeError'; +end; + +constructor EBESENRangeError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='RangeError'; +end; + +constructor EBESENRangeError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='RangeError'; +end; + +constructor EBESENReferenceError.Create; +begin + inherited Create; + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='ReferenceError'; +end; + +constructor EBESENSyntaxError.Create; +begin + inherited Create; + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='SyntaxError'; +end; + +constructor EBESENTypeError.Create; +begin + inherited Create; + Name:='TypeError'; +end; + +constructor EBESENTypeError.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='TypeError'; +end; + +constructor EBESENTypeError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='TypeError'; +end; + +constructor EBESENTypeError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='TypeError'; +end; + +constructor EBESENTypeError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='TypeError'; +end; + +constructor EBESENURIError.Create; +begin + inherited Create; + Name:='URIError'; +end; + +constructor EBESENURIError.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='URIError'; +end; + +constructor EBESENURIError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='URIError'; +end; + +constructor EBESENURIError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='URIError'; +end; + +constructor EBESENURIError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='URIError'; +end; + +constructor EBESENThrowException.Create; +begin + inherited Create; + Name:='ThrowException'; +end; + +constructor EBESENThrowException.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='ThrowException'; +end; + +constructor EBESENThrowException.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='ThrowException'; +end; + +constructor EBESENThrowException.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='ThrowException'; +end; + +constructor EBESENThrowException.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='ThrowException'; +end; + +procedure BESENThrowReferenceError(const Msg:TBESENString); +begin + raise EBESENReferenceError.CreateUTF16(Msg); +end; + +procedure BESENThrowSyntaxError(const Msg:TBESENString); +begin + raise EBESENSyntaxError.CreateUTF16(Msg); +end; + +procedure BESENThrowTypeError(const Msg:TBESENString); +begin + raise EBESENTypeError.CreateUTF16(Msg); +end; + +procedure BESENThrowRangeError(const Msg:TBESENString); +begin + raise EBESENRangeError.CreateUTF16(Msg); +end; + +procedure BESENThrowInternalError(const Msg:TBESENString); +begin + raise EBESENInternalError.CreateUTF16(Msg); +end; + +procedure BESENThrowError(const Msg:TBESENString); +begin + raise EBESENError.CreateUTF16(Msg); +end; + +procedure BESENThrowCodeGeneratorInvalidRegister; +begin + BESENThrowError('Invalid register in code generation'); +end; + +procedure BESENThrowRecursionLimitReached; +begin + BESENThrowError('Recursion limit reached'); +end; + +procedure BESENThrowNotDefined(const ARef:TBESENValue); +begin + BESENThrowReferenceError('"'+ARef.Str+'" is not defined'); +end; + +procedure BESENThrowReference; +begin + BESENThrowReferenceError('Reference error'); +end; + +procedure BESENThrowNotAccessable(const ARef:TBESENValue); +begin + BESENThrowReferenceError('"'+ARef.Str+'" is not accessable'); +end; + +procedure BESENThrowNotReadable(const P:TBESENString); +begin + BESENThrowReferenceError('"'+P+'" is not readable'); +end; + +procedure BESENThrowNotWritable(const P:TBESENString); +begin + BESENThrowReferenceError('"'+P+'" is not writable'); +end; + +procedure BESENThrowNoSetter(const P:TBESENString); +begin + BESENThrowTypeError('"'+P+'" has no setter'); +end; + +procedure BESENThrowRcursivePrototypeChain; +begin + BESENThrowTypeError('Recursive prototype chain not allowed'); +end; + +procedure BESENThrowPut(const P:TBESENString); +begin + BESENThrowTypeError('Put for "'+P+'" failed'); +end; + +procedure BESENThrowPutRecursivePrototypeChain; +begin + BESENThrowTypeError('Put for "__proto__" failed, because the prototype chain would be recursive'); +end; + +procedure BESENThrowPutInvalidPrototype; +begin + BESENThrowTypeError('Put for "__proto__" failed, because the prototype would be invalid'); +end; + +procedure BESENThrowDefineOwnProperty(const P:TBESENString); +begin + BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); +end; + +procedure BESENThrowCaller; +begin + BESENThrowTypeError('"caller" not allowed here'); +end; + +procedure BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(const fn:TBESENString); +begin + BESENThrowTypeError('"'+fn+'" not writable or is a accessor descriptor'); +end; + +procedure BESENThrowTypeErrorNotAConstructorObject; +begin + BESENThrowTypeError('Not a constructor object'); +end; + +procedure BESENThrowTypeErrorObjectHasNoConstruct; +begin + BESENThrowTypeError('Object has no construct'); +end; + +procedure BESENThrowTypeErrorNotAFunction; +begin + BESENThrowTypeError('Not a function'); +end; + +procedure BESENThrowTypeErrorNotCallable; +begin + BESENThrowTypeError('Not callable'); +end; + +end. diff --git a/3rd/besen/src/BESENEvalCache.pas b/3rd/besen/src/BESENEvalCache.pas new file mode 100644 index 000000000..7b164b91d --- /dev/null +++ b/3rd/besen/src/BESENEvalCache.pas @@ -0,0 +1,142 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENEvalCache; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, + BESENEvalCacheItem; + +type TBESENEvalCache=class(TBESENBaseObject) + private + procedure SetCacheSize(NewSize:longword); + public + HashSize:longword; + HashSizeMask:longword; + HashItems:TBESENEvalCacheItems; + MaxSourceLength:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Hash(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENHash; + function Get(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENEvalCacheItem; + published + property CacheSize:longword read HashSize write SetCacheSize; + end; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; + +constructor TBESENEvalCache.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashItems:=nil; + SetCacheSize(BESENEvalCacheSize); + MaxSourceLength:=BESENEvalCacheMaxSourceLength; +end; + +destructor TBESENEvalCache.Destroy; +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + BESENFreeAndNil(HashItems[i]); + HashItems[i]:=nil; + end; + end; + SetLength(HashItems,0); + inherited Destroy; +end; + +procedure TBESENEvalCache.SetCacheSize(NewSize:longword); +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + HashItems[i].DecRef; + HashItems[i]:=nil; + end; + end; + HashSize:=BESENRoundUpToPowerOfTwo(NewSize); + HashSizeMask:=HashSize-1; + SetLength(HashItems,HashSize); + for i:=0 to length(HashItems)-1 do begin + HashItems[i]:=nil; + end; +end; + +function TBESENEvalCache.Hash(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENHash; +begin + result:=BESENHashKey(Source); + if CallerStrict then begin + result:=not (result+1); + end; +end; + +function TBESENEvalCache.Get(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENEvalCacheItem; +var HashValue:TBESENUINT32; + Node:TBESENASTNode; +begin + if HashSize>0 then begin + HashValue:=Hash(Source,CallerStrict) and HashSizeMask; + result:=HashItems[HashValue]; + if (assigned(result) and ((result.Source<>Source) or (result.CallerStrict<>CallerStrict))) or not assigned(result) then begin + result:=TBESENEvalCacheItem.Create(Instance); + try + result.Source:=Source; + result.CallerStrict:=CallerStrict; + Node:=TBESEN(Instance).Compile({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}Source{$ifndef BESENSingleStringType}){$endif}); + if (not assigned(Node)) or not (Node is TBESENASTNodeProgram) then begin + BESENThrowError('No program'); + end; + result.Node:=TBESENASTNodeProgram(Node); + try + if assigned(HashItems[HashValue]) then begin + HashItems[HashValue].DecRef; + end; + HashItems[HashValue]:=result; + result.IncRef; + except + HashItems[HashValue]:=nil; + raise; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + end else begin + result:=nil; + end; +end; + +end. diff --git a/3rd/besen/src/BESENEvalCacheItem.pas b/3rd/besen/src/BESENEvalCacheItem.pas new file mode 100644 index 000000000..a82d03176 --- /dev/null +++ b/3rd/besen/src/BESENEvalCacheItem.pas @@ -0,0 +1,85 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENEvalCacheItem; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENRegExp,BESENASTNodes; + +type TBESENEvalCacheItem=class(TBESENBaseObject) + public + ReferenceCounter:integer; + Source:TBESENString; + CallerStrict:TBESENBoolean; + Node:TBESENASTNodeProgram; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure IncRef; + procedure DecRef; + end; + + TBESENEvalCacheItems=array of TBESENEvalCacheItem; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; + +constructor TBESENEvalCacheItem.Create(AInstance:TObject); +begin + inherited Create(Instance); + ReferenceCounter:=0; + Source:=''; + CallerStrict:=false; + Node:=nil; +end; + +destructor TBESENEvalCacheItem.Destroy; +begin + BESENFreeAndNil(Node); + Source:=''; + inherited Destroy; +end; + +procedure TBESENEvalCacheItem.IncRef; +begin + inc(ReferenceCounter); +end; + +procedure TBESENEvalCacheItem.DecRef; +begin + dec(ReferenceCounter); + if ReferenceCounter<=0 then begin + Destroy; + end; +end; + +end. diff --git a/3rd/besen/src/BESENGarbageCollector.pas b/3rd/besen/src/BESENGarbageCollector.pas new file mode 100644 index 000000000..8f88112b6 --- /dev/null +++ b/3rd/besen/src/BESENGarbageCollector.pas @@ -0,0 +1,991 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENGarbageCollector; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENBaseObject,BESENCollectorObject, + BESENPointerSelfBalancedTree,BESENValue; + +type TBESENGarbageCollectorObjectList=class; + + TBESENGarbageCollectorObject=class(TBESENCollectorObject) + public + GarbageCollectorPrevious,GarbageCollectorNext, + GarbageCollectorRootObjectListPrevious,GarbageCollectorRootObjectListNext, + GarbageCollectorProtectedObjectListPrevious,GarbageCollectorProtectedObjectListNext, + GarbageCollectorObjectListPrevious,GarbageCollectorObjectListNext:TBESENGarbageCollectorObject; + GarbageCollectorObjectList:TBESENGarbageCollectorObjectList; + GarbageCollectorDependsChildren,GarbageCollectorDependsParents:TBESENPointerSelfBalancedTree; + GarbageCollectorLockReferenceCounter:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; virtual; + procedure Mark; virtual; + procedure DependsOn(Parent:TBESENGarbageCollectorObject); + procedure GarbageCollectorWriteBarrier; + procedure GarbageCollectorLock; + procedure GarbageCollectorUnlock; + end; + + TBESENGarbageCollectorRootObjectList=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure ClearWithFree; + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure Remove(AObject:TBESENGarbageCollectorObject); + function Contains(AObject:TBESENGarbageCollectorObject):boolean; + procedure Push(AObject:TBESENGarbageCollectorObject); + function Pop:TBESENGarbageCollectorObject; + end; + + TBESENGarbageCollectorProtectedObjectList=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure ClearWithFree; + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure Remove(AObject:TBESENGarbageCollectorObject); + function Contains(AObject:TBESENGarbageCollectorObject):boolean; + procedure Push(AObject:TBESENGarbageCollectorObject); + function Pop:TBESENGarbageCollectorObject; + end; + + TBESENGarbageCollectorObjectList=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure ClearWithFree; + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure Remove(AObject:TBESENGarbageCollectorObject); + function Contains(AObject:TBESENGarbageCollectorObject):boolean; + procedure Push(AObject:TBESENGarbageCollectorObject); + function Pop:TBESENGarbageCollectorObject; + end; + + TBESENGarbageCollectorState=(bgcsINIT,bgcsMARKROOTS,bgcsMARKPROTECTED,bgcsMARKPROGRAMNODES,bgcsMARKCONTEXTS,bgcsMARKGRAYS,bgcsSWEEPWHITES,bgcsDONE); + + TBESENGarbageCollector=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + CurrentRootObject:TBESENGarbageCollectorObject; + CurrentProtectedObject:TBESENGarbageCollectorObject; + CurrentMarkObject:TBESENGarbageCollectorObject; + CurrentSweepObject:TBESENGarbageCollectorObject; + CurrentContext:TObject; + RootObjectList:TBESENGarbageCollectorRootObjectList; + ProtectedObjectList:TBESENGarbageCollectorProtectedObjectList; + WhiteObjectList:TBESENGarbageCollectorObjectList; + GrayObjectList:TBESENGarbageCollectorObjectList; + BlackObjectList:TBESENGarbageCollectorObjectList; + IsSweeping:longbool; + State:TBESENGarbageCollectorState; + TriggerCounter:integer; + MarkFactor:integer; + TriggerCountPerCollect:integer; + Count:int64; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure Reset; + procedure WhiteIt(AObject:TBESENGarbageCollectorObject); + procedure ForceGrayIt(AObject:TBESENGarbageCollectorObject); + procedure GrayIt(AObject:TBESENGarbageCollectorObject); + procedure BlackIt(AObject:TBESENGarbageCollectorObject); + procedure Protect(AObject:TBESENGarbageCollectorObject); + procedure Unprotect(AObject:TBESENGarbageCollectorObject); + procedure FinalizeObjectForSweeping(AObject:TBESENGarbageCollectorObject); + procedure GrayValue(var Value:TBESENValue); + procedure FinalizeValue(var Value:TBESENValue); + procedure Mark(AObject:TBESENGarbageCollectorObject); + procedure Flip; + procedure TriggerCollect; + function Collect:boolean; + procedure CollectAll; + procedure Use(AObject:TBESENGarbageCollectorObject); + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure AddRoot(AObject:TBESENGarbageCollectorObject); + procedure RemoveRoot(AObject:TBESENGarbageCollectorObject); + procedure AddProtected(AObject:TBESENGarbageCollectorObject); + procedure RemoveProtected(AObject:TBESENGarbageCollectorObject); + procedure LockObject(Obj:TBESENGarbageCollectorObject); + procedure UnlockObject(Obj:TBESENGarbageCollectorObject); + procedure LockValue(const Value:TBESENValue); + procedure UnlockValue(const Value:TBESENValue); + end; + +implementation + +uses BESEN,BESENUtils,BESENObject,BESENEnvironmentRecord, + BESENASTNodes,BESENCode,BESENContext, + BESENObjectDeclaredFunction; + +constructor TBESENGarbageCollectorObject.Create(AInstance:TObject); +begin + inherited Create(AInstance); + inc(TBESEN(Instance).GarbageCollector.Count); + GarbageCollectorPrevious:=TBESEN(Instance).GarbageCollector.Last; + GarbageCollectorNext:=nil; + if assigned(GarbageCollectorPrevious) then begin + GarbageCollectorPrevious.GarbageCollectorNext:=self; + end else begin + TBESEN(Instance).GarbageCollector.First:=self; + end; + TBESEN(Instance).GarbageCollector.Last:=self; + GarbageCollectorRootObjectListPrevious:=nil; + GarbageCollectorRootObjectListNext:=nil; + GarbageCollectorProtectedObjectListPrevious:=nil; + GarbageCollectorProtectedObjectListNext:=nil; + GarbageCollectorObjectListPrevious:=nil; + GarbageCollectorObjectListNext:=nil; + GarbageCollectorObjectList:=nil; + GarbageCollectorDependsChildren:=TBESENPointerSelfBalancedTree.Create; + GarbageCollectorDependsParents:=TBESENPointerSelfBalancedTree.Create; + GarbageCollectorLockReferenceCounter:=0; +end; + +destructor TBESENGarbageCollectorObject.Destroy; +var n:PBESENPointerSelfBalancedTreeNode; +begin + if assigned(GarbageCollectorPrevious) then begin + GarbageCollectorPrevious.GarbageCollectorNext:=GarbageCollectorNext; + end else if TBESEN(Instance).GarbageCollector.First=self then begin + TBESEN(Instance).GarbageCollector.First:=GarbageCollectorNext; + end; + if assigned(GarbageCollectorNext) then begin + GarbageCollectorNext.GarbageCollectorPrevious:=GarbageCollectorPrevious; + end else if TBESEN(Instance).GarbageCollector.Last=self then begin + TBESEN(Instance).GarbageCollector.Last:=GarbageCollectorPrevious; + end; + GarbageCollectorNext:=nil; + GarbageCollectorPrevious:=nil; + if assigned(GarbageCollectorObjectList) then begin + GarbageCollectorObjectList.Remove(self); + GarbageCollectorObjectList:=nil; + end; + if assigned(GarbageCollectorDependsParents) then begin + n:=GarbageCollectorDependsParents.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren.Remove(self); + end; + n:=n^.NextKey; + end; + end; + if assigned(GarbageCollectorDependsChildren) then begin + n:=GarbageCollectorDependsChildren.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents.Remove(self); + end; + n:=n^.NextKey; + end; + end; + BESENFreeAndNil(GarbageCollectorDependsChildren); + BESENFreeAndNil(GarbageCollectorDependsParents); + if assigned(Instance) and assigned(TBESEN(Instance).GarbageCollector) then begin + if assigned(TBESEN(Instance).GarbageCollector.RootObjectList) and TBESEN(Instance).GarbageCollector.RootObjectList.Contains(self) then begin + TBESEN(Instance).GarbageCollector.RootObjectList.Remove(self); + end; + if assigned(TBESEN(Instance).GarbageCollector.ProtectedObjectList) and TBESEN(Instance).GarbageCollector.ProtectedObjectList.Contains(self) then begin + TBESEN(Instance).GarbageCollector.ProtectedObjectList.Remove(self); + end; + end; + dec(TBESEN(Instance).GarbageCollector.Count); + inherited Destroy; +end; + +procedure TBESENGarbageCollectorObject.Finalize; +var n:PBESENPointerSelfBalancedTreeNode; +begin + if assigned(GarbageCollectorDependsParents) then begin + n:=GarbageCollectorDependsParents.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren.Remove(self); + end; + n:=n^.NextKey; + end; + end; + if assigned(GarbageCollectorDependsChildren) then begin + n:=GarbageCollectorDependsChildren.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents.Remove(self); + end; + n:=n^.NextKey; + end; + end; +end; + +procedure TBESENGarbageCollectorObject.Mark; +var n:PBESENPointerSelfBalancedTreeNode; +begin + if assigned(GarbageCollectorDependsChildren) then begin + n:=GarbageCollectorDependsChildren.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) then begin + TBESEN(Instance).GarbageCollector.GrayIt(TBESENGarbageCollectorObject(n^.Key)); + end; + n:=n^.NextKey; + end; + end; +end; + +procedure TBESENGarbageCollectorObject.DependsOn(Parent:TBESENGarbageCollectorObject); +var v:TBESENPointerSelfBalancedTreeValue; +begin + if assigned(Parent) then begin + if assigned(GarbageCollectorDependsParents) then begin + v.p:=Parent; + GarbageCollectorDependsParents.Insert(Parent,v); + end; + if assigned(Parent.GarbageCollectorDependsChildren) then begin + v.p:=self; + Parent.GarbageCollectorDependsChildren.Insert(self,v); + end; + end; +end; + +procedure TBESENGarbageCollectorObject.GarbageCollectorWriteBarrier; +begin + TBESEN(Instance).GarbageCollector.GrayIt(self); +end; + +procedure TBESENGarbageCollectorObject.GarbageCollectorLock; +begin + inc(GarbageCollectorLockReferenceCounter); +end; + +procedure TBESENGarbageCollectorObject.GarbageCollectorUnlock; +begin + dec(GarbageCollectorLockReferenceCounter); +end; + +constructor TBESENGarbageCollectorRootObjectList.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Clear; +end; + +destructor TBESENGarbageCollectorRootObjectList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENGarbageCollectorRootObjectList.Clear; +var Item,NextItem:TBESENGarbageCollectorObject; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.GarbageCollectorRootObjectListNext; + Item.GarbageCollectorRootObjectListPrevious:=nil; + Item.GarbageCollectorRootObjectListNext:=nil; + Item:=NextItem; + end; + First:=nil; + Last:=nil; +end; + +procedure TBESENGarbageCollectorRootObjectList.ClearWithFree; +begin + while assigned(First) do begin + First.Free; + end; + Clear; +end; + +procedure TBESENGarbageCollectorRootObjectList.Add(AObject:TBESENGarbageCollectorObject); +begin + if assigned(Last) then begin + Last.GarbageCollectorRootObjectListNext:=AObject; + AObject.GarbageCollectorRootObjectListPrevious:=Last; + AObject.GarbageCollectorRootObjectListNext:=nil; + Last:=AObject; + end else begin + First:=AObject; + Last:=AObject; + end; +end; + +procedure TBESENGarbageCollectorRootObjectList.Remove(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorRootObjectListPrevious) then begin + AObject.GarbageCollectorRootObjectListPrevious.GarbageCollectorRootObjectListNext:=AObject.GarbageCollectorRootObjectListNext; + end else if First=AObject then begin + First:=AObject.GarbageCollectorRootObjectListNext; + end; + if assigned(AObject.GarbageCollectorRootObjectListNext) then begin + AObject.GarbageCollectorRootObjectListNext.GarbageCollectorRootObjectListPrevious:=AObject.GarbageCollectorRootObjectListPrevious; + end else if Last=AObject then begin + Last:=AObject.GarbageCollectorRootObjectListPrevious; + end; + AObject.GarbageCollectorRootObjectListNext:=nil; + AObject.GarbageCollectorRootObjectListPrevious:=nil; +end; + +function TBESENGarbageCollectorRootObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; +begin + result:=((First=AObject) or (Last=AObject)) or (assigned(AObject.GarbageCollectorRootObjectListNext) or assigned(AObject.GarbageCollectorRootObjectListPrevious)); +end; + +procedure TBESENGarbageCollectorRootObjectList.Push(AObject:TBESENGarbageCollectorObject); +begin + Add(AObject); +end; + +function TBESENGarbageCollectorRootObjectList.Pop:TBESENGarbageCollectorObject; +begin + result:=Last; + if assigned(result) then begin + Remove(result); + end; +end; + +constructor TBESENGarbageCollectorProtectedObjectList.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Clear; +end; + +destructor TBESENGarbageCollectorProtectedObjectList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Clear; +var Item,NextItem:TBESENGarbageCollectorObject; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.GarbageCollectorProtectedObjectListNext; + Item.GarbageCollectorProtectedObjectListPrevious:=nil; + Item.GarbageCollectorProtectedObjectListNext:=nil; + Item:=NextItem; + end; + First:=nil; + Last:=nil; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.ClearWithFree; +begin + while assigned(First) do begin + First.Free; + end; + Clear; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Add(AObject:TBESENGarbageCollectorObject); +begin + if assigned(Last) then begin + Last.GarbageCollectorProtectedObjectListNext:=AObject; + AObject.GarbageCollectorProtectedObjectListPrevious:=Last; + AObject.GarbageCollectorProtectedObjectListNext:=nil; + Last:=AObject; + end else begin + First:=AObject; + Last:=AObject; + end; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Remove(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorProtectedObjectListPrevious) then begin + AObject.GarbageCollectorProtectedObjectListPrevious.GarbageCollectorProtectedObjectListNext:=AObject.GarbageCollectorProtectedObjectListNext; + end else if First=AObject then begin + First:=AObject.GarbageCollectorProtectedObjectListNext; + end; + if assigned(AObject.GarbageCollectorProtectedObjectListNext) then begin + AObject.GarbageCollectorProtectedObjectListNext.GarbageCollectorProtectedObjectListPrevious:=AObject.GarbageCollectorProtectedObjectListPrevious; + end else if Last=AObject then begin + Last:=AObject.GarbageCollectorProtectedObjectListPrevious; + end; + AObject.GarbageCollectorProtectedObjectListNext:=nil; + AObject.GarbageCollectorProtectedObjectListPrevious:=nil; +end; + +function TBESENGarbageCollectorProtectedObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; +begin + result:=((First=AObject) or (Last=AObject)) or (assigned(AObject.GarbageCollectorProtectedObjectListNext) or assigned(AObject.GarbageCollectorProtectedObjectListPrevious)); +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Push(AObject:TBESENGarbageCollectorObject); +begin + Add(AObject); +end; + +function TBESENGarbageCollectorProtectedObjectList.Pop:TBESENGarbageCollectorObject; +begin + result:=Last; + if assigned(result) then begin + Remove(result); + end; +end; + +constructor TBESENGarbageCollectorObjectList.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Clear; +end; + +destructor TBESENGarbageCollectorObjectList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENGarbageCollectorObjectList.Clear; +var Item,NextItem:TBESENGarbageCollectorObject; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.GarbageCollectorObjectListNext; + Item.GarbageCollectorObjectListPrevious:=nil; + Item.GarbageCollectorObjectListNext:=nil; + Item.GarbageCollectorObjectList:=nil; + Item:=NextItem; + end; + First:=nil; + Last:=nil; +end; + +procedure TBESENGarbageCollectorObjectList.ClearWithFree; +begin + while assigned(First) do begin + First.Free; + end; + Clear; +end; + +procedure TBESENGarbageCollectorObjectList.Add(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + end; + AObject.GarbageCollectorObjectList:=self; + if assigned(Last) then begin + AObject.GarbageCollectorObjectListPrevious:=Last; + Last.GarbageCollectorObjectListNext:=AObject; + end else begin + First:=AObject; + AObject.GarbageCollectorObjectListPrevious:=nil; + end; + AObject.GarbageCollectorObjectListNext:=nil; + Last:=AObject; +end; + +procedure TBESENGarbageCollectorObjectList.Remove(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorObjectListPrevious) then begin + AObject.GarbageCollectorObjectListPrevious.GarbageCollectorObjectListNext:=AObject.GarbageCollectorObjectListNext; + end else if First=AObject then begin + First:=AObject.GarbageCollectorObjectListNext; + end; + if assigned(AObject.GarbageCollectorObjectListNext) then begin + AObject.GarbageCollectorObjectListNext.GarbageCollectorObjectListPrevious:=AObject.GarbageCollectorObjectListPrevious; + end else if Last=AObject then begin + Last:=AObject.GarbageCollectorObjectListPrevious; + end; + AObject.GarbageCollectorObjectListNext:=nil; + AObject.GarbageCollectorObjectListPrevious:=nil; + AObject.GarbageCollectorObjectList:=nil; +end; + +function TBESENGarbageCollectorObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; +begin + result:=AObject.GarbageCollectorObjectList=self; +end; + +procedure TBESENGarbageCollectorObjectList.Push(AObject:TBESENGarbageCollectorObject); +begin + Add(AObject); +end; + +function TBESENGarbageCollectorObjectList.Pop:TBESENGarbageCollectorObject; +begin + result:=Last; + if assigned(result) then begin + Remove(result); + end; +end; + +constructor TBESENGarbageCollector.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; + RootObjectList:=TBESENGarbageCollectorRootObjectList.Create(Instance); + ProtectedObjectList:=TBESENGarbageCollectorProtectedObjectList.Create(Instance); + WhiteObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); + GrayObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); + BlackObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); + IsSweeping:=false; + State:=bgcsINIT; + TriggerCounter:=0; + MarkFactor:=BESEN_GC_MARKFACTOR; + TriggerCountPerCollect:=BESEN_GC_TRIGGERCOUNT_PER_COLLECT; + Count:=0; +end; + +destructor TBESENGarbageCollector.Destroy; +begin + Clear; + RootObjectList.Free; + ProtectedObjectList.Free; + WhiteObjectList.Free; + GrayObjectList.Free; + BlackObjectList.Free; + inherited Destroy; +end; + +procedure TBESENGarbageCollector.Clear; +var CurrentObject:TBESENGarbageCollectorObject; +begin + CurrentObject:=First; + while assigned(CurrentObject) do begin + FinalizeObjectForSweeping(CurrentObject); + CurrentObject:=CurrentObject.GarbageCollectorNext; + end; + while assigned(First) do begin + First.Free; + end; + First:=nil; + Last:=nil; + RootObjectList.Clear; + ProtectedObjectList.Clear; + WhiteObjectList.Clear; + GrayObjectList.Clear; + BlackObjectList.Clear; + CurrentRootObject:=nil; + CurrentProtectedObject:=nil; + CurrentMarkObject:=nil; + CurrentSweepObject:=nil; + TriggerCounter:=0; + Count:=0; + State:=bgcsINIT; + IsSweeping:=false; +end; + +procedure TBESENGarbageCollector.Reset; +begin + Flip; + CurrentRootObject:=nil; + CurrentProtectedObject:=nil; + CurrentSweepObject:=nil; + State:=bgcsINIT; +end; + +procedure TBESENGarbageCollector.WhiteIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not WhiteObjectList.Contains(AObject) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + WhiteObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.ForceGrayIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not GrayObjectList.Contains(AObject) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + GrayObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.GrayIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not (GrayObjectList.Contains(AObject) or BlackObjectList.Contains(AObject)) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + GrayObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.BlackIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not BlackObjectList.Contains(AObject) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + BlackObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.Protect(AObject:TBESENGarbageCollectorObject); +begin + AddProtected(AObject); +end; + +procedure TBESENGarbageCollector.Unprotect(AObject:TBESENGarbageCollectorObject); +begin + RemoveProtected(AObject); +end; + +procedure TBESENGarbageCollector.GrayValue(var Value:TBESENValue); +begin + case Value.ValueType of + bvtOBJECT:begin + if assigned(Value.Obj) then begin + GrayIt(TBESENObject(Value.Obj)); + end; + end; + bvtREFERENCE:begin + case Value.ReferenceBase.ValueType of + brbvtOBJECT:begin + if assigned(Value.ReferenceBase.Obj) then begin + GrayIt(TBESENObject(Value.ReferenceBase.Obj)); + end; + end; + brbvtENVREC:begin + if assigned(Value.ReferenceBase.EnvRec) then begin + GrayIt(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); + end; + end; + end; + end; + end; +end; + +procedure TBESENGarbageCollector.FinalizeValue(var Value:TBESENValue); +begin + Value:=BESENEmptyValue; +end; + +procedure TBESENGarbageCollector.Mark(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) then begin + AObject.Mark; + end; +end; + +procedure TBESENGarbageCollector.FinalizeObjectForSweeping(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) then begin + AObject.Finalize; + end; +end; + +procedure TBESENGarbageCollector.Flip; +var TempObjectList:TBESENGarbageCollectorObjectList; +begin + TempObjectList:=WhiteObjectList; + WhiteObjectList:=BlackObjectList; + BlackObjectList:=TempObjectList; +end; + +procedure TBESENGarbageCollector.TriggerCollect; +begin + inc(TriggerCounter); + if TriggerCounter>=TriggerCountPerCollect then begin + TriggerCounter:=0; + Collect; + end; +end; + +function TBESENGarbageCollector.Collect:boolean; +var i:integer; + MarkCount:int64; + Current:PBESENPointerSelfBalancedTreeNode; + Node:TBESENASTNodeProgram; + NextObject:TBESENGarbageCollectorObject; +begin + result:=false; + while true do begin + case State of + bgcsINIT:begin + State:=bgcsMARKROOTS; + CurrentRootObject:=RootObjectList.First; + end; + bgcsMARKROOTS:begin + result:=false; + MarkCount:=(MarkFactor*Count) div 256; + if MarkCount<256 then begin + MarkCount:=256; + end else if MarkCount>$7fffffff then begin + MarkCount:=$7fffffff; + end; + for i:=1 to MarkCount do begin + if assigned(CurrentRootObject) then begin + BlackIt(CurrentRootObject); + Mark(CurrentRootObject); + CurrentRootObject:=CurrentRootObject.GarbageCollectorRootObjectListNext; + result:=assigned(CurrentRootObject); + end else begin + break; + end; + end; + if result then begin + break; + end else begin + CurrentProtectedObject:=ProtectedObjectList.First; + State:=bgcsMARKPROTECTED; + end; + end; + bgcsMARKPROTECTED:begin + result:=false; + MarkCount:=(MarkFactor*Count) div 256; + if MarkCount<256 then begin + MarkCount:=256; + end else if MarkCount>$7fffffff then begin + MarkCount:=$7fffffff; + end; + for i:=1 to MarkCount do begin + if assigned(CurrentProtectedObject) then begin + BlackIt(CurrentProtectedObject); + Mark(CurrentProtectedObject); + CurrentProtectedObject:=CurrentProtectedObject.GarbageCollectorProtectedObjectListNext; + result:=assigned(CurrentProtectedObject); + end else begin + break; + end; + end; + if result then begin + break; + end else begin + State:=bgcsMARKPROGRAMNODES; + end; + end; + bgcsMARKPROGRAMNODES:begin + Current:=TBESEN(Instance).ProgramNodes.FirstKey; + while assigned(Current) do begin + Node:=TBESENASTNodeProgram(Current^.Key); + if assigned(Node) and assigned(Node.Body) and assigned(Node.Body.Code) then begin + TBESENCode(Node.Body.Code).Mark; + end; + Current:=Current^.NextKey; + end; + CurrentContext:=TBESEN(Instance).ContextFirst; + State:=bgcsMARKCONTEXTS; + end; + bgcsMARKCONTEXTS:begin + result:=false; + while assigned(CurrentContext) do begin + TBESENContext(CurrentContext).Mark; + CurrentContext:=TBESENContext(CurrentContext).Next; + result:=assigned(CurrentContext); + end; + if result then begin + break; + end else begin + State:=bgcsMARKGRAYS; + end; + end; + bgcsMARKGRAYS:begin + result:=false; + MarkCount:=(MarkFactor*Count) div 256; + if MarkCount<256 then begin + MarkCount:=256; + end else if MarkCount>$7fffffff then begin + MarkCount:=$7fffffff; + end; + for i:=1 to MarkCount do begin + CurrentMarkObject:=GrayObjectList.Pop; + if assigned(CurrentMarkObject) then begin + Mark(CurrentMarkObject); + BlackIt(CurrentMarkObject); + result:=assigned(GrayObjectList.Last); + end else begin + break; + end; + end; + if result then begin + break; + end else begin + CurrentSweepObject:=WhiteObjectList.First; + State:=bgcsSWEEPWHITES; + end; + end; + bgcsSWEEPWHITES:begin + while assigned(CurrentSweepObject) do begin + NextObject:=CurrentSweepObject.GarbageCollectorObjectListNext; + if (CurrentSweepObject.GarbageCollectorLockReferenceCounter>0) or ProtectedObjectList.Contains(CurrentSweepObject) then begin + GrayIt(CurrentSweepObject); + end; + CurrentSweepObject:=NextObject; + end; + if assigned(GrayObjectList.First) then begin + State:=bgcsMARKGRAYS; + end else begin + CurrentSweepObject:=WhiteObjectList.First; + if assigned(CurrentSweepObject) then begin + while assigned(CurrentSweepObject) do begin + FinalizeObjectForSweeping(CurrentSweepObject); + CurrentSweepObject:=CurrentSweepObject.GarbageCollectorObjectListNext; + end; + while assigned(WhiteObjectList.First) do begin + IsSweeping:=true; + WhiteObjectList.First.Free; + IsSweeping:=false; + end; + end; + State:=bgcsDONE; + end; + end; + bgcsDONE:begin + Flip; + State:=bgcsINIT; + result:=false; + break; + end; + end; + end; +end; + +procedure TBESENGarbageCollector.CollectAll; +begin + while Collect do begin + end; +end; + +procedure TBESENGarbageCollector.Use(AObject:TBESENGarbageCollectorObject); +begin + ForceGrayIt(AObject); +end; + +procedure TBESENGarbageCollector.Add(AObject:TBESENGarbageCollectorObject); +begin + GrayIt(AObject); +end; + +procedure TBESENGarbageCollector.AddRoot(AObject:TBESENGarbageCollectorObject); +begin + RootObjectList.Add(AObject); + State:=bgcsINIT; +end; + +procedure TBESENGarbageCollector.RemoveRoot(AObject:TBESENGarbageCollectorObject); +begin + State:=bgcsINIT; + if RootObjectList.Contains(AObject) then begin + RootObjectList.Remove(AObject); + ForceGrayIt(AObject); + end; +end; + +procedure TBESENGarbageCollector.AddProtected(AObject:TBESENGarbageCollectorObject); +begin + GrayIt(AObject); + ProtectedObjectList.Add(AObject); + State:=bgcsINIT; +end; + +procedure TBESENGarbageCollector.RemoveProtected(AObject:TBESENGarbageCollectorObject); +begin + State:=bgcsINIT; + if ProtectedObjectList.Contains(AObject) then begin + ProtectedObjectList.Remove(AObject); + ForceGrayIt(AObject); + end; +end; + +procedure TBESENGarbageCollector.LockObject(Obj:TBESENGarbageCollectorObject); +begin + if assigned(Obj) then begin + Obj.GarbageCollectorLock; + end; +end; + +procedure TBESENGarbageCollector.UnlockObject(Obj:TBESENGarbageCollectorObject); +begin + if assigned(Obj) then begin + Obj.GarbageCollectorUnlock; + end; +end; + +procedure TBESENGarbageCollector.LockValue(const Value:TBESENValue); +begin + case Value.ValueType of + bvtOBJECT:begin + if assigned(Value.Obj) then begin + LockObject(TBESENObject(Value.Obj)); + end; + end; + bvtREFERENCE:begin + case Value.ReferenceBase.ValueType of + brbvtOBJECT:begin + if assigned(Value.ReferenceBase.Obj) then begin + LockObject(TBESENObject(Value.ReferenceBase.Obj)); + end; + end; + brbvtENVREC:begin + if assigned(Value.ReferenceBase.EnvRec) then begin + LockObject(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); + end; + end; + end; + end; + end; +end; + +procedure TBESENGarbageCollector.UnlockValue(const Value:TBESENValue); +begin + case Value.ValueType of + bvtOBJECT:begin + if assigned(Value.Obj) then begin + UnlockObject(TBESENObject(Value.Obj)); + end; + end; + bvtREFERENCE:begin + case Value.ReferenceBase.ValueType of + brbvtOBJECT:begin + if assigned(Value.ReferenceBase.Obj) then begin + UnlockObject(TBESENObject(Value.ReferenceBase.Obj)); + end; + end; + brbvtENVREC:begin + if assigned(Value.ReferenceBase.EnvRec) then begin + UnlockObject(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); + end; + end; + end; + end; + end; +end; + +end. diff --git a/3rd/besen/src/BESENGlobals.pas b/3rd/besen/src/BESENGlobals.pas new file mode 100644 index 000000000..54392bdc5 --- /dev/null +++ b/3rd/besen/src/BESENGlobals.pas @@ -0,0 +1,42 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENGlobals; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +var BESENLengthHash:TBESENHash; + +implementation + +end. diff --git a/3rd/besen/src/BESENHashMap.pas b/3rd/besen/src/BESENHashMap.pas new file mode 100644 index 000000000..773fb908f --- /dev/null +++ b/3rd/besen/src/BESENHashMap.pas @@ -0,0 +1,308 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENHashMap; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils,BESENHashUtils; + +type PBESENHashMapItem=^TBESENHashMapItem; + TBESENHashMapItem=record + Previous,Next,HashPrevious,HashNext:PBESENHashMapItem; + Hash:TBESENHash; + Key:TBESENString; + Value:int64; + Ptr:pointer; + end; + + TBESENHashMapHashBucket=record + HashFirst,HashLast:PBESENHashMapItem; + end; + + TBESENHashMapHashBuckets=array of TBESENHashMapHashBucket; + + TBESENHashMap=class + private + LastUsedItem:PBESENHashMapItem; + procedure GrowAndRehashIfNeeded; + public + First,Last:PBESENHashMapItem; + HashBuckets:TBESENHashMapHashBuckets; + HashSize:longword; + HashSizeMask:longword; + HashedItems:longword; + HashBucketsUsed:longword; + constructor Create; + destructor Destroy; override; + procedure Clear; + function GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENHashMapItem; + function NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENHashMapItem; + function DeleteKey(const Item:PBESENHashMapItem):TBESENBoolean; + end; + +implementation + +constructor TBESENHashMap.Create; +var Hash:TBESENHash; +begin + inherited Create; + FillChar(HashBuckets,sizeof(TBESENHashMapHashBuckets),#0); + First:=nil; + Last:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + HashBuckets:=nil; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + LastUsedItem:=nil; +end; + +destructor TBESENHashMap.Destroy; +begin + Clear; + SetLength(HashBuckets,0); + inherited Destroy; +end; + +procedure TBESENHashMap.Clear; +var Hash:TBESENHash; + Item,NextItem:PBESENHashMapItem; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item^.Next; + Item^.Next:=nil; + Item^.Key:=''; + Dispose(Item); + Item:=NextItem; + end; + First:=nil; + Last:=nil; + LastUsedItem:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; +end; + +procedure TBESENHashMap.GrowAndRehashIfNeeded; +var Hash:TBESENHash; + Item:PBESENHashMapItem; +begin + if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin + LastUsedItem:=nil; + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + inc(HashSize,HashSize); + if HashSize>BESENHashMaxSize then begin + HashSize:=BESENHashMaxSize; + end; + HashSizeMask:=HashSize-1; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashedItems:=0; + Item:=First; + while assigned(Item) do begin + inc(HashedItems); + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + Item:=Item^.Next; + end; + HashBucketsUsed:=0; + Item:=First; + while assigned(Item) do begin + Hash:=BESENHashKey(Item^.Key) and HashSizeMask; + Item^.Hash:=Hash; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=Item; + Item^.HashPrevious:=HashBuckets[Hash].HashLast; + HashBuckets[Hash].HashLast:=Item; + Item^.HashNext:=nil; + end else begin + inc(HashBucketsUsed); + HashBuckets[Hash].HashFirst:=Item; + HashBuckets[Hash].HashLast:=Item; + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + end; + Item:=Item^.Next; + end; + end; +end; + +function TBESENHashMap.GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENHashMapItem; +begin + if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + while assigned(result) and (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if assigned(result) then begin + LastUsedItem:=result; + if HashBuckets[Hash].HashFirst<>result then begin + if assigned(result^.HashPrevious) then begin + result^.HashPrevious^.HashNext:=result^.HashNext; + end; + if assigned(result^.HashNext) then begin + result^.HashNext^.HashPrevious:=result^.HashPrevious; + end else if HashBuckets[Hash].HashLast=result then begin + HashBuckets[Hash].HashLast:=result^.HashPrevious; + end; + HashBuckets[Hash].HashFirst^.HashPrevious:=result; + result^.HashNext:=HashBuckets[Hash].HashFirst; + result^.HashPrevious:=nil; + HashBuckets[Hash].HashFirst:=result; + end; + end; +end; + +function TBESENHashMap.NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENHashMapItem; +begin + if Force then begin + result:=nil; + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + end else if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + if not assigned(result) then begin + inc(HashBucketsUsed); + end; + while assigned(result) and not (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if not assigned(result) then begin + inc(HashedItems); + New(result); + fillchar(result^,sizeof(TBESENHashMapItem),#0); + result^.Hash:=Hash; + result^.Key:=Key; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=result; + result^.HashPrevious:=HashBuckets[Hash].HashLast; + result^.HashNext:=nil; + HashBuckets[Hash].HashLast:=result; + end else begin + HashBuckets[Hash].HashFirst:=result; + HashBuckets[Hash].HashLast:=result; + result^.HashPrevious:=nil; + result^.HashNext:=nil; + end; + if assigned(Last) then begin + Last^.Next:=result; + result^.Previous:=Last; + result^.Next:=nil; + Last:=result; + end else begin + First:=result; + Last:=result; + result^.Previous:=nil; + result^.Next:=nil; + end; + LastUsedItem:=result; + end; + GrowAndRehashIfNeeded; +end; + +function TBESENHashMap.DeleteKey(const Item:PBESENHashMapItem):TBESENBoolean; +begin + result:=assigned(Item); + if result then begin + if LastUsedItem=Item then begin + if assigned(Item^.Next) then begin + LastUsedItem:=Item^.Next; + end else begin + LastUsedItem:=Item^.Previous; + end; + end; + if assigned(Item^.Previous) then begin + Item^.Previous^.Next:=Item^.Next; + end else if First=Item then begin + First:=Item^.Next; + end; + if assigned(Item^.Next) then begin + Item^.Next^.Previous:=Item^.Previous; + end else if Last=Item then begin + Last:=Item^.Previous; + end; + Item^.Next:=nil; + Item^.Previous:=nil; + if assigned(Item^.HashPrevious) then begin + Item^.HashPrevious^.HashNext:=Item^.HashNext; + end else if HashBuckets[Item^.Hash].HashFirst=Item then begin + HashBuckets[Item^.Hash].HashFirst:=Item^.HashNext; + end; + if assigned(Item^.HashNext) then begin + Item^.HashNext^.HashPrevious:=Item^.HashPrevious; + end else if HashBuckets[Item^.Hash].HashLast=Item then begin + HashBuckets[Item^.Hash].HashLast:=Item^.HashPrevious; + end; + Item^.HashNext:=nil; + Item^.HashPrevious:=nil; + Item^.Key:=''; + Dispose(Item); + end; +end; + +end. diff --git a/3rd/besen/src/BESENHashUtils.pas b/3rd/besen/src/BESENHashUtils.pas new file mode 100644 index 000000000..74be316e8 --- /dev/null +++ b/3rd/besen/src/BESENHashUtils.pas @@ -0,0 +1,159 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENHashUtils; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +function BESENHashKey(const Key:TBESENString):TBESENHash; +function BESENDoubleHash(Hash:TBESENHash):TBESENHash; + +implementation + +function BESENHashKey(const Key:TBESENString):TBESENHash; +{$ifdef PurePascal} +var i,h:longword; +begin + h:=2166136261; + for i:=1 to length(Key) do begin +{$ifdef UseOptimizedHashing} + h:=h xor ord(Key[i]); + inc(h,(h shl 1)+(h shl 4)+(h shl 7)+(h shl 8)+(h shl 24)); +{$else} + h:=(h xor ord(Key[i]))*16777619; +{$endif} + end; + if h=0 then begin + // result must be never zero ! ! ! + result:=$ffffffff; + end else begin + result:=h; + end; +end; +{$else} +{$ifdef cpu64} +var i:longword; + h:{$ifdef fpc}qword{$else}int64{$endif}; +begin + h:={$ifdef fpc}qword(14695981039346656037){$else}int64($14650FB0739D0383){$endif}; + for i:=1 to length(Key) do begin +{$ifdef UseOptimizedHashing} + h:=h xor word(widechar(Key[i])); + inc(h,(h shl 1)+(h shl 4)+(h shl 5)+(h shl 7)+(h shl 8)+(h shl 40)); +{$else} + h:=(h xor word(widechar(Key[i])))*1099511628211; +{$endif} + end; + result:=h; + dec(result,ord(result=0)); +end; +{$else} +{$ifdef cpu386} assembler; register; +asm + push ebx + push esi + push edi + test eax,eax + jz @Zero + mov ecx,dword ptr [eax-4] + jecxz @Zero + shr ecx,1 + mov esi,eax + mov eax,2166136261 + xor ebx,ebx +{$ifndef UseOptimizedHashing} + mov edi,16777619 +{$endif} + @Loop: + mov bx,word ptr [esi] + xor eax,ebx +{$ifdef UseOptimizedHashing} + mov ebx,eax + mov edi,ebx + add edi,edi + add eax,edi + mov edi,ebx + shl edi,4 + add eax,edi + mov edi,ebx + shl edi,7 + add eax,edi + mov edi,ebx + shl edi,8 + add eax,edi + shl ebx,24 + add eax,ebx +{$else} + mul edi +{$endif} + add esi,2 + dec ecx + jnz @Loop + or eax,eax + jnz @Done + @Zero: + xor eax,eax + not eax + @Done: + pop edi + pop esi + pop ebx +end; +{$else} +var i,h:longword; +begin + h:=2166136261; + for i:=1 to length(Key) do begin +{$ifdef UseOptimizedHashing} + h:=h xor word(widechar(Key[i])); + inc(h,(h shl 1)+(h shl 4)+(h shl 7)+(h shl 8)+(h shl 24)); +{$else} + h:=(h xor word(widechar(Key[i])))*16777619; +{$endif} + end; + result:=h-ord(h=0); +end; +{$endif} +{$endif} +{$endif} + +function BESENDoubleHash(Hash:TBESENHash):TBESENHash; +begin + result:=(not Hash)+(Hash shr 23); + result:=result xor (result shl 22); + result:=result xor (result shr 7); + result:=result xor (result shl 2); + result:=result xor (result shr 20); +end; + +end. diff --git a/3rd/besen/src/BESENInt64SelfBalancedTree.pas b/3rd/besen/src/BESENInt64SelfBalancedTree.pas new file mode 100644 index 000000000..a6f4ca204 --- /dev/null +++ b/3rd/besen/src/BESENInt64SelfBalancedTree.pas @@ -0,0 +1,632 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENInt64SelfBalancedTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENInt64SelfBalancedTreeValue=^TBESENInt64SelfBalancedTreeValue; + TBESENInt64SelfBalancedTreeValue=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENInt64SelfBalancedTreeNode=^TBESENInt64SelfBalancedTreeNode; + TBESENInt64SelfBalancedTreeNode=record + Parent,Left,Right,PreviousKey,NextKey:PBESENInt64SelfBalancedTreeNode; + Level:int64; + Key:int64; + Value:TBESENInt64SelfBalancedTreeValue; + end; + + TBESENInt64SelfBalancedTreeKeys=array of int64; + + TBESENInt64SelfBalancedTree=class + protected + procedure Skew(OldParent:PBESENInt64SelfBalancedTreeNode); + function Split(OldParent:PBESENInt64SelfBalancedTreeNode):boolean; + procedure RebalanceAfterLeafAdd(n:PBESENInt64SelfBalancedTreeNode); + procedure DeleteNode(n:PBESENInt64SelfBalancedTreeNode); + function First(StartNode:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; + function Next(n:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; + function FindNode(const Key:int64):PBESENInt64SelfBalancedTreeNode; + procedure ClearNode(var Node:PBESENInt64SelfBalancedTreeNode); + procedure OptimizeNode(var Node:PBESENInt64SelfBalancedTreeNode;MoreOptimize:boolean); + function GetValue(Key:int64):TBESENInt64SelfBalancedTreeValue; + procedure SetValue(Key:int64;Value:TBESENInt64SelfBalancedTreeValue); + public + RootNode:PBESENInt64SelfBalancedTreeNode; + FirstKey,LastKey:PBESENInt64SelfBalancedTreeNode; + constructor Create; + destructor Destroy; override; + function Find(const Key:int64;var Value:TBESENInt64SelfBalancedTreeValue):boolean; + function Insert(const Key:int64;Value:TBESENInt64SelfBalancedTreeValue):PBESENInt64SelfBalancedTreeNode; + procedure Remove(const Key:int64); + procedure Optimize; + function Keys:TBESENInt64SelfBalancedTreeKeys; + property Values[Key:int64]:TBESENInt64SelfBalancedTreeValue read GetValue write SetValue; default; + end; + +implementation + +constructor TBESENInt64SelfBalancedTree.Create; +begin + inherited Create; + New(RootNode); + FillChar(RootNode^,SizeOf(TBESENInt64SelfBalancedTreeNode),#0); + RootNode^.Level:=$7fffffffffffffff; + FirstKey:=nil; + LastKey:=nil; +end; + +destructor TBESENInt64SelfBalancedTree.Destroy; +begin + ClearNode(RootNode^.Left); + Dispose(RootNode); + inherited Destroy; +end; + +function TBESENInt64SelfBalancedTree.First(StartNode:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; +begin + try + if not assigned(StartNode^.Left) then begin + result:=nil; + exit; + end; + result:=StartNode; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + except + result:=nil; + end; +end; + +function TBESENInt64SelfBalancedTree.Next(n:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; +begin + try + if assigned(n^.Right) then begin + result:=n^.Right; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + end else begin + while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin + n:=n^.Parent; + end; + n:=n^.Parent; + if not assigned(n) then begin + result:=nil; + exit; + end; + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENInt64SelfBalancedTree.Skew(OldParent:PBESENInt64SelfBalancedTreeNode); +var NewParent:PBESENInt64SelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Left; +{$ifdef UseAssert} + Assert(assigned(NewParent)); +{$endif} + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Left:=NewParent^.Right; + if assigned(OldParent^.Left) then begin + OldParent^.Left^.Parent:=OldParent; + end; + NewParent^.Right:=OldParent; + + if assigned(OldParent^.Left) then begin + OldParent^.level:=OldParent^.Left^.level+1; + end else begin + OldParent^.level:=1; + end; +end; + +function TBESENInt64SelfBalancedTree.Split(OldParent:PBESENInt64SelfBalancedTreeNode):boolean; +var NewParent:PBESENInt64SelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Right; + if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Right:=NewParent^.Left; + if assigned(OldParent^.Right) then begin + OldParent^.Right^.Parent:=OldParent; + end; + NewParent^.Left:=OldParent; + + NewParent^.level:=OldParent^.level+1; + + result:=true; + end else begin + result:=false; + end; +end; + +procedure TBESENInt64SelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENInt64SelfBalancedTreeNode); +begin + // n is a node that has just been inserted and is now a Leaf node. + n^.Level:=1; + n^.Left:=nil; + n^.Right:=nil; + n:=n^.Parent; + while n<>RootNode do begin + if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin + // this point the tree is correct, except (AA2) for n->Parent + Skew(n); + // We handle it (a Left add) by changing it into a Right add using Skew + // If the original add was to the Left side of a node that is on the + // Right side of a horizontal link, n now points to the rights side + // of the second horizontal link, which is correct. + // However if the original add was to the Left of node with a horizontal + // link, we must get to the Right side of the second link. + if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin + n:=n^.Parent; + end; + end; + if not Split(n^.Parent) then begin + break; + end; + n:=n^.Parent; + end; +end; + +function TBESENInt64SelfBalancedTree.FindNode(const Key:int64):PBESENInt64SelfBalancedTreeNode; +var n:PBESENInt64SelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + result:=n; + break; + end else if Key<n^.Key then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + result:=nil; + end; +end; + +function TBESENInt64SelfBalancedTree.Insert(const Key:int64;Value:TBESENInt64SelfBalancedTreeValue):PBESENInt64SelfBalancedTreeNode; +var n,s:PBESENInt64SelfBalancedTreeNode; + LessThan:boolean; +begin + result:=nil; + try + n:=nil; + s:=RootNode^.Left; + while assigned(s) do begin + if Key=s^.Key then begin + n:=s; + break; + end else if Key<s^.Key then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + end; + if assigned(s) then begin + n^.Value:=Value; + end else begin + new(n); + fillchar(n^,sizeof(TBESENInt64SelfBalancedTreeNode),#0); + n^.Key:=Key; + n^.Value:=Value; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + RebalanceAfterLeafAdd(n); + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENInt64SelfBalancedTree.DeleteNode(n:PBESENInt64SelfBalancedTreeNode); +var Leaf,Temp:PBESENInt64SelfBalancedTreeNode; +begin + try + // If n is not a Leaf, we first swap it out with the Leaf node that just + // precedes it. + Leaf:=n; + if assigned(n^.Left) then begin + Leaf:=n^.Left; + while assigned(Leaf^.Right) do begin + Leaf:=Leaf^.Right; + end; + end else if assigned(n^.Right) then begin + Leaf:=n^.Right; + end; + + if Leaf^.Parent=n then begin + Temp:=Leaf; + end else begin + Temp:=Leaf^.Parent; + end; + if Leaf^.Parent^.Left=Leaf then begin + Leaf^.Parent^.Left:=nil; + end else begin + Leaf^.Parent^.Right:=nil; + end; + + if n<>Leaf then begin + if n^.Parent^.Left=n then begin + n^.Parent^.Left:=Leaf; + end else begin + n^.Parent^.Right:=Leaf; + end; + Leaf^.Parent:=n^.Parent; + if assigned(n^.Left) then begin + n^.Left^.Parent:=Leaf; + end; + Leaf^.Left:=n^.Left; + if assigned(n^.Right) then begin + n^.Right^.Parent:=Leaf; + end; + Leaf^.Right:=n^.Right; + Leaf^.level:=n^.level; + end; + if n<>RootNode then begin + n^.Key:=0; + if assigned(n^.PreviousKey) then begin + n^.PreviousKey^.NextKey:=n^.NextKey; + end else if FirstKey=n then begin + FirstKey:=n^.NextKey; + end; + if assigned(n^.NextKey) then begin + n^.NextKey^.PreviousKey:=n^.PreviousKey; + end else if LastKey=n then begin + LastKey:=n^.PreviousKey; + end; + dispose(n); + end; + + while Temp<>RootNode do begin + if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin + dec(Temp^.level); + if Split(Temp) then begin + if Split(Temp) then begin + Skew(Temp^.Parent^.Parent); + end; + break; + end; + Temp:=Temp^.Parent; + end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin + break; + end else begin + Skew(Temp); + { if assigned(Temp^.Right) then begin + if assigned(Temp^.Right^.Left) then begin + Temp^.Right^.level:=Temp^.Right^.level+1; + end else begin + Temp^.Right^.level:=1; + end; + end;} + if Temp^.level>Temp^.Parent^.level then begin + Skew(Temp); + Split(Temp^.Parent^.Parent); + break; + end; + Temp:=Temp^.Parent^.Parent; + end; + end; + except + end; +end; + +procedure TBESENInt64SelfBalancedTree.Remove(const Key:int64); +var n:PBESENInt64SelfBalancedTreeNode; +begin + try + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + DeleteNode(n); + break; + end else if Key<n^.Key then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + end; +end; + +procedure TBESENInt64SelfBalancedTree.ClearNode(var Node:PBESENInt64SelfBalancedTreeNode); +begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=0; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end else if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end else if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + ClearNode(Node^.Left); + ClearNode(Node^.Right); + dispose(Node); + Node:=nil; +end; + +procedure TBESENInt64SelfBalancedTree.OptimizeNode(var Node:PBESENInt64SelfBalancedTreeNode;MoreOptimize:boolean); +var Nodes:array of TBESENInt64SelfBalancedTreeNode; + NodeCount,NodeIndex:integer; + procedure CountNodes(Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + inc(NodeCount); + end; + procedure CollectNodes(Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CollectNodes(Node^.Left); + if NodeIndex>=length(Nodes) then begin + NodeCount:=NodeIndex+1; + SetLength(Nodes,NodeCount); + end; + Nodes[NodeIndex]:=Node^; + inc(NodeIndex); + CollectNodes(Node^.Right); + end; + procedure FreeNodes(var Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=0; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end; + if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + dispose(Node); + Node:=nil; + end; + procedure DoInsertNode(const Node:TBESENInt64SelfBalancedTreeNode); + var n,s:PBESENInt64SelfBalancedTreeNode; + LessThan:boolean; + begin + new(n); + n^:=Node; + n^.Parent:=nil; + n^.Left:=nil; + n^.Right:=nil; + n^.Level:=0; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=n^.Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + if not MoreOptimize then begin + RebalanceAfterLeafAdd(n); + end; + end; + procedure RepairNodes(var Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + RepairNodes(Node^.Left); + RepairNodes(Node^.Right); + if assigned(Node^.Left) and assigned(Node^.Right) then begin + Node^.Level:=Node^.Left^.Level+1; + end else begin + Node^.Level:=1; + end; + end; + procedure ReinsertNodesForRepair(LowNode,HighNode:integer); + var MiddleNode:integer; + begin + if HighNode<LowNode then begin + exit; + end; + MiddleNode:=LowNode+((HighNode-LowNode) div 2); + DoInsertNode(Nodes[MiddleNode]); + ReinsertNodesForRepair(LowNode,MiddleNode-1); + ReinsertNodesForRepair(MiddleNode+1,HighNode); + end; + procedure ReinsertNodes(LowNode,HighNode:integer); + var i:integer; + begin + for i:=LowNode to HighNode do begin + DoInsertNode(Nodes[i]); + end; + end; +begin + if not assigned(Node) then begin + exit; + end; + try + Nodes:=nil; + NodeCount:=0; + CountNodes(Node); + SetLength(Nodes,NodeCount); + NodeIndex:=0; + CollectNodes(Node); + FreeNodes(Node); + if MoreOptimize then begin + ReinsertNodesForRepair(0,length(Nodes)-1); + RepairNodes(RootNode^.Left); + end else begin + ReinsertNodes(0,length(Nodes)-1); + end; + SetLength(Nodes,0); + except + end; +end; + +function TBESENInt64SelfBalancedTree.Find(const Key:int64;var Value:TBESENInt64SelfBalancedTreeValue):boolean; +var n:PBESENInt64SelfBalancedTreeNode; +begin + n:=FindNode(Key); + if assigned(n) then begin + Value:=n^.Value; + result:=true; + end else begin + fillchar(Value,sizeof(TBESENInt64SelfBalancedTreeValue),#0); + result:=false; + end; +end; + +procedure TBESENInt64SelfBalancedTree.Optimize; +begin + OptimizeNode(RootNode^.Left,true); +end; + +function TBESENInt64SelfBalancedTree.Keys:TBESENInt64SelfBalancedTreeKeys; +var CurrentNode:PBESENInt64SelfBalancedTreeNode; + Count:integer; +begin + + result:=nil; + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; + SetLength(result,Count); + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + result[Count]:=CurrentNode^.Key; + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; +end; + +function TBESENInt64SelfBalancedTree.GetValue(Key:int64):TBESENInt64SelfBalancedTreeValue; +begin + Find(Key,result); +end; + +procedure TBESENInt64SelfBalancedTree.SetValue(Key:int64;Value:TBESENInt64SelfBalancedTreeValue); +begin + Insert(Key,Value); +end; + + +end. diff --git a/3rd/besen/src/BESENIntegerList.pas b/3rd/besen/src/BESENIntegerList.pas new file mode 100644 index 000000000..44a65c584 --- /dev/null +++ b/3rd/besen/src/BESENIntegerList.pas @@ -0,0 +1,230 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENIntegerList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENIntegerArray=^TBESENIntegerArray; + TBESENIntegerArray=array[0..(2147483647 div sizeof(integer))-1] of integer; + + TBESENIntegerList=class + private + FList:PBESENIntegerArray; + FCount,FSize:integer; + function GetItem(index:integer):integer; + procedure SetItem(index:integer;Value:integer); + function GetItemPointer(index:integer):pointer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:integer):integer; + procedure Insert(index:integer;Item:integer); + procedure Delete(index:integer); + function Remove(Item:integer):integer; + function Find(Item:integer):integer; + function IndexOf(Item:integer):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:integer read GetItem write SetItem; default; + property Items[index:integer]:integer read GetItem write SetItem; + property PItems[index:integer]:pointer read GetItemPointer; + end; + +implementation + +constructor TBESENIntegerList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENIntegerList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENIntegerList.Clear; +begin + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENIntegerList.SetCapacity(NewCapacity:integer); +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENIntegerArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + ReallocMem(FList,NewCapacity*sizeof(integer)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(integer),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENIntegerList.SetCount(NewCount:integer); +begin + if (NewCount>=0) and (NewCount<high(TBESENIntegerArray)) then begin + if NewCount<FCount then begin + FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(integer),#0); + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENIntegerList.Add(Item:integer):integer; +begin + result:=FCount; + SetCount(result+1); + FList^[result]:=Item; +end; + +procedure TBESENIntegerList.Insert(index:integer;Item:integer); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENIntegerList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENIntegerList.Remove(Item:integer):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENIntegerList.Find(Item:integer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENIntegerList.IndexOf(Item:integer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENIntegerList.Exchange(Index1,Index2:integer); +var TempInteger:integer; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempInteger:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempInteger; + end; +end; + +function TBESENIntegerList.GetItem(index:integer):integer; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=0; + end; +end; + +procedure TBESENIntegerList.SetItem(index:integer;Value:integer); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +function TBESENIntegerList.GetItemPointer(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=@FList^[index]; + end else begin + result:=nil; + end; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENKeyIDManager.pas b/3rd/besen/src/BESENKeyIDManager.pas new file mode 100644 index 000000000..1e8542a4b --- /dev/null +++ b/3rd/besen/src/BESENKeyIDManager.pas @@ -0,0 +1,120 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENKeyIDManager; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENGarbageCollector,BESENHashMap,BESENStringList, + BESENBaseObject; + +type TBESENKeyIDManager=class(TBESENBaseObject) + public + HashMap:TBESENHashMap; + List:TBESENStringList; + Count:int64; + CallerID:TBESENINT32; + LengthID:TBESENINT32; + ProtoID:TBESENINT32; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; + function GetString(const Key:TBESENString;Hash:TBESENHash=0):TBESENString; + function Find(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; + end; + +implementation + +uses BESEN; + +constructor TBESENKeyIDManager.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashMap:=TBESENHashMap.Create; + List:=TBESENStringList.Create; + Count:=0; + CallerID:=Get('caller'); + LengthID:=Get('length'); + ProtoID:=Get('__proto__'); +end; + +destructor TBESENKeyIDManager.Destroy; +begin + HashMap.Free; + List.Free; + inherited Destroy; +end; + +function TBESENKeyIDManager.Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; +var Item:PBESENHashMapItem; +begin + Item:=HashMap.GetKey(Key,Hash); + if TBESEN(Instance).InlineCacheEnabled and not assigned(Item) then begin + inc(Count); + if Count<bimMAXIDENTS then begin + Item:=HashMap.NewKey(Key,true,Hash); + Item^.Value:=List.Add(Key); + end else begin + TBESEN(Instance).InlineCacheEnabled:=false; + List.Clear; + HashMap.Clear; + end; + end; + if assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; +end; + +function TBESENKeyIDManager.GetString(const Key:TBESENString;Hash:TBESENHash=0):TBESENString; +var Item:PBESENHashMapItem; +begin + Item:=HashMap.GetKey(Key,Hash); + if TBESEN(Instance).InlineCacheEnabled and assigned(Item) then begin + result:=List[Item^.Value]; + end else begin + result:=Key; + end; +end; + +function TBESENKeyIDManager.Find(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; +var Item:PBESENHashMapItem; +begin + Item:=HashMap.GetKey(Key,Hash); + if TBESEN(Instance).InlineCacheEnabled and assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; +end; + +end. diff --git a/3rd/besen/src/BESENLexer.pas b/3rd/besen/src/BESENLexer.pas new file mode 100644 index 000000000..6fb3bcc5a --- /dev/null +++ b/3rd/besen/src/BESENLexer.pas @@ -0,0 +1,1416 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENLexer; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils,BESENBaseObject; + +type TBESENLexerTokenType=(ltNONE,ltUNKNOWN,ltEOF, + + // Types + lttIDENTIFIER,lttSTRING,lttINTEGER,lttFLOAT, + + // Operators + ltoASSIGNMENT,ltoBITWISEAND,ltoBITWISEANDASSIGNMENT, + ltoBITWISENOT,ltoBITWISEOR,ltoBITWISEORASSIGNMENT, + ltoBITWISEXOR,ltoBITWISEXORASSIGNMENT,ltoCLOSEBRACE, + ltoCLOSEPAREN,ltoCLOSESQUARE,ltoCOLON,ltoCOMMA, + ltoCONDITIONAL,ltoDIVIDE,ltoDIVIDEASSIGNMENT,ltoDOT, + ltoEQUALEQUAL,ltoEQUALEQUALEQUAL,ltoGREATERTHAN, + ltoGREATERTHANOREQUAL,ltoLESSTHAN,ltoLESSTHANOREQUAL, + ltoLOGICALAND,ltoLOGICALNOT,ltoLOGICALOR,ltoMINUS, + ltoMINUSASSIGNMENT,ltoMINUSMINUS,ltoMODULO, + ltoMODULOASSIGNMENT,ltoMULTIPLY, + ltoMULTIPLYASSIGNMENT,ltoNOTEQUAL,ltoNOTEQUALEQUAL, + ltoOPENBRACE,ltoOPENPAREN,ltoOPENSQUARE,ltoPLUS, + ltoPLUSASSIGNMENT,ltoPLUSPLUS,ltoSEMICOLON, + ltoSHIFTLEFT,ltoSHIFTLEFTASSIGNMENT,ltoSHIFTRIGHT, + ltoSHIFTRIGHTASSIGNMENT,ltoSHIFTRIGHTUNSIGNED, + ltoSHIFTRIGHTUNSIGNEDASSIGNMENT, + + // Used keywords + ltkBREAK,ltkCASE,ltkCATCH,ltkCONTINUE,ltkDEBUGGER, + ltkDEFAULT,ltkDELETE,ltkDO,ltkELSE,ltkFALSE, + ltkFINALLY,ltkFOR,ltkFUNCTION,ltkIF,ltkIN, + ltkINSTANCEOF,ltkNEW,ltkNULL,ltkRETURN,ltkSWITCH, + ltkTHIS,ltkTHROW,ltkTRUE,ltkTRY,ltkTYPEOF,ltkVAR, + ltkVOID,ltkWHILE,ltkWITH, + + // Reserved keywords + ltkCLASS,ltkCONST,ltkENUM,ltkEXPORT,ltkEXTENDS, + ltkIMPORT,ltkSUPER, + + // Additional reserved keywords in strict mode + ltkIMPLEMENTS,ltkINTERFACE,ltkLET,ltkPACKAGE, + ltkPRIVATE,ltkPROTECTED,ltkPUBLIC,ltkSTATIC, + ltkYIELD + ); + + TBESENLexerTokenTypeSet=set of TBESENLexerTokenType; + + TBESENLexerToken=record + TokenType:TBESENLexerTokenType; + Name:TBESENString; + StringValue:TBESENString; + IntValue:int64; + FloatValue:double; + LineNumber:integer; + LineEnd:longbool; + WasLineEnd:longbool; + OldChar:TBESENUTF32CHAR; + OldLineNumber:integer; + OldPosition:integer; + OldCharEOF:longbool; + OldTokenEOF:longbool; + end; + + TBESENLexer=class(TBESENBaseObject) + public + Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; + Position:integer; + LineNumber:integer; + CurrentChar:TBESENUTF32CHAR; + WarningProc:TBESENWarningProc; + CharEOF:longbool; + TokenEOF:longbool; + LastWasLineEnd:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure NextChar; + procedure Restore(var Token:TBESENLexerToken); + function ParseRegExpLiteral(var Token:TBESENLexerToken;var ASource,AFlags:TBESENString):boolean; + function IsEOF:boolean; + procedure GetToken(var AResult:TBESENLexerToken); + end; + +const BESENLexerReservedTokens:TBESENLexerTokenTypeSet=[ltkCLASS,ltkCONST,ltkENUM,ltkEXPORT,ltkEXTENDS,ltkIMPORT,ltkSUPER]; + + BESENLexerStrictReservedTokens:TBESENLexerTokenTypeSet=[ltkIMPLEMENTS,ltkINTERFACE,ltkLET,ltkPACKAGE,ltkPRIVATE, + ltkPROTECTED,ltkPUBLIC,ltkSTATIC,ltkYIELD]; + + BESENLexerKeywordsTokens:TBESENLexerTokenTypeSet=[ltkBREAK..ltkYIELD]; + + BESENTokenStrings:array[TBESENLexerTokenType] of TBESENString=('','','EOF', + + // Types + 'IDENTIFIER','STRING','INTEGER','FLOAT', + + // Operators + '==','&','&=', + '~','|','|=', + '^','^=','}', + ')',']',':',',', + '?','/','/=','.', + '==','===','>', + '>=','<','<=', + '&&','!','||','-', + '-=','--','%', + '%=','*', + '*=','!=','!==', + '{','(','[','+', + '+=','++',';', + '<<','<<=','>>', + '>>=','>>>','>>>=', + + // Used keywords + 'break','case','catch','continue','debugger', + 'default','delete','do','else','false', + 'finally','for','function','if','in', + 'instanceof','new','null','return','switch', + 'this','throw','true','try','typeof','var', + 'void','while','with', + + // Reserved keywords + 'class','const','enum','export','extends', + 'import','super', + + // Additional reserved keywords in strict mode + 'implements','interface','let','package', + 'private','protected','public','static', + 'yield'); + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESEN,BESENRegExp,BESENErrors,BESENNumberUtils; + +type TKeywordToken=ltkBREAK..ltkYIELD; + + TKeyword=TKeywordToken; + + TKeywords=array of TKeyword; + +const KeywordNames:array[TKeywordToken] of TBESENUTF16STRING= + (// Used keywords + 'break','case','catch','continue','debugger', + 'default','delete','do','else','false', + 'finally','for','function','if','in', + 'instanceof','new','null','return','switch', + 'this','throw','true','try','typeof','var', + 'void','while','with', + + // Reserved keywords + 'class','const','enum','export','extends', + 'import','super', + + // Additional reserved keywords in strict mode + 'implements','interface','let','package', + 'private','protected','public','static', + 'yield'); + + Keywords:TKeywords=nil; + +constructor TBESENLexer.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Source:=''; + Position:=1; + LineNumber:=1; + WarningProc:=nil; + CharEOF:=false; + TokenEOF:=false; + LastWasLineEnd:=false; +end; + +destructor TBESENLexer.Destroy; +begin + Source:=''; + inherited Destroy; +end; + +function TBESENLexer.IsEOF:boolean; +begin + result:=TokenEOF; +end; + +procedure TBESENLexer.NextChar; +{$ifdef BESENSingleStringType} +var Len:integer; +{$else} +var b:byte; +{$endif} +begin + if (Position>=1) and (Position<=length(Source)) then begin +{$ifdef BESENSingleStringType} +{$ifdef BESENEmbarcaderoNextGen} + CurrentChar:=Char.ConvertToUTF32(s,Position-1,Len); + inc(Position,Len); +{$else} + CurrentChar:=ord(Source[Position]); + inc(Position); + if (Position<=length(Source)) and ((SizeOf(Source[Position])=SizeOf(word)) and (((CurrentChar and $fc00)=$d800) and ((ord(Source[Position]) and $fc00)=$dc00))) then begin + // UTF16 + CurrentChar:=(((CurrentChar and $3ff) shl 10) or (ord(Source[Position]) and $3ff))+$10000; + inc(Position); + end; +{$endif} +{$else} + b:=byte(Source[Position]); + if (b and $80)=0 then begin + CurrentChar:=b; + inc(Position); + end else if ((Position+1)<=length(Source)) and ((b and $e0)=$c0) and ((byte(Source[Position+1]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $1f) shl 6) or (byte(Source[Position+1]) and $3f); + inc(Position,2); + end else if ((Position+2)<=length(Source)) and ((b and $f0)=$e0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $0f) shl 12) or ((byte(Source[Position+1]) and $3f) shl 6) or (byte(Source[Position+2]) and $3f); + inc(Position,3); + end else if ((Position+3)<=length(Source)) and ((b and $f8)=$f0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $07) shl 18) or ((byte(Source[Position+1]) and $3f) shl 12) or ((byte(Source[Position+2]) and $3f) shl 6) or (byte(Source[Position+3]) and $3f); + inc(Position,4); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+4)<=length(Source)) and ((b and $fc)=$f8) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $03) shl 24) or ((byte(Source[Position+1]) and $3f) shl 18) or ((byte(Source[Position+2]) and $3f) shl 12) or ((byte(Source[Position+3]) and $3f) shl 6) or (byte(Source[Position+4]) and $3f); + inc(Position,5); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+5)<=length(Source)) and ((b and $fe)=$fc) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) and ((byte(Source[Position+5]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $01) shl 30) or ((byte(Source[Position+1]) and $3f) shl 24) or ((byte(Source[Position+2]) and $3f) shl 18) or ((byte(Source[Position+3]) and $3f) shl 12) or ((byte(Source[Position+4]) and $3f) shl 6) or (byte(Source[Position+5]) and $3f); + inc(Position,6); + end else begin + CurrentChar:=$fffd; + inc(Position); + end; +{$endif} + end else begin + CurrentChar:=0; + CharEOF:=true; + end; +end; + +procedure TBESENLexer.Restore(var Token:TBESENLexerToken); +begin + Position:=Token.OldPosition; + LineNumber:=Token.OldLineNumber; + CurrentChar:=Token.OldChar; + CharEOF:=Token.OldCharEOF; + TokenEOF:=Token.OldTokenEOF; +end; + +function TBESENLexer.ParseRegExpLiteral(var Token:TBESENLexerToken;var ASource,AFlags:TBESENString):boolean; +var InCharClass,fg,fi,fm:boolean; + RegExpFlags:TBESENRegExpFlags; +begin + result:=false; + ASource:=''; + AFlags:=''; + InCharClass:=false; + while not CharEOF do begin + NextChar; + case CurrentChar of + $00,$0a,$0d,$2028,$2029:begin + exit; + end; + ord('\'):begin + ASource:=ASource+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + ord('['):begin + InCharClass:=true; + end; + ord(']'):begin + InCharClass:=false; + end; + ord('/'):begin + if not InCharClass then begin + break; + end; + end; + end; + ASource:=ASource+BESENUTF32CHARToUTF16(CurrentChar); + end; + if (not CharEOF) and (CurrentChar=ord('/')) then begin + NextChar; + end else begin + raise EBESENSyntaxError.Create('unterminated regex'); + end; + AFlags:=''; + fg:=false; + fi:=false; + fm:=false; + while not CharEOF do begin + case CurrentChar of + ord('g'):begin + if fg then begin + raise EBESENSyntaxError.Create('Too many global regular expression flags'); + end else begin + fg:=true; + AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + ord('i'):begin + if fi then begin + raise EBESENSyntaxError.Create('Too many ignorecase regular expression flags'); + end else begin + fi:=true; + AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + ord('m'):begin + if fm then begin + raise EBESENSyntaxError.Create('Too many multiline regular expression flags'); + end else begin + fm:=true; + AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + else begin + break; + end; + end; + end; + if BESENUnicodeIsLetter(CurrentChar) then begin + raise EBESENSyntaxError.Create('Unknown regular expression flag'); + end; + RegExpFlags:=[]; + if fg then begin + RegExpFlags:=RegExpFlags+[brefGLOBAL]; + end; + if fi then begin + RegExpFlags:=RegExpFlags+[brefIGNORECASE]; + end; + if fm then begin + RegExpFlags:=RegExpFlags+[brefMULTILINE]; + end; + try + TBESEN(Instance).RegExpCache.Get(ASource,RegExpFlags); + except + raise EBESENSyntaxError.Create('Invalid regular expression'); + end; + Token.StringValue:='/'+ASource+'/'+AFlags; + result:=true; +end; + +procedure TBESENLexer.GetToken(var AResult:TBESENLexerToken); +var c:TBESENUTF32CHAR; + v:longword; + procedure AddError(const Msg:TBESENSTRING); + begin + TBESEN(Instance).LineNumber:=LineNumber; + raise EBESENSyntaxError.CreateUTF16(Msg); + end; + procedure AddWarning(const Msg:TBESENSTRING); + begin + if assigned(WarningProc) then begin + WarningProc(LineNumber,Msg); + end; + end; + procedure ParseNumber(c:widechar;var Token:TBESENLexerToken); + var s:TBESENString; + HasDigits:boolean; + begin + Token.TokenType:=ltUNKNOWN; + + HasDigits:=false; + + s:=''; + + if c='.' then begin + if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + s:=s+'.'; + + while (not CharEOF) and (CurrentChar=ord('0')) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + + if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin + s:=s+widechar(CurrentChar); + NextChar; + if (not CharEOF) and ((CurrentChar=ord('+')) or (CurrentChar=ord('-'))) then begin + s:=s+widechar(CurrentChar); + NextChar; + end; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + end; + + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble('0'+s); + s:=''; + end; + exit; + end; + + if (not CharEOF) and (CurrentChar=ord('0')) then begin + NextChar; + case CurrentChar of + ord('x'),ord('X'):begin + NextChar; + s:='0x'; + while not CharEOF do begin + case CurrentChar of + ord('a')..ord('f'),ord('A')..ord('F'),ord('0')..ord('9'):begin + s:=s+widechar(word(CurrentChar)); + HasDigits:=true; + NextChar; + end; + else begin + break; + end; + end; + end; + if HasDigits then begin + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble(s); + end; + s:=''; + exit; + end; + ord('0')..ord('7'):begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and not TBESEN(Instance).IsStrict then begin + s:='0'; + while not CharEOF do begin + case CurrentChar of + ord('0')..ord('7'):begin + s:=s+widechar(word(CurrentChar)); + HasDigits:=true; + NextChar; + end; + else begin + break; + end; + end; + end; + if HasDigits then begin + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble(s); + end; + s:=''; + exit; + end else begin + AddError('Bad number literal'); + end; + end; + ord('8')..ord('9'):begin + AddError('Bad number literal'); + end; + else begin + HasDigits:=true; + s:=s+widechar('0'); + end; + end; + end; + + if TBESEN(Instance).IsStrict and HasDigits and ((not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9')))) then begin + AddError('Bad number literal'); + end else begin + + while (not CharEOF) and (CurrentChar=ord('0')) do begin + s:=s+widechar(CurrentChar); + HasDigits:=true; + NextChar; + end; + + if TBESEN(Instance).IsStrict and HasDigits and ((not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9')))) then begin + AddError('Bad number literal'); + end else begin + + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + HasDigits:=true; + NextChar; + end; + + if (not CharEOF) and (CurrentChar=ord('.')) then begin + s:=s+widechar(CurrentChar); + NextChar; + + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + HasDigits:=true; + end; + end; + + if HasDigits then begin + + if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin + HasDigits:=false; + s:=s+widechar(CurrentChar); + NextChar; + if (not CharEOF) and ((CurrentChar=ord('+')) or (CurrentChar=ord('-'))) then begin + s:=s+widechar(CurrentChar); + NextChar; + end; + if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + HasDigits:=true; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + end else begin + exit; + end; + end; + + if HasDigits then begin + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble(s); + end; + end; + end; + end; + + s:=''; + end; + function FindKeyword(const Name:TBESENUTF16STRING):TBESENLexerTokenType; + var LowIndex,HighIndex,MiddleIndex:integer; + begin + result:=lttIDENTIFIER; + LowIndex:=0; + HighIndex:=length(Keywords)-1; + while LowIndex<=HighIndex do begin + case (HighIndex-LowIndex)+1 of + 1:begin + if KeywordNames[Keywords[LowIndex]]=Name then begin + result:=Keywords[LowIndex]; + end; + end; + 2:begin + if KeywordNames[Keywords[LowIndex]]=Name then begin + result:=Keywords[LowIndex]; + end else if KeywordNames[Keywords[HighIndex]]=Name then begin + result:=Keywords[HighIndex]; + end; + end; + else begin + MiddleIndex:=(LowIndex+HighIndex) div 2; + if KeywordNames[Keywords[MiddleIndex]]=Name then begin + result:=Keywords[MiddleIndex]; + end else if LowIndex<>HighIndex then begin + if KeywordNames[Keywords[MiddleIndex]]>Name then begin + HighIndex:=MiddleIndex-1; + end else begin + LowIndex:=MiddleIndex+1; + end; + continue; + end; + end; + end; + break; + end; + end; +begin + AResult.Name:=''; + AResult.StringValue:=''; + AResult.FloatValue:=0; + AResult.IntValue:=0; + AResult.LineNumber:=LineNumber; + AResult.LineEnd:=false; + AResult.WasLineEnd:=LastWasLineEnd; + AResult.OldChar:=CurrentChar; + AResult.OldLineNumber:=LineNumber; + AResult.OldPosition:=Position; + AResult.OldCharEOF:=CharEOF; + AResult.OldTokenEOF:=TokenEOF; + LastWasLineEnd:=false; + AResult.TokenType:=ltUNKNOWN; + while true do begin + if CharEOF then begin + TokenEOF:=true; + AResult.TokenType:=ltEOF; + break; + end else begin + while BESENUnicodeIsParserWhiteSpace(CurrentChar) do begin + case CurrentChar of + 0:begin + NextChar; + if not CharEOF then begin + CurrentChar:=1; + end; + end; + $000d:begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + inc(LineNumber); + AResult.WasLineEnd:=true; + end; + $000a,$2028,$2029:begin + NextChar; + inc(LineNumber); + AResult.WasLineEnd:=true; + end; + else begin + NextChar; + end; + end; + end; + if CharEOF then begin + AResult.TokenType:=ltEOF; + TokenEOF:=true; + break; + end else begin + AResult.LineNumber:=LineNumber; + AResult.OldChar:=CurrentChar; + AResult.OldLineNumber:=LineNumber; + AResult.OldPosition:=Position; + AResult.OldCharEOF:=CharEOF; + AResult.OldTokenEOF:=TokenEOF; + case CurrentChar of + 0:begin + end; + ord('='):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoEQUALEQUALEQUAL; + end; + else begin + AResult.TokenType:=ltoEQUALEQUAL; + end; + end; + end; + else begin + AResult.TokenType:=ltoASSIGNMENT; + end; + end; + end; + ord('&'):begin + NextChar; + case CurrentChar of + ord('&'):begin + NextChar; + AResult.TokenType:=ltoLOGICALAND; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoBITWISEANDASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoBITWISEAND; + end; + end; + end; + ord('|'):begin + NextChar; + case CurrentChar of + ord('|'):begin + NextChar; + AResult.TokenType:=ltoLOGICALOR; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoBITWISEORASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoBITWISEOR; + end; + end; + end; + ord('^'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoBITWISEXORASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoBITWISEXOR; + end; + end; + end; + ord('/'):begin + NextChar; + case CurrentChar of + ord('/'):begin + while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin + NextChar; + end; + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + end else begin + NextChar; + end; + end; + continue; + end; + ord('*'):begin + NextChar; + c:=0; + while (not ((c=ord('*')) and (CurrentChar=ord('/')))) and not CharEOF do begin + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + c:=CurrentChar; + NextChar; + if CurrentChar=$000a then begin + c:=CurrentChar; + NextChar; + end; + end else begin + c:=CurrentChar; + NextChar; + end; + end else begin + c:=CurrentChar; + NextChar; + end; + end; + if CurrentChar=ord('/') then begin + NextChar; + end; + continue; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoDIVIDEASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoDIVIDE; + end; + end; + end; + ord('>'):begin + NextChar; + case CurrentChar of + ord('>'):begin + NextChar; + case CurrentChar of + ord('>'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoSHIFTRIGHTUNSIGNEDASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoSHIFTRIGHTUNSIGNED; + end; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoSHIFTRIGHTASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoSHIFTRIGHT; + end; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoGREATERTHANOREQUAL; + end; + else begin + AResult.TokenType:=ltoGREATERTHAN; + end; + end; + end; + ord('<'):begin + NextChar; + case CurrentChar of + ord('<'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoSHIFTLEFTASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoSHIFTLEFT; + end; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoLESSTHANOREQUAL; + end; + ord('!'):begin + if (TBESEN(Instance).Compatibility and COMPAT_SGMLCOM)<>0 then begin + if ((Position+2)<=length(Source)) and (Source[Position]='-') and (Source[Position+1]='-') then begin + while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin + NextChar; + end; + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + end else begin + NextChar; + end; + continue; + end; + end else begin + AResult.TokenType:=ltoLESSTHAN; + end; + end else begin + AResult.TokenType:=ltoLESSTHAN; + end; + end; + else begin + AResult.TokenType:=ltoLESSTHAN; + end; + end; + end; + ord('-'):begin + NextChar; + case CurrentChar of + ord('-'):begin + NextChar; + if (TBESEN(Instance).Compatibility and COMPAT_SGMLCOM)<>0 then begin + if (Position=length(Source)) and (Source[Position]='>') then begin + while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin + NextChar; + end; + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + end else begin + NextChar; + end; + continue; + end; + end else begin + AResult.TokenType:=ltoMINUSMINUS; + end; + end else begin + AResult.TokenType:=ltoMINUSMINUS; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoMINUSASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoMINUS; + end; + end; + end; + ord('+'):begin + NextChar; + case CurrentChar of + ord('+'):begin + NextChar; + AResult.TokenType:=ltoPLUSPLUS; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoPLUSASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoPLUS; + end; + end; + end; + ord('%'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoMODULOASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoMODULO; + end; + end; + end; + ord('*'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoMULTIPLYASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoMULTIPLY; + end; + end; + end; + ord('!'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoNOTEQUALEQUAL; + end else begin + AResult.TokenType:=ltoNOTEQUAL; + end; + end; + end; + else begin + AResult.TokenType:=ltoLOGICALNOT; + end; + end; + end; + ord('~'):begin + NextChar; + AResult.TokenType:=ltoBITWISENOT; + end; + ord('}'):begin + NextChar; + AResult.TokenType:=ltoCLOSEBRACE; + end; + ord(')'):begin + NextChar; + AResult.TokenType:=ltoCLOSEPAREN; + end; + ord(']'):begin + NextChar; + AResult.TokenType:=ltoCLOSESQUARE; + end; + ord('{'):begin + NextChar; + AResult.TokenType:=ltoOPENBRACE; + end; + ord('('):begin + NextChar; + AResult.TokenType:=ltoOPENPAREN; + end; + ord('['):begin + NextChar; + AResult.TokenType:=ltoOPENSQUARE; + end; + ord(':'):begin + NextChar; + AResult.TokenType:=ltoCOLON; + end; + ord(';'):begin + NextChar; + AResult.TokenType:=ltoSEMICOLON; + end; + ord(','):begin + NextChar; + AResult.TokenType:=ltoCOMMA; + end; + ord('?'):begin + NextChar; + AResult.TokenType:=ltoCONDITIONAL; + end; + ord('.'):begin + NextChar; + case CurrentChar of + ord('0')..ord('9'):begin + ParseNumber('.',AResult); + end; + else begin + AResult.TokenType:=ltoDOT; + end; + end; + end; + ord('0')..ord('9'):begin + ParseNumber(#0,AResult); + end; + ord('"'),ord(''''):begin + AResult.TokenType:=lttSTRING; + c:=CurrentChar; + NextChar; + AResult.StringValue:=''; + while (CurrentChar<>c) and (Position<=length(Source)) do begin + case CurrentChar of + $000a,$000d,$2028,$2029:begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + AddError('Unterminated string literal'); + break; + end else begin + NextChar; + end; + end; + $fffe,$feff:begin + AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); + NextChar; + end; + ord('\'):begin + NextChar; + case CurrentChar of + $000d:begin + AResult.StringValue:=AResult.StringValue+#$000d; + NextChar; + if CurrentChar=$000a then begin + AResult.StringValue:=AResult.StringValue+#$000a; + NextChar; + end; + inc(LineNumber); + AResult.WasLineEnd:=true; + end; + $000a,$2028,$2029:begin + AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); + inc(LineNumber); + AResult.WasLineEnd:=true; + break; + end; + ord('b'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$0008; + end; + ord('t'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$0009; + end; + ord('n'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000a; + end; + ord('v'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000b; + end; + ord('f'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000c; + end; + ord('r'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000d; + end; + ord('s'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$fffe; + end; + ord('0')..ord('7'):begin + if TBESEN(Instance).IsStrict then begin + AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); + NextChar; + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin + raise EBESENSyntaxError.Create('Octals aren''t allowed in strict mode'); + end; + end else begin + v:=CurrentChar-ord('0'); + NextChar; + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin + v:=(v shl 3) or longword(CurrentChar-ord('0')); + NextChar; + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin + v:=(v shl 3) or longword(CurrentChar-ord('0')); + NextChar; + end; + end; + AResult.StringValue:=AResult.StringValue+widechar(word(v)); + end; + end; + ord('x'):begin + if ((Position+1)<=length(Source)) and BESENIsHex(word(widechar(Source[Position]))) and BESENIsHex(word(widechar(Source[Position+1]))) then begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + AResult.StringValue:=AResult.StringValue+widechar(word(v)); + end else begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + AddError('Invalid escape char x'); + end else begin + NextChar; + AResult.StringValue:=AResult.StringValue+'x'; + end; + end; + end; + ord('u'):begin + if ((Position+3)<=length(Source)) and BESENIsHex(word(widechar(Source[Position]))) and BESENIsHex(word(widechar(Source[Position+1]))) and BESENIsHex(word(widechar(Source[Position+2]))) and BESENIsHex(word(widechar(Source[Position+3]))) then begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + end; + end; + AResult.StringValue:=AResult.StringValue+widechar(word(v)); + end else begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + AddError('Invalid escape char u'); + end else begin + NextChar; + AResult.StringValue:=AResult.StringValue+'u'; + end; + end; + end; + else begin + AResult.StringValue:=AResult.StringValue+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + end; + else begin + AResult.StringValue:=AResult.StringValue+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + end; + if CurrentChar=c then begin + NextChar; + end else begin + AddError('Unterminated string literal'); + end; + end; + else begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (CurrentChar=ord('#')) then begin + NextChar; + AResult.Name:='function'; + AResult.TokenType:=ltkFUNCTION; + end else if BESENUnicodeIsIDStart(CurrentChar) or (CurrentChar=ord('\')) then begin + AResult.Name:=''; + while BESENUnicodeIsIDPart(CurrentChar) or (CurrentChar=ord('\')) do begin + if CurrentChar=ord('\') then begin + NextChar; + case CurrentChar of + ord('x'),ord('X'):begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + AResult.Name:=AResult.Name+widechar(word(v)); + end; + ord('u'),ord('U'):begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + end; + end; + AResult.Name:=AResult.Name+widechar(word(v)); + end; + else begin + AResult.Name:=AResult.Name+'\'+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + end else begin + AResult.Name:=AResult.Name+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + if (length(AResult.Name)>0) and ((word(widechar(AResult.Name[1]))=$200c) or (word(widechar(AResult.Name[1]))=$200d)) then begin + raise EBESENSyntaxError.Create('Invalid identifier because <ZWJ> and <ZWNJ> are prohibited as first character'); + end; + AResult.TokenType:=FindKeyword(AResult.Name); + if AResult.TokenType in BESENLexerStrictReservedTokens then begin + if TBESEN(Instance).IsStrict then begin + raise EBESENSyntaxError.CreateUTF16('"'+AResult.Name+'" is a reserved keyword'); + end else begin + AResult.TokenType:=lttIDENTIFIER; + end; + end; + end; + end; + end; + end; + break; + end; + AResult.LineEnd:=BESENUnicodeIsLineTerminator(CurrentChar); + LastWasLineEnd:=AResult.LineEnd; + end; +end; + +procedure InitKeywords; +var kt:TKeywordToken; + i:integer; + k:TKeyword; +begin + SetLength(Keywords,(integer(high(TKeywordToken))-integer(low(TKeywordToken)))+1); + i:=0; + for kt:=low(TKeywordToken) to high(TKeywordToken) do begin + Keywords[i]:=kt; + inc(i); + end; + i:=0; + while (i+1)<length(Keywords) do begin + if KeywordNames[Keywords[i]]>KeywordNames[Keywords[i+1]] then begin + k:=Keywords[i]; + Keywords[i]:=Keywords[i+1]; + Keywords[i+1]:=k; + if i>0 then begin + dec(i); + end else begin + inc(i); + end; + end else begin + inc(i); + end; + end; +end; + +procedure DoneKeywords; +begin + SetLength(Keywords,0); +end; + +procedure InitBESEN; +begin + InitKeywords; +end; + +procedure DoneBESEN; +begin + DoneKeywords; +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENLexicalEnvironment.pas b/3rd/besen/src/BESENLexicalEnvironment.pas new file mode 100644 index 000000000..6ce3e5281 --- /dev/null +++ b/3rd/besen/src/BESENLexicalEnvironment.pas @@ -0,0 +1,80 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENLexicalEnvironment; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENGarbageCollector; + +type TBESENLexicalEnvironment=class(TBESENGarbageCollectorObject) + public + Outer:TBESENLexicalEnvironment; + EnvironmentRecord:TBESENEnvironmentRecord; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENLexicalEnvironment.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Outer:=nil; + EnvironmentRecord:=nil; +end; + +destructor TBESENLexicalEnvironment.Destroy; +begin + Outer:=nil; + EnvironmentRecord:=nil; + inherited Destroy; +end; + +procedure TBESENLexicalEnvironment.Finalize; +begin + Outer:=nil; + EnvironmentRecord:=nil; + inherited Finalize; +end; + +procedure TBESENLexicalEnvironment.Mark; +begin + TBESEN(Instance).GarbageCollector.GrayIt(Outer); + TBESEN(Instance).GarbageCollector.GrayIt(EnvironmentRecord); + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENLocale.pas b/3rd/besen/src/BESENLocale.pas new file mode 100644 index 000000000..7dbffbe2f --- /dev/null +++ b/3rd/besen/src/BESENLocale.pas @@ -0,0 +1,225 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENLocale; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,BESENConstants,BESENTypes,BESENBaseObject; + +const BESENDefaultFormatSettings:TFormatSettings=( +{$ifdef DelphiXEAndUp} + CurrencyString:'$'; + CurrencyFormat:1; + CurrencyDecimals:2; + DateSeparator:'-'; + TimeSeparator:':'; + ListSeparator:','; + ShortDateFormat:'d/m/y'; + LongDateFormat:'dd" "mmmm" "yyyy'; + TimeAMString:'AM'; + TimePMString:'PM'; + ShortTimeFormat:'hh:nn'; + LongTimeFormat:'hh:nn:ss'; + ShortMonthNames:('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + LongMonthNames:('January','February','March','April','May','June','July','August','September','October','November','December'); + ShortDayNames:('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); + LongDayNames:('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); + ThousandSeparator:','; + DecimalSeparator:'.'; + TwoDigitYearCenturyWindow:50; + NegCurrFormat:5; +{$else} + CurrencyFormat:1; + NegCurrFormat:5; + ThousandSeparator:','; + DecimalSeparator:'.'; + CurrencyDecimals:2; + DateSeparator:'-'; + TimeSeparator:':'; + ListSeparator:','; + CurrencyString:'$'; + ShortDateFormat:'d/m/y'; + LongDateFormat:'dd" "mmmm" "yyyy'; + TimeAMString:'AM'; + TimePMString:'PM'; + ShortTimeFormat:'hh:nn'; + LongTimeFormat:'hh:nn:ss'; + ShortMonthNames:('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + LongMonthNames:('January','February','March','April','May','June','July','August','September','October','November','December'); + ShortDayNames:('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); + LongDayNames:('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); + TwoDigitYearCenturyWindow:50; +{$endif} + ); + +var BESENLocaleFormatSettings:TFormatSettings; + +implementation + +uses BESENCharSet,BESENStringUtils; + +{$warnings off} +procedure InitLocaleFormatSettings; +{$ifdef windows} +{$ifdef fpc} +var i:integer; +begin + BESENLocaleCharset:=ISO_8859_1;//BESENGetCodePage('ISO-8859-1'); + BESENLocaleFormatSettings:=BESENDefaultFormatSettings; + for i:= 1 to 12 do begin + BESENLocaleFormatSettings.ShortMonthNames[i]:=SysUtils.ShortMonthNames[i]; + BESENLocaleFormatSettings.LongMonthNames[i]:=SysUtils.LongMonthNames[i]; + end; + for i:=1 to 7 do begin + BESENLocaleFormatSettings.ShortDayNames[i]:=SysUtils.ShortDayNames[i]; + BESENLocaleFormatSettings.LongDayNames[i]:=SysUtils.LongDayNames[i]; + end; + BESENLocaleFormatSettings.DateSeparator:=SysUtils.DateSeparator; + BESENLocaleFormatSettings.ShortDateFormat:=SysUtils.ShortDateFormat; + BESENLocaleFormatSettings.LongDateFormat:=SysUtils.LongDateFormat; + BESENLocaleFormatSettings.TimeSeparator:=SysUtils.TimeSeparator; + BESENLocaleFormatSettings.TimeAMString:=SysUtils.TimeAMString; + BESENLocaleFormatSettings.TimePMString:=SysUtils.TimePMString; + BESENLocaleFormatSettings.ShortTimeFormat:=SysUtils.ShortTimeFormat; + BESENLocaleFormatSettings.LongTimeFormat:=SysUtils.LongTimeFormat; + BESENLocaleFormatSettings.CurrencyString:=SysUtils.CurrencyString; + BESENLocaleFormatSettings.CurrencyFormat:=SysUtils.CurrencyFormat; + BESENLocaleFormatSettings.NegCurrFormat:=SysUtils.NegCurrFormat; + BESENLocaleFormatSettings.ThousandSeparator:=SysUtils.ThousandSeparator; + BESENLocaleFormatSettings.DecimalSeparator:=SysUtils.DecimalSeparator; + BESENLocaleFormatSettings.CurrencyDecimals:=SysUtils.CurrencyDecimals; + BESENLocaleFormatSettings.ListSeparator:=SysUtils.ListSeparator; +end; +{$else} +var HourFormat,TimePrefix,TimePostfix:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; + LID:LCID; + i,LCP,Day:integer; +begin + BESENLocaleFormatSettings:=BESENDefaultFormatSettings; + LID:=GetThreadLocale; + if not TryStrToInt(GetLocaleStr(LID,LOCALE_IDEFAULTANSICODEPAGE,inttostr(GetACP)),LCP) then begin + LCP:=GetACP; + end; +{$ifndef BESENSingleStringType} + if LCP>0 then begin + BESENLocaleCharset:=BESENGetCodePage('WINDOWS-'+inttostr(LCP)); + end else{$endif} begin + BESENLocaleCharset:=ISO_8859_1; + end; + for i:=1 to 12 do begin + BESENLocaleFormatSettings.ShortMonthNames[i]:=GetLocaleStr(LID,LOCALE_SABBREVMONTHNAME1+i-1,BESENDefaultFormatSettings.ShortMonthNames[i]); + BESENLocaleFormatSettings.LongMonthNames[i]:=GetLocaleStr(LID,LOCALE_SMONTHNAME1+i-1,BESENDefaultFormatSettings.LongMonthNames[i]); + end; + for i:=1 to 7 do begin + Day:=(i+5) mod 7; + BESENLocaleFormatSettings.ShortDayNames[i]:=GetLocaleStr(LID,LOCALE_SABBREVDAYNAME1+Day,BESENDefaultFormatSettings.ShortDayNames[i]); + BESENLocaleFormatSettings.LongDayNames[i]:=GetLocaleStr(LID,LOCALE_SDAYNAME1+Day,BESENDefaultFormatSettings.LongDayNames[i]); + end; + BESENLocaleFormatSettings.DateSeparator:=GetLocaleChar(LID,LOCALE_SDATE,'/'); + BESENLocaleFormatSettings.ShortDateFormat:=GetLocaleStr(LID,LOCALE_SSHORTDATE,'m/d/yy'); + BESENLocaleFormatSettings.LongDateFormat:=GetLocaleStr(LID,LOCALE_SLONGDATE,'mmmm d, yyyy'); + BESENLocaleFormatSettings.TimeSeparator:=GetLocaleChar(LID,LOCALE_STIME,':'); + BESENLocaleFormatSettings.TimeAMString:=GetLocaleStr(LID,LOCALE_S1159,'AM'); + BESENLocaleFormatSettings.TimePMString:=GetLocaleStr(LID,LOCALE_S2359,'PM'); + if StrToIntDef(GetLocaleStr(LID,LOCALE_ITLZERO,'0'),0)=0 then begin + HourFormat:='h'; + end else begin + HourFormat:='hh'; + end; + TimePostfix:=''; + TimePrefix:=''; + if StrToIntDef(GetLocaleStr(LID,LOCALE_ITIME,'0'),0)=0 then begin + if StrToIntDef(GetLocaleStr(LID,LOCALE_ITIMEMARKPOSN,'0'),0)=0 then begin + TimePostfix:=' AMPM'; + end else begin + TimePrefix:='AMPM '; + end; + end; + BESENLocaleFormatSettings.ShortTimeFormat:=TimePrefix+HourFormat+':nn'+TimePrefix; + BESENLocaleFormatSettings.LongTimeFormat:=TimePrefix+HourFormat+':nn:ss'+TimePrefix; + BESENLocaleFormatSettings.CurrencyString:=GetLocaleStr(LID,LOCALE_SCURRENCY,''); + BESENLocaleFormatSettings.CurrencyFormat:=StrToIntDef(GetLocaleStr(LID,LOCALE_ICURRENCY,'0'),0); + BESENLocaleFormatSettings.NegCurrFormat:=StrToIntDef(GetLocaleStr(LID,LOCALE_INEGCURR,'0'),0); + BESENLocaleFormatSettings.ThousandSeparator:=GetLocaleChar(LID,LOCALE_STHOUSAND,','); + BESENLocaleFormatSettings.DecimalSeparator:=GetLocaleChar(LID,LOCALE_SDECIMAL,'.'); + BESENLocaleFormatSettings.CurrencyDecimals:=StrToIntDef(GetLocaleStr(LID,LOCALE_ICURRDIGITS,'0'),0); + BESENLocaleFormatSettings.ListSeparator:=GetLocaleChar(LID,LOCALE_SLIST,','); +end; +{$endif} +{$else} +var i:integer; +begin + BESENLocaleCharset:=ISO_8859_1;//BESENGetCodePage('ISO-8859-1'); + BESENLocaleFormatSettings:=BESENDefaultFormatSettings; + for i:= 1 to 12 do begin + BESENLocaleFormatSettings.ShortMonthNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.ShortMonthNames[i]{$endif}; + BESENLocaleFormatSettings.LongMonthNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.LongMonthNames[i]{$endif}; + end; + for i:=1 to 7 do begin + BESENLocaleFormatSettings.ShortDayNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.ShortDayNames[i]{$endif}; + BESENLocaleFormatSettings.LongDayNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.LongDayNames[i]{$endif}; + end; + BESENLocaleFormatSettings.DateSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.DateSeparator{$else}SysUtils.DateSeparator{$endif}; + BESENLocaleFormatSettings.ShortDateFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortDateFormat{$else}SysUtils.ShortDateFormat{$endif}; + BESENLocaleFormatSettings.LongDateFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongDateFormat{$else}SysUtils.LongDateFormat{$endif}; + BESENLocaleFormatSettings.TimeSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimeSeparator{$else}SysUtils.TimeSeparator{$endif}; + BESENLocaleFormatSettings.TimeAMString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimeAMString{$else}SysUtils.TimeAMString{$endif}; + BESENLocaleFormatSettings.TimePMString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimePMString{$else}SysUtils.TimePMString{$endif}; + BESENLocaleFormatSettings.ShortTimeFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortTimeFormat{$else}SysUtils.ShortTimeFormat{$endif}; + BESENLocaleFormatSettings.LongTimeFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongTimeFormat{$else}SysUtils.LongTimeFormat{$endif}; + BESENLocaleFormatSettings.CurrencyString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyString{$else}SysUtils.CurrencyString{$endif}; + BESENLocaleFormatSettings.CurrencyFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyFormat{$else}SysUtils.CurrencyFormat{$endif}; + BESENLocaleFormatSettings.NegCurrFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.NegCurrFormat{$else}SysUtils.NegCurrFormat{$endif}; + BESENLocaleFormatSettings.ThousandSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ThousandSeparator{$else}SysUtils.ThousandSeparator{$endif}; + BESENLocaleFormatSettings.DecimalSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.DecimalSeparator{$else}SysUtils.DecimalSeparator{$endif}; + BESENLocaleFormatSettings.CurrencyDecimals:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyDecimals{$else}SysUtils.CurrencyDecimals{$endif}; + BESENLocaleFormatSettings.ListSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ListSeparator{$else}SysUtils.ListSeparator{$endif}; +end; +{$endif} +{$warnings on} + +procedure InitBESEN; +begin + InitLocaleFormatSettings; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; + +end. diff --git a/3rd/besen/src/BESENNativeCodeMemoryManager.pas b/3rd/besen/src/BESENNativeCodeMemoryManager.pas new file mode 100644 index 000000000..f23aa30b3 --- /dev/null +++ b/3rd/besen/src/BESENNativeCodeMemoryManager.pas @@ -0,0 +1,335 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENNativeCodeMemoryManager; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix,UnixType,{$endif} + SysUtils,Classes,BESENConstants,BESENTypes; + +type PBESENNativeCodeMemoryManagerBlock=^TBESENNativeCodeMemoryManagerBlock; + TBESENNativeCodeMemoryManagerBlock=packed record + Signature:ptruint; + Previous:PBESENNativeCodeMemoryManagerBlock; + Next:PBESENNativeCodeMemoryManagerBlock; + Size:ptruint; + end; + + PBESENNativeCodeMemoryManagerBlockContainer=^TBESENNativeCodeMemoryManagerBlockContainer; + TBESENNativeCodeMemoryManagerBlockContainer=record + Previous:PBESENNativeCodeMemoryManagerBlockContainer; + Next:PBESENNativeCodeMemoryManagerBlockContainer; + Base:pointer; + Size:ptruint; + Used:ptruint; + First:PBESENNativeCodeMemoryManagerBlock; + Last:PBESENNativeCodeMemoryManagerBlock; + end; + + TBESENNativeCodeMemoryManager=class + private + PageSize:ptruint; + Alignment:ptruint; + function AllocateBlockContainer(BlockContainerSize:ptruint):PBESENNativeCodeMemoryManagerBlockContainer; + procedure FreeBlockContainer(BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer); + public + First,Last:PBESENNativeCodeMemoryManagerBlockContainer; + constructor Create; + destructor Destroy; override; + function GetMemory(Size:ptruint):pointer; + procedure FreeMemory(p:pointer); + function ReallocMemory(p:pointer;Size:ptruint):pointer; + end; + +{$ifdef HasJIT} +{$ifdef unix} +var fpmprotect:function(__addr:pointer;__len:cardinal;__prot:longint):longint; cdecl;// external 'c' name 'mprotect'; +{$endif} +{$endif} + +implementation + +uses BESENUtils; + +const bncmmMemoryBlockSignature:ptruint={$ifdef cpu64}$1337bab3deadc0d3{$else}$deadc0d3{$endif}; + +constructor TBESENNativeCodeMemoryManager.Create; +{$ifdef windows} +var SystemInfo:TSystemInfo; +{$else} +{$ifdef unix} +{$endif} +{$endif} +begin + inherited Create; +{$ifdef windows} + GetSystemInfo(SystemInfo); + PageSize:=BESENRoundUpToPowerOfTwo(SystemInfo.dwPageSize); +{$else} +{$ifdef unix} + PageSize:=4096; +{$else} + PageSize:=4096; +{$endif} +{$endif} +{$ifdef cpu386} + Alignment:=16; +{$else} +{$ifdef cpuamd64} + Alignment:=16; +{$else} +{$ifdef cpuarm} + Alignment:=16; +{$else} + Alignment:=PageSize; +{$endif} +{$endif} +{$endif} + First:=nil; + Last:=nil; +end; + +destructor TBESENNativeCodeMemoryManager.Destroy; +begin + while assigned(First) do begin + FreeBlockContainer(First); + end; + inherited Destroy; +end; + +function TBESENNativeCodeMemoryManager.AllocateBlockContainer(BlockContainerSize:ptruint):PBESENNativeCodeMemoryManagerBlockContainer; +var Size:ptruint; + Block:PBESENNativeCodeMemoryManagerBlock; +begin + if BlockContainerSize>0 then begin + Size:=BESENRoundUpToMask(BlockContainerSize,PageSize); + New(result); +{$ifdef windows} + result^.Base:=VirtualAlloc(nil,Size,MEM_COMMIT,PAGE_EXECUTE_READWRITE); +{$else} +{$ifdef unix} + result^.Base:=fpmmap(nil,Size,PROT_READ or PROT_WRITE or PROT_EXEC,MAP_PRIVATE or MAP_ANONYMOUS,-1,0); +{$else} + GetMem(result^.Base,Size); +{$endif} +{$endif} + result^.Size:=Size; + result^.Used:=sizeof(TBESENNativeCodeMemoryManagerBlock)*2; + if assigned(Last) then begin + Last^.Next:=result; + result^.Previous:=Last; + Last:=result; + result^.Next:=nil; + end else begin + First:=result; + Last:=result; + result^.Previous:=nil; + result^.Next:=nil; + end; + FillChar(result^.Base^,result^.Size,#0); + result^.First:=result^.Base; + result^.Last:=pointer(@PBESENByteArray(result^.Base)[result^.Size-sizeof(TBESENNativeCodeMemoryManagerBlock)]); + Block:=result^.First; + Block^.Signature:=bncmmMemoryBlockSignature; + Block^.Previous:=nil; + Block^.Next:=result^.Last; + Block^.Size:=0; + Block:=result^.Last; + Block^.Signature:=bncmmMemoryBlockSignature; + Block^.Previous:=result^.First; + Block^.Next:=nil; + Block^.Size:=0; + end else begin + result:=nil; + end; +end; + +procedure TBESENNativeCodeMemoryManager.FreeBlockContainer(BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer); +begin + if assigned(BlockContainer^.Previous) then begin + BlockContainer^.Previous^.Next:=BlockContainer^.Next; + end else begin + First:=BlockContainer^.Next; + end; + if assigned(BlockContainer^.Next) then begin + BlockContainer^.Next^.Previous:=BlockContainer^.Previous; + end else begin + Last:=BlockContainer^.Previous; + end; +{$ifdef windows} + VirtualFree(BlockContainer^.Base,0,MEM_RELEASE); +{$else} +{$ifdef unix} + fpmunmap(BlockContainer^.Base,BlockContainer^.Size); +{$else} + FreeMem(BlockContainer^.Base); +{$endif} +{$endif} + Dispose(BlockContainer); +end; + +function TBESENNativeCodeMemoryManager.GetMemory(Size:ptruint):pointer; +var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; + CurrentBlock,NewBlock:PBESENNativeCodeMemoryManagerBlock; + DestSize,BlockContainerSize:ptruint; +begin + result:=nil; + if Size>0 then begin + DestSize:=Size+sizeof(TBESENNativeCodeMemoryManagerBlock); + BlockContainer:=First; + while true do begin + while assigned(BlockContainer) do begin + if (BlockContainer^.Used+DestSize)<=BlockContainer^.Size then begin + CurrentBlock:=BlockContainer^.First; + while assigned(CurrentBlock) and (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and assigned(CurrentBlock^.Next) do begin + NewBlock:=pointer(ptruint(BESENRoundUpToMask(ptruint(pointer(@PBESENByteArray(CurrentBlock)[(sizeof(TBESENNativeCodeMemoryManagerBlock)*2)+CurrentBlock^.Size])),Alignment)-sizeof(TBESENNativeCodeMemoryManagerBlock))); + if (ptruint(CurrentBlock^.Next)-ptruint(NewBlock))>=DestSize then begin + NewBlock^.Signature:=bncmmMemoryBlockSignature; + NewBlock^.Previous:=CurrentBlock; + NewBlock^.Next:=CurrentBlock^.Next; + NewBlock^.Size:=Size; + CurrentBlock^.Next^.Previous:=NewBlock; + CurrentBlock^.Next:=NewBlock; + result:=pointer(@PBESENByteArray(NewBlock)[sizeof(TBESENNativeCodeMemoryManagerBlock)]); + inc(BlockContainer^.Used,DestSize); + exit; + end else begin + CurrentBlock:=CurrentBlock^.Next; + end; + end; + end; + BlockContainer:=BlockContainer^.Next; + end; + if DestSize<=bncmmMINBLOCKCONTAINERSIZE then begin + BlockContainerSize:=bncmmMINBLOCKCONTAINERSIZE; + end else begin + BlockContainerSize:=BESENRoundUpToPowerOfTwo(DestSize); + end; + BlockContainer:=AllocateBlockContainer(BlockContainerSize); + if not assigned(BlockContainer) then begin + break; + end; + end; + end; +end; + +procedure TBESENNativeCodeMemoryManager.FreeMemory(p:pointer); +var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; + CurrentBlock:PBESENNativeCodeMemoryManagerBlock; +begin + BlockContainer:=First; + while assigned(BlockContainer) do begin + if ((ptruint(BlockContainer^.Base)+sizeof(TBESENNativeCodeMemoryManagerBlock))<=ptruint(p)) and ((ptruint(p)+sizeof(TBESENNativeCodeMemoryManagerBlock))<(ptruint(BlockContainer^.Base)+BlockContainer^.Size)) then begin + CurrentBlock:=pointer(ptruint(ptruint(p)-sizeof(TBESENNativeCodeMemoryManagerBlock))); + if (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and (CurrentBlock<>BlockContainer^.First) and (CurrentBlock<>BlockContainer^.Last) then begin + dec(BlockContainer^.Used,CurrentBlock^.Size+sizeof(TBESENNativeCodeMemoryManagerBlock)); + CurrentBlock^.Signature:=0; + CurrentBlock^.Previous^.Next:=CurrentBlock^.Next; + CurrentBlock^.Next^.Previous:=CurrentBlock^.Previous; + if (assigned(BlockContainer^.First) and (BlockContainer^.First^.Next=BlockContainer^.Last)) or not assigned(BlockContainer^.First) then begin + FreeBlockContainer(BlockContainer); + end; + exit; + end; + end; + BlockContainer:=BlockContainer^.Next; + end; +end; + +function TBESENNativeCodeMemoryManager.ReallocMemory(p:pointer;Size:ptruint):pointer; +var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; + CurrentBlock:PBESENNativeCodeMemoryManagerBlock; + DestSize:ptruint; +begin + result:=nil; + if assigned(p) then begin + if Size=0 then begin + FreeMemory(p); + end else begin + DestSize:=Size+sizeof(TBESENNativeCodeMemoryManagerBlock); + BlockContainer:=First; + while assigned(BlockContainer) do begin + if ((ptruint(BlockContainer^.Base)+sizeof(TBESENNativeCodeMemoryManagerBlock))<=ptruint(p)) and ((ptruint(p)+sizeof(TBESENNativeCodeMemoryManagerBlock))<(ptruint(BlockContainer^.Base)+BlockContainer^.Size)) then begin + CurrentBlock:=pointer(ptruint(ptruint(p)-sizeof(TBESENNativeCodeMemoryManagerBlock))); + if (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and (CurrentBlock<>BlockContainer^.First) and (CurrentBlock<>BlockContainer^.Last) then begin + if (ptruint(CurrentBlock^.Next)-ptruint(CurrentBlock))>=DestSize then begin + CurrentBlock^.Size:=Size; + result:=p; + exit; + end else begin + result:=GetMemory(Size); + if assigned(result) then begin + if CurrentBlock^.Size<Size then begin + Move(p^,result^,CurrentBlock^.Size); + end else begin + Move(p^,result^,Size); + end; + end; + FreeMemory(p); + exit; + end; + end; + end; + BlockContainer:=BlockContainer^.Next; + end; + end; + FreeMemory(p); + end else if Size<>0 then begin + result:=GetMemory(Size); + end; +end; + +procedure InitBESEN; +begin +{$ifdef HasJIT} +{$ifdef unix} +{$ifdef darwin} + fpmprotect:=dlsym(dlopen('libc.dylib',RTLD_NOW),'mprotect'); +{$else} + fpmprotect:=dlsym(dlopen('libc.so',RTLD_NOW),'mprotect'); +{$endif} + if not assigned(fpmprotect) then begin + raise Exception.Create('Importing of mprotect from libc.so failed!'); + end; +{$endif} +{$endif} +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENNativeObject.pas b/3rd/besen/src/BESENNativeObject.pas new file mode 100644 index 000000000..e888373a9 --- /dev/null +++ b/3rd/besen/src/BESENNativeObject.pas @@ -0,0 +1,612 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENNativeObject; +{$i BESEN.inc} + +interface + +uses TypInfo,Variants,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, + BESENEnvironmentRecord; + +type TBESENNativeObject=class(TBESENObjectFunction) + private + PropList:PPropList; + PropListLen:integer; + function GetProp(const Prop:TBESENObjectProperty;var V:TBESENValue;Throw:boolean):boolean; + function PutProp(const Prop:TBESENObjectProperty;const V:TBESENValue;Throw:boolean):boolean; + protected + procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); virtual; + procedure InitializeObject; virtual; + procedure FinalizeObject; virtual; + public + Initialized:TBESENBoolean; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; + procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; + function HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + + TBESENNativeObjectClass=class of TBESENNativeObject; + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.SysUtils,{$endif}BESEN,BESENErrors,BESENHashUtils,BESENStringUtils,BESENGarbageCollector; + +{$ifdef BESENEmbarcaderoNextGen} +function PByteToString(Src:pbyte):string; +var SrcLen,ResultLen:longint; + TempStr:MarshaledAString; + TempBuffer:array[0..255] of char; +begin + result:=''; + if not assigned(Src) then begin + SrcLen:=Src^; + if ShortStringLength>0 then begin + inc(Src); + TempStr:=MarshaledAString(Src); + ResultLen:=UTF8ToUnicode(TempBuffer,length(TempBuffer),TempStr,SrcKen); + SetString(Result,TempBuffer,ResultLen-1); + end; + end; +end; +{$endif} + +constructor TBESENNativeObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + Initialized:=false; + PropList:=nil; + PropListLen:=0; + ObjectClassName:=ClassName+'$Constructor'; +end; + +destructor TBESENNativeObject.Destroy; +begin + if Initialized then begin + FinalizeObject; + end; + if assigned(PropList) then begin + FreeMem(PropList); + PropList:=nil; + PropListLen:=0; + end; + inherited Destroy; +end; + +procedure TBESENNativeObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); +begin +end; + +procedure TBESENNativeObject.InitializeObject; +{$ifdef fpc} +type PShortString=^ShortString; +{$endif} +type PMethodNameRec=^TMethodNameRec; + TMethodNameRec=packed record +{$ifdef fpc} + Name:PShortString; + Address:pointer; +{$else} + Size:word; + Address:pointer; + Name:{$ifdef BESENEmbarcaderoNextGen}TSymbolName{$else}ShortString{$endif}; +{$endif} + end; + TMethodNameRecs=packed array[word] of TMethodNameRec; + PMethodNameTable=^TMethodNameTable; + TMethodNameTable=packed record + Count:{$ifdef fpc}longword{$else}word{$endif}; + Methods:TMethodNameRecs; + end; +var i:integer; + Prop:TBESENObjectProperty; + Item:PPropInfo; + MethodTable:PMethodNameTable; + MethodNameRec:PMethodNameRec; + MethodName:TBESENSTRING; + MethodAddress:pointer; + NativeFunction:TBESENNativeFunction; +begin + if not Initialized then begin + Initialized:=true; + + ObjectClassName:=ClassName+'$Instance'; + + try + MethodTable:=pointer(pointer(ptrint(ptrint(pointer(self)^)+vmtMethodTable))^); + if assigned(MethodTable) then begin + MethodNameRec:=@MethodTable^.Methods[0]; + for i:=0 to MethodTable^.Count-1 do begin +{$ifdef fpc} + MethodName:=MethodNameRec^.Name^; +{$else} +{$ifdef BESENEmbarcaderoNextGen} + MethodName:=PByteToString(@(MethodNameRec^.Name)); +{$else} + MethodName:=TBESENSTRING(MethodNameRec^.Name); +{$endif} +{$endif} + MethodAddress:=MethodNameRec^.Address; + if (length(MethodName)>0) and assigned(MethodAddress) then begin + TMethod(NativeFunction).Code:=MethodAddress; + TMethod(NativeFunction).Data:=self; + RegisterNativeFunction(MethodName,NativeFunction,0,[],false); + end; +{$ifdef fpc} + inc(MethodNameRec); +{$else} + inc(ptruint(MethodNameRec),MethodNameRec^.Size); +{$endif} + end; + end; + except + raise; + end; + + PropListLen:=GetPropList(self,PropList); + try + for i:=0 to PropListLen-1 do begin + Item:=PropList^[i]; + if assigned(Item^.PropType) then begin + case Item^.PropType^.Kind of + tkLString,tkWString{$ifdef fpc},tkAString{$endif},tkVariant{$ifdef fpc},tkUString{$endif}, + tkInteger,tkChar,tkFloat,tkEnumeration,tkWChar,tkSet{$ifdef fpc},tkSString{$endif}, + tkInt64{$ifdef fpc},tkQWORD{$endif},tkClass:begin +{$ifdef BESENEmbarcaderoNextGen} + if not assigned(Item^.GetProc) then begin + BESENThrowNotReadable(PByteToString(@(Item^.Name))); + end; + Prop:=Properties.Get(PByteToString(@(Item^.Name))); + if not assigned(Prop) then begin + Prop:=Properties.Put(PByteToString(@(Item^.Name))); + end; +{$else} + if not assigned(Item^.GetProc) then begin + BESENThrowNotReadable(TBESENString(Item^.Name)); + end; + Prop:=Properties.Get(TBESENString(Item^.Name)); + if not assigned(Prop) then begin + Prop:=Properties.Put(TBESENString(Item^.Name)); + end; +{$endif} + Prop.PropIndex:=i; + Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + if assigned(Item^.SetProc) then begin + Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE]; + end else begin + Prop.Descriptor.Attributes:=[bopaENUMERABLE]; + end; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + end; + end; + end; + end; + except + FreeMem(PropList); + PropList:=nil; + PropListLen:=0; + raise; + end; + + InvalidateStructure; + end; +end; + +procedure TBESENNativeObject.FinalizeObject; +begin + if Initialized then begin + Initialized:=false; + if assigned(PropList) then begin + FreeMem(PropList); + PropList:=nil; + PropListLen:=0; + end; + end; +end; + +function TBESENNativeObject.GetProp(const Prop:TBESENObjectProperty;var V:TBESENValue;Throw:boolean):boolean; +var Item:PPropInfo; + O:TObject; + Index:integer; +begin + result:=false; + if not Initialized then begin + exit; + end; + + Index:=Prop.PropIndex; + if (Index>=0) and (Index<PropListLen) then begin + Item:=PropList^[Index]; + end else begin + exit; + end; + + if not assigned(Item^.GetProc) then begin + if Throw then begin +{$ifdef BESENEmbarcaderoNextGen} + BESENThrowNotReadable(PByteToString(@(Item^.Name))); +{$else} + BESENThrowNotReadable(TBESENString(Item^.Name)); +{$endif} + end; + exit; + end; + + case Item^.PropType^.Kind of + tkLString{$ifdef fpc},tkAString,tkSString{$endif}:begin + V.ValueType:=bvtSTRING; +{$ifdef Delphi2009AndUp} + V.Str:=GetStrProp(self,Item); +{$else} + V.Str:=BESENConvertToUTF8(GetStrProp(self,Item)); +{$endif} + end; + tkWString{$ifdef fpc},tkUString{$endif}{$ifdef BESENEmbarcaderoNextGen},tkUString{$endif}:begin + V.ValueType:=bvtSTRING; + V.Str:={$ifdef BESENEmbarcaderoNextGen}GetStrProp{$else}GetWideStrProp{$endif}(self,Item); + end; + tkEnumeration:begin + V.ValueType:=bvtSTRING; + V.Str:=GetEnumProp(self,Item); + end; + tkSet:begin + V.ValueType:=bvtSTRING; + V.Str:=GetSetProp(self,Item,false); + end; + tkInteger:begin + V.ValueType:=bvtNUMBER; + V.Num:=GetOrdProp(self,Item); + end; + tkChar:begin + V.ValueType:=bvtSTRING; + V.Str:=WideChar({$ifndef BESENEmbarcaderoNextGen}TBESENCHAR({$endif}byte(GetOrdProp(self,Item)){$ifndef BESENEmbarcaderoNextGen}){$endif}); + end; + tkWChar:begin + V.ValueType:=bvtSTRING; + V.Str:=widechar(word(GetOrdProp(self,Item))); + end; + tkInt64{$ifdef fpc},tkQWORD{$endif}:begin + V.ValueType:=bvtNUMBER; + V.Num:=GetInt64Prop(self,Item); + end; + tkFloat:begin + V.ValueType:=bvtNUMBER; + V.Num:=GetFloatProp(self,Item); + end; + tkClass:begin + O:=GetObjectProp(self,Item); + if assigned(O) then begin + if O is TBESENObject then begin + V.ValueType:=bvtOBJECT; + TBESENObject(v.Obj):=TBESENObject(o); + end else begin + V.ValueType:=bvtUNDEFINED; + end; + end else begin + V.ValueType:=bvtNULL; + end; + end; + tkVariant:begin + BESENVariantToValue(GetVariantProp(self,Item),V); + end; + else begin + if Throw then begin + BESENThrowTypeError('Unknown native property data type'); + end; + exit; + end; + end; + + result:=true; +end; + +function TBESENNativeObject.PutProp(const Prop:TBESENObjectProperty;const V:TBESENValue;Throw:boolean):boolean; +var Item:PPropInfo; + Index:integer; +begin + result:=false; + if not Initialized then begin + exit; + end; + + Index:=Prop.PropIndex; + if (Index>=0) and (Index<PropListLen) then begin + Item:=PropList^[Index]; + end else begin + exit; + end; + + if not (assigned(Item^.SetProc) and ((boppWRITABLE in Prop.Descriptor.Presents) and (bopaWRITABLE in Prop.Descriptor.Attributes))) then begin + if Throw then begin +{$ifdef BESENEmbarcaderoNextGen} + BESENThrowNotWritable(PByteToString(@(Item^.Name))); +{$else} + BESENThrowNotWritable(TBESENString(Item^.Name)); +{$endif} + end; + exit; + end; + + case Item^.PropType^.Kind of + tkLString{$ifdef fpc},tkAString,tkSString{$endif}:begin +{$ifdef Delphi2009AndUp} + SetStrProp(self,Item,TBESEN(Instance).ToStr(V)); +{$else} + SetStrProp(self,Item,BESENUTF16ToUTF8(TBESEN(Instance).ToStr(V))); +{$endif} + end; + tkWString{$ifdef fpc},tkUString{$endif}{$ifdef BESENEmbarcaderoNextGen},tkUString{$endif}:begin + {$ifdef BESENEmbarcaderoNextGen}SetStrProp{$else}SetWideStrProp{$endif}(self,Item,TBESEN(Instance).ToStr(V)); + end; + tkEnumeration:begin + SetEnumProp(self,Item,TBESEN(Instance).ToStr(V)); + end; + tkSet:begin + SetSetProp(self,Item,TBESEN(Instance).ToStr(V)); + end; + tkInteger:begin + SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); + end; + tkChar:begin + if (V.ValueType=bvtSTRING) and (length(V.Str)>0) then begin + SetOrdProp(self,Item,byte(word(widechar(V.Str[1])))); + end else begin + SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); + end; + end; + tkWChar:begin + if (V.ValueType=bvtSTRING) and (length(V.Str)>0) then begin + SetOrdProp(self,Item,word(widechar(V.Str[1]))); + end else begin + SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); + end; + end; + tkInt64{$ifdef fpc},tkQWORD{$endif}:begin + SetInt64Prop(self,Item,TBESEN(Instance).ToInt(V)); + end; + tkFloat:begin + SetFloatProp(self,Item,TBESEN(Instance).ToNum(V)); + end; + tkClass:begin + SetObjectProp(self,Item,TBESEN(Instance).ToObj(V)); + end; + tkVariant:begin + SetVariantProp(self,Item,BESENValueToVariant(V)); + end; + else begin + if Throw then begin + BESENThrowTypeError('Wrong native property data type'); + end; + exit; + end; + end; + + result:=true; +end; + +function TBESENNativeObject.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + if GetProp(LastProp,Descriptor.Value,true) then begin + Descriptor.Getter:=LastProp.Descriptor.Getter; + Descriptor.Setter:=LastProp.Descriptor.Setter; + Descriptor.Attributes:=LastProp.Descriptor.Attributes; + Descriptor.Presents:=LastProp.Descriptor.Presents; + result:=true; + end else begin + result:=false; + end; + end else begin + result:=inherited GetOwnProperty(P,Descriptor); + end; +end; + +function TBESENNativeObject.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + result:=GetProp(LastProp,AResult,true); + end else begin + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + end; +end; + +function TBESENNativeObject.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + if (((Index>=0) and (Index<Properties.ItemCount)) and (Properties.Items[Index].ID=ID)) and (Properties.Items[Index].PropIndex>=0) then begin + result:=GetProp(Properties.Items[Index],AResult,true); + end else begin + result:=Get(TBESEN(Instance).KeyIDManager.List[ID],AResult,Base); + end; +end; + +procedure TBESENNativeObject.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + PutProp(LastProp,V,Throw); + end else begin + inherited PutEx(P,V,Throw,Descriptor,OwnDescriptor,TempValue,Hash); + end; +end; + +procedure TBESENNativeObject.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); +begin + if (((Index>=0) and (Index<Properties.ItemCount)) and (Properties.Items[Index].ID=ID)) and (Properties.Items[Index].PropIndex>=0) then begin + PutProp(Properties.Items[Index],V,Throw); + end else begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end; +end; + +function TBESENNativeObject.HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + result:=true; + end else begin + result:=inherited HasPropertyEx(P,Descriptor,Hash); + end; +end; + +function TBESENNativeObject.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; + procedure BESENThrowIt; + begin + BESENThrowTypeError('Delete for "'+P+'" failed'); + end; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + result:=false; + if Throw then begin + BESENThrowIt; + end; + end else begin + result:=DeleteEx(P,Throw,Descriptor,Hash); + end; +end; + +function TBESENNativeObject.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + if (boppVALUE in Descriptor.Presents) and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)) then begin + PutProp(LastProp,Descriptor.Value,Throw); + result:=true; + end else begin + if Throw then begin + BESENThrowDefineOwnProperty(P); + end; + result:=false; + end; + end else begin + result:=inherited DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); + end; +end; + +procedure TBESENNativeObject.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENNativeObjectClass(ClassType).Create(Instance,self,false); + TBESEN(Instance).GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObject(AResult.Obj).GarbageCollectorLock; + try + TBESENNativeObject(AResult.Obj).ObjectClassName:=AResult.Obj.ClassName; + TBESENNativeObject(AResult.Obj).InitializeObject; + TBESENNativeObject(AResult.Obj).ConstructObject(ThisArgument,Arguments,CountArguments); + finally + TBESENObject(AResult.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENNativeObject.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + BESENThrowTypeError('Not a function'); +end; + +function TBESENNativeObject.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENNativeObject.HasCall:TBESENBoolean; +begin + result:=false; +end; + +procedure TBESENNativeObject.Finalize; +var i:integer; + o:TObject; + Item:PPropInfo; +begin + if assigned(PropList) then begin + for i:=0 to PropListLen-1 do begin + Item:=PropList^[i]; + if assigned(Item^.PropType) then begin + case Item^.PropType^.Kind of + tkCLASS:begin + if assigned(Item^.SetProc) then begin + o:=GetObjectProp(self,Item); + if o is TBESENGarbageCollectorObject then begin + SetObjectProp(self,Item,nil); + end; + end; + end; + end; + end; + end; + end; + inherited Finalize; +end; + +procedure TBESENNativeObject.Mark; +var i:integer; + o:TObject; +begin + if assigned(PropList) then begin + for i:=0 to PropListLen-1 do begin + if assigned(PropList^[i].PropType) then begin + case PropList^[i].PropType^.Kind of + tkCLASS:begin + o:=GetObjectProp(self,PropList^[i]); + if o is TBESENGarbageCollectorObject then begin + TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(o)); + end; + end; + end; + end; + end; + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENNumberUtils.pas b/3rd/besen/src/BESENNumberUtils.pas new file mode 100644 index 000000000..2aa91ea3d --- /dev/null +++ b/3rd/besen/src/BESENNumberUtils.pas @@ -0,0 +1,4419 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENNumberUtils; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENDoubleBytes=^TBESENDoubleBytes; + TBESENDoubleBytes=array[0..sizeof(double)-1] of byte; + + TBESENNumberCodeFlagLookupTable=array[word,boolean] of byte; + + PBESENNumberCodeAbstractRelationalLookupTableItem=^TBESENNumberCodeAbstractRelationalLookupTableItem; + TBESENNumberCodeAbstractRelationalLookupTableItem=packed record + IsNotUndefined:bytebool; + ResultBooleanValue:bytebool; + DoCompare:bytebool; + Spacer:bytebool; + end; + + TBESENNumberCodeAbstractRelationalLookupTable=array[byte] of TBESENNumberCodeAbstractRelationalLookupTableItem; + +const BESEN_ROUND_TO_NEAREST=0; + BESEN_ROUND_TOWARD_ZERO=1; + BESEN_ROUND_UPWARD=2; + BESEN_ROUND_DOWNWARD=3; + + BESEN_CHECKNUMBERSTRING_FAIL=-1; + BESEN_CHECKNUMBERSTRING_EMPTY=0; + BESEN_CHECKNUMBERSTRING_VALID=1; + BESEN_CHECKNUMBERSTRING_INFNEG=2; + BESEN_CHECKNUMBERSTRING_INFPOS=3; + BESEN_CHECKNUMBERSTRING_NAN=4; + + BESEN_DOUBLETOSTRINGMODE_STANDARD=0; + BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL=1; + BESEN_DOUBLETOSTRINGMODE_FIXED=2; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL=3; + BESEN_DOUBLETOSTRINGMODE_PRECISION=4; + BESEN_DOUBLETOSTRINGMODE_RADIX=5; + +{$ifdef BIG_ENDIAN} + BESENDoubleNaN:TBESENDoubleBytes=($7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff); + BESENDoubleInfPos:TBESENDoubleBytes=($7f,$f0,$00,$00,$00,$00,$00,$00); + BESENDoubleInfNeg:TBESENDoubleBytes=($ff,$f0,$00,$00,$00,$00,$00,$00); + BESENDoubleMax:TBESENDoubleBytes=($7f,$ef,$ff,$ff,$ff,$ff,$ff,$ff); + BESENDoubleMin:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$00,$01); +{$else} + BESENDoubleNaN:TBESENDoubleBytes=($ff,$ff,$ff,$ff,$ff,$ff,$ff,$7f); + BESENDoubleInfPos:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$f0,$7f); + BESENDoubleInfNeg:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$f0,$ff); + BESENDoubleMax:TBESENDoubleBytes=($ff,$ff,$ff,$ff,$ff,$ff,$ef,$7f); + BESENDoubleMin:TBESENDoubleBytes=($01,$00,$00,$00,$00,$00,$00,$00); +{$endif} + BESENDoubleZero:TBESENNumber=0.0; + BESENDoubleOne:TBESENNumber=1.0; + + BESENNumZero:TBESENNumber=0; + BESENNumOne:TBESENNumber=1; + +var BESENNumberCodeFlagLookupTable:TBESENNumberCodeFlagLookupTable; + BESENNumberCodeAbstractRelationalLookupTable:TBESENNumberCodeAbstractRelationalLookupTable; + +function BESENNumberCodeFlags(const AValue:TBESENNumber):byte; {$ifdef caninline}inline;{$endif} + +function BESENIntLog2(x:longword):longword; {$ifdef cpu386}assembler; register;{$endif} + +function BESENToInt(v:TBESENNumber):TBESENINT64; +function BESENToInt32(v:TBESENNumber):TBESENINT32; +function BESENToUInt32(v:TBESENNumber):TBESENUINT32; +function BESENToInt16(v:TBESENNumber):TBESENINT32; +function BESENToUInt16(v:TBESENNumber):TBESENUINT32; + +function BESENToIntFast(v:PBESENNumber):TBESENINT64; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToInt32Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToUInt32Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToInt16Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToUInt16Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} + +function BESENFloatToStr(const Value:TBESENNumber):TBESENString; +function BESENFloatToLocaleStr(const Value:TBESENNumber):TBESENString; + +function BESENSameValue(const A,B:TBESENNumber):boolean; +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENNumberAbsolute(const AValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +function BESENIsSameValue(const a,b:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENFloor(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +function BESENCeil(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} + +function BESENStringToDoubleExact(const StringValue:TBESENString;RoundingMode:longint=BESEN_ROUND_TO_NEAREST;Base:longint=-1;OK:pointer=nil):double; +function BESENStringToDoubleFast(const StringValue:TBESENString;RoundingMode:integer=BESEN_ROUND_TO_NEAREST):double; +function BESENStringToDouble(const StringValue:TBESENString):double; + +function BESENStringToNumber(const StringValue:TBESENString;EmptyIsValid:TBESENBoolean=true;AcceptHex:TBESENBoolean=false;OnlyNumber:boolean=false;AcceptHexSign:boolean=true):TBESENNumber; + +function BESENStringToNumberBase(const StringValue:TBESENString;Base:longint):TBESENNumber; + +function BESENDoubleToString(const AValue:double;Mode,RequestedDigits:longint):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; + +function BESENNumberToString(const Value:TBESENNumber):TBESENString; + +function BESENNumberToRadixString(const Value:TBESENNumber;Radix:longint):TBESENString; + +function BESENCheckNumberString(const StringValue:TBESENString;var StartPosition,EndPosition:integer;IsParseFloat,AcceptHex,OnlyNumber,AcceptHexSign:boolean):integer; + +function BESENModulo(x,y:double):double;{$ifdef cpu386}stdcall; assembler;{$endif} +function BESENModuloPos(x,y:double):double; + +implementation + +uses BESENLocale; + +procedure InitBESENNumberTables; +var i:word; + j:boolean; + c,ca,cb:byte; + Item:PBESENNumberCodeAbstractRelationalLookupTableItem; +begin + for i:=low(TBESENNumberCodeFlagLookupTable) to high(TBESENNumberCodeFlagLookupTable) do begin + for j:=low(boolean) to high(boolean) do begin + c:=0; + if j then begin + if (i and $7ff0)=$7ff0 then begin + c:=c or bncfNAN; + end; + end else begin + if (i and $7ff0)=$7ff0 then begin + if (i and $000f)<>0 then begin + c:=c or bncfNAN; + end else begin + c:=c or bncfINFINITE; + end; + end else if (i and $7fff)=0 then begin + c:=c or bncfZERO; + end; + end; + if (i and $8000)<>0 then begin + c:=c or bncfNEGATIVE; + end; + BESENNumberCodeFlagLookupTable[i,j]:=c; + end; + end; + for c:=low(byte) to high(byte) do begin + Item:=@BESENNumberCodeAbstractRelationalLookupTable[c]; + ca:=c shr 4; + cb:=c and $f; + Item^.Spacer:=false; + if ((ca or cb) and bncfNAN)<>0 then begin + Item^.IsNotUndefined:=false; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (((ca and cb) and bncfZERO)<>0) and (((ca xor cb) and bncfNEGATIVE)<>0) then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (ca and (bncfINFINITE or bncfNEGATIVE))=bncfINFINITE then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (cb and (bncfINFINITE or bncfNEGATIVE))=bncfINFINITE then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=true; + Item^.DoCompare:=false; + end else if (cb and (bncfINFINITE or bncfNEGATIVE))=(bncfINFINITE or bncfNEGATIVE) then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (ca and (bncfINFINITE or bncfNEGATIVE))=(bncfINFINITE or bncfNEGATIVE) then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=true; + Item^.DoCompare:=false; + end else begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=true; + end; + end; +end; + +function BESENNumberCodeFlags(const AValue:TBESENNumber):byte; {$ifdef caninline}inline;{$endif} +{$ifdef fpc} +var HighPart:longword; +begin + HighPart:=qword(pointer(@AValue)^) shr 32; + result:=BESENNumberCodeFlagLookupTable[HighPart shr 16,((HighPart and $ffff) or longword(qword(pointer(@AValue)^) and $ffffffff))<>0]; +end; +{$else} +{$ifdef cpu386} +asm + mov ecx,dword ptr [AValue+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [AValue] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] +end; +{$else} +var HighPart:longword; +begin + HighPart:=int64(pointer(@AValue)^) shr 32; + result:=BESENNumberCodeFlagLookupTable[HighPart shr 16,((HighPart and $ffff) or longword(int64(pointer(@AValue)^) and $ffffffff))<>0]; +end; +{$endif} +{$endif} + +function BESENStringToDoubleExact(const StringValue:TBESENString;RoundingMode:longint=BESEN_ROUND_TO_NEAREST;Base:longint=-1;OK:pointer=nil):double; +type PDoubleCasted=^TDoubleCasted; + TDoubleCasted=packed record + case byte of + 0:(Value:double); + 1:({$ifdef BIG_ENDIAN}Hi,Lo{$else}Lo,Hi{$endif}:longword); + 2:(Value64:int64); + end; +const MantissaWords=12; //6; // 12 + MantissaDigits=52; //28; // 52 + WordTopBit=$8000; + WordBits=16; + WordBitShift=4; + WordBitMask=WordBits-1; + WordMask=$ffff; + IEEEFormatBytes=8; + IEEEFormatBits=IEEEFormatBytes shl 3; + IEEEFormatExplicit=0; + IEEEFormatExponent=11; + IEEEFormatOneMask=WordTopBit shr ((IEEEFormatExponent+IEEEFormatExplicit) and WordBitMask); + IEEEFormatOnePos=(IEEEFormatExponent+IEEEFormatExplicit) shr WordBitShift; + IEEEFormatExpMax=1 shl (IEEEFormatExponent-1); + Bit53=int64(int64(1) shl 53); + MaximumMultiplier=longword(longword($ffffffff) div 36); +{$ifndef BESENNoFPU} + DtoAFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; + DtoAFPUPrecisionMode:TFPUPrecisionMode=pmDOUBLE; + DtoAFPURoundingMode:TFPURoundingMode=rmNEAREST; +{$endif} +type PWords=^TWords; + TWords=array[0..MantissaWords] of word; + PTemp=^TTemp; + TTemp=array[0..MantissaWords*2] of longword; + PDigits=^TDigits; + TDigits=array[0..MantissaDigits] of byte; +var MantissaPosition,Exponent,TenPower,TwoPower,ExtraTwos,Shift,i,p,q,r,Digit,Overflow,OverflowBits,DroppedBits,DroppedBitsMask,MiddleValue:longint; + Bit,Carry:word; + Negative,ExponentNegative,HasDigits,Started,ZeroTail,Done:boolean; + ResultCasted:PDoubleCasted; + Temp:PTemp; + Digits:PDigits; + MantissaMultiplicator,Mantissa:PWords; + Value:int64; + c:widechar; + Part,Multiplier,NextMultiplier:longword; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPUPrecisionMode:TFPUPrecisionMode; + OldFPURoundingMode:TFPURoundingMode; +{$endif} + function MantissaMultiply(vTo,vFrom:PWords):longint; + var i,j,k:longint; + v:longword; + t:PTemp; + begin + t:=Temp; + FillChar(t^,sizeof(TTemp),#0); + for i:=0 to MantissaWords-1 do begin + for j:=0 to MantissaWords-1 do begin + v:=longword(vTo^[i]+0)*longword(vFrom^[j]+0); + k:=i+j; + inc(t^[k],v shr WordBits); + inc(t^[k+1],v and WordMask); + end; + end; + for i:=high(TTemp) downto 1 do begin + inc(t^[i-1],t^[i] shr WordBits); + t^[i]:=t^[i] and WordMask; + end; + if (t^[0] and WordTopBit)<>0 then begin + for i:=0 to MantissaWords-1 do begin + vTo^[i]:=t^[i] and WordMask; + end; + result:=0; + end else begin + for i:=0 to MantissaWords-1 do begin + vTo^[i]:=(t^[i] shl 1)+word(ord((t^[i+1] and WordTopBit)<>0)); + end; + result:=-1; + end; + end; + procedure MantissaShiftRight(var Mantissa:TWords;Shift:longint); + var Bits,Words,InvBits,Position:longint; + Carry,Current:longword; + begin + Bits:=Shift and WordBitMask; + Words:=Shift shr WordBitShift; + InvBits:=WordBits-Bits; + Position:=high(TWords); + if Bits=0 then begin + if Words<>0 then begin + while Position>=Words do begin + Mantissa[Position]:=Mantissa[Position-Words]; + dec(Position); + end; + end; + end else begin + if (high(TWords)-Words)>=0 then begin + Carry:=Mantissa[high(TWords)-Words] shr Bits; + end else begin + Carry:=0; + end; + while Position>Words do begin + Current:=Mantissa[Position-(Words+1)]; + Mantissa[Position]:=(Current shl InvBits) or Carry; + Carry:=Current shr Bits; + dec(Position); + end; + Mantissa[Position]:=Carry; + dec(Position); + end; + while Position>=0 do begin + Mantissa[Position]:=0; + dec(Position); + end; + end; + procedure MantissaSetBit(var Mantissa:TWords;i:longint); + begin + Mantissa[i shr WordBitShift]:=Mantissa[i shr WordBitShift] or (WordTopBit shr (i and WordBitMask)); + end; + function MantissaTestBit(var Mantissa:TWords;i:longint):boolean; + begin + result:=(Mantissa[i shr WordBitShift] shr ((not i) and WordBitMask))<>0; + end; + function MantissaIsZero(var Mantissa:TWords):boolean; + var i:longint; + begin + result:=true; + for i:=low(TWords) to High(TWords) do begin + if Mantissa[i]<>0 then begin + result:=false; + break; + end; + end; + end; + function MantissaRound(Negative:boolean;var Mantissa:TWords;BitPos:longint):boolean; + var i,p:longint; + Bit:longword; + function RoundAbsDown:boolean; + var j:longint; + begin + Mantissa[i]:=Mantissa[i] and not (Bit-1); + for j:=i+1 to high(TWords) do begin + Mantissa[j]:=0; + end; + result:=false; + end; + function RoundAbsUp:boolean; + var j:longint; + begin + Mantissa[i]:=(Mantissa[i] and not (Bit-1))+Bit; + for j:=i+1 to high(TWords) do begin + Mantissa[j]:=0; + end; + while (i>0) and (Mantissa[i]=0) do begin + dec(i); + inc(Mantissa[i]); + end; + result:=Mantissa[0]=0; + end; + function RoundTowardsInfinity:boolean; + var j:longint; + m:longword; + begin + m:=Mantissa[i] and ((Bit shl 1)-1); + for j:=i+1 to high(TWords) do begin + m:=m or Mantissa[j]; + end; + if m<>0 then begin + result:=RoundAbsUp; + end else begin + result:=RoundAbsDown; + end; + end; + function RoundNear:boolean; + var j:longint; + m:longword; + begin + if (Mantissa[i] and Bit)<>0 then begin + Mantissa[i]:=Mantissa[i] and not Bit; + m:=Mantissa[i] and ((Bit shl 1)-1); + for j:=i+1 to high(TWords) do begin + m:=m or Mantissa[j]; + end; + Mantissa[i]:=Mantissa[i] or Bit; + if m<>0 then begin + result:=RoundAbsUp; + end else begin + if MantissaTestBit(Mantissa,BitPos-1) then begin + result:=RoundAbsUp; + end else begin + result:=RoundAbsDown; + end; + end; + end else begin + result:=RoundAbsDown; + end; + end; + begin + i:=BitPos shr WordBitShift; + p:=BitPos and WordBitMask; + Bit:=WordTopBit shr p; + case RoundingMode of + BESEN_ROUND_TO_NEAREST:begin + result:=RoundNear; + end; + BESEN_ROUND_TOWARD_ZERO:begin + result:=RoundAbsDown; + end; + BESEN_ROUND_UPWARD:begin + if Negative then begin + result:=RoundAbsDown; + end else begin + result:=RoundTowardsInfinity; + end; + end; + BESEN_ROUND_DOWNWARD:begin + if Negative then begin + result:=RoundTowardsInfinity; + end else begin + result:=RoundAbsDown; + end; + end; + else begin + result:=false; + end; + end; + end; + function CountLeadingZeros32(a:longword):longint; + const CountLeadingZerosHigh:array[byte] of byte=(8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + begin + result:=0; + if a<$10000 then begin + inc(result,16); + a:=a shl 16; + end; + if a<$1000000 then begin + inc(result,8); + a:=a shl 8; + end; + inc(result,CountLeadingZerosHigh[a shr 24]); + end; + function CountLeadingZeros64(a:int64):longint; + begin + if a<int64($100000000) then begin + result:=32; + end else begin + result:=0; + a:=a shr 32; + end; + inc(result,CountLeadingZeros32(a)); + end; +begin + if assigned(OK) then begin + longbool(OK^):=false; + end; + ResultCasted:=pointer(@result); + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + i:=1; + p:=i; + while (i<=length(StringValue)) and BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i]))) do begin + inc(i); + end; + if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin + Negative:=StringValue[i]='-'; + inc(i); + end else begin + Negative:=false; + end; + HasDigits:=false; + if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin + if Negative then begin + ResultCasted^.Hi:=$fff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end else if (Base in [2,4,8,16,32]) or ((not (Base in [2..36])) and ((((i+1)<=length(StringValue)) and ((StringValue[i]='0') and ((StringValue[i+1]='b') or (StringValue[i+1]='o') or (StringValue[i+1]='x')))))) then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + case Base of + 2:begin + Shift:=1; + end; + 4:begin + Shift:=2; + end; + 8:begin + Shift:=3; + end; + 16:begin + Shift:=4; + end; + 32:begin + Shift:=5; + end; + else begin + inc(i); + case StringValue[i] of + 'b':begin + Shift:=1; + end; + 'o':begin + Shift:=3; + end; + else {'x':}begin + Shift:=4; + end; + end; + inc(i); + end; + end; + TwoPower:=1 shl Shift; + Value:=0; + Exponent:=0; + while (i<=length(StringValue)) and (StringValue[i]='0') do begin + HasDigits:=true; + inc(i); + end; + if i<=length(StringValue) then begin + q:=0; + Digit:=0; + while i<=length(StringValue) do begin + c:=StringValue[i]; + if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+TwoPower)) then begin + Digit:=ord(c)-ord('0'); + end else if (TwoPower>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('a'))+10; + end else if (TwoPower>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('A'))+10; + end else begin + break; + end; + inc(i); + HasDigits:=true; + Value:=(Value shl Shift) or Digit; + Overflow:=longint(int64(Value shr 53)); + if Overflow<>0 then begin + OverflowBits:=1; + while Overflow>1 do begin + inc(OverflowBits); + Overflow:=Overflow shr 1; + end; + DroppedBitsMask:=(1 shl OverflowBits)-1; + DroppedBits:=Value and DroppedBitsMask; + Value:=Value shr OverflowBits; + Exponent:=OverflowBits; + ZeroTail:=true; + while i<=length(StringValue) do begin + c:=StringValue[i]; + if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+TwoPower)) then begin + Digit:=ord(c)-ord('0'); + end else if (TwoPower>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('a'))+10; + end else if (TwoPower>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('A'))+10; + end else begin + break; + end; + inc(i); + if Digit<>0 then begin + ZeroTail:=false; + end; + inc(Exponent,Shift); + end; + MiddleValue:=1 shl (OverflowBits-1); + if DroppedBits>MiddleValue then begin + inc(Value); + end else if DroppedBits=MiddleValue then begin + if ((Value and 1)<>0) or not ZeroTail then begin + inc(Value); + end; + end; + while (Value and Bit53)<>0 do begin + Value:=Value shr 1; + inc(Exponent); + end; + break; + end; + end; + if (Exponent<IEEEFormatExponent) and (Value<Bit53) then begin + Shift:=CountLeadingZeros64(Value)-11; + if Shift>=0 then begin + Value:=Value shl Shift; + end else begin + Value:=Value shr (-Shift); + end; + ResultCasted^.Value64:=((int64($432-(Shift-Exponent)) shl 52)+Value) and int64($7fffffffffffffff); + end else begin + New(Mantissa); + try + FillChar(Mantissa^,sizeof(TWords),#0); + Shift:=CountLeadingZeros64(Value); + Value:=Value shl Shift; + inc(Exponent,64-Shift); + Mantissa^[0]:=(Value shr 48) and $ffff; + Mantissa^[1]:=(Value shr 32) and $ffff; + Mantissa^[2]:=(Value shr 16) and $ffff; + Mantissa^[3]:=(Value shr 0) and $ffff; + if (Mantissa^[0] and WordTopBit)<>0 then begin + dec(Exponent); + if (Exponent>=(2-IEEEFormatExpMax)) and (Exponent<=IEEEFormatExpMax) then begin + inc(Exponent,IEEEFormatExpMax-1); + MantissaShiftRight(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if MantissaTestBit(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit-1) then begin + MantissaShiftRight(Mantissa^,1); + inc(Exponent); + end; + if Exponent>=(IEEEFormatExpMax shl 1)-1 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end else if Exponent>0 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + Shift:=IEEEFormatExplicit-(Exponent+(IEEEFormatExpMax-(2+IEEEFormatExponent))); + MantissaShiftRight(Mantissa^,Shift); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if (Mantissa^[IEEEFormatOnePos] and IEEEFormatOneMask)<>0 then begin + Exponent:=1; + if IEEEFormatExplicit=0 then begin + Mantissa^[IEEEFormatOnePos]:=Mantissa^[IEEEFormatOnePos] and not IEEEFormatOneMask; + end; + Mantissa^[0]:=Mantissa^[0] or (Exponent shl (WordBitMask-IEEEFormatExponent)); + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end else begin + if MantissaIsZero(Mantissa^) then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(Mantissa^[0] shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end; + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + finally + Dispose(Mantissa); + end; + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if HasDigits then begin + if assigned(OK) then begin + longbool(OK^):=true; + end; + end; + end else if Base in [2..36] then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + while (i<=length(StringValue)) and (StringValue[i]='0') do begin + HasDigits:=true; + inc(i); + end; + if i<=length(StringValue) then begin +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPUPrecisionMode:=GetPrecisionMode; + OldFPURoundingMode:=GetRoundMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(DtoAFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(DtoAFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(DtoAFPURoundingMode); + end; +{$endif} + Part:=0; + Multiplier:=1; + Digit:=0; + Done:=false; + while not Done do begin + while true do begin + c:=StringValue[i]; + if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+Base)) then begin + Digit:=ord(c)-ord('0'); + end else if (Base>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+Base)-10))) then begin + Digit:=(ord(c)-ord('a'))+10; + end else if (Base>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+Base)-10))) then begin + Digit:=(ord(c)-ord('A'))+10; + end else begin + Done:=true; + break; + end; + HasDigits:=true; + NextMultiplier:=Multiplier*longword(Base); + if NextMultiplier>MaximumMultiplier then begin + break; + end; + Part:=(Part*longword(Base))+longword(Digit); + Multiplier:=NextMultiplier; + Assert(Multiplier>Part); + inc(i); + if i>length(StringValue) then begin + Done:=true; + break; + end; + end; + ResultCasted^.Value:=(ResultCasted^.Value*Multiplier)+Part; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(OldFPURoundingMode); + end; +{$endif} + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if HasDigits then begin + if assigned(OK) then begin + longbool(OK^):=true; + end; + end; + end else begin + HasDigits:=false; + Value:=0; + q:=i; + while i<=length(StringValue) do begin + c:=StringValue[i]; + if (c>='0') and (c<='9') then begin + HasDigits:=true; + Value:=(Value*10)+(ord(c)-ord('0')); + if (Value shr 53)<>0 then begin + HasDigits:=false; + break; + end; + end else begin + HasDigits:=false; + break; + end; + inc(i); + end; + if HasDigits then begin + if Value=0 then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end else begin + Shift:=CountLeadingZeros64(Value)-11; + if Shift>=0 then begin + Value:=Value shl Shift; + end else begin + Value:=Value shr (-Shift); + end; + ResultCasted^.Value64:=((int64($432-Shift) shl 52)+Value) and int64($7fffffffffffffff); + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end else begin + i:=q; + New(MantissaMultiplicator); + New(Mantissa); + New(Temp); + New(Digits); + try + FillChar(Digits^,sizeof(TDigits),#0); + + p:=0; + TenPower:=0; + HasDigits:=false; + Started:=false; + ExponentNegative:=false; + Exponent:=0; + while i<=length(StringValue) do begin + case StringValue[i] of + '0':begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + while i<=length(StringValue) do begin + case StringValue[i] of + '0'..'9':begin + HasDigits:=true; + Started:=true; + if p<=high(TDigits) then begin + Digits^[p]:=ord(StringValue[i])-ord('0'); + inc(p); + end; + inc(TenPower); + inc(i); + end; + else begin + break; + end; + end; + end; + if (i<=length(StringValue)) and (StringValue[i]='.') then begin + inc(i); + if not Started then begin + while i<=length(StringValue) do begin + case StringValue[i] of + '0':begin + HasDigits:=true; + dec(TenPower); + inc(i); + end; + else begin + break; + end; + end; + end; + end; + while i<=length(StringValue) do begin + case StringValue[i] of + '0'..'9':begin + HasDigits:=true; + if p<=high(TDigits) then begin + Digits^[p]:=ord(StringValue[i])-ord('0'); + inc(p); + end; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin + inc(i); + if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin + ExponentNegative:=StringValue[i]='-'; + inc(i); + end; + HasDigits:=false; + while i<=length(StringValue) do begin + case StringValue[i] of + '0'..'9':begin + Exponent:=(Exponent*10)+longint(ord(StringValue[i])-ord('0')); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + if ExponentNegative then begin + dec(TenPower,Exponent); + end else begin + inc(TenPower,Exponent); + end; + + FillChar(Mantissa^,sizeof(TWords),#0); + + Bit:=WordTopBit; + q:=0; + Started:=false; + TwoPower:=0; + MantissaPosition:=0; + while MantissaPosition<MantissaWords do begin + Carry:=0; + while (p>q) and (Digits^[p-1]=0) do begin + dec(p); + end; + if p<=q then begin + break; + end; + r:=p; + while r>q do begin + dec(r); + i:=(2*Digits^[r])+Carry; + if i>=10 then begin + dec(i,10); + Carry:=1; + end else begin + Carry:=0; + end; + Digits^[r]:=i; + end; + if Carry<>0 then begin + Mantissa^[MantissaPosition]:=Mantissa^[MantissaPosition] or Bit; + Started:=true; + end; + if Started then begin + if Bit=1 then begin + Bit:=WordTopBit; + inc(MantissaPosition); + end else begin + Bit:=Bit shr 1; + end; + end else begin + dec(TwoPower); + end; + end; + inc(TwoPower,TenPower); + + if TenPower<0 then begin + for i:=0 to high(TWords)-1 do begin + MantissaMultiplicator^[i]:=$cccc; + end; + MantissaMultiplicator^[high(TWords)]:=$cccd; + ExtraTwos:=-2; + TenPower:=-TenPower; + end else if TenPower>0 then begin + MantissaMultiplicator^[0]:=$a000; + for i:=1 to high(TWords) do begin + MantissaMultiplicator^[i]:=$0000; + end; + ExtraTwos:=3; + end else begin + ExtraTwos:=0; + end; + while TenPower<>0 do begin + if (TenPower and 1)<>0 then begin + inc(TwoPower,ExtraTwos+MantissaMultiply(Mantissa,MantissaMultiplicator)); + end; + inc(ExtraTwos,ExtraTwos+MantissaMultiply(MantissaMultiplicator,MantissaMultiplicator)); + TenPower:=TenPower shr 1; + end; + + Exponent:=TwoPower; + if (Mantissa^[0] and WordTopBit)<>0 then begin + dec(Exponent); + + if (Exponent>=(2-IEEEFormatExpMax)) and (Exponent<=IEEEFormatExpMax) then begin + inc(Exponent,IEEEFormatExpMax-1); + MantissaShiftRight(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if MantissaTestBit(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit-1) then begin + MantissaShiftRight(Mantissa^,1); + inc(Exponent); + end; + if Exponent>=(IEEEFormatExpMax shl 1)-1 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end else if Exponent>0 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + Shift:=IEEEFormatExplicit-(Exponent+(IEEEFormatExpMax-(2+IEEEFormatExponent))); + MantissaShiftRight(Mantissa^,Shift); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if (Mantissa^[IEEEFormatOnePos] and IEEEFormatOneMask)<>0 then begin + Exponent:=1; + if IEEEFormatExplicit=0 then begin + Mantissa^[IEEEFormatOnePos]:=Mantissa^[IEEEFormatOnePos] and not IEEEFormatOneMask; + end; + Mantissa^[0]:=Mantissa^[0] or (Exponent shl (WordBitMask-IEEEFormatExponent)); + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end else begin + if MantissaIsZero(Mantissa^) then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(Mantissa^[0] shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end; + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end; + end; + finally + Dispose(MantissaMultiplicator); + Dispose(Mantissa); + Dispose(Temp); + Dispose(Digits); + end; + end; + end; +end; + +function BESENConvertMantissaExponentToDouble(Mantissa:int64;MantissaSize,FractionalDigits,FractionalExponent,Exponent,ExponentSign:integer):double; {$ifdef caninline}inline;{$endif} +const MaxExponentOfTen=308; + MaxExponentOfTenMinusTwo=MaxExponentOfTen-2; + PowersOfTen:array[0..8] of TBESENParsingNumberType=(1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256); +var FloatValue,ExponentFactor:TBESENParsingNumberType; + MantissaExponent,PartExponent,Index:integer; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(rmNearest); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + + FloatValue:=Mantissa; + + MantissaExponent:=FractionalDigits+FractionalExponent; + if MantissaSize>18 then begin + dec(MantissaExponent,MantissaSize-18); + end; + + if ExponentSign>0 then begin + dec(Exponent,MantissaExponent); + end else begin + inc(Exponent,MantissaExponent); + end; + if Exponent<0 then begin + ExponentSign:=-ExponentSign; + Exponent:=-Exponent; + end; + + while Exponent>0 do begin + PartExponent:=Exponent; + if PartExponent>MaxExponentOfTenMinusTwo then begin + PartExponent:=MaxExponentOfTenMinusTwo; + end; + dec(Exponent,PartExponent); + + Index:=0; + ExponentFactor:=1; + while (PartExponent<>0) and (Index<length(PowersOfTen)) do begin + if (PartExponent and 1)<>0 then begin + ExponentFactor:=ExponentFactor*PowersOfTen[Index]; + end; + inc(Index); + PartExponent:=PartExponent shr 1; + end; + + if ExponentSign>0 then begin + FloatValue:=FloatValue*ExponentFactor; + end else begin + FloatValue:=FloatValue/ExponentFactor; + end; + end; + result:=FloatValue; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + end; +end; + +function BESENStringToDoubleFast(const StringValue:TBESENString;RoundingMode:integer=BESEN_ROUND_TO_NEAREST):double; +type PDoubleCasted=^TDoubleCasted; + TDoubleCasted=packed record + case byte of + 0:(Value:double); + 1:({$ifdef BIG_ENDIAN}Hi,Lo{$else}Lo,Hi{$endif}:longword); + end; +const MaxExponentOfTen=308; + MaxExponentOfTenMinusTwo=MaxExponentOfTen-2; + PowersOfTen:array[0..8] of double=(1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256); +var i:integer; + Negative,HasDigits:boolean; + Mantissa:int64; + MantissaSize,FractionalDigits,FractionalExponent,ExponentSign,Exponent:integer; + ResultCasted:PDoubleCasted; + FloatValue,ExponentFactor:double; + MantissaExponent,PartExponent,Index:integer; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode,NewFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin + ResultCasted:=pointer(@result); + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + i:=1; + while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin + inc(i); + end; + if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin + Negative:=StringValue[i]='-'; + inc(i); + end else begin + Negative:=false; + end; + if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin + if Negative then begin + ResultCasted^.Hi:=$fff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end; + end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + end else begin + FractionalDigits:=0; + FractionalExponent:=0; + MantissaSize:=0; + Mantissa:=0; + HasDigits:=false; + ExponentSign:=1; + Exponent:=0; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + if MantissaSize<18 then begin + Mantissa:=(Mantissa*10)+(word(widechar(StringValue[i]))-ord('0')); + end; + inc(MantissaSize); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if (i<=length(StringValue)) and (StringValue[i]='.') then begin + inc(i); + if (MantissaSize=0) and (Mantissa=0) then begin + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0'):begin + inc(FractionalExponent); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + if MantissaSize<18 then begin + Mantissa:=(Mantissa*10)+(word(widechar(StringValue[i]))-ord('0')); + inc(MantissaSize); + inc(FractionalDigits); + end; + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin + inc(i); + if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin + if StringValue[i]='-' then begin + ExponentSign:=-1; + end; + inc(i); + end; + HasDigits:=false; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + Exponent:=(Exponent*10)+integer(word(widechar(StringValue[i]))-ord('0')); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + +{$ifndef BESENNoFPU} + case RoundingMode of + BESEN_ROUND_TO_NEAREST:begin + NewFPURoundingMode:=rmNearest; + end; + BESEN_ROUND_TOWARD_ZERO:begin + NewFPURoundingMode:=rmTruncate; + end; + BESEN_ROUND_UPWARD:begin + NewFPURoundingMode:=rmUp; + end; + BESEN_ROUND_DOWNWARD:begin + NewFPURoundingMode:=rmDown; + end; + else begin + NewFPURoundingMode:=rmNearest; + end; + end; + + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>NewFPURoundingMode then begin + SetRoundMode(NewFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + + FloatValue:=Mantissa; + + MantissaExponent:=FractionalDigits+FractionalExponent; + if MantissaSize>18 then begin + dec(MantissaExponent,MantissaSize-18); + end; + + if ExponentSign>0 then begin + dec(Exponent,MantissaExponent); + end else begin + inc(Exponent,MantissaExponent); + end; + if Exponent<0 then begin + ExponentSign:=-ExponentSign; + Exponent:=-Exponent; + end; + + while Exponent>0 do begin + PartExponent:=Exponent; + if PartExponent>MaxExponentOfTenMinusTwo then begin + PartExponent:=MaxExponentOfTenMinusTwo; + end; + dec(Exponent,PartExponent); + + Index:=0; + ExponentFactor:=1; + while (PartExponent<>0) and (Index<length(PowersOfTen)) do begin + if (PartExponent and 1)<>0 then begin + ExponentFactor:=ExponentFactor*PowersOfTen[Index]; + end; + inc(Index); + PartExponent:=PartExponent shr 1; + end; + + if ExponentSign>0 then begin + FloatValue:=FloatValue*ExponentFactor; + end else begin + FloatValue:=FloatValue/ExponentFactor; + end; + end; + + ResultCasted^.Value:=FloatValue; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>NewFPURoundingMode then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + end; + end; + end; + end; +end; + +function BESENStringToDouble(const StringValue:TBESENString):double; +var OK:longbool; +begin + OK:=false; + result:=BESENStringToDoubleExact(StringValue,BESEN_ROUND_TO_NEAREST,-1,@OK); + if not OK Then begin + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENCheckNumberString(const StringValue:TBESENString;var StartPosition,EndPosition:integer;IsParseFloat,AcceptHex,OnlyNumber,AcceptHexSign:boolean):integer; +var i,OldPosition:integer; + Negative,HasDigits,HasSign:boolean; +begin + result:=BESEN_CHECKNUMBERSTRING_FAIL; + i:=1; + while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin + inc(i); + end; + StartPosition:=i; + EndPosition:=i; + if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin + Negative:=StringValue[i]='-'; + HasSign:=true; + inc(i); + end else begin + Negative:=false; + HasSign:=false; + end; + if i>length(StringValue) then begin + result:=BESEN_CHECKNUMBERSTRING_EMPTY; + end else if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin + EndPosition:=i+7; + if Negative then begin + result:=BESEN_CHECKNUMBERSTRING_INFNEG; + end else begin + result:=BESEN_CHECKNUMBERSTRING_INFPOS; + end; + end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin + EndPosition:=i+2; + result:=BESEN_CHECKNUMBERSTRING_NAN; + end else begin + HasDigits:=false; + if (i<=length(StringValue)) and (StringValue[i]='0') then begin + inc(i); + HasDigits:=true; + if (i<=length(StringValue)) and ((StringValue[i]='x') or (StringValue[i]='X')) then begin + inc(i); + HasDigits:=false; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'),ord('a')..ord('f'),ord('A')..ord('F'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if HasDigits then begin + EndPosition:=i-1; + if AcceptHex and (AcceptHexSign or not HasSign) then begin + result:=BESEN_CHECKNUMBERSTRING_VALID; + end else begin + result:=BESEN_CHECKNUMBERSTRING_FAIL; + end; + end; + exit; + end; + end; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if (i<=length(StringValue)) and (StringValue[i]='.') then begin + inc(i); + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + OldPosition:=i; + if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin + inc(i); + if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin + inc(i); + end; + HasDigits:=false; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if IsParseFloat and not HasDigits then begin + i:=OldPosition; + HasDigits:=true; + end; + end; + if HasDigits then begin + EndPosition:=i-1; + if OnlyNumber then begin + while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin + inc(i); + end; + if i>length(StringValue) then begin + result:=BESEN_CHECKNUMBERSTRING_VALID; + end else begin + result:=BESEN_CHECKNUMBERSTRING_FAIL; + end; + end else begin + result:=BESEN_CHECKNUMBERSTRING_VALID; + end; + end; + end; + end; +end; + +function BESENStringToNumber(const StringValue:TBESENString;EmptyIsValid:TBESENBoolean=true;AcceptHex:TBESENBoolean=false;OnlyNumber:boolean=false;AcceptHexSign:boolean=true):TBESENNumber; +var StartPosition,EndPosition:integer; +begin + case BESENCheckNumberString(StringValue,StartPosition,EndPosition,false,AcceptHex,OnlyNumber,AcceptHexSign) of + BESEN_CHECKNUMBERSTRING_EMPTY:begin + if EmptyIsValid then begin + result:=0; + end else begin + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; + end; + BESEN_CHECKNUMBERSTRING_VALID:begin + result:=BESENStringToDouble(copy(StringValue,StartPosition,(EndPosition-StartPosition)+1)); + end; + BESEN_CHECKNUMBERSTRING_INFNEG:begin + result:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end; + BESEN_CHECKNUMBERSTRING_INFPOS:begin + result:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end; + else begin + // CHECKNUMBERSTRING_FAIL,CHECKNUMBERSTRING_NAN + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; + end; +end; + +function BESENStringToNumberBase(const StringValue:TBESENString;Base:longint):TBESENNumber; +var OK:longbool; +begin + case Base of + 10:begin + result:=BESENStringToDouble(StringValue); + end; + else begin + OK:=false; + result:=BESENStringToDoubleExact(StringValue,BESEN_ROUND_TO_NEAREST,Base,@OK); + if not OK Then begin + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; + end; + end; +end; + +function BESENSameValue(const A,B:TBESENNumber):boolean; + function min(a,b:TBESENNumber):TBESENNumber; + begin + if a<b then begin + result:=a; + end else begin + result:=b; + end; + end; + function max(a,b:TBESENNumber):TBESENNumber; + begin + if a>b then begin + result:=a; + end else begin + result:=b; + end; + end; +const FuzzFactor=1000; + DoubleResolution=1E-15*FuzzFactor; +var Epsilon:TBESENNumber; +begin + if int64(pointer(@A)^)=int64(pointer(@B)^) then begin + result:=true; + end else begin + Epsilon:=max(min(abs(A),abs(B))*DoubleResolution,DoubleResolution); + if A>B then begin + result:=(A-B)<=Epsilon; + end else begin + result:=(B-A)<=Epsilon; + end; + end; +end; + +function BESENSameNumber(const A,B:TBESENNumber):boolean; + function min(a,b:TBESENNumber):TBESENNumber; + begin + if a<b then begin + result:=a; + end else begin + result:=b; + end; + end; + function max(a,b:TBESENNumber):TBESENNumber; + begin + if a>b then begin + result:=a; + end else begin + result:=b; + end; + end; +const FuzzFactor=1000; + DoubleResolution=1E-15*FuzzFactor; +var Epsilon:TBESENNumber; +begin + if int64(pointer(@A)^)=int64(pointer(@B)^) then begin + result:=true; + end else if BESENIsNaN(A) and BESENIsNaN(B) then begin + result:=true; + end else if (abs(A)=0) and (abs(B)=0) then begin + result:=(int64(pointer(@A)^) shr 63)=(int64(pointer(@B)^) shr 63); + end else begin + Epsilon:=max(min(abs(A),abs(B))*DoubleResolution,DoubleResolution); + if A>B then begin + result:=(A-B)<=Epsilon; + end else begin + result:=(B-A)<=Epsilon; + end; + end; +end; + +function BESENFloor(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +begin + result:=System.int(FloatValue); + if System.frac(FloatValue)<0 then begin + result:=result-1; + end; +end; + +function BESENCeil(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +begin + result:=System.int(FloatValue); + if System.frac(FloatValue)>0 then begin + result:=result+1; + end; +end; + +function BESENToInt(v:TBESENNumber):TBESENINT64; +begin + result:=trunc(v); +end; + +function BESENToInt32(v:TBESENNumber):TBESENINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),4294967296.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+4294967296.0; + end; + if v>=2147483648.0 then begin + v:=v-4294967296.0; + end; + end; + result:=trunc(v); +end; + +function BESENToUInt32(v:TBESENNumber):TBESENUINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),4294967296.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+4294967296.0; + end; + end; + result:=trunc(v); +end; + +function BESENToInt16(v:TBESENNumber):TBESENINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),65536.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+65536.0; + end; + if v>=32768.0 then begin + v:=v-65536.0; + end; + end; + result:=trunc(v); +end; + +function BESENToUInt16(v:TBESENNumber):TBESENUINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),65536.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+65536.0; + end; + end; + result:=trunc(v); +end; + +function BESENToIntFast(v:PBESENNumber):TBESENINT64; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + result:=trunc(v^); +end; + +function BESENToInt32Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=2147483648.0) and (v^<2147483648.0)) then begin + result:=BESENToInt32(v^); + end else begin + result:=trunc(v^); + end; +end; + +function BESENToUInt32Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=0.0) and (v^<4294967296.0)) then begin + result:=BESENToUInt32(v^); + end else begin + result:=int64(trunc(v^)); + end; +end; + +function BESENToInt16Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=-32768.0) and (v^<32768.0)) then begin + result:=BESENToInt16(v^); + end else begin + result:=trunc(v^); + end; +end; + +function BESENToUInt16Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=0.0) and (v^<65536.0)) then begin + result:=BESENToUInt16(v^); + end else begin + result:=trunc(v^); + end; +end; + +function BESENIntLog2(x:longword):longword; {$ifdef cpu386}assembler; register; +asm + test eax,eax + jz @Done + bsr eax,eax + @Done: +end; +{$else} +begin + x:=x or (x shr 1); + x:=x or (x shr 2); + x:=x or (x shr 4); + x:=x or (x shr 8); + x:=x or (x shr 16); + x:=x shr 1; + x:=x-((x shr 1) and $55555555); + x:=((x shr 2) and $33333333)+(x and $33333333); + x:=((x shr 4)+x) and $0f0f0f0f; + x:=x+(x shr 8); + x:=x+(x shr 16); + result:=x and $3f; +end; +{$endif} + +{$ifdef cpu64} +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENINT64(@AValue)^ and $7ff0000000000000)=$7ff0000000000000) and ((PBESENINT64(@AValue)^ and $000fffffffffffff)<>$0000000000000000); +end; + +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENINT64(@AValue)^ and $7fffffffffffffff)=$7ff0000000000000; +end; + +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENINT64(@AValue)^ and $7ff0000000000000)<>$7ff0000000000000; +end; + +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=PBESENINT64(@AValue)^=int64($7ff0000000000000); +end; + +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=qword(pointer(@AValue)^)=qword($fff0000000000000); +{$else} + result:=PBESENINT64(@AValue)^=int64($fff0000000000000); +{$endif} +end; + +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=PBESENINT64(@AValue)^=int64($0000000000000000); +end; + +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=qword(pointer(@AValue)^)=qword($8000000000000000); +{$else} + result:=PBESENINT64(@AValue)^=int64($8000000000000000); +{$endif} +end; + +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=(qword(pointer(@AValue)^) and qword($7fffffffffffffff))=qword($0000000000000000); +{$else} + result:=(PBESENINT64(@AValue)^ and int64($7fffffffffffffff))=int64($0000000000000000); +{$endif} +end; + +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=(qword(pointer(@AValue)^) and qword($8000000000000000))<>0; +{$else} + result:=(PBESENINT64(@AValue)^ shr 63)<>0; +{$endif} +end; +{$else} +{$ifdef TrickyNumberChecks} +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var l:longword; +begin + l:=PBESENDoubleHiLo(@AValue)^.Lo; + result:=(longword($7ff00000-longword(longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or ((l or (-l)) shr 31))) shr 31)<>0; +end; + +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=longword((longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(longword((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff)-$7ff00000) shr 31)<>0; +end; + +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(((longword(h and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(h shr 31))=0; +end; + +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(((longword(h and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(longword(not h) shr 31))=0; +end; + +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(longword(longword(h and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(h shr 31))=0; +end; + +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(longword(longword(h and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(longword(not h) shr 31))=0; +end; + +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=longword(longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=longword(PBESENDoubleHiLo(@AValue)^.Hi and longword($80000000))<>0; +end; +{$else} +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7ff00000)=$7ff00000) and (((PBESENDoubleHiLo(@AValue)^.Hi and $000fffff) or PBESENDoubleHiLo(@AValue)^.Lo)<>0); +end; + +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff)=$7ff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi and $7ff00000)<>$7ff00000; +end; + +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi=$7ff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi=$fff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi=$80000000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi and $80000000)<>0; +end; +{$endif} +{$endif} + +function BESENNumberAbsolute(const AValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +begin +{$ifdef cpu64} + PBESENINT64(@result)^:=PBESENINT64(@AValue)^ and $7fffffffffffffff; +{$else} + PBESENDoubleHiLo(@result)^.Hi:=PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff; + PBESENDoubleHiLo(@result)^.Lo:=PBESENDoubleHiLo(@AValue)^.Lo; +{$endif} +end; + +function BESENIsSameValue(const a,b:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=qword(pointer(@a)^)=qword(pointer(@b)^); +{$else} + result:=PBESENINT64(@a)^=PBESENINT64(@b)^; +{$endif} +end; + +function BESENModulo(x,y:double):double;{$ifdef cpu386}stdcall; assembler; +asm + fld qword ptr y + fld qword ptr x + @Repeat: + fprem + fstsw ax + sahf + jp @Repeat + fstp st(1) +end; +{$else} +begin + result:=x-(BESENFloor(x/y)*y); +end; +{$endif} + +function BESENModuloPos(x,y:double):double; +begin + result:=BESENModulo(x,y); + if BESENIsNegative(result) then begin + result:=result+y; + end; +end; + +const BESENDoubleToStringPowerOfTenTable:array[0..86,0..2] of int64=((int64($fa8fd5a0081c0288),-1220,-348), + (int64($baaee17fa23ebf76),-1193,-340), + (int64($8b16fb203055ac76),-1166,-332), + (int64($cf42894a5dce35ea),-1140,-324), + (int64($9a6bb0aa55653b2d),-1113,-316), + (int64($e61acf033d1a45df),-1087,-308), + (int64($ab70fe17c79ac6ca),-1060,-300), + (int64($ff77b1fcbebcdc4f),-1034,-292), + (int64($be5691ef416bd60c),-1007,-284), + (int64($8dd01fad907ffc3c),-980,-276), + (int64($d3515c2831559a83),-954,-268), + (int64($9d71ac8fada6c9b5),-927,-260), + (int64($ea9c227723ee8bcb),-901,-252), + (int64($aecc49914078536d),-874,-244), + (int64($823c12795db6ce57),-847,-236), + (int64($c21094364dfb5637),-821,-228), + (int64($9096ea6f3848984f),-794,-220), + (int64($d77485cb25823ac7),-768,-212), + (int64($a086cfcd97bf97f4),-741,-204), + (int64($ef340a98172aace5),-715,-196), + (int64($b23867fb2a35b28e),-688,-188), + (int64($84c8d4dfd2c63f3b),-661,-180), + (int64($c5dd44271ad3cdba),-635,-172), + (int64($936b9fcebb25c996),-608,-164), + (int64($dbac6c247d62a584),-582,-156), + (int64($a3ab66580d5fdaf6),-555,-148), + (int64($f3e2f893dec3f126),-529,-140), + (int64($b5b5ada8aaff80b8),-502,-132), + (int64($87625f056c7c4a8b),-475,-124), + (int64($c9bcff6034c13053),-449,-116), + (int64($964e858c91ba2655),-422,-108), + (int64($dff9772470297ebd),-396,-100), + (int64($a6dfbd9fb8e5b88f),-369,-92), + (int64($f8a95fcf88747d94),-343,-84), + (int64($b94470938fa89bcf),-316,-76), + (int64($8a08f0f8bf0f156b),-289,-68), + (int64($cdb02555653131b6),-263,-60), + (int64($993fe2c6d07b7fac),-236,-52), + (int64($e45c10c42a2b3b06),-210,-44), + (int64($aa242499697392d3),-183,-36), + (int64($fd87b5f28300ca0e),-157,-28), + (int64($bce5086492111aeb),-130,-20), + (int64($8cbccc096f5088cc),-103,-12), + (int64($d1b71758e219652c),-77,-4), + (int64($9c40000000000000),-50,4), + (int64($e8d4a51000000000),-24,12), + (int64($ad78ebc5ac620000),3,20), + (int64($813f3978f8940984),30,28), + (int64($c097ce7bc90715b3),56,36), + (int64($8f7e32ce7bea5c70),83,44), + (int64($d5d238a4abe98068),109,52), + (int64($9f4f2726179a2245),136,60), + (int64($ed63a231d4c4fb27),162,68), + (int64($b0de65388cc8ada8),189,76), + (int64($83c7088e1aab65db),216,84), + (int64($c45d1df942711d9a),242,92), + (int64($924d692ca61be758),269,100), + (int64($da01ee641a708dea),295,108), + (int64($a26da3999aef774a),322,116), + (int64($f209787bb47d6b85),348,124), + (int64($b454e4a179dd1877),375,132), + (int64($865b86925b9bc5c2),402,140), + (int64($c83553c5c8965d3d),428,148), + (int64($952ab45cfa97a0b3),455,156), + (int64($de469fbd99a05fe3),481,164), + (int64($a59bc234db398c25),508,172), + (int64($f6c69a72a3989f5c),534,180), + (int64($b7dcbf5354e9bece),561,188), + (int64($88fcf317f22241e2),588,196), + (int64($cc20ce9bd35c78a5),614,204), + (int64($98165af37b2153df),641,212), + (int64($e2a0b5dc971f303a),667,220), + (int64($a8d9d1535ce3b396),694,228), + (int64($fb9b7cd9a4a7443c),720,236), + (int64($bb764c4ca7a44410),747,244), + (int64($8bab8eefb6409c1a),774,252), + (int64($d01fef10a657842c),800,260), + (int64($9b10a4e5e9913129),827,268), + (int64($e7109bfba19c0c9d),853,276), + (int64($ac2820d9623bf429),880,284), + (int64($80444b5e7aa7cf85),907,292), + (int64($bf21e44003acdd2d),933,300), + (int64($8e679c2f5e44ff8f),960,308), + (int64($d433179d9c8cb841),986,316), + (int64($9e19db92b4e31ba9),1013,324), + (int64($eb96bf6ebadf77d9),1039,332), + (int64($af87023b9bf0ee6b),1066,340)); + + BESENDoubleToStringPowerOfTenBinaryExponentTable:array[-1220..(1066+27)-1] of byte=(0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24, + 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25, + 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, + 25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26, + 26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27, + 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,31, + 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, + 31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33, + 33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,34, + 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, + 34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35, + 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, + 35,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,40,40, + 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, + 40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41, + 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, + 41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,45,45,45,45,45,45,45,46,46,46, + 46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, + 46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47, + 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, + 47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48, + 48,48,48,48,48,48,48,48,48,48,48,48,48,49,49,49, + 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, + 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51, + 51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53, + 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, + 53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56, + 56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, + 56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,58,58,58,58, + 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58, + 58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59, + 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, + 59,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, + 60,60,60,60,60,60,60,60,60,60,60,60,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62, + 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, + 62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,68, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 68,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 69,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70, + 70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, + 70,70,70,70,70,70,71,71,71,71,71,71,71,71,71,71, + 71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,73,73,73,73,73, + 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, + 73,73,73,73,73,74,74,74,74,74,74,74,74,74,74,74, + 74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, + 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, + 75,75,75,75,75,75,75,75,75,75,75,76,76,76,76,76, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, + 76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, + 78,78,78,78,78,78,78,78,78,78,79,79,79,79,79,79, + 79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, + 79,79,79,79,79,80,80,80,80,80,80,80,80,80,80,80, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, + 81,81,81,81,81,81,81,81,81,81,82,82,82,82,82,82, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 82,82,82,82,82,83,83,83,83,83,83,83,83,83,83,83, + 83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,86,86,86,86,86,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86,86); + + BESENDoubleToStringPowerOfTenDecimalExponentTable:array[-348..(340+8)-1] of byte=(0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2, + 2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4, + 4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6, + 6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8, + 8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10, + 10,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12, + 12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14, + 14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16, + 16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18, + 18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20, + 20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22, + 22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24, + 24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26, + 26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28, + 28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30, + 30,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32, + 32,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34, + 34,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36, + 36,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38, + 38,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40, + 40,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42, + 42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44, + 44,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46, + 46,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48, + 48,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50, + 50,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52, + 52,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54, + 54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56, + 56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58, + 58,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60, + 60,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62, + 62,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64, + 64,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66, + 66,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68, + 68,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70, + 70,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72, + 72,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74, + 74,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76, + 76,77,77,77,77,77,77,77,77,78,78,78,78,78,78,78, + 78,79,79,79,79,79,79,79,79,80,80,80,80,80,80,80, + 80,81,81,81,81,81,81,81,81,82,82,82,82,82,82,82, + 82,83,83,83,83,83,83,83,83,84,84,84,84,84,84,84, + 84,85,85,85,85,85,85,85,85,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86); + + BESENDoubleToStringEstimatePowerFactorTable:array[2..36] of int64=(4294967296, // round((ln(2)/ln(Radix))*4294967296.0); + 2709822658, + 2147483648, + 1849741732, + 1661520155, + 1529898219, + 1431655765, + 1354911329, + 1292913986, + 1241523975, + 1198050829, + 1160664035, + 1128071163, + 1099331346, + 1073741824, + 1050766077, + 1029986701, + 1011073584, + 993761859, + 977836272, + 963119891, + 949465783, + 936750801, + 924870866, + 913737342, + 903274219, + 893415894, + 884105413, + 875293062, + 866935226, + 858993459, + 851433729, + 844225782, + 837342623, + 830760078); + +function BESENDoubleToString(const AValue:double;Mode,RequestedDigits:longint):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; +{$ifndef fpc} +type qword=int64; +{$endif} +const SignificantMantissaSize=64; + MinimalTargetExponent=-60; + MaximalTargetExponent=-32; + mSHORTEST=0; + mFIXED=1; + mPRECISION=2; + BigNumMaxSignificantMantissaBits=3584; + BigitChunkSize=32; + BigitDoubleChunkSize=64; + BigitSize=28; + BigitMask=(1 shl BigitSize)-1; + BigNumCapacity=(BigNumMaxSignificantMantissaBits+(BigitSize-1)) div BigitSize; +{$ifdef BESENSingleStringType} + DigitChars:array[0..9] of char=('0','1','2','3','4','5','6','7','8','9'); +{$endif} +type TDoubleValue=record + SignificantMantissa:qword; + Exponent:longint; + end; + TBigNumChunk=longword; + TBigNumDoubleChunk=qword; + TBigNum=record + Bigits:array[0..BigNumCapacity] of TBigNumChunk; + UsedDigits:longint; + Exponent:longint; + end; + function QWordLessOrEqual(a,b:qword):boolean; + begin + result:=(a=b) or (((a shr 32)<(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)<(b and $ffffffff)))); + end; + function QWordGreaterOrEqual(a,b:qword):boolean; + begin + result:=(a=b) or (((a shr 32)>(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)>(b and $ffffffff)))); + end; + function QWordLess(a,b:qword):boolean; + begin + result:=((a shr 32)<(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)<(b and $ffffffff))); + end; + function QWordGreater(a,b:qword):boolean; + begin + result:=((a shr 32)>(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)>(b and $ffffffff))); + end; + function DoubleValue(SignificantMantissa:qword=0;Exponent:longint=0):TDoubleValue; + begin + result.SignificantMantissa:=SignificantMantissa; + result.Exponent:=Exponent; + end; + procedure SplitDouble(Value:double;var SignificantMantissa:qword;var Exponent:longint); + var Casted:qword absolute Value; + begin + SignificantMantissa:=Casted and qword($000fffffffffffff); + if (Casted and qword($7ff0000000000000))<>0 then begin + inc(SignificantMantissa,qword($0010000000000000)); + Exponent:=((Casted and qword($7ff0000000000000)) shr 52)-($3ff+52); + end else begin + Exponent:=(-($3ff+52))+1; + end; + end; + function DoubleValueGet(Value:double):TDoubleValue; + var SignificantMantissa:qword; + Exponent:longint; + begin + Assert(Value>0); + SplitDouble(Value,SignificantMantissa,Exponent); + while (SignificantMantissa and qword($0010000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + SignificantMantissa:=SignificantMantissa shl (SignificantMantissaSize-53); + dec(Exponent,SignificantMantissaSize-53); + result.SignificantMantissa:=SignificantMantissa; + result.Exponent:=Exponent; + end; + procedure DoubleValueSubtract(var Left:TDoubleValue;const Right:TDoubleValue); + begin + Assert(Left.Exponent=Right.Exponent); + Assert(QWordGreaterOrEqual(Left.SignificantMantissa,Right.SignificantMantissa)); + dec(Left.SignificantMantissa,Right.SignificantMantissa); + end; + function DoubleValueMinus(const Left,Right:TDoubleValue):TDoubleValue; + begin + Assert(Left.Exponent=Right.Exponent); + Assert(QWordGreaterOrEqual(Left.SignificantMantissa,Right.SignificantMantissa)); + result.Exponent:=Left.Exponent; + result.SignificantMantissa:=Left.SignificantMantissa-Right.SignificantMantissa; + end; + procedure DoubleValueMuliply(var Left:TDoubleValue;const Right:TDoubleValue); + var a,b,c,d,ac,bc,ad,bd:qword; + begin + a:=Left.SignificantMantissa shr 32; + b:=Left.SignificantMantissa and $ffffffff; + c:=Right.SignificantMantissa shr 32; + d:=Right.SignificantMantissa and $ffffffff; + ac:=a*c; + bc:=b*c; + ad:=a*d; + bd:=b*d; + inc(Left.Exponent,Right.Exponent+64); + Left.SignificantMantissa:=ac+(ad shr 32)+(bc shr 32)+(qword(((bd shr 32)+((ad and $ffffffff)+(bc and $ffffffff)))+(qword(1) shl 31)) shr 32); + end; + function DoubleValueMul(const Left,Right:TDoubleValue):TDoubleValue; + var a,b,c,d,ac,bc,ad,bd:qword; + begin + a:=Left.SignificantMantissa shr 32; + b:=Left.SignificantMantissa and $ffffffff; + c:=Right.SignificantMantissa shr 32; + d:=Right.SignificantMantissa and $ffffffff; + ac:=a*c; + bc:=b*c; + ad:=a*d; + bd:=b*d; + result.Exponent:=Left.Exponent+(Right.Exponent+64); + a:=((bd shr 32)+((ad and $ffffffff)+(bc and $ffffffff)))+(qword(1) shl 31); + result.SignificantMantissa:=ac+(ad shr 32)+(bc shr 32)+(a shr 32); + end; + procedure DoubleValueNormalize(var Value:TDoubleValue); + var SignificantMantissa:qword; + Exponent:longint; + begin + Assert(Value.SignificantMantissa<>0); + SignificantMantissa:=Value.SignificantMantissa; + Exponent:=Value.Exponent; + while (SignificantMantissa and qword($ffc0000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 10; + dec(Exponent,10); + end; + while (SignificantMantissa and qword($8000000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + Value.SignificantMantissa:=SignificantMantissa; + Value.Exponent:=Exponent; + end; + function DoubleValueNorm(const Value:TDoubleValue):TDoubleValue; + var SignificantMantissa:qword; + Exponent:longint; + begin + Assert(Value.SignificantMantissa<>0); + SignificantMantissa:=Value.SignificantMantissa; + Exponent:=Value.Exponent; + while (SignificantMantissa and qword($ffc0000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 10; + dec(Exponent,10); + end; + while (SignificantMantissa and qword($8000000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + result.SignificantMantissa:=SignificantMantissa; + result.Exponent:=Exponent; + end; + function BigNumNew:TBigNum; + begin + FillChar(result,sizeof(TBigNum),#0); + end; + procedure BigNumZero(var BigNum:TBigNum); + begin + BigNum.UsedDigits:=0; + BigNum.Exponent:=0; + end; + procedure BigNumEnsureCapacity(var BigNum:TBigNum;Size:longint); + begin + end; + procedure BigNumClamp(var BigNum:TBigNum); + begin + while (BigNum.UsedDigits>0) and (BigNum.Bigits[BigNum.UsedDigits-1]=0) do begin + dec(BigNum.UsedDigits); + end; + if BigNum.UsedDigits=0 then begin + BigNum.Exponent:=0; + end; + end; + function BigNumIsClamped(const BigNum:TBigNum):boolean; + begin + result:=(BigNum.UsedDigits=0) or (BigNum.Bigits[BigNum.UsedDigits-1]<>0); + end; + procedure BigNumAlign(var BigNum:TBigNum;const Other:TBigNum); + var ZeroDigits,i:longint; + begin + if BigNum.Exponent>Other.Exponent then begin + ZeroDigits:=BigNum.Exponent-Other.Exponent; + BigNumEnsureCapacity(BigNum,Bignum.UsedDigits+ZeroDigits); + for i:=BigNum.UsedDigits-1 downto 0 do begin + BigNum.Bigits[i+ZeroDigits]:=BigNum.Bigits[i]; + end; + for i:=0 to ZeroDigits-1 do begin + BigNum.Bigits[i]:=0; + end; + inc(BigNum.UsedDigits,ZeroDigits); + dec(BigNum.Exponent,ZeroDigits); + Assert(BigNum.UsedDigits>=0); + Assert(BigNum.Exponent>=0); + end; + end; + procedure BigNumAssignUInt16(var BigNum:TBigNum;Value:word); + begin + Assert(BigitSize>=(sizeof(word)*8)); + BigNumZero(BigNum); + if Value<>0 then begin + BigNumEnsureCapacity(BigNum,1); + BigNum.Bigits[0]:=Value; + BigNum.UsedDigits:=1; + end; + end; + procedure BigNumAssignUInt64(var BigNum:TBigNum;Value:qword); + var i,j:longint; + begin + BigNumZero(BigNum); + if Value<>0 then begin + j:=(64 div BigitSize)+1; + BigNumEnsureCapacity(BigNum,j); + for i:=0 to j-1 do begin + BigNum.Bigits[i]:=Value and BigitMask; + Value:=Value shr BigitSize; + end; + BigNum.UsedDigits:=j; + BigNumClamp(BigNum); + end; + end; + procedure BigNumAssignBigNum(var BigNum:TBigNum;const Other:TBigNum); + begin + BigNum.Exponent:=Other.Exponent; + BigNum.Bigits:=Other.Bigits; + BigNum.UsedDigits:=Other.UsedDigits; + end; + procedure BigNumAddBigNum(var BigNum:TBigNum;const Other:TBigNum); + var Carry,Sum:TBigNumChunk; + BigitPos,i:longint; + begin + Assert(BigNumIsClamped(BigNum)); + Assert(BigNumIsClamped(Other)); + BigNumAlign(BigNum,Other); + BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+Other.UsedDigits); + BigitPos:=Other.Exponent-BigNum.Exponent; + Assert(BigitPos>=0); + Carry:=0; + for i:=0 to Other.UsedDigits-1 do begin + Sum:=BigNum.Bigits[BigitPos]+Other.Bigits[i]+Carry; + BigNum.Bigits[BigitPos]:=Sum and BigitMask; + Carry:=Sum shr BigitSize; + inc(BigitPos); + end; + while Carry<>0 do begin + Sum:=BigNum.Bigits[BigitPos]+Carry; + BigNum.Bigits[BigitPos]:=Sum and BigitMask; + Carry:=Sum shr BigitSize; + inc(BigitPos); + end; + if BigNum.UsedDigits<BigitPos then begin + BigNum.UsedDigits:=BigitPos; + end; + Assert(BigNumIsClamped(BigNum)); + end; + procedure BigNumAddUInt64(var BigNum:TBigNum;const Value:qword); + var Other:TBigNum; + begin + Other:=BigNumNew; + BigNumAssignUInt64(Other,Value); + BigNumAddBigNum(BigNum,Other); + end; + function BigNumBigitAt(const BigNum:TBigNum;Index:longint):TBigNumChunk; + begin + if (Index<BigNum.Exponent) or (Index>=(BigNum.UsedDigits+BigNum.Exponent)) then begin + result:=0; + end else begin + result:=BigNum.Bigits[Index-BigNum.Exponent]; + end; + end; + function BigNumCompare(const a,b:TBigNum):longint; + var la,lb,i,j:longint; + ba,bb:TBigNumChunk; + begin + Assert(BigNumIsClamped(a)); + Assert(BigNumIsClamped(b)); + la:=a.UsedDigits+a.Exponent; + lb:=b.UsedDigits+b.Exponent; + if la<lb then begin + result:=-1; + end else if la>lb then begin + result:=1; + end else begin + if a.Exponent<b.Exponent then begin + j:=a.Exponent; + end else begin + j:=b.Exponent; + end; + result:=0; + for i:=la-1 downto j do begin + ba:=BigNumBigItAt(a,i); + bb:=BigNumBigItAt(b,i); + if ba<bb then begin + result:=-1; + break; + end else if ba>bb then begin + result:=1; + break; + end; + end; + end; + end; + function BigNumPlusCompare(const a,b,c:TBigNum):longint; + var la,lb,lc,i,j:longint; + ba,bb,bc,br,Sum:TBigNumChunk; + begin + Assert(BigNumIsClamped(a)); + Assert(BigNumIsClamped(b)); + Assert(BigNumIsClamped(c)); + la:=a.UsedDigits+a.Exponent; + lb:=b.UsedDigits+b.Exponent; + lc:=c.UsedDigits+c.Exponent; + if la<lb then begin + result:=BigNumPlusCompare(b,a,c); + end else begin + if (la+1)<lc then begin + result:=-1; + end else if la>lc then begin + result:=1; + end else if (a.Exponent>=lb) and (la<lc) then begin + result:=-1; + end else begin + if a.Exponent<b.Exponent then begin + if a.Exponent<c.Exponent then begin + j:=a.Exponent; + end else begin + j:=c.Exponent; + end; + end else begin + if b.Exponent<c.Exponent then begin + j:=b.Exponent; + end else begin + j:=c.Exponent; + end; + end; + br:=0; + for i:=lc-1 downto j do begin + ba:=BigNumBigItAt(a,i); + bb:=BigNumBigItAt(b,i); + bc:=BigNumBigItAt(c,i); + Sum:=ba+bb; + if Sum>(bc+br) then begin + result:=1; + exit; + end else begin + br:=(bc+br)-Sum; + if br>1 then begin + result:=-1; + exit; + end; + br:=br shl BigitSize; + end; + end; + if br=0 then begin + result:=0; + end else begin + result:=-1; + end; + end; + end; + end; + procedure BigNumSubtractBigNum(var BigNum:TBigNum;const Other:TBigNum); + var Borrow,Difference:TBigNumChunk; + i,Offset:longint; + begin + Assert(BigNumIsClamped(BigNum)); + Assert(BigNumIsClamped(Other)); + Assert(BigNumCompare(Other,BigNum)<=0); + BigNumAlign(BigNum,Other); + Offset:=Other.Exponent-BigNum.Exponent; + Borrow:=0; + for i:=0 to Other.UsedDigits-1 do begin + Assert((Borrow=0) or (Borrow=1)); + Difference:=(BigNum.Bigits[i+Offset]-Other.Bigits[i])-Borrow; + BigNum.Bigits[i+Offset]:=Difference and BigitMask; + Borrow:=Difference shr (BigitChunkSize-1); + end; + i:=Other.UsedDigits; + while Borrow<>0 do begin + Difference:=BigNum.Bigits[i+Offset]-Borrow; + BigNum.Bigits[i+Offset]:=Difference and BigitMask; + Borrow:=Difference shr (BigitChunkSize-1); + inc(i); + end; + BigNumClamp(BigNum); + end; + procedure BigNumBigitsShiftLeft(var BigNum:TBigNum;Shift:longint); + var Carry,NextCarry:TBigNumChunk; + i:longint; + begin + Assert(Shift<BigitSize); + Assert(Shift>=0); + Carry:=0; + for i:=0 to BigNum.UsedDigits-1 do begin + NextCarry:=BigNum.Bigits[i] shr (BigitSize-Shift); + BigNum.Bigits[i]:=((BigNum.Bigits[i] shl Shift)+Carry) and BigitMask; + Carry:=NextCarry; + end; + if Carry<>0 then begin + BigNum.Bigits[BigNum.UsedDigits]:=Carry; + inc(BigNum.UsedDigits); + end; + end; + procedure BigNumBigitsShiftRight(var BigNum:TBigNum;Shift:longint); + var Carry,NextCarry:TBigNumChunk; + i:longint; + begin + Assert(Shift<BigitSize); + Assert(Shift>=0); + if BigNum.UsedDigits>0 then begin + Carry:=0; + for i:=BigNum.UsedDigits-1 downto 1 do begin + NextCarry:=BigNum.Bigits[i] shl (BigitSize-Shift); + BigNum.Bigits[i]:=((BigNum.Bigits[i] shr Shift)+Carry) and BigitMask; + Carry:=NextCarry; + end; + BigNum.Bigits[0]:=(BigNum.Bigits[0] shr Shift)+Carry; + end; + BigNumClamp(BigNum); + end; + procedure BignumSubtractTimes(var BigNum:TBigNum;const Other:TBigNum;Factor:longint); + var i,ExponentDiff:longint; + Borrow,Difference:TBigNumChunk; + Product,Remove:TBigNumDoubleChunk; + begin + Assert(BigNum.Exponent<=Other.Exponent); + if Factor<3 then begin + for i:=1 to Factor do begin + BigNumSubtractBignum(BigNum,Other); + end; + end else begin + Borrow:=0; + ExponentDiff:=Other.Exponent-BigNum.Exponent; + for i:=0 to Other.UsedDigits-1 do begin + Product:=TBigNumDoubleChunk(Factor)*Other.Bigits[i]; + Remove:=Borrow+Product; + Difference:=BigNum.Bigits[i+ExponentDiff]-TBigNumChunk(Remove and BigitMask); + BigNum.Bigits[i+ExponentDiff]:=Difference and BigitMask; + Borrow:=TBigNumChunk((Difference shr (BigitChunkSize-1))+(Remove shr BigitSize)); + end; + for i:=Other.UsedDigits+ExponentDiff to BigNum.UsedDigits-1 do begin + if Borrow=0 then begin + exit; + end; + Difference:=BigNum.Bigits[i]-Borrow; + BigNum.Bigits[i]:=Difference and BigitMask; + Borrow:=TBigNumChunk(Difference shr (BigitChunkSize-1)); + end; + BigNumClamp(BigNum); + end; + end; + procedure BigNumShiftLeft(var BigNum:TBigNum;Shift:longint); + begin + if BigNum.UsedDigits<>0 then begin + inc(BigNum.Exponent,Shift div BigitSize); + BignumEnsureCapacity(BigNum,BigNum.UsedDigits+1); + BigNumBigitsShiftLeft(BigNum,Shift mod BigitSize); + end; + end; + procedure BigNumShiftRight(var BigNum:TBigNum;Shift:longint); + begin + if BigNum.UsedDigits<>0 then begin + dec(BigNum.Exponent,Shift div BigitSize); + BignumEnsureCapacity(BigNum,BigNum.UsedDigits); + BigNumBigitsShiftRight(BigNum,Shift mod BigitSize); + end; + end; + procedure BigNumMultiplyByUInt32(var BigNum:TBigNum;Factor:word); + var Carry,Product:qword; + i:longint; + begin + if Factor=0 then begin + BigNumZero(BigNum); + end else if Factor<>1 then begin + Assert(BigitSize<32); + Carry:=0; + for i:=0 to BigNum.UsedDigits-1 do begin + Product:=(Factor*BigNum.Bigits[i])+Carry; + BigNum.Bigits[i]:=Product and BigitMask; + Carry:=Product shr BigitSize; + end; + while Carry<>0 do begin + BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+1); + BigNum.Bigits[BigNum.UsedDigits]:=Carry and BigitMask; + inc(BigNum.UsedDigits); + Carry:=Carry shr BigitSize; + end; + end; + end; + procedure BigNumMultiplyByUInt64(var BigNum:TBigNum;Factor:qword); + var Carry,Low,High,ProductLow,ProductHigh,Tmp:qword; + i:longint; + begin + if Factor=0 then begin + BigNumZero(BigNum); + end else if Factor<>1 then begin + Assert(BigitSize<32); + Carry:=0; + Low:=Factor and $ffffffff; + High:=Factor shr 32; + for i:=0 to BigNum.UsedDigits-1 do begin + ProductLow:=Low*BigNum.Bigits[i]; + ProductHigh:=High*BigNum.Bigits[i]; + Tmp:=(Carry and BigitMask)+ProductLow; + BigNum.Bigits[i]:=Tmp and BigitMask; + Carry:=(Carry shr BigitSize)+(Tmp shr BigitSize)+(ProductHigh shl (32-BigitSize)); + end; + while Carry<>0 do begin + BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+1); + BigNum.Bigits[BigNum.UsedDigits]:=Carry and BigitMask; + inc(BigNum.UsedDigits); + Carry:=Carry shr BigitSize; + end; + end; + end; + procedure BigNumSquare(var BigNum:TBigNum); + var ProductLength,CopyOffset,i,BigitIndex1,BigitIndex2:longint; + Accumulator:TBigNumDoubleChunk; + Chunk1,Chunk2:TBigNumChunk; + begin + Assert(BigNumIsClamped(BigNum)); + ProductLength:=2*BigNum.UsedDigits; + BigNumEnsureCapacity(BigNum,ProductLength); + Assert(not ((1 shl (2*(BigItChunkSize-BigitSize)))<=BigNum.UsedDigits)); + Accumulator:=0; + CopyOffset:=BigNum.UsedDigits; + for i:=0 to BigNum.UsedDigits-1 do begin + BigNum.Bigits[i+CopyOffset]:=BigNum.Bigits[i]; + end; + for i:=0 to BigNum.UsedDigits-1 do begin + BigitIndex1:=i; + BigitIndex2:=0; + while BigitIndex1>=0 do begin + Chunk1:=BigNum.Bigits[CopyOffset+BigitIndex1]; + Chunk2:=BigNum.Bigits[CopyOffset+BigitIndex2]; + inc(Accumulator,TBigNumDoubleChunk(Chunk1)*Chunk2); + dec(BigitIndex1); + inc(BigitIndex2); + end; + BigNum.Bigits[i]:=Accumulator and BigitMask; + Accumulator:=Accumulator shr BigitSize; + end; + for i:=BigNum.UsedDigits-1 to ProductLength-1 do begin + BigitIndex1:=BigNum.UsedDigits-1; + BigitIndex2:=i-BigitIndex1; + while BigitIndex2<BigNum.UsedDigits do begin + Chunk1:=BigNum.Bigits[CopyOffset+BigitIndex1]; + Chunk2:=BigNum.Bigits[CopyOffset+BigitIndex2]; + inc(Accumulator,TBigNumDoubleChunk(Chunk1)*Chunk2); + dec(BigitIndex1); + inc(BigitIndex2); + end; + BigNum.Bigits[i]:=Accumulator and BigitMask; + Accumulator:=Accumulator shr BigitSize; + end; + Assert(Accumulator=0); + BigNum.UsedDigits:=ProductLength; + inc(BigNum.Exponent,BigNum.Exponent); + BigNumClamp(BigNum); + end; + procedure BigNumAssignPowerUInt16(var BigNum:TBigNum;Base:word;PowerExponent:longint); + var Shifts,BitSize,TmpBase,FinalSize,Mask:longint; + ThisValue:qword; + DelayedMultipliciation:boolean; + begin + Assert(Base<>0); + Assert(PowerExponent>=0); + if PowerExponent=0 then begin + BigNumAssignUInt16(BigNum,1); + end else begin + BigNumZero(BigNum); + Shifts:=0; + while (Base and 1)=0 do begin + Base:=Base shr 1; + inc(Shifts); + end; + BitSize:=0; + TmpBase:=Base; + while TmpBase<>0 do begin + TmpBase:=TmpBase shr 1; + inc(BitSize); + end; + FinalSize:=BitSize*PowerExponent; + BigNumEnsureCapacity(BigNum,FinalSize); + Mask:=1; + while Mask<=PowerExponent do begin + inc(Mask,Mask); + end; + Mask:=Mask shr 2; + ThisValue:=Base; + DelayedMultipliciation:=false; + while (Mask<>0) and (ThisValue<=$ffffffff) do begin + ThisValue:=ThisValue*ThisValue; + if (PowerExponent and Mask)<>0 then begin + if (ThisValue and not ((qword(1) shl (64-BitSize))-1))=0 then begin + ThisValue:=ThisValue*Base; + end else begin + DelayedMultipliciation:=true; + end; + end; + Mask:=Mask shr 1; + end; + BigNumAssignUInt64(BigNum,ThisValue); + if DelayedMultipliciation then begin + BigNumMultiplyByUInt32(BigNum,Base); + end; + while Mask<>0 do begin + BigNumSquare(BigNum); + if (PowerExponent and Mask)<>0 then begin + BigNumMultiplyByUInt32(BigNum,Base); + end; + Mask:=Mask shr 1; + end; + BigNumShiftLeft(BigNum,Shifts*PowerExponent); + end; + end; + function BigNumDivideModuloIntBigNum(var BigNum:TBigNum;const Other:TBigNum):word; + var ThisBigit,OtherBigit:TBigNumChunk; + Quotient,DivisionEstimate:longword; + begin + Assert(BigNumIsClamped(BigNum)); + Assert(BigNumIsClamped(Other)); + Assert(Other.UsedDigits>0); + result:=0; + if (BigNum.UsedDigits+BigNum.Exponent)>=(Other.UsedDigits+Other.Exponent) then begin + BigNumAlign(BigNum,Other); + while (BigNum.UsedDigits+BigNum.Exponent)>(Other.UsedDigits+Other.Exponent) do begin + Assert(Other.Bigits[Other.UsedDigits-1]>=((1 shl BigitSize) div 16)); + inc(result,BigNum.Bigits[BigNum.UsedDigits-1]); + BigNumSubtractTimes(BigNum,Other,BigNum.Bigits[BigNum.UsedDigits-1]); + end; + Assert((BigNum.UsedDigits+BigNum.Exponent)=(Other.UsedDigits+Other.Exponent)); + ThisBigit:=BigNum.Bigits[BigNum.UsedDigits-1]; + OtherBigit:=Other.Bigits[Other.UsedDigits-1]; + if Other.UsedDigits=1 then begin + Quotient:=ThisBigit div OtherBigit; + BigNum.Bigits[BigNum.UsedDigits-1]:=ThisBigit-(OtherBigit*Quotient); + inc(result,Quotient); + BigNumClamp(BigNum); + end else begin + DivisionEstimate:=ThisBigit div (OtherBigit+1); + inc(result,DivisionEstimate); + BigNumSubtractTimes(BigNum,Other,DivisionEstimate); + if (OtherBigit*(DivisionEstimate+1))<=ThisBigit then begin + while BigNumCompare(Other,BigNum)<=0 do begin + BigNumSubtractBigNum(BigNum,Other); + inc(result); + end; + end; + end; + end; + end; + function BigNumDivideModuloInt(var BigNum:TBigNum;Divisor:word):word; + var q0,r0,q1,r1:qword; + i:integer; + begin + Assert(BigNumIsClamped(BigNum)); + q0:=0; + for i:=BigNum.UsedDigits-1 downto 1 do begin + q1:=(BigNum.Bigits[i] div Divisor)+q0; + r1:=((BigNum.Bigits[i] mod Divisor) shl 16)+(BigNum.Bigits[i-1] shr 16); + q0:=((r1 div Divisor) shl 16); + r0:=r1 mod Divisor; + BigNum.Bigits[i]:=q1; + BigNum.Bigits[i-1]:=(r0 shl 16)+(BigNum.Bigits[i-1] and $ffff); + end; + q1:=(BigNum.Bigits[0] div Divisor)+q0; + r1:=BigNum.Bigits[0] mod Divisor; + BigNum.Bigits[0]:=q1; + result:=r1; + BigNumClamp(BigNum); + end; + function NormalizedExponent(SignificantMantissa:qword;Exponent:longint):longint; + begin + Assert(SignificantMantissa<>0); + while (SignificantMantissa and qword($0010000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + result:=Exponent; + end; + function GetEstimatePower(Exponent:longint):longint; + begin + result:=longint(int64(((Exponent+52)*int64(1292913986))-$1000) shr 32)+1; // result:=System.Trunc(Math.Ceil(((Exponent+52)*0.30102999566398114)-(1e-10))); + end; + function GetEstimatePowerOf(Exponent,Radix:longint):longint; + begin + result:=longint(int64(((Exponent+52)*BESENDoubleToStringEstimatePowerFactorTable[Radix])-$1000) shr 32)+1; // result:=System.Trunc(Math.Ceil(((Exponent+52)*(ln(2)/ln(Radix)))-(1e-10))); + end; + procedure GenerateShortestDigits(var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;IsEven:boolean;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var Digit,Compare:longint; + InDeltaRoomMinus,InDeltaRoomPlus:boolean; + begin + Len:=0; + while true do begin + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + Assert((Digit>=0) and (Digit<=9)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + if IsEven then begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<=0; + end else begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<0; + end; + if IsEven then begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; + end else begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; + end; + if (not InDeltaRoomMinus) and (not InDeltaRoomPlus) then begin + BigNumMultiplyByUInt32(Numerator,10); + BigNumMultiplyByUInt32(DeltaMinus,10); + BigNumMultiplyByUInt32(DeltaPlus,10); + end else if InDeltaRoomMinus and InDeltaRoomPlus then begin + Compare:=BigNumPlusCompare(Numerator,Numerator,Denominator); + if Compare<0 then begin + end else if Compare>0 then begin + Assert(Buffer[Len]<>'9'); + inc(Buffer[Len]); + end else begin + if ((ord(Buffer[Len])-ord('0')) and 1)<>0 then begin + Assert(Buffer[Len]<>'9'); + inc(Buffer[Len]); + end; + end; + exit; + end else if InDeltaRoomMinus then begin + exit; + end else begin + Assert(Buffer[Len]<>'9'); + inc(Buffer[Len]); + exit; + end; + end; + end; + procedure GenerateCountedDigits(Count:longint;var DecimalPoint:longint;var Numerator,Denominator:TBigNum;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var i,Digit:longint; + begin + Assert(Count>=0); + for i:=1 to Count-1 do begin + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + Assert((Digit>=0) and (Digit<=9)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + BigNumMultiplyByUInt32(Numerator,10); + end; + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + if BigNumPlusCompare(Numerator,Numerator,Denominator)>=0 then begin + inc(Digit); + end; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + for i:=Len downto 2 do begin + if ord(Buffer[i])<>(ord('0')+10) then begin + break; + end; + Buffer[i]:='0'; + inc(Buffer[i-1]); + end; + if ord(Buffer[1])=(ord('0')+10) then begin + Buffer[1]:='1'; + inc(DecimalPoint); + end; + end; + procedure GenerateFixedDigits(RequestedDigits:longint;var DecimalPoint:longint;var Numerator,Denominator:TBigNum;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + begin + if (-DecimalPoint)>RequestedDigits then begin + DecimalPoint:=-RequestedDigits; + Len:=0; + end else if (-DecimalPoint)=RequestedDigits then begin + Assert(DecimalPoint=(-RequestedDigits)); + BigNumMultiplyByUInt32(Denominator,10); + if BigNumPlusCompare(Numerator,Numerator,Denominator)>=0 then begin + Buffer:='1'; + Len:=1; + end else begin + Len:=0; + end; + end else begin + GenerateCountedDigits(DecimalPoint+RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); + end; + end; + procedure FixupMultiplyBase(EstimatedPower:longint;IsEven:boolean;var DecimalPoint:longint;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + var InRange:boolean; + begin + if IsEven then begin + InRange:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; + end else begin + InRange:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; + end; + if InRange then begin + DecimalPoint:=EstimatedPower+1; + end else begin + DecimalPoint:=EstimatedPower; + BigNumMultiplyByUInt32(Numerator,Base); + if BigNumCompare(DeltaMinus,DeltaPlus)=0 then begin + BigNumMultiplyByUInt32(DeltaMinus,Base); + BigNumAssignBigNum(DeltaPlus,DeltaMinus); + end else begin + BigNumMultiplyByUInt32(DeltaMinus,Base); + BigNumMultiplyByUInt32(DeltaPlus,Base); + end; + end; + end; + procedure InitialScaledStartValuesPositiveExponent(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + Assert(EstimatedPower>=0); + + BigNumAssignUInt64(Numerator,SignificantMantissa); + BigNumShiftLeft(Numerator,Exponent); + BigNumAssignPowerUInt16(Denominator,Base,EstimatedPower); + + if NeedBoundaryDeltas then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + + BigNumAssignUInt16(DeltaPlus,1); + BigNumShiftLeft(DeltaPlus,Exponent); + + BigNumAssignUInt16(DeltaMinus,1); + BigNumShiftLeft(DeltaMinus,Exponent); + + if (Casted and qword($000fffffffffffff))=0 then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + BigNumShiftLeft(DeltaPlus,1); + end; + end; + end; + procedure InitialScaledStartValuesNegativeExponentPositivePower(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + BigNumAssignUInt64(Numerator,SignificantMantissa); + BigNumAssignPowerUInt16(Denominator,Base,EstimatedPower); + BigNumShiftLeft(Denominator,-Exponent); + + if NeedBoundaryDeltas then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + + BigNumAssignUInt16(DeltaPlus,1); + BigNumAssignUInt16(DeltaMinus,1); + + if (Casted and qword($000fffffffffffff))=0 then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + BigNumShiftLeft(DeltaPlus,1); + end; + end; + end; + procedure InitialScaledStartValuesNegativeExponentNegativePower(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + BigNumAssignPowerUInt16(Numerator,Base,-EstimatedPower); + if NeedBoundaryDeltas then begin + BigNumAssignBigNum(DeltaPlus,Numerator); + BigNumAssignBigNum(DeltaMinus,Numerator); + end; + BigNumMultiplyByUInt64(Numerator,SignificantMantissa); + + BigNumAssignUInt16(Denominator,1); + BigNumShiftLeft(Denominator,-Exponent); + + if NeedBoundaryDeltas then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + if ((Casted and qword($000fffffffffffff))=0) and ((Casted and qword($7ff0000000000000))<>qword($0010000000000000)) then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + BigNumShiftLeft(DeltaPlus,1); + end; + end; + end; + procedure InitialScaledStartValues(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + if Exponent>=0 then begin + InitialScaledStartValuesPositiveExponent(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); + end else if EstimatedPower>=0 then begin + InitialScaledStartValuesNegativeExponentPositivePower(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); + end else begin + InitialScaledStartValuesNegativeExponentNegativePower(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); + end; + end; + procedure DoubleToDecimal(Value:double;Mode,RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var Casted:qword absolute Value; + SignificantMantissa:qword; + Exponent,EstimatedPower:longint; + Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum; + IsEven,NeedBoundaryDeltas:boolean; + begin + Assert(Value>0); + Assert(BESENIsFinite(Value)); + SplitDouble(Value,SignificantMantissa,Exponent); + IsEven:=(SignificantMantissa and 1)=0; + EstimatedPower:=GetEstimatePower(NormalizedExponent(SignificantMantissa,Exponent)); + if (Mode=mFIXED) and (((-EstimatedPower)-1)>RequestedDigits) then begin + Buffer:=''; + Len:=0; + DecimalPoint:=-RequestedDigits; + end else begin + Assert(BigNumMaxSignificantMantissaBits>=(324*4)); + NeedBoundaryDeltas:=Mode=mSHORTEST; + InitialScaledStartValues(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,10); + FixupMultiplyBase(EstimatedPower,IsEven,DecimalPoint,Numerator,Denominator,DeltaMinus,DeltaPlus,10); + case Mode of + mSHORTEST:begin + GenerateShortestDigits(Numerator,Denominator,DeltaMinus,DeltaPlus,IsEven,Buffer,Len); + end; + mFIXED:begin + GenerateFixedDigits(RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); + end; + else {mPRECISION:}begin + GenerateCountedDigits(RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); + end; + end; + end; + end; + procedure GenerateRadixDigits(var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;IsEven:boolean;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint;Radix:longint); + const Base36:array[0..36] of {$ifdef BESENSingleStringType}char{$else}ansichar{$endif}='0123456789abcdefghijklmnopqrstuvwxyz{'; + var Digit,Compare,MaxDigit:longint; + InDeltaRoomMinus,InDeltaRoomPlus:boolean; + function ValueOf(c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}):longint; + begin + case c of + '0'..'9':begin + result:=ord(c)-ord('0'); + end; + else begin + result:=(ord(c)-ord('a'))+$a; + end; + end; + end; + begin + Len:=0; + MaxDigit:=Radix-1; + while true do begin + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + Assert((Digit>=0) and (Digit<=MaxDigit)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:=Base36[Digit]; + BigNumClamp(Numerator); + BigNumClamp(DeltaMinus); + BigNumClamp(DeltaPlus); + if IsEven then begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<=0; + end else begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<0; + end; + if IsEven then begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; + end else begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; + end; + if (not InDeltaRoomMinus) and (not InDeltaRoomPlus) then begin + BigNumMultiplyByUInt32(Numerator,Radix); + BigNumMultiplyByUInt32(DeltaMinus,Radix); + BigNumMultiplyByUInt32(DeltaPlus,Radix); + end else if InDeltaRoomMinus and InDeltaRoomPlus then begin + Compare:=BigNumPlusCompare(Numerator,Numerator,Denominator); + if Compare<0 then begin + end else if Compare>0 then begin + Assert(ValueOf(Buffer[Len])<>MaxDigit); + Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; + end else begin + if (ValueOf(Buffer[Len]) and 1)<>0 then begin + Assert(ValueOf(Buffer[Len])<>MaxDigit); + Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; + end; + end; + exit; + end else if InDeltaRoomMinus then begin + exit; + end else begin + Assert(ValueOf(Buffer[Len])<>MaxDigit); + Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; + exit; + end; + end; + end; + procedure DoubleToRadix(Value:double;Radix:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var Casted:qword absolute Value; + SignificantMantissa:qword; + Exponent,EstimatedPower:longint; + Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum; + IsEven,NeedBoundaryDeltas:boolean; + begin + Assert(Value>0); + Assert(BESENIsFinite(Value)); + SplitDouble(Value,SignificantMantissa,Exponent); + IsEven:=(SignificantMantissa and 1)=0; + EstimatedPower:=GetEstimatePowerOf(NormalizedExponent(SignificantMantissa,Exponent),Radix); + Assert(BigNumMaxSignificantMantissaBits>=(324*4)); + NeedBoundaryDeltas:=true; + InitialScaledStartValues(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Radix); + FixupMultiplyBase(EstimatedPower,IsEven,DecimalPoint,Numerator,Denominator,DeltaMinus,DeltaPlus,Radix); + GenerateRadixDigits(Numerator,Denominator,DeltaMinus,DeltaPlus,IsEven,Buffer,Len,Radix); + end; + procedure FastDoubleToRadix(v:double;Radix:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + const Base36:array[0..35] of {$ifdef BESENSingleStringType}char{$else}ansichar{$endif}='0123456789abcdefghijklmnopqrstuvwxyz'; +{$ifndef BESENNoFPU} + DtoAFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; + DtoAFPUPrecisionMode:TFPUPrecisionMode=pmDOUBLE; + DtoAFPURoundingMode:TFPURoundingMode=rmNEAREST; +{$endif} + var IntPart,FracPart,Old,Epsilon:double; + Digit,i,j:longint; + TempBuffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPUPrecisionMode:TFPUPrecisionMode; + OldFPURoundingMode:TFPURoundingMode; +{$endif} + IntPart64:int64; + begin + if (Radix<2) or (Radix>36) then begin + result:=''; + end else begin +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPUPrecisionMode:=GetPrecisionMode; + OldFPURoundingMode:=GetRoundMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(DtoAFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(DtoAFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(DtoAFPURoundingMode); + end; +{$endif} + try + TempBuffer:=''; + IntPart:=System.Int(v); + FracPart:=System.Frac(v); + if IntPart=0 then begin + result:='0'; + end else begin + if IntPart<4294967295.0 then begin + IntPart64:=trunc(IntPart); + while IntPart64>0 do begin + Digit:=IntPart64 mod Radix; + Assert((Digit>=0) and (Digit<Radix)); + IntPart64:=IntPart64 div Radix; + inc(Len); + if Len>=length(TempBuffer) then begin + SetLength(TempBuffer,Len*2); + end; + TempBuffer[Len]:=Base36[Digit]; + end; + end else begin + while IntPart>0 do begin + Old:=IntPart; + IntPart:=System.Int(IntPart/Radix); + Digit:=trunc(Old-(IntPart*Radix)); + Assert((Digit>=0) and (Digit<Radix)); + inc(Len); + if Len>=length(TempBuffer) then begin + SetLength(TempBuffer,Len*2); + end; + TempBuffer[Len]:=Base36[Digit]; + end; + end; + SetLength(Buffer,Len); + j:=1; + for i:=Len downto 1 do begin + Buffer[j]:=TempBuffer[i]; + inc(j); + end; + end; + if FracPart<>0 then begin + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:='.'; + Epsilon:=0.001/Radix; + while (FracPart>=Epsilon) and (Len<32) do begin + FracPart:=FracPart*Radix; + Digit:=trunc(FracPart); + FracPart:=System.Frac(FracPart); + Assert((Digit>=0) and (Digit<Radix)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:=Base36[Digit]; + end; + end; + finally + TempBuffer:=''; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(OldFPURoundingMode); + end; +{$endif} + end; + end; + end; + function GetCachedPowerForBinaryExponentRange(MinExponent,MaxExponent:longint;var Power:TDoubleValue;var DecimalExponent:longint):boolean; + var Index:longint; + begin + result:=false; + if (low(BESENDoubleToStringPowerOfTenBinaryExponentTable)<=MinExponent) and (MinExponent<=high(BESENDoubleToStringPowerOfTenBinaryExponentTable)) then begin + Index:=BESENDoubleToStringPowerOfTenBinaryExponentTable[MinExponent]; + if ((Index>=0) and (Index<length(BESENDoubleToStringPowerOfTenTable))) and ((MinExponent<=BESENDoubleToStringPowerOfTenTable[Index,1]) and (BESENDoubleToStringPowerOfTenTable[Index,1]<=MaxExponent)) then begin + Power.SignificantMantissa:=BESENDoubleToStringPowerOfTenTable[Index,0]; + Power.Exponent:=BESENDoubleToStringPowerOfTenTable[Index,1]; + DecimalExponent:=BESENDoubleToStringPowerOfTenTable[Index,2]; + result:=true; + end; + end; + end; + function GetCachedPowerForDecimalExponent(RequestedExponent:longint;var Power:TDoubleValue;var FoundExponent:longint):boolean; + var Index:longint; + begin + result:=false; + if (low(BESENDoubleToStringPowerOfTenDecimalExponentTable)<=RequestedExponent) and (RequestedExponent<=high(BESENDoubleToStringPowerOfTenDecimalExponentTable)) then begin + Index:=BESENDoubleToStringPowerOfTenDecimalExponentTable[RequestedExponent]; + if (Index>=0) and (Index<length(BESENDoubleToStringPowerOfTenTable)) then begin + Power.SignificantMantissa:=BESENDoubleToStringPowerOfTenTable[Index,0]; + Power.Exponent:=BESENDoubleToStringPowerOfTenTable[Index,1]; + FoundExponent:=BESENDoubleToStringPowerOfTenTable[Index,2]; + result:=true; + end; + end; + end; + function RoundWeed(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};Len:longint;DistanceTooHighW,UnsafeInterval,Rest,TenCapacity,UnitValue:qword):boolean; + var SmallDistance,BigDistance:qword; + begin + SmallDistance:=DistanceTooHighW-UnitValue; + BigDistance:=DistanceTooHighW+UnitValue; + Assert(QWordLessOrEqual(Rest,UnsafeInterval)); + while (QWordLess(Rest,SmallDistance) and (QWordGreaterOrEqual(UnsafeInterval-Rest,TenCapacity))) and (QWordLess(Rest+TenCapacity,SmallDistance) or QWordGreaterOrEqual(SmallDistance-Rest,((Rest+TenCapacity)-SmallDistance))) do begin + dec(Buffer[Len]); + inc(Rest,TenCapacity); + end; + if ((QWordLess(Rest,BigDistance) and QWordGreaterOrEqual(UnsafeInterval-Rest,TenCapacity)) and (QWordLess(Rest+TenCapacity,BigDistance) or QWordGreater(BigDistance-Rest,((Rest+TenCapacity)-BigDistance)))) then begin + result:=false; + end else begin + result:=(QWordLessOrEqual(2*UnitValue,Rest) and QWordLessOrEqual(Rest,UnsafeInterval-(4*UnitValue))); + end; + end; + function RoundWeedCounted(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};Len:longint;Rest,TenCapacity,UnitValue:qword;var Capacity:longint):boolean; + var i:longint; + begin + Assert(QWordLess(Rest,TenCapacity)); + result:=false; + if QWordGreater(TenCapacity-UnitValue,UnitValue) then begin + result:=QWordGreater(TenCapacity-Rest,Rest) and QWordGreaterOrEqual(TenCapacity-(2*Rest),2*UnitValue); + if not result then begin + result:=QWordGreater(Rest,UnitValue) and QWordLessOrEqual(TenCapacity-(Rest-UnitValue),Rest-UnitValue); + if result then begin + inc(Buffer[Len]); + for i:=Len downto 2 do begin + if ord(Buffer[i])<>(ord('0')+10) then begin + break; + end; + Buffer[i]:='0'; + inc(Buffer[i-1]); + end; + end; + if ord(Buffer[1])=(ord('0')+10) then begin + Buffer[1]:='1'; + inc(Capacity); + end; + end; + end; + end; + function BiggestPowerTen(Number:longword;NumberBits:longint;var Power:longword;var Exponent:longint):boolean; + label c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11; + begin + result:=true; + case NumberBits of + 30,31,32:begin + c1: + if 1000000000<=Number then begin + Power:=1000000000; + Exponent:=9; + end else begin + goto c2; + end; + end; + 27,28,29:begin + c2: + if 100000000<=Number then begin + Power:=100000000; + Exponent:=8; + end else begin + goto c3; + end; + end; + 24,25,26:begin + c3: + if 10000000<=Number then begin + Power:=10000000; + Exponent:=7; + end else begin + goto c4; + end; + end; + 20,21,22,23:begin + c4: + if 1000000<=Number then begin + Power:=1000000; + Exponent:=6; + end else begin + goto c5; + end; + end; + 17,18,19:begin + c5: + if 100000<=Number then begin + Power:=100000; + Exponent:=5; + end else begin + goto c6; + end; + end; + 14,15,16:begin + c6: + if 10000<=Number then begin + Power:=10000; + Exponent:=4; + end else begin + goto c7; + end; + end; + 10,11,12,13:begin + c7: + if 1000<=Number then begin + Power:=1000; + Exponent:=3; + end else begin + goto c8; + end; + end; + 7,8,9:begin + c8: + if 100<=Number then begin + Power:=100; + Exponent:=2; + end else begin + goto c9; + end; + end; + 4,5,6:begin + c9: + if 10<=Number then begin + Power:=10; + Exponent:=1; + end else begin + goto c10; + end; + end; + 1,2,3:begin + c10: + if 1<=Number then begin + Power:=1; + Exponent:=0; + end else begin + goto c11; + end; + end; + 0:begin + c11: + Power:=0; + Exponent:=-1; + end; + else begin + Power:=0; + Exponent:=0; + result:=false; + end; + end; + end; + function DigitGen(Low,w,High:TDoubleValue;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,Capacity:longint):boolean; + var UnitValue,Fractionals,Rest:qword; + TooLow,TooHigh,UnsafeInterval,One:TDoubleValue; + Integrals,Divisor,Digit:longword; + DivisorExponent:longint; + begin + result:=false; + if ((Low.Exponent=w.Exponent) and (w.Exponent=High.Exponent)) and (QWordLessOrEqual(Low.SignificantMantissa+1,High.SignificantMantissa-1) and + ((MinimalTargetExponent<=w.Exponent) and (w.Exponent<=MaximalTargetExponent))) then begin + UnitValue:=1; + TooLow.SignificantMantissa:=Low.SignificantMantissa-UnitValue; + TooLow.Exponent:=Low.Exponent; + TooHigh.SignificantMantissa:=High.SignificantMantissa+UnitValue; + TooHigh.Exponent:=High.Exponent; + UnsafeInterval:=DoubleValueMinus(TooHigh,TooLow); + One.SignificantMantissa:=qword(1) shl (-w.Exponent); + One.Exponent:=w.Exponent; + Integrals:=TooHigh.SignificantMantissa shr (-One.Exponent); + Fractionals:=TooHigh.SignificantMantissa and (One.SignificantMantissa-1); + Divisor:=0; + DivisorExponent:=0; + if BiggestPowerTen(Integrals,SignificantMantissaSize-(-One.Exponent),Divisor,DivisorExponent) then begin + Capacity:=DivisorExponent+1; + Len:=0; + while Capacity>0 do begin + Digit:=Integrals div Divisor; + Integrals:=Integrals mod Divisor; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(Capacity); + Rest:=qword(qword(Integrals) shl (-One.Exponent))+Fractionals; + if QWordLess(Rest,UnsafeInterval.SignificantMantissa) then begin + result:=RoundWeed(Buffer,Len,DoubleValueMinus(TooHigh,w).SignificantMantissa,UnsafeInterval.SignificantMantissa,Rest,qword(Divisor) shl (-One.Exponent),UnitValue); + exit; + end; + Divisor:=Divisor div 10; + end; + if (One.Exponent>=-60) and (QWordLess(Fractionals,One.SignificantMantissa) and QWordGreaterOrEqual(qword($1999999999999999),One.SignificantMantissa)) then begin + while true do begin + Fractionals:=Fractionals*10; + UnitValue:=UnitValue*10; + UnsafeInterval.SignificantMantissa:=UnsafeInterval.SignificantMantissa*10; + Digit:=Fractionals shr (-One.Exponent); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(Capacity); + Fractionals:=Fractionals and (One.SignificantMantissa-1); + if QWordLess(Fractionals,UnsafeInterval.SignificantMantissa) then begin + result:=RoundWeed(Buffer,Len,DoubleValueMinus(TooHigh,w).SignificantMantissa*UnitValue,UnsafeInterval.SignificantMantissa,Fractionals,One.SignificantMantissa,UnitValue); + exit; + end; + end; + end; + end; + end; + end; + function DigitGenCounted(w:TDoubleValue;RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,Capacity:longint):boolean; + var wError,Fractionals,Rest:qword; + One:TDoubleValue; + Integrals,Divisor,Digit:longword; + DivisorExponent:longint; + begin + result:=false; + if ((MinimalTargetExponent<=w.Exponent) and (w.Exponent<=MaximalTargetExponent)) and ((MinimalTargetExponent>=-60) and (MaximalTargetExponent<=-32)) then begin + wError:=1; + One.SignificantMantissa:=qword(1) shl (-w.Exponent); + One.Exponent:=w.Exponent; + Integrals:=w.SignificantMantissa shr (-One.Exponent); + Fractionals:=w.SignificantMantissa and (One.SignificantMantissa-1); + Divisor:=0; + DivisorExponent:=0; + if BiggestPowerTen(Integrals,SignificantMantissaSize-(-One.Exponent),Divisor,DivisorExponent) then begin + Capacity:=DivisorExponent+1; + Len:=0; + while Capacity>0 do begin + Digit:=Integrals div Divisor; + Integrals:=Integrals mod Divisor; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(RequestedDigits); + dec(Capacity); + if RequestedDigits=0 then begin + break; + end; + Divisor:=Divisor div 10; + end; + if RequestedDigits=0 then begin + Rest:=qword(qword(Integrals) shl (-One.Exponent))+Fractionals; + result:=RoundWeedCounted(Buffer,Len,Rest,qword(Divisor) shl (-One.Exponent),wError,Capacity); + exit; + end; + if ((One.Exponent>=-60) and QWordLess(Fractionals,One.SignificantMantissa)) and QWordGreaterOrEqual(qword($1999999999999999),One.SignificantMantissa) then begin + while (RequestedDigits>0) and (Fractionals>wError) do begin + Fractionals:=Fractionals*10; + Digit:=Fractionals shr (-One.Exponent); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(RequestedDigits); + dec(Capacity); + Fractionals:=Fractionals and (One.SignificantMantissa-1); + end; + if RequestedDigits=0 then begin + result:=RoundWeedCounted(Buffer,Len,Fractionals,One.SignificantMantissa,wError,Capacity); + end else begin + result:=false; + end; + end; + end; + end; + end; + procedure NormalizedBoundaries(Value:double;var BoundaryMinus,BoundaryPlus:TDoubleValue); + var v:TDoubleValue; + SignificantMantissaIsZero:boolean; + begin + Assert(not BESENIsNegative(Value)); + Assert(BESENIsFinite(Value)); + SplitDouble(Value,v.SignificantMantissa,v.Exponent); + SignificantMantissaIsZero:=v.SignificantMantissa=qword($0010000000000000); + BoundaryPlus.SignificantMantissa:=(v.SignificantMantissa shl 1)+1; + BoundaryPlus.Exponent:=v.Exponent-1; + DoubleValueNormalize(BoundaryPlus); + if SignificantMantissaIsZero and (v.Exponent<>((-($3ff+52))+1)) then begin + BoundaryMinus.SignificantMantissa:=(v.SignificantMantissa shl 2)-1; + BoundaryMinus.Exponent:=v.Exponent-2; + end else begin + BoundaryMinus.SignificantMantissa:=(v.SignificantMantissa shl 1)-1; + BoundaryMinus.Exponent:=v.Exponent-1; + end; + BoundaryMinus.SignificantMantissa:=BoundaryMinus.SignificantMantissa shl (BoundaryMinus.Exponent-BoundaryPlus.Exponent); + BoundaryMinus.Exponent:=BoundaryPlus.Exponent; + end; + function DoFastShortest(Value:double;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalExponent:longint):boolean; + var w,BoundaryMinus,BoundaryPlus,TenMK,ScaledW,ScaledBoundaryMinus,ScaledBoundaryPlus:TDoubleValue; + mK,TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,Capacity:longint; + begin + result:=false; + w:=DoubleValueGet(Value); + NormalizedBoundaries(Value,BoundaryMinus,BoundaryPlus); + Assert(BoundaryPlus.Exponent=w.Exponent); + TenMKMinimalBinaryExponent:=MinimalTargetExponent-(w.Exponent+SignificantMantissaSize); + TenMKMaximalBinaryExponent:=MaximalTargetExponent-(w.Exponent+SignificantMantissaSize); + if GetCachedPowerForBinaryExponentRange(TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,TenMK,mK) then begin + if (MinimalTargetExponent<=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) and (MaximalTargetExponent>=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) then begin + ScaledW:=DoubleValueMul(w,TenMK); + if ScaledW.Exponent=(BoundaryPlus.Exponent+TenMK.Exponent+SignificantMantissaSize) then begin + ScaledBoundaryMinus:=DoubleValueMul(BoundaryMinus,TenMK); + ScaledBoundaryPlus:=DoubleValueMul(BoundaryPlus,TenMK); + Capacity:=0; + result:=DigitGen(ScaledBoundaryMinus,ScaledW,ScaledBoundaryPlus,Buffer,Len,Capacity); + DecimalExponent:=Capacity-mK; + end; + end; + end; + end; + function DoFastPrecision(Value:double;RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalExponent:longint):boolean; + var w,TenMK,ScaledW:TDoubleValue; + mK,TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,Capacity:longint; + begin + result:=false; + w:=DoubleValueGet(Value); + TenMKMinimalBinaryExponent:=MinimalTargetExponent-(w.Exponent+SignificantMantissaSize); + TenMKMaximalBinaryExponent:=MaximalTargetExponent-(w.Exponent+SignificantMantissaSize); + if GetCachedPowerForBinaryExponentRange(TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,TenMK,mK) then begin + if (MinimalTargetExponent<=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) and (MaximalTargetExponent>=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) then begin + ScaledW:=DoubleValueMul(w,TenMK); + Capacity:=0; + result:=DigitGenCounted(ScaledW,RequestedDigits,Buffer,Len,Capacity); + DecimalExponent:=Capacity-mK; + end; + end; + end; + function DoFastFixed(Value:double;FracitionalCount:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint):boolean; + const Five17=$b1a2bc2ec5; // 5^17 + type TInt128=record + High,Low:qword; + end; + procedure Int128Mul(var a:TInt128;const Multiplicand:longword); + var Accumulator:qword; + Part:longword; + begin + Accumulator:=(a.Low and $ffffffff)*Multiplicand; + Part:=Accumulator and $ffffffff; + Accumulator:=(Accumulator shr 32)+((a.Low shr 32)*Multiplicand); + a.Low:=(Accumulator shl 32)+Part; + Accumulator:=(Accumulator shr 32)+((a.High and $ffffffff)*Multiplicand); + Part:=Accumulator and $ffffffff; + Accumulator:=(Accumulator shr 32)+((a.High shr 32)*Multiplicand); + a.High:=(Accumulator shl 32)+Part; + Assert((Accumulator shr 32)=0); + end; + procedure Int128Shift(var a:TInt128;const Shift:longint); + begin + Assert(((-64)<=Shift) and (Shift<=64)); + if Shift<>0 then begin + if Shift=-64 then begin + a.High:=a.Low; + a.Low:=0; + end else if Shift=64 then begin + a.Low:=a.High; + a.High:=0; + end else if Shift<=0 then begin + a.High:=(a.High shl (-Shift))+(a.Low shr (64+Shift)); + a.Low:=a.Low shl (-Shift); + end else begin + a.Low:=(a.Low shr Shift)+(a.High shl (64-Shift)); + a.High:=a.High shr Shift; + end; + end; + end; + function Int128DivModPowerOfTwo(var a:TInt128;const Power:longint):longint; + begin + if Power>=64 then begin + result:=a.High shr (Power-64); + dec(a.High,result shl (Power-64)); + end else begin + result:=(a.Low shr Power)+(a.High shl (64-Power)); + a.High:=0; + dec(a.Low,(a.Low shr Power) shl Power); + end; + end; + function Int128IsZero(const a:TInt128):boolean; + begin + result:=(a.High=0) and (a.Low=0); + end; + function Int128BitAt(const a:TInt128;const Position:longint):boolean; + begin + if Position>=64 then begin + result:=((a.High shr (Position-64)) and 1)<>0; + end else begin + result:=((a.LOw shr Position) and 1)<>0; + end; + end; + procedure FillDigits32FixedLength(Number:longword;RequestedLength:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var i,l:longint; + begin + l:=Len; + inc(Len,RequestedLength); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + for i:=RequestedLength downto 1 do begin + Buffer[l+i]:={$ifdef BESENSingleStringType}DigitChars[Number mod 10]{$else}AnsiChar(byte(byte(AnsiChar('0'))+(Number mod 10))){$endif}; + Number:=Number div 10; + end; + end; + procedure FillDigits32(Number:longword;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var NumberLength,i,l:longint; + OldNumber:longword; + begin + OldNumber:=Number; + NumberLength:=0; + while Number<>0 do begin + Number:=Number div 10; + inc(NumberLength); + end; + if NumberLength<>0 then begin + l:=Len; + inc(Len,NumberLength); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Number:=OldNumber; + for i:=NumberLength downto 1 do begin + Buffer[l+i]:={$ifdef BESENSingleStringType}DigitChars[Number mod 10]{$else}AnsiChar(byte(byte(AnsiChar('0'))+(Number mod 10))){$endif}; + Number:=Number div 10; + end; + end; + end; + procedure FillDigits64FixedLength(Number:qword;RequestedLength:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var p0,p1,p2:longword; + begin + p2:=Number mod 10000000; + Number:=Number div 10000000; + p1:=Number mod 10000000; + p0:=Number div 10000000; + FillDigits32FixedLength(p0,3,Buffer,Len); + FillDigits32FixedLength(p1,7,Buffer,Len); + FillDigits32FixedLength(p2,7,Buffer,Len); + end; + procedure FillDigits64(Number:qword;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var p0,p1,p2:longword; + begin + p2:=Number mod 10000000; + Number:=Number div 10000000; + p1:=Number mod 10000000; + p0:=Number div 10000000; + if p0<>0 then begin + FillDigits32(p0,Buffer,Len); + FillDigits32FixedLength(p1,7,Buffer,Len); + FillDigits32FixedLength(p2,7,Buffer,Len); + end else if p1<>0 then begin + FillDigits32(p1,Buffer,Len); + FillDigits32FixedLength(p2,7,Buffer,Len); + end else begin + FillDigits32(p2,Buffer,Len); + end; + end; + procedure RoundUp(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var i:longint; + begin + if Len=0 then begin + Buffer:='1'; + Len:=1; + DecimalPoint:=1; + end else begin + inc(Buffer[Len]); + for i:=Len downto 2 do begin + if ord(Buffer[i])<>(ord('0')+10) then begin + exit; + end; + Buffer[i]:='0'; + inc(Buffer[i-1]); + end; + if ord(Buffer[1])=(ord('0')+10) then begin + Buffer[1]:='1'; + inc(DecimalPoint); + end; + end; + end; + procedure FillFractionals(Fractionals:qword;Exponent:longint;FractionalCount:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var Point,i,Digit:longint; + Fractionals128:TInt128; + begin + Assert(((-128)<=Exponent) and (Exponent<=0)); + if (-Exponent)<=64 then begin + Assert((Fractionals shr 56)=0); + Point:=-Exponent; + for i:=1 to FracitionalCount do begin + Fractionals:=Fractionals*5; + dec(Point); + Digit:=Fractionals shr Point; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(Fractionals,qword(Digit) shl Point); + end; + if ((Fractionals shr (Point-1)) and 1)<>0 then begin + RoundUp(Buffer,Len,DecimalPoint); + end; + end else begin + Assert((64<(-Exponent)) and ((-Exponent)<=128)); + Fractionals128.High:=Fractionals; + Fractionals128.Low:=0; + Int128Shift(Fractionals128,(-Exponent)-64); + Point:=128; + for i:=1 to FracitionalCount do begin + if Int128IsZero(Fractionals128) then begin + break; + end; + Int128Mul(Fractionals128,5); + dec(Point); + Digit:=Int128DivModPowerOfTwo(Fractionals128,Point); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + end; + if Int128BitAt(Fractionals128,Point-1) then begin + RoundUp(Buffer,Len,DecimalPoint); + end; + end; + end; + procedure TrimZeros(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var i:longint; + begin + while (Len>0) and (Buffer[Len]='0') do begin + dec(Len); + end; + i:=0; + while (i<Len) and (Buffer[i+1]='0') do begin + inc(i); + end; + if i<>0 then begin + Delete(Buffer,1,i); + dec(Len,i); + dec(DecimalPoint,i); + end; + end; + var SignificantMantissa,Divisor,Dividend,Remainder,Integrals,Fractionals:qword; + Exponent,DivisorPower:longint; + Quotient:longword; + begin + result:=false; + SplitDouble(Value,SignificantMantissa,Exponent); + if (Exponent<=20) and (FracitionalCount<=20) then begin + Len:=0; + if (Exponent+53)>74 then begin + Divisor:=Five17; + DivisorPower:=17; + Dividend:=SignificantMantissa; + if Exponent>DivisorPower then begin + Dividend:=Dividend shl (Exponent-DivisorPower); + Quotient:=Dividend div Divisor; + Remainder:=(Dividend mod Divisor) shl DivisorPower; + end else begin + Dividend:=Dividend shl (DivisorPower-Exponent); + Quotient:=Dividend div Divisor; + Remainder:=(Dividend mod Divisor) shl Exponent; + end; + FillDigits32(Quotient,Buffer,Len); + FillDigits64FixedLength(Remainder,DivisorPower,Buffer,Len); + DecimalPoint:=Len; + end else if Exponent>=0 then begin + SignificantMantissa:=SignificantMantissa shl Exponent; + FillDigits64(SignificantMantissa,Buffer,Len); + DecimalPoint:=Len; + end else if Exponent>-53 then begin + Integrals:=SignificantMantissa shr (-Exponent); + Fractionals:=SignificantMantissa-(Integrals shl (-Exponent)); + if Integrals>$ffffffff then begin + FillDigits64(Integrals,Buffer,Len); + end else begin + FillDigits32(Integrals,Buffer,Len); + end; + DecimalPoint:=Len; + FillFractionals(Fractionals,Exponent,FracitionalCount,Buffer,Len,DecimalPoint); + end else if Exponent<-128 then begin + Assert(FracitionalCount>=20); + Buffer:=''; + Len:=0; + DecimalPoint:=-FracitionalCount; + end else begin + DecimalPoint:=0; + FillFractionals(SignificantMantissa,Exponent,FracitionalCount,Buffer,Len,DecimalPoint); + end; + TrimZeros(Buffer,Len,DecimalPoint); + SetLength(Buffer,Len); + if Len=0 then begin + DecimalPoint:=-FracitionalCount; + end; + result:=true; + end; + end; +var OK,Fast:boolean; + Len,DecimalPoint,ZeroPrefixLength,ZeroPostfixLength,i:longint; +begin + if BESENIsNaN(AValue) then begin + result:='NaN'; + end else if BESENIsZero(AValue) then begin + result:='0'; + end else if BESENIsNegInfinite(AValue) then begin + result:='-Infinity'; + end else if BESENIsNegative(AValue) then begin + result:='-'+BESENDoubleToString(BESENNumberAbsolute(AValue),Mode,RequestedDigits); + end else if BESENIsInfinite(AValue) then begin + result:='Infinity'; + end else begin + result:='0'; + if AValue<>0 then begin + Len:=0; + DecimalPoint:=0; + OK:=false; + Fast:=false; + if ((Mode=BESEN_DOUBLETOSTRINGMODE_FIXED) and (AValue>=1e21)) or ((Mode=BESEN_DOUBLETOSTRINGMODE_RADIX) and (RequestedDigits=10)) then begin + Mode:=BESEN_DOUBLETOSTRINGMODE_STANDARD; + end; + case Mode of + BESEN_DOUBLETOSTRINGMODE_STANDARD,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin + OK:=DoFastShortest(AValue,result,Len,DecimalPoint); + inc(DecimalPoint,Len); + end; + BESEN_DOUBLETOSTRINGMODE_FIXED:begin + OK:=DoFastFixed(AValue,RequestedDigits,result,Len,DecimalPoint); + end; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,BESEN_DOUBLETOSTRINGMODE_PRECISION:begin + if RequestedDigits<=0 then begin + OK:=DoFastShortest(AValue,result,Len,DecimalPoint); + inc(DecimalPoint,Len); + RequestedDigits:=Len-1; + end else begin + OK:=DoFastPrecision(AValue,RequestedDigits,result,Len,DecimalPoint); + inc(DecimalPoint,Len); + end; + Assert((Len>0) and (Len<=(RequestedDigits+1))); + end; + BESEN_DOUBLETOSTRINGMODE_RADIX:begin + if ((RequestedDigits>=2) and (RequestedDigits<=36)) and (BESENIsFinite(AValue) and (AValue<4294967295.0) and (System.Int(AValue)=AValue)) then begin + FastDoubleToRadix(AValue,RequestedDigits,result,Len,DecimalPoint); + Fast:=true; + OK:=true; + end; + end; + end; + if not OK then begin + case Mode of + BESEN_DOUBLETOSTRINGMODE_STANDARD,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin + DoubleToDecimal(AValue,mSHORTEST,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + BESEN_DOUBLETOSTRINGMODE_FIXED:begin + DoubleToDecimal(AValue,mFIXED,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,BESEN_DOUBLETOSTRINGMODE_PRECISION:begin + if RequestedDigits<=0 then begin + DoubleToDecimal(AValue,mSHORTEST,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + RequestedDigits:=Len-1; + end else begin + DoubleToDecimal(AValue,mPRECISION,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + Assert((Len>0) and (Len<=(RequestedDigits+1))); + end; + BESEN_DOUBLETOSTRINGMODE_RADIX:begin + if (RequestedDigits>=2) and (RequestedDigits<=36) then begin + DoubleToRadix(AValue,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + end; + end; + end; + if OK then begin + SetLength(result,Len); + case Mode of + BESEN_DOUBLETOSTRINGMODE_STANDARD:begin + if (Len<=DecimalPoint) and (DecimalPoint<=21) then begin + SetLength(result,DecimalPoint); + FillChar(result[Len+1],DecimalPoint-Len,'0'); + end else if (0<DecimalPoint) and (DecimalPoint<=21) then begin + Insert('.',result,DecimalPoint+1); + end else if (DecimalPoint<=0) and (DecimalPoint>-6) then begin + for i:=1 to -DecimalPoint do begin + result:='0'+result; + end; + result:='0.'+result; + end else begin + if Len<>1 then begin + Insert('.',result,2); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + end; + BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin + if Len<>1 then begin + Insert('.',result,2); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + BESEN_DOUBLETOSTRINGMODE_FIXED:begin + ZeroPrefixLength:=0; + ZeroPostfixLength:=0; + if DecimalPoint<=0 then begin + ZeroPrefixLength:=(-DecimalPoint)+1; + DecimalPoint:=1; + end; + if (ZeroPrefixLength+Len)<(DecimalPoint+RequestedDigits) then begin + ZeroPostfixLength:=((DecimalPoint+RequestedDigits)-Len)-ZeroPrefixLength; + end; + for i:=1 to ZeroPrefixLength do begin + result:='0'+result; + end; + for i:=1 to ZeroPostfixLength do begin + result:=result+'0'; + end; + if (RequestedDigits>0) and (DecimalPoint>0) and (DecimalPoint<=length(result)) then begin + Insert('.',result,DecimalPoint+1); + end; + end; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL:begin + if RequestedDigits<1 then begin + RequestedDigits:=1; + end; + if RequestedDigits<>1 then begin + Insert('.',result,2); + for i:=Len+1 to RequestedDigits do begin + result:=result+'0'; + end; + end else begin + SetLength(result,1); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + BESEN_DOUBLETOSTRINGMODE_PRECISION:begin + if RequestedDigits<1 then begin + RequestedDigits:=1; + end; + if (DecimalPoint<-6) or (DecimalPoint>=RequestedDigits) then begin + if RequestedDigits<>1 then begin + Insert('.',result,2); + for i:=Len+1 to RequestedDigits do begin + result:=result+'0'; + end; + end else begin + SetLength(result,1); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end else begin + if DecimalPoint<=0 then begin + for i:=1 to -DecimalPoint do begin + result:='0'+result; + end; + result:='0.'+result; + for i:=Len+1 to RequestedDigits do begin + result:=result+'0'; + end; + end else begin + SetLength(result,RequestedDigits); + for i:=Len+1 to RequestedDigits do begin + result[i]:='0'; + end; + if DecimalPoint<RequestedDigits then begin + if Len<>1 then begin + Insert('.',result,DecimalPoint+1); + end; + end; + end; + end; + end; + BESEN_DOUBLETOSTRINGMODE_RADIX:begin + if not Fast then begin + if (Len<=DecimalPoint) and (DecimalPoint<=21) then begin + SetLength(result,DecimalPoint); + FillChar(result[Len+1],DecimalPoint-Len,'0'); + end else if (0<DecimalPoint) and (DecimalPoint<=21) then begin + Insert('.',result,DecimalPoint+1); + end else if (DecimalPoint<=0) and (DecimalPoint>-6) then begin + for i:=1 to -DecimalPoint do begin + result:='0'+result; + end; + result:='0.'+result; + end else begin + if Len<>1 then begin + Insert('.',result,2); + end; + if DecimalPoint>=0 then begin + result:=result+'p+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'p-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + while (length(result)>1) and ((result[1]='0') and (result[2] in ['0'..'9','a'..'f'])) do begin + Delete(result,1,1); + end; + end; + end; + end; + end else begin + result:=''; + end; + end; + end; +end; + +function BESENNumberToString(const Value:TBESENNumber):TBESENString; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); + end; +end; + +function BESENNumberToRadixString(const Value:TBESENNumber;Radix:longint):TBESENString; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_RADIX,Radix)); + end; +end; + +function BESENFloatToStr(const Value:TBESENNumber):TBESENString; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); + end; +end; + +function BESENFloatToLocaleStr(const Value:TBESENNumber):TBESENString; +var i:integer; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToLocaleStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); + for i:=1 to length(result) do begin + case word(result[i]) of + ord('.'):begin + result[i]:=widechar(word(ord(BESENLocaleFormatSettings.DecimalSeparator))); + end; + end; + end; + end; +end; + +procedure InitBESEN; +begin + InitBESENNumberTables; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENObject.pas b/3rd/besen/src/BESENObject.pas new file mode 100644 index 000000000..d3a2b064e --- /dev/null +++ b/3rd/besen/src/BESENObject.pas @@ -0,0 +1,2513 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObject; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENSelfBalancedTree,BESENHashMap, + BESENGarbageCollector, + BESENPointerSelfBalancedTree; + +type TBESENNativeFunction=procedure(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var ResultValue:TBESENValue) of object; + + TBESENObjectPropertyContainer=class; + + TBESENObjectProperty=class(TBESENCollectorObject) + public + PropertyContainer:TBESENObjectPropertyContainer; + HashPrevious,HashNext,Previous,Next:TBESENObjectProperty; + Hash:TBESENHash; + FullHash:TBESENHash; + Index:TBESENINT32; + ID:TBESENINT32; + ArrayIndex:TBESENINT32; + PropIndex:TBESENINT32; + Key:TBESENString; + Descriptor:TBESENObjectPropertyDescriptor; + IsInSelfBalancedTree:TBESENBoolean; + SelfBalancedTreeNode:PBESENSelfBalancedTreeNode; + constructor Create(AInstance:TObject;const APropertyMap:TBESENObjectPropertyContainer;const AHash,AFullHash:TBESENHash;const AKey:TBESENString); overload; + destructor Destroy; override; + end; + + TBESENObjectProperties=array of TBESENObjectProperty; + + TBESENObjectPropertyContainerHashBucket=record + HashFirst,HashLast:TBESENObjectProperty; + end; + + TBESENObjectPropertyContainerHashBuckets=array of TBESENObjectPropertyContainerHashBucket; + + TBESENObject=class; + + TBESENObjectPropertyEnumerator=class; + + TBESENObjectPropertiesBuckets=array of TBESENObjectProperties; + + TBESENObjectPropertyContainer=class(TBESENCollectorObject) + private + procedure GrowAndRehashIfNeeded; + protected + SelfBalancedTree:TBESENSelfBalancedTree; + HashBuckets:TBESENObjectPropertyContainerHashBuckets; + HashSize:longword; + HashSizeMask:longword; + HashedItems:longword; + HashBucketsUsed:longword; + EnumeratorFirst,EnumeratorLast:TBESENObjectPropertyEnumerator; + Sorted,IsArray:longbool; + LastUsedItem:TBESENObjectProperty; + Obj:TBESENObject; + public + First,Last:TBESENObjectProperty; + Items:TBESENObjectProperties; + ItemCount:longint; + ArrayBuckets:TBESENObjectPropertiesBuckets; + ArrayItemCount:longint; + constructor Create(AInstance:TObject;ASorted:boolean;AObj:TBESENObject); overload; + destructor Destroy; override; + procedure Clear; + procedure ArraySet(Index:longint;PropertyValue:TBESENObjectProperty); + function ArrayGet(Index:longint):TBESENObjectProperty; + procedure Sort(AIsArray:boolean); + function Put(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; + function Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; + procedure Remove(const Key:TBESENString;Hash:TBESENHash=0); + function GetFirst:TBESENObjectProperty; + function GetLast:TBESENObjectProperty; + function GetPrevious(const Item:TBESENObjectProperty):TBESENObjectProperty; + function GetNext(const Item:TBESENObjectProperty):TBESENObjectProperty; + end; + + TBESENObjectPropertyEnumerator=class(TBESENCollectorObject) + public + Obj:TBESENObject; + Previous,Next,Prototype:TBESENObjectPropertyEnumerator; + NextItem:TBESENObjectProperty; + GetOnlyOwnProperties:TBESENBoolean; + GetAllProperties:TBESENBoolean; + DuplicatesHashMap:TBESENHashMap; + constructor Create(AInstance:TObject;AObj:TBESENObject;AGetOnlyOwnProperties,AGetAllProperties:TBESENBoolean); overload; virtual; + destructor Destroy; override; + procedure Reset; + function GetNext(var Key:TBESENString):boolean; + end; + + PBESENObjectStructureProperty=^TBESENObjectStructureProperty; + TBESENObjectStructureProperty=record + Index:TBESENINT32; + ID:TBESENINT32; + Attributes:TBESENObjectPropertyDescriptorAttributes; + Presents:TBESENObjectPropertyDescriptorPresents; + end; + + TBESENObjectStructureProperties=array of TBESENObjectStructureProperty; + + TBESENObjectStructure=class(TBESENCollectorObject) + public + HashPrevious,HashNext,Previous,Next:TBESENObjectStructure; + TransitionFrom:TBESENObjectStructure; + ID:TBESENINT32; + Hash:TBESENHash; + PrototypeID:TBESENINT32; + Properties:TBESENObjectStructureProperties; + ReferenceCounter:longint; + constructor Create(AInstance:TObject); override; + destructor Destroy; override; + procedure IncRef; + procedure DecRef; + function IsPrefixTo(APrototypeID:TBESENINT32;const AProperties:TBESENObjectStructureProperties;var FirstNewPropIndex:longint):TBESENBoolean; + function IsEqualTo(APrototypeID:TBESENINT32;AHash:TBESENHash;const AProperties:TBESENObjectStructureProperties):TBESENBoolean; + function ContainsStructureID(StructureID:TBESENINT32):TBESENBoolean; + function GetStructureIDFromKeyID(KeyID:TBESENINT32):TBESENINT32; + end; + + TBESENObjectStructures=array of TBESENObjectStructure; + + PBESENObjectStructureIDManagerHashBucket=^TBESENObjectStructureIDManagerHashBucket; + TBESENObjectStructureIDManagerHashBucket=record + HashFirst,HashLast:TBESENObjectStructure; + end; + + TBESENObjectStructureIDManagerHashBuckets=array[0..BESENObjectStructureIDManagerHashSize-1] of TBESENObjectStructureIDManagerHashBucket; + + TBESENObjectStructureIDManager=class(TBESENBaseObject) + private + procedure Remove(Structure:TBESENObjectStructure); + public + First,Last:TBESENObjectStructure; + IDCounter:TBESENINT32; + HashBuckets:TBESENObjectStructureIDManagerHashBuckets; + constructor Create(AInstance:TObject); override; + destructor Destroy; override; + procedure Reset; + function ResetIfNeeded:longbool; + function Get(PrototypeID:TBESENINT32;const Properties:TBESENObjectStructureProperties;OldStructure:TBESENObjectStructure):TBESENObjectStructure; + end; + + TBESENObject=class(TBESENGarbageCollectorObject) + private + procedure SetPrototypeObject(NewPrototypeObject:TBESENObject); + procedure RebuildOwnStructure; + protected + procedure InvalidateStructure; + procedure PutNew(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); + procedure PutSetter(Base:TBESENObject;const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;const Descriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue); + procedure GetGetter(Base:TBESENObject;var AResult:TBESENValue;const Descriptor:TBESENObjectPropertyDescriptor); + public + ObjectClassName:TBESENString; + ObjectName:TBESENString; + Properties:TBESENObjectPropertyContainer; + Extensible:TBESENBoolean; + PrototypeObject:TBESENObject; + PrototypeChildren:TBESENPointerSelfBalancedTree; + Structure:TBESENObjectStructure; + StructureID:TBESENINT32; + StructureHash:TBESENHash; + LastProp:TBESENObjectProperty; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; virtual; + destructor Destroy; override; + function RebuildStructure:TBESENBoolean; + procedure RegisterNativeFunction(const AName:TBESENSTRING;const ANative:TBESENNativeFunction;const Len:longint=0;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];const AHasPrototypeProperty:longbool=false); + function HasRecursivePrototypeChain:TBESENBoolean; + procedure PutPrototype(const V:TBESENValue;Throw:TBESENBoolean); + function OverwriteAccessor(const P:TBESENString;const Getter:TBESENObject=nil;const Setter:TBESENObject=nil;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; + function OverwriteData(const P:TBESENString;const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; virtual; + function GetProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; virtual; + function GetFull(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; + function GetIndex(const Index,ID:longint;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; virtual; + function GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; virtual; + function Get(const P:TBESENString;var AResult:TBESENValue;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; + function CanPut(const P:TBESENString;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); virtual; + procedure PutFull(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var Temp:TBESENValue;Hash:TBESENHash=0); + procedure PutIndex(const Index,ID:longint;const V:TBESENValue;Throw:TBESENBoolean); virtual; + procedure PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); virtual; + procedure Put(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); + function HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function HasProperty(const P:TBESENString;Hash:TBESENHash=0):TBESENBoolean; + function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function Delete(const P:TBESENString;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; + function DeleteIndex(const Index,ID:longint;Throw:TBESENBoolean):TBESENBoolean; virtual; + function DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; virtual; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function DefineOwnProperty(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; + procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); virtual; + function Enumerator(GetOnlyOwnProperties,GetAllProperties:TBESENBoolean):TBESENObjectPropertyEnumerator; virtual; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); virtual; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); virtual; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; virtual; + function GetSecurityDomain:pointer; virtual; + function HasCall:TBESENBoolean; virtual; + function HasConstruct:TBESENBoolean; virtual; + function HasHasInstance:TBESENBoolean; virtual; + function HasEnumerator:TBESENBoolean; virtual; + function HasGetSecurityDomain:TBESENBoolean; virtual; + procedure Finalize; override; + procedure Mark; override; + property Prototype:TBESENObject read PrototypeObject write SetPrototypeObject; + end; + +procedure BESENCheckObjectCoercible(const v:TBESENValue); {$ifdef caninline}inline;{$endif} + +function BESENIsCallable(const v:TBESENValue):TBESENBoolean; {$ifdef caninline}inline;{$endif} + +implementation + +uses BESEN,BESENUtils,BESENArrayUtils,BESENHashUtils,BESENStringUtils,BESENCode,BESENErrors, + BESENObjectNativeFunction; + +function SortedKeyNormal(AProp:TBESENString):TBESENString; +begin + result:=AProp; +end; + +function SortedKeyNumberic(AProp:TBESENString):TBESENString; +var i:int64; +begin + if BESENArrayToIndex(AProp,i) then begin + result:=AProp; + while length(result)<16 do begin + result:='0'+result; + end; + result:=widechar(word($feff))+result; + end else begin + result:=widechar(word($fffe))+AProp; + end; +end; + +type TSortedKeyFunc=function(AProp:TBESENString):TBESENString; + +const SortedKeyFunc:array[boolean] of TSortedKeyFunc=(SortedKeyNormal,SortedKeyNumberic); + +constructor TBESENObjectProperty.Create(AInstance:TObject;const APropertyMap:TBESENObjectPropertyContainer;const AHash,AFullHash:TBESENHash;const AKey:TBESENString); +var InsertAtItem:TBESENObjectProperty; + SelfBalancedTreeValue:TBESENSelfBalancedTreeValue; + InsertAtNode:PBESENSelfBalancedTreeNode; + v:int64; + i,j:longint; + OK:boolean; +begin + inherited Create(AInstance); + Index:=-1; + v:=0; + if TBESEN(Instance).InlineCacheEnabled then begin + if BESENArrayToIndex(AKey,v) then begin + ID:=TBESEN(Instance).KeyIDManager.Find(AKey,AFullHash); + end else begin + v:=-1; + ID:=TBESEN(Instance).KeyIDManager.Get(AKey,AFullHash); + end; + end else begin + if not BESENArrayToIndex(AKey,v) then begin + v:=-1; + end; + ID:=-1; + end; + PropIndex:=-1; + ArrayIndex:=-1; + PropertyContainer:=APropertyMap; + Hash:=AHash; + FullHash:=AFullHash; + Key:=AKey; + Descriptor.Value.ValueType:=bvtUNDEFINED; + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=[]; + Descriptor.Presents:=[]; + IsInSelfBalancedTree:=false; + SelfBalancedTreeNode:=nil; + if ID>=0 then begin + Index:=PropertyContainer.ItemCount; + inc(PropertyContainer.ItemCount); + if Index>=length(PropertyContainer.Items) then begin + SetLength(PropertyContainer.Items,Index+256); + end; + PropertyContainer.Items[Index]:=self; + end; + if PropertyContainer.IsArray then begin + if (v>=0) and (v<=$7fffffff) then begin + ArrayIndex:=v; + PropertyContainer.ArraySet(ArrayIndex,self); + end; + end; + if assigned(PropertyContainer.HashBuckets[Hash].HashFirst) then begin + PropertyContainer.HashBuckets[Hash].HashFirst.HashPrevious:=self; + HashNext:=PropertyContainer.HashBuckets[Hash].HashFirst; + HashPrevious:=nil; + PropertyContainer.HashBuckets[Hash].HashFirst:=self; + end else begin + PropertyContainer.HashBuckets[Hash].HashFirst:=self; + PropertyContainer.HashBuckets[Hash].HashLast:=self; + HashPrevious:=nil; + HashNext:=nil; + end; +{if assigned(PropertyContainer.HashBuckets[Hash].HashLast) then begin + PropertyContainer.HashBuckets[Hash].HashLast.HashNext:=self; + HashPrevious:=PropertyContainer.HashBuckets[Hash].HashLast; + HashNext:=nil; + PropertyContainer.HashBuckets[Hash].HashLast:=self; + end else begin + PropertyContainer.HashBuckets[Hash].HashFirst:=self; + PropertyContainer.HashBuckets[Hash].HashLast:=self; + HashPrevious:=nil; + HashNext:=nil; + end;} + if PropertyContainer.Sorted then begin + if assigned(PropertyContainer.First) then begin + if SortedKeyFunc[boolean(PropertyContainer.IsArray)](PropertyContainer.First.Key)>=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key) then begin + PropertyContainer.First.Previous:=self; + Previous:=nil; + Next:=PropertyContainer.First; + PropertyContainer.First:=self; + end else if SortedKeyFunc[boolean(PropertyContainer.IsArray)](PropertyContainer.Last.Key)<=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key) then begin + PropertyContainer.Last.Next:=self; + Previous:=PropertyContainer.Last; + Next:=nil; + PropertyContainer.Last:=self; + end else begin + InsertAtNode:=PropertyContainer.SelfBalancedTree.FindNearest(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)); + if assigned(InsertAtNode) then begin + InsertAtItem:=InsertAtNode^.Value.p; + if SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)<SortedKeyFunc[boolean(PropertyContainer.IsArray)](InsertAtItem.Key) then begin + Previous:=InsertAtItem.Previous; + Next:=InsertAtItem; + InsertAtItem.Previous:=self; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + PropertyContainer.First:=self; + end; + end else begin + Previous:=InsertAtItem; + Next:=InsertAtItem.Next; + InsertAtItem.Next:=self; + if assigned(Next) then begin + Next.Previous:=self; + end else begin + PropertyContainer.Last:=self; + end; + end; + end else begin + InsertAtItem:=PropertyContainer.First; + while assigned(InsertAtItem) and (SortedKeyFunc[boolean(PropertyContainer.IsArray)](InsertAtItem.Key)<=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)) do begin + InsertAtItem:=InsertAtItem.Next; + end; + if assigned(InsertAtItem) then begin + Previous:=InsertAtItem.Previous; + Next:=InsertAtItem; + InsertAtItem.Previous:=self; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + PropertyContainer.First:=self; + end; + end else begin + PropertyContainer.Last.Next:=self; + Previous:=PropertyContainer.Last; + Next:=nil; + PropertyContainer.Last:=self; + end; + end; + end; + end else begin + PropertyContainer.First:=self; + PropertyContainer.Last:=self; + Previous:=nil; + Next:=nil; + end; + SelfBalancedTreeValue.p:=self; + SelfBalancedTreeNode:=PropertyContainer.SelfBalancedTree.Insert(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key),SelfBalancedTreeValue); + if assigned(SelfBalancedTreeNode) then begin + IsInSelfBalancedTree:=true; + end; + end else begin + if assigned(PropertyContainer.Last) then begin + PropertyContainer.Last.Next:=self; + Previous:=PropertyContainer.Last; + Next:=nil; + PropertyContainer.Last:=self; + end else begin + PropertyContainer.First:=self; + PropertyContainer.Last:=self; + Previous:=nil; + Next:=nil; + end; + end; + if ID>=0 then begin + PropertyContainer.Obj.InvalidateStructure; + end; +end; + +destructor TBESENObjectProperty.Destroy; +begin + if ID>=0 then begin + PropertyContainer.Obj.InvalidateStructure; + end; + if (Index>=0) and (Index<length(PropertyContainer.Items)) then begin + PropertyContainer.Items[Index]:=nil; + end; + Index:=-1; + if ArrayIndex>=0 then begin + PropertyContainer.ArraySet(ArrayIndex,nil); + end; + ArrayIndex:=-1; + if assigned(Previous) then begin + Previous.Next:=Next; + end else if PropertyContainer.First=self then begin + PropertyContainer.First:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if PropertyContainer.Last=self then begin + PropertyContainer.Last:=Previous; + end; + Next:=nil; + Previous:=nil; + if assigned(HashPrevious) then begin + HashPrevious.HashNext:=HashNext; + end else if PropertyContainer.HashBuckets[Hash].HashFirst=self then begin + PropertyContainer.HashBuckets[Hash].HashFirst:=HashNext; + end; + if assigned(HashNext) then begin + HashNext.HashPrevious:=HashPrevious; + end else if PropertyContainer.HashBuckets[Hash].HashLast=self then begin + PropertyContainer.HashBuckets[Hash].HashLast:=HashPrevious; + end; + HashNext:=nil; + HashPrevious:=nil; + if IsInSelfBalancedTree then begin + if assigned(SelfBalancedTreeNode) then begin + SelfBalancedTreeNode.Value.p:=nil; + end; + PropertyContainer.SelfBalancedTree.Remove(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)); + IsInSelfBalancedTree:=false; + end; + Key:=''; + inherited Destroy; +end; + +constructor TBESENObjectPropertyContainer.Create(AInstance:TObject;ASorted:boolean;AObj:TBESENObject); +var Hash:TBESENHash; +begin + inherited Create(AInstance); + SelfBalancedTree:=TBESENSelfBalancedTree.Create; + FillChar(HashBuckets,sizeof(TBESENObjectPropertyContainerHashBuckets),#0); + Sorted:=ASorted; + Obj:=AObj; + Items:=nil; + ItemCount:=0; + ArrayBuckets:=nil; + ArrayItemCount:=0; + First:=nil; + Last:=nil; + EnumeratorFirst:=nil; + EnumeratorLast:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + LastUsedItem:=nil; +end; + +destructor TBESENObjectPropertyContainer.Destroy; +var Enumerator,NextEnumerator:TBESENObjectPropertyEnumerator; +begin + Enumerator:=EnumeratorFirst; + while assigned(Enumerator) do begin + NextEnumerator:=Enumerator.Next; + Enumerator.Previous:=nil; + Enumerator.Next:=nil; + BESENFreeAndNil(Enumerator); + Enumerator:=NextEnumerator; + end; + Clear; + SetLength(HashBuckets,0); + SetLength(Items,0); + ItemCount:=0; + SetLength(ArrayBuckets,0); + ArrayItemCount:=0; + SelfBalancedTree.Free; + inherited Destroy; +end; + +procedure TBESENObjectPropertyContainer.Clear; +var Hash:TBESENHash; + Item,NextItem:TBESENObjectProperty; + i:longint; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.Next; + Item.Previous:=nil; + Item.Next:=nil; + BESENFreeAndNil(Item); + Item:=NextItem; + end; + First:=nil; + Last:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + for i:=0 to length(Items)-1 do begin + Items[i]:=nil; + end; + ItemCount:=0; + for i:=0 to length(ArrayBuckets)-1 do begin + SetLength(ArrayBuckets[i],0); + end; + SetLength(ArrayBuckets,0); + ArrayItemCount:=0; + LastUsedItem:=nil; +end; + +procedure TBESENObjectPropertyContainer.ArraySet(Index:longint;PropertyValue:TBESENObjectProperty); +var BucketIndex,InBucketIndex,OldLength,Counter,NewLength:longint; +begin + if Index>=0 then begin + BucketIndex:=Index shr 16; + InBucketIndex:=Index and $ffff; + if assigned(PropertyValue) then begin + OldLength:=length(ArrayBuckets); + if OldLength<=BucketIndex then begin + SetLength(ArrayBuckets,BESENRoundUpToPowerOfTwo(BucketIndex+1)); + for Counter:=OldLength to length(ArrayBuckets)-1 do begin + ArrayBuckets[Counter]:=nil; + end; + end; + OldLength:=length(ArrayBuckets[BucketIndex]); + if OldLength<=InBucketIndex then begin + SetLength(ArrayBuckets[BucketIndex],BESENRoundUpToPowerOfTwo(InBucketIndex+1)); + for Counter:=OldLength to length(ArrayBuckets[BucketIndex])-1 do begin + ArrayBuckets[BucketIndex,Counter]:=nil; + end; + end; + ArrayBuckets[BucketIndex,InBucketIndex]:=PropertyValue; + end else begin + if BucketIndex<length(ArrayBuckets) then begin + OldLength:=length(ArrayBuckets[BucketIndex]); + if InBucketIndex<OldLength then begin + ArrayBuckets[BucketIndex,InBucketIndex]:=nil; + NewLength:=0; + for Counter:=OldLength-1 downto 0 do begin + if assigned(ArrayBuckets[BucketIndex,Counter]) then begin + NewLength:=Counter+1; + break; + end; + end; + if NewLength=0 then begin + SetLength(ArrayBuckets[BucketIndex],0); + ArrayBuckets[BucketIndex]:=nil; + end else if NewLength<>OldLength then begin + NewLength:=BESENRoundUpToPowerOfTwo(NewLength+1); + if NewLength<>OldLength then begin + SetLength(ArrayBuckets[BucketIndex],NewLength); + end; + end; + end; + OldLength:=length(ArrayBuckets); + NewLength:=0; + for Counter:=OldLength-1 downto 0 do begin + if assigned(ArrayBuckets[Counter]) then begin + NewLength:=Counter+1; + break; + end; + end; + if NewLength=0 then begin + SetLength(ArrayBuckets,0); + ArrayBuckets:=nil; + end else if NewLength<>OldLength then begin + NewLength:=BESENRoundUpToPowerOfTwo(NewLength+1); + if NewLength<>OldLength then begin + SetLength(ArrayBuckets,NewLength); + end; + end; + end; + end; + BucketIndex:=length(ArrayBuckets)-1; + if BucketIndex>=0 then begin + ArrayItemCount:=(BucketIndex shl 16)+length(ArrayBuckets[BucketIndex]); + end else begin + ArrayItemCount:=0; + end; + end; +end; + +function TBESENObjectPropertyContainer.ArrayGet(Index:longint):TBESENObjectProperty; +var BucketIndex,InBucketIndex:longint; +begin + result:=nil; + if Index>=0 then begin + BucketIndex:=Index shr 16; + InBucketIndex:=Index and $ffff; + if (BucketIndex<length(ArrayBuckets)) and (InBucketIndex<length(ArrayBuckets[BucketIndex])) then begin + result:=ArrayBuckets[BucketIndex,InBucketIndex]; + end; + end; +end; + +procedure TBESENObjectPropertyContainer.Sort(AIsArray:boolean); +var PartA,PartB,Item:TBESENObjectProperty; + InSize,PartASize,PartBSize,Merges:longint; + SelfBalancedTreeValue:TBESENSelfBalancedTreeValue; + s:TBESENString; +begin + if not Sorted then begin + IsArray:=AIsArray; + end; + if assigned(First) then begin + InSize:=1; + while true do begin + PartA:=First; + First:=nil; + Last:=nil; + Merges:=0; + while assigned(PartA) do begin + inc(Merges); + PartB:=PartA; + PartASize:=0; + while PartASize<InSize do begin + inc(PartASize); + PartB:=PartB.Next; + if not assigned(PartB) then begin + break; + end; + end; + PartBSize:=InSize; + while (PartASize>0) or ((PartBSize>0) and assigned(PartB)) do begin + if PartASize=0 then begin + Item:=PartB; + PartB:=PartB.Next; + dec(PartBSize); + end else if (PartBSize=0) or not assigned(PartB) then begin + Item:=PartA; + PartA:=PartA.Next; + dec(PartASize); + end else if SortedKeyFunc[boolean(IsArray)](PartA.Key)<=SortedKeyFunc[boolean(IsArray)](PartB.Key) then begin + Item:=PartA; + PartA:=PartA.Next; + dec(PartASize); + end else begin + Item:=PartB; + PartB:=PartB.Next; + dec(PartBSize); + end; + if assigned(Last) then begin + Last.Next:=Item; + end else begin + First:=Item; + end; + Item.Previous:=Last; + Last:=Item; + end; + PartA:=PartB; + end; + Last.Next:=nil; + if Merges<=1 then begin + break; + end; + inc(InSize,InSize); + end; + if not Sorted then begin + Item:=First; + while assigned(Item) do begin + SelfBalancedTreeValue.p:=Item; + s:=SortedKeyFunc[boolean(IsArray)](Item.Key); + Item.SelfBalancedTreeNode:=SelfBalancedTree.Insert(s,SelfBalancedTreeValue); + s:=''; + Item.IsInSelfBalancedTree:=assigned(Item.SelfBalancedTreeNode); + Item:=Item.Next; + end; + end; + end; + Sorted:=true; +end; + +procedure TBESENObjectPropertyContainer.GrowAndRehashIfNeeded; +var Hash:TBESENHash; + Item:TBESENObjectProperty; +begin + if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + inc(HashSize,HashSize); + if HashSize>BESENHashMaxSize then begin + HashSize:=BESENHashMaxSize; + end; + HashSizeMask:=HashSize-1; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashedItems:=0; + Item:=First; + while assigned(Item) do begin + inc(HashedItems); + Item.HashPrevious:=nil; + Item.HashNext:=nil; + Item:=Item.Next; + end; + HashBucketsUsed:=0; + Item:=First; + while assigned(Item) do begin + Hash:=Item.FullHash and HashSizeMask; + Item.Hash:=Hash; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast.HashNext:=Item; + Item.HashPrevious:=HashBuckets[Hash].HashLast; + HashBuckets[Hash].HashLast:=Item; + Item.HashNext:=nil; + end else begin + inc(HashBucketsUsed); + HashBuckets[Hash].HashFirst:=Item; + HashBuckets[Hash].HashLast:=Item; + Item.HashPrevious:=nil; + Item.HashNext:=nil; + end; + Item:=Item.Next; + end; + end; +end; + +function TBESENObjectPropertyContainer.Put(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; +var Item:TBESENObjectProperty; + Enumerator:TBESENObjectPropertyEnumerator; + FullHash:TBESENHash; +begin + result:=nil; + if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin + Item:=LastUsedItem; + Hash:=Item.Hash; + FullHash:=Item.FullHash; + end else begin + IF Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + FullHash:=Hash; + Hash:=Hash and HashSizeMask; + Item:=HashBuckets[Hash].HashFirst; + if not assigned(Item) then begin + inc(HashBucketsUsed); + end; + while assigned(Item) and (Item.Key<>Key) do begin + Item:=Item.Next; + end; + end; + if assigned(Item) then begin + LastUsedItem:=Item; + result:=Item; + end else begin + inc(HashedItems); + Item:=TBESENObjectProperty.Create(Instance,self,Hash,FullHash,Key); + if assigned(Item) then begin + result:=Item; + LastUsedItem:=Item; + Enumerator:=EnumeratorFirst; + while assigned(Enumerator) do begin + if not assigned(Enumerator.NextItem) then begin + Enumerator.NextItem:=Item; + end; + Enumerator:=Enumerator.Next; + end; + end; + end; + GrowAndRehashIfNeeded; +end; + +function TBESENObjectPropertyContainer.Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; +begin + if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin + result:=LastUsedItem; + Hash:=result.Hash; + end else begin + IF Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + while assigned(result) and (result.Key<>Key) do begin + result:=result.HashNext; + end; + end; + if assigned(result) then begin + LastUsedItem:=result; + if HashBuckets[Hash].HashFirst<>result then begin + if assigned(result.HashPrevious) then begin + result.HashPrevious.HashNext:=result.HashNext; + end; + if assigned(result.HashNext) then begin + result.HashNext.HashPrevious:=result.HashPrevious; + end else if HashBuckets[Hash].HashLast=result then begin + HashBuckets[Hash].HashLast:=result.HashPrevious; + end; + HashBuckets[Hash].HashFirst.HashPrevious:=result; + result.HashNext:=HashBuckets[Hash].HashFirst; + result.HashPrevious:=nil; + HashBuckets[Hash].HashFirst:=result; + end; + end; +end; + +procedure TBESENObjectPropertyContainer.Remove(const Key:TBESENString;Hash:TBESENHash=0); +var Item:TBESENObjectProperty; + Enumerator:TBESENObjectPropertyEnumerator; +begin + if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin + Item:=LastUsedItem; + end else begin + IF Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + Item:=HashBuckets[Hash].HashFirst; + while assigned(Item) and (Item.Key<>Key) do begin + Item:=Item.HashNext; + end; + end; + if assigned(Item) then begin + if LastUsedItem=Item then begin + if assigned(Item.Next) then begin + LastUsedItem:=Item.Next; + end else begin + LastUsedItem:=Item.Previous; + end; + end; + Enumerator:=EnumeratorFirst; + while assigned(Enumerator) do begin + if Enumerator.NextItem=Item then begin + Enumerator.NextItem:=Item.Next; + end; + Enumerator:=Enumerator.Next; + end; + Item.Free; + if HashedItems>0 then begin + dec(HashedItems); + end; + end; +end; + +function TBESENObjectPropertyContainer.GetFirst:TBESENObjectProperty; +begin + result:=First; +end; + +function TBESENObjectPropertyContainer.GetLast:TBESENObjectProperty; +begin + result:=Last; +end; + +function TBESENObjectPropertyContainer.GetPrevious(const Item:TBESENObjectProperty):TBESENObjectProperty; +begin + if assigned(Item) then begin + result:=Item.Previous; + end else begin + result:=nil; + end; +end; + +function TBESENObjectPropertyContainer.GetNext(const Item:TBESENObjectProperty):TBESENObjectProperty; +begin + if assigned(Item) then begin + result:=Item.Next; + end else begin + result:=nil; + end; +end; + +constructor TBESENObjectPropertyEnumerator.Create(AInstance:TObject;AObj:TBESENObject;AGetOnlyOwnProperties,AGetAllProperties:TBESENBoolean); +begin + inherited Create(AInstance); + Obj:=AObj; + GetOnlyOwnProperties:=AGetOnlyOwnProperties; + GetAllProperties:=AGetAllProperties; + DuplicatesHashMap:=TBESENHashMap.Create; + if assigned(Obj.Properties.EnumeratorLast) then begin + Obj.Properties.EnumeratorLast.Next:=self; + Previous:=Obj.Properties.EnumeratorLast; + Next:=nil; + Obj.Properties.EnumeratorLast:=self; + end else begin + Obj.Properties.EnumeratorFirst:=self; + Obj.Properties.EnumeratorLast:=self; + Previous:=nil; + Next:=nil; + end; + Prototype:=nil; + NextItem:=nil; +end; + +destructor TBESENObjectPropertyEnumerator.Destroy; +begin + BESENFreeAndNil(Prototype); + BESENFreeAndNil(DuplicatesHashMap); + if assigned(Previous) then begin + Previous.Next:=Next; + end else if Obj.Properties.EnumeratorFirst=self then begin + Obj.Properties.EnumeratorFirst:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if Obj.Properties.EnumeratorLast=self then begin + Obj.Properties.EnumeratorLast:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +procedure TBESENObjectPropertyEnumerator.Reset; +begin + if assigned(Prototype) then begin + BESENFreeAndNil(Prototype); + end; + if GetOnlyOwnProperties then begin + Prototype:=nil; + end else begin + if assigned(Obj.Prototype) then begin + Prototype:=Obj.Prototype.Enumerator(GetOnlyOwnProperties,GetAllProperties); + end else begin + Prototype:=nil; + end; + end; + NextItem:=TBESENObjectProperty(Obj.Properties.GetFirst); +end; + +function TBESENObjectPropertyEnumerator.GetNext(var Key:TBESENString):boolean; +var Prop:TBESENObjectProperty; + Hash:TBESENHash; +begin + while assigned(Prototype) do begin + if Prototype.GetNext(Key) then begin + Hash:=BESENHashKey(Key); + Prop:=Obj.Properties.Get(Key,Hash); + if assigned(Prop) then begin + if not assigned(DuplicatesHashMap.GetKey(Key,Hash)) then begin + DuplicatesHashMap.NewKey(Key,true,Hash); + if GetAllProperties or ((boppENUMERABLE in Prop.Descriptor.Presents) and (bopaENUMERABLE in Prop.Descriptor.Attributes)) then begin + result:=true; + exit; + end; + end; + end else begin + result:=true; + exit; + end; + end else begin + BESENFreeAndNil(Prototype); + Prototype:=nil; + break; + end; + end; + while assigned(NextItem) do begin + if not assigned(DuplicatesHashMap.GetKey(NextItem.Key,NextItem.FullHash)) then begin + if GetAllProperties or ((boppENUMERABLE in NextItem.Descriptor.Presents) and (bopaENUMERABLE in NextItem.Descriptor.Attributes)) then begin + Key:=NextItem.Key; + NextItem:=NextItem.Next; + result:=true; + exit; + end; + end; + NextItem:=NextItem.Next; + end; + Key:=''; + result:=false; +end; + +constructor TBESENObjectStructure.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashPrevious:=nil; + HashNext:=nil; + Previous:=nil; + Next:=nil; + TransitionFrom:=nil; + ID:=-1; + Hash:=0; + PrototypeID:=-1; + Properties:=nil; + ReferenceCounter:=0; +end; + +destructor TBESENObjectStructure.Destroy; +begin + if assigned(TransitionFrom) then begin + TransitionFrom.DecRef; + TransitionFrom:=nil; + end; + SetLength(Properties,0); + TBESEN(Instance).ObjectStructureIDManager.Remove(self); + inherited Destroy; +end; + +procedure TBESENObjectStructure.IncRef; +begin + inc(ReferenceCounter); +end; + +procedure TBESENObjectStructure.DecRef; +begin + dec(ReferenceCounter); + if ReferenceCounter<=0 then begin + Destroy; + end; +end; + +function TBESENObjectStructure.IsPrefixTo(APrototypeID:TBESENINT32;const AProperties:TBESENObjectStructureProperties;var FirstNewPropIndex:longint):TBESENBoolean; +var Transition:TBESENObjectStructure; + Transitions:TBESENObjectStructures; + TransitionCount,TransitionIndex,APropIndex,TransitionPropIndex:longint; + AProp,TransitionProp:PBESENObjectStructureProperty; +begin + result:=false; + + if PrototypeID<>APrototypeID then begin + exit; + end; + + TransitionCount:=0; + Transition:=self; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin + inc(TransitionCount); + Transition:=Transition.TransitionFrom; + end; + if assigned(Transition) and (Transition.PrototypeID<>PrototypeID) then begin + exit; + end; + + Transitions:=nil; + try + SetLength(Transitions,TransitionCount); + + TransitionIndex:=TransitionCount; + + Transition:=self; + while assigned(Transition) do begin + dec(TransitionIndex); + Transitions[TransitionIndex]:=Transition; + Transition:=Transition.TransitionFrom; + end; + + if TransitionIndex>0 then begin + SetLength(Transitions,0); + exit; + end; + + APropIndex:=0; + TransitionIndex:=0; + while (APropIndex<length(AProperties)) and (TransitionIndex<length(Transitions)) do begin + Transition:=Transitions[TransitionIndex]; + TransitionPropIndex:=0; + while (APropIndex<length(AProperties)) and (TransitionPropIndex<length(Transition.Properties)) do begin + AProp:=@AProperties[APropIndex]; + TransitionProp:=@Transition.Properties[TransitionPropIndex]; + if (AProp^.Index<>TransitionProp^.Index) or (AProp^.ID<>TransitionProp^.ID) or (AProp^.Attributes<>TransitionProp^.Attributes) or (AProp^.Presents<>TransitionProp^.Presents) then begin + SetLength(Transitions,0); + exit; + end; + inc(APropIndex); + inc(TransitionPropIndex); + end; + if TransitionPropIndex<length(Transition.Properties) then begin + SetLength(Transitions,0); + exit; + end; + inc(TransitionIndex); + end; + + if TransitionIndex<length(Transitions) then begin + SetLength(Transitions,0); + exit; + end; + + FirstNewPropIndex:=APropIndex; + + result:=true; + finally + SetLength(Transitions,0); + end; +end; + +function TBESENObjectStructure.IsEqualTo(APrototypeID:TBESENINT32;AHash:TBESENHash;const AProperties:TBESENObjectStructureProperties):TBESENBoolean; +var Transition:TBESENObjectStructure; + APropIndex,TransitionPropIndex:longint; + AProp,Prop:PBESENObjectStructureProperty; +begin + if (PrototypeID<>APrototypeID) or (Hash<>AHash) then begin + result:=false; + exit; + end; + if assigned(TransitionFrom) then begin + APropIndex:=length(AProperties)-1; + Transition:=self; + result:=true; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) and (APropIndex>=0) do begin + TransitionPropIndex:=length(Transition.Properties)-1; + while (APropIndex>=0) and (TransitionPropIndex>=0) do begin + AProp:=@AProperties[APropIndex]; + Prop:=@Transition.Properties[TransitionPropIndex]; + if (AProp^.Index<>Prop^.Index) or (AProp^.ID<>Prop^.ID) or (AProp^.Attributes<>Prop^.Attributes) or (AProp^.Presents<>Prop^.Presents) then begin + result:=false; + exit; + end; + dec(TransitionPropIndex); + dec(APropIndex); + end; + if TransitionPropIndex>=0 then begin + result:=false; + exit; + end; + Transition:=Transition.TransitionFrom; + end; + if APropIndex>=0 then begin + result:=false; + end; + end else if length(Properties)=length(AProperties) then begin + result:=true; + for APropIndex:=0 to length(AProperties)-1 do begin + AProp:=@AProperties[APropIndex]; + Prop:=@Properties[APropIndex]; + if (AProp^.Index<>Prop^.Index) or (AProp^.ID<>Prop^.ID) or (AProp^.Attributes<>Prop^.Attributes) or (AProp^.Presents<>Prop^.Presents) then begin + result:=false; + break; + end; + end; + end else begin + result:=false; + end; +end; + +function TBESENObjectStructure.ContainsStructureID(StructureID:TBESENINT32):TBESENBoolean; +var Transition:TBESENObjectStructure; +begin + result:=false; + Transition:=self; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin + if Transition.ID=StructureID then begin + result:=true; + exit; + end; + Transition:=Transition.TransitionFrom; + end; +end; + +function TBESENObjectStructure.GetStructureIDFromKeyID(KeyID:TBESENINT32):TBESENINT32; +var Transition:TBESENObjectStructure; + PropIndex:longint; +begin + result:=-1; + Transition:=self; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin + for PropIndex:=0 to length(Transition.Properties)-1 do begin + if Transition.Properties[PropIndex].ID=KeyID then begin + result:=Transition.ID; + exit; + end; + end; + Transition:=Transition.TransitionFrom; + end; +end; + +constructor TBESENObjectStructureIDManager.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; + IDCounter:=0; + FillChar(HashBuckets,sizeof(TBESENObjectStructureIDManagerHashBuckets),#0); +end; + +destructor TBESENObjectStructureIDManager.Destroy; +begin + while assigned(First) do begin + First.Free; + end; + inherited Destroy; +end; + +procedure TBESENObjectStructureIDManager.Reset; +var Code:TBESENCode; + GarbageCollectorObject:TBESENGarbageCollectorObject; + Obj:TBESENObject; +begin + try + Code:=TBESEN(Instance).CodeFirst; + while assigned(Code) do begin + Code.ResetPolymorphicInlineCacheInstructions; + Code:=Code.CodeNext; + end; + + GarbageCollectorObject:=TBESEN(Instance).GarbageCollector.First; + while assigned(GarbageCollectorObject) do begin + if GarbageCollectorObject is TBESENObject then begin + Obj:=TBESENObject(GarbageCollectorObject); + Obj.Structure:=nil; + Obj.StructureID:=0; + Obj.StructureHash:=0; + end; + GarbageCollectorObject:=GarbageCollectorObject.GarbageCollectorNext; + end; + + while assigned(First) do begin + First.Free; + end; + IDCounter:=0; + except + TBESEN(Instance).InlineCacheEnabled:=false; + end; +end; + +function TBESENObjectStructureIDManager.ResetIfNeeded:longbool; +begin + if IDCounter>=$40000000 then begin + Reset; + result:=true; + end else begin + result:=false; + end; +end; + +function TBESENObjectStructureIDManager.Get(PrototypeID:TBESENINT32;const Properties:TBESENObjectStructureProperties;OldStructure:TBESENObjectStructure):TBESENObjectStructure; +var Hash:TBESENHash; + HashBucket:PBESENObjectStructureIDManagerHashBucket; + PropIndex,FirstNewPropIndex:longint; + Prop:PBESENObjectStructureProperty; + Transitions:TBESENObjectStructures; +begin + Transitions:=nil; + try + Hash:=(2166136261 xor TBESENUINT32(PrototypeID))*1664525; + for PropIndex:=0 to length(Properties)-1 do begin + Prop:=@Properties[PropIndex]; + Hash:=((Hash+TBESENUINT32(Prop^.Index)) xor TBESENUINT32(Prop^.ID))*16777619; + Hash:=((Hash-TBESENUINT32(byte(Prop^.Attributes))) xor TBESENUINT32(byte(Prop^.Presents)))*1664525; + end; + HashBucket:=@HashBuckets[Hash and BESENObjectStructureIDManagerHashSizeMask]; + result:=HashBucket^.HashFirst; + while assigned(result) do begin + if result.IsEqualTo(PrototypeID,Hash,Properties) then begin + exit; + end; + result:=result.HashNext; + end; + result:=TBESENObjectStructure.Create(Instance); + result.PrototypeID:=PrototypeID; + result.Hash:=Hash; + inc(IDCounter); + result.ID:=IDCounter; + FirstNewPropIndex:=0; + if assigned(OldStructure) and OldStructure.IsPrefixTo(PrototypeID,Properties,FirstNewPropIndex) then begin + if FirstNewPropIndex<length(Properties) then begin + result.TransitionFrom:=OldStructure; + result.TransitionFrom.IncRef; + result.Properties:=copy(Properties,FirstNewPropIndex,length(Properties)-FirstNewPropIndex); + end else begin + result.Properties:=copy(Properties,0,length(Properties)); + end; + end else begin + result.Properties:=copy(Properties,0,length(Properties)); + end; + result.HashNext:=nil; + if assigned(HashBucket^.HashLast) then begin + HashBucket^.HashLast.HashNext:=result; + result.HashPrevious:=HashBucket^.HashLast; + HashBucket^.HashLast:=result; + end else begin + result.HashPrevious:=nil; + HashBucket^.HashFirst:=result; + HashBucket^.HashLast:=result; + end; + result.Next:=nil; + if assigned(Last) then begin + Last.Next:=result; + result.Previous:=Last; + Last:=result; + end else begin + result.Previous:=nil; + First:=result; + Last:=result; + end; + finally + SetLength(Transitions,0); + end; +end; + +procedure TBESENObjectStructureIDManager.Remove(Structure:TBESENObjectStructure); +var HashBucket:PBESENObjectStructureIDManagerHashBucket; +begin + if assigned(Structure) then begin + HashBucket:=@HashBuckets[Structure.Hash and BESENObjectStructureIDManagerHashSizeMask]; + if assigned(Structure.HashPrevious) then begin + Structure.HashPrevious.HashNext:=Structure.HashNext; + end else if HashBucket^.HashFirst=Structure then begin + HashBucket^.HashFirst:=Structure.HashNext; + end; + if assigned(Structure.HashNext) then begin + Structure.HashNext.HashPrevious:=Structure.HashPrevious; + end else if HashBucket^.HashLast=Structure then begin + HashBucket^.HashLast:=Structure.HashPrevious; + end; + Structure.HashNext:=nil; + Structure.HashPrevious:=nil; + if assigned(Structure.Previous) then begin + Structure.Previous.Next:=Structure.Next; + end else if First=Structure then begin + First:=Structure.Next; + end; + if assigned(Structure.Next) then begin + Structure.Next.Previous:=Structure.Previous; + end else if Last=Structure then begin + Last:=Structure.Previous; + end; + Structure.Next:=nil; + Structure.Previous:=nil; + end; +end; + +constructor TBESENObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance); + ObjectClassName:='Object'; + ObjectName:='object'; + + PrototypeChildren:=TBESENPointerSelfBalancedTree.Create; + + Structure:=nil; + StructureID:=0; + StructureHash:=0; + + Properties:=TBESENObjectPropertyContainer.Create(AInstance,false,self); + + PrototypeObject:=nil; + if assigned(APrototype) then begin + Prototype:=APrototype; + end; + + Extensible:=true; + + LastProp:=nil; + + if AHasPrototypeProperty and assigned(Prototype) then begin + OverwriteData('prototype',BESENObjectValueEx(Prototype),[]); + end; + + StructureID:=0; +end; + +destructor TBESENObject.Destroy; +var Node:PBESENPointerSelfBalancedTreeNode; + Obj:TBESENObject; +begin + TBESEN(Instance).GarbageCollector.FinalizeObjectForSweeping(self); + + BESENFreeAndNil(Properties); + + Prototype:=nil; + + if assigned(PrototypeChildren) then begin + Node:=PrototypeChildren.FirstKey; + while assigned(Node) do begin + Obj:=TBESENObject(Node^.Key); + if assigned(Obj) and (Obj.PrototypeObject=self) then begin + Obj.PrototypeObject:=nil; + Obj.InvalidateStructure; + end; + Node:=Node^.NextKey; + end; + end; + + BESENFreeAndNil(PrototypeChildren); + + if assigned(Structure) then begin + Structure.DecRef; + Structure:=nil; + end; + + ObjectName:=''; + ObjectClassName:=''; + inherited Destroy; +end; + +procedure TBESENObject.SetPrototypeObject(NewPrototypeObject:TBESENObject); +var Obj:TBESENObject; + Value:TBESENPointerSelfBalancedTreeValue; +begin + if assigned(NewPrototypeObject) then begin + Obj:=NewPrototypeObject; + while assigned(Obj) do begin + if Obj=self then begin + BESENThrowRcursivePrototypeChain; + end; + Obj:=Obj.Prototype; + end; + end; + if assigned(PrototypeObject) then begin + PrototypeObject.PrototypeChildren.Remove(self); + end; + PrototypeObject:=NewPrototypeObject; + if assigned(PrototypeObject) then begin + Value.p:=self; + PrototypeObject.PrototypeChildren.Insert(self,Value); + end; + InvalidateStructure; +end; + +procedure TBESENObject.InvalidateStructure; +var Node:PBESENPointerSelfBalancedTreeNode; + Obj:TBESENObject; +begin + if StructureID<>0 then begin + if assigned(PrototypeChildren) then begin + Node:=PrototypeChildren.FirstKey; + while assigned(Node) do begin + Obj:=TBESENObject(Node^.Key); + if assigned(Obj) and (Obj.PrototypeObject=self) then begin + Obj.InvalidateStructure; + end; + Node:=Node^.NextKey; + end; + end; + StructureID:=0; + end; +end; + +procedure TBESENObject.RebuildOwnStructure; +var PrototypeID:TBESENINT64; + Count,Index:longint; + Prop:TBESENObjectProperty; + StructureProperties:TBESENObjectStructureProperties; + OldStructure:TBESENObjectStructure; +begin + StructureProperties:=nil; + try + OldStructure:=Structure; + Structure:=nil; + + StructureID:=0; + StructureHash:=0; + + if TBESEN(Instance).InlineCacheEnabled then begin + + if assigned(Prototype) then begin + PrototypeID:=Prototype.StructureID; + end else begin + PrototypeID:=-1; + end; + + Count:=0; + Prop:=Properties.First; + while assigned(Prop) do begin + if Prop.ID>=0 then begin + inc(Count); + end; + Prop:=Prop.Next; + end; + SetLength(StructureProperties,Count); + Index:=0; + Prop:=Properties.First; + while assigned(Prop) do begin + if Prop.ID>=0 then begin + StructureProperties[Index].Index:=Prop.Index; + StructureProperties[Index].ID:=Prop.ID; + StructureProperties[Index].Attributes:=Prop.Descriptor.Attributes; + StructureProperties[Index].Presents:=Prop.Descriptor.Presents; + inc(Index); + end; + Prop:=Prop.Next; + end; + + Structure:=TBESEN(Instance).ObjectStructureIDManager.Get(PrototypeID,StructureProperties,OldStructure); + if assigned(Structure) then begin + Structure.IncRef; + StructureID:=Structure.ID; + StructureHash:=Structure.Hash; + end; + end; + + if assigned(OldStructure) then begin + OldStructure.DecRef; + OldStructure:=nil; + end; + finally + SetLength(StructureProperties,0); + end; +end; + +function TBESENObject.RebuildStructure:TBESENBoolean; + procedure RebuildObjectStructure(Obj:TBESENObject); + begin + if Obj.StructureID=0 then begin + if assigned(Obj.Prototype) then begin + RebuildObjectStructure(Obj.Prototype); + end; + Obj.RebuildOwnStructure; + end; + end; +begin + RebuildObjectStructure(self); + result:=not TBESEN(Instance).ObjectStructureIDManager.ResetIfNeeded; +end; + +procedure TBESENObject.RegisterNativeFunction(const AName:TBESENSTRING;const ANative:TBESENNativeFunction;const Len:longint=0;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];const AHasPrototypeProperty:longbool=false); +var o:TBESENObjectNativeFunction; +begin + o:=TBESENObjectNativeFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,AHasPrototypeProperty); + o.Native:=ANative; + o.ObjectName:=AName; + TBESEN(Instance).GarbageCollector.Add(o); + o.GarbageCollectorLock; + try + OverwriteData(AName,BESENObjectValueEx(o),Attributes,true); + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + o.OverwriteData('name',BESENStringValue(AName),[]); + end; + o.OverwriteData('length',BESENNumberValue(Len),[]); + finally + o.GarbageCollectorUnlock; + end; +end; + +function TBESENObject.HasRecursivePrototypeChain:TBESENBoolean; +var Obj:TBESENObject; +begin + result:=false; + Obj:=Prototype; + while assigned(Obj) do begin + if Obj=self then begin + result:=true; + break; + end; + Obj:=Obj.Prototype; + end; +end; + +procedure TBESENObject.PutPrototype(const V:TBESENValue;Throw:TBESENBoolean); +var Obj:TBESENObject; +begin + case V.ValueType of + bvtUNDEFINED,bvtNULL:begin + Prototype:=nil; + end; + bvtOBJECT:begin + Obj:=TBESENObject(V.Obj); + while assigned(Obj) do begin + if Obj=self then begin + if Throw then begin + BESENThrowPutRecursivePrototypeChain; + end; + exit; + end; + Obj:=Obj.Prototype; + end; + Prototype:=TBESENObject(V.Obj); + end; + else begin + if Throw then begin + BESENThrowPutInvalidPrototype; + end; + end; + end; +end; + +function TBESENObject.OverwriteAccessor(const P:TBESENString;const Getter:TBESENObject=nil;const Setter:TBESENObject=nil;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Get(P); + if assigned(Prop) then begin + if Prop.ID>=0 then begin + if (Prop.Descriptor.Attributes<>(Attributes*[bopaENUMERABLE,bopaCONFIGURABLE])) or (([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[]) then begin + InvalidateStructure; + end; + if assigned(Prop.Descriptor.Getter) then begin + if not (boppGETTER in Prop.Descriptor.Presents) then begin + InvalidateStructure; + end; + end; + if assigned(Prop.Descriptor.Setter) then begin + if not (boppSETTER in Prop.Descriptor.Presents) then begin + InvalidateStructure; + end; + end; + end; + end else begin + Prop:=Properties.Put(P); + end; + Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; + Prop.Descriptor.Getter:=Getter; + Prop.Descriptor.Setter:=Setter; + Prop.Descriptor.Attributes:=Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + Prop.Descriptor.Presents:=[boppENUMERABLE,boppCONFIGURABLE]; + if assigned(Prop.Descriptor.Getter) then begin + Prop.Descriptor.Presents:=Prop.Descriptor.Presents+[boppGETTER]; + end; + if assigned(Prop.Descriptor.Setter) then begin + Prop.Descriptor.Presents:=Prop.Descriptor.Presents+[boppSETTER]; + end; + result:=true; +end; + +function TBESENObject.OverwriteData(const P:TBESENString;const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Get(P); + if assigned(Prop) then begin + if Prop.ID>=0 then begin + if (Prop.Descriptor.Attributes<>Attributes) or (Prop.Descriptor.Presents<>[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]) then begin + InvalidateStructure; + end; + end; + end else begin + Prop:=Properties.Put(P); + end; + BESENCopyValue(Prop.Descriptor.Value,Value); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Attributes:=Attributes; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; +end; + +function TBESENObject.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Get(P,Hash); + LastProp:=Prop; + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(Descriptor.Value,Prop.Descriptor.Value); + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=Prop.Descriptor.Attributes; + Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + Descriptor.Value.ValueType:=bvtUNDEFINED; + Descriptor.Getter:=Prop.Descriptor.Getter; + Descriptor.Setter:=Prop.Descriptor.Setter; + Descriptor.Attributes:=Prop.Descriptor.Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + Descriptor.Presents:=[boppGETTER,boppSETTER,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; + end else begin + result:=false; + end; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin + if assigned(Prototype) then begin + Descriptor.Value.ValueType:=bvtOBJECT; + Descriptor.Value.Obj:=Prototype; + end else begin + Descriptor.Value.ValueType:=bvtNULL; + end; + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=[bopaWRITABLE]; + Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE,boppPROTO]; + result:=true; + end else begin + Descriptor.Presents:=[]; + result:=false; + end; +end; + +function TBESENObject.GetProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var Base:TBESENObject; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + Base:=self; + while assigned(Base) do begin + if Base.GetOwnProperty(P,Descriptor,Hash) then begin + result:=true; + exit; + end; + Base:=Base.Prototype; + end; + Descriptor.Presents:=[]; + result:=false; +end; + +procedure TBESENObject.GetGetter(Base:TBESENObject;var AResult:TBESENValue;const Descriptor:TBESENObjectPropertyDescriptor); +begin + if (boppGETTER in Descriptor.Presents) and assigned(Descriptor.Getter) then begin + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Getter),BESENObjectValue(Base),nil,0,AResult); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObject.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +var Prop:TBESENObjectProperty; +begin + if not assigned(Base) then begin + Base:=self; + end; + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(AResult,Prop.Descriptor.Value); + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + GetGetter(Base,AResult,Prop.Descriptor); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + result:=true; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin + if assigned(Prototype) then begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=Prototype; + end else begin + AResult.ValueType:=bvtNULL; + end; + result:=true; + end else begin + if assigned(Prototype) then begin + result:=Prototype.GetEx(P,AResult,Descriptor,Base,Hash); + end else begin + AResult.ValueType:=bvtUNDEFINED; + result:=false; + end; + end; +end; + +function TBESENObject.GetFull(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + result:=false; + AResult.ValueType:=bvtUNDEFINED; + if GetProperty(P,Descriptor,Hash) then begin + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + if boppVALUE in Descriptor.Presents then begin + BESENCopyValue(AResult,Descriptor.Value); + end; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if assigned(Base) then begin + GetGetter(Base,AResult,Descriptor); + end else begin + GetGetter(self,AResult,Descriptor); + end; + end; + result:=true; + end; +end; + +function TBESENObject.GetIndex(const Index,ID:longint;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +var Prop:TBESENObjectProperty; +begin + result:=false; + if not assigned(Base) then begin + Base:=self; + end; + if (Index>=0) and (Index<Properties.ItemCount) then begin + Prop:=Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(AResult,Prop.Descriptor.Value); + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + GetGetter(Base,AResult,Prop.Descriptor); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + result:=true; + exit; + end; + end; + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (TBESEN(Instance).KeyIDManager.ProtoID=ID) then begin + if assigned(Prototype) then begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=Prototype; + end else begin + AResult.ValueType:=bvtNULL; + end; + result:=true; + exit; + end else if assigned(Prototype) then begin + result:=Prototype.GetIndex(Index,ID,AResult,Base); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObject.GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + result:=Get(BESENArrayIndexToStr(Index),AResult,Base); +end; + +function TBESENObject.Get(const P:TBESENString;var AResult:TBESENValue;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if not assigned(Base) then begin + Base:=self; + end; + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + result:=GetEx(P,AResult,Descriptor,Base,Hash); +end; + +function TBESENObject.CanPut(const P:TBESENString;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + Descriptor.Presents:=[]; + if GetOwnProperty(P,OwnDescriptor) then begin + if ([boppGETTER,boppSETTER]*OwnDescriptor.Presents)<>[] then begin + result:=(boppSETTER in OwnDescriptor.Presents) and assigned(OwnDescriptor.Setter); + end else begin + result:=(boppWRITABLE in OwnDescriptor.Presents) and (bopaWRITABLE in OwnDescriptor.Attributes); + end; + end else begin + if assigned(Prototype) then begin + if Prototype.GetProperty(P,Descriptor) then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + result:=(boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter); + end else begin + result:=Extensible and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)); + end; + end else begin + result:=Extensible; + end; + end else begin + result:=Extensible; + end; + end; +end; + +procedure TBESENObject.PutNew(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Put(P,Hash); + BESENCopyValue(Prop.Descriptor.Value,V); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; +end; + +procedure TBESENObject.PutSetter(Base:TBESENObject;const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;const Descriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue); +var ValuePointers:array[0..0] of PBESENValue; +begin + if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin + ValuePointers[0]:=@v; + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BESENObjectValue(Base),@ValuePointers,1,TempValue); + end else begin + if Throw then begin + BESENThrowNoSetter(P); + end; + end; +end; + +procedure TBESENObject.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +var Prop:TBESENObjectProperty; +begin + // Optimized and combined GetOwnProperty + CanPut + DefineOwnProperty + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + if bopaWRITABLE in Prop.Descriptor.Attributes then begin + BESENCopyValue(Prop.Descriptor.Value,V); + end else begin + if Throw then begin + BESENThrowPut(P); + end; + end; + exit; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,P,V,Throw,Prop.Descriptor,TempValue); + exit; + end; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin + PutPrototype(V,Throw); + exit; + end; + + if assigned(Prototype) then begin + if Prototype.GetProperty(P,Descriptor) then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + PutSetter(self,P,V,Throw,Descriptor,TempValue); + exit; + end else begin + if not (Extensible and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes))) then begin + if Throw then begin + BESENThrowPut(P); + end; + exit; + end; + end; + end; + end; + + if Extensible then begin + PutNew(P,V,Throw,Hash); + exit; + end; + + if Throw then begin + BESENThrowPut(P); + end; +end; + +procedure TBESENObject.PutFull(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var Temp:TBESENValue;Hash:TBESENHash=0); +var ValuePointers:array[0..0] of PBESENValue; +begin + if CanPut(P,Descriptor,OwnDescriptor,Hash) then begin + if boppPROTO in OwnDescriptor.Presents then begin + PutPrototype(V,Throw); + end else if ([boppVALUE,boppWRITABLE]*OwnDescriptor.Presents)<>[] then begin + BESENCopyValue(OwnDescriptor.Value,V); + OwnDescriptor.Getter:=nil; + OwnDescriptor.Setter:=nil; + OwnDescriptor.Attributes:=[]; + OwnDescriptor.Presents:=[boppVALUE]; + DefineOwnPropertyEx(P,OwnDescriptor,Throw,Descriptor,Hash); + end else begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin + ValuePointers[0]:=@V; + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BESENObjectValue(self),@ValuePointers,1,Temp); + end else begin + if Throw then begin + BESENThrowNoSetter(P); + end; + end; + end else begin + BESENCopyValue(OwnDescriptor.Value,v); + OwnDescriptor.Getter:=nil; + OwnDescriptor.Setter:=nil; + OwnDescriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; + OwnDescriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + DefineOwnPropertyEx(P,OwnDescriptor,Throw,Descriptor,Hash); + end; + end; + end else begin + if Throw then begin + BESENThrowPut(P); + end; + end; +end; + +procedure TBESENObject.PutIndex(const Index,ID:longint;const V:TBESENValue;Throw:TBESENBoolean); + procedure ThrowIt; + begin + BESENThrowTypeError('Put failed'); + end; + procedure PutSetter(Obj:TBESENObject;Prop:TBESENObjectProperty); + var TempValue:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; + begin + if (boppSETTER in Prop.Descriptor.Presents) and assigned(Prop.Descriptor.Setter) then begin + ValuePointers[0]:=@V; + TBESEN(Instance).ObjectCall(TBESENObject(Prop.Descriptor.Setter),BESENObjectValue(Obj),@ValuePointers,1,TempValue); + exit; + end; + if Throw then begin + BESENThrowNoSetter(Prop.Key); + end; + end; +var Obj:TBESENObject; + Prop:TBESENObjectProperty; +begin + if (Index>=0) and (Index<Properties.ItemCount) then begin + Prop:=Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + if bopaWRITABLE in Prop.Descriptor.Attributes then begin + BESENCopyValue(Prop.Descriptor.Value,V); + end else begin + if Throw then begin + BESENThrowPut(Prop.Key); + end; + end; + exit; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,Prop); + exit; + end; + end; + end; + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (ID=TBESEN(Instance).KeyIDManager.ProtoID) then begin + PutPrototype(V,Throw); + exit; + end; + Prop:=nil; + Obj:=Prototype; + while assigned(Obj) do begin + if (Index>=0) and (Index<Obj.Properties.ItemCount) then begin + Prop:=Obj.Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) and (([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[]) then begin + break; + end; + end; + Obj:=Obj.Prototype; + end; + if assigned(Obj) and assigned(Prop) then begin + if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,Prop); + exit; + end else begin + if not (Extensible and ((boppWRITABLE in Prop.Descriptor.Presents) and (bopaWRITABLE in Prop.Descriptor.Attributes))) then begin + if Throw then begin + BESENThrowPut(Prop.Key); + end; + exit; + end; + end; + end else begin + Obj:=self; + end; + if Extensible then begin + PutNew(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end; + if Throw then begin + ThrowIt; + end; +end; + +procedure TBESENObject.PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); +begin + Put(BESENArrayIndexToStr(Index),V,Throw); +end; + +procedure TBESENObject.Put(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); +var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; + Temp:TBESENValue; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + PutEx(P,V,Throw,Descriptor,OwnDescriptor,Temp,Hash); +end; + +function TBESENObject.HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=GetProperty(P,Descriptor,Hash); +end; + +function TBESENObject.HasProperty(const P:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + result:=HasPropertyEx(P,Descriptor,Hash); +end; + +function TBESENObject.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; + procedure ThrowIt; + begin + BESENThrowTypeError('Delete for "'+P+'" failed'); + end; +begin + if GetOwnProperty(P,Descriptor,Hash) then begin + if boppPROTO in Descriptor.Presents then begin + Prototype:=nil; + result:=true; + end else if (boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes) then begin + Properties.Remove(P,Hash); + result:=true; + end else begin + if Throw then begin + ThrowIt; + end; + result:=false; + end; + end else begin + result:=true; + end; +end; + +function TBESENObject.Delete(const P:TBESENString;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + result:=DeleteEx(P,Throw,Descriptor,Hash); +end; + +function TBESENObject.DeleteIndex(const Index,ID:longint;Throw:TBESENBoolean):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; + Prop:TBESENObjectProperty; +begin + if (Index>=0) and (Index<Properties.ItemCount) then begin + Prop:=Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) then begin + result:=DeleteEx(Prop.Key,Throw,Descriptor); + exit; + end; + end; + result:=DeleteEx(TBESEN(Instance).KeyIDManager.List[ID],Throw,Descriptor); +end; + +function TBESENObject.DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; +begin + result:=Delete(BESENArrayIndexToStr(Index),Throw); +end; + +function TBESENObject.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var Prop:TBESENObjectProperty; + CurrentResult:boolean; + procedure ThrowIt; + begin + BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); + end; +begin + result:=false; + CurrentResult:=GetOwnProperty(P,Current,Hash); + if not CurrentResult then begin + if Extensible then begin + if (([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Descriptor.Presents)=[]) or (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin + Prop:=Properties.Get(P,Hash); + if not assigned(Prop) then begin + Prop:=Properties.Put(P,Hash); + end; + BESENCopyValue(Prop.Descriptor.Value,Descriptor.Value); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Attributes:=Descriptor.Attributes; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; + result:=true; + exit; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + Prop:=Properties.Get(P,Hash); + if not assigned(Prop) then begin + Prop:=Properties.Put(P,Hash); + end; + Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; + Prop.Descriptor.Getter:=Descriptor.Getter; + Prop.Descriptor.Setter:=Descriptor.Setter; + Prop.Descriptor.Attributes:=Descriptor.Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + Prop.Descriptor.Presents:=[boppGETTER,boppSETTER,boppENUMERABLE,boppCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; + result:=true; + exit; + end; + end else begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + if Descriptor.Presents=[] then begin + result:=true; + exit; + end; + if boppPROTO in Current.Presents then begin + if ((([boppGETTER,boppSETTER]*Descriptor.Presents)=[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[])) and (boppVALUE in Descriptor.Presents) then begin + PutPrototype(Descriptor.Value,Throw); + result:=true; + end else begin + if Throw then begin + ThrowIt; + end; + end; + result:=true; + exit; + end; + if ((Descriptor.Presents*Current.Presents)=Descriptor.Presents) and + (((boppVALUE in Descriptor.Presents) and TBESEN(Instance).SameValue(Descriptor.Value,Current.Value)) or not (boppVALUE in Descriptor.Presents)) and + (((boppGETTER in Descriptor.Presents) and TBESEN(Instance).SameObject(TBESENObject(Descriptor.Getter),TBESENObject(Current.Getter))) or not (boppGETTER in Descriptor.Presents)) and + (((boppSETTER in Descriptor.Presents) and TBESEN(Instance).SameObject(TBESENObject(Descriptor.Setter),TBESENObject(Current.Setter))) or not (boppSETTER in Descriptor.Presents)) and + (((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppWRITABLE in Descriptor.Presents)) and + (((boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppENUMERABLE in Descriptor.Presents)) and + (((boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppCONFIGURABLE in Descriptor.Presents)) then begin + result:=true; + exit; + end; + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if (((boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes))) or + ((((boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in Descriptor.Attributes)))<>(((boppENUMERABLE in Current.Presents) and (bopaENUMERABLE in Current.Attributes)))) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + if ([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Descriptor.Presents)=[] then begin + end else if (([boppVALUE,boppWRITABLE]*Current.Presents)<>[])<>(([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + if ([boppVALUE,boppWRITABLE]*Current.Presents)<>[] then begin + Current.Value.ValueType:=bvtUNDEFINED; + Current.Getter:=nil; + Current.Setter:=nil; + Current.Attributes:=Current.Attributes*[bopaCONFIGURABLE,bopaENUMERABLE]; + Current.Presents:=Current.Presents*[boppCONFIGURABLE,boppENUMERABLE]; + end else begin + Current.Value.ValueType:=bvtUNDEFINED; + Current.Getter:=nil; + Current.Setter:=nil; + Current.Attributes:=Current.Attributes*[bopaCONFIGURABLE,bopaENUMERABLE]; + Current.Presents:=(Current.Presents*[boppCONFIGURABLE,boppENUMERABLE])+[boppVALUE]; + end; + end else if (([boppVALUE,boppWRITABLE]*Current.Presents)<>[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if (((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)) or + ((boppVALUE in Descriptor.Presents) and not (((boppVALUE in Current.Presents) and TBESEN(Instance).SameValue(Descriptor.Value,Current.Value)) or + (TBESEN(Instance).SameValue(Descriptor.Value,BESENUndefinedValue) and not (boppVALUE in Current.Presents))))) and not + ((boppWRITABLE in Current.Presents) and (bopaWRITABLE in Current.Attributes)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + end else if (([boppGETTER,boppSETTER]*Current.Presents)<>[]) and (([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) then begin + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if boppSETTER in Descriptor.Presents then begin + if boppSETTER in Current.Presents then begin + if not TBESEN(Instance).SameObject(TBESENObject(Descriptor.Setter),TBESENObject(Current.Setter)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end else begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + if boppGETTER in Descriptor.Presents then begin + if boppGETTER in Current.Presents then begin + if not TBESEN(Instance).SameObject(TBESENObject(Descriptor.Getter),TBESENObject(Current.Getter)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end else begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + end; + end; + if boppVALUE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppVALUE]; + BESENCopyValue(Current.Value,Descriptor.Value); + end; + if boppGETTER in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppGETTER]; + Current.Getter:=Descriptor.Getter; + end; + if boppSETTER in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppSETTER]; + Current.Setter:=Descriptor.Setter; + end; + if boppWRITABLE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppWRITABLE]; + Current.Attributes:=(Current.Attributes-[bopaWRITABLE])+(Descriptor.Attributes*[bopaWRITABLE]); + end; + if boppENUMERABLE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppENUMERABLE]; + Current.Attributes:=(Current.Attributes-[bopaENUMERABLE])+(Descriptor.Attributes*[bopaENUMERABLE]); + end; + if boppCONFIGURABLE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppCONFIGURABLE]; + Current.Attributes:=(Current.Attributes-[bopaCONFIGURABLE])+(Descriptor.Attributes*[bopaCONFIGURABLE]); + end; + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if (Prop.ID>=0) and ((Prop.Descriptor.Attributes<>Current.Attributes) or (Prop.Descriptor.Presents<>Current.Presents)) then begin + InvalidateStructure; + end; + end else begin + Prop:=Properties.Put(P,Hash); + end; + BESENCopyValue(Prop.Descriptor.Value,Current.Value); + Prop.Descriptor.Getter:=Current.Getter; + Prop.Descriptor.Setter:=Current.Setter; + Prop.Descriptor.Attributes:=Current.Attributes; + Prop.Descriptor.Presents:=Current.Presents; + result:=true; +end; + +function TBESENObject.DefineOwnProperty(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; +var Current:TBESENObjectPropertyDescriptor; +begin + result:=DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); +end; + +procedure TBESENObject.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); +var EffectiveHint:TBESENObject; + v:TBESENValue; + procedure ThrowIt; + begin + raise EBESENTypeError.Create('Bad default value'); + end; +begin + case AHint.ValueType of + bvtNUMBER:begin + EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; + end; + bvtSTRING:begin + EffectiveHint:=TBESEN(Instance).ObjectStringConstructor; + end; + bvtOBJECT:begin + if (AHint.Obj=TBESEN(Instance).ObjectNumberConstructor) or (AHint.Obj=TBESEN(Instance).ObjectStringConstructor) then begin + EffectiveHint:=TBESENObject(AHint.Obj); + end else if AHint.Obj=TBESEN(Instance).ObjectDateConstructor then begin + EffectiveHint:=TBESEN(Instance).ObjectStringConstructor; + end else begin + EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; + end; + end else begin + EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; + end; + end; + if EffectiveHint=TBESEN(Instance).ObjectStringConstructor then begin + Get('toString',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + Get('valueOf',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + AResult:=BESENStringValue('[object '+inttostr(ptruint(self))+']'); + end else begin + ThrowIt; + end; + end else if EffectiveHint=TBESEN(Instance).ObjectNumberConstructor then begin + Get('valueOf',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + Get('toString',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + AResult:=BESENStringValue('[object '+inttostr(ptruint(self))+']'); + end else begin + ThrowIt; + end; + end else begin + ThrowIt; + end; +end; + +function TBESENObject.Enumerator(GetOnlyOwnProperties,GetAllProperties:TBESENBoolean):TBESENObjectPropertyEnumerator; +begin + result:=TBESENObjectPropertyEnumerator.Create(Instance,self,GetOnlyOwnProperties,GetAllProperties); +end; + +procedure TBESENObject.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +procedure TBESENObject.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +function TBESENObject.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.GetSecurityDomain:pointer; +begin + result:=nil; +end; + +function TBESENObject.HasCall:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasConstruct:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasHasInstance:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasEnumerator:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasGetSecurityDomain:TBESENBoolean; +begin + result:=false; +end; + +procedure TBESENObject.Finalize; +var CurrentItem:TBESENObjectProperty; +begin + Prototype:=nil; + CurrentItem:=Properties.GetFirst; + while assigned(CurrentItem) do begin + TBESEN(Instance).GarbageCollector.FinalizeValue(CurrentItem.Descriptor.Value); + CurrentItem:=CurrentItem.Next; + end; + Properties.Clear; + inherited Finalize; +end; + +procedure TBESENObject.Mark; +var CurrentItem:TBESENObjectProperty; +begin + TBESEN(Instance).GarbageCollector.GrayIt(Prototype); + CurrentItem:=Properties.First; + while assigned(CurrentItem) do begin + TBESEN(Instance).GarbageCollector.GrayValue(CurrentItem.Descriptor.Value); + TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(CurrentItem.Descriptor.Getter)); + TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(CurrentItem.Descriptor.Setter)); + CurrentItem:=CurrentItem.Next; + end; + inherited Mark; +end; + +procedure BESENCheckObjectCoercible(const v:TBESENValue); {$ifdef caninline}inline;{$endif} +begin + case v.ValueType of + bvtUNDEFINED,bvtNULL,bvtREFERENCE,bvtLOCAL:begin + BESENThrowTypeError('CheckObjectCoercible failed'); + end; + end; +end; + +function BESENIsCallable(const v:TBESENValue):TBESENBoolean; {$ifdef caninline}inline;{$endif} +begin + result:=(v.ValueType=bvtOBJECT) and (assigned(v.Obj) and TBESENObject(v.Obj).HasCall); +end; + +end. diff --git a/3rd/besen/src/BESENObjectArgGetterFunction.pas b/3rd/besen/src/BESENObjectArgGetterFunction.pas new file mode 100644 index 000000000..c0c517f51 --- /dev/null +++ b/3rd/besen/src/BESENObjectArgGetterFunction.pas @@ -0,0 +1,94 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArgGetterFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; + +type TBESENObjectArgGetterFunction=class(TBESENObjectFunction) + public + Env:TBESENEnvironmentRecord; + ArgName:TBESENString; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENHashUtils; + +constructor TBESENObjectArgGetterFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='ArgGetter'; + Env:=nil; + ArgName:=''; +end; + +destructor TBESENObjectArgGetterFunction.Destroy; +begin + Env:=nil; + ArgName:=''; + inherited Destroy; +end; + +procedure TBESENObjectArgGetterFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Env.GetBindingValue(ArgName,true,AResult,BESENHashKey(ArgName)); +end; + +function TBESENObjectArgGetterFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectArgGetterFunction.Finalize; +begin + Env:=nil; + inherited Finalize; +end; + +procedure TBESENObjectArgGetterFunction.Mark; +begin + if assigned(Env) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Env); + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectArgSetterFunction.pas b/3rd/besen/src/BESENObjectArgSetterFunction.pas new file mode 100644 index 000000000..2f95ebfbf --- /dev/null +++ b/3rd/besen/src/BESENObjectArgSetterFunction.pas @@ -0,0 +1,99 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArgSetterFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; + +type TBESENObjectArgSetterFunction=class(TBESENObjectFunction) + public + Env:TBESENEnvironmentRecord; + ArgName:TBESENString; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENHashUtils; + +constructor TBESENObjectArgSetterFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='ArgSetter'; + Env:=nil; + ArgName:=''; +end; + +destructor TBESENObjectArgSetterFunction.Destroy; +begin + Env:=nil; + ArgName:=''; + inherited Destroy; +end; + +procedure TBESENObjectArgSetterFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments<1 then begin + Env.SetMutableBinding(ArgName,BESENUndefinedValue,true,BESENHashKey(ArgName)); + end else begin + Env.SetMutableBinding(ArgName,Arguments^[0]^,true,BESENHashKey(ArgName)); + end; + AResult.ValueType:=bvtUNDEFINED; +end; + +function TBESENObjectArgSetterFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectArgSetterFunction.Finalize; +begin + Env:=nil; + inherited Finalize; +end; + +procedure TBESENObjectArgSetterFunction.Mark; +begin + if assigned(Env) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Env); + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectArray.pas b/3rd/besen/src/BESENObjectArray.pas new file mode 100644 index 000000000..6520bb2df --- /dev/null +++ b/3rd/besen/src/BESENObjectArray.pas @@ -0,0 +1,362 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArray; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectArray=class(TBESENObject) + private + ArrayLength:TBESENUINT32; + function ToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; + function GetLen:TBESENUINT32; + procedure SetLen(NewLen:TBESENUINT32); + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; + procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); override; + function DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + procedure Push(const AValue:TBESENValue); + property Len:TBESENUINT32 read GetLen write SetLen; + end; + +implementation + +uses BESEN,BESENUtils,BESENArrayUtils,BESENHashUtils,BESENGlobals, + BESENNumberUtils,BESENErrors; + +constructor TBESENObjectArray.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Array'; + ObjectName:='array'; + Len:=0; + ArrayLength:=0; + + Properties.Sort(true); + + inherited OverwriteData('length',BESENNumberValue(0),[bopaWRITABLE]); +end; + +destructor TBESENObjectArray.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectArray.ToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; +begin + result:=BESENArrayToIndex(AProp,v); +end; + +{procedure TBESENObjectArray.SetLen(const AValue:TBESENValue); +var NewLen,i:TBESENUInt32; +begin + NewLen:=TBESEN(Instance).ToUInt32(AValue); + if Len>NewLen then begin + for i:=Len+1 to NewLen do begin + inherited Delete(IndexToStr(i-1),true); + end; + end; + Len:=NewLen; +end;} + +function TBESENObjectArray.GetLen:TBESENUINT32; +var LenDesc:TBESENObjectPropertyDescriptor; +begin + GetOwnProperty('length',LenDesc,BESENLengthHash); + result:=TBESEN(Instance).ToUINT32(LenDesc.Value); + ArrayLength:=result; +end; + +procedure TBESENObjectArray.SetLen(NewLen:TBESENUINT32); +begin + ArrayLength:=NewLen; + inherited OverwriteData('length',BESENNumberValue(NewLen),[bopaWRITABLE]); +end; + +procedure TBESENObjectArray.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +var Index:int64; + Prop:TBESENObjectProperty; +begin + // Trying faster pre-catching implementation first + if ToIndex(P,Index) then begin + if (Index>=0) and (Index<ArrayLength) then begin + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if (([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[]) and (bopaWRITABLE in Prop.Descriptor.Attributes) then begin + BESENCopyValue(Prop.Descriptor.Value,v); + exit; + end; + end else if Extensible then begin + Prop:=Properties.Put(P,Hash); + if assigned(Prop) then begin + BESENCopyValue(Prop.Descriptor.Value,v); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; + exit; + end; + end; + end; + end; + + // Fallback to specification-conformant implementation + PutFull(P,V,Throw,Descriptor,OwnDescriptor,TempValue,Hash); +end; + +procedure TBESENObjectArray.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); +begin + if ID=TBESEN(Instance).KeyIDManager.LengthID then begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end else if ((Index>=0) and (Index<Properties.ItemCount)) and assigned(Properties.Items[Index]) and (Properties.Items[Index].ID=ID) then begin + inherited PutIndex(Index,ID,V,Throw); + end else begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end; +end; + +function TBESENObjectArray.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var OldLenDesc,NewLenDesc:TBESENObjectPropertyDescriptor; + NewLen,OldLen:TBESENUInt32; + NewWritable:boolean; + Index:int64; + Num:double; +begin + GetOwnProperty('length',OldLenDesc,BESENLengthHash); + OldLen:=TBESEN(Instance).ToUINT32(OldLenDesc.Value); + if P='length' then begin + if not (boppVALUE in Descriptor.Presents) then begin + result:=inherited DefineOwnPropertyEx('length',Descriptor,Throw,Current,BESENLengthHash); + exit; + end; + NewLenDesc:=Descriptor; + NewLen:=TBESEN(Instance).ToUInt32(Descriptor.Value); + Num:=TBESEN(Instance).ToNum(Descriptor.Value); + if (NewLen<>Num) or not BESENIsFinite(Num) then begin + raise EBESENRangeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end; + if NewLen>=OldLen then begin + ArrayLength:=NewLen; + result:=inherited DefineOwnPropertyEx('length',Descriptor,Throw,Current,BESENLengthHash); + exit; + end; + if not ((boppWRITABLE in OldLenDesc.Presents) and (bopaWRITABLE in OldLenDesc.Attributes)) then begin + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + if ((boppWRITABLE in NewLenDesc.Presents) and (bopaWRITABLE in NewLenDesc.Attributes)) or not (bopaWRITABLE in NewLenDesc.Attributes) then begin + NewWritable:=true; + end else begin + NewWritable:=false; + NewLenDesc.Presents:=NewLenDesc.Presents+[boppWRITABLE]; + NewLenDesc.Attributes:=NewLenDesc.Attributes+[bopaWRITABLE]; + end; + result:=inherited DefineOwnPropertyEx('length',NewLenDesc,Throw,Current,BESENLengthHash); + if not result then begin + exit; + end; + ArrayLength:=NewLen; + while NewLen<OldLen do begin + dec(OldLen); + if not Delete(BESENArrayIndexToStr(OldLen),false) then begin + NewLenDesc.Value:=BESENNumberValue(OldLen+1); + if not NewWritable then begin + NewLenDesc.Attributes:=NewLenDesc.Attributes-[bopaWRITABLE]; + end; + inherited DefineOwnPropertyEx('length',NewLenDesc,false,Current,BESENLengthHash); + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + end; + if not NewWritable then begin + NewLenDesc:=BESENUndefinedPropertyDescriptor; + NewLenDesc.Presents:=NewLenDesc.Presents+[boppWRITABLE]; + NewLenDesc.Attributes:=NewLenDesc.Attributes-[bopaWRITABLE]; + inherited DefineOwnPropertyEx('length',NewLenDesc,false,Current,BESENLengthHash); + end; + result:=true; + end else if ToIndex(P,Index) then begin + if (Index>=OldLen) and not ((boppWRITABLE in OldLenDesc.Presents) and (bopaWRITABLE in OldLenDesc.Attributes)) then begin + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + result:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); + if not result then begin + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + if Index>=OldLen then begin + ArrayLength:=Index+1; + OldLenDesc.Value:=BESENNumberValue(Index+1); + inherited DefineOwnPropertyEx('length',OldLenDesc,false,Current,BESENLengthHash); + end; + result:=true; + end else begin + result:=inherited DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); + end; +end; + +function TBESENObjectArray.GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; + function Fallback:boolean; + begin + result:=Get(BESENArrayIndexToStr(Index),AResult,Base); + end; +var Prop:TBESENObjectProperty; +begin + result:=false; + if not assigned(Base) then begin + Base:=self; + end; + if Index<TBESENUINT32(Properties.ArrayItemCount) then begin + Prop:=Properties.ArrayGet(Index); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(AResult,Prop.Descriptor.Value); + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + GetGetter(Base,AResult,Prop.Descriptor); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + result:=true; + exit; + end; + end; + result:=Fallback; +end; + +procedure TBESENObjectArray.PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); + procedure Fallback; + begin + Put(BESENArrayIndexToStr(Index),V,Throw); + end; + procedure PutSetter(Obj:TBESENObject;Prop:TBESENObjectProperty); + var TempValue:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; + begin + if (boppSETTER in Prop.Descriptor.Presents) and assigned(Prop.Descriptor.Setter) then begin + ValuePointers[0]:=@V; + TBESEN(Instance).ObjectCall(TBESENObject(Prop.Descriptor.Setter),BESENObjectValue(Obj),@ValuePointers,1,TempValue); + exit; + end; + if Throw then begin + BESENThrowNoSetter(Prop.Key); + end; + end; +var Prop:TBESENObjectProperty; +begin + if Index<TBESENUINT32(Properties.ArrayItemCount) then begin + Prop:=Properties.ArrayGet(Index); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + if bopaWRITABLE in Prop.Descriptor.Attributes then begin + BESENCopyValue(Prop.Descriptor.Value,V); + end else begin + if Throw then begin + BESENThrowPut(Prop.Key); + end; + end; + exit; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,Prop); + exit; + end; + end; + end; + Fallback; +end; + +function TBESENObjectArray.DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; + function Fallback:boolean; + begin + result:=Delete(BESENArrayIndexToStr(Index),Throw); + end; +var Prop:TBESENObjectProperty; +begin + if Index<TBESENUINT32(Properties.ArrayItemCount) then begin + Prop:=Properties.ArrayGet(Index); + if assigned(Prop) then begin + result:=Delete(Prop.Key,Throw); + exit; + end; + end; + result:=Fallback; +end; + +procedure TBESENObjectArray.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectArray.Mark; +begin + inherited Mark; +end; + +procedure TBESENObjectArray.Push(const AValue:TBESENValue); +var v,tv:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; +begin + Get('push',v); + if (v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall then begin + ValuePointers[0]:=@AValue; + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),@ValuePointers,1,tv); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectArrayConstructor.pas b/3rd/besen/src/BESENObjectArrayConstructor.pas new file mode 100644 index 000000000..28dd8c1b4 --- /dev/null +++ b/3rd/besen/src/BESENObjectArrayConstructor.pas @@ -0,0 +1,123 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArrayConstructor; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectArrayConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeIsArray(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENGlobals,BESENObjectArray,BESENNumberUtils,BESENErrors; + +constructor TBESENObjectArrayConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + + ObjectClassName:='Function'; + ObjectName:='Array'; + + RegisterNativeFunction('isArray',NativeIsArray,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectArrayConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectArrayConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectArray; + r3:TBESENValue; + l:int64; + i:integer; +begin + r3:=BESENEmptyValue; + r1:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + if CountArguments>0 then begin + r1.GarbageCollectorLock; + try + if (CountArguments=1) and (Arguments^[0]^.ValueType=bvtNUMBER) then begin + r3:=Arguments^[0]^; + l:=TBESEN(Instance).ToUInt32(r3); + if (l<>r3.Num) or not BESENIsFinite(r3.Num) then begin + raise EBESENRangeError.Create('Bad array length'); + end; + r1.Put('length',r3,true,BESENLengthHash); + end else begin + for i:=0 to CountArguments-1 do begin + r1.DefineOwnProperty(inttostr(i),BESENDataPropertyDescriptor(Arguments^[i]^,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + end; + r3:=BESENNumberValue(CountArguments); + r1.Put('length',r3,true,BESENLengthHash); + end; + finally + r1.GarbageCollectorUnlock; + end; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectArrayConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectArrayConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectArrayConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectArrayConstructor.NativeIsArray(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=(CountArguments>0) and (((Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) and (TBESENObject(Arguments^[0]^.Obj).ObjectClassName='Array')); +end; + +end. diff --git a/3rd/besen/src/BESENObjectArrayPrototype.pas b/3rd/besen/src/BESENObjectArrayPrototype.pas new file mode 100644 index 000000000..70de1ac16 --- /dev/null +++ b/3rd/besen/src/BESENObjectArrayPrototype.pas @@ -0,0 +1,1330 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArrayPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectArray,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectArrayPrototype=class(TBESENObjectArray) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeJoin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReverse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeShift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSort(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSplice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeUnshift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEvery(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSome(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeForEach(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMap(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFilter(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReduce(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReduceRight(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENGlobals,BESENArrayUtils,BESENHashUtils,BESENNumberUtils,BESENStringUtils,BESENLocale; + +constructor TBESENObjectArrayPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Array'; + ObjectName:='Array'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('concat',NativeConcat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('join',NativeJoin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('pop',NativePop,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('push',NativePush,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('reverse',NativeReverse,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('shift',NativeShift,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('slice',NativeSlice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sort',NativeSort,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('splice',NativeSplice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('unshift',NativeUnshift,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('indexOf',NativeIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('lastIndexOf',NativeLastIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('every',NativeEvery,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('some',NativeSome,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('forEach',NativeForEach,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('map',NativeMap,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('filter',NativeFilter,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('reduce',NativeReduce,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('reduceRight',NativeReduceRight,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectArrayPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectArrayPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,ov:TBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('join',v); + if BESENIsCallable(v) then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),ThisArgument,nil,0,ResultValue); + end else begin + TBESEN(Instance).ObjectPrototype.NativeToString(ThisArgument,Arguments,CountArguments,ResultValue); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v,vo,vs:TBESENValue; + i,l:int64; + Separator,s:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + Separator:=BESENLocaleFormatSettings.ListSeparator; + s:=''; + if l>0 then begin + i:=0; + while i<l do begin + if i>0 then begin + s:=s+Separator; + end; + TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(i),v); + TBESEN(Instance).ToObjectValue(v,vo); + if (vo.ValueType<>bvtOBJECT) or not assigned(TBESENObject(vo.Obj)) then begin + raise EBESENTypeError.Create('No valid object'); + end; + TBESENObject(vo.Obj).Get('toLocaleString',v); + if (v.ValueType<>bvtOBJECT) or not (assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall) then begin + raise EBESENTypeError.Create('No callable'); + end; + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),vo,nil,0,vs); + if v.ValueType<>bvtSTRING then begin + raise EBESENTypeError.Create('No string'); + end; + s:=s+TBESEN(Instance).ToStr(vs); + inc(i); + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectArrayPrototype.NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var a,eA:TBESENObjectArray; + ov,e,v:TBESENValue; + l:int64; + pk:TBESENString; + k,n:int64; + i:integer; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + e:=BESENEmptyValue; + e:=BESENObjectValue(TBESENObject(ov.Obj)); + n:=0; + i:=0; + while true do begin + if (e.ValueType=bvtOBJECT) and assigned(e.Obj) and (e.Obj is TBESENObjectArray) then begin + eA:=TBESENObjectArray(e.Obj); + eA.Get('length',v,eA,BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + k:=0; + while k<l do begin + BESENArrayCheckTooLong(n,1); + pk:=BESENArrayIndexToStr(k); + if eA.Get(pk,v) then begin + a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(n); + inc(k); + end; + end else begin + BESENArrayCheckTooLong(n,1); + A.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(e,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(n); + end; + if i<CountArguments then begin + e:=Arguments^[i]^; + inc(i); + end else begin + break; + end; + end; + a.Len:=n; + finally + a.GarbageCollectorUnlock; + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); +end; + +procedure TBESENObjectArrayPrototype.NativeJoin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + i,l:int64; + UseComma:boolean; + Separator,s:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + v:=BESENEmptyValue; + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + UseComma:=(CountArguments=0) or (Arguments^[0]^.ValueType=bvtUNDEFINED); + if UseComma then begin + Separator:=','; + end else begin + Separator:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + s:=''; + if l>0 then begin + i:=0; + while i<l do begin + if i>0 then begin + s:=s+Separator; + end; + TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(i),v); + if not (v.ValueType in [bvtUNDEFINED,bvtNULL]) then begin + s:=s+TBESEN(Instance).ToStr(v); + end; + inc(i); + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectArrayPrototype.NativePop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + l:int64; + si:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENUndefinedValue; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + if l=0 then begin + TBESENObject(ov.Obj).Put('length',BESENNumberValue(0),true,BESENLengthHash); + ResultValue:=BESENUndefinedValue; + end else begin + si:=BESENArrayIndexToStr(l-1); + TBESENObject(ov.Obj).Get(si,ResultValue); + TBESENObject(ov.Obj).Delete(si,true); + TBESENObject(ov.Obj).Put('length',BESENNumberValue(l-1),true,BESENLengthHash); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativePush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + l:int64; + p:integer; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + for p:=0 to CountArguments-1 do begin + BESENArrayCheckTooLong(l,1); + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(l),Arguments^[p]^,true); + inc(l); + end; + TBESENObject(ov.Obj).Put('length',BESENNumberValue(l),true,BESENLengthHash); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENNumberValue(l); +end; + +procedure TBESENObjectArrayPrototype.NativeReverse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,uv,lv:TBESENValue; + l:int64; + up,lp:TBESENString; + middle,lower,upper:longword; + ue,le:TBESENBoolean; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + uv:=BESENEmptyValue; + lv:=BESENEmptyValue; + TBESENObject(ov.Obj).Get('length',lv,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(lv); + middle:=l shr 1; + lower:=0; + while lower<>middle do begin + upper:=l-(lower+1); + up:=BESENArrayIndexToStr(upper); + lp:=BESENArrayIndexToStr(lower); + le:=TBESENObject(ov.Obj).Get(lp,lv); + ue:=TBESENObject(ov.Obj).Get(up,uv); + if le and ue then begin + TBESENObject(ov.Obj).Put(lp,uv,true); + TBESENObject(ov.Obj).Put(up,lv,true); + end else if ue and not le then begin + TBESENObject(ov.Obj).Put(lp,uv,true); + TBESENObject(ov.Obj).Delete(up,true); + end else if le and not ue then begin + TBESENObject(ov.Obj).Put(up,lv,true); + TBESENObject(ov.Obj).Delete(lp,true); + end; + inc(lower); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(TBESENObject(ov.Obj)); +end; + +procedure TBESENObjectArrayPrototype.NativeShift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + l,k:int64; + fp,tp:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + if l=0 then begin + TBESENObject(ov.Obj).Put('length',BESENNumberValue(0),true,BESENLengthHash); + ResultValue:=BESENUndefinedValue; + end else begin + TBESENObject(ov.Obj).Get('0',ResultValue); + k:=1; + while k<l do begin + fp:=BESENArrayIndexToStr(k); + tp:=BESENArrayIndexToStr(k-1); + if TBESENObject(ov.Obj).Get(fp,v) then begin + TBESENObject(ov.Obj).Put(tp,v,true); + end else begin + TBESENObject(ov.Obj).Delete(tp,true); + end; + inc(k); + end; + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(l-1),true); + TBESENObject(ov.Obj).Put('length',BESENNumberValue(l-1),true,BESENLengthHash); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var a:TBESENObjectArray; + ov,v:TBESENValue; + l:int64; + Pk:TBESENString; + rs,re,k,f,n:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + rs:=TBESEN(Instance).ToInt32(Arguments^[0]^); + end else begin + rs:=0; + end; + if rs<0 then begin + k:=l+rs; + if k<0 then begin + k:=0; + end; + end else begin + k:=rs; + if l<k then begin + k:=l; + end; + end; + if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin + re:=TBESEN(Instance).ToInt32(Arguments^[1]^); + end else begin + re:=l; + end; + if re<0 then begin + f:=l+re; + if f<0 then begin + f:=0; + end; + end else begin + f:=re; + if l<f then begin + f:=l; + end; + end; + n:=0; + while k<f do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(k); + inc(n); + end; + a.Put('length',BESENNumberValue(n),true,BESENLengthHash); + finally + a.GarbageCollectorUnlock; + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); +end; + +procedure TBESENObjectArrayPrototype.NativeSort(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var CompareFunction:TBESENObject; + ov,sva,svb:TBESENValue; + procedure IntroSort(Left,Right,Depth:int64); + function SortCompare(const x,y:TBESENValue):integer; + var vn:TBESENValue; + sx,sy:TBESENString; + ValuePointers:array[0..1] of PBESENValue; + begin + if (x.ValueType=bvtNONE) and (y.ValueType=bvtNONE) then begin + result:=0; + end else if x.ValueType=bvtNONE then begin + result:=1; + end else if y.ValueType=bvtNONE then begin + result:=-1; + end else if (x.ValueType=bvtUNDEFINED) and (y.ValueType=bvtUNDEFINED) then begin + result:=0; + end else if x.ValueType=bvtUNDEFINED then begin + result:=1; + end else if y.ValueType=bvtUNDEFINED then begin + result:=-1; + end else begin + if assigned(CompareFunction) then begin + ValuePointers[0]:=@x; + ValuePointers[1]:=@y; + TBESEN(Instance).ObjectCall(CompareFunction,ThisArgument,@ValuePointers,2,vn); + if (vn.ValueType<>bvtNUMBER) or BESENIsNaN(vn.Num) then begin + raise EBESENTypeError.Create('Array sort error'); + end; + if BESENIsNegative(vn.Num) then begin + result:=-1; + end else if not BESENIsZero(0) then begin + result:=1; + end else begin + result:=0; + end; + end else begin + sx:=TBESEN(Instance).ToStr(x); + sy:=TBESEN(Instance).ToStr(y); + if sx<sy then begin + result:=-1; + end else if sx>sy then begin + result:=1; + end else begin + result:=0; + end; + sx:=''; + sy:=''; + end; + end; + end; + procedure GetIndex(i:int64;var r:TBESENValue); + var s:TBESENString; + begin + s:=BESENArrayIndexToStr(i); + if not TBESENObject(ov.Obj).Get(s,r) then begin + r.ValueType:=bvtNONE; + end; + end; + procedure PutIndex(i:int64;const a:TBESENValue); + begin + if a.ValueType=bvtNONE then begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(i),true); + end else begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(i),a,true); + end; + end; + function CompareIndex(const a,b:int64):integer; + begin + GetIndex(a,sva); + GetIndex(b,svb); + result:=SortCompare(sva,svb); + end; + procedure Swap(a,b:int64); + begin + GetIndex(a,sva); + GetIndex(b,svb); + PutIndex(b,sva); + PutIndex(a,svb); + end; + procedure SiftDown(Current,MaxIndex:int64); + var SiftLeft,SiftRight,Largest:int64; + sl,sr,l:TBESENValue; + begin + SiftLeft:=Left+(2*(Current-Left))+1; + SiftRight:=Left+(2*(Current-Left))+2; + Largest:=Current; + sl:=BESENEmptyValue; + sr:=BESENEmptyValue; + l:=BESENEmptyValue; + GetIndex(SiftLeft,sl); + GetIndex(Largest,l); + if (SiftLeft<=MaxIndex) and (SortCompare(sl,l)>0) then begin + Largest:=SiftLeft; + GetIndex(Largest,l); + end; + GetIndex(SiftRight,sr); + if (SiftRight<=MaxIndex) and (SortCompare(sr,l)>0) then begin + Largest:=SiftRight; + end; + if Largest<>Current then begin + Swap(Current,Largest); + SiftDown(Largest,MaxIndex); + end; + end; + procedure InsertionSort; + var i,j:int64; + t,x,v:TBESENValue; + begin + t:=BESENEmptyValue; + x:=BESENEmptyValue; + v:=BESENEmptyValue; + i:=Left+1; + while i<=Right do begin + GetIndex(i,t); + j:=i-1; + while j>=Left do begin + GetIndex(j,v); + if SortCompare(t,v)<0 then begin + GetIndex(j,x); + PutIndex(j+1,x); + dec(j); + end else begin + break; + end; + end; + PutIndex(j+1,t); + inc(i); + end; + end; + procedure HeapSort; + var i:int64; + begin + i:=((Left+Right+1) div 2)-1; + while i>=Left do begin + SiftDown(i,Right); + dec(i); + end; + i:=Right; + while i>=Left+1 do begin + Swap(i,Left); + SiftDown(Left,i-1); + dec(i); + end; + end; + procedure QuickSortWidthMedianOfThreeOptimization; + var Middle,i,j:integer; + Pivot,v:TBESENValue; + begin + Middle:=(Left+Right) div 2; + if (Right-Left)>3 then begin + if CompareIndex(Left,Middle)>0 then begin + Swap(Left,Middle); + end; + if CompareIndex(Left,Right)>0 then begin + Swap(Left,Right); + end; + if CompareIndex(Middle,Right)>0 then begin + Swap(Middle,Right); + end; + end; + Pivot:=BESENEmptyValue; + v:=BESENEmptyValue; + GetIndex(Middle,Pivot); + i:=Left; + j:=Right; + while true do begin + while i<j do begin + GetIndex(i,v); + if SortCompare(v,Pivot)<0 then begin + inc(i); + end else begin + break; + end; + end; + while j>i do begin + GetIndex(j,v); + if SortCompare(v,Pivot)>0 then begin + dec(j); + end else begin + break; + end; + end; + if i>j then begin + break; + end; + Swap(i,j); + inc(i); + dec(j); + end; + IntroSort(Left,j,Depth-1); + IntroSort(i,Right,Depth-1); + end; + begin + if Left<Right then begin + if (Right-Left)<16 then begin + InsertionSort; + end else if Depth=0 then begin + HeapSort; + end else begin + QuickSortWidthMedianOfThreeOptimization; + end; + end; + end; +var l:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',sva,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(sva); + if CountArguments>0 then begin + if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and TBESENObject(Arguments^[0]^.Obj).HasCall then begin + CompareFunction:=TBESENObject(Arguments^[0]^.Obj); + end else begin + raise EBESENTypeError.Create('Bad argument'); + end; + end else begin + CompareFunction:=nil; + end; + IntroSort(0,l-1,BESENIntLog2(l)*2); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(TBESENObject(ov.Obj)); +end; + +procedure TBESENObjectArrayPrototype.NativeSplice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + A:TBESENObject; + r3,r5,r6,r17,k:TBESENUINT32; + s9,s11,s22,s33,s39:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + r3:=TBESEN(Instance).ToUINT32(v); + + if CountArguments<1 then begin + v:=BESENNumberValue(0); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + end; + if (-v.Num)>r3 then begin + r5:=0; + end else if BESENIsNegative(v.Num) then begin + r5:=trunc(r3+v.Num); + end else if v.Num<r3 then begin + r5:=trunc(v.Num); + end else begin + r5:=r3; + end; + + if CountArguments<2 then begin + v:=BESENNumberValue(0); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + end; + if BESENIsNegative(v.Num) then begin + r6:=0; + end else begin + r6:=trunc(v.Num); + end; + if (r3-r5)<r6 then begin + r6:=r3-r5; + end; + k:=0; + while k<r6 do begin + s9:=BESENArrayIndexToStr(r5+k); + if TBESENObject(ov.Obj).Get(s9,v) then begin + s11:=BESENArrayIndexToStr(k); + A.DefineOwnProperty(s11,BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(k); + end; + + A.Put('length',BESENNumberValue(r6),true,BESENLengthHash); + if CountArguments<2 then begin + r17:=0; + end else begin + r17:=CountArguments-2; + end; + if r17<>r6 then begin + if r17<=r6 then begin + k:=r5; + while k<(r3-r6) do begin + s22:=BESENArrayIndexToStr(k+r6); + if TBESENObject(ov.Obj).Get(s22,v) then begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k+r17),v,true); + end else begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(k+r17),true); + end; + inc(k); + end; + k:=r3; + while k>((r3+r17)-r6) do begin + s33:=BESENArrayIndexToStr(k-1); + TBESENObject(ov.Obj).Delete(s33,true); + dec(k); + end; + end else begin + k:=r3-r6; + while k>r5 do begin + s39:=BESENArrayIndexToStr(k+r6-1); + if TBESENObject(ov.Obj).Get(s39,v) then begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k+r17-1),v,true); + end else begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(k+r17-1),true); + end; + dec(k); + end; + end; + end; + + k:=2; + while k<longword(CountArguments) do begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr((k+r5)-2),Arguments^[k]^,true); + inc(k); + end; + + TBESENObject(ov.Obj).Put('length',BESENNumberValue((r3+r17)-r6),true,BESENLengthHash); + finally + a.GarbageCollectorUnlock; + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); +end; + +procedure TBESENObjectArrayPrototype.NativeUnshift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var r2,r3,k:TBESENUINT32; + ov,v:TBESENValue; + p:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + r2:=TBESEN(Instance).ToUINT32(v); + r3:=CountArguments; + BESENArrayCheckTooLong(r2,r3); + k:=r2; + while k>0 do begin + p:=BESENArrayIndexToStr(k-1); + if TBESENObject(ov.Obj).Get(p,v) then begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr((k+r3)-1),v,true); + end else begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr((k+r3)-1),true); + end; + dec(k); + end; + k:=0; + while k<r3 do begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k),Arguments^[k]^,true); + inc(k); + end; + TBESENObject(ov.Obj).Put('length',BESENNumberValue(r2+r3),true,BESENLengthHash); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENUndefinedValue; +end; + +procedure TBESENObjectArrayPrototype.NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,sv,v:TBESENValue; + Len,n,k:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=-1; + if Len>0 then begin + if CountArguments>0 then begin + sv:=Arguments^[0]^; + end else begin + sv:=BESENUndefinedValue; + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToInt(Arguments^[1]^); + end else begin + n:=0; + end; + if n<Len then begin + if n<0 then begin + k:=Len-abs(n); + if k<0 then begin + k:=0; + end; + end else begin + k:=n; + end; + while k<Len do begin + if TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(k),v) then begin + if BESENEqualityExpressionStrictEquals(sv,v) then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=k; + break; + end; + end; + inc(k); + end; + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,sv,v:TBESENValue; + Len,n,k:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=-1; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if Len>0 then begin + if CountArguments>0 then begin + sv:=Arguments^[0]^; + end else begin + sv:=BESENUndefinedValue; + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToInt(Arguments^[1]^); + end else begin + n:=Len-1; + end; + if n<0 then begin + k:=Len-abs(n); + end else begin + k:=min(n,Len-1); + end; + while k>=0 do begin + if TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(k),v) then begin + if BESENEqualityExpressionStrictEquals(sv,v) then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=k; + break; + end; + end; + dec(k); + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeEvery(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=true; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + if not TBESEN(Instance).ToBool(vr) then begin + ResultValue.Bool:=false; + break; + end; + end; + inc(k); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeSome(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=false; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + if TBESEN(Instance).ToBool(vr) then begin + ResultValue.Bool:=true; + break; + end; + end; + inc(k); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeForEach(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + end; + inc(k); + end; + ResultValue.ValueType:=bvtUNDEFINED; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeMap(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + a:TBESENObjectArray; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + a.Len:=Len; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + a.DefineOwnProperty(Pk,BESENDataPropertyDescriptor(vr,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(k); + end; + finally + a.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeFilter(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,kv,vr,vi:TBESENValue; + Len,k,n:int64; + Pk:TBESENString; + a:TBESENObjectArray; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',kv,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(kv); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + ValuePointers[0]:=@kv; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + n:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,kv) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + if TBESEN(Instance).ToBool(vr) then begin + a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(kv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(n); + end; + end; + inc(k); + end; + finally + a.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeReduce(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,av,v,vi,nav:TBESENValue; + Len,k:int64; + Pk:TBESENString; + kPresent:boolean; + ValuePointers:array[0..3] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + k:=0; + if CountArguments>1 then begin + av:=Arguments^[1]^; + end else if Len=0 then begin + raise EBESENTypeError.Create('Reduce failed'); + end else begin + kPresent:=false; + while (k<Len) and not kPresent do begin + Pk:=BESENArrayIndexToStr(k); + kPresent:=TBESENObject(ov.Obj).HasProperty(Pk); + if kPresent then begin + TBESENObject(ov.Obj).Get(Pk,av); + end; + inc(k); + end; + if not kPresent then begin + raise EBESENTypeError.Create('Reduce failed'); + end; + end; + nav:=BesenUndefinedValue; + ValuePointers[0]:=@av; + ValuePointers[1]:=@v; + ValuePointers[2]:=@vi; + ValuePointers[3]:=@ov; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),BESENUndefinedValue,@ValuePointers,4,nav); + BesenCopyValue(av,nav); + end; + inc(k); + end; + BESENCopyValue(ResultValue,av); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeReduceRight(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,av,v,vi,nav:TBESENValue; + Len,k:int64; + Pk:TBESENString; + kPresent:boolean; + ValuePointers:array[0..3] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + k:=Len-1; + if CountArguments>1 then begin + av:=Arguments^[1]^; + end else if Len=0 then begin + raise EBESENTypeError.Create('Reduce failed'); + end else begin + kPresent:=false; + while (k>=0) and not kPresent do begin + Pk:=BESENArrayIndexToStr(k); + kPresent:=TBESENObject(ov.Obj).HasProperty(Pk); + if kPresent then begin + TBESENObject(ov.Obj).Get(Pk,av); + end; + dec(k); + end; + if not kPresent then begin + raise EBESENTypeError.Create('Reduce failed'); + end; + end; + nav:=BesenUndefinedValue; + ValuePointers[0]:=@av; + ValuePointers[1]:=@v; + ValuePointers[2]:=@vi; + ValuePointers[3]:=@ov; + while k>=0 do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),BESENUndefinedValue,@ValuePointers,4,nav); // ES5 errata fix + BesenCopyValue(av,nav); + end; + dec(k); + end; + BESENCopyValue(ResultValue,av); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectBindingFunction.pas b/3rd/besen/src/BESENObjectBindingFunction.pas new file mode 100644 index 000000000..bdec1ecda --- /dev/null +++ b/3rd/besen/src/BESENObjectBindingFunction.pas @@ -0,0 +1,191 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBindingFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; + +type TBESENObjectBindingFunction=class(TBESENObjectFunction) + public + TargetFunction:TBESENObject; + BoundThis:TBESENValue; + BoundArguments:TBESENValues; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + function HasHasInstance:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENHashUtils; + +constructor TBESENObjectBindingFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Binding'; + TargetFunction:=nil; + BoundThis:=BESENUndefinedValue; + BoundArguments:=nil; +end; + +destructor TBESENObjectBindingFunction.Destroy; +begin + TargetFunction:=nil; + BoundThis:=BESENUndefinedValue; + SetLength(BoundArguments,0); + inherited Destroy; +end; + +function TBESENObjectBindingFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetEx(p,AResult,Descriptor,Base,Hash); +end; + +function TBESENObjectBindingFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetIndex(Index,ID,AResult,Base); +end; + +procedure TBESENObjectBindingFunction.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var CallArgs:TBESENValuePointers; + i,j:integer; +begin + CallArgs:=nil; + if assigned(TargetFunction) and TargetFunction.HasConstruct then begin + SetLength(CallArgs,length(BoundArguments)+CountArguments); + try + j:=0; + for i:=0 to length(BoundArguments)-1 do begin + CallArgs[j]:=@BoundArguments[i]; + inc(j); + end; + for i:=0 to CountArguments-1 do begin + CallArgs[j]:=Arguments^[i]; + inc(j); + end; + TargetFunction.Construct(BoundThis,@CallArgs[0],length(CallArgs),AResult); + finally + SetLength(CallArgs,0); + end; + end else begin + raise EBESENTypeError.Create('No hasConstruct'); + end; +end; + +procedure TBESENObjectBindingFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var CallArgs:TBESENValuePointers; + i,j:integer; +begin + CallArgs:=nil; + if assigned(TargetFunction) and TargetFunction.HasCall then begin + SetLength(CallArgs,length(BoundArguments)+CountArguments); + try + j:=0; + for i:=0 to length(BoundArguments)-1 do begin + CallArgs[j]:=@BoundArguments[i]; + inc(j); + end; + for i:=0 to CountArguments-1 do begin + CallArgs[j]:=Arguments^[i]; + inc(j); + end; + TBESEN(Instance).ObjectCall(TargetFunction,BoundThis,@CallArgs[0],length(CallArgs),AResult); + finally + SetLength(CallArgs,0); + end; + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObjectBindingFunction.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +begin + if not TargetFunction.HasHasInstance then begin + raise EBESENTypeError.Create('No hasInstance'); + end; + result:=assigned(TargetFunction) and TargetFunction.HasInstance(AInstance); +end; + +function TBESENObjectBindingFunction.HasConstruct:TBESENBoolean; +begin + result:=assigned(TargetFunction) and TargetFunction.HasConstruct; +end; + +function TBESENObjectBindingFunction.HasCall:TBESENBoolean; +begin + result:=assigned(TargetFunction) and TargetFunction.HasCall; +end; + +function TBESENObjectBindingFunction.HasHasInstance:TBESENBoolean; +begin + result:=assigned(TargetFunction) and TargetFunction.HasHasInstance; +end; + +procedure TBESENObjectBindingFunction.Finalize; +begin + TargetFunction:=nil; + BoundThis:=BESENUndefinedValue; + SetLength(BoundArguments,0); + inherited Finalize; +end; + +procedure TBESENObjectBindingFunction.Mark; +var i:integer; +begin + if assigned(TargetFunction) then begin + TBESEN(Instance).GarbageCollector.GrayIt(TargetFunction); + end; + TBESEN(Instance).GarbageCollector.GrayValue(BoundThis); + for i:=0 to length(BoundArguments)-1 do begin + TBESEN(Instance).GarbageCollector.GrayValue(BoundArguments[i]); + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectBoolean.pas b/3rd/besen/src/BESENObjectBoolean.pas new file mode 100644 index 000000000..504bc0031 --- /dev/null +++ b/3rd/besen/src/BESENObjectBoolean.pas @@ -0,0 +1,74 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBoolean; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectBoolean=class(TBESENObject) + public + Value:TBESENBoolean; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectBoolean.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Boolean'; + ObjectName:=''; + Value:=false; +end; + +destructor TBESENObjectBoolean.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectBoolean.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectBoolean.Mark; +begin + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectBooleanConstructor.pas b/3rd/besen/src/BESENObjectBooleanConstructor.pas new file mode 100644 index 000000000..be28a3ae8 --- /dev/null +++ b/3rd/besen/src/BESENObjectBooleanConstructor.pas @@ -0,0 +1,103 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBooleanConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectBooleanConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectBoolean; + +constructor TBESENObjectBooleanConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Boolean'; +end; + +destructor TBESENObjectBooleanConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectBooleanConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectBoolean; +begin + r1:=TBESENObjectBoolean.Create(Instance,TBESEN(Instance).ObjectBooleanPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments>0 then begin + r1.Value:=TBESEN(Instance).ToBool(Arguments^[0]^); + end else begin + r1.Value:=false; + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectBooleanConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments<1 then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else begin + TBESEN(Instance).ToBooleanValue(Arguments^[0]^,AResult); + end; +end; + +function TBESENObjectBooleanConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectBooleanConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/3rd/besen/src/BESENObjectBooleanPrototype.pas b/3rd/besen/src/BESENObjectBooleanPrototype.pas new file mode 100644 index 000000000..d44fd6606 --- /dev/null +++ b/3rd/besen/src/BESENObjectBooleanPrototype.pas @@ -0,0 +1,101 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBooleanPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectBooleanPrototype=class(TBESENObjectBoolean) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectBooleanPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype); + ObjectClassName:='Boolean'; + ObjectName:='Boolean'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectBooleanPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectBooleanPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtBOOLEAN then begin + if ThisArgument.Bool then begin + ResultValue:=BESENStringValue('true'); + end else begin + ResultValue:=BESENStringValue('false'); + end; + end else if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) then begin + if TBESENObjectBoolean(TBESENObject(ThisArgument.Obj)).Value then begin + ResultValue:=BESENStringValue('true'); + end else begin + ResultValue:=BESENStringValue('false'); + end; + end else begin + raise EBESENTypeError.Create('Not a boolean object'); + end; +end; + +procedure TBESENObjectBooleanPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtBOOLEAN then begin + BESENCopyValue(ResultValue,ThisArgument); + end else if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) then begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=TBESENObjectBoolean(TBESENObject(ThisArgument.Obj)).Value; + end else begin + raise EBESENTypeError.Create('Not a boolean object'); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectConsole.pas b/3rd/besen/src/BESENObjectConsole.pas new file mode 100644 index 000000000..ad461a72e --- /dev/null +++ b/3rd/besen/src/BESENObjectConsole.pas @@ -0,0 +1,155 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectConsole; +{$i BESEN.inc} + +interface + +const BESENObjectConsoleSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}widestring{$endif}= +'/**'+#13#10+ +' * Console object for BESEN'+#13#10+ +' * @author Dmitry A. Soshnikov <dmitry.soshnikov@gmail.com>'+#13#10+ +' */'+#13#10+ +'(function initConsole(global) {'+#13#10+ +''+#13#10+ +' // helpers'+#13#10+ +''+#13#10+ +' var getClass = Object.prototype.toString;'+#13#10+ +' var timeMap = {};'+#13#10+ +''+#13#10+ +' function repeatSring(string, times) {'+#13#10+ +' return Array(times + 1).join(string);'+#13#10+ +' }'+#13#10+ +''+#13#10+ +' function dir(object, deep, level) {'+#13#10+ +' level || (level = 1);'+#13#10+ +' typeof deep == "undefined" && (deep = true);'+#13#10+ +' var openBracket, closeBracket;'+#13#10+ +' if (Array.isArray(object)) {'+#13#10+ +' openBracket = "["; closeBracket = "]"'+#13#10+ +' } else {'+#13#10+ +' openBracket = "{"; closeBracket = "}"'+#13#10+ +' }'+#13#10+ +' var props = [];'+#13#10+ +' var indent = repeatSring(console.dir.indention, level);'+#13#10+ +' if (console.dir.showInternals) {'+#13#10+ +' props.push(indent + "[[Class]]: \"" + getClass.call(object).slice(8, -1) + "\"");'+#13#10+ +' }'+#13#10+ +' var data, current, currentClass;'+#13#10+ +' var goDeeper = (typeof deep == "number" ? deep > level : deep);'+#13#10+ +' Object.getOwnPropertyNames(object).forEach(function (property) {'+#13#10+ +' current = object[property];'+#13#10+ +' currentClass = getClass.call(current);'+#13#10+ +' if (goDeeper && (currentClass == "[object Object]" || Array.isArray(current))) {'+#13#10+ +' data = dir(current, deep, level + 1);'+#13#10+ +' } else {'+#13#10+ +' data = ('+#13#10+ +' typeof current == "function" ? "function" : ('+#13#10+ +' Array.isArray(current) ? "[" + current + "]" :'+#13#10+ +' (currentClass == "[object String]" ? "\"" + current + "\"" : current)'+#13#10+ +' )'+#13#10+ +' );'+#13#10+ +' }'+#13#10+ +' props.push(indent + property + ": " + data);'+#13#10+ +' });'+#13#10+ +' return "".concat('+#13#10+ +' openBracket, "\n", props.join(",\n"), "\n",'+#13#10+ +' (level > 1 ? repeatSring(console.dir.indention, level - 1) : ""),'+#13#10+ +' closeBracket'+#13#10+ +' );'+#13#10+ +' }'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * console object;'+#13#10+ +' * implements: log, dir, time, timeEnd'+#13#10+ +' */'+#13#10+ +' global.console = {'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * simple log using toString'+#13#10+ +' */'+#13#10+ +' log: function(){'+#13#10+ +' var s = "", a = arguments, j = +a.length;'+#13#10+ +' for(var i=0;i<j;i++) s += a[i] + " ";'+#13#10+ +' println(s);'+#13#10+ +' },'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * dir an object'+#13#10+ +' * @param {Object} object'+#13#10+ +' * @param {Variant} deep - level of depth, default is {Boolean} true'+#13#10+ +' * can be set also to {Number} value specifying needed level of depth'+#13#10+ +' * Examples:'+#13#10+ +' * - console.dir(obj) // console.dir(obj, true)'+#13#10+ +' * - console.dir(obj, false); // only first level is shown'+#13#10+ +' * - console.dir(obj, 3); // properties of three levels are shown'+#13#10+ +' */'+#13#10+ +' dir: function (object, deep) {'+#13#10+ +' // if called for a primitive'+#13#10+ +' if (Object(object) !== object) {'+#13#10+ +' return console.log(object);'+#13#10+ +' }'+#13#10+ +' // else for an object'+#13#10+ +' return println(dir(object, deep));'+#13#10+ +' },'+#13#10+ +''+#13#10+ +' // time functions borrowed from Firebug'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * time start'+#13#10+ +' */'+#13#10+ +' time: function(name) {'+#13#10+ +' timeMap[name] = Date.now();'+#13#10+ +' },'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * time end'+#13#10+ +' */'+#13#10+ +' timeEnd: function(name) {'+#13#10+ +' if (name in timeMap) {'+#13#10+ +' var delta = Date.now() - timeMap[name];'+#13#10+ +' println(name + ": ", delta + "ms");'+#13#10+ +' delete timeMap[name];'+#13#10+ +' }'+#13#10+ +' }'+#13#10+ +' };'+#13#10+ +''+#13#10+ +' // indention for dir, default is 4 spaces'+#13#10+ +' console.dir.indention = " ";'+#13#10+ +''+#13#10+ +' // whether to show internal properties such as [[Class]]'+#13#10+ +' console.dir.showInternals = true;'+#13#10+ +''+#13#10+ +'})(this);'+#13#10; + +implementation + +end. diff --git a/3rd/besen/src/BESENObjectConstructor.pas b/3rd/besen/src/BESENObjectConstructor.pas new file mode 100644 index 000000000..1ae63c7a2 --- /dev/null +++ b/3rd/besen/src/BESENObjectConstructor.pas @@ -0,0 +1,457 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectConstructor; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeGetPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetOwnPropertyDescriptor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetOwnPropertyNames(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCreate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDefineProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDefineProperties(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSeal(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFreeze(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePreventExtensions(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsSealed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsFrozen(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsExtensible(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeKeys(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENUtils,BESENArrayUtils,BESENErrors,BESENObjectString,BESENObjectArray; + +constructor TBESENObjectConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + + RegisterNativeFunction('getPrototypeOf',NativeGetPrototypeOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getOwnPropertyDescriptor',NativeGetOwnPropertyDescriptor,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getOwnPropertyNames',NativeGetOwnPropertyNames,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('create',NativeCreate,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('defineProperty',NativeDefineProperty,3,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('defineProperties',NativeDefineProperties,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('seal',NativeSeal,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('freeze',NativeFreeze,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('preventExtensions',NativePreventExtensions,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isSealed',NativeIsSealed,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isFrozen',NativeIsFrozen,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isExtensible',NativeIsExtensible,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('keys',NativeKeys,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments>0 then begin + case Arguments^[0]^.ValueType of + bvtNULL,bvtUNDEFINED:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + end; + else begin + TBESEN(Instance).ToObjectValue(Arguments^[0]^,AResult); + end; + end; + end else begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + end; + if (AResult.ValueType=bvtOBJECT) and assigned(AResult.Obj) then begin + TBESEN(Instance).GarbageCollector.Add(TBESENObject(AResult.Obj)); + end; +end; + +procedure TBESENObjectConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectConstructor.NativeGetPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + ResultValue:=BESENObjectValueEx(TBESENObject(Arguments^[0]^.Obj).Prototype); +end; + +procedure TBESENObjectConstructor.NativeGetOwnPropertyDescriptor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var n:TBESENString; + Descriptor:TBESENObjectPropertyDescriptor; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToStr(Arguments^[1]^); + end else begin + n:=''; + end; + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(n,Descriptor); + TBESEN(Instance).FromPropertyDescriptor(Descriptor,ResultValue); + if (ResultValue.ValueType=bvtOBJECT) and assigned(ResultValue.Obj) then begin + TBESEN(Instance).GarbageCollector.Add(TBESENObject(ResultValue.Obj)); + end; +end; + +procedure TBESENObjectConstructor.NativeGetOwnPropertyNames(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ArrayObject:TBESENObjectArray; + o:TBESENObject; + PropItem:TBESENObjectProperty; + n:longword; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + ArrayObject:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ArrayObject); + ArrayObject.GarbageCollectorLock; + try + o:=TBESENObject(Arguments^[0]^.Obj); + if o is TBESENObjectString then begin + for n:=1 to length(TBESENObjectString(o).Value) do begin + ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(n-1),BESENDataPropertyDescriptor(BESENStringValue(BESENArrayIndexToStr(n-1)),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + n:=length(TBESENObjectString(o).Value); + end else begin + n:=0; + end; + PropItem:=o.Properties.First; + while assigned(PropItem) do begin + ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(BESENStringValue(PropItem.Key),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(n); + PropItem:=PropItem.Next; + end; + ArrayObject.Len:=n; + finally + ArrayObject.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(ArrayObject); +end; + +procedure TBESENObjectConstructor.NativeCreate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var o:TBESENObject; + vo:TBESENValue; + ValuePointers:array[0..1] of PBESENValue; +begin + if not ((CountArguments>0) and ((Arguments^[0]^.ValueType=bvtNULL) or ((Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)))) then begin + raise EBESENTypeError.Create('No object and not null'); + end; + if Arguments^[0]^.ValueType=bvtNULL then begin + o:=TBESENObject.Create(Instance,nil); + end else begin + o:=TBESENObject.Create(Instance,TBESENObject(Arguments^[0]^.Obj)); + end; + if CountArguments>1 then begin + vo.ValueType:=bvtOBJECT; + TBESENObject(vo.Obj):=o; + ValuePointers[0]:=@vo; + ValuePointers[1]:=Arguments^[1]; + NativeDefineProperties(ThisArgument,@ValuePointers,CountArguments,ResultValue); + end; + ResultValue.ValueType:=bvtOBJECT; + ResultValue.Obj:=o; +end; + +procedure TBESENObjectConstructor.NativeDefineProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var n:TBESENString; + Descriptor:TBESENObjectPropertyDescriptor; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToStr(Arguments^[1]^); + end else begin + n:=''; + end; + if CountArguments>2 then begin + TBESEN(Instance).ToPropertyDescriptor(Arguments^[2]^,Descriptor); + end else begin + Descriptor:=BESENUndefinedPropertyDescriptor; + end; + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(n,Descriptor,true); + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativeDefineProperties(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Props:TBESENObject; + Names:TBESENStrings; + Descriptors:TBESENObjectPropertyDescriptors; + Enumerator:TBESENObjectPropertyEnumerator; + i,Count:integer; + v:TBESENValue; + Key:TBESENString; +begin + Names:=nil; + Descriptors:=nil; + Enumerator:=nil; + Key:=''; + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + try + if CountArguments>1 then begin + Props:=TBESEN(Instance).ToObj(Arguments^[1]^); + end else begin + Props:=TBESEN(Instance).ToObj(BESENUndefinedValue); + end; + TBESEN(Instance).GarbageCollector.Add(Props); + Props.GarbageCollectorLock; + try + Count:=0; + Enumerator:=Props.Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + if Count>=length(Names) then begin + SetLength(Names,Count+256); + end; + if Count>=length(Descriptors) then begin + SetLength(Descriptors,Count+256); + end; + Names[Count]:=Key; + Props.Get(Key,v); + TBESEN(Instance).ToPropertyDescriptor(v,Descriptors[Count]); + inc(Count); + end; + for i:=0 to Count-1 do begin + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Names[i],Descriptors[i],true); + end; + finally + Props.GarbageCollectorUnlock; + end; + finally + BESENFreeAndNil(Enumerator); + SetLength(Names,0); + SetLength(Descriptors,0); + end; + ResultValue:=Arguments^[0]^; +end; + + +procedure TBESENObjectConstructor.NativeSeal(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + Descriptor.Attributes:=Descriptor.Attributes-[bopaCONFIGURABLE]; + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Key,Descriptor,true); + end; + finally + BESENFreeAndNil(Enumerator); + end; + TBESENObject(Arguments^[0]^.Obj).Extensible:=false; + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativeFreeze(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + Descriptor.Attributes:=Descriptor.Attributes-[bopaWRITABLE]; + end; + Descriptor.Attributes:=Descriptor.Attributes-[bopaCONFIGURABLE]; + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Key,Descriptor,true); + end; + finally + BESENFreeAndNil(Enumerator); + end; + TBESENObject(Arguments^[0]^.Obj).Extensible:=false; + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativePreventExtensions(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + TBESENObject(Arguments^[0]^.Obj).Extensible:=false; + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativeIsSealed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; + IsSealed:boolean; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + IsSealed:=true; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + if (boppCONFIGURABLE In Descriptor.Presents) and (bopaCONFIGURABLE In Descriptor.Attributes) then begin + IsSealed:=false; + break; + end; + end; + finally + BESENFreeAndNil(Enumerator); + end; + if TBESENObject(Arguments^[0]^.Obj).Extensible then begin + IsSealed:=false; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=IsSealed; +end; + +procedure TBESENObjectConstructor.NativeIsFrozen(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; + IsFrozen:boolean; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + IsFrozen:=true; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + if ((([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) and ((boppWRITABLE In Descriptor.Presents) and (bopaWRITABLE In Descriptor.Attributes))) or + ((boppCONFIGURABLE In Descriptor.Presents) and (bopaCONFIGURABLE In Descriptor.Attributes)) then begin + IsFrozen:=false; + break; + end; + end; + finally + BESENFreeAndNil(Enumerator); + end; + if TBESENObject(Arguments^[0]^.Obj).Extensible then begin + IsFrozen:=false; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=IsFrozen; +end; + +procedure TBESENObjectConstructor.NativeIsExtensible(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=TBESENObject(Arguments^[0]^.Obj).Extensible; +end; + +procedure TBESENObjectConstructor.NativeKeys(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ArrayObject:TBESENObjectArray; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; + Index:longword; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + ArrayObject:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ArrayObject); + ArrayObject.GarbageCollectorLock; + try + Index:=0; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENDataPropertyDescriptor(BESENStringValue(Key),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(Index); + end; + finally + BESENFreeAndNil(Enumerator); + end; + ArrayObject.Len:=Index; + finally + ArrayObject.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(ArrayObject); +end; + +end. diff --git a/3rd/besen/src/BESENObjectDate.pas b/3rd/besen/src/BESENObjectDate.pas new file mode 100644 index 000000000..a2088c4f5 --- /dev/null +++ b/3rd/besen/src/BESENObjectDate.pas @@ -0,0 +1,95 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDate; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectDate=class(TBESENObject) + public + Value:TBESENDate; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectDate.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Date'; + ObjectName:=''; + + Value:=Now; +end; + +destructor TBESENObjectDate.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectDate.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); +begin + case AHint.ValueType of + bvtNUMBER,bvtSTRING:begin + inherited DefaultValue(AHint,AResult); + end; + bvtOBJECT:begin + if AHint.Obj<>TBESEN(Instance).ObjectNumberConstructor then begin + inherited DefaultValue(TBESEN(Instance).ObjectStringConstructorValue,AResult); + end else begin + inherited DefaultValue(AHint,AResult); + end; + end; + else begin + inherited DefaultValue(TBESEN(Instance).ObjectStringConstructorValue,AResult); + end; + end; +end; + +procedure TBESENObjectDate.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectDate.Mark; +begin + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectDateConstructor.pas b/3rd/besen/src/BESENObjectDateConstructor.pas new file mode 100644 index 000000000..637ef0f3d --- /dev/null +++ b/3rd/besen/src/BESENObjectDateConstructor.pas @@ -0,0 +1,231 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDateConstructor; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectDateConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeNow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeUTC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENASTNodes,BESENStringUtils,BESENUtils,BESENObjectDate,BESENDateUtils,BESENNumberUtils,BESENLocale; + +constructor TBESENObjectDateConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Date'; + + RegisterNativeFunction('now',NativeNow,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('parse',NativeParse,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('UTC',NativeUTC,7,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectDateConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectDateConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectDate; + r3:TBESENValue; + s:TBESENString; + year,month,date,hours,minutes,seconds,ms:TBESENNumber; +begin + r3:=BESENEmptyValue; + r1:=TBESENObjectDate.Create(Instance,TBESEN(Instance).ObjectDatePrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments=0 then begin + r1.Value:=BESENTimeClip(BESENDateTimeToBESENDate(BESENGetUTCDateTime)); + end else if CountArguments=1 then begin + TBESEN(Instance).ToPrimitiveValue(Arguments^[0]^,TBESEN(Instance).ObjectNumberConstructorValue,r3); + if r3.ValueType<>bvtSTRING then begin + r1.Value:=BESENTimeClip(TBESEN(Instance).ToNum(r3)); + end else begin + s:=TBESEN(Instance).ToStr(r3); + r1.Value:=BESENParseTime(s); + if BESENIsNaN(r1.Value) then begin + r1.Value:=BESENParseISOTime(s); + if BESENIsNaN(r1.Value) then begin + r1.Value:=BESENParseNetscapeTime(s); + if BESENIsNaN(r1.Value) then begin + try + r1.Value:=BESENTimeClip(BESENDateTimeToBESENDate(BESENLocalDateTimeToUTC(StrToDateTime(s{$if ((FPC_VERSION>=3) or ((FPC_VERSION>=2) and ((FPC_RELEASE>=5) or ((FPC_RELEASE>=4) and (FPC_PATCH>=1)))))},BESENLocaleFormatSettings{$ifend})))); + except + r1.Value:=double(pointer(@BESENDoubleNaN)^); + end; + end; + end; + end; + end; + end else if CountArguments>1 then begin + year:=TBESEN(Instance).ToNum(Arguments^[0]^); + month:=TBESEN(Instance).ToNum(Arguments^[1]^); + date:=1; + hours:=0; + minutes:=0; + seconds:=0; + ms:=0; + if CountArguments>2 then begin + date:=TBESEN(Instance).ToNum(Arguments^[2]^); + if CountArguments>3 then begin + hours:=TBESEN(Instance).ToNum(Arguments^[3]^); + if CountArguments>4 then begin + minutes:=TBESEN(Instance).ToNum(Arguments^[4]^); + if CountArguments>5 then begin + seconds:=TBESEN(Instance).ToNum(Arguments^[5]^); + if CountArguments>6 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[6]^); + end; + end; + end; + end; + end; + r1.Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENMakeTime(Hours,Minutes,Seconds,ms))); + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult:=BESENObjectValue(r1); +end; + +procedure TBESENObjectDateConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var Value:TBESENDate; +begin + Value:=BESENTimeClip(BESENGetUTCBESENDate); + if BESENIsNaN(Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + AResult:=BESENStringValue('Invalid Date'); + end else begin + AResult:=BESENStringValue('NaN'); + end; + end else begin + AResult:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyyy hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(Value)),BESENDefaultFormatSettings)+' GMT'+BESENGetDateTimeOffsetString(BESENGetLocalDateTimeZone)); + end; +end; + +procedure TBESENObjectDateConstructor.NativeNow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue:=BESENNumberValue(BESENGetUTCBESENDate); +end; + +procedure TBESENObjectDateConstructor.NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENNumber; + s:TBESENString; +begin + try + if CountArguments>0 then begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + v:=BESENParseTime(s); + if BESENIsNaN(v) then begin + v:=BESENParseISOTime(s); + if BESENIsNaN(v) then begin + v:=BESENParseNetscapeTime(s); + if BESENIsNaN(v) then begin + try + v:=BESENTimeClip(BESENDateTimeToBESENDate(BESENLocalDateTimeToUTC(StrToDateTime(s{$if ((FPC_VERSION>=3) or ((FPC_VERSION>=2) and ((FPC_RELEASE>=5) or ((FPC_RELEASE>=4) and (FPC_PATCH>=1)))))},BESENLocaleFormatSettings{$ifend})))); + except + v:=double(pointer(@BESENDoubleNaN)^); + end; + end; + end; + end; + ResultValue:=BESENNumberValue(v); + end else begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end; + finally + end; +end; + +procedure TBESENObjectDateConstructor.NativeUTC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var year,month,date,hours,minutes,seconds,ms:TBESENNumber; +begin + try + if CountArguments>1 then begin + year:=TBESEN(Instance).ToNum(Arguments^[0]^); + month:=TBESEN(Instance).ToNum(Arguments^[1]^); + date:=1; + hours:=0; + minutes:=0; + seconds:=0; + ms:=0; + if CountArguments>2 then begin + date:=TBESEN(Instance).ToNum(Arguments^[2]^); + if CountArguments>3 then begin + hours:=TBESEN(Instance).ToNum(Arguments^[3]^); + if CountArguments>4 then begin + minutes:=TBESEN(Instance).ToNum(Arguments^[4]^); + if CountArguments>5 then begin + seconds:=TBESEN(Instance).ToNum(Arguments^[5]^); + if CountArguments>6 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[6]^); + end; + end; + end; + end; + end; + ResultValue:=BESENNumberValue(BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENMakeTime(Hours,Minutes,Seconds,ms)))); + end else begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end; + finally + end; +end; + +function TBESENObjectDateConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectDateConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectDatePrototype.pas b/3rd/besen/src/BESENObjectDatePrototype.pas new file mode 100644 index 000000000..53b3549e4 --- /dev/null +++ b/3rd/besen/src/BESENObjectDatePrototype.pas @@ -0,0 +1,1082 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDatePrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectDate,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp; + +type TBESENObjectDatePrototype=class(TBESENObjectDate) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToUTCString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetTimezoneOffset(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToGMTString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToISOString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToJSON(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENNumberUtils,BESENArrayUtils,BESENDateUtils,BESENLocale; + +constructor TBESENObjectDatePrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Date'; + ObjectName:='Date'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toDateString',NativeToDateString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toTimeString',NativeToTimeString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleDateString',NativeToLocaleDateString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleTimeString',NativeToLocaleTimeString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toUTCString',NativeToUTCString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getTime',NativeGetTime,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getFullYear',NativeGetFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCFullYear',NativeGetUTCFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getMonth',NativeGetMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCMonth',NativeGetUTCMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getDate',NativeGetDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCDate',NativeGetUTCDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getDay',NativeGetDay,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCDay',NativeGetUTCDay,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getHours',NativeGetHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCHours',NativeGetUTCHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getMinutes',NativeGetMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCMinutes',NativeGetUTCMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getSeconds',NativeGetSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCSeconds',NativeGetUTCSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getMilliseconds',NativeGetMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCMilliseconds',NativeGetUTCMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getTimezoneOffset',NativeGetTimezoneOffset,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setTime',NativeSetTime,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setMilliseconds',NativeSetMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCMilliseconds',NativeSetUTCMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setSeconds',NativeSetSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCSeconds',NativeSetUTCSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setMinutes',NativeSetMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCMinutes',NativeSetUTCMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setHours',NativeSetHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCHours',NativeSetUTCHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setDate',NativeSetDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCDate',NativeSetUTCDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setMonth',NativeSetMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCMonth',NativeSetUTCMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setFullYear',NativeSetFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCFullYear',NativeSetUTCFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toGMTString',NativeToGMTString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toISOString',NativeToISOString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toJSON',NativeToJSON,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getYear',NativeGetYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setYear',NativeSetYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectDatePrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectDatePrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyyy hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)+' GMT'+BESENGetDateTimeOffsetString(BESENGetLocalDateTimeZone)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyy',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('dddddd tt',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToLocaleDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('dddddd',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToLocaleTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('tt',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToUTCString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('ddd, dd mmm yyyy hh:nn:ss',BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value),BESENDefaultFormatSettings)+' GMT'); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; + +end; + +procedure TBESENObjectDatePrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENYearFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENYearFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMonthFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMonthFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENDayFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENDayFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENWeekDay(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENWeekDay(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENHourFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENHourFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMinuteFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMinuteFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENSecondFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENSecondFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMillisecondFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMillisecondFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetTimezoneOffset(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue((TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value-BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))/BESENmsPerMinute); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(TBESEN(Instance).ToNum(Arguments^[0]^)); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + ms:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),BESENSecondFromTime(t),ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + ms:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),BESENSecondFromTime(t),ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Seconds:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),Seconds,ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Seconds:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),Seconds,ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Minutes:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>2 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),Minutes,Seconds,ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Minutes:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>2 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),Minutes,Seconds,ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Hours,Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Hours:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Minutes:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Minutes:=BESENMinuteFromTime(t); + end; + if CountArguments>2 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>3 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[3]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(Hours,Minutes,Seconds,ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Hours,Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Hours:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Minutes:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Minutes:=BESENMinuteFromTime(t); + end; + if CountArguments>2 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>3 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[3]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(Hours,Minutes,Seconds,ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Date:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),BESENMonthFromTime(t),Date),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Date:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),BESENMonthFromTime(t),Date),BESENTimeWithinDay(t))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Month:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),Month,Date),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Month:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),Month,Date),BESENTimeWithinDay(t))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Year,Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Year:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Month:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Month:=BESENMonthFromTime(t); + end; + if CountArguments>2 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Year,Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Year:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Month:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Month:=BESENMonthFromTime(t); + end; + if CountArguments>2 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENTimeWithinDay(t))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToGMTString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + NativeToUTCString(ThisArgument,Arguments,CountArguments,ResultValue); +end; + +procedure TBESENObjectDatePrototype.NativeToISOString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz"Z"',BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value),BESENDefaultFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToJSON(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,tv:TBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + TBESEN(Instance).ToPrimitiveValue(ov,TBESEN(Instance).ObjectNumberConstructorValue,tv); + if (tv.ValueType=bvtNUMBER) and not BESENIsFinite(tv.Num) then begin + ResultValue:=BESENNullValue; + end else begin + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('toISOString',tv); + if not BESENIsCallable(tv) then begin + raise EBESENTypeError.Create('no "toISOString" callable object'); + end; + TBESEN(Instance).ObjectCall(TBESENObject(tv.Obj),ov,nil,0,ResultValue); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENYearFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))-1900); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Year:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Year:=TBESEN(Instance).ToNum(Arguments^[0]^); + if (0<=Year) and (Year<=99) then begin + Year:=Year+1900; + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(Year,BESENMonthFromTime(t),BESENDayFromTime(t)),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectDeclaredFunction.pas b/3rd/besen/src/BESENObjectDeclaredFunction.pas new file mode 100644 index 000000000..a950651c4 --- /dev/null +++ b/3rd/besen/src/BESENObjectDeclaredFunction.pas @@ -0,0 +1,235 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDeclaredFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, + BESENLexicalEnvironment,BESENContext,BESENASTNodes; + +type TBESENObjectDeclaredFunctionParameters=array of TBESENString; + + TBESENObjectDeclaredFunction=class(TBESENObjectFunction) + public + LexicalEnvironment:TBESENLexicalEnvironment; + Node:TBESENASTNodeFunctionLiteral; + Parameters:TBESENObjectDeclaredFunctionParameters; + Container:TBESENFunctionLiteralContainer; + ContextCache:TBESENContextCache; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure CallEx(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue;IsConstruct:boolean); virtual; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENUtils,BESENCode,BESENDeclarativeEnvironmentRecord; + +constructor TBESENObjectDeclaredFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='declared'; + LexicalEnvironment:=nil; + Node:=nil; + Parameters:=nil; + Container:=nil; + ContextCache:=TBESENContextCache.Create(Instance); +end; + +destructor TBESENObjectDeclaredFunction.Destroy; +begin + SetLength(Parameters,0); + BESENFreeAndNil(ContextCache); + inherited Destroy; +end; + +function TBESENObjectDeclaredFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + if Node.Body.IsStrict and (P='caller') then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +function TBESENObjectDeclaredFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetIndex(Index,ID,AResult,Base); + if TBESEN(Instance).IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +procedure TBESENObjectDeclaredFunction.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObject; + r3:TBESENValue; +begin + Get('prototype',r3); + if (r3.ValueType=bvtOBJECT) and assigned(TBESENObject(r3.Obj)) then begin + r1:=TBESENObject.Create(Instance,TBESENObject(r3.Obj),false); + end else begin + r1:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + end; + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + r1.Extensible:=true; + CallEx(BESENObjectValue(r1),Arguments,CountArguments,AResult,true); + finally + r1.GarbageCollectorUnlock; + end; + if AResult.ValueType<>bvtOBJECT then begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; + end; +end; + +procedure TBESENObjectDeclaredFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + CallEx(ThisArgument,Arguments,CountArguments,AResult,false); +end; + +procedure TBESENObjectDeclaredFunction.CallEx(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue;IsConstruct:boolean); +var NewContext:TBESENContext; + LocalEnv:TBESENLexicalEnvironment; + procedure SetThisBinding; + begin + if Node.Body.IsStrict then begin + BESENCopyValue(NewContext.ThisBinding,ThisArgument); + end else if ThisArgument.ValueType in [bvtUNDEFINED,bvtNULL] then begin + NewContext.ThisBinding.ValueType:=bvtOBJECT; + NewContext.ThisBinding.Obj:=TBESEN(Instance).ObjectGlobal; + end else if ThisArgument.ValueType<>bvtOBJECT then begin + TBESEN(Instance).ToObjectValue(ThisArgument,NewContext.ThisBinding); + end else begin + BESENCopyValue(NewContext.ThisBinding,ThisArgument); + end; + end; +begin + if assigned(Node) and (assigned(Node.Body) and not (Node.Body.IsEmpty and (CountArguments=0))) then begin + GarbageCollectorLock; + try + NewContext:=ContextCache.Pop; + if assigned(NewContext) then begin + LocalEnv:=NewContext.VariableEnvironment; + end else begin + NewContext:=TBESENContext.Create(Instance); + LocalEnv:=nil; + end; + if assigned(LocalEnv) then begin + LocalEnv.Outer:=LexicalEnvironment; + NewContext.LexicalEnvironment:=LocalEnv; + SetThisBinding; + NewContext.InitializeDeclarationBindingInstantiation(Node.Body,self,false,Arguments,CountArguments,true); + end else begin + LocalEnv:=TBESEN(Instance).NewDeclarativeEnvironment(LexicalEnvironment,Node.Body.IsStrict,TBESENCode(Node.Body.Code).HasMaybeDirectEval); + TBESEN(Instance).GarbageCollector.Add(LocalEnv); + NewContext.LexicalEnvironment:=LocalEnv; + NewContext.VariableEnvironment:=LocalEnv; + SetThisBinding; + NewContext.InitializeDeclarationBindingInstantiation(Node.Body,self,false,Arguments,CountArguments,false); + if not IsConstruct then begin + TBESEN(Instance).GarbageCollector.TriggerCollect; + end; + end; + try + if Node.Body.IsEmpty then begin + AResult.ValueType:=bvtUNDEFINED; + end else begin + Node.ExecuteCode(NewContext,AResult); + end; + if (ContextCache.Count<TBESEN(Instance).MaxCountOfFreeContexts) and (Node.Body.DisableArgumentsObject and ((length(Node.Body.Functions)=0) and (assigned(Node.Body.Code) and ((TBESENCode(Node.Body.Code).CountFunctionLiteralContainers=0) and not (TBESENCode(Node.Body.Code).IsComplexFunction or TBESENCode(Node.Body.Code).HasLocalDelete))))) then begin + NewContext.Reset; + if (((assigned(LocalEnv) and (NewContext.VariableEnvironment=LocalEnv){ and (LocalEnv.Outer=Instance.GlobalLexicalEnvironment)}) and assigned(LocalEnv.EnvironmentRecord)) and (LocalEnv.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord)) and not TBESENDeclarativeEnvironmentRecord(LocalEnv.EnvironmentRecord).Touched then begin + LocalEnv.Outer:=nil; + TBESENDeclarativeEnvironmentRecord(LocalEnv.EnvironmentRecord).Reset; + ContextCache.Push(NewContext); + NewContext:=nil; + end; + end; + finally + NewContext.Free; + end; + finally + GarbageCollectorUnlock; + end; + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObjectDeclaredFunction.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectDeclaredFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectDeclaredFunction.Finalize; +begin + Container:=nil; + LexicalEnvironment:=nil; + inherited Finalize; +end; + +procedure TBESENObjectDeclaredFunction.Mark; +begin + if assigned(Container) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Container); + end; + if assigned(LexicalEnvironment) then begin + TBESEN(Instance).GarbageCollector.GrayIt(LexicalEnvironment); + end; + if assigned(ContextCache) then begin + ContextCache.Mark; + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectEnvironmentRecord.pas b/3rd/besen/src/BESENObjectEnvironmentRecord.pas new file mode 100644 index 000000000..03afffbf6 --- /dev/null +++ b/3rd/besen/src/BESENObjectEnvironmentRecord.pas @@ -0,0 +1,168 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectEnvironmentRecord; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENObject, + BESENObjectPropertyDescriptor,BESENValue; + +type TBESENObjectEnvironmentRecord=class(TBESENEnvironmentRecord) + public + BindingObject:TBESENObject; + ProvideThis:TBESENBoolean; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; override; + function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; + procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); override; + function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure UpdateImplicitThisValue; override; + function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; override; + procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); override; + function DeleteIndex(const I,ID:integer):TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENStringUtils,BESENErrors; + +constructor TBESENObjectEnvironmentRecord.Create(AInstance:TObject); +begin + inherited Create(AInstance); + BindingObject:=nil; + ProvideThis:=false; + RecordType:=BESENEnvironmentRecordTypeObject; +end; + +destructor TBESENObjectEnvironmentRecord.Destroy; +begin + BindingObject:=nil; + inherited Destroy; +end; + +function TBESENObjectEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=BindingObject.HasPropertyEx(N,Descriptor,Hash); +end; + +function TBESENObjectEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; +begin + if BindingObject.HasProperty(N,Hash) then begin + BESENThrowTypeError('CreateMutableBinding for "'+N+'" failed'); + end; + if D then begin + result:=BindingObject.DefineOwnProperty(N,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true,Hash); // ES5 errata false to true + end else begin + result:=BindingObject.DefineOwnProperty(N,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE]),true,Hash); // ES5 errata false to true + end; +end; + +function TBESENObjectEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +begin + BindingObject.PutEx(N,V,S,Descriptor,OwnDescriptor,TempValue,Hash); + result:=true; +end; + +procedure TBESENObjectEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); + procedure ThrowIt; + begin + BESENThrowTypeError('GetBindingValue for "'+N+'" failed'); + end; +begin + if not BindingObject.GetEx(N,R,Descriptor,BindingObject,Hash) then begin + if S then begin + ThrowIt; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; +end; + +function TBESENObjectEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=BindingObject.DeleteEx(N,false,Descriptor,Hash); +end; + +procedure TBESENObjectEnvironmentRecord.UpdateImplicitThisValue; +begin + if ProvideThis then begin + ImplicitThisValue.ValueType:=bvtOBJECT; + ImplicitThisValue.Obj:=BindingObject; + end else begin + ImplicitThisValue.ValueType:=bvtUNDEFINED; + ImplicitThisValue.Obj:=nil; + end; +end; + +function TBESENObjectEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +begin + BindingObject.PutIndex(I,ID,V,S); + result:=true; +end; + +procedure TBESENObjectEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); + procedure ThrowIt; + begin + BESENThrowTypeError('GetIndexValue failed'); + end; +begin + if not BindingObject.GetIndex(I,ID,R,BindingObject) then begin + if S then begin + ThrowIt; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; +end; + +function TBESENObjectEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; +begin + result:=BindingObject.DeleteIndex(I,iD,false); +end; + +procedure TBESENObjectEnvironmentRecord.Finalize; +begin + BindingObject:=nil; + inherited Finalize; +end; + +procedure TBESENObjectEnvironmentRecord.Mark; +begin + TBESEN(Instance).GarbageCollector.GrayIt(BindingObject); + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectError.pas b/3rd/besen/src/BESENObjectError.pas new file mode 100644 index 000000000..e0d26d1a9 --- /dev/null +++ b/3rd/besen/src/BESENObjectError.pas @@ -0,0 +1,74 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectError; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectError=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectError.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Error'; + ObjectName:=''; + + OverwriteData('length',BESENNumberValue(1),[]); +end; + +destructor TBESENObjectError.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectError.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectError.Mark; +begin + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectErrorConstructor.pas b/3rd/besen/src/BESENObjectErrorConstructor.pas new file mode 100644 index 000000000..ecbe71fb3 --- /dev/null +++ b/3rd/besen/src/BESENObjectErrorConstructor.pas @@ -0,0 +1,108 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectErrorConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectErrorConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectError; + +constructor TBESENObjectErrorConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Error'; +end; + +destructor TBESENObjectErrorConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectErrorConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectError; + r2:TBESENObject; + r3:TBESENValue; +begin + // ES5 errata fix + Get('prototype',r3); + if r3.ValueType=bvtOBJECT then begin + r2:=TBESENObject(r3.Obj); + end else begin + r2:=nil; + end; + r1:=TBESENObjectError.Create(Instance,r2,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + r1.OverwriteData('message',BESENStringValue(TBESEN(Instance).ToStr(Arguments^[0]^)),[bopaWRITABLE,bopaCONFIGURABLE]); + end else begin + r1.OverwriteData('message',BESENStringValue(''),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectErrorConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + // ES5 Errate fix + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectErrorConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectErrorConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/3rd/besen/src/BESENObjectErrorPrototype.pas b/3rd/besen/src/BESENObjectErrorPrototype.pas new file mode 100644 index 000000000..1fd6e4453 --- /dev/null +++ b/3rd/besen/src/BESENObjectErrorPrototype.pas @@ -0,0 +1,99 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectErrorPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectError,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectErrorPrototype=class(TBESENObjectError) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectErrorPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Error'; + ObjectName:='Error'; + + OverwriteData('name',BESENStringValue('Error'),[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('message',BESENStringValue(''),[bopaWRITABLE,bopaCONFIGURABLE]); + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + +end; + +destructor TBESENObjectErrorPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectErrorPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var nv,mv:TBESENValue; + n,m:TBESENString; +begin + // ES5 errata fix + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObjectError(TBESENObject(ThisArgument.Obj)).Get('name',nv); + TBESENObjectError(TBESENObject(ThisArgument.Obj)).Get('message',mv); + if nv.ValueType=bvtUNDEFINED then begin + n:='Error'; + end else begin + n:=TBESEN(Instance).ToStr(nv); + end; + if mv.ValueType=bvtUNDEFINED then begin + m:=''; + end else begin + m:=TBESEN(Instance).ToStr(mv); + end; + if (length(n)=0) and (length(m)=0) then begin + ResultValue:=BESENStringValue('Error'); + end else if length(n)=0 then begin + ResultValue:=BESENStringValue(m); + end else if length(m)=0 then begin + ResultValue:=BESENStringValue(n); + end else begin + ResultValue:=BESENStringValue(n+': '+m); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectFunction.pas b/3rd/besen/src/BESENObjectFunction.pas new file mode 100644 index 000000000..d857cb3ae --- /dev/null +++ b/3rd/besen/src/BESENObjectFunction.pas @@ -0,0 +1,122 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectFunction=class(TBESENObject) + public + SecurityDomain:pointer; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetSecurityDomain:pointer; override; + function HasGetSecurityDomain:TBESENBoolean; override; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; + function HasHasInstance:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='function'; + + SecurityDomain:=nil; + + OverwriteData('length',BESENNumberValue(1),[]); +end; + +destructor TBESENObjectFunction.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectFunction.GetSecurityDomain:pointer; +begin + result:=SecurityDomain; +end; + +function TBESENObjectFunction.HasGetSecurityDomain:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectFunction.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +var v,o:TBESENObject; + ov:TBESENValue; +begin + result:=false; + if AInstance.ValueType<>bvtOBJECT then begin + exit; + end; + v:=TBESENObject(AInstance.Obj); + Get('prototype',ov); + if ov.ValueType<>bvtOBJECT then begin + raise EBESENTypeError.Create('Prototype not object'); + end; + o:=TBESENObject(ov.Obj); + while true do begin + v:=v.Prototype; + if not assigned(v) then begin + break; + end else if TBESEN(Instance).SameObject(v,o) then begin + result:=true; + break; + end; + end; +end; + +function TBESENObjectFunction.HasHasInstance:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectFunction.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectFunction.Mark; +begin + inherited Mark; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectFunctionArguments.pas b/3rd/besen/src/BESENObjectFunctionArguments.pas new file mode 100644 index 000000000..1ca9914f6 --- /dev/null +++ b/3rd/besen/src/BESENObjectFunctionArguments.pas @@ -0,0 +1,230 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunctionArguments; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectFunctionArguments=class(TBESENObject) + public + ParameterMap:TBESENObject; + IsStrict:longbool; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; + procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENGlobals,BESENStringUtils,BESENErrors; + +constructor TBESENObjectFunctionArguments.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Arguments'; + ObjectName:='Arguments'; + ParameterMap:=nil; +end; + +destructor TBESENObjectFunctionArguments.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectFunctionArguments.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var MappedDescriptor:TBESENObjectPropertyDescriptor; +begin + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited GetOwnProperty(P,Descriptor,Hash); + end else begin + result:=inherited GetOwnProperty(P,Descriptor,Hash); + if result then begin + MappedDescriptor:=Descriptor; + if not ParameterMap.GetOwnProperty(P,MappedDescriptor,Hash) then begin + ParameterMap.Get(P,Descriptor.Value); + result:=Descriptor.Presents<>[]; + end; + end; + end; +end; + +function TBESENObjectFunctionArguments.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + end else begin + if ParameterMap.GetOwnProperty(P,Descriptor,Hash) then begin + result:=ParameterMap.GetEx(P,AResult,Descriptor,Base,Hash); + end else begin + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + if IsStrict and (P='caller') then begin + BESENThrowCaller; + end; + end; + end; +end; + +function TBESENObjectFunctionArguments.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if not assigned(Base) then begin + Base:=self; + end; + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited GetIndex(Index,ID,AResult,Base); + end else begin + if ParameterMap.GetOwnProperty(TBESEN(Instance).KeyIDManager.List[ID],Descriptor) then begin + result:=ParameterMap.GetEx(TBESEN(Instance).KeyIDManager.List[ID],AResult,Descriptor,Base); + end else begin + result:=inherited GetIndex(Index,ID,AResult,Base); + if IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin + BESENThrowCaller; + end; + end; + end; +end; + +function TBESENObjectFunctionArguments.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var IsMapped:boolean; +begin + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited DeleteEx(P,Throw,Descriptor,Hash); + end else begin + IsMapped:=ParameterMap.GetOwnProperty(P,Descriptor,Hash); + result:=inherited DeleteEx(P,Throw,Descriptor,Hash); + if result and IsMapped then begin + ParameterMap.DeleteEx(P,false,Descriptor,Hash); + end; + end; +end; + +procedure TBESENObjectFunctionArguments.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +begin + PutFull(P,V,false,Descriptor,OwnDescriptor,TempValue,Hash); +end; + +procedure TBESENObjectFunctionArguments.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); +begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); +end; + +function TBESENObjectFunctionArguments.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var IsMapped,Allowed:boolean; + procedure ThrowIt; + begin + BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); + end; +begin + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); + end else begin + IsMapped:=ParameterMap.GetOwnProperty(P,Current,Hash); + Allowed:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); + if not Allowed then begin + if Throw then begin + ThrowIt; + end; + result:=false; + exit; + end; + if IsMapped then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + ParameterMap.DeleteEx(p,false,Current,Hash); + end else begin + if boppVALUE in Descriptor.Presents then begin + ParameterMap.Put(p,Descriptor.Value,Throw,Hash); + end; + if (boppWRITABLE in Descriptor.Presents) and not (bopaWRITABLE in Descriptor.Attributes) then begin + ParameterMap.DeleteEx(p,false,Current,Hash); + end; + end; + end; + result:=true; + end; +end; + +procedure TBESENObjectFunctionArguments.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); +var i,j:integer; + s:TBESENString; + v:TBESENValue; + procedure ThrowIt; + begin + BESENThrowTypeError('Bad default value'); + end; +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + s:='['; + Get('length',v,self,BESENLengthHash); + j:=TBESEN(Instance).ToInt32(v); + for i:=0 to j-1 do begin + if i>0 then begin + s:=s+', '; + end; + Get(IntToStr(i),v); + s:=s+inttostr(i)+'='+TBESEN(Instance).ToStr(v); + end; + s:=s+']'; + AResult:=BESENStringValue(s); + end else begin + inherited DefaultValue(AHint,AResult); + end; +end; + +procedure TBESENObjectFunctionArguments.Finalize; +begin + ParameterMap:=nil; + inherited Finalize; +end; + +procedure TBESENObjectFunctionArguments.Mark; +begin + if assigned(ParameterMap) then begin + TBESEN(Instance).GarbageCollector.GrayIt(ParameterMap); + end; + inherited Mark; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectFunctionConstructor.pas b/3rd/besen/src/BESENObjectFunctionConstructor.pas new file mode 100644 index 000000000..97dd867fb --- /dev/null +++ b/3rd/besen/src/BESENObjectFunctionConstructor.pas @@ -0,0 +1,124 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunctionConstructor; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectFunctionConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENASTNodes,BESENStringUtils,BESENUtils,BESENObjectDeclaredFunction; + +constructor TBESENObjectFunctionConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); +end; + +destructor TBESENObjectFunctionConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectFunctionConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var Body,Parameters:TBESENString; + i:integer; + Node:TBESENASTNode; + f:TBESENObjectDeclaredFunction; + OldIsStrict:boolean; +begin + Body:=''; + Parameters:=''; + OldIsStrict:=TBESEN(Instance).IsStrict; + try + if CountArguments>0 then begin + for i:=0 to CountArguments-2 do begin + if i>0 then begin + Parameters:=Parameters+','; + end; + Parameters:=Parameters+TBESEN(Instance).ToStr(Arguments^[i]^); + end; + Body:=TBESEN(Instance).ToStr(Arguments[CountArguments-1]^); + end; + TBESEN(Instance).IsStrict:=false; + Node:=TBESEN(Instance).Compile({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}Body{$ifndef BESENSingleStringType}),BESENUTF16ToUTF8({$endif}Parameters{$ifndef BESENSingleStringType}){$endif},true); + if assigned(Node) and (Node is TBESENASTNodeFunctionExpression) then begin + if assigned(TBESENASTNodeFunctionExpression(Node).Container.Literal.Name) then begin + if TBESEN(Instance).IsStrict then begin + if TBESENASTNodeFunctionExpression(Node).Container.Literal.Name.Name='eval' then begin + raise EBESENSyntaxError.Create('"eval" not allowed here'); + end; + end; + f:=TBESEN(Instance).MakeFunction(TBESENASTNodeFunctionExpression(Node).Container.Literal,TBESENASTNodeFunctionExpression(Node).Container.Literal.Name.Name,TBESEN(Instance).GlobalLexicalEnvironment); + end else begin + f:=TBESEN(Instance).MakeFunction(TBESENASTNodeFunctionExpression(Node).Container.Literal,'',TBESEN(Instance).GlobalLexicalEnvironment); + end; + TBESEN(Instance).GarbageCollector.Add(f); + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=f; + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + BESENFreeAndNil(Node); + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENObjectFunctionConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectFunctionConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectFunctionConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectFunctionPrototype.pas b/3rd/besen/src/BESENObjectFunctionPrototype.pas new file mode 100644 index 000000000..e335f62fb --- /dev/null +++ b/3rd/besen/src/BESENObjectFunctionPrototype.pas @@ -0,0 +1,237 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunctionPrototype; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectNativeFunction; + +type TBESENObjectFunctionPrototype=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeApply(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBind(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENGlobals,BESENStringUtils,BESENErrors,BESENObjectDeclaredFunction, + BESENObjectThrowTypeErrorFunction,BESENObjectArgGetterFunction, + BESENObjectArgSetterFunction,BESENObjectBindingFunction; + +constructor TBESENObjectFunctionPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='prototype'; + + OverwriteData('length',BESENNumberValue(0),[]); + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; +end; + +destructor TBESENObjectFunctionPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectFunctionPrototype.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +function TBESENObjectFunctionPrototype.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectFunctionPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ThisArgumentObj:TObject; +begin + ThisArgumentObj:=ThisArgument.Obj; + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgumentObj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectDeclaredFunction) then begin + if assigned(TBESENObjectDeclaredFunction(ThisArgumentObj).Node) then begin + ResultValue:=BESENStringValue(BESENUTF8ToUTF16(TBESEN(Instance).Decompile(TBESENObjectDeclaredFunction(ThisArgumentObj).Node))); + end else begin + ResultValue:=BESENStringValue('function () {'#10'}'#10); + end; + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectNativeFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectThrowTypeErrorFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, ThrowTypeError]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectArgGetterFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, ArgGetter]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectArgSetterFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, ArgSetter]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectBindingFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, Binding]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectFunction) then begin + ResultValue:=BESENStringValue('function () {'#10'}'#10); + end else begin + raise EBESENTypeError.Create('Not a function object'); + end; +end; + +procedure TBESENObjectFunctionPrototype.NativeApply(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var CallThisArg:TBESENValue; + v2,v3:TBESENValue; + vArgs:TBESENValues; + pArgs:TBESENValuePointers; + i,j:integer; +begin + // ES5 errata fix + vArgs:=nil; + pArgs:=nil; + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not TBESENObject(ThisArgument.Obj).HasCall then begin + raise EBESENTypeError.Create('No callable'); + end; + v2:=BESENEmptyValue; + v3:=BESENEmptyValue; + try + if CountArguments<1 then begin + CallThisArg:=BESENUndefinedValue; + end else begin + BESENCopyValue(CallThisArg,Arguments^[0]^); + if (CountArguments>1) and not (Arguments^[1]^.ValueType in [bvtUNDEFINED,bvtNULL]) then begin + TBESEN(Instance).ToObjectValue(Arguments^[1]^,v2); + if (v2.ValueType=bvtOBJECT) and assigned(v2.Obj) then begin + TBESENObject(v2.Obj).GarbageCollectorLock; + end; + TBESENObject(v2.Obj).Get('length',v3,TBESENObject(v2.Obj),BESENLengthHash); + j:=TBESEN(Instance).ToUInt32(v3); + SetLength(vArgs,j); + SetLength(pArgs,j); + for i:=0 to j-1 do begin + TBESENObject(v2.Obj).Get(inttostr(i),vArgs[i]); + pArgs[i]:=@vArgs[i]; + end; + end; + end; + TBESEN(Instance).ObjectCall(TBESENObject(ThisArgument.Obj),CallThisArg,@pArgs[0],length(pArgs),ResultValue); + finally + if (v2.ValueType=bvtOBJECT) and assigned(v2.Obj) then begin + TBESENObject(v2.Obj).GarbageCollectorUnlock; + end; + SetLength(vArgs,0); + SetLength(pArgs,0); + end; +end; + +procedure TBESENObjectFunctionPrototype.NativeCall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var CallThisArg:TBESENValue; + pArgs:TBESENValuePointers; + i:integer; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not TBESENObject(ThisArgument.Obj).HasCall then begin + raise EBESENTypeError.Create('No callable'); + end; + pArgs:=nil; + try + if CountArguments<1 then begin + CallThisArg:=BESENUndefinedValue; + end else begin + BESENCopyValue(CallThisArg,Arguments^[0]^); + if CountArguments>1 then begin + SetLength(pArgs,CountArguments-1); + for i:=0 to length(pArgs)-1 do begin + pArgs[i]:=Arguments[i+1]; + end; + end; + end; + TBESEN(Instance).ObjectCall(TBESENObject(ThisArgument.Obj),CallThisArg,@pArgs[0],length(pArgs),ResultValue); + finally + SetLength(pArgs,0); + end; +end; + +procedure TBESENObjectFunctionPrototype.NativeBind(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var o:TBESENObjectBindingFunction; + i:integer; + v:TBESENValue; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not TBESENObject(ThisArgument.Obj).HasCall then begin + raise EBESENTypeError.Create('Bad arg'); + end; + o:=TBESENObjectBindingFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,false); + TBESEN(Instance).GarbageCollector.Add(o); + o.GarbageCollectorLock; + try + o.TargetFunction:=TBESENObject(ThisArgument.Obj); + if CountArguments>0 then begin + BESENCopyValue(o.BoundThis,Arguments^[0]^); + end else begin + o.BoundThis.ValueType:=bvtUNDEFINED; + end; + if CountArguments>1 then begin + SetLength(o.BoundArguments,CountArguments-1); + for i:=1 to CountArguments-1 do begin + BESENCopyValue(o.BoundArguments[i-1],Arguments^[i]^); + end; + end else begin + SetLength(o.BoundArguments,0); + end; + if o.TargetFunction is TBESENObjectFunction then begin + TBESENObjectFunction(o.TargetFunction).Get('length',v,o.TargetFunction,BESENLengthHash); + o.OverwriteData('length',BESENNumberValue(max(0,TBESEN(Instance).ToInt(v)-length(o.BoundArguments))),[]); + end else begin + o.OverwriteData('length',BESENNumberValue(0),[]); + end; + o.Extensible:=true; + o.OverwriteAccessor('caller',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + o.OverwriteAccessor('arguments',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + finally + o.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(o); +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectGlobal.pas b/3rd/besen/src/BESENObjectGlobal.pas new file mode 100644 index 000000000..753530099 --- /dev/null +++ b/3rd/besen/src/BESENObjectGlobal.pas @@ -0,0 +1,516 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectGlobal; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor,BESENCharSet; + +type TBESENObjectGlobal=class(TBESENObject) + private + function Encode(const s:TBESENString;const NotToEscapeChars:TBESENCharBitmap):TBESENString; + function Decode(const s:TBESENString;const ReservedChars:TBESENCharBitmap):TBESENString; + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeEval(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeParseInt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeParseFloat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsNaN(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsFinite(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDecodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDecodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEncodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEncodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEscape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeUnescape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCompatability(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENNumberUtils,BESENStringUtils,BESENErrors; + +const BESENCompatibilityModes:TBESENCompatibilityModes=( + (Name:'utf8_unsafe';Flag:COMPAT_UTF8_UNSAFE), + (Name:'sgmlcom';Flag:COMPAT_SGMLCOM), + (Name:'besen';Flag:COMPAT_BESEN), + (Name:'js';Flag:COMPAT_JS)); + +constructor TBESENObjectGlobal.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var v:TBESENValue; +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + + v:=BESENEmptyValue; + + v:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + OverwriteData('NaN',v,[]); + + v:=BESENNumberValue(double(pointer(@BESENDoubleInfPos)^)); + OverwriteData('Infinity',v,[]); + + v:=BESENUndefinedValue; + OverwriteData('undefined',v,[]); + + RegisterNativeFunction('eval',NativeEval,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('parseInt',NativeParseInt,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('parseFloat',NativeParseFloat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isNaN',NativeIsNaN,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isFinite',NativeIsFinite,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('decodeURI',NativeDecodeURI,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('decodeURIComponent',NativeDecodeURIComponent,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('encodeURI',NativeEncodeURI,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('encodeURIComponent',NativeEncodeURIComponent,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + + RegisterNativeFunction('escape',NativeEscape,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('unescape',NativeUnescape,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + RegisterNativeFunction('compat',NativeCompatability,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('compatability',NativeCompatability,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + end; +end; + +destructor TBESENObjectGlobal.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectGlobal.NativeEval(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue:=BESENUndefinedValue; +end; + +procedure TBESENObjectGlobal.NativeParseInt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i,StartPos,UntilPos,r,c:integer; + Negative:boolean; +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + if CountArguments>0 then begin + if CountArguments>1 then begin + r:=TBESEN(Instance).ToInt(Arguments^[1]^); + end else begin + r:=0; + end; + if (r<>0) and ((r<2) or (r>36)) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + exit; + end; + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + i:=1; + while (i<=length(s)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(s[i])))) do begin + inc(i); + end; + if (i<=length(s)) and ((s[i]='-') or (s[i]='+')) then begin + Negative:=s[i]='-'; + inc(i); + end else begin + Negative:=false; + end; + if (r in [0,16]) and ((i+1)<=length(s)) and (s[i]='0') and ((s[i+1]='x') or (s[i+1]='X')) then begin + r:=16; + inc(i,2); + end else if (((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and not TBESEN(Instance).IsStrict) and ((r=0) and ((i<=length(s)) and (s[i]='0'))) then begin + r:=8; + inc(i); + end; + if r=0 then begin + r:=10; + end; + StartPos:=i; + UntilPos:=i; + while UntilPos<=length(s) do begin + c:=word(widechar(s[UntilPos])); + case c of + ord('0')..ord('9'):begin + c:=c-ord('0'); + end; + ord('a')..ord('z'):begin + c:=(c+10)-ord('a'); + end; + ord('A')..ord('Z'):begin + c:=(c+10)-ord('A'); + end; + else begin + break; + end; + end; + if c>=r then begin + break; + end; + inc(UntilPos); + end; + if StartPos>=UntilPos then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + exit; + end; + i:=UntilPos-StartPos; + if r=10 then begin + ResultValue.Num:=BESENStringToNumber(copy(s,StartPos,UntilPos-StartPos),false,false); + end else begin + ResultValue.Num:=BESENStringToNumberBase(copy(s,StartPos,UntilPos-StartPos),r); + end; + if Negative and not BESENIsNaN(ResultValue.Num) then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end; + end; +end; + +procedure TBESENObjectGlobal.NativeParseFloat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + ResultValue.Num:=BESENStringToNumber(TBESEN(Instance).ToStr(Arguments^[0]^),false,false); + end; +end; + +procedure TBESENObjectGlobal.NativeIsNaN(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments=0 then begin + ResultValue.Bool:=true; + end else begin + ResultValue.Bool:=BESENIsNaN(TBESEN(Instance).ToNum(Arguments^[0]^)); + end; +end; + +procedure TBESENObjectGlobal.NativeIsFinite(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments=0 then begin + ResultValue.Bool:=false; + end else begin + ResultValue.Bool:=BESENIsFinite(TBESEN(Instance).ToNum(Arguments^[0]^)); + end; +end; + +function TBESENObjectGlobal.Encode(const s:TBESENString;const NotToEscapeChars:TBESENCharBitmap):TBESENString; +var i:integer; + c:TBESENUTF32CHAR; + r:TBESENString; + procedure DoEscape(v:longword); + begin + r:=r+'%'+BESENHexChars[false,(v shr 4) and $f]+BESENHexChars[false,v and $f]; + end; +begin + r:=''; + i:=1; + while i<=length(s) do begin + c:=word(widechar(s[i])); + if (c and $fc00)=$dc00 then begin + raise EBESENURIError.Create('Bad UTF16 string'); + end else if (c and $fc00)=$d800 then begin + if ((i+1)<=length(s)) and ((word(widechar(s[i+1])) and $fc00)=$dc00) then begin + c:=(((c and $3ff) shl 10) or (word(widechar(s[i+1])) and $3ff))+$10000; + inc(i,2); + end else begin + raise EBESENURIError.Create('Bad UTF16 string'); + end; + end else begin + inc(i); + end; + if c<=$7f then begin + if (NotToEscapeChars[(c and $7f) shr 3] and (1 shl (c and 7)))<>0 then begin + r:=r+widechar(word(c)); + end else begin + DoEscape(c); + end; + end else if c<=$7ff then begin + DoEscape($c0 or (c shr 6)); + DoEscape($80 or (c and $3f)); + end else if c<=$ffff then begin + DoEscape($e0 or (c shr 12)); + DoEscape($80 or ((c shr 6) and $3f)); + DoEscape($80 or (c and $3f)); + end else if c<=$1fffff then begin + DoEscape($f0 or (c shr 18)); + DoEscape($80 or ((c shr 12) and $3f)); + DoEscape($80 or ((c shr 6) and $3f)); + DoEscape($80 or (c and $3f)); + end else begin + raise EBESENURIError.Create('Bad UTF16 string'); + end; + end; + result:=r; +end; + +function TBESENObjectGlobal.Decode(const s:TBESENString;const ReservedChars:TBESENCharBitmap):TBESENString; +const UTF8Mask:array[0..5] of byte=($c0,$e0,$f0,$f8,$fc,$fe); +var i,j,k,h:integer; + c,ac:TBESENUTF32CHAR; +begin + result:=''; + i:=1; + while i<=length(s) do begin + j:=i; + c:=word(widechar(s[i])); + if (c and $fc00)=$dc00 then begin + raise EBESENURIError.Create('Bad UTF16 string'); + end else if (c and $fc00)=$d800 then begin + if ((i+1)<=length(s)) and ((word(widechar(s[i+1])) and $fc00)=$dc00) then begin + c:=(((c and $3ff) shl 10) or (word(widechar(s[i+1])) and $3ff))+$10000; + inc(i,2); + end else begin + raise EBESENURIError.Create('Bad UTF16 string'); + end; + end else begin + inc(i); + end; + if c=ord('%') then begin + if ((i+1)<=length(s)) and (BESENIsHex(word(widechar(s[i]))) and BESENIsHex(word(widechar(s[i+1])))) then begin + c:=(BESENHexValues[word(widechar(s[i]))] shl 4) or BESENHexValues[word(widechar(s[i+1]))]; + end else begin + raise EBESENURIError.Create('Bad URI hex'); + end; + inc(i,2); + if (c and $80)<>0 then begin + k:=1; + while k<6 do begin + if (c and UTF8Mask[k])=UTF8Mask[k-1] then begin + break; + end; + inc(k); + end; + if k>=6 then begin + raise EBESENURIError.Create('Bad UTF8'); + end; + c:=c and not UTF8Mask[k]; + for h:=1 to k do begin + if ((i+2)<=length(s)) and ((s[i]='%') and (BESENIsHex(word(widechar(s[i+1]))) and BESENIsHex(word(widechar(s[i+2]))))) then begin + ac:=(BESENHexValues[word(widechar(s[i+1]))] shl 4) or BESENHexValues[word(widechar(s[i+2]))]; + end else begin + raise EBESENURIError.Create('Bad URI hex'); + end; + inc(i,3); + if (ac and not $3f)<>$80 then begin + raise EBESENURIError.Create('Bad UTF8'); + end; + c:=(C shl 6) or (ac and $3f); + end; + end; + end; + if c<=$ffff then begin + if (c<=$7f) and ((ReservedChars[(c and $7f) shr 3] and (1 shl (c and 7)))<>0) then begin + result:=result+copy(s,j,(i-j)+1); + end else begin + result:=result+widechar(word(c)); + end; + end else if c<=$10ffff then begin + dec(c,$100000); + result:=result+widechar(word($d800 or ((c shr 10) and $3ff)))+widechar(word($dc00 or (c and $3ff))); + end else begin + raise EBESENURIError.Create('Bad unicode'); + end; + end; +end; + +procedure TBESENObjectGlobal.NativeDecodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$58,$98,$00,$ac,$01,$00,$00,$00,$00,$00,$00,$00); // [;/?:@&=+$,#] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Decode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeDecodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00); // [] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Decode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeEncodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$da,$ff,$ff,$af,$ff,$ff,$ff,$87,$fe,$ff,$ff,$47); // [-_.!~*'();/?:@&=+$,#a-zA-Z0-9] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Encode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeEncodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$82,$67,$ff,$03,$fe,$ff,$ff,$87,$fe,$ff,$ff,$47); // [-_.!~*'()a-zA-Z0-9] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Encode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeEscape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const NotToEscapeChars:TBESENCharBitmap=($00,$00,$00,$00,$00,$ec,$ff,$03,$ff,$ff,$ff,$87,$fe,$ff,$ff,$07); // [A-Za-z0-9@*_+\-./] +var s,ss:TBESENString; + i:integer; + c:word; + HexUppercase:boolean; +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + HexUppercase:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + ss:=''; + for i:=1 to length(s) do begin + c:=word(widechar(s[i])); + if (c<$80) and ((NotToEscapeChars[c shr 3] and (1 shl (c and 7)))<>0) then begin + ss:=ss+widechar(c); + end else if c<$100 then begin + ss:=ss+'%'+BESENHexChars[HexUppercase,(c shr 4) and $f]+BESENHexChars[HexUppercase,c and $f]; + end else begin + ss:=ss+'%u'+BESENHexChars[HexUppercase,(c shr 12) and $f]+BESENHexChars[HexUppercase,(c shr 8) and $f]+BESENHexChars[HexUppercase,(c shr 4) and $f]+BESENHexChars[HexUppercase,c and $f]; + end; + end; + ResultValue:=BESENStringValue(ss); + end; +end; + +procedure TBESENObjectGlobal.NativeUnescape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s,ss:TBESENString; + i:integer; + c:word; +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + ss:=''; + i:=1; + while i<=length(s) do begin + c:=word(widechar(s[i])); + if c=ord('%') then begin + inc(i); + if ((i+4)<=length(s)) and (s[i]='u') then begin + ss:=ss+widechar(word((BESENHexValues[word(widechar(s[i+1]))] shl 12) or (BESENHexValues[word(widechar(s[i+2]))] shl 8) or (BESENHexValues[word(widechar(s[i+3]))] shl 4) or BESENHexValues[word(widechar(s[i+4]))])); + inc(i,5); + end else if (i+1)<=length(s) then begin + ss:=ss+widechar(word((BESENHexValues[word(widechar(s[i]))] shl 4) or BESENHexValues[word(widechar(s[i+1]))])); + inc(i,2); + end else begin + ss:=ss+widechar(c); + inc(i); + end; + end else begin + ss:=ss+widechar(c); + inc(i); + end; + end; + ResultValue:=BESENStringValue(ss); + end; +end; + +procedure TBESENObjectGlobal.NativeCompatability(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ParseCompatibility(s:TBESENString); + var No:boolean; + i:integer; + begin + s:=BESENLowercase(s); + if copy(s,1,3)='no_' then begin + System.delete(s,1,3); + No:=true; + end else if copy(s,1,4)='not_' then begin + System.delete(s,1,4); + No:=true; + end else if copy(s,1,1)='-' then begin + System.delete(s,1,1); + No:=true; + end else if copy(s,1,1)='!' then begin + System.delete(s,1,1); + No:=true; + end else if copy(s,1,1)='~' then begin + System.delete(s,1,1); + No:=true; + end else begin + No:=false; + end; + for i:=low(TBESENCompatibilityModes) to high(TBESENCompatibilityModes) do begin + if s=BESENCompatibilityModes[i].Name then begin + if No then begin + TBESEN(Instance).Compatibility:=TBESEN(Instance).Compatibility and not BESENCompatibilityModes[i].Flag; + end else begin + TBESEN(Instance).Compatibility:=TBESEN(Instance).Compatibility or BESENCompatibilityModes[i].Flag; + end; + break; + end; + end; + end; +var i:integer; + s,ps:TBESENString; +begin + s:=''; + for i:=0 to CountArguments-1 do begin + if length(s)>0 then begin + s:=s+' '; + end; + s:=TBESEN(Instance).ToStr(Arguments^[i]^); + end; + ps:=''; + for i:=1 to length(s) do begin + if BESENUnicodeIsStringWhiteSpace(word(widechar(s[i]))) then begin + if length(ps)>0 then begin + ParseCompatibility(ps); + ps:=''; + end; + end else begin + ps:=ps+s[i]; + end; + end; + if length(ps)>0 then begin + ParseCompatibility(ps); + ps:=''; + end; + s:=''; + for i:=low(TBESENCompatibilityModes) to high(TBESENCompatibilityModes) do begin + if (TBESEN(Instance).Compatibility and BESENCompatibilityModes[i].Flag)<>0 then begin + if length(s)>0 then begin + s:=s+' '; + end; + s:=s+BESENCompatibilityModes[i].Name; + end; + end; + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:=s; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectJSON.pas b/3rd/besen/src/BESENObjectJSON.pas new file mode 100644 index 000000000..f7d1b0af9 --- /dev/null +++ b/3rd/besen/src/BESENObjectJSON.pas @@ -0,0 +1,439 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectJSON; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectJSON=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeStringify(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENGlobals,BESENUtils,BESENArrayUtils,BESENStringUtils,BESENPointerList, + BESENStringTree,BESENNumberUtils,BESENErrors,BESENObjectBoolean,BESENObjectNumber, + BESENObjectString,BESENObjectArray; + +constructor TBESENObjectJSON.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='JSON'; + + RegisterNativeFunction('parse',NativeParse,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('stringify',NativeStringify,3,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectJSON.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectJSON.NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Root,Recviver:TBESENObject; + procedure Walk(const Holder:TBESENObject;const Name:TBESENString;var rv:TBESENValue); + var Val,NewElement,Temp:TBESENValue; + i,Len:int64; + Enumerator:TBESENObjectPropertyEnumerator; + PropKey:TBESENString; + Keys:TBESENStrings; + p:TBESENString; + ValuePointers:array[0..1] of PBESENValue; + o:TBESENObject; + begin + Keys:=nil; + Holder.Get(Name,Val); + if (Val.ValueType=bvtOBJECT) and assigned(Val.Obj) then begin + o:=TBESENObject(Val.Obj); + o.GarbageCollectorLock; + try + if Val.Obj is TBESENObjectArray then begin + i:=0; + TBESENObject(Val.Obj).Get('length',Temp,TBESENObject(Val.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToInt(Temp); + while i<Len do begin + Walk(TBESENObject(Val.Obj),BESENArrayIndexToStr(i),NewElement); + if NewElement.ValueType=bvtUNDEFINED then begin + TBESENObject(Val.Obj).Delete(BESENArrayIndexToStr(i),false); + end else begin + TBESENObject(Val.Obj).DefineOwnProperty(BESENArrayIndexToStr(i),BESENDataPropertyDescriptor(NewElement,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(i); + end; + end else begin + try + i:=0; + Enumerator:=nil; + PropKey:=''; + try + Enumerator:=TBESENObject(Val.Obj).Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(PropKey) do begin + if i>=length(Keys) then begin + SetLength(Keys,i+256); + end; + Keys[i]:=PropKey; + inc(i); + end; + finally + BESENFreeAndNil(Enumerator); + end; + i:=0; + while i<length(Keys) do begin + p:=Keys[i]; + Walk(TBESENObject(Val.Obj),p,NewElement); + if NewElement.ValueType=bvtUNDEFINED then begin + TBESENObject(Val.Obj).Delete(p,false); + end else begin + TBESENObject(Val.Obj).DefineOwnProperty(p,BESENDataPropertyDescriptor(NewElement,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(i); + end; + finally + SetLength(Keys,0); + end; + end; + finally + o.GarbageCollectorUnlock; + end; + end; + Temp.ValueType:=bvtSTRING; + Temp.Str:=Name; + ValuePointers[0]:=@Temp; + ValuePointers[1]:=@Val; + TBESEN(Instance).ObjectCall(Recviver,BESENObjectValue(Holder),@ValuePointers,2,rv); + end; +begin + if CountArguments>0 then begin + ResultValue:=TBESEN(Instance).JSONEval({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}TBESEN(Instance).ToStr(Arguments^[0]^){$ifndef BESENSingleStringType}){$endif}); + end else begin + ResultValue:=BESENUndefinedValue; + end; + if (CountArguments>1) and BESENIsCallable(Arguments^[1]^) then begin + Recviver:=TBESENObject(Arguments^[1]^.Obj); + Root:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + TBESEN(Instance).GarbageCollector.Add(Root); + Root.GarbageCollectorLock; + try + Root.DefineOwnProperty('',BESENDataPropertyDescriptor(ResultValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + Walk(Root,'',ResultValue); + finally + Root.GarbageCollectorUnlock; + end; + end; +end; + +procedure TBESENObjectJSON.NativeStringify(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Value,Replacer,Space,v:TBESENValue; + i,j,k:int64; + Gap,Ident,vs:TBESENString; + ReplacerFunction,Wrapper:TBESENObject; + Stack:TBESENPointerList; + PropertyList:TBESENStrings; + HasPropertyList:boolean; + PropertyListStringTree:TBESENStringTree; + PropertyListStringTreeData:TBESENStringTreeData; + procedure Str(const Key:TBESENSTRING;const Holder:TBESENObject;var rv:TBESENValue); + var Value,toJSON,v,Temp:TBESENValue; + Output,StepBack:TBESENString; + i,j:int64; + oi:integer; + Enumerator:TBESENObjectPropertyEnumerator; + PropKey:TBESENString; + Keys:TBESENStrings; + ValuePointers:array[0..1] of PBESENValue; + begin + Keys:=nil; + Holder.Get(Key,Value); + if Value.ValueType=bvtOBJECT then begin + TBESENObject(Value.Obj).Get('toJSON',toJSON); + iF BESENIsCallable(toJSON) then begin + v.ValueType:=bvtSTRING; + v.Str:=Key; + ValuePointers[0]:=@v; + TBESEN(Instance).ObjectCall(TBESENObject(toJSON.Obj),Value,@ValuePointers,1,Temp); + BESENCopyValue(Value,Temp); + end; + end; + if assigned(ReplacerFunction) then begin + v.ValueType:=bvtSTRING; + v.Str:=Key; + ValuePointers[0]:=@v; + ValuePointers[1]:=@Value; + TBESEN(Instance).ObjectCall(ReplacerFunction,BESENObjectValue(Holder),@ValuePointers,2,Temp); + BESENCopyValue(Value,Temp); + end; + if (Value.ValueType=bvtOBJECT) and not assigned(Value.Obj) then begin + Value.ValueType:=bvtNULL; + end; + if Value.ValueType=bvtOBJECT then begin + if Value.Obj is TBESENObjectNumber then begin + TBESEN(Instance).ToNumberValue(Value,Temp); + BESENCopyValue(Value,Temp); + end else if Value.Obj is TBESENObjectString then begin + TBESEN(Instance).ToStringValue(Value,Temp); + BESENCopyValue(Value,Temp); + end else if Value.Obj is TBESENObjectBoolean then begin + TBESEN(Instance).ToPrimitiveValue(Value,Temp); + BESENCopyValue(Value,Temp); + end; + end; + case Value.ValueType of + bvtNULL:begin + rv:=BESENStringValue('null'); + end; + bvtBOOLEAN:begin + if Value.Bool then begin + rv:=BESENStringValue('true'); + end else begin + rv:=BESENStringValue('false'); + end; + end; + bvtSTRING:begin + rv:=BESENStringValue(BESENJSONStringQuote(TBESEN(Instance).ToStr(Value))); + end; + bvtNUMBER:begin + if BESENIsFinite(Value.Num) then begin + TBESEN(Instance).ToStringValue(Value,rv); + end else begin + rv:=BESENStringValue('null'); + end; + end; + bvtOBJECT:begin + if Stack.Find(Value.Obj)>=0 then begin + raise EBESENTypeError.Create('Cyclical situation found'); + end; + oi:=Stack.Add(Value.Obj); + StepBack:=Ident; + Ident:=Ident+Gap; + if BESENIsCallable(Value) then begin + rv:=BESENUndefinedValue; + end else if Value.Obj is TBESENObjectArray then begin + TBESENObject(Value.Obj).Get('length',Temp,TBESENObject(Value.Obj),BESENLengthHash); + j:=TBESEN(Instance).ToUInt32(Temp); + if j=0 then begin + Output:='[]'; + end else begin + if length(Ident)>0 then begin + Output:='['#10+Ident; + end else begin + Output:='['; + end; + i:=0; + while i<j do begin + Str(BESENArrayIndexToStr(i),TBESENObject(Value.Obj),v); + if v.ValueType=bvtUNDEFINED then begin + Output:=Output+'null'; + end else begin + Output:=Output+TBESEN(Instance).ToStr(v); + end; + inc(i); + if i<j then begin + Output:=Output+','; + if length(Ident)>0 then begin + Output:=Output+#10+Ident; + end; + end; + end; + if length(Ident)>0 then begin + Output:=Output+#10+StepBack+']'; + end else begin + Output:=Output+']'; + end; + end; + rv:=BESENStringValue(Output); + end else begin + try + if HasPropertyList and (length(PropertyList)>0) then begin + Keys:=copy(PropertyList,0,length(PropertyList)); + j:=length(Keys); + end else begin + j:=0; + Enumerator:=nil; + PropKey:=''; + try + Enumerator:=TBESENObject(Value.Obj).Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(PropKey) do begin + if j>=length(Keys) then begin + SetLength(Keys,j+256); + end; + Keys[j]:=PropKey; + inc(j); + end; + finally + BESENFreeAndNil(Enumerator); + end; + end; + if j=0 then begin + Output:='{}'; + end else begin + if length(Ident)>0 then begin + Output:='{'#10+Ident; + end else begin + Output:='{'; + end; + i:=0; + while i<j do begin + Str(Keys[i],TBESENObject(Value.Obj),v); + Output:=Output+BESENJSONStringQuote(Keys[i]); + if length(Ident)>0 then begin + Output:=Output+': '; + end else begin + Output:=Output+':'; + end; + if v.ValueType=bvtUNDEFINED then begin + Output:=Output+'null'; + end else begin + Output:=Output+TBESEN(Instance).ToStr(v); + end; + inc(i); + if i<j then begin + Output:=Output+','; + if length(Ident)>0 then begin + Output:=Output+#10+Ident; + end; + end; + end; + if length(Ident)>0 then begin + Output:=Output+#10+StepBack+'}'; + end else begin + Output:=Output+'}'; + end; + end; + rv:=BESENStringValue(Output); + finally + SetLength(Keys,0); + end; + end; + Stack.Delete(oi); + Ident:=StepBack; + end; + else begin + rv:=BESENUndefinedValue; + end; + end; + end; +var PropItem:TBESENObjectProperty; +begin + Gap:=''; + Ident:=''; + ReplacerFunction:=nil; + PropertyList:=nil; + Stack:=TBESENPointerList.Create; + try + if CountArguments>0 then begin + Value:=Arguments^[0]^; + end else begin + Value:=BESENUndefinedValue; + end; + if CountArguments>1 then begin + Replacer:=Arguments^[1]^; + end else begin + Replacer:=BESENUndefinedValue; + end; + HasPropertyList:=false; + if (Replacer.ValueType=bvtOBJECT) and assigned(Replacer.Obj) then begin + if BESENIsCallable(Replacer) then begin + ReplacerFunction:=TBESENObject(Replacer.Obj); + end else if Replacer.Obj is TBESENObjectArray then begin + PropertyListStringTree:=TBESENStringTree.Create; + try + HasPropertyList:=true; + PropItem:=TBESENObject(Replacer.Obj).Properties.First; + k:=0; + while assigned(PropItem) do begin + if (boppENUMERABLE in PropItem.Descriptor.Presents) and (bopaENUMERABLE in PropItem.Descriptor.Attributes) and BESENArrayToIndex(PropItem.Key,i) then begin + TBESENObject(Replacer.Obj).Get(PropItem.Key,v); + if (v.ValueType in [bvtSTRING,bvtNUMBER]) or ((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and ((TBESENObject(v.Obj) is TBESENObjectString) or (TBESENObject(v.Obj) is TBESENObjectNumber))) then begin + vs:=TBESEN(Instance).ToStr(v); + if not PropertyListStringTree.Find(vs,PropertyListStringTreeData) then begin + PropertyListStringTreeData.i:=k; + PropertyListStringTree.Add(vs,PropertyListStringTreeData); + if k>=length(PropertyList) then begin + SetLength(PropertyList,k+256); + end; + PropertyList[k]:=vs; + inc(k); + end; + end; + end; + PropItem:=PropItem.Next; + end; + SetLength(PropertyList,k); + finally + BESENFreeAndNil(PropertyListStringTree); + end; + end; + end; + if CountArguments>2 then begin + if (Arguments^[2]^.ValueType=bvtOBJECT) and assigned(Arguments^[2]^.Obj) then begin + if Arguments^[2]^.Obj is TBESENObjectNumber then begin + TBESEN(Instance).ToNumberValue(Arguments^[2]^,Space); + end else if Arguments^[2]^.Obj is TBESENObjectString then begin + TBESEN(Instance).ToStringValue(Arguments^[2]^,Space); + end; + end else begin + Space:=Arguments^[2]^; + end; + if Space.ValueType=bvtNumber then begin + j:=min(10,TBESEN(Instance).ToInt(Space)); + i:=0; + while i<j do begin + Gap:=Gap+' '; + inc(i); + end; + end else if Space.ValueType=bvtSTRING then begin + Gap:=copy(TBESEN(Instance).ToStr(Space),1,10); + end; + end; + Wrapper:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + TBESEN(Instance).GarbageCollector.Add(Wrapper); + Wrapper.GarbageCollectorLock; + try + Wrapper.DefineOwnProperty('',BESENDataPropertyDescriptor(Value,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + Str('',Wrapper,ResultValue); + finally + Wrapper.GarbageCollectorUnlock; + end; + finally + BESENFreeAndNil(Stack); + SetLength(PropertyList,0); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectMath.pas b/3rd/besen/src/BESENObjectMath.pas new file mode 100644 index 000000000..e7bcc0307 --- /dev/null +++ b/3rd/besen/src/BESENObjectMath.pas @@ -0,0 +1,524 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectMath; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectMath=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeAbs(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeACos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeASin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeATan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeATan2(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCeil(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeExp(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFloor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLog(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMax(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeRandom(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeRound(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSqrt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENNumberUtils; + +constructor TBESENObjectMath.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var v:TBESENValue; +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Math'; + + v:=BESENEmptyValue; + v:=BESENNumberValue(2.7182818284590452354); + OverwriteData('E',v,[]); + + v:=BESENNumberValue(2.7182818284590452354); + OverwriteData('E',v,[]); + + v:=BESENNumberValue(2.302585092994046); + OverwriteData('LN10',v,[]); + + v:=BESENNumberValue(0.6931471805599453); + OverwriteData('LN2',v,[]); + + v:=BESENNumberValue(1.4426950408889634); + OverwriteData('LOG2E',v,[]); + + v:=BESENNumberValue(0.4342944819032518); + OverwriteData('LOG10E',v,[]); + + v:=BESENNumberValue(3.1415926535897932); + OverwriteData('PI',v,[]); + + v:=BESENNumberValue(0.7071067811865476); + OverwriteData('SQRT1_2',v,[]); + + v:=BESENNumberValue(1.4142135623730951); + OverwriteData('SQRT2',v,[]); + + RegisterNativeFunction('abs',NativeAbs,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('acos',NativeACos,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('asin',NativeASin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('atan',NativeATan,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('atan2',NativeATan2,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('ceil',NativeCeil,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('cos',NativeCos,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('exp',NativeExp,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('floor',NativeFloor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('log',NativeLog,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('max',NativeMax,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('min',NativeMin,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('pow',NativePow,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('random',NativeRandom,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('round',NativeRound,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sin',NativeSin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sqrt',NativeSqrt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('tan',NativeTan,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectMath.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectMath.NativeAbs(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not BESENIsNaN(ResultValue.Num) then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi and $7fffffff; + end; + end; +end; + +procedure TBESENObjectMath.NativeACos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not BESENIsNaN(ResultValue.Num) then begin + if (ResultValue.Num<-1) or (ResultValue.Num>1) then begin + int64(pointer(@ResultValue.Num)^):=int64(pointer(@BESENDoubleNaN)^); + end else if ResultValue.Num=1 then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=arccos(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeASin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not BESENIsNaN(ResultValue.Num) then begin + if (ResultValue.Num<-1) or (ResultValue.Num>1) then begin + int64(pointer(@ResultValue.Num)^):=int64(pointer(@BESENDoubleNaN)^); + end else if not BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=arcsin(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeATan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not (BESENIsNaN(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin + if BESENIsPosInfinite(ResultValue.Num) then begin + ResultValue.Num:=PI*0.5; + end else if BESENIsNegInfinite(ResultValue.Num) then begin + ResultValue.Num:=-(PI*0.5); + end else begin + ResultValue.Num:=arctan(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeATan2(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,y:TBESENNumber; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments<2 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + y:=TBESEN(Instance).ToNum(Arguments^[0]^); + x:=TBESEN(Instance).ToNum(Arguments^[1]^); + if BESENIsNaN(y) or BESENIsNaN(x) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if (y>0) and BESENIsZero(x) then begin + ResultValue.Num:=PI*0.5; + end else if BESENIsPosZero(y) and ((x>0) or BESENIsPosZero(x)) then begin + ResultValue.Num:=0; + end else if BESENIsPosZero(y) and (BESENIsNegZero(x) or (x<0)) then begin + ResultValue.Num:=PI; + end else if BESENIsNegZero(y) and ((BESENIsFinite(x) and not BESENIsNegative(x)) or BESENIsPosZero(x)) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else if BESENIsNegZero(y) and (BESENIsNegZero(x) or (x<0)) then begin + ResultValue.Num:=-PI; + end else if (y<0) and BESENIsZero(x) then begin + ResultValue.Num:=-PI*0.5; + end else if ((y>0) and BESENIsFinite(y)) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=0; + end else if ((y>0) and BESENIsFinite(y)) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=PI; + end else if ((y<0) and BESENIsFinite(y)) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else if ((y<0) and BESENIsFinite(y)) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=-PI; + end else if BESENIsPosInfinite(y) and BESENIsFinite(x) then begin + ResultValue.Num:=PI*0.5; + end else if BESENIsNegInfinite(y) and BESENIsFinite(x) then begin + ResultValue.Num:=-(PI*0.5); + end else if BESENIsPosInfinite(y) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=PI*0.25; + end else if BESENIsPosInfinite(y) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=(3*PI)*0.25; + end else if BESENIsNegInfinite(y) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=-(PI*0.25); + end else if BESENIsNegInfinite(y) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=-((3*PI)*0.25); + end else begin + ResultValue.Num:=arctan2(y,x); + end; + end; +end; + +procedure TBESENObjectMath.NativeCeil(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not (BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin + if (ResultValue.Num<0) and (ResultValue.Num>(-1)) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else begin + ResultValue.Num:=BESENCeil(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeCos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=1; + end else begin + ResultValue.Num:=cos(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeExp(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=1; + end else if BESENIsPosInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsNegInfinite(ResultValue.Num) then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=exp(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeFloor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not (BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin + if (ResultValue.Num>0) and (ResultValue.Num<1) then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=BESENFloor(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeLog(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or (ResultValue.Num<0) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else if ResultValue.Num=1 then begin + ResultValue.Num:=0; + end else if BESENIsPosInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else begin + ResultValue.Num:=ln(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeMax(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,n:TBESENNumber; + i:integer; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else begin + n:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + for i:=0 to CountArguments-1 do begin + x:=TBESEN(Instance).ToNum(Arguments^[i]^); + if BESENIsNaN(x) then begin + n:=TBESENNumber(pointer(@BESENDoubleNaN)^); + break; + end; + if (i=0) or ((x>n) or (BESENIsPosInfinite(x) or (BESENIsPosZero(x) and BESENIsNegZero(n)))) then begin + n:=x; + end; + end; + ResultValue.Num:=n; + end; +end; + +procedure TBESENObjectMath.NativeMin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,n:TBESENNumber; + i:integer; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else begin + n:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + for i:=0 to CountArguments-1 do begin + x:=TBESEN(Instance).ToNum(Arguments^[i]^); + if BESENIsNaN(x) then begin + n:=TBESENNumber(pointer(@BESENDoubleNaN)^); + break; + end; + if (i=0) or ((x<n) or (BESENIsNegInfinite(x) or (BESENIsNegZero(x) and BESENIsPosZero(n)))) then begin + n:=x; + end; + end; + ResultValue.Num:=n; + end; +end; + +procedure TBESENObjectMath.NativePow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,y:TBESENNumber; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments<2 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + x:=TBESEN(Instance).ToNum(Arguments^[0]^); + y:=TBESEN(Instance).ToNum(Arguments^[1]^); + if BESENIsNaN(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(y) then begin + ResultValue.Num:=1; + end else if BESENIsNaN(x) and not BESENIsZero(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if (abs(x)>1) and BESENIsPosInfinite(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if (abs(x)>1) and BESENIsNegInfinite(y) then begin + ResultValue.Num:=0; + end else if (abs(x)=1) and BESENIsInfinite(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if (abs(x)<1) and BESENIsPosInfinite(y) then begin + ResultValue.Num:=0; + end else if (abs(x)<1) and BESENIsNegInfinite(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsPosInfinite(x) and (y>0) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsPosInfinite(x) and (y<0) then begin + ResultValue.Num:=0; + end else if BESENIsNegInfinite(x) and (y>0) then begin + y:=abs(BESENModulo(y,2.0)); + if y=1 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end; + end else if BESENIsNegInfinite(x) and (y<0) then begin + y:=abs(BESENModulo(-y,2.0)); + ResultValue.Num:=0; + if y=1 then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end; + end else if BESENIsPosZero(x) and (y>0) then begin + ResultValue.Num:=0; + end else if BESENIsPosZero(x) and (y<0) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsNegZero(x) and (y>0) then begin + y:=abs(BESENModulo(-y,2.0)); + ResultValue.Num:=0; + if y=1 then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end; + end else if BESENIsNegZero(x) and (y<0) then begin + y:=abs(BESENModulo(y,2.0)); + if y=1 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end; + end else if ((x<0) and BESENIsFinite(x)) and (BESENIsFinite(y) and not BESENIsZero(frac(y))) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + ResultValue.Num:=power(x,y); + end; + end; +end; + +procedure TBESENObjectMath.NativeRandom(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESEN(Instance).RandomGenerator.GetNumber; +end; + +procedure TBESENObjectMath.NativeRound(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not (BESENIsZero(ResultValue.Num) or BESENIsInfinite(ResultValue.Num)) then begin + if (ResultValue.Num>=-0.5) and (ResultValue.Num<0) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else if (ResultValue.Num>0) and (ResultValue.Num<0.5) then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=BESENFloor(ResultValue.Num+0.5); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeSin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=sin(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeSqrt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsNegative(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not (BESENIsZero(ResultValue.Num) or BESENIsPosInfinite(ResultValue.Num)) then begin + ResultValue.Num:=sqrt(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeTan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=tan(ResultValue.Num); + end; + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectNativeFunction.pas b/3rd/besen/src/BESENObjectNativeFunction.pas new file mode 100644 index 000000000..07db4cd3a --- /dev/null +++ b/3rd/besen/src/BESENObjectNativeFunction.pas @@ -0,0 +1,102 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNativeFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectNativeFunction=class(TBESENObjectFunction) + public + Native:TBESENNativeFunction; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectNativeFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='native'; + Native:=nil; +end; + +destructor TBESENObjectNativeFunction.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectNativeFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + if TBESEN(Instance).IsStrict and (P='caller') then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +function TBESENObjectNativeFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetIndex(Index,ID,AResult,Base); + if TBESEN(Instance).IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +procedure TBESENObjectNativeFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if assigned(Native) then begin + Native(ThisArgument,Arguments,CountArguments,AResult); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObjectNativeFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/3rd/besen/src/BESENObjectNumber.pas b/3rd/besen/src/BESENObjectNumber.pas new file mode 100644 index 000000000..3ae3c18f0 --- /dev/null +++ b/3rd/besen/src/BESENObjectNumber.pas @@ -0,0 +1,75 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNumber; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectNumber=class(TBESENObject) + public + Value:TBESENNumber; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectNumber.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Number'; + ObjectName:=''; + + Value:=0; +end; + +destructor TBESENObjectNumber.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectNumber.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectNumber.Mark; +begin + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENObjectNumberConstructor.pas b/3rd/besen/src/BESENObjectNumberConstructor.pas new file mode 100644 index 000000000..4cb87c2f4 --- /dev/null +++ b/3rd/besen/src/BESENObjectNumberConstructor.pas @@ -0,0 +1,130 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNumberConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectNumberConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectNumber,BESENNumberUtils,BESENGlobals,BESENObjectArray; + +constructor TBESENObjectNumberConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var v:TBESENValue; +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Number'; + + v:=BESENEmptyValue; + + v:=BESENNumberValue(0); + move(BESENDoubleMax,v.Num,sizeof(TBESENNumber)); + OverwriteData('MAX_VALUE',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleMin,v.Num,sizeof(TBESENNumber)); + OverwriteData('MIN_VALUE',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleNaN,v.Num,sizeof(TBESENNumber)); + OverwriteData('NaN',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleInfNeg,v.Num,sizeof(TBESENNumber)); + OverwriteData('NEGATIVE_INFINITY',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleInfPos,v.Num,sizeof(TBESENNumber)); + OverwriteData('POSITIVE_INFINITY',v,[]); +end; + +destructor TBESENObjectNumberConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectNumberConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectNumber; +begin + r1:=TBESENObjectNumber.Create(Instance,TBESEN(Instance).ObjectNumberPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments>0 then begin + r1.Value:=TBESEN(Instance).ToNum(Arguments^[0]^); + end else begin + r1.Value:=0.0; + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectNumberConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var v:TBESENValue; +begin + if CountArguments<1 then begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=0; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectArray) then begin + TBESENObjectArray(Arguments^[0]^.Obj).Get('length',v,TBESENObject(Arguments^[0]^.Obj),BESENLengthHash); + TBESEN(Instance).ToNumberValue(v,AResult); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,AResult); + end; +end; + +function TBESENObjectNumberConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectNumberConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/3rd/besen/src/BESENObjectNumberPrototype.pas b/3rd/besen/src/BESENObjectNumberPrototype.pas new file mode 100644 index 000000000..373bbf03c --- /dev/null +++ b/3rd/besen/src/BESENObjectNumberPrototype.pas @@ -0,0 +1,281 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNumberPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectNumber,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectNumberPrototype=class(TBESENObjectNumber) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToExponential(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToPrecision(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENNumberUtils; + +constructor TBESENObjectNumberPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Number'; + ObjectName:='Number'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toFixed',NativeToFixed,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toExponential',NativeToExponential,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toPrecision',NativeToPrecision,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectNumberPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectNumberPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Radix:integer; + nv:TBESENValue; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + if CountArguments=0 then begin + Radix:=10; + end else begin + Radix:=TBESEN(Instance).ToInt32(Arguments^[0]^); + end; + if Radix=10 then begin + TBESEN(Instance).ToStringValue(nv,ResultValue); + end else if Radix in [2..36] then begin + ResultValue.ValueType:=bvtSTRING; + if BESENIsNaN(nv.Num) then begin + ResultValue.Str:='NaN'; + end else if BESENIsZero(nv.Num) then begin + ResultValue.Str:='0'; + end else if BESENIsInfinite(nv.Num) then begin + if BESENIsNegative(nv.Num) then begin + ResultValue.Str:='-Infinity'; + end else begin + ResultValue.Str:='Infinity'; + end; + end else begin + ResultValue.Str:=BESENNumberToRadixString(nv.Num,Radix); + end; + end else begin + raise EBESENRangeError.Create('Bad radix'); + end; +end; + +procedure TBESENObjectNumberPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var nv:TBESENValue; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + ResultValue:=BESENStringValue(BESENFloatToLocaleStr(nv.Num)); +end; + +procedure TBESENObjectNumberPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtNUMBER then begin + ResultValue:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + ResultValue:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; +end; + +procedure TBESENObjectNumberPrototype.NativeToFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +{$ifdef UseDTOA} +var f:int64; + v,nv:TBESENValue; + x:TBESENNumber; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>1076)) then begin + raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end else begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin + raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + ResultValue.ValueType:=bvtSTRING; + if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin + ResultValue.Str:=BESENFloatToStr(x); + end else begin + ResultValue.Str:=dtostr(x,DTOSTR_FIXED,f); + end; +end; +{$else} +var f:int64; + v,nv:TBESENValue; + x:TBESENNumber; + s:TBESENString; + ss:shortstring; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin + raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + ResultValue.ValueType:=bvtSTRING; + if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin + ResultValue.Str:=BESENFloatToStr(x); + end else begin + str(x:1:f,ss); + s:=TBESENString(ss); + ResultValue.Str:=s; + end; +end; +{$endif} + +procedure TBESENObjectNumberPrototype.NativeToExponential(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,nv:TBESENValue; + x:TBESENNumber; + f:integer; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>1076)) then begin + raise EBESENRangeError.CreateUTF16('Exponent width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end else begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin + raise EBESENRangeError.CreateUTF16('Exponent width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + if not BESENIsFinite(x) then begin + ResultValue:=BESENStringValue(BESENFloatToStr(x)); + end else begin + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,f+1))); + end else begin + ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL,0))); + end; + end; +end; + +procedure TBESENObjectNumberPrototype.NativeToPrecision(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var f:int64; + v,nv:TBESENValue; + x:TBESENNumber; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + if BESENIsNaN(v.Num) or ((v.Num<1) or (v.Num>1076)) then begin + raise EBESENRangeError.CreateUTF16('Precision '+BESENFloatToStr(v.Num)+' out of range'); + end; + end else begin + if BESENIsNaN(v.Num) or ((v.Num<1) or (v.Num>21)) then begin + raise EBESENRangeError.CreateUTF16('Precision '+BESENFloatToStr(v.Num)+' out of range'); + end; + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin + ResultValue:=BESENStringValue(BESENFloatToStr(x)); + end else begin + ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_PRECISION,f))); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectPropertyDescriptor.pas b/3rd/besen/src/BESENObjectPropertyDescriptor.pas new file mode 100644 index 000000000..9e1edf697 --- /dev/null +++ b/3rd/besen/src/BESENObjectPropertyDescriptor.pas @@ -0,0 +1,146 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectPropertyDescriptor; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue; + +type TBESENObjectPropertyDescriptorAttribute=(bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE); + + TBESENObjectPropertyDescriptorAttributes=set of TBESENObjectPropertyDescriptorAttribute; + + TBESENObjectPropertyDescriptorPresent=(boppVALUE,boppGETTER,boppSETTER,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE,boppPROTO); + + TBESENObjectPropertyDescriptorPresents=set of TBESENObjectPropertyDescriptorPresent; + + PBESENObjectPropertyDescriptor=^TBESENObjectPropertyDescriptor; + TBESENObjectPropertyDescriptor=record + Value:TBESENValue; + Getter:TObject; + Setter:TObject; + Attributes:TBESENObjectPropertyDescriptorAttributes; + Presents:TBESENObjectPropertyDescriptorPresents; + end; + + TBESENObjectPropertyDescriptors=array of TBESENObjectPropertyDescriptor; + +var BESENUndefinedPropertyDescriptor:TBESENObjectPropertyDescriptor; + +function BESENAccessorPropertyDescriptor(const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +function BESENDataPropertyDescriptor(const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +function BESENPropertyDescriptor(const Value:TBESENValue;const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} + +function BESENIsUndefinedDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsAccessorDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsDataDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsGenericDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsInconsistentDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} + +implementation + +uses BESEN; + +function BESENAccessorPropertyDescriptor(const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +begin + result.Value.ValueType:=bvtUNDEFINED; + result.Getter:=Getter; + result.Setter:=Setter; + result.Attributes:=Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + result.Presents:=[boppENUMERABLE,boppCONFIGURABLE]; + if assigned(result.Getter) then begin + result.Presents:=result.Presents+[boppGETTER]; + end; + if assigned(result.Setter) then begin + result.Presents:=result.Presents+[boppSETTER]; + end; +end; + +function BESENDataPropertyDescriptor(const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +begin + BESENCopyValue(result.Value,Value); + result.Getter:=nil; + result.Setter:=nil; + result.Attributes:=Attributes; + result.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; +end; + +function BESENPropertyDescriptor(const Value:TBESENValue;const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +begin + BESENCopyValue(result.Value,Value); + result.Getter:=Getter; + result.Setter:=Setter; + result.Attributes:=Attributes; + result.Presents:=[boppVALUE,boppGETTER,boppSETTER,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; +end; + +function BESENIsUndefinedDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=Descriptor.Presents=[]; +end; + +function BESENIsAccessorDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]; +end; + +function BESENIsDataDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]; +end; + +function BESENIsGenericDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=not (BESENIsAccessorDescriptor(Descriptor) or BESENIsDataDescriptor(Descriptor)); +end; + +function BESENIsInconsistentDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]); +end; + +procedure InitBESEN; +begin + fillchar(BESENUndefinedPropertyDescriptor,sizeof(TBESENObjectPropertyDescriptor),#0); + BESENUndefinedPropertyDescriptor.Presents:=[]; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. + diff --git a/3rd/besen/src/BESENObjectPrototype.pas b/3rd/besen/src/BESENObjectPrototype.pas new file mode 100644 index 000000000..29ce83c7f --- /dev/null +++ b/3rd/besen/src/BESENObjectPrototype.pas @@ -0,0 +1,223 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectPrototype; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectPrototype=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToSource(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeHasOwnProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePropertyIsEnumerable(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectName:='prototype'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toSource',NativeToSource,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('hasOwnProperty',NativeHasOwnProperty,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isPrototypeOf',NativeIsPrototypeOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('propertyIsEnumerable',NativePropertyIsEnumerable,0,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var o:TBesenObject; +begin + // ES5 errata fix + case ThisArgument.ValueType of + bvtUNDEFINED:begin + ResultValue:=BESENStringValue('[object Undefined]'); + end; + bvtNULL:begin + ResultValue:=BESENStringValue('[object Null]'); + end; + else begin + o:=TBESEN(Instance).ToObj(ThisArgument); + o.GarbageCollectorLock; + try + if assigned(o) then begin + if length(o.ObjectClassName)>0 then begin + ResultValue:=BESENStringValue('[object '+o.ObjectClassName+']'); + end else begin + ResultValue:=BESENStringValue('[object Object]'); + end; + end else begin + BESENThrowTypeError('Null this object'); + end; + finally + o.GarbageCollectorUnlock; + end; + end; + end; +end; + +procedure TBESENObjectPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + o:TBesenObject; +begin + o:=TBESEN(Instance).ToObj(ThisArgument); + if assigned(o) then begin + o.GarbageCollectorLock; + try + o.Get('toString',v); + if (v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),ThisArgument,Arguments,CountArguments,ResultValue); + end else begin + BESENThrowTypeError('Null this object'); + end; + finally + o.GarbageCollectorUnlock; + end; + end else begin + BESENThrowTypeError('Null this object'); + end; +end; + +procedure TBESENObjectPrototype.NativeToSource(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue:=BESENStringValue('/* Unimplemented */'); +end; + +procedure TBESENObjectPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ResultValue); +end; + +procedure TBESENObjectPrototype.NativeHasOwnProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + o:TBesenObject; +begin + o:=TBESEN(Instance).ToObj(ThisArgument); + if not assigned(o) then begin + raise EBESENTypeError.Create('Null this object'); + end; + o.GarbageCollectorLock; + try + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments>0 then begin + ResultValue.Bool:=o.GetOwnProperty(TBESEN(Instance).ToStr(Arguments^[0]^),Descriptor); + end else begin + ResultValue.Bool:=false; + end; + finally + o.GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectPrototype.NativeIsPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,o:TBESENObject; +begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=false; + if (CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) then begin + o:=TBESEN(Instance).ToObj(ThisArgument); + if not assigned(o) then begin + raise EBESENTypeError.Create('Null this object'); + end; + o.GarbageCollectorLock; + try + v:=TBESENObject(Arguments^[0]^.Obj); + while assigned(v) do begin + v:=v.Prototype; + if assigned(v) then begin + if o=v then begin + ResultValue.Bool:=true; + break; + end; + end else begin + ResultValue.Bool:=false; + break; + end; + end; + finally + o.GarbageCollectorUnlock; + end; + end else begin + ResultValue.Bool:=false; + end; +end; + +procedure TBESENObjectPrototype.NativePropertyIsEnumerable(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + o:TBESENObject; + s:TBESENString; +begin + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments>0 then begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + o:=TBESEN(Instance).ToObj(ThisArgument); + if not assigned(o) then begin + raise EBESENTypeError.Create('Null this object'); + end; + o.GarbageCollectorLock; + try + if o.GetOwnProperty(s,Descriptor) then begin + ResultValue.Bool:=(boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in Descriptor.Attributes); + end else begin + ResultValue.Bool:=false; + end; + finally + o.GarbageCollectorUnlock; + end; + end else begin + ResultValue.Bool:=false; + end; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectRegExp.pas b/3rd/besen/src/BESENObjectRegExp.pas new file mode 100644 index 000000000..6c26f1e02 --- /dev/null +++ b/3rd/besen/src/BESENObjectRegExp.pas @@ -0,0 +1,199 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectRegExp; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp; + +type TBESENObjectRegExp=class(TBESENObject) + public + Engine:TBESENRegExp; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + procedure SetStatic(const Input:TBESENString;const Captures:TBESENRegExpCaptures); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectRegExp.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var bv:TBESENValue; +begin + inherited Create(AInstance,APrototype); + ObjectClassName:='RegExp'; + ObjectName:=''; + + Engine:=TBESEN(Instance).DefaultRegExp; + + OverwriteData('source',BESENStringValue(''),[]); + + bv.ValueType:=bvtBOOLEAN; + bv.Bool:=brefGLOBAL in Engine.Flags; + OverwriteData('global',bv,[]); + + bv.Bool:=brefIGNORECASE in Engine.Flags; + OverwriteData('ignoreCase',bv,[]); + + bv.Bool:=brefMULTILINE in Engine.Flags; + OverwriteData('multiline',bv,[]); + + OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); +end; + +destructor TBESENObjectRegExp.Destroy; +begin + if assigned(Engine) then begin + if Engine<>TBESEN(Instance).DefaultRegExp then begin + Engine.DecRef; + end; + Engine:=nil; + end; + inherited Destroy; +end; + +procedure TBESENObjectRegExp.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + TBESEN(Instance).ObjectRegExpPrototype.NativeExec(ThisArgument,Arguments,CountArguments,AResult); + end else begin + raise EBESENTypeError.Create('Not callable'); + end; +end; + +function TBESENObjectRegExp.HasCall:TBESENBoolean; +begin + result:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; +end; + +procedure TBESENObjectRegExp.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectRegExp.Mark; +begin + inherited Mark; +end; + +procedure TBESENObjectRegExp.SetStatic(const Input:TBESENString;const Captures:TBESENRegExpCaptures); +var i:integer; + v:TBESENValue; + pn,lastParen:TBESENString; +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + exit; + end; + v:=BESENEmptyValue; + lastParen:=''; + for i:=0 to 9 do begin + case i of + 0:pn:='$&'; + 1:pn:='$1'; + 2:pn:='$2'; + 3:pn:='$3'; + 4:pn:='$4'; + 5:pn:='$5'; + 6:pn:='$6'; + 7:pn:='$7'; + 8:pn:='$8'; + 9:pn:='$9'; + else pn:='$0'; + end; + if (i<length(Captures)) and (Captures[i].e<>brecUNDEFINED) then begin + v:=BESENStringValue(copy(Input,Captures[i].s+1,Captures[i].e-Captures[i].s)); + end else begin + v:=BESENStringValue(''); + end; + if (i>0) and (i<length(Captures)) then begin + lastParen:=v.Str; + end; + OverwriteData(pn,v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]); + if i=0 then begin + OverwriteData('lastMatch',v,[bopaWRITABLE,bopaCONFIGURABLE]); + end; + end; + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefMULTILINE in Engine.Flags; + OverwriteData('$*',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('multiline',v,[]); + + v:=BESENStringValue(Input); + OverwriteData('$_',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('input',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENStringValue(lastParen); + OverwriteData('$+',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('leftParen',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin + v:=BESENStringValue(copy(Input,1,Captures[0].s)); + end else begin + v:=BESENStringValue(''); + end; + OverwriteData('$`',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('leftContext',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin + v:=BESENStringValue(copy(Input,Captures[0].e,(length(Input)-longint(Captures[0].e))+1)); + end else begin + v:=BESENStringValue(''); + end; + OverwriteData('$''',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('rightContext',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefGLOBAL in Engine.Flags; + OverwriteData('global',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefIGNORECASE in Engine.Flags; + OverwriteData('ignoreCase',v,[]); + + if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin + v:=BESENNumberValue(Captures[0].e); + end else begin + v:=BESENNumberValue(0); + end; + OverwriteData('lastIndex',v,[bopaWRITABLE]); + + OverwriteData('source',BESENStringValue(Engine.Source),[]); +end; + +end. diff --git a/3rd/besen/src/BESENObjectRegExpConstructor.pas b/3rd/besen/src/BESENObjectRegExpConstructor.pas new file mode 100644 index 000000000..0343d4916 --- /dev/null +++ b/3rd/besen/src/BESENObjectRegExpConstructor.pas @@ -0,0 +1,188 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectRegExpConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectRegExpConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; + function HasHasInstance:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectRegExp,BESENRegExp,BESENErrors; + +constructor TBESENObjectRegExpConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='RegExp'; +end; + +destructor TBESENObjectRegExpConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectRegExpConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectRegExp; + s,f:TBESENString; + Flags:TBESENRegExpFlags; + v:TBESENValue; + i:integer; +begin + r1:=TBESENObjectRegExp.Create(Instance,TBESEN(Instance).ObjectRegExpPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if (CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin + r1.Engine:=TBESENObjectRegExp(Arguments^[0]^.Obj).Engine; + end else begin + if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin + s:=''; + end else begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + if CountArguments>1 then begin + f:=TBESEN(Instance).ToStr(Arguments^[1]^); + end else begin + f:=''; + end; + Flags:=[]; + for i:=1 to length(f) do begin + case f[i] of + 'g':begin + if brefGLOBAL in Flags then begin + raise EBESENSyntaxError.Create('Too many global regular expression flags'); + end else begin + Flags:=Flags+[brefGLOBAL]; + end; + end; + 'i':begin + if brefIGNORECASE in Flags then begin + raise EBESENSyntaxError.Create('Too many ignorecase regular expression flags'); + end else begin + Flags:=Flags+[brefIGNORECASE]; + end; + end; + 'm':begin + if brefMULTILINE in Flags then begin + raise EBESENSyntaxError.Create('Too many multiline regular expression flags'); + end else begin + Flags:=Flags+[brefMULTILINE]; + end; + end; + else begin + raise EBESENSyntaxError.Create('Unknown regular expression flag'); + end; + end; + end; + try + r1.Engine:=TBESEN(Instance).RegExpCache.Get(s,Flags); + except + raise EBESENSyntaxError.Create('Invalid regular expression'); + end; + end; + + if assigned(r1.Engine) then begin + r1.Engine.IncRef; + end else begin + raise EBESENError.Create('Fatal error'); + end; + + r1.Engine.DebugDump; + + v.ValueType:=bvtSTRING; + v.Str:=r1.Engine.Source; + r1.OverwriteData('source',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefGLOBAL in r1.Engine.Flags; + r1.OverwriteData('global',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefIGNORECASE in r1.Engine.Flags; + r1.OverwriteData('ignoreCase',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefMULTILINE in r1.Engine.Flags; + r1.OverwriteData('multiline',v,[]); + + v.ValueType:=bvtNUMBER; + v.Num:=0; + r1.OverwriteData('lastIndex',v,[bopaWRITABLE]); + finally + r1.GarbageCollectorUnlock; + end; + AResult:=BESENObjectValue(r1); +end; + +procedure TBESENObjectRegExpConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectRegExpConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectRegExpConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectRegExpConstructor.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + result:=(AInstance.ValueType=bvtOBJECT) and assigned(AInstance.Obj) and (AInstance.Obj is TBESENObjectRegExp); + end else begin + raise EBESENTypeError.Create('Has no instance'); + end; +end; + +function TBESENObjectRegExpConstructor.HasHasInstance:TBESENBoolean; +begin + result:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; +end; + +end. diff --git a/3rd/besen/src/BESENObjectRegExpPrototype.pas b/3rd/besen/src/BESENObjectRegExpPrototype.pas new file mode 100644 index 000000000..d3eba81ff --- /dev/null +++ b/3rd/besen/src/BESENObjectRegExpPrototype.pas @@ -0,0 +1,228 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectRegExpPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectRegExp,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp; + +type TBESENObjectRegExpPrototype=class(TBESENObjectRegExp) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTest(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeExec(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENNumberUtils,BESENArrayUtils,BESENObjectArray; + +constructor TBESENObjectRegExpPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='RegExp'; + ObjectName:='RegExp'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('test',NativeTest,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('exec',NativeExec,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectRegExpPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectRegExpPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i:integer; + c:widechar; +begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)))and (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExpPrototype)) then begin + ResultValue:=BESENStringValue('RegExp.prototype'); + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExp) then begin + s:='/'; + i:=1; + while i<=length(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source) do begin + c:=TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source[i]; + case c of + '/':begin + s:=s+'\/'; + inc(i); + end; + '\':begin + s:=s+'\\'; + inc(i); + if i<=length(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source) then begin + c:=TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source[i]; + s:=s+c; + inc(i); + end; + end; + else begin + s:=s+c; + inc(i); + end; + end; + end; + s:=s+'/'; + if brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + s:=s+'g'; + end; + if brefIGNORECASE in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + s:=s+'i'; + end; + if brefMULTILINE in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + s:=s+'m'; + end; + ResultValue:=BESENStringValue(s); + end else begin + raise EBESENTypeError.Create('Not a RegExp object'); + end; +end; + +procedure TBESENObjectRegExpPrototype.NativeTest(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,vo,vs:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; +begin + Get('exec',v); + TBESEN(Instance).ToObjectValue(v,vo); + if (vo.ValueType<>bvtOBJECT) or not (assigned(TBESENObject(vo.Obj)) and TBESENObject(vo.Obj).HasCall) then begin + raise EBESENTypeError.Create('No callable'); + end; + TBESENObject(vo.Obj).GarbageCollectorLock; + try + if CountArguments<1 then begin + ValuePointers[0]:=@BESENUndefinedValue; + end else begin + ValuePointers[0]:=Arguments^[0]; + end; + TBESEN(Instance).ObjectCall(TBESENObject(vo.Obj),ThisArgument,@ValuePointers,1,vs); + finally + TBESENObject(vo.Obj).GarbageCollectorUnlock; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=TBESEN(Instance).EqualityExpressionCompare(vs,BESENNullValue)<>0; +end; + +procedure TBESENObjectRegExpPrototype.NativeExec(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,vi:TBESENValue; + i:integer; + s:TBESENString; + Captures:TBESENRegExpCaptures; + o:TBESENObjectArray; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExp) then begin + raise EBESENTypeError.Create('Not a RegExp object'); + end; + if CountArguments<1 then begin + raise EBESENRangeError.Create('Bad argument count'); + end; + + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + + i:=0; + + try + TBESENObject(ThisArgument.Obj).Get('lastIndex',v); + TBESEN(Instance).ToNumberValue(v,vi); + if not (brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags) then begin + v:=BESENNumberValue(0); + end; + if (not BESENIsFinite(v.Num)) or (v.Num<0) or (v.Num>length(s)) then begin + TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(0),true); + ResultValue:=BESENNullValue; + exit; + end; + i:=trunc(vi.Num); + except + end; + +{$ifdef UseAssert} + Assert(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.CountOfCaptures>0); +{$endif} + Captures:=nil; + try + SetLength(Captures,TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.CountOfCaptures); + while not TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Match(s,i,Captures) do begin + inc(i); + if i>length(s) then begin + TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(0),true); + ResultValue:=BESENNullValue; + for i:=0 to length(Captures)-1 do begin + Captures[i].e:=brecUNDEFINED; + end; + TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).SetStatic(s,Captures); + SetLength(Captures,0); + exit; + end; + end; + TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).SetStatic(s,Captures); + if brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(Captures[0].e),true); + end; + v:=BESENEmptyValue; + o:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(o); + o.GarbageCollectorLock; + try + for i:=0 to length(Captures)-1 do begin + if Captures[i].e=brecUNDEFINED then begin + v:=BESENUndefinedValue; + end else begin + v:=BESENStringValue(copy(s,Captures[i].s+1,Captures[i].e-Captures[i].s)); + end; + o.DefineOwnProperty(BESENArrayIndexToStr(i),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + end; + o.Len:=length(Captures); + o.DefineOwnProperty('index',BESENDataPropertyDescriptor(BESENNumberValue(Captures[0].s),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + o.DefineOwnProperty('input',BESENDataPropertyDescriptor(BESENStringValue(s),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + finally + o.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(o); + finally + SetLength(Captures,0); + end; +end; + +end. diff --git a/3rd/besen/src/BESENObjectString.pas b/3rd/besen/src/BESENObjectString.pas new file mode 100644 index 000000000..c2a1bd264 --- /dev/null +++ b/3rd/besen/src/BESENObjectString.pas @@ -0,0 +1,133 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectString; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectString=class(TBESENObject) + public + Value:TBESENString; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; + procedure Finalize; override; + procedure Mark; override; + procedure UpdateLength; + end; + +implementation + +uses BESEN,BESENStringUtils,BESENNumberUtils; + +constructor TBESENObjectString.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='String'; + ObjectName:=''; + + Value:=''; + OverwriteData('length',BESENNumberValue(0),[]); +end; + +destructor TBESENObjectString.Destroy; +begin + Value:=''; + inherited Destroy; +end; + +function TBESENObjectString.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + result:=false; + AResult.ValueType:=bvtUNDEFINED; + if GetProperty(P,Descriptor,Hash) then begin + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + if boppVALUE in Descriptor.Presents then begin + BESENCopyValue(AResult,Descriptor.Value); + end; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if assigned(Base) then begin + GetGetter(Base,AResult,Descriptor); + end else begin + GetGetter(self,AResult,Descriptor); + end; + end; + result:=true; + end; +end; + +function TBESENObjectString.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var Index:int64; + v:TBESENValue; +begin + // ES5 errata fix + Descriptor.Value.ValueType:=BESENUndefinedPropertyDescriptor.Value.ValueType; + Descriptor.Getter:=BESENUndefinedPropertyDescriptor.Getter; + Descriptor.Setter:=BESENUndefinedPropertyDescriptor.Setter; + Descriptor.Attributes:=BESENUndefinedPropertyDescriptor.Attributes; + Descriptor.Presents:=BESENUndefinedPropertyDescriptor.Presents; + result:=inherited GetOwnProperty(P,Descriptor,Hash); + if not result then begin + TBESEN(Instance).ToIntegerValue(BESENStringValue(p),v); + if BESENIsFinite(v.Num) then begin + Index:=BESENToInt(v.Num); + if (IntToStr(abs(Index))=P) and ((Index>=0) and (Index<length(Value))) then begin + Descriptor.Value.ValueType:=bvtSTRING; + Descriptor.Value.Str:=copy(Value,Index+1,1); + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=[bopaENUMERABLE]; + Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; + end; + end; + end; +end; + +procedure TBESENObjectString.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectString.Mark; +begin + inherited Mark; +end; + +procedure TBESENObjectString.UpdateLength; +begin + OverwriteData('length',BESENNumberValue(length(Value)),[]); +end; + +end. diff --git a/3rd/besen/src/BESENObjectStringConstructor.pas b/3rd/besen/src/BESENObjectStringConstructor.pas new file mode 100644 index 000000000..64bcf214a --- /dev/null +++ b/3rd/besen/src/BESENObjectStringConstructor.pas @@ -0,0 +1,119 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectStringConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectStringConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeFromCharCode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENObjectString; + +constructor TBESENObjectStringConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='String'; + + OverwriteData('length',BESENNumberValue(1),[]); + + RegisterNativeFunction('fromCharCode',NativeFromCharCode,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectStringConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectStringConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectString; +begin + r1:=TBESENObjectString.Create(Instance,TBESEN(Instance).ObjectStringPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments>0 then begin + r1.Value:=TBESEN(Instance).ToStr(Arguments^[0]^); + end else begin + r1.Value:=''; + end; + r1.UpdateLength; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectStringConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments<1 then begin + AResult:=BESENStringValue(''); + end else begin + TBESEN(Instance).ToStringValue(Arguments^[0]^,AResult); + end; +end; + +function TBESENObjectStringConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectStringConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectStringConstructor.NativeFromCharCode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i:integer; +begin + s:=''; + for i:=0 to CountArguments-1 do begin + s:=s+widechar(word(TBESEN(Instance).ToUInt16(Arguments^[i]^))); + end; + ResultValue:=BESENStringValue(s); +end; + +end. diff --git a/3rd/besen/src/BESENObjectStringPrototype.pas b/3rd/besen/src/BESENObjectStringPrototype.pas new file mode 100644 index 000000000..29f97158b --- /dev/null +++ b/3rd/besen/src/BESENObjectStringPrototype.pas @@ -0,0 +1,1108 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectStringPrototype; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectString,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectStringPrototype=class(TBESENObjectString) + private + function RegExpArg(Arguments:PPBESENValues;CountArguments:integer):TBESENObject; + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCharAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCharCodeAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLocaleCompare(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMatch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReplace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSearch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSplit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSubstring(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTrim(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSubstr(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeAnchor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBig(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBlink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBold(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFontColor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFontSize(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeItalics(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSmall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeStrike(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSub(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSup(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENObjectRegExp,BESENNumberUtils,BESENRegExp,BESENStringUtils, + BESENObjectArray; + +constructor TBESENObjectStringPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='String'; + ObjectName:='Number'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + OverwriteData('length',BESENNumberValue(0),[]); + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + + RegisterNativeFunction('charAt',NativeCharAt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('charCodeAt',NativeCharCodeAt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('concat',NativeConcat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('indexOf',NativeIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('lastIndexOf',NativeLastIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('localeCompare',NativeLocaleCompare,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('match',NativeMatch,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('replace',NativeReplace,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('search',NativeSearch,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('slice',NativeSlice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('split',NativeSplit,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('substring',NativeSubString,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLowerCase',NativeToLowerCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleLowerCase',NativeToLocaleLowerCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toUpperCase',NativeToUpperCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleUpperCase',NativeToLocaleUpperCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('trim',NativeTrim,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + + RegisterNativeFunction('substr',NativeSubStr,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + RegisterNativeFunction('anchor',NativeAnchor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('big',NativeBig,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('blink',NativeBlink,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('bold',NativeBold,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('fixed',NativeFixed,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('fontcolor',NativeFontColor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('fontsize',NativeFontSize,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('italics',NativeItalics,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('link',NativeLink,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('small',NativeSmall,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('strike',NativeStrike,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sub',NativeSub,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sup',NativeSup,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + end; +end; + +destructor TBESENObjectStringPrototype.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectStringPrototype.RegExpArg(Arguments:PPBESENValues;CountArguments:integer):TBESENObject; +var v:TBESENValue; +begin + v:=BESENEmptyValue; + if CountArguments<0 then begin + TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),nil,0,v); + if v.ValueType=bvtOBJECT then begin + result:=TBESENObject(v.Obj); + end else begin + result:=nil; + end; + end else if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin + result:=TBESENObject(Arguments^[0]^.Obj); + end else begin + TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),Arguments,1,v); + if v.ValueType=bvtOBJECT then begin + result:=TBESENObject(v.Obj); + end else begin + result:=nil; + end; + end; +{$ifdef UseAssert} + Assert(assigned(result)); +{$endif} +end; + +procedure TBESENObjectStringPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtSTRING then begin + BESENCopyValue(ResultValue,ThisArgument); + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectString) then begin + ResultValue:=BESENStringValue(TBESENObjectString(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a string object'); + end; +end; + +procedure TBESENObjectStringPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtSTRING then begin + BESENCopyValue(ResultValue,ThisArgument); + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectString) then begin + ResultValue:=BESENStringValue(TBESENObjectString(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a string object'); + end; +end; + +procedure TBESENObjectStringPrototype.NativeCharAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + i:integer; + s:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + v:=BESENEmptyValue; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + i:=-1; + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsFinite(v.Num) then begin + i:=trunc(v.Num); + end; + end else begin + i:=0; + end; + if (i>=0) and (i<length(s)) then begin + ResultValue:=BESENStringValue(copy(s,i+1,1)); + end else begin + ResultValue:=BESENStringValue(''); + end; +end; + +procedure TBESENObjectStringPrototype.NativeCharCodeAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + i:integer; + s:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + i:=-1; + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsFinite(v.Num) then begin + i:=trunc(v.Num); + end; + end else begin + i:=0; + end; + if (i>=0) and (i<length(s)) then begin + ResultValue:=BESENNumberValue(word(widechar(s[i+1]))); + end else begin + ResultValue:=BESENNumberValue(0); + move(BESENDoubleNaN,ResultValue.Num,sizeof(TBESENNumber)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + for i:=0 to CountArguments-1 do begin + s:=s+TBESEN(Instance).ToStr(Arguments^[i]^); + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectStringPrototype.NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + i,j,k,l,ls,p,fp,fl:integer; + s,ss:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if CountArguments<1 then begin + ss:=''; + end else begin + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + p:=0; + if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + p:=trunc(v.Num); + end; + if p<0 then begin + p:=0; + end else if p>=length(s) then begin + p:=length(s)-1; + end; + inc(p); + ls:=length(ss); + l:=(length(s)-ls)+1; + fp:=0; + for i:=p to l do begin + fl:=0; + for j:=1 to ls do begin + k:=i+j-1; + if ((k<1) or (k>length(s))) or (s[k]<>ss[j]) then begin + break; + end else begin + inc(fl); + end; + end; + if fl=ls then begin + fp:=i; + break; + end; + end; + ResultValue:=BESENNumberValue(fp-1); +end; + +procedure TBESENObjectStringPrototype.NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,vi:TBESENValue; + i,j,k,l,ls,p,fp,fl:integer; + s,ss:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if CountArguments<1 then begin + ss:=''; + end else begin + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + vi:=BESENEmptyValue; + if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + end else begin + v:=BESENNumberValue(0); + move(BESENDoubleNaN,v.Num,sizeof(TBESENNumber)); + end; + if BESENIsNaN(v.Num) then begin + vi:=BESENNumberValue(0); + move(BESENDoubleInfPos,vi.Num,sizeof(TBESENNumber)); + end else begin + TBESEN(Instance).ToIntegerValue(v,vi); + end; + l:=trunc(min(max(vi.Num,0),length(s))); + ls:=length(ss); + if l<ls then begin + ResultValue:=BESENNumberValue(-1); + exit; + end; + p:=length(s)-ls; + if p<l then begin + l:=p; + end; + fp:=-1; + for i:=l downto 0 do begin + fl:=0; + for j:=1 to ls do begin + k:=i+j; + if ((k<1) or (k>length(s))) or (s[k]<>ss[j]) then begin + break; + end else begin + inc(fl); + end; + end; + if fl=ls then begin + fp:=i; + break; + end; + end; + ResultValue:=BESENNumberValue(fp); +end; + +procedure TBESENObjectStringPrototype.NativeLocaleCompare(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s,ss:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if CountArguments<1 then begin + ss:='undefined'; + end else begin + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + if s<ss then begin + ResultValue:=BESENNumberValue(-1); + end else if s>ss then begin + ResultValue:=BESENNumberValue(1); + end else begin + ResultValue:=BESENNumberValue(0); + end; +end; + +procedure TBESENObjectStringPrototype.NativeMatch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var RegExp:TBESENObjectRegExp; + v,vr,vs:TBESENValue; + Exec:TBESENObject; + Global:boolean; + s:TBESENString; + a:TBESENObjectArray; + n,Matches:integer; + ValuePointers:array[0..0] of PBESENValue; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + v:=BESENEmptyValue; + + RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); + RegExp.Get('exec',v); +{$ifdef UseAssert} + Assert((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall); +{$endif} + Exec:=TBESENObject(v.Obj); + + RegExp.Get('global',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtBOOLEAN); +{$endif} + Global:=v.Bool; + if Global then begin + v:=BESENEmptyValue; + vr:=BESENEmptyValue; + + Matches:=0; + + RegExp.OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); + + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + n:=0; + while true do begin + vs.ValueType:=bvtSTRING; + vs.Str:=s; + ValuePointers[0]:=@vs; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,vr); + if vr.ValueType=bvtNULL then begin + break; + end; + + {$ifdef UseAssert} + Assert((vr.ValueType=bvtOBJECT) and assigned(vr.Obj) and (vr.Obj is TBESENObjectArray)); + {$endif} + TBESENObject(vr.Obj).Get('0',v); + {$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); + {$endif} + + a.OverwriteData(inttostr(n),v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]); + inc(Matches); + + if length(v.Str)=0 then begin + RegExp.Get('lastIndex',v); + {$ifdef UseAssert} + Assert(v.ValueType=bvtNUMBER); + {$endif} + v.Num:=v.Num+1; + RegExp.OverwriteData('lastIndex',v,[bopaWRITABLE]); + end; + inc(n); + end; + finally + a.GarbageCollectorUnlock; + end; + if Matches=0 then begin + ResultValue:=BESENNullValue; + end else begin + ResultValue:=BESENObjectValue(a); + end; + end else begin + vs.ValueType:=bvtSTRING; + vs.Str:=s; + ValuePointers[0]:=@vs; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,ResultValue); + end; +end; + +procedure TBESENObjectStringPrototype.NativeReplace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure Helper(var PrevIndexP:longword;a:TBESENObject;var OutStr:TBESENString;const Source:TBESENString;var ReplaceValue:TBESENValue;CountCaptures:integer); + var v,vr:TBESENValue; + n:integer; + Index,i,j,k:longword; + ms,Replace:TBESENString; + Values:TBESENValues; + pValues:TBESENValuePointers; + begin + v:=BESENEmptyValue; + + a.Get('index',v); + Index:=TBESEN(Instance).ToUInt32(v); + + a.Get('0',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); +{$endif} + ms:=TBESEN(Instance).ToStr(v); + + i:=PrevIndexP; + if i<Index then begin + OutStr:=OutStr+copy(Source,i+1,Index-i); + end; + PrevIndexP:=Index+longword(length(ms)); + + if ReplaceValue.ValueType=bvtOBJECT then begin + Values:=nil; + pValues:=nil; + try + SetLength(Values,CountCaptures+2); + SetLength(pValues,CountCaptures+2); + for n:=0 to length(Values)-1 do begin + Values[n]:=BESENEmptyValue; + end; + for n:=0 to CountCaptures-1 do begin + a.Get(inttostr(n),Values[n]); + end; + Values[CountCaptures]:=BESENNumberValue(Index); + Values[CountCaptures+1]:=BESENStringValue(Source); + for n:=0 to length(Values)-1 do begin + pValues[n]:=@Values[n]; + end; + TBESEN(Instance).ObjectCall(TBESENObject(ReplaceValue.Obj),BESENObjectValueEx(TBESENObject(ReplaceValue.Obj)),@pValues[0],length(pValues),vr); + OutStr:=OutStr+TBESEN(Instance).ToStr(vr); + finally + SetLength(Values,0); + SetLength(pValues,0); + end; + exit; + end; + + Replace:=TBESEN(Instance).ToStr(ReplaceValue); + + i:=0; + while i<longword(length(Replace)) do begin + if (Replace[i+1]='$') and ((i+1)<longword(length(Replace))) then begin + inc(i); + case Replace[i+1] of + '$':begin + OutStr:=OutStr+'$'; + inc(i); + continue; + end; + '`':begin + k:=0; + while k<Index do begin + OutStr:=OutStr+Source[k+1]; + inc(k); + end; + inc(i); + continue; + end; + '''':begin + k:=PrevIndexP; + while k<longword(length(Source)) do begin + OutStr:=OutStr+Source[k+1]; + inc(k); + end; + inc(i); + continue; + end; + '&':begin + OutStr:=OutStr+ms; + inc(i); + continue; + end; + end; + j:=i; + n:=0; + while (j<longword(length(Replace))) and ((word(widechar(Replace[j+1]))>=ord('0')) and (word(widechar(Replace[j+1]))<=ord('9'))) do begin + n:=(n*10)+(word(widechar(Replace[j+1]))-ord('0')); + inc(j); + end; + if i=j then begin + OutStr:=OutStr+'$'; + continue; + end; + a.Get(inttostr(n),v); + if v.ValueType<>bvtUNDEFINED then begin +{$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); +{$endif} + OutStr:=OutStr+v.Str; + end; + i:=j; + end else begin + OutStr:=OutStr+Replace[i+1]; + inc(i); + end; + end; + end; +var RegExp:TBESENObjectRegExp; + CountCaptures:integer; + ReplaceValue,v,v2,vr,vs:TBESENValue; + Exec:TBESENObject; + Global:boolean; + s,OutStr:TBESENString; + PrevIndex:longword; + ValuePointers:array[0..0] of PBESENValue; + HasOutputString:boolean; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); + CountCaptures:=RegExp.Engine.CountOfCaptures; + ReplaceValue:=BESENEmptyValue; + v:=BESENEmptyValue; + v2:=BESENEmptyValue; + vr:=BESENEmptyValue; + OutStr:=''; + + PrevIndex:=0; + + if CountArguments<2 then begin + ReplaceValue.ValueType:=bvtSTRING; + ReplaceValue.Str:=''; + end else if (Arguments^[1]^.ValueType=bvtOBJECT) and assigned(Arguments^[1]^.Obj) and TBESENObject(Arguments^[1]^.Obj).HasCall then begin + BESENCopyValue(ReplaceValue,Arguments^[1]^); + end else begin + TBESEN(Instance).ToStringValue(Arguments^[1]^,ReplaceValue); + end; + + RegExp.Get('exec',v); +{$ifdef UseAssert} + Assert((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall); +{$endif} + Exec:=TBESENObject(v.Obj); + + RegExp.Get('global',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtBOOLEAN); +{$endif} + Global:=v.Bool; + + HasOutputString:=false; + + if Global then begin + RegExp.OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); + while true do begin + vs.ValueType:=bvtSTRING; + vs.Str:=s; + ValuePointers[0]:=@vs; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,vr); + if vr.ValueType=bvtNULL then begin + break; + end; +{$ifdef UseAssert} + Assert((vr.ValueType=bvtOBJECT) and assigned(TBESENObject(vr.Obj)) and (TBESENObject(vr.Obj) is TBESENObjectArray)); +{$endif} + TBESENObject(vr.Obj).Get('0',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); +{$endif} + if length(v.Str)<>0 then begin + Helper(PrevIndex,TBESENObject(vr.Obj),OutStr,s,ReplaceValue,CountCaptures); + HasOutputString:=true; + end else begin + RegExp.Get('lastIndex',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtNUMBER); +{$endif} + v.Num:=v.Num+1; + RegExp.OverwriteData('lastIndex',v,[bopaWRITABLE]); + end; + end; + end else begin + v.ValueType:=bvtSTRING; + v.Str:=s; + ValuePointers[0]:=@v; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,v2); + if v2.ValueType<>bvtNULL then begin +{$ifdef UseAssert} + Assert((v2.ValueType=bvtOBJECT) and assigned(v2.Obj) and (v2.Obj is TBESENObjectArray)); +{$endif} + Helper(PrevIndex,TBESENObject(v2.Obj),OutStr,s,ReplaceValue,CountCaptures); + HasOutputString:=true; + end; + end; + + if HasOutputString then begin + ResultValue:=BESENStringValue(OutStr+copy(s,PrevIndex+1,(longword(length(s))-PrevIndex)+1)); + end else begin + ResultValue:=BESENStringValue(s); + end; +end; + +procedure TBESENObjectStringPrototype.NativeSearch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var RegExp:TBESENObjectRegExp; + s:TBESENSTRING; + i:integer; + Captures:TBESENRegExpCaptures; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); + Captures:=nil; + try + ResultValue:=BESENNumberValue(-1); + for i:=0 to length(s)-1 do begin + if RegExp.Engine.Match(s,i,Captures) then begin + ResultValue:=BESENNumberValue(Captures[0].s); + break; + end; + end; + finally + SetLength(Captures,0); + end; +end; + +procedure TBESENObjectStringPrototype.NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + len,intStart,intEnd,sFrom,sTo,span:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + + s:=TBESEN(Instance).ToStr(ThisArgument); + + len:=length(s); + + if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin + intStart:=0; + end else begin + intStart:=TBESEN(Instance).ToInt(Arguments^[0]^); + end; + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + intEnd:=len; + end else begin + intEnd:=TBESEN(Instance).ToInt(Arguments^[1]^); + end; + + if intStart<0 then begin + sFrom:=max(len+intStart,0); + end else begin + sFrom:=min(intStart,len); + end; + + if intEnd<0 then begin + sTo:=max(len+intEnd,0); + end else begin + STo:=min(intEnd,len); + end; + + span:=max(sTo-sFrom,0); + + if span=0 then begin + ResultValue:=BESENStringValue(''); + end else begin + ResultValue:=BESENStringValue(copy(s,sFrom+1,span)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeSplit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + function SplitMatch(var r:TBESENValue;var s:TBESENString;q:integer;var Captures:TBESENRegExpCaptures):boolean; + var rl,sl,i:integer; + begin + if r.ValueType<>bvtOBJECT then begin + rl:=length(r.Str); + sl:=length(s); + if (q+rl)>sl then begin + result:=false; + end else begin + for i:=0 to rl-1 do begin + if s[q+i+1]<>r.Str[i+1] then begin + result:=false; + exit; + end; + end; + Captures[0].s:=q; + Captures[0].e:=q+rl; + result:=true; + end; + end else begin + result:=TBESENObjectRegExp(R.Obj).Engine.Match(s,q,Captures); + end; + end; +var v,av,r:TBESENValue; + s,rs:TBESENString; + a:TBESENObjectArray; + lim:TBESENUINT32; + p,sl,CountCaptures,e,q,i:integer; + Captures:TBESENRegExpCaptures; + n,Done:boolean; + ValuePointers:array[0..0] of PBESENValue; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + v:=BESENEmptyValue; + + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + ResultValue:=BESENObjectValue(a); + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + lim:=$ffffffff; + end else begin + lim:=TBESEN(Instance).ToUInt32(Arguments^[1]^); + end; + + Done:=false; + sl:=length(s); + if (sl=0) and ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) then begin + Done:=true; + end; + + if not Done then begin + v:=BESENEmptyValue; + av:=BESENEmptyValue; + r:=BESENEmptyValue; + Captures:=nil; + try + p:=0; + if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin + r:=BESENStringValue('undefined'); + CountCaptures:=1; + end else if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin + BESENCopyValue(r,Arguments^[0]^); + CountCaptures:=TBESENObjectRegExp(Arguments^[0]^.Obj).Engine.CountOfCaptures; + end else begin + rs:=TBESEN(Instance).ToStr(Arguments^[0]^); + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (rs=' ') then begin + av:=BESENStringValue('\s+'); + ValuePointers[0]:=@av; + TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),@ValuePointers,1,r); + while (p<sl) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[p+1]))) do begin + inc(p); + end; + end else begin + r:=BESENStringValue(rs); + end; + CountCaptures:=1; + end; + if CountCaptures<>0 then begin + SetLength(Captures,CountCaptures); + end; + if lim>0 then begin + if (CountArguments<1) or ((Arguments^[0]^.ValueType=bvtUNDEFINED) and ((TBESEN(Instance).Compatibility and COMPAT_JS)=0)) then begin + v:=BESENStringValue(s); + a.Push(v); + end else if length(s)=0 then begin + if not SplitMatch(r,s,0,Captures) then begin + v:=BESENStringValue(s); + a.Push(v); + end; + end else begin + q:=p; + while true do begin + if q=sl then begin + v:=BESENStringValue(copy(s,p+1,sl-p)); + a.Push(v); + break; + end else begin + if not SplitMatch(r,s,q,Captures) then begin + inc(q); + continue; + end else begin + e:=Captures[0].e; + if e=p then begin + inc(q); + continue; + end else begin + v:=BESENStringValue(copy(s,p+1,q-p)); + a.Push(v); + if A.Len=lim then begin + break; + end else begin + p:=e; + i:=0; + n:=false; + while true do begin + if i=(CountCaptures-1) then begin + q:=p; + n:=false; + break; + end else begin + inc(i); + if Captures[i].e=brecUNDEFINED then begin + v:=BESENUndefinedValue; + end else begin + v:=BESENStringValue(copy(s,Captures[i].s+1,Captures[i].e-Captures[i].s)); + end; + a.Push(v); + if A.Len=lim then begin + n:=true; + break; + end; + end; + end; + if n then begin + break; + end else begin + continue; + end; + end; + end; + end; + end; + end; + end; + end; + finally + SetLength(Captures,0); + end; + end; + finally + a.GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectStringPrototype.NativeSubstring(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + s:TBESENString; + a,b,ss,se,sl:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + if CountArguments<1 then begin + a:=0; + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsNaN(v.Num) then begin + a:=0; + end else begin + a:=trunc(min(max(v.Num,0),length(s))); + end; + end; + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + b:=length(s); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + if BESENIsNaN(v.Num) then begin + b:=0; + end else begin + b:=trunc(min(max(v.Num,0),length(s))); + end; + end; + + ss:=min(a,b); + se:=max(a,b); + sl:=max(se-ss,0); + + if sl=0 then begin + ResultValue:=BESENStringValue(''); + end else begin + ResultValue:=BESENStringValue(copy(s,ss+1,sl)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeToLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENLowercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeToLocaleLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENLowercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeToUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENUppercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeToLocaleUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENUppercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeTrim(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + StartPosition,LengthCount:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + LengthCount:=length(s); + if LengthCount>0 then begin + while (LengthCount>0) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[LengthCount]))) do begin + dec(LengthCount); + end; + StartPosition:=1; + while (StartPosition<=LengthCount) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[StartPosition]))) do begin + inc(StartPosition); + end; + s:=copy(s,StartPosition,LengthCount-StartPosition+1); + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectStringPrototype.NativeSubstr(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + s:TBESENString; + ss,sl:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + if CountArguments<1 then begin + v:=BESENNumberValue(0); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + end; + if BESENIsNegative(v.Num) then begin + ss:=trunc(max(v.Num+length(s),0)); + end else begin + ss:=trunc(min(v.Num,length(s))); + end; + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + sl:=length(s)-ss; + end else begin + sl:=min(TBESEN(Instance).ToInt(Arguments^[1]^),length(s)-ss); + end; + + if sl=0 then begin + ResultValue:=BESENStringValue(''); + end else begin + ResultValue:=BESENStringValue(copy(s,ss+1,sl)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeAnchor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeBig(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeBlink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeBold(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeFontColor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeFontSize(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeItalics(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeLink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeSmall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeStrike(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeSub(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeSup(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +end. diff --git a/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas b/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas new file mode 100644 index 000000000..cad4125fb --- /dev/null +++ b/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas @@ -0,0 +1,74 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectThrowTypeErrorFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectThrowTypeErrorFunction=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectThrowTypeErrorFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='ThrowTypeError'; +end; + +destructor TBESENObjectThrowTypeErrorFunction.Destroy; +begin + inherited Destroy; +end; + +{$warnings off} +procedure TBESENObjectThrowTypeErrorFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + raise EBESENTypeError.Create('ThrowTypeError'); +end; +{$warnings on} + +function TBESENObjectThrowTypeErrorFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/3rd/besen/src/BESENOpcodes.pas b/3rd/besen/src/BESENOpcodes.pas new file mode 100644 index 000000000..2de31364c --- /dev/null +++ b/3rd/besen/src/BESENOpcodes.pas @@ -0,0 +1,365 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENOpcodes; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +const bopSTOP=0; + bopNEW=1; + bopCALL=2; + bopEND=3; + bopVREF=4; + bopLREF=5; + bopNOP=6; + bopCOPY=7; + bopNEQ=8; + bopNSEQ=9; + bopAREF=10; + bopTHROW=11; + bopSETC=12; + bopGETC=13; + bopTHIS=14; + bopOBJECT=15; + bopARRAY=16; + bopREGEXP=17; + bopREF=18; + bopGETVALUE=19; + bopLOOKUP=20; + bopPUTVALUE=21; + bopDELETE=22; + bopTYPEOF=23; + bopTOOBJECT=24; + bopTONUMBER=25; + bopTOBOOLEAN=26; + bopTOSTRING=27; + bopTOPRIMITIVE=28; + bopNEG=29; + bopINV=30; + bopNOT=31; + bopMUL=32; + bopDIV=33; + bopMOD=34; + bopADD=35; + bopADDNUM=36; + bopSUB=37; + bopSHL=38; + bopSHR=39; + bopUSHR=40; + bopLT=41; + bopGT=42; + bopLE=43; + bopGE=44; + bopINSTANCEOF=45; + bopIN=46; + bopEQ=47; + bopSEQ=48; + bopBAND=49; + bopBXOR=50; + bopBOR=51; + bopSENUM=52; + bopSWITH=53; + bopSCATCH=54; + bopENDF=55; + bopJMP=56; + bopJZ=57; + bopJNZ=58; + bopJNULL=59; + bopLOOPENUM=60; + bopSTRYC=61; + bopSTRYF=62; + bopLITERAL=63; + bopLITERALUNDEF=64; + bopLITERALNULL=65; + bopLITERALBOOL=66; + bopLITERALNUM=67; + bopLITERALSTR=68; + bopLITERALOBJ=69; + bopFUNC=70; + bopLINE=71; + bopGC=72; + bopSTRICT=73; + bopSTRICTCHECKREF=74; + bopDEBUGGER=75; + bopCHECKOBJECTCOERCIBLE=76; + bopPUTOBJVALUE=77; + bopPUTOBJGET=78; + bopPUTOBJSET=79; + bopINC=80; + bopDEC=81; + bopCOPYBOOL=82; + bopCOPYNUM=83; + bopCOPYSTR=84; + bopCOPYOBJ=85; + bopCOPYREF=86; + bopCOPYLOCAL=87; + bopGETVALUEREF=88; + bopPUTVALUEREF=89; + bopGETVALUELOCAL=90; + bopPUTVALUELOCAL=91; + bopGETVALUELOCALFAST=92; + bopPUTVALUELOCALFAST=93; + bopGETVALUELOCALBOOL=94; + bopPUTVALUELOCALBOOL=95; + bopGETVALUELOCALNUM=96; + bopPUTVALUELOCALNUM=97; + bopGETVALUELOCALSTR=98; + bopPUTVALUELOCALSTR=99; + bopGETVALUELOCALOBJ=100; + bopPUTVALUELOCALOBJ=101; + bopGETVALUELOCALINDEX=102; + bopPUTVALUELOCALINDEX=103; + bopGETVALUELOCALINDEXBOOL=104; + bopPUTVALUELOCALINDEXBOOL=105; + bopGETVALUELOCALINDEXNUM=106; + bopPUTVALUELOCALINDEXNUM=107; + bopGETVALUELOCALINDEXSTR=108; + bopPUTVALUELOCALINDEXSTR=109; + bopGETVALUELOCALINDEXOBJ=110; + bopPUTVALUELOCALINDEXOBJ=111; + bopLOOPINITCOUNT=112; + bopLOOPADDCOUNT=113; + bopTRACE=114; + bopLTBOOL=115; + bopGTBOOL=116; + bopLEBOOL=117; + bopGEBOOL=118; + bopEQBOOL=119; + bopNEQBOOL=120; + bopLTNUM=121; + bopGTNUM=122; + bopLENUM=123; + bopGENUM=124; + bopEQNUM=125; + bopNEQNUM=126; + bopLTSTR=127; + bopGTSTR=128; + bopLESTR=129; + bopGESTR=130; + bopEQSTR=131; + bopNEQSTR=132; + bopSHLBOOl=133; + bopSHRBOOL=134; + bopBANDBOOL=135; + bopBXORBOOL=136; + bopBORBOOL=137; + bopSHLNUM=138; + bopSHRNUM=139; + bopUSHRNUM=140; + bopBANDNUM=141; + bopBXORNUM=142; + bopBORNUM=143; + bopSETCUNDEF=144; + bopSETCNULL=145; + bopSETCBOOL=146; + bopSETCNUM=147; + bopSETCSTR=148; + bopSETCOBJ=149; + bopTRACENEW=150; + bopTRACECALL=151; + bopLTNUMCONST=152; + bopGTNUMCONST=153; + bopLENUMCONST=154; + bopGENUMCONST=155; + bopEQNUMCONST=156; + bopNEQNUMCONST=157; + bopJZERO=158; + bopJNZERO=159; + + bopFIRST=0; + bopLAST=159; + + OpcodeNames:array[bopFIRST..bopLAST] of TBESENString=('STOP', + 'NEW', + 'CALL', + 'END', + 'VREF', + 'LREF', + 'NOP', + 'COPY', + 'NEQ', + 'NSEQ', + 'AREF', + 'THROW', + 'SETC', + 'GETC', + 'THIS', + 'OBJECT', + 'ARRAY', + 'REGEXP', + 'REF', + 'GETVALUE', + 'LOOKUP', + 'PUTVALUE', + 'DELETE', + 'TYPEOF', + 'TOOBJECT', + 'TONUMBER', + 'TOBOOLEAN', + 'TOSTRING', + 'TOPRIMITIVE', + 'NEG', + 'INV', + 'NOT', + 'MUL', + 'DIV', + 'MOD', + 'ADD', + 'ADDNUM', + 'SUB', + 'SHL', + 'SHR', + 'USHR', + 'LT', + 'GT', + 'LE', + 'GE', + 'INSTANCEOF', + 'IN', + 'EQ', + 'SEQ', + 'BAND', + 'BXOR', + 'BOR', + 'SENUM', + 'SWITH', + 'SCATCH', + 'ENDF', + 'JMP', + 'JZ', + 'JNZ', + 'JNULL', + 'LOOPENUM', + 'STRYC', + 'STRYF', + 'LITERAL', + 'LITERALUNDEF', + 'LITERALNULL', + 'LITERALBOOL', + 'LITERALNUM', + 'LITERALSTR', + 'LITERALOBJ', + 'FUNC', + 'LINE', + 'GC', + 'STRICT', + 'STRICTCHECKREF', + 'DEBUGGER', + 'CHECKOBJECTCOERCIBLE', + 'PUTOBJVALUE', + 'PUTOBJGET', + 'PUTOBJSET', + 'INC', + 'DEC', + 'COPYBOOL', + 'COPYNUM', + 'COPYSTR', + 'COPYOBJ', + 'COPYREF', + 'COPYLOCAL', + 'GETVALUEREF', + 'PUTVALUEREF', + 'GETVALUELOCAL', + 'PUTVALUELOCAL', + 'GETVALUELOCALFAST', + 'PUTVALUELOCALFAST', + 'GETVALUELOCALBOOL', + 'PUTVALUELOCALBOOL', + 'GETVALUELOCALNUM', + 'PUTVALUELOCALNUM', + 'GETVALUELOCALSTR', + 'PUTVALUELOCALSTR', + 'GETVALUELOCALOBJ', + 'PUTVALUELOCALOBJ', + 'GETVALUELOCALINDEX', + 'PUTVALUELOCALINDEX', + 'GETVALUELOCALINDEXBOOL', + 'PUTVALUELOCALINDEXBOOL', + 'GETVALUELOCALINDEXNUM', + 'PUTVALUELOCALINDEXNUM', + 'GETVALUELOCALINDEXSTR', + 'PUTVALUELOCALINDEXSTR', + 'GETVALUELOCALINDEXOBJ', + 'PUTVALUELOCALINDEXOBJ', + 'LOOPINITCOUNT', + 'LOOPADDCOUNT', + 'TRACE', + 'LTBOOL', + 'GTBOOL', + 'LEBOOL', + 'GEBOOL', + 'EQBOOL', + 'NEQBOOL', + 'LTNUM', + 'GTNUM', + 'LENUM', + 'GENUM', + 'EQNUM', + 'NEQNUM', + 'LTSTR', + 'GTSTR', + 'LESTR', + 'GESTR', + 'EQSTR', + 'NEQSTR', + 'SHLBOOl', + 'SHRBOOL', + 'BANDBOOL', + 'BXORBOOL', + 'BORBOOL', + 'SHLNUM', + 'SHRNUM', + 'USHRNUM', + 'BANDNUM', + 'BXORNUM', + 'BORNUM', + 'SETCUNDEF', + 'SETCNULL', + 'SETCBOOL', + 'SETCNUM', + 'SETCSTR', + 'SETCOBJ', + 'TRACENEW', + 'TRACECALL', + 'LTNUMCONST', + 'GTNUMCONST', + 'LENUMCONST', + 'GENUMCONST', + 'EQNUMCONST', + 'NEQNUMCONST', + 'JZERO', + 'JNZERO'); + +implementation + +end. diff --git a/3rd/besen/src/BESENParser.pas b/3rd/besen/src/BESENParser.pas new file mode 100644 index 000000000..1cb64b9c5 --- /dev/null +++ b/3rd/besen/src/BESENParser.pas @@ -0,0 +1,2698 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENParser; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENLexicalEnvironment,BESENASTNodes, + BESENEnvironmentRecord,BESENStringTree, + BESENPointerList, + BESENLexer; + +type TBESENParserLabelSet=class(TBESENCollectorObject) + public + Next:TBESENParserLabelSet; + Target:TBESENTarget; + Continuable:longbool; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENParserLabel=class(TBESENCollectorObject) + public + Next:TBESENParserLabel; + Name:TBESENString; + LabelSet:TBESENParserLabelSet; + Node:TBESENASTNode; + LineNumber:integer; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENParser=class(TBESENBaseObject) + public + Lexer:TBESENLexer; + WarningProc:TBESENWarningProc; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Init; + function Parse(IsFunction,IsJSON:boolean):TBESENASTNode; + end; + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESEN,BESENUtils,BESENStringUtils,BESENErrors; + +constructor TBESENParserLabelSet.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Next:=nil; + Target:=-1; + Continuable:=false; + Index:=-1; +end; + +destructor TBESENParserLabelSet.Destroy; +begin + Next:=nil; + inherited Destroy; +end; + +constructor TBESENParserLabel.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Next:=nil; + Name:=''; + LabelSet:=nil; + Node:=nil; + LineNumber:=0; + Index:=-1; +end; + +destructor TBESENParserLabel.Destroy; +begin + Next:=nil; + Node:=nil; + LabelSet:=nil; + Name:=''; + inherited Destroy; +end; + +constructor TBESENParser.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Lexer:=TBESENLexer.Create(Instance); + ErrorProc:=nil; + WarningProc:=nil; +end; + +destructor TBESENParser.Destroy; +begin + Lexer.Free; + inherited Destroy; +end; + +procedure TBESENParser.Init; +begin + Lexer.NextChar; +end; + +function TBESENParser.Parse(IsFunction,IsJSON:boolean):TBESENASTNode; +var CurrentToken:TBESENLexerToken; + InForHeader:boolean; + Labels:TBESENParserLabel; + LabelSets,CurrentLabelSet:TBESENParserLabelSet; + LabelSetList,LabelList:TBESENPointerList; + IsInFunction,UseStrictAlreadyParsed:boolean; + procedure AddError(const Msg:TBESENSTRING); + begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16(Msg); + end; + procedure AddWarning(const Msg:TBESENSTRING); + begin + if assigned(WarningProc) then begin + WarningProc(Lexer.LineNumber,Msg); + end; + end; + procedure NextToken; + begin + Lexer.GetToken(CurrentToken); + end; + procedure SkipToken(TokenType:TBESENLexerTokenType); + begin + if CurrentToken.TokenType<>TokenType then begin + AddError('"'+BESENTokenStrings[TokenType]+'" expected'); + end; + NextToken; + end; + procedure CleanUpLabels; + var i:integer; + begin + for i:=0 to LabelSetList.Count-1 do begin + TBESENParserLabelSet(LabelSetList[i]).Free; + LabelSetList[i]:=nil; + end; + LabelSetList.Clear; + for i:=0 to LabelList.Count-1 do begin + TBESENParserLabelSet(LabelList[i]).Free; + LabelList[i]:=nil; + end; + LabelList.Clear; + end; + function LabelSetCurrent:TBESENParserLabelSet; + begin + if not assigned(CurrentLabelSet) then begin + CurrentLabelSet:=TBESENParserLabelSet.Create(Instance); + CurrentLabelSet.Index:=LabelSetList.Add(CurrentLabelSet); + if assigned(LabelSets) then begin + CurrentLabelSet.Target:=LabelSets.Target+1; + end else begin + CurrentLabelSet.Target:=1; + end; + CurrentLabelSet.Next:=LabelSets; + LabelSets:=CurrentLabelSet; + end; + result:=CurrentLabelSet; + end; + function LabelEnter(const Name:TBESENString='';const Node:TBESENASTNode=nil):TBESENParserLabel; + var l:TBESENParserLabel; + begin + result:=nil; + try + if length(Name)<>0 then begin + l:=Labels; + while assigned(l) do begin + if l.Name=Name then begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16('Duplicate label "'+Name+'"'); + end; + l:=l.Next; + end; + end; + result:=TBESENParserLabel.Create(Instance); + result.Name:=Name; + result.LabelSet:=LabelSetCurrent; + result.Node:=Node; + result.LineNumber:=Lexer.LineNumber; + result.Next:=Labels; + result.Index:=LabelList.Add(result); + Labels:=result; + except + BESENFreeAndNil(result); + raise; + end; + end; + procedure LabelLeave; + var OldLabels:TBESENParserLabel; + begin +{$ifdef UseAssert} + Assert(assigned(Labels)); +{$endif} + if assigned(Labels) then begin + OldLabels:=Labels; + Labels:=OldLabels.Next; + LabelList[OldLabels.Index]:=niL; + BESENFreeAndNil(OldLabels); + end; + end; + function LabelTargetLookup(const Name:TBESENString='';const Continuable:boolean=false):TBESENTarget; + var l:TBESENParserLabel; + begin + try + l:=Labels; + while assigned(l) do begin + if l.Name=Name then begin + if Continuable and not l.LabelSet.Continuable then begin + if length(Name)=0 then begin + continue; + end; + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16('Label name "'+Name+'" not suitable for continue'); + end; + result:=l.LabelSet.Target; + exit; + end; + l:=l.Next; + end; + if length(Name)<>0 then begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16('Label name "'+Name+'" not defined, or not reachable'); + end else if Continuable then begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.Create('Continue statement not within a loop'); + end else begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.Create('Break statement not within a loop or switch'); + end; + except + raise; + end; + end; + function ParseSourceElement:TBESENASTNodeStatement; forward; + function ParseStatement(ResetCurrentLabelSet:boolean):TBESENASTNodeStatement; forward; + function ParseAssignmentExpression(InFlag:boolean):TBESENASTNodeExpression; forward; + function ParseExpression(InFlag:boolean):TBESENASTNodeExpression; forward; + function NextIsSemicolon:boolean; + begin + result:=(CurrentToken.TokenType in [ltEOF,ltoCLOSEBRACE,ltoSEMICOLON]) or (CurrentToken.WasLineEnd and not InForHeader); + end; + procedure ParseOptionalSemicolon; + begin + case CurrentToken.TokenType of + ltEOF:begin + end; + ltoCLOSEBRACE:begin + end; + ltoSEMICOLON:begin + SkipToken(ltoSEMICOLON); + end; + else begin + if not (CurrentToken.WasLineEnd and not InForHeader) then begin + SkipToken(ltoSEMICOLON); + end; + end; + end; + end; + procedure ParseDirective(var IsDirectivePrologue,FirstDirective:boolean;Body:TBESENASTNodeFunctionBody); + var OldToken:TBESENLexerToken; + begin + if IsDirectivePrologue then begin + if CurrentToken.TokenType=lttSTRING then begin + OldToken:=CurrentToken; + NextToken; + if NextIsSemicolon then begin + if (length(OldToken.StringValue)=10) and (copy(Lexer.Source,OldToken.OldPosition,10)='use strict') then begin + if UseStrictAlreadyParsed then begin + AddWarning('"use strict"/''use strict'' already seen!'); + end else begin + UseStrictAlreadyParsed:=true; + if not TBESEN(Instance).IsStrict then begin + TBESEN(Instance).IsStrict:=true; + Body.IsStrict:=true; + if not FirstDirective then begin + raise EBESENUseStrict.Create('Wrong "use strict"/''use strict'' position!'); + end; + end else begin + TBESEN(Instance).IsStrict:=true; + end; + end; + end; + FirstDirective:=false; + end else begin + IsDirectivePrologue:=false; + end; + Lexer.Restore(OldToken); + NextToken; + end else begin + IsDirectivePrologue:=false; + end; + end; + end; + function ParseIdentifier(AllowEvalArguments:boolean):TBESENASTNodeIdentifier; + begin + result:=nil; + try + result:=TBESENASTNodeIdentifier.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType=lttIDENTIFIER then begin + result.Name:=CurrentToken.Name; + end else begin + AddError('identifier literal expected'); + end; + if (TBESEN(Instance).IsStrict and not AllowEvalArguments) and ((result.Name='eval') or (result.Name='arguments')) then begin + AddError('"'+result.Name+'" not allowed here'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseIdentifierName(AllowEvalArguments:boolean):TBESENASTNodeIdentifier; + begin + result:=nil; + try + result:=TBESENASTNodeIdentifier.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType in BESENLexerKeywordsTokens then begin + result.Name:=BESENTokenStrings[CurrentToken.TokenType]; + end else if CurrentToken.TokenType=lttIDENTIFIER then begin + result.Name:=CurrentToken.Name; + end else begin + AddError('identifier literal expected'); + end; + if (TBESEN(Instance).IsStrict and not AllowEvalArguments) and ((result.Name='eval') or (result.Name='arguments')) then begin + AddError('"'+result.Name+'" not allowed here'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseFunctionLiteral(WithFunction,WithName:boolean):TBESENASTNodeFunctionLiteral; + var i,j:integer; + OldIsInFunction,OldIsStrict,OldUseStrictAlreadyParsed:boolean; + OldToken:TBesenLexerToken; + procedure ParseFunctionStatements; + var IsDirectivePrologue,FirstDirective:boolean; + Statements,i:integer; + begin + Statements:=0; + try + IsDirectivePrologue:=true; + FirstDirective:=true; + UseStrictAlreadyParsed:=false; + while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin + if IsDirectivePrologue then begin + ParseDirective(IsDirectivePrologue,FirstDirective,result.Body); + end; + if Statements>=length(result.Body.Statements) then begin + SetLength(result.Body.Statements,Statements+256); + end; + result.Body.Statements[Statements]:=ParseSourceElement; + inc(Statements); + end; + SetLength(result.Body.Statements,Statements); + SkipToken(ltoCLOSEBRACE); + except + for i:=0 to Statements-1 do begin + BesenFreeAndNil(result.Body.Statements[i]); + end; + SetLength(result.Body.Statements,0); + Statements:=0; + raise; + end; + end; + function ParseFakeReturnStatement:TBESENASTNodeReturnStatement; + begin + result:=nil; + try + result:=TBESENASTNodeReturnStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + if not NextIsSemicolon then begin + result.Expression:=ParseExpression(true); + end; + if NextIsSemicolon then begin + ParseOptionalSemicolon; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + var FakeReturnStatement:TBESENASTNodeReturnStatement; + begin + result:=nil; + try + OldUseStrictAlreadyParsed:=UseStrictAlreadyParsed; + OldIsInFunction:=IsInFunction; + OldIsStrict:=TBESEN(Instance).IsStrict; + IsInFunction:=true; + try + result:=TBESENASTNodeFunctionLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + + if WithFunction then begin + SkipToken(ltkFUNCTION); + end; + + if WithName or (CurrentToken.TokenType<>ltoOPENPAREN) then begin + result.Name:=ParseIdentifier(not TBESEN(Instance).IsStrict); + end; + + SkipToken(ltoOPENPAREN); + i:=0; + if (CurrentToken.TokenType<>ltoCLOSEPAREN) and not Lexer.IsEOF then begin + while true do begin + if i>=length(result.Body.Parameters) then begin + SetLength(result.Body.Parameters,i+256); + end; + result.Body.Parameters[i]:=ParseIdentifier(not TBESEN(Instance).IsStrict); + if TBESEN(Instance).IsStrict and (result.Body.Parameters[i] is TBESENASTNodeIdentifier) then begin + for j:=0 to i-1 do begin + if TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name=TBESENASTNodeIdentifier(result.Body.Parameters[j]).Name then begin + AddError('Duplicate parameter "'+TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name+'"'); + end; + end; + end; + inc(i); + if Lexer.IsEOF or (CurrentToken.TokenType=ltoCLOSEPAREN) then begin + break; + end else if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end; + end; + end; + SetLength(result.Body.Parameters,i); + SkipToken(ltoCLOSEPAREN); + + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (CurrentToken.TokenType<>ltoOPENBRACE) then begin + UseStrictAlreadyParsed:=false; + result.Body.IsStrict:=TBESEN(Instance).IsStrict; + if CurrentToken.WasLineEnd then begin + CurrentToken.WasLineEnd:=false; + end; + FakeReturnStatement:=ParseFakeReturnStatement; + SetLength(result.Body.Statements,1); + result.Body.Statements[0]:=FakeReturnStatement; + end else begin + SkipToken(ltoOPENBRACE); + if IsFunction then begin + IsFunction:=false; + Lexer.LineNumber:=1; + end; + OldToken:=CurrentToken; + result.Body.IsStrict:=TBESEN(Instance).IsStrict; + try + ParseFunctionStatements; + except + on e:EBESENUseStrict do begin + result.Body.IsStrict:=TBESEN(Instance).IsStrict; + Lexer.Restore(OldToken); + NextToken; + ParseFunctionStatements; + end; + end; + end; + finally + IsInFunction:=OldIsInFunction; + TBESEN(Instance).IsStrict:=OldIsStrict; + UseStrictAlreadyParsed:=OldUseStrictAlreadyParsed; + end; + if result.Body.IsStrict then begin + if assigned(result.Name) and ((result.Name.Name='eval') or (result.Name.Name='arguments')) then begin + AddError('"'+result.Name.Name+'" not allowed here as function parameter name'); + end; + for i:=0 to length(result.Body.Parameters)-1 do begin + if (result.Body.Parameters[i].Name='eval') or (result.Body.Parameters[i].Name='arguments') then begin + AddError('"'+result.Body.Parameters[i].Name+'" not allowed here as function parameter name'); + end; + for j:=0 to i-1 do begin + if result.Body.Parameters[i].Name=result.Body.Parameters[j].Name then begin + AddError('Duplicate parameter "'+TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name+'"'); + end; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseFunctionDeclaration:TBESENASTNodeFunctionDeclaration; + var Literal:TBESENASTNodeFunctionLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeFunctionDeclaration.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + Literal:=ParseFunctionLiteral(true,true); + result.Container:=Literal.Container; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseFunctionExpression(WithFunction,WithName:boolean):TBESENASTNodeFunctionExpression; + var Literal:TBESENASTNodeFunctionLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeFunctionExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + Literal:=ParseFunctionLiteral(WithFunction,WithName); + result.Container:=Literal.Container; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseStatementList(InSwitch:boolean):TBESENASTNodeStatements; + var Count:integer; + begin + result:=nil; + try + Count:=0; + while (not ((CurrentToken.TokenType=ltoCLOSEBRACE) or (InSwitch and (CurrentToken.TokenType=ltkCASE) or (CurrentToken.TokenType=ltkDEFAULT)))) and not Lexer.IsEOF do begin + if Count>=length(result) then begin + SetLength(result,Count+256); + end; + result[Count]:=ParseStatement(true); + inc(Count); + if CurrentToken.TokenType=ltkFUNCTION then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + break; + end; + end; + end; + SetLength(result,Count); + except + for Count:=0 to length(result)-1 do begin + BESENFreeAndNil(result[Count]); + end; + SetLength(result,0); + raise; + end; + end; + function ParseBlockStatement:TBESENASTNodeBlockStatement; + begin + result:=nil; + try + SkipToken(ltoOPENBRACE); + result:=TBESENASTNodeBlockStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + result.Statements:=ParseStatementList(false); + SkipToken(ltoCLOSEBRACE); + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseDebuggerStatement:TBESENASTNodeDebuggerStatement; + begin + result:=nil; + try + SkipToken(ltkDEBUGGER); + result:=TBESENASTNodeDebuggerStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBreakStatement:TBESENASTNodeBreakStatement; + begin + result:=nil; + try + SkipToken(ltkBREAK); + result:=TBESENASTNodeBreakStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + if NextIsSemicolon then begin + result.Target:=LabelTargetLookup('',false); + end else begin + if CurrentToken.TokenType=lttIDENTIFIER then begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after break'); + end; + result.Identifier:=ParseIdentifier(true); + if assigned(result.Identifier) then begin + result.Target:=LabelTargetLookup(result.Identifier.Name,false); + end else begin + result.Target:=LabelTargetLookup('',false); + end; + end; + ParseOptionalSemicolon; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseContinueStatement:TBESENASTNodeContinueStatement; + begin + result:=nil; + try + SkipToken(ltkCONTINUE); + result:=TBESENASTNodeContinueStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + if NextIsSemicolon then begin + result.Target:=LabelTargetLookup('',true); + end else begin + if CurrentToken.TokenType=lttIDENTIFIER then begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after continue'); + end; + result.Identifier:=ParseIdentifier(true); + if assigned(result.Identifier) then begin + result.Target:=LabelTargetLookup(result.Identifier.Name,true); + end else begin + result.Target:=LabelTargetLookup('',true); + end; + end; + ParseOptionalSemicolon; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseAssignmentExpression(InFlag); + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoCOMMA:begin + SkipToken(ltoCOMMA); + Left:=result; + result:=TBESENASTNodeBinaryCommaExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryCommaExpression(result).LeftExpression:=Left; + TBESENASTNodeBinaryCommaExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseDoStatement:TBESENASTNodeDoStatement; + var LabelSet:TBESENParserLabelSet; + begin + result:=nil; + try + result:=TBESENASTNodeDoStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + LabelEnter('',result); + result.Target:=LabelSet.Target; + SkipToken(ltkDO); + result.Statement:=ParseStatement(true); + SkipToken(ltkWHILE); + result.Expression:=ParseExpression(true); + ParseOptionalSemicolon; + LabelLeave; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseRegExpLiteral:TBESENASTNodeRegExpLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeRegExpLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType in [ltoDIVIDE,ltoDIVIDEASSIGNMENT] then begin + Lexer.Restore(CurrentToken); + if not Lexer.ParseRegExpLiteral(CurrentToken,result.Source,result.Flags) then begin + AddError('regex literal expected'); + end; + end else begin + AddError('regex literal expected'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseStringLiteral:TBESENASTNodeStringLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeStringLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType=lttSTRING then begin + result.Value:=CurrentToken.StringValue; + end else begin + AddError('string literal expected'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseNumbericLiteral:TBESENASTNodeNumberLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeNumberLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + case CurrentToken.TokenType of + lttINTEGER:begin + result.Value:=CurrentToken.IntValue; + end; + lttFLOAT:begin + result.Value:=CurrentToken.FloatValue; + end; + else begin + AddError('numberic literal expected'); + end; + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseObjectLiteralProperty(const Parent:TBESENASTNodeObjectLiteral;const Count:integer):TBESENASTNodeObjectLiteralProperty; + var PropertyType:TBESENASTNodeObjectLiteralPropertyType; + PropertyAccessorType:TBESENASTNodeObjectLiteralPropertyAccessorType; + OldToken:TBESENLexerToken; + i:integer; + Key:TBESENString; + function ParseObjectLiteralPropertyName:TBESENString; + begin + case CurrentToken.TokenType of + lttIDENTIFIER:begin + result:=CurrentToken.Name; + NextToken; + end; + lttSTRING:begin + result:=CurrentToken.StringValue; + NextToken; + end; + lttINTEGER:begin + result:=TBESEN(Instance).ToStr(BESENNumberValue(CurrentToken.IntValue)); + NextToken; + end; + lttFLOAT:begin + result:=TBESEN(Instance).ToStr(BESENNumberValue(CurrentToken.FloatValue)); + NextToken; + end; + else begin + if CurrentToken.TokenType in BESENLexerKeywordsTokens then begin + result:=BESENTokenStrings[CurrentToken.TokenType]; + NextToken; + end else begin + AddError('identifier or numeric literal expected'); + end; + end; + end; + end; + var Literal:TBESENASTNodeFunctionLiteral; + begin + result:=nil; + try + PropertyType:=banolptDATA; + PropertyAccessorType:=banolpatNONE; + if (CurrentToken.TokenType=lttIDENTIFIER) and ((CurrentToken.Name='get') or (CurrentToken.Name='set')) then begin + OldToken:=CurrentToken; + if CurrentToken.Name='get' then begin + PropertyType:=banolptACCESSOR; + PropertyAccessorType:=banolpatGET; + end else if CurrentToken.Name='set' then begin + PropertyType:=banolptACCESSOR; + PropertyAccessorType:=banolpatSET; + end; + if PropertyType=banolptACCESSOR then begin + NextToken; + if not (CurrentToken.TokenType in [lttIDENTIFIER,lttSTRING,lttINTEGER,lttFLOAT]) then begin + PropertyType:=banolptDATA; + Lexer.Restore(OldToken); + NextToken; + end; + end; + end; + Key:=ParseObjectLiteralPropertyName; + case PropertyType of + banolptACCESSOR:begin + for i:=0 to Count-1 do begin + if Key=Parent.Properties[i].Name then begin + case Parent.Properties[i].PropertyType of + banolptACCESSOR:begin + if Parent.Properties[i].PropertyAccessorType=PropertyAccessorType then begin + case PropertyAccessorType of + banolpatGET:begin + AddError('Duplicate accessor property getter "'+Key+'"'); + end; + banolpatSET:begin + AddError('Duplicate accessor property setter "'+Key+'"'); + end; + else begin + AddError('Invalid property "'+Key+'"'); + end; + end; + end; + end; + banolptDATA:begin + AddError('Invalid property "'+Key+'"'); + end; + end; + end; + end; + result:=TBESENASTNodeObjectLiteralProperty.Create(Instance); + result.PropertyType:=PropertyType; + result.PropertyAccessorType:=PropertyAccessorType; + result.Name:=Key; + Literal:=ParseFunctionLiteral(false,false); + result.Container:=Literal.Container; + if not ((PropertyAccessorType in [banolpatGET,banolpatSET]) and (assigned(Literal) and assigned(Literal.Body))) then begin + AddError('Invalid property "'+Key+'"'); + end else begin + case PropertyAccessorType of + banolpatGET:begin + if length(Literal.Body.Parameters)>0 then begin + AddError('Getter must have no parameters'); + end; + end; + banolpatSET:begin + if length(Literal.Body.Parameters)<>1 then begin + AddError('Setter must have only one parameter'); + end; + end; + else begin + AddError('Invalid property "'+Key+'"'); + end; + end; + end; + end; + banolptDATA:begin + for i:=0 to Count-1 do begin + if Key=Parent.Properties[i].Name then begin + case Parent.Properties[i].PropertyType of + banolptACCESSOR:begin + AddError('Invalid property "'+Key+'"'); + end; + banolptDATA:begin + if TBESEN(Instance).IsStrict then begin + AddError('Duplicate data property "'+Key+'"'); + end; + end; + end; + end; + end; + result:=TBESENASTNodeObjectLiteralProperty.Create(Instance); + result.PropertyType:=banolptDATA; + result.Location.LineNumber:=CurrentToken.LineNumber; + result.Name:=Key; + SkipToken(ltoCOLON); + result.Value:=ParseAssignmentExpression(true); + end; + else begin + AddError('Invalid property "'+Key+'"'); + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseObjectLiteral:TBESENASTNodeObjectLiteral; + var Count:integer; + begin + result:=nil; + try + result:=TBESENASTNodeObjectLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + result.Properties:=nil; + Count:=0; + SkipToken(ltoOPENBRACE); + while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin + if Count>=length(result.Properties) then begin + SetLength(result.Properties,Count+256); + end; + result.Properties[Count]:=ParseObjectLiteralProperty(result,Count); + inc(Count); + if CurrentToken.TokenType<>ltoCLOSEBRACE then begin + if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end else begin + AddError(''','' or ''}'' expected'); + break; + end; + end; + end; + SetLength(result.Properties,Count); + SkipToken(ltoCLOSEBRACE); + except + for Count:=0 to length(result.Properties)-1 do begin + BESENFreeAndNil(result.Properties[Count]); + end; + SetLength(result.Properties,0); + BESENFreeAndNil(result); + raise; + end; + end; + function ParseArrayLiteral:TBESENASTNodeArrayLiteral; + var Count:integer; + begin + result:=nil; + try + result:=TBESENASTNodeArrayLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoOPENSQUARE); + result.Elements:=nil; + Count:=0; + while (CurrentToken.TokenType<>ltoCLOSESQUARE) and not Lexer.IsEOF do begin + if Count>=length(result.Elements) then begin + SetLength(result.Elements,Count+256); + end; + if CurrentToken.TokenType=ltoCOMMA then begin + result.Elements[Count]:=nil; + end else begin + result.Elements[Count]:=ParseAssignmentExpression(true); + end; + inc(Count); + if CurrentToken.TokenType<>ltoCLOSESQUARE then begin + if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end else begin + AddError(''','' or '']'' expected'); + break; + end; + end; + end; + SetLength(result.Elements,Count); + SkipToken(ltoCLOSESQUARE); + except + for Count:=0 to length(result.Elements)-1 do begin + BESENFreeAndNil(result.Elements[Count]); + end; + SetLength(result.Elements,0); + BESENFreeAndNil(result); + raise; + end; + end; + function ParsePrimaryExpression:TBESENASTNodeExpression; + begin + result:=nil; + try + case CurrentToken.TokenType of + ltkTHIS:begin + result:=TBESENASTNodeThisLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkTHIS); + end; + ltkNULL:begin + result:=TBESENASTNodeNullLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkNULL); + end; + ltkTRUE:begin + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBooleanLiteral(result).Value:=true; + SkipToken(ltkTRUE); + end; + ltkFALSE:begin + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBooleanLiteral(result).Value:=false; + SkipToken(ltkFALSE); + end; + ltoOPENPAREN:begin + SkipToken(ltoOPENPAREN); + result:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + end; + ltoOPENBRACE:begin + result:=ParseObjectLiteral; + end; + ltoOPENSQUARE:begin + result:=ParseArrayLiteral; + end; + lttIDENTIFIER:begin + result:=ParseIdentifier(true); + end; + ltoDIVIDE,ltoDIVIDEASSIGNMENT:begin + result:=ParseRegExpLiteral; + end; + lttSTRING:begin + result:=ParseStringLiteral; + end; + lttINTEGER,lttFLOAT:begin + result:=ParseNumbericLiteral; + end; + else begin + AddError('identifier or literal expected'); + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseArgumentList:TBESENASTNodeExpressions; + var Count:integer; + begin + result:=nil; + try + Count:=0; + SkipToken(ltoOPENPAREN); + if (CurrentToken.TokenType<>ltoCLOSEPAREN) and not Lexer.IsEOF then begin + while true do begin + if Count>=length(result) then begin + SetLength(result,Count+256); + end; + result[Count]:=ParseAssignmentExpression(true); + inc(Count); + if Lexer.IsEOF or (CurrentToken.TokenType=ltoCLOSEPAREN) then begin + break; + end else if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end else begin + break; + end; + end; + end; + SkipToken(ltoCLOSEPAREN); + SetLength(result,Count); + except + for Count:=0 to length(result)-1 do begin + BESENFreeAndNil(result[Count]); + end; + SetLength(result,0); + raise; + end; + end; + function ParseLeftHandSideAndMemberExpression(IsLeftHandSideExpression:boolean=true):TBESENASTNodeExpression; + var Expression:TBESENASTNodeExpression; + Identifier:TBESENASTNodeIdentifier; + begin + result:=nil; + try + case CurrentToken.TokenType of + ltkNEW:begin + SkipToken(ltkNEW); + result:=TBESENASTNodeNewExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeNewExpression(result).TheFunction:=ParseLeftHandSideAndMemberExpression(false); + if CurrentToken.TokenType=ltoOPENPAREN then begin + TBESENASTNodeNewExpression(result).Arguments:=ParseArgumentList; + end else begin + TBESENASTNodeNewExpression(result).Arguments:=nil; + end; + end; + ltkFUNCTION:begin + result:=ParseFunctionExpression(true,false); + end; + else begin + result:=ParsePrimaryExpression; + end; + end; + while not Lexer.IsEOF do begin + if IsLeftHandSideExpression and (CurrentToken.TokenType=ltoOPENPAREN) then begin + Expression:=result; + result:=TBESENASTNodeCallExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeCallExpression(result).TheFunction:=Expression; + TBESENASTNodeCallExpression(result).Arguments:=ParseArgumentList; + end else if CurrentToken.TokenType=ltoOPENSQUARE then begin + Expression:=result; + result:=TBESENASTNodePropertyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodePropertyExpression(result).Dot:=false; + TBESENASTNodePropertyExpression(result).LeftExpression:=Expression; + SkipToken(ltoOPENSQUARE); + TBESENASTNodePropertyExpression(result).RightExpression:=ParseExpression(true); + if TBESEN(Instance).IsStrict then begin + if assigned(TBESENASTNodePropertyExpression(result).RightExpression) then begin + if TBESENASTNodePropertyExpression(result).RightExpression is TBESENASTNodeStringLiteral then begin + if ((TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value='eval') or (TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value='arguments')) then begin + AddError('"'+TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value+'" not allowed here'); + end; + end; + end; + end; + SkipToken(ltoCLOSESQUARE); + end else if CurrentToken.TokenType=ltoDOT then begin + Expression:=result; + result:=TBESENASTNodePropertyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodePropertyExpression(result).Dot:=true; + TBESENASTNodePropertyExpression(result).LeftExpression:=Expression; + SkipToken(ltoDOT); + TBESENASTNodePropertyExpression(result).RightExpression:=TBESENASTNodeStringLiteral.Create(Instance); + Identifier:=ParseIdentifierName(true); + TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value:=Identifier.Name; + Identifier.Free; + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParsePostfixExpression:TBESENASTNodeExpression; + var Expression:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseLeftHandSideAndMemberExpression; + case CurrentToken.TokenType of + ltoPLUSPLUS:begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator before postfix increment'); + end; + Expression:=result; + result:=TBESENASTNodePostfixIncExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoPLUSPLUS); + TBESENASTNodePostfixIncExpression(result).SubExpression:=Expression; + end; + ltoMINUSMINUS:begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator before postfix decrement'); + end; + Expression:=result; + result:=TBESENASTNodePostfixDecExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoMINUSMINUS); + TBESENASTNodePostfixDecExpression(result).SubExpression:=Expression; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseUnaryExpression:TBESENASTNodeExpression; + begin + result:=nil; + try + case CurrentToken.TokenType of + ltoPLUSPLUS:begin + result:=TBESENASTNodePrefixIncExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoPLUSPLUS); + TBESENASTNodePrefixIncExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoMINUSMINUS:begin + result:=TBESENASTNodePrefixDecExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoMINUSMINUS); + TBESENASTNodePrefixdecExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoPLUS:begin + result:=TBESENASTNodeUnaryPlusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoPLUS); + TBESENASTNodeUnaryPlusExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoMINUS:begin + result:=TBESENASTNodeUnaryMinusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoMINUS); + TBESENASTNodeUnaryMinusExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoBITWISENOT:begin + result:=TBESENASTNodeUnaryBitwiseNotExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoBITWISENOT); + TBESENASTNodeUnaryBitwiseNotExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoLOGICALNOT:begin + result:=TBESENASTNodeUnaryLogicalNotExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoLOGICALNOT); + TBESENASTNodeUnaryLogicalNotExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltkVOID:begin + result:=TBESENASTNodeUnaryVoidExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkVOID); + TBESENASTNodeUnaryVoidExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltkTYPEOF:begin + result:=TBESENASTNodeUnaryTypeOfExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkTYPEOF); + TBESENASTNodeUnaryTypeOfExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltkDELETE:begin + result:=TBESENASTNodeDeleteExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkDELETE); + TBESENASTNodeDeleteExpression(result).SubExpression:=ParseUnaryExpression; + end; + else begin + result:=ParsePostfixExpression; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseMultiplyExpression:TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseUnaryExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoDIVIDE:begin + Left:=result; + result:=TBESENASTNodeBinaryDivideExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryDivideExpression(result).LeftExpression:=Left; + SkipToken(ltoDIVIDE); + TBESENASTNodeBinaryDivideExpression(result).RightExpression:=ParseUnaryExpression; + end; + ltoMODULO:begin + Left:=result; + result:=TBESENASTNodeBinaryModuloExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryModuloExpression(result).LeftExpression:=Left; + SkipToken(ltoMODULO); + TBESENASTNodeBinaryModuloExpression(result).RightExpression:=ParseUnaryExpression; + end; + ltoMULTIPLY:begin + Left:=result; + result:=TBESENASTNodeBinaryMultiplyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryMultiplyExpression(result).LeftExpression:=Left; + SkipToken(ltoMULTIPLY); + TBESENASTNodeBinaryMultiplyExpression(result).RightExpression:=ParseUnaryExpression; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseAdditionExpression:TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseMultiplyExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoPLUS:begin + Left:=result; + result:=TBESENASTNodeBinaryPlusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryPlusExpression(result).LeftExpression:=Left; + SkipToken(ltoPLUS); + TBESENASTNodeBinaryPlusExpression(result).RightExpression:=ParseMultiplyExpression; + end; + ltoMINUS:begin + Left:=result; + result:=TBESENASTNodeBinaryMinusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryMinusExpression(result).LeftExpression:=Left; + SkipToken(ltoMINUS); + TBESENASTNodeBinaryMinusExpression(result).RightExpression:=ParseMultiplyExpression; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseShiftExpression:TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseAdditionExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoSHIFTLEFT:begin + Left:=result; + result:=TBESENASTNodeBinaryShiftLeftExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryShiftLeftExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTLEFT); + TBESENASTNodeBinaryShiftLeftExpression(result).RightExpression:=ParseAdditionExpression; + end; + ltoSHIFTRIGHT:begin + Left:=result; + result:=TBESENASTNodeBinaryShiftRightExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryShiftRightExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHT); + TBESENASTNodeBinaryShiftRightExpression(result).RightExpression:=ParseAdditionExpression; + end; + ltoSHIFTRIGHTUNSIGNED:begin + Left:=result; + result:=TBESENASTNodeBinaryShiftRightUnsignedExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHTUNSIGNED); + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).RightExpression:=ParseAdditionExpression; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseRelationalExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseShiftExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoGREATERTHAN:begin + Left:=result; + result:=TBESENASTNodeBinaryGreaterThanExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryGreaterThanExpression(result).LeftExpression:=Left; + SkipToken(ltoGREATERTHAN); + TBESENASTNodeBinaryGreaterThanExpression(result).RightExpression:=ParseShiftExpression; + end; + ltoGREATERTHANOREQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryGreaterThanOrEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoGREATERTHANOREQUAL); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).RightExpression:=ParseShiftExpression; + end; + ltoLESSTHAN:begin + Left:=result; + result:=TBESENASTNodeBinaryLessThanExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryLessThanExpression(result).LeftExpression:=Left; + SkipToken(ltoLESSTHAN); + TBESENASTNodeBinaryLessThanExpression(result).RightExpression:=ParseShiftExpression; + end; + ltoLESSTHANOREQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryLessThanOrEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryLessThanOrEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoLESSTHANOREQUAL); + TBESENASTNodeBinaryLessThanOrEqualExpression(result).RightExpression:=ParseShiftExpression; + end; + ltkINSTANCEOF:begin + Left:=result; + result:=TBESENASTNodeBinaryInstanceOfExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryInstanceOfExpression(result).LeftExpression:=Left; + SkipToken(ltkINSTANCEOF); + TBESENASTNodeBinaryInstanceOfExpression(result).RightExpression:=ParseShiftExpression; + end; + ltkIN:begin + if InFlag then begin + Left:=result; + result:=TBESENASTNodeBinaryInExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryInExpression(result).LeftExpression:=Left; + SkipToken(ltkIN); + TBESENASTNodeBinaryInExpression(result).RightExpression:=ParseShiftExpression; + end else begin + break; + end; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseEqualityExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseRelationalExpression(InFlag); + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoEQUALEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryEqualEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryEqualEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoEQUALEQUAL); + TBESENASTNodeBinaryEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + ltoEQUALEQUALEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryEqualEqualEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryEqualEqualEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoEQUALEQUALEQUAL); + TBESENASTNodeBinaryEqualEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + ltoNOTEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryNotEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryNotEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoNOTEQUAL); + TBESENASTNodeBinaryNotEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + ltoNOTEQUALEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryNotEqualEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryNotEqualEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoNOTEQUALEQUAL); + TBESENASTNodeBinaryNotEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBitwiseAndExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseEqualityExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoBITWISEAND then begin + Left:=result; + result:=TBESENASTNodeBinaryBitwiseAndExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryBitwiseAndExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEAND); + TBESENASTNodeBinaryBitwiseAndExpression(result).RightExpression:=ParseEqualityExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBitwiseXorExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseBitwiseAndExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoBITWISEXOR then begin + Left:=result; + result:=TBESENASTNodeBinaryBitwiseXorExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryBitwiseXorExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEXOR); + TBESENASTNodeBinaryBitwiseXorExpression(result).RightExpression:=ParseBitwiseAndExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBitwiseOrExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseBitwiseXorExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoBITWISEOR then begin + Left:=result; + result:=TBESENASTNodeBinaryBitwiseOrExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryBitwiseOrExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEOR); + TBESENASTNodeBinaryBitwiseOrExpression(result).RightExpression:=ParseBitwiseXorExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseLogicalAndExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseBitwiseOrExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoLOGICALAND then begin + Left:=result; + result:=TBESENASTNodeLogicalAndExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeLogicalAndExpression(result).LeftExpression:=Left; + SkipToken(ltoLOGICALAND); + TBESENASTNodeLogicalAndExpression(result).RightExpression:=ParseBitwiseOrExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseLogicalOrExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseLogicalAndExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoLOGICALOR then begin + Left:=result; + result:=TBESENASTNodeLogicalOrExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeLogicalOrExpression(result).LeftExpression:=Left; + SkipToken(ltoLOGICALOR); + TBESENASTNodeLogicalOrExpression(result).RightExpression:=ParseLogicalAndExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseConditionalExpression(InFlag:boolean):TBESENASTNodeExpression; + var Expression:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseLogicalOrExpression(InFlag); + if CurrentToken.TokenType=ltoCONDITIONAL then begin + Expression:=result; + result:=TBESENASTNodeConditionalExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeConditionalExpression(result).Expression:=Expression; + SkipToken(ltoCONDITIONAL); + TBESENASTNodeConditionalExpression(result).TrueExpression:=ParseAssignmentExpression(InFlag); + SkipToken(ltoCOLON); + TBESENASTNodeConditionalExpression(result).FalseExpression:=ParseAssignmentExpression(InFlag); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseAssignmentExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + Left:=nil; + try + result:=ParseConditionalExpression(InFlag); + case CurrentToken.TokenType of + ltoASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentExpression(result).LeftExpression:=Left; + SkipToken(ltoASSIGNMENT); + TBESENASTNodeAssignmentExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoMULTIPLYASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentMultiplyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentMultiplyExpression(result).LeftExpression:=Left; + SkipToken(ltoMULTIPLYASSIGNMENT); + TBESENASTNodeAssignmentMultiplyExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoDIVIDEASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentDivideExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentDivideExpression(result).LeftExpression:=Left; + SkipToken(ltoDIVIDEASSIGNMENT); + TBESENASTNodeAssignmentDivideExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoMODULOASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentModuloExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentModuloExpression(result).LeftExpression:=Left; + SkipToken(ltoMODULOASSIGNMENT); + TBESENASTNodeAssignmentModuloExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoPLUSASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentPlusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentPlusExpression(result).LeftExpression:=Left; + SkipToken(ltoPLUSASSIGNMENT); + TBESENASTNodeAssignmentPlusExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoMINUSASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentMinusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentMinusExpression(result).LeftExpression:=Left; + SkipToken(ltoMINUSASSIGNMENT); + TBESENASTNodeAssignmentMinusExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoSHIFTLEFTASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentShiftLeftExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentShiftLeftExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTLEFTASSIGNMENT); + TBESENASTNodeAssignmentShiftLeftExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoSHIFTRIGHTASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentShiftRightExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentShiftRightExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHTASSIGNMENT); + TBESENASTNodeAssignmentShiftRightExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoSHIFTRIGHTUNSIGNEDASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentShiftRightUnsignedExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHTUNSIGNEDASSIGNMENT); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoBITWISEANDASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentBitwiseAndExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentBitwiseAndExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEANDASSIGNMENT); + TBESENASTNodeAssignmentBitwiseAndExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoBITWISEXORASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentBitwiseXorExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentBitwiseXorExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEXORASSIGNMENT); + TBESENASTNodeAssignmentBitwiseXorExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoBITWISEORASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentBitwiseOrExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentBitwiseOrExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEORASSIGNMENT); + TBESENASTNodeAssignmentBitwiseOrExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseVariableDeclaration(InFlag:boolean):TBESENASTNodeVariableDeclaration; + begin + result:=nil; + try + result:=TBESENASTNodeVariableDeclaration.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + result.Identifier:=ParseIdentifier(not TBESEN(Instance).IsStrict); + if CurrentToken.TokenType=ltoASSIGNMENT then begin + SkipToken(ltoASSIGNMENT); + result.Expression:=ParseAssignmentExpression(InFlag); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseForStatement:TBESENASTNodeStatement; + var OldInForHeader:boolean; + State,i,ln:integer; + Declaration:TBESENASTNodeVariableDeclaration; + Initial,Expression,Variable:TBESENASTNodeExpression; + VariableExpression:TBESENASTNodeVariableExpression; + LabelSet:TBESENParserLabelSet; + ALabel:TBESENParserLabel; + begin + ln:=Lexer.LineNumber; + result:=nil; + Initial:=nil; + Declaration:=nil; + Variable:=nil; + Expression:=nil; + try + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + ALabel:=LabelEnter('',nil); + + SkipToken(ltkFOR); + + SkipToken(ltoOPENPAREN); + OldInForHeader:=InForHeader; + InForHeader:=true; + State:=0; + while not Lexer.IsEOF do begin + case State of + 0:begin + if CurrentToken.TokenType=ltkVAR then begin + State:=1; + end else if CurrentToken.TokenType<>ltoSEMICOLON then begin + State:=2; + end else begin + State:=5; + end; + end; + 1:begin + SkipToken(ltkVAR); + Declaration:=ParseVariableDeclaration(false); + if (CurrentToken.TokenType=ltkIN) and (assigned(Declaration) and not assigned(Declaration.Expression)) then begin + Variable:=Declaration; + Declaration:=nil; + State:=3; + end else begin + State:=4; + end; + end; + 2:begin + Initial:=ParseExpression(false); + if CurrentToken.TokenType=ltkIN then begin + Variable:=Initial; + Initial:=nil; + State:=3; + end else begin + State:=5; + end; + end; + 3:begin + SkipToken(ltkIN); + Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + InForHeader:=OldInForHeader; + result:=TBESENASTNodeForInStatement.Create(Instance); + TBESENASTNodeForInStatement(result).Target:=LabelSet.Target; + TBESENASTNodeForInStatement(result).Variable:=Variable; + TBESENASTNodeForInStatement(result).Expression:=Expression; + ALabel.Node:=result; + Variable:=nil; + Expression:=nil; + break; + end; + 4:begin + VariableExpression:=TBESENASTNodeVariableExpression.Create(Instance); + Initial:=VariableExpression; + SetLength(VariableExpression.Declarations,1); + VariableExpression.Declarations[0]:=Declaration; + Declaration:=nil; + i:=1; + while (CurrentToken.TokenType=ltoCOMMA) and not Lexer.IsEOF do begin + SkipToken(ltoCOMMA); + if i>=length(VariableExpression.Declarations) then begin + SetLength(VariableExpression.Declarations,i+256); + end; + VariableExpression.Declarations[i]:=ParseVariableDeclaration(false); + inc(i); + end; + SetLength(VariableExpression.Declarations,i); + State:=5; + end; + 5:begin + result:=TBESENASTNodeForStatement.Create(Instance); + TBESENASTNodeForStatement(result).Initial:=Initial; + TBESENASTNodeForStatement(result).Target:=LabelSet.Target; + ALabel.Node:=result; + Initial:=nil; + SkipToken(ltoSEMICOLON); + if CurrentToken.TokenType<>ltoSEMICOLON then begin + TBESENASTNodeForStatement(result).Condition:=ParseExpression(true); + end; + SkipToken(ltoSEMICOLON); + if CurrentToken.TokenType<>ltoCLOSEPAREN then begin + TBESENASTNodeForStatement(result).Increment:=ParseExpression(true); + end; + SkipToken(ltoCLOSEPAREN); + break; + end; + end; + end; + InForHeader:=OldInForHeader; + if assigned(result) then begin + if result is TBESENASTNodeForStatement then begin + TBESENASTNodeForStatement(result).Statement:=ParseStatement(true); + end else if result is TBESENASTNodeForInStatement then begin + TBESENASTNodeForInStatement(result).Statement:=ParseStatement(true); + end; + end else begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + end; + result.Location.LineNumber:=ln; + LabelLeave; + except + BESENFreeAndNil(Initial); + BESENFreeAndNil(Declaration); + BESENFreeAndNil(Variable); + BESENFreeAndNil(Expression); + BESENFreeAndNil(result); + raise; + end; + end; + function ParseIfStatement:TBESENASTNodeIfStatement; + begin + result:=nil; + try + result:=TBESENASTNodeIfStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkIF); + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + result.TrueStatement:=ParseStatement(true); + if CurrentToken.TokenType=ltkELSE then begin + SkipToken(ltkELSE); + result.FalseStatement:=ParseStatement(true); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseReturnStatement:TBESENASTNodeReturnStatement; + begin + result:=nil; + try + if not IsInFunction then begin + raise EBESENSyntaxError.Create('Return outside a function'); + end; + result:=TBESENASTNodeReturnStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkRETURN); + if not NextIsSemicolon then begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after return'); + end; + result.Expression:=ParseExpression(true); + end; + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseThrowStatement:TBESENASTNodeThrowStatement; + begin + result:=nil; + try + result:=TBESENASTNodeThrowStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkTHROW); + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after throw'); + end; + result.Expression:=ParseExpression(true); + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseTryStatement:TBESENASTNodeTryStatement; + begin + result:=nil; + try + result:=TBESENASTNodeTryStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkTRY); + + result.CatchBlock:=nil; + result.FinallyBlock:=nil; + result.CatchIdentifier:=nil; + + result.TryBlock:=ParseBlockStatement; + + if (CurrentToken.TokenType<>ltkCATCH) and (CurrentToken.TokenType<>ltkFINALLY) then begin + AddError('catch or finally expected after try'); + end; + + if CurrentToken.TokenType=ltkCATCH then begin + SkipToken(ltkCATCH); + SkipToken(ltoOPENPAREN); + result.CatchIdentifier:=ParseIdentifier(not TBESEN(Instance).IsStrict); + SkipToken(ltoCLOSEPAREN); + result.CatchBlock:=ParseBlockStatement; + end; + + if CurrentToken.TokenType=ltkFINALLY then begin + SkipToken(ltkFINALLY); + result.FinallyBlock:=ParseBlockStatement; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseSwitchStatement:TBESENASTNodeSwitchStatement; + var CaseStatements:integer; + CaseStatement:TBESENASTNodeCaseStatement; + DefaultSeen:boolean; + LabelSet:TBESENParserLabelSet; + begin + result:=nil; + try + result:=TBESENASTNodeSwitchStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkSWITCH); + + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + LabelEnter('',result); + + result.Target:=LabelSet.Target; + + DefaultSeen:=false; + + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + + CaseStatements:=0; + SkipToken(ltoOPENBRACE); + while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin + if CaseStatements>=length(result.CaseStatements) then begin + SetLength(result.CaseStatements,CaseStatements+256); + end; + result.CaseStatements[CaseStatements]:=TBESENASTNodeCaseStatement.Create(Instance); + result.CaseStatements[CaseStatements].Location.LineNumber:=Lexer.LineNumber; + CaseStatement:=result.CaseStatements[CaseStatements]; + inc(CaseStatements); + + CaseStatement.Expression:=nil; + + if CurrentToken.TokenType=ltkCASE then begin + SkipToken(ltkCASE); + CaseStatement.Expression:=ParseExpression(true); + SkipToken(ltoCOLON); + end else begin + if DefaultSeen then begin + AddError('duplication default clause in switch statement'); + end else begin + DefaultSeen:=true; + SkipToken(ltkDEFAULT); + SkipToken(ltoCOLON); + end; + end; + + CaseStatement.Statements:=ParseStatementList(true); + end; + SetLength(result.CaseStatements,CaseStatements); + + SkipToken(ltoCLOSEBRACE); + LabelLeave; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseVariableStatement:TBESENASTNodeVariableStatement; + var Count:integer; + begin + result:=nil; + try + result:=TBESENASTNodeVariableStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkVAR); + + result.Declarations:=niL; + Count:=1; + SetLength(result.Declarations,Count); + result.Declarations[0]:=ParseVariableDeclaration(true); + while (CurrentToken.TokenType=ltoCOMMA) and not Lexer.IsEOF do begin + SkipToken(ltoCOMMA); + if Count>=length(result.Declarations) then begin + SetLength(result.Declarations,Count+256); + end; + result.Declarations[Count]:=ParseVariableDeclaration(true); + inc(Count); + end; + SetLength(result.Declarations,Count); + + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseWhileStatement:TBESENASTNodeWhileStatement; + var LabelSet:TBESENParserLabelSet; + begin + result:=nil; + try + result:=TBESENASTNodeWhileStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + LabelEnter('',result); + result.Target:=LabelSet.Target; + SkipToken(ltkWHILE); + + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + + result.Statement:=ParseStatement(true); + LabelLeave; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseWithStatement:TBESENASTNodeWithStatement; + begin + result:=nil; + try + if TBESEN(Instance).IsStrict then begin + AddError('WITH isn''t allowed in strict mode'); + end; + result:=TBESENASTNodeWithStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkWITH); + + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + + result.Statement:=ParseStatement(true); + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseExpressionStatement:TBESENASTNodeStatement; + var Expression:TBESENASTNodeExpression; + LabelSet,OldLabelSet:TBESENParserLabelSet; + ln,LabelCount:integer; + OldToken:TBESENLexerToken; + begin + ln:=Lexer.LineNumber; + result:=nil; + Expression:=nil; + try + Expression:=ParseExpression(true); + if (Expression is TBESENASTNodeIdentifier) and (CurrentToken.TokenType=ltoCOLON) then begin + SkipToken(ltoCOLON); + + result:=TBESENASTNodeLabelledStatement.Create(Instance); + result.Location.LineNumber:=ln; + + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,1); + TBESENASTNodeLabelledStatement(result).Identifiers[0]:=TBESENASTNodeIdentifier(Expression); + + Expression:=nil; + + OldLabelSet:=CurrentLabelSet; + CurrentLabelSet:=nil; + + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + + LabelCount:=1; + LabelEnter(TBESENASTNodeLabelledStatement(result).Identifiers[0].Name,result); + while true do begin + OldToken:=CurrentToken; + if CurrentToken.TokenType=lttIDENTIFIER then begin + Expression:=ParseIdentifier(true); + if assigned(Expression) and (Expression is TBESENASTNodeIdentifier) and (CurrentToken.TokenType=ltoCOLON) then begin + SkipToken(ltoCOLON); + if LabelCount>=length(TBESENASTNodeLabelledStatement(result).Identifiers) then begin + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,LabelCount+256); + end; + TBESENASTNodeLabelledStatement(result).Identifiers[LabelCount]:=TBESENASTNodeIdentifier(Expression); + LabelEnter(TBESENASTNodeLabelledStatement(result).Identifiers[LabelCount].Name,result); + inc(LabelCount); + end else begin + if assigned(Expression) then begin + BESENFreeAndNil(Expression); + end; + Lexer.Restore(OldToken); + NextToken; + break; + end; + end else begin + break; + end; + end; + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,LabelCount); + + TBESENASTNodeLabelledStatement(result).Target:=LabelSet.Target; + TBESENASTNodeLabelledStatement(result).Statement:=ParseStatement(not (CurrentToken.TokenType in [ltkFOR,ltkWHILE,ltkDO])); + + while LabelCount>0 do begin + dec(LabelCount); + LabelLeave; + end; + + if assigned(CurrentLabelSet) then begin + LabelSetList[CurrentLabelSet.Index]:=nil; + BESENFreeAndNil(CurrentLabelSet); + end; + CurrentLabelSet:=OldLabelSet; + + end else begin + ParseOptionalSemicolon; + result:=TBESENASTNodeExpressionStatement.Create(Instance); + result.Location.LineNumber:=ln; + TBESENASTNodeExpressionStatement(result).Expression:=Expression; + Expression:=nil; + end; + except + BESENFreeAndNil(result); + BESENFreeAndNil(Expression); + raise; + end; + end; + function ParseFunctionStatement:TBESENASTNodeStatement; + var Expression:TBESENASTNodeAssignmentExpression; + begin + result:=nil; + try + result:=TBESENASTNodeExpressionStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + TBESENASTNodeExpressionStatement(result).Expression:=TBESENASTNodeAssignmentExpression.Create(Instance); + Expression:=TBESENASTNodeAssignmentExpression(TBESENASTNodeExpressionStatement(result).Expression); + Expression.LeftExpression:=ParseIdentifier(not TBESEN(Instance).IsStrict); + Expression.RightExpression:=ParseFunctionExpression(false,false); + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseStatement(ResetCurrentLabelSet:boolean):TBESENASTNodeStatement; + var LineNumber:integer; + OldToken:TBESENLexerToken; + begin + result:=nil; + try + if ResetCurrentLabelSet then begin + CurrentLabelSet:=nil; + end; + LineNumber:=CurrentToken.LineNumber; + case CurrentToken.TokenType of + ltoSEMICOLON:begin + SkipToken(ltoSEMICOLON); + result:=TBESENASTNodeEmptyStatement.Create(Instance); + end; + ltoOPENBRACE:begin + result:=ParseBlockStatement; + end; + ltkDEBUGGER:begin + result:=ParseDebuggerStatement; + end; + ltkBREAK:begin + result:=ParseBreakStatement; + end; + ltkCONTINUE:begin + result:=ParseContinueStatement; + end; + ltkDO:begin + result:=ParseDoStatement; + end; + ltkFOR:begin + result:=ParseForStatement; + end; + ltkIF:begin + result:=ParseIfStatement; + end; + ltkRETURN:begin + result:=ParseReturnStatement; + end; + ltkTHROW:begin + result:=ParseThrowStatement; + end; + ltkTRY:begin + result:=ParseTryStatement; + end; + ltkSWITCH:begin + result:=ParseSwitchStatement; + end; + ltkVAR:begin + result:=ParseVariableStatement; + end; + ltkWHILE:begin + result:=ParseWhileStatement; + end; + ltkWITH:begin + result:=ParseWithStatement; + end; + else begin + if CurrentToken.TokenType=ltkFUNCTION then begin + OldToken:=CurrentToken; + SkipToken(ltkFUNCTION); + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + if CurrentToken.TokenType<>ltoOPENPAREN then begin + result:=ParseFunctionStatement; + end else begin + Lexer.Restore(OldToken); + NextToken; + result:=ParseExpressionStatement; + end; + end else begin + AddError('function keyword not allowed here'); + result:=nil; + end; + end else begin + result:=ParseExpressionStatement; + end; + end; + end; + if assigned(result) then begin + result.Location.LineNumber:=LineNumber; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseSourceElement:TBESENASTNodeStatement; + begin + result:=nil; + try + if CurrentToken.TokenType=ltkFUNCTION then begin + result:=ParseFunctionDeclaration; + end else begin + result:=ParseStatement(true); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + procedure CheckJSON(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); + var Position:integer; + CurrentChar:TBESENUTF32CHAR; + CharEOF:boolean; + procedure NextChar; +{$ifdef BESENSingleStringType} + var Len:integer; +{$else} + var b:byte; +{$endif} + begin + if (Position>=1) and (Position<=length(Source)) then begin +{$ifdef BESENSingleStringType} +{$ifdef BESENEmbarcaderoNextGen} + CurrentChar:=Char.ConvertToUTF32(s,Position-1,Len); + inc(Position,Len); +{$else} + CurrentChar:=ord(Source[Position]); + inc(Position); + if (Position<=length(Source)) and ((SizeOf(Source[Position])=SizeOf(word)) and (((CurrentChar and $fc00)=$d800) and ((ord(Source[Position]) and $fc00)=$dc00))) then begin + // UTF16 + CurrentChar:=(((CurrentChar and $3ff) shl 10) or (ord(Source[Position]) and $3ff))+$10000; + inc(Position); + end; +{$endif} +{$else} + b:=byte(Source[Position]); + if (b and $80)=0 then begin + CurrentChar:=b; + inc(Position); + end else if ((Position+1)<=length(Source)) and ((b and $e0)=$c0) and ((byte(Source[Position+1]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $1f) shl 6) or (byte(Source[Position+1]) and $3f); + inc(Position,2); + end else if ((Position+2)<=length(Source)) and ((b and $f0)=$e0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $0f) shl 12) or ((byte(Source[Position+1]) and $3f) shl 6) or (byte(Source[Position+2]) and $3f); + inc(Position,3); + end else if ((Position+3)<=length(Source)) and ((b and $f8)=$f0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $07) shl 18) or ((byte(Source[Position+1]) and $3f) shl 12) or ((byte(Source[Position+2]) and $3f) shl 6) or (byte(Source[Position+3]) and $3f); + inc(Position,4); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+4)<=length(Source)) and ((b and $fc)=$f8) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $03) shl 24) or ((byte(Source[Position+1]) and $3f) shl 18) or ((byte(Source[Position+2]) and $3f) shl 12) or ((byte(Source[Position+3]) and $3f) shl 6) or (byte(Source[Position+4]) and $3f); + inc(Position,5); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+5)<=length(Source)) and ((b and $fe)=$fc) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) and ((byte(Source[Position+5]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $01) shl 30) or ((byte(Source[Position+1]) and $3f) shl 24) or ((byte(Source[Position+2]) and $3f) shl 18) or ((byte(Source[Position+3]) and $3f) shl 12) or ((byte(Source[Position+4]) and $3f) shl 6) or (byte(Source[Position+5]) and $3f); + inc(Position,6); + end else begin + CurrentChar:=$fffd; + inc(Position); + end; +{$endif} + end else begin + CurrentChar:=0; + CharEOF:=true; + end; + end; + procedure JSONError; + begin + raise EBESENSyntaxError.Create('JSON.parse'); + end; + procedure SkipWhite; + begin + while (not CharEOF) and ((CurrentChar=$0009) or (CurrentChar=$000a) or (CurrentChar=$000d) or (CurrentChar=$0020)) do begin + NextChar; + end; + end; + function IsChar(c:widechar):boolean; + begin + result:=(not CharEOF) and (CurrentChar=word(c)); + end; + procedure ExpectChar(c:widechar); + begin + if IsChar(c) then begin + NextChar; + end else begin + JSONError; + end; + end; + procedure CheckValue; + procedure CheckString; + begin + if IsChar('"') then begin + NextChar; + while not (CharEOF or IsChar('"')) do begin + case CurrentChar of + $0000..$001f:begin + JSONError; + end; + ord('\'):begin + NextChar; + case CurrentChar of + ord('"'),ord('\'),ord('/'),ord('b'),ord('f'),ord('n'),ord('r'),ord('t'):begin + NextChar; + end; + ord('u'):begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + end else begin + JSONError; + end; + end else begin + JSONError; + end; + end else begin + JSONError; + end; + end else begin + JSONError; + end; + end; + else begin + JSONError; + end; + end; + end; + else begin + NextChar; + end; + end; + end; + ExpectChar('"'); + end else begin + JSONError; + end; + SkipWhite; + end; + procedure CheckNumber; + begin + if CharEOF then begin + JSONError; + end; + case CurrentChar of + ord('-'),ord('0')..ord('9'):begin + if IsChar('-') then begin + NextChar; + if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + end; + if (not CharEOF) and (CurrentChar=ord('0')) then begin + NextChar; + if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + end else begin + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + NextChar; + end; + end; + if IsChar('.') then begin + NextChar; + if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + NextChar; + end; + end; + if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin + NextChar; + if (not CharEOF) and ((CurrentChar=ord('-')) or (CurrentChar=ord('+'))) then begin + NextChar; + end; + if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + NextChar; + end; + end; + end else begin + JSONError; + end; + end; + end; + procedure CheckObjectProperty; + begin + CheckString; + SkipWhite; + ExpectChar(':'); + SkipWhite; + CheckValue; + end; + procedure CheckObject; + begin + ExpectChar('{'); + SkipWhite; + while not (CharEOF or IsChar('}')) do begin + CheckObjectProperty; + SkipWhite; + if IsChar(',') then begin + NextChar; + SkipWhite; + if (not CharEOF) and IsChar('}') then begin + JSONError; + end; + end; + end; + ExpectChar('}'); + end; + procedure CheckArray; + begin + ExpectChar('['); + SkipWhite; + while not (CharEOF or IsChar(']')) do begin + CheckValue; + SkipWhite; + if IsChar(',') then begin + NextChar; + SkipWhite; + if (not CharEOF) and IsChar(']') then begin + JSONError; + end; + end; + end; + ExpectChar(']'); + end; + procedure CheckKeyword(const Keyword:TBESENString); + var i:integer; + begin + for i:=1 to length(Keyword) do begin + ExpectChar(Keyword[i]); + end; + end; + begin + SkipWhite; + if CharEOF then begin + JSONError; + end; + case CurrentChar of + ord('{'):begin + CheckObject; + end; + ord('['):begin + CheckArray; + end; + ord('"'):begin + CheckString; + end; + ord('-'),ord('0')..ord('9'):begin + CheckNumber; + end; + ord('t'):begin + CheckKeyword('true'); + end; + ord('f'):begin + CheckKeyword('false'); + end; + ord('n'):begin + CheckKeyword('null'); + end; + else begin + JSONError; + end; + end; + end; + begin + CharEOF:=false; + Position:=1; + NextChar; + CheckValue; + SkipWhite; + if not CharEOF then begin + JSONError; + end; + end; +var Statement:TBESENASTNodeStatement; + OldIsStrict:boolean; + OldToken:TBesenLexerToken; + procedure ParseJSONStatements; + var i:integer; + begin + try + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + if not Lexer.IsEOF then begin + Statement:=ParseExpressionStatement; + if assigned(Statement) then begin + SetLength(TBESENASTNodeProgram(result).Body.Statements,1); + TBESENASTNodeProgram(result).Body.Statements[0]:=Statement; + end else begin + AddError('Fatal error'); + end; + end; + except + for i:=0 to length(TBESENASTNodeProgram(result).Body.Statements)-1 do begin + BesenFreeAndNil(TBESENASTNodeProgram(result).Body.Statements[i]); + end; + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + raise; + end; + end; + procedure ParseProgramStatements; + var IsDirectivePrologue,FirstDirective:boolean; + Statements,i:integer; + begin + Statements:=0; + try + IsDirectivePrologue:=true; + FirstDirective:=true; + UseStrictAlreadyParsed:=false; + while not Lexer.IsEOF do begin + if IsDirectivePrologue then begin + ParseDirective(IsDirectivePrologue,FirstDirective,TBESENASTNodeProgram(result).Body); + end; + Statement:=ParseSourceElement; + if assigned(Statement) then begin + if Statements>=length(TBESENASTNodeProgram(result).Body.Statements) then begin + SetLength(TBESENASTNodeProgram(result).Body.Statements,Statements+256); + end; + TBESENASTNodeProgram(result).Body.Statements[Statements]:=Statement; + inc(Statements); + end else begin + AddError('Fatal error'); + break; + end; + end; + SetLength(TBESENASTNodeProgram(result).Body.Statements,Statements); + except + for i:=0 to Statements-1 do begin + BesenFreeAndNil(TBESENASTNodeProgram(result).Body.Statements[i]); + end; + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + Statements:=0; + raise; + end; + end; +begin + Labels:=nil; + LabelSets:=nil; + CurrentLabelSet:=nil; + LabelSetList:=TBESENPointerList.Create; + LabelList:=TBESENPointerList.Create; + OldIsStrict:=TBESEN(Instance).IsStrict; + try + NextToken; + InForHeader:=false; + if IsFunction then begin + IsInFunction:=true; + try + result:=ParseFunctionExpression(true,false); + except + result:=nil; + raise; + end; + end else if IsJSON then begin + IsInFunction:=false; + result:=TBESENASTNodeProgram.Create(Instance); + try + CheckJSON(Lexer.Source); + TBESEN(Instance).IsStrict:=false; + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + ParseJSONStatements; + except + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + raise; + end; + end else begin + IsInFunction:=false; + result:=TBESENASTNodeProgram.Create(Instance); + try + OldToken:=CurrentToken; + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + try + ParseProgramStatements; + except + on e:EBESENUseStrict do begin + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + Lexer.Restore(OldToken); + NextToken; + ParseProgramStatements; + end; + end; + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + except + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + raise; + end; + end; + finally + CurrentToken.Name:=''; + CurrentToken.StringValue:=''; + CleanUpLabels; + TBESEN(Instance).IsStrict:=OldIsStrict; + BESENFreeAndNil(LabelSetList); + BESENFreeAndNil(LabelList); + end; +end; + +end. diff --git a/3rd/besen/src/BESENPointerList.pas b/3rd/besen/src/BESENPointerList.pas new file mode 100644 index 000000000..8c8fa2240 --- /dev/null +++ b/3rd/besen/src/BESENPointerList.pas @@ -0,0 +1,230 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENPointerList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENPointerArray=^TBESENPointerArray; + TBESENPointerArray=array[0..(2147483647 div sizeof(pointer))-1] of pointer; + + TBESENPointerList=class + private + FList:PBESENPointerArray; + FCount,FSize:integer; + function GetItem(index:integer):pointer; + procedure SetItem(index:integer;Value:pointer); + function GetItemPointer(index:integer):pointer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:pointer):integer; + procedure Insert(index:integer;Item:pointer); + procedure Delete(index:integer); + function Remove(Item:pointer):integer; + function Find(Item:pointer):integer; + function IndexOf(Item:pointer):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:pointer read GetItem write SetItem; default; + property Items[index:integer]:pointer read GetItem write SetItem; + property PItems[index:integer]:pointer read GetItemPointer; + end; + +implementation + +constructor TBESENPointerList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENPointerList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENPointerList.Clear; +begin + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENPointerList.SetCapacity(NewCapacity:integer); +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENPointerArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + ReallocMem(FList,NewCapacity*sizeof(pointer)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(pointer),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENPointerList.SetCount(NewCount:integer); +begin + if (NewCount>=0) and (NewCount<high(TBESENPointerArray)) then begin + if NewCount<FCount then begin + FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(pointer),#0); + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENPointerList.Add(Item:pointer):integer; +begin + result:=FCount; + SetCount(result+1); + FList^[result]:=Item; +end; + +procedure TBESENPointerList.Insert(index:integer;Item:pointer); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENPointerList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENPointerList.Remove(Item:pointer):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENPointerList.Find(Item:pointer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENPointerList.IndexOf(Item:pointer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENPointerList.Exchange(Index1,Index2:integer); +var TempPointer:pointer; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempPointer:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempPointer; + end; +end; + +function TBESENPointerList.GetItem(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=nil; + end; +end; + +procedure TBESENPointerList.SetItem(index:integer;Value:pointer); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +function TBESENPointerList.GetItemPointer(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=@FList^[index]; + end else begin + result:=nil; + end; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENPointerSelfBalancedTree.pas b/3rd/besen/src/BESENPointerSelfBalancedTree.pas new file mode 100644 index 000000000..322e2b38d --- /dev/null +++ b/3rd/besen/src/BESENPointerSelfBalancedTree.pas @@ -0,0 +1,630 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENPointerSelfBalancedTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENPointerSelfBalancedTreeValue=^TBESENPointerSelfBalancedTreeValue; + TBESENPointerSelfBalancedTreeValue=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENPointerSelfBalancedTreeNode=^TBESENPointerSelfBalancedTreeNode; + TBESENPointerSelfBalancedTreeNode=record + Parent,Left,Right,PreviousKey,NextKey:PBESENPointerSelfBalancedTreeNode; + Level:int64; + Key:pointer; + Value:TBESENPointerSelfBalancedTreeValue; + end; + + TBESENPointerSelfBalancedTreeKeys=array of pointer; + + TBESENPointerSelfBalancedTree=class + protected + procedure Skew(OldParent:PBESENPointerSelfBalancedTreeNode); + function Split(OldParent:PBESENPointerSelfBalancedTreeNode):boolean; + procedure RebalanceAfterLeafAdd(n:PBESENPointerSelfBalancedTreeNode); + procedure DeleteNode(n:PBESENPointerSelfBalancedTreeNode); + function First(StartNode:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; + function Next(n:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; + function FindNode(const Key:pointer):PBESENPointerSelfBalancedTreeNode; + procedure ClearNode(var Node:PBESENPointerSelfBalancedTreeNode); + procedure OptimizeNode(var Node:PBESENPointerSelfBalancedTreeNode;MoreOptimize:boolean); + function GetValue(Key:pointer):TBESENPointerSelfBalancedTreeValue; + procedure SetValue(Key:pointer;Value:TBESENPointerSelfBalancedTreeValue); + public + RootNode:PBESENPointerSelfBalancedTreeNode; + FirstKey,LastKey:PBESENPointerSelfBalancedTreeNode; + constructor Create; + destructor Destroy; override; + function Find(const Key:pointer;var Value:TBESENPointerSelfBalancedTreeValue):boolean; + function Insert(const Key:pointer;Value:TBESENPointerSelfBalancedTreeValue):PBESENPointerSelfBalancedTreeNode; + procedure Remove(const Key:pointer); + procedure Optimize; + function Keys:TBESENPointerSelfBalancedTreeKeys; + property Values[Key:pointer]:TBESENPointerSelfBalancedTreeValue read GetValue write SetValue; default; + end; + +implementation + +constructor TBESENPointerSelfBalancedTree.Create; +begin + inherited Create; + new(RootNode); + fillchar(RootNode^,sizeof(TBESENPointerSelfBalancedTreeNode),#0); + RootNode^.Level:=$7fffffffffffffff; + FirstKey:=nil; + LastKey:=nil; +end; + +destructor TBESENPointerSelfBalancedTree.Destroy; +begin + ClearNode(RootNode^.Left); + dispose(RootNode); + inherited Destroy; +end; + +function TBESENPointerSelfBalancedTree.First(StartNode:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; +begin + try + if not assigned(StartNode^.Left) then begin + result:=nil; + exit; + end; + result:=StartNode; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + except + result:=nil; + end; +end; + +function TBESENPointerSelfBalancedTree.Next(n:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; +begin + try + if assigned(n^.Right) then begin + result:=n^.Right; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + end else begin + while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin + n:=n^.Parent; + end; + n:=n^.Parent; + if not assigned(n) then begin + result:=nil; + exit; + end; + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENPointerSelfBalancedTree.Skew(OldParent:PBESENPointerSelfBalancedTreeNode); +var NewParent:PBESENPointerSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Left; +{$ifdef UseAssert} + Assert(assigned(NewParent)); +{$endif} + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Left:=NewParent^.Right; + if assigned(OldParent^.Left) then begin + OldParent^.Left^.Parent:=OldParent; + end; + NewParent^.Right:=OldParent; + + if assigned(OldParent^.Left) then begin + OldParent^.level:=OldParent^.Left^.level+1; + end else begin + OldParent^.level:=1; + end; +end; + +function TBESENPointerSelfBalancedTree.Split(OldParent:PBESENPointerSelfBalancedTreeNode):boolean; +var NewParent:PBESENPointerSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Right; + if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Right:=NewParent^.Left; + if assigned(OldParent^.Right) then begin + OldParent^.Right^.Parent:=OldParent; + end; + NewParent^.Left:=OldParent; + + NewParent^.level:=OldParent^.level+1; + + result:=true; + end else begin + result:=false; + end; +end; + +procedure TBESENPointerSelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENPointerSelfBalancedTreeNode); +begin + // n is a node that has just been inserted and is now a Leaf node. + n^.Level:=1; + n^.Left:=nil; + n^.Right:=nil; + n:=n^.Parent; + while n<>RootNode do begin + if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin + // this point the tree is correct, except (AA2) for n->Parent + Skew(n); + // We handle it (a Left add) by changing it into a Right add using Skew + // If the original add was to the Left side of a node that is on the + // Right side of a horizontal link, n now points to the rights side + // of the second horizontal link, which is correct. + // However if the original add was to the Left of node with a horizontal + // link, we must get to the Right side of the second link. + if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin + n:=n^.Parent; + end; + end; + if not Split(n^.Parent) then begin + break; + end; + n:=n^.Parent; + end; +end; + +function TBESENPointerSelfBalancedTree.FindNode(const Key:pointer):PBESENPointerSelfBalancedTreeNode; +var n:PBESENPointerSelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + result:=n; + break; + end else if ptruint(Key)<ptruint(n^.Key) then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + result:=nil; + end; +end; + +function TBESENPointerSelfBalancedTree.Insert(const Key:pointer;Value:TBESENPointerSelfBalancedTreeValue):PBESENPointerSelfBalancedTreeNode; +var n,s:PBESENPointerSelfBalancedTreeNode; + LessThan:boolean; +begin + result:=nil; + try + n:=nil; + s:=RootNode^.Left; + while assigned(s) do begin + if Key=s^.Key then begin + n:=s; + break; + end else if ptruint(Key)<ptruint(s^.Key) then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + end; + if assigned(s) then begin + n^.Value:=Value; + end else begin + new(n); + fillchar(n^,sizeof(TBESENPointerSelfBalancedTreeNode),#0); + n^.Key:=Key; + n^.Value:=Value; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=ptruint(Key)<ptruint(s^.Key); + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + RebalanceAfterLeafAdd(n); + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENPointerSelfBalancedTree.DeleteNode(n:PBESENPointerSelfBalancedTreeNode); +var Leaf,Temp:PBESENPointerSelfBalancedTreeNode; +begin + try + // If n is not a Leaf, we first swap it out with the Leaf node that just + // precedes it. + Leaf:=n; + if assigned(n^.Left) then begin + Leaf:=n^.Left; + while assigned(Leaf^.Right) do begin + Leaf:=Leaf^.Right; + end; + end else if assigned(n^.Right) then begin + Leaf:=n^.Right; + end; + + if Leaf^.Parent=n then begin + Temp:=Leaf; + end else begin + Temp:=Leaf^.Parent; + end; + if Leaf^.Parent^.Left=Leaf then begin + Leaf^.Parent^.Left:=nil; + end else begin + Leaf^.Parent^.Right:=nil; + end; + + if n<>Leaf then begin + if n^.Parent^.Left=n then begin + n^.Parent^.Left:=Leaf; + end else begin + n^.Parent^.Right:=Leaf; + end; + Leaf^.Parent:=n^.Parent; + if assigned(n^.Left) then begin + n^.Left^.Parent:=Leaf; + end; + Leaf^.Left:=n^.Left; + if assigned(n^.Right) then begin + n^.Right^.Parent:=Leaf; + end; + Leaf^.Right:=n^.Right; + Leaf^.level:=n^.level; + end; + if n<>RootNode then begin + n^.Key:=nil; + if assigned(n^.PreviousKey) then begin + n^.PreviousKey^.NextKey:=n^.NextKey; + end else if FirstKey=n then begin + FirstKey:=n^.NextKey; + end; + if assigned(n^.NextKey) then begin + n^.NextKey^.PreviousKey:=n^.PreviousKey; + end else if LastKey=n then begin + LastKey:=n^.PreviousKey; + end; + dispose(n); + end; + + while Temp<>RootNode do begin + if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin + dec(Temp^.level); + if Split(Temp) then begin + if Split(Temp) then begin + Skew(Temp^.Parent^.Parent); + end; + break; + end; + Temp:=Temp^.Parent; + end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin + break; + end else begin + Skew(Temp); + { if assigned(Temp^.Right) then begin + if assigned(Temp^.Right^.Left) then begin + Temp^.Right^.level:=Temp^.Right^.level+1; + end else begin + Temp^.Right^.level:=1; + end; + end;} + if Temp^.level>Temp^.Parent^.level then begin + Skew(Temp); + Split(Temp^.Parent^.Parent); + break; + end; + Temp:=Temp^.Parent^.Parent; + end; + end; + except + end; +end; + +procedure TBESENPointerSelfBalancedTree.Remove(const Key:pointer); +var n:PBESENPointerSelfBalancedTreeNode; +begin + try + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + DeleteNode(n); + break; + end else if ptruint(Key)<ptruint(n^.Key) then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + end; +end; + +procedure TBESENPointerSelfBalancedTree.ClearNode(var Node:PBESENPointerSelfBalancedTreeNode); +begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=nil; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end else if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end else if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + ClearNode(Node^.Left); + ClearNode(Node^.Right); + dispose(Node); + Node:=nil; +end; + +procedure TBESENPointerSelfBalancedTree.OptimizeNode(var Node:PBESENPointerSelfBalancedTreeNode;MoreOptimize:boolean); +var Nodes:array of TBESENPointerSelfBalancedTreeNode; + NodeCount,NodeIndex:integer; + procedure CountNodes(Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + inc(NodeCount); + end; + procedure CollectNodes(Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CollectNodes(Node^.Left); + if NodeIndex>=length(Nodes) then begin + NodeCount:=NodeIndex+1; + SetLength(Nodes,NodeCount); + end; + Nodes[NodeIndex]:=Node^; + inc(NodeIndex); + CollectNodes(Node^.Right); + end; + procedure FreeNodes(var Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=nil; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end; + if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + dispose(Node); + Node:=nil; + end; + procedure DoInsertNode(const Node:TBESENPointerSelfBalancedTreeNode); + var n,s:PBESENPointerSelfBalancedTreeNode; + LessThan:boolean; + begin + new(n); + n^:=Node; + n^.Parent:=nil; + n^.Left:=nil; + n^.Right:=nil; + n^.Level:=0; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=ptruint(n^.Key)<ptruint(s^.Key); + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + if not MoreOptimize then begin + RebalanceAfterLeafAdd(n); + end; + end; + procedure RepairNodes(var Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + RepairNodes(Node^.Left); + RepairNodes(Node^.Right); + if assigned(Node^.Left) and assigned(Node^.Right) then begin + Node^.Level:=Node^.Left^.Level+1; + end else begin + Node^.Level:=1; + end; + end; + procedure ReinsertNodesForRepair(LowNode,HighNode:integer); + var MiddleNode:integer; + begin + if HighNode<LowNode then begin + exit; + end; + MiddleNode:=LowNode+((HighNode-LowNode) div 2); + DoInsertNode(Nodes[MiddleNode]); + ReinsertNodesForRepair(LowNode,MiddleNode-1); + ReinsertNodesForRepair(MiddleNode+1,HighNode); + end; + procedure ReinsertNodes(LowNode,HighNode:integer); + var i:integer; + begin + for i:=LowNode to HighNode do begin + DoInsertNode(Nodes[i]); + end; + end; +begin + if not assigned(Node) then begin + exit; + end; + try + Nodes:=nil; + NodeCount:=0; + CountNodes(Node); + SetLength(Nodes,NodeCount); + NodeIndex:=0; + CollectNodes(Node); + FreeNodes(Node); + if MoreOptimize then begin + ReinsertNodesForRepair(0,length(Nodes)-1); + RepairNodes(RootNode^.Left); + end else begin + ReinsertNodes(0,length(Nodes)-1); + end; + SetLength(Nodes,0); + except + end; +end; + +function TBESENPointerSelfBalancedTree.Find(const Key:pointer;var Value:TBESENPointerSelfBalancedTreeValue):boolean; +var n:PBESENPointerSelfBalancedTreeNode; +begin + n:=FindNode(Key); + if assigned(n) then begin + Value:=n^.Value; + result:=true; + end else begin + fillchar(Value,sizeof(TBESENPointerSelfBalancedTreeValue),#0); + result:=false; + end; +end; + +procedure TBESENPointerSelfBalancedTree.Optimize; +begin + OptimizeNode(RootNode^.Left,true); +end; + +function TBESENPointerSelfBalancedTree.Keys:TBESENPointerSelfBalancedTreeKeys; +var CurrentNode:PBESENPointerSelfBalancedTreeNode; + Count:integer; +begin + result:=nil; + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; + SetLength(result,Count); + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + result[Count]:=CurrentNode^.Key; + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; +end; + +function TBESENPointerSelfBalancedTree.GetValue(Key:pointer):TBESENPointerSelfBalancedTreeValue; +begin + Find(Key,result); +end; + +procedure TBESENPointerSelfBalancedTree.SetValue(Key:pointer;Value:TBESENPointerSelfBalancedTreeValue); +begin + Insert(Key,Value); +end; + +end. diff --git a/3rd/besen/src/BESENRandomGenerator.pas b/3rd/besen/src/BESENRandomGenerator.pas new file mode 100644 index 000000000..d4979eaaf --- /dev/null +++ b/3rd/besen/src/BESENRandomGenerator.pas @@ -0,0 +1,274 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENRandomGenerator; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,Math,BESENConstants,BESENTypes, + BESENObject,BESENValue,BESENCollectorObject; + +type TBESENRandomGeneratorTable=array[0..BESEN_CMWCRND_SIZE-1] of longword; + + TBESENRandomGenerator=class(TBESENCollectorObject) + public + Table:TBESENRandomGeneratorTable; + Position:longword; + Carry:longword; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Reinitialize; + function Get:longword; + function GetNumber:TBESENNumber; + end; + +implementation + +uses BESEN; + +constructor TBESENRandomGenerator.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Reinitialize; +end; + +destructor TBESENRandomGenerator.Destroy; +begin + inherited Destroy; +end; + +{$ifdef win32} +type HCRYPTPROV=DWORD; + +const PROV_RSA_FULL=1; + CRYPT_VERIFYCONTEXT=$F0000000; + +function CryptAcquireContext(var phProv:HCRYPTPROV;pszContainer:PAnsiChar;pszProvider:PAnsiChar;dwProvType:DWORD; dwFlags:DWORD):BOOL; stdcall; external advapi32 name 'CryptAcquireContextA'; +function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL; stdcall; external advapi32 name 'CryptReleaseContext'; +function CryptGenRandom(hProv: HCRYPTPROV; dwLen: DWORD; pbBuffer: Pointer): BOOL; stdcall; external advapi32 name 'CryptGenRandom'; + +function CoCreateGuid(var guid: TGUID): HResult; stdcall; external 'ole32.dll'; +{$endif} + +procedure TBESENRandomGenerator.Reinitialize; +const N=25; + m=7; + s=7; + t=15; + a=longword($8ebfd028); + b=longword($2b5b2500); + c=longword($db8b0000); +var LRG,LFSR,k,y,Seed1,Seed2:longword; + i,j:integer; + x:array[0..N-1] of longword; + UnixTimeInMilliSeconds:int64; +{$ifdef unix} + f:file of longword; + ura,urb:longword; +{$else} +{$ifdef win32} + lpc,lpf:int64; + pp,p:pwidechar; + st:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; +{$endif} +{$endif} +{$ifdef win32} + function GenerateRandomBytes(var Buffer;Bytes:Cardinal):boolean; + var CryptProv:HCRYPTPROV; + begin + try + if not CryptAcquireContext(CryptProv,nil,nil,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT) then begin + result:=false; + exit; + end; + FillChar(Buffer,Bytes,#0); + result:=CryptGenRandom(CryptProv,Bytes,@Buffer); + CryptReleaseContext(CryptProv,0); + except + result:=false; + end; + end; + function GetRandomGUIDGarbage:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; + var g:TGUID; + begin + CoCreateGUID(g); + SetLength(result,sizeof(TGUID)); + move(g,result[1],sizeof(TGUID)); + end; +{$endif} +begin + UnixTimeInMilliSeconds:=round((SysUtils.Now-25569.0)*86400000.0); + Seed1:=longword(UnixTimeInMilliSeconds and $ffffffff)+longword(UnixTimeInMilliSeconds shr 32); + Seed2:=longword(UnixTimeInMilliSeconds shr 32) xor not longword(UnixTimeInMilliSeconds and $ffffffff); +{$ifdef unix} + ura:=0; + urb:=0; + AssignFile(f,'/dev/urandom'); + {$i-}System.reset(f,1);{$i+} + if ioresult=0 then begin + System.read(f,ura); + System.read(f,urb); + CloseFile(f); + end else begin + AssignFile(f,'/dev/random'); + {$i-}System.reset(f,1);{$i+} + if ioresult=0 then begin + System.read(f,ura); + System.read(f,urb); + CloseFile(f); + end; + end; + Seed1:=Seed1 xor ura; + Seed2:=Seed2 xor urb; +{$else} +{$ifdef win32} + QueryPerformanceCounter(lpc); + QueryPerformanceFrequency(lpf); + inc(Seed1,timeGetTime+GetCurrentProcessId); + dec(Seed2,GetTickCount-GetCurrentThreadId); + inc(Seed1,paramcount); + Seed1:=Seed1 xor (lpc shr 32); + Seed2:=Seed2 xor lpc; + Seed1:=(Seed1*lpc)+(Seed2*(lpf-Seed1)); + Seed2:=(Seed2*lpc)+(Seed1*(lpf-Seed2)); + pp:=GetEnvironmentStringsW; + if assigned(pp) then begin + p:=pp; + while assigned(p) and (p^<>#0) do begin + while assigned(p) and (p^<>#0) do begin + inc(Seed1,(Seed2*word(p^))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*word(p^)); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + inc(p); + end; + inc(p); + end; + FreeEnvironmentStringsW(pointer(pp)); + end; + pp:=pointer(GetCommandLineW); + if assigned(pp) then begin + p:=pp; + while assigned(p) and (p^<>#0) do begin + inc(Seed1,(Seed2*word(p^))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*word(p^)); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + inc(p); + end; + end; + SetLength(st,4096); + if GenerateRandomBytes(st[1],length(st)) then begin + for i:=1 to length(st) do begin + inc(Seed1,(Seed2*byte(st[i]))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*byte(st[i])); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + end; + end; + st:=GetRandomGUIDGarbage; + for i:=1 to length(st) do begin + inc(Seed1,(Seed2*byte(st[i]))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*byte(st[i])); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + end; + SetLength(st,0); +{$endif} +{$endif} + LRG:=not Seed1; + LFSR:=Seed2; + for i:=0 to N-1 do begin + LRG:=(LRG*1664525)+1013904223; + LFSR:=LFSR xor (LFSR shl 13); + LFSR:=LFSR xor (LFSR shr 17); + LFSR:=LFSR xor (LFSR shl 5); + x[i]:=LRG xor not LFSR; + end; + k:=N-1; + LRG:=Seed1; + LFSR:=not Seed2; + for i:=0 to BESEN_CMWCRND_MASK do begin + LRG:=(LRG*1664525)+1013904223; + LFSR:=LFSR xor (LFSR shl 13); + LFSR:=LFSR xor (LFSR shr 17); + LFSR:=LFSR xor (LFSR shl 5); + inc(k); + if k>=N then begin + for j:=0 to (N-m)-1 do begin + x[j]:=x[j+m] xor (x[j] shr 1) xor ((x[j] and 1)*a); + end; + for j:=(N-m) to N-1 do begin + x[j]:=x[j+m-N] xor (x[j] shr 1) xor ((x[j] and 1)*a); + end; + k:=0; + end; + y:=x[k] xor ((x[k] shl s) and b); + y:=y xor ((y shl t) and c); + Table[i]:=(LRG+LFSR) xor y; + end; + Position:=(x[LFSR and $f] xor Table[LRG and BESEN_CMWCRND_MASK]) and BESEN_CMWCRND_MASK; +end; + +function TBESENRandomGenerator.Get:longword; +var t:{$ifdef fpc}qword{$else}int64{$endif}; + x:longword; +begin + Position:=(Position+1) and BESEN_CMWCRND_MASK; + t:=(BESEN_CMWCRND_A*Table[Position])+Carry; + Carry:=t shr 32; + x:=t+Carry; + if x<Carry then begin + inc(x); + inc(Carry); + end; + result:=BESEN_CMWCRND_M-x; + Table[Position]:=result; +end; + +function TBESENRandomGenerator.GetNumber:TBESENNumber; +const f:TBESENNumber=1.0/int64($100000000); +var i:int64; +begin + i:=Get; + result:=i*f; +end; + +end. diff --git a/3rd/besen/src/BESENRegExp.pas b/3rd/besen/src/BESENRegExp.pas new file mode 100644 index 000000000..facbde819 --- /dev/null +++ b/3rd/besen/src/BESENRegExp.pas @@ -0,0 +1,2550 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENRegExp; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENCollectorObject; + +const breoFAIL=0; // match failed + breoSUCCEED=1; // match succeeded + breoCHAR=2; // match a char class instance + breoZERO=3; // reset counter + breoREACH=4; // test counter over + breoNREACH=5; // test counter under + breoSTART=6; // enter a group + breoEND=7; // exit a group + breoUNDEF=8; // reset a group + breoMARK=9; // record a position + breoFDIST=10; // position test + breoRDIST=11; // position and counter test + breoMNEXT=12; // max-loop + breoRNEXT=13; // reach-loop + breoGOTO=14; // Branch + breoGS=15; // greeedy success + breoNS=16; // non-greeedy success + breoGF=17; // greedy fail + breoNF=18; // non-greeedy fail + breoAS=19; // assert success + breoAF=20; // assert fail + breoBOL=21; // test begin of a line + breoEOL=22; // test end of a line + breoBRK=23; // test work-break + breoNBRK=24; // test non-work-break + breoBACKREF=25; // backreference match + + brecUNDEFINED=longword($ffffffff); + brecINFINITY=-1; + + bresADDR=2; + bresINT=2; + + breMAXSTATESHOLDINMEMORY:longint=16; + + BESENRegExpCacheSize:longint=256; + +type TBESENRegExpOpcode=byte; + + TBESENRegExpFlag=(brefGLOBAL,brefIGNORECASE,brefMULTILINE); + + TBESENRegExpFlags=set of TBESENRegExpFlag; + + TBESENRegExpCharClass=class; + + TBESENRegExpCharClassRange=class + public + CharClass:TBESENRegExpCharClass; + Previous,Next:TBESENRegExpCharClassRange; + Lo,Hi:TBESENUTF32CHAR; + constructor Create(ACharClass:TBESENRegExpCharClass;ALo,AHi:TBESENUTF32CHAR); + constructor CreateBefore(ACharClass:TBESENRegExpCharClass;ABefore:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); + constructor CreateAfter(ACharClass:TBESENRegExpCharClass;AAfter:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); + destructor Destroy; override; + end; + + TBESENRegExp=class; + + TBESENRegExpCharClass=class + public + RegExp:TBESENRegExp; + Previous,Next:TBESENRegExpCharClass; + First,Last:TBESENRegExpCharClassRange; + Inverted:longbool; + Canonicalized:longbool; + constructor Create(ARegExp:TBESENRegExp); + destructor Destroy; override; + procedure Clear; + procedure Dump; + procedure DebugDump; + procedure Optimize; + procedure AddRange(Lo,Hi:TBESENUTF32CHAR;IgnoreCase:boolean=false); + procedure AddChar(c:TBESENUTF32CHAR;IgnoreCase:boolean=false); + procedure TakeoverCombine(From:TBESENRegExpCharClass); + procedure Assign(From:TBESENRegExpCharClass); + procedure Append(From:TBESENRegExpCharClass); + procedure Invert; + procedure Canonicalize; + function Count:longword; + function Contains(c:TBESENUTF32CHAR):boolean; + function IsSingle:boolean; + end; + + TBESENRegExpCharClasses=array of TBESENRegExpCharClass; + + TBESENRegExpCapture=record + s,e:longword; + end; + + TBESENRegExpCaptures=array of TBESENRegExpCapture; + + TBESENRegExpValue=longint; + + TBESENRegExpValues=array of TBESENRegExpValue; + + TBESENRegExpState=class + public + RegExp:TBESENRegExp; + Previous,Next:TBESENRegExpState; + Captures:TBESENRegExpCaptures; + Counters:TBESENRegExpValues; + Marks:TBESENRegExpValues; + constructor Create(ARegExp:TBESENRegExp); + destructor Destroy; override; + end; + + TBESENRegExp=class(TBESENCollectorObject) + private + FirstCharClass,LastCharClass:TBESENRegExpCharClass; + FirstState,LastState,CurrentState:TBESENRegExpState; + CountStates:longint; + function InternCharClass(c:TBESENRegExpCharClass):longint; + function CodePos:longint; + procedure CodePosSet(p:longint); + procedure CodeAdd(c:longint); + procedure CodePatch(p,c:longint); + procedure CodeInsert(p,n:longint); + procedure CodeAddI(c:longint); + procedure CodeAddA(c:longint); + procedure CodePatchI(p,c:longint); + procedure CodePatchA(p,c:longint); + function AllocateState:TBESENRegExpState; + procedure CleanupStates; + procedure CopyState(const a,b:TBESENRegExpState); + function DisassembleOpcode(PC:longint):TBESENString; + procedure DebugDisassemble; + function Execute(PC:longint;const Input:TBESENString;var State:TBESENRegExpState;var RemainTimeOutSteps:int64):boolean; + public + Source:TBESENString; + ByteCode:TBESENBytes; + ByteCodeLen:longint; + Flags:TBESENRegExpFlags; + CountOfCaptures:longint; + CountOfCounters:longint; + CountOfMarks:longint; + MaxRef:longint; + CharClasses:TBESENRegExpCharClasses; + CharClassesCount:longint; + ReferenceCounter:longint; + constructor Create(AInstance:TObject); override; + destructor Destroy; override; + procedure IncRef; + procedure DecRef; + procedure Compile(const ASource:TBESENString;const AFlags:TBESENRegExpFlags=[]); + function Match(const Input:TBESENString;Index:longint;var Captures:TBESENRegExpCaptures):boolean; + function Disassemble:TBESENString; + procedure DebugDump; + end; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors; + +type TBESENUTF8ORSINGLESTRING={$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; + +constructor TBESENRegExpCharClassRange.Create(ACharClass:TBESENRegExpCharClass;ALo,AHi:TBESENUTF32CHAR); +begin + inherited Create; + CharClass:=ACharClass; + Lo:=ALo; + Hi:=AHi; + if assigned(CharClass.Last) then begin + Previous:=CharClass.Last; + CharClass.Last:=self; + Previous.Next:=self; + Next:=nil; + end else begin + CharClass.First:=self; + CharClass.Last:=self; + Previous:=nil; + Next:=nil; + end; +end; + +constructor TBESENRegExpCharClassRange.CreateBefore(ACharClass:TBESENRegExpCharClass;ABefore:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); +begin + inherited Create; + CharClass:=ACharClass; + Lo:=ALo; + Hi:=AHi; + Previous:=ABefore.Previous; + Next:=ABefore; + ABefore.Previous:=self; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + CharClass.First:=self; + end; +end; + +constructor TBESENRegExpCharClassRange.CreateAfter(ACharClass:TBESENRegExpCharClass;AAfter:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); +begin + inherited Create; + CharClass:=ACharClass; + Lo:=ALo; + Hi:=AHi; + Previous:=AAfter; + Next:=AAfter.Next; + AAfter.Next:=self; + if assigned(Next) then begin + Next.Previous:=self; + end else begin + CharClass.Last:=self; + end; +end; + +destructor TBESENRegExpCharClassRange.Destroy; +begin + if assigned(Previous) then begin + Previous.Next:=Next; + end else if CharClass.First=self then begin + CharClass.First:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if CharClass.Last=self then begin + CharClass.Last:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +constructor TBESENRegExpCharClass.Create(ARegExp:TBESENRegExp); +begin + inherited Create; + RegExp:=ARegExp; + if assigned(RegExp.LastCharClass) then begin + Previous:=RegExp.LastCharClass; + RegExp.LastCharClass:=self; + Previous.Next:=self; + Next:=nil; + end else begin + RegExp.FirstCharClass:=self; + RegExp.LastCharClass:=self; + Previous:=nil; + Next:=nil; + end; + First:=nil; + Last:=nil; + Inverted:=false; + Canonicalized:=false; +end; + +destructor TBESENRegExpCharClass.Destroy; +begin + while assigned(First) do begin + First.Free; + end; + if assigned(Previous) then begin + Previous.Next:=Next; + end else if RegExp.FirstCharClass=self then begin + RegExp.FirstCharClass:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if RegExp.LastCharClass=self then begin + RegExp.LastCharClass:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +procedure TBESENRegExpCharClass.Clear; +begin + while assigned(First) do begin + First.Free; + end; + Inverted:=false; + Canonicalized:=false; +end; + +procedure TBESENRegExpCharClass.Dump; +var Range:TBESENRegExpCharClassRange; +begin + Range:=First; + while assigned(Range) do begin + writeln(Range.Lo:8,' ',Range.Hi:8); + Range:=Range.Next; + end; +end; + +procedure TBESENRegExpCharClass.DebugDump; +var Range:TBESENRegExpCharClassRange; +begin + Range:=First; + while assigned(Range) do begin + if assigned(TBESEN(RegExp.Instance).RegExpDebugOutputHook) then begin + TBESEN(RegExp.Instance).RegExpDebugOutputHook(TBESEN(RegExp.Instance),'[0x'+TBESENUTF8ORSINGLESTRING(IntToHex(Range.Lo,8))+',0x'+TBESENUTF8ORSINGLESTRING(IntToHex(Range.Hi,8))+']',true); + end; + Range:=Range.Next; + end; +end; + +procedure TBESENRegExpCharClass.Optimize; +var Range:TBESENRegExpCharClassRange; +begin + Range:=First; + while assigned(Range) do begin + if assigned(Range.Previous) and (((Range.Previous.Hi>=Range.Lo) or ((Range.Previous.Hi+1)=Range.Lo))) then begin + if Range.Lo>Range.Previous.Lo then begin + Range.Lo:=Range.Previous.Lo; + end; + if Range.Hi<Range.Previous.Hi then begin + Range.Hi:=Range.Previous.Hi; + end; + Range.Previous.Free; + if assigned(Range.Previous) then begin + Range:=Range.Previous; + end; + end else if assigned(Range.Next) and (((Range.Hi>=Range.Next.Lo) or ((Range.Hi+1)=Range.Next.Lo))) then begin + if Range.Lo>Range.Next.Lo then begin + Range.Lo:=Range.Next.Lo; + end; + if Range.Hi<Range.Next.Hi then begin + Range.Hi:=Range.Next.Hi; + end; + Range.Next.Free; + if assigned(Range.Previous) then begin + Range:=Range.Previous; + end; + end else begin + Range:=Range.Next; + end; + end; +end; + +procedure TBESENRegExpCharClass.AddRange(Lo,Hi:TBESENUTF32CHAR;IgnoreCase:boolean=false); +var Range:TBESENRegExpCharClassRange; + c,cl,cu:TBESENUTF32CHAR; + NeedToCanonicalize:boolean; +begin + if IgnoreCase then begin + NeedToCanonicalize:=false; + for c:=Lo to Hi do begin + cl:=BESENUnicodeToLower(c); + cu:=BESENUnicodeToUpper(c); + if (cl<>cu) or (cl<>c) or (cu<>c) then begin + NeedToCanonicalize:=true; + break; + end; + end; + if NeedToCanonicalize then begin + for c:=Lo to Hi do begin + cl:=BESENUnicodeToLower(c); + cu:=BESENUnicodeToUpper(c); + if (cl=cu) and (cl=c) then begin + AddRange(c,c,false); + end else begin + AddRange(cl,cl,false); + AddRange(cu,cu,false); + if (cl<>c) and (cu<>c) then begin + AddRange(c,c,false); + end; + end; + end; + end else begin + AddRange(Lo,Hi,false); + end; + end else begin + Range:=First; + while assigned(Range) do begin + if (Lo>=Range.Lo) and (Hi<=Range.Hi) then begin + exit; + end else if (Lo<=Range.Lo) or ((Lo=Range.Lo) and (Hi<=Range.Hi)) then begin + break; + end; + Range:=Range.Next; + end; + if assigned(Range) then begin + TBESENRegExpCharClassRange.CreateBefore(self,Range,Lo,Hi); + end else begin + TBESENRegExpCharClassRange.Create(self,Lo,Hi); + end; + Optimize; + end; +end; + +procedure TBESENRegExpCharClass.AddChar(c:TBESENUTF32CHAR;IgnoreCase:boolean=false); +begin + AddRange(c,c,IgnoreCase); +end; + +procedure TBESENRegExpCharClass.TakeoverCombine(From:TBESENRegExpCharClass); +var Range:TBESENRegExpCharClassRange; +begin + if assigned(From) then begin + if assigned(First) then begin + Canonicalized:=Canonicalized and From.Canonicalized; + end else begin + Canonicalized:=From.Canonicalized; + end; + Range:=From.First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + if assigned(Last) then begin + Last.Next:=From.First; + From.First.Previous:=Last; + Last:=From.Last; + end else begin + First:=From.First; + Last:=From.Last; + end; + From.First:=nil; + From.Last:=nil; + end; +end; + +procedure TBESENRegExpCharClass.Assign(From:TBESENRegExpCharClass); +var Range:TBESENRegExpCharClassRange; +begin + if assigned(From) then begin + while assigned(First) do begin + First.Free; + end; + Inverted:=From.Inverted; + Canonicalized:=From.Canonicalized; + Range:=From.First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + First:=From.First; + Last:=From.Last; + From.First:=nil; + From.Last:=nil; + end; +end; + +procedure TBESENRegExpCharClass.Append(From:TBESENRegExpCharClass); +var Range:TBESENRegExpCharClassRange; +begin + if assigned(From) then begin + Range:=From.First; + while assigned(Range) do begin + TBESENRegExpCharClassRange.Create(self,Range.Lo,Range.Hi); + Range:=Range.Next; + end; + end; +end; + +procedure TBESENRegExpCharClass.Invert; +var NewList:TBESENRegExpCharClass; + Range:TBESENRegExpCharClassRange; + Lo,Hi:TBESENUTF32CHAR; +begin + Optimize; + Inverted:=not Inverted; + if assigned(First) and (First=Last) and (First.Lo=0) and (First.Hi=$ffffffff) then begin + First.Free; + end else if not assigned(First) then begin + TBESENRegExpCharClassRange.Create(self,0,$ffffffff); + end else begin + NewList:=TBESENRegExpCharClass.Create(RegExp); + try + Range:=First; + if Range.Lo>0 then begin + TBESENRegExpCharClassRange.Create(NewList,0,Range.Lo-1); + end; + Lo:=Range.Hi; + Range:=Range.Next; + while assigned(Range) do begin + if (Lo+1)<Range.Lo then begin + Hi:=Range.Lo; + TBESENRegExpCharClassRange.Create(NewList,Lo+1,Hi-1); + end; + Lo:=Range.Hi; + Range:=Range.Next; + end; + if Lo<>$ffffffff then begin + TBESENRegExpCharClassRange.Create(NewList,Lo+1,$ffffffff); + end; + while assigned(First) do begin + First.Free; + end; + Range:=NewList.First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + First:=NewList.First; + Last:=NewList.Last; + NewList.First:=nil; + NewList.Last:=nil; + Range:=First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + finally + NewList.Free; + end; + end; +end; + +procedure TBESENRegExpCharClass.Canonicalize; +var NewList:TBESENRegExpCharClass; + Range:TBESENRegExpCharClassRange; + OldInverted:boolean; +begin + if not Canonicalized then begin + NewList:=TBESENRegExpCharClass.Create(RegExp); + try + OldInverted:=Inverted; + if Inverted then begin + Invert; + end; + Range:=First; + while assigned(Range) do begin + NewList.AddRange(Range.Lo,Range.Hi,true); + Range:=Range.Next; + end; + while assigned(First) do begin + First.Free; + end; + First:=NewList.First; + Last:=NewList.Last; + NewList.First:=nil; + NewList.Last:=nil; + Range:=First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + if OldInverted then begin + Invert; + end; + Inverted:=OldInverted; + finally + NewList.Free; + end; + Canonicalized:=true; + end; +end; + +function TBESENRegExpCharClass.Count:longword; +var Range:TBESENRegExpCharClassRange; +begin + result:=0; + Range:=First; + while assigned(Range) do begin + inc(result,(Range.Hi-Range.Lo)+1); + Range:=Range.Next; + end; +end; + +function TBESENRegExpCharClass.Contains(c:TBESENUTF32CHAR):boolean; +var Range:TBESENRegExpCharClassRange; +begin + result:=false; + Range:=First; + while assigned(Range) do begin + if (c>=Range.Lo) and (c<=Range.Hi) then begin + result:=true; + break; + end; + Range:=Range.Next; + end; +end; + +function TBESENRegExpCharClass.IsSingle:boolean; +begin + result:=(First=Last) and ((assigned(First) and (First.Lo=First.Hi)) or not assigned(First)); +end; + +function CompareCharClasses(c1,c2:TBESENRegExpCharClass):longint; +var r1,r2:TBESENRegExpCharClassRange; +begin + r1:=c1.First; + r2:=c2.First; + while assigned(r1) and assigned(r2) do begin + if r1.Lo<>r2.Lo then begin + result:=longint(r1.Lo)-longint(r2.Lo); + exit; + end; + if r1.Hi<>r2.Hi then begin + result:=longint(r1.Hi)-longint(r2.Hi); + exit; + end; + r1:=r1.Next; + r2:=r2.Next; + end; + if assigned(r1) then begin + result:=1; + end else if assigned(r2) then begin + result:=-1; + end else begin + result:=0; + end; +end; + +constructor TBESENRegExpState.Create(ARegExp:TBESENRegExp); +begin + inherited Create; + RegExp:=ARegExp; + if assigned(RegExp.LastState) then begin + Previous:=RegExp.LastState; + RegExp.LastState:=self; + Previous.Next:=self; + Next:=nil; + end else begin + RegExp.FirstState:=self; + RegExp.LastState:=self; + Previous:=nil; + Next:=nil; + end; + Captures:=nil; + Counters:=nil; + Marks:=nil; + SetLength(Captures,RegExp.CountOfCaptures); + SetLength(Counters,RegExp.CountOfCounters); + SetLength(Marks,RegExp.CountOfMarks); +end; + +destructor TBESENRegExpState.Destroy; +begin + SetLength(Captures,0); + SetLength(Counters,0); + SetLength(Marks,0); + if assigned(Previous) then begin + Previous.Next:=Next; + end else if RegExp.FirstState=self then begin + RegExp.FirstState:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if RegExp.LastState=self then begin + RegExp.LastState:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +constructor TBESENRegExp.Create(AInstance:TObject); +begin + inherited Create(AInstance); + FirstCharClass:=nil; + LastCharClass:=nil; + FirstState:=nil; + LastState:=nil; + CurrentState:=nil; + CountStates:=0; + Source:=''; + ByteCode:=nil; + ByteCodeLen:=0; + Flags:=[]; + CountOfCaptures:=0; + CountOfCounters:=0; + CountOfMarks:=0; + MaxRef:=0; + CharClasses:=nil; + CharClassesCount:=0; + ReferenceCounter:=0; +end; + +destructor TBESENRegExp.Destroy; +begin + SetLength(CharClasses,0); + while assigned(FirstCharClass) do begin + FirstCharClass.Free; + end; + while assigned(FirstState) do begin + FirstState.Free; + end; + Source:=''; + SetLength(ByteCode,0); + inherited Destroy; +end; + +procedure TBESENRegExp.IncRef; +begin + inc(ReferenceCounter); +end; + +procedure TBESENRegExp.DecRef; +begin + if ReferenceCounter>1 then begin + dec(ReferenceCounter); + end else begin + ReferenceCounter:=0; + Destroy; + end; +end; + +function TBESENRegExp.InternCharClass(c:TBESENRegExpCharClass):longint; +var i:longint; +begin + for i:=0 to CharClassesCount-1 do begin + if CompareCharClasses(c,CharClasses[i])=0 then begin + result:=i; + exit; + end; + end; + result:=CharClassesCount; + inc(CharClassesCount); + if CharClassesCount>=length(CharClasses) then begin + SetLength(CharClasses,(CharClassesCount+256) and not 255); + end; + CharClasses[result]:=c; +end; + +function TBESENRegExp.CodePos:longint; +begin + result:=ByteCodeLen; +end; + +procedure TBESENRegExp.CodePosSet(p:longint); +begin + ByteCodeLen:=p; + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4097) and 4095); + end; +end; + +procedure TBESENRegExp.CodeAdd(c:longint); +var i:longint; +begin + i:=ByteCodeLen; + inc(ByteCodeLen); + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4097) and 4095); + end; + ByteCode[i]:=c; +end; + +procedure TBESENRegExp.CodePatch(p,c:longint); +var i:longint; +begin + i:=p; + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4097) and 4095); + end; + ByteCode[i]:=c; +end; + +procedure TBESENRegExp.CodeInsert(p,n:longint); +var i,j:longint; +begin + for i:=1 to n do begin + CodeAdd(0); + end; + for i:=ByteCodeLen-n downto p+1 do begin + j:=i-1; + ByteCode[j+n]:=ByteCode[j]; + end; +end; + +procedure TBESENRegExp.CodeAddI(c:longint); +begin + CodeAdd((c shr 8) and $ff); + CodeAdd(c and $ff); +end; + +procedure TBESENRegExp.CodeAddA(c:longint); +begin + CodeAddI(c-CodePos); +end; + +procedure TBESENRegExp.CodePatchI(p,c:longint); +begin + CodePatch(p,(c shr 8) and $ff); + CodePatch(p+1,c and $ff); +end; + +procedure TBESENRegExp.CodePatchA(p,c:longint); +begin + CodePatchI(p,c-p); +end; + +function TBESENRegExp.AllocateState:TBESENRegExpState; +begin + if assigned(CurrentState) then begin + if assigned(CurrentState.Next) then begin + CurrentState:=CurrentState.Next; + end else begin + CurrentState:=TBESENRegExpState.Create(self); + inc(CountStates); + end; + end else begin + if assigned(FirstState) then begin + CurrentState:=FirstState; + end else begin + CurrentState:=TBESENRegExpState.Create(self); + inc(CountStates); + end; + end; + result:=CurrentState; +end; + +procedure TBESENRegExp.CleanupStates; +begin + while assigned(LastState) and (CountStates>TBESEN(Instance).RegExpMaxStatesHoldInMemory) do begin + LastState.Free; + dec(CountStates); + end; + CurrentState:=nil; +end; + +procedure TBESENRegExp.CopyState(const a,b:TBESENRegExpState); +begin + if CountOfCaptures>0 then begin + move(b.Captures[0],a.Captures[0],CountOfCaptures*sizeof(TBESENRegExpCapture)); + end; + if CountOfCounters>0 then begin + move(b.Counters[0],a.Counters[0],CountOfCounters*sizeof(TBESENRegExpValue)); + end; + if CountOfMarks>0 then begin + move(b.Marks[0],a.Marks[0],CountOfMarks*sizeof(TBESENRegExpValue)); + end; +end; + +procedure TBESENRegExp.Compile(const ASource:TBESENString;const AFlags:TBESENRegExpFlags=[]); +var AtEOF:boolean; + CurrentChar:TBESENUTF32CHAR; + UTF32Source:TBESENUTF32STRING; + SourcePos:longint; + function NextChar:TBESENUTF32CHAR; + begin + if (SourcePos+1)<length(UTF32Source) then begin + inc(SourcePos); + CurrentChar:=UTF32Source[SourcePos]; + end else begin + CurrentChar:=0; + AtEOF:=true; + end; + result:=CurrentChar; + end; + procedure SyntaxError; + begin + raise EBESENSyntaxError.Create('regex syntax error'); + end; + procedure Expect(c:TBESENUTF32CHAR); + begin + if AtEOF or (CurrentChar<>c) then begin + SyntaxError; + end; + NextChar; + end; + function ParseInteger:longint; + var OK:boolean; + begin + result:=0; + OK:=false; + while (not AtEOF) and (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) do begin + result:=(result*10)+longint(CurrentChar-ord('0')); + OK:=true; + NextChar; + end; + if not OK then begin + SyntaxError; + end; + end; + function ParseHex:longword; + begin + result:=0; + if AtEOF then begin + SyntaxError; + end else if (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) then begin + result:=CurrentChar-ord('0'); + NextChar; + end else if (CurrentChar>=ord('a')) and (CurrentChar<=ord('f')) then begin + result:=CurrentChar-ord('a')+$a; + NextChar; + end else if (CurrentChar>=ord('A')) and (CurrentChar<=ord('F')) then begin + result:=CurrentChar-ord('A')+$a; + NextChar; + end else begin + SyntaxError; + end; + end; + procedure ParseDisjunction; forward; + function ParseClassEscape(CanBeAlreadyCanonicalized:boolean):TBESENRegExpCharClass; + var i:longint; + ch:TBESENUTF32CHAR; + IgnoreCase:boolean; + begin + result:=nil; + try + IgnoreCase:=CanBeAlreadyCanonicalized and (brefIGNORECASE in Flags); + result:=TBESENRegExpCharClass.Create(self); + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) then begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and + (CurrentChar=ord('0')) and ((SourcePos+2)<length(UTF32Source)) and ((UTF32Source[SourcePos+1]>=ord('0')) and (UTF32Source[SourcePos+1]<=ord('7'))) and + ((UTF32Source[SourcePos+2]>=ord('0')) and (UTF32Source[SourcePos+2]<=ord('7'))) then begin + result.AddChar(((UTF32Source[SourcePos+1]-ord('0'))*8)+(UTF32Source[SourcePos+2]-ord('0')),IgnoreCase); + result.Canonicalized:=IgnoreCase; + NextChar; + NextChar; + NextChar; + exit; + end; + i:=0; + while (not AtEOF) and (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) do begin + i:=(i*10)+longint(CurrentChar-ord('0')); + NextChar; + end; + if i<>0 then begin + SyntaxError; + end; + result.AddChar(i,IgnoreCase); + result.Canonicalized:=IgnoreCase; + exit; + end; + ch:=CurrentChar; + NextChar; + case ch of + ord('b'):begin + result.AddChar($0008); + result.Canonicalized:=true; + end; + ord('t'):begin + result.AddChar($0009); + result.Canonicalized:=true; + end; + ord('n'):begin + result.AddChar($000a); + result.Canonicalized:=true; + end; + ord('v'):begin + result.AddChar($000b); + result.Canonicalized:=true; + end; + ord('f'):begin + result.AddChar($000c); + result.Canonicalized:=true; + end; + ord('r'):begin + result.AddChar($000d); + result.Canonicalized:=true; + end; + ord('d'):begin + result.AddRange(ord('0'),ord('9')); + result.Canonicalized:=true; + end; + ord('D'):begin + result.AddRange(ord('0'),ord('9')); + result.Invert; + result.Inverted:=false; + result.Canonicalized:=true; + end; + ord('w'):begin + result.AddRange(ord('a'),ord('z')); + result.AddRange(ord('A'),ord('Z')); + result.AddRange(ord('0'),ord('9')); + result.AddChar(ord('_')); + result.Canonicalized:=true; + end; + ord('W'):begin + result.AddRange(ord('a'),ord('z')); + result.AddRange(ord('A'),ord('Z')); + result.AddRange(ord('0'),ord('9')); + result.AddChar(ord('_')); + result.Invert; + result.Inverted:=false; + result.Canonicalized:=true; + end; + ord('s'):begin + result.AddRange($0009,$000d); + result.AddChar($0020); + result.AddChar($00a0); + result.AddChar($1680); + result.AddChar($180e); + result.AddRange($2000,$200b); + result.AddRange($2028,$2029); + result.AddChar($202f); + result.AddChar($205f); + result.AddChar($3000); + result.AddChar($fffe); + result.AddChar($feff); + result.Canonicalized:=true; + end; + ord('S'):begin + result.AddRange($0009,$000d); + result.AddChar($0020); + result.AddChar($00a0); + result.AddChar($1680); + result.AddChar($180e); + result.AddRange($2000,$200b); + result.AddRange($2028,$2029); + result.AddChar($202f); + result.AddChar($205f); + result.AddChar($3000); + result.AddChar($fffe); + result.AddChar($feff); + result.Invert; + result.Inverted:=false; + result.Canonicalized:=true; + end; + ord('c'):begin + if AtEOF then begin + SyntaxError; + end; + ch:=CurrentChar; + NextChar; + if ((ch>=ord('a')) and (ch<=ord('z'))) or ((ch>=ord('A')) and (ch<=ord('Z'))) then begin + result.AddChar(ch mod 32,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end else begin + SyntaxError; + end; + end; + ord('x'):begin + ch:=ParseHex; + ch:=(ch shl 4) or ParseHex; + result.AddChar(ch,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end; + ord('u'):begin + ch:=ParseHex; + ch:=(ch shl 4) or ParseHex; + ch:=(ch shl 4) or ParseHex; + ch:=(ch shl 4) or ParseHex; + result.AddChar(ch,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end; + else begin + result.AddChar(ch,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseClassAtom:TBESENRegExpCharClass; + begin + if AtEOF then begin + SyntaxError; + end; + result:=nil; + try + if CurrentChar=ord('\') then begin + NextChar; + result:=ParseClassEscape(false); + end else begin + result:=TBESENRegExpCharClass.Create(self); + result.AddChar(CurrentChar); + NextChar; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseCharacterClass:TBESENRegExpCharClass; + var InvertFlag:boolean; + a,b:TBESENRegExpCharClass; + begin + result:=nil; + try + a:=nil; + b:=nil; + try + result:=TBESENRegExpCharClass.Create(self); + Expect(ord('[')); + InvertFlag:=(not AtEOF) and (CurrentChar=ord('^')); + if InvertFlag then begin + NextChar; + end; + while (not AtEOF) and (CurrentChar<>ord(']')) do begin + a:=ParseClassAtom; + if (not AtEOF) and (CurrentChar=ord('-')) then begin + NextChar; + if (not AtEOF) and (CurrentChar=ord(']')) then begin + a.AddChar(ord('-')); + end else begin + if not a.IsSingle then begin + BESENFreeAndNil(a); + SyntaxError; + end; + b:=ParseClassAtom; + if (not b.IsSingle) or ((assigned(a.Last) and assigned(b.Last)) and not (a.Last.Lo<=b.Last.Hi)) then begin + BESENFreeAndNil(a); + BESENFreeAndNil(b); + SyntaxError; + end; + if assigned(a.Last) and assigned(b.Last) then begin + a.Last.Hi:=b.Last.Hi; + end else begin + a.TakeoverCombine(b); + end; + BESENFreeAndNil(b); + end; + end; + result.TakeoverCombine(a); + BESENFreeAndNil(a); + end; + Expect(ord(']')); + if (brefIGNORECASE in Flags) and not result.Canonicalized then begin + result.Canonicalize; + end; + if InvertFlag then begin + result.Invert; + end; + finally + BESENFreeAndNil(a); + BESENFreeAndNil(b); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + procedure ParseAtom; + var neg:boolean; + i,p1,px:longint; + c:TBESENRegExpCharClass; + begin + c:=nil; + try + if CurrentChar=ord('(') then begin + NextChar; + if (not AtEOF) and (CurrentChar=ord('?')) then begin + NextChar; + if (not AtEOF) and (CurrentChar=ord(':')) then begin + NextChar; + ParseDisjunction; + end else if (not AtEOF) and ((CurrentChar=ord('=')) or (CurrentChar=ord('!'))) then begin + neg:=CurrentChar=ord('!'); + NextChar; + if neg then begin + CodeAdd(breoAF); + end else begin + CodeAdd(breoAS); + end; + p1:=CodePos; + CodeAddA(0); + ParseDisjunction; + CodeAdd(breoSUCCEED); + px:=CodePos; + CodePatchA(p1,px); + end else begin + SyntaxError; + end; + end else begin + i:=CountOfCaptures; + inc(CountOfCaptures); + CodeAdd(breoSTART); + CodeAddI(i); + ParseDisjunction; + CodeAdd(breoEND); + CodeAddI(i); + end; + Expect(ord(')')); + end else begin + case CurrentChar of + ord('\'):begin + NextChar; + if AtEOF then begin + SyntaxError; + end; + if (CurrentChar>=ord('1')) and (CurrentChar<=ord('9')) then begin + i:=ParseInteger; + CodeAdd(breoBACKREF); + CodeAddI(i); + if i>MaxRef then begin + MaxRef:=i; + end; + exit; + end; + c:=ParseClassEscape(true); + end; + ord('['):begin + c:=ParseCharacterClass; + end; + ord('.'):begin + NextChar; + c:=TBESENRegExpCharClass.Create(self); + c.AddChar($000a); + c.AddChar($000d); + c.AddRange($2028,$2029); + c.Invert; + c.Inverted:=false; + c.Canonicalized:=true; + end; + else begin + c:=TBESENRegExpCharClass.Create(self); + c.AddChar(CurrentChar,brefIGNORECASE in Flags); + c.Canonicalized:=brefIGNORECASE in Flags; + NextChar; + end; + end; + i:=InternCharClass(c); + CodeAdd(breoCHAR); + CodeAddI(i); + end; + except + BESENFreeAndNil(c); + raise; + end; + end; + procedure ParseTerm; + function QuantifierIsNext:boolean; + var Lookahead:PBESENUTF32CHARS; + Len,p:longint; + begin + if CurrentChar<>ord('{') then begin + result:=false; + end else if not (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + result:=true; + end else begin + Lookahead:=@UTF32Source[SourcePos]; + Len:=length(UTF32Source)-SourcePos; + p:=1; + if Len=0 then begin + result:=false; + end else begin + while (p<Len) and (Lookahead^[p]>=ord('0')) and (Lookahead^[p]<=ord('9')) do begin + inc(p); + end; + if (p<Len) and (Lookahead^[p]=ord(',')) then begin + inc(p); + while (p<Len) and (Lookahead^[p]>=ord('0')) and (Lookahead^[p]<=ord('9')) do begin + inc(p); + end; + if (p<Len) and (Lookahead^[p]>=ord('}')) then begin + result:=true; + end else begin + result:=false; + end; + end else if (p<Len) and (Lookahead^[p]>=ord('}')) then begin + result:=p>1; + end else begin + result:=false; + end; + end; + end; + end; + var Lookahead:PBESENUTF32CHARS; + Len,Position,oparen,cparen,min,max,m,px,py,i,c,p,p1,k:longint; + Greedy:boolean; + begin + Lookahead:=@UTF32Source[SourcePos]; + Len:=length(UTF32Source)-SourcePos; + case CurrentChar of + ord('\'):begin + if (Len>1) and (Lookahead^[1]=ord('b')) then begin + NextChar; + NextChar; + CodeAdd(breoBRK); + exit; + end; + if (Len>1) and (Lookahead^[1]=ord('B')) then begin + NextChar; + NextChar; + CodeAdd(breoNBRK); + exit; + end; + end; + ord('^'):begin + NextChar; + CodeAdd(breoBOL); + exit; + end; + ord('$'):begin + NextChar; + CodeAdd(breoEOL); + exit; + end; + ord('*'),ord('+'),ord('?'),ord(')'),ord(']'),ord('{'),ord('}'),ord('|'):begin + SyntaxError; + end; + end; + + Position:=CodePos; + oparen:=CountOfCaptures; + ParseAtom; + cparen:=CountOfCaptures; + + if AtEOF then begin + min:=1; + max:=1; + end else if CurrentChar=ord('*') then begin + NextChar; + min:=0; + max:=brecINFINITY; + end else if CurrentChar=ord('+') then begin + NextChar; + min:=1; + max:=brecINFINITY; + end else if CurrentChar=ord('?') then begin + NextChar; + min:=0; + max:=1; + end else if QuantifierIsNext then begin + NextChar; + min:=ParseInteger; + if (not AtEOF) and (CurrentChar=ord(',')) then begin + Expect(ord(',')); + if (not AtEOF) and (CurrentChar=ord('}')) then begin + max:=brecINFINITY; + end else begin + max:=ParseInteger; + end; + end else begin + max:=min; + end; + Expect(ord('}')); + end else begin + min:=1; + max:=1; + end; + + if (not AtEOF) and (CurrentChar=ord('?')) then begin + NextChar; + Greedy:=false; + end else begin + Greedy:=true; + end; + + if (min=max) and not Greedy then begin + Greedy:=true; + end; + + if (Max<>brecINFINITY) and (min>max) then begin + SyntaxError; + end; + + if (min=1) and (max=1) then begin + exit; + end; + + if max=0 then begin + CodePosSet(Position); + exit; + end; + + if oparen<>cparen then begin + CodeInsert(Position,1+(2*bresINT)); + CodePatch(Position,breoUNDEF); + CodePatchI(Position+1,oparen); + CodePatchI(Position+1+bresINT,cparen); + end; + + if min=max then begin + p:=Position; + i:=1+bresINT; + c:=CountOfCounters; + inc(CountOfCounters); + CodeInsert(Position,i); + CodePatch(p,breoZERO); + inc(p); + CodePatchI(p,c); + inc(p,bresINT); + px:=p; +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + CodeAdd(breoRNEXT); + CodeAddI(c); + CodeAddI(max); + CodeAddA(px); + end else if (min=0) and (max=1) then begin + p:=Position; + i:=1+bresADDR; + CodeInsert(Position,i); + if Greedy then begin + CodePatch(p,breoGF); + end else begin + CodePatch(p,breoNF); + end; + inc(p); + p1:=p; + inc(p,bresADDR); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + px:=CodePos; + CodePatchA(p1,px); + end else if (min=0) and (max=brecINFINITY) then begin + p:=Position; + i:=2+bresADDR+bresINT; + m:=CountOfMarks; + inc(CountOfMarks); + CodeInsert(Position,i); + px:=p; + if Greedy then begin + CodePatch(p,breoGF); + end else begin + CodePatch(p,breoNF); + end; + inc(p); + p1:=p; + inc(p,bresADDR); + CodePatch(p,breoMARK); + inc(p); + CodePatchI(p,m); + inc(p,bresINT); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + CodeAdd(breoFDIST); + CodeAddI(m); + CodeAdd(breoGOTO); + CodeAddA(px); + py:=CodePos; + CodePatchA(p1,py); + end else begin + p:=Position; + i:=3+(bresINT*2)+bresADDR; + c:=CountOfCounters; + k:=CountOfMarks; + inc(CountOfCounters); + inc(CountOfMarks); + CodeInsert(Position,i); + CodePatch(p,breoZERO); + inc(p); + CodePatchI(p,c); + inc(p,bresINT); + px:=p; + if Greedy then begin + CodePatch(p,breoGF); + end else begin + CodePatch(p,breoNF); + end; + inc(p); + p1:=p; + inc(p,bresADDR); + CodePatch(p,breoMARK); + inc(p); + CodePatchI(p,k); + inc(p,bresINT); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + if min<>0 then begin + CodeAdd(breoRDIST); + CodeAddI(k); + CodeAddI(c); + CodeAddI(min); + end else begin + CodeAdd(breoFDIST); + CodeAddI(k); + end; + if max<>brecINFINITY then begin + CodeAdd(breoRNEXT); + CodeAddI(c); + CodeAddI(max); + CodeAddA(px); + end else begin + CodeAdd(breoMNEXT); + CodeAddI(c); + CodeAddI(min); + CodeAddA(px); + end; + py:=CodePos; + if min<>0 then begin + CodeAdd(breoREACH); + CodeAddI(c); + CodeAddI(min); + end; + CodePatchA(p1,py); + end; + end; + procedure ParseAlternative; + begin + while not (AtEOF or (CurrentChar=ord(')')) or (CurrentChar=ord('|'))) do begin + ParseTerm; + end; + end; + procedure ParseDisjunction; + var Position,p,p1,p2,x1,x2,i:longint; + begin + Position:=CodePos; + ParseAlternative; + if (not AtEOF) and (CurrentChar=ord('|')) then begin + NextChar; + + p:=Position; + i:=1+bresADDR; + + CodeInsert(Position,i); + + CodePatch(p,breoGF); + inc(p); + p1:=p; + inc(p,bresADDR); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + + CodeAdd(breoGOTO); + p2:=CodePos; + + CodeAddA(0); + x1:=CodePos; + + ParseDisjunction; + + x2:=CodePos; + CodePatchA(p1,x1); + CodePatchA(p2,x2); + end; + end; + procedure Optimize; + begin + end; +begin + Flags:=AFlags; + CountOfCaptures:=1; + Source:=ASource; + AtEOF:=false; + UTF32Source:=nil; + try + UTF32Source:=BESENUTF16ToUTF32(Source); + SourcePos:=-1; + NextChar; + ParseDisjunction; + CodeAdd(breoSUCCEED); + SetLength(ByteCode,ByteCodeLen); + Optimize; + SetLength(CharClasses,CharClassesCount); + finally + SetLength(UTF32Source,0); + end; +end; + +function TBESENRegExp.Disassemble:TBESENString; + function CodeMakeI(a:longint):longint; + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + raise EBESENInternalError.Create('Internal error: 201002250421-0000'); + end; + end; + function CodeMakeA(a:longint):longint; + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; +var PC,i,i2,i3,a:longint; + Opcode:byte; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; +begin + result:=''; + PC:=0; + i:=0; + i2:=0; + i3:=0; + a:=0; + while (PC>=0) and (PC<ByteCodeLen) do begin + result:=result+'0x'+IntToHex(PC,8)+': '; + Opcode:=ByteCode[PC]; + inc(PC); + case Opcode of + breoFAIL:begin + result:=result+'FAIL'; + end; + breoSUCCEED:begin + result:=result+'SUCCEED'; + end; + breoCHAR:begin + GetParams1; + result:=result+'CHAR '+IntToStr(i); + end; + breoZERO:begin + GetParams1; + result:=result+'ZERO '+IntToStr(i); + end; + breoREACH:begin + GetParams2; + result:=result+'REACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoNREACH:begin + GetParams2; + result:=result+'NREACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoSTART:begin + GetParams1; + result:=result+'START '+IntToStr(i); + end; + breoEND:begin + GetParams1; + result:=result+'END '+IntToStr(i); + end; + breoUNDEF:begin + GetParams2; + result:=result+'UNDEF '+IntToStr(i)+', '+IntToStr(i2); + end; + breoMARK:begin + GetParams1; + result:=result+'MARK '+IntToStr(i); + end; + breoFDIST:begin + GetParams1; + result:=result+'FDIST '+IntToStr(i); + end; + breoRDIST:begin + GetParams3; + result:=result+'RDIST '+IntToStr(i)+', '+IntToStr(i2)+', '+IntToStr(i3); + end; + breoMNEXT:begin + GetParams2A; + result:=result+'MNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoRNEXT:begin + GetParams2A; + result:=result+'RNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoGOTO:begin + GetParamsA; + result:=result+'GOTO 0x'+IntToHex(a,8); + end; + breoGS:begin + GetParamsA; + result:=result+'GS 0x'+IntToHex(a,8); + end; + breoNS:begin + GetParamsA; + result:=result+'NS 0x'+IntToHex(a,8); + end; + breoGF:begin + GetParamsA; + result:=result+'GF 0x'+IntToHex(a,8); + end; + breoNF:begin + GetParamsA; + result:=result+'NF 0x'+IntToHex(a,8); + end; + breoAS:begin + GetParamsA; + result:=result+'AS 0x'+IntToHex(a,8); + end; + breoAF:begin + GetParamsA; + result:=result+'AF 0x'+IntToHex(a,8); + end; + breoBOL:begin + result:=result+'BOL'; + end; + breoEOL:begin + result:=result+'EOL'; + end; + breoBRK:begin + result:=result+'BRK'; + end; + breoNBRK:begin + result:=result+'NBRK'; + end; + breoBACKREF:begin + GetParams1; + result:=result+'BACKREF '+IntToStr(i); + end; + else begin + raise EBESENInternalError.Create('Internal error: 201002250323-0000'); + end; + end; + result:=result+#10; + end; +end; + +procedure TBESENRegExp.DebugDisassemble; + function CodeMakeI(a:longint):longint; + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + raise EBESENInternalError.Create('Internal error: 201002250421-0000'); + end; + end; + function CodeMakeA(a:longint):longint; + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; +var PC,i,i2,i3,a:longint; + Opcode:byte; + Line:TBESENUTF8ORSINGLESTRING; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; +begin + PC:=0; + i:=0; + i2:=0; + i3:=0; + a:=0; + while (PC>=0) and (PC<ByteCodeLen) do begin + Line:='0x'+TBESENUTF8ORSINGLESTRING(IntToHex(PC,8))+': '; + Opcode:=ByteCode[PC]; + inc(PC); + case Opcode of + breoFAIL:begin + Line:=Line+'FAIL'; + end; + breoSUCCEED:begin + Line:=Line+'SUCCEED'; + end; + breoCHAR:begin + GetParams1; + Line:=Line+'CHAR '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoZERO:begin + GetParams1; + Line:=Line+'ZERO '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoREACH:begin + GetParams2; + Line:=Line+'REACH '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); + end; + breoNREACH:begin + GetParams2; + Line:=Line+'NREACH '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); + end; + breoSTART:begin + GetParams1; + Line:=Line+'START '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoEND:begin + GetParams1; + Line:=Line+'END '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoUNDEF:begin + GetParams2; + Line:=Line+'UNDEF '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); + end; + breoMARK:begin + GetParams1; + Line:=Line+'MARK '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoFDIST:begin + GetParams1; + Line:=Line+'FDIST '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoRDIST:begin + GetParams3; + Line:=Line+'RDIST '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i3)); + end; + breoMNEXT:begin + GetParams2A; + Line:=Line+'MNEXT '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoRNEXT:begin + GetParams2A; + Line:=Line+'RNEXT '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoGOTO:begin + GetParamsA; + Line:=Line+'GOTO 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoGS:begin + GetParamsA; + Line:=Line+'GS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoNS:begin + GetParamsA; + Line:=Line+'NS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoGF:begin + GetParamsA; + Line:=Line+'GF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoNF:begin + GetParamsA; + Line:=Line+'NF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoAS:begin + GetParamsA; + Line:=Line+'AS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoAF:begin + GetParamsA; + Line:=Line+'AF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoBOL:begin + Line:=Line+'BOL'; + end; + breoEOL:begin + Line:=Line+'EOL'; + end; + breoBRK:begin + Line:=Line+'BRK'; + end; + breoNBRK:begin + Line:=Line+'NBRK'; + end; + breoBACKREF:begin + GetParams1; + Line:=Line+'BACKREF '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + else begin + raise EBESENInternalError.Create('Internal error: 201002250323-0000'); + end; + end; + if assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),Line,true); + end; + end; +end; + +function TBESENRegExp.DisassembleOpcode(PC:longint):TBESENString; + function CodeMakeI(a:longint):longint; + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + raise EBESENInternalError.Create('Internal error: 201002250421-0000'); + end; + end; + function CodeMakeA(a:longint):longint; + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; +var i,i2,i3,a:longint; + Opcode:byte; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; +begin + result:=''; + i:=0; + i2:=0; + i3:=0; + a:=0; + if (PC>=0) and (PC<ByteCodeLen) then begin + result:=result+'0x'+IntToHex(PC,8)+': '; + Opcode:=ByteCode[PC]; + inc(PC); + case Opcode of + breoFAIL:begin + result:=result+'FAIL'; + end; + breoSUCCEED:begin + result:=result+'SUCCEED'; + end; + breoCHAR:begin + GetParams1; + result:=result+'CHAR '+IntToStr(i); + end; + breoZERO:begin + GetParams1; + result:=result+'ZERO '+IntToStr(i); + end; + breoREACH:begin + GetParams2; + result:=result+'REACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoNREACH:begin + GetParams2; + result:=result+'NREACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoSTART:begin + GetParams1; + result:=result+'START '+IntToStr(i); + end; + breoEND:begin + GetParams1; + result:=result+'END '+IntToStr(i); + end; + breoUNDEF:begin + GetParams2; + result:=result+'UNDEF '+IntToStr(i)+', '+IntToStr(i2); + end; + breoMARK:begin + GetParams1; + result:=result+'MARK '+IntToStr(i); + end; + breoFDIST:begin + GetParams1; + result:=result+'FDIST '+IntToStr(i); + end; + breoRDIST:begin + GetParams3; + result:=result+'RDIST '+IntToStr(i)+', '+IntToStr(i2)+', '+IntToStr(i3); + end; + breoMNEXT:begin + GetParams2A; + result:=result+'MNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoRNEXT:begin + GetParams2A; + result:=result+'RNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoGOTO:begin + GetParamsA; + result:=result+'GOTO 0x'+IntToHex(a,8); + end; + breoGS:begin + GetParamsA; + result:=result+'GS 0x'+IntToHex(a,8); + end; + breoNS:begin + GetParamsA; + result:=result+'NS 0x'+IntToHex(a,8); + end; + breoGF:begin + GetParamsA; + result:=result+'GF 0x'+IntToHex(a,8); + end; + breoNF:begin + GetParamsA; + result:=result+'NF 0x'+IntToHex(a,8); + end; + breoAS:begin + GetParamsA; + result:=result+'AS 0x'+IntToHex(a,8); + end; + breoAF:begin + GetParamsA; + result:=result+'AF 0x'+IntToHex(a,8); + end; + breoBOL:begin + result:=result+'BOL'; + end; + breoEOL:begin + result:=result+'EOL'; + end; + breoBRK:begin + result:=result+'BRK'; + end; + breoNBRK:begin + result:=result+'NBRK'; + end; + breoBACKREF:begin + GetParams1; + result:=result+'BACKREF '+IntToStr(i); + end; + else begin + raise EBESENInternalError.Create('Internal error: 201002250323-0000'); + end; + end; + end; +end; + +function TBESENRegExp.Execute(PC:longint;const Input:TBESENString;var State:TBESENRegExpState;var RemainTimeOutSteps:int64):boolean; + procedure Print(Data:TBESENUTF8ORSINGLESTRING); + begin + if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),TBESENUTF8ORSINGLESTRING(Data),false); + end; + end; + procedure PrintLn(Data:TBESENUTF8ORSINGLESTRING); + begin + if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),TBESENUTF8ORSINGLESTRING(Data),true); + end; + end; + function CodeMakeI(a:longint):longint; {$ifdef caninline}inline;{$endif} + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + BESENThrowInternalError('Internal error: 201002250421-0000'); + result:=0; + end; + end; + function CodeMakeA(a:longint):longint; {$ifdef caninline}inline;{$endif} + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; + function GetChar(i:longint):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} + begin + if (i>=0) and (i<length(Input)) then begin + result:=word(widechar(Input[i+1])); + end else begin + BESENThrowInternalError('Internal error: 201002250421-0001'); + result:=0; + end; + end; + function IsWordChar(i:longint):boolean; {$ifdef caninline}inline;{$endif} + begin + if (i>=0) and (i<length(Input)) then begin + case word(widechar(Input[i+1])) of + ord('a')..ord('z'),ord('A')..ord('Z'),ord('0')..ord('9'),ord('_'):begin + result:=true; + end; + else begin + result:=false; + end; + end; + end else begin + result:=false; + end; + end; +var Opcode:byte; + i,i2,i3,a,x,br,len,opc:longint; + ch:TBESENUTF32CHAR; + OldCurrentState,NewState:TBESENRegExpState; + DoBreak:boolean; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure DebugOut; + var c:longint; + e:longword; + begin + opc:=PC; + Print('index='+AnsiString(IntToStr(State.Captures[0].e))+' captures=['); + for c:=0 to CountOfCaptures-1 do begin + if c<>0 then begin + Print(','); + end; + if State.Captures[c].s=brecUNDEFINED then begin + Print('undef'); + end else if int64(State.Captures[c].s+State.Captures[c].e)>length(Input) then begin + Print('bad<'+AnsiString(IntToHex(State.Captures[c].s,8))+','+AnsiString(IntToHex(State.Captures[c].e,8))+'>'); + end else begin + e:=State.Captures[c].e; + if e=brecUNDEFINED then begin + e:=State.Captures[0].e; + end; + Print('"'+BESENUTF16ToUTF8(copy(Input,State.Captures[c].s+1,e-State.Captures[c].s))+'"'); + if State.Captures[c].e=brecUNDEFINED then begin + Print('+'); + end; + end; + end; + Print(']'); + if Opcode in [breoZERO,breoREACH,breoNREACH,breoMNEXT,breoRNEXT] then begin + Print(' counters=['); + for c:=0 to CountOfCounters-1 do begin + if c<>0 then begin + Print(','); + end; + Print(AnsiString(IntToStr(State.Counters[c]))); + end; + Print(']'); + end; + if Opcode in [breoMARK,breoFDIST,breoRDIST] then begin + Print(' marks=['); + for c:=0 to CountOfMarks-1 do begin + if c<>0 then begin + Print(','); + end; + Print(AnsiString(IntToStr(State.Marks[c]))); + end; + Print(']'); + end; + if Opcode<>breoCHAR then begin + PrintLn(''); + PrintLn(AnsiString(DisassembleOpcode(opc))); + end; + end; +begin + result:=false; + OldCurrentState:=CurrentState; + try + NewState:=AllocateState; + i:=0; + i2:=0; + i3:=0; + a:=0; + opc:=0; + while (PC>=0) and (PC<ByteCodeLen) and (RemainTimeOutSteps<>0) do begin + if RemainTimeOutSteps>0 then begin + dec(RemainTimeOutSteps); + end; + Opcode:=ByteCode[PC]; + if TBESEN(Instance).RegExpDebug<>0 then begin + DebugOut; + end; + inc(PC); + case Opcode of + breoFAIL:begin + result:=false; + break; + end; + breoSUCCEED:begin + result:=true; + break; + end; + breoCHAR:begin + GetParams1; + if State.Captures[0].e<longword(length(Input)) then begin + ch:=GetChar(State.Captures[0].e); + inc(State.Captures[0].e); + if ((ch and $fc00)=$d800) and (State.Captures[0].e<longword(length(Input))) and ((GetChar(State.Captures[0].e) and $fc00)=$dc00) then begin + ch:=(((ch and $3ff) shl 10) or (GetChar(State.Captures[0].e) and $3ff))+$10000; + end; + if TBESEN(Instance).RegExpDebug<>0 then begin + Print(' ch="'+BESENUTF32CHARToUTF8(ch)+'" result='); + if CharClasses[i].Contains(ch) then begin + PrintLn('true'); + end else begin + PrintLn('false'); + end; + PrintLn(AnsiString(DisassembleOpcode(opc))); + end; + if not CharClasses[i].Contains(ch) then begin + result:=false; + break; + end; + end else begin + if TBESEN(Instance).RegExpDebug<>0 then begin + PrintLn(''); + PrintLn(AnsiString(DisassembleOpcode(opc))); + end; + result:=false; + break; + end; + end; + breoZERO:begin + GetParams1; + State.Counters[i]:=0; + end; + breoREACH:begin + GetParams2; + if State.Counters[i]<i2 then begin + result:=false; + break; + end; + end; + breoNREACH:begin + GetParams2; + if State.Counters[i]>=i2 then begin + result:=false; + break; + end; + end; + breoSTART:begin + GetParams1; + State.Captures[i].s:=State.Captures[0].e; + State.Captures[i].e:=brecUNDEFINED; + end; + breoEND:begin + GetParams1; + State.Captures[i].e:=State.Captures[0].e; + end; + breoUNDEF:begin + GetParams2; + while i<i2 do begin + State.Captures[i].s:=brecUNDEFINED; + State.Captures[i].e:=brecUNDEFINED; + inc(i); + end; + end; + breoMARK:begin + GetParams1; + State.Marks[i]:=State.Captures[0].e; + end; + breoFDIST:begin + GetParams1; + if State.Marks[i]=longint(State.Captures[0].e) then begin + result:=false; + break; + end; + end; + breoRDIST:begin + GetParams3; + if (State.Marks[i]=longint(State.Captures[0].e)) and (State.Counters[i2]>=i3) then begin + result:=false; + break; + end; + end; + breoMNEXT:begin + GetParams2A; + if State.Counters[i]<i2 then begin + inc(State.Counters[i]); + end; + PC:=a; + end; + breoRNEXT:begin + GetParams2A; + inc(State.Counters[i]); + if State.Counters[i]<i2 then begin + PC:=a; + end; + end; + breoGOTO:begin + GetParamsA; + PC:=a; + end; + breoGS:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + PC:=a; + end else begin + result:=false; + break; + end; + end; + breoNS:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(a,Input,NewState,RemainTimeOutSteps); + if not result then begin + result:=false; + break; + end; + end; + breoGF:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + CopyState(State,NewState); + result:=true; + break; + end else begin + PC:=a; + end; + end; + breoNF:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(a,Input,NewState,RemainTimeOutSteps); + if result then begin + CopyState(State,NewState); + result:=true; + break; + end; + end; + breoAS:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + i:=State.Captures[0].e; + CopyState(State,NewState); + State.Captures[0].e:=i; + PC:=a; + end else begin + result:=false; + break; + end; + end; + breoAF:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + result:=false; + break; + end else begin + PC:=a; + end; + end; + breoBOL:begin + if State.Captures[0].e=0 then begin + end else if not (brefMULTILINE in Flags) then begin + result:=false; + break; + end else if (word(widechar(Input[State.Captures[0].e]))=$000a) or + (word(widechar(Input[State.Captures[0].e]))=$000d) or + (word(widechar(Input[State.Captures[0].e]))=$2028) or + (word(widechar(Input[State.Captures[0].e]))=$2029) then begin + end else begin + result:=false; + break; + end; + end; + breoEOL:begin + if State.Captures[0].e=longword(length(Input)) then begin + end else if not (brefMULTILINE in Flags) then begin + result:=false; + break; + end else if (word(widechar(Input[State.Captures[0].e]))=$000a) or + (word(widechar(Input[State.Captures[0].e]))=$000d) or + (word(widechar(Input[State.Captures[0].e]))=$2028) or + (word(widechar(Input[State.Captures[0].e]))=$2029) then begin + end else begin + result:=false; + break; + end; + end; + breoBRK:begin + if IsWordChar(State.Captures[0].e-1)=IsWordChar(State.Captures[0].e) then begin + result:=false; + break; + end; + end; + breoNBRK:begin + if IsWordChar(State.Captures[0].e-1)<>IsWordChar(State.Captures[0].e) then begin + result:=false; + break; + end; + end; + breoBACKREF:begin + GetParams1; + if ((i>=0) and (i<length(State.Captures))) and (State.Captures[i].e<>brecUNDEFINED) then begin + br:=State.Captures[i].s; + len:=longword(longword(State.Captures[i].e)-longword(br)); + if int64(len+int64(State.Captures[0].e))>length(Input) then begin + result:=false; + break; + end; + DoBreak:=false; + if brefIGNORECASE in Flags then begin + for x:=0 to len-1 do begin + if BESENUnicodeToUpper(GetChar(br+x))<>BESENUnicodeToUpper(GetChar(longint(State.Captures[0].e)+x)) then begin + result:=false; + DoBreak:=true; + break; + end; + end; + end else begin + for x:=0 to len-1 do begin + if GetChar(br+x)<>GetChar(longint(State.Captures[0].e)+x) then begin + result:=false; + DoBreak:=true; + break; + end; + end; + end; + if DoBreak then begin + break; + end; + inc(State.Captures[0].e,len); + end; + end; + else begin + BESENThrowInternalError('Internal error: 201002250323-0000'); + end; + end; + end; + finally + CurrentState:=OldCurrentState; + end; +end; + +function TBESENRegExp.Match(const Input:TBESENString;Index:longint;var Captures:TBESENRegExpCaptures):boolean; +var State:TBESENRegExpState; + i:longint; + RemainTimeOutSteps:int64; +begin + CurrentState:=nil; + State:=AllocateState; + try + Captures:=nil; + State.Captures[0].s:=Index; + State.Captures[0].e:=Index; + for i:=1 to CountOfCaptures-1 do begin + State.Captures[i].s:=brecUNDEFINED; + State.Captures[i].e:=brecUNDEFINED; + end; + if TBESEN(Instance).RegExpTimeOutSteps>0 then begin + RemainTimeOutSteps:=TBESEN(Instance).RegExpTimeOutSteps; + end else begin + RemainTimeOutSteps:=-1; + end; + result:=Execute(0,Input,State,RemainTimeOutSteps); + if RemainTimeOutSteps=0 then begin + if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'TIMEOUT',true); + end; + end; + if result then begin + if length(Captures)<>length(State.Captures) then begin + SetLength(Captures,length(State.Captures)); + end; + if length(State.Captures)>0 then begin + move(State.Captures[0],Captures[0],length(State.Captures)*sizeof(TBESENRegExpCapture)); + end; + end else begin + SetLength(Captures,0); + end; + finally + CleanupStates; + end; +end; + +procedure TBESENRegExp.DebugDump; +var i:longint; +begin + if assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + if (TBESEN(Instance).RegExpDebug>2) and (CharClassesCount>0) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASSES-DUMP-BEGIN---',true); + for i:=0 to CharClassesCount-1 do begin + if assigned(CharClasses[i]) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASS-NUMBER-0x'+AnsiString(IntToHex(i,8))+'-DUMP-BEGIN---',true); + CharClasses[i].DebugDump; + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASS-NUMBER-0x'+AnsiString(IntToHex(i,8))+'-DUMP-END---',true); + end; + end; + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASSES-DUMP-END---',true); + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'',true); + end; + if TBESEN(Instance).RegExpDebug>1 then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---REGEXP-BYTECODE-DISASSEMBLY-BEGIN---',true); + DebugDisassemble; + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---REGEXP-BYTECODE-DISASSEMBLY-END---',true); + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'',true); + end; + end; +end; + +end. diff --git a/3rd/besen/src/BESENRegExpCache.pas b/3rd/besen/src/BESENRegExpCache.pas new file mode 100644 index 000000000..48928a0ab --- /dev/null +++ b/3rd/besen/src/BESENRegExpCache.pas @@ -0,0 +1,152 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENRegExpCache; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENRegExp; + +type TBESENRegExpCacheItems=array of TBESENRegExp; + + TBESENRegExpCache=class(TBESENBaseObject) + private + HashSize:longword; + HashSizeMask:longword; + HashItems:TBESENRegExpCacheItems; + procedure SetCacheSize(NewSize:longword); + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Hash(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENHash; + function Get(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENRegExp; + function IsCached(RegExp:TBESENRegExp):boolean; + published + property CacheSize:longword read HashSize write SetCacheSize; + end; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; + +constructor TBESENRegExpCache.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashItems:=nil; + SetCacheSize(BESENRegExpCacheSize); +end; + +destructor TBESENRegExpCache.Destroy; +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + BesenFreeAndNil(HashItems[i]); + HashItems[i]:=nil; + end; + end; + SetLength(HashItems,0); + inherited Destroy; +end; + +procedure TBESENRegExpCache.SetCacheSize(NewSize:longword); +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + HashItems[i].DecRef; + HashItems[i]:=nil; + end; + end; + HashSize:=BESENRoundUpToPowerOfTwo(NewSize); + HashSizeMask:=HashSize-1; + SetLength(HashItems,HashSize); + for i:=0 to length(HashItems)-1 do begin + HashItems[i]:=nil; + end; +end; + +function TBESENRegExpCache.Hash(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENHash; +begin + result:=BESENHashKey(Source); + if brefGLOBAL in Flags then begin + result:=result+4; + end; + if brefIGNORECASE in Flags then begin + result:=result+2; + end; + if brefMULTILINE in Flags then begin + result:=result+1; + end; +end; + +function TBESENRegExpCache.Get(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENRegExp; +var HashValue:TBESENUINT32; +begin + if HashSize>0 then begin + HashValue:=Hash(Source,Flags) and HashSizeMask; + result:=HashItems[HashValue]; + if (assigned(result) and ((result.Source<>Source) or (result.Flags<>Flags))) or not assigned(result) then begin + result:=TBESENRegExp.Create(Instance); + try + result.Compile(Source,Flags); + try + if assigned(HashItems[HashValue]) then begin + HashItems[HashValue].DecRef; + end; + HashItems[HashValue]:=result; + result.IncRef; + except + HashItems[HashValue]:=nil; + raise; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + end else begin + result:=TBESENRegExp.Create(Instance); + try + result.Compile(Source,Flags); + except + BESENFreeAndNil(result); + raise; + end; + end; +end; + +function TBESENRegExpCache.IsCached(RegExp:TBESENRegExp):boolean; +begin + result:=(HashSize>0) and (assigned(RegExp) and (RegExp=HashItems[Hash(RegExp.Source,RegExp.Flags) and HashSizeMask])); +end; + +end. diff --git a/3rd/besen/src/BESENScope.pas b/3rd/besen/src/BESENScope.pas new file mode 100644 index 000000000..a842569e1 --- /dev/null +++ b/3rd/besen/src/BESENScope.pas @@ -0,0 +1,83 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENScope; +{$i BESEN.inc} + +interface + +uses BESENObject,BESENGarbageCollector; + +type TBESENScope=class(TBESENGarbageCollectorObject) + public + Next:TBESENScope; + Obj:TBESENObject; + constructor Create(AInstance:TObject;AObj:TBESENObject); overload; virtual; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENScope.Create(AInstance:TObject;AObj:TBESENObject); +begin + inherited Create(AInstance); + Next:=nil; + Obj:=AObj; +end; + +destructor TBESENScope.Destroy; +begin + Obj:=nil; + inherited Destroy; +end; + +procedure TBESENScope.Finalize; +begin + Obj:=nil; + Next:=nil; + inherited Finalize; +end; + +procedure TBESENScope.Mark; +begin + if assigned(Obj) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Obj); + end; + if assigned(Next) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Next); + end; + inherited Mark; +end; + +end. diff --git a/3rd/besen/src/BESENSelfBalancedTree.pas b/3rd/besen/src/BESENSelfBalancedTree.pas new file mode 100644 index 000000000..6b5a09734 --- /dev/null +++ b/3rd/besen/src/BESENSelfBalancedTree.pas @@ -0,0 +1,678 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENSelfBalancedTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENSelfBalancedTreeValue=^TBESENSelfBalancedTreeValue; + TBESENSelfBalancedTreeValue=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENSelfBalancedTreeNode=^TBESENSelfBalancedTreeNode; + TBESENSelfBalancedTreeNode=record + Parent,Left,Right,PreviousKey,NextKey:PBESENSelfBalancedTreeNode; + Level:int64; + Key:TBESENString; + Value:TBESENSelfBalancedTreeValue; + end; + + TBESENSelfBalancedTreeKeys=array of widestring; + + TBESENSelfBalancedTree=class + protected + procedure Skew(OldParent:PBESENSelfBalancedTreeNode); + function Split(OldParent:PBESENSelfBalancedTreeNode):boolean; + procedure RebalanceAfterLeafAdd(n:PBESENSelfBalancedTreeNode); + procedure DeleteNode(n:PBESENSelfBalancedTreeNode); + function First(StartNode:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; + function Next(n:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; + function FindNode(const Key:TBESENString):PBESENSelfBalancedTreeNode; + procedure ClearNode(var Node:PBESENSelfBalancedTreeNode); + procedure OptimizeNode(var Node:PBESENSelfBalancedTreeNode;MoreOptimize:boolean); + function GetValue(Key:TBESENString):TBESENSelfBalancedTreeValue; + procedure SetValue(Key:TBESENString;Value:TBESENSelfBalancedTreeValue); + public + RootNode:PBESENSelfBalancedTreeNode; + FirstKey,LastKey:PBESENSelfBalancedTreeNode; + constructor Create; + destructor Destroy; override; + function Find(const Key:TBESENString;var Value:TBESENSelfBalancedTreeValue):boolean; + function FindNearest(const Key:TBESENString):PBESENSelfBalancedTreeNode; + function Insert(const Key:TBESENString;Value:TBESENSelfBalancedTreeValue):PBESENSelfBalancedTreeNode; + procedure Remove(const Key:TBESENString); + procedure Optimize; + function Keys:TBESENSelfBalancedTreeKeys; + property Values[Key:TBESENString]:TBESENSelfBalancedTreeValue read GetValue write SetValue; default; + end; + +implementation + +constructor TBESENSelfBalancedTree.Create; +begin + inherited Create; + new(RootNode); + fillchar(RootNode^,sizeof(TBESENSelfBalancedTreeNode),#0); + RootNode^.Level:=$7fffffffffffffff; + FirstKey:=nil; + LastKey:=nil; +end; + +destructor TBESENSelfBalancedTree.Destroy; +begin + ClearNode(RootNode^.Left); + dispose(RootNode); + inherited Destroy; +end; + +function TBESENSelfBalancedTree.First(StartNode:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; +begin + try + if not assigned(StartNode^.Left) then begin + result:=nil; + exit; + end; + result:=StartNode; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + except + result:=nil; + end; +end; + +function TBESENSelfBalancedTree.Next(n:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; +begin + try + if assigned(n^.Right) then begin + result:=n^.Right; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + end else begin + while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin + n:=n^.Parent; + end; + n:=n^.Parent; + if not assigned(n) then begin + result:=nil; + exit; + end; + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENSelfBalancedTree.Skew(OldParent:PBESENSelfBalancedTreeNode); +var NewParent:PBESENSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Left; +{$ifdef UseAssert} + Assert(assigned(NewParent)); +{$endif} + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Left:=NewParent^.Right; + if assigned(OldParent^.Left) then begin + OldParent^.Left^.Parent:=OldParent; + end; + NewParent^.Right:=OldParent; + + if assigned(OldParent^.Left) then begin + OldParent^.level:=OldParent^.Left^.level+1; + end else begin + OldParent^.level:=1; + end; +end; + +function TBESENSelfBalancedTree.Split(OldParent:PBESENSelfBalancedTreeNode):boolean; +var NewParent:PBESENSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Right; + if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Right:=NewParent^.Left; + if assigned(OldParent^.Right) then begin + OldParent^.Right^.Parent:=OldParent; + end; + NewParent^.Left:=OldParent; + + NewParent^.level:=OldParent^.level+1; + + result:=true; + end else begin + result:=false; + end; +end; + +procedure TBESENSelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENSelfBalancedTreeNode); +begin + // n is a node that has just been inserted and is now a Leaf node. + n^.Level:=1; + n^.Left:=nil; + n^.Right:=nil; + n:=n^.Parent; + while n<>RootNode do begin + if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin + // this point the tree is correct, except (AA2) for n->Parent + Skew(n); + // We handle it (a Left add) by changing it into a Right add using Skew + // If the original add was to the Left side of a node that is on the + // Right side of a horizontal link, n now points to the rights side + // of the second horizontal link, which is correct. + // However if the original add was to the Left of node with a horizontal + // link, we must get to the Right side of the second link. + if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin + n:=n^.Parent; + end; + end; + if not Split(n^.Parent) then begin + break; + end; + n:=n^.Parent; + end; +end; + +function TBESENSelfBalancedTree.FindNode(const Key:TBESENString):PBESENSelfBalancedTreeNode; +var n:PBESENSelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + case BESENStringCompare(Key,n^.Key) of + -1:begin + n:=n^.Left; + end; + 1:begin + n:=n^.Right; + end; + else begin + result:=n; + break; + end; + end; + end; + except + result:=nil; + end; +end; + +function TBESENSelfBalancedTree.FindNearest(const Key:TBESENString):PBESENSelfBalancedTreeNode; +var n:PBESENSelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + result:=n; + case BESENStringCompare(Key,n^.Key) of + -1:begin + n:=n^.Left; + end; + 1:begin + n:=n^.Right; + end; + else begin + break; + end; + end; + end; + except + result:=nil; + end; +end; + +function TBESENSelfBalancedTree.Insert(const Key:TBESENString;Value:TBESENSelfBalancedTreeValue):PBESENSelfBalancedTreeNode; +var n,s:PBESENSelfBalancedTreeNode; + LessThan:boolean; +begin + result:=nil; + try + n:=nil; + s:=RootNode^.Left; + while assigned(s) do begin + case BESENStringCompare(Key,s^.Key) of + -1:begin + s:=s^.Left; + end; + 1:begin + s:=s^.Right; + end; + else begin + n:=s; + break; + end; + end; + end; + if assigned(s) then begin + n^.Value:=Value; + end else begin + new(n); + fillchar(n^,sizeof(TBESENSelfBalancedTreeNode),#0); + n^.Key:=Key; + n^.Value:=Value; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + RebalanceAfterLeafAdd(n); + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENSelfBalancedTree.DeleteNode(n:PBESENSelfBalancedTreeNode); +var Leaf,Temp:PBESENSelfBalancedTreeNode; +begin + try + // If n is not a Leaf, we first swap it out with the Leaf node that just + // precedes it. + Leaf:=n; + if assigned(n^.Left) then begin + Leaf:=n^.Left; + while assigned(Leaf^.Right) do begin + Leaf:=Leaf^.Right; + end; + end else if assigned(n^.Right) then begin + Leaf:=n^.Right; + end; + + if Leaf^.Parent=n then begin + Temp:=Leaf; + end else begin + Temp:=Leaf^.Parent; + end; + if Leaf^.Parent^.Left=Leaf then begin + Leaf^.Parent^.Left:=nil; + end else begin + Leaf^.Parent^.Right:=nil; + end; + + if n<>Leaf then begin + if n^.Parent^.Left=n then begin + n^.Parent^.Left:=Leaf; + end else begin + n^.Parent^.Right:=Leaf; + end; + Leaf^.Parent:=n^.Parent; + if assigned(n^.Left) then begin + n^.Left^.Parent:=Leaf; + end; + Leaf^.Left:=n^.Left; + if assigned(n^.Right) then begin + n^.Right^.Parent:=Leaf; + end; + Leaf^.Right:=n^.Right; + Leaf^.level:=n^.level; + end; + if n<>RootNode then begin + n^.Key:=''; + if assigned(n^.PreviousKey) then begin + n^.PreviousKey^.NextKey:=n^.NextKey; + end else if FirstKey=n then begin + FirstKey:=n^.NextKey; + end; + if assigned(n^.NextKey) then begin + n^.NextKey^.PreviousKey:=n^.PreviousKey; + end else if LastKey=n then begin + LastKey:=n^.PreviousKey; + end; + dispose(n); + end; + + while Temp<>RootNode do begin + if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin + dec(Temp^.level); + if Split(Temp) then begin + if Split(Temp) then begin + Skew(Temp^.Parent^.Parent); + end; + break; + end; + Temp:=Temp^.Parent; + end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin + break; + end else begin + Skew(Temp); + { if assigned(Temp^.Right) then begin + if assigned(Temp^.Right^.Left) then begin + Temp^.Right^.level:=Temp^.Right^.level+1; + end else begin + Temp^.Right^.level:=1; + end; + end;} + if Temp^.level>Temp^.Parent^.level then begin + Skew(Temp); + Split(Temp^.Parent^.Parent); + break; + end; + Temp:=Temp^.Parent^.Parent; + end; + end; + except + end; +end; + +procedure TBESENSelfBalancedTree.Remove(const Key:TBESENString); +var n:PBESENSelfBalancedTreeNode; +begin + try + n:=RootNode^.Left; + while assigned(n) do begin + case BESENStringCompare(Key,n^.Key) of + -1:begin + n:=n^.Left; + end; + 1:begin + n:=n^.Right; + end; + else begin + DeleteNode(n); + break; + end; + end; + end; + except + end; +end; + +procedure TBESENSelfBalancedTree.ClearNode(var Node:PBESENSelfBalancedTreeNode); +begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=''; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end else if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end else if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + ClearNode(Node^.Left); + ClearNode(Node^.Right); + dispose(Node); + Node:=nil; +end; + +procedure TBESENSelfBalancedTree.OptimizeNode(var Node:PBESENSelfBalancedTreeNode;MoreOptimize:boolean); +var Nodes:array of TBESENSelfBalancedTreeNode; + + NodeCount,NodeIndex:integer; + procedure CountNodes(Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + inc(NodeCount); + end; + procedure CollectNodes(Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CollectNodes(Node^.Left); + if NodeIndex>=length(Nodes) then begin + NodeCount:=NodeIndex+1; + SetLength(Nodes,NodeCount); + end; + Nodes[NodeIndex].Key:=Node^.Key; + Nodes[NodeIndex].Value:=Node^.Value; + Node^.Key:=''; + inc(NodeIndex); + CollectNodes(Node^.Right); + end; + procedure FreeNodes(var Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=''; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end; + if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + dispose(Node); + Node:=nil; + end; + procedure DoInsertNode(const Node:TBESENSelfBalancedTreeNode); + var n,s:PBESENSelfBalancedTreeNode; + LessThan:boolean; + begin + new(n); + n^.Key:=Node.Key; + n^.Value:=Node.Value; + n^.Parent:=nil; + n^.Left:=nil; + n^.Right:=nil; + n^.Level:=0; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=n^.Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + if not MoreOptimize then begin + RebalanceAfterLeafAdd(n); + end; + end; + procedure RepairNodes(var Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + RepairNodes(Node^.Left); + RepairNodes(Node^.Right); + if assigned(Node^.Left) and assigned(Node^.Right) then begin + Node^.Level:=Node^.Left^.Level+1; + end else begin + Node^.Level:=1; + end; + end; + procedure ReinsertNodesForRepair(LowNode,HighNode:integer); + var MiddleNode:integer; + begin + if HighNode<LowNode then begin + exit; + end; + MiddleNode:=LowNode+((HighNode-LowNode) div 2); + DoInsertNode(Nodes[MiddleNode]); + Nodes[MiddleNode].Key:=''; + ReinsertNodesForRepair(LowNode,MiddleNode-1); + ReinsertNodesForRepair(MiddleNode+1,HighNode); + end; + procedure ReinsertNodes(LowNode,HighNode:integer); + var i:integer; + begin + for i:=LowNode to HighNode do begin + DoInsertNode(Nodes[i]); + Nodes[i].Key:=''; + end; + end; +var i:integer; +begin + if not assigned(Node) then begin + exit; + end; + try + Nodes:=nil; + NodeCount:=0; + CountNodes(Node); + SetLength(Nodes,NodeCount); + NodeIndex:=0; + CollectNodes(Node); + FreeNodes(Node); + if MoreOptimize then begin + ReinsertNodesForRepair(0,length(Nodes)-1); + RepairNodes(RootNode^.Left); + end else begin + ReinsertNodes(0,length(Nodes)-1); + end; + for i:=0 to length(Nodes)-1 do begin + Nodes[i].Key:=''; + end; + SetLength(Nodes,0); + except + end; +end; + +function TBESENSelfBalancedTree.Find(const Key:TBESENString;var Value:TBESENSelfBalancedTreeValue):boolean; +var n:PBESENSelfBalancedTreeNode; +begin + n:=FindNode(Key); + if assigned(n) then begin + Value:=n^.Value; + result:=true; + end else begin + fillchar(Value,sizeof(TBESENSelfBalancedTreeValue),#0); + result:=false; + end; +end; + +procedure TBESENSelfBalancedTree.Optimize; +begin + OptimizeNode(RootNode^.Left,true); +end; + +function TBESENSelfBalancedTree.Keys:TBESENSelfBalancedTreeKeys; +var CurrentNode:PBESENSelfBalancedTreeNode; + Count:integer; +begin + result:=nil; + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; + SetLength(result,Count); + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + result[Count]:=CurrentNode^.Key; + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; +end; + +function TBESENSelfBalancedTree.GetValue(Key:TBESENString):TBESENSelfBalancedTreeValue; +begin + Find(Key,result); +end; + +procedure TBESENSelfBalancedTree.SetValue(Key:TBESENString;Value:TBESENSelfBalancedTreeValue); +begin + Insert(Key,Value); +end; + +end. diff --git a/3rd/besen/src/BESENShell.cfg b/3rd/besen/src/BESENShell.cfg new file mode 100644 index 000000000..e9c1cc14e --- /dev/null +++ b/3rd/besen/src/BESENShell.cfg @@ -0,0 +1,38 @@ +-$A8 +-$B- +-$C+ +-$D+ +-$E- +-$F- +-$G+ +-$H+ +-$I+ +-$J- +-$K- +-$L+ +-$M- +-$N+ +-$O+ +-$P+ +-$Q- +-$R- +-$S- +-$T- +-$U- +-$V+ +-$W- +-$X+ +-$YD +-$Z1 +-cg +-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +-H+ +-W+ +-M +-$M16384,1048576 +-K$00400000 +-LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" +-LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" +-w-UNSAFE_TYPE +-w-UNSAFE_CODE +-w-UNSAFE_CAST diff --git a/3rd/besen/src/BESENShell.dof b/3rd/besen/src/BESENShell.dof new file mode 100644 index 000000000..b1bb99770 --- /dev/null +++ b/3rd/besen/src/BESENShell.dof @@ -0,0 +1,136 @@ +[FileVersion] +Version=7.0 +[Compiler] +A=8 +B=0 +C=1 +D=1 +E=0 +F=0 +G=1 +H=1 +I=1 +J=0 +K=0 +L=1 +M=0 +N=1 +O=1 +P=1 +Q=0 +R=0 +S=0 +T=0 +U=0 +V=1 +W=0 +X=1 +Y=1 +Z=1 +ShowHints=1 +ShowWarnings=1 +UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; +NamespacePrefix= +SymbolDeprecated=1 +SymbolLibrary=1 +SymbolPlatform=1 +UnitLibrary=1 +UnitPlatform=1 +UnitDeprecated=1 +HResultCompat=1 +HidingMember=1 +HiddenVirtual=1 +Garbage=1 +BoundsError=1 +ZeroNilCompat=1 +StringConstTruncated=1 +ForLoopVarVarPar=1 +TypedConstVarPar=1 +AsgToTypedConst=1 +CaseLabelRange=1 +ForVariable=1 +ConstructingAbstract=1 +ComparisonFalse=1 +ComparisonTrue=1 +ComparingSignedUnsigned=1 +CombiningSignedUnsigned=1 +UnsupportedConstruct=1 +FileOpen=1 +FileOpenUnitSrc=1 +BadGlobalSymbol=1 +DuplicateConstructorDestructor=1 +InvalidDirective=1 +PackageNoLink=1 +PackageThreadVar=1 +ImplicitImport=1 +HPPEMITIgnored=1 +NoRetVal=1 +UseBeforeDef=1 +ForLoopVarUndef=1 +UnitNameMismatch=1 +NoCFGFileFound=1 +MessageDirective=1 +ImplicitVariants=1 +UnicodeToLocale=1 +LocaleToUnicode=1 +ImagebaseMultiple=1 +SuspiciousTypecast=1 +PrivatePropAccessor=1 +UnsafeType=0 +UnsafeCode=0 +UnsafeCast=0 +[Linker] +MapFile=0 +OutputObjs=0 +ConsoleApp=1 +DebugInfo=0 +RemoteSymbols=0 +MinStackSize=16384 +MaxStackSize=1048576 +ImageBase=4194304 +ExeDescription= +[Directories] +OutputDir= +UnitOutputDir= +PackageDLLOutputDir= +PackageDCPOutputDir= +SearchPath= +Packages= +Conditionals= +DebugSourceDirs= +UsePackages=0 +[Parameters] +RunParams= +HostApplication= +Launcher= +UseLauncher=0 +DebugCWD= +[Language] +ActiveLang= +ProjectLang= +RootDir= +[Version Info] +IncludeVerInfo=0 +AutoIncBuild=0 +MajorVer=1 +MinorVer=0 +Release=0 +Build=0 +Debug=0 +PreRelease=0 +Special=0 +Private=0 +DLL=0 +Locale=1031 +CodePage=1252 +[Version Info Keys] +CompanyName= +FileDescription= +FileVersion=1.0.0.0 +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion=1.0.0.0 +Comments= diff --git a/3rd/besen/src/BESENShell.dpr b/3rd/besen/src/BESENShell.dpr new file mode 100644 index 000000000..f0e0ddc0a --- /dev/null +++ b/3rd/besen/src/BESENShell.dpr @@ -0,0 +1,942 @@ +program BESENShell; +{$i BESEN.inc} +{$ifdef win32} + {$apptype console} +{$endif} + +uses +{$ifdef fpc} +{$ifdef win32} + Windows, +{$endif} +{$else} +{$ifdef win32} +// FastMM4, + Windows, +{$endif} +{$endif} + SysUtils, + Classes, + BESEN in 'BESEN.pas', + BESENCodeSnapshot in 'BESENCodeSnapshot.pas', + BESENVersionConstants in 'BESENVersionConstants.pas', + BESENConstants in 'BESENConstants.pas', + BESENValueContainer in 'BESENValueContainer.pas', + BESENUnicodeTables in 'BESENUnicodeTables.pas', + BESENStringUtils in 'BESENStringUtils.pas', + BESENStringTree in 'BESENStringTree.pas', + BESENStringList in 'BESENStringList.pas', + BESENSelfBalancedTree in 'BESENSelfBalancedTree.pas', + BESENScope in 'BESENScope.pas', + BESENRegExpCache in 'BESENRegExpCache.pas', + BESENRandomGenerator in 'BESENRandomGenerator.pas', + BESENPointerSelfBalancedTree in 'BESENPointerSelfBalancedTree.pas', + BESENPointerList in 'BESENPointerList.pas', + BESENParser in 'BESENParser.pas', + BESENOpcodes in 'BESENOpcodes.pas', + BESENObjectThrowTypeErrorFunction in 'BESENObjectThrowTypeErrorFunction.pas', + BESENObjectStringPrototype in 'BESENObjectStringPrototype.pas', + BESENObjectStringConstructor in 'BESENObjectStringConstructor.pas', + BESENObjectString in 'BESENObjectString.pas', + BESENObjectRegExpPrototype in 'BESENObjectRegExpPrototype.pas', + BESENObjectRegExpConstructor in 'BESENObjectRegExpConstructor.pas', + BESENObjectRegExp in 'BESENObjectRegExp.pas', + BESENObjectPrototype in 'BESENObjectPrototype.pas', + BESENObjectPropertyDescriptor in 'BESENObjectPropertyDescriptor.pas', + BESENObjectNumberPrototype in 'BESENObjectNumberPrototype.pas', + BESENObjectNumberConstructor in 'BESENObjectNumberConstructor.pas', + BESENObjectNumber in 'BESENObjectNumber.pas', + BESENObjectNativeFunction in 'BESENObjectNativeFunction.pas', + BESENObjectMath in 'BESENObjectMath.pas', + BESENObjectJSON in 'BESENObjectJSON.pas', + BESENObjectGlobal in 'BESENObjectGlobal.pas', + BESENObjectFunctionPrototype in 'BESENObjectFunctionPrototype.pas', + BESENObjectFunctionConstructor in 'BESENObjectFunctionConstructor.pas', + BESENObjectFunctionArguments in 'BESENObjectFunctionArguments.pas', + BESENObjectFunction in 'BESENObjectFunction.pas', + BESENObjectErrorPrototype in 'BESENObjectErrorPrototype.pas', + BESENObjectErrorConstructor in 'BESENObjectErrorConstructor.pas', + BESENObjectError in 'BESENObjectError.pas', + BESENObjectEnvironmentRecord in 'BESENObjectEnvironmentRecord.pas', + BESENObjectDeclaredFunction in 'BESENObjectDeclaredFunction.pas', + BESENObjectDatePrototype in 'BESENObjectDatePrototype.pas', + BESENObjectDateConstructor in 'BESENObjectDateConstructor.pas', + BESENObjectDate in 'BESENObjectDate.pas', + BESENObjectConstructor in 'BESENObjectConstructor.pas', + BESENObjectBooleanPrototype in 'BESENObjectBooleanPrototype.pas', + BESENObjectBooleanConstructor in 'BESENObjectBooleanConstructor.pas', + BESENObjectBoolean in 'BESENObjectBoolean.pas', + BESENObjectBindingFunction in 'BESENObjectBindingFunction.pas', + BESENObjectArrayPrototype in 'BESENObjectArrayPrototype.pas', + BESENObjectArrayConstructor in 'BESENObjectArrayConstructor.pas', + BESENObjectArray in 'BESENObjectArray.pas', + BESENObjectArgSetterFunction in 'BESENObjectArgSetterFunction.pas', + BESENObjectArgGetterFunction in 'BESENObjectArgGetterFunction.pas', + BESENObject in 'BESENObject.pas', + BESENNumberUtils in 'BESENNumberUtils.pas', + BESENNativeObject in 'BESENNativeObject.pas', + BESENNativeCodeMemoryManager in 'BESENNativeCodeMemoryManager.pas', + BESENLocale in 'BESENLocale.pas', + BESENLexicalEnvironment in 'BESENLexicalEnvironment.pas', + BESENLexer in 'BESENLexer.pas', + BESENKeyIDManager in 'BESENKeyIDManager.pas', + BESENIntegerList in 'BESENIntegerList.pas', + BESENInt64SelfBalancedTree in 'BESENInt64SelfBalancedTree.pas', + BESENHashUtils in 'BESENHashUtils.pas', + BESENHashMap in 'BESENHashMap.pas', + BESENGlobals in 'BESENGlobals.pas', + BESENGarbageCollector in 'BESENGarbageCollector.pas', + BESENEvalCacheItem in 'BESENEvalCacheItem.pas', + BESENEvalCache in 'BESENEvalCache.pas', + BESENErrors in 'BESENErrors.pas', + BESENEnvironmentRecord in 'BESENEnvironmentRecord.pas', + BESENDoubleList in 'BESENDoubleList.pas', + BESENDecompiler in 'BESENDecompiler.pas', + BESENDeclarativeEnvironmentRecord in 'BESENDeclarativeEnvironmentRecord.pas', + BESENDateUtils in 'BESENDateUtils.pas', + BESENCompiler in 'BESENCompiler.pas', + BESENCollectorObject in 'BESENCollectorObject.pas', + BESENCollector in 'BESENCollector.pas', + BESENCharset in 'BESENCharset.pas', + BESENBaseObject in 'BESENBaseObject.pas', + BESENArrayUtils in 'BESENArrayUtils.pas', + BESENTypes in 'BESENTypes.pas', + BESENUtils in 'BESENUtils.pas', + BESENValue in 'BESENValue.pas', + BESENRegExp in 'BESENRegExp.pas', + BESENCode in 'BESENCode.pas', + BESENASTNodes in 'BESENASTNodes.pas', + BESENCodeContext in 'BESENCodeContext.pas', + BESENCodeGeneratorContext in 'BESENCodeGeneratorContext.pas', + BESENContext in 'BESENContext.pas', + BESENObjectConsole in 'BESENObjectConsole.pas'; + +type TShellFunctions=class + procedure RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); + procedure NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + + TFileObject=class(TBESENNativeObject) + private + fFileName:TBESENString; + fFileStream:TFileStream; + protected + procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); override; + procedure InitializeObject; override; + procedure FinalizeObject; override; + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); override; + destructor Destroy; override; + published + procedure close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + property fileName:TBESENString read fFileName write fFileName; + end; + +var Instance:TBESEN; + ShellFunctions:TShellFunctions; + DoExit:boolean; + +constructor TFileObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + fFileStream:=nil; +end; + +destructor TFileObject.Destroy; +begin + BesenFreeAndNil(fFileStream); + inherited Destroy; +end; + +procedure TFileObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); +var s:string; + Mode:longword; +begin + inherited ConstructObject(ThisArgument,Arguments,CountArguments); + if CountArguments=0 then begin + raise EBESENError.Create('FileError','Too few arguments'); + end else begin + fFileName:=TBESEN(Instance).ToStr(Arguments^[0]^); + if FileExists(fFileName) then begin + Mode:=fmOpenReadWrite or fmShareExclusive; + end else begin + Mode:=fmCreate or fmShareDenyRead; + end; + if CountArguments>1 then begin + s:=TBESEN(Instance).ToStr(Arguments^[1]^); + if s='c' then begin + Mode:=fmCreate or fmShareDenyRead; + end else if s='r' then begin + Mode:=fmOpenRead or fmShareDenyWrite; + end else if s='rw' then begin + Mode:=fmOpenReadWrite or fmShareExclusive; + end else if s='w' then begin + if FileExists(fFileName) then begin + Mode:=fmOpenWrite or fmShareDenyRead; + end else begin + Mode:=fmCreate or fmShareDenyRead; + end; + end; + end; +{$ifdef BESENSingleStringType} + fFileStream:=TFileStream.Create(fFileName,Mode); +{$else} + fFileStream:=TFileStream.Create(String(BESENEncodeString(BESENUTF16ToUTF8(fFileName),UTF_8,BESENLocaleCharset)),Mode); +{$endif} + end; + s:=''; +end; + +procedure TFileObject.InitializeObject; +begin + inherited InitializeObject; + fFileName:=''; + fFileStream:=nil; +end; + +procedure TFileObject.FinalizeObject; +begin + BesenFreeAndNil(fFileStream); + inherited FinalizeObject; +end; + +procedure TFileObject.close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + BesenFreeAndNil(fFileStream); +end; + +procedure TFileObject.read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var l,ms:int64; + s:string; +begin + s:=''; + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ms:=fFileStream.Size-fFileStream.Position; + if CountArguments=0 then begin + l:=ms; + end else begin + if Arguments^[0]^.ValueType=bvtUNDEFINED then begin + l:=ms; + end else begin + l:=TBESEN(Instance).ToInt(Arguments^[0]^); + if l>ms then begin + l:=ms; + end; + end; + end; + SetLength(s,l); + if l>0 then begin + fFileStream.Read(s[1],l); + end; + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:=s; + SetLength(s,0); + end; +end; + +procedure TFileObject.write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var l:int64; + s:string; +begin + s:=''; + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + if CountArguments>0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=0; + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + l:=length(s); + if l>0 then begin + ResultValue.Num:=fFileStream.Write(s[1],l); + end; + SetLength(s,0); + end; + end; +end; + +procedure TFileObject.seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var l,ms:int64; +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ms:=fFileStream.Size; + if CountArguments=0 then begin + l:=fFileStream.Position; + end else begin + if Arguments^[0]^.ValueType=bvtUNDEFINED then begin + l:=fFileStream.Position; + end else begin + l:=TBESEN(Instance).ToInt(Arguments^[0]^); + if l>ms then begin + l:=ms; + end; + end; + end; + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=fFileStream.Seek(l,soFromBeginning); + end; +end; + +procedure TFileObject.position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=fFileStream.Position; + end; +end; + +procedure TFileObject.eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=fFileStream.Position<fFileStream.Size; + end; +end; + +procedure TFileObject.flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin +{$ifdef win32} + Windows.FlushFileBuffers(fFileStream.Handle); +{$endif} + end; +end; + +procedure TShellFunctions.RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); +begin + if NewLine then begin + writeln(Data); + end else begin + write(Data); + end; +end; + +procedure TShellFunctions.NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if CountArguments>0 then begin + Instance.RegExpDebug:=Instance.ToUINT32(Arguments^[0]^); + end; +end; + +procedure TShellFunctions.NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=Instance.RegExpDebug; +end; + +procedure TShellFunctions.NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if CountArguments>0 then begin + Instance.RegExpTimeOutSteps:=Instance.ToINT(Arguments^[0]^); + end; +end; + +procedure TShellFunctions.NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=Instance.RegExpTimeOutSteps; +end; + +procedure TShellFunctions.NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var i:integer; + v:PBESENValue; + fOutput:widestring; + procedure writeit(s:widestring); + begin + fOutput:=fOutput+s; + end; +begin + fOutput:=''; + ResultValue.ValueType:=bvtUNDEFINED; + for i:=0 to CountArguments-1 do begin + v:=Arguments^[i]; + case v^.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v^.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v^.Num)); + end; + bvtSTRING:begin + writeit(v^.Str); + end; + bvtOBJECT:begin + writeit(TBESEN(Instance).ToStr(v^)); + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; + end; +{$ifdef Delphi2009AndUp} + writeln(fOutput); +{$else} + writeln(BESENEncodeString(BESENUTF16ToUTF8(fOutput),UTF_8,BESENLocaleCharset)); +{$endif} +end; + +procedure TShellFunctions.NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + NativePrint(ThisArgument,Arguments,CountArguments,ResultValue); + writeln; +end; + +procedure TShellFunctions.NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:string; +begin + readln(s); +{$ifdef Delphi2009AndUp} + ResultValue:=BESENStringValue(s); +{$else} + ResultValue:=BESENStringLocaleCharsetValue(s); +{$endif} +end; + +procedure TShellFunctions.NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + NativePrintLn(ThisArgument,Arguments,CountArguments,ResultValue); +end; + +procedure TShellFunctions.NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var i:integer; + v:PBESENValue; + ss:widestring; + procedure writeit(s:widestring); + begin + ss:=ss+s; + end; +begin + ss:=''; + ResultValue.ValueType:=bvtUNDEFINED; + for i:=0 to CountArguments-1 do begin + v:=Arguments^[i]; + case v^.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v^.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v^.Num)); + end; + bvtSTRING:begin + writeit(v^.Str); + end; + bvtOBJECT:begin + writeit(TBESEN(Instance).ToStr(v^)); + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; + end; +{$ifdef Delphi2009AndUp} + writeln(ss); +{$else} + writeln(BESENEncodeString(BESENUTF16ToUTF8(ss),UTF_8,BESENLocaleCharset)); +{$endif} +end; + +procedure TShellFunctions.NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ss:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + s:string; +begin + ss:=''; + try + if CountArguments>0 then begin +{$ifdef BESENSingleStringType} + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); +{$else} + ss:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + end else begin + ss:=''; + end; +(* if CountArguments>1 then begin +{$ifdef BESENSingleStringType} + s:=TBESEN(Instance).ToStr(Arguments^[1]^); +{$else} + s:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)),UTF_8,BESENLocaleCharset); +{$endif} + end else begin + s:=''; + end;*) + write(ss); + readln(s); +{$ifdef Delphi2009AndUp} + ResultValue:=BESENStringValue(s); +{$else} + ResultValue:=BESENStringLocaleCharsetValue(s); +{$endif} + finally + end; +end; + +procedure TShellFunctions.NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + DoExit:=true; +end; + +procedure TShellFunctions.NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + fm:byte; + f:file; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>0 then begin +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + Content:=''; + fm:=filemode; + filemode:=0; + assignfile(f,String(FileName)); + {$i-}reset(f,1);{$i+}; + if ioresult=0 then begin + SetLength(Content,filesize(f)); + if length(Content)>0 then begin + {$i-}blockread(f,Content[1],length(Content));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); + exit; + end; + end; + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:={$ifndef BESENSingleStringType}BESENUTF8ToUTF16(BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType})){$endif}; + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + end else begin + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); + end; + end else begin + raise EBESENError.Create('FileError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + fm:byte; + f:file; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>1 then begin +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); + Content:=TBESEN(Instance).ToStr(Arguments^[1]^); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); + Content:=#$ef#$bb#$bf+BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)); +{$endif} + fm:=filemode; + filemode:=2; + assignfile(f,String(FileName)); + {$i-}rewrite(f,1);{$i+}; + if ioresult=0 then begin + if length(Content)>0 then begin + {$i-}blockwrite(f,Content[1],length(Content));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); + exit; + end; + end; + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + end else begin + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); + end; + end else begin + raise EBESENError.Create('FileError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const BoolStr:array[boolean] of {$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}=('false','true'); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + SearchRec:TSearchRec; + Count:integer; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>0 then begin + Content:='['; +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + if FindFirst(String(FileName),faAnyFile or faDirectory,SearchRec)=0 then begin + Count:=0; + repeat + if Count>0 then begin + Content:=Content+','; + end; + Content:=Content+'{'; + Content:=Content+'"name":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENJSONStringQuote(BESENUTF8ToUTF16(BESENEncodeString(AnsiString(SearchRec.Name),BESENLocaleCharset,UTF_8))))+','; + Content:=Content+'"size":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(IntToStr(SearchRec.Size))+','; + Content:=Content+'"time":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENFloatToStr(BESENDateTimeToBESENDate(FileDateToDateTime(SearchRec.Time))))+','; + Content:=Content+'"flags":{'; + Content:=Content+'"hidden":'+BoolStr[(SearchRec.Attr and faHidden)<>0]+','; + Content:=Content+'"systemFile":'+BoolStr[(SearchRec.Attr and faSysFile)<>0]+','; + Content:=Content+'"volumeID":'+BoolStr[(SearchRec.Attr and faVolumeID)<>0]+','; + Content:=Content+'"directory":'+BoolStr[(SearchRec.Attr and faDirectory)<>0]+','; + Content:=Content+'"archive":'+BoolStr[(SearchRec.Attr and faArchive)<>0]+''; + Content:=Content+'}}'; + inc(Count); + until FindNext(SearchRec)<>0; + FindClose(SearchRec); + end; + Content:=Content+']'; + ResultValue:=TBESEN(Instance).JSONEval(Content); + end else begin + raise EBESENError.Create('DirectoryError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + fm:byte; + f:file; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>0 then begin +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + Content:=''; + fm:=filemode; + filemode:=0; + assignfile(f,string(FileName)); + {$i-}reset(f,1);{$i+}; + if ioresult=0 then begin + SetLength(Content,filesize(f)); + if length(Content)>0 then begin + {$i-}blockread(f,Content[1],length(Content));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); + exit; + end; + end; + ResultValue:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType}){$endif}); + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + end else begin + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); + end; + end else begin + raise EBESENError.Create('FileError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + TBESEN(Instance).GarbageCollector.CollectAll; +end; + +procedure TShellFunctions.NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:='BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'; +end; + +procedure Print(const v:TBESENValue); +var fOutput:widestring; + procedure writeit(s:widestring); + begin + fOutput:=fOutput+s; + end; +begin + fOutput:=''; + case v.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v.Num)); + end; + bvtSTRING:begin + writeit(v.Str); + end; + bvtOBJECT:begin +{$ifdef BESENSingleStringType} + writeit(TBESEN(Instance).ToStr(v)); +{$else} + writeit(WideString(BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(v)),UTF_8,BESENLocaleCharset))); +{$endif} + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; +{$ifdef Delphi2009AndUp} + writeln(fOutput); +{$else} + writeln(BESENUTF16ToUTF8(fOutput)); +{$endif} +end; + +var FileName,s:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + ss:widestring; + v:TBESENValue; + i:integer; + c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}; + Compatibility:longword; + ObjDocument,ObjNavigator,ObjShell,ObjWindow:TBESENObject; +begin +{$ifdef cpu386} + Set8087CW($133f); +{$endif} +{$ifdef cpuamd64} + Set8087CW($133f); +{$endif} + DoExit:=false; + FileName:=''; + Compatibility:=COMPAT_BESEN; + if paramcount>0 then begin + for i:=1 to paramcount do begin + s:={$ifndef BESENSingleStringType}AnsiString({$endif}paramstr(i){$ifndef BESENSingleStringType}){$endif}; + if length(s)>0 then begin + case s[1] of + '-','+','/':begin + c:=s[1]; + if c='-' then begin + end; + delete(s,1,1); + if (s='?') or (s='h') or (s='help') then begin + writeln('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'); + writeln('Usage: ',ExtractFileName(paramstr(0)),' [filename] [options]'); + writeln('Options: +help = This help text'); + writeln(' +javascript = Enable facile javascript compatibility mode'); + writeln(' +sgmlcom = Treat ''<!--'' as a ''//'' comment'); + writeln(' +unsafeutf8 = Accept ''valid but insecure'' UTF8'); + DoExit:=true; + end else if s='javascript' then begin + Compatibility:=Compatibility or COMPAT_JS; + end else if s='sgmlcom' then begin + Compatibility:=Compatibility or COMPAT_SGMLCOM; + end else if s='unsafeutf8' then begin + Compatibility:=Compatibility or COMPAT_UTF8_UNSAFE; + end; + end; + else begin + FileName:=s; + end; + end; + end; + end; + end; + ShellFunctions:=TShellFunctions.Create; + Instance:=TBESEN.Create(Compatibility); + TBESEN(Instance).RegExpDebugOutputHook:=ShellFunctions.RegExpDebugOutputHook; + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); + TBESEN(Instance).RegisterNativeObject('File',TFileObject); + + ObjDocument:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ObjDocument); + TBESEN(Instance).ObjectGlobal.OverwriteData('document',BESENObjectValue(ObjDocument),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjDocument.RegisterNativeFunction('write',ShellFunctions.NativePrint,1,[]); + ObjDocument.RegisterNativeFunction('writeln',ShellFunctions.NativePrintLn,1,[]); + + ObjNavigator:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ObjNavigator); + TBESEN(Instance).ObjectGlobal.OverwriteData('navigator',BESENObjectValue(ObjNavigator),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjNavigator.OverwriteData('userAgent',BESENStringValue('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux'),[bopaWRITABLE,bopaCONFIGURABLE]); + + ObjShell:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ObjShell); + TBESEN(Instance).ObjectGlobal.OverwriteData('Shell',BESENObjectValue(ObjShell),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjShell.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); + ObjShell.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); + ObjShell.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); + ObjShell.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); + ObjShell.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); + ObjShell.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); + ObjShell.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); + ObjShell.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); + ObjShell.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); + ObjShell.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); + ObjShell.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); + ObjShell.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); + ObjShell.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); + ObjShell.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); + ObjShell.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); + ObjShell.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); + ObjShell.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); + + ObjWindow:=TBESEN(Instance).ObjectGlobal; + TBESEN(Instance).ObjectGlobal.OverwriteData('window',BESENObjectValue(ObjWindow),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjDocument.OverwriteData('window',BESENObjectValue(TBESEN(Instance).ObjectGlobal),[bopaWRITABLE,bopaCONFIGURABLE]); + + try + try + if not DoExit then begin + TBESEN(Instance).InjectObject('console',{$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}BESENObjectConsoleSource{$ifndef BESENSingleStringType}){$endif}); + end; + except + on e:EBESENError do begin + writeln(e.Name,': ',e.Message); + end; + on e:exception do begin + writeln('Exception: ',e.Message); + end; + end; + if length(FileName)>0 then begin + try + if not DoExit then begin + v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}BESENGetFileContent(FileName){$ifndef BESENSingleStringType}){$endif}); + Print(v); + end; + except + on e:EBESENError do begin + writeln(e.Name,': ',e.Message); + end; + on e:exception do begin + writeln('Exception: ',e.Message); + end; + end; + end else begin + v.ValueType:=bvtUNDEFINED; + v.Obj:=nil; + while not DoExit do begin + write('>'); + readln(ss); + try + v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}ss{$ifndef BESENSingleStringType}){$endif}); + if not DoExit then begin + Print(v); + v.ValueType:=bvtUNDEFINED; + v.Obj:=nil; + TBESEN(Instance).GarbageCollector.CollectAll; + end; + except + on e:EBESENError do begin + writeln(e.Name,'(',TBESEN(Instance).LineNumber,'): ',e.Message); + end; + on e:exception do begin + writeln('Exception(',TBESEN(Instance).LineNumber,'): ',e.Message); + end; + end; + end; + end; + except + on e:exception do begin + writeln(e.Message); + end; + end; + FileName:=''; + s:=''; + ShellFunctions.Destroy; + TBESEN(Instance).Destroy; +end. diff --git a/3rd/besen/src/BESENShell.dproj b/3rd/besen/src/BESENShell.dproj new file mode 100644 index 000000000..0c8081b54 --- /dev/null +++ b/3rd/besen/src/BESENShell.dproj @@ -0,0 +1,214 @@ +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectGuid>{64B522E5-F0C1-47B8-BF9A-FB051D6D623B}</ProjectGuid> + <MainSource>BESENShell.dpr</MainSource> + <Base>True</Base> + <Config Condition="'$(Config)'==''">Release</Config> + <TargetedPlatforms>1</TargetedPlatforms> + <AppType>Console</AppType> + <FrameworkType>None</FrameworkType> + <ProjectVersion>14.3</ProjectVersion> + <Platform Condition="'$(Platform)'==''">Win32</Platform> + </PropertyGroup> + <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> + <Base_Win32>true</Base_Win32> + <CfgParent>Base</CfgParent> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> + <Cfg_1>true</Cfg_1> + <CfgParent>Base</CfgParent> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> + <Cfg_2>true</Cfg_2> + <CfgParent>Base</CfgParent> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="'$(Base)'!=''"> + <DCC_ImageBase>00400000</DCC_ImageBase> + <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)</DCC_Namespace> + <DCC_SymbolReferenceInfo>1</DCC_SymbolReferenceInfo> + <DCC_F>false</DCC_F> + <DCC_K>false</DCC_K> + <VerInfo_Locale>1031</VerInfo_Locale> + <DCC_N>true</DCC_N> + <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> + <DCC_E>false</DCC_E> + <DCC_S>false</DCC_S> + </PropertyGroup> + <PropertyGroup Condition="'$(Base_Win32)'!=''"> + <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> + <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> + <VerInfo_Locale>1033</VerInfo_Locale> + </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_1)'!=''"> + <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> + <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> + <DCC_DebugInformation>false</DCC_DebugInformation> + <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> + </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_2)'!=''"> + <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> + <DCC_Optimize>false</DCC_Optimize> + <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> + </PropertyGroup> + <ItemGroup> + <DelphiCompile Include="$(MainSource)"> + <MainSource>MainSource</MainSource> + </DelphiCompile> + <DCCReference Include="BESEN.pas"/> + <DCCReference Include="BESENCodeSnapshot.pas"/> + <DCCReference Include="BESENVersionConstants.pas"/> + <DCCReference Include="BESENConstants.pas"/> + <DCCReference Include="BESENValueContainer.pas"/> + <DCCReference Include="BESENUnicodeTables.pas"/> + <DCCReference Include="BESENStringUtils.pas"/> + <DCCReference Include="BESENStringTree.pas"/> + <DCCReference Include="BESENStringList.pas"/> + <DCCReference Include="BESENSelfBalancedTree.pas"/> + <DCCReference Include="BESENScope.pas"/> + <DCCReference Include="BESENRegExpCache.pas"/> + <DCCReference Include="BESENRandomGenerator.pas"/> + <DCCReference Include="BESENPointerSelfBalancedTree.pas"/> + <DCCReference Include="BESENPointerList.pas"/> + <DCCReference Include="BESENParser.pas"/> + <DCCReference Include="BESENOpcodes.pas"/> + <DCCReference Include="BESENObjectThrowTypeErrorFunction.pas"/> + <DCCReference Include="BESENObjectStringPrototype.pas"/> + <DCCReference Include="BESENObjectStringConstructor.pas"/> + <DCCReference Include="BESENObjectString.pas"/> + <DCCReference Include="BESENObjectRegExpPrototype.pas"/> + <DCCReference Include="BESENObjectRegExpConstructor.pas"/> + <DCCReference Include="BESENObjectRegExp.pas"/> + <DCCReference Include="BESENObjectPrototype.pas"/> + <DCCReference Include="BESENObjectPropertyDescriptor.pas"/> + <DCCReference Include="BESENObjectNumberPrototype.pas"/> + <DCCReference Include="BESENObjectNumberConstructor.pas"/> + <DCCReference Include="BESENObjectNumber.pas"/> + <DCCReference Include="BESENObjectNativeFunction.pas"/> + <DCCReference Include="BESENObjectMath.pas"/> + <DCCReference Include="BESENObjectJSON.pas"/> + <DCCReference Include="BESENObjectGlobal.pas"/> + <DCCReference Include="BESENObjectFunctionPrototype.pas"/> + <DCCReference Include="BESENObjectFunctionConstructor.pas"/> + <DCCReference Include="BESENObjectFunctionArguments.pas"/> + <DCCReference Include="BESENObjectFunction.pas"/> + <DCCReference Include="BESENObjectErrorPrototype.pas"/> + <DCCReference Include="BESENObjectErrorConstructor.pas"/> + <DCCReference Include="BESENObjectError.pas"/> + <DCCReference Include="BESENObjectEnvironmentRecord.pas"/> + <DCCReference Include="BESENObjectDeclaredFunction.pas"/> + <DCCReference Include="BESENObjectDatePrototype.pas"/> + <DCCReference Include="BESENObjectDateConstructor.pas"/> + <DCCReference Include="BESENObjectDate.pas"/> + <DCCReference Include="BESENObjectConstructor.pas"/> + <DCCReference Include="BESENObjectBooleanPrototype.pas"/> + <DCCReference Include="BESENObjectBooleanConstructor.pas"/> + <DCCReference Include="BESENObjectBoolean.pas"/> + <DCCReference Include="BESENObjectBindingFunction.pas"/> + <DCCReference Include="BESENObjectArrayPrototype.pas"/> + <DCCReference Include="BESENObjectArrayConstructor.pas"/> + <DCCReference Include="BESENObjectArray.pas"/> + <DCCReference Include="BESENObjectArgSetterFunction.pas"/> + <DCCReference Include="BESENObjectArgGetterFunction.pas"/> + <DCCReference Include="BESENObject.pas"/> + <DCCReference Include="BESENNumberUtils.pas"/> + <DCCReference Include="BESENNativeObject.pas"/> + <DCCReference Include="BESENNativeCodeMemoryManager.pas"/> + <DCCReference Include="BESENLocale.pas"/> + <DCCReference Include="BESENLexicalEnvironment.pas"/> + <DCCReference Include="BESENLexer.pas"/> + <DCCReference Include="BESENKeyIDManager.pas"/> + <DCCReference Include="BESENIntegerList.pas"/> + <DCCReference Include="BESENInt64SelfBalancedTree.pas"/> + <DCCReference Include="BESENHashUtils.pas"/> + <DCCReference Include="BESENHashMap.pas"/> + <DCCReference Include="BESENGlobals.pas"/> + <DCCReference Include="BESENGarbageCollector.pas"/> + <DCCReference Include="BESENEvalCacheItem.pas"/> + <DCCReference Include="BESENEvalCache.pas"/> + <DCCReference Include="BESENErrors.pas"/> + <DCCReference Include="BESENEnvironmentRecord.pas"/> + <DCCReference Include="BESENDoubleList.pas"/> + <DCCReference Include="BESENDecompiler.pas"/> + <DCCReference Include="BESENDeclarativeEnvironmentRecord.pas"/> + <DCCReference Include="BESENDateUtils.pas"/> + <DCCReference Include="BESENCompiler.pas"/> + <DCCReference Include="BESENCollectorObject.pas"/> + <DCCReference Include="BESENCollector.pas"/> + <DCCReference Include="BESENCharset.pas"/> + <DCCReference Include="BESENBaseObject.pas"/> + <DCCReference Include="BESENArrayUtils.pas"/> + <DCCReference Include="BESENTypes.pas"/> + <DCCReference Include="BESENUtils.pas"/> + <DCCReference Include="BESENValue.pas"/> + <DCCReference Include="BESENRegExp.pas"/> + <DCCReference Include="BESENCode.pas"/> + <DCCReference Include="BESENASTNodes.pas"/> + <DCCReference Include="BESENCodeContext.pas"/> + <DCCReference Include="BESENCodeGeneratorContext.pas"/> + <DCCReference Include="BESENContext.pas"/> + <DCCReference Include="BESENObjectConsole.pas"/> + <BuildConfiguration Include="Debug"> + <Key>Cfg_2</Key> + <CfgParent>Base</CfgParent> + </BuildConfiguration> + <BuildConfiguration Include="Base"> + <Key>Base</Key> + </BuildConfiguration> + <BuildConfiguration Include="Release"> + <Key>Cfg_1</Key> + <CfgParent>Base</CfgParent> + </BuildConfiguration> + </ItemGroup> + <ProjectExtensions> + <Borland.Personality>Delphi.Personality.12</Borland.Personality> + <Borland.ProjectType>VCLApplication</Borland.ProjectType> + <BorlandProject> + <Delphi.Personality> + <Source> + <Source Name="MainSource">BESENShell.dpr</Source> + </Source> + <VersionInfo> + <VersionInfo Name="IncludeVerInfo">False</VersionInfo> + <VersionInfo Name="AutoIncBuild">False</VersionInfo> + <VersionInfo Name="MajorVer">1</VersionInfo> + <VersionInfo Name="MinorVer">0</VersionInfo> + <VersionInfo Name="Release">0</VersionInfo> + <VersionInfo Name="Build">0</VersionInfo> + <VersionInfo Name="Debug">False</VersionInfo> + <VersionInfo Name="PreRelease">False</VersionInfo> + <VersionInfo Name="Special">False</VersionInfo> + <VersionInfo Name="Private">False</VersionInfo> + <VersionInfo Name="DLL">False</VersionInfo> + <VersionInfo Name="Locale">1031</VersionInfo> + <VersionInfo Name="CodePage">1252</VersionInfo> + </VersionInfo> + <VersionInfoKeys> + <VersionInfoKeys Name="CompanyName"/> + <VersionInfoKeys Name="FileDescription"/> + <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> + <VersionInfoKeys Name="InternalName"/> + <VersionInfoKeys Name="LegalCopyright"/> + <VersionInfoKeys Name="LegalTrademarks"/> + <VersionInfoKeys Name="OriginalFilename"/> + <VersionInfoKeys Name="ProductName"/> + <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> + <VersionInfoKeys Name="Comments"/> + </VersionInfoKeys> + </Delphi.Personality> + <Platforms> + <Platform value="OSX32">False</Platform> + <Platform value="Win32">True</Platform> + <Platform value="Win64">False</Platform> + </Platforms> + </BorlandProject> + <ProjectFileVersion>12</ProjectFileVersion> + </ProjectExtensions> + <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> + <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> +</Project> diff --git a/3rd/besen/src/BESENShell.lpi b/3rd/besen/src/BESENShell.lpi new file mode 100644 index 000000000..35cf14b20 --- /dev/null +++ b/3rd/besen/src/BESENShell.lpi @@ -0,0 +1,113 @@ +<?xml version="1.0"?> +<CONFIG> + <ProjectOptions> + <PathDelim Value="\"/> + <Version Value="7"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <UseDefaultCompilerOptions Value="True"/> + </Flags> + <MainUnit Value="0"/> + <TargetFileExt Value=".exe"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <ActiveWindowIndexAtStart Value="0"/> + </General> + <VersionInfo> + <Language Value=""/> + <CharSet Value=""/> + <StringTable Comments="" CompanyName="" FileDescription="" FileVersion="" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/> + </VersionInfo> + <PublishOptions> + <Version Value="2"/> + <IgnoreBinaries Value="False"/> + <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> + <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + <CommandLineParams Value="bl3.js"/> + <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> + </local> + </RunParams> + <Units Count="2"> + <Unit0> + <Filename Value="BESENShell.lpr"/> + <IsPartOfProject Value="True"/> + <UnitName Value="BESENShell"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="0"/> + <WindowIndex Value="0"/> + <TopLine Value="135"/> + <CursorPos X="1" Y="163"/> + <UsageCount Value="20"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit0> + <Unit1> + <Filename Value="BESEN.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="BESEN"/> + <WindowIndex Value="0"/> + <TopLine Value="1779"/> + <CursorPos X="62" Y="1827"/> + <UsageCount Value="20"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit1> + </Units> + <JumpHistory Count="0" HistoryIndex="-1"/> + </ProjectOptions> + <CompilerOptions> + <Version Value="8"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="BESENShell"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)\"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <UseAnsiStrings Value="True"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Debugging> + <GenerateDebugInfo Value="True"/> + </Debugging> + </Linking> + <Other> + <CompilerPath Value="$(CompPath)"/> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions Count="7"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + <Item4> + <Name Value="EBesenTypeError"/> + </Item4> + <Item5> + <Name Value="EBesenReferenceError"/> + </Item5> + <Item6> + <Name Value="EBesenSyntaxError"/> + </Item6> + <Item7> + <Name Value="EBesenThrowException"/> + </Item7> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/3rd/besen/src/BESENShell.lpr b/3rd/besen/src/BESENShell.lpr new file mode 100644 index 000000000..f0e0ddc0a --- /dev/null +++ b/3rd/besen/src/BESENShell.lpr @@ -0,0 +1,942 @@ +program BESENShell; +{$i BESEN.inc} +{$ifdef win32} + {$apptype console} +{$endif} + +uses +{$ifdef fpc} +{$ifdef win32} + Windows, +{$endif} +{$else} +{$ifdef win32} +// FastMM4, + Windows, +{$endif} +{$endif} + SysUtils, + Classes, + BESEN in 'BESEN.pas', + BESENCodeSnapshot in 'BESENCodeSnapshot.pas', + BESENVersionConstants in 'BESENVersionConstants.pas', + BESENConstants in 'BESENConstants.pas', + BESENValueContainer in 'BESENValueContainer.pas', + BESENUnicodeTables in 'BESENUnicodeTables.pas', + BESENStringUtils in 'BESENStringUtils.pas', + BESENStringTree in 'BESENStringTree.pas', + BESENStringList in 'BESENStringList.pas', + BESENSelfBalancedTree in 'BESENSelfBalancedTree.pas', + BESENScope in 'BESENScope.pas', + BESENRegExpCache in 'BESENRegExpCache.pas', + BESENRandomGenerator in 'BESENRandomGenerator.pas', + BESENPointerSelfBalancedTree in 'BESENPointerSelfBalancedTree.pas', + BESENPointerList in 'BESENPointerList.pas', + BESENParser in 'BESENParser.pas', + BESENOpcodes in 'BESENOpcodes.pas', + BESENObjectThrowTypeErrorFunction in 'BESENObjectThrowTypeErrorFunction.pas', + BESENObjectStringPrototype in 'BESENObjectStringPrototype.pas', + BESENObjectStringConstructor in 'BESENObjectStringConstructor.pas', + BESENObjectString in 'BESENObjectString.pas', + BESENObjectRegExpPrototype in 'BESENObjectRegExpPrototype.pas', + BESENObjectRegExpConstructor in 'BESENObjectRegExpConstructor.pas', + BESENObjectRegExp in 'BESENObjectRegExp.pas', + BESENObjectPrototype in 'BESENObjectPrototype.pas', + BESENObjectPropertyDescriptor in 'BESENObjectPropertyDescriptor.pas', + BESENObjectNumberPrototype in 'BESENObjectNumberPrototype.pas', + BESENObjectNumberConstructor in 'BESENObjectNumberConstructor.pas', + BESENObjectNumber in 'BESENObjectNumber.pas', + BESENObjectNativeFunction in 'BESENObjectNativeFunction.pas', + BESENObjectMath in 'BESENObjectMath.pas', + BESENObjectJSON in 'BESENObjectJSON.pas', + BESENObjectGlobal in 'BESENObjectGlobal.pas', + BESENObjectFunctionPrototype in 'BESENObjectFunctionPrototype.pas', + BESENObjectFunctionConstructor in 'BESENObjectFunctionConstructor.pas', + BESENObjectFunctionArguments in 'BESENObjectFunctionArguments.pas', + BESENObjectFunction in 'BESENObjectFunction.pas', + BESENObjectErrorPrototype in 'BESENObjectErrorPrototype.pas', + BESENObjectErrorConstructor in 'BESENObjectErrorConstructor.pas', + BESENObjectError in 'BESENObjectError.pas', + BESENObjectEnvironmentRecord in 'BESENObjectEnvironmentRecord.pas', + BESENObjectDeclaredFunction in 'BESENObjectDeclaredFunction.pas', + BESENObjectDatePrototype in 'BESENObjectDatePrototype.pas', + BESENObjectDateConstructor in 'BESENObjectDateConstructor.pas', + BESENObjectDate in 'BESENObjectDate.pas', + BESENObjectConstructor in 'BESENObjectConstructor.pas', + BESENObjectBooleanPrototype in 'BESENObjectBooleanPrototype.pas', + BESENObjectBooleanConstructor in 'BESENObjectBooleanConstructor.pas', + BESENObjectBoolean in 'BESENObjectBoolean.pas', + BESENObjectBindingFunction in 'BESENObjectBindingFunction.pas', + BESENObjectArrayPrototype in 'BESENObjectArrayPrototype.pas', + BESENObjectArrayConstructor in 'BESENObjectArrayConstructor.pas', + BESENObjectArray in 'BESENObjectArray.pas', + BESENObjectArgSetterFunction in 'BESENObjectArgSetterFunction.pas', + BESENObjectArgGetterFunction in 'BESENObjectArgGetterFunction.pas', + BESENObject in 'BESENObject.pas', + BESENNumberUtils in 'BESENNumberUtils.pas', + BESENNativeObject in 'BESENNativeObject.pas', + BESENNativeCodeMemoryManager in 'BESENNativeCodeMemoryManager.pas', + BESENLocale in 'BESENLocale.pas', + BESENLexicalEnvironment in 'BESENLexicalEnvironment.pas', + BESENLexer in 'BESENLexer.pas', + BESENKeyIDManager in 'BESENKeyIDManager.pas', + BESENIntegerList in 'BESENIntegerList.pas', + BESENInt64SelfBalancedTree in 'BESENInt64SelfBalancedTree.pas', + BESENHashUtils in 'BESENHashUtils.pas', + BESENHashMap in 'BESENHashMap.pas', + BESENGlobals in 'BESENGlobals.pas', + BESENGarbageCollector in 'BESENGarbageCollector.pas', + BESENEvalCacheItem in 'BESENEvalCacheItem.pas', + BESENEvalCache in 'BESENEvalCache.pas', + BESENErrors in 'BESENErrors.pas', + BESENEnvironmentRecord in 'BESENEnvironmentRecord.pas', + BESENDoubleList in 'BESENDoubleList.pas', + BESENDecompiler in 'BESENDecompiler.pas', + BESENDeclarativeEnvironmentRecord in 'BESENDeclarativeEnvironmentRecord.pas', + BESENDateUtils in 'BESENDateUtils.pas', + BESENCompiler in 'BESENCompiler.pas', + BESENCollectorObject in 'BESENCollectorObject.pas', + BESENCollector in 'BESENCollector.pas', + BESENCharset in 'BESENCharset.pas', + BESENBaseObject in 'BESENBaseObject.pas', + BESENArrayUtils in 'BESENArrayUtils.pas', + BESENTypes in 'BESENTypes.pas', + BESENUtils in 'BESENUtils.pas', + BESENValue in 'BESENValue.pas', + BESENRegExp in 'BESENRegExp.pas', + BESENCode in 'BESENCode.pas', + BESENASTNodes in 'BESENASTNodes.pas', + BESENCodeContext in 'BESENCodeContext.pas', + BESENCodeGeneratorContext in 'BESENCodeGeneratorContext.pas', + BESENContext in 'BESENContext.pas', + BESENObjectConsole in 'BESENObjectConsole.pas'; + +type TShellFunctions=class + procedure RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); + procedure NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + + TFileObject=class(TBESENNativeObject) + private + fFileName:TBESENString; + fFileStream:TFileStream; + protected + procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); override; + procedure InitializeObject; override; + procedure FinalizeObject; override; + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); override; + destructor Destroy; override; + published + procedure close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + property fileName:TBESENString read fFileName write fFileName; + end; + +var Instance:TBESEN; + ShellFunctions:TShellFunctions; + DoExit:boolean; + +constructor TFileObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + fFileStream:=nil; +end; + +destructor TFileObject.Destroy; +begin + BesenFreeAndNil(fFileStream); + inherited Destroy; +end; + +procedure TFileObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); +var s:string; + Mode:longword; +begin + inherited ConstructObject(ThisArgument,Arguments,CountArguments); + if CountArguments=0 then begin + raise EBESENError.Create('FileError','Too few arguments'); + end else begin + fFileName:=TBESEN(Instance).ToStr(Arguments^[0]^); + if FileExists(fFileName) then begin + Mode:=fmOpenReadWrite or fmShareExclusive; + end else begin + Mode:=fmCreate or fmShareDenyRead; + end; + if CountArguments>1 then begin + s:=TBESEN(Instance).ToStr(Arguments^[1]^); + if s='c' then begin + Mode:=fmCreate or fmShareDenyRead; + end else if s='r' then begin + Mode:=fmOpenRead or fmShareDenyWrite; + end else if s='rw' then begin + Mode:=fmOpenReadWrite or fmShareExclusive; + end else if s='w' then begin + if FileExists(fFileName) then begin + Mode:=fmOpenWrite or fmShareDenyRead; + end else begin + Mode:=fmCreate or fmShareDenyRead; + end; + end; + end; +{$ifdef BESENSingleStringType} + fFileStream:=TFileStream.Create(fFileName,Mode); +{$else} + fFileStream:=TFileStream.Create(String(BESENEncodeString(BESENUTF16ToUTF8(fFileName),UTF_8,BESENLocaleCharset)),Mode); +{$endif} + end; + s:=''; +end; + +procedure TFileObject.InitializeObject; +begin + inherited InitializeObject; + fFileName:=''; + fFileStream:=nil; +end; + +procedure TFileObject.FinalizeObject; +begin + BesenFreeAndNil(fFileStream); + inherited FinalizeObject; +end; + +procedure TFileObject.close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + BesenFreeAndNil(fFileStream); +end; + +procedure TFileObject.read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var l,ms:int64; + s:string; +begin + s:=''; + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ms:=fFileStream.Size-fFileStream.Position; + if CountArguments=0 then begin + l:=ms; + end else begin + if Arguments^[0]^.ValueType=bvtUNDEFINED then begin + l:=ms; + end else begin + l:=TBESEN(Instance).ToInt(Arguments^[0]^); + if l>ms then begin + l:=ms; + end; + end; + end; + SetLength(s,l); + if l>0 then begin + fFileStream.Read(s[1],l); + end; + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:=s; + SetLength(s,0); + end; +end; + +procedure TFileObject.write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var l:int64; + s:string; +begin + s:=''; + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + if CountArguments>0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=0; + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + l:=length(s); + if l>0 then begin + ResultValue.Num:=fFileStream.Write(s[1],l); + end; + SetLength(s,0); + end; + end; +end; + +procedure TFileObject.seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var l,ms:int64; +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ms:=fFileStream.Size; + if CountArguments=0 then begin + l:=fFileStream.Position; + end else begin + if Arguments^[0]^.ValueType=bvtUNDEFINED then begin + l:=fFileStream.Position; + end else begin + l:=TBESEN(Instance).ToInt(Arguments^[0]^); + if l>ms then begin + l:=ms; + end; + end; + end; + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=fFileStream.Seek(l,soFromBeginning); + end; +end; + +procedure TFileObject.position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=fFileStream.Position; + end; +end; + +procedure TFileObject.eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=fFileStream.Position<fFileStream.Size; + end; +end; + +procedure TFileObject.flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if assigned(fFileStream) then begin +{$ifdef win32} + Windows.FlushFileBuffers(fFileStream.Handle); +{$endif} + end; +end; + +procedure TShellFunctions.RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); +begin + if NewLine then begin + writeln(Data); + end else begin + write(Data); + end; +end; + +procedure TShellFunctions.NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if CountArguments>0 then begin + Instance.RegExpDebug:=Instance.ToUINT32(Arguments^[0]^); + end; +end; + +procedure TShellFunctions.NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=Instance.RegExpDebug; +end; + +procedure TShellFunctions.NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + if CountArguments>0 then begin + Instance.RegExpTimeOutSteps:=Instance.ToINT(Arguments^[0]^); + end; +end; + +procedure TShellFunctions.NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=Instance.RegExpTimeOutSteps; +end; + +procedure TShellFunctions.NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var i:integer; + v:PBESENValue; + fOutput:widestring; + procedure writeit(s:widestring); + begin + fOutput:=fOutput+s; + end; +begin + fOutput:=''; + ResultValue.ValueType:=bvtUNDEFINED; + for i:=0 to CountArguments-1 do begin + v:=Arguments^[i]; + case v^.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v^.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v^.Num)); + end; + bvtSTRING:begin + writeit(v^.Str); + end; + bvtOBJECT:begin + writeit(TBESEN(Instance).ToStr(v^)); + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; + end; +{$ifdef Delphi2009AndUp} + writeln(fOutput); +{$else} + writeln(BESENEncodeString(BESENUTF16ToUTF8(fOutput),UTF_8,BESENLocaleCharset)); +{$endif} +end; + +procedure TShellFunctions.NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + NativePrint(ThisArgument,Arguments,CountArguments,ResultValue); + writeln; +end; + +procedure TShellFunctions.NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:string; +begin + readln(s); +{$ifdef Delphi2009AndUp} + ResultValue:=BESENStringValue(s); +{$else} + ResultValue:=BESENStringLocaleCharsetValue(s); +{$endif} +end; + +procedure TShellFunctions.NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + NativePrintLn(ThisArgument,Arguments,CountArguments,ResultValue); +end; + +procedure TShellFunctions.NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var i:integer; + v:PBESENValue; + ss:widestring; + procedure writeit(s:widestring); + begin + ss:=ss+s; + end; +begin + ss:=''; + ResultValue.ValueType:=bvtUNDEFINED; + for i:=0 to CountArguments-1 do begin + v:=Arguments^[i]; + case v^.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v^.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v^.Num)); + end; + bvtSTRING:begin + writeit(v^.Str); + end; + bvtOBJECT:begin + writeit(TBESEN(Instance).ToStr(v^)); + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; + end; +{$ifdef Delphi2009AndUp} + writeln(ss); +{$else} + writeln(BESENEncodeString(BESENUTF16ToUTF8(ss),UTF_8,BESENLocaleCharset)); +{$endif} +end; + +procedure TShellFunctions.NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ss:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + s:string; +begin + ss:=''; + try + if CountArguments>0 then begin +{$ifdef BESENSingleStringType} + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); +{$else} + ss:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + end else begin + ss:=''; + end; +(* if CountArguments>1 then begin +{$ifdef BESENSingleStringType} + s:=TBESEN(Instance).ToStr(Arguments^[1]^); +{$else} + s:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)),UTF_8,BESENLocaleCharset); +{$endif} + end else begin + s:=''; + end;*) + write(ss); + readln(s); +{$ifdef Delphi2009AndUp} + ResultValue:=BESENStringValue(s); +{$else} + ResultValue:=BESENStringLocaleCharsetValue(s); +{$endif} + finally + end; +end; + +procedure TShellFunctions.NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + DoExit:=true; +end; + +procedure TShellFunctions.NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + fm:byte; + f:file; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>0 then begin +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + Content:=''; + fm:=filemode; + filemode:=0; + assignfile(f,String(FileName)); + {$i-}reset(f,1);{$i+}; + if ioresult=0 then begin + SetLength(Content,filesize(f)); + if length(Content)>0 then begin + {$i-}blockread(f,Content[1],length(Content));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); + exit; + end; + end; + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:={$ifndef BESENSingleStringType}BESENUTF8ToUTF16(BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType})){$endif}; + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + end else begin + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); + end; + end else begin + raise EBESENError.Create('FileError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + fm:byte; + f:file; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>1 then begin +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); + Content:=TBESEN(Instance).ToStr(Arguments^[1]^); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); + Content:=#$ef#$bb#$bf+BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)); +{$endif} + fm:=filemode; + filemode:=2; + assignfile(f,String(FileName)); + {$i-}rewrite(f,1);{$i+}; + if ioresult=0 then begin + if length(Content)>0 then begin + {$i-}blockwrite(f,Content[1],length(Content));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); + exit; + end; + end; + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + end else begin + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); + end; + end else begin + raise EBESENError.Create('FileError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const BoolStr:array[boolean] of {$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}=('false','true'); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + SearchRec:TSearchRec; + Count:integer; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>0 then begin + Content:='['; +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + if FindFirst(String(FileName),faAnyFile or faDirectory,SearchRec)=0 then begin + Count:=0; + repeat + if Count>0 then begin + Content:=Content+','; + end; + Content:=Content+'{'; + Content:=Content+'"name":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENJSONStringQuote(BESENUTF8ToUTF16(BESENEncodeString(AnsiString(SearchRec.Name),BESENLocaleCharset,UTF_8))))+','; + Content:=Content+'"size":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(IntToStr(SearchRec.Size))+','; + Content:=Content+'"time":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENFloatToStr(BESENDateTimeToBESENDate(FileDateToDateTime(SearchRec.Time))))+','; + Content:=Content+'"flags":{'; + Content:=Content+'"hidden":'+BoolStr[(SearchRec.Attr and faHidden)<>0]+','; + Content:=Content+'"systemFile":'+BoolStr[(SearchRec.Attr and faSysFile)<>0]+','; + Content:=Content+'"volumeID":'+BoolStr[(SearchRec.Attr and faVolumeID)<>0]+','; + Content:=Content+'"directory":'+BoolStr[(SearchRec.Attr and faDirectory)<>0]+','; + Content:=Content+'"archive":'+BoolStr[(SearchRec.Attr and faArchive)<>0]+''; + Content:=Content+'}}'; + inc(Count); + until FindNext(SearchRec)<>0; + FindClose(SearchRec); + end; + Content:=Content+']'; + ResultValue:=TBESEN(Instance).JSONEval(Content); + end else begin + raise EBESENError.Create('DirectoryError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + fm:byte; + f:file; +begin + ResultValue.ValueType:=bvtUNDEFINED; + try + if CountArguments>0 then begin +{$ifdef BESENSingleStringType} + FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); +{$else} + FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); +{$endif} + Content:=''; + fm:=filemode; + filemode:=0; + assignfile(f,string(FileName)); + {$i-}reset(f,1);{$i+}; + if ioresult=0 then begin + SetLength(Content,filesize(f)); + if length(Content)>0 then begin + {$i-}blockread(f,Content[1],length(Content));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); + exit; + end; + end; + ResultValue:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType}){$endif}); + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + end else begin + {$i-}closefile(f);{$i+} + if ioresult=0 then begin + end; + filemode:=fm; + raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); + end; + end else begin + raise EBESENError.Create('FileError','Too few arguments'); + end; + finally + end; +end; + +procedure TShellFunctions.NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtUNDEFINED; + TBESEN(Instance).GarbageCollector.CollectAll; +end; + +procedure TShellFunctions.NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:='BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'; +end; + +procedure Print(const v:TBESENValue); +var fOutput:widestring; + procedure writeit(s:widestring); + begin + fOutput:=fOutput+s; + end; +begin + fOutput:=''; + case v.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v.Num)); + end; + bvtSTRING:begin + writeit(v.Str); + end; + bvtOBJECT:begin +{$ifdef BESENSingleStringType} + writeit(TBESEN(Instance).ToStr(v)); +{$else} + writeit(WideString(BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(v)),UTF_8,BESENLocaleCharset))); +{$endif} + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; +{$ifdef Delphi2009AndUp} + writeln(fOutput); +{$else} + writeln(BESENUTF16ToUTF8(fOutput)); +{$endif} +end; + +var FileName,s:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; + ss:widestring; + v:TBESENValue; + i:integer; + c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}; + Compatibility:longword; + ObjDocument,ObjNavigator,ObjShell,ObjWindow:TBESENObject; +begin +{$ifdef cpu386} + Set8087CW($133f); +{$endif} +{$ifdef cpuamd64} + Set8087CW($133f); +{$endif} + DoExit:=false; + FileName:=''; + Compatibility:=COMPAT_BESEN; + if paramcount>0 then begin + for i:=1 to paramcount do begin + s:={$ifndef BESENSingleStringType}AnsiString({$endif}paramstr(i){$ifndef BESENSingleStringType}){$endif}; + if length(s)>0 then begin + case s[1] of + '-','+','/':begin + c:=s[1]; + if c='-' then begin + end; + delete(s,1,1); + if (s='?') or (s='h') or (s='help') then begin + writeln('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'); + writeln('Usage: ',ExtractFileName(paramstr(0)),' [filename] [options]'); + writeln('Options: +help = This help text'); + writeln(' +javascript = Enable facile javascript compatibility mode'); + writeln(' +sgmlcom = Treat ''<!--'' as a ''//'' comment'); + writeln(' +unsafeutf8 = Accept ''valid but insecure'' UTF8'); + DoExit:=true; + end else if s='javascript' then begin + Compatibility:=Compatibility or COMPAT_JS; + end else if s='sgmlcom' then begin + Compatibility:=Compatibility or COMPAT_SGMLCOM; + end else if s='unsafeutf8' then begin + Compatibility:=Compatibility or COMPAT_UTF8_UNSAFE; + end; + end; + else begin + FileName:=s; + end; + end; + end; + end; + end; + ShellFunctions:=TShellFunctions.Create; + Instance:=TBESEN.Create(Compatibility); + TBESEN(Instance).RegExpDebugOutputHook:=ShellFunctions.RegExpDebugOutputHook; + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); + TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); + TBESEN(Instance).RegisterNativeObject('File',TFileObject); + + ObjDocument:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ObjDocument); + TBESEN(Instance).ObjectGlobal.OverwriteData('document',BESENObjectValue(ObjDocument),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjDocument.RegisterNativeFunction('write',ShellFunctions.NativePrint,1,[]); + ObjDocument.RegisterNativeFunction('writeln',ShellFunctions.NativePrintLn,1,[]); + + ObjNavigator:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ObjNavigator); + TBESEN(Instance).ObjectGlobal.OverwriteData('navigator',BESENObjectValue(ObjNavigator),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjNavigator.OverwriteData('userAgent',BESENStringValue('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux'),[bopaWRITABLE,bopaCONFIGURABLE]); + + ObjShell:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ObjShell); + TBESEN(Instance).ObjectGlobal.OverwriteData('Shell',BESENObjectValue(ObjShell),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjShell.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); + ObjShell.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); + ObjShell.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); + ObjShell.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); + ObjShell.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); + ObjShell.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); + ObjShell.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); + ObjShell.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); + ObjShell.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); + ObjShell.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); + ObjShell.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); + ObjShell.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); + ObjShell.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); + ObjShell.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); + ObjShell.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); + ObjShell.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); + ObjShell.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); + + ObjWindow:=TBESEN(Instance).ObjectGlobal; + TBESEN(Instance).ObjectGlobal.OverwriteData('window',BESENObjectValue(ObjWindow),[bopaWRITABLE,bopaCONFIGURABLE]); + ObjDocument.OverwriteData('window',BESENObjectValue(TBESEN(Instance).ObjectGlobal),[bopaWRITABLE,bopaCONFIGURABLE]); + + try + try + if not DoExit then begin + TBESEN(Instance).InjectObject('console',{$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}BESENObjectConsoleSource{$ifndef BESENSingleStringType}){$endif}); + end; + except + on e:EBESENError do begin + writeln(e.Name,': ',e.Message); + end; + on e:exception do begin + writeln('Exception: ',e.Message); + end; + end; + if length(FileName)>0 then begin + try + if not DoExit then begin + v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}BESENGetFileContent(FileName){$ifndef BESENSingleStringType}){$endif}); + Print(v); + end; + except + on e:EBESENError do begin + writeln(e.Name,': ',e.Message); + end; + on e:exception do begin + writeln('Exception: ',e.Message); + end; + end; + end else begin + v.ValueType:=bvtUNDEFINED; + v.Obj:=nil; + while not DoExit do begin + write('>'); + readln(ss); + try + v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}ss{$ifndef BESENSingleStringType}){$endif}); + if not DoExit then begin + Print(v); + v.ValueType:=bvtUNDEFINED; + v.Obj:=nil; + TBESEN(Instance).GarbageCollector.CollectAll; + end; + except + on e:EBESENError do begin + writeln(e.Name,'(',TBESEN(Instance).LineNumber,'): ',e.Message); + end; + on e:exception do begin + writeln('Exception(',TBESEN(Instance).LineNumber,'): ',e.Message); + end; + end; + end; + end; + except + on e:exception do begin + writeln(e.Message); + end; + end; + FileName:=''; + s:=''; + ShellFunctions.Destroy; + TBESEN(Instance).Destroy; +end. diff --git a/3rd/besen/src/BESENStringList.pas b/3rd/besen/src/BESENStringList.pas new file mode 100644 index 000000000..585ba6120 --- /dev/null +++ b/3rd/besen/src/BESENStringList.pas @@ -0,0 +1,231 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENStringList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENStringArray=^TBESENStringArray; + TBESENStringArray=array[0..(2147483647 div sizeof(TBESENString))-1] of TBESENString; + + TBESENStringList=class + private + FCount,FSize:integer; + function GetItem(index:integer):TBESENString; + procedure SetItem(index:integer;Value:TBESENString); + public + FList:PBESENStringArray; + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:TBESENString):integer; + procedure Insert(index:integer;Item:TBESENString); + procedure Delete(index:integer); + function Remove(Item:TBESENString):integer; + function Find(Item:TBESENString):integer; + function IndexOf(Item:TBESENString):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:TBESENString read GetItem write SetItem; default; + property Items[index:integer]:TBESENString read GetItem write SetItem; + end; + +implementation + +constructor TBESENStringList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENStringList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENStringList.Clear; +var i:integer; +begin + for i:=0 to FSize-1 do begin + FList^[i]:=''; + end; + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENStringList.SetCapacity(NewCapacity:integer); +var i:integer; +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENStringArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + if NewCapacity<FSize then begin + for i:=NewCapacity to FSize-1 do begin + FList^[i]:=''; + end; + end; + ReallocMem(FList,NewCapacity*sizeof(TBESENString)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(TBESENString),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENStringList.SetCount(NewCount:integer); +var i:integer; +begin + if (NewCount>=0) and (NewCount<high(TBESENStringArray)) then begin + if NewCount<FCount then begin + for i:=NewCount to FCount-1 do begin + FList^[i]:=''; + end; + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENStringList.Add(Item:TBESENString):integer; +begin + result:=FCount; + SetCount(FCount+1); + FList^[result]:=Item; +end; + +procedure TBESENStringList.Insert(index:integer;Item:TBESENString); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENStringList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENStringList.Remove(Item:TBESENString):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENStringList.Find(Item:TBESENString):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENStringList.IndexOf(Item:TBESENString):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENStringList.Exchange(Index1,Index2:integer); +var TempString:TBESENString; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempString:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempString; + end; +end; + +function TBESENStringList.GetItem(index:integer):TBESENString; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=''; + end; +end; + +procedure TBESENStringList.SetItem(index:integer;Value:TBESENString); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +end. diff --git a/3rd/besen/src/BESENStringTree.pas b/3rd/besen/src/BESENStringTree.pas new file mode 100644 index 000000000..74fb4ae6b --- /dev/null +++ b/3rd/besen/src/BESENStringTree.pas @@ -0,0 +1,356 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENStringTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type TBESENStringTreeData=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENStringTreeNode=^TBESENStringTreeNode; + TBESENStringTreeNode=record + TheChar:widechar; + Data:TBESENStringTreeData; + DataExist:longbool; + Previous,Next,Up,Down:PBESENStringTreeNode; + end; + + TBESENStringTree=class + public + Root:PBESENStringTreeNode; + function CreateBESENStringTreeNode(AChar:widechar):PBESENStringTreeNode; + procedure DestroyBESENStringTreeNode(Node:PBESENStringTreeNode); + public + constructor Create; + destructor Destroy; override; + procedure Clear; + procedure DumpTree; + procedure DumpList; + procedure AppendTo(DestBESENStringTree:TBESENStringTree); + procedure Optimize(DestBESENStringTree:TBESENStringTree); + function Add(Content:TBESENString;const Data:TBESENStringTreeData;Replace:boolean=false):boolean; + function Delete(Content:TBESENString):boolean; + function Find(Content:TBESENString;var Data:TBESENStringTreeData):boolean; + end; + +implementation + +constructor TBESENStringTree.Create; +begin + inherited Create; + Root:=nil; + Clear; +end; + +destructor TBESENStringTree.Destroy; +begin + Clear; + inherited Destroy; +end; + +function TBESENStringTree.CreateBESENStringTreeNode(AChar:widechar):PBESENStringTreeNode; +begin + getmem(result,sizeof(TBESENStringTreeNode)); + fillchar(result^.Data,sizeof(TBESENStringTreeData),#0); + result^.TheChar:=AChar; + result^.DataExist:=false; + result^.Previous:=nil; + result^.Next:=nil; + result^.Up:=nil; + result^.Down:=nil; +end; + +procedure TBESENStringTree.DestroyBESENStringTreeNode(Node:PBESENStringTreeNode); +begin + if not assigned(Node) then exit; + DestroyBESENStringTreeNode(Node^.Next); + DestroyBESENStringTreeNode(Node^.Down); + freemem(Node); +end; + +procedure TBESENStringTree.Clear; +begin + DestroyBESENStringTreeNode(Root); + Root:=nil; +end; + +procedure TBESENStringTree.DumpTree; +var Ident:integer; + procedure DumpNode(Node:PBESENStringTreeNode); + var SubNode:PBESENStringTreeNode; + IdentCounter,IdentOld:integer; + begin + for IdentCounter:=1 to Ident do write(' '); + write(Node^.TheChar); + IdentOld:=Ident; + SubNode:=Node^.Next; + while assigned(SubNode) do begin + write(SubNode^.TheChar); + if not assigned(SubNode^.Next) then break; + inc(Ident); + SubNode:=SubNode^.Next; + end; + writeln; + inc(Ident); + while assigned(SubNode) and (SubNode<>Node) do begin + if assigned(SubNode^.Down) then DumpNode(SubNode^.Down); + SubNode:=SubNode^.Previous; + dec(Ident); + end; + Ident:=IdentOld; + if assigned(Node^.Down) then DumpNode(Node^.Down); + end; +begin + Ident:=0; + DumpNode(Root); +end; + +procedure TBESENStringTree.DumpList; + procedure DumpNode(Node:PBESENStringTreeNode;const ParentStr:TBESENString); + var s:TBESENString; + begin + if not assigned(Node) then exit; + if Node^.DataExist then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + writeln({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}s{$ifndef BESENSingleStringType}){$endif}); + end; + if assigned(Node^.Next) then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DumpNode(Node^.Next,s); + end; + if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); + end; +begin + if not assigned(Root) then exit; + DumpNode(Root,''); +end; + +procedure TBESENStringTree.AppendTo(DestBESENStringTree:TBESENStringTree); + procedure DumpNode(Node:PBESENStringTreeNode;const ParentStr:TBESENString); + var s:TBESENString; + begin + if not assigned(Node) then exit; + if Node^.DataExist then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DestBESENStringTree.Add(s,Node^.Data); + end; + if assigned(Node^.Next) then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DumpNode(Node^.Next,s); + end; + if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); + end; +begin + if not assigned(DestBESENStringTree) then exit; + if not assigned(Root) then exit; + DumpNode(Root,''); +end; + +procedure TBESENStringTree.Optimize(DestBESENStringTree:TBESENStringTree); + procedure DumpNode(Node:PBESENStringTreeNode;ParentStr:TBESENString); + var s:TBESENString; + begin + if not assigned(Node) then exit; + ParentStr:=ParentStr; + if Node^.DataExist then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DestBESENStringTree.Add(s,Node^.Data); + end; + if assigned(Node^.Next) then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DumpNode(Node^.Next,s); + end; + if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); + end; +begin + if not assigned(DestBESENStringTree) then exit; + DestBESENStringTree.Clear; + if not assigned(Root) then exit; + DumpNode(Root,''); +end; + +function TBESENStringTree.Add(Content:TBESENString;const Data:TBESENStringTreeData;Replace:boolean=false):boolean; +var StringLength,Position,PositionCounter:integer; + NewNode,LastNode,Node:PBESENStringTreeNode; + StringChar,NodeChar:widechar; +begin + result:=false; + StringLength:=length(Content); + if StringLength>0 then begin + LastNode:=nil; + Node:=Root; + for Position:=1 to StringLength do begin + StringChar:=Content[Position]; + if assigned(Node) then begin + NodeChar:=Node^.TheChar; + if NodeChar=StringChar then begin + LastNode:=Node; + Node:=Node^.Next; + end else begin + while (NodeChar<StringChar) and assigned(Node^.Down) do begin + Node:=Node^.Down; + NodeChar:=Node^.TheChar; + end; + if NodeChar=StringChar then begin + LastNode:=Node; + Node:=Node^.Next; + end else begin + NewNode:=CreateBESENStringTreeNode(StringChar); + if NodeChar<StringChar then begin + NewNode^.Down:=Node^.Down; + NewNode^.Up:=Node; + if assigned(NewNode^.Down) then begin + NewNode^.Down^.Up:=NewNode; + end; + NewNode^.Previous:=Node^.Previous; + Node^.Down:=NewNode; + end else if NodeChar>StringChar then begin + NewNode^.Down:=Node; + NewNode^.Up:=Node^.Up; + if assigned(NewNode^.Up) then begin + NewNode^.Up^.Down:=NewNode; + end; + NewNode^.Previous:=Node^.Previous; + if not assigned(NewNode^.Up) then begin + if assigned(NewNode^.Previous) then begin + NewNode^.Previous^.Next:=NewNode; + end else begin + Root:=NewNode; + end; + end; + Node^.Up:=NewNode; + end; + LastNode:=NewNode; + Node:=LastNode^.Next; + end; + end; + end else begin + for PositionCounter:=Position to StringLength do begin + NewNode:=CreateBESENStringTreeNode(Content[PositionCounter]); + if assigned(LastNode) then begin + NewNode^.Previous:=LastNode; + LastNode^.Next:=NewNode; + LastNode:=LastNode^.Next; + end else begin + if not assigned(Root) then begin + Root:=NewNode; + LastNode:=Root; + end; + end; + end; + break; + end; + end; + if assigned(LastNode) then begin + if Replace or not LastNode^.DataExist then begin + LastNode^.Data:=Data; + LastNode^.DataExist:=true; + result:=true; + end; + end; + end; +end; + +function TBESENStringTree.Delete(Content:TBESENString):boolean; +var StringLength,Position:integer; + Node:PBESENStringTreeNode; + StringChar,NodeChar:widechar; +begin + result:=false; + StringLength:=length(Content); + if StringLength>0 then begin + Node:=Root; + for Position:=1 to StringLength do begin + StringChar:=Content[Position]; + if assigned(Node) then begin + NodeChar:=Node^.TheChar; + while (NodeChar<>StringChar) and assigned(Node^.Down) do begin + Node:=Node^.Down; + NodeChar:=Node^.TheChar; + end; + if NodeChar=StringChar then begin + if (Position=StringLength) and Node^.DataExist then begin + Node^.DataExist:=false; + result:=true; + exit; + end; + Node:=Node^.Next; + end else begin + break; + end; + end else begin + break; + end; + end; + end; +end; + +function TBESENStringTree.Find(Content:TBESENString;var Data:TBESENStringTreeData):boolean; +var StringLength,Position:integer; + Node:PBESENStringTreeNode; + StringChar,NodeChar:TBESENString; +begin + result:=false; + StringLength:=length(Content); + if StringLength>0 then begin + Node:=Root; + for Position:=1 to StringLength do begin + StringChar:=Content[Position]; + if assigned(Node) then begin + NodeChar:=Node^.TheChar; + while (NodeChar<>StringChar) and assigned(Node^.Down) do begin + Node:=Node^.Down; + NodeChar:=Node^.TheChar; + end; + if NodeChar=StringChar then begin + if (Position=StringLength) and Node^.DataExist then begin + Data:=Node^.Data; + result:=true; + exit; + end; + Node:=Node^.Next; + end else begin + break; + end; + end else begin + break; + end; + end; + end; +end; + +end. diff --git a/3rd/besen/src/BESENStringUtils.pas b/3rd/besen/src/BESENStringUtils.pas new file mode 100644 index 000000000..3f608dcc6 --- /dev/null +++ b/3rd/besen/src/BESENStringUtils.pas @@ -0,0 +1,2618 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENStringUtils; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,BESENConstants,BESENTypes,BESENCharset; + +type TBESENHexValues=array[word] of byte; + +const BESENBase64Chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +const BESENHexChars:array[boolean,0..15] of widechar=(('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'), + ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')); + +var BESENHexValues:TBESENHexValues; + +function BESENPosChar(ToFindChar:TBESENWIDECHAR;const InString:TBESENSTRING):longint; +function BESENPos(const ToFindString,InString:TBESENSTRING):longint; + +{$ifndef BESENSingleStringType} +function BESENANSIPosChar(ToFindChar:TBESENCHAR;const InString:TBESENANSISTRING):longint; +function BESENANSIPos(const ToFindString,InString:TBESENANSISTRING):longint; + +function BESENANSITrim(const InputString:TBESENANSISTRING):TBESENANSISTRING; + +function BESENANSIUpperCase(const InputString:TBESENANSISTRING):TBESENANSISTRING; +{$endif} + +function BESENStringCompare(const s1,s2:TBESENString):longint; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} + +{$ifdef BESENSingleStringType} +function BESENGetFileContent(fn:TBESENSTRING):TBESENSTRING; +{$else} +function BESENGetFileContent(fn:TBESENANSISTRING):TBESENANSISTRING; +function BESENConvertToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; + +function BESENDecodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +function BESENEncodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +function BESENDequote(s:TBESENANSISTRING):TBESENANSISTRING; + +function BESENIsUTF8(const s:TBESENANSISTRING):boolean; +function BESENEncodeString(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharset):TBESENANSISTRING; +function BESENGetCodePage(Value:TBESENANSISTRING):TBESENCharset; +function BESENGetCodePageID(Value:TBESENCharset):TBESENANSISTRING; +function BESENDoNeedEncoding(Value:TBESENANSISTRING):boolean; +function BESENFindIdealCoding(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharsetSet):TBESENCharset; +function BESENISOToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; + +function BESENUTF32Pos(const ToFindString,InString:TBESENUTF32STRING):longint; +procedure BESENUTF32Delete(var s:TBESENUTF32STRING;Index,Len:longint); +function BESENUTF32Compare(const a,b:TBESENUTF32STRING):boolean; overload; +function BESENUTF32Compare(const a:TBESENUTF32STRING;const b:TBESENANSISTRING):boolean; overload; +procedure BESENUTF32Clear(var a:TBESENUTF32STRING); +procedure BESENBESENUTF32AddString(var a:TBESENUTF32STRING;const b:TBESENANSISTRING); +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENUTF32CHAR); overload; +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENCHAR); overload; +procedure BESENUTF32Add(var a:TBESENUTF32STRING;const b:TBESENUTF32STRING); +function BESENUTF32ToUTF8(const s:TBESENUTF32STRING):TBESENUTF8STRING; +function BESENUTF8ToUTF32(const s:TBESENUTF8STRING):TBESENUTF32STRING; +function BESENUTF8ToUTF16(const s:TBESENUTF8STRING):TBESENUTF16STRING; +function BESENUTF16ToUTF8(const s:TBESENUTF16STRING):TBESENUTF8STRING; +{$endif} +function BESENUTF32ToUTF16(const s:TBESENUTF32STRING):TBESENUTF16STRING; +function BESENUTF32CHARToUTF16(w:TBESENUTF32CHAR):TBESENUTF16STRING; +function BESENUTF16ToUTF32(const s:TBESENUTF16STRING):TBESENUTF32STRING; +{$ifndef BESENSingleStringType} +function BESENUTF32ToWIDESTRING(const s:TBESENUTF32STRING):widestring; +function BESENWIDESTRINGToUTF32(const s:widestring):TBESENUTF32STRING; +function BESENUTF32ToSTRING(const s:TBESENUTF32STRING):TBESENANSISTRING; +function BESENSTRINGToUTF32(const s:TBESENANSISTRING):TBESENUTF32STRING; +function BESENUTF32CharToUTF8(u4c:TBESENUTF32CHAR):TBESENUTF8STRING; +procedure BESENUTF8Inc(var s:TBESENUTF8STRING;var i:longint); +procedure BESENUTF8Dec(var s:TBESENUTF8STRING;var i:longint); +procedure BESENUTF8Delete(var s:TBESENUTF8STRING;i:longint); +function BESENUTF8Length(const s:TBESENUTF8STRING):longint; +function BESENUTF8GetRawPos(const s:TBESENUTF8STRING;Index:longint):longint; +function BESENUTF8GetChar(var s:TBESENUTF8STRING;Index:longint):TBESENUTF32CHAR; +function BESENUTF8GetRawChar(var s:TBESENUTF8STRING;i:longint):TBESENUTF32CHAR; +function BESENUTF8GetRawCharAndInc(var s:TBESENUTF8STRING;var i:longint):TBESENUTF32CHAR; +function BESENUTF8Pos(ToFindString,InString:TBESENUTF8STRING):longint; +{$endif} + +function BESENUnicodeGetLUT(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +function BESENUnicodeGetType(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsAlpha(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsAlphaNumber(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsLetter(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsIDPartEx(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsIDStart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsIDPart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsDigit(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsStringWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsParserWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsLineTerminator(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsPrint(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsUpper(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsLower(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeToUpper(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} +function BESENUnicodeToLower(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} + +function BESENLowercase(const s:TBESENString):TBESENString; +function BESENUppercase(const s:TBESENString):TBESENString; + +function BESENJSONStringQuote(const s:TBESENString):TBESENString; + +function BESENIsHex(const v:word):boolean; + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESENUnicodeTables; + +const JSCT_UNASSIGNED=0; + JSCT_UPPERCASE_LETTER=1; + JSCT_LOWERCASE_LETTER=2; + JSCT_TITLECASE_LETTER=3; + JSCT_MODIFIER_LETTER=4; + JSCT_OTHER_LETTER=5; + JSCT_NON_SPACING_MARK=6; + JSCT_ENCLOSING_MARK=7; + JSCT_COMBINING_SPACING_MARK=8; + JSCT_DECIMAL_DIGIT_NUMBER=9; + JSCT_LETTER_NUMBER=10; + JSCT_OTHER_NUMBER=11; + JSCT_SPACE_SEPARATOR=12; + JSCT_LINE_SEPARATOR=13; + JSCT_PARAGRAPH_SEPARATOR=14; + JSCT_CONTROL=15; + JSCT_FORMAT=16; + JSCT_PRIVATE_USE=18; + JSCT_SURROGATE=19; + JSCT_DASH_PUNCTUATION=20; + JSCT_START_PUNCTUATION=21; + JSCT_END_PUNCTUATION=22; + JSCT_CONNECTOR_PUNCTUATION=23; + JSCT_OTHER_PUNCTUATION=24; + JSCT_MATH_SYMBOL=25; + JSCT_CURRENCY_SYMBOL=26; + JSCT_MODIFIER_SYMBOL=27; + JSCT_OTHER_SYMBOL=28; + +function BESENUnicodeGetLUT(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +begin + result:=UnicodeALut[UnicodeYLut[(UnicodeXLut[(c and $ffff) shr 6] shl 6) or (c and $3f)]]; +end; + +function BESENUnicodeGetType(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetLUT(c) and $1f; +end; + +function BESENUnicodeIsAlpha(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsAlphaNumber(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER) or + (1 shl JSCT_DECIMAL_DIGIT_NUMBER)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsLetter(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER) or + (1 shl JSCT_LETTER_NUMBER)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsIDPartEx(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER) or + (1 shl JSCT_LETTER_NUMBER) or + (1 shl JSCT_NON_SPACING_MARK) or + (1 shl JSCT_COMBINING_SPACING_MARK) or + (1 shl JSCT_DECIMAL_DIGIT_NUMBER) or + (1 shl JSCT_CONNECTOR_PUNCTUATION)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsIDStart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeIsLetter(c) or ((c=ord('_')) or (c=ord('$'))); +end; + +function BESENUnicodeIsIDPart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeIsIDPartEx(c) or ((c=ord('_')) or (c=ord('$')) or ((c=$200c) or (c=$200d))); +end; + +function BESENUnicodeIsDigit(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetType(c)=JSCT_DECIMAL_DIGIT_NUMBER; +end; + +function BESENUnicodeIsSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(BESENUnicodeGetLUT(c) and $00070000)=$0040000; +end; + +function BESENUnicodeIsStringWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((c>=$0009) and (c<=$000d)) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$2028) or (c=$2029) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); +end; + +function BESENUnicodeIsParserWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((c>=$0009) and (c<=$000d)) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$2028) or (c=$2029) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); +end; + +function BESENUnicodeIsWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(c=$0009) or (c=$000b) or (c=$000c) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); +end; + +function BESENUnicodeIsLineTerminator(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(c=$000a) or (c=$000d) or (c=$2028) or (c=$2029); +end; + +function BESENUnicodeIsPrint(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=c<128; +end; + +function BESENUnicodeIsUpper(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetType(c)=JSCT_UPPERCASE_LETTER; +end; + +function BESENUnicodeIsLower(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetType(c)=JSCT_LOWERCASE_LETTER; +end; + +function BESENUnicodeToUpper(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} +begin + if (BESENUnicodeGetLUT(c) and $00100000)<>0 then begin + result:=c-TBESENUTF32CHAR(BESENUnicodeGetLUT(c) shr 22); + end else begin + result:=c; + end; +end; + +function BESENUnicodeToLower(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} +begin + if (BESENUnicodeGetLUT(c) and $00200000)<>0 then begin + result:=c+TBESENUTF32CHAR(BESENUnicodeGetLUT(c) shr 22); + end else begin + result:=c; + end; +end; + +function BESENPosChar(ToFindChar:TBESENWIDECHAR;const InString:TBESENSTRING):longint; +var i:longint; +begin + result:=0; + for i:=1 to length(InString) do begin + if InString[i]=ToFindChar then begin + result:=i; + break; + end; + end; +end; + +function BESENPos(const ToFindString,InString:TBESENSTRING):longint; +var i,j,l:longint; + OK:boolean; +begin + result:=0; + i:=1; + while i<=length(InString) do begin + l:=i+length(ToFindString)-1; + if l>length(InString) then begin + exit; + end; + OK:=true; + for j:=1 to length(ToFindString) do begin + if InString[i+j-1]<>ToFindString[j] then begin + OK:=false; + break; + end; + end; + if OK then begin + result:=i; + exit; + end; + inc(i); + end; +end; + +{$ifndef BESENSingleStringType} +function BESENANSIPosChar(ToFindChar:TBESENCHAR;const InString:TBESENANSISTRING):longint; +var i:longint; +begin + result:=0; + for i:=1 to length(InString) do begin + if InString[i]=ToFindChar then begin + result:=i; + break; + end; + end; +end; + +function BESENANSIPos(const ToFindString,InString:TBESENANSISTRING):longint; +var i,j,l:longint; + OK:boolean; +begin + result:=0; + i:=1; + while i<=length(InString) do begin + l:=i+length(ToFindString)-1; + if l>length(InString) then begin + exit; + end; + OK:=true; + for j:=1 to length(ToFindString) do begin + if InString[i+j-1]<>ToFindString[j] then begin + OK:=false; + break; + end; + end; + if OK then begin + result:=i; + exit; + end; + inc(i); + end; +end; + +function BESENANSITrim(const InputString:TBESENANSISTRING):TBESENANSISTRING; +var Counter,FromHere,ToHere:longint; +begin + FromHere:=1; + ToHere:=length(InputString); + for Counter:=1 to length(InputString) do begin + if not (InputString[Counter] in [#0..#32]) then begin + FromHere:=Counter; + break; + end; + end; + for Counter:=length(InputString) downto FromHere do begin + if not (InputString[Counter] in [#0..#32]) then begin + ToHere:=Counter; + break; + end; + end; + result:=copy(InputString,FromHere,(ToHere-FromHere)+1); +end; + +function BESENANSIUpperCase(const InputString:TBESENANSISTRING):TBESENANSISTRING; +var i:longint; +begin + result:=InputString; + for i:=1 to length(result) do begin + if result[i] in ['a'..'z'] then begin + inc(byte(AnsiChar(result[i])),byte(AnsiChar('A'))-byte(AnsiChar('a'))); + end; + end; +end; +{$endif} + +function BESENStringCompare(const s1,s2:TBESENString):longint; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} +const BoolToSign:array[boolean] of longint=(1,-1); +var i,j:longint; +begin + if pointer(s1)=pointer(s2) then begin + result:=0; + exit; + end; + j:=length(s1); + if length(s2)<j then begin + j:=length(s2); + end; + for i:=1 to j do begin + result:=longint(word(s1[i]))-longint(word(s2[i])); + if result<>0 then begin + result:=BoolToSign[result<0]; + exit; + end; + end; + result:=length(s1)-length(s2); + if result<>0 then begin + result:=BoolToSign[result<0]; + end; +end; + +{$ifdef cpu64} +function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} +begin + result:=s1=s2; +end; +{$else} +{$ifdef cpu386} +procedure BESENStringEqualsAlignFiller; assembler; register; +asm + nop; +end; + +function BESENStringEquals(const s1,s2:TBESENString):boolean; assembler; register; +asm + push ebx + cmp eax,edx + je @Match + test eax,eax + jz @CheckNullEAX + test edx,edx + jz @CheckNullEDX + mov ecx,dword ptr [eax-4] + cmp ecx,dword ptr [edx-4] + jne @Mismatch + sub ecx,8 + jl @Small + mov ebx,dword ptr [eax] + cmp ebx,dword ptr [edx] + jne @Mismatch + lea ebx,dword ptr [eax+ecx] + add edx,ecx + mov eax,dword ptr [ebx] + cmp eax,dword ptr [edx] + jne @Mismatch + mov eax,dword ptr [ebx+4] + cmp eax,dword ptr [edx+4] + jne @Mismatch + sub ecx,4 + jle @Match + neg ecx + add ecx,ebx + and ecx,-4 + sub ecx,ebx +@LargeLoop: + mov eax,dword ptr [ebx+ecx] + cmp eax,dword ptr [edx+ecx] + jne @Mismatch + mov eax,dword ptr [ebx+ecx+4] + cmp eax,dword ptr [edx+ecx+4] + jne @Mismatch + add ecx,8 + jl @LargeLoop +@Match: + mov eax,1 + jmp @Done +@Small: + add ecx,8 + jle @Match +@SmallLoop: + mov bx,word ptr [eax] + cmp bx,word ptr [edx] + jne @Mismatch + add eax,2 + add edx,2 + sub ecx,2 + jnz @SmallLoop + jmp @Match +@CheckNullEAX: + cmp dword ptr [edx-4],eax + je @Match + jmp @Mismatch +@CheckNullEDX: + cmp dword ptr [eax-4],edx + je @Match +@Mismatch: + xor eax,eax +@Done: + pop ebx +end; +(* is a plain asm implementation of: +function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef UseRegister}register;{$endif} +var l:TBESENINT32; + x,y:PWideChar; +begin + result:=false; + x:=PWideChar(s1); + y:=PWideChar(s2); + if x=y then begin + result:=true; + exit; + end; + if (ptruint(x) and ptruint(y))=0 then begin + result:=(assigned(x) and (PBESENUINT32(pointer(ptruint(ptruint(x)-sizeof(longword))))^=0)) or + (assigned(y) and (PBESENUINT32(pointer(ptruint(ptruint(y)-sizeof(longword))))^=0)); + exit; + end; + l:=PBESENINT32(pointer(ptruint(ptruint(x)-sizeof(longword))))^; + if l<>PBESENINT32(pointer(ptruint(ptruint(y)-sizeof(longword))))^ then begin + exit; + end; + if l<8 then begin + while l>0 do begin + if x^<>y^ then begin + exit; + end; + inc(x); + inc(y); + dec(l,2); + end; + end else begin + if (PBESENUINT32(x)^<>PBESENUINT32(y)^) then begin + exit; + end; + dec(l,8); + inc(ptrint(x),l); + inc(ptrint(y),l); + if PBESENUINT32Array(x)^[0]<>PBESENUINT32Array(y)^[0] then begin + exit; + end; + if PBESENUINT32Array(x)^[1]<>PBESENUINT32Array(y)^[1] then begin + exit; + end; + dec(l,4); + if l>0 then begin + l:=(((-l)+ptrint(x)) and (-4))-ptrint(x); + inc(ptrint(x),l); + inc(ptrint(y),l); + repeat + if PBESENUINT32Array(x)^[0]<>PBESENUINT32Array(y)^[0] then begin + exit; + end; + if PBESENUINT32Array(x)^[1]<>PBESENUINT32Array(y)^[1] then begin + exit; + end; + inc(PBESENUINT32(x),2); + inc(PBESENUINT32(y)); + inc(l,8); + until l>=0; + end; + end; + result:=true; +end; +*) +{$else} +function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} +begin + result:=s1=s2; +end; +{$endif} +{$endif} + +{$ifdef BESENSingleStringType} +function BESENGetFileContent(fn:TBESENSTRING):TBESENSTRING; +var sl:TStringList; +begin + result:=''; + sl:=TStringList.Create; + try + sl.LoadFromFile(fn); + result:=sl.Text; + finally + sl.Free; + end; +end; +{$else} +function BESENGetFileContent(fn:TBESENANSISTRING):TBESENANSISTRING; +var fm:byte; + f:file; +begin + result:=''; + fm:=filemode; + filemode:=0; + assignfile(f,String(fn)); + {$i-}reset(f,1);{$i+}; + if ioresult=0 then begin + SetLength(result,filesize(f)); + if length(result)>0 then begin + {$i-}blockread(f,result[1],length(result));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + exit; + end; + end; + {$i-}closefile(f);{$i+} + end; + filemode:=fm; +end; + +function BESENConvertToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; +var s2:TBESENANSISTRING; + i,j,k:longint; +begin + if (length(s)>=3) and (s[1]=#$ef) and (s[2]=#$bb) and (s[3]=#$bf) then begin + // UTF8 + result:=copy(s,4,length(s)-3); + end else if (length(s)>=4) and (s[1]=#$00) and (s[2]=#$00) and (s[3]=#$fe) and (s[4]=#$ff) then begin + // UTF32 big endian + s:=copy(s,5,length(s)-4); + s2:=s; + SetLength(s2,(length(s)+3) and not 3); + for i:=1 to length(s) do begin + j:=i shr 2; + k:=i and 3; + s2[(j shl 2)+(4-k)]:=s[i]; + end; + result:=BESENEncodeString(s,UTF_32,UTF_8); + end else if (length(s)>=4) and (s[1]=#$ff) and (s[2]=#$fe) and (s[3]=#$00) and (s[4]=#$00) then begin + // UTF32 little endian + result:=BESENEncodeString(copy(s,5,length(s)-4),UTF_32,UTF_8); + end else if (length(s)>=2) and (s[1]=#$fe) and (s[2]=#$ff) then begin + // UTF16 big endian + s:=copy(s,3,length(s)-2); + s2:=s; + SetLength(s2,(length(s)+1) and not 1); + for i:=1 to length(s) do begin + j:=i shr 1; + k:=i and 1; + s2[(j shl 1)+(2-k)]:=s[i]; + end; + result:=BESENEncodeString(s,UTF_16,UTF_8); + end else if (length(s)>=2) and (s[1]=#$ff) and (s[2]=#$fe) then begin + // UTF16 little endian + result:=BESENEncodeString(copy(s,3,length(s)-2),UTF_16,UTF_8); + end else if BESENIsUTF8(s) then begin + // UTF8 without byte order mark or plain US-ASCII + result:=s; + end else begin + // Without any unicode byte order mark + result:=BESENEncodeString(s,BESENLocaleCharset,UTF_8); + end; +end; + +const Base64Table:array[0..63] of TBESENCHAR='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +var Base64DecoderTable:array[TBESENCHAR] of byte; + +procedure InitBase64; +var i:longint; +begin + for i:=0 to 63 do begin + Base64DecoderTable[Base64Table[i]]:=i; + end; +end; + +function BESENDecodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +var i,j,l:longint; + c:longword; +begin + SetLength(result,((length(s)*3) shr 2)+3); +{while (length(s) and 3)<>0 do begin + s:=s+'='; + end;} + l:=0; + i:=1; + while i<=length(s) do begin + c:=0; + for j:=1 to 4 do begin + if i<=length(s) then begin + case s[i] of + 'A'..'Z','a'..'z','0'..'9','+','/':begin + c:=c or (Base64DecoderTable[s[i]] shl (24-((j shl 2)+(j shl 1)))); + end; + '=':begin + c:=(c and $00ffffff) or (((c shr 24)+1) shl 24); + end; + else begin + c:=c or $f0000000; + break; + end; + end; + end else begin + c:=(c and $00ffffff) or (((c shr 24)+1) shl 24); + end; + inc(i); + end; + if (c shr 24)<3 then begin + inc(l); + result[l]:=ansichar(byte((c shr 16) and $ff)); + if (c shr 24)<2 then begin + inc(l); + result[l]:=ansichar(byte((c shr 8) and $ff)); + if (c shr 24)<1 then begin + inc(l); + result[l]:=ansichar(byte(c and $ff)); + end; + end; + end else begin + break; + end; + end; + SetLength(result,l); +end; + +function BESENEncodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +var i,l:longint; + c:longword; +begin + if length(s)=0 then begin + result:=''; + end else begin + SetLength(result,((length(s)*4) div 3)+4); + l:=1; + i:=1; + while (i+2)<=length(s) do begin + c:=(byte(s[i]) shl 16) or (byte(s[i+1]) shl 8) or byte(s[i+2]); + result[l]:=Base64Table[(c shr 18) and $3f]; + result[l+1]:=Base64Table[(c shr 12) and $3f]; + result[l+2]:=Base64Table[(c shr 6) and $3f]; + result[l+3]:=Base64Table[c and $3f]; + inc(i,3); + inc(l,4); + end; + if (i+1)<=length(s) then begin + c:=(byte(s[i]) shl 16) or (byte(s[i+1]) shl 8); + result[l]:=Base64Table[(c shr 18) and $3f]; + result[l+1]:=Base64Table[(c shr 12) and $3f]; + result[l+2]:=Base64Table[(c shr 6) and $3f]; + result[l+3]:='='; + inc(l,4); + end else if i<=length(s) then begin + c:=byte(s[i]) shl 16; + result[l]:=Base64Table[(c shr 18) and $3f]; + result[l+1]:=Base64Table[(c shr 12) and $3f]; + result[l+2]:='='; + result[l+3]:='='; + inc(l,4); + end; + if l>1 then begin + SetLength(result,l-1); + end else begin + result:=BESENAnsiTrim(result); + end; + end; +end; + +function BESENDequote(s:TBESENANSISTRING):TBESENANSISTRING; +const hexa:array[1..$F] of TBESENCHAR='123456789ABCDEF'; +var p:longint; + encode:TBESENANSISTRING; +begin + if s='' then begin + result:=#13#10; + end else begin + result:=''; + if s[length(s)]='=' then begin + SetLength(s,Length(s)-1) + end else begin + if (length(s)>=3) and (s[length(s)-2]<>'=') then begin + s:=s+#13#10; + end; + end; + p:=BESENANSIPosChar('=',s); + while p>0 do begin + encode:=ansichar(byte((pos(s[p+1],hexa) shl 4) or pos(s[p+2],hexa))); + if encode=#0 then begin + encode:=#13#10; + end; + result:=result+copy(s,1,p-1)+encode; + delete(s,1,p+2); + p:=BESENANSIPosChar('=',s); + end; + result:=result+s; + p:=BESENANSIPosChar('_',result); + while p>0 do begin + result[p]:=' '; + p:=BESENANSIPosChar('_',result); + end; + end; +end; + +const UnknownChar=#254; + +function GetCharsetTable(CharSet:TBESENCharset):TBESENCharsetTable; +begin + case CharSet of + ISO_8859_1:result:=BESENCharISO_8859_1; + ISO_8859_2:result:=BESENCharISO_8859_2; + ISO_8859_3:result:=BESENCharISO_8859_3; + ISO_8859_4:result:=BESENCharISO_8859_4; + ISO_8859_5:result:=BESENCharISO_8859_5; + ISO_8859_6:result:=BESENCharISO_8859_6; + ISO_8859_7:result:=BESENCharISO_8859_7; + ISO_8859_8:result:=BESENCharISO_8859_8; + ISO_8859_9:result:=BESENCharISO_8859_9; + ISO_8859_10:result:=BESENCharISO_8859_10; + CP1250:result:=BESENCharCP_1250; + CP1251:result:=BESENCharCP_1251; + CP1252:result:=BESENCharCP_1252; + CP1253:result:=BESENCharCP_1253; + CP1254:result:=BESENCharCP_1254; + CP1255:result:=BESENCharCP_1255; + CP1256:result:=BESENCharCP_1256; + CP1257:result:=BESENCharCP_1257; + CP1258:result:=BESENCharCP_1258; + KOI8_R:result:=BESENCharKOI8_R; + end; +end; + +function BESENIsUTF8(const s:TBESENANSISTRING):boolean; +var i,j:longint; + b:byte; +begin + j:=0; + i:=1; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + inc(j); + end else if ((i+1)<length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + inc(j); + end else if ((i+2)<length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + inc(j); + end else if ((i+3)<length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + inc(j); + end else if ((i+5)<length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + inc(j); +{$endif} + end else begin + i:=0; + j:=0; + break; + end; + end; + result:=(i>0) and (j>0); +end; + +function BESENEncodeString(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharset):TBESENANSISTRING; + function UTF16ToUTF32(const Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + s:widestring; + Buffer:array of longword; + v:longword; + w:word; + begin + SetLength(s,(length(Value)+1) and not 1); + i:=1; + j:=0; + while (i+1)<=length(Value) do begin + inc(j); + s[j]:=widechar(word((word(byte(Value[i])) shl 8) or byte(Value[i+1]))); + inc(i,2); + end; + SetLength(s,j); + SetLength(Buffer,length(s)); + j:=0; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + Buffer[j]:=w; + inc(j); + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + Buffer[j]:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(j); + inc(i,2); + end else begin + Buffer[j]:=$fffd; + inc(j); + inc(i); + end; + end; + SetLength(Buffer,j); + SetLength(result,length(Buffer)*4); + j:=1; + for i:=0 to length(Buffer)-1 do begin + v:=Buffer[i]; + result[j]:=ansichar(byte((v shr 24) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 16) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 8) and $ff)); + inc(j); + result[j]:=ansichar(byte(v and $ff)); + inc(j); + end; + SetLength(Buffer,0); + end; + function UTF32ToUTF16(const Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + w,u4c:TBESENUTF32CHAR; + Buffer:widestring; + s:array of longword; + begin + SetLength(s,(length(Value)+3) shr 2); + for i:=0 to length(s)-1 do begin + j:=(i shl 2)+1; + u4c:=0; + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 24); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 16); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 8); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or byte(Value[j]); + end; + end; + end; + end; + s[i]:=u4c; + end; + SetLength(Buffer,length(s)*2); + j:=0; + for i:=0 to length(s)-1 do begin + w:=s[i]; + if w<=$d7ff then begin + inc(j); + Buffer[j]:=widechar(word(w)); + end else if w<=$dfff then begin + inc(j); + Buffer[j]:=#$fffd; + end else if w<=$fffd then begin + inc(j); + Buffer[j]:=widechar(word(w)); + end else if w<=$ffff then begin + inc(j); + Buffer[j]:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + inc(j); + Buffer[j]:=widechar(word((w shr 10) or $d800)); + inc(j); + Buffer[j]:=widechar(word((w and $3ff) or $dc00)); + end else begin + inc(j); + Buffer[j]:=#$fffd; + end; + end; + SetLength(Buffer,j); + SetLength(result,length(Buffer)*2); + j:=1; + for i:=1 to length(Buffer) do begin + w:=word(Buffer[i]); + result[j]:=ansichar(byte((w shr 8) and $ff)); + inc(j); + result[j]:=ansichar(byte(w and $ff)); + inc(j); + end; + SetLength(Buffer,0); + end; + function UTF8ToUTF32(Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + b:byte; + Buffer:array of longword; + v:longword; + begin + j:=0; + i:=1; + while i<=length(Value) do begin + b:=byte(Value[i]); + if (b and $80)=0 then begin + inc(i); + inc(j); + end else if ((i+1)<=length(Value)) and ((b and $e0)=$c0) and ((byte(Value[i+1]) and $c0)=$80) then begin + inc(i,2); + inc(j); + end else if ((i+2)<=length(Value)) and ((b and $f0)=$e0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) then begin + inc(i,3); + inc(j); + end else if ((i+3)<=length(Value)) and ((b and $f8)=$f0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) then begin + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(Value)) and ((b and $fc)=$f8) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) then begin + inc(i,5); + inc(j); + end else if ((i+5)<=length(Value)) and ((b and $fe)=$fc) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) and ((byte(Value[i+5]) and $c0)=$80) then begin + inc(i,6); + inc(j); +{$endif} + end else begin + inc(i); + inc(j); + end; + end; + SetLength(Buffer,j); + if j=0 then begin + exit; + end; + j:=0; + i:=1; + while i<=length(Value) do begin + b:=byte(Value[i]); + if (b and $80)=0 then begin + Buffer[j]:=b; + inc(i); + inc(j); + end else if ((i+1)<=length(Value)) and ((b and $e0)=$c0) and ((byte(Value[i+1]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $1f) shl 6) or (byte(Value[i+1]) and $3f); + inc(i,2); + inc(j); + end else if ((i+2)<=length(Value)) and ((b and $f0)=$e0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $0f) shl 12) or ((byte(Value[i+1]) and $3f) shl 6) or (byte(Value[i+2]) and $3f); + inc(i,3); + inc(j); + end else if ((i+3)<=length(Value)) and ((b and $f8)=$f0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $07) shl 18) or ((byte(Value[i+1]) and $3f) shl 12) or ((byte(Value[i+2]) and $3f) shl 6) or (byte(Value[i+3]) and $3f); + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(Value)) and ((b and $fc)=$f8) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $03) shl 24) or ((byte(Value[i+1]) and $3f) shl 18) or ((byte(Value[i+2]) and $3f) shl 12) or ((byte(Value[i+3]) and $3f) shl 6) or (byte(Value[i+4]) and $3f); + inc(i,5); + inc(j); + end else if ((i+5)<=length(Value)) and ((b and $fe)=$fc) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) and ((byte(Value[i+5]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $01) shl 30) or ((byte(Value[i+1]) and $3f) shl 24) or ((byte(Value[i+2]) and $3f) shl 18) or ((byte(Value[i+3]) and $3f) shl 12) or ((byte(Value[i+4]) and $3f) shl 6) or (byte(Value[i+5]) and $3f); + inc(i,6); + inc(j); +{$endif} + end else begin + Buffer[j]:=$fffd; + inc(i); + inc(j); + end; + end; + SetLength(result,length(Buffer)*4); + j:=1; + for i:=0 to length(Buffer)-1 do begin + v:=Buffer[i]; + result[j]:=ansichar(byte((v shr 24) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 16) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 8) and $ff)); + inc(j); + result[j]:=ansichar(byte(v and $ff)); + inc(j); + end; + SetLength(Buffer,0); + end; + function UTF32toUTF8(Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + u4c:longword; + s:array of longword; + begin + SetLength(s,(length(Value)+3) shr 2); + for i:=0 to length(s)-1 do begin + j:=(i shl 2)+1; + u4c:=0; + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 24); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 16); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 8); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or byte(Value[j]); + end; + end; + end; + end; + s[i]:=u4c; + end; + result:=''; + j:=0; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + inc(j); + end else if u4c<=$7ff then begin + inc(j,2); + end else if u4c<=$ffff then begin + inc(j,3); + end else if u4c<=$1fffff then begin + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + inc(j,5); + end else if u4c<=$7fffffff then begin + inc(j,6); +{$endif} + end else begin + inc(j,3); + end; + end; + SetLength(result,j); + j:=1; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + result[j]:=ansichar(byte(u4c)); + inc(j); + end else if u4c<=$7ff then begin + result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); + result[j+1]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,2); + end else if u4c<=$ffff then begin + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end else if u4c<=$1fffff then begin + result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+3]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+4]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,5); + end else if u4c<=$7fffffff then begin + result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+5]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,6); +{$endif} + end else begin + u4c:=$fffd; + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end; + end; + SetLength(s,0); + end; + function UTF7toUCS2(Value:TBESENANSISTRING):TBESENANSISTRING; + var i:longint; + c:TBESENCHAR; + s:TBESENANSISTRING; + begin + result:=''; + i:=1; + while i<=length(Value) do begin + c:=Value[i]; + inc(i); + if c<>'+' then begin + result:=result+#0+c; + end else begin + s:=''; + while i<=length(Value) do begin + c:=Value[i]; + inc(i); + if c='-' then begin + break; + end else if (c='=') or (BESENANSIPosChar(c,BESENBase64Chars)<1) then begin + dec(i); + break; + end; + s:=s+c; + end; + if s='' then begin + s:='+'; + end else begin + s:=BESENDecodeBase64(s); + end; + result:=result+s; + end; + end; + end; + function UCS2toUTF7(Value:TBESENANSISTRING):TBESENANSISTRING; + var s:TBESENANSISTRING; + c1,c2:TBESENCHAR; + i,j:longint; + begin + result:=''; + i:=1; + while i<=length(Value) do begin + c2:=Value[i]; + if (i+1)<=length(Value) then begin + c1:=Value[i+1]; + end else begin + c1:=#0; + end; + inc(i,2); + if (c2=#0) and (c1<#128) then begin + if c1='+' then begin + result:=result+'+-'; + end else begin + result:=result+TBESENCHAR(c1); + end; + end else begin + s:=c2+c1; + while i<=length(Value) do begin + c2:=Value[i]; + if (i+1)<=length(Value) then begin + c1:=Value[i+1]; + end else begin + c1:=#0; + end; + if c2=#0 then begin + break; + end else begin + inc(i,2); + s:=s+c2+c1; + end; + end; + s:=BESENEncodeBase64(s); + j:=BESENANSIPosChar('=',s); + if j>0 then begin + s:=copy(s,1,j-1); + end; + result:=result+'+'+s+'-'; + end; + end; + end; +var Unicode:word; + i,j:longint; + b:byte; + c1,c2,c3,c4:TBESENCHAR; + SourceTable,TargetTable:TBESENCharsetTable; + FromByteCount,ToByteCount:byte; +begin + if CharFrom=CharTo then begin + result:=Value; + end else begin + SourceTable:=GetCharsetTable(CharFrom); + TargetTable:=GetCharsetTable(CharTo); + if CharFrom in [UCS_2,UTF_7] then begin + FromByteCount:=2; + end else if CharFrom in [UCS_4,UTF_32,UTF_16,UTF_8] then begin + FromByteCount:=4; + end else begin + FromByteCount:=1; + end; + if CharTo in [UCS_2,UTF_7] then begin + ToByteCount:=2; + end else if CharTo in [UCS_4,UTF_32,UTF_16,UTF_8] then begin + ToByteCount:=4; + end else begin + ToByteCount:=1; + end; + case CharFrom of + UTF_7:begin + Value:=UTF7toUCS2(Value); + end; + UTF_8:begin + Value:=UTF8ToUTF32(Value); + end; + UTF_16:begin + Value:=UTF16ToUTF32(Value); + end; + end; + c1:=#0; + c2:=#0; + c3:=#0; + c4:=#0; + result:=''; + i:=1; + while i<=length(Value) do begin + case FromByteCount of + 1:begin + c1:=Value[i]; + if c1>#127 then begin + Unicode:=SourceTable[byte(c1)]; + c1:=ansichar(byte(Unicode and $ff)); + c2:=ansichar(byte(Unicode shr 8)); + end; + inc(i); + end; + 2:begin + c2:=Value[i]; + if (i+1)<=length(Value) then begin + c1:=Value[i+1]; + end else begin + c1:=#0; + end; + inc(i,2); + end; + 3:begin + c3:=Value[i]; + if (i+1)<=length(Value) then begin + c2:=Value[i+1]; + end else begin + c2:=#0; + end; + if (i+2)<=length(Value) then begin + c1:=Value[i+2]; + end else begin + c1:=#0; + end; + inc(i,3); + end; + 4:begin + c4:=Value[i]; + if (i+1)<=length(Value) then begin + c3:=Value[i+1]; + end else begin + c3:=#0; + end; + if (i+2)<=length(Value) then begin + c2:=Value[i+2]; + end else begin + c2:=#0; + end; + if (i+3)<=length(Value) then begin + c1:=Value[i+3]; + end else begin + c1:=#0; + end; + inc(i,4); + end; + end; + Unicode:=(byte(c2) shl 8) or byte(c1); + if ToByteCount=1 then begin + if (c3<>#0) or (c4<>#0) then begin + c1:=UnknownChar; + c2:=#0; + c3:=#0; + c4:=#0; + end else begin + if Unicode>127 then begin + b:=ord(UnknownChar); + for j:=128 to 255 do begin + if TargetTable[j]=Unicode then begin + b:=j; + break; + end; + end; + c1:=ansichar(byte(b)); + c2:=#0; + end else begin + c1:=ansichar(byte(Unicode and $ff)); + end; + end; + end; + case ToByteCount of + 1:begin + result:=result+c1; + end; + 2:begin + result:=result+c2+c1; + end; + 3:begin + result:=result+c3+c2+c1; + end; + 4:begin + result:=result+c4+c3+c2+c1; + end; + end; + end; + case CharTo of + UTF_7:begin + result:=UCS2toUTF7(result); + end; + UTF_8:begin + result:=UTF32toUTF8(result); + end; + UTF_16:begin + result:=UTF32ToUTF16(result); + end; + end; + end; +end; + +function BESENGetCodePage(Value:TBESENANSISTRING):TBESENCharset; +begin + Value:=BESENANSIUpperCase(Value); + if BESENANSIPos('ISO-8859-10',Value)>0 then begin + result:=ISO_8859_10; + end else if BESENANSIPos('ISO-8859-1',Value)>0 then begin + result:=ISO_8859_1; + end else if BESENANSIPos('ISO-8859-2',Value)>0 then begin + result:=ISO_8859_2; + end else if BESENANSIPos('ISO-8859-3',Value)>0 then begin + result:=ISO_8859_3; + end else if BESENANSIPos('ISO-8859-4',Value)>0 then begin + result:=ISO_8859_4; + end else if BESENANSIPos('ISO-8859-5',Value)>0 then begin + result:=ISO_8859_5; + end else if BESENANSIPos('ISO-8859-6',Value)>0 then begin + result:=ISO_8859_6; + end else if BESENANSIPos('ISO-8859-7',Value)>0 then begin + result:=ISO_8859_7; + end else if BESENANSIPos('ISO-8859-8',Value)>0 then begin + result:=ISO_8859_8; + end else if BESENANSIPos('ISO-8859-9',Value)>0 then begin + result:=ISO_8859_9; + end else if (BESENANSIPos('WINDOWS-1250',Value)>0) or (BESENANSIPos('X-CP1250',Value)>0) then begin + result:=CP1250; + end else if (BESENANSIPos('WINDOWS-1251',Value)>0) or (BESENANSIPos('X-CP1251',Value)>0) then begin + result:=CP1251; + end else if (BESENANSIPos('WINDOWS-1252',Value)>0) or (BESENANSIPos('X-CP1252',Value)>0) then begin + result:=CP1252; + end else if (BESENANSIPos('WINDOWS-1253',Value)>0) or (BESENANSIPos('X-CP1253',Value)>0) then begin + result:=CP1253; + end else if (BESENANSIPos('WINDOWS-1254',Value)>0) or (BESENANSIPos('X-CP1254',Value)>0) then begin + result:=CP1254; + end else if (BESENANSIPos('WINDOWS-1255',Value)>0) or (BESENANSIPos('X-CP1255',Value)>0) then begin + result:=CP1255; + end else if (BESENANSIPos('WINDOWS-1256',Value)>0) or (BESENANSIPos('X-CP1256',Value)>0) then begin + result:=CP1256; + end else if (BESENANSIPos('WINDOWS-1257',Value)>0) or (BESENANSIPos('X-CP1257',Value)>0) then begin + result:=CP1257; + end else if (BESENANSIPos('WINDOWS-1258',Value)>0) or (BESENANSIPos('X-CP1258',Value)>0) then begin + result:=CP1258; + end else if BESENANSIPos('KOI8-R',Value)>0 then begin + result:=KOI8_R; + end else if BESENANSIPos('UTF-7',Value)>0 then begin + result:=UTF_7; + end else if BESENANSIPos('UTF-8',Value)>0 then begin + result:=UTF_8; + end else if BESENANSIPos('UTF-16',Value)>0 then begin + result:=UTF_16; + end else if BESENANSIPos('UTF-32',Value)>0 then begin + result:=UTF_32; + end else if BESENANSIPos('UCS-4',Value)>0 then begin + result:=UCS_4; + end else if BESENANSIPos('UCS-2',Value)>0 then begin + result:=UCS_2; + end else if BESENANSIPos('UNICODE',Value)>0 then begin + result:=UCS_2; + end else begin + result:=ISO_8859_1; + end; +end; + +function BESENGetCodePageID(Value:TBESENCharset):TBESENANSISTRING; +begin + case Value of + ISO_8859_2:result:='ISO-8859-2'; + ISO_8859_3:result:='ISO-8859-3'; + ISO_8859_4:result:='ISO-8859-4'; + ISO_8859_5:result:='ISO-8859-5'; + ISO_8859_6:result:='ISO-8859-6'; + ISO_8859_7:result:='ISO-8859-7'; + ISO_8859_8:result:='ISO-8859-8'; + ISO_8859_9:result:='ISO-8859-9'; + ISO_8859_10:result:='ISO-8859-10'; + CP1250:result:='WINDOWS-1250'; + CP1251:result:='WINDOWS-1251'; + CP1252:result:='WINDOWS-1252'; + CP1253:result:='WINDOWS-1253'; + CP1254:result:='WINDOWS-1254'; + CP1255:result:='WINDOWS-1255'; + CP1256:result:='WINDOWS-1256'; + CP1257:result:='WINDOWS-1257'; + CP1258:result:='WINDOWS-1258'; + KOI8_R:result:='KOI8-R'; + UCS_2:result:='Unicode-1-1-UCS-2'; + UCS_4:result:='Unicode-1-1-UCS-4'; + UTF_32:result:='UTF-32'; + UTF_16:result:='UTF-16'; + UTF_8:result:='UTF-8'; + UTF_7:result:='UTF-7'; + else result:='ISO-8859-1'; + end; +end; + +function BESENDoNeedEncoding(Value:TBESENANSISTRING):boolean; +var i:longint; +begin + result:=false; + for i:=1 to length(Value) do begin + if ord(Value[i])>127 then begin + result:=true; + break; + end; + end; +end; + +function BESENFindIdealCoding(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharsetSet):TBESENCharset; +var cs:TBESENCharset; + i,j,k:longint; + s,t:TBESENANSISTRING; +begin + result:=ISO_8859_1; + s:=''; + for i:=1 to length(Value) do begin + if ord(Value[i])>127 then begin + s:=s+Value[i]; + end; + end; + j:=128; + for cs:=low(TBESENCharset) to high(TBESENCharset) do begin + if cs in CharTo then begin + t:=BESENEncodeString(s,CharFrom,cs); + k:=0; + for i:=1 to length(t) do begin + if t[i]=UnknownChar then begin + inc(k); + end; + end; + if k<j then begin + j:=k; + result:=cs; + if k=0 then begin + break; + end; + end; + end; + end; +end; + +function BESENISOToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; +var q,us,e:TBESENANSISTRING; + encode:TBESENCHAR; + p1,p2,p3:longint; + cs:TBESENCharset; +begin + result:=''; + us:=BESENANSIUpperCase(s); + p1:=BESENANSIPos('=?ISO',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + e:=copy(q,1,p2-1); + cs:=BESENGetCodePage(e); + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + q:=BESENEncodeString(q,cs,UTF_8); + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?ISO',us); + end; + p1:=BESENANSIPos('=?UTF-7',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + q:=BESENEncodeString(s,UTF_7,UTF_8); + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?UTF-7',us); + end; + p1:=BESENANSIPos('=?UTF-8',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?UTF-8',us); + end; + p1:=BESENANSIPos('=?',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + e:=copy(q,1,p2-1); + cs:=BESENGetCodePage(e); + if cs=ISO_8859_1 then begin + result:=result+'=?'; + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?',us); + continue; + end; + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + q:=BESENEncodeString(q,cs,UTF_8); + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?',us); + end; + result:=result+BESENEncodeString(s,ISO_8859_1,UTF_8); +end; + +function BESENUTF32Pos(const ToFindString,InString:TBESENUTF32STRING):longint; +var i,j:longint; +begin + result:=-1; + for i:=0 to length(InString)-length(ToFindString) do begin + for j:=0 to length(ToFindString)-1 do begin + if ToFindString[j]<>InString[i+j] then begin + break; + end; + result:=i; + exit; + end; + end; +end; + +procedure BESENUTF32Delete(var s:TBESENUTF32STRING;Index,Len:longint); +var i,a,b:longint; +begin + if Index>=length(s) then begin + exit; + end; + if Len>length(s) then begin + Len:=length(s); + end; + if (Index+Len)>=length(s) then begin + Len:=length(s)-Index; + end; + a:=Index+Len; + b:=Index; + i:=length(s)-a; + move(s[a],s[b],i*sizeof(TBESENUTF32CHAR)); + SetLength(s,length(s)-Len); +end; + +function BESENUTF32Compare(const a,b:TBESENUTF32STRING):boolean; overload; +var i:longint; +begin + if a=b then begin + result:=true; + exit; + end; + if length(a)<>length(b) then begin + result:=false; + exit; + end; + for i:=0 to length(a)-1 do begin + if a[i]<>b[i] then begin + result:=false; + exit; + end; + end; + result:=true; +end; + +function BESENUTF32Compare(const a:TBESENUTF32STRING;const b:TBESENANSISTRING):boolean; overload; +var i:longint; +begin + if length(a)<>length(b) then begin + result:=false; + exit; + end; + for i:=0 to length(a)-1 do begin + if a[i]<>byte(b[i+1]) then begin + result:=false; + exit; + end; + end; + result:=true; +end; + +procedure BESENUTF32Clear(var a:TBESENUTF32STRING); +begin + SetLength(a,0); +end; + +procedure BESENBESENUTF32AddString(var a:TBESENUTF32STRING;const b:TBESENANSISTRING); +var i,j:longint; +begin + j:=length(a); + SetLength(a,j+length(b)); + for i:=1 to length(b) do begin + a[j+i-1]:=byte(b[i]); + end; +end; + +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENUTF32CHAR); overload; +var j:longint; +begin + j:=length(a); + SetLength(a,j+1); + a[j]:=b; +end; + +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENCHAR); overload; +var j:longint; +begin + j:=length(a); + SetLength(a,j+1); + a[j]:=byte(b); +end; + +procedure BESENUTF32Add(var a:TBESENUTF32STRING;const b:TBESENUTF32STRING); +var i,j:longint; +begin + j:=length(a); + SetLength(a,j+length(b)); + for i:=0 to length(b)-1 do begin + a[j+i]:=byte(b[i]); + end; +end; + +function BESENUTF32ToUTF8(const s:TBESENUTF32STRING):TBESENUTF8STRING; +var i,j:longint; + u4c:TBESENUTF32CHAR; +begin + result:=''; + j:=0; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + inc(j); + end else if u4c<=$7ff then begin + inc(j,2); + end else if u4c<=$ffff then begin + inc(j,3); + end else if u4c<=$1fffff then begin + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + inc(j,5); + end else if u4c<=$7fffffff then begin + inc(j,6); +{$endif} + end else begin + inc(j,3); + end; + end; + SetLength(result,j); + j:=1; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + result[j]:=ansichar(byte(u4c)); + inc(j); + end else if u4c<=$7ff then begin + result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); + result[j+1]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,2); + end else if u4c<=$ffff then begin + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end else if u4c<=$1fffff then begin + result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+3]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+4]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,5); + end else if u4c<=$7fffffff then begin + result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+5]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,6); +{$endif} + end else begin + u4c:=$fffd; + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end; + end; +end; + +function BESENUTF8ToUTF32(const s:TBESENUTF8STRING):TBESENUTF32STRING; +var i,j:longint; + b:byte; +begin + j:=0; + i:=1; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + inc(j); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + inc(j); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + inc(j); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + inc(j); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + inc(j); +{$endif} + end else begin + inc(i); + inc(j); + end; + end; + SetLength(result,j); + if j=0 then begin + exit; + end; + j:=0; + i:=1; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + result[j]:=b; + inc(i); + inc(j); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + inc(j); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + inc(j); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + inc(j); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); + inc(j); +{$endif} + end else begin + result[j]:=$fffd; + inc(i); + inc(j); + end; + end; +end; + +function BESENUTF8ToUTF16(const s:TBESENUTF8STRING):TBESENUTF16STRING; +var i,j:longint; + w:TBESENUTF32CHAR; + b:byte; +begin + result:=''; + i:=1; + j:=0; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + w:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + w:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + w:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + w:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + w:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + w:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); +{$endif} + end else begin + w:=$fffd; + inc(i); + end; + if w<=$d7ff then begin + inc(j); + end else if w<=$dfff then begin + inc(j); + end else if w<=$fffd then begin + inc(j); + end else if w<=$ffff then begin + inc(j); + end else if w<=$10ffff then begin + inc(j,2); + end else begin + inc(j); + end; + end; + SetLength(result,j); + i:=1; + j:=0; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + w:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + w:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + w:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + w:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + w:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + w:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); +{$endif} + end else begin + w:=$fffd; + inc(i); + end; + if w<=$d7ff then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$dfff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$fffd then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$ffff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + inc(j); + result[j]:=widechar(word((w shr 10) or $d800)); + inc(j); + result[j]:=widechar(word((w and $3ff) or $dc00)); + end else begin + inc(j); + result[j]:=#$fffd; + end; + end; +end; + +function BESENUTF16ToUTF8(const s:TBESENUTF16STRING):TBESENUTF8STRING; +var i,j:longint; + w:word; + u4c:TBESENUTF32CHAR; +begin + result:=''; + j:=0; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + u4c:=w; + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + u4c:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(i,2); + end else begin + u4c:=$fffd; + inc(i); + end; + if u4c<=$7f then begin + inc(j); + end else if u4c<=$7ff then begin + inc(j,2); + end else if u4c<=$ffff then begin + inc(j,3); + end else if u4c<=$1fffff then begin + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + inc(j,5); + end else if u4c<=$7fffffff then begin + inc(j,6); +{$endif} + end else begin + inc(j,3); + end; + end; + SetLength(result,j); + j:=1; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + u4c:=w; + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + u4c:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(i,2); + end else begin + u4c:=$fffd; + inc(i); + end; + if u4c<=$7f then begin + result[j]:=ansichar(byte(u4c)); + inc(j); + end else if u4c<=$7ff then begin + result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); + result[j+1]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,2); + end else if u4c<=$ffff then begin + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end else if u4c<=$1fffff then begin + result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+3]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+4]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,5); + end else if u4c<=$7fffffff then begin + result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+5]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,6); +{$endif} + end else begin + u4c:=$fffd; + result[j]:=ansichar(byte($e0 or (u4c shr 12))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end; + end; +end; +{$endif} + +function BESENUTF32ToUTF16(const s:TBESENUTF32STRING):TBESENUTF16STRING; +var i,j:longint; + w:TBESENUTF32CHAR; +begin + SetLength(result,length(s)*2); + j:=0; + for i:=0 to length(s)-1 do begin + w:=s[i]; + if w<=$d7ff then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$dfff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$fffd then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$ffff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + inc(j); + result[j]:=widechar(word((w shr 10) or $d800)); + inc(j); + result[j]:=widechar(word((w and $3ff) or $dc00)); + end else begin + inc(j); + result[j]:=#$fffd; + end; + end; + SetLength(result,j); +end; + +function BESENUTF32CHARToUTF16(w:TBESENUTF32CHAR):TBESENUTF16STRING; +begin + if w<=$d7ff then begin + result:=widechar(word(w)); + end else if w<=$dfff then begin + result:=#$fffd; + end else if w<=$fffd then begin + result:=widechar(word(w)); + end else if w<=$ffff then begin + result:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + result:=widechar(word((w shr 10) or $d800)); + result:=result+widechar(word((w and $3ff) or $dc00)); + end else begin + result:=#$fffd; + end; +end; + +function BESENUTF16ToUTF32(const s:TBESENUTF16STRING):TBESENUTF32STRING; +var i,j:longint; + w:word; +begin + SetLength(result,length(s)); + j:=0; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + result[j]:=w; + inc(j); + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + result[j]:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(j); + inc(i,2); + end else begin + result[j]:=$fffd; + inc(j); + inc(i); + end; + end; + SetLength(result,j); +end; + +{$ifndef BESENSingleStringType} +function BESENUTF32ToWIDESTRING(const s:TBESENUTF32STRING):widestring; +var i:longint; +begin + SetLength(result,length(s)); + for i:=0 to length(s)-1 do begin + result[i+1]:=widechar(word(s[i])); + end; +end; + +function BESENWIDESTRINGToUTF32(const s:widestring):TBESENUTF32STRING; +var i:longint; +begin + SetLength(result,length(s)); + for i:=1 to length(s) do begin + result[i-1]:=word(widechar(s[i])); + end; +end; + +function BESENUTF32ToSTRING(const s:TBESENUTF32STRING):TBESENANSISTRING; +var i:longint; +begin + SetLength(result,length(s)); + for i:=0 to length(s)-1 do begin + result[i+1]:=TBESENCHAR(byte(s[i])); + end; +end; + +function BESENSTRINGToUTF32(const s:TBESENANSISTRING):TBESENUTF32STRING; +var i:longint; +begin + SetLength(result,length(s)); + for i:=1 to length(s) do begin + result[i-1]:=byte(TBESENCHAR(s[i])); + end; +end; + +function BESENUTF32CharToUTF8(u4c:TBESENUTF32CHAR):TBESENUTF8STRING; +begin + if u4c<=$7f then begin + result:=ansichar(byte(u4c)); + end else if u4c<=$7ff then begin + result:=ansichar(byte($c0 or ((u4c shr 6) and $1f)))+ansichar(byte($80 or (u4c and $3f))); + end else if u4c<=$ffff then begin + result:=ansichar(byte($e0 or ((u4c shr 12) and $0f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); + end else if u4c<=$1fffff then begin + result:=ansichar(byte($f0 or ((u4c shr 18) and $07)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result:=ansichar(byte($f8 or ((u4c shr 24) and $03)))+ansichar(byte($80 or ((u4c shr 18) and $3f)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); + end else if u4c<=$7fffffff then begin + result:=ansichar(byte($fc or ((u4c shr 30) and $01)))+ansichar(byte($80 or ((u4c shr 24) and $3f)))+ansichar(byte($80 or ((u4c shr 18) and $3f)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); +{$endif} + end else begin + u4c:=$fffd; + result:=ansichar(byte($e0 or ((u4c shr 12) and $0f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); + end; +end; + +procedure BESENUTF8Inc(var s:TBESENUTF8STRING;var i:longint); +var b:byte; +begin + if (i>=1) and (i<=length(s)) then begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + end else begin + inc(i); + end; + end; +end; + +procedure BESENUTF8Dec(var s:TBESENUTF8STRING;var i:longint); +begin + if (i>=1) and (i<=(length(s)+1)) then begin + dec(i); + while i>0 do begin + if byte(s[i]) in [$80..$bf] then begin + dec(i); + end else begin + break; + end; + end; + end; +end; + +procedure BESENUTF8Delete(var s:TBESENUTF8STRING;i:longint); +begin + if (i>=1) and (i<=length(s)) then begin + delete(s,i,1); + while (i>=1) and (i<=length(s)+1) do begin + if byte(s[i]) in [$80..$bf] then begin + delete(s,i,1); + end else begin + break; + end; + end; + end; +end; + +function BESENUTF8Length(const s:TBESENUTF8STRING):longint; +var b:byte; + i,j:longint; +begin + result:=0; + i:=1; + j:=length(s); + while i<=j do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + end else begin + inc(i); + end; + inc(result); + end; +end; + +function BESENUTF8GetRawPos(const s:TBESENUTF8STRING;Index:longint):longint; +var b:byte; + i,j,k:longint; +begin + result:=0; + k:=1; + i:=1; + j:=length(s); + while i<=j do begin + if k=Index then begin + result:=i; + exit; + end; + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + end else begin + inc(i); + end; + inc(k); + end; +end; + +function BESENUTF8GetChar(var s:TBESENUTF8STRING;Index:longint):TBESENUTF32CHAR; +var b,i,j:longint; +begin + i:=1; + j:=0; + while i<=Index do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + result:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); + end else begin + result:=$fffd; + inc(i); + end; + inc(j); + if j=Index then begin + exit; + end; + end; + result:=0; +end; + +function BESENUTF8GetRawChar(var s:TBESENUTF8STRING;i:longint):TBESENUTF32CHAR; +var b:byte; +begin + if (i<1) or (i>length(s)) then begin + result:=0; + inc(i); + exit; + end; + b:=byte(s[i]); + if (b and $80)=0 then begin + result:=b; + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + end else begin + result:=$fffd; + end; +end; + +function BESENUTF8GetRawCharAndInc(var s:TBESENUTF8STRING;var i:longint):TBESENUTF32CHAR; +var b:byte; +begin + if (i<1) or (i>length(s)) then begin + result:=0; + inc(i); + exit; + end; + b:=byte(s[i]); + if (b and $80)=0 then begin + result:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); +{$endif} + end else begin + result:=$fffd; + inc(i); + end; +end; +{$endif} + +function BESENUTF8Pos(ToFindString,InString:TBESENUTF8STRING):longint; +var i,j,l:longint; + OK:boolean; +begin + result:=0; + i:=1; + while i<=length(InString) do begin + l:=i+length(ToFindString)-1; + if l>length(InString) then begin + exit; + end; + OK:=true; + for j:=1 to length(ToFindString) do begin + if InString[i+j-1]<>ToFindString[j] then begin + OK:=false; + break; + end; + end; + if OK then begin + result:=i; + exit; + end; + BESENUTF8Inc(InString,i); + end; +end; + +function BESENLowercase(const s:TBESENString):TBESENString; +var t:TBESENUTF32STRING; + i:longint; +begin + t:=BESENUTF16ToUTF32(s); + for i:=0 to length(t)-1 do begin + t[i]:=BESENUnicodeToLower(t[i]); + end; + result:=BESENUTF32ToUTF16(t); + SetLength(t,0); +end; + +function BESENUppercase(const s:TBESENString):TBESENString; +var t:TBESENUTF32STRING; + i:longint; +begin + t:=BESENUTF16ToUTF32(s); + for i:=0 to length(t)-1 do begin + t[i]:=BESENUnicodeToUpper(t[i]); + end; + result:=BESENUTF32ToUTF16(t); + SetLength(t,0); +end; + +function BESENJSONStringQuote(const s:TBESENString):TBESENString; +var i:longint; + c:word; +begin + result:='"'; + i:=1; + while i<=length(s) do begin + case s[i] of + '"','\':begin + result:=result+'\'+s[i]; + inc(i); + end; + #$0008:begin + result:=result+'\b'; + inc(i); + end; + #$0009:begin + result:=result+'\t'; + inc(i); + end; + #$000a:begin + result:=result+'\n'; + inc(i); + end; + #$000b:begin + result:=result+'\v'; + inc(i); + end; + #$000c:begin + result:=result+'\f'; + inc(i); + end; + #$000d:begin + result:=result+'\r'; + inc(i); + end; + #$0000..#$0007,#$000e..#$001f,#$007d..#$009f,#$00ad,#$0600..#$0604,#$070f,#$17b4,#$17b5,#$200c..#$200f,#$2028..#$202f,#$2060..#$206f,#$feff,#$fff0..#$ffff:begin + c:=word(widechar(s[i])); + result:=result+'\u'+BESENHexChars[false,(c shr 12) and $f]+BESENHexChars[false,(c shr 8) and $f]+BESENHexChars[false,(c shr 4) and $f]+BESENHexChars[false,c and $f]; + inc(i); + end; + else begin + result:=result+s[i]; + inc(i); + end; + end; + end; + result:=result+'"'; +end; + +function BESENIsHex(const v:word):boolean; +const IsCharHex:TBESENCharBitmap=($00,$00,$00,$00,$00,$00,$ff,$03,$7e,$00,$00,$00,$7e,$00,$00,$00); // [0-9a-fA-F] +begin + result:=(v<$80) and ((IsCharHex[(v shr 3) and $7f] and (1 shl (v and 7)))<>0); +end; + +procedure InitHexValues; +var i:longint; +begin + fillchar(BESENHexValues,sizeof(TBESENHexValues),#0); + for i:=0 to 15 do begin + BESENHexValues[word(widechar(BESENHexChars[false,i]))]:=i; + BESENHexValues[word(widechar(BESENHexChars[true,i]))]:=i; + end; +end; + +procedure InitBESEN; +begin +{$ifndef BESENSingleStringType} + InitBase64; +{$endif} + InitHexValues; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENTypes.pas b/3rd/besen/src/BESENTypes.pas new file mode 100644 index 000000000..3919fafed --- /dev/null +++ b/3rd/besen/src/BESENTypes.pas @@ -0,0 +1,200 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENTypes; +{$i BESEN.inc} + +interface + +uses BESENConstants; + +type{$ifdef BESENSingleStringType} + TBESENCHAR=widechar; + + PBESENCHAR=pwidechar; +{$else} + TBESENCHAR=ansichar; + + PBESENCHAR=pansichar; +{$endif} + + TBESENWIDECHAR=widechar; + + PBESENWIDECHAR=pwidechar; + + PBESENByte=^byte; + +{$ifdef BESENSingleStringType} +{$ifdef BESENEmbarcaderoNextGen} + WideString=UnicodeString; +{$endif} +{$else} + TBESENANSISTRING=ansistring; + + TBESENUTF8STRING=TBESENANSISTRING; +{$endif} + + TBESENUTF16STRING=widestring; + + TBESENUTF32CHAR=longword; + + PBESENUTF32CHARS=^TBESENUTF32CHARS; + TBESENUTF32CHARS=array[0..($7fffffff div sizeof(TBESENUTF32CHAR))-1] of TBESENUTF32CHAR; + + TBESENUTF32STRING=array of TBESENUTF32CHAR; + +{$ifdef fpc} + {$undef OldDelphi} +{$else} + {$ifdef conditionalexpressions} + {$if CompilerVersion>=23.0} + {$undef OldDelphi} + qword=uint64; + ptruint=NativeUInt; + ptrint=NativeInt; + {$else} + {$define OldDelphi} + {$ifend} + {$else} + {$define OldDelphi} + {$endif} +{$endif} +{$ifdef OldDelphi} + qword=int64; +{$ifdef cpu64} + ptruint=qword; + ptrint=int64; +{$else} + ptruint=longword; + ptrint=longint; +{$endif} +{$endif} + + TBESENParsingNumberType={$ifdef HAS_TYPE_EXTENDED}extended{$else}double{$endif}; + + PBESENNumber=^TBESENNumber; + TBESENNumber=double; + + TBESENBoolean=longbool; + + TBESENDate=TBEsenNumber; + + PBESENString=^TBESENString; + TBESENString=TBESENUTF16STRING; + + TBESENINT16=smallint; + TBESENUINT16=word; + + PBESENINT32=^TBESENINT32; + TBESENINT32=longint; + + PBESENUINT32=^TBESENUINT32; + TBESENUINT32=longword; + + PBESENINT64=^TBESENINT64; + TBESENINT64=int64; + +{$ifdef fpc} + PBESENQWORD=^TBESENQWORD; + TBESENQWORD=qword; +{$endif} + + TBESENHash=TBESENUINT32; + + TBESENTarget=TBESENINT32; + + PBESENByteArray=^TBESENByteArray; + TBESENByteArray=array[0..$7fffffff-2] of byte; + + PBESENUINT32Array=^TBESENUINT32Array; + TBESENUINT32Array=array[0..($7fffffff div sizeof(TBESENUINT32))-1] of TBESENUINT32; + + PBESENINT32Array=^TBESENINT32Array; + TBESENINT32Array=array[0..($7fffffff div sizeof(TBESENUINT32))-1] of TBESENINT32; + + PBESENINT64Array=^TBESENINT64Array; + TBESENINT64Array=array[0..($7fffffff div sizeof(TBESENINT64))-1] of TBESENINT64; + + TBESENBytes=array of byte; + + TBESENIntegers=array of integer; + + TBESENUINT32s=array of TBESENUINT32; + + TBESENINT32s=array of TBESENINT32; + + TBESENNativeCodePCOffsets=array of pointer; + + TBESENRadixChars=array[0..35] of TBESENCHAR; + + TBESENLocation=record + LineNumber:integer; + end; + + PBESENDoubleHiLo=^TBESENDoubleHiLo; + TBESENDoubleHiLo=packed record +{$ifdef BIG_ENDIAN} + Hi,Lo:longword; +{$else} + Lo,Hi:longword; +{$endif} + end; + + TBESENLocations=array of TBESENLocation; + + TBESENStrings=array of TBESENString; + + TBESENWarningProc=procedure(LineNumber:integer;const Msg:TBESENSTRING) of object; + + TBESENTraceType=(bttNONE,bttSTATEMENT,bttCALL,bttRETURN,bttTHROW,bttDEBUGGER); + + TBESENCompatibilityMode=record + Name:TBESENString; + Flag:longword; + end; + + TBESENCompatibilityModes=array[0..3] of TBESENCompatibilityMode; + +{$ifdef BESENDelphiHasNoSystemTimeMore} + TSystemTime=record + wYear:word; + wMonth:word; + wDayOfWeek:word; + wDay:word; + wHour:word; + wMinute:word; + wSecond:word; + wMilliseconds:word; + end; +{$endif} + +implementation + +end. diff --git a/3rd/besen/src/BESENUnicodeTables.pas b/3rd/besen/src/BESENUnicodeTables.pas new file mode 100644 index 000000000..7e258ccc1 --- /dev/null +++ b/3rd/besen/src/BESENUnicodeTables.pas @@ -0,0 +1,1274 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENUnicodeTables; +{$i BESEN.inc} + +interface + +const UnicodeXLut:array[0..1023] of byte=( + 0, 1, 2, 3, 4, 5, 6, 7, (* $0000 *) + 8, 9, 10, 11, 12, 13, 14, 15, (* $0200 *) + 16, 17, 18, 19, 20, 21, 22, 23, (* $0400 *) + 24, 25, 26, 27, 28, 28, 28, 28, (* $0600 *) + 28, 28, 28, 28, 29, 30, 31, 32, (* $0800 *) + 33, 34, 35, 36, 37, 38, 39, 40, (* $0A00 *) + 41, 42, 43, 44, 45, 46, 28, 28, (* $0C00 *) + 47, 48, 49, 50, 51, 52, 53, 28, (* $0E00 *) + 28, 28, 54, 55, 56, 57, 58, 59, (* $1000 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1C00 *) + 60, 60, 61, 62, 63, 64, 65, 66, (* $1E00 *) + 67, 68, 69, 70, 71, 72, 73, 74, (* $2000 *) + 75, 75, 75, 76, 77, 78, 28, 28, (* $2200 *) + 79, 80, 81, 82, 83, 83, 84, 85, (* $2400 *) + 86, 85, 28, 28, 87, 88, 89, 28, (* $2600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2C00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2E00 *) + 90, 91, 92, 93, 94, 56, 95, 28, (* $3000 *) + 96, 97, 98, 99, 83, 100, 83, 101, (* $3200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3C00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3E00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4000 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $4E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9C00 *) + 56, 56, 56, 56, 56, 56, 102, 28, (* $9E00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A000 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $AA00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $AC00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $AE00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $BA00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $BC00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $BE00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $CA00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $CC00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $CE00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $D000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $D200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $D400 *) + 56, 56, 56, 56, 56, 56, 103, 28, (* $D600 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $D800 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $DA00 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $DC00 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $DE00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E000 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E200 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E400 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E600 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E800 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $EA00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $EC00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $EE00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F000 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F200 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F400 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F600 *) +105, 105, 105, 105, 56, 56, 56, 56, (* $F800 *) +106, 28, 28, 28, 107, 108, 109, 110, (* $FA00 *) + 56, 56, 56, 56, 111, 112, 113, 114, (* $FC00 *) +115, 116, 56, 117, 118, 119, 120, 121); (* $FE00 *) + +UnicodeYLut:array[0..7807] of byte=( + 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) + 0, 1, 1, 1, 1, 1, 0, 0, (* 0 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) + 2, 3, 3, 3, 4, 3, 3, 3, (* 0 *) + 5, 6, 3, 7, 3, 8, 3, 3, (* 0 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 0 *) + 9, 9, 3, 3, 7, 7, 7, 3, (* 0 *) + 3, 10, 10, 10, 10, 10, 10, 10, (* 1 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 1 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 1 *) + 10, 10, 10, 5, 3, 6, 11, 12, (* 1 *) + 11, 13, 13, 13, 13, 13, 13, 13, (* 1 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 1 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 1 *) + 13, 13, 13, 5, 7, 6, 7, 0, (* 1 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 2, 3, 4, 4, 4, 4, 15, 15, (* 2 *) + 11, 15, 16, 5, 7, 8, 15, 11, (* 2 *) + 15, 7, 17, 17, 11, 16, 15, 3, (* 2 *) + 11, 18, 16, 6, 19, 19, 19, 3, (* 2 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 3 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 3 *) + 20, 20, 20, 20, 20, 20, 20, 7, (* 3 *) + 20, 20, 20, 20, 20, 20, 20, 16, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 7, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 22, (* 3 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 25, 26, 23, 24, 23, 24, 23, 24, (* 4 *) + 16, 23, 24, 23, 24, 23, 24, 23, (* 4 *) + 24, 23, 24, 23, 24, 23, 24, 23, (* 5 *) + 24, 16, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 27, 23, 24, 23, 24, 23, 24, 28, (* 5 *) + 16, 29, 23, 24, 23, 24, 30, 23, (* 6 *) + 24, 31, 31, 23, 24, 16, 32, 32, (* 6 *) + 33, 23, 24, 31, 34, 16, 35, 36, (* 6 *) + 23, 24, 16, 16, 35, 37, 16, 38, (* 6 *) + 23, 24, 23, 24, 23, 24, 38, 23, (* 6 *) + 24, 39, 40, 16, 23, 24, 39, 23, (* 6 *) + 24, 41, 41, 23, 24, 23, 24, 42, (* 6 *) + 23, 24, 16, 40, 23, 24, 40, 40, (* 6 *) + 40, 40, 40, 40, 43, 44, 45, 43, (* 7 *) + 44, 45, 43, 44, 45, 23, 24, 23, (* 7 *) + 24, 23, 24, 23, 24, 23, 24, 23, (* 7 *) + 24, 23, 24, 23, 24, 16, 23, 24, (* 7 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 7 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 7 *) + 16, 43, 44, 45, 23, 24, 46, 46, (* 7 *) + 46, 46, 23, 24, 23, 24, 23, 24, (* 7 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 9 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 9 *) + 16, 16, 16, 47, 48, 16, 49, 49, (* 9 *) + 50, 50, 16, 51, 16, 16, 16, 16, (* 9 *) + 49, 16, 16, 52, 16, 16, 16, 16, (* 9 *) + 53, 54, 16, 16, 16, 16, 16, 54, (* 9 *) + 16, 16, 55, 16, 16, 16, 16, 16, (* 9 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 9 *) + 16, 16, 16, 56, 16, 16, 16, 16, (* 10 *) + 56, 16, 57, 57, 16, 16, 16, 16, (* 10 *) + 16, 16, 58, 16, 16, 16, 16, 16, (* 10 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 10 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 10 *) + 16, 46, 46, 46, 46, 46, 46, 46, (* 10 *) + 59, 59, 59, 59, 59, 59, 59, 59, (* 10 *) + 59, 11, 11, 59, 59, 59, 59, 59, (* 10 *) + 59, 59, 11, 11, 11, 11, 11, 11, (* 11 *) + 11, 11, 11, 11, 11, 11, 11, 11, (* 11 *) + 59, 59, 11, 11, 11, 11, 11, 11, (* 11 *) + 11, 11, 11, 11, 11, 11, 11, 46, (* 11 *) + 59, 59, 59, 59, 59, 11, 11, 11, (* 11 *) + 11, 11, 46, 46, 46, 46, 46, 46, (* 11 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 11 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 11 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 60, 60, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 3, 3, 46, 46, (* 13 *) + 46, 46, 59, 46, 46, 46, 3, 46, (* 13 *) + 46, 46, 46, 46, 11, 11, 61, 3, (* 14 *) + 62, 62, 62, 46, 63, 46, 64, 64, (* 14 *) + 16, 20, 20, 20, 20, 20, 20, 20, (* 14 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 14 *) + 20, 20, 46, 20, 20, 20, 20, 20, (* 14 *) + 20, 20, 20, 20, 65, 66, 66, 66, (* 14 *) + 16, 21, 21, 21, 21, 21, 21, 21, (* 14 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 14 *) + 21, 21, 16, 21, 21, 21, 21, 21, (* 15 *) + 21, 21, 21, 21, 67, 68, 68, 46, (* 15 *) + 69, 70, 38, 38, 38, 71, 72, 46, (* 15 *) + 46, 46, 38, 46, 38, 46, 38, 46, (* 15 *) + 38, 46, 23, 24, 23, 24, 23, 24, (* 15 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 15 *) + 73, 74, 16, 40, 46, 46, 46, 46, (* 15 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 15 *) + 46, 75, 75, 75, 75, 75, 75, 75, (* 16 *) + 75, 75, 75, 75, 75, 46, 75, 75, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 16 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 16 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 17 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 17 *) + 46, 74, 74, 74, 74, 74, 74, 74, (* 17 *) + 74, 74, 74, 74, 74, 46, 74, 74, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 15, 60, 60, 60, 60, 46, (* 18 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 40, 23, 24, 23, 24, 46, 46, 23, (* 19 *) + 24, 46, 46, 23, 24, 46, 46, 46, (* 19 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) + 23, 24, 23, 24, 46, 46, 23, 24, (* 19 *) + 23, 24, 23, 24, 23, 24, 46, 46, (* 19 *) + 23, 24, 46, 46, 46, 46, 46, 46, (* 19 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 76, 76, 76, 76, 76, 76, 76, (* 20 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 20 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 21 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 21 *) + 76, 76, 76, 76, 76, 76, 76, 46, (* 21 *) + 46, 59, 3, 3, 3, 3, 3, 3, (* 21 *) + 46, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 16, (* 22 *) + 46, 3, 46, 46, 46, 46, 46, 46, (* 22 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 46, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 46, 60, 60, 60, 3, 60, (* 22 *) + 3, 60, 60, 3, 60, 46, 46, 46, (* 23 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 23 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) + 40, 40, 40, 46, 46, 46, 46, 46, (* 23 *) + 40, 40, 40, 3, 3, 46, 46, 46, (* 23 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 23 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 24 *) + 46, 46, 46, 46, 3, 46, 46, 46, (* 24 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 24 *) + 46, 46, 46, 3, 46, 46, 46, 3, (* 24 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 24 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 24 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 24 *) + 40, 40, 40, 46, 46, 46, 46, 46, (* 24 *) + 59, 40, 40, 40, 40, 40, 40, 40, (* 25 *) + 40, 40, 40, 60, 60, 60, 60, 60, (* 25 *) + 60, 60, 60, 46, 46, 46, 46, 46, (* 25 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 25 *) + 78, 78, 78, 78, 78, 78, 78, 78, (* 25 *) + 78, 78, 3, 3, 3, 3, 46, 46, (* 25 *) + 60, 40, 40, 40, 40, 40, 40, 40, (* 25 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 25 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 46, 46, 40, 40, 40, 40, 40, 46, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 27 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 27 *) + 40, 40, 40, 40, 3, 40, 60, 60, (* 27 *) + 60, 60, 60, 60, 60, 79, 79, 60, (* 27 *) + 60, 60, 60, 60, 60, 59, 59, 60, (* 27 *) + 60, 15, 60, 60, 60, 60, 46, 46, (* 27 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 27 *) + 9, 9, 46, 46, 46, 46, 46, 46, (* 27 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 60, 60, 80, 46, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 46, 46, 60, 40, 80, 80, (* 29 *) + 80, 60, 60, 60, 60, 60, 60, 60, (* 30 *) + 60, 80, 80, 80, 80, 60, 46, 46, (* 30 *) + 15, 60, 60, 60, 60, 46, 46, 46, (* 30 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 30 *) + 40, 40, 60, 60, 3, 3, 81, 81, (* 30 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 30 *) + 3, 46, 46, 46, 46, 46, 46, 46, (* 30 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 30 *) + 46, 60, 80, 80, 46, 40, 40, 40, (* 31 *) + 40, 40, 40, 40, 40, 46, 46, 40, (* 31 *) + 40, 46, 46, 40, 40, 40, 40, 40, (* 31 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 31 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 31 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 31 *) + 40, 46, 40, 46, 46, 46, 40, 40, (* 31 *) + 40, 40, 46, 46, 60, 46, 80, 80, (* 31 *) + 80, 60, 60, 60, 60, 46, 46, 80, (* 32 *) + 80, 46, 46, 80, 80, 60, 46, 46, (* 32 *) + 46, 46, 46, 46, 46, 46, 46, 80, (* 32 *) + 46, 46, 46, 46, 40, 40, 46, 40, (* 32 *) + 40, 40, 60, 60, 46, 46, 81, 81, (* 32 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 32 *) + 40, 40, 4, 4, 82, 82, 82, 82, (* 32 *) + 19, 83, 15, 46, 46, 46, 46, 46, (* 32 *) + 46, 46, 60, 46, 46, 40, 40, 40, (* 33 *) + 40, 40, 40, 46, 46, 46, 46, 40, (* 33 *) + 40, 46, 46, 40, 40, 40, 40, 40, (* 33 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 33 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 33 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 33 *) + 40, 46, 40, 40, 46, 40, 40, 46, (* 33 *) + 40, 40, 46, 46, 60, 46, 80, 80, (* 33 *) + 80, 60, 60, 46, 46, 46, 46, 60, (* 34 *) + 60, 46, 46, 60, 60, 60, 46, 46, (* 34 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 34 *) + 46, 40, 40, 40, 40, 46, 40, 46, (* 34 *) + 46, 46, 46, 46, 46, 46, 81, 81, (* 34 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 34 *) + 60, 60, 40, 40, 40, 46, 46, 46, (* 34 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 34 *) + 46, 60, 60, 80, 46, 40, 40, 40, (* 35 *) + 40, 40, 40, 40, 46, 40, 46, 40, (* 35 *) + 40, 40, 46, 40, 40, 40, 40, 40, (* 35 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 35 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 35 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 35 *) + 40, 46, 40, 40, 46, 40, 40, 40, (* 35 *) + 40, 40, 46, 46, 60, 40, 80, 80, (* 35 *) + 80, 60, 60, 60, 60, 60, 46, 60, (* 36 *) + 60, 80, 46, 80, 80, 60, 46, 46, (* 36 *) + 15, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 40, 46, 46, 46, 46, 46, 81, 81, (* 36 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 36 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 46, 60, 80, 80, 46, 40, 40, 40, (* 37 *) + 40, 40, 40, 40, 40, 46, 46, 40, (* 37 *) + 40, 46, 46, 40, 40, 40, 40, 40, (* 37 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 37 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 37 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 37 *) + 40, 46, 40, 40, 46, 46, 40, 40, (* 37 *) + 40, 40, 46, 46, 60, 40, 80, 60, (* 37 *) + 80, 60, 60, 60, 46, 46, 46, 80, (* 38 *) + 80, 46, 46, 80, 80, 60, 46, 46, (* 38 *) + 46, 46, 46, 46, 46, 46, 60, 80, (* 38 *) + 46, 46, 46, 46, 40, 40, 46, 40, (* 38 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 38 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 38 *) + 15, 46, 46, 46, 46, 46, 46, 46, (* 38 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 38 *) + 46, 46, 60, 80, 46, 40, 40, 40, (* 39 *) + 40, 40, 40, 46, 46, 46, 40, 40, (* 39 *) + 40, 46, 40, 40, 40, 40, 46, 46, (* 39 *) + 46, 40, 40, 46, 40, 46, 40, 40, (* 39 *) + 46, 46, 46, 40, 40, 46, 46, 46, (* 39 *) + 40, 40, 40, 46, 46, 46, 40, 40, (* 39 *) + 40, 40, 40, 40, 40, 40, 46, 40, (* 39 *) + 40, 40, 46, 46, 46, 46, 80, 80, (* 39 *) + 60, 80, 80, 46, 46, 46, 80, 80, (* 40 *) + 80, 46, 80, 80, 80, 60, 46, 46, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 80, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 81, (* 40 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 40 *) + 84, 19, 19, 46, 46, 46, 46, 46, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 40 *) + 46, 80, 80, 80, 46, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 40, 46, 40, 40, (* 41 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 46, 40, 40, 40, (* 41 *) + 40, 40, 46, 46, 46, 46, 60, 60, (* 41 *) + 60, 80, 80, 80, 80, 46, 60, 60, (* 42 *) + 60, 46, 60, 60, 60, 60, 46, 46, (* 42 *) + 46, 46, 46, 46, 46, 60, 60, 46, (* 42 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 42 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 42 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) + 46, 46, 80, 80, 46, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 40, 46, 40, 40, (* 43 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 46, 40, 40, 40, (* 43 *) + 40, 40, 46, 46, 46, 46, 80, 60, (* 43 *) + 80, 80, 80, 80, 80, 46, 60, 80, (* 44 *) + 80, 46, 80, 80, 60, 60, 46, 46, (* 44 *) + 46, 46, 46, 46, 46, 80, 80, 46, (* 44 *) + 46, 46, 46, 46, 46, 46, 40, 46, (* 44 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 44 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 44 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 44 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 44 *) + 46, 46, 80, 80, 46, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 46, 40, 40, (* 45 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 46, 46, 46, 46, 80, 80, (* 45 *) + 80, 60, 60, 60, 46, 46, 80, 80, (* 46 *) + 80, 46, 80, 80, 80, 60, 46, 46, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 80, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 46 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 3, (* 47 *) + 40, 60, 40, 40, 60, 60, 60, 60, (* 47 *) + 60, 60, 60, 46, 46, 46, 46, 4, (* 47 *) + 40, 40, 40, 40, 40, 40, 59, 60, (* 48 *) + 60, 60, 60, 60, 60, 60, 60, 15, (* 48 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 48 *) + 9, 9, 3, 3, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 40, 40, 46, 40, 46, 46, 40, (* 49 *) + 40, 46, 40, 46, 46, 40, 46, 46, (* 49 *) + 46, 46, 46, 46, 40, 40, 40, 40, (* 49 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 49 *) + 46, 40, 40, 40, 46, 40, 46, 40, (* 49 *) + 46, 46, 40, 40, 46, 40, 40, 3, (* 49 *) + 40, 60, 40, 40, 60, 60, 60, 60, (* 49 *) + 60, 60, 46, 60, 60, 40, 46, 46, (* 49 *) + 40, 40, 40, 40, 40, 46, 59, 46, (* 50 *) + 60, 60, 60, 60, 60, 60, 46, 46, (* 50 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 50 *) + 9, 9, 46, 46, 40, 40, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 15, 15, 15, 15, 3, 3, 3, 3, (* 51 *) + 3, 3, 3, 3, 3, 3, 3, 3, (* 51 *) + 3, 3, 3, 15, 15, 15, 15, 15, (* 51 *) + 60, 60, 15, 15, 15, 15, 15, 15, (* 51 *) + 78, 78, 78, 78, 78, 78, 78, 78, (* 51 *) + 78, 78, 85, 85, 85, 85, 85, 85, (* 51 *) + 85, 85, 85, 85, 15, 60, 15, 60, (* 51 *) + 15, 60, 5, 6, 5, 6, 80, 80, (* 51 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 46, 46, 46, 46, 46, 46, (* 52 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 52 *) + 60, 60, 60, 60, 60, 60, 60, 80, (* 52 *) + 60, 60, 60, 60, 60, 3, 60, 60, (* 53 *) + 60, 60, 60, 60, 46, 46, 46, 46, (* 53 *) + 60, 60, 60, 60, 60, 60, 46, 60, (* 53 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 53 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 53 *) + 60, 60, 60, 60, 60, 60, 46, 46, (* 53 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 53 *) + 46, 60, 46, 46, 46, 46, 46, 46, (* 53 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 46, 46, (* 55 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 46, (* 55 *) + 46, 46, 46, 3, 46, 46, 46, 46, (* 55 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 46, 46, 46, 46, 46, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 46, 46, 46, 46, 46, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 46, 46, 46, 46, 46, 46, (* 59 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 16, 16, (* 61 *) + 16, 16, 16, 16, 46, 46, 46, 46, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 46, 46, 46, 46, 46, 46, (* 62 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) + 86, 86, 86, 86, 86, 86, 46, 46, (* 63 *) + 87, 87, 87, 87, 87, 87, 46, 46, (* 63 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) + 86, 86, 86, 86, 86, 86, 46, 46, (* 64 *) + 87, 87, 87, 87, 87, 87, 46, 46, (* 64 *) + 16, 86, 16, 86, 16, 86, 16, 86, (* 64 *) + 46, 87, 46, 87, 46, 87, 46, 87, (* 64 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 64 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 64 *) + 88, 88, 89, 89, 89, 89, 90, 90, (* 64 *) + 91, 91, 92, 92, 93, 93, 46, 46, (* 64 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) + 86, 86, 16, 94, 16, 46, 16, 16, (* 65 *) + 87, 87, 95, 95, 96, 11, 38, 11, (* 65 *) + 11, 11, 16, 94, 16, 46, 16, 16, (* 66 *) + 97, 97, 97, 97, 96, 11, 11, 11, (* 66 *) + 86, 86, 16, 16, 46, 46, 16, 16, (* 66 *) + 87, 87, 98, 98, 46, 11, 11, 11, (* 66 *) + 86, 86, 16, 16, 16, 99, 16, 16, (* 66 *) + 87, 87, 100, 100, 101, 11, 11, 11, (* 66 *) + 46, 46, 16, 94, 16, 46, 16, 16, (* 66 *) +102, 102, 103, 103, 96, 11, 11, 46, (* 66 *) + 2, 2, 2, 2, 2, 2, 2, 2, (* 67 *) + 2, 2, 2, 2, 104, 104, 104, 104, (* 67 *) + 8, 8, 8, 8, 8, 8, 3, 3, (* 67 *) + 5, 6, 5, 5, 5, 6, 5, 5, (* 67 *) + 3, 3, 3, 3, 3, 3, 3, 3, (* 67 *) +105, 106, 104, 104, 104, 104, 104, 46, (* 67 *) + 3, 3, 3, 3, 3, 3, 3, 3, (* 67 *) + 3, 5, 6, 3, 3, 3, 3, 12, (* 67 *) + 12, 3, 3, 3, 7, 5, 6, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 104, 104, 104, 104, 104, 104, (* 68 *) + 17, 46, 46, 46, 17, 17, 17, 17, (* 68 *) + 17, 17, 7, 7, 7, 5, 6, 16, (* 68 *) +107, 107, 107, 107, 107, 107, 107, 107, (* 69 *) +107, 107, 7, 7, 7, 5, 6, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 4, 4, 4, 4, 4, 4, 4, 4, (* 69 *) + 4, 4, 4, 4, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 70 *) + 60, 60, 60, 60, 60, 79, 79, 79, (* 70 *) + 79, 60, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 15, 15, 38, 15, 15, 15, 15, 38, (* 71 *) + 15, 15, 16, 38, 38, 38, 16, 16, (* 71 *) + 38, 38, 38, 16, 15, 38, 15, 15, (* 71 *) + 38, 38, 38, 38, 38, 38, 15, 15, (* 71 *) + 15, 15, 15, 15, 38, 15, 38, 15, (* 71 *) + 38, 15, 38, 38, 38, 38, 16, 16, (* 71 *) + 38, 38, 15, 38, 16, 40, 40, 40, (* 71 *) + 40, 46, 46, 46, 46, 46, 46, 46, (* 71 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 72 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 72 *) + 46, 46, 46, 19, 19, 19, 19, 19, (* 72 *) + 19, 19, 19, 19, 19, 19, 19, 108, (* 72 *) +109, 109, 109, 109, 109, 109, 109, 109, (* 72 *) +109, 109, 109, 109, 110, 110, 110, 110, (* 72 *) +111, 111, 111, 111, 111, 111, 111, 111, (* 72 *) +111, 111, 111, 111, 112, 112, 112, 112, (* 72 *) +113, 113, 113, 46, 46, 46, 46, 46, (* 73 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 73 *) + + 7, 7, 7, 7, 7, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 7, 15, 7, 15, 15, 15, (* 74 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 15, 46, 46, 46, 46, 46, (* 74 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 74 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 74 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 46, 46, 46, 46, 46, 46, (* 76 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 76 *) + 15, 46, 15, 15, 15, 15, 15, 15, (* 77 *) + 7, 7, 7, 7, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 7, 7, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 5, 6, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 46, 46, 46, 46, 46, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 46, 46, 46, (* 79 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 80 *) + 15, 15, 15, 46, 46, 46, 46, 46, (* 80 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 80 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 80 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 80 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 80 *) +114, 114, 114, 114, 82, 82, 82, 82, (* 80 *) + 82, 82, 82, 82, 82, 82, 82, 82, (* 80 *) + 82, 82, 82, 82, 82, 82, 82, 82, (* 81 *) +115, 115, 115, 115, 115, 115, 115, 115, (* 81 *) +115, 115, 115, 115, 115, 115, 115, 115, (* 81 *) +115, 115, 115, 115, 15, 15, 15, 15, (* 81 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 81 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 81 *) + 15, 15, 15, 15, 15, 15, 116, 116, (* 81 *) +116, 116, 116, 116, 116, 116, 116, 116, (* 81 *) +116, 116, 116, 116, 116, 116, 116, 116, (* 82 *) +116, 116, 116, 116, 116, 116, 116, 116, (* 82 *) +117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) +117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) +117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) +117, 117, 118, 46, 46, 46, 46, 46, (* 82 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 82 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 82 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 46, 46, (* 84 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 85 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 46, 46, 46, 46, (* 86 *) + 46, 46, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 46, 15, 15, 15, 15, 46, 15, 15, (* 87 *) + 15, 15, 46, 46, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 46, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 88 *) + 15, 15, 15, 15, 46, 15, 46, 15, (* 88 *) + 15, 15, 15, 46, 46, 46, 15, 46, (* 88 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 88 *) + 46, 15, 15, 15, 15, 15, 15, 15, (* 88 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 88 *) + 46, 46, 46, 46, 46, 46, 119, 119, (* 88 *) +119, 119, 119, 119, 119, 119, 119, 119, (* 88 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 89 *) +114, 114, 83, 83, 83, 83, 83, 83, (* 89 *) + 83, 83, 83, 83, 15, 46, 46, 46, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 46, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 89 *) + 2, 3, 3, 3, 15, 59, 3, 120, (* 90 *) + 5, 6, 5, 6, 5, 6, 5, 6, (* 90 *) + 5, 6, 15, 15, 5, 6, 5, 6, (* 90 *) + 5, 6, 5, 6, 8, 5, 6, 5, (* 90 *) + 15, 121, 121, 121, 121, 121, 121, 121, (* 90 *) +121, 121, 60, 60, 60, 60, 60, 60, (* 90 *) + 8, 59, 59, 59, 59, 59, 15, 15, (* 90 *) + 46, 46, 46, 46, 46, 46, 46, 15, (* 90 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 46, 46, 46, (* 92 *) + 46, 60, 60, 59, 59, 59, 59, 46, (* 92 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 3, 59, 59, 59, 46, (* 93 *) + 46, 46, 46, 46, 46, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 46, 46, 46, (* 94 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 95 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 95 *) + 15, 15, 85, 85, 85, 85, 15, 15, (* 95 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 46, 46, 46, (* 96 *) + 85, 85, 85, 85, 85, 85, 85, 85, (* 96 *) + 85, 85, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 46, 46, 46, 46, (* 97 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) + 15, 15, 15, 15, 46, 46, 46, 15, (* 97 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 98 *) +114, 114, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 46, 46, 46, 46, 46, 46, 46, (* 98 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 46, 46, 46, 46, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 100 *) + 46, 46, 46, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 46, 46, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 101 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 46, 46, (* 102 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 46, 46, 46, 46, (* 103 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 46, 46, (* 106 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 106 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 106 *) + 16, 16, 16, 16, 16, 16, 16, 46, (* 107 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 107 *) + 46, 46, 46, 16, 16, 16, 16, 16, (* 107 *) + 46, 46, 46, 46, 46, 46, 60, 40, (* 107 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 107 *) + 40, 7, 40, 40, 40, 40, 40, 40, (* 107 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 107 *) + 40, 40, 40, 40, 40, 46, 40, 46, (* 107 *) + 40, 40, 46, 40, 40, 46, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 46, 46, 46, 46, 46, 46, (* 109 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 109 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 110 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 110 *) + 46, 46, 46, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 5, 6, (* 111 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 112 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 114 *) + 40, 40, 40, 40, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 60, 60, 60, 60, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 3, 8, 8, 12, 12, 5, 6, 5, (* 115 *) + 6, 5, 6, 5, 6, 5, 6, 5, (* 115 *) + 6, 5, 6, 5, 6, 46, 46, 46, (* 116 *) + 46, 3, 3, 3, 3, 12, 12, 12, (* 116 *) + 3, 3, 3, 46, 3, 3, 3, 3, (* 116 *) + 8, 5, 6, 5, 6, 5, 6, 3, (* 116 *) + 3, 3, 7, 8, 7, 7, 7, 46, (* 116 *) + 3, 4, 3, 3, 46, 46, 46, 46, (* 116 *) + 40, 40, 40, 46, 40, 46, 40, 40, (* 116 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 116 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 46, 46, 104, (* 117 *) + 46, 3, 3, 3, 4, 3, 3, 3, (* 118 *) + 5, 6, 3, 7, 3, 8, 3, 3, (* 118 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 118 *) + 9, 9, 3, 3, 7, 7, 7, 3, (* 118 *) + 3, 10, 10, 10, 10, 10, 10, 10, (* 118 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 118 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 118 *) + 10, 10, 10, 5, 3, 6, 11, 12, (* 118 *) + 11, 13, 13, 13, 13, 13, 13, 13, (* 119 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 119 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 119 *) + 13, 13, 13, 5, 7, 6, 7, 46, (* 119 *) + 46, 3, 5, 6, 3, 3, 40, 40, (* 119 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 119 *) + 59, 40, 40, 40, 40, 40, 40, 40, (* 119 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 119 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 59, 59, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 120 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) + 46, 46, 40, 40, 40, 46, 46, 46, (* 121 *) + 4, 4, 7, 11, 15, 4, 4, 46, (* 121 *) + 7, 7, 7, 7, 7, 15, 15, 46, (* 121 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 121 *) + 46, 46, 46, 46, 46, 15, 46, 46); (* 121 *) + +UnicodeALut:array[0..123] of longword=( + $0001000F, (* 0 Cc, ignorable *) + $0004000F, (* 1 Cc, whitespace *) + $0004000C, (* 2 Zs, whitespace *) + $00000018, (* 3 Po *) + $0006001A, (* 4 Sc, currency *) + $00000015, (* 5 Ps *) + $00000016, (* 6 Pe *) + $00000019, (* 7 Sm *) + $00000014, (* 8 Pd *) + $00036089, (* 9 Nd, identifier part, decimal 16 *) + $0827FF81, (* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 *) + $0000001B, (* 11 Sk *) + $00050017, (* 12 Pc, underscore *) + $0817FF82, (* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 *) + $0000000C, (* 14 Zs *) + $0000001C, (* 15 So *) + $00070182, (* 16 Ll, identifier start *) + $0000600B, (* 17 No, decimal 16 *) + $0000500B, (* 18 No, decimal 8 *) + $0000800B, (* 19 No, strange *) + $08270181, (* 20 Lu, hasLower (add 32), identifier start *) + $08170182, (* 21 Ll, hasUpper (subtract 32), identifier start *) + $E1D70182, (* 22 Ll, hasUpper (subtract -121), identifier start *) + $00670181, (* 23 Lu, hasLower (add 1), identifier start *) + $00570182, (* 24 Ll, hasUpper (subtract 1), identifier start *) + $CE670181, (* 25 Lu, hasLower (add -199), identifier start *) + $3A170182, (* 26 Ll, hasUpper (subtract 232), identifier start *) + $E1E70181, (* 27 Lu, hasLower (add -121), identifier start *) + $4B170182, (* 28 Ll, hasUpper (subtract 300), identifier start *) + $34A70181, (* 29 Lu, hasLower (add 210), identifier start *) + $33A70181, (* 30 Lu, hasLower (add 206), identifier start *) + $33670181, (* 31 Lu, hasLower (add 205), identifier start *) + $32A70181, (* 32 Lu, hasLower (add 202), identifier start *) + $32E70181, (* 33 Lu, hasLower (add 203), identifier start *) + $33E70181, (* 34 Lu, hasLower (add 207), identifier start *) + $34E70181, (* 35 Lu, hasLower (add 211), identifier start *) + $34670181, (* 36 Lu, hasLower (add 209), identifier start *) + $35670181, (* 37 Lu, hasLower (add 213), identifier start *) + $00070181, (* 38 Lu, identifier start *) + $36A70181, (* 39 Lu, hasLower (add 218), identifier start *) + $00070185, (* 40 Lo, identifier start *) + $36670181, (* 41 Lu, hasLower (add 217), identifier start *) + $36E70181, (* 42 Lu, hasLower (add 219), identifier start *) + $00AF0181, (* 43 Lu, hasLower (add 2), hasTitle, identifier start *) + $007F0183, (* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start *) + $009F0182, (* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start *) + $00000000, (* 46 unassigned *) + $34970182, (* 47 Ll, hasUpper (subtract 210), identifier start *) + $33970182, (* 48 Ll, hasUpper (subtract 206), identifier start *) + $33570182, (* 49 Ll, hasUpper (subtract 205), identifier start *) + $32970182, (* 50 Ll, hasUpper (subtract 202), identifier start *) + $32D70182, (* 51 Ll, hasUpper (subtract 203), identifier start *) + $33D70182, (* 52 Ll, hasUpper (subtract 207), identifier start *) + $34570182, (* 53 Ll, hasUpper (subtract 209), identifier start *) + $34D70182, (* 54 Ll, hasUpper (subtract 211), identifier start *) + $35570182, (* 55 Ll, hasUpper (subtract 213), identifier start *) + $36970182, (* 56 Ll, hasUpper (subtract 218), identifier start *) + $36570182, (* 57 Ll, hasUpper (subtract 217), identifier start *) + $36D70182, (* 58 Ll, hasUpper (subtract 219), identifier start *) + $00070084, (* 59 Lm, identifier start *) + $00030086, (* 60 Mn, identifier part *) + $09A70181, (* 61 Lu, hasLower (add 38), identifier start *) + $09670181, (* 62 Lu, hasLower (add 37), identifier start *) + $10270181, (* 63 Lu, hasLower (add 64), identifier start *) + $0FE70181, (* 64 Lu, hasLower (add 63), identifier start *) + $09970182, (* 65 Ll, hasUpper (subtract 38), identifier start *) + $09570182, (* 66 Ll, hasUpper (subtract 37), identifier start *) + $10170182, (* 67 Ll, hasUpper (subtract 64), identifier start *) + $0FD70182, (* 68 Ll, hasUpper (subtract 63), identifier start *) + $0F970182, (* 69 Ll, hasUpper (subtract 62), identifier start *) + $0E570182, (* 70 Ll, hasUpper (subtract 57), identifier start *) + $0BD70182, (* 71 Ll, hasUpper (subtract 47), identifier start *) + $0D970182, (* 72 Ll, hasUpper (subtract 54), identifier start *) + $15970182, (* 73 Ll, hasUpper (subtract 86), identifier start *) + $14170182, (* 74 Ll, hasUpper (subtract 80), identifier start *) + $14270181, (* 75 Lu, hasLower (add 80), identifier start *) + $0C270181, (* 76 Lu, hasLower (add 48), identifier start *) + $0C170182, (* 77 Ll, hasUpper (subtract 48), identifier start *) + $00034089, (* 78 Nd, identifier part, decimal 0 *) + $00000087, (* 79 Me *) + $00030088, (* 80 Mc, identifier part *) + $00037489, (* 81 Nd, identifier part, decimal 26 *) + $00005A0B, (* 82 No, decimal 13 *) + $00006E0B, (* 83 No, decimal 23 *) + $0000740B, (* 84 No, decimal 26 *) + $0000000B, (* 85 No *) + $FE170182, (* 86 Ll, hasUpper (subtract -8), identifier start *) + $FE270181, (* 87 Lu, hasLower (add -8), identifier start *) + $ED970182, (* 88 Ll, hasUpper (subtract -74), identifier start *) + $EA970182, (* 89 Ll, hasUpper (subtract -86), identifier start *) + $E7170182, (* 90 Ll, hasUpper (subtract -100), identifier start *) + $E0170182, (* 91 Ll, hasUpper (subtract -128), identifier start *) + $E4170182, (* 92 Ll, hasUpper (subtract -112), identifier start *) + $E0970182, (* 93 Ll, hasUpper (subtract -126), identifier start *) + $FDD70182, (* 94 Ll, hasUpper (subtract -9), identifier start *) + $EDA70181, (* 95 Lu, hasLower (add -74), identifier start *) + $FDE70181, (* 96 Lu, hasLower (add -9), identifier start *) + $EAA70181, (* 97 Lu, hasLower (add -86), identifier start *) + $E7270181, (* 98 Lu, hasLower (add -100), identifier start *) + $FE570182, (* 99 Ll, hasUpper (subtract -7), identifier start *) + $E4270181, (* 100 Lu, hasLower (add -112), identifier start *) + $FE670181, (* 101 Lu, hasLower (add -7), identifier start *) + $E0270181, (* 102 Lu, hasLower (add -128), identifier start *) + $E0A70181, (* 103 Lu, hasLower (add -126), identifier start *) + $00010010, (* 104 Cf, ignorable *) + $0004000D, (* 105 Zl, whitespace *) + $0004000E, (* 106 Zp, whitespace *) + $0000400B, (* 107 No, decimal 0 *) + $0000440B, (* 108 No, decimal 2 *) + $0427438A, (* 109 Nl, hasLower (add 16), identifier start, decimal 1 *) + $0427818A, (* 110 Nl, hasLower (add 16), identifier start, strange *) + $0417638A, (* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 *) + $0417818A, (* 112 Nl, hasUpper (subtract 16), identifier start, strange *) + $0007818A, (* 113 Nl, identifier start, strange *) + $0000420B, (* 114 No, decimal 1 *) + $0000720B, (* 115 No, decimal 25 *) + $06A0001C, (* 116 So, hasLower (add 26) *) + $0690001C, (* 117 So, hasUpper (subtract 26) *) + $00006C0B, (* 118 No, decimal 22 *) + $0000560B, (* 119 No, decimal 11 *) + $0007738A, (* 120 Nl, identifier start, decimal 25 *) + $0007418A, (* 121 Nl, identifier start, decimal 0 *) + $00000013, (* 122 Cs *) + $00000012); (* 123 Co *) + + +implementation + +end. diff --git a/3rd/besen/src/BESENUtils.pas b/3rd/besen/src/BESENUtils.pas new file mode 100644 index 000000000..cc18900cd --- /dev/null +++ b/3rd/besen/src/BESENUtils.pas @@ -0,0 +1,76 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENUtils; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +function BESENRoundUpToMask(x,m:ptruint):ptruint; +function BESENRoundUpToPowerOfTwo(x:ptruint):ptruint; + +procedure BESENFreeAndNil(var Obj); + +implementation + +function BESENRoundUpToMask(x,m:ptruint):ptruint; +begin + if (x and (m-1))<>0 then begin + result:=(x+m) and not (m-1); + end else begin + result:=x; + end; +end; + +function BESENRoundUpToPowerOfTwo(x:ptruint):ptruint; +begin + dec(x); + x:=x or (x shr 1); + x:=x or (x shr 2); + x:=x or (x shr 4); + x:=x or (x shr 8); + x:=x or (x shr 16); +{$ifdef cpu64} + x:=x or (x shr 32); +{$endif} + result:=x+1; +end; + +procedure BESENFreeAndNil(var Obj); +begin + if assigned(TObject(Obj)) then begin + TObject(Obj).Free; + TObject(Obj):=nil; + end; +end; + +end. diff --git a/3rd/besen/src/BESENValue.pas b/3rd/besen/src/BESENValue.pas new file mode 100644 index 000000000..a9d22b2ad --- /dev/null +++ b/3rd/besen/src/BESENValue.pas @@ -0,0 +1,705 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENValue; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils,BESENCharSet,Variants; + +const brbvtUNDEFINED=0; + brbvtBOOLEAN=1; + brbvtNUMBER=2; + brbvtSTRING=3; + brbvtOBJECT=4; + brbvtENVREC=5; + + brbvtFIRST=brbvtUNDEFINED; + brbvtLAST=brbvtENVREC; + + bvtUNDEFINED=0; + bvtNULL=1; + bvtBOOLEAN=2; + bvtNUMBER=3; + bvtSTRING=4; + bvtOBJECT=5; + bvtREFERENCE=6; + bvtLOCAL=7; + bvtENVREC=8; + bvtNONE=9; + + bvtFIRST=bvtUNDEFINED; + bvtLAST=bvtNONE; + +type TBESENReferenceBaseValueType=ptruint; + + PBESENReferenceBaseValue=^TBESENReferenceBaseValue; + TBESENReferenceBaseValue=record + Str:TBESENString; +{$ifdef BESENEmbarcaderoNextGen} + Obj:TObject; + EnvRec:TObject; +{$endif} + case ValueType:TBESENReferenceBaseValueType of + brbvtUNDEFINED:( + ); + brbvtBOOLEAN:( + Bool:TBESENBoolean; + ); + brbvtNUMBER:( + Num:TBESENNumber; + ); + brbvtSTRING:( + ); + brbvtOBJECT:( +{$ifndef BESENEmbarcaderoNextGen} + Obj:TObject; +{$endif} + ); + brbvtENVREC:( +{$ifndef BESENEmbarcaderoNextGen} + EnvRec:TObject; +{$endif} + ); + end; + + TBESENValueType=ptruint; + + PBESENValue=^TBESENValue; + TBESENValue=record + Str:TBESENString; + ReferenceBase:TBESENReferenceBaseValue; +{$ifdef BESENEmbarcaderoNextGen} + Obj:TObject; + EnvRec:TObject; +{$endif} + case ValueType:TBESENValueType of + bvtUNDEFINED:( + ); + bvtNULL:( + ); + bvtBOOLEAN:( + Bool:TBESENBoolean; + ); + bvtNUMBER:( + Num:TBESENNumber; + ); + bvtSTRING:( + ); + bvtOBJECT:( +{$ifndef BESENEmbarcaderoNextGen} + Obj:TObject; +{$endif} + ); + bvtREFERENCE:( + ReferenceIsStrict:longbool; + ReferenceHash:TBESENHash; + ReferenceIndex:TBESENINT32; + ReferenceID:TBESENINT32; + ); + bvtLOCAL:( + LocalIndex:TBESENINT32; + ); + bvtENVREC:( +{$ifndef BESENEmbarcaderoNextGen} + EnvRec:TObject; +{$endif} + ); + bvtNONE:( + ); + end; + + TBESENValueTypes=array of TBESENValueType; + + TBESENValueTypesItems=array of TBESENValueTypes; + + TBESENValues=array of TBESENValue; + + TBESENValuePointers=array of PBESENValue; + + PPBESENValues=^TPBESENValues; + TPBESENValues=array[0..($7fffffff div sizeof(PBESENValue))-1] of PBESENValue; + + TBESENPointerToValues=array of PBESENValue; + + TBESENCopyReferenceBaseValueProc=procedure(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + + TBESENCopyReferenceBaseValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENCopyReferenceBaseValueProc; + + TBESENCopyValueProc=procedure(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + + TBESENCopyValueProcs=array[bvtFIRST..bvtLAST] of TBESENCopyValueProc; + + TBESENValueToRefBaseValueProc=procedure(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + + TBESENValueToRefBaseValueProcs=array[bvtFIRST..bvtLAST] of TBESENValueToRefBaseValueProc; + + TBESENRefBaseValueToValueProc=procedure(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + + TBESENRefBaseValueToValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENRefBaseValueToValueProc; + + TBESENRefBaseValueToCallThisArgValueProc=procedure(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); + + TBESENRefBaseValueToCallThisArgValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENRefBaseValueToCallThisArgValueProc; + +procedure BESENCopyReferenceBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENCopyReferenceBaseValue(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENCopyValueUndefined(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueNull(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueBoolean(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueNumber(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueString(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueObject(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueReference(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueLocal(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueEnvRec(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueNone(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENCopyValue(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENValueToRefBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueNull(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueReference(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueLocal(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENValueToReferenceBaseValue(const Value:TBESENValue;var AResult:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENRefBaseValueToValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENReferenceBaseValueToValue(const Value:TBESENReferenceBaseValue;var AResult:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENRefBaseValueToCallThisArgValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +const BESENCopyReferenceBaseValueProcs:TBESENCopyReferenceBaseValueProcs=(BESENCopyReferenceBaseValueUndefined, + BESENCopyReferenceBaseValueBoolean, + BESENCopyReferenceBaseValueNumber, + BESENCopyReferenceBaseValueString, + BESENCopyReferenceBaseValueObject, + BESENCopyReferenceBaseValueEnvRec); + + BESENCopyValueProcs:TBESENCopyValueProcs=(BESENCopyValueUndefined, + BESENCopyValueNull, + BESENCopyValueBoolean, + BESENCopyValueNumber, + BESENCopyValueString, + BESENCopyValueObject, + BESENCopyValueReference, + BESENCopyValueLocal, + BESENCopyValueEnvRec, + BESENCopyValueNone); + + BESENValueToRefBaseValueProcs:TBESENValueToRefBaseValueProcs=(BESENValueToRefBaseValueUndefined, + BESENValueToRefBaseValueNull, + BESENValueToRefBaseValueBoolean, + BESENValueToRefBaseValueNumber, + BESENValueToRefBaseValueString, + BESENValueToRefBaseValueObject, + BESENValueToRefBaseValueReference, + BESENValueToRefBaseValueLocal, + BESENValueToRefBaseValueEnvRec, + BESENValueToRefBaseValueNone); + + BESENRefBaseValueToValueProcs:TBESENRefBaseValueToValueProcs=(BESENRefBaseValueToValueUndefined, + BESENRefBaseValueToValueBoolean, + BESENRefBaseValueToValueNumber, + BESENRefBaseValueToValueString, + BESENRefBaseValueToValueObject, + BESENRefBaseValueToValueEnvRec); + + BESENRefBaseValueToCallThisArgValueProcs:TBESENRefBaseValueToCallThisArgValueProcs=(BESENRefBaseValueToCallThisArgValueUndefined, + BESENRefBaseValueToCallThisArgValueBoolean, + BESENRefBaseValueToCallThisArgValueNumber, + BESENRefBaseValueToCallThisArgValueString, + BESENRefBaseValueToCallThisArgValueObject, + BESENRefBaseValueToCallThisArgValueEnvRec); + +function BESENValueToVariant(const v:TBESENValue):Variant; +procedure BESENVariantToValue(const vt:Variant;var v:TBESENValue); + +function BESENBooleanValue(const Bool:TBESENBoolean):TBESENValue; +function BESENNumberValue(const Num:TBESENNumber):TBESENValue; +function BESENStringValue(const Str:TBESENString):TBESENValue; +{$ifndef BESENSingleStringType} +function BESENStringLocaleCharsetValue(const Str:TBESENAnsiString):TBESENValue; +{$endif} +function BESENObjectValue(const Obj:TObject):TBESENValue; +function BESENObjectValueEx(const Obj:TObject):TBESENValue; + +function BESENEqualityExpressionStrictEquals(const a,b:TBESENValue):longbool; + +var BESENEmptyValue:TBESENValue; + BESENNullValue:TBESENValue; + BESENUndefinedValue:TBESENValue; + BESENDummyValue:TBESENValue; + +implementation + +uses BESEN,BESENNumberUtils,BESENEnvironmentRecord; + +procedure BESENCopyReferenceBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENCopyReferenceBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENCopyReferenceBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENCopyReferenceBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENCopyReferenceBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENCopyReferenceBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENCopyReferenceBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNONE; +end; + +procedure BESENCopyReferenceBaseValue(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyReferenceBaseValueProcs[Src.ValueType](Dest,Src); +end; + +procedure BESENCopyValueUndefined(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtUNDEFINED; +end; + +procedure BESENCopyValueNull(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNULL; +end; + +procedure BESENCopyValueBoolean(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENCopyValueNumber(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENCopyValueString(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENCopyValueObject(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENCopyValueReference(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtREFERENCE; + BESENCopyReferenceBaseValue(Dest.ReferenceBase,Src.ReferenceBase); + Dest.Str:=Src.Str; + Dest.ReferenceIsStrict:=Src.ReferenceIsStrict; + Dest.ReferenceHash:=Src.ReferenceHash; + Dest.ReferenceIndex:=Src.ReferenceIndex; + Dest.ReferenceID:=Src.ReferenceID; +end; + +procedure BESENCopyValueLocal(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtLOCAL; + Dest.LocalIndex:=Src.LocalIndex; +end; + +procedure BESENCopyValueEnvRec(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENCopyValueNone(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNONE; +end; + +procedure BESENCopyValue(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValueProcs[Src.ValueType](Dest,Src); +end; + +procedure BESENValueToRefBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueNull(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENValueToRefBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENValueToRefBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENValueToRefBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENValueToRefBaseValueReference(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueLocal(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENValueToRefBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToReferenceBaseValue(const Value:TBESENValue;var AResult:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + BESENValueToRefBaseValueProcs[Value.ValueType](AResult,Value); +end; + +procedure BESENRefBaseValueToValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtUNDEFINED; +end; + +procedure BESENRefBaseValueToValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENRefBaseValueToValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENRefBaseValueToValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENRefBaseValueToValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENRefBaseValueToValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENReferenceBaseValueToValue(const Value:TBESENReferenceBaseValue;var AResult:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + BESENRefBaseValueToValueProcs[Value.ValueType](AResult,Value); +end; + +procedure BESENRefBaseValueToCallThisArgValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtUNDEFINED; +end; + +procedure BESENRefBaseValueToCallThisArgValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENRefBaseValueToCallThisArgValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENRefBaseValueToCallThisArgValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENRefBaseValueToCallThisArgValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENRefBaseValueToCallThisArgValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +var ImplicitThisValue:PBESENValue; +begin + ImplicitThisValue:=@TBESENEnvironmentRecord(Src.EnvRec).ImplicitThisValue; + Dest.ValueType:=ImplicitThisValue.ValueType; + Dest.Obj:=ImplicitThisValue.Obj; +end; + +function BESENValueToVariant(const v:TBESENValue):Variant; +begin + case v.ValueType of + bvtNULL:begin + result:=Variants.Null; + end; + bvtBOOLEAN:begin + result:=V.Bool; + end; + bvtSTRING:begin + result:=V.Str; + end; + bvtNUMBER:begin + result:=V.Num; + end; + else begin + result:=Variants.Unassigned; + end; + end; +end; + +procedure BESENVariantToValue(const vt:Variant;var v:TBESENValue); +begin + try + case VarType(vt) of + varNull:begin + V.ValueType:=bvtNULL; + end; + varSmallInt,varInteger,varShortInt,varByte,varWord,varLongWord,varInt64{$ifdef fpc},varQWord{$endif}:begin + V.ValueType:=bvtNUMBER; + V.Num:=vt; + end; + varSingle,varDouble,varDATE,varCurrency:begin + V.ValueType:=bvtNUMBER; + V.Num:=vt; + end; + varBoolean:begin + V.ValueType:=bvtBOOLEAN; + V.Bool:=vt; + end; + varString,varOleStr:begin + V.ValueType:=bvtSTRING; + V.Str:=vt; + end; + else begin + V.ValueType:=bvtUNDEFINED; + end; + end; + except + V.ValueType:=bvtUNDEFINED; + end; +end; + +function BESENBooleanValue(const Bool:TBESENBoolean):TBESENValue; +begin + result.ValueType:=bvtBOOLEAN; + result.Bool:=Bool; +end; + +function BESENNumberValue(const Num:TBESENNumber):TBESENValue; +begin + result.ValueType:=bvtNUMBER; + result.Num:=Num; +end; + +function BESENStringValue(const Str:TBESENString):TBESENValue; +begin + result.ValueType:=bvtSTRING; + result.Str:=Str; +end; + +{$ifndef BESENSingleStringType} +function BESENStringLocaleCharsetValue(const Str:TBESENAnsiString):TBESENValue; +begin + result.ValueType:=bvtSTRING; + result.Str:=BESENUTF8ToUTF16(BESENEncodeString(Str,BESENLocaleCharset,UTF_8)); +end; +{$endif} + +function BESENObjectValue(const Obj:TObject):TBESENValue; +begin + result.ValueType:=bvtOBJECT; + result.Obj:=Obj; +end; + +function BESENObjectValueEx(const Obj:TObject):TBESENValue; +begin + if assigned(Obj) then begin + result.ValueType:=bvtOBJECT; + result.Obj:=Obj; + end else begin + result:=BESENNullValue; + end; +end; + +function BESENObjectValueEx2(const Obj:TObject):TBESENValue; +begin + if assigned(Obj) then begin + result.ValueType:=bvtOBJECT; + result.Obj:=Obj; + end else begin + result:=BESENUndefinedValue; + end; +end; + +function BESENEqualityExpressionStrictEquals(const a,b:TBESENValue):longbool; +begin + if a.ValueType<>b.ValueType then begin + result:=false; + end else begin + case a.ValueType of + bvtUNDEFINED:begin + result:=true; + end; + bvtNULL:begin + result:=true; + end; + bvtNUMBER:begin +{$ifdef UseSafeOperations} + if BESENIsNaN(a.Num) then begin + result:=false; + end else if BESENIsNaN(b.Num) then begin + result:=false; + end else begin + result:=(a.Num=b.Num) or (BESENIsZero(a.Num) and BESENIsZero(b.Num)); + end; +{$else} + result:=(not (BESENIsNaN(a.Num) or BESENIsNaN(b.Num))) and (a.Num=b.Num); +{$endif} + end; + bvtSTRING:begin + result:=a.Str=b.Str; + end; + bvtBOOLEAN:begin + result:=a.Bool=b.Bool; + end; + bvtOBJECT:begin + result:=a.Obj=b.Obj; + end; + else begin + result:=false; + end; + end; + end; +end; + +procedure InitBESEN; +begin + fillchar(BESENEmptyValue,sizeof(TBESENValue),#0); + fillchar(BESENNullValue,sizeof(TBESENValue),#0); + fillchar(BESENUndefinedValue,sizeof(TBESENValue),#0); + BESENEmptyValue.ValueType:=bvtUNDEFINED; + BESENNullValue.ValueType:=bvtNULL; + BESENUndefinedValue.ValueType:=bvtUNDEFINED; + BESENDummyValue:=BESENEmptyValue; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/3rd/besen/src/BESENValueContainer.pas b/3rd/besen/src/BESENValueContainer.pas new file mode 100644 index 000000000..2212b131a --- /dev/null +++ b/3rd/besen/src/BESENValueContainer.pas @@ -0,0 +1,77 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENValueContainer; +{$i BESEN.inc} + +interface + +uses BESENValue,BESENGarbageCollector; + +type TBESENValueContainer=class(TBESENGarbageCollectorObject) + public + Value:TBESENValue; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENValueContainer.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Value:=BESENEmptyValue; +end; + +destructor TBESENValueContainer.Destroy; +begin + Value.Str:=''; + Value.ReferenceBase.Str:=''; + inherited Destroy; +end; + +procedure TBESENValueContainer.Finalize; +begin + TBESEN(Instance).GarbageCollector.FinalizeValue(Value); + inherited Finalize; +end; + +procedure TBESENValueContainer.Mark; +begin + TBESEN(Instance).GarbageCollector.GrayValue(Value); + inherited Mark; +end; + +end. + \ No newline at end of file diff --git a/3rd/besen/src/BESENVersionConstants.pas b/3rd/besen/src/BESENVersionConstants.pas new file mode 100644 index 000000000..d124514c5 --- /dev/null +++ b/3rd/besen/src/BESENVersionConstants.pas @@ -0,0 +1,42 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENVersionConstants; +{$i BESEN.inc} + +interface + +const BESENVersion='20150630-2027-0000'; + + BESENCodeFormatRevisionNumber:int64=19; + +implementation + +end. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 884f25216..284792303 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -32,9 +32,9 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> + <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -77,9 +77,9 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> + <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -125,9 +125,9 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> + <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -170,9 +170,9 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> + <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -315,9 +315,9 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\Batoto;..\baseunits\includes\AnimeA;..\baseunits\includes\MangaHere;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacan;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFox;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPanda;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaReader;..\baseunits\includes\MangaStream;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\PecintaKomik;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo;..\baseunits\includes\EHentai"/> + <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\baseunits\SimpleException;forms;..\baseunits\modules;..\baseunits\extras"/> + <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 78a31605fca1b86116d332c88d9d437e0b34fa4e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jan 2016 02:30:52 +0800 Subject: [PATCH 0716/2794] baseunit, add gethosturl --- baseunits/uBaseUnit.pas | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ebe3b8eb2..9f471d43d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -836,6 +836,9 @@ function FillURLProtocol(const AProtocol, AURL: String): String; function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; function FillMangaSiteHost(const Website, URL: String): String; overload; function FillHost(const Host, URL: String): String; + +// modify url +function GetHostURL(URL: String): String; function MaybeFillHost(const Host, URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(Const URLs: TStringList); @@ -1432,6 +1435,13 @@ function FillHost(const Host, URL: String): String; end; end; +function GetHostURL(URL: String): String; +begin + Result:=URL; + if URL='' then Exit; + Result:=ReplaceRegExpr(REGEX_HOST,Result,'$1$2',True); +end; + function MaybeFillHost(const Host, URL: String): String; var tu: string; From c42fd0d382bd7dd7d57560a5e5ce57828e062470 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jan 2016 02:31:30 +0800 Subject: [PATCH 0717/2794] added cloudflare scraper unit #116 --- baseunits/modules/Cloudflare.pas | 115 +++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 baseunits/modules/Cloudflare.pas diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas new file mode 100644 index 000000000..08bc17038 --- /dev/null +++ b/baseunits/modules/Cloudflare.pas @@ -0,0 +1,115 @@ +unit Cloudflare; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, uBaseUnit, BESEN, BESENValue, RegExpr; + +function AntiBotActive(const AHTTP:THTTPSendThread):Boolean; +function GETCF(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String):Boolean; + +implementation + +function GetAnsweredURL(const Source,URL:String;var OMethod,OURL:String;var OSleepTime:Integer):Boolean; +var + s, meth, surl, jschl_vc, pass, jschl_answer: String; + query: TXQueryEngineHTML; + js: TBESEN; + v: TBESENValue; +begin + Result:=False; + if (Source='') or (URL='') then Exit; + + meth:=''; + surl:=''; + jschl_vc:=''; + pass:=''; + jschl_answer:=''; + + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(Source); + meth:=UpperCase(query.XPathString('//form[@id="challenge-form"]/@method')); + surl:=query.XPathString('//form[@id="challenge-form"]/@action'); + jschl_vc:=query.XPathString('//input[@name="jschl_vc"]/@value'); + pass:=query.XPathString('//input[@name="pass"]/@value'); + finally + query.Free; + end; + + if (meth='') or (surl='') or (jschl_vc='') or (pass='') then Exit; + + s:=Source; + with TRegExpr.Create do + try + ModifierG:=False; + ModifierI:=True; + Expression:='^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; + Expression:='^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; + s:=Replace(s,'$1',True); + Expression:='\s{3,}[a-z](\s*=\s*document\.|\.).+;\r?\n'; + s:=Replace(s,'',False); + Expression:='t\s=\s*t\.firstChild.href;'; + s:=Replace(s,' t = "'+URL+'";',False); + Expression:='a\.value\s*='; + s:=Replace(s,'a =',False); + Expression:='^.*\.submit\(.*\},\s*(\d{4,})\).*$'; + OSleepTime:=StrToIntDef(Replace(Source,'$1',True),5000); + finally + Free; + end; + + js:=TBESEN.Create; + try + v:=js.Execute(s); + if v.ValueType=bvtNUMBER then + jschl_answer:=FloatToStr(v.Num); + except + jschl_answer:=''; + end; + js.Free; + + if jschl_answer='' then Exit; + OMethod:=meth; + OURL:=surl+'?jschl_vc='+jschl_vc+'&pass='+pass+'&jschl_answer='+jschl_answer; + Result:=True; +end; + +function AntiBotActive(const AHTTP:THTTPSendThread):Boolean; +begin + Result:=False; + if AHTTP=nil then Exit; + Result:=Pos('URL=/cdn-cgi/',AHTTP.Headers.Values['Refresh'])>0; +end; + +function GETCF(const AHTTP:THTTPSendThread;AURL:String;var Cookie:String):Boolean; +var + m, u, h: String; + st: Integer; +begin + Result:=False; + if AHTTP=nil then Exit; + if Cookie<>'' then AHTTP.Cookies.Text:=Cookie; + Result := AHTTP.GET(AURL); + if AntiBotActive(AHTTP) then begin + m:='GET'; + u:=''; + h:=AppendURLDelim(GetHostURL(AURL)); + st:=5000; + if GetAnsweredURL(StreamToString(AHTTP.Document),h,m,u,st) then + if (m<>'') and (u<>'') then begin + AHTTP.Reset; + AHTTP.Headers.Values['Referer']:=' '+AURL; + Sleep(st); + AHTTP.FollowRedirection:=False; + if AHTTP.HTTPRequest(m,FillHost(h,u)) then + Result:=AHTTP.Cookies.Values['cf_clearance']<>''; + AHTTP.FollowRedirection:=True; + if Result then Cookie:=AHTTP.GetCookies; + end; + end; +end; + +end. From d8639ef3f92bd29276c4f8c6d1e478a07d81292a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jan 2016 02:34:34 +0800 Subject: [PATCH 0718/2794] added kissmanga module #116 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/KissManga.pas | 185 ++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/KissManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 860172a70..443393d17 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -18,4 +18,5 @@ uses HentaiCafe, MangaTr, Madokami, - RawSenManga; + RawSenManga, + KissManga; diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas new file mode 100644 index 000000000..a19db477a --- /dev/null +++ b/baseunits/modules/KissManga.pas @@ -0,0 +1,185 @@ +unit KissManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + Cloudflare, RegExpr, synautil; + +implementation + +var + kissmangacookies: String=''; + lockget: TRTLCriticalSection; + onlockget: Boolean=False; + +function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; +begin + AHTTP.Cookies.Text:=kissmangacookies; + Result:=AHTTP.GET(AURL); + if (AHTTP.ResultCode>500) and Cloudflare.AntiBotActive(AHTTP) then begin + if TryEnterCriticalsection(lockget)>0 then begin + onlockget:=True; + Result:=Cloudflare.GETCF(AHTTP,AURL,kissmangacookies); + onlockget:=False; + LeaveCriticalsection(lockget); + end + else begin + while onlockget do Sleep(1000); + AHTTP.Cookies.Text:=kissmangacookies; + end; + Result:=AHTTP.GET(AURL); + end; +end; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+'/MangaList/Newest') then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=query.XPathString('//ul[@class="pager"]/li[last()]/a/@href'); + if s<>'' then begin + s:=ReplaceRegExpr('^.*=(\d+)$',s,'$1',True); + Page:=StrToIntDef(s,1); + end; + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+'/Mangalist/Newest'; + if AURL<>'0' then + s:=s+'?page='+IncStr(AURL); + if GETWithCookie(MangaInfo.FHTTP,s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@class="listing"]/tbody/tr/td[1]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + i: Integer; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GETWithCookie(MangaInfo.FHTTP,FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//div[@id="rightside"]//img/@src'); + if title=''then title:=query.XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); + v:=query.XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); + if v.Count > 0 then begin + i:=0; + while i<v.Count-2 do begin + s:=v.get(i).toString; + if Pos('Genres:',s)=1 then genres:=SeparateRight(s,':') else + if Pos('Author:',s)=1 then authors:=SeparateRight(s,':') else + if Pos('Artist:',s)=1 then artists:=SeparateRight(s,':') else + if Pos('Status:',s)=1 then begin + if Pos('ongoing',LowerCase(v.get(i).toString))>0 then status:='1' + else status:='0'; + end else + if Pos('Summary:',s)=1 then summary:=v.get(i+1).toString; + Inc(i); + end; + end; + for v in query.XPath('//table[@class="listing"]/tbody/tr/td/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + source: TStringList; + i: Integer; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GETWithCookie(DownloadThread.FHTTP,FillHost(Module.RootURL,AURL)) then begin + Result:=True; + source:=TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count>0 then + for i:=0 to source.Count-1 do begin + if Pos('lstImages.push',source[i])>0 then + PageLinks.Add(GetBetween('.push("','");',source[i])); + end; + finally + source.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='KissManga'; + RootURL:='http://kissmanga.com'; + SortedList:=True; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + InitCriticalSection(lockget); + RegisterModule; + +finalization + DoneCriticalsection(lockget); + +end. From eed1606d55cbfa4525f82bb38232e1313f292dd0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jan 2016 02:37:20 +0800 Subject: [PATCH 0719/2794] remove kissmanga close #116 --- .../KissManga/chapter_page_number.inc | 42 ----- .../KissManga/directory_page_number.inc | 36 ---- .../includes/KissManga/manga_information.inc | 137 -------------- .../includes/KissManga/names_and_links.inc | 39 ---- baseunits/uBaseUnit.pas | 168 +++++++++--------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 5 - 7 files changed, 82 insertions(+), 360 deletions(-) delete mode 100644 baseunits/includes/KissManga/chapter_page_number.inc delete mode 100644 baseunits/includes/KissManga/directory_page_number.inc delete mode 100644 baseunits/includes/KissManga/manga_information.inc delete mode 100644 baseunits/includes/KissManga/names_and_links.inc diff --git a/baseunits/includes/KissManga/chapter_page_number.inc b/baseunits/includes/KissManga/chapter_page_number.inc deleted file mode 100644 index f3e740018..000000000 --- a/baseunits/includes/KissManga/chapter_page_number.inc +++ /dev/null @@ -1,42 +0,0 @@ -function GetKissMangaPageNumber: Boolean; -var - s, imageURL: String; - j, i: Integer; - l: TStringList; -begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(KISSMANGA_ID, URL), - manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('lstImages.push("', parse.Strings[i]) > 0 then - begin - s := parse.Strings[i]; - repeat - j := Pos('lstImages.push("', s); - imageURL := DecodeUrl(GetString(s, 'lstImages.push("', '");')); - if (Pos('googleusercontent', imageURL) > 0) and - (Pos('proxy?', imageURL) > 0) then - begin - imageURL := GetString(imageURL + '<~>', '*&url=', '<~>'); - end; - manager.container.PageLinks.Add(EncodeUrl(imageURL)); - Delete(s, Pos('lstImages.push("', s), 16); - j := Pos('lstImages.push("', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; -end; diff --git a/baseunits/includes/KissManga/directory_page_number.inc b/baseunits/includes/KissManga/directory_page_number.inc deleted file mode 100644 index 3effccf70..000000000 --- a/baseunits/includes/KissManga/directory_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetKissMangaDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[KISSMANGA_ID, 1] + - KISSMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('» Last', parse.Strings[i]) > 0) then - begin - Page := StrToInt(StringReplace( - TrimRight(TrimLeft(GetAttributeValue(GetTagAttribute(parse.Strings[i - 1], 'page=')))), - '"', '', [rfReplaceAll])); - Result := NO_ERROR; - Break; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/KissManga/manga_information.inc b/baseunits/includes/KissManga/manga_information.inc deleted file mode 100644 index 53752510d..000000000 --- a/baseunits/includes/KissManga/manga_information.inc +++ /dev/null @@ -1,137 +0,0 @@ - function GetKissMangaInfoFromURL: Byte; - var - i, j: Integer; - s: string; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[KISSMANGA_ID, 0]; - mangaInfo.url := EncodeURL(FillMangaSiteHost(KISSMANGA_ID, URL + '?confirm=yes')); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - ParseHTML(Source.Text, parse); - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - //get manga title - if mangaInfo.title = '' then - if GetTagName(parse[i]) = 'title' then - begin - s := Trim(parse[i+1]); - j := Pos(#13#10, s); - if j <> 0 then - Delete(s, j, Length(s)); - mangaInfo.title := CommonStringFilter(s); - end; - - // get cover link - if GetTagName(parse.Strings[i]) = 'img' then - if (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'width=')) = '190px') then - mangaInfo.coverLink := - EncodeURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src'))); - - // get summary - if (Pos('Summary:', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 4; - mangaInfo.summary := ''; - while (Pos('</p>', parse.Strings[j]) = 0) and (j < parse.Count - 1) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := StringFilter(parse.Strings[j]); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - if (not isExtractChapter) and (Pos('Chapter Name', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (GetTagName(parse.Strings[i]) = 'a') and - (Pos('?id=', parse.Strings[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[KISSMANGA_ID, 1], '', [rfReplaceAll])); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #10, '', [rfReplaceAll]); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #13, '', [rfReplaceAll]); - parse.Strings[i + 1] := TrimLeft(parse.Strings[i + 1]); - parse.Strings[i + 1] := TrimRight(parse.Strings[i + 1]); - mangaInfo.chapterName.Add( - StringFilter(TrimRight(RemoveSymbols(parse.Strings[i + 1])))); - end; - - if (isExtractChapter) and - (Pos('fb-comments', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get authors - if (Pos('Author:', parse.Strings[i]) <> 0) then - mangaInfo.authors := parse.Strings[i + 4]; - - // get artists - if (Pos('Artist:', parse.Strings[i]) <> 0) then - mangaInfo.artists := parse.Strings[i + 4]; - - // get genres - if (Pos('Genres:', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if (i + 1 < parse.Count) and (Pos('"/Genre/', parse.Strings[i]) > 0) then - mangaInfo.genres := mangaInfo.genres + - (TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '); - if Pos('</p>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (Pos('Status:', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/KissManga/names_and_links.inc b/baseunits/includes/KissManga/names_and_links.inc deleted file mode 100644 index 460a605a6..000000000 --- a/baseunits/includes/KissManga/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function KissMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[KISSMANGA_ID, 1] + - KISSMANGA_BROWSER + '?page=' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/Manga/', parse.Strings[i]) > 0) and - (Pos('title=', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringReplace(parse.Strings[i + 3], #10, '', [rfReplaceAll]); - s := Trim(StringReplace(s, #13, '', [rfReplaceAll])); - names.Add(s); - links.Add(StringReplace(GetAttributeValue(GetTagAttribute( - parse.Strings[i + 2], 'href=')), WebsiteRoots[KISSMANGA_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9f471d43d..87ceb8ab3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -268,93 +268,91 @@ interface ANIMEA_ID = 0; MANGAINN_ID = 1; OURMANGA_ID = 2; - KISSMANGA_ID = 3; - MANGA24H_ID = 4; - VNSHARING_ID = 5; - HENTAI2READ_ID = 6; - FAKKU_ID = 7; - TRUYEN18_ID = 8; - MANGAPARK_ID = 9; - MANGATRADERS_ID = 10; - MANGAEDEN_ID = 11; - PERVEDEN_ID = 12; - TRUYENTRANHTUAN_ID = 13; - TURKCRAFT_ID = 14; - MANGAVADISI_ID = 15; - MANGAFRAME_ID = 16; - EATMANGA_ID = 17; - STARKANA_ID = 18; - REDHAWKSCANS_ID = 19; - BLOGTRUYEN_ID = 20; - KOMIKID_ID = 21; - SUBMANGA_ID = 22; - ESMANGAHERE_ID = 23; - ANIMEEXTREMIST_ID = 24; - HUGEMANGA_ID = 25; - S2SCAN_ID = 26; - SENMANGA_ID = 27; - IMANHUA_ID = 28; - MABUNS_ID = 29; - MANGAESTA_ID = 30; - CENTRALDEMANGAS_ID = 31; - EGSCANS_ID = 32; - MANGAAR_ID = 33; - MANGAAE_ID = 34; - ANIMESTORY_ID = 35; - LECTUREENLIGNE_ID = 36; - SCANMANGA_ID = 37; - MANGAGO_ID = 38; - DM5_ID = 39; - PURURIN_ID = 40; - MANGACOW_ID = 41; - KIVMANGA_ID = 42; - MEINMANGA_ID = 43; - MANGASPROJECT_ID = 44; - MANGAREADER_POR_ID = 45; - MANGASTREAMTO_ID = 46; - NINEMANGA_ID = 47; - NINEMANGA_ES_ID = 48; - NINEMANGA_CN_ID = 49; - NINEMANGA_RU_ID = 50; - NINEMANGA_DE_ID = 51; - NINEMANGA_IT_ID = 52; - NINEMANGA_BR_ID = 53; - JAPANSHIN_ID = 54; - JAPSCAN_ID = 55; - CENTRUMMANGI_PL_ID = 56; - MANGALIB_PL_ID = 57; - ONEMANGA_ID = 58; - MANGATOWN_ID = 59; - MANGAOKU_ID = 60; - MYREADINGMANGAINFO_ID = 61; - IKOMIK_ID = 62; - NHENTAI_ID = 63; - UNIONMANGAS_ID = 64; - MANGAMINT_ID = 65; - UNIXMANGA_ID = 66; - HAKIHOME_ID = 67; - EXTREMEMANGAS_ID = 68; - MANGAHOST_ID = 69; - PORNCOMIX_ID = 70; - PORNCOMIXRE_ID = 71; - PORNCOMIXIC_ID = 72; - XXCOMICS_ID = 73; - XXCOMICSMT_ID = 74; - XXCOMICS3D_ID = 75; - PORNXXXCOMICS_ID = 76; - MANGASEE_ID = 77; - MANGAKU_ID = 78; - ACADEMYVN_ID = 79; - MANGAAT_ID = 80; - READMANGATODAY_ID = 81; - LONEMANGA_ID = 82; - DYNASTYSCANS_ID = 83; - - WebsiteRoots: array [0..83] of array [0..1] of string = ( + MANGA24H_ID = 3; + VNSHARING_ID = 4; + HENTAI2READ_ID = 5; + FAKKU_ID = 6; + TRUYEN18_ID = 7; + MANGAPARK_ID = 8; + MANGATRADERS_ID = 9; + MANGAEDEN_ID = 10; + PERVEDEN_ID = 11; + TRUYENTRANHTUAN_ID = 12; + TURKCRAFT_ID = 13; + MANGAVADISI_ID = 14; + MANGAFRAME_ID = 15; + EATMANGA_ID = 16; + STARKANA_ID = 17; + REDHAWKSCANS_ID = 18; + BLOGTRUYEN_ID = 19; + KOMIKID_ID = 20; + SUBMANGA_ID = 21; + ESMANGAHERE_ID = 22; + ANIMEEXTREMIST_ID = 23; + HUGEMANGA_ID = 24; + S2SCAN_ID = 25; + SENMANGA_ID = 26; + IMANHUA_ID = 27; + MABUNS_ID = 28; + MANGAESTA_ID = 29; + CENTRALDEMANGAS_ID = 30; + EGSCANS_ID = 31; + MANGAAR_ID = 32; + MANGAAE_ID = 33; + ANIMESTORY_ID = 34; + LECTUREENLIGNE_ID = 35; + SCANMANGA_ID = 36; + MANGAGO_ID = 37; + DM5_ID = 38; + PURURIN_ID = 39; + MANGACOW_ID = 40; + KIVMANGA_ID = 41; + MEINMANGA_ID = 42; + MANGASPROJECT_ID = 43; + MANGAREADER_POR_ID = 44; + MANGASTREAMTO_ID = 45; + NINEMANGA_ID = 46; + NINEMANGA_ES_ID = 47; + NINEMANGA_CN_ID = 48; + NINEMANGA_RU_ID = 49; + NINEMANGA_DE_ID = 50; + NINEMANGA_IT_ID = 51; + NINEMANGA_BR_ID = 52; + JAPANSHIN_ID = 53; + JAPSCAN_ID = 54; + CENTRUMMANGI_PL_ID = 55; + MANGALIB_PL_ID = 56; + ONEMANGA_ID = 57; + MANGATOWN_ID = 58; + MANGAOKU_ID = 59; + MYREADINGMANGAINFO_ID = 60; + IKOMIK_ID = 61; + NHENTAI_ID = 62; + UNIONMANGAS_ID = 63; + MANGAMINT_ID = 64; + UNIXMANGA_ID = 65; + HAKIHOME_ID = 66; + EXTREMEMANGAS_ID = 67; + MANGAHOST_ID = 68; + PORNCOMIX_ID = 69; + PORNCOMIXRE_ID = 70; + PORNCOMIXIC_ID = 71; + XXCOMICS_ID = 72; + XXCOMICSMT_ID = 73; + XXCOMICS3D_ID = 74; + PORNXXXCOMICS_ID = 75; + MANGASEE_ID = 76; + MANGAKU_ID = 77; + ACADEMYVN_ID = 78; + MANGAAT_ID = 79; + READMANGATODAY_ID = 80; + LONEMANGA_ID = 81; + DYNASTYSCANS_ID = 82; + + WebsiteRoots: array [0..82] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), - ('KissManga', 'http://kissmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Hentai2Read', 'http://hentai2read.com'), @@ -446,8 +444,6 @@ interface OURMANGA_BROWSER = '/directory/'; - KISSMANGA_BROWSER = '/MangaList'; - MANGA24H_BROWSER = '/manga/update/page/'; VNSHARING_BROWSER = '/DanhSach'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 11ffe723f..f879fbeba 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1956,8 +1956,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/AnimeA/directory_page_number.inc} - {$I includes/KissManga/directory_page_number.inc} - {$I includes/Manga24h/directory_page_number.inc} {$I includes/VnSharing/directory_page_number.inc} @@ -2058,9 +2056,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = ANIMEA_ID then Result := GetAnimeADirectoryPageNumber else - if WebsiteID = KISSMANGA_ID then - Result := GetKissMangaDirectoryPageNumber - else if WebsiteID = MANGA24H_ID then Result := GetManga24hDirectoryPageNumber else @@ -2211,8 +2206,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaInn/names_and_links.inc} - {$I includes/KissManga/names_and_links.inc} - {$I includes/Manga24h/names_and_links.inc} {$I includes/VnSharing/names_and_links.inc} @@ -2357,9 +2350,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGAINN_ID then Result := MangaInnGetNamesAndLinks else - if WebsiteID = KISSMANGA_ID then - Result := KissMangaGetNamesAndLinks - else if WebsiteID = MANGA24H_ID then Result := Manga24hGetNamesAndLinks else @@ -2604,8 +2594,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaInn/manga_information.inc} - {$I includes/KissManga/manga_information.inc} - {$I includes/Manga24h/manga_information.inc} {$I includes/VnSharing/manga_information.inc} @@ -2761,9 +2749,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGAINN_ID then Result := GetMangaInnInfoFromURL else - if WebsiteID = KISSMANGA_ID then - Result := GetKissMangaInfoFromURL - else if WebsiteID = MANGA24H_ID then Result := GetManga24hInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 939bfb62e..043ccac7d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -383,8 +383,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/HugeManga/chapter_page_number.inc} - {$I includes/KissManga/chapter_page_number.inc} - {$I includes/Kivmanga/chapter_page_number.inc} {$I includes/Komikid/chapter_page_number.inc} @@ -562,9 +560,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; (manager.container.MangaSiteID = PERVEDEN_ID) then Result := GetMangaEdenPageNumber else - if manager.container.MangaSiteID = KISSMANGA_ID then - Result := GetKissMangaPageNumber - else if manager.container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else From 40e47cae1ee4de2554453f6871a5f033d9219248 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 5 Jan 2016 18:04:43 +0800 Subject: [PATCH 0720/2794] baseunit, follow deprecated tjsonparser.create --- baseunits/uBaseUnit.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 87ceb8ab3..4ade98631 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -19,10 +19,10 @@ interface UTF8Process, {$endif} SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, - LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, FastHTMLParser, - fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, - uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, - Imaging, ImagingExtras, USimpleException, USimpleLogger; + LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, + FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, + synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, + xquery, xquery_json, Imaging, ImagingExtras, USimpleException, USimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); @@ -1534,7 +1534,7 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); i: Integer; begin OutArray.BeginUpdate; - P := TJSONParser.Create(Trim(S)); + P := TJSONParser.Create(Trim(S), jsonscanner.DefaultOptions); try D := P.Parse; try From 7e871415f313acd45a8d21c66abf877ca6576707 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 5 Jan 2016 18:13:02 +0800 Subject: [PATCH 0721/2794] rename simpleexception files --- ...impleException.pas => SimpleException.pas} | 48 +++++++++---------- ...eptionForm.lfm => SimpleExceptionForm.lfm} | 0 ...eptionForm.pas => SimpleExceptionForm.pas} | 4 +- .../{USimpleLogger.pas => SimpleLogger.pas} | 2 +- baseunits/accountmanagerdb.pas | 2 +- baseunits/httpsendthread.pas | 2 +- baseunits/uBaseUnit.pas | 2 +- baseunits/uData.pas | 2 +- baseunits/uDownloadsManager.pas | 2 +- baseunits/uFMDThread.pas | 2 +- baseunits/uFavoritesManager.pas | 2 +- baseunits/uImg2Pdf.pas | 6 +-- baseunits/uPacker.pas | 6 +-- baseunits/uUpdateThread.pas | 2 +- mangadownloader/forms/frmAccountManager.pas | 2 +- mangadownloader/forms/frmMain.pas | 4 +- updater/languages/updater.en.po | 5 +- updater/languages/updater.id_ID.po | 13 +++-- updater/languages/updater.po | 4 -- updater/uMain.lfm | 3 +- updater/uMain.pas | 4 +- 21 files changed, 58 insertions(+), 59 deletions(-) rename baseunits/SimpleException/{USimpleException.pas => SimpleException.pas} (92%) rename baseunits/SimpleException/{USimpleExceptionForm.lfm => SimpleExceptionForm.lfm} (100%) rename baseunits/SimpleException/{USimpleExceptionForm.pas => SimpleExceptionForm.pas} (98%) rename baseunits/SimpleException/{USimpleLogger.pas => SimpleLogger.pas} (99%) diff --git a/baseunits/SimpleException/USimpleException.pas b/baseunits/SimpleException/SimpleException.pas similarity index 92% rename from baseunits/SimpleException/USimpleException.pas rename to baseunits/SimpleException/SimpleException.pas index 2b00df468..10d10b401 100644 --- a/baseunits/SimpleException/USimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -18,7 +18,7 @@ MA 02111-1307, USA. } -unit USimpleException; +unit SimpleException; {$mode objfpc}{$H+} @@ -26,7 +26,7 @@ interface uses Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, LCLVersion, - USimpleExceptionForm, USimpleLogger, + SimpleExceptionForm, SimpleLogger, {$IFDEF WINDOWS} windows, win32proc, {$ENDIF} @@ -95,7 +95,7 @@ procedure InitSimpleExceptionHandler(const LogFilename: String = ''); procedure DoneSimpleExceptionHandler; var - SimpleException: TSimpleException; + MyException: TSimpleException; resourcestring SExceptionDialogTitle = 'Exception Info'; @@ -110,63 +110,63 @@ implementation procedure SetMaxStackCount(const ACount : Integer); begin - if SimpleException <> nil then - SimpleException.MaxStackCount := ACount; + if MyException <> nil then + MyException.MaxStackCount := ACount; end; function AddIgnoredException(const EClassName : String) : Boolean; begin Result := False; - if SimpleException <> nil then - if SimpleException.IgnoredExceptionList.IndexOf(EClassName) < 0 then + if MyException <> nil then + if MyException.IgnoredExceptionList.IndexOf(EClassName) < 0 then begin Result := True; - SimpleException.IgnoredExceptionList.Add(EClassName); + MyException.IgnoredExceptionList.Add(EClassName); end; end; function RemoveIgnoredClass(const EClassName : String) : Boolean; begin Result := False; - if SimpleException <> nil then - if SimpleException.IgnoredExceptionList.IndexOf(EClassName) > -1 then + if MyException <> nil then + if MyException.IgnoredExceptionList.IndexOf(EClassName) > -1 then begin Result := True; - SimpleException.IgnoredExceptionList.Delete( - SimpleException.IgnoredExceptionList.IndexOf(EClassName)); + MyException.IgnoredExceptionList.Delete( + MyException.IgnoredExceptionList.IndexOf(EClassName)); end; end; procedure ClearIgnoredException; begin - if SimpleException <> nil then - SimpleException.IgnoredExceptionList.Clear; + if MyException <> nil then + MyException.IgnoredExceptionList.Clear; end; procedure ExceptionHandle(Sender: TObject; E: Exception); begin - if not Assigned(SimpleException) then + if not Assigned(MyException) then InitSimpleExceptionHandler; - SimpleException.SimpleExceptionHandler(Sender, E); + MyException.SimpleExceptionHandler(Sender, E); end; procedure ExceptionHandleSaveLogOnly(Sender: TObject; E: Exception); begin - if not Assigned(SimpleException) then + if not Assigned(MyException) then InitSimpleExceptionHandler; - SimpleException.SimpleExceptionHandlerSaveLogOnly(Sender, E); + MyException.SimpleExceptionHandlerSaveLogOnly(Sender, E); end; procedure InitSimpleExceptionHandler(const LogFilename : String); begin - if SimpleException = nil then - SimpleException := TSimpleException.Create(LogFilename); + if MyException = nil then + MyException := TSimpleException.Create(LogFilename); end; procedure DoneSimpleExceptionHandler; begin - if SimpleException <> nil then - FreeAndNil(SimpleException); + if MyException <> nil then + FreeAndNil(MyException); end; { TSimpleException } @@ -407,8 +407,8 @@ procedure TSimpleException.SimpleExceptionHandlerSaveLogOnly(Sender: TObject; Procedure CatchUnhandledExcept(Obj : TObject; Addr: CodePointer; FrameCount: Longint; Frames: PCodePointer); begin - if Assigned(SimpleException) then - SimpleException.UnhandledException(Obj, Addr, FrameCount, Frames); + if Assigned(MyException) then + MyException.UnhandledException(Obj, Addr, FrameCount, Frames); end; constructor TSimpleException.Create(Filename : string); diff --git a/baseunits/SimpleException/USimpleExceptionForm.lfm b/baseunits/SimpleException/SimpleExceptionForm.lfm similarity index 100% rename from baseunits/SimpleException/USimpleExceptionForm.lfm rename to baseunits/SimpleException/SimpleExceptionForm.lfm diff --git a/baseunits/SimpleException/USimpleExceptionForm.pas b/baseunits/SimpleException/SimpleExceptionForm.pas similarity index 98% rename from baseunits/SimpleException/USimpleExceptionForm.pas rename to baseunits/SimpleException/SimpleExceptionForm.pas index 93074b747..8f24825b9 100644 --- a/baseunits/SimpleException/USimpleExceptionForm.pas +++ b/baseunits/SimpleException/SimpleExceptionForm.pas @@ -18,7 +18,7 @@ MA 02111-1307, USA. } -unit USimpleExceptionForm; +unit SimpleExceptionForm; {$mode objfpc}{$H+} @@ -64,7 +64,7 @@ TSimpleExceptionForm = class(TForm) implementation -uses USimpleException; +uses SimpleException; {$R *.lfm} diff --git a/baseunits/SimpleException/USimpleLogger.pas b/baseunits/SimpleException/SimpleLogger.pas similarity index 99% rename from baseunits/SimpleException/USimpleLogger.pas rename to baseunits/SimpleException/SimpleLogger.pas index c363545c7..920d670ec 100644 --- a/baseunits/SimpleException/USimpleLogger.pas +++ b/baseunits/SimpleException/SimpleLogger.pas @@ -18,7 +18,7 @@ MA 02111-1307, USA. } -unit USimpleLogger; +unit SimpleLogger; {$mode objfpc}{$H+} diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index b9b0bd4e3..cc6325a0a 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, LazFileUtils, USimpleLogger, base64, sqlite3conn, + Classes, SysUtils, LazFileUtils, SimpleLogger, base64, sqlite3conn, sqldb, db; type diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index b9035e98c..129ce0bf8 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - uFMDThread, GZIPUtils, Graphics, USimpleLogger, RegExpr; + uFMDThread, GZIPUtils, Graphics, SimpleLogger, RegExpr; type diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4ade98631..d48a2b81b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -22,7 +22,7 @@ interface LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, - xquery, xquery_json, Imaging, ImagingExtras, USimpleException, USimpleLogger; + xquery, xquery_json, Imaging, ImagingExtras, SimpleException, SimpleLogger; Type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index f879fbeba..c51a2ba59 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, - sqlite3backup, sqlite3dyn, sqldb, DB, USimpleLogger, strutils, dateutils, + sqlite3backup, sqlite3dyn, sqldb, DB, SimpleLogger, strutils, dateutils, RegExpr, httpsend; type diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 043ccac7d..0fe0b5b90 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface lazutf8classes, LazFileUtils, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, - uFMDThread, uMisc, USimpleLogger, dateutils; + uFMDThread, uMisc, SimpleLogger, dateutils; type TDownloadManager = class; diff --git a/baseunits/uFMDThread.pas b/baseunits/uFMDThread.pas index 657f4bb0b..0719fc019 100644 --- a/baseunits/uFMDThread.pas +++ b/baseunits/uFMDThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, USimpleLogger; + Classes, SysUtils, SimpleLogger; type diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 885546486..ae5811d5f 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -13,7 +13,7 @@ interface uses Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, - USimpleException; + SimpleException; type TFavoriteManager = class; diff --git a/baseunits/uImg2Pdf.pas b/baseunits/uImg2Pdf.pas index 87f737955..419ec7184 100644 --- a/baseunits/uImg2Pdf.pas +++ b/baseunits/uImg2Pdf.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, ZStream, FPImage, FPReadJPEG, FPWriteJPEG, - ImagingTypes, Imaging, lazutf8classes, USimpleLogger, USimpleException; + ImagingTypes, Imaging, lazutf8classes, SimpleLogger, SimpleException; const TPDFFormatSetings: TFormatSettings = ( @@ -341,7 +341,7 @@ procedure TImg2Pdf.AddFlateImage(const AName: String); except on E :Exception do begin WriteLog_E('TImg2Pdf.AddFlateImage.Error, '+E.Message); - USimpleException.ExceptionHandleSaveLogOnly(Self, E); + SimpleException.ExceptionHandleSaveLogOnly(Self, E); end; end; fs.Free; @@ -383,7 +383,7 @@ procedure TImg2Pdf.AddDCTImage(const AName: String); except on E :Exception do begin WriteLog_E('TImg2Pdf.AddCDTImage.Error, '+E.Message); - USimpleException.ExceptionHandleSaveLogOnly(Self, E); + SimpleException.ExceptionHandleSaveLogOnly(Self, E); end; end; EndPDFPage; diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 9ae16a6ac..d5774b684 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -12,7 +12,7 @@ interface uses Classes, Zipper, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, - USimpleException, USimpleLogger; + SimpleException, SimpleLogger; type TPacker = class @@ -96,7 +96,7 @@ procedure TPacker.DoZipCbz; on E: Exception do begin E.Message := 'DoZipCbz.Exception'#13#10 + E.Message; - USimpleException.ExceptionHandleSaveLogOnly(Self, E); + SimpleException.ExceptionHandleSaveLogOnly(Self, E); end; end; end; @@ -154,7 +154,7 @@ procedure TPacker.DoPdf; on E: Exception do begin E.Message := 'DoPdf.Exception'#13#10 + E.Message; - USimpleException.ExceptionHandleSaveLogOnly(Self, E); + SimpleException.ExceptionHandleSaveLogOnly(Self, E); end; end; end; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 7cf015c07..43bcc39a0 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -91,7 +91,7 @@ TUpdateMangaManagerThread = class(TFMDThread) implementation uses - frmMain, Dialogs, ComCtrls, Forms, Controls, USimpleLogger; + frmMain, Dialogs, ComCtrls, Forms, Controls, SimpleLogger; { TUpdateMangaThread } diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 202a3eeb9..37813763f 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons, ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, uFMDThread, - uBaseUnit, frmAccountSet, USimpleLogger, USimpleException; + uBaseUnit, frmAccountSet, SimpleLogger, SimpleException; type diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 651bf1de5..082b7eb43 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, frmAccountManager, CheckUpdate, accountmanagerdb, - mangafoxwatermarkremover, USimpleException, USimpleLogger; + mangafoxwatermarkremover, SimpleException, SimpleLogger; type @@ -5064,7 +5064,7 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); procedure TMainForm.ExceptionHandler(Sender: TObject; E: Exception); begin - USimpleException.ExceptionHandle(Sender, E); + SimpleException.ExceptionHandle(Sender, E); end; procedure TMainForm.tmBackupTimer(Sender: TObject); diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index 59fe6a004..5d7b80386 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -11,10 +11,6 @@ msgstr "" "Language: en\n" "X-Generator: Poedit 1.7.6\n" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Updater" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "File size" @@ -56,6 +52,7 @@ msgid "File not found!" msgstr "File not found!" #: umain.rs_filenotfound_mfdatalink +#, fuzzy #| msgid "" #| "File not found!\n" #| "This site probably have been added to unofficial build.\n" diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 09436326b..5f9253ea8 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -11,10 +11,6 @@ msgstr "" "Language: id_ID\n" "X-Generator: Poedit 1.8.2\n" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Pembaruan" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Ukuran" @@ -56,6 +52,15 @@ msgid "File not found!" msgstr "Berkas tidak ditemukan!" #: umain.rs_filenotfound_mfdatalink +#, fuzzy +#| msgid "" +#| "File not found!\n" +#| "This site probably have been added to unofficial build.\n" +#| "\n" +#| "Remedy:\n" +#| "Build you manga list from scratch or download manually from this link:\n" +#| "%s\n" +#| "Link copied to clipboard!\n" msgid "" "File not found!\n" "This site probably have been added to unofficial build.\n" diff --git a/updater/languages/updater.po b/updater/languages/updater.po index 8f14f02c9..a6e4f13e2 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -1,10 +1,6 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "" diff --git a/updater/uMain.lfm b/updater/uMain.lfm index aadd78367..2f5f24a4f 100644 --- a/updater/uMain.lfm +++ b/updater/uMain.lfm @@ -13,7 +13,8 @@ object frmMain: TfrmMain OnDestroy = FormDestroy OnShow = FormShow Position = poOwnerFormCenter - LCLVersion = '1.5' + LCLVersion = '1.7' + Visible = False object pbDownload: TProgressBar Left = 8 Height = 20 diff --git a/updater/uMain.pas b/updater/uMain.pas index 9e30afeec..e44ab183d 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -11,7 +11,7 @@ interface {$endif} Classes, SysUtils, zipper, FileUtil,LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, - RegExpr, IniFiles, USimpleException, uMisc, uTranslation, + RegExpr, IniFiles, SimpleException, uMisc, uTranslation, httpsend, blcksock, ssl_openssl, ssl_openssl_lib, uFMDThread; type @@ -729,7 +729,7 @@ procedure TfrmMain.itMonitorTimer(Sender: TObject); procedure TfrmMain.ExceptionHandler(Sender : TObject; E : Exception); begin - USimpleException.ExceptionHandle(Sender, E); + SimpleException.ExceptionHandle(Sender, E); end; end. From a47a416873f42c3769b200b139ae8bd867ae3152 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 19:44:56 +0800 Subject: [PATCH 0722/2794] account list, fix default font. --- mangadownloader/forms/frmAccountManager.lfm | 17 ++++++++--------- mangadownloader/forms/frmAccountManager.pas | 4 ++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 0528c3caa..dedc56643 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -14,13 +14,12 @@ object AccountManagerForm: TAccountManagerForm OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow - LCLVersion = '1.7' Visible = False object pnBtContainer: TPanel - Left = 295 + Left = 297 Height = 304 Top = 6 - Width = 91 + Width = 89 Align = alRight AutoSize = True BevelOuter = bvNone @@ -28,13 +27,13 @@ object AccountManagerForm: TAccountManagerForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 304 - ClientWidth = 91 + ClientWidth = 89 TabOrder = 1 object btDelete: TBitBtn Left = 6 Height = 26 Top = 64 - Width = 85 + Width = 83 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -83,7 +82,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 26 Top = 32 - Width = 85 + Width = 83 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -132,7 +131,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 26 Top = 0 - Width = 85 + Width = 83 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -181,7 +180,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 26 Top = 96 - Width = 85 + Width = 83 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -231,7 +230,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 304 Top = 6 - Width = 289 + Width = 291 Align = alClient Header.AutoSizeIndex = 0 Header.Columns = < diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 37813763f..bd536a684 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -215,8 +215,8 @@ procedure TAccountManagerForm.vtAccountListPaintText(Sender: TBaseVirtualTree; TextType: TVSTTextType); begin if node = nil then Exit; - if Node^.CheckState = csUncheckedNormal then TargetCanvas.Font.Color := clGrayText - else TargetCanvas.Font.Color := clDefault; + if Node^.CheckState = csUncheckedNormal then + TargetCanvas.Font.Color := clGrayText; end; procedure TAccountManagerForm.RefreshList; From ad783d80c666dfd05284259476f711bf02d782d4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 21:16:15 +0800 Subject: [PATCH 0723/2794] batoto, lower maxconnectionlimit #156 --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 22b27c28d..4dd502462 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -349,7 +349,7 @@ procedure RegisterModule; Website := modulename; RootURL := urlroot; MaxTaskLimit := 1; - MaxConnectionLimit := 3; + MaxConnectionLimit := 2; AccountSupport := True; SortedList := True; InformationAvailable := True; From 945227390771ea8dbae2fafe4c827b0184ff3356 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 21:24:28 +0800 Subject: [PATCH 0724/2794] rawsenmanga , fix strip url --- baseunits/modules/RawSenManga.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 4825cd661..bdb340abf 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -49,11 +49,11 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; cl:=''; with TRegExpr.Create do try - Expression:='/\d+(/\d+)?$'; + Expression:='(.+)/.+/\d+?$'; cu:=Exec(s); if cu then begin cl:=s; - s:=Replace(s,'',False); + s:=Replace(s,'$1',True); end; finally Free; @@ -110,7 +110,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; s:=RemoveURLDelim(ChapterLinks[CurrentDownloadChapterPtr]); with TRegExpr.Create do try - Expression:='/\d+/\d+$'; + Expression:='(.+)/.+/\d+?$'; if Exec(s) then begin Expression:='/\d+$'; s:=Replace(s,'',False); From a19bbadf6a280fae67e2573af551d0bb32ff94ae Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 21:44:48 +0800 Subject: [PATCH 0725/2794] rawse nmanga, populate chapter list through single chapter link #146 --- baseunits/modules/RawSenManga.pas | 35 +++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index bdb340abf..f32eb9139 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -39,28 +39,30 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; query: TXQueryEngineHTML; v: IXQValue; i: Integer; - s: String; + s,cl,m: String; cu: Boolean; - cl: String; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=RemoveURLDelim(AURL); + m:=FillHost(Module.RootURL,AURL); + m:=RemoveURLDelim(m); cl:=''; with TRegExpr.Create do try Expression:='(.+)/.+/\d+?$'; - cu:=Exec(s); + cu:=Exec(m); if cu then begin - cl:=s; - s:=Replace(s,'$1',True); + cl:=m; + m:=Replace(m,'$1',True); end; finally Free; end; + m:=AppendURLDelim(m); with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - url:=AppendURLDelim(FillHost(Module.RootURL,s)); - if GET(url) then begin + if cl<>'' then url:=cl + else url:=m; + if GET(m) then begin Result:=NO_ERROR; query:=TXQueryEngineHTML.Create; try @@ -82,14 +84,21 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; summary:=query.XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); if cu and (cl<>'') then - if GET(FillHost(Module.RootURL,cl)) then + if GET(cl) then begin query.ParseHTML(StreamToString(Document)); - s:=query.XPathString('//select[@name="chapter"]/option[@selected="selected"]'); - if s<>'' then begin - chapterLinks.Add(cl); - chapterName.Add(s); + //selected chapter + //s:=query.XPathString('//select[@name="chapter"]/option[@selected="selected"]'); + //if s<>'' then begin + // chapterLinks.Add(cl); + // chapterName.Add(s); + //end; + //all chapter + for v in query.XPath('//select[@name="chapter"]/option') do begin + chapterLinks.Add(m+v.toNode.getAttribute('value')); + chapterName.Add(v.toString); end; + InvertStrings([chapterLinks,chapterName]); end; finally query.Free; From c6f44632a4591576c1f0055763c412fe0ee68f33 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 21:55:54 +0800 Subject: [PATCH 0726/2794] rawse nmanga, fix stripping url info #146 --- baseunits/modules/RawSenManga.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index f32eb9139..c42af8758 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -44,7 +44,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); - m:=FillHost(Module.RootURL,AURL); + m:=RemoveHostFromURL(AURL); m:=RemoveURLDelim(m); cl:=''; with TRegExpr.Create do @@ -60,9 +60,9 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; m:=AppendURLDelim(m); with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if cl<>'' then url:=cl - else url:=m; - if GET(m) then begin + if cl<>'' then url:=FillHost(Module.RootURL,cl) + else url:=FillHost(Module.RootURL,m); + if GET(FillHost(Module.RootURL,m)) then begin Result:=NO_ERROR; query:=TXQueryEngineHTML.Create; try @@ -84,7 +84,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; summary:=query.XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); if cu and (cl<>'') then - if GET(cl) then + if GET(FillHost(Module.RootURL,cl)) then begin query.ParseHTML(StreamToString(Document)); //selected chapter From 912996cf2928d4d8e639093966733ca9577aee62 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 23:29:36 +0800 Subject: [PATCH 0727/2794] encode critical characters in all url before request --- baseunits/httpsendthread.pas | 2 +- baseunits/uBaseUnit.pas | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 129ce0bf8..ef48534f3 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -90,7 +90,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; mstream: TMemoryStream; begin Result := False; - rurl := URL; + rurl := EncodeURL(URL); if Pos('HTTP/', Headers.Text) = 1 then Reset; HTTPHeader:= TStringList.Create; HTTPHeader.Assign(Headers); diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d48a2b81b..7e823e8cb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2973,6 +2973,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; if Trim(URL) = '' then Exit; URL := FixURL(URL); + URL := EncodeURL(URL); HTTPHeader := TStringList.Create; HTTPHeader.NameValueSeparator := ':'; @@ -3286,6 +3287,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; Exit(True); URL := FixURL(URL); + URL := EncodeURL(URL); HTTPHeader := TStringList.Create; HTTPHeader.NameValueSeparator := ':'; From e774308ba1845ed709df78937e4d5addebc8dfdf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 23:33:44 +0800 Subject: [PATCH 0728/2794] remove unionmanga #152 --- .../UnionMangas/chapter_page_number.inc | 33 ------- .../UnionMangas/directory_page_number.inc | 37 -------- .../UnionMangas/manga_information.inc | 86 ------------------- .../includes/UnionMangas/names_and_links.inc | 39 --------- baseunits/uBaseUnit.pas | 44 +++++----- baseunits/uData.pas | 15 ---- baseunits/uDownloadsManager.pas | 5 -- 7 files changed, 21 insertions(+), 238 deletions(-) delete mode 100644 baseunits/includes/UnionMangas/chapter_page_number.inc delete mode 100644 baseunits/includes/UnionMangas/directory_page_number.inc delete mode 100644 baseunits/includes/UnionMangas/manga_information.inc delete mode 100644 baseunits/includes/UnionMangas/names_and_links.inc diff --git a/baseunits/includes/UnionMangas/chapter_page_number.inc b/baseunits/includes/UnionMangas/chapter_page_number.inc deleted file mode 100644 index 28ee69d2a..000000000 --- a/baseunits/includes/UnionMangas/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetUnionMangasPageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - manager.container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(UNIONMANGAS_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - CleanHTMLComments(l); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', parse[i]) > 0) and (Pos('class="real', parse[i]) > 0) and - (Pos('data-lazy', parse[i]) > 0) then - manager.container.PageLinks.Add(GetVal(parse[i], 'data-lazy')); - end; - manager.container.PageNumber := manager.container.PageLinks.Count; - end; - parse.Free; - end; diff --git a/baseunits/includes/UnionMangas/directory_page_number.inc b/baseunits/includes/UnionMangas/directory_page_number.inc deleted file mode 100644 index 176e1176e..000000000 --- a/baseunits/includes/UnionMangas/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetUnionMangasDirectoryPageNumber: Byte; - var - i, p: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[UNIONMANGAS_ID, 1] + - UNIONMANGAS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - CleanHTMLComments(Source); - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - Page := 1; - for i := parse.Count - 1 downto 2 do - begin //http://unionmangas.com.br/mangas/a-z/2/* - if (Pos('<a', parse[i]) > 0) and (Pos('/mangas/a-z/', parse[i]) > 0) then - begin - p := StrToIntDef(ReplaceRegExpr('^.*/a-z/(\d+)/.*$', GetVal(parse[i], 'href'), '$1', True), 0); - if Page < p then - Page := p; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/UnionMangas/manga_information.inc b/baseunits/includes/UnionMangas/manga_information.inc deleted file mode 100644 index 3600f145b..000000000 --- a/baseunits/includes/UnionMangas/manga_information.inc +++ /dev/null @@ -1,86 +0,0 @@ - function GetUnionMangasInfoFromURL: Byte; - var - i: Integer; - begin - mangaInfo.website := WebsiteRoots[UNIONMANGAS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(UNIONMANGAS_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Source.Free; - Exit; - end; - - CleanHTMLComments(Source); - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //title - if (i + 1 < parse.Count - 1) then - if (Pos(' - Union Mang', parse[i]) > 0) then - mangaInfo.title := CommonStringFilter(ReplaceRegExpr('\s-\sUnion\sMang.*$', parse[i], '', False)); - - //cover - if (Pos('<img', parse[i]) > 0) and (Pos('class="img-thumbnail', parse[i]) > 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //authors - if (i + 2 < parse.Count - 1) then - if (Pos('Autor:', parse[i]) > 0) and (Pos('</label', parse[i + 1]) > 0) then - mangaInfo.authors := CommonStringFilter(parse[i + 2]); - - //artists - if (i + 2 < parse.Count - 1) then - if (Pos('Artista:', parse[i]) > 0) and (Pos('</label', parse[i + 1]) > 0) then - mangaInfo.artists := CommonStringFilter(parse[i + 2]); - - //category/genre - if (i + 2 < parse.Count - 1) then - if (Pos('Gênero(s):', parse[i]) > 0) and (Pos('</label', parse[i + 1]) > 0) then - mangaInfo.genres := CommonStringFilter(parse[i + 2]); - - //status - if (i + 1 < parse.Count - 1) then - if (Pos('class="label label-info"', parse[i]) > 0) then - if Trim(LowerCase(parse[i + 1])) = 'completo' then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - - //sinopsis - if (i + 1 < parse.Count - 1) then - if (Pos('class="panel-body"', parse[i]) > 0)then - mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 1])); - - //chapters - if (i + 7 < parse.Count - 1) then - if Pos('class="row lancamento-linha', parse[i]) > 0 then - begin - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i + 6], 'href'), - WebsiteRoots[UNIONMANGAS_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 7])); - end; - end; - - if mangaInfo.chapterName.Count > 1 then - begin - // invert chapter - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/UnionMangas/names_and_links.inc b/baseunits/includes/UnionMangas/names_and_links.inc deleted file mode 100644 index 9cfb549d2..000000000 --- a/baseunits/includes/UnionMangas/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function UnionMangasNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), - WebsiteRoots[UNIONMANGAS_ID, 1] + UNIONMANGAS_BROWSER + '/a-z/' + - IntToStr(StrToInt(URL) + 1) + '/*', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - CleanHTMLComments(Source); - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) > 0) and (Pos('class="capa_', parse[i]) > 0) and - (i + 6 < parse.Count - 1) then - begin - names.Add(CommonStringFilter(parse[i + 6])); - links.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[UNIONMANGAS_ID, 1], '', [rfIgnoreCase])); - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7e823e8cb..d6c286ffb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -328,28 +328,27 @@ interface MYREADINGMANGAINFO_ID = 60; IKOMIK_ID = 61; NHENTAI_ID = 62; - UNIONMANGAS_ID = 63; - MANGAMINT_ID = 64; - UNIXMANGA_ID = 65; - HAKIHOME_ID = 66; - EXTREMEMANGAS_ID = 67; - MANGAHOST_ID = 68; - PORNCOMIX_ID = 69; - PORNCOMIXRE_ID = 70; - PORNCOMIXIC_ID = 71; - XXCOMICS_ID = 72; - XXCOMICSMT_ID = 73; - XXCOMICS3D_ID = 74; - PORNXXXCOMICS_ID = 75; - MANGASEE_ID = 76; - MANGAKU_ID = 77; - ACADEMYVN_ID = 78; - MANGAAT_ID = 79; - READMANGATODAY_ID = 80; - LONEMANGA_ID = 81; - DYNASTYSCANS_ID = 82; - - WebsiteRoots: array [0..82] of array [0..1] of string = ( + MANGAMINT_ID = 63; + UNIXMANGA_ID = 64; + HAKIHOME_ID = 65; + EXTREMEMANGAS_ID = 66; + MANGAHOST_ID = 67; + PORNCOMIX_ID = 68; + PORNCOMIXRE_ID = 69; + PORNCOMIXIC_ID = 70; + XXCOMICS_ID = 71; + XXCOMICSMT_ID = 72; + XXCOMICS3D_ID = 73; + PORNXXXCOMICS_ID = 74; + MANGASEE_ID = 75; + MANGAKU_ID = 76; + ACADEMYVN_ID = 77; + MANGAAT_ID = 78; + READMANGATODAY_ID = 79; + LONEMANGA_ID = 80; + DYNASTYSCANS_ID = 81; + + WebsiteRoots: array [0..81] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -413,7 +412,6 @@ interface ('MyReadingMangaInfo', 'http://myreadingmanga.info'), ('I-Komik', 'http://www.i-komik.com'), ('NHentai', 'http://nhentai.net'), - ('UnionMangas', 'http://unionmangas.com.br'), ('MangaMint', 'http://www.mangamint.com'), ('UnixManga', 'http://unixmanga.co'), ('HakiHome', 'http://hakihome.com'), diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c51a2ba59..1f4d7423c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2006,8 +2006,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/NHentai/directory_page_number.inc} - {$I includes/UnionMangas/directory_page_number.inc} - {$I includes/MangaMint/directory_page_number.inc} {$I includes/HakiHome/directory_page_number.inc} @@ -2140,9 +2138,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = NHENTAI_ID then Result := GetNHentaiDirectoryPageNumber else - if website = GetMangaSiteName(UNIONMANGAS_ID) then - Result := GetUnionMangasDirectoryPageNumber - else if WebsiteID = MANGAMINT_ID then Result := GetMangaMintDirectoryPageNumber else @@ -2304,8 +2299,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/NHentai/names_and_links.inc} - {$I includes/UnionMangas/names_and_links.inc} - {$I includes/MangaMint/names_and_links.inc} {$I includes/UnixManga/names_and_links.inc} @@ -2512,9 +2505,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = NHENTAI_ID then Result := NHentaiNamesAndLinks else - if WebsiteID = UNIONMANGAS_ID then - Result := UnionMangasNamesAndLinks - else if WebsiteID = MANGAMINT_ID then Result := MangaMintGetNamesAndLinks else @@ -2688,8 +2678,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/NHentai/manga_information.inc} - {$I includes/UnionMangas/manga_information.inc} - {$I includes/MangaMint/manga_information.inc} {$I includes/UnixManga/manga_information.inc} @@ -2908,9 +2896,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = NHENTAI_ID then Result := GetNHentaiInfoFromURL else - if WebsiteID = UNIONMANGAS_ID then - Result := GetUnionMangasInfoFromURL - else if WebsiteID = MANGAMINT_ID then Result := GetMangaMintInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 0fe0b5b90..af2a6b7f0 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -451,8 +451,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/NHentai/chapter_page_number.inc} - {$I includes/UnionMangas/chapter_page_number.inc} - {$I includes/MangaMint/chapter_page_number.inc} {$I includes/UnixManga/chapter_page_number.inc} @@ -611,9 +609,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiPageNumber else - if manager.container.MangaSiteID = UNIONMANGAS_ID then - Result := GetUnionMangasPageNumber - else if manager.container.MangaSiteID = MANGAMINT_ID then Result := GetMangaMintPageNumber else From 400ff1cd215be93bc4abf81ba82a5fd198328b71 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Jan 2016 23:34:14 +0800 Subject: [PATCH 0729/2794] added unionmangas module fix #152 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/UnionMangas.pas | 148 ++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/UnionMangas.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 443393d17..434518b04 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -19,4 +19,5 @@ uses MangaTr, Madokami, RawSenManga, - KissManga; + KissManga, + UnionMangas; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas new file mode 100644 index 000000000..c23007877 --- /dev/null +++ b/baseunits/modules/UnionMangas.pas @@ -0,0 +1,148 @@ +unit UnionMangas; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr, synautil; + +implementation + +const + dirurl='/mangas'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=query.XPathString('//*[@class="pagination"]/li[last()]/a/@href'); + if s<>'' then begin + s:=ReplaceRegExpr('^.*/(\d+)/?\*?$',s,'$1',True); + Page:=StrToIntDef(s,1); + end; + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='/a-z/'+IncStr(AURL)+'/*'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//div[@class="row"]/div/a[2]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//img[@class="img-thumbnail"]/@src'); + if title=''then title:=query.XPathString('//div/h2'); + for v in query.XPath('//h4') do begin + s:=v.toString; + if Pos('Gênero(s):',s)=1 then genres:=SeparateRight(s,':') else + if Pos('Autor:',s)=1 then authors:=SeparateRight(s,':') else + if Pos('Artista:',s)=1 then artists:=SeparateRight(s,':') else + if Pos('Status:',s)=1 then begin + if Pos('Ativo',s)>0 then status:='1' else status:='0'; + end; + end; + summary:=query.XPathString('//div/div[@class="panel-body"]'); + for v in query.XPath('//div[@class="row lancamento-linha"]/div[1]/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + for v in query.XPath('//div[@id="image"]/div/img[@class="real img-responsive"][@id!="imagem-forum"]/@data-lazy') do + PageLinks.Add(v.toString); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='UnionMangas'; + RootURL:='http://unionmangas.com.br'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From 3f08a823f0a200b01d96c38c44d6769885702d05 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 12:33:21 +0800 Subject: [PATCH 0730/2794] remove pururin close #113 --- .../includes/Pururin/chapter_page_number.inc | 45 ----- .../Pururin/directory_page_number.inc | 32 ---- baseunits/includes/Pururin/image_url.inc | 35 ---- .../includes/Pururin/manga_information.inc | 155 ------------------ .../includes/Pururin/names_and_links.inc | 47 ------ baseunits/uBaseUnit.pas | 95 +++++------ baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- config/mangalist.ini | 2 +- 9 files changed, 45 insertions(+), 391 deletions(-) delete mode 100644 baseunits/includes/Pururin/chapter_page_number.inc delete mode 100644 baseunits/includes/Pururin/directory_page_number.inc delete mode 100644 baseunits/includes/Pururin/image_url.inc delete mode 100644 baseunits/includes/Pururin/manga_information.inc delete mode 100644 baseunits/includes/Pururin/names_and_links.inc diff --git a/baseunits/includes/Pururin/chapter_page_number.inc b/baseunits/includes/Pururin/chapter_page_number.inc deleted file mode 100644 index d61a02fc4..000000000 --- a/baseunits/includes/Pururin/chapter_page_number.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetPururinPageNumber: Boolean; - var - s: String; - i, g: Cardinal; - l: TStringList; - isStartGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(PURURIN_ID, URL); - s := StringReplace(s, '_1.html', '.html', []); - s := StringReplace(s, '/view/', '/gallery/', []); - s := DecodeUrl(StringReplace(s, '/00/', '/', [])); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="square"', parse.Strings[i]) > 0) then - isStartGetPageNumber := True; - - if (isStartGetPageNumber) and - (Pos('class="square"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i + 1]; - g := length(s); - Delete(s, g - 10, g - 3); - Delete(s, 1, 9); - g := StrToInt(s); - manager.container.PageNumber := g; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Pururin/directory_page_number.inc b/baseunits/includes/Pururin/directory_page_number.inc deleted file mode 100644 index 307565181..000000000 --- a/baseunits/includes/Pururin/directory_page_number.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetPururinDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[PURURIN_ID, 1], 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('/browse/0/11/2.html', parse.Strings[i]) > 0) then - begin - Page := StrToInt(Trim(parse.Strings[i - 2])); - Break; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Pururin/image_url.inc b/baseunits/includes/Pururin/image_url.inc deleted file mode 100644 index 0ec24b528..000000000 --- a/baseunits/includes/Pururin/image_url.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetPururinImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(PURURIN_ID, URL); - s := StringReplace(s, '_1.html', '_', []); - s := DecodeUrl(StringReplace(s, '/00', '/0' + IntToStr(workCounter + 0), []) + - IntToStr(workCounter + 1) + '.html'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := parse.Count - 1 downto 4 do - if (Pos('class="b"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - EncodeURL(WebsiteRoots[PURURIN_ID, 1] + - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Pururin/manga_information.inc b/baseunits/includes/Pururin/manga_information.inc deleted file mode 100644 index fac6f8d48..000000000 --- a/baseunits/includes/Pururin/manga_information.inc +++ /dev/null @@ -1,155 +0,0 @@ - function GetPururinInfoFromURL: Byte; - var - s, readURL: String; - i, j: Integer; - isExtractArtists: Boolean = False; - isExtractParodies: Boolean = False; - isExtractGenres: Boolean = False; - isExtractCharacters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[PURURIN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(PURURIN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '0'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - readURL := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - //for i:=0 to parse.Count-1 do - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and (Pos('class="gallery-cover', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(WebsiteRoots[PURURIN_ID, 1] + - GetVal(parse[i + 4], 'src')); - - // get title - //if (Pos('class="otitle"', parse[i])<>0) AND (mangaInfo.title = '') then - if Pos('<title>', parse[i]) > 0 then - begin - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - if Pos('- Pururin', mangaInfo.title) <> 0 then - mangaInfo.title := ReplaceRegExpr( - '^(.*)\s\-.*\s-\sPururin,\sFree\sOnline\sHentai\sManga.*$', - mangaInfo.title, '$1', True); - end; - - // get summary - if (Pos('class="gallery-description', parse[i]) <> 0) then - begin - j := i + 1; - while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter( - StringFilter(TrimLeft(parse[j]))); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - Break; - end; - Inc(j); - end; - end; - - // get authors - if (Pos('Circle', parse[i]) <> 0) and - (Pos('</td>', parse[i + 1]) <> 0) then - mangaInfo.authors := parse[i + 6]; - - // get category - if (Pos('Category', parse[i]) <> 0) and - (Pos('</td>', parse[i + 1]) <> 0) then - mangaInfo.genres := mangaInfo.genres + parse[i + 6]; - - // get artists - if (Pos('Artist', parse[i]) <> 0) and - (Pos('</td>', parse[i + 1]) <> 0) then - isExtractArtists := True; - if isExtractArtists and (Pos('</ul', parse[i]) <> 0) then - isExtractArtists := False; - if isExtractArtists and (Pos('/browse/', parse[i]) <> 0) then - begin - if mangaInfo.artists = '' then - mangaInfo.artists := Trim(parse[i + 1]) - else - mangaInfo.artists := mangaInfo.artists + ', ' + Trim(parse[i + 1]); - end; - - // get parody - if ((Pos('Parody', parse[i]) <> 0) or - (Pos('Parodies', parse[i]) <> 0)) and - (Pos('</td>', parse[i + 1]) <> 0) then - isExtractParodies := True; - if isExtractParodies and (Pos('</ul', parse[i]) <> 0) then - isExtractParodies := False; - if isExtractParodies and (Pos('/browse/', parse[i]) <> 0) then - mangaInfo.genres := mangaInfo.genres + Trim(parse[i + 1]) + ', '; - - // get language - if (Pos('Language', parse[i]) <> 0) and - (Pos('</td>', parse[i + 1]) <> 0) then - mangaInfo.genres := mangaInfo.genres + parse[i + 6] + ', '; - - // get convention - if (Pos('Convention', parse[i]) <> 0) and - (Pos('</td>', parse[i + 1]) <> 0) then - mangaInfo.genres := mangaInfo.genres + parse[i + 6] + ', '; - - // get character - if (Pos('Character', parse[i]) <> 0) and - (Pos('</td>', parse[i + 1]) <> 0) then - isExtractCharacters := True; - if isExtractCharacters and (Pos('</ul', parse[i]) <> 0) then - isExtractCharacters := False; - if isExtractCharacters and (Pos('/browse/', parse[i]) <> 0) then - mangaInfo.genres := mangaInfo.genres + Trim(parse[i + 1]) + ', '; - - // get genres - if (Pos('Contents', parse[i]) <> 0) then - isExtractGenres := True; - if isExtractGenres and (Pos('</ul', parse[i]) <> 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('/browse/', parse[i]) <> 0) then - mangaInfo.genres := mangaInfo.genres + Trim(parse[i + 1]) + ', '; - - // get chapters - if (Pos('<a', parse[i]) <> 0) and (Pos('class="btn link-next', parse[i]) <> 0) then - readURL := GetVal(parse[i], 'href'); - end; - mangaInfo.artists := StringReplace(mangaInfo.artists, '</tr>, ', '', []); - mangaInfo.genres := StringReplace(mangaInfo.genres, '</tr>, ', '', []); - //only 1 chapter - if readURL <> '' then - begin - mangaInfo.numChapter := 1; - if not ExecRegExpr('^https?\://', readURL) then - readURL := WebsiteRoots[PURURIN_ID, 1] + readURL; - mangaInfo.chapterName.Add(mangaInfo.title); - mangaInfo.chapterLinks.Add(readURL); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Pururin/names_and_links.inc b/baseunits/includes/Pururin/names_and_links.inc deleted file mode 100644 index 87e157dda..000000000 --- a/baseunits/includes/Pururin/names_and_links.inc +++ /dev/null @@ -1,47 +0,0 @@ - function PururinGetNamesAndLinks: Byte; - var - numPage: Integer; - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - numPage := StrToIntDef(URL, 0); - if numPage = 0 then - s := WebsiteRoots[PURURIN_ID, 1] + '/' - else - s := WebsiteRoots[PURURIN_ID, 1] + PURURIN_BROWSER + '0/1' + - IntToStr(numPage) + '/' + IntToStr(numPage + 1) + '.html'; - - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="overlay', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 7]); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetAttributeValue(GetTagAttribute( - parse.Strings[i - 2], 'href=')), - WebsiteRoots[PURURIN_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d6c286ffb..930f620e7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -304,51 +304,50 @@ interface SCANMANGA_ID = 36; MANGAGO_ID = 37; DM5_ID = 38; - PURURIN_ID = 39; - MANGACOW_ID = 40; - KIVMANGA_ID = 41; - MEINMANGA_ID = 42; - MANGASPROJECT_ID = 43; - MANGAREADER_POR_ID = 44; - MANGASTREAMTO_ID = 45; - NINEMANGA_ID = 46; - NINEMANGA_ES_ID = 47; - NINEMANGA_CN_ID = 48; - NINEMANGA_RU_ID = 49; - NINEMANGA_DE_ID = 50; - NINEMANGA_IT_ID = 51; - NINEMANGA_BR_ID = 52; - JAPANSHIN_ID = 53; - JAPSCAN_ID = 54; - CENTRUMMANGI_PL_ID = 55; - MANGALIB_PL_ID = 56; - ONEMANGA_ID = 57; - MANGATOWN_ID = 58; - MANGAOKU_ID = 59; - MYREADINGMANGAINFO_ID = 60; - IKOMIK_ID = 61; - NHENTAI_ID = 62; - MANGAMINT_ID = 63; - UNIXMANGA_ID = 64; - HAKIHOME_ID = 65; - EXTREMEMANGAS_ID = 66; - MANGAHOST_ID = 67; - PORNCOMIX_ID = 68; - PORNCOMIXRE_ID = 69; - PORNCOMIXIC_ID = 70; - XXCOMICS_ID = 71; - XXCOMICSMT_ID = 72; - XXCOMICS3D_ID = 73; - PORNXXXCOMICS_ID = 74; - MANGASEE_ID = 75; - MANGAKU_ID = 76; - ACADEMYVN_ID = 77; - MANGAAT_ID = 78; - READMANGATODAY_ID = 79; - LONEMANGA_ID = 80; - DYNASTYSCANS_ID = 81; - - WebsiteRoots: array [0..81] of array [0..1] of string = ( + MANGACOW_ID = 39; + KIVMANGA_ID = 40; + MEINMANGA_ID = 41; + MANGASPROJECT_ID = 42; + MANGAREADER_POR_ID = 43; + MANGASTREAMTO_ID = 44; + NINEMANGA_ID = 45; + NINEMANGA_ES_ID = 46; + NINEMANGA_CN_ID = 47; + NINEMANGA_RU_ID = 48; + NINEMANGA_DE_ID = 49; + NINEMANGA_IT_ID = 50; + NINEMANGA_BR_ID = 51; + JAPANSHIN_ID = 52; + JAPSCAN_ID = 53; + CENTRUMMANGI_PL_ID = 54; + MANGALIB_PL_ID = 55; + ONEMANGA_ID = 56; + MANGATOWN_ID = 57; + MANGAOKU_ID = 58; + MYREADINGMANGAINFO_ID = 59; + IKOMIK_ID = 60; + NHENTAI_ID = 61; + MANGAMINT_ID = 62; + UNIXMANGA_ID = 63; + HAKIHOME_ID = 64; + EXTREMEMANGAS_ID = 65; + MANGAHOST_ID = 66; + PORNCOMIX_ID = 67; + PORNCOMIXRE_ID = 68; + PORNCOMIXIC_ID = 69; + XXCOMICS_ID = 70; + XXCOMICSMT_ID = 71; + XXCOMICS3D_ID = 72; + PORNXXXCOMICS_ID = 73; + MANGASEE_ID = 74; + MANGAKU_ID = 75; + ACADEMYVN_ID = 76; + MANGAAT_ID = 77; + READMANGATODAY_ID = 78; + LONEMANGA_ID = 79; + DYNASTYSCANS_ID = 80; + + WebsiteRoots: array [0..80] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -388,7 +387,6 @@ interface ('ScanManga', 'http://www.scan-manga.com'), ('MangaGo', 'http://www.mangago.me'), ('DM5', 'http://www.dm5.com'), - ('Pururin', 'http://pururin.com'), ('Mangacow', 'http://mangacow.co'), ('KivManga', 'http://www.kivmanga.com'), ('MeinManga', 'http://www.meinmanga.com/'), @@ -519,8 +517,6 @@ interface DM5_BROWSER = '/manhua-new'; - PURURIN_BROWSER = '/browse/'; - //MANGACOW_BROWSER :string = '/manga-list/all/any/name-az/'; MANGACOW_BROWSER = '/manga-list/all/any/last-added/'; @@ -1274,7 +1270,6 @@ function SitesWithSortedList(const website : String) : Boolean; end; Result := SitesMemberOf(website, [ FAKKU_ID, - PURURIN_ID, NINEMANGA_ID, NINEMANGA_ES_ID, NINEMANGA_CN_ID, @@ -1310,7 +1305,6 @@ function SitesWithoutFavorites(const website : String) : Boolean; end; Result := SitesMemberOf(website, [ FAKKU_ID, - PURURIN_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID, PORNCOMIX_ID, @@ -1376,7 +1370,6 @@ function SitesWithSingleChapter(const website : String) : Boolean; Result := False; Result := SitesMemberOf(website, [ FAKKU_ID, - PURURIN_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID, PORNCOMIX_ID, diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1f4d7423c..1ff3ae755 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1964,8 +1964,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/Fakku/directory_page_number.inc} - {$I includes/Pururin/directory_page_number.inc} - {$I includes/MangaPark/directory_page_number.inc} //{$I includes/MangaTraders/directory_page_number.inc} @@ -2105,9 +2103,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = DM5_ID then Result := GetDM5DirectoryPageNumber else - if WebsiteID = PURURIN_ID then - Result := GetPururinDirectoryPageNumber - else if (WebsiteID = NINEMANGA_ID) or (WebsiteID = NINEMANGA_ES_ID) or (WebsiteID = NINEMANGA_CN_ID) or @@ -2223,8 +2218,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaEsta/names_and_links.inc} - {$I includes/Pururin/names_and_links.inc} - {$I includes/HugeManga/names_and_links.inc} {$I includes/AnimeStory/names_and_links.inc} @@ -2412,9 +2405,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGAESTA_ID then Result := MangaEstaGetNamesAndLinks else - if WebsiteID = PURURIN_ID then - Result := PururinGetNamesAndLinks - else if WebsiteID = HUGEMANGA_ID then Result := HugeMangaGetNamesAndLinks else @@ -2618,8 +2608,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaEsta/manga_information.inc} - {$I includes/Pururin/manga_information.inc} - {$I includes/HugeManga/manga_information.inc} {$I includes/AnimeStory/manga_information.inc} @@ -2803,9 +2791,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGAESTA_ID then Result := GetMangaEstaInfoFromURL else - if WebsiteID = PURURIN_ID then - Result := GetPururinInfoFromURL - else if WebsiteID = HUGEMANGA_ID then Result := GetHugeMangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index af2a6b7f0..21c9c7bec 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -411,8 +411,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MeinManga/chapter_page_number.inc} - {$I includes/Pururin/chapter_page_number.inc} - {$I includes/RedHawkScans/chapter_page_number.inc} {$I includes/S2Scans/chapter_page_number.inc} @@ -527,9 +525,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = KOMIKID_ID then Result := GetKomikidPageNumber else - if manager.container.MangaSiteID = PURURIN_ID then - Result := GetPururinPageNumber - else if manager.container.MangaSiteID = HUGEMANGA_ID then Result := GetHugeMangaPageNumber else @@ -718,8 +713,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaVadisi/image_url.inc} - {$I includes/Pururin/image_url.inc} - {$I includes/RedHawkScans/image_url.inc} {$I includes/ScanManga/image_url.inc} @@ -839,9 +832,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAESTA_ID then Result := GetMangaEstaImageURL else - if manager.container.MangaSiteID = PURURIN_ID then - Result := GetPururinImageURL - else if manager.container.MangaSiteID = HUGEMANGA_ID then Result := GetHugeMangaImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 87ca92eab..178db69dd 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -18,4 +18,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,Pururin,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From ad3a1ba34d718f0e7d762193916c1c021d67a324 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 12:34:36 +0800 Subject: [PATCH 0731/2794] added seemh module #148 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Seemh.pas | 136 ++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Seemh.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 434518b04..a98a0e9a4 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -20,4 +20,5 @@ uses Madokami, RawSenManga, KissManga, - UnionMangas; + UnionMangas, + Seemh; diff --git a/baseunits/modules/Seemh.pas b/baseunits/modules/Seemh.pas new file mode 100644 index 000000000..830fbeecf --- /dev/null +++ b/baseunits/modules/Seemh.pas @@ -0,0 +1,136 @@ +unit Seemh; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr, synautil; + +implementation + +const + dirurl='/list/'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + Page:=StrToIntDef(query.XPathString('//div[@class="result-count"]/strong[2]'),1); + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='/index_p'+IncStr(AURL)+'.html'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//ul[@id="contList"]/li/p/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//p[@class="hcover"]/img/@src'); + if title=''then title:=query.XPathString('//div[@class="book-title"]/h1'); + genres:=SeparateRight(query.XPathString('//ul[@class="detail-list cf"]/li[2]/span[1]'),':'); + authors:=SeparateRight(query.XPathString('//ul[@class="detail-list cf"]/li[2]/span[2]'),':'); + if Pos('连载中',query.XPathString('//ul[@class="detail-list cf"]/li[@class="status"]'))>0 then status:='1' else status:='0'; + summary:=query.XPathString('//div[@id="intro-all"]'); + for v in query.XPath('//div[@id="chapter-list-0"]/ul/li/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toNode.getAttribute('title')); + end; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + for v in query.XPath('//div[@id="image"]/div/img[@class="real img-responsive"][@id!="imagem-forum"]/@data-lazy') do + PageLinks.Add(v.toString); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='Seemh'; + RootURL:='http://www.seemh.com'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From cf65ee41d5d40d80f0e3490399e00efb65b8cd8f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 14:31:30 +0800 Subject: [PATCH 0732/2794] mangafox remove watermark, fix not respect the option #125 --- baseunits/modules/MangaFox.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 5e2af03c1..c8f1a9312 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -297,7 +297,9 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; function AfterImageSaved(const AFilename: String; Module: TModuleContainer): Boolean; begin - Result := mangafoxwatermarkremover.RemoveWatermark(AFilename); + Result := True; + if OptionMangaFoxRemoveWatermark then + Result := mangafoxwatermarkremover.RemoveWatermark(AFilename); end; procedure RegisterModule; From a47897e09fa8071cf209c2fadf29af1dcd043a98 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 14:40:38 +0800 Subject: [PATCH 0733/2794] added option to save as png on mangafox remove watermark #125 --- baseunits/extras/mangafoxwatermarkremover.pas | 12 ++++++++---- baseunits/modules/MangaFox.pas | 2 +- baseunits/uBaseUnit.pas | 1 + mangadownloader/forms/frmMain.lfm | 14 ++++++++++++-- mangadownloader/forms/frmMain.pas | 10 ++++++++++ 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas index 00a37405a..a995810c4 100644 --- a/baseunits/extras/mangafoxwatermarkremover.pas +++ b/baseunits/extras/mangafoxwatermarkremover.pas @@ -10,7 +10,7 @@ interface LazFileUtils; function LoadTemplate(const TempDir: String): Integer; -function RemoveWatermark(const AFilename: String): Boolean; +function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean = False): Boolean; procedure ClearTemplate; var @@ -69,7 +69,7 @@ function ColorIsWhite(const Color: TColor32Rec): Boolean; Result := (Color.R = 255) and (Color.G = 255) and (Color.B = 255); end; -function RemoveWatermark(const AFilename: String): Boolean; +function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; var imgbase, imgproc, imgtemp: TImageData; i, x, y, bmi: Integer; @@ -147,8 +147,12 @@ function RemoveWatermark(const AFilename: String): Boolean; try NewImage(imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgbase.Format, imgproc); CopyRect(imgbase, 0, 0, imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgproc, 0, 0); - if DeleteFileUTF8(AFilename) then - Result := SaveImageToFile(AFilename, imgproc); + if DeleteFileUTF8(AFilename) then begin + if SaveAsPNG then + Result := SaveImageToFile(ChangeFileExt(AFilename, '.png'), imgproc) + else + Result := SaveImageToFile(AFilename, imgproc); + end; finally FreeImage(imgproc); end; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index c8f1a9312..b6a5c57ae 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -299,7 +299,7 @@ function AfterImageSaved(const AFilename: String; Module: TModuleContainer): Boo begin Result := True; if OptionMangaFoxRemoveWatermark then - Result := mangafoxwatermarkremover.RemoveWatermark(AFilename); + Result := mangafoxwatermarkremover.RemoveWatermark(AFilename, OptionMangaFoxRemoveWatermarkSaveAsPNG); end; procedure RegisterModule; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 930f620e7..4e91e6216 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -631,6 +631,7 @@ interface OptionBatotoShowAllLang: Boolean = True; OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; OptionMangaFoxRemoveWatermark: Boolean = False; + OptionMangaFoxRemoveWatermarkSaveAsPNG: Boolean = False; OptionHTTPUseGzip: Boolean = True; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 746a23caf..4ad59cd00 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,6 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange LCLVersion = '1.7' - Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -2942,11 +2941,22 @@ object MainForm: TMainForm Left = 16 Height = 19 Top = 88 - Width = 312 + Width = 186 Caption = '[Mangafox] Remove watermark' + OnChange = cbOptionMangaFoxRemoveWatermarkChange ParentFont = False TabOrder = 2 end + object cbOptionMangaFoxRemoveWatermarkSaveAsPNG: TCheckBox + Left = 34 + Height = 19 + Top = 112 + Width = 85 + Caption = 'Save as PNG' + Enabled = False + ParentFont = False + TabOrder = 3 + end end end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 082b7eb43..2793ba2a1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -55,6 +55,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; cbOptionMangaFoxRemoveWatermark: TCheckBox; + cbOptionMangaFoxRemoveWatermarkSaveAsPNG: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; @@ -358,6 +359,7 @@ TMainForm = class(TForm) procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderNameChange(Sender: TObject); + procedure cbOptionMangaFoxRemoveWatermarkChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; @@ -2143,6 +2145,11 @@ procedure TMainForm.cbOptionGenerateMangaFolderNameChange(Sender: TObject); lbOptionMangaCustomRenameHint.Enabled := cbOptionGenerateMangaFolderName.Checked; end; +procedure TMainForm.cbOptionMangaFoxRemoveWatermarkChange(Sender: TObject); +begin + cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Enabled:=cbOptionMangaFoxRemoveWatermark.Checked; +end; + procedure TMainForm.btReadOnlineClick(Sender: TObject); begin OpenURL(mangaInfo.url); @@ -4409,6 +4416,7 @@ procedure TMainForm.LoadOptions; cbOptionBatotoShowScanGroup.Checked := ReadBool('misc', 'BatotoShowScanGroup', True); cbOptionBatotoShowAllLang.Checked := ReadBool('misc', 'BatotoShowAllLang', False); cbOptionMangaFoxRemoveWatermark.Checked := ReadBool('misc', 'MangafoxRemoveWatermark', False); + cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Checked := ReadBool('misc', 'MangafoxRemoveWatermarkSaveAsPNG', False); // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4528,6 +4536,7 @@ procedure TMainForm.SaveOptions; WriteBool('misc', 'BatotoShowScanGroup', cbOptionBatotoShowScanGroup.Checked); WriteBool('misc', 'BatotoShowAllLang', cbOptionBatotoShowAllLang.Checked); WriteBool('misc', 'MangafoxRemoveWatermark', cbOptionMangaFoxRemoveWatermark.Checked); + WriteBool('misc', 'MangafoxRemoveWatermarkSaveAsPNG', cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Checked); finally UpdateFile; end; @@ -4663,6 +4672,7 @@ procedure TMainForm.ApplyOptions; OptionBatotoShowScanGroup := cbOptionBatotoShowScanGroup.Checked; OptionBatotoShowAllLang := cbOptionBatotoShowAllLang.Checked; OptionMangaFoxRemoveWatermark := cbOptionMangaFoxRemoveWatermark.Checked; + OptionMangaFoxRemoveWatermarkSaveAsPNG := cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Checked; if OptionMangaFoxRemoveWatermark then mangafoxwatermarkremover.LoadTemplate(CleanAndExpandDirectory(GetCurrentDirUTF8) + OptionMangaFoxTemplateFolder) else From 6b7e9466bf07ba3eb19287f51dfc8bd130b71cbe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 14:40:50 +0800 Subject: [PATCH 0734/2794] update translations --- mangadownloader/languages/fmd.en.po | 32 ++++++++------------------ mangadownloader/languages/fmd.id_ID.po | 9 ++++++++ mangadownloader/languages/fmd.po | 9 ++++++++ 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6efc4856f..03e6f65f0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -91,9 +91,6 @@ msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" #: frmmain.rs_dlgtitleexistindllist -#| msgid "" -#| "This title are already in download list.\n" -#| "Do you want to download it anyway?\n" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" @@ -122,9 +119,6 @@ msgid "URL not supported!" msgstr "URL not supported!" #: frmmain.rs_droptargetmodeitems -#| msgid "" -#| "Download all\n" -#| "Add to favorites\n" msgid "" "Download all\n" "Add to favorites\n" @@ -133,10 +127,6 @@ msgstr "" "Add to favorites\n" #: frmmain.rs_filterstatusitems -#| msgid "" -#| "Completed\n" -#| "Ongoing\n" -#| "<none>\n" msgid "" "Completed\n" "Ongoing\n" @@ -151,9 +141,6 @@ msgid "Free Manga Downloader already running!" msgstr "Free Manga Downloader already running!" #: frmmain.rs_hintfavoriteproblem -#| msgid "" -#| "There is a problem with this data!\n" -#| "Removing and re-adding this data may fix the problem.\n" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" @@ -207,11 +194,6 @@ msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" #: frmmain.rs_lbloptionexternalparamshint -#| msgid "" -#| "%s : Path to the manga\n" -#| "%s : Chapter filename\n" -#| "\n" -#| "Example : \"%s%s\"\n" msgid "" "%s : Path to the manga\n" "%s : Chapter filename\n" @@ -250,11 +232,6 @@ msgid "One week" msgstr "One week" #: frmmain.rs_optionfmddoitems -#| msgid "" -#| "Do nothing\n" -#| "Exit FMD\n" -#| "Shutdown\n" -#| "Hibernate\n" msgid "" "Do nothing\n" "Exit FMD\n" @@ -477,6 +454,11 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" +#: tmainform.caption +msgctxt "tmainform.caption" +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" @@ -555,6 +537,10 @@ msgctxt "tmainform.cboptionmangafoxremovewatermark.caption" msgid "[Mangafox] Remove watermark" msgstr "[Mangafox] Remove watermark" +#: tmainform.cboptionmangafoxremovewatermarksaveaspng.caption +msgid "Save as PNG" +msgstr "Save as PNG" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Minimize to tray" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index eeb7221f7..2d8dd8cae 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -446,6 +446,11 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" +#: tmainform.caption +msgctxt "tmainform.caption" +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" @@ -521,6 +526,10 @@ msgctxt "tmainform.cboptionmangafoxremovewatermark.caption" msgid "[Mangafox] Remove watermark" msgstr "[Mangafox] Hapus watermark" +#: tmainform.cboptionmangafoxremovewatermarksaveaspng.caption +msgid "Save as PNG" +msgstr "Simpan sebagai PNG" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Perkecil ke penampan" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 3c68b8155..2738ea8d3 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -418,6 +418,11 @@ msgstr "" msgid "Visit my blog" msgstr "" +#: tmainform.caption +msgctxt "TMAINFORM.CAPTION" +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" @@ -493,6 +498,10 @@ msgctxt "TMAINFORM.CBOPTIONMANGAFOXREMOVEWATERMARK.CAPTION" msgid "[Mangafox] Remove watermark" msgstr "" +#: tmainform.cboptionmangafoxremovewatermarksaveaspng.caption +msgid "Save as PNG" +msgstr "" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "" From e5773a6fb7ca20af5f299d28b7543e3b93458364 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 15:02:17 +0800 Subject: [PATCH 0735/2794] remove mangastreamto script #154 --- .../MangaStreamTo/chapter_page_number.inc | 37 --------- .../includes/MangaStreamTo/image_url.inc | 33 -------- .../MangaStreamTo/manga_information.inc | 57 ------------- .../MangaStreamTo/names_and_links.inc | 40 --------- baseunits/uBaseUnit.pas | 81 +++++++++---------- baseunits/uData.pas | 10 --- baseunits/uDownloadsManager.pas | 10 --- 7 files changed, 38 insertions(+), 230 deletions(-) delete mode 100644 baseunits/includes/MangaStreamTo/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaStreamTo/image_url.inc delete mode 100644 baseunits/includes/MangaStreamTo/manga_information.inc delete mode 100644 baseunits/includes/MangaStreamTo/names_and_links.inc diff --git a/baseunits/includes/MangaStreamTo/chapter_page_number.inc b/baseunits/includes/MangaStreamTo/chapter_page_number.inc deleted file mode 100644 index 2c66f08c6..000000000 --- a/baseunits/includes/MangaStreamTo/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetMangaStreamToPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGASTREAMTO_ID, URL); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := parse.Count - 1 downto 0 do - begin - if (Pos('option value=', parse.Strings[i]) > 0) then - begin - try - manager.container.PageNumber := - StrToInt(Trim(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')))); - except - manager.container.PageNumber := 0; - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaStreamTo/image_url.inc b/baseunits/includes/MangaStreamTo/image_url.inc deleted file mode 100644 index fe22e4b96..000000000 --- a/baseunits/includes/MangaStreamTo/image_url.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangaStreamToImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := StringReplace(URL, '.html', '', []); - s := s + '-page-' + IntToStr(workCounter + 1) + '.html'; - s := FillMangaSiteHost(MANGASTREAMTO_ID, s); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="manga-page"', parse.Strings[i]) > 0) and - (Pos('<img', parse.Strings[i]) > 0) then - begin - if not Terminated then - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaStreamTo/manga_information.inc b/baseunits/includes/MangaStreamTo/manga_information.inc deleted file mode 100644 index cf139cb6c..000000000 --- a/baseunits/includes/MangaStreamTo/manga_information.inc +++ /dev/null @@ -1,57 +0,0 @@ - function GetMangaStreamToInfoFromURL: Byte; - var - isExtractChapter: Boolean = False; - i: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGASTREAMTO_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGASTREAMTO_ID, 0]; - - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.status := ''; - - if parse.Count = 0 then - Exit; - - // mangastream.to only has chapter list - - // get current_topic - for i := 0 to parse.Count - 1 do - begin - //title - if Pos('<h1>', parse[i]) > 0 then - if Pos('</h1>', parse[i + 2]) > 0 then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - - //names and links - if (Pos('<td ', parse[i]) > 0) and (Pos('class="ch-subject"', parse[i]) > 0) then - isExtractChapter := True; - if isExtractChapter and (Pos('</td', parse[i]) > 0) then - isExtractChapter := False; - if isExtractChapter and (Pos('<a ', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(Trim(GetVal(parse[i], 'href'))); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaStreamTo/names_and_links.inc b/baseunits/includes/MangaStreamTo/names_and_links.inc deleted file mode 100644 index c8e7f4d5a..000000000 --- a/baseunits/includes/MangaStreamTo/names_and_links.inc +++ /dev/null @@ -1,40 +0,0 @@ - function MangaStreamToGetNamesAndLinks: Byte; - var - i: Cardinal; - isExtractNamesAndLinks: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGASTREAMTO_ID, 1] + - MANGASTREAMTO_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (Pos('<table', parse.Strings[i]) > 0) and - (Pos('id="page-list"', parse.Strings[i]) > 0) then - isExtractNamesAndLinks := True; - - if isExtractNamesAndLinks and - (Pos('</table', parse.Strings[i]) > 0) then - isExtractNamesAndLinks := False; - - if isExtractNamesAndLinks and - (Pos('href="/', parse.Strings[i]) > 0) then - begin - names.Add(HTMLEntitiesFilter(StringFilter(Trim(parse.Strings[i + 1])))); - links.Add(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href='))); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4e91e6216..227d195b0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -309,45 +309,44 @@ interface MEINMANGA_ID = 41; MANGASPROJECT_ID = 42; MANGAREADER_POR_ID = 43; - MANGASTREAMTO_ID = 44; - NINEMANGA_ID = 45; - NINEMANGA_ES_ID = 46; - NINEMANGA_CN_ID = 47; - NINEMANGA_RU_ID = 48; - NINEMANGA_DE_ID = 49; - NINEMANGA_IT_ID = 50; - NINEMANGA_BR_ID = 51; - JAPANSHIN_ID = 52; - JAPSCAN_ID = 53; - CENTRUMMANGI_PL_ID = 54; - MANGALIB_PL_ID = 55; - ONEMANGA_ID = 56; - MANGATOWN_ID = 57; - MANGAOKU_ID = 58; - MYREADINGMANGAINFO_ID = 59; - IKOMIK_ID = 60; - NHENTAI_ID = 61; - MANGAMINT_ID = 62; - UNIXMANGA_ID = 63; - HAKIHOME_ID = 64; - EXTREMEMANGAS_ID = 65; - MANGAHOST_ID = 66; - PORNCOMIX_ID = 67; - PORNCOMIXRE_ID = 68; - PORNCOMIXIC_ID = 69; - XXCOMICS_ID = 70; - XXCOMICSMT_ID = 71; - XXCOMICS3D_ID = 72; - PORNXXXCOMICS_ID = 73; - MANGASEE_ID = 74; - MANGAKU_ID = 75; - ACADEMYVN_ID = 76; - MANGAAT_ID = 77; - READMANGATODAY_ID = 78; - LONEMANGA_ID = 79; - DYNASTYSCANS_ID = 80; - - WebsiteRoots: array [0..80] of array [0..1] of string = ( + NINEMANGA_ID = 44; + NINEMANGA_ES_ID = 45; + NINEMANGA_CN_ID = 46; + NINEMANGA_RU_ID = 47; + NINEMANGA_DE_ID = 48; + NINEMANGA_IT_ID = 49; + NINEMANGA_BR_ID = 50; + JAPANSHIN_ID = 51; + JAPSCAN_ID = 52; + CENTRUMMANGI_PL_ID = 53; + MANGALIB_PL_ID = 54; + ONEMANGA_ID = 55; + MANGATOWN_ID = 56; + MANGAOKU_ID = 57; + MYREADINGMANGAINFO_ID = 58; + IKOMIK_ID = 59; + NHENTAI_ID = 60; + MANGAMINT_ID = 61; + UNIXMANGA_ID = 62; + HAKIHOME_ID = 63; + EXTREMEMANGAS_ID = 64; + MANGAHOST_ID = 65; + PORNCOMIX_ID = 66; + PORNCOMIXRE_ID = 67; + PORNCOMIXIC_ID = 68; + XXCOMICS_ID = 69; + XXCOMICSMT_ID = 70; + XXCOMICS3D_ID = 71; + PORNXXXCOMICS_ID = 72; + MANGASEE_ID = 73; + MANGAKU_ID = 74; + ACADEMYVN_ID = 75; + MANGAAT_ID = 76; + READMANGATODAY_ID = 77; + LONEMANGA_ID = 78; + DYNASTYSCANS_ID = 79; + + WebsiteRoots: array [0..79] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -392,7 +391,6 @@ interface ('MeinManga', 'http://www.meinmanga.com/'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), - ('MangaStreamTo', 'http://www.mangastream.to'), ('NineManga', 'http://www.ninemanga.com'), ('NineManga_ES', 'http://es.ninemanga.com'), ('NineManga_CN', 'http://cn.ninemanga.com'), @@ -528,8 +526,6 @@ interface MANGAREADER_POR_BROWSER = '/AJAX/listaMangas/all'; - MANGASTREAMTO_BROWSER = '/series.html'; - NINEMANGA_BROWSER = '/search/?name_sel=contain&wd=&author_sel=contain&author=&artist_sel=contain&artist=&category_id=&out_category_id=&completed_series=either'; @@ -1336,7 +1332,6 @@ function SitesWithoutInformation(const website: String): Boolean; TURKCRAFT_ID, HUGEMANGA_ID, KIVMANGA_ID, - MANGASTREAMTO_ID, MANGAOKU_ID, UNIXMANGA_ID ]); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1ff3ae755..fa78a3fd9 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -2268,8 +2268,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaREADER_POR/names_and_links.inc} - {$I includes/MangaStreamTo/names_and_links.inc} - {$I includes/NineManga/names_and_links.inc} {$I includes/JapanShin/names_and_links.inc} @@ -2453,9 +2451,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGAREADER_POR_ID then Result := MangaREADER_PORGetNamesAndLinks else - if WebsiteID = MANGASTREAMTO_ID then - Result := MangaStreamToGetNamesAndLinks - else if (WebsiteID = NINEMANGA_ID) or (WebsiteID = NINEMANGA_ES_ID) or (WebsiteID = NINEMANGA_CN_ID) or @@ -2642,8 +2637,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaREADER_POR/manga_information.inc} - {$I includes/MangaStreamTo/manga_information.inc} - {$I includes/NineManga/manga_information.inc} {$I includes/JapanShin/manga_information.inc} @@ -2839,9 +2832,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORInfoFromURL else - if WebsiteID = MANGASTREAMTO_ID then - Result := GetMangaStreamToInfoFromURL - else if (WebsiteID = NINEMANGA_ID) or (WebsiteID = NINEMANGA_ES_ID) or (WebsiteID = NINEMANGA_CN_ID) or diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 21c9c7bec..738fb2b1d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -403,8 +403,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaPark/chapter_page_number.inc} - {$I includes/MangaStreamTo/chapter_page_number.inc} - {$I includes/MangaTraders/chapter_page_number.inc} {$I includes/MangaVadisi/chapter_page_number.inc} @@ -559,9 +557,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = HENTAI2READ_ID then Result := GetHentai2ReadPageNumber else - if manager.container.MangaSiteID = MANGASTREAMTO_ID then - Result := GetMangaStreamToPageNumber - else if (manager.container.MangaSiteID = NINEMANGA_ID) or (manager.container.MangaSiteID = NINEMANGA_ES_ID) or (manager.container.MangaSiteID = NINEMANGA_CN_ID) or @@ -707,8 +702,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangasPROJECT/image_url.inc} - {$I includes/MangaStreamTo/image_url.inc} - {$I includes/MangaTraders/image_url.inc} {$I includes/MangaVadisi/image_url.inc} @@ -884,9 +877,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORImageURL else - if manager.container.MangaSiteID = MANGASTREAMTO_ID then - Result := GetMangaStreamToImageURL - else if (manager.container.MangaSiteID = NINEMANGA_ID) or (manager.container.MangaSiteID = NINEMANGA_ES_ID) or (manager.container.MangaSiteID = NINEMANGA_CN_ID) or From af64ff3e0239c1c55a29ddf2109407b4bd47d7f7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 15:14:19 +0800 Subject: [PATCH 0736/2794] added mangastreamto module fix #154 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaStreamTo.pas | 132 ++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaStreamTo.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a98a0e9a4..9454b4767 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -21,4 +21,5 @@ uses RawSenManga, KissManga, UnionMangas, - Seemh; + Seemh, + MangaStreamTo; diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas new file mode 100644 index 000000000..c3e4ab98f --- /dev/null +++ b/baseunits/modules/MangaStreamTo.pas @@ -0,0 +1,132 @@ +unit MangaStreamTo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr, synautil; + +implementation + +const + dirurl='/series.html'; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@id="page-list"]//tr/td/p/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + if title=''then title:=query.XPathString('//div[@id="content-main"]/h1'); + for v in query.XPath('//table[@class="ch-table"]/tbody/tr/td/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('//select[@id="id_page"]/option').Count; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=AURL; + s:=ReplaceRegExpr('\.html?$',s,'',False); + s+='-page-'+IncStr(DownloadThread.workCounter)+'.html'; + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageLinks[DownloadThread.workCounter]:=query.XPathString('//img[@class="manga-page center-block"]/@src'); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='MangaStreamTo'; + RootURL:='http://www.mangastream.to'; + InformationAvailable:=False; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 9c03cf34f54ffcb5b39863c550fd473d3bf4c8df Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 15:29:32 +0800 Subject: [PATCH 0737/2794] cloudflare, force minimun wait time to 5s --- baseunits/modules/Cloudflare.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 08bc17038..ac9ac6eab 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -102,6 +102,8 @@ function GETCF(const AHTTP:THTTPSendThread;AURL:String;var Cookie:String):Boolea if (m<>'') and (u<>'') then begin AHTTP.Reset; AHTTP.Headers.Values['Referer']:=' '+AURL; + //minimum wait time is 5000 + if st<5000 then st:=5000; Sleep(st); AHTTP.FollowRedirection:=False; if AHTTP.HTTPRequest(m,FillHost(h,u)) then From b4876c8539b742b48fd47369d8ea3bf7b006c411 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 15:47:55 +0800 Subject: [PATCH 0738/2794] cloudflare: work with previous connection on first attempt and do retry for 3 times before fail --- baseunits/modules/Cloudflare.pas | 48 +++++++++++++++++++------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index ac9ac6eab..5ee0d6c74 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -87,30 +87,38 @@ function AntiBotActive(const AHTTP:THTTPSendThread):Boolean; function GETCF(const AHTTP:THTTPSendThread;AURL:String;var Cookie:String):Boolean; var m, u, h: String; - st: Integer; + st, counter: Integer; begin Result:=False; if AHTTP=nil then Exit; if Cookie<>'' then AHTTP.Cookies.Text:=Cookie; - Result := AHTTP.GET(AURL); - if AntiBotActive(AHTTP) then begin - m:='GET'; - u:=''; - h:=AppendURLDelim(GetHostURL(AURL)); - st:=5000; - if GetAnsweredURL(StreamToString(AHTTP.Document),h,m,u,st) then - if (m<>'') and (u<>'') then begin - AHTTP.Reset; - AHTTP.Headers.Values['Referer']:=' '+AURL; - //minimum wait time is 5000 - if st<5000 then st:=5000; - Sleep(st); - AHTTP.FollowRedirection:=False; - if AHTTP.HTTPRequest(m,FillHost(h,u)) then - Result:=AHTTP.Cookies.Values['cf_clearance']<>''; - AHTTP.FollowRedirection:=True; - if Result then Cookie:=AHTTP.GetCookies; - end; + counter:=0; + while counter<3 do begin + Inc(counter); + if AntiBotActive(AHTTP) then begin + m:='GET'; + u:=''; + h:=AppendURLDelim(GetHostURL(AURL)); + st:=5000; + if GetAnsweredURL(StreamToString(AHTTP.Document),h,m,u,st) then + if (m<>'') and (u<>'') then begin + AHTTP.Reset; + AHTTP.Headers.Values['Referer']:=' '+AURL; + //minimum wait time is 5000 + if st<5000 then st:=5000; + Sleep(st); + AHTTP.FollowRedirection:=False; + if AHTTP.HTTPRequest(m,FillHost(h,u)) then + Result:=AHTTP.Cookies.Values['cf_clearance']<>''; + AHTTP.FollowRedirection:=True; + if Result then Cookie:=AHTTP.GetCookies; + end; + end; + if Result then Exit + else if counter<3 then begin + AHTTP.Reset; + Result:=AHTTP.GET(AURL); + end; end; end; From 3373ecb65414572d5c6bd0743ed88a008726f83b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 16:36:44 +0800 Subject: [PATCH 0739/2794] pecintakomik, rewrite all script #147 --- baseunits/modules/PecintaKomik - Copy.pas | 447 ++++++++++++++++++++ baseunits/modules/PecintaKomik.pas | 475 ++++------------------ 2 files changed, 532 insertions(+), 390 deletions(-) create mode 100644 baseunits/modules/PecintaKomik - Copy.pas diff --git a/baseunits/modules/PecintaKomik - Copy.pas b/baseunits/modules/PecintaKomik - Copy.pas new file mode 100644 index 000000000..f28661839 --- /dev/null +++ b/baseunits/modules/PecintaKomik - Copy.pas @@ -0,0 +1,447 @@ +unit PecintaKomik; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + HTMLUtil, synautil; + +implementation + +const + dirURL = '/directory/'; + +function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; + var Page: Integer; {%H-}Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := 1; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const Names, Links: TStringList; const {%H-}URL: String; + Module: TModuleContainer): Integer; +var + Parse: TStringList; + + procedure ScanParse; + var + i, j: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'section') and + (GetVal(Parse[i], 'class') = 'cols') then + begin + for j := i + 1 to Parse.Count - 1 do + if GetTagName(Parse[j]) = '/section' then + Break + else + if (GetTagName(Parse[j]) = 'a') and + (GetVal(Parse[j], 'class') = 'screenshot') then + begin + Links.Add(AppendURLDelim(GetVal(Parse[j], 'href'))); + Names.Add(CommonStringFilter(Parse[j + 1])); + end; + Break; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const URL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + Parse: TStringList; + info: TMangaInfo; + + procedure ScanChapters(const StartIndex: Integer); + var + i: Integer; + s: String; + begin + for i := StartIndex + 1 to Parse.Count - 1 do + begin + s := GetTagName(Parse[i]); + if s = '/div' then + Break + else + if s = 'a' then + begin + info.chapterLinks.Add(AppendURLDelim(GetVal(Parse[i], 'href'))); + info.chapterName.Add(CommonStringFilter(Parse[i + 1])); + end; + end; + + //invert chapters + if info.chapterLinks.Count > 0 then + InvertStrings([info.chapterLinks, info.chapterName]); + end; + + procedure ScanInfo(const StartIndex: Integer); + var + i: Integer; + s: String; + begin + for i := StartIndex + 1 to Parse.Count - 1 do + begin + s := GetTagName(Parse[i]); + if s = '/div' then + Break + else + if s = 'li' then + begin + //authors + if Pos('Author(s):', Parse[i + 1]) = 1 then + info.authors := CommonStringFilter(SeparateRight(Parse[i + 1], + 'Author(s):')) + else + //artist + if Pos('Artist(s):', Parse[i + 1]) = 1 then + info.artists := CommonStringFilter(SeparateRight(Parse[i + 1], + 'Artist(s):')) + else + //genres + if Pos('Genre:', Parse[i + 1]) = 1 then + info.genres := CommonStringFilter(SeparateRight(Parse[i + 1], 'Genre:')) + else + //summary + if Pos('Sinopsis:', Parse[i + 1]) = 1 then + info.summary := CommonStringFilter(SeparateRight(Parse[i + 1], 'Sinopsis:')); + end; + end; + end; + + procedure ScanInfo2(const StartIndex: Integer); + var + i: Integer; + s: String; + begin + for i := StartIndex + 1 to Parse.Count - 1 do + begin + s := GetTagName(Parse[i]); + if s = '/div' then + Break + else + if s = 'li' then + begin + //authors + if Pos('Author(s):', Parse[i + 2]) = 1 then + info.authors := CommonStringFilter(Parse[i + 4]) + else + //artist + if Pos('Artist(s):', Parse[i + 2]) = 1 then + info.artists := CommonStringFilter(Parse[i + 4]) + else + //genres + if Pos('Genre:', Parse[i + 2]) = 1 then + info.genres := CommonStringFilter(Parse[i + 4]) + else + //summary + if Pos('Sinopsis:', Parse[i + 2]) = 1 then + info.summary := CommonStringFilter(Parse[i + 4]); + end; + end; + end; + + //broken layout + procedure ScanInfo3; + var + i, j: Integer; + begin + info.genres := ''; + info.summary := ''; + for i := 0 to Parse.Count - 1 do + begin + //cover + if info.coverLink = '' then + if (GetTagName(Parse[i]) = 'img') and + (GetVal(Parse[i], 'class') = 'pecintakomik') then + info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); + //title + if info.title = '' then + if GetVal(Parse[i], 'class') = 'aname' then + info.title := CommonStringFilter(Parse[i + 1]); + if GetVal(Parse[i], 'class') = 'propertytitle' then + begin + //author + if Pos('Autor:', Parse[i + 1]) = 1 then + info.authors := CommonStringFilter(Parse[i + 6]) + else + //artist + if Pos('Artist:', Parse[i + 1]) = 1 then + info.artists := CommonStringFilter(Parse[i + 6]); + //summary + if Pos('Ringkasan Cerita:', Parse[i + 1]) = 1 then + for j := i + 3 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/td' then + Break + else + if (Parse[j] <> '') and (Parse[j][1] <> '<') then + begin + if info.summary <> '' then + info.summary += LineEnding; + info.summary += CommonStringFilter(Parse[j]); + end; + end; + //genre + if GetVal(Parse[i], 'class') = 'genretags' then + AddCommaString(info.genres, CommonStringFilter(Parse[i + 1])); + end; + //chapters + if (GetTagName(Parse[i]) = 'ul') and + (GetVal(Parse[i], 'class') = 'series_alpha') then + begin + ScanChapters(i); + Break; + end; + end; + end; + + procedure ScanParse; + var + i, j: Integer; + begin + if Pos('/manga/', URL) = 0 then + begin + for i := 0 to Parse.Count - 1 do + begin + if GetVal(Parse[i], 'http-equiv') = 'x-ua-compatible' then + begin + ScanInfo3; + Break; + end; + + //cover + if info.coverLink = '' then + if (GetTagName(Parse[i]) = 'img') and + (GetVal(Parse[i], 'class') = 'pecintakomik') then + info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); + + if GetVal(Parse[i], 'class') = 'post-cnt' then + if GetTagName(Parse[i + 2]) = 'h2' then + begin + //chapters + if Pos('List Chapter(s)', Parse[i + 3]) <> 0 then + begin + ScanChapters(i); + Break; + end + else + begin + //title + if info.title = '' then + info.title := CommonStringFilter(Parse[i + 3]); + //info + if (GetTagName(Parse[i + 8]) = 'li') and + (GetTagName(Parse[i + 9]) <> 'strong') then + ScanInfo(i) + else + ScanInfo2(i); + end; + end; + end; + end + else + //no info + for i := 0 to Parse.Count - 1 do + begin + //title + if info.title = '' then + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'name') = 'manga') then + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if (GetTagName(Parse[j]) = 'option') and + (GetVal(Parse[j], 'selected') = 'selected') then + begin + info.title := CommonStringFilter(Parse[j + 1]); + Break; + end; + end; + //chapters + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'name') = 'chapter') then + begin + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if GetTagName(Parse[j]) = 'option' then + begin + Inc(info.numChapter); + info.chapterLinks.Add(AppendURLDelim(URL) + IntToStr(info.numChapter)); + info.chapterName.Add('Chapter ' + IntToStr(info.numChapter)); + end; + end; + Break; + end; + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit; + info := MangaInfo.mangaInfo; + info.website := Module.Website; + info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + Parse := TStringList.Create; + try + if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then + begin + Result := INFORMATION_NOT_FOUND; + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := NO_ERROR; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i, j: Integer; + begin + for i := 0 to Parse.Count - 1 do + if (GetTagName(Parse[i]) = 'select') and + (GetVal(Parse[i], 'name') = 'page') then + begin + for j := i + 1 to Parse.Count - 1 do + begin + if GetTagName(Parse[j]) = '/select' then + Break + else + if GetTagName(Parse[j]) = 'option' then + Inc(Container.PageNumber); + end; + Break; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.PageNumber := 0; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + FillHost(Module.RootURL, URL), + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; + Module: TModuleContainer): Boolean; +var + Parse: TStringList; + Container: TTaskContainer; + + procedure ScanParse; + var + i: Integer; + baseurl: String; + begin + baseurl := Module.RootURL; + for i := 0 to Parse.Count - 1 do + begin + if GetTagName(Parse[i]) = 'base' then + baseurl := GetVal(Parse[i], 'href'); + if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'picture') then + begin + if DownloadThread.workCounter < Container.PageLinks.Count then + Container.PageLinks[DownloadThread.workCounter] := + MaybeFillHost(baseurl, GetVal(Parse[i], 'src')); + Break; + end; + end; + end; + +begin + Result := False; + if DownloadThread = nil then Exit; + Container := DownloadThread.manager.container; + Parse := TStringList.Create; + try + if DownloadThread.GetPage(TObject(Parse), + AppendURLDelim(FillHost(Module.RootURL, URL)) + IncStr(DownloadThread.workCounter), + Container.Manager.retryConnect) then + begin + ParseHTML(Parse.Text, Parse); + if Parse.Count > 0 then + begin + Result := True; + ScanParse; + end; + end; + finally + Parse.Free; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'PecintaKomik'; + RootURL := 'http://www.pecintakomik.com'; + SortedList := False; + InformationAvailable := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index f28661839..1be686352 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -6,422 +6,120 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, synautil; + synautil; implementation const - dirURL = '/directory/'; - -function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; - var Page: Integer; {%H-}Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - Page := 1; -end; + dirurl='/directory/'; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const {%H-}URL: String; - Module: TModuleContainer): Integer; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanParse; - var - i, j: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'section') and - (GetVal(Parse[i], 'class') = 'cols') then - begin - for j := i + 1 to Parse.Count - 1 do - if GetTagName(Parse[j]) = '/section' then - Break - else - if (GetTagName(Parse[j]) = 'a') and - (GetVal(Parse[j], 'class') = 'screenshot') then - begin - Links.Add(AppendURLDelim(GetVal(Parse[j], 'href'))); - Names.Add(CommonStringFilter(Parse[j + 1])); - end; - Break; - end; - end; - + query: TXQueryEngineHTML; + v: IXQValue; begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//section[@class="cols"]//div[@class="col-cnt"]/ul/li/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; + finally + query.Free; end; - finally - Parse.Free; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - s: String; - begin - for i := StartIndex + 1 to Parse.Count - 1 do - begin - s := GetTagName(Parse[i]); - if s = '/div' then - Break - else - if s = 'a' then - begin - info.chapterLinks.Add(AppendURLDelim(GetVal(Parse[i], 'href'))); - info.chapterName.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - - //invert chapters - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; - - procedure ScanInfo(const StartIndex: Integer); - var - i: Integer; - s: String; - begin - for i := StartIndex + 1 to Parse.Count - 1 do - begin - s := GetTagName(Parse[i]); - if s = '/div' then - Break - else - if s = 'li' then - begin - //authors - if Pos('Author(s):', Parse[i + 1]) = 1 then - info.authors := CommonStringFilter(SeparateRight(Parse[i + 1], - 'Author(s):')) - else - //artist - if Pos('Artist(s):', Parse[i + 1]) = 1 then - info.artists := CommonStringFilter(SeparateRight(Parse[i + 1], - 'Artist(s):')) - else - //genres - if Pos('Genre:', Parse[i + 1]) = 1 then - info.genres := CommonStringFilter(SeparateRight(Parse[i + 1], 'Genre:')) - else - //summary - if Pos('Sinopsis:', Parse[i + 1]) = 1 then - info.summary := CommonStringFilter(SeparateRight(Parse[i + 1], 'Sinopsis:')); - end; - end; - end; - - procedure ScanInfo2(const StartIndex: Integer); - var - i: Integer; - s: String; - begin - for i := StartIndex + 1 to Parse.Count - 1 do - begin - s := GetTagName(Parse[i]); - if s = '/div' then - Break - else - if s = 'li' then - begin - //authors - if Pos('Author(s):', Parse[i + 2]) = 1 then - info.authors := CommonStringFilter(Parse[i + 4]) - else - //artist - if Pos('Artist(s):', Parse[i + 2]) = 1 then - info.artists := CommonStringFilter(Parse[i + 4]) - else - //genres - if Pos('Genre:', Parse[i + 2]) = 1 then - info.genres := CommonStringFilter(Parse[i + 4]) - else - //summary - if Pos('Sinopsis:', Parse[i + 2]) = 1 then - info.summary := CommonStringFilter(Parse[i + 4]); - end; - end; - end; - - //broken layout - procedure ScanInfo3; - var - i, j: Integer; - begin - info.genres := ''; - info.summary := ''; - for i := 0 to Parse.Count - 1 do - begin - //cover - if info.coverLink = '' then - if (GetTagName(Parse[i]) = 'img') and - (GetVal(Parse[i], 'class') = 'pecintakomik') then - info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); - //title - if info.title = '' then - if GetVal(Parse[i], 'class') = 'aname' then - info.title := CommonStringFilter(Parse[i + 1]); - if GetVal(Parse[i], 'class') = 'propertytitle' then - begin - //author - if Pos('Autor:', Parse[i + 1]) = 1 then - info.authors := CommonStringFilter(Parse[i + 6]) - else - //artist - if Pos('Artist:', Parse[i + 1]) = 1 then - info.artists := CommonStringFilter(Parse[i + 6]); - //summary - if Pos('Ringkasan Cerita:', Parse[i + 1]) = 1 then - for j := i + 3 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/td' then - Break - else - if (Parse[j] <> '') and (Parse[j][1] <> '<') then - begin - if info.summary <> '' then - info.summary += LineEnding; - info.summary += CommonStringFilter(Parse[j]); - end; - end; - //genre - if GetVal(Parse[i], 'class') = 'genretags' then - AddCommaString(info.genres, CommonStringFilter(Parse[i + 1])); - end; - //chapters - if (GetTagName(Parse[i]) = 'ul') and - (GetVal(Parse[i], 'class') = 'series_alpha') then - begin - ScanChapters(i); - Break; - end; - end; - end; - - procedure ScanParse; - var - i, j: Integer; - begin - if Pos('/manga/', URL) = 0 then - begin - for i := 0 to Parse.Count - 1 do - begin - if GetVal(Parse[i], 'http-equiv') = 'x-ua-compatible' then - begin - ScanInfo3; - Break; + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//section[@class="post"]/img/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=query.XPathString('//div[@class="post-cnt"]/h2'); + for v in query.XPath('(//div[@class="post-cnt"])[1]/ul/li') do begin + s:=v.toString; + if Pos('Author(s):',s)=1 then authors:=SeparateRight(s,':') else + if Pos('Artist(s):',s)=1 then artists:=SeparateRight(s,':') else + if Pos('Genre:',s)=1 then genres:=SeparateRight(s,':') else + if Pos('Sinopsis:',s)=1 then summary:=SeparateRight(s,':'); end; - - //cover - if info.coverLink = '' then - if (GetTagName(Parse[i]) = 'img') and - (GetVal(Parse[i], 'class') = 'pecintakomik') then - info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); - - if GetVal(Parse[i], 'class') = 'post-cnt' then - if GetTagName(Parse[i + 2]) = 'h2' then - begin - //chapters - if Pos('List Chapter(s)', Parse[i + 3]) <> 0 then - begin - ScanChapters(i); - Break; - end - else - begin - //title - if info.title = '' then - info.title := CommonStringFilter(Parse[i + 3]); - //info - if (GetTagName(Parse[i + 8]) = 'li') and - (GetTagName(Parse[i + 9]) <> 'strong') then - ScanInfo(i) - else - ScanInfo2(i); - end; - end; - end; - end - else - //no info - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'name') = 'manga') then - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if (GetTagName(Parse[j]) = 'option') and - (GetVal(Parse[j], 'selected') = 'selected') then - begin - info.title := CommonStringFilter(Parse[j + 1]); - Break; - end; - end; - //chapters - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'name') = 'chapter') then - begin - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if GetTagName(Parse[j]) = 'option' then - begin - Inc(info.numChapter); - info.chapterLinks.Add(AppendURLDelim(URL) + IntToStr(info.numChapter)); - info.chapterName.Add('Chapter ' + IntToStr(info.numChapter)); - end; - end; - Break; + for v in query.XPath('(//div[@class="post-cnt"])[2]/ul/li/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(query.XPathString('text()',v.toNode)); end; - end; - end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; + InvertStrings([chapterLinks,chapterName]) + finally + query.Free; end; end; - finally - Parse.Free; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i, j: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'name') = 'page') then - begin - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if GetTagName(Parse[j]) = 'option' then - Inc(Container.PageNumber); - end; - Break; - end; - end; - + query: TXQueryEngineHTML; begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - FillHost(Module.RootURL, URL), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('//select[@name="page"]/option').Count; + finally + query.Free; end; end; - finally - Parse.Free; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - baseurl: String; - begin - baseurl := Module.RootURL; - for i := 0 to Parse.Count - 1 do - begin - if GetTagName(Parse[i]) = 'base' then - baseurl := GetVal(Parse[i], 'href'); - if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'picture') then - begin - if DownloadThread.workCounter < Container.PageLinks.Count then - Container.PageLinks[DownloadThread.workCounter] := - MaybeFillHost(baseurl, GetVal(Parse[i], 'src')); - Break; - end; - end; - end; - + query: TXQueryEngineHTML; + s: String; begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - AppendURLDelim(FillHost(Module.RootURL, URL)) + IncStr(DownloadThread.workCounter), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=RemoveURLDelim(AURL); + if DownloadThread.workCounter>0 then s+='/'+IncStr(DownloadThread.workCounter); + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + s:=query.XPathString('//img[@class="picture"]/@src'); + if s<>'' then + PageLinks[DownloadThread.workCounter]:=MaybeFillHost(Module.RootURL,s); + finally + query.Free; end; end; - finally - Parse.Free; end; end; @@ -429,15 +127,12 @@ procedure RegisterModule; begin with AddModule do begin - Website := 'PecintaKomik'; - RootURL := 'http://www.pecintakomik.com'; - SortedList := False; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; + Website:='PecintaKomik'; + RootURL:='http://www.pecintakomik.com'; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; end; end; From 5cf296abbbe07c6e13fedc699d13785c543c9c6f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jan 2016 16:47:00 +0800 Subject: [PATCH 0740/2794] pecintakomik, fix base url on image url fix #147 --- baseunits/modules/PecintaKomik.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 1be686352..5eec6c2aa 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -101,7 +101,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; - s: String; + s, b: String; begin Result:=False; if DownloadThread=nil then Exit; @@ -113,9 +113,10 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; query:=TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); + b:=query.XPathString('//base/@href'); + if b='' then b:=Module.RootURL; s:=query.XPathString('//img[@class="picture"]/@src'); - if s<>'' then - PageLinks[DownloadThread.workCounter]:=MaybeFillHost(Module.RootURL,s); + if s<>'' then PageLinks[DownloadThread.workCounter]:=MaybeFillHost(b,s); finally query.Free; end; From ec22b876dbf03d1a99879e774ed02e9ca14853a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Jan 2016 01:10:05 +0800 Subject: [PATCH 0741/2794] Bump version 0.9.29.0 --- changelog.txt | 9 +++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0ade2b4ef..7e0b886b6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,15 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.29.0 (10-01-2016) +[*] KissManga: rewrite all script +[*] RawSenManga: rewrite all script (load full chapter list via one of chapter link https://github.com/riderkick/FMD/issues/146) +[*] UnionMangas: rewrite all script +[-] Pururin: drop support +[+] MangaFox: added option to save as PNG on remove watermark +[*] PecintaKomik: rewrite all script +[*] Various changes and bug fixes + 0.9.28.0 (29-12-2015) [+] Added Manga folder custom rename. Options > Save to [*] Madokami: rewrite and add account support diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 284792303..8095ecf06 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="28"/> + <RevisionNr Value="29"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 9a6576613..145125e4f 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.28.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.28.0/fmd_0.9.28.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.28.0/fmd_0.9.28.0_Win64.7z +VERSION=0.9.29.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.29.0/fmd_0.9.29.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.29.0/fmd_0.9.29.0_Win64.7z From 5eec17191cbb77eaf77288b2d3587fb6081e8b7e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Jan 2016 01:50:25 +0800 Subject: [PATCH 0742/2794] fix empty user-agent if not defined in advanced.ini causing server to refuse the request, like login or cookie permit. --- mangadownloader/forms/frmMain.pas | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2793ba2a1..947b0c899 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -791,11 +791,15 @@ procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); end; procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); +var + s: String; begin if HTTP = nil then Exit; if Website = '' then Exit; - HTTP.UserAgent := INIAdvanced.ReadString('UserAgent', Website, ''); - HTTP.Cookies.Text := INIAdvanced.ReadString('Cookies', Website, ''); + s:=Trim(INIAdvanced.ReadString('UserAgent',Website,'')); + if s<>'' then HTTP.UserAgent:=s; + s:=Trim(INIAdvanced.ReadString('Cookies',Website,'')); + if s<>'' then HTTP.Cookies.Text:=s; end; { TSearchDBThread } From 776dce26afb39c0f496880ba314726048e34dacf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Jan 2016 02:01:22 +0800 Subject: [PATCH 0743/2794] Bump version 0.9.29.1 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7e0b886b6..c19c27dac 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,9 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.29.1 (11-01-2016) +[!*] Fix empty user-agent if it's not defined in advanced.ini (causing connection issue) + 0.9.29.0 (10-01-2016) [*] KissManga: rewrite all script [*] RawSenManga: rewrite all script (load full chapter list via one of chapter link https://github.com/riderkick/FMD/issues/146) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8095ecf06..9476580e8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="29"/> + <BuildNr Value="1"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> diff --git a/update b/update index 145125e4f..3cb0c8854 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.29.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.29.0/fmd_0.9.29.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.29.0/fmd_0.9.29.0_Win64.7z +VERSION=0.9.29.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.29.1/fmd_0.9.29.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.29.1/fmd_0.9.29.1_Win64.7z From e2ea6b3b73e29f299d736eaef437a4f0bd539f3b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 07:01:03 +0800 Subject: [PATCH 0744/2794] batoto, fix misc login behavior and add more log --- baseunits/modules/Batoto.pas | 46 ++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 4dd502462..ae10270b8 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, synautil, HTMLUtil, RegExpr; + accountmanagerdb, SimpleLogger, synautil, HTMLUtil, RegExpr; implementation @@ -41,6 +41,7 @@ function Login(var AHTTP: THTTPSendThread): Boolean; Account.Status[modulename] := asChecking; Reset; Cookies.Clear; + Writelog_V('Batoto, login: get login form'); if GET(urlroot) then begin loginform := THTMLForm.Create; query := TXQueryEngineHTML.Create; @@ -57,17 +58,25 @@ function Login(var AHTTP: THTTPSendThread): Boolean; end; Clear; Headers.Values['Referer'] := ' https://bato.to/'; + Writelog_V('Batoto, login: send authentification'); if POST(urllogin, loginform.GetData) then begin if ResultCode = 200 then begin Result := Cookies.Values['pass_hash'] <> ''; if Result then begin + Writelog_V('Batoto, login: success'); Account.Cookies[modulename] := GetCookies; Account.Status[modulename] := asValid; - end else + end else begin + Writelog_V('Batoto, login: failed, wrong user/password?'); Account.Status[modulename] := asInvalid; + end; Account.Save; - end; - end; + end + else + Writelog_V(['Batoto, login: failed, unexpected server reply: ',ResultCode,' ',ResultString]); + end + else + Writelog_V('Batoto, login: connection failed'); end; finally query.Free; @@ -90,19 +99,26 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; var s: String; begin - Result := False; - AHTTP.Cookies.Text := Account.Cookies['Batoto']; - if AHTTP.GET(AURL) then begin - Result := True; - if (Account.Enabled[modulename] = False) or (Account.Username[modulename] = '') then Exit; - s := StreamToString(AHTTP.Document); + Result:=False; + AHTTP.Cookies.Text:=Account.Cookies['Batoto']; + Result:=AHTTP.GET(AURL); + if Result then begin + Result:=True; + if Account.Enabled[modulename]=False then Exit; + if Account.Username[modulename]='' then Exit; + if Account.Status[modulename]=asInvalid then Exit; + s:=StreamToString(AHTTP.Document); Result := (Pos('class=''logged_in''', s) > 0) or (Pos('class="logged_in"', s) > 0); - if not Result then - if Login(AHTTP) then - Result := AHTTP.GET(AURL); if not Result then begin - AHTTP.Document.Clear; - WriteStrToStream(AHTTP.Document, s); + Result:=Login(AHTTP); + if Result then + Result:=AHTTP.GET(AURL) + else + begin + Result:=True; + AHTTP.Document.Clear; + WriteStrToStream(AHTTP.Document, s); + end; end; end; end; From f2bee123c2e3f554dc6e89cba9adc61a41920d52 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 07:19:12 +0800 Subject: [PATCH 0745/2794] add pid and handle in log --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 947b0c899..8feab36e2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -949,7 +949,7 @@ procedure TMainForm.FormCreate(Sender: TObject); fmdDirectory := CleanAndExpandDirectory(GetCurrentDirUTF8); SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), FormatDateTime('dd-mm-yyyy', Now)])); - Writelog_I('Starting ' + AnsiQuotedStr(Application.Title, '"')); + Writelog_I(['Starting ',QuotedStrd(Application.Title),' [PID:',GetProcessID,' HANDLE:',IntToStr(GetCurrentProcess),']']); InitSimpleExceptionHandler; AddIgnoredException('EImagingError'); AddIgnoredException('ERegExpr'); @@ -1202,7 +1202,7 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(updates); FreeAndNil(options); FreeAndNil(INIAdvanced); - Writelog_I(AnsiQuotedStr(Application.Title, '"') + ' exit normally'); + Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+' HANDLE:'+IntToStr(GetCurrentProcess)+']'); end; procedure TMainForm.FormShow(Sender: TObject); From 32396091f818207a8e1872fdc5a205aceaa167ea Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 07:55:56 +0800 Subject: [PATCH 0746/2794] batoto, rewrite update list script --- baseunits/modules/Batoto.pas | 117 ++++++++++------------------------- 1 file changed, 34 insertions(+), 83 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index ae10270b8..3eaf20801 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -126,101 +126,52 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - s: String; - begin - if Parse.Count > 0 then - for i := 0 to Parse.Count - 1 do - if (Pos('Page 1 of ', Parse.Strings[i]) > 0) then - begin - s := GetString(Parse.Strings[i] + '~!@', 'Page 1 of ', '~!@'); - Page := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - + query: TXQueryEngineHTML; + s: String; begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; - try - MangaInfo.FHTTP.Cookies.Text := Account.Cookies[modulename]; - if MangaInfo.GetPage(TObject(Parse), - Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + - dirparam + IntToStr(perpage), 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; + Result:=NET_PROBLEM; + Page:=1; + if MangaInfo =nil then Exit(UNKNOWN_ERROR); + MangaInfo.FHTTP.Cookies.Text:=Account.Cookies[modulename]; + if MangaInfo.FHTTP.GET(Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=Trim(query.XPathString('//ul[@class="ipsList_inline left pages"]/li/a')); + if s<>'' then + Page:=StrToIntDef(Trim(SeparateRight(LowerCase(s),'page 1 of ')),1); + finally + query.Free; end; - finally - Parse.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; var - Parse: TStringList; + query: TXQueryEngineHTML; + v: IXQValue; s: String; - p: Integer; - - procedure ScanParse; - var - i, j: Integer; - begin - j := -1; - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'table') and - (GetVal(Parse[i], 'class') = 'ipb_table topic_list hover_rows') then - begin - j := i; - Break; - end; - if (j > -1) and (j < Parse.Count) then - for i := j to Parse.Count - 1 do - if Pos('</table', Parse[i]) <> 0 then - Break - else - if GetTagName(Parse[i]) = 'a' then - begin - ALinks.Add(GetVal(Parse[i], 'href')); - ANames.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + - dirparam + IntToStr(perpage); - p := StrToIntDef(AURL, 0); - if p > 0 then - s += '&st=' + (IntToStr(p * perpage)); - Parse := TStringList.Create; - try - MangaInfo.FHTTP.Cookies.Text := Account.Cookies[modulename]; - if MangaInfo.GetPage(TObject(Parse), s, 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage); + if AURL<>'0' then s+='&st='+IntToStr(StrToInt(AURL)*perpage); + MangaInfo.FHTTP.Cookies.Text:=Account.Cookies[modulename]; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@class="ipb_table topic_list hover_rows"]/tbody/tr/td/h4/a') do begin + WriteLog_D('name: '+v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; + finally + query.Free; end; - finally - Parse.Free; end; end; From 98099a860c12ce51c979a1ab8d850579e3e85fb3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:00:27 +0800 Subject: [PATCH 0747/2794] batoto, clean up --- baseunits/modules/Batoto.pas | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 3eaf20801..02467af46 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -244,7 +244,6 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - source: TStringList; query: TXQueryEngineHTML; v: IXQValue; cid: String; @@ -257,11 +256,9 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; cid := SeparateRight(AURL, '/reader#'); if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin Result := True; - source := TStringList.Create; query := TXQueryEngineHTML.Create; try - source.LoadFromStream(Document); - query.ParseHTML(source.Text); + query.ParseHTML(StreamToString(Document)); PageContainerLinks.Text := cid; if query.XPathString('//select[@id="page_select"]') <> '' then PageNumber := Query.XPath('//div[1]/ul/li/select[@id="page_select"]/option/@value').Count @@ -273,7 +270,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; finally query.Free; - source.Free; end; end; end; @@ -282,7 +278,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - source: TStringList; query: TXQueryEngineHTML; rurl: String; begin @@ -295,15 +290,12 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; if GET(rurl) then begin Result := True; - source := TStringList.Create; query := TXQueryEngineHTML.Create; try - source.LoadFromStream(Document); - query.ParseHTML(source.Text); + query.ParseHTML(StreamToString(Document)); PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@id="full_image"]//img/@src'); finally query.Free; - source.Free; end; end; end; From 45852bb6a9e481feca03f66ec5850fe02675e29c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:09:58 +0800 Subject: [PATCH 0748/2794] batoto, increase perpage of update list to 1000 --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 02467af46..1842787a7 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -17,7 +17,7 @@ implementation dirurls: array [0..1] of String = ( '/comic/_/sp/', '/comic/_/comics/'); - perpage = 50; + perpage = 1000; dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; var From 85c1368bce2eb27f672c2015a65a166edbb3595f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:10:36 +0800 Subject: [PATCH 0749/2794] batoto, clean up --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 1842787a7..a5debe36e 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, SimpleLogger, synautil, HTMLUtil, RegExpr; + accountmanagerdb, SimpleLogger, synautil; implementation From a1ea2e664eda6e0b8e238b726f56241fa085b024 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:24:05 +0800 Subject: [PATCH 0750/2794] add more log on updatemanagerthread --- baseunits/uUpdateThread.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 43bcc39a0..5fc8c8dfa 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -562,6 +562,8 @@ procedure TUpdateMangaManagerThread.Execute; SortedList := SitesWithSortedList(website); NoMangaInfo := SitesWithoutInformation(website); Inc(websitePtr); + WriteLog_V('UpdateManagerThread, '+website+': sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); + WriteLog_V('UpdateManagerThread, '+website+': prepare database file'); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); @@ -585,6 +587,7 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.InitLocateLink; mainDataProcess.CloseTable; + WriteLog_V('UpdateManagerThread, '+website+': get number of directory page'); // get directory page count INIAdvanced.Reload; directoryCount := 0; @@ -593,6 +596,7 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; + WriteLog_V('UpdateManagerThread, '+website+': get names and links'); // get names and links INIAdvanced.Reload; workPtr := 0; @@ -631,6 +635,7 @@ procedure TUpdateMangaManagerThread.Execute; tempDataProcess.OpenTable('', True); + WriteLog_V('UpdateManagerThread, '+website+': removing duplicate '+IntToStr(tempDataProcess.RecordCount)); // remove duplicate found<>current database if (mainDataProcess.LinkCount>0) and (tempDataProcess.RecordCount>0) then begin MainForm.ulTotalPtr:=tempDataProcess.RecordCount; @@ -661,6 +666,7 @@ procedure TUpdateMangaManagerThread.Execute; tempDataProcess.Refresh(True); mainDataProcess.DoneLocateLink; + WriteLog_V('UpdateManagerThread, '+website+': get info '+IntToStr(tempDataProcess.RecordCount)); // get manga info if tempDataProcess.RecordCount>0 then begin @@ -693,15 +699,19 @@ procedure TUpdateMangaManagerThread.Execute; if workPtr > 0 then if not (Terminated and SortedList) then begin + WriteLog_V('UpdateManagerThread, '+website+': saving data'); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); mainDataProcess.Sort; mainDataProcess.Close; Synchronize(RefreshList); - end; + end + else + WriteLog_V('UpdateManagerThread, '+website+': sorted list, data abandoned'); end; + WriteLog_V('UpdateManagerThread, '+website+': close database file'); mainDataProcess.Close; DeleteDBDataProcess(twebsite); From a145208d222fad2f53c760234eba79c3bf6fcd08 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:28:34 +0800 Subject: [PATCH 0751/2794] batoto, cleanup --- baseunits/modules/Batoto.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index a5debe36e..d76f62f88 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -165,7 +165,6 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//table[@class="ipb_table topic_list hover_rows"]/tbody/tr/td/h4/a') do begin - WriteLog_D('name: '+v.toString); ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end; From 98299e006a640b1ab90548fe5e04f3a5b0acb0e8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:30:40 +0800 Subject: [PATCH 0752/2794] updatemanager, fix clean temp database on each website --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 5fc8c8dfa..2cea2c68f 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -554,9 +554,9 @@ procedure TUpdateMangaManagerThread.Execute; end; end else - tempDataProcess.CreateDatabase('__tempupdatelist'); while websitePtr < websites.Count do begin + tempDataProcess.CreateDatabase('__tempupdatelist'); website := websites.Strings[websitePtr]; ModuleId := Modules.LocateModule(website); SortedList := SitesWithSortedList(website); From d333ba147a3a0e4253afd466bb3e1bf35220ba96 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 08:34:34 +0800 Subject: [PATCH 0753/2794] updatemanager, reduce refresh rate --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 2cea2c68f..a7e77d44f 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -650,7 +650,7 @@ procedure TUpdateMangaManagerThread.Execute; if Terminated then Break; Inc(c); Inc(MainForm.ulWorkPtr); - if c>750 then begin + if c>250 then begin c:=0; Synchronize(MainThreadStatusRepaint); end; From f7dd66de2d2698b85bb85c26618831b5f4783d4a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 09:00:38 +0800 Subject: [PATCH 0754/2794] downloadmanager, don't show exit counter if update list running --- baseunits/uDownloadsManager.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 738fb2b1d..77c317b82 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2210,6 +2210,7 @@ procedure TDownloadManager.RemoveAllFinishedTasks; procedure TDownloadManager.doExitWaitCounter; begin + if MainForm.isUpdating then Exit; frmMain.DoAfterFMD := OptionLetFMDDo; MainForm.itMonitor.Enabled := True; end; From a234f01d986a2c2b40d7fa526e8653cf2fdf907f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 09:21:32 +0800 Subject: [PATCH 0755/2794] downloadmanager, updatemanager, do pending exit counter --- baseunits/uDownloadsManager.pas | 15 ++++----------- baseunits/uUpdateThread.pas | 2 ++ mangadownloader/forms/frmMain.pas | 11 ++++++++++- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 77c317b82..b74e668fb 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -214,8 +214,6 @@ TDownloadManager = class procedure RemoveTask(const taskID : Integer); // Remove all finished tasks. procedure RemoveAllFinishedTasks; - // show exit counter - procedure doExitWaitCounter; // check status of task function TaskStatusPresent(Stats: TDownloadStatusTypes): Boolean; @@ -2044,8 +2042,10 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); begin MainForm.itRefreshDLInfo.Enabled := False; MainForm.UpdateVtDownload; - if isCheckForFMDDo then - doExitWaitCounter; + if isCheckForFMDDo then begin + frmMain.DoAfterFMD := OptionLetFMDDo; + MainForm.DoExitWaitCounter; + end; end; except on E: Exception do @@ -2208,13 +2208,6 @@ procedure TDownloadManager.RemoveAllFinishedTasks; end; end; -procedure TDownloadManager.doExitWaitCounter; -begin - if MainForm.isUpdating then Exit; - frmMain.DoAfterFMD := OptionLetFMDDo; - MainForm.itMonitor.Enabled := True; -end; - function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolean; var i: Integer; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index a7e77d44f..721959346 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -291,6 +291,8 @@ procedure TUpdateMangaManagerThread.MainThreadEndGetting; mainForm.sbUpdateList.Panels[0].Style := psText; MainForm.sbUpdateList.Hide; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; + MainForm.isUpdating:=False; + if MainForm.isPendingExitCounter then MainForm.DoExitWaitCounter; end; procedure TUpdateMangaManagerThread.MainThreadRemoveFilter; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8feab36e2..6f4934e01 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -555,7 +555,7 @@ TMainForm = class(TForm) ulTotalPtr, ulWorkPtr: Integer; optionMangaSiteSelectionNodes: array of PVirtualNode; LastSearchStr, LastSearchWeb: String; - isStartup, isExiting, isRunDownloadFilter, isUpdating: Boolean; + isStartup, isExiting, isRunDownloadFilter, isUpdating, isPendingExitCounter: Boolean; revisionIni, updates, mangalistIni, options: TIniFile; FavoriteManager: TFavoriteManager; dataProcess: TDBDataProcess; @@ -645,6 +645,7 @@ TMainForm = class(TForm) procedure TransferRateGraphAddItem(TransferRate: Integer); // exit counter + procedure DoExitWaitCounter; function ShowExitCounter: Boolean; // open db with thread @@ -958,6 +959,7 @@ procedure TMainForm.FormCreate(Sender: TObject); isUpdating := False; isExiting := False; isGetMangaInfos := False; + isPendingExitCounter:=False; DoAfterFMD := DO_NOTHING; Application.HintHidePause := 10000; sbUpdateList.DoubleBuffered := True; @@ -1271,6 +1273,7 @@ function TMainForm.ShowExitCounter: Boolean; finally Free; end; + isPendingExitCounter:=False; IsDlgCounter := False; end; @@ -5076,6 +5079,12 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); end; end; +procedure TMainForm.DoExitWaitCounter; +begin + if isUpdating then isPendingExitCounter:=True + else itMonitor.Enabled:=True; +end; + procedure TMainForm.ExceptionHandler(Sender: TObject; E: Exception); begin SimpleException.ExceptionHandle(Sender, E); From 0cc07a940f21ac2a995e31d5b644192c1c7539a3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 10:36:27 +0800 Subject: [PATCH 0756/2794] typo log --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6f4934e01..ef909e502 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -950,7 +950,7 @@ procedure TMainForm.FormCreate(Sender: TObject); fmdDirectory := CleanAndExpandDirectory(GetCurrentDirUTF8); SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), FormatDateTime('dd-mm-yyyy', Now)])); - Writelog_I(['Starting ',QuotedStrd(Application.Title),' [PID:',GetProcessID,' HANDLE:',IntToStr(GetCurrentProcess),']']); + Writelog_I(['Starting ',QuotedStrd(Application.Title),' [PID:',GetProcessID,'] [HANDLE:',IntToStr(GetCurrentProcess),']']); InitSimpleExceptionHandler; AddIgnoredException('EImagingError'); AddIgnoredException('ERegExpr'); @@ -1204,7 +1204,7 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(updates); FreeAndNil(options); FreeAndNil(INIAdvanced); - Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+' HANDLE:'+IntToStr(GetCurrentProcess)+']'); + Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); end; procedure TMainForm.FormShow(Sender: TObject); From e30dfb8137fe41b3f48f7d48b1aa6cfb63634b2f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 12:07:25 +0800 Subject: [PATCH 0757/2794] updatemanager, increase refresh rate to 5000 --- baseunits/uUpdateThread.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 721959346..26fb62520 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -652,7 +652,7 @@ procedure TUpdateMangaManagerThread.Execute; if Terminated then Break; Inc(c); Inc(MainForm.ulWorkPtr); - if c>250 then begin + if c>500 then begin c:=0; Synchronize(MainThreadStatusRepaint); end; @@ -697,6 +697,7 @@ procedure TUpdateMangaManagerThread.Execute; else GetInfo(tempDataProcess.RecordCount, CS_INFO); mainDataProcess.Commit; + WriteLog_V('UpdateManagerThread, '+website+': get info finished '+IntToStr(workPtr)); if workPtr > 0 then if not (Terminated and SortedList) then From 875a125927efaba4b16068da3cc6c43950bb1217 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 12:12:07 +0800 Subject: [PATCH 0758/2794] more log --- baseunits/uUpdateThread.pas | 7 +++++-- mangadownloader/forms/frmMain.pas | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 26fb62520..527233bc6 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -292,7 +292,10 @@ procedure TUpdateMangaManagerThread.MainThreadEndGetting; MainForm.sbUpdateList.Hide; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; MainForm.isUpdating:=False; - if MainForm.isPendingExitCounter then MainForm.DoExitWaitCounter; + if MainForm.isPendingExitCounter then begin + WriteLog_V('UpdateManagerThread, pending exit counter executed'); + MainForm.DoExitWaitCounter; + end; end; procedure TUpdateMangaManagerThread.MainThreadRemoveFilter; @@ -702,7 +705,7 @@ procedure TUpdateMangaManagerThread.Execute; if workPtr > 0 then if not (Terminated and SortedList) then begin - WriteLog_V('UpdateManagerThread, '+website+': saving data'); + WriteLog_V('UpdateManagerThread, '+website+': saving data '+IntToStr(workPtr)); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ef909e502..9bfa643b5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5081,7 +5081,11 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); procedure TMainForm.DoExitWaitCounter; begin - if isUpdating then isPendingExitCounter:=True + Writelog_V('Execute exit counter'); + if isUpdating then begin + Writelog_V('Update thread still exist, pending exit counter'); + isPendingExitCounter:=True + end else itMonitor.Enabled:=True; end; From c4e17b42fa783486e7b1c3654538c5551b851f7b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 14:05:01 +0800 Subject: [PATCH 0759/2794] kissmanga, fix update url --- baseunits/modules/KissManga.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index a19db477a..a37462f0c 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -10,6 +10,9 @@ interface implementation +const + dirurl='/MangaList/Newest'; + var kissmangacookies: String=''; lockget: TRTLCriticalSection; @@ -43,7 +46,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+'/MangaList/Newest') then begin + if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+dirurl) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try @@ -68,7 +71,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+'/Mangalist/Newest'; + s:=Module.RootURL+dirurl; if AURL<>'0' then s:=s+'?page='+IncStr(AURL); if GETWithCookie(MangaInfo.FHTTP,s) then begin From fd75360170b9825b5be4a60121ea3a25df07843e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 14:29:18 +0800 Subject: [PATCH 0760/2794] dataprocess, added rollback and change addata to function: boolean --- baseunits/uData.pas | 74 +++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fa78a3fd9..cd2958472 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -92,13 +92,14 @@ TDBDataProcess = class(TObject) procedure Save; procedure Backup(AWebsite: String); procedure Refresh(RecheckDataCount: Boolean = False); - procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter, JDN: Integer); overload; - procedure AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer; JDN: TDateTime); overload; + function AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter, JDN: Integer): Boolean; overload; + function AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter: Integer; JDN: TDateTime): Boolean; overload; procedure UpdateData(Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String = ''); procedure Commit; + procedure Rollback; procedure RemoveFilter; procedure Sort; @@ -860,38 +861,36 @@ procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); end; end; -procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, - Status, Summary: String; NumChapter, JDN: Integer); -var - s: String; +function TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, + Summary: String; NumChapter, JDN: Integer): Boolean; begin - if FConn.Connected then - try - FConn.ExecuteDirect( - 'INSERT OR IGNORE INTO ' + QuotedStrd(FTableName) + - #13#10'(' + DBDataProcessParam + ')' + - #13#10'VALUES' + - #13#10'('#13#10 + - QuotedStrd(Title) + ','#13#10 + - QuotedStrd(Link) + ','#13#10 + - QuotedStrd(Authors) + ','#13#10 + - QuotedStrd(Artists) + ','#13#10 + - QuotedStrd(Genres) + ','#13#10 + - QuotedStrd(Status) + ','#13#10 + - QuotedStrd(Summary) + ','#13#10 + - QuotedStrd(IntToStr(NumChapter)) + ','#13#10 + - QuotedStrd(IntToStr(JDN)) + - #13#10');'); - except - on E: Exception do - WriteLog_E('TDBDataProcess.AddData.Error!', E, Self); - end; + if FConn.Connected=False then Exit(False); + try + FConn.ExecuteDirect( + 'INSERT OR ABORT INTO ' + QuotedStrd(FTableName) + + #13#10'(' + DBDataProcessParam + ')' + + #13#10'VALUES' + + #13#10'('#13#10 + + QuotedStrd(Title) + ','#13#10 + + QuotedStrd(Link) + ','#13#10 + + QuotedStrd(Authors) + ','#13#10 + + QuotedStrd(Artists) + ','#13#10 + + QuotedStrd(Genres) + ','#13#10 + + QuotedStrd(Status) + ','#13#10 + + QuotedStrd(Summary) + ','#13#10 + + QuotedStrd(IntToStr(NumChapter)) + ','#13#10 + + QuotedStrd(IntToStr(JDN)) + + #13#10');'); + Result:=True; + except + Result:=False; + end; end; -procedure TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, - Status, Summary: String; NumChapter: Integer; JDN: TDateTime); +function TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, + Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; begin - AddData(Title, Link, Authors, Artists, Genres, Status, Summary, + Result := AddData(Title, Link, Authors, Artists, Genres, Status, Summary, NumChapter, DateToJDN(JDN)); end; @@ -952,6 +951,17 @@ procedure TDBDataProcess.Commit; end; end; +procedure TDBDataProcess.Rollback; +begin + if FConn.Connected then + try + FTrans.RollbackRetaining; + except + on E: Exception do + WriteLog_E('TDBDataProcess.Rollback.Error!', E, Self); + end; +end; + function TDBDataProcess.Search(ATitle: String): Boolean; var i: Integer; From fa8d788745ef6d9c7f4b7ced0f803b0f77121def Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 14:44:34 +0800 Subject: [PATCH 0761/2794] dataprocess, add more log --- baseunits/uData.pas | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index cd2958472..9d0a09cfb 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -466,7 +466,7 @@ procedure TDBDataProcess.VacuumTable; ExecuteDirect('VACUUM'); except on E: Exception do - WriteLog_E('TDBDataProcess.VacuumTable.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].VacuumTable.Error!', E, Self); end; ExecuteDirect('BEGIN TRANSACTION'); end; @@ -546,7 +546,7 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; except on E: Exception do begin - WriteLog_E('TDBDataProcess.InternalOpen.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].InternalOpen.Error!', E, Self); Result := False; end; end; @@ -562,7 +562,7 @@ function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; Result := FQuery.FieldByName('website').AsString; except on E: Exception do - WriteLog_E('TDBDataProcess.GetWebsiteName', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].GetWebsiteName', E, Self); end; end; @@ -580,7 +580,7 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; except on E: Exception do - WriteLog_E('TDBDataProcess.GetParam.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].GetParam.Error!', E, Self); end; end; @@ -618,7 +618,7 @@ procedure TDBDataProcess.AttachAllSites; end; except on E: Exception do - Writelog_E('TDBDataProcess.AttachAllSites.Error!', E, Self) + Writelog_E('TDBDataProcess['+Website+'].AttachAllSites.Error!', E, Self) end; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := FAttachedSites.Count > 0; @@ -640,7 +640,7 @@ procedure TDBDataProcess.DetachAllSites; FAttachedSites.Delete(i); except on E: Exception do - Writelog_E('TDBDataProcess.DetachAllSites.Error!', E, Self); + Writelog_E('TDBDataProcess['+Website+'].DetachAllSites.Error!', E, Self); end; end; FConn.ExecuteDirect('BEGIN TRANSACTION'); @@ -657,7 +657,7 @@ function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; Result := True; except on E: Exception do - WriteLog_E('TDBDataProcess.ExecuteDirect.Error!'#13#10 + + WriteLog_E('TDBDataProcess['+Website+'].ExecuteDirect.Error!'#13#10 + 'SQL: ' + SQL, E, Self); end; end; @@ -697,7 +697,7 @@ destructor TDBDataProcess.Destroy; end; except on E: Exception do - WriteLog_E('TDBDataProcess.Destroy.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].Destroy.Error!', E, Self); end; DoneLocateLink; FAttachedSites.Free; @@ -749,7 +749,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; Result := FQuery.Active; except on E: Exception do - WriteLog_E('TDBDataProcess.Open.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].Open.Error!', E, Self); end; end; @@ -776,7 +776,7 @@ function TDBDataProcess.OpenTable(const ATableName: String; end; except on E: Exception do - WriteLog_E('TDBDataProcess.OpenTable.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].OpenTable.Error!', E, Self); end; end; Result := FQuery.Active; @@ -813,7 +813,7 @@ procedure TDBDataProcess.Close; FConn.DatabaseName := ''; except on E: Exception do - WriteLog_E('TDBDataProcess.Close.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].Close.Error!', E, Self); end; end; @@ -929,7 +929,7 @@ procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, FConn.ExecuteDirect(sql); except on E: Exception do - WriteLog_E('TDBDataProcess.UpdateData.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].UpdateData.Error!', E, Self); end; end; end; @@ -940,6 +940,7 @@ procedure TDBDataProcess.Commit; begin if FConn.Connected then try + WriteLog_V('TDBDataProcess['+Website+'].Commit'); queryactive := FQuery.Active; if FQuery.Active then FQuery.Close; FTrans.Commit; @@ -947,7 +948,7 @@ procedure TDBDataProcess.Commit; FQuery.Active := queryactive; except on E: Exception do - WriteLog_E('TDBDataProcess.Commit.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].Commit.Error!',E,Self); end; end; @@ -955,10 +956,12 @@ procedure TDBDataProcess.Rollback; begin if FConn.Connected then try - FTrans.RollbackRetaining; + WriteLog_V('TDBDataProcess['+Website+'].Rollback'); + FTrans.Rollback; + FTrans.EndTransaction; except on E: Exception do - WriteLog_E('TDBDataProcess.Rollback.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].Rollback.Error!',E,Self); end; end; @@ -1010,7 +1013,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; GetRecordCount; except on E: Exception do - WriteLog_E('TDBDataProcess.Search.Error!'#13#10 + + WriteLog_E('TDBDataProcess['+Website+'].Search.Error!'#13#10 + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); end; end; @@ -1155,7 +1158,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList except on E: Exception do begin - WriteLog_E('TDBDataProcess.Filter.Error!'#13#10 + + WriteLog_E('TDBDataProcess['+Website+'].Filter.Error!'#13#10 + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); FQuery.Close; SQL.Text := tsql; @@ -1244,7 +1247,7 @@ procedure TDBDataProcess.Sort; VacuumTable; except on E: Exception do - WriteLog_E('TDBDataProcess.Sort.Error!', E, Self); + WriteLog_E('TDBDataProcess['+Website+'].Sort.Error!', E, Self); end; if FQuery.Active <> queryactive then FQuery.Active := queryactive; From 256fe16dcc9c355ad82d46866bda15c747df4e33 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 15:52:58 +0800 Subject: [PATCH 0762/2794] dataprocess, ignore if failed --- baseunits/uData.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9d0a09cfb..9a96e4cf8 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -867,7 +867,7 @@ function TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, if FConn.Connected=False then Exit(False); try FConn.ExecuteDirect( - 'INSERT OR ABORT INTO ' + QuotedStrd(FTableName) + + 'INSERT OR IGNORE INTO ' + QuotedStrd(FTableName) + #13#10'(' + DBDataProcessParam + ')' + #13#10'VALUES' + #13#10'('#13#10 + @@ -958,7 +958,6 @@ procedure TDBDataProcess.Rollback; try WriteLog_V('TDBDataProcess['+Website+'].Rollback'); FTrans.Rollback; - FTrans.EndTransaction; except on E: Exception do WriteLog_E('TDBDataProcess['+Website+'].Rollback.Error!',E,Self); From fc2e3e76fd260d53ce9f7f724bd4ff0f76140516 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Jan 2016 15:53:35 +0800 Subject: [PATCH 0763/2794] updatemanager, remove duplicate directly after getting list --- baseunits/uUpdateThread.pas | 61 +++++++++++++------------------------ 1 file changed, 21 insertions(+), 40 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 527233bc6..3a0ffe2b2 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -201,9 +201,19 @@ procedure TUpdateMangaThread.Execute; manager.CS_AddNamesAndLinks.Acquire; try - for i := 0 to links.Count - 1 do - manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); - manager.tempDataProcess.Commit; + i:=0; + while i<links.Count do begin + if manager.mainDataProcess.LinkExist(links[i]) then begin + links.Delete(i); + names.Delete(i); + end + else Inc(i); + end; + if links.Count>0 then begin + for i:=0 to links.Count-1 do + manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); + manager.tempDataProcess.Commit; + end; finally manager.CS_AddNamesAndLinks.Release; end; @@ -588,10 +598,6 @@ procedure TUpdateMangaManagerThread.Execute; if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); - mainDataProcess.OpenTable; - mainDataProcess.InitLocateLink; - mainDataProcess.CloseTable; - WriteLog_V('UpdateManagerThread, '+website+': get number of directory page'); // get directory page count INIAdvanced.Reload; @@ -601,6 +607,10 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; + mainDataProcess.OpenTable; + mainDataProcess.InitLocateLink; + mainDataProcess.CloseTable; + WriteLog_V('UpdateManagerThread, '+website+': get names and links'); // get names and links INIAdvanced.Reload; @@ -632,45 +642,16 @@ procedure TUpdateMangaManagerThread.Execute; end else GetInfo(directoryCount, CS_DIRECTORY_PAGE); + mainDataProcess.DoneLocateLink; + if Terminated then Break; + tempDataProcess.OpenTable('', True); + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; Synchronize(MainThreadShowGetting); - tempDataProcess.OpenTable('', True); - - WriteLog_V('UpdateManagerThread, '+website+': removing duplicate '+IntToStr(tempDataProcess.RecordCount)); - // remove duplicate found<>current database - if (mainDataProcess.LinkCount>0) and (tempDataProcess.RecordCount>0) then begin - MainForm.ulTotalPtr:=tempDataProcess.RecordCount; - MainForm.ulWorkPtr:=0; - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_RemovingDuplicateFromCurrentData + '...'; - Synchronize(MainThreadShowGetting); - with tempDataProcess.Table do begin - c:=0; - First; - while not tempDataProcess.Table.EOF do begin - if Terminated then Break; - Inc(c); - Inc(MainForm.ulWorkPtr); - if c>500 then begin - c:=0; - Synchronize(MainThreadStatusRepaint); - end; - if mainDataProcess.LinkExist(Fields[1].AsString) then - Delete - else - Next; - end; - ApplyUpdates; - end; - end; - - tempDataProcess.Refresh(True); - mainDataProcess.DoneLocateLink; - WriteLog_V('UpdateManagerThread, '+website+': get info '+IntToStr(tempDataProcess.RecordCount)); // get manga info if tempDataProcess.RecordCount>0 then From f04705ea15d531978c106d6499786d6e573a08d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 03:31:59 +0800 Subject: [PATCH 0764/2794] updatemanager, reload iniadvance --- baseunits/uUpdateThread.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 3a0ffe2b2..c228c9130 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -440,6 +440,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; begin MainForm.ulTotalPtr := limit; try + INIAdvanced.Reload; while (not Terminated) and (workPtr < limit) do begin mt := INIAdvanced.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then @@ -516,6 +517,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; FStatus := s; MainForm.ulWorkPtr := workPtr + 1; Synchronize(MainThreadShowGetting); + INIAdvanced.Reload; finally UnlockCreateConnection; end; From 9d0ffed043c8a8534b15a87c73751f7ae7f2b4e7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 03:35:02 +0800 Subject: [PATCH 0765/2794] batoto, load all page with login --- baseunits/modules/Batoto.pas | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index d76f62f88..68462f929 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -132,8 +132,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result:=NET_PROBLEM; Page:=1; if MangaInfo =nil then Exit(UNKNOWN_ERROR); - MangaInfo.FHTTP.Cookies.Text:=Account.Cookies[modulename]; - if MangaInfo.FHTTP.GET(Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin + if GETWithLogin(MangaInfo.FHTTP,Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin Result:=NO_ERROR; query:=TXQueryEngineHTML.Create; try @@ -158,8 +157,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if MangaInfo=nil then Exit(UNKNOWN_ERROR); s:=Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage); if AURL<>'0' then s+='&st='+IntToStr(StrToInt(AURL)*perpage); - MangaInfo.FHTTP.Cookies.Text:=Account.Cookies[modulename]; - if MangaInfo.FHTTP.GET(s) then begin + if GETWithLogin(MangaInfo.FHTTP,s) then begin Result:=NO_ERROR; query:=TXQueryEngineHTML.Create; try @@ -188,7 +186,6 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; mangaInfo.website := modulename; mangaInfo.url := FillHost(urlroot, AURL); while onlogin do Sleep(1000); - FHTTP.Cookies.Text := Account.Cookies[modulename]; if GETWithLogin(FHTTP, mangaInfo.url) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; @@ -250,10 +247,9 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.manager.container, DownloadThread.FHTTP do begin - Cookies.Text := Account.Cookies[modulename]; Headers.Values['Referer'] := ' ' + urlroot + '/reader'; cid := SeparateRight(AURL, '/reader#'); - if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin + if GETWithLogin(DownloadThread.FHTTP,urlroot + '/areader?id=' + cid + '&p=1') then begin Result := True; query := TXQueryEngineHTML.Create; try @@ -284,10 +280,9 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; if DownloadThread = nil then Exit; with DownloadThread.manager.container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; - Cookies.Text := Account.Cookies[modulename]; rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + IntToStr(DownloadThread.WorkCounter + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; - if GET(rurl) then begin + if GETWithLogin(DownloadThread.FHTTP,rurl) then begin Result := True; query := TXQueryEngineHTML.Create; try @@ -307,7 +302,7 @@ procedure RegisterModule; Website := modulename; RootURL := urlroot; MaxTaskLimit := 1; - MaxConnectionLimit := 2; + MaxConnectionLimit := 1; AccountSupport := True; SortedList := True; InformationAvailable := True; From 78e0166f31706e6a9032ec92178c6546f1b7a41a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 04:57:41 +0800 Subject: [PATCH 0766/2794] batoto, connection always close, max=2 --- baseunits/modules/Batoto.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 68462f929..d6eafacbb 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, SimpleLogger, synautil; + accountmanagerdb, dateutils, SimpleLogger, synautil; implementation @@ -101,6 +101,7 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; begin Result:=False; AHTTP.Cookies.Text:=Account.Cookies['Batoto']; + AHTTP.KeepAlive:=False; Result:=AHTTP.GET(AURL); if Result then begin Result:=True; @@ -302,7 +303,7 @@ procedure RegisterModule; Website := modulename; RootURL := urlroot; MaxTaskLimit := 1; - MaxConnectionLimit := 1; + MaxConnectionLimit := 2; AccountSupport := True; SortedList := True; InformationAvailable := True; From e7cacb9947d1d28d0b266a928063049193b9edfe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 08:27:08 +0800 Subject: [PATCH 0767/2794] dataprocess, less verbose --- baseunits/uData.pas | 2 -- 1 file changed, 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9a96e4cf8..5ca25267e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -940,7 +940,6 @@ procedure TDBDataProcess.Commit; begin if FConn.Connected then try - WriteLog_V('TDBDataProcess['+Website+'].Commit'); queryactive := FQuery.Active; if FQuery.Active then FQuery.Close; FTrans.Commit; @@ -956,7 +955,6 @@ procedure TDBDataProcess.Rollback; begin if FConn.Connected then try - WriteLog_V('TDBDataProcess['+Website+'].Rollback'); FTrans.Rollback; except on E: Exception do From 4e8e684c82d5d148a0aca165d337ceb0d9419f88 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 09:22:28 +0800 Subject: [PATCH 0768/2794] dataprocess, change adddata sql statement --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5ca25267e..b344d5d87 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -867,7 +867,7 @@ function TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, if FConn.Connected=False then Exit(False); try FConn.ExecuteDirect( - 'INSERT OR IGNORE INTO ' + QuotedStrd(FTableName) + + 'INSERT OR FAIL INTO ' + QuotedStrd(FTableName) + #13#10'(' + DBDataProcessParam + ')' + #13#10'VALUES' + #13#10'('#13#10 + From ca939bf38b9d3b753a90ff89cad6989eafba48c2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 09:29:20 +0800 Subject: [PATCH 0769/2794] updatemanager, remove duplicate by database --- baseunits/uUpdateThread.pas | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index c228c9130..f6d2b4ee9 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -201,19 +201,12 @@ procedure TUpdateMangaThread.Execute; manager.CS_AddNamesAndLinks.Acquire; try - i:=0; - while i<links.Count do begin - if manager.mainDataProcess.LinkExist(links[i]) then begin - links.Delete(i); - names.Delete(i); - end - else Inc(i); - end; - if links.Count>0 then begin - for i:=0 to links.Count-1 do + for i:=0 to links.Count-1 do begin + if manager.mainDataProcess.AddData(names[i],links[i],'','','','','',0,0) then manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); - manager.tempDataProcess.Commit; end; + manager.mainDataProcess.Rollback; + manager.tempDataProcess.Commit; finally manager.CS_AddNamesAndLinks.Release; end; @@ -551,7 +544,7 @@ procedure TUpdateMangaManagerThread.DoTerminate; procedure TUpdateMangaManagerThread.Execute; var - c, j, k: Integer; + j, k: Integer; begin if websites.Count = 0 then Exit; @@ -609,10 +602,6 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; - mainDataProcess.OpenTable; - mainDataProcess.InitLocateLink; - mainDataProcess.CloseTable; - WriteLog_V('UpdateManagerThread, '+website+': get names and links'); // get names and links INIAdvanced.Reload; @@ -644,7 +633,6 @@ procedure TUpdateMangaManagerThread.Execute; end else GetInfo(directoryCount, CS_DIRECTORY_PAGE); - mainDataProcess.DoneLocateLink; if Terminated then Break; From b6f28f611efa483b3e717772ec5e9a5668529345 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 09:36:02 +0800 Subject: [PATCH 0770/2794] updatemanager, increase commit frequency --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index f6d2b4ee9..c0db89813 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -229,7 +229,7 @@ procedure TUpdateMangaThread.Execute; try Info.AddInfoToData(name, link, manager.mainDataProcess); - manager.CheckCommit(32); + manager.CheckCommit(16); finally manager.CS_AddInfoToData.Release; end; From 9e4cae1d2d26cd56b5a966deac99fd80de4d07a6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 10:01:05 +0800 Subject: [PATCH 0771/2794] add more verbose log --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 26 +++++++++++++++++--------- mangadownloader/languages/fmd.en.po | 5 ----- mangadownloader/languages/fmd.id_ID.po | 5 ----- mangadownloader/languages/fmd.po | 5 ----- 5 files changed, 18 insertions(+), 24 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 4ad59cd00..db570a925 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,6 +14,7 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange LCLVersion = '1.7' + Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9bfa643b5..e72e2c8f0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1111,10 +1111,12 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin + WriteLog_V('FormClose action'); if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then begin + WriteLog_V('FormClose aborted'); CloseAction := caNone; Exit; end; @@ -1125,6 +1127,7 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin + WriteLog_V('FormClose.CloseNow, terminating all threads and waitfor'); //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin @@ -1156,6 +1159,7 @@ procedure TMainForm.CloseNow; SilentThreadManager.StopAll(True); DLManager.StopAllDownloadTasksForExit; + WriteLog_V('FormClose.CloseNow, disabling all timer'); tmBackup.Enabled := False; itSaveDownloadedList.Enabled := False; itRefreshDLInfo.Enabled := False; @@ -1164,15 +1168,7 @@ procedure TMainForm.CloseNow; itStartup.Enabled := False; itMonitor.Enabled := False; - if Assigned(FormDropTarget) then - FormDropTarget.Close; - - if FMDInstance <> nil then - begin - FMDInstance.StopServer; - FreeAndNil(FMDInstance); - end; - + WriteLog_V('FormClose.CloseNow, backup all data to file'); //Backup data DLManager.Backup; DLManager.BackupDownloadedChaptersList; @@ -1181,13 +1177,25 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; + WriteLog_V('FormClose.CloseNow, closing other form'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; + + if Assigned(FormDropTarget) then + FormDropTarget.Close; + + if FMDInstance <> nil then + begin + WriteLog_V('FormClose.CloseNow, stop ipc server'); + FMDInstance.StopServer; + FreeAndNil(FMDInstance); + end; end; procedure TMainForm.FormDestroy(Sender: TObject); begin + WriteLog_V('FormDestroy, freeing all objects'); SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 03e6f65f0..2b6d07cd9 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -454,11 +454,6 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 2d8dd8cae..60d57a164 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -446,11 +446,6 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 2738ea8d3..6c64594e3 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -418,11 +418,6 @@ msgstr "" msgid "Visit my blog" msgstr "" -#: tmainform.caption -msgctxt "TMAINFORM.CAPTION" -msgid "Free Manga Downloader" -msgstr "" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From 5bcef41f53112112ed8307c5de6317c2cc707c13 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 10:17:38 +0800 Subject: [PATCH 0772/2794] updatemanager, fix finish searching on sorted list --- baseunits/uUpdateThread.pas | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index c0db89813..9c9d39cc6 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -195,15 +195,13 @@ procedure TUpdateMangaThread.Execute; //we will stop at first found against current db if links.Count > 0 then begin - if manager.SortedList then - if manager.mainDataProcess.LinkExist(links[0]) then - manager.isFinishSearchingForNewManga := True; - manager.CS_AddNamesAndLinks.Acquire; try for i:=0 to links.Count-1 do begin if manager.mainDataProcess.AddData(names[i],links[i],'','','','','',0,0) then - manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); + manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0) + else if (manager.isFinishSearchingForNewManga=False) and manager.SortedList then + manager.isFinishSearchingForNewManga:=True; end; manager.mainDataProcess.Rollback; manager.tempDataProcess.Commit; From 23855d0bee95ff79f5f8968f981eb1cde5cbbd32 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 11:01:23 +0800 Subject: [PATCH 0773/2794] add more log --- baseunits/uUpdateThread.pas | 13 +++++++++++++ mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 9c9d39cc6..4e8117d79 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -39,6 +39,8 @@ TUpdateMangaManagerThread = class(TFMDThread) private FStatus: String; FCommitCount: Integer; + FThreadAborted: Boolean; + FThreadEndNormally: Boolean; protected procedure Execute; override; {$IFNDEF DOWNLOADER} @@ -347,10 +349,14 @@ constructor TUpdateMangaManagerThread.Create; SortedList := False; NoMangaInfo := False; ModuleId := -1; + FThreadEndNormally:=False; + FThreadAborted:=False; end; destructor TUpdateMangaManagerThread.Destroy; begin + if FThreadAborted then WriteLog_W('UpdateManagerThread, thread aborted by user?'); + if not FThreadEndNormally then WriteLog_W('UpdateManagerThread, thread doesn''t end normally, ended by user?'); websites.Free; mainDataProcess.Close; DeleteDBDataProcess(twebsite); @@ -546,6 +552,7 @@ procedure TUpdateMangaManagerThread.Execute; begin if websites.Count = 0 then Exit; + WriteLog_V('UpdateManagerThread, thread started'); try websitePtr := 0; if isDownloadFromServer then @@ -564,12 +571,14 @@ procedure TUpdateMangaManagerThread.Execute; else while websitePtr < websites.Count do begin + FThreadAborted:=True; tempDataProcess.CreateDatabase('__tempupdatelist'); website := websites.Strings[websitePtr]; ModuleId := Modules.LocateModule(website); SortedList := SitesWithSortedList(website); NoMangaInfo := SitesWithoutInformation(website); Inc(websitePtr); + WriteLog_V('UpdateManagerThread, '+website+': update list started'); WriteLog_V('UpdateManagerThread, '+website+': sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); WriteLog_V('UpdateManagerThread, '+website+': prepare database file'); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', @@ -694,11 +703,15 @@ procedure TUpdateMangaManagerThread.Execute; Break; websites[websitePtr - 1] := UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); + WriteLog_V('UpdateManagerThread, '+website+': update list finished'); + FThreadAborted:=False; end; except on E: Exception do MainForm.ExceptionHandler(Self, E); end; + FThreadEndNormally:=True; + WriteLog_V('UpdateManagerThread, thread ended normally'); Synchronize(MainThreadEndGetting); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e72e2c8f0..da65a072e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1177,7 +1177,7 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; - WriteLog_V('FormClose.CloseNow, closing other form'); + WriteLog_V('FormClose.CloseNow, closing other forms'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; From 5ea46b95b5b96970b88977d5c874f1c3917011a5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 11:02:32 +0800 Subject: [PATCH 0774/2794] fix calculate day on filter "search only on new manga" --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b344d5d87..a7f3b2a5b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1059,7 +1059,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList // filter new manga based on date if searchNewManga then AddSQLCond('"jdn" > ' + - QuotedStrd(IntToStr(DateToJDN(IncDay(Now, (0 - minusDay)))))); + QuotedStrd(IntToStr(DateToJDN(Now)-minusDay))); // filter title AddSQLSimpleFilter('title', stTitle, False, False, useRegExpr); From c3560db3d061d8a1059bc4e31b3d9ea0938c5329 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 11:55:47 +0800 Subject: [PATCH 0775/2794] more log --- baseunits/uUpdateThread.pas | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 4e8117d79..6bb0b3a54 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -296,7 +296,7 @@ procedure TUpdateMangaManagerThread.MainThreadEndGetting; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; MainForm.isUpdating:=False; if MainForm.isPendingExitCounter then begin - WriteLog_V('UpdateManagerThread, pending exit counter executed'); + WriteLog_V(Self.ClassName+', pending exit counter executed'); MainForm.DoExitWaitCounter; end; end; @@ -355,8 +355,8 @@ constructor TUpdateMangaManagerThread.Create; destructor TUpdateMangaManagerThread.Destroy; begin - if FThreadAborted then WriteLog_W('UpdateManagerThread, thread aborted by user?'); - if not FThreadEndNormally then WriteLog_W('UpdateManagerThread, thread doesn''t end normally, ended by user?'); + if FThreadAborted then WriteLog_W(Self.ClassName+', thread aborted by user?'); + if not FThreadEndNormally then WriteLog_W(Self.ClassName+', thread doesn''t end normally, ended by user?'); websites.Free; mainDataProcess.Close; DeleteDBDataProcess(twebsite); @@ -549,10 +549,11 @@ procedure TUpdateMangaManagerThread.DoTerminate; procedure TUpdateMangaManagerThread.Execute; var j, k: Integer; + cloghead: String; begin if websites.Count = 0 then Exit; - WriteLog_V('UpdateManagerThread, thread started'); + WriteLog_V(Self.ClassName+', thread started'); try websitePtr := 0; if isDownloadFromServer then @@ -578,9 +579,11 @@ procedure TUpdateMangaManagerThread.Execute; SortedList := SitesWithSortedList(website); NoMangaInfo := SitesWithoutInformation(website); Inc(websitePtr); - WriteLog_V('UpdateManagerThread, '+website+': update list started'); - WriteLog_V('UpdateManagerThread, '+website+': sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); - WriteLog_V('UpdateManagerThread, '+website+': prepare database file'); + + cloghead:=Self.ClassName+', '+website+': '; + WriteLog_V(cloghead+'update list started'); + WriteLog_V(cloghead+'sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); + WriteLog_V(cloghead+'prepare database file'); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); @@ -600,7 +603,7 @@ procedure TUpdateMangaManagerThread.Execute; if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); - WriteLog_V('UpdateManagerThread, '+website+': get number of directory page'); + WriteLog_V(cloghead+'get number of directory page'); // get directory page count INIAdvanced.Reload; directoryCount := 0; @@ -609,7 +612,7 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; - WriteLog_V('UpdateManagerThread, '+website+': get names and links'); + WriteLog_V(cloghead+'get names and links'); // get names and links INIAdvanced.Reload; workPtr := 0; @@ -649,7 +652,7 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; Synchronize(MainThreadShowGetting); - WriteLog_V('UpdateManagerThread, '+website+': get info '+IntToStr(tempDataProcess.RecordCount)); + WriteLog_V(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); // get manga info if tempDataProcess.RecordCount>0 then begin @@ -678,12 +681,12 @@ procedure TUpdateMangaManagerThread.Execute; else GetInfo(tempDataProcess.RecordCount, CS_INFO); mainDataProcess.Commit; - WriteLog_V('UpdateManagerThread, '+website+': get info finished '+IntToStr(workPtr)); + WriteLog_V(cloghead+'get info finished '+IntToStr(workPtr)); if workPtr > 0 then if not (Terminated and SortedList) then begin - WriteLog_V('UpdateManagerThread, '+website+': saving data '+IntToStr(workPtr)); + WriteLog_V(cloghead+'saving data '+IntToStr(workPtr)); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); @@ -692,10 +695,10 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(RefreshList); end else - WriteLog_V('UpdateManagerThread, '+website+': sorted list, data abandoned'); + WriteLog_V(cloghead+'sorted list, data abandoned'); end; - WriteLog_V('UpdateManagerThread, '+website+': close database file'); + WriteLog_V(cloghead+'close database file'); mainDataProcess.Close; DeleteDBDataProcess(twebsite); @@ -703,7 +706,7 @@ procedure TUpdateMangaManagerThread.Execute; Break; websites[websitePtr - 1] := UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); - WriteLog_V('UpdateManagerThread, '+website+': update list finished'); + WriteLog_V(cloghead+'update list finished'); FThreadAborted:=False; end; except @@ -711,7 +714,7 @@ procedure TUpdateMangaManagerThread.Execute; MainForm.ExceptionHandler(Self, E); end; FThreadEndNormally:=True; - WriteLog_V('UpdateManagerThread, thread ended normally'); + WriteLog_V(Self.ClassName+', thread ended normally'); Synchronize(MainThreadEndGetting); end; From 9907d29c9d9ac6e1be0026555b78b9bb1d5d0a79 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 11:59:13 +0800 Subject: [PATCH 0776/2794] another log --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 6bb0b3a54..d8485be00 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -652,10 +652,10 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; Synchronize(MainThreadShowGetting); - WriteLog_V(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); // get manga info if tempDataProcess.RecordCount>0 then begin + WriteLog_V(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); workPtr := 0; FCommitCount := 0; if NoMangaInfo or From 96b8cfd8d2daaaad1632ee3b77e66afd14dd226a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 14:20:36 +0800 Subject: [PATCH 0777/2794] updatemanager, close temp data --- baseunits/uUpdateThread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index d8485be00..bfa460719 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -699,6 +699,7 @@ procedure TUpdateMangaManagerThread.Execute; end; WriteLog_V(cloghead+'close database file'); + tempDataProcess.Close; mainDataProcess.Close; DeleteDBDataProcess(twebsite); From 41129c7788aacb005a6aa19b96e4ddb307a39a02 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 18:07:07 +0800 Subject: [PATCH 0778/2794] updatemanager, speed up add list to temp data if no pre list available --- baseunits/uUpdateThread.pas | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index bfa460719..a32be9819 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -39,8 +39,9 @@ TUpdateMangaManagerThread = class(TFMDThread) private FStatus: String; FCommitCount: Integer; - FThreadAborted: Boolean; - FThreadEndNormally: Boolean; + FThreadAborted, + FThreadEndNormally, + FIsPreListAvailable: Boolean; protected procedure Execute; override; {$IFNDEF DOWNLOADER} @@ -199,13 +200,18 @@ procedure TUpdateMangaThread.Execute; begin manager.CS_AddNamesAndLinks.Acquire; try - for i:=0 to links.Count-1 do begin - if manager.mainDataProcess.AddData(names[i],links[i],'','','','','',0,0) then - manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0) - else if (manager.isFinishSearchingForNewManga=False) and manager.SortedList then - manager.isFinishSearchingForNewManga:=True; - end; - manager.mainDataProcess.Rollback; + if manager.FIsPreListAvailable then begin + for i:=0 to links.Count-1 do begin + if manager.mainDataProcess.AddData(names[i],links[i],'','','','','',0,0) then + manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0) + else if (manager.isFinishSearchingForNewManga=False) and manager.SortedList then + manager.isFinishSearchingForNewManga:=True; + end; + manager.mainDataProcess.Rollback; + end + else + for i:=0 to links.Count-1 do + manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); manager.tempDataProcess.Commit; finally manager.CS_AddNamesAndLinks.Release; @@ -351,6 +357,7 @@ constructor TUpdateMangaManagerThread.Create; ModuleId := -1; FThreadEndNormally:=False; FThreadAborted:=False; + FIsPreListAvailable:=False; end; destructor TUpdateMangaManagerThread.Destroy; @@ -603,6 +610,10 @@ procedure TUpdateMangaManagerThread.Execute; if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); + mainDataProcess.OpenTable('',True); + FIsPreListAvailable:=mainDataProcess.RecordCount>0; + mainDataProcess.CloseTable; + WriteLog_V(cloghead+'get number of directory page'); // get directory page count INIAdvanced.Reload; From 8e99ad2b67554a538175a36d34ffa7457de480a0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 18:49:42 +0800 Subject: [PATCH 0779/2794] dataprocess, change sql statements adddata,updatedata --- baseunits/uData.pas | 96 +++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index a7f3b2a5b..9fc1430a1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -92,11 +92,11 @@ TDBDataProcess = class(TObject) procedure Save; procedure Backup(AWebsite: String); procedure Refresh(RecheckDataCount: Boolean = False); - function AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer): Boolean; overload; - function AddData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; overload; - procedure UpdateData(Title, Link, Authors, Artists, Genres, Status, Summary: String; + procedure UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String = ''); procedure Commit; procedure Rollback; @@ -861,76 +861,60 @@ procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); end; end; -function TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, - Summary: String; NumChapter, JDN: Integer): Boolean; +function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter, JDN: Integer): Boolean; begin - if FConn.Connected=False then Exit(False); + Result:=False; + if FConn.Connected=False then Exit; try FConn.ExecuteDirect( - 'INSERT OR FAIL INTO ' + QuotedStrd(FTableName) + - #13#10'(' + DBDataProcessParam + ')' + - #13#10'VALUES' + - #13#10'('#13#10 + - QuotedStrd(Title) + ','#13#10 + - QuotedStrd(Link) + ','#13#10 + - QuotedStrd(Authors) + ','#13#10 + - QuotedStrd(Artists) + ','#13#10 + - QuotedStrd(Genres) + ','#13#10 + - QuotedStrd(Status) + ','#13#10 + - QuotedStrd(Summary) + ','#13#10 + - QuotedStrd(IntToStr(NumChapter)) + ','#13#10 + - QuotedStrd(IntToStr(JDN)) + - #13#10');'); + 'INSERT INTO "'+FTableName+'" ('+DBDataProcessParam+') VALUES ("'+ + Title+'","'+ + Link+'","'+ + Authors+'","'+ + Artists+'","'+ + Genres+'","'+ + Status+'","'+ + Summary+'","'+ + IntToStr(NumChapter)+'","'+ + IntToStr(JDN)+'")'); Result:=True; except - Result:=False; end; end; -function TDBDataProcess.AddData(Title, Link, Authors, Artists, Genres, Status, - Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; +function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; begin Result := AddData(Title, Link, Authors, Artists, Genres, Status, Summary, NumChapter, DateToJDN(JDN)); end; -procedure TDBDataProcess.UpdateData(Title, Link, Authors, Artists, +procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String); var sql: String; - - procedure AddSQL(const field, Value: String); - begin - if sql <> '' then - sql += ','#13#10; - sql += QuotedStrd(field) + '=' + QuotedStrd(Value); - end; - begin - if Link = '' then - Exit; - if FConn.Connected then - begin - try - sql := ''; - AddSQL('title', Title); - AddSQL('authors', Authors); - AddSQL('artists', Artists); - AddSQL('genres', Genres); - AddSQL('status', Status); - AddSQL('summary', Summary); - AddSQL('numchapter', IntToStr(NumChapter)); - if (AWebsite <> '') and (AWebsite <> FWebsite) and FAllSitesAttached then - sql := 'UPDATE OR IGNORE ' + AWebsite + '.' + QuotedStrd(FTableName) + - #13#10'SET'#13#10 + sql - else - sql := 'UPDATE OR IGNORE ' + QuotedStrd(FTableName) + #13#10'SET'#13#10 + sql; - sql += #13#10'WHERE "link"=' + QuotedStrd(Link) + ';'; - FConn.ExecuteDirect(sql); - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].UpdateData.Error!', E, Self); - end; + if Link='' then Exit; + if FConn.Connected=False then Exit; + try + sql:='UPDATE "'; + if (AWebsite<>'') and (AWebsite<>FWebsite) and FAllSitesAttached then + sql+=AWebsite+'"."'+FTableName + else + sql+=FTableName; + sql+='" SET "title"="'+Title+ + '","authors"="'+Authors+ + '","artists"="'+Artists+ + '","genres"="'+Genres+ + '","status"="'+Status+ + '","summary"="'+Summary+ + '","numchapter"="'+IntToStr(NumChapter)+'"'; + sql+=' WHERE "link"="'+Link+'"'; + FConn.ExecuteDirect(sql); + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].UpdateData.Error!'#13#10'SQL = '+sql, E, Self); end; end; From 9f5221786013df641211d5c23a4cd012adaffe8c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 20:02:50 +0800 Subject: [PATCH 0780/2794] move tdbdataprocess to its own unit --- baseunits/DBDataProcess.pas | 1180 +++++++++++++++++++++++++++++ baseunits/uData.pas | 1166 +--------------------------- baseunits/uUpdateThread.pas | 2 +- mangadownloader/forms/frmMain.pas | 2 +- 4 files changed, 1184 insertions(+), 1166 deletions(-) create mode 100644 baseunits/DBDataProcess.pas diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas new file mode 100644 index 000000000..0b9b66f25 --- /dev/null +++ b/baseunits/DBDataProcess.pas @@ -0,0 +1,1180 @@ +unit DBDataProcess; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, LazFileUtils, sqlite3conn, + sqlite3backup, sqlite3dyn, sqldb, DB, SimpleLogger, dateutils, + RegExpr; + +type + + TSQLite3Connectionx = class(TSQLite3Connection) + public + property Handle read GetHandle; + end; + + { TDBDataProcess } + + TDBDataProcess = class(TObject) + private + FConn: TSQLite3Connection; + FTrans: TSQLTransaction; + FQuery: TSQLQuery; + FRegxp: TRegExpr; + FWebsite: String; + FTableName: String; + FRecordCount: Integer; + FFiltered: Boolean; + FFilterAllSites: Boolean; + FFilterApplied: Boolean; + FAllSitesAttached: Boolean; + FSitesList: TStringList; + FAttachedSites: TStringList; + FSQLSelect: String; + FFilterSQL: String; + FLinks: TStringList; + function GetLinkCount: Integer; + protected + procedure CreateTable; + procedure ConvertNewTable; + procedure VacuumTable; + procedure GetRecordCount; + procedure AddSQLCond(const sqltext: String; useOR: Boolean = False); + procedure AddSQLSimpleFilter(const fieldname, Value: String; + useNOT: Boolean = False; useOR: Boolean = False; useRegexp: Boolean = False); + function GetConnected: Boolean; + function InternalOpen(const FilePath: String = ''): Boolean; + function GetWebsiteName(RecIndex: Integer): String; + function GetValue(RecIndex, FieldIndex: Integer): String; + procedure AttachAllSites; + procedure DetachAllSites; + function ExecuteDirect(SQL: String): Boolean; + public + constructor Create; + destructor Destroy; override; + + function Connect(AWebsite: String): Boolean; + function Open(AWebsite: String = ''): Boolean; + function OpenTable(const ATableName: String = ''; + CheckRecordCount: Boolean = False): Boolean; + function TableExist(const ATableName: String): Boolean; + function Search(ATitle: String): Boolean; + function CanFilter(const checkedGenres, uncheckedGenres: TStringList; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; + const {%H-}minusDay: Cardinal; + const haveAllChecked, searchNewManga: Boolean): Boolean; + function Filter(const checkedGenres, uncheckedGenres: TStringList; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; + const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; + useRegExpr: Boolean = False): Boolean; + function LocateByLink(ALink: String): Boolean; + function WebsiteLoaded(const AWebsite: String): Boolean; + function LinkExist(ALink: String): Boolean; + + procedure InitLocateLink; + procedure DoneLocateLink; + procedure CreateDatabase(AWebsite: String = ''); + procedure GetFieldNames(List: TStringList); + procedure Close; + procedure CloseTable; + procedure Save; + procedure Backup(AWebsite: String); + procedure Refresh(RecheckDataCount: Boolean = False); + function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter, JDN: Integer): Boolean; overload; + function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter: Integer; JDN: TDateTime): Boolean; overload; + procedure UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter: Integer; AWebsite: String = ''); + procedure Commit; + procedure Rollback; + procedure RemoveFilter; + procedure Sort; + + property Website: String read FWebsite write FWebsite; + property TableName: String read FTableName write FTableName; + property Connected: Boolean read GetConnected; + property RecordCount: Integer read FRecordCount; + property Filtered: Boolean read FFiltered; + property FilterAllSites: Boolean read FFilterAllSites write FFilterAllSites; + property SitesList: TStringList read FSitesList write FSitesList; + property WebsiteName[RecIndex: Integer]: String read GetWebsiteName; + property Value[RecIndex, ParamNo: Integer]: String read GetValue; + property LinkCount: Integer read GetLinkCount; + property Table: TSQLQuery read FQuery; + end; + +const + DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; + DBDataProcessParams: array [0..8] of ShortString = + ('title', 'link', 'authors', 'artists', 'genres', 'status', + 'summary', 'numchapter', 'jdn'); + DBDataProccesCreateParam = '('#13#10 + + '"title" TEXT,'#13#10 + + '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + + '"authors" TEXT,'#13#10 + + '"artists" TEXT,'#13#10 + + '"genres" TEXT,'#13#10 + + '"status" TEXT,'#13#10 + + '"summary" TEXT,'#13#10 + + '"numchapter" INTEGER,'#13#10 + + '"jdn" INTEGER'#13#10 + + ');'; + +function DBDataFilePath(const AWebsite: String): String; +procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); +function DataFileExist(const AWebsite: String): Boolean; +procedure CopyDBDataProcess(const AWebsite, NWebsite: String); +function DeleteDBDataProcess(const AWebsite: String): Boolean; +procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); + +implementation + +uses + uBaseUnit, uData, uMisc; + +function NaturalCompareCallback({%H-}user: pointer; len1: longint; + data1: pointer; len2: longint; data2: pointer): longint; cdecl; +var + s1, s2: String; +begin + SetString(s1, data1, len1); + SetString(s2, data2, len2); + Result := NaturalCompareStr(s1, s2); +end; + +procedure RegexCallback(context: PSqlite3_Context; argc: longint; + argv: PPSqlite3_Value); cdecl; +var + regexp, Text: PChar; + regex: TRegExpr; +begin + if sqlite3_user_data(context) = nil then + begin + sqlite3_result_int64(context, 0); + Exit; + end; + if argc <> 2 then + begin + sqlite3_result_int64(context, 0); + Exit; + end; + regexp := sqlite3_value_text(argv[0]); + Text := sqlite3_value_text(argv[1]); + if (regexp = nil) or (Text = nil) then + begin + sqlite3_result_int64(context, 0); + Exit; + end; + try + regex := TRegExpr(sqlite3_user_data(context)); + regex.Expression := regexp; + sqlite3_result_int64(context, int64(regex.Exec(Text))); + except + sqlite3_result_int64(context, 0); + end; +end; + +function QuotedLike(const S: String): String; +begin + Result := QuotedStrd(AnsiQuotedStr(S, '%')); +end; + +function DBDataFilePath(const AWebsite: String): String; +begin + Result := fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT; +end; + +procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); +var + filepath: String; + rawdata: TDataProcess; + dbdata: TDBDataProcess; + rcount: Integer; + i: Integer; +begin + filepath := fmdDirectory + DATA_FOLDER + AWebsite; + if FileExistsUTF8(filepath + DATA_EXT) then + begin + rawdata := TDataProcess.Create; + dbdata := TDBDataProcess.Create; + try + if FileExistsUTF8(filepath + DBDATA_EXT) then + DeleteFileUTF8(filepath + DBDATA_EXT); + rawdata.LoadFromFile(AWebsite); + dbdata.CreateDatabase(AWebsite); + if rawdata.Data.Count > 0 then + with rawdata do + begin + rcount := 0; + for i := 0 to Data.Count - 1 do + begin + dbdata.AddData(Title[i], Link[i], Authors[i], Artists[i], Genres[i], + Status[i], StringBreaks(Summary[i]), + StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), + {%H-}integer(JDN[i]) - 3); + Inc(rcount); + if rcount >= 5000 then + begin + rcount := 0; + dbdata.Commit; + end; + end; + dbdata.Commit; + end; + dbdata.Sort; + finally + rawdata.Free; + dbdata.Free; + end; + if DeleteOriginal then + DeleteFileUTF8(filepath + DATA_EXT); + end; +end; + +function DataFileExist(const AWebsite: String): Boolean; +begin + if AWebsite = '' then + Exit(False); + Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DATA_EXT) or + FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); +end; + +procedure CopyDBDataProcess(const AWebsite, NWebsite: String); +begin + if NWebsite = '' then + Exit; + if DataFileExist(AWebsite) then + begin + try + CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + [cffPreserveTime, cffOverwriteFile], True); + except + on E: Exception do + Writelog_E('CopyDBDataProcess.Error!', E); + end; + end; +end; + +function DeleteDBDataProcess(const AWebsite: String): Boolean; +var + tryc: Integer; +begin + Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + if Result = False then + begin + tryc := 0; + while not DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do + begin + if tryc > 3 then + Break; + Inc(tryc); + Sleep(250); + end; + Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + end; +end; + +procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); +begin + if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then + begin + if DeleteDBDataProcess(AWebsite) then + RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + end; +end; + +{ TDBDataProcess } + +function TDBDataProcess.GetLinkCount: Integer; +begin + if Assigned(FLinks) then + Result := FLinks.Count + else + Result := 0; +end; + +procedure TDBDataProcess.CreateTable; +begin + if FConn.Connected then + begin + FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + + DBDataProccesCreateParam); + FTrans.Commit; + end; +end; + +procedure TDBDataProcess.ConvertNewTable; +begin + //'"title" TEXT,'#13#10 + + // '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + + // '"authors" TEXT,'#13#10 + + // '"artists" TEXT,'#13#10 + + // '"genres" TEXT,'#13#10 + + // '"status" TEXT,'#13#10 + + // '"summary" TEXT,'#13#10 + + if FQuery.Active = False then Exit; + if (FieldTypeNames[FQuery.FieldByName('title').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('authors').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('artists').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('genres').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('status').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('summary').DataType] <> Fieldtypenames[ftMemo]) then + try + FQuery.Close; + with fconn do begin + ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+FTableName)); + ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+FTableName)+#13#10+DBDataProccesCreateParam); + ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+FTableName)+' SELECT * FROM '+QuotedStrd(FTableName)); + ExecuteDirect('DROP TABLE '+QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+FTableName)+' RENAME TO '+QuotedStrd(FTableName)); + end; + FTrans.Commit; + FQuery.Open; + except + FTrans.Rollback; + end; +end; + +procedure TDBDataProcess.VacuumTable; +var + queryactive: Boolean; +begin + if FConn.Connected then + begin + queryactive := FQuery.Active; + FQuery.Close; + with FConn do + begin + ExecuteDirect('END TRANSACTION'); + try + ExecuteDirect('VACUUM'); + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].VacuumTable.Error!', E, Self); + end; + ExecuteDirect('BEGIN TRANSACTION'); + end; + if FQuery.Active <> queryactive then + FQuery.Active := queryactive; + end; +end; + +procedure TDBDataProcess.GetRecordCount; +begin + if FQuery.Active then + begin + FQuery.Last; + FRecordCount := FQuery.RecordCount; + FQuery.Refresh; + end + else + FRecordCount := 0; +end; + +procedure TDBDataProcess.AddSQLCond(const sqltext: String; useOR: Boolean); +begin + with FQuery.SQL do + begin + if Count > 0 then + if (Strings[Count - 1] <> '(') and + (UpCase(Trim(Strings[Count - 1])) <> 'WHERE') then + begin + if useOR then + Add('OR') + else + Add('AND'); + end; + Add(sqltext); + end; +end; + +procedure TDBDataProcess.AddSQLSimpleFilter(const fieldname, Value: String; + useNOT: Boolean; useOR: Boolean; useRegexp: Boolean); +var + svalue: String; + scond: String; +begin + svalue := LowerCase(Trim(Value)); + if (fieldname = '') or (svalue = '') then + Exit; + if useNOT then + scond := ' NOT' + else + scond := ''; + if useRegexp then + AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStrd(svalue), useOR) + else + AddSQLCond(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); +end; + +function TDBDataProcess.GetConnected: Boolean; +begin + Result := FConn.Connected; +end; + +function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; +begin + Result := False; + if FilePath <> '' then + FConn.DatabaseName := FilePath; + if FConn.DatabaseName = '' then + Exit; + try + FConn.CharSet := 'UTF8'; + FConn.Connected := True; + sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, + @NaturalCompareCallback); + sqlite3_create_function(FConn.Handle, PChar('REGEXP'), 2, SQLITE_UTF8, FRegxp, + @RegexCallback, nil, nil); + FTrans.Active := True; + except + on E: Exception do + begin + WriteLog_E('TDBDataProcess['+Website+'].InternalOpen.Error!', E, Self); + Result := False; + end; + end; + Result := FConn.Connected; +end; + +function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; +begin + Result := FWebsite; + if FQuery.Active and (FAttachedSites.Count > 0) then + try + FQuery.RecNo := RecIndex + 1; + Result := FQuery.FieldByName('website').AsString; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].GetWebsiteName', E, Self); + end; +end; + +function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; +begin + if FieldIndex in [DATA_PARAM_NUMCHAPTER, DATA_PARAM_JDN] then + Result := '0' + else + Result := ''; + if not FQuery.Active then Exit; + if FieldIndex >= Length(DBDataProcessParams) then Exit; + if (RecIndex < 0) and (RecIndex > FRecordCount) then Exit; + try + FQuery.RecNo := RecIndex + 1; + Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].GetParam.Error!', E, Self); + end; +end; + +procedure TDBDataProcess.AttachAllSites; + + procedure RemoveCurrentSite; + var + j: Integer; + begin + if SitesList.Count > 0 then + for j := 0 to SitesList.Count - 1 do + if SitesList[j] = FWebsite then + begin + SitesList.Delete(j); + Break; + end; + end; + +var + i: Integer; +begin + RemoveCurrentSite; + if (not FConn.Connected) or (SitesList.Count = 0) then Exit; + if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then Exit; + DetachAllSites; + FConn.ExecuteDirect('END TRANSACTION'); + try + for i := 0 to SitesList.Count - 1 do + if (FAttachedSites.IndexOf(SitesList[i]) = -1) and + (FileExistsUTF8(DBDataFilePath(SitesList[i]))) then + begin + FConn.ExecuteDirect('ATTACH ' + + QuotedStrd(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); + FAttachedSites.Add(SitesList[i]); + end; + except + on E: Exception do + Writelog_E('TDBDataProcess['+Website+'].AttachAllSites.Error!', E, Self) + end; + FConn.ExecuteDirect('BEGIN TRANSACTION'); + FAllSitesAttached := FAttachedSites.Count > 0; +end; + +procedure TDBDataProcess.DetachAllSites; +var + i: Integer; + queryactive: Boolean; +begin + if (not FConn.Connected) or (FAttachedSites.Count = 0) then Exit; + queryactive := FQuery.Active; + if FQuery.Active then FQuery.Close; + FTrans.Commit; + FConn.ExecuteDirect('END TRANSACTION'); + for i := FAttachedSites.Count - 1 downto 0 do begin + try + FConn.ExecuteDirect('DETACH ' + QuotedStrd(FAttachedSites[i])); + FAttachedSites.Delete(i); + except + on E: Exception do + Writelog_E('TDBDataProcess['+Website+'].DetachAllSites.Error!', E, Self); + end; + end; + FConn.ExecuteDirect('BEGIN TRANSACTION'); + FAllSitesAttached := FAttachedSites.Count > 0; + if FQuery.Active <> queryactive then FQuery.Active := queryactive; +end; + +function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; +begin + Result := False; + if FConn.Connected then + try + FConn.ExecuteDirect(SQL); + Result := True; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].ExecuteDirect.Error!'#13#10 + + 'SQL: ' + SQL, E, Self); + end; +end; + +constructor TDBDataProcess.Create; +begin + inherited Create; + FConn := TSQLite3Connectionx.Create(nil); + FTrans := TSQLTransaction.Create(nil); + FQuery := TSQLQuery.Create(nil); + FConn.Transaction := FTrans; + FQuery.PacketRecords := 25; + FQuery.DataBase := FTrans.DataBase; + FQuery.Transaction := FTrans; + FRegxp := TRegExpr.Create; + FRegxp.ModifierI := True; + FSitesList := TStringList.Create; + FAttachedSites := TStringList.Create; + FTableName := 'masterlist'; + FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); + FRecordCount := 0; + FFiltered := False; + FFilterAllSites := False; + FFilterApplied := False; + FFilterSQL := ''; + FAllSitesAttached := False; +end; + +destructor TDBDataProcess.Destroy; +begin + try + if FConn.Connected then + begin + FQuery.Close; + Commit; + Close; + end; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Destroy.Error!', E, Self); + end; + DoneLocateLink; + FAttachedSites.Free; + FSitesList.Free; + FQuery.Free; + FTrans.Free; + FConn.Free; + FRegxp.Free; + inherited Destroy; +end; + +function TDBDataProcess.Connect(AWebsite: String): Boolean; +var + filepath: String; +begin + Result := False; + if AWebsite <> '' then + FWebsite := AWebsite; + if FWebsite = '' then + Exit; + filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + if not FileExistsUTF8(filepath) then + Exit; + Result := InternalOpen(filepath); +end; + +function TDBDataProcess.Open(AWebsite: String): Boolean; +var + filepath: String; +begin + Result := False; + Self.Close; + if AWebsite <> '' then + FWebsite := AWebsite; + if FWebsite = '' then + Exit; + filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + if not FileExistsUTF8(filepath) then + ConvertDataProccessToDB(AWebsite, True); + if not FileExistsUTF8(filepath) then + Exit; + try + if InternalOpen(filepath) then + begin + if not TableExist(FTableName) then + CreateTable; + OpenTable(FTableName, True); + end; + Result := FQuery.Active; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Open.Error!', E, Self); + end; +end; + +function TDBDataProcess.OpenTable(const ATableName: String; + CheckRecordCount: Boolean): Boolean; +begin + Result := False; + if FConn.Connected then + begin + try + if ATableName <> '' then + FTableName := ATableName; + if FTableName = '' then + Exit; + if TableExist(FTableName) then + begin + if FQuery.Active then + FQuery.Close; + FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); + FQuery.SQL.Text := FSQLSelect; + FQuery.Open; + if CheckRecordCount then + GetRecordCount; + end; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].OpenTable.Error!', E, Self); + end; + end; + Result := FQuery.Active; + if Result then ConvertNewTable; +end; + +function TDBDataProcess.TableExist(const ATableName: String): Boolean; +var + ts: TStringList; + i: Integer; +begin + Result := False; + if FConn.Connected then + begin + ts := TStringList.Create; + try + FConn.GetTableNames(ts); + ts.Sorted := True; + Result := ts.Find(ATableName, i); + finally + ts.Free; + end; + end; +end; + +procedure TDBDataProcess.Close; +begin + FRecordCount := 0; + if FConn.Connected then + try + FQuery.Close; + RemoveFilter; + FConn.Close; + FConn.DatabaseName := ''; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Close.Error!', E, Self); + end; +end; + +procedure TDBDataProcess.CloseTable; +begin + if FQuery.Active then + begin + FRecordCount := 0; + RemoveFilter; + FQuery.Close; + end; +end; + +procedure TDBDataProcess.Save; +begin + Commit; +end; + +procedure TDBDataProcess.Backup(AWebsite: String); +begin + if AWebsite = '' then + Exit; + if FConn.Connected then + begin + with TSQLite3Backup.Create do + try + Backup(FConn, fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + finally + Free; + end; + end; +end; + +procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); +begin + if FConn.Connected then + begin + if FQuery.Active then + FQuery.Refresh + else + if Trim(FQuery.SQL.Text) <> '' then + FQuery.Open; + if RecheckDataCount then + GetRecordCount; + end; +end; + +function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter, JDN: Integer): Boolean; +begin + Result:=False; + if FConn.Connected=False then Exit; + try + FConn.ExecuteDirect( + 'INSERT INTO "'+FTableName+'" ('+DBDataProcessParam+') VALUES ("'+ + Title+'","'+ + Link+'","'+ + Authors+'","'+ + Artists+'","'+ + Genres+'","'+ + Status+'","'+ + Summary+'","'+ + IntToStr(NumChapter)+'","'+ + IntToStr(JDN)+'")'); + Result:=True; + except + end; +end; + +function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; +begin + Result := AddData(Title, Link, Authors, Artists, Genres, Status, Summary, + NumChapter, DateToJDN(JDN)); +end; + +procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, + Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String); +var + sql: String; +begin + if Link='' then Exit; + if FConn.Connected=False then Exit; + try + sql:='UPDATE "'; + if (AWebsite<>'') and (AWebsite<>FWebsite) and FAllSitesAttached then + sql+=AWebsite+'"."'+FTableName + else + sql+=FTableName; + sql+='" SET "title"="'+Title+ + '","authors"="'+Authors+ + '","artists"="'+Artists+ + '","genres"="'+Genres+ + '","status"="'+Status+ + '","summary"="'+Summary+ + '","numchapter"="'+IntToStr(NumChapter)+'"'; + sql+=' WHERE "link"="'+Link+'"'; + FConn.ExecuteDirect(sql); + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].UpdateData.Error!'#13#10'SQL = '+sql, E, Self); + end; +end; + +procedure TDBDataProcess.Commit; +var + queryactive: Boolean; +begin + if FConn.Connected then + try + queryactive := FQuery.Active; + if FQuery.Active then FQuery.Close; + FTrans.Commit; + if FQuery.Active <> queryactive then + FQuery.Active := queryactive; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Commit.Error!',E,Self); + end; +end; + +procedure TDBDataProcess.Rollback; +begin + if FConn.Connected then + try + FTrans.Rollback; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Rollback.Error!',E,Self); + end; +end; + +function TDBDataProcess.Search(ATitle: String): Boolean; +var + i: Integer; +begin + if FQuery.Active then + begin + try + FQuery.Close; + with FQuery do + begin + SQL.Clear; + if FFilterApplied then + SQL.AddText(FFilterSQL) + else + SQL.Add(FSQLSelect); + if ATitle <> '' then + begin + if not FFilterApplied then + SQL.Add('WHERE'); + if FAllSitesAttached then + begin + if SQL.Count > 0 then + begin + i := 0; + while i < SQL.Count do + begin + if (SQL[i] = 'UNION ALL') or (SQL[i] = ')') then + begin + SQL.Insert(i, 'AND'); + SQL.Insert(i + 1, '"title" LIKE ' + QuotedLike(ATitle)); + Inc(i, 3); + end + else + Inc(i); + end; + end; + end + else + AddSQLSimpleFilter('title', ATitle); + FFiltered := True; + end + else + FFiltered := FFilterApplied; + end; + FQuery.Open; + GetRecordCount; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Search.Error!'#13#10 + + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); + end; + end; + Result := FQuery.Active; + if not Result then + begin + FFiltered := False; + FRecordCount := 0; + end; +end; + +function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; + const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; +begin + Result := False; + if not FQuery.Active then + Exit; + if ((stTitle = '') and + (stAuthors = '') and + (stArtists = '') and + (stSummary = '') and + (stStatus = '2') and + (checkedGenres.Count = 0) and + (uncheckedGenres.Count = 0)) and + (not searchNewManga) and + haveAllChecked then + Result := False + else + Result := True; +end; + +function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; + const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; + useRegExpr: Boolean): Boolean; +var + tsql: String; + i: Integer; + filtersingle: Boolean = True; + + procedure GenerateSQLFilter; + var + j: Integer; + begin + // filter new manga based on date + if searchNewManga then + AddSQLCond('"jdn" > ' + + QuotedStrd(IntToStr(DateToJDN(Now)-minusDay))); + + // filter title + AddSQLSimpleFilter('title', stTitle, False, False, useRegExpr); + + // filter authors + AddSQLSimpleFilter('authors', stAuthors, False, False, useRegExpr); + + // filter artists + AddSQLSimpleFilter('artists', stArtists, False, False, useRegExpr); + + // filter summary + AddSQLSimpleFilter('summary', stSummary, False, False, useRegExpr); + + // filter status + if stStatus <> '2' then + AddSQLCond('"status"=' + QuotedStrd(stStatus)); + + //filter checked genres + if checkedGenres.Count > 0 then + begin + AddSQLCond('('); + for j := 0 to checkedGenres.Count - 1 do + AddSQLSimpleFilter('genres', checkedGenres[j], False, + (not haveAllChecked), useRegExpr); + FQuery.SQL.Add(')'); + end; + + //filter unchecked genres + if uncheckedGenres.Count > 0 then + begin + AddSQLCond('('); + for j := 0 to uncheckedGenres.Count - 1 do + AddSQLSimpleFilter('genres', uncheckedGenres[j], True, + (not haveAllChecked), useRegExpr); + FQuery.SQL.Add(')'); + end; + end; + +begin + Result := False; + if FQuery.Active = False then + Exit; + if not CanFilter(checkedGenres, uncheckedGenres, stTitle, stAuthors, + stArtists, stStatus, stSummary, minusDay, haveAllChecked, searchNewManga) then + Exit; + with FQuery do + begin + FQuery.Close; + FRecordCount := 0; + tsql := SQL.Text; + SQL.Clear; + try + if FFilterAllSites and (FSitesList.Count > 0) then + begin + AttachAllSites; + if FAttachedSites.Count > 0 then + begin + SQL.Add('SELECT * FROM'); + SQL.Add('('); + SQL.Add('SELECT *, ' + QuotedStrd(FWebsite) + ' AS "website" FROM ' + + QuotedStrd(FTableName)); + SQL.Add('WHERE'); + GenerateSQLFilter; + for i := 0 to FAttachedSites.Count - 1 do + begin + SQL.Add('UNION ALL'); + SQL.Add('SELECT *, ' + QuotedStrd(FAttachedSites[i]) + + ' AS "website" FROM ' + + QuotedStrd(FAttachedSites[i]) + '.' + QuotedStrd(FTableName)); + SQL.Add('WHERE'); + GenerateSQLFilter; + end; + SQL.Add(')'); + SQL.Add('ORDER BY "title" COLLATE NATCMP'); + filtersingle := False; + end; + end; + + if filtersingle then + begin + SQL.Add(FSQLSelect); + SQL.Add('WHERE'); + GenerateSQLFilter; + end; + + FQuery.Open; + FFiltered := Active; + FFilterApplied := FFiltered; + if FFilterApplied then + FFilterSQL := SQL.Text + else + FFilterSQL := ''; + except + on E: Exception do + begin + WriteLog_E('TDBDataProcess['+Website+'].Filter.Error!'#13#10 + + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); + FQuery.Close; + SQL.Text := tsql; + FQuery.Open; + FFilterAllSites := False; + FFiltered := False; + FFilterApplied := False; + FFilterSQL := ''; + end; + end; + GetRecordCount; + Result := FFiltered; + end; +end; + +function TDBDataProcess.LocateByLink(ALink: String): Boolean; +begin + Result := False; + if (FQuery.Active) and (FRecordCount > 0) and (ALink <> '') then + try + Result := FQuery.Locate('link', ALink, [loCaseInsensitive]); + except + on E: Exception do + WriteLog_E('TDBDataProcess.LocateByLink.Error!', E, Self); + end; +end; + +procedure TDBDataProcess.CreateDatabase(AWebsite: String); +var + filepath: String; +begin + if AWebsite <> '' then FWebsite := AWebsite; + if FWebsite = '' then Exit; + Close; + filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + if FileExistsUTF8(filepath) then + DeleteFileUTF8(filepath); + InternalOpen(filepath); + CreateTable; +end; + +procedure TDBDataProcess.GetFieldNames(List: TStringList); +begin + if (List <> nil) and (FQuery.Active) then + FQuery.GetFieldNames(List); +end; + +procedure TDBDataProcess.RemoveFilter; +begin + if FFiltered then + begin + FFilterAllSites := False; + FFiltered := False; + FFilterApplied := False; + FFilterSQL := ''; + FQuery.SQL.Text := FSQLSelect; + FRecordCount := 0; + DetachAllSites; + if FQuery.Active then + begin + OpenTable; + GetRecordCount; + end; + end; +end; + +procedure TDBDataProcess.Sort; +var + queryactive: Boolean; +begin + if FConn.Connected then + begin + queryactive := FQuery.Active; + FQuery.Close; + with FConn do + try + ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName + '_ordered')); + ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + + DBDataProccesCreateParam); + ExecuteDirect('INSERT INTO '+QuotedStrd(FTableName + '_ordered') + + ' SELECT * FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); + ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + + 'RENAME TO ' + QuotedStrd(FTableName)); + FTrans.Commit; + VacuumTable; + except + on E: Exception do + WriteLog_E('TDBDataProcess['+Website+'].Sort.Error!', E, Self); + end; + if FQuery.Active <> queryactive then + FQuery.Active := queryactive; + end; +end; + +function TDBDataProcess.WebsiteLoaded(const AWebsite: String): Boolean; +var + i: Integer; +begin + Result := False; + if FWebsite = AWebsite then + Exit(True); + if FAllSitesAttached then + for i := 0 to FAttachedSites.Count - 1 do + if FAttachedSites[i] = AWebsite then + begin + Result := True; + Break; + end; +end; + +function TDBDataProcess.LinkExist(ALink: String): Boolean; +var + i: Integer; +begin + if Assigned(FLinks) then + Result := FLinks.Find(ALink, i) + else + Result := False; +end; + +procedure TDBDataProcess.InitLocateLink; +begin + if Assigned(FLinks) then + FLinks.Clear + else + FLinks := TStringList.Create; + FLinks.Sorted := False; + if FQuery.Active then + begin + FQuery.First; + repeat + FLinks.Add(FQuery.Fields[1].AsString); + FQuery.Next; + until FQuery.EOF; + if FLinks.Count > 0 then + FLinks.Sorted := True; + end; +end; + +procedure TDBDataProcess.DoneLocateLink; +begin + if Assigned(FLinks) then + FreeAndNil(FLinks); +end; + +end. diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9fc1430a1..4f30305e0 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,108 +14,11 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, FileUtil, LazFileUtils, sqlite3conn, - sqlite3backup, sqlite3dyn, sqldb, DB, SimpleLogger, strutils, dateutils, - RegExpr, httpsend; + Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FileUtil, + LazFileUtils, SimpleLogger, strutils, dateutils, RegExpr, httpsend; type - TSQLite3Connectionx = class(TSQLite3Connection) - public - property Handle read GetHandle; - end; - - { TDBDataProcess } - - TDBDataProcess = class(TObject) - private - FConn: TSQLite3Connectionx; - FTrans: TSQLTransaction; - FQuery: TSQLQuery; - FRegxp: TRegExpr; - FWebsite: String; - FTableName: String; - FRecordCount: Integer; - FFiltered: Boolean; - FFilterAllSites: Boolean; - FFilterApplied: Boolean; - FAllSitesAttached: Boolean; - FSitesList: TStringList; - FAttachedSites: TStringList; - FSQLSelect: String; - FFilterSQL: String; - FLinks: TStringList; - function GetLinkCount: Integer; - protected - procedure CreateTable; - procedure ConvertNewTable; - procedure VacuumTable; - procedure GetRecordCount; - procedure AddSQLCond(const sqltext: String; useOR: Boolean = False); - procedure AddSQLSimpleFilter(const fieldname, Value: String; - useNOT: Boolean = False; useOR: Boolean = False; useRegexp: Boolean = False); - function GetConnected: Boolean; - function InternalOpen(const FilePath: String = ''): Boolean; - function GetWebsiteName(RecIndex: Integer): String; - function GetValue(RecIndex, FieldIndex: Integer): String; - procedure AttachAllSites; - procedure DetachAllSites; - function ExecuteDirect(SQL: String): Boolean; - public - constructor Create; - destructor Destroy; override; - - function Connect(AWebsite: String): Boolean; - function Open(AWebsite: String = ''): Boolean; - function OpenTable(const ATableName: String = ''; - CheckRecordCount: Boolean = False): Boolean; - function TableExist(const ATableName: String): Boolean; - function Search(ATitle: String): Boolean; - function CanFilter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const {%H-}minusDay: Cardinal; - const haveAllChecked, searchNewManga: Boolean): Boolean; - function Filter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; - useRegExpr: Boolean = False): Boolean; - function LocateByLink(ALink: String): Boolean; - function WebsiteLoaded(const AWebsite: String): Boolean; - function LinkExist(ALink: String): Boolean; - - procedure InitLocateLink; - procedure DoneLocateLink; - procedure CreateDatabase(AWebsite: String = ''); - procedure GetFieldNames(List: TStringList); - procedure Close; - procedure CloseTable; - procedure Save; - procedure Backup(AWebsite: String); - procedure Refresh(RecheckDataCount: Boolean = False); - function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter, JDN: Integer): Boolean; overload; - function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer; JDN: TDateTime): Boolean; overload; - procedure UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer; AWebsite: String = ''); - procedure Commit; - procedure Rollback; - procedure RemoveFilter; - procedure Sort; - - property Website: String read FWebsite write FWebsite; - property TableName: String read FTableName write FTableName; - property Connected: Boolean read GetConnected; - property RecordCount: Integer read FRecordCount; - property Filtered: Boolean read FFiltered; - property FilterAllSites: Boolean read FFilterAllSites write FFilterAllSites; - property SitesList: TStringList read FSitesList write FSitesList; - property WebsiteName[RecIndex: Integer]: String read GetWebsiteName; - property Value[RecIndex, ParamNo: Integer]: String read GetValue; - property LinkCount: Integer read GetLinkCount; - property Table: TSQLQuery read FQuery; - end; - { TDataProcess } TDataProcess = class(TObject) @@ -215,1077 +118,12 @@ TMangaInformation = class(TObject) var options: TStringList; -const - DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; - DBDataProcessParams: array [0..8] of ShortString = - ('title', 'link', 'authors', 'artists', 'genres', 'status', - 'summary', 'numchapter', 'jdn'); - DBDataProccesCreateParam = '('#13#10 + - '"title" TEXT,'#13#10 + - '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + - '"authors" TEXT,'#13#10 + - '"artists" TEXT,'#13#10 + - '"genres" TEXT,'#13#10 + - '"status" TEXT,'#13#10 + - '"summary" TEXT,'#13#10 + - '"numchapter" INTEGER,'#13#10 + - '"jdn" INTEGER'#13#10 + - ');'; - -function DBDataFilePath(const AWebsite: String): String; -procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); -function DataFileExist(const AWebsite: String): Boolean; -procedure CopyDBDataProcess(const AWebsite, NWebsite: String); -function DeleteDBDataProcess(const AWebsite: String): Boolean; -procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); - implementation uses Dialogs, fpJSON, JSONParser, IniFiles, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, uMisc, frmMain, WebsiteModules; -function NaturalCompareCallback({%H-}user: pointer; len1: longint; - data1: pointer; len2: longint; data2: pointer): longint; cdecl; -var - s1, s2: String; -begin - SetString(s1, data1, len1); - SetString(s2, data2, len2); - Result := NaturalCompareStr(s1, s2); -end; - -procedure RegexCallback(context: PSqlite3_Context; argc: longint; - argv: PPSqlite3_Value); cdecl; -var - regexp, Text: PChar; - regex: TRegExpr; -begin - if sqlite3_user_data(context) = nil then - begin - sqlite3_result_int64(context, 0); - Exit; - end; - if argc <> 2 then - begin - sqlite3_result_int64(context, 0); - Exit; - end; - regexp := sqlite3_value_text(argv[0]); - Text := sqlite3_value_text(argv[1]); - if (regexp = nil) or (Text = nil) then - begin - sqlite3_result_int64(context, 0); - Exit; - end; - try - regex := TRegExpr(sqlite3_user_data(context)); - regex.Expression := regexp; - sqlite3_result_int64(context, int64(regex.Exec(Text))); - except - sqlite3_result_int64(context, 0); - end; -end; - -function QuotedLike(const S: String): String; -begin - Result := QuotedStrd(AnsiQuotedStr(S, '%')); -end; - -function DBDataFilePath(const AWebsite: String): String; -begin - Result := fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT; -end; - -procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); -var - filepath: String; - rawdata: TDataProcess; - dbdata: TDBDataProcess; - rcount: Integer; - i: Integer; -begin - filepath := fmdDirectory + DATA_FOLDER + AWebsite; - if FileExistsUTF8(filepath + DATA_EXT) then - begin - rawdata := TDataProcess.Create; - dbdata := TDBDataProcess.Create; - try - if FileExistsUTF8(filepath + DBDATA_EXT) then - DeleteFileUTF8(filepath + DBDATA_EXT); - rawdata.LoadFromFile(AWebsite); - dbdata.CreateDatabase(AWebsite); - if rawdata.Data.Count > 0 then - with rawdata do - begin - rcount := 0; - for i := 0 to Data.Count - 1 do - begin - dbdata.AddData(Title[i], Link[i], Authors[i], Artists[i], Genres[i], - Status[i], StringBreaks(Summary[i]), - StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), - {%H-}integer(JDN[i]) - 3); - Inc(rcount); - if rcount >= 5000 then - begin - rcount := 0; - dbdata.Commit; - end; - end; - dbdata.Commit; - end; - dbdata.Sort; - finally - rawdata.Free; - dbdata.Free; - end; - if DeleteOriginal then - DeleteFileUTF8(filepath + DATA_EXT); - end; -end; - -function DataFileExist(const AWebsite: String): Boolean; -begin - if AWebsite = '' then - Exit(False); - Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DATA_EXT) or - FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); -end; - -procedure CopyDBDataProcess(const AWebsite, NWebsite: String); -begin - if NWebsite = '' then - Exit; - if DataFileExist(AWebsite) then - begin - try - CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, - [cffPreserveTime, cffOverwriteFile], True); - except - on E: Exception do - Writelog_E('CopyDBDataProcess.Error!', E); - end; - end; -end; - -function DeleteDBDataProcess(const AWebsite: String): Boolean; -var - tryc: Integer; -begin - Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - if Result = False then - begin - tryc := 0; - while not DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do - begin - if tryc > 3 then - Break; - Inc(tryc); - Sleep(250); - end; - Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - end; -end; - -procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); -begin - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then - begin - if DeleteDBDataProcess(AWebsite) then - RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - end; -end; - -{ TDBDataProcess } - -function TDBDataProcess.GetLinkCount: Integer; -begin - if Assigned(FLinks) then - Result := FLinks.Count - else - Result := 0; -end; - -procedure TDBDataProcess.CreateTable; -begin - if FConn.Connected then - begin - FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); - FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + - DBDataProccesCreateParam); - FTrans.Commit; - end; -end; - -procedure TDBDataProcess.ConvertNewTable; -begin - //'"title" TEXT,'#13#10 + - // '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + - // '"authors" TEXT,'#13#10 + - // '"artists" TEXT,'#13#10 + - // '"genres" TEXT,'#13#10 + - // '"status" TEXT,'#13#10 + - // '"summary" TEXT,'#13#10 + - if FQuery.Active = False then Exit; - if (FieldTypeNames[FQuery.FieldByName('title').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[FQuery.FieldByName('authors').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[FQuery.FieldByName('artists').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[FQuery.FieldByName('genres').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[FQuery.FieldByName('status').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[FQuery.FieldByName('summary').DataType] <> Fieldtypenames[ftMemo]) then - try - FQuery.Close; - with fconn do begin - ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+FTableName)); - ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+FTableName)+#13#10+DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+FTableName)+' SELECT * FROM '+QuotedStrd(FTableName)); - ExecuteDirect('DROP TABLE '+QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+FTableName)+' RENAME TO '+QuotedStrd(FTableName)); - end; - FTrans.Commit; - FQuery.Open; - except - FTrans.Rollback; - end; -end; - -procedure TDBDataProcess.VacuumTable; -var - queryactive: Boolean; -begin - if FConn.Connected then - begin - queryactive := FQuery.Active; - FQuery.Close; - with FConn do - begin - ExecuteDirect('END TRANSACTION'); - try - ExecuteDirect('VACUUM'); - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].VacuumTable.Error!', E, Self); - end; - ExecuteDirect('BEGIN TRANSACTION'); - end; - if FQuery.Active <> queryactive then - FQuery.Active := queryactive; - end; -end; - -procedure TDBDataProcess.GetRecordCount; -begin - if FQuery.Active then - begin - FQuery.Last; - FRecordCount := FQuery.RecordCount; - FQuery.Refresh; - end - else - FRecordCount := 0; -end; - -procedure TDBDataProcess.AddSQLCond(const sqltext: String; useOR: Boolean); -begin - with FQuery.SQL do - begin - if Count > 0 then - if (Strings[Count - 1] <> '(') and - (UpCase(Trim(Strings[Count - 1])) <> 'WHERE') then - begin - if useOR then - Add('OR') - else - Add('AND'); - end; - Add(sqltext); - end; -end; - -procedure TDBDataProcess.AddSQLSimpleFilter(const fieldname, Value: String; - useNOT: Boolean; useOR: Boolean; useRegexp: Boolean); -var - svalue: String; - scond: String; -begin - svalue := LowerCase(Trim(Value)); - if (fieldname = '') or (svalue = '') then - Exit; - if useNOT then - scond := ' NOT' - else - scond := ''; - if useRegexp then - AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStrd(svalue), useOR) - else - AddSQLCond(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); -end; - -function TDBDataProcess.GetConnected: Boolean; -begin - Result := FConn.Connected; -end; - -function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; -begin - Result := False; - if FilePath <> '' then - FConn.DatabaseName := FilePath; - if FConn.DatabaseName = '' then - Exit; - try - FConn.CharSet := 'UTF8'; - FConn.Connected := True; - sqlite3_create_collation(FConn.Handle, PChar('NATCMP'), SQLITE_UTF8, nil, - NaturalCompareCallback); - sqlite3_create_function(FConn.Handle, PChar('REGEXP'), 2, SQLITE_UTF8, FRegxp, - RegexCallback, nil, nil); - FTrans.Active := True; - except - on E: Exception do - begin - WriteLog_E('TDBDataProcess['+Website+'].InternalOpen.Error!', E, Self); - Result := False; - end; - end; - Result := FConn.Connected; -end; - -function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; -begin - Result := FWebsite; - if FQuery.Active and (FAttachedSites.Count > 0) then - try - FQuery.RecNo := RecIndex + 1; - Result := FQuery.FieldByName('website').AsString; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].GetWebsiteName', E, Self); - end; -end; - -function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; -begin - if FieldIndex in [DATA_PARAM_NUMCHAPTER, DATA_PARAM_JDN] then - Result := '0' - else - Result := ''; - if not FQuery.Active then Exit; - if FieldIndex >= Length(DBDataProcessParams) then Exit; - if (RecIndex < 0) and (RecIndex > FRecordCount) then Exit; - try - FQuery.RecNo := RecIndex + 1; - Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].GetParam.Error!', E, Self); - end; -end; - -procedure TDBDataProcess.AttachAllSites; - - procedure RemoveCurrentSite; - var - j: Integer; - begin - if SitesList.Count > 0 then - for j := 0 to SitesList.Count - 1 do - if SitesList[j] = FWebsite then - begin - SitesList.Delete(j); - Break; - end; - end; - -var - i: Integer; -begin - RemoveCurrentSite; - if (not FConn.Connected) or (SitesList.Count = 0) then Exit; - if Trim(SitesList.Text) = Trim(FAttachedSites.Text) then Exit; - DetachAllSites; - FConn.ExecuteDirect('END TRANSACTION'); - try - for i := 0 to SitesList.Count - 1 do - if (FAttachedSites.IndexOf(SitesList[i]) = -1) and - (FileExistsUTF8(DBDataFilePath(SitesList[i]))) then - begin - FConn.ExecuteDirect('ATTACH ' + - QuotedStrd(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); - FAttachedSites.Add(SitesList[i]); - end; - except - on E: Exception do - Writelog_E('TDBDataProcess['+Website+'].AttachAllSites.Error!', E, Self) - end; - FConn.ExecuteDirect('BEGIN TRANSACTION'); - FAllSitesAttached := FAttachedSites.Count > 0; -end; - -procedure TDBDataProcess.DetachAllSites; -var - i: Integer; - queryactive: Boolean; -begin - if (not FConn.Connected) or (FAttachedSites.Count = 0) then Exit; - queryactive := FQuery.Active; - if FQuery.Active then FQuery.Close; - FTrans.Commit; - FConn.ExecuteDirect('END TRANSACTION'); - for i := FAttachedSites.Count - 1 downto 0 do begin - try - FConn.ExecuteDirect('DETACH ' + QuotedStrd(FAttachedSites[i])); - FAttachedSites.Delete(i); - except - on E: Exception do - Writelog_E('TDBDataProcess['+Website+'].DetachAllSites.Error!', E, Self); - end; - end; - FConn.ExecuteDirect('BEGIN TRANSACTION'); - FAllSitesAttached := FAttachedSites.Count > 0; - if FQuery.Active <> queryactive then FQuery.Active := queryactive; -end; - -function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; -begin - Result := False; - if FConn.Connected then - try - FConn.ExecuteDirect(SQL); - Result := True; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].ExecuteDirect.Error!'#13#10 + - 'SQL: ' + SQL, E, Self); - end; -end; - -constructor TDBDataProcess.Create; -begin - inherited Create; - FConn := TSQLite3Connectionx.Create(nil); - FTrans := TSQLTransaction.Create(nil); - FQuery := TSQLQuery.Create(nil); - FConn.Transaction := FTrans; - FQuery.PacketRecords := 25; - FQuery.DataBase := FTrans.DataBase; - FQuery.Transaction := FTrans; - FRegxp := TRegExpr.Create; - FRegxp.ModifierI := True; - FSitesList := TStringList.Create; - FAttachedSites := TStringList.Create; - FTableName := 'masterlist'; - FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); - FRecordCount := 0; - FFiltered := False; - FFilterAllSites := False; - FFilterApplied := False; - FFilterSQL := ''; - FAllSitesAttached := False; -end; - -destructor TDBDataProcess.Destroy; -begin - try - if FConn.Connected then - begin - FQuery.Close; - Commit; - Close; - end; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Destroy.Error!', E, Self); - end; - DoneLocateLink; - FAttachedSites.Free; - FSitesList.Free; - FQuery.Free; - FTrans.Free; - FConn.Free; - FRegxp.Free; - inherited Destroy; -end; - -function TDBDataProcess.Connect(AWebsite: String): Boolean; -var - filepath: String; -begin - Result := False; - if AWebsite <> '' then - FWebsite := AWebsite; - if FWebsite = '' then - Exit; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; - if not FileExistsUTF8(filepath) then - Exit; - Result := InternalOpen(filepath); -end; - -function TDBDataProcess.Open(AWebsite: String): Boolean; -var - filepath: String; -begin - Result := False; - Self.Close; - if AWebsite <> '' then - FWebsite := AWebsite; - if FWebsite = '' then - Exit; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; - if not FileExistsUTF8(filepath) then - ConvertDataProccessToDB(AWebsite, True); - if not FileExistsUTF8(filepath) then - Exit; - try - if InternalOpen(filepath) then - begin - if not TableExist(FTableName) then - CreateTable; - OpenTable(FTableName, True); - end; - Result := FQuery.Active; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Open.Error!', E, Self); - end; -end; - -function TDBDataProcess.OpenTable(const ATableName: String; - CheckRecordCount: Boolean): Boolean; -begin - Result := False; - if FConn.Connected then - begin - try - if ATableName <> '' then - FTableName := ATableName; - if FTableName = '' then - Exit; - if TableExist(FTableName) then - begin - if FQuery.Active then - FQuery.Close; - FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); - FQuery.SQL.Text := FSQLSelect; - FQuery.Open; - if CheckRecordCount then - GetRecordCount; - end; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].OpenTable.Error!', E, Self); - end; - end; - Result := FQuery.Active; - if Result then ConvertNewTable; -end; - -function TDBDataProcess.TableExist(const ATableName: String): Boolean; -var - ts: TStringList; - i: Integer; -begin - Result := False; - if FConn.Connected then - begin - ts := TStringList.Create; - try - FConn.GetTableNames(ts); - ts.Sorted := True; - Result := ts.Find(ATableName, i); - finally - ts.Free; - end; - end; -end; - -procedure TDBDataProcess.Close; -begin - FRecordCount := 0; - if FConn.Connected then - try - FQuery.Close; - RemoveFilter; - FConn.Close; - FConn.DatabaseName := ''; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Close.Error!', E, Self); - end; -end; - -procedure TDBDataProcess.CloseTable; -begin - if FQuery.Active then - begin - FRecordCount := 0; - RemoveFilter; - FQuery.Close; - end; -end; - -procedure TDBDataProcess.Save; -begin - Commit; -end; - -procedure TDBDataProcess.Backup(AWebsite: String); -begin - if AWebsite = '' then - Exit; - if FConn.Connected then - begin - with TSQLite3Backup.Create do - try - Backup(FConn, fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); - finally - Free; - end; - end; -end; - -procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); -begin - if FConn.Connected then - begin - if FQuery.Active then - FQuery.Refresh - else - if Trim(FQuery.SQL.Text) <> '' then - FQuery.Open; - if RecheckDataCount then - GetRecordCount; - end; -end; - -function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, - Status, Summary: String; NumChapter, JDN: Integer): Boolean; -begin - Result:=False; - if FConn.Connected=False then Exit; - try - FConn.ExecuteDirect( - 'INSERT INTO "'+FTableName+'" ('+DBDataProcessParam+') VALUES ("'+ - Title+'","'+ - Link+'","'+ - Authors+'","'+ - Artists+'","'+ - Genres+'","'+ - Status+'","'+ - Summary+'","'+ - IntToStr(NumChapter)+'","'+ - IntToStr(JDN)+'")'); - Result:=True; - except - end; -end; - -function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, - Status, Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; -begin - Result := AddData(Title, Link, Authors, Artists, Genres, Status, Summary, - NumChapter, DateToJDN(JDN)); -end; - -procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, - Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String); -var - sql: String; -begin - if Link='' then Exit; - if FConn.Connected=False then Exit; - try - sql:='UPDATE "'; - if (AWebsite<>'') and (AWebsite<>FWebsite) and FAllSitesAttached then - sql+=AWebsite+'"."'+FTableName - else - sql+=FTableName; - sql+='" SET "title"="'+Title+ - '","authors"="'+Authors+ - '","artists"="'+Artists+ - '","genres"="'+Genres+ - '","status"="'+Status+ - '","summary"="'+Summary+ - '","numchapter"="'+IntToStr(NumChapter)+'"'; - sql+=' WHERE "link"="'+Link+'"'; - FConn.ExecuteDirect(sql); - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].UpdateData.Error!'#13#10'SQL = '+sql, E, Self); - end; -end; - -procedure TDBDataProcess.Commit; -var - queryactive: Boolean; -begin - if FConn.Connected then - try - queryactive := FQuery.Active; - if FQuery.Active then FQuery.Close; - FTrans.Commit; - if FQuery.Active <> queryactive then - FQuery.Active := queryactive; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Commit.Error!',E,Self); - end; -end; - -procedure TDBDataProcess.Rollback; -begin - if FConn.Connected then - try - FTrans.Rollback; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Rollback.Error!',E,Self); - end; -end; - -function TDBDataProcess.Search(ATitle: String): Boolean; -var - i: Integer; -begin - if FQuery.Active then - begin - try - FQuery.Close; - with FQuery do - begin - SQL.Clear; - if FFilterApplied then - SQL.AddText(FFilterSQL) - else - SQL.Add(FSQLSelect); - if ATitle <> '' then - begin - if not FFilterApplied then - SQL.Add('WHERE'); - if FAllSitesAttached then - begin - if SQL.Count > 0 then - begin - i := 0; - while i < SQL.Count do - begin - if (SQL[i] = 'UNION ALL') or (SQL[i] = ')') then - begin - SQL.Insert(i, 'AND'); - SQL.Insert(i + 1, '"title" LIKE ' + QuotedLike(ATitle)); - Inc(i, 3); - end - else - Inc(i); - end; - end; - end - else - AddSQLSimpleFilter('title', ATitle); - FFiltered := True; - end - else - FFiltered := FFilterApplied; - end; - FQuery.Open; - GetRecordCount; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Search.Error!'#13#10 + - 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); - end; - end; - Result := FQuery.Active; - if not Result then - begin - FFiltered := False; - FRecordCount := 0; - end; -end; - -function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; -begin - Result := False; - if not FQuery.Active then - Exit; - if ((stTitle = '') and - (stAuthors = '') and - (stArtists = '') and - (stSummary = '') and - (stStatus = '2') and - (checkedGenres.Count = 0) and - (uncheckedGenres.Count = 0)) and - (not searchNewManga) and - haveAllChecked then - Result := False - else - Result := True; -end; - -function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; - useRegExpr: Boolean): Boolean; -var - tsql: String; - i: Integer; - filtersingle: Boolean = True; - - procedure GenerateSQLFilter; - var - j: Integer; - begin - // filter new manga based on date - if searchNewManga then - AddSQLCond('"jdn" > ' + - QuotedStrd(IntToStr(DateToJDN(Now)-minusDay))); - - // filter title - AddSQLSimpleFilter('title', stTitle, False, False, useRegExpr); - - // filter authors - AddSQLSimpleFilter('authors', stAuthors, False, False, useRegExpr); - - // filter artists - AddSQLSimpleFilter('artists', stArtists, False, False, useRegExpr); - - // filter summary - AddSQLSimpleFilter('summary', stSummary, False, False, useRegExpr); - - // filter status - if stStatus <> '2' then - AddSQLCond('"status"=' + QuotedStrd(stStatus)); - - //filter checked genres - if checkedGenres.Count > 0 then - begin - AddSQLCond('('); - for j := 0 to checkedGenres.Count - 1 do - AddSQLSimpleFilter('genres', checkedGenres[j], False, - (not haveAllChecked), useRegExpr); - FQuery.SQL.Add(')'); - end; - - //filter unchecked genres - if uncheckedGenres.Count > 0 then - begin - AddSQLCond('('); - for j := 0 to uncheckedGenres.Count - 1 do - AddSQLSimpleFilter('genres', uncheckedGenres[j], True, - (not haveAllChecked), useRegExpr); - FQuery.SQL.Add(')'); - end; - end; - -begin - Result := False; - if FQuery.Active = False then - Exit; - if not CanFilter(checkedGenres, uncheckedGenres, stTitle, stAuthors, - stArtists, stStatus, stSummary, minusDay, haveAllChecked, searchNewManga) then - Exit; - with FQuery do - begin - FQuery.Close; - FRecordCount := 0; - tsql := SQL.Text; - SQL.Clear; - try - if FFilterAllSites and (FSitesList.Count > 0) then - begin - AttachAllSites; - if FAttachedSites.Count > 0 then - begin - SQL.Add('SELECT * FROM'); - SQL.Add('('); - SQL.Add('SELECT *, ' + QuotedStrd(FWebsite) + ' AS "website" FROM ' + - QuotedStrd(FTableName)); - SQL.Add('WHERE'); - GenerateSQLFilter; - for i := 0 to FAttachedSites.Count - 1 do - begin - SQL.Add('UNION ALL'); - SQL.Add('SELECT *, ' + QuotedStrd(FAttachedSites[i]) + - ' AS "website" FROM ' + - QuotedStrd(FAttachedSites[i]) + '.' + QuotedStrd(FTableName)); - SQL.Add('WHERE'); - GenerateSQLFilter; - end; - SQL.Add(')'); - SQL.Add('ORDER BY "title" COLLATE NATCMP'); - filtersingle := False; - end; - end; - - if filtersingle then - begin - SQL.Add(FSQLSelect); - SQL.Add('WHERE'); - GenerateSQLFilter; - end; - - FQuery.Open; - FFiltered := Active; - FFilterApplied := FFiltered; - if FFilterApplied then - FFilterSQL := SQL.Text - else - FFilterSQL := ''; - except - on E: Exception do - begin - WriteLog_E('TDBDataProcess['+Website+'].Filter.Error!'#13#10 + - 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); - FQuery.Close; - SQL.Text := tsql; - FQuery.Open; - FFilterAllSites := False; - FFiltered := False; - FFilterApplied := False; - FFilterSQL := ''; - end; - end; - GetRecordCount; - Result := FFiltered; - end; -end; - -function TDBDataProcess.LocateByLink(ALink: String): Boolean; -begin - Result := False; - if (FQuery.Active) and (FRecordCount > 0) and (ALink <> '') then - try - Result := FQuery.Locate('link', ALink, [loCaseInsensitive]); - except - on E: Exception do - WriteLog_E('TDBDataProcess.LocateByLink.Error!', E, Self); - end; -end; - -procedure TDBDataProcess.CreateDatabase(AWebsite: String); -var - filepath: String; -begin - if AWebsite <> '' then FWebsite := AWebsite; - if FWebsite = '' then Exit; - Close; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; - if FileExistsUTF8(filepath) then - DeleteFileUTF8(filepath); - InternalOpen(filepath); - CreateTable; -end; - -procedure TDBDataProcess.GetFieldNames(List: TStringList); -begin - if (List <> nil) and (FQuery.Active) then - FQuery.GetFieldNames(List); -end; - -procedure TDBDataProcess.RemoveFilter; -begin - if FFiltered then - begin - FFilterAllSites := False; - FFiltered := False; - FFilterApplied := False; - FFilterSQL := ''; - FQuery.SQL.Text := FSQLSelect; - FRecordCount := 0; - DetachAllSites; - if FQuery.Active then - begin - OpenTable; - GetRecordCount; - end; - end; -end; - -procedure TDBDataProcess.Sort; -var - queryactive: Boolean; -begin - if FConn.Connected then - begin - queryactive := FQuery.Active; - FQuery.Close; - with FConn do - try - ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName + '_ordered')); - ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + - DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO '+QuotedStrd(FTableName + '_ordered') + - ' SELECT * FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); - ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + - 'RENAME TO ' + QuotedStrd(FTableName)); - FTrans.Commit; - VacuumTable; - except - on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Sort.Error!', E, Self); - end; - if FQuery.Active <> queryactive then - FQuery.Active := queryactive; - end; -end; - -function TDBDataProcess.WebsiteLoaded(const AWebsite: String): Boolean; -var - i: Integer; -begin - Result := False; - if FWebsite = AWebsite then - Exit(True); - if FAllSitesAttached then - for i := 0 to FAttachedSites.Count - 1 do - if FAttachedSites[i] = AWebsite then - begin - Result := True; - Break; - end; -end; - -function TDBDataProcess.LinkExist(ALink: String): Boolean; -var - i: Integer; -begin - if Assigned(FLinks) then - Result := FLinks.Find(ALink, i) - else - Result := False; -end; - -procedure TDBDataProcess.InitLocateLink; -begin - if Assigned(FLinks) then - FLinks.Clear - else - FLinks := TStringList.Create; - FLinks.Sorted := False; - if FQuery.Active then - begin - FQuery.First; - repeat - FLinks.Add(FQuery.Fields[1].AsString); - FQuery.Next; - until FQuery.EOF; - if FLinks.Count > 0 then - FLinks.Sorted := True; - end; -end; - -procedure TDBDataProcess.DoneLocateLink; -begin - if Assigned(FLinks) then - FreeAndNil(FLinks); -end; - // ----- TDataProcess ----- constructor TDataProcess.Create; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index a32be9819..d5fe7389e 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, - uBaseUnit, uFMDThread, uTranslation, uMisc, WebsiteModules; + uBaseUnit, uFMDThread, uTranslation, uMisc, WebsiteModules, DBDataProcess; type TUpdateMangaManagerThread = class; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index da65a072e..e71076480 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, frmDropTarget, frmAccountManager, CheckUpdate, accountmanagerdb, - mangafoxwatermarkremover, SimpleException, SimpleLogger; + DBDataProcess, mangafoxwatermarkremover, SimpleException, SimpleLogger; type From 46c8fc08be35612cc7224084d67059e48436415b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 20:04:38 +0800 Subject: [PATCH 0781/2794] dbdataprocess, clean up --- baseunits/DBDataProcess.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 0b9b66f25..a61d82394 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -5,9 +5,8 @@ interface uses - Classes, SysUtils, FileUtil, LazFileUtils, sqlite3conn, - sqlite3backup, sqlite3dyn, sqldb, DB, SimpleLogger, dateutils, - RegExpr; + Classes, SysUtils, FileUtil, LazFileUtils, sqlite3conn, sqlite3backup, + sqlite3dyn, sqldb, DB, dateutils, RegExpr; type @@ -134,7 +133,7 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); implementation uses - uBaseUnit, uData, uMisc; + uBaseUnit, uData, uMisc, SimpleLogger; function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; From 396ace869f8f424bcccf3e526d06a2e5e5682744 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 20:19:47 +0800 Subject: [PATCH 0782/2794] frmmain, fix wrong align error load in lazarus docked form editor --- mangadownloader/forms/frmMain.lfm | 2 -- 1 file changed, 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index db570a925..270eb130b 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4,7 +4,6 @@ object MainForm: TMainForm Top = 96 Width = 819 ActiveControl = pcMain - Align = alBottom Caption = 'Free Manga Downloader' ClientHeight = 616 ClientWidth = 819 @@ -13,7 +12,6 @@ object MainForm: TMainForm OnDestroy = FormDestroy OnShow = FormShow OnWindowStateChange = FormWindowStateChange - LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 From a7cc69dfe0b2fa51e1e3b3847c4c89adbcfcaecf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Jan 2016 22:17:32 +0800 Subject: [PATCH 0783/2794] madokami, fix series title on update list --- baseunits/modules/Madokami.pas | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 4a37b0a4f..61077e0c1 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -99,23 +99,23 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; currentdir: Integer; s: String; begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - currentdir := StrToIntDef(AURL, 0); - if currentdir > Length(madokamidirlist) then Exit; - if MangaInfo.FHTTP.GET(Module.RootURL + madokamidirlist[currentdir]) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + currentdir:=StrToIntDef(AURL,0); + if currentdir>Length(madokamidirlist) then Exit; + if MangaInfo.FHTTP.GET(Module.RootURL+madokamidirlist[currentdir]) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do begin - s := v.toString; - if Length(s) > 1 then begin - if s[Length(s)] = '/' then SetLength(s, Length(s) - 1); - ANames.Add(v.toString); - ALinks.Add(v.toNode.getAttribute('href')); - end; + ALinks.Add(v.toNode.getAttribute('href')); + s:=v.toString; + if Length(s)>1 then + if s[Length(s)]='/' then + SetLength(s,Length(s)-1); + ANames.Add(s); end; finally query.Free; From 40f81ea3cc0611c922a31ca903a9022d5b4d53d7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 14:35:22 +0800 Subject: [PATCH 0784/2794] ehentai, strip all url parameter to avoid wrong page detection #158 --- baseunits/modules/EHentai.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 1cfff7961..a6bc19c3a 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -191,7 +191,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; if MangaInfo = nil then Exit; with MangaInfo.mangaInfo do begin website := Module.Website; - url := FillHost(Module.RootURL, AURL); + url:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); + url:=AppendURLDelim(FillHost(Module.RootURL,url)); if GETWithLogin(MangaInfo.FHTTP, url, Module.Website) then begin Result := NO_ERROR; // if there is only 1 line, it's banned message! @@ -262,7 +263,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; - rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); + rurl:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); + rurl:=AppendURLDelim(FillHost(Module.RootURL,rurl)); if GETWithLogin(DownloadThread.FHTTP, rurl, Module.Website) then begin Result := True; query := TXQueryEngineHTML.Create; From acaeda3b9160e3895d1aa432b1aacd572dd44d7a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 15:05:54 +0800 Subject: [PATCH 0785/2794] ehentai, fix wrong page number, incorrect sub page url fix #158 --- baseunits/modules/EHentai.pas | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index a6bc19c3a..3cc5a2e75 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,11 +6,11 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, synacode; + accountmanagerdb; implementation -uses RegExpr; +uses RegExpr, synacode; const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; @@ -214,23 +214,25 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; - v: IXQValue; rurl: String; procedure GetImageLink; + var + x: IXQValue; begin - for v in query.XPath('//div[@id="gdt"]//a/@href') do - with DownloadThread.manager.container do begin + with DownloadThread.manager.container do begin + for x in query.XPath('//div[@id="gdt"]//a/@href') do + PageContainerLinks.Add(x.toString); + while PageLinks.Count<PageContainerLinks.Count do PageLinks.Add('G'); - PageContainerLinks.Add(v.toString); - end; + end; end; procedure ScanParse; var getOK: Boolean; i, p: Integer; - //s: String; + v: IXQValue; begin getOK := True; //check content warning @@ -244,11 +246,12 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; begin GetImageLink; //get page count - p := StrToIntDef(query.CSSString( - 'table.ptt>tbody>tr>td:nth-last-child(2)>a'), 1) - 1; + p:=0; + v:=query.XPath('//table[@class="ptt"]//td'); + if v.Count>2 then p:=StrToIntDef(v.get(v.Count-2).toString,0); if p > 0 then for i := 1 to p do - if GETWithLogin(DownloadThread.FHTTP, rurl + '?p' + IntToStr(i), Module.Website) then + if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then begin query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); GetImageLink; From 146b7f169cdb03b33bece473c55c7f05d4c409d8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 15:20:34 +0800 Subject: [PATCH 0786/2794] corrected log message --- baseunits/DBDataProcess.pas | 34 +++++++++++++++---------------- mangadownloader/forms/frmMain.pas | 20 +++++++++--------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index a61d82394..4b06a2acb 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -356,7 +356,7 @@ procedure TDBDataProcess.VacuumTable; ExecuteDirect('VACUUM'); except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].VacuumTable.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].VacuumTable.Error!', E, Self); end; ExecuteDirect('BEGIN TRANSACTION'); end; @@ -436,7 +436,7 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; except on E: Exception do begin - WriteLog_E('TDBDataProcess['+Website+'].InternalOpen.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].InternalOpen.Error!', E, Self); Result := False; end; end; @@ -452,7 +452,7 @@ function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; Result := FQuery.FieldByName('website').AsString; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].GetWebsiteName', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].GetWebsiteName', E, Self); end; end; @@ -470,7 +470,7 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].GetParam.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].GetParam.Error!', E, Self); end; end; @@ -508,7 +508,7 @@ procedure TDBDataProcess.AttachAllSites; end; except on E: Exception do - Writelog_E('TDBDataProcess['+Website+'].AttachAllSites.Error!', E, Self) + Writelog_E(Self.ClassName+'['+Website+'].AttachAllSites.Error!', E, Self) end; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := FAttachedSites.Count > 0; @@ -530,7 +530,7 @@ procedure TDBDataProcess.DetachAllSites; FAttachedSites.Delete(i); except on E: Exception do - Writelog_E('TDBDataProcess['+Website+'].DetachAllSites.Error!', E, Self); + Writelog_E(Self.ClassName+'['+Website+'].DetachAllSites.Error!', E, Self); end; end; FConn.ExecuteDirect('BEGIN TRANSACTION'); @@ -547,7 +547,7 @@ function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; Result := True; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].ExecuteDirect.Error!'#13#10 + + WriteLog_E(Self.ClassName+'['+Website+'].ExecuteDirect.Error!'#13#10 + 'SQL: ' + SQL, E, Self); end; end; @@ -587,7 +587,7 @@ destructor TDBDataProcess.Destroy; end; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Destroy.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].Destroy.Error!', E, Self); end; DoneLocateLink; FAttachedSites.Free; @@ -639,7 +639,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; Result := FQuery.Active; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Open.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].Open.Error!', E, Self); end; end; @@ -666,7 +666,7 @@ function TDBDataProcess.OpenTable(const ATableName: String; end; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].OpenTable.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].OpenTable.Error!', E, Self); end; end; Result := FQuery.Active; @@ -703,7 +703,7 @@ procedure TDBDataProcess.Close; FConn.DatabaseName := ''; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Close.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].Close.Error!', E, Self); end; end; @@ -804,7 +804,7 @@ procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, FConn.ExecuteDirect(sql); except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].UpdateData.Error!'#13#10'SQL = '+sql, E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].UpdateData.Error!'#13#10'SQL = '+sql, E, Self); end; end; @@ -821,7 +821,7 @@ procedure TDBDataProcess.Commit; FQuery.Active := queryactive; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Commit.Error!',E,Self); + WriteLog_E(Self.ClassName+'['+Website+'].Commit.Error!',E,Self); end; end; @@ -832,7 +832,7 @@ procedure TDBDataProcess.Rollback; FTrans.Rollback; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Rollback.Error!',E,Self); + WriteLog_E(Self.ClassName+'['+Website+'].Rollback.Error!',E,Self); end; end; @@ -884,7 +884,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; GetRecordCount; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Search.Error!'#13#10 + + WriteLog_E(Self.ClassName+'['+Website+'].Search.Error!'#13#10 + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); end; end; @@ -1029,7 +1029,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList except on E: Exception do begin - WriteLog_E('TDBDataProcess['+Website+'].Filter.Error!'#13#10 + + WriteLog_E(Self.ClassName+'['+Website+'].Filter.Error!'#13#10 + 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); FQuery.Close; SQL.Text := tsql; @@ -1118,7 +1118,7 @@ procedure TDBDataProcess.Sort; VacuumTable; except on E: Exception do - WriteLog_E('TDBDataProcess['+Website+'].Sort.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].Sort.Error!', E, Self); end; if FQuery.Active <> queryactive then FQuery.Active := queryactive; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e71076480..d997f73d2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1111,12 +1111,12 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin - WriteLog_V('FormClose action'); + WriteLog_V(Self.ClassName+'.FormClose action'); if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then begin - WriteLog_V('FormClose aborted'); + WriteLog_V(Self.ClassName+'.FormClose aborted'); CloseAction := caNone; Exit; end; @@ -1127,7 +1127,7 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin - WriteLog_V('FormClose.CloseNow, terminating all threads and waitfor'); + WriteLog_V(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin @@ -1159,7 +1159,7 @@ procedure TMainForm.CloseNow; SilentThreadManager.StopAll(True); DLManager.StopAllDownloadTasksForExit; - WriteLog_V('FormClose.CloseNow, disabling all timer'); + WriteLog_V(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; itSaveDownloadedList.Enabled := False; itRefreshDLInfo.Enabled := False; @@ -1168,7 +1168,7 @@ procedure TMainForm.CloseNow; itStartup.Enabled := False; itMonitor.Enabled := False; - WriteLog_V('FormClose.CloseNow, backup all data to file'); + WriteLog_V(Self.ClassName+'.CloseNow, backup all data to file'); //Backup data DLManager.Backup; DLManager.BackupDownloadedChaptersList; @@ -1177,7 +1177,7 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; - WriteLog_V('FormClose.CloseNow, closing other forms'); + WriteLog_V(Self.ClassName+'.CloseNow, closing other forms'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; @@ -1187,7 +1187,7 @@ procedure TMainForm.CloseNow; if FMDInstance <> nil then begin - WriteLog_V('FormClose.CloseNow, stop ipc server'); + WriteLog_V(Self.ClassName+'.CloseNow, stop ipc server'); FMDInstance.StopServer; FreeAndNil(FMDInstance); end; @@ -1195,7 +1195,7 @@ procedure TMainForm.CloseNow; procedure TMainForm.FormDestroy(Sender: TObject); begin - WriteLog_V('FormDestroy, freeing all objects'); + WriteLog_V(Self.ClassName+'.FormDestroy, freeing all objects'); SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); @@ -5089,9 +5089,9 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); procedure TMainForm.DoExitWaitCounter; begin - Writelog_V('Execute exit counter'); + Writelog_V(Self.ClassName+'Execute exit counter'); if isUpdating then begin - Writelog_V('Update thread still exist, pending exit counter'); + Writelog_V(Self.ClassName+'Update thread still exist, pending exit counter'); isPendingExitCounter:=True end else itMonitor.Enabled:=True; From 99f540d26069cabf04f135768a18f80431a9dd3f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 17:04:55 +0800 Subject: [PATCH 0787/2794] updatemanager, change temporary database name for update list --- baseunits/uUpdateThread.pas | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index d5fe7389e..be0826701 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -63,7 +63,7 @@ TUpdateMangaManagerThread = class(TFMDThread) mainDataProcess: TDBDataProcess; tempDataProcess: TDBDataProcess; websites: TStringList; - website, twebsite: String; + website, twebsite, twebsitetemp: String; ModuleId: Integer; workPtr, directoryCount, // for fakku's doujinshi only @@ -366,9 +366,9 @@ destructor TUpdateMangaManagerThread.Destroy; if not FThreadEndNormally then WriteLog_W(Self.ClassName+', thread doesn''t end normally, ended by user?'); websites.Free; mainDataProcess.Close; - DeleteDBDataProcess(twebsite); tempDataProcess.Close; - DeleteDBDataProcess('__tempupdatelist'); + DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); mainDataProcess.Free; tempDataProcess.Free; threads.Free; @@ -580,7 +580,6 @@ procedure TUpdateMangaManagerThread.Execute; while websitePtr < websites.Count do begin FThreadAborted:=True; - tempDataProcess.CreateDatabase('__tempupdatelist'); website := websites.Strings[websitePtr]; ModuleId := Modules.LocateModule(website); SortedList := SitesWithSortedList(website); @@ -595,8 +594,10 @@ procedure TUpdateMangaManagerThread.Execute; [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); - twebsite := '__' + website; + twebsite:='__'+website; + twebsitetemp:=twebsite+'_templist'; DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); if (MainForm.dataProcess.Website = website) and (MainForm.dataProcess.Connected) then MainForm.dataProcess.Backup(twebsite) @@ -609,6 +610,7 @@ procedure TUpdateMangaManagerThread.Execute; if not mainDataProcess.Connect(twebsite) then mainDataProcess.CreateDatabase(twebsite); + tempDataProcess.CreateDatabase(twebsitetemp); mainDataProcess.OpenTable('',True); FIsPreListAvailable:=mainDataProcess.RecordCount>0; @@ -713,6 +715,7 @@ procedure TUpdateMangaManagerThread.Execute; tempDataProcess.Close; mainDataProcess.Close; DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); if Terminated then Break; From 83d15b1bb114523f2aab2c55e60cc33074c1acbb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 21:20:56 +0800 Subject: [PATCH 0788/2794] dbdataprocess, fix sql insert update statements --- baseunits/DBDataProcess.pas | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 4b06a2acb..e89f63afb 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -758,16 +758,16 @@ function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, if FConn.Connected=False then Exit; try FConn.ExecuteDirect( - 'INSERT INTO "'+FTableName+'" ('+DBDataProcessParam+') VALUES ("'+ - Title+'","'+ - Link+'","'+ - Authors+'","'+ - Artists+'","'+ - Genres+'","'+ - Status+'","'+ - Summary+'","'+ - IntToStr(NumChapter)+'","'+ - IntToStr(JDN)+'")'); + 'INSERT INTO '+QuotedStrd(FTableName)+' ('+DBDataProcessParam+') VALUES ('+ + QuotedStr(Title)+', '+ + QuotedStr(Link)+', '+ + QuotedStr(Authors)+', '+ + QuotedStr(Artists)+', '+ + QuotedStr(Genres)+', '+ + QuotedStr(Status)+', '+ + QuotedStr(Summary)+', '+ + QuotedStr(IntToStr(NumChapter))+', '+ + QuotedStr(IntToStr(JDN))+');'); Result:=True; except end; @@ -788,19 +788,19 @@ procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, if Link='' then Exit; if FConn.Connected=False then Exit; try - sql:='UPDATE "'; + sql:='UPDATE '; if (AWebsite<>'') and (AWebsite<>FWebsite) and FAllSitesAttached then - sql+=AWebsite+'"."'+FTableName + sql+=QuotedStrd(AWebsite)+'.'+QuotedStrd(FTableName) else - sql+=FTableName; - sql+='" SET "title"="'+Title+ - '","authors"="'+Authors+ - '","artists"="'+Artists+ - '","genres"="'+Genres+ - '","status"="'+Status+ - '","summary"="'+Summary+ - '","numchapter"="'+IntToStr(NumChapter)+'"'; - sql+=' WHERE "link"="'+Link+'"'; + sql+=QuotedStrd(FTableName); + sql+=' SET "title"='+QuotedStr(Title)+ + ', "authors"='+QuotedStr(Authors)+ + ', "artists"='+QuotedStr(Artists)+ + ', "genres"='+QuotedStr(Genres)+ + ', "status"='+QuotedStr(Status)+ + ', "summary"='+QuotedStr(Summary)+ + ', "numchapter"='+QuotedStr(IntToStr(NumChapter))+ + ' WHERE ("link"='+QuotedStr(Link)+');'; FConn.ExecuteDirect(sql); except on E: Exception do From 01ce8da0eaa0497708f179017cc45b0dc86d7d7d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 21:30:44 +0800 Subject: [PATCH 0789/2794] dbdataprocess, fix search and filter. properly escape quote. --- baseunits/DBDataProcess.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index e89f63afb..c6db9f905 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -179,7 +179,7 @@ procedure RegexCallback(context: PSqlite3_Context; argc: longint; function QuotedLike(const S: String): String; begin - Result := QuotedStrd(AnsiQuotedStr(S, '%')); + Result := QuotedStr('%'+S+'%'); end; function DBDataFilePath(const AWebsite: String): String; @@ -408,7 +408,7 @@ procedure TDBDataProcess.AddSQLSimpleFilter(const fieldname, Value: String; else scond := ''; if useRegexp then - AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStrd(svalue), useOR) + AddSQLCond(QuotedStrd(fieldname) + scond + ' REGEXP ' + QuotedStr(svalue), useOR) else AddSQLCond(QuotedStrd(fieldname) + scond + ' LIKE ' + QuotedLike(svalue), useOR); end; From 97462e1ce0ac6b140b5c0dfb110fa38c25588f9d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 23:28:47 +0800 Subject: [PATCH 0790/2794] more verbose log --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 270eb130b..a2617648d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -12,6 +12,7 @@ object MainForm: TMainForm OnDestroy = FormDestroy OnShow = FormShow OnWindowStateChange = FormWindowStateChange + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d997f73d2..a9a137bab 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1128,36 +1128,46 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin WriteLog_V(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); + FavoriteManager.StopChekForNewChapter(True); + SilentThreadManager.StopAll(True); + DLManager.StopAllDownloadTasksForExit; //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin + WriteLog_V(Self.ClassName+'.CloseNow, terminating CheckUpdateThread'); CheckUpdateThread.Terminate; CheckUpdateThread.WaitFor; + WriteLog_V(Self.ClassName+'.CloseNow, CheckUpdateThread terminated'); end; if Assigned(SearchDBThread) then begin + WriteLog_V(Self.ClassName+'.CloseNow, terminating SearchDBThread'); SearchDBThread.Terminate; SearchDBThread.WaitFor; + WriteLog_V(Self.ClassName+'.CloseNow, SearchDBThread terminated'); end; if Assigned(OpenDBThread) then begin + WriteLog_V(Self.ClassName+'.CloseNow, terminating OpenDBThread'); OpenDBThread.Terminate; OpenDBThread.WaitFor; + WriteLog_V(Self.ClassName+'.CloseNow, OpenDBThread terminated'); end; if isGetMangaInfos then begin + WriteLog_V(Self.ClassName+'.CloseNow, terminating GetInfosThread'); GetInfosThread.IsFlushed := True; GetInfosThread.Terminate; GetInfosThread.WaitFor; + WriteLog_V(Self.ClassName+'.CloseNow, GetInfosThread terminated'); end; if isUpdating then begin + WriteLog_V(Self.ClassName+'.CloseNow, terminating UpdateListThread'); updateList.Terminate; updateList.WaitFor; + WriteLog_V(Self.ClassName+'.CloseNow, UpdateListThread terminated'); end; - FavoriteManager.StopChekForNewChapter(True); - SilentThreadManager.StopAll(True); - DLManager.StopAllDownloadTasksForExit; WriteLog_V(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; @@ -5089,9 +5099,9 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); procedure TMainForm.DoExitWaitCounter; begin - Writelog_V(Self.ClassName+'Execute exit counter'); + Writelog_V(Self.ClassName+', Execute exit counter'); if isUpdating then begin - Writelog_V(Self.ClassName+'Update thread still exist, pending exit counter'); + Writelog_V(Self.ClassName+', Update thread still exist, pending exit counter'); isPendingExitCounter:=True end else itMonitor.Enabled:=True; From 4154d14664d3e674366076fd083b98b009ddc6b7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 23:39:32 +0800 Subject: [PATCH 0791/2794] corrected log message --- baseunits/uUpdateThread.pas | 28 +++++++++++----------- mangadownloader/forms/frmMain.pas | 40 +++++++++++++++---------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index be0826701..d0d00d90d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -302,7 +302,7 @@ procedure TUpdateMangaManagerThread.MainThreadEndGetting; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; MainForm.isUpdating:=False; if MainForm.isPendingExitCounter then begin - WriteLog_V(Self.ClassName+', pending exit counter executed'); + Writelog_D(Self.ClassName+', pending exit counter executed'); MainForm.DoExitWaitCounter; end; end; @@ -560,7 +560,7 @@ procedure TUpdateMangaManagerThread.Execute; begin if websites.Count = 0 then Exit; - WriteLog_V(Self.ClassName+', thread started'); + Writelog_D(Self.ClassName+', thread started'); try websitePtr := 0; if isDownloadFromServer then @@ -587,9 +587,9 @@ procedure TUpdateMangaManagerThread.Execute; Inc(websitePtr); cloghead:=Self.ClassName+', '+website+': '; - WriteLog_V(cloghead+'update list started'); - WriteLog_V(cloghead+'sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); - WriteLog_V(cloghead+'prepare database file'); + Writelog_D(cloghead+'update list started'); + Writelog_D(cloghead+'sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); + Writelog_D(cloghead+'prepare database file'); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); @@ -616,7 +616,7 @@ procedure TUpdateMangaManagerThread.Execute; FIsPreListAvailable:=mainDataProcess.RecordCount>0; mainDataProcess.CloseTable; - WriteLog_V(cloghead+'get number of directory page'); + Writelog_D(cloghead+'get number of directory page'); // get directory page count INIAdvanced.Reload; directoryCount := 0; @@ -625,7 +625,7 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; - WriteLog_V(cloghead+'get names and links'); + Writelog_D(cloghead+'get names and links'); // get names and links INIAdvanced.Reload; workPtr := 0; @@ -668,7 +668,7 @@ procedure TUpdateMangaManagerThread.Execute; // get manga info if tempDataProcess.RecordCount>0 then begin - WriteLog_V(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); + Writelog_D(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); workPtr := 0; FCommitCount := 0; if NoMangaInfo or @@ -694,12 +694,12 @@ procedure TUpdateMangaManagerThread.Execute; else GetInfo(tempDataProcess.RecordCount, CS_INFO); mainDataProcess.Commit; - WriteLog_V(cloghead+'get info finished '+IntToStr(workPtr)); + Writelog_D(cloghead+'get info finished '+IntToStr(workPtr)); if workPtr > 0 then if not (Terminated and SortedList) then begin - WriteLog_V(cloghead+'saving data '+IntToStr(workPtr)); + Writelog_D(cloghead+'saving data '+IntToStr(workPtr)); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; Synchronize(MainThreadShowGetting); @@ -708,10 +708,10 @@ procedure TUpdateMangaManagerThread.Execute; Synchronize(RefreshList); end else - WriteLog_V(cloghead+'sorted list, data abandoned'); + Writelog_D(cloghead+'sorted list, data abandoned'); end; - WriteLog_V(cloghead+'close database file'); + Writelog_D(cloghead+'close database file'); tempDataProcess.Close; mainDataProcess.Close; DeleteDBDataProcess(twebsite); @@ -721,7 +721,7 @@ procedure TUpdateMangaManagerThread.Execute; Break; websites[websitePtr - 1] := UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); - WriteLog_V(cloghead+'update list finished'); + Writelog_D(cloghead+'update list finished'); FThreadAborted:=False; end; except @@ -729,7 +729,7 @@ procedure TUpdateMangaManagerThread.Execute; MainForm.ExceptionHandler(Self, E); end; FThreadEndNormally:=True; - WriteLog_V(Self.ClassName+', thread ended normally'); + Writelog_D(Self.ClassName+', thread ended normally'); Synchronize(MainThreadEndGetting); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a9a137bab..b09673241 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1111,12 +1111,12 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin - WriteLog_V(Self.ClassName+'.FormClose action'); + Writelog_D(Self.ClassName+'.FormClose action'); if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then begin - WriteLog_V(Self.ClassName+'.FormClose aborted'); + Writelog_D(Self.ClassName+'.FormClose aborted'); CloseAction := caNone; Exit; end; @@ -1127,49 +1127,49 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin - WriteLog_V(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); + Writelog_D(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); FavoriteManager.StopChekForNewChapter(True); SilentThreadManager.StopAll(True); DLManager.StopAllDownloadTasksForExit; //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin - WriteLog_V(Self.ClassName+'.CloseNow, terminating CheckUpdateThread'); + Writelog_D(Self.ClassName+'.CloseNow, terminating CheckUpdateThread'); CheckUpdateThread.Terminate; CheckUpdateThread.WaitFor; - WriteLog_V(Self.ClassName+'.CloseNow, CheckUpdateThread terminated'); + Writelog_D(Self.ClassName+'.CloseNow, CheckUpdateThread terminated'); end; if Assigned(SearchDBThread) then begin - WriteLog_V(Self.ClassName+'.CloseNow, terminating SearchDBThread'); + Writelog_D(Self.ClassName+'.CloseNow, terminating SearchDBThread'); SearchDBThread.Terminate; SearchDBThread.WaitFor; - WriteLog_V(Self.ClassName+'.CloseNow, SearchDBThread terminated'); + Writelog_D(Self.ClassName+'.CloseNow, SearchDBThread terminated'); end; if Assigned(OpenDBThread) then begin - WriteLog_V(Self.ClassName+'.CloseNow, terminating OpenDBThread'); + Writelog_D(Self.ClassName+'.CloseNow, terminating OpenDBThread'); OpenDBThread.Terminate; OpenDBThread.WaitFor; - WriteLog_V(Self.ClassName+'.CloseNow, OpenDBThread terminated'); + Writelog_D(Self.ClassName+'.CloseNow, OpenDBThread terminated'); end; if isGetMangaInfos then begin - WriteLog_V(Self.ClassName+'.CloseNow, terminating GetInfosThread'); + Writelog_D(Self.ClassName+'.CloseNow, terminating GetInfosThread'); GetInfosThread.IsFlushed := True; GetInfosThread.Terminate; GetInfosThread.WaitFor; - WriteLog_V(Self.ClassName+'.CloseNow, GetInfosThread terminated'); + Writelog_D(Self.ClassName+'.CloseNow, GetInfosThread terminated'); end; if isUpdating then begin - WriteLog_V(Self.ClassName+'.CloseNow, terminating UpdateListThread'); + Writelog_D(Self.ClassName+'.CloseNow, terminating UpdateListThread'); updateList.Terminate; updateList.WaitFor; - WriteLog_V(Self.ClassName+'.CloseNow, UpdateListThread terminated'); + Writelog_D(Self.ClassName+'.CloseNow, UpdateListThread terminated'); end; - WriteLog_V(Self.ClassName+'.CloseNow, disabling all timer'); + Writelog_D(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; itSaveDownloadedList.Enabled := False; itRefreshDLInfo.Enabled := False; @@ -1178,7 +1178,7 @@ procedure TMainForm.CloseNow; itStartup.Enabled := False; itMonitor.Enabled := False; - WriteLog_V(Self.ClassName+'.CloseNow, backup all data to file'); + Writelog_D(Self.ClassName+'.CloseNow, backup all data to file'); //Backup data DLManager.Backup; DLManager.BackupDownloadedChaptersList; @@ -1187,7 +1187,7 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; - WriteLog_V(Self.ClassName+'.CloseNow, closing other forms'); + Writelog_D(Self.ClassName+'.CloseNow, closing other forms'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; @@ -1197,7 +1197,7 @@ procedure TMainForm.CloseNow; if FMDInstance <> nil then begin - WriteLog_V(Self.ClassName+'.CloseNow, stop ipc server'); + Writelog_D(Self.ClassName+'.CloseNow, stop ipc server'); FMDInstance.StopServer; FreeAndNil(FMDInstance); end; @@ -1205,7 +1205,7 @@ procedure TMainForm.CloseNow; procedure TMainForm.FormDestroy(Sender: TObject); begin - WriteLog_V(Self.ClassName+'.FormDestroy, freeing all objects'); + Writelog_D(Self.ClassName+'.FormDestroy, freeing all objects'); SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); @@ -5099,9 +5099,9 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); procedure TMainForm.DoExitWaitCounter; begin - Writelog_V(Self.ClassName+', Execute exit counter'); + Writelog_D(Self.ClassName+', Execute exit counter'); if isUpdating then begin - Writelog_V(Self.ClassName+', Update thread still exist, pending exit counter'); + Writelog_D(Self.ClassName+', Update thread still exist, pending exit counter'); isPendingExitCounter:=True end else itMonitor.Enabled:=True; From 7f701ffbd49615b2135e43291233bade36fc7572 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 14 Jan 2016 23:58:57 +0800 Subject: [PATCH 0792/2794] dbdataprocess, fix getvalue --- baseunits/DBDataProcess.pas | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index c6db9f905..ae2cc1237 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -458,19 +458,20 @@ function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; begin - if FieldIndex in [DATA_PARAM_NUMCHAPTER, DATA_PARAM_JDN] then - Result := '0' + if FieldIndex in [DATA_PARAM_NUMCHAPTER,DATA_PARAM_JDN] then + Result:='0' else - Result := ''; - if not FQuery.Active then Exit; - if FieldIndex >= Length(DBDataProcessParams) then Exit; - if (RecIndex < 0) and (RecIndex > FRecordCount) then Exit; + Result:=''; + if FQuery.Active=False then Exit; + if FieldIndex>=FQuery.Fields.Count then Exit; + if (RecIndex<0) or (RecIndex>FRecordCount) then Exit; try - FQuery.RecNo := RecIndex + 1; - Result := FQuery.FieldByName(DBDataProcessParams[FieldIndex]).AsString; + FQuery.RecNo:=RecIndex+1; + Result:=FQuery.Fields[FieldIndex].AsString; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].GetParam.Error!', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].GetValue.Error!'+ + 'RecIndex: '+IntToStr(RecIndex)+', FieldIndex: '+IntToStr(FieldIndex), E, Self); end; end; From 68b3653a1ae9dce2be2b9f3c15453cd4d0d300c9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 00:17:05 +0800 Subject: [PATCH 0793/2794] dbdataprocess, fix getwebsitename --- baseunits/DBDataProcess.pas | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index ae2cc1237..ad2487702 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -111,6 +111,7 @@ TDBDataProcess = class(TObject) DBDataProcessParams: array [0..8] of ShortString = ('title', 'link', 'authors', 'artists', 'genres', 'status', 'summary', 'numchapter', 'jdn'); + DBTempFieldWebsiteIndex = Length(DBDataProcessParams); DBDataProccesCreateParam = '('#13#10 + '"title" TEXT,'#13#10 + '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + @@ -445,14 +446,18 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; begin - Result := FWebsite; - if FQuery.Active and (FAttachedSites.Count > 0) then + Result:=FWebsite; + if FQuery.Active=False then Exit; + if DBTempFieldWebsiteIndex>=FQuery.Fields.Count then Exit; + if (RecIndex<0) or (RecIndex>FRecordCount) then Exit; + if FAttachedSites.Count>0 then try - FQuery.RecNo := RecIndex + 1; - Result := FQuery.FieldByName('website').AsString; + FQuery.RecNo:=RecIndex+1; + Result:=FQuery.Fields[DBTempFieldWebsiteIndex].AsString; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].GetWebsiteName', E, Self); + WriteLog_E(Self.ClassName+'['+Website+'].GetWebsiteName Error!'+ + 'RecIndex: '+IntToStr(RecIndex), E, Self); end; end; From 386edf6cdf1ecca7ad42f4c5463117e213942019 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 00:45:15 +0800 Subject: [PATCH 0794/2794] dbdataprocess, fix attach website, limit to 10 --- baseunits/DBDataProcess.pas | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index ad2487702..45ca502fa 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -504,17 +504,21 @@ procedure TDBDataProcess.AttachAllSites; DetachAllSites; FConn.ExecuteDirect('END TRANSACTION'); try - for i := 0 to SitesList.Count - 1 do + for i:=0 to SitesList.Count-1 do begin + //max attached database is 10 + if FAttachedSites.Count=10 then Break; if (FAttachedSites.IndexOf(SitesList[i]) = -1) and (FileExistsUTF8(DBDataFilePath(SitesList[i]))) then begin FConn.ExecuteDirect('ATTACH ' + - QuotedStrd(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); + QuotedStr(DBDataFilePath(SitesList[i])) + ' AS ' + QuotedStrd(SitesList[i])); FAttachedSites.Add(SitesList[i]); end; + end; except on E: Exception do - Writelog_E(Self.ClassName+'['+Website+'].AttachAllSites.Error!', E, Self) + Writelog_E(Self.ClassName+'['+Website+'].AttachAllSites.Error!'+ + ' try to attach '+QuotedStr(SitesList[i]), E, Self) end; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := FAttachedSites.Count > 0; From 31272280b0890cafd4be8d98ef3c34b83f9af914 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 00:47:46 +0800 Subject: [PATCH 0795/2794] dbdataprocess, disable attached databases limit, let library throw error and break --- baseunits/DBDataProcess.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 45ca502fa..63ea64bf7 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -506,7 +506,7 @@ procedure TDBDataProcess.AttachAllSites; try for i:=0 to SitesList.Count-1 do begin //max attached database is 10 - if FAttachedSites.Count=10 then Break; + //if FAttachedSites.Count=10 then Break; if (FAttachedSites.IndexOf(SitesList[i]) = -1) and (FileExistsUTF8(DBDataFilePath(SitesList[i]))) then begin From b27378ef96ec18c3ccd297342a48134eb8731188 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 01:57:05 +0800 Subject: [PATCH 0796/2794] added missing license notice --- baseunits/CheckUpdate.pas | 5 +++++ baseunits/DBDataProcess.pas | 5 +++++ baseunits/WebsiteModules.pas | 5 +++++ baseunits/accountmanagerdb.pas | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index dff1aca0e..6c04f8aac 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -1,3 +1,8 @@ +{ + License: GPLv2 + This unit is a part of Free Manga Downloader +} + unit CheckUpdate; {$mode objfpc}{$H+} diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 63ea64bf7..477ee1894 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -1,3 +1,8 @@ +{ + License: GPLv2 + This unit is a part of Free Manga Downloader +} + unit DBDataProcess; {$mode objfpc}{$H+} diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index fbc04b225..81781afa7 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -1,3 +1,8 @@ +{ + License: GPLv2 + This unit is a part of Free Manga Downloader +} + unit WebsiteModules; {$mode objfpc}{$H+} diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index cc6325a0a..a26408caa 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -1,3 +1,8 @@ +{ + License: GPLv2 + This unit is a part of Free Manga Downloader +} + unit accountmanagerdb; {$mode objfpc}{$H+} From 8644212ad3a0545afdd683dc5441ed57108c18f5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 03:22:21 +0800 Subject: [PATCH 0797/2794] more log for exit --- mangadownloader/forms/frmMain.pas | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b09673241..650117002 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -555,7 +555,8 @@ TMainForm = class(TForm) ulTotalPtr, ulWorkPtr: Integer; optionMangaSiteSelectionNodes: array of PVirtualNode; LastSearchStr, LastSearchWeb: String; - isStartup, isExiting, isRunDownloadFilter, isUpdating, isPendingExitCounter: Boolean; + isStartup, isExiting, isRunDownloadFilter, isUpdating, isPendingExitCounter, + isNormalExit: Boolean; revisionIni, updates, mangalistIni, options: TIniFile; FavoriteManager: TFavoriteManager; dataProcess: TDBDataProcess; @@ -960,6 +961,7 @@ procedure TMainForm.FormCreate(Sender: TObject); isExiting := False; isGetMangaInfos := False; isPendingExitCounter:=False; + isNormalExit:=False; DoAfterFMD := DO_NOTHING; Application.HintHidePause := 10000; sbUpdateList.DoubleBuffered := True; @@ -1201,6 +1203,7 @@ procedure TMainForm.CloseNow; FMDInstance.StopServer; FreeAndNil(FMDInstance); end; + isNormalExit:=True; end; procedure TMainForm.FormDestroy(Sender: TObject); @@ -1222,7 +1225,10 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(updates); FreeAndNil(options); FreeAndNil(INIAdvanced); - Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); + if isNormalExit then + Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']') + else + Writelog_W(QuotedStrd(Application.Title)+' doesn''t exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); end; procedure TMainForm.FormShow(Sender: TObject); From ce48d661a784c4f6540afb793f345a08f1aaa1a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 03:30:21 +0800 Subject: [PATCH 0798/2794] updatethread, put main jobs in try except clause --- baseunits/uUpdateThread.pas | 201 ++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 98 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index d0d00d90d..af6836c2d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -596,119 +596,124 @@ procedure TUpdateMangaManagerThread.Execute; twebsite:='__'+website; twebsitetemp:=twebsite+'_templist'; - DeleteDBDataProcess(twebsite); - DeleteDBDataProcess(twebsitetemp); - if (MainForm.dataProcess.Website = website) and - (MainForm.dataProcess.Connected) then - MainForm.dataProcess.Backup(twebsite) - else - begin - if MainForm.dataProcess.WebsiteLoaded(website) then - Synchronize(MainThreadRemoveFilter); - CopyDBDataProcess(website, twebsite); - end; - - if not mainDataProcess.Connect(twebsite) then - mainDataProcess.CreateDatabase(twebsite); - tempDataProcess.CreateDatabase(twebsitetemp); - - mainDataProcess.OpenTable('',True); - FIsPreListAvailable:=mainDataProcess.RecordCount>0; - mainDataProcess.CloseTable; - - Writelog_D(cloghead+'get number of directory page'); - // get directory page count - INIAdvanced.Reload; - directoryCount := 0; - directoryCount2 := 0; - workPtr := 0; - GetInfo(1, CS_DIRECTORY_COUNT); - if Terminated then Break; - - Writelog_D(cloghead+'get names and links'); - // get names and links - INIAdvanced.Reload; - workPtr := 0; - isFinishSearchingForNewManga := False; - if ModuleId <> -1 then - begin - with Modules.Module[ModuleId] do - for j := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do + try + DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); + if (MainForm.dataProcess.Website = website) and + (MainForm.dataProcess.Connected) then + MainForm.dataProcess.Backup(twebsite) + else begin - workPtr := 0; - isFinishSearchingForNewManga := False; - CurrentDirectoryIndex := j; - GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); + if MainForm.dataProcess.WebsiteLoaded(website) then + Synchronize(MainThreadRemoveFilter); + CopyDBDataProcess(website, twebsite); end; - end - else - if SitesMemberOf(website, [FAKKU_ID, MANGAEDEN_ID, - PERVEDEN_ID]) then - begin - if directoryCount = 0 then - directoryCount := 1; - GetInfo(directoryCount, CS_DIRECTORY_PAGE); - workPtr := 0; - isFinishSearchingForNewManga := False; - if directoryCount2 = 0 then - directoryCount2 := 1; - GetInfo(directoryCount2, CS_DIRECTORY_PAGE_2); - end - else - GetInfo(directoryCount, CS_DIRECTORY_PAGE); - if Terminated then Break; + if not mainDataProcess.Connect(twebsite) then + mainDataProcess.CreateDatabase(twebsite); + tempDataProcess.CreateDatabase(twebsitetemp); - tempDataProcess.OpenTable('', True); + mainDataProcess.OpenTable('',True); + FIsPreListAvailable:=mainDataProcess.RecordCount>0; + mainDataProcess.CloseTable; - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; - Synchronize(MainThreadShowGetting); + Writelog_D(cloghead+'get number of directory page'); + // get directory page count + INIAdvanced.Reload; + directoryCount := 0; + directoryCount2 := 0; + workPtr := 0; + GetInfo(1, CS_DIRECTORY_COUNT); + if Terminated then Break; - // get manga info - if tempDataProcess.RecordCount>0 then - begin - Writelog_D(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); + Writelog_D(cloghead+'get names and links'); + // get names and links + INIAdvanced.Reload; workPtr := 0; - FCommitCount := 0; - if NoMangaInfo or - OptionUpdateListNoMangaInfo then + isFinishSearchingForNewManga := False; + if ModuleId <> -1 then begin - Inc(workPtr); - for k:=0 to tempDataProcess.RecordCount-1 do + with Modules.Module[ModuleId] do + for j := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do begin - mainDataProcess.AddData( - tempDataProcess.Value[k,0], - tempDataProcess.Value[k,1], - '', - '', - '', - '', - '', - 0, - Now - ); - CheckCommit(5000); + workPtr := 0; + isFinishSearchingForNewManga := False; + CurrentDirectoryIndex := j; + GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); end; end else - GetInfo(tempDataProcess.RecordCount, CS_INFO); - mainDataProcess.Commit; - Writelog_D(cloghead+'get info finished '+IntToStr(workPtr)); + if SitesMemberOf(website, [FAKKU_ID, MANGAEDEN_ID, + PERVEDEN_ID]) then + begin + if directoryCount = 0 then + directoryCount := 1; + GetInfo(directoryCount, CS_DIRECTORY_PAGE); + workPtr := 0; + isFinishSearchingForNewManga := False; + if directoryCount2 = 0 then + directoryCount2 := 1; + GetInfo(directoryCount2, CS_DIRECTORY_PAGE_2); + end + else + GetInfo(directoryCount, CS_DIRECTORY_PAGE); + + if Terminated then Break; - if workPtr > 0 then - if not (Terminated and SortedList) then + tempDataProcess.OpenTable('', True); + + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; + Synchronize(MainThreadShowGetting); + + // get manga info + if tempDataProcess.RecordCount>0 then + begin + Writelog_D(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); + workPtr := 0; + FCommitCount := 0; + if NoMangaInfo or + OptionUpdateListNoMangaInfo then begin - Writelog_D(cloghead+'saving data '+IntToStr(workPtr)); - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; - Synchronize(MainThreadShowGetting); - mainDataProcess.Sort; - mainDataProcess.Close; - Synchronize(RefreshList); + Inc(workPtr); + for k:=0 to tempDataProcess.RecordCount-1 do + begin + mainDataProcess.AddData( + tempDataProcess.Value[k,0], + tempDataProcess.Value[k,1], + '', + '', + '', + '', + '', + 0, + Now + ); + CheckCommit(5000); + end; end else - Writelog_D(cloghead+'sorted list, data abandoned'); + GetInfo(tempDataProcess.RecordCount, CS_INFO); + mainDataProcess.Commit; + Writelog_D(cloghead+'get info finished '+IntToStr(workPtr)); + + if workPtr > 0 then + if not (Terminated and SortedList) then + begin + Writelog_D(cloghead+'saving data '+IntToStr(workPtr)); + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; + Synchronize(MainThreadShowGetting); + mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); + end + else + Writelog_D(cloghead+'sorted list, data abandoned'); + end; + except + on E: Exception do + WriteLog_E(cloghead+'error occured!', E, Self); end; Writelog_D(cloghead+'close database file'); @@ -729,8 +734,8 @@ procedure TUpdateMangaManagerThread.Execute; MainForm.ExceptionHandler(Self, E); end; FThreadEndNormally:=True; - Writelog_D(Self.ClassName+', thread ended normally'); Synchronize(MainThreadEndGetting); + Writelog_D(Self.ClassName+', thread ended'); end; end. From 8372e5fcaca4d1c7637e8d4a7ead59b76a74b93a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 21:16:41 +0800 Subject: [PATCH 0799/2794] simplelogger, corrected message --- baseunits/SimpleException/SimpleLogger.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/SimpleException/SimpleLogger.pas b/baseunits/SimpleException/SimpleLogger.pas index 920d670ec..de9482433 100644 --- a/baseunits/SimpleException/SimpleLogger.pas +++ b/baseunits/SimpleException/SimpleLogger.pas @@ -171,12 +171,12 @@ procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); s := ''; if Assigned(Sender) then s += LineEnding + - 'Sender Class : ' + Sender.ClassName; + 'Sender Class : ' + Sender.ClassName; if Assigned(Exc) then begin s += LineEnding + - 'Exception Class : ' + Exc.ClassName + LineEnding + - 'Exception Message: ' + Exc.Message; + 'Exception Class : ' + Exc.ClassName + LineEnding + + 'Exception Message : ' + Exc.Message; end; s += LineEnding + GetStackTraceInfo; WriteLog_E(msg + s); From 79c376db110bd33f65c8552470350134060c5d3b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 21:19:26 +0800 Subject: [PATCH 0800/2794] updatethread, commit data frequency based on number of connections --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index af6836c2d..57762b381 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -235,7 +235,7 @@ procedure TUpdateMangaThread.Execute; try Info.AddInfoToData(name, link, manager.mainDataProcess); - manager.CheckCommit(16); + manager.CheckCommit(manager.numberOfThreads); finally manager.CS_AddInfoToData.Release; end; From 3eed8fe670900b6dd5fa630f4f95afddd8ea4f19 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 21:20:55 +0800 Subject: [PATCH 0801/2794] updatethread, close main data on get info. not used at the moment. --- baseunits/uUpdateThread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 57762b381..20eb0453e 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -660,6 +660,7 @@ procedure TUpdateMangaManagerThread.Execute; if Terminated then Break; + mainDataProcess.CloseTable; tempDataProcess.OpenTable('', True); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', From 873d544deb744808ae49495d0611289a878c1231 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 21:45:23 +0800 Subject: [PATCH 0802/2794] dbdataprocess, activate sqltransaction on opentable --- baseunits/DBDataProcess.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 477ee1894..b7588d688 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -481,7 +481,8 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; except on E: Exception do WriteLog_E(Self.ClassName+'['+Website+'].GetValue.Error!'+ - 'RecIndex: '+IntToStr(RecIndex)+', FieldIndex: '+IntToStr(FieldIndex), E, Self); + ' RecIndex: '+IntToStr(RecIndex)+', FieldIndex: '+IntToStr(FieldIndex)+ + ', RecordCount: '+IntToStr(FQuery.RecordCount), E, Self); end; end; @@ -673,6 +674,7 @@ function TDBDataProcess.OpenTable(const ATableName: String; begin if FQuery.Active then FQuery.Close; + if FTrans.Active=False then FTrans.Active:=True; FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FQuery.SQL.Text := FSQLSelect; FQuery.Open; From c91868de18e8bb4adc0bf5b602703bc1685fbfc3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 21:52:44 +0800 Subject: [PATCH 0803/2794] updatethread, move open main data to after get directory count --- baseunits/uUpdateThread.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 20eb0453e..9ad2bb22d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -613,10 +613,6 @@ procedure TUpdateMangaManagerThread.Execute; mainDataProcess.CreateDatabase(twebsite); tempDataProcess.CreateDatabase(twebsitetemp); - mainDataProcess.OpenTable('',True); - FIsPreListAvailable:=mainDataProcess.RecordCount>0; - mainDataProcess.CloseTable; - Writelog_D(cloghead+'get number of directory page'); // get directory page count INIAdvanced.Reload; @@ -626,6 +622,9 @@ procedure TUpdateMangaManagerThread.Execute; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; + mainDataProcess.OpenTable('',True); + FIsPreListAvailable:=mainDataProcess.RecordCount>0; + Writelog_D(cloghead+'get names and links'); // get names and links INIAdvanced.Reload; From 527d71d2e31b641cc8eea99007d3f865b2293bee Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 22:05:25 +0800 Subject: [PATCH 0804/2794] updathread, tupdatemangathread, move info to public --- baseunits/uUpdateThread.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 9ad2bb22d..d7a6ff3a8 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -21,7 +21,6 @@ TUpdateMangaManagerThread = class; TUpdateMangaThread = class(TFMDThread) protected - Info: TMangaInformation; checkStyle: TCheckStyleType; workPtr: Integer; manager: TUpdateMangaManagerThread; @@ -29,6 +28,8 @@ TUpdateMangaThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; public + Info: TMangaInformation; + constructor Create; destructor Destroy; override; end; From c3b534f2288ce44c414a716fd5bace8fef2ca98c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 22:40:19 +0800 Subject: [PATCH 0805/2794] updatethread, fix unexpected crash. unsafe fetching db with multithread fix #157 --- baseunits/uUpdateThread.pas | 48 +++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index d7a6ff3a8..a385304c8 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -21,6 +21,7 @@ TUpdateMangaManagerThread = class; TUpdateMangaThread = class(TFMDThread) protected + Info: TMangaInformation; checkStyle: TCheckStyleType; workPtr: Integer; manager: TUpdateMangaManagerThread; @@ -28,8 +29,7 @@ TUpdateMangaThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; public - Info: TMangaInformation; - + title, link: String; constructor Create; destructor Destroy; override; end; @@ -114,7 +114,6 @@ destructor TUpdateMangaThread.Destroy; procedure TUpdateMangaThread.Execute; var names, links: TStringList; - name, link: String; i: Integer; begin try @@ -226,19 +225,18 @@ procedure TUpdateMangaThread.Execute; CS_INFO: begin - name := manager.tempDataProcess.Value[workPtr,0]; - link := manager.tempDataProcess.Value[workPtr,1]; - Info.mangaInfo.title := name; - Info.GetInfoFromURL(manager.website, link,OptionConnectionMaxRetry); - if not Terminated then - begin - manager.CS_AddInfoToData.Acquire; - try - Info.AddInfoToData(name, link, - manager.mainDataProcess); - manager.CheckCommit(manager.numberOfThreads); - finally - manager.CS_AddInfoToData.Release; + Info.mangaInfo.title:=title; + if link<>'' then begin + Info.GetInfoFromURL(manager.website,link,OptionConnectionMaxRetry); + if not Terminated then + begin + manager.CS_AddInfoToData.Acquire; + try + Info.AddInfoToData(title,link,manager.mainDataProcess); + manager.CheckCommit(manager.numberOfThreads); + finally + manager.CS_AddInfoToData.Release; + end; end; end; end; @@ -252,7 +250,7 @@ procedure TUpdateMangaThread.Execute; if checkStyle = CS_INFO then begin E.Message := E.Message + - ' Title : ' + name + LineEnding + + ' Title : ' + title + LineEnding + ' URL : ' + link + LineEnding; end; MainForm.ExceptionHandler(Self, E); @@ -440,7 +438,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; end; var - mt: Integer; + mt, i: Integer; s: String; begin MainForm.ulTotalPtr := limit; @@ -488,11 +486,15 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; try if Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads then Exit; Modules.IncActiveConnectionCount(ModuleId); - threads.Add(TUpdateMangaThread.Create); - TUpdateMangaThread(threads.Last).checkStyle := cs; - TUpdateMangaThread(threads.Last).manager := Self; - TUpdateMangaThread(threads.Last).workPtr := workPtr; - TUpdateMangaThread(threads.Last).Start; + i:=threads.Add(TUpdateMangaThread.Create); + if cs=CS_INFO then begin + TUpdateMangaThread(threads[i]).title:=tempDataProcess.Value[workPtr,0]; + TUpdateMangaThread(threads[i]).link:=tempDataProcess.Value[workPtr,1]; + end; + TUpdateMangaThread(threads[i]).checkStyle:=cs; + TUpdateMangaThread(threads[i]).manager:=Self; + TUpdateMangaThread(threads[i]).workPtr:=Self.workPtr; + TUpdateMangaThread(threads[i]).Start; Inc(workPtr); s := RS_UpdatingList + Format(' [%d/%d] %s | [T:%d] [%d/%d]', [websitePtr, websites.Count, website, threads.Count, workPtr, limit]); From 3e152d43beaf001473627a2821e66ecafea3df14 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 22:43:11 +0800 Subject: [PATCH 0806/2794] dbdataprocess, turn updatedata to function: boolean --- baseunits/DBDataProcess.pas | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index b7588d688..a427dd8ce 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -91,8 +91,8 @@ TDBDataProcess = class(TObject) NumChapter, JDN: Integer): Boolean; overload; function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; JDN: TDateTime): Boolean; overload; - procedure UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer; AWebsite: String = ''); + function UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; + NumChapter: Integer; AWebsite: String = ''): Boolean; procedure Commit; procedure Rollback; procedure RemoveFilter; @@ -797,11 +797,12 @@ function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, NumChapter, DateToJDN(JDN)); end; -procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, - Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String); +function TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, Genres, + Status, Summary: String; NumChapter: Integer; AWebsite: String): Boolean; var sql: String; begin + Result:=False; if Link='' then Exit; if FConn.Connected=False then Exit; try @@ -819,9 +820,8 @@ procedure TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, ', "numchapter"='+QuotedStr(IntToStr(NumChapter))+ ' WHERE ("link"='+QuotedStr(Link)+');'; FConn.ExecuteDirect(sql); + Result:=True; except - on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].UpdateData.Error!'#13#10'SQL = '+sql, E, Self); end; end; From 1860bda39ceb65e01d5435be92cf43a3b6ad8a27 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 22:44:43 +0800 Subject: [PATCH 0807/2794] dbdataprocess, don't add data if link empty --- baseunits/DBDataProcess.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index a427dd8ce..8282760da 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -772,6 +772,7 @@ function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer): Boolean; begin Result:=False; + if Link='' then Exit; if FConn.Connected=False then Exit; try FConn.ExecuteDirect( From 47b40b5b1e3274880ae855bd172e05b44acccd22 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Jan 2016 22:49:31 +0800 Subject: [PATCH 0808/2794] updatethread, rename classname --- baseunits/uUpdateThread.pas | 66 +++++++++++++++---------------- mangadownloader/forms/frmMain.pas | 8 ++-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index a385304c8..48c6ffb5d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -15,16 +15,16 @@ interface uBaseUnit, uFMDThread, uTranslation, uMisc, WebsiteModules, DBDataProcess; type - TUpdateMangaManagerThread = class; + TUpdateListManagerThread = class; - { TUpdateMangaThread } + { TUpdateListThread } - TUpdateMangaThread = class(TFMDThread) + TUpdateListThread = class(TFMDThread) protected Info: TMangaInformation; checkStyle: TCheckStyleType; workPtr: Integer; - manager: TUpdateMangaManagerThread; + manager: TUpdateListManagerThread; procedure Execute; override; procedure DoTerminate; override; @@ -34,9 +34,9 @@ TUpdateMangaThread = class(TFMDThread) destructor Destroy; override; end; - { TUpdateMangaManagerThread } + { TUpdateListManagerThread } - TUpdateMangaManagerThread = class(TFMDThread) + TUpdateListManagerThread = class(TFMDThread) private FStatus: String; FCommitCount: Integer; @@ -97,21 +97,21 @@ implementation uses frmMain, Dialogs, ComCtrls, Forms, Controls, SimpleLogger; -{ TUpdateMangaThread } +{ TUpdateListThread } -constructor TUpdateMangaThread.Create; +constructor TUpdateListThread.Create; begin inherited Create(True); end; -destructor TUpdateMangaThread.Destroy; +destructor TUpdateListThread.Destroy; begin if Assigned(Info) then Info.Free; inherited Destroy; end; -procedure TUpdateMangaThread.Execute; +procedure TUpdateListThread.Execute; var names, links: TStringList; i: Integer; @@ -258,7 +258,7 @@ procedure TUpdateMangaThread.Execute; end; end; -procedure TUpdateMangaThread.DoTerminate; +procedure TUpdateListThread.DoTerminate; begin LockCreateConnection; try @@ -270,14 +270,14 @@ procedure TUpdateMangaThread.DoTerminate; inherited DoTerminate; end; -{ TUpdateMangaManagerThread } +{ TUpdateListManagerThread } -procedure TUpdateMangaManagerThread.MainThreadStatusRepaint; +procedure TUpdateListManagerThread.MainThreadStatusRepaint; begin MainForm.sbUpdateList.Repaint; end; -procedure TUpdateMangaManagerThread.MainThreadShowGetting; +procedure TUpdateListManagerThread.MainThreadShowGetting; begin if MainForm.sbUpdateList.Visible = False then begin @@ -293,7 +293,7 @@ procedure TUpdateMangaManagerThread.MainThreadShowGetting; MainForm.sbUpdateList.Panels[0].Text := FStatus; end; -procedure TUpdateMangaManagerThread.MainThreadEndGetting; +procedure TUpdateListManagerThread.MainThreadEndGetting; begin MainForm.sbUpdateList.Panels[0].Text := ''; mainForm.sbUpdateList.Panels[0].Style := psText; @@ -306,12 +306,12 @@ procedure TUpdateMangaManagerThread.MainThreadEndGetting; end; end; -procedure TUpdateMangaManagerThread.MainThreadRemoveFilter; +procedure TUpdateListManagerThread.MainThreadRemoveFilter; begin MainForm.btRemoveFilterClick(MainForm.btRemoveFilter); end; -procedure TUpdateMangaManagerThread.ExtractFile; +procedure TUpdateListManagerThread.ExtractFile; var Sza, datapath, filepath: String; begin @@ -338,7 +338,7 @@ procedure TUpdateMangaManagerThread.ExtractFile; end end; -constructor TUpdateMangaManagerThread.Create; +constructor TUpdateListManagerThread.Create; begin inherited Create(True); CS_AddInfoToData := TCriticalSection.Create; @@ -359,7 +359,7 @@ constructor TUpdateMangaManagerThread.Create; FIsPreListAvailable:=False; end; -destructor TUpdateMangaManagerThread.Destroy; +destructor TUpdateListManagerThread.Destroy; begin if FThreadAborted then WriteLog_W(Self.ClassName+', thread aborted by user?'); if not FThreadEndNormally then WriteLog_W(Self.ClassName+', thread doesn''t end normally, ended by user?'); @@ -377,7 +377,7 @@ destructor TUpdateMangaManagerThread.Destroy; inherited Destroy; end; -procedure TUpdateMangaManagerThread.CheckCommit(const CommitCount: Integer); +procedure TUpdateListManagerThread.CheckCommit(const CommitCount: Integer); begin Inc(FCommitCount); if FCommitCount >= CommitCount then @@ -388,7 +388,7 @@ procedure TUpdateMangaManagerThread.CheckCommit(const CommitCount: Integer); end; end; -procedure TUpdateMangaManagerThread.RefreshList; +procedure TUpdateListManagerThread.RefreshList; begin try with MainForm do @@ -422,13 +422,13 @@ procedure TUpdateMangaManagerThread.RefreshList; end; end; -procedure TUpdateMangaManagerThread.DlgReport; +procedure TUpdateListManagerThread.DlgReport; begin MessageDlg('', Format(RS_DlgHasNewManga, [website, tempDataProcess.RecordCount]), mtInformation, [mbYes], 0); end; -procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; +procedure TUpdateListManagerThread.GetInfo(const limit: Integer; const cs: TCheckStyleType); procedure WaitForThreads; @@ -486,15 +486,15 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; try if Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads then Exit; Modules.IncActiveConnectionCount(ModuleId); - i:=threads.Add(TUpdateMangaThread.Create); + i:=threads.Add(TUpdateListThread.Create); if cs=CS_INFO then begin - TUpdateMangaThread(threads[i]).title:=tempDataProcess.Value[workPtr,0]; - TUpdateMangaThread(threads[i]).link:=tempDataProcess.Value[workPtr,1]; + TUpdateListThread(threads[i]).title:=tempDataProcess.Value[workPtr,0]; + TUpdateListThread(threads[i]).link:=tempDataProcess.Value[workPtr,1]; end; - TUpdateMangaThread(threads[i]).checkStyle:=cs; - TUpdateMangaThread(threads[i]).manager:=Self; - TUpdateMangaThread(threads[i]).workPtr:=Self.workPtr; - TUpdateMangaThread(threads[i]).Start; + TUpdateListThread(threads[i]).checkStyle:=cs; + TUpdateListThread(threads[i]).manager:=Self; + TUpdateListThread(threads[i]).workPtr:=Self.workPtr; + TUpdateListThread(threads[i]).Start; Inc(workPtr); s := RS_UpdatingList + Format(' [%d/%d] %s | [T:%d] [%d/%d]', [websitePtr, websites.Count, website, threads.Count, workPtr, limit]); @@ -537,7 +537,7 @@ procedure TUpdateMangaManagerThread.GetInfo(const limit: Integer; WaitForThreads; end; -procedure TUpdateMangaManagerThread.DoTerminate; +procedure TUpdateListManagerThread.DoTerminate; var i: Integer; begin @@ -546,7 +546,7 @@ procedure TUpdateMangaManagerThread.DoTerminate; LockCreateConnection; try for i := 0 to threads.Count - 1 do - TUpdateMangaThread(threads[i]).Terminate; + TUpdateListThread(threads[i]).Terminate; finally UnlockCreateConnection; end; @@ -556,7 +556,7 @@ procedure TUpdateMangaManagerThread.DoTerminate; inherited DoTerminate; end; -procedure TUpdateMangaManagerThread.Execute; +procedure TUpdateListManagerThread.Execute; var j, k: Integer; cloghead: String; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 650117002..e20eb6ca6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -564,7 +564,7 @@ TMainForm = class(TForm) ChapterList: array of TChapterStateItem; DLManager: TDownloadManager; updateDB: TUpdateDBThread; - updateList: TUpdateMangaManagerThread; + updateList: TUpdateListManagerThread; SilentThreadManager: TSilentThreadManager; // animation gif gifWaiting: TAnimatedGif; @@ -2705,7 +2705,7 @@ procedure TMainForm.mnDownload1ClickClick(Sender: TObject); // if dataProcess.Title.Count > 1 then //begin isUpdating := True; - updateList := TUpdateMangaManagerThread.Create; + updateList := TUpdateListManagerThread.Create; for i := 0 to cbSelectManga.Items.Count - 1 do updateList.websites.Add(cbSelectManga.Items[i]); updateList.isDownloadFromServer := True; @@ -2730,7 +2730,7 @@ procedure TMainForm.mnUpdate1ClickClick(Sender: TObject); {$ENDIF} begin isUpdating := True; - updateList := TUpdateMangaManagerThread.Create; + updateList := TUpdateListManagerThread.Create; for i := 0 to cbSelectManga.Items.Count - 1 do updateList.websites.Add(cbSelectManga.Items[i]); updateList.isDownloadFromServer := False; @@ -2789,7 +2789,7 @@ procedure TMainForm.mnUpdateListClick(Sender: TObject); {$ENDIF} begin isUpdating := True; - updateList := TUpdateMangaManagerThread.Create; + updateList := TUpdateListManagerThread.Create; updateList.numberOfThreads := 4; updateList.websites.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); updateList.isDownloadFromServer := False; From bf406bdf8b09344ec729eb329e2c4f254ce2b645 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 08:19:45 +0800 Subject: [PATCH 0809/2794] updatethread, close main data table when not needed --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 48c6ffb5d..94eee62e4 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -627,6 +627,7 @@ procedure TUpdateListManagerThread.Execute; mainDataProcess.OpenTable('',True); FIsPreListAvailable:=mainDataProcess.RecordCount>0; + mainDataProcess.CloseTable; Writelog_D(cloghead+'get names and links'); // get names and links @@ -662,7 +663,6 @@ procedure TUpdateListManagerThread.Execute; if Terminated then Break; - mainDataProcess.CloseTable; tempDataProcess.OpenTable('', True); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', From 4784613bd7139203764e4bf9d6c657c5a3227ddb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 08:20:24 +0800 Subject: [PATCH 0810/2794] updatethread, corrected status --- baseunits/uUpdateThread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 94eee62e4..2870bd1a3 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -663,12 +663,12 @@ procedure TUpdateListManagerThread.Execute; if Terminated then Break; - tempDataProcess.OpenTable('', True); - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; Synchronize(MainThreadShowGetting); + tempDataProcess.OpenTable('', True); + // get manga info if tempDataProcess.RecordCount>0 then begin From af5b71660bc3ddca4c9b98e7e47da27756d50c69 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 08:22:50 +0800 Subject: [PATCH 0811/2794] batoto, fail if resultcode >400 = not found --- baseunits/modules/Batoto.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index d6eafacbb..0ce0685d3 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -103,6 +103,7 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; AHTTP.Cookies.Text:=Account.Cookies['Batoto']; AHTTP.KeepAlive:=False; Result:=AHTTP.GET(AURL); + if (AHTTP.ResultCode>400) and (AHTTP.ResultCode<500) then Exit; if Result then begin Result:=True; if Account.Enabled[modulename]=False then Exit; From e483b9b9b739f0913c458ed8d97971727b11e2e7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 08:40:02 +0800 Subject: [PATCH 0812/2794] batoto, change xpath for pagenumber --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 0ce0685d3..004cb2720 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -258,7 +258,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; query.ParseHTML(StreamToString(Document)); PageContainerLinks.Text := cid; if query.XPathString('//select[@id="page_select"]') <> '' then - PageNumber := Query.XPath('//div[1]/ul/li/select[@id="page_select"]/option/@value').Count + PageNumber := Query.XPath('(//select[@id="page_select"])[1]/option/@value').Count else begin // long-strip view PageLinks.Clear; From 9cf69593e7fd629e379478fd4a23ff5ed18d854c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 08:47:02 +0800 Subject: [PATCH 0813/2794] batoto, only getinfo need login. can't determine login status on getpagenumber, partial content. --- baseunits/modules/Batoto.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 004cb2720..e56e58622 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -134,7 +134,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result:=NET_PROBLEM; Page:=1; if MangaInfo =nil then Exit(UNKNOWN_ERROR); - if GETWithLogin(MangaInfo.FHTTP,Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin + if MangaInfo.FHTTP.GET(Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin Result:=NO_ERROR; query:=TXQueryEngineHTML.Create; try @@ -159,7 +159,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if MangaInfo=nil then Exit(UNKNOWN_ERROR); s:=Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage); if AURL<>'0' then s+='&st='+IntToStr(StrToInt(AURL)*perpage); - if GETWithLogin(MangaInfo.FHTTP,s) then begin + if MangaInfo.FHTTP.GET(s) then begin Result:=NO_ERROR; query:=TXQueryEngineHTML.Create; try @@ -251,7 +251,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; with DownloadThread.manager.container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + urlroot + '/reader'; cid := SeparateRight(AURL, '/reader#'); - if GETWithLogin(DownloadThread.FHTTP,urlroot + '/areader?id=' + cid + '&p=1') then begin + if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin Result := True; query := TXQueryEngineHTML.Create; try @@ -284,7 +284,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; if PageContainerLinks.Text = '' then Exit; rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + IntToStr(DownloadThread.WorkCounter + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; - if GETWithLogin(DownloadThread.FHTTP,rurl) then begin + if GET(rurl) then begin Result := True; query := TXQueryEngineHTML.Create; try From a9e39d142c50a5666922f14de23ac553b3d437b6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 08:50:02 +0800 Subject: [PATCH 0814/2794] batoto, add first page image url on getpagenumber --- baseunits/modules/Batoto.pas | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index e56e58622..7a7715941 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -244,7 +244,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; var query: TXQueryEngineHTML; v: IXQValue; - cid: String; + cid, s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -257,8 +257,13 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; try query.ParseHTML(StreamToString(Document)); PageContainerLinks.Text := cid; - if query.XPathString('//select[@id="page_select"]') <> '' then - PageNumber := Query.XPath('(//select[@id="page_select"])[1]/option/@value').Count + if query.XPathString('//select[@id="page_select"]') <> '' then begin + PageNumber := Query.XPath('(//select[@id="page_select"])[1]/option/@value').Count; + if PageNumber>0 then begin + s:=query.XPathString('//div[@id="full_image"]//img/@src'); + if s<>'' then PageLinks.Add(s) + end; + end else begin // long-strip view PageLinks.Clear; From 6bf29b07c9c2629820b2de927f508805cc34043f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 09:06:20 +0800 Subject: [PATCH 0815/2794] remove unused units, mh160 --- baseunits/ModuleList.inc | 1 - baseunits/modules/PecintaKomik - Copy.pas | 447 ---------------------- baseunits/modules/mh160com.pas | 327 ---------------- 3 files changed, 775 deletions(-) delete mode 100644 baseunits/modules/PecintaKomik - Copy.pas delete mode 100644 baseunits/modules/mh160com.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 9454b4767..b43a6a1b7 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,6 +1,5 @@ uses FoOlSlide, - mh160com, Batoto, WPManga, MangaFox, diff --git a/baseunits/modules/PecintaKomik - Copy.pas b/baseunits/modules/PecintaKomik - Copy.pas deleted file mode 100644 index f28661839..000000000 --- a/baseunits/modules/PecintaKomik - Copy.pas +++ /dev/null @@ -1,447 +0,0 @@ -unit PecintaKomik; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, synautil; - -implementation - -const - dirURL = '/directory/'; - -function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; - var Page: Integer; {%H-}Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - Page := 1; -end; - -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const {%H-}URL: String; - Module: TModuleContainer): Integer; -var - Parse: TStringList; - - procedure ScanParse; - var - i, j: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'section') and - (GetVal(Parse[i], 'class') = 'cols') then - begin - for j := i + 1 to Parse.Count - 1 do - if GetTagName(Parse[j]) = '/section' then - Break - else - if (GetTagName(Parse[j]) = 'a') and - (GetVal(Parse[j], 'class') = 'screenshot') then - begin - Links.Add(AppendURLDelim(GetVal(Parse[j], 'href'))); - Names.Add(CommonStringFilter(Parse[j + 1])); - end; - Break; - end; - end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; -var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - s: String; - begin - for i := StartIndex + 1 to Parse.Count - 1 do - begin - s := GetTagName(Parse[i]); - if s = '/div' then - Break - else - if s = 'a' then - begin - info.chapterLinks.Add(AppendURLDelim(GetVal(Parse[i], 'href'))); - info.chapterName.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - - //invert chapters - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; - - procedure ScanInfo(const StartIndex: Integer); - var - i: Integer; - s: String; - begin - for i := StartIndex + 1 to Parse.Count - 1 do - begin - s := GetTagName(Parse[i]); - if s = '/div' then - Break - else - if s = 'li' then - begin - //authors - if Pos('Author(s):', Parse[i + 1]) = 1 then - info.authors := CommonStringFilter(SeparateRight(Parse[i + 1], - 'Author(s):')) - else - //artist - if Pos('Artist(s):', Parse[i + 1]) = 1 then - info.artists := CommonStringFilter(SeparateRight(Parse[i + 1], - 'Artist(s):')) - else - //genres - if Pos('Genre:', Parse[i + 1]) = 1 then - info.genres := CommonStringFilter(SeparateRight(Parse[i + 1], 'Genre:')) - else - //summary - if Pos('Sinopsis:', Parse[i + 1]) = 1 then - info.summary := CommonStringFilter(SeparateRight(Parse[i + 1], 'Sinopsis:')); - end; - end; - end; - - procedure ScanInfo2(const StartIndex: Integer); - var - i: Integer; - s: String; - begin - for i := StartIndex + 1 to Parse.Count - 1 do - begin - s := GetTagName(Parse[i]); - if s = '/div' then - Break - else - if s = 'li' then - begin - //authors - if Pos('Author(s):', Parse[i + 2]) = 1 then - info.authors := CommonStringFilter(Parse[i + 4]) - else - //artist - if Pos('Artist(s):', Parse[i + 2]) = 1 then - info.artists := CommonStringFilter(Parse[i + 4]) - else - //genres - if Pos('Genre:', Parse[i + 2]) = 1 then - info.genres := CommonStringFilter(Parse[i + 4]) - else - //summary - if Pos('Sinopsis:', Parse[i + 2]) = 1 then - info.summary := CommonStringFilter(Parse[i + 4]); - end; - end; - end; - - //broken layout - procedure ScanInfo3; - var - i, j: Integer; - begin - info.genres := ''; - info.summary := ''; - for i := 0 to Parse.Count - 1 do - begin - //cover - if info.coverLink = '' then - if (GetTagName(Parse[i]) = 'img') and - (GetVal(Parse[i], 'class') = 'pecintakomik') then - info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); - //title - if info.title = '' then - if GetVal(Parse[i], 'class') = 'aname' then - info.title := CommonStringFilter(Parse[i + 1]); - if GetVal(Parse[i], 'class') = 'propertytitle' then - begin - //author - if Pos('Autor:', Parse[i + 1]) = 1 then - info.authors := CommonStringFilter(Parse[i + 6]) - else - //artist - if Pos('Artist:', Parse[i + 1]) = 1 then - info.artists := CommonStringFilter(Parse[i + 6]); - //summary - if Pos('Ringkasan Cerita:', Parse[i + 1]) = 1 then - for j := i + 3 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/td' then - Break - else - if (Parse[j] <> '') and (Parse[j][1] <> '<') then - begin - if info.summary <> '' then - info.summary += LineEnding; - info.summary += CommonStringFilter(Parse[j]); - end; - end; - //genre - if GetVal(Parse[i], 'class') = 'genretags' then - AddCommaString(info.genres, CommonStringFilter(Parse[i + 1])); - end; - //chapters - if (GetTagName(Parse[i]) = 'ul') and - (GetVal(Parse[i], 'class') = 'series_alpha') then - begin - ScanChapters(i); - Break; - end; - end; - end; - - procedure ScanParse; - var - i, j: Integer; - begin - if Pos('/manga/', URL) = 0 then - begin - for i := 0 to Parse.Count - 1 do - begin - if GetVal(Parse[i], 'http-equiv') = 'x-ua-compatible' then - begin - ScanInfo3; - Break; - end; - - //cover - if info.coverLink = '' then - if (GetTagName(Parse[i]) = 'img') and - (GetVal(Parse[i], 'class') = 'pecintakomik') then - info.coverLink := MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src')); - - if GetVal(Parse[i], 'class') = 'post-cnt' then - if GetTagName(Parse[i + 2]) = 'h2' then - begin - //chapters - if Pos('List Chapter(s)', Parse[i + 3]) <> 0 then - begin - ScanChapters(i); - Break; - end - else - begin - //title - if info.title = '' then - info.title := CommonStringFilter(Parse[i + 3]); - //info - if (GetTagName(Parse[i + 8]) = 'li') and - (GetTagName(Parse[i + 9]) <> 'strong') then - ScanInfo(i) - else - ScanInfo2(i); - end; - end; - end; - end - else - //no info - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'name') = 'manga') then - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if (GetTagName(Parse[j]) = 'option') and - (GetVal(Parse[j], 'selected') = 'selected') then - begin - info.title := CommonStringFilter(Parse[j + 1]); - Break; - end; - end; - //chapters - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'name') = 'chapter') then - begin - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if GetTagName(Parse[j]) = 'option' then - begin - Inc(info.numChapter); - info.chapterLinks.Add(AppendURLDelim(URL) + IntToStr(info.numChapter)); - info.chapterName.Add('Chapter ' + IntToStr(info.numChapter)); - end; - end; - Break; - end; - end; - end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; -var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i, j: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'name') = 'page') then - begin - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if GetTagName(Parse[j]) = 'option' then - Inc(Container.PageNumber); - end; - Break; - end; - end; - -begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - FillHost(Module.RootURL, URL), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; -var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - baseurl: String; - begin - baseurl := Module.RootURL; - for i := 0 to Parse.Count - 1 do - begin - if GetTagName(Parse[i]) = 'base' then - baseurl := GetVal(Parse[i], 'href'); - if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'class') = 'picture') then - begin - if DownloadThread.workCounter < Container.PageLinks.Count then - Container.PageLinks[DownloadThread.workCounter] := - MaybeFillHost(baseurl, GetVal(Parse[i], 'src')); - Break; - end; - end; - end; - -begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - AppendURLDelim(FillHost(Module.RootURL, URL)) + IncStr(DownloadThread.workCounter), - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'PecintaKomik'; - RootURL := 'http://www.pecintakomik.com'; - SortedList := False; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/baseunits/modules/mh160com.pas b/baseunits/modules/mh160com.pas deleted file mode 100644 index 63d04e96f..000000000 --- a/baseunits/modules/mh160com.pas +++ /dev/null @@ -1,327 +0,0 @@ -unit mh160com; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synacode, synautil, LConvEncoding, HTMLUtil, base64, RegExpr; - -implementation - -const - diralpha = 'abcdefghijklmnopqrstuvwxyz'; - -function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; - var Page: Integer; {%H-}Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - Page := Length(diralpha); -end; - -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; -var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - begin - if Parse[i] = '<dt>' then - if GetTagName(Parse[i + 1]) = 'a' then - begin - Links.Add(GetVal(Parse[i + 1], 'href')); - Names.Add(CommonStringFilter(Parse[i + 2])); - end; - end; - end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/kanmanhua/' + - diralpha[StrToInt(URL) + 1] + '.html', 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(CP936ToUTF8(Parse.Text), Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; -var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - g: String = ''; - begin - if (StartIndex = -1) or (StartIndex >= Parse.Count) then - Exit; - for i := StartIndex to Parse.Count - 1 do - begin - if Parse[i] = '</div>' then - Break; - if GetTagName(Parse[i]) = 'a' then - begin - info.chapterLinks.Add(GetVal(Parse[i], 'href')); - info.chapterName.Add(g + Trim(Parse[i + 1])); - end; - end; - //invert chapters - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; - - procedure ScanParse; - var - i: Integer; - chapterinfopos: Integer = -1; - begin - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if GetVal(Parse[i], 'class') = 'intro_l' then - if GetVal(Parse[i + 2], 'class') = 'title' then - info.title := CommonStringFilter(Parse[i + 5]); - - //cover - if info.coverLink = '' then - if GetVal(Parse[i], 'class') = 'cover' then - if GetTagName(Parse[i + 1]) = 'img' then - begin - info.coverLink := GetVal(Parse[i + 1], 'src'); - if Pos('http', info.coverLink) <> 1 then - info.coverLink := Module.RootURL + info.coverLink; - end; - - //author - if (Pos('原著作者:', Parse[i]) <> 0) and - (Parse[i + 1] = '</em>') then - info.authors := CommonStringFilter(Parse[i + 2]); - - //genres - if (Pos('剧情类别:', Parse[i]) <> 0) and - (Parse[i + 1] = '</em>') then - info.genres := Trim(Parse[i + 3]); - - //summary - if Pos('class="introduction"', Parse[i]) <> 0 then - info.summary := Trim(Parse[i + 2]); - - //chapters - if GetVal(Parse[i], 'class') = 'plist pnormal' then - if chapterinfopos = -1 then - chapterinfopos := i; - end; - ScanChapters(chapterinfopos); - end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(CP936ToUTF8(Parse.Text), Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -function padZero(const S: String; len: Integer): String; -begin - Result := S; - while Length(Result) < len do - Result := '0' + Result; -end; - -function getcurpic_skin4_20110501(const URL: String): String; - - function getrealurl(const S: String): String; - begin - Result := S; - if Pos('img1.fshmy.com', S) <> 0 then - Result := StringReplace(S, 'img1.fshmy.com', 'img1.hgysxz.cn', []) - else if Pos('imgs.k6188.com', S) <> 0 then - Result := StringReplace(S, 'imgs.k6188.com', 'imgs.zhujios.com', []) - else if Pos('073.k6188.com', S) <> 0 then - Result := StringReplace(S, '073.k6188.com', 'cartoon.zhujios.com', []) - else if Pos('cartoon.jide123.cc', S) <> 0 then - Result := StringReplace(S, 'cartoon.jide123.cc', - 'cartoon.shhh88.com', []) - else if Pos('www.jide123.com', S) <> 0 then - Result := StringReplace(S, 'www.jide123.com', 'cartoon.shhh88.com', []) - else if Pos('cartoon.chuixue123.com', S) <> 0 then - Result := StringReplace(S, 'cartoon.chuixue123.com', - 'cartoon.shhh88.com', []) - else if Pos('p10.tuku.cc:8899', S) <> 0 then - Result := StringReplace(S, 'p10.tuku.cc:8899', 'tkpic.tukucc.com', []); - end; - - function getkekerealurl(const S: String): String; - var - i: Integer; - sn: String; - begin - Result := S; - for i := 1 to 15 do - begin - sn := '/dm' + padZero(IntToStr(i), 2) + '/'; - if Pos(sn, S) <> 0 then - begin - Result := 'http://2.cococomic.com:9115' + sn + SeparateRight(S, sn); - Break; - end; - end; - end; - - function getremoteqqurl(const S: String): String; - begin - Result := SeparateRight(S, 'dir_path=/'); - Result := StringReplace(Result, '&name=', '', []); - Result := StringReplace(Result, 'mif2', 'jpg', []); - Result := StringReplace(Result, '/', '_', [rfReplaceAll]); - //Result := 'http://img11.aoyuanba.com/pictmdown.php?p=' + - // EncodeStringBase64(S) + '$sf=' + Result + - // '&ym=http://img11.hgysxz.cn'; - Result := 'http://img11.hgysxz.cn/Pic/' + Result; - end; - -begin - Result := URL; - if Pos('qq.com/store_file_download', URL) <> 0 then - Result := getremoteqqurl(URL) - else - if Pos('/ok-comic', URL) <> 0 then - Result := getkekerealurl(URL) - else if Pos('mangafiles.com', URL) <> 0 then - Result := 'http://img6.aoyuanba.com:8056/pictmdown.php?p=' + EncodeStringBase64(URL) - else if Pos('imgs.gengxin123.com', URL) <> 0 then - begin - Result := StringReplace(URL, 'imgs.gengxin123.com', 'imgs1.ysryd.com', - [rfIgnoreCase]); - Result := 'http://imgsty1.aoyuanba.com/pictmdown.php?bu=' + 'http://www.kxdm.com/' + - '&p=' + EncodeStringBase64(Result); - end - else if Pos('imgs1.ysryd.com', URL) <> 0 then - Result := 'http://imgsty1.aoyuanba.com/pictmdown.php?bu=' + - 'http://www.kxdm.com/' + '&p=' + EncodeStringBase64(URL) - else if Pos('dmzj.com', URL) <> 0 then - Result := 'http://imgsty.aoyuanba.com:8056/pictmdown.php?bu=' + - 'http://manhua.dmzj.com/' + '&p=' + EncodeStringBase64(EncodeURL(URL)) - else if Pos('imgsrc.baidu.com', URL) <> 0 then - Result := 'http://img7.aoyuanba.com:8056/picinc/qTcms.Pic.FangDao.asp?p=' + - EncodeStringBase64(URL) - else if Pos('sinaimg.cn', URL) <> 0 then - Result := 'http://img7.aoyuanba.com:8056/picinc/qTcms.Pic.FangDao.asp?p=' + - EncodeStringBase64(URL) - else if Pos('jumpcn.cc', URL) <> 0 then - Result := 'http://img7.aoyuanba.com:8056/picinc/qTcms.Pic.FangDao.asp?p=' + - EncodeStringBase64(URL) - else if Pos('JLmh160', URL) <> 0 then - Result := 'http://img3.aoyuanba.com/picinc/qTcms.Pic.FangDao.asp?p=' + - EncodeStringBase64(URL) - else - Result := getrealurl(URL); -end; - -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; -var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - picTree: String; - begin - for i := 0 to Parse.Count - 1 do - begin - if Pos('var picTree', Parse[i]) <> 0 then - begin - picTree := ReplaceRegExpr('(?ig)^.*var\spicTree\s*=[''"](.+?)[''"].*$', - Parse[i], '$1', True); - picTree := DecodeStringBase64(picTree); - picTree := StringReplace(picTree, '$qingtiandy$', #13#10, [rfReplaceAll]); - Container.PageLinks.AddText(picTree); - Break; - end; - end; - if Container.PageLinks.Count > 0 then - for i := 0 to Container.PageLinks.Count - 1 do - Container.PageLinks[i] := getcurpic_skin4_20110501(Container.PageLinks[i]); - end; - -begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), FillHost(Module.RootURL, URL), - Container.Manager.retryConnect) then - begin - ParseHTML(CP936ToUTF8(Parse.Text), Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; - end; - finally - Parse.Free; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'mh160'; - RootURL := 'http://www.mh160.com'; - SortedList := False; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 259f5e0f91b868b4a6e308f84231ab1017ad3405 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 10:12:56 +0800 Subject: [PATCH 0816/2794] cleanup --- baseunits/modules/MangaStreamTo.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index c3e4ab98f..a8a02f8c4 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -18,7 +18,6 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; var query: TXQueryEngineHTML; v: IXQValue; - s: String; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); From e25da3e4620649f1b0e163caef176a0ac4f32d0f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 10:14:09 +0800 Subject: [PATCH 0817/2794] added mangakoi #159 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaKoi.pas | 173 +++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaKoi.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index b43a6a1b7..3de3f6d34 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -21,4 +21,5 @@ uses KissManga, UnionMangas, Seemh, - MangaStreamTo; + MangaStreamTo, + MangaKoi; diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas new file mode 100644 index 000000000..c12b0d3e0 --- /dev/null +++ b/baseunits/modules/MangaKoi.pas @@ -0,0 +1,173 @@ +unit MangaKoi; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; + +implementation + +const + dirurl='/directory'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + Page:=query.XPath('//select/option').Count; + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='/'+IncStr(AURL)+'.html'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//div[@class="cover-info"]/p[@class="title"]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + a, v, t: IXQValue; + s: String; + i: Integer; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//img[@class="detail-cover"]/@src'); + if title=''then title:=query.XPathString('//div[@class="manga-detail"]/h1'); + for v in query.XPath('//div[@class="manga-detail"]//p') do begin + s:=v.toString; + if Pos('Author(s):',s)>0 then authors:=SeparateRight(s,':') else + if Pos('Artist(s):',s)>0 then artists:=SeparateRight(s,':') else + if Pos('Genre(s):',s)>0 then genres:=SeparateRight(s,':') else + if Pos('Status:',s)>0 then begin + s:=LowerCase(s); + if Pos('ongoing',s)>0 then status:='1' else status:='0'; + end; + end; + summary:=query.XPathString('//p[@id="show"]/text()]'); + + a:=query.XPath('//ul[@class="detail-chlist"]/li/a/@href'); + v:=query.XPath('//ul[@class="detail-chlist"]/li/a/span[1]'); + t:=query.XPath('//ul[@class="detail-chlist"]/li/span[@class="vol"]'); + if (a.Count>0) and (a.Count=v.Count) and (a.Count=t.Count) then + for i:=1 to a.Count do begin + chapterLinks.Add(a.get(i).toString); + chapterName.Add(v.get(i).toString+' '+t.get(i).toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('//div[@class="mangaread-pagenav"]/select/option').Count; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=RemoveURLDelim(AURL); + if DownloadThread.workCounter>0 then s+='/'+IncStr(DownloadThread.workCounter)+'.html'; + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageLinks[DownloadThread.workCounter]:=query.XPathString('//section[@id="viewer"]//img/@src'); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='MangaKoi'; + RootURL:='http://www.mangakoi.com'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 178db69dd..107c294eb 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From d575f653f3e3917dc4583160f52706780128eca6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 10:30:13 +0800 Subject: [PATCH 0818/2794] mangakoi, typo on xpath summary --- baseunits/modules/MangaKoi.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index c12b0d3e0..1a41f1355 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -87,7 +87,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; if Pos('ongoing',s)>0 then status:='1' else status:='0'; end; end; - summary:=query.XPathString('//p[@id="show"]/text()]'); + summary:=query.XPathString('//p[@id="show"]/text()'); a:=query.XPath('//ul[@class="detail-chlist"]/li/a/@href'); v:=query.XPath('//ul[@class="detail-chlist"]/li/a/span[1]'); From a7d1e2ad4f1a75ed05d88252a2d3c04b315700b4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 11:37:44 +0800 Subject: [PATCH 0819/2794] foolslide, rewrite all --- baseunits/modules/FoOlSlide.pas | 258 ++++++++++++-------------------- 1 file changed, 97 insertions(+), 161 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index d86d66711..f6993b882 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -5,219 +5,155 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr, synautil; implementation -uses - simplehtmltreeparser, xquery, RegExpr; - const - dirurl = '/directory/'; + dirurl='/directory/'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; var - Source: TStringList; - Parser: TTreeParser; + query: TXQueryEngineHTML; + s: String; begin Result := NET_PROBLEM; Page := 1; - if MangaInfo = nil then Exit; - Source := TStringList.Create; - try - if GetPage(TObject(Source), Module.RootURL + dirurl, 3) then - begin - Result := INFORMATION_NOT_FOUND; - if Source.Count > 0 then - begin - Result := NO_ERROR; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', - SelectXPathString('//a[contains(text(),"Last »»")]/@href', Parser), - '$1', True), 1); - finally - Parser.Free; - end; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=query.XPathString('//div[@class="next"]/a[contains(text(),"Last")]/@href'); + if s<>'' then begin + s:=ReplaceRegExpr('.*/(\d+)/$',s,'$1',True); + Page:=StrToIntDef(s,1); end; + finally + query.Free; end; - finally - Source.Free; end; end; function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; var - Source: TStringList; - Parser: TTreeParser; + query: TXQueryEngineHTML; v: IXQValue; + s: String; begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Source := TStringList.Create; - try - if GetPage(TObject(Source), Module.RootURL + dirurl + IncStr(URL), 3) then - begin - Result := INFORMATION_NOT_FOUND; - if Source.Count > 0 then - begin - Result := NO_ERROR; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - for v in SelectXPathIX('//*[@class="list series"]/*/*[@class="title"]/a', - Parser) do - begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); - end; - finally - Parser.Free; - end; + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+=IncStr(AURL)+'/'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//div[@class="list series"]/div/div[@class="title"]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; + finally + query.Free; end; - finally - Source.Free; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; const Reconnect: Integer; Module: TModuleContainer): Integer; var - Source: TStringList; - Parser: TTreeParser; - - procedure ScanInfo; - var - v: IXQValue; - begin - with MangaInfo.mangaInfo do begin - //cover - coverLink := SelectXPathString( - '//*[@id="content"]//*[@class="thumbnail"]/img/@src', Parser); - //title - title := SelectXPathString('//*[@id="content"]//h1[@class="title"]', Parser); - //author - authors := TrimLeftChar(SelectXPathString( - '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]', - Parser), [':', ' ']); - //artist - artists := TrimLeftChar(SelectXPathString( - '//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]', - Parser), [':', ' ']); - //summary - summary := TrimLeftChar(SelectXPathString( - '//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]', - Parser), [':', ' ']); - //chapters - for v in SelectXPathIX('//*[@class="list"]//*[@class="title"]/a', Parser) do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - if v.toNode.getAttribute('title') <> '' then - chapterName.Add(v.toNode.getAttribute('title')) - else chapterName.Add(v.toString); - end; - if chapterLinks.Count > 0 then - InvertStrings([chapterLinks, chapterName]); - end; - end; - + query: TXQueryEngineHTML; + v: IXQValue; begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - MangaInfo.mangaInfo.website := Module.Website; - MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); - Source := TStringList.Create; - try - if GetPage(TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then - begin - Result := INFORMATION_NOT_FOUND; - if Source.Count > 0 then - begin - Result := NO_ERROR; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - ScanInfo; - finally - Parser.Free; + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//div[@class="thumbnail"]/img/@src'); + if title=''then title:=query.XPathString('//h1[@class="title"]'); + authors:=TrimLeftChar(query.XPathString('//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'),[':',' ']); + artists:=TrimLeftChar(query.XPathString('//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'),[':',' ']); + summary:=TrimLeftChar(query.XPathString('//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'),[':',' ']); + for v in query.XPath('//div[@class="list"]//div[@class="title"]/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + if v.toNode.getAttribute('title') <> '' then + chapterName.Add(v.toNode.getAttribute('title')) + else chapterName.Add(v.toString); end; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; end; end; - finally - Source.Free; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Parser: TTreeParser; + query: TXQueryEngineHTML; + v: IXQValue; + s: String; begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; - Source := TStringList.Create; - try - if GetPage(TObject(Source), FillHost(Module.RootURL, URL), - Manager.retryConnect) then - begin - if Source.Count > 0 then - begin - Result := True; - Parser := TTreeParser.Create; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').Count; + s:=query.XPathString('//script[contains(.,"var pages")]'); + if s<>'' then begin + s:=GetBetween('var pages = ',';',s); try - ParseHTMLTree(Parser, Source.Text); - PageNumber := SelectXPathIX( - '//*[@class="topbar_right"]//ul[@class="dropdown"]/li', Parser).Count; - finally - Parser.Free; + query.ParseHTML(s); + for v in query.XPath('json(*)()("url")') do + PageLinks.Add(v.toString); + except end; end; + finally + query.Free; end; - finally - Source.Free; end; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; Module: TModuleContainer): Boolean; var - Source: TStringList; - Parser: TTreeParser; + query: TXQueryEngineHTML; + s: String; begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin - Source := TStringList.Create; - try - if GetPage(TObject(Source), FillHost(Module.RootURL, URL) + - 'page/' + IncStr(DownloadThread.workCounter), - Manager.retryConnect) then - begin - if Source.Count > 0 then - begin - Result := True; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - PageLinks[DownloadThread.workCounter] := - SelectXPathString('//*[@id="page"]//img/@src', Parser); - finally - Parser.Free; - end; - end; + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=AURL; + if DownloadThread.workCounter>0 then s:=AppendURLDelim(s)+'page/'+IncStr(DownloadThread.workCounter); + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageLinks[DownloadThread.workCounter]:=query.XPathString('//div[@id="page"]//img/@src'); + finally + query.Free; end; - finally - Source.Free; end; end; end; From ef96156f07fb528f83570a44a5e472e4259f88d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 12:00:43 +0800 Subject: [PATCH 0820/2794] added yomanga and rawyomanga #159 --- baseunits/modules/FoOlSlide.pas | 37 ++++++++++++++++++++++----------- config/mangalist.ini | 4 ++-- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index f6993b882..a82a0d31e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -12,6 +12,7 @@ implementation const dirurl='/directory/'; + yomangadirurl='/reader/directory/'; function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; var Page: Integer; Module: TModuleContainer): Integer; @@ -22,7 +23,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if Module.Website='YoManga' then s:=yomangadirurl + else s:=dirurl; + if MangaInfo.FHTTP.GET(Module.RootURL+s) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try @@ -47,7 +50,9 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; + if Module.Website='YoManga' then s:=yomangadirurl + else s:=dirurl; + s:=Module.RootURL+s; if AURL<>'0' then s+=IncStr(AURL)+'/'; if MangaInfo.FHTTP.GET(s) then begin Result:=NO_ERROR; @@ -159,17 +164,25 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; end; procedure RegisterModule; + + procedure AddWebsiteModule(AWebsite,ARootURL: String); + begin + with AddModule do + begin + Website:=AWebsite; + RootURL:=ARootURL; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; + end; + begin - with AddModule do - begin - Website := 'Shoujosense'; - RootURL := 'http://reader.shoujosense.com'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; + AddWebsiteModule('Shoujosense','http://reader.shoujosense.com'); + AddWebsiteModule('YoManga','http://yomanga.co'); + AddWebsiteModule('RawYoManga','http://raws.yomanga.co'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 107c294eb..1f32a8217 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,14 +5,14 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader Arabic=MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans +English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint,RawSenManga +Raw=MangaMint,RawSenManga,RawYoManga Russian=NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom From 1f83942bbc3b5917f240cf393f911cb01c010487 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 12:27:51 +0800 Subject: [PATCH 0821/2794] add color as const for reuse --- mangadownloader/forms/frmMain.pas | 80 +++++++++++++++++-------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e20eb6ca6..2ebcc2f45 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -706,9 +706,33 @@ TSearchDBThread = class(TThread) FUpdateURL: String; const - CL_HLBlueMarks = $FDC594; - CL_HLGreenMarks = $B8FFB8; - CL_HLRedMarks = $008080FF; + CL_HLBlueMarks = $FDC594; + CL_HLGreenMarks = $B8FFB8; + CL_HLRedMarks = $8080FF; + + CL_BarGrayLine = $bcbcbc; + CL_BarGray = $e6e6e6; + + CL_BarGreenLine = $25b006; + CL_BarGreen = $42d932; + + CL_BarOrangLine = $00b399; + CL_BarOrange = $1870e9; + + CL_BarRedLine = $1a1ab1; + CL_BarRed = $4b4af0; + + CL_BarBlueLine = $b36b1d; + CL_BarBlue = $fab24f; + + CL_BarBlueLigthLine = $eab27c; + CL_BarBlueLigth = $fed2a3; + + CL_BarYellowLine = $4a4af0; + CL_BarYellow = $80ebfe; + + CL_BarBrownGoldLine = $5ea2c8; + CL_BarBrownGold = $8dd5f0; resourcestring RS_FilterStatusItems = 'Completed'#13#10'Ongoing'#13#10'<none>'; @@ -3337,8 +3361,8 @@ procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; Pen.Style := psSolid; Brush.Style := bsSolid; - Pen.Color := RGB(188, 188, 188); - Brush.Color := RGB(230, 230, 230); + Pen.Color:=CL_BarGrayLine; + Brush.Color:=CL_BarGray; Rectangle(BarRect); ProgressBarRect := BarRect; @@ -3347,12 +3371,8 @@ procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; if (ProgressBarRect.Right - ProgressBarRect.Left) > 0 then begin - //green - Pen.Color := RGB(6, 176, 37); - Brush.Color := RGB(50, 217, 66); - //orange - //Pen.Color := RGB(153, 79, 0); - //Brush.Color := RGB(233, 112, 24); + Pen.Color:=CL_BarGreenLine; + Brush.Color:=CL_BarGreen; Rectangle(ProgressBarRect); end; Brush.Style := bsClear; @@ -3468,8 +3488,8 @@ procedure TMainForm.vtDownloadAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas.Pen.Style := psSolid; TargetCanvas.Brush.Style := bsSolid; - TargetCanvas.Pen.Color := RGB(188, 188, 188); - TargetCanvas.Brush.Color := RGB(230, 230, 230); + TargetCanvas.Pen.Color:=CL_BarGrayLine; + TargetCanvas.Brush.Color:=CL_BarGray; TargetCanvas.Rectangle(BarRect); //TargetCanvas.RoundRect(BarRect, 6,6); @@ -3491,43 +3511,33 @@ procedure TMainForm.vtDownloadAfterCellPaint(Sender: TBaseVirtualTree; //STATUS_DOWNLOAD, STATUS_FINISH, STATUS_COMPRESS, STATUS_PROBLEM, STATUS_FAILED); STATUS_STOP, STATUS_FAILED: begin - //Red - TargetCanvas.Pen.Color := RGB(177, 26, 26); - TargetCanvas.Brush.Color := RGB(240, 74, 74); + TargetCanvas.Pen.Color := CL_BarRedLine; + TargetCanvas.Brush.Color := CL_BarRed; end; STATUS_WAIT: begin - //gray - TargetCanvas.Pen.Color := RGB(188, 188, 188); - TargetCanvas.Brush.Color := RGB(230, 230, 230); + TargetCanvas.Pen.Color := CL_BarGray; + TargetCanvas.Brush.Color := CL_BarGrayLine; end; STATUS_DOWNLOAD: begin - //blue - TargetCanvas.Pen.Color := RGB(29, 107, 179); - TargetCanvas.Brush.Color := RGB(79, 178, 250); - //blue light - //TargetCanvas.Pen.Color:= RGB(124,178,234); - //TargetCanvas.Brush.Color:= RGB(163,210,254); + TargetCanvas.Pen.Color := CL_BarBlueLine; + TargetCanvas.Brush.Color := CL_BarBlue; end; STATUS_PROBLEM: begin - //yellow - //TargetCanvas.Pen.Color := RGB(195, 145, 79); - TargetCanvas.Pen.Color := RGB(240, 74, 74); - TargetCanvas.Brush.Color := RGB(254, 235, 128); + TargetCanvas.Pen.Color := CL_BarYellowLine; + TargetCanvas.Brush.Color := CL_BarYellow; end; STATUS_FINISH: begin - //green - TargetCanvas.Pen.Color := RGB(6, 176, 37); - TargetCanvas.Brush.Color := RGB(50, 217, 66); + TargetCanvas.Pen.Color := CL_BarGreenLine; + TargetCanvas.Brush.Color := CL_BarGreenLine; end; else begin - //browngold - TargetCanvas.Pen.Color := RGB(200, 162, 94); - TargetCanvas.Brush.Color := RGB(240, 213, 141); + TargetCanvas.Pen.Color := CL_BarBrownGoldLine; + TargetCanvas.Brush.Color := CL_BarBrownGold; end; end; //TargetCanvas.RoundRect(ProgressBarRect, 5, 5); From df106ca8d45df2f70eec900e236bc17a0482df8e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 12:30:58 +0800 Subject: [PATCH 0822/2794] fix progress bar position in update list statubar --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2ebcc2f45..edbf7ff5b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3344,7 +3344,7 @@ procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; if ulTotalPtr = 0 then ulTotalPtr := 100; if ulWorkPtr > ulTotalPtr then - ulWorkPtr := 0; + ulWorkPtr := ulTotalPtr; Percents := ulWorkPtr / ulTotalPtr; with StatusBar.Canvas do begin From b9ff025613a1b1e890358d36d69d3e9e19ff4265 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 13:22:04 +0800 Subject: [PATCH 0823/2794] frmmain, draw background color for sorted column, download list and favorite list --- mangadownloader/forms/frmMain.lfm | 2 +- mangadownloader/forms/frmMain.pas | 26 ++++++++++++++++++++++++-- mangadownloader/languages/fmd.en.po | 5 +++++ mangadownloader/languages/fmd.id_ID.po | 5 +++++ mangadownloader/languages/fmd.po | 5 +++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index a2617648d..c8dfcfc22 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,7 +13,6 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange LCLVersion = '1.7' - Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -114,6 +113,7 @@ object MainForm: TMainForm TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnAfterCellPaint = vtDownloadAfterCellPaint + OnBeforeCellPaint = vtDownloadBeforeCellPaint OnColumnDblClick = vtDownloadColumnDblClick OnDragAllowed = vtDownloadDragAllowed OnDragOver = vtDownloadDragOver diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index edbf7ff5b..ddccfec72 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -468,6 +468,9 @@ TMainForm = class(TForm) procedure vtDownloadAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const CellRect: TRect); + procedure vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); procedure vtDownloadColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); procedure vtDownloadDragAllowed(Sender : TBaseVirtualTree; @@ -725,8 +728,8 @@ TSearchDBThread = class(TThread) CL_BarBlueLine = $b36b1d; CL_BarBlue = $fab24f; - CL_BarBlueLigthLine = $eab27c; - CL_BarBlueLigth = $fed2a3; + CL_BarBlueLightLine = $eab27c; + CL_BarBlueLight = $fed2a3; CL_BarYellowLine = $4a4af0; CL_BarYellow = $80ebfe; @@ -734,6 +737,9 @@ TSearchDBThread = class(TThread) CL_BarBrownGoldLine = $5ea2c8; CL_BarBrownGold = $8dd5f0; + CL_YellowLight = $eaffff; + CL_BlueLight = $f8f8f3; + resourcestring RS_FilterStatusItems = 'Completed'#13#10'Ongoing'#13#10'<none>'; RS_OptionFMDDoItems = 'Do nothing'#13#10'Exit FMD'#13#10'Shutdown'#13#10'Hibernate'; @@ -3553,6 +3559,17 @@ procedure TMainForm.vtDownloadAfterCellPaint(Sender: TBaseVirtualTree; end; end; +procedure TMainForm.vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +begin + if Column=TVirtualStringTree(Sender).Header.SortColumn then + begin + TargetCanvas.Brush.Color:=CL_BlueLight; + TargetCanvas.FillRect(CellRect); + end; +end; + procedure TMainForm.vtDownloadColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin @@ -3836,6 +3853,11 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; var Data: PFavoriteInfo; begin + if Column=TVirtualStringTree(Sender).Header.SortColumn then + begin + TargetCanvas.Brush.Color:=CL_BlueLight; + TargetCanvas.FillRect(CellRect); + end; Data := Sender.GetNodeData(Node); if Assigned(Data) then begin diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 2b6d07cd9..03e6f65f0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -454,6 +454,11 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" +#: tmainform.caption +msgctxt "tmainform.caption" +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 60d57a164..2d8dd8cae 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -446,6 +446,11 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" +#: tmainform.caption +msgctxt "tmainform.caption" +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 6c64594e3..2738ea8d3 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -418,6 +418,11 @@ msgstr "" msgid "Visit my blog" msgstr "" +#: tmainform.caption +msgctxt "TMAINFORM.CAPTION" +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From 306c697c8455bb929302505fe2af03f76e9e4ea4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 13:26:48 +0800 Subject: [PATCH 0824/2794] frmmain, disable drag on manga list --- mangadownloader/forms/frmMain.lfm | 3 +-- mangadownloader/forms/frmMain.pas | 18 ------------------ 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index c8dfcfc22..bbbd14c61 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3260,6 +3260,7 @@ object MainForm: TMainForm BorderSpacing.Right = 2 BorderSpacing.Around = 2 DefaultText = 'Node' + DragOperations = [] Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 @@ -3278,8 +3279,6 @@ object MainForm: TMainForm OnBeforeCellPaint = vtMangaListBeforeCellPaint OnChange = vtMangaListChange OnColumnDblClick = vtMangaListColumnDblClick - OnDragAllowed = vtMangaListDragAllowed - OnDragOver = vtMangaListDragOver OnGetCursor = vtMangaListGetCursor OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ddccfec72..0a0b3e27a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -518,11 +518,6 @@ TMainForm = class(TForm) procedure vtMangaListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtMangaListColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); - procedure vtMangaListDragAllowed(Sender : TBaseVirtualTree; - Node : PVirtualNode; Column : TColumnIndex; var Allowed : Boolean); - procedure vtMangaListDragOver(Sender : TBaseVirtualTree; Source : TObject; - Shift : TShiftState; State : TDragState; const Pt : TPoint; - Mode : TDropMode; var Effect : LongWord; var Accept : Boolean); procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -4016,19 +4011,6 @@ procedure TMainForm.vtMangaListColumnDblClick(Sender: TBaseVirtualTree; miMangaListViewInfosClick(vtMangaList); end; -procedure TMainForm.vtMangaListDragAllowed(Sender : TBaseVirtualTree; - Node : PVirtualNode; Column : TColumnIndex; var Allowed : Boolean); -begin - Allowed := False; -end; - -procedure TMainForm.vtMangaListDragOver(Sender : TBaseVirtualTree; - Source : TObject; Shift : TShiftState; State : TDragState; const Pt : TPoint; - Mode : TDropMode; var Effect : LongWord; var Accept : Boolean); -begin - Accept := False; -end; - // options procedure TMainForm.btOptionApplyClick(Sender: TObject); From a86d2e558b110fd1a3c57c5220485293adaa4232 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 14:37:31 +0800 Subject: [PATCH 0825/2794] frmmain, cleanup vtdownloadlist, trim unused step, less repaint --- mangadownloader/forms/frmMain.lfm | 4 +- mangadownloader/forms/frmMain.pas | 342 +++++++++++------------------- 2 files changed, 130 insertions(+), 216 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index bbbd14c61..c3ad2e652 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -112,18 +112,16 @@ object MainForm: TMainForm TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnAfterCellPaint = vtDownloadAfterCellPaint OnBeforeCellPaint = vtDownloadBeforeCellPaint OnColumnDblClick = vtDownloadColumnDblClick OnDragAllowed = vtDownloadDragAllowed OnDragOver = vtDownloadDragOver OnDragDrop = vtDownloadDragDrop - OnFreeNode = vtDownloadFreeNode + OnDrawText = vtDownloadDrawText OnGetText = vtDownloadGetText OnGetImageIndex = vtDownloadGetImageIndex OnGetHint = vtDownloadGetHint OnHeaderClick = vtDownloadHeaderClick - OnInitNode = vtDownloadInitNode OnKeyDown = vtDownloadKeyDown OnKeyUp = vtDownloadKeyUp end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0a0b3e27a..4f229b522 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -465,9 +465,6 @@ TMainForm = class(TForm) procedure tvDownloadFilterSelectionChanged(Sender: TObject); procedure UniqueInstanceFMDOtherInstance(Sender: TObject; ParamCount: Integer; Parameters: array of String); - procedure vtDownloadAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - const CellRect: TRect); procedure vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -481,7 +478,9 @@ TMainForm = class(TForm) procedure vtDownloadDragOver(Sender : TBaseVirtualTree; Source : TObject; Shift : TShiftState; State : TDragState; const Pt : TPoint; Mode : TDropMode; var Effect : LongWord; var Accept : Boolean); - procedure vtDownloadFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vtDownloadDrawText(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + const CellText: String; const CellRect: TRect; var DefaultDraw: Boolean); procedure vtDownloadGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -492,8 +491,6 @@ TMainForm = class(TForm) Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure vtDownloadHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - procedure vtDownloadInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure vtDownloadKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); procedure vtDownloadKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); @@ -3457,103 +3454,6 @@ procedure TMainForm.UniqueInstanceFMDOtherInstance(Sender: TObject; BringToFront; end; -procedure TMainForm.vtDownloadAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - const CellRect: TRect); -var - Data: PDownloadInfo; - BarRect, ProgressBarRect: TRect; - Percents: double; - ww, hh: Integer; -begin - if Node = nil then Exit; - if Node^.Index >= DLManager.Count then Exit; - if Column = 2 then - begin - Data := vtDownload.GetNodeData(Node); - //if Data^.Status = stFinish then - if DLManager.TaskItem(Node^.Index).Status in - [STATUS_FINISH, STATUS_COMPRESS, STATUS_FAILED] then - Percents := 1 - else - if StrToIntDef(Trim(ExtractWord(2, Data^.Progress, ['/'])), 100) = 0 then - Percents := 0 - else - Percents := StrToIntDef(Trim(ExtractWord(1, Data^.Progress, ['/'])), 0) / - StrToIntDef(Trim(ExtractWord(2, Data^.Progress, ['/'])), 100); - //progress-bar box - BarRect.Left := CellRect.Left + 2; - BarRect.Top := CellRect.Top + 2; - BarRect.Right := CellRect.Right - 2; - BarRect.Bottom := CellRect.Bottom - 2; - TargetCanvas.Pen.Style := psSolid; - TargetCanvas.Brush.Style := bsSolid; - - TargetCanvas.Pen.Color:=CL_BarGrayLine; - TargetCanvas.Brush.Color:=CL_BarGray; - - TargetCanvas.Rectangle(BarRect); - //TargetCanvas.RoundRect(BarRect, 6,6); - - // a progress-bar - ProgressBarRect := BarRect; - //Inc(ProgressBarRect.Left); - //Inc(ProgressBarRect.Top); - //Dec(ProgressBarRect.Right); - //Dec(ProgressBarRect.Bottom); - ProgressBarRect.Right := round((ProgressBarRect.Right - ProgressBarRect.Left) * - Percents) + ProgressBarRect.Left; - if (ProgressBarRect.Right - ProgressBarRect.Left) > 0 then - begin - //TargetCanvas.Pen.Style:= psClear; - - case DLManager.TaskItem(Node^.Index).Status of - //(STATUS_STOP, STATUS_WAIT, STATUS_PREPARE, - //STATUS_DOWNLOAD, STATUS_FINISH, STATUS_COMPRESS, STATUS_PROBLEM, STATUS_FAILED); - STATUS_STOP, STATUS_FAILED: - begin - TargetCanvas.Pen.Color := CL_BarRedLine; - TargetCanvas.Brush.Color := CL_BarRed; - end; - STATUS_WAIT: - begin - TargetCanvas.Pen.Color := CL_BarGray; - TargetCanvas.Brush.Color := CL_BarGrayLine; - end; - STATUS_DOWNLOAD: - begin - TargetCanvas.Pen.Color := CL_BarBlueLine; - TargetCanvas.Brush.Color := CL_BarBlue; - end; - STATUS_PROBLEM: - begin - TargetCanvas.Pen.Color := CL_BarYellowLine; - TargetCanvas.Brush.Color := CL_BarYellow; - end; - STATUS_FINISH: - begin - TargetCanvas.Pen.Color := CL_BarGreenLine; - TargetCanvas.Brush.Color := CL_BarGreenLine; - end; - else - begin - TargetCanvas.Pen.Color := CL_BarBrownGoldLine; - TargetCanvas.Brush.Color := CL_BarBrownGold; - end; - end; - //TargetCanvas.RoundRect(ProgressBarRect, 5, 5); - TargetCanvas.Rectangle(ProgressBarRect); - //TargetCanvas.FillRect(ProgressBarRect); - end; - //text - TargetCanvas.Font.Color := clBlack; - TargetCanvas.Brush.Style := bsClear; - TargetCanvas.GetTextSize(Data^.Progress, ww, hh); - TargetCanvas.TextOut(CellRect.Left + ((CellRect.Right - CellRect.Left - ww) div 2), - CellRect.Top + ((CellRect.Bottom - CellRect.Top - hh) div 2), Data^.Progress); - end; -end; - procedure TMainForm.vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -3669,73 +3569,130 @@ procedure TMainForm.vtDownloadDragOver(Sender : TBaseVirtualTree; Accept := (Sender = Source); end; -// Download table - -procedure TMainForm.vtDownloadFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + const CellText: String; const CellRect: TRect; var DefaultDraw: Boolean); var - Data: PDownloadInfo; + BarRect, ProgressBarRect: TRect; + Percents: double; + ww, hh: Integer; begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - Finalize(Data^); + if Column = 2 then + begin + DefaultDraw:=False; + if Node=nil then Exit; + if Node^.Index>=DLManager.Count then Exit; + with DLManager.TaskItem(Node^.Index).DownloadInfo,TargetCanvas do begin + if DLManager.TaskItem(Node^.Index).Status in + [STATUS_FINISH, STATUS_COMPRESS, STATUS_FAILED] then + Percents := 1 + else + if StrToIntDef(Trim(ExtractWord(2, Progress, ['/'])), 100) = 0 then + Percents:= 0 + else + Percents:=StrToIntDef(Trim(ExtractWord(1, Progress, ['/'])), 0) / + StrToIntDef(Trim(ExtractWord(2, Progress, ['/'])), 100); + + //base bar + BarRect.Left := CellRect.Left + 2; + BarRect.Top := CellRect.Top + 2; + BarRect.Right := CellRect.Right - 2; + BarRect.Bottom := CellRect.Bottom - 2; + Pen.Style := psSolid; + Brush.Style := bsSolid; + Pen.Color:=CL_BarGrayLine; + Brush.Color:=CL_BarGray; + Rectangle(BarRect); + //progress bar + ProgressBarRect := BarRect; + //Inc(ProgressBarRect.Left); + //Inc(ProgressBarRect.Top); + //Dec(ProgressBarRect.Right); + //Dec(ProgressBarRect.Bottom); + ProgressBarRect.Right := round((ProgressBarRect.Right - ProgressBarRect.Left) * + Percents) + ProgressBarRect.Left; + if (ProgressBarRect.Right - ProgressBarRect.Left) > 0 then + begin + case DLManager.TaskItem(Node^.Index).Status of + STATUS_STOP, + STATUS_FAILED : begin + Pen.Color := CL_BarRedLine; + Brush.Color := CL_BarRed; + end; + STATUS_WAIT : begin + Pen.Color := CL_BarGrayLine; + Brush.Color := CL_BarGray; + end; + STATUS_DOWNLOAD: begin + Pen.Color := CL_BarBlueLine; + Brush.Color := CL_BarBlue; + end; + STATUS_PROBLEM : begin + Pen.Color := CL_BarYellowLine; + Brush.Color := CL_BarYellow; + end; + STATUS_FINISH : begin + Pen.Color := CL_BarGreenLine; + Brush.Color := CL_BarGreenLine; + end; + else begin + Pen.Color := CL_BarBrownGoldLine; + Brush.Color := CL_BarBrownGold; + end; + end; + Rectangle(ProgressBarRect); + end; + //text + Font.Color := clBlack; + Brush.Style := bsClear; + GetTextSize(Progress, ww, hh); + TextOut(CellRect.Left + ((CellRect.Right - CellRect.Left - ww) div 2), + CellRect.Top + ((CellRect.Bottom - CellRect.Top - hh) div 2), Progress); + end; + end; end; +// Download table + procedure TMainForm.vtDownloadGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); var l, i: Cardinal; - p: PDownloadInfo; begin - if Node^.Index >= DLManager.Count then Exit; - if Column = 0 then - begin - l := DLManager.TaskItem(Node^.Index).ChapterLinks.Count; - if l > 0 then - begin - HintText := ''; - if l < 5 then - begin - for i := 0 to l - 1 do - if HintText = '' then - HintText := - DLManager.TaskItem(Node^.Index).ChapterName.Strings[i]{ + ' : ' + - DLManager.TaskItem(Node^.Index).ChapterLinks.Strings[i]} - else - HintText := HintText + LineEnding + - DLManager.TaskItem(Node^.Index).ChapterName.Strings[i]{ + ' : ' + - DLManager.TaskItem(Node^.Index).ChapterLinks.Strings[i]}; - end - else - begin - for i := 0 to 1 do - if HintText = '' then - HintText := - DLManager.TaskItem(Node^.Index).ChapterName.Strings[i]{ + ' : ' + - DLManager.TaskItem(Node^.Index).ChapterLinks.Strings[i]} - else - HintText := HintText + LineEnding + - DLManager.TaskItem(Node^.Index).ChapterName.Strings[i]{ + ' : ' + - DLManager.TaskItem(Node^.Index).ChapterLinks.Strings[i]}; - HintText := HintText + LineEnding + '...'; - for i := l - 2 to l - 1 do - HintText := HintText + LineEnding + - DLManager.TaskItem(Node^.Index).ChapterName.Strings[i]{ + ' : ' + - DLManager.TaskItem(Node^.Index).ChapterLinks.Strings[i]}; - end; - end; - end - else - begin - p := Sender.GetNodeData(Node); + if Node^.Index>=DLManager.Count then Exit; + with DLManager.TaskItem(Node^.Index),DLManager.TaskItem(Node^.Index).DownloadInfo do case Column of - 1: HintText := p^.Status; - 2: HintText := p^.Progress; - 4: HintText := p^.Website; - 5: HintText := p^.SaveTo; - 6: HintText := DateTimeToStr(p^.dateTime); + 0: begin + l := ChapterLinks.Count; + if l>0 then + begin + HintText:=''; + if l<5 then + for i:=0 to l-1 do begin + if HintText<>'' then HintText+=LineEnding; + HintText+=ChapterName.Strings[i] + end + else + begin + for i:=0 to 1 do begin + if HintText<>'' then HintText+=LineEnding; + HintText+=ChapterName.Strings[i] + end; + HintText+=LineEnding+'...'; + for i:=l-2 to l-1 do begin + if HintText<>'' then HintText+=LineEnding; + HintText+=ChapterName.Strings[i] + end; + end; + end; + end; + 1: HintText:=Status; + 2: HintText:=Progress; + 4: HintText:=Website; + 5: HintText:=SaveTo; + 6: HintText:=DateTimeToStr(DateTime); end; - end; end; procedure TMainForm.vtDownloadGetImageIndex(Sender: TBaseVirtualTree; @@ -3744,42 +3701,27 @@ procedure TMainForm.vtDownloadGetImageIndex(Sender: TBaseVirtualTree; begin if (Node^.Index < DLManager.Count) and (vtDownload.Header.Columns[Column].Position = 0) then - ImageIndex := integer(DLManager.TaskItem(Node^.Index).Status); + ImageIndex := Integer(DLManager.TaskItem(Node^.Index).Status); end; procedure TMainForm.vtDownloadGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - Data: PDownloadInfo; - pos: Cardinal; begin if Node^.Index >= DLManager.Count then Exit; - with Sender do - begin - pos := Node^.Index; - Data := Sender.GetNodeData(Node); - if (DLManager.Count > 0) then - if Assigned(Data) and (DLManager.TaskItem(pos) <> nil) then - begin - Data^.Title := DLManager.TaskItem(pos).DownloadInfo.Title; - Data^.Status := DLManager.TaskItem(pos).DownloadInfo.Status; - Data^.Progress := DLManager.TaskItem(pos).DownloadInfo.Progress; - Data^.TransferRate := DLManager.TaskItem(pos).DownloadInfo.TransferRate; - Data^.Website := DLManager.TaskItem(pos).DownloadInfo.Website; - Data^.SaveTo := DLManager.TaskItem(pos).DownloadInfo.SaveTo; - Data^.DateTime := DLManager.TaskItem(pos).DownloadInfo.DateTime; - case Column of - 0: CellText := Data^.title; - 1: CellText := Data^.status; - 2: CellText := ''; - 3: CellText := Data^.TransferRate; - 4: CellText := Data^.website; - 5: CellText := Data^.saveTo; - 6: CellText := DateTimeToStr(Data^.dateTime); - end; - end; - end; + with DLManager.TaskItem(Node^.Index).DownloadInfo do + case Column of + 0: CellText:=Title; + 1: CellText:=Status; + 2: begin + if Progress='' then CellText:='Empty' + else CellText:=Progress; + end; + 3: CellText:=TransferRate; + 4: CellText:=Website; + 5: CellText:=SaveTo; + 6: CellText:=DateTimeToStr(DateTime); + end; end; procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; @@ -3797,32 +3739,6 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; vtDownload.Repaint; end; -procedure TMainForm.vtDownloadInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Data: PDownloadInfo; - pos: Cardinal; -begin - with Sender do - begin - pos := Node^.Index; - Data := GetNodeData(Node); - if (DLManager.Count <> 0) then - if (DLManager.TaskItem(pos) <> nil) or - (not DLManager.TaskItem(pos).Thread.isTerminated) then - begin - Data^.title := DLManager.TaskItem(pos).DownloadInfo.title; - Data^.status := DLManager.TaskItem(pos).DownloadInfo.Status; - Data^.progress := DLManager.TaskItem(pos).DownloadInfo.Progress; - Data^.TransferRate := DLManager.TaskItem(pos).DownloadInfo.TransferRate; - Data^.website := DLManager.TaskItem(pos).DownloadInfo.Website; - Data^.saveTo := DLManager.TaskItem(pos).DownloadInfo.SaveTo; - Data^.dateTime := DLManager.TaskItem(pos).DownloadInfo.dateTime; - end; - end; - vtDownload.ValidateNode(Node, False); -end; - procedure TMainForm.vtDownloadKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); begin From 7fde1411e69f79e53a1be30200f08e6dd48b7890 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 14:55:44 +0800 Subject: [PATCH 0826/2794] downloadmanager, replace taskitem with property Items --- baseunits/uDownloadsManager.pas | 16 ++--- baseunits/uSilentThread.pas | 26 +++---- mangadownloader/forms/frmMain.pas | 108 +++++++++++++++--------------- 3 files changed, 75 insertions(+), 75 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b74e668fb..69d025543 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -150,6 +150,7 @@ TDownloadManager = class FSortDirection: Boolean; FSortColumn: Integer; DownloadManagerFile: TIniFile; + function GetItems(Index: Integer): TTaskContainer; protected function GetTaskCount: Integer; function GetTransferRate: Integer; @@ -175,7 +176,6 @@ TDownloadManager = class constructor Create; destructor Destroy; override; - function TaskItem(const Index: Integer): TTaskContainer; property Count: Integer read GetTaskCount; procedure BackupDownloadedChaptersList; @@ -223,6 +223,7 @@ TDownloadManager = class property SortDirection: Boolean read FSortDirection write FSortDirection; property SortColumn: Integer read FSortColumn write FSortColumn; property TransferRate: Integer read GetTransferRate; + property Items[Index: Integer]: TTaskContainer read GetItems; end; resourcestring @@ -1604,6 +1605,12 @@ destructor TTaskContainer.Destroy; { TDownloadManager } +function TDownloadManager.GetItems(Index: Integer): TTaskContainer; +begin + if (Index<0) or (Containers.Count=0) then Exit(nil); + Result:=TTaskContainer(Containers[Index]); +end; + function TDownloadManager.GetTaskCount: Integer; begin Result := Containers.Count; @@ -1685,13 +1692,6 @@ destructor TDownloadManager.Destroy; inherited Destroy; end; -function TDownloadManager.TaskItem(const Index: Integer): TTaskContainer; -begin - if (Index < 0) or (Containers.Count < 0) then - Exit(nil); - Result := TTaskContainer(Containers[Index]); -end; - procedure TDownloadManager.BackupDownloadedChaptersList; begin if CS_DownloadedChapterList.TryEnter then diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index d08ea1dd3..26fb3e4c0 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -319,7 +319,7 @@ procedure TSilentThread.MainThreadAfterChecking; begin // add a new download task p := DLManager.AddTask; - DLManager.TaskItem(p).Website := website; + DLManager.Items[p].Website := website; if Trim(title) = '' then title := Info.mangaInfo.title; @@ -334,27 +334,27 @@ procedure TSilentThread.MainThreadAfterChecking; Info.mangaInfo.chapterName.Strings[i], Format('%.4d', [i + 1]), OptionChangeUnicodeCharacter); - DLManager.TaskItem(p).chapterName.Add(s); - DLManager.TaskItem(p).chapterLinks.Add( + DLManager.Items[p].chapterName.Add(s); + DLManager.Items[p].chapterLinks.Add( Info.mangaInfo.chapterLinks.Strings[i]); end; if cbAddAsStopped.Checked then begin - DLManager.TaskItem(p).Status := STATUS_STOP; - DLManager.TaskItem(p).downloadInfo.Status := RS_Stopped; + DLManager.Items[p].Status := STATUS_STOP; + DLManager.Items[p].downloadInfo.Status := RS_Stopped; end else begin - DLManager.TaskItem(p).downloadInfo.Status := RS_Waiting; - DLManager.TaskItem(p).Status := STATUS_WAIT; + DLManager.Items[p].downloadInfo.Status := RS_Waiting; + DLManager.Items[p].Status := STATUS_WAIT; end; - DLManager.TaskItem(p).currentDownloadChapterPtr := 0; - DLManager.TaskItem(p).downloadInfo.Website := website; - DLManager.TaskItem(p).downloadInfo.Link := URL; - DLManager.TaskItem(p).downloadInfo.Title := title; - DLManager.TaskItem(p).downloadInfo.DateTime := Now; + DLManager.Items[p].currentDownloadChapterPtr := 0; + DLManager.Items[p].downloadInfo.Website := website; + DLManager.Items[p].downloadInfo.Link := URL; + DLManager.Items[p].downloadInfo.Title := title; + DLManager.Items[p].downloadInfo.DateTime := Now; if FSavePath = '' then begin @@ -377,7 +377,7 @@ procedure TSilentThread.MainThreadAfterChecking; OptionChangeUnicodeCharacter); FSavePath := CorrectPathSys(FSavePath); end; - DLManager.TaskItem(p).downloadInfo.SaveTo := FSavePath; + DLManager.Items[p].downloadInfo.SaveTo := FSavePath; UpdateVtDownload; DLManager.CheckAndActiveTask(False); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 4f229b522..558c85638 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1473,7 +1473,7 @@ procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); i: Integer; begin if vtDownload.Focused then - with DLManager.TaskItem(vtDownload.FocusedNode^.Index) do + with DLManager.Items[vtDownload.FocusedNode^.Index] do begin i := Modules.LocateModule(DownloadInfo.Website); if i > -1 then @@ -1555,28 +1555,28 @@ procedure TMainForm.miDownloadMergeCompletedClick(Sender: TObject); i := DLManager.Count - 1; while i > 0 do begin - if DLManager.TaskItem(i).Status = STATUS_FINISH then + if DLManager.Items[i].Status = STATUS_FINISH then begin j := i - 1; while j > 0 do begin if (i <> j) and - (DLManager.TaskItem(j).Status = STATUS_FINISH) and - SameText(DLManager.TaskItem(i).DownloadInfo.title, - DLManager.TaskItem(j).DownloadInfo.title) and - SameText(DLManager.TaskItem(i).DownloadInfo.website, - DLManager.TaskItem(j).DownloadInfo.website) and - SameText(DLManager.TaskItem(i).DownloadInfo.saveTo, - DLManager.TaskItem(j).DownloadInfo.saveTo) then + (DLManager.Items[j].Status = STATUS_FINISH) and + SameText(DLManager.Items[i].DownloadInfo.title, + DLManager.Items[j].DownloadInfo.title) and + SameText(DLManager.Items[i].DownloadInfo.website, + DLManager.Items[j].DownloadInfo.website) and + SameText(DLManager.Items[i].DownloadInfo.saveTo, + DLManager.Items[j].DownloadInfo.saveTo) then begin - DLManager.TaskItem(i).ChapterLinks.Text := - DLManager.TaskItem(j).ChapterLinks.Text + - DLManager.TaskItem(i).ChapterLinks.Text; - DLManager.TaskItem(i).ChapterName.Text := - DLManager.TaskItem(j).ChapterName.Text + - DLManager.TaskItem(i).ChapterName.Text; - DLManager.TaskItem(i).DownloadInfo.dateTime := - DLManager.TaskItem(j).DownloadInfo.dateTime; + DLManager.Items[i].ChapterLinks.Text := + DLManager.Items[j].ChapterLinks.Text + + DLManager.Items[i].ChapterLinks.Text; + DLManager.Items[i].ChapterName.Text := + DLManager.Items[j].ChapterName.Text + + DLManager.Items[i].ChapterName.Text; + DLManager.Items[i].DownloadInfo.dateTime := + DLManager.Items[j].DownloadInfo.dateTime; DLManager.RemoveTask(j); Dec(i); end; @@ -1758,7 +1758,7 @@ procedure TMainForm.tvDownloadFilterRepaint; if (Assigned(DLManager)) and (DLManager.Count > 0) then for i := 0 to DLManager.Count - 1 do begin - case DLManager.TaskItem(i).Status of + case DLManager.Items[i].Status of STATUS_FINISH: Inc(LFinishedTasks); STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT: Inc(LInProgressTasks); STATUS_STOP: Inc(LStoppedTasks); @@ -1863,7 +1863,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); pos := DLManager.AddTask; isCreate := True; end; - DLManager.TaskItem(pos).Website := mangaInfo.website; + DLManager.Items[pos].Website := mangaInfo.website; // generate chapter folder name s := CustomRename(OptionChapterCustomRename, mangaInfo.website, @@ -1873,8 +1873,8 @@ procedure TMainForm.btDownloadClick(Sender: TObject); mangaInfo.chapterName.Strings[xNode^.Index], Format('%.4d', [xNode^.Index + 1]), OptionChangeUnicodeCharacter); - DLManager.TaskItem(pos).ChapterName.Add(s); - DLManager.TaskItem(pos).ChapterLinks.Add( + DLManager.Items[pos].ChapterName.Add(s); + DLManager.Items[pos].ChapterLinks.Add( mangaInfo.chapterLinks.Strings[xNode^.Index]); ChapterList[xNode^.Index].Downloaded := True; clbChapterList.ReinitNode(xNode, False); @@ -1885,19 +1885,19 @@ procedure TMainForm.btDownloadClick(Sender: TObject); Exit; if cbAddAsStopped.Checked then begin - DLManager.TaskItem(pos).DownloadInfo.Status := RS_Stopped; - DLManager.TaskItem(pos).Status := STATUS_STOP; + DLManager.Items[pos].DownloadInfo.Status := RS_Stopped; + DLManager.Items[pos].Status := STATUS_STOP; end else begin - DLManager.TaskItem(pos).DownloadInfo.Status := RS_Waiting; - DLManager.TaskItem(pos).Status := STATUS_WAIT; + DLManager.Items[pos].DownloadInfo.Status := RS_Waiting; + DLManager.Items[pos].Status := STATUS_WAIT; end; - DLManager.TaskItem(pos).CurrentDownloadChapterPtr := 0; - DLManager.TaskItem(pos).DownloadInfo.Website := mangaInfo.website; - DLManager.TaskItem(pos).DownloadInfo.Link := mangaInfo.url; - DLManager.TaskItem(pos).DownloadInfo.Title := mangaInfo.title; - DLManager.TaskItem(pos).DownloadInfo.DateTime := Now; + DLManager.Items[pos].CurrentDownloadChapterPtr := 0; + DLManager.Items[pos].DownloadInfo.Website := mangaInfo.website; + DLManager.Items[pos].DownloadInfo.Link := mangaInfo.url; + DLManager.Items[pos].DownloadInfo.Title := mangaInfo.title; + DLManager.Items[pos].DownloadInfo.DateTime := Now; s := CorrectPathSys(CleanAndExpandDirectory(edSaveTo.Text)); // save to @@ -1912,14 +1912,14 @@ procedure TMainForm.btDownloadClick(Sender: TObject); '', OptionChangeUnicodeCharacter); s := CorrectPathSys(s); - DLManager.TaskItem(pos).DownloadInfo.SaveTo := s; + DLManager.Items[pos].DownloadInfo.SaveTo := s; UpdateVtDownload; DLManager.CheckAndActiveTask; DLManager.AddToDownloadedChaptersList( - mangaInfo.website + mangaInfo.link, DLManager.TaskItem(pos).ChapterLinks); + mangaInfo.website + mangaInfo.link, DLManager.Items[pos].ChapterLinks); FavoriteManager.AddToDownloadedChaptersList( - mangaInfo.website, mangaInfo.link, DLManager.TaskItem(pos).ChapterLinks); + mangaInfo.website, mangaInfo.link, DLManager.Items[pos].ChapterLinks); clbChapterList.Repaint; pcMain.ActivePage := tsDownload; end; @@ -2910,7 +2910,7 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); if DLManager.Count > 0 then for j := 0 to DLManager.Count - 1 do if dataProcess.Value[xNode^.Index, DATA_PARAM_TITLE] = - DLManager.TaskItem(j).DownloadInfo.title then + DLManager.Items[j].DownloadInfo.title then begin if YesAll then AllowedToCreate := True @@ -2919,7 +2919,7 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); else begin pcMain.ActivePage := tsDownload; - mResult := MessageDlg('', DLManager.TaskItem(j).DownloadInfo.title + + mResult := MessageDlg('', DLManager.Items[j].DownloadInfo.title + LineEnding + LineEnding + RS_DlgTitleExistInDLlist, mtConfirmation, mBtns, 0); case mResult of @@ -3019,7 +3019,7 @@ procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); if (vtDownload.SelectedCount = 0) or (Assigned(vtDownload.FocusedNode) = False) then Exit; OpenDocument(TrimRightChar( - DLManager.TaskItem(vtDownload.FocusedNode^.Index).DownloadInfo.SaveTo, + DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo, [PathDelim])); end; @@ -3064,14 +3064,14 @@ procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); Exit; l := TStringList.Create; try - fd := StringReplace(DLManager.TaskItem( - vtDownload.FocusedNode^.Index).DownloadInfo.SaveTo, '/', '\', [rfReplaceAll]); + fd := StringReplace(DLManager.Items[ + vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo, '/', '\', [rfReplaceAll]); if fd[Length(fd)] <> PathDelim then fd := fd + PathDelim; - if DLManager.TaskItem(vtDownload.FocusedNode^.Index).ChapterName.Count > 0 then + if DLManager.Items[vtDownload.FocusedNode^.Index].ChapterName.Count > 0 then begin - ff := DLManager.TaskItem(vtDownload.FocusedNode^.Index). + ff := DLManager.Items[vtDownload.FocusedNode^.Index]. ChapterName[0]; if FileExistsUTF8(fd + ff + '.zip') then f := ff + '.zip' @@ -3123,7 +3123,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); CS_DownloadManager_Task.Acquire; try for i := 0 to Count - 1 do - if TaskItem(i).Status = STATUS_FINISH then + if Items[i].Status = STATUS_FINISH then begin Result := True; Break; @@ -3147,7 +3147,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); try xNode := vtDownload.GetFirstSelected; repeat - if TaskItem(xNode^.Index).Status in Stats then + if Items[xNode^.Index].Status in Stats then begin Result := True; Break; @@ -3179,14 +3179,14 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); else if vtDownload.SelectedCount = 1 then begin - miDownloadStop.Enabled := (TaskItem(vtDownload.FocusedNode^.Index).Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT]); - miDownloadResume.Enabled := (TaskItem(vtDownload.FocusedNode^.Index).Status in [STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM]); + miDownloadStop.Enabled := (Items[vtDownload.FocusedNode^.Index].Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT]); + miDownloadResume.Enabled := (Items[vtDownload.FocusedNode^.Index].Status in [STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM]); miDownloadDelete.Enabled := True; miDownloadDeleteTask.Enabled := True; miDownloadDeleteTaskData.Enabled := True; miDownloadDeleteCompleted.Enabled := FinishedTaskPresent; miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; - miDownloadViewMangaInfo.Enabled := (TaskItem(vtDownload.FocusedNode^.Index).DownloadInfo.Link <> ''); + miDownloadViewMangaInfo.Enabled := (Items[vtDownload.FocusedNode^.Index].DownloadInfo.Link <> ''); miDownloadOpenFolder.Enabled := True; miDownloadOpenWith.Enabled := True; end @@ -3498,7 +3498,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); if vtDownload.Selected[cNode] then begin vtDownload.Selected[cNode] := False; - ConTemp.Add(DLManager.TaskItem(i)); + ConTemp.Add(DLManager.Items[i]); DLManager.containers.Delete(i); if (i < nIndex) and (nIndex > 0) then Dec(nIndex); @@ -3582,8 +3582,8 @@ procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; DefaultDraw:=False; if Node=nil then Exit; if Node^.Index>=DLManager.Count then Exit; - with DLManager.TaskItem(Node^.Index).DownloadInfo,TargetCanvas do begin - if DLManager.TaskItem(Node^.Index).Status in + with DLManager.Items[Node^.Index].DownloadInfo,TargetCanvas do begin + if DLManager.Items[Node^.Index].Status in [STATUS_FINISH, STATUS_COMPRESS, STATUS_FAILED] then Percents := 1 else @@ -3613,7 +3613,7 @@ procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; Percents) + ProgressBarRect.Left; if (ProgressBarRect.Right - ProgressBarRect.Left) > 0 then begin - case DLManager.TaskItem(Node^.Index).Status of + case DLManager.Items[Node^.Index].Status of STATUS_STOP, STATUS_FAILED : begin Pen.Color := CL_BarRedLine; @@ -3661,7 +3661,7 @@ procedure TMainForm.vtDownloadGetHint(Sender: TBaseVirtualTree; l, i: Cardinal; begin if Node^.Index>=DLManager.Count then Exit; - with DLManager.TaskItem(Node^.Index),DLManager.TaskItem(Node^.Index).DownloadInfo do + with DLManager.Items[Node^.Index],DLManager.Items[Node^.Index].DownloadInfo do case Column of 0: begin l := ChapterLinks.Count; @@ -3701,7 +3701,7 @@ procedure TMainForm.vtDownloadGetImageIndex(Sender: TBaseVirtualTree; begin if (Node^.Index < DLManager.Count) and (vtDownload.Header.Columns[Column].Position = 0) then - ImageIndex := Integer(DLManager.TaskItem(Node^.Index).Status); + ImageIndex := Integer(DLManager.Items[Node^.Index].Status); end; procedure TMainForm.vtDownloadGetText(Sender: TBaseVirtualTree; @@ -3709,7 +3709,7 @@ procedure TMainForm.vtDownloadGetText(Sender: TBaseVirtualTree; var CellText: String); begin if Node^.Index >= DLManager.Count then Exit; - with DLManager.TaskItem(Node^.Index).DownloadInfo do + with DLManager.Items[Node^.Index].DownloadInfo do case Column of 0: CellText:=Title; 1: CellText:=Status; @@ -4037,7 +4037,7 @@ procedure TMainForm.ShowTasks(Status: TDownloadStatusTypes); if Status = [] then vtDownload.isVisible[xNode] := True else - vtDownload.IsVisible[xNode] := DLManager.TaskItem(i).Status in Status; + vtDownload.IsVisible[xNode] := DLManager.Items[i].Status in Status; if canExit then Exit; if xNode = vtDownload.GetFirst then @@ -4066,7 +4066,7 @@ procedure TMainForm.ShowTasksOnCertainDays(const L, H: longint); begin if i < DLManager.Count then begin - dt := DLManager.TaskItem(i).DownloadInfo.dateTime; + dt := DLManager.Items[i].DownloadInfo.dateTime; DecodeDate(dt, year, month, day); jdn := DateToJDN(year, month, day); From 39ec798823467a30b091db0e28347cba852ab13d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 15:10:50 +0800 Subject: [PATCH 0827/2794] cleanup --- mangadownloader/forms/frmMain.pas | 81 +++++++++++++++---------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 558c85638..7882d8641 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1550,33 +1550,26 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); procedure TMainForm.miDownloadMergeCompletedClick(Sender: TObject); var i, j: Cardinal; + ic, jc: TTaskContainer; // merge all finished tasks that have same manga name, website and directory begin - i := DLManager.Count - 1; - while i > 0 do - begin - if DLManager.Items[i].Status = STATUS_FINISH then + i:=DLManager.Count-1; + while i>0 do begin + ic:=DLManager.Items[i]; + if ic.Status=STATUS_FINISH then begin - j := i - 1; - while j > 0 do - begin - if (i <> j) and - (DLManager.Items[j].Status = STATUS_FINISH) and - SameText(DLManager.Items[i].DownloadInfo.title, - DLManager.Items[j].DownloadInfo.title) and - SameText(DLManager.Items[i].DownloadInfo.website, - DLManager.Items[j].DownloadInfo.website) and - SameText(DLManager.Items[i].DownloadInfo.saveTo, - DLManager.Items[j].DownloadInfo.saveTo) then + j:=i-1; + while j>0 do begin + jc:=DLManager.Items[j]; + if (i<>j) and + (jc.Status = STATUS_FINISH) and + SameText(ic.DownloadInfo.title,jc.DownloadInfo.title) and + SameText(ic.DownloadInfo.website,jc.DownloadInfo.website) and + SameText(ic.DownloadInfo.saveTo,jc.DownloadInfo.saveTo) then begin - DLManager.Items[i].ChapterLinks.Text := - DLManager.Items[j].ChapterLinks.Text + - DLManager.Items[i].ChapterLinks.Text; - DLManager.Items[i].ChapterName.Text := - DLManager.Items[j].ChapterName.Text + - DLManager.Items[i].ChapterName.Text; - DLManager.Items[i].DownloadInfo.dateTime := - DLManager.Items[j].DownloadInfo.dateTime; + ic.ChapterLinks.Text:=jc.ChapterLinks.Text+ic.ChapterLinks.Text; + ic.ChapterName.Text:=jc.ChapterName.Text+ic.ChapterName.Text; + ic.DownloadInfo.dateTime:=jc.DownloadInfo.dateTime; DLManager.RemoveTask(j); Dec(i); end; @@ -1759,31 +1752,35 @@ procedure TMainForm.tvDownloadFilterRepaint; for i := 0 to DLManager.Count - 1 do begin case DLManager.Items[i].Status of - STATUS_FINISH: Inc(LFinishedTasks); - STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT: Inc(LInProgressTasks); - STATUS_STOP: Inc(LStoppedTasks); - STATUS_PROBLEM, STATUS_FAILED: Inc(LFailedTask); + STATUS_FINISH : Inc(LFinishedTasks); + STATUS_DOWNLOAD, + STATUS_PREPARE, + STATUS_WAIT : Inc(LInProgressTasks); + STATUS_STOP : Inc(LStoppedTasks); + STATUS_PROBLEM, + STATUS_FAILED : Inc(LFailedTask); end; end; - // root - tvDownloadFilter.Items[0].Text := - Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); + with tvDownloadFilter do begin + // root + Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); - // childs - tvDownloadFilter.Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); - tvDownloadFilter.Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); - tvDownloadFilter.Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); - tvDownloadFilter.Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); + // childs + Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); + Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); + Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); + Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); - // root - tvDownloadFilter.Items[5].Text := RS_History; + // root + Items[5].Text := RS_History; - // childs - tvDownloadFilter.Items[6].Text := RS_Today; - tvDownloadFilter.Items[7].Text := RS_Yesterday; - tvDownloadFilter.Items[8].Text := RS_OneWeek; - tvDownloadFilter.Items[9].Text := RS_OneMonth; + // childs + Items[6].Text := RS_Today; + Items[7].Text := RS_Yesterday; + Items[8].Text := RS_OneWeek; + Items[9].Text := RS_OneMonth; + end; end; procedure TMainForm.GeneratetvDownloadFilterNodes; From 8c2214fd9b227efe434e54ac691ab2d6ee74429c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 15:31:24 +0800 Subject: [PATCH 0828/2794] frmmain, cleanup vtfavorites --- mangadownloader/forms/frmMain.lfm | 3 - mangadownloader/forms/frmMain.pas | 97 ++++++++----------------------- 2 files changed, 25 insertions(+), 75 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index c3ad2e652..9a39a4a91 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -496,7 +496,6 @@ object MainForm: TMainForm TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = clbChapterListBeforeCellPaint - OnFreeNode = clbChapterListFreeNode OnGetText = clbChapterListGetText OnGetNodeDataSize = clbChapterListGetNodeDataSize OnInitNode = clbChapterListInitNode @@ -1719,12 +1718,10 @@ object MainForm: TMainForm TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = vtFavoritesBeforeCellPaint OnColumnDblClick = vtFavoritesColumnDblClick - OnFreeNode = vtFavoritesFreeNode OnGetText = vtFavoritesGetText OnGetImageIndex = vtFavoritesGetImageIndex OnGetHint = vtFavoritesGetHint OnHeaderClick = vtFavoritesHeaderClick - OnInitNode = vtFavoritesInitNode end object btFavoritesImport: TBitBtn Left = 33 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7882d8641..0c13d9ce3 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -499,7 +499,6 @@ TMainForm = class(TForm) CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); procedure vtFavoritesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); - procedure vtFavoritesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtFavoritesGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -510,8 +509,6 @@ TMainForm = class(TForm) Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure vtFavoritesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - procedure vtFavoritesInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure vtMangaListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtMangaListColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); @@ -3792,58 +3789,36 @@ procedure TMainForm.vtFavoritesColumnDblClick(Sender: TBaseVirtualTree; miFavoritesOpenFolderClick(Sender); end; -procedure TMainForm.vtFavoritesFreeNode(Sender: TBaseVirtualTree; - Node: PVirtualNode); -var - Data: PFavoriteInfo; -begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - Finalize(Data^); -end; - procedure TMainForm.vtFavoritesGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); -var - Data: PFavoriteInfo; begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then + if Node^.Index>=FavoriteManager.Count then Exit; + with FavoriteManager.FavoriteItem(Node^.Index).FavoriteInfo do case Column of - 1: if Trim(Data^.Link) = '' then - HintText := RS_HintFavoriteProblem - else - HintText := Data^.Title; - 2: HintText := Data^.currentChapter; - 3: HintText := Data^.website; - 4: HintText := Data^.saveTo; + 1: if Trim(Link)='' then HintText:=RS_HintFavoriteProblem + else HintText:=Title; + 2: HintText:=currentChapter; + 3: HintText:=website; + 4: HintText:=saveTo; end; end; procedure TMainForm.vtFavoritesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); -var - Data: PFavoriteInfo; begin - if vtFavorites.Header.Columns[Column].Position = 1 then - begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - with FavoriteManager.FavoriteItem(Node^.Index) do - begin - if Trim(FavoriteInfo.Link) = '' then - ImageIndex := 16 - else - case Status of - STATUS_CHECK: ImageIndex := 19; - STATUS_CHECKING: ImageIndex := 12; - STATUS_CHECKED: ImageIndex := 20; - else - ImageIndex := -1; - end; - end; + if vtFavorites.Header.Columns[Column].Position<>1 then Exit; + if Node^.Index>=FavoriteManager.Count then Exit; + if Trim(FavoriteManager.FavoriteItem(Node^.Index).FavoriteInfo.Link)='' then + ImageIndex:=16 + else + case FavoriteManager.FavoriteItem(Node^.Index).Status of + STATUS_CHECK : ImageIndex:=19; + STATUS_CHECKING : ImageIndex:=12; + STATUS_CHECKED : ImageIndex:=20; + else + ImageIndex:=-1; end; end; @@ -3852,17 +3827,15 @@ procedure TMainForm.vtFavoritesGetImageIndex(Sender: TBaseVirtualTree; procedure TMainForm.vtFavoritesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - Data: PFavoriteInfo; begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then + if Node^.Index>=FavoriteManager.Count then Exit; + with FavoriteManager.FavoriteItem(Node^.Index).FavoriteInfo do case Column of - 0: CellText := Data^.numbering; - 1: CellText := Data^.Title; - 2: CellText := Data^.currentChapter; - 3: CellText := Data^.website; - 4: CellText := Data^.saveTo; + 0: CellText:=IntToStr(Node^.Index+1); + 1: CellText:=Title; + 2: CellText:=currentChapter; + 3: CellText:=website; + 4: CellText:=saveTo; end; end; @@ -3887,26 +3860,6 @@ procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; end; end; -procedure TMainForm.vtFavoritesInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Data: PFavoriteInfo; - pos: Cardinal; -begin - with Sender do - begin - pos := Node^.Index; - Data := GetNodeData(Node); - Data^.numbering := IntToStr(QWord(pos) + 1); - Data^.Title := FavoriteManager.FavoriteItem(pos).FavoriteInfo.Title; - Data^.currentChapter := FavoriteManager.FavoriteItem(pos).FavoriteInfo.currentChapter; - Data^.website := FavoriteManager.FavoriteItem(pos).FavoriteInfo.website; - Data^.saveTo := FavoriteManager.FavoriteItem(pos).FavoriteInfo.saveTo; - Data^.Link := FavoriteManager.FavoriteItem(pos).FavoriteInfo.Link; - end; - vtFavorites.ValidateNode(Node, False); -end; - procedure TMainForm.vtMangaListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); begin //if (NOT isUpdating) then From 22e629e419c2ae17b3fb493a9e3a49887d20347e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 15:44:20 +0800 Subject: [PATCH 0829/2794] frmmain, cleanup clbchapterlist --- mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.pas | 62 +++++++------------------------ 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9a39a4a91..e0770ae01 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -497,7 +497,6 @@ object MainForm: TMainForm TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = clbChapterListBeforeCellPaint OnGetText = clbChapterListGetText - OnGetNodeDataSize = clbChapterListGetNodeDataSize OnInitNode = clbChapterListInitNode end object btReadOnline: TBitBtn diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0c13d9ce3..614472d5a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -364,15 +364,11 @@ TMainForm = class(TForm) procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure clbChapterListFreeNode(Sender : TBaseVirtualTree; - Node : PVirtualNode); - procedure clbChapterListGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); procedure clbChapterListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure clbChapterListInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure edSearchChange(Sender: TObject); procedure edSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState ); @@ -2269,59 +2265,29 @@ procedure TMainForm.clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin - if Assigned(Node) then - if ChapterList[Node^.Index].Downloaded then - begin - TargetCanvas.Brush.Color := CL_HLGreenMarks; - TargetCanvas.FillRect(CellRect); - end; -end; - -procedure TMainForm.clbChapterListFreeNode(Sender : TBaseVirtualTree; - Node : PVirtualNode); -var - Data: PChapterStateItem; -begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - Finalize(Data^); -end; - -procedure TMainForm.clbChapterListGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TChapterStateItem); + if Node^.Index>=Length(ChapterList) then Exit; + if ChapterList[Node^.Index].Downloaded then + begin + TargetCanvas.Brush.Color:=CL_HLGreenMarks; + TargetCanvas.FillRect(CellRect); + end; end; procedure TMainForm.clbChapterListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - Data: PChapterStateItem; begin - Data := clbChapterList.GetNodeData(Node); - if Assigned(Data) then - CellText := Data^.Title; + if Node^.Index>=Length(ChapterList) then Exit; + if Length(ChapterList)=1 then + CellText:=ChapterList[Node^.Index].Title + else + CellText:=Format('%.4d - %s',[Node^.Index+1,ChapterList[Node^.Index].Title]); end; procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Data: PChapterStateItem; begin - with Sender do - begin - Data := GetNodeData(Node); - if mangaInfo.chapterName.Count = 1 then - Data^.Title := ChapterList[Node^.Index].Title - else - Data^.Title := Format('%.4d - %s', [Node^.Index + 1, - ChapterList[Node^.Index].Title]); - Data^.Link := ChapterList[Node^.Index].Link; - Data^.Downloaded := ChapterList[Node^.Index].Downloaded; - Node^.CheckType := ctCheckBox; - clbChapterList.ValidateNode(Node, False); - end; + if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; procedure TMainForm.edURLKeyPress(Sender: TObject; var Key: Char); From e48c5a77396f22976fb5835dd1808aeee449a8f7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 15:55:26 +0800 Subject: [PATCH 0830/2794] favoritemanager, replace favoriteitem with property items --- baseunits/uFavoritesManager.pas | 31 +++++++++++----------- mangadownloader/forms/frmMain.pas | 44 +++++++++++++++---------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index ae5811d5f..8205eb9b0 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -86,6 +86,7 @@ TFavoriteManager = class FSortColumn: Integer; FSortDirection, FIsAuto, FIsRunning: Boolean; FFavorites: TFPList; + function GetItems(Index: Integer): TFavoriteContainer; protected function GetFavoritesCount: Integer; public @@ -98,8 +99,6 @@ TFavoriteManager = class constructor Create; destructor Destroy; override; - function FavoriteItem(const Index: Integer): TFavoriteContainer; - //Check favorites procedure CheckForNewChapter(FavoriteIndex: Integer = -1); procedure StopChekForNewChapter(WaitFor: Boolean = True; FavoriteIndex: Integer = -1); @@ -137,6 +136,7 @@ TFavoriteManager = class property SortColumn: Integer read FSortColumn write FSortColumn; property isAuto: Boolean read FIsAuto write FIsAuto; property isRunning: Boolean read FIsRunning write FIsRunning; + property Items[Index: Integer]: TFavoriteContainer read GetItems; end; resourcestring @@ -301,7 +301,7 @@ procedure TFavoriteTask.Checkout; with thread do begin task := Self; - container := manager.FavoriteItem(i); + container := manager.Items[i]; workCounter := i; Start; end; @@ -406,6 +406,12 @@ destructor TFavoriteTask.Destroy; { TFavoriteManager } +function TFavoriteManager.GetItems(Index: Integer): TFavoriteContainer; +begin + if (Index<0) or (Index>=FFavorites.Count) then Exit(nil); + Result := TFavoriteContainer(FFavorites.Items[Index]); +end; + function TFavoriteManager.GetFavoritesCount: Integer; begin CS_Favorites.Acquire; @@ -444,13 +450,6 @@ destructor TFavoriteManager.Destroy; inherited Destroy; end; -function TFavoriteManager.FavoriteItem(const Index: Integer): TFavoriteContainer; -begin - if (Index < 0) or (Index >= FFavorites.Count) then - Exit(nil); - Result := TFavoriteContainer(FFavorites.Items[Index]); -end; - procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); var i: Integer; @@ -543,7 +542,7 @@ procedure TFavoriteManager.ShowResult; numOfCompleted := 0; counter := 0; while counter < FFavorites.Count do - with FavoriteItem(counter) do try + with Items[counter] do try if Assigned(MangaInfo) then if MangaInfo.chapterLinks.Count > 0 then begin @@ -571,7 +570,7 @@ procedure TFavoriteManager.ShowResult; begin newChapterListStr := newChapterListStr + LineEnding + '- ' + Format(RS_FavoriteHasNewChapter, - [FavoriteInfo.Title, FavoriteItem(counter).FavoriteInfo.Website, + [FavoriteInfo.Title, Items[counter].FavoriteInfo.Website, NewMangaInfo.chapterLinks.Count]); Inc(numOfMangaNewChapters); end; @@ -618,11 +617,11 @@ procedure TFavoriteManager.ShowResult; while counter < FFavorites.Count do begin favDelete := False; - with FavoriteItem(counter) do if Assigned(NewMangaInfo) then + with Items[counter] do if Assigned(NewMangaInfo) then if (NewMangaInfo.chapterLinks.Count = 0) and (NewMangaInfo.status = '0') then begin - FavoriteItem(counter).Free; + Items[counter].Free; FFavorites.Delete(counter); favDelete := True; end; @@ -666,7 +665,7 @@ procedure TFavoriteManager.ShowResult; counter := 0; while counter < FFavorites.Count do begin - with FavoriteItem(counter) do if Assigned(NewMangaInfo) then + with Items[counter] do if Assigned(NewMangaInfo) then if NewMangaInfo.chapterLinks.Count > 0 then begin DLManager.CS_DownloadManager_Task.Acquire; @@ -736,7 +735,7 @@ procedure TFavoriteManager.ShowResult; counter := 0; while counter < FFavorites.Count do begin - with FavoriteItem(counter) do begin + with Items[counter] do begin if Assigned(MangaInfo) then FreeAndNil(MangaInfo); if Assigned(NewMangaInfo) then diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 614472d5a..bc8f27e7d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1604,7 +1604,7 @@ procedure TMainForm.miFavoritesDownloadAllClick(Sender: TObject); for i := 0 to vtFavorites.SelectedCount - 1 do begin if vtFavorites.Selected[xNode] then - with FavoriteManager.FavoriteItem(xNode^.Index).FavoriteInfo do + with FavoriteManager.Items[xNode^.Index].FavoriteInfo do SilentThreadManager.Add(MD_DownloadAll, Website, Title, Link, SaveTo); xNode := vtFavorites.GetNextSelected(xNode); end; @@ -1647,9 +1647,9 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); rmInformation.Lines.Add('Loading ...'); clbChapterList.Clear; - website := FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.Website; - link := FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.link; - title := FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.Title; + website := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Website; + link := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.link; + title := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Title; if isGetMangaInfos then begin @@ -2569,13 +2569,13 @@ procedure TMainForm.miFavoritesChangeCurrentChapterClick(Sender: TObject); end; if not Assigned(vtFavorites.FocusedNode) then Exit; - s := FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.currentChapter; + s := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter; repeat if InputQuery('', RS_DlgTypeInNewChapter, s) then until TryStrToInt(s, i); - if s <> FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.currentChapter then + if s <> FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter then begin - FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.currentChapter := s; + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter := s; UpdateVtFavorites; FavoriteManager.Backup; end; @@ -2592,10 +2592,10 @@ procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); if not Assigned(vtFavorites.FocusedNode) then Exit; if InputQuery('', RS_DlgTypeInNewSavePath, - FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.SaveTo) then + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo) then begin - FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.SaveTo := - CorrectFilePath(FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.SaveTo); + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := + CorrectFilePath(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); UpdateVtFavorites; FavoriteManager.Backup; end; @@ -2970,7 +2970,7 @@ procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); if not Assigned(vtFavorites.FocusedNode) then Exit; OpenDocument(TrimRightChar( - FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.SaveTo, + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo, [PathDelim])); end; @@ -2993,8 +2993,8 @@ procedure TMainForm.miFavoritesOpenWithClick(Sender: TObject); Exit; l := TStringList.Create; try - fd := StringReplace(FavoriteManager.FavoriteItem( - vtFavorites.FocusedNode^.Index).FavoriteInfo.SaveTo, '/', '\', [rfReplaceAll]); + fd := StringReplace(FavoriteManager.Items[ + vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo, '/', '\', [rfReplaceAll]); if fd[Length(fd)] <> PathDelim then fd := fd + PathDelim; @@ -3195,7 +3195,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); repeat if Assigned(xNode) then begin - if FavoriteManager.FavoriteItem(xNode^.Index).Status in Stats then + if FavoriteManager.Items[xNode^.Index].Status in Stats then begin Result := True; Break; @@ -3227,12 +3227,12 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesStopCheckNewChapter.Visible := SelectedStatusPresent([STATUS_CHECK, STATUS_CHECKING]); miFavoritesViewInfos.Enabled := True; - miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.FavoriteItem( - vtFavorites.FocusedNode^.Index).FavoriteInfo.Link) <> ''); + miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.Items[ + vtFavorites.FocusedNode^.Index].FavoriteInfo.Link) <> ''); miFavoritesDelete.Enabled := True; miFavoritesChangeSaveTo.Enabled := True; miFavoritesOpenFolder.Enabled := - DirectoryExistsUTF8(FavoriteManager.FavoriteItem(vtFavorites.FocusedNode^.Index).FavoriteInfo.SaveTo); + DirectoryExistsUTF8(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); miFavoritesOpenWith.Enabled := miFavoritesOpenFolder.Enabled; end else @@ -3732,7 +3732,7 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; Data := Sender.GetNodeData(Node); if Assigned(Data) then begin - with FavoriteManager.FavoriteItem(Node^.Index) do + with FavoriteManager.Items[Node^.Index] do begin if Trim(FavoriteInfo.Link) = '' then begin @@ -3760,7 +3760,7 @@ procedure TMainForm.vtFavoritesGetHint(Sender: TBaseVirtualTree; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); begin if Node^.Index>=FavoriteManager.Count then Exit; - with FavoriteManager.FavoriteItem(Node^.Index).FavoriteInfo do + with FavoriteManager.Items[Node^.Index].FavoriteInfo do case Column of 1: if Trim(Link)='' then HintText:=RS_HintFavoriteProblem else HintText:=Title; @@ -3776,10 +3776,10 @@ procedure TMainForm.vtFavoritesGetImageIndex(Sender: TBaseVirtualTree; begin if vtFavorites.Header.Columns[Column].Position<>1 then Exit; if Node^.Index>=FavoriteManager.Count then Exit; - if Trim(FavoriteManager.FavoriteItem(Node^.Index).FavoriteInfo.Link)='' then + if Trim(FavoriteManager.Items[Node^.Index].FavoriteInfo.Link)='' then ImageIndex:=16 else - case FavoriteManager.FavoriteItem(Node^.Index).Status of + case FavoriteManager.Items[Node^.Index].Status of STATUS_CHECK : ImageIndex:=19; STATUS_CHECKING : ImageIndex:=12; STATUS_CHECKED : ImageIndex:=20; @@ -3795,7 +3795,7 @@ procedure TMainForm.vtFavoritesGetText(Sender: TBaseVirtualTree; var CellText: String); begin if Node^.Index>=FavoriteManager.Count then Exit; - with FavoriteManager.FavoriteItem(Node^.Index).FavoriteInfo do + with FavoriteManager.Items[Node^.Index].FavoriteInfo do case Column of 0: CellText:=IntToStr(Node^.Index+1); 1: CellText:=Title; From 1e6a07bf7dee8d1e3c7df35c30096dca4f041748 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 16:00:29 +0800 Subject: [PATCH 0831/2794] frmmain, vtfavorites, first column is fixed, index --- mangadownloader/forms/frmMain.lfm | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e0770ae01..be4b85beb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1677,6 +1677,7 @@ object MainForm: TMainForm Header.Columns = < item Alignment = taRightJustify + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coFixed] Position = 0 Text = '#' end From 08ed84eb3a4cb29e08dc7bb3ea37d2be20b10cf2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 17:49:22 +0800 Subject: [PATCH 0832/2794] baseunit, change streamtostring parameter to tstream --- baseunits/uBaseUnit.pas | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 227d195b0..59760e452 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -854,7 +854,7 @@ function Base64Decode(const s: string): string; // StringUtils function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; -function StreamToString(const M: TMemoryStream): string; inline; +function StreamToString(const Stream: TStream): string; inline; function GetRightValue(const name, s: string): string; function QuotedStrd(const S: string): string; overload; inline; function QuotedStrd(const S: Integer): string; overload; inline; @@ -1662,9 +1662,15 @@ procedure ConvertCharsetToUTF8(S: TStrings); if cs <> '' then S.Text := ConvertEncoding(S.Text, cs, 'utf8'); end; -function StreamToString(const M: TMemoryStream): string; +function StreamToString(const Stream: TStream): string; +var + x: Integer; begin - SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char)); + //SetString(Result, PChar(Stream.Memory), Stream.Size div SizeOf(Char)); + Stream.Position:=0; + Setlength(Result,Stream.Size); + x:=Stream.Read(PChar(Result)^,Stream.Size); + SetLength(Result,x); end; function GetRightValue(const name, s: string): string; From f93803dd9cf7343282b41da269f81c56ef9de7d1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 17:53:35 +0800 Subject: [PATCH 0833/2794] baseunit, overload txqueryenginehtml.parsehtml with tstream --- baseunits/uBaseUnit.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 59760e452..f60533c46 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -762,7 +762,8 @@ TXQueryEngineHTML = class public constructor Create(HTML: String = ''); destructor Destroy; override; - procedure ParseHTML(HTML: String); + procedure ParseHTML(HTML: String); overload; + procedure ParseHTML(Stream: TStream); overload; function XPath(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; function XPathString(Expression: String; Tree: TTreeNode = nil): String; inline; function CSS(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; @@ -3744,6 +3745,11 @@ procedure TXQueryEngineHTML.ParseHTML(HTML: String); if HTML <> '' then FTreeParser.parseTree(HTML); end; +procedure TXQueryEngineHTML.ParseHTML(Stream: TStream); +begin + ParseHTML(StreamToString(Stream)); +end; + function TXQueryEngineHTML.XPath(Expression: String; Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, False, Tree); From 701db7cdb89a8ec1a122313b056d3276148d7217 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 17:59:03 +0800 Subject: [PATCH 0834/2794] baseunit, overload txqueryenginehtml.parsehtml with tstream --- baseunits/uBaseUnit.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f60533c46..e5bedcf17 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -763,7 +763,7 @@ TXQueryEngineHTML = class constructor Create(HTML: String = ''); destructor Destroy; override; procedure ParseHTML(HTML: String); overload; - procedure ParseHTML(Stream: TStream); overload; + procedure ParseHTML(HTMLStream: TStream); overload; function XPath(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; function XPathString(Expression: String; Tree: TTreeNode = nil): String; inline; function CSS(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; @@ -3745,9 +3745,9 @@ procedure TXQueryEngineHTML.ParseHTML(HTML: String); if HTML <> '' then FTreeParser.parseTree(HTML); end; -procedure TXQueryEngineHTML.ParseHTML(Stream: TStream); +procedure TXQueryEngineHTML.ParseHTML(HTMLStream: TStream); begin - ParseHTML(StreamToString(Stream)); + ParseHTML(StreamToString(HTMLStream)); end; function TXQueryEngineHTML.XPath(Expression: String; Tree: TTreeNode): IXQValue; From d39351f8aa9cb4487b59dd42be4aeb9b4f37a17b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 18:06:50 +0800 Subject: [PATCH 0835/2794] added gameofscanlation close #159 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/GameofScanlation.pas | 156 +++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/GameofScanlation.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 3de3f6d34..3cbdf2e10 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -22,4 +22,5 @@ uses UnionMangas, Seemh, MangaStreamTo, - MangaKoi; + MangaKoi, + GameofScanlation; diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas new file mode 100644 index 000000000..e911145e0 --- /dev/null +++ b/baseunits/modules/GameofScanlation.pas @@ -0,0 +1,156 @@ +unit GameofScanlation; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr, synautil; + +implementation + +const + dirurl='/forums/projects-releases.9/'; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(MangaInfo.FHTTP.Document); + for v in query.XPath('//h4/a[@class="menuRow"]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + i, p: Integer; + rurl: String; + + procedure GetChapters; + begin + for v in query.XPath('//*[@class="discussionListItems"]//div[@class="listBlock main"]/div/h3/a') do begin + MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); + MangaInfo.mangaInfo.chapterName.Add(v.toString); + end; + end; + +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + rurl:=AppendURLDelim(FillHost(Module.RootURL,AURL)); + if GET(rurl) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(Document); + if title=''then title:=query.XPathString('//div[@class="titleBarContent"]/h1'); + GetChapters; + p:=StrToIntDef(query.XPathString('(//div[@class="PageNav"])[1]/@data-end'),1); + if p>1 then + for i:=2 to p do + if GET(rurl+'page-'+IntToStr(i)) then begin + query.ParseHTML(Document); + GetChapters; + end; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: RegExprString; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + s:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); + s:=AppendURLDelim(FillHost(Module.RootURL,s))+'?chapter_view=fullstrip'; + if GET(s) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(Document); + for v in query.XPath('//div[@id="comicMainImage"]/a/img/@src') do + PageLinks.Add(MaybeFillHost(Module.RootURL,v.toString)); + PageNumber:=query.XPath('//select[@id="ctrl_chapter_page"]/option').Count; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=AppendURLDelim(AURL); + if DownloadThread.workCounter>0 then s+='?comic_page='+IncStr(DownloadThread.workCounter); + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(Document); + s:=query.XPathString('//img[@id="comicMainImage"]/@src'); + if s<>'' then begin + s:=MaybeFillHost(Module.RootURL,s); + PageLinks[DownloadThread.workCounter]:=s; + end; + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='GameofScanlation'; + RootURL:='https://gameofscanlation.moe'; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 1f32a8217..ce76dfa0e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,7 +5,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader Arabic=MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,Mangacow,MangaStream,RedHawkScans,S2Scans,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,RedHawkScans,S2Scans,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From 58a0fd45cfb688a5ba9f8cae6ae6a42e27c5bf00 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 18:17:02 +0800 Subject: [PATCH 0836/2794] gameofscanlation, fix total sub page for chapters --- baseunits/modules/GameofScanlation.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index e911145e0..97e2c3396 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -64,7 +64,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; query.ParseHTML(Document); if title=''then title:=query.XPathString('//div[@class="titleBarContent"]/h1'); GetChapters; - p:=StrToIntDef(query.XPathString('(//div[@class="PageNav"])[1]/@data-end'),1); + p:=StrToIntDef(query.XPathString('(//div[@class="PageNav"])[1]/@data-last'),1); if p>1 then for i:=2 to p do if GET(rurl+'page-'+IntToStr(i)) then begin From 88dc8aefa00e3ed146fdf3c8f40225c98185c37e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 18:58:19 +0800 Subject: [PATCH 0837/2794] Bump version 0.9.30.0 --- changelog.txt | 11 +++++++++++ mangadownloader/md.lpi | 5 ++--- update | 6 +++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index c19c27dac..0374a8902 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,17 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.30.0 (17-01-2016) +[*] E-Hentai/ExHentai: fix incorrect page links/page number +[*] Batoto: various fix +[*] Fix filter "Search only new manga" +[*] Fix various issue on "Update manga list" +[+] Added MangaKoi[EN] +[+] Added YoManga[EN-SC] +[+] Added RawYoManga[RAW] +[+] Added GameofScanlation[EN-SC] +[*] Various changes and bug fixes + 0.9.29.1 (11-01-2016) [!*] Fix empty user-agent if it's not defined in advanced.ini (causing connection issue) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9476580e8..c6c6f2ae6 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,10 +18,9 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="29"/> - <BuildNr Value="1"/> + <RevisionNr Value="30"/> <Attributes pvaPrivateBuild="True"/> - <StringTable Comments="Unofficial Build" FileDescription="Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> + <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> <BuildModes Count="5"> <Item1 Name="Win32" Default="True"/> diff --git a/update b/update index 3cb0c8854..209d347c8 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.29.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.29.1/fmd_0.9.29.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.29.1/fmd_0.9.29.1_Win64.7z +VERSION=0.9.30.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.30.0/fmd_0.9.30.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.30.0/fmd_0.9.30.0_Win64.7z From 7212a0252f91ee7a0dcdce28579343973d7420da Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 23:19:19 +0800 Subject: [PATCH 0838/2794] frmmain, vtdownload fix before cellpaint --- mangadownloader/forms/frmMain.pas | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bc8f27e7d..2b399c237 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3863,17 +3863,13 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin - if (isExiting) or (dataProcess.RecordCount = 0) then - Exit; + if Node^.Index>=dataProcess.RecordCount then Exit; if miHighlightNewManga.Checked then - begin - if Assigned(Node) then - if StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - OptionNewMangaTime) then - begin - TargetCanvas.Brush.Color := CL_HLBlueMarks; - TargetCanvas.FillRect(CellRect); - end; - end; + if StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - OptionNewMangaTime) then + begin + TargetCanvas.Brush.Color := CL_HLBlueMarks; + TargetCanvas.FillRect(CellRect); + end; end; procedure TMainForm.vtMangaListGetCursor(Sender: TBaseVirtualTree; From 0bece86590157268e1bba7f727b65bceb0bbe465 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jan 2016 23:42:08 +0800 Subject: [PATCH 0839/2794] frmaccountmanager, column 0(account enable/disable checkbox) is fixed column --- mangadownloader/forms/frmAccountManager.lfm | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index dedc56643..69e47e236 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -14,12 +14,12 @@ object AccountManagerForm: TAccountManagerForm OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow - Visible = False + LCLVersion = '1.7' object pnBtContainer: TPanel - Left = 297 + Left = 295 Height = 304 Top = 6 - Width = 89 + Width = 91 Align = alRight AutoSize = True BevelOuter = bvNone @@ -27,13 +27,13 @@ object AccountManagerForm: TAccountManagerForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 1 ClientHeight = 304 - ClientWidth = 89 + ClientWidth = 91 TabOrder = 1 object btDelete: TBitBtn Left = 6 Height = 26 Top = 64 - Width = 83 + Width = 85 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -82,7 +82,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 26 Top = 32 - Width = 83 + Width = 85 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -131,7 +131,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 26 Top = 0 - Width = 83 + Width = 85 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -180,7 +180,7 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 26 Top = 96 - Width = 83 + Width = 85 Align = alTop AutoSize = True BorderSpacing.Left = 6 @@ -230,13 +230,13 @@ object AccountManagerForm: TAccountManagerForm Left = 6 Height = 304 Top = 6 - Width = 291 + Width = 289 Align = alClient Header.AutoSizeIndex = 0 Header.Columns = < item MinWidth = 25 - Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible] + Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coFixed] Position = 0 Width = 25 end @@ -253,6 +253,7 @@ object AccountManagerForm: TAccountManagerForm Text = 'Status' end> Header.DefaultHeight = 17 + Header.Height = 25 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] NodeDataSize = 1 TabOrder = 0 From dc9540b2973faf2d1c22c6a60aeb4e2a38336ce3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 03:55:54 +0800 Subject: [PATCH 0840/2794] frmmain, fix loadoptions, wrong identifier inside "with" block --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2b399c237..ef92e73a2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4297,7 +4297,7 @@ procedure TMainForm.LoadOptions; optionMangaSiteSelectionNodes[i]^.CheckState := csUncheckedNormal; l := TStringList.Create; try - s := options.ReadString('general', 'MangaListSelect', + s := ReadString('general', 'MangaListSelect', mangalistIni.ReadString('general', 'DefaultSelect', DEFAULT_LIST)); if Pos(SEPERATOR, s) > 0 then GetParams(l, s) //for old config From 21d6146f5895ebec4822790a2d41dbfb634c033b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 04:01:43 +0800 Subject: [PATCH 0841/2794] rename utranslation unit to simpletranslator --- ...{utranslation.pas => SimpleTranslator.pas} | 4 ++-- baseunits/uUpdateDBThread.pas | 4 ++-- baseunits/uUpdateThread.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 24 +++++++++---------- 4 files changed, 18 insertions(+), 18 deletions(-) rename baseunits/{utranslation.pas => SimpleTranslator.pas} (99%) diff --git a/baseunits/utranslation.pas b/baseunits/SimpleTranslator.pas similarity index 99% rename from baseunits/utranslation.pas rename to baseunits/SimpleTranslator.pas index 07cd4b9cc..1518341e2 100644 --- a/baseunits/utranslation.pas +++ b/baseunits/SimpleTranslator.pas @@ -1,4 +1,4 @@ -{ Simple Translation Collector +{ Simple Translator Copyright (C) 2015 Nur Cholif @@ -18,7 +18,7 @@ MA 02111-1307, USA. } -unit uTranslation; +unit SimpleTranslator; {$mode objfpc}{$H+} diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 1ec11a18b..6cef62fca 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, uBaseUnit, uTranslation, uMisc, + Classes, SysUtils, uBaseUnit, uMisc, SimpleTranslator, LazFileUtils; type @@ -134,7 +134,7 @@ procedure TUpdateDBThread.Execute; try Synchronize(MainThreadShowGetting); RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', - GetMangaDatabaseURL(websiteName), '--lang', uTranslation.LastSelected]); + GetMangaDatabaseURL(websiteName), '--lang', SimpleTranslator.LastSelected]); if FileExistsUTF8(fmdDirectory + DATA_FOLDER + websiteName + '.7z') or FileExistsUTF8(fmdDirectory + DATA_FOLDER + websiteName + '.zip') then Synchronize(MainThreadRefreshList) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 2870bd1a3..76d7996ba 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, - uBaseUnit, uFMDThread, uTranslation, uMisc, WebsiteModules, DBDataProcess; + uBaseUnit, uFMDThread, uMisc, WebsiteModules, DBDataProcess, SimpleTranslator; type TUpdateListManagerThread = class; @@ -575,7 +575,7 @@ procedure TUpdateListManagerThread.Execute; FStatus := RS_GettingListFor + ' ' + website + ' ...'; Synchronize(MainThreadShowGetting); RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', - GetMangaDatabaseURL(website), '--lang', uTranslation.LastSelected]); + GetMangaDatabaseURL(website), '--lang', SimpleTranslator.LastSelected]); Synchronize(RefreshList); end; end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ef92e73a2..47a11c79e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -21,9 +21,9 @@ interface simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, - uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, uTranslation, - frmDropTarget, frmAccountManager, CheckUpdate, accountmanagerdb, - DBDataProcess, mangafoxwatermarkremover, SimpleException, SimpleLogger; + uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, + frmAccountManager, CheckUpdate, accountmanagerdb, DBDataProcess, + mangafoxwatermarkremover, SimpleTranslator, SimpleException, SimpleLogger; type @@ -1360,7 +1360,7 @@ procedure TMainForm.itMonitorTimer(Sender: TObject); Self.CloseNow; RunExternalProcess(fmdDirectory + 'old_updater.exe', ['-x', '-r', '3', '-a', FUpdateURL, '-l', Application.ExeName, - '--lang', uTranslation.LastSelected], True, False); + '--lang', SimpleTranslator.LastSelected], True, False); Self.Close; end; end; @@ -4839,14 +4839,14 @@ procedure TMainForm.CollectLanguagesFromFiles; i: Integer; begin cbLanguages.Items.Clear; - uTranslation.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; - uTranslation.LangAppName := 'fmd'; - uTranslation.CollectLanguagesFiles; - if uTranslation.AvailableLanguages.Count > 0 then + SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; + SimpleTranslator.LangAppName := 'fmd'; + SimpleTranslator.CollectLanguagesFiles; + if SimpleTranslator.AvailableLanguages.Count > 0 then begin for i := 0 to AvailableLanguages.Count - 1 do - cbLanguages.Items.Add(uTranslation.AvailableLanguages.ValueFromIndex[i]); - cbLanguages.ItemIndex := uTranslation.AvailableLanguages.IndexOfName( + cbLanguages.Items.Add(SimpleTranslator.AvailableLanguages.ValueFromIndex[i]); + cbLanguages.ItemIndex := SimpleTranslator.AvailableLanguages.IndexOfName( options.ReadString('languages', 'Selected', 'en')); end; end; @@ -4860,14 +4860,14 @@ procedure TMainForm.ApplyLanguage; idxDropTargetMode: Integer; begin if AvailableLanguages.Count = 0 then Exit; - if uTranslation.LastSelected <> AvailableLanguages.Names[cbLanguages.ItemIndex] then + if SimpleTranslator.LastSelected <> AvailableLanguages.Names[cbLanguages.ItemIndex] then begin idxLanguages := cbLanguages.ItemIndex; idxFilterStatus := cbFilterStatus.ItemIndex; idxOptionLetFMDDo := cbOptionLetFMDDo.ItemIndex; idxOptionProxyType := cbOptionProxyType.ItemIndex; idxDropTargetMode := rgDropTargetMode.ItemIndex; - if uTranslation.SetLangByIndex(cbLanguages.ItemIndex) then + if SimpleTranslator.SetLangByIndex(cbLanguages.ItemIndex) then begin lbOptionExternalParamsHint.Hint := Format(RS_LblOptionExternalParamsHint, [EXPARAM_PATH, EXPARAM_CHAPTER, EXPARAM_PATH, EXPARAM_CHAPTER]); From 2f41b05050dd9c38367318b6489674ee0e9cd88d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 06:54:06 +0800 Subject: [PATCH 0842/2794] remove seemh --- baseunits/ModuleList.inc | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 3cbdf2e10..0402df2d2 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -20,7 +20,6 @@ uses RawSenManga, KissManga, UnionMangas, - Seemh, MangaStreamTo, MangaKoi, GameofScanlation; From 31b46a653f0a1f939d601050655bf473fa3f85a6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 06:54:28 +0800 Subject: [PATCH 0843/2794] remove s2scan from websitewithoutinformation --- baseunits/uBaseUnit.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e5bedcf17..d5f5e6435 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1328,7 +1328,6 @@ function SitesWithoutInformation(const website: String): Boolean; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, MANGAVADISI_ID, - S2SCAN_ID, EGSCANS_ID, TURKCRAFT_ID, HUGEMANGA_ID, From 2e5f6181af4783ed1f48c5b8b640b15876667377 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 07:44:45 +0800 Subject: [PATCH 0844/2794] frmmain, fix empty selected website after changing language --- mangadownloader/forms/frmMain.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 47a11c79e..4673188d3 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4853,6 +4853,7 @@ procedure TMainForm.CollectLanguagesFromFiles; procedure TMainForm.ApplyLanguage; var + idxSelectManga, idxLanguages, idxFilterStatus, idxOptionLetFMDDo, @@ -4862,6 +4863,9 @@ procedure TMainForm.ApplyLanguage; if AvailableLanguages.Count = 0 then Exit; if SimpleTranslator.LastSelected <> AvailableLanguages.Names[cbLanguages.ItemIndex] then begin + // TCombobox.Items will be cleared upon changing languge + // save TComboBox.ItemIndex and restore it + idxSelectManga:=cbSelectManga.ItemIndex; idxLanguages := cbLanguages.ItemIndex; idxFilterStatus := cbFilterStatus.ItemIndex; idxOptionLetFMDDo := cbOptionLetFMDDo.ItemIndex; @@ -4876,6 +4880,7 @@ procedure TMainForm.ApplyLanguage; cbOptionLetFMDDo.Items.Text := RS_OptionFMDDoItems; rgDropTargetMode.Items.Text := RS_DropTargetModeItems; + cbSelectManga.ItemIndex:=idxSelectManga; cbLanguages.ItemIndex := idxLanguages; cbFilterStatus.ItemIndex := idxFilterStatus; cbOptionLetFMDDo.ItemIndex := idxOptionLetFMDDo; From adf6b7328f0a3f10b212c5e71c90eee3d5255587 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 08:00:42 +0800 Subject: [PATCH 0845/2794] add comments --- mangadownloader/forms/frmMain.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 4673188d3..85003e23f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4863,8 +4863,9 @@ procedure TMainForm.ApplyLanguage; if AvailableLanguages.Count = 0 then Exit; if SimpleTranslator.LastSelected <> AvailableLanguages.Names[cbLanguages.ItemIndex] then begin - // TCombobox.Items will be cleared upon changing languge - // save TComboBox.ItemIndex and restore it + // TCombobox.Items will be cleared upon changing language, + // and ItemIndex will fall to -1 + // save TComboBox.ItemIndex idxSelectManga:=cbSelectManga.ItemIndex; idxLanguages := cbLanguages.ItemIndex; idxFilterStatus := cbFilterStatus.ItemIndex; @@ -4880,6 +4881,7 @@ procedure TMainForm.ApplyLanguage; cbOptionLetFMDDo.Items.Text := RS_OptionFMDDoItems; rgDropTargetMode.Items.Text := RS_DropTargetModeItems; + // restore ItemIndex cbSelectManga.ItemIndex:=idxSelectManga; cbLanguages.ItemIndex := idxLanguages; cbFilterStatus.ItemIndex := idxFilterStatus; From a3071fa21a41464dd39b2ee5fea2652b7c714c3c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 19:52:10 +0800 Subject: [PATCH 0846/2794] frmmain, fix incorrect color for progress bar finish --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 85003e23f..c6e86f977 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3593,7 +3593,7 @@ procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; end; STATUS_FINISH : begin Pen.Color := CL_BarGreenLine; - Brush.Color := CL_BarGreenLine; + Brush.Color := CL_BarGreen; end; else begin Pen.Color := CL_BarBrownGoldLine; From f6d325a5e56acc938c15c39f0093c2b0c2bd87dc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 20:12:36 +0800 Subject: [PATCH 0847/2794] batoto, change update list per page to default --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 7a7715941..22a1cff07 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -17,7 +17,7 @@ implementation dirurls: array [0..1] of String = ( '/comic/_/sp/', '/comic/_/comics/'); - perpage = 1000; + perpage = 50; dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; var From 036d8e81290c6ce6540fcfd57157578214554feb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 20:32:43 +0800 Subject: [PATCH 0848/2794] simpletranslator, refresh datamodules --- baseunits/SimpleTranslator.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/SimpleTranslator.pas b/baseunits/SimpleTranslator.pas index 1518341e2..53f24bb14 100644 --- a/baseunits/SimpleTranslator.pas +++ b/baseunits/SimpleTranslator.pas @@ -944,6 +944,8 @@ function SetLang(const lang: string; appname: string): Boolean; LRSTranslator := ltrans; for i := 0 to Screen.CustomFormCount-1 do ltrans.UpdateTranslation(Screen.CustomForms[i]); + for i := 0 to Screen.DataModuleCount-1 do + ltrans.UpdateTranslation(Screen.DataModules[i]); LastSelected := lang; Result := True; end; From e316e2054b71cf7d0b51fe6c2aac26fd1b515a82 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 23:53:29 +0800 Subject: [PATCH 0849/2794] frmain, vtdownload, added keyboard shortcut to move items --- mangadownloader/forms/frmMain.pas | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c6e86f977..d7a61eb21 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3701,14 +3701,17 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; procedure TMainForm.vtDownloadKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); -begin - if (Key in [VK_UP, VK_DOWN]) and (ssCtrl in Shift) then - begin - if Key = VK_DOWN then - vtDownloadMoveItems(vtDownload.GetFirstSelected^.Index, dmBelow) - else - if vtDownload.GetFirstSelected^.Index > 0 then - vtDownloadMoveItems(vtDownload.GetFirstSelected^.Index - 1, dmAbove); +var + p: Cardinal; +begin + if not (ssCtrl in Shift) then Exit; + if vtDownload.SelectedCount=0 then Exit; + p:=vtDownload.GetFirstSelected()^.Index; + case Key of + VK_UP : if p>0 then vtDownloadMoveItems(p-1,dmAbove); + VK_DOWN : vtDownloadMoveItems(p,dmBelow); + VK_HOME : vtDownloadMoveItems(0,dmAbove); + VK_END : vtDownloadMoveItems(vtDownload.RootNodeCount-1,dmBelow); end; end; From 606dfc8da6b5d34c65876e1c2afc7545f4b40f97 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jan 2016 23:57:43 +0800 Subject: [PATCH 0850/2794] frmmain, cleanup and fix vtdownloadmoveitems --- mangadownloader/forms/frmMain.pas | 82 ++++++++++++++----------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d7a61eb21..14cbc34b0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3439,71 +3439,65 @@ procedure TMainForm.vtDownloadDragAllowed(Sender : TBaseVirtualTree; procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); var - i, nIndex: Integer; + i, nIndex: Cardinal; cNode: PVirtualNode; ConTemp: TFPList; begin + if vtDownload.SelectedCount=0 then Exit; vtDownload.BeginUpdate; ConTemp := TFPList.Create; try nIndex := NextIndex; - - if vtDownload.SelectedCount > 0 then + cNode := vtDownload.GetFirst; + i := 0; + while i < vtDownload.RootNodeCount do begin - cNode := vtDownload.GetFirst; - i := 0; - while i < vtDownload.RootNodeCount do - //DLManager.Count do + if vtDownload.Selected[cNode] then begin - if vtDownload.Selected[cNode] then - begin - vtDownload.Selected[cNode] := False; - ConTemp.Add(DLManager.Items[i]); - DLManager.containers.Delete(i); - if (i < nIndex) and (nIndex > 0) then - Dec(nIndex); - end - else - Inc(i); - cNode := vtDownload.GetNext(cNode); - end; - vtDownload.FocusedNode := nil; + vtDownload.Selected[cNode] := False; + ConTemp.Add(DLManager.Items[i]); + DLManager.containers.Delete(i); + if (i < nIndex) and (nIndex > 0) then + Dec(nIndex); + end + else + Inc(i); + cNode := vtDownload.GetNext(cNode); + end; + vtDownload.FocusedNode := nil; - for i := 0 to ConTemp.Count - 1 do + for i := 0 to ConTemp.Count - 1 do + begin + if (i = 0) and (Mode in [dmBelow, dmNowhere]) then + Inc(nIndex) + else + if (i > 0) then begin - if (i = 0) and (Mode in [dmBelow, dmNowhere]) then - Inc(nIndex) - else - if (i > 0) then - begin - if (nIndex < DLManager.Count) then - Inc(nIndex); - end; - if nIndex > DLManager.Count then - Dec(nIndex); - DLManager.containers.Insert(nIndex, ConTemp[i]); + if (nIndex < DLManager.Count) then + Inc(nIndex); end; + if nIndex > DLManager.Count then + Dec(nIndex); + DLManager.containers.Insert(nIndex, ConTemp[i]); + end; - cNode := vtDownload.GetFirst; - while Assigned(cNode) and (cNode^.Index < nIndex) do - cNode := vtDownload.GetNext(cNode); + cNode := vtDownload.GetFirst; + while Assigned(cNode) and (cNode^.Index < nIndex) do + cNode := vtDownload.GetNext(cNode); - for i := 0 to ConTemp.Count - 1 do + for i := 0 to ConTemp.Count - 1 do + begin + if Assigned(cNode) then begin - if Assigned(cNode) then - begin - vtDownload.Selected[cNode] := True; - vtDownload.FocusedNode := cNode; - cNode := vtDownload.GetPrevious(cNode); - end; + vtDownload.Selected[cNode] := True; + vtDownload.FocusedNode := cNode; + cNode := vtDownload.GetPrevious(cNode); end; end; finally ConTemp.Free; cNode := nil; vtDownload.EndUpdate; - //vtDownload.Repaint; - //Some node isn't repaint correctly if not explicitly triggering repaint? end; vtDownloadFilters; end; From 94ab61ecc27c78380f955be88371fc9fc998a104 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 00:03:35 +0800 Subject: [PATCH 0851/2794] frmmain, cleanup and fix vtdownloadmoveitems --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 14cbc34b0..6eb0c8486 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3473,10 +3473,10 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); else if (i > 0) then begin - if (nIndex < DLManager.Count) then + if nIndex < vtDownload.RootNodeCount then Inc(nIndex); end; - if nIndex > DLManager.Count then + if nIndex > vtDownload.RootNodeCount then Dec(nIndex); DLManager.containers.Insert(nIndex, ConTemp[i]); end; From 8213f630c35a01c14cd21d8bf3da00460a6c64d2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 00:15:17 +0800 Subject: [PATCH 0852/2794] frmmain, vtdownload, disable horizontal scrolling on hotkey move items --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index be4b85beb..1068b91ee 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -122,6 +122,7 @@ object MainForm: TMainForm OnGetImageIndex = vtDownloadGetImageIndex OnGetHint = vtDownloadGetHint OnHeaderClick = vtDownloadHeaderClick + OnKeyAction = vtDownloadKeyAction OnKeyDown = vtDownloadKeyDown OnKeyUp = vtDownloadKeyUp end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6eb0c8486..beb3a433a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -20,7 +20,7 @@ interface ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, - uBaseUnit, uData, uDownloadsManager, uFavoritesManager, uUpdateThread, + uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, CheckUpdate, accountmanagerdb, DBDataProcess, mangafoxwatermarkremover, SimpleTranslator, SimpleException, SimpleLogger; @@ -487,6 +487,8 @@ TMainForm = class(TForm) Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure vtDownloadHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure vtDownloadKeyAction(Sender: TBaseVirtualTree; var CharCode: Word; + var Shift: TShiftState; var DoDefault: Boolean); procedure vtDownloadKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); procedure vtDownloadKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); @@ -3693,6 +3695,13 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; vtDownload.Repaint; end; +procedure TMainForm.vtDownloadKeyAction(Sender: TBaseVirtualTree; + var CharCode: Word; var Shift: TShiftState; var DoDefault: Boolean); +begin + if (ssCtrl in Shift) and (CharCode in [VK_HOME,VK_END]) then + DoDefault:=False; +end; + procedure TMainForm.vtDownloadKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); var From 4168563e783e64eff4f9e3693d057ebb617021c8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 01:56:45 +0800 Subject: [PATCH 0853/2794] frmmain, fix vtdownloadmoveitems --- mangadownloader/forms/frmMain.pas | 70 +++++++++++++------------------ 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index beb3a433a..34e4f012e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3446,61 +3446,51 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); ConTemp: TFPList; begin if vtDownload.SelectedCount=0 then Exit; + nIndex:=NextIndex; vtDownload.BeginUpdate; - ConTemp := TFPList.Create; + ConTemp:=TFPList.Create; + DLManager.CS_DownloadManager_Task.Acquire; try - nIndex := NextIndex; - cNode := vtDownload.GetFirst; - i := 0; - while i < vtDownload.RootNodeCount do + i:=0; + cNode:=vtDownload.GetFirstSelected(); + while cNode<>nil do begin - if vtDownload.Selected[cNode] then - begin - vtDownload.Selected[cNode] := False; - ConTemp.Add(DLManager.Items[i]); - DLManager.containers.Delete(i); - if (i < nIndex) and (nIndex > 0) then - Dec(nIndex); - end - else - Inc(i); - cNode := vtDownload.GetNext(cNode); + vtDownload.Selected[cNode]:=False; + ConTemp.Add(DLManager.Items[cNode^.Index-i]); + DLManager.Containers.Delete(cNode^.Index-i); + if (nIndex>0) and (cNode^.Index<nIndex) then + Dec(nIndex); + Inc(i); + cNode:=vtDownload.GetNextSelected(cNode); end; - vtDownload.FocusedNode := nil; - for i := 0 to ConTemp.Count - 1 do + for i:=0 to ConTemp.Count-1 do begin - if (i = 0) and (Mode in [dmBelow, dmNowhere]) then + if (i=0) and (Mode in [dmBelow,dmNowhere]) then Inc(nIndex) - else - if (i > 0) then - begin - if nIndex < vtDownload.RootNodeCount then - Inc(nIndex); - end; - if nIndex > vtDownload.RootNodeCount then - Dec(nIndex); + else if (i>0) and (nIndex<DLManager.Count) then + Inc(nIndex); + if nIndex>DLManager.Count then + nIndex:=DLManager.Count; DLManager.containers.Insert(nIndex, ConTemp[i]); end; - cNode := vtDownload.GetFirst; - while Assigned(cNode) and (cNode^.Index < nIndex) do - cNode := vtDownload.GetNext(cNode); + cNode:=vtDownload.GetFirst; + while cNode^.Index<nIndex do + cNode:=vtDownload.GetNext(cNode); - for i := 0 to ConTemp.Count - 1 do + for i:=0 to ConTemp.Count-1 do begin - if Assigned(cNode) then - begin - vtDownload.Selected[cNode] := True; - vtDownload.FocusedNode := cNode; - cNode := vtDownload.GetPrevious(cNode); - end; + vtDownload.Selected[cNode]:=True; + if i<ConTemp.Count-1 then + cNode:=vtDownload.GetPrevious(cNode); end; + vtDownload.FocusedNode:=cNode; finally - ConTemp.Free; - cNode := nil; - vtDownload.EndUpdate; + DLManager.CS_DownloadManager_Task.Release; end; + ConTemp.Free; + vtDownload.EndUpdate; vtDownloadFilters; end; From 45ebfd8df0dd999eaafdea04823878898a90d873 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 01:59:34 +0800 Subject: [PATCH 0854/2794] frmmain, vtdownloadmoveitems, scroll to new position --- mangadownloader/forms/frmMain.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 34e4f012e..c7986548e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3479,6 +3479,9 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); while cNode^.Index<nIndex do cNode:=vtDownload.GetNext(cNode); + if Mode=dmBelow then + vtDownload.ScrollIntoView(cNode,False,False); + for i:=0 to ConTemp.Count-1 do begin vtDownload.Selected[cNode]:=True; @@ -3486,6 +3489,8 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); cNode:=vtDownload.GetPrevious(cNode); end; vtDownload.FocusedNode:=cNode; + if Mode=dmAbove then + vtDownload.ScrollIntoView(cNode,False,False); finally DLManager.CS_DownloadManager_Task.Release; end; From bcb8bb364ebb6dc20ee2f803c473d2dcec405442 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 02:11:58 +0800 Subject: [PATCH 0855/2794] disable all list auto scroll on select --- mangadownloader/forms/frmAccountManager.lfm | 1 + mangadownloader/forms/frmMain.lfm | 7 +++++-- mangadownloader/languages/fmd.en.po | 4 ++++ mangadownloader/languages/fmd.id_ID.po | 4 ++++ mangadownloader/languages/fmd.po | 4 ++++ 5 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 69e47e236..20e6e3f40 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -257,6 +257,7 @@ object AccountManagerForm: TAccountManagerForm Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] NodeDataSize = 1 TabOrder = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect] diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 1068b91ee..7da5e3317 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -108,7 +108,7 @@ object MainForm: TMainForm ShowHint = True TabOrder = 0 TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] @@ -493,6 +493,7 @@ object MainForm: TMainForm PopupMenu = pmChapterList TabOrder = 0 TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] @@ -1715,6 +1716,7 @@ object MainForm: TMainForm ShowHint = True TabOrder = 0 TextMargin = 2 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = vtFavoritesBeforeCellPaint @@ -2777,6 +2779,7 @@ object MainForm: TMainForm ParentFont = False TabOrder = 0 TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] OnChange = vtOptionMangaSiteSelectionChange @@ -3269,7 +3272,7 @@ object MainForm: TMainForm ShowHint = True TabOrder = 0 TextMargin = 3 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes] + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] OnBeforeCellPaint = vtMangaListBeforeCellPaint diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 03e6f65f0..94aff1c8b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -293,6 +293,10 @@ msgstr "Edit" msgid "Refresh" msgstr "Refresh" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "AccountManagerForm" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 2d8dd8cae..14d3f5beb 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -292,6 +292,10 @@ msgstr "Ubah" msgid "Refresh" msgstr "Segarkan" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "AccountManagerForm" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 2738ea8d3..338773b74 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -264,6 +264,10 @@ msgstr "" msgid "Refresh" msgstr "" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" From 145c5fcd04c283677a735b708994f99070717471 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 02:33:15 +0800 Subject: [PATCH 0856/2794] frmdroptarget, change drop effect to dropeffect_link --- mangadownloader/forms/frmDropTarget.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index ce84bd147..f4f00abea 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -333,14 +333,16 @@ function TFormDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: DWOR pt: TPoint; var dwEffect: DWORD): HResult; stdcall; begin FCanDrop := CanDrop(dataObj); - dwEffect := CursorEffect(dwEffect, grfKeyState); + if FCanDrop then + dwEffect:=DROPEFFECT_LINK; Result := S_OK; end; function TFormDropTarget.DragOver(grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; begin - dwEffect := CursorEffect(dwEffect, grfKeyState); + if FCanDrop then + dwEffect:=DROPEFFECT_LINK; Result := S_OK; end; From 6aff8926c3fbe828cdd33c0d4e23bb7905d451da Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 03:04:14 +0800 Subject: [PATCH 0857/2794] frmdroptarget, explode get urls from clipboard to public --- mangadownloader/forms/frmDropTarget.pas | 317 ++++++++++++------------ 1 file changed, 159 insertions(+), 158 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index f4f00abea..9b057709e 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -42,17 +42,9 @@ TFormDropTarget = class(TForm, IDropTarget) x0, y0: Integer; FCanDrop: Boolean; // IDropTarget - function MakeFormatEtc(const Fmt: TCLIPFORMAT): TFormatEtc; function CursorEffect(const AllowedEffects: Cardinal; const KeyState: Integer): Cardinal; function CanDrop(const DataObj: IDataObject): Boolean; - function GetTextFromObj(const DataObj: IDataObject; - const Fmt: TCLIPFORMAT): String; - function GetWideTextFromObj(const DataObj: IDataObject; - const Fmt: TCLIPFORMAT): String; - function GetURLsFromHTML(const S: String): String; - function ParseDataObj(const DataObj: IDataObject; - const Fmt: TClipboardFormat): String; function DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; {%H-}pt: TPoint; var dwEffect: DWORD): HResult; stdcall; function {%H-}DragOver(grfKeyState: DWORD; {%H-}pt: TPoint; @@ -66,6 +58,8 @@ TFormDropTarget = class(TForm, IDropTarget) { public declarations } end; + function GetDropURLs(const DataObject: IDataObject): string; + var FormDropTarget: TFormDropTarget; FAlphaBlendValue: Integer = 255; @@ -85,6 +79,162 @@ implementation {$R *.lfm} +function MakeFormatEtc(const Fmt: TCLIPFORMAT): TFormatEtc; +begin + Result.cfFormat := Fmt; + Result.ptd := nil; + Result.dwAspect := DVASPECT_CONTENT; + Result.lindex := -1; + Result.tymed := TYMED_HGLOBAL; +end; + +function GetTextFromObj(const DataObj: IDataObject; + const Fmt: TCLIPFORMAT): String; +var + Medium: TStgMedium; + PText: PChar; +begin + if DataObj.GetData(MakeFormatEtc(Fmt), Medium) = S_OK then + begin + Assert(Medium.tymed = MakeFormatEtc(Fmt).tymed); + try + PText := GlobalLock(Medium.hGlobal); + try + Result := PText; + finally + GlobalUnlock(Medium.hGlobal); + end; + finally + ReleaseStgMedium(Medium); + end; + end + else + Result := ''; +end; + +function GetWideTextFromObj(const DataObj: IDataObject; + const Fmt: TCLIPFORMAT): String; +var + Medium: TStgMedium; + PwText: PWideChar; +begin + if DataObj.GetData(MakeFormatEtc(Fmt), Medium) = S_OK then + begin + Assert(Medium.tymed = MakeFormatEtc(Fmt).tymed); + try + PwText := GlobalLock(Medium.hGlobal); + try + Result := PwText; + finally + GlobalUnlock(Medium.hGlobal); + end; + finally + ReleaseStgMedium(Medium); + end; + end + else + Result := ''; +end; + +function GetURLsFromHTML(const S: String): String; +var + Parse, URls: TStringList; + i: Integer; + url: String; +begin + Result := S; + if S = '' then Exit; + Parse:= TStringList.Create; + try + ParseHTML(S, Parse); + if Parse.Count > 0 then + begin + URls := TStringList.Create; + try + for i := 0 to Parse.Count - 1 do + begin + if LowerCase(GetTagName(Parse[i])) = 'a' then + url := GetVal(Parse[i], 'href'); + if Pos('javascript', url) <> 1 then + URls.Add(url); + end; + if URls.Count > 0 then + begin + RemoveDuplicateStrings(URls); + Result := URls.Text; + end; + finally + URls.Free; + end; + end; + finally + Parse.Free; + end; +end; + +function ParseDataObj(const DataObj: IDataObject; + const Fmt: TClipboardFormat): String; +begin + if Fmt = CF_HTML then + Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) + else + if Fmt = CF_UNICODETEXT then + Result := GetWideTextFromObj(DataObj, Fmt) + else + if Fmt = CF_TEXT then + Result := GetTextFromObj(DataObj, Fmt) + else + Result := ''; + Result := Trim(Result); +end; + +function GetDropURLs(const DataObject: IDataObject): string; +var + Enum: IEnumFORMATETC; + FmtEtc: TFORMATETC; + url: String; + + function GetDataObjectFormat(Fmt: TCLIPFORMAT): Boolean; + begin + Result:=False; + Enum.Reset; + while Enum.Next(1,FmtEtc,nil)=S_OK do + if FmtEtc.CfFormat=Fmt then + begin + url:=ParseDataObj(DataObject,Fmt); + if url<>'' then + Result:=True; + Break; + end; + end; + + function GetDataObjectFormats(Fmts: array of TCLIPFORMAT): Boolean; + var + i: Integer; + begin + Result:=False; + if Length(Fmts)=0 then Exit; + for i:=Low(Fmts) to High(Fmts) do + if GetDataObjectFormat(Fmts[i]) then + begin + Result:=True; + Break; + end; + end; + +begin + Result:=''; + if DataObject=nil then Exit; + url:=Result; + OleCheck(DataObject.EnumFormatEtc(DATADIR_GET,Enum)); + if GetDataObjectFormats([ + CF_HTML, + CF_UNICODETEXT, + CF_TEXT + ]) then + Result:=url; +end; + { TFormDropTarget } procedure TFormDropTarget.FormCreate(Sender: TObject); @@ -197,15 +347,6 @@ procedure TFormDropTarget.pmDropTargetPopup(Sender: TObject); miAddToFavorites.Checked := not miDownloadAll.Checked; end; -function TFormDropTarget.MakeFormatEtc(const Fmt: TCLIPFORMAT): TFormatEtc; -begin - Result.cfFormat := Fmt; - Result.ptd := nil; - Result.dwAspect := DVASPECT_CONTENT; - Result.lindex := -1; - Result.tymed := TYMED_HGLOBAL; -end; - function TFormDropTarget.CursorEffect(const AllowedEffects: Cardinal; const KeyState: Integer): Cardinal; begin @@ -229,106 +370,6 @@ function TFormDropTarget.CanDrop(const DataObj: IDataObject): Boolean; Result := DataObj.QueryGetData(MakeFormatEtc(CF_TEXT)) = S_OK; end; -function TFormDropTarget.GetTextFromObj(const DataObj: IDataObject; - const Fmt: TCLIPFORMAT): String; -var - Medium: TStgMedium; - PText: PChar; -begin - if DataObj.GetData(MakeFormatEtc(Fmt), Medium) = S_OK then - begin - Assert(Medium.tymed = MakeFormatEtc(Fmt).tymed); - try - PText := GlobalLock(Medium.hGlobal); - try - Result := PText; - finally - GlobalUnlock(Medium.hGlobal); - end; - finally - ReleaseStgMedium(Medium); - end; - end - else - Result := ''; -end; - -function TFormDropTarget.GetWideTextFromObj(const DataObj: IDataObject; - const Fmt: TCLIPFORMAT): String; -var - Medium: TStgMedium; - PwText: PWideChar; -begin - if DataObj.GetData(MakeFormatEtc(Fmt), Medium) = S_OK then - begin - Assert(Medium.tymed = MakeFormatEtc(Fmt).tymed); - try - PwText := GlobalLock(Medium.hGlobal); - try - Result := PwText; - finally - GlobalUnlock(Medium.hGlobal); - end; - finally - ReleaseStgMedium(Medium); - end; - end - else - Result := ''; -end; - -function TFormDropTarget.GetURLsFromHTML(const S: String): String; -var - Parse, URls: TStringList; - i: Integer; - url: String; -begin - Result := S; - if S = '' then Exit; - Parse:= TStringList.Create; - try - ParseHTML(S, Parse); - if Parse.Count > 0 then - begin - URls := TStringList.Create; - try - for i := 0 to Parse.Count - 1 do - begin - if LowerCase(GetTagName(Parse[i])) = 'a' then - url := GetVal(Parse[i], 'href'); - if Pos('javascript', url) <> 1 then - URls.Add(url); - end; - if URls.Count > 0 then - begin - RemoveDuplicateStrings(URls); - Result := URls.Text; - end; - finally - URls.Free; - end; - end; - finally - Parse.Free; - end; -end; - -function TFormDropTarget.ParseDataObj(const DataObj: IDataObject; - const Fmt: TClipboardFormat): String; -begin - if Fmt = CF_HTML then - Result := GetURLsFromHTML(GetTextFromObj(DataObj, Fmt)) - else - if Fmt = CF_UNICODETEXT then - Result := GetWideTextFromObj(DataObj, Fmt) - else - if Fmt = CF_TEXT then - Result := GetTextFromObj(DataObj, Fmt) - else - Result := ''; - Result := Trim(Result); -end; - function TFormDropTarget.DragEnter(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; begin @@ -353,49 +394,9 @@ function TFormDropTarget.DragLeave: HResult; stdcall; function TFormDropTarget.Drop(const dataObj: IDataObject; grfKeyState: DWORD; pt: TPoint; var dwEffect: DWORD): HResult; stdcall; -var - Enum: IEnumFORMATETC; - FmtEtc: TFORMATETC; - url: String; - - function GetDataObjectFormat(Fmt: TCLIPFORMAT): Boolean; - begin - Result := False; - Enum.Reset; - while Enum.Next(1, FmtEtc, nil) = S_OK do - if FmtEtc.CfFormat = Fmt then - begin - url := ParseDataObj(dataObj, Fmt); - if url <> '' then - Result := True; - Break; - end; - end; - - function GetDataObjectFormats(Fmts: array of TCLIPFORMAT): Boolean; - var - i: Integer; - begin - Result := False; - if Length(Fmts) = 0 then Exit; - for i := Low(Fmts) to High(Fmts) do - if GetDataObjectFormat(Fmts[i]) then - begin - Result := True; - Break; - end; - end; - begin - url := ''; - OleCheck(DataObj.EnumFormatEtc(DATADIR_GET, Enum)); if Assigned(OnDropChekout) then - if GetDataObjectFormats([ - CF_HTML, - CF_UNICODETEXT, - CF_TEXT - ]) then - OnDropChekout(url); + OnDropChekout(GetDropURLs(dataObj)); Result := S_OK; end; From 4e98b65674cd848201114a5b51c0699258a2b98c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 03:17:04 +0800 Subject: [PATCH 0858/2794] frmmain, overload addsilentthread --- mangadownloader/forms/frmMain.pas | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c7986548e..842670a48 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -594,7 +594,8 @@ TMainForm = class(TForm) procedure AddChapterNameToList; // Create silent thread - procedure AddSilentThread(URL: string); + procedure AddSilentThread(URL: string; MetaDataType: TMetaDataType); overload; + procedure AddSilentThread(URL: string); overload; // Add text to TRichMemo procedure AddTextToInfo(title, infoText: String); @@ -4045,12 +4046,11 @@ procedure TMainForm.AddChapterNameToList; UpdateVtChapter; end; -procedure TMainForm.AddSilentThread(URL: string); +procedure TMainForm.AddSilentThread(URL: string; MetaDataType: TMetaDataType); var i, j, m: Integer; host, link, webs: String; URls: TStringList; - mt: TMetaDataType; begin if Trim(URL) = '' then Exit; URLs := TStringList.Create; @@ -4082,12 +4082,8 @@ procedure TMainForm.AddSilentThread(URL: string); end; if webs <> '' then begin - if rgDropTargetMode.ItemIndex = 0 then - mt := MD_DownloadAll - else - mt := MD_AddToFavorites; - if not ((mt = MD_AddToFavorites) and SitesWithoutFavorites(webs)) then - SilentThreadManager.Add(mt, webs, '', link); + if not ((MetaDataType = MD_AddToFavorites) and SitesWithoutFavorites(webs)) then + SilentThreadManager.Add(MetaDataType, webs, '', link); end; end; end; @@ -4101,6 +4097,18 @@ procedure TMainForm.AddSilentThread(URL: string); end; end; +procedure TMainForm.AddSilentThread(URL: string); +var + mt: TMetaDataType; +begin + if Trim(URL)='' then Exit; + if rgDropTargetMode.ItemIndex=0 then + mt:=MD_DownloadAll + else + mt:=MD_AddToFavorites; + AddSilentThread(URL,mt); +end; + procedure TMainForm.AddTextToInfo(title, infoText: String); var fp: TFontParams; From 3d8104896319e3e1a2e1f5187da7cf172a2e3036 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 03:18:50 +0800 Subject: [PATCH 0859/2794] frmmain, download list accept drop urls --- mangadownloader/forms/frmMain.pas | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 842670a48..e70805a8e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3505,20 +3505,22 @@ procedure TMainForm.vtDownloadDragDrop(Sender : TBaseVirtualTree; Shift : TShiftState; const Pt : TPoint; var Effect : LongWord; Mode : TDropMode); begin - if (Source <> vtDownload) or (Source <> Sender) or - (DLManager.Count < 2) then - Exit; - if Mode = dmNowhere then - vtDownloadMoveItems(vtDownload.GetLast^.Index, Mode) + if (Source=vtDownload) and (vtDownload.RootNodeCount>1) then + begin + if Mode = dmNowhere then + vtDownloadMoveItems(vtDownload.GetLast^.Index, Mode) + else + vtDownloadMoveItems(vtDownload.DropTargetNode^.Index, Mode); + end else - vtDownloadMoveItems(vtDownload.DropTargetNode^.Index, Mode); + AddSilentThread(frmDropTarget.GetDropURLs(DataObject), MD_DownloadAll); end; procedure TMainForm.vtDownloadDragOver(Sender : TBaseVirtualTree; Source : TObject; Shift : TShiftState; State : TDragState; const Pt : TPoint; Mode : TDropMode; var Effect : LongWord; var Accept : Boolean); begin - Accept := (Sender = Source); + Accept:=True; end; procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; From 8841d44ca834934ea50614da89e21e76081f0f1c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 03:21:34 +0800 Subject: [PATCH 0860/2794] frmmain, favorite list accept drop urls --- mangadownloader/forms/frmMain.lfm | 2 ++ mangadownloader/forms/frmMain.pas | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 7da5e3317..c06ed6cdb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1721,6 +1721,8 @@ object MainForm: TMainForm TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = vtFavoritesBeforeCellPaint OnColumnDblClick = vtFavoritesColumnDblClick + OnDragOver = vtFavoritesDragOver + OnDragDrop = vtFavoritesDragDrop OnGetText = vtFavoritesGetText OnGetImageIndex = vtFavoritesGetImageIndex OnGetHint = vtFavoritesGetHint diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e70805a8e..df2fa3016 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -497,6 +497,12 @@ TMainForm = class(TForm) CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); procedure vtFavoritesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); + procedure vtFavoritesDragDrop(Sender: TBaseVirtualTree; Source: TObject; + DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; + const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); + procedure vtFavoritesDragOver(Sender: TBaseVirtualTree; Source: TObject; + Shift: TShiftState; State: TDragState; const Pt: TPoint; Mode: TDropMode; + var Effect: LongWord; var Accept: Boolean); procedure vtFavoritesGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -3759,6 +3765,21 @@ procedure TMainForm.vtFavoritesColumnDblClick(Sender: TBaseVirtualTree; miFavoritesOpenFolderClick(Sender); end; +procedure TMainForm.vtFavoritesDragDrop(Sender: TBaseVirtualTree; + Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); +begin + AddSilentThread(frmDropTarget.GetDropURLs(DataObject), MD_AddToFavorites); +end; + +procedure TMainForm.vtFavoritesDragOver(Sender: TBaseVirtualTree; + Source: TObject; Shift: TShiftState; State: TDragState; const Pt: TPoint; + Mode: TDropMode; var Effect: LongWord; var Accept: Boolean); +begin + Accept:=True; + Effect:=DROPEFFECT_LINK; +end; + procedure TMainForm.vtFavoritesGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); From 1a57a5d835dfe1132f3738833d92a5c091aa5fef Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 04:22:07 +0800 Subject: [PATCH 0861/2794] updater, use httpsendthread and some changes --- updater/languages/updater.en.po | 8 +-- updater/languages/updater.id_ID.po | 14 ++--- updater/languages/updater.po | 4 ++ updater/uMain.lfm | 1 - updater/uMain.pas | 82 +++++------------------------- 5 files changed, 27 insertions(+), 82 deletions(-) diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index 5d7b80386..8d4d5ba17 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -9,7 +9,11 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en\n" -"X-Generator: Poedit 1.7.6\n" +"X-Generator: Poedit 1.8.2\n" + +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "Free Manga Downloader - Updater" #: tfrmmain.lbfilesize.caption msgid "File size" @@ -52,7 +56,6 @@ msgid "File not found!" msgstr "File not found!" #: umain.rs_filenotfound_mfdatalink -#, fuzzy #| msgid "" #| "File not found!\n" #| "This site probably have been added to unofficial build.\n" @@ -125,4 +128,3 @@ msgstr "Unpacking file [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Waiting main app to close..." - diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 5f9253ea8..3b4f6c71e 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -11,6 +11,10 @@ msgstr "" "Language: id_ID\n" "X-Generator: Poedit 1.8.2\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "Free Manga Downloader - Pembaruan" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Ukuran" @@ -52,15 +56,6 @@ msgid "File not found!" msgstr "Berkas tidak ditemukan!" #: umain.rs_filenotfound_mfdatalink -#, fuzzy -#| msgid "" -#| "File not found!\n" -#| "This site probably have been added to unofficial build.\n" -#| "\n" -#| "Remedy:\n" -#| "Build you manga list from scratch or download manually from this link:\n" -#| "%s\n" -#| "Link copied to clipboard!\n" msgid "" "File not found!\n" "This site probably have been added to unofficial build.\n" @@ -124,4 +119,3 @@ msgstr "Membuka berkas [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Menunggu aplikasi utama untuk berhenti..." - diff --git a/updater/languages/updater.po b/updater/languages/updater.po index a6e4f13e2..8f14f02c9 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -1,6 +1,10 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "" diff --git a/updater/uMain.lfm b/updater/uMain.lfm index 2f5f24a4f..92e5ab6e8 100644 --- a/updater/uMain.lfm +++ b/updater/uMain.lfm @@ -14,7 +14,6 @@ object frmMain: TfrmMain OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '1.7' - Visible = False object pbDownload: TProgressBar Left = 8 Height = 20 diff --git a/updater/uMain.pas b/updater/uMain.pas index e44ab183d..4d0528bb4 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -9,10 +9,10 @@ interface cthreads, cmem, {$endif} - Classes, SysUtils, zipper, FileUtil,LazFileUtils, LazUTF8, LazUTF8Classes, + Classes, SysUtils, zipper, FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, - RegExpr, IniFiles, SimpleException, uMisc, uTranslation, - httpsend, blcksock, ssl_openssl, ssl_openssl_lib, uFMDThread; + RegExpr, IniFiles, SimpleException, uMisc, httpsend, blcksock, ssl_openssl, + ssl_openssl_lib, uFMDThread, SimpleTranslator, httpsendthread; type @@ -43,7 +43,7 @@ TfrmMain = class(TForm) TDownloadThread = class(TFMDThread) private FTotalSize, FCurrentSize :integer; - FHTTP :THTTPSend; + FHTTP :THTTPSendThread; FStatus :string; FProgress :string; FErrorMessage :string; @@ -169,13 +169,14 @@ constructor TDownloadThread.Create; begin inherited Create(True); isDownload := True; - FHTTP := THTTPSend.Create; - FHTTP.Headers.NameValueSeparator := ':'; + FHTTP := THTTPSendThread.Create(Self); FHTTP.Sock.OnStatus := @SockOnStatus; FHTTP.Timeout := 10000; - FHTTP.Sock.ConnectionTimeout := FHTTP.Timeout; - FHTTP.Sock.SetTimeout(FHTTP.Timeout); - OnCustomTerminate := @OnThreadTerminate; + FHTTP.SetProxy(ProxyType,ProxyHost,ProxyPort,ProxyUser,ProxyPass); + if isSFURL then + FHTTP.UserAgent := UA_CURL + else + FHTTP.UserAgent := DEFAULT_UA; FTotalSize := 0; FCurrentSize := 0; URL := ''; @@ -274,59 +275,6 @@ procedure TDownloadThread.UZipOnStartFile(Sender :TObject; const AFileName :stri end; procedure TDownloadThread.Execute; - - procedure PrepareHTTP(var HTTP :THTTPSend); - begin - if HTTP <> nil then - begin - FHTTP.Clear; - FHTTP.Cookies.Clear; - FHTTP.Protocol := '1.1'; - if isSFURL then - FHTTP.UserAgent := UA_CURL - else - FHTTP.UserAgent := DEFAULT_UA; - with FHTTP do - begin - Timeout := 10000; - Sock.ConnectionTimeout := Timeout; - Sock.SetTimeout(Timeout); - end; - - if ProxyType = 'HTTP' then - begin - HTTP.ProxyHost := ProxyHost; - HTTP.ProxyPort := ProxyPort; - HTTP.ProxyUser := ProxyUser; - HTTP.ProxyPass := ProxyPass; - end - else - if (ProxyType = 'SOCKS4') or (ProxyType = 'SOCKS5') then - begin - if ProxyType = 'SOCKS4' then - HTTP.Sock.SocksType := ST_Socks4 - else - if ProxyType = 'SOCKS5' then - HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := ProxyHost; - HTTP.Sock.SocksPort := ProxyPort; - HTTP.Sock.SocksUsername := ProxyUser; - http.Sock.SocksPassword := ProxyPass; - end - else - begin - HTTP.Sock.SocksIP := ProxyHost; - HTTP.Sock.SocksPort := ProxyPort; - HTTP.Sock.SocksUsername := ProxyUser; - http.Sock.SocksPassword := ProxyPass; - HTTP.ProxyHost := ProxyHost; - HTTP.ProxyPort := ProxyPort; - HTTP.ProxyUser := ProxyUser; - HTTP.ProxyPass := ProxyPass; - end; - end; - end; - var regx : TRegExpr; i, ctry : Cardinal; @@ -343,8 +291,6 @@ procedure TDownloadThread.Execute; HTTPHeaders := TStringList.Create; regx := TRegExpr.Create; try - HTTPHeaders.NameValueSeparator := ':'; - PrepareHTTP(FHTTP); regx.ModifierI := True; if isSFURL then begin @@ -600,9 +546,9 @@ procedure TfrmMain.FormCreate(Sender :TObject); begin Randomize; InitSimpleExceptionHandler(ChangeFileExt(Application.ExeName, '.log')); - uTranslation.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; - uTranslation.LangAppName := 'updater'; - uTranslation.CollectLanguagesFiles; + SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; + SimpleTranslator.LangAppName := 'updater'; + SimpleTranslator.CollectLanguagesFiles; InitCriticalSection(CS_ReadCount); //load proxy config from fmd config := TIniFile.Create('config/config.ini'); @@ -668,7 +614,7 @@ procedure TfrmMain.FormShow(Sender :TObject); else if s = '-l' then _LaunchApp := ParamStrUTF8(i + 1) else if (LowerCase(s) = '--lang') then - uTranslation.SetLang(ParamStrUTF8(i + 1)); + SimpleTranslator.SetLang(ParamStrUTF8(i + 1)); end; end; end; From 5ef26bfe664e7eeb4d157dccce34fc5becef9ef8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 04:34:10 +0800 Subject: [PATCH 0862/2794] updater, fix header separator --- updater/uMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/updater/uMain.pas b/updater/uMain.pas index 4d0528bb4..96db975b2 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -291,6 +291,7 @@ procedure TDownloadThread.Execute; HTTPHeaders := TStringList.Create; regx := TRegExpr.Create; try + HTTPHeaders.NameValueSeparator:=':'; regx.ModifierI := True; if isSFURL then begin From 3e068dc9a0a5855a4936ccc6544b8e29f50475b6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 14:41:11 +0800 Subject: [PATCH 0863/2794] updater, load previous url when fail and clear all cookies --- updater/uMain.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/updater/uMain.pas b/updater/uMain.pas index 96db975b2..e29832dbb 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -390,6 +390,7 @@ procedure TDownloadThread.Execute; FHTTP.Clear; HTTPHeaders.Values['Accept'] := ' */*'; FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Cookies.Clear; while (not FHTTP.HTTPMethod('GET', Trim(rurl))) or (FHTTP.ResultCode >= 300) do begin @@ -410,6 +411,7 @@ procedure TDownloadThread.Execute; else if (FHTTP.ResultCode >= 400) and (FHTTP.ResultCode < 500) then begin + { UpdateStatus(RS_FileNotFound); if _UpdApp then ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + @@ -421,6 +423,12 @@ procedure TDownloadThread.Execute; ShowErrorMessage(Format(RS_FileNotFound_mfdatalink, [mf_data_link])); end; Break; + } + //try to load previous url, in case it was temporary url + if ctry>0 then begin + rurl:=URL; + FHTTP.Cookies.Clear; + end; end else if FHTTP.ResultCode >= 300 then From eb660b88b8a26b3405ceb3a0f51c5e470c8cc3cc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 14:48:17 +0800 Subject: [PATCH 0864/2794] updater, fix retry download fail --- updater/uMain.pas | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index e29832dbb..c0518b772 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -411,24 +411,26 @@ procedure TDownloadThread.Execute; else if (FHTTP.ResultCode >= 400) and (FHTTP.ResultCode < 500) then begin - { - UpdateStatus(RS_FileNotFound); - if _UpdApp then - ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + - RS_Response + ':' + LineEnding + - IntToStr(FHTTP.ResultCode) + ' ' + FHTTP.ResultString) - else + if ctry>=MaxRetry then begin - Clipboard.AsText := mf_data_link; - ShowErrorMessage(Format(RS_FileNotFound_mfdatalink, [mf_data_link])); + UpdateStatus(RS_FileNotFound); + if _UpdApp then + ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + + RS_Response + ':' + LineEnding + + IntToStr(FHTTP.ResultCode) + ' ' + FHTTP.ResultString) + else + begin + Clipboard.AsText := mf_data_link; + ShowErrorMessage(Format(RS_FileNotFound_mfdatalink, [mf_data_link])); + end; + Break; end; - Break; - } //try to load previous url, in case it was temporary url if ctry>0 then begin rurl:=URL; FHTTP.Cookies.Clear; end; + Inc(ctry); end else if FHTTP.ResultCode >= 300 then From c53dc9d6b6ed987d3e1033069f4336bd15f177c0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jan 2016 15:07:55 +0800 Subject: [PATCH 0865/2794] Bump version 0.9.31.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0374a8902..5b6b628a0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,12 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.31.0 (19-01-2016) +[+] Download list: Assign CTRL+Home to move item to top and CTRL+End to move item to bottom +[+] Download list and Favorite list now accept url(s) via drag n drop +[*] Updater: fix various issue +[*] Various changes and bug fixes + 0.9.30.0 (17-01-2016) [*] E-Hentai/ExHentai: fix incorrect page links/page number [*] Batoto: various fix diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c6c6f2ae6..1c7faae53 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="30"/> + <RevisionNr Value="31"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 209d347c8..5962bdce5 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.30.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.30.0/fmd_0.9.30.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.30.0/fmd_0.9.30.0_Win64.7z +VERSION=0.9.31.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.0/fmd_0.9.31.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.0/fmd_0.9.31.0_Win64.7z From ea333508c80de2fe1d317dee53f600a7e1f7e80a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jan 2016 22:43:29 +0800 Subject: [PATCH 0866/2794] decode url first before encode to avoid double encoded fix #166 --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d5f5e6435..1df952470 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2966,7 +2966,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; if Trim(URL) = '' then Exit; URL := FixURL(URL); - URL := EncodeURL(URL); + URL := EncodeURL(DecodeURL(URL)); HTTPHeader := TStringList.Create; HTTPHeader.NameValueSeparator := ':'; @@ -3280,7 +3280,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; Exit(True); URL := FixURL(URL); - URL := EncodeURL(URL); + URL := EncodeURL(DecodeURL(URL)); HTTPHeader := TStringList.Create; HTTPHeader.NameValueSeparator := ':'; From b7aa807a57e818c356cd291db28135b52c96f1c3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jan 2016 22:44:52 +0800 Subject: [PATCH 0867/2794] httpsendthread, decode url first before encode to avoid double encoded --- baseunits/httpsendthread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index ef48534f3..101dd3da8 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -90,7 +90,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; mstream: TMemoryStream; begin Result := False; - rurl := EncodeURL(URL); + rurl := EncodeURL(DecodeURL(URL)); if Pos('HTTP/', Headers.Text) = 1 then Reset; HTTPHeader:= TStringList.Create; HTTPHeader.Assign(Headers); From 829acf5dc5f729998885464c578782f745848da1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jan 2016 23:20:27 +0800 Subject: [PATCH 0868/2794] updater, do url encoding on all urls --- updater/uMain.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index c0518b772..595ac80c0 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -12,7 +12,7 @@ interface Classes, SysUtils, zipper, FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, RegExpr, IniFiles, SimpleException, uMisc, httpsend, blcksock, ssl_openssl, - ssl_openssl_lib, uFMDThread, SimpleTranslator, httpsendthread; + ssl_openssl_lib, synacode, uFMDThread, SimpleTranslator, httpsendthread; type @@ -287,7 +287,7 @@ procedure TDownloadThread.Execute; st, HTTPHeaders: TStringList; filestream : TFileStreamUTF8; begin - URL := Trim(URL); + URL := EncodeURL(DecodeURL(Trim(URL))); HTTPHeaders := TStringList.Create; regx := TRegExpr.Create; try @@ -312,6 +312,7 @@ procedure TDownloadThread.Execute; FileName := sfile; rurl := 'http://sourceforge.net/projects/' + sproject + '/files/' + sdir + '/' + sfile + '/download'; + rurl := EncodeURL(DecodeURL(Trim(rurl))); end else begin @@ -380,6 +381,7 @@ procedure TDownloadThread.Execute; sproject + '/' + sdir + '/' + sfile; end; end; + rurl := EncodeURL(DecodeURL(Trim(rurl))); end; //**download file @@ -437,6 +439,7 @@ procedure TDownloadThread.Execute; begin HTTPHeaders.Values['Referer'] := ' ' + rurl; rurl := Trim(FHTTP.Headers.Values['location']); + rurl := EncodeURL(DecodeURL(Trim(rurl))); end; FHTTP.Clear; FHTTP.Headers.Text := HTTPHeaders.Text; From 9b17cae454098ca611bd268c26fde622224aa6bf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jan 2016 23:21:42 +0800 Subject: [PATCH 0869/2794] remove egscan from siteswithoutinformation --- baseunits/uBaseUnit.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1df952470..9efb7035a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1328,7 +1328,6 @@ function SitesWithoutInformation(const website: String): Boolean; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, MANGAVADISI_ID, - EGSCANS_ID, TURKCRAFT_ID, HUGEMANGA_ID, KIVMANGA_ID, From f0cc0f1ea9c5c697e7e50888f9b4a81293385c45 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jan 2016 23:23:48 +0800 Subject: [PATCH 0870/2794] Bump version 0.9.31.1 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5b6b628a0..7fb4702b6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,10 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.31.0 (21-01-2016) +[*] Fix double URL encoding +[*] Various changes + 0.9.31.0 (19-01-2016) [+] Download list: Assign CTRL+Home to move item to top and CTRL+End to move item to bottom [+] Download list and Favorite list now accept url(s) via drag n drop diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1c7faae53..7a3503de2 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="31"/> + <BuildNr Value="1"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5962bdce5..ff94e65c4 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.31.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.0/fmd_0.9.31.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.0/fmd_0.9.31.0_Win64.7z +VERSION=0.9.31.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.1/fmd_0.9.31.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.1/fmd_0.9.31.1_Win64.7z From b96a21be9fccb17efa02eea98137330493c794de Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 24 Jan 2016 00:32:29 +0800 Subject: [PATCH 0871/2794] frmnain, vtdownload, disable scroll when moving items --- mangadownloader/forms/frmMain.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index df2fa3016..95905e3f7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3702,8 +3702,11 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; procedure TMainForm.vtDownloadKeyAction(Sender: TBaseVirtualTree; var CharCode: Word; var Shift: TShiftState; var DoDefault: Boolean); begin - if (ssCtrl in Shift) and (CharCode in [VK_HOME,VK_END]) then - DoDefault:=False; + if (ssCtrl in Shift) then begin + if (Sender.SelectedCount>0) and + (CharCode in [VK_UP,VK_DOWN,VK_HOME,VK_END]) then + DoDefault:=False; + end; end; procedure TMainForm.vtDownloadKeyDown(Sender : TObject; var Key : Word; From f381255ca797def95247531f2766835c139c4992 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 24 Jan 2016 00:50:41 +0800 Subject: [PATCH 0872/2794] frmmain, vtdownload, fix scroll when moving items --- mangadownloader/forms/frmMain.pas | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 95905e3f7..208811f2c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3449,8 +3449,9 @@ procedure TMainForm.vtDownloadDragAllowed(Sender : TBaseVirtualTree; procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); var i, nIndex: Cardinal; - cNode: PVirtualNode; + cNode, fNode: PVirtualNode; ConTemp: TFPList; + fRect: TRect; begin if vtDownload.SelectedCount=0 then Exit; nIndex:=NextIndex; @@ -3485,19 +3486,22 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); cNode:=vtDownload.GetFirst; while cNode^.Index<nIndex do cNode:=vtDownload.GetNext(cNode); + vtDownload.FocusedNode:=cNode; - if Mode=dmBelow then - vtDownload.ScrollIntoView(cNode,False,False); - + if Mode in [dmBelow,dmNowhere] then + fNode:=cNode; for i:=0 to ConTemp.Count-1 do begin vtDownload.Selected[cNode]:=True; if i<ConTemp.Count-1 then cNode:=vtDownload.GetPrevious(cNode); end; - vtDownload.FocusedNode:=cNode; if Mode=dmAbove then - vtDownload.ScrollIntoView(cNode,False,False); + fNode:=cNode; + + fRect:=vtDownload.GetDisplayRect(fNode,0,False); + if (fRect.Top-vtDownload.Header.Height<0) or (fRect.Bottom>vtDownload.ClientHeight) then + vtDownload.ScrollIntoView(fNode,False,False); finally DLManager.CS_DownloadManager_Task.Release; end; From cf514edd45794b971d14fc552cc8cb55e84b2a71 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 24 Jan 2016 09:32:32 +0800 Subject: [PATCH 0873/2794] fix mangafoxremovewatermark it seems there is a bug in imagingio --- baseunits/extras/mangafoxwatermarkremover.pas | 66 +++++++++++++++---- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas index a995810c4..b5a9dfb8a 100644 --- a/baseunits/extras/mangafoxwatermarkremover.pas +++ b/baseunits/extras/mangafoxwatermarkremover.pas @@ -6,8 +6,8 @@ interface uses Classes, SysUtils, ImagingCompare, ImagingExtras, ImagingBinary, - ImagingClasses, ImagingTypes, ImagingCanvases, Imaging, FileUtil, - LazFileUtils; + ImagingTypes, ImagingCanvases, Imaging, FileUtil, LazFileUtils, + LazUTF8Classes, SimpleLogger; function LoadTemplate(const TempDir: String): Integer; function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean = False): Boolean; @@ -24,6 +24,9 @@ implementation lockproc: TRTLCriticalSection; colorwhite: TColor32Rec = (Color: $FFFFFFFF); +const + mftempfile = 'mangafoxremovewatermarktempfile'; + function LoadTemplate(const TempDir: String): Integer; var flist: TStringList; @@ -71,29 +74,43 @@ function ColorIsWhite(const Color: TColor32Rec): Boolean; function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; var + ms: TMemoryStreamUTF8; imgbase, imgproc, imgtemp: TImageData; i, x, y, bmi: Integer; bmv, PSNR, MSE, RMSE, PAE, MAE: Single; invalidborder: Boolean; + tempfilename, newfilename, newfileext: String; begin Result := False; if not FileExistsUTF8(AFilename) then Exit; if Length(imgtemplate) = 0 then Exit; EnterCriticalsection(lockproc); - InitImage(imgbase); try - // not supported image file - if not LoadImageFromFile(AFilename, imgbase) then Exit; + InitImage(imgbase); + ms:=TMemoryStreamUTF8.Create; + try + ms.LoadFromFile(AFilename); + newfileext:=DetermineStreamFormat(ms); + if newfileext<>'' then + Result:=LoadImageFromStream(ms,imgbase); + finally + ms.Free; + end; + if not Result then begin + FreeImage(imgbase); + Exit; + end; + Result:=False; bmi := -1; bmv := 0; // compare image to all template for i := Low(imgtemplate) to High(imgtemplate) do if imgbase.Height > imgtemplate[i].Height then begin - InitImage(imgproc); - InitImage(imgtemp); try + InitImage(imgproc); + InitImage(imgtemp); invalidborder := False; // crop image to match template @@ -147,11 +164,36 @@ function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; try NewImage(imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgbase.Format, imgproc); CopyRect(imgbase, 0, 0, imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgproc, 0, 0); - if DeleteFileUTF8(AFilename) then begin - if SaveAsPNG then - Result := SaveImageToFile(ChangeFileExt(AFilename, '.png'), imgproc) - else - Result := SaveImageToFile(AFilename, imgproc); + + tempfilename:=ExtractFileDir(AFilename)+mftempfile; + WriteLog_D('tempfilename: '+tempfilename); + + if SaveAsPNG then begin + newfilename:=ChangeFileExt(AFilename,'.png'); + newfileext:='png'; + end + else + newfilename:=AFilename; + + ms:=TMemoryStreamUTF8.Create; + try + Result:=SaveImageToStream(newfileext,ms,imgproc); + if Result then begin + Result:=DeleteFileUTF8(AFilename); + if Result then begin + ms.SaveToFile(newfilename); + Result:=FileExistsUTF8(newfilename); + end + else + WriteLog_E('MangaFoxRemoveWatermark, failed to replace file! '+AFilename); + end + else begin + WriteLog_E('MangaFoxRemoveWatermark, failed to save to file! '+AFilename); + if FileExistsUTF8(tempfilename) then + DeleteFileUTF8(tempfilename); + end; + finally + ms.Free; end; finally FreeImage(imgproc); From 59cad9f5ce9d9be4b17941fcfd58692cfd0807cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 24 Jan 2016 10:29:16 +0800 Subject: [PATCH 0874/2794] Bump version 0.9.31.2 --- changelog.txt | 6 +++++- mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7fb4702b6..b36e2776a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,7 +7,11 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.31.0 (21-01-2016) +0.9.31.2 (24-01-2016) +[*] Fix remove mangafox watermark (file IO error when using multiple threads) +[*] Various changes and bug fixes + +0.9.31.1 (21-01-2016) [*] Fix double URL encoding [*] Various changes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 7a3503de2..5cea285e6 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="31"/> - <BuildNr Value="1"/> + <BuildNr Value="2"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index ff94e65c4..5997ce089 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.31.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.1/fmd_0.9.31.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.1/fmd_0.9.31.1_Win64.7z +VERSION=0.9.31.2 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.2/fmd_0.9.31.2.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.2/fmd_0.9.31.2_Win64.7z From deb3bb31666f93922abfcd5216a3663bc2118ded Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 25 Jan 2016 20:15:45 +0800 Subject: [PATCH 0875/2794] BESEN --- 3rd/besen/src/BESEN.inc | 2 +- 3rd/besen/src/BESEN.pas | 4 ++-- 3rd/besen/src/BESENASTNodes.pas | 2 +- 3rd/besen/src/BESENArrayUtils.pas | 2 +- 3rd/besen/src/BESENBaseObject.pas | 2 +- 3rd/besen/src/BESENCharset.pas | 2 +- 3rd/besen/src/BESENCode.pas | 2 +- 3rd/besen/src/BESENCodeContext.pas | 2 +- 3rd/besen/src/BESENCodeGeneratorContext.pas | 2 +- 3rd/besen/src/BESENCodeJIT.pas | 2 +- 3rd/besen/src/BESENCodeJITx64.pas | 2 +- 3rd/besen/src/BESENCodeJITx86.pas | 2 +- 3rd/besen/src/BESENCodeSnapshot.pas | 2 +- 3rd/besen/src/BESENCollector.pas | 2 +- 3rd/besen/src/BESENCollectorObject.pas | 2 +- 3rd/besen/src/BESENCompiler.pas | 2 +- 3rd/besen/src/BESENConstants.pas | 2 +- 3rd/besen/src/BESENContext.pas | 2 +- 3rd/besen/src/BESENDateUtils.pas | 2 +- 3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas | 2 +- 3rd/besen/src/BESENDecompiler.pas | 6 +++--- 3rd/besen/src/BESENDoubleList.pas | 2 +- 3rd/besen/src/BESENEnvironmentRecord.pas | 2 +- 3rd/besen/src/BESENErrors.pas | 2 +- 3rd/besen/src/BESENEvalCache.pas | 2 +- 3rd/besen/src/BESENEvalCacheItem.pas | 2 +- 3rd/besen/src/BESENGarbageCollector.pas | 2 +- 3rd/besen/src/BESENGlobals.pas | 2 +- 3rd/besen/src/BESENHashMap.pas | 2 +- 3rd/besen/src/BESENHashUtils.pas | 2 +- 3rd/besen/src/BESENInt64SelfBalancedTree.pas | 2 +- 3rd/besen/src/BESENIntegerList.pas | 2 +- 3rd/besen/src/BESENKeyIDManager.pas | 2 +- 3rd/besen/src/BESENLexer.pas | 2 +- 3rd/besen/src/BESENLexicalEnvironment.pas | 2 +- 3rd/besen/src/BESENLocale.pas | 2 +- 3rd/besen/src/BESENNativeCodeMemoryManager.pas | 2 +- 3rd/besen/src/BESENNativeObject.pas | 2 +- 3rd/besen/src/BESENNumberUtils.pas | 2 +- 3rd/besen/src/BESENObject.pas | 2 +- 3rd/besen/src/BESENObjectArgGetterFunction.pas | 2 +- 3rd/besen/src/BESENObjectArgSetterFunction.pas | 2 +- 3rd/besen/src/BESENObjectArray.pas | 2 +- 3rd/besen/src/BESENObjectArrayConstructor.pas | 2 +- 3rd/besen/src/BESENObjectArrayPrototype.pas | 2 +- 3rd/besen/src/BESENObjectBindingFunction.pas | 2 +- 3rd/besen/src/BESENObjectBoolean.pas | 2 +- 3rd/besen/src/BESENObjectBooleanConstructor.pas | 2 +- 3rd/besen/src/BESENObjectBooleanPrototype.pas | 2 +- 3rd/besen/src/BESENObjectConsole.pas | 2 +- 3rd/besen/src/BESENObjectConstructor.pas | 2 +- 3rd/besen/src/BESENObjectDate.pas | 2 +- 3rd/besen/src/BESENObjectDateConstructor.pas | 2 +- 3rd/besen/src/BESENObjectDatePrototype.pas | 2 +- 3rd/besen/src/BESENObjectDeclaredFunction.pas | 2 +- 3rd/besen/src/BESENObjectEnvironmentRecord.pas | 2 +- 3rd/besen/src/BESENObjectError.pas | 2 +- 3rd/besen/src/BESENObjectErrorConstructor.pas | 2 +- 3rd/besen/src/BESENObjectErrorPrototype.pas | 2 +- 3rd/besen/src/BESENObjectFunction.pas | 2 +- 3rd/besen/src/BESENObjectFunctionArguments.pas | 2 +- 3rd/besen/src/BESENObjectFunctionConstructor.pas | 2 +- 3rd/besen/src/BESENObjectFunctionPrototype.pas | 2 +- 3rd/besen/src/BESENObjectGlobal.pas | 2 +- 3rd/besen/src/BESENObjectJSON.pas | 2 +- 3rd/besen/src/BESENObjectMath.pas | 2 +- 3rd/besen/src/BESENObjectNativeFunction.pas | 2 +- 3rd/besen/src/BESENObjectNumber.pas | 2 +- 3rd/besen/src/BESENObjectNumberConstructor.pas | 2 +- 3rd/besen/src/BESENObjectNumberPrototype.pas | 2 +- 3rd/besen/src/BESENObjectPropertyDescriptor.pas | 2 +- 3rd/besen/src/BESENObjectPrototype.pas | 2 +- 3rd/besen/src/BESENObjectRegExp.pas | 2 +- 3rd/besen/src/BESENObjectRegExpConstructor.pas | 2 +- 3rd/besen/src/BESENObjectRegExpPrototype.pas | 2 +- 3rd/besen/src/BESENObjectString.pas | 2 +- 3rd/besen/src/BESENObjectStringConstructor.pas | 2 +- 3rd/besen/src/BESENObjectStringPrototype.pas | 2 +- 3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas | 2 +- 3rd/besen/src/BESENOpcodes.pas | 2 +- 3rd/besen/src/BESENParser.pas | 2 +- 3rd/besen/src/BESENPointerList.pas | 2 +- 3rd/besen/src/BESENPointerSelfBalancedTree.pas | 2 +- 3rd/besen/src/BESENRandomGenerator.pas | 2 +- 3rd/besen/src/BESENRegExp.pas | 2 +- 3rd/besen/src/BESENRegExpCache.pas | 2 +- 3rd/besen/src/BESENScope.pas | 2 +- 3rd/besen/src/BESENSelfBalancedTree.pas | 2 +- 3rd/besen/src/BESENStringList.pas | 2 +- 3rd/besen/src/BESENStringTree.pas | 2 +- 90 files changed, 93 insertions(+), 93 deletions(-) diff --git a/3rd/besen/src/BESEN.inc b/3rd/besen/src/BESEN.inc index 3fb68545a..f23723ff9 100644 --- a/3rd/besen/src/BESEN.inc +++ b/3rd/besen/src/BESEN.inc @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESEN.pas b/3rd/besen/src/BESEN.pas index 25e28909e..b4b5b51e7 100644 --- a/3rd/besen/src/BESEN.pas +++ b/3rd/besen/src/BESEN.pas @@ -4,7 +4,7 @@ Version: See at line in BESENVersionConstants.pas, which contains "BESENVersion" -------------------------------------------------------------------------------- - Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux <benjamin@rosseaux.com> + Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux <benjamin@rosseaux.com> Website: www.rosseaux.com @@ -47,7 +47,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENASTNodes.pas b/3rd/besen/src/BESENASTNodes.pas index b7ee609c1..bc1877728 100644 --- a/3rd/besen/src/BESENASTNodes.pas +++ b/3rd/besen/src/BESENASTNodes.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENArrayUtils.pas b/3rd/besen/src/BESENArrayUtils.pas index c8e8f1944..b43983dc0 100644 --- a/3rd/besen/src/BESENArrayUtils.pas +++ b/3rd/besen/src/BESENArrayUtils.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENBaseObject.pas b/3rd/besen/src/BESENBaseObject.pas index d98f92f57..bbc3cbdf6 100644 --- a/3rd/besen/src/BESENBaseObject.pas +++ b/3rd/besen/src/BESENBaseObject.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCharset.pas b/3rd/besen/src/BESENCharset.pas index f4827ca15..3ef487e46 100644 --- a/3rd/besen/src/BESENCharset.pas +++ b/3rd/besen/src/BESENCharset.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCode.pas b/3rd/besen/src/BESENCode.pas index c233aedf3..68d921bce 100644 --- a/3rd/besen/src/BESENCode.pas +++ b/3rd/besen/src/BESENCode.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCodeContext.pas b/3rd/besen/src/BESENCodeContext.pas index 04f4cdb5f..a5657aa4c 100644 --- a/3rd/besen/src/BESENCodeContext.pas +++ b/3rd/besen/src/BESENCodeContext.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCodeGeneratorContext.pas b/3rd/besen/src/BESENCodeGeneratorContext.pas index efdb0aac7..7b0cc5ed2 100644 --- a/3rd/besen/src/BESENCodeGeneratorContext.pas +++ b/3rd/besen/src/BESENCodeGeneratorContext.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCodeJIT.pas b/3rd/besen/src/BESENCodeJIT.pas index 30634221f..cf1acf911 100644 --- a/3rd/besen/src/BESENCodeJIT.pas +++ b/3rd/besen/src/BESENCodeJIT.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCodeJITx64.pas b/3rd/besen/src/BESENCodeJITx64.pas index dabc5ff85..fb4d067c2 100644 --- a/3rd/besen/src/BESENCodeJITx64.pas +++ b/3rd/besen/src/BESENCodeJITx64.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCodeJITx86.pas b/3rd/besen/src/BESENCodeJITx86.pas index 0f9a153ec..1328ea679 100644 --- a/3rd/besen/src/BESENCodeJITx86.pas +++ b/3rd/besen/src/BESENCodeJITx86.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCodeSnapshot.pas b/3rd/besen/src/BESENCodeSnapshot.pas index eac0acbec..02756543a 100644 --- a/3rd/besen/src/BESENCodeSnapshot.pas +++ b/3rd/besen/src/BESENCodeSnapshot.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCollector.pas b/3rd/besen/src/BESENCollector.pas index 7a9c8c7f5..4f91d3e42 100644 --- a/3rd/besen/src/BESENCollector.pas +++ b/3rd/besen/src/BESENCollector.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCollectorObject.pas b/3rd/besen/src/BESENCollectorObject.pas index 9c58e984c..6523d33f7 100644 --- a/3rd/besen/src/BESENCollectorObject.pas +++ b/3rd/besen/src/BESENCollectorObject.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENCompiler.pas b/3rd/besen/src/BESENCompiler.pas index e735a4580..31fe5c132 100644 --- a/3rd/besen/src/BESENCompiler.pas +++ b/3rd/besen/src/BESENCompiler.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENConstants.pas b/3rd/besen/src/BESENConstants.pas index e1c510728..cdea9090e 100644 --- a/3rd/besen/src/BESENConstants.pas +++ b/3rd/besen/src/BESENConstants.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENContext.pas b/3rd/besen/src/BESENContext.pas index dff5c26d9..9914497c1 100644 --- a/3rd/besen/src/BESENContext.pas +++ b/3rd/besen/src/BESENContext.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENDateUtils.pas b/3rd/besen/src/BESENDateUtils.pas index c754585f5..694a984bd 100644 --- a/3rd/besen/src/BESENDateUtils.pas +++ b/3rd/besen/src/BESENDateUtils.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas b/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas index eb6ecd072..b4636da80 100644 --- a/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas +++ b/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENDecompiler.pas b/3rd/besen/src/BESENDecompiler.pas index 2e7bd733b..11d94d074 100644 --- a/3rd/besen/src/BESENDecompiler.pas +++ b/3rd/besen/src/BESENDecompiler.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 @@ -850,11 +850,11 @@ function TBESENDecompiler.Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; end; end; bntUNARYVOIDEXPRESSION:begin - Add('void'); + Add('void '); Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); end; bntUNARYTYPEOFEXPRESSION:begin - Add('typeof'); + Add('typeof '); Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); end; bntPROPERTYEXPRESSION:begin diff --git a/3rd/besen/src/BESENDoubleList.pas b/3rd/besen/src/BESENDoubleList.pas index 3b1e196af..30bea5aaa 100644 --- a/3rd/besen/src/BESENDoubleList.pas +++ b/3rd/besen/src/BESENDoubleList.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENEnvironmentRecord.pas b/3rd/besen/src/BESENEnvironmentRecord.pas index 8dd3fba6e..415652e1a 100644 --- a/3rd/besen/src/BESENEnvironmentRecord.pas +++ b/3rd/besen/src/BESENEnvironmentRecord.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENErrors.pas b/3rd/besen/src/BESENErrors.pas index 0eb79a9a3..efab7d836 100644 --- a/3rd/besen/src/BESENErrors.pas +++ b/3rd/besen/src/BESENErrors.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENEvalCache.pas b/3rd/besen/src/BESENEvalCache.pas index 7b164b91d..a7d4ffc06 100644 --- a/3rd/besen/src/BESENEvalCache.pas +++ b/3rd/besen/src/BESENEvalCache.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENEvalCacheItem.pas b/3rd/besen/src/BESENEvalCacheItem.pas index a82d03176..49b50ee4d 100644 --- a/3rd/besen/src/BESENEvalCacheItem.pas +++ b/3rd/besen/src/BESENEvalCacheItem.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENGarbageCollector.pas b/3rd/besen/src/BESENGarbageCollector.pas index 8f88112b6..2e523a97d 100644 --- a/3rd/besen/src/BESENGarbageCollector.pas +++ b/3rd/besen/src/BESENGarbageCollector.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENGlobals.pas b/3rd/besen/src/BESENGlobals.pas index 54392bdc5..6880c1f2b 100644 --- a/3rd/besen/src/BESENGlobals.pas +++ b/3rd/besen/src/BESENGlobals.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENHashMap.pas b/3rd/besen/src/BESENHashMap.pas index 773fb908f..cb7e502a0 100644 --- a/3rd/besen/src/BESENHashMap.pas +++ b/3rd/besen/src/BESENHashMap.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENHashUtils.pas b/3rd/besen/src/BESENHashUtils.pas index 74be316e8..2655a42bb 100644 --- a/3rd/besen/src/BESENHashUtils.pas +++ b/3rd/besen/src/BESENHashUtils.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENInt64SelfBalancedTree.pas b/3rd/besen/src/BESENInt64SelfBalancedTree.pas index a6f4ca204..391124762 100644 --- a/3rd/besen/src/BESENInt64SelfBalancedTree.pas +++ b/3rd/besen/src/BESENInt64SelfBalancedTree.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENIntegerList.pas b/3rd/besen/src/BESENIntegerList.pas index 44a65c584..182ae56f6 100644 --- a/3rd/besen/src/BESENIntegerList.pas +++ b/3rd/besen/src/BESENIntegerList.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENKeyIDManager.pas b/3rd/besen/src/BESENKeyIDManager.pas index 1e8542a4b..59eba91bd 100644 --- a/3rd/besen/src/BESENKeyIDManager.pas +++ b/3rd/besen/src/BESENKeyIDManager.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENLexer.pas b/3rd/besen/src/BESENLexer.pas index 6fb3bcc5a..17a26c576 100644 --- a/3rd/besen/src/BESENLexer.pas +++ b/3rd/besen/src/BESENLexer.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENLexicalEnvironment.pas b/3rd/besen/src/BESENLexicalEnvironment.pas index 6ce3e5281..65a726cd7 100644 --- a/3rd/besen/src/BESENLexicalEnvironment.pas +++ b/3rd/besen/src/BESENLexicalEnvironment.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENLocale.pas b/3rd/besen/src/BESENLocale.pas index 7dbffbe2f..9791fe191 100644 --- a/3rd/besen/src/BESENLocale.pas +++ b/3rd/besen/src/BESENLocale.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENNativeCodeMemoryManager.pas b/3rd/besen/src/BESENNativeCodeMemoryManager.pas index f23aa30b3..a21b0e392 100644 --- a/3rd/besen/src/BESENNativeCodeMemoryManager.pas +++ b/3rd/besen/src/BESENNativeCodeMemoryManager.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENNativeObject.pas b/3rd/besen/src/BESENNativeObject.pas index e888373a9..6c1e2f026 100644 --- a/3rd/besen/src/BESENNativeObject.pas +++ b/3rd/besen/src/BESENNativeObject.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENNumberUtils.pas b/3rd/besen/src/BESENNumberUtils.pas index 2aa91ea3d..4865d286c 100644 --- a/3rd/besen/src/BESENNumberUtils.pas +++ b/3rd/besen/src/BESENNumberUtils.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObject.pas b/3rd/besen/src/BESENObject.pas index d3a2b064e..f0a1cf769 100644 --- a/3rd/besen/src/BESENObject.pas +++ b/3rd/besen/src/BESENObject.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectArgGetterFunction.pas b/3rd/besen/src/BESENObjectArgGetterFunction.pas index c0c517f51..cb0ee4ce3 100644 --- a/3rd/besen/src/BESENObjectArgGetterFunction.pas +++ b/3rd/besen/src/BESENObjectArgGetterFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectArgSetterFunction.pas b/3rd/besen/src/BESENObjectArgSetterFunction.pas index 2f95ebfbf..60bac0587 100644 --- a/3rd/besen/src/BESENObjectArgSetterFunction.pas +++ b/3rd/besen/src/BESENObjectArgSetterFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectArray.pas b/3rd/besen/src/BESENObjectArray.pas index 6520bb2df..4db3bac2b 100644 --- a/3rd/besen/src/BESENObjectArray.pas +++ b/3rd/besen/src/BESENObjectArray.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectArrayConstructor.pas b/3rd/besen/src/BESENObjectArrayConstructor.pas index 28dd8c1b4..2590278e7 100644 --- a/3rd/besen/src/BESENObjectArrayConstructor.pas +++ b/3rd/besen/src/BESENObjectArrayConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectArrayPrototype.pas b/3rd/besen/src/BESENObjectArrayPrototype.pas index 70de1ac16..60bf971ec 100644 --- a/3rd/besen/src/BESENObjectArrayPrototype.pas +++ b/3rd/besen/src/BESENObjectArrayPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectBindingFunction.pas b/3rd/besen/src/BESENObjectBindingFunction.pas index bdec1ecda..da3c0cbd3 100644 --- a/3rd/besen/src/BESENObjectBindingFunction.pas +++ b/3rd/besen/src/BESENObjectBindingFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectBoolean.pas b/3rd/besen/src/BESENObjectBoolean.pas index 504bc0031..118264e62 100644 --- a/3rd/besen/src/BESENObjectBoolean.pas +++ b/3rd/besen/src/BESENObjectBoolean.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectBooleanConstructor.pas b/3rd/besen/src/BESENObjectBooleanConstructor.pas index be28a3ae8..8ad3c33fb 100644 --- a/3rd/besen/src/BESENObjectBooleanConstructor.pas +++ b/3rd/besen/src/BESENObjectBooleanConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectBooleanPrototype.pas b/3rd/besen/src/BESENObjectBooleanPrototype.pas index d44fd6606..466a7536b 100644 --- a/3rd/besen/src/BESENObjectBooleanPrototype.pas +++ b/3rd/besen/src/BESENObjectBooleanPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectConsole.pas b/3rd/besen/src/BESENObjectConsole.pas index ad461a72e..531b0e9fc 100644 --- a/3rd/besen/src/BESENObjectConsole.pas +++ b/3rd/besen/src/BESENObjectConsole.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectConstructor.pas b/3rd/besen/src/BESENObjectConstructor.pas index 1ae63c7a2..afd5ed97e 100644 --- a/3rd/besen/src/BESENObjectConstructor.pas +++ b/3rd/besen/src/BESENObjectConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectDate.pas b/3rd/besen/src/BESENObjectDate.pas index a2088c4f5..d6572d073 100644 --- a/3rd/besen/src/BESENObjectDate.pas +++ b/3rd/besen/src/BESENObjectDate.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectDateConstructor.pas b/3rd/besen/src/BESENObjectDateConstructor.pas index 637ef0f3d..7da26baed 100644 --- a/3rd/besen/src/BESENObjectDateConstructor.pas +++ b/3rd/besen/src/BESENObjectDateConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectDatePrototype.pas b/3rd/besen/src/BESENObjectDatePrototype.pas index 53b3549e4..bd095da39 100644 --- a/3rd/besen/src/BESENObjectDatePrototype.pas +++ b/3rd/besen/src/BESENObjectDatePrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectDeclaredFunction.pas b/3rd/besen/src/BESENObjectDeclaredFunction.pas index a950651c4..9d0506dfb 100644 --- a/3rd/besen/src/BESENObjectDeclaredFunction.pas +++ b/3rd/besen/src/BESENObjectDeclaredFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectEnvironmentRecord.pas b/3rd/besen/src/BESENObjectEnvironmentRecord.pas index 03afffbf6..af811c7f9 100644 --- a/3rd/besen/src/BESENObjectEnvironmentRecord.pas +++ b/3rd/besen/src/BESENObjectEnvironmentRecord.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectError.pas b/3rd/besen/src/BESENObjectError.pas index e0d26d1a9..3e86d3f1d 100644 --- a/3rd/besen/src/BESENObjectError.pas +++ b/3rd/besen/src/BESENObjectError.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectErrorConstructor.pas b/3rd/besen/src/BESENObjectErrorConstructor.pas index ecbe71fb3..9e00fc4c3 100644 --- a/3rd/besen/src/BESENObjectErrorConstructor.pas +++ b/3rd/besen/src/BESENObjectErrorConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectErrorPrototype.pas b/3rd/besen/src/BESENObjectErrorPrototype.pas index 1fd6e4453..dd3c10158 100644 --- a/3rd/besen/src/BESENObjectErrorPrototype.pas +++ b/3rd/besen/src/BESENObjectErrorPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectFunction.pas b/3rd/besen/src/BESENObjectFunction.pas index d857cb3ae..bccd29aa2 100644 --- a/3rd/besen/src/BESENObjectFunction.pas +++ b/3rd/besen/src/BESENObjectFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectFunctionArguments.pas b/3rd/besen/src/BESENObjectFunctionArguments.pas index 1ca9914f6..d52ba4275 100644 --- a/3rd/besen/src/BESENObjectFunctionArguments.pas +++ b/3rd/besen/src/BESENObjectFunctionArguments.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectFunctionConstructor.pas b/3rd/besen/src/BESENObjectFunctionConstructor.pas index 97dd867fb..d69c8e03d 100644 --- a/3rd/besen/src/BESENObjectFunctionConstructor.pas +++ b/3rd/besen/src/BESENObjectFunctionConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectFunctionPrototype.pas b/3rd/besen/src/BESENObjectFunctionPrototype.pas index e335f62fb..71dddaab1 100644 --- a/3rd/besen/src/BESENObjectFunctionPrototype.pas +++ b/3rd/besen/src/BESENObjectFunctionPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectGlobal.pas b/3rd/besen/src/BESENObjectGlobal.pas index 753530099..2b1a5d7bf 100644 --- a/3rd/besen/src/BESENObjectGlobal.pas +++ b/3rd/besen/src/BESENObjectGlobal.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectJSON.pas b/3rd/besen/src/BESENObjectJSON.pas index f7d1b0af9..5773631b7 100644 --- a/3rd/besen/src/BESENObjectJSON.pas +++ b/3rd/besen/src/BESENObjectJSON.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectMath.pas b/3rd/besen/src/BESENObjectMath.pas index e7bcc0307..35944d657 100644 --- a/3rd/besen/src/BESENObjectMath.pas +++ b/3rd/besen/src/BESENObjectMath.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectNativeFunction.pas b/3rd/besen/src/BESENObjectNativeFunction.pas index 07db4cd3a..99e4ee82c 100644 --- a/3rd/besen/src/BESENObjectNativeFunction.pas +++ b/3rd/besen/src/BESENObjectNativeFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectNumber.pas b/3rd/besen/src/BESENObjectNumber.pas index 3ae3c18f0..c981651d3 100644 --- a/3rd/besen/src/BESENObjectNumber.pas +++ b/3rd/besen/src/BESENObjectNumber.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectNumberConstructor.pas b/3rd/besen/src/BESENObjectNumberConstructor.pas index 4cb87c2f4..a0261fc5a 100644 --- a/3rd/besen/src/BESENObjectNumberConstructor.pas +++ b/3rd/besen/src/BESENObjectNumberConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectNumberPrototype.pas b/3rd/besen/src/BESENObjectNumberPrototype.pas index 373bbf03c..4ce2dfb24 100644 --- a/3rd/besen/src/BESENObjectNumberPrototype.pas +++ b/3rd/besen/src/BESENObjectNumberPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectPropertyDescriptor.pas b/3rd/besen/src/BESENObjectPropertyDescriptor.pas index 9e1edf697..425667358 100644 --- a/3rd/besen/src/BESENObjectPropertyDescriptor.pas +++ b/3rd/besen/src/BESENObjectPropertyDescriptor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectPrototype.pas b/3rd/besen/src/BESENObjectPrototype.pas index 29ce83c7f..713a8c147 100644 --- a/3rd/besen/src/BESENObjectPrototype.pas +++ b/3rd/besen/src/BESENObjectPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectRegExp.pas b/3rd/besen/src/BESENObjectRegExp.pas index 6c26f1e02..c812bbc73 100644 --- a/3rd/besen/src/BESENObjectRegExp.pas +++ b/3rd/besen/src/BESENObjectRegExp.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectRegExpConstructor.pas b/3rd/besen/src/BESENObjectRegExpConstructor.pas index 0343d4916..793d58410 100644 --- a/3rd/besen/src/BESENObjectRegExpConstructor.pas +++ b/3rd/besen/src/BESENObjectRegExpConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectRegExpPrototype.pas b/3rd/besen/src/BESENObjectRegExpPrototype.pas index d3eba81ff..4d191ebd6 100644 --- a/3rd/besen/src/BESENObjectRegExpPrototype.pas +++ b/3rd/besen/src/BESENObjectRegExpPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectString.pas b/3rd/besen/src/BESENObjectString.pas index c2a1bd264..0969d292a 100644 --- a/3rd/besen/src/BESENObjectString.pas +++ b/3rd/besen/src/BESENObjectString.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectStringConstructor.pas b/3rd/besen/src/BESENObjectStringConstructor.pas index 64bcf214a..263aa140a 100644 --- a/3rd/besen/src/BESENObjectStringConstructor.pas +++ b/3rd/besen/src/BESENObjectStringConstructor.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectStringPrototype.pas b/3rd/besen/src/BESENObjectStringPrototype.pas index 29f97158b..d22643c04 100644 --- a/3rd/besen/src/BESENObjectStringPrototype.pas +++ b/3rd/besen/src/BESENObjectStringPrototype.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas b/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas index cad4125fb..da3648759 100644 --- a/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas +++ b/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENOpcodes.pas b/3rd/besen/src/BESENOpcodes.pas index 2de31364c..e3e2a4e16 100644 --- a/3rd/besen/src/BESENOpcodes.pas +++ b/3rd/besen/src/BESENOpcodes.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENParser.pas b/3rd/besen/src/BESENParser.pas index 1cb64b9c5..81fb24a5e 100644 --- a/3rd/besen/src/BESENParser.pas +++ b/3rd/besen/src/BESENParser.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENPointerList.pas b/3rd/besen/src/BESENPointerList.pas index 8c8fa2240..e49fbb8e0 100644 --- a/3rd/besen/src/BESENPointerList.pas +++ b/3rd/besen/src/BESENPointerList.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENPointerSelfBalancedTree.pas b/3rd/besen/src/BESENPointerSelfBalancedTree.pas index 322e2b38d..48f1ffa4e 100644 --- a/3rd/besen/src/BESENPointerSelfBalancedTree.pas +++ b/3rd/besen/src/BESENPointerSelfBalancedTree.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENRandomGenerator.pas b/3rd/besen/src/BESENRandomGenerator.pas index d4979eaaf..23d455539 100644 --- a/3rd/besen/src/BESENRandomGenerator.pas +++ b/3rd/besen/src/BESENRandomGenerator.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENRegExp.pas b/3rd/besen/src/BESENRegExp.pas index facbde819..175394068 100644 --- a/3rd/besen/src/BESENRegExp.pas +++ b/3rd/besen/src/BESENRegExp.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENRegExpCache.pas b/3rd/besen/src/BESENRegExpCache.pas index 48928a0ab..930b64f0a 100644 --- a/3rd/besen/src/BESENRegExpCache.pas +++ b/3rd/besen/src/BESENRegExpCache.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENScope.pas b/3rd/besen/src/BESENScope.pas index a842569e1..9c4d3f98a 100644 --- a/3rd/besen/src/BESENScope.pas +++ b/3rd/besen/src/BESENScope.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENSelfBalancedTree.pas b/3rd/besen/src/BESENSelfBalancedTree.pas index 6b5a09734..8cf5b441a 100644 --- a/3rd/besen/src/BESENSelfBalancedTree.pas +++ b/3rd/besen/src/BESENSelfBalancedTree.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENStringList.pas b/3rd/besen/src/BESENStringList.pas index 585ba6120..3abb6ef48 100644 --- a/3rd/besen/src/BESENStringList.pas +++ b/3rd/besen/src/BESENStringList.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENStringTree.pas b/3rd/besen/src/BESENStringTree.pas index 74fb4ae6b..a3b2dcffd 100644 --- a/3rd/besen/src/BESENStringTree.pas +++ b/3rd/besen/src/BESENStringTree.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 From ba3157a3ea4b49f986c373bf44fb24990fb004d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 25 Jan 2016 20:34:32 +0800 Subject: [PATCH 0876/2794] mangafoxremovewatermark, load from filestream directly --- baseunits/extras/mangafoxwatermarkremover.pas | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas index b5a9dfb8a..d2d9c2b41 100644 --- a/baseunits/extras/mangafoxwatermarkremover.pas +++ b/baseunits/extras/mangafoxwatermarkremover.pas @@ -74,6 +74,7 @@ function ColorIsWhite(const Color: TColor32Rec): Boolean; function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; var + fs: TFileStreamUTF8; ms: TMemoryStreamUTF8; imgbase, imgproc, imgtemp: TImageData; i, x, y, bmi: Integer; @@ -85,17 +86,20 @@ function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; if not FileExistsUTF8(AFilename) then Exit; if Length(imgtemplate) = 0 then Exit; + tempfilename:=''; + newfilename:=''; + newfileext:=''; + EnterCriticalsection(lockproc); try InitImage(imgbase); - ms:=TMemoryStreamUTF8.Create; + fs:=TFileStreamUTF8.Create(AFilename,fmOpenRead or fmShareDenyWrite); try - ms.LoadFromFile(AFilename); - newfileext:=DetermineStreamFormat(ms); + newfileext:=DetermineStreamFormat(fs); if newfileext<>'' then - Result:=LoadImageFromStream(ms,imgbase); + Result:=LoadImageFromStream(fs,imgbase); finally - ms.Free; + fs.Free; end; if not Result then begin FreeImage(imgbase); From 6fba1e52eda441ef5ff0fbfa4e219e653fe31131 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 25 Jan 2016 22:30:46 +0800 Subject: [PATCH 0877/2794] downloadmanager, doexitwaitcounter only if not do_nothing --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 69d025543..7e2029022 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2042,7 +2042,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); begin MainForm.itRefreshDLInfo.Enabled := False; MainForm.UpdateVtDownload; - if isCheckForFMDDo then begin + if isCheckForFMDDo and (OptionLetFMDDo<>DO_NOTHING) then begin frmMain.DoAfterFMD := OptionLetFMDDo; MainForm.DoExitWaitCounter; end; From 5acf88994cbf813fbab701c0d1cc29dc6a45dc26 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 25 Jan 2016 23:35:08 +0800 Subject: [PATCH 0878/2794] mangafoxremovewatermark, cleanup --- baseunits/extras/mangafoxwatermarkremover.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas index d2d9c2b41..1c0282456 100644 --- a/baseunits/extras/mangafoxwatermarkremover.pas +++ b/baseunits/extras/mangafoxwatermarkremover.pas @@ -170,7 +170,6 @@ function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; CopyRect(imgbase, 0, 0, imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgproc, 0, 0); tempfilename:=ExtractFileDir(AFilename)+mftempfile; - WriteLog_D('tempfilename: '+tempfilename); if SaveAsPNG then begin newfilename:=ChangeFileExt(AFilename,'.png'); From 686373e8295a54efbcd1c9ec13e54bf14c1b5d52 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 25 Jan 2016 23:41:49 +0800 Subject: [PATCH 0879/2794] img2pdf, cleanup and fix --- baseunits/uImg2Pdf.pas | 213 ++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 120 deletions(-) diff --git a/baseunits/uImg2Pdf.pas b/baseunits/uImg2Pdf.pas index 419ec7184..6d4ad4d43 100644 --- a/baseunits/uImg2Pdf.pas +++ b/baseunits/uImg2Pdf.pas @@ -11,8 +11,9 @@ interface uses - Classes, SysUtils, ZStream, FPImage, FPReadJPEG, FPWriteJPEG, - ImagingTypes, Imaging, lazutf8classes, SimpleLogger, SimpleException; + Classes, SysUtils, lazutf8classes, LazFileUtils, + ZStream, ImagingTypes, Imaging, ImagingExtras, + SimpleLogger, SimpleException; const TPDFFormatSetings: TFormatSettings = ( @@ -44,7 +45,7 @@ interface type TPageInfo = record fWidth, fHeight: Single; - imgStream : TMemoryStream; + imgStream : TMemoryStreamUTF8; bpc : Byte; cs, f : String; end; @@ -53,7 +54,7 @@ TPageInfo = record TImg2Pdf = class(TObject) private - FBuffer : TMemoryStream; + FBuffer : TMemoryStreamUTF8; FState : Integer; FCompressionQuality, FObjCount, @@ -71,10 +72,7 @@ TImg2Pdf = class(TObject) procedure PDFWrite(AText: String); function PDFString(const AText: String): String; procedure Error(AMsg: String); - procedure AddFlateImage(const AName: String); - procedure AddDCTImage(const AName: String); function GetImageFormat(imData: TImageData): string; - procedure SetCompressionQuality(Quality: Cardinal); public constructor Create; destructor Destroy; override; @@ -83,7 +81,7 @@ TImg2Pdf = class(TObject) procedure SaveToFile(const AFile: String); property Title: String read FTitle write FTitle; - property CompressionQuality: Cardinal read FCompressionQuality write SetCompressionQuality; + property CompressionQuality: Cardinal read FCompressionQuality write FCompressionQuality; end; implementation @@ -270,7 +268,7 @@ constructor TImg2Pdf.Create; SetLength(FPages, 0); SetLength(FOffsets, 3); SetLength(FPageInfos, 0); - FBuffer:= TMemoryStream.Create; + FBuffer:= TMemoryStreamUTF8.Create; BeginPDF; end; @@ -289,107 +287,6 @@ destructor TImg2Pdf.Destroy; inherited; end; -procedure TImg2Pdf.AddFlateImage(const AName: String); -var - fs : TFileStreamUTF8; - ext : String; - im : TImageData; -begin - ext:= StringReplace(UpperCase(ExtractFileExt(AName)), '.', '', [rfReplaceAll]); - if (ext = '') then - Error('File without an extension!'); - - Initialize(im); - fs := TFileStreamUTF8.Create(AName, fmOpenRead); - try - LoadImageFromStream(fs, im); - if not Assigned(im.Bits) then Exit; - - BeginPDFPage(im.Width, im.Height); - FPageInfos[FCurrentPage].imgStream:= TMemoryStream.Create; - try - FPageInfos[FCurrentPage].cs := GetImageFormat(im); - FPageInfos[FCurrentPage].fWidth := im.Width; - FPageInfos[FCurrentPage].fHeight:= im.Height; - FPageInfos[FCurrentPage].bpc := 8; - PDFWrite('q ' + FloatToStr(im.Width) + ' 0 0 ' + FloatToStr(im.Height) + - ' 0 -' + FloatToStr(im.Height) + ' cm /I' + - IntToStr(FCurrentPage) + ' Do Q'); - - if (ext = 'JPG') or (ext = 'JPEG') then - begin - FPageInfos[FCurrentPage].f := 'DCTDecode'; - FPageInfos[FCurrentPage].imgStream.CopyFrom(fs, 0); - end - else - begin - FPageInfos[FCurrentPage].f := 'FlateDecode'; - if GetImageFormat(im) = 'DeviceRGB' then try - SwapChannels(im, ChannelRed, ChannelBlue); - except - end; - FPageInfos[FCurrentPage].imgStream.Position := 0; - with Tcompressionstream.create(clmax, FPageInfos[FCurrentPage].imgStream) do try - write(im.Bits^, im.Size); - finally - Free; - end; - end; - finally - EndPDFPage; - end; - except - on E :Exception do begin - WriteLog_E('TImg2Pdf.AddFlateImage.Error, '+E.Message); - SimpleException.ExceptionHandleSaveLogOnly(Self, E); - end; - end; - fs.Free; - FreeImage(im); -end; - -procedure TImg2Pdf.AddDCTImage(const AName: String); -var - fs : TFileStreamUTF8; - im : TImageData; - ext : string; -begin - ext := StringReplace(UpperCase(ExtractFileExt(AName)), '.', '', [rfReplaceAll]); - if (ext = '') then - Error('File without an extension!'); - - Initialize(im); - fs:= TFileStreamUTF8.Create(AName, fmOpenRead); - try - LoadImageFromStream(fs, im); - finally - fs.Free; - end; - if not Assigned(im.Bits) then Exit; - - BeginPDFPage(im.Width, im.Height); - FPageInfos[FCurrentPage].imgStream := TMemoryStream.Create; - try - FPageInfos[FCurrentPage].cs := GetImageFormat(im); - FPageInfos[FCurrentPage].fWidth := im.Width; - FPageInfos[FCurrentPage].fHeight:= im.Height; - FPageInfos[FCurrentPage].bpc := 8; - FPageInfos[FCurrentPage].f := 'DCTDecode'; - PDFWrite('q ' + FloatToStr(im.Width) + ' 0 0 ' + FloatToStr(im.Height) + - ' 0 -' + FloatToStr(im.Height) + ' cm /I' + - IntToStr(FCurrentPage) + ' Do Q'); - - SaveImageToStream('jpg', FPageInfos[FCurrentPage].imgStream, im); - except - on E :Exception do begin - WriteLog_E('TImg2Pdf.AddCDTImage.Error, '+E.Message); - SimpleException.ExceptionHandleSaveLogOnly(Self, E); - end; - end; - EndPDFPage; - FreeImage(im); -end; - function TImg2Pdf.GetImageFormat(imData: TImageData): string; begin case imData.Format of @@ -430,18 +327,93 @@ function TImg2Pdf.GetImageFormat(imData: TImageData): string; end; end; -procedure TImg2Pdf.SetCompressionQuality(Quality: Cardinal); -begin - FCompressionQuality := Quality; - Imaging.SetOption(ImagingJpegQuality, FCompressionQuality); -end; - procedure TImg2Pdf.AddImage(const AName: String); +var + ms: TMemoryStreamUTF8; + img: TImageData; + imgloaded: Boolean; + imgext,imgc: String; + imgwidth,imgheight,defaultjpeg: LongInt; begin - if FCompressionQuality = 100 then - AddFlateImage(AName) - else - AddDCTImage(AName); + if not FileExistsUTF8(AName) then Exit; + imgloaded:=False; + ms:=TMemoryStreamUTF8.Create; + try + ms.LoadFromFile(AName); + imgext:=LowerCase(DetermineStreamFormat(ms)); + + if imgext<> '' then begin + InitImage(img); + try + if LoadImageFromStream(ms,img) then begin + imgc:=GetImageFormat(img); + imgwidth:=img.Width; + imgheight:=img.Height; + if (imgext<>'jpg') and (imgext<>'jpeg') then begin + ms.Clear; + if FCompressionQuality<100 then begin + //DCTDecode + //convert to jpg for non jpg + defaultjpeg:=Imaging.GetOption(ImagingJpegQuality); + try + Imaging.SetOption(ImagingJpegQuality,FCompressionQuality); + imgloaded:=SaveImageToStream('jpg',ms,img); + imgext:='jpg'; + finally + Imaging.SetOption(ImagingJpegQuality,defaultjpeg); + end; + end + else begin + //FlateDecode + if imgc='DeviceRGB' then + try + SwapChannels(img,ChannelRed,ChannelBlue); + except + end; + with Tcompressionstream.create(clmax,ms) do + try + write(img.Bits^,img.Size); + imgloaded:=True; + finally + Free; + end; + end; + end + else + imgloaded:=True; + end; + finally + FreeImage(img); + end; + + if imgloaded then begin + try + BeginPDFPage(imgwidth,imgheight); + with FPageInfos[FCurrentPage] do begin + if (imgext='jpg') or (imgext='jpeg') then + f:='DCTDecode' + else + f:='FlateDecode'; + imgStream:=ms; + bpc:=8; + cs:=imgc; + fWidth:=imgwidth; + fHeight:=imgheight; + PDFWrite(Format('q %d 0 0 %d 0 -%d cm /I%d Do Q',[imgwidth,imgheight,imgheight,FCurrentPage])); + end + finally + EndPDFPage; + end; + end; + end; + except + on E :Exception do begin + WriteLog_E('TImg2Pdf.AddFlateImage.Error, '+E.Message); + SimpleException.ExceptionHandleSaveLogOnly(Self, E); + end; + end; + if (imgloaded=False) and Assigned(ms) then + FreeAndNil(ms); end; procedure TImg2Pdf.SaveToStream(const AStream: TStream); @@ -479,3 +451,4 @@ procedure TImg2Pdf.SaveToFile(const AFile: String); end. + From 9fa0890285c6afd20b5dab29bbb726cf52c560c0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 26 Jan 2016 14:04:10 +0800 Subject: [PATCH 0880/2794] upacker, clean up and fix --- baseunits/uPacker.pas | 66 +++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index d5774b684..73bd305b4 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -110,46 +110,52 @@ procedure TPacker.DoPdf; fstream: TFileStreamUTF8; begin try - // Path:= FixPath(Path); fPath := Trim(Path); RenameFileUTF8(Path, fPath); list := TStringList.Create; searcher := TFileSearcher.Create; - searcher.OnFileFound := OnFileFound; - searcher.Search(fPath, '*.jpg;*.jpeg;*.png;*.gif', False, False); + try + searcher.OnFileFound := OnFileFound; + searcher.Search(fPath, '*.jpg;*.jpeg;*.png;*.gif', False, False); - if list.Count <> 0 then - begin - pdf := TImg2Pdf.Create; - pdf.CompressionQuality := CompressionQuality; - pdf.Title := GetLastDir(Path); - // pdf.FileName:= fPath+ext; - for i := 0 to list.Count - 1 do + if list.Count <> 0 then begin - s := list[i]; - {$IFDEF WINDOWS} - s := StringReplace(s, '/', '\', [rfReplaceAll]); - {$ENDIF} - // add image to PDF + pdf := TImg2Pdf.Create; try - pdf.AddImage(s); - except + pdf.CompressionQuality := CompressionQuality; + pdf.Title := GetLastDir(Path); + // pdf.FileName:= fPath+ext; + for i := 0 to list.Count - 1 do + begin + s := list[i]; + {$IFDEF WINDOWS} + s := StringReplace(s, '/', '\', [rfReplaceAll]); + {$ENDIF} + // add image to PDF + try + pdf.AddImage(s); + except + end; + end; + + fstream := TFileStreamUTF8.Create(fPath + ext, fmCreate); + try + pdf.SaveToStream(fstream); + finally + fstream.Free; + end; + + finally + pdf.Free; end; + if DeleteDirectory(fPath, False) then + RemoveDirUTF8(fPath); + RenameFileUTF8(fPath + ext, Path + ext); end; - - fstream := TFileStreamUTF8.Create(fPath + ext, fmCreate); - pdf.SaveToStream(fstream); - fstream.Free; - pdf.Free; - //searcher.Search(fPath, '*.db', False, False); - //for i := 0 to list.Count - 1 do - // DeleteFileUTF8(list.Strings[i]); - if DeleteDirectory(fPath, False) then - RemoveDirUTF8(fPath); - RenameFileUTF8(fPath + ext, Path + ext); + finally + searcher.Free; + list.Free; end; - searcher.Free; - list.Free; except on E: Exception do begin From 6fb3bb0999aa978969e82b4ba12ac28d644491a2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 26 Jan 2016 23:03:27 +0800 Subject: [PATCH 0881/2794] img2pdf, convert indexed to rgb temporary workaround --- baseunits/uImg2Pdf.pas | 69 ++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/baseunits/uImg2Pdf.pas b/baseunits/uImg2Pdf.pas index 6d4ad4d43..4052b4fe4 100644 --- a/baseunits/uImg2Pdf.pas +++ b/baseunits/uImg2Pdf.pas @@ -44,10 +44,12 @@ interface type TPageInfo = record - fWidth, fHeight: Single; - imgStream : TMemoryStreamUTF8; - bpc : Byte; - cs, f : String; + Width, + Height: Single; + BitsPerComponent: Byte; + ColorSpace, + Filter: String; + Stream: TMemoryStreamUTF8; end; { TImg2Pdf } @@ -118,7 +120,7 @@ procedure TImg2Pdf.EndPDF; PDFWrite('<</Type /Page'); PDFWrite('/Parent 1 0 R'); - PDFWrite('/MediaBox [0 0 ' + FloatToStr(FPageInfos[i].fWidth) + ' ' + FloatToStr(FPageInfos[i].fHeight) + ']'); + PDFWrite('/MediaBox [0 0 ' + FloatToStr(FPageInfos[i].Width) + ' ' + FloatToStr(FPageInfos[i].Height) + ']'); PDFWrite('/Resources 2 0 R'); PDFWrite('/Contents ' + IntToStr(QWord(FObjCount) + 1) + ' 0 R>>'); PDFWrite('endobj'); @@ -137,15 +139,15 @@ procedure TImg2Pdf.EndPDF; CreateNewObj; PDFWrite('<</Type /XObject'); PDFWrite('/Subtype /Image'); - PDFWrite('/Width ' + FloatToStr(FPageInfos[i].fWidth)); - PDFWrite('/Height ' + FloatToStr(FPageInfos[i].fHeight)); - PDFWrite('/ColorSpace /' + FPageInfos[i].cs); - PDFWrite('/BitsPerComponent ' + IntToStr(FPageInfos[i].bpc)); - PDFWrite('/Filter /' + FPageInfos[i].f); - PDFWrite('/Length ' + IntToStr(FPageInfos[i].imgStream.Size) + '>>'); + PDFWrite('/Width ' + FloatToStr(FPageInfos[i].Width)); + PDFWrite('/Height ' + FloatToStr(FPageInfos[i].Height)); + PDFWrite('/ColorSpace [ /' + FPageInfos[i].ColorSpace + ' ]'); + PDFWrite('/BitsPerComponent ' + IntToStr(FPageInfos[i].BitsPerComponent)); + PDFWrite('/Filter /' + FPageInfos[i].Filter); + PDFWrite('/Length ' + IntToStr(FPageInfos[i].Stream.Size) + '>>'); PDFWrite('stream'); - FPageInfos[i].imgStream.Position := 0; - FBuffer.CopyFrom(FPageInfos[i].imgStream, FPageInfos[i].imgStream.Size); + FPageInfos[i].Stream.Position := 0; + FBuffer.CopyFrom(FPageInfos[i].Stream, FPageInfos[i].Stream.Size); PDFWrite(#10 + 'endstream'); PDFWrite('endobj'); end; @@ -173,7 +175,7 @@ procedure TImg2Pdf.EndPDF; begin PDFWrite('/I' + IntToStr(i) + ' ' + IntToStr(vni + (i) + vnbpal) + ' 0 R'); - if (FPageInfos[i].cs = 'Indexed') then + if (FPageInfos[i].ColorSpace = 'Indexed') then vnbpal:= vnbpal + 1; end; PDFWrite('>>'); @@ -279,7 +281,7 @@ destructor TImg2Pdf.Destroy; begin if FCurrentPage > 0 then for i:= 1 to FCurrentPage do - FPageInfos[i].imgStream.Free; + FPageInfos[i].Stream.Free; SetLength(FPageInfos, 0); SetLength(FOffsets, 0); SetLength(FPages, 0); @@ -290,6 +292,8 @@ destructor TImg2Pdf.Destroy; function TImg2Pdf.GetImageFormat(imData: TImageData): string; begin case imData.Format of + ifIndex8: Result := 'Indexed'; + ifGray8, ifA8Gray8, ifGray16, @@ -297,9 +301,6 @@ function TImg2Pdf.GetImageFormat(imData: TImageData): string; ifGray64, ifA16Gray16: Result := 'DeviceGray'; - ifUnknown, - ifDefault, - ifIndex8, ifX5R1G1B1, ifR3G3B2, ifR5G6B5, @@ -365,18 +366,22 @@ procedure TImg2Pdf.AddImage(const AName: String); end else begin //FlateDecode + if imgc='Indexed' then begin + ConvertImage(img,ifR8G8B8); + imgc:='DeviceRGB'; + end; if imgc='DeviceRGB' then try SwapChannels(img,ChannelRed,ChannelBlue); except end; - with Tcompressionstream.create(clmax,ms) do - try - write(img.Bits^,img.Size); - imgloaded:=True; - finally - Free; - end; + with Tcompressionstream.create(clmax,ms) do + try + write(img.Bits^,img.Size); + imgloaded:=True; + finally + Free; + end; end; end else @@ -391,14 +396,14 @@ procedure TImg2Pdf.AddImage(const AName: String); BeginPDFPage(imgwidth,imgheight); with FPageInfos[FCurrentPage] do begin if (imgext='jpg') or (imgext='jpeg') then - f:='DCTDecode' + Filter:='DCTDecode' else - f:='FlateDecode'; - imgStream:=ms; - bpc:=8; - cs:=imgc; - fWidth:=imgwidth; - fHeight:=imgheight; + Filter:='FlateDecode'; + Stream:=ms; + BitsPerComponent:=8; + ColorSpace:=imgc; + Width:=imgwidth; + Height:=imgheight; PDFWrite(Format('q %d 0 0 %d 0 -%d cm /I%d Do Q',[imgwidth,imgheight,imgheight,FCurrentPage])); end finally From 403dc204d1d1e067328d6391dcd69663202f26a7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jan 2016 00:54:07 +0800 Subject: [PATCH 0882/2794] img2pdf, fix handle indexed image fix #170 --- baseunits/uImg2Pdf.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/uImg2Pdf.pas b/baseunits/uImg2Pdf.pas index 4052b4fe4..feaee49e7 100644 --- a/baseunits/uImg2Pdf.pas +++ b/baseunits/uImg2Pdf.pas @@ -141,7 +141,7 @@ procedure TImg2Pdf.EndPDF; PDFWrite('/Subtype /Image'); PDFWrite('/Width ' + FloatToStr(FPageInfos[i].Width)); PDFWrite('/Height ' + FloatToStr(FPageInfos[i].Height)); - PDFWrite('/ColorSpace [ /' + FPageInfos[i].ColorSpace + ' ]'); + PDFWrite('/ColorSpace [/' + FPageInfos[i].ColorSpace + ']'); PDFWrite('/BitsPerComponent ' + IntToStr(FPageInfos[i].BitsPerComponent)); PDFWrite('/Filter /' + FPageInfos[i].Filter); PDFWrite('/Length ' + IntToStr(FPageInfos[i].Stream.Size) + '>>'); @@ -335,6 +335,8 @@ procedure TImg2Pdf.AddImage(const AName: String); imgloaded: Boolean; imgext,imgc: String; imgwidth,imgheight,defaultjpeg: LongInt; + i: Integer; + imginfo: TImageFormatInfo; begin if not FileExistsUTF8(AName) then Exit; imgloaded:=False; @@ -366,9 +368,13 @@ procedure TImg2Pdf.AddImage(const AName: String); end else begin //FlateDecode - if imgc='Indexed' then begin - ConvertImage(img,ifR8G8B8); - imgc:='DeviceRGB'; + GetImageFormatInfo(img.Format,imginfo); + if (imginfo.IsIndexed) and (imginfo.PaletteEntries>0) then begin + imgc:='Indexed /DeviceRGB '+IntToStr(imginfo.PaletteEntries)+' <'; + for i:=0 to imginfo.PaletteEntries-1 do + with img.Palette^[i] do + imgc+=IntToHex(R,2)+IntToHex(G,2)+IntToHex(B,2); + imgc+='>'; end; if imgc='DeviceRGB' then try From 0c49df3e2f6dfd624151e1a54d3e39df3bb9b411 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jan 2016 01:09:58 +0800 Subject: [PATCH 0883/2794] img2pdf, palettes index count from 0 --- baseunits/uImg2Pdf.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uImg2Pdf.pas b/baseunits/uImg2Pdf.pas index feaee49e7..848d523bf 100644 --- a/baseunits/uImg2Pdf.pas +++ b/baseunits/uImg2Pdf.pas @@ -370,7 +370,7 @@ procedure TImg2Pdf.AddImage(const AName: String); //FlateDecode GetImageFormatInfo(img.Format,imginfo); if (imginfo.IsIndexed) and (imginfo.PaletteEntries>0) then begin - imgc:='Indexed /DeviceRGB '+IntToStr(imginfo.PaletteEntries)+' <'; + imgc:='Indexed /DeviceRGB '+IntToStr(imginfo.PaletteEntries-1)+' <'; for i:=0 to imginfo.PaletteEntries-1 do with img.Palette^[i] do imgc+=IntToHex(R,2)+IntToHex(G,2)+IntToHex(B,2); From 58572d04844028558ad590b696d08ee8f7da090a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jan 2016 19:42:27 +0800 Subject: [PATCH 0884/2794] cleanup project, remove all library with package file --- .../Extras/Extensions/ElderImagery.pas | 657 --- .../Extras/Extensions/ElderImageryBsi.pas | 409 -- .../Extras/Extensions/ElderImageryCif.pas | 289 -- .../Extras/Extensions/ElderImageryImg.pas | 226 - .../Extras/Extensions/ElderImagerySky.pas | 141 - .../Extras/Extensions/ElderImageryTexture.pas | 390 -- .../Extras/Extensions/ImagingBinary.pas | 457 -- .../Extras/Extensions/ImagingCompare.pas | 131 - .../Extras/Extensions/ImagingDirect3D9.pas | 784 --- .../Extras/Extensions/ImagingExtras.pas | 153 - 3rd/Imaging/Extras/Extensions/ImagingFmx.pas | 353 -- .../Extras/Extensions/ImagingGraphics32.pas | 256 - .../Extras/Extensions/ImagingJpeg2000.pas | 628 --- .../Extras/Extensions/ImagingJpegIJL.pas | 447 -- .../Extensions/ImagingLibTiffDelphi.pas | 605 --- .../Extras/Extensions/ImagingOpenGL.pas | 955 ---- 3rd/Imaging/Extras/Extensions/ImagingPcx.pas | 375 -- 3rd/Imaging/Extras/Extensions/ImagingPsd.pas | 801 --- 3rd/Imaging/Extras/Extensions/ImagingSDL.pas | 393 -- .../Extras/Extensions/ImagingSquishLib.pas | 170 - 3rd/Imaging/Extras/Extensions/ImagingXpm.pas | 582 --- .../Extras/Extensions/J2KObjects/bio.obj | Bin 3381 -> 0 bytes .../Extras/Extensions/J2KObjects/cio.obj | Bin 3680 -> 0 bytes .../Extras/Extensions/J2KObjects/dwt.obj | Bin 9849 -> 0 bytes .../Extras/Extensions/J2KObjects/event.obj | Bin 3114 -> 0 bytes .../Extras/Extensions/J2KObjects/image.obj | Bin 3230 -> 0 bytes .../Extras/Extensions/J2KObjects/j2k.obj | Bin 20915 -> 0 bytes .../Extras/Extensions/J2KObjects/j2k_lib.obj | Bin 7884 -> 0 bytes .../Extras/Extensions/J2KObjects/jp2.obj | Bin 9136 -> 0 bytes .../Extras/Extensions/J2KObjects/jpt.obj | Bin 3245 -> 0 bytes .../Extras/Extensions/J2KObjects/libcrtdll.a | Bin 357874 -> 0 bytes .../Extensions/J2KObjects/libopenjpeglinx86.a | Bin 142232 -> 0 bytes .../J2KObjects/libopenjpeglinx86_64.a | Bin 180386 -> 0 bytes .../Extensions/J2KObjects/libopenjpegosxx86.a | Bin 165176 -> 0 bytes .../Extensions/J2KObjects/libopenjpegwin32.a | Bin 122284 -> 0 bytes .../Extras/Extensions/J2KObjects/mct.obj | Bin 3522 -> 0 bytes .../Extras/Extensions/J2KObjects/mqc.obj | Bin 6951 -> 0 bytes .../Extras/Extensions/J2KObjects/openjpeg.obj | Bin 10117 -> 0 bytes .../Extras/Extensions/J2KObjects/pi.obj | Bin 12125 -> 0 bytes .../Extras/Extensions/J2KObjects/raw.obj | Bin 2889 -> 0 bytes .../Extras/Extensions/J2KObjects/t1.obj | Bin 13137 -> 0 bytes .../Extras/Extensions/J2KObjects/t2.obj | Bin 8834 -> 0 bytes .../Extras/Extensions/J2KObjects/tcd.obj | Bin 22667 -> 0 bytes .../Extras/Extensions/J2KObjects/tgt.obj | Bin 3615 -> 0 bytes .../Extensions/LibTiff/Compiled/adler32.obj | Bin 726 -> 0 bytes .../Extensions/LibTiff/Compiled/compress.obj | Bin 763 -> 0 bytes .../Extensions/LibTiff/Compiled/crc32.obj | Bin 11970 -> 0 bytes .../Extensions/LibTiff/Compiled/deflate.obj | Bin 8912 -> 0 bytes .../Extensions/LibTiff/Compiled/inffast.obj | Bin 2709 -> 0 bytes .../Extensions/LibTiff/Compiled/inflate.obj | Bin 11402 -> 0 bytes .../Extensions/LibTiff/Compiled/inftrees.obj | Bin 2737 -> 0 bytes .../Extensions/LibTiff/Compiled/jcapimin.obj | Bin 2721 -> 0 bytes .../Extensions/LibTiff/Compiled/jcapistd.obj | Bin 2133 -> 0 bytes .../Extensions/LibTiff/Compiled/jccoefct.obj | Bin 3615 -> 0 bytes .../Extensions/LibTiff/Compiled/jccolor.obj | Bin 3330 -> 0 bytes .../Extensions/LibTiff/Compiled/jcdctmgr.obj | Bin 3337 -> 0 bytes .../Extensions/LibTiff/Compiled/jchuff.obj | Bin 5176 -> 0 bytes .../Extensions/LibTiff/Compiled/jcinit.obj | Bin 1970 -> 0 bytes .../Extensions/LibTiff/Compiled/jcmainct.obj | Bin 1885 -> 0 bytes .../Extensions/LibTiff/Compiled/jcmarker.obj | Bin 4002 -> 0 bytes .../Extensions/LibTiff/Compiled/jcmaster.obj | Bin 4593 -> 0 bytes .../Extensions/LibTiff/Compiled/jcomapi.obj | Bin 1758 -> 0 bytes .../Extensions/LibTiff/Compiled/jcparam.obj | Bin 5494 -> 0 bytes .../Extensions/LibTiff/Compiled/jcphuff.obj | Bin 4664 -> 0 bytes .../Extensions/LibTiff/Compiled/jcprepct.obj | Bin 2957 -> 0 bytes .../Extensions/LibTiff/Compiled/jcsample.obj | Bin 3998 -> 0 bytes .../Extensions/LibTiff/Compiled/jctrans.obj | Bin 3432 -> 0 bytes .../Extensions/LibTiff/Compiled/jdapimin.obj | Bin 3230 -> 0 bytes .../Extensions/LibTiff/Compiled/jdapistd.obj | Bin 2606 -> 0 bytes .../Extensions/LibTiff/Compiled/jdatadst.obj | Bin 1786 -> 0 bytes .../Extensions/LibTiff/Compiled/jdatasrc.obj | Bin 1806 -> 0 bytes .../Extensions/LibTiff/Compiled/jdcoefct.obj | Bin 5655 -> 0 bytes .../Extensions/LibTiff/Compiled/jdcolor.obj | Bin 3065 -> 0 bytes .../Extensions/LibTiff/Compiled/jddctmgr.obj | Bin 2645 -> 0 bytes .../Extensions/LibTiff/Compiled/jdhuff.obj | Bin 4839 -> 0 bytes .../Extensions/LibTiff/Compiled/jdinput.obj | Bin 3084 -> 0 bytes .../Extensions/LibTiff/Compiled/jdmainct.obj | Bin 3280 -> 0 bytes .../Extensions/LibTiff/Compiled/jdmarker.obj | Bin 9817 -> 0 bytes .../Extensions/LibTiff/Compiled/jdmaster.obj | Bin 3924 -> 0 bytes .../Extensions/LibTiff/Compiled/jdmerge.obj | Bin 3088 -> 0 bytes .../Extensions/LibTiff/Compiled/jdphuff.obj | Bin 5335 -> 0 bytes .../Extensions/LibTiff/Compiled/jdpostct.obj | Bin 2329 -> 0 bytes .../Extensions/LibTiff/Compiled/jdsample.obj | Bin 3392 -> 0 bytes .../Extensions/LibTiff/Compiled/jdtrans.obj | Bin 1976 -> 0 bytes .../Extensions/LibTiff/Compiled/jerror.obj | Bin 7729 -> 0 bytes .../Extensions/LibTiff/Compiled/jfdctflt.obj | Bin 2306 -> 0 bytes .../Extensions/LibTiff/Compiled/jfdctfst.obj | Bin 2216 -> 0 bytes .../Extensions/LibTiff/Compiled/jfdctint.obj | Bin 2527 -> 0 bytes .../Extensions/LibTiff/Compiled/jidctflt.obj | Bin 2770 -> 0 bytes .../Extensions/LibTiff/Compiled/jidctfst.obj | Bin 2699 -> 0 bytes .../Extensions/LibTiff/Compiled/jidctint.obj | Bin 3151 -> 0 bytes .../Extensions/LibTiff/Compiled/jidctred.obj | Bin 3159 -> 0 bytes .../Extensions/LibTiff/Compiled/jmemmgr.obj | Bin 5150 -> 0 bytes .../Extensions/LibTiff/Compiled/jmemnobs.obj | Bin 1900 -> 0 bytes .../Extensions/LibTiff/Compiled/jquant1.obj | Bin 5131 -> 0 bytes .../Extensions/LibTiff/Compiled/jquant2.obj | Bin 6662 -> 0 bytes .../Extensions/LibTiff/Compiled/jutils.obj | Bin 2162 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_aux.obj | Bin 3844 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_close.obj | Bin 1700 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_codec.obj | Bin 2396 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_color.obj | Bin 4056 -> 0 bytes .../LibTiff/Compiled/tif_compress.obj | Bin 3597 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_dir.obj | Bin 13015 -> 0 bytes .../LibTiff/Compiled/tif_dirinfo.obj | Bin 13115 -> 0 bytes .../LibTiff/Compiled/tif_dirread.obj | Bin 17601 -> 0 bytes .../LibTiff/Compiled/tif_dirwrite.obj | Bin 11692 -> 0 bytes .../LibTiff/Compiled/tif_dumpmode.obj | Bin 1803 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_error.obj | Bin 1640 -> 0 bytes .../LibTiff/Compiled/tif_extension.obj | Bin 1730 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_fax3.obj | Bin 23904 -> 0 bytes .../LibTiff/Compiled/tif_fax3sm.obj | Bin 100394 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_flush.obj | Bin 1468 -> 0 bytes .../LibTiff/Compiled/tif_getimage.obj | Bin 35495 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_jpeg.obj | Bin 13364 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_luv.obj | Bin 15799 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_lzw.obj | Bin 7571 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_next.obj | Bin 1877 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_ojpeg.obj | Bin 1257 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_open.obj | Bin 4558 -> 0 bytes .../LibTiff/Compiled/tif_packbits.obj | Bin 2935 -> 0 bytes .../LibTiff/Compiled/tif_pixarlog.obj | Bin 15694 -> 0 bytes .../LibTiff/Compiled/tif_predict.obj | Bin 6382 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_print.obj | Bin 9579 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_read.obj | Bin 6820 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_strip.obj | Bin 4135 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_swab.obj | Bin 2463 -> 0 bytes .../LibTiff/Compiled/tif_thunder.obj | Bin 2100 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_tile.obj | Bin 3520 -> 0 bytes .../LibTiff/Compiled/tif_version.obj | Bin 1414 -> 0 bytes .../LibTiff/Compiled/tif_warning.obj | Bin 1658 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_write.obj | Bin 6475 -> 0 bytes .../Extensions/LibTiff/Compiled/tif_zip.obj | Bin 3748 -> 0 bytes .../Extensions/LibTiff/Compiled/trees.obj | Bin 12422 -> 0 bytes .../Extensions/LibTiff/Compiled/uncompr.obj | Bin 681 -> 0 bytes .../Extensions/LibTiff/Compiled/zutil.obj | Bin 1784 -> 0 bytes .../Extras/Extensions/LibTiff/LibDelphi.pas | 371 -- .../Extensions/LibTiff/LibJpegDelphi.pas | 521 -- .../Extensions/LibTiff/LibTiffDelphi.pas | 1602 ------ .../Extras/Extensions/LibTiff/ZLibDelphi.pas | 80 - 3rd/Imaging/Extras/Extensions/OpenJpeg.pas | 740 --- 3rd/Imaging/Source/Imaging.pas | 4253 ---------------- 3rd/Imaging/Source/ImagingBitmap.pas | 856 ---- 3rd/Imaging/Source/ImagingCanvases.pas | 2111 -------- 3rd/Imaging/Source/ImagingClasses.pas | 1092 ---- 3rd/Imaging/Source/ImagingColors.pas | 246 - 3rd/Imaging/Source/ImagingComponents.pas | 1297 ----- 3rd/Imaging/Source/ImagingDds.pas | 1145 ----- 3rd/Imaging/Source/ImagingFormats.pas | 4411 ----------------- 3rd/Imaging/Source/ImagingGif.pas | 1291 ----- 3rd/Imaging/Source/ImagingIO.pas | 647 --- 3rd/Imaging/Source/ImagingJpeg.pas | 769 --- 3rd/Imaging/Source/ImagingNetworkGraphics.pas | 2695 ---------- 3rd/Imaging/Source/ImagingOptions.inc | 214 - 3rd/Imaging/Source/ImagingPortableMaps.pas | 977 ---- 3rd/Imaging/Source/ImagingRadiance.pas | 497 -- 3rd/Imaging/Source/ImagingTarga.pas | 620 --- 3rd/Imaging/Source/ImagingTypes.pas | 567 --- 3rd/Imaging/Source/ImagingUtility.pas | 1693 ------- 3rd/Imaging/Source/JpegLib/imjcapimin.pas | 401 -- 3rd/Imaging/Source/JpegLib/imjcapistd.pas | 222 - 3rd/Imaging/Source/JpegLib/imjccoefct.pas | 521 -- 3rd/Imaging/Source/JpegLib/imjccolor.pas | 530 -- 3rd/Imaging/Source/JpegLib/imjcdctmgr.pas | 514 -- 3rd/Imaging/Source/JpegLib/imjchuff.pas | 1116 ----- 3rd/Imaging/Source/JpegLib/imjcinit.pas | 95 - 3rd/Imaging/Source/JpegLib/imjcmainct.pas | 343 -- 3rd/Imaging/Source/JpegLib/imjcmarker.pas | 724 --- 3rd/Imaging/Source/JpegLib/imjcmaster.pas | 701 --- 3rd/Imaging/Source/JpegLib/imjcomapi.pas | 130 - 3rd/Imaging/Source/JpegLib/imjconfig.inc | 126 - 3rd/Imaging/Source/JpegLib/imjcparam.pas | 701 --- 3rd/Imaging/Source/JpegLib/imjcphuff.pas | 962 ---- 3rd/Imaging/Source/JpegLib/imjcprepct.pas | 406 -- 3rd/Imaging/Source/JpegLib/imjcsample.pas | 631 --- 3rd/Imaging/Source/JpegLib/imjdapimin.pas | 505 -- 3rd/Imaging/Source/JpegLib/imjdapistd.pas | 377 -- 3rd/Imaging/Source/JpegLib/imjdcoefct.pas | 895 ---- 3rd/Imaging/Source/JpegLib/imjdcolor.pas | 501 -- 3rd/Imaging/Source/JpegLib/imjdct.pas | 109 - 3rd/Imaging/Source/JpegLib/imjddctmgr.pas | 330 -- 3rd/Imaging/Source/JpegLib/imjdeferr.pas | 497 -- 3rd/Imaging/Source/JpegLib/imjdhuff.pas | 1205 ----- 3rd/Imaging/Source/JpegLib/imjdinput.pas | 416 -- 3rd/Imaging/Source/JpegLib/imjdmainct.pas | 610 --- 3rd/Imaging/Source/JpegLib/imjdmarker.pas | 2648 ---------- 3rd/Imaging/Source/JpegLib/imjdmaster.pas | 679 --- 3rd/Imaging/Source/JpegLib/imjdmerge.pas | 514 -- 3rd/Imaging/Source/JpegLib/imjdphuff.pas | 1065 ---- 3rd/Imaging/Source/JpegLib/imjdpostct.pas | 341 -- 3rd/Imaging/Source/JpegLib/imjdsample.pas | 592 --- 3rd/Imaging/Source/JpegLib/imjerror.pas | 462 -- 3rd/Imaging/Source/JpegLib/imjfdctflt.pas | 176 - 3rd/Imaging/Source/JpegLib/imjfdctfst.pas | 237 - 3rd/Imaging/Source/JpegLib/imjfdctint.pas | 297 -- 3rd/Imaging/Source/JpegLib/imjidctasm.pas | 793 --- 3rd/Imaging/Source/JpegLib/imjidctflt.pas | 286 -- 3rd/Imaging/Source/JpegLib/imjidctfst.pas | 410 -- 3rd/Imaging/Source/JpegLib/imjidctint.pas | 440 -- 3rd/Imaging/Source/JpegLib/imjidctred.pas | 525 -- 3rd/Imaging/Source/JpegLib/imjinclude.pas | 126 - 3rd/Imaging/Source/JpegLib/imjmemmgr.pas | 1283 ----- 3rd/Imaging/Source/JpegLib/imjmemnobs.pas | 259 - 3rd/Imaging/Source/JpegLib/imjmorecfg.pas | 219 - 3rd/Imaging/Source/JpegLib/imjpeglib.pas | 1300 ----- 3rd/Imaging/Source/JpegLib/imjquant1.pas | 1009 ---- 3rd/Imaging/Source/JpegLib/imjquant2.pas | 1551 ------ 3rd/Imaging/Source/JpegLib/imjutils.pas | 232 - 3rd/Imaging/Source/JpegLib/readme.txt | 381 -- 3rd/Imaging/Source/ZLib/dzlib.pas | 523 -- 3rd/Imaging/Source/ZLib/imadler.pas | 114 - 3rd/Imaging/Source/ZLib/iminfblock.pas | 951 ---- 3rd/Imaging/Source/ZLib/iminfcodes.pas | 576 --- 3rd/Imaging/Source/ZLib/iminffast.pas | 318 -- 3rd/Imaging/Source/ZLib/iminftrees.pas | 781 --- 3rd/Imaging/Source/ZLib/iminfutil.pas | 222 - 3rd/Imaging/Source/ZLib/impaszlib.pas | 520 -- 3rd/Imaging/Source/ZLib/imtrees.pas | 2249 --------- 3rd/Imaging/Source/ZLib/imzconf.inc | 25 - 3rd/Imaging/Source/ZLib/imzdeflate.pas | 2129 -------- 3rd/Imaging/Source/ZLib/imzinflate.pas | 750 --- 3rd/Imaging/Source/ZLib/imzutil.pas | 191 - 3rd/Imaging/Source/ZLib/readme.txt | 129 - 3rd/synapse/README.txt | 45 - 3rd/synapse/Release.txt | 2 - 3rd/synapse/licence.txt | 28 - 3rd/synapse/source/asn1util.pas | 520 -- 3rd/synapse/source/blcksock.pas | 4354 ---------------- 3rd/synapse/source/clamsend.pas | 277 -- 3rd/synapse/source/dnssend.pas | 603 --- 3rd/synapse/source/ftpsend.pas | 1964 -------- 3rd/synapse/source/ftptsend.pas | 403 -- 3rd/synapse/source/httpsend.pas | 848 ---- 3rd/synapse/source/imapsend.pas | 869 ---- 3rd/synapse/source/jedi.inc | 1430 ------ 3rd/synapse/source/kylix.inc | 30 - 3rd/synapse/source/laz_synapse.lpk | 167 - 3rd/synapse/source/laz_synapse.pas | 18 - 3rd/synapse/source/ldapsend.pas | 1261 ----- 3rd/synapse/source/mimeinln.pas | 263 - 3rd/synapse/source/mimemess.pas | 851 ---- 3rd/synapse/source/mimepart.pas | 1227 ----- 3rd/synapse/source/nntpsend.pas | 483 -- 3rd/synapse/source/pingsend.pas | 720 --- 3rd/synapse/source/pop3send.pas | 483 -- 3rd/synapse/source/slogsend.pas | 320 -- 3rd/synapse/source/smtpsend.pas | 724 --- 3rd/synapse/source/snmpsend.pas | 1266 ----- 3rd/synapse/source/sntpsend.pas | 374 -- 3rd/synapse/source/ssdotnet.inc | 1099 ---- 3rd/synapse/source/ssfpc.inc | 925 ---- 3rd/synapse/source/ssl_cryptlib.pas | 677 --- 3rd/synapse/source/ssl_libssh2.pas | 251 - 3rd/synapse/source/ssl_openssl.pas | 922 ---- 3rd/synapse/source/ssl_openssl_lib.pas | 2160 -------- 3rd/synapse/source/ssl_sbb.pas | 697 --- 3rd/synapse/source/ssl_streamsec.pas | 539 -- 3rd/synapse/source/sslinux.inc | 1313 ----- 3rd/synapse/source/ssos2ws1.inc | 1843 ------- 3rd/synapse/source/ssposix.inc | 1144 ----- 3rd/synapse/source/sswin32.inc | 1622 ------ 3rd/synapse/source/synachar.pas | 2038 -------- 3rd/synapse/source/synacode.pas | 1467 ------ 3rd/synapse/source/synacrypt.pas | 2412 --------- 3rd/synapse/source/synadbg.pas | 156 - 3rd/synapse/source/synafpc.pas | 148 - 3rd/synapse/source/synaicnv.pas | 368 -- 3rd/synapse/source/synaip.pas | 422 -- 3rd/synapse/source/synamisc.pas | 408 -- 3rd/synapse/source/synaser.pas | 2336 --------- 3rd/synapse/source/synautil.pas | 2124 -------- 3rd/synapse/source/synsock.pas | 86 - 3rd/synapse/source/tlntsend.pas | 364 -- 3rd/synapse/source/tzutil.pas | 702 --- mangadownloader/md.lpi | 43 +- mangadownloader/md.lpr | 4 +- 275 files changed, 24 insertions(+), 122544 deletions(-) delete mode 100644 3rd/Imaging/Extras/Extensions/ElderImagery.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ElderImageryBsi.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ElderImageryCif.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ElderImageryImg.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ElderImagerySky.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ElderImageryTexture.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingBinary.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingCompare.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingDirect3D9.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingExtras.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingFmx.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingGraphics32.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingJpeg2000.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingJpegIJL.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingLibTiffDelphi.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingOpenGL.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingPcx.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingPsd.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingSDL.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingSquishLib.pas delete mode 100644 3rd/Imaging/Extras/Extensions/ImagingXpm.pas delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/bio.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/cio.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/dwt.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/event.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/image.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/j2k.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/j2k_lib.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/jp2.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/jpt.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/libcrtdll.a delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpeglinx86.a delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpeglinx86_64.a delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpegosxx86.a delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpegwin32.a delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/mct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/mqc.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/openjpeg.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/pi.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/raw.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/t1.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/t2.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/tcd.obj delete mode 100644 3rd/Imaging/Extras/Extensions/J2KObjects/tgt.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/adler32.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/compress.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/crc32.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/deflate.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inffast.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inflate.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inftrees.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcapimin.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcapistd.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jccoefct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jccolor.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcdctmgr.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jchuff.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcinit.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmainct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmarker.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmaster.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcomapi.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcparam.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcphuff.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcprepct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcsample.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jctrans.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdapimin.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdapistd.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdatadst.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdatasrc.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdcoefct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdcolor.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jddctmgr.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdhuff.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdinput.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmainct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmarker.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmaster.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmerge.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdphuff.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdpostct.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdsample.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdtrans.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jerror.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctflt.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctfst.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctint.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctflt.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctfst.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctint.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctred.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jmemmgr.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jmemnobs.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jquant1.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jquant2.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jutils.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_aux.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_close.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_codec.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_color.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_compress.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dir.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirinfo.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirread.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirwrite.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dumpmode.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_error.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_extension.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_fax3.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_fax3sm.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_flush.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_getimage.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_jpeg.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_luv.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_lzw.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_next.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_ojpeg.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_open.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_packbits.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_pixarlog.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_predict.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_print.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_read.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_strip.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_swab.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_thunder.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_tile.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_version.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_warning.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_write.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_zip.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/trees.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/uncompr.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/Compiled/zutil.obj delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/LibDelphi.pas delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/LibJpegDelphi.pas delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/LibTiffDelphi.pas delete mode 100644 3rd/Imaging/Extras/Extensions/LibTiff/ZLibDelphi.pas delete mode 100644 3rd/Imaging/Extras/Extensions/OpenJpeg.pas delete mode 100644 3rd/Imaging/Source/Imaging.pas delete mode 100644 3rd/Imaging/Source/ImagingBitmap.pas delete mode 100644 3rd/Imaging/Source/ImagingCanvases.pas delete mode 100644 3rd/Imaging/Source/ImagingClasses.pas delete mode 100644 3rd/Imaging/Source/ImagingColors.pas delete mode 100644 3rd/Imaging/Source/ImagingComponents.pas delete mode 100644 3rd/Imaging/Source/ImagingDds.pas delete mode 100644 3rd/Imaging/Source/ImagingFormats.pas delete mode 100644 3rd/Imaging/Source/ImagingGif.pas delete mode 100644 3rd/Imaging/Source/ImagingIO.pas delete mode 100644 3rd/Imaging/Source/ImagingJpeg.pas delete mode 100644 3rd/Imaging/Source/ImagingNetworkGraphics.pas delete mode 100644 3rd/Imaging/Source/ImagingOptions.inc delete mode 100644 3rd/Imaging/Source/ImagingPortableMaps.pas delete mode 100644 3rd/Imaging/Source/ImagingRadiance.pas delete mode 100644 3rd/Imaging/Source/ImagingTarga.pas delete mode 100644 3rd/Imaging/Source/ImagingTypes.pas delete mode 100644 3rd/Imaging/Source/ImagingUtility.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcapimin.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcapistd.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjccoefct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjccolor.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcdctmgr.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjchuff.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcinit.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcmainct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcmarker.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcmaster.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcomapi.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjconfig.inc delete mode 100644 3rd/Imaging/Source/JpegLib/imjcparam.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcphuff.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcprepct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjcsample.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdapimin.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdapistd.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdcoefct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdcolor.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjddctmgr.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdeferr.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdhuff.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdinput.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdmainct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdmarker.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdmaster.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdmerge.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdphuff.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdpostct.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjdsample.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjerror.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjfdctflt.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjfdctfst.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjfdctint.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjidctasm.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjidctflt.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjidctfst.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjidctint.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjidctred.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjinclude.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjmemmgr.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjmemnobs.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjmorecfg.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjpeglib.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjquant1.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjquant2.pas delete mode 100644 3rd/Imaging/Source/JpegLib/imjutils.pas delete mode 100644 3rd/Imaging/Source/JpegLib/readme.txt delete mode 100644 3rd/Imaging/Source/ZLib/dzlib.pas delete mode 100644 3rd/Imaging/Source/ZLib/imadler.pas delete mode 100644 3rd/Imaging/Source/ZLib/iminfblock.pas delete mode 100644 3rd/Imaging/Source/ZLib/iminfcodes.pas delete mode 100644 3rd/Imaging/Source/ZLib/iminffast.pas delete mode 100644 3rd/Imaging/Source/ZLib/iminftrees.pas delete mode 100644 3rd/Imaging/Source/ZLib/iminfutil.pas delete mode 100644 3rd/Imaging/Source/ZLib/impaszlib.pas delete mode 100644 3rd/Imaging/Source/ZLib/imtrees.pas delete mode 100644 3rd/Imaging/Source/ZLib/imzconf.inc delete mode 100644 3rd/Imaging/Source/ZLib/imzdeflate.pas delete mode 100644 3rd/Imaging/Source/ZLib/imzinflate.pas delete mode 100644 3rd/Imaging/Source/ZLib/imzutil.pas delete mode 100644 3rd/Imaging/Source/ZLib/readme.txt delete mode 100644 3rd/synapse/README.txt delete mode 100644 3rd/synapse/Release.txt delete mode 100644 3rd/synapse/licence.txt delete mode 100644 3rd/synapse/source/asn1util.pas delete mode 100644 3rd/synapse/source/blcksock.pas delete mode 100644 3rd/synapse/source/clamsend.pas delete mode 100644 3rd/synapse/source/dnssend.pas delete mode 100644 3rd/synapse/source/ftpsend.pas delete mode 100644 3rd/synapse/source/ftptsend.pas delete mode 100644 3rd/synapse/source/httpsend.pas delete mode 100644 3rd/synapse/source/imapsend.pas delete mode 100644 3rd/synapse/source/jedi.inc delete mode 100644 3rd/synapse/source/kylix.inc delete mode 100644 3rd/synapse/source/laz_synapse.lpk delete mode 100644 3rd/synapse/source/laz_synapse.pas delete mode 100644 3rd/synapse/source/ldapsend.pas delete mode 100644 3rd/synapse/source/mimeinln.pas delete mode 100644 3rd/synapse/source/mimemess.pas delete mode 100644 3rd/synapse/source/mimepart.pas delete mode 100644 3rd/synapse/source/nntpsend.pas delete mode 100644 3rd/synapse/source/pingsend.pas delete mode 100644 3rd/synapse/source/pop3send.pas delete mode 100644 3rd/synapse/source/slogsend.pas delete mode 100644 3rd/synapse/source/smtpsend.pas delete mode 100644 3rd/synapse/source/snmpsend.pas delete mode 100644 3rd/synapse/source/sntpsend.pas delete mode 100644 3rd/synapse/source/ssdotnet.inc delete mode 100644 3rd/synapse/source/ssfpc.inc delete mode 100644 3rd/synapse/source/ssl_cryptlib.pas delete mode 100644 3rd/synapse/source/ssl_libssh2.pas delete mode 100644 3rd/synapse/source/ssl_openssl.pas delete mode 100644 3rd/synapse/source/ssl_openssl_lib.pas delete mode 100644 3rd/synapse/source/ssl_sbb.pas delete mode 100644 3rd/synapse/source/ssl_streamsec.pas delete mode 100644 3rd/synapse/source/sslinux.inc delete mode 100644 3rd/synapse/source/ssos2ws1.inc delete mode 100644 3rd/synapse/source/ssposix.inc delete mode 100644 3rd/synapse/source/sswin32.inc delete mode 100644 3rd/synapse/source/synachar.pas delete mode 100644 3rd/synapse/source/synacode.pas delete mode 100644 3rd/synapse/source/synacrypt.pas delete mode 100644 3rd/synapse/source/synadbg.pas delete mode 100644 3rd/synapse/source/synafpc.pas delete mode 100644 3rd/synapse/source/synaicnv.pas delete mode 100644 3rd/synapse/source/synaip.pas delete mode 100644 3rd/synapse/source/synamisc.pas delete mode 100644 3rd/synapse/source/synaser.pas delete mode 100644 3rd/synapse/source/synautil.pas delete mode 100644 3rd/synapse/source/synsock.pas delete mode 100644 3rd/synapse/source/tlntsend.pas delete mode 100644 3rd/synapse/source/tzutil.pas diff --git a/3rd/Imaging/Extras/Extensions/ElderImagery.pas b/3rd/Imaging/Extras/Extensions/ElderImagery.pas deleted file mode 100644 index d84f792c8..000000000 --- a/3rd/Imaging/Extras/Extensions/ElderImagery.pas +++ /dev/null @@ -1,657 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This is basic unit of Elder Imagery extension for Vampyre Imaging Library. - It adds support for loading and saving of images and textures from older - Bethesda games (like TES2: Daggerfall, Redguard, Terminator: FS, TES: Arena, ...). - This unit registers all file formats declared in additional ElderImagery units - so its the only unit you need to add to uses clause of your project - for Imaging to be able to load/save these new formats using standard - loading/saving functions.} -unit ElderImagery; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging; - -type - TElderFileFormat = class; - TElderFileFormatClass = class of TElderFileFormat; - - { Used to hold information about some special images without headers.} - TNoHeaderFileInfo = record - Size: LongInt; - Width: LongInt; - Height: LongInt; - end; - - { Basic class for image formats used mainly in TES2: Daggerfall.} - TElderFileFormat = class(TImageFileFormat) - protected - FPalette: TPalette24Size256; - FARGBPalette: PPalette32; - procedure Define; override; - { Decodes RLE compressed data.} - procedure DagRLEDecode(InData: Pointer; OutSize: LongInt; out OutData: Pointer); - function FindNoHeaderInfo(Size: LongInt; Infos: array of TNoHeaderFileInfo): LongInt; - function TestNoHeaderFormat(Handle: TImagingHandle): TElderFileFormatClass; - procedure ConvertPalette(const ElderPal: TPalette24Size256; ARGBPal: PPalette32); - procedure SetPalette(const Value: TPalette24Size256); - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - function IsSupported(const Image: TImageData): Boolean; override; - public - destructor Destroy; override; - function TestFormat(Handle: TImagingHandle): Boolean; override; - { Current palette used when loading and saving images. Nearly all images - in Daggerfall use external palettes. Change this property if you want - images that don't use default palette to load correctly.} - property Palette: TPalette24Size256 read FPalette write SetPalette; - end; - - { Header of IMG and CIF files.} - TImgHeader = packed record - XOff: Word; - YOff: Word; - Width: Word; - Height: Word; - Unk: Word; // Might indicate compressed data or not - ImageSize: Word; // Size of Image data (but not always) - end; - -const - { This is default Daggerfall's palette (C:\Dagger\Arena2\pal.pal). - Every TElderFileFormat descendant loads this pal in constructor.} - DaggerfallPalette: TPalette24Size256 = ( - (B: 0; G: 0; R: 0), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 244; G: 202; R: 167), - (B: 227; G: 180; R: 144), (B: 207; G: 152; R: 118), (B: 193; G: 133; R: 100), - (B: 180; G: 113; R: 80), (B: 165; G: 100; R: 70), (B: 152; G: 93; R: 63), - (B: 140; G: 86; R: 55), (B: 129; G: 79; R: 48), (B: 122; G: 75; R: 43), - (B: 112; G: 70; R: 40), (B: 103; G: 64; R: 39), (B: 91; G: 67; R: 38), - (B: 79; G: 63; R: 43), (B: 66; G: 54; R: 41), (B: 54; G: 50; R: 40), - (B: 232; G: 196; R: 196), (B: 220; G: 177; R: 177), (B: 204; G: 157; R: 157), - (B: 188; G: 138; R: 138), (B: 175; G: 122; R: 122), (B: 155; G: 105; R: 106), - (B: 143; G: 94; R: 97), (B: 126; G: 81; R: 89), (B: 109; G: 72; R: 88), - (B: 101; G: 68; R: 85), (B: 86; G: 61; R: 77), (B: 75; G: 55; R: 71), - (B: 67; G: 51; R: 63), (B: 63; G: 47; R: 56), (B: 56; G: 45; R: 52), - (B: 46; G: 44; R: 46), (B: 245; G: 212; R: 172), (B: 229; G: 193; R: 150), - (B: 213; G: 174; R: 128), (B: 196; G: 154; R: 105), (B: 183; G: 140; R: 88), - (B: 173; G: 127; R: 78), (B: 160; G: 118; R: 74), (B: 151; G: 110; R: 69), - (B: 134; G: 103; R: 65), (B: 123; G: 92; R: 60), (B: 109; G: 85; R: 54), - (B: 96; G: 76; R: 51), (B: 83; G: 71; R: 44), (B: 69; G: 63; R: 42), - (B: 61; G: 54; R: 38), (B: 50; G: 45; R: 34), (B: 205; G: 205; R: 224), - (B: 188; G: 188; R: 199), (B: 165; G: 165; R: 174), (B: 145; G: 145; R: 159), - (B: 135; G: 135; R: 149), (B: 122; G: 122; R: 137), (B: 114; G: 114; R: 127), - (B: 103; G: 103; R: 116), (B: 94; G: 94; R: 109), (B: 85; G: 85; R: 96), - (B: 75; G: 75; R: 85), (B: 68; G: 68; R: 80), (B: 61; G: 61; R: 67), - (B: 53; G: 53; R: 59), (B: 48; G: 48; R: 50), (B: 44; G: 44; R: 45), - (B: 176; G: 205; R: 255), (B: 147; G: 185; R: 244), (B: 123; G: 164; R: 230), - (B: 104; G: 152; R: 217), (B: 87; G: 137; R: 205), (B: 68; G: 124; R: 192), - (B: 68; G: 112; R: 179), (B: 62; G: 105; R: 167), (B: 55; G: 97; R: 154), - (B: 49; G: 90; R: 142), (B: 45; G: 82; R: 122), (B: 51; G: 77; R: 102), - (B: 52; G: 69; R: 87), (B: 50; G: 62; R: 73), (B: 47; G: 59; R: 60), - (B: 44; G: 48; R: 49), (B: 220; G: 220; R: 220), (B: 197; G: 197; R: 197), - (B: 185; G: 185; R: 185), (B: 174; G: 174; R: 174), (B: 162; G: 162; R: 162), - (B: 147; G: 147; R: 147), (B: 132; G: 132; R: 132), (B: 119; G: 119; R: 119), - (B: 110; G: 110; R: 110), (B: 99; G: 99; R: 99), (B: 87; G: 87; R: 87), - (B: 78; G: 78; R: 78), (B: 67; G: 67; R: 67), (B: 58; G: 58; R: 58), - (B: 51; G: 51; R: 51), (B: 44; G: 44; R: 44), (B: 182; G: 218; R: 227), - (B: 158; G: 202; R: 202), (B: 134; G: 187; R: 187), (B: 109; G: 170; R: 170), - (B: 87; G: 154; R: 154), (B: 77; G: 142; R: 142), (B: 70; G: 135; R: 135), - (B: 62; G: 124; R: 124), (B: 54; G: 112; R: 112), (B: 46; G: 103; R: 103), - (B: 39; G: 91; R: 91), (B: 40; G: 83; R: 83), (B: 45; G: 72; R: 72), - (B: 47; G: 63; R: 63), (B: 50; G: 55; R: 55), (B: 45; G: 48; R: 48), - (B: 255; G: 246; R: 103), (B: 241; G: 238; R: 45), (B: 226; G: 220; R: 0), - (B: 212; G: 203; R: 0), (B: 197; G: 185; R: 0), (B: 183; G: 168; R: 0), - (B: 168; G: 150; R: 0), (B: 154; G: 133; R: 0), (B: 139; G: 115; R: 0), - (B: 127; G: 106; R: 4), (B: 116; G: 97; R: 7), (B: 104; G: 87; R: 11), - (B: 93; G: 78; R: 14), (B: 81; G: 69; R: 18), (B: 69; G: 60; R: 21), - (B: 58; G: 51; R: 25), (B: 202; G: 221; R: 196), (B: 175; G: 200; R: 168), - (B: 148; G: 176; R: 141), (B: 123; G: 156; R: 118), (B: 107; G: 144; R: 109), - (B: 93; G: 130; R: 94), (B: 82; G: 116; R: 86), (B: 77; G: 110; R: 78), - (B: 68; G: 99; R: 67), (B: 61; G: 89; R: 53), (B: 52; G: 77; R: 45), - (B: 46; G: 68; R: 37), (B: 39; G: 60; R: 39), (B: 30; G: 55; R: 30), - (B: 34; G: 51; R: 34), (B: 40; G: 47; R: 40), (B: 179; G: 107; R: 83), - (B: 175; G: 95; R: 75), (B: 175; G: 87; R: 67), (B: 163; G: 79; R: 59), - (B: 155; G: 75; R: 51), (B: 147; G: 71; R: 47), (B: 155; G: 91; R: 47), - (B: 139; G: 83; R: 43), (B: 127; G: 75; R: 39), (B: 115; G: 67; R: 35), - (B: 99; G: 63; R: 31), (B: 87; G: 55; R: 27), (B: 75; G: 47; R: 23), - (B: 59; G: 39; R: 19), (B: 47; G: 31; R: 15), (B: 35; G: 23; R: 11), - (B: 216; G: 227; R: 162), (B: 185; G: 205; R: 127), (B: 159; G: 183; R: 101), - (B: 130; G: 162; R: 77), (B: 109; G: 146; R: 66), (B: 101; G: 137; R: 60), - (B: 92; G: 127; R: 54), (B: 84; G: 118; R: 48), (B: 76; G: 108; R: 42), - (B: 65; G: 98; R: 37), (B: 53; G: 87; R: 34), (B: 51; G: 75; R: 35), - (B: 45; G: 64; R: 37), (B: 43; G: 56; R: 39), (B: 38; G: 51; R: 40), - (B: 43; G: 46; R: 45), (B: 179; G: 115; R: 79), (B: 175; G: 111; R: 75), - (B: 171; G: 107; R: 71), (B: 167; G: 103; R: 67), (B: 159; G: 99; R: 63), - (B: 155; G: 95; R: 59), (B: 151; G: 91; R: 55), (B: 143; G: 87; R: 51), - (B: 40; G: 40; R: 40), (B: 38; G: 38; R: 38), (B: 35; G: 35; R: 35), - (B: 31; G: 31; R: 31), (B: 27; G: 27; R: 27), (B: 23; G: 23; R: 23), - (B: 19; G: 19; R: 19), (B: 15; G: 15; R: 15), (B: 254; G: 255; R: 199), - (B: 254; G: 245; R: 185), (B: 254; G: 235; R: 170), (B: 254; G: 225; R: 156), - (B: 255; G: 215; R: 141), (B: 255; G: 205; R: 127), (B: 255; G: 195; R: 112), - (B: 255; G: 185; R: 98), (B: 255; G: 175; R: 83), (B: 241; G: 167; R: 54), - (B: 234; G: 155; R: 50), (B: 226; G: 143; R: 46), (B: 219; G: 131; R: 43), - (B: 212; G: 119; R: 39), (B: 205; G: 107; R: 35), (B: 198; G: 95; R: 31), - (B: 190; G: 84; R: 27), (B: 183; G: 72; R: 23), (B: 176; G: 60; R: 19), - (B: 169; G: 48; R: 15), (B: 162; G: 36; R: 12), (B: 154; G: 24; R: 8), - (B: 147; G: 12; R: 4), (B: 130; G: 22; R: 0), (B: 111; G: 34; R: 0), - (B: 102; G: 33; R: 1), (B: 92; G: 33; R: 3), (B: 83; G: 32; R: 10), - (B: 74; G: 39; R: 27), (B: 65; G: 41; R: 33), (B: 57; G: 43; R: 39), - (B: 48; G: 45; R: 45)); - - { This is default Redguard's palette (Redguard\fxart\Redguard.col). - It is default palette for BSI image file format.} - RedguardPalette: TPalette24Size256 = ( - (B: 0; G: 0; R: 0), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), (B: 255; G: 0; R: 255), - (B: 255; G: 0; R: 255), (B: 133; G: 196; R: 183), (B: 100; G: 181; R: 153), - (B: 66; G: 165; R: 124), (B: 33; G: 150; R: 94), (B: 31; G: 139; R: 87), - (B: 28; G: 127; R: 80), (B: 26; G: 116; R: 73), (B: 24; G: 105; R: 66), - (B: 21; G: 93; R: 59), (B: 19; G: 82; R: 52), (B: 17; G: 71; R: 45), - (B: 14; G: 59; R: 38), (B: 12; G: 48; R: 31), (B: 10; G: 37; R: 24), - (B: 7; G: 25; R: 17), (B: 5; G: 14; R: 10), (B: 230; G: 179; R: 142), - (B: 216; G: 155; R: 127), (B: 199; G: 151; R: 136), (B: 205; G: 134; R: 118), - (B: 199; G: 131; R: 103), (B: 191; G: 130; R: 108), (B: 202; G: 113; R: 95), - (B: 180; G: 112; R: 94), (B: 197; G: 95; R: 78), (B: 183; G: 106; R: 78), - (B: 174; G: 96; R: 75), (B: 160; G: 91; R: 63), (B: 166; G: 84; R: 55), - (B: 151; G: 91; R: 54), (B: 152; G: 75; R: 49), (B: 142; G: 81; R: 51), - (B: 216; G: 227; R: 162), (B: 155; G: 212; R: 109), (B: 95; G: 198; R: 57), - (B: 34; G: 183; R: 4), (B: 32; G: 169; R: 4), (B: 29; G: 155; R: 4), - (B: 27; G: 141; R: 4), (B: 25; G: 127; R: 4), (B: 22; G: 113; R: 4), - (B: 20; G: 100; R: 4), (B: 18; G: 86; R: 3), (B: 15; G: 72; R: 3), - (B: 13; G: 58; R: 3), (B: 11; G: 44; R: 3), (B: 8; G: 30; R: 3), - (B: 6; G: 16; R: 3), (B: 134; G: 72; R: 57), (B: 132; G: 71; R: 47), - (B: 122; G: 75; R: 51), (B: 123; G: 61; R: 44), (B: 119; G: 59; R: 37), - (B: 103; G: 55; R: 41), (B: 104; G: 47; R: 31), (B: 98; G: 47; R: 27), - (B: 91; G: 45; R: 33), (B: 83; G: 42; R: 34), (B: 75; G: 40; R: 24), - (B: 80; G: 33; R: 22), (B: 63; G: 29; R: 24), (B: 66; G: 24; R: 16), - (B: 51; G: 27; R: 24), (B: 40; G: 24; R: 24), (B: 255; G: 246; R: 103), - (B: 241; G: 238; R: 45), (B: 235; G: 247; R: 0), (B: 228; G: 228; R: 3), - (B: 204; G: 207; R: 1), (B: 189; G: 187; R: 2), (B: 173; G: 166; R: 2), - (B: 158; G: 146; R: 3), (B: 142; G: 126; R: 3), (B: 127; G: 106; R: 4), - (B: 114; G: 97; R: 9), (B: 96; G: 81; R: 7), (B: 75; G: 63; R: 6), - (B: 53; G: 47; R: 6), (B: 35; G: 31; R: 6), (B: 19; G: 18; R: 6), - (B: 184; G: 116; R: 83), (B: 175; G: 96; R: 57), (B: 166; G: 75; R: 30), - (B: 157; G: 55; R: 4), (B: 145; G: 51; R: 4), (B: 133; G: 47; R: 4), - (B: 122; G: 43; R: 4), (B: 110; G: 39; R: 3), (B: 98; G: 35; R: 3), - (B: 86; G: 31; R: 3), (B: 74; G: 26; R: 3), (B: 62; G: 22; R: 3), - (B: 51; G: 18; R: 3), (B: 39; G: 14; R: 2), (B: 27; G: 10; R: 2), - (B: 15; G: 6; R: 2), (B: 255; G: 255; R: 184), (B: 255; G: 241; R: 137), - (B: 255; G: 226; R: 90), (B: 255; G: 212; R: 43), (B: 240; G: 189; R: 39), - (B: 225; G: 166; R: 35), (B: 211; G: 144; R: 30), (B: 196; G: 121; R: 26), - (B: 181; G: 98; R: 22), (B: 163; G: 92; R: 20), (B: 127; G: 73; R: 15), - (B: 105; G: 60; R: 13), (B: 83; G: 46; R: 12), (B: 61; G: 33; R: 10), - (B: 39; G: 20; R: 8), (B: 26; G: 15; R: 9), (B: 252; G: 203; R: 179), - (B: 245; G: 189; R: 158), (B: 222; G: 167; R: 133), (B: 196; G: 147; R: 111), - (B: 186; G: 134; R: 91), (B: 174; G: 125; R: 81), (B: 161; G: 118; R: 78), - (B: 147; G: 110; R: 72), (B: 136; G: 102; R: 65), (B: 122; G: 93; R: 59), - (B: 110; G: 85; R: 55), (B: 98; G: 79; R: 53), (B: 85; G: 69; R: 46), - (B: 66; G: 54; R: 37), (B: 46; G: 40; R: 29), (B: 27; G: 25; R: 20), - (B: 228; G: 133; R: 133), (B: 225; G: 96; R: 94), (B: 222; G: 58; R: 55), - (B: 219; G: 21; R: 16), (B: 202; G: 20; R: 15), (B: 185; G: 18; R: 14), - (B: 167; G: 17; R: 13), (B: 150; G: 16; R: 12), (B: 133; G: 14; R: 11), - (B: 116; G: 13; R: 11), (B: 98; G: 12; R: 10), (B: 81; G: 10; R: 9), - (B: 64; G: 9; R: 8), (B: 47; G: 8; R: 7), (B: 29; G: 6; R: 6), - (B: 12; G: 5; R: 5), (B: 255; G: 255; R: 255), (B: 240; G: 240; R: 240), - (B: 220; G: 220; R: 220), (B: 201; G: 201; R: 201), (B: 181; G: 181; R: 181), - (B: 162; G: 162; R: 162), (B: 148; G: 148; R: 148), (B: 135; G: 135; R: 135), - (B: 121; G: 121; R: 121), (B: 108; G: 108; R: 108), (B: 90; G: 90; R: 90), - (B: 74; G: 74; R: 74), (B: 58; G: 58; R: 58), (B: 42; G: 42; R: 42), - (B: 22; G: 22; R: 22), (B: 8; G: 8; R: 8), (B: 104; G: 150; R: 233), - (B: 93; G: 125; R: 242), (B: 82; G: 98; R: 249), (B: 72; G: 72; R: 255), - (B: 48; G: 48; R: 255), (B: 25; G: 25; R: 254), (B: 7; G: 7; R: 246), - (B: 7; G: 7; R: 220), (B: 6; G: 6; R: 194), (B: 6; G: 6; R: 169), - (B: 5; G: 5; R: 143), (B: 5; G: 5; R: 117), (B: 4; G: 4; R: 91), - (B: 4; G: 4; R: 66), (B: 3; G: 3; R: 40), (B: 3; G: 3; R: 14), - (B: 191; G: 88; R: 117), (B: 180; G: 63; R: 97), (B: 169; G: 38; R: 78), - (B: 159; G: 14; R: 56), (B: 147; G: 13; R: 52), (B: 135; G: 12; R: 48), - (B: 123; G: 12; R: 44), (B: 111; G: 11; R: 40), (B: 99; G: 10; R: 36), - (B: 87; G: 9; R: 32), (B: 75; G: 8; R: 27), (B: 63; G: 7; R: 23), - (B: 51; G: 7; R: 19), (B: 39; G: 6; R: 15), (B: 27; G: 5; R: 11), - (B: 15; G: 4; R: 7), (B: 135; G: 224; R: 255), (B: 91; G: 213; R: 255), - (B: 46; G: 197; R: 255), (B: 2; G: 184; R: 255), (B: 2; G: 170; R: 235), - (B: 2; G: 156; R: 215), (B: 2; G: 141; R: 195), (B: 2; G: 127; R: 175), - (B: 2; G: 113; R: 155), (B: 3; G: 99; R: 136), (B: 3; G: 84; R: 116), - (B: 3; G: 70; R: 96), (B: 3; G: 56; R: 76), (B: 3; G: 42; R: 56), - (B: 3; G: 27; R: 36), (B: 3; G: 13; R: 16), (B: 254; G: 255; R: 199), - (B: 254; G: 235; R: 170), (B: 255; G: 215; R: 141), (B: 255; G: 205; R: 127), - (B: 255; G: 195; R: 112), (B: 255; G: 175; R: 83), (B: 234; G: 155; R: 50), - (B: 219; G: 131; R: 43), (B: 205; G: 107; R: 35), (B: 190; G: 84; R: 27), - (B: 176; G: 60; R: 19), (B: 155; G: 24; R: 10), (B: 130; G: 21; R: 9), - (B: 105; G: 19; R: 8), (B: 80; G: 16; R: 7), (B: 55; G: 13; R: 6), - (B: 197; G: 215; R: 255), (B: 181; G: 196; R: 233), (B: 165; G: 177; R: 212), - (B: 149; G: 158; R: 190), (B: 138; G: 146; R: 176), (B: 126; G: 134; R: 162), - (B: 115; G: 122; R: 147), (B: 103; G: 110; R: 133), (B: 92; G: 98; R: 119), - (B: 81; G: 87; R: 105), (B: 69; G: 75; R: 90), (B: 58; G: 63; R: 76), - (B: 46; G: 51; R: 62), (B: 35; G: 39; R: 48), (B: 23; G: 27; R: 33), - (B: 12; G: 15; R: 19)); - - { This is default Arena's palette (Arena\pal.col).} - ArenaPalette: TPalette24Size256 = ( - (B: 0; G: 0; R: 0), (B: 0; G: 0; R: 170), (B: 0; G: 170; R: 0), - (B: 0; G: 170; R: 170), (B: 170; G: 0; R: 0), (B: 170; G: 0; R: 170), - (B: 170; G: 85; R: 0), (B: 170; G: 170; R: 170), (B: 85; G: 85; R: 85), - (B: 85; G: 85; R: 255), (B: 85; G: 255; R: 85), (B: 85; G: 255; R: 255), - (B: 255; G: 85; R: 85), (B: 255; G: 85; R: 255), (B: 255; G: 255; R: 85), - (B: 255; G: 255; R: 255), (B: 212; G: 232; R: 248), (B: 193; G: 211; R: 227), - (B: 174; G: 190; R: 205), (B: 155; G: 169; R: 184), (B: 136; G: 148; R: 163), - (B: 118; G: 128; R: 142), (B: 99; G: 107; R: 120), (B: 80; G: 86; R: 99), - (B: 61; G: 65; R: 78), (B: 42; G: 44; R: 56), (B: 0; G: 180; R: 0), - (B: 0; G: 160; R: 0), (B: 0; G: 144; R: 0), (B: 144; G: 184; R: 0), - (B: 124; G: 160; R: 0), (B: 108; G: 140; R: 0), (B: 175; G: 175; R: 187), - (B: 160; G: 160; R: 172), (B: 145; G: 145; R: 157), (B: 129; G: 129; R: 141), - (B: 114; G: 114; R: 126), (B: 99; G: 99; R: 111), (B: 84; G: 84; R: 96), - (B: 69; G: 69; R: 81), (B: 53; G: 53; R: 65), (B: 38; G: 38; R: 50), - (B: 139; G: 127; R: 127), (B: 127; G: 117; R: 118), (B: 116; G: 106; R: 109), - (B: 104; G: 96; R: 99), (B: 93; G: 85; R: 90), (B: 81; G: 75; R: 81), - (B: 69; G: 65; R: 72), (B: 58; G: 54; R: 63), (B: 46; G: 44; R: 53), - (B: 35; G: 33; R: 44), (B: 127; G: 127; R: 139), (B: 117; G: 117; R: 129), - (B: 106; G: 106; R: 118), (B: 96; G: 96; R: 108), (B: 85; G: 85; R: 97), - (B: 75; G: 75; R: 87), (B: 65; G: 65; R: 77), (B: 54; G: 54; R: 66), - (B: 44; G: 44; R: 56), (B: 33; G: 33; R: 45), (B: 0; G: 0; R: 203), - (B: 0; G: 0; R: 175), (B: 30; G: 97; R: 134), (B: 29; G: 90; R: 124), - (B: 29; G: 82; R: 114), (B: 28; G: 75; R: 104), (B: 27; G: 67; R: 94), - (B: 27; G: 60; R: 85), (B: 26; G: 53; R: 75), (B: 25; G: 45; R: 65), - (B: 24; G: 38; R: 55), (B: 24; G: 30; R: 45), (B: 0; G: 127; R: 127), - (B: 2; G: 117; R: 118), (B: 5; G: 106; R: 109), (B: 7; G: 96; R: 99), - (B: 9; G: 85; R: 90), (B: 12; G: 75; R: 81), (B: 14; G: 65; R: 72), - (B: 16; G: 54; R: 63), (B: 18; G: 44; R: 53), (B: 21; G: 33; R: 44), - (B: 75; G: 92; R: 95), (B: 70; G: 85; R: 89), (B: 65; G: 78; R: 83), - (B: 59; G: 71; R: 77), (B: 54; G: 64; R: 71), (B: 49; G: 58; R: 65), - (B: 44; G: 51; R: 59), (B: 39; G: 44; R: 53), (B: 33; G: 37; R: 47), - (B: 28; G: 30; R: 41), (B: 187; G: 39; R: 239), (B: 195; G: 0; R: 199), - (B: 231; G: 215; R: 0), (B: 255; G: 167; R: 0), (B: 223; G: 119; R: 0), - (B: 231; G: 83; R: 0), (B: 139; G: 139; R: 150), (B: 111; G: 111; R: 123), - (B: 95; G: 95; R: 107), (B: 79; G: 79; R: 91), (B: 63; G: 63; R: 75), - (B: 51; G: 51; R: 59), (B: 43; G: 43; R: 51), (B: 39; G: 39; R: 47), - (B: 31; G: 31; R: 43), (B: 27; G: 27; R: 39), (B: 23; G: 23; R: 35), - (B: 19; G: 19; R: 31), (B: 15; G: 15; R: 27), (B: 255; G: 255; R: 255), - (B: 255; G: 255; R: 255), (B: 30; G: 9; R: 1), (B: 112; G: 112; R: 112), - (B: 103; G: 103; R: 104), (B: 94; G: 94; R: 97), (B: 85; G: 85; R: 89), - (B: 76; G: 76; R: 81), (B: 68; G: 68; R: 74), (B: 59; G: 59; R: 66), - (B: 50; G: 50; R: 58), (B: 41; G: 41; R: 50), (B: 32; G: 32; R: 43), - (B: 2; G: 221; R: 221), (B: 0; G: 175; R: 175), (B: 155; G: 51; R: 51), - (B: 142; G: 48; R: 49), (B: 129; G: 45; R: 48), (B: 115; G: 43; R: 46), - (B: 102; G: 40; R: 45), (B: 89; G: 37; R: 43), (B: 76; G: 34; R: 41), - (B: 63; G: 31; R: 40), (B: 49; G: 29; R: 38), (B: 36; G: 26; R: 37), - (B: 127; G: 0; R: 0), (B: 117; G: 2; R: 4), (B: 106; G: 5; R: 7), - (B: 96; G: 7; R: 11), (B: 85; G: 9; R: 14), (B: 75; G: 12; R: 18), - (B: 65; G: 14; R: 21), (B: 54; G: 16; R: 25), (B: 44; G: 18; R: 28), - (B: 33; G: 21; R: 32), (B: 78; G: 61; R: 48), (B: 73; G: 57; R: 47), - (B: 67; G: 53; R: 45), (B: 62; G: 50; R: 44), (B: 56; G: 46; R: 43), - (B: 51; G: 42; R: 42), (B: 45; G: 38; R: 40), (B: 40; G: 34; R: 39), - (B: 34; G: 31; R: 38), (B: 29; G: 27; R: 36), (B: 225; G: 2; R: 2), - (B: 195; G: 0; R: 0), (B: 0; G: 127; R: 0), (B: 2; G: 117; R: 4), - (B: 5; G: 106; R: 7), (B: 7; G: 96; R: 11), (B: 9; G: 85; R: 14), - (B: 12; G: 75; R: 18), (B: 14; G: 65; R: 21), (B: 16; G: 54; R: 25), - (B: 18; G: 44; R: 28), (B: 21; G: 33; R: 32), (B: 55; G: 63; R: 39), - (B: 52; G: 59; R: 39), (B: 49; G: 55; R: 38), (B: 45; G: 51; R: 38), - (B: 42; G: 47; R: 37), (B: 39; G: 43; R: 37), (B: 36; G: 39; R: 37), - (B: 33; G: 35; R: 36), (B: 29; G: 31; R: 36), (B: 26; G: 27; R: 35), - (B: 158; G: 176; R: 195), (B: 145; G: 161; R: 179), (B: 131; G: 145; R: 163), - (B: 118; G: 130; R: 147), (B: 104; G: 115; R: 131), (B: 91; G: 100; R: 115), - (B: 77; G: 84; R: 99), (B: 64; G: 69; R: 83), (B: 50; G: 54; R: 67), - (B: 37; G: 38; R: 51), (B: 56; G: 25; R: 25), (B: 36; G: 20; R: 26), - (B: 215; G: 159; R: 7), (B: 196; G: 145; R: 10), (B: 177; G: 132; R: 13), - (B: 157; G: 118; R: 15), (B: 138; G: 105; R: 18), (B: 119; G: 91; R: 21), - (B: 100; G: 77; R: 24), (B: 81; G: 64; R: 27), (B: 61; G: 50; R: 29), - (B: 42; G: 37; R: 32), (B: 139; G: 115; R: 0), (B: 127; G: 106; R: 4), - (B: 116; G: 97; R: 7), (B: 104; G: 87; R: 11), (B: 93; G: 78; R: 14), - (B: 81; G: 69; R: 18), (B: 69; G: 60; R: 21), (B: 58; G: 51; R: 25), - (B: 46; G: 41; R: 28), (B: 35; G: 32; R: 32), (B: 151; G: 99; R: 0), - (B: 138; G: 91; R: 4), (B: 125; G: 84; R: 7), (B: 113; G: 76; R: 11), - (B: 100; G: 69; R: 14), (B: 87; G: 61; R: 18), (B: 74; G: 53; R: 21), - (B: 61; G: 46; R: 25), (B: 49; G: 38; R: 28), (B: 36; G: 31; R: 32), - (B: 254; G: 170; R: 0), (B: 255; G: 184; R: 0), (B: 211; G: 203; R: 179), - (B: 208; G: 195; R: 167), (B: 205; G: 186; R: 155), (B: 212; G: 178; R: 143), - (B: 200; G: 163; R: 131), (B: 187; G: 148; R: 119), (B: 183; G: 133; R: 107), - (B: 170; G: 118; R: 95), (B: 156; G: 104; R: 84), (B: 143; G: 89; R: 72), - (B: 126; G: 74; R: 60), (B: 103; G: 59; R: 48), (B: 90; G: 45; R: 36), - (B: 77; G: 30; R: 24), (B: 64; G: 15; R: 12), (B: 41; G: 0; R: 0), - (B: 212; G: 120; R: 8), (B: 209; G: 111; R: 9), (B: 206; G: 102; R: 10), - (B: 204; G: 92; R: 10), (B: 201; G: 83; R: 11), (B: 198; G: 74; R: 12), - (B: 195; G: 65; R: 13), (B: 192; G: 56; R: 14), (B: 190; G: 46; R: 14), - (B: 187; G: 37; R: 15), (B: 184; G: 28; R: 16), (B: 0; G: 0; R: 60), - (B: 251; G: 239; R: 79), (B: 191; G: 115; R: 0), (B: 197; G: 197; R: 197), - (B: 52; G: 52; R: 52)); - - { This is default Terminator Future Shock's palette (Shock\Gamedata\Shock.col).} - FutureShockPalette: TPalette24Size256 = ( - (B: 0; G: 0; R: 0), (B: 255; G: 255; R: 255), (B: 255; G: 255; R: 211), - (B: 255; G: 255; R: 177), (B: 255; G: 255; R: 127), (B: 255; G: 255; R: 97), - (B: 255; G: 210; R: 67), (B: 255; G: 166; R: 55), (B: 255; G: 0; R: 0), - (B: 255; G: 131; R: 0), (B: 0; G: 255; R: 0), (B: 71; G: 71; R: 255), - (B: 255; G: 255; R: 0), (B: 254; G: 137; R: 46), (B: 216; G: 111; R: 37), - (B: 177; G: 88; R: 29), (B: 51; G: 55; R: 55), (B: 55; G: 51; R: 55), - (B: 51; G: 51; R: 53), (B: 51; G: 51; R: 54), (B: 59; G: 51; R: 63), - (B: 59; G: 51; R: 54), (B: 51; G: 55; R: 57), (B: 51; G: 51; R: 51), - (B: 239; G: 51; R: 239), (B: 239; G: 51; R: 239), (B: 239; G: 51; R: 239), - (B: 239; G: 51; R: 239), (B: 64; G: 41; R: 38), (B: 49; G: 33; R: 32), - (B: 33; G: 26; R: 27), (B: 18; G: 18; R: 21), (B: 191; G: 239; R: 211), - (B: 179; G: 223; R: 195), (B: 163; G: 207; R: 179), (B: 147; G: 191; R: 159), - (B: 131; G: 175; R: 143), (B: 115; G: 155; R: 127), (B: 103; G: 139; R: 111), - (B: 91; G: 131; R: 103), (B: 83; G: 119; R: 91), (B: 75; G: 107; R: 83), - (B: 67; G: 95; R: 71), (B: 63; G: 87; R: 67), (B: 59; G: 79; R: 63), - (B: 55; G: 71; R: 59), (B: 55; G: 63; R: 55), (B: 51; G: 55; R: 51), - (B: 227; G: 203; R: 203), (B: 211; G: 187; R: 187), (B: 191; G: 175; R: 171), - (B: 175; G: 159; R: 159), (B: 159; G: 143; R: 143), (B: 143; G: 127; R: 127), - (B: 127; G: 111; R: 111), (B: 115; G: 99; R: 99), (B: 103; G: 91; R: 91), - (B: 91; G: 83; R: 83), (B: 83; G: 71; R: 71), (B: 75; G: 67; R: 67), - (B: 71; G: 63; R: 63), (B: 67; G: 59; R: 59), (B: 63; G: 55; R: 55), - (B: 59; G: 51; R: 51), (B: 179; G: 235; R: 247), (B: 163; G: 219; R: 231), - (B: 147; G: 203; R: 219), (B: 131; G: 187; R: 203), (B: 115; G: 171; R: 191), - (B: 99; G: 155; R: 175), (B: 83; G: 139; R: 163), (B: 75; G: 127; R: 151), - (B: 67; G: 115; R: 139), (B: 59; G: 103; R: 123), (B: 51; G: 91; R: 111), - (B: 51; G: 83; R: 99), (B: 51; G: 79; R: 91), (B: 51; G: 71; R: 79), - (B: 51; G: 63; R: 67), (B: 51; G: 55; R: 55), (B: 207; G: 207; R: 215), - (B: 191; G: 191; R: 199), (B: 175; G: 179; R: 187), (B: 163; G: 163; R: 171), - (B: 147; G: 151; R: 155), (B: 131; G: 135; R: 143), (B: 119; G: 119; R: 127), - (B: 107; G: 111; R: 115), (B: 99; G: 103; R: 107), (B: 87; G: 91; R: 95), - (B: 79; G: 83; R: 83), (B: 71; G: 75; R: 79), (B: 67; G: 71; R: 71), - (B: 63; G: 63; R: 67), (B: 55; G: 59; R: 59), (B: 51; G: 55; R: 55), - (B: 231; G: 211; R: 171), (B: 215; G: 195; R: 155), (B: 199; G: 179; R: 143), - (B: 187; G: 159; R: 127), (B: 171; G: 143; R: 111), (B: 155; G: 127; R: 95), - (B: 139; G: 107; R: 83), (B: 131; G: 99; R: 75), (B: 119; G: 87; R: 67), - (B: 107; G: 75; R: 59), (B: 95; G: 67; R: 51), (B: 87; G: 63; R: 51), - (B: 79; G: 59; R: 51), (B: 71; G: 59; R: 51), (B: 63; G: 55; R: 51), - (B: 55; G: 51; R: 51), (B: 140; G: 47; R: 47), (B: 179; G: 54; R: 54), - (B: 255; G: 99; R: 0), (B: 255; G: 191; R: 0), (B: 151; G: 78; R: 26), - (B: 112; G: 70; R: 41), (B: 94; G: 57; R: 53), (B: 64; G: 41; R: 38), - (B: 47; G: 47; R: 52), (B: 43; G: 43; R: 49), (B: 38; G: 38; R: 44), - (B: 35; G: 35; R: 40), (B: 31; G: 31; R: 36), (B: 27; G: 27; R: 30), - (B: 22; G: 22; R: 27), (B: 18; G: 18; R: 21), (B: 175; G: 219; R: 219), - (B: 131; G: 231; R: 231), (B: 95; G: 231; R: 231), (B: 51; G: 239; R: 239), - (B: 51; G: 235; R: 235), (B: 51; G: 219; R: 219), (B: 51; G: 199; R: 199), - (B: 51; G: 175; R: 179), (B: 51; G: 159; R: 163), (B: 51; G: 139; R: 143), - (B: 51; G: 119; R: 123), (B: 51; G: 99; R: 107), (B: 51; G: 87; R: 91), - (B: 51; G: 71; R: 79), (B: 51; G: 55; R: 63), (B: 51; G: 51; R: 51), - (B: 219; G: 219; R: 175), (B: 231; G: 231; R: 131), (B: 231; G: 231; R: 95), - (B: 239; G: 239; R: 51), (B: 235; G: 235; R: 51), (B: 219; G: 219; R: 51), - (B: 199; G: 199; R: 51), (B: 179; G: 175; R: 51), (B: 163; G: 159; R: 51), - (B: 143; G: 139; R: 51), (B: 123; G: 119; R: 51), (B: 107; G: 99; R: 51), - (B: 91; G: 87; R: 51), (B: 79; G: 71; R: 51), (B: 63; G: 55; R: 51), - (B: 51; G: 51; R: 51), (B: 219; G: 175; R: 219), (B: 231; G: 131; R: 231), - (B: 231; G: 95; R: 231), (B: 239; G: 51; R: 239), (B: 235; G: 51; R: 235), - (B: 219; G: 51; R: 219), (B: 199; G: 51; R: 199), (B: 179; G: 51; R: 179), - (B: 163; G: 51; R: 159), (B: 143; G: 51; R: 139), (B: 123; G: 51; R: 119), - (B: 107; G: 51; R: 99), (B: 91; G: 51; R: 87), (B: 79; G: 51; R: 71), - (B: 63; G: 51; R: 55), (B: 51; G: 51; R: 51), (B: 175; G: 219; R: 175), - (B: 131; G: 231; R: 131), (B: 99; G: 231; R: 99), (B: 55; G: 235; R: 55), - (B: 55; G: 231; R: 55), (B: 55; G: 211; R: 55), (B: 63; G: 187; R: 63), - (B: 71; G: 159; R: 71), (B: 67; G: 143; R: 67), (B: 67; G: 127; R: 67), - (B: 63; G: 111; R: 63), (B: 59; G: 99; R: 59), (B: 59; G: 83; R: 59), - (B: 55; G: 71; R: 55), (B: 55; G: 59; R: 55), (B: 51; G: 55; R: 51), - (B: 143; G: 143; R: 223), (B: 123; G: 123; R: 235), (B: 95; G: 95; R: 243), - (B: 59; G: 59; R: 255), (B: 55; G: 55; R: 235), (B: 59; G: 59; R: 211), - (B: 63; G: 63; R: 191), (B: 67; G: 67; R: 167), (B: 63; G: 63; R: 151), - (B: 63; G: 63; R: 131), (B: 59; G: 59; R: 119), (B: 55; G: 55; R: 103), - (B: 55; G: 55; R: 91), (B: 55; G: 55; R: 75), (B: 51; G: 51; R: 63), - (B: 51; G: 51; R: 55), (B: 219; G: 131; R: 131), (B: 235; G: 111; R: 111), - (B: 239; G: 95; R: 95), (B: 243; G: 67; R: 67), (B: 235; G: 51; R: 51), - (B: 215; G: 51; R: 51), (B: 199; G: 55; R: 55), (B: 179; G: 51; R: 51), - (B: 163; G: 51; R: 51), (B: 143; G: 51; R: 51), (B: 123; G: 51; R: 51), - (B: 107; G: 51; R: 51), (B: 91; G: 51; R: 51), (B: 79; G: 51; R: 51), - (B: 63; G: 51; R: 51), (B: 51; G: 51; R: 51), (B: 203; G: 187; R: 227), - (B: 191; G: 175; R: 211), (B: 175; G: 163; R: 195), (B: 159; G: 147; R: 179), - (B: 147; G: 135; R: 167), (B: 131; G: 123; R: 151), (B: 119; G: 107; R: 135), - (B: 107; G: 99; R: 123), (B: 99; G: 91; R: 111), (B: 91; G: 83; R: 103), - (B: 79; G: 71; R: 91), (B: 75; G: 67; R: 83), (B: 71; G: 63; R: 79), - (B: 67; G: 59; R: 71), (B: 63; G: 55; R: 67), (B: 59; G: 51; R: 63), - (B: 183; G: 219; R: 227), (B: 167; G: 203; R: 211), (B: 151; G: 187; R: 191), - (B: 135; G: 167; R: 175), (B: 119; G: 151; R: 155), (B: 99; G: 135; R: 139), - (B: 83; G: 119; R: 119), (B: 75; G: 107; R: 111), (B: 67; G: 95; R: 99), - (B: 67; G: 91; R: 91), (B: 63; G: 83; R: 83), (B: 59; G: 75; R: 79), - (B: 59; G: 71; R: 71), (B: 55; G: 63; R: 63), (B: 51; G: 59; R: 59), - (B: 49; G: 51; R: 51)); - -implementation - -uses - Types, - SysUtils, - Classes, - ImagingIO, - ImagingUtility, - ElderImageryBsi, - ElderImageryCif, - ElderImageryImg, - ElderImageryTexture, - ElderImagerySky; - -{ TDaggerfallFileFormat class implementation } - -procedure TElderFileFormat.Define; -begin - inherited; - FFeatures := [ffLoad, ffSave, ffMultiImage]; - FSupportedFormats := []; - - GetMem(FARGBPalette, Length(FPalette) * SizeOf(TColor32Rec)); - SetPalette(DaggerfallPalette); -end; - -destructor TElderFileFormat.Destroy; -begin - FreeMem(FARGBPalette); - inherited Destroy; -end; - -procedure TElderFileFormat.DagRLEDecode(InData: Pointer; OutSize: LongInt; - out OutData: Pointer); -var - I, Pos, CByte: LongInt; - Rle, B: Byte; -begin - Pos := 0; - CByte := 0; - while Pos < OutSize do - begin - Rle := PByteArray(InData)[CByte]; - CByte := CByte + 1; - if Rle < 128 then - begin - Rle := Rle + 1; - Move(PByteArray(InData)[CByte], PByteArray(OutData)[Pos], Rle); - CByte := CByte + Rle; - Pos := Pos + Rle; - end - else - begin - Rle := Rle - 127; - B := PByteArray(InData)[CByte];; - CByte := CByte + 1; - for I := 0 to Rle - 1 do - begin - PByteArray(OutData)[Pos] := B; - Pos := Pos + 1; - end; - end; - end; -end; - -function TElderFileFormat.FindNoHeaderInfo(Size: LongInt; - Infos: array of TNoHeaderFileInfo): LongInt; -var - I: LongInt; -begin - for I := Low(Infos) to High(Infos) do - begin - if Size = Infos[I].Size then - begin - Result := I; - Exit; - end; - end; - Result := -1; -end; - -function TElderFileFormat.TestNoHeaderFormat(Handle: TImagingHandle): TElderFileFormatClass; -var - InputSize, I: LongInt; -begin - Result := nil; - if Handle <> nil then - begin - InputSize := GetInputSize(GetIO, Handle); - // Check special IMG files - I := FindNoHeaderInfo(InputSize, NoHeaderIMGInfos); - if I >= 0 then - begin - Result := TIMGFileFormat; - Exit; - end; - // Check special CIF files - I := FindNoHeaderInfo(InputSize, NoHeaderCIFInfos); - if I >= 0 then - begin - Result := TCIFFileFormat; - Exit; - end; - end; -end; - -procedure TElderFileFormat.ConvertPalette(const ElderPal: TPalette24Size256; - ARGBPal: PPalette32); -var - I: LongInt; -begin - for I := Low(ElderPal) to High(ElderPal) do - begin - ARGBPal[I].A := $FF; - ARGBPal[I].R := ElderPal[I].B; - ARGBPal[I].G := ElderPal[I].G; - ARGBPal[I].B := ElderPal[I].R; - end; - // Palette index 0 represents transparent color - ARGBPal[0].A := 0; -end; - -procedure TElderFileFormat.SetPalette(const Value: TPalette24Size256); -begin - FPalette := Value; - ConvertPalette(FPalette, FARGBPalette); -end; - -procedure TElderFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - R: TRect; -begin - if CanSave then - begin - if Image.Width * Image.Height > 65535 then - begin - // Regular CIF and IMG files can only store images no larger than 65535 bytes - if Image.Width > Image.Height then - R := Rect(0, 0, 320, 200) - else - R := Rect(0, 0, 200, 320); - R := ScaleRectToRect(Rect(0, 0, Image.Width, Image.Height), R); - ResizeImage(Image, R.Right - R.Left, R.Bottom - R.Top, rfBilinear); - end; - // Map image to current palette - MapImageToPalette(Image, FARGBPalette, Length(FPalette)); - end; -end; - -function TElderFileFormat.IsSupported(const Image: TImageData): Boolean; -begin - // Image is supported for saving if its indexed and is mapped to current palette - Result := (Image.Format = ifIndex8) and - CompareMem(Image.Palette, FARGBPalette, Length(FPalette) * SizeOf(TColor32Rec)); -end; - -function TElderFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Hdr: TImgHeader; - DagClass: TElderFileFormatClass; - ReadCount: LongInt; -begin - // TestFormat for both IMG and CIF formats - Result := False; - DagClass := TestNoHeaderFormat(Handle); - if (DagClass = nil) and (Handle <> nil) then - begin - // Check ordinary IMG/CIF files with header - ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount > 0) and (Hdr.ImageSize <= Hdr.Width * Hdr.Height) and - (Hdr.Width * Hdr.Height <= High(Word)) and (Hdr.ImageSize <> 0) and - (Hdr.Width <> 0) and (Hdr.Height <> 0); - if IsMultiImageFormat then - Result := Result and (GetInputSize(GetIO, Handle) > Hdr.ImageSize + SizeOf(Hdr)) - else - Result := Result and (GetInputSize(GetIO, Handle) = Hdr.ImageSize + SizeOf(Hdr)); - end - else if DagClass = Self.ClassType then - Result := True; -end; - -initialization - RegisterImageFileFormat(TBSIFileFormat); - RegisterImageFileFormat(TCIFFileFormat); - RegisterImageFileFormat(TIMGFileFormat); - RegisterImageFileFormat(TTextureFileFormat); - RegisterImageFileFormat(TSKYFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Fixed TestFormat which could identify something (eof) as image. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Too large images that are to be saved in CIF/IMG formats are - automatically rescaled in ConvertToSupported method. - - MakeCompatible method moved to base class, put ConvertToSupported here. - GetSupportedFormats removed, it is now set in constructor. - - Added default palettes for more games. - - Added transparency to Daggerfall palettes. - - Initial version created based on my older code. -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ElderImageryBsi.pas b/3rd/Imaging/Extras/Extensions/ElderImageryBsi.pas deleted file mode 100644 index 3f15609ef..000000000 --- a/3rd/Imaging/Extras/Extensions/ElderImageryBsi.pas +++ /dev/null @@ -1,409 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader for textures and images - from Redguard and BattleSpire.} -unit ElderImageryBsi; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ElderImagery, ImagingUtility; - -type - { Class for loading of BSI format textures and images found - in Redguard and BattleSpire (maybe in other games too, Skynet?). This format - uses chunk structure similar to PNG (HDR/DAT/END). Redguard stores - multiple images in one file (usually related like textures for various - parts of single 3d object). Image data is stored as 8bit. Each image - can have its own embedded palette or it can use external default palette. - BattleSpire BSI use *.bsi file extension whilst Redguard uses - texbsi.* mask with number extension (just like Daggerfall). - Only loading is supported for this format. - BattleSpire images also contain some sort of 8bit->16bit color mapping data - which I've not yet figured out (only blue channel known).} - TBSIFileFormat = class(TElderFileFormat) - private - function IsMultiBSI(Handle: TImagingHandle): Boolean; - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - end; - -implementation - -const - SBSIFormatName = 'Bethesda Image'; - SBSIMasks = '*.bsi,texbsi.*'; - -resourcestring - SErrorLoadingChunk = 'Error when reading %s chunk data.'; - -type - { BSI chunk header.} - TChunk = packed record - ChunkID: TChar4; - DataSize: LongWord; // In Big Endian! - end; - - { Additional header of BSI textures.} - TTextureBSIHeader = packed record - Name: array[0..8] of AnsiChar; - ImageSize: LongInt; - end; - - { Main image info header located in BHDR chunk's data.} - TBHDRChunk = packed record - OffsetX: Word; - OffsetY: Word; - Width: SmallInt; - Height: SmallInt; - Unk1, Unk2: Byte; - Unk3, Unk4: Word; - Frames: Word; - Unk6, Unk7, Unk8: Word; - Unk9, Unk10: Byte; - Unk11: Word; - end; - -const - IFHDSignature: TChar4 = 'IFHD'; - BSIFSignature: TChar4 = 'BSIF'; - BHDRSignature: TChar4 = 'BHDR'; - CMAPSignature: TChar4 = 'CMAP'; - HICLSignature: TChar4 = 'HICL'; - HTBLSignature: TChar4 = 'HTBL'; - DATASignature: TChar4 = 'DATA'; - ENDSignature: TChar4 = 'END '; - - -{ TBSIFileFormat class implementation } - -procedure TBSIFileFormat.Define; -begin - inherited; - FName := SBSIFormatName; - FFeatures := [ffLoad, ffMultiImage]; - - AddMasks(SBSIMasks); - SetPalette(RedguardPalette); -end; - -function TBSIFileFormat.IsMultiBSI(Handle: TImagingHandle): Boolean; -var - ReadCount, StartPos: LongInt; - Sig: TChar4; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - StartPos := Tell(Handle); - // Redguard textures have 13 byte tex header and then IFHD or BSIF - Seek(Handle, SizeOf(TTextureBSIHeader), smFromCurrent); - ReadCount := Read(Handle, @Sig, SizeOf(Sig)); - Seek(Handle, StartPos, smFromBeginning); - Result := Result or ((ReadCount = SizeOf(Sig)) and - ((Sig = IFHDSignature) or (Sig = BSIFSignature))); - end; -end; - -function TBSIFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Chunk: TChunk; - ChunkData: Pointer; - DATASize: LongInt; - BHDR: TBHDRChunk; - PalLoaded: TPalette24Size256; - HICL: PByteArray; - HTBL: PWordArray; - IsMulti: Boolean; - TextureHdr: TTextureBSIHeader; - PaletteFound: Boolean; - - procedure ReadChunk; - begin - GetIO.Read(Handle, @Chunk, SizeOf(Chunk)); - Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); - end; - - procedure ReadChunkData; - var - ReadBytes: LongWord; - begin - FreeMemNil(ChunkData); - GetMem(ChunkData, Chunk.DataSize); - ReadBytes := GetIO.Read(Handle, ChunkData, Chunk.DataSize); - if ReadBytes <> Chunk.DataSize then - RaiseImaging(SErrorLoadingChunk, [Chunk.ChunkID]); - end; - - procedure SkipChunkData; - begin - GetIO.Seek(Handle, Chunk.DataSize, smFromCurrent); - end; - - procedure GetBHDR; - begin - ReadChunkData; - BHDR := TBHDRChunk(ChunkData^); - end; - - procedure GetHICL; - begin - ReadChunkData; - GetMem(HICL, Chunk.DataSize); - Move(ChunkData^, HICL[0], Chunk.DataSize); - end; - - procedure GetHTBL; - begin - ReadChunkData; - GetMem(HTBL, Chunk.DataSize); - Move(ChunkData^, HTBL[0], Chunk.DataSize); - end; - - procedure GetCMAP; - begin - ReadChunkData; - Move(ChunkData^, PalLoaded, Chunk.DataSize); - PaletteFound := True; - end; - - procedure GetDATA; - begin - ReadChunkData; - DATASize := Chunk.DataSize; - end; - - function AddImage(Width, Height: LongInt): LongInt; - begin - Result := Length(Images); - SetLength(Images, Length(Images) + 1); - NewImage(Width, Height, ifIndex8, Images[Result]); - if not PaletteFound then - Move(FARGBPalette[0], Images[Result].Palette[0], Length(FPalette) * SizeOf(TColor32Rec)) - else - ConvertPalette(PalLoaded, Images[Result].Palette); - end; - - function AddImageHiColor(Width, Height: LongInt): LongInt; - begin - Result := Length(Images); - SetLength(Images, Length(Images) + 1); - NewImage(Width, Height, ifA8R8G8B8, Images[Result]); - end; - - procedure Reconstruct; - var - Index, I, J, K: LongInt; - RowOffsets: PLongIntArray; - Idx: Byte; - W: Word; - begin - if HICL = nil then - begin - if BHDR.Frames = 1 then - begin - // Load simple image - Index := AddImage(BHDR.Width, BHDR.Height); - Move(ChunkData^, Images[Index].Bits^, Images[Index].Size); - end - else - begin - // Load animated image: - // At the beggining of the chunk data there is BHDR.Height * BHDR.Frames - // 32bit offsets. Each BHDR.Height offsets point to rows of the current frame - RowOffsets := PLongIntArray(ChunkData); - - for I := 0 to BHDR.Frames - 1 do - begin - Index := AddImage(BHDR.Width, BHDR.Height); - with Images[Index] do - for J := 0 to BHDR.Height - 1 do - Move(PByteArray(ChunkData)[RowOffsets[I * BHDR.Height + J]], - PByteArray(Bits)[J * Width], Width); - end; - end; - end - else - begin - if BHDR.Frames = 1 then - begin - // Experimental BattleSpire 16bit image support! - Index := AddImageHiColor(BHDR.Width, BHDR.Height); - with Images[Index] do - for I := 0 to DATASize - 1 do - with PColor32RecArray(Bits)[I] do - begin - // It looks like "HICL[PByteArray(ChunkData)[I]] and 63" gives - // value of 6bit Blue channel, not other channels are sure yet. - // So now it looks grayscalish. - // You can also get interesting results using HTBL as look up table - // 8->16bit. There are 16 tables for shading (table 0 - darkest colors, - // table 15 - lightest) each with 256 16bit Words. But their data format - // is weird (555 is closest). There are some pixels that look - // as they should (proper color) but some does not. - // PWordArray(Bits)[I] := HTBL[256 * 15 + PByteArray(ChunkData)[I]] - Idx := PByteArray(ChunkData)[I]; - A := Iff(Idx <> 0, 255, 0); - R := MulDiv(HICL[Idx] and 63, 255, 63); - G := MulDiv(HICL[Idx] and 63, 255, 63); - B := MulDiv(HICL[Idx] and 63, 255, 63); - end; - end - else - begin - // Load animated BattleSpire image, uses offset list just like Redguard - // animated textures (but high word must be zeroed first to get valid offset) - RowOffsets := PLongIntArray(ChunkData); - - for I := 0 to BHDR.Frames - 1 do - begin - Index := AddImageHiColor(BHDR.Width, BHDR.Height); - with Images[Index] do - for J := 0 to BHDR.Height - 1 do - for K := 0 to BHDR.Width - 1 do - with PColor32RecArray(Bits)[J * BHDR.Width + K] do - begin - Idx := PByteArray(ChunkData)[RowOffsets[I * BHDR.Height + J] and $FFFF + K]; - W := HTBL[256 * 15 + Idx]; - A := Iff(Idx <> 0, 255, 0); - R := MulDiv(W shr 10 and 31, 255, 31); - G := MulDiv(W shr 5 and 31, 255, 31); - B := MulDiv(W and 31, 255, 31); - { A := Iff(Idx <> 0, 255, 0); - R := MulDiv(HICL[Idx] and 63, 255, 63); - G := MulDiv(HICL[Idx] and 63, 255, 63); - B := MulDiv(HICL[Idx] and 63, 255, 63);} - end; - end; - end; - end; - end; - - procedure ReadTextureHeader; - begin - FillChar(TextureHdr, SizeOf(TextureHdr), 0); - if IsMulti then - GetIO.Read(Handle, @TextureHdr, SizeOf(TextureHdr)) - else if Length(Images) = 0 then - // Ensure that while loop that reads chunks is executed for - // single-image files - TextureHdr.ImageSize := 1; - end; - -begin - ChunkData := nil; - HICL := nil; - HTBL := nil; - SetLength(Images, 0); - IsMulti := IsMultiBSI(Handle); - with GetIO do - begin - // Redguard textures can contain more than one image. Try to read texture - // header and if ImageSize is >0 there is another image. - ReadTextureHeader; - while TextureHdr.ImageSize > 0 do - try - PaletteFound := False; - ReadChunk; - SkipChunkData; - // Read data chunks. If they are recognized their data is stored for - // later image reconstruction - repeat - ReadChunk; - if Chunk.ChunkID = BHDRSignature then - GetBHDR - else if Chunk.ChunkID = HICLSignature then - GetHICL - else if Chunk.ChunkID = HTBLSignature then - GetHTBL - else if Chunk.ChunkID = CMAPSignature then - GetCMAP - else if Chunk.ChunkID = DATASignature then - GetDATA - else - SkipChunkData; - until Eof(Handle) or (Chunk.ChunkID = ENDSignature); - // Recontruct current image according to data read from chunks - Reconstruct; - // Read header for next image - ReadTextureHeader; - finally - FreeMemNil(ChunkData); - FreeMemNil(HICL); - FreeMemNil(HTBL); - end; - Result := True; - end; -end; - -function TBSIFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - ReadCount: LongInt; - Sig: TChar4; -begin - // First check if have multi-image BSI file (Redguard textures) - Result := IsMultiBSI(Handle); - if not Result and (Handle <> nil) then - with GetIO do - begin - // Check standard Bettlespire images with IFHD chunk at - // the beginning of the file - ReadCount := Read(Handle, @Sig, SizeOf(Sig)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(Sig)) and (Sig = IFHDSignature); - end; -end; - - -{ - Changes/Bug Fixes: - - -- TODOS ---------------------------------------------------- - - crack the BattleSpire format completely - - -- 0.21 ----------------------------------------------------- - - Blue channel of BattleSpire images cracked but others arer still unknown. - - Added support for animated BattleSpire images. - - Added support for animated Redguard textures. - - Added support for Redguard textures (Battlespire images still don't figured out). - - Updated to current Imaging version. - - -- 0.13 ----------------------------------------------------- - - TBSIFileFormat class added - -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ElderImageryCif.pas b/3rd/Imaging/Extras/Extensions/ElderImageryCif.pas deleted file mode 100644 index 8bc42ec59..000000000 --- a/3rd/Imaging/Extras/Extensions/ElderImageryCif.pas +++ /dev/null @@ -1,289 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for Daggerfall - multi-image fomat CIF.} -unit ElderImageryCif; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingIO, ElderImagery; - -type - { Class for loading and saving of multi-images in CIF format. It is - 8 bit indexed format found in Daggerfall. It is basically a sequence of - images in IMG (see TIMGFileFormat) stored in one file (with exception - of Weapo*.cif files which are little bit more complex). As with IMG files - CIF files can be RLE compressed and there are also special CIFs without header. - Total number of frames in file is known after the whole file was parsed - so exact file size must be known prior to loading.} - TCIFFileFormat = class(TElderFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - end; - -const - { Info about special CIFs without header.} - NoHeaderCIFInfos: array[0..6] of TNoHeaderFileInfo = ( - (Size: 2601; Width: 17; Height: 17), // MPOP.RCI - (Size: 3168; Width: 44; Height: 9), // NOTE.RCI - (Size: 4356; Width: 22; Height: 22), // SPOP.RCI - (Size: 10752; Width: 32; Height: 16), // BUTTONS.RCI - (Size: 49152; Width: 64; Height: 64), // CHLD00I0.RCI - (Size: 249856; Width: 64; Height: 64), // FACES.CIF - (Size: 2060295; Width: 64; Height: 64)); // TFAC00I0.RCI - -implementation - -const - SCIFFormatName = 'Daggerfall MultiImage'; - SCIFMasks = '*.cif,*.rci'; - -resourcestring - SInvalidImageSize = 'Size of image in IMG/CIF format cannot exceed 65535 bytes. %s'; - -type - { Header for CIF group files.} - TCIFGroup = packed record - Width: Word; - Height: Word; - XOff: Word; - YOff: Word; - Unk: Word; - ImageSize: Word; // Size of Image data (but not always) - Offsets: array[0..31] of Word; // Offsets from beginning of header to - // image datas. Last offset points to next - // group header - end; - -{ TCIFFileFormat class implementation } - -procedure TCIFFileFormat.Define; -begin - inherited; - FName := SCIFFormatName; - AddMasks(SCIFMasks); -end; - -function TCIFFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Hdr: TImgHeader; - Group: TCIFGroup; - Data: Pointer; - IsWeapon, ISW9, IsStandard, IsFirst: Boolean; - InputSize, I, FrameWidth, FrameHeight, OldPos, Index, BufferSize: LongInt; - HasHeader: Boolean; - - function AddImage(Width, Height: LongInt): LongInt; - begin - Result := Length(Images); - SetLength(Images, Length(Images) + 1); - NewImage(Width, Height, ifIndex8, Images[Result]); - Move(FARGBPalette[0], Images[Result].Palette[0], Length(FPalette) * SizeOf(TColor32Rec)); - end; - -begin - SetLength(Images, 0); - with GetIO do - begin - InputSize := GetInputSize(GetIO, Handle); - HasHeader := True; - IsWeapon := False; - IsW9 := False; - IsFirst := True; - FrameWidth := 0; - FrameHeight := 0; - - // Check if this is one of special CIF with no header - I := FindNoHeaderInfo(InputSize, NoHeaderCIFInfos); - - if I >= 0 then - begin - // It is no-header CIF - FrameWidth := NoHeaderCIFInfos[I].Width; - FrameHeight := NoHeaderCIFInfos[I].Height; - HasHeader := False; - end; - - if HasHeader then - begin - OldPos := Tell(Handle); - // CIF has header so use its values - Read(Handle, @Hdr, SizeOf(Hdr)); - - if Hdr.Unk = $15 then - begin - // This file is weapon09.cif (shooting arrows) - IsWeapon := True; - IsW9 := True; - end; - - if Tell(Handle) + Hdr.ImageSize < InputSize then - begin - Seek(Handle, Hdr.ImageSize, smFromCurrent); - Read(Handle, @Group, SizeOf(Group)); - if Group.Offsets[0] = 76 then - // CIF is regular weapon file - IsWeapon := True; - end; - Seek(Handle, OldPos, smFromBeginning); - end; - - IsStandard := HasHeader and (not IsWeapon); - - while not Eof(Handle) do - begin - if IsStandard then - begin - // Handle CIFs in standard format with header - Read(Handle, @Hdr, SizeOf(Hdr)); - Index := AddImage(Hdr.Width, Hdr.Height); - if Hdr.Unk <> 2 then - begin - // Read uncompressed data - Read(Handle, Images[Index].Bits, Hdr.ImageSize); - end - else - begin - GetMem(Data, Hdr.ImageSize); - try - // Read RLE compressed data - Read(Handle, Data, Hdr.ImageSize); - DagRLEDecode(Data, Images[Index].Size, Images[Index].Bits); - finally - FreeMem(Data); - end; - end; - end - else if not HasHeader then - begin - // Handle CIFs in standard format without header - if Tell(Handle) + FrameWidth * FrameHeight <= InputSize then - begin - Index := AddImage(FrameWidth, FrameHeight); - Read(Handle, Images[Index].Bits, Images[Index].Size); - end - else - Break; - end - else if IsWeapon then - begin - // Handle CIFs with weapon animations - if IsFirst and (not IsW9) then - begin - // First frame is std IMG file, next ones are not - // but if IsW9 is true this first frame is missing - Read(Handle, @Hdr, SizeOf(Hdr)); - Index := AddImage(Hdr.Width, Hdr.Height); - Read(Handle, Images[Index].Bits, Images[Index].Size); - IsFirst := False; - end - else - begin - OldPos := Tell(Handle); - // Read next group - Read(Handle, @Group, SizeOf(Group)); - // Read images in group - I := 0; - while Group.Offsets[I] <> 0 do - begin - BufferSize := Group.Offsets[I + 1] - Group.Offsets[I]; - if BufferSize < 0 then - BufferSize := Group.Offsets[31] - Group.Offsets[I]; - - Seek(Handle, OldPos + Group.Offsets[I], smFromBeginning); - Index := AddImage(Group.Width, Group.Height); - // Read current image from current group and decode it - GetMem(Data, BufferSize); - try - Read(Handle, Data, BufferSize); - DagRLEDecode(Data, Images[Index].Size, Images[Index].Bits); - Inc(I); - finally - FreeMem(Data); - end; - end; - Seek(Handle, OldPos + Group.Offsets[31], smFromBeginning); - end; - end; - end; - Result := True; - end; -end; - -function TCIFFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - Hdr: TImgHeader; - ImageToSave: TImageData; - MustBeFreed: Boolean; - I: LongInt; -begin - Result := False; - for I := FFirstIdx to FLastIdx do - begin - if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - FillChar(Hdr, SizeOf(Hdr), 0); - Hdr.Width := Width; - Hdr.Height := Height; - // Hdr.ImageSize is Word so max size of image in bytes can be 65535 - if Width * Height > High(Word) then - RaiseImaging(SInvalidImageSize, [ImageToStr(ImageToSave)]); - Hdr.ImageSize := Width * Height; - Write(Handle, @Hdr, SizeOf(Hdr)); - Write(Handle, Bits, Hdr.ImageSize); - finally - if MustBeFreed then - FreeImage(ImageToSave); - end - else - Exit; - end; - Result := True; -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Initial version created based on my older code (fixed few things). -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ElderImageryImg.pas b/3rd/Imaging/Extras/Extensions/ElderImageryImg.pas deleted file mode 100644 index 0106781d3..000000000 --- a/3rd/Imaging/Extras/Extensions/ElderImageryImg.pas +++ /dev/null @@ -1,226 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for IMG file format used - in Daggerfall and other old Bethesda games.} -unit ElderImageryImg; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingIO, ElderImagery; - -type - { Class for loading and saving of images in IMG format. It is - 8 bit indexed format found in Daggerfall, Arena, Terminator: FS, - and maybe other old Bethesda games. Files can be RLE compressed - and may contain palette although most images use external palettes. - Some files have no header at all so exact file size must be known - prior to loading (otherwise no-header files wont be recognized or whole - image could be identified as CIF as they use the same header).} - TIMGFileFormat = class(TElderFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - end; - -const - { Info about special images without header.} - NoHeaderIMGInfos: array[0..18] of TNoHeaderFileInfo = ( - (Size: 64; Width: 8; Height: 8), // Arena file - (Size: 90; Width: 9; Height: 10), // Arena file - (Size: 128; Width: 8; Height: 16), // Arena file - (Size: 720; Width: 9; Height: 80), - (Size: 990; Width: 45; Height: 22), - (Size: 1720; Width: 43; Height: 40), - (Size: 2140; Width: 107; Height: 20), - (Size: 2916; Width: 81; Height: 36), - (Size: 3200; Width: 40; Height: 80), - (Size: 3938; Width: 179; Height: 22), - (Size: 4096; Width: 64; Height: 64), // Textures from TES: Arena - (Size: 4280; Width: 107; Height: 40), - (Size: 4508; Width: 322; Height: 14), - (Size: 20480; Width: 320; Height: 64), - (Size: 26496; Width: 184; Height: 144), - (Size: 64000; Width: 320; Height: 200), - (Size: 64768; Width: 320; Height: 200), // These contain palette - (Size: 68800; Width: 320; Height: 215), - (Size: 112128; Width: 512; Height: 219)); - -implementation - -const - SIMGFormatName = 'Daggerfall Image'; - SIMGMasks = '*.img'; - -resourcestring - SInvalidImageSize = 'Size of image in IMG format cannot exceed 65535 bytes. %s'; - -{ TIMGFileFormat class implementation } - -procedure TIMGFileFormat.Define; -begin - inherited; - FFeatures := [ffLoad, ffSave]; - FName := SIMGFormatName; - AddMasks(SIMGMasks); -end; - -function TIMGFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Hdr: TImgHeader; - PalUsed: TPalette24Size256; - Data: Pointer; - IsRLE: Boolean; - InputSize, I: LongInt; - - procedure SetSize(W, H: LongInt); - begin - Images[0].Width := W; - Images[0].Height := H; - Images[0].Size := W * H; - end; - -begin - Result := False; - SetLength(Images, 1); - with GetIO, Images[0] do - begin - InputSize := GetInputSize(GetIO, Handle); - Format := ifIndex8; - IsRLE := False; - - // Check if this is one of special images with no header - I := FindNoHeaderInfo(InputSize, NoHeaderIMGInfos); - - if I >= 0 then - begin - // It is no-header image - NewImage(NoHeaderIMGInfos[I].Width, NoHeaderIMGInfos[I].Height, ifIndex8, Images[0]); - end - else - begin - // Image has header so use its values - Read(Handle, @Hdr, SizeOf(Hdr)); - NewImage(Hdr.Width, Hdr.Height, ifIndex8, Images[0]); - IsRLE := Hdr.Unk = 2; - end; - - if (Hdr.Unk = 260) or (Hdr.Unk = 264) then - begin - // Compressed data from Arena: - // compression algorithm is unknown to me now - // if Unk = 264 then after header is word size of original data - // if Unk = 260 no size after head - Exit; - end; - - if not IsRLE then - begin - // Read uncompressed data - GetMem(Bits, Size); - Read(Handle, Bits, Size); - end - else - begin - GetMem(Data, Hdr.ImageSize); - try - // Read compressed data - Read(Handle, Data, Hdr.ImageSize); - DagRLEDecode(Data, Size, Bits); - finally - FreeMem(Data); - end; - end; - - // Palette handling - GetMem(Palette, 256 * SizeOf(TColor32Rec)); - - if (InputSize = Tell(Handle) + 768) then - begin - // Some IMG files has embedded palette - Read(Handle, @PalUsed, 768); - for I := Low(PalUsed) to High(PalUsed) do - begin - Palette[I].A := $FF; - Palette[I].R := PalUsed[I].B; - Palette[I].G := PalUsed[I].G; - Palette[I].B := PalUsed[I].R; - end; - Palette[0].A := 0; - end - else - Move(FARGBPalette[0], Palette[0], Length(FPalette) * SizeOf(TColor32Rec)); - - Result := True; - end; -end; - -function TIMGFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - Hdr: TImgHeader; - ImageToSave: TImageData; - MustBeFreed: Boolean; -begin - Result := False; - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - FillChar(Hdr, SizeOf(Hdr), 0); - Hdr.Width := Width; - Hdr.Height := Height; - // Hdr.ImageSize is Word so max size of image in bytes can be 65535 - if Width * Height > High(Word) then - RaiseImaging(SInvalidImageSize, [ImageToStr(ImageToSave)]); - Hdr.ImageSize := Width * Height; - Write(Handle, @Hdr, SizeOf(Hdr)); - Write(Handle, Bits, Hdr.ImageSize); - Result := True; - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Initial version created based on my older code (fixed few things). -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ElderImagerySky.pas b/3rd/Imaging/Extras/Extensions/ElderImagerySky.pas deleted file mode 100644 index fe68a02fa..000000000 --- a/3rd/Imaging/Extras/Extensions/ElderImagerySky.pas +++ /dev/null @@ -1,141 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for SKY file format used - in Daggerfall to store sky backdrops.} -unit ElderImagerySky; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, ImagingTypes, Imaging, ElderImagery; - -type - { Class for loading and saving of images in SKY format. It is - 8 bit indexed format found in Daggerfall, and maybe other old Bethesda - games. Files are named SKY##.DAT and each contains two sets of 32 images - (512 by 220 pixels), each with its palette. First set contains sky - without sun, seconf set sky with sun. } - TSKYFileFormat = class(TElderFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - end; - -implementation - -const - SSKYFormatName = 'Daggerfall Sky Images'; - SSKYMasks = '*.dagsky,sky??.dat'; - - SkyWidth = 512; - SkyHeight = 220; - SkyCount = 64; - DataOffset = 549120; - PalFileSize = 776; - SkyImageSize = SkyWidth * SkyHeight; - - SkyFileId: array[0..5] of Byte = ($08, $03, $00, $00, $23, $B1); - -{ TSKYFileFormat class implementation } - -procedure TSKYFileFormat.Define; -begin - inherited; - FFeatures := [ffLoad, ffMultiImage]; - FName := SSKYFormatName; - AddMasks(SSKYMasks); -end; - -function TSKYFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - I: Integer; - Pal24: TPalette24Size256; - - procedure CopyPalette(Dest: PPalette32); - var - I: Integer; - begin - for I := 0 to 255 do - begin - Dest[I].A := 255; - Dest[I].R := Pal24[I].B; - Dest[I].G := Pal24[I].G; - Dest[I].B := Pal24[I].R; - end; - end; - -begin - SetLength(Images, SkyCount); - for I := 0 to SkyCount - 1 do - begin - NewImage(SkyWidth, SkyHeight, ifIndex8, Images[I]); - // Read corresponding palette from file - GetIO.Seek(Handle, PalFileSize * (I mod 32) + 8, smFromBeginning); - GetIO.Read(Handle, @Pal24, SizeOf(Pal24)); - CopyPalette(Images[I].Palette); - // Now read image pixels - GetIO.Seek(Handle, DataOffset + I * SkyImageSize, smFromBeginning); - GetIO.Read(Handle, Images[I].Bits, SkyImageSize); - end; - Result := True; -end; - -function TSKYFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Id: array[0..5] of Byte; - ReadCount: Integer; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - FillChar(ID, SizeOf(Id), 0); - ReadCount := Read(Handle, @Id, SizeOf(Id)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(Id)) and - CompareMem(@Id, @SkyFileId, SizeOf(SkyFileId)); - end; -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Initial version created. -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ElderImageryTexture.pas b/3rd/Imaging/Extras/Extensions/ElderImageryTexture.pas deleted file mode 100644 index 3c255c736..000000000 --- a/3rd/Imaging/Extras/Extensions/ElderImageryTexture.pas +++ /dev/null @@ -1,390 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader of Daggerfall texture file format.} -unit ElderImageryTexture; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ElderImagery, ImagingIO, ImagingUtility; - -type - { Class that proveides loading of textures from TES2: Daggerfall - (works for Terminator: FS and maybe other games too). - Textures are stored in 8bit indexed format with external palette. - This format is very complicated (more images with subimages, - non-standard RLE, many unknowns) so module supports only loading. - These texture files cannot be recognized by filename extension because - their filenames are in form texture.### where # is number. Use filename - masks instead. Also note that after loading the input position is not set - at the exact end of the data so it's not "stream-safe".} - TTextureFileFormat = class(TElderFileFormat) - private - FLastTextureName: string; - { Deletes non-valid chars from texture name.} - function RepairName(const S: array of AnsiChar): string; - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - { Internal name of the last texture loaded.} - property LastTextureName: string read FLastTextureName; - end; - -const - { Metadata item id for accessing name of last loaded Daggetfall texture. - Value type is string.} - SMetaDagTextureName = 'DagTexture.Name'; - -implementation - -const - STextureFormatName = 'Daggerfall Texture'; - STextureMasks = '*.dagtexture,texture.*'; // fake ext first, it's used as format id - -type - { Main texture header.} - TTexHeader = packed record - ImgCount: Word; // Number of images in texture - TexName: array[0..23] of AnsiChar; // Name of texture - end; - - { Offset list for texture.} - TOffset = packed record - Type1: Word; // ?? - HdrOffset: LongInt; // Contains offsetof Img header from the origin - // of the file - Type2: Word; // ?? - Unk: LongWord; // Ranges from 0 to 4 (0 in 90%) - Null1: LongWord; // Always 0 - Null2: LongWord; // Always 0 - end; - - TOffsetList = array[Word] of TOffset; - POffsetList = ^TOffsetList; - - { Image header for texture.} - TTexImgHeader = packed record - XOff: Word; - YOff: Word; - Width: Word; - Height: Word; - Unk1: Word; // $0108 = Image has subimages which are RLE - // compressed data. - // $1108 = Image has RLE type compressed data with - // a row offset section before the single image data. - ImageSize: LongInt; // Image size (including header) - ImageOff: LongInt; // Pointer to start of image data from this header - Unk2: Word; // $0000 = Image has subimages in special - // compressed format. - // $00C0 = Usual value, regular single image. - // NonZero = Regular single image.Unknown what the - // differences indicate - SubImages: Word; // Number of subimages (1 = single image) - Unk3: LongInt; - Unk4: Word; - end; - -{ TTextureFileFormat } - -procedure TTextureFileFormat.Define; -begin - inherited; - FFeatures := [ffLoad, ffMultiImage]; - FName := STextureFormatName; - AddMasks(STextureMasks); -end; - -function TTextureFileFormat.RepairName(const S: array of AnsiChar): string; -var - I: LongInt; - First: Boolean; -begin - I := 1; - Result := string(S); - First := False; - while I <= Length(Result) do - begin - if (Ord(Result[I]) < 32) or ((Ord(Result[I]) = 32) and (not First)) then - begin - Delete(Result, I, 1); - end - else - begin - Inc(I); - First := True; - end; - end; -end; - -function TTextureFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Hdr: TTexHeader; - InputSize, BasePos, HdrPos, Index, I, Bias: LongInt; - List: POffsetList; - ImageHdr: TTexImgHeader; - - function AddImage(Width, Height: LongInt): LongInt; - begin - Result := Length(Images); - SetLength(Images, Length(Images) + 1); - NewImage(Width, Height, ifIndex8, Images[Result]); - Move(FARGBPalette[0], Images[Result].Palette[0], Length(FPalette) * SizeOf(TColor32Rec)); - end; - - procedure LoadUncompressed; - var - I: LongInt; - begin - // Add image and read its pixels row by row - Index := AddImage(ImageHdr.Width, ImageHdr.Height); - with GetIO, Images[Index] do - for I := 0 to ImageHdr.Height - 1 do - begin - Read(Handle, @PByteArray(Bits)[I * Width], Width); - Seek(Handle, 256 - Width, smFromCurrent); - end; - end; - - procedure LoadUncompressedSubImages; - var - SubOffs: packed array[0..63] of LongInt; - I, StartPos, J, WritePos: LongInt; - NumZeroes, NumImageBytes: Byte; - SubWidth, SubHeight: Word; - begin - // Read subimages offset list - StartPos := GetIO.Tell(Handle); - FillChar(SubOffs, SizeOf(SubOffs), 0); - GetIO.Read(Handle, @SubOffs, ImageHdr.SubImages * 4); - for I := 0 to ImageHdr.SubImages - 1 do - begin - // Add new subimage and load its pixels - Index := AddImage(ImageHdr.Width, ImageHdr.Height); - with GetIO, Images[Index] do - begin - Seek(Handle, StartPos + SubOffs[I], smFromBeginning); - Read(Handle, @SubWidth, 2); - Read(Handle, @SubHeight, 2); - // Read rows - for J := 0 to SubHeight - 1 do - begin - WritePos := 0; - while WritePos < SubWidth do - begin - // First there is a number of zero pixels that should be written - // to this row (slight compression as many images/sprites have - // many zero pixels) - Read(Handle, @NumZeroes, 1); - FillChar(PByteArray(Bits)[J * SubWidth + WritePos], NumZeroes, 0); - WritePos := WritePos + NumZeroes; - // Now there is a number of bytes that contain image data and should - // be copied to this row - Read(Handle, @NumImageBytes, 1); - Read(Handle, @PByteArray(Bits)[J * SubWidth + WritePos], NumImageBytes); - WritePos := WritePos + NumImageBytes; - end; - end; - end; - end; - end; - - procedure LoadRLESubImages; - type - TRowOff = packed record - Off: Word; - RLEStatus: Word; - end; - var - RowOffs: packed array[0..255] of TRowOff; - I, J, WritePos, NextOffsetPos: LongInt; - RLEData: Byte; - ByteCount, RowWidth: SmallInt; - begin - NextOffsetPos := GetIO.Tell(Handle); - for I := 0 to ImageHdr.SubImages - 1 do - begin - // Read row offsets for RLE subimage - FillChar(RowOffs, SizeOf(RowOffs), 0); - GetIO.Seek(Handle, NextOffsetPos, smFromBeginning); - GetIO.Read(Handle, @RowOffs, ImageHdr.Height * SizeOf(TRowOff)); - NextOffsetPos := GetIO.Tell(Handle); - // Add new image - Index := AddImage(ImageHdr.Width, ImageHdr.Height); - with GetIO, Images[Index] do - begin - for J := 0 to Height - 1 do - begin - // Seek to the beginning of the current row in the source - Seek(Handle, HdrPos + RowOffs[J].Off, smFromBeginning); - if RowOffs[J].RLEStatus = $8000 then - begin - // This row is compressed so it must be decoded (it is different - // from RLE in IMG/CIF files) - Read(Handle, @RowWidth, 2); - WritePos := 0; - while WritePos < RowWidth do - begin - Read(Handle, @ByteCount, 2); - if ByteCount > 0 then - begin - Read(Handle, @PByteArray(Bits)[J * Width + WritePos], ByteCount); - WritePos := WritePos + ByteCount; - end - else - begin - Read(Handle, @RLEData, 1); - FillChar(PByteArray(Bits)[J * Width + WritePos], -ByteCount, RLEData); - WritePos := WritePos - ByteCount; - end; - end; - end - else - // Read uncompressed row - Read(Handle, @PByteArray(Bits)[J * Width], Width); - end; - end; - end; - end; - -begin - Result := False; - SetLength(Images, 0); - with GetIO do - begin - InputSize := GetInputSize(GetIO, Handle); - BasePos := Tell(Handle); - Read(Handle, @Hdr, SizeOf(Hdr)); - FLastTextureName := RepairName(Hdr.TexName); - FMetadata.SetMetaItem(SMetaDagTextureName, FLastTextureName); - - if InputSize = 2586 then - begin - // Handle texture.001 and texture.000 files - // They contain only indices to palette so we create small - // images with colors defined by these indices - Bias := 0; - if Pos('B', FLastTextureName) > 0 then - Bias := 128; - for I := 0 to Hdr.ImgCount - 1 do - begin - Index := AddImage(16, 16); - FillMemoryByte(Images[Index].Bits, Images[Index].Size, I + Bias); - end; - end - else if (InputSize = 46) or (InputSize = 126) or (InputSize = 266) then - begin - // These textures don't contain any image data - Exit; - end - else - begin - GetMem(List, Hdr.ImgCount * SizeOf(TOffset)); - try - // Load offsets - for I := 0 to Hdr.ImgCount - 1 do - Read(Handle, @List[I], SizeOf(TOffset)); - // Load subimages one by one - for I := 0 to Hdr.ImgCount - 1 do - begin - // Jump at position of image header - Seek(Handle, BasePos + List[I].HdrOffset, smFromBeginning); - HdrPos := Tell(Handle); - Read(Handle, @ImageHdr, SizeOf(ImageHdr)); - Seek(Handle, HdrPos + ImageHdr.ImageOff, smFromBeginning); - // According to number of subimages and RLE settings appropriate - // procedure is called to load subimages - if ImageHdr.SubImages = 1 then - begin - if (ImageHdr.Unk1 <> $1108) and (ImageHdr.Unk1 <> $0108) then - LoadUncompressed - else - LoadRLESubImages; - end - else - begin - if (ImageHdr.Unk1 <> $0108) then - LoadUncompressedSubImages - else - LoadRLESubImages; - end; - end; - finally - FreeMem(List); - end; - end; - Result := True; - end; -end; - -function TTextureFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Hdr: TTexHeader; - ReadCount, I: LongInt; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(Hdr)) and (Hdr.ImgCount > 0) and - (Hdr.ImgCount <= 2048); - if Result then - begin - for I := 0 to High(Hdr.TexName) do - begin - if not (Hdr.TexName[I] in [#0, #32, 'a'..'z', 'A'..'Z', '0'..'9', '.', - '(', ')', '_', ',', '-', '''', '"', '/', '\', #9, '+']) then - begin - Result := False; - Exit; - end; - end; - end; - end; -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Last texture name now accessible trough metadata interface. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Initial version created based on my older code (fixed few things). -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingBinary.pas b/3rd/Imaging/Extras/Extensions/ImagingBinary.pas deleted file mode 100644 index 15dc5afb2..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingBinary.pas +++ /dev/null @@ -1,457 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ Unit with operations on binary images. Binary images in Imaging are - ifGray8 images where pixels with value 0 are considerend off, an pixels > 0 - are on. - Note: Native ifBinary data format was later added to Imaging. However, - these functions still use ifGray8 for representation for less complex - and faster processing. ifBinary is meant moreless like interchange - format for IO file formats. } -unit ImagingBinary; - -{$I ImagingOptions.inc} - -interface - -uses - Types, ImagingTypes, Imaging, ImagingFormats, ImagingUtility; - -type - { Basic morphologic operators.} - TMorphologyOp = ( - moErode, // Erosion - moDilate // Dilatation - ); - - { Structuring element for morphology operations. Use ones and - zeroes to define your struct elements.} - TStructElement = array of array of Byte; - - TCalcSkewAngleStats = record - PixelCount: Integer; - TestedPixels: Integer; - AccumulatorSize: Integer; - AccumulatedCounts: Integer; - BestCount: Integer; - end; - PCalcSkewAngleStats = ^TCalcSkewAngleStats; - -{ Thresholding using Otsu's method (which chooses the threshold - to minimize the intraclass variance of the black and white pixels!). - Functions returns calculated threshold level value [0..255]. - If BinarizeImage is True then the Image is automatically converted to binary using - computed threshold level.} -function OtsuThresholding(var Image: TImageData; BinarizeImage: Boolean = False): Integer; -{ Applies basic morphology operators (Erode/Dilate) on Image using given structuring element - Strel. You can do composite operations (Open/Close) by calling this function - twice each time with different operator.} -procedure Morphology(var Image: TImageData; const Strel: TStructElement; Op: TMorphologyOp); -{ Calculates rotation angle for given 8bit grayscale image. - Useful for finding skew of scanned documents etc. - Uses Hough transform internally. - MaxAngle is maximal (abs. value) expected skew angle in degrees (to speed things up) - and Threshold (0..255) is used to classify pixel as black (text) or white (background). - Area of interest rectangle can be defined to restrict the detection to - work only in defined part of image (useful when the document has text only in - smaller area of page and non-text features outside the area confuse the rotation detector). - Various calculations stats can be retrieved by passing Stats parameter.} -function CalcRotationAngle(MaxAngle: Integer; Treshold: Integer; - Width, Height: Integer; Pixels: PByteArray; DetectionArea: PRect = nil; - Stats: PCalcSkewAngleStats = nil): Double; -{ Deskews given image. Finds rotation angle and rotates image accordingly. - Works best on low-color document-like images (scans). - MaxAngle is maximal (abs. value) expected skew angle in degrees (to speed things up) - and Threshold (0..255) is used to classify pixel as black (text) or white (background). - If Treshold=-1 then auto threshold calculated by OtsuThresholding is used.} -procedure DeskewImage(var Image: TImageData; MaxAngle: Integer = 10; Threshold: Integer = -1); - -implementation - -function OtsuThresholding(var Image: TImageData; BinarizeImage: Boolean): Integer; -var - Histogram: array[Byte] of Single; - Level, Max, Min, I, J, NumPixels: Integer; - Pix: PByte; - Mean, Variance: Single; - Mu, Omega, LevelMean, LargestMu: Single; -begin - Assert(Image.Format = ifGray8); - - FillChar(Histogram, SizeOf(Histogram), 0); - Min := 255; - Max := 0; - Level := 0; - NumPixels := Image.Width * Image.Height; - Pix := Image.Bits; - - // Compute histogram and determine min and max pixel values - for I := 0 to NumPixels - 1 do - begin - Histogram[Pix^] := Histogram[Pix^] + 1.0; - if Pix^ < Min then - Min := Pix^; - if Pix^ > Max then - Max := Pix^; - Inc(Pix); - end; - - // Normalize histogram - for I := 0 to 255 do - Histogram[I] := Histogram[I] / NumPixels; - - // Compute image mean and variance - Mean := 0.0; - Variance := 0.0; - for I := 0 to 255 do - Mean := Mean + (I + 1) * Histogram[I]; - for I := 0 to 255 do - Variance := Variance + Sqr(I + 1 - Mean) * Histogram[I]; - - // Now finally compute threshold level - LargestMu := 0; - - for I := 0 to 255 do - begin - Omega := 0.0; - LevelMean := 0.0; - - for J := 0 to I - 1 do - begin - Omega := Omega + Histogram[J]; - LevelMean := LevelMean + (J + 1) * Histogram[J]; - end; - - Mu := Sqr(Mean * Omega - LevelMean); - Omega := Omega * (1.0 - Omega); - - if Omega > 0.0 then - Mu := Mu / Omega - else - Mu := 0; - - if Mu > LargestMu then - begin - LargestMu := Mu; - Level := I; - end; - end; - - if BinarizeImage then - begin - // Do thresholding using computed level - Pix := Image.Bits; - for I := 0 to Image.Width * Image.Height - 1 do - begin - if Pix^ >= Level then - Pix^ := 255 - else - Pix^ := 0; - Inc(Pix); - end; - end; - - Result := Level; -end; - -procedure Morphology(var Image: TImageData; const Strel: TStructElement; Op: TMorphologyOp); -var - X, Y, I, J: Integer; - SWidth, SHeight, PixCount, PixVal, NumOnes, PosX, PosY: Integer; - ImgOut: TImageData; - OutPix: PByte; -begin - Assert(Image.Format = ifGray8); - Assert((Length(Strel) > 0) and (Length(Strel[0]) > 0)); - - SWidth := Length(Strel); - SHeight := Length(Strel[0]); - - NumOnes := 0; - if Op = moErode then - begin - // We need to know number of ones in the strel for erosion - for I := 0 to SWidth - 1 do - for J := 0 to SHeight - 1 do - NumOnes := NumOnes + Strel[I, J]; - end; - - InitImage(ImgOut); - NewImage(Image.Width, Image.Height, ifGray8, ImgOut); - OutPix := ImgOut.Bits; - - for J := 0 to Image.Height - 1 do - for I := 0 to Image.Width - 1 do - begin - PixCount := 0; - - for X := 0 to SWidth - 1 do - begin - PosX := ClampInt(X + I - SWidth div 2, 0, Image.Width - 1); - for Y := 0 to SHeight - 1 do - begin - PosY := ClampInt(Y + J - SHeight div 2, 0, Image.Height - 1); - if (PosX >= 0) and (PosX < Image.Width) and - (PosY >= 0) and (PosY < Image.Height) then - begin - PixVal := PByteArray(Image.Bits)[PosY * Image.Width + PosX]; - end - else - PixVal := 0; - - if (Strel[X, Y] > 0) and (PixVal > 0) then - Inc(PixCount); - end; - end; - - case Op of - moErode: OutPix^ := Iff(PixCount = NumOnes, 255, 0); - moDilate: OutPix^ := Iff(PixCount > 0, 255, 0); - end; - - Inc(OutPix); - end; - - FreeImage(Image); - Image := ImgOut; -end; - -function CalcRotationAngle(MaxAngle: Integer; Treshold: Integer; - Width, Height: Integer; Pixels: PByteArray; DetectionArea: PRect; Stats: PCalcSkewAngleStats): Double; -const - // Number of "best" lines we take into account when determining - // resulting rotation angle (lines with most votes). - BestLinesCount = 20; - // Angle step used in alpha parameter quantization - AlphaStep = 0.1; -type - TLine = record - Count: Integer; - Index: Integer; - Alpha: Double; - D: Double; - end; - TLineArray = array of TLine; -var - AlphaStart, MinD, SumAngles: Double; - AlphaSteps, DCount, AccumulatorSize, I, AccumulatedCounts: Integer; - BestLines: TLineArray; - HoughAccumulator: array of Integer; - PageWidth, PageHeight: Integer; - ContentRect: TRect; - - // Classifies pixel at [X, Y] as black or white using threshold. - function IsPixelBlack(X, Y: Integer): Boolean; - begin - Result := Pixels[Y * Width + X] < Treshold; - end; - - // Calculates alpha parameter for given angle step. - function GetAlpha(Index: Integer): Double; - begin - Result := AlphaStart + Index * AlphaStep; - end; - - function CalcDIndex(D: Double): Integer; - begin - Result := Trunc(D - MinD); - end; - - // Calculates angle and distance parameters for all lines - // going through point [X, Y]. - procedure CalcLines(X, Y: Integer); - var - D, Rads: Double; - I, DIndex, Index: Integer; - begin - for I := 0 to AlphaSteps - 1 do - begin - Rads := GetAlpha(I) * Pi / 180; // Angle for current step in radians - D := Y * Cos(Rads) - X * Sin(Rads); // Parameter D of the line y=tg(alpha)x + d - DIndex := CalcDIndex(D); - Index := DIndex * AlphaSteps + I; - HoughAccumulator[Index] := HoughAccumulator[Index] + 1; // Add one vote for current line - end; - end; - - // Uses Hough transform to calculate all lines that intersect - // interesting points (those classified as beign on base line of the text). - procedure CalcHoughTransform; - var - Y, X: Integer; - begin - for Y := 0 to PageHeight - 1 do - for X := 0 to PageWidth - 1 do - begin - if IsPixelBlack(ContentRect.Left + X, ContentRect.Top + Y) and - not IsPixelBlack(ContentRect.Left + X, ContentRect.Top + Y + 1) then - begin - CalcLines(X, Y); - end; - end; - end; - - // Chooses "best" lines (with the most votes) from the accumulator - function GetBestLines(Count: Integer): TLineArray; - var - I, J, DIndex, AlphaIndex: Integer; - Temp: TLine; - begin - AccumulatedCounts := 0; - SetLength(Result, Count); - - for I := 0 to AccumulatorSize - 1 do - begin - if HoughAccumulator[I] > Result[Count - 1].Count then - begin - // Current line has more votes than the last selected one, - // let's put it the pot - Result[Count - 1].Count := HoughAccumulator[I]; - Result[Count - 1].Index := I; - J := Count - 1; - - // Sort the lines based on number of votes - while (J > 0) and (Result[J].Count > Result[J - 1].Count) do - begin - Temp := Result[J]; - Result[J] := Result[J - 1]; - Result[J - 1] := Temp; - J := J - 1; - end; - end; - - AccumulatedCounts := AccumulatedCounts + HoughAccumulator[I]; - end; - - for I := 0 to Count - 1 do - begin - // Caculate line angle and distance according to index in the accumulator - DIndex := Result[I].Index div AlphaSteps; - AlphaIndex := Result[I].Index - DIndex * AlphaSteps; - Result[I].Alpha := GetAlpha(AlphaIndex); - Result[I].D := DIndex + MinD; - end; - end; - -begin - // Use supplied page content rect or just the whole image - ContentRect := Rect(0, 0, Width, Height); - if DetectionArea <> nil then - begin - Assert((RectWidth(DetectionArea^) <= Width) and (RectHeight(DetectionArea^) <= Height)); - ContentRect := DetectionArea^; - end; - - PageWidth := ContentRect.Right - ContentRect.Left; - PageHeight := ContentRect.Bottom - ContentRect.Top; - - AlphaStart := -MaxAngle; - AlphaSteps := Round(2 * MaxAngle / AlphaStep); // Number of angle steps = samples from interval <-MaxAngle, MaxAngle> - MinD := -PageWidth; - DCount := 2 * (PageWidth + PageHeight); - - // Determine the size of line accumulator - AccumulatorSize := DCount * AlphaSteps; - SetLength(HoughAccumulator, AccumulatorSize); - - // Calculate Hough transform - CalcHoughTransform; - - // Get the best lines with most votes - BestLines := GetBestLines(BestLinesCount); - - // Average angles of the selected lines to get the rotation angle of the image - SumAngles := 0; - for I := 0 to BestLinesCount - 1 do - SumAngles := SumAngles + BestLines[I].Alpha; - - Result := SumAngles / BestLinesCount; - - if Stats <> nil then - begin - Stats.BestCount := BestLines[0].Count; - Stats.PixelCount := PageWidth * PageHeight; - Stats.AccumulatorSize := AccumulatorSize; - Stats.AccumulatedCounts := AccumulatedCounts; - Stats.TestedPixels := AccumulatedCounts div AlphaSteps; - end; -end; - -procedure DeskewImage(var Image: TImageData; MaxAngle: Integer; Threshold: Integer); -var - Angle: Double; - OutputImage: TImageData; - Info: TImageFormatInfo; -begin - if not TestImage(Image) then - raise EImagingBadImage.Create; - - // Clone input image and convert it to 8bit grayscale. This will be our - // working image. - CloneImage(Image, OutputImage); - ConvertImage(Image, ifGray8); - - if Threshold < 0 then - begin - // Determine the threshold automatically if needed. - Threshold := OtsuThresholding(Image); - end; - - // Main step - calculate image rotation angle - Angle := CalcRotationAngle(MaxAngle, Threshold, Image.Width, Image.Height, Image.Bits); - - // Finally, rotate the image. We rotate the original input image, not the working - // one so the color space is preserved. - GetImageFormatInfo(OutputImage.Format, Info); - if Info.IsIndexed or Info.IsSpecial then - ConvertImage(OutputImage, ifA8R8G8B8); // Rotation doesn't like indexed and compressed images - RotateImage(OutputImage, Angle); - - FreeImage(Image); - Image := OutputImage; -end; - - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77 ------------------------------------------------------- - - OtsuThresholding signature changed, now it's a function and - always returns the computed level. - - Extended CalcRotationAngle, added margins and stats. - - Added CalcRotationAngle and DeskewImage functions. - - -- 0.25.0 Changes/Bug Fixes ----------------------------------- - - Unit created with basic stuff (otsu and erode/dilate morphology ops). - -} - -end. - diff --git a/3rd/Imaging/Extras/Extensions/ImagingCompare.pas b/3rd/Imaging/Extras/Extensions/ImagingCompare.pas deleted file mode 100644 index 4f0c8aee2..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingCompare.pas +++ /dev/null @@ -1,131 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ - This unit contains various image comparing functions and image difference - computations. -} -unit ImagingCompare; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, ImagingTypes, Imaging, ImagingFormats, ImagingUtility; - -{ Computes various error metrics for two images. Images must have - the same size and format. Only formats with 1, 2, and 4 byte samples are - supported (no indexed, compressed, etc.).} -procedure ComputeErrorMetrics(const Image1, Image2: TImageData; - var PSNR, MSE, RMSE, PAE, MAE: Single); - -implementation - -procedure ComputeErrorMetrics(const Image1, Image2: TImageData; - var PSNR, MSE, RMSE, PAE, MAE: Single); -var - I: Integer; - Info: TImageFormatInfo; - Samples, Bps: Integer; - PixelPtr1, PixelPtr2: PByte; - Diff, MaxSample: Single; -begin - GetImageFormatInfo(Image1.Format, Info); - Bps := Info.ChannelCount div Info.BytesPerPixel; - Assert((Image1.Width = Image2.Width) and (Image1.Height = Image2.Height) and - (Image1.Format = Image2.Format)); - Assert(not Info.IsIndexed and not Info.IsSpecial and not Info.UsePixelFormat - and (Bps in [1, 2, 4])); - - Diff := 0; - PSNR := 0; - MSE := 0; - RMSE := 0; - PAE := 0; - MAE := 0; - PixelPtr1 := Image1.Bits; - PixelPtr2 := Image2.Bits; - Samples := Image1.Width * Image1.Height * Info.ChannelCount; - - for I := 0 to Samples - 1 do - begin - // Compute difference betwen pixels - case Bps of - 1: Diff := Abs(PixelPtr2^ - PixelPtr1^); - 2: - begin - if Info.IsFloatingPoint then - Diff := Abs(HalfToFloat(PWord(PixelPtr2)^) - HalfToFloat(PWord(PixelPtr1)^)) - else - Diff := Abs(PWord(PixelPtr2)^ - PWord(PixelPtr1)^); - end; - 4: - begin - if Info.IsFloatingPoint then - Diff := Abs(PSingle(PixelPtr2)^ - PSingle(PixelPtr1)^) - else - Diff := Abs(PLongWord(PixelPtr2)^ - PLongWord(PixelPtr1)^); - end; - end; - - // Update metrics - MAE := MAE + Diff; - PAE := MaxFloat(PAE, Diff); - MSE := MSE + Diff * Diff; - - Inc(PixelPtr1, Bps); - Inc(PixelPtr2, Bps); - end; - - if Info.IsFloatingPoint then - MaxSample := 1.0 - else - MaxSample := Pow2Int(Bps * 8) - 1; - - // Final metrics calculations - MAE := MAE / Samples; - MSE := MSE / Samples; - RMSE := Sqrt(MSE); - if RMSE < 0.0001 then - PSNR := 1e06 - else - PSNR := 20 * Log10(MaxSample / RMSE); -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - none - - -- 0.26.5 Changes/Bug Fixes ----------------------------------- - - Added ComputeErrorMetrics. - - Unit created. -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingDirect3D9.pas b/3rd/Imaging/Extras/Extensions/ImagingDirect3D9.pas deleted file mode 100644 index d3956a6a7..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingDirect3D9.pas +++ /dev/null @@ -1,784 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains functions for loading and saving Direct3D 9 textures - using Imaging and for converting images to textures and vice versa.} -unit ImagingDirect3D9; - -{$I ImagingOptions.inc} - -interface - -uses - Windows, SysUtils, Classes, ImagingTypes, Imaging, ImagingFormats, - ImagingUtility, Direct3D9; - -type - { Contains some texture capabilities of Direct3D device.} - TD3DTextureCaps = record - PowerOfTwo: Boolean; - CubePowerOfTwo: Boolean; - VolumePowerOfTwo: Boolean; - MaxWidth: LongInt; - MaxHeight: LongInt; - DXTCompression: Boolean; - ATI3DcCompression: Boolean; - MaxAnisotropy: LongInt; - MaxSimultaneousTextures: LongInt; - end; - -{ Returns some texture capabilities of the given D3D device.} -function GetDeviceTextureCaps(Device: IDirect3DDevice9; var Caps: TD3DTextureCaps): Boolean; -{ Returns True if the given Format is valid texture format for the given D3D device.} -function IsD3DFormatSupported(Device: IDirect3DDevice9; Format: TD3DFormat): Boolean; -{ Returns D3D format equivalent to the given TImageFormatInfo. It returns D3DFMT_UNKNOWN - if equivalent cannot be found. If returned ConversionTo is not the same - as input format then image must be first converted to this format for - the returned D3D format to be valid. You should also check if returned D3D - format is supported by the current D3D device using IsD3DFormatSupported.} -function ImageFormatToD3DFormat(const Format: TImageFormat; var ConversionTo: TImageFormat): TD3DFormat; -{ Returns TImageFormat equivalent to the given D3D format. If equivalent does - not exist ifUnknown is returned.} -function D3DFormatToImageFormat(Format: TD3DFormat): TImageFormat; - -{ LoadD3DTextureFromFile and similar functions use these default values: - All mipmap levels are created, Pool is D3DPOOL_MANAGED, - Usage is 0, Format and size are taken from image.} - -{ Creates D3D texture from image in file in format supported by Imaging. - You can use CreatedWidth and Height parameters to query dimensions of created textures - (it could differ from dimensions of source image).} -function LoadD3DTextureFromFile(const FileName: string; Device: IDirect3DDevice9; - var Texture: IDirect3DTexture9; CreatedWidth: PLongInt = nil; - CreatedHeight: PLongInt = nil): Boolean; -{ Creates D3D texture from image in stream in format supported by Imaging. - You can use CreatedWidth and Height parameters to query dimensions of created textures - (it could differ from dimensions of source image).} -function LoadD3DTextureFromStream(Stream: TStream; Device: IDirect3DDevice9; - var Texture: IDirect3DTexture9; CreatedWidth: PLongInt = nil; - CreatedHeight: PLongInt = nil): Boolean; -{ Creates D3D texture from image in memory in format supported by Imaging. - You can use CreatedWidth and Height parameters to query dimensions of created textures - (it could differ from dimensions of source image).} -function LoadD3DTextureFromMemory(Data: Pointer; Size: LongInt; - Device: IDirect3DDevice9; var Texture: IDirect3DTexture9; - CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): Boolean; - -{ Converts TImageData structure to IDirect3DTexture9 texture. - Input images is used as main mipmap level and additional requested - levels are generated from this one. For the details on parameters - look at CreateD3DTextureFromMultiImage function.} -function CreateD3DTextureFromImage(const Image: TImageData; - Device: IDirect3DDevice9; var Texture: IDirect3DTexture9; Width: LongInt = 0; - Height: LongInt = 0; MipLevels: LongInt = 0; Usage: LongWord = 0; - Format: TD3DFormat = D3DFMT_UNKNOWN; Pool: TD3DPool = D3DPOOL_MANAGED; - CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): Boolean; -{ Converts images in TDymImageDataArray to one IDirect3DTexture9 texture. - First image in array is used as main mipmap level and additional images - are used as subsequent levels. If MipLevels is larger than number of images - in array missing levels are automatically generated. - If Device supports only power of two sized textures images are resized. - If Format is D3DFMT_UNKNOWN then format of input image is used. - If desired texture format is not supported by hardware default - A8R8G8B8 format is used instead. - Width and Height of 0 mean use width and height of main image. - MipLevels set to 0 mean build all possible levels. For details on - Usage and Pool parameters look at DirectX SDK docs. - You can use CreatedWidth and CreatedHeight parameters to query dimensions of - created texture's largest mipmap level (it could differ from dimensions - of source image).} -function CreateD3DTextureFromMultiImage(const Images: TDynImageDataArray; - Device: IDirect3DDevice9; var Texture: IDirect3DTexture9; Width: LongInt = 0; - Height: LongInt = 0; MipLevels: LongInt = 0; Usage: LongWord = 0; - Format: TD3DFormat = D3DFMT_UNKNOWN; Pool: TD3DPool = D3DPOOL_MANAGED; - CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): Boolean; - -{ Saves D3D texture to file in one of formats supported by Imaging. - Saves all present mipmap levels.} -function SaveD3DTextureToFile(const FileName: string; const Texture: IDirect3DTexture9): Boolean; -{ Saves D3D texture to stream in one of formats supported by Imaging. - Saves all present mipmap levels.} -function SaveD3DTextureToStream(const Ext: string; Stream: TStream; const Texture: IDirect3DTexture9): Boolean; -{ Saves D3D texture to memory in one of formats supported by Imaging. - Saves all present mipmap levels.} -function SaveD3DTextureToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Texture: IDirect3DTexture9): Boolean; - -{ Converts main level of the D3D texture to TImageData strucrue. OverrideFormat - can be used to convert output image to the specified format rather - than use the format taken from D3D texture, ifUnknown means no conversion.} -function CreateImageFromD3DTexture(const Texture: IDirect3DTexture9; - var Image: TImageData; OverrideFormat: TImageFormat = ifUnknown): Boolean; -{ Converts D3D texture to TDynImageDataArray array of images. You can specify - how many mipmap levels of the input texture you want to be converted - (default is all levels). OverrideFormat can be used to convert output images to - the specified format rather than use the format taken from D3D texture, - ifUnknown means no conversion.} -function CreateMultiImageFromD3DTexture(const Texture: IDirect3DTexture9; - var Images: TDynImageDataArray; MipLevels: LongInt = 0; - OverrideFormat: TImageFormat = ifUnknown): Boolean; - -{ Creates contents of Image to D3D surface. Surface must exist before calling this - function so it can be used to fill various types of surfaces (textures surfaces, - offscreen, depth buffer, ...). Surface must be lockable for function to work.} -function CreateD3DSurfaceFromImage(const Image: TImageData; Surface: IDirect3DSurface9): Boolean; -{ Creates image filled with contents of input D3D surface. - Surface must be lockable for function to work.} -function CreateImageFromD3DSurface(Surface: IDirect3DSurface9; var Image: TImageData): Boolean; - -const - D3DFMT_ATI1 = TD3DFormat(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or - (Byte('1') shl 24)); - D3DFMT_ATI2 = TD3DFormat(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or - (Byte('2') shl 24)); - -implementation - -const - DefaultUsage = 0; - DefaultPool = D3DPOOL_MANAGED; - -function GetDeviceTextureCaps(Device: IDirect3DDevice9; - var Caps: TD3DTextureCaps): Boolean; -var - D3DCaps: TD3DCaps9; -begin - FillChar(Caps, SizeOf(Caps), 0); - Result := Device <> nil; - // Get D3D Device Caps and fill our caps - if Result and (Device.GetDeviceCaps(D3DCaps) = D3D_OK) then - begin - Caps.PowerOfTwo := (D3DCaps.TextureCaps and D3DPTEXTURECAPS_POW2) = D3DPTEXTURECAPS_POW2; - Caps.CubePowerOfTwo := (D3DCaps.TextureCaps and D3DPTEXTURECAPS_CUBEMAP_POW2) = D3DPTEXTURECAPS_CUBEMAP_POW2; - Caps.VolumePowerOfTwo := (D3DCaps.TextureCaps and D3DPTEXTURECAPS_VOLUMEMAP_POW2) = D3DPTEXTURECAPS_VOLUMEMAP_POW2; - Caps.MaxWidth := D3DCaps.MaxTextureWidth; - Caps.MaxHeight := D3DCaps.MaxTextureHeight; - if (D3DCaps.TextureFilterCaps and D3DPTFILTERCAPS_MINFANISOTROPIC) = D3DPTFILTERCAPS_MINFANISOTROPIC then - Caps.MaxAnisotropy := D3DCaps.MaxAnisotropy - else - Caps.MaxAnisotropy := 0; - Caps.MaxSimultaneousTextures := D3DCaps.MaxSimultaneousTextures; - // Texture format caps - Caps.DXTCompression := IsD3DFormatSupported(Device, D3DFMT_DXT1) and - IsD3DFormatSupported(Device, D3DFMT_DXT3) and IsD3DFormatSupported(Device, D3DFMT_DXT5); - Caps.ATI3DcCompression := IsD3DFormatSupported(Device, D3DFMT_ATI1) and - IsD3DFormatSupported(Device, D3DFMT_ATI2); - end; -end; - -function IsD3DFormatSupported(Device: IDirect3DDevice9; Format: TD3DFormat): Boolean; -var - Direct3D: IDirect3D9; - Mode: TD3DDisplayMode; - Hr: HResult; -begin - Result := False; - if Device <> nil then - begin - Device.GetDirect3D(Direct3D); - if Direct3D <> nil then - begin - Direct3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, Mode); - Hr := Direct3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, Mode.Format, 0, D3DRTYPE_TEXTURE, Format); - Result := Succeeded(Hr); - end; - end; -end; - -function ImageFormatToD3DFormat(const Format: TImageFormat; var ConversionTo: TImageFormat): TD3DFormat; -begin - Result := D3DFMT_UNKNOWN; - ConversionTo := Format; - case Format of - ifIndex8: Result := D3DFMT_P8; - ifGray8: Result := D3DFMT_L8; - ifA8Gray8: Result := D3DFMT_A8L8; - ifGray16: Result := D3DFMT_L16; - ifGray32, - ifGray64: - begin - Result := D3DFMT_L16; - ConversionTo := ifGray16; - end; - ifA16Gray16: - begin - Result := D3DFMT_A8L8; - ConversionTo := ifA8Gray8; - end; - ifX5R1G1B1: - begin - Result := D3DFMT_R3G3B2; - ConversionTo := ifR3G3B2; - end; - ifR3G3B2: Result := D3DFMT_R3G3B2; - ifR5G6B5: Result := D3DFMT_R5G6B5; - ifA1R5G5B5: Result := D3DFMT_A1R5G5B5; - ifA4R4G4B4: Result := D3DFMT_A4R4G4B4; - ifX1R5G5B5: Result := D3DFMT_X1R5G5B5; - ifX4R4G4B4: Result := D3DFMT_X4R4G4B4; - ifR8G8B8: Result := D3DFMT_R8G8B8; - ifA8R8G8B8: Result := D3DFMT_A8R8G8B8; - ifX8R8G8B8: Result := D3DFMT_X8R8G8B8; - ifR16G16B16, - ifA16R16G16B16, - ifB16G16R16: - begin - Result := D3DFMT_A16B16G16R16; - ConversionTo := ifA16B16G16R16; - end; - ifA16B16G16R16: Result := D3DFMT_A16B16G16R16; - ifR32F: Result := D3DFMT_R32F; - ifA32B32G32R32F: Result := D3DFMT_A32B32G32R32F; - ifA32R32G32B32F: - begin - Result := D3DFMT_A32B32G32R32F; - ConversionTo := ifA32B32G32R32F; - end; - ifR16F: Result := D3DFMT_R16F; - ifA16B16G16R16F: Result := D3DFMT_A16B16G16R16F; - ifA16R16G16B16F: - begin - Result := D3DFMT_A16B16G16R16F; - ConversionTo := ifA16B16G16R16F; - end; - ifDXT1: Result := D3DFMT_DXT1; - ifDXT3: Result := D3DFMT_DXT3; - ifDXT5: Result := D3DFMT_DXT5; - ifATI1N: Result := D3DFMT_ATI1; - ifATI2N: Result := D3DFMT_ATI2; - end; -end; - -function D3DFormatToImageFormat(Format: TD3DFormat): TImageFormat; -begin - Result := ifUnknown; - case Format of - D3DFMT_P8: Result := ifIndex8; - D3DFMT_A8, - D3DFMT_L8: Result := ifGray8; - D3DFMT_A8L8, - D3DFMT_V8U8: Result := ifA8Gray8; - D3DFMT_L16: Result := ifGray16; - D3DFMT_R3G3B2: Result := ifR3G3B2; - D3DFMT_R5G6B5: Result := ifR5G6B5; - D3DFMT_X1R5G5B5: Result := ifX1R5G5B5; - D3DFMT_A1R5G5B5: Result := ifA1R5G5B5; - D3DFMT_A4R4G4B4: Result := ifA4R4G4B4; - D3DFMT_X4R4G4B4: Result := ifX4R4G4B4; - D3DFMT_R8G8B8: Result := ifR8G8B8; - D3DFMT_A8R8G8B8, - D3DFMT_Q8W8V8U8, - D3DFMT_A8B8G8R8: Result := ifA8R8G8B8; - D3DFMT_X8R8G8B8, - D3DFMT_X8L8V8U8, - D3DFMT_X8B8G8R8: Result := ifX8R8G8B8; - D3DFMT_A16B16G16R16, - D3DFMT_Q16W16V16U16: Result := ifA16B16G16R16; - D3DFMT_R32F: Result := ifR32F; - D3DFMT_A32B32G32R32F: Result := ifA32B32G32R32F; - D3DFMT_R16F: Result := ifR16F; - D3DFMT_A16B16G16R16F: Result := ifA16B16G16R16F; - D3DFMT_DXT1: Result := ifDXT1; - D3DFMT_DXT3: Result := ifDXT3; - D3DFMT_DXT5: Result := ifDXT5; - D3DFMT_ATI1: Result := ifATI1N; - D3DFMT_ATI2: Result := ifATI2N; - end; -end; - -function LoadD3DTextureFromFile(const FileName: string; Device: IDirect3DDevice9; - var Texture: IDirect3DTexture9; CreatedWidth, CreatedHeight: PLongInt): Boolean; -var - Images: TDynImageDataArray; -begin - if LoadMultiImageFromFile(FileName, Images) and (Length(Images) > 0) then - begin - Result := CreateD3DTextureFromMultiImage(Images, Device, Texture, - Images[0].Width, Images[0].Height, 0, DefaultUsage, D3DFMT_UNKNOWN, - DefaultPool, CreatedWidth, CreatedHeight); - end - else - Result := False; - FreeImagesInArray(Images); -end; - -function LoadD3DTextureFromStream(Stream: TStream; Device: IDirect3DDevice9; - var Texture: IDirect3DTexture9; CreatedWidth, CreatedHeight: PLongInt): Boolean; -var - Images: TDynImageDataArray; -begin - if LoadMultiImageFromStream(Stream, Images) and (Length(Images) > 0) then - begin - Result := CreateD3DTextureFromMultiImage(Images, Device, Texture, - Images[0].Width, Images[0].Height, 0, DefaultUsage, D3DFMT_UNKNOWN, - DefaultPool, CreatedWidth, CreatedHeight); - end - else - Result := False; - FreeImagesInArray(Images); -end; - -function LoadD3DTextureFromMemory(Data: Pointer; Size: LongInt; - Device: IDirect3DDevice9; var Texture: IDirect3DTexture9; - CreatedWidth, CreatedHeight: PLongInt): Boolean; -var - Images: TDynImageDataArray; -begin - if LoadMultiImageFromMemory(Data, Size, Images) and (Length(Images) > 0) then - begin - Result := CreateD3DTextureFromMultiImage(Images, Device, Texture, Images[0].Width, - Images[0].Height, 0, DefaultUsage, D3DFMT_UNKNOWN, DefaultPool, - CreatedWidth, CreatedHeight); - end - else - Result := False; - FreeImagesInArray(Images); -end; - -function CreateD3DTextureFromImage(const Image: TImageData; - Device: IDirect3DDevice9; var Texture: IDirect3DTexture9; Width, - Height, MipLevels: LongInt; Usage: LongWord; Format: TD3DFormat; - Pool: TD3DPool; CreatedWidth, CreatedHeight: PLongInt): Boolean; -var - Arr: TDynImageDataArray; -begin - // Just calls function operating on image arrays - SetLength(Arr, 1); - Arr[0] := Image; - Result := CreateD3DTextureFromMultiImage(Arr, Device, Texture, Width, Height, - MipLevels, Usage, Format, Pool, CreatedWidth, CreatedHeight); -end; - -procedure FillLockedRectWithImage(var Rect: TD3DLockedRect; const Image: TImageData); -var - I, LineBytes: LongInt; - Info: TImageFormatInfo; -begin - GetImageFormatInfo(Image.Format, Info); - LineBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1); - // Pixels of the image are copied to D3D texture - if (not Info.IsSpecial) and (LineBytes < Rect.Pitch) then - begin - for I := 0 to Image.Height - 1 do - Move(PByteArray(Image.Bits)[I * LineBytes], - PByteArray(Rect.pBits)[I * Rect.Pitch], LineBytes); - end - else - Move(Image.Bits^, Rect.pBits^, Image.Size); -end; - -function CreateD3DTextureFromMultiImage(const Images: TDynImageDataArray; - Device: IDirect3DDevice9; var Texture: IDirect3DTexture9; Width, - Height, MipLevels: LongInt; Usage: LongWord; Format: TD3DFormat; - Pool: TD3DPool; CreatedWidth, CreatedHeight: PLongInt): Boolean; -var - I, PossibleLevels, ExistingLevels, CurrentWidth, CurrentHeight: LongInt; - Caps: TD3DTextureCaps; - Rect: TD3DLockedRect; - ConvTo: TImageFormat; - LevelsArray: TDynImageDataArray; - NeedsResize, NeedsConvert: Boolean; -begin - Texture := nil; - ExistingLevels := 0; - Result := False; - // Get texture caps of the current device and test if there is anything to convert - if GetDeviceTextureCaps(Device, Caps) and (Length(Images) > 0) then - try - // First check desired size and modify it if necessary - if Width <= 0 then Width := Images[0].Width; - if Height <= 0 then Height := Images[0].Height; - if Caps.PowerOfTwo then - begin - // If device supports only power of 2 texture sizes - Width := NextPow2(Width); - Height := NextPow2(Height); - end; - Width := ClampInt(Width, 1, Caps.MaxWidth); - Height := ClampInt(Height, 1, Caps.MaxHeight); - - // Get various mipmap level counts and modify - // desired MipLevels if its value is invalid - ExistingLevels := Length(Images); - PossibleLevels := GetNumMipMapLevels(Width, Height); - if (MipLevels < 1) or (MipLevels > PossibleLevels) then - MipLevels := PossibleLevels; - - // Now determine which image format will be used - if Format = D3DFMT_UNKNOWN then - begin - // D3D texture format is not explicitly defined so we use - // the current format of the input image - Format := ImageFormatToD3DFormat(Images[0].Format, ConvTo); - // Format is now either D3DFMT_UNKNOWN or some valid format and - // ConvTo contains format to which input image must be converted first - // (if ConvTo and input image's format differ). - // We must also test if returned D3D format is supported by D3D device - if (Format = D3DFMT_UNKNOWN) or not IsD3DFormatSupported(Device, Format) then - begin - Format := D3DFMT_A8R8G8B8; - ConvTo := ifA8R8G8B8; - end; - end - else - begin - // Image format coresponding to desired D3D format is either found - // and image is converted to it (if the image is not in this format already) - // or it is not found (or not supported by hardware) and default format is used - ConvTo := D3DFormatToImageFormat(Format); - if (ConvTo = ifUnknown) or not IsD3DFormatSupported(Device, Format) then - begin - Format := D3DFMT_A8R8G8B8; - ConvTo := ifA8R8G8B8; - end; - end; - - // Prepare array for mipmap levels - SetLength(LevelsArray, MipLevels); - - CurrentWidth := Width; - CurrentHeight := Height; - - for I := 0 to MipLevels - 1 do - begin - // Check if we can use input image array as a source for this mipmap level - if I < ExistingLevels then - begin - // Check if input image for this mipmap level has the right - // size and format - NeedsResize := not ((Images[I].Width = CurrentWidth) and (Images[I].Height = CurrentHeight)); - NeedsConvert := not (Images[I].Format = ConvTo); - - if NeedsResize or NeedsConvert then - begin - // Input image must be resized or converted to different format - // to become valid mipmap level - CloneImage(Images[I], LevelsArray[I]); - if NeedsConvert then - ConvertImage(LevelsArray[I], ConvTo); - if NeedsResize then - ResizeImage(LevelsArray[I], CurrentWidth, CurrentHeight, rfBilinear); - end - else - // Input image can be used without any changes - LevelsArray[I] := Images[I]; - end - else - begin - // This mipmap level is not present in the input image array - // so we create a new level - FillMipMapLevel(LevelsArray[I - 1], CurrentWidth, CurrentHeight, LevelsArray[I]); - end; - // Calculate width and height of the next mipmap level - CurrentWidth := ClampInt(CurrentWidth div 2, 1, CurrentWidth); - CurrentHeight := ClampInt(CurrentHeight div 2, 1, CurrentHeight); - end; - - // Finally create D3D texture object - if Succeeded(Device.CreateTexture(LevelsArray[0].Width, - LevelsArray[0].Height, MipLevels, Usage, Format, Pool, Texture, nil)) then - begin - // Fill each mipmap level - for I := 0 to MipLevels - 1 do - if Succeeded(Texture.LockRect(I, Rect, nil, 0)) then - begin - FillLockedRectWithImage(Rect, LevelsArray[I]); - Texture.UnlockRect(I); - end; - Result := True; - end; - - // If user is interested in width and height of created texture lets - // give him that - if CreatedWidth <> nil then CreatedWidth^ := LevelsArray[0].Width; - if CreatedHeight <> nil then CreatedHeight^ := LevelsArray[0].Height; - - finally - // Free local image copies - for I := 0 to Length(LevelsArray) - 1 do - begin - if ((I < ExistingLevels) and (LevelsArray[I].Bits <> Images[I].Bits)) or - (I >= ExistingLevels) then - FreeImage(LevelsArray[I]); - end; - end; -end; - -function SaveD3DTextureToFile(const FileName: string; const Texture: IDirect3DTexture9): Boolean; -var - Arr: TDynImageDataArray; - Fmt: TImageFileFormat; - IsDDS: Boolean; -begin - Result := CreateMultiImageFromD3DTexture(Texture, Arr); - if Result then - begin - Fmt := FindImageFileFormatByName(FileName); - if Fmt <> nil then - begin - IsDDS := SameText(Fmt.Extensions[0], 'dds'); - if IsDDS then - begin - PushOptions; - SetOption(ImagingDDSSaveMipMapCount, Length(Arr)); - end; - Result := SaveMultiImageToFile(FileName, Arr); - if IsDDS then - PopOptions; - end; - end; -end; - -function SaveD3DTextureToStream(const Ext: string; Stream: TStream; const Texture: IDirect3DTexture9): Boolean; -var - Arr: TDynImageDataArray; - Fmt: TImageFileFormat; - IsDDS: Boolean; -begin - Result := CreateMultiImageFromD3DTexture(Texture, Arr); - if Result then - begin - Fmt := FindImageFileFormatByExt(Ext); - if Fmt <> nil then - begin - IsDDS := SameText(Fmt.Extensions[0], 'dds'); - if IsDDS then - begin - PushOptions; - SetOption(ImagingDDSSaveMipMapCount, Length(Arr)); - end; - Result := SaveMultiImageToStream(Ext, Stream, Arr); - if IsDDS then - PopOptions; - end; - end; -end; - -function SaveD3DTextureToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Texture: IDirect3DTexture9): Boolean; -var - Arr: TDynImageDataArray; - Fmt: TImageFileFormat; - IsDDS: Boolean; -begin - Result := CreateMultiImageFromD3DTexture(Texture, Arr); - if Result then - begin - Fmt := FindImageFileFormatByExt(Ext); - if Fmt <> nil then - begin - IsDDS := SameText(Fmt.Extensions[0], 'dds'); - if IsDDS then - begin - PushOptions; - SetOption(ImagingDDSSaveMipMapCount, Length(Arr)); - end; - Result := SaveMultiImageToMemory(Ext, Data, Size, Arr); - if IsDDS then - PopOptions; - end; - end; -end; - -function CreateImageFromD3DTexture(const Texture: IDirect3DTexture9; - var Image: TImageData; OverrideFormat: TImageFormat): Boolean; -var - Arr: TDynImageDataArray; -begin - // Just calls function operating on image arrays - FreeImage(Image); - SetLength(Arr, 1); - Result := CreateMultiImageFromD3DTexture(Texture, Arr, 1, OverrideFormat); - Image := Arr[0]; -end; - -procedure FillImageWithLockedRect(var Image: TImageData; const Rect: TD3DLockedRect); -var - I, LineBytes: LongInt; - Info: TImageFormatInfo; -begin - GetImageFormatInfo(Image.Format, Info); - LineBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1); - // Pixels are copied from D3D texture to the image - if (not Info.IsSpecial) and (LineBytes < Rect.Pitch) then - begin - for I := 0 to Image.Height - 1 do - Move(PByteArray(Rect.pBits)[I * Rect.Pitch], - PByteArray(Image.Bits)[I * LineBytes], LineBytes); - end - else - Move(Rect.pBits^, Image.Bits^, Image.Size); -end; - -function CreateMultiImageFromD3DTexture(const Texture: IDirect3DTexture9; - var Images: TDynImageDataArray; MipLevels: LongInt; OverrideFormat: TImageFormat): Boolean; -var - Rect: TD3DLockedRect; - Desc: TD3DSurfaceDesc; - I,ExistingLevels: LongInt; - CurrentFormat: TImageFormat; - Info: TImageFormatInfo; -begin - FreeImagesInArray(Images); - SetLength(Images, 0); - Result := False; - if Texture <> nil then - begin - // Check if desired mipmap level count is valid - ExistingLevels := Texture.GetLevelCount; - if (MipLevels <= 0) or (Miplevels > ExistingLevels) then - MipLevels := ExistingLevels; - - Texture.GetLevelDesc(0, Desc); - // Try to find image format compatible with d3d texture's format - CurrentFormat := D3DFormatToImageFormat(Desc.Format); - // Exit if no compatible image format is found - if CurrentFormat = ifUnknown then - Exit; - - SetLength(Images, MipLevels); - GetImageFormatInfo(CurrentFormat, Info); - - for I := 0 to MipLevels - 1 do - begin - if Failed(Texture.LockRect(I, Rect, nil, D3DLOCK_READONLY)) then Exit; - Texture.GetLevelDesc(I, Desc); - - // Create image for the current mipmap level and copy texture data to it - NewImage(Desc.Width, Desc.Height, CurrentFormat, Images[I]); - FillImageWithLockedRect(Images[I], Rect); - - // If override format is set each mipmap level is converted to it - if OverrideFormat <> ifUnknown then - ConvertImage(Images[I], OverrideFormat); - - Texture.UnlockRect(I); - end; - Result := True; - end; -end; - -function CreateD3DSurfaceFromImage(const Image: TImageData; Surface: IDirect3DSurface9): Boolean; -var - ConvTo: TImageFormat; - Desc: TD3DSurfaceDesc; - Rect: TD3DLockedRect; - WorkImage: TImageData; -begin - Result := False; - if (Surface = nil) or not TestImage(Image) then - Exit; - // Get surface's format and find Imaging data format match - Surface.GetDesc(Desc); - ConvTo := D3DFormatToImageFormat(Desc.Format); - // If no Imaging data format was found we must exit - if ConvTo = ifUnknown then - Exit; - - if (LongInt(Desc.Width) <> Image.Width) or (LongInt(Desc.Height) <> Image.Height) or - (Image.Format <> ConvTo) then - begin - // Source image has different dimensions or format than dest surface, - // working image is created - InitImage(WorkImage); - NewImage(Desc.Width, Desc.Height, ConvTo, WorkImage); - StretchRect(Image, 0, 0, Image.Width, Image.Height, WorkImage, 0, 0, - WorkImage.Width, WorkImage.Height, rfBilinear); - end - else - WorkImage := Image; - - try - // Lock surface and fill it with image - if Succeeded(Surface.LockRect(Rect, nil, 0)) then - begin - FillLockedRectWithImage(Rect, WorkImage); - Surface.UnlockRect; - Result := True; - end; - finally - // Free working image if it is not reference to source image - if WorkImage.Bits <> Image.Bits then - FreeImage(WorkImage); - end; -end; - -function CreateImageFromD3DSurface(Surface: IDirect3DSurface9; var Image: TImageData): Boolean; -var - CurrentFormat: TImageFormat; - Desc: TD3DSurfaceDesc; - Rect: TD3DLockedRect; -begin - Result := False; - FreeImage(Image); - if Surface = nil then - Exit; - Surface.GetDesc(Desc); - CurrentFormat := D3DFormatToImageFormat(Desc.Format); - // Exit if no compatible image format is found - if CurrentFormat = ifUnknown then - Exit; - - if Succeeded(Surface.LockRect(Rect, nil, D3DLOCK_READONLY)) then - begin - // If surface was successfuly locked a new image is created - // and surface's contents are copied to it - NewImage(Desc.Width, Desc.Height, CurrentFormat, Image); - FillImageWithLockedRect(Image, Rect); - Surface.UnlockRect; - Result := True; - end; -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - support for cube and volume maps - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - Added support for 3Dc compressed texture formats. - - Added detection of 3Dc support to texture caps. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Added CreatedWidth and CreatedHeight parameters to most - LoadD3DTextureFromXXX/CreateD3DTextureFromXXX functions. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - fixed bug in CreateGLTextureFromMultiImage which caused assert failure - when creating mipmaps (using FillMipMapLevel) for DXTC formats - - added support for 16bit half-float texture formats - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - D3D surface support - fill surface with image and vice versa - - more texture caps added - - filtered mipmap creation - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - unit created and initial stuff added -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingExtras.pas b/3rd/Imaging/Extras/Extensions/ImagingExtras.pas deleted file mode 100644 index f8074f707..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingExtras.pas +++ /dev/null @@ -1,153 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This is helper unit that registers all image file formats in Extras package - to Imaging core loading and saving functions. Just put this unit in your uses - clause instead of adding every unit that provides new file format support. - Also new constants for SetOption/GetOption functions for new file formats - are located here.} -unit ImagingExtras; - -{$I ImagingOptions.inc} - -//{$DEFINE DONT_LINK_JPEG2000} // link support for JPEG2000 images -//{$DEFINE DONT_LINK_TIFF} // link support for TIFF images -//{$DEFINE DONT_LINK_PSD} // link support for PSD images -//{$DEFINE DONT_LINK_PCX} // link support for PCX images -//{$DEFINE DONT_LINK_XPM} // link support for XPM images -{$IFNDEF FULL_FEATURE_SET} - {$DEFINE DONT_LINK_ELDER} // link support for Elder Imagery images -{$ENDIF} - -{$IF not ( - (Defined(DCC) and Defined(CPUX86) and not Defined(MACOS)) or - (Defined(FPC) and not Defined(MSDOS) and - ((Defined(CPUX86) and (Defined(LINUX) or Defined(WIN32) or Defined(MACOS)) or - (Defined(CPUX64) and Defined(LINUX))))) - )} - // JPEG2000 only for 32bit Windows/Linux/OSX and for 64bit Unix with FPC - {$DEFINE DONT_LINK_JPEG2000} -{$IFEND} - -{$IF not (Defined(DCC) and Defined(CPUX86) and not Defined(MACOS))} - {$DEFINE DONT_LINK_TIFF} // Only for Delphi now -{$IFEND} - -interface - -const - { Those are new options for GetOption/SetOption interface. } - - { Controls JPEG 2000 lossy compression quality. It is number in range 1..100. - 1 means small/ugly file, 100 means large/nice file. Default is 80.} - ImagingJpeg2000Quality = 55; - { Controls whether JPEG 2000 image is saved with full file headers or just - as code stream. Default value is False (0).} - ImagingJpeg2000CodeStreamOnly = 56; - { Specifies JPEG 2000 image compression type. If True (1), saved JPEG 2000 files - will be losslessly compressed. Otherwise lossy compression is used. - Default value is False (0).} - ImagingJpeg2000LosslessCompression = 57; - { Specifies compression scheme used when saving TIFF images. Supported values - are 0 (Uncompressed), 1 (LZW), 2 (PackBits RLE), 3 (Deflate - ZLib), 4 (JPEG), - 5 (CCITT Group 4 fax encoding - for binary images only). - Default is 1 (LZW). Note that not all images can be stored with - JPEG compression - these images will be saved with default compression if - JPEG is set.} - ImagingTiffCompression = 65; - { Controls compression quality when selected TIFF compression is Jpeg. - It is number in range 1..100. 1 means small/ugly file, - 100 means large/nice file. Accessible trough ImagingTiffJpegQuality option.} - ImagingTiffJpegQuality = 66; - { When activated (True = 1) existing TIFF files are not overwritten when saving but - new images are instead appended thus producing multipage TIFFs. - Default value is False (0).} - ImagingTiffAppendMode = 67; - { If enabled image data is saved as layer of PSD file. This is required - to get proper transparency when opened in Photoshop for images with - alpha data (will be opened with one layer, RGB color channels, and transparency). - If you don't need this Photoshop compatibility turn this option off as you'll get - smaller file (will be opened in PS as background raster with RGBA channels). - Default value is True (1). } - ImagingPSDSaveAsLayer = 70; - -implementation - -uses -{$IFNDEF DONT_LINK_JPEG2000} - ImagingJpeg2000, -{$ENDIF} -{$IFNDEF DONT_LINK_TIFF} - ImagingLibTiffDelphi, -{$ENDIF} -{$IFNDEF DONT_LINK_PSD} - ImagingPsd, -{$ENDIF} -{$IFNDEF DONT_LINK_PCX} - ImagingPcx, -{$ENDIF} -{$IFNDEF DONT_LINK_XPM} - ImagingXpm, -{$ENDIF} -{$IFNDEF DONT_LINK_ELDER} - ElderImagery, -{$ENDIF} - Imaging; - -{ - File Notes: - - -- TODOS ----------------------------------------------------- - - nothing now - - -- 0.77 ----------------------------------------------------- - - Added ImagingTiffAppendMode option. - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Added Group 4 Fax encoding as compression for TIFF files. - - Added ImagingTiffJpegQuality option. - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Allowed JPEG2000 for Mac OS X x86 - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - ElderImagery formats are disabled by default, TIFF enabled. - - Changed _LINK_ symbols according to changes in ImagingOptions.inc. - - -- 0.24.1 Changes/Bug Fixes --------------------------------- - - Allowed JPEG2000 for x86_64 CPUS in Linux - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Better IF conditional to disable JPEG2000 on unsupported platforms. - - Added PSD and TIFF related stuff. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Created with initial stuff. - -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingFmx.pas b/3rd/Imaging/Extras/Extensions/ImagingFmx.pas deleted file mode 100644 index 2dcfe1189..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingFmx.pas +++ /dev/null @@ -1,353 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ Functions and classes for interoperability between Imaging and - FireMonkey framework.} -unit ImagingFmx; - -{$I ImagingOptions.inc} - -{$IF not Defined(DCC) or (CompilerVersion < 23)} - {$MESSAGE FATAL 'FMX needs Delphi XE2+'} -{$IFEND} - -{$IF (CompilerVersion = 24)} - {$MESSAGE FATAL 'FMX needs Delphi XE4+'} -{$IFEND} - - -interface - -uses -{$IF (CompilerVersion > 23)} - System.UITypes, -{$IFEND} - Types, - SysUtils, - ImagingTypes, - Imaging, - ImagingFormats, - ImagingClasses, - ImagingUtility, - Fmx.Types; - -{ Converts image from TImageData record to FMX bitmap. Bitmap must be already instantiated.} -procedure ConvertImageDataToFmxBitmap(const Image: TImageData; Bitmap: TBitmap); -{$IF (CompilerVersion > 23)} -{ Converts FMX bitmap to TImageData. Image Data must already instantiated.} -procedure ConvertFmxBitmapToImageData(const Bitmap: TBitmap;Image: TImageData); -{$IFEND} - -{ Converts image from TBaseImage instance to FMX bitmap. Bitmap must be already instantiated.} -procedure ConvertImageToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap); - -{ Copies rectangular area of pixels from TImageData record to existing FMX bitmap.} -procedure CopyRectToFmxBitmap(const Image: TImageData; Bitmap: TBitmap; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); overload; -{ Copies rectangular area of pixels from TBaseImage instance to existing FMX bitmap.} -procedure CopyRectToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); overload; - -implementation - -{$IF (CompilerVersion > 23)} -type - TARGB = record - A, R, G, B: System.Byte; - end; - -procedure ConvertFmxBitmapToImageData(const Bitmap: TBitmap;Image: TImageData); -var - Color32:TColor32Rec; - MapData:TBitmapData; - SourceData: PAlphaColorRec; - TargetData: PByte; - X, Y, Bpp, SrcWidthBytes: Integer; - TargetInfo: TImageFormatInfo; -begin - Bitmap.Map(TMapAccess.maRead,MapData); - GetImageFormatInfo(Image.Format, TargetInfo); - - Bpp := TargetInfo.BytesPerPixel; - SrcWidthBytes := Image.Width * Bpp; - TargetData := @PByteArray(Image.Bits)[0]; - - for Y := 0 to Pred(Bitmap.Height) do - for X:= 0 to Pred(Bitmap.Width) do - begin - SourceData:= @PAlphaColorArray(MapData.Data)[Y * (MapData.Pitch div 4)+X]; - case TargetInfo.Format of - ifIndex8: - begin - Image.Palette[TargetData^].R := SourceData^.R; - Image.Palette[TargetData^].G := SourceData^.G; - Image.Palette[TargetData^].B := SourceData^.B; - Image.Palette[TargetData^].A := SourceData^.A; - end; - ifGray8: - TargetData^ := SourceData.R; - ifA8Gray8: - begin - TargetData^ := SourceData.R; - PWordRec(TargetData).High := SourceData.A; - end; - ifGray16: - PWord(TargetData)^ := SourceData.R; - ifR8G8B8: - begin - PColor24Rec(TargetData)^.R := SourceData.R; - PColor24Rec(TargetData)^.G := SourceData.G; - PColor24Rec(TargetData)^.B := SourceData.B; - end; - ifA8R8G8B8: - begin - PColor32Rec(TargetData)^.A := SourceData^.B; - PColor32Rec(TargetData)^.G := SourceData^.R; - PColor32Rec(TargetData)^.R := SourceData^.G; - PColor32Rec(TargetData)^.B := SourceData^.A; - end; - ifR16G16B16: - begin - PColor48Rec(TargetData).R := Round(SourceData.R*$FFFF/255); - PColor48Rec(TargetData).G := Round(SourceData.G*$FFFF/255); - PColor48Rec(TargetData).B := Round(SourceData.B*$FFFF/255); - end; - ifA16R16G16B16: - begin - PColor64Rec(TargetData).R := Round(SourceData.R*$FFFF/255); - PColor64Rec(TargetData).G := Round(SourceData.G*$FFFF/255); - PColor64Rec(TargetData).B := Round(SourceData.B*$FFFF/255); - PColor64Rec(TargetData).A := Round(SourceData.A*$FFFF/255); - end; - else - Color32.R := SourceData^.R; - Color32.G := SourceData^.G; - Color32.B := SourceData^.B; - Color32.A := SourceData^.A; - TargetInfo.SetPixel32(TargetData,@TargetInfo, Image.Palette,Color32); - end; - Inc(TargetData, Bpp); - end; - Bitmap.Unmap(MapData); -end; -{$IFEND} - -procedure ConvertImageDataToFmxBitmap(const Image: TImageData; Bitmap: TBitmap); -begin - Assert(TestImage(Image)); - Bitmap.SetSize(Image.Width, Image.Height); - CopyRectToFmxBitmap(Image, Bitmap, 0, 0, Image.Width, Image.Height, 0, 0); -end; - -procedure ConvertImageToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap); -begin - ConvertImageDataToFmxBitmap(Image.ImageDataPointer^, Bitmap); -end; - -{$IF (CompilerVersion > 23)} -procedure ConvertToAlphaColorRec(SrcPix: PByte; DestPix: PAlphaColorRec; - const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32); -var - Color32:TColor32Rec; -begin - case SrcInfo.Format of - ifIndex8: - begin - DestPix^.R := SrcPalette[SrcPix^].R; - DestPix^.G := SrcPalette[SrcPix^].G; - DestPix^.B := SrcPalette[SrcPix^].B; - DestPix^.A := SrcPalette[SrcPix^].A; - end; - ifGray8: - begin - DestPix.R := SrcPix^; - DestPix.G := SrcPix^; - DestPix.B := SrcPix^; - DestPix.A := 255; - end; - ifA8Gray8: - begin - DestPix.R := SrcPix^; - DestPix.G := SrcPix^; - DestPix.B := SrcPix^; - DestPix.A := PWordRec(SrcPix).High; - end; - ifGray16: - begin - DestPix.R := PWord(SrcPix)^ shr 8; - DestPix.G := DestPix.R; - DestPix.B := DestPix.R; - DestPix.A := 255; - end; - ifR8G8B8: - begin - DestPix.R := PColor24Rec(SrcPix)^.R; - DestPix.G := PColor24Rec(SrcPix)^.G; - DestPix.B := PColor24Rec(SrcPix)^.B; - DestPix.A := 255; - end; - ifA8R8G8B8: - begin - DestPix^.R := PColor32Rec(SrcPix)^.R; - DestPix^.G := PColor32Rec(SrcPix)^.G; - DestPix^.B := PColor32Rec(SrcPix)^.B; - DestPix^.A := PColor32Rec(SrcPix)^.A; - end; - ifR16G16B16: - begin - DestPix.R := PColor48Rec(SrcPix).R shr 8; - DestPix.G := PColor48Rec(SrcPix).G shr 8; - DestPix.B := PColor48Rec(SrcPix).B shr 8; - DestPix.A := 255; - end; - ifA16R16G16B16: - begin - DestPix.R := PColor64Rec(SrcPix).R shr 8; - DestPix.G := PColor64Rec(SrcPix).G shr 8; - DestPix.B := PColor64Rec(SrcPix).B shr 8; - DestPix.A := PColor64Rec(SrcPix).A shr 8; - end; - else - Color32:=SrcInfo.GetPixel32(SrcPix, @SrcInfo, SrcPalette); - DestPix^.R := Color32.R; - DestPix^.G := Color32.G; - DestPix^.B := Color32.B; - DestPix^.A := Color32.A; - end; -end; -{$IFEND} - -procedure CopyRectToFmxBitmap(const Image: TImageData; Bitmap: TBitmap; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); -var - TempImage: TImageData; - X, Y, Bpp, SrcWidthBytes, MoveBytes: Integer; - SrcPtr: PByte; - Info: TImageFormatInfo; -{$IF (CompilerVersion > 23)} - MapData: TBitmapData; - DstPtr: PAlphaColorRec; - ARGB: TARGB; -{$ELSE} - DstPtr: PColor32Rec; -{$IFEND} -begin - Assert(TestImage(Image) and not Bitmap.IsEmpty); - - ClipCopyBounds(SrcX, SrcY, Width, Height, DstX, DstY, Image.Width, Image.Height, - Rect(0, 0, Bitmap.Width, Bitmap.Height)); - GetImageFormatInfo(Image.Format, Info); - - if not Info.IsSpecial then - begin - Bpp := Info.BytesPerPixel; - SrcWidthBytes := Image.Width * Bpp; - MoveBytes := Width * Bpp; - SrcPtr := @PByteArray(Image.Bits)[SrcY * SrcWidthBytes + SrcX * Bpp]; -{$IF (CompilerVersion > 23)} - Bitmap.Map(TMapAccess.maReadWrite,MapData); -{$IFEND} - for Y := 0 to Height - 1 do - begin -{$IF (CompilerVersion = 23)} - DstPtr := PColor32Rec(@Bitmap.ScanLine[Y][DstX]); -{$IFEND} - if Info.Format = ifA8R8G8B8 then - begin -{$IF (CompilerVersion = 23)} - Move(SrcPtr^, DstPtr^, MoveBytes); - Inc(SrcPtr, MoveBytes); -{$ELSE} //CompilerVersion > 23 - for X:= 0 to Pred(Width) do - begin - DstPtr:= @PAlphaColorArray(MapData.Data)[Y * (MapData.Pitch div 4)+X]; - Move(SrcPtr^,ARGB,4); - DstPtr^.A:=ARGB.A; - DstPtr^.R:=ARGB.R; - DstPtr^.G:=ARGB.G; - DstPtr^.B:=ARGB.B; - Inc(SrcPtr,4); - end; -{$IFEND} - end - else - begin - for X := 0 to Width - 1 do - begin -{$IF (CompilerVersion = 23)} - ConvertToPixel32(SrcPtr, DstPtr, Info, Image.Palette); - Inc(DstPtr); - Inc(SrcPtr, Bpp); -{$ELSE} //CompilerVersion > 23 - DstPtr:= @PAlphaColorArray(MapData.Data)[Y * (MapData.Pitch div 4)+X]; - ConvertToAlphaColorRec(SrcPtr, DstPtr, Info, Image.Palette); - Inc(SrcPtr, Bpp); -{$IFEND} - end; - end; - end; - end - else - begin - InitImage(TempImage); - CloneImage(Image, TempImage); - ConvertImage(TempImage, ifA8R8G8B8); - try - CopyRectToFmxBitmap(TempImage, Bitmap, SrcX, SrcY, Width, Height, DstX, DstY); - finally - FreeImage(TempImage); - end; - end; -{$IF (CompilerVersion > 23)} - Bitmap.UnMap(MapData); -{$ELSE} - Bitmap.UpdateHandles; - Bitmap.BitmapChanged; -{$IFEND} -end; - -procedure CopyRectToFmxBitmap(Image: TBaseImage; Bitmap: TBitmap; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); -begin - CopyRectToFmxBitmap(Image.ImageDataPointer^, Bitmap, - SrcX, SrcY, Width, Height, DstX, DstY); -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 Changes/Bug Fixes --------------------------------- - - Support for current FMX version (XE4+) contributed by Ken Schafer. - - -- 0.77 Changes/Bug Fixes ----------------------------------- - - Unit created with initial stuff, working with FMX1 in Delphi XE2. - } - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingGraphics32.pas b/3rd/Imaging/Extras/Extensions/ImagingGraphics32.pas deleted file mode 100644 index a64f24ef8..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingGraphics32.pas +++ /dev/null @@ -1,256 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ Unit functions for converting and copying images between Imaging and Graphics32 library.} -unit ImagingGraphics32; - -{$I ImagingOptions.inc} - -interface - -uses - Types, GR32, ImagingTypes, Imaging, ImagingFormats, ImagingUtility, ImagingClasses; - -{ Converts image from TImageData record to GR32's bitmap. Bitmap32 must be already - instantiated.} -procedure ConvertImageDataToBitmap32(const Image: TImageData; Bitmap32: TCustomBitmap32); -{ Converts image from TBaseImage instance to GR32's bitmap. Bitmap32 must be already - instantiated.} -procedure ConvertImageToBitmap32(Image: TBaseImage; Bitmap32: TCustomBitmap32); - -{ Converts image data from GR32's bitmap to TImageData record.} -procedure ConvertBitmap32ToImageData(Bitmap32: TCustomBitmap32; var Image: TImageData); -{ Converts image data from GR32's bitmap to existing TBaseImage instance.} -procedure ConvertBitmap32ToImage(Bitmap32: TCustomBitmap32; Image: TBaseImage); - -{ Copies pixels from TImageData record (with all the necessary conversion if - the format is not 32bit) to existing GR32's bitmap. Both Image and Bitmap32 must - have the same width and height. } -procedure CopyImageDataToBitmap32(const Image: TImageData; Bitmap32: TCustomBitmap32); -{ Copies pixels from TBaseImage instance (with all the necessary conversion if - the format is not 32bit) to existing GR32's bitmap. Both Image and Bitmap32 must - have the same width and height. } -procedure CopyImageToBitmap32(Image: TBaseImage; Bitmap32: TCustomBitmap32); - -{ Copies rectangular area of pixels from TImageData record to existing GR32's bitmap.} -procedure CopyRectToBitmap32(const Image: TImageData; Bitmap32: TCustomBitmap32; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); overload; -{ Copies rectangular area of pixels from TBaseImage instance to existing GR32's bitmap.} -procedure CopyRectToBitmap32(Image: TBaseImage; Bitmap32: TCustomBitmap32; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); overload; - -{ Maps GR32 bitmap on TImageData record so that they'll both share - the same pixels in memory (Bitmap32.Bits and Image.Bits point to the same - memory address). Usefull if you wan to e.g. save Bitmap32 using Imaging - and don't want to needlesly duplicate the entire image in memory. - Note that you must not call FreeImage on Image after the mapping or - the memory of Bitmap32 would be freed too.} -procedure MapBitmap32ToImageData(Bitmap32: TCustomBitmap32; var Image: TImageData); - -implementation - -procedure ConvertImageDataToBitmap32(const Image: TImageData; Bitmap32: TCustomBitmap32); -begin - Assert(TestImage(Image)); - Bitmap32.SetSize(Image.Width, Image.Height); - CopyImageDataToBitmap32(Image, Bitmap32); -end; - -procedure ConvertImageToBitmap32(Image: TBaseImage; Bitmap32: TCustomBitmap32); -begin - ConvertImageDataToBitmap32(Image.ImageDataPointer^, Bitmap32); -end; - -procedure ConvertBitmap32ToImageData(Bitmap32: TCustomBitmap32; var Image: TImageData); -begin - Assert(not Bitmap32.Empty); - NewImage(Bitmap32.Width, Bitmap32.Height, ifA8R8G8B8, Image); - Move(Bitmap32.Bits^, Image.Bits^, Image.Size); -end; - -procedure ConvertBitmap32ToImage(Bitmap32: TCustomBitmap32; Image: TBaseImage); -begin - ConvertBitmap32ToImageData(Bitmap32, Image.ImageDataPointer^); -end; - -procedure CopyImageDataToBitmap32(const Image: TImageData; Bitmap32: TCustomBitmap32); -begin - Assert(TestImage(Image) and (Image.Width = Bitmap32.Width) and (Image.Height = Bitmap32.Height)); - CopyRectToBitmap32(Image, Bitmap32, 0, 0, Image.Width, Image.Height, 0, 0); -end; - -procedure CopyImageToBitmap32(Image: TBaseImage; Bitmap32: TCustomBitmap32); -begin - CopyImageDataToBitmap32(Image.ImageDataPointer^, Bitmap32); -end; - -procedure CopyRectToBitmap32(const Image: TImageData; Bitmap32: TCustomBitmap32; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); -var - TempImage: TImageData; - X, Y, Bpp, SrcWidthBytes, DstWidth, MoveBytes: Integer; - DstPtr: PColor32Rec; - SrcPtr: PByte; - Info: TImageFormatInfo; -begin - Assert(TestImage(Image) and not Bitmap32.Empty); - - ClipCopyBounds(SrcX, SrcY, Width, Height, DstX, DstY, Image.Width, Image.Height, - Rect(0, 0, Bitmap32.Width, Bitmap32.Height)); - - if Image.Format in [ifIndex8, ifGray8, ifA8Gray8, ifGray16, ifR8G8B8, ifA8R8G8B8, - ifR16G16B16, ifA16R16G16B16] then - begin - GetImageFormatInfo(Image.Format, Info); - Bpp := Info.BytesPerPixel; - SrcWidthBytes := Image.Width * Bpp; - DstWidth := Bitmap32.Width; - MoveBytes := Width * Bpp; - SrcPtr := @PByteArray(Image.Bits)[SrcY * SrcWidthBytes + SrcX * Bpp]; - DstPtr := @PColor32RecArray(Bitmap32.Bits)[DstY * DstWidth + DstX]; - - for Y := 0 to Height - 1 do - begin - case Image.Format of - ifIndex8: - for X := 0 to Width - 1 do - begin - DstPtr^ := Image.Palette[SrcPtr^]; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - ifGray8: - for X := 0 to Width - 1 do - begin - DstPtr.R := SrcPtr^; - DstPtr.G := SrcPtr^; - DstPtr.B := SrcPtr^; - DstPtr.A := 255; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - ifA8Gray8: - for X := 0 to Width - 1 do - begin - DstPtr.R := SrcPtr^; - DstPtr.G := SrcPtr^; - DstPtr.B := SrcPtr^; - DstPtr.A := PWordRec(SrcPtr).High; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - ifGray16: - for X := 0 to Width - 1 do - begin - DstPtr.R := PWord(SrcPtr)^ shr 8; - DstPtr.G := DstPtr.R; - DstPtr.B := DstPtr.R; - DstPtr.A := 255; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - ifR8G8B8: - for X := 0 to Width - 1 do - begin - DstPtr.Color24Rec := PColor24Rec(SrcPtr)^; - DstPtr.A := 255; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - ifA8R8G8B8: - begin - Move(SrcPtr^, DstPtr^, MoveBytes); - Inc(DstPtr, Width); - Inc(SrcPtr, MoveBytes); - end; - ifR16G16B16: - for X := 0 to Width - 1 do - begin - DstPtr.R := PColor48Rec(SrcPtr).R shr 8; - DstPtr.G := PColor48Rec(SrcPtr).G shr 8; - DstPtr.B := PColor48Rec(SrcPtr).B shr 8; - DstPtr.A := 255; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - ifA16R16G16B16: - for X := 0 to Width - 1 do - begin - DstPtr.R := PColor64Rec(SrcPtr).R shr 8; - DstPtr.G := PColor64Rec(SrcPtr).G shr 8; - DstPtr.B := PColor64Rec(SrcPtr).B shr 8; - DstPtr.A := PColor64Rec(SrcPtr).A shr 8; - Inc(DstPtr); - Inc(SrcPtr, Bpp); - end; - end; - - Inc(SrcPtr, SrcWidthBytes - MoveBytes); - Inc(DstPtr, DstWidth - Width); - end; - end - else - begin - InitImage(TempImage); - CloneImage(Image, TempImage); - ConvertImage(TempImage, ifA8R8G8B8); - try - CopyRectToBitmap32(TempImage, Bitmap32, SrcX, SrcY, Width, Height, DstX, DstY); - finally - FreeImage(TempImage); - end; - end; -end; - -procedure CopyRectToBitmap32(Image: TBaseImage; Bitmap32: TCustomBitmap32; - SrcX, SrcY, Width, Height, DstX, DstY: Integer); -begin - CopyRectToBitmap32(Image.ImageDataPointer^, Bitmap32, - SrcX, SrcY, Width, Height, DstX, DstY); -end; - -procedure MapBitmap32ToImageData(Bitmap32: TCustomBitmap32; var Image: TImageData); -begin - Assert(not Bitmap32.Empty); - FreeImage(Image); - - Image.Width := Bitmap32.Width; - Image.Height := Bitmap32.Height; - Image.Format := ifA8R8G8B8; - Image.Size := Image.Width * Image.Height * 4; - - Image.Bits := Bitmap32.Bits; -end; - -{ - File Notes: - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Created with initial stuff. -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingJpeg2000.pas b/3rd/Imaging/Extras/Extensions/ImagingJpeg2000.pas deleted file mode 100644 index dbeca970a..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingJpeg2000.pas +++ /dev/null @@ -1,628 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for Jpeg 2000 images.} -unit ImagingJpeg2000; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, ImagingTypes, Imaging, ImagingColors, ImagingIO, ImagingUtility, - ImagingExtras, OpenJpeg; - -type - { Type Jpeg 2000 file (needed for OpenJPEG codec settings).} - TJpeg2000FileType = (jtInvalid, jtJP2, jtJ2K, jtJPT); - - { Class for loading/saving Jpeg 2000 images. It uses OpenJPEG library - compiled to object files and linked to Object Pascal program. Jpeg 2000 - supports wide variety of data formats. You can have arbitrary number - of components/channels, each with different bitdepth and optional - "signedness". Jpeg 2000 images can be lossy or lossless compressed. - - Imaging can load most data formats (except images - with componenet bitdepth > 16 => no Imaging data format equivalents). - Components with sample separation are loaded correctly, ICC profiles - or palettes are not used, YCbCr images are translated to RGB. - - You can set various options when saving Jpeg-2000 images. Look at - properties of TJpeg2000FileFormat for details.} - TJpeg2000FileFormat = class(TImageFileFormat) - private - FQuality: LongInt; - FCodeStreamOnly: LongBool; - FLosslessCompression: LongBool; - function GetFileType(Handle: TImagingHandle): TJpeg2000FileType; - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - procedure CheckOptionsValidity; override; - published - { Controls JPEG 2000 lossy compression quality. It is number in range 1..100. - 1 means small/ugly file, 100 means large/nice file. Accessible trough - ImagingJpeg2000Quality option. Default value is 80.} - property Quality: LongInt read FQuality write FQuality; - { Controls whether JPEG 2000 image is saved with full file headers or just - as code stream. Default value is False. Accessible trough - ImagingJpeg2000CodeStreamOnly option.} - property CodeStreamOnly: LongBool read FCodeStreamOnly write FCodeStreamOnly; - { Specifies JPEG 2000 image compression type. If True, saved JPEG 2000 files - will be losslessly compressed. Otherwise lossy compression is used. - Default value is False. Accessible trough - ImagingJpeg2000LosslessCompression option.} - property LosslessCompression: LongBool read FLosslessCompression write FLosslessCompression; - end; - -implementation - -const - SJpeg2000FormatName = 'JPEG 2000 Image'; - SJpeg2000Masks = '*.jp2,*.j2k,*.j2c,*.jpx,*.jpc'; - Jpeg2000SupportedFormats: TImageFormats = [ifGray8, ifGray16, - ifA8Gray8, ifA16Gray16, ifR8G8B8, ifR16G16B16, ifA8R8G8B8, ifA16R16G16B16]; - Jpeg2000DefaultQuality = 80; - Jpeg2000DefaultCodeStreamOnly = False; - Jpeg2000DefaultLosslessCompression = False; - -const - JP2Signature: TChar8 = #0#0#0#$0C#$6A#$50#$20#$20; - J2KSignature: TChar4 = #$FF#$4F#$FF#$51; - -procedure TJpeg2000FileFormat.Define; -begin - inherited; - FName := SJpeg2000FormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := Jpeg2000SupportedFormats; - - FQuality := Jpeg2000DefaultQuality; - FCodeStreamOnly := Jpeg2000DefaultCodeStreamOnly; - FLosslessCompression := Jpeg2000DefaultLosslessCompression; - - AddMasks(SJpeg2000Masks); - RegisterOption(ImagingJpeg2000Quality, @FQuality); - RegisterOption(ImagingJpeg2000CodeStreamOnly, @FCodeStreamOnly); - RegisterOption(ImagingJpeg2000LosslessCompression, @FLosslessCompression); -end; - -procedure TJpeg2000FileFormat.CheckOptionsValidity; -begin - // Check if option values are valid - if not (FQuality in [1..100]) then - FQuality := Jpeg2000DefaultQuality; -end; - -function TJpeg2000FileFormat.GetFileType(Handle: TImagingHandle): TJpeg2000FileType; -var - ReadCount: LongInt; - Id: TChar8; -begin - Result := jtInvalid; - with GetIO do - begin - ReadCount := Read(Handle, @Id, SizeOf(Id)); - if ReadCount = SizeOf(Id) then - begin - // Check if we have full JP2 file format or just J2K code stream - if CompareMem(@Id, @JP2Signature, SizeOf(JP2Signature)) then - Result := jtJP2 - else if CompareMem(@Id, @J2KSignature, SizeOf(J2KSignature)) then - Result := jtJ2K; - end; - Seek(Handle, -ReadCount, smFromCurrent); - end; -end; - -function TJpeg2000FileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -type - TChannelInfo = record - DestOffset: Integer; - CompType: OPJ_COMPONENT_TYPE; - Shift: Integer; - SrcMaxValue: Integer; - DestMaxValue: Integer; - end; -var - FileType: TJpeg2000FileType; - Buffer: PByte; - BufferSize, ChannelSize, I: Integer; - Info: TImageFormatInfo; - dinfo: popj_dinfo_t; - parameters: opj_dparameters_t; - cio: popj_cio_t; - image: popj_image_t; - StartPos: Int64; - Channels: array of TChannelInfo; - - procedure WriteSample(Dest: PByte; ChannelSize, Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} - begin - case ChannelSize of - 1: Dest^ := Value; - 2: PWord(Dest)^ := Value; - 4: PLongWord(Dest)^ := Value; - end; - end; - - procedure CopySample(Src, Dest: PByte; ChannelSize: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} - begin - case ChannelSize of - 1: Dest^ := Src^; - 2: PWord(Dest)^ := PWord(Src)^; - 4: PLongWord(Dest)^ := PLongWord(Src)^; - end; - end; - - procedure ReadChannel(const Image: TImageData; const Info: TChannelInfo; const Comp: opj_image_comp; BytesPerPixel: Integer); - var - X, Y, SX, SY, SrcIdx, LineBytes: Integer; - DestPtr, NewPtr, LineUpPtr: PByte; - DontScaleSamples: Boolean; - begin - DontScaleSamples := Info.SrcMaxValue = Info.DestMaxValue; - LineBytes := Image.Width * BytesPerPixel; - DestPtr := @PByteArray(Image.Bits)[Info.DestOffset]; - SrcIdx := 0; - - if (Comp.dx = 1) and (Comp.dy = 1) then - begin - // X and Y sample separation is 1 so just need to assign component values - // to image pixels one by one - for Y := 0 to Image.Height * Image.Width - 1 do - begin - if DontScaleSamples then - WriteSample(DestPtr, ChannelSize, Comp.data[SrcIdx] + Info.Shift) - else - WriteSample(DestPtr, ChannelSize, MulDiv(Comp.data[SrcIdx] + Info.Shift, Info.DestMaxValue, Info.SrcMaxValue)); - - Inc(SrcIdx); - Inc(DestPtr, BytesPerPixel); - end; - end - else - begin - // Sample separation is active - component is sub-sampled. Real component - // dimensions are [Comp.w * Comp.dx, Comp.h * Comp.dy] - for Y := 0 to Comp.h - 1 do - begin - LineUpPtr := @PByteArray(Image.Bits)[Y * Comp.dy * LineBytes + Info.DestOffset]; - DestPtr := LineUpPtr; - - for X := 0 to Comp.w - 1 do - begin - if DontScaleSamples then - WriteSample(DestPtr, ChannelSize, Comp.data[SrcIdx] + Info.Shift) - else - WriteSample(DestPtr, ChannelSize, MulDiv(Comp.data[SrcIdx] + Info.Shift, Info.DestMaxValue, Info.SrcMaxValue)); - - NewPtr := DestPtr; - - for SX := 1 to Comp.dx - 1 do - begin - if X * Comp.dx + SX >= Image.Width then Break; - // Replicate pixels on line - Inc(NewPtr, BytesPerPixel); - CopySample(DestPtr, NewPtr, ChannelSize); - end; - - Inc(SrcIdx); - Inc(DestPtr, BytesPerPixel * Comp.dx); - end; - - for SY := 1 to Comp.dy - 1 do - begin - if Y * Comp.dy + SY >= Image.Height then Break; - // Replicate line - NewPtr := @PByteArray(Image.Bits)[(Y * Comp.dy + SY) * LineBytes + Info.DestOffset]; - for X := 0 to Image.Width - 1 do - begin - CopySample(LineUpPtr, NewPtr, ChannelSize); - Inc(LineUpPtr, BytesPerPixel); - Inc(NewPtr, BytesPerPixel); - end; - end; - end; - end; - end; - - procedure ConvertYCbCrToRGB(Pixels: PByte; NumPixels, BytesPerPixel: Integer); - var - I: Integer; - PixPtr: PByte; - CY, CB, CR: Byte; - CYW, CBW, CRW: Word; - begin - PixPtr := Pixels; - for I := 0 to NumPixels - 1 do - begin - if BytesPerPixel in [3, 4] then - with PColor24Rec(PixPtr)^ do - begin - CY := R; - CB := G; - CR := B; - YCbCrToRGB(CY, CB, CR, R, G, B); - end - else - with PColor48Rec(PixPtr)^ do - begin - CYW := R; - CBW := G; - CRW := B; - YCbCrToRGB16(CYW, CBW, CRW, R, G, B); - end; - Inc(PixPtr, BytesPerPixel); - end; - end; - -begin - Result := False; - image := nil; - cio := nil; - opj_set_default_decoder_parameters(@parameters); - // Determine which codec to use - FileType := GetFileType(Handle); - case FileType of - jtJP2: dinfo := opj_create_decompress(CODEC_JP2); - jtJ2K: dinfo := opj_create_decompress(CODEC_J2K); - jtJPT: dinfo := opj_create_decompress(CODEC_JPT); - else - Exit; - end; - // Set event manager to nil to avoid getting messages - dinfo.event_mgr := nil; - // Currently OpenJPEG can load images only from memory so we have to - // preload whole input to mem buffer. Not good but no other way now. - // At least we set stream pos to end of JP2 data after loading (we will now - // the exact size by then). - StartPos := GetIO.Tell(Handle); - BufferSize := ImagingIO.GetInputSize(GetIO, Handle); - GetMem(Buffer, BufferSize); - - SetLength(Images, 1); - with GetIO, Images[0] do - try - Read(Handle, Buffer, BufferSize); - cio := opj_cio_open(opj_common_ptr(dinfo), Buffer, BufferSize); - opj_setup_decoder(dinfo, @parameters); - // Decode image - image := opj_decode(dinfo, cio); - if image = nil then - Exit; - - // Determine which Imaging data format to use accorsing to - // decoded image components - case image.numcomps of - 2: case image.comps[0].prec of - 1..8: Format := ifA8Gray8; - 9..16: Format := ifA16Gray16; - end; - 3: case image.comps[0].prec of - 1..8: Format := ifR8G8B8; - 9..16: Format := ifR16G16B16; - end; - 4: case image.comps[0].prec of - 1..8: Format := ifA8R8G8B8; - 9..16: Format := ifA16R16G16B16; - end; - else - // There is only one component or there is more than four => - // just load the first one as gray - case image.comps[0].prec of - 1..8: Format := ifGray8; - 9..16: Format := ifGray16; - 17..32: Format := ifGray32; - end; - end; - // Exit if no compatible format was found - if Format = ifUnknown then - Exit; - - NewImage(image.x1 - image.x0, image.y1 - image.y0, Format, Images[0]); - Info := GetFormatInfo(Format); - ChannelSize := Info.BytesPerPixel div Info.ChannelCount; - SetLength(Channels, Info.ChannelCount); - - // Get information about all channels/components of JP2 file - for I := 0 to Info.ChannelCount - 1 do - begin - // Get component type for this channel and based on this - // determine where in dest image bits write this channel's data - Channels[I].CompType := image.comps[I].comp_type; - case Channels[I].CompType of - COMPTYPE_UNKNOWN: - begin - if Info.ChannelCount <> 4 then - begin - // Missing CDEF box in file - usually BGR order - Channels[I].DestOffset := image.numcomps - I - 1 - end - else - begin - // Missing CDEF box in file - usually ABGR order - if I = 3 then - Channels[I].DestOffset := 3 - else - Channels[I].DestOffset := image.numcomps - I - 2 - end; - end; - COMPTYPE_R: Channels[I].DestOffset := 2; - COMPTYPE_G: Channels[I].DestOffset := 1; - COMPTYPE_B: Channels[I].DestOffset := 0; - COMPTYPE_CB: Channels[I].DestOffset := 1; - COMPTYPE_CR: Channels[I].DestOffset := 0; - COMPTYPE_OPACITY: Channels[I].DestOffset := 3; - COMPTYPE_Y: - case image.color_space of - CLRSPC_SYCC: Channels[I].DestOffset := 2; // Y is intensity part of YCC - CLRSPC_GRAY: Channels[I].DestOffset := 0; // Y is independent gray channel - end; - end; - // Scale channel offset - Channels[I].DestOffset := Channels[I].DestOffset * ChannelSize; - // Signed componets must be scaled to [0, 1] interval (depends on precision) - if image.comps[I].sgnd = 1 then - Channels[I].Shift := 1 shl (image.comps[I].prec - 1); - // Max channel values used to easier scaling of precisions - // not supported by Imaging to supported ones (like 12bits etc.). - Channels[I].SrcMaxValue := 1 shl image.comps[I].prec - 1; - Channels[I].DestMaxValue := 1 shl (ChannelSize * 8) - 1; - end; - - // Images components are stored separately in JP2, each can have - // different dimensions, bitdepth, ... - for I := 0 to Info.ChannelCount - 1 do - ReadChannel(Images[0], Channels[I], image.comps[I], Info.BytesPerPixel); - - // If we have YCbCr image we need to convert it to RGB - if (image.color_space = CLRSPC_SYCC) and (Info.ChannelCount in [3, 4]) then - ConvertYCbCrToRGB(Bits, Width * Height, Info.BytesPerPixel); - - // Set the input position just after end of image - Seek(Handle, StartPos + Cardinal(cio.bp) - Cardinal(cio.start), smFromBeginning); - - Result := True; - finally - opj_image_destroy(image); - opj_destroy_decompress(dinfo); - opj_cio_close(cio); - FreeMem(Buffer); - end; -end; - -function TJpeg2000FileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - TargetSize, Rate: Single; - ImageToSave: TImageData; - MustBeFreed: Boolean; - Info: TImageFormatInfo; - I, Z, InvZ, Channel, ChannelSize, NumPixels: Integer; - Pix: PByte; - image: popj_image_t; - cio: popj_cio_t; - cinfo: popj_cinfo_t; - parameters: opj_cparameters_t; - compparams: popj_image_cmptparm_array; - ColorSpace: OPJ_COLOR_SPACE; - - function GetComponentType(Comp: Integer): OPJ_COMPONENT_TYPE; - begin - if Info.HasAlphaChannel and (Comp = Info.ChannelCount - 1) then - Result := COMPTYPE_OPACITY - else if Info.HasGrayChannel then - Result := COMPTYPE_Y - else if Comp = 2 then - Result := COMPTYPE_B - else if Comp = 1 then - Result := COMPTYPE_G - else if Comp = 0 then - Result := COMPTYPE_R - else - Result := COMPTYPE_UNKNOWN; - end; - -begin - Result := False; - image := nil; - compparams := nil; - cinfo := nil; - cio := nil; - // Makes image to save compatible with Jpeg 2000 saving capabilities - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - Info := GetFormatInfo(Format); - ChannelSize := Info.BytesPerPixel div Info.ChannelCount; - - // Fill component info structures and then create OpenJPEG image - GetMem(compparams, Info.ChannelCount * SizeOf(opj_image_comptparm)); - for I := 0 to Info.ChannelCount - 1 do - with compparams[I] do - begin - dx := 1; - dy := 1; - w := Width; - h := Height; - prec := (Info.BytesPerPixel div Info.ChannelCount) * 8; - bpp := prec; - sgnd := 0; - comp_type := GetComponentType(I); - x0 := 0; - y0 := 0; - end; - - if Info.HasGrayChannel then - ColorSpace := CLRSPC_GRAY - else - ColorSpace := CLRSPC_SRGB; - - image := opj_image_create(Info.ChannelCount, @compparams[0], ColorSpace); - if image = nil then Exit; - image.x1 := Width; - image.y1 := Height; - - if FCodeStreamOnly then - cinfo := opj_create_compress(CODEC_J2K) - else - cinfo := opj_create_compress(CODEC_JP2); - - // Set event manager to nil to avoid getting messages - cinfo.event_mgr := nil; - // Set compression parameters based current file format properties - opj_set_default_encoder_parameters(@parameters); - parameters.cod_format := Iff(FCodeStreamOnly, 0, 1); - parameters.numresolution := 6; - parameters.tcp_numlayers := 1; - parameters.cp_disto_alloc := 1; - if FLosslessCompression then - begin - // Set rate to 0 -> lossless - parameters.tcp_rates[0] := 0; - end - else - begin - // Quality -> Rate computation taken from ImageMagick - Rate := 100.0 / Sqr(115 - FQuality); - NumPixels := Width * Height * Info.BytesPerPixel; - TargetSize := (NumPixels * Rate) + 550 + (Info.ChannelCount - 1) * 142; - parameters.tcp_rates[0] := 1.0 / (TargetSize / NumPixels); - end; - // Setup encoder - opj_setup_encoder(cinfo, @parameters, image); - - // Fill component samples in data with values taken from - // image pixels. - // Components should be ordered like this: RGBA, YA, RGB, etc. - for Channel := 0 to Info.ChannelCount - 1 do - begin - Z := Channel; - InvZ := Info.ChannelCount - 1 - Z; - if Info.HasAlphaChannel then - begin - if Channel = Info.ChannelCount - 1 then - InvZ := Z - else - InvZ := Info.ChannelCount - 2 - Z; - end; - Pix := @PByteArray(Bits)[InvZ * ChannelSize]; - for I := 0 to Width * Height - 1 do - begin - case ChannelSize of - 1: image.comps[Z].data[I] := Pix^; - 2: image.comps[Z].data[I] := PWord(Pix)^; - 4: LongWord(image.comps[Z].data[I]) := PLongWord(Pix)^; - end; - Inc(Pix, Info.BytesPerPixel); - end; - end; - - // Open OpenJPEG output - cio := opj_cio_open(opj_common_ptr(cinfo), nil, 0); - // Try to encode the image - if not opj_encode(cinfo, cio, image, nil) then - Exit; - // Finally write buffer with encoded image to output - Write(Handle, cio.buffer, cio_tell(cio)); - - Result := True; - finally - if MustBeFreed then - FreeImage(ImageToSave); - opj_destroy_compress(cinfo); - opj_image_destroy(image); - opj_cio_close(cio); - FreeMem(compparams); - end; -end; - -procedure TJpeg2000FileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsFloatingPoint then - ConvFormat := IffFormat(Info.ChannelCount = 1, ifGray16, ifA16R16G16B16) - else if Info.HasGrayChannel then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16) - else if Info.IsIndexed then - ConvFormat := ifA8R8G8B8 - else if Info.BytesPerPixel div Info.ChannelCount > 1 then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16) - else - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8); - - ConvertImage(Image, ConvFormat); -end; - -function TJpeg2000FileFormat.TestFormat(Handle: TImagingHandle): Boolean; -begin - Result := False; - if Handle <> nil then - Result := GetFileType(Handle) <> jtInvalid; -end; - -initialization - RegisterImageFileFormat(TJpeg2000FileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.26.3 Changes/Bug Fixes ----------------------------------- - - Rewritten JP2 loading part (based on PasJpeg2000) to be - more readable (it's a bit faster too) and handled more JP2 files better: - components with precisions like 12bit (not direct Imaging equivalent) - are properly scaled, images/components with offsets are loaded ok. - - -- 0.24.3 Changes/Bug Fixes ----------------------------------- - - Alpha channels are now saved properly in FPC (GCC optimization issue), - FPC lossy compression enabled again! - - Added handling of component types (CDEF Box), JP2 images with alpha - are now properly recognized by other applications. - - Fixed wrong color space when saving grayscale images - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Removed ifGray32 from supported formats, OpenJPEG crashes when saving them. - - Added Seek after loading to set input pos to the end of image. - - Saving added losy/lossless, quality option added. - - Initial loading-only version created. - -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingJpegIJL.pas b/3rd/Imaging/Extras/Extensions/ImagingJpegIJL.pas deleted file mode 100644 index 67fed22ba..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingJpegIJL.pas +++ /dev/null @@ -1,447 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format alternative loader/saver for Jpeg images - using Intel Jpeg Library (Win32 only).} -unit ImagingJpegIJL; - -{$I ImagingOptions.inc} - -{$IFNDEF WIN32} - {$ERROR 'IJL 1.5 only for Win32'} -{$ENDIF} - -interface - -uses - SysUtils, ImagingTypes, Imaging, ImagingUtility, ImagingIO; - -type - { Class for loading/saving Jpeg images. This is alternative to - default built-in Jpeg handler (which uses JpegLib). - This handler uses Intel Jpeg Library 1.5 (DLL needed) and is - much faster than JpegLib (2-4x). Also supports reading and writing of - alpha channels in Jpeg files.} - TJpegFileFormatIJL = class(TImageFileFormat) - private - FQuality: LongInt; - procedure JpegError(Code: Integer); - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - procedure CheckOptionsValidity; override; - published - { Controls Jpeg save compression quality. It is number in range 1..100. - 1 means small/ugly file, 100 means large/nice file. Accessible trough - ImagingJpegQuality option.} - property Quality: LongInt read FQuality write FQuality; - end; - -implementation - -{$MINENUMSIZE 4} // Min enum size: 4 B - -uses - Types; - -const - SJpegFormatName = 'JPEG Image (IJL)'; - SJpegMasks = '*.jpg,*.jpeg,*.jfif,*.jpe,*.jif,*.jpa'; - JpegSupportedFormats: TImageFormats = [ifGray8, ifR8G8B8, ifA8R8G8B8]; - JpegDefaultQuality = 90; - JpegDefaultProgressive = False; - -resourcestring - SJpegError = 'JPEG Error'; - -const - { Jpeg file identifiers.} - JpegMagic: TChar2 = #$FF#$D8; - SIJLLibrary = 'ijl15.dll'; - -const - IJL_SETUP = -1; - IJL_OK = 0; - IJL_NONE = 0; - IJL_OTHER = 255; - JBUFSIZE = 4096; // Size of file I/O buffer (4K). - -type - { - Purpose: Possible types of data read/write/other operations to be - performed by the functions IJL_Read and IJL_Write. - See the Developer's Guide for details on appropriate usage. - Fields: - IJL_JFILE_XXXXXXX Indicates JPEG data in a stdio file. - IJL_JBUFF_XXXXXXX Indicates JPEG data in an addressable buffer. - } - TIJLIOType = ( - // Read JPEG parameters (i.e., height, width, channels, sampling, etc.) - // from a JPEG bit stream. - IJL_JFILE_READPARAMS = 0, - IJL_JBUFF_READPARAMS = 1, - // Read a JPEG Interchange Format image. - IJL_JFILE_READWHOLEIMAGE = 2, - IJL_JBUFF_READWHOLEIMAGE = 3, - // Read JPEG tables from a JPEG Abbreviated Format bit stream. - IJL_JFILE_READHEADER = 4, - IJL_JBUFF_READHEADER = 5, - // Read image info from a JPEG Abbreviated Format bit stream. - IJL_JFILE_READENTROPY = 6, - IJL_JBUFF_READENTROPY = 7, - // Write an entire JFIF bit stream. - IJL_JFILE_WRITEWHOLEIMAGE = 8, - IJL_JBUFF_WRITEWHOLEIMAGE = 9, - // Write a JPEG Abbreviated Format bit stream. - IJL_JFILE_WRITEHEADER = 10, - IJL_JBUFF_WRITEHEADER = 11, - // Write image info to a JPEG Abbreviated Format bit stream. - IJL_JFILE_WRITEENTROPY = 12, - IJL_JBUFF_WRITEENTROPY = 13, - - // Scaled Decoding Options: - // Reads a JPEG image scaled to 1/2 size. - IJL_JFILE_READONEHALF = 14, - IJL_JBUFF_READONEHALF = 15, - // Reads a JPEG image scaled to 1/4 size. - IJL_JFILE_READONEQUARTER = 16, - IJL_JBUFF_READONEQUARTER = 17, - // Reads a JPEG image scaled to 1/8 size. - IJL_JFILE_READONEEIGHTH = 18, - IJL_JBUFF_READONEEIGHTH = 19, - // Reads an embedded thumbnail from a JFIF bit stream. - IJL_JFILE_READTHUMBNAIL = 20, - IJL_JBUFF_READTHUMBNAIL = 21 - ); - - { - Purpose: Possible color space formats. - Note these formats do *not* necessarily denote - the number of channels in the color space. - There exists separate "channel" fields in the - JPEG_CORE_PROPERTIES data structure specifically - for indicating the number of channels in the - JPEG and/or DIB color spaces.} - TIJL_COLOR = ( - IJL_RGB = 1, // Red-Green-Blue color space. - IJL_BGR = 2, // Reversed channel ordering from IJL_RGB. - IJL_YCBCR = 3, // Luminance-Chrominance color space as defined - // by CCIR Recommendation 601. - IJL_G = 4, // Grayscale color space. - IJL_RGBA_FPX = 5, // FlashPix RGB 4 channel color space that - // has pre-multiplied opacity. - IJL_YCBCRA_FPX = 6 // FlashPix YCbCr 4 channel color space that - // has pre-multiplied opacity. - //IJL_OTHER = 255 // Some other color space not defined by the IJL. - // (This means no color space conversion will - // be done by the IJL.) - ); - - { Purpose: Possible subsampling formats used in the JPEG.} - TIJL_JPGSUBSAMPLING = ( - IJL_NOSUBSAMP = 0, - IJL_411 = 1, // Valid on a JPEG w/ 3 channels. - IJL_422 = 2, // Valid on a JPEG w/ 3 channels. - IJL_4114 = 3, // Valid on a JPEG w/ 4 channels. - IJL_4224 = 4 // Valid on a JPEG w/ 4 channels. - ); - - { Purpose: Possible subsampling formats used in the DIB. } - TIJL_DIBSUBSAMPLING = TIJL_JPGSUBSAMPLING; - - { Purpose: This is the primary data structure between the IJL and - the external user. It stores JPEG state information - and controls the IJL. It is user-modifiable. - Context: Used by all low-level IJL routines to store - pseudo-global information.} - TJpegCoreProperties = packed record - UseJPEGPROPERTIES : LongBool; // default = 0 - // DIB specific I/O data specifiers. - DIBBytes : PByte; // default = NULL - DIBWidth : LongWord; // default = 0 - DIBHeight : LongWord; // default = 0 - DIBPadBytes : LongWord; // default = 0 - DIBChannels : LongWord; // default = 3 - DIBColor : TIJL_COLOR; // default = IJL_BGR - DIBSubsampling : TIJL_DIBSUBSAMPLING; // default = IJL_NONE - // JPEG specific I/O data specifiers. - JPGFile : PAnsiChar; // default = NULL - JPGBytes : PByte; // default = NULL - JPGSizeBytes : LongWord; // default = 0 - JPGWidth : LongWord; // default = 0 - JPGHeight : LongWord; // default = 0 - JPGChannels : LongWord; // default = 3 - JPGColor : TIJL_COLOR; // default = IJL_YCBCR - JPGSubsampling : TIJL_JPGSUBSAMPLING; // default = IJL_411 - JPGThumbWidth : LongWord; // default = 0 - JPGThumbHeight : LongWord; // default = 0 - // JPEG conversion properties. - NeedsConvert : LongBool; // default = TRUE - NeedsResample : LongBool; // default = TRUE - Quality : LongWord; // default = 75 - // Low-level properties. - PropsAndUnused : array[0..19987] of Byte; - end; - PJpegCoreProperties = ^TJpegCoreProperties; - -function ijlInit(var Props: TJpegCoreProperties): Integer; stdcall; external SIJLLibrary; -function ijlFree(var Props: TJpegCoreProperties): Integer; stdcall; external SIJLLibrary; -function ijlRead(var Props: TJpegCoreProperties; IoType : TIJLIOTYPE): Integer; stdcall; external SIJLLibrary; -function ijlWrite(var Props: TJpegCoreProperties; IoType : TIJLIOTYPE): Integer; stdcall; external SIJLLibrary; -function ijlErrorStr(Code : Integer) : PAnsiChar; stdcall; external SIJLLibrary; - -{ TJpegFileFormatIJL class implementation } - -procedure TJpegFileFormatIJL.Define; -begin - inherited; - FName := SJpegFormatName; - FCanLoad := True; - FCanSave := True; - FIsMultiImageFormat := False; - FSupportedFormats := JpegSupportedFormats; - - FQuality := JpegDefaultQuality; - - AddMasks(SJpegMasks); - RegisterOption(ImagingJpegQuality, @FQuality); -end; - -procedure TJpegFileFormatIJL.CheckOptionsValidity; -begin - // Check if option values are valid - if not (FQuality in [1..100]) then - FQuality := JpegDefaultQuality; -end; - -procedure TJpegFileFormatIJL.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin - if Info.HasAlphaChannel then - ConvertImage(Image, ifA8R8G8B8) - else if Info.HasGrayChannel then - ConvertImage(Image, ifGray8) - else - ConvertImage(Image, ifR8G8B8); -end; - -function TJpegFileFormatIJL.TestFormat(Handle: TImagingHandle): Boolean; -var - ReadCount: LongInt; - ID: array[0..9] of AnsiChar; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - FillChar(ID, SizeOf(ID), 0); - ReadCount := Read(Handle, @ID, SizeOf(ID)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(ID)) and - CompareMem(@ID, @JpegMagic, SizeOf(JpegMagic)); - end; -end; - -procedure TJpegFileFormatIJL.JpegError(Code: Integer); -begin - raise EImagingError.Create(SJpegError + ': ' + ijlErrorStr(Code)); -end; - -function TJpegFileFormatIJL.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Props: TJpegCoreProperties; - Status: Integer; - Buffer: TDynByteArray; - InputLen: Integer; - JpegFmt: TImageFormat; -begin - // Copy IO functions to global var used in JpegLib callbacks - Result := False; - SetLength(Images, 1); - - with Images[0] do - try - InputLen := GetInputSize(GetIO, Handle); - - Status := IjlInit(Props); - if Status = IJL_OK then - begin - // Load input to memory and read Jpeg props - SetLength(Buffer, InputLen); - Props.JPGSizeBytes := InputLen; - Props.JPGBytes := @Buffer[0]; - GetIO.Read(Handle, @Buffer[0], InputLen); - Status := ijlRead(Props, IJL_JBUFF_READPARAMS); - end; - - if Status = IJL_OK then - begin - // Set image and DIB props based on Jpeg params read from input - case Props.JPGChannels of - 1: - begin - JpegFmt := ifGray8; - Props.DIBColor := IJL_G; - end; - 3: - begin - JpegFmt := ifR8G8B8; - Props.DIBColor := IJL_BGR; - end; - 4: - begin - JpegFmt := ifA8R8G8B8; - Props.DIBColor := IJL_RGBA_FPX; - end - else - Exit; - end; - - NewImage(Props.JPGWidth, Props.JPGHeight, JpegFmt, Images[0]); - - Props.DIBWidth := Props.JPGWidth; - Props.DIBHeight := Props.JPGHeight; - Props.DIBChannels := Props.JPGChannels; - Props.DIBPadBytes := 0; - Props.DIBBytes := Bits; - - // Now read the image bits - Status := ijlRead(Props, IJL_JBUFF_READWHOLEIMAGE); - end; - - if Status <> IJL_OK then - JpegError(Status); - - // Decoded images with alpha are in ABGR format so R and B chanels are switched - if JpegFmt = ifA8R8G8B8 then - SwapChannels(Images[0], ChannelRed, ChannelBlue); - - Result := True; - finally - ijlFree(Props); - end; -end; - -function TJpegFileFormatIJL.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - Props: TJpegCoreProperties; - Status: Integer; - Info: TImageFormatInfo; - ImageToSave: TImageData; - MustBeFreed: Boolean; - Buffer: TDynByteArray; -begin - Result := False; - // Makes image to save compatible with Jpeg saving capabilities - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with ImageToSave do - try - Status := ijlInit(Props); - if Status = IJL_OK then - begin - Info := GetFormatInfo(Format); - // Set all the needed props - Props.DIBWidth := Width; - Props.DIBHeight := Height; - Props.DIBChannels := Info.ChannelCount; - Props.DIBPadBytes := 0; - Props.DIBBytes := Bits; - - Props.Quality := FQuality; - - Props.JPGWidth := Width; - Props.JPGHeight := Height; - Props.JPGChannels := Info.ChannelCount; - SetLength(Buffer, Size); - Props.JPGSizeBytes := Size; - Props.JPGBytes := @Buffer[0]; - - case Info.ChannelCount of - 1: - begin - Props.DIBColor := IJL_G; - Props.JPGColor := IJL_G; - Props.JPGSubsampling := IJL_NOSUBSAMP; - end; - 3: - begin - Props.DIBColor := IJL_BGR; - Props.JPGColor := IJL_YCBCR; - Props.JPGSubsampling := IJL_411; - end; - 4: - begin - Props.DIBColor := IJL_RGBA_FPX; - Props.JPGColor := IJL_YCBCRA_FPX; - Props.JPGSubsampling := IJL_4114; - SwapChannels(ImageToSave, ChannelRed, ChannelBlue); // IJL expects ABGR order - end; - end; - - // Encode image - Status := ijlWrite(Props, IJL_JBUFF_WRITEWHOLEIMAGE); - end; - - if Status <> IJL_OK then - JpegError(Status); - - // Write temp buffer to file - GetIO.Write(Handle, @Buffer[0], Props.JPGSizeBytes); - - Result := True; - finally - ijlFree(Props); - if MustBeFreed then - FreeImage(ImageToSave) - else if Format = ifA8R8G8B8 then - SwapChannels(ImageToSave, ChannelRed, ChannelBlue); // Swap image back to ARGB if not temp - end; -end; - -initialization - RegisterImageFileFormat(TJpegFileFormatIJL); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Initial version created. -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingLibTiffDelphi.pas b/3rd/Imaging/Extras/Extensions/ImagingLibTiffDelphi.pas deleted file mode 100644 index b7701d306..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingLibTiffDelphi.pas +++ /dev/null @@ -1,605 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for TIFF images - using LibTiff C library compiled to object files for Delphi.} -unit ImagingLibTiffDelphi; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Imaging, ImagingTypes, ImagingUtility, ImagingIO, ImagingExtras, - LibTiffDelphi; - -type - { TIFF (Tag Image File Format) loader/saver class. Uses LibTiff so - it can handle most types of TIFF files.} - TTiffFileFormat = class(TImageFileFormat) - private - FCompression: Integer; - FJpegQuality: Integer; - FAppendMode: LongBool; - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: Integer): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - { Specifies compression scheme used when saving TIFF images. Supported values - are 0 (Uncompressed), 1 (LZW), 2 (PackBits RLE), 3 (Deflate - ZLib), 4 (JPEG), - 5 (CCITT Group 4 fax encoding - for binary images only). - Default is 1 (LZW). Note that not all images can be stored with - JPEG compression - these images will be saved with default compression if - JPEG is set.} - property Compression: Integer read FCompression write FCompression; - { Controls compression quality when selected TIFF compression is Jpeg. - It is number in range 1..100. 1 means small/ugly file, - 100 means large/nice file. Accessible trough ImagingTiffJpegQuality option.} - property JpegQuality: Integer read FJpegQuality write FJpegQuality; - { When activated (True = 1) existing TIFF files are not overwritten when saving but - new images are instead appended thus producing multipage TIFFs. - Default value is False (0).} - property AppendMode: LongBool read FAppendMode write FAppendMode; - end; - -implementation - -const - STiffFormatName = 'Tagged Image File Format'; - STiffMasks = '*.tif,*.tiff'; - TiffSupportedFormats: TImageFormats = [ifIndex8, ifGray8, ifA8Gray8, - ifGray16, ifA16Gray16, ifGray32, ifR8G8B8, ifA8R8G8B8, ifR16G16B16, - ifA16R16G16B16, ifR32F, ifA32R32G32B32F, ifR16F, ifA16R16G16B16F, ifBinary]; - TiffDefaultCompression = 1; - TiffDefaultJpegQuality = 90; - TiffDefaultAppendMode = False; - -const - TiffBEMagic: TChar4 = 'MM'#0#42; - TiffLEMagic: TChar4 = 'II'#42#0; - -type - TTiffIOWrapper = record - IO: TIOFunctions; - Handle: TImagingHandle; - end; - PTiffIOWrapper = ^TTiffIOWrapper; - -function TIFFReadProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; -begin - Result := PTiffIOWrapper(Fd).IO.Read(PTiffIOWrapper(Fd).Handle, Buffer, Size); -end; - -function TIFFWriteProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; -begin - Result := PTiffIOWrapper(Fd).IO.Write(PTiffIOWrapper(Fd).Handle, Buffer, Size); -end; - -function TIFFSizeProc(Fd: Cardinal): Cardinal; cdecl; -begin - Result := ImagingIO.GetInputSize(PTiffIOWrapper(Fd).IO, PTiffIOWrapper(Fd).Handle); -end; - -function TIFFSeekProc(Fd: Cardinal; Offset: Cardinal; Where: Integer): Cardinal; cdecl; -const - SEEK_SET = 0; - SEEK_CUR = 1; - SEEK_END = 2; -var - Mode: TSeekMode; -begin - if Offset = $FFFFFFFF then - begin - Result := $FFFFFFFF; - Exit; - end; - case Where of - SEEK_SET: Mode := smFromBeginning; - SEEK_CUR: Mode := smFromCurrent; - SEEK_END: Mode := smFromEnd; - else - Mode := smFromBeginning; - end; - Result := PTiffIOWrapper(Fd).IO.Seek(PTiffIOWrapper(Fd).Handle, Offset, Mode); -end; - -function TIFFCloseProc(Fd: Cardinal): Integer; cdecl; -begin - Result := 0; -end; - -function TIFFNoMapProc(Fd: Cardinal; Base: PPointer; Size: PCardinal): Integer; cdecl; -begin - Result := 0; -end; - -procedure TIFFNoUnmapProc(Fd: Cardinal; Base: Pointer; Size: Cardinal); cdecl; -begin -end; - -var - LastError: string = 'None'; - -procedure TIFFErrorHandler(const A, B: AnsiString); -begin - LastError := string(A + ': ' + B); -end; - -{ - TTiffFileFormat implementation -} - -procedure TTiffFileFormat.Define; -begin - inherited; - FName := STiffFormatName; - FFeatures := [ffLoad, ffSave, ffMultiImage, ffReadOnSave { needed for Append mode }]; - FSupportedFormats := TiffSupportedFormats; - FCompression := TiffDefaultCompression; - FJpegQuality := TiffDefaultJpegQuality; - FAppendMode := TiffDefaultAppendMode; - - AddMasks(STiffMasks); - RegisterOption(ImagingTiffCompression, @FCompression); - RegisterOption(ImagingTiffJpegQuality, @FJpegQuality); - RegisterOption(ImagingTiffAppendMode, @FAppendMode); -end; - -function TTiffFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Tiff: PTIFF; - IOWrapper: TTiffIOWrapper; - I, Idx, TiffResult, ScanLineSize, NumDirectories, X: Integer; - RowsPerStrip: LongWord; - Orientation, BitsPerSample, SamplesPerPixel, Photometric, - PlanarConfig, SampleFormat: Word; - DataFormat: TImageFormat; - CanAccessScanlines: Boolean; - Ptr: PByte; - Red, Green, Blue: PWordRecArray; - - procedure LoadMetadata(Tiff: PTiff; TiffPage: Integer); - var - TiffResUnit: Word; - XRes, YRes: Single; - ResUnit: TResolutionUnit; - begin - TIFFGetFieldDefaulted(Tiff, TIFFTAG_RESOLUTIONUNIT, @TiffResUnit); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_XRESOLUTION, @XRes); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_YRESOLUTION, @YRes); - if (TiffResUnit <> RESUNIT_NONE) and (XRes >= 0.1) and (YRes >= 0.1) then - begin - ResUnit := ruDpi; - if TiffResUnit = RESUNIT_CENTIMETER then - ResUnit := ruDpcm; - FMetadata.SetPhysicalPixelSize(ResUnit, XRes, YRes, False, TiffPage); - end; - end; - -begin - Result := False; - LibTiffDelphiSetErrorHandler(TIFFErrorHandler); - - // Set up IO wrapper and open TIFF - IOWrapper.IO := GetIO; - IOWrapper.Handle := Handle; - - Tiff := TIFFClientOpen('LibTIFF', 'r', Cardinal(@IOWrapper), @TIFFReadProc, - @TIFFWriteProc, @TIFFSeekProc, @TIFFCloseProc, - @TIFFSizeProc, @TIFFNoMapProc, @TIFFNoUnmapProc); - - if Tiff <> nil then - TIFFSetFileNo(Tiff, Cardinal(@IOWrapper)) - else - Exit; - - NumDirectories := TIFFNumberOfDirectories(Tiff); - if OnlyFirstLevel then - NumDirectories := Min(1, NumDirectories); - - SetLength(Images, NumDirectories); - - for Idx := 0 to NumDirectories - 1 do - begin - TIFFSetDirectory(Tiff, Idx); - - // Set defaults for TIFF fields - DataFormat := ifUnknown; - - // Read some TIFF fields with basic image info - TIFFGetField(Tiff, TIFFTAG_IMAGEWIDTH, @Images[Idx].Width); - TIFFGetField(Tiff, TIFFTAG_IMAGELENGTH, @Images[Idx].Height); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_ORIENTATION, @Orientation); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_BITSPERSAMPLE, @BitsPerSample); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_SAMPLESPERPIXEL, @SamplesPerPixel); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_SAMPLEFORMAT, @SampleFormat); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_PHOTOMETRIC, @Photometric); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_PLANARCONFIG, @PlanarConfig); - TIFFGetFieldDefaulted(Tiff, TIFFTAG_ROWSPERSTRIP, @RowsPerStrip); - - // Load supported metadata - LoadMetadata(Tiff, Idx); - // See if we can just copy scanlines from TIFF to Imaging image - CanAccessScanlines := (PlanarConfig = PLANARCONFIG_CONTIG) or (SamplesPerPixel = 1); - - if CanAccessScanlines then - begin - // We can copy scanlines so we try to find data format that best matches - // TIFFs internal data format - if (Photometric = PHOTOMETRIC_MINISBLACK) or (Photometric = PHOTOMETRIC_MINISWHITE) then - begin - if SampleFormat = SAMPLEFORMAT_UINT then - begin - case BitsPerSample of - 1: - if SamplesPerPixel = 1 then - DataFormat := ifBinary; - 8: - case SamplesPerPixel of - 1: DataFormat := ifGray8; - 2: DataFormat := ifA8Gray8; - end; - 16: - case SamplesPerPixel of - 1: DataFormat := ifGray16; - 2: DataFormat := ifA16Gray16; - end; - 32: - if SamplesPerPixel = 1 then - DataFormat := ifGray32; - end; - end - else if SampleFormat = SAMPLEFORMAT_IEEEFP then - begin - case BitsPerSample of - 16: - if SamplesPerPixel = 1 then - DataFormat := ifR16F; - 32: - if SamplesPerPixel = 1 then - DataFormat := ifR32F; - end; - end; - end - else if Photometric = PHOTOMETRIC_RGB then - begin - if SampleFormat = SAMPLEFORMAT_UINT then - begin - case BitsPerSample of - 8: - case SamplesPerPixel of - 3: DataFormat := ifR8G8B8; - 4: DataFormat := ifA8R8G8B8; - end; - 16: - case SamplesPerPixel of - 3: DataFormat := ifR16G16B16; - 4: DataFormat := ifA16R16G16B16; - end; - end; - end - else if SampleFormat = SAMPLEFORMAT_IEEEFP then - begin - case BitsPerSample of - 16: - if SamplesPerPixel = 4 then - DataFormat := ifA16R16G16B16F; - 32: - if SamplesPerPixel = 4 then - DataFormat := ifA32R32G32B32F; - end; - end; - end - else if Photometric = PHOTOMETRIC_PALETTE then - begin - if (SamplesPerPixel = 1) and (SampleFormat = SAMPLEFORMAT_UINT) and (BitsPerSample = 8) then - DataFormat := ifIndex8 - end; - end; - - if DataFormat = ifUnknown then - begin - // Use RGBA interface to read A8R8G8B8 TIFFs and mainly TIFFs in various - // formats with no Imaging equivalent, exotic color spaces etc. - NewImage(Images[Idx].Width, Images[Idx].Height, ifA8R8G8B8, Images[Idx]); - TiffResult := TIFFReadRGBAImageOriented(Tiff, Images[Idx].Width, Images[Idx].Height, - Images[Idx].Bits, Orientation, 0); - if TiffResult = 0 then - RaiseImaging(LastError, []); - end - else - begin - // Create new image in given format and read scanlines from TIFF, - // read palette too if needed - NewImage(Images[Idx].Width, Images[Idx].Height, DataFormat, Images[Idx]); - ScanLineSize := TIFFScanlineSize(Tiff); - - for I := 0 to Images[Idx].Height - 1 do - TIFFReadScanline(Tiff, @PByteArray(Images[Idx].Bits)[I * ScanLineSize], I, 0); - - if DataFormat = ifIndex8 then - begin - TIFFGetField(Tiff, TIFFTAG_COLORMAP, @Red, @Green, @Blue); - for I := 0 to 255 do - with Images[Idx].Palette[I] do - begin - A := 255; - R := Red[I].High; - G := Green[I].High; - B := Blue[I].High; - end; - end; - - // TIFF uses BGR order so we must swap it (but not images we got - // from TiffLib RGBA interface) - if Photometric = PHOTOMETRIC_RGB then - SwapChannels(Images[Idx], ChannelRed, ChannelBlue); - - // We need to negate 'MinIsWhite' formats to get common grayscale - // formats where min sample value is black - if Photometric = PHOTOMETRIC_MINISWHITE then - for I := 0 to Images[Idx].Height - 1 do - begin - Ptr := @PByteArray(Images[Idx].Bits)[I * ScanLineSize]; - for X := 0 to ScanLineSize - 1 do - begin - Ptr^ := not Ptr^; - Inc(Ptr); - end; - end; - end; - end; - - TIFFClose(Tiff); - Result := True; -end; - -function TTiffFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -const - Compressions: array[0..5] of Word = (COMPRESSION_NONE, COMPRESSION_LZW, - COMPRESSION_PACKBITS, COMPRESSION_DEFLATE, COMPRESSION_JPEG, COMPRESSION_CCITTFAX4); -var - Tiff: PTIFF; - IOWrapper: TTiffIOWrapper; - I, J, ScanLineSize: Integer; - ImageToSave: TImageData; - MustBeFreed: Boolean; - Info: TImageFormatInfo; - Orientation, BitsPerSample, SamplesPerPixel, Photometric, - PlanarConfig, SampleFormat, CompressionScheme: Word; - RowsPerStrip: LongWord; - Red, Green, Blue: array[Byte] of TWordRec; - CompressionMismatch: Boolean; - OpenMode: PAnsiChar; - - procedure SaveMetadata(Tiff: PTiff; TiffPage: Integer); - var - XRes, YRes: Single; - begin - XRes := -1; - YRes := -1; - - // First try to find phys. size for current TIFF page index. If not found then - // try size for main image (index 0). - if not FMetadata.GetPhysicalPixelSize(ruDpcm, XRes, YRes, True, TiffPage) then - FMetadata.GetPhysicalPixelSize(ruDpcm, XRes, YRes, True, 0); - - if (XRes > 0) and (YRes > 0) then - begin - TIFFSetField(Tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER); - TIFFSetField(Tiff, TIFFTAG_XRESOLUTION, XRes); - TIFFSetField(Tiff, TIFFTAG_YRESOLUTION, YRes); - end; - end; - -begin - Result := False; - LibTiffDelphiSetErrorHandler(TIFFErrorHandler); - - if not (FCompression in [0..5]) then - FCompression := TiffDefaultCompression; - - // Set up IO wrapper and open TIFF - IOWrapper.IO := GetIO; - IOWrapper.Handle := Handle; - - OpenMode := 'w'; - if FAppendMode then - OpenMode := 'a'; - - Tiff := TIFFClientOpen('LibTIFF', OpenMode, Cardinal(@IOWrapper), @TIFFReadProc, - @TIFFWriteProc, @TIFFSeekProc, @TIFFCloseProc, - @TIFFSizeProc, @TIFFNoMapProc, @TIFFNoUnmapProc); - - if Tiff <> nil then - TIFFSetFileNo(Tiff, Cardinal(@IOWrapper)) - else - Exit; - - for I := FFirstIdx to FLastIdx do - begin - if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - GetImageFormatInfo(Format, Info); - - // Set Tag values - Orientation := ORIENTATION_TOPLEFT; - BitsPerSample := Info.BytesPerPixel div Info.ChannelCount * 8; - if Info.Format = ifBinary then - BitsPerSample := 1; - SamplesPerPixel := Info.ChannelCount; - SampleFormat := Iff(not Info.IsFloatingPoint, SAMPLEFORMAT_UINT, SAMPLEFORMAT_IEEEFP); - PlanarConfig := PLANARCONFIG_CONTIG; - CompressionScheme := Compressions[FCompression]; - - // Check if selected compression scheme can be used for current image - CompressionMismatch := (CompressionScheme = COMPRESSION_JPEG) and ((BitsPerSample <> 8) or - not (SamplesPerPixel in [1, 3]) or Info.IsIndexed or Info.IsFloatingPoint); - CompressionMismatch := CompressionMismatch or ((CompressionScheme = COMPRESSION_CCITTFAX4) and (Info.Format <> ifBinary)); - if CompressionMismatch then - CompressionScheme := Compressions[TiffDefaultCompression]; - // If we have some compression scheme selected and it's not Fax then select it automatically - better comp ratios! - if (Info.Format = ifBinary) and (CompressionScheme <> COMPRESSION_NONE) and (CompressionScheme <> COMPRESSION_CCITTFAX4) then - CompressionScheme := COMPRESSION_CCITTFAX4; - - RowsPerStrip := TIFFDefaultStripSize(Tiff, Height); - if Info.IsIndexed then - Photometric := PHOTOMETRIC_PALETTE - else if (Info.HasGrayChannel) or (Info.ChannelCount = 1) then - Photometric := PHOTOMETRIC_MINISBLACK - else - Photometric := PHOTOMETRIC_RGB; - - // Write tags - TIFFSetField(Tiff, TIFFTAG_IMAGEWIDTH, Width); - TIFFSetField(Tiff, TIFFTAG_IMAGELENGTH, Height); - TIFFSetField(Tiff, TIFFTAG_PHOTOMETRIC, Photometric); - TIFFSetField(Tiff, TIFFTAG_PLANARCONFIG, PlanarConfig); - TIFFSetField(Tiff, TIFFTAG_ORIENTATION, Orientation); - TIFFSetField(Tiff, TIFFTAG_BITSPERSAMPLE, BitsPerSample); - TIFFSetField(Tiff, TIFFTAG_SAMPLESPERPIXEL, SamplesPerPixel); - TIFFSetField(Tiff, TIFFTAG_SAMPLEFORMAT, SampleFormat); - TIFFSetField(Tiff, TIFFTAG_COMPRESSION, CompressionScheme); - if CompressionScheme = COMPRESSION_JPEG then - TIFFSetField(Tiff, TIFFTAG_JPEGQUALITY, FJpegQuality); - TIFFSetField(Tiff, TIFFTAG_ROWSPERSTRIP, RowsPerStrip); - // Save supported metadata - SaveMetadata(Tiff, I); - - if Format = ifIndex8 then - begin - // Set paletee for indexed images - for J := 0 to 255 do - with ImageToSave.Palette[J] do - begin - Red[J].High := R; - Green[J].High := G; - Blue[J].High := B; - end; - TIFFSetField(Tiff, TIFFTAG_COLORMAP, Red, Green, Blue); - end; - - ScanLineSize := Info.GetPixelsSize(Info.Format, Width, 1); - - if Photometric = PHOTOMETRIC_RGB then - SwapChannels(ImageToSave, ChannelRed, ChannelBlue); - // Write image scanlines and then directory for current image - for J := 0 to Height - 1 do - TIFFWriteScanline(Tiff, @PByteArray(Bits)[J * ScanLineSize], J, 0); - if Info.ChannelCount > 1 then - SwapChannels(ImageToSave, ChannelRed, ChannelBlue); - - TIFFWriteDirectory(Tiff); - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; - end; - - TIFFClose(Tiff); - Result := True; -end; - -procedure TTiffFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.RBSwapFormat in GetSupportedFormats then - ConvFormat := Info.RBSwapFormat - else if Info.IsFloatingPoint then - ConvFormat := IffFormat(Info.ChannelCount = 1, ifR32F, ifA32R32G32B32F) - else if Info.HasGrayChannel then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray32) - else - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8); - - ConvertImage(Image, ConvFormat); -end; - -function TTiffFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Magic: TChar4; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Magic, SizeOf(Magic)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount >= SizeOf(Magic)) and - ((Magic = TiffBEMagic) or (Magic = TiffLEMagic)); - end; -end; - -initialization - RegisterImageFileFormat(TTiffFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 ---------------------------------------------------- - - Renamed unit to ImagingLibTiffDelphi since there will be more - Tiff implementations in the future, cleaned up interface units - and obj file a little bit. - - Updated LibTiff to version 3.9.4 and added EXIF tag support. - - Added TIFF Append mode: when saving existing files are not - overwritten but images are appended to TIFF instead. - - Images in ifBinary format are now supported for loading/saving - (optional Group 4 fax encoding added). - - PHOTOMETRIC_MINISWHITE is now properly read as Grayscale/Binary - instead of using unefficient RGBA interface. - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Fix: All pages of multipage TIFF were loaded even when - OnlyFirstLevel was True. - - Loading and saving of physical resolution metadata. - - Unicode compatibility fixes in LibTiffDelphi. - - Added Jpeg compression quality setting. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - Fixed bug in loading and saving of 2 channel images - Imaging - tried to swap R and B channels here. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added TIFF loading and saving. - - Unit created and initial code added. -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingOpenGL.pas b/3rd/Imaging/Extras/Extensions/ImagingOpenGL.pas deleted file mode 100644 index 19ae6bb8a..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingOpenGL.pas +++ /dev/null @@ -1,955 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains functions for loading and saving OpenGL textures - using Imaging and for converting images to textures and vice versa.} -unit ImagingOpenGL; - -{$I ImagingOptions.inc} - -{ Define this symbol if you want to use dglOpenGL header.} -{$DEFINE USE_DGL_HEADERS} -{ $DEFINE USE_GLSCENE_HEADERS} - -interface - -uses - SysUtils, Classes, ImagingTypes, Imaging, ImagingFormats, -{$IF Defined(USE_DGL_HEADERS)} - dglOpenGL, -{$ELSEIF Defined(USE_GLSCENE_HEADERS)} - OpenGL1x, -{$ELSE} - gl, glext, -{$IFEND} - ImagingUtility; - -type - { Various texture capabilities of installed OpenGL driver.} - TGLTextureCaps = record - MaxTextureSize: LongInt; // Max size of texture in pixels supported by HW - NonPowerOfTwo: Boolean; // HW has full support for NPOT textures - DXTCompression: Boolean; // HW supports S3TC/DXTC compressed textures - ATI3DcCompression: Boolean; // HW supports ATI 3Dc compressed textures (ATI2N) - LATCCompression: Boolean; // HW supports LATC/RGTC compressed textures (ATI1N+ATI2N) - FloatTextures: Boolean; // HW supports floating point textures - MaxAnisotropy: LongInt; // Max anisotropy for aniso texture filtering - MaxSimultaneousTextures: LongInt; // Number of texture units - ClampToEdge: Boolean; // GL_EXT_texture_edge_clamp - TextureLOD: Boolean; // GL_SGIS_texture_lod - VertexTextureUnits: Integer; // Texture units accessible in vertex programs - end; - -{ Returns texture capabilities of installed OpenGL driver.} -function GetGLTextureCaps(var Caps: TGLTextureCaps): Boolean; -{ Function which can be used to retrieve GL extension functions.} -function GetGLProcAddress(const ProcName: string): Pointer; -{ Returns True if the given GL extension is supported.} -function IsGLExtensionSupported(const Extension: string): Boolean; -{ Returns True if the given image format can be represented as GL texture - format. GLFormat, GLType, and GLInternal are parameters for functions like - glTexImage. Note that GLU functions like gluBuildMipmaps cannot handle some - formats returned by this function (i.e. GL_UNSIGNED_SHORT_5_5_5_1 as GLType). - If you are using compressed or floating-point images make sure that they are - supported by hardware using GetGLTextureCaps, ImageFormatToGL does not - check this.} -function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum; - var GLType: GLenum; var GLInternal: GLint; const Caps: TGLTextureCaps): Boolean; - -{ All GL textures created by Imaging functions have default parameters set - - that means that no glTexParameter calls are made so default filtering, - wrapping, and other parameters are used. Created textures - are left bound by glBindTexture when function is exited.} - -{ Creates GL texture from image in file in format supported by Imaging. - You can use CreatedWidth and Height parameters to query dimensions of created textures - (it could differ from dimensions of source image).} -function LoadGLTextureFromFile(const FileName: string; CreatedWidth: PLongInt = nil; - CreatedHeight: PLongInt = nil): GLuint; -{ Creates GL texture from image in stream in format supported by Imaging. - You can use CreatedWidth and Height parameters to query dimensions of created textures - (it could differ from dimensions of source image).} -function LoadGLTextureFromStream(Stream: TStream; CreatedWidth: PLongInt = nil; - CreatedHeight: PLongInt = nil): GLuint; -{ Creates GL texture from image in memory in format supported by Imaging. - You can use CreatedWidth and Height parameters to query dimensions of created textures - (it could differ from dimensions of source image).} -function LoadGLTextureFromMemory(Data: Pointer; Size: LongInt; - CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): GLuint; - -{ Converts TImageData structure to OpenGL texture. - Input images is used as main mipmap level and additional requested - levels are generated from this one. For the details on parameters - look at CreateGLTextureFromMultiImage function.} -function CreateGLTextureFromImage(const Image: TImageData; - Width: LongInt = 0; Height: LongInt = 0; MipMaps: Boolean = True; - OverrideFormat: TImageFormat = ifUnknown; CreatedWidth: PLongInt = nil; - CreatedHeight: PLongInt = nil): GLuint; -{ Converts images in TDymImageDataArray to one OpenGL texture. - Image at index MainLevelIndex in the array is used as main mipmap level and - additional images are used as subsequent levels. If there is not enough images - in array missing levels are automatically generated (and if there is enough images - but they have wrong dimensions or format then they are resized/converted). - If driver supports only power of two sized textures images are resized. - OverrideFormat can be used to convert image into specific format before - it is passed to OpenGL, ifUnknown means no conversion. - If desired texture format is not supported by hardware default - A8R8G8B8 format is used instead for color images and ifGray8 is used - for luminance images. DXTC (S3TC) compressed and floating point textures - are created if supported by hardware. - Width and Height can be used to set size of main mipmap level according - to your needs, Width and Height of 0 mean use width and height of input - image that will become main level mipmap. - MipMaps set to True mean build all possible levels, False means use only level 0. - You can use CreatedWidth and CreatedHeight parameters to query dimensions of - created texture's largest mipmap level (it could differ from dimensions - of source image).} -function CreateGLTextureFromMultiImage(const Images: TDynImageDataArray; - Width: LongInt = 0; Height: LongInt = 0; MipMaps: Boolean = True; - MainLevelIndex: LongInt = 0; OverrideFormat: TImageFormat = ifUnknown; - CreatedWidth: PLongInt = nil; CreatedHeight: PLongInt = nil): GLuint; - -{ Saves GL texture to file in one of formats supported by Imaging. - Saves all present mipmap levels.} -function SaveGLTextureToFile(const FileName: string; const Texture: GLuint): Boolean; -{ Saves GL texture to stream in one of formats supported by Imaging. - Saves all present mipmap levels.} -function SaveGLTextureToStream(const Ext: string; Stream: TStream; const Texture: GLuint): Boolean; -{ Saves GL texture to memory in one of formats supported by Imaging. - Saves all present mipmap levels.} -function SaveGLTextureToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Texture: GLuint): Boolean; - -{ Converts main level of the GL texture to TImageData strucrue. OverrideFormat - can be used to convert output image to the specified format rather - than use the format taken from GL texture, ifUnknown means no conversion.} -function CreateImageFromGLTexture(const Texture: GLuint; - var Image: TImageData; OverrideFormat: TImageFormat = ifUnknown): Boolean; -{ Converts GL texture to TDynImageDataArray array of images. You can specify - how many mipmap levels of the input texture you want to be converted - (default is all levels). OverrideFormat can be used to convert output images to - the specified format rather than use the format taken from GL texture, - ifUnknown means no conversion.} -function CreateMultiImageFromGLTexture(const Texture: GLuint; - var Images: TDynImageDataArray; MipLevels: LongInt = 0; - OverrideFormat: TImageFormat = ifUnknown): Boolean; - -var - { Standard behaviour of image->texture functions like CreateGLTextureFrom(Multi)Image is: - If graphic card supports non power of 2 textures and image is nonpow2 then - texture is created directly from image. - If graphic card does not support them input image is rescaled (bilinear) - to power of 2 size. - If you set PasteNonPow2ImagesIntoPow2 to True then instead of rescaling, a new - pow2 texture is created and nonpow2 input image is pasted into it - keeping its original size. This could be useful for some 2D stuff - (and its faster than rescaling of course). Note that this is applied - to all rescaling smaller->bigger operations that might ocurr during - image->texture process (usually only pow2/nonpow2 stuff and when you - set custom Width & Height in CreateGLTextureFrom(Multi)Image).} - PasteNonPow2ImagesIntoPow2: Boolean = False; - { Standard behaviur if GL_ARB_texture_non_power_of_two extension is not supported - is to rescale image to power of 2 dimensions. NPOT extension is exposed only - when HW has full support for NPOT textures but some cards - (pre-DX10 ATI Radeons, some other maybe) have partial NPOT support. - Namely Radeons can use NPOT textures but not mipmapped. If you know what you are doing - you can disable NPOT support check so the image won't be rescaled to POT - by seting DisableNPOTSupportCheck to True.} - DisableNPOTSupportCheck: Boolean = False; - -implementation - -const - // Cube map consts - GL_TEXTURE_BINDING_CUBE_MAP = $8514; - GL_TEXTURE_CUBE_MAP_POSITIVE_X = $8515; - GL_TEXTURE_CUBE_MAP_NEGATIVE_X = $8516; - GL_TEXTURE_CUBE_MAP_POSITIVE_Y = $8517; - GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = $8518; - GL_TEXTURE_CUBE_MAP_POSITIVE_Z = $8519; - GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = $851A; - - // Texture formats - GL_COLOR_INDEX = $1900; - GL_STENCIL_INDEX = $1901; - GL_DEPTH_COMPONENT = $1902; - GL_RED = $1903; - GL_GREEN = $1904; - GL_BLUE = $1905; - GL_ALPHA = $1906; - GL_RGB = $1907; - GL_RGBA = $1908; - GL_LUMINANCE = $1909; - GL_LUMINANCE_ALPHA = $190A; - GL_BGR_EXT = $80E0; - GL_BGRA_EXT = $80E1; - - // Texture internal formats - GL_ALPHA4 = $803B; - GL_ALPHA8 = $803C; - GL_ALPHA12 = $803D; - GL_ALPHA16 = $803E; - GL_LUMINANCE4 = $803F; - GL_LUMINANCE8 = $8040; - GL_LUMINANCE12 = $8041; - GL_LUMINANCE16 = $8042; - GL_LUMINANCE4_ALPHA4 = $8043; - GL_LUMINANCE6_ALPHA2 = $8044; - GL_LUMINANCE8_ALPHA8 = $8045; - GL_LUMINANCE12_ALPHA4 = $8046; - GL_LUMINANCE12_ALPHA12 = $8047; - GL_LUMINANCE16_ALPHA16 = $8048; - GL_INTENSITY = $8049; - GL_INTENSITY4 = $804A; - GL_INTENSITY8 = $804B; - GL_INTENSITY12 = $804C; - GL_INTENSITY16 = $804D; - GL_R3_G3_B2 = $2A10; - GL_RGB4 = $804F; - GL_RGB5 = $8050; - GL_RGB8 = $8051; - GL_RGB10 = $8052; - GL_RGB12 = $8053; - GL_RGB16 = $8054; - GL_RGBA2 = $8055; - GL_RGBA4 = $8056; - GL_RGB5_A1 = $8057; - GL_RGBA8 = $8058; - GL_RGB10_A2 = $8059; - GL_RGBA12 = $805A; - GL_RGBA16 = $805B; - GL_RGB565 = $8D62; - - // Floating point texture formats - GL_RGBA32F_ARB = $8814; - GL_INTENSITY32F_ARB = $8817; - GL_LUMINANCE32F_ARB = $8818; - GL_RGBA16F_ARB = $881A; - GL_INTENSITY16F_ARB = $881D; - GL_LUMINANCE16F_ARB = $881E; - - // Compressed texture formats - // S3TC/DXTC - GL_COMPRESSED_RGB_S3TC_DXT1_EXT = $83F0; - GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = $83F1; - GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = $83F2; - GL_COMPRESSED_RGBA_S3TC_DXT5_EXT = $83F3; - // 3Dc LATC - GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI = $8837; - GL_COMPRESSED_LUMINANCE_LATC1_EXT = $8C70; - GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = $8C71; - GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = $8C72; - GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = $8C73; - // ETC1 GL_OES_compressed_ETC1_RGB8_texture - GL_ETC1_RGB_OES = $8D64; - // PVRTC GL_IMG_texture_compression_pvrtc - GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = $8C00; - GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = $8C01; - GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = $8C02; - GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = $8C03; - // AMD ATC - GL_ATC_RGBA_EXPLICIT_ALPHA_AMD = $8C93; - GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD = $87EE; - // ETC2/EAC - GL_COMPRESSED_R11_EAC = $9270; - GL_COMPRESSED_SIGNED_R11_EAC = $9271; - GL_COMPRESSED_RG11_EAC = $9272; - GL_COMPRESSED_SIGNED_RG11_EAC = $9273; - GL_COMPRESSED_RGB8_ETC2 = $9274; - GL_COMPRESSED_SRGB8_ETC2 = $9275; - GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = $9276; - GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = $9277; - GL_COMPRESSED_RGBA8_ETC2_EAC = $9278; - GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = $9279; - - // Various GL extension constants - GL_MAX_TEXTURE_UNITS = $84E2; - GL_TEXTURE_MAX_ANISOTROPY_EXT = $84FE; - GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = $84FF; - - // Texture source data formats - GL_UNSIGNED_BYTE_3_3_2 = $8032; - GL_UNSIGNED_SHORT_4_4_4_4 = $8033; - GL_UNSIGNED_SHORT_5_5_5_1 = $8034; - GL_UNSIGNED_INT_8_8_8_8 = $8035; - GL_UNSIGNED_INT_10_10_10_2 = $8036; - GL_UNSIGNED_BYTE_2_3_3_REV = $8362; - GL_UNSIGNED_SHORT_5_6_5 = $8363; - GL_UNSIGNED_SHORT_5_6_5_REV = $8364; - GL_UNSIGNED_SHORT_4_4_4_4_REV = $8365; - GL_UNSIGNED_SHORT_1_5_5_5_REV = $8366; - GL_UNSIGNED_INT_8_8_8_8_REV = $8367; - GL_UNSIGNED_INT_2_10_10_10_REV = $8368; - GL_HALF_FLOAT_ARB = $140B; - - // Other GL constants - GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS = $8B4C; - - -{$IFDEF MSWINDOWS} - GLLibName = 'opengl32.dll'; -{$ENDIF} -{$IFDEF UNIX} - GLLibName = 'libGL.so'; -{$ENDIF} - -type - TglCompressedTexImage2D = procedure (Target: GLenum; Level: GLint; - InternalFormat: GLenum; Width: GLsizei; Height: GLsizei; Border: GLint; - ImageSize: GLsizei; const Data: PGLvoid); - {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} -var - glCompressedTexImage2D: TglCompressedTexImage2D = nil; - ExtensionBuffer: string = ''; - -{$IFDEF MSWINDOWS} -function wglGetProcAddress(ProcName: PAnsiChar): Pointer; stdcall; external GLLibName; -{$ENDIF} -{$IFDEF UNIX} -function glXGetProcAddress(ProcName: PAnsiChar): Pointer; cdecl; external GLLibName; -{$ENDIF} - -function IsGLExtensionSupported(const Extension: string): Boolean; -var - ExtPos: LongInt; -begin - if ExtensionBuffer = '' then - ExtensionBuffer := glGetString(GL_EXTENSIONS); - - ExtPos := Pos(Extension, ExtensionBuffer); - Result := ExtPos > 0; - if Result then - begin - Result := ((ExtPos + Length(Extension) - 1) = Length(ExtensionBuffer)) or - not (ExtensionBuffer[ExtPos + Length(Extension)] in ['_', 'A'..'Z', 'a'..'z']); - end; -end; - -function GetGLProcAddress(const ProcName: string): Pointer; -begin -{$IFDEF MSWINDOWS} - Result := wglGetProcAddress(PAnsiChar(AnsiString(ProcName))); -{$ENDIF} -{$IFDEF UNIX} - Result := glXGetProcAddress(PAnsiChar(AnsiString(ProcName))); -{$ENDIF} -end; - -function GetGLTextureCaps(var Caps: TGLTextureCaps): Boolean; -begin - // Check DXTC support and load extension functions if necesary - Caps.DXTCompression := IsGLExtensionSupported('GL_ARB_texture_compression') and - IsGLExtensionSupported('GL_EXT_texture_compression_s3tc'); - if Caps.DXTCompression then - glCompressedTexImage2D := GetGLProcAddress('glCompressedTexImage2D'); - Caps.DXTCompression := Caps.DXTCompression and (@glCompressedTexImage2D <> nil); - Caps.ATI3DcCompression := Caps.DXTCompression and - IsGLExtensionSupported('GL_ATI_texture_compression_3dc'); - Caps.LATCCompression := Caps.DXTCompression and - IsGLExtensionSupported('GL_EXT_texture_compression_latc'); - // Check non power of 2 textures - Caps.NonPowerOfTwo := IsGLExtensionSupported('GL_ARB_texture_non_power_of_two'); - // Check for floating point textures support - Caps.FloatTextures := IsGLExtensionSupported('GL_ARB_texture_float'); - // Get max texture size - glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize); - // Get max anisotropy - if IsGLExtensionSupported('GL_EXT_texture_filter_anisotropic') then - glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, @Caps.MaxAnisotropy) - else - Caps.MaxAnisotropy := 0; - // Get number of texture units - if IsGLExtensionSupported('GL_ARB_multitexture') then - glGetIntegerv(GL_MAX_TEXTURE_UNITS, @Caps.MaxSimultaneousTextures) - else - Caps.MaxSimultaneousTextures := 1; - // Get number of vertex texture units - if IsGLExtensionSupported('GL_ARB_vertex_shader') then - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, @Caps.VertexTextureUnits) - else - Caps.VertexTextureUnits := 1; - // Get max texture size - glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Caps.MaxTextureSize); - // Clamp texture to edge? - Caps.ClampToEdge := IsGLExtensionSupported('GL_EXT_texture_edge_clamp'); - // Texture LOD extension? - Caps.TextureLOD := IsGLExtensionSupported('GL_SGIS_texture_lod'); - - Result := True; -end; - -function ImageFormatToGL(Format: TImageFormat; var GLFormat: GLenum; - var GLType: GLenum; var GLInternal: GLint; const Caps: TGLTextureCaps): Boolean; -begin - GLFormat := 0; - GLType := 0; - GLInternal := 0; - case Format of - // Gray formats - ifGray8, ifGray16: - begin - GLFormat := GL_LUMINANCE; - GLType := Iff(Format = ifGray8, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT); - GLInternal := Iff(Format = ifGray8, GL_LUMINANCE8, GL_LUMINANCE16); - end; - ifA8Gray8, ifA16Gray16: - begin - GLFormat := GL_LUMINANCE_ALPHA; - GLType := Iff(Format = ifA8Gray8, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT); - GLInternal := Iff(Format = ifA8Gray8, GL_LUMINANCE8_ALPHA8, GL_LUMINANCE16_ALPHA16); - end; - // RGBA formats - ifR3G3B2: - begin - GLFormat := GL_RGB; - GLType := GL_UNSIGNED_BYTE_3_3_2; - GLInternal := GL_R3_G3_B2; - end; - ifR5G6B5: - begin - GLFormat := GL_RGB; - GLType := GL_UNSIGNED_SHORT_5_6_5; - GLInternal := GL_RGB5; //GL_RGB565 ot working on Radeons - end; - ifA1R5G5B5, ifX1R5G5B5: - begin - GLFormat := GL_BGRA_EXT; - GLType := GL_UNSIGNED_SHORT_1_5_5_5_REV; - GLInternal := Iff(Format = ifA1R5G5B5, GL_RGB5_A1, GL_RGB5); - end; - ifA4R4G4B4, ifX4R4G4B4: - begin - GLFormat := GL_BGRA_EXT; - GLType := GL_UNSIGNED_SHORT_4_4_4_4_REV; - GLInternal := Iff(Format = ifA4R4G4B4, GL_RGBA4, GL_RGB4); - end; - ifR8G8B8: - begin - GLFormat := GL_BGR_EXT; - GLType := GL_UNSIGNED_BYTE; - GLInternal := GL_RGB8; - end; - ifA8R8G8B8, ifX8R8G8B8: - begin - GLFormat := GL_BGRA_EXT; - GLType := GL_UNSIGNED_BYTE; - GLInternal := Iff(Format = ifA8R8G8B8, GL_RGBA8, GL_RGB8); - end; - ifR16G16B16, ifB16G16R16: - begin - GLFormat := Iff(Format = ifR16G16B16, GL_BGR_EXT, GL_RGB); - GLType := GL_UNSIGNED_SHORT; - GLInternal := GL_RGB16; - end; - ifA16R16G16B16, ifA16B16G16R16: - begin - GLFormat := Iff(Format = ifA16R16G16B16, GL_BGRA_EXT, GL_RGBA); - GLType := GL_UNSIGNED_SHORT; - GLInternal := GL_RGBA16; - end; - // Floating-Point formats - ifR32F: - begin - GLFormat := GL_RED; - GLType := GL_FLOAT; - GLInternal := GL_LUMINANCE32F_ARB; - end; - ifA32R32G32B32F, ifA32B32G32R32F: - begin - GLFormat := Iff(Format = ifA32R32G32B32F, GL_BGRA_EXT, GL_RGBA); - GLType := GL_FLOAT; - GLInternal := GL_RGBA32F_ARB; - end; - ifR16F: - begin - GLFormat := GL_RED; - GLType := GL_HALF_FLOAT_ARB; - GLInternal := GL_LUMINANCE16F_ARB; - end; - ifA16R16G16B16F, ifA16B16G16R16F: - begin - GLFormat := Iff(Format = ifA16R16G16B16F, GL_BGRA_EXT, GL_RGBA); - GLType := GL_HALF_FLOAT_ARB; - GLInternal := GL_RGBA16F_ARB; - end; - // Special formats - ifDXT1: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; - ifDXT3: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - ifDXT5: GLInternal := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - ifATI1N: GLInternal := GL_COMPRESSED_LUMINANCE_LATC1_EXT; - ifATI2N: - begin - GLInternal := GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT; - if not Caps.LATCCompression and Caps.ATI3DcCompression then - GLInternal := GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI; - end; - end; - Result := GLInternal <> 0; -end; - -function LoadGLTextureFromFile(const FileName: string; CreatedWidth, CreatedHeight: PLongInt): GLuint; -var - Images: TDynImageDataArray; -begin - if LoadMultiImageFromFile(FileName, Images) and (Length(Images) > 0) then - begin - Result := CreateGLTextureFromMultiImage(Images, Images[0].Width, - Images[0].Height, True, 0, ifUnknown, CreatedWidth, CreatedHeight); - end - else - Result := 0; - FreeImagesInArray(Images); -end; - -function LoadGLTextureFromStream(Stream: TStream; CreatedWidth, CreatedHeight: PLongInt): GLuint; -var - Images: TDynImageDataArray; -begin - if LoadMultiImageFromStream(Stream, Images) and (Length(Images) > 0) then - begin - Result := CreateGLTextureFromMultiImage(Images, Images[0].Width, - Images[0].Height, True, 0, ifUnknown, CreatedWidth, CreatedHeight); - end - else - Result := 0; - FreeImagesInArray(Images); -end; - -function LoadGLTextureFromMemory(Data: Pointer; Size: LongInt; CreatedWidth, CreatedHeight: PLongInt): GLuint; -var - Images: TDynImageDataArray; -begin - if LoadMultiImageFromMemory(Data, Size, Images) and (Length(Images) > 0) then - begin - Result := CreateGLTextureFromMultiImage(Images, Images[0].Width, - Images[0].Height, True, 0, ifUnknown, CreatedWidth, CreatedHeight); - end - else - Result := 0; - FreeImagesInArray(Images); -end; - -function CreateGLTextureFromImage(const Image: TImageData; - Width, Height: LongInt; MipMaps: Boolean; OverrideFormat: TImageFormat; - CreatedWidth, CreatedHeight: PLongInt): GLuint; -var - Arr: TDynImageDataArray; -begin - // Just calls function operating on image arrays - SetLength(Arr, 1); - Arr[0] := Image; - Result := CreateGLTextureFromMultiImage(Arr, Width, Height, MipMaps, 0, - OverrideFormat, CreatedWidth, CreatedHeight); -end; - -function CreateGLTextureFromMultiImage(const Images: TDynImageDataArray; - Width, Height: LongInt; MipMaps: Boolean; MainLevelIndex: LongInt; OverrideFormat: TImageFormat; - CreatedWidth, CreatedHeight: PLongInt): GLuint; -const - BlockCompressedFormats: TImageFormats = [ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N]; -var - I, MipLevels, PossibleLevels, ExistingLevels, CurrentWidth, CurrentHeight: LongInt; - Caps: TGLTextureCaps; - GLFormat: GLenum; - GLType: GLenum; - GLInternal: GLint; - Desired, ConvTo: TImageFormat; - Info: TImageFormatInfo; - LevelsArray: TDynImageDataArray; - NeedsResize, NeedsConvert: Boolean; - UnpackAlignment, UnpackSkipRows, UnpackSkipPixels, UnpackRowLength: LongInt; - - procedure PasteImage(var Image: TImageData; Width, Height: LongInt); - var - Clone: TImageData; - begin - CloneImage(Image, Clone); - NewImage(Width, Height, Clone.Format, Image); - FillRect(Image, 0, 0, Width, Height, Clone.Bits); - CopyRect(Clone, 0, 0, Clone.Width, Clone.Height, Image, 0, 0); - FreeImage(Clone); - end; - -begin - Result := 0; - ExistingLevels := Length(Images); - - if GetGLTextureCaps(Caps) and (ExistingLevels > 0) then - try - // Check if requested main level is at valid index - if (MainLevelIndex < 0) or (MainLevelIndex > High(Images)) then - MainLevelIndex := 0; - - // First check desired size and modify it if necessary - if Width <= 0 then Width := Images[MainLevelIndex].Width; - if Height <= 0 then Height := Images[MainLevelIndex].Height; - if not Caps.NonPowerOfTwo and not DisableNPOTSupportCheck then - begin - // If device supports only power of 2 texture sizes - Width := NextPow2(Width); - Height := NextPow2(Height); - end; - Width := ClampInt(Width, 1, Caps.MaxTextureSize); - Height := ClampInt(Height, 1, Caps.MaxTextureSize); - - // Get various mipmap level counts and modify - // desired MipLevels if its value is invalid - PossibleLevels := GetNumMipMapLevels(Width, Height); - if MipMaps then - MipLevels := PossibleLevels - else - MipLevels := 1; - - // Prepare array for mipmap levels. Make it larger than necessary - that - // way we can use the same index for input images and levels in the large loop below - SetLength(LevelsArray, MipLevels + MainLevelIndex); - - // Now determine which image format will be used - if OverrideFormat = ifUnknown then - Desired := Images[MainLevelIndex].Format - else - Desired := OverrideFormat; - - // Check if the hardware supports floating point and compressed textures - GetImageFormatInfo(Desired, Info); - if Info.IsFloatingPoint and not Caps.FloatTextures then - Desired := ifA8R8G8B8; - if (Desired in [ifDXT1, ifDXT3, ifDXT5]) and not Caps.DXTCompression then - Desired := ifA8R8G8B8; - if (Desired = ifATI1N) and not Caps.LATCCompression then - Desired := ifGray8; - if (Desired = ifATI2N) and not (Caps.ATI3DcCompression or Caps.LATCCompression) then - Desired := ifA8Gray8; - - // Try to find GL format equivalent to image format and if it is not - // found use one of default formats - if not ImageFormatToGL(Desired, GLFormat, GLType, GLInternal, Caps) then - begin - GetImageFormatInfo(Desired, Info); - if Info.HasGrayChannel then - ConvTo := ifGray8 - else - ConvTo := ifA8R8G8B8; - if not ImageFormatToGL(ConvTo, GLFormat, GLType, GLInternal, Caps) then - Exit; - end - else - ConvTo := Desired; - - CurrentWidth := Width; - CurrentHeight := Height; - // If user is interested in width and height of created texture lets - // give him that - if CreatedWidth <> nil then CreatedWidth^ := CurrentWidth; - if CreatedHeight <> nil then CreatedHeight^ := CurrentHeight; - - // Store old pixel unpacking settings - glGetIntegerv(GL_UNPACK_ALIGNMENT, @UnpackAlignment); - glGetIntegerv(GL_UNPACK_SKIP_ROWS, @UnpackSkipRows); - glGetIntegerv(GL_UNPACK_SKIP_PIXELS, @UnpackSkipPixels); - glGetIntegerv(GL_UNPACK_ROW_LENGTH, @UnpackRowLength); - // Set new pixel unpacking settings - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - // Generate new texture, bind it and set - glGenTextures(1, @Result); - glBindTexture(GL_TEXTURE_2D, Result); - if Byte(glIsTexture(Result)) <> GL_TRUE then - Exit; - - for I := MainLevelIndex to MipLevels - 1 + MainLevelIndex do - begin - // Check if we can use input image array as a source for this mipmap level - if I < ExistingLevels then - begin - // Check if input image for this mipmap level has the right - // size and format - NeedsConvert := not (Images[I].Format = ConvTo); - if ConvTo in BlockCompressedFormats then - begin - // Input images in DXTC will have min dimensions of 4, but we need - // current Width and Height to be lesser (for glCompressedTexImage2D) - NeedsResize := not ((Images[I].Width = Max(4, CurrentWidth)) and - (Images[I].Height = Max(4, CurrentHeight))); - end - else - NeedsResize := not ((Images[I].Width = CurrentWidth) and (Images[I].Height = CurrentHeight)); - - if NeedsResize or NeedsConvert then - begin - // Input image must be resized or converted to different format - // to become valid mipmap level - CloneImage(Images[I], LevelsArray[I]); - if NeedsConvert then - ConvertImage(LevelsArray[I], ConvTo); - if NeedsResize then - begin - if (not PasteNonPow2ImagesIntoPow2) or (LevelsArray[I].Width > CurrentWidth) or - (LevelsArray[I].Height > CurrentHeight)then - begin - // If pasteNP2toP2 is disabled or if source is bigger than target - // we rescale image, otherwise we paste it with the same size - ResizeImage(LevelsArray[I], CurrentWidth, CurrentHeight, rfBilinear) - end - else - PasteImage(LevelsArray[I], CurrentWidth, CurrentHeight); - end; - end - else - // Input image can be used without any changes - LevelsArray[I] := Images[I]; - end - else - begin - // This mipmap level is not present in the input image array - // so we create a new level - FillMipMapLevel(LevelsArray[I - 1], CurrentWidth, CurrentHeight, LevelsArray[I]); - end; - - if ConvTo in BlockCompressedFormats then - begin - // Note: GL DXTC texture snaller than 4x4 must have width and height - // as expected for non-DXTC texture (like 1x1 - we cannot - // use LevelsArray[I].Width and LevelsArray[I].Height - they are - // at least 4 for DXTC images). But Bits and Size passed to - // glCompressedTexImage2D must contain regular 4x4 DXTC block. - glCompressedTexImage2D(GL_TEXTURE_2D, I - MainLevelIndex, GLInternal, CurrentWidth, - CurrentHeight, 0, LevelsArray[I].Size, LevelsArray[I].Bits) - end - else - begin - glTexImage2D(GL_TEXTURE_2D, I - MainLevelIndex, GLInternal, CurrentWidth, - CurrentHeight, 0, GLFormat, GLType, LevelsArray[I].Bits); - end; - - // Calculate width and height of the next mipmap level - CurrentWidth := ClampInt(CurrentWidth div 2, 1, CurrentWidth); - CurrentHeight := ClampInt(CurrentHeight div 2, 1, CurrentHeight); - end; - - // Restore old pixel unpacking settings - glPixelStorei(GL_UNPACK_ALIGNMENT, UnpackAlignment); - glPixelStorei(GL_UNPACK_SKIP_ROWS, UnpackSkipRows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, UnpackSkipPixels); - glPixelStorei(GL_UNPACK_ROW_LENGTH, UnpackRowLength); - finally - // Free local image copies - for I := 0 to Length(LevelsArray) - 1 do - begin - if ((I < ExistingLevels) and (LevelsArray[I].Bits <> Images[I].Bits)) or - (I >= ExistingLevels) then - FreeImage(LevelsArray[I]); - end; - end; -end; - -function SaveGLTextureToFile(const FileName: string; const Texture: GLuint): Boolean; -var - Arr: TDynImageDataArray; - Fmt: TImageFileFormat; - IsDDS: Boolean; -begin - Result := CreateMultiImageFromGLTexture(Texture, Arr); - if Result then - begin - Fmt := FindImageFileFormatByName(FileName); - if Fmt <> nil then - begin - IsDDS := SameText(Fmt.Extensions[0], 'dds'); - if IsDDS then - begin - PushOptions; - SetOption(ImagingDDSSaveMipMapCount, Length(Arr)); - end; - Result := SaveMultiImageToFile(FileName, Arr); - if IsDDS then - PopOptions; - end; - FreeImagesInArray(Arr); - end; -end; - -function SaveGLTextureToStream(const Ext: string; Stream: TStream; const Texture: GLuint): Boolean; -var - Arr: TDynImageDataArray; - Fmt: TImageFileFormat; - IsDDS: Boolean; -begin - Result := CreateMultiImageFromGLTexture(Texture, Arr); - if Result then - begin - Fmt := FindImageFileFormatByExt(Ext); - if Fmt <> nil then - begin - IsDDS := SameText(Fmt.Extensions[0], 'dds'); - if IsDDS then - begin - PushOptions; - SetOption(ImagingDDSSaveMipMapCount, Length(Arr)); - end; - Result := SaveMultiImageToStream(Ext, Stream, Arr); - if IsDDS then - PopOptions; - end; - FreeImagesInArray(Arr); - end; -end; - -function SaveGLTextureToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Texture: GLuint): Boolean; -var - Arr: TDynImageDataArray; - Fmt: TImageFileFormat; - IsDDS: Boolean; -begin - Result := CreateMultiImageFromGLTexture(Texture, Arr); - if Result then - begin - Fmt := FindImageFileFormatByExt(Ext); - if Fmt <> nil then - begin - IsDDS := SameText(Fmt.Extensions[0], 'dds'); - if IsDDS then - begin - PushOptions; - SetOption(ImagingDDSSaveMipMapCount, Length(Arr)); - end; - Result := SaveMultiImageToMemory(Ext, Data, Size, Arr); - if IsDDS then - PopOptions; - end; - FreeImagesInArray(Arr); - end; -end; - -function CreateImageFromGLTexture(const Texture: GLuint; - var Image: TImageData; OverrideFormat: TImageFormat): Boolean; -var - Arr: TDynImageDataArray; -begin - // Just calls function operating on image arrays - FreeImage(Image); - SetLength(Arr, 1); - Result := CreateMultiImageFromGLTexture(Texture, Arr, 1, OverrideFormat); - Image := Arr[0]; -end; - -function CreateMultiImageFromGLTexture(const Texture: GLuint; - var Images: TDynImageDataArray; MipLevels: LongInt; OverrideFormat: TImageFormat): Boolean; -var - I, Width, Height, ExistingLevels: LongInt; -begin - FreeImagesInArray(Images); - SetLength(Images, 0); - Result := False; - if Byte(glIsTexture(Texture)) = GL_TRUE then - begin - // Check if desired mipmap level count is valid - glBindTexture(GL_TEXTURE_2D, Texture); - if MipLevels <= 0 then - MipLevels := GetNumMipMapLevels(Width, Height); - SetLength(Images, MipLevels); - ExistingLevels := 0; - - for I := 0 to MipLevels - 1 do - begin - // Get the current level size - glGetTexLevelParameteriv(GL_TEXTURE_2D, I, GL_TEXTURE_WIDTH, @Width); - glGetTexLevelParameteriv(GL_TEXTURE_2D, I, GL_TEXTURE_HEIGHT, @Height); - // Break when the mipmap chain is broken - if (Width = 0) or (Height = 0) then - Break; - // Create new image and copy texture data - NewImage(Width, Height, ifA8R8G8B8, Images[I]); - glGetTexImage(GL_TEXTURE_2D, I, GL_BGRA_EXT, GL_UNSIGNED_BYTE, Images[I].Bits); - Inc(ExistingLevels); - end; - // Resize mipmap array if necessary - if MipLevels <> ExistingLevels then - SetLength(Images, ExistingLevels); - // Convert images to desired format if set - if OverrideFormat <> ifUnknown then - for I := 0 to Length(Images) - 1 do - ConvertImage(Images[I], OverrideFormat); - - Result := True; - end; -end; - -initialization - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - -- 0.77.1 --------------------------------------------------- - - Added some new compressed formats IDs - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Fixed GetGLProcAddress in Unicode Delphi. Compressed - textures didn't work because of this. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - Added support for GLScene's OpenGL header. - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - Added 3Dc compressed texture formats support. - - Added detection of 3Dc formats to texture caps. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - Added DisableNPOTSupportCheck option and related functionality. - - Added some new texture caps detection. - - -- 0.24.1 Changes/Bug Fixes --------------------------------- - - Added PasteNonPow2ImagesIntoPow2 option and related functionality. - - Better NeedsResize determination for small DXTC textures - - avoids needless resizing. - - Added MainLevelIndex to CreateMultiImageFromGLTexture. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Added CreatedWidth and CreatedHeight parameters to most - LoadGLTextureFromXXX/CreateGLTextureFromXXX functions. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - fixed bug in CreateGLTextureFromMultiImage which caused assert failure - when creating mipmaps (using FillMipMapLevel) for DXTC formats - - changed single channel floating point texture formats from - GL_INTENSITY..._ARB to GL_LUMINANCE..._ARB - - added support for half float texture formats (GL_RGBA16F_ARB etc.) - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - filtered mipmap creation - - more texture caps added - - fixed memory leaks in SaveGLTextureTo... functions - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - unit created and initial stuff added -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingPcx.pas b/3rd/Imaging/Extras/Extensions/ImagingPcx.pas deleted file mode 100644 index bcd858c0c..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingPcx.pas +++ /dev/null @@ -1,375 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader for ZSoft Paintbrush images known as PCX.} -unit ImagingPcx; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingFormats, ImagingUtility, ImagingIO; - -type - { Class for loading ZSoft Paintbrush images known as PCX. It is old - format which can store 1bit, 2bit, 4bit, 8bit, and 24bit (and 32bit but is - probably non-standard) images. Only loading is supported (you can still come - accross some PCX files) but saving is not (I don't wont this venerable format - to spread).} - TPCXFileFormat = class(TImageFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - end; - -implementation - -const - SPCXFormatName = 'ZSoft Paintbrush Image'; - SPCXMasks = '*.pcx'; - -type - TPCXHeader = packed record - Id: Byte; // Always $0A - Version: Byte; // 0, 2, 3, 4, 5 - Encoding: Byte; // 0, 1 - BitsPerPixel: Byte; // 1, 2, 4, 8 - X0, Y0: Word; // Image window top-left - X1, Y1: Word; // Image window bottom-right - DpiX: Word; - DpiY: Word; - Palette16: array [0..15] of TColor24Rec; - Reserved1: Byte; - Planes: Byte; // 1, 3, 4 - BytesPerLine: Word; - PaletteType: Word; // 1: color or s/w 2: grayscale - Reserved2: array [0..57] of Byte; - end; - -{ TPCXFileFormat } - -procedure TPCXFileFormat.Define; -begin - inherited; - FName := SPCXFormatName; - FFeatures := [ffLoad]; - - AddMasks(SPCXMasks); -end; - -function TPCXFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -const - ifMono: TImageFormat = TImageFormat(250); - ifIndex2: TImageFormat = TImageFormat(251); - ifIndex4: TImageFormat = TImageFormat(252); -var - Hdr: TPCXHeader; - PalID, B: Byte; - PalPCX: TPalette24Size256; - FileDataFormat: TImageFormat; - I, J, UncompSize, BytesPerLine, ByteNum, BitNum: LongInt; - UncompData, RowPointer, PixelIdx: PByte; - Pixel24: PColor24Rec; - Pixel32: PColor32Rec; - AlphaPlane, RedPlane, GreenPlane, BluePlane, - Plane1, Plane2, Plane3, Plane4: PByteArray; - - procedure RleDecode(Target: PByte; UnpackedSize: LongInt); - var - Count: LongInt; - Source: Byte; - begin - while UnpackedSize > 0 do - with GetIO do - begin - GetIO.Read(Handle, @Source, SizeOf(Source)); - if (Source and $C0) = $C0 then - begin - // RLE data - Count := Source and $3F; - if UnpackedSize < Count then - Count := UnpackedSize; - Read(Handle, @Source, SizeOf(Source)); - FillChar(Target^, Count, Source); - //Inc(Source); - Inc(Target, Count); - Dec(UnpackedSize, Count); - end - else - begin - // Uncompressed data - Target^ := Source; - Inc(Target); - Dec(UnpackedSize); - end; - end; - end; - -begin - Result := False; - SetLength(Images, 1); - with GetIO, Images[0] do - begin - // Read PCX header and store input position (start of image data) - Read(Handle, @Hdr, SizeOf(Hdr)); - FileDataFormat := ifUnknown; - - // Determine image's data format and find its Imaging equivalent - // (using some custom TImageFormat constants) - case Hdr.BitsPerPixel of - 1: - case Hdr.Planes of - 1: FileDataFormat := ifMono; - 4: FileDataFormat := ifIndex4; - end; - 2: FileDataFormat := ifIndex2; - 4: FileDataFormat := ifIndex4; - 8: - case Hdr.Planes of - 1: FileDataFormat := ifIndex8; - 3: FileDataFormat := ifR8G8B8; - 4: FileDataFormat := ifA8R8G8B8; - end; - end; - - // No compatible Imaging format found, exit - if FileDataFormat = ifUnknown then - Exit; - - // Get width, height, and output data format (unsupported formats - // like ifMono are converted later to ifIndex8) - Width := Hdr.X1 - Hdr.X0 + 1; - Height := Hdr.Y1 - Hdr.Y0 + 1; - if FileDataFormat in [ifIndex8, ifR8G8B8] then - Format := FileDataFormat - else - Format := ifIndex8; - - NewImage(Width, Height, Format, Images[0]); - - if not (FileDataFormat in [ifIndex8, ifR8G8B8]) then - begin - // other formats use palette embedded to file header - for I := Low(Hdr.Palette16) to High(Hdr.Palette16) do - begin - Palette[I].A := $FF; - Palette[I].R := Hdr.Palette16[I].B; - Palette[I].G := Hdr.Palette16[I].G; - Palette[I].B := Hdr.Palette16[I].R; - end; - end; - - // Now we determine various data sizes - BytesPerLine := Hdr.BytesPerLine * Hdr.Planes; - UncompSize := BytesPerLine * Height; - - GetMem(UncompData, UncompSize); - try - if Hdr.Encoding = 1 then - begin - // Image data is compressed -> read and decompress - RleDecode(UncompData, UncompSize); - end - else - begin - // Just read uncompressed data - Read(Handle, UncompData, UncompSize); - end; - - if FileDataFormat in [ifR8G8B8, ifA8R8G8B8] then - begin - // RGB and ARGB images are stored in layout different from - // Imaging's (and most other file formats'). First there is - // Width red values then there is Width green values and so on - RowPointer := UncompData; - - if FileDataFormat = ifA8R8G8B8 then - begin - Pixel32 := Bits; - for I := 0 to Height - 1 do - begin - AlphaPlane := PByteArray(RowPointer); - RedPlane := @AlphaPlane[Hdr.BytesPerLine]; - GreenPlane := @AlphaPlane[Hdr.BytesPerLine * 2]; - BluePlane := @AlphaPlane[Hdr.BytesPerLine * 3]; - for J := 0 to Width - 1 do - begin - Pixel32.A := AlphaPlane[J]; - Pixel32.R := RedPlane[J]; - Pixel32.G := GreenPlane[J]; - Pixel32.B := BluePlane[J]; - Inc(Pixel32); - end; - Inc(RowPointer, BytesPerLine); - end; - end - else - begin - Pixel24 := Bits; - for I := 0 to Height - 1 do - begin - RedPlane := PByteArray(RowPointer); - GreenPlane := @RedPlane[Hdr.BytesPerLine]; - BluePlane := @RedPlane[Hdr.BytesPerLine * 2]; - for J := 0 to Width - 1 do - begin - Pixel24.R := RedPlane[J]; - Pixel24.G := GreenPlane[J]; - Pixel24.B := BluePlane[J]; - Inc(Pixel24); - end; - Inc(RowPointer, BytesPerLine); - end; - end; - end - else if FileDataFormat = ifIndex8 then - begin - // Just copy 8bit lines - for I := 0 to Height - 1 do - Move(PByteArray(UncompData)[I * Hdr.BytesPerLine], PByteArray(Bits)[I * Width], Width); - end - else if FileDataFormat = ifMono then - begin - // Convert 1bit images to ifIndex8 - Convert1To8(UncompData, Bits, Width, Height, Hdr.BytesPerLine, False); - end - else if FileDataFormat = ifIndex2 then - begin - // Convert 2bit images to ifIndex8. Note that 2bit PCX images - // usually use (from specs, I've never seen one myself) CGA palette - // which is not array of RGB tripplets. So 2bit PCXs are loaded but - // their colors would be wrong - Convert2To8(UncompData, Bits, Width, Height, Hdr.BytesPerLine, False); - end - else if FileDataFormat = ifIndex4 then - begin - // 4bit images can be stored similar to RGB images (in four one bit planes) - // or like array of nibbles (which is more common) - if (Hdr.BitsPerPixel = 1) and (Hdr.Planes = 4) then - begin - RowPointer := UncompData; - PixelIdx := Bits; - for I := 0 to Height - 1 do - begin - Plane1 := PByteArray(RowPointer); - Plane2 := @Plane1[Hdr.BytesPerLine]; - Plane3 := @Plane1[Hdr.BytesPerLine * 2]; - Plane4 := @Plane1[Hdr.BytesPerLine * 3]; - - for J := 0 to Width - 1 do - begin - B := 0; - ByteNum := J div 8; - BitNum := 7 - (J mod 8); - if (Plane1[ByteNum] shr BitNum) and $1 <> 0 then B := B or $01; - if (Plane2[ByteNum] shr BitNum) and $1 <> 0 then B := B or $02; - if (Plane3[ByteNum] shr BitNum) and $1 <> 0 then B := B or $04; - if (Plane4[ByteNum] shr BitNum) and $1 <> 0 then B := B or $08; - PixelIdx^ := B; - Inc(PixelIdx); - end; - Inc(RowPointer, BytesPerLine); - end; - end - else if (Hdr.BitsPerPixel = 4) and (Hdr.Planes = 1) then - begin - // Convert 4bit images to ifIndex8 - Convert4To8(UncompData, Bits, Width, Height, Hdr.BytesPerLine, False); - end - end; - - if FileDataFormat = ifIndex8 then - begin - // 8bit palette is appended at the end of the file - // with $0C identifier - //Seek(Handle, -769, smFromEnd); - Read(Handle, @PalID, SizeOf(PalID)); - if PalID = $0C then - begin - Read(Handle, @PalPCX, SizeOf(PalPCX)); - for I := Low(PalPCX) to High(PalPCX) do - begin - Palette[I].A := $FF; - Palette[I].R := PalPCX[I].B; - Palette[I].G := PalPCX[I].G; - Palette[I].B := PalPCX[I].R; - end; - end - else - Seek(Handle, -SizeOf(PalID), smFromCurrent); - end; - - finally - FreeMem(UncompData); - end; - Result := True; - end; -end; - -function TPCXFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Hdr: TPCXHeader; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount >= SizeOf(Hdr)) and - (Hdr.Id = $0A) and - (Hdr.Version in [0, 2, 3, 4, 5]) and - (Hdr.Encoding in [0..1]) and - (Hdr.BitsPerPixel in [1, 2, 4, 8]) and - (Hdr.Planes in [1, 3, 4]) and - (Hdr.PaletteType in [1..2]); - end; - -end; - -initialization - RegisterImageFileFormat(TPCXFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Made loader stream-safe - stream position is exactly at the end of the - image after loading and file size doesn't need to be know during the process. - - Initial TPCXFileFormat class implemented. - -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingPsd.pas b/3rd/Imaging/Extras/Extensions/ImagingPsd.pas deleted file mode 100644 index 96ce9c919..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingPsd.pas +++ /dev/null @@ -1,801 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for Photoshop PSD image format.} -unit ImagingPsd; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, ImagingTypes, Imaging, ImagingColors, ImagingUtility; - -type - { Class for loading and saving Adobe Photoshop PSD images. - Loading and saving of indexed, grayscale, RGB(A), HDR (FP32), and CMYK - (auto converted to RGB) images is supported. Non-HDR gray, RGB, - and CMYK images can have 8bit or 16bit color channels. - There is no support for loading mono images, duotone images are treated - like grayscale images, and multichannel and CIE Lab images are loaded as - RGB images but without actual conversion to RGB color space. - Also no layer information is loaded.} - TPSDFileFormat = class(TImageFileFormat) - private - FSaveAsLayer: LongBool; - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - published - property SaveAsLayer: LongBool read FSaveAsLayer write FSaveAsLayer; - end; - -implementation - -uses - ImagingExtras; - -const - SPSDFormatName = 'Photoshop Image'; - SPSDMasks = '*.psd,*.pdd'; - PSDSupportedFormats: TImageFormats = [ifIndex8, ifGray8, ifA8Gray8, - ifR8G8B8, ifA8R8G8B8, ifGray16, ifA16Gray16, ifR16G16B16, ifA16R16G16B16, - ifR32F, ifR32G32B32F, ifA32R32G32B32F]; - PSDDefaultSaveAsLayer = True; - -const - SPSDMagic = '8BPS'; - CompressionNone: Word = 0; - CompressionRLE: Word = 1; - -type - {$MINENUMSIZE 2} - { PSD Image color mode.} - TPSDColorMode = ( - cmMono = 0, - cmGrayscale = 1, - cmIndexed = 2, - cmRGB = 3, - cmCMYK = 4, - cmMultiChannel = 7, - cmDuoTone = 8, - cmLab = 9 - ); - - { PSD image main header.} - TPSDHeader = packed record - Signature: TChar4; // Format ID '8BPS' - Version: Word; // Always 1 - Reserved: array[0..5] of Byte; // Reserved, all zero - Channels: Word; // Number of color channels (1-24) including alpha channels - Rows : LongWord; // Height of image in pixels (1-30000) - Columns: LongWord; // Width of image in pixels (1-30000) - Depth: Word; // Number of bits per channel (1, 8, and 16) - Mode: TPSDColorMode; // Color mode - end; - - TPSDChannelInfo = packed record - ChannelID: Word; // 0 = Red, 1 = Green, 2 = Blue etc., -1 = Transparency mask, -2 = User mask - Size: LongWord; // Size of channel data. - end; - -procedure SwapHeader(var Header: TPSDHeader); -begin - Header.Version := SwapEndianWord(Header.Version); - Header.Channels := SwapEndianWord(Header.Channels); - Header.Depth := SwapEndianWord(Header.Depth); - Header.Rows := SwapEndianLongWord(Header.Rows); - Header.Columns := SwapEndianLongWord(Header.Columns); - Header.Mode := TPSDColorMode(SwapEndianWord(Word(Header.Mode))); -end; - -{ - TPSDFileFormat class implementation -} - -procedure TPSDFileFormat.Define; -begin - inherited; - FName := SPSDFormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := PSDSupportedFormats; - AddMasks(SPSDMasks); - - FSaveAsLayer := PSDDefaultSaveAsLayer; - RegisterOption(ImagingPSDSaveAsLayer, @FSaveAsLayer); -end; - -function TPSDFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Header: TPSDHeader; - ByteCount: LongWord; - RawPal: array[0..767] of Byte; - Compression, PackedSize: Word; - LineSize, ChannelPixelSize, WidthBytes, - CurrChannel, MaxRLESize, I, Y, X: LongInt; - Info: TImageFormatInfo; - PackedLine, LineBuffer: PByte; - RLELineSizes: array of Word; - Col32: TColor32Rec; - Col64: TColor64Rec; - PCol32: PColor32Rec; - PCol64: PColor64Rec; - - { PackBits RLE decode code from Mike Lischke's GraphicEx library.} - procedure DecodeRLE(Source, Dest: PByte; PackedSize, UnpackedSize: LongInt); - var - Count: LongInt; - begin - while (UnpackedSize > 0) and (PackedSize > 0) do - begin - Count := ShortInt(Source^); - Inc(Source); - Dec(PackedSize); - if Count < 0 then - begin - // Replicate next byte -Count + 1 times - if Count = -128 then - Continue; - Count := -Count + 1; - if Count > UnpackedSize then - Count := UnpackedSize; - FillChar(Dest^, Count, Source^); - Inc(Source); - Dec(PackedSize); - Inc(Dest, Count); - Dec(UnpackedSize, Count); - end - else - begin - // Copy next Count + 1 bytes from input - Inc(Count); - if Count > UnpackedSize then - Count := UnpackedSize; - if Count > PackedSize then - Count := PackedSize; - Move(Source^, Dest^, Count); - Inc(Dest, Count); - Inc(Source, Count); - Dec(PackedSize, Count); - Dec(UnpackedSize, Count); - end; - end; - end; - -begin - Result := False; - SetLength(Images, 1); - with GetIO, Images[0] do - begin - // Read PSD header - Read(Handle, @Header, SizeOf(Header)); - SwapHeader(Header); - - // Determine image data format - Format := ifUnknown; - case Header.Mode of - cmGrayscale, cmDuoTone: - begin - if Header.Depth in [8, 16] then - begin - if Header.Channels = 1 then - Format := IffFormat(Header.Depth = 8, ifGray8, ifGray16) - else if Header.Channels >= 2 then - Format := IffFormat(Header.Depth = 8, ifA8Gray8, ifA16Gray16); - end - else if (Header.Depth = 32) and (Header.Channels = 1) then - Format := ifR32F; - end; - cmIndexed: - begin - if Header.Depth = 8 then - Format := ifIndex8; - end; - cmRGB, cmMultiChannel, cmCMYK, cmLab: - begin - if Header.Depth in [8, 16] then - begin - if Header.Channels = 3 then - Format := IffFormat(Header.Depth = 8, ifR8G8B8, ifR16G16B16) - else if Header.Channels >= 4 then - Format := IffFormat(Header.Depth = 8, ifA8R8G8B8, ifA16R16G16B16); - end - else if Header.Depth = 32 then - begin - if Header.Channels = 3 then - Format := ifR32G32B32F - else if Header.Channels >= 4 then - Format := ifA32R32G32B32F; - end; - end; - cmMono:; // Not supported - end; - - // Exit if no compatible format was found - if Format = ifUnknown then - Exit; - - NewImage(Header.Columns, Header.Rows, Format, Images[0]); - Info := GetFormatInfo(Format); - - // Read or skip Color Mode Data Block (palette) - Read(Handle, @ByteCount, SizeOf(ByteCount)); - ByteCount := SwapEndianLongWord(ByteCount); - if Format = ifIndex8 then - begin - // Read palette only for indexed images - Read(Handle, @RawPal, SizeOf(RawPal)); - for I := 0 to 255 do - begin - Palette[I].A := $FF; - Palette[I].R := RawPal[I + 0]; - Palette[I].G := RawPal[I + 256]; - Palette[I].B := RawPal[I + 512]; - end; - end - else - Seek(Handle, ByteCount, smFromCurrent); - - // Skip Image Resources Block - Read(Handle, @ByteCount, SizeOf(ByteCount)); - ByteCount := SwapEndianLongWord(ByteCount); - Seek(Handle, ByteCount, smFromCurrent); - // Now there is Layer and Mask Information Block - Read(Handle, @ByteCount, SizeOf(ByteCount)); - ByteCount := SwapEndianLongWord(ByteCount); - // Skip Layer and Mask Information Block - Seek(Handle, ByteCount, smFromCurrent); - - // Read compression flag - Read(Handle, @Compression, SizeOf(Compression)); - Compression := SwapEndianWord(Compression); - - if Compression = CompressionRLE then - begin - // RLE compressed PSDs (most) have first lengths of compressed scanlines - // for each channel stored - SetLength(RLELineSizes, Height * Header.Channels); - Read(Handle, @RLELineSizes[0], Length(RLELineSizes) * SizeOf(Word)); - SwapEndianWord(@RLELineSizes[0], Height * Header.Channels); - MaxRLESize := RLELineSizes[0]; - for I := 1 to High(RLELineSizes) do - begin - if MaxRLESize < RLELineSizes[I] then - MaxRLESize := RLELineSizes[I]; - end; - end - else - MaxRLESize := 0; - - ChannelPixelSize := Info.BytesPerPixel div Info.ChannelCount; - LineSize := Width * ChannelPixelSize; - WidthBytes := Width * Info.BytesPerPixel; - GetMem(LineBuffer, LineSize); - GetMem(PackedLine, MaxRLESize); - - try - // Image color chanels are stored separately in PSDs so we will load - // one by one and copy their data to appropriate addresses of dest image. - for I := 0 to Header.Channels - 1 do - begin - // Now determine to which color channel of destination image we are going - // to write pixels. - if I <= 4 then - begin - // If PSD has alpha channel we need to switch current channel order - - // PSDs have alpha stored after blue channel but Imaging has alpha - // before red. - if Info.HasAlphaChannel and (Header.Mode <> cmCMYK) then - begin - if I = Info.ChannelCount - 1 then - CurrChannel := I - else - CurrChannel := Info.ChannelCount - 2 - I; - end - else - CurrChannel := Info.ChannelCount - 1 - I; - end - else - begin - // No valid channel remains - CurrChannel := -1; - end; - - if CurrChannel >= 0 then - begin - for Y := 0 to Height - 1 do - begin - if Compression = CompressionRLE then - begin - // Read RLE line and decompress it - PackedSize := RLELineSizes[I * Height + Y]; - Read(Handle, PackedLine, PackedSize); - DecodeRLE(PackedLine, LineBuffer, PackedSize, LineSize); - end - else - begin - // Just read uncompressed line - Read(Handle, LineBuffer, LineSize); - end; - - // Swap endian if needed - if ChannelPixelSize = 4 then - SwapEndianLongWord(PLongWord(LineBuffer), Width) - else if ChannelPixelSize = 2 then - SwapEndianWord(PWordArray(LineBuffer), Width); - - if Info.ChannelCount > 1 then - begin - // Copy each pixel fragment to its right place in destination image - for X := 0 to Width - 1 do - begin - Move(PByteArray(LineBuffer)[X * ChannelPixelSize], - PByteArray(Bits)[Y * WidthBytes + X * Info.BytesPerPixel + CurrChannel * ChannelPixelSize], - ChannelPixelSize); - end; - end - else - begin - // Just copy the line - Move(LineBuffer^, PByteArray(Bits)[Y * LineSize], LineSize); - end; - end; - end - else - begin - // Skip current color channel, not needed for image loading - just to - // get stream's position to the end of PSD - if Compression = CompressionRLE then - begin - for Y := 0 to Height - 1 do - Seek(Handle, RLELineSizes[I * Height + Y], smFromCurrent); - end - else - Seek(Handle, LineSize * Height, smFromCurrent); - end; - end; - - if Header.Mode = cmCMYK then - begin - // Convert CMYK images to RGB (alpha is ignored here). PSD stores CMYK - // channels in the way that first requires substraction from max channel value - if ChannelPixelSize = 1 then - begin - PCol32 := Bits; - for X := 0 to Width * Height - 1 do - begin - Col32.A := 255 - PCol32.A; - Col32.R := 255 - PCol32.R; - Col32.G := 255 - PCol32.G; - Col32.B := 255 - PCol32.B; - CMYKToRGB(Col32.A, Col32.R, Col32.G, Col32.B, PCol32.R, PCol32.G, PCol32.B); - PCol32.A := 255; - Inc(PCol32); - end; - end - else - begin - PCol64 := Bits; - for X := 0 to Width * Height - 1 do - begin - Col64.A := 65535 - PCol64.A; - Col64.R := 65535 - PCol64.R; - Col64.G := 65535 - PCol64.G; - Col64.B := 65535 - PCol64.B; - CMYKToRGB16(Col64.A, Col64.R, Col64.G, Col64.B, PCol64.R, PCol64.G, PCol64.B); - PCol64.A := 65535; - Inc(PCol64); - end; - end; - end; - - Result := True; - finally - FreeMem(LineBuffer); - FreeMem(PackedLine); - end; - end; -end; - -function TPSDFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -type - TURect = packed record - Top, Left, Bottom, Right: LongWord; - end; -const - BlendMode: TChar8 = '8BIMnorm'; - LayerOptions: array[0..3] of Byte = (255, 0, 0, 0); - LayerName: array[0..7] of AnsiChar = #7'Layer 0'; -var - MustBeFreed: Boolean; - ImageToSave: TImageData; - Info: TImageFormatInfo; - Header: TPSDHeader; - I, CurrChannel, ChannelPixelSize: LongInt; - LayerBlockOffset, SaveOffset, ChannelInfoOffset: Integer; - ChannelInfo: TPSDChannelInfo; - R: TURect; - LongVal: LongWord; - WordVal, LayerCount: Word; - RawPal: array[0..767] of Byte; - ChannelDataSizes: array of Integer; - - function PackLine(Src, Dest: PByteArray; Length: Integer): Integer; - var - I, Remaining: Integer; - begin - Remaining := Length; - Result := 0; - while Remaining > 0 do - begin - I := 0; - // Look for characters same as the first - while (I < 128) and (Remaining - I > 0) and (Src[0] = Src[I]) do - Inc(I); - - if I > 2 then - begin - Dest[0] := Byte(-(I - 1)); - Dest[1] := Src[0]; - Dest := PByteArray(@Dest[2]); - - Src := PByteArray(@Src[I]); - Dec(Remaining, I); - Inc(Result, 2); - end - else - begin - // Look for different characters - I := 0; - while (I < 128) and (Remaining - (I + 1) > 0) and - ((Src[I] <> Src[I + 1]) or (Remaining - (I + 2) <= 0) or - (Src[I] <> Src[I + 2])) do - begin - Inc(I); - end; - // If there's only 1 remaining, the previous WHILE doesn't catch it - if Remaining = 1 then - I := 1; - - if I > 0 then - begin - // Some distinct ones found - Dest[0] := I - 1; - Move(Src[0], Dest[1], I); - Dest := PByteArray(@Dest[1 + I]); - Src := PByteArray(@Src[I]); - Dec(Remaining, I); - Inc(Result, I + 1); - end; - end; - end; - end; - - procedure WriteChannelData(SeparateChannelStorage: Boolean); - var - I, X, Y, LineSize, WidthBytes, RLETableOffset, CurrentOffset, WrittenLineSize: Integer; - LineBuffer, RLEBuffer: PByteArray; - RLELengths: array of Word; - Compression: Word; - begin - LineSize := ImageToSave.Width * ChannelPixelSize; - WidthBytes := ImageToSave.Width * Info.BytesPerPixel; - GetMem(LineBuffer, LineSize); - GetMem(RLEBuffer, LineSize * 3); - SetLength(RLELengths, ImageToSave.Height * Info.ChannelCount); - RLETableOffset := 0; - // No compression for FP32, Photoshop won't open them - Compression := Iff(Info.IsFloatingPoint, CompressionNone, CompressionRLE); - - if not SeparateChannelStorage then - begin - // This is for storing background merged image. There's only one - // compression flag and one RLE lenghts table for all channels - WordVal := Swap(Compression); - GetIO.Write(Handle, @WordVal, SizeOf(WordVal)); - if Compression = CompressionRLE then - begin - RLETableOffset := GetIO.Tell(Handle); - GetIO.Write(Handle, @RLELengths[0], SizeOf(Word) * ImageToSave.Height * Info.ChannelCount); - end; - end; - - for I := 0 to Info.ChannelCount - 1 do - begin - if SeparateChannelStorage then - begin - // Layer image data has compression flag and RLE lenghts table - // independent for each channel - WordVal := Swap(CompressionRLE); - GetIO.Write(Handle, @WordVal, SizeOf(WordVal)); - if Compression = CompressionRLE then - begin - RLETableOffset := GetIO.Tell(Handle); - GetIO.Write(Handle, @RLELengths[0], SizeOf(Word) * ImageToSave.Height); - ChannelDataSizes[I] := 0; - end; - end; - - // Now determine which color channel we are going to write to file. - if Info.HasAlphaChannel then - begin - if I = Info.ChannelCount - 1 then - CurrChannel := I - else - CurrChannel := Info.ChannelCount - 2 - I; - end - else - CurrChannel := Info.ChannelCount - 1 - I; - - for Y := 0 to ImageToSave.Height - 1 do - begin - if Info.ChannelCount > 1 then - begin - // Copy each pixel fragment to its right place in destination image - for X := 0 to ImageToSave.Width - 1 do - begin - Move(PByteArray(ImageToSave.Bits)[Y * WidthBytes + X * Info.BytesPerPixel + CurrChannel * ChannelPixelSize], - PByteArray(LineBuffer)[X * ChannelPixelSize], ChannelPixelSize); - end; - end - else - Move(PByteArray(ImageToSave.Bits)[Y * LineSize], LineBuffer^, LineSize); - - // Write current channel line to file (swap endian if needed first) - if ChannelPixelSize = 4 then - SwapEndianLongWord(PLongWord(LineBuffer), ImageToSave.Width) - else if ChannelPixelSize = 2 then - SwapEndianWord(PWordArray(LineBuffer), ImageToSave.Width); - - if Compression = CompressionRLE then - begin - // Compress and write line - WrittenLineSize := PackLine(LineBuffer, RLEBuffer, LineSize); - RLELengths[ImageToSave.Height * I + Y] := SwapEndianWord(WrittenLineSize); - GetIO.Write(Handle, RLEBuffer, WrittenLineSize); - end - else - begin - WrittenLineSize := LineSize; - GetIO.Write(Handle, LineBuffer, WrittenLineSize); - end; - - if SeparateChannelStorage then - Inc(ChannelDataSizes[I], WrittenLineSize); - end; - - if SeparateChannelStorage and (Compression = CompressionRLE) then - begin - // Update channel RLE lengths - CurrentOffset := GetIO.Tell(Handle); - GetIO.Seek(Handle, RLETableOffset, smFromBeginning); - GetIO.Write(Handle, @RLELengths[ImageToSave.Height * I], SizeOf(Word) * ImageToSave.Height); - GetIO.Seek(Handle, CurrentOffset, smFromBeginning); - Inc(ChannelDataSizes[I], SizeOf(Word) * ImageToSave.Height); - end; - end; - - if not SeparateChannelStorage and (Compression = CompressionRLE) then - begin - // Update channel RLE lengths - CurrentOffset := GetIO.Tell(Handle); - GetIO.Seek(Handle, RLETableOffset, smFromBeginning); - GetIO.Write(Handle, @RLELengths[0], SizeOf(Word) * ImageToSave.Height * Info.ChannelCount); - GetIO.Seek(Handle, CurrentOffset, smFromBeginning); - end; - - FreeMem(LineBuffer); - FreeMem(RLEBuffer); - end; - -begin - Result := False; - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - Info := GetFormatInfo(Format); - ChannelPixelSize := Info.BytesPerPixel div Info.ChannelCount; - - // Fill header with proper info and save it - FillChar(Header, SizeOf(Header), 0); - Header.Signature := SPSDMagic; - Header.Version := 1; - Header.Channels := Info.ChannelCount; - Header.Rows := Height; - Header.Columns := Width; - Header.Depth := Info.BytesPerPixel div Info.ChannelCount * 8; - if Info.IsIndexed then - Header.Mode := cmIndexed - else if Info.HasGrayChannel or (Info.ChannelCount = 1) then - Header.Mode := cmGrayscale - else - Header.Mode := cmRGB; - - SwapHeader(Header); - Write(Handle, @Header, SizeOf(Header)); - - // Write palette size and data - LongVal := SwapEndianLongWord(IffUnsigned(Info.IsIndexed, SizeOf(RawPal), 0)); - Write(Handle, @LongVal, SizeOf(LongVal)); - if Info.IsIndexed then - begin - for I := 0 to Info.PaletteEntries - 1 do - begin - RawPal[I] := Palette[I].R; - RawPal[I + 256] := Palette[I].G; - RawPal[I + 512] := Palette[I].B; - end; - Write(Handle, @RawPal, SizeOf(RawPal)); - end; - - // Write empty resource and layer block sizes - LongVal := 0; - Write(Handle, @LongVal, SizeOf(LongVal)); - LayerBlockOffset := Tell(Handle); - Write(Handle, @LongVal, SizeOf(LongVal)); - - if FSaveAsLayer and (ChannelPixelSize < 4) then // No Layers for FP32 images - begin - LayerCount := SwapEndianWord(Iff(Info.HasAlphaChannel, Word(-1), 1)); // Must be -1 to get transparency in Photoshop - R.Top := 0; - R.Left := 0; - R.Bottom := SwapEndianLongWord(Height); - R.Right := SwapEndianLongWord(Width); - WordVal := SwapEndianWord(Info.ChannelCount); - Write(Handle, @LongVal, SizeOf(LongVal)); // Layer section size, empty now - Write(Handle, @LayerCount, SizeOf(LayerCount)); // Layer count - Write(Handle, @R, SizeOf(R)); // Bounds rect - Write(Handle, @WordVal, SizeOf(WordVal)); // Channel count - - ChannelInfoOffset := Tell(Handle); - SetLength(ChannelDataSizes, Info.ChannelCount); // Empty channel infos - FillChar(ChannelInfo, SizeOf(ChannelInfo), 0); - for I := 0 to Info.ChannelCount - 1 do - Write(Handle, @ChannelInfo, SizeOf(ChannelInfo)); - - Write(Handle, @BlendMode, SizeOf(BlendMode)); // Blend mode = normal - Write(Handle, @LayerOptions, SizeOf(LayerOptions)); // Predefined options - LongVal := SwapEndianLongWord(16); // Extra data size (4 (mask size) + 4 (ranges size) + 8 (name)) - Write(Handle, @LongVal, SizeOf(LongVal)); - LongVal := 0; - Write(Handle, @LongVal, SizeOf(LongVal)); // Mask size = 0 - LongVal := 0; - Write(Handle, @LongVal, SizeOf(LongVal)); // Blend ranges size - Write(Handle, @LayerName, SizeOf(LayerName)); // Layer name - - WriteChannelData(True); // Write Layer image data - - Write(Handle, @LongVal, SizeOf(LongVal)); // Global mask info size = 0 - - SaveOffset := Tell(Handle); - Seek(Handle, LayerBlockOffset, smFromBeginning); - - // Update layer and mask section sizes - LongVal := SwapEndianLongWord(SaveOffset - LayerBlockOffset - 4); - Write(Handle, @LongVal, SizeOf(LongVal)); - LongVal := SwapEndianLongWord(SaveOffset - LayerBlockOffset - 8); - Write(Handle, @LongVal, SizeOf(LongVal)); - - // Update layer channel info - Seek(Handle, ChannelInfoOffset, smFromBeginning); - for I := 0 to Info.ChannelCount - 1 do - begin - ChannelInfo.ChannelID := SwapEndianWord(I); - if (I = Info.ChannelCount - 1) and Info.HasAlphaChannel then - ChannelInfo.ChannelID := Swap(Word(-1)); - ChannelInfo.Size := SwapEndianLongWord(ChannelDataSizes[I] + 2); // datasize (incl RLE table) + comp. flag - Write(Handle, @ChannelInfo, SizeOf(ChannelInfo)); - end; - - Seek(Handle, SaveOffset, smFromBeginning); - end; - - // Write background merged image - WriteChannelData(False); - - Result := True; - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -procedure TPSDFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsFloatingPoint then - begin - if Info.ChannelCount = 1 then - ConvFormat := ifR32F - else if Info.HasAlphaChannel then - ConvFormat := ifA32R32G32B32F - else - ConvFormat := ifR32G32B32F; - end - else if Info.HasGrayChannel then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16) - else if Info.RBSwapFormat in GetSupportedFormats then - ConvFormat := Info.RBSwapFormat - else - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8); - - ConvertImage(Image, ConvFormat); -end; - -function TPSDFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Header: TPSDHeader; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Header, SizeOf(Header)); - SwapHeader(Header); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount >= SizeOf(Header)) and - (Header.Signature = SPSDMagic) and - (Header.Version = 1); - end; -end; - -initialization - RegisterImageFileFormat(TPSDFileFormat); - -{ - File Notes: - - -- 0.77.1 --------------------------------------------------- - - 3 channel RGB float images are loaded and saved directly - as ifR32G32B32F. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - PSDs are now saved with RLE compression. - - Mask layer saving added to SaveData for images with alpha - (shows proper transparency when opened in Photoshop). Can be - enabled/disabled using option - - Fixed memory leak in SaveData. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Saving implemented. - - Loading implemented. - - Unit created with initial stuff! -} - -end. - diff --git a/3rd/Imaging/Extras/Extensions/ImagingSDL.pas b/3rd/Imaging/Extras/Extensions/ImagingSDL.pas deleted file mode 100644 index eddf203e9..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingSDL.pas +++ /dev/null @@ -1,393 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains functions for loading/saving SDL surfaces using Imaging - and for converting images to surfaces and vice versa.} -unit ImagingSDL; - -{$I ImagingOptions.inc} - -interface - -uses - Classes, sdl, ImagingTypes, Imaging, ImagingUtility; - -type - { This SDL type is redefined here so ImagingExport unit does not - need sdl unit in the uses list.} - PSDL_Surface = sdl.PSDL_Surface; - -{ LoadSDLSurfaceFromFile and similar functions use SDL_SWSURFACE as Flags when creating - SDL surface. If you want other Flags to be used load image by standard - LoadImageFromFile and similar functions and then call CreateSDLSurfaceFromImage - which has more options.} - -{ Creates SDL surface from image in file in format supported by Imaging.} -function LoadSDLSurfaceFromFile(const FileName: string): PSDL_Surface; -{ Creates SDL surface from image in stream in format supported by Imaging.} -function LoadSDLSurfaceFromStream(Stream: TStream): PSDL_Surface; -{ Creates SDL surface from image in memory in format supported by Imaging.} -function LoadSDLSurfaceFromMemory(Data: Pointer; Size: LongInt): PSDL_Surface; - -{ Converts image to SDL surface. Flags is used when creating SDL surface - using SDL_CreateRGBSurface and is passed to it. OverrideFormat can be - used to convert image to specified format before SDL surface is created, - ifUnknown means no conversion.} -function CreateSDLSurfaceFromImage(const ImageData: TImageData; - Flags: LongWord; OverrideFormat: TImageFormat = ifUnknown): PSDL_Surface; - -{ Saves SDL surface to file in one of the formats supported by Imaging.} -function SaveSDLSurfaceToFile(const FileName: string; Surface: PSDL_Surface): Boolean; -{ Saves SDL surface to stream in one of the formats supported by Imaging defined by Ext.} -function SaveSDLSurfaceToStream(const Ext: string; Stream: TStream; Surface: PSDL_Surface): Boolean; -{ Saves SDL surface to memory in one of the formats supported by Imaging defined - by Ext. Size must contain size of available memory before the function - is called and memory size taken up by the image is returned in this parameter.} -function SaveSDLSurfaceToMemory(const Ext: string; Data: Pointer; var Size: LongInt; Surface: PSDL_Surface): Boolean; - -{ Converts SDL surface to TImageData structure. OverrideFormat can be - used to convert output image to the specified format rather than - use the format taken from SDL surface, ifUnknown means no conversion.} -function CreateImageFromSDLSurface(Surface: PSDL_Surface; var ImageData: TImageData; - OverrideFormat: TImageFormat = ifUnknown): Boolean; - -implementation - -const - DefaultFlags = SDL_SWSURFACE; - -function Iff(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; overload; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function LoadSDLSurfaceFromFile(const FileName: string): PSDL_Surface; -var - ImageData: TImageData; -begin - InitImage(ImageData); - if LoadImageFromFile(FileName, ImageData) then - Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags) - else - Result := nil; - FreeImage(ImageData); -end; - -function LoadSDLSurfaceFromStream(Stream: TStream): PSDL_Surface; -var - ImageData: TImageData; -begin - InitImage(ImageData); - if LoadImageFromStream(Stream, ImageData) then - Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags) - else - Result := nil; - FreeImage(ImageData); -end; - -function LoadSDLSurfaceFromMemory(Data: Pointer; Size: LongInt): PSDL_Surface; -var - ImageData: TImageData; -begin - InitImage(ImageData); - if LoadImageFromMemory(Data, Size, ImageData) then - Result := CreateSDLSurfaceFromImage(ImageData, DefaultFlags) - else - Result := nil; - FreeImage(ImageData); -end; - -function CreateSDLSurfaceFromImage(const ImageData: TImageData; - Flags: LongWord; OverrideFormat: TImageFormat): PSDL_Surface; -var - WorkData: TImageData; - Info: TImageFormatInfo; - ConvFormat: TImageFormat; - AMask, RMask, GMask, BMask: LongWord; - I, LineBytes: LongInt; - - procedure DetermineSDLMasks(var AMask, RMask, GMask, BMask: LongWord); - begin - if Info.UsePixelFormat then - begin - AMask := Info.PixelFormat.ABitMask; - RMask := Info.PixelFormat.RBitMask; - GMask := Info.PixelFormat.GBitMask; - BMask := Info.PixelFormat.BBitMask; - end - else - begin - AMask := IffUnsigned(Info.HasAlphaChannel, $FF000000, 0); - RMask := $00FF0000; - GMask := $0000FF00; - BMask := $000000FF; - end; - end; - -begin - Result := nil; - if TestImage(ImageData) then - begin - InitImage(WorkData); - CloneImage(ImageData, WorkData); - // Image is converted to override format - if OverrideFormat <> ifUnknown then - ConvertImage(WorkData, OverrideFormat); - - GetImageFormatInfo(WorkData.Format, Info); - // Image is first converted to format supported by SDL - if Info.IsFloatingPoint or Info.IsSpecial then - ConvFormat := ifA8R8G8B8 - else - if Info.UsePixelFormat then - begin - if Info.BytesPerPixel < 2 then - ConvFormat := Iff(Info.HasAlphaChannel, ifA4R4G4B4, ifR5G6B5) - else - ConvFormat := WorkData.Format; - end - else - if Info.IsIndexed then - ConvFormat := ifIndex8 - else - ConvFormat := Iff(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8); - - ConvertImage(WorkData, ConvFormat); - GetImageFormatInfo(WorkData.Format, Info); - // Channel masks are determined based on image's format, - // only 8/16/24/32bit images should be here now - DetermineSDLMasks(AMask, RMask, GMask, BMask); - - // SDL surface is created - Result := SDL_CreateRGBSurface(Flags, WorkData.Width, WorkData.Height, - Info.BytesPerPixel * 8, RMask, GMask, BMask, AMask); - - if Result <> nil then - begin - LineBytes := Info.BytesPerPixel * WorkData.Width; - - if SDL_MustLock(Result) then - SDL_LockSurface(Result); - - // Pixels of image are copied to SDL surface - if LineBytes = Result.pitch then - Move(WorkData.Bits^, Result.pixels^, WorkData.Size) - else - for I := 0 to WorkData.Height - 1 do - Move(PByteArray(WorkData.Bits)[I * LineBytes], - PByteArray(Result.pixels)[I * Result.pitch], LineBytes); - - if SDL_MustLock(Result) then - SDL_UnlockSurface(Result); - - // If surface is in indexed format, palette is copied - if (Info.Format = ifIndex8) and (Result.format.palette <> nil) then - begin - Result.format.palette.ncolors := Info.PaletteEntries; - for I := 0 to Info.PaletteEntries - 1 do - begin - Result.format.palette.colors[I].r := WorkData.Palette[I].R; - Result.format.palette.colors[I].g := WorkData.Palette[I].G; - Result.format.palette.colors[I].b := WorkData.Palette[I].B; - Result.format.palette.colors[I].unused := 0; - end; - end; - end; - - FreeImage(WorkData); - end; -end; - -function SaveSDLSurfaceToFile(const FileName: string; Surface: PSDL_Surface): Boolean; -var - ImageData: TImageData; -begin - Result := False; - if CreateImageFromSDLSurface(Surface, ImageData) then - begin - Result := SaveImageToFile(FileName, ImageData); - FreeImage(ImageData); - end; -end; - -function SaveSDLSurfaceToStream(const Ext: string; Stream: TStream; Surface: PSDL_Surface): Boolean; -var - ImageData: TImageData; -begin - Result := False; - if CreateImageFromSDLSurface(Surface, ImageData) then - begin - Result := SaveImageToStream(Ext, Stream, ImageData); - FreeImage(ImageData); - end; -end; - -function SaveSDLSurfaceToMemory(const Ext: string; Data: Pointer; var Size: LongInt; Surface: PSDL_Surface): Boolean; -var - ImageData: TImageData; -begin - Result := False; - if CreateImageFromSDLSurface(Surface, ImageData) then - begin - Result := SaveImageToMemory(Ext, Data, Size, ImageData); - FreeImage(ImageData); - end; -end; - -function CreateImageFromSDLSurface(Surface: PSDL_Surface; var ImageData: TImageData; - OverrideFormat: TImageFormat): Boolean; -const - SDL_A8R8G8B8Format: TSDL_PixelFormat = (palette: nil; BitsPerPixel: 32; - BytesPerPixel: 4; Rloss: 0; Gloss: 0; Bloss: 0; Aloss: 0; - Rshift: 16; Gshift: 8; Bshift: 0; Ashift: 24; - Rmask: $00FF0000; Gmask: $0000FF00; Bmask: $000000FF; Amask: $FF000000; - colorkey: 0; alpha: $FF); -var - Format: TImageFormat; - Converted: PSDL_Surface; - Info: TImageFormatInfo; - I, LineBytes: LongInt; - - function DetermineImageFormat: TImageFormat; - var - Fmt: TImageFormat; - begin - Result := ifUnknown; - case Surface.format.BitsPerPixel of - 8: Result := ifIndex8; - 16: - begin - // go trough 16bit formats supported by Imaging and - // if there is one that matches SDL format's masks then use it - for Fmt := ifR5G6B5 to ifX4R4G4B4 do - begin - GetImageFormatInfo(Fmt, Info); - if (Info.PixelFormat.ABitMask = Surface.format.AMask) and - (Info.PixelFormat.RBitMask = Surface.format.RMask) and - (Info.PixelFormat.GBitMask = Surface.format.GMask) and - (Info.PixelFormat.BBitMask = Surface.format.BMask) then - begin - Result := Fmt; - Break; - end; - end; - end; - 24: - begin - if (Surface.format.RMask = $FF0000) and - (Surface.format.GMask = $00FF00) and - (Surface.format.BMask = $0000FF) then - Result := ifR8G8B8; - end; - 32: - begin - if (Surface.format.RMask = $00FF0000) and - (Surface.format.GMask = $0000FF00) and - (Surface.format.BMask = $000000FF) then - if (Surface.format.AMask = $FF000000) then - Result := ifA8R8G8B8 - else - Result := ifX8R8G8B8 - end; - end; - end; - -begin - Result := False; - FreeImage(ImageData); - - // See if surface is in format supported by Imaging and if it is - // not then it is converted to A8R8G8B8 - Format := DetermineImageFormat; - if Format = ifUnknown then - begin - Converted := SDL_ConvertSurface(Surface, @SDL_A8R8G8B8Format, SDL_SWSURFACE); - Format := ifA8R8G8B8; - end - else - Converted := Surface; - - if (Converted <> nil) and NewImage(Converted.w, Converted.h, Format, ImageData) then - begin - GetImageFormatInfo(Format, Info); - LineBytes := Info.BytesPerPixel * ImageData.Width; - - if SDL_MustLock(Converted) then - SDL_LockSurface(Converted); - - // New image is created and pixels are copied from SDL surface - if LineBytes = Converted.pitch then - Move(Converted.pixels^, ImageData.Bits^, ImageData.Size) - else - for I := 0 to ImageData.Height - 1 do - Move(PByteArray(Converted.pixels)[I * Converted.pitch], - PByteArray(ImageData.Bits)[I * LineBytes], LineBytes); - - if SDL_MustLock(Converted) then - SDL_UnlockSurface(Converted); - - // Copy palette if necessary - // If surface is in indexed format, palette is copied - if (Info.Format = ifIndex8) and (Converted.format.palette <> nil) then - begin - for I := 0 to Min(Info.PaletteEntries, Converted.format.palette.ncolors) - 1 do - begin - ImageData.Palette[I].A := 255; - ImageData.Palette[I].R := Converted.format.palette.colors[I].r; - ImageData.Palette[I].G := Converted.format.palette.colors[I].g; - ImageData.Palette[I].B := Converted.format.palette.colors[I].b; - end; - end; - - // Image is converted to override format - if OverrideFormat <> ifUnknown then - ConvertImage(ImageData, OverrideFormat); - - Result := True; - end; - - if Converted <> Surface then - SDL_FreeSurface(Converted); -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Fixed possible int overflow in CreateSDLSurfaceFromImage. - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - unit created and initial stuff added -} - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingSquishLib.pas b/3rd/Imaging/Extras/Extensions/ImagingSquishLib.pas deleted file mode 100644 index 4d6c763fb..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingSquishLib.pas +++ /dev/null @@ -1,170 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ High quality DXTC compressor using Squish library (dynamicaly linked).} -unit ImagingSquishLib; - -interface - -{$I ImagingOptions.inc} - -uses - ImagingTypes, Imaging, ImagingFormats; - -type - TDXTCompressor = ( - dcClusterFit, // Use a slow but high quality colour compressor (the default). - dcRangeFit, // Use a fast but low quality colour compressor. - dcClusterFitAlphaWeighted // Cluster fit that weights the colour by alpha. - // For images that are rendered using alpha blending, - // this can significantly increase the perceived quality. - ); - - TColorMetric = ( - cmPerceptual, // Use a perceptual metric for colour error (the default). - cmUniform // Use a uniform metric for colour error. - ); - -{ Compresses SrcImage using selected DXTn compression into DestImage. - DestImage should be cleared before calling.} -procedure DXTCompressImage(const SrcImage: TImageData; var DestImage: TImageData; - DXTFormat: TImageFormat; Compressor: TDXTCompressor = dcClusterFit; - Metric: TColorMetric = cmPerceptual); - -implementation - -const - FlagDXT1 = 1 shl 0; - FlagDXT3 = 1 shl 1; - FlagDXT5 = 1 shl 2; - FlagColourClusterFit = 1 shl 3; - FlagColourRangeFit = 1 shl 4; - FlagColourMetricPerceptual = 1 shl 5; - FlagColourMetricUniform = 1 shl 6; - FlagWeightColourByAlpha = 1 shl 7; - -(* @brief Compresses an image in memory. - - @param rgba The pixels of the source. - @param width The width of the source image. - @param height The height of the source image. - @param blocks Storage for the compressed output. - @param flags Compression flags. - - The source pixels should be presented as a contiguous array of width*height - rgba values, with each component as 1 byte each. In memory this should be: - - { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height - - The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, - however, DXT1 will be used by default if none is specified. When using DXT1 - compression, 8 bytes of storage are required for each compressed DXT block. - DXT3 and DXT5 compression require 16 bytes of storage per block. - - The flags parameter can also specify a preferred colour compressor and - colour error metric to use when fitting the RGB components of the data. - Possible colour compressors are: kColourClusterFit (the default) or - kColourRangeFit. Possible colour error metrics are: kColourMetricPerceptual - (the default) or kColourMetricUniform. If no flags are specified in any - particular category then the default will be used. Unknown flags are - ignored. - - When using kColourClusterFit, an additional flag can be specified to - weight the colour of each pixel by its alpha value. For images that are - rendered using alpha blending, this can significantly increase the - perceived quality. - - Internally this function calls squish::Compress for each block. To see how - much memory is required in the compressed image, use - squish::GetStorageRequirements. -*) - -procedure CompressImage(RGBA: PByte; Width, Height: Integer; Blocks: Pointer; - Flags: Integer); cdecl; external 'libsquish.dll'; - - -procedure DXTCompressImage(const SrcImage: TImageData; var DestImage: TImageData; - DXTFormat: TImageFormat; Compressor: TDXTCompressor = dcClusterFit; - Metric: TColorMetric = cmPerceptual); -var - Width, Height: Integer; - Info: TImageFormatInfo; - TempImage: TImageData; - Flags: Integer; - - function GetSquishFlags: Integer; - begin - Result := 0; - - case DXTFormat of - ifDXT1: Result := FlagDXT1; - ifDXT3: Result := FlagDXT3; - ifDXT5: Result := FlagDXT5; - end; - - case Compressor of - dcClusterFit: Result := Result or FlagColourClusterFit; - dcRangeFit: Result := Result or FlagColourRangeFit; - dcClusterFitAlphaWeighted: Result := Result or FlagColourClusterFit or FlagWeightColourByAlpha; - end; - - case Metric of - cmPerceptual: Result := Result or FlagColourMetricPerceptual; - cmUniform: Result := Result or FlagColourMetricUniform; - end; - end; - -begin - Assert(DXTFormat in [ifDXT1, ifDXT3, ifDXT5]); - - Width := SrcImage.Width; - Height := SrcImage.Height; - Flags := GetSquishFlags; - - // Check if input has correct dimensions and change them if needed - GetImageFormatInfo(DXTFormat, Info); - Info.CheckDimensions(DXTFormat, Width, Height); - - try - // Create temp image as input for squish (must be ABGR order with - // dimensions being multiples of 4) - NewImage(Width, Height, ifA8R8G8B8, TempImage); - CopyRect(SrcImage, 0, 0, SrcImage.Width, SrcImage.Height, TempImage, 0, 0); - SwapChannels(TempImage, ChannelRed, ChannelBlue); - - // Init and create out image - InitImage(DestImage); - NewImage(Width, Height, DXTFormat, DestImage); - - // Finally call Squish - CompressImage(TempImage.Bits, Width, Height, DestImage.Bits, Flags); - finally - FreeImage(TempImage); - end; -end; - -end. diff --git a/3rd/Imaging/Extras/Extensions/ImagingXpm.pas b/3rd/Imaging/Extras/Extensions/ImagingXpm.pas deleted file mode 100644 index fc91a8dc8..000000000 --- a/3rd/Imaging/Extras/Extensions/ImagingXpm.pas +++ /dev/null @@ -1,582 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader for X Window Pixmap images. } -unit ImagingXpm; -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, Contnrs, ImagingTypes, Imaging, ImagingUtility, - ImagingFormats, ImagingIO, ImagingCanvases; - -type - { Class for loading X Window Pixmap images known as XPM. - It is ASCII-text-based format, basicaly a fragment of C code - declaring static array. Loaded image is in ifA8R8G8B8 data format. - Loading as well as saving is supported now. } - TXPMFileFormat = class(TImageFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - end; - -implementation - -const - SXPMFormatName = 'X Window Pixmap'; - SXPMMasks = '*.xpm'; - XPMSupportedFormats: TImageFormats = [ifA8R8G8B8]; - -const - SXPMId = '/* XPM */'; - WhiteSpaces = [#9, #10, #13, #32]; - -const - BucketCount = 257; - -type - TColorHolder = class - public - Color: TColor32; - end; - - TBucketItem = record - Key: TColor32; - Data: string[8]; - end; - - TBucketItemArray = array of TBucketItem; - - TBucket = record - Count: Integer; - ItemIdxStart: Integer; - Items: TBucketItemArray; - end; - - TBucketArray = array of TBucket; - - { Simple color-string hash table for faster than linear searches - during XPM saving. } - TSimpleBucketList = class - private - FBuckets: TBucketArray; - FItemCount: Integer; - FABucket, FAIndex: Integer; - function GetData(AKey: TColor32): string; - procedure SetData(AKey: TColor32; const AData: string); - function FindItem(AKey: TColor32; out ABucket, AIndex: Integer): Boolean; - public - constructor Create; - procedure Add(AKey: TColor32; const AData: string); - function Exists(AKey: TColor32): Boolean; - function EnumNext(out AData: string): TColor32; - property Data[AKey: TColor32]: string read GetData write SetData; default; - property ItemCount: Integer read FItemCount; - end; - - { TSimpleBucketList } - -constructor TSimpleBucketList.Create; -begin - SetLength(FBuckets, BucketCount); -end; - -function TSimpleBucketList.GetData(AKey: TColor32): string; -var - Bucket, Index: Integer; -begin - Result := ''; - if FindItem(AKey, Bucket, Index) then - Result := string(FBuckets[Bucket].Items[Index].Data); -end; - -procedure TSimpleBucketList.SetData(AKey: TColor32; const AData: string); -var - Bucket, Index: Integer; -begin - if FindItem(AKey, Bucket, Index) then - FBuckets[Bucket].Items[Index].Data := ShortString(AData); -end; - -function TSimpleBucketList.EnumNext(out AData: string): TColor32; -begin - // Skip empty buckets - while FAIndex >= FBuckets[FABucket].Count do - begin - Inc(FABucket); - if FABucket >= Length(FBuckets) then - FABucket := 0; - FAIndex := 0; - end; - - Result := FBuckets[FABucket].Items[FAIndex].Key; - AData := string(FBuckets[FABucket].Items[FAIndex].Data); - Inc(FAIndex); -end; - -function TSimpleBucketList.FindItem(AKey: TColor32; out ABucket, - AIndex: Integer): Boolean; -var - I: Integer; - Col: TColor32Rec; -begin - Result := False; - Col := TColor32Rec(AKey); - ABucket := (Col.A + 11 * Col.B + 59 * Col.R + 119 * Col.G) mod BucketCount; - with FBuckets[ABucket] do - for I := 0 to Count - 1 do - if Items[I].Key = AKey then - begin - AIndex := I; - Result := True; - Break; - end; -end; - -procedure TSimpleBucketList.Add(AKey: TColor32; const AData: string); -var - Bucket, Index, Delta, Size: Integer; -begin - if not FindItem(AKey, Bucket, Index) then - with FBuckets[Bucket] do - begin - Size := Length(Items); - if Count = Size then - begin - if Size > 64 then - Delta := Size div 4 - else - Delta := 16; - SetLength(Items, Size + Delta); - end; - - with Items[Count] do - begin - Key := AKey; - Data := ShortString(AData); - end; - Inc(Count); - Inc(FItemCount); - end; -end; - -function TSimpleBucketList.Exists(AKey: TColor32): Boolean; -var - Bucket, Index: Integer; -begin - Result := FindItem(AKey, Bucket, Index); -end; - -{ - TXPMFileFormat implementation -} - -procedure TXPMFileFormat.Define; -begin - inherited; - FName := SXPMFormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := XPMSupportedFormats; - - AddMasks(SXPMMasks); -end; - -function TXPMFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Contents, PalLookup: TStringList; - S: AnsiString; - I, J, NumColors, Cpp, Line: Integer; - - procedure SkipWhiteSpace(var Line: string); - begin - while (Length(Line) > 0) and (AnsiChar(Line[1]) in WhiteSpaces) do - Delete(Line, 1, 1); - end; - - function ReadString(var Line: string): string; - begin - Result := ''; - SkipWhiteSpace(Line); - while (Length(Line) > 0) and not (AnsiChar(Line[1]) in WhiteSpaces) do - begin - SetLength(Result, Length(Result) + 1); - Result[Length(Result)] := Line[1]; - Delete(Line, 1, 1); - end; - end; - - function ReadInt(var Line: string): Integer; - begin - Result := StrToInt(ReadString(Line)); - end; - - function ParseHeader: Boolean; - var - S: string; - begin - S := Contents[0]; - try - Images[0].Width := ReadInt(S); - Images[0].Height := ReadInt(S); - NumColors := ReadInt(S); - Cpp := ReadInt(S); - Line := 1; - Result := True; - except - Result := False; - end; - end; - - function NamedToColor(const ColStr: string): TColor32; - var - S: string; - begin - S := LowerCase(ColStr); - if (S = 'transparent') or (S = 'none') then - Result := pcClear - else if S = 'black' then - Result := pcBlack - else if S = 'blue' then - Result := pcBlue - else if S = 'green' then - Result := pcGreen - else if S = 'cyan' then - Result := pcAqua - else if S = 'red' then - Result := pcRed - else if S = 'magenta' then - Result := pcFuchsia - else if S = 'yellow' then - Result := pcYellow - else if S = 'white' then - Result := pcWhite - else if S = 'gray' then - Result := pcLtGray - else if S = 'dkblue' then - Result := pcNavy - else if S = 'dkgreen' then - Result := pcGreen - else if S = 'dkcyan' then - Result := pcTeal - else if S = 'dkred' then - Result := pcMaroon - else if S = 'dkmagenta' then - Result := pcPurple - else if S = 'dkyellow' then - Result := pcOlive - else if S = 'maroon' then - Result := pcMaroon - else if S = 'olive' then - Result := pcOlive - else if S = 'navy' then - Result := pcNavy - else if S = 'purple' then - Result := pcPurple - else if S = 'teal' then - Result := pcTeal - else if S = 'silver' then - Result := pcSilver - else if S = 'lime' then - Result := pcLime - else if S = 'fuchsia' then - Result := pcFuchsia - else if S = 'aqua' then - Result := pcAqua - else - Result := pcClear; - end; - - procedure ParsePalette; - var - I: Integer; - S, ColType, ColStr, Code: string; - Color: TColor32; - Holder: TColorHolder; - begin - for I := 0 to NumColors - 1 do - begin - Holder := TColorHolder.Create; - // Parse pixel code and color - S := Contents[Line + I]; - Code := Copy(S, 1, Cpp); - Delete(S, 1, Cpp); - ColType := ReadString(S); - ColStr := ReadString(S); - // Convert color from hex number or named constant - if ColStr[1] = '#' then - begin - Delete(ColStr, 1, 1); - Color := LongWord(StrToInt('$' + Trim(ColStr))) or $FF000000; - end - else - Color := NamedToColor(ColStr); - // Store code and color in table for later lookup - Holder.Color := Color; - PalLookup.AddObject(Code, Holder); - end; - Inc(Line, NumColors); - end; - - procedure ParsePixels; - var - X, Y, Idx: Integer; - S, Code: string; - Pix: PColor32; - begin - Pix := Images[0].Bits; - for Y := 0 to Images[0].Height - 1 do - begin - S := Contents[Line + Y]; - for X := 0 to Images[0].Width - 1 do - begin - // Read code and look up color in the palette - Code := Copy(S, X * Cpp + 1, Cpp); - if PalLookup.Find(Code, Idx) then - Pix^ := TColorHolder(PalLookup.Objects[Idx]).Color - else - Pix^ := pcClear; - Inc(Pix); - end; - end; - end; - -begin - Result := False; - SetLength(Images, 1); - with GetIO, Images[0] do - begin - // Look up table for XPM palette entries - PalLookup := TStringList.Create; - PalLookup.Sorted := True; - PalLookup.CaseSensitive := True; - // Read whole file and assign it to string list - Contents := TStringList.Create; - SetLength(S, GetInputSize(GetIO, Handle)); - Read(Handle, @S[1], Length(S)); - Contents.Text := string(S); - // Remove quotes and other stuff - for I := Contents.Count - 1 downto 0 do - begin - J := Pos('"', Contents[I]); - if J > 0 then - Contents[I] := Copy(Contents[I], J + 1, LastDelimiter('"', Contents[I]) - J - 1) - else - Contents.Delete(I); - end; - // Parse header and create new image - if not ParseHeader then - Exit; - NewImage(Width, Height, ifA8R8G8B8, Images[0]); - // Read palette entries and assign colors to pixels - ParsePalette; - ParsePixels; - - Contents.Free; - for I := 0 to PalLookup.Count - 1 do - PalLookup.Objects[I].Free; - PalLookup.Free; - Result := True; - end; -end; - -function TXPMFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -const - ColorCharsCount = 92; - ColorChars = ' .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`''][{}|'; -var - X, Y: Integer; - ImageToSave: TImageData; - MustBeFreed: Boolean; - StrFile: TStringList; - ColTable: TSimpleBucketList; - Stream: TMemoryStream; - Line, Id: string; - CharsPerPixel: Integer; - Ptr: PColor32Rec; - ColRec: TColor32Rec; - - procedure BuildColorTables(const Img: TImageData); - var - I: Integer; - begin - Ptr := Img.Bits; - for I := 0 to Img.Width * Img.Height - 1 do - begin - if not ColTable.Exists(Ptr.Color) then - ColTable.Add(Ptr.Color, ''); - Inc(Ptr); - end; - end; - - procedure MakeStrIdsForColors; - var - I, J, K: Integer; - Id, Data: string; - begin - SetLength(Id, CharsPerPixel); - for I := 0 to ColTable.ItemCount - 1 do - begin - ColRec.Color := ColTable.EnumNext(Data); - K := I; - for J := 0 to CharsPerPixel - 1 do - begin - Id[J + 1] := ColorChars[K mod ColorCharsCount + 1]; - K := K div ColorCharsCount; - end; - ColTable.Data[ColRec.Color] := Id; - end; - end; - -begin - Result := False; - - StrFile := TStringList.Create; - ColTable := TSimpleBucketList.Create; - Stream := TMemoryStream.Create; - - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - try - // Put all unique colors of image to table - BuildColorTables(ImageToSave); - // Compute the character per pixel - CharsPerPixel := 1; - X := ColorCharsCount; - while ColTable.ItemCount > X do - begin - X := X * ColorCharsCount; - Inc(CharsPerPixel); - end; - // Assign char id to each color - MakeStrIdsForColors; - - // Start writing XPM file - StrFile.Add(SXPMId); - StrFile.Add('static char *graphic[] = {'); - StrFile.Add('/* width height num_colors chars_per_pixel */'); - StrFile.Add(SysUtils.Format('"%d %d %d %d", ', [ImageToSave.Width, - ImageToSave.Height, ColTable.ItemCount, CharsPerPixel])); - StrFile.Add('/* colors */'); - - // Write 'colors' part of XPM file - for X := 0 to ColTable.ItemCount - 1 do - begin - ColRec.Color := ColTable.EnumNext(Id); - if ColRec.A >= 128 then - StrFile.Add(Format('"%s c #%.2x%.2x%.2x",', [Id, ColRec.R, ColRec.G, ColRec.B])) - else - StrFile.Add(Format('"%s c None",', [Id])); - end; - - StrFile.Add('/* pixels */'); - - // Write pixels - for aech pixel of image find its char id - // and append it to line - Ptr := ImageToSave.Bits; - for Y := 0 to ImageToSave.Height - 1 do - begin - Line := ''; - for X := 0 to ImageToSave.Width - 1 do - begin - Line := Line + ColTable.Data[Ptr.Color]; - Inc(Ptr); - end; - Line := '"' + Line + '"'; - if Y < ImageToSave.Height - 1 then - Line := Line + ','; - StrFile.Add(Line); - end; - - StrFile.Add('};'); - - // Finally save strings to stream and write stream's data to output - // (we could directly write lines from list to output, but stream method - // takes care of D2009+ Unicode strings). - StrFile.SaveToStream(Stream); - GetIO.Write(Handle, Stream.Memory, Stream.Size); - - Result := True; - finally - StrFile.Free; - ColTable.Free; - Stream.Free; - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -procedure TXPMFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin - ConvertImage(Image, ifA8R8G8B8) -end; - -function TXPMFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Id: array[0 .. 8] of AnsiChar; - ReadCount: Integer; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Id, SizeOf(Id)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (Id = SXPMId) and (ReadCount = SizeOf(Id)); - end; -end; - -initialization - -RegisterImageFileFormat(TXPMFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.26.3 Changes/Bug Fixes ----------------------------------- - - Added XPM saving. - - -- 0.25.0 Changes/Bug Fixes ----------------------------------- - - Added XPM loading. - - Unit created. -} - -end. - - diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/bio.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/bio.obj deleted file mode 100644 index f28a922a947ee6c4db6c09bbd6154bbd65f1695d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3381 zcmbtWZ%i9y7=KGkd(0y{#-<h25EBz42`bG78)gEf8Ih3Hl@`fbZ^zxWT)keq>s2Je zCLu)X>jyp<BPJ#!P7~w4nm9kTvTW#Lf@}QZz7RfDF~$$ZRkB#0_u4D%IzDhspd8Pi z-}8HZ&-1?5_u5gLEKSD~q7qGrk>Iox@8QwP34~CaJ1&UlL{9B;cXxN4>^a?wRyq*M zKO*6qYvDe$@+3mP^>V+QssRj3@AS+Z;FA>1@LhjuxvwTK#_K*OV7}jZv7f0Xsr4FZ zUq75C%vRC}WNq5ZMp|7pjTeaTk<}8Ckyh877O6BqB&cbCC|Pd2&Zly-hL1E?lNY<p z8@{@F(L|-*i=T6~dC|ndsziI=BAA^ZCgIXvEv6LXBI1D+`BE1old!4D6yFw00~`eJ zrS*=!e*R1_p~fRB7wZa3vX~6=utE`7p`gkMT}dq^Nb%swo|l4>!pkW^405s@*V`Q` zL!3S|M680*1sI((p?+s|d+|h+-4A&hLWlw<szX2>7XBw1JOlo|b*}&MYQJ$fNWgHJ z=b6LvoaVK;gs!xCy($pq^-5|2r$$IG<}p}>jF(`TZv}XicI(x$q<x2$RFh&2k_gLj zPCruSNyIp9hA3ekfo=E<0038-M*}R9n%dY_0Dz?En`M40L{(Mvd(-@KCgHx}^^r7y zp$X+1!F(&Ml9J`d&Il`r;Us}Df9<ev&H#mgoGl-;Q-?liF)`NIY5+i7og)~}0*PCf z`TmaD8#c<8UkQ4<<eNm@OSAmd#0oz2@$;yeo$$OdVRN4!@xb%Q(8Q39eAq|MT{!Re z+Sp;A&kDcj69@Y0tku$l^e2RD&Bl|1Lg-UFvKOtzCiLMG$QD*b5!p*`3uI?yIhK+U zT5Utfas;Zgyee{<n74rK7}y>oHbI27kI(&0jO}2giBU<#rsp&<NkP?ptE5O8D=NIR z-YSUvE5ynGLJL8dRV7WlL`+A)L=h7d7e1;93d^bFOoo^$bR>n7rHEn!mDY!?K+2E* zz<wHgsDZ7kP5ArJ#_H;7m2JM-HqIEKS8OD7U~|ESv!M-=L~=aTa%RDfx9<PC+l04D zV8lL7@U7X=wfp~8@I5r%{0{1)+>X^xy@oe)dwN18K3CX}rCfKH3YII>&xK+5d$q97 zbLnOQd+4<bUZ}8^2RM}W6w>|&*i*p%2aDSX6m#9RcnWQX?dbKb*6d#E)KqAr#2I_( z><+cKQ!GNVmtNdM@Q`xcZ~)kD^9@)6lpbZUmm2WeRL8f3b7%vPQjk|1q_V$LuFOhX z6<2e3UJAfmKYVbcWt4VhbZ$NzqL$uefQv8xda+oXDvmK2emrz;yTwgkG-_7I%~i#@ z>0Ewk+fs^)9@o{GGUiKWr8&GMBOn=CP~A*r4*FiC89dHde@u_s(q5PYD0F*}A)=J@ zJ0OMxGK3)D`T~<U#NY*b45z5&d-G0w2j9*WfSNauKMsVKZc<~*_ZIT(oBKTlCSCvF z5RDgzYyQ||zMXW2@8q_vf05un@hv@^;Db)COxn%(@-O@cLC_ebj|tE~KS#<5Y<%FQ zANIO3dckT8?4w~7puNRC@|kk_^3T<!5jZ^;eb$Pu{S>f%u^VXm5(O*>!)ZhR1GKr_ AEdT%j diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/cio.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/cio.obj deleted file mode 100644 index 072ff44239f38a2b31bc9a5f3f0fa54768538c3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3680 zcmbtXZ)_7~7=PRA#yPssxiRVn=0YGLPN!~x4Hk85D<T7_+ghBo)LVOPuUvcOdUZ}1 zNM^(8tI1-Ff(gkI8Htgv{)u1Q+yX=)P8Jj5j6oB~mid7X1}a%npXYk*S_dE2HEHke zd7j_zd7j_<@A_^fsgT4zIVwa#Q6b>+igLY|46i4IRJ6-J;bnnWxc0g_ZhQUC1~Obj z$lOB!UtRDwk>Mu@nQ!2K-BCd37vHWAKEfwP)U5B)#za#AF6`BOR^U8Sd$`$>U!>ZQ zg?;&dn6EzvL&`$f^I6!kY^v9XzK3RuidopQ=F~v00hFMifj&@DZ+w|g;rp{bY_0$o zKIYB(mgNgYbNQbAoG-+MqK{T3)Nm9zYe7t`r7~YkG0X>qM`pzNpd+!G0;KSkkQu;M z;C*wnrm5Mx%N14RfWn74zbFYYmlvi`0H%;j;eA|8jr&B|wY~m1ml*L%ai8GgB}vxW z-K|sXTrovB$H4(dZP49p&2LYRhCE9ln{)-%=ZAng9(cw+p9Fu?DBoP2@6Rp{3~1Bq z+_myL`@HHvR8zWmy>b-A>lIUdyb{1(is$e|aCniU_*S5f%-niOm$YfclB!~Ol|}d^ znb($7@kNArHHb<S&)`}08UO-5Gajp`BBm;<n-xGHMzon#{HzcZC8F&(#ZS%{>^EL* zNLIn2`t%*4_*OiTxFoG^jd*;5KZX>=Z#y1XXTX9aFX{_z$BGwPSO~9fY5;+(3?Rp5 zDB|)lZ*xuI4jc05M}pQazDX=QH1$^#27Kg`ZKTB0V|%^F)PAtT2KODidv=@fr?lhc zu7eJ{$<x-|&A^wOT|>TjgE1J1cK0zcm1OP+S;G?YSt%(^Gif9F;2C1_D}q2uGp7Y9 z$CE=l;ymG4fRuV9DIAv|m0y)5LPjbHF_<w1>hj<bu}HvL1y&7-R<9(-1Ok~y)`6Kt zlPXBkwgO8`5RNvZWdp=mFeVZY_YJ5*OcMO+e)L$t^B8&pg4!2#6`1-JQ59|$Fe(D? zvw}=ZSz|}V=zg?34oqv22@}Y1HHg3pFqUPFVq_F-qemD6ArAUCb(pD*ZJ9o0q(8VP zM@B~SY$x(<2Q1mplO_ypxjJZ~6Yfa_A;!ig#s^F3^!?u!jC49fhV}!<&rIw+cmLlU zzs*dqeh2x<%wLRy-AAv^JkS8S_?gsFEZcZvC}lXw{*r2g>#5XIokLS8YBQhfvO|V* zb3jLuwp7xwNNp+VSUi1;fUb=<47OB7*0%1_bos=C^4?zeB;@LL9-@P08fQZrHFPh% znV5~QX&j&b8Mzu0X|;A}&_dMpSK3WjZt^%w9hPLbdHz#)N~G5%-h(TK#7`#fsqa7- zXiMm;=An6mQu2ygwopm;SZK6$p_)3Y=spuY*1E8^JCm((d?7TuhyA_$AK<=OvIxJL zgQk+l&4=`g?j~bw;$HlzAn=lqfiiZ@F*IdfV%d^Uxq)`G$!-hnWSLHLva^b|v&nWV zo%9?z?4AUU>(}rz1?R|v4%C3U*~F~6Vd%KY7%zk141cfA4j6q-*jQ?}*4Zs6KaLYV zTNsBqX}1={RMpw7c`>c%&Bj|>>{Uv2up!e5$+glr?w$npbgT9K1Lkj0>ESXY)p2{P zz}fO+|Hjw4AZJ$)YDXz@cxxWssN-;K-4+<$P8i?B?1|0vr-?rqdSzyAOWN+73#HTP zp(&WMaT5#!+nJah{Dayonn+q+z&GBbZZjQ3=ZTs_b231Bx27StMm2Mbxr?wn^s<K1 zYBf^_YiNU($$1;OaNTJdTkABA4LA+A&-55>f7oLf`^Z@`cHU{ceW}Md_O+84``&37 zyXG`ptcLF<r{PY2kMZJZCv)c;xK213GI|#G7n`EU3a7mY^D3OdTxP%J{9yIU;iw|S zVuFwB6ID2)1wLFxv~7cf(^gi>2yPge`(0d=*Fx2xzzGo_C;K_P#rOCOl-m|lc}3-3 b;I{gn=Dcx5fj<HI69Uj)1|onAIM@FJN%=2j diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/dwt.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/dwt.obj deleted file mode 100644 index c90e97951facbd01f335d7655f936d773bbca8da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9849 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/event.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/event.obj deleted file mode 100644 index dbc8db54bd2136374614540e8c9a3ceb5a4da1c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3114 zcmbtWZA@EL7(V@=+%T9W4#UP~h#IqG6Sr1q+2RKucQ73CQCh&YUN5(|<<{Hw?)H{# z$;zBfBY14W4>hvHgv5o!xSyIV`vpQ8{+J-d#JCuZ$r7~w+YjotSl@GdTUr?=v_J0G zdEe)G-}gE1Ip@CLfSwkGiLk_n0ut|c^HY3CY2naJ145|2E9~Wacvf!iI&q@8wWZyH zW{x7X^+bq;{jm+r97gC5@>X9=>JzTCOzvS5Ae?5qeKcV!!38<h)(D&*HeIxvi#Zib z9`^NrVcyFH7@;hMozBB{MN>F0u{|-GB;;Ycic|cB0=~WFD=lC`2<LITY%+T}ZzIK( z7JiA#+jhkZNQHPWf612O0@B{91T60n&L$9(<We&0LXh?Idq(7PRS+b}rUaSm7vOyZ ztnV%yvDvvZZb=UNWj5IC6GT4Z=AeoE&_r&T^)^S8s8<NPTU$=Kg%Br3y}X+h#jsj# zhepx9Z;D`nqZv4wCO!7X;$8_$0cOYL7`PAx8j4*&9R|LM2G4@sw!qq-DYoYq2yy7t z@;tNuJSRBis-!AizFq~2^7V=+URL&#TFU2OLS%XgNBN~d9=YCnU6a(dZ%Gv)SYZ-A zG0dt<s{AB^tTIWID4&6;cntsno12dcvWO^hWnBRTLP+hb^1FhU<&e5>mfxHa*l##> zN-E$`yxNXXekn{SDvFh@5ys2=B7~y+ZHIw%1}uc+HEp4_?R%jG`Cw(O0R&<BD&cqz zl1N?R>_<v>*Z`v)32M3jbKJo1i2*3kXU9<$GeVDz7`q0#X?XAM80j#Qo2k2Jc)&Sm zWI7!V16=6yYV?(;*Xfb^b{rY2a&HJ#QwZHOAyd|n)uWG}M<&QK!YjxGtt|2(L`_8` z=xN1=OpGW7qas3c@Q<LYC#MQHGU^e?1pV?SIxrmqQynpB!x8^CFuWk?;qJtLVP`F- zsk7_X_4qr_%G}&s(b%=(v3_&jb=pW=&#uLcc-gZ;Km<cmiKUncuW$dH*5maY85!>< z{D$S;`R%_8{B$i|y9@Er=I;h4)rZ$MAF6<Y|7K>#m$GieGrDQ&hfF6tuV;4hjIU-e zT{}NK2odJDfDX;lnOWy!OlPq3@r~b*86oS2j?UEQ$DX>qUbp<PZhYLc0<j#fQR@bd zQrKh0DM)nt0nQ|{Q+1A^(XC&y*=&3j^290Y#`c4cJ|Ofnx@3ordFP^5GvEm{T8m>; z{E_}zRs7Kl)75usz!NlB!9OLkvBs3?B}dYw8{YnPbZaI@ngaVl0B>C>eB+cxThLOe z$7aZBmcsq!*<Mw0>k<Tpyl<?cf3jH;JxW>cVN+sBc@ZY3PpRos4#fY|D+kiGxG_!P zF=N_*$Ed`;XpMC#J(V`XU5dxdNZ|p)P9kW(07`yJ=!R7Rq2y%j5T?z8>gV{Y#AT}b zE_ncHzj-J(j@L(tQ!+`QxiO;FIpd(lmfei6Qg_H4Lt*&7X9az67~T5bWxRiKM89~@ zrCU7a(l55cb>3w_3nxi{Q>QJ~S6bU__V$j>u5S8VPw)A@H!t+RH840d>=<#nM#skA LCewg0IHP|7;{$)K diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/image.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/image.obj deleted file mode 100644 index 635b5c64d51f697ee37cb570f82f71d47155d5b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3230 zcmbtWUrbwN6hCb*<wiRxk!c;wT+L#Z%pgKGU?jRxE;G&nqx4QfyX&RBh1RyW++K!@ z8&fN~n{Q2cTExVJ#IeM<_~wfbX2_zvm>|Rl-OFOKgoQn9FHjefdcJ$x(gI7QeYk(V z@0{Q7`<?Th^WFQ&et13_9##@^Jd%({eBqchA~y!$>V5#Ibt^&nlq{*7`^XXQXk&Xb zTx|eY-4#+j=5K?mF9AGgmi|0eTTB`Xf7Ceo6k9m1<!!ebrdmsIv4CN7A?KI%Lv7At zPOUi)`+hqtI8lI6%2L>ydDxECv_O#Bc3mwI&ck*Dr;QW>`0+-lG=Sl-lE>|^snSH= zMuRI2d@PW+?N~38D6IF!w^AuCl6ZPnBF!IC&U#EH)w0X3KW&QwW)u`j)s!IR3$nR^ zC(!!A?19#{z;RzfRYp`P#)ZOBIq3^v5shFG`BW*$CAINjSn(ZgZ1RQUf#`Tp_DRvG zVuX7#N724#idcbzLyr1Uf19hgR+L0U+;TaHE;IxCi(N1~B93W>UPgQCtkm{Gu|3}) z)S)w{^Z4F%4hOW037L|VpRWQ%`T0s}K}j8<GRo%=<8*r~3k7wUwe@x`rLB8TsTPh^ zC?XV9B%`Iu7ZH=RQJRVJ8N`Zv00|^>KPpg>)YQtV0tv!#qq52`a9LI3#<^L3aVGJ+ z2^d>a0f!dMoe1TJBF4v~(aL&649cM-r6~W{5wXvZg_69LYqVo~ZnT&jtE@DTKv6GJ zj#p8{uVaC>1EnWyM9h5>jBx4ahW=BOd~OQACpNUg^}|pl4)E^}Fz((i9^bo84xD7@ z&E9pYzt`Kxh@Bpf4KMhr8opDk7AqKU?*UU~z5!IT0AJg|p0#DIaIG2a*hbh(z=Tv; z2D|y)02Xto%2F%|)u9BIxE2Dt7>&lpqX5${0$7~%BV))D1L&y94hvfFXTnmuWeLj2 zqFg+LGPavcP}3#=%qFdf^^%9g>mWSav2?{se(^6%Pfr)kT`HbC<IKBGGSszW@iIf^ z{R<RCF+4kU`?8%ZZT!7vB}*n5oj*hQZS(KUZ2Vi`=N)A6CtM#^{;_%4cgf<)69Z82 zU&(CwvMtN0jAfGjBh!h`E14~wsXH0MJ7)U(aD|ywqywGL=-y4jXNY(6(|h0qXj!)K zncDnZ&8?+<^H25-4*C}&4H1ihN!?*{ai8@F=ZdFEW-43r`D5fIyi-3_NBpcVI@8Qh znn}&yv-TPALGnnSa80d`bE8zjXcOM@yysSb#?fHQ?FT>Lvt^lT!+iWj_{|QUtw~?U zSu)|mAz4Z@ooVJXq_sUF&+5++H=}nm#KY<WOHMoV9tUwd^=>Ee)agPUIqlMWT*Td= zcQ+6Zrwbf8eMs+lJ;IP~b|daErD0@xcT;Mz3C0hOzJ_aU6ZeWKZmllMZ>AOwW6nCf zY|XVuHk&2CiRXtfOUB-M1dM#@uGW$I*acc+%lcY<nz@i>zMyK|F4EUDwX9Y5o9XE8 zNIEawLxE?_vB!LzAM!82H|=oacfmeq5iD~qyiN$V`@I9!`vU?qHz-ui-4!hNAL95i zj@N~%o4tbdrifQau)=H~U`c!9(r{GfG=(!d2z!7td!7p^DrdItGyl^I2ol17dhm^a diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/j2k.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/j2k.obj deleted file mode 100644 index 23f360146dce2a54379a4a9e9ab37bd80b13e1ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20915 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/j2k_lib.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/j2k_lib.obj deleted file mode 100644 index 3dbe8d569e5081df7fe7df24fb8d9e3f6f9ca17e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7884 zcmb_hU2IfE6rOFDQeug142o1u<C6(V#Uiv&gO+y1m=FlGM&dT>?A+=0?%u!Nx!Y}x zfQAr@*M~kCF&atag~+QfK8ZDk7n2I{#l*xIA0Yb9N*eK;xp$W?r4M_CChczT%=zY= zZ@zQp=YH@M+u_(nKagHIkfnTis8WFc2L)T&!5Hfs_bquu@^D~$_wIpxg9nD#(sPX6 z+QjI}7atF^rKcIYJ;Z<A-?tuk#$Fhl-K5R-qDI@*XU-3|*ttTt?F7t^`rjGpU5^<J zHO#(w(9Ehe%@DHH?4^d;hS4HnVcSDT3+#s3hTx)7Gk|X|&$I?mwEc$NhPIH`8f_R{ zYv6OD(Y9f{a?l*_#jkm*T{+mC6_{Pb><2Q@mnYVfX}i26Hyu$VQJ^Jy(_$&-Wio-U zLF>Dhb`6h+gZUuzOCfg$W^6~QyZ{-MKt}nHTLUVpTDG6xH@GKnd%~$&GS3~y*Wr$( z5C__ZaGMwdfYCoYJ+gCscz#eW-0$)%bU_9ls(oMxG=6*d5+8Z86(UIzB#G{4!9z+A zgHD%<fIx(JHKl8~ZMq`cHFRRe@wt{E-3gaRvu13%()Ghd#CRU4_-Rgz>}s8|av{~2 z!cK=$zV^4xm+iV{0ItvlkS?5>?WuX4B;#omqisi_qL4dw$-__%rzi*8MiIX2T29Ff z#CIgGMq0&mPoT;Kw&kEF^lb9EF@&oYT<wLy)W~oi!kNcd=pq4D(_rWr)zEQ$EfG4W zqExl@Qc8EjFP6<i@hV=;FccYvo|Y*+6a`D4FsyV?^P#dC=3KE{<Vx3ldeH`n=^X}L z96_jN^~yod7A%H=?;GYEqPQZ|LN)Tm_C=(9p=%@zgyI^5UJe1nQ+8lhLJ-6X%`j@w zVj%U3YecIOJeeFituV!MMtefX@I<(n?6~O|#U_RkBTW?gPG-(Gq{H^OWh@XiWXTy6 znGqez7ZqKM=s5!d31n#Kikg*<!;=#tJs`+Dt`<GRJs#$71dEng1}CKiG3e9+h9#tV zIRX%Lgf4k-1Oe!4o>$zv2NCFV>$+-DMN%Ik=qS#6av|WJUa;uVz}{V#0Qw4USu)x0 z(&q#qkWso1!b(L>rxSADlTl4yiqK1YD7i}Z%XAFzB$WC@WrQ&=4bvX{5RV`h&oLBO zH1AjS7Li_kAe5>~_@FB!P_qFS6@6o9G&3bjUmwyvfp9?YzMfwrQW_@!x+|5)eFXcv zl-d!qx|*UGZUO>7z-fLYuDpyW^tuQ)S_nX|?gitkQ~=<~6{Ud}aMgry(31uLY|rqL z32!0NeI`9;FkvF4*W9D&omsB!J2MqXkwl~l_?f)cpvxpZE54pObjZXZoF_UxZc$)0 zKoEn)+#CW5Wbzt<E;)cm)k2S?;8h)cj5mM)C-nMBpA^toL-=$$0E34*1L?8I1(6(` zCsL)p(!Nryie**Otqq+LoLs-AdBxX1_^$GyuYcgxXD76?PhVhL3X{3FC$r<nCUWq7 zVr+6Oi+{Q%j+{6)bv#=*eDY)`{IbusvMW8AOb6577|U*HeB0X1*ymlW>t5%*4))15 z)>UvEx9Tvq+{;*I8@`niP;M)0jIpK182hS<_oi^s_rQObdNUcurs99%sh&93J-T|f zBmQA}WqEmd-Lv=CKRepn=z1oLT}Q8<&c@fKSI`J;a^2^@Kiw6t-udnCj(9Zz!{<j4 zzw_D~7w`Pr#LxA_*S~}D+08#Yr@G&auiw0@4VwLL*6;W2-h1O*J#(h}m-=D&JX^o- z=eZy2ajxg$iQ_QB#ajT!F68PLrq<$IJ)T<o@DB!@?7fl6)%zOH9>2P}{o38_r%p|; e{Jtd%9;~2M^7G|3cKPSGGJpLynPD+d&;AEoY(irI diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/jp2.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/jp2.obj deleted file mode 100644 index 587d7a758006c0aa451dbfbd6be1cc8c0cbdc9a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9136 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%0DUKh=0(O;OHlE?|^LPSⅇ2YmAL-K!Zffc$U;l3nZeYK(7J(K!Kckr{^s{uR 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 Jm{67u{{w=(`R)J! diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/jpt.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/jpt.obj deleted file mode 100644 index a2949243c5d77d1728212ccc699b2e94fa93f15d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3245 zcmbtWUr1Y57(X|O=B~yW{|&2l+?EXnf@{rMZ42A{lbH#{%$PVa>D@KCi8o7f)0>-i z9kXtPGUM5UPh%|<gw==9!uGJe?5UZ>>7bA)gVMoJ#~>qnZxk{6&P{Gisy>)J<mTM- z`+mRg&pF>Y_wz<n9}p(RFdy=Vd7slCmOI^OwizK*-!FRjL7tPC{*DgjeCNe3G~0?$ z>JUN~_s0b^dlI34$*4roD}2&9bp$4aWEFeZe!IJb7j!FF3uu1XHqm1&4pQz?X%Akc zd2SSFM6#52PNg02Cc8ZZJJefPP-zE}lYNB*e!A~1O<+<GRo($i;%=xINv<^UYi<=g z;E$|MzL;-*%a!u{;iIeK@A{bV+Mt*umd4^@3PH}ttEvY)x^r0&Cc#RW{B=IJfbRnO z(L!r?kNc7{EQvme3o>3Iz(<^J*g`(oLQaYEFcCTG5k%+t&a+M-<PJnVypszAL?zwc zyu`(0O9TrV3~01Xxq4cP(-XsfcHiU_n2-uI7n?wJSa>Hjcop#O1+M3nVq9$wV$he5 z^V0F-oOH`K!%C&guUA2${CY)X4=4FZF6C>mA+o$gqx@7Lj@;gQCtuR;W0zDGf)xhg z4Tzl5QsoB`<m4$*iSiZLihBSAxZHYF5Jg0mD%%wxAcT~iRsOEvB`Ktwo8@oL2%I-= zWl1W~kUjYmq5M?XP&5#ztVdW6?~M?N@{b)B`V3Tv$lLiwyKwAA3-ZCrwgw1@(oLdq z27*|==I&`NJz@Q9{z_2NJ@iW=|7oHH0rd47sEQpme>ke^A09Bnc%XN*S4SSz1A`;O zcB_u<v)Q!pL*MApcMmj_1}USnNLQ5`A*81fx?7E^v)Zf%eRT%alDk5=)YxFehiJI_ zSc&I6sG1D~g3$m%^YHycH9{Z|tsoOCb_xu5$wC!_gj5916A)6O8VFMX9euqv(C~`8 z2(Wg*nse9-x-w7~zSqFhj{n1U12)r_lQSCpi)(3qe!gh#v*NicM%DC|j+kCvnbzTi zYl)Bu$4uXTG+m98&!43=IGGb8^H+$zHetE*e7m4;HsF<?!9QBx(%R`Eyt2Nd5DNC| znSEQ@v=+-yx9Hz9eege%*^e{!ID^fGJ0n)`a3=+FC~nTg?Yr2V!S>xRHjoh^(;8*Y z)T?uK50kZto!aqn*An=$Ik3xsqqLuLDD2o{I^CG~TOZq+sd-j3X<D00;@=Y6`uF8c zfM3sor`X0!%~QN|bt0d?Y0b0>VZ@E5wYWuRT8&%jxWzzb<5p#^DQ;~!($*NaGyw=P zePDBp;b|j|8kWsjv~1o(W2x0_Hao7ygP)on%`HKwiA+^&LmNv`(h2#LMSjg9ccjlv zkt+BpY^O)^DH+o3s#3ZEMikLZ)A<oa#BegPql;}(Ls9*&gF3P<cqO)3_flOVqqjs~ z#(JwG^<*!b1*dU66vLh!iZ+=3jI*@Ok@_(Y4ALNF-m~No10Z)*#DE8lATg)D8}V4v zh$Ho>`rd?x>DVR}+op2l79hJ+u!X%k0n3H%okaJaIJAp34$UG1zaJc$f7VAei+?#N zwD1;!R(wyCCIvW`Ld<n85ak&@<QAhLnU@$L#02?B1ind`Tx&6>PoID+frS1C*zUap diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/libcrtdll.a b/3rd/Imaging/Extras/Extensions/J2KObjects/libcrtdll.a deleted file mode 100644 index 7128707781c3c15cee9511a585968bed58849786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357874 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 G@&5zkE_M6> diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpeglinx86.a b/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpeglinx86.a deleted file mode 100644 index 32e4dd02ff2bf91fcf9ba884d2237db476050fc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142232 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpeglinx86_64.a b/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpeglinx86_64.a deleted file mode 100644 index a6af54430507a0a7ec01275bf3bef10b4d17a661..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 180386 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%0Aux&^`xM`@@|g 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpegosxx86.a b/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpegosxx86.a deleted file mode 100644 index 1f7dd32b12df86390241e2a9e5010edfb8f2a95f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165176 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpegwin32.a b/3rd/Imaging/Extras/Extensions/J2KObjects/libopenjpegwin32.a deleted file mode 100644 index efef2ac99dcb44d6a23e9f04dca1b4ac57d1adf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122284 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/mct.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/mct.obj deleted file mode 100644 index 4a25c0d901e817bbb530427a14de1b756e0d59f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3522 zcmbtXeQXnD7=Qc0R-tp7<6{gki~eKMWNw|XG7J^Qi5MHYk4}M>^VVKJX1{2!0)~R7 zA?|!3nZ_7EO=ct}Ml>cwO;D4KO`Ig^fS7E45FuGOv?fh#vSZZM=e_H7tz#x@|G4)0 zJkRg<e7|>nxenF(eSM)Y8|)9W9(%yaH9671DuhsNN65wQWSK}~hr!Uev1zjr4KyGm z+yiiK{qZ(5uoj`)M&_qYMTBnOp(gJlI$w}ebcCS@M*;y{J#fCdZl9^9Fi6g*z&`pf z%ylpiBb3Fk76rDz8|QQ_>MiV3U<;DtJoyAZJL@h^pwAala0_%1=Afb@$rUGlz^UjK z`0Een{XP0VQ;h2mFJ6^?;|qjy9TbzqQdd|^Ux4wji+Xg*Sr8<NrU=Qt$jS|T0<_N$ zHME(W?e=ga<cTnWMz_z;M(s`*ArFj@J;Jyeqg>483)wd|HQRkbr$6Rm?Tp_alG5Fl zqu9J;ia?&D5jfU)9j5xi^g`i&dfsFMn2-vrDl~!W(D0ko;6c#04Kb$Gg?eQ<h{5(; zob5}Gv(L#L4oj6Ty<T~W((4uFTuj76aw(mI4wCi~j?z<sION$f=SteP<dSl}K$$_f z{UJtLsnUZ8Fr1fEqI3qj>>U6CM(#%$QAD{&c~b!dzMwQ&rB4MLi3Fu{v-IJN!g=GA zT2clF=gOT3rKds%V}5^mJ3_lyca%_+e(cb&XTU;8w&oUX(~=i0zy``24Il_b4ik=t zAc#u`oTi526SkkuJrbmJ$(zK2XLRn>L<2hX)+1;c-9tUsqwUzegM#}V+j_QX$w$SG zon5<aRxQ1~yITVnI#r22Jg-ryk#yILw9Di>ger9iovA<-Sxr`rPOL!{wBH|y`H`Nc zxmctx^dvbP5E`sSNVOci(`=AD&oZb`=3<G=uL9WvV7G$Uc~~wOiUfWo!qp(Go(Izr zmhmTx6f%RP&_i;AYXDJGKqG0+f@bIo4FGL8iEVmJ>9$N9Q{#({(ZRvN0@;y5nWaWC zJ*p+9TgKyBJmMH7AcCQE$A{w;cw*+~Kh=0bCL?kS;n$2jb$aGbo}bd=@eAM|UAw8V z>7K^p*JdR^-u{|6Z>wv)nh;e-byvjg@O@02k25hQVoHCy%L*P&3qXf>O5|-BOo`Z* zdF6LhgHY>L6(!axvg&gaRU@-id-ga+!B=7|**e_a`z%jou&oBD@MY}CK=4oy$I3W` zjkq3f=HueY$D^9KIFeQK@idN$hB?D^KAz$oN$g1T_1KZ(8?YnEugy}K#E3R=QJWan z0uzuN`I6qh4^KljlE2jd`Rl;-yhFqdxP_0UaV)L*dt^@Ci(?{fn8ES1W)6IwT>l^j z&nDh@Pj6o<-jtsFru~N0Me#4>{X?>latcz#lbFhEp;qGA>XUzgEw1BjBEFxuq;Vxr zrM$1-2Qr)3CA>D5%_hclR_}K(o!FA@6b{Lfy_$(G?*}kdm`Yg%r!3r~8RsoYuNzhb z`e7BGk;OBUR_~eRgfZPEm~y6u@lG#kmV|#ePs-Z_S!@wI1-&e`dfipTFl`lP|B>R^ zYXI+OU?;I9)hSHNLTpLy<yX96xQJ~6znZTko%vRqxTH;tYUOmRPt;|z*`j(S#)R(P z)?YAHgU55j4r9RLW<Hj|Mm{D=otdK2lT~j*wv$w5%8{C)#L22t<YyowsosJ6>$j&I zNl7!L7z#L+;+t_S$s2J@;9ENKlS0PiZFx$d{9keB%|Et$y7k7DP3Gx|n`W{Tln(j` ze_x=F=-mzI?DxH@>FFNzt@a+(tzB^0;BvzCagQ1eJ%*qbiQ&udQJ>#6AG_Ng{$b#c c{I?>%@zTmqcHYRC_g~nhR~zn_5e5+Y7ck~rZ2$lO diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/mqc.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/mqc.obj deleted file mode 100644 index cd84bbe02378ba97b73468698f905ceba7e6753a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6951 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 HP~rU_sGf2s diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/openjpeg.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/openjpeg.obj deleted file mode 100644 index 9b971a1c90f13911ea0f409cf7a7e9affbb9548c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10117 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/pi.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/pi.obj deleted file mode 100644 index 5e606499ac7465a186fe50fb71564e73e468f569..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12125 zcmd5?aadH>m47f#o!Bvhl}0w9Ep7R>ejk3R72A*wUzcHcIsqrXnPE^94H7`bfD)W( zG>Q>NTP~L|q`2MKO}2bllh3ql&F;EeTkTg+DroJNsNK-6-JK*feXp=B-Li4klFt6l zee=cv#2D=#_4^+0-gC}9_ndR@{hf2)xc9?SMt$Am+Zt=PZfUIDw63x4{%Wc9Ba$S| zcWtYwT~S-rl;g_F%lX{>4=$Bj|3Z?q>GEH>@6iIm)0bBL^z-vm)orZXasTEScy(KY zCa*jDzyp)UHB<{;mL%z<eUgd6rRK12O&wPARB{-poILEa=CEnA1*>a_cf;8bkeM6^ zZb~}vFGn^`cHr^4ZRWUXyr!zBOddHm+3_c<P2RL%ZfQ);_nE)1nmlex<IGXnvh)ek zc^`sFwk$|ppt^>tO|>)5SZ#PgBgvXcBWu4@Yb;<9xEs3eeW0NF3+o!2wry&vYRK7G zS6{n*T{U*lChVYfO;t5H+k>H+x^3$|cmI-gbz7_JLp8PQs_N^v33r_d6%T%36%9!p zInZ(6=Jf?xsqSrS+){a6<f9Ow2z(?}1ktHPpJMPa@E_=^D!3<=ZypU2C{Eb<g%57$ z<JG~PjUv*wAFrf}+mF}wU`<uiCi3O>byRMp<s}`r?+WZN_SRn|Li)f54r#Ei;SP=1 zSih}G9I4wkqM<6dnIduf8Y=Jj3_wAZu^x9|#r9y+o$U%JsM{)b*6r_#+NP$h0yl4e zb8ZLTREs6K10BJd1R~tNE0tSA_4RjlMk;G+H*O~tw+}m&IA_p8O1_vlXrKSU2d$yD z;m)=O6l`nSNjg3WBhEfqU2yMYgxyk^ND0E-nes3S6AQ*mUt1*2sw`L5l*_JFB?{Ul z&T^+re`c4g@U04{a%HjKZ^0uyKSz4?Z*$YqCDF>3<XJ{blIB<?>Fcwl*>OueU20z> z&BhtRL6YQ+O|`YsY$It%bFizoRyXdHW>?nNH-zdXsRPL{Ewix>7S{#qs_N^u*H+eU zrA)UW6WoR1W`JAWR9h7^Iax?7Q#m!YG^X!vaOPvoT#Tuy#cbPlW*|*<fSxu7w5_!} zg2zGVlI1i>3h+@LuyMue7<?w3pI(2aqoX5*wmX&P$uLFt$Rz3*XqI{J`ZF|$#wgYU zJ<YTE;MJdxr1L>T8PPqY-_q+oeD(j5`V|`=_#Wn$F1=+5SWEf9rE6k9QvOoxx~w(- zVmOwz$NGA#81H9d*X<1V#kgWS>{BtrVGZgero>oaf-5l|m}rSg8IqKLF-?ihH);0n z!Fj#c=B-`3{tV{wV_bO0A}O?ht69Bo$(D{j=+M84KO?j9&oTERt`;#hSMLUeyB9Ne zwqSB~2~)F1b|r`KN37hP?fBU<=_A#>Z_3<fv%J2yKnl&}rB?f~QX6x-xmv>1oRLEA z≧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 Yl|Gj$sV=m9E79_)u9ffxae#pI|DfnvHvj+t diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/raw.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/raw.obj deleted file mode 100644 index e02070854e32dfc3570a8d3ac472b9b2c16c3401..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2889 zcmbtWPi)&%82^&Ei8WF!r5TL2puh>KsDoBrvQ>iqvlby$v$m$9B9U=zCv~vn%yHN% zv5l#kX!bbtgeVeH5#0f?D;zjcib{7tDy_KeH0?CB-Iq<3!uOmwjcI$Rb4cR+zVG+@ z{=DzK=P$aUOH=2JqEg5gm0a2suMSACbP52vCJb4*ponH{qQ5^jJaBFhmU;jlA42$f zEgOfW*8u(<6#qHv63nXC2Ih~jsRhfi-Rrv@cky(|ww*@JFMB^uL|T)y1|8Z@|EI}U zn=~rvroHFT4n(sgnc5DGR#Y9@f#R%OvjExxR{?XX;qVUFXqOvJp~bm)`W4Bs9f+4N zHshW7L3H!-#iP5DAN-VR_F^+>F5RuoRCO_@92rrnS3#LH8y8dgOsOy6C|W;R?TII( z^XZ~#<V;bIWmQcnr6nAp9F7pql^iQsWmz@S!vpW8)q<pzWhE_Ynqika){r=NYze)o z5krmM`Ap(;Yk5X7FYLR#jxMwVr&?XGI|BZvJ$M7{@l`SLN~_)39MoaFk>~m2=Q$@? z3q`xr-uu;*@ZPVIC5vW`*5X}5DA47l8s1C6JnFOcL8GPdW4F{&^){2pYKCZUDep<> zqBT!D;ax#!dk>(1SYMAevM5<*dsBe|YQdf??^B_eX2Cu;y$@#z&l|~Jk~TCfxp5+R zFGVPnHLblpBFIX%L?yf*I|A-ARG}j8H#XYYV{bHF(c2ph6fn#Ms__;kv3W&G^teyh zywJE3>~iUw#G#iazM2Hk24BAo9l|vC(KIu0agxL5$+77%hJFPnFI>8q;u&H5^5p=2 z;F}Qq_`T2P2m1+t>2RJxEWo!x2-X5MKYaBnFj-SkAXvXGASh^>Ue*AXy8wJA@X8h> zQxPp?4-k79v6m<&D>(MX0_#Jt8^JII3uS$7!BR?nE>tb37Wzx?P_!wE0A7+jVykz3 z_?;q8Nh(Y@c4YgepZuQLSYBRk!9H)rrXr5(4TidoY+Yx_dS-)?D2HQj|8_k{wx2zC z;wRg6F^W%7{lI#1<=OM5J{KlizhZpYeH2KsACj%z7dD~kzgyk+WrubatG*lT-_>#a zy;<GQbMcQV;leAIc#N>}80DbCRV%4I!c|FX@76<z01WN;xN4V!oxHc*x&ESab~dw- z@3R@RPR%rbE5z49j9#ya@R5E#N<%jOr@|FJI<!NkB9$at;lrC4;(jH`wB);Zje+v; zpQ8+}IS@WP!n5U$O{hJ2bLjpZ_SW+n!sQU!L$*CilHohi6HAfWXt<VSNRm1E3+z@G bANn#I@LeaY{WTL<tIhcDMrV9LaJJw-TRs)V diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/t1.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/t1.obj deleted file mode 100644 index 9f4cd2213689dc2b78a0fd170cd49ce83272eef2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13137 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 UB}>HuQeec{7O-g`l$D782a2gi&j0`b diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/t2.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/t2.obj deleted file mode 100644 index 7cb038923b6b30316bba5fce913046338fa60591..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8834 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 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/tcd.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/tcd.obj deleted file mode 100644 index 30060181ad4e12c7e06e502eb1f18f4f399fe4fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22667 zcmdUX3tUv^nfDoHz>$oZF`1-eO48X@v$SIp3^p;vG~A9saJ~$enTVGV0w^E~g&Cs; zqGqJa@ntH0pZ3$OW@(F;?%LJunqO=`+k&!+mrXI!bPQmLMV;Akw<M)X6C1w&^PY3& z;w4GVe*62DA2a8i_j%s?^FH@8>+TgM*Hpb!TUW87x~^jBB6nH&qh&(NeS#oN&Z;f1 zc($Un-kN2zS-<}1Q;!QR4+uiw78U;HiwkE7EmH&`_;~5BpNMI2N!6-HD{lj<TH#h< z`;wZUjH$Q0jKeHwlUg^$4DxZc+CSV_t^DP1HEJ@p+6=YYO}){yG0I!^R#&A~yJ>Rn zrQr#@(Xk|U0xwn7s`YMy)tA1k!f0}_6aQA33cIPl>bh`$kNvPTwqAAJ?N_Dx@nzKJ z7qOT$mV2WYvub(i(u&*mSSHVcYSL(8YF4bQkT)<L&==bucyd<RHx|{^*DkFuU2a`c zRa4Qhs0<{u6eP5$zO>xh;P#YP)h_z_qbZB3R+QCv$}1L?*3{JU>1HTRJoOhhu{_*{ z6>WU6a`7xn^z>@$s!Jj$4+4c&;J#=StWF7@X$>9%{K@vxS@%c7)x$vunaVi7@t2SD zr84*GI=<3(zFy%b?tHx(+~uY9OKC25-bTp^+Foko&ZmNL$h7s0vZPP`#Y^h0TK+i) zv81N9lpm=(AH?!fcO|XFowrc(xz7L^D3$l)bBv<FUH|#00u5BH;FNXeR8di1zk>74 zJ15Qt@S8HeC7+`Wce%n5?tCgGD?BwdpYM#6lvgZipeF8|?Udl0p%rT6o613Z;x9gE z%PW?DKGHw~we_p1jW1&m$G%lI>w#DfTV0}v1U_BTByJLnifW<-O!#iH5MNRx&M(qs zJ(n%wK0Bi*Lq}f;+0Pa{=XB^wG7Af}_z2r32tV2(YT^WbHxj3dm+u5&f?g2*HbF=j z*N(>tt(!CnI7B!}f^JEDMTL+cOASF+R#8<WXzOZU7A8WHtSTvgsis1hu%r&e?p`8H zBmq-~YRiO4bjyWe$?}G!LL#(-lCt`WQg?-L7u}av;Dpq!7ACr9sO5>cRf~<duUJ76 zv!v{$nq>_F6_i&*6(mBtQBVYaFGGd9sC;RKdueIa3c(mbDnaKpa)HtgFEB-+%P5oG zkE>nRm6k25a5o54q*PLiCZb50Pa=oP(@BJ?79JJdE2A<-%9VjcfO0`XNlndiPYt$j ziMzH&FqD+IJ@qfu&LO5O2yI3|(CD%2CFP#wb=L)yOh!o}mB_;w04=oLgR;9gmb|=4 zIut^Y(@ds9c@vf4%_h+O02v8HyQ~0)P0@g=6;<kl+R^$=jmh&{1zn*H`h@2GsD6|c zb3-~d{uSWRmo@jw@MRS>rK>CIOP~-}lvjQ&x^g{8gp(ewGW^9y05_xZq?pPrRQv@L zo2WRtT1pBa;i)NPM8nwjWHcaZd}Fht0emrJs5=_~D0~_-brJ<Aq4rt<Z5MPJL2$Aw z%xPevKCO3c96Pf3Xj@xbR9RzmncbwKzN#bCw4Np%>sox2Dp4I#-`v@hz<RH}8;WDS za${6(r}nj7Ioq%ODcrtjU_C!W|H9b|TBkmj^_=~XR|w;u9gE=VQ{VQEX<pTz8Oy|V z?O0@--tI9b8nzcW(8KlsniC{(Ombdl;uv#YUq2*(CQ{$lh+~u0GULA9NnIaKDlT4p z6n%NShYDTKGmpNK>biIf-flhGWa&xFVJKiZx_su)7cjxWF#imlgE>tsF~4$R6uvdJ zQxdNSOTeCJg>o(En`P+PNuN32XWoqet_wQt5lOsKIU}kXy1Bv}rUGWa!ZHkK_zKI_ z=kr1xFVr|H)1vT`Qs0)GV?jTbjjA}ux-P`C3^O$xsH6!*#%~X>3=>)muv`OL4DcyX zA&oyk<M%}2C(-yvgC*23pyDXYHM8EXp?KSouAw+>k7OUN{QD?;J+lw93=5hX1}54c zmZyP2ng$AK8YrY`3^PpQji}mFX&NKJGbm#Ak*@dRwf13eSCV8Os=OLTW8x6)gTqol zTWlXXmytA>G!><MQ|v=nUi37?a<M%qG!;}PVD#z&OidjR6;SznGdqqcRAv*<r|Z=E z!&_WvE?{}4e3peF7h;3+(2~|s>56K`TG<-)q<@yChH2%RjQexUX@6?mS-CwLJ}!>% z$y?IwBgReE@$vD>j#&68-wIQjbJV!$e|`-3k7MDODM-PTCXN|5O(FQfSon1!KGB3( z8~5we?AMK(TK^2JpGISqys(g6RL@SKt9llnaWV5Z_j`1youR4Bsh0}P)rNqubGy*- zudatKPArPsWpqur_!O?s;97_4N?hA<-Hq!BTz`e@pKu*_O}O;cqPX3U;kp#p<+y$a z*Dbi7#I+aK%ea2vns9k?QQV#{;QA$8r{Vext|G1_xK`l07T0E6{|?t(xc&>Sr(6^E z47;>KyH2OM4$&Y8#cV`sury!w+*K$~1(S$lM_*WoN#Y0>vc>x5e)nXSWpT)G1x<mk z?@q@~&?y)7IGvIsiP>@TOj3rGucn^mW`oY8L^|J2J<G_!0hTg!l@9c-tR0G}OwZ4G zmEGJ2*9z@}qegp1q7!2pughM*L^C@HCMSU|ZzvH5sP}XW&Y|S=6Gzm5eC54NVUAhG z{mvon$^5|7kH*KD-4D{2G{l7X3Bs_zd1kWQ*~b0$0d1Ef@aGSK=HzIZI>O7rfurVz z(lLu`)w8r2DUQI=C@jnvSl|VOH6UZn)@ICf1a?MY8B*Woc);;XIVK78ZV&h}%u;g^ z)-ZS)bjG&Q?YX#f@!jC9=T5vE{O!=y?rb9)!B(O5b!$w5aYHjb_&BD<KdA?p)Gns& zuz+#&$6@g2Pk>F}+MkXY_-%UQ{#@!7#SX{|zs&&}KS}H~(}Lq>k$m&eFKv)L(BI7O zGY#k8CpM+E9np4rJ3rWdZM8va&H-9K|2`iKl`}r_bAmDmi~ucWSg@V_7!vOdOXKg) z&|%qala2cwCfr~U85pkLmVrU^@+H9_@-5QVY~DJ3pMO7;ATNTlBoC;4-Ly0tu^Qf{ zVZr^Bf|_~VAAgz_MOh+w8DC#HB?{gfflmp2m8yHb66v82P^DIbL9TTi;%6j-a~MNz znseB5zuLTinx7hzm%=hG4tx2nPL>a8_F?0uY2Y?APlpLYr9dHjyI;yM6U~nW?}xnO zvSEyE>?P_a@t{58(`EW}uPH*J4=WZUm3o;SV%WgCe1;sKp#?k1%q<WJeo%j)d5pHR zmq<PCX1t;nk{y0w=hH%m;L>)OTyY&K_&kZvdYAU%jv~#)V?~-vdH8%EpEvR8$LFIW z&E+Zh<P>T4tWw#?1d@A!g^><%Xl^$$$d$m1C`{1XjdM`OM#3(T5QPeg>BWpl^4oiD zaV(z-Z27ut|AqxpcoX0fmO<=;V!^~-95Si_%I|_8wDoko7niT{93YxgPe^tMjXq!7 zbZ{eSs{@1={N)6!Kf1~=<=DhgN$jR3ZXvYWn7td)u@}-YP=9TFoCK=9jTlQem=Ai@ z<p&lh<<2&VI0*pMFxDU=3V>>ILr{nU$&r>a4Bn<u!873y_<|6MKSb=BQA-wP@4Kqe zxRY2jjhKOxoMt|LyM6<ZB(W!S_i^zwj054g*h3fQJdF)+Bg(jNRT=B)vqO^D$(%iq z<!!_Z1IJZR4}lId@ib=AM*2peO$G5<hnU#IL7CVjj|$?o4l?^`CLXehooBJL7%fhG z4-*gC#KTH~nNRCsCW7=2Fy~>(xsTZoN%p<KlEe-SRdTkYl4RczDyYVKb~*x+<vvgW z1<u1bLTbT26xa{t2Y&xYJ}pVyOH~d!0_W8NYB5)CaxU6rVmpT3$7eN1#o5Nh9dfB5 zKair9ZlTjT65IlF7+TfVMp|q|r)nde%C`z7d^RNdvB4whY%7(~tYzS8lg4de%^Y!+ zN$Z)w)$&jrX=$zD@;KnA_`s2OJdS#AksI`a?|T|lLIK4I@)+e>u|#)qRNi1^Br$Y% zA{G`ydOucRd>~SWA@~y_9I=~^I31+h4QfAo0m8JE>1`0Fji^Aw6LwA%I-0>o{!wKK zcgcGZ$E%`=nA$BkoK)SRRF`oxb+<%rh43Zhuf!tjZ;6bS4TOC44>2nspCj5Lh`v#u zE?p~*csoCaXw!;)-p(YcneVK#&%4Gfc<zzclr(&qSA<OR9)OQ1+(QyKkO>5F*DJGV zmTzI%uUWL>21#7Ue7revolOJnT52W*sh@vC$F9VhrdP|FkGC5w6K;Q|&Od1YLc||G zgm1`4z6a-ual&Py>tiOFShSm`f)C_Mkn}j2IJdI8>@&}0C&Au)h7&4>Q??%xCN#xo z?o?(q*PPlfE!u45-%08Gc$@GI{lM%q%uVZRJWFJECAf{uEm%<Y_U+d``USBdJe|E{ z+z&<IBWB<6ODZ~h*|;C;(9Q|=?2y)TK-;uWdyH?6)Let90TVXpZ=|i2^uW)7vYId+ z#4BLkFqahD;kWP0q@Y#sz>=O1oKy<4bn3pqG}%f`7X<!Rh3QootPS2%LEu#t1~IXX zY>&Woxde~kZq05Qk8?`_%YyKFPX%ouP#p(t0|=b@?*T#;;_f3%+;a93>>2Rs{}ojO zVA~ti-r0|(2C%y=Hr~Y9F)7Pjox-wA*Or-OS|V|rWnp9-Whvyvi;{Q|>?KZdyvUk5 z9@LOVXy2x+F6&{(w_p1hdYjfqz42nnS5Bj~W8h(UkJd+1P~a~T{2HINwwaKn=0z%$ z*Xz2Z(>4>9)I6VXwZ54vwGFU8w-R<iAZJA0mN^DSRvbrl1RhsQP29foQJeVzy;3Ud zoF;S}ciq=<&UMeOzjDQ2Ooc}ARFP&^lS{kjUYBOi!>+_VPq`9hL&P}8%nik@)PF(X zgWoG1TB<dbaaP4npjAomCd5@+s>{R6G)EWv2rCjha10BcHfC)7J=Cso&@fKQ0wQvD z^jft!O}t{<ln=v>3`&T^3`?2_gK{wx^>K03%S9@5H&PqY?64#sA0q%9A%3WDX-?RV z{g6H5;&pG+b&aw0*WfjZQHTQ}|78e*6`yu|M(`2R@%e@ztb2z0L<UkjVK2d@LFzWV z85w$b7-Z)|riL~=5T)ipMG=Rgr33{6!90e-;xI?_8M2UuWRw3idQrvG5I6bJ6CLGm z6M&XsfR5V&Gq==PR#J1P8{!*4p%^U`Cb2B*4Mo<}tD%|fW9_(a_F4wQHII3Ze5~rP zdEj|}!r|c!utE!)_aPJo{xnA>`m~Y8BLFBBXeZ!WfccgIBTC+f3aliv55Ui&w&NVY zlyl9rIpmJ8q&cxU(}0G}A$JGa@7R_1Nu!n>B+3B9VNAk-ieO0OpW$ZyevTF(KZ=S* zOHF9X{=G~XFj-->z!9Y&@n^!*$JqO_v8!%hl_*=Pu=#Rp$c=-2Gm({=oBjFB)P#Sh zA$_Wu`r9kC1fOQ6?ux>?y_vc;3hPtM)ZIjgVKa3RT)dynOnniUw=+|@A!2oDI%eRL z?$YdPbltUU6F&Q0al3ww&nbL{TyeYO@%bh`75Hp)#a;dxjFI6Yjm$>w{V%h2`CR_f ztzBA6Wo4tR-Ix`ArSc|Ax14Hyf~8v-f#1T?tpW6wmTr_COAby0OkU%rJRBA>n#O{s z^t77+GT+*`#Yz^IwnsKap@<M)>H~E`Pl73n^G64y7mSTaK=ItN9B`D)us-}`L;djI zi0Zk;3I+aV?FznCn6_kUt|m;`w*3@S^SLNY=(?X|YEF$ph01`TlBI^5Tbr5y7sC=G zk50tcl$>BueZKYFn&g5cxS6a;E==ay?4uIbp>M^*+nBQ(7FsV^Xg?0h>MN`#*zSsL z2=i>KQVuH<4i(kR1kY`ZRLH~`SIkWC_Od8|Voj1a6V~KUxiu-aN!SBt-_^J~wI&}_ z$8@tb8K;77wkA&n<Qdv;wk8j#pgXW8g`E!y!&OC^;a}qOYkd9)t>Zp?pndFKsv0L> zIPe*b&Ux}sB1UJLTA&)8UsDTIqjQQ{@Cioe`pdF<BgPn=%hXcE=v?yuq0yNpk5N{( zV~tL$0=kvasf&fh7@dJjG9`Rwqw`HvP;6rIZQafe<Q682!Tl5q^MzRCPqr{;D8p8! z``^RDtOKw2$Gh?U*(^*bK+Y?{qyP1WV8gI{LShWT7nH(V8G?_huv-{{_o%S2At>y; zPuSh+x^MUEu6uT0a>ZX7gKP6+Rg3syn_PigOgGqx9u;)6o%l_FPz6>>jGg$`Q8fU* zt(^$%TG4=EF%}{O1{;wpqudy@cwb2p+=<ZH6(sK~R(dY9sv2t^0)_v5Ov-<{Aa8K2 zN%=jsG{&U-mRcHPBQ8`+|KHh&58q@XvfJ5+FWzJ$J`6u@*v2S<^Xf($QOLN#NQ@YW zeW{(PZ>OH1pxR;+YcjxwLl_KUVlwAoK<TA5Jjzy>4XZ^mvAi4!?(VGYYs+$c=5(LA z4gUy<tE2&A2C<b)9$p&@rL(+wq+S)yV}|u?=0-9?kHHM}&8+jyJb-`ptcg4V-_lES zOx0HQJUJWjM|3zxwyws~@*ItaXfW4<-vD<YJ~0+NN_IhX+q#XadkjGgbkjAYV+9s% zCd}PF(wgev0J=_bjuF<i{n{(ptPA=R-N5I{jBu@wURyRxn}tx@YeTY-aP~nVdJaAa zapc;v+1f0`*Oo>=&;_5P$oOcwTJMP{pq@QPvHB4J<(gBXfM5;R!*LX0=OaSL8bm@i z!Wj8G*Iga^@%gzcv7^_Oxa&<ACq4N5#--VP626Rk5Ygtr)Gs}6VTO(90j|1&K%v~Y zln~u8Fy?Kf(f4t0`(p~u9E3|Ey+@iMbM!712SPIjC)^NxQI~$Jo+fY8nBdW|yF-&% zf&&>31%YZA#-M#);m~+CM;9`(`=M+G@&kEFRWYCf^&t~;Az*JG&JSd$&|wv7ASm)S z>_c$Ls?Z_s9vMr^au{1@kU8zS&W_3S#AwbxNyeOqZQ>P2;5oI<Km;;m69bOG*Hwt0 zJqwj|Kq@+bIs2t~2M|=ef+slE0(c_J9VD72B0T>yoY1g=4&Tc9?ia@+!Dy4@u=1$0 znPtqYGPEgSWo=Fk)<QMa=P~no3LZz2Nnn*wK1n`8$=smNoX4DIW@rPw+s#Dsi^=ps zHVMXY+h861G^l(%l0q^>`*(|AU4Rt+Y3IqHp_B|#_;19M17dJ#!1VcOFpNp2&yA=& z{s&C>Ezd+@a^i{YJlrU(gxyi7I0?htMWf@98}ijea#d6xjeSUsT*3w8+sMrw?uQIM zM&=IrZA`f~CsKtFv;@N%gMSC^=?n3;GhG+rD5ItwhX4dR1m|xc4c(L2bhcymR809N znCn*}<uunm5D^;2p-5B!_I4x<s0|?#C-DA2xTQ>}WH<{q1kc)e@N8HKo|S`GD0nu& zWGAW;Jo8iVY(Ng4`Q_l*04TnlcIqFL9_#}YA?t;K3-h&|A7^1_ys-PCYGiz+O~v#R zCPHEZm~T6ySX!|P;*Ipc{^cNwrF~Nc@mk$f1JV5Uv`js+OHPC)k*`ebu^|pK26wO6 z&Lf=d4C_Nk1{DcrcehPE9Y#XP4U6$G3{lD1iLf38_nbYF^AOBS$$k)n<Dob|LUBCg zX79}p{Bys|Rm4sTsGW8MexMc{rWjmLL1435aEM}X-T8raY5}#FBR7f2+dgJLKpcQ? zUf^A&*}crZPc8)uds{8-;4#_YAkq*?z_c>wDCkD(Z1)~XlAJAk9<&l5h|vrtw(tdL zL3m8#o`^^9jWITa`=~GuP<xAaHAUdKUmOuQG{23ZNeZnkRp|@7`)Bf4fKMilOr{jf z{ee>MY~jINg-~(Sq$mK6nnI|URb8Ydgwu9IilRMku~0w^LU4$O({{+=v`k>rc%saj zz8Ji1O5kit1Tk#W#A5DHqGrE87j80BHE3cn(IyX>{R=SpA;je5qoc&j#(2DJRE?Jn zQ@o6}Wta!cj94YG2!%0#KAkPmVX`g6BySNW+ae)yWp8C-n-U`<zTM9w3%7`oIa_&v zY!MPd{qZm2`}_(2q;g!*ImO5@955}oUR$E0V_-2jZakTc5!>;Z-wta;Eeih{2`=E) z%?Kzo66P9-gt_)bhq(?Yff%i)Q`>Yn9Oh~yHe%l=hq+eK1ERK0@<r_aJ&cTxUH9zC za>ZXRfU9yoJ})A7;=3xF`0Ex*q7z4A;$VVbJ|bFbhzG&`<2P~%Y#&;0ihxnC1%WOV z0J;N!!e2Ckg1}xC0EWJohrb?{Tg4+Wqz%m3A;-S%R?9o6d>wP{l>=Yzq6HumQNR`7 zp$5K=^5PB@pB=J!Hc)ds>NR5XtYh{LdVr#Cy7nJF^E#i|frVFAodRE<)k^WxQL*n; z)*GBo4Sd-*C{Zm6fKhkRQ7`*C1xV2^-^^d~scLzo&o}dBIUdO|cttG_(sf;mlbS1m zkBAqk-BN<&(y_Y`=As@P0rxxd%FofWLgdWwz*>Ib1+~;bF+w#QIa4i#N)BC<H|q#I zB$uM;IcCX~9220jpbwtc*v<n~?Mi?O5syuOCJ5Y#?L0t*h==(jDjD<g7#{dNvNI8& zLOANk7y+)U$&b*Bwp<JAMOa8~Sl~+0r}f=qABHs~hm~^aDAqAm5)mun@u*}8N*7v# zx&Vo-vz_s6_%+o*VnuK}9Ttd7uC{ZZE@ox#gQDc~aU2pQIPiK^@n`u-WLjjew@Bil z&`M&t!wgdAq+~ygBn?L5C}dCVM~(*(*<l9vFqC5)<zb{51i*THP&Sdg*P}hfGVA(v zE&UVxlNKSx`}_%Rl}HI$-eWrNN7}|?<ggYy4Lr323p2cS?>Mwt@!%@*FO&Z|VBGWy zR*L(tnYfoaKNzGGP-4Zm&{2A6xTDN@kcPW2=q5~YlnfTJ7hDiihah!=b?k%XA|41n z!4XD~Z9=CR;dCU#_Rs=B&|U$9VP}FLa=M1<h*TsU5*B?1@<nt&Yv{NN<6@#K@$yWt zhcwrhWTV11SK9^t+4Y_lv3YHdj{L_^`p)?bc|HR}Y9?El#1>lEB4)A8Px3Yy1kc?p zG40e^5|LAEr$YC!L{{Hodn@e^YZGnfZKs+~G{vQ!;E3@^0hpi6<|iX_^`7Pv?nLV1 zl(*~SP$D}OO5hzPvvbVTZJVDgJ%l9Ch2B-kg69EW(p*-jXN%4U0Fz$OvBlji1%dC- z<57^hWJHnKD!pydH5F}svM*_&Qd4W;bxqzTli=1$Imr|p6nhvFwvezy`M-8VX-8m8 z@Z-_Tpld0K!Ib@bkOM}&;yxS%K#&uR6Vk*>$FS!HnT&X}_Gw-Uszj7gHXG*SY=zD7 zbx%{4s|!i$sr{iz)tW+A;1Ad7%p0=UoaD6mhQ<)jh2=^3-tL1+s;grvnFmnvMTE<w zqON3orW0xLbLceq=Jnzv9Sjz7`2x)Ah>sw0t33m%at=$dz-7WZ6nu!I3^Rl$ZW-AH z6F5W^b~t!}C`?g^hM*9kKNw1Oesbt21^03UkmLaPE|hM_Jna!+A>R}x4-Ofyx`S1O zg;)xuU+5@xMW!(1#q`py=Yq`o6cXu_GLsqpdze48njJ;T45<T|`sNd!d$H-BUhJpj z>0xyS$#XjNW#7!XY>j^0jXh5(v0VdvFkSD{&1Loaf%0P`gNu8-O}&C=%AnYDE`EB7 z8hS#8>njiV@-(6Q`o-RXrk+93q{O7^wJ6R?TQI%xHP*!z_t`R&C2e!32V~NRbw|Fh z!w~!~PL+2JNb^zZY5_>|C}^&alV%@#oN_Wy=;>pPM@OVr^|*{muNp%0SbefmVU3=s z71d;N<y99XW7I^koY4EU4@fUiJA>IrM`%SBU|#71<#-VL2IrF*f~i979uNjC-X;rC zbuOoBih=pV#0#okuTu3888lH;ohef_XYDdY8_B4+G@!aBACn23tI~2R!dWgRK->Y9 zxL=PZZY&JFgR;Im86-{OjVB)T9Ty>BN1j32poG%{cAa5G&LC(1Q;Ee)qIzT%JCcc7 zVfYTSNzljz#JC|T;Dky&fp`^Q$lHcRY~peO>0#u~;c@}|olp)F3iQP>ndY2e`eT4c zEJ}(B9-?D28vHtEpE7?v#I?+W*kQcNKrhlT;<E>DAnF4k>fl>6R3h#J#8Mq#sdI70 z`dOylmlFszMbm7*Otbqq&315_-3xz4ifxAE*@xX5DAf-x?(jD46FhODXZpo`15F)+ zi+2o)_#ci0NyQx`#bA4h0S+2aKr6v@0D^b~Xei6uWdYq9Ti1Yx(VR0awoH>P*I?Wa z!>wC`xLYO?rOlB-=V4855>Jviz?=uLpK6lCgJ^*#s~jTPsg#2YURLM@?17S4zyS{{ z1cHTDl!F$O+)5_1dFw5TdL=ba2X*xGZ~wGaco~XbumM#Zf&K<pBFjjEPefLn=54k> zOKc``>gV5b1;i7ahx;>=&Yu_%PY*6W&DD`^o-YG+<UNq2x5+HH3z^+aRF*NH<xcN< z4>IP27L08h)&stAY@W0^StX@yEY~Wvq|jsTRH<bqXOf)|<XsoEVLg7Eq)F}f{hWpq z%mRVpWDvJ&gDxbATgZz9d&D_}R7=T@l)cV#+1t$L;u|qVdC!RPd=;)B`861Tx0_*q zsQylVbp+UHt^$Ujj+>w$gDB;w4_Cp_9oGpZo|4u7$U0g+vD4qWEgkQsA^%UdXQrw- ze}iJ*01{-K-AMjB|NcO=b#NzlL)d$~t1TKNmESzb*I)h`%x&))s|M`g5n;H}l`!1s zO1M;psKpj&3lm-1%X4sD>eB70b$#jb4{-kr7#ty$ZKO88L#t=+Jhx#xjVgKtUN?UG zr+mqg1x$<}39blaB`N7L5;w_kh<RohWFjWdv&ST!fyb^5ifsd8i+|D<OnY$We9&pN zF#g6OBG@<RsSvFd1oVHR6*MEK*Sp$^_ZOD(qu%44h5L(ieyK}CeznYV=#?!!oGrYR z9J-*wEO;E&q1=#<VhWUFsMDc%lijHLr&FGu0y^*{F(36TA+?JqrAhWJ!Pn4XunAw# zb%;q1rYDCcqM^Zrf$Vpa2X{J9VUP#x2f2E!9`>1xr=$@TZKX+3&aT`#-*lw|zV*R} zsE;W$Grm|vh4NB~TY_<F*XS~ny0-JK&wWDIkNpK*|B%-3=3ZO>vzOL<^U{XCrgq$- zPPbJV`BpN+ly%!m*3>x92=)HF2DesYYbV&kad88dMi}I_STtSYWUkQ<@;QYPWbok5 zRlLE-o)?FvC=I{?AZKGk5=uP(*4wlJu5cv3uH>vInW%|!v!*l0eCX41iYXWnGn|xk z=j1$FDf^tRS~LDeBMtTq>J1zV4!fMIoPKX4o(Y_IO7vOY<1oKF(~1qo)_;PP##v=p z!9?00W+?pYY5DIX{zN7GPfiKkr{t7DDa1*zvWyxC7kVLtJD4f*bApTGBofC%k{u%0 zPpEc-gb9(Lw$OL3Udov&H&Nv@aDR734Q9aeA|@AUI==3*48Mfykn8^4X|DS({Rnvx zeXc38vGF7vvl+>}H7K{xI&sF5DHg-W#1%-rca>f+HvbmMBb+$`G`Jvz)E(o7Zp?=v zI}z_QK{x9Rdxk@9hOzc_{Vtw)EH*zYFn9efj;)-pJ<Apwx_+l+YfQeRe&5XVQscMH zKw)dlfYS5fZ*QYE>*2$xH)}jt91EMl3g-LF?@9+>OQNHO68_A#Zvd*a<F$5_rhB_! z7WAcMni@A$V__^TXC}U3R^UxA`<R>w2m=>B3<wiux3IZr^KEIvnW<ofsaJz<q7k2N zrL2hgbl>(iu1C0)h{@tJujKw|+<ceKYm>#|T<+ra&0gu7{R{4-MkwfK++7WKV&ZWw zK1jhL$F_wP9fBi4@p1qAF|w??5rK1#(r}<YEih~StWa;emt3`S4f7#hfifrcHoWWd zCTg*_U=ff_A&zL@A}0+`!}1yahtKdGZ{tR+R}IU9Cf^%+o;5+q8?rTZ8}~OIrU}fo zAjucwFWQ{KdTjO{?XP&o79~67;gu|VCq3p_pqhp5fdScc$Yww7J))D0Uh$AFJuOR* zgd-SaVsBcOq4E2{zoA`vhvCf#cxvBa>nR`1XLg|nZzJB&_EfV%9Td&b0vd=jJP^Z5 zRzL$We1{cn{FH$l<d$sHL3tou@7+aXIVg|iQe-Tz&%rvTfnZw6>cfcO@fF<FFxy$W z8SZCtcH-p&5ERnW4v<pG514l~M)?4gF1(ODA1@@&Du8V+`!pe@!Q#08nkU}o0*=;T zsO8QI-&xeWZ4>fk^9cS9MSftIrQ`i!`9Y#p(Y~Xu%VuoQMAdEj1w!Qr-p0)s$^->4 z2Ti5bnHqmgM=(=OktG$=IRc6p#Q+A>VZ!k-ph!X-$6_~_0~}g-jRT=7?;4BXfzY`^ z;@ABE&H|(;a?tH~L05zW`^ixvQ4>$ve$=J!2qHn-<VxBz+x5Vn2A641tLxr9KX4iL zyy?1o&r#PTfnILEo(4Yw3HM@T!WVOk2k&@Vj%OH%p~JRB7enX*OeCEAjz~6VTO{k@ zS_j*Tk@XZBjUL$uv^`~-aBL#fq9|r5<e#$p!x_D32eU;-hMcrs&jOV*4ZM_s(!t^s z^fX>KbG$C4@-W6$t&1I$8GH5+?b%zZg-#I*aUXc9qG!&*Qm1{()c7tGX@#xBsPcBN zi^S<YX0{ln&?q8al;$YvrMl^yZxX|xqeiKOdfdpbs%K2)v$s|q<4iiY2DmVVa+CSc z;Ej`Cq#j&+g*RfQ?~H6nhHF(h4&NNS^4%xTgjlnpt3knP?l*482LSsnlIO{JIye!J zyiqH2)WG<M<^czld`5XlPJ2dvjUKiY1?D=*Shb&4mxAOCLPecEIml;U7yJ?JF4-4k z#UY}HuQ=^VqH!(w1<RWcb^&I})|z~VGg9Mvvr=R@!`7Om!|ORq2V&D9HW%mcIkN_@ zhuJ$RB=<Frx(@Z&Gr;5wK5xFye1_TAF^MzyR?gr<Uj`=7j&I;dJVwV6k8j{&feO;S z;yOry!;k{T);tpE2*PE}Ov7t&n?l4K@<<r;Ad{Z^G?Wv^=Rw2Io3Dz4PAN+-?*bhb z=197ksC%L2`U_n0c_LEnRY{f1W3W}3RM$6MCk?gO^WbrD6#F7n{*HE0J_+G;AG|q^ zzrn?D2u03LG09X)vk1MwJvTh5wpf-FEYAS8ZMzpt&3i<P?NG>8%Hm3a10wylua)LQ z!Rb@Emm&H!hqeDZ3@PR#8mJh?pvFCcanEq2u(Md`nC`N4G`Q~Xc+EAXW4lW~{Le*k z9bK-89m7c0e!-=`*n}6_nQP+iUm;II<Ff2|$n}LikGQ5>&cci6`L2n3ie36Wm0&C1 z1N@ZBxaXp4(w>k@&$W@UXLOLoIIFP~uB;85)#Oy5A3TZV7-P8#%vxmaTD_~Ls&7dX zHIETBga6Odn`j5qtu|;$SQGzTpDxR%^M?JX(mXE*^!RicKHYlSfVoL*t_AXcs?anm z(p7<(WyhHu>cN^?P&tK0izsMh%Wxi3JA-?mDv@VTeMy)4Poh`Vvs<R7H+R1J6amj+ zfZ9`0PTgeoJrWn*Mg}oqaH!Oz4<$zKqc_XA>5m|3Wt#>D7Y~ekhQ>VumEH0h64{37 z3uYJwnT(())~HQcL7ZmzslcT8jZH(>e1wktY_6HVV=KX1Pt7E=*Z9a*VPN2J2XPos z53+TB_zu!jDN`7zB0~@2{J;|r$w@L)z9Shb-$lt#zPDe+&?5^j=Z_!Y)R4rT^%gZ{ zLt$KC*#~$^5g0c%abHxv!3W+|Tzz{xbT>Kc=UV3S80^^#l5;OGIrJW?k`so|kF3yn z>rmm7m70prBnM4FO600O6a>55$!UZ1Yv%!5oFwibe0sBI8^=q=JTWk+gWvzTq7H81 z7|GxkXa_vJMFq6+K2rqGg9JjgT)e%XgCIcU<>h@+CS)5FVm*HoNX@$^za&=!Wd*Q; zy{Zcpvxh>@vEQ(xHkZzpfT#*ab^uBV+`hWkD3WX6tD#72I|hP?puIIe@RP$}kH2DP zZT2>sa|^g6vKkFqaAB-nilp0|mG*+Zao@9PuNoSE0PP-~RHKs@Z{JDFx%j$l1aHL_ zPNF>exL4!cfan(1r2{>0C<x4^UVp<**_>@QJ9?#eLWTvfl)J%F?gxAMN8BHFP24rf zHF?(*mw8tzSWGrpOaaP{xxTpT1J{Fl?t?GnE%-m)p$N)ejb<#%$p??0I@rewF!+sp z@ZaNu-%KQvqYz$k?0M>eajKlBD-gruo{@3SmC9e=>O9d4z}z^9zrpY$+m16F3(tHY zwvOM$k$(cn+Z|9M2?&q#U#?JD1YYHbCsPXrb%ZGJdhq|y8HIuvNhcy7*A;pTV?BWo zIa!4m@>rBtb&R`Ip>WIbs^b){x(bsr^aw=>5ph0-5S8*87`^kQDx8eJ6sA7SVb7b5 z`=2+Zeb5LI9SAFOSgKK^Z{c@V*1k@w7Wq{bZt>F(?I=14FcA-d9tUqV9Dz?j3e!wf zjj&iXl6QVp=$ML(yV=-gJGOZtwj8hb>`KNfKu_TF9PU@+v&|JJw2#JN7x+(dT3<;N ztXB8SPfshKZgp4UVqKNOzh}_*YJR_(?l~TQnn|u<mC>fl7}Kq*2nA2_Wrb&XS?%(= z2BjK0K*ch(=BL)JuV|>P@wlsMSI8|STCG-;Me5`E6Z@}|=Tk@XnQp~sUMgKt9vKZ) zr;^X!V1v7&uAyp8#naQ4$n8bVjasu>>*}K?D3|e-yv-7o$wMroA=1*Se@&5x@U3#g zFZja$BYZ`z@-J|eTdP)Br!BEIBnq_7R_t5t5`5zkKdmMI+}1aMLt9c);jXa0RE6JE zt0-MAw^LEy@W>3SyS8?j(ui1JUt4eG_3%rJyr)O4MU@qNAuH;s@u(d_O*}5IU0GpW zIIY|^W3jcW!CG0hv=W%^%F-413fH``D#lIF+WM-cRVzwstn@2%^3bTQ#fkRX@~S1P tIZjy}e$B1iQ&wTEE5$FrVjA_2()jT!bJ1g07Dk?Q)WQ(wU?6(o{{l75onin0 diff --git a/3rd/Imaging/Extras/Extensions/J2KObjects/tgt.obj b/3rd/Imaging/Extras/Extensions/J2KObjects/tgt.obj deleted file mode 100644 index 3396853cb6f8446cb95371190b40a71f6dbc0051..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3615 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/adler32.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/adler32.obj deleted file mode 100644 index 4ea3e7625bc4e3a1c07577ee291db9eb7c301387..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 726 zcmZoLV9;~6ig652EJ{@ft}HG|%`J}c$xL!d%_+#pjEMp=W2$n1L}E%#YLT&#UNS?6 zFarYvzf*ouPGVk)g0r@^f~lS<Lx(v7!wXW);%hF{XXr3tV0d}EFGXL6D2G%f=jWyA zWiWIY1GS|!73ymfrw!-{kS;TzE|9e(`<fZ3kztw!18aPUYeWc(v%iZgknQ3a;>ZFb z*j(I${6hm+;+=wnnSq#L20Oz_3r0pJ1~7|(frS;uV&`CBn8n7x_MiDb6T<{P1_nlU zXy^h1mSKSnBO?PtX!o1ou<&kIj_y*P?jPMZ4!##?eEk1E14H9;5ZU^zlxqi28N*99 zAlV%%(0Yl#?F*3K?JLmubAu=YLosW&tH5j49U!)*t3dM)0sfwOKn2E^j8Arnb@?$e z-!i_${G0h^R~QqJx&;*VV+Qe!FLi~nz(iPKB5W`bc9;kUOoS6A!UYrIhKcaNM0jB$ zd@vDykVx|}0p{P$FTk$rP5S@;f9rt~9-srnm~Xi;|Mn>TvhyR*v)zY{FMa>mc^Sev j4(413`mXf=e>)FQQ}^+M4+OXm$Hzs-9%kqU1~>x%-Bbno diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/compress.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/compress.obj deleted file mode 100644 index e2b153ee2f4f166afb3dcd7af7ec19ebf07caa3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 763 zcmZoLWYBlEig652EJ{@ft}HG|%`J}c$xL!d%_+#pjEMp=W2$n1L~?#^K~ZXPv0gGm zhcE*J1HV&#QBGoBih{GYwt}giDMN<^1H%iF4co)>T#uo{gn{AZ?Y<O!9ip64m7JfK zrkBCcVGPuk)>NpkO`JBMH$b|~fx1A}lJ0M2piYKq8Vs!QA+8Z2EYAKeu0XbnV~8UQ zh+uPZ5AqKUV2O7M4rT^oh8gS(D<3j2GBJQz91JY15EcUiI|l>9EH(zV|IGiH7<yC~ zcv4c+auQ2YJ@Yb4;u+YXJO(Z(!!<93fnkCG0|O%`EFO%2alkNvA1K5D6IuZh5dn(u z!bF_%OY>4r0EHJkWng4r2<?8;eB?xMSa&H;x2r&>>xu4Ak<QRF-M$>1zE`@%x({`_ z-mtz<!oK78|NsAA7aCvc41HmIveWmC@qtd)4_Ou&AUnH5C4zc=PXxXIahi_^bl+&b zUBc3R__bpeOK<3jAgDM;_l@S?j3tu2t|tP(LXoYvOQ9x<162!mhu-NFgBujteWUwu zTy*!-*uxVh0Nt7OzuQ$LpgU9`sN0t(u-la*;DsH~QO!q0fC_-}K#}eX2Ve0pUpV-J zkNHCLA@1%&v4<JviZVQL3}IU07sj|GEsSYNWf=34>0!(a3wRiSv0$iYq-O~B1CYZ2 E05aqcjQ{`u diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/crc32.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/crc32.obj deleted file mode 100644 index 25d86be35fde37b99bfbc39937ab3eb6487cece9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11970 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/deflate.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/deflate.obj deleted file mode 100644 index 25bbf9db63a589c0f8d26e89af16d5fbee7b8571..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8912 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inffast.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inffast.obj deleted file mode 100644 index cfaf0b61d7597123f8968e6a92bfc155c6f823bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2709 zcmbVMUrbw77(e|3Yk;LVT|%NEUGM>RCuIUtR}<+!2bD8w=~XjZNog;m@zQGVEk>T) zI!rGo8u#GhpO_F|j1T%Kap?mEBCI8*gvOLXl;Bi4`Y_FcY(eXHZd(={I_Sea{q>yl z`+mRko$q|_w4i45X_xV3Pl(g?zAcE{kl^a}_ggsrjX}Tb96;9y4}(82FyIlyW-p39 zj1bbAf+5}$@afD9qib(&N71JcT0dy4&Cj3Eqv$DwvI*{3^TCV^7Kk5LHtP3H<UJzS z3`Fpny>q!ruix*{#Sq5{lzAGMsPVbRCxK~q^qg@RvF`b<Zfmd0)Z^$jp0&8lCbp~F zVs*5;y3U%rS&P-hg+hTKB^!$5)&r0Q&J*$umdzG@aCwydbWywI0NO*`5T!m-q@Fwg zwT};a%QX#D4=>+SS;~SKDpwh({=j+4F6W;60%4vno9yET<O+MXnC-TMWLpq@z%T#U zC3YK#FTd~8p8)X(_k<B|Fd&Pz0&U>pn|fw{v|>q8G4eIPU$L<0m$OUT1#KMre)Xlk zr2-<l(ugYhoYq&IYIBdp3fN+F8r5{Dw48DDuy%Eyskc`JANuGJ`f^IGP$C)Gk-DOQ z5IUqm=#xrRnOEhN=mY47iW=yTw7c|CG3bwIT&-3h#FAWOCf55Bv1*9@F^SzKSVI(@ zl68x)8UmwD9m!Ux<|KTZPT(41ssYeRGQ?5KBre=kKoDk0m6F`IBsNDNfK4aibs0P^ z;Ttk&l<=wyPDpq~1}zfK$e>NaX&G1~oRUGOgy&_@eHCJ(#WkD6&dHGAZPI0zCuRtn zj@;D>$MfKkM%dDRb7XN%!Db@Xv}VsqLKWv45`;~WnlTAawl0sk<0QE_lxcFO>7U8b z<#2V!7&{fM&E_Dho71)0OIHABC-9VnW09Y=qs!tckTzT&KDxI^vSb?M8Wt36tRzsT z;TdXp{=W>%4ksW@+KKQK*eh5&xwkc(HY`2JHn_GmER;N}{vhlvl3}hJe$+-PL56(K zB*_wCZ$JX-pj2j!b+ne?x@MJ+0>~!lCU(U}@apKbu#Vt$CaGE=IA&N9Mw;9)Q^yNq zRZ&g&Pm*GO*cgOu;K>ZzRCtw1GVayVX1r@Ny8=6H#2qsvg;wHT-L*&~)x-KdrP_b5 zgMr8$<#4^JW30*))$EK>O=KvhDy+V>2EU`%w3mK|gLIgvO?g3~efOur%n_)IG(9dT z?kmz4_eJ{fUZgRAo6{ZP2C}<mXtB{O%#%khOYCH}^6z{ep4_aduAXY+?O6p)^+x~y zkyAx--Cz0q=Cn?%manLq@{Sko4VoL=6#DEi`qkuA{`M7ocb!T!{vA>vb@4hkjuH%w z;I<(lR1=&t#I+Yc-KK8R@tZ0MY8%Iz=!RH)P1VGvi;px7FZ37-j}7v-Wt6Jk>r?=i zY&AQ<4inl=wwOdDUa|2|VVX(2_$~A=bdG_7huvyfP&iE39Fw{*Mf=PKM94Amt8&jt zLCcctwX`Q#Gm^1|whWw>Y;CW-N`7%qqj4vKm+KD<dw9Q3=kp7qC*b9DVlb#1@Pu^z h9`Eb-uX=+%ZfBPFi(JUV>v=A4UL4fPYluKl^bdsI_Xq$0 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inflate.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inflate.obj deleted file mode 100644 index 6b1536110c7d32c7c65d76d90761fcbcf51dc03b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11402 zcmbVS3tW`fmA~`;K$KB2!35(NF~JThib;vsme-7k%rHD=e8d+rLqK_$nZZ|TDj7-m zxFI#|_PJ}DrqMLrrrYhdjmd5+pzWyH%_6$3(Zm8Fk#VvuiL8R5nf;&d`v%lXqW=8- zz2CX_o_p>+=iGD8y~Ca~Ha~aC+U%9(UXQ7Cr_b-H^{p+e-jwI5*;-Y-b`3t)?yA9m z)peCM<$lln3f4T8F&3Xw@2x4XbDMI_X46CSA7ag4WUT*o$ND&C%>s!twEtT><}J9@ ziBwka@VMt!vF3*v3!U)Hnt#hns4VySqm19vr!2T-MrrMkh*gG$pO0N|%X9U6Jsuy4 zTmnv(@|BcDSf!(+Xjw_N&179(XenKrQ&duzZO>bqo8w$wm}e<@Xzg-)ZlN>Jvex7E z*3}bprox<l8_YgWxwoR~j=BAAn4P#Y6xnIFA-mR7ORSG5tP5|0bwf>k#hp$XtmQSH zJC^M8d+$^-SgY$EBknt~^M<;HnwmRic6%x%4_m5ed-3gP+vj(K|IU{k<z5Wo=bm#f zNQLmvk0!e+>gyz->0qmT>hT5UTVqpPl7#V}*W9YG27k4rT?!Wza&B+eBjRbm$iAJz zbQ{VntID*wMR^u{=Vg~=Yw16I-m;P+r$f6Tr?gZ9u<sh!D?gvEQZwo6*;uVk{$k7^ zF!p^t(?>KBHG6g$Gwg!L!fly;S4Aa41=C~eRBYYJbQRu;^hL~2?ym88@i9>ez#IJK zn`%5PE=p2FV{9K{vMO3v;_-P<huQ?xMj4maRr?oh*htmacBbkL87kCHLT7_A>|RWL z-(*z8DixMG_nB#^yBBo{N?obPpI2Ssudc5v_wG!&3$0VoIw9J+v#z4>Zd3v)<299z z`szA=TH+1ebL+S6bffYGtrnAU@(;OFXzKDCcurDNTZ7@yr;$ix-4Rgf$Hn|au^>S# z5b#-$nBFBC0f&|v;^@mnU&-{9Mqi6t_oYDpqQfmZ@<m5pdfU1q7{AoTEk@oD$JYr> zZT^H7)-vrNjI*SpLEyH8z;K2?_Rv)b4gClzYdY5uD@`HvO;8xRG?A|`H63q=3+9?o z!_wQt+!S7#+|<=z2<9eJRn<?Rtj#LEBBeM|Y6={Ulh!eUA;ZODZc@|b-7)E1SI&zL zAv~GC)jq7v4t$y><_o(ufe+#Xp9){q1wM^`@@@yuO>sm@lLJQulA9z=BOEVoO`;X1 zmiBi-HLKS@y6(unefvmn7NdhZ<4QKibDL1yKLzpvM~!He+Js<M9!)NoRTv```3#E= zW;viCrs!oQw+MVy63<P=jMHcZNpHX=>{M?FwK!5rFmj}rmc$1{Uux53D2F<P+VLMR zH9-k?gGs78)h*_lXyPfb#foGa06KRV%^&kzQ|5qowgZFl;y80>2?RR&F#^ND)Hww` z#N6a?4S&J}C76dYulUsb)0OZHUJz$~tC*LjYC21zEaodsm;JL~Re|SAt=9}E`d}QB zSehK3sd^#>CL!U+8g$acIHpCUPosJwIlXPem@WfHJ4;=p4tU6elGvoC<Ng_v7UJNY zQ)%uhXemKz)S^*wlQ`@#s`DmsePC!pgFdK_Bjrd_7i~k*5Ju5CD2*UmMySP_#&>B& z%K%@$SlkUm4q|$ie$jcFPYMjrh=1mB?8r!R>nwz$?@>t7GWHDYb_H<i89NM2H!$`T z5C$q?**^jEVd*8npMj!S#@c`%PGD>{cKmz5E+b>dfx{U7i`c>!fk~KuJi<pkumflW zIKc{CG)$0J6LOPtePZ<8-xP`8`!0sy&XM#s{$}8a(4sCn)vdA&L@Xod;XQxZDyaP> z+&R#AbtY%5VcBLz|0Lsy)&!Wm#Wv9D>}<Ama?1eQ|0CA7txVnbs!P?^=2E}Eu1x*@ zmNNB$t1ivKdBAd)=E96J)rDEW9AGXm4_F911Uv$K3CIR4z;eI_6a!9RHLwmS2RuME zPzyW`Gypq+-9RJI1c*Q@@I3IXGS$l$U0OL*Y1{jSX3NRV>Jn~GD31CfR)mOP8Av}D z)Jr?#eQZ+HSdGww%5TCFp^7;XxWwx-@n8Ezp}kwsbRZyn1izXF_XuVs{tU(o>Jdd) z=m7Y^6zGl*3<+p=3c;MjBV+ANXm76_&<4U<ZW{>n#0T2pPf3}_wkdtjkM&)RzSn3U zs>gIOqL`ERIt7KxmXFj8nn1f+oTMxw^Z-~!4gJG-7}_$D-X$B_Sahma<s3CMW{G7= zOS@*OACHMY`?pBsvUPGdR$&u@*@+V&Q(5I<xk>F$Zm|rs+B%ypolp~$)9i$Xi@7yn zG(eDsyVB2z&VisFhZPHaVv^lZHU8{O<c5>g{)aL8wL`=0ptSaovDwyz>9_YMHd{_@ z*8aUkA<qJN*n5ztxc&3kLE~#fl6QNn!LDXt)B4ws%9!_=G9-;>D3Y85t(MMaWkEu- z4SI8MSHftNB)uKSI&4@6#e7MUom(?ROCNXkWnT4Z#NB<|)`wV@DvfzJxAfse8M#p% zW^}XksVH>y&2?pPdq&go_@<{Ok~I;DXk@{^jv_-H>d2EIU<4zlx3y?vMa!88Rh*Fy zd0SuR@b(^XnEbaO4m|Nq(<MO&b0o+p3(}FG<Dv}{qgkaNZ;3OCHc61>3}U!JTH&Z5 zTVF9c-l!g0m#t4_8{xzg-}DOv?w}t2OM=w?(ow5?2MyfG_CLa2n&i^<J&JJk1n_d1 z`la8xbnicakd=*)wbi9P(CyM5{4($p;IA(2%j<z)G=vD_#Z1_(u{VMs0q@K_8I1}L zjO~{$Bq+)*7-vHV^$7GV^a?tT?vVRw-Z$UB*ddT5?E!&yUMO)6gZ#!Gid2og^sPCD zW@&r3_abN|YEEd5!MOH>^m7zL3eu!4f+GfJ1*JUcbh6oo#DX|F^PGdC!$@bIWkgg_ z|6LTXM0=XJe(@pN$DuaN?lTv|ZE=BNUHslhu`+Je!mRi3H~FbRk0H=&I8{4fJ{!~{ zkz}D?4b!4Ea#)y0y>Gr~4HiwIRV7-rCu;{*VBvvYP2i%+8|ya~_>&6!v%(94diWL# zKj`Xz@e1;-pdN=L3nvEk2sbQDOF}54Q&tXTh{ftaSRG2k9Qctyw}BrspTXotjj$gY z8fQLa1gB(#i-@D7{*USZ%#LWpw2g`hbq+-$qBTQ_(?LA~1(c#}W^Aq1aOKQlc~8@J z8_ew3rsuXnX^-^5z4s>2M4Wxd=|->{hU5TCd%)SJa*j}rXX~458<e*C5Gt|NLu(*a z@vI_z20oc2EBP2EHqN3ZNuCwxnc3K`!igx_S3yO(Kv*ZKerA?vT^p?+^~VP~w4$pl zdZgJ`H4fhgw(U67)&_>|i=Jwm$29Q=m<4;^zA>mrBErJUM@_$I{8_>Dm6!l`ZH!nq z#=jQl+=G2y33FA7dG;zu*95{EZr#XTWtkn`SHsh|UGAy1Nj-yk)+#L7wJ~sYs`tIt zr|F{6`t5!=vS@XS*1Vv#kRnt`tG%$e)#`S%x~eu$Em6{*z|lm}a+=#tv;A{f-+Y9P z6$llH2pz}E)E}gksSiGfEN4lX`T_@jU8a8dl1ndV9dU@xN|Ny0m<ldmrf?v-paP_F zEOZqb<Mu)&56_2F&F<j#Jg#jNE#2u|EzX|Iv%Z-Wp>wco#c)L}#?kZqh!8$p8Q9%x z^c93>P``V|>xWQl>&blEd$z^WgT&xiODCKiiZh>uVk^0`w^A&#R)wlCBWb{f9rA$3 zp`M!xmIg!)f-(Q}cVi-~C~3{hW2>Jjtrk|yvsdDDQFd{MMs)VUkkW2^1zI8TlN+|m z;tM`Uyyiyn>22n-(ZLOY=-}if;UZGdFiyVDT94tg2K-u}V}d+eLm+H`t6|e2+`3l5 z={231C$`N(#6;fLKDy}eJlP@P#AhUz#Rd&n`Xac2eZcJ!ANV(Bo``?u5^}4XIw%Ia z#zE~>kXKT?S=Enf+{7dowVXzjRWyEXRCws=K?FCuyY*?w;qCdYE=SPnptIirk9Q+q zTZ_YWm8MJc$3RC_$!7JnW7<xS`S6voF&AM>Ik*NQdaoA|tMRHDmi0a+of<=8cARve z42lIt=|C9~Dfo&zwb;j^mCh0F?57)QG#STPgG+0i=p3REvW=o;kVc3V>4X>f4lV9o z@}(>E>r1qt8#as!8|Eq6FtUrw8)h;#`c3T|KHOsI-rMGHxNPYjXsGATZqfM;GOo53 z%R4Q$cQwb9t29o%g4rigbLwLJYnJnxPHxRhKh6{OiOz27+#_|)d|MXxB9cPoZdKHx z#>I;5pT+uOkzokH-w-M)T>1}op?nSHTL=|%Tn0H*809+{w(?6DGQA7?vc>tX`7HKp zdK-xN*POi&C%Q7sXQZjq?GA4?EYyW#2dgmoQ6Xg!?Q%s{)D<S;=uk5EgJ>cJb>r$G z+OvXs+#hieWx;Q9<gFHa;}W9t;;yXBv)*^OJ?pwarLrQW%)$iC>oFXzo(N@*>w0ik z{!J|NBC_*wETfpj(k)uZBnW_#NlqxEB4Xsv?tqe@lJlqfHHek@h-GrLgh}2-z|?eP zo{>$mWL!Cto=LS}fli@kS?N9IvzP&CPrBXB9n)UbN0A8GL3Ay>PKkJNyIzUE$H{V? zAAGJ7myRltTa&RfuqxZ2xt+U~W_I|LnS5nzCg%re`{6AQIp-kq`Msqi(bA87Xzrj4 z-o6w;3D?S8jDXC*d=deRTT>8sFy558=wUU1FhhB%n)Yz)*f+-=0m;Zo-(C0uS9lWA z4U9*VAsUU8pPU%YPmpWS`$*qhdqxZP_)zoYtcYbOV(V+b$&x{-d73m^%EUr*@QD`_ z%4lAogTOh|V$W!fl^6!)fD%$sA9}!u-#Y-F(Oj%vVz_A*F6Cl_bDjNC^yyb+<D%TJ zawT$GKf+fYw;JK$_sS6mk2?M4W5w6rw!+iVk<u#kFn2g^cp{+uHz!TX#`@)vbnwA2 z0$4N!$F20Dl7jb2DR_^Rf_Ea;$tie`l!Bi`_^>BPR|M&RST|<SiGOALr?b8_2ov8$ zR&hT<Ljx`!`&_yUm&(*~h)BTRZBy>H(<PUq2d`4@G9rU4BsJaF6!F(9yNVunuD$b{ zyuI9>80ew*iOgfs*x((T!mEFw*r41w@4@&%%V}twg=gRcr&1)GaEP8oLsrzvudGWY zi`?S90Ujqk!QB<Onz(zR9OR*I<jcvj_60}(H$Fs~dX$!B4C<30T$Xs6R!eVk+POA7 zxZ#{IMs59}DjU}oOrc*@kO0f7tcl!3PtwJ*?F(d!-6z`~2Mf-n8*Lm;0weCu^j`V* z&N24tl10;?s|-E6v~kzsLwiu8Il-}{34TqWZ4c4_iy-Ewa_5Ki#4Jw%CtF-#NZT-p zJ5Ngw&z94lK#$yV8gH2Vefc?;-nY;BCvm(u(*;<1q821A<H;Dc+>we!O(@~gJ2gEs zqtd}kQ%aOaXS~EFrMF4%%hI#?O5R}Py9IcJfiI)SdF9FTC0fLWB(4bz#YUe&_o43k z%bbherbl0K_=<$gcE90}<OP*{rLkmX|AmWDQ%wwNMoksYm)?uF&44=NG=HS$;uWdU zBR)=fDZW=49Sxv0$M8a|Bph*~FFBYSM@~2TzN@Tdos>o3)d0hWQ{#WLC@`e<Y11QN z-C^2rnO7P#S>Y*rmN36Iy)7K`J9?cl5AZ)^=VZRUO$Y6J-=uA<=IzS6F~$uX9inIB z1_2M!2E4+J>F5n`^Yuxxt*7wP#eu7WFZK{wE%XCwn;N(}!(SNG%phXLVq9uZRiyFU z#ki8p&0U<{*6JJz$G5CV%W96zY2T721hy;|sNb;Q3(;ftMn@~|aILu;9sT!WP`bXk z@Q^jBSgI1_s<~FJO0TjCycG8qE!5BU&tQF}c&jMJ1*G1kJLm?yz#DjKJ?ql27k-IL zTcTv8S^P;{!V>Ug?dlI-z*SfTP0zlfD<P<%JOPSWy_$ZGkbiNI+|H3i4l21Fye=z= z3xVN@@MFhfI3H<NCmq6)%NCRJcGGhKSf|6!rty_vhYuIwCl~U%<S~sJDN<}tivHNL z48N7Elzy2wBmHJ0#gz{+DJTbzPxe#{@GySTut$HLaPXDzbcuyt;VmN=dRnPmNt;2A z6F(($I0ek>3cva~U9vA7*s$KkKY9Hk(%nl3*2|eScjcKoo4R&ta5HGXs&4O9Yfd$G zNWVUn<{_IfA8R^}#&%8nu)4iRt$DMtU20sB&t2|uIo;B%aLQaWX;-RrVUPMZdWgBH zczTB`u1O*TtUJQ?>)3&BlJT@!9O4`4A}TllBTEo`Y>HtfzPAEtjK#DuqX7|H*a(<F zzkrhZ?*XzvccUFE6;=UwT#4DorW)`^3BnE_19T^wY`~pUr~*<z{{kfj5SoE}&;#Jd z))C5p1U5~05Bz3)`+>!1KL&n0un2A-8T3z3Qvba`9_W7X(|BtE#DtjdvIIjZzP}1A z1$_qVLDDMJ0I8r4p^O8b1qwkAfgcH*Py$SW{2xR9Y<zoxMQA??`S4v~6L3H1mrz1! z!c#yF=sxg6fx;R9M_9~1Kz=U1cL7U4pN4#-yuxPS3!s06lJwaE6o4KCKduad3%HAA zVJTA$>G<9TJdF1LgnYat36;PDpnryv^!+qo1^prTaY+)^1NVXcC&;hB_mjYvLB9j} z_@O|k1LlMN50r3I;W@w#dPK2*G3d!ye?YPS<DeI!y#wRZe9M7ZpkG9Zoh38^*`RyT zPV-p}AVrAzhGPGnpdSI<rP#k3^jy%tL`m}%f#sk-20z);2~1-~L9LSQ-vIg{w4YGy z?*Tmr^iNTezM23F=!@Vd`>z8K8)Lq&*nc<ZFM&R**uNI^JkW2TB!6lJY@n}#pX^UQ zGZpJUqS)UD8g_{JgJOTu>1@ykQBwZ^kPG?)@RR)?1)%4cZ!7kH0(2(mKPvX$0vdiD z^Ba`pPaIeQ`ZD-wJu88`ud)Aj&|gIRTZ;W31N|WApQ9vs&j8Cn{{{S{&kX?fZOji8 z`+p7eS3sXv>|YOh0qEbMB!BukPz3r@>6dji(|&dsXonbbgN=X*Y(GNDfIUDK=pM9_ z8>|8nK|im!!4A+Fpie4pPz5>#^uMAcvo!<xpg#gXxxsj0;JD%jZuCh;|5s2_|GhvS z=n(j6ytP0Q=<g|R@Kw-DLBFlIK@I3s(66J61D*v6K@WqU%sO5e_`Tu=o6zTe^gn=7 z4Lk+pfPNqRWR^9+J)pm(xWO*aOF;jR;s%>Re*yHbQIbAefCA9}2Yzyc@xs7=DQ-}S zJ`bS(t0+m|PXkua{|kO{gZ03Dp!X|o@FeIjgML?WgF4XjLH`!zB;Yx~4*GAO69$f8 ze41}LFbn;Ej8X+O0@<M7Lp#l9H836YH*W|7rxg2FqkS&g{|zP0R|J-Wz65@<=Xhb@ zO~w8m^qGVH|BRCK)dW~Thrv(wUkA(p{f~<McZ2>C=yQtwYeCNg{qHCz0<C}z^e5ma z`;Qj}f{Ohs&}TOKzl@Ul2Y_7A7r;;Ue-yYE^mi2dKLI)u^q&;_Zvkxv{Tj*%00&lp zz5;$)&v;?rzZLsGhCUCX|G%IldCvgLK>ro|q|ay=_@QF|Xc+jjV*h&dS%ChBQN{yb z2Z}&P5C-<C)yM&KDt5O{rJAan%<k2xjFWXbHeILEPSa(x89G&#QKw;vI+Z#>H;X0d zRHiAq7<P|NCETTJWLa2&QKtrfBlxEif8u1Ff%x^)bmhdq(WuiBza~MqkoeQ4;HNq8 z$K9oCm-*RbHiaS!Gq4z@XR%DjCNM3FV;VM*so5l^V)1O@{6+H@vg*2udau`0;Wt%z z%H1BXsiMkLv4u6%ZK<o@UT3PPuifhP_<Z;~BvY-&Usdl0$F}mCYPV^7b)CC@yUAC* z%kx>?qa!K9;}2aQ^O@*xsG{<`6{gy1Uv0U+qH1*PP57&=EhhiYt)9^;pTFMgahv3p z8c*G0{wg2y*VmhB%j<TU<O);0*W|AD`OE7nJSN}H+D-K}zR>|H>fIitpFDx+LN-<V zqx@daR!_Nqlx6&unrgqtTVAt3nTWKY=y=f?TrcH%4k*?=wzeq8IJLCO%5tx1Q#mX% ZW-xcTzg#ibSf!!}*^2N1#t~xK{{!;u9t8jZ diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inftrees.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/inftrees.obj deleted file mode 100644 index 4357da25e08863ae8c9f220302179288a43e411c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2737 zcmbVNZ%kWN6hH5^D;>ffIJU73XALpVb@FE&*`F?vLa!U9Z%p91Mcc6s`UbJUY+o^( z*&^1OzTU9RFJ_u(miPtDqTj61FO=z87Gh9PSwLhNGhi{Ph7h(jtLHw-VvNQCC+~6Z zyXSX*=lssOw{KKJdF_6u?Wo)5F*Tm?E1nL&)6ss??(v>(Yj?hcL+4p9zS=uw#pm(( z%UU439sq=zE}z%k*=njan@v?^RS@0_Ftg&#My|A#LwFCs?45UV%U2jm8-({G61G3P zeHSKiq@n&`gH1F&SLYy&&YJoLhwZT4Sz9C3IqamN%2{`~)*;!6)8q4Xc9kL6ngv@{ z0QP&_zLvICqm@<^lc7;9E%1sJaCdk*7<6A2TDbyfv$v~dwLv4)?e(mh*{}Fk%Z$+W z&QlD%nmRXk2E5)?gIhhapMei#)!w}lwf#yf;#Z&cGI}?Xk6&ml--+b^e@4%?baiT^ z7KF)fzFKa6I9RqN85#Z5`><pIrCn2(9bR^fS9o~w9?>BZ-rWvsnw!Y6CVg$ao#5DR zYqIIt%V0m)P%j<PH`g>a>hOU}Iq>lddX5Kew3E}XSsDT47y;flfFYyH@NlshIKB`s zEU#PfG`Dn}KI3aY)u!O31s96|xcucM#eLH2VV^JS^&Egi=Yn5{E&Yuz9;IS|O47Zg zPmbeqhNOf2JeAVHyF&NxmVPSbSrgp_LUc=TfUlM_c2}P@@mh+KVp`BkuBp;|oGc0m zl!JRAur4Dm2K(<*X)$=0^UqN-k3;J~w}FyHRhxvq4;X`q%<MNP$d?!h^pa0hlAt7^ zZID|NBne*QMzD3bTc<Ikndetocip%UtuRl9#?NUxy^cF&qYk8l_l53XLgVL4C^3fm zm3$#e`sfYwSnwXFXx<`v%W)C`h!btsCH`I#k!djvBxKz-Sv|(H4Ot*4g)1GrC-`on z6s|ngl|VJj)RmCwRyj1TY!ag5GF4n*rc79fPSQY$tm=<fGc*eI1I7`Y;e2|fD7lA< zC8{{AilcEd#C}(j`{QJ^0tY=EqdZnRPKG<R+3?bA2r%R126VcDpK*0g`!|%qKUGR= zdQhpzvVgJWs^XYskV^Ban2M8W=0e5!kz1;3j*4@2syIbOV_jeaPI~Sbu$g?hUobsq z4<IoH)~mN+86sjTLee{8Ve&Ipgt~@gY80X|>(z6)*T@9OsyLZ^ii$(l*!hiA9FFAK z!r}xKM`fzF$tsylGPe_`?<CtaO-ag}&}c@c=yfe#7SYVpWQK|<IysW0;*9PF702kg z3H88xI13F1ZX&WSi%Rm}&4f~cyI9M$G*MUjhc1=mEelLtO44%1fo)6K3vt`<3l$fw zG2yMBFf&X*h#D!$6QX&CR2B@b&g1Ia8<{v{s`MHar<u1wo2Nqk0RwuVfb@EnJ~qX3 zWDHLO%VhXL3dwas)K2=$W7ugzjcy!Qbpsl;@7D)dj$r>A5B-begDg66s`Oh`oTj9R z;$%8p6vlVNH6M0{ITXa42o0Xm1!KC{9c;mAS#@0EXI=L*85Fo0YZQ@EI|i^!OIn8( zl#{4vXi#}_DKTl<I-qQ}46<a%Jf3gt6Rk%O%8Cmg6vFLD6My>>KA++9c@qzpC2Tl7 zB7PkCjbhs3gqnBpzlt&ZeCeM{#Rx3~KBSneRK(=ssaVV?IZJ=@@t5gs*HyS&!R|3r z_9`+}mhCF5G}SKORi?^)`>LMVRZ(FviEiI3CR?l5<1+#1Ko4uc06AcUwU7&sKt2di z2<u@JY=y_66wF`&E7U?Gw16Li@DW^vTfnonhJt@sAtISQnzi+~53{1IZGa^!00-2d z41AV92f6bRw;7&*O0a<&dLRZI*TZo<r{naTfirS>Tme_inYaqBnmh4#_GQLpCdRQ5 ZZ4+8C+GeyZXj{=r&>lmpMgxk1!C#cqv~B<Z diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcapimin.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcapimin.obj deleted file mode 100644 index 1979f24ebab7e4e922ffda7855d03eb23fd0ca6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2721 zcmbtVUuaup6#v?!-DRdUT~f)mg2geYOv<{uqPF|f^d?>Zq-&bnqz$IKOOvn7t@+2j zH;g*P&AUQxKb2xdL=b!^4#5Y(C*MLh41H4f<df{N8j*r9iWK8HH@CIJ3QK%Q@_pYq zzw<li_nq_Q&MTx>=!<!$;|lE*msE{r)L1~C^U-uZCF5!|PZwfod2SJZ7ZdTkoRPEL z39{lMgtQLklyp3s>=e$O>+J3BB`a45*{(BW&%0-P$VxvUztH=kGkh&+QANoq-6^ti z3D6(5eDvbQTF_9LoYfG18Q=qf(>*n5lF2DFF~6`+-}mO(o?7WaUxdF3^rY)**Llc3 z7@D{i@{V^7jRgE+Y;YnJ@Lu=Dgu(Dgz~>M3#zw9Sfw0dX%g_u$U$dY+H9)0wE`eB- z9BEPVXQc&bJWcCnRyFgw>R|?`oHf<12Q6ji<!au2R@E13s9M#Ma;{#<R2o+jsk+fx z((00W5|^@tbQ-Da0w?LbieQ{BY!qzoXKfS-Gz0wqDBD6Kc?Zm9O|zBA!F`*}f}{QQ zH+MT~8f`h7NEec3n<E}ysG9JHo=Y2Q_i-0#lBWDKQ+8p(=ZCe=JLR?GSF`V0Xd)c6 zOM{|lgAe)S82K_~YiK0qiV%C#{^}S<$fwPuxnip{lJ`bQGduw*)rfOZ&dQnuyPUEl zWfm0Tz(-q3QW%-s5;<<};&VAgBQDD~uDn4N>6RjER3T*T6d?^R(@julT%$rRlUJy! z!c$MyI>6X|IHHuW%s-&{AFN4nV0?_m(|~oGShbKhLrPkFE=|>)r>*l)f|@$O`WgW1 z0c@LzHS?4*X3{T%GKV-Vla!+IBvrmb<G*my+>%E3jxtqq@xUE@p0)vJnEfV3ruib9 z<yhFk3QqmcD~4d#PBL3*!0mvXO9LMGt0P9RLu9VXiRj(GQh>7@+N%zDV&p9c#<Saw z6do-SaT^?n{?K9Y#%;%Ug3~&Q@<l`7_(z85;kS%2A76Z59OkzMjN|&IUEj68^#`8J zm?z*c>a>o3=ZgT+Zz7*~z9d{EWany0a3_I9y7Bt#1E`1jxu8iKoqe!AMmhB-Fw z&^L$Kh2<w&^U4Qz06$=Hluf(7IkRtU12(2OtDd;o_x$+=Fsvbm7(oFAx4uiYCVh9l z@Df|cUSVUM{XeR$rkDcks}hQgU4k%`NiJG`$3!h?w@e>5VnnwQ^oZ=aN?WviQ)Ig7 z>x}YG%9okIEf+PHk+-w;$KY!OIgyQV;0anYeHfz#?fOIRUa`>1T%|!b^afZk))3PX z(!Zm8E3$PnXo!neQ(5)4+$(D9a2~)AAx9L#dMcC7X!Qo8mbR17ELiE=ZfF&zV~NYf z!U?PL7oc+Ol)k&5wI5l{H1j)x2OMr_3&xO-c|C@IuiU~vT75nwR>FHwz!3XhFIASe z3ctd=;!Rd{M)F!|nco?N<_>}EW_6Ruyx%JhFmWNaTD5q9`6({E(&T@XBQjeh2nsRL xQvoF{r4CroB6!dPxX5QG$woZVu%Sj8H-3uPHnt=7FU~~l_s1hmgu$eezX91beNzAc diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcapistd.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcapistd.obj deleted file mode 100644 index b6b51c1db76649751e0ff721491bd3b4f8be5816..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2133 zcmbu9PiWIn9LIlIyII-9$}%15p(x^DFr9O#+tjsboO7M)l66|vEo5oBrKD*|QboNe zov`jHh!YV(@GuZ>!cN}m9~|Dqvu9ECAb8Njp#EOkp$CN}9{T$7@;>kTec$}vyM7FM zxxQ5Rf^4cG@rq@uIV%;@W}~WJnAd3UTtS^n>Dp|T{$~}rpjmdhOM%5!0N5VMo4RbI zLtJNPsJE*Z7Eb|u^0;K9?_dZP`vE?yPlWwFZfvQhnK!%UVQ~QIyW8&VJL-nUooR+m z@so%T#`bi($|RRJRV6dGA>ViPK(||Y%$MTFQ64%@cN|9dabavo2#<!&499pe6&Vv^ z;q%cH7fB4qqP)<X8a~g(5>Y;tQ*#tOQAfL7ppu?fC`%)!vNZC|$|5T3s%K@(c0QLE zWkfZ@N!tr885ynSyRW|MBQAE0rLX0^MrNt9smyz(?R33Lycm~^qOMbEPjFhzSQMtG zixvtk@68s9gqb1#AKR|eRD3U<O;=}2$>aBSiiIBSXR9~%x;omLq3Ff5Q|6SXH<T;> zkL%J$v%B8`jnV{val+4yMS1K;!xLdYZJMG(!dN2imm;F*!yi1@0#Cm)OanMQ0Dt2~ zZ%Y8+VG}e}ebolI)deiQnkB1PD442cNwz$zs}{6nHAAx{C7-Je=VZLxO@KSQ0hrbr zV$0_58F-z;ojv%nw%%n^vsKAbWJA{s)w1c^-)QZvDPNY-vMnEG03QEfuuYJ!BAE^l zjxGI6+ik?RHpsGw5|J&(+eOk`-H}}4TNWyIa~8x;RI~ItAd=Rq5KM|>q`f*GNY=*j zu{3~7R)fi&_vPhxIQ4l3o2Ak-Y!@m;X1F}UPEEf;&2e#(6oVVW>OX`@i7rCKQ2$Gl zCCzJL_8LBCt0M7L<9_r(xWLVdy^}a%<+z`Wgvw{p9Tz|oWSP2II@hxB)^6VL7WXF! z7peiBFZ<tE4dh!-<#uAd%&$)hWVB@*XAaU`P=O#xtTWEygkPVTN;=-rdOfhrCVaR5 z&38}bOVOM6)eo4!i;q6S2m8NW+D=;6BJ3_4s(mTKx5P!Ve3tqbXh4{{AH@R9s*~iK W8H^tuZH1LXlg!G{WCIYaSNH|~{HMkM diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jccoefct.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jccoefct.obj deleted file mode 100644 index 505b1a3356d98e0f97e109b2b803d186cfe06f45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3615 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jccolor.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jccolor.obj deleted file mode 100644 index 7e8d7dc02777f69019fef0f9ff3f7613671a4862..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3330 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcdctmgr.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcdctmgr.obj deleted file mode 100644 index 4dc9d104dda93d42dcf28adc3f5efeb6291c12d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3337 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 b=9Kaqnfvgeo%fY{KX?4Vblg)SOfK;|Gtd1G diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jchuff.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jchuff.obj deleted file mode 100644 index fe396b80084dc58b35402e3409a54e4e78faf98b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5176 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcinit.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcinit.obj deleted file mode 100644 index 6a6d0a4b979474e4ef46e167c1e301db1b2cc8de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1970 zcmbtV%WD&15T7*9T71;{wn(rPD}`XKL9L4BWr@b7W|P%m%Cg=4(rnyE*xgw4q7n}! z>!DZ?Q3MYQ>a8kx@E}D6@5Q^<mij-$@7rub#Y=ZRBs<K^Z+<hgGqVq(FrJtw#cr@F z3R8DA9Z6a#Bg`g|SgQy`x>7@PB~h5Il4q3@WI>N`urL4sJL8HfvN9h|jE;t*kti&j z2Uv3zF#qY;5G<SnSVwPiLyl5Hs;a1wibcNuWc$;jr<@dos}f|Lz%O9(OPRxCQ73Ro zQ4v?3>(Ec!8y<5?k9$ktXD~gCTpT%p>8Eqq$z1GO_;NavqDt{>E)$zdmJ;zoI+IN0 zqNVgyB2!4FN)nO?^sEgXa{y&Tg(Fzfazaa5zExTbWkuwgS<|i8<%StU1=;Gh8#E)A zg?8Q(cGV{xRITZ}ptx<BhFF!WxJK)|Jtb}uXXLsl5^7gq9+fo$#;a`&3K{RM4hn;N zhVlPVwv8s_gLpR`?G~rt_iYUeS?%SI4+kBswjgt2owvrE3>&#nj_y+TRC-D0o{fN? z$)|4SeTi%`h2>-{AM=sFKyosdElm5EI7NB!51t3%-52omfF%L={2eJ60(cRCK+D_e zfycjKUzMC=hGQfaUv8Db73-=Z!d_dih>E4WgH&vW{<fM|=4FkQY9dzc??kAnsMf&~ zgY8>Z)Ol9r8J^Q&pzT|$)XQZC$(+Jtzuj%+U%GBkPC@0(LAwTt739qZJG8{Aw{aQs zszB0(#X$g1w-yPfsA+bo`0E3&zk&y#VEm?xnNSs|HKJ^M4>cRhSa`HjKiF0k?Z+k; zThm;6Pdr!kexvV4Y!8kGl;LgdDsCKVF8yqqdTrm0pe-22TWm?+-_dM*ATBF)-}vf= z|1&}7+CDgmf5|B0s;_nZK#?*U8SIN$Zq0mySI5EZqdn#ky2l)*y=H{=nWt&L$<YB* Vq=V)n9Wr0iy{1WT0|So)`~mT%aDxB< diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmainct.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmainct.obj deleted file mode 100644 index e9cbdfe3f757c5af8190dbc921234258ea094364..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1885 zcmbu9-A~g{6u?he8P(J<fkYCCSujK*2@1HVfV$C+4;c*FjgL5NMpvLqw~@9>)M$c^ zhix}AL=7<}8sCg>B)<71AA#^Fulhg?4-)(Xcp$0wj*<9CXVUhb-g|%deB5)+!cFjS zoe|%7R9D>MW5ZMuMkJt4^NKb<rxNM@yfPcn)af`G<8mUZCS|i#hHNbWRQIHGEt-tE zxt12Ur_}@5y8yq-JkssB;)ZM&z`pWHxZGjKEJfE-dg~lyyD|Oh+?&Q5c4+LGnluT1 z2jkwr#Wq_pNu+c|o|!#S-}$7e&8~VJUxMGl>Y@2w^L1?fh!E@(d_(Tufq-9(^aO=~ zZ<vp8J>h`>?-x9gfnhEX=KYa`k|5~q653`1m9&&hSQ2ugmW2GYYB3tsl(ID&X7Rep z(Tq_wS&Vi$w3M7tkL~U(dEIWqYr~AGsd7VRC{bOWE1NcBr7S7Oa4DJAG@`mJIHt@P z1SZu*5{0DqX%j`lF~j_SxLu-&@&;U+wrWdG;rlKo3n}fDFV7onl{W5mS~^xtbHbAj zWsCo(T{=kYmYbnc3i&5OG#BLkSmu2pA5A_^zE22-M`)=>6dm}5w^i_2rl<-iN&s}_ ziB!b^ymNxna#$6xbP0gE5Lc6`DajJ)&Jy<7)Ki+K=s$6b{y0lf0Ach;L}3OEu?t^U z@GPJgUOb(?*6|}Z!H^HT>2*P_zb>;+8E3b=bO3L9Ftv^<w!C#TmIYK})lA}<C34o- zIC|znX$E~D#~i4LV>5@0;f^x}krfJq^`ppNH!_aGtT2XN@_3ImN@q42j`yW|3t~N4 z=s#It7Qdyd^PCG0SFP$z&P5$G=0(@yj_I_j@Go?1=LT7eV-S9pcd<QPYkFRKSh8o7 z7&OJiy>UuJ9BsLB8DiHK-UpC>O+3zQu!}qCP=1JA+&0f6N69S_)nc~}x;wTDkLq(n zN66q0nouvhy6YH0V-2gn90ECWkhVsd%!VshmD!>#|50W$g#1TH?Cx57`W>4wIkgV& R&%j=Lh}t_0QGoEh!C!%!S|0!a diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmarker.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmarker.obj deleted file mode 100644 index d65aed34f8bfa77291d87d0d67c67948dd52b7e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4002 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 ToW#?G=M0`uw}nvr`6K@Y07h=9 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmaster.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcmaster.obj deleted file mode 100644 index 7e7d2e15a3df609ef183fcf94418a2ba2b781132..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4593 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcomapi.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcomapi.obj deleted file mode 100644 index 655eb62ea27e78fc34946682d95b58b2bb5b581c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1758 zcmbtU!E4iC6o1{at;ob}PA^U<PN6U;&aR?U(KcykU0qAEPQ}cSCSTW#G?{67m=~vW z&>4{-BI3!LhzA9aUIrWLu3r5I9D49SsPDBMh^HkUl6<`P{oe1rU*3BwXJLY$l#@49 zhef32n#-y+IcJmvW-e6>I$c|03$kgH7U{dF*;RGPh-uI`3;>5xwqvT69^uEvB8gZ6 z8kYcm1dBK}kR64_1%O@lMjVa%Ns2j+?Zhh3xQOUy2cMttRT9=^ST4aa`Q0nIW8(=w z<W<{YT6tlQe)8U_aliDaF2T<sJwz`@Pa}On%uk8Q>yb=0mzLyIUd$zD1es42vpFFx zCgki4pDPM!xyq^pJ>P+j`+zE@tr3<aCt8wxzqANdO%|BB=C*!U5N3oLR!i+5XvHcU z?Yt*DRiE)ub<NccJE&weraD?BFxu5ST@oa5#j2YoQ3nF+tXv~7O&2u^wfBA-MM2FF z{~u*{&_q6hv*~NLG#meSt66BYKYV;J;%l@GOEc?wtIdg?Hk42Ly=B==(!Gd6k20IS zIm_{RA&qAtIh*9@)hkSi`C@@nQj*k-54`Myx9=d-1+5bR*Ryx(3j@6Bh2Ca&vkNu` z0YV38Gb?Jzc3fP^uz`y?)Zen{45!6jzDm~PXg%7#Y2x%Mck8O<Dy~{GnMwW;^dI@l zU#XYNZTAy&zkUxPfTH(Hn)B*mFT<^Ex)Yz!1Zc=`&BDpm?eO&4_xrye&ka2K<_><z z41Yy$d}sY>KVJLUhXx%DcW%#bZBQI<KJ4)nCM<ap*A%0-;ydxp^=WRMAMV_#JVd}E kc<FG#D{#%B)$RVzD=TP&c8tmpM*i17NJ-6afrr|`A03D!qW}N^ diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcparam.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcparam.obj deleted file mode 100644 index 4de111311e2d181f360d3f849938ca7326b81dc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5494 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcphuff.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcphuff.obj deleted file mode 100644 index cacf644a807428b0c02347566b05d4546bace903..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4664 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcprepct.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcprepct.obj deleted file mode 100644 index 744687d5607fdf1231a56a257e352da2d4a13c0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2957 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 CxgQ(= diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcsample.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jcsample.obj deleted file mode 100644 index 1bfaf5b1cc4056c1cf7f853ae63f462495732869..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3998 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jctrans.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jctrans.obj deleted file mode 100644 index 90204b13b31efe709e35943bb6afaac19b22701b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3432 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdapimin.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdapimin.obj deleted file mode 100644 index e427785da96c77b4b9c218f18de95c5803297038..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3230 zcmbtVZ){Ul6u)nM>&mEZV+D#%T>z5_I0tWwV=!3vI$&F2UEfxy44z&4#ya~i?@t6F zGV&nq^=fRKF~)?14>QOI6B56Wn3x4g%S=SG=r=!*Xu@WRAu%z7OzJsrU04(&txe9o z_nmWo_x!&df0eZGZ9}fZL0PI7PARGsQ-(Z|VYd`bjz;j*lax*jMI*ywxQ~T{$w({` zZw!%%T0%%wXF`q!<KcRK>(=^~#uhTMhmg4vuiW?6i`&V>E<)y|%f3xqF>Xn+oRAww z$;56zfAG|Y8=H$kLu8S-itu)TcX*!NUQ|wE30Vq_oLDyB24NIy9`cLuRxnQ*_BJ$u z_g-J$exK`L{l0EbmoU`X=kvG@xrg}9!ETSc%hxj0eTerAy1RyAQVgLx3()OFK*eYx zgjh^Dn#Ghqsab#qqf*J171b<PDV6~miJRFj1ue!$B1?X^6{6lzMAV8JjwDJ=nIZ+{ z&}hkMHC*VDQXCiKS~QBLO9F?b5e30GUDznt-cQ;nBIFG4|0C=I8jaV%Y!)?Jp#;?1 zY!)2tt6!X}D{8bO@laF?n{AGGe4&cMuXrvkn7fY}NVz!Bb!33$``le{cDn{#EG|~} zeqZ09mlZn&!2(1+t{_($%b7A_o(N&fmroToLO!t)Yu=JCBkv9qD?9;;q>}2fNIas7 z@Rg8HiLnzhsV#7V@*9#Y%2F^a$z<IUGZIf~stEZ}<wP_Jd^^7IVpxLtN}M8<=2vhy zA*+O>>j+`inj9W(Q6;w&O2m?~q$uzwK+?~Hc>PK^T(hk311dbin>Vfy|AON6fUh?3 z=%YAlI(i#IPj3Lp8dCzEDq2huO~1X6&Ga)Mt2JfIvBZ*5NtFl-!bdKR1{E=;Mb!uh zMI{uBE4xwQIY6&7(Ib#HWpss4CqaIRWf?*S>0QBpn46}@Y;@30wQBvr9)oAq4b+nD zaM;23Y=;y6@`&NB6KHLIP2k+atAHygtX)z-j*%=VP>!Cqk0NV~2y>u7^c!}AGfvwx zd^NMg32@T}Z{ubS!O2a(H<<<{Zl=Si)UUJp0(<6nWL{ckax+FxbwTnQ0ChXuUAU*P zWqHR<P#2FMJ@$1PVxnC(uW35)`0swfj}h~m52!WzT$%d9fvWSEj`=VwS-t^Q*tX#| ze-zf#B!Tt(tZD}#l!nZI3rmXHkUOIuO6jZMw2hHj_34}wbfC0k{t7J1`WN9$E!-?* zRYvF}0t~NnEHBX2`F^&br{A#UG)ixvHbeUdsPP#b^#w+&)gP2;PwV$B+Ny$X&Z95* zkiQ@KohBdc=9(#|XPkz%NVP@7O1l;fFG~j(jUF3aopm`9pfkn@)ROnIV6Si+glmEm zsYx@cS+zGs(aG_7Mz%hjQCH{IfGTtj$+f}(rj_Jg`HzrL2}7zVAi;=vK_xd0#pfFg zVOy4O0wa*8X56?LC~$8p<cWvp@ZR1G-$63Gix|8+!yjNWd^b=JXnWAv4DV&K`~cR* z5Y!BR1ULbp*U0gsSot*ef?!tK(T)wG*0s;zw$^NK2OO#3fGS`OY68L>yn!S@zt?|d z<R-PeM_rYB=^DC~+n73NheB7GI1V^V!%%3yYv>HNo@ozTi~ED}j`G%gKCdrSzIi4! zu0q%3H(xjl8*3?J%pYNXhR+{?ZUKD`Gzlco$u!u^``Ca$d!6}yTL9V{-4>{BN~#0& zp8k;0+Jw2LKl6DMe}hhL`O5Tl(@MSE<3ptxb5zpg;!ZLZ^fOb6zijGDzh&yWpPl;2 zUp{r$Z@ujDTkk{$m^(?Jvp_n~J3tiZ{Q-tt+QBe{{acF9RJ6~6GjIQkT{D7IM~#`S zmF2+*o(x<44=fI&TG4(BHmx}&bex~nUZ%Y#DgXMen@Sa}&2~C?kQJ&-^>NIvm&L@P zueomMf^!ePLpTiA60e2!I?mlkvAX54-IA+)l;;c6S~)ijel685)l&n_a$BIhGw*dm XU%@RTaFqcCa<QCzy4i0f6no|`pKAfM diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdapistd.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdapistd.obj deleted file mode 100644 index ba183e825947e8f7c573803e19450f23671eb4b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2606 zcmbtV-*4Mg6uz#V)?%HSE}mAlJOmJ;VxppS70^(q<CwK1Yn`|mM9px$#9bZoqw)_3 zP_b1_rKXoj6`K%3LgHc4#KS~UUqDPK0z?G^M!SEaC_JziG*D4E*G{z#ZD<J(iBEj| z-Sd6lImbEoG#V6!QvA!Rp#|hOO-sw0si=NBtmWorbrQWar=3aV^wU{#&1Td&-Lx`& zX|(J^2z7;uMoukc0>aUwfx*5(wER3m+bteBPCphv%Rz*G)h@>$8EA%<W*9}IZx$^- z2k7_qUwrsjGiXqz7c2rF2KY$yNPknF<co%uo;kBye(0@7`<pEf{u1~zP#*QZ(EB8? zm*Nx0<NS%hi(^qyPK74oQGPs}5<-cwXjqI7rpCsFXd*18@>-ripKU<<n}900Vwzxy z<)kdJ{C>*<RLyBES2iuDU9D6Gs9tc~ZUwCrW^|YLP($@oO{j*^*Nd%MW@@UDo^2Uz zWg1h`3UQ@i=W?WUOW=$)V-hggE;1-&yzh5V6z~l2|3h{IO^W+rH=Ek6bP@XP3=3K9 zwe<ymQ>(2P(m6Zhj5)!RH&j#jJ+Diec=vuU@+gzyE0c^c5f&j1^OHP7zS_gb;}Z#q zQ9`mz!v}rPfj+rHQ*FqJ5Mn&LQ3s3AhwZ4nPS@MeyNA)CtX|M9C9lHU+fXuEx|p9c zG}A<A)sGN$ki5B}3#wt=k%aVNNc)_$p{W_gOsj>QUeL@k1<3~?dEj=^P~T88s-<$k zXtf7&-Fwb0+SZ(HT_vg8uo<9b&MIy$0Qx`vjD~{~_%|7!VzIyt{{Vj>_CxYETu^dF z9w~2Gof`so9e%D+Q>VUx_!`7m<`(`Uf&CiBt8l~$?=4p?8O!X_menES2wU$?%6O6F z>fYp1)%FZj0l#>w&3eLp>c-+N+M-A8Yvf^`!7&C4EFNWpoAaOJ3w{7n5?i~1h55>2 z8A{axIKnOb`6GnZK}>IqaGcAeBK634AE~$94tJ7JW_6WlI@u8AKuR*caE`D!kR15F z5-EWaa=$iR8-lt^Rm)qE7%Wd$B(^~xo2BzYDT|~m0xao3J<cqC>&1~$@TScSRBHm3 zOE@we+%&F&R_Any0oivHauX{OTi&v-fAKTaToL$k)uzTO5pIoo)uBuH#&(<V6FhSd ziC8EB$KcmS58k)Ib8o|w*}9DBx&+Kvpv1dke87z8iA+~UL65*f69%@<i#wIX4nE<H zNjT9Nmoau!#T-@Q4h4scJ5$Mj`$ssp%4h1{eDFF4o?_A4_33&KM8V%*@4~)~5O)ab zxgEt~rv!E`JKlGKLKq}syoWMN_&Z{q+h@D8(P}cNmVfv^hGglFv!1WuJme1Niqs7= z{s4~52XDSZV{^W;PKHh1{_^j7J?S=Q&we<q=@=%C*hk#`;J`+w^)V(1L-h-!YRAYf rk;r=du9I5x-DNkhJP!>4P;m3?{=MvO?A<{0kq2G!oum+k-A4Za!0A$c diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdatadst.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdatadst.obj deleted file mode 100644 index 22be293e7e7d0fb563ddf5cdfd1f2ebe945dfe1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1786 zcmbu9&r2IY6vyA1HRd2q)SxN#5D=>%h_(%FwYEt%QLL#+ck`p6(IsX#X2T|t-Azk> zL5m0p(}Sl{3WZXH(woqGX{nHZM8QH2o}{<*%_h<w-R)s^hMD(yKfe2BUS5X)H<t@# z@|x@yp6G^L(Q`3nBO<F?C55i;ZpoWDRoN)hxh&<4yrdh`1!xQbfID2%)O=O)b5m3P zz;pl_w*iiAx)dA}erU`C{FFcOV^^)DC2Lwun=V0P0qJ1u(yXPTDm6_m6gMe<3;DUH z<FnVSL`P*%Ad25W947Bf&LE!P<4b(#o_}#U78P>gI3EkGMsi#@wH%8?`9N-Ym5Ze! z(OgBYQ1oUOowb09YOO$7su>MSH9K!uMDwa_JF;$=dfSPNs8Ti6wnK~6qSDEGu3PmL z3svieq}1$6rptM)P_j)MQnyR&BraC#s!BuKf+e}AQ<%0lZ4}zx=WP@bHADVC%I?xM z_$b~@OLwbK!~bnI3%%O=UtWz`y4p&$pw=a`%_&cx7)$&=@128c_hu4$#boqBlI7x& zD6S)+WQe67XJm<wrxL6f76b<lc-se`#~7vu%oPCJd$#Ix0lag9v+Zd2!0Q2U79VSh zA>&+B>v{=bcNl<i(-)VDuhc|I){R4aZ$C^h3_yzf64Dt`cae2p2|NI0CQTOEwrBgG zpZsn<^EKyN97_+x^@nRec1`<^IpMsCE<yw!e~dn1`@pk6jSV-s&<c6SaVt%nZBG_0 z_L=5T*O%$4<10g6xQOWcN-4szQztv8k1i9z%csi>S@GRJb31>6KKoih(`SZ^v<I_f z#oIZ~Vk)P>K@VDtw8C8rcY7fFH)pcuBAjpMTisJ0ErUP=wmpa?HaQ<|w}Pl5Kr7fk rV@{suIFVF;GvURW;r&I}TS+r}A8~w7_Z+#B%#j<%aFPLn{{;R3LWCob diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdatasrc.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdatasrc.obj deleted file mode 100644 index 0b20f8b99efd1a0338d28298c73db6c031c139d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1806 zcmbu9O=uHQ5XWbmZ5pw(p{+GykOf;z4Hjz++SZRGo1|1@6Y^DyX_hqEGzpt**=(p4 z{Gu%+J`X*K2!aPeya{^n;Gtki=+#rjtA&alJbPK^Z6bPX;^F1ZzT~(6nSbWZgA3r` zC*!WUq#|<R)siX}N^yT~(IZOB*&L0oEsINWDYuxXdp@01lO-iJnu1C{0Q9<LMM@Ua z9B;RCj!_3xt^n+}`O2u_6bF?lfN$cf(8=*u(h?O#Rz|Z>xs0^ae|)T^q6)GirZP*E zzl8kco#C<bt*E0jXb{COA`Z5zwzG%_LxJg#>jvkW@q5E@cOc|<&3fXzJ38a{ctei( z%q;JZdc5(1SfJ=c6CG;-6(l)DS?U>;rJfyB7SW_6wyj)Jb-&wDMl@H{-EM~#ikVy^ z@5yG>=US+`q^5InyOx#2q>{?EO{?i<m$Z|(P%KLlm2L}8i<uIIX?xQ~q3wOpMiJ06 z<o~1WCQZeycsE<RTPYd;Z@pRQ)qeB#p|z!}ohzoKa$0Y5%F_|k693P<Gf?lI*q~F0 zcyC5nKH%|U>~Te0Ed4NgrbB^fkQLnFumKl5?Sj`M4ATL61i*IwiMmVx&x~Ny3|a>~ z=Abj9h{-ez(h(~tVrjLQ5>%N+YEn@FHje->J^HtL{|Y#PKj8FzafV?4qT~nhnuya< za}F^JA2;zi93y2DNmvMP4Q9a%kY`Ak3+*EVYuo0Ht(A#K*N4`3)Lvq&I|okVaf}RV zee<NJ?i#p_k9jRdj9QRg+cpuNtASQ?GN0dLEr2ho_E&kf#t*?8CUFZDHyfIBWTBhf zHIWs|#+Q3XzaO&i&h5*Zrp*%{JGFcNCv##X!3sKoIsWBnu0G4gR(UvY%VQ!jR_j~a z?k2m{gr$)^9{O0#jE7a8!@9;ljqlWXbP=G=cVm6Hnb-AgpmAt<hdc4&@2%A^TRluw e;rTImX^$~qe?^!*2A2s}Z>(c)Fv0+#wfzRX+BhBn diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdcoefct.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdcoefct.obj deleted file mode 100644 index 79348f7e1b30152c369ea8d75b92a851a808c12f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5655 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 bzm-*P|Gd1+_W3jTN5}v9i87lY*oyxEFj?Kj diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdcolor.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdcolor.obj deleted file mode 100644 index bbc03e3c1bdf20492753cf18f9d71ef0cad9175d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3065 zcmbtVUrbYH6#p*0V4XEB&^e}!Vbd*S7y=?@TAhXVsuU`<<s!t^2HPU-3MFl?Ml+pS zxAgYRh5e0L;$pUCX1>gX#JE3kqHGMu1Dj+c#s{+D(ylDS$wPH4cjvnWB=};xhwpNF z&i6aN^Y`QUMzX=U*-^WvJ>)I59}Y*nU13L~Z@<YK=;`!P$=u^T;0XBk`{`f5#~lm= zLltfkD<*`f>w=*`d$*_5SYBRQQ&B@=TM0?z<}smS*N~W=kfis#ZB2DHL3u+VjH#2v zwjlcL<?lY5RZ5tbuRB8F7<|&uxT>lq8}hDT$m{MnFh{@n$a7WM(qnZg{6(ZEW!uUs zk=|-++F`4;ly0wY<m`^RCR=0eE|bGp$JaNSI9rXQewVS4H*t<GZx@AbnuS(n0d)m} zZi=NPr?j->k4uZt_JB8M=5R!AS1!y5^>xeD&IRr2?(k*e-aMQ2`Yf^zM?Ah@t|be5 z+e7ZooY4`_?3CmZxT{+T1SoY*V2`&WOu=-!=%CQ?e%wKEVa*W#KhmB>Q*s^dW>&l9 z4r0IMVWF#ivG0T~tJU^(y90tp9&<`hU#P6;A3l}}TDtekNWQC?Yi(wYO(qUyQ*CoC zOFsps9kwRk%DU?8b_E`CW(oOhAfL%2vP1}*KPN3w67oR-DUcLW9(hAc3jOY2&tX@% zy{jkSb%lb5!i4m$CWLv)@9XwOT=IME@_4Zn2fd+)H<Z9w&ao^*2oIC?77V1a3 zldy#NnHJd2N}A|^N;E3xRV}PkB&$^Os$Hy9D62H{s(GNc`s$a*B}ww#NOmyfL_axB z2!xgW_cfyGb>EGTzI~`v%_%GDB?-cr3%{SIvNi*(LyTdog#T@heZFt6^LlSD#vL6P zwYTg6UI`~@>|l0?mMMsrQrW5$`AM*<L_PsljmS@cK`V0O$uH0aa4K+WK+sf6paD(; z+LKgeU_p0A7L>5zqJ(-*3na>ES@Gz!D2$5EF_FIw{4_YH^f$vHz#q;r^`#>9rB$MH z2Ard^kOt=@2x-vuo!(Fw*R76~fO8y#88}LHAWSH9SJ2Y`kLI*iwzo3iOwbFuzPNT} z%$gUys*t#8i5r!;F^QXJ4818?O4Q;@SX0-&y>Q2QU9Q12wvSUn&ss1zL~bUvyZR@Q zPlH7T{USFFd|Lnav5jDv1_pQyu)V-*p$IH##gAZ_d2Q&RDqa#>X;A!J|Ju+YBuz)T zX%@J&e(Kd5SOc0q(jLB$VU+7m>8uVLSW0&Lv6xybI>uirV5|u&FNqG6$g#}^=15i2 zs%pT3m5wj0YxR)+?!n^t%2;b&td)tCVB)oP`n!kzq>Mi-==1O+eV$y<XY4Tcc|z{< zxZLO4$$O92XZ9kk5k@Cyz@U1h?Ng#K3<5TPM0Add{21_4*j@cib@UzT9~HFe^8+w4 zHvrg9+UzTIU=_E@@5OahbPR4U7=v*f1KEy)Fn5Jc!UVmurSB^l`b+t(xb|rr3E+q0 zMKP-)dX<&9DTy1FxRK0&%!hQc3kO4<5cc7O$o-=0LiYvx;Z*ud{EQupne~P#k(|vZ zpEk8H<lOfRL)bpLNrMIB_&$KKY-eQo&S)Ypw3>d_r|QAJ)*NYtWrMZaConZTC?ri= zY6q&L4-}DYiwzaBfsH)B*zhEEbX2`a4fb{BNTE5>5&a`ieX0)$l7Hc6(CERKXgJX{ z6UmRJ6+-3UcD54V#mm%?S^*;f11R<Xswf{ZoYvaDGrd(wkVAj%mEV##DOfRR(5^zk z4$Gv%w&XV`qF>B1<5wXRqsz<mLgM}dNoq@;r6zlsSx}*&6}gf?H4SCa`+34r)P0TI zsUr&<7fVHLDIa>pCp2?0U(n#ia|pI4KBit%W;qM?p@U6OJXp6NvQ!xu*CDU|nxKY; zwPJ&3j!M0VD&Al|H56GoXzY}WPyj}cXzZj*L(V=!CYCfa6BqFO+sxcqf#(H0c04cR Md9RrvfKieE0Okoo#{d8T diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jddctmgr.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jddctmgr.obj deleted file mode 100644 index ad7d4bb3919a656152995cf2f274c38ea4c73a0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2645 zcmbuAZERCj7{^b$%T`{NvN5yi2q|-hC1cCF(M(shy<P8EN6SjvTShG2^yO~5OV^V2 zP9_WjT-05UfEZ#3Q8Af;sfjO{fq)<O(vb?rWRQJ;xL{3+uIVBRX|U01J*V5G@`=_a zw>{@M&+j}h_kT{0Gy_#@i-X+l46q98>p`CF4?2vTOV4`u^>TRBv5)O>csW-e{_XR4 z+<bpepxzCJHvj<SI)A|H^m!DmwY3UWy$TG!48VMzTYmpZodOKM06^?FVv9nVQ(A7m zz84Iu5zAh*Jlm8D%LW4e0H$9=^n1l;s<!1qqponiOz@Wwt~FLFbLwZmKft=Xdsf1? z9C%KdYk2f-F#bFW4{9_u4JdoFrE|N5G%4B)M#}2Yby|$%PQ9a5M;nZK%A#@@cD5R6 zJ>}?U`!R}Jj#1q5Cq)^r-;G(^a?IkEKPih)r<ct;a*)rwu6!aRl=Ee}oe$0Uy1Avi zTb8SC%%SQa@8SIUwk*gx1Mc3uY2LG}l6(?pd;?xD4xJb5VY`DE#-|Gl1<U(Mg~Fho zA^v}qy-efa8`0U!>1?_E=zV9zf{*rBV@EgUbhJ62+dJUN$Q<+dcFT#+x@rq>@7}Kg zs~8*AWg}WU^%NTGNgGMvuR{HHODAn67@gHxfF5wR2z)vrl}N$T2oS55MgSDa0613& z3eyE?DR^f;D8|=1!=YQ9Q4T7zr;US++0$)<+kpI$GZ*yw_y5Px?F{nShHkIl$%8_4 z#ROR%tYa8{AmH-1Wvt-c3IHS}eVmWu8P4|_8wj!t%Ap-){PDC@0ssvcgz1^4TTR!k z_T7+@!6P3at4JqA(_+&tkxmH{1T@Lu>1p&YB+^Ndio}x01DcYMtZwH^+j)gBFXgui z^8~Moy@kBO)FS!@m`=pbWErlDrbJB0GE9h6B0d0V8SKytF-f3^-(cVs@%oh=GVAp6 zEKDU(To9)o%~2H~uEPA9Fj>}sW~c%)T%Ru86W@fhmV~usMc7OyVMn#tUh(fbG({k_ zC`!=E+Z_$Zugi~@<Ep3#G}k~=LVZ(yyf9-(LbFk%7och34dnD76C(mqe=>eJ>ot6> zf%n9wGE2za+%y4iKzc!b`5EzPtuRRlQ&J(R9l9U;Cd);n=dPeBN)0>8$CdIg?;Z^S zBpWy|H~Hr}VNxn?!X!0EXfb{#J_xC$?L~SXcQ+cQW{;pPnjS)W{=~*(SMUVVvm$*P z?Ruh2C%@bx9-2X${7B8fL$|eUbMm>>!ldj@r4S;7zhy&r(^OQTW@V6$3V+CkF2$e1 z5|BOKOo56JX(}a9NgM7eSq<rwdP;uk_rKC<=G9l=y}co%qg_}*1F}9_pTrK^i1d14 zdY$+tmQxtzwIqntiNUS#Bdn#ksu!T8Y~NP%k_kYo*)oq2v_rTkjXpv+lRyZ?Pr<fo z^>;&)DDa-WA@E@xh}!LvXpdbQ9kdrj&)SLT1^cS#C41q$LpJHX3H1D6lm60UlUz7w zFG8{hST@>gUFWU39YAYn9H|;Dxz@G$U@GY9z1B5Ot!+45ao(B=lKnQ<dFvQS)|Hm) zcDQ<NuESlr9h=oxYeHp@^M=N8YK+{hHZ&gF(p(uS9;sT}K-OKY8L4Wn94|e&dbH$l zMQM4cY_ud&d~)?q1TGGMMa_L@``2dWL(L7p>GT)BCN!Uwc<;Mr9%xq9)#Dc@xayeZ YTSfTbfn7gq_I@6?OOM{v0EmnD2k1PN761SM diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdhuff.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdhuff.obj deleted file mode 100644 index 75e2a82bfefd277de78d1e1e6a572cb7138ca54e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4839 zcmbtW4@?{96~BXnT!||?iM!IKX`>~TkWjibPNcM~3jdA}YA43vKsK01z$q{S5!h8* z0Zn%H%JFcE7FtEssz$52WLhUh>XOm4s+<(@CylxkqKd7kWfff=nRV`hA}8^3`@ORv zbX%*!5a0Rk``-KBd%ySI@B0pK6Kq9~))Z9LwR_iBJl)~*9_*;GH|;O>wj63~;<vIx z-Y05Wn)WyIZ*xPV|G<HV>V=*)f*_a++uB>|S{v3E<>s#6_Ruz==ZAt2S=NT$@3}V! zJ$Zs~<#$&1hGn?anAG;3a4k*S+uq*R{t&d``jubaIq?0hOMwHJG`0Fz{V}NL+t)t4 zZ7J#p+uFVL2cDQW|L8LhKD<=($PBA*hj}4qN6u!Lce?iMbQL((m+Z1D6*Yx>T=s(9 z#Wh8R?p^j`#kH+w*X|;_yI83?=sn1)kEB!|UV^HprLCTIIbm#;6ZT!rLba~NyKKuH zJ|kVru?*FwRs-$jXnR@@G$s9hG!^xhB}CofYiMd)E@U0vy7v0UWo!EyQdP1X$33n7 zmKHX>Eae98feu#Y?&3n>^8T)c;sIvR|3AV`X|wVB(3?x@t@<|P+b9-p?Ne_axo=6W z-PBs&;%_j@oQsY5Z5gZvqD^PyUdj<NJe5jyrBt-1SiyU7L1lr&kIdqou03w2<SDGE zNXHP4tq^|Ozfw#SjJLyrl#zTBgcY(Nyqqay>gjr#(6>%l&6MtGt@HWY>smZ*?G4^` zArqv~;q?hZ|NVj>-fc)6toxbQ)8N5!)05r?k8gjAQ-r`;2v`jP^hJwjf0NI%ABTgt z{ihOE@5ZXdSmhG~%Jppx-X8eUe-BnxH#fCHe$i69eWf5Amn7`$rdf3;Qn9y+YGr!! z7-mRq!7~{4KR`zh;Z41<!*3<>@#L64i`1u#WuKMSj1*d*!O_&LSI|nmTvCT*n;t5$ zYDz40GzU_edoEf=jyV#^X{FL^%@Ge3zm(&2HH#IIacHVT7IMeWeU_H~k$Qf+iyZOt zW}zbT$JCM%vyE$(ovIR(RAo*g+K5f_u6Mp+3x{@>YDyxc7PA>gL{nx%FCBwgw45BX z^aussW(TM%LZw!+KcAzSVV^(k&u`cE<n)$q4vhI$52uM#x^b8J)v!7(_7rACSJ=Y% z=}FU-M4_rgV0Km_M}pLRwmjPTYumVOOxtVGcAJJvWMGwmO|4|3=O;g=&uic7?+2bo zhA!RE^@_a&*lI1ok2^Een^I>sDKZHo`PMD0QJqb0*+p6Us(rnRDG>IV@J)R$ALkIV zShVlhDHeoncOp3M|3-DnM5^v;>_@hnMPt)4NnfQ7nY2vGd>38|ni98#0W;#zdi#ut zIRbXoqAlE;j%1NL798)iaH5o0`sk7C0@S+iVvn*$3aqGP0UkNYqOaZup-|w?%eQnr zD$_?j7G0UkCr1n^(or3MFDX)QS-MY<GH3gEIFP||0=egGVa+{je)lwgYsy^IjycGL zk`keT7a6f=mUgdtUg8~#%<sy1U-|w)9}IE?6VrL`J!|-r1^^9z=Fv<4xC9&Z4j85a z<Nn_uJ&rjeZc^eQr(JVL5O}CS?6m~OeVaH)*#1?BEs`UWJE5(zjrUqaOya-q#fv=e zj%a0r$b%y?QZT6Fk87bMpJN-uwj=q)x^5O41vFnXu!(2%!%Jrb50tbCMeCk-ArW$l zaA8D=aUfhu2)j~TrMV{!C=EX}Wf~^wg65csR+BP)mP5?_h-xQEpbHbzbm6Q4!)J5> zdDLpBf@4%04-KUC!+}shW$WFmwasc+qS~oly=!~!Eewu5`=zcRG1EYF5}=YY!+|1M zc^`JYT%s!x^_FZFUda$nIQFI`=|FmZKY~qGq@BZv8Q87Tln9Chodwmcq(sbTKoF?w zxcM8(1eRd{wn&*p+gx1K9?UhUZ=;|ON&Nbhg`Vp~fWfdiIKU{mE$WSX%%KnQ9=zsX zTSa@a^>Wj`K-iD|yz*xj*_n+U4oSPYgo_^2G3DQpl vT??|m|KGB{%V?SvgRB;n zHN$vx9l1^CK9g6T*A$bgSY&co)a&<{`<?+J(Osli;a1-H?j7_3vt)0940rCQyTO5e zY}2e)kvYkM^c)Ke=gZ<-pkIzA_riqNG@@9HPes<a`L%Wsi%g11E09ld<HDX+W&)9< zXr$aAWeas>=iThyR8;{{C--+`5KRQ)gn3yV)vpX2He@Q3HHV4etTyF-N`4c)pX{Am z^e1v#C#Fj`#6r?pkY=<v{hE4H?8*fTBWAF!Tpp=k*fay1Mt$tiq8%Tn_hEk`4w_sU z10g3Q&=RHP#h!iBaNVTp@E+mFTD7VBex56|kOkm8X@KJ-IdwpUqln(haN5t7Qa|%i zNZMjPQ!KAS?E4TrC=}$ma2%Cbg5jsr)$odQ@pL*m0BFTRE4qBQrGixc)SWVyhGYvz zx7fyU{zPTlSfM6!HzZGt4?DkHU}`#Ql-jsoVgf%UF5s;WolKQxKj%+Fe8|rcCir03 z_W;LRwh<h67lL#~s!$d41!+PTV!5|W4vd+D*Kmno9F$Q5g>15D?m;S*G{-w{K@e*R zdJ2h3P_+fms!-R-&>`#9*F7LfB@UfXZ}L#P$Ryp*hnnWTWb`49yvxWK6UF2ehhb-u zx1S@&WfBc0zf5I0nqyYIDR=z<M`=|^8FWT|k(jR-?w?v#><Uxu5KG-LqRb#%A-Xm6 zc$|de1L>k5k4(fL<mTX}ANV=bi{_pQj{7XRwKHgH^O--0Og+)fP`-oZlo`}!%msUn z!SaamFSci;STNkh7XOJ0Qqp4Zn$MMYwR`>ElxJ6OF81ugf?Vz=C^&dQAEcPCY{Pl7 zo`xwQ?|j!vGM&!HYx-z3jYjD!QZ5<nzJ`>GB&7R-Cp8T4`2lSUIWF}UWCg<Jz$Sz_ zqC_~@+wiytU6IzWIiV~#k%DLXHaxd+nO(qTI*H3P*l{r~(@9*Wfy?YXE}M)z+{WcE z*g1&{4WElk>fca3zD7}r%tOT9@j;brcZTxBg33}MijXyk(2*;^veg;A6YOmca(Ux$ zGc#MeBkGNObKj?+f-5ta|1YpOw*_BwCwsx26j)Q=4%So>tf~J1YbpuW)MBs%BP+MT zGN{}r+eKjIB*9w8^~7Mkc6}Z!rh~2|xVfK1??ABrHS>Yu=!+xJ4d`KAiL1&*9Fdn) z<ua~&lOQ&kdilDCb3Jd={KBh98h54tBo%_X1~nX^?`Wksxe^-s*qzXRgqcL>X{*uR zS6|11Ub^v=n7R`(oq^37-vFY_xJ44EQe}!6!3>`HQasbRH-t*J(>ddUDQl&%LhzS* zL+Xs-KoDM8C(InHOq+SFGVSxXF@`ZF_ljRMR*GM=Rf@v#fPk{)KgOS5nQHhNVZm6B xk&kg0<68x=%$T5kbpWY<h4EL6a~MZ3L>{OP5s-*+j2Ol=Mi}ETU-j7XzX4=}S6To7 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdinput.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdinput.obj deleted file mode 100644 index 6f66c5413606b84167fb7fc2cbd54cc2a6296a96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3084 zcmbtWUrbwN6#q&utbt<7Xcpo+ZCp(-Tb3bUaAmQV{uy%}&|c^yV>YamQBqn~+GQBV zoEHq2!y>VZSxk(3a5Fxb8E2x2KCq2&w-;l0@x=!<TLP&sCS<UQxt{agB8yLJP55rl zcfRkO^E<zD&KKT&jWu}=^@%6?(=mrMK9-4%jP(WLr@gVn=un)bH%DV<`V#Te!}L2m z5KoR~GY6t<rj{{gX-lOO{mB7`XWu?Y^MPhIbC|J}(mb}onZ0br#n@`>^U&VLVnD^x z=~Vi_5SwX5>kq51yi`<5m{&ZRA#()3>JIE~Xf7uBNGctR4xZTxf9Rc;8;T8&?2>s4 zhG+F})E~s~U7^k+A@R7we>C8e`r0}}0kOl|=V|LX8u0o;&3#8ZJb@msuWuwaLZ+`5 zOdE<YjU-Z0vL(tXEK&ZfVbQcd5i2?JScaFYl*nirPja?Pv5q7M<2vp`g{)sKBI~it zKs;3{Wn;1ababd>>&!r*OG*JANoErX3SE-%Kx}Y~jA^>4QK-G2wNWC-8QTAkv<uc0 z+>WzZ)NDmlSa04eG}>R?x@0eEwByNWB0Ip_oWj!!RaE%x$I?jDeN@lNBi+8Yx&=?C z*N3uK>=p(3RCtesI(xc=NSh=Xaj~mA*cS`shBC$_#)R@MX@`lik1JS(X4J~qTpg>% zC;40?oysN$BH2+^fe%7-beysIJ&YN44abx5OoYGL5hNp%P9+kt^aOglCI|+`df*Q! zd;(6Hz~eali^kZ+Dv<1#o{%`X3yiAU_6ol9s=JOf64YutdjS?uB|kQ0>i7i<?jT1x zrK?VYDy^m$JWhF|a?;MvpQm%liHEA&UWpt1jw)Lb0RAymwiTpC4Q?%>CO-^*)AYim zP2LbLS|DtmUY;~Thgp6sOj@|po!pNOhy37u*FC(GqfOojVUxl|;J(q+bsJCl22cHF zg^NezrEY}gdNT2WD%YVUlFPP0tX?8)ekbXGgT4K$u?y+3+zgvSE2w4iqDk@F0SN!? z-;6<IaXo47+CFpWfI@H#tvXD>?UQ;P4El4RKeO&n@$YZEzvMq?P&xwWo5S-sT^p9U zjHYRj<8gjBqC3a7E7^|GL3Yv?bGb87IScm?+|>Py8RU6XFS)ITd?n<#+-7Bww@;qB zJCC&w7K+b}+p~iJ_2eaJS8^>Rhz><=ML`vt@QXjB#UIk)HK!7EH!iE9mv2P}oHegM zf;-a-*)mvC#CANB-FQaFN{()=?#7Rf70X+W<(+(SyGe4CgWe|sniP8JY3jFWmpQ<v znb&F80XHryIf{H)ri75n#z%^8bM*s)-LnamAet1h2}H9Zwm`7Sa`Pu8*a~9Pdfcgq zm=lP07;jo%FC?QXqL-8o7;kx6*$(5az*97;)bLKIRoiUU|6<SA>ZcmNqkJP12k^73 zYSYUXANXb8rT{=myZ*GyMX|(KnO-an)ka=i)2q|CfY2}JC=sP+EuVzrYtR7x0MdLC zCau%jgjLpr3so@n{X9lS^-fM{6K<6AIFU3ZL+{~k*dW0%L93A$&5Cb>t3KJouDim9 z>nCuX#Ra&22pevEjqAs-fn8fP7?{8czPq4jW2*#aIKF{xs`)l$-<klvP2lCj{+q@u z;9(&R2_F|}<=ekCtyfwJV2ZsG$X78J&5BZPh9rDbcy9vG7DPcQqXy+PfX@W;)VONd z95%(NyW3CJEmF_=Yo-=5mEYl0$yVp^gHErI(~!^$8=%T7hV;2id3&ZgpPCKZrj|3+ z(#rn75XX|=#_}g;JFHXpv-+d5mzxt^(uzn>^Q}w%8pCXd4QJ^Ekjd|CS2g-@LX|4o z@IMd?XT(gf(4Gm%O`*bd=R$=dlLV?hXgm+%L7zsIQ6e~#xN30Ouqw4$i0A;0yrvgR zE>kXrF(upKx?zmv5i~1RkB_zPNOcQte9u+4sRiAtZu9y7ct<A;%lz4M;j#zscN-pd T;<}3KQ(QN2ec5ebK=l0s8TIfN diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmainct.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmainct.obj deleted file mode 100644 index 2e170859e973d0dc092d9ac026f0f20f14fa7ba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3280 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmarker.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmarker.obj deleted file mode 100644 index 877b3e2e987ed652ada8448f21076aa060c336de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9817 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmaster.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmaster.obj deleted file mode 100644 index 615bec6d13279b6787e3f5639655344adf6af661..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3924 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmerge.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdmerge.obj deleted file mode 100644 index dddbf74e8f9c55fb4471522022288a7775c65445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3088 zcmbtVZD><x6n<}VtC`JA)NEukVwfH4uoSzto3qN=CRgd&*feRX#oT5!No_)!l-yj0 zgA_G>+}mSD(IIZ&5MjvnXCH!&ZAgoqZsMRy8U4{89n=wLe`F%Alj7ZZZ*Qxx51Q=9 z&3o?2`<(Nf=bZPw2VW;OjxGL%UERsB-FrYth5H15OJuJz9P96mQ0wjf@IHSmvNuZC zXs9oo+!wA45@`(~#MGEb#=7GnyJO=<du?Sck+u<%D=uPE|B9VRb%fjvU+`?GE`(G# znM@=rdx^9a(I=n%;H82}!nz{y6on)CyY($=t7;2L-j_&*gFX8e(r<b1<*Gu{qq-En z8Pk*Ux5_tRdbg)_ho`}1-`>>1dHs#8o|cB4PQRnk*VN+VJhlF&osJftlk@k5`zZ8H z4O&$IG!RP!DV9o3(^AQoniiqmv2f9ug_PQ^VlpE%5?9qO1|5j^MCN&K(W-u}fU1R5 zD3T~vG9lcZ4E7d{PKC57DTa6;F2-Usby46@xJRI1db;SK(D7dCpaf7e#Q%@7H8f3b z!?Rh?*$O7G-|Dc?qy5FjL$-pBb|fB*i6M2&X?l7?6_ozTWvQpqoh~OOfp%_pJL_n5 za%ejn+8bE<v&^}})9Q1xfkv-aj}JMsoP3%qVRS^b2w_VWtmOtmK3YbWDSAamPFTpQ zXfV-#ARu)2^~b`2Wa3?ckfC*iFwaLL@klD5-q)dk*gwA`8N*2DSe7Bg2Q%Id5DoD0 zIehCSEFn>*1Gck@IWuaM9p*(>2dk`BU6w`HPF7i^x~z+?MWC&E_?v@@qC{@o?P18F z5ps|a5X>Wgnq}j$$c^*gKXF<XoRv+A0)kcD@aqL?+vb6d=&IkQ;Kyd*^R7Mo)uAEe z4L$=LrmU~kml5#1BfBg3tLV>+&U!m`0cU`;4SaSuL-!0i%8m@DD!^Ori84`=_1eJ% zoOR?Eo&JZmDDmVlHpz@yui##C%~3|~wO>Ku2{<b1^80m=hvgf`>V6h<a36fu%wq<O zhh^97ej~nt^DrxObN5z2vt4%0A)3i@vu^O2VMQBoMzjnb#cRxrnwd9V6)Fas%Z~gg zmH=l~NT6#^XD1e<^}$AI^JZ9y#9)XL*SoB3P}&AAW1Cy?&=?A~T@^vCb)44fGSFn4 z5k904`YM<~wxcbJQy^GmagypPPQV_U%#VW=Y^P*C54%~_n1Ol&ScYU@j%vzTz~cvU z>o?gq4Zi84w@t^+Qzd*erc0|8ZU*?A>C#%6f1q$V;HN-*0Je)VKL;2%{QzoC0Y9Oy z`4;%ek;i7RoRWRB;LEGnJf!EcwpD|+I?0M_)`DiWw3`8bcF^*o<kn?|^@Z$JTpGjU zT{vn;{$Zn^N%@hgN^<o)&!v+@ddTx18M=_+3S@{4gFD)s-K5&1VlGvC-U45#@}p<K z3@26j(-SaYk<;TaV3pHju-_(&H{o~KtbYhKmt}EAvs0H@S<FE{3pMY{;xz4tQIcI# zPzny5tvnrzdjGAQ%uNC}d34xxY$a_pH*LB^6mA+TTxiJ@s{d3=ZmKQG06(U-WSq8y z&B)v=aM(_wkh3M^lV>^@a&CrU2ur&=m))uxw5^w3$l7#S7R_p@Q|%CIl^S%J5xoXo z;$9pUq==KE#f5ZUT92V|)uIQq=)mVChc3hAF~h&1<{=>FrLMoB6qhE>@%xW)8aTtl zdOu@2a)J)8rV&|~h^1<Tw2}XRDpEZRuG}C4E*x#$ps|#eQJOXCaHVXGRZ=tliQ|Ju zEB|DI7LL3jy6LGK7bax&Ccdu!TD^!21h)JCh=*iHIh?j&&ohs7;)d%Eb`1Z%?l5k~ zj|w!Gw`n2Vta=~Y@2$Zt5^l#W-{DeyTlU&Ja_b%`N+-QL$l2$}9cX9ne1^}L`22*= LcsoOYUV484E8<x7 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdphuff.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdphuff.obj deleted file mode 100644 index 97294890442d07b46730182d9de6be86ae096e4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5335 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 Q1db?<5RQGC#(*^c3y;S#e*gdg diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdpostct.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdpostct.obj deleted file mode 100644 index ea40e463ae3df157c2126d1862fa559e2c023f82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2329 zcmbtUPi)&{6#txfotX@^AW(}%C;}lm1ywDj0$Tnwb=<CP(mHnHP&J#^ChnRjO)A?d zf`J4|hnl_(Dzr@qiEStT+>p3%LTy?R^+?5mBSI4tg~M)uR4KgAO`!-OE#YAMv)=o? z_j|wh-uL!%WI!5Bg_3iY8PHz09dpS}MY8i@Grzo;rKgEy^I|HWozKy4F0)*;owU=F zCTkB7LOMr^R(`IK2}r?UV4!D!ti4Rgew!gzyiWzl+7KbXn4hXo^tVFGw5+1lvq;un zMDz#uUwi!7R?t{kw%}0sO9&s1obGE$lcl0%rWY<Ar5}9b$-Y+8qrMdWJf<hzuXOh! zdqtfdQ$x|f=y*idQX|u9Bs3LHNh68zNLW?}QsYxnBoUTVOXd=VzR-mBwE#8p#WclI z$!S_D`Mst^=v>}xJG1S$?P@18LbC-|?RL;cVIh0Sd$3vcGc8nYJDF^;UCC^7&Pp$~ zjdn84DQSneQ7Gl}G<93xjJaS_Fx@UXD0IB<bx;h{4DtV?>?WEf_v3E1v|H&S_S+p6 zy4qiS`HsJ()y@{u`BKImbBd=oR7?0{*QJ+gccYt}Fyiv7aaNiR%Xkil;vts4I>KY> zbV6Z`5l!>rLq0r7K4-m*hqxy~*b_&mlN=!*b&!sRx8WgIcyeFPDwYZvqqI!O#$$vq zUAb%_>lhh>Ue*Rm;8?|c-n1MHcAN7uge2fsO@|T(H?QCy$b5O9vADC&{8?wX{^q(q zvAXA+sY&ctc*nyee|fjGl4C#;lpFz#Q+1eP8!>-*$5)Z~`YgPAn?_OCipJKXFv+2R zCv?<?eJtX2c%<>*3<m2(r+UwSn!lswPI#aeYQj1i!c6~OMH4HU@BHk!?Tw8M<Q>!W zB)sK6Mm_*t!76CNP<6!v)&AW|^gy{PA1I*lDnxxTkOc)2JhFa|@@&M|@{S*<L)X@i z9*BzGZ&i?ZMTZ-oQM-zE0ip*?r*VFE<{x?gQcMyrZ<bD@CYqqaB<7Gf#OrKBZK?v7 zM5@<SO+-779DK+DeWQF#Kh&$CxI83r=y&@}uvU=|AaS7P$kxvuM0o#5qMyr$`U#Nm zQ%a{WC}`qP^)-%>d|2zGctq0eDN4h^Ew`ynirBEfDJCI#jG`@oBnI!&&~gAy1-FL2 zu|04X#x8*73sw*RbddcZ91}|1`oV+JdaFtj-ggO7K?QVUdKsHm{cnO)#3sKIm-FWs z9Y)!P0N?j-R@@Qn->cz*5K@u2ipH0B`1PrY)m=x2uYK5($|Yf4=2thJr)e=sn7R<# zr{3iqPJz+XZ-opFCJjm(Ae47R3{!s;CWY9MwQ1v!D2^;jc5a(|{4lxG9cS*8@VORe Qe!3oKKH1h80=OpRPg2?VfB*mh diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdsample.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdsample.obj deleted file mode 100644 index 279e125ba585ca0376b3051a7f79e905d6a53c63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3392 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 Qa9rwO-pX{c1TYiwZy2-#W&i*H diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdtrans.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jdtrans.obj deleted file mode 100644 index 98ce9983a33c13c65c3ed1dc9ac3758878afa378..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1976 zcmbu9-)qxQ6vt2cV~sd<KZ=S@7*1g@9L`zM>9B2D?X=pi*{0Qw&?TwM$dZxXg32D0 zI_P>8h7%D%@IetDM8OvkgrVZxe2~q5Vp5+)1gYn?9pam*56L~;oX`E9b8^nTb_fm% zeW}2?w57I-SF%K%%%-B+SV+~U#x-W0no=*NbZu;ctrH5d(nhvhhC(X<Yzdl{o;H+r zp{uLi*X@HsKfqdjC;ocl?0~{ifUoM4L`Sckpj68;t?qFs97Fo{raQZBrG$BD24Oe` z|J5Je+2gY#K51I2oVm0v-*<Iyk6n4JF2fI_JaiuK+>i3{MC@cDaHjplKr}3-g0Vz2 za5j_@g2MyRP&naB4V)FC!=Z3$Qk`Vzks8`#1C?}BW-Kc?lVv6US6M{Ux>~n#mQ;RM zJ<5n`My1;I(2|kSs&V(#vOZuV>nu?;v)+<r)wCs#*G&_p)+O}>E*UvpXVP`SikitX zm`xXJ6xQDV+9(p%4Eg^^yGAqdHk?gcvn8AOzbnncM*GFf>ut71TQg)mr&QXU$+H{E zmi(W~(#cA9w-embQ26|iONfQSXomtr0T+8Ugia=6!*Q1s6h$XKaL)rzFLRs&Di(mt zy>5AUfcp*5P<ECba8rQR3C+-mG&P>fWF$qEO+~e!rMmgo-nQzVBFUzj!IwcSQ`gZM z=5_&aTiN|CS!%lKkkMpKHAogOd3ZR@aR9^gn@C4_DtP;saWl7BTziIVa#8TE;7UdB z^`FehU7)A=nI+;8slb<;k|Ld-L%iIQoLR`ZdlxQ_zRUk`kbP9-XI9CV{0}E_MslAJ zDhFJ2(1jF@@JCmsU(xwC1i3h0dWIsaOa#T*N<96anN(}>wExBuX{7lAdQyKA9!{N$ zey^7~i{9Dzc9Cu@HzzByb91#EJ_vrUm|sGl8w;eFwk`&}h(p!2w4<2+SpBp?Ttfqr zB~Q(m;HpOcJugzxRZeWj^k^l$K|YC*&n%E=alV4Dl8sc{bIY5^zjc(h(LD1iMw&2O zH}03*ubCtwy-TwZ7o{xKEzg%{BYf}bY`k&N-^9LSKJZ`@Jo-MuJt~hl9`hqkpx71g E8>{1T{{R30 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jerror.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jerror.obj deleted file mode 100644 index 543ab46d9f354dc145389db76ee9f7085b7f73be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7729 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctflt.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctflt.obj deleted file mode 100644 index 9a866178c462de445c694db67c357ef1f0992c5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2306 zcmchXOK4MB7{|Y~w+{wO1s@30#YIsog*qJ#&UD81rpZw%>4P+7vdATg$%#$5O-hn3 zW>%3RRDvKX5(FU&!3Qn`yC~u!Vizt%MY=c#Tx1co14Rqdg#%*!zLOMOxahqDv-ooU zIm!S0&-tB4;RLw7{bA1^u`Jgo{><h1OfKwCo%L~Rb}B{c%q%|_wo+%Oshv(H;`yYN z?~TL4E&%8p%4DrrI-z@edUSWM8x{rtRviv`vH7qL3%>&V{Xsjd_t}{i&Z>6`7Jfr7 zza2Pm%#N35vzaWpe@FL~j%)jm+i@e6R9c0fM7!btvCkIInM{_)ljpYL`~N!FXEz@A zhU~v!Jai9s|Aez24~(4-ct-S7!+tgq9vTbyJ)^#`cW83h?_&XXczD$7pY*Zt44)w@ zAtx&#->x-cW#Z%|<m4sf+x4O~W^u>KxxCsgC&_3{r4?-_?npYBs?WQ>vFe{~tU8xZ zq%uyC<#;R`pK|QZCmN^3$;2b+Im@DGN9F`i=EzL9iw+7M@9iFx2r@(ee^_?IP2pX5 zH*MXmcn0@d9TvLU4<4THvURmn>9{qQP{*A7^t##dfAiEf6T9o(&=Lu<P*C%Z`50=S zC+N}Wqt$mhFg7`^MTRCOnz5kN26q>mTuq=9fY!35+S&nbv_k7<^JWuV-V5OBq=!91 zVUeVjiRJNChw@UB3t+OiHov_1s0}-cBkjc}5`@tu&Cl3Iv8_r&6UIJiej*V?QIkfy zFm_9GgG3a?sx)>8W2ZFNNkmbsN%mQ=b!omK!BM=D?2}*{(i9{(iWSM;2qxq{YPpc1 zosz8x_DXcz!X-)bxkSyL%TPNBjspL=CfKSPbycvM8muN*wJ{i95gm7w_pxlbk3x)K z!eePZlPwR_R~#R|RwNT!Da(>o1zVQp5($oCQL;tBp2^T|5*)=2$(97G$dE>Yqv)Ei z=w~jx?!5Hk%jRbBiK2(V3RR?7XIHLE#HWiwMRg-VU6kt@AsV7kR{hA)5aqf?lu=PA zsD7jw73I2i0<@&8-)Cwxn3gIO^?zb5l~rP$Y;=pP-XL45;;-`+O~JiKaNn9w;UCRC zxaZ^3ftBJ9gL5Zu55mnOP`es*)m~x=toK;|23>EleRl}!DAoYhc+dq!+<Ev4Pi1p8 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctfst.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctfst.obj deleted file mode 100644 index dca0149f5159e174a6cde12cdbf1c37be375acf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2216 zcmchXU1$?o6o7Ag$2Lf%l?_rb4}&5W2Flj8sI_X-B-$>C8Iq1I7#-7OVn@@YBoV3* zP>PcAFj{uSmEDK!+p=%MzSOq{1;K(#*M~waHuwV-ium_X+hRN?jX(P$oe08Y?q9w+ z_kQ=>dwv&db+v_@z2TH52G6E5+F&~5)%)FAd}u(Y+RsDU$xvMHKSkxKSTvG}r8CVD zmivJ*R^ORS#lwlH=#nI{wYin$_A@qL;U}-~?IO$VVeI(}VY}F3Wm-6^<^h)5i>&rn zVCzp-SS^)GrigAw`j-vYw(PV*qZK_-3ce5V4)5j`OFjpaDJ>E^`7wOkxos_0!{go% zz8k}{rUOks;_T&s|4_i`6AyNKJ;6|?Kj3v9c86S@O1IbT3ABc~54*gI+Y=hp1_>qQ zgp%^LqG~)DA(oUAOUl>EA{vfs6-Q2IO50UQWJL8u$#x~QnuzJE^KL7zdWVHor!!GK zS*fzL7EVP5DyB2ha+XvwaW!!!9;eV1!BH)iCYVkaB?_hYS`$S@XUKoUvdc6Dci`Ey zbhaW%-0xDd(9yp6&jp92qpc?*@iWm<niEgAn<f5>tCo|y>rHH(+T-c#5nO(^2kUNU zk5iymjr&l*ugHSh84Pm#u^YAQ?@QHH)vQ!wOj!4^R%>JI_Zn7H<i%<>x{0x>db-$E z3a09@a5{sxIvcxOUB#FJ3nO=CgGYM7W4r5_t;GRofIbJ@gV!Jn(i=VrGrX@+k{b<W z0c0C2@nO4>U4db{G;Js^L9U~&1|z!&!wuB+7L-NEF7heqU&A*Kz7@!>@JVUTY~LtN z8M_U+0Tk?>=QF1L57Qnr?Z4uaU$XIgMwbl-BrF@j_Y#!1e2U6r3m9S&3;sx2K3(k3 z7i~uNDJ<n53w+wN|7O~IA^ViRFb&J5<4=6@Pq;LPo%~^b*~aJKomqF)tn-)NSM%>| zW_yeD3ho=(g1K`&1{|^*U3H)o_ya>0z*mqajV{N?gjn>=f--yYzk2i8`(p8bl5P}8 z7J4d4>Jwpf0z3E&$RdnWm1Ll@4j3P!0c@>&YL(rcfbsL?u|<%}t+hxTCG0C6J61jB rCg^Y9SLMwyjA?Y8DBBcQZRQHtJ2D}B7J3VXs>hGQvtzdzU>dUzhw2%{ diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctint.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jfdctint.obj deleted file mode 100644 index c03cc6008fb326380ec7de909a56063b52fa0f40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2527 zcmd5+VQ3p=82;Mtnr5Vufk6sJ2+CODpjg+U)~QL8xOOCKNg5YeV%jFx^+uYEBx6xH zSSUh|kJI5qihr!X#2<pNANG&Xv%--42;E?^uGrL6sZb<hplLIAzV9`i^UvtTKSFZ% z-1pvd@B2Q_`+e75CIjxli0k}hMsNh*&E|yJY{Vx{d4%NU84=Oh%fiJ-Qk=Sk_e;}> zcuq{^dgEmNX+nr~D4j`8rV<V}&pQTs2gv*zglxC?$s6>fgUr85$Zx-MCmnr8%7UtT zXUP0(z!km-yl~10SIA`28DyUZ_D4^B{CvL=HmHJn0R45KJAKdg8Pan$oe|>G7Z1}9 zzIUR}XnODl>90U~((`7|i%|VoVDwDD<#)U_;`0V0L!$wo>zpUz9tw^4Jl?=SWaOON z7xH)`v%)M=QF5fB<VU5(lIb{dQF7#><VWQKbuuZmoH?7*?P?`6P{ow4b}Q^yYFa#~ zd$8H{O9r~m<`QDMRmrl#WF|h-GCP-OPDv|;$5L04Nle`mIU!7Ek&L?w2L;FbsDly% z&4B+O+HSHjxgGYVp}iGPgWvkF;MV^7X2EV~Ym2FP@=8J<bL8XcW{CgTQA<&~PkKm4 zY}^|j=iH+nFJO;r+{NL=<T(=<4UKWJp<s~0pDc8eFTbU2?L<d}a2<!J(@e;xCSua4 z)=sWJLr9wy5B3-)i;3A}`YN32WKpGUgoN16-1qCjx6d=L`IdLR69UZ4!gjXG{^0+l zcUYKXMLOKghr8uym4(eLZ>C`zpSQ_Ujpe&&{<thX0Kg-tGwA`{m!%!J^FPX=ZN+Bc zi!8cB*VIb8+zp7=QTR9uZPQh@rvA*)JBsZF{B+2o+pMA3V`_z?8*0VGZ_xX6t*}Bk zLez#uh63*G-cvU@T2#82x=Hz>y4k@O>1yFS{hfV_Jl4(pH5RSXA`8`J{}#Q={Plz9 zXpR0P-ab{)H088K)IL8!h%A*wss6z+M0HWB-E<+UiBffZ3Q?6kRQj)~zaFEzO8++i zMQQ7=uQW}Tw%8t)VxlFb>q97sFR7dDe2F!7?^AzSv45skC=X3^&<!Tl={~(n_dtfi zEi9Bq%c^FP^L8fHsI)~J(4`(|_KGnZld2di6;!>qJqt=O+$D#(xn+muUuXXH_kXY| zXCG?Xzx-P$qmPd)bg-pmTqx4g0pd4wGo5T{5!Ru+ypz|VZt4VGx(3U-uM>O|Kf&6$ zm3Fmp=x+020l#3>V<&oSmBY>_c#QAtTjlG^`2GL6%}}duvsGRyW4Vtz4KZ*UuBry% mMLqn;Y+T;6q87swa@aAq%>85bb6|GtoeS)j=n7%5`^n!yv94|a diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctflt.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctflt.obj deleted file mode 100644 index 0d0cc684cf404ebd7934cd6ddffb16e6fc1df2ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2770 zcmbtVUr1Y582_%hQE3&0i3s)K?oX*uaJp93xprQ?ITc+}LripFu2JJnO}Qp6e_-pA z5(b*vvN6WkCW4HC^v$sr^58=@9d)A*eemHN5RyT<SqMd_4-RzMcW#tDEDt7q_|Ey| zeD`<0@BF^+oXo!qT}rpNcXTqMNyDE;W7=%gYY$G@G<|L+$kE`OcH655r|$6iPH@^E z3+S<SKP<im01bWNh&~ybmXynvrLOiaSo{EBufi=8ufP2kEWQWu{DpW)>MSQM%&L6` z7T-s%w&r^CN;zCD5(!5*`#Q3}tpDnbtL3m!m0-vWego;U{X%D1dd`L;nm=&+G<^5n zi=E|$$J%iEH4G1JJ#8JBz0)<+@9K3(HwWxw*xNVcviIJyd6hoTfZax1UEYCPirr%) z-dSyyQ@P}v$|XN5)u)I3oXaKWTrT-pxk#PVwTdH0V`jN3iHy`>$W*%$wl5S27W3{t zIrTeboH`nt4u&h0EUHaL{4*7^W78*HQc2>zP+Zq}=!(eGS|G~F{C4q1;q86aM)9F$ z$bW@npRjrGR=k^K-7S9@>uoj*zuN0REwq+(wSytQ9-lVbob&nXRv!Pqr`E!?`??LR zJ~#QuEh<Acg4ovU?iKk^ZR>Xpd7PrJZ+O^(2H(`c16dTRz(fF|^%T|A0(@5u)dfqT z3hp)IE`eBBhdQ4x7LQDYZ|dR67{C|J073(Q@qPTk_XUc}0IPy10C<f2!q)mfg~IU2 z==~KA3{q=&>Wq|xUV}6mF6YAIdHjEPOi~yS0*Ox=A$}Jp3F1+lIv}p&Btu-o$qDgs zoF*VXiqjm#of$}^tLVAJFCtSP8jgoc=lSrVWR9{qPVmv-K}@iE3eu+_iy*NnK2Kmy z8KCEwdX$kRIw&*sFeA$}IgcMO^&lfp&}7=g`-~h>a=_GG4m1RmkwZ%MnfjCiZJ*Y6 zhyYZ3%G4c3b}2z{!~tJHI;CU>_vb)EfSWhcL5ZpPjNCy7Cz!gIk)1TTYKF^Y<T;wm znmEfyj*>m5Zg8L>*k&Y8NtUTw9B2sAjBHV|!BqTsi)tIiWXvSDDM{1%tC$;8pD^n+ zo}?p9wI}>6*6ZfaZPXMMr34o-`5kl5oSAA46Ely4ar34KS$4tHAj_7`1i1`3HYS-e z<k)hWXH5=x%40GInDX+fxwubBo-NOxU@gzaCa?|#N6K)dKKrfV^B2d3La}YGq?bs_ z@H82}FFDqk#USfcX*4<v(qci$cbSFy8~O2+TB@}08X)kulv@L)G*P9FD~rI7V4Eo- zRa&{S2>b}ruc+)9HQhr^u(QRV4=oo9c&U?3HH*zfnM=7wYRvA-mGlY4N|f|f7b{cJ zS5+)lNuQMwUc8b%k^40Ctq{l^yM<>-v~SVANBhw&{JDUZLwkvK<QD!q?-tg&M}##G z+Q(@3(H@}viuT8d0IU5V9HR*TQ)I-F*pvz+l_2XPwoKyh+J<}W_{jLi$Bbv{CcG3M b^^7O-Jv&CSCw}8n8dj|E1K^GZK6vmiQ3xzE diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctfst.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctfst.obj deleted file mode 100644 index a237e9941412aec77efbc640f0664df007eb11c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2699 zcmcgs|4Um}6u;&@HB`6AR)*cemVINw1E=exo9#L^$@<Llsw8HL%WKqpsZXMYBoAC6 zpakJv&qB)>L-tGkZS*Gx{R7l)Fr4Dt@CO6MICP*8h6Sl^I<s?Mv~y!Wm<$HVJNKS@ zKlgLa`J8)4FOddoqqn)UHyX6KKZ(VIgE6mD>9YmHk$#1Z9FgEnZ&>LYV0J(W_~W5i zyw*>&X9*#umf>i)cPL=73WBAfwt;9@3E3+0NbAdQzDBfn3EBRYf5TE=NLUzEZ9ma2 zBR2Sz>(z^eV1v=<aFn61Ao{bXK7ZxyLeN+hWk@G~58+MD7wQYD=iqQO=nvgIp>MqP zdVQhvs11X^gY=~4{hB(AzTMS!&DAVfK4^8?-QJcqm$Ui0&1-G(v^s5eSA)0py4C5i z*}a3oK?Y?dXHZu1vqF90VL!vNk~1tT`B||D?F|QuW{$;mxr$*%s4}EiyBM@@D5T`$ zZamKVtpc)+#RJN4u_cQId!zpTqS5idahDVmxNk@ehZ%KI;6N}GV_<f>SfjA^K5L`+ zux5z=4{0Bx8MztnW<ht$Ka6_o&BCts*Z0TF1zl}r$RAb%dYdymd)*4d|Mk>ztae}2 zkWycVy{m(_w%P1Bwl#M&^XyY*yXI>1wDZ0ex0}O1nJg#w`uGw9(MN>vr6;3uBOzaw zk+K|@Gmtya5mI7e54(@O>pmsa8;j$sPNsOigb)v8$G%-W%H`Z2b%NapcP!`}doYR{ zsAmN{Rba0Kv7Jh*sd2XLJNq)8PD06BRYVP<u@LnJnmVF(qG=*(JDPT)wxa1FY73eO zQ7@Zj&Vjs|d|)t5S5PArEmUlxVh`1HCT)uGX|wuw9luHYDxaL?w{K%Kc__n4ho%{a z1<x@}f7nE&eVjGvGZ<w^X%`(mdB?2o*a2x5<U=kE(jln3!V;+aoVr8RO&maCQ&4x5 z#{<YQcVy%a1a*@p4w*Yc<(-uIX<>=V`}t$5@~jprWs#%~XOLJm%|zQVlsx7ADWo*b zbVp3nch?!ayp=N73y(m`LShRu=YD`hR!D5o#KY8;3SogJwm^QU%rky&O?mA9BbS4N zxeZ>(%xxI(b7Y+R&6qN0<_?ThUdO%qDwj!_@8S;<>$o6f&~kgoAnXZCDf0y?XE9@( za~WElA7MI^EFzHixi#8lK`X4$$ywdC%cW^o6Ue(lnodsXt}IA9+(KR&9D<z1V8xze zO>)vQNXz5%rrUcMaK0-p{zN^?;5iT9Q)v-Ai|`Cc)!dID^5gSrH;6_wZV)TcI6<sJ zV+Zj(nyVmIqqzj48BHBv#-(FF=kP9oyfRT)p`FtlC7Q#aIXKP1YmQRQQKmV{le3oX z2`n2JAyNftVToIVh!Kvsk!qUQgpq0iE3)}ST7AYH{JXdq2t+C&4I^ee<q<}Snu$EB zHNp!c=KoDCNUY2ql#Xq%<R{E8Y0saC_s@myaug7q+}hvvcbDk8f_nOx7q#v()E1pw z`qXZ88+6HmOod1Z;iXfc$_rTMyzblr%J4)IriX(+>4?)SsE5AD<?PEz`yvmX<>c>1 V)2I8`A-)?Q!!PnT1n{LIe*)U2@q_>X diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctint.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctint.obj deleted file mode 100644 index 25fba0b5bc4b4331796c0f4252d5abd45c1107f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3151 zcmcIkZERCj7(VT}>xOJ;VG9!7kH$~pO%P;@im3Z&Wy4-}X?Fo*Yd5+MF6r8(A0d!j zv!*WT-LX19;@7YF%lN}!!ViCzi%T4HKQ>$#AR*nT2+3jy5E!#i-}hb!LlJ0=Nqg>l z-t#{1=X1`$i=?r2qqliScQk1C?2pBReKD^~-sK2}`uE5vZRrp0_J-tLd-1zh?g_-@ zaC~imq-zNw)|N;#)E(}zxAMHbacv_>zedRUGF`5+KmQa-zf8!5Ke%V@>q|)svRb=` zq+bDS@EiA&8%n_jqtQqd(VGDMam}YsG?apdu3$d^{wlzmT#v6Wsh@q3XfV*b`*!$^ z2cBMEYIv9p!e4^$WX<bq)<O27yJNGvS+Kv+?s9s(Egf!G^HztqwMA-oIh^iBZ~N9( zm*jAI`+|K4#g-!!TmG<6e<%__EVdl6*z$+P0<=36EIV>6u8*sn$N-hYdbi6#`@_Am zk@v=1RliU|)v<Vw94WVDv0!&Ju%~Qvyyq56%1PWGPJ}`jx-4){us4Qayj@5Xr1!%T z#Sc9L{C_C>78--s!`&?DZUrJRZ=Ec7wZA`<tS{+m%i%yM(WBEG@%XxxhQIUFQtaJl zYe<E^)48*gYwd72L3T8EHgmXG9Gl%8lF0d6JRS;v@<k>2_8E)GOmvA5uHv>-Sw+ZK z7Gf#VqL~b@BE)3Hhux3wx?hfkBKzP~CnFqZB1B^I$<fi9#iD2X4(6<4!*)<6j|_l; zDorrKrV1yRvzm#bDotkw(efwf7z7|pI?<atU?YilnE=v$J4wV1-8z!kYv`ItqRY^U zB(dGlb&-V2(Djo<3+Sxb6-=169$cZ#nN^!A+EuYh6}!}7J&EBFOlA16zUE*}IZv2V z&S@@nn7iPC>cN*ayT#5VaIvLH74qPcCGytnwl3Z6M+jv?o{qDV+F6dC%+!AgKV4+w z*G_7)939V84{5WMAJ=9p_;Gfe{+wxuYUen5NjqoZFF^=;)tX&NFEbxRsa2&ss8G(j zo2&;v8Ndj>JUykItx<gi5P3sfU{Zk|SEVcP<>7mtNegsJl`g`Uhwr>z{<eN2(Hyu@ zrGinAs24Oef;wRVYm%m!uVBr#uY)?VtJZAPrW-|}_yu}~PRYM+I9n`Yc8VVPCd5*5 z^3l#+ke`yHi*oVnr@^0cT2=}lEJLXvD+`C3QCeU(GY$K+bIa(pOv4W#%1Zvmci>LR zv&Cztv^fi%$<%$W&2jt;Op2e8mE3!m@jOSR(@Z&SQgWG1kC~JLQ}R^FnZP3mGthS_ zM^7>73cXB^Cyx-05N&a}3b|k5m+XhJd?sC_Q+I4csO%!YM4|Hls%64F9Zzbyuj|Xz zwkA+uPnYP@*g7Ua%L{jz0xM8=m+1hQF5y*C7-PcN;8E*`kKQO24c2csrb?i#V=%T+ zCX6y5?P{FmBon#8V~GT7s~S9-2s5!7cDq@d4R&2jtb^TKtZg;y+)S*8-J7h6NfRl} zrd_W{&KBX`rw-eP>K<XjWEz}Krni~&)vT{nUpalP&{vDTR$dU0{9+Z3TU>1rJdrPz z<7DJHvx#tbsBWWI*&+~qr;Yx}|Dyd~qs`R-O;qUlgSgyQuL=dI7;W3CaZ3FhodVMS zosskmu+bpv13781_kU+5^G)dFBxWGz%H$l5WvH%}`6kn~KvX!^xq6RdPbF{^;Yiba zottzHGhyN%=f<>Qp3vKQ=+wWO02R=LzmExU1742v_wxc&LX&%W(HUr@!xf!lDd#B1 Zq_NaumGynR0{(a2X21D<Bn&7={sP4-$3Fl7 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctred.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jidctred.obj deleted file mode 100644 index 5ca86acf14732f3db301bcb7ce5aff67ae47a9be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3159 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 OGv+Y)`w8HG9r70+^`)i& diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jmemmgr.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jmemmgr.obj deleted file mode 100644 index 2667f56cca391a190d03d31e464a30157133d417..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5150 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jmemnobs.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jmemnobs.obj deleted file mode 100644 index 7860f549aa7f27863abb44bcb8fe30ad9a005873..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 zcmbu9-)qxQ6vt10tm}ibRp&1pQXFDoP*!Jg)?aIzIxBH4=?@iBVw&EznQ2m!Oqfsl zR;Uj}L_`pLD2Q)@|A5d3|CJ5=AL==2CyG8S@gd30J@<3I_nv#sd2tm|xwM#hAe$^! z-nDGjwM1TRa7^oUR2tpuv9_qGjcxjFcUf0A8dgGq{s{nxWDQf3^=2%$vJy)rQqaEz zu;<a`e&A9J`Zoafg-CGuipy<TyH=tD{p*OcPr~w=8=RS@VG>Q^uNU52a3zj`QFWW} zn}~1l=aTM1YM4xEwGZUe&o3t3%H#DAzK-$`za3x2vzLV8rjWTGyHnuvWieY6_{<h3 z=CaiS&*g=bSlG((RW2{$g%Wygh9+I0l4dBxQpib`LVj3TL}iV6R<>;Cy1XbOs_IU( zz0i{0Qm6Y)&rW^W#i=d3sTy8GW--}RI-Y5}Im;3+8<+GQO(SVfaFey1+NA2DM4|LP zY@$dQGvxo{*fW~Mm#{Wn)s|x5eLKlQrTyjW%OzK(t?G)l({$3DcxrI2_}{v1fMWMH z4s%i^|F9Cw6}dc)xlAP!q*sXB6pGbSP|B9e0es-yJbdng&kxQBAUJn0nhyiK4?$=W znE2sU1VUX|!*YaR%VZ2-coM*Ol)AmtX0~LJ6+1l)PvLyTnWu$QLzE1E0-9{LS?nKx zV^}4_S@d+=@q`DI<Y%&~$qkKdknKF$PCGWE$8@P7D^IXoF$=Iu-lYYLxM1NItm>-$ z`0r_(ncWUfe|!o)fa>7KAb+H^hZFFqJ|24dkJiTy7al~vXBU&`sx*K}bmnjE+thD; Z3?GicC|vW6&eZ&)IDXe_ei-0Az)v~HP?`V$ diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jquant1.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jquant1.obj deleted file mode 100644 index 5fa2e4179d54b4555ba10129614ea7cb372edbbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5131 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 I2*vOJ08{=-y#N3J diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jquant2.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jquant2.obj deleted file mode 100644 index 91adacbf0d29410d00e841ea56f280faf11137d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6662 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 SjMiJOV(scLc3LE2O#Ls!1Utb1 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jutils.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/jutils.obj deleted file mode 100644 index 84003fa50ffb55596326514f26d12d72077ccb4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2162 zcmb`I*-sNu6vj^%OVJ|WzMxjzPy|J-3oh7YL`<=zrKq7eDeWLrr=4b|)nMWlVuHDv zG-`|*O?V(0eKPUE=ZZ1@4L-TNXyS`c#z<1XJAl4A)h55r<ed5D+<WdhXRdf?r@uY! zJ(18PcXUM0OBp>Llm`Qnk{g!!-Laf>Ca%bXX?{%?^0K10CTVOT5!L!sO-W=^Zhv#L z+tccyu>(Y(D|+GJ;}$oK?I-#oJ&CL{wIoT?RIPQ`2>#_(&7H<wW;TRf$=N)YA4KrO z!If<uGxCh8Ny(uzv*Ft>Y-lqZ9=YZ6y$DZD9ZlO2J{$>kM!enbBV9ou8ux`FLGSTE z-0zEZ1p`9F6Yo0i55@vQJR@bebl;4$&4g4`)FjvPl=HAW<$oI%(u5*a99hpB$5lyW zNad`N?Ml>Qc1WIHcl*q)cbM3<o=?eYr76>;gq9qxSe;MJR7oWZ7qbOL;h`%Mr=%gB zi_zLfq44tl+d>hMGwA<e+cRn&yaByws<)CV&f6#!-rCP!Tx~Gb+Hy9j6jDZ+^J3!@ z%G6x?Jt}QHb9b9)j@T=l?6vzt0Ri^`Z?D(R{~UqNNGKMzi@s>o2IyWDJ$*qID;al( zE%rIncSKcAq6ZFglx<}z-KZxA20$`5VqA48PgGnE-2y(U#cU#9&=QKMYAH#>u%_Z7 zB1=s=C7%;DwUAATg`8oogSk3AYr;cRTn1BpI;rMHL_LwoDH0Ut_3hlX1g_d?*C6J= zS?;;Q9n-J5AZe;Nl+Yf+H2#t-L^1Z2b-S40w3UwD|NdiOvREv_7G(o2*6qCMFWcU- z(*5s0S*iI|KfLhuMEg##LLD1$GNIwRFvVhcbW!Ppm0es``e?O%v%R}kzO;(jMknoT z$><w9>z?WfM?NDajlOn;u9Yu;5>NM^nvKPTy3+fqFpD`OSW3_Aa|4rnZGtPDChq!U zrbjh2akkGgaT`4Av(k8gp9cS7Lxe*h?3StlH{*P1E~p2{9J#@AumH>hc7P)!7vP`G z6<{rB0z9XiK_gfRc=~IA15|<eU@>R_>%bP!2Jp2YjD6Yxn!$Ro3gCFC7Ays;!3MAu p>;!0kLM78K&;mAsHDD8H1s;G#BXkSx2HU_Ma0qn#2Z-@({Q{iPRx|(r diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_aux.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_aux.obj deleted file mode 100644 index e98da5586619ffd54fb80eb0c70fda5579be63fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3844 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 BAyxnY diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_close.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_close.obj deleted file mode 100644 index b85ecdcfba66416d8198a442a04518cebf308209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1700 zcmbVMUuauZ82@f=mfX5@&1N5pzI2E~*htr<YTM+cO`17;XtpHR71Leg%}o=%y$SbE zq{zlb4Ah;0g^3i|#vWR5Ft$M-Ht=DUjXIyCI8d1QCbU#k5Oh%J_4`h))V`&CIOm@8 zJLmWPzCY)?7dv6UT`4K5UbVD{3bWk+5FV|Xdci36CXOEMeLXUGg2QV&Zsv?9ahN>_ zu>Sj{@8TU~qgXK`Wtbg840@{3{={%TZC0nu!gOz{qH9*(Gn*exX7U4(<M~sDsyjt3 zZ`s9yIkh*gVwBJ}aR*5^ZA6dnMz>NW>LH}QTKhi!0)|nlYo_%d`0eGxF%GI#qeS2V zyeVVo0lG;**aIX2TGrn19Er5;$h0<1w%#NnX0ESoqM}z-V(vcYNG!DS##J$IyHK_4 z?MfqaH<dOk2CsD7i*=ywSgjeW&z`Aiyg0nrn5y=Rtr(83Q?B+vEovpMI_y>UMB7d) z__mR~H{FtI*xY4o%Jn<%9gc;l&FCpscn+!iR_Z_U?!&iNBb65squ$)v)gn3m#cQxn z$&Q`P`V-^HF<d7{vLk+)0?CtS#&c=EGMdSVIAA^qx8?=G2Ye-ge_v|_5R?GE3_!pY zT_0SDLPz#gDwWb5s|*ME($utM#ne>0YR*81LRbkg2;!qL)ae?)Tql4KQ1nv8DB|A+ z=CG-R;QN+VFx7I50PII$KQR-!Rxq5}1p=|t1g@5#f0ZKu+`J~>oMXRb<abyu%$#mE z7GgiK;jX(|;`7*My~lN=jGOCeJeHcvj-Nf+ki=hNn;)%3mz8txPCoLe=R<5V+<ayq zV}Gq~b=`Hk#eZaE{*Sn_aj3a`A;8Xei(7B6ZZ@AePj{M_lo}sPU<Wg66wyS+y&A{l zO?X?D=xHw7ucTXt8!xdxS>V&gS9rs%OD#}teHcg4*`HY>i|0t|{5#R<vx6QPH<JCb zyHqCfQjyO#%~xwUHy(!?Uw@7ZsGp9y8$+xyhZ{EVpzD4r)ObGP9QnZS*286Tk_#dM z#lnc~aN}f*TQMKHOJtyR<^{8zIW{J-`A<mT9=VWS`(w*>CuH}B2}&+p?}vrYWMSck y>|3}kiwoc2c!FbH7JnVc`WA;||KeM+xHyiZh~q<9gqtBiOWDFyFS!T|H}Ef|uQam& diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_codec.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_codec.obj deleted file mode 100644 index 6963428659a26e980c6fcfde5cac916d08e3e77e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2396 zcmbVMT}T{P6h7mwyPLSW8)LyhA2v{-A*ou|wpOL!{%F@4-MZswlQo;o?yNg>omu9` zDkZ6@U8<c(eJY_OkOu?lOH<lHTj;}rVv?tl(2_uCp)dhcr4$Njsh~ag&a4~T7xlu- z_ucQFbMBdY?wRRos8WSYA|<8yRAUNe>j1zTkmOuaO#6bzkNaL~Y-^$N>JH2I)%%?= zdkEn1?-%cM9w0H&g4~#e*;i46dddG{ust4?r7<}<?&}tEyb`y<#si^PytT189uZSH zEzQRjHJy~l_UD@rGZ>rrwvm0KqQ7}B`w9|qtwq;{{12T6@iQ_LysVVOTOS?mpkhiA zGeoRGOHRDq=^&Ow@LGb42xhdGtwb7koya&pPGY@69P#9ucI}wRNh#vF_cKSwq<L<1 zS3I{p?5e2cN~7mqDlH2lt#qgLt*yKMR%J?QQm67fEe<U<9@XxPoe;HLj-1s#T+@7p z?%Hluwq@5zC-82g_x|?Hq(qgbj7|CY^Rq`g+@#IORTStMlI~lXxKFze?_Qqlau_wz zn>)MOMiT$zd8kaV;Stsz90-Mxhq~A<J9#-mJ%a;7QF|f~i`npj%TD;Lonb0~vPH&T zX)*w(3*b`+IJRtC6>!PMc-csIcSID_kT#w_iGLBODk*)ZhGBa-noPYN5L5*YmzLSA zCZ>5gmP(4?E{Xm82wR@@M#DYj5W!%CWe5AhaHwQmQilH{btfnN|Cd_Jshx^M%W<Q^ zWK!;v#-OGYH`Ws&^J+5h7Q{3;uOK*;Jl<Y4W9Ao@Wl0WCssIbs0E{D%%b+FxJz)WV z5{&bl!YAcawu1;qfT^fWkZ1u-$f<%z1IDN^)|RR6m((CFt0wd5pNPw|C_h8<QK)fw z*}(u@dyT>OkiH({hV>z@uGQ&bxBftH_uSmH{oS!KQNN|RVp~J?Gs~_*QM2nyYcAU_ z9UJeg`iqG(r$?78*Yj?D)LVF{p3wiiyXm>9)!F{y(DNzBm9^SJ@q$A?UuWBV<L*Y` zq4r}r#LO}#ppUvTdT=DVN<QZ;{SVJKILS_8e)B`?gH)Yab{C$gcD-iJHh*&c&Fs6l zxaHsaO2rFi8F>B0GpF@OG&BD_{~bN-np*%|zcp>g_XUhSH|wQyw>AG3qX2ctptZF> z`C5N*bV-l83inKU@gH)cs?)M3t8lde7C+`{j4N!#;&skre22Kgd5txeF*aD{x`(TI zbc|)-+6~eK573`%M#j(hU^me5E8){7{|(`o#h)PGe9zQ35S%8ZK^(|QJ{}B+q3Jk+ z+%|3U2Et7We&lwGcOmCLG<|!Ke`(ndBFCPjBY}M0(zD1_v?oJCu36kv%y+*e@<7^j zyE~t5O4^IG1qX8J7Zi0W$NT7%ww;f3;x=m<ws?;$X?dT2$E+11u>oIiAkqUNK9ftT zJana{b9`yC-GEl#nb6V-4QXgld?{%>FY}5bNTN^C@_9*CeS+c>B^8&*zmPNyz|}c0 zfUPiG9Amf<>$nP|9?{3yjOP$faCV~^v5l)VIuS#h!+0GriX~?e<DAnti<sqHMh;Qs v4j7Y&)7(Mh1H?;cw}5z=t0LFNSVX*m_yy-SzDE3>t2T;=x4CN2NoD^96AI|b diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_color.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_color.obj deleted file mode 100644 index 26b2cd037b694b6f85bc45ad398d699c0edcfefe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4056 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 I6qk+s4{uHnuK)l5 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_compress.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_compress.obj deleted file mode 100644 index 26a919a87d8987dd2526bbcbe6a25a2167a168f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3597 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dir.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dir.obj deleted file mode 100644 index 4282fee209c9efdc221f1705ef1b060e1c63ecc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13015 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirinfo.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirinfo.obj deleted file mode 100644 index dcf31dc0cd6905a87beff50c966ccc36b2aa544c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13115 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirread.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirread.obj deleted file mode 100644 index 2e3c2d3ab718dced5b50bae394d4513e01465478..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17601 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 G<^C^ll1jJ$ diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirwrite.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dirwrite.obj deleted file mode 100644 index 687b5f095bf14d5f7601b30970bb2b6674c8dac7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11692 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dumpmode.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_dumpmode.obj deleted file mode 100644 index 98dbf0779fe11237a201626750631eb8b358ff42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1803 zcmbVMU1%It6h4#LY_@iqj3sCg!6~#_*|1HzQDZg_Hrb5?e-gSsR@^vUXJ@kmvop*5 zqz%|LvMj9LJ_G_qszM)H!51UsMSTh;Bry+_f?%K^hy+t2BJD$kV8(NArfErEHhDNR zXU^R3JO6h|gjPo@$a%L^E}3~XqCmYJ0K@^)(sM>$8VrY}mm<BVq5d?$#@@qeW2GPJ zPXgTe`{SSb4>2aqiWH&#D%zmKjCK$9Wk)S@+{%@tAx&59tk0Ysh$pi>k*@5pq3CX2 z&Du^rXN?~WD;ovmrr2KUchrb>?Z>ZXQs_~Ho+$s^{{*H{m{2YIfpPiMV=-n_Ort=J zt#~qnsR!vvY7l)xh#Gd-UiJftG#p4tEm5vlC=e@ms$rn4n+iqlzvc+c?bMBV#k%do ztL;4OG$QxYX-hL$r~Ca}dm7Hwp0rOnlVz1Phcz2Z)p)aI!_{?Ks{=suYJqv}^E-RG z;h<%lZA2f;Z$U8}7BcSToo~(`iwShi=qPHehIIRuCVpkxhqG6vUY<f5-Oa~#o2Ri~ zISI{jDse6q7#xWwP>-KUoe9uKF#h`4k@RRl9!Ms66!@$KzW#&bnt*9t5NO`f09rx- zSA!7rc&`aAcfw&gH9RzgGpv*+p_S@Gx@#BXIVaZ*0{u={mT4s}Isns00Jxy67c?V} zmkmtgLUAo0*lNyFiZN=y%Z3vvXxPx4I9^U~;pH^V0bKi&!)KcOmCU?D(jsx&NkSlN zq_1suoBubqHPPX@p`@4Ys4j+T^KO7FY=-#XVp|tBqVw|m?~N_^&`Sat6Kl7fPIB+o zcH6Am&fm`<@)6+D=F!@GB}gu{^V@IS+N#}lf7wGJlCe<DtEl8YnK_RoBCGsOQay)S zY^4$)|Ag<7YL<Q_1m_5{3!@t}+v=jg%~3lyM^T(BgtvDHVlx!{p_pXn-o^Nvt1I5- zp_=#6=ig!4@Gt}7iZt=DP>hjOp7Z9`@I;Y1@S@(FgG9bJF*?8bJegsU{OBCcoZS<~ zi;RKs`voFtfh0m?wQaWkCXKL8v2C-{^n=uC(Baij*qfnPQ4z2_^(_AS4<lHfI=-uQ z?rIWh754Y!uGY1y^`e%=6nskfvKy{{pW&|mo@rWtCe?J~g$#e=wG6lZMT%Sh3gugr zA5a!iZlbKEIJnjW$ns!b;;MpE(<i-cI+ALb?s!qk<2XtM(~@i@XXu)tN+)mv34-8% D5U^4) diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_error.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_error.obj deleted file mode 100644 index 72ef9d5bee0113af9004a20c9a6f040189e98080..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1640 zcmbVM-%C?*6hC*H+qI@%b;T$GC8EHXKPz+VLES9rLFsNQXzRANJ6&Aw<nCU}2c?pM zbrbBNh@dd&rI)0?AVD#E3L!`kdPzYsBIuz&*gD_u?ljSd%?syp_?+`O=X}rkp6|Uf zIH)G#f~Y7-#TA8d2LNy#Nkxjtv6{}hx|%bt)+P$C?eGl93mzD+1X%xh|C6Vb#E2yn zS3iuOM+}_F=ElypP_L5gQz8R3T?t7{g^aMF4lf^SaW#ax<*1~^#866&MU=k%aRoV! zu?e@8<n5K48;Z%BND^ulQcnzi_8h=t#D_#Bl?OjQs&!K^nv~-NEJx2E9^Fbj3BVZu zOMqOovqmAVf(scC2S}`QgovH1FPJDu$tYnK-*Y5Ja($y&v2R6WO{v?HMrJXSRuVFu zw8uDWOTlMN4X5hW;X#oOhYlNCRrs(4S(7Bvt9?*oVw`4eGbY<qaM1$ZZDj8+Z#*ii zv}9b$^>;UG-FC8O<SHg;56Sk;4}GQEhj(v~WT{4s?B>p`Hj~1ioq`g<@4M!=boO|C zsC(P}?H2O0dM{q-3G`Zo4xTroz;heCJ<c#Dpqd3NB{>bi#sa*sf;DT-n&7bmDg}Rc zR~LOgF5#0Qi3-4E831Dyq<BJ(;d26$xHXLJR!WR0(SA1pjsjzH>|*-vs?_}mx>u91 zyr}xf!(>DrCDdbRJiLby$xnzK7m_I@cFKH1AnXZa--6KbJEBu383rJr|KNjH^#G@9 z4&7(hm-M!Z>5TcWdvnN{)mT0oaE{Hf=^4$U&u*~hZ|==IYt1vljqBlAgF0f@!(4h< zJ+1#<%v4Nk4)dQNGXEpaZ&amcMy>jY!<@OixS3wozHEnhjirDdU>_bL3XQr4#0Pba zod|Pd7l;?A<$PAN2eXtjHfPVn9EEQ~-oS0uscZI$up{qB=-h64We&#Tjlh%-FB@Uy tL6BL|QJ(ruE3Z)Aqy7P90re%6U#Mq-%&N_AT6OwOFvS919{TA-`3JzH82JDI diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_extension.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_extension.obj deleted file mode 100644 index 717df59c23739db51cdecd1fa778107b47600103..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1730 zcmbVMOKTHR6h6r$>8R1B8nEi7E|h{2we?Y(ENs(Mii*V~qhjhbPA2Wh<W87Jwa|)M zf{9nrm53<1u%H|L11^FUZC6qd6a=?cD{fpU6dKQ+Old{Lw2PU!^PT&B=XKA$+yM2a zk`?8Prc4Y)BOwWjK>!GJYPy;xnWpHD9ZmZ}Z7oo21ep12cals-px6NL<@=SX$SS6l zQS{It6b~W>jauuTXnU$x*9P=-uBls5Wh3QCr#idhslB1ysU9M!Rz^-4W+tr<tc)v? zENU}u8}r*sT6ZtUuc9&PdZcd4zm2TMG_pgoZY+Rru5S(7prny31J~hB0aN#}oeT&# z0MCG`+I}aHP|bnl<Q&sFz=&A6T{RO$Rg)NV`87vkx>`5eE7olpUJY}x)5u&-r*(zc zosKxU?yWgjW7ybb4(DaNId-$LRJAu-B$leOTCISZk+ZhfcBiu~H3u!?*+%xt{AML$ z+9Bg$etFivHSA|&#*U(5*N{!$>!J7d^x@gdGcOwvW3&19baO2DJI&w~6R}eXPxN?K z4A)&9i4G5Y`MM6DIG*hFh@J5`hY#GXgQpi=E;raK0FQTJRmTI|^MS9zRorl6JNWQC zNVz<$5feS#-MO@ihsy?4nN*GWVSw9f0bD*&%_<~=7Y*FTS#s5#Gvu@`4Tc%88G#K< z;;?Kc(gQ~o!;EScF)#hY7$c@We2W>kAT!9A9g-v)29l4-=Af1_UN9?OV6Fy7H>xT! zF?&c>oBG2Pm(4|!%LVXgguRpWTU<CvlL2Z4Y0OVQ(DwT0^W3lS+)!i1;^UQM<Jc>{ zP_{gDVwUGVh378Jw3fxQXZj`_>ZqUg1qvU{o%F}_eEoAP$o&+MxrF$7c736I$wx<n z-29R0xxz>5-J%4I@nhv?difPbYiqJ7lKj}q=0bUd4_{^Yh<9wV(l>F_e~4b4#D5wr zQn$02_uj`2I?+(ek9zd(6NF~nbPI+R5Gn>ggCwZt@f9&Ije2I?t>q<ISOGf9(}({d z@)%qRxsmgJTk<s4>l)*fIH3w0>aBiDQGTgon)H|Ao|3I^7Y`n6g2$f)*LV{??Sgy! Qh`^1<@!KzWfTAM&28Rzt%K!iX diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_fax3.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_fax3.obj deleted file mode 100644 index 3818b96a9a33255f711946836bcb0e54a6cebc85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23904 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 H1n~a`gwQCd diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_fax3sm.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_fax3sm.obj deleted file mode 100644 index 806ecc748486113494f990a98194cee68cf98e9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100394 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 E0}_2^4FCWD diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_flush.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_flush.obj deleted file mode 100644 index 2a4cfcaffb7771e7df7f0653a0272fcb46a7ce91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1468 zcmbW1O-K}B7{{M+)^)5^H`~J=^<W6b`mt8#?jhZELpmtU?pm}qO|vsPFwV$)7!pb% z3(|BDf`}jp@=%w&)@?ztI)xAz2%T4qItUpEPR~1zU$<QkyS)5)fB)y}edb9WoHu2O zlN8Gsj|i|30)Sw@rYpRfZ%VYaHC>7Hbh&cr)Xj|gB@PQ00JeV5eT~-=kG!l$#$n+) zY7o|<or&Juu&#~i{6teqRzxG`+2;C_Y_2=fksDM6#mb90!_4#g*x6W4mC&28JtXe1 z8tteguB;KX5z&^(Z}D?jhBPJW#-aH6X>-gK1x=NRSdTZeSh}CwBtp;=7$O|FUG)-) zl%2?gI6=Iw5fD4qUN*=nnn1|PdyXJ~&^I?K_N{`bhIu?`BrBP;F01aO<6f=ZW!Gv< z8|~)wr05RE9X7VA{9$vdr6{CVXF&6!<VNlFCfikZ(j2~Rq|X*t5>(So8JBYF!-M8n zfUFsLin7~7vVCh)8}9bu+nXd&E}}+u^Ym8JB=HxmP|c+W?xcN*q2vIblYQwvANlhq zZ{8lt4Ewl#mZk9rFKgia4p3F#o&bE+ho>3_;FTZz4((LIvleJf52jKhx@?L`Sr-LU z)2E@HXeshVN%AJ&39wiPK>0aElGQwZUtkf}h^l#Lh`cV0$B2MyMAaT)vqZw8sk$SH zIDJC-%`Q*?8T%KT9kDY(+X~qO0sDvD+pxS(|BLNSg&m7wolJOsl_?Z0pS`lp&_82) zk4n)ZcmLk#iigew?9pIh)4Xi&tnW80TOoQki{uG#ZM(5hob}r?A$tGT`d(qv`hLQ~ z9%beqGhkj~ORbpJU5r&7Eu#P5M1V1aYzf5^>PJi(yy%G9iNL!Xhrnvk49^Jx=a1vC c&hs!f{n*X(K@wiq!qVF;wX~hB0vj*Ef9(G5$p8QV diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_getimage.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_getimage.obj deleted file mode 100644 index acd6476fafe2fb5e0b99fe2ab5e97475c8e14344..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35495 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_jpeg.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_jpeg.obj deleted file mode 100644 index b7fb8678ca611c61b06cea5eabb05f04c93fd629..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13364 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◊tSEfoa!5F>#k4&tW{T!}H@}(yr~Ib=QmH@Lg|- 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_luv.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_luv.obj deleted file mode 100644 index 2baa44337ec18f46495ccc31a66e62faa7b54866..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15799 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 E7fC3l-~a#s diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_lzw.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_lzw.obj deleted file mode 100644 index 6baebbb19df8d7e88f12ddb108d4be81d6af5c7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7571 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_next.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_next.obj deleted file mode 100644 index f241b3069afe0d2e5ec06637f16233586f543c7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1877 zcmbVMUrbwN6hF7Olq*)LtTAZNbjh|zSQuMzGD<R6xEOQ=w7qqSWnFD=p-H)y+}`5Q z6frj>wBHaOj4>uAdr%W!wz(&L1504b9^8zHizLQnN+6e*8Ji44!}WY0-5=k8hkNt8 z=bqm==lh*=z6mGP=&58>k<aVRahP%gfXlCH>6nu6bT&14UT$tX22=Y0Rv&kilxrO@ z^$ft;UmsoXc!EYqq_pNCm^y(rs8_v5JKH1unmVY(hCSV>w48}lqDK5(!ANU!OQc7M zr?Uw;lF<_}ZE$bgsFK9kl-ox0_AB0&-Q-QFlv;<>gCjq7P$80|vX*&ZTq^AMF=Jd+ zlGOM#dWP}n4(dq_u8KjRhV5v_D}^-gxR7Can8tdA5>dG$J0?ccYMe56uQ?K9+q$u= zsM{{GX7op$M&@oht)&#!>5j@-TX%fc%vk1#J~kq==CEd?R6B2WRLQ2(RI5Eu6LOMe zZLf6p*p7>i;%p;(Z+Vk(MQ0`BPOe=#x8LWaYeq*g#WbYbw>bI>+diDV5t@aLGTqJp z?KDs8{`4iNiiX59A$w<Emx#FQROpnQz8qbzz11i6+oS$qkjDo;tA=l4HqHhNwSc{9 z8v#@c0G~U+Veys?E;PWC(NIr!H_mT-WDJ}Xi<+it;&~ll_9+0)5ltskN&+txn8oGc zs^87XF)cpiqXxWGI7aGGQhKj^CUhKAUX*PdfJD}V;kSw8B3U;Po#ZxYuf4p*Z}>Jx z>#eL1w4{1tL71G&+DXwA_}_e+@2z_0qG#V3C|0OBCmC=}F6)QMKex7OFK6BS{V*~g zBQBbClXK$^l5_K0Z`|6PT+aUdD1@=V3c%DiNx+p4lui4h&GM5#*$~Ut<n<5#CXzs| zMzCTE3g-}@7sIC+F6G4yBj<wJj~nnn-sQrJ-4;3&ja5#oHdasSP39<(%08)7d*NC1 zu(BmAaATEfWh^-PY>5O)je+vo5*oa7-k%DNLYSNXUGOgRKNQZ|=I;t<3-kQ1(;wJ< zxpM8yO>~@g^EBej0^;Cwul-G4+~|K8^L}HlY`*WEqh-F{mJh5GX@lID|JPyM;f=c| z^MQNj33BaK`nASsHF{l-{#=jlF%J|1_vY_7rfSUR8L|sCri&pPA_pR&#!qe-MO0?I z$|tUC-{ULeGIC|mJ06_f{Dg?5M$tv25+`kIGxNumWs!i8|CT8!3aChamWufuN&@B~ ztkk-C8}Sf+0(x3Ui6~fCbabg4%f-4z{$#DkpGy-B_;VcHmnIH8M29Pg#T_WZ7can< zn_=#&zA(44FJ$}rP}sKO4{<A}@d<}GxY!EFpi|i;$JK<~?&(!^kF2QK!68o~rpG)< WRr6%xF(sW+WY57g8*(5>g8u+<1(KWq diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_ojpeg.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_ojpeg.obj deleted file mode 100644 index f460b3e6f8eb090a9cb4612df9ac57e72b6fcf98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1257 zcmZqRW#BH!OpDLYDo9P&OJ?X0VPIeoaLO;rNz6-8aMspVFx9g#0t>%DQMtSHx(!2z zAOpk8ca0})I6-ElWESaVFmzY~#TX>=jSZcxVgict(~A;w72Gm&Qj24t#>P0g1jm@@ z8N_(zCFhi;q{bANq$C!llczU6FAZomNUsIR-hez~15)hG%m--|0%}z)IB&xR^hR1) zYEdyv@OYP^HCQk?KQ9d=$OlvzmUqI24WtqzAOIEM00}@$GlM!rk7$SFrsjgoG6!h{ zhMYdp8sl^FlR-L34|AZ#L`b-SZ3TuK3APrOAYvM*la!b)%FF}Dv<=j+CPe$SxUyKk zq_Q9t968{~1_l-JksY5`nv(+xD>AgEq^5ywwSva15z&s02c~VHZu0C+OU^3+I~kZM zU#?3~wB`Y2Gf+~@1cxCg_Z=&{4$ghRv{wMKMHnas%A2UUni=HqX&MZy@gc4eAuP`R zF0Mefi(`l*3y5HIaS!qj4Pc3P3JzulVul&)3@hsx7?~KrECvP^Rv3$&gMncd8w1;a z=Ko9#6L=XI7}?@;(lYZ>faM0m1Yq`HWKSwiO)N^zum%b&XkuVwU<mDg6C4)a9V*aW zD$?!B(|x1cihun-<{#F-%Ow7nas>Ymm1sV~(R!eirTg$}4(5B-zsp}3ABc~Ojy(+3 zTFcWNE6{qoM5p`n#ee+kOGTK!hXHjWX*~8?sP#Y{TX(Gp^FQy4zgusYUV$3H&<*qk F0|1tfrnLY7 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_open.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_open.obj deleted file mode 100644 index 5731976aa3243b74620fe4142a740c5337f007cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4558 zcmbVQe{2)i9e?LIwn;A71aAw4(u0DQ0t=L|wI#5naYD&Lz{U0fYO?fVpJQkC**f0= zS(nz)C2EdaCbq0-npTNF$fjyq>C{b(wL%#|b!jVYWtED=epZCWm`$6uhOAI--|zFU z1oj7T@V)om_w)VrzVG{<-zCkGDkU23NhC$7AxK8ugb-ItLXHVii1Vyp&waV!@y%p( zDIqiS1q0IC+sNn=LbCrDI=^iZS_nnuh6ovb0(hh@(fFumYnN9}^vOb;+Yyb4sjh<6 zu9j9`*OrD&UF}jZriR3>loAr;zWdYdk-}gbbstB+Ua4`@z4(nLP_-6R*Cv0r4HFSQ zD9WiKGjn8B6J-VyQW%+wL6V25+fWi2t^&h>jJ&n46as0u>p<dS9Bn;@ijcXDcdghH zO9WB#-g6F$LOyTQE9C7Syrz`$N`vOTth5}J=t^%Z%yr9M&owoW+Nca9MY=e2u_0A= zzt}yJ8jE4B?n5;shN;)Bg_YfW*FpC{ZG-mx`3(mpg@z1!GW+VYtD0EcW>|_*nnT=u zZyo%Q?mno!BznP8#=W^<Pgh{v$LdLCkH2ld-|E@Z+6MjBC;d-a@nvg$YVV$a*V@zK z^Hl(mAKJ+)ik-0#+M8jlmH8eab_XFpvJsnEVOq#{eok0_`;HxLvYe3H4lAU(2ZwPX z2GvDuP$e-@Dl)}*N>nH_m>eJvQAwYuw2EOtjVYc)JSmH*R5T&^6hRS54O;RY5_)}+ zgsc!Z4hyoaQCSQs33(vz9ffu!q&~6)W%i0fs4P&8EKf`nBsEFM(HcS+TTd(;l|pdJ zk)yDi8GCO^6y#u}2^nz8F)R(OPgFV+A@MA7KL^~!c}r1IQue?}xsoYLBOi~q-9lWP zgFGGmJV-l{3$rT%78?MtTufC_TuLlO9;_^rpK4xMN~}coZ5~5{B0P%xIuNJR1lyh% z27}Po5Q2qg=yadTN4|dn6XbC^!3E6rlpg{Q9Yki?qbkc_cW>g*DDszsS(<!Lo?puC zF+{%rsEcMMkNOljnw&tSl!byGdU_p!(iGZLEdz=OtCviQq2DghX-@@`J|Uij;QoL> zDNF6CPG8IBUA~s-+vHoKeQi=GDoEEC0FVnT2>2Na*4pRC3&1`(s)&eih?L?5#3zd1 zM4;hz6;CXYqAJ_&P>Ftv0$)d98Dymvvw}+@B(Vt4+<wGL`2;K=#mi_I(BoDs)K$Q^ z=HvGn0hgh=jW*V}Xl!+!yj3yRbmL&1sXBaSpiVpI7@1V9##GKx@#m%+hh`cld%p2Z z_f$c3kTtqpBbSs7#=qac<vgjnE3WgPIZyGeT<yr@^EPA9U2&`9{Tm~f)DOxg8YihG z`ZC%ane+z`6+T0QY-cAS>e5X5_rThMtetEcn(nDQD?<Ai1}JLpnnzsetAesJeRYXq zPhYK6+_^6{UUHskX0*BW>c%(Vgdw^5H!NVxd4_0nht%am?-JnVmU<&U1JG32ez<tR zqn&dZQ{^eDj>wPm_{?`r(}aW=bDC*7hfi7w;i<-f%3pvbZ@zC_ggGwfBfkNqf~Koz zH~SpuL|y~oe&Q=I*)a_ndIg_1V0_qke&{3fCUvFz9N~=iM~K=qb>lL$8SSrhWSSZ6 zVxecWxpYkdBif*wD0SLk9Z_nv!4*VdwLy+3Hf?YXQ6Gr>>CTYY><paQM!>C)9|i+P zXPs_*8#`?)bS;gY0H==+Q)rEDj6z2ntS3sf(N?c(F&O5mGPHdjQ#ZH)p}+=xJXwIS z9RVmm-2)j93qg|+Q?(Cuu*88~rBX93`EeROv)LSoIL}<r&YsaeUGIGH5)6-g|1?-K z*Ss_hP1Pdcpfa(;F1+)pgftTZ6C)PpMQ9EHVVed@0WAUA1+)q1t3Y9()j-!X1fo+U z2rUiDInn4~wZGle&NF%ko7-pjSnZ>m+B+8A$L89Lm<6#Wn9*Z}8RZ&aux=>Gn%7M; zw+aRiA_5k3ZWy=_c>xfb0dUxS#5H`uIZ_SPHS1YqQCIal#<aH~5U=?<uBu6wMmxu9 za}MY5Um!5;IR{afMXEuD&&w2xDO&>yvmQ3B*utkfJ9F0X>Gt-pZlF1+q<5fMm&a?y zH1e`eE+6w-F24fwrr$E{@LMKod1ksE+E%_|!pmExyMf;e<9?o*c!9T0e2=f3{wMH0 z0p4dkbEVVIT#5LZpGdsz%B#@-70@(L7U=Il{{s31=)XXp`I(Oyph}=cKs7*<e#=ka z;~8@Na0NrG7+_%|HD1ui--BU4{3|8`D-sfsPfx$2lprkGe1eo^k%vL)_O$50bDkQ< zH0<@waQWR;sL7E@=WrB&#`AiIt8r5I)PZZ?ig3omK{-xkpP{;RMYiLqq^#cF-VV)j zuQ#$Cu!X+d*$1h7(bq3;(49=z<bg2*C-^j7tpj5kPOmUq2o52rcUV}AW}#I!n}KzA zo}w$L&8?%(e|?9TJ9`|&u-YIYjTc}t<9_Jr<6ZdH_QQMDvzSrrFs)&bGy?3As&rOR zy3^SuiUkUu#-w}Pvz{7<Qa?5x0hKW$1n<317gqtdJ!Bhx80>{AFJ)4BIHNraFx0ZC zb+B-f<{rv9%P{_uEXMRY3cT`<0i5Fo9Pe<XW3Q7nT)M+JTVga@OI^UcR(+>+9-79D zGGE{*GW1b=&l78Q%$M;x^quou%r@6poi9zo0b3GE;}KgNg^e_x#KobJ#*?@_nwvM8 zZD!L8O@Z;|+c_+=kmEdc6bp3dQ>-%Q4;Ds($8*^k7JPYx+oC+e)4DvuBfC7pr7Mr{ zaPFQWFK;I&Y`pz)tKV|M%QGhuyyNm~(0>#9AM^GT|KS%++X_d+m!N$Dj)K#C)x<^K zF>#HrCdaSg4IUp8i9W>^1||MHUS0?x0{1lfzz1&WK_1e4UJ1O94!t?jYb@TW$?CPK z)myn1A;iVuu1eOXwsLz^g-e7v_&|pHK39(l9DG-(K}D6tN5~#YL|BQ4T#(w~l5o)y zLjb0@Xo}k%*tLsGCZdue$_>OLNK!)KWVjJ>)KUa`qD<)b3wH?agYa>>0ND-VLY{+v zX4t^>VsJuVG{{M6yjPUDwIQy4)8Vy;A0hq-IE4QK2bWQ59#tARjsoF?92XQ0{ioDq p6257~P*v{$gbphBCkOcQ!KuWez4T8D<o~)Z3f|!yl5gN*{|}T?(@g*X diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_packbits.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_packbits.obj deleted file mode 100644 index 65f2b8bed416c0166851dc742c17c641f960f3d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2935 zcmb_eZERCj7(TaOyNp2#4n)I`qGBK=V^Bm~M*{2a1hHe#k3n25U3<%_-R*LF@AwEU z9i`g#h>)0w!I1D{{4h}=CMJd$vpC!sKU5}(L=5{OOIo@R5|&X|-Ss`E-6V=+5PzI| z-@fO(&-=Vz=QeIY^QB<G)8+NO+a8o6H9nN8MhF=i!eYoP_>ESR$@ogmhP5d5EJE3T z9(D?s>QQO|Lb=;LL-lhAl0PWcbfDC0phHW-<~7#3wiYqGSM+uon}Q)e(pE-pYiP8$ zt*fbR+bZ}%vY&5@NPe%l_vvgsLIALd?FQnvMKISsiQizDm@Wj<<y}A3S3($pZeEN` zD+e>nEL7<W3jv~>4<}s^x{jPA3PV}J5=9AZeVItjtci5;odoMuVhEXAJ!?ZxDC{Ga zPo8ry^p^5Qy+Yoez-vVMyV79!B$XC}0<Cm?Io5Tvjx};1vRXRO#na-@VneECUu=&c zhe9M*Phslk1Jr9>xw30#P1*y!4c1TRH{cT_N*U%d_vM~tmMSu4q!oiShh+K&x__n9 z2ff!tyetMCnazLAwwiGNcm>jW9NaF4#=5<c1G#atW3z@lbd9g?-0p1AcpB_>H7xW= z1^R5amQf)peU3ERl7vtNi_j?@(kW_1g+ADa=6W1ko0>YkA?PWjC$a-Za%Xs-J$R5u z2BNV0yh11_@KiI0o)3sTkLHujrjQ)zX!J_nHKpIJUQvK9;r2_@(0r$_>j0`EhdEIU zi)0I(n1>Lf^MnFH!4LNqIsvoERJ2EUujuQr5Cz;@40XR%2udw*&o#h3SJWVMMx$X6 za^f+&s}(y9Sgyug6~2b+^yjA31<Pdj5=Cb1igQWgBAe`!HMl>|s&7~(_hrp}p10p} z_m@qhRoHDvUYAzkyH}?4=j3YjJr`I$WH^vtnCy$`aI{)Iwe8Ae^16KWAqebd-_c|V z`Q7Qn7DzQX)0+Fh!Gv|5Mp|Gm?ctBeURsscPb)B0FyBBFs6+>IEIvUYhNX&~B|ExJ z$tEsl%|j&ED2rtSc30t(4uDjj+yzhkej9;z7R|$HTQ==1Bq#JA)_}@9l$mQy+s2v) zxpCqtuT{A5W@~aHHpe`idB)-#lWrf|qO#bE`XfhRKM~C`k`A6~d54KBq`5noE0`!c z^Zp(HY%TGEDA~j%CHDt_mYnD3VrL;!nPL^Lun9ZwB)B_Da`^Bqe4J9V74pj;gY)SO z4t8b}w-|AeB)p+NIs}y9Wq{pWD?Ad>aVAzj$Yp^E>WPlW;T2mvfO<A%Y-1^QQ%@&V z<yI<+l5vj5zgH%HOBu?WxkZ4G<_ZG{ZOS;uKo3BmLb)P5W}sop9tZv7)T5v;fDyz$ zrOH%7Uauq`9EL6!f?AXu<xWj|So;{(kw-!2+aE<a|0dxp*TwfwDe^jOD}dJpi3hRh z3XtQBDzgA8e>rjgu≷=d~9|m}zG=vqed5naWjyqjC~+Q-3N7bj$H!c;lZ<CrP!K zlcdyXT6WrjFfn+Pw&4!ag3zeYg3+qvM5$qMW!hGZt-|i2<wi_}Zv-$`-C}QrIm$Kw zY~rFJ*%#G9zvSnsCrx*g6Nj%(!|pCOccF|Mg;B1;C(7-NZ7lAgT)0B+3!3Ai{=4TD zuBg}wJ(F>C`Z?5_axuNVE>-W>E_LtkF3nlVr9JztON-9983w^sfez_<@(41JydG^% zOvd#`-vi~n>sHH1%xD_1cfc<MF)6j!$tqt-5ISvgpp8dNlb8dSsN^!QPU)KPFNuEA z+T;1n$F?z+`_UInBUXFI#{Wb)=25J6MJ~F^uvO~2rb)(KT<I<(q6HLVlZyU02Q5ny z>ntXfG>xAG4<kt9kFB8Gu0a$X2Z<vatE?fM&p%Ap+?UtRB({`UI5QYu3L*UfeLWa| zX+~N#BUOVG1I)qr5|A!a$p{i*I~ZR9QkdG-mL=-J-H%RhL^oe_sCw7CbT@<WKIGE% z9&=UP90qyR#g4KLW^^H}rLbOxRST;QRwJxt2ZPR>M}RnesW<Yzu%E9p`hyXlSM<Zz z!?--;H?|*;_=r&o8@=7(ApDdA0bVqQ;UAtT3;(Zib67I+LRjA0Vf4eN%oqrZM&Lrf MdV~u}I}k>H0Zr>7#sB~S diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_pixarlog.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_pixarlog.obj deleted file mode 100644 index 34314f1f1d205c185d2e1c8b03815a09f2391c65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15694 zcmc&*4SZC^wV&O)NfubxpeZ1Qx)iJ+6p+x0gw{ydD8fo4n=M$^7?NE!7?QXjh)PU& z*FbJAAZj00f2F3r5PUxSq+*Fu>kE()s8l0Tn;4+<z0H@48cW1QBK!Vl?%j`kXcMsS z<@Y<eGiPSboH^&rnVB;?Wr=K*H{Y3EoWDNDT~M@oW-hBpVvHp&EOHm*6y}-IrcXEh zVCK9ztYR!<9epcj6&_i@DsEz|lVubp&q|wrPlmf_wL536DLucy;kiepa?ip=nfJ_{ zIs2Z)g}DX3JjXq2bG)vZE><y*T8=A9o;~Q64!66oh??H4HobAsO+AhrcP{Uiw*|vP zXzR@@$X`YM8qx1n<~QafJe*rp=p@W2U{+54`<(cP)hgctf+RDNOV;hk%g^;v#nHfj zyz%IQVT8}icVFf(ym>k9)tA>cyU+=}P+Kl}h+y!N_jvR2x#X|HFs>_pXTfj`!@17k z_7FWnHdIbZ;mBCY*dT~_s!6pHQHv0ILMYUJ2oxF5%t7mMtz#|G;#LRS8NAhH7Zl}E z%b}YN8s;c+8@jD$d%RIi57Fq{`Gs853rI*9>)b&L$@7qBmiM7z2UpI}r&)HPub_Zr zbs0_b98TWrd{wh^2F)}?m50`s*RM0T(92nd|LXkD`zECrXqu5J=5ra+>^r>fFMRgF z_KK;OF~HGG?dJmp;(f<d7ME=`udwRUmMt<Pz35i!tvdP_zv#B*%d#?b*$Xo>1pxbb z0{eH(42_oY)C@rvr=$!lLC@H;@hm<hgtTnSZcSXa(_2))1UOqJIMx@l5!u$o>FH~8 z3SeYx7|%G}4hI{}lXn(n6nVUh9Jxh#4rZX5X1BY@ZC>wXhWtWjL5|n4xG>+F9my?s zcpP4qpq8-_Y9jNY!d#X_?K2<DS#_)1o%7H#XQr#j?Pa3~`;#1ZA&iaFg$iQmsyUUe zno}C37x+A`MLFJ_8x_(SimxkjrxiGI3Vp?FxZ1n9Fpmvan^O8(KDJB;2IkE16?oH% z))u=R9#4KzVWt;DVk6bc897)?Jj%dPJw4x1kf-FVaAcYJ4?9>QA5?BmVL^VOg1MSg zw>aFZ9lXKfLT6D}%#O7rp3&4M!Yv7q8M3pzKKH7k^n#)sFJs$BGNy^oE^y|9UHol_ zm)9h$Qr3_ZLSQ}A@V=>e2Cbh<i&j5#17lShorbY2`D~``CvsMz>`Ri(2DwR|Z+!WZ z5KOtaZd}Nx&kSXa6YKTmbv~VZD4-Wkr(ArnBe^d7-k;hJsZC1^vOTf9#XCbj_wFU* z%f2Mxa~oR5G&~%*s=V&ec)27=xU}Tmi{&l86HyXkeG@TY87F6f0ljQDq}UUUTmA;# z#F9keccBEvjOA4rim`UK<m-{={zmehHP#kuC0~$dI*`#xzHXlJ%f7SH9NE_)xplJ7 zFS+&NT7w{#7?^R}R-#!KFCH`y4&*c-=j)k#E=p4an!ccl;e<6H?CVxB15gL$(ic1D zDD3Kt<wpk1DcFved|kZrGyT|>eP<*$F{)FTZv<VjPA?uzB-~{&PaSH|p|49F&R6zI zgL*P>pX^JNd?!Peljv^pIk8Slyv`91f~AwJv>nCMd<J6g(I4=tO(9E@Q=W&kQ?sDB zf1@T=dMete^evc?+{z6}tUp0kP%@6p(5{CirkG&`2|C6a%xB34$QX>}t08A&?bT9N zPqXgnrjdK%8EdvfPib1o9BkHY4x{|W+Dx64)g4poOtZP8Y2vGB@z*oI^bAL?10rPs zo%6NO2&WX^Z1(pm_V+4I*EXBa^eR8oyIdEwv%BDy#Y6Gp;dsT)uGVDr$d;bTmb1;e z$HN?QrZwiEoE4m$g@VXv!1@xM#?mdDyC<7b5E;`yVE{YLtnE#!rtMvTAJAph)O=~v zv>UCO-4pPgh3^7<JyuQo7QimRZ-9FfxJG<W;fpq`N~hC&iBU(znXZ`a<7uH#sPl0w zIM5$v$9q?xKWI5#GIzyD<m5kDrOoD(y;Od(x5`Pq>g@bA&HqDs@i4g?%+7C0<uK!T zO;(p|>FRAg|L-Fwhx+(%Qtm6zI@S*<i)O#Ec0_MRJN|)+#6w!~uvRRAYp4U2X<3Rt zxlgtvN|qBL%L&<>=#;N^YLe1`GS=#r^qv%hrGJ8zz7nNhTBW)k@NQ;Zx0tb(iS-== zEks<i(S@i2E#TO&5IN<!4>+Yc>Pn>K+*)-lQnN8m!9f;6i;wCQB8yK9o$%@tODw$p zL@1JP-q$&X$nh!l!q7NUR~?mHj0x9+4qsqY6COH)Y-b6pW;Ts~j#c9~16Ba;2Rvxi zR6hp%4t)O&-+lNV!uNfA|Hr0j9dFgNCIglN9DoO`nq7|qza8J5`0l~?_xQr)?1IZ_ z8wFQ|HZ|8HU5NC<NN={OZYY7&;>H||E_RW@lI)%j<nhJoY{-IbgtD$F6|l0w63?>I z*61Sj=uNzGN66CAe`Skp*1<|!qRmQ=#;$E$e2ayJ&43*a-`->>>Jwh4rOmend~j1* zua!!A#DL(G9)=~Y*GVP8@)l%t#%<q;+D`y`mwCeH@+Ifw3r=Z1Drz+)utxwPl%|@J zATU7%qbqMIJ=obo8s;|hm|`=red@vuqkYz{kC#fifsZ$CdoF4n0mycU-Gjw=4M@oV z&SE?m+7qxqV2~;{7Qo(#p+EuU=S$B{rw!$!v$*8DLYA(m<el<tUi(w9&b8IWN>B6Z zrSHZ{e88z(t_uB4F7yq?+HsP-r*gtI72}PyE3}e5Na?#Z$mk?{H_vFJtNLx!n)Z@3 ziJ^gU8hejy@0ol$LP28>%J!gwP{?TP-Lkz~#lW^;es6SMim2h|Tn&TZ0xZQ#_Abtn z5M6a%B}%jg(Y_E`89GZuSYz*!?OiI9e5+jgV&EQZ>Lt4}N5)M)4WaX4F68s06NS_4 zil<KI6~ptxPCLI9;G|a*%#FWBo0R@3R#X0goNjBZri|s};tp%!cO#0ie~e66W%iGv zs<fZ2RCXgH>>opymG+M+?$%b?&sN+`a*I6(gjK0iDaYzcAs?$x-bbv)(NX^%NWnFo zGZpS5hk=Oh?4JyB2=-4Z#t%R~vfVh=NAbOtsC07~;~BVD8q|}jL6DvY&~AT&@P{mZ znzjQQg#T*{q6!A#T9w#!i|fTtk6ZYT3n$Q1_KxN_7lI=veagOFGWWEYdzyYkI24{T zcQl`A8d-pxSRXt!VM?@Nmy2PEUxTnP{!W>@PFgxZ@buAB_A?QZ%@c9bVBu_6^F%$* z7V{33oqj4#7}%@}$Cq<LD<$(W7b~M^Gyae};$qn5hI92Uohh7?gDx#Xis7OYE{#5# zYZOb4F|SE1Il{c-#gcmFO)3w06UCAf%sX5xX~f}|`(COwEaW?;P~p{)Jrd5M9kTUG z76cN05-tH9l$;1>8+o=-$znN5J}zyq!U&S<WQ$(fSWU^Ja+Y4Ie1Ve3QAOJRvuFkK zS-e7WomBY?WI8{CxhJ1bZb`BClw2d(>sripCoN}A*_%$8o0=!orl+A`LpxmM#*0kP zSjqL0{f!p$8(a+$O`WuKK`CieU#YgCS>D`pEhx80o0$o^(LL8R(hGew#jWQmC-O}b z34`<8x_IaQP$)1QI6gADQD!?IV!Ik_+Sd25YiPmlp&dJm&#+TqHlgM!o6z<>>>OrU zg|;8y`(u0;p=_y5Q}a`st|lMwAfO!ZB%lh=WQ(h52b{OX?bZMi0oMXvv<dAea4`A+ z(1t_Nh44<qXgT4Ol2&rgH}vD2FvPj;mEL??8Y_~nN!xgljAX+WMX<q=*^>RW7V~Qm ztYm++#r!G~r;j%4YMYkU>P|P)iB^*?XB~4&bMJ<{gBu#DVL+2E+4r=V_q2S!485H` zD%oFZF~1bf^(NqcPtH2R+d~1V=(|2b;)NFT3oYN@qLQd?F;|Ck{Ylh^Nx&*L)XSFO zyB8i3#CMrwscJD-!J3*U!f2TE8rc-=OtzemD#@r&Bxf~B+sUS2in95bw6Q8&=ZI8E zmdWeXOWVmbUqc5hx{YULx3JV-ECMc-g-UP3_ZG%V)5>5wdZsP=6uFIM%HQWmW5bV5 z#6O0NwYSbR)-IkQ9tesT#u+z@Xjv&8#8^X9wzlAd5UGxiwwT<#{xtJ&nQ)Hk0Y)Kx zEnp@<3<|!~{b<GlH;X}?SGe7G<9;1wZ=h_P7}WYq`-x=W8nt}%exe>2u4c8Eb_dk} zo9sh;O)tM?eEDqz*$nc5<l~>8OX>1zF$oW-VYs_!4K2}ceQ>J$-0h&$uz8Eht+6(J z)$P7`r)-;#K*xR!b4r;T)@VcP7KGN}G?lg?qhkjSahQ4;9b3bR$CLy-tXR^+d<n^Q zozH>2kgtc&t(8*RdhwC<O2H-+h`)P`7mu`c?79>Rt&~K{hq054wYC|{UAusC0a&Qk z3+6Z_u|6@mE|9)vp6fgcwq~X(u2rlzl-GGDhde7nH@SKSY?p*~qXGs|E<>><YziwC znUR(Joa7*Hx8lE)nJSmvM~SpW;-S<`Wf0|c#-G)RXEaJ6Q>^EEbja|wsTj8+Mp+q0 zht~Zau|sehz1qM;oFNZ<s6}Kc@I#zO-|dtv-GLc6qe|xPz!W*F$5?yEjJsR{Y%_FI zi0$+-{|Fp_Mgu0|urm{f9vSIp0B-|M!X=Hh3a$I`Jpecj_-_E*Nb84yj{$#&dwSFs zUvu21Yd2W6?W3()#AXuOZ@@R%rf**a++w7ywuIeJ+lIAYz?gYF=ITCz?pz5O7;8Nn zWDGEKz47JZL@9HrZ0Qz`N=q`<Xtt)MW~ge>i$RS~8@OK#e(9S>dZ=yUBXZq<k1Gi> z@1@0Y5!J1P;%32KK1Mwxrzkq4(@y_Z&|&9cl!%XHum{WJv<x(uni1(LcfdyD(C7)2 zU;t89*ZJEFW!_OCUw6pY6=ofAvu8fPRDRrhJ@7VI(9;7GQtD01>P|i?S%R`Tm}2fW zZk<iEpW^oWMVxW-hcwhF|GETsrCk6cZerfUcMqTvkP8UyB~KRe84$PIa2G<~T^+gr zO{paL@PRX0joHxo2dc1_oE)!~xnVi4Huh7c+S|fWjm4nMu_!UjO<wEwXO&v-3&%BC zhQNkiJ=Of33KQkSLLE8^WQX>W`|Q=rXXki(jn5EBjVTWETJ~9_coGc5Set>#dJ<BA z{q`}Sz_%$t!TCT$DwtyFHg0Legbz<YHJ01g8x6t-J#mqkfDft&CrXt>tPdg&GN2FI zf`YKOfe)(s;;Vd+9uvSdnaK1V*;4qRg(wZ}tw3?aoFQ5mrRs^uqx5e*G*7ftE?WUI zQd-7Wd!njefd$50x*86b%pGbJT+TA2WFas<Y#4^jBjO9OkTeTT6F)I2fo=V%xN}Gb z?rs*?&SzM4ye*-6u5GwK)2c;0Mq8bWe35O0UqXHx^3T{3{BI(C2<f*`_KD5Vnqbwo z!qw~=Ya7{m2VBsdfaL%i;BLUZfK_ly^R3#N+iVFne}QX)TWTKzH#7;ZX%@aewvB3E z2Amb?Y`CW9ZN~Q3twQ@p*d+xiWQ^;lFUK}byr}X$27|CDTYF<|(rr@K$rkg;z)du? zkWytGh9*qH(7p@gNIioDqC5Sjk+j0XhMM9=pbmEi#@a^2_35r4P1j#Q_i}8w`>~Yk z)qhiqxhZfnuhf@;$%Gv=2kBTYg3W3A0a*Yxh6R0Z7EZL7PY?^JGyn_wA+SJqA<^@1 zA>F6Y`4=}7hYVj~JyFK`siv{T+<0ZGksF=Uvk<PzI_s3iV3Kn&_ch^vq@iOi=3`f? zA<hV*WW<P#Um{(OqK>qfk6fvuI41~?aZYsDPw;!c$E|R%oxjI!Qi<FxgP9LqVf8KM z`YTh|mCYqO6ZY2>+j*<Tuf?`#G`2<8VLLP%FyAUvn{8VE606|1qHHC~D2BWauo3wu zkgq`+*HHd9tU@(Tc>X`3F2#~@%JXB(<i7y_q{FE%38%hkNY4e_Vik7Xfzx0Hwp%Mv zb}z~*fPV_G6Zw~ruS5DRz@M$ct~03HhPt1itQ&FWk??op0F!Y_Oh*28q%#5cS_PaI zwQWT>L9Rzx3Cf-Z{&~Q!kw@IR?Ksk>03BAL<{au?fFH!TcPHTb>}L2woIKm%V|Uw; zN9?<O17MR?*!_e}+x|4_R-tSc%4&f>2>287h=aFdYsj~HUwoVU#s4d}M5p&FwRUb# z>HLZ|%`l*61UAMq8hU$1ItvpEs5F3QGz`HrVtwf1F;s-P5az~e%5%8LJCr!|iAG2B zE1PKFh-aiTfB*S5G$Z+DJR`*$uGCigc}A}H0alBzH5m$GT&c-$PP$YdO_$M%kN)GA z@X>kLGt)0<EQz<vjY8dl|JDj!(<}zz172s_Z?Qe$=R}H(4&AUQ=<+p&#dhAT@iVx- z5paoP;1VamCBmgv-vF2RBjDk#um#j$`={~4P5DK@HmiW`pVt2z>b`)oU!x2z&<_{L z-Dw;07vT=$0i)p(C%`3s7cOx+T;goFOWF$3bzKqibY1r((r~4%yRE{mS5Wsg)WxZG z*I|_X6?i()QUERvE^$2EA^2;X4VRb#mv}4OC$^e3%TSgNycbZ4{Nu=1BmFX9zg4LD z1M0qox(K+{G^6Ys@R#5chruOY1D7}xX~m@qyO+UzX2E@8ySf|WZr_WtHvvbG{|oW~ zq|b+4=(U5`P+~WU^S@Ib<(y`)@r!9J){~Ob#gDaO0KWwA<4!yW!4ud3G_Tmk63SD2 z;7rJJX6SmSpxM{xeQ->N`8xyt)`6dxs2Qv><}dZxXAa!T^F7a{;(JT4dvP<r!OYUD zXAyppDd04t97JA1ePivM1D7BRLAe>7ZLB?yn{s2VTMM*;E5^kpkU=1IK;n9n-=i1f z`U>c7<F?;m9?>m1uG#3KlL#7X=RSbj&gpc)S%Qt)yeQE~5%zFYgd5Zd?MNARRlJOT zC5DT~Uv*lj4}KH+K@8WrL37=Q=UR7s>`>zQP`ZrU+CW@9sHf{Wx-|W!hXN5&zmZ|W zG4Wy2ugWmY@<9GpPiVS5Q8+KWFC4~=>W?FL*$Ol2c$HgN=d=aIJOvt)78HveTJb|% zS>o>Q9nb*1gSgC5+AUEVDs@oQ5qqP@e^6*2C&OGUiHPtvn7io0HN|2uK7O18e*r(_ z`Xxk@e6(`7Q#LGdN_yiyH||}Jg09CYsV33`BpD516zd2^k1!Gu!Vv~_U?g)rWF8kV z{w|n6y!<xMXriFG)ev4!X0y*77bzf{p@QMC84<ft1{W$+kAO>ryYs_ERbLAi=z=@+ z07{VGf;@I({{H~{)+$ujq3&VSeFtSH)VTi_llcuXP5;u}ozwY<aTj>_vPMkfQ)Qr- z6&>T$A06?Z1k%rqVg?(Qfu74CI#ilD>QG4rprr~YECU10n|<ztNC8b6YB36vM!8_- zBie?WK%YVQ^iKJb@II|?A)$c^9-Sju_;vBVISRkCaaZr0HurWXesAcUH1~EG%N-*9 zy5a-XH<m(6a~7+WskHoP=|{1K)J-uEGo}v@$>OTuSsv8=ny73rut1H<1_N`r*9``4 zh(u+V!B>G^Xf}*8^h)n2bmzU$lNubQ$Y^p%PFs&dSV~FIxV09lQ-gvZYTS2;9}3=S zcOV+<4DGE#5#o&D*q@=}w`x#Njr|1*LVK&jb(FxLq2p6Ts3<<D1pWexLwjEcS5cyV zhK?_LcomA;MF+6%>jtnBB!o*!c#gBZWic&1OV&$EQW4!0>Ja{36C2vXuX+(9^{l`> zNa#k_PSAGY*#MW&o*3a!fNK%OXno0aU4z(qB@ba$P)Hp=^yQ(Jl~h#8qwPzUQl0I* zPG*Mq$RhS&MV|;E>D8x~e@W`ZH6r-Z#f04Sa!_u7J-D@j+43f$BWGr$9P}=leo)#( zo!Znc5xznw4gK*-h^Yl8QM~zwuD!s!(n+NI`V2(B%=c878Gc!y*q5^*b%vhdKd$a0 z_bw`f;od|FGfJDPh@YpnQ+mfQC@oeY4N)d2!Sj`}SWT{^^=SmqUbH2&A?Q|fKZ0ac zw#2qqt=hKNk#9i$W83K6^K6N`b8MsA%Md6lN1$vw0%h;muG$^6#VH57>-*9sL+RBS z1)qB%D9qdoK@s5?#Cfp{2#t4w_^6)w3=zSv3=H48B=s&;wrT5Qny6PMxGLU3DpMsA z`3<=8gI)Ou_C^~!M=}kQ_fj?Q{bJ`ZZ(L^qdBB4@d0~&VsRCV#kLa1#e14O{#sb)6 zdTMANm4vS!==x_$Xx)lXvI{@XV6K%Y3+?T#%Fan3%T?JqHl_m}xep?8|3_*wrToX! zz^@9A;JXv>Ux2>>*63YYG*w22OQ$s&S7vO!a}#K+N&NasfxLb-w7tm$7WS*rr=x&r zjj2yBLT?)9(?;sN!&E&41o22n5_=-N;>K+$<iw>BFf7l=4DBET#gL*p!u+%t<Yuh! z8v|TN|H5@NRtyY-Co_qMb+WBTE+aKa+Q4_hd6FmcqilCA4{hgx_Ig7gj`tL$ZP%~S zx(ZM;B1$|MxYpG|y5pB4vAQ$h24@;rchQDXwYDyaTTJ<R<73^x@}f1Woh8>{98!8g za$UnF;s#DF)FA3WdlfEQ8$>-)#aB~m0#emHH6@ao5lI=4dI0w~4Pp{fkKkQIgE$VU zv6y2Gq6w)5*HLO}BsDvdnv2x)yxsz&UPnrPiX4HogGACGQu;@DQz6Ub5~OV;{RWZJ z&rC&%n?3O@Z7M^FszzJKpZ|uN3Po$<T?q(1^p_Uf`4OugW{ayH510;E0I&d@wyUe% zwxsGZq&EY0*uI6>{g_sU*nJ#aPogcMH5CUg#Fkod_~XB=%)r+QSb;;C!!~x84^Rns z7Vr|_4Zz!g(||79So~6AY>m-2u4a<$nzk3=w)WV@x4i)ub^z&PaA9ZgtB6asZ?{jt zLF#(|#P8bY1Jrm{JNju~1t<U@eg`+FX|DwQ4DccVht1vZ+a|Ps2>161+}{_r1XeYI zX}*{aBO&u*RkP`U5q`FUr!~G}^^s8+*C)%Xm<#zkq;Qo!S$e6|2W5*q+F>*|V*i@a z|Cm0w4}hbmIk8V_B21ccqpyTac<*z)*W|(z)dGiURle6_%5xNZU9<A=8p-4=a^r<5 z)nAognB&E(BGXh}Jl}L(-ZXaO%sDfY*>xV|JnXtWYHrFeEcSU#g+*SI$5&j8XHkwk z;7s9>^4eS?cqC=QBh(_d2|ak!XGb7AgA)TydIhS~Q0N17C&)Sqi+rnHCeB~)mZqs5 zdWQuXrd1Dl9iC~tGrSti&vOtm-^2OJF|EZ*sr+J$x5#Po<gBGsZjrChi>}c<r|fn6 z3Ul#*DsN^)Y>FP|n|y`Qk&(b=DI`cFk-A?kVpUA^#wy2+!N3k63D4!pa_}No%n2Qm z#3S+?K*W7ejM4Ki(p6Z47+Rhq_xqk=M{d3|KiA~VS?w`7bMT5RkKI{h@)YOfI>>OM p4LtM`&9n;7^6uw$yK@-xZ@`5f{r2JcQ4C(i0P`iI2FS2n_P;AUC%6Cr diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_predict.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_predict.obj deleted file mode 100644 index 1a2d2276c829ad04b28b4df2f62cca6213b3d0ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6382 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 bnN|0i4zuFM5_sVB?RjLd(rF+Ri$?wfEDi5} diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_print.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_print.obj deleted file mode 100644 index 3bdc51dcb58e3ff2fb8a62eaa06d4b567619e87c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9579 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 DBWzOD diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_read.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_read.obj deleted file mode 100644 index 34546af2fb907573d51baedd8b5f9aeebae977da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6820 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_strip.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_strip.obj deleted file mode 100644 index 0fe67ceb1b650be017d6af4375e45dc819c409b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4135 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_swab.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_swab.obj deleted file mode 100644 index 6da888d1e40190a2818184ead1959d197f7e314a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2463 zcmbVMXIPS57(ToplA)3-Q!8zkrsm4jhC3^h1kDN~L{JLB7?PDXh(g|m?VYx_wzI8S zmTg;Bw#(9N@3Q1O=M}#C`te=bkN3Uq>%O1+d7kr}F_jL?6e1y4uHq%R^MTd|0Kf>5 z%EUZLvU8}btFy1WzZcM215opOV7%mP5YV;)p!W5&@}L$dL$XNbo(i;mAP4NF-n~Kt zI82!|MaD~Wju43ja*iP@CnSu;@p1R$L`nE!WwL-HS0wXfDSzkXN`x>s^7^B?Oo_K= zbLxtu$Z7?xozpJ|p+N{U1TwjiJfm|7BuKtgB1EJGj6_SPqDVwA3<M1kjoJJRjkq_t zku*UX%GDbg;p9A;Y~+fieB^BY%%PFjI5(myoLe)h$`!wM8akV^(=w5S*y$j{T78<l zR(Yn}Ly?&-AU22CY&fc>Z#Gw=6pPWU{=%9p5E4}b3_I)9<fggsY(w|o)fMt33Zi9r zCu<AFxCGMCHA6>HM9dJ~zOsx;;`YI_myW8Sql^ydf9^CH^}VDUFyXSp6WEl{n6Pk& z!-Cnt6!fEpMaIU&F)7>-7K;o&u*?)}b;C#)AP~SPCI$pdX#lLC0;-;@$3U(*03<3` zEEGwS;j001;q4%qCdman89y};5wLNRIXfyMf(2g}R;pB{$VN1LOh|MiJwz%=$wjOq zWNnOWuuR6wj1dx^0;INus@)$dTP8|}4@)J|9iVRghmKMM5)^HrXkiq?q{<|*z!&jO zkheARhLVjk8_8{;Y=z`Vfg(hth!te8dC;mwnjO?Ekp@}#VhErv&x1m~CkFp<_)Av& za6FEID{b&_I(`ceuq<pKe+{h9u-7YTEPb54`V>u5tfb(jbu{w*z<O1UcQJSLsKio( zHH(fXGBi~RH~d3IgJq%8hWsTSI)5{k)mdqZv#EHN4Y^@(MZKm<dHq)kJe;Oul5{lf zK$4b0BqbO!V#r#Cj*01@G7!@;NrsZRl8#5y>MZdRbqR*N_SyvK#mm%XdQGva=HK3a z4<w^RFcABnKu463qGOU#prJO*3_VPeG5cL(c07?b7Gu>M)$8>*8D~-8lya<dLMg_< zpyG+NITSx8t7a(-f_j}f5lMupOKJEe)Nr}#g(0Oniv|>?MevM(I+G%F92ysV7%_M> z9nMAljh2z-U8S?vIXP(UAxI!0lt4ldBOrz#nSf*jDFmb-XhJ{}1gQk1B4|oLQ*|*- zU5g5+^6JbW-&kS*ep_9l*Ho!q!F7Sv=Ae238>?OpzYS~*<Wn$s^}y5t#m@O-9x`&7 zS3Gy6zl9rjw%eA}8vA7lxBQDHe5K3?JJo4J@>82d?CU=J6d&ochg@*mA%5w!igP#U z=;R;R^pKMs)+If*S`d5HYme-`nQqXz9^1yga9A<&PQc-b->EYr%DQY4KC@dAf79<k z#%GJULoc}(NM5&FGx~nN<Jk?QX~88fYk7}a%^z0LYxnqfEpnpDyKfcMwpl*ncArC; z-%K>&r#o*HRNF3&yWzWE`N@1v^u?Y#(_Xb*op`VBv8<nDb!chF_53H+3t88^_sT!C z#0Q^u-9E0)apkD0z$26DO=m@(>AE@PdF!RaD|;VQeX*PubJ?R%`lfvz_d)*?Q}lp@ zktrrrQ(6nNmUMFqOGYazYa3g;*7j{29G%*>YwzsRp<}1cUAlJb-ow?cr@Mz|FE4K& zU%%e|eF6f5`u6KTAUGs6EIcA|VAP<&L!yVqFo(sm*m3d06Gn_2#Yr5^9m7lF!>2hV zRWx>-I87o=A1{+Dlo_fCnG+{X&dQ!Lb=q|G49(10+8iA|d(PZ>x$_q+T(o$}(q+q6 ztX#EvO<w-mb?Y~5+_ZVi)@|E&>?|nUwR_Lreftj_EIM@f$kAiRPZXD&EIoC)?9AEn zbLTHyyma|W#no%qZ``cBb^A`$-Fx>RJbd){$<yj*&ueO5)V+N5`pw&S?>~I}^!dxz QZ{O>G{A|zz936sx06Mjt>;M1& diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_thunder.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_thunder.obj deleted file mode 100644 index d3909ab482d5b1988966b1bc18a8ff0cdb6120cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2100 zcmbVMZ%7+w7=JH!Cf7D?QtO5tGR|#6hpTm_+pKYa{1b=UY-PD*Eyku<axsB;Czm_h z!nBq%5c|sT(-?z7KMnR}rC&xr#wxmfnk{2<mX<M5%rZvlzy{*HJ@4y@Yhe(5;k|qA zd7t0!dEV#Gjk(Z4Eg27M30;m!YC{xds}Mr&c12A^<e1P=UoX7T(A<Qw&m*+<jBQZ< zz7=H;Bb5K^>JP2^2v01jHY8B?6zEX3;(5KJCDf}b18QVY=t`!fbjTtOwRieMCmR|= z-EuUg$D~kNi$&Cdy<x+09JmR#nfUFMJ&n8Zn^Xw25}<WMKeq0NYs7~oHNCBzzgFv| z%BUj8iSiIwlB?T^B~iF71y2-PY;RhDG?X34pfpIh-XcKA+=;S*;gk|3$ld20fRU}d zQLm7<U3g7vJCz3HZYr%NWm@T0>#iruzH9n&`h<3QNTS7|#fDUsU+l1~r&1(Wdw|BI zIQ80MRko?@pu^DHfZm(mcvRMC$S{`qZ!gq(on*{ND<)|U$@I+)|3aq^dT)q$c@A`> zL7$y$mW2MrF;o#2eP>0k<4mUy<jyv+jUx|x=ldU@3G{N|cE6v6jlOiCZ&qxK4N>V5 z;wrWzgd99VU)hn}WKA2IbRnnM-PPq&RYmn((h!<Dh!A5Br{YOD27ePY1tY^aK21vz zHJb1e#S5S~LO|VeQWLj+KK^J#o&{$&@-_yc0RGb-`~(NwSg*o9Ctk!YuA7@|(OVj> zHg(=_2C9u&K9kcqJX7G=hu+e~HBT;lzOR4Af{r+GzdLhZdkz16chhxKuVSAB0r?-` zT%j_P8@1z+Dt7b3yQR#1{ihuYW47oI;vOgV@pvi(aZLm^sC<FSMNiJNo|hm}9N2Ju zS84h-%$_1%y1JZ$3mOGRtuYGkY5}A0o@;!8sz9g#`+Orjp3K1mX$N@5le@;Wb$w89 z;Kk`>?!XND*sHro4rT6*?$0u9#viuKy({bOI@di``^fmsm46I4yfj_njAhm+*|Zl~ z?mDOte%J-a>obg2!82_ZUG^w3wUukSW#=0I9Qd|rf2Oo|EZU2BVfuG2d$=GIV%Au8 z7$uIz0Dr;%kHNA#1*FvOY0{UrNsr<?_~|2ub!3bb(da(NjB9do(=<sTdNwAqq%K4b z6ep%gUBEzl$JE_WINrRq2stLnblfIwSg5$Iz^gaWNFojJW)n5i0Ja7iWX#rha$rOX zbH4A~xt&IG<9;6N&Wt(wvYBoU`qv)(W17aSlXM?Ij$q>>AgM31k22<!2b5sD5h1ww zu^KoXhdn>`iX~B-{uy-rI9fR_+E&iO9*2Dk_OGIC^)&1N>^{-<wH#zt7er=tNo3HC z&k!(>MWQ6jghk%un;gNA(*+TlkSMyW0qc~aN=#}I>e50iqD6#=CZu8JQb}17>QXV` iSY1jNYTpJ~e-)ipG(nOTeIS8EMG*$|XacfEJp2o}+2i>D diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_tile.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_tile.obj deleted file mode 100644 index 1194a0f5f5fd079befb41dbbf320f8df3923d623..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3520 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 b1eYj}h?p&W{yxwObG)C&yD>NdKnnREmP9M< diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_version.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_version.obj deleted file mode 100644 index 4b3920df3a6a89128105d0b4560c1b151011a69c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1414 zcmbVMJ!lhg6o2U@X)OJSB}&KZAXFN!O;c;qWNAJcf`tb2p<wD6FL%w!^)B2;B}1#C zf#5BjL<FI$i(MTHk*bpv1cic=LrcZQL7~w2{+AP_E=h+w{``2q_kQp5!4M4SqQI{5 zswOHj!$HFb0N$9QN+r2W$H&L%%S>nr8s`D_PuLdZcTs4Z1vvQr@O|_Q@lzI6rUH#H zVlbiv1M%5nMpc&8(h5B<O1xII9T#JXY;l^IET&~nGRk~W)5|4w`E*=X7SK20hDh9u z9GvVXuBZ^|Fj6m6KScX54S|&75BT=UXv6|JMHUD+h?XREH?bsu*9JTUXnUKng)kip zS>acRuPcOzm7D08$Vv)FnBCVLiKTYktf*MGE~0As-%ca5n@+2uY;`(n=Q`bSu3Al- z&}&uRYL3-xELG>tW@ST?NUcsmE%SmEb=L0eRL7!OoNZ*EF0R1Ix+NLc^5E6&(MUg8 zGct;zRYS6UJFB0p?Zertk|^g8BLjMJvne9|=@_`!T=GWF8DC5!@tv5<%{j@>ok(3< z%x9czESsh9gJ-?)@-aAiz<S*Ur>p$}==A_RcZ0h{wR&J<0Knm9B|((ScspPN7sSzf zN8?K>SBVe+1vv(D>G}B-uNT^vW*za(1~>rn=C^F&x|#QyhR;m)o1e|up{--;SLA4Q zq-A)rt^CNNH=g>o;WV3v9_mZv=-z&Co4s{&scBQ!`pqS8eNXqBKX#9YwhSNjvw+Nh zh&zYF_3d@Hx#pveukIez_l%FWi`PVP6JEIB>-}60Y|4P?E~H~bt)I5V(m^K7O!vi= zYE2cFD>^;KU8DoyQ0P)19G;=Gc-<CwL6CU$KbvsCwh<)}yGEzfQney-nxDqY#{ifZ G4t@hk*we@W diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_warning.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_warning.obj deleted file mode 100644 index 226c2e15aeadc1103fecff9d88a33fe93cf60013..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1658 zcmbVM-%C?*6hC*H+pVTvZOR^sl!yXj{;bTc2X(Wg2c^5spxJG0ce=RV$=$u04@xD2 z)lIO6B7(x8mtK<of&|6vDTE+F=p_Zkh@gi8Ve5RqyDKptHV5Bv_}ugPobx?DzIV!@ zRE@`k(Xb-N<pEa&(hdONIueQ$mZLSDb#*moT&+!zt_IlH<r|cjJdmyc*!+I?gXaLz ziN+PzAf(SD2F^rtV`p2aS4j*g;h~zYxFjY+hH$9E%ZFNA4WVv1B56@ElvJZ(Wnh0? zL5`s|;kJ^vy>fFyF>&JwLajvViQ$i)gLsYDh^Qp<;QI%)ZVE;ca*Tjw=t-__C7uM} z41gs-PVKCbh^yd4hQuMFb&e3Ra`goh1t}3B%;IZ~#Bi=|G%D7uh^R^RU#F2-Os5qx zX_&FcxNA$ncTJ8Z>(#Mgkv4}m8%tGqvjtg`BocWa)TkJvQQM5pHWi$-fU}M4{l$$% zWR<3jYq|O6My=aU){Kl|oYs(R-{Qz;x_vl%!z4--Vq`#fZ?>7F{^S&t2!7vHzooOs z>qFby?r*n{KdblRm7YMaMd;vpGah(qgV)Cy#st)|fTbj70oYi8XI8Lg%~=yXtcJsa zzq_l;ctkGY!y$<Zz;r19V-=)WT#n+S0@JuTjO}Jp3@edAHvx_UW2)YR>$|N|!Vx4? z5oumj`*Kf|p*}(A$MCar&(A3Eh<M;uGlz(W!G1+RtPfMR14QSqh|ip47=VEOjSu$e z0Z!K(y3ek!=xyb*8S`)V_J}j9v3xe*oLpd2bDBk;-(t;Q+}ooY&2z%_YyI;Eb=<D^ zbE#GJwElBBQ$DLX%)f%j+(BI2s!YvISoLv-Idge=JGH8P`X})cQvp4|-p4cnsOlaN zAJjE=s-K&@K)gUL<FlGQn5CS_1$!RmD0~a@AGp7H>Y9D3-;wttbnbt8MGnT~4PnZM x=Z&y-FUYLvcpm#rYcKG;Mf)9|CA3%Y{6ISsWY%qd)4J1df*BTYkmye*#vgO`AWHxM diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_write.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_write.obj deleted file mode 100644 index 7b22eb8973fe32023f3d928472048e75e261fea4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6475 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 a=q6JLVoB*`Q$ZNN)4B!^jm>mw@BahdIo8|& diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_zip.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/tif_zip.obj deleted file mode 100644 index cba16eff1479470f7457d0c9849ffcd229cc7d13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3748 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/trees.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/trees.obj deleted file mode 100644 index b0bf941734103250f8a3a58a884ddb4ce02bb35d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12422 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 diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/uncompr.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/uncompr.obj deleted file mode 100644 index 2d22cbbbec21fc11360fe3e82043478cd79b8ad8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681 zcmZoLV9;~6ig652EJ{@ft}HG|%`J}c$xL!d%_+#pjEMp=W2$n1L}^}fer`dLUNS?6 zFarYvzf*ouPGVk)g0r@^f~lS<Lx(v7!wXW)n#1#4kD<eaf#K!tz7%~Oq8w6{oS&Db zm%-3s4Ahp^RH&~_oHn2*K)TF;x<J;F>}zJAMuuq`46N}Xt`Q+D&i*d0K(>oxh$9P# zU~_Q~@(&GQiFXPPW(H!08SD%zcQG(BF@RYd3@oe=76Su22Lr<_HU_r;%>S7fdQ=#A zGV{`M5=&A&^D;}~8Q7sb1}-SWH7|vMVS*q710xqS5>ktcfl<J)U>^e`14C%{o8}`Y zg2TF9MY>CQx<dszLr-*H=nOq$eW-+M$M66D|G(@7D(?2>==8nPE!KUg)Afe+g%WnK z)az2?OP!%Fj8As@zR9x40GZnBdLrNjh|zq6r~5|h?Gl#m!>|3aSb9TG1VP0)x^Fc9 zW-L*ID~)Xa%~ZnE{QGw)Uw7!4)=Q=AJN^PKek~5vD%>4<r&Fxg_e3CAcVzdC?!$4> z-A`i=Gt3obc;XYnv?Mf)aY=3%(~^cT<|V7cm>CxEFaU$iP|rxu5af_<Acp|}(Estq diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/zutil.obj b/3rd/Imaging/Extras/Extensions/LibTiff/Compiled/zutil.obj deleted file mode 100644 index 5dc64c82b4eddb520233199a37ea033b9b55fe4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1784 zcmbVM%WD&15T9%|4>X$ifLc`8gNH~YeFn4&Hm{aK+SD|u54MEu?w599vs-t!LgS^l z6ap)flZaU9p$7%gOApmku$OxBaT2_E=%H<T@IR>YrD^n-<na4;zS;TB%+Bo0au}|~ zhxq7SK_}eQl3|jf!KdWe1W^{|W&Qz*d`Y3lqA4q35z6NPz#r3eMNlO!9tv@ha0JQ` zfZg^y-PyR<1LYxrJqX?o_G1#0ne=ETI?j!ZrIJ&8ES*V3ClY)-mK#eYl9>oUHW5$d z5=oxux~hfep?tGJ9%zGX5J4B`J7${_7K5^{H)8j;5xYo=lzO8<?Q4UYS2VHHq>(Bp zq~pkjsdpL~sj@mp*`4$`uP!P|$7G2V3`)M$sP<qx)iz8C`JI3EF?$e$|9U3%v^Zm; zrq+WFAg%D^VNVEiZecVVza$N2zgJofRv&0A5T(&!Y%#~<J>WzdJP(2^pH1G&vhj2x ziE<*Ejk5G`Cq^^r+$5WiO-(rw@WKOc55U1dU0Mg$btD0JyZ|rV;68L7GVs(7?xLXJ zKMQO@Cj_A4N0zsg$FVOObGUt=au&dGlCGs`q8qZN)|FkT3{YiUD=x?i8Bv5e16@Pq z6uxnnlDe+xuju_W-aRE83XHPx&p@Q{e&T)Y4>$leU!%BHsSH#<u_#&ljM+sGkG0R5 zu9|na=C!I!&1qGgAL|BtjM;7B;j#8u(^ETPRat7{r6#_nkM5?Ax=DbVaMYx?>E-f& zUVK({xaM;$V+J*stBMaysgkn~HnEam=e(iMHoJl%%-{>u+sS~P^V#Fxl`p2--VSX$ zzxzLY%j{B<`%N3)<dFg$to)eSg4Hvy<H#~Q@3PGL*J;Q4?`a0s-T=l3A`h1x#1RQZ z8o?uICmtiph*gA2h{Q><XktGEeF<>(iBRN-DghL*9US&g)0^u0MG{P*p_f%-u~3jj znW!d*i&8@uv#23@(?G<&3Z^`Zz8)R-y)WD!?!yGG!VX~iEW(TMAp(f=hzp2I2o7;2 J%YaP__ZPC4BAWmJ diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/LibDelphi.pas b/3rd/Imaging/Extras/Extensions/LibTiff/LibDelphi.pas deleted file mode 100644 index 03dce376f..000000000 --- a/3rd/Imaging/Extras/Extensions/LibTiff/LibDelphi.pas +++ /dev/null @@ -1,371 +0,0 @@ -unit LibDelphi; - -interface - -uses - Windows, SysUtils; - -function fprintf(stream: Pointer; format: Pointer; arguments: Pointer): Integer; cdecl; -function sprintf(buffer: Pointer; format: Pointer; arguments: Pointer): Integer; cdecl; -function fputs(s: Pointer; stream: Pointer): Integer; cdecl; -function fputc(c: Integer; stream: Pointer): Integer; cdecl; -function isprint(c: Integer): Integer; cdecl; -procedure memset(a: Pointer; b: Integer; c: Cardinal); cdecl; -function memcpy(dest: Pointer; const src: Pointer; count: Cardinal): Pointer; cdecl; -function _ftol: Integer; cdecl; -function malloc(s: Longint): Pointer; cdecl; -procedure free(p: Pointer); cdecl; -function _ltolower(ch: Integer): Integer; cdecl; -function _ltoupper(ch: Integer): Integer; cdecl; -function _ltowlower(ch: Integer): Integer; cdecl; -function _ltowupper(ch: Integer): Integer; cdecl; -function strcpy(dest: Pointer; src: Pointer): Pointer; cdecl; - -function sprintfsec(buffer: Pointer; format: Pointer; arguments: Pointer): Integer; - -var - __turboFloat: LongBool = False; - _streams: Integer; - -implementation - -{PODD} - -function fputc(c: Integer; stream: Pointer): Integer; cdecl; -var - m: array[0..1] of AnsiChar; - n: Cardinal; - o: Cardinal; -begin - if c=13 then - begin - m[0]:=#13; - m[1]:=#10; - n:=2; - end - else - begin - m[0]:=AnsiChar(c); - n:=1; - end; - WriteFile(Cardinal(stream),m[0],n,o,nil); - Result:=c; -end; - -function isprint(c: Integer): Integer; cdecl; -begin - if (c<32) or (127<=c) then - Result:=0 - else - Result:=1; -end; - -function fputs(s: Pointer; stream: Pointer): Integer; cdecl; -var - m: Integer; - n: Pointer; - o: Cardinal; -begin - m:=0; - n:=s; - while PByte(n)^<>0 do - begin - Inc(m); - Inc(PByte(n)); - end; - WriteFile(Cardinal(stream),s^,Cardinal(m),o,nil); - Result:=1; -end; - -function sprintf(buffer: Pointer; format: Pointer; arguments: Pointer): Integer; cdecl; -begin - Result := sprintfsec(buffer,format,@arguments); -end; - -function fprintf(stream: Pointer; format: Pointer; arguments: Pointer): Integer; cdecl; -var - m: Integer; - n: Pointer; - o: Cardinal; -begin - m:=sprintfsec(nil,format,@arguments); - GetMem(n,m); - sprintfsec(n,format,@arguments); - WriteFile(Cardinal(stream),n^,Cardinal(m),o,nil); - FreeMem(n); - Result := m; -end; - -function strcpy(dest: Pointer; src: Pointer): Pointer; cdecl; -var - ma,mb: PByte; - n: Integer; -begin - ma:=src; - mb:=dest; - while True do - begin - n:=ma^; - mb^:=n; - if n=0 then break; - Inc(ma); - Inc(mb); - end; - Result:=dest; -end; - -function _ltolower(ch: Integer): Integer; cdecl; -begin - raise Exception.Create('LibDelphi - call to _ltolower - should presumably not occur'); -end; - -function _ltoupper(ch: Integer): Integer; cdecl; -begin - raise Exception.Create('LibDelphi - call to _ltoupper - should presumably not occur'); -end; - -function _ltowlower(ch: Integer): Integer; cdecl; -begin - raise Exception.Create('LibDelphi - call to _ltowlower - should presumably not occur'); -end; - -function _ltowupper(ch: Integer): Integer; cdecl; -begin - raise Exception.Create('LibDelphi - call to _ltowupper - should presumably not occur'); -end; - -function sprintfsec(buffer: Pointer; format: Pointer; arguments: Pointer): Integer; -var - Modifier: Integer; - Width: Integer; - m,ma: PByte; - mb: Boolean; - n: PByte; - o: PByte; - r: PByte; - -procedure Append(const p: AnsiString); -var - q: Integer; -begin - if Width>Length(p) then - begin - if buffer<>nil then - begin - for q:=0 to Width-Length(p)-1 do - begin - o^:=Ord('0'); - Inc(o); - end; - end - else - Inc(o,Width-Length(p)); - end; - if buffer<>nil then CopyMemory(o,PAnsiChar(p),Length(p)); - Inc(o,Length(p)); -end; -begin - m:=format; - n:=arguments; - o:=buffer; - while True do - begin - if m^=0 then break; - if m^=Ord('%') then - begin - ma:=m; - mb:=True; - Inc(m); - Width:=-1; - Modifier:=0; - {flags} - case m^ of - Ord('-'): mb:=False; - Ord('+'): mb:=False; - Ord(' '): mb:=False; - Ord('#'): mb:=False; - end; - if mb then - begin - {width} - case m^ of - Ord('1')..Ord('9'): - begin - Width:=0; - while True do - begin - if (m^<Ord('0')) or (Ord('9')<m^) then break; - Width:=Width*10+m^-Ord('0'); - Inc(m); - end; - end; - Ord('0'): mb:=False; - Ord('*'): mb:=False; - end; - end; - if mb then - begin - {prec} - case m^ of - Ord('.'): mb:=False; - end; - end; - if mb then - begin - {modifier} - case m^ of - Ord('F'): mb:=False; - Ord('N'): mb:=False; - Ord('h'): mb:=False; - Ord('l'): - begin - Modifier:=4; - Inc(m); - end; - Ord('L'): mb:=False; - end; - end; - if mb then - begin - {type} - case m^ of - Ord('d'): - begin - case Modifier of - 0: - begin - Append(IntToStr(PInteger(n)^)); - Inc(m); - Inc(n,SizeOf(Integer)); - end; - else - mb:=False; - end; - end; - Ord('i'): mb:=False; - Ord('o'): mb:=False; - Ord('u'): - begin - case Modifier of - 0,4: - begin - Append(IntToStr(PCardinal(n)^)); - Inc(m); - Inc(n,SizeOf(Cardinal)); - end; - else - mb:=False; - end; - end; - Ord('x'): - begin - case Modifier of - 0,4: - begin - Append(IntToHex(PCardinal(n)^,8)); - Inc(m); - Inc(n,SizeOf(Cardinal)); - end; - else - mb:=False; - end; - end; - Ord('X'): mb:=False; - Ord('f'): mb:=False; - Ord('e'): mb:=False; - Ord('g'): - begin - case Modifier of - 0: - begin - Append(FloatToStr(PSingle(n)^)); - Inc(m); - Inc(n,SizeOf(Single)); - end; - else - mb:=False; - end; - end; - Ord('E'): mb:=False; - Ord('G'): mb:=False; - Ord('c'): mb:=False; - Ord('s'): - begin - r:=PPointer(n)^; - while r^<>0 do - begin - if buffer<>nil then o^:=r^; - Inc(o); - Inc(r); - end; - Inc(n,SizeOf(Pointer)); - Inc(m); - end; - Ord('%'): mb:=False; - Ord('n'): mb:=False; - Ord('p'): mb:=False; - else - raise Exception.Create('LibDelphi'); - end; - end; - if mb=False then - begin - m:=ma; - if buffer<>nil then o^:=m^; - Inc(o); - Inc(m); - end; - end - else if m^=10 then - begin - if buffer<>nil then o^:=13; - Inc(o); - if buffer<>nil then o^:=10; - Inc(o); - Inc(m); - end - else - begin - if buffer<>nil then o^:=m^; - Inc(o); - Inc(m); - end; - end; - if buffer<>nil then o^:=0; - Inc(o); - Result:=(Cardinal(o)-Cardinal(buffer)); -end; - -procedure free(p: Pointer); cdecl; -begin - FreeMem(p); -end; - -function malloc(s: Longint): Pointer; cdecl; -begin - Result := AllocMem(s); -end; - -function _ftol: Integer; cdecl; -var - f: double; -begin - asm - lea eax, f // BC++ passes floats on the FPU stack - fstp qword ptr [eax] // Delphi passes floats on the CPU stack - end; - Result := Trunc(f); -end; - -function memcpy(dest: Pointer; const src: Pointer; count: Cardinal): Pointer; cdecl; -begin - CopyMemory(dest,src,count); - Result:=dest; -end; - -procedure memset(a: Pointer; b: Integer; c: Cardinal); cdecl; -begin - FillMemory(a,c,b); -end; - -end. diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/LibJpegDelphi.pas b/3rd/Imaging/Extras/Extensions/LibTiff/LibJpegDelphi.pas deleted file mode 100644 index 59c83440f..000000000 --- a/3rd/Imaging/Extras/Extensions/LibTiff/LibJpegDelphi.pas +++ /dev/null @@ -1,521 +0,0 @@ -unit LibJpegDelphi; - -interface - -uses - Windows, SysUtils; - -const - - JPEG_LIB_VERSION = 62; { Version 6b } - - JMSG_STR_PARM_MAX = 80; - JMSG_LENGTH_MAX = 200; { recommended size of format_message buffer } - NUM_QUANT_TBLS = 4; { Quantization tables are numbered 0..3 } - NUM_HUFF_TBLS = 4; { Huffman tables are numbered 0..3 } - NUM_ARITH_TBLS = 16; { Arith-coding tables are numbered 0..15 } - MAX_COMPS_IN_SCAN = 4; { JPEG limit on # of components in one scan } - C_MAX_BLOCKS_IN_MCU = 10; { compressor's limit on blocks per MCU } - D_MAX_BLOCKS_IN_MCU = 10; { decompressor's limit on blocks per MCU } - DCTSIZE2 = 64; - - JCS_UNKNOWN = 0; { error/unspecified } - JCS_GRAYSCALE = 1; { monochrome } - JCS_RGB = 2; { red/green/blue } - JCS_YCbCr = 3; { Y/Cb/Cr (also known as YUV) } - JCS_CMYK = 4; { C/M/Y/K } - JCS_YCCK = 5; { Y/Cb/Cr/K } - -type - - PRJpegErrorMgr = ^RJpegErrorMgr; - PRJpegMemoryMgr = Pointer; - PRJpegProgressMgr = Pointer; - PRJpegDestinationMgr = ^RJpegDestinationMgr; - PRJpegSourceMgr = ^RJpegSourceMgr; - PRJpegComponentInfo = ^RJpegComponentInfo; - PRJpegQuantTbl = Pointer; - PRJpegHuffTbl = Pointer; - PRJpegScanInfo = Pointer; - PRJpegCompMaster = Pointer; - PRJpegCMainController = Pointer; - PRJpegCPrepController = Pointer; - PRJpegCCoefController = Pointer; - PRJpegMarkerWriter = Pointer; - PRJpegColorConverter = Pointer; - PRJpegDownsampler = Pointer; - PRJpegForwardDct = Pointer; - PRJpegEntropyEncoder = Pointer; - PRJpegSavedMarker = Pointer; - PRJpegDecompMaster = Pointer; - PRJpegDMainController = Pointer; - PRJpegDCoefController = Pointer; - PRJpegDPosController = Pointer; - PRJpegInputController = Pointer; - PRJpegMarkerReader = Pointer; - PRJpegEntropyDecoder = Pointer; - PRJpegInverseDct = Pointer; - PRJpegUpsampler = Pointer; - PRJpegColorDeconverter = Pointer; - PRJpegColorQuantizer = Pointer; - PRJpegCommonStruct = ^RJpegCommonStruct; - PRJpegCompressStruct = ^RJpegCompressStruct; - PRJpegDecompressStruct = ^RJpegDecompressStruct; - - TJpegErrorExit = procedure(cinfo: PRJpegCommonStruct); cdecl; - TJpegEmitMessage = procedure(cinfo: PRJpegCommonStruct; MsgLevel: Integer); cdecl; - TJpegOutputMessage = procedure(cinfo: PRJpegCommonStruct); cdecl; - TJpegFormatMessage = procedure(cinfo: PRJpegCommonStruct; Buffer: Pointer); cdecl; - TJpegResetErrorMgr = procedure(cinfo: PRJpegCommonStruct); cdecl; - - RJpegErrorMgrMsgParm = record - case Boolean of - False: (MsgParmI: array[0..7] of Integer); - True: (MsgParmS: array[0..JMSG_STR_PARM_MAX-1] of AnsiChar); - end; - - RJpegErrorMgr = record - ErrorExit: TJpegErrorExit; { Error exit handler: does not return to caller } - EmitMessage: TJpegEmitMessage; { Conditionally emit a trace or warning message } - OutputMessage: TJpegOutputMessage; { Routine that actually outputs a trace or error message } - FormatMessage: TJpegFormatMessage; { Format a message string for the most recent JPEG error or message } - ResetErrorMgr: TJpegResetErrorMgr; { Reset error state variables at start of a new image } - { The message ID code and any parameters are saved here. A message can have one string parameter or up to 8 int parameters. } - MsgCode: Integer; - MsgParm: RJpegErrorMgrMsgParm; - { Standard state variables for error facility } - TraceLevel: Integer; {max msg_level that will be displayed} - { For recoverable corrupt-data errors, we emit a warning message, but keep going unless emit_message chooses to abort. - emit_message should count warnings in num_warnings. The surrounding application can check for bad data by seeing if num_warnings - is nonzero at the end of processing. } - NumWarnings: Integer; { number of corrupt-data warnings } - { These fields point to the table(s) of error message strings. An application can change the table pointer to switch to a different - message list (typically, to change the language in which errors are reported). Some applications may wish to add additional - error codes that will be handled by the JPEG library error mechanism; the second table pointer is used for this purpose. - First table includes all errors generated by JPEG library itself. Error code 0 is reserved for a "no such error string" message. } - JpegMessageTable: PPAnsiChar; { Library errors } - LastJpegMessage: Integer; { Table contains strings 0..last_jpeg_message } - { Second table can be added by application (see cjpeg/djpeg for example). It contains strings numbered - first_addon_message..last_addon_message. } - AddonMessageTable: PPAnsiChar; { Non-library errors } - FirstAddonMessage: Integer; { code for first string in addon table } - LastAddonMessage: Integer; { code for last string in addon table } - end; - - TJpegInitDestination = procedure(cinfo: PRJpegCompressStruct); cdecl; - TJpegEmptyOutputBuffer = function(cinfo: PRJpegCompressStruct): Boolean; cdecl; - TJpegTermDestination = procedure(cinfo: PRJpegCompressStruct); cdecl; - - RJpegDestinationMgr = record - NextOutputByte: Pointer; { => next byte to write in buffer } - FreeInBuffer: Cardinal; { # of byte spaces remaining in buffer } - InitDestination: TJpegInitDestination; - EmptyOutputBuffer: TJpegEmptyOutputBuffer; - TermDestination: TJpegTermDestination; - end; - - TJpegInitSource = procedure(cinfo: PRJpegDecompressStruct); cdecl; - TJpegFillInputBuffer = function(cinfo: PRJpegDecompressStruct): Boolean; cdecl; - TJpegSkipInputData = procedure(cinfo: PRJpegDecompressStruct; NumBytes: Integer); cdecl; - TJpegResyncToRestart = function(cinfo: PRJpegDecompressStruct; Desired: Integer): Boolean; cdecl; - TJpegTermSource = procedure(cinfo: PRJpegDecompressStruct); cdecl; - - RJpegSourceMgr = record - NextInputByte: Pointer; - BytesInBuffer: Cardinal; - InitSource: TJpegInitSource; - FillInputBuffer: TJpegFillInputBuffer; - SkipInputData: TJpegSkipInputData; - ResyncToRestart: TJpegResyncToRestart; - TermSource: TJpegTermSource; - end; - - RJpegComponentInfo = record - { Basic info about one component (color channel). } - { These values are fixed over the whole image. } - { For compression, they must be supplied by parameter setup; } - { for decompression, they are read from the SOF marker. } - ComponentId: Integer; { identifier for this component (0..255) } - ComponentIndex: Integer; { its index in SOF or cinfo->comp_info[] } - HSampFactor: Integer; { horizontal sampling factor (1..4) } - VSampFactor: Integer; { vertical sampling factor (1..4) } - QuantTblNo: Integer; { quantization table selector (0..3) } - { These values may vary between scans. } - { For compression, they must be supplied by parameter setup; } - { for decompression, they are read from the SOS marker. } - { The decompressor output side may not use these variables. } - DcTblNo: Integer; { DC entropy table selector (0..3) } - AsTblNo: Integer; { AC entropy table selector (0..3) } - { Remaining fields should be treated as private by applications. } - { These values are computed during compression or decompression startup: } - { Component's size in DCT blocks. Any dummy blocks added to complete an MCU are not counted; therefore these values do not depend - on whether a scan is interleaved or not. } - WidthInBlocks: Cardinal; - HeightInBlocks: Cardinal; - { Size of a DCT block in samples. Always DCTSIZE for compression. For decompression this is the size of the output from one DCT - block, reflecting any scaling we choose to apply during the IDCT step. Values of 1,2,4,8 are likely to be supported. Note that - different components may receive different IDCT scalings. } - DctScaledSize: Integer; - { The downsampled dimensions are the component's actual, unpadded number of samples at the main buffer (preprocessing/compression - interface), thus downsampled_width = ceil(image_width * Hi/Hmax) and similarly for height. For decompression, IDCT scaling is - included, so downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) } - DownsampledWidth: Cardinal; { actual width in samples } - DownsampledHeight: Cardinal; { actual height in samples } - { This flag is used only for decompression. In cases where some of the components will be ignored (eg grayscale output from YCbCr - image), we can skip most computations for the unused components. } - ComponentNeeded: Boolean; { do we need the value of this component? } - { These values are computed before starting a scan of the component. } - { The decompressor output side may not use these variables. } - McuWidth: Integer; { number of blocks per MCU, horizontally } - McuHeight: Integer; { number of blocks per MCU, vertically } - McuBlocks: Integer; { MCU_width * MCU_height } - McuSampleWidth: Integer; { MCU width in samples, MCU_width*DCT_scaled_size } - LastColWidth: Integer; { # of non-dummy blocks across in last MCU } - LastRowHeight: Integer; { # of non-dummy blocks down in last MCU } - { Saved quantization table for component; NULL if none yet saved. See jdinput.c comments about the need for this information. This - field is currently used only for decompression. } - QuantTable: PRJpegQuantTbl; - { Private per-component storage for DCT or IDCT subsystem. } - DctTable: Pointer; - end; - - RJpegCommonStruct = record - Err: PRJpegErrorMgr; { Error handler module } - Mem: PRJpegMemoryMgr; { Memory manager module } - Progress: PRJpegProgressMgr; { Progress monitor, or NULL if none } - ClientData: Pointer; { Available for use by application } - IsDecompressor: Boolean; { So common code can tell which is which } - GlobalState: Integer; { For checking call sequence validity } - end; - - RJpegCompressStruct = record - Err: PRJpegErrorMgr; { Error handler module } - Mem: PRJpegMemoryMgr; { Memory manager module } - Progress: PRJpegProgressMgr; { Progress monitor, or NULL if none } - ClientData: Pointer; { Available for use by application } - IsDecompressor: Boolean; { So common code can tell which is which } - GlobalState: Integer; { For checking call sequence validity } - { Destination for compressed data } - Dest: PRJpegDestinationMgr; - { Description of source image --- these fields must be filled in by outer application before starting compression. - in_color_space must be correct before you can even call jpeg_set_defaults(). } - ImageWidth: Cardinal; { input image width } - ImageHeight: Cardinal; { input image height } - InputComponents: Integer; { # of color components in input image } - InColorSpace: Integer; { colorspace of input image } - InputGamme: Double; { image gamma of input image } - { Compression parameters --- these fields must be set before calling jpeg_start_compress(). We recommend calling - jpeg_set_defaults() to initialize everything to reasonable defaults, then changing anything the application specifically wants - to change. That way you won't get burnt when new parameters are added. Also note that there are several helper routines to - simplify changing parameters. } - DataPrecision: Integer; { bits of precision in image data } - NumComponents: Integer; { # of color components in JPEG image } - JpegColorSpace: Integer; { colorspace of JPEG image } - CompInfo: PRJpegComponentInfo; { comp_info[i] describes component that appears i'th in SOF } - QuantTblPtrs: array[0..NUM_QUANT_TBLS-1] of PRJpegQuantTbl; {ptrs to coefficient quantization tables, or NULL if not defined } - DcHuffTblPtrs: array[0..NUM_HUFF_TBLS-1] of PRJpegHuffTbl; {ptrs to Huffman coding tables, or NULL if not defined } - AcHuffTblPtrs: array[0..NUM_HUFF_TBLS-1] of PRJpegHuffTbl; - ArithDcL: array[0..NUM_ARITH_TBLS-1] of Byte; { L values for DC arith-coding tables } - ArithDcU: array[0..NUM_ARITH_TBLS-1] of Byte; { U values for DC arith-coding tables } - ArithAcK: array[0..NUM_ARITH_TBLS-1] of Byte; { Kx values for AC arith-coding tables } - NumScans: Integer; { # of entries in scan_info array } - ScanInfo: PRJpegScanInfo; { script for multi-scan file, or NULL } - { The default value of scan_info is NULL, which causes a single-scan sequential JPEG file to be emitted. To create a multi-scan - file, set num_scans and scan_info to point to an array of scan definitions. } - RawDataIn: Boolean; { TRUE=caller supplies downsampled data } - ArithCode: Boolean; { TRUE=arithmetic coding, FALSE=Huffman } - OptimizeCoding: Boolean; { TRUE=optimize entropy encoding parms } - CCIR601Sampling: Boolean; { TRUE=first samples are cosited } - SmoothingFactor: Integer; { 1..100, or 0 for no input smoothing } - DctMethod: Integer; { DCT algorithm selector } - { The restart interval can be specified in absolute MCUs by setting restart_interval, or in MCU rows by setting restart_in_rows - (in which case the correct restart_interval will be figured for each scan). } - RestartInterval: Cardinal; { MCUs per restart, or 0 for no restart } - RestartInRows: Integer; { if > 0, MCU rows per restart interval } - { Parameters controlling emission of special markers. } - WriteJfifHeader: Boolean; { should a JFIF marker be written? } - JfifMajorVersion: Byte; { What to write for the JFIF version number } - JFifMinorVersion: Byte; - { These three values are not used by the JPEG code, merely copied into the JFIF APP0 marker. density_unit can be 0 for unknown, - 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect ratio is defined by X_density/Y_density even when density_unit=0. } - DensityUnit: Byte; { JFIF code for pixel size units } - XDensity: Word; { Horizontal pixel density } - YDensity: WOrd; { Vertical pixel density } - WriteAdobeMarker: Boolean; { should an Adobe marker be written? } - { State variable: index of next scanline to be written to jpeg_write_scanlines(). Application may use this to control its - processing loop, e.g., "while (next_scanline < image_height)". } - NextScanline: Cardinal; { 0 .. image_height-1 } - { Remaining fields are known throughout compressor, but generally should not be touched by a surrounding application. } - { These fields are computed during compression startup } - ProgressiveMode: Boolean; { TRUE if scan script uses progressive mode } - MaxHSampFactor: Integer; { largest h_samp_factor } - MaxVSampFactor: Integer; { largest v_samp_factor } - TotalIMCURows: Cardinal; { # of iMCU rows to be input to coef ctlr } - { The coefficient controller receives data in units of MCU rows as defined for fully interleaved scans (whether the JPEG file is - interleaved or not). There are v_samp_factor * DCTSIZE sample rows of each component in an "iMCU" (interleaved MCU) row. } - { These fields are valid during any one scan. They describe the components and MCUs actually appearing in the scan. } - CompsInScan: Integer; { # of JPEG components in this scan } - CurCompInfo: array[0..MAX_COMPS_IN_SCAN-1] of PRJpegComponentInfo; - { *cur_comp_info[i] describes component that appears i'th in SOS } - MCUsPerRow: Cardinal; { # of MCUs across the image } - MCUsRowsInScan: Cardinal; { # of MCU rows in the image } - BlocksInMcu: Integer; { # of DCT blocks per MCU } - MCUMembership: array[0..C_MAX_BLOCKS_IN_MCU-1] of Integer; - { MCU_membership[i] is index in cur_comp_info of component owning i'th block in an MCU } - Ss,Se,Ah,Al: Integer; { progressive JPEG parameters for scan } - { Links to compression subobjects (methods and private variables of modules) } - Master: PRJpegCompMaster; - Main: PRJpegCMainController; - Prep: PRJpegCPrepController; - Coef: PRJpegCCoefController; - Marker: PRJpegMarkerWriter; - CConvert: PRJpegColorConverter; - Downsample: PRJpegDownsampler; - FDct: PRJpegForwardDct; - Entropy: PRJpegEntropyEncoder; - ScriptSpace: PRJpegScanInfo; { workspace for jpeg_simple_progression } - ScriptSpaceSize: Integer; - end; - - RJpegDecompressStruct = record - { Fields shared with jpeg_compress_struct } - Err: PRJpegErrorMgr; { Error handler module } - Mem: PRJpegMemoryMgr; { Memory manager module } - Progress: PRJpegProgressMgr; { Progress monitor, or NULL if none } - ClientData: Pointer; { Available for use by application } - IsDecompressor: Boolean; { So common code can tell which is which } - GlobalState: Integer; { For checking call sequence validity } - { Source of compressed data } - Src: PRJpegSourceMgr; - { Basic description of image --- filled in by jpeg_read_header(). } - { Application may inspect these values to decide how to process image. } - ImageWidth: Cardinal; { nominal image width (from SOF marker) } - ImageHeight: Cardinal; { nominal image height } - NumComponents: Integer; { # of color components in JPEG image } - JpegColorSpace: Integer; { colorspace of JPEG image } - { Decompression processing parameters --- these fields must be set before calling jpeg_start_decompress(). Note that - jpeg_read_header() initializes them to default values. } - OutColorSpace: Integer; { colorspace for output } - ScaleNum,ScaleDenom: Cardinal; { fraction by which to scale image } - OutputGamme: Double; { image gamma wanted in output } - BufferedImage: Boolean; { TRUE=multiple output passes } - RawDataOut: Boolean; { TRUE=downsampled data wanted } - DctMethod: Integer; { IDCT algorithm selector } - DoFancyUpsampling: Boolean; { TRUE=apply fancy upsampling } - DoBlockSmoothing: Boolean; { TRUE=apply interblock smoothing } - QuantizeColors: Boolean; { TRUE=colormapped output wanted } - { the following are ignored if not quantize_colors: } - DitherMode: Integer; { type of color dithering to use } - TwoPassQuantize: Boolean; { TRUE=use two-pass color quantization } - DesiredNumberOfColors: Integer;{ max # colors to use in created colormap } - { these are significant only in buffered-image mode: } - Enable1PassQuant: Boolean; { enable future use of 1-pass quantizer } - EnableExternalQuant: Boolean; { enable future use of external colormap } - Enable2PassQuant: Boolean; { enable future use of 2-pass quantizer } - { Description of actual output image that will be returned to application. These fields are computed by jpeg_start_decompress(). - You can also use jpeg_calc_output_dimensions() to determine these values in advance of calling jpeg_start_decompress(). } - OutputWidth: Cardinal; { scaled image width } - OutputHeight: Cardinal; { scaled image height } - OutColorComponents: Integer; { # of color components in out_color_space } - OutputComponents: Integer; { # of color components returned } - { output_components is 1 (a colormap index) when quantizing colors; otherwise it equals out_color_components. } - RecOutbufHeight: Integer; { min recommended height of scanline buffer } - { If the buffer passed to jpeg_read_scanlines() is less than this many rows high, space and time will be wasted due to unnecessary - data copying. Usually rec_outbuf_height will be 1 or 2, at most 4. } - { When quantizing colors, the output colormap is described by these fields. The application can supply a colormap by setting - colormap non-NULL before calling jpeg_start_decompress; otherwise a colormap is created during jpeg_start_decompress or - jpeg_start_output. The map has out_color_components rows and actual_number_of_colors columns. } - ActualNumberOfColors: Integer; { number of entries in use } - Colormap: Pointer; { The color map as a 2-D pixel array } - { State variables: these variables indicate the progress of decompression. The application may examine these but must not modify - them. } - { Row index of next scanline to be read from jpeg_read_scanlines(). Application may use this to control its processing loop, e.g., - "while (output_scanline < output_height)". } - OutputScanline: Cardinal; { 0 .. output_height-1 } - { Current input scan number and number of iMCU rows completed in scan. These indicate the progress of the decompressor input side. } - InputScanNumber: Integer; { Number of SOS markers seen so far } - InputIMcuRow: Cardinal; { Number of iMCU rows completed } - { The "output scan number" is the notional scan being displayed by the output side. The decompressor will not allow output - scan/row number to get ahead of input scan/row, but it can fall arbitrarily far behind. } - OutputScanNumber: Integer; { Nominal scan number being displayed } - OutputIMcuRow: Cardinal; { Number of iMCU rows read } - { Current progression status. coef_bits[c][i] indicates the precision with which component c's DCT coefficient i (in zigzag order) - is known. It is -1 when no data has yet been received, otherwise it is the point transform (shift) value for the most recent scan - of the coefficient (thus, 0 at completion of the progression). This pointer is NULL when reading a non-progressive file. } - CoefBits: Pointer; { -1 or current Al value for each coef } - { Internal JPEG parameters --- the application usually need not look at these fields. Note that the decompressor output side may - not use any parameters that can change between scans. } - { Quantization and Huffman tables are carried forward across input datastreams when processing abbreviated JPEG datastreams. } - QuantTblPtrs: array[0..NUM_QUANT_TBLS-1] of Pointer; - { ptrs to coefficient quantization tables, or NULL if not defined } - DcHuffTblPtrs: array[0..NUM_HUFF_TBLS-1] of Pointer; - AcHuffTblPtrs: array[0..NUM_HUFF_TBLS-1] of Pointer; - { ptrs to Huffman coding tables, or NULL if not defined } - { These parameters are never carried across datastreams, since they are given in SOF/SOS markers or defined to be reset by SOI. } - DataPrecision: Integer; { bits of precision in image data } - CompInfo: PRJpegComponentInfo; { comp_info[i] describes component that appears i'th in SOF } - ProgressiveMode: Boolean; { TRUE if SOFn specifies progressive mode } - ArithCode: Boolean; { TRUE=arithmetic coding, FALSE=Huffman } - ArithDcL: array[0..NUM_ARITH_TBLS-1] of Byte; { L values for DC arith-coding tables } - ArithDcY: array[0..NUM_ARITH_TBLS-1] of Byte; { U values for DC arith-coding tables } - ArithAcK: array[0..NUM_ARITH_TBLS-1] of Byte; { Kx values for AC arith-coding tables } - RestartInterval: Cardinal; { MCUs per restart interval, or 0 for no restart } - { These fields record data obtained from optional markers recognized by the JPEG library. } - SawJfifMarker: Boolean; { TRUE iff a JFIF APP0 marker was found } - { Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: } - JfifMajorVersion: Byte; { JFIF version number } - JfifMinorVersion: Byte; { JFIF code for pixel size units } - XDensity: Word; { Horizontal pixel density } - YDensity: Word; { Vertical pixel density } - SawAdobeMarker: Boolean; { TRUE iff an Adobe APP14 marker was found } - AdobeTransform: Byte; { Color transform code from Adobe marker } - Ccir601Sampling: Boolean; { TRUE=first samples are cosited } - { Aside from the specific data retained from APPn markers known to the library, the uninterpreted contents of any or all APPn and - COM markers can be saved in a list for examination by the application. } - MarkerList: PRJpegSavedMarker; { Head of list of saved markers } - { Remaining fields are known throughout decompressor, but generally should not be touched by a surrounding application. } - { These fields are computed during decompression startup } - MaxHSampFactor: Integer; { largest h_samp_factor } - MaxVSampFactor: Integer; { largest v_samp_factor } - MinDctScaledSize: Integer; { smallest DCT_scaled_size of any component } - TotalIMcuRows: Cardinal; { # of iMCU rows in image } - { The coefficient controller's input and output progress is measured in units of "iMCU" (interleaved MCU) rows. These are the same - as MCU rows in fully interleaved JPEG scans, but are used whether the scan is interleaved or not. We define an iMCU row as - v_samp_factor DCT block rows of each component. Therefore, the IDCT output contains v_samp_factor*DCT_scaled_size sample rows - of a component per iMCU row. } - SampleRangeLimit: Pointer; { table for fast range-limiting } - { These fields are valid during any one scan. They describe the components and MCUs actually appearing in the scan. Note that the - decompressor output side must not use these fields. } - CompsInScan: Integer; { # of JPEG components in this scan } - CurCompInfo: array[0..MAX_COMPS_IN_SCAN-1] of PRJpegComponentInfo; - { *cur_comp_info[i] describes component that appears i'th in SOS } - McusPerRow: Cardinal; { # of MCUs across the image } - McuRowsInScan: Cardinal; { # of MCU rows in the image } - BlocksInMcu: Integer; { # of DCT blocks per MCU } - McuMembership: array[0..D_MAX_BLOCKS_IN_MCU-1] of Integer; - { MCU_membership[i] is index in cur_comp_info of component owning i'th block in an MCU } - Ss,Se,Ah,Al: Integer; { progressive JPEG parameters for scan } - { This field is shared between entropy decoder and marker parser. It is either zero or the code of a JPEG marker that has been read - from the data source, but has not yet been processed. } - UnreadMarker: Integer; - { Links to decompression subobjects (methods, private variables of modules) } - Master: PRJpegDecompMaster; - Main: PRJpegDMainController; - Coef: PRJpegDCoefController; - Post: PRJpegDPosController; - InputCtl: PRJpegInputController; - Marker: PRJpegMarkerReader; - Entropy: PRJpegEntropyDecoder; - IDct: PRJpegInverseDct; - Upsample: PRJpegUpsampler; - CConvert: PRJpegColorDeconverter; - CQuantize: PRJpegColorQuantizer; - end; - -procedure jpeg_create_compress(cinfo: PRJpegCompressStruct); cdecl; -procedure jpeg_CreateCompress(cinfo: PRJpegCompressStruct; version: Integer; structsize: Cardinal); cdecl; external; -procedure jpeg_create_decompress(cinfo: PRJpegDecompressStruct); cdecl; -procedure jpeg_CreateDecompress(cinfo: PRJpegDecompressStruct; version: Integer; structsize: Cardinal); cdecl; external; -procedure jpeg_abort(cinfo: PRJpegCommonStruct); cdecl; external; -procedure jpeg_set_defaults(cinfo: PRJpegCompressStruct); cdecl; external; -procedure jpeg_set_colorspace(cinfo: PRJpegCompressStruct; colorspace: Integer); cdecl; external; -procedure jpeg_set_quality(cinfo: PRJpegCompressStruct; quality: Integer; force_baseline: Byte); cdecl; external; -procedure jpeg_suppress_tables(cinfo: PRJpegCompressStruct; suppress: Byte); cdecl; external; -procedure jpeg_start_compress(cinfo: PRJpegCompressStruct; write_all_tables: Byte); cdecl; external; -function jpeg_write_scanlines(cinfo: PRJpegCompressStruct; scanlines: PPointer; num_lines: Cardinal): Cardinal; cdecl; external; -function jpeg_write_raw_data(cinfo: PRJpegCompressStruct; data: Pointer; num_lines: Cardinal): Cardinal; cdecl; external; -procedure jpeg_finish_compress(cinfo: PRJpegCompressStruct); cdecl; external; -procedure jpeg_write_tables(cinfo: PRJpegCompressStruct); cdecl; external; -function jpeg_read_header(cinfo: PRJpegDecompressStruct; require_image: Boolean): Integer; cdecl; external; -function jpeg_start_decompress(cinfo: PRJpegDecompressStruct): Byte; cdecl; external; -function jpeg_read_scanlines(cinfo: PRJpegDecompressStruct; scanlines: Pointer; max_lines: Cardinal): Cardinal; cdecl; external; -function jpeg_read_raw_data(cinfo: PRJpegDecompressStruct; data: Pointer; max_lines: Cardinal): Cardinal; cdecl; external; -function jpeg_finish_decompress(cinfo: PRJpegDecompressStruct): Byte; cdecl; external; -procedure jpeg_destroy(cinfo: PRJpegCommonStruct); cdecl; external; -function jpeg_std_error(err: PRJpegErrorMgr): Pointer; cdecl; external; -function jpeg_resync_to_restart(cinfo: PRJpegDecompressStruct; desired: Integer): Byte; cdecl; external; - -implementation - -uses - LibDelphi; - -procedure jpeg_error_exit_raise; cdecl; -begin - raise Exception.Create('LibJpeg error_exit'); -end; - -procedure jpeg_create_compress(cinfo: PRJpegCompressStruct); cdecl; -begin - jpeg_CreateCompress(cinfo,JPEG_LIB_VERSION,SizeOf(RJpegCompressStruct)); -end; - -procedure jpeg_create_decompress(cinfo: PRJpegDecompressStruct); cdecl; -begin - jpeg_CreateDecompress(cinfo,JPEG_LIB_VERSION,SizeOf(RJpegDecompressStruct)); -end; - -function jpeg_get_small(cinfo: PRJpegCommonStruct; sizeofobject: Cardinal): Pointer; cdecl; external; -function jpeg_get_large(cinfo: PRJpegCommonStruct; sizeofobject: Cardinal): Pointer; cdecl; external; -function jpeg_mem_available(cinfo: PRJpegCommonStruct; min_bytes_needed: Integer; max_bytes_needed: Integer; already_allocated: Integer): Integer; cdecl; external; -procedure jpeg_open_backing_store(cinfo: PRJpegCommonStruct; info: Pointer; total_bytes_needed: Integer); cdecl; external; -procedure jpeg_free_large(cinfo: PRJpegCommonStruct; objectt: Pointer; sizeofobject: Cardinal); cdecl; external; -procedure jpeg_free_small(cinfo: PRJpegCommonStruct; objectt: Pointer; sizeofobject: Cardinal); cdecl; external; -procedure jpeg_mem_term(cinfo: PRJpegCommonStruct); cdecl; external; -function jpeg_mem_init(cinfo: PRJpegCommonStruct): Integer; cdecl; external; -procedure jinit_memory_mgr(cinfo: PRJpegCommonStruct); cdecl; external; -function jpeg_alloc_huff_table(cinfo: PRJpegCommonStruct): Pointer; cdecl; external; -function jpeg_alloc_quant_table(cinfo: PRJpegCommonStruct): Pointer; cdecl; external; -function jdiv_round_up(a: Integer; b: Integer): Integer; cdecl; external; -procedure jcopy_sample_rows(input_array: Pointer; source_row: Integer; output_array: Pointer; dest_row: Integer; num_rows: Integer; - num_cols: Cardinal); cdecl; external; -function jround_up(a: Integer; b: Integer): Integer; cdecl; external; -procedure jcopy_block_row(input_row: Pointer; output_row: Pointer; num_blocks: Cardinal); cdecl; external; - -{$L Compiled\jmemnobs.obj} -{$L Compiled\jmemmgr.obj} -{$L Compiled\jcomapi.obj} -{$L Compiled\jerror.obj} -{$L Compiled\jcapimin.obj} -{$L Compiled\jcmarker.obj} -{$L Compiled\jutils.obj} -{$L Compiled\jdapimin.obj} -{$L Compiled\jdmarker.obj} -{$L Compiled\jdinput.obj} -{$L Compiled\jcparam.obj} -{$L Compiled\jcapistd.obj} -{$L Compiled\jcinit.obj} -{$L Compiled\jcmaster.obj} -{$L Compiled\jccolor.obj} -{$L Compiled\jcsample.obj} -{$L Compiled\jcprepct.obj} -{$L Compiled\jcdctmgr.obj} -{$L Compiled\jcphuff.obj} -{$L Compiled\jchuff.obj} -{$L Compiled\jccoefct.obj} -{$L Compiled\jcmainct.obj} -{$L Compiled\jfdctint.obj} -{$L Compiled\jfdctfst.obj} -{$L Compiled\jfdctflt.obj} -{$L Compiled\jdapistd.obj} -{$L Compiled\jdmaster.obj} -{$L Compiled\jquant1.obj} -{$L Compiled\jquant2.obj} -{$L Compiled\jdmerge.obj} -{$L Compiled\jdcolor.obj} -{$L Compiled\jdsample.obj} -{$L Compiled\jdpostct.obj} -{$L Compiled\jddctmgr.obj} -{$L Compiled\jdphuff.obj} -{$L Compiled\jdhuff.obj} -{$L Compiled\jdcoefct.obj} -{$L Compiled\jdmainct.obj} -{$L Compiled\jidctred.obj} -{$L Compiled\jidctint.obj} -{$L Compiled\jidctfst.obj} -{$L Compiled\jidctflt.obj} - -end. - - - diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/LibTiffDelphi.pas b/3rd/Imaging/Extras/Extensions/LibTiff/LibTiffDelphi.pas deleted file mode 100644 index e68980438..000000000 --- a/3rd/Imaging/Extras/Extensions/LibTiff/LibTiffDelphi.pas +++ /dev/null @@ -1,1602 +0,0 @@ -unit LibTiffDelphi; - -{$ALIGN 8} -{$MINENUMSIZE 1} - -interface - -uses - Windows, SysUtils, Classes; - -const - //DW - LibTiffDelphiVersionString = 'LibTiffDelphi 3.9.4.00'#13#10'Pre-compiled LibTiff for Delphi'#13#10'http://www.awaresystems.be/'#13#10'3.9.4 implementaion by Do-wan Kim'#13#10; - - TIFF_NOTYPE = 0; - TIFF_BYTE = 1; { 8-bit unsigned integer } - TIFF_ASCII = 2; { 8-bit bytes w/ last byte null } - TIFF_SHORT = 3; { 16-bit unsigned integer } - TIFF_LONG = 4; { 32-bit unsigned integer } - TIFF_RATIONAL = 5; { 64-bit unsigned fraction } - TIFF_SBYTE = 6; { !8-bit signed integer } - TIFF_UNDEFINED = 7; { !8-bit untyped data } - TIFF_SSHORT = 8; { !16-bit signed integer } - TIFF_SLONG = 9; { !32-bit signed integer } - TIFF_SRATIONAL = 10; { !64-bit signed fraction } - TIFF_FLOAT = 11; { !32-bit IEEE floating point } - TIFF_DOUBLE = 12; { !64-bit IEEE floating point } - TIFF_IFD = 13; { %32-bit unsigned integer (offset) } - TIFF_UNICODE = 14; - TIFF_COMPLEX = 15; - TIFF_LONG8 = 16; - TIFF_SLONG8 = 17; - TIFF_IFD8 = 18; - - - TIFFTAG_SUBFILETYPE = 254; { subfile data descriptor } - FILETYPE_REDUCEDIMAGE = $1; { reduced resolution version } - FILETYPE_PAGE = $2; { one page of many } - FILETYPE_MASK = $4; { transparency mask } - TIFFTAG_OSUBFILETYPE = 255; { kind of data in subfile } - OFILETYPE_IMAGE = 1; { full resolution image data } - OFILETYPE_REDUCEDIMAGE = 2; { reduced size image data } - OFILETYPE_PAGE = 3; { one page of many } - TIFFTAG_IMAGEWIDTH = 256; { image width in pixels } - TIFFTAG_IMAGELENGTH = 257; { image height in pixels } - TIFFTAG_BITSPERSAMPLE = 258; { bits per channel (sample) } - TIFFTAG_COMPRESSION = 259; { data compression technique } - COMPRESSION_NONE = 1; { dump mode } - COMPRESSION_CCITTRLE = 2; { CCITT modified Huffman RLE } - COMPRESSION_CCITTFAX3 = 3; { CCITT Group 3 fax encoding } - COMPRESSION_CCITT_T4 = 3; { CCITT T.4 (TIFF 6 name) } - COMPRESSION_CCITTFAX4 = 4; { CCITT Group 4 fax encoding } - COMPRESSION_CCITT_T6 = 4; { CCITT T.6 (TIFF 6 name) } - COMPRESSION_LZW = 5; { Lempel-Ziv & Welch } - COMPRESSION_OJPEG = 6; { !6.0 JPEG } - COMPRESSION_JPEG = 7; { %JPEG DCT compression } - COMPRESSION_NEXT = 32766; { NeXT 2-bit RLE } - COMPRESSION_CCITTRLEW = 32771; { #1 w/ word alignment } - COMPRESSION_PACKBITS = 32773; { Macintosh RLE } - COMPRESSION_THUNDERSCAN = 32809; { ThunderScan RLE } - { codes 32895-32898 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) } - COMPRESSION_IT8CTPAD = 32895; { IT8 CT w/padding } - COMPRESSION_IT8LW = 32896; { IT8 Linework RLE } - COMPRESSION_IT8MP = 32897; { IT8 Monochrome picture } - COMPRESSION_IT8BL = 32898; { IT8 Binary line art } - { compression codes 32908-32911 are reserved for Pixar } - COMPRESSION_PIXARFILM = 32908; { Pixar companded 10bit LZW } - COMPRESSION_PIXARLOG = 32909; { Pixar companded 11bit ZIP } - COMPRESSION_DEFLATE = 32946; { Deflate compression } - COMPRESSION_ADOBE_DEFLATE = 8; { Deflate compression, as recognized by Adobe } - { compression code 32947 is reserved for Oceana Matrix <dev@oceana.com> } - COMPRESSION_DCS = 32947; { Kodak DCS encoding } - COMPRESSION_JBIG = 34661; { ISO JBIG } - COMPRESSION_SGILOG = 34676; { SGI Log Luminance RLE } - COMPRESSION_SGILOG24 = 34677; { SGI Log 24-bit packed } - COMPRESSION_JP2000 = 34712; { Leadtools JPEG2000 } - TIFFTAG_PHOTOMETRIC = 262; { photometric interpretation } - PHOTOMETRIC_MINISWHITE = 0; { min value is white } - PHOTOMETRIC_MINISBLACK = 1; { min value is black } - PHOTOMETRIC_RGB = 2; { RGB color model } - PHOTOMETRIC_PALETTE = 3; { color map indexed } - PHOTOMETRIC_MASK = 4; { $holdout mask } - PHOTOMETRIC_SEPARATED = 5; { !color separations } - PHOTOMETRIC_YCBCR = 6; { !CCIR 601 } - PHOTOMETRIC_CIELAB = 8; { !1976 CIE L*a*b* } - PHOTOMETRIC_ICCLAB = 9; { ICC L*a*b* [Adobe TIFF Technote 4] } - PHOTOMETRIC_ITULAB = 10; { ITU L*a*b* } - PHOTOMETRIC_LOGL = 32844; { CIE Log2(L) } - PHOTOMETRIC_LOGLUV = 32845; { CIE Log2(L) (u',v') } - TIFFTAG_THRESHHOLDING = 263; { thresholding used on data } - THRESHHOLD_BILEVEL = 1; { b&w art scan } - THRESHHOLD_HALFTONE = 2; { or dithered scan } - THRESHHOLD_ERRORDIFFUSE = 3; { usually floyd-steinberg } - TIFFTAG_CELLWIDTH = 264; { +dithering matrix width } - TIFFTAG_CELLLENGTH = 265; { +dithering matrix height } - TIFFTAG_FILLORDER = 266; { data order within a byte } - FILLORDER_MSB2LSB = 1; { most significant -> least } - FILLORDER_LSB2MSB = 2; { least significant -> most } - TIFFTAG_DOCUMENTNAME = 269; { name of doc. image is from } - TIFFTAG_IMAGEDESCRIPTION = 270; { info about image } - TIFFTAG_MAKE = 271; { scanner manufacturer name } - TIFFTAG_MODEL = 272; { scanner model name/number } - TIFFTAG_STRIPOFFSETS = 273; { offsets to data strips } - TIFFTAG_ORIENTATION = 274; { +image orientation } - ORIENTATION_TOPLEFT = 1; { row 0 top, col 0 lhs } - ORIENTATION_TOPRIGHT = 2; { row 0 top, col 0 rhs } - ORIENTATION_BOTRIGHT = 3; { row 0 bottom, col 0 rhs } - ORIENTATION_BOTLEFT = 4; { row 0 bottom, col 0 lhs } - ORIENTATION_LEFTTOP = 5; { row 0 lhs, col 0 top } - ORIENTATION_RIGHTTOP = 6; { row 0 rhs, col 0 top } - ORIENTATION_RIGHTBOT = 7; { row 0 rhs, col 0 bottom } - ORIENTATION_LEFTBOT = 8; { row 0 lhs, col 0 bottom } - TIFFTAG_SAMPLESPERPIXEL = 277; { samples per pixel } - TIFFTAG_ROWSPERSTRIP = 278; { rows per strip of data } - TIFFTAG_STRIPBYTECOUNTS = 279; { bytes counts for strips } - TIFFTAG_MINSAMPLEVALUE = 280; { +minimum sample value } - TIFFTAG_MAXSAMPLEVALUE = 281; { +maximum sample value } - TIFFTAG_XRESOLUTION = 282; { pixels/resolution in x } - TIFFTAG_YRESOLUTION = 283; { pixels/resolution in y } - TIFFTAG_PLANARCONFIG = 284; { storage organization } - PLANARCONFIG_CONTIG = 1; { single image plane } - PLANARCONFIG_SEPARATE = 2; { separate planes of data } - TIFFTAG_PAGENAME = 285; { page name image is from } - TIFFTAG_XPOSITION = 286; { x page offset of image lhs } - TIFFTAG_YPOSITION = 287; { y page offset of image lhs } - TIFFTAG_FREEOFFSETS = 288; { +byte offset to free block } - TIFFTAG_FREEBYTECOUNTS = 289; { +sizes of free blocks } - - {matched with tag reference up to this point} - - TIFFTAG_GRAYRESPONSEUNIT = 290; { $gray scale curve accuracy } - GRAYRESPONSEUNIT_10S = 1; { tenths of a unit } - GRAYRESPONSEUNIT_100S = 2; { hundredths of a unit } - GRAYRESPONSEUNIT_1000S = 3; { thousandths of a unit } - GRAYRESPONSEUNIT_10000S = 4; { ten-thousandths of a unit } - GRAYRESPONSEUNIT_100000S = 5; { hundred-thousandths } - TIFFTAG_GRAYRESPONSECURVE = 291; { $gray scale response curve } - TIFFTAG_GROUP3OPTIONS = 292; { 32 flag bits } - TIFFTAG_T4OPTIONS = 292; { TIFF 6.0 proper name alias } - GROUP3OPT_2DENCODING = $1; { 2-dimensional coding } - GROUP3OPT_UNCOMPRESSED = $2; { data not compressed } - GROUP3OPT_FILLBITS = $4; { fill to byte boundary } - TIFFTAG_GROUP4OPTIONS = 293; { 32 flag bits } - TIFFTAG_T6OPTIONS = 293; { TIFF 6.0 proper name } - GROUP4OPT_UNCOMPRESSED = $2; { data not compressed } - TIFFTAG_RESOLUTIONUNIT = 296; { units of resolutions } - RESUNIT_NONE = 1; { no meaningful units } - RESUNIT_INCH = 2; { english } - RESUNIT_CENTIMETER = 3; { metric } - TIFFTAG_PAGENUMBER = 297; { page numbers of multi-page } - TIFFTAG_COLORRESPONSEUNIT = 300; { $color curve accuracy } - COLORRESPONSEUNIT_10S = 1; { tenths of a unit } - COLORRESPONSEUNIT_100S = 2; { hundredths of a unit } - COLORRESPONSEUNIT_1000S = 3; { thousandths of a unit } - COLORRESPONSEUNIT_10000S = 4; { ten-thousandths of a unit } - COLORRESPONSEUNIT_100000S = 5; { hundred-thousandths } - TIFFTAG_TRANSFERFUNCTION = 301; { !colorimetry info } - TIFFTAG_SOFTWARE = 305; { name & release } - TIFFTAG_DATETIME = 306; { creation date and time } - TIFFTAG_ARTIST = 315; { creator of image } - TIFFTAG_HOSTCOMPUTER = 316; { machine where created } - TIFFTAG_PREDICTOR = 317; { prediction scheme w/ LZW } - TIFFTAG_WHITEPOINT = 318; { image white point } - TIFFTAG_PRIMARYCHROMATICITIES = 319; { !primary chromaticities } - TIFFTAG_COLORMAP = 320; { RGB map for pallette image } - TIFFTAG_HALFTONEHINTS = 321; { !highlight+shadow info } - TIFFTAG_TILEWIDTH = 322; { !rows/data tile } - TIFFTAG_TILELENGTH = 323; { !cols/data tile } - TIFFTAG_TILEOFFSETS = 324; { !offsets to data tiles } - TIFFTAG_TILEBYTECOUNTS = 325; { !byte counts for tiles } - TIFFTAG_BADFAXLINES = 326; { lines w/ wrong pixel count } - TIFFTAG_CLEANFAXDATA = 327; { regenerated line info } - CLEANFAXDATA_CLEAN = 0; { no errors detected } - CLEANFAXDATA_REGENERATED = 1; { receiver regenerated lines } - CLEANFAXDATA_UNCLEAN = 2; { uncorrected errors exist } - TIFFTAG_CONSECUTIVEBADFAXLINES = 328; { max consecutive bad lines } - TIFFTAG_SUBIFD = 330; { subimage descriptors } - TIFFTAG_INKSET = 332; { !inks in separated image } - INKSET_CMYK = 1; { !cyan-magenta-yellow-black color } - INKSET_MULTIINK = 2; { !multi-ink or hi-fi color } - TIFFTAG_INKNAMES = 333; { !ascii names of inks } - TIFFTAG_NUMBEROFINKS = 334; { !number of inks } - TIFFTAG_DOTRANGE = 336; { !0% and 100% dot codes } - TIFFTAG_TARGETPRINTER = 337; { !separation target } - TIFFTAG_EXTRASAMPLES = 338; { !info about extra samples } - EXTRASAMPLE_UNSPECIFIED = 0; { !unspecified data } - EXTRASAMPLE_ASSOCALPHA = 1; { !associated alpha data } - EXTRASAMPLE_UNASSALPHA = 2; { !unassociated alpha data } - TIFFTAG_SAMPLEFORMAT = 339; { !data sample format } - SAMPLEFORMAT_UINT = 1; { !unsigned integer data } - SAMPLEFORMAT_INT = 2; { !signed integer data } - SAMPLEFORMAT_IEEEFP = 3; { !IEEE floating point data } - SAMPLEFORMAT_VOID = 4; { !untyped data } - SAMPLEFORMAT_COMPLEXINT = 5; { !complex signed int } - SAMPLEFORMAT_COMPLEXIEEEFP = 6; { !complex ieee floating } - TIFFTAG_SMINSAMPLEVALUE = 340; { !variable MinSampleValue } - TIFFTAG_SMAXSAMPLEVALUE = 341; { !variable MaxSampleValue } - TIFFTAG_CLIPPATH = 343; { %ClipPath [Adobe TIFF technote 2] } - TIFFTAG_XCLIPPATHUNITS = 344; { %XClipPathUnits [Adobe TIFF technote 2] } - TIFFTAG_YCLIPPATHUNITS = 345; { %YClipPathUnits [Adobe TIFF technote 2] } - TIFFTAG_INDEXED = 346; { %Indexed [Adobe TIFF Technote 3] } - TIFFTAG_JPEGTABLES = 347; { %JPEG table stream } - TIFFTAG_OPIPROXY = 351; { %OPI Proxy [Adobe TIFF technote] } - { Tags 512-521 are obsoleted by Technical Note #2 - which specifies a revised JPEG-in-TIFF scheme. } - TIFFTAG_JPEGPROC = 512; { !JPEG processing algorithm } - JPEGPROC_BASELINE = 1; { !baseline sequential } - JPEGPROC_LOSSLESS = 14; { !Huffman coded lossless } - TIFFTAG_JPEGIFOFFSET = 513; { !pointer to SOI marker } - TIFFTAG_JPEGIFBYTECOUNT = 514; { !JFIF stream length } - TIFFTAG_JPEGRESTARTINTERVAL = 515; { !restart interval length } - TIFFTAG_JPEGLOSSLESSPREDICTORS = 517; { !lossless proc predictor } - TIFFTAG_JPEGPOINTTRANSFORM = 518; { !lossless point transform } - TIFFTAG_JPEGQTABLES = 519; { !Q matrice offsets } - TIFFTAG_JPEGDCTABLES = 520; { !DCT table offsets } - TIFFTAG_JPEGACTABLES = 521; { !AC coefficient offsets } - TIFFTAG_YCBCRCOEFFICIENTS = 529; { !RGB -> YCbCr transform } - TIFFTAG_YCBCRSUBSAMPLING = 530; { !YCbCr subsampling factors } - TIFFTAG_YCBCRPOSITIONING = 531; { !subsample positioning } - YCBCRPOSITION_CENTERED = 1; { !as in PostScript Level 2 } - YCBCRPOSITION_COSITED = 2; { !as in CCIR 601-1 } - TIFFTAG_REFERENCEBLACKWHITE = 532; { !colorimetry info } - TIFFTAG_XMLPACKET = 700; { %XML packet [Adobe XMP technote 9-14-02] (dkelly@apago.com) } - TIFFTAG_OPIIMAGEID = 32781; { %OPI ImageID [Adobe TIFF technote] } - { tags 32952-32956 are private tags registered to Island Graphics } - TIFFTAG_REFPTS = 32953; { image reference points } - TIFFTAG_REGIONTACKPOINT = 32954; { region-xform tack point } - TIFFTAG_REGIONWARPCORNERS = 32955; { warp quadrilateral } - TIFFTAG_REGIONAFFINE = 32956; { affine transformation mat } - { tags 32995-32999 are private tags registered to SGI } - TIFFTAG_MATTEING = 32995; { $use ExtraSamples } - TIFFTAG_DATATYPE = 32996; { $use SampleFormat } - TIFFTAG_IMAGEDEPTH = 32997; { z depth of image } - TIFFTAG_TILEDEPTH = 32998; { z depth/data tile } - { tags 33300-33309 are private tags registered to Pixar } - { TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH are set when an image has been cropped out of a larger image. - They reflect the size of the original uncropped image. The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used to determine the - position of the smaller image in the larger one. } - TIFFTAG_PIXAR_IMAGEFULLWIDTH = 33300; { full image size in x } - TIFFTAG_PIXAR_IMAGEFULLLENGTH = 33301; { full image size in y } - { Tags 33302-33306 are used to identify special image modes and data used by Pixar's texture formats. } - TIFFTAG_PIXAR_TEXTUREFORMAT = 33302; { texture map format } - TIFFTAG_PIXAR_WRAPMODES = 33303; { s & t wrap modes } - TIFFTAG_PIXAR_FOVCOT = 33304; { cotan(fov) for env. maps } - TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN = 33305; - TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA = 33306; - { tag 33405 is a private tag registered to Eastman Kodak } - TIFFTAG_WRITERSERIALNUMBER = 33405; { device serial number } - { tag 33432 is listed in the 6.0 spec w/ unknown ownership } - TIFFTAG_COPYRIGHT = 33432; { copyright string } - { IPTC TAG from RichTIFF specifications } - TIFFTAG_RICHTIFFIPTC = 33723; - { 34016-34029 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) } - TIFFTAG_IT8SITE = 34016; { site name } - TIFFTAG_IT8COLORSEQUENCE = 34017; { color seq. [RGB,CMYK,etc] } - TIFFTAG_IT8HEADER = 34018; { DDES Header } - TIFFTAG_IT8RASTERPADDING = 34019; { raster scanline padding } - TIFFTAG_IT8BITSPERRUNLENGTH = 34020; { # of bits in short run } - TIFFTAG_IT8BITSPEREXTENDEDRUNLENGTH = 34021; { # of bits in long run } - TIFFTAG_IT8COLORTABLE = 34022; { LW colortable } - TIFFTAG_IT8IMAGECOLORINDICATOR = 34023; { BP/BL image color switch } - TIFFTAG_IT8BKGCOLORINDICATOR = 34024; { BP/BL bg color switch } - TIFFTAG_IT8IMAGECOLORVALUE = 34025; { BP/BL image color value } - TIFFTAG_IT8BKGCOLORVALUE = 34026; { BP/BL bg color value } - TIFFTAG_IT8PIXELINTENSITYRANGE = 34027; { MP pixel intensity value } - TIFFTAG_IT8TRANSPARENCYINDICATOR = 34028; { HC transparency switch } - TIFFTAG_IT8COLORCHARACTERIZATION = 34029; { color character. table } - TIFFTAG_IT8HCUSAGE = 34030; { HC usage indicator } - TIFFTAG_IT8TRAPINDICATOR = 34031; { Trapping indicator (untrapped=0, trapped=1) } - TIFFTAG_IT8CMYKEQUIVALENT = 34032; { CMYK color equivalents } - { tags 34232-34236 are private tags registered to Texas Instruments } - TIFFTAG_FRAMECOUNT = 34232; { Sequence Frame Count } - { tag 34750 is a private tag registered to Adobe? } - TIFFTAG_ICCPROFILE = 34675; { ICC profile data } - { tag 34377 is private tag registered to Adobe for PhotoShop } - TIFFTAG_PHOTOSHOP = 34377; - { tag 34750 is a private tag registered to Pixel Magic } - TIFFTAG_JBIGOPTIONS = 34750; { JBIG options } - { tags 34908-34914 are private tags registered to SGI } - TIFFTAG_FAXRECVPARAMS = 34908; { encoded Class 2 ses. parms } - TIFFTAG_FAXSUBADDRESS = 34909; { received SubAddr string } - TIFFTAG_FAXRECVTIME = 34910; { receive time (secs) } - { tags 37439-37443 are registered to SGI <gregl@sgi.com> } - TIFFTAG_STONITS = 37439; { Sample value to Nits } - { tag 34929 is a private tag registered to FedEx } - TIFFTAG_FEDEX_EDR = 34929; { unknown use } - { tag 65535 is an undefined tag used by Eastman Kodak } - TIFFTAG_DCSHUESHIFTVALUES = 65535; { hue shift correction data } - { The following are ``pseudo tags'' that can be used to control codec-specific functionality. These tags are not written to file. - Note that these values start at 0xffff+1 so that they'll never collide with Aldus-assigned tags. } - TIFFTAG_FAXMODE = 65536; { Group 3/4 format control } - FAXMODE_CLASSIC = $0; { default, include RTC } - FAXMODE_NORTC = $1; { no RTC at end of data } - FAXMODE_NOEOL = $2; { no EOL code at end of row } - FAXMODE_BYTEALIGN = $4; { byte align row } - FAXMODE_WORDALIGN = $8; { word align row } - FAXMODE_CLASSF = FAXMODE_NORTC; { TIFF Class F } - TIFFTAG_JPEGQUALITY = 65537; { Compression quality level } - { Note: quality level is on the IJG 0-100 scale. Default value is 75 } - TIFFTAG_JPEGCOLORMODE = 65538; { Auto RGB<=>YCbCr convert? } - JPEGCOLORMODE_RAW = $0; { no conversion (default) } - JPEGCOLORMODE_RGB = $1; { do auto conversion } - TIFFTAG_JPEGTABLESMODE = 65539; { What to put in JPEGTables } - JPEGTABLESMODE_QUANT = $1; { include quantization tbls } - JPEGTABLESMODE_HUFF = $2; { include Huffman tbls } - { Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF } - TIFFTAG_FAXFILLFUNC = 65540; { G3/G4 fill function } - TIFFTAG_PIXARLOGDATAFMT = 65549; { PixarLogCodec I/O data sz } - PIXARLOGDATAFMT_8BIT = 0; { regular u_char samples } - PIXARLOGDATAFMT_8BITABGR = 1; { ABGR-order u_chars } - PIXARLOGDATAFMT_11BITLOG = 2; { 11-bit log-encoded (raw) } - PIXARLOGDATAFMT_12BITPICIO = 3; { as per PICIO (1.0==2048) } - PIXARLOGDATAFMT_16BIT = 4; { signed short samples } - PIXARLOGDATAFMT_FLOAT = 5; { IEEE float samples } - { 65550-65556 are allocated to Oceana Matrix <dev@oceana.com> } - TIFFTAG_DCSIMAGERTYPE = 65550; { imager model & filter } - DCSIMAGERMODEL_M3 = 0; { M3 chip (1280 x 1024) } - DCSIMAGERMODEL_M5 = 1; { M5 chip (1536 x 1024) } - DCSIMAGERMODEL_M6 = 2; { M6 chip (3072 x 2048) } - DCSIMAGERFILTER_IR = 0; { infrared filter } - DCSIMAGERFILTER_MONO = 1; { monochrome filter } - DCSIMAGERFILTER_CFA = 2; { color filter array } - DCSIMAGERFILTER_OTHER = 3; { other filter } - TIFFTAG_DCSINTERPMODE = 65551; { interpolation mode } - DCSINTERPMODE_NORMAL = 0; { whole image, default } - DCSINTERPMODE_PREVIEW = 1; { preview of image (384x256) } - TIFFTAG_DCSBALANCEARRAY = 65552; { color balance values } - TIFFTAG_DCSCORRECTMATRIX = 65553; { color correction values } - TIFFTAG_DCSGAMMA = 65554; { gamma value } - TIFFTAG_DCSTOESHOULDERPTS = 65555; { toe & shoulder points } - TIFFTAG_DCSCALIBRATIONFD = 65556; { calibration file desc } - { Note: quality level is on the ZLIB 1-9 scale. Default value is -1 } - TIFFTAG_ZIPQUALITY = 65557; { compression quality level } - TIFFTAG_PIXARLOGQUALITY = 65558; { PixarLog uses same scale } - { 65559 is allocated to Oceana Matrix <dev@oceana.com> } - TIFFTAG_DCSCLIPRECTANGLE = 65559; { area of image to acquire } - TIFFTAG_SGILOGDATAFMT = 65560; { SGILog user data format } - SGILOGDATAFMT_FLOAT = 0; { IEEE float samples } - SGILOGDATAFMT_16BIT = 1; { 16-bit samples } - SGILOGDATAFMT_RAW = 2; { uninterpreted data } - SGILOGDATAFMT_8BIT = 3; { 8-bit RGB monitor values } - TIFFTAG_SGILOGENCODE = 65561; { SGILog data encoding control } - SGILOGENCODE_NODITHER = 0; { do not dither encoded values } - SGILOGENCODE_RANDITHER = 1; { randomly dither encd values } - - - { Flags to pass to TIFFPrintDirectory to control printing of data structures that are potentially very large. Bit-or these flags to - enable printing multiple items. } - TIFFPRINT_NONE = $0; { no extra info } - TIFFPRINT_STRIPS = $1; { strips/tiles info } - TIFFPRINT_CURVES = $2; { color/gray response curves } - TIFFPRINT_COLORMAP = $4; { colormap } - TIFFPRINT_JPEGQTABLES = $100; { JPEG Q matrices } - TIFFPRINT_JPEGACTABLES = $200; { JPEG AC tables } - TIFFPRINT_JPEGDCTABLES = $200; { JPEG DC tables } - - - TIFF_ANY = TIFF_NOTYPE; { for field descriptor searching } - TIFF_VARIABLE = -1; { marker for variable length tags } - TIFF_SPP = -2; { marker for SamplesPerPixel tags } - TIFF_VARIABLE2 = -3; { marker for uint32 var-length tags } - - FIELD_CUSTOM = 65; - - {added for LibTiff 3.9.4 by Alex (leontyyy@gmail.com) Dec.2011} - TIFFTAG_EXIFIFD = 34665; { pointer to the Exif IFD } - EXIFTAG_FOCALLENGTH = 37386; { focal length } - EXIFTAG_FOCALLENGTHIN35MMFILM = 41989; { indicates the equivalent focal length assuming a 35mm film camera, in mm } - EXIFTAG_EXIFVERSION = 36864; { version of exif format } - EXIFTAG_DATETIMEDIGITIZED = 36868; { date and time when the image was stored as digital data } - EXIFTAG_DATETIMEORIGINAL = 36867; { date and time when the original image data was generated } - EXIFTAG_EXPOSURETIME = 33434; { exposure time, given in seconds } - EXIFTAG_FNUMBER = 33437; { F number } - EXIFTAG_EXPOSUREPROGRAM = 34850; { class of the program used by the camera to set exposure } - EXIFTAG_SPECTRALSENSITIVITY = 34852; { spectral sensitivity of each channel of the camera used } - EXIFTAG_ISOSPEEDRATINGS = 34855; { ISO Speed and ISO Latitude } - EXIFTAG_OECF = 34856; { Opto-Electric Conversion Function } - EXIFTAG_COMPONENTSCONFIGURATION = 37121; { meaning of each component } - EXIFTAG_COMPRESSEDBITSPERPIXEL = 37122; { compression mode } - EXIFTAG_SHUTTERSPEEDVALUE = 37377; { shutter speed } - EXIFTAG_APERTUREVALUE = 37378; { lens aperture } - EXIFTAG_BRIGHTNESSVALUE = 37379; { brightness } - EXIFTAG_EXPOSUREBIASVALUE = 37380; { exposure bias } - EXIFTAG_MAXAPERTUREVALUE = 37381; { maximum lens aperture } - EXIFTAG_SUBJECTDISTANCE = 37382; { distance to the subject in meters } - EXIFTAG_METERINGMODE = 37383; { metering mode } - EXIFTAG_LIGHTSOURCE = 37384; { light source } - EXIFTAG_FLASH = 37385; { flash } - EXIFTAG_SUBJECTAREA = 37396; { subject area (in exif ver.2.2) } - EXIFTAG_MAKERNOTE = 37500; { manufacturer notes } - EXIFTAG_USERCOMMENT = 37510; { user comments } - EXIFTAG_SUBSECTIME = 37520; { DateTime subseconds } - EXIFTAG_SUBSECTIMEORIGINAL = 37521; { DateTimeOriginal subseconds } - EXIFTAG_SUBSECTIMEDIGITIZED = 37522; { DateTimeDigitized subseconds } - EXIFTAG_FLASHPIXVERSION = 40960; { FlashPix format version } - EXIFTAG_COLORSPACE = 40961; { color space information } - EXIFTAG_PIXELXDIMENSION = 40962; { valid image width } - EXIFTAG_PIXELYDIMENSION = 40963; { valid image height } - EXIFTAG_RELATEDSOUNDFILE = 40964; { related audio file } - EXIFTAG_FLASHENERGY = 41483; { flash energy } - EXIFTAG_SPATIALFREQUENCYRESPONSE = 41484; { spatial frequency response } - EXIFTAG_FOCALPLANEXRESOLUTION = 41486; { focal plane X resolution } - EXIFTAG_FOCALPLANEYRESOLUTION = 41487; { focal plane Y resolution } - EXIFTAG_FOCALPLANERESOLUTIONUNIT = 41488; { focal plane resolution unit } - EXIFTAG_SUBJECTLOCATION = 41492; { subject location } - EXIFTAG_EXPOSUREINDEX = 41493; { exposure index } - EXIFTAG_SENSINGMETHOD = 41495; { sensing method } - EXIFTAG_FILESOURCE = 41728; { file source } - EXIFTAG_SCENETYPE = 41729; { scene type } - EXIFTAG_CFAPATTERN = 41730; { CFA pattern } - EXIFTAG_CUSTOMRENDERED = 41985; { custom image processing (in exif ver.2.2) } - EXIFTAG_EXPOSUREMODE = 41986; { exposure mode (in exif ver.2.2) } - EXIFTAG_WHITEBALANCE = 41987; { white balance (in exif ver.2.2) } - EXIFTAG_DIGITALZOOMRATIO = 41988; { digital zoom ratio (in exif ver.2.2) } - EXIFTAG_SCENECAPTURETYPE = 41990; { scene capture type (in exif ver.2.2) } - EXIFTAG_GAINCONTROL = 41991; { gain control (in exif ver.2.2) } - EXIFTAG_CONTRAST = 41992; { contrast (in exif ver.2.2) } - EXIFTAG_SATURATION = 41993; { saturation (in exif ver.2.2) } - EXIFTAG_SHARPNESS = 41994; { sharpness (in exif ver.2.2) } - EXIFTAG_DEVICESETTINGDESCRIPTION = 41995; { device settings description (in exif ver.2.2) } - EXIFTAG_SUBJECTDISTANCERANGE = 41996; { subject distance range (in exif ver.2.2) } - EXIFTAG_IMAGEUNIQUEID = 42016; { Unique image ID (in exif ver.2.2) } - -type - - PTIFF = Pointer; - PTIFFRGBAImage = Pointer; - - TIFFErrorHandler = procedure(a: Pointer; b: Pointer; c: Pointer); cdecl; - LibTiffDelphiErrorHandler = procedure(const a,b: AnsiString); - TIFFReadWriteProc = function(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; - TIFFSeekProc = function(Fd: Cardinal; Off: Cardinal; Whence: Integer): Cardinal; cdecl; - TIFFCloseProc = function(Fd: Cardinal): Integer; cdecl; - TIFFSizeProc = function(Fd: Cardinal): Cardinal; cdecl; - TIFFMapFileProc = function(Fd: Cardinal; PBase: PPointer; PSize: PCardinal): Integer; cdecl; - TIFFUnmapFileProc = procedure(Fd: Cardinal; Base: Pointer; Size: Cardinal); cdecl; - TIFFExtendProc = procedure(Handle: PTIFF); cdecl; - - TIFFInitMethod = function(Handle: PTIFF; Scheme: Integer): Integer; cdecl; - - PTIFFCodec = ^TIFFCodec; - TIFFCodec = record - Name: PAnsiChar; - Scheme: Word; - Init: TIFFInitMethod; - end; - - PTIFFFieldInfo = ^TIFFFieldInfo; - TIFFFieldInfo = record - FieldTag: Cardinal; { field's tag } - FieldReadCount: Smallint; { read count/TIFF_VARIABLE/TIFF_SPP } - FieldWriteCount: Smallint; { write count/TIFF_VARIABLE } - FieldType: Integer; { type of associated data } - FieldBit: Word; { bit in fieldsset bit vector } - FieldOkToChange: Byte; { if true, can change while writing } - FieldPassCount: Byte; { if true, pass dir count on set } - FieldName: PAnsiChar; { ASCII name } - end; - - PTIFFTagValue = ^TIFFTagValue; - TIFFTagValue = record - Info: PTIFFFieldInfo; - Count: Integer; - Value: Pointer; - end; - -function LibTiffDelphiVersion: AnsiString; -function TIFFGetVersion: PAnsiChar; cdecl; external; -function TIFFFindCODEC(Scheme: Word): PTIFFCodec; cdecl; external; -function TIFFRegisterCODEC(Scheme: Word; Name: PAnsiChar; InitMethod: TIFFInitMethod): PTIFFCodec; cdecl; external; -procedure TIFFUnRegisterCODEC(c: PTIFFCodec); cdecl; external; -function TIFFIsCODECConfigured(Scheme: Word): Integer; cdecl; external; -function TIFFGetConfiguredCODECs: PTIFFCodec; cdecl; external; - -function TIFFOpen(const Name: AnsiString; const Mode: AnsiString): PTIFF; -function TIFFOpenStream(const Stream: TStream; const Mode: AnsiString): PTIFF; -function TIFFClientOpen(Name: PAnsiChar; Mode: PAnsiChar; ClientData: Cardinal; - ReadProc: TIFFReadWriteProc; - WriteProc: TIFFReadWriteProc; - SeekProc: TIFFSeekProc; - CloseProc: TIFFCloseProc; - SizeProc: TIFFSizeProc; - MapProc: TIFFMapFileProc; - UnmapProc: TIFFUnmapFileProc): PTIFF; cdecl; external; -procedure TIFFCleanup(Handle: PTIFF); cdecl; external; -procedure TIFFClose(Handle: PTIFF); cdecl; external; -function TIFFFileno(Handle: PTIFF): Integer; cdecl; external; -function TIFFSetFileno(Handle: PTIFF; Newvalue: Integer): Integer; cdecl; external; -function TIFFClientdata(Handle: PTIFF): Cardinal; cdecl; external; -function TIFFSetClientdata(Handle: PTIFF; Newvalue: Cardinal): Cardinal; cdecl; external; -function TIFFGetMode(Handle: PTIFF): Integer; cdecl; external; -function TIFFSetMode(Handle: PTIFF; Mode: Integer): Integer; cdecl; external; -function TIFFFileName(Handle: PTIFF): Pointer; cdecl; external; -function TIFFSetFileName(Handle: PTIFF; Name: PAnsiChar): PAnsiChar; cdecl; external; -function TIFFGetReadProc(Handle: PTIFF): TIFFReadWriteProc; cdecl; external; -function TIFFGetWriteProc(Handle: PTIFF): TIFFReadWriteProc; cdecl; external; -function TIFFGetSeekProc(Handle: PTIFF): TIFFSeekProc; cdecl; external; -function TIFFGetCloseProc(Handle: PTIFF): TIFFCloseProc; cdecl; external; -function TIFFGetSizeProc(Handle: PTIFF): TIFFSizeProc; cdecl; external; -procedure TIFFError(Module: Pointer; Fmt: Pointer); cdecl; external; varargs; -function TIFFSetErrorHandler(Handler: TIFFErrorHandler): TIFFErrorHandler; cdecl; external; -function LibTiffDelphiGetErrorHandler: LibTiffDelphiErrorHandler; -function LibTiffDelphiSetErrorHandler(Handler: LibTiffDelphiErrorHandler): LibTiffDelphiErrorHandler; -procedure TIFFWarning(Module: Pointer; Fmt: Pointer); cdecl; external; varargs; -function TIFFSetWarningHandler(Handler: TIFFErrorHandler): TIFFErrorHandler; cdecl; external; -function LibTiffDelphiGetWarningHandler: LibTiffDelphiErrorHandler; -function LibTiffDelphiSetWarningHandler(Handler: LibTiffDelphiErrorHandler): LibTiffDelphiErrorHandler; -function TIFFSetTagExtender(Extender: TIFFExtendProc): TIFFExtendProc; cdecl; external; - - -function TIFFFlush(Handle: PTIFF): Integer; cdecl; external; -function TIFFFlushData(Handle: PTIFF): Integer; cdecl; external; - -{added for LibTiff 3.9.4 by Alex (leontyyy@gmail.com) Dec.2011} -function TIFFReadEXIFDirectory(Handle: PTIFF; Diroff: Cardinal): Integer; cdecl; external; - -function TIFFReadDirectory(Handle: PTIFF): Integer; cdecl; external; -function TIFFCurrentDirectory(Handle: PTIFF): Word; cdecl; external; -function TIFFCurrentDirOffset(Handle: PTIFF): Cardinal; cdecl; external; -function TIFFLastDirectory(Handle: PTIFF): Integer; cdecl; external; -function TIFFNumberOfDirectories(Handle: PTIFF): Word; cdecl; external; -function TIFFSetDirectory(Handle: PTIFF; Dirn: Word): Integer; cdecl; external; -function TIFFSetSubDirectory(Handle: PTIFF; Diroff: Cardinal): Integer; cdecl; external; -function TIFFCreateDirectory(Handle: PTIFF): Integer; cdecl; external; -function TIFFWriteDirectory(Handle: PTIFF): Integer; cdecl; external; -function TIFFUnlinkDirectory(handle: PTIFF; Dirn: Word): Integer; cdecl; external; -procedure TIFFPrintDirectory(Handle: PTIFF; Fd: Pointer; Flags: Integer); cdecl; external; - -function TIFFGetField(Handle: PTIFF; Tag: Cardinal): Integer; cdecl; external; varargs; -function TIFFGetFieldDefaulted(Handle: PTIFF; Tag: Cardinal): Integer; cdecl; external; varargs; -function TIFFVGetField(Handle: PTIFF; Tag: Cardinal; Ap: Pointer): Integer; cdecl; external; -function TIFFSetField(Handle: PTIFF; Tag: Cardinal): Integer; cdecl; external; varargs; -function TIFFVSetField(Handle: PTIFF; Tag: Cardinal; Ap: Pointer): Integer; cdecl; external; -function TIFFIsBigEndian(Handle: PTIFF): Integer; cdecl; external; -function TIFFIsTiled(Handle: PTIFF): Integer; cdecl; external; -function TIFFIsByteSwapped(Handle: PTIFF): Integer; cdecl; external; -function TIFFIsUpSampled(Handle: PTIFF): Integer; cdecl; external; -function TIFFIsMSB2LSB(Handle: PTIFF): Integer; cdecl; external; - -function TIFFGetTagListCount(Handle: PTIFF): Integer; cdecl; external; -function TIFFGetTagListEntry(Handle: PTIFF; TagIndex: Integer): Cardinal; cdecl; external; -procedure TIFFMergeFieldInfo(Handle: PTIFF; Info: PTIFFFieldInfo; N: Integer); cdecl; external; -function TIFFFindFieldInfo(Handle: PTIFF; Tag: Cardinal; Dt: Integer): PTIFFFieldInfo; cdecl; external; -function TIFFFindFieldInfoByName(Handle: PTIFF; FIeldName: PAnsiChar; Dt: Integer): PTIFFFieldInfo; cdecl; external; -function TIFFFieldWithTag(Handle: PTIFF; Tag: Cardinal): PTIFFFieldInfo; cdecl; external; -function TIFFFieldWithName(Handle: PTIFF; FieldName: PAnsiChar): PTIFFFieldInfo; cdecl; external; -function TIFFDataWidth(DataType: Integer): Integer; cdecl; external; - -function TIFFReadRGBAImage(Handle: PTIFF; RWidth,RHeight: Cardinal; Raster: Pointer; Stop: Integer): Integer; cdecl; external; -function TIFFReadRGBAImageOriented(Handle: PTIFF; RWidth,RHeight: Cardinal; Raster: Pointer; Orientation: Integer; Stop: Integer): Integer; cdecl; external; -function TIFFReadRGBAStrip(Handle: PTIFF; Row: Cardinal; Raster: Pointer): Integer; cdecl; external; -function TIFFReadRGBATile(Handle: PTIFF; Col,Row: Cardinal; Raster: Pointer): Integer; cdecl; external; -function TIFFRGBAImageOk(Handle: PTIFF; Emsg: PAnsiChar): Integer; cdecl; external; -function TIFFRGBAImageBegin(Img: PTIFFRGBAImage; Handle: PTIFF; Stop: Integer; Emsg: PAnsiChar): Integer; cdecl; external; -function TIFFRGBAImageGet(Img: PTIFFRGBAImage; Raster: Pointer; W,H: Cardinal): Integer; cdecl; external; -procedure TIFFRGBAImageEnd(Img: PTIFFRGBAImage); cdecl; external; - -function TIFFCurrentRow(Handle: PTIFF): Cardinal; cdecl; external; - -function TIFFStripSize(Handle: PTIFF): Integer; cdecl; external; -function TIFFRawStripSize(Handle: PTIFF; Strip: Cardinal): Integer; cdecl; external; -function TIFFVStripSize(Handle: PTIFF; NRows: Cardinal): Integer; cdecl; external; -function TIFFDefaultStripSize(Handle: PTIFF; Request: Cardinal): Cardinal; cdecl; external; -function TIFFNumberOfStrips(Handle: PTIFF): Cardinal; cdecl; external; -function TIFFComputeStrip(Handle: PTIFF; Row: Cardinal; Sample: Word): Cardinal; cdecl; external; -function TIFFReadRawStrip(Handle: PTIFF; Strip: Cardinal; Buf: Pointer; Size: Integer): Integer; cdecl; external; -function TIFFReadEncodedStrip(Handle: PTIFF; Strip: Cardinal; Buf: Pointer; Size: Integer): Integer; cdecl; external; -function TIFFWriteRawStrip(Handle: PTIFF; Strip: Cardinal; Data: Pointer; Cc: Integer): Integer; cdecl; external; -function TIFFWriteEncodedStrip(Handle: PTIFF; Strip: Cardinal; Data: Pointer; Cc: Integer): Integer; cdecl; external; -function TIFFCurrentStrip(Handle: PTIFF): Cardinal; cdecl; external; - -function TIFFTileSize(Handle: PTIFF): Integer; cdecl; external; -function TIFFTileRowSize(Handle: PTIFF): Integer; cdecl; external; -function TIFFVTileSize(Handle: PTIFF; NRows: Cardinal): Integer; cdecl; external; -procedure TIFFDefaultTileSize(Handle: PTIFF; Tw: PCardinal; Th: PCardinal); cdecl; external; -function TIFFNumberOfTiles(Handle: PTIFF): Cardinal; cdecl; external; -function TIFFComputeTile(Handle: PTIFF; X,Y,Z: Cardinal; S: Word): Cardinal; cdecl; external; -function TIFFReadRawTile(Handle: PTIFF; Tile: Cardinal; Buf: Pointer; Size: Integer): Integer; cdecl; external; -function TIFFReadEncodedTile(Handle: PTIFF; Tile: Cardinal; Buf: Pointer; Size: Integer): Integer; cdecl; external; -function TIFFWriteRawTile(Handle: PTIFF; Tile: Cardinal; Data: Pointer; Cc: Integer): Integer; cdecl; external; -function TIFFWriteEncodedTile(Handle: PTIFF; Tile: Cardinal; Data: Pointer; Cc: Integer): Integer; cdecl; external; -function TIFFCurrentTile(Handle: PTIFF): Cardinal; cdecl; external; - -function TIFFScanlineSize(Handle: PTIFF): Integer; cdecl; external; -function TIFFRasterScanlineSize(Handle: PTIFF): Integer; cdecl; external; -function TIFFReadScanline(Handle: PTIFF; Buf: Pointer; Row: Cardinal; Sample: Word): Integer; cdecl; external; -function TIFFWriteScanline(Handle: PTIFF; Buf: Pointer; Row: Cardinal; Sample: Word): Integer; cdecl; external; - -procedure TIFFSetWriteOffset(Handle: PTIFF; Off: Cardinal); cdecl; external; - -procedure TIFFSwabShort(Wp: PWord); cdecl; external; -procedure TIFFSwabLong(Lp: PCardinal); cdecl; external; -procedure TIFFSwabDouble(Dp: PDouble); cdecl; external; -procedure TIFFSwabArrayOfShort(Wp: PWord; N: Cardinal); cdecl; external; -procedure TIFFSwabArrayOfLong(Lp: PCardinal; N: Cardinal); cdecl; external; -procedure TIFFSwabArrayOfDouble(Dp: PDouble; N: Cardinal); cdecl; external; -procedure TIFFReverseBits(Cp: Pointer; N: Cardinal); cdecl; external; -function TIFFGetBitRevTable(Reversed: Integer): Pointer; cdecl; external; - -function _TIFFmalloc(s: Longint): Pointer; cdecl; -function _TIFFrealloc(p: Pointer; s: Longint): Pointer; cdecl; -procedure _TIFFfree(p: Pointer); cdecl; - -implementation - -uses - Math, LibDelphi, LibJpegDelphi, ZLibDelphi; - -type - - TCompareFunc = function(a,b: Pointer): Integer; cdecl; - -function floor(x: Double): Double; cdecl; forward; -function pow(x: Double; y: Double): Double; cdecl; forward; -function sqrt(x: Double): Double; cdecl; forward; -function atan2(y: Double; x: Double): Double; cdecl; forward; -function exp(x: Double): Double; cdecl; forward; -function log(x: Double): Double; cdecl; forward; -function fabs(x: Double): Double; cdecl; forward; -function rand: Integer; cdecl; forward; -function strlen(s: Pointer): Cardinal; cdecl; forward; -function strcmp(a: Pointer; b: Pointer): Integer; cdecl; forward; -function strncmp(a: Pointer; b: Pointer; c: Longint): Integer; cdecl; forward; -procedure qsort(base: Pointer; num: Cardinal; width: Cardinal; compare: TCompareFunc); cdecl; forward; -//DW function bsearch(key: Pointer; base: Pointer; nelem: Cardinal; width: Cardinal; fcmp: TCompareFunc): Pointer; cdecl; forward; -function memmove(dest: Pointer; src: Pointer; n: Cardinal): Pointer; cdecl; forward; -function strchr(s: Pointer; c: Integer): Pointer; cdecl; forward; - -procedure _TIFFmemcpy(d: Pointer; s: Pointer; c: Longint); cdecl; forward; -procedure _TIFFmemset(p: Pointer; v: Integer; c: Longint); cdecl; forward; -function _TIFFmemcmp(buf1: Pointer; buf2: Pointer; count: Cardinal): Integer; cdecl; forward; - -var - - _TIFFwarningHandler: TIFFErrorHandler; - _TIFFerrorHandler: TIFFErrorHandler; - FLibTiffDelphiWarningHandler: LibTiffDelphiErrorHandler; - FLibTiffDelphiErrorHandler: LibTiffDelphiErrorHandler; - -function fabs(x: Double): Double; -begin - if x<0 then - Result:=-x - else - Result:=x; -end; - -function atan2(y: Double; x: Double): Double; -begin - Result:=ArcTan2(y,x); -end; - -function rand: Integer; cdecl; -begin - Result:=Trunc(Random*($7FFF+1)); -end; - -function sqrt(x: Double): Double; cdecl; -begin - Result:=System.Sqrt(x); -end; - -function log(x: Double): Double; cdecl; -begin - Result:=Ln(x); -end; - -function exp(x: Double): Double; cdecl; -begin - Result:=System.Exp(x); -end; - -function strchr(s: Pointer; c: Integer): Pointer; cdecl; -begin - Result:=s; - while True do - begin - if PByte(Result)^=c then exit; - if PByte(Result)^=0 then - begin - Result:=nil; - exit; - end; - Inc(PByte(Result)); - end; -end; - -function memmove(dest: Pointer; src: Pointer; n: Cardinal): Pointer; cdecl; -begin - MoveMemory(dest,src,n); - Result:=dest; -end; - -function _TIFFmemcmp(buf1: Pointer; buf2: Pointer; count: Cardinal): Integer; cdecl; -var - ma,mb: PByte; - n: Integer; -begin - ma:=buf1; - mb:=buf2; - n:=0; - while Cardinal(n)<Count do - begin - if ma^<>mb^ then - begin - if ma^<mb^ then - Result:=-1 - else - Result:=1; - exit; - end; - Inc(ma); - Inc(mb); - Inc(n); - end; - Result:=0; -end; - -procedure _TIFFmemset(p: Pointer; v: Integer; c: Longint); cdecl; -begin - FillMemory(p,c,v); -end; - -(* DW -function bsearch(key: Pointer; base: Pointer; nelem: Cardinal; width: Cardinal; fcmp: TBsearchFcmp): Pointer; cdecl; -begin - raise Exception.Create('LibTiffDelphi - call to bsearch - should presumably not occur'); -end; -*) - -procedure qsort(base: Pointer; num: Cardinal; width: Cardinal; compare: TCompareFunc); cdecl; -var - m: Pointer; - n: Integer; - o: Pointer; - oa,ob,oc: Integer; - p: Integer; -begin - if num<2 then exit; - GetMem(m,num*width); - if compare(base,Pointer(Cardinal(base)+width))<=0 then - CopyMemory(m,base,(width shl 1)) - else - begin - CopyMemory(m,Pointer(Cardinal(base)+width),width); - CopyMemory(Pointer(Cardinal(m)+width),base,width); - end; - n:=2; - while Cardinal(n)<num do - begin - o:=Pointer(Cardinal(base)+Cardinal(n)*width); - if compare(m,o)>=0 then - ob:=0 - else - begin - oa:=0; - ob:=n; - while oa+1<ob do - begin - oc:=((oa+ob) shr 1); - p:=compare(Pointer(Cardinal(m)+Cardinal(oc)*width),o); - if p<0 then - oa:=oc - else if p=0 then - begin - ob:=oc; - break; - end - else - ob:=oc; - end; - end; - if ob=0 then - begin - MoveMemory(Pointer(Cardinal(m)+width),m,Cardinal(n)*width); - CopyMemory(m,o,width); - end - else if ob=n then - CopyMemory(Pointer(Cardinal(m)+Cardinal(n)*width),o,width) - else - begin - MoveMemory(Pointer(Cardinal(m)+Cardinal(ob+1)*width),Pointer(Cardinal(m)+Cardinal(ob)*width),Cardinal(n-ob)*width); - CopyMemory(Pointer(Cardinal(m)+Cardinal(ob)*width),o,width); - end; - Inc(n); - end; - CopyMemory(base,m,num*width); - FreeMem(m,num*width); -end; - -function _TIFFrealloc(p: Pointer; s: Longint): Pointer; cdecl; -begin - if p=nil then - Result:=AllocMem(s) - else - Result:=ReallocMemory(p,s); -end; - -function strncmp(a: Pointer; b: Pointer; c: Longint): Integer; cdecl; -var - ma,mb: PByte; - n: Integer; -begin - ma:=a; - mb:=b; - n:=0; - while n<c do - begin - if ma^<>mb^ then - begin - if ma^<mb^ then - Result:=-1 - else - Result:=1; - exit; - end; - if ma^=0 then - begin - Result:=0; - exit; - end; - Inc(ma); - Inc(mb); - Inc(n); - end; - Result:=0; -end; - -function strcmp(a: Pointer; b: Pointer): Integer; cdecl; -var - ma,mb: PByte; -begin - ma:=a; - mb:=b; - while True do - begin - if ma^<>mb^ then - begin - if ma^<mb^ then - Result:=-1 - else - Result:=1; - exit; - end; - if ma^=0 then - begin - Result:=0; - exit; - end; - Inc(ma); - Inc(mb); - end; - Result:=0; -end; - -function strlen(s: Pointer): Cardinal; cdecl; -var - m: PByte; -begin - Result:=0; - m:=s; - while m^<>0 do - begin - Inc(Result); - Inc(m); - end; -end; - -procedure _TIFFfree(p: Pointer); cdecl; -begin - FreeMem(p); -end; - -procedure _TIFFmemcpy(d: Pointer; s: Pointer; c: Longint); cdecl; -begin - CopyMemory(d,s,c); -end; - -function pow(x: Double; y: Double): Double; cdecl; -begin - Result:=Power(x,y); -end; - -function floor(x: Double): Double; cdecl; -begin - Result:=Trunc(x); -end; - -function _TIFFmalloc(s: Longint): Pointer; cdecl; -begin - Result:=AllocMem(s); -end; - -{LibTiffDelphi} - -function LibTiffDelphiVersion: AnsiString; -var - m: AnsiString; - na,nb: Integer; -begin - Result:=''; - m:=TIFFGetVersion; - na:=1; - while True do - begin - nb:=na; - while nb<=Length(m) do - begin - if m[nb]=#10 then break; - Inc(nb); - end; - Result:=Result+System.Copy(m,na,nb-na); - if nb>Length(m) then break; - Result:=Result+#13#10; - na:=nb+1; - end; - Result:=Result+#13#10+LibTiffDelphiVersionString; -end; - -procedure LibTiffDelphiWarningThrp(a: Pointer; b: Pointer; c: Pointer); cdecl; -var - m: Integer; - n: AnsiString; -begin - if @FLibTiffDelphiWarningHandler<>nil then - begin - m:=sprintfsec(nil,b,@c); - SetLength(n,m); - sprintfsec(Pointer(n),b,@c); - FLibTiffDelphiWarningHandler(PAnsiChar(a),n); - end; -end; - -procedure LibTiffDelphiErrorThrp(a: Pointer; b: Pointer; c: Pointer); cdecl; -var - m: Integer; - n: AnsiString; -begin - if @FLibTiffDelphiErrorHandler<>nil then - begin - m:=sprintfsec(nil,b,@c); - SetLength(n,m); - sprintfsec(Pointer(n),b,@c); - FLibTiffDelphiErrorHandler(PAnsiChar(a),n); - end; -end; - -function LibTiffDelphiGetWarningHandler: LibTiffDelphiErrorHandler; -begin - Result:=FLibTiffDelphiWarningHandler; -end; - -function LibTiffDelphiSetWarningHandler(Handler: LibTiffDelphiErrorHandler): LibTiffDelphiErrorHandler; -begin - Result:=FLibTiffDelphiWarningHandler; - FLibTiffDelphiWarningHandler:=Handler; -end; - -function LibTiffDelphiGetErrorHandler: LibTiffDelphiErrorHandler; -begin - Result:=FLibTiffDelphiErrorHandler; -end; - -function LibTiffDelphiSetErrorHandler(Handler: LibTiffDelphiErrorHandler): LibTiffDelphiErrorHandler; -begin - Result:=FLibTiffDelphiErrorHandler; - FLibTiffDelphiErrorHandler:=Handler; -end; - -{tif_read} - -procedure _TIFFSwab16BitData(tif: Pointer; buf: Pointer; cc: Integer); cdecl; external; -procedure _TIFFSwab24BitData(tif: pointer; buf: pointer; cc: integer); cdecl; external; //DW 3.8.2 -procedure _TIFFSwab32BitData(tif: Pointer; buf: Pointer; cc: Integer); cdecl; external; -procedure _TIFFSwab64BitData(tif: Pointer; buf: Pointer; cc: Integer); cdecl; external; -procedure _TIFFNoPostDecode(tif: Pointer; buf: Pointer; cc: Integer); cdecl; external; -function TIFFReadTile(tif: Pointer; buf: Pointer; x: Cardinal; y: Cardinal; z: Cardinal; s: Word): Integer; cdecl; external; -function TIFFFillTile(tif: Pointer; tile: longword):integer; cdecl; external; //DW 3.8.2 - -{$L Compiled\tif_read.obj} - -{tif_dirinfo} - -function _TIFFSampleToTagType(tif: Pointer): Integer; cdecl; external; -procedure _TIFFSetupFieldInfo(tif: Pointer); cdecl; external; -function _TIFFCreateAnonFieldInfo(tif: Pointer; tag: Cardinal; field_type: Integer): Pointer; cdecl; external; -function _TIFFGetExifFieldInfo(size : plongint):pointer; cdecl; external; //DW 3.8.2 -function _TIFFDataSize(TIFFDataType : longint):longint; cdecl; external; //DW 3.8.2 -function _TIFFGetFieldInfo(size : plongint):pointer; cdecl; external; //DW 3.8.2 -function _TIFFMergeFieldInfo(tif: Pointer; fieldinfo : Pointer; n : Integer):Integer; cdecl; external; //DW 3.9.1 - -{$L Compiled\tif_dirinfo.obj} - -{tif_dirwrite} - -{$L Compiled\tif_dirwrite.obj} - -{tif_flush} - -{$L Compiled\tif_flush.obj} - -{tif_write} - -function TIFFFlushData1(tif: Pointer): Integer; cdecl; external; -function TIFFSetupStrips(tif: Pointer): Integer; cdecl; external; - -{$L Compiled\tif_write.obj} - -{tif_dumpmode} - -function TIFFInitDumpMode(tif: Pointer; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_dumpmode.obj} - -{tif_compress} - -function TIFFSetCompressionScheme(tif: Pointer; scheme: Integer): Integer; cdecl; external; -procedure _TIFFSetDefaultCompressionState(tif: Pointer); cdecl; external; - -{$L Compiled\tif_compress.obj} - -{tif_dirread} - -{$L Compiled\tif_dirread.obj} - -{tif_dir} - -procedure TIFFFreeDirectory(tif: Pointer); cdecl; external; -function TIFFDefaultDirectory(tif: Pointer): Integer; cdecl; external; -function TIFFReassignTagToIgnore(task: Integer; TIFFtagID: Integer): Integer; cdecl; external; -procedure _TIFFsetString(cpp: Pointer; cp: Pointer); cdecl; external; -procedure _TIFFsetByteArray(vpp: Pointer; vp: Pointer; n: Integer); cdecl; external; - -{$L Compiled\tif_dir.obj} - -{tif_aux} - -function TIFFVGetFieldDefaulted(tif: Pointer; tag: Cardinal; ap: Pointer): Integer; cdecl; external; - -{$L Compiled\tif_aux.obj} - -{tif_color} - -procedure TIFFCIELabToXYZ(cielab: Pointer; l: Cardinal; a: Integer; b: Integer; X: Pointer; Y: Pointer; Z: Pointer); cdecl; external; -procedure TIFFXYZToRGB(cielab: Pointer; X: Single; Y: Single; Z: Single; r: Pointer; g: Pointer; b: Pointer); cdecl; external; -procedure TIFFYCbCrtoRGB(ycbcr: Pointer; Y: Cardinal; Cb: Integer; Cr: Integer; r: Pointer; g: Pointer; b: Pointer); cdecl; external; -function TIFFYCbCrToRGBInit(ycbcr: Pointer; luma: Pointer; refBlackWhite: Pointer): Integer; cdecl; external; -function TIFFCIELabToRGBInit(cielab: Pointer; display: Pointer; refWhite: Pointer): Integer; cdecl; external; - -{$L Compiled\tif_color.obj} - -{tif_close} - -{$L Compiled\tif_close.obj} - -{tif_extension} - -{$L Compiled\tif_extension.obj} - -{tif_open} - -function _TIFFgetMode(mode: PAnsiChar; module: PAnsiChar): Integer; cdecl; external; - -{$L Compiled\tif_open.obj} - -{tif_getimage} - -{$L Compiled\tif_getimage.obj} - -{tif_predict} - -function TIFFPredictorInit(tif: PTIFF): Integer; cdecl; external; -function TIFFPredictorCleanup(tif: PTIFF):integer; cdecl; external; //DW 3.8.2 - -{$L Compiled\tif_predict.obj} - -{tif_print} - -{$L Compiled\tif_print.obj} - -{tif_error} - -{$L Compiled\tif_error.obj} - -{tif_strip} - -function _TIFFDefaultStripSize(tif: Pointer; s: Cardinal): Cardinal; cdecl; external; -function TIFFOldScanlineSize(tif: Pointer):Cardinal; cdecl; external; //DW 3.9.1 - -{$L Compiled\tif_strip.obj} - -{tif_swab} - -{$L Compiled\tif_swab.obj} - -{tif_tile} - -function TIFFCheckTile(tif: Pointer; x: Cardinal; y: Cardinal; z: Cardinal; s: Word): Integer; cdecl; external; -procedure _TIFFDefaultTileSize(tif: Pointer; tw: Pointer; th: Pointer); cdecl; external; - -{$L Compiled\tif_tile.obj} - -{tif_warning} - -{$L Compiled\tif_warning.obj} - -{tif_fax3} - -function TIFFInitCCITTRLE(tif: PTIFF; scheme: Integer): Integer; cdecl; external; -function TIFFInitCCITTRLEW(tif: PTIFF; scheme: Integer): Integer; cdecl; external; -function TIFFInitCCITTFax3(tif: PTIFF; scheme: Integer): Integer; cdecl; external; -function TIFFInitCCITTFax4(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_fax3.obj} - -{tif_fax3sm} - -{$L Compiled\tif_fax3sm.obj} - -{tif_jpeg} - -procedure TIFFjpeg_error_exit_raise; cdecl; -begin - raise Exception.Create('TIFFjpeg_error_exit'); -end; - -function TIFFcallvjpeg_jpeg_CreateCompress(cinfo: Pointer; version: Integer; structsize: Cardinal): Integer; cdecl; -begin - try - jpeg_CreateCompress(cinfo,version,structsize); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_CreateDecompress(cinfo: Pointer; version: Integer; structsize: Cardinal): Integer; cdecl; -begin - try - jpeg_CreateDecompress(cinfo,version,structsize); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_set_defaults(cinfo: Pointer): Integer; cdecl; -begin - try - jpeg_set_defaults(cinfo); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_set_colorspace(cinfo: Pointer; colorspace: Integer): Integer; cdecl; -begin - try - jpeg_set_colorspace(cinfo, colorspace); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_set_quality(cinfo: Pointer; quality: Integer; force_baseline: Byte): Integer; cdecl; -begin - try - jpeg_set_quality(cinfo,quality,force_baseline); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_suppress_tables(cinfo: PRJpegCompressStruct; suppress: Byte): Integer; cdecl; -begin - try - jpeg_suppress_tables(cinfo,suppress); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_start_compress(cinfo: PRJpegCompressStruct; write_all_tables: Byte): Integer; cdecl; -begin - try - jpeg_start_compress(cinfo,write_all_tables); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcalljpeg_jpeg_write_scanlines(errreturn: Integer; cinfo: PRJpegCompressStruct; scanlines: Pointer; num_lines: Cardinal): Integer; cdecl; -begin - try - Result:=jpeg_write_scanlines(cinfo,scanlines,num_lines); - except - Result:=errreturn; - end; -end; - -function TIFFcalljpeg_jpeg_write_raw_data(errreturn: Integer; cinfo: PRJpegCompressStruct; data: Pointer; num_lines: Cardinal): Integer; cdecl; -begin - try - Result:=jpeg_write_raw_data(cinfo,data,num_lines); - except - Result:=errreturn; - end; -end; - -function TIFFcallvjpeg_jpeg_finish_compress(cinfo: PRJpegCompressStruct): Integer; cdecl; -begin - try - jpeg_finish_compress(cinfo); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_write_tables(cinfo: PRJpegCompressStruct): Integer; cdecl; -begin - try - jpeg_write_tables(cinfo); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcalljpeg_jpeg_read_header(errreturn: Integer; cinfo: PRJpegDecompressStruct; require_image: Byte): Integer; cdecl; -begin - try - Result:=jpeg_read_header(cinfo,Boolean(require_image)); - except - Result:=errreturn; - end; -end; - -function TIFFcallvjpeg_jpeg_start_decompress(cinfo: PRJpegDecompressStruct): Integer; cdecl; -begin - try - jpeg_start_decompress(cinfo); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcalljpeg_jpeg_read_scanlines(errreturn: Integer; cinfo: PRJpegDecompressStruct; scanlines: Pointer; max_lines: Cardinal): Integer; cdecl; -begin - try - Result:=jpeg_read_scanlines(cinfo,scanlines,max_lines); - except - Result:=errreturn; - end; -end; - -function TIFFcalljpeg_jpeg_read_raw_data(errreturn: Integer; cinfo: PRJpegDecompressStruct; data: Pointer; max_lines: Cardinal): Integer; cdecl; -begin - try - Result:=jpeg_read_raw_data(cinfo,data,max_lines); - except - Result:=errreturn; - end; -end; - -function TIFFcalljpeg_jpeg_finish_decompress(errreturn: Integer; cinfo: PRJpegDecompressStruct): Integer; cdecl; -begin - try - Result:=jpeg_finish_decompress(cinfo); - except - Result:=errreturn; - end; -end; - -function TIFFcallvjpeg_jpeg_abort(cinfo: PRJpegCommonStruct): Integer; cdecl; -begin - try - jpeg_abort(cinfo); - Result:=1; - except - Result:=0; - end; -end; - -function TIFFcallvjpeg_jpeg_destroy(cinfo: PRJpegCommonStruct): Integer; cdecl; -begin - try - jpeg_destroy(cinfo); - Result:=1; - except - Result:=0; - end; -end; - -type - jpeg_alloc_sarray = function(cinfo: PRJpegCommonStruct; pool_id: Integer; samplesperrow: Cardinal; numrows: Cardinal): Pointer; cdecl; - -function TIFFcalljpeg_alloc_sarray(alloc_sarray: jpeg_alloc_sarray; cinfo: PRJpegCommonStruct; pool_id: Integer; samplesperrow: Cardinal; - numrows: Cardinal): Pointer; cdecl; -begin - try - Result:=alloc_sarray(cinfo,pool_id,samplesperrow,numrows); - except - Result:=nil; - end; -end; - -function TIFFInitJPEG(tif: PTIFF; scheme: Integer): Integer; cdecl; external; -function TIFFFillStrip(tif : PTIFF; Len : longword): integer; cdecl; external; //DW 3.8.2 - -{$L Compiled\tif_jpeg.obj} - -{tif_luv} - -function TIFFInitSGILog(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_luv.obj} - -{tif_lzw} - -function TIFFInitLZW(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_lzw.obj} - -{tif_next} - -function TIFFInitNeXT(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_next.obj} - -{tif_packbits} - -function TIFFInitPackBits(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_packbits.obj} - -{tif_pixarlog} - -function TIFFInitPixarLog(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_pixarlog.obj} - -{tif_thunder} - -function TIFFInitThunderScan(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_thunder.obj} - -{tif_version} - -{$L Compiled\tif_version.obj} - -{tif_zip} - -function TIFFInitZIP(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{$L Compiled\tif_zip.obj} - -{tif_codec} - -function NotConfigured(tif: PTIFF; scheme: Integer): Integer; cdecl; external; - -{DW -const - - _TIFFBuiltinCODECS: array[0..17] of TIFFCodec = ( - (name:'None'; scheme: COMPRESSION_NONE; init: TIFFInitDumpMode), - (name:'LZW'; scheme: COMPRESSION_LZW; init: TIFFInitLZW), - (name:'PackBits'; scheme: COMPRESSION_PACKBITS; init: TIFFInitPackBits), - (name:'ThunderScan'; scheme: COMPRESSION_THUNDERSCAN; init: TIFFInitThunderScan), - (name:'NeXT'; scheme: COMPRESSION_NEXT; init: TIFFInitNeXT), - (name:'JPEG'; scheme: COMPRESSION_JPEG; init: TIFFInitJPEG), - (name:'Old-style JPEG'; scheme: COMPRESSION_OJPEG; init: NotConfigured), - (name:'CCITT RLE'; scheme: COMPRESSION_CCITTRLE; init: TIFFInitCCITTRLE), - (name:'CCITT RLE/W'; scheme: COMPRESSION_CCITTRLEW; init: TIFFInitCCITTRLEW), - (name:'CCITT Group 3'; scheme: COMPRESSION_CCITTFAX3; init: TIFFInitCCITTFax3), - (name:'CCITT Group 4'; scheme: COMPRESSION_CCITTFAX4; init: TIFFInitCCITTFax4), - (name:'ISO JBIG'; scheme: COMPRESSION_JBIG; init: NotConfigured), - (name:'Deflate'; scheme: COMPRESSION_DEFLATE; init: TIFFInitZIP), - (name:'AdobeDeflate'; scheme: COMPRESSION_ADOBE_DEFLATE; init: TIFFInitZIP), - (name:'PixarLog'; scheme: COMPRESSION_PIXARLOG; init: TIFFInitPixarLog), - (name:'SGILog'; scheme: COMPRESSION_SGILOG; init: TIFFInitSGILog), - (name:'SGILog24'; scheme: COMPRESSION_SGILOG24; init: TIFFInitSGILog), - (name:nil; scheme:0; init:nil)); -} - -{$L Compiled\tif_codec.obj} - -{LibTiffDelphi} - -function TIFFFileReadProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; forward; -function TIFFFileWriteProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; forward; -function TIFFFileSizeProc(Fd: Cardinal): Cardinal; cdecl; forward; -function TIFFFileSeekProc(Fd: Cardinal; Off: Cardinal; Whence: Integer): Cardinal; cdecl; forward; -function TIFFFileCloseProc(Fd: Cardinal): Integer; cdecl; forward; - -function TIFFStreamReadProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; forward; -function TIFFStreamWriteProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; forward; -function TIFFStreamSizeProc(Fd: Cardinal): Cardinal; cdecl; forward; -function TIFFStreamSeekProc(Fd: Cardinal; Off: Cardinal; Whence: Integer): Cardinal; cdecl; forward; -function TIFFStreamCloseProc(Fd: Cardinal): Integer; cdecl; forward; - -function TIFFNoMapProc(Fd: Cardinal; PBase: PPointer; PSize: PCardinal): Integer; cdecl; forward; -procedure TIFFNoUnmapProc(Fd: Cardinal; Base: Pointer; Size: Cardinal); cdecl; forward; - -function TIFFFileCloseProc(Fd: Cardinal): Integer; cdecl; -begin - if CloseHandle(Fd)=True then - Result:=0 - else - Result:=-1; -end; - -function TIFFFileSizeProc(Fd: Cardinal): Cardinal; cdecl; -begin - Result:=GetFileSize(Fd,nil); -end; - -function TIFFFileSeekProc(Fd: Cardinal; Off: Cardinal; Whence: Integer): Cardinal; cdecl; -const - SEEK_SET = 0; - SEEK_CUR = 1; - SEEK_END = 2; -var - MoveMethod: Cardinal; -begin - if Off=$ffffffff then - begin - Result:=$ffffffff; - exit; - end; - case Whence of - SEEK_SET: MoveMethod:=FILE_BEGIN; - SEEK_CUR: MoveMethod:=FILE_CURRENT; - SEEK_END: MoveMethod:=FILE_END; - else - MoveMethod:=FILE_BEGIN; - end; - Result:=SetFilePointer(Fd,Off,nil,MoveMethod); -end; - -function TIFFFileReadProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; -var - m: Cardinal; -begin - if ReadFile(Fd,Buffer^,Cardinal(Size),m,nil)=False then - Result:=0 - else - Result:=m; -end; - -function TIFFFileWriteProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; -var - m: Cardinal; -begin - if WriteFile(Fd,Buffer^,Cardinal(Size),m,nil)=False then - Result:=0 - else - Result:=m; -end; - -function TIFFStreamCloseProc(Fd: Cardinal): Integer; cdecl; -begin - Result:=0; -end; - -function TIFFStreamSizeProc(Fd: Cardinal): Cardinal; cdecl; -begin - try - Result:=TStream(Fd).Size; - except - Result:=0; - end; -end; - -function TIFFStreamSeekProc(Fd: Cardinal; Off: Cardinal; Whence: Integer): Cardinal; cdecl; -const - SEEK_SET = 0; - SEEK_CUR = 1; - SEEK_END = 2; -var - MoveMethod: Word; -begin - if Off=$ffffffff then - begin - Result:=$ffffffff; - exit; - end; - case Whence of - SEEK_SET: MoveMethod:=soFromBeginning; - SEEK_CUR: MoveMethod:=soFromCurrent; - SEEK_END: MoveMethod:=soFromEnd; - else - MoveMethod:=soFromBeginning; - end; - try - Result:=TStream(Fd).Seek(Off,MoveMethod); - except - Result:=0; - end; -end; - -function TIFFStreamReadProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; -begin - try - Result:=TStream(Fd).Read(Buffer^,Size); - except - Result:=0; - end; -end; - -function TIFFStreamWriteProc(Fd: Cardinal; Buffer: Pointer; Size: Integer): Integer; cdecl; -begin - try - Result:=TStream(Fd).Write(Buffer^,Size); - except - Result:=0; - end; -end; - -function TIFFNoMapProc(Fd: Cardinal; PBase: PPointer; PSize: PCardinal): Integer; cdecl; -begin - Result:=0; -end; - -procedure TIFFNoUnmapProc(Fd: Cardinal; Base: Pointer; Size: Cardinal); cdecl; -begin -end; - -function TIFFOpen(const Name: AnsiString; const Mode: AnsiString): PTIFF; -const - Module: AnsiString = 'TIFFOpen'; - O_RDONLY = 0; - O_WRONLY = 1; - O_RDWR = 2; - O_CREAT = $0100; - O_TRUNC = $0200; -var - m: Integer; - DesiredAccess: Cardinal; - CreateDisposition: Cardinal; - FlagsAndAttributes: Cardinal; - fd: THandle; -begin - m:=_TIFFgetMode(PAnsiChar(Mode),PAnsiChar(Module)); - if m=o_RDONLY then - DesiredAccess:=GENERIC_READ - else - DesiredAccess:=(GENERIC_READ or GENERIC_WRITE); - case m of - O_RDONLY: CreateDisposition:=OPEN_EXISTING; - O_RDWR: CreateDisposition:=OPEN_ALWAYS; - (O_RDWR or O_CREAT): CreateDisposition:=OPEN_ALWAYS; - (O_RDWR or O_TRUNC): CreateDisposition:=CREATE_ALWAYS; - (O_RDWR or O_CREAT or O_TRUNC): CreateDisposition:=CREATE_ALWAYS; - else - Result:=nil; - exit; - end; - if m=O_RDONLY then - FlagsAndAttributes:=FILE_ATTRIBUTE_READONLY - else - FlagsAndAttributes:=FILE_ATTRIBUTE_NORMAL; - fd:=CreateFileA(PAnsiChar(Name),DesiredAccess,FILE_SHARE_READ,nil,CreateDisposition,FlagsAndAttributes,0); - if fd=INVALID_HANDLE_VALUE then - begin - TiffError(PAnsiChar(Module),PAnsiChar('%s: Cannot open'),PAnsiChar(Name)); - Result:=nil; - exit; - end; - Result:=TIFFClientOpen(PAnsiChar(Name),PAnsiChar(Mode),fd,@TIFFFileReadProc,@TIFFFileWriteProc,@TIFFFileSeekProc,@TIFFFileCloseProc, - @TIFFFileSizeProc,@TIFFNoMapProc,@TIFFNoUnmapProc); - if Result<>nil then - TIFFSetFileno(Result,fd) - else - CloseHandle(fd); -end; - -function TIFFOpenStream(const Stream: TStream; const Mode: AnsiString): PTIFF; -var - m: AnsiString; -begin - m:='Stream'; - Result:=TIFFClientOpen(PAnsiChar(m),PAnsiChar(Mode),Cardinal(Stream),@TIFFStreamReadProc,@TIFFStreamWriteProc,@TIFFStreamSeekProc,@TIFFStreamCloseProc, - @TIFFStreamSizeProc,@TIFFNoMapProc,@TIFFNoUnmapProc); - if Result<>nil then TIFFSetFileno(Result,Cardinal(Stream)); -end; - - -initialization - - _TIFFwarningHandler:=LibTiffDelphiWarningThrp; - _TIFFerrorHandler:=LibTiffDelphiErrorThrp; - -end. - diff --git a/3rd/Imaging/Extras/Extensions/LibTiff/ZLibDelphi.pas b/3rd/Imaging/Extras/Extensions/LibTiff/ZLibDelphi.pas deleted file mode 100644 index e96491c78..000000000 --- a/3rd/Imaging/Extras/Extensions/LibTiff/ZLibDelphi.pas +++ /dev/null @@ -1,80 +0,0 @@ -unit ZLibDelphi; - -interface - -uses - Windows, SysUtils; - -const - - ZLIB_VERSION = '1.2.1'; - - Z_NO_FLUSH = 0; - Z_FINISH = 4; - - Z_OK = 0; - Z_STREAM_END = 1; - -type - - PRZStream = ^RZStream; - - RZStream = record - NextIn: PByte; - AvailIn: Cardinal; - TotalIn: Cardinal; - NextOut: PByte; - AvailOut: Cardinal; - TotalOut: Cardinal; - Msg: PAnsiChar; - State: Pointer; - AllocFunc: Pointer; - FreeFunc: Pointer; - Opaque: Cardinal; - DataType: Integer; - Adler: Cardinal; - Reserved: Cardinal; - end; - -function inflateInit_(strm: Pointer; version: Pointer; stream_size: Integer): Integer; cdecl; external; -function inflateReset(strm: Pointer): Integer; cdecl; external; -function inflate(strm: Pointer; flush: Integer): Integer; cdecl; external; -function inflateSync(strm: Pointer): Integer; cdecl; external; -function deflateInit(strm: Pointer; level: Integer): Integer; -function deflateInit_(strm: Pointer; level: Integer; version: Pointer; stream_size: Integer): Integer; cdecl; external; -function deflateReset(strm: Pointer): Integer; cdecl; external; -function deflate(strm: Pointer; flush: Integer): Integer; cdecl; external; -function deflateEnd(strm: Pointer): Integer; cdecl; external; -function inflateEnd(strm: Pointer): Integer; cdecl; external; -function deflateParams(strm: Pointer; level: Integer; strategy: Integer): Integer; cdecl; external; - -implementation - -uses - LibDelphi; - -function deflateInit(strm: Pointer; level: Integer): Integer; -begin - Result:=deflateInit_(strm,level,PAnsiChar(ZLIB_VERSION),SizeOf(RZStream)); -end; - -{$L Compiled\inflate.obj} -{$L Compiled\crc32.obj} -{$L Compiled\adler32.obj} -{$L Compiled\inftrees.obj} -{$L Compiled\inffast.obj} -{$L Compiled\deflate.obj} -{$L Compiled\zutil.obj} -{$L Compiled\trees.obj} -{$L Compiled\compress.obj} -{$L Compiled\uncompr.obj} - -end. - - - - - - - - diff --git a/3rd/Imaging/Extras/Extensions/OpenJpeg.pas b/3rd/Imaging/Extras/Extensions/OpenJpeg.pas deleted file mode 100644 index b42225399..000000000 --- a/3rd/Imaging/Extras/Extensions/OpenJpeg.pas +++ /dev/null @@ -1,740 +0,0 @@ -(* - * Copyright (c) 2002-2007, Communications and Remote Sensing Laboratory, Universite catholique de Louvain (UCL), Belgium - * Copyright (c) 2002-2007, Professor Benoit Macq - * Copyright (c) 2001-2003, David Janssens - * Copyright (c) 2002-2003, Yannick Verschueren - * Copyright (c) 2003-2007, Francois-Olivier Devaux and Antonin Descampe - * Copyright (c) 2005, Herve Drolon, FreeImage Team - * Copyright (c) 2006-2007, Parvatha Elangovan - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *) - -{ - PasOpenJpeg - Free JPEG 2000 library for Delphi and Free Pascal - - Headers translated to Object Pascal and C code precompliled - by Marek Mauder (http://galfar.vevb.net) - for Vampyre Imaging Library (http://imaginglib.sourceforge.net). - - Supported compilers: Delphi, Free Pascal - Supported platforms (tested): Windows 32bit, Linux 32/64bit - - OpenJpeg Homepage: http://www.openjpeg.org - PasOpenJpeg Homepage: http://galfar.vevb.net/openjpeg - - Current Version: 1.05 (OpenJpeg 1.3 SVN revision 611 with CDEF/PCLR patch) - - History: - v1.05 (2010-08-12): - - added palette support - - added CMYK support - v1.04 (2010-06-08): - - added few Pascal-looking type aliases - v1.03 (2009-06-04): - - added Mac OSX x86 support - v1.02 (2009-01-30): - - removed linking to stdc++ lib in LINUX/UNIX - v1.01 (2008-12-27): - - Delphi 2009 compatibility checks - v1.00 (2008-03-01): - - CDEF patch for OpenJpeg, added component types -} - -unit OpenJpeg; - -{$IFDEF FPC} - { Free Pascal settings } - {$PACKRECORDS 8} - {$PACKENUM 4} -{$ELSE} - { Delphi settings } - {$DEFINE DCC} - {$ALIGN 8} - {$MINENUMSIZE 4} -{$ENDIF} - -interface - -const - OPENJPEG_VERSION = '1.3.0'; - -type - Bool = ByteBool; - Char = AnsiChar; - -{ Constant Definitions } - -const - { Maximum allowed size for filenames } - OPJ_PATH_LEN = 4096; - - { Number of maximum resolution level authorized } - J2K_MAXRLVLS = 33; - { Number of maximum sub-band linked to number of resolution level } - J2K_MAXBANDS = 3 * J2K_MAXRLVLS - 2; - - JPWL_MAX_NO_TILESPECS = 16; - JPWL_MAX_NO_PACKSPECS = 16; - JPWL_MAX_NO_MARKERS = 512; - JPWL_PRIVATEINDEX_NAME = 'jpwl_index_privatefilename'; - JPWL_EXPECTED_COMPONENTS = 3; - JPWL_MAXIMUM_TILES = 8192; - JPWL_MAXIMUM_HAMMING = 2; - JPWL_MAXIMUM_EPB_ROOM = 65450; - -{ Enum Definitions } - -type - { Rsiz capabilities } - OPJ_RSIZ_CAPABILITIES = ( - STD_RSIZ = 0, { Standard JPEG2000 profile } - CINEMA2K = 3, { Profile name for a 2K image } - CINEMA4K = 4 { Profile name for a 4K image } - ); - - { Digital cinema operation mode } - OPJ_CINEMA_MODE = ( - OFF = 0, { Not Digital Cinema } - CINEMA2K_24 = 1, { 2K Digital Cinema at 24 fps } - CINEMA2K_48 = 2, { 2K Digital Cinema at 48 fps } - CINEMA4K_24 = 3 { 4K Digital Cinema at 24 fps } - ); - - { Progression order } - OPJ_PROG_ORDER = ( - PROG_UNKNOWN = -1, { place-holder } - LRCP = 0, { layer-resolution-component-precinct order } - RLCP = 1, { resolution-layer-component-precinct order } - RPCL = 2, { resolution-precinct-component-layer order } - PCRL = 3, { precinct-component-resolution-layer order } - CPRL = 4 { component-precinct-resolution-layer order } - ); - - { Supported image color spaces } - OPJ_COLOR_SPACE = ( - CLRSPC_UNKNOWN = -1, { place-holder } - CLRSPC_SRGB = 1, { sRGB } - CLRSPC_GRAY = 2, { grayscale } - CLRSPC_SYCC = 3, { YUV } - CLRSPC_CMYK = 4 { CMYK } - ); - TOpjColorSpace = OPJ_COLOR_SPACE; - - { Supported image component types - added by patch } - OPJ_COMPONENT_TYPE = ( - COMPTYPE_UNKNOWN = 0, { unknown component type, cdef box not present } - COMPTYPE_R = 1, { red component of sRGB image } - COMPTYPE_G = 2, { green component of sRGB image } - COMPTYPE_B = 3, { blue component of sRGB image } - COMPTYPE_L = 4, { luminance component of YUV and grayscale images } - COMPTYPE_CB = 5, { Cb component of YUV image } - COMPTYPE_CR = 6, { Cr component of YUV image } - COMPTYPE_OPACITY = 7, { opacity/alpha channel } - COMPTYPE_C = 8, { C component of CMYK image } - COMPTYPE_M = 9, { M component of CMYK image } - COMPTYPE_Y = 10, { Y component of CMYK image } - COMPTYPE_K = 11 { K component of CMYK image } - ); - TOpjComponentType = OPJ_COMPONENT_TYPE; - - { Supported codec } - OPJ_CODEC_FORMAT = ( - CODEC_UNKNOWN = -1, { place-holder } - CODEC_J2K = 0, { JPEG-2000 codestream : read/write } - CODEC_JPT = 1, { JPT-stream (JPEG 2000, JPIP) : read only } - CODEC_JP2 = 2 { JPEG-2000 file format : read/write } - ); - - { Limit decoding to certain portions of the codestream. } - OPJ_LIMIT_DECODING = ( - NO_LIMITATION = 0, { No limitation for the decoding. The entire codestream will de decoded } - LIMIT_TO_MAIN_HEADER = 1, { The decoding is limited to the Main Header } - DECODE_ALL_BUT_PACKETS = 2 { Decode everything except the JPEG 2000 packets } - ); - -{ Event Manager Type Definitions } - - { Callback function prototype for events } - opj_msg_callback = procedure(msg: PAnsiChar; client_data: Pointer); cdecl; - { Message handler object } - opj_event_mgr = record - error_handler: opj_msg_callback; { Error message callback if available, NULL otherwise } - warning_handler: opj_msg_callback; { Warning message callback if available, NULL otherwise } - info_handler: opj_msg_callback; { Debug message callback if available, NULL otherwise } - end; - opj_event_mgr_t = opj_event_mgr; - popj_event_mgr_t = ^opj_event_mgr_t; - - -{ Codec Type Definitions } - - { Progression order changes } - opj_poc = record - resno0, compno0: Integer; - layno1, resno1, compno1: Integer; - layno0, precno0, precno1: Integer; - prg1, prg: OPJ_PROG_ORDER; - progorder: array[0..4] of Char; - tile: Integer; - tx0, tx1, ty0, ty1: Integer; - layS, resS, compS, prcS: Integer; - layE, resE, compE, prcE: Integer; - txS, txE, tyS, tyE, dx, dy: Integer; - lay_t, res_t, comp_t, prc_t, tx0_t, ty0_t: Integer; - end; - opj_poc_t = opj_poc; - - { Compression parameters } - opj_cparameters = record - tile_size_on: Bool; - cp_tx0: Integer; - cp_ty0: Integer; - cp_tdx: Integer; - cp_tdy: Integer; - cp_disto_alloc: Integer; - cp_fixed_alloc: Integer; - cp_fixed_quality: Integer; - cp_matrice: PInteger; - cp_comment: PAnsiChar; - csty: Integer; - prog_order: OPJ_PROG_ORDER; - POC: array[0..31] of opj_poc_t; - numpocs: Integer; - tcp_numlayers: Integer; - tcp_rates: array[0..99] of Single; - tcp_distoratio: array[0..99] of Single; - numresolution: Integer; - cblockw_init: Integer; - cblockh_init: Integer; - mode: Integer; - irreversible: Integer; - roi_compno: Integer; - roi_shift: Integer; - res_spec: Integer; - prcw_init: array[0..J2K_MAXRLVLS - 1] of Integer; - prch_init: array[0..J2K_MAXRLVLS - 1] of Integer; - infile: array[0..OPJ_PATH_LEN - 1] of Char; - outfile: array[0..OPJ_PATH_LEN - 1] of Char; - index_on: Integer; - index: array[0..OPJ_PATH_LEN - 1] of Char; - image_offset_x0: Integer; - image_offset_y0: Integer; - subsampling_dx: Integer; - subsampling_dy: Integer; - decod_format: Integer; - cod_format: Integer; - jpwl_epc_on: Bool; - jpwl_hprot_MH: Integer; - jpwl_hprot_TPH_tileno: array[0..JPWL_MAX_NO_TILESPECS - 1] of Integer; - jpwl_hprot_TPH: array[0..JPWL_MAX_NO_TILESPECS - 1] of Integer; - jpwl_pprot_tileno: array[0..JPWL_MAX_NO_PACKSPECS - 1] of Integer; - jpwl_pprot_packno: array[0..JPWL_MAX_NO_PACKSPECS - 1] of Integer; - jpwl_pprot: array[0..JPWL_MAX_NO_PACKSPECS - 1] of Integer; - jpwl_sens_size: Integer; - jpwl_sens_addr: Integer; - jpwl_sens_range: Integer; - jpwl_sens_MH: Integer; - jpwl_sens_TPH_tileno: array[0..JPWL_MAX_NO_TILESPECS - 1] of Integer; - jpwl_sens_TPH: array[0..JPWL_MAX_NO_TILESPECS - 1] of Integer; - cp_cinema: OPJ_CINEMA_MODE; - max_comp_size: Integer; - cp_rsiz: OPJ_RSIZ_CAPABILITIES; - tp_on: Byte; - tp_flag: Byte; - tcp_mct: Byte; - end; - opj_cparameters_t = opj_cparameters; - popj_cparameters_t = ^opj_cparameters_t; - TOpjCParameters = opj_cparameters_t; - - { Decompression parameters } - opj_dparameters = record - cp_reduce: Integer; - cp_layer: Integer; - infile: array[0..OPJ_PATH_LEN - 1] of Char; - outfile: array[0..OPJ_PATH_LEN - 1] of Char; - decod_format: Integer; - cod_format: Integer; - jpwl_correct: Bool; - jpwl_exp_comps: Integer; - jpwl_max_tiles: Integer; - cp_limit_decoding: OPJ_LIMIT_DECODING; - end; - opj_dparameters_t = opj_dparameters; - popj_dparameters_t = ^opj_dparameters_t; - TOpjDParameters = opj_dparameters_t; - - { Routines that are to be used by both halves of the library are declared - to receive a Pointer to this structure. There are no actual instances of - opj_common_struct_t, only of opj_cinfo_t and opj_dinfo_t. } - opj_common_struct = record - event_mgr: popj_event_mgr_t; { Pointer to the event manager } - client_data: Pointer; { Available for use by application } - is_decompressor: Bool; { So common code can tell which is which } - codec_format: OPJ_CODEC_FORMAT; { selected codec } - j2k_handle: Pointer; { Pointer to the J2K codec } - jp2_handle: Pointer; { Pointer to the JP2 codec } - mj2_handle: Pointer; - end; - opj_common_struct_t = opj_common_struct; - opj_common_ptr = ^opj_common_struct_t; - - { Compression context info } - opj_cinfo = record - event_mgr: popj_event_mgr_t; - client_data: Pointer; - is_decompressor: Bool; - codec_format: OPJ_CODEC_FORMAT; - j2k_handle: Pointer; - jp2_handle: Pointer; - mj2_handle: Pointer; - end; - opj_cinfo_t = opj_cinfo; - popj_cinfo_t = ^opj_cinfo_t; - TOpjCInfo = opj_cinfo_t; - POpjCInfo = popj_cinfo_t; - - { Decompression context info } - opj_dinfo = record - event_mgr: popj_event_mgr_t; - client_data: Pointer; - is_decompressor: Bool; - codec_format: OPJ_CODEC_FORMAT; - j2k_handle: Pointer; - jp2_handle: Pointer; - mj2_handle: Pointer; - end; - opj_dinfo_t = opj_dinfo; - popj_dinfo_t = ^opj_dinfo_t; - TOpjDInfo = opj_dinfo_t; - POpjDInfo = popj_dinfo_t; - -{ I/O Stream Types Definitions } - -const - { Stream open flags } - { The stream was opened for reading } - OPJ_STREAM_READ = $0001; - { The stream was opened for writing } - OPJ_STREAM_WRITE = $0002; - -type - { Byte input-output stream (CIO) } - opj_cio = record - cinfo: opj_common_ptr; { codec context } - openmode: Integer; { open mode (read/write) either OPJ_STREAM_READ or OPJ_STREAM_WRITE } - buffer: PAnsiChar; { Pointer to the start of the buffer } - length: Integer; { buffer size in bytes } - start: PAnsiChar; { Pointer to the start of the stream } - end_: PAnsiChar; { Pointer to the end of the stream } - bp: PAnsiChar; { Pointer to the current position } - end; - opj_cio_t = opj_cio; - popj_cio_t = ^opj_cio_t; - TOpjCio = opj_cio_t; - POpjCio = popj_cio_t; - -{ Image Type Definitions } - - { Defines a single image component } - opj_image_comp = record - dx: Integer; { XRsiz: horizontal separation of a sample of ith component with respect to the reference grid } - dy: Integer; { YRsiz: vertical separation of a sample of ith component with respect to the reference grid } - w: Integer; { data width } - h: Integer; { data height } - x0: Integer; { x component offset compared to the whole image } - y0: Integer; { y component offset compared to the whole image } - prec: Integer; { precision } - bpp: Integer; { image depth in bits } - sgnd: Integer; { signed (1) / unsigned (0) } - resno_decoded: Integer; { number of decoded resolution } - factor: Integer; { number of division by 2 of the out image compared to the original size of image } - comp_type: OPJ_COMPONENT_TYPE; { type of this component: color channel, opacity, ... } - data: PIntegerArray; { image component data } - end; - opj_image_comp_t = opj_image_comp; - popj_image_comp_t = ^opj_image_comp_t; - opj_image_comp_array = array[0..255] of opj_image_comp_t; - popj_image_comp_array = ^opj_image_comp_array; - TOpjImageComp = opj_image_comp_t; - POpjImageComp = popj_image_comp_t; - - { Defines image palette - added by patch } - opj_image_palette = record - hascmap: Integer; { set to one if the original image had a component mapping box } - haspalette: Integer; { set to one if the original image had a palette color box } - numchans: Integer; { number of channels the palette has } - numentrs: Integer; { number of entries the palette has } - sizentr: Integer; { size of one entry for one channel (in bytes) } - paldata: PByte; { byte pointer to the palette data } - end; - opj_image_palette_t = opj_image_palette; - popj_image_palette_t = ^opj_image_palette_t; - - { Defines image data and characteristics } - opj_image = record - x0: Integer; { XOsiz: horizontal offset from the origin of the reference grid to the left side of the image area } - y0: Integer; { YOsiz: vertical offset from the origin of the reference grid to the top side of the image area } - x1: Integer; { Xsiz: width of the reference grid } - y1: Integer; { Ysiz: height of the reference grid } - numcomps: Integer; { number of components in the image } - color_space: OPJ_COLOR_SPACE; { color space: sRGB, Greyscale or YUV } - comps: popj_image_comp_array; { image components } - palette: popj_image_palette_t; { palette structure } - end; - opj_image_t = opj_image; - popj_image_t = ^opj_image_t; - TOpjImage = opj_image_t; - POpjImage = popj_image_t; - - { Component parameters structure used by the opj_image_create function } - opj_image_comptparm = record - dx: Integer; { XRsiz: horizontal separation of a sample of ith component with respect to the reference grid } - dy: Integer; { YRsiz: vertical separation of a sample of ith component with respect to the reference grid } - w: Integer; { data width } - h: Integer; { data height } - x0: Integer; { x component offset compared to the whole image } - y0: Integer; { y component offset compared to the whole image } - prec: Integer; { precision } - bpp: Integer; { image depth in bits } - sgnd: Integer; { signed (1) / unsigned (0) } - comp_type: OPJ_COMPONENT_TYPE; { type of this component: color channel, opacity, ... } - end; - opj_image_cmptparm_t = opj_image_comptparm; - popj_image_cmptparm_t = ^opj_image_cmptparm_t; - opj_image_cmptparm_array = array[0..255] of opj_image_cmptparm_t; - popj_image_cmptparm_array = ^opj_image_cmptparm_array; - TOpjImageCompParam = opj_image_cmptparm_t; - -{ OpenJpeg Version Functions Definitions } - -function opj_version: PAnsiChar; cdecl; external; - -{ Image Functions Definitions } - -{ Create an image - @param numcmpts number of components - @param cmptparms components parameters - @param clrspc image color space - @return returns a new image structure if successful, returns NULL otherwise } -function opj_image_create(numcmpts: Integer; cmptparms: popj_image_cmptparm_t; - clrspc: OPJ_COLOR_SPACE): popj_image_t; cdecl; external; - -{ Deallocate any resources associated with an image - @param image image to be destroyed } -procedure opj_image_destroy(image: popj_image_t); cdecl; external; - -{ Stream Functions Definitions } - -{ Open and allocate a memory stream for read / write. - On reading, the user must provide a buffer containing encoded data. The buffer - will be wrapped by the returned CIO handle. - On writing, buffer parameters must be set to 0: a buffer will be allocated - by the library to contain encoded data. - @param cinfo Codec context info - @param buffer Reading: buffer address. Writing: NULL - @param length Reading: buffer length. Writing: 0 - @return Returns a CIO handle if successful, returns NULL otherwise } -function opj_cio_open(cinfo: opj_common_ptr; buffer: PByte; - length: Integer): popj_cio_t; cdecl; external; - -{ Close and free a CIO handle - @param cio CIO handle to free } -procedure opj_cio_close(cio: popj_cio_t); cdecl; external; - -{ Get position in byte stream - @param cio CIO handle - @return Returns the position in bytes } -function cio_tell(cio: popj_cio_t): Integer; cdecl; external; - -{ Set position in byte stream - @param cio CIO handle - @param pos Position, in number of bytes, from the beginning of the stream } -procedure cio_seek(cio: popj_cio_t; pos: Integer); cdecl; external; - -{ Event Manager Functions Definitions } - -function opj_set_event_mgr(cinfo: opj_common_ptr; event_mgr: popj_event_mgr_t; - context: Pointer): popj_event_mgr_t; cdecl; external; - -{ Codec Functions Definitions } - -{ Creates a J2K/JPT/JP2 decompression structure - @param format Decoder to select - @return Returns a handle to a decompressor if successful, returns NULL otherwise } -function opj_create_decompress(format: OPJ_CODEC_FORMAT): popj_dinfo_t; cdecl; external; - -{ Destroy a decompressor handle - @param dinfo decompressor handle to destroy } -procedure opj_destroy_decompress(dinfo: popj_dinfo_t); cdecl; external; - -{ Set decoding parameters to default values - @param parameters Decompression parameters } -procedure opj_set_default_decoder_parameters(parameters: popj_dparameters_t); cdecl; external ; - -{ Setup the decoder decoding parameters using user parameters. - Decoding parameters are returned in j2k->cp. - @param dinfo decompressor handle - @param parameters decompression parameters } -procedure opj_setup_decoder(dinfo: popj_dinfo_t; parameters: popj_dparameters_t); cdecl; external; - -{ Decode an image from a JPEG-2000 codestream - @param dinfo decompressor handle - @param cio Input buffer stream - @return Returns a decoded image if successful, returns NULL otherwise } -function opj_decode(dinfo: popj_dinfo_t; cio: popj_cio_t): popj_image_t; cdecl; external; - -{ Creates a J2K/JP2 compression structure - @param format Coder to select - @return Returns a handle to a compressor if successful, returns NULL otherwise } -function opj_create_compress(format: OPJ_CODEC_FORMAT): popj_cinfo_t; cdecl; external; - -{ Destroy a compressor handle - @param cinfo compressor handle to destroy } -procedure opj_destroy_compress(cinfo: popj_cinfo_t); cdecl; external; - -{ Set encoding parameters to default values, that means : - <ul> - <li>Lossless - <li>1 tile - <li>Size of precinct : 2^15 x 2^15 (means 1 precinct) - <li>Size of code-block : 64 x 64 - <li>Number of resolutions: 6 - <li>No SOP marker in the codestream - <li>No EPH marker in the codestream - <li>No sub-sampling in x or y direction - <li>No mode switch activated - <li>Progression order: LRCP - <li>No index file - <li>No ROI upshifted - <li>No offset of the origin of the image - <li>No offset of the origin of the tiles - <li>Reversible DWT 5-3 - </ul> - @param parameters Compression parameters } -procedure opj_set_default_encoder_parameters(parameters: popj_cparameters_t); cdecl; external; - -{ Setup the encoder parameters using the current image and using user parameters. - @param cinfo compressor handle - @param parameters compression parameters - @param image input filled image } -procedure opj_setup_encoder(cinfo: popj_cinfo_t; parameters: popj_cparameters_t; - image: popj_image_t); cdecl; external; - -{ Encode an image into a JPEG-2000 codestream - @param cinfo compressor handle - @param cio Output buffer stream - @param image Image to encode - @param index Name of the index file if required, NULL otherwise - @return Returns true if successful, returns false otherwise } -function opj_encode(cinfo: popj_cinfo_t; cio: popj_cio_t; image: popj_image_t; - index: PAnsiChar): Bool; cdecl; external; - -implementation - -function pow(const Base, Exponent: Double): Double; cdecl; {$IFDEF FPC}[Public];{$ENDIF} -begin - if Exponent = 0.0 then - Result := 1.0 - else if (Base = 0.0) and (Exponent > 0.0) then - Result := 0.0 - else - Result := Exp(Exponent * Ln(Base)); -end; - -{$IF Defined(MSWINDOWS)} - {$IF Defined(DCC)} - { Delphi Win32 } - { Link object files created with C++ Builder.} - {$L J2KObjects\pi.obj} - {$L J2KObjects\openjpeg.obj} - {$L J2KObjects\j2k_lib.obj} - {$L J2KObjects\event.obj} - {$L J2KObjects\cio.obj} - {$L J2KObjects\image.obj} - {$L J2KObjects\j2k.obj} - {$L J2KObjects\jp2.obj} - {$L J2KObjects\jpt.obj} - {$L J2KObjects\mqc.obj} - {$L J2KObjects\raw.obj} - {$L J2KObjects\bio.obj} - {$L J2KObjects\tgt.obj} - {$L J2KObjects\tcd.obj} - {$L J2KObjects\t1.obj} - {$L J2KObjects\dwt.obj} - {$L J2KObjects\t2.obj} - {$L J2KObjects\mct.obj} - - const - { MS C Runtime library needed for importing std C functions.} - MSCRuntimeLib = 'msvcrt.dll'; - var - { Some unresolved external constants.} - __turboFloat: LongBool = False; - _max_dble: Double = 1.7e308; - _streams: Pointer; - - { Internal OpenJpeg functions external declarations. - Delphi yells 'unsatisfied external declaration' if they are not referenced here.} - procedure mqc_create; cdecl; external; - procedure raw_create; cdecl; external; - procedure bio_create; cdecl; external; - procedure opj_image_create0; cdecl; external; - procedure opj_event_msg; cdecl; external; - procedure opj_clock; cdecl; external; - procedure cio_read; cdecl; external; - procedure cio_write; cdecl; external; - procedure cio_skip; cdecl; external; - procedure bio_read; cdecl; external; - procedure bio_write; cdecl; external; - procedure cio_numbytesleft; cdecl; external; - procedure cio_getbp; cdecl; external; - procedure j2k_destroy_compress; cdecl; external; - procedure tgt_create; cdecl; external; - procedure tgt_destroy; cdecl; external; - procedure mqc_bypass_enc; cdecl; external; - procedure mqc_encode; cdecl; external; - procedure mqc_decode; cdecl; external; - procedure raw_decode; cdecl; external; - procedure mqc_resetstates; cdecl; external; - procedure mqc_setstate; cdecl; external; - procedure mqc_init_enc; cdecl; external; - procedure mqc_segmark_enc; cdecl; external; - procedure mqc_flush; cdecl; external; - procedure mqc_bypass_init_enc; cdecl; external; - procedure mqc_numbytes; cdecl; external; - procedure mqc_reset_enc; cdecl; external; - procedure mqc_erterm_enc; cdecl; external; - procedure mqc_init_dec; cdecl; external; - procedure raw_init_dec; cdecl; external; - procedure mqc_destroy; cdecl; external; - procedure mqc_restart_init_enc; cdecl; external; - procedure raw_destroy; cdecl; external; - procedure tgt_reset; cdecl; external; - procedure tgt_setvalue; cdecl; external; - procedure bio_init_enc; cdecl; external; - procedure bio_flush; cdecl; external; - procedure bio_numbytes; cdecl; external; - procedure bio_destroy; cdecl; external; - procedure bio_init_dec; cdecl; external; - procedure pi_create_encode; cdecl; external; - procedure pi_initialise_encode; cdecl; external; - procedure pi_create_decode; cdecl; external; - procedure pi_next; cdecl; external; - procedure pi_destroy; cdecl; external; - procedure tgt_encode; cdecl; external; - procedure tgt_decode; cdecl; external; - procedure bio_inalign; cdecl; external; - - procedure _llmul; cdecl; - asm - { from Delphi's System.pas __llmul } - push edx - push eax - - mov eax, [esp+16] - mul dword ptr [esp] - mov ecx, eax - - mov eax, [esp+4] - mul dword ptr [esp+12] - add ecx, eax - - mov eax, [esp] - mul dword ptr [esp+12] - add edx, ecx - - pop ecx - pop ecx - - ret 8 - end; - - { C library imports } - function malloc(size: Cardinal): Pointer; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_malloc'{$ENDIF}; - function calloc(nelem, elsize: Cardinal): Pointer; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_calloc'{$ENDIF}; - procedure free(ptr: Pointer); cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_free'{$ENDIF}; - function realloc(ptr: Pointer; size: Cardinal): Pointer; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_realloc'{$ENDIF}; - function memset(s: Pointer; c, n: Cardinal): Pointer; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_memset'{$ENDIF}; - function memcpy(s1, s2: Pointer; n: Cardinal): Pointer; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_memcpy'{$ENDIF}; - function floor(const x: Double): Double; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_floor'{$ENDIF}; - function ceil(const num: Double): Double; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_ceil'{$ENDIF}; - function printf(format: PAnsiChar): Integer; cdecl; varargs; external MSCRuntimeLib{$IFDEF BCB} name '_printf'{$ENDIF}; - function fprintf(f: Pointer; format: PAnsiChar): Integer; cdecl; varargs; external MSCRuntimeLib{$IFDEF BCB} name '_fprintf'{$ENDIF}; - function vsprintf(s, format: PAnsiChar): Integer; cdecl; varargs; external MSCRuntimeLib{$IFDEF BCB} name '_vsprintf'{$ENDIF}; - function _ftol(x: Single): LongInt; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '__ftol'{$ENDIF}; - function strcpy(s1, s2: PAnsiChar): PAnsiChar; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_strcpy'{$ENDIF}; - function wcscpy(s1, s2: PAnsiChar): PAnsiChar; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_wstrcpy'{$ENDIF}; - function strncpy(s1, s2: PAnsiChar; maxlen: Integer): PAnsiChar; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_strncpy'{$ENDIF}; - function strlen(s: PAnsiChar): Integer; cdecl; external MSCRuntimeLib{$IFDEF BCB} name '_strlen'{$ENDIF}; - {$ELSEIF Defined(FPC)} - { Free Pascal Win32 } - { Link OpenJpeg static library and C runtime library.} - {$LINKLIB libopenjpegwin32.a} - {$LINKLIB libcrtdll.a} - {$IFEND} - -{$ELSEIF Defined(LINUX)} - {$IF Defined(FPC)} - { Free Pascal Linux } - { Link C runtime library.} - {$LINKLIB c} - - {$IF Defined(CPU86)} - { Free Pascal Linux x86 } - { Link OpenJpeg static library.} - {$LINKLIB libopenjpeglinx86.a} - {$ELSEIF Defined(CPUX86_64)} - { Free Pascal Linux x86_64 } - { Link OpenJpeg static library.} - {$LINKLIB libopenjpeglinx86_64.a} - {$ELSE} - No support for this CPU architecture. - {$IFEND} - {$ELSE} - No support for this compiler - {$IFEND} -{$ELSEIF Defined(DARWIN)} - {$IF Defined(FPC)} - { Free Pascal MacOSX } - { Link C runtime library.} - {$LINKLIB c} - - {$IF Defined(CPU86)} - { Free Pascal MacOSX x86 } - { Link OpenJpeg static library.} - {$LINKLIB libopenjpegosxx86.a} - {$ELSE} - No support for this CPU architecture. - {$IFEND} - {$ELSE} - No support for this compiler - {$IFEND} -{$ELSE} - No suppor for this OS -{$IFEND} - -end. - diff --git a/3rd/Imaging/Source/Imaging.pas b/3rd/Imaging/Source/Imaging.pas deleted file mode 100644 index 6cab849e0..000000000 --- a/3rd/Imaging/Source/Imaging.pas +++ /dev/null @@ -1,4253 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit is heart of Imaging library. It contains basic functions for - manipulating image data as well as various image file format support.} -unit Imaging; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, Types, ImagingTypes; - -type - { Default Imaging excepton class } - EImagingError = class(Exception); - { Raised when function receives bad image (not passed TestImage).} - EImagingBadImage = class(Exception) - public - constructor Create; - end; - - { Dynamic array of TImageData records } - TDynImageDataArray = array of TImageData; - - -{ ------------------------------------------------------------------------ - Low Level Interface Functions - ------------------------------------------------------------------------} - -{ General Functions } - -{ Initializes image (all is set to zeroes). Call this for each image - before using it (before calling every other function) to be sure there - are no random-filled bytes (which would cause errors later).} -procedure InitImage(var Image: TImageData); -{ Creates empty image of given dimensions and format. Image is filled with - transparent black color (A=0, R=0, G=0, B=0).} -function NewImage(Width, Height: LongInt; Format: TImageFormat; - var Image: TImageData): Boolean; -{ Returns True if given TImageData record is valid.} -function TestImage(const Image: TImageData): Boolean; -{ Frees given image data. Ater this call image is in the same state - as after calling InitImage. If image is not valid (dost not pass TestImage - test) it is only zeroed by calling InitImage.} -procedure FreeImage(var Image: TImageData); -{ Call FreeImage() on all images in given dynamic array and sets its - length to zero.} -procedure FreeImagesInArray(var Images: TDynImageDataArray); -{ Returns True if all TImageData records in given array are valid. Returns False - if at least one is invalid or if array is empty.} -function TestImagesInArray(const Images: TDynImageDataArray): Boolean; -{ Checks given file for every supported image file format and if - the file is in one of them returns its string identifier - (which can be used in LoadFromStream/LoadFromMem type functions). - If file is not in any of the supported formats empty string is returned.} -function DetermineFileFormat(const FileName: string): string; -{ Checks given stream for every supported image file format and if - the stream is in one of them returns its string identifier - (which can be used in LoadFromStream/LoadFromMem type functions). - If stream is not in any of the supported formats empty string is returned.} -function DetermineStreamFormat(Stream: TStream): string; -{ Checks given memory for every supported image file format and if - the memory is in one of them returns its string identifier - (which can be used in LoadFromStream/LoadFromMem type functions). - If memory is not in any of the supported formats empty string is returned.} -function DetermineMemoryFormat(Data: Pointer; Size: LongInt): string; -{ Checks that an apropriate file format is supported purely from inspecting - the given file name's extension (not contents of the file itself). - The file need not exist.} -function IsFileFormatSupported(const FileName: string): Boolean; -{ Enumerates all registered image file formats. Descriptive name, - default extension, masks (like '*.jpg,*.jfif') and some capabilities - of each format are returned. To enumerate all formats start with Index at 0 and - call EnumFileFormats with given Index in loop until it returns False (Index is - automatically increased by 1 in function's body on successful call).} -function EnumFileFormats(var Index: LongInt; var Name, DefaultExt, Masks: string; - var CanSaveImages, IsMultiImageFormat: Boolean): Boolean; - -{ Loading Functions } - -{ Loads single image from given file.} -function LoadImageFromFile(const FileName: string; var Image: TImageData): Boolean; -{ Loads single image from given stream. If function fails stream position - is not changed.} -function LoadImageFromStream(Stream: TStream; var Image: TImageData): Boolean; -{ Loads single image from given memory location.} -function LoadImageFromMemory(Data: Pointer; Size: LongInt; var Image: TImageData): Boolean; -{ Loads multiple images from given file.} -function LoadMultiImageFromFile(const FileName: string; - var Images: TDynImageDataArray): Boolean; -{ Loads multiple images from given stream. If function fails stream position - is not changed.} -function LoadMultiImageFromStream(Stream: TStream; - var Images: TDynImageDataArray): Boolean; -{ Loads multiple images from given memory location.} -function LoadMultiImageFromMemory(Data: Pointer; Size: LongInt; - var Images: TDynImageDataArray): Boolean; - -{ Saving Functions } - -{ Saves single image to given file.} -function SaveImageToFile(const FileName: string; const Image: TImageData): Boolean; -{ Saves single image to given stream. If function fails stream position - is not changed. Ext identifies desired image file format (jpg, png, dds, ...).} -function SaveImageToStream(const Ext: string; Stream: TStream; - const Image: TImageData): Boolean; -{ Saves single image to given memory location. Memory must be allocated and its - size is passed in Size parameter in which number of written bytes is returned. - Ext identifies desired image file format (jpg, png, dds, ...).} -function SaveImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt; - const Image: TImageData): Boolean; -{ Saves multiple images to given file. If format supports - only single level images and there are multiple images to be saved, - they are saved as sequence of files img000.jpg, img001.jpg ....).} -function SaveMultiImageToFile(const FileName: string; - const Images: TDynImageDataArray): Boolean; -{ Saves multiple images to given stream. If format supports - only single level images and there are multiple images to be saved, - they are saved one after another to the stream. If function fails stream - position is not changed. Ext identifies desired image file format (jpg, png, dds, ...).} -function SaveMultiImageToStream(const Ext: string; Stream: TStream; - const Images: TDynImageDataArray): Boolean; -{ Saves multiple images to given memory location. If format supports - only single level images and there are multiple images to be saved, - they are saved one after another to the memory. Memory must be allocated and - its size is passed in Size parameter in which number of written bytes is returned. - Ext identifies desired image file format (jpg, png, dds, ...).} -function SaveMultiImageToMemory(const Ext: string; Data: Pointer; - var Size: LongInt; const Images: TDynImageDataArray): Boolean; - -{ Manipulation Functions } - -{ Creates identical copy of image data. Clone should be initialized - by InitImage or it should be vaild image which will be freed by CloneImage.} -function CloneImage(const Image: TImageData; var Clone: TImageData): Boolean; -{ Converts image to the given format.} -function ConvertImage(var Image: TImageData; DestFormat: TImageFormat): Boolean; -{ Flips given image. Reverses the image along its horizontal axis - the top - becomes the bottom and vice versa.} -function FlipImage(var Image: TImageData): Boolean; -{ Mirrors given image. Reverses the image along its vertical axis � the left - side becomes the right and vice versa.} -function MirrorImage(var Image: TImageData): Boolean; -{ Resizes given image to new dimensions. Nearest, bilinear, or bicubic filtering - can be used. Input Image must already be created - use NewImage to create new images.} -function ResizeImage(var Image: TImageData; NewWidth, NewHeight: LongInt; - Filter: TResizeFilter): Boolean; -{ Swaps SrcChannel and DstChannel color or alpha channels of image. - Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to - identify channels.} -function SwapChannels(var Image: TImageData; SrcChannel, DstChannel: LongInt): Boolean; -{ Reduces the number of colors of the Image. Currently MaxColors must be in - range <2, 4096>. Color reduction works also for alpha channel. Note that for - large images and big number of colors it can be very slow. - Output format of the image is the same as input format.} -function ReduceColors(var Image: TImageData; MaxColors: LongInt): Boolean; -{ Generates mipmaps for image. Levels is the number of desired mipmaps levels - with zero (or some invalid number) meaning all possible levels.} -function GenerateMipMaps(const Image: TImageData; Levels: LongInt; - var MipMaps: TDynImageDataArray): Boolean; -{ Maps image to existing palette producing image in ifIndex8 format. - Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes. - As resulting image is in 8bit indexed format Entries must be lower or - equal to 256.} -function MapImageToPalette(var Image: TImageData; Pal: PPalette32; - Entries: LongInt): Boolean; -{ Splits image into XChunks x YChunks subimages. Default size of each chunk is - ChunkWidth x ChunkHeight. If PreserveSize si True chunks at the edges of - the image are also ChunkWidth x ChunkHeight sized and empty space is filled - with optional Fill pixels. After calling this function XChunks contains number of - chunks along x axis and YChunks along y axis. To access chunk [X, Y] use this - index: Chunks[Y * XChunks + X].} -function SplitImage(var Image: TImageData; var Chunks: TDynImageDataArray; - ChunkWidth, ChunkHeight: LongInt; var XChunks, YChunks: LongInt; - PreserveSize: Boolean; Fill: Pointer = nil): Boolean; -{ Creates palette with MaxColors based on the colors of images in Images array. - Use it when you want to convert several images to indexed format using - single palette for all of them. If ConvertImages is True images in array - are converted to indexed format using resulting palette. if it is False - images are left intact and only resulting palatte is returned in Pal. - Pal must be allocated to have at least MaxColors entries.} -function MakePaletteForImages(var Images: TDynImageDataArray; Pal: PPalette32; - MaxColors: LongInt; ConvertImages: Boolean): Boolean; -{ Rotates image by Angle degrees counterclockwise. All angles are allowed.} -procedure RotateImage(var Image: TImageData; Angle: Single); - -{ Drawing/Pixel functions } - -{ Copies rectangular part of SrcImage to DstImage. No blending is performed - - alpha is simply copied to destination image. Operates also with - negative X and Y coordinates. - Note that copying is fastest for images in the same data format - (and slowest for images in special formats).} -function CopyRect(const SrcImage: TImageData; SrcX, SrcY, Width, Height: LongInt; - var DstImage: TImageData; DstX, DstY: LongInt): Boolean; -{ Fills given rectangle of image with given pixel fill data. Fill should point - to the pixel in the same format as the given image is in.} -function FillRect(var Image: TImageData; X, Y, Width, Height: LongInt; FillColor: Pointer): Boolean; -{ Replaces pixels with OldPixel in the given rectangle by NewPixel. - OldPixel and NewPixel should point to the pixels in the same format - as the given image is in.} -function ReplaceColor(var Image: TImageData; X, Y, Width, Height: LongInt; - OldColor, NewColor: Pointer): Boolean; -{ Stretches the contents of the source rectangle to the destination rectangle - with optional resampling. No blending is performed - alpha is - simply copied/resampled to destination image. Note that stretching is - fastest for images in the same data format (and slowest for - images in special formats).} -function StretchRect(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt; Filter: TResizeFilter): Boolean; -{ Copies pixel of Image at [X, Y] to memory pointed at by Pixel. Doesn't - work with special formats.} -procedure GetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); -{ Copies pixel from memory pointed at by Pixel to Image at position [X, Y]. - Doesn't work with special formats.} -procedure SetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); -{ Function for getting pixel colors. Native pixel is read from Image and - then translated to 32 bit ARGB. Works for all image formats (except special) - so it is not very fast.} -function GetPixel32(const Image: TImageData; X, Y: LongInt): TColor32Rec; -{ Procedure for setting pixel colors. Input 32 bit ARGB color is translated to - native format and then written to Image. Works for all image formats (except special) - so it is not very fast.} -procedure SetPixel32(const Image: TImageData; X, Y: LongInt; const Color: TColor32Rec); -{ Function for getting pixel colors. Native pixel is read from Image and - then translated to FP ARGB. Works for all image formats (except special) - so it is not very fast.} -function GetPixelFP(const Image: TImageData; X, Y: LongInt): TColorFPRec; -{ Procedure for setting pixel colors. Input FP ARGB color is translated to - native format and then written to Image. Works for all image formats (except special) - so it is not very fast.} -procedure SetPixelFP(const Image: TImageData; X, Y: LongInt; const Color: TColorFPRec); - -{ Palette Functions } - -{ Allocates new palette with Entries ARGB color entries.} -procedure NewPalette(Entries: LongInt; var Pal: PPalette32); -{ Frees given palette.} -procedure FreePalette(var Pal: PPalette32); -{ Copies Count palette entries from SrcPal starting at index SrcIdx to - DstPal at index DstPal.} -procedure CopyPalette(SrcPal, DstPal: PPalette32; SrcIdx, DstIdx, Count: LongInt); -{ Returns index of color in palette or index of nearest color if exact match - is not found. Pal must have at least Entries color entries.} -function FindColor(Pal: PPalette32; Entries: LongInt; Color: TColor32): LongInt; -{ Creates grayscale palette where each color channel has the same value. - Pal must have at least Entries color entries.} -procedure FillGrayscalePalette(Pal: PPalette32; Entries: LongInt); -{ Creates palette with given bitcount for each channel. - 2^(RBits + GBits + BBits) should be equl to Entries. Examples: - (3, 3, 2) will create palette with all possible colors of R3G3B2 format - and (8, 0, 0) will create palette with 256 shades of red. - Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes.} -procedure FillCustomPalette(Pal: PPalette32; Entries: LongInt; RBits, GBits, - BBits: Byte; Alpha: Byte = $FF); -{ Swaps SrcChannel and DstChannel color or alpha channels of palette. - Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to - identify channels. Pal must be allocated to at least - Entries * SizeOf(TColor32Rec) bytes.} -procedure SwapChannelsOfPalette(Pal: PPalette32; Entries, SrcChannel, - DstChannel: LongInt); - -{ Options Functions } - -{ Sets value of integer option specified by OptionId parameter. - Option Ids are constans starting ImagingXXX.} -function SetOption(OptionId, Value: LongInt): Boolean; -{ Returns value of integer option specified by OptionId parameter. If OptionId is - invalid, InvalidOption is returned. Option Ids are constans - starting ImagingXXX.} -function GetOption(OptionId: LongInt): LongInt; -{ Pushes current values of all options on the stack. Returns True - if successfull (max stack depth is 8 now). } -function PushOptions: Boolean; -{ Pops back values of all options from the top of the stack. Returns True - if successfull (max stack depth is 8 now). } -function PopOptions: Boolean; - -{ Image Format Functions } - -{ Returns short information about given image format.} -function GetImageFormatInfo(Format: TImageFormat; out Info: TImageFormatInfo): Boolean; -{ Returns size in bytes of Width x Height area of pixels. Works for all formats.} -function GetPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; - -{ IO Functions } - -{ User can set his own file IO functions used when loading from/saving to - files by this function.} -procedure SetUserFileIO(OpenProc: TOpenProc; CloseProc: TCloseProc; EofProc: TEofProc; SeekProc: - TSeekProc; TellProc: TTellProc; ReadProc: TReadProc; WriteProc: TWriteProc); -{ Sets file IO functions to Imaging default.} -procedure ResetFileIO; - -{ Raw Image IO Functions } - -procedure ReadRawImageFromFile(const FileName: string; Width, Height: Integer; - Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); -procedure ReadRawImageFromStream(Stream: TStream; Width, Height: Integer; - Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); -procedure ReadRawImageFromMemory(Data: Pointer; DataSize: Integer; Width, Height: Integer; - Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); -procedure ReadRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; - var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); - -procedure WriteRawImageToFile(const FileName: string; const Image: TImageData; - Offset: Integer = 0; RowLength: Integer = 0); -procedure WriteRawImageToStream(Stream: TStream; const Image: TImageData; - Offset: Integer = 0; RowLength: Integer = 0); -procedure WriteRawImageToMemory(Data: Pointer; DataSize: Integer; const Image: TImageData; - Offset: Integer = 0; RowLength: Integer = 0); -procedure WriteRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; - const Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); - -{ Convenience/helper Functions } - -procedure ResizeImageToFit(const SrcImage: TImageData; FitWidth, FitHeight: Integer; - Filter: TResizeFilter; var DestImage: TImageData); - - -{ ------------------------------------------------------------------------ - Other Imaging Stuff - ------------------------------------------------------------------------} - -type - { Set of TImageFormat enum.} - TImageFormats = set of TImageFormat; - - { Record containg set of IO functions internaly used by image loaders/savers.} - TIOFunctions = record - Open: TOpenProc; - Close: TCloseProc; - Eof: TEofProc; - Seek: TSeekProc; - Tell: TTellProc; - Read: TReadProc; - Write: TWriteProc; - end; - PIOFunctions = ^TIOFunctions; - -type - TFileFormatFeature = ( - ffLoad, - ffSave, - ffMultiImage, - ffReadOnSave, - ffProgress, - ffReadScanlines); - - TFileFormatFeatures = set of TFileFormatFeature; - - TMetadata = class; - - { Base class for various image file format loaders/savers which - descend from this class. If you want to add support for new image file - format the best way is probably to look at TImageFileFormat descendants' - implementations that are already part of Imaging.} -{$TYPEINFO ON} - TImageFileFormat = class - private - FExtensions: TStringList; - FMasks: TStringList; - function GetCanLoad: Boolean; - function GetCanSave: Boolean; - function GetIsMultiImageFormat: Boolean; - { Does various checks and actions before LoadData method is called.} - function PrepareLoad(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstFrame: Boolean): Boolean; - { Processes some actions according to result of LoadData.} - function PostLoadCheck(var Images: TDynImageDataArray; LoadResult: Boolean): Boolean; - { Helper function to be called in SaveData methods of descendants (ensures proper - index and sets FFirstIdx and FLastIdx for multi-images).} - function PrepareSave(Handle: TImagingHandle; const Images: TDynImageDataArray; - var Index: LongInt): Boolean; - { Returns file open mode used for saving images. Depends on defined Features.} - function GetSaveOpenMode: TOpenMode; - protected - FName: string; - FFeatures: TFileFormatFeatures; - FSupportedFormats: TImageFormats; - FFirstIdx, FLastIdx: LongInt; - FMetadata: TMetadata; - { Descendants must override this method and define file format name and - capabilities.} - procedure Define; virtual; - { Defines filename masks for this image file format. AMasks should be - in format '*.ext1,*.ext2,umajo.*'.} - procedure AddMasks(const AMasks: string); - function GetFormatInfo(Format: TImageFormat): TImageFormatInfo; - { Returns set of TImageData formats that can be saved in this file format - without need for conversion.} - function GetSupportedFormats: TImageFormats; virtual; - { Method which must be overrided in descendants if they' are be capable - of loading images. Images are already freed and length is set to zero - whenever this method gets called. Also Handle is assured to be valid - and contains data that passed TestFormat method's check.} - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstFrame: Boolean): Boolean; virtual; - { Method which must be overriden in descendants if they are be capable - of saving images. Images are checked to have length >0 and - that they contain valid images. For single-image file formats - Index contain valid index to Images array (to image which should be saved). - Multi-image formats should use FFirstIdx and FLastIdx fields to - to get all images that are to be saved.} - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; virtual; - { This method is called internaly by MakeCompatible when input image - is in format not supported by this file format. Image is clone of - MakeCompatible's input and Info is its extended format info.} - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); virtual; - { Returns True if given image is supported for saving by this file format. - Most file formats don't need to override this method. It checks - (in this base class) if Image's format is in SupportedFromats set. - But you may override it if you want further checks - (proper widht and height for example).} - function IsSupported(const Image: TImageData): Boolean; virtual; - public - constructor Create(AMetadata: TMetadata = nil); virtual; - destructor Destroy; override; - - { Loads images from file source.} - function LoadFromFile(const FileName: string; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean = False): Boolean; - { Loads images from stream source.} - function LoadFromStream(Stream: TStream; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean = False): Boolean; - { Loads images from memory source.} - function LoadFromMemory(Data: Pointer; Size: LongInt; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; - - { Saves images to file. If format supports only single level images and - there are multiple images to be saved, they are saved as sequence of - independent images (for example SaveToFile saves sequence of - files img000.jpg, img001.jpg ....).} - function SaveToFile(const FileName: string; const Images: TDynImageDataArray; - OnlyFirstLevel: Boolean = False): Boolean; - { Saves images to stream. If format supports only single level images and - there are multiple images to be saved, they are saved as sequence of - independent images.} - function SaveToStream(Stream: TStream; const Images: TDynImageDataArray; - OnlyFirstLevel: Boolean = False): Boolean; - { Saves images to memory. If format supports only single level images and - there are multiple images to be saved, they are saved as sequence of - independent images. Data must be already allocated and their size passed - as Size parameter, number of written bytes is then returned in the same - parameter.} - function SaveToMemory(Data: Pointer; var Size: LongInt; - const Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; - - { Makes Image compatible with this file format (that means it is in one - of data formats in Supported formats set). If input is already - in supported format then Compatible just use value from input - (Compatible := Image) so must not free it after you are done with it - (image bits pointer points to input image's bits). - If input is not in supported format then it is cloned to Compatible - and concerted to one of supported formats (which one dependeds on - this file format). If image is cloned MustBeFreed is set to True - to indicated that you must free Compatible after you are done with it.} - function MakeCompatible(const Image: TImageData; var Compatible: TImageData; - out MustBeFreed: Boolean): Boolean; - { Returns True if data located in source identified by Handle - represent valid image in current format.} - function TestFormat(Handle: TImagingHandle): Boolean; virtual; - { Resturns True if the given FileName matches filter for this file format. - For most formats it just checks filename extensions. - It uses filename masks in from Masks property so it can recognize - filenames like this 'umajoXXXumajo.j0j' if one of themasks is - 'umajo*umajo.j?j'.} - function TestFileName(const FileName: string): Boolean; - { Descendants use this method to check if their options (registered with - constant Ids for SetOption/GetOption interface or accessible as properties - of descendants) have valid values and make necessary changes.} - procedure CheckOptionsValidity; virtual; - - { Description of this format.} - property Name: string read FName; - { Indicates whether images in this format can be loaded.} - property CanLoad: Boolean read GetCanLoad; - { Indicates whether images in this format can be saved.} - property CanSave: Boolean read GetCanSave; - { Indicates whether images in this format can contain multiple image levels.} - property IsMultiImageFormat: Boolean read GetIsMultiImageFormat; - { List of filename extensions for this format.} - property Extensions: TStringList read FExtensions; - { List of filename masks that are used to associate filenames - with TImageFileFormat descendants. Typical mask looks like - '*.bmp' or 'texture.*' (supports file formats which use filename instead - of extension to identify image files).} - property Masks: TStringList read FMasks; - { Set of TImageFormats supported by saving functions of this format. Images - can be saved only in one those formats.} - property SupportedFormats: TImageFormats read GetSupportedFormats; - end; -{$TYPEINFO OFF} - - { Class reference for TImageFileFormat class} - TImageFileFormatClass = class of TImageFileFormat; - - { Physical resolution unit.} - TResolutionUnit = ( - ruSizeInMicroMeters, // value is pixel size in micrometers - ruDpi, // value is pixels/dots per inch - ruDpm, // value is pixels/dots per meter - ruDpcm // value is pixels/dots per centimeter - ); - - { Class for storage of single metadata item.} - TMetadataItem = class - public - Id: string; - ImageIndex: Integer; - Value: Variant; - end; - - { Metadata manager class.} - TMetadata = class - private - FLoadMetaItems: TStringList; - FSaveMetaItems: TStringList; - procedure AddMetaToList(List: TStringList; const Id: string; const Value: Variant; ImageIndex: Integer); - procedure ClearMetaList(List: TStringList); - function GetMetaById(const Id: string): Variant; - function GetMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; - function GetMetaCount: Integer; - function GetMetaByIdx(Index: Integer): TMetadataItem; - function GetSaveMetaById(const Id: string): Variant; - function GetSaveMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; - procedure TranslateUnits(ResolutionUnit: TResolutionUnit; var XRes, YRes: Single); - public - constructor Create; - destructor Destroy; override; - - procedure SetMetaItem(const Id: string; const Value: Variant; ImageIndex: Integer = 0); - procedure SetMetaItemForSaving(const Id: string; const Value: Variant; ImageIndex: Integer = 0); - function HasMetaItem(const Id: string; ImageIndex: Integer = 0): Boolean; - function HasMetaItemForSaving(const Id: string; ImageIndex: Integer = 0): Boolean; - - procedure ClearMetaItems; - procedure ClearMetaItemsForSaving; - function GetMetaItemName(const Id: string; ImageIndex: Integer): string; - { Copies loaded meta items to items-for-save stack. Use this when you want to - save metadata that have been just loaded (e.g. resaving image in - different file format but keeping the metadata).} - procedure CopyLoadedMetaItemsForSaving; - - function GetPhysicalPixelSize(ResUnit: TResolutionUnit; var XSize, - YSize: Single; MetaForSave: Boolean = False; ImageIndex: Integer = 0): Boolean; - procedure SetPhysicalPixelSize(ResUnit: TResolutionUnit; XSize, YSize: Single; - MetaForSave: Boolean = False; ImageIndex: Integer = 0); - - property MetaItems[const Id: string]: Variant read GetMetaById; - property MetaItemsMulti[const Id: string; ImageIndex: Integer]: Variant read GetMetaByIdMulti; - { Number of loaded metadata items.} - property MetaItemCount: Integer read GetMetaCount; - property MetaItemsByIdx[Index: Integer]: TMetadataItem read GetMetaByIdx; - property MetaItemsForSaving[const Id: string]: Variant read GetSaveMetaById; - property MetaItemsForSavingMulti[const Id: string; ImageIndex: Integer]: Variant read GetSaveMetaByIdMulti; - end; - -const - { Metadata item id constants } - - { Physical size of one pixel in micrometers. Type of value is Float.} - SMetaPhysicalPixelSizeX = 'PhysicalPixelSizeX'; - SMetaPhysicalPixelSizeY = 'PhysicalPixelSizeY'; - { Delay for frame of animation (how long it should stay visible) in milliseconds. - Type of value is Integer.} - SMetaFrameDelay = 'FrameDelay'; - { Number of times animation should be looped (0 = infinite looping). Type is Int. } - SMetaAnimationLoops = 'AnimationLoops'; - { Gamma correction value. Type is Float.} - SMetaGamma = 'Gamma'; - { Exposure value for HDR etc. Type is Float.} - SMetaExposure = 'Exposure'; - { EXIF image metadata raw blob.} - SMetaExifBlob = 'ExifBlob'; - { XMP image metadata raw blob.} - SMetaXmpBlob = 'XmpBlob'; - { IPTC image metadata raw blob.} - SMetaIptcBlob = 'IptcBlob'; - -var - GlobalMetadata: TMetadata; - -{ Returns symbolic name of given format.} -function GetFormatName(Format: TImageFormat): string; -{ Returns string with information about given Image.} -function ImageToStr(const Image: TImageData): string; -{ Returns Imaging version string in format 'Major.Minor.Patch'.} -function GetVersionStr: string; -{ If Condition is True then TruePart is retured, otherwise FalsePart is returned.} -function IffFormat(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; - -{ Registers new option so it can be used by SetOption and GetOption functions. - Returns True if registration was succesful - that is Id is valid and is - not already taken by another option.} -function RegisterOption(OptionId: LongInt; Variable: PLongInt): Boolean; - -{ Registers new image loader/saver so it can be used by LoadFrom/SaveTo - functions.} -procedure RegisterImageFileFormat(AClass: TImageFileFormatClass); -{ Returns image format loader/saver according to given extension - or nil if not found.} -function FindImageFileFormatByExt(const Ext: string): TImageFileFormat; -{ Returns image format loader/saver according to given filename - or nil if not found.} -function FindImageFileFormatByName(const FileName: string): TImageFileFormat; -{ Returns image format loader/saver based on its class - or nil if not found or not registered.} -function FindImageFileFormatByClass(AClass: TImageFileFormatClass): TImageFileFormat; -{ Returns number of registered image file format loaders/saver.} -function GetFileFormatCount: LongInt; -{ Returns image file format loader/saver at given index. Index must be - in range [0..GetFileFormatCount - 1] otherwise nil is returned.} -function GetFileFormatAtIndex(Index: LongInt): TImageFileFormat; -{ Returns filter string for usage with open and save picture dialogs - which contains all registered image file formats. - Set OpenFileFilter to True if you want filter for open dialog - and to False if you want save dialog filter (formats that cannot save to files - are not added then). - For open dialog filter for all known graphic files - (like All(*.jpg;*.png;....) is added too at the first index.} -function GetImageFileFormatsFilter(OpenFileFilter: Boolean): string; -{ Returns file extension (without dot) of image format selected - by given filter index. Used filter string is defined by GetImageFileFormatsFilter - function. This function can be used with save dialogs (with filters created - by GetImageFileFormatsFilter) to get the extension of file format selected - in dialog quickly. Index is in range 1..N (as FilterIndex property - of TOpenDialog/TSaveDialog)} -function GetFilterIndexExtension(Index: LongInt; OpenFileFilter: Boolean): string; -{ Returns filter index of image file format of file specified by FileName. Used filter - string is defined by GetImageFileFormatsFilter function. - Returned index is in range 1..N (as FilterIndex property of TOpenDialog/TSaveDialog)} -function GetFileNameFilterIndex(const FileName: string; OpenFileFilter: Boolean): LongInt; - -{ Returns current IO functions.} -function GetIO: TIOFunctions; -{ Raises EImagingError with given message.} -procedure RaiseImaging(const Msg: string; const Args: array of const); overload; -procedure RaiseImaging(const Msg: string); overload; {$IFDEF USE_INLINE}inline;{$ENDIF} - -const - SImagingLibTitle = 'Vampyre Imaging Library'; - -implementation - -uses -{$IFNDEF DONT_LINK_BITMAP} - ImagingBitmap, -{$ENDIF} -{$IFNDEF DONT_LINK_JPEG} - ImagingJpeg, -{$ENDIF} -{$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)} - ImagingNetworkGraphics, -{$IFEND} -{$IFNDEF DONT_LINK_GIF} - ImagingGif, -{$ENDIF} -{$IFNDEF DONT_LINK_DDS} - ImagingDds, -{$ENDIF} -{$IFNDEF DONT_LINK_TARGA} - ImagingTarga, -{$ENDIF} -{$IFNDEF DONT_LINK_PNM} - ImagingPortableMaps, -{$ENDIF} -{$IFNDEF DONT_LINK_RADHDR} - ImagingRadiance, -{$ENDIF} -{$IFNDEF DONT_LINK_EXTRAS} - ImagingExtras, -{$ENDIF} - //ImagingDebug, - ImagingFormats, ImagingUtility, ImagingIO, Variants; - -resourcestring - SExceptMsg = 'Exception Message'; - SAllFilter = 'All Images'; - SUnknownFormat = 'Unknown and unsupported format'; - - SErrorFreeImage = 'Error while freeing image. %s'; - SErrorCloneImage = 'Error while cloning image. %s'; - SErrorFlipImage = 'Error while flipping image. %s'; - SErrorMirrorImage = 'Error while mirroring image. %s'; - SErrorResizeImage = 'Error while resizing image. %s'; - SErrorSwapImage = 'Error while swapping channels of image. %s'; - SFileFormatCanNotLoad = 'Image Format "%s" does not support loading images.'; - SFileFormatCanNotSave = 'Image Format "%s" does not support saving images.'; - SErrorNewImage = 'Error while creating image data with params: Width=%d ' + - 'Height=%d Format=%s.'; - SErrorConvertImage = 'Error while converting image to format "%s". %s'; - SImageInfo = 'Image @%p info: Width = %dpx, Height = %dpx, ' + - 'Format = %s, Size = %.0n %s, Bits @%p, Palette @%p.'; - SImageInfoInvalid = 'Access violation encountered when getting info on ' + - 'image at address %p.'; - SFileNotValid = 'File "%s" is not valid image in "%s" format.'; - SStreamNotValid = 'Stream %p does not contain valid image in "%s" format.'; - SMemoryNotValid = 'Memory %p (%d Bytes) does not contain valid image ' + - 'in "%s" format.'; - SErrorLoadingFile = 'Error while loading images from file "%s" (file format: %s).'; - SErrorLoadingStream = 'Error while loading images from stream %p (file format: %s).'; - SErrorLoadingMemory = 'Error while loading images from memory %p (%d Bytes) (file format: %s).'; - SErrorSavingFile = 'Error while saving images to file "%s" (file format: %s).'; - SErrorSavingStream = 'Error while saving images to stream %p (file format: %s).'; - SErrorSavingMemory = 'Error while saving images to memory %p (%d Bytes) (file format: %s).'; - SErrorFindColor = 'Error while finding color in palette @%p with %d entries.'; - SErrorGrayscalePalette = 'Error while filling grayscale palette @%p with %d entries.'; - SErrorCustomPalette = 'Error while filling custom palette @%p with %d entries.'; - SErrorSwapPalette = 'Error while swapping channels of palette @%p with %d entries.'; - SErrorReduceColors = 'Error while reducing number of colors of image to %d. %s'; - SErrorGenerateMipMaps = 'Error while generating %d mipmap levels for image %s'; - SImagesNotValid = 'One or more images are not valid.'; - SErrorCopyRect = 'Error while copying rect from image %s to image %s.'; - SErrorMapImage = 'Error while mapping image %s to palette.'; - SErrorFillRect = 'Error while filling rectangle X:%d Y:%d W:%d H:%d in image %s'; - SErrorSplitImage = 'Error while splitting image %s to %dx%d sized chunks.'; - SErrorMakePaletteForImages = 'Error while making %d color palette for %d images.'; - SErrorNewPalette = 'Error while creating new palette with %d entries'; - SErrorFreePalette = 'Error while freeing palette @%p'; - SErrorCopyPalette = 'Error while copying %d entries from palette @%p to @%p'; - SErrorReplaceColor = 'Error while replacing colors in rectangle X:%d Y:%d W:%d H:%d of image %s'; - SErrorRotateImage = 'Error while rotating image %s by %.2n degrees'; - SErrorStretchRect = 'Error while stretching rect from image %s to image %s.'; - SErrorEmptyStream = 'Input stream has no data. Check Position property.'; - SErrorInvalidInputImage = 'Invalid input image.'; - - SErrorBadImage = 'Bad image detected.'; - -const - // Initial size of array with options information - InitialOptions = 256; - // Max depth of the option stack - OptionStackDepth = 8; - // Do not change the default format now, its too late - DefaultImageFormat: TImageFormat = ifA8R8G8B8; - // Format used to create metadata IDs for frames loaded form multiimages. - SMetaIdForSubImage = '%s/%d'; - -type - TOptionArray = array of PLongInt; - TOptionValueArray = array of LongInt; - - TOptionStack = class(TObject) - private - FStack: array[0..OptionStackDepth - 1] of TOptionValueArray; - FPosition: LongInt; - public - constructor Create; - destructor Destroy; override; - function Push: Boolean; - function Pop: Boolean; - end; - -var - // Currently set IO functions - IO: TIOFunctions; - // List with all registered TImageFileFormat classes - ImageFileFormats: TList = nil; - // Aarray with registered options (pointers to their values) - Options: TOptionArray = nil; - // Array containing addional infomation about every image format - ImageFormatInfos: TImageFormatInfoArray; - // Stack used by PushOptions/PopOtions functions - OptionStack: TOptionStack = nil; -var - // Variable for ImagingColorReduction option - ColorReductionMask: LongInt = $FF; - // Variable for ImagingLoadOverrideFormat option - LoadOverrideFormat: TImageFormat = ifUnknown; - // Variable for ImagingSaveOverrideFormat option - SaveOverrideFormat: TImageFormat = ifUnknown; - // Variable for ImagingSaveOverrideFormat option - MipMapFilter: TSamplingFilter = sfLinear; - // Variable for ImagingBinaryTreshold option - BinaryTreshold: Integer = 128; - -{ Exceptions } - -constructor EImagingBadImage.Create; -begin - inherited Create(SErrorBadImage); -end; - -{ Internal unit functions } - -{ Modifies option value to be in the allowed range. Works only - for options registered in this unit.} -function CheckOptionValue(OptionId, Value: LongInt): LongInt; forward; -{ Sets IO functions to file IO.} -procedure SetFileIO; forward; -{ Sets IO functions to stream IO.} -procedure SetStreamIO; forward; -{ Sets IO functions to memory IO.} -procedure SetMemoryIO; forward; -{ Inits image format infos array.} -procedure InitImageFormats; forward; -{ Freew image format infos array.} -procedure FreeImageFileFormats; forward; -{ Creates options array and stack.} -procedure InitOptions; forward; -{ Frees options array and stack.} -procedure FreeOptions; forward; - -function UpdateExceptMessage(E: Exception; const MsgToPrepend: string; const Args: array of const): Exception; -begin - Result := E; - E.Message := Format(MsgToPrepend, Args) + ' ' + SExceptMsg + ': ' + E.Message -end; - -{ ------------------------------------------------------------------------ - Low Level Interface Functions - ------------------------------------------------------------------------} - -{ General Functions } - -procedure InitImage(var Image: TImageData); -begin - FillChar(Image, SizeOf(Image), 0); -end; - -function NewImage(Width, Height: LongInt; Format: TImageFormat; var Image: - TImageData): Boolean; -var - FInfo: PImageFormatInfo; -begin - Assert((Width > 0) and (Height >0)); - Assert(IsImageFormatValid(Format)); - Result := False; - FreeImage(Image); - try - Image.Width := Width; - Image.Height := Height; - // Select default data format if selected - if (Format = ifDefault) then - Image.Format := DefaultImageFormat - else - Image.Format := Format; - // Get extended format info - FInfo := ImageFormatInfos[Image.Format]; - if FInfo = nil then - begin - InitImage(Image); - Exit; - end; - // Check image dimensions and calculate its size in bytes - FInfo.CheckDimensions(FInfo.Format, Image.Width, Image.Height); - Image.Size := FInfo.GetPixelsSize(FInfo.Format, Image.Width, Image.Height); - if Image.Size = 0 then - begin - InitImage(Image); - Exit; - end; - // Image bits are allocated and set to zeroes - GetMem(Image.Bits, Image.Size); - FillChar(Image.Bits^, Image.Size, 0); - // Palette is allocated and set to zeroes - if FInfo.PaletteEntries > 0 then - begin - GetMem(Image.Palette, FInfo.PaletteEntries * SizeOf(TColor32Rec)); - FillChar(Image.Palette^, FInfo.PaletteEntries * SizeOf(TColor32Rec), 0); - end; - Result := TestImage(Image); - except - on E: Exception do - begin - FreeMem(Image.Bits); - FreeMem(Image.Palette); - InitImage(Image); - raise UpdateExceptMessage(E, SErrorNewImage, [Width, Height, GetFormatName(Format)]); - end; - end; -end; - -function TestImage(const Image: TImageData): Boolean; -begin - try - Result := (LongInt(Image.Format) >= LongInt(Low(TImageFormat))) and - (LongInt(Image.Format) <= LongInt(High(TImageFormat))) and - (ImageFormatInfos[Image.Format] <> nil) and - (Assigned(ImageFormatInfos[Image.Format].GetPixelsSize) and - (ImageFormatInfos[Image.Format].GetPixelsSize(Image.Format, - Image.Width, Image.Height) = Image.Size)); - except - // Possible int overflows or other errors - Result := False; - end; -end; - -procedure FreeImage(var Image: TImageData); -begin - try - if TestImage(Image) then - begin - FreeMemNil(Image.Bits); - FreeMemNil(Image.Palette); - end; - InitImage(Image); - except - raise UpdateExceptMessage(GetExceptObject, SErrorFreeImage, [ImageToStr(Image)]); - end; -end; - -procedure FreeImagesInArray(var Images: TDynImageDataArray); -var - I: LongInt; -begin - if Length(Images) > 0 then - begin - for I := 0 to Length(Images) - 1 do - FreeImage(Images[I]); - SetLength(Images, 0); - end; -end; - -function TestImagesInArray(const Images: TDynImageDataArray): Boolean; -var - I: LongInt; -begin - if Length(Images) > 0 then - begin - Result := True; - for I := 0 to Length(Images) - 1 do - begin - Result := Result and TestImage(Images[I]); - if not Result then - Break; - end; - end - else - Result := False; -end; - -function DetermineFileFormat(const FileName: string): string; -var - I: LongInt; - Fmt: TImageFileFormat; - Handle: TImagingHandle; -begin - Assert(FileName <> ''); - Result := ''; - SetFileIO; - Handle := IO.Open(PChar(FileName), omReadOnly); - try - // First file format according to FileName and test if the data in - // file is really in that format - for I := 0 to ImageFileFormats.Count - 1 do - begin - Fmt := TImageFileFormat(ImageFileFormats[I]); - if Fmt.TestFileName(FileName) and Fmt.TestFormat(Handle) then - begin - Result := Fmt.Extensions[0]; - Exit; - end; - end; - // No file format was found with filename search so try data-based search - for I := 0 to ImageFileFormats.Count - 1 do - begin - Fmt := TImageFileFormat(ImageFileFormats[I]); - if Fmt.TestFormat(Handle) then - begin - Result := Fmt.Extensions[0]; - Exit; - end; - end; - finally - IO.Close(Handle); - end; -end; - -function DetermineStreamFormat(Stream: TStream): string; -var - I: LongInt; - Fmt: TImageFileFormat; - Handle: TImagingHandle; -begin - Assert(Stream <> nil); - Result := ''; - SetStreamIO; - Handle := IO.Open(Pointer(Stream), omReadOnly); - try - for I := 0 to ImageFileFormats.Count - 1 do - begin - Fmt := TImageFileFormat(ImageFileFormats[I]); - if Fmt.TestFormat(Handle) then - begin - Result := Fmt.Extensions[0]; - Exit; - end; - end; - finally - IO.Close(Handle); - end; -end; - -function DetermineMemoryFormat(Data: Pointer; Size: LongInt): string; -var - I: LongInt; - Fmt: TImageFileFormat; - Handle: TImagingHandle; - IORec: TMemoryIORec; -begin - Assert((Data <> nil) and (Size > 0)); - Result := ''; - SetMemoryIO; - IORec.Data := Data; - IORec.Position := 0; - IORec.Size := Size; - Handle := IO.Open(@IORec, omReadOnly); - try - for I := 0 to ImageFileFormats.Count - 1 do - begin - Fmt := TImageFileFormat(ImageFileFormats[I]); - if Fmt.TestFormat(Handle) then - begin - Result := Fmt.Extensions[0]; - Exit; - end; - end; - finally - IO.Close(Handle); - end; -end; - -function IsFileFormatSupported(const FileName: string): Boolean; -begin - Result := FindImageFileFormatByName(FileName) <> nil; -end; - -function EnumFileFormats(var Index: LongInt; var Name, DefaultExt, Masks: string; - var CanSaveImages, IsMultiImageFormat: Boolean): Boolean; -var - FileFmt: TImageFileFormat; -begin - FileFmt := GetFileFormatAtIndex(Index); - Result := FileFmt <> nil; - if Result then - begin - Name := FileFmt.Name; - DefaultExt := FileFmt.Extensions[0]; - Masks := FileFmt.Masks.DelimitedText; - CanSaveImages := FileFmt.CanSave; - IsMultiImageFormat := FileFmt.IsMultiImageFormat; - Inc(Index); - end - else - begin - Name := ''; - DefaultExt := ''; - Masks := ''; - CanSaveImages := False; - IsMultiImageFormat := False; - end; -end; - -{ Loading Functions } - -function LoadImageFromFile(const FileName: string; var Image: TImageData): - Boolean; -var - Format: TImageFileFormat; - IArray: TDynImageDataArray; - I: LongInt; -begin - Assert(FileName <> ''); - Result := False; - Format := FindImageFileFormatByExt(DetermineFileFormat(FileName)); - if Format <> nil then - begin - FreeImage(Image); - Result := Format.LoadFromFile(FileName, IArray, True); - if Result and (Length(IArray) > 0) then - begin - Image := IArray[0]; - for I := 1 to Length(IArray) - 1 do - FreeImage(IArray[I]); - end - else - Result := False; - end; -end; - -function LoadImageFromStream(Stream: TStream; var Image: TImageData): Boolean; -var - Format: TImageFileFormat; - IArray: TDynImageDataArray; - I: LongInt; -begin - Assert(Stream <> nil); - if Stream.Size - Stream.Position = 0 then - RaiseImaging(SErrorEmptyStream, []); - Result := False; - Format := FindImageFileFormatByExt(DetermineStreamFormat(Stream)); - if Format <> nil then - begin - FreeImage(Image); - Result := Format.LoadFromStream(Stream, IArray, True); - if Result and (Length(IArray) > 0) then - begin - Image := IArray[0]; - for I := 1 to Length(IArray) - 1 do - FreeImage(IArray[I]); - end - else - Result := False; - end; -end; - -function LoadImageFromMemory(Data: Pointer; Size: LongInt; var Image: TImageData): Boolean; -var - Format: TImageFileFormat; - IArray: TDynImageDataArray; - I: LongInt; -begin - Assert((Data <> nil) and (Size > 0)); - Result := False; - Format := FindImageFileFormatByExt(DetermineMemoryFormat(Data, Size)); - if Format <> nil then - begin - FreeImage(Image); - Result := Format.LoadFromMemory(Data, Size, IArray, True); - if Result and (Length(IArray) > 0) then - begin - Image := IArray[0]; - for I := 1 to Length(IArray) - 1 do - FreeImage(IArray[I]); - end - else - Result := False; - end; -end; - -function LoadMultiImageFromFile(const FileName: string; var Images: - TDynImageDataArray): Boolean; -var - Format: TImageFileFormat; -begin - Assert(FileName <> ''); - Result := False; - Format := FindImageFileFormatByExt(DetermineFileFormat(FileName)); - if Format <> nil then - begin - FreeImagesInArray(Images); - Result := Format.LoadFromFile(FileName, Images); - end; -end; - -function LoadMultiImageFromStream(Stream: TStream; var Images: TDynImageDataArray): Boolean; -var - Format: TImageFileFormat; -begin - Assert(Stream <> nil); - if Stream.Size - Stream.Position = 0 then - RaiseImaging(SErrorEmptyStream, []); - Result := False; - Format := FindImageFileFormatByExt(DetermineStreamFormat(Stream)); - if Format <> nil then - begin - FreeImagesInArray(Images); - Result := Format.LoadFromStream(Stream, Images); - end; -end; - -function LoadMultiImageFromMemory(Data: Pointer; Size: LongInt; - var Images: TDynImageDataArray): Boolean; -var - Format: TImageFileFormat; -begin - Assert((Data <> nil) and (Size > 0)); - Result := False; - Format := FindImageFileFormatByExt(DetermineMemoryFormat(Data, Size)); - if Format <> nil then - begin - FreeImagesInArray(Images); - Result := Format.LoadFromMemory(Data, Size, Images); - end; -end; - -{ Saving Functions } - -function SaveImageToFile(const FileName: string; const Image: TImageData): Boolean; -var - Format: TImageFileFormat; - IArray: TDynImageDataArray; -begin - Assert(FileName <> ''); - Result := False; - Format := FindImageFileFormatByName(FileName); - if Format <> nil then - begin - SetLength(IArray, 1); - IArray[0] := Image; - Result := Format.SaveToFile(FileName, IArray, True); - end; -end; - -function SaveImageToStream(const Ext: string; Stream: TStream; - const Image: TImageData): Boolean; -var - Format: TImageFileFormat; - IArray: TDynImageDataArray; -begin - Assert((Ext <> '') and (Stream <> nil)); - Result := False; - Format := FindImageFileFormatByExt(Ext); - if Format <> nil then - begin - SetLength(IArray, 1); - IArray[0] := Image; - Result := Format.SaveToStream(Stream, IArray, True); - end; -end; - -function SaveImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt; - const Image: TImageData): Boolean; -var - Format: TImageFileFormat; - IArray: TDynImageDataArray; -begin - Assert((Ext <> '') and (Data <> nil) and (Size > 0)); - Result := False; - Format := FindImageFileFormatByExt(Ext); - if Format <> nil then - begin - SetLength(IArray, 1); - IArray[0] := Image; - Result := Format.SaveToMemory(Data, Size, IArray, True); - end; -end; - -function SaveMultiImageToFile(const FileName: string; - const Images: TDynImageDataArray): Boolean; -var - Format: TImageFileFormat; -begin - Assert(FileName <> ''); - Result := False; - Format := FindImageFileFormatByName(FileName); - if Format <> nil then - Result := Format.SaveToFile(FileName, Images); -end; - -function SaveMultiImageToStream(const Ext: string; Stream: TStream; - const Images: TDynImageDataArray): Boolean; -var - Format: TImageFileFormat; -begin - Assert((Ext <> '') and (Stream <> nil)); - Result := False; - Format := FindImageFileFormatByExt(Ext); - if Format <> nil then - Result := Format.SaveToStream(Stream, Images); -end; - -function SaveMultiImageToMemory(const Ext: string; Data: Pointer; - var Size: LongInt; const Images: TDynImageDataArray): Boolean; -var - Format: TImageFileFormat; -begin - Assert((Ext <> '') and (Data <> nil) and (Size > 0)); - Result := False; - Format := FindImageFileFormatByExt(Ext); - if Format <> nil then - Result := Format.SaveToMemory(Data, Size, Images); -end; - -{ Manipulation Functions } - -function CloneImage(const Image: TImageData; var Clone: TImageData): Boolean; -var - Info: PImageFormatInfo; -begin - Result := False; - if TestImage(Image) then - try - if TestImage(Clone) and (Image.Bits <> Clone.Bits) then - FreeImage(Clone) - else - InitImage(Clone); - - Info := ImageFormatInfos[Image.Format]; - Clone.Width := Image.Width; - Clone.Height := Image.Height; - Clone.Format := Image.Format; - Clone.Size := Image.Size; - - if Info.PaletteEntries > 0 then - begin - GetMem(Clone.Palette, Info.PaletteEntries * SizeOf(TColor32Rec)); - Move(Image.Palette^, Clone.Palette^, Info.PaletteEntries * - SizeOf(TColor32Rec)); - end; - - GetMem(Clone.Bits, Clone.Size); - Move(Image.Bits^, Clone.Bits^, Clone.Size); - Result := True; - except - raise UpdateExceptMessage(GetExceptObject, SErrorCloneImage, [ImageToStr(Image)]); - end; -end; - -function ConvertImage(var Image: TImageData; DestFormat: TImageFormat): Boolean; -var - NewData: Pointer; - NewPal: PPalette32; - NewSize, NumPixels: LongInt; - SrcInfo, DstInfo: PImageFormatInfo; -begin - Assert(IsImageFormatValid(DestFormat)); - Result := False; - if TestImage(Image) then - with Image do - try - // If default format is set we use DefaultImageFormat - if DestFormat = ifDefault then - DestFormat := DefaultImageFormat; - SrcInfo := ImageFormatInfos[Format]; - DstInfo := ImageFormatInfos[DestFormat]; - if SrcInfo = DstInfo then - begin - // There is nothing to convert - src is alredy in dest format - Result := True; - Exit; - end; - // Exit Src or Dest format is invalid - if (SrcInfo = nil) or (DstInfo = nil) then Exit; - // If dest format is just src with swapped channels we call - // SwapChannels instead - if (SrcInfo.RBSwapFormat = DestFormat) and - (DstInfo.RBSwapFormat = SrcInfo.Format) then - begin - Result := SwapChannels(Image, ChannelRed, ChannelBlue); - Image.Format := SrcInfo.RBSwapFormat; - Exit; - end; - - if (not SrcInfo.IsSpecial) and (not DstInfo.IsSpecial) then - begin - NumPixels := Width * Height; - NewSize := NumPixels * DstInfo.BytesPerPixel; - GetMem(NewData, NewSize); - FillChar(NewData^, NewSize, 0); - GetMem(NewPal, DstInfo.PaletteEntries * SizeOf(TColor32Rec)); - FillChar(NewPal^, DstInfo.PaletteEntries * SizeOf(TColor32Rec), 0); - - if SrcInfo.IsIndexed then - begin - // Source: indexed format - if DstInfo.IsIndexed then - IndexToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette, NewPal) - else if DstInfo.HasGrayChannel then - IndexToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette) - else if DstInfo.IsFloatingPoint then - IndexToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette) - else - IndexToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette); - end - else if SrcInfo.HasGrayChannel then - begin - // Source: grayscale format - if DstInfo.IsIndexed then - GrayToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal) - else if DstInfo.HasGrayChannel then - GrayToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo) - else if DstInfo.IsFloatingPoint then - GrayToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo) - else - GrayToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo); - end - else if SrcInfo.IsFloatingPoint then - begin - // Source: floating point format - if DstInfo.IsIndexed then - FloatToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal) - else if DstInfo.HasGrayChannel then - FloatToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo) - else if DstInfo.IsFloatingPoint then - FloatToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo) - else - FloatToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo); - end - else - begin - // Source: standard multi channel image - if DstInfo.IsIndexed then - ChannelToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal) - else if DstInfo.HasGrayChannel then - ChannelToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo) - else if DstInfo.IsFloatingPoint then - ChannelToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo) - else - ChannelToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo); - end; - - FreeMemNil(Bits); - FreeMemNil(Palette); - Format := DestFormat; - Bits := NewData; - Size := NewSize; - Palette := NewPal; - end - else - ConvertSpecial(Image, SrcInfo, DstInfo); - - Assert(SrcInfo.Format <> Image.Format); - - Result := True; - except - raise UpdateExceptMessage(GetExceptObject, SErrorConvertImage, [GetFormatName(DestFormat), ImageToStr(Image)]); - end; -end; - -function FlipImage(var Image: TImageData): Boolean; -var - P1, P2, Buff: Pointer; - WidthBytes, I: LongInt; - OldFmt: TImageFormat; -begin - Result := False; - OldFmt := Image.Format; - if TestImage(Image) then - with Image do - try - if ImageFormatInfos[OldFmt].IsSpecial then - ConvertImage(Image, ifDefault); - - WidthBytes := Width * ImageFormatInfos[Format].BytesPerPixel; - GetMem(Buff, WidthBytes); - try - // Swap all scanlines of image - for I := 0 to Height div 2 - 1 do - begin - P1 := @PByteArray(Bits)[I * WidthBytes]; - P2 := @PByteArray(Bits)[(Height - I - 1) * WidthBytes]; - Move(P1^, Buff^, WidthBytes); - Move(P2^, P1^, WidthBytes); - Move(Buff^, P2^, WidthBytes); - end; - finally - FreeMemNil(Buff); - end; - - if OldFmt <> Format then - ConvertImage(Image, OldFmt); - - Result := True; - except - RaiseImaging(SErrorFlipImage, [ImageToStr(Image)]); - end; -end; - -function MirrorImage(var Image: TImageData): Boolean; -var - Scanline: PByte; - Buff: TColorFPRec; - Bpp, Y, X, WidthDiv2, WidthBytes, XLeft, XRight: LongInt; - OldFmt: TImageFormat; -begin - Result := False; - OldFmt := Image.Format; - if TestImage(Image) then - with Image do - try - if ImageFormatInfos[OldFmt].IsSpecial then - ConvertImage(Image, ifDefault); - - Bpp := ImageFormatInfos[Format].BytesPerPixel; - WidthDiv2 := Width div 2; - WidthBytes := Width * Bpp; - // Mirror all pixels on each scanline of image - for Y := 0 to Height - 1 do - begin - Scanline := @PByteArray(Bits)[Y * WidthBytes]; - XLeft := 0; - XRight := (Width - 1) * Bpp; - for X := 0 to WidthDiv2 - 1 do - begin - CopyPixel(@PByteArray(Scanline)[XLeft], @Buff, Bpp); - CopyPixel(@PByteArray(Scanline)[XRight], - @PByteArray(Scanline)[XLeft], Bpp); - CopyPixel(@Buff, @PByteArray(Scanline)[XRight], Bpp); - Inc(XLeft, Bpp); - Dec(XRight, Bpp); - end; - end; - - if OldFmt <> Format then - ConvertImage(Image, OldFmt); - - Result := True; - except - RaiseImaging(SErrorMirrorImage, [ImageToStr(Image)]); - end; -end; - -function ResizeImage(var Image: TImageData; NewWidth, NewHeight: LongInt; - Filter: TResizeFilter): Boolean; -var - WorkImage: TImageData; -begin - Assert((NewWidth > 0) and (NewHeight > 0), 'New width or height is zero.'); - Result := False; - if TestImage(Image) and ((Image.Width <> NewWidth) or (Image.Height <> NewHeight)) then - try - InitImage(WorkImage); - // Create new image with desired dimensions - NewImage(NewWidth, NewHeight, Image.Format, WorkImage); - // Stretch pixels from old image to new one - StretchRect(Image, 0, 0, Image.Width, Image.Height, - WorkImage, 0, 0, WorkImage.Width, WorkImage.Height, Filter); - // Free old image and assign new image to it - FreeMemNil(Image.Bits); - if Image.Palette <> nil then - begin - FreeMem(WorkImage.Palette); - WorkImage.Palette := Image.Palette; - end; - Image := WorkImage; - Result := True; - except - raise UpdateExceptMessage(GetExceptObject, SErrorResizeImage, [ImageToStr(Image)]); - end; -end; - -function SwapChannels(var Image: TImageData; SrcChannel, DstChannel: LongInt): Boolean; -var - I, NumPixels: LongInt; - Info: PImageFormatInfo; - Swap, Alpha: Word; - Data: PByte; - Pix64: TColor64Rec; - PixF: TColorFPRec; - SwapF: Single; -begin - Assert((SrcChannel in [0..3]) and (DstChannel in [0..3])); - Result := False; - if TestImage(Image) and (SrcChannel <> DstChannel) then - with Image do - try - NumPixels := Width * Height; - Info := ImageFormatInfos[Format]; - Data := Bits; - - if (Info.Format = ifR8G8B8) or ((Info.Format = ifA8R8G8B8) and - (SrcChannel <> ChannelAlpha) and (DstChannel <> ChannelAlpha)) then - begin - // Swap channels of most common formats R8G8B8 and A8R8G8B8 (no alpha) - for I := 0 to NumPixels - 1 do - with PColor24Rec(Data)^ do - begin - Swap := Channels[SrcChannel]; - Channels[SrcChannel] := Channels[DstChannel]; - Channels[DstChannel] := Swap; - Inc(Data, Info.BytesPerPixel); - end; - end - else if Info.IsIndexed then - begin - // Swap palette channels of indexed images - SwapChannelsOfPalette(Palette, Info.PaletteEntries, SrcChannel, DstChannel) - end - else if Info.IsFloatingPoint then - begin - // Swap channels of floating point images - for I := 0 to NumPixels - 1 do - begin - FloatGetSrcPixel(Data, Info, PixF); - with PixF do - begin - SwapF := Channels[SrcChannel]; - Channels[SrcChannel] := Channels[DstChannel]; - Channels[DstChannel] := SwapF; - end; - FloatSetDstPixel(Data, Info, PixF); - Inc(Data, Info.BytesPerPixel); - end; - end - else if Info.IsSpecial then - begin - // Swap channels of special format images - ConvertImage(Image, ifDefault); - SwapChannels(Image, SrcChannel, DstChannel); - ConvertImage(Image, Info.Format); - end - else if Info.HasGrayChannel and Info.HasAlphaChannel and - ((SrcChannel = ChannelAlpha) or (DstChannel = ChannelAlpha)) then - begin - for I := 0 to NumPixels - 1 do - begin - // If we have grayscale image with alpha and alpha is channel - // to be swapped, we swap it. No other alternative for gray images, - // just alpha and something - GrayGetSrcPixel(Data, Info, Pix64, Alpha); - Swap := Alpha; - Alpha := Pix64.A; - Pix64.A := Swap; - GraySetDstPixel(Data, Info, Pix64, Alpha); - Inc(Data, Info.BytesPerPixel); - end; - end - else - begin - // Then do general swap on other channel image formats - for I := 0 to NumPixels - 1 do - begin - ChannelGetSrcPixel(Data, Info, Pix64); - with Pix64 do - begin - Swap := Channels[SrcChannel]; - Channels[SrcChannel] := Channels[DstChannel]; - Channels[DstChannel] := Swap; - end; - ChannelSetDstPixel(Data, Info, Pix64); - Inc(Data, Info.BytesPerPixel); - end; - end; - - Result := True; - except - RaiseImaging(SErrorSwapImage, [ImageToStr(Image)]); - end; -end; - -function ReduceColors(var Image: TImageData; MaxColors: LongInt): Boolean; -var - TmpInfo: TImageFormatInfo; - Data, Index: PWord; - I, NumPixels: LongInt; - Pal: PPalette32; - Col:PColor32Rec; - OldFmt: TImageFormat; -begin - Result := False; - if TestImage(Image) then - with Image do - try - // First create temp image info and allocate output bits and palette - MaxColors := ClampInt(MaxColors, 2, High(Word)); - OldFmt := Format; - FillChar(TmpInfo, SizeOf(TmpInfo), 0); - TmpInfo.PaletteEntries := MaxColors; - TmpInfo.BytesPerPixel := 2; - NumPixels := Width * Height; - GetMem(Data, NumPixels * TmpInfo.BytesPerPixel); - GetMem(Pal, MaxColors * SizeOf(TColor32Rec)); - ConvertImage(Image, ifA8R8G8B8); - // We use median cut algorithm to create reduced palette and to - // fill Data with indices to this palette - ReduceColorsMedianCut(NumPixels, Bits, PByte(Data), - ImageFormatInfos[Format], @TmpInfo, MaxColors, ColorReductionMask, Pal); - Col := Bits; - Index := Data; - // Then we write reduced colors to the input image - for I := 0 to NumPixels - 1 do - begin - Col.Color := Pal[Index^].Color; - Inc(Col); - Inc(Index); - end; - FreeMemNil(Data); - FreeMemNil(Pal); - // And convert it to its original format - ConvertImage(Image, OldFmt); - Result := True; - except - RaiseImaging(SErrorReduceColors, [MaxColors, ImageToStr(Image)]); - end; -end; - -function GenerateMipMaps(const Image: TImageData; Levels: LongInt; - var MipMaps: TDynImageDataArray): Boolean; -var - Width, Height, I, Count: LongInt; - Info: TImageFormatInfo; - CompatibleCopy: TImageData; -begin - Result := False; - if TestImage(Image) then - try - Width := Image.Width; - Height := Image.Height; - // We compute number of possible mipmap levels and if - // the given levels are invalid or zero we use this value - Count := GetNumMipMapLevels(Width, Height); - if (Levels <= 0) or (Levels > Count) then - Levels := Count; - - // If we have special format image we create copy to allow pixel access. - // This is also done in FillMipMapLevel which is called for each level - // but then the main big image would be converted to compatible - // for every level. - GetImageFormatInfo(Image.Format, Info); - if Info.IsSpecial then - begin - InitImage(CompatibleCopy); - CloneImage(Image, CompatibleCopy); - ConvertImage(CompatibleCopy, ifDefault); - end - else - CompatibleCopy := Image; - - FreeImagesInArray(MipMaps); - SetLength(MipMaps, Levels); - CloneImage(Image, MipMaps[0]); - - for I := 1 to Levels - 1 do - begin - Width := Width shr 1; - Height := Height shr 1; - if Width < 1 then Width := 1; - if Height < 1 then Height := 1; - FillMipMapLevel(CompatibleCopy, Width, Height, MipMaps[I]); - end; - - if CompatibleCopy.Format <> MipMaps[0].Format then - begin - // Must convert smaller levels to proper format - for I := 1 to High(MipMaps) do - ConvertImage(MipMaps[I], MipMaps[0].Format); - FreeImage(CompatibleCopy); - end; - - Result := True; - except - RaiseImaging(SErrorGenerateMipMaps, [Levels, ImageToStr(Image)]); - end; -end; - -function MapImageToPalette(var Image: TImageData; Pal: PPalette32; - Entries: LongInt): Boolean; - - function FindNearestColor(Pal: PPalette32; Entries: LongInt; Col: TColor32Rec): LongInt; - var - I, MinDif, Dif: LongInt; - begin - Result := 0; - MinDif := 1020; - for I := 0 to Entries - 1 do - with Pal[I] do - begin - Dif := Abs(R - Col.R); - if Dif > MinDif then Continue; - Dif := Dif + Abs(G - Col.G); - if Dif > MinDif then Continue; - Dif := Dif + Abs(B - Col.B); - if Dif > MinDif then Continue; - Dif := Dif + Abs(A - Col.A); - if Dif < MinDif then - begin - MinDif := Dif; - Result := I; - end; - end; - end; - -var - I, MaxEntries: LongInt; - PIndex: PByte; - PColor: PColor32Rec; - CloneARGB: TImageData; - Info: PImageFormatInfo; -begin - Assert((Entries >= 2) and (Entries <= 256)); - Result := False; - - if TestImage(Image) then - try - // We create clone of source image in A8R8G8B8 and - // then recreate source image in ifIndex8 format - // with palette taken from Pal parameter - InitImage(CloneARGB); - CloneImage(Image, CloneARGB); - ConvertImage(CloneARGB, ifA8R8G8B8); - FreeImage(Image); - NewImage(CloneARGB.Width, CloneARGB.Height, ifIndex8, Image); - - Info := ImageFormatInfos[Image.Format]; - MaxEntries := Min(Info.PaletteEntries, Entries); - Move(Pal^, Image.Palette^, MaxEntries * SizeOf(TColor32Rec)); - PIndex := Image.Bits; - PColor := CloneARGB.Bits; - - // For every pixel of ARGB clone we find closest color in - // given palette and assign its index to resulting image's pixel - // procedure used here is very slow but simple and memory usage friendly - // (contrary to other methods) - for I := 0 to Image.Width * Image.Height - 1 do - begin - PIndex^ := Byte(FindNearestColor(Image.Palette, MaxEntries, PColor^)); - Inc(PIndex); - Inc(PColor); - end; - - FreeImage(CloneARGB); - Result := True; - except - raise UpdateExceptMessage(GetExceptObject, SErrorMapImage, [ImageToStr(Image)]); - end; -end; - -function SplitImage(var Image: TImageData; var Chunks: TDynImageDataArray; - ChunkWidth, ChunkHeight: LongInt; var XChunks, YChunks: LongInt; - PreserveSize: Boolean; Fill: Pointer): Boolean; -var - X, Y, XTrunc, YTrunc: LongInt; - NotOnEdge: Boolean; - Info: PImageFormatInfo; - OldFmt: TImageFormat; -begin - Assert((ChunkWidth > 0) and (ChunkHeight > 0)); - Result := False; - OldFmt := Image.Format; - FreeImagesInArray(Chunks); - - if TestImage(Image) then - try - Info := ImageFormatInfos[Image.Format]; - if Info.IsSpecial then - ConvertImage(Image, ifDefault); - - // We compute make sure that chunks are not larger than source image or negative - ChunkWidth := ClampInt(ChunkWidth, 0, Image.Width); - ChunkHeight := ClampInt(ChunkHeight, 0, Image.Height); - // Number of chunks along X and Y axes is computed - XChunks := Trunc(Ceil(Image.Width / ChunkWidth)); - YChunks := Trunc(Ceil(Image.Height / ChunkHeight)); - SetLength(Chunks, XChunks * YChunks); - - // For every chunk we create new image and copy a portion of - // the source image to it. If chunk is on the edge of the source image - // we fill enpty space with Fill pixel data if PreserveSize is set or - // make the chunk smaller if it is not set - for Y := 0 to YChunks - 1 do - for X := 0 to XChunks - 1 do - begin - // Determine if current chunk is on the edge of original image - NotOnEdge := ((X < XChunks - 1) and (Y < YChunks - 1)) or - ((Image.Width mod ChunkWidth = 0) and (Image.Height mod ChunkHeight = 0)); - - if PreserveSize or NotOnEdge then - begin - // We should preserve chunk sizes or we are somewhere inside original image - NewImage(ChunkWidth, ChunkHeight, Image.Format, Chunks[Y * XChunks + X]); - if (not NotOnEdge) and (Fill <> nil) then - FillRect(Chunks[Y * XChunks + X], 0, 0, ChunkWidth, ChunkHeight, Fill); - CopyRect(Image, X * ChunkWidth, Y * ChunkHeight, ChunkWidth, ChunkHeight, - Chunks[Y * XChunks + X], 0, 0); - end - else - begin - // Create smaller edge chunk - XTrunc := Image.Width - X * ChunkWidth; - YTrunc := Image.Height - Y * ChunkHeight; - NewImage(XTrunc, YTrunc, Image.Format, Chunks[Y * XChunks + X]); - CopyRect(Image, X * ChunkWidth, Y * ChunkHeight, XTrunc, YTrunc, - Chunks[Y * XChunks + X], 0, 0); - end; - - // If source image is in indexed format we copy its palette to chunk - if Info.IsIndexed then - begin - Move(Image.Palette^, Chunks[Y * XChunks + X].Palette^, - Info.PaletteEntries * SizeOf(TColor32Rec)); - end; - end; - - if OldFmt <> Image.Format then - begin - ConvertImage(Image, OldFmt); - for X := 0 to Length(Chunks) - 1 do - ConvertImage(Chunks[X], OldFmt); - end; - - Result := True; - except - raise UpdateExceptMessage(GetExceptObject, SErrorSplitImage, - [ImageToStr(Image), ChunkWidth, ChunkHeight]); - end; -end; - -function MakePaletteForImages(var Images: TDynImageDataArray; Pal: PPalette32; - MaxColors: LongInt; ConvertImages: Boolean): Boolean; -var - I: Integer; - SrcInfo, DstInfo: PImageFormatInfo; - Target, TempImage: TImageData; - DstFormat: TImageFormat; -begin - Assert((Pal <> nil) and (MaxColors > 0)); - Result := False; - InitImage(TempImage); - - if TestImagesInArray(Images) then - try - // Null the color histogram - ReduceColorsMedianCut(0, nil, nil, nil, nil, 0, 0, nil, [raCreateHistogram]); - for I := 0 to Length(Images) - 1 do - begin - SrcInfo := ImageFormatInfos[Images[I].Format]; - if SrcInfo.IsIndexed or SrcInfo.IsSpecial then - begin - // create temp image in supported format for updating histogram - CloneImage(Images[I], TempImage); - ConvertImage(TempImage, ifA8R8G8B8); - SrcInfo := ImageFormatInfos[TempImage.Format]; - end - else - TempImage := Images[I]; - - // Update histogram with colors of each input image - ReduceColorsMedianCut(TempImage.Width * TempImage.Height, TempImage.Bits, - nil, SrcInfo, nil, MaxColors, ColorReductionMask, nil, [raUpdateHistogram]); - - if Images[I].Bits <> TempImage.Bits then - FreeImage(TempImage); - end; - // Construct reduced color map from the histogram - ReduceColorsMedianCut(0, nil, nil, nil, nil, MaxColors, ColorReductionMask, - Pal, [raMakeColorMap]); - - if ConvertImages then - begin - DstFormat := ifIndex8; - DstInfo := ImageFormatInfos[DstFormat]; - MaxColors := Min(DstInfo.PaletteEntries, MaxColors); - - for I := 0 to Length(Images) - 1 do - begin - SrcInfo := ImageFormatInfos[Images[I].Format]; - if SrcInfo.IsIndexed or SrcInfo.IsSpecial then - begin - // If source image is in format not supported by ReduceColorsMedianCut - // we convert it - ConvertImage(Images[I], ifA8R8G8B8); - SrcInfo := ImageFormatInfos[Images[I].Format]; - end; - - InitImage(Target); - NewImage(Images[I].Width, Images[I].Height, DstFormat, Target); - // We map each input image to reduced palette and replace - // image in array with mapped image - ReduceColorsMedianCut(Images[I].Width * Images[I].Height, Images[I].Bits, - Target.Bits, SrcInfo, DstInfo, MaxColors, 0, nil, [raMapImage]); - Move(Pal^, Target.Palette^, MaxColors * SizeOf(TColor32Rec)); - - FreeImage(Images[I]); - Images[I] := Target; - end; - end; - Result := True; - except - RaiseImaging(SErrorMakePaletteForImages, [MaxColors, Length(Images)]); - end; -end; - -procedure RotateImage(var Image: TImageData; Angle: Single); -var - OldFmt: TImageFormat; - - procedure XShear(var Src, Dst: TImageData; Row, Offset, Weight, Bpp: Integer); - var - I, J, XPos: Integer; - PixSrc, PixLeft, PixOldLeft: TColor32Rec; - LineDst: PByteArray; - SrcPtr: PColor32; - begin - SrcPtr := @PByteArray(Src.Bits)[Row * Src.Width * Bpp]; - LineDst := @PByteArray(Dst.Bits)[Row * Dst.Width * Bpp]; - PixOldLeft.Color := 0; - - for I := 0 to Src.Width - 1 do - begin - CopyPixel(SrcPtr, @PixSrc, Bpp); - for J := 0 to Bpp - 1 do - PixLeft.Channels[J] := MulDiv(PixSrc.Channels[J], Weight, 256); - - XPos := I + Offset; - if (XPos >= 0) and (XPos < Dst.Width) then - begin - for J := 0 to Bpp - 1 do - PixSrc.Channels[J] := ClampToByte(PixSrc.Channels[J] - (PixLeft.Channels[J] - PixOldLeft.Channels[J])); - CopyPixel(@PixSrc, @LineDst[XPos * Bpp], Bpp); - end; - PixOldLeft := PixLeft; - Inc(PByte(SrcPtr), Bpp); - end; - - XPos := Src.Width + Offset; - if XPos < Dst.Width then - CopyPixel(@PixOldLeft, @LineDst[XPos * Bpp], Bpp); - end; - - procedure YShear(var Src, Dst: TImageData; Col, Offset, Weight, Bpp: Integer); - var - I, J, YPos: Integer; - PixSrc, PixLeft, PixOldLeft: TColor32Rec; - SrcPtr: PByte; - begin - SrcPtr := @PByteArray(Src.Bits)[Col * Bpp]; - PixOldLeft.Color := 0; - - for I := 0 to Src.Height - 1 do - begin - CopyPixel(SrcPtr, @PixSrc, Bpp); - for J := 0 to Bpp - 1 do - PixLeft.Channels[J] := MulDiv(PixSrc.Channels[J], Weight, 256); - - YPos := I + Offset; - if (YPos >= 0) and (YPos < Dst.Height) then - begin - for J := 0 to Bpp - 1 do - PixSrc.Channels[J] := ClampToByte(PixSrc.Channels[J] - (PixLeft.Channels[J] - PixOldLeft.Channels[J])); - CopyPixel(@PixSrc, @PByteArray(Dst.Bits)[(YPos * Dst.Width + Col) * Bpp], Bpp); - end; - PixOldLeft := PixLeft; - Inc(SrcPtr, Src.Width * Bpp); - end; - - YPos := Src.Height + Offset; - if YPos < Dst.Height then - CopyPixel(@PixOldLeft, @PByteArray(Dst.Bits)[(YPos * Dst.Width + Col) * Bpp], Bpp); - end; - - procedure Rotate45(var Image: TImageData; Angle: Single); - var - TempImage1, TempImage2: TImageData; - AngleRad, AngleTan, AngleSin, AngleCos, Shear: Single; - I, DstWidth, DstHeight, SrcWidth, SrcHeight, Bpp: Integer; - SrcFmt, TempFormat: TImageFormat; - Info: TImageFormatInfo; - begin - AngleRad := Angle * Pi / 180; - AngleSin := Sin(AngleRad); - AngleCos := Cos(AngleRad); - AngleTan := Sin(AngleRad / 2) / Cos(AngleRad / 2); - SrcWidth := Image.Width; - SrcHeight := Image.Height; - SrcFmt := Image.Format; - - if not (SrcFmt in [ifR8G8B8..ifX8R8G8B8, ifGray8..ifGray32, ifA16Gray16]) then - ConvertImage(Image, ifA8R8G8B8); - - TempFormat := Image.Format; - GetImageFormatInfo(TempFormat, Info); - Bpp := Info.BytesPerPixel; - - // 1st shear (horizontal) - DstWidth := Trunc(SrcWidth + SrcHeight * Abs(AngleTan) + 0.5); - DstHeight := SrcHeight; - InitImage(TempImage1); - NewImage(DstWidth, DstHeight, TempFormat, TempImage1); - - for I := 0 to DstHeight - 1 do - begin - if AngleTan >= 0 then - Shear := (I + 0.5) * AngleTan - else - Shear := (I - DstHeight + 0.5) * AngleTan; - XShear(Image, TempImage1, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp); - end; - - // 2nd shear (vertical) - FreeImage(Image); - DstHeight := Trunc(SrcWidth * Abs(AngleSin) + SrcHeight * AngleCos + 0.5) + 1; - InitImage(TempImage2); - NewImage(DstWidth, DstHeight, TempFormat, TempImage2); - - if AngleSin >= 0 then - Shear := (SrcWidth - 1) * AngleSin - else - Shear := (SrcWidth - DstWidth) * -AngleSin; - - for I := 0 to DstWidth - 1 do - begin - YShear(TempImage1, TempImage2, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp); - Shear := Shear - AngleSin; - end; - - // 3rd shear (horizontal) - FreeImage(TempImage1); - DstWidth := Trunc(SrcHeight * Abs(AngleSin) + SrcWidth * AngleCos + 0.5) + 1; - NewImage(DstWidth, DstHeight, TempFormat, Image); - - if AngleSin >= 0 then - Shear := (SrcWidth - 1) * AngleSin * -AngleTan - else - Shear := ((SrcWidth - 1) * -AngleSin + (1 - DstHeight)) * AngleTan; - - for I := 0 to DstHeight - 1 do - begin - XShear(TempImage2, Image, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp); - Shear := Shear + AngleTan; - end; - - FreeImage(TempImage2); - if Image.Format <> SrcFmt then - ConvertImage(Image, SrcFmt); - end; - - procedure RotateMul90(var Image: TImageData; Angle: Integer); - var - RotImage: TImageData; - X, Y, BytesPerPixel: Integer; - RotPix, Pix: PByte; - begin - InitImage(RotImage); - BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel; - - if ((Angle = 90) or (Angle = 270)) and (Image.Width <> Image.Height) then - NewImage(Image.Height, Image.Width, Image.Format, RotImage) - else - NewImage(Image.Width, Image.Height, Image.Format, RotImage); - - RotPix := RotImage.Bits; - case Angle of - 90: - begin - for Y := 0 to RotImage.Height - 1 do - begin - Pix := @PByteArray(Image.Bits)[(Image.Width - Y - 1) * BytesPerPixel]; - for X := 0 to RotImage.Width - 1 do - begin - CopyPixel(Pix, RotPix, BytesPerPixel); - Inc(RotPix, BytesPerPixel); - Inc(Pix, Image.Width * BytesPerPixel); - end; - end; - end; - 180: - begin - Pix := @PByteArray(Image.Bits)[((Image.Height - 1) * Image.Width + - (Image.Width - 1)) * BytesPerPixel]; - for Y := 0 to RotImage.Height - 1 do - for X := 0 to RotImage.Width - 1 do - begin - CopyPixel(Pix, RotPix, BytesPerPixel); - Inc(RotPix, BytesPerPixel); - Dec(Pix, BytesPerPixel); - end; - end; - 270: - begin - for Y := 0 to RotImage.Height - 1 do - begin - Pix := @PByteArray(Image.Bits)[((Image.Height - 1) * Image.Width + Y) * BytesPerPixel]; - for X := 0 to RotImage.Width - 1 do - begin - CopyPixel(Pix, RotPix, BytesPerPixel); - Inc(RotPix, BytesPerPixel); - Dec(Pix, Image.Width * BytesPerPixel); - end; - end; - end; - end; - - FreeMemNil(Image.Bits); - RotImage.Palette := Image.Palette; - Image := RotImage; - end; - -begin - if TestImage(Image) then - try - while Angle >= 360 do - Angle := Angle - 360; - while Angle < 0 do - Angle := Angle + 360; - - if (Angle = 0) or (Abs(Angle) = 360) then - Exit; - - OldFmt := Image.Format; - if ImageFormatInfos[Image.Format].IsSpecial then - ConvertImage(Image, ifDefault); - - if (Angle > 45) and (Angle <= 135) then - begin - RotateMul90(Image, 90); - Angle := Angle - 90; - end - else if (Angle > 135) and (Angle <= 225) then - begin - RotateMul90(Image, 180); - Angle := Angle - 180; - end - else if (Angle > 225) and (Angle <= 315) then - begin - RotateMul90(Image, 270); - Angle := Angle - 270; - end; - - if Angle <> 0 then - Rotate45(Image, Angle); - - if OldFmt <> Image.Format then - ConvertImage(Image, OldFmt); - - except - raise UpdateExceptMessage(GetExceptObject, SErrorRotateImage, [ImageToStr(Image), Angle]); - end; -end; - -{ Drawing/Pixel functions } - -function CopyRect(const SrcImage: TImageData; SrcX, SrcY, Width, Height: LongInt; - var DstImage: TImageData; DstX, DstY: LongInt): Boolean; -var - Info: PImageFormatInfo; - I, SrcWidthBytes, DstWidthBytes, MoveBytes: LongInt; - SrcPointer, DstPointer: PByte; - WorkImage: TImageData; - OldFormat: TImageFormat; -begin - Result := False; - OldFormat := ifUnknown; - if TestImage(SrcImage) and TestImage(DstImage) then - try - // Make sure we are still copying image to image, not invalid pointer to protected memory - ClipCopyBounds(SrcX, SrcY, Width, Height, DstX, DstY, SrcImage.Width, SrcImage.Height, - Rect(0, 0, DstImage.Width, DstImage.Height)); - - if (Width > 0) and (Height > 0) then - begin - Info := ImageFormatInfos[DstImage.Format]; - if Info.IsSpecial then - begin - // If dest image is in special format we convert it to default - OldFormat := Info.Format; - ConvertImage(DstImage, ifDefault); - Info := ImageFormatInfos[DstImage.Format]; - end; - if SrcImage.Format <> DstImage.Format then - begin - // If images are in different format source is converted to dest's format - InitImage(WorkImage); - CloneImage(SrcImage, WorkImage); - ConvertImage(WorkImage, DstImage.Format); - end - else - WorkImage := SrcImage; - - MoveBytes := Width * Info.BytesPerPixel; - DstWidthBytes := DstImage.Width * Info.BytesPerPixel; - DstPointer := @PByteArray(DstImage.Bits)[DstY * DstWidthBytes + - DstX * Info.BytesPerPixel]; - SrcWidthBytes := WorkImage.Width * Info.BytesPerPixel; - SrcPointer := @PByteArray(WorkImage.Bits)[SrcY * SrcWidthBytes + - SrcX * Info.BytesPerPixel]; - - for I := 0 to Height - 1 do - begin - Move(SrcPointer^, DstPointer^, MoveBytes); - Inc(SrcPointer, SrcWidthBytes); - Inc(DstPointer, DstWidthBytes); - end; - // If dest image was in special format we convert it back - if OldFormat <> ifUnknown then - ConvertImage(DstImage, OldFormat); - // Working image must be freed if it is not the same as source image - if WorkImage.Bits <> SrcImage.Bits then - FreeImage(WorkImage); - - Result := True; - end; - except - RaiseImaging(SErrorCopyRect, [ImageToStr(SrcImage), ImageToStr(DstImage)]); - end; -end; - -function FillRect(var Image: TImageData; X, Y, Width, Height: LongInt; - FillColor: Pointer): Boolean; -var - Info: PImageFormatInfo; - I, J, ImageWidthBytes, RectWidthBytes, Bpp: Longint; - LinePointer, PixPointer: PByte; - OldFmt: TImageFormat; -begin - Result := False; - if TestImage(Image) then - try - ClipRectBounds(X, Y, Width, Height, Rect(0, 0, Image.Width, Image.Height)); - - if (Width > 0) and (Height > 0) then - begin - OldFmt := Image.Format; - if ImageFormatInfos[OldFmt].IsSpecial then - ConvertImage(Image, ifDefault); - - Info := ImageFormatInfos[Image.Format]; - Bpp := Info.BytesPerPixel; - ImageWidthBytes := Image.Width * Bpp; - RectWidthBytes := Width * Bpp; - LinePointer := @PByteArray(Image.Bits)[Y * ImageWidthBytes + X * Bpp]; - - for I := 0 to Height - 1 do - begin - case Bpp of - 1: FillMemoryByte(LinePointer, RectWidthBytes, PByte(FillColor)^); - 2: FillMemoryWord(LinePointer, RectWidthBytes, PWord(FillColor)^); - 4: FillMemoryLongWord(LinePointer, RectWidthBytes, PLongWord(FillColor)^); - else - PixPointer := LinePointer; - for J := 0 to Width - 1 do - begin - CopyPixel(FillColor, PixPointer, Bpp); - Inc(PixPointer, Bpp); - end; - end; - Inc(LinePointer, ImageWidthBytes); - end; - - if OldFmt <> Image.Format then - ConvertImage(Image, OldFmt); - end; - - Result := True; - except - RaiseImaging(SErrorFillRect, [X, Y, Width, Height, ImageToStr(Image)]); - end; -end; - -function ReplaceColor(var Image: TImageData; X, Y, Width, Height: LongInt; - OldColor, NewColor: Pointer): Boolean; -var - Info: PImageFormatInfo; - I, J, WidthBytes, Bpp: Longint; - LinePointer, PixPointer: PByte; - OldFmt: TImageFormat; -begin - Assert((OldColor <> nil) and (NewColor <> nil)); - Result := False; - if TestImage(Image) then - try - ClipRectBounds(X, Y, Width, Height, Rect(0, 0, Image.Width, Image.Height)); - - if (Width > 0) and (Height > 0) then - begin - OldFmt := Image.Format; - if ImageFormatInfos[OldFmt].IsSpecial then - ConvertImage(Image, ifDefault); - - Info := ImageFormatInfos[Image.Format]; - Bpp := Info.BytesPerPixel; - WidthBytes := Image.Width * Bpp; - LinePointer := @PByteArray(Image.Bits)[Y * WidthBytes + X * Bpp]; - - for I := 0 to Height - 1 do - begin - PixPointer := LinePointer; - for J := 0 to Width - 1 do - begin - if ComparePixels(PixPointer, OldColor, Bpp) then - CopyPixel(NewColor, PixPointer, Bpp); - Inc(PixPointer, Bpp); - end; - Inc(LinePointer, WidthBytes); - end; - - if OldFmt <> Image.Format then - ConvertImage(Image, OldFmt); - end; - - Result := True; - except - RaiseImaging(SErrorReplaceColor, [X, Y, Width, Height, ImageToStr(Image)]); - end; -end; - -function StretchRect(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt; Filter: TResizeFilter): Boolean; -var - Info: PImageFormatInfo; - WorkImage: TImageData; - OldFormat: TImageFormat; - Resampling: TSamplingFilter; -begin - Result := False; - OldFormat := ifUnknown; - if TestImage(SrcImage) and TestImage(DstImage) then - try - // Make sure we are still copying image to image, not invalid pointer to protected memory - ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, DstWidth, DstHeight, - SrcImage.Width, SrcImage.Height, Rect(0, 0, DstImage.Width, DstImage.Height)); - - if (SrcWidth = DstWidth) and (SrcHeight = DstHeight) then - begin - // If source and dest rectangles have the same size call CopyRect - Result := CopyRect(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY); - end - else if (SrcWidth > 0) and (SrcHeight > 0) and (DstWidth > 0) and (DstHeight > 0) then - begin - // If source and dest rectangles don't have the same size we do stretch - Info := ImageFormatInfos[DstImage.Format]; - - if Info.IsSpecial then - begin - // If dest image is in special format we convert it to default - OldFormat := Info.Format; - ConvertImage(DstImage, ifDefault); - Info := ImageFormatInfos[DstImage.Format]; - end; - - if SrcImage.Format <> DstImage.Format then - begin - // If images are in different format source is converted to dest's format - InitImage(WorkImage); - CloneImage(SrcImage, WorkImage); - ConvertImage(WorkImage, DstImage.Format); - end - else - WorkImage := SrcImage; - - // Only pixel resize is supported for indexed images - if Info.IsIndexed then - Filter := rfNearest; - - if Filter = rfNearest then - begin - StretchNearest(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight, - DstImage, DstX, DstY, DstWidth, DstHeight); - end - else - begin - Resampling := sfNearest; - case Filter of - rfBilinear: Resampling := sfLinear; - rfBicubic: Resampling := DefaultCubicFilter; - rfLanczos: Resampling := sfLanczos; - end; - StretchResample(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight, - DstImage, DstX, DstY, DstWidth, DstHeight, Resampling); - end; - - // If dest image was in special format we convert it back - if OldFormat <> ifUnknown then - ConvertImage(DstImage, OldFormat); - // Working image must be freed if it is not the same as source image - if WorkImage.Bits <> SrcImage.Bits then - FreeImage(WorkImage); - - Result := True; - end; - except - RaiseImaging(SErrorStretchRect, [ImageToStr(SrcImage), ImageToStr(DstImage)]); - end; -end; - -procedure GetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); -var - BytesPerPixel: LongInt; -begin - Assert(Pixel <> nil); - BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel; - CopyPixel(@PByteArray(Image.Bits)[(Y * Image.Width + X) * BytesPerPixel], - Pixel, BytesPerPixel); -end; - -procedure SetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); -var - BytesPerPixel: LongInt; -begin - Assert(Pixel <> nil); - BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel; - CopyPixel(Pixel, @PByteArray(Image.Bits)[(Y * Image.Width + X) * BytesPerPixel], - BytesPerPixel); -end; - -function GetPixel32(const Image: TImageData; X, Y: LongInt): TColor32Rec; -var - Info: PImageFormatInfo; - Data: PByte; -begin - Info := ImageFormatInfos[Image.Format]; - Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; - Result := GetPixel32Generic(Data, Info, Image.Palette); -end; - -procedure SetPixel32(const Image: TImageData; X, Y: LongInt; const Color: TColor32Rec); -var - Info: PImageFormatInfo; - Data: PByte; -begin - Info := ImageFormatInfos[Image.Format]; - Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; - SetPixel32Generic(Data, Info, Image.Palette, Color); -end; - -function GetPixelFP(const Image: TImageData; X, Y: LongInt): TColorFPRec; -var - Info: PImageFormatInfo; - Data: PByte; -begin - Info := ImageFormatInfos[Image.Format]; - Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; - Result := GetPixelFPGeneric(Data, Info, Image.Palette); -end; - -procedure SetPixelFP(const Image: TImageData; X, Y: LongInt; const Color: TColorFPRec); -var - Info: PImageFormatInfo; - Data: PByte; -begin - Info := ImageFormatInfos[Image.Format]; - Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; - SetPixelFPGeneric(Data, Info, Image.Palette, Color); -end; - -{ Palette Functions } - -procedure NewPalette(Entries: LongInt; var Pal: PPalette32); -begin - Assert((Entries > 2) and (Entries <= 65535)); - try - GetMem(Pal, Entries * SizeOf(TColor32Rec)); - FillChar(Pal^, Entries * SizeOf(TColor32Rec), $FF); - except - RaiseImaging(SErrorNewPalette, [Entries]); - end; -end; - -procedure FreePalette(var Pal: PPalette32); -begin - try - FreeMemNil(Pal); - except - RaiseImaging(SErrorFreePalette, [Pal]); - end; -end; - -procedure CopyPalette(SrcPal, DstPal: PPalette32; SrcIdx, DstIdx, Count: LongInt); -begin - Assert((SrcPal <> nil) and (DstPal <> nil)); - Assert((SrcIdx >= 0) and (DstIdx >= 0) and (Count >= 0)); - try - Move(SrcPal[SrcIdx], DstPal[DstIdx], Count * SizeOf(TColor32Rec)); - except - RaiseImaging(SErrorCopyPalette, [Count, SrcPal, DstPal]); - end; -end; - -function FindColor(Pal: PPalette32; Entries: LongInt; Color: TColor32): - LongInt; -var - Col: TColor32Rec; - I, MinDif, Dif: LongInt; -begin - Assert(Pal <> nil); - Result := -1; - Col.Color := Color; - try - // First try to find exact match - for I := 0 to Entries - 1 do - with Pal[I] do - begin - if (A = Col.A) and (R = Col.R) and - (G = Col.G) and (B = Col.B) then - begin - Result := I; - Exit; - end; - end; - - // If exact match was not found, find nearest color - MinDif := 1020; - for I := 0 to Entries - 1 do - with Pal[I] do - begin - Dif := Abs(R - Col.R); - if Dif > MinDif then Continue; - Dif := Dif + Abs(G - Col.G); - if Dif > MinDif then Continue; - Dif := Dif + Abs(B - Col.B); - if Dif > MinDif then Continue; - Dif := Dif + Abs(A - Col.A); - if Dif < MinDif then - begin - MinDif := Dif; - Result := I; - end; - end; - except - RaiseImaging(SErrorFindColor, [Pal, Entries]); - end; -end; - -procedure FillGrayscalePalette(Pal: PPalette32; Entries: LongInt); -var - I: LongInt; -begin - Assert(Pal <> nil); - try - for I := 0 to Entries - 1 do - with Pal[I] do - begin - A := $FF; - R := Byte(I); - G := Byte(I); - B := Byte(I); - end; - except - RaiseImaging(SErrorGrayscalePalette, [Pal, Entries]); - end; -end; - -procedure FillCustomPalette(Pal: PPalette32; Entries: LongInt; RBits, GBits, - BBits: Byte; Alpha: Byte = $FF); -var - I, TotalBits, MaxEntries: LongInt; -begin - Assert(Pal <> nil); - TotalBits := RBits + GBits + BBits; - MaxEntries := Min(Pow2Int(TotalBits), Entries); - FillChar(Pal^, Entries * SizeOf(TColor32Rec), 0); - try - for I := 0 to MaxEntries - 1 do - with Pal[I] do - begin - A := Alpha; - if RBits > 0 then - R := ((I shr Max(0, GBits + BBits - 1)) and (1 shl RBits - 1)) * 255 div (1 shl RBits - 1); - if GBits > 0 then - G := ((I shr Max(0, BBits - 1)) and (1 shl GBits - 1)) * 255 div (1 shl GBits - 1); - if BBits > 0 then - B := ((I shr 0) and (1 shl BBits - 1)) * 255 div (1 shl BBits - 1); - end; - except - RaiseImaging(SErrorCustomPalette, [Pal, Entries]); - end; -end; - -procedure SwapChannelsOfPalette(Pal: PPalette32; Entries, SrcChannel, - DstChannel: LongInt); -var - I: LongInt; - Swap: Byte; -begin - Assert(Pal <> nil); - Assert((SrcChannel in [0..3]) and (DstChannel in [0..3])); - try - for I := 0 to Entries - 1 do - with Pal[I] do - begin - Swap := Channels[SrcChannel]; - Channels[SrcChannel] := Channels[DstChannel]; - Channels[DstChannel] := Swap; - end; - except - RaiseImaging(SErrorSwapPalette, [Pal, Entries]); - end; -end; - -{ Options Functions } - -function SetOption(OptionId, Value: LongInt): Boolean; -begin - Result := False; - if (OptionId >= 0) and (OptionId < Length(Options)) and - (Options[OptionID] <> nil) then - begin - Options[OptionID]^ := CheckOptionValue(OptionId, Value); - Result := True; - end; -end; - -function GetOption(OptionId: LongInt): LongInt; -begin - Result := InvalidOption; - if (OptionId >= 0) and (OptionId < Length(Options)) and - (Options[OptionID] <> nil) then - begin - Result := Options[OptionID]^; - end; -end; - -function PushOptions: Boolean; -begin - Result := OptionStack.Push; -end; - -function PopOptions: Boolean; -begin - Result := OptionStack.Pop; -end; - -{ Image Format Functions } - -function GetImageFormatInfo(Format: TImageFormat; out Info: TImageFormatInfo): Boolean; -begin - FillChar(Info, SizeOf(Info), 0); - if ImageFormatInfos[Format] <> nil then - begin - Info := ImageFormatInfos[Format]^; - Result := True; - end - else - Result := False; -end; - -function GetPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; -begin - if ImageFormatInfos[Format] <> nil then - Result := ImageFormatInfos[Format].GetPixelsSize(Format, Width, Height) - else - Result := 0; -end; - -{ IO Functions } - -procedure SetUserFileIO(OpenProc: TOpenProc; - CloseProc: TCloseProc; EofProc: TEofProc; SeekProc: TSeekProc; TellProc: - TTellProc; ReadProc: TReadProc; WriteProc: TWriteProc); -begin - FileIO.Open := OpenProc; - FileIO.Close := CloseProc; - FileIO.Eof := EofProc; - FileIO.Seek := SeekProc; - FileIO.Tell := TellProc; - FileIO.Read := ReadProc; - FileIO.Write := WriteProc; -end; - -procedure ResetFileIO; -begin - FileIO := OriginalFileIO; -end; - -{ Raw Image IO Functions } - -procedure ReadRawImage(Handle: TImagingHandle; Width, Height: Integer; - Format: TImageFormat; out Image: TImageData; Offset, RowLength: Integer); -var - WidthBytes, I: Integer; - Info: PImageFormatInfo; -begin - Info := ImageFormatInfos[Format]; - // Calc scanline size - WidthBytes := Info.GetPixelsSize(Format, Width, 1); - if RowLength = 0 then - RowLength := WidthBytes; - // Create new image if needed - don't need to allocate new one if there is already - // one with desired size and format - if (Image.Width <> Width) or (Image.Height <> Height) or (Image.Format <> Format) then - NewImage(Width, Height, Format, Image); - // Move past the header - IO.Seek(Handle, Offset, smFromCurrent); - // Read scanlines from input - for I := 0 to Height - 1 do - begin - IO.Read(Handle, @PByteArray(Image.Bits)[I * WidthBytes], WidthBytes); - IO.Seek(Handle, RowLength - WidthBytes, smFromCurrent); - end; -end; - -procedure ReadRawImageFromFile(const FileName: string; Width, Height: Integer; - Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer); -var - Handle: TImagingHandle; -begin - Assert(FileName <> ''); - // Set IO ops to file ops and open given file - SetFileIO; - Handle := IO.Open(PChar(FileName), omReadOnly); - try - ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength); - finally - IO.Close(Handle); - end; -end; - -procedure ReadRawImageFromStream(Stream: TStream; Width, Height: Integer; - Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer); -var - Handle: TImagingHandle; -begin - Assert(Stream <> nil); - if Stream.Size - Stream.Position = 0 then - RaiseImaging(SErrorEmptyStream, []); - // Set IO ops to stream ops and open given stream - SetStreamIO; - Handle := IO.Open(Pointer(Stream), omReadOnly); - try - ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength); - finally - IO.Close(Handle); - end; -end; - -procedure ReadRawImageFromMemory(Data: Pointer; DataSize: Integer; Width, Height: Integer; - Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer); -var - Handle: TImagingHandle; - MemRec: TMemoryIORec; -begin - Assert((Data <> nil) and (DataSize > 0)); - // Set IO ops to memory ops and open given stream - SetMemoryIO; - MemRec := PrepareMemIO(Data, DataSize); - Handle := IO.Open(@MemRec, omReadOnly); - try - ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength); - finally - IO.Close(Handle); - end; -end; - -procedure ReadRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; - var Image: TImageData; Offset, RowLength: Integer); -var - DestScanBytes, RectBytes, I: Integer; - Info: PImageFormatInfo; - Src, Dest: PByte; -begin - Assert(Data <> nil); - Assert((Left + Width <= Image.Width) and (Top + Height <= Image.Height)); - Info := ImageFormatInfos[Image.Format]; - - // Calc scanline size - DestScanBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1); - RectBytes := Info.GetPixelsSize(Info.Format, Width, 1); - if RowLength = 0 then - RowLength := RectBytes; - - Src := Data; - Dest := @PByteArray(Image.Bits)[Top * DestScanBytes + Info.GetPixelsSize(Info.Format, Left, 1)]; - // Move past the header - Inc(Src, Offset); - - // Read lines into rect in the existing image - for I := 0 to Height - 1 do - begin - Move(Src^, Dest^, RectBytes); - Inc(Src, RowLength); - Inc(Dest, DestScanBytes); - end; -end; - -procedure WriteRawImage(Handle: TImagingHandle; const Image: TImageData; - Offset, RowLength: Integer); -var - WidthBytes, I: Integer; - Info: PImageFormatInfo; -begin - Info := ImageFormatInfos[Image.Format]; - // Calc scanline size - WidthBytes := Info.GetPixelsSize(Image.Format, Image.Width, 1); - if RowLength = 0 then - RowLength := WidthBytes; - // Move past the header - IO.Seek(Handle, Offset, smFromCurrent); - // Write scanlines to output - for I := 0 to Image.Height - 1 do - begin - IO.Write(Handle, @PByteArray(Image.Bits)[I * WidthBytes], WidthBytes); - IO.Seek(Handle, RowLength - WidthBytes, smFromCurrent); - end; -end; - -procedure WriteRawImageToFile(const FileName: string; const Image: TImageData; - Offset, RowLength: Integer); -var - Handle: TImagingHandle; -begin - Assert(FileName <> ''); - // Set IO ops to file ops and open given file - SetFileIO; - Handle := IO.Open(PChar(FileName), omCreate); - try - WriteRawImage(Handle, Image, Offset, RowLength); - finally - IO.Close(Handle); - end; -end; - -procedure WriteRawImageToStream(Stream: TStream; const Image: TImageData; - Offset, RowLength: Integer); -var - Handle: TImagingHandle; -begin - Assert(Stream <> nil); - // Set IO ops to stream ops and open given stream - SetStreamIO; - Handle := IO.Open(Pointer(Stream), omCreate); - try - WriteRawImage(Handle, Image, Offset, RowLength); - finally - IO.Close(Handle); - end; -end; - -procedure WriteRawImageToMemory(Data: Pointer; DataSize: Integer; const Image: TImageData; - Offset, RowLength: Integer); -var - Handle: TImagingHandle; - MemRec: TMemoryIORec; -begin - Assert((Data <> nil) and (DataSize > 0)); - // Set IO ops to memory ops and open given stream - SetMemoryIO; - MemRec := PrepareMemIO(Data, DataSize); - Handle := IO.Open(@MemRec, omCreate); - try - WriteRawImage(Handle, Image, Offset, RowLength); - finally - IO.Close(Handle); - end; -end; - -procedure WriteRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; - const Image: TImageData; Offset, RowLength: Integer); -var - SrcScanBytes, RectBytes, I: Integer; - Info: PImageFormatInfo; - Src, Dest: PByte; -begin - Assert(Data <> nil); - Assert((Left + Width <= Image.Width) and (Top + Height <= Image.Height)); - Info := ImageFormatInfos[Image.Format]; - - // Calc scanline size - SrcScanBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1); - RectBytes := Info.GetPixelsSize(Info.Format, Width, 1); - if RowLength = 0 then - RowLength := RectBytes; - - Src := @PByteArray(Image.Bits)[Top * SrcScanBytes + Info.GetPixelsSize(Info.Format, Left, 1)]; - Dest := Data; - // Move past the header - Inc(Dest, Offset); - - // Write lines from rect of the existing image - for I := 0 to Height - 1 do - begin - Move(Src^, Dest^, RectBytes); - Inc(Dest, RowLength); - Inc(Src, SrcScanBytes); - end; -end; - -{ Convenience/helper Functions } - -procedure ResizeImageToFit(const SrcImage: TImageData; FitWidth, FitHeight: Integer; - Filter: TResizeFilter; var DestImage: TImageData); -var - CurSize, FitSize, DestSize: TSize; -begin - if not TestImage(SrcImage) then - raise EImagingError.Create(SErrorInvalidInputImage); - - FitSize.CX := FitWidth; - FitSize.CY := FitHeight; - CurSize.CX := SrcImage.Width; - CurSize.CY := SrcImage.Height; - DestSize := ImagingUtility.ScaleSizeToFit(CurSize, FitSize); - - NewImage(Max(DestSize.CX, 1), Max(DestSize.CY, 1), SrcImage.Format, DestImage); - if SrcImage.Palette <> nil then - CopyPalette(SrcImage.Palette, DestImage.Palette, 0, 0, ImageFormatInfos[SrcImage.Format].PaletteEntries); - - StretchRect(SrcImage, 0, 0, CurSize.CX, CurSize.CY, DestImage, 0, 0, - DestSize.CX, DestSize.CY, Filter); -end; - -{ ------------------------------------------------------------------------ - Other Imaging Stuff - ------------------------------------------------------------------------} - -function GetFormatName(Format: TImageFormat): string; -begin - if ImageFormatInfos[Format] <> nil then - Result := ImageFormatInfos[Format].Name - else - Result := SUnknownFormat; -end; - -function ImageToStr(const Image: TImageData): string; -var - ImgSize: Integer; -begin - if TestImage(Image) then - with Image do - begin - ImgSize := Size; - if ImgSize > 8192 then - ImgSize := ImgSize div 1024; - Result := SysUtils.Format(SImageInfo, [@Image, Width, Height, - GetFormatName(Format), ImgSize + 0.0, Iff(ImgSize = Size, 'B', 'KiB'), Bits, - Palette]); - end - else - Result := SysUtils.Format(SImageInfoInvalid, [@Image]); -end; - -function GetVersionStr: string; -begin - Result := Format('%.1d.%.2d.%.1d', [ImagingVersionMajor, - ImagingVersionMinor, ImagingVersionPatch]); -end; - -function IffFormat(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -procedure RegisterImageFileFormat(AClass: TImageFileFormatClass); -begin - Assert(AClass <> nil); - if ImageFileFormats = nil then - ImageFileFormats := TList.Create; - if GlobalMetadata = nil then - GlobalMetadata := TMetadata.Create; - if ImageFileFormats <> nil then - ImageFileFormats.Add(AClass.Create); -end; - -function RegisterOption(OptionId: LongInt; Variable: PLongInt): Boolean; -begin - Result := False; - if Options = nil then - InitOptions; - - Assert(Variable <> nil); - - if OptionId >= Length(Options) then - SetLength(Options, OptionId + InitialOptions); - if (OptionId >= 0) and (OptionId < Length(Options)) {and (Options[OptionId] = nil) - must be able to override existing } then - begin - Options[OptionId] := Variable; - Result := True; - end; -end; - -function FindImageFileFormatByExt(const Ext: string): TImageFileFormat; -var - I: LongInt; -begin - Result := nil; - for I := ImageFileFormats.Count - 1 downto 0 do - if TImageFileFormat(ImageFileFormats[I]).Extensions.IndexOf(Ext) >= 0 then - begin - Result := TImageFileFormat(ImageFileFormats[I]); - Exit; - end; -end; - -function FindImageFileFormatByName(const FileName: string): TImageFileFormat; -var - I: LongInt; -begin - Result := nil; - for I := ImageFileFormats.Count - 1 downto 0 do - if TImageFileFormat(ImageFileFormats[I]).TestFileName(FileName) then - begin - Result := TImageFileFormat(ImageFileFormats[I]); - Exit; - end; -end; - -function FindImageFileFormatByClass(AClass: TImageFileFormatClass): TImageFileFormat; -var - I: LongInt; -begin - Result := nil; - for I := 0 to ImageFileFormats.Count - 1 do - if TImageFileFormat(ImageFileFormats[I]) is AClass then - begin - Result := TObject(ImageFileFormats[I]) as TImageFileFormat; - Break; - end; -end; - -function GetFileFormatCount: LongInt; -begin - Result := ImageFileFormats.Count; -end; - -function GetFileFormatAtIndex(Index: LongInt): TImageFileFormat; -begin - if (Index >= 0) and (Index < ImageFileFormats.Count) then - Result := TImageFileFormat(ImageFileFormats[Index]) - else - Result := nil; -end; - -function GetImageFileFormatsFilter(OpenFileFilter: Boolean): string; -var - I, J, Count: LongInt; - Descriptions: string; - Filters, CurFilter: string; - FileFormat: TImageFileFormat; -begin - Descriptions := ''; - Filters := ''; - Count := 0; - - for I := 0 to ImageFileFormats.Count - 1 do - begin - FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat; - - // If we are creating filter for save dialog and this format cannot save - // files the we skip it - if not OpenFileFilter and not FileFormat.CanSave then - Continue; - - CurFilter := ''; - for J := 0 to FileFormat.Masks.Count - 1 do - begin - CurFilter := CurFilter + FileFormat.Masks[J]; - if J < FileFormat.Masks.Count - 1 then - CurFilter := CurFilter + ';'; - end; - - FmtStr(Descriptions, '%s%s (%s)|%2:s', [Descriptions, FileFormat.Name, CurFilter]); - if Filters <> '' then - FmtStr(Filters, '%s;%s', [Filters, CurFilter]) - else - Filters := CurFilter; - - if I < ImageFileFormats.Count - 1 then - Descriptions := Descriptions + '|'; - - Inc(Count); - end; - - if (Count > 1) and OpenFileFilter then - FmtStr(Descriptions, '%s (%s)|%1:s|%s', [SAllFilter, Filters, Descriptions]); - - Result := Descriptions; -end; - -function GetFilterIndexExtension(Index: LongInt; OpenFileFilter: Boolean): string; -var - I, Count: LongInt; - FileFormat: TImageFileFormat; -begin - // -1 because filter indices are in 1..n range - Index := Index - 1; - Result := ''; - if OpenFileFilter then - begin - if Index > 0 then - Index := Index - 1; - end; - - if (Index >= 0) and (Index < ImageFileFormats.Count) then - begin - Count := 0; - for I := 0 to ImageFileFormats.Count - 1 do - begin - FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat; - if not OpenFileFilter and not FileFormat.CanSave then - Continue; - if Index = Count then - begin - if FileFormat.Extensions.Count > 0 then - Result := FileFormat.Extensions[0]; - Exit; - end; - Inc(Count); - end; - end; -end; - -function GetFileNameFilterIndex(const FileName: string; OpenFileFilter: Boolean): LongInt; -var - I: LongInt; - FileFormat: TImageFileFormat; -begin - Result := 0; - for I := 0 to ImageFileFormats.Count - 1 do - begin - FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat; - if not OpenFileFilter and not FileFormat.CanSave then - Continue; - if FileFormat.TestFileName(FileName) then - begin - // +1 because filter indices are in 1..n range - Inc(Result); - if OpenFileFilter then - Inc(Result); - Exit; - end; - Inc(Result); - end; - Result := -1; -end; - -function GetIO: TIOFunctions; -begin - Result := IO; -end; - -procedure RaiseImaging(const Msg: string; const Args: array of const); -var - WholeMsg: string; -begin - WholeMsg := Msg; - if GetExceptObject <> nil then - begin - WholeMsg := WholeMsg + ' ' + SExceptMsg + ': ' + - GetExceptObject.Message; - end; - raise EImagingError.CreateFmt(WholeMsg, Args); -end; - -procedure RaiseImaging(const Msg: string); -begin - RaiseImaging(Msg, []); -end; - -{ Internal unit functions } - -function CheckOptionValue(OptionId, Value: LongInt): LongInt; -begin - case OptionId of - ImagingColorReductionMask: - Result := ClampInt(Value, 0, $FF); - ImagingLoadOverrideFormat, ImagingSaveOverrideFormat: - Result := Iff(ImagingFormats.IsImageFormatValid(TImageFormat(Value)), - Value, LongInt(ifUnknown)); - ImagingMipMapFilter: Result := ClampInt(Value, Ord(Low(TSamplingFilter)), - Ord(High(TSamplingFilter))); - else - Result := Value; - end; -end; - -procedure SetFileIO; -begin - IO := FileIO; -end; - -procedure SetStreamIO; -begin - IO := StreamIO; -end; - -procedure SetMemoryIO; -begin - IO := MemoryIO; -end; - -procedure InitImageFormats; -begin - ImagingFormats.InitImageFormats(ImageFormatInfos); -end; - -procedure FreeImageFileFormats; -var - I: LongInt; -begin - if ImageFileFormats <> nil then - for I := 0 to ImageFileFormats.Count - 1 do - TImageFileFormat(ImageFileFormats[I]).Free; - FreeAndNil(ImageFileFormats); -end; - -procedure InitOptions; -begin - SetLength(Options, InitialOptions); - OptionStack := TOptionStack.Create; -end; - -procedure FreeOptions; -begin - SetLength(Options, 0); - FreeAndNil(OptionStack); -end; - -{ - TImageFileFormat class implementation -} - -constructor TImageFileFormat.Create(AMetadata: TMetadata); -begin - inherited Create; - FName := SUnknownFormat; - FExtensions := TStringList.Create; - FMasks := TStringList.Create; - if AMetadata = nil then - FMetadata := GlobalMetadata - else - FMetadata := AMetadata; - Define; -end; - -destructor TImageFileFormat.Destroy; -begin - FExtensions.Free; - FMasks.Free; - inherited Destroy; -end; - -procedure TImageFileFormat.Define; -begin -end; - -function TImageFileFormat.PrepareLoad(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean; -begin - FMetadata.ClearMetaItems; // Clear old metadata - FreeImagesInArray(Images); - SetLength(Images, 0); - Result := Handle <> nil; -end; - -function TImageFileFormat.PostLoadCheck(var Images: TDynImageDataArray; - LoadResult: Boolean): Boolean; -var - I: LongInt; -begin - if not LoadResult then - begin - FreeImagesInArray(Images); - SetLength(Images, 0); - Result := False; - end - else - begin - Result := (Length(Images) > 0) and TestImagesInArray(Images); - - if Result then - begin - // Convert to overriden format if it is set - if LoadOverrideFormat <> ifUnknown then - for I := Low(Images) to High(Images) do - ConvertImage(Images[I], LoadOverrideFormat); - end; - end; -end; - -function TImageFileFormat.PrepareSave(Handle: TImagingHandle; - const Images: TDynImageDataArray; var Index: Integer): Boolean; -var - Len, I: LongInt; -begin - CheckOptionsValidity; - Result := False; - if CanSave then - begin - Len := Length(Images); - Assert(Len > 0); - - // If there are no images to be saved exit - if Len = 0 then Exit; - - // Check index of image to be saved (-1 as index means save all images) - if IsMultiImageFormat then - begin - if (Index >= Len) then - Index := 0; - - if Index < 0 then - begin - Index := 0; - FFirstIdx := 0; - FLastIdx := Len - 1; - end - else - begin - FFirstIdx := Index; - FLastIdx := Index; - end; - - for I := FFirstIdx to FLastIdx - 1 do - begin - if not TestImage(Images[I]) then - Exit; - end; - end - else - begin - if (Index >= Len) or (Index < 0) then - Index := 0; - if not TestImage(Images[Index]) then - Exit; - end; - - Result := True; - end; -end; - -procedure TImageFileFormat.AddMasks(const AMasks: string); -var - I: LongInt; - Ext: string; -begin - FExtensions.Clear; - FMasks.CommaText := AMasks; - FMasks.Delimiter := ';'; - - for I := 0 to FMasks.Count - 1 do - begin - FMasks[I] := Trim(FMasks[I]); - Ext := GetFileExt(FMasks[I]); - if (Ext <> '') and (Ext <> '*') then - FExtensions.Add(Ext); - end; -end; - -function TImageFileFormat.GetFormatInfo(Format: TImageFormat): TImageFormatInfo; -begin - Result := ImageFormatInfos[Format]^; -end; - -function TImageFileFormat.GetSupportedFormats: TImageFormats; -begin - Result := FSupportedFormats; -end; - -function TImageFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean; -begin - Result := False; - RaiseImaging(SFileFormatCanNotLoad, [FName]); -end; - -function TImageFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -begin - Result := False; - RaiseImaging(SFileFormatCanNotSave, [FName]); -end; - -procedure TImageFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin -end; - -function TImageFileFormat.IsSupported(const Image: TImageData): Boolean; -begin - Result := Image.Format in GetSupportedFormats; -end; - -function TImageFileFormat.LoadFromFile(const FileName: string; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Handle: TImagingHandle; -begin - Result := False; - if CanLoad then - try - // Set IO ops to file ops and open given file - SetFileIO; - Handle := IO.Open(PChar(FileName), omReadOnly); - try - // Test if file contains valid image and if so then load it - if TestFormat(Handle) then - begin - Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and - LoadData(Handle, Images, OnlyFirstlevel); - Result := PostLoadCheck(Images, Result); - end - else - RaiseImaging(SFileNotValid, [FileName, Name]); - finally - IO.Close(Handle); - end; - except - RaiseImaging(SErrorLoadingFile, [FileName, FExtensions[0]]); - end; -end; - -function TImageFileFormat.LoadFromStream(Stream: TStream; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Handle: TImagingHandle; - OldPosition: Int64; -begin - Result := False; - OldPosition := Stream.Position; - if CanLoad then - try - // Set IO ops to stream ops and "open" given memory - SetStreamIO; - Handle := IO.Open(Pointer(Stream), omReadOnly); - try - // Test if stream contains valid image and if so then load it - if TestFormat(Handle) then - begin - Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and - LoadData(Handle, Images, OnlyFirstlevel); - Result := PostLoadCheck(Images, Result); - end - else - RaiseImaging(SStreamNotValid, [@Stream, Name]); - finally - IO.Close(Handle); - end; - except - Stream.Position := OldPosition; - FreeImagesInArray(Images); - RaiseImaging(SErrorLoadingStream, [@Stream, FExtensions[0]]); - end; -end; - -function TImageFileFormat.LoadFromMemory(Data: Pointer; Size: LongInt; var - Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Handle: TImagingHandle; - IORec: TMemoryIORec; -begin - Result := False; - if CanLoad then - try - // Set IO ops to memory ops and "open" given memory - SetMemoryIO; - IORec := PrepareMemIO(Data, Size); - Handle := IO.Open(@IORec,omReadOnly); - try - // Test if memory contains valid image and if so then load it - if TestFormat(Handle) then - begin - Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and - LoadData(Handle, Images, OnlyFirstlevel); - Result := PostLoadCheck(Images, Result); - end - else - RaiseImaging(SMemoryNotValid, [Data, Size, Name]); - finally - IO.Close(Handle); - end; - except - RaiseImaging(SErrorLoadingMemory, [Data, Size, FExtensions[0]]); - end; -end; - -function TImageFileFormat.SaveToFile(const FileName: string; - const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Handle: TImagingHandle; - Len, Index, I: LongInt; - Ext, FName: string; -begin - Result := False; - if CanSave and TestImagesInArray(Images) then - try - SetFileIO; - Len := Length(Images); - if IsMultiImageFormat or - (not IsMultiImageFormat and (OnlyFirstLevel or (Len = 1))) then - begin - Handle := IO.Open(PChar(FileName), GetSaveOpenMode); - try - if OnlyFirstLevel then - Index := 0 - else - Index := -1; - // Write multi image to one file - Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); - finally - IO.Close(Handle); - end; - end - else - begin - // Write multi image to file sequence - Ext := ExtractFileExt(FileName); - FName := ChangeFileExt(FileName, ''); - Result := True; - for I := 0 to Len - 1 do - begin - Handle := IO.Open(PChar(Format(FName + '%.3d' + Ext, [I])), GetSaveOpenMode); - try - Index := I; - Result := Result and PrepareSave(Handle, Images, Index) and - SaveData(Handle, Images, Index); - if not Result then - Break; - finally - IO.Close(Handle); - end; - end; - end; - except - raise UpdateExceptMessage(GetExceptObject, SErrorSavingFile, [FileName, FExtensions[0]]); - end; -end; - -function TImageFileFormat.SaveToStream(Stream: TStream; - const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Handle: TImagingHandle; - Len, Index, I: LongInt; - OldPosition: Int64; -begin - Result := False; - OldPosition := Stream.Position; - if CanSave and TestImagesInArray(Images) then - try - SetStreamIO; - Handle := IO.Open(PChar(Stream), GetSaveOpenMode); - try - if IsMultiImageFormat or OnlyFirstLevel then - begin - if OnlyFirstLevel then - Index := 0 - else - Index := -1; - // Write multi image in one run - Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); - end - else - begin - // Write multi image to sequence - Result := True; - Len := Length(Images); - for I := 0 to Len - 1 do - begin - Index := I; - Result := Result and PrepareSave(Handle, Images, Index) and - SaveData(Handle, Images, Index); - if not Result then - Break; - end; - end; - finally - IO.Close(Handle); - end; - except - Stream.Position := OldPosition; - raise UpdateExceptMessage(GetExceptObject, SErrorSavingStream, [@Stream, FExtensions[0]]); - end; -end; - -function TImageFileFormat.SaveToMemory(Data: Pointer; var Size: LongInt; - const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Handle: TImagingHandle; - Len, Index, I: LongInt; - IORec: TMemoryIORec; -begin - Result := False; - if CanSave and TestImagesInArray(Images) then - try - SetMemoryIO; - IORec := PrepareMemIO(Data, Size); - Handle := IO.Open(PChar(@IORec), GetSaveOpenMode); - try - if IsMultiImageFormat or OnlyFirstLevel then - begin - if OnlyFirstLevel then - Index := 0 - else - Index := -1; - // Write multi image in one run - Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); - end - else - begin - // Write multi image to sequence - Result := True; - Len := Length(Images); - for I := 0 to Len - 1 do - begin - Index := I; - Result := Result and PrepareSave(Handle, Images, Index) and - SaveData(Handle, Images, Index); - if not Result then - Break; - end; - end; - Size := IORec.Position; - finally - IO.Close(Handle); - end; - except - raise UpdateExceptMessage(GetExceptObject, SErrorSavingMemory, [Data, Size, FExtensions[0]]); - end; -end; - -function TImageFileFormat.MakeCompatible(const Image: TImageData; - var Compatible: TImageData; out MustBeFreed: Boolean): Boolean; -begin - InitImage(Compatible); - - if SaveOverrideFormat <> ifUnknown then - begin - // Save format override is active. Clone input and convert it to override format. - CloneImage(Image, Compatible); - ConvertImage(Compatible, SaveOverrideFormat); - // Now check if override format is supported by file format. If it is not - // then file format specific conversion (virtual method) is called. - Result := IsSupported(Compatible); - if not Result then - begin - ConvertToSupported(Compatible, GetFormatInfo(Compatible.Format)); - Result := IsSupported(Compatible); - end; - end // Add IsCompatible function! not only checking by Format - else if IsSupported(Image) then - begin - // No save format override and input is in format supported by this - // file format. Just copy Image's fields to Compatible - Compatible := Image; - Result := True; - end - else - begin - // No override and input's format is not compatible with file format. - // Clone it and the call file format specific conversion (virtual method). - CloneImage(Image, Compatible); - ConvertToSupported(Compatible, GetFormatInfo(Compatible.Format)); - Result := IsSupported(Compatible); - end; - // Tell the user that he must free Compatible after he's done with it - // (if necessary). - MustBeFreed := Image.Bits <> Compatible.Bits; -end; - -function TImageFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -begin - Result := False; -end; - -function TImageFileFormat.TestFileName(const FileName: string): Boolean; -var - I: LongInt; - OnlyName: string; -begin - OnlyName := ExtractFileName(FileName); - // For each mask test if filename matches it - for I := 0 to FMasks.Count - 1 do - if StrMaskMatch(OnlyName, FMasks[I], False) then - begin - Result := True; - Exit; - end; - Result := False; -end; - -procedure TImageFileFormat.CheckOptionsValidity; -begin -end; - -function TImageFileFormat.GetCanLoad: Boolean; -begin - Result := ffLoad in FFeatures; -end; - -function TImageFileFormat.GetCanSave: Boolean; -begin - Result := ffSave in FFeatures; -end; - -function TImageFileFormat.GetIsMultiImageFormat: Boolean; -begin - Result := ffMultiImage in FFeatures; -end; - -function TImageFileFormat.GetSaveOpenMode: TOpenMode; -begin - // TODO: fix - //if ffReadOnSave in FFeatures then - // Result := omReadWrite - //else - Result := omCreate; -end; - -{ TOptionStack class implementation } - -constructor TOptionStack.Create; -begin - inherited Create; - FPosition := -1; -end; - -destructor TOptionStack.Destroy; -var - I: LongInt; -begin - for I := 0 to OptionStackDepth - 1 do - SetLength(FStack[I], 0); - inherited Destroy; -end; - -function TOptionStack.Pop: Boolean; -var - I: LongInt; -begin - Result := False; - if FPosition >= 0 then - begin - SetLength(Options, Length(FStack[FPosition])); - for I := 0 to Length(FStack[FPosition]) - 1 do - if Options[I] <> nil then - Options[I]^ := FStack[FPosition, I]; - Dec(FPosition); - Result := True; - end; -end; - -function TOptionStack.Push: Boolean; -var - I: LongInt; -begin - Result := False; - if FPosition < OptionStackDepth - 1 then - begin - Inc(FPosition); - SetLength(FStack[FPosition], Length(Options)); - for I := 0 to Length(Options) - 1 do - if Options[I] <> nil then - FStack[FPosition, I] := Options[I]^; - Result := True; - end; -end; - -{ TMetadata } - -procedure TMetadata.SetMetaItem(const Id: string; const Value: Variant; - ImageIndex: Integer); -begin - AddMetaToList(FLoadMetaItems, Id, Value, ImageIndex); -end; - -procedure TMetadata.SetMetaItemForSaving(const Id: string; const Value: Variant; - ImageIndex: Integer); -begin - AddMetaToList(FSaveMetaItems, Id, Value, ImageIndex); -end; - -procedure TMetadata.AddMetaToList(List: TStringList; const Id: string; - const Value: Variant; ImageIndex: Integer); -var - Item: TMetadataItem; - Idx: Integer; - FullId: string; -begin - FullId := GetMetaItemName(Id, ImageIndex); - if List.Find(FullId, Idx) then - (List.Objects[Idx] as TMetadataItem).Value := Value - else - begin - Item := TMetadataItem.Create; - Item.Id := Id; - Item.ImageIndex := ImageIndex; - Item.Value := Value; - List.AddObject(FullId, Item); - end; -end; - -procedure TMetadata.ClearMetaItems; -begin - ClearMetaList(FLoadMetaItems); -end; - -procedure TMetadata.ClearMetaItemsForSaving; -begin - ClearMetaList(FSaveMetaItems); -end; - -procedure TMetadata.ClearMetaList(List: TStringList); -var - I: Integer; -begin - for I := 0 to List.Count - 1 do - List.Objects[I].Free; - List.Clear; -end; - -procedure TMetadata.CopyLoadedMetaItemsForSaving; -var - I: Integer; - Copy, Orig: TMetadataItem; -begin - ClearMetaItemsForSaving; - for I := 0 to FLoadMetaItems.Count - 1 do - begin - Orig := TMetadataItem(FLoadMetaItems.Objects[I]); - Copy := TMetadataItem.Create; - Copy.Id := Orig.Id; - Copy.ImageIndex := Orig.ImageIndex; - Copy.Value := Orig.Value; - FSaveMetaItems.AddObject(GetMetaItemName(Copy.Id, Copy.ImageIndex), Copy); - end; -end; - -constructor TMetadata.Create; -begin - inherited; - FLoadMetaItems := TStringList.Create; - FLoadMetaItems.Sorted := True; - FSaveMetaItems := TStringList.Create; - FSaveMetaItems.Sorted := True; -end; - -destructor TMetadata.Destroy; -begin - ClearMetaItems; - ClearMetaItemsForSaving; - FLoadMetaItems.Free; - FSaveMetaItems.Free; - inherited; -end; - -function TMetadata.GetMetaById(const Id: string): Variant; -var - Idx: Integer; -begin - if FLoadMetaItems.Find(Id, Idx) then - Result := (FLoadMetaItems.Objects[Idx] as TMetadataItem).Value - else - Result := Variants.Null; -end; - -function TMetadata.GetMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; -begin - Result := GetMetaById(GetMetaItemName(Id, ImageIndex)); -end; - -function TMetadata.GetSaveMetaById(const Id: string): Variant; -var - Idx: Integer; -begin - if FSaveMetaItems.Find(Id, Idx) then - Result := (FSaveMetaItems.Objects[Idx] as TMetadataItem).Value - else - Result := Variants.Null; -end; - -function TMetadata.GetSaveMetaByIdMulti(const Id: string; - ImageIndex: Integer): Variant; -begin - Result := GetSaveMetaById(GetMetaItemName(Id, ImageIndex)); -end; - -function TMetadata.GetMetaByIdx(Index: Integer): TMetadataItem; -begin - Result := FLoadMetaItems.Objects[Index] as TMetadataItem; -end; - -function TMetadata.GetMetaCount: Integer; -begin - Result := FLoadMetaItems.Count; -end; - -function TMetadata.GetMetaItemName(const Id: string; - ImageIndex: Integer): string; -begin - Result := Iff(ImageIndex = 0, Id, Format(SMetaIdForSubImage, [Id, ImageIndex])); -end; - -function TMetadata.GetPhysicalPixelSize(ResUnit: TResolutionUnit; var XSize, - YSize: Single; MetaForSave: Boolean; ImageIndex: Integer): Boolean; -type - TGetter = function(const Id: string; ImageIndex: Integer): Variant of object; -var - Getter: TGetter; - XMeta, YMeta: Variant; -begin - if MetaForSave then - Getter := GetSaveMetaByIdMulti - else - Getter := GetMetaByIdMulti; - - XMeta := Getter(SMetaPhysicalPixelSizeX, ImageIndex); - YMeta := Getter(SMetaPhysicalPixelSizeY, ImageIndex); - XSize := -1; - YSize := -1; - - Result := not VarIsNull(XMeta) or not VarIsNull(YMeta); - - if not Result then - Exit; - - if not VarIsNull(XMeta) then - XSize := XMeta; - if not VarIsNull(YMeta) then - YSize := YMeta; - - if XSize < 0 then - XSize := YSize; - if YSize < 0 then - YSize := XSize; - - TranslateUnits(ResUnit, XSize, YSize); -end; - -procedure TMetadata.SetPhysicalPixelSize(ResUnit: TResolutionUnit; XSize, - YSize: Single; MetaForSave: Boolean; ImageIndex: Integer); -type - TAdder = procedure(const Id: string; const Value: Variant; ImageIndex: Integer) of object; -var - Adder: TAdder; -begin - TranslateUnits(ResUnit, XSize, YSize); - - if MetaForSave then - Adder := SetMetaItemForSaving - else - Adder := SetMetaItem; - - Adder(SMetaPhysicalPixelSizeX, XSize, ImageIndex); - Adder(SMetaPhysicalPixelSizeY, YSize, ImageIndex); -end; - -procedure TMetadata.TranslateUnits(ResolutionUnit: TResolutionUnit; var XRes, - YRes: Single); -var - UnitSize: Single; -begin - case ResolutionUnit of - ruDpi: UnitSize := 25400; - ruDpm: UnitSize := 1e06; - ruDpcm: UnitSize := 1e04; - else - UnitSize := 1; - end; - if ResolutionUnit <> ruSizeInMicroMeters then - begin - XRes := UnitSize / XRes; - YRes := UnitSize / YRes; - end; -end; - -function TMetadata.HasMetaItem(const Id: string; ImageIndex: Integer): Boolean; -begin - Result := GetMetaByIdMulti(Id, ImageIndex) <> Variants.Null; -end; - -function TMetadata.HasMetaItemForSaving(const Id: string; ImageIndex: Integer): Boolean; -begin - Result := GetSaveMetaByIdMulti(Id, ImageIndex) <> Variants.Null; -end; - -initialization -{$IFDEF MEMCHECK} - {$IF CompilerVersion >= 18} - System.ReportMemoryLeaksOnShutdown := True; - {$IFEND} -{$ENDIF} - if GlobalMetadata = nil then - GlobalMetadata := TMetadata.Create; - if ImageFileFormats = nil then - ImageFileFormats := TList.Create; - InitImageFormats; - RegisterOption(ImagingColorReductionMask, @ColorReductionMask); - RegisterOption(ImagingLoadOverrideFormat, @LoadOverrideFormat); - RegisterOption(ImagingSaveOverrideFormat, @SaveOverrideFormat); - RegisterOption(ImagingMipMapFilter, @MipMapFilter); - RegisterOption(ImagingBinaryTreshold, @BinaryTreshold); -finalization - FreeOptions; - FreeImageFileFormats; - GlobalMetadata.Free; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 --------------------------------------------------- - - Updated IO Open functions according to changes in ImagingTypes. - - Fixed bug in SplitImage that could cause wrong size of edge chunks. - - Metadata support fixes and extensions (frame delays, animation loops). - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Started reworking exception raising to keep the original class type - (e.g. in NewImage EOutOfMemory could be raised but was hidden - by EImagingError raised afterwards in NewImage try/except). - - Fixed possible AV in Rotate45 subproc of RotateImage. - - Added ReadRawXXX and WriteRawXXX functions for raw image bits IO. - - Implemented ImagingBinaryTreshold option. - - Added support for simple image metadata loading/saving. - - Moved file format definition (name, exts, caps, ...) from - constructor to new Define method. - - Fixed some memory leaks caused by failures during image loading. - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Extended RotateImage to allow arbitrary angle rotations. - - Reversed the order file formats list is searched so - if you register a new one it will be found sooner than - built in formats. - - Fixed memory leak in ResizeImage ocurring when resizing - indexed images. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - Added position/size checks to LoadFromStream functions. - - Changed conditional compilation in impl. uses section to reflect changes - in LINK symbols. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - GenerateMipMaps now generates all smaller levels from - original big image (better results when using more advanced filters). - Also conversion to compatible image format is now done here not - in FillMipMapLevel (that is called for every mipmap level). - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - MakePaletteForImages now works correctly for indexed and special format images - - Fixed bug in StretchRect: Image was not properly stretched if - src and dst dimensions differed only in height. - - ConvertImage now fills new image with zeroes to avoid random data in - some conversions (RGB->XRGB) - - Changed RegisterOption procedure to function - - Changed bunch of palette functions from low level interface to procedure - (there was no reason for them to be functions). - - Changed FreeImage and FreeImagesInArray functions to procedures. - - Added many assertions, come try-finally, other checks, and small code - and doc changes. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - GenerateMipMaps threw failed assertion when input was indexed or special, - fixed. - - Added CheckOptionsValidity to TImageFileFormat and its decendants. - - Unit ImagingExtras which registers file formats in Extras package - is now automatically added to uses clause if LINK_EXTRAS symbol is - defined in ImagingOptions.inc file. - - Added EnumFileFormats function to low level interface. - - Fixed bug in SwapChannels which could cause AV when swapping alpha - channel of A8R8G8B8 images. - - Converting loaded images to ImagingOverrideFormat is now done - in PostLoadCheck method to avoid code duplicity. - - Added GetFileFormatCount and GetFileFormatAtIndex functions - - Bug in ConvertImage: if some format was converted to similar format - only with swapped channels (R16G16B16<>B16G16R16) then channels were - swapped correctly but new data format (swapped one) was not set. - - Made TImageFileFormat.MakeCompatible public non-virtual method - (and modified its function). Created new virtual - ConvertToSupported which should be overriden by descendants. - Main reason for doint this is to avoid duplicate code that was in all - TImageFileFormat's descendants. - - Changed TImageFileFormat.GetFormatInfo's result type to TImageFormatInfo. - - Split overloaded FindImageFileFormat functions to - FindImageFileFormatByClass and FindImageFileFormatByExt and created new - FindImageFileFormatByName which operates on whole filenames. - - Function GetExtensionFilterIndex renamed to GetFileNameFilterIndex - (because it now works with filenames not extensions). - - DetermineFileFormat now first searches by filename and if not found - then by data. - - Added TestFileName method to TImageFileFormat. - - Updated GetImageFileFormatsFilter to uses Masks instead of Extensions - property of TImageFileFormat. Also you can now request - OpenDialog and SaveDialog type filters - - Added Masks property and AddMasks method to TImageFileFormat. - AddMasks replaces AddExtensions, it uses filename masks instead - of sime filename extensions to identify supported files. - - Changed TImageFileFormat.LoadData procedure to function and - moved varios duplicate code from its descandats (check index,...) - here to TImageFileFormat helper methods. - - Changed TImageFileFormat.SaveData procedure to function and - moved varios duplicate code from its descandats (check index,...) - here to TImageFileFormat helper methods. - - Removed RAISE_EXCEPTIONS define, exceptions are now raised everytime - - Added MustBeFreed parameter to TImageFileFormat.MakeComptible method - that indicates that compatible image returned by this method must be - freed after its usage. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - fixed bug in NewImage: if given format was ifDefault it wasn't - replaced with DefaultImageFormat constant which caused problems later - in other units - - fixed bug in RotateImage which caused that rotated special format - images were whole black - - LoadImageFromXXX and LoadMultiImageFromXXX now use DetermineXXXFormat - when choosing proper loader, this eliminated need for Ext parameter - in stream and memory loading functions - - added GetVersionStr function - - fixed bug in ResizeImage which caued indexed images to lose their - palette during process resulting in whole black image - - Clipping in ...Rect functions now uses clipping procs from ImagingUtility, - it also works better - - FillRect optimization for 8, 16, and 32 bit formats - - added pixel set/get functions to low level interface: - GetPixelDirect, SetPixelDirect, GetPixel32, SetPixel32, - GetPixelFP, SetPixelFP - - removed GetPixelBytes low level intf function - redundant - (same data can be obtained by GetImageFormatInfo) - - made small changes in many parts of library to compile - on AMD64 CPU (Linux with FPC) - - changed InitImage to procedure (function was pointless) - - Method TestFormat of TImageFileFormat class made public - (was protected) - - added function IsFileFormatSupported to low level interface - (contributed by Paul Michell) - - fixed some missing format arguments from error strings - which caused Format function to raise exception - - removed forgotten debug code that disabled filtered resizing of images with - channel bitcounts > 8 - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - changed order of parameters of CopyRect function - - GenerateMipMaps now filters mipmap levels - - ResizeImage functions was extended to allow bilinear and bicubic filtering - - added StretchRect function to low level interface - - added functions GetImageFileFormatsFilter, GetFilterIndexExtension, - and GetExtensionFilterIndex - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - added function RotateImage to low level interface - - moved TImageFormatInfo record and types required by it to - ImagingTypes unit, changed GetImageFormatInfo low level - interface function to return TImageFormatInfo instead of short info - - added checking of options values validity before they are used - - fixed possible memory leak in CloneImage - - added ReplaceColor function to low level interface - - new function FindImageFileFormat by class added - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - added DetermineFileFormat, DetermineStreamFormat, DetermineMemoryFormat, - GetPixelsSize functions to low level interface - - added NewPalette, CopyPalette, FreePalette functions - to low level interface - - added MapImageToPalette, FillRect, SplitImage, MakePaletteForImages - functions to low level interface - - fixed buggy FillCustomPalette function (possible div by zero and others) - - added CopyRect function to low level interface - - Member functions of TImageFormatInfo record implemented for all formats - - before saving images TestImagesInArray is called now - - added TestImagesInArray function to low level interface - - added GenerateMipMaps function to low level interface - - stream position in load/save from/to stream is now set to position before - function was called if error occurs - - when error occured during load/save from/to file file handle - was not released - - CloneImage returned always False - -} -end. - diff --git a/3rd/Imaging/Source/ImagingBitmap.pas b/3rd/Imaging/Source/ImagingBitmap.pas deleted file mode 100644 index 81684e4b9..000000000 --- a/3rd/Imaging/Source/ImagingBitmap.pas +++ /dev/null @@ -1,856 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ - This unit contains image format loader/saver for Windows Bitmap images. -} -unit ImagingBitmap; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingUtility, ImagingFormats, ImagingIO; - -type - { Class for loading and saving Windows Bitmap images. - It can load/save 8bit indexed, 16, 24, 32 bit RGB or ARGB - images with or without RLE compression. It can also load 1/4 bit - indexed images and OS2 bitmaps.} - TBitmapFileFormat = class(TImageFileFormat) - protected - FUseRLE: LongBool; - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - published - { Controls that RLE compression is used during saving. Accessible trough - ImagingBitmapRLE option.} - property UseRLE: LongBool read FUseRLE write FUseRLE; - end; - -implementation - -const - SBitmapFormatName = 'Windows Bitmap Image'; - SBitmapMasks = '*.bmp,*.dib'; - BitmapSupportedFormats: TImageFormats = [ifIndex8, ifA1R5G5B5, ifA4R4G4B4, - ifR5G6B5, ifR8G8B8, ifA8R8G8B8, ifX1R5G5B5, ifX4R4G4B4, ifX8R8G8B8]; - BitmapDefaultRLE = True; - -const - { Bitmap file identifier 'BM'.} - BMMagic: Word = 19778; - - { Constants for the TBitmapInfoHeader.Compression field.} - BI_RGB = 0; - BI_RLE8 = 1; - BI_RLE4 = 2; - BI_BITFIELDS = 3; - - V3InfoHeaderSize = 40; - V4InfoHeaderSize = 108; - -type - { File Header for Windows/OS2 bitmap file.} - TBitmapFileHeader = packed record - ID: Word; // Is always 19778 : 'BM' - Size: LongWord; // Filesize - Reserved1: Word; - Reserved2: Word; - Offset: LongWord; // Offset from start pos to beginning of image bits - end; - - { Info Header for Windows bitmap file version 4.} - TBitmapInfoHeader = packed record - Size: LongWord; - Width: LongInt; - Height: LongInt; - Planes: Word; - BitCount: Word; - Compression: LongWord; - SizeImage: LongWord; - XPelsPerMeter: LongInt; - YPelsPerMeter: LongInt; - ClrUsed: LongInt; - ClrImportant: LongInt; - RedMask: LongWord; - GreenMask: LongWord; - BlueMask: LongWord; - AlphaMask: LongWord; - CSType: LongWord; - EndPoints: array[0..8] of LongWord; - GammaRed: LongWord; - GammaGreen: LongWord; - GammaBlue: LongWord; - end; - - { Info Header for OS2 bitmaps.} - TBitmapCoreHeader = packed record - Size: LongWord; - Width: Word; - Height: Word; - Planes: Word; - BitCount: Word; - end; - - { Used in RLE encoding and decoding.} - TRLEOpcode = packed record - Count: Byte; - Command: Byte; - end; - PRLEOpcode = ^TRLEOpcode; - -{ TBitmapFileFormat class implementation } - -procedure TBitmapFileFormat.Define; -begin - inherited; - FName := SBitmapFormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := BitmapSupportedFormats; - - FUseRLE := BitmapDefaultRLE; - - AddMasks(SBitmapMasks); - RegisterOption(ImagingBitmapRLE, @FUseRLE); -end; - -function TBitmapFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - BF: TBitmapFileHeader; - BI: TBitmapInfoHeader; - BC: TBitmapCoreHeader; - IsOS2: Boolean; - PalRGB: PPalette24; - I, FPalSize, AlignedSize, StartPos, HeaderSize, AlignedWidthBytes, WidthBytes: LongInt; - Info: TImageFormatInfo; - Data: Pointer; - - procedure LoadRGB; - var - I: LongInt; - LineBuffer: PByte; - begin - with Images[0], GetIO do - begin - // If BI.Height is < 0 then image data are stored non-flipped - // but default in windows is flipped so if Height is positive we must - // flip it - - if BI.BitCount < 8 then - begin - // For 1 and 4 bit images load aligned data, they will be converted to - // 8 bit and unaligned later - GetMem(Data, AlignedSize); - - if BI.Height < 0 then - Read(Handle, Data, AlignedSize) - else - for I := Height - 1 downto 0 do - Read(Handle, @PByteArray(Data)[I * AlignedWidthBytes], AlignedWidthBytes); - end - else - begin - // Images with pixels of size >= 1 Byte are read line by line and - // copied to image bits without padding bytes - GetMem(LineBuffer, AlignedWidthBytes); - try - if BI.Height < 0 then - for I := 0 to Height - 1 do - begin - Read(Handle, LineBuffer, AlignedWidthBytes); - Move(LineBuffer^, PByteArray(Bits)[I * WidthBytes], WidthBytes); - end - else - for I := Height - 1 downto 0 do - begin - Read(Handle, LineBuffer, AlignedWidthBytes); - Move(LineBuffer^, PByteArray(Bits)[I * WidthBytes], WidthBytes); - end; - finally - FreeMemNil(LineBuffer); - end; - end; - end; - end; - - procedure LoadRLE4; - var - RLESrc: PByteArray; - Row, Col, WriteRow, I: LongInt; - SrcPos: LongWord; - DeltaX, DeltaY, Low, High: Byte; - Pixels: PByteArray; - OpCode: TRLEOpcode; - NegHeightBitmap: Boolean; - begin - GetMem(RLESrc, BI.SizeImage); - GetIO.Read(Handle, RLESrc, BI.SizeImage); - with Images[0] do - try - Low := 0; - Pixels := Bits; - SrcPos := 0; - NegHeightBitmap := BI.Height < 0; - Row := 0; // Current row in dest image - Col := 0; // Current column in dest image - // Row in dest image where actuall writting will be done - WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); - while (Row < Height) and (SrcPos < BI.SizeImage) do - begin - // Read RLE op-code - OpCode := PRLEOpcode(@RLESrc[SrcPos])^; - Inc(SrcPos, SizeOf(OpCode)); - if OpCode.Count = 0 then - begin - // A byte Count of zero means that this is a special - // instruction. - case OpCode.Command of - 0: - begin - // Move to next row - Inc(Row); - WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); - Col := 0; - end ; - 1: Break; // Image is finished - 2: - begin - // Move to a new relative position - DeltaX := RLESrc[SrcPos]; - DeltaY := RLESrc[SrcPos + 1]; - Inc(SrcPos, 2); - Inc(Col, DeltaX); - Inc(Row, DeltaY); - end - else - // Do not read data after EOF - if SrcPos + OpCode.Command > BI.SizeImage then - OpCode.Command := BI.SizeImage - SrcPos; - // Take padding bytes and nibbles into account - if Col + OpCode.Command > Width then - OpCode.Command := Width - Col; - // Store absolute data. Command code is the - // number of absolute bytes to store - for I := 0 to OpCode.Command - 1 do - begin - if (I and 1) = 0 then - begin - High := RLESrc[SrcPos] shr 4; - Low := RLESrc[SrcPos] and $F; - Pixels[WriteRow * Width + Col] := High; - Inc(SrcPos); - end - else - Pixels[WriteRow * Width + Col] := Low; - Inc(Col); - end; - // Odd number of bytes is followed by a pad byte - if (OpCode.Command mod 4) in [1, 2] then - Inc(SrcPos); - end; - end - else - begin - // Take padding bytes and nibbles into account - if Col + OpCode.Count > Width then - OpCode.Count := Width - Col; - // Store a run of the same color value - for I := 0 to OpCode.Count - 1 do - begin - if (I and 1) = 0 then - Pixels[WriteRow * Width + Col] := OpCode.Command shr 4 - else - Pixels[WriteRow * Width + Col] := OpCode.Command and $F; - Inc(Col); - end; - end; - end; - finally - FreeMem(RLESrc); - end; - end; - - procedure LoadRLE8; - var - RLESrc: PByteArray; - SrcCount, Row, Col, WriteRow: LongInt; - SrcPos: LongWord; - DeltaX, DeltaY: Byte; - Pixels: PByteArray; - OpCode: TRLEOpcode; - NegHeightBitmap: Boolean; - begin - GetMem(RLESrc, BI.SizeImage); - GetIO.Read(Handle, RLESrc, BI.SizeImage); - with Images[0] do - try - Pixels := Bits; - SrcPos := 0; - NegHeightBitmap := BI.Height < 0; - Row := 0; // Current row in dest image - Col := 0; // Current column in dest image - // Row in dest image where actuall writting will be done - WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); - while (Row < Height) and (SrcPos < BI.SizeImage) do - begin - // Read RLE op-code - OpCode := PRLEOpcode(@RLESrc[SrcPos])^; - Inc(SrcPos, SizeOf(OpCode)); - if OpCode.Count = 0 then - begin - // A byte Count of zero means that this is a special - // instruction. - case OpCode.Command of - 0: - begin - // Move to next row - Inc(Row); - WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); - Col := 0; - end ; - 1: Break; // Image is finished - 2: - begin - // Move to a new relative position - DeltaX := RLESrc[SrcPos]; - DeltaY := RLESrc[SrcPos + 1]; - Inc(SrcPos, 2); - Inc(Col, DeltaX); - Inc(Row, DeltaY); - end - else - SrcCount := OpCode.Command; - // Do not read data after EOF - if SrcPos + OpCode.Command > BI.SizeImage then - OpCode.Command := BI.SizeImage - SrcPos; - // Take padding bytes into account - if Col + OpCode.Command > Width then - OpCode.Command := Width - Col; - // Store absolute data. Command code is the - // number of absolute bytes to store - Move(RLESrc[SrcPos], Pixels[WriteRow * Width + Col], OpCode.Command); - Inc(SrcPos, SrcCount); - Inc(Col, OpCode.Command); - // Odd number of bytes is followed by a pad byte - if (SrcCount mod 2) = 1 then - Inc(SrcPos); - end; - end - else - begin - // Take padding bytes into account - if Col + OpCode.Count > Width then - OpCode.Count := Width - Col; - // Store a run of the same color value. Count is number of bytes to store - FillChar(Pixels [WriteRow * Width + Col], OpCode.Count, OpCode.Command); - Inc(Col, OpCode.Count); - end; - end; - finally - FreeMem(RLESrc); - end; - end; - -begin - Data := nil; - SetLength(Images, 1); - with GetIO, Images[0] do - try - FillChar(BI, SizeOf(BI), 0); - StartPos := Tell(Handle); - Read(Handle, @BF, SizeOf(BF)); - Read(Handle, @BI.Size, SizeOf(BI.Size)); - IsOS2 := BI.Size = SizeOf(TBitmapCoreHeader); - - // Bitmap Info reading - if IsOS2 then - begin - // OS/2 type bitmap, reads info header without 4 already read bytes - Read(Handle, @PByteArray(@BC)[SizeOf(BI.Size)], - SizeOf(TBitmapCoreHeader) - SizeOf(BI.Size)); - with BI do - begin - ClrUsed := 0; - Compression := BI_RGB; - BitCount := BC.BitCount; - Height := BC.Height; - Width := BC.Width; - end; - end - else - begin - // Windows type bitmap - HeaderSize := Min(BI.Size - SizeOf(BI.Size), SizeOf(BI) - SizeOf(BI.Size)); // do not read more than size of BI! - Read(Handle, @PByteArray(@BI)[SizeOf(BI.Size)], HeaderSize); - // SizeImage can be 0 for BI_RGB images, but it is here because of: - // I saved 8bit bitmap in Paint Shop Pro 8 as OS2 RLE compressed. - // It wrote strange 64 Byte Info header with SizeImage set to 0 - // Some progs were able to open it, some were not. - if BI.SizeImage = 0 then - BI.SizeImage := BF.Size - BF.Offset; - end; - // Bit mask reading. Only read it if there is V3 header, V4 header has - // masks laoded already (only masks for RGB in V3). - if (BI.Compression = BI_BITFIELDS) and (BI.Size = V3InfoHeaderSize) then - Read(Handle, @BI.RedMask, SizeOf(BI.RedMask) * 3); - - case BI.BitCount of - 1, 4, 8: Format := ifIndex8; - 16: - if BI.RedMask = $0F00 then - // Set XRGB4 or ARGB4 according to value of alpha mask - Format := IffFormat(BI.AlphaMask = 0, ifX4R4G4B4, ifA4R4G4B4) - else if BI.RedMask = $F800 then - Format := ifR5G6B5 - else - // R5G5B5 is default 16bit format (with Compression = BI_RGB or masks). - // We set it to A1.. and later there is a check if there are any alpha values - // and if not it is changed to X1R5G5B5 - Format := ifA1R5G5B5; - 24: Format := ifR8G8B8; - 32: Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later - end; - - NewImage(BI.Width, Abs(BI.Height), Format, Images[0]); - Info := GetFormatInfo(Format); - WidthBytes := Width * Info.BytesPerPixel; - AlignedWidthBytes := (((Width * BI.BitCount) + 31) shr 5) * 4; - AlignedSize := Height * LongInt(AlignedWidthBytes); - - // Palette settings and reading - if BI.BitCount <= 8 then - begin - // Seek to the begining of palette - Seek(Handle, StartPos + SizeOf(TBitmapFileHeader) + LongInt(BI.Size), - smFromBeginning); - if IsOS2 then - begin - // OS/2 type - FPalSize := 1 shl BI.BitCount; - GetMem(PalRGB, FPalSize * SizeOf(TColor24Rec)); - try - Read(Handle, PalRGB, FPalSize * SizeOf(TColor24Rec)); - for I := 0 to FPalSize - 1 do - with PalRGB[I] do - begin - Palette[I].R := R; - Palette[I].G := G; - Palette[I].B := B; - end; - finally - FreeMemNil(PalRGB); - end; - end - else - begin - // Windows type - FPalSize := BI.ClrUsed; - if FPalSize = 0 then - FPalSize := 1 shl BI.BitCount; - Read(Handle, Palette, FPalSize * SizeOf(TColor32Rec)); - end; - for I := 0 to Info.PaletteEntries - 1 do - Palette[I].A := $FF; - end; - - // Seek to the beginning of image bits - Seek(Handle, StartPos + LongInt(BF.Offset), smFromBeginning); - - case BI.Compression of - BI_RGB: LoadRGB; - BI_RLE4: LoadRLE4; - BI_RLE8: LoadRLE8; - BI_BITFIELDS: LoadRGB; - end; - - if BI.AlphaMask = 0 then - begin - // Alpha mask is not stored in file (V3) or not defined. - // Check alpha channels of loaded images if they might contain them. - if Format = ifA1R5G5B5 then - begin - // Check if there is alpha channel present in A1R5GB5 images, if it is not - // change format to X1R5G5B5 - if not Has16BitImageAlpha(Width * Height, Bits) then - Format := ifX1R5G5B5; - end - else if Format = ifA8R8G8B8 then - begin - // Check if there is alpha channel present in A8R8G8B8 images, if it is not - // change format to X8R8G8B8 - if not Has32BitImageAlpha(Width * Height, Bits) then - Format := ifX8R8G8B8; - end; - end; - - if BI.BitCount < 8 then - begin - // 1 and 4 bpp images are supported only for loading which is now - // so we now convert them to 8bpp (and unalign scanlines). - case BI.BitCount of - 1: Convert1To8(Data, Bits, Width, Height, AlignedWidthBytes, False); - 4: - begin - // RLE4 bitmaps are translated to 8bit during RLE decoding - if BI.Compression <> BI_RLE4 then - Convert4To8(Data, Bits, Width, Height, AlignedWidthBytes, False); - end; - end; - // Enlarge palette - ReallocMem(Palette, Info.PaletteEntries * SizeOf(TColor32Rec)); - end; - - Result := True; - finally - FreeMemNil(Data); - end; -end; - -function TBitmapFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - StartPos, EndPos, I, Pad, PadSize, WidthBytes: LongInt; - BF: TBitmapFileHeader; - BI: TBitmapInfoHeader; - Info: TImageFormatInfo; - ImageToSave: TImageData; - MustBeFreed: Boolean; - - procedure SaveRLE8; - const - BufferSize = 8 * 1024; - var - X, Y, I, SrcPos: LongInt; - DiffCount, SameCount: Byte; - Pixels: PByteArray; - Buffer: array[0..BufferSize - 1] of Byte; - BufferPos: LongInt; - - procedure WriteByte(ByteToWrite: Byte); - begin - if BufferPos = BufferSize then - begin - // Flush buffer if necessary - GetIO.Write(Handle, @Buffer, BufferPos); - BufferPos := 0; - end; - Buffer[BufferPos] := ByteToWrite; - Inc(BufferPos); - end; - - begin - BufferPos := 0; - with GetIO, ImageToSave do - begin - for Y := Height - 1 downto 0 do - begin - X := 0; - SrcPos := 0; - Pixels := @PByteArray(Bits)[Y * Width]; - - while X < Width do - begin - SameCount := 1; - DiffCount := 0; - // Determine run length - while X + SameCount < Width do - begin - // If we reach max run length or byte with different value - // we end this run - if (SameCount = 255) or (Pixels[SrcPos + SameCount] <> Pixels[SrcPos]) then - Break; - Inc(SameCount); - end; - - if SameCount = 1 then - begin - // If there are not some bytes with the same value we - // compute how many different bytes are there - while X + DiffCount < Width do - begin - // Stop diff byte counting if there two bytes with the same value - // or DiffCount is too big - if (DiffCount = 255) or (Pixels[SrcPos + DiffCount + 1] = - Pixels[SrcPos + DiffCount]) then - Break; - Inc(DiffCount); - end; - end; - - // Now store absolute data (direct copy image->file) or - // store RLE code only (number of repeats + byte to be repeated) - if DiffCount > 2 then - begin - // Save 'Absolute Data' (0 + number of bytes) but only - // if number is >2 because (0+1) and (0+2) are other special commands - WriteByte(0); - WriteByte(DiffCount); - // Write absolute data to buffer - for I := 0 to DiffCount - 1 do - WriteByte(Pixels[SrcPos + I]); - Inc(X, DiffCount); - Inc(SrcPos, DiffCount); - // Odd number of bytes must be padded - if (DiffCount mod 2) = 1 then - WriteByte(0); - end - else - begin - // Save number of repeats and byte that should be repeated - WriteByte(SameCount); - WriteByte(Pixels[SrcPos]); - Inc(X, SameCount); - Inc(SrcPos, SameCount); - end; - end; - // Save 'End Of Line' command - WriteByte(0); - WriteByte(0); - end; - // Save 'End Of Bitmap' command - WriteByte(0); - WriteByte(1); - // Flush buffer - GetIO.Write(Handle, @Buffer, BufferPos); - end; - end; - -begin - Result := False; - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - Info := GetFormatInfo(Format); - StartPos := Tell(Handle); - FillChar(BF, SizeOf(BF), 0); - FillChar(BI, SizeOf(BI), 0); - // Other fields will be filled later - we don't know all values now - BF.ID := BMMagic; - Write(Handle, @BF, SizeOf(BF)); - if Info.HasAlphaChannel and (Info.BytesPerPixel = 2){V4 temp hack} then - // Save images with alpha in V4 format - BI.Size := V4InfoHeaderSize - else - // Save images without alpha in V3 format - for better compatibility - BI.Size := V3InfoHeaderSize; - BI.Width := Width; - BI.Height := Height; - BI.Planes := 1; - BI.BitCount := Info.BytesPerPixel * 8; - BI.XPelsPerMeter := 2835; // 72 dpi - BI.YPelsPerMeter := 2835; // 72 dpi - // Set compression - if (Info.BytesPerPixel = 1) and FUseRLE then - BI.Compression := BI_RLE8 - else if (Info.HasAlphaChannel or - ((BI.BitCount = 16) and (Format <> ifX1R5G5B5))) and (Info.BytesPerPixel = 2){V4 temp hack} then - BI.Compression := BI_BITFIELDS - else - BI.Compression := BI_RGB; - // Write header (first time) - Write(Handle, @BI, BI.Size); - - // Write mask info - if BI.Compression = BI_BITFIELDS then - begin - if BI.BitCount = 16 then - with Info.PixelFormat^ do - begin - BI.RedMask := RBitMask; - BI.GreenMask := GBitMask; - BI.BlueMask := BBitMask; - BI.AlphaMask := ABitMask; - end - else - begin - // Set masks for A8R8G8B8 - BI.RedMask := $00FF0000; - BI.GreenMask := $0000FF00; - BI.BlueMask := $000000FF; - BI.AlphaMask := $FF000000; - end; - // If V3 header is used RGB masks must be written to file separately. - // V4 header has embedded masks (V4 is default for formats with alpha). - if BI.Size = V3InfoHeaderSize then - Write(Handle, @BI.RedMask, SizeOf(BI.RedMask) * 3); - end; - // Write palette - if Palette <> nil then - Write(Handle, Palette, Info.PaletteEntries * SizeOf(TColor32Rec)); - - BF.Offset := Tell(Handle) - StartPos; - - if BI.Compression <> BI_RLE8 then - begin - // Save uncompressed data, scanlines must be filled with pad bytes - // to be multiples of 4, save as bottom-up (Windows native) bitmap - Pad := 0; - WidthBytes := Width * Info.BytesPerPixel; - PadSize := ((Width * BI.BitCount + 31) div 32) * 4 - WidthBytes; - - for I := Height - 1 downto 0 do - begin - Write(Handle, @PByteArray(Bits)[I * WidthBytes], WidthBytes); - if PadSize > 0 then - Write(Handle, @Pad, PadSize); - end; - end - else - begin - // Save data with RLE8 compression - SaveRLE8; - end; - - EndPos := Tell(Handle); - Seek(Handle, StartPos, smFromBeginning); - // Rewrite header with new values - BF.Size := EndPos - StartPos; - BI.SizeImage := BF.Size - BF.Offset; - Write(Handle, @BF, SizeOf(BF)); - Write(Handle, @BI, BI.Size); - Seek(Handle, EndPos, smFromBeginning); - - Result := True; - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -procedure TBitmapFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsFloatingPoint then - // Convert FP image to RGB/ARGB according to presence of alpha channel - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8) - else if Info.HasGrayChannel or Info.IsIndexed then - // Convert all grayscale and indexed images to Index8 unless they have alpha - // (preserve it) - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifIndex8) - else if Info.HasAlphaChannel then - // Convert images with alpha channel to A8R8G8B8 - ConvFormat := ifA8R8G8B8 - else if Info.UsePixelFormat then - // Convert 16bit RGB images (no alpha) to X1R5G5B5 - ConvFormat := ifX1R5G5B5 - else - // Convert all other formats to R8G8B8 - ConvFormat := ifR8G8B8; - - ConvertImage(Image, ConvFormat); -end; - -function TBitmapFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Hdr: TBitmapFileHeader; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - ReadCount := Read(Handle, @Hdr, SizeOf(Hdr)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (Hdr.ID = BMMagic) and (ReadCount = SizeOf(Hdr)); - end; -end; - -initialization - RegisterImageFileFormat(TBitmapFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - Add option to choose to save V3 or V4 headers. - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - Fixed problem with indexed BMP loading - some pal entries - could end up with alpha=0. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Now saves bitmaps as bottom-up for better compatibility - (mainly Lazarus' TImage!). - - Fixed crash when loading bitmaps with headers larger than V4. - - Temp hacks to disable V4 headers for 32bit images (compatibility with - other soft). - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Removed temporary data allocation for image with aligned scanlines. - They are now directly written to output so memory requirements are - much lower now. - - Now uses and recognizes BITMAPINFOHEADERV4 when loading/saving. - Mainly for formats with alpha channels. - - Added ifR5G6B5 to supported formats, changed converting to supported - formats little bit. - - Rewritten SaveRLE8 nested procedure. Old code was long and - mysterious - new is short and much more readable. - - MakeCompatible method moved to base class, put ConvertToSupported here. - GetSupportedFormats removed, it is now set in constructor. - - Rewritten LoadRLE4 and LoadRLE8 nested procedures. - Should be less buggy an more readable (load inspired by Colosseum Builders' code). - - Made public properties for options registered to SetOption/GetOption - functions. - - Addded alpha check to 32b bitmap loading too (teh same as in 16b - bitmap loading). - - Moved Convert1To8 and Convert4To8 to ImagingFormats - - Changed extensions to filename masks. - - Changed SaveData, LoadData, and MakeCompatible methods according - to changes in base class in Imaging unit. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - fixed wrong const that caused A4R4G4B4 BMPs to load as A1R5G5B5 - - fixed the bug that caused 8bit RLE compressed bitmaps to load as - whole black - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - 16 bit images are usually without alpha but some has alpha - channel and there is no indication of it - so I have added - a check: if all pixels of image are with alpha = 0 image is treated - as X1R5G5B5 otherwise as A1R5G5B5 - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - when loading 1/4 bit images with dword aligned dimensions - there was ugly memory rewritting bug causing image corruption - -} - -end. - diff --git a/3rd/Imaging/Source/ImagingCanvases.pas b/3rd/Imaging/Source/ImagingCanvases.pas deleted file mode 100644 index 4f1776d7a..000000000 --- a/3rd/Imaging/Source/ImagingCanvases.pas +++ /dev/null @@ -1,2111 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains canvas classes for drawing and applying effects.} -unit ImagingCanvases; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Types, Classes, ImagingTypes, Imaging, ImagingClasses, - ImagingFormats, ImagingUtility; - -const - { Color constants in ifA8R8G8B8 format.} - pcClear = $00000000; - pcBlack = $FF000000; - pcWhite = $FFFFFFFF; - pcMaroon = $FF800000; - pcGreen = $FF008000; - pcOlive = $FF808000; - pcNavy = $FF000080; - pcPurple = $FF800080; - pcTeal = $FF008080; - pcGray = $FF808080; - pcSilver = $FFC0C0C0; - pcRed = $FFFF0000; - pcLime = $FF00FF00; - pcYellow = $FFFFFF00; - pcBlue = $FF0000FF; - pcFuchsia = $FFFF00FF; - pcAqua = $FF00FFFF; - pcLtGray = $FFC0C0C0; - pcDkGray = $FF808080; - - MaxPenWidth = 256; - -type - EImagingCanvasError = class(EImagingError); - EImagingCanvasBlendingError = class(EImagingError); - - { Fill mode used when drawing filled objects on canvas.} - TFillMode = ( - fmSolid, // Solid fill using current fill color - fmClear // No filling done - ); - - { Pen mode used when drawing lines, object outlines, and similar on canvas.} - TPenMode = ( - pmSolid, // Draws solid lines using current pen color. - pmClear // No drawing done - ); - - { Source and destination blending factors for drawing functions with blending. - Blending formula: SrcColor * SrcFactor + DestColor * DestFactor } - TBlendingFactor = ( - bfIgnore, // Don't care - bfZero, // For Src and Dest, Factor = (0, 0, 0, 0) - bfOne, // For Src and Dest, Factor = (1, 1, 1, 1) - bfSrcAlpha, // For Src and Dest, Factor = (Src.A, Src.A, Src.A, Src.A) - bfOneMinusSrcAlpha, // For Src and Dest, Factor = (1 - Src.A, 1 - Src.A, 1 - Src.A, 1 - Src.A) - bfDstAlpha, // For Src and Dest, Factor = (Dest.A, Dest.A, Dest.A, Dest.A) - bfOneMinusDstAlpha, // For Src and Dest, Factor = (1 - Dest.A, 1 - Dest.A, 1 - Dest.A, 1 - Dest.A) - bfSrcColor, // For Dest, Factor = (Src.R, Src.R, Src.B, Src.A) - bfOneMinusSrcColor, // For Dest, Factor = (1 - Src.R, 1 - Src.G, 1 - Src.B, 1 - Src.A) - bfDstColor, // For Src, Factor = (Dest.R, Dest.G, Dest.B, Dest.A) - bfOneMinusDstColor // For Src, Factor = (1 - Dest.R, 1 - Dest.G, 1 - Dest.B, 1 - Dest.A) - ); - - { Procedure for custom pixel write modes with blending.} - TPixelWriteProc = procedure(const SrcPix: TColorFPRec; DestPtr: PByte; - DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); - - { Represents 3x3 convolution filter kernel.} - TConvolutionFilter3x3 = record - Kernel: array[0..2, 0..2] of LongInt; - Divisor: LongInt; - Bias: Single; - end; - - { Represents 5x5 convolution filter kernel.} - TConvolutionFilter5x5 = record - Kernel: array[0..4, 0..4] of LongInt; - Divisor: LongInt; - Bias: Single; - end; - - TPointTransformFunction = function(const Pixel: TColorFPRec; - Param1, Param2, Param3: Single): TColorFPRec; - - TDynFPPixelArray = array of TColorFPRec; - - THistogramArray = array[Byte] of Integer; - - TSelectPixelFunction = function(var Pixels: TDynFPPixelArray): TColorFPRec; - - { Base canvas class for drawing objects, applying effects, and other. - Constructor takes TBaseImage (or pointer to TImageData). Source image - bits are not copied but referenced so all canvas functions affect - source image and vice versa. When you change format or resolution of - source image you must call UpdateCanvasState method (so canvas could - recompute some data size related stuff). - - TImagingCanvas works for all image data formats except special ones - (compressed). Because of this its methods are quite slow (they usually work - with colors in ifA32R32G32B32F format). If you want fast drawing you - can use one of fast canvas clases. These descendants of TImagingCanvas - work only for few select formats (or only one) but they are optimized thus - much faster. - } - TImagingCanvas = class(TObject) - private - FDataSizeOnUpdate: LongInt; - FLineRecursion: Boolean; - function GetPixel32(X, Y: LongInt): TColor32; virtual; - function GetPixelFP(X, Y: LongInt): TColorFPRec; virtual; - function GetValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetPixel32(X, Y: LongInt; const Value: TColor32); virtual; - procedure SetPixelFP(X, Y: LongInt; const Value: TColorFPRec); virtual; - procedure SetPenColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetPenColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetPenWidth(const Value: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetFillColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetFillColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetClipRect(const Value: TRect); - procedure CheckBeforeBlending(SrcFactor, DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas); - protected - FPData: PImageData; - FClipRect: TRect; - FPenColorFP: TColorFPRec; - FPenColor32: TColor32; - FPenMode: TPenMode; - FPenWidth: LongInt; - FFillColorFP: TColorFPRec; - FFillColor32: TColor32; - FFillMode: TFillMode; - FNativeColor: TColorFPRec; - FFormatInfo: TImageFormatInfo; - - { Returns pointer to pixel at given position.} - function GetPixelPointer(X, Y: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} - { Translates given FP color to native format of canvas and stores it - in FNativeColor field (its bit copy) or user pointer (in overloaded method).} - procedure TranslateFPToNative(const Color: TColorFPRec); overload; {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure TranslateFPToNative(const Color: TColorFPRec; Native: Pointer); overload; {$IFDEF USE_INLINE}inline;{$ENDIF} - { Clipping function used by horizontal and vertical line drawing functions.} - function ClipAxisParallelLine(var A1, A2, B: LongInt; - AStart, AStop, BStart, BStop: LongInt): Boolean; - { Internal horizontal line drawer used mainly for filling inside of objects - like ellipses and circles.} - procedure HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; Bpp: LongInt); virtual; - procedure CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; Bpp: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure DrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas; - DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc); - procedure StretchDrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas; - const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor; - Filter: TResizeFilter; PixelWriteProc: TPixelWriteProc); - public - constructor CreateForData(ImageDataPointer: PImageData); - constructor CreateForImage(Image: TBaseImage); - destructor Destroy; override; - - { Call this method when you change size or format of image this canvas - operates on (like calling ResizeImage, ConvertImage, or changing Format - property of TBaseImage descendants).} - procedure UpdateCanvasState; virtual; - { Resets clipping rectangle to Rect(0, 0, ImageWidth, ImageHeight).} - procedure ResetClipRect; - - { Clears entire canvas with current fill color (ignores clipping rectangle - and always uses fmSolid fill mode).} - procedure Clear; - - { Draws horizontal line with current pen settings.} - procedure HorzLine(X1, X2, Y: LongInt); virtual; - { Draws vertical line with current pen settings.} - procedure VertLine(X, Y1, Y2: LongInt); virtual; - { Draws line from [X1, Y1] to [X2, Y2] with current pen settings.} - procedure Line(X1, Y1, X2, Y2: LongInt); virtual; - { Draws a rectangle using current pen settings.} - procedure FrameRect(const Rect: TRect); - { Fills given rectangle with current fill settings.} - procedure FillRect(const Rect: TRect); virtual; - { Fills given rectangle with current fill settings and pixel blending.} - procedure FillRectBlend(const Rect: TRect; SrcFactor, DestFactor: TBlendingFactor); - { Draws rectangle which is outlined by using the current pen settings and - filled by using the current fill settings.} - procedure Rectangle(const Rect: TRect); - { Draws ellipse which is outlined by using the current pen settings and - filled by using the current fill settings. Rect specifies bounding rectangle - of ellipse to be drawn.} - procedure Ellipse(const Rect: TRect); - { Fills area of canvas with current fill color starting at point [X, Y] and - coloring its neighbors. Default flood fill mode changes color of all - neighbors with the same color as pixel [X, Y]. With BoundaryFillMode - set to True neighbors are recolored regardless of their old color, - but area which will be recolored has boundary (specified by current pen color).} - procedure FloodFill(X, Y: Integer; BoundaryFillMode: Boolean = False); - - { Draws contents of this canvas onto another canvas with pixel blending. - Blending factors are chosen using TBlendingFactor parameters. - Resulting destination pixel color is: - SrcColor * SrcFactor + DstColor * DstFactor} - procedure DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; - DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor); - { Draws contents of this canvas onto another one with typical alpha - blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)} - procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); virtual; - { Draws contents of this canvas onto another one using additive blending - (source and dest factors are bfOne).} - procedure DrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); - { Draws stretched and filtered contents of this canvas onto another canvas - with pixel blending. Blending factors are chosen using TBlendingFactor parameters. - Resulting destination pixel color is: - SrcColor * SrcFactor + DstColor * DstFactor} - procedure StretchDrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; - const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor; - Filter: TResizeFilter = rfBilinear); - { Draws contents of this canvas onto another one with typical alpha - blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)} - procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; - const DestRect: TRect; Filter: TResizeFilter = rfBilinear); virtual; - { Draws contents of this canvas onto another one using additive blending - (source and dest factors are bfOne).} - procedure StretchDrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; - const DestRect: TRect; Filter: TResizeFilter = rfBilinear); - - { Convolves canvas' image with given 3x3 filter kernel. You can use - predefined filter kernels or define your own.} - procedure ApplyConvolution3x3(const Filter: TConvolutionFilter3x3); - { Convolves canvas' image with given 5x5 filter kernel. You can use - predefined filter kernels or define your own.} - procedure ApplyConvolution5x5(const Filter: TConvolutionFilter5x5); - { Computes 2D convolution of canvas' image and given filter kernel. - Kernel is in row format and KernelSize must be odd number >= 3. Divisor - is normalizing value based on Kernel (usually sum of all kernel's cells). - The Bias number shifts each color value by a fixed amount (color values - are usually in range [0, 1] during processing). If ClampChannels - is True all output color values are clamped to [0, 1]. You can use - predefined filter kernels or define your own.} - procedure ApplyConvolution(Kernel: PLongInt; KernelSize, Divisor: LongInt; - Bias: Single = 0.0; ClampChannels: Boolean = True); virtual; - - { Applies custom non-linear filter. Filter size is diameter of pixel - neighborhood. Typical values are 3, 5, or 7. } - procedure ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction); - { Applies median non-linear filter with user defined pixel neighborhood. - Selects median pixel from the neighborhood as new pixel - (current implementation is quite slow).} - procedure ApplyMedianFilter(FilterSize: Integer); - { Applies min non-linear filter with user defined pixel neighborhood. - Selects min pixel from the neighborhood as new pixel.} - procedure ApplyMinFilter(FilterSize: Integer); - { Applies max non-linear filter with user defined pixel neighborhood. - Selects max pixel from the neighborhood as new pixel.} - procedure ApplyMaxFilter(FilterSize: Integer); - - { Transforms pixels one by one by given function. Pixel neighbors are - not taken into account. Param 1-3 are optional parameters - for transform function.} - procedure PointTransform(Transform: TPointTransformFunction; - Param1, Param2, Param3: Single); - { Modifies image contrast and brightness. Parameters should be - in range <-100; 100>.} - procedure ModifyContrastBrightness(Contrast, Brightness: Single); - { Gamma correction of individual color channels. Range is (0, +inf), - 1.0 means no change.} - procedure GammaCorection(Red, Green, Blue: Single); - { Inverts colors of all image pixels, makes negative image. Ignores alpha channel.} - procedure InvertColors; virtual; - { Simple single level thresholding with threshold level (in range [0, 1]) - for each color channel.} - procedure Threshold(Red, Green, Blue: Single); - { Adjusts the color levels of the image by scaling the - colors falling between specified white and black points to full [0, 1] range. - The black point specifies the darkest color in the image, white point - specifies the lightest color, and mid point is gamma aplied to image. - Black and white point must be in range [0, 1].} - procedure AdjustColorLevels(BlackPoint, WhitePoint: Single; MidPoint: Single = 1.0); - { Premultiplies color channel values by alpha. Needed for some platforms/APIs - to display images with alpha properly.} - procedure PremultiplyAlpha; - { Reverses PremultiplyAlpha operation.} - procedure UnPremultiplyAlpha; - - { Calculates image histogram for each channel and also gray values. Each - channel has 256 values available. Channel values of data formats with higher - precision are scaled and rounded. Example: Red[126] specifies number of pixels - in image with red channel = 126.} - procedure GetHistogram(out Red, Green, Blue, Alpha, Gray: THistogramArray); - { Fills image channel with given value leaving other channels intact. - Use ChannelAlpha, ChannelRed, etc. constants from ImagingTypes as - channel identifier.} - procedure FillChannel(ChannelId: Integer; NewChannelValue: Byte); overload; - { Fills image channel with given value leaving other channels intact. - Use ChannelAlpha, ChannelRed, etc. constants from ImagingTypes as - channel identifier.} - procedure FillChannelFP(ChannelId: Integer; NewChannelValue: Single); overload; - - { Color used when drawing lines, frames, and outlines of objects.} - property PenColor32: TColor32 read FPenColor32 write SetPenColor32; - { Color used when drawing lines, frames, and outlines of objects.} - property PenColorFP: TColorFPRec read FPenColorFP write SetPenColorFP; - { Pen mode used when drawing lines, object outlines, and similar on canvas.} - property PenMode: TPenMode read FPenMode write FPenMode; - { Width with which objects like lines, frames, etc. (everything which uses - PenColor) are drawn.} - property PenWidth: LongInt read FPenWidth write SetPenWidth; - { Color used for filling when drawing various objects.} - property FillColor32: TColor32 read FFillColor32 write SetFillColor32; - { Color used for filling when drawing various objects.} - property FillColorFP: TColorFPRec read FFillColorFP write SetFillColorFP; - { Fill mode used when drawing filled objects on canvas.} - property FillMode: TFillMode read FFillMode write FFillMode; - { Specifies the current color of the pixels of canvas. Native pixel is - read from canvas and then translated to 32bit ARGB. Reverse operation - is made when setting pixel color.} - property Pixels32[X, Y: LongInt]: TColor32 read GetPixel32 write SetPixel32; - { Specifies the current color of the pixels of canvas. Native pixel is - read from canvas and then translated to FP ARGB. Reverse operation - is made when setting pixel color.} - property PixelsFP[X, Y: LongInt]: TColorFPRec read GetPixelFP write SetPixelFP; - { Clipping rectangle of this canvas. No pixels outside this rectangle are - altered by canvas methods if Clipping property is True. Clip rect gets - reseted when UpdateCanvasState is called.} - property ClipRect: TRect read FClipRect write SetClipRect; - { Extended format information.} - property FormatInfo: TImageFormatInfo read FFormatInfo; - { Indicates that this canvas is in valid state. If False canvas oprations - may crash.} - property Valid: Boolean read GetValid; - - { Returns all formats supported by this canvas class.} - class function GetSupportedFormats: TImageFormats; virtual; - end; - - TImagingCanvasClass = class of TImagingCanvas; - - TScanlineArray = array[0..MaxInt div SizeOf(Pointer) - 1] of PColor32RecArray; - PScanlineArray = ^TScanlineArray; - - { Fast canvas class for ifA8R8G8B8 format images.} - TFastARGB32Canvas = class(TImagingCanvas) - protected - FScanlines: PScanlineArray; - procedure AlphaBlendPixels(SrcPix, DestPix: PColor32Rec); {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetPixel32(X, Y: LongInt): TColor32; override; - procedure SetPixel32(X, Y: LongInt; const Value: TColor32); override; - public - destructor Destroy; override; - - procedure UpdateCanvasState; override; - - procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); override; - procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; - const DestRect: TRect; Filter: TResizeFilter = rfBilinear); override; - procedure InvertColors; override; - - property Scanlines: PScanlineArray read FScanlines; - - class function GetSupportedFormats: TImageFormats; override; - end; - -const - { Kernel for 3x3 average smoothing filter.} - FilterAverage3x3: TConvolutionFilter3x3 = ( - Kernel: ((1, 1, 1), - (1, 1, 1), - (1, 1, 1)); - Divisor: 9); - - { Kernel for 5x5 average smoothing filter.} - FilterAverage5x5: TConvolutionFilter5x5 = ( - Kernel: ((1, 1, 1, 1, 1), - (1, 1, 1, 1, 1), - (1, 1, 1, 1, 1), - (1, 1, 1, 1, 1), - (1, 1, 1, 1, 1)); - Divisor: 25); - - { Kernel for 3x3 Gaussian smoothing filter.} - FilterGaussian3x3: TConvolutionFilter3x3 = ( - Kernel: ((1, 2, 1), - (2, 4, 2), - (1, 2, 1)); - Divisor: 16); - - { Kernel for 5x5 Gaussian smoothing filter.} - FilterGaussian5x5: TConvolutionFilter5x5 = ( - Kernel: ((1, 4, 6, 4, 1), - (4, 16, 24, 16, 4), - (6, 24, 36, 24, 6), - (4, 16, 24, 16, 4), - (1, 4, 6, 4, 1)); - Divisor: 256); - - { Kernel for 3x3 Sobel horizontal edge detection filter (1st derivative approximation).} - FilterSobelHorz3x3: TConvolutionFilter3x3 = ( - Kernel: (( 1, 2, 1), - ( 0, 0, 0), - (-1, -2, -1)); - Divisor: 1); - - { Kernel for 3x3 Sobel vertical edge detection filter (1st derivative approximation).} - FilterSobelVert3x3: TConvolutionFilter3x3 = ( - Kernel: ((-1, 0, 1), - (-2, 0, 2), - (-1, 0, 1)); - Divisor: 1); - - { Kernel for 3x3 Prewitt horizontal edge detection filter.} - FilterPrewittHorz3x3: TConvolutionFilter3x3 = ( - Kernel: (( 1, 1, 1), - ( 0, 0, 0), - (-1, -1, -1)); - Divisor: 1); - - { Kernel for 3x3 Prewitt vertical edge detection filter.} - FilterPrewittVert3x3: TConvolutionFilter3x3 = ( - Kernel: ((-1, 0, 1), - (-1, 0, 1), - (-1, 0, 1)); - Divisor: 1); - - { Kernel for 3x3 Kirsh horizontal edge detection filter.} - FilterKirshHorz3x3: TConvolutionFilter3x3 = ( - Kernel: (( 5, 5, 5), - (-3, 0, -3), - (-3, -3, -3)); - Divisor: 1); - - { Kernel for 3x3 Kirsh vertical edge detection filter.} - FilterKirshVert3x3: TConvolutionFilter3x3 = ( - Kernel: ((5, -3, -3), - (5, 0, -3), - (5, -3, -3)); - Divisor: 1); - - { Kernel for 3x3 Laplace omni-directional edge detection filter - (2nd derivative approximation).} - FilterLaplace3x3: TConvolutionFilter3x3 = ( - Kernel: ((-1, -1, -1), - (-1, 8, -1), - (-1, -1, -1)); - Divisor: 1); - - { Kernel for 5x5 Laplace omni-directional edge detection filter - (2nd derivative approximation).} - FilterLaplace5x5: TConvolutionFilter5x5 = ( - Kernel: ((-1, -1, -1, -1, -1), - (-1, -1, -1, -1, -1), - (-1, -1, 24, -1, -1), - (-1, -1, -1, -1, -1), - (-1, -1, -1, -1, -1)); - Divisor: 1); - - { Kernel for 3x3 spharpening filter (Laplacian + original color).} - FilterSharpen3x3: TConvolutionFilter3x3 = ( - Kernel: ((-1, -1, -1), - (-1, 9, -1), - (-1, -1, -1)); - Divisor: 1); - - { Kernel for 5x5 spharpening filter (Laplacian + original color).} - FilterSharpen5x5: TConvolutionFilter5x5 = ( - Kernel: ((-1, -1, -1, -1, -1), - (-1, -1, -1, -1, -1), - (-1, -1, 25, -1, -1), - (-1, -1, -1, -1, -1), - (-1, -1, -1, -1, -1)); - Divisor: 1); - - { Kernel for 5x5 glow filter.} - FilterGlow5x5: TConvolutionFilter5x5 = ( - Kernel: (( 1, 2, 2, 2, 1), - ( 2, 0, 0, 0, 2), - ( 2, 0, -20, 0, 2), - ( 2, 0, 0, 0, 2), - ( 1, 2, 2, 2, 1)); - Divisor: 8); - - { Kernel for 3x3 edge enhancement filter.} - FilterEdgeEnhance3x3: TConvolutionFilter3x3 = ( - Kernel: ((-1, -2, -1), - (-2, 16, -2), - (-1, -2, -1)); - Divisor: 4); - - { Kernel for 3x3 contour enhancement filter.} - FilterTraceControur3x3: TConvolutionFilter3x3 = ( - Kernel: ((-6, -6, -2), - (-1, 32, -1), - (-6, -2, -6)); - Divisor: 4; - Bias: 240/255); - - { Kernel for filter that negates all images pixels.} - FilterNegative3x3: TConvolutionFilter3x3 = ( - Kernel: ((0, 0, 0), - (0, -1, 0), - (0, 0, 0)); - Divisor: 1; - Bias: 1); - - { Kernel for 3x3 horz/vert embossing filter.} - FilterEmboss3x3: TConvolutionFilter3x3 = ( - Kernel: ((2, 0, 0), - (0, -1, 0), - (0, 0, -1)); - Divisor: 1; - Bias: 0.5); - - -{ You can register your own canvas class. List of registered canvases is used - by FindBestCanvasForImage functions to find best canvas for given image. - If two different canvases which support the same image data format are - registered then the one that was registered later is returned (so you can - override builtin Imaging canvases).} -procedure RegisterCanvas(CanvasClass: TImagingCanvasClass); -{ Returns best canvas for given TImageFormat.} -function FindBestCanvasForImage(ImageFormat: TImageFormat): TImagingCanvasClass; overload; -{ Returns best canvas for given TImageData.} -function FindBestCanvasForImage(const ImageData: TImageData): TImagingCanvasClass; overload; -{ Returns best canvas for given TBaseImage.} -function FindBestCanvasForImage(Image: TBaseImage): TImagingCanvasClass; overload; - -implementation - -resourcestring - SConstructorInvalidPointer = 'Invalid pointer (%p) to TImageData passed to TImagingCanvas constructor.'; - SConstructorInvalidImage = 'Invalid image data passed to TImagingCanvas constructor (%s).'; - SConstructorUnsupportedFormat = 'Image passed to TImagingCanvas constructor is in unsupported format (%s)'; - -var - // list with all registered TImagingCanvas classes - CanvasClasses: TList = nil; - -procedure RegisterCanvas(CanvasClass: TImagingCanvasClass); -begin - Assert(CanvasClass <> nil); - if CanvasClasses = nil then - CanvasClasses := TList.Create; - if CanvasClasses.IndexOf(CanvasClass) < 0 then - CanvasClasses.Add(CanvasClass); -end; - -function FindBestCanvasForImage(ImageFormat: TImageFormat): TImagingCanvasClass; overload; -var - I: LongInt; -begin - for I := CanvasClasses.Count - 1 downto 0 do - begin - if ImageFormat in TImagingCanvasClass(CanvasClasses[I]).GetSupportedFormats then - begin - Result := TImagingCanvasClass(CanvasClasses[I]); - Exit; - end; - end; - Result := TImagingCanvas; -end; - -function FindBestCanvasForImage(const ImageData: TImageData): TImagingCanvasClass; -begin - Result := FindBestCanvasForImage(ImageData.Format); -end; - -function FindBestCanvasForImage(Image: TBaseImage): TImagingCanvasClass; -begin - Result := FindBestCanvasForImage(Image.Format); -end; - -{ Canvas helper functions } - -procedure PixelBlendProc(const SrcPix: TColorFPRec; DestPtr: PByte; - DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); -var - DestPix, FSrc, FDst: TColorFPRec; -begin - // Get set pixel color - DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil); - // Determine current blending factors - case SrcFactor of - bfZero: FSrc := ColorFP(0, 0, 0, 0); - bfOne: FSrc := ColorFP(1, 1, 1, 1); - bfSrcAlpha: FSrc := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A); - bfOneMinusSrcAlpha: FSrc := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A); - bfDstAlpha: FSrc := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A); - bfOneMinusDstAlpha: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A); - bfDstColor: FSrc := ColorFP(DestPix.A, DestPix.R, DestPix.G, DestPix.B); - bfOneMinusDstColor: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.R, 1 - DestPix.G, 1 - DestPix.B); - end; - case DestFactor of - bfZero: FDst := ColorFP(0, 0, 0, 0); - bfOne: FDst := ColorFP(1, 1, 1, 1); - bfSrcAlpha: FDst := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A); - bfOneMinusSrcAlpha: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A); - bfDstAlpha: FDst := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A); - bfOneMinusDstAlpha: FDst := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A); - bfSrcColor: FDst := ColorFP(SrcPix.A, SrcPix.R, SrcPix.G, SrcPix.B); - bfOneMinusSrcColor: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.R, 1 - SrcPix.G, 1 - SrcPix.B); - end; - // Compute blending formula - DestPix.R := SrcPix.R * FSrc.R + DestPix.R * FDst.R; - DestPix.G := SrcPix.G * FSrc.G + DestPix.G * FDst.G; - DestPix.B := SrcPix.B * FSrc.B + DestPix.B * FDst.B; - DestPix.A := SrcPix.A * FSrc.A + DestPix.A * FDst.A; - // Write blended pixel - DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix); -end; - -procedure PixelAlphaProc(const SrcPix: TColorFPRec; DestPtr: PByte; - DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); -var - DestPix: TColorFPRec; - SrcAlpha, DestAlpha: Single; -begin - DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil); - // Blend the two pixels (Src 'over' Dest alpha composition operation) - DestPix.A := SrcPix.A + DestPix.A - SrcPix.A * DestPix.A; - if DestPix.A = 0 then - SrcAlpha := 0 - else - SrcAlpha := SrcPix.A / DestPix.A; - DestAlpha := 1.0 - SrcAlpha; - DestPix.R := SrcPix.R * SrcAlpha + DestPix.R * DestAlpha; - DestPix.G := SrcPix.G * SrcAlpha + DestPix.G * DestAlpha; - DestPix.B := SrcPix.B * SrcAlpha + DestPix.B * DestAlpha; - // Write blended pixel - DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix); -end; - -procedure PixelAddProc(const SrcPix: TColorFPRec; DestPtr: PByte; - DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); -var - DestPix: TColorFPRec; -begin - // Just add Src and Dest - DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil); - DestPix.R := SrcPix.R + DestPix.R; - DestPix.G := SrcPix.G + DestPix.G; - DestPix.B := SrcPix.B + DestPix.B; - DestPix.A := SrcPix.A + DestPix.A; - DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix); -end; - -function CompareColors(const C1, C2: TColorFPRec): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} -begin - Result := (C1.R * GrayConv.R + C1.G * GrayConv.G + C1.B * GrayConv.B) - - (C2.R * GrayConv.R + C2.G * GrayConv.G + C2.B * GrayConv.B); -end; - -function MedianSelect(var Pixels: TDynFPPixelArray): TColorFPRec; - - procedure QuickSort(L, R: Integer); - var - I, J: Integer; - P, Temp: TColorFPRec; - begin - repeat - I := L; - J := R; - P := Pixels[(L + R) shr 1]; - repeat - while CompareColors(Pixels[I], P) < 0 do Inc(I); - while CompareColors(Pixels[J], P) > 0 do Dec(J); - if I <= J then - begin - Temp := Pixels[I]; - Pixels[I] := Pixels[J]; - Pixels[J] := Temp; - Inc(I); - Dec(J); - end; - until I > J; - if L < J then - QuickSort(L, J); - L := I; - until I >= R; - end; - -begin - // First sort pixels - QuickSort(0, High(Pixels)); - // Select middle pixel - Result := Pixels[Length(Pixels) div 2]; -end; - -function MinSelect(var Pixels: TDynFPPixelArray): TColorFPRec; -var - I: Integer; -begin - Result := Pixels[0]; - for I := 1 to High(Pixels) do - begin - if CompareColors(Pixels[I], Result) < 0 then - Result := Pixels[I]; - end; -end; - -function MaxSelect(var Pixels: TDynFPPixelArray): TColorFPRec; -var - I: Integer; -begin - Result := Pixels[0]; - for I := 1 to High(Pixels) do - begin - if CompareColors(Pixels[I], Result) > 0 then - Result := Pixels[I]; - end; -end; - -function TransformContrastBrightness(const Pixel: TColorFPRec; C, B, P3: Single): TColorFPRec; -begin - Result.A := Pixel.A; - Result.R := Pixel.R * C + B; - Result.G := Pixel.G * C + B; - Result.B := Pixel.B * C + B; -end; - -function TransformGamma(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec; -begin - Result.A := Pixel.A; - Result.R := Power(Pixel.R, 1.0 / R); - Result.G := Power(Pixel.G, 1.0 / G); - Result.B := Power(Pixel.B, 1.0 / B); -end; - -function TransformInvert(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec; -begin - Result.A := Pixel.A; - Result.R := 1.0 - Pixel.R; - Result.G := 1.0 - Pixel.G; - Result.B := 1.0 - Pixel.B; -end; - -function TransformThreshold(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec; -begin - Result.A := Pixel.A; - Result.R := IffFloat(Pixel.R >= R, 1.0, 0.0); - Result.G := IffFloat(Pixel.G >= G, 1.0, 0.0); - Result.B := IffFloat(Pixel.B >= B, 1.0, 0.0); -end; - -function TransformLevels(const Pixel: TColorFPRec; BlackPoint, WhitePoint, Exp: Single): TColorFPRec; -begin - Result.A := Pixel.A; - if Pixel.R > BlackPoint then - Result.R := Power((Pixel.R - BlackPoint) / (WhitePoint - BlackPoint), Exp) - else - Result.R := 0.0; - if Pixel.G > BlackPoint then - Result.G := Power((Pixel.G - BlackPoint) / (WhitePoint - BlackPoint), Exp) - else - Result.G := 0.0; - if Pixel.B > BlackPoint then - Result.B := Power((Pixel.B - BlackPoint) / (WhitePoint - BlackPoint), Exp) - else - Result.B := 0.0; -end; - -function TransformPremultiplyAlpha(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec; -begin - Result.A := Pixel.A; - Result.R := Result.R * Pixel.A; - Result.G := Result.G * Pixel.A; - Result.B := Result.B * Pixel.A; -end; - -function TransformUnPremultiplyAlpha(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec; -begin - Result.A := Pixel.A; - if Pixel.A <> 0.0 then - begin - Result.R := Result.R / Pixel.A; - Result.G := Result.G / Pixel.A; - Result.B := Result.B / Pixel.A; - end - else - begin - Result.R := 0; - Result.G := 0; - Result.B := 0; - end; -end; - - -{ TImagingCanvas class implementation } - -constructor TImagingCanvas.CreateForData(ImageDataPointer: PImageData); -begin - if ImageDataPointer = nil then - raise EImagingCanvasError.CreateFmt(SConstructorInvalidPointer, [ImageDataPointer]); - - if not TestImage(ImageDataPointer^) then - raise EImagingCanvasError.CreateFmt(SConstructorInvalidImage, [Imaging.ImageToStr(ImageDataPointer^)]); - - if not (ImageDataPointer.Format in GetSupportedFormats) then - raise EImagingCanvasError.CreateFmt(SConstructorUnsupportedFormat, [Imaging.ImageToStr(ImageDataPointer^)]); - - FPData := ImageDataPointer; - FPenWidth := 1; - SetPenColor32(pcWhite); - SetFillColor32(pcBlack); - FFillMode := fmSolid; - - UpdateCanvasState; -end; - -constructor TImagingCanvas.CreateForImage(Image: TBaseImage); -begin - CreateForData(Image.ImageDataPointer); -end; - -destructor TImagingCanvas.Destroy; -begin - inherited Destroy; -end; - -function TImagingCanvas.GetPixel32(X, Y: LongInt): TColor32; -begin - Result := Imaging.GetPixel32(FPData^, X, Y).Color; -end; - -function TImagingCanvas.GetPixelFP(X, Y: LongInt): TColorFPRec; -begin - Result := Imaging.GetPixelFP(FPData^, X, Y); -end; - -function TImagingCanvas.GetValid: Boolean; -begin - Result := (FPData <> nil) and (FDataSizeOnUpdate = FPData.Size); -end; - -procedure TImagingCanvas.SetPixel32(X, Y: LongInt; const Value: TColor32); -begin - if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and - (X < FClipRect.Right) and (Y < FClipRect.Bottom) then - begin - Imaging.SetPixel32(FPData^, X, Y, TColor32Rec(Value)); - end; -end; - -procedure TImagingCanvas.SetPixelFP(X, Y: LongInt; const Value: TColorFPRec); -begin - if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and - (X < FClipRect.Right) and (Y < FClipRect.Bottom) then - begin - Imaging.SetPixelFP(FPData^, X, Y, TColorFPRec(Value)); - end; -end; - -procedure TImagingCanvas.SetPenColor32(const Value: TColor32); -begin - FPenColor32 := Value; - TranslatePixel(@FPenColor32, @FPenColorFP, ifA8R8G8B8, ifA32R32G32B32F, nil, nil); -end; - -procedure TImagingCanvas.SetPenColorFP(const Value: TColorFPRec); -begin - FPenColorFP := Value; - TranslatePixel(@FPenColorFP, @FPenColor32, ifA32R32G32B32F, ifA8R8G8B8, nil, nil); -end; - -procedure TImagingCanvas.SetPenWidth(const Value: LongInt); -begin - FPenWidth := ClampInt(Value, 0, MaxPenWidth); -end; - -procedure TImagingCanvas.SetFillColor32(const Value: TColor32); -begin - FFillColor32 := Value; - TranslatePixel(@FFillColor32, @FFillColorFP, ifA8R8G8B8, ifA32R32G32B32F, nil, nil); -end; - -procedure TImagingCanvas.SetFillColorFP(const Value: TColorFPRec); -begin - FFillColorFP := Value; - TranslatePixel(@FFillColorFP, @FFillColor32, ifA32R32G32B32F, ifA8R8G8B8, nil, nil); -end; - -procedure TImagingCanvas.SetClipRect(const Value: TRect); -begin - FClipRect := Value; - SwapMin(FClipRect.Left, FClipRect.Right); - SwapMin(FClipRect.Top, FClipRect.Bottom); - IntersectRect(FClipRect, FClipRect, Rect(0, 0, FPData.Width, FPData.Height)); -end; - -procedure TImagingCanvas.CheckBeforeBlending(SrcFactor, - DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas); -begin - if SrcFactor in [bfSrcColor, bfOneMinusSrcColor] then - raise EImagingCanvasBlendingError.Create('Invalid source blending factor. Check the documentation for TBlendingFactor.'); - if DestFactor in [bfDstColor, bfOneMinusDstColor] then - raise EImagingCanvasBlendingError.Create('Invalid destination blending factor. Check the documentation for TBlendingFactor.'); - if DestCanvas.FormatInfo.IsIndexed then - raise EImagingCanvasBlendingError.Create('Blending destination canvas cannot be in indexed mode.'); -end; - -function TImagingCanvas.GetPixelPointer(X, Y: LongInt): Pointer; -begin - Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * FFormatInfo.BytesPerPixel] -end; - -procedure TImagingCanvas.TranslateFPToNative(const Color: TColorFPRec); -begin - TranslateFPToNative(Color, @FNativeColor); -end; - -procedure TImagingCanvas.TranslateFPToNative(const Color: TColorFPRec; - Native: Pointer); -begin - ImagingFormats.TranslatePixel(@Color, Native, ifA32R32G32B32F, - FPData.Format, nil, FPData.Palette); -end; - -procedure TImagingCanvas.UpdateCanvasState; -begin - FDataSizeOnUpdate := FPData.Size; - ResetClipRect; - Imaging.GetImageFormatInfo(FPData.Format, FFormatInfo) -end; - -procedure TImagingCanvas.ResetClipRect; -begin - FClipRect := Rect(0, 0, FPData.Width, FPData.Height) -end; - -procedure TImagingCanvas.Clear; -begin - TranslateFPToNative(FFillColorFP); - Imaging.FillRect(FPData^, 0, 0, FPData.Width, FPData.Height, @FNativeColor); -end; - -function TImagingCanvas.ClipAxisParallelLine(var A1, A2, B: LongInt; - AStart, AStop, BStart, BStop: LongInt): Boolean; -begin - if (B >= BStart) and (B < BStop) then - begin - SwapMin(A1, A2); - if A1 < AStart then A1 := AStart; - if A2 >= AStop then A2 := AStop - 1; - Result := True; - end - else - Result := False; -end; - -procedure TImagingCanvas.HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; - Bpp: LongInt); -var - I, WidthBytes: LongInt; - PixelPtr: PByte; -begin - if (Y >= FClipRect.Top) and (Y < FClipRect.Bottom) then - begin - SwapMin(X1, X2); - X1 := Max(X1, FClipRect.Left); - X2 := Min(X2, FClipRect.Right); - PixelPtr := GetPixelPointer(X1, Y); - WidthBytes := (X2 - X1) * Bpp; - case Bpp of - 1: FillMemoryByte(PixelPtr, WidthBytes, PByte(Color)^); - 2: FillMemoryWord(PixelPtr, WidthBytes, PWord(Color)^); - 4: FillMemoryLongWord(PixelPtr, WidthBytes, PLongWord(Color)^); - else - for I := X1 to X2 do - begin - ImagingFormats.CopyPixel(Color, PixelPtr, Bpp); - Inc(PixelPtr, Bpp); - end; - end; - end; -end; - -procedure TImagingCanvas.CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; - Bpp: LongInt); -begin - if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and - (X < FClipRect.Right) and (Y < FClipRect.Bottom) then - begin - ImagingFormats.CopyPixel(Pixel, GetPixelPointer(X, Y), Bpp); - end; -end; - -procedure TImagingCanvas.HorzLine(X1, X2, Y: LongInt); -var - DstRect: TRect; -begin - if FPenMode = pmClear then Exit; - SwapMin(X1, X2); - if IntersectRect(DstRect, Rect(X1, Y - FPenWidth div 2, X2, - Y + FPenWidth div 2 + FPenWidth mod 2), FClipRect) then - begin - TranslateFPToNative(FPenColorFP); - Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, - DstRect.Bottom - DstRect.Top, @FNativeColor); - end; -end; - -procedure TImagingCanvas.VertLine(X, Y1, Y2: LongInt); -var - DstRect: TRect; -begin - if FPenMode = pmClear then Exit; - SwapMin(Y1, Y2); - if IntersectRect(DstRect, Rect(X - FPenWidth div 2, Y1, - X + FPenWidth div 2 + FPenWidth mod 2, Y2), FClipRect) then - begin - TranslateFPToNative(FPenColorFP); - Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, - DstRect.Bottom - DstRect.Top, @FNativeColor); - end; -end; - -procedure TImagingCanvas.Line(X1, Y1, X2, Y2: LongInt); -var - Steep: Boolean; - Error, YStep, DeltaX, DeltaY, X, Y, I, Bpp, W1, W2, Code1, Code2: LongInt; -begin - if FPenMode = pmClear then Exit; - - // If line is vertical or horizontal just call appropriate method - if X2 = X1 then - begin - VertLine(X1, Y1, Y2); - Exit; - end; - if Y2 = Y1 then - begin - HorzLine(X1, X2, Y1); - Exit; - end; - - // Determine if line is steep (angle with X-axis > 45 degrees) - Steep := Abs(Y2 - Y1) > Abs(X2 - X1); - - // If we need to draw thick line we just draw more 1 pixel lines around - // the one we already drawn. Setting FLineRecursion assures that we - // won't be doing recursions till the end of the world. - if (FPenWidth > 1) and not FLineRecursion then - begin - FLineRecursion := True; - W1 := FPenWidth div 2; - W2 := W1; - if FPenWidth mod 2 = 0 then - Dec(W1); - if Steep then - begin - // Add lines left/right - for I := 1 to W1 do - Line(X1, Y1 - I, X2, Y2 - I); - for I := 1 to W2 do - Line(X1, Y1 + I, X2, Y2 + I); - end - else - begin - // Add lines above/under - for I := 1 to W1 do - Line(X1 - I, Y1, X2 - I, Y2); - for I := 1 to W2 do - Line(X1 + I, Y1, X2 + I, Y2); - end; - FLineRecursion := False; - end; - - with FClipRect do - begin - // Use part of Cohen-Sutherland line clipping to determine if any part of line - // is in ClipRect - Code1 := Ord(X1 < Left) + Ord(X1 > Right) shl 1 + Ord(Y1 < Top) shl 2 + Ord(Y1 > Bottom) shl 3; - Code2 := Ord(X2 < Left) + Ord(X2 > Right) shl 1 + Ord(Y2 < Top) shl 2 + Ord(Y2 > Bottom) shl 3; - end; - - if (Code1 and Code2) = 0 then - begin - TranslateFPToNative(FPenColorFP); - Bpp := FFormatInfo.BytesPerPixel; - - // If line is steep swap X and Y coordinates so later we just have one loop - // of two (where only one is used according to steepness). - if Steep then - begin - SwapValues(X1, Y1); - SwapValues(X2, Y2); - end; - if X1 > X2 then - begin - SwapValues(X1, X2); - SwapValues(Y1, Y2); - end; - - DeltaX := X2 - X1; - DeltaY := Abs(Y2 - Y1); - YStep := Iff(Y2 > Y1, 1, -1); - Error := 0; - Y := Y1; - - // Draw line using Bresenham algorithm. No real line clipping here, - // just don't draw pixels outsize clip rect. - for X := X1 to X2 do - begin - if Steep then - CopyPixelInternal(Y, X, @FNativeColor, Bpp) - else - CopyPixelInternal(X, Y, @FNativeColor, Bpp); - Error := Error + DeltaY; - if Error * 2 >= DeltaX then - begin - Inc(Y, YStep); - Dec(Error, DeltaX); - end; - end; - end; -end; - -procedure TImagingCanvas.FrameRect(const Rect: TRect); -var - HalfPen, PenMod: LongInt; -begin - if FPenMode = pmClear then Exit; - HalfPen := FPenWidth div 2; - PenMod := FPenWidth mod 2; - HorzLine(Rect.Left - HalfPen, Rect.Right + HalfPen + PenMod - 1, Rect.Top); - HorzLine(Rect.Left - HalfPen, Rect.Right + HalfPen + PenMod - 1, Rect.Bottom - 1); - VertLine(Rect.Left, Rect.Top, Rect.Bottom); - VertLine(Rect.Right - 1, Rect.Top, Rect.Bottom); -end; - -procedure TImagingCanvas.FillRect(const Rect: TRect); -var - DstRect: TRect; -begin - if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then - begin - TranslateFPToNative(FFillColorFP); - Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, - DstRect.Bottom - DstRect.Top, @FNativeColor); - end; -end; - -procedure TImagingCanvas.FillRectBlend(const Rect: TRect; SrcFactor, - DestFactor: TBlendingFactor); -var - DstRect: TRect; - X, Y: Integer; - Line: PByte; -begin - if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then - begin - CheckBeforeBlending(SrcFactor, DestFactor, Self); - for Y := DstRect.Top to DstRect.Bottom - 1 do - begin - Line := @PByteArray(FPData.Bits)[(Y * FPData.Width + DstRect.Left) * FFormatInfo.BytesPerPixel]; - for X := DstRect.Left to DstRect.Right - 1 do - begin - PixelBlendProc(FFillColorFP, Line, @FFormatInfo, SrcFactor, DestFactor); - Inc(Line, FFormatInfo.BytesPerPixel); - end; - end; - end; -end; - -procedure TImagingCanvas.Rectangle(const Rect: TRect); -begin - FillRect(Rect); - FrameRect(Rect); -end; - -procedure TImagingCanvas.Ellipse(const Rect: TRect); -var - RadX, RadY, DeltaX, DeltaY, R, RX, RY: LongInt; - X1, X2, Y1, Y2, Bpp, OldY: LongInt; - Fill, Pen: TColorFPRec; -begin - // TODO: Use PenWidth - X1 := Rect.Left; - X2 := Rect.Right; - Y1 := Rect.Top; - Y2 := Rect.Bottom; - - TranslateFPToNative(FPenColorFP, @Pen); - TranslateFPToNative(FFillColorFP, @Fill); - Bpp := FFormatInfo.BytesPerPixel; - - SwapMin(X1, X2); - SwapMin(Y1, Y2); - - RadX := (X2 - X1) div 2; - RadY := (Y2 - Y1) div 2; - - Y1 := Y1 + RadY; - Y2 := Y1; - OldY := Y1; - - DeltaX := (RadX * RadX); - DeltaY := (RadY * RadY); - R := RadX * RadY * RadY; - RX := R; - RY := 0; - - if (FFillMode <> fmClear) then - HorzLineInternal(X1, X2, Y1, @Fill, Bpp); - CopyPixelInternal(X1, Y1, @Pen, Bpp); - CopyPixelInternal(X2, Y1, @Pen, Bpp); - - while RadX > 0 do - begin - if R > 0 then - begin - Inc(Y1); - Dec(Y2); - Inc(RY, DeltaX); - Dec(R, RY); - end; - if R <= 0 then - begin - Dec(RadX); - Inc(X1); - Dec(X2); - Dec(RX, DeltaY); - Inc(R, RX); - end; - - if (OldY <> Y1) and (FFillMode <> fmClear) then - begin - HorzLineInternal(X1, X2, Y1, @Fill, Bpp); - HorzLineInternal(X1, X2, Y2, @Fill, Bpp); - end; - OldY := Y1; - - CopyPixelInternal(X1, Y1, @Pen, Bpp); - CopyPixelInternal(X2, Y1, @Pen, Bpp); - CopyPixelInternal(X1, Y2, @Pen, Bpp); - CopyPixelInternal(X2, Y2, @Pen, Bpp); - end; -end; - -procedure TImagingCanvas.FloodFill(X, Y: Integer; BoundaryFillMode: Boolean); -var - Stack: array of TPoint; - StackPos, Y1: Integer; - OldColor: TColor32; - SpanLeft, SpanRight: Boolean; - - procedure Push(AX, AY: Integer); - begin - if StackPos < High(Stack) then - begin - Inc(StackPos); - Stack[StackPos].X := AX; - Stack[StackPos].Y := AY; - end - else - begin - SetLength(Stack, Length(Stack) + FPData.Width); - Push(AX, AY); - end; - end; - - function Pop(out AX, AY: Integer): Boolean; - begin - if StackPos > 0 then - begin - AX := Stack[StackPos].X; - AY := Stack[StackPos].Y; - Dec(StackPos); - Result := True; - end - else - Result := False; - end; - - function Compare(AX, AY: Integer): Boolean; - var - Color: TColor32; - begin - Color := GetPixel32(AX, AY); - if BoundaryFillMode then - Result := (Color <> FFillColor32) and (Color <> FPenColor32) - else - Result := Color = OldColor; - end; - -begin - // Scanline Floodfill Algorithm With Stack - // http://student.kuleuven.be/~m0216922/CG/floodfill.html - - if not PtInRect(FClipRect, Point(X, Y)) then Exit; - - SetLength(Stack, FPData.Width * 4); - StackPos := 0; - - OldColor := GetPixel32(X, Y); - - Push(X, Y); - - while Pop(X, Y) do - begin - Y1 := Y; - while (Y1 >= FClipRect.Top) and Compare(X, Y1) do - Dec(Y1); - - Inc(Y1); - SpanLeft := False; - SpanRight := False; - - while (Y1 < FClipRect.Bottom) and Compare(X, Y1) do - begin - SetPixel32(X, Y1, FFillColor32); - if not SpanLeft and (X > FClipRect.Left) and Compare(X - 1, Y1) then - begin - Push(X - 1, Y1); - SpanLeft := True; - end - else if SpanLeft and (X > FClipRect.Left) and not Compare(X - 1, Y1) then - SpanLeft := False - else if not SpanRight and (X < FClipRect.Right - 1) and Compare(X + 1, Y1)then - begin - Push(X + 1, Y1); - SpanRight := True; - end - else if SpanRight and (X < FClipRect.Right - 1) and not Compare(X + 1, Y1) then - SpanRight := False; - - Inc(Y1); - end; - end; -end; - -procedure TImagingCanvas.DrawInternal(const SrcRect: TRect; - DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor, - DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc); -var - X, Y, SrcX, SrcY, Width, Height, SrcBpp, DestBpp: Integer; - PSrc: TColorFPRec; - SrcPointer, DestPointer: PByte; -begin - CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas); - SrcX := SrcRect.Left; - SrcY := SrcRect.Top; - Width := SrcRect.Right - SrcRect.Left; - Height := SrcRect.Bottom - SrcRect.Top; - SrcBpp := FFormatInfo.BytesPerPixel; - DestBpp := DestCanvas.FFormatInfo.BytesPerPixel; - // Clip src and dst rects - ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY, - FPData.Width, FPData.Height, DestCanvas.ClipRect); - - for Y := 0 to Height - 1 do - begin - // Get src and dst scanlines - SrcPointer := @PByteArray(FPData.Bits)[((SrcY + Y) * FPData.Width + SrcX) * SrcBpp]; - DestPointer := @PByteArray(DestCanvas.FPData.Bits)[((DestY + Y) * DestCanvas.FPData.Width + DestX) * DestBpp]; - - for X := 0 to Width - 1 do - begin - PSrc := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, FPData.Palette); - // Call pixel writer procedure - combine source and dest pixels - PixelWriteProc(PSrc, DestPointer, @DestCanvas.FFormatInfo, SrcFactor, DestFactor); - // Increment pixel pointers - Inc(SrcPointer, SrcBpp); - Inc(DestPointer, DestBpp); - end; - end; -end; - -procedure TImagingCanvas.DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; - DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor); -begin - DrawInternal(SrcRect, DestCanvas, DestX, DestY, SrcFactor, DestFactor, PixelBlendProc); -end; - -procedure TImagingCanvas.DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; - DestX, DestY: Integer); -begin - DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAlphaProc); -end; - -procedure TImagingCanvas.DrawAdd(const SrcRect: TRect; - DestCanvas: TImagingCanvas; DestX, DestY: Integer); -begin - DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAddProc); -end; - -procedure TImagingCanvas.StretchDrawInternal(const SrcRect: TRect; - DestCanvas: TImagingCanvas; const DestRect: TRect; - SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter; - PixelWriteProc: TPixelWriteProc); -const - FilterMapping: array[TResizeFilter] of TSamplingFilter = - (sfNearest, sfLinear, DefaultCubicFilter, sfLanczos); -var - X, Y, I, J, SrcX, SrcY, SrcWidth, SrcHeight: Integer; - DestX, DestY, DestWidth, DestHeight, SrcBpp, DestBpp: Integer; - SrcPix: TColorFPRec; - MapX, MapY: TMappingTable; - XMinimum, XMaximum: Integer; - LineBuffer: array of TColorFPRec; - ClusterX, ClusterY: TCluster; - Weight, AccumA, AccumR, AccumG, AccumB: Single; - DestLine: PByte; - FilterFunction: TFilterFunction; - Radius: Single; -begin - CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas); - SrcX := SrcRect.Left; - SrcY := SrcRect.Top; - SrcWidth := SrcRect.Right - SrcRect.Left; - SrcHeight := SrcRect.Bottom - SrcRect.Top; - DestX := DestRect.Left; - DestY := DestRect.Top; - DestWidth := DestRect.Right - DestRect.Left; - DestHeight := DestRect.Bottom - DestRect.Top; - SrcBpp := FFormatInfo.BytesPerPixel; - DestBpp := DestCanvas.FFormatInfo.BytesPerPixel; - // Get actual resampling filter and radius - FilterFunction := SamplingFilterFunctions[FilterMapping[Filter]]; - Radius := SamplingFilterRadii[FilterMapping[Filter]]; - // Clip src and dst rects - ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight, - FPData.Width, FPData.Height, DestCanvas.ClipRect); - // Generate mapping tables - MapX := BuildMappingTable(DestX, DestX + DestWidth, SrcX, SrcX + SrcWidth, - FPData.Width, FilterFunction, Radius, False); - MapY := BuildMappingTable(DestY, DestY + DestHeight, SrcY, SrcY + SrcHeight, - FPData.Height, FilterFunction, Radius, False); - FindExtremes(MapX, XMinimum, XMaximum); - SetLength(LineBuffer, XMaximum - XMinimum + 1); - - for J := 0 to DestHeight - 1 do - begin - ClusterY := MapY[J]; - for X := XMinimum to XMaximum do - begin - AccumA := 0.0; - AccumR := 0.0; - AccumG := 0.0; - AccumB := 0.0; - for Y := 0 to Length(ClusterY) - 1 do - begin - Weight := ClusterY[Y].Weight; - SrcPix := FFormatInfo.GetPixelFP(@PByteArray(FPData.Bits)[(ClusterY[Y].Pos * FPData.Width + X) * SrcBpp], - @FFormatInfo, FPData.Palette); - AccumB := AccumB + SrcPix.B * Weight; - AccumG := AccumG + SrcPix.G * Weight; - AccumR := AccumR + SrcPix.R * Weight; - AccumA := AccumA + SrcPix.A * Weight; - end; - with LineBuffer[X - XMinimum] do - begin - A := AccumA; - R := AccumR; - G := AccumG; - B := AccumB; - end; - end; - - DestLine := @PByteArray(DestCanvas.FPData.Bits)[((J + DestY) * DestCanvas.FPData.Width + DestX) * DestBpp]; - - for I := 0 to DestWidth - 1 do - begin - ClusterX := MapX[I]; - AccumA := 0.0; - AccumR := 0.0; - AccumG := 0.0; - AccumB := 0.0; - for X := 0 to Length(ClusterX) - 1 do - begin - Weight := ClusterX[X].Weight; - with LineBuffer[ClusterX[X].Pos - XMinimum] do - begin - AccumB := AccumB + B * Weight; - AccumG := AccumG + G * Weight; - AccumR := AccumR + R * Weight; - AccumA := AccumA + A * Weight; - end; - end; - - SrcPix.A := AccumA; - SrcPix.R := AccumR; - SrcPix.G := AccumG; - SrcPix.B := AccumB; - - // Write resulting blended pixel - PixelWriteProc(SrcPix, DestLine, @DestCanvas.FFormatInfo, SrcFactor, DestFactor); - Inc(DestLine, DestBpp); - end; - end; -end; - -procedure TImagingCanvas.StretchDrawBlend(const SrcRect: TRect; - DestCanvas: TImagingCanvas; const DestRect: TRect; - SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter); -begin - StretchDrawInternal(SrcRect, DestCanvas, DestRect, SrcFactor, DestFactor, Filter, PixelBlendProc); -end; - -procedure TImagingCanvas.StretchDrawAlpha(const SrcRect: TRect; - DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter); -begin - StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAlphaProc); -end; - -procedure TImagingCanvas.StretchDrawAdd(const SrcRect: TRect; - DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter); -begin - StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAddProc); -end; - -procedure TImagingCanvas.ApplyConvolution(Kernel: PLongInt; KernelSize, - Divisor: LongInt; Bias: Single; ClampChannels: Boolean); -var - X, Y, I, J, PosY, PosX, SizeDiv2, KernelValue, WidthBytes, Bpp: LongInt; - R, G, B, DivFloat: Single; - Pixel: TColorFPRec; - TempImage: TImageData; - DstPointer, SrcPointer: PByte; -begin - SizeDiv2 := KernelSize div 2; - DivFloat := IffFloat(Divisor > 1, 1.0 / Divisor, 1.0); - Bpp := FFormatInfo.BytesPerPixel; - WidthBytes := FPData.Width * Bpp; - - InitImage(TempImage); - CloneImage(FPData^, TempImage); - - try - // For every pixel in clip rect - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp]; - - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - // Reset accumulators - R := 0.0; - G := 0.0; - B := 0.0; - - for J := 0 to KernelSize - 1 do - begin - PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1); - - for I := 0 to KernelSize - 1 do - begin - PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1); - SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp]; - - // Get pixels from neighbourhood of current pixel and add their - // colors to accumulators weighted by filter kernel values - Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette); - KernelValue := PLongIntArray(Kernel)[J * KernelSize + I]; - - R := R + Pixel.R * KernelValue; - G := G + Pixel.G * KernelValue; - B := B + Pixel.B * KernelValue; - end; - end; - - Pixel := FFormatInfo.GetPixelFP(DstPointer, @FFormatInfo, FPData.Palette); - - Pixel.R := R * DivFloat + Bias; - Pixel.G := G * DivFloat + Bias; - Pixel.B := B * DivFloat + Bias; - - if ClampChannels then - ClampFloatPixel(Pixel); - - // Set resulting pixel color - FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel); - - Inc(DstPointer, Bpp); - end; - end; - - finally - FreeImage(TempImage); - end; -end; - -procedure TImagingCanvas.ApplyConvolution3x3(const Filter: TConvolutionFilter3x3); -begin - ApplyConvolution(@Filter.Kernel, 3, Filter.Divisor, Filter.Bias, True); -end; - -procedure TImagingCanvas.ApplyConvolution5x5(const Filter: TConvolutionFilter5x5); -begin - ApplyConvolution(@Filter.Kernel, 5, Filter.Divisor, Filter.Bias, True); -end; - -procedure TImagingCanvas.ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction); -var - X, Y, I, J, PosY, PosX, SizeDiv2, WidthBytes, Bpp: LongInt; - Pixel: TColorFPRec; - TempImage: TImageData; - DstPointer, SrcPointer: PByte; - NeighPixels: TDynFPPixelArray; -begin - SizeDiv2 := FilterSize div 2; - Bpp := FFormatInfo.BytesPerPixel; - WidthBytes := FPData.Width * Bpp; - SetLength(NeighPixels, FilterSize * FilterSize); - - InitImage(TempImage); - CloneImage(FPData^, TempImage); - - try - // For every pixel in clip rect - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp]; - - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - for J := 0 to FilterSize - 1 do - begin - PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1); - - for I := 0 to FilterSize - 1 do - begin - PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1); - SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp]; - - // Get pixels from neighbourhood of current pixel and store them - Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette); - NeighPixels[J * FilterSize + I] := Pixel; - end; - end; - - // Choose pixel using custom function - Pixel := SelectFunc(NeighPixels); - // Set resulting pixel color - FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel); - - Inc(DstPointer, Bpp); - end; - end; - - finally - FreeImage(TempImage); - end; -end; - -procedure TImagingCanvas.ApplyMedianFilter(FilterSize: Integer); -begin - ApplyNonLinearFilter(FilterSize, MedianSelect); -end; - -procedure TImagingCanvas.ApplyMinFilter(FilterSize: Integer); -begin - ApplyNonLinearFilter(FilterSize, MinSelect); -end; - -procedure TImagingCanvas.ApplyMaxFilter(FilterSize: Integer); -begin - ApplyNonLinearFilter(FilterSize, MaxSelect); -end; - -procedure TImagingCanvas.PointTransform(Transform: TPointTransformFunction; - Param1, Param2, Param3: Single); -var - X, Y, Bpp, WidthBytes: Integer; - PixPointer: PByte; - Pixel: TColorFPRec; -begin - Bpp := FFormatInfo.BytesPerPixel; - WidthBytes := FPData.Width * Bpp; - - // For every pixel in clip rect - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - PixPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp]; - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - Pixel := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette); - - FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette, - Transform(Pixel, Param1, Param2, Param3)); - - Inc(PixPointer, Bpp); - end; - end; -end; - -procedure TImagingCanvas.ModifyContrastBrightness(Contrast, Brightness: Single); -begin - PointTransform(TransformContrastBrightness, 1.0 + Contrast / 100, - Brightness / 100, 0); -end; - -procedure TImagingCanvas.GammaCorection(Red, Green, Blue: Single); -begin - PointTransform(TransformGamma, Red, Green, Blue); -end; - -procedure TImagingCanvas.InvertColors; -begin - PointTransform(TransformInvert, 0, 0, 0); -end; - -procedure TImagingCanvas.Threshold(Red, Green, Blue: Single); -begin - PointTransform(TransformThreshold, Red, Green, Blue); -end; - -procedure TImagingCanvas.AdjustColorLevels(BlackPoint, WhitePoint, MidPoint: Single); -begin - PointTransform(TransformLevels, BlackPoint, WhitePoint, 1.0 / MidPoint); -end; - -procedure TImagingCanvas.PremultiplyAlpha; -begin - PointTransform(TransformPremultiplyAlpha, 0, 0, 0); -end; - -procedure TImagingCanvas.UnPremultiplyAlpha; -begin - PointTransform(TransformUnPremultiplyAlpha, 0, 0, 0); -end; - -procedure TImagingCanvas.GetHistogram(out Red, Green, Blue, Alpha, - Gray: THistogramArray); -var - X, Y, Bpp: Integer; - PixPointer: PByte; - Color32: TColor32Rec; -begin - FillChar(Red, SizeOf(Red), 0); - FillChar(Green, SizeOf(Green), 0); - FillChar(Blue, SizeOf(Blue), 0); - FillChar(Alpha, SizeOf(Alpha), 0); - FillChar(Gray, SizeOf(Gray), 0); - - Bpp := FFormatInfo.BytesPerPixel; - - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp]; - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - Color32 := FFormatInfo.GetPixel32(PixPointer, @FFormatInfo, FPData.Palette); - - Inc(Red[Color32.R]); - Inc(Green[Color32.G]); - Inc(Blue[Color32.B]); - Inc(Alpha[Color32.A]); - Inc(Gray[Round(GrayConv.R * Color32.R + GrayConv.G * Color32.G + GrayConv.B * Color32.B)]); - - Inc(PixPointer, Bpp); - end; - end; -end; - -procedure TImagingCanvas.FillChannel(ChannelId: Integer; NewChannelValue: Byte); -var - X, Y, Bpp: Integer; - PixPointer: PByte; - Color32: TColor32Rec; -begin - Bpp := FFormatInfo.BytesPerPixel; - - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp]; - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - Color32 := FFormatInfo.GetPixel32(PixPointer, @FFormatInfo, FPData.Palette); - Color32.Channels[ChannelId] := NewChannelValue; - FFormatInfo.SetPixel32(PixPointer, @FFormatInfo, FPData.Palette, Color32); - - Inc(PixPointer, Bpp); - end; - end; -end; - -procedure TImagingCanvas.FillChannelFP(ChannelId: Integer; NewChannelValue: Single); -var - X, Y, Bpp: Integer; - PixPointer: PByte; - ColorFP: TColorFPRec; -begin - Bpp := FFormatInfo.BytesPerPixel; - - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp]; - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - ColorFP := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette); - ColorFP.Channels[ChannelId] := NewChannelValue; - FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette, ColorFP); - - Inc(PixPointer, Bpp); - end; - end; -end; - -class function TImagingCanvas.GetSupportedFormats: TImageFormats; -begin - Result := [ifIndex8..Pred(ifDXT1)]; -end; - -{ TFastARGB32Canvas } - -destructor TFastARGB32Canvas.Destroy; -begin - FreeMem(FScanlines); - inherited Destroy; -end; - -procedure TFastARGB32Canvas.AlphaBlendPixels(SrcPix, DestPix: PColor32Rec); -var - SrcAlpha, DestAlpha, FinalAlpha: Integer; -begin - FinalAlpha := SrcPix.A + 1 + (DestPix.A * (256 - SrcPix.A)) shr 8; - if FinalAlpha = 0 then - SrcAlpha := 0 - else - SrcAlpha := (SrcPix.A shl 8) div FinalAlpha; - DestAlpha := 256 - SrcAlpha; - - DestPix.A := ClampToByte(FinalAlpha); - DestPix.R := (SrcPix.R * SrcAlpha + DestPix.R * DestAlpha) shr 8; - DestPix.G := (SrcPix.G * SrcAlpha + DestPix.G * DestAlpha) shr 8; - DestPix.B := (SrcPix.B * SrcAlpha + DestPix.B * DestAlpha) shr 8; -end; - -procedure TFastARGB32Canvas.DrawAlpha(const SrcRect: TRect; - DestCanvas: TImagingCanvas; DestX, DestY: Integer); -var - X, Y, SrcX, SrcY, Width, Height: Integer; - SrcPix, DestPix: PColor32Rec; -begin - if DestCanvas.ClassType <> Self.ClassType then - begin - inherited; - Exit; - end; - - SrcX := SrcRect.Left; - SrcY := SrcRect.Top; - Width := SrcRect.Right - SrcRect.Left; - Height := SrcRect.Bottom - SrcRect.Top; - ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY, - FPData.Width, FPData.Height, DestCanvas.ClipRect); - - for Y := 0 to Height - 1 do - begin - SrcPix := @FScanlines[SrcY + Y, SrcX]; - DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[DestY + Y, DestX]; - for X := 0 to Width - 1 do - begin - AlphaBlendPixels(SrcPix, DestPix); - Inc(SrcPix); - Inc(DestPix); - end; - end; -end; - -function TFastARGB32Canvas.GetPixel32(X, Y: LongInt): TColor32; -begin - Result := FScanlines[Y, X].Color; -end; - -procedure TFastARGB32Canvas.SetPixel32(X, Y: LongInt; const Value: TColor32); -begin - if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and - (X < FClipRect.Right) and (Y < FClipRect.Bottom) then - begin - FScanlines[Y, X].Color := Value; - end; -end; - -procedure TFastARGB32Canvas.StretchDrawAlpha(const SrcRect: TRect; - DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter); -var - X, Y, ScaleX, ScaleY, Yp, Xp, Weight1, Weight2, Weight3, Weight4, InvFracY, T1, T2: Integer; - FracX, FracY: Cardinal; - SrcX, SrcY, SrcWidth, SrcHeight: Integer; - DestX, DestY, DestWidth, DestHeight: Integer; - SrcLine, SrcLine2: PColor32RecArray; - DestPix: PColor32Rec; - Accum: TColor32Rec; -begin - if (Filter = rfBicubic) or (DestCanvas.ClassType <> Self.ClassType) then - begin - inherited; - Exit; - end; - - SrcX := SrcRect.Left; - SrcY := SrcRect.Top; - SrcWidth := SrcRect.Right - SrcRect.Left; - SrcHeight := SrcRect.Bottom - SrcRect.Top; - DestX := DestRect.Left; - DestY := DestRect.Top; - DestWidth := DestRect.Right - DestRect.Left; - DestHeight := DestRect.Bottom - DestRect.Top; - // Clip src and dst rects - ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight, - FPData.Width, FPData.Height, DestCanvas.ClipRect); - ScaleX := (SrcWidth shl 16) div DestWidth; - ScaleY := (SrcHeight shl 16) div DestHeight; - - // Nearest and linear filtering using fixed point math - - if Filter = rfNearest then - begin - Yp := 0; - for Y := DestY to DestY + DestHeight - 1 do - begin - Xp := 0; - SrcLine := @FScanlines[SrcY + Yp shr 16, SrcX]; - DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[Y, DestX]; - for X := 0 to DestWidth - 1 do - begin - AlphaBlendPixels(@SrcLine[Xp shr 16], DestPix); - Inc(DestPix); - Inc(Xp, ScaleX); - end; - Inc(Yp, ScaleY); - end; - end - else - begin - Yp := (ScaleY shr 1) - $8000; - for Y := DestY to DestY + DestHeight - 1 do - begin - DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[Y, DestX]; - if Yp < 0 then - begin - T1 := 0; - FracY := 0; - InvFracY := $10000; - end - else - begin - T1 := Yp shr 16; - FracY := Yp and $FFFF; - InvFracY := (not Yp and $FFFF) + 1; - end; - - T2 := Iff(T1 < SrcHeight - 1, T1 + 1, T1); - SrcLine := @Scanlines[T1 + SrcY, SrcX]; - SrcLine2 := @Scanlines[T2 + SrcY, SrcX]; - Xp := (ScaleX shr 1) - $8000; - - for X := 0 to DestWidth - 1 do - begin - if Xp < 0 then - begin - T1 := 0; - FracX := 0; - end - else - begin - T1 := Xp shr 16; - FracX := Xp and $FFFF; - end; - - T2 := Iff(T1 < SrcWidth - 1, T1 + 1, T1); - Weight2:= Integer((Cardinal(InvFracY) * FracX) shr 16); // cast to Card, Int can overflow here - Weight1:= InvFracY - Weight2; - Weight4:= Integer((Cardinal(FracY) * FracX) shr 16); - Weight3:= FracY - Weight4; - - Accum.B := (SrcLine[T1].B * Weight1 + SrcLine[T2].B * Weight2 + - SrcLine2[T1].B * Weight3 + SrcLine2[T2].B * Weight4 + $8000) shr 16; - Accum.G := (SrcLine[T1].G * Weight1 + SrcLine[T2].G * Weight2 + - SrcLine2[T1].G * Weight3 + SrcLine2[T2].G * Weight4 + $8000) shr 16; - Accum.R := (SrcLine[T1].R * Weight1 + SrcLine[T2].R * Weight2 + - SrcLine2[T1].R * Weight3 + SrcLine2[T2].R * Weight4 + $8000) shr 16; - Accum.A := (SrcLine[T1].A * Weight1 + SrcLine[T2].A * Weight2 + - SrcLine2[T1].A * Weight3 + SrcLine2[T2].A * Weight4 + $8000) shr 16; - - AlphaBlendPixels(@Accum, DestPix); - - Inc(Xp, ScaleX); - Inc(DestPix); - end; - Inc(Yp, ScaleY); - end; - end; -end; - -procedure TFastARGB32Canvas.UpdateCanvasState; -var - I: LongInt; - ScanPos: PLongWord; -begin - inherited UpdateCanvasState; - - // Realloc and update scanline array - ReallocMem(FScanlines, FPData.Height * SizeOf(PColor32RecArray)); - ScanPos := FPData.Bits; - - for I := 0 to FPData.Height - 1 do - begin - FScanlines[I] := PColor32RecArray(ScanPos); - Inc(ScanPos, FPData.Width); - end; -end; - -class function TFastARGB32Canvas.GetSupportedFormats: TImageFormats; -begin - Result := [ifA8R8G8B8]; -end; - -procedure TFastARGB32Canvas.InvertColors; -var - X, Y: Integer; - PixPtr: PColor32Rec; -begin - for Y := FClipRect.Top to FClipRect.Bottom - 1 do - begin - PixPtr := @FScanlines[Y, FClipRect.Left]; - for X := FClipRect.Left to FClipRect.Right - 1 do - begin - PixPtr.R := not PixPtr.R; - PixPtr.G := not PixPtr.G; - PixPtr.B := not PixPtr.B; - Inc(PixPtr); - end; - end; -end; - -initialization - RegisterCanvas(TFastARGB32Canvas); - -finalization - FreeAndNil(CanvasClasses); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - more more more ... - - implement pen width everywhere - - more objects (arc, polygon) - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Fixed bug that could raise floating point error in DrawAlpha - and StretchDrawAlpha. - - Fixed bug in TImagingCanvas.Line that caused not drawing - of horz or vert lines. - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Added some methods to TFastARGB32Canvas (InvertColors, DrawAlpha/StretchDrawAlpha) - - Fixed DrawAlpha/StretchDrawAlpha destination alpha calculation. - - Added PremultiplyAlpha and UnPremultiplyAlpha methods. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - Added FillChannel methods. - - Added FloodFill method. - - Added GetHistogram method. - - Fixed "Invalid FP operation" in AdjustColorLevels in FPC compiled exes - (thanks to Carlos Gonz�lez). - - Added TImagingCanvas.AdjustColorLevels method. - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - Fixed error that could cause AV in linear and nonlinear filters. - - Added blended rect filling function FillRectBlend. - - Added drawing function with blending (DrawAlpha, StretchDrawAlpha, - StretchDrawAdd, DrawBlend, StretchDrawBlend, ...) - - Added non-linear filters (min, max, median). - - Added point transforms (invert, contrast, gamma, brightness). - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Added some new filter kernels for convolution. - - Added FillMode and PenMode properties. - - Added FrameRect, Rectangle, Ellipse, and Line methods. - - Removed HorzLine and VertLine from TFastARGB32Canvas - new versions - in general canvas is now as fast as those in TFastARGB32Canvas - (only in case of A8R8G8B8 images of course). - - Added PenWidth property, updated HorzLine and VertLine to use it. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - added TFastARGB32Canvas - - added convolutions, hline, vline - - unit created, intial stuff added - -} - -end. - diff --git a/3rd/Imaging/Source/ImagingClasses.pas b/3rd/Imaging/Source/ImagingClasses.pas deleted file mode 100644 index 1539d0f77..000000000 --- a/3rd/Imaging/Source/ImagingClasses.pas +++ /dev/null @@ -1,1092 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains class based wrapper to Imaging library.} -unit ImagingClasses; - -{$I ImagingOptions.inc} - -interface - -uses - Types, Classes, ImagingTypes, Imaging, ImagingFormats, ImagingUtility; - -type - { Base abstract high level class wrapper to low level Imaging structures and - functions.} - TBaseImage = class(TPersistent) - private - function GetEmpty: Boolean; - protected - FPData: PImageData; - FOnDataSizeChanged: TNotifyEvent; - FOnPixelsChanged: TNotifyEvent; - function GetFormat: TImageFormat; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetHeight: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetSize: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetWidth: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetBits: Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetPalette: PPalette32; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetPaletteEntries: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetScanline(Index: Integer): Pointer; - function GetPixelPointer(X, Y: Integer): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetScanlineSize: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetFormatInfo: TImageFormatInfo; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetBoundsRect: TRect; - procedure SetFormat(const Value: TImageFormat); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetHeight(const Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetWidth(const Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetPointer; virtual; abstract; - procedure DoDataSizeChanged; virtual; - procedure DoPixelsChanged; virtual; - public - constructor Create; virtual; - constructor CreateFromImage(AImage: TBaseImage); - destructor Destroy; override; - { Returns info about current image.} - function ToString: string; {$IF Defined(DCC) and (CompilerVersion >= 20.0)}override;{$IFEND} - - { Creates a new image data with the given size and format. Old image - data is lost. Works only for the current image of TMultiImage.} - procedure RecreateImageData(AWidth, AHeight: Integer; AFormat: TImageFormat); - { Maps underlying image data to given TImageData record. Both TBaseImage and - TImageData now share some image memory (bits). So don't call FreeImage - on TImageData afterwards since this TBaseImage would get really broken.} - procedure MapImageData(const ImageData: TImageData); - { Deletes current image.} - procedure Clear; - - { Resizes current image with optional resampling.} - procedure Resize(NewWidth, NewHeight: Integer; Filter: TResizeFilter); - - procedure ResizeToFit(FitWidth, FitHeight: Integer; Filter: TResizeFilter; DstImage: TBaseImage); - { Flips current image. Reverses the image along its horizontal axis the top - becomes the bottom and vice versa.} - procedure Flip; - { Mirrors current image. Reverses the image along its vertical axis the left - side becomes the right and vice versa.} - procedure Mirror; - { Rotates image by Angle degrees counterclockwise.} - procedure Rotate(Angle: Single); - { Copies rectangular part of SrcImage to DstImage. No blending is performed - - alpha is simply copied to destination image. Operates also with - negative X and Y coordinates. - Note that copying is fastest for images in the same data format - (and slowest for images in special formats).} - procedure CopyTo(SrcX, SrcY, Width, Height: Integer; DstImage: TBaseImage; DstX, DstY: Integer); - { Stretches the contents of the source rectangle to the destination rectangle - with optional resampling. No blending is performed - alpha is - simply copied/resampled to destination image. Note that stretching is - fastest for images in the same data format (and slowest for - images in special formats).} - procedure StretchTo(SrcX, SrcY, SrcWidth, SrcHeight: Integer; DstImage: TBaseImage; DstX, DstY, DstWidth, DstHeight: Integer; Filter: TResizeFilter); - { Replaces pixels with OldPixel in the given rectangle by NewPixel. - OldPixel and NewPixel should point to the pixels in the same format - as the given image is in.} - procedure ReplaceColor(X, Y, Width, Height: Integer; OldColor, NewColor: Pointer); - { Swaps SrcChannel and DstChannel color or alpha channels of image. - Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to - identify channels.} - procedure SwapChannels(SrcChannel, DstChannel: Integer); - - { Loads current image data from file.} - procedure LoadFromFile(const FileName: string); virtual; - { Loads current image data from stream.} - procedure LoadFromStream(Stream: TStream); virtual; - - { Saves current image data to file.} - procedure SaveToFile(const FileName: string); - { Saves current image data to stream. Ext identifies desired image file - format (jpg, png, dds, ...)} - procedure SaveToStream(const Ext: string; Stream: TStream); - - { Width of current image in pixels.} - property Width: Integer read GetWidth write SetWidth; - { Height of current image in pixels.} - property Height: Integer read GetHeight write SetHeight; - { Image data format of current image.} - property Format: TImageFormat read GetFormat write SetFormat; - { Size in bytes of current image's data.} - property Size: Integer read GetSize; - { Pointer to memory containing image bits.} - property Bits: Pointer read GetBits; - { Pointer to palette for indexed format images. It is nil for others. - Max palette entry is at index [PaletteEntries - 1].} - property Palette: PPalette32 read GetPalette; - { Number of entries in image's palette} - property PaletteEntries: Integer read GetPaletteEntries; - { Provides indexed access to each line of pixels. Does not work with special - format images (like DXT).} - property Scanline[Index: Integer]: Pointer read GetScanline; - { Returns pointer to image pixel at [X, Y] coordinates.} - property PixelPointer[X, Y: Integer]: Pointer read GetPixelPointer; - { Size/length of one image scanline in bytes.} - property ScanlineSize: Integer read GetScanlineSize; - { Extended image format information.} - property FormatInfo: TImageFormatInfo read GetFormatInfo; - { This gives complete access to underlying TImageData record. - It can be used in functions that take TImageData as parameter - (for example: ReduceColors(SingleImageInstance.ImageData^, 64)).} - property ImageDataPointer: PImageData read FPData; - { Indicates whether the current image is valid (proper format, - allowed dimensions, right size, ...).} - property Valid: Boolean read GetValid; - { Indicates whether image containst any data (size in bytes > 0).} - property Empty: Boolean read GetEmpty; - { Specifies the bounding rectangle of the image.} - property BoundsRect: TRect read GetBoundsRect; - { This event occurs when the image data size has just changed. That means - image width, height, or format has been changed.} - property OnDataSizeChanged: TNotifyEvent read FOnDataSizeChanged write FOnDataSizeChanged; - { This event occurs when some pixels of the image have just changed.} - property OnPixelsChanged: TNotifyEvent read FOnPixelsChanged write FOnPixelsChanged; - end; - - { Extension of TBaseImage which uses single TImageData record to - store image. All methods inherited from TBaseImage work with this record.} - TSingleImage = class(TBaseImage) - protected - FImageData: TImageData; - procedure SetPointer; override; - public - constructor Create; override; - constructor CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault); - constructor CreateFromData(const AData: TImageData); - constructor CreateFromFile(const FileName: string); - constructor CreateFromStream(Stream: TStream); - destructor Destroy; override; - { Assigns single image from another single image or multi image.} - procedure Assign(Source: TPersistent); override; - { Assigns single image from image data record.} - procedure AssignFromImageData(const AImageData: TImageData); - end; - - { Extension of TBaseImage which uses array of TImageData records to - store multiple images. Images are independent on each other and they don't - share any common characteristic. Each can have different size, format, and - palette. All methods inherited from TBaseImage work only with - active image (it could represent mipmap level, animation frame, or whatever). - Methods whose names contain word 'Multi' work with all images in array - (as well as other methods with obvious names).} - TMultiImage = class(TBaseImage) - protected - FDataArray: TDynImageDataArray; - FActiveImage: Integer; - procedure SetActiveImage(Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetImageCount: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetImageCount(Value: Integer); - function GetAllImagesValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} - function GetImage(Index: Integer): TImageData; {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetImage(Index: Integer; Value: TImageData); {$IFDEF USE_INLINE}inline;{$ENDIF} - procedure SetPointer; override; - function PrepareInsert(Index, Count: Integer): Boolean; - procedure DoInsertImages(Index: Integer; const Images: TDynImageDataArray); - procedure DoInsertNew(Index: Integer; AWidth, AHeight: Integer; AFormat: TImageFormat); - public - constructor Create; override; - constructor CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat; ImageCount: Integer); - constructor CreateFromArray(const ADataArray: TDynImageDataArray); - constructor CreateFromFile(const FileName: string); - constructor CreateFromStream(Stream: TStream); - destructor Destroy; override; - { Assigns multi image from another multi image or single image.} - procedure Assign(Source: TPersistent); override; - { Assigns multi image from array of image data records.} - procedure AssignFromArray(const ADataArray: TDynImageDataArray); - - { Adds new image at the end of the image array. } - function AddImage(AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault): Integer; overload; - { Adds existing image at the end of the image array. } - function AddImage(const Image: TImageData): Integer; overload; - { Adds existing image (Active image of a TmultiImage) - at the end of the image array. } - function AddImage(Image: TBaseImage): Integer; overload; - { Adds existing image array ((all images of a multi image)) - at the end of the image array. } - procedure AddImages(const Images: TDynImageDataArray); overload; - { Adds existing MultiImage images at the end of the image array. } - procedure AddImages(Images: TMultiImage); overload; - - { Inserts new image image at the given position in the image array. } - procedure InsertImage(Index, AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault); overload; - { Inserts existing image at the given position in the image array. } - procedure InsertImage(Index: Integer; const Image: TImageData); overload; - { Inserts existing image (Active image of a TmultiImage) - at the given position in the image array. } - procedure InsertImage(Index: Integer; Image: TBaseImage); overload; - { Inserts existing image at the given position in the image array. } - procedure InsertImages(Index: Integer; const Images: TDynImageDataArray); overload; - { Inserts existing images (all images of a TmultiImage) at - the given position in the image array. } - procedure InsertImages(Index: Integer; Images: TMultiImage); overload; - - { Exchanges two images at the given positions in the image array. } - procedure ExchangeImages(Index1, Index2: Integer); - { Deletes image at the given position in the image array.} - procedure DeleteImage(Index: Integer); - { Rearranges images so that the first image will become last and vice versa.} - procedure ReverseImages; - { Deletes all images.} - procedure ClearAll; - - { Converts all images to another image data format.} - procedure ConvertImages(Format: TImageFormat); - { Resizes all images.} - procedure ResizeImages(NewWidth, NewHeight: Integer; Filter: TResizeFilter); - - { Overloaded loading method that will add new image to multiimage if - image array is empty bero loading. } - procedure LoadFromFile(const FileName: string); override; - { Overloaded loading method that will add new image to multiimage if - image array is empty bero loading. } - procedure LoadFromStream(Stream: TStream); override; - - { Loads whole multi image from file.} - procedure LoadMultiFromFile(const FileName: string); - { Loads whole multi image from stream.} - procedure LoadMultiFromStream(Stream: TStream); - { Saves whole multi image to file.} - procedure SaveMultiToFile(const FileName: string); - { Saves whole multi image to stream. Ext identifies desired - image file format (jpg, png, dds, ...).} - procedure SaveMultiToStream(const Ext: string; Stream: TStream); - - { Indicates active image of this multi image. All methods inherited - from TBaseImage operate on this image only.} - property ActiveImage: Integer read FActiveImage write SetActiveImage; - { Number of images of this multi image.} - property ImageCount: Integer read GetImageCount write SetImageCount; - { This value is True if all images of this TMultiImage are valid.} - property AllImagesValid: Boolean read GetAllImagesValid; - { This gives complete access to underlying TDynImageDataArray. - It can be used in functions that take TDynImageDataArray - as parameter.} - property DataArray: TDynImageDataArray read FDataArray; - { Array property for accessing individual images of TMultiImage. When you - set image at given index the old image is freed and the source is cloned.} - property Images[Index: Integer]: TImageData read GetImage write SetImage; default; - end; - -implementation - -const - DefaultWidth = 16; - Defaultheight = 16; - -function GetArrayFromImageData(const ImageData: TImageData): TDynImageDataArray; -begin - SetLength(Result, 1); - Result[0] := ImageData; -end; - -{ TBaseImage class implementation } - -constructor TBaseImage.Create; -begin - SetPointer; -end; - -constructor TBaseImage.CreateFromImage(AImage: TBaseImage); -begin - Create; - Assign(AImage); -end; - -destructor TBaseImage.Destroy; -begin - inherited Destroy; -end; - -function TBaseImage.GetWidth: Integer; -begin - if Valid then - Result := FPData.Width - else - Result := 0; -end; - -function TBaseImage.GetHeight: Integer; -begin - if Valid then - Result := FPData.Height - else - Result := 0; -end; - -function TBaseImage.GetFormat: TImageFormat; -begin - if Valid then - Result := FPData.Format - else - Result := ifUnknown; -end; - -function TBaseImage.GetScanline(Index: Integer): Pointer; -var - Info: TImageFormatInfo; -begin - if Valid then - begin - Info := GetFormatInfo; - if not Info.IsSpecial then - Result := ImagingFormats.GetScanLine(FPData.Bits, Info, FPData.Width, Index) - else - Result := FPData.Bits; - end - else - Result := nil; -end; - -function TBaseImage.GetScanlineSize: Integer; -begin - if Valid then - Result := FormatInfo.GetPixelsSize(Format, Width, 1) - else - Result := 0; -end; - -function TBaseImage.GetPixelPointer(X, Y: Integer): Pointer; -begin - if Valid then - Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * GetFormatInfo.BytesPerPixel] - else - Result := nil; -end; - -function TBaseImage.GetSize: Integer; -begin - if Valid then - Result := FPData.Size - else - Result := 0; -end; - -function TBaseImage.GetBits: Pointer; -begin - if Valid then - Result := FPData.Bits - else - Result := nil; -end; - -function TBaseImage.GetPalette: PPalette32; -begin - if Valid then - Result := FPData.Palette - else - Result := nil; -end; - -function TBaseImage.GetPaletteEntries: Integer; -begin - Result := GetFormatInfo.PaletteEntries; -end; - -function TBaseImage.GetFormatInfo: TImageFormatInfo; -begin - if Valid then - Imaging.GetImageFormatInfo(FPData.Format, Result) - else - FillChar(Result, SizeOf(Result), 0); -end; - -function TBaseImage.GetValid: Boolean; -begin - Result := Assigned(FPData) and Imaging.TestImage(FPData^); -end; - -function TBaseImage.GetBoundsRect: TRect; -begin - Result := Rect(0, 0, GetWidth, GetHeight); -end; - -function TBaseImage.GetEmpty: Boolean; -begin - Result := FPData.Size = 0; -end; - -procedure TBaseImage.SetWidth(const Value: Integer); -begin - Resize(Value, GetHeight, rfNearest); -end; - -procedure TBaseImage.SetHeight(const Value: Integer); -begin - Resize(GetWidth, Value, rfNearest); -end; - -procedure TBaseImage.SetFormat(const Value: TImageFormat); -begin - if Valid and Imaging.ConvertImage(FPData^, Value) then - DoDataSizeChanged; -end; - -procedure TBaseImage.DoDataSizeChanged; -begin - if Assigned(FOnDataSizeChanged) then - FOnDataSizeChanged(Self); - DoPixelsChanged; -end; - -procedure TBaseImage.DoPixelsChanged; -begin - if Assigned(FOnPixelsChanged) then - FOnPixelsChanged(Self); -end; - -procedure TBaseImage.RecreateImageData(AWidth, AHeight: Integer; AFormat: TImageFormat); -begin - if Assigned(FPData) and Imaging.NewImage(AWidth, AHeight, AFormat, FPData^) then - DoDataSizeChanged; -end; - -procedure TBaseImage.MapImageData(const ImageData: TImageData); -begin - Clear; - FPData.Width := ImageData.Width; - FPData.Height := ImageData.Height; - FPData.Format := ImageData.Format; - FPData.Size := ImageData.Size; - FPData.Bits := ImageData.Bits; - FPData.Palette := ImageData.Palette; -end; - -procedure TBaseImage.Clear; -begin - FreeImage(FPData^); -end; - -procedure TBaseImage.Resize(NewWidth, NewHeight: Integer; Filter: TResizeFilter); -begin - if Valid and Imaging.ResizeImage(FPData^, NewWidth, NewHeight, Filter) then - DoDataSizeChanged; -end; - -procedure TBaseImage.ResizeToFit(FitWidth, FitHeight: Integer; - Filter: TResizeFilter; DstImage: TBaseImage); -begin - if Valid and Assigned(DstImage) then - begin - Imaging.ResizeImageToFit(FPData^, FitWidth, FitHeight, Filter, - DstImage.FPData^); - DstImage.DoDataSizeChanged; - end; -end; - -procedure TBaseImage.Flip; -begin - if Valid and Imaging.FlipImage(FPData^) then - DoPixelsChanged; -end; - -procedure TBaseImage.Mirror; -begin - if Valid and Imaging.MirrorImage(FPData^) then - DoPixelsChanged; -end; - -procedure TBaseImage.Rotate(Angle: Single); -begin - if Valid then - begin - Imaging.RotateImage(FPData^, Angle); - DoPixelsChanged; - end; -end; - -procedure TBaseImage.CopyTo(SrcX, SrcY, Width, Height: Integer; - DstImage: TBaseImage; DstX, DstY: Integer); -begin - if Valid and Assigned(DstImage) and DstImage.Valid then - begin - Imaging.CopyRect(FPData^, SrcX, SrcY, Width, Height, DstImage.FPData^, DstX, DstY); - DstImage.DoPixelsChanged; - end; -end; - -procedure TBaseImage.StretchTo(SrcX, SrcY, SrcWidth, SrcHeight: Integer; - DstImage: TBaseImage; DstX, DstY, DstWidth, DstHeight: Integer; Filter: TResizeFilter); -begin - if Valid and Assigned(DstImage) and DstImage.Valid then - begin - Imaging.StretchRect(FPData^, SrcX, SrcY, SrcWidth, SrcHeight, - DstImage.FPData^, DstX, DstY, DstWidth, DstHeight, Filter); - DstImage.DoPixelsChanged; - end; -end; - -procedure TBaseImage.ReplaceColor(X, Y, Width, Height: Integer; OldColor, - NewColor: Pointer); -begin - if Valid then - begin - Imaging.ReplaceColor(FPData^, X, Y, Width, Height, OldColor, NewColor); - DoPixelsChanged; - end; -end; - -procedure TBaseImage.SwapChannels(SrcChannel, DstChannel: Integer); -begin - if Valid then - begin - Imaging.SwapChannels(FPData^, SrcChannel, DstChannel); - DoPixelsChanged; - end; -end; - -function TBaseImage.ToString: string; -begin - Result := Iff(Valid, Imaging.ImageToStr(FPData^), 'empty image'); -end; - -procedure TBaseImage.LoadFromFile(const FileName: string); -begin - if Assigned(FPData) and Imaging.LoadImageFromFile(FileName, FPData^) then - DoDataSizeChanged; -end; - -procedure TBaseImage.LoadFromStream(Stream: TStream); -begin - if Assigned(FPData) and Imaging.LoadImageFromStream(Stream, FPData^) then - DoDataSizeChanged; -end; - -procedure TBaseImage.SaveToFile(const FileName: string); -begin - if Valid then - Imaging.SaveImageToFile(FileName, FPData^); -end; - -procedure TBaseImage.SaveToStream(const Ext: string; Stream: TStream); -begin - if Valid then - Imaging.SaveImageToStream(Ext, Stream, FPData^); -end; - - -{ TSingleImage class implementation } - -constructor TSingleImage.Create; -begin - inherited Create; - Clear; -end; - -constructor TSingleImage.CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat); -begin - inherited Create; - RecreateImageData(AWidth, AHeight, AFormat); -end; - -constructor TSingleImage.CreateFromData(const AData: TImageData); -begin - inherited Create; - AssignFromImageData(AData); -end; - -constructor TSingleImage.CreateFromFile(const FileName: string); -begin - inherited Create; - LoadFromFile(FileName); -end; - -constructor TSingleImage.CreateFromStream(Stream: TStream); -begin - inherited Create; - LoadFromStream(Stream); -end; - -destructor TSingleImage.Destroy; -begin - Imaging.FreeImage(FImageData); - inherited Destroy; -end; - -procedure TSingleImage.SetPointer; -begin - FPData := @FImageData; -end; - -procedure TSingleImage.Assign(Source: TPersistent); -begin - if Source = nil then - begin - Clear; - end - else if Source is TSingleImage then - begin - AssignFromImageData(TSingleImage(Source).FImageData); - end - else if Source is TMultiImage then - begin - if TMultiImage(Source).Valid then - AssignFromImageData(TMultiImage(Source).FPData^) - else - Clear; - end - else - inherited Assign(Source); -end; - -procedure TSingleImage.AssignFromImageData(const AImageData: TImageData); -begin - if Imaging.TestImage(AImageData) then - begin - Imaging.CloneImage(AImageData, FImageData); - DoDataSizeChanged; - end - else - Clear; -end; - -{ TMultiImage class implementation } - -constructor TMultiImage.Create; -begin - inherited Create; -end; - -constructor TMultiImage.CreateFromParams(AWidth, AHeight: Integer; - AFormat: TImageFormat; ImageCount: Integer); -var - I: Integer; -begin - Imaging.FreeImagesInArray(FDataArray); - SetLength(FDataArray, ImageCount); - for I := 0 to GetImageCount - 1 do - Imaging.NewImage(AWidth, AHeight, AFormat, FDataArray[I]); - if GetImageCount > 0 then - SetActiveImage(0); -end; - -constructor TMultiImage.CreateFromArray(const ADataArray: TDynImageDataArray); -begin - AssignFromArray(ADataArray); -end; - -constructor TMultiImage.CreateFromFile(const FileName: string); -begin - LoadMultiFromFile(FileName); -end; - -constructor TMultiImage.CreateFromStream(Stream: TStream); -begin - LoadMultiFromStream(Stream); -end; - -destructor TMultiImage.Destroy; -begin - Imaging.FreeImagesInArray(FDataArray); - inherited Destroy; -end; - -procedure TMultiImage.SetActiveImage(Value: Integer); -begin - FActiveImage := Value; - SetPointer; -end; - -function TMultiImage.GetImageCount: Integer; -begin - Result := Length(FDataArray); -end; - -procedure TMultiImage.SetImageCount(Value: Integer); -var - I, OldCount: Integer; -begin - if Value > GetImageCount then - begin - // Create new empty images if array will be enlarged - OldCount := GetImageCount; - SetLength(FDataArray, Value); - for I := OldCount to Value - 1 do - Imaging.NewImage(DefaultWidth, DefaultHeight, ifDefault, FDataArray[I]); - end - else - begin - // Free images that exceed desired count and shrink array - for I := Value to GetImageCount - 1 do - Imaging.FreeImage(FDataArray[I]); - SetLength(FDataArray, Value); - end; - SetPointer; -end; - -function TMultiImage.GetAllImagesValid: Boolean; -begin - Result := (GetImageCount > 0) and TestImagesInArray(FDataArray); -end; - -function TMultiImage.GetImage(Index: Integer): TImageData; -begin - if (Index >= 0) and (Index < GetImageCount) then - Result := FDataArray[Index]; -end; - -procedure TMultiImage.SetImage(Index: Integer; Value: TImageData); -begin - if (Index >= 0) and (Index < GetImageCount) then - Imaging.CloneImage(Value, FDataArray[Index]); -end; - -procedure TMultiImage.SetPointer; -begin - if GetImageCount > 0 then - begin - FActiveImage := ClampInt(FActiveImage, 0, GetImageCount - 1); - FPData := @FDataArray[FActiveImage]; - end - else - begin - FActiveImage := -1; - FPData := nil - end; -end; - -function TMultiImage.PrepareInsert(Index, Count: Integer): Boolean; -var - I: Integer; -begin - // Inserting to empty image will add image at index 0 - if GetImageCount = 0 then - Index := 0; - - if (Index >= 0) and (Index <= GetImageCount) and (Count > 0) then - begin - SetLength(FDataArray, GetImageCount + Count); - if Index < GetImageCount - 1 then - begin - // Move imges to new position - System.Move(FDataArray[Index], FDataArray[Index + Count], - (GetImageCount - Count - Index) * SizeOf(TImageData)); - // Null old images, not free them! - for I := Index to Index + Count - 1 do - InitImage(FDataArray[I]); - end; - Result := True; - end - else - Result := False; -end; - -procedure TMultiImage.DoInsertImages(Index: Integer; const Images: TDynImageDataArray); -var - I, Len: Integer; -begin - Len := Length(Images); - if PrepareInsert(Index, Len) then - begin - for I := 0 to Len - 1 do - Imaging.CloneImage(Images[I], FDataArray[Index + I]); - end; -end; - -procedure TMultiImage.DoInsertNew(Index, AWidth, AHeight: Integer; - AFormat: TImageFormat); -begin - if PrepareInsert(Index, 1) then - Imaging.NewImage(AWidth, AHeight, AFormat, FDataArray[Index]); -end; - -procedure TMultiImage.Assign(Source: TPersistent); -var - Arr: TDynImageDataArray; -begin - if Source = nil then - begin - ClearAll; - end - else if Source is TMultiImage then - begin - AssignFromArray(TMultiImage(Source).FDataArray); - SetActiveImage(TMultiImage(Source).ActiveImage); - end - else if Source is TSingleImage then - begin - SetLength(Arr, 1); - Arr[0] := TSingleImage(Source).FImageData; - AssignFromArray(Arr); - end - else - inherited Assign(Source); -end; - -procedure TMultiImage.AssignFromArray(const ADataArray: TDynImageDataArray); -var - I: Integer; -begin - Imaging.FreeImagesInArray(FDataArray); - SetLength(FDataArray, Length(ADataArray)); - for I := 0 to GetImageCount - 1 do - begin - // Clone only valid images - if Imaging.TestImage(ADataArray[I]) then - Imaging.CloneImage(ADataArray[I], FDataArray[I]) - else - Imaging.NewImage(DefaultWidth, DefaultHeight, ifDefault, FDataArray[I]); - end; - if GetImageCount > 0 then - SetActiveImage(0); -end; - -function TMultiImage.AddImage(AWidth, AHeight: Integer; AFormat: TImageFormat): Integer; -begin - Result := GetImageCount; - DoInsertNew(Result, AWidth, AHeight, AFormat); -end; - -function TMultiImage.AddImage(const Image: TImageData): Integer; -begin - Result := GetImageCount; - DoInsertImages(Result, GetArrayFromImageData(Image)); -end; - -function TMultiImage.AddImage(Image: TBaseImage): Integer; -begin - if Assigned(Image) and Image.Valid then - begin - Result := GetImageCount; - DoInsertImages(Result, GetArrayFromImageData(Image.FPData^)); - end - else - Result := -1; -end; - -procedure TMultiImage.AddImages(const Images: TDynImageDataArray); -begin - DoInsertImages(GetImageCount, Images); -end; - -procedure TMultiImage.AddImages(Images: TMultiImage); -begin - DoInsertImages(GetImageCount, Images.FDataArray); -end; - -procedure TMultiImage.InsertImage(Index, AWidth, AHeight: Integer; - AFormat: TImageFormat); -begin - DoInsertNew(Index, AWidth, AHeight, AFormat); -end; - -procedure TMultiImage.InsertImage(Index: Integer; const Image: TImageData); -begin - DoInsertImages(Index, GetArrayFromImageData(Image)); -end; - -procedure TMultiImage.InsertImage(Index: Integer; Image: TBaseImage); -begin - if Assigned(Image) and Image.Valid then - DoInsertImages(Index, GetArrayFromImageData(Image.FPData^)); -end; - -procedure TMultiImage.InsertImages(Index: Integer; - const Images: TDynImageDataArray); -begin - DoInsertImages(Index, FDataArray); -end; - -procedure TMultiImage.InsertImages(Index: Integer; Images: TMultiImage); -begin - DoInsertImages(Index, Images.FDataArray); -end; - -procedure TMultiImage.ExchangeImages(Index1, Index2: Integer); -var - TempData: TImageData; -begin - if (Index1 >= 0) and (Index1 < GetImageCount) and - (Index2 >= 0) and (Index2 < GetImageCount) then - begin - TempData := FDataArray[Index1]; - FDataArray[Index1] := FDataArray[Index2]; - FDataArray[Index2] := TempData; - end; -end; - -procedure TMultiImage.DeleteImage(Index: Integer); -var - I: Integer; -begin - if (Index >= 0) and (Index < GetImageCount) then - begin - // Free image at index to be deleted - Imaging.FreeImage(FDataArray[Index]); - if Index < GetImageCount - 1 then - begin - // Move images to new indices if necessary - for I := Index to GetImageCount - 2 do - FDataArray[I] := FDataArray[I + 1]; - end; - // Set new array length and update pointer to active image - SetLength(FDataArray, GetImageCount - 1); - SetPointer; - end; -end; - -procedure TMultiImage.ClearAll; -begin - ImageCount := 0; -end; - -procedure TMultiImage.ConvertImages(Format: TImageFormat); -var - I: Integer; -begin - for I := 0 to GetImageCount - 1 do - Imaging.ConvertImage(FDataArray[I], Format); -end; - -procedure TMultiImage.ResizeImages(NewWidth, NewHeight: Integer; - Filter: TResizeFilter); -var - I: Integer; -begin - for I := 0 to GetImageCount - 1 do - Imaging.ResizeImage(FDataArray[I], NewWidth, NewHeight, Filter); -end; - -procedure TMultiImage.ReverseImages; -var - I: Integer; -begin - for I := 0 to GetImageCount div 2 do - ExchangeImages(I, GetImageCount - 1 - I); -end; - -procedure TMultiImage.LoadFromFile(const FileName: string); -begin - if GetImageCount = 0 then - ImageCount := 1; - inherited LoadFromFile(FileName); -end; - -procedure TMultiImage.LoadFromStream(Stream: TStream); -begin - if GetImageCount = 0 then - ImageCount := 1; - inherited LoadFromStream(Stream); -end; - -procedure TMultiImage.LoadMultiFromFile(const FileName: string); -begin - Imaging.LoadMultiImageFromFile(FileName, FDataArray); - SetActiveImage(0); -end; - -procedure TMultiImage.LoadMultiFromStream(Stream: TStream); -begin - Imaging.LoadMultiImageFromStream(Stream, FDataArray); - SetActiveImage(0); -end; - -procedure TMultiImage.SaveMultiToFile(const FileName: string); -begin - Imaging.SaveMultiImageToFile(FileName, FDataArray); -end; - -procedure TMultiImage.SaveMultiToStream(const Ext: string; Stream: TStream); -begin - Imaging.SaveMultiImageToStream(Ext, Stream, FDataArray); -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 --------------------------------------------------- - - Added TSingleImage.AssignFromData and TMultiImage.AssigntFromArray - as a replacement for constructors used as methods (that is - compiler error in Delphi XE3). - - Added TBaseImage.ResizeToFit method. - - Changed TMultiImage to have default state with no images. - - TMultiImage.AddImage now returns index of newly added image. - - Fixed img index bug in TMultiImage.ResizeImages - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Added MapImageData method to TBaseImage - - Added Empty property to TBaseImage. - - Added Clear method to TBaseImage. - - Added ScanlineSize property to TBaseImage. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - Added TMultiImage.ReverseImages method. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added SwapChannels method to TBaseImage. - - Added ReplaceColor method to TBaseImage. - - Added ToString method to TBaseImage. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Inserting images to empty MultiImage will act as Add method. - - MultiImages with empty arrays will now create one image when - LoadFromFile or LoadFromStream is called. - - Fixed bug that caused AVs when getting props like Width, Height, asn Size - and when inlining was off. There was call to Iff but with inlining disabled - params like FPData.Size were evaluated and when FPData was nil => AV. - - Added many FPData validity checks to many methods. There were AVs - when calling most methods on empty TMultiImage. - - Added AllImagesValid property to TMultiImage. - - Fixed memory leak in TMultiImage.CreateFromParams. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - added ResizeImages method to TMultiImage - - removed Ext parameter from various LoadFromStream methods, no - longer needed - - fixed various issues concerning ActiveImage of TMultiImage - (it pointed to invalid location after some operations) - - most of property set/get methods are now inline - - added PixelPointers property to TBaseImage - - added Images default array property to TMultiImage - - renamed methods in TMultiImage to contain 'Image' instead of 'Level' - - added canvas support - - added OnDataSizeChanged and OnPixelsChanged event to TBaseImage - - renamed TSingleImage.NewImage to RecreateImageData, made public, and - moved to TBaseImage - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - added props PaletteEntries and ScanLine to TBaseImage - - aded new constructor to TBaseImage that take TBaseImage source - - TMultiImage levels adding and inserting rewritten internally - - added some new functions to TMultiImage: AddLevels, InsertLevels - - added some new functions to TBaseImage: Flip, Mirror, Rotate, - CopyRect, StretchRect - - TBasicImage.Resize has now filter parameter - - new stuff added to TMultiImage (DataArray prop, ConvertLevels) - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - added AddLevel, InsertLevel, ExchangeLevels and DeleteLevel - methods to TMultiImage - - added TBaseImage, TSingleImage and TMultiImage with initial - members -} - -end. - diff --git a/3rd/Imaging/Source/ImagingColors.pas b/3rd/Imaging/Source/ImagingColors.pas deleted file mode 100644 index c7fc81138..000000000 --- a/3rd/Imaging/Source/ImagingColors.pas +++ /dev/null @@ -1,246 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains functions for manipulating and converting color values.} -unit ImagingColors; - -interface - -{$I ImagingOptions.inc} - -uses - SysUtils, ImagingTypes, ImagingUtility; - -{ Converts RGB color to YUV.} -procedure RGBToYUV(R, G, B: Byte; var Y, U, V: Byte); -{ Converts YIV to RGB color.} -procedure YUVToRGB(Y, U, V: Byte; var R, G, B: Byte); - -{ Converts RGB color to YCbCr as used in JPEG.} -procedure RGBToYCbCr(R, G, B: Byte; var Y, Cb, Cr: Byte); -{ Converts YCbCr as used in JPEG to RGB color.} -procedure YCbCrToRGB(Y, Cb, Cr: Byte; var R, G, B: Byte); -{ Converts RGB color to YCbCr as used in JPEG.} -procedure RGBToYCbCr16(R, G, B: Word; var Y, Cb, Cr: Word); -{ Converts YCbCr as used in JPEG to RGB color.} -procedure YCbCrToRGB16(Y, Cb, Cr: Word; var R, G, B: Word); - -{ Converts RGB color to CMY.} -procedure RGBToCMY(R, G, B: Byte; var C, M, Y: Byte); -{ Converts CMY to RGB color.} -procedure CMYToRGB(C, M, Y: Byte; var R, G, B: Byte); -{ Converts RGB color to CMY.} -procedure RGBToCMY16(R, G, B: Word; var C, M, Y: Word); -{ Converts CMY to RGB color.} -procedure CMYToRGB16(C, M, Y: Word; var R, G, B: Word); - -{ Converts RGB color to CMYK.} -procedure RGBToCMYK(R, G, B: Byte; var C, M, Y, K: Byte); -{ Converts CMYK to RGB color.} -procedure CMYKToRGB(C, M, Y, K: Byte; var R, G, B: Byte); -{ Converts RGB color to CMYK.} -procedure RGBToCMYK16(R, G, B: Word; var C, M, Y, K: Word); -{ Converts CMYK to RGB color.} -procedure CMYKToRGB16(C, M, Y, K: Word; var R, G, B: Word); - -{ Converts RGB color to YCoCg.} -procedure RGBToYCoCg(R, G, B: Byte; var Y, Co, Cg: Byte); -{ Converts YCoCg to RGB color.} -procedure YCoCgToRGB(Y, Co, Cg: Byte; var R, G, B: Byte); - -//procedure RGBToHSL(R, G, B: Byte; var H, S, L: Byte); -//procedure HSLToRGB(H, S, L: Byte; var R, G, B: Byte); - -implementation - -procedure RGBToYUV(R, G, B: Byte; var Y, U, V: Byte); -begin - Y := ClampToByte(Round( 0.257 * R + 0.504 * G + 0.098 * B) + 16); - V := ClampToByte(Round( 0.439 * R - 0.368 * G - 0.071 * B) + 128); - U := ClampToByte(Round(-0.148 * R - 0.291 * G + 0.439 * B) + 128); -end; - -procedure YUVToRGB(Y, U, V: Byte; var R, G, B: Byte); -var - CY, CU, CV: LongInt; -begin - CY := Y - 16; - CU := U - 128; - CV := V - 128; - R := ClampToByte(Round(1.164 * CY - 0.002 * CU + 1.596 * CV)); - G := ClampToByte(Round(1.164 * CY - 0.391 * CU - 0.813 * CV)); - B := ClampToByte(Round(1.164 * CY + 2.018 * CU - 0.001 * CV)); -end; - -procedure RGBToYCbCr(R, G, B: Byte; var Y, Cb, Cr: Byte); -begin - Y := ClampToByte(Round( 0.29900 * R + 0.58700 * G + 0.11400 * B)); - Cb := ClampToByte(Round(-0.16874 * R - 0.33126 * G + 0.50000 * B + 128)); - Cr := ClampToByte(Round( 0.50000 * R - 0.41869 * G - 0.08131 * B + 128)); -end; - -procedure YCbCrToRGB(Y, Cb, Cr: Byte; var R, G, B: Byte); -begin - R := ClampToByte(Round(Y + 1.40200 * (Cr - 128))); - G := ClampToByte(Round(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128))); - B := ClampToByte(Round(Y + 1.77200 * (Cb - 128))); -end; - -procedure RGBToYCbCr16(R, G, B: Word; var Y, Cb, Cr: Word); -begin - Y := ClampToWord(Round( 0.29900 * R + 0.58700 * G + 0.11400 * B)); - Cb := ClampToWord(Round(-0.16874 * R - 0.33126 * G + 0.50000 * B + 32768)); - Cr := ClampToWord(Round( 0.50000 * R - 0.41869 * G - 0.08131 * B + 32768)); -end; - -procedure YCbCrToRGB16(Y, Cb, Cr: Word; var R, G, B: Word); -begin - R := ClampToWord(Round(Y + 1.40200 * (Cr - 32768))); - G := ClampToWord(Round(Y - 0.34414 * (Cb - 32768) - 0.71414 * (Cr - 32768))); - B := ClampToWord(Round(Y + 1.77200 * (Cb - 32768))); -end; - -procedure RGBToCMY(R, G, B: Byte; var C, M, Y: Byte); -begin - C := 255 - R; - M := 255 - G; - Y := 255 - B; -end; - -procedure CMYToRGB(C, M, Y: Byte; var R, G, B: Byte); -begin - R := 255 - C; - G := 255 - M; - B := 255 - Y; -end; - -procedure RGBToCMY16(R, G, B: Word; var C, M, Y: Word); -begin - C := 65535 - R; - M := 65535 - G; - Y := 65535 - B; -end; - -procedure CMYToRGB16(C, M, Y: Word; var R, G, B: Word); -begin - R := 65535 - C; - G := 65535 - M; - B := 65535 - Y; -end; - -procedure RGBToCMYK(R, G, B: Byte; var C, M, Y, K: Byte); -begin - RGBToCMY(R, G, B, C, M, Y); - K := Min(C, Min(M, Y)); - if K = 255 then - begin - C := 0; - M := 0; - Y := 0; - end - else - begin - C := ClampToByte(Round((C - K) / (255 - K) * 255)); - M := ClampToByte(Round((M - K) / (255 - K) * 255)); - Y := ClampToByte(Round((Y - K) / (255 - K) * 255)); - end; -end; - -procedure CMYKToRGB(C, M, Y, K: Byte; var R, G, B: Byte); -begin - R := (255 - (C - MulDiv(C, K, 255) + K)); - G := (255 - (M - MulDiv(M, K, 255) + K)); - B := (255 - (Y - MulDiv(Y, K, 255) + K)); -end; - -procedure RGBToCMYK16(R, G, B: Word; var C, M, Y, K: Word); -begin - RGBToCMY16(R, G, B, C, M, Y); - K := Min(C, Min(M, Y)); - if K = 65535 then - begin - C := 0; - M := 0; - Y := 0; - end - else - begin - C := ClampToWord(Round((C - K) / (65535 - K) * 65535)); - M := ClampToWord(Round((M - K) / (65535 - K) * 65535)); - Y := ClampToWord(Round((Y - K) / (65535 - K) * 65535)); - end; -end; - -procedure CMYKToRGB16(C, M, Y, K: Word; var R, G, B: Word); -begin - R := 65535 - (C - MulDiv(C, K, 65535) + K); - G := 65535 - (M - MulDiv(M, K, 65535) + K); - B := 65535 - (Y - MulDiv(Y, K, 65535) + K); -end; - -procedure RGBToYCoCg(R, G, B: Byte; var Y, Co, Cg: Byte); -begin - // C and Delphi's SHR behaviour differs for negative numbers, use div instead. - Y := ClampToByte(( R + G shl 1 + B + 2) div 4); - Co := ClampToByte(( R shl 1 - B shl 1 + 2) div 4 + 128); - Cg := ClampToByte((-R + G shl 1 - B + 2) div 4 + 128); -end; - -procedure YCoCgToRGB(Y, Co, Cg: Byte; var R, G, B: Byte); -var - CoInt, CgInt: Integer; -begin - CoInt := Co - 128; - CgInt := Cg - 128; - R := ClampToByte(Y + CoInt - CgInt); - G := ClampToByte(Y + CgInt); - B := ClampToByte(Y - CoInt - CgInt); -end; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Added RGB<>YCoCg conversion functions. - - Fixed RGB>>CMYK conversions. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added RGB<>CMY(K) converion functions for 16 bit channels - (needed by PSD loading code). - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Added some color space conversion functions and LUTs - (RGB/YUV/YCrCb/CMY/CMYK). - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - unit created (empty!) -} - -end. diff --git a/3rd/Imaging/Source/ImagingComponents.pas b/3rd/Imaging/Source/ImagingComponents.pas deleted file mode 100644 index 2e0af75b7..000000000 --- a/3rd/Imaging/Source/ImagingComponents.pas +++ /dev/null @@ -1,1297 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains VCL/LCL TGraphic descendant which uses Imaging library - for saving and loading.} -unit ImagingComponents; - -{$I ImagingOptions.inc} - -interface - -{$IFDEF LCL} - {$DEFINE COMPONENT_SET_LCL} - {$UNDEF COMPONENT_SET_VCL} -{$ENDIF} - -{$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)} -// If no component sets should be used just include empty unit. -//DOC-IGNORE-BEGIN -implementation -//DOC-IGNORE-END -{$ELSE} - -uses - SysUtils, Types, Classes, -{$IFDEF MSWINDOWS} - Windows, -{$ENDIF} -{$IFDEF COMPONENT_SET_VCL} - Graphics, -{$ENDIF} -{$IFDEF COMPONENT_SET_LCL} - InterfaceBase, - GraphType, - Graphics, - LCLType, - LCLIntf, -{$ENDIF} - ImagingTypes, Imaging, ImagingClasses; - -type - { Graphic class which uses Imaging to load images. - It has standard TBitmap class as ancestor and it can - Assign also to/from TImageData structres and TBaseImage - classes. For saving is uses inherited TBitmap methods. - This class is automatically registered to TPicture for all - file extensions supported by Imaging (useful only for loading). - If you just want to load images in various formats you can use this - class or simply use TPicture.LoadFromXXX which will create this class - automatically. For TGraphic class that saves with Imaging look - at TImagingGraphicForSave class.} - TImagingGraphic = class(TBitmap) - protected - procedure ReadDataFromStream(Stream: TStream); virtual; - procedure AssignTo(Dest: TPersistent); override; - public - constructor Create; override; - - { Loads new image from the stream. It can load all image - file formats supported by Imaging (and enabled of course) - even though it is called by descendant class capable of - saving only one file format.} - procedure LoadFromStream(Stream: TStream); override; - { Copies the image contained in Source to this graphic object. - Supports also TBaseImage descendants from ImagingClasses unit. } - procedure Assign(Source: TPersistent); override; - { Copies the image contained in TBaseImage to this graphic object.} - procedure AssignFromImage(Image: TBaseImage); - { Copies the current image to TBaseImage object.} - procedure AssignToImage(Image: TBaseImage); - { Copies the image contained in TImageData structure to this graphic object.} - procedure AssignFromImageData(const ImageData: TImageData); - { Copies the current image to TImageData structure.} - procedure AssignToImageData(var ImageData: TImageData); - end; - - TImagingGraphicClass = class of TImagingGraphic; - - { Base class for file format specific TGraphic classes that use - Imaging for saving. Each descendant class can load all file formats - supported by Imaging but save only one format (TImagingBitmap - for *.bmp, TImagingJpeg for *.jpg). Format specific classes also - allow easy access to Imaging options that affect saving of files - (they are properties here).} - TImagingGraphicForSave = class(TImagingGraphic) - protected - FDefaultFileExt: string; - FSavingFormat: TImageFormat; - procedure WriteDataToStream(Stream: TStream); virtual; - public - constructor Create; override; - { Saves the current image to the stream. It is saved in the - file format according to the DefaultFileExt property. - So each descendant class can save some other file format.} - procedure SaveToStream(Stream: TStream); override; - { Returns TImageFileFormat descendant for this graphic class.} - class function GetFileFormat: TImageFileFormat; virtual; abstract; - {$IFDEF COMPONENT_SET_LCL} - { Returns file extensions of this graphic class.} - class function GetFileExtensions: string; override; - { Returns default MIME type of this graphic class.} - function GetMimeType: string; override; - {$ENDIF} - { Default (the most common) file extension of this graphic class.} - property DefaultFileExt: string read FDefaultFileExt; - end; - - TImagingGraphicForSaveClass = class of TImagingGraphicForSave; - -{$IFNDEF DONT_LINK_BITMAP} - { TImagingGraphic descendant for loading/saving Windows bitmaps. - VCL/CLX/LCL all have native support for bitmaps so you might - want to disable this class (although you can save bitmaps with - RLE compression with this class).} - TImagingBitmap = class(TImagingGraphicForSave) - protected - FUseRLE: Boolean; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - { See ImagingBitmapRLE option for details.} - property UseRLE: Boolean read FUseRLE write FUseRLE; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_JPEG} - { TImagingGraphic descendant for loading/saving JPEG images.} - TImagingJpeg = class(TImagingGraphicForSave) - protected - FQuality: LongInt; - FProgressive: Boolean; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - {$IFDEF COMPONENT_SET_LCL} - function GetMimeType: string; override; - {$ENDIF} - { See ImagingJpegQuality option for details.} - property Quality: LongInt read FQuality write FQuality; - { See ImagingJpegProgressive option for details.} - property Progressive: Boolean read FProgressive write FProgressive; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_PNG} - { TImagingGraphic descendant for loading/saving PNG images.} - TImagingPNG = class(TImagingGraphicForSave) - protected - FPreFilter: LongInt; - FCompressLevel: LongInt; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - { See ImagingPNGPreFilter option for details.} - property PreFilter: LongInt read FPreFilter write FPreFilter; - { See ImagingPNGCompressLevel option for details.} - property CompressLevel: LongInt read FCompressLevel write FCompressLevel; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_GIF} - { TImagingGraphic descendant for loading/saving GIF images.} - TImagingGIF = class(TImagingGraphicForSave) - public - class function GetFileFormat: TImageFileFormat; override; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_TARGA} - { TImagingGraphic descendant for loading/saving Targa images.} - TImagingTarga = class(TImagingGraphicForSave) - protected - FUseRLE: Boolean; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - { See ImagingTargaRLE option for details.} - property UseRLE: Boolean read FUseRLE write FUseRLE; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_DDS} - { Compresssion type used when saving DDS files by TImagingDds.} - TDDSCompresion = (dcNone, dcDXT1, dcDXT3, dcDXT5); - - { TImagingGraphic descendant for loading/saving DDS images.} - TImagingDDS = class(TImagingGraphicForSave) - protected - FCompression: TDDSCompresion; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - { You can choose compression type used when saving DDS file. - dcNone means that file will be saved in the current bitmaps pixel format.} - property Compression: TDDSCompresion read FCompression write FCompression; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_MNG} - { TImagingGraphic descendant for loading/saving MNG images.} - TImagingMNG = class(TImagingGraphicForSave) - protected - FLossyCompression: Boolean; - FLossyAlpha: Boolean; - FPreFilter: LongInt; - FCompressLevel: LongInt; - FQuality: LongInt; - FProgressive: Boolean; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - {$IFDEF COMPONENT_SET_LCL} - function GetMimeType: string; override; - {$ENDIF} - { See ImagingMNGLossyCompression option for details.} - property LossyCompression: Boolean read FLossyCompression write FLossyCompression; - { See ImagingMNGLossyAlpha option for details.} - property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha; - { See ImagingMNGPreFilter option for details.} - property PreFilter: LongInt read FPreFilter write FPreFilter; - { See ImagingMNGCompressLevel option for details.} - property CompressLevel: LongInt read FCompressLevel write FCompressLevel; - { See ImagingMNGQuality option for details.} - property Quality: LongInt read FQuality write FQuality; - { See ImagingMNGProgressive option for details.} - property Progressive: Boolean read FProgressive write FProgressive; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_JNG} - { TImagingGraphic descendant for loading/saving JNG images.} - TImagingJNG = class(TImagingGraphicForSave) - protected - FLossyAlpha: Boolean; - FAlphaPreFilter: LongInt; - FAlphaCompressLevel: LongInt; - FQuality: LongInt; - FProgressive: Boolean; - public - constructor Create; override; - procedure SaveToStream(Stream: TStream); override; - class function GetFileFormat: TImageFileFormat; override; - { See ImagingJNGLossyAlpha option for details.} - property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha; - { See ImagingJNGPreFilter option for details.} - property AlphaPreFilter: LongInt read FAlphaPreFilter write FAlphaPreFilter; - { See ImagingJNGCompressLevel option for details.} - property AlphaCompressLevel: LongInt read FAlphaCompressLevel write FAlphaCompressLevel; - { See ImagingJNGQuality option for details.} - property Quality: LongInt read FQuality write FQuality; - { See ImagingJNGProgressive option for details.} - property Progressive: Boolean read FProgressive write FProgressive; - end; -{$ENDIF} - -{ Returns bitmap pixel format with the closest match with given data format.} -function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat; -{ Returns data format with closest match with given bitmap pixel format.} -function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat; - -{ Converts TImageData structure to VCL/CLX/LCL bitmap.} -procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap); -{ Converts VCL/CLX/LCL bitmap to TImageData structure.} -procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData); -{ Converts TBaseImage instance to VCL/CLX/LCL bitmap.} -procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap); -{ Converts VCL/CLX/LCL bitmap to TBaseImage. Image must exist before - procedure is called. It overwrites its current image data. - When Image is TMultiImage only the current image level is overwritten.} -procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage); - -{ Displays image stored in TImageData structure onto TCanvas. This procedure - draws image without converting from Imaging format to TBitmap. - Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this - when you want displaying images that change frequently (because converting to - TBitmap by ConvertImageDataToBitmap is generally slow). Dest and Src - rectangles represent coordinates in the form (X1, Y1, X2, Y2).} -procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); -{ Displays image onto TCanvas at position [DstX, DstY]. This procedure - draws image without converting from Imaging format to TBitmap. - Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this - when you want displaying images that change frequently (because converting to - TBitmap by ConvertImageDataToBitmap is generally slow).} -procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); overload; -{ Displays image onto TCanvas to rectangle DstRect. This procedure - draws image without converting from Imaging format to TBitmap. - Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this - when you want displaying images that change frequently (because converting to - TBitmap by ConvertImageDataToBitmap is generally slow).} -procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); overload; -{ Displays part of the image specified by SrcRect onto TCanvas to rectangle DstRect. - This procedure draws image without converting from Imaging format to TBitmap. - Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this - when you want displaying images that change frequently (because converting to - TBitmap by ConvertImageDataToBitmap is generally slow).} -procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); overload; - -{$IFDEF MSWINDOWS} -{ Displays image stored in TImageData structure onto Windows device context. - Behaviour is the same as of DisplayImageData.} -procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); -{$ENDIF} - -implementation - -uses -{$IF Defined(LCL)} - {$IF Defined(LCLGTK2)} - GLib2, GDK2, GTK2, GTK2Def, GTK2Proc, - {$IFEND} -{$IFEND} -{$IFNDEF DONT_LINK_BITMAP} - ImagingBitmap, -{$ENDIF} -{$IFNDEF DONT_LINK_JPEG} - ImagingJpeg, -{$ENDIF} -{$IFNDEF DONT_LINK_GIF} - ImagingGif, -{$ENDIF} -{$IFNDEF DONT_LINK_TARGA} - ImagingTarga, -{$ENDIF} -{$IFNDEF DONT_LINK_DDS} - ImagingDds, -{$ENDIF} -{$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)} - ImagingNetworkGraphics, -{$IFEND} - ImagingFormats, ImagingUtility; - -resourcestring - SBadFormatDataToBitmap = 'Cannot find compatible bitmap format for image %s'; - SBadFormatBitmapToData = 'Cannot find compatible data format for bitmap %p'; - SBadFormatDisplay = 'Unsupported image format passed'; - SUnsupportedLCLWidgetSet = 'This function is not implemented for current LCL widget set'; - SImagingGraphicName = 'Imaging Graphic AllInOne'; - -{ Registers types to VCL/LCL.} -procedure RegisterTypes; -var - I: LongInt; - - procedure RegisterFileFormatAllInOne(Format: TImageFileFormat); - var - I: LongInt; - begin - for I := 0 to Format.Extensions.Count - 1 do - TPicture.RegisterFileFormat(Format.Extensions[I], SImagingGraphicName, - TImagingGraphic); - end; - - procedure RegisterFileFormat(AClass: TImagingGraphicForSaveClass); - var - I: LongInt; - begin - for I := 0 to AClass.GetFileFormat.Extensions.Count - 1 do - TPicture.RegisterFileFormat(AClass.GetFileFormat.Extensions[I], - AClass.GetFileFormat.Name, AClass); - end; - -begin - for I := Imaging.GetFileFormatCount - 1 downto 0 do - RegisterFileFormatAllInOne(Imaging.GetFileFormatAtIndex(I)); - Classes.RegisterClass(TImagingGraphic); - -{$IFNDEF DONT_LINK_TARGA} - RegisterFileFormat(TImagingTarga); - Classes.RegisterClass(TImagingTarga); -{$ENDIF} -{$IFNDEF DONT_LINK_DDS} - RegisterFileFormat(TImagingDDS); - Classes.RegisterClass(TImagingDDS); -{$ENDIF} -{$IFNDEF DONT_LINK_JNG} - RegisterFileFormat(TImagingJNG); - Classes.RegisterClass(TImagingJNG); -{$ENDIF} -{$IFNDEF DONT_LINK_MNG} - RegisterFileFormat(TImagingMNG); - Classes.RegisterClass(TImagingMNG); -{$ENDIF} -{$IFNDEF DONT_LINK_GIF} - RegisterFileFormat(TImagingGIF); - Classes.RegisterClass(TImagingGIF); -{$ENDIF} -{$IFNDEF DONT_LINK_PNG} - {$IFDEF COMPONENT_SET_LCL} - // Unregister Lazarus� default PNG loader which crashes on some PNG files - TPicture.UnregisterGraphicClass(TPortableNetworkGraphic); - {$ENDIF} - RegisterFileFormat(TImagingPNG); - Classes.RegisterClass(TImagingPNG); -{$ENDIF} -{$IFNDEF DONT_LINK_JPEG} - RegisterFileFormat(TImagingJpeg); - Classes.RegisterClass(TImagingJpeg); -{$ENDIF} -{$IFNDEF DONT_LINK_BITMAP} - RegisterFileFormat(TImagingBitmap); - Classes.RegisterClass(TImagingBitmap); -{$ENDIF} -end; - -{ Unregisters types from VCL/LCL.} -procedure UnRegisterTypes; -begin -{$IFNDEF DONT_LINK_BITMAP} - TPicture.UnregisterGraphicClass(TImagingBitmap); - Classes.UnRegisterClass(TImagingBitmap); -{$ENDIF} -{$IFNDEF DONT_LINK_JPEG} - TPicture.UnregisterGraphicClass(TImagingJpeg); - Classes.UnRegisterClass(TImagingJpeg); -{$ENDIF} -{$IFNDEF DONT_LINK_PNG} - TPicture.UnregisterGraphicClass(TImagingPNG); - Classes.UnRegisterClass(TImagingPNG); -{$ENDIF} -{$IFNDEF DONT_LINK_GIF} - TPicture.UnregisterGraphicClass(TImagingGIF); - Classes.UnRegisterClass(TImagingGIF); -{$ENDIF} -{$IFNDEF DONT_LINK_TARGA} - TPicture.UnregisterGraphicClass(TImagingTarga); - Classes.UnRegisterClass(TImagingTarga); -{$ENDIF} -{$IFNDEF DONT_LINK_DDS} - TPicture.UnregisterGraphicClass(TImagingDDS); - Classes.UnRegisterClass(TImagingDDS); -{$ENDIF} - TPicture.UnregisterGraphicClass(TImagingGraphic); - Classes.UnRegisterClass(TImagingGraphic); -end; - -function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat; -begin - case Format of -{$IFDEF COMPONENT_SET_VCL} - ifIndex8: Result := pf8bit; - ifR5G6B5: Result := pf16bit; - ifR8G8B8: Result := pf24bit; -{$ENDIF} - ifA8R8G8B8, - ifX8R8G8B8: Result := pf32bit; - else - Result := pfCustom; - end; -end; - -function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat; -begin - case Format of - pf8bit: Result := ifIndex8; - pf15bit: Result := ifA1R5G5B5; - pf16bit: Result := ifR5G6B5; - pf24bit: Result := ifR8G8B8; - pf32bit: Result := ifA8R8G8B8; - else - Result := ifUnknown; - end; -end; - -procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap); -var - I, LineBytes: LongInt; - PF: TPixelFormat; - Info: TImageFormatInfo; - WorkData: TImageData; -{$IFDEF COMPONENT_SET_VCL} - LogPalette: TMaxLogPalette; -{$ENDIF} -{$IFDEF COMPONENT_SET_LCL} - RawImage: TRawImage; - ImgHandle, ImgMaskHandle: HBitmap; -{$ENDIF} -begin - PF := DataFormatToPixelFormat(Data.Format); - GetImageFormatInfo(Data.Format, Info); - - if (PF = pf8bit) and PaletteHasAlpha(Data.Palette, Info.PaletteEntries) then - begin - // Some indexed images may have valid alpha data, dont lose it! - // (e.g. transparent 8bit PNG or GIF images) - PF := pfCustom; - end; - - if PF = pfCustom then - begin - // Convert from formats not supported by Graphics unit - Imaging.InitImage(WorkData); - Imaging.CloneImage(Data, WorkData); - if Info.IsFloatingPoint or Info.HasAlphaChannel or Info.IsSpecial then - Imaging.ConvertImage(WorkData, ifA8R8G8B8) - else - begin -{$IFDEF COMPONENT_SET_VCL} - if Info.IsIndexed or Info.HasGrayChannel then - Imaging.ConvertImage(WorkData, ifIndex8) - else if Info.UsePixelFormat then - Imaging.ConvertImage(WorkData, ifR5G6B5) - else - Imaging.ConvertImage(WorkData, ifR8G8B8); -{$ELSE} - Imaging.ConvertImage(WorkData, ifA8R8G8B8); -{$ENDIF} - end; - - PF := DataFormatToPixelFormat(WorkData.Format); - GetImageFormatInfo(WorkData.Format, Info); - end - else - WorkData := Data; - - if PF = pfCustom then - RaiseImaging(SBadFormatDataToBitmap, [ImageToStr(WorkData)]); - - LineBytes := WorkData.Width * Info.BytesPerPixel; - -{$IFDEF COMPONENT_SET_VCL} - Bitmap.Width := WorkData.Width; - Bitmap.Height := WorkData.Height; - Bitmap.PixelFormat := PF; - - if (PF = pf8bit) and (WorkData.Palette <> nil) then - begin - // Copy palette, this must be done before copying bits - FillChar(LogPalette, SizeOf(LogPalette), 0); - LogPalette.palVersion := $300; - LogPalette.palNumEntries := Info.PaletteEntries; - for I := 0 to Info.PaletteEntries - 1 do - with LogPalette do - begin - palPalEntry[I].peRed := WorkData.Palette[I].R; - palPalEntry[I].peGreen := WorkData.Palette[I].G; - palPalEntry[I].peBlue := WorkData.Palette[I].B; - end; - Bitmap.Palette := CreatePalette(PLogPalette(@LogPalette)^); - end; - // Copy scanlines - for I := 0 to WorkData.Height - 1 do - Move(PByteArray(WorkData.Bits)[I * LineBytes], Bitmap.Scanline[I]^, LineBytes); - - // Delphi 2009 and newer support alpha transparency fro TBitmap -{$IF Defined(DELPHI) and (CompilerVersion >= 20.0)} - if Bitmap.PixelFormat = pf32bit then - Bitmap.AlphaFormat := afDefined; -{$IFEND} - -{$ENDIF} -{$IFDEF COMPONENT_SET_LCL} - // Create 32bit raw image from image data - FillChar(RawImage, SizeOf(RawImage), 0); - with RawImage.Description do - begin - Width := WorkData.Width; - Height := WorkData.Height; - BitsPerPixel := 32; - Format := ricfRGBA; - LineEnd := rileDWordBoundary; - BitOrder := riboBitsInOrder; - ByteOrder := riboLSBFirst; - LineOrder := riloTopToBottom; - AlphaPrec := 8; - RedPrec := 8; - GreenPrec := 8; - BluePrec := 8; - AlphaShift := 24; - RedShift := 16; - GreenShift := 8; - BlueShift := 0; - Depth := 32; // Must be 32 for alpha blending (and for working in MacOSX Carbon) - end; - RawImage.Data := WorkData.Bits; - RawImage.DataSize := WorkData.Size; - - // Create bitmap from raw image - if RawImage_CreateBitmaps(RawImage, ImgHandle, ImgMaskHandle) then - begin - Bitmap.Handle := ImgHandle; - Bitmap.MaskHandle := ImgMaskHandle; - end; -{$ENDIF} - if WorkData.Bits <> Data.Bits then - Imaging.FreeImage(WorkData); -end; - -procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData); -var - I, LineBytes: LongInt; - Format: TImageFormat; - Info: TImageFormatInfo; -{$IFDEF COMPONENT_SET_VCL} - Colors: Word; - LogPalette: TMaxLogPalette; -{$ENDIF} -{$IFDEF COMPONENT_SET_LCL} - RawImage: TRawImage; - LineLazBytes: LongInt; -{$ENDIF} -begin -{$IFDEF COMPONENT_SET_LCL} - // In the current Lazarus 0.9.10 Bitmap.PixelFormat property is useless. - // We cannot change bitmap's format by changing it (it will just release - // old image but not convert it to new format) nor we can determine bitmaps's - // current format (it is usually set to pfDevice). So bitmap's format is obtained - // trough RawImage api and cannot be changed to mirror some Imaging format - // (so formats with no coresponding Imaging format cannot be saved now). - - if RawImage_DescriptionFromBitmap(Bitmap.Handle, RawImage.Description) then - case RawImage.Description.BitsPerPixel of - 8: Format := ifIndex8; - 16: - if RawImage.Description.Depth = 15 then - Format := ifA1R5G5B5 - else - Format := ifR5G6B5; - 24: Format := ifR8G8B8; - 32: Format := ifA8R8G8B8; - 48: Format := ifR16G16B16; - 64: Format := ifA16R16G16B16; - else - Format := ifUnknown; - end; -{$ELSE} - Format := PixelFormatToDataFormat(Bitmap.PixelFormat); - if Format = ifUnknown then - begin - // Convert from formats not supported by Imaging (1/4 bit) - if Bitmap.PixelFormat < pf8bit then - Bitmap.PixelFormat := pf8bit - else - Bitmap.PixelFormat := pf32bit; - Format := PixelFormatToDataFormat(Bitmap.PixelFormat); - end; -{$ENDIF} - - if Format = ifUnknown then - RaiseImaging(SBadFormatBitmapToData, []); - - Imaging.NewImage(Bitmap.Width, Bitmap.Height, Format, Data); - GetImageFormatInfo(Data.Format, Info); - LineBytes := Data.Width * Info.BytesPerPixel; - -{$IFDEF COMPONENT_SET_VCL} - if (Format = ifIndex8) and (GetObject(Bitmap.Palette, SizeOf(Colors), - @Colors) <> 0) then - begin - // Copy palette - GetPaletteEntries(Bitmap.Palette, 0, Colors, LogPalette.palPalEntry); - if Colors > Info.PaletteEntries then - Colors := Info.PaletteEntries; - for I := 0 to Colors - 1 do - with LogPalette do - begin - Data.Palette[I].A := $FF; - Data.Palette[I].R := palPalEntry[I].peRed; - Data.Palette[I].G := palPalEntry[I].peGreen; - Data.Palette[I].B := palPalEntry[I].peBlue; - end; - end; - // Copy scanlines - for I := 0 to Data.Height - 1 do - Move(Bitmap.ScanLine[I]^, PByteArray(Data.Bits)[I * LineBytes], LineBytes); -{$ENDIF} -{$IFDEF COMPONENT_SET_LCL} - // Get raw image from bitmap (mask handle must be 0 or expect violations) - if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, nil) then - begin - LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel, - RawImage.Description.LineEnd); - // Copy scanlines - for I := 0 to Data.Height - 1 do - begin - Move(PByteArray(RawImage.Data)[I * LineLazBytes], - PByteArray(Data.Bits)[I * LineBytes], LineBytes); - end; - // May need to swap RB order, depends on wifget set - if RawImage.Description.BlueShift > RawImage.Description.RedShift then - SwapChannels(Data, ChannelRed, ChannelBlue); - - RawImage.FreeData; - end; -{$ENDIF} -end; - -procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap); -begin - ConvertDataToBitmap(Image.ImageDataPointer^, Bitmap); -end; - -procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage); -begin - ConvertBitmapToData(Bitmap, Image.ImageDataPointer^); -end; - -{$IFDEF MSWINDOWS} -procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); -var - OldMode: Integer; - BitmapInfo: Windows.TBitmapInfo; - Bmp: TBitmap; -begin - if TestImage(ImageData) then - begin - Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay); - OldMode := Windows.SetStretchBltMode(DC, COLORONCOLOR); - - FillChar(BitmapInfo, SizeOf(BitmapInfo), 0); - with BitmapInfo.bmiHeader do - begin - biSize := SizeOf(TBitmapInfoHeader); - biPlanes := 1; - biBitCount := 32; - biCompression := BI_RGB; - biWidth := ImageData.Width; - biHeight := -ImageData.Height; - biSizeImage := ImageData.Size; - biXPelsPerMeter := 0; - biYPelsPerMeter := 0; - biClrUsed := 0; - biClrImportant := 0; - end; - - try - with SrcRect, ImageData do - if Windows.StretchDIBits(DC, DstRect.Left, DstRect.Top, - DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Left, - Top, Right - Left, Bottom - Top, Bits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY) <> Height then - begin - // StretchDIBits may fail on some ocassions (error 487, http://support.microsoft.com/kb/269585). - // This fallback is slow but works every time. Thanks to Sergey Galezdinov for the fix. - Bmp := TBitmap.Create; - try - ConvertDataToBitmap(ImageData, Bmp); - StretchBlt(DC, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, - Bmp.Canvas.Handle, 0, 0, Width, Height, SRCCOPY); - finally - Bmp.Free; - end; - end; - finally - Windows.SetStretchBltMode(DC, OldMode); - end; - end; -end; -{$ENDIF} - -procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); -{$IF Defined(DCC) or Defined(LCLWIN32)} // Delphi or LCL Win32 -begin - DisplayImageDataOnDC(DstCanvas.Handle, DstRect, ImageData, SrcRect); -end; -{$ELSEIF Defined(LCLGTK2)} - type - TDeviceContext = TGtk2DeviceContext; - - procedure GDKDrawBitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, - SrcWidth, SrcHeight: Integer; ImageData: TImageData); - var - P: TPoint; - begin - P := TDeviceContext(Dest).Offset; - Inc(DstX, P.X); - Inc(DstY, P.Y); - gdk_draw_rgb_32_image(TDeviceContext(Dest).Drawable, TDeviceContext(Dest).GC, - DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE, - @PLongWordArray(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4); - end; - -var - DisplayImage: TImageData; - NewWidth, NewHeight: Integer; - SrcBounds, DstBounds, DstClip: TRect; -begin - if TestImage(ImageData) then - begin - Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay); - InitImage(DisplayImage); - - SrcBounds := RectToBounds(SrcRect); - DstBounds := RectToBounds(DstRect); - WidgetSet.GetClipBox(DstCanvas.Handle, @DstClip); - - ClipStretchBounds(SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, SrcBounds.Bottom, - DstBounds.Left, DstBounds.Top, DstBounds.Right, DstBounds.Bottom, ImageData.Width, - ImageData.Height, DstClip); - - NewWidth := DstBounds.Right; - NewHeight := DstBounds.Bottom; - - if (NewWidth > 0) and (NewHeight > 0) then - begin - if (SrcBounds.Right = NewWidth) and (SrcBounds.Bottom = NewHeight) then - try - CloneImage(ImageData, DisplayImage); - // Swap R-B channels for GTK display compatability! - SwapChannels(DisplayImage, ChannelRed, ChannelBlue); - GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, - SrcBounds.Left, SrcBounds.Top, NewWidth, NewHeight, DisplayImage); - finally - FreeImage(DisplayImage); - end - else - try - // Create new image with desired dimensions - NewImage(NewWidth, NewHeight, ImageData.Format, DisplayImage); - // Stretch pixels from old image to new one TResizeFilter = (rfNearest, rfBilinear, rfBicubic); - StretchRect(ImageData, SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, - SrcBounds.Bottom, DisplayImage, 0, 0, NewWidth, NewHeight, rfNearest); - // Swap R-B channels for GTK display compatability! - SwapChannels(DisplayImage, ChannelRed, ChannelBlue); - GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, 0, 0, - NewWidth, NewHeight, DisplayImage); - finally - FreeImage(DisplayImage); - end - end; - end; -end; -{$ELSE} -begin - raise Exception.Create(SUnsupportedLCLWidgetSet); -end; -{$IFEND} - -procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); -begin - DisplayImageData(DstCanvas, BoundsToRect(DstX, DstY, Image.Width, Image.Height), - Image.ImageDataPointer^, Image.BoundsRect); -end; - -procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); -begin - DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, Image.BoundsRect); -end; - -procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); -begin - DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, SrcRect); -end; - - -{ TImagingGraphic class implementation } - -constructor TImagingGraphic.Create; -begin - inherited Create; - PixelFormat := pf24Bit; -end; - -procedure TImagingGraphic.LoadFromStream(Stream: TStream); -begin - ReadDataFromStream(Stream); -end; - -procedure TImagingGraphic.ReadDataFromStream(Stream: TStream); -var - Image: TSingleImage; -begin - Image := TSingleImage.Create; - try - Image.LoadFromStream(Stream); - Assign(Image); - finally - Image.Free; - end; -end; - -procedure TImagingGraphic.AssignTo(Dest: TPersistent); -var - Arr: TDynImageDataArray; -begin - if Dest is TSingleImage then - begin - AssignToImage(TSingleImage(Dest)) - end - else if Dest is TMultiImage then - begin - SetLength(Arr, 1); - AssignToImageData(Arr[0]); - TMultiImage(Dest).CreateFromArray(Arr); - Imaging.FreeImagesInArray(Arr); - end - else - inherited AssignTo(Dest); -end; - -procedure TImagingGraphic.Assign(Source: TPersistent); -begin - if Source is TBaseImage then - AssignFromImage(TBaseImage(Source)) - else - inherited Assign(Source); -end; - -procedure TImagingGraphic.AssignFromImage(Image: TBaseImage); -begin - if (Image <> nil) and Image.Valid then - AssignFromImageData(Image.ImageDataPointer^); -end; - -procedure TImagingGraphic.AssignToImage(Image: TBaseImage); -begin - if (Image <> nil) and (Image.ImageDataPointer <> nil) then - AssignToImageData(Image.ImageDataPointer^); -end; - -procedure TImagingGraphic.AssignFromImageData(const ImageData: TImageData); -begin - if Imaging.TestImage(ImageData) then - ConvertDataToBitmap(ImageData, Self); -end; - -procedure TImagingGraphic.AssignToImageData(var ImageData: TImageData); -begin - Imaging.FreeImage(ImageData); - ConvertBitmapToData(Self, ImageData); -end; - - -{ TImagingGraphicForSave class implementation } - -constructor TImagingGraphicForSave.Create; -begin - inherited Create; - FDefaultFileExt := GetFileFormat.Extensions[0]; - FSavingFormat := ifUnknown; - GetFileFormat.CheckOptionsValidity; -end; - -procedure TImagingGraphicForSave.WriteDataToStream(Stream: TStream); -var - Image: TSingleImage; -begin - if FDefaultFileExt <> '' then - begin - Image := TSingleImage.Create; - try - Image.Assign(Self); - if FSavingFormat <> ifUnknown then - Image.Format := FSavingFormat; - Image.SaveToStream(FDefaultFileExt, Stream); - finally - Image.Free; - end; - end; -end; - -procedure TImagingGraphicForSave.SaveToStream(Stream: TStream); -begin - WriteDataToStream(Stream); -end; - -{$IFDEF COMPONENT_SET_LCL} -class function TImagingGraphicForSave.GetFileExtensions: string; -begin - Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]); -end; - -function TImagingGraphicForSave.GetMimeType: string; -begin - Result := 'image/' + FDefaultFileExt; -end; -{$ENDIF} - -{$IFNDEF DONT_LINK_BITMAP} - -{ TImagingBitmap class implementation } - -constructor TImagingBitmap.Create; -begin - inherited Create; - FUseRLE := (GetFileFormat as TBitmapFileFormat).UseRLE; -end; - -class function TImagingBitmap.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TBitmapFileFormat); -end; - -procedure TImagingBitmap.SaveToStream(Stream: TStream); -begin - Imaging.PushOptions; - Imaging.SetOption(ImagingBitmapRLE, Ord(FUseRLE)); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; -{$ENDIF} - -{$IFNDEF DONT_LINK_JPEG} - -{ TImagingJpeg class implementation } - -constructor TImagingJpeg.Create; -begin - inherited Create; - FQuality := (GetFileFormat as TJpegFileFormat).Quality; - FProgressive := (GetFileFormat as TJpegFileFormat).Progressive; -end; - -class function TImagingJpeg.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TJpegFileFormat); -end; - -{$IFDEF COMPONENT_SET_LCL} -function TImagingJpeg.GetMimeType: string; -begin - Result := 'image/jpeg'; -end; -{$ENDIF} - -procedure TImagingJpeg.SaveToStream(Stream: TStream); -begin - Imaging.PushOptions; - Imaging.SetOption(ImagingJpegQuality, FQuality); - Imaging.SetOption(ImagingJpegProgressive, Ord(FProgressive)); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; - -{$ENDIF} - -{$IFNDEF DONT_LINK_PNG} - -{ TImagingPNG class implementation } - -constructor TImagingPNG.Create; -begin - inherited Create; - FPreFilter := (GetFileFormat as TPNGFileFormat).PreFilter; - FCompressLevel := (GetFileFormat as TPNGFileFormat).CompressLevel; -end; - -class function TImagingPNG.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TPNGFileFormat); -end; - -procedure TImagingPNG.SaveToStream(Stream: TStream); -begin - Imaging.PushOptions; - Imaging.SetOption(ImagingPNGPreFilter, FPreFilter); - Imaging.SetOption(ImagingPNGCompressLevel, FCompressLevel); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; -{$ENDIF} - -{$IFNDEF DONT_LINK_GIF} - -{ TImagingGIF class implementation} - -class function TImagingGIF.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TGIFFileFormat); -end; - -{$ENDIF} - -{$IFNDEF DONT_LINK_TARGA} - -{ TImagingTarga class implementation } - -constructor TImagingTarga.Create; -begin - inherited Create; - FUseRLE := (GetFileFormat as TTargaFileFormat).UseRLE; -end; - -class function TImagingTarga.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TTargaFileFormat); -end; - -procedure TImagingTarga.SaveToStream(Stream: TStream); -begin - Imaging.PushOptions; - Imaging.SetOption(ImagingTargaRLE, Ord(FUseRLE)); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; -{$ENDIF} - -{$IFNDEF DONT_LINK_DDS} - -{ TImagingDDS class implementation } - -constructor TImagingDDS.Create; -begin - inherited Create; - FCompression := dcNone; -end; - -class function TImagingDDS.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TDDSFileFormat); -end; - -procedure TImagingDDS.SaveToStream(Stream: TStream); -begin - case FCompression of - dcNone: FSavingFormat := ifUnknown; - dcDXT1: FSavingFormat := ifDXT1; - dcDXT3: FSavingFormat := ifDXT3; - dcDXT5: FSavingFormat := ifDXT5; - end; - Imaging.PushOptions; - Imaging.SetOption(ImagingDDSSaveCubeMap, Ord(False)); - Imaging.SetOption(ImagingDDSSaveVolume, Ord(False)); - Imaging.SetOption(ImagingDDSSaveMipMapCount, 1); - Imaging.SetOption(ImagingDDSSaveDepth, 1); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; -{$ENDIF} - -{$IFNDEF DONT_LINK_MNG} - -{ TImagingMNG class implementation } - -constructor TImagingMNG.Create; -begin - inherited Create; - FLossyCompression := (GetFileFormat as TMNGFileFormat).LossyCompression; - FLossyAlpha := (GetFileFormat as TMNGFileFormat).LossyAlpha; - FPreFilter := (GetFileFormat as TMNGFileFormat).PreFilter; - FCompressLevel := (GetFileFormat as TMNGFileFormat).CompressLevel; - FQuality := (GetFileFormat as TMNGFileFormat).Quality; - FProgressive := (GetFileFormat as TMNGFileFormat).Progressive; -end; - -class function TImagingMNG.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TMNGFileFormat); -end; - -{$IFDEF COMPONENT_SET_LCL} -function TImagingMNG.GetMimeType: string; -begin - Result := 'video/mng'; -end; -{$ENDIF} - -procedure TImagingMNG.SaveToStream(Stream: TStream); -begin - Imaging.PushOptions; - Imaging.SetOption(ImagingMNGLossyCompression, Ord(FLossyCompression)); - Imaging.SetOption(ImagingMNGLossyAlpha, Ord(FLossyAlpha)); - Imaging.SetOption(ImagingMNGPreFilter, FPreFilter); - Imaging.SetOption(ImagingMNGCompressLevel, FCompressLevel); - Imaging.SetOption(ImagingMNGQuality, FQuality); - Imaging.SetOption(ImagingMNGProgressive, Ord(FProgressive)); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; -{$ENDIF} - -{$IFNDEF DONT_LINK_JNG} - -{ TImagingJNG class implementation } - -constructor TImagingJNG.Create; -begin - inherited Create; - FLossyAlpha := (GetFileFormat as TJNGFileFormat).LossyAlpha; - FAlphaPreFilter := (GetFileFormat as TJNGFileFormat).PreFilter; - FAlphaCompressLevel := (GetFileFormat as TJNGFileFormat).CompressLevel; - FQuality := (GetFileFormat as TJNGFileFormat).Quality; - FProgressive := (GetFileFormat as TJNGFileFormat).Progressive; -end; - -class function TImagingJNG.GetFileFormat: TImageFileFormat; -begin - Result := FindImageFileFormatByClass(TJNGFileFormat); -end; - -procedure TImagingJNG.SaveToStream(Stream: TStream); -begin - Imaging.PushOptions; - Imaging.SetOption(ImagingJNGLossyALpha, Ord(FLossyAlpha)); - Imaging.SetOption(ImagingJNGAlphaPreFilter, FAlphaPreFilter); - Imaging.SetOption(ImagingJNGAlphaCompressLevel, FAlphaCompressLevel); - Imaging.SetOption(ImagingJNGQuality, FQuality); - Imaging.SetOption(ImagingJNGProgressive, Ord(FProgressive)); - inherited SaveToStream(Stream); - Imaging.PopOptions; -end; -{$ENDIF} - -initialization - RegisterTypes; -finalization - UnRegisterTypes; - -{$IFEND} // {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)} - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 --------------------------------------------------- - - Fixed bug in ConvertBitmapToData causing images from GTK2 bitmaps - to have swapped RB channels. - - LCL: Removed GTK1 support (deprecated). - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Transparency of 8bit images (like loaded from 8bit PNG or GIF) is - kept intact during conversion to TBitmap in ConvertDataToBitmap - (32bit bitmap is created). - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Setting AlphaFormat property of TBitmap in ConvertDataToBitmap - when using Delphi 2009+. - - Fixed garbled LCL TBitmaps created by ConvertDataToBitmap - in Mac OS X (Carbon). - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - Added some more IFDEFs for Lazarus widget sets. - - Removed CLX code. - - GTK version of Unix DisplayImageData only used with LCL GTK so the - the rest of the unit can be used with Qt or other LCL interfaces. - - Fallback mechanism for DisplayImageDataOnDC, it may fail on occasions. - - Changed file format conditional compilation to reflect changes - in LINK symbols. - - Lazarus 0.9.26 compatibility changes. - - -- 0.24.1 Changes/Bug Fixes --------------------------------- - - Fixed wrong IFDEF causing that Imaging wouldn't compile in Lazarus - with GTK2 target. - - Added commnets with code for Lazarus rev. 11861+ regarding - RawImage interface. Replace current code with that in comments - if you use Lazarus from SVN. New RawImage interface will be used by - default after next Lazarus release. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added TImagingGIF. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Uses only high level interface now (except for saving options). - - Slightly changed class hierarchy. TImagingGraphic is now only for loading - and base class for savers is new TImagingGraphicForSave. Also - TImagingGraphic is now registered with all supported file formats - by TPicture's format support. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - added DisplayImage procedures (thanks to Paul Michell, modified) - - removed RegisterTypes and UnRegisterTypes from interface section, - they are called automatically - - added procedures: ConvertImageToBitmap and ConvertBitmapToImage - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - LCL data to bitmap conversion didn�t work in Linux, fixed - - added MNG file format - - added JNG file format - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - made it LCL compatible - - made it CLX compatible - - added all initial stuff -} - -end. - diff --git a/3rd/Imaging/Source/ImagingDds.pas b/3rd/Imaging/Source/ImagingDds.pas deleted file mode 100644 index 9bcee5aac..000000000 --- a/3rd/Imaging/Source/ImagingDds.pas +++ /dev/null @@ -1,1145 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for DirectDraw Surface images.} -unit ImagingDds; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingUtility, ImagingFormats; - -type - { Class for loading and saving Microsoft DirectDraw surfaces. - It can load/save all D3D formats which have coresponding - TImageFormat. It supports plain textures, cube textures and - volume textures, all of these can have mipmaps. It can also - load some formats which have no exact TImageFormat, but can be easily - converted to one (bump map formats, etc.). - You can get some information about last loaded DDS file by calling - GetOption with ImagingDDSLoadedXXX options and you can set some - saving options by calling SetOption with ImagingDDSSaveXXX or you can - simply use properties of this class. - Note that when saving cube maps and volumes input image array must contain - at least number of images to build cube/volume based on current - Depth and MipMapCount settings.} - TDDSFileFormat = class(TImageFileFormat) - private - FLoadedCubeMap: LongBool; - FLoadedVolume: LongBool; - FLoadedMipMapCount: LongInt; - FLoadedDepth: LongInt; - FSaveCubeMap: LongBool; - FSaveVolume: LongBool; - FSaveMipMapCount: LongInt; - FSaveDepth: LongInt; - procedure ComputeSubDimensions(Idx, Width, Height, MipMaps, Depth: LongInt; - IsCubeMap, IsVolume: Boolean; var CurWidth, CurHeight: LongInt); - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - procedure CheckOptionsValidity; override; - published - { True if last loaded DDS file was cube map.} - property LoadedCubeMap: LongBool read FLoadedCubeMap write FLoadedCubeMap; - { True if last loaded DDS file was volume texture.} - property LoadedVolume: LongBool read FLoadedVolume write FLoadedVolume; - { Number of mipmap levels of last loaded DDS image.} - property LoadedMipMapCount: LongInt read FLoadedMipMapCount write FLoadedMipMapCount; - { Depth (slices of volume texture or faces of cube map) of last loaded DDS image.} - property LoadedDepth: LongInt read FLoadedDepth write FLoadedDepth; - { True if next DDS file to be saved should be stored as cube map.} - property SaveCubeMap: LongBool read FSaveCubeMap write FSaveCubeMap; - { True if next DDS file to be saved should be stored as volume texture.} - property SaveVolume: LongBool read FSaveVolume write FSaveVolume; - { Sets the number of mipmaps which should be stored in the next saved DDS file. - Only applies to cube maps and volumes, ordinary 2D textures save all - levels present in input.} - property SaveMipMapCount: LongInt read FSaveMipMapCount write FSaveMipMapCount; - { Sets the depth (slices of volume texture or faces of cube map) - of the next saved DDS file.} - property SaveDepth: LongInt read FSaveDepth write FSaveDepth; - end; - -const - { DDS related metadata Ids } - - { DXGI format of textures stored in DDS files with DX10 extension. Type is - Enum (value corresponding to DXGI_FORMAT enum from DX SDK).} - SMetaDdsDxgiFormat = 'DdsDxgiFormat'; - { Number of mipmaps for each main image in DDS file.} - SMetaDdsMipMapCount = 'DdsMipMapCount'; - { Texture array size stored in DDS file (DX10 extension).} - SMetaDdsArraySize = 'DdsArraySize'; - -implementation - -const - SDDSFormatName = 'DirectDraw Surface'; - SDDSMasks = '*.dds'; - DDSSupportedFormats: TImageFormats = [ifR8G8B8, ifA8R8G8B8, ifX8R8G8B8, - ifA1R5G5B5, ifA4R4G4B4, ifX1R5G5B5, ifX4R4G4B4, ifR5G6B5, ifA16B16G16R16, - ifR32F, ifA32B32G32R32F, ifR16F, ifA16B16G16R16F, ifR3G3B2, ifGray8, ifA8Gray8, - ifGray16, ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N]; - -const - { Four character codes.} - DDSMagic = LongWord(Byte('D') or (Byte('D') shl 8) or (Byte('S') shl 16) or - (Byte(' ') shl 24)); - FOURCC_DXT1 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or - (Byte('1') shl 24)); - FOURCC_DXT3 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or - (Byte('3') shl 24)); - FOURCC_DXT5 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or - (Byte('5') shl 24)); - FOURCC_ATI1 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or - (Byte('1') shl 24)); - FOURCC_ATI2 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or - (Byte('2') shl 24)); - FOURCC_DX10 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('1') shl 16) or - (Byte('0') shl 24)); - - { Some D3DFORMAT values used in DDS files as FourCC value.} - D3DFMT_A16B16G16R16 = 36; - D3DFMT_R32F = 114; - D3DFMT_A32B32G32R32F = 116; - D3DFMT_R16F = 111; - D3DFMT_A16B16G16R16F = 113; - - { Constans used by TDDSurfaceDesc2.Flags.} - DDSD_CAPS = $00000001; - DDSD_HEIGHT = $00000002; - DDSD_WIDTH = $00000004; - DDSD_PITCH = $00000008; - DDSD_PIXELFORMAT = $00001000; - DDSD_MIPMAPCOUNT = $00020000; - DDSD_LINEARSIZE = $00080000; - DDSD_DEPTH = $00800000; - - { Constans used by TDDSPixelFormat.Flags.} - DDPF_ALPHAPIXELS = $00000001; // used by formats which contain alpha - DDPF_FOURCC = $00000004; // used by DXT and large ARGB formats - DDPF_RGB = $00000040; // used by RGB formats - DDPF_LUMINANCE = $00020000; // used by formats like D3DFMT_L16 - DDPF_BUMPLUMINANCE = $00040000; // used by mixed signed-unsigned formats - DDPF_BUMPDUDV = $00080000; // used by signed formats - - { Constans used by TDDSCaps.Caps1.} - DDSCAPS_COMPLEX = $00000008; - DDSCAPS_TEXTURE = $00001000; - DDSCAPS_MIPMAP = $00400000; - - { Constans used by TDDSCaps.Caps2.} - DDSCAPS2_CUBEMAP = $00000200; - DDSCAPS2_POSITIVEX = $00000400; - DDSCAPS2_NEGATIVEX = $00000800; - DDSCAPS2_POSITIVEY = $00001000; - DDSCAPS2_NEGATIVEY = $00002000; - DDSCAPS2_POSITIVEZ = $00004000; - DDSCAPS2_NEGATIVEZ = $00008000; - DDSCAPS2_VOLUME = $00200000; - - { Flags for TDDSurfaceDesc2.Flags used when saving DDS file.} - DDS_SAVE_FLAGS = DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or - DDSD_HEIGHT or DDSD_LINEARSIZE; - -type - { Stores the pixel format information.} - TDDPixelFormat = packed record - Size: LongWord; // Size of the structure = 32 bytes - Flags: LongWord; // Flags to indicate valid fields - FourCC: LongWord; // Four-char code for compressed textures (DXT) - BitCount: LongWord; // Bits per pixel if uncomp. usually 16,24 or 32 - RedMask: LongWord; // Bit mask for the Red component - GreenMask: LongWord; // Bit mask for the Green component - BlueMask: LongWord; // Bit mask for the Blue component - AlphaMask: LongWord; // Bit mask for the Alpha component - end; - - { Specifies capabilities of surface.} - TDDSCaps = packed record - Caps1: LongWord; // Should always include DDSCAPS_TEXTURE - Caps2: LongWord; // For cubic environment maps - Reserved: array[0..1] of LongWord; // Reserved - end; - - { Record describing DDS file contents.} - TDDSurfaceDesc2 = packed record - Size: LongWord; // Size of the structure = 124 Bytes - Flags: LongWord; // Flags to indicate valid fields - Height: LongWord; // Height of the main image in pixels - Width: LongWord; // Width of the main image in pixels - PitchOrLinearSize: LongWord; // For uncomp formats number of bytes per - // scanline. For comp it is the size in - // bytes of the main image - Depth: LongWord; // Only for volume text depth of the volume - MipMaps: LongInt; // Total number of levels in the mipmap chain - Reserved1: array[0..10] of LongWord; // Reserved - PixelFormat: TDDPixelFormat; // Format of the pixel data - Caps: TDDSCaps; // Capabilities - Reserved2: LongWord; // Reserved - end; - - { DDS file header.} - TDDSFileHeader = packed record - Magic: LongWord; // File format magic - Desc: TDDSurfaceDesc2; // Surface description - end; - - { Resoirce types for D3D 10+ } - TD3D10ResourceDimension = ( - D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, - D3D10_RESOURCE_DIMENSION_BUFFER = 1, - D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, - D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, - D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4 - ); - - { Texture formats for D3D 10+ } - TDXGIFormat = ( - DXGI_FORMAT_UNKNOWN = 0, - DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, - DXGI_FORMAT_R32G32B32A32_FLOAT = 2, - DXGI_FORMAT_R32G32B32A32_UINT = 3, - DXGI_FORMAT_R32G32B32A32_SINT = 4, - DXGI_FORMAT_R32G32B32_TYPELESS = 5, - DXGI_FORMAT_R32G32B32_FLOAT = 6, - DXGI_FORMAT_R32G32B32_UINT = 7, - DXGI_FORMAT_R32G32B32_SINT = 8, - DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, - DXGI_FORMAT_R16G16B16A16_FLOAT = 10, - DXGI_FORMAT_R16G16B16A16_UNORM = 11, - DXGI_FORMAT_R16G16B16A16_UINT = 12, - DXGI_FORMAT_R16G16B16A16_SNORM = 13, - DXGI_FORMAT_R16G16B16A16_SINT = 14, - DXGI_FORMAT_R32G32_TYPELESS = 15, - DXGI_FORMAT_R32G32_FLOAT = 16, - DXGI_FORMAT_R32G32_UINT = 17, - DXGI_FORMAT_R32G32_SINT = 18, - DXGI_FORMAT_R32G8X24_TYPELESS = 19, - DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, - DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, - DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, - DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, - DXGI_FORMAT_R10G10B10A2_UNORM = 24, - DXGI_FORMAT_R10G10B10A2_UINT = 25, - DXGI_FORMAT_R11G11B10_FLOAT = 26, - DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, - DXGI_FORMAT_R8G8B8A8_UNORM = 28, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, - DXGI_FORMAT_R8G8B8A8_UINT = 30, - DXGI_FORMAT_R8G8B8A8_SNORM = 31, - DXGI_FORMAT_R8G8B8A8_SINT = 32, - DXGI_FORMAT_R16G16_TYPELESS = 33, - DXGI_FORMAT_R16G16_FLOAT = 34, - DXGI_FORMAT_R16G16_UNORM = 35, - DXGI_FORMAT_R16G16_UINT = 36, - DXGI_FORMAT_R16G16_SNORM = 37, - DXGI_FORMAT_R16G16_SINT = 38, - DXGI_FORMAT_R32_TYPELESS = 39, - DXGI_FORMAT_D32_FLOAT = 40, - DXGI_FORMAT_R32_FLOAT = 41, - DXGI_FORMAT_R32_UINT = 42, - DXGI_FORMAT_R32_SINT = 43, - DXGI_FORMAT_R24G8_TYPELESS = 44, - DXGI_FORMAT_D24_UNORM_S8_UINT = 45, - DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, - DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, - DXGI_FORMAT_R8G8_TYPELESS = 48, - DXGI_FORMAT_R8G8_UNORM = 49, - DXGI_FORMAT_R8G8_UINT = 50, - DXGI_FORMAT_R8G8_SNORM = 51, - DXGI_FORMAT_R8G8_SINT = 52, - DXGI_FORMAT_R16_TYPELESS = 53, - DXGI_FORMAT_R16_FLOAT = 54, - DXGI_FORMAT_D16_UNORM = 55, - DXGI_FORMAT_R16_UNORM = 56, - DXGI_FORMAT_R16_UINT = 57, - DXGI_FORMAT_R16_SNORM = 58, - DXGI_FORMAT_R16_SINT = 59, - DXGI_FORMAT_R8_TYPELESS = 60, - DXGI_FORMAT_R8_UNORM = 61, - DXGI_FORMAT_R8_UINT = 62, - DXGI_FORMAT_R8_SNORM = 63, - DXGI_FORMAT_R8_SINT = 64, - DXGI_FORMAT_A8_UNORM = 65, - DXGI_FORMAT_R1_UNORM = 66, - DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, - DXGI_FORMAT_R8G8_B8G8_UNORM = 68, - DXGI_FORMAT_G8R8_G8B8_UNORM = 69, - DXGI_FORMAT_BC1_TYPELESS = 70, - DXGI_FORMAT_BC1_UNORM = 71, - DXGI_FORMAT_BC1_UNORM_SRGB = 72, - DXGI_FORMAT_BC2_TYPELESS = 73, - DXGI_FORMAT_BC2_UNORM = 74, - DXGI_FORMAT_BC2_UNORM_SRGB = 75, - DXGI_FORMAT_BC3_TYPELESS = 76, - DXGI_FORMAT_BC3_UNORM = 77, - DXGI_FORMAT_BC3_UNORM_SRGB = 78, - DXGI_FORMAT_BC4_TYPELESS = 79, - DXGI_FORMAT_BC4_UNORM = 80, - DXGI_FORMAT_BC4_SNORM = 81, - DXGI_FORMAT_BC5_TYPELESS = 82, - DXGI_FORMAT_BC5_UNORM = 83, - DXGI_FORMAT_BC5_SNORM = 84, - DXGI_FORMAT_B5G6R5_UNORM = 85, - DXGI_FORMAT_B5G5R5A1_UNORM = 86, - DXGI_FORMAT_B8G8R8A8_UNORM = 87, - DXGI_FORMAT_B8G8R8X8_UNORM = 88, - DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, - DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, - DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, - DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, - DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, - DXGI_FORMAT_BC6H_TYPELESS = 94, - DXGI_FORMAT_BC6H_UF16 = 95, - DXGI_FORMAT_BC6H_SF16 = 96, - DXGI_FORMAT_BC7_TYPELESS = 97, - DXGI_FORMAT_BC7_UNORM = 98, - DXGI_FORMAT_BC7_UNORM_SRGB = 99, - DXGI_FORMAT_AYUV = 100, - DXGI_FORMAT_Y410 = 101, - DXGI_FORMAT_Y416 = 102, - DXGI_FORMAT_NV12 = 103, - DXGI_FORMAT_P010 = 104, - DXGI_FORMAT_P016 = 105, - DXGI_FORMAT_420_OPAQUE = 106, - DXGI_FORMAT_YUY2 = 107, - DXGI_FORMAT_Y210 = 108, - DXGI_FORMAT_Y216 = 109, - DXGI_FORMAT_NV11 = 110, - DXGI_FORMAT_AI44 = 111, - DXGI_FORMAT_IA44 = 112, - DXGI_FORMAT_P8 = 113, - DXGI_FORMAT_A8P8 = 114, - DXGI_FORMAT_B4G4R4A4_UNORM = 115 - ); - - { DX10 extension header for DDS file format } - TDX10Header = packed record - DXGIFormat: TDXGIFormat; - ResourceDimension: TD3D10ResourceDimension; - MiscFlags: LongWord; - ArraySize: LongWord; - Reserved: LongWord; - end; - -{ TDDSFileFormat class implementation } - -procedure TDDSFileFormat.Define; -begin - inherited; - FName := SDDSFormatName; - FFeatures := [ffLoad, ffSave, ffMultiImage]; - FSupportedFormats := DDSSupportedFormats; - - FSaveCubeMap := False; - FSaveVolume := False; - FSaveMipMapCount := 1; - FSaveDepth := 1; - - AddMasks(SDDSMasks); - - RegisterOption(ImagingDDSLoadedCubeMap, @FLoadedCubeMap); - RegisterOption(ImagingDDSLoadedVolume, @FLoadedVolume); - RegisterOption(ImagingDDSLoadedMipMapCount, @FLoadedMipMapCount); - RegisterOption(ImagingDDSLoadedDepth, @FLoadedDepth); - RegisterOption(ImagingDDSSaveCubeMap, @FSaveCubeMap); - RegisterOption(ImagingDDSSaveVolume, @FSaveVolume); - RegisterOption(ImagingDDSSaveMipMapCount, @FSaveMipMapCount); - RegisterOption(ImagingDDSSaveDepth, @FSaveDepth); -end; - -procedure TDDSFileFormat.CheckOptionsValidity; -begin - if FSaveCubeMap then - FSaveVolume := False; - if FSaveVolume then - FSaveCubeMap := False; - if FSaveDepth < 1 then - FSaveDepth := 1; - if FSaveMipMapCount < 1 then - FSaveMipMapCount := 1; -end; - -procedure TDDSFileFormat.ComputeSubDimensions(Idx, Width, Height, MipMaps, Depth: LongInt; - IsCubeMap, IsVolume: Boolean; var CurWidth, CurHeight: LongInt); -var - I, Last, Shift: LongInt; -begin - CurWidth := Width; - CurHeight := Height; - if MipMaps > 1 then - begin - if not IsVolume then - begin - if IsCubeMap then - begin - // Cube maps are stored like this - // Face 0 mimap 0 - // Face 0 mipmap 1 - // ... - // Face 1 mipmap 0 - // Face 1 mipmap 1 - // ... - - // Modify index so later in for loop we iterate less times - Idx := Idx - ((Idx div MipMaps) * MipMaps); - end; - for I := 0 to Idx - 1 do - begin - CurWidth := ClampInt(CurWidth shr 1, 1, CurWidth); - CurHeight := ClampInt(CurHeight shr 1, 1, CurHeight); - end; - end - else - begin - // Volume textures are stored in DDS files like this: - // Slice 0 mipmap 0 - // Slice 1 mipmap 0 - // Slice 2 mipmap 0 - // Slice 3 mipmap 0 - // Slice 0 mipmap 1 - // Slice 1 mipmap 1 - // Slice 0 mipmap 2 - // Slice 0 mipmap 3 ... - Shift := 0; - Last := Depth; - while Idx > Last - 1 do - begin - CurWidth := ClampInt(CurWidth shr 1, 1, CurWidth); - CurHeight := ClampInt(CurHeight shr 1, 1, CurHeight); - if (CurWidth = 1) and (CurHeight = 1) then - Break; - Inc(Shift); - Inc(Last, ClampInt(Depth shr Shift, 1, Depth)); - end; - end; - end; -end; - -function TDDSFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Hdr: TDDSFileHeader; - HdrDX10: TDX10Header; - SrcFormat: TImageFormat; - FmtInfo: TImageFormatInfo; - NeedsSwapChannels: Boolean; - CurrentWidth, CurrentHeight, ImageCount, LoadSize, I, - PitchOrLinear, MainImageLinearSize: Integer; - Data: PByte; - UseAsPitch: Boolean; - UseAsLinear: Boolean; - - function MasksEqual(const DDPF: TDDPixelFormat; PF: PPixelFormatInfo): Boolean; - begin - Result := (DDPF.AlphaMask = PF.ABitMask) and - (DDPF.RedMask = PF.RBitMask) and (DDPF.GreenMask = PF.GBitMask) and - (DDPF.BlueMask = PF.BBitMask); - end; - - function FindFourCCFormat(FourCC: LongWord): TImageFormat; - begin - // Handle FourCC and large ARGB formats - case FourCC of - D3DFMT_A16B16G16R16: Result := ifA16B16G16R16; - D3DFMT_R32F: Result := ifR32F; - D3DFMT_A32B32G32R32F: Result := ifA32B32G32R32F; - D3DFMT_R16F: Result := ifR16F; - D3DFMT_A16B16G16R16F: Result := ifA16B16G16R16F; - FOURCC_DXT1: Result := ifDXT1; - FOURCC_DXT3: Result := ifDXT3; - FOURCC_DXT5: Result := ifDXT5; - FOURCC_ATI1: Result := ifATI1N; - FOURCC_ATI2: Result := ifATI2N; - else - Result := ifUnknown; - end; - end; - - function FindDX10Format(DXGIFormat: TDXGIFormat; var NeedsSwapChannels: Boolean): TImageFormat; - begin - Result := ifUnknown; - NeedsSwapChannels := False; - - case DXGIFormat of - DXGI_FORMAT_UNKNOWN: ; - DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT: - Result := ifA32B32G32R32F; - DXGI_FORMAT_R32G32B32A32_UINT: ; - DXGI_FORMAT_R32G32B32A32_SINT: ; - DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT: - Result := ifB32G32R32F; - DXGI_FORMAT_R32G32B32_UINT: ; - DXGI_FORMAT_R32G32B32_SINT: ; - DXGI_FORMAT_R16G16B16A16_FLOAT: - Result := ifA16B16G16R16F; - DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM, - DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SNORM, - DXGI_FORMAT_R16G16B16A16_SINT: - Result := ifA16B16G16R16; - DXGI_FORMAT_R32G32_TYPELESS: ; - DXGI_FORMAT_R32G32_FLOAT: ; - DXGI_FORMAT_R32G32_UINT: ; - DXGI_FORMAT_R32G32_SINT: ; - DXGI_FORMAT_R32G8X24_TYPELESS: ; - DXGI_FORMAT_D32_FLOAT_S8X24_UINT: ; - DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: ; - DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: ; - DXGI_FORMAT_R10G10B10A2_TYPELESS: ; - DXGI_FORMAT_R10G10B10A2_UNORM: ; - DXGI_FORMAT_R10G10B10A2_UINT: ; - DXGI_FORMAT_R11G11B10_FLOAT: ; - DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_SNORM,DXGI_FORMAT_R8G8B8A8_SINT, - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - begin - Result := ifA8R8G8B8; - NeedsSwapChannels := True; - end; - DXGI_FORMAT_R16G16_TYPELESS: ; - DXGI_FORMAT_R16G16_FLOAT: ; - DXGI_FORMAT_R16G16_UNORM: ; - DXGI_FORMAT_R16G16_UINT: ; - DXGI_FORMAT_R16G16_SNORM: ; - DXGI_FORMAT_R16G16_SINT: ; - DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_SINT: - Result := ifGray32; - DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_R32_FLOAT: - Result := ifR32F; - DXGI_FORMAT_R24G8_TYPELESS: ; - DXGI_FORMAT_D24_UNORM_S8_UINT: ; - DXGI_FORMAT_R24_UNORM_X8_TYPELESS: ; - DXGI_FORMAT_X24_TYPELESS_G8_UINT: ; - DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UINT, - DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SINT: - Result := ifA8Gray8; - DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_R16_UNORM, - DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_SINT: - Result := ifGray16; - DXGI_FORMAT_R16_FLOAT: - Result := ifR16F; - DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UINT, - DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_A8_UNORM: - Result := ifGray8; - DXGI_FORMAT_R1_UNORM: ; - DXGI_FORMAT_R9G9B9E5_SHAREDEXP: ; - DXGI_FORMAT_R8G8_B8G8_UNORM: ; - DXGI_FORMAT_G8R8_G8B8_UNORM: ; - DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB: - Result := ifDXT1; - DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB: - Result := ifDXT3; - DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB: - Result := ifDXT5; - DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM: - Result := ifATI1N; - DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM: - Result := ifATI2N; - DXGI_FORMAT_B5G6R5_UNORM: - Result := ifR5G6B5; - DXGI_FORMAT_B5G5R5A1_UNORM: - Result := ifA1R5G5B5; - DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_TYPELESS: - Result := ifA8R8G8B8; - DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8X8_TYPELESS: - Result := ifX8R8G8B8; - DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: ; - DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: ; - DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: ; - DXGI_FORMAT_BC6H_TYPELESS: ; - DXGI_FORMAT_BC6H_UF16: ; - DXGI_FORMAT_BC6H_SF16: ; - DXGI_FORMAT_BC7_TYPELESS: ; - DXGI_FORMAT_BC7_UNORM: ; - DXGI_FORMAT_BC7_UNORM_SRGB: ; - DXGI_FORMAT_P8: ; - DXGI_FORMAT_A8P8: ; - DXGI_FORMAT_B4G4R4A4_UNORM: - Result := ifA4R4G4B4; - end; - end; - -begin - Result := False; - ImageCount := 1; - FLoadedMipMapCount := 1; - FLoadedDepth := 1; - FLoadedVolume := False; - FLoadedCubeMap := False; - ZeroMemory(@HdrDX10, SizeOf(HdrDX10)); - - with GetIO, Hdr, Hdr.Desc.PixelFormat do - begin - Read(Handle, @Hdr, SizeOf(Hdr)); - - SrcFormat := ifUnknown; - NeedsSwapChannels := False; - - // Get image data format - if (Flags and DDPF_FOURCC) = DDPF_FOURCC then - begin - if FourCC = FOURCC_DX10 then - begin - Read(Handle, @HdrDX10, SizeOf(HdrDX10)); - SrcFormat := FindDX10Format(HdrDX10.DXGIFormat, NeedsSwapChannels); - FMetadata.SetMetaItem(SMetaDdsDxgiFormat, HdrDX10.DXGIFormat); - FMetadata.SetMetaItem(SMetaDdsArraySize, HdrDX10.ArraySize); - end - else - SrcFormat := FindFourCCFormat(FourCC); - end - else if (Flags and DDPF_RGB) = DDPF_RGB then - begin - // Handle RGB formats - if (Flags and DDPF_ALPHAPIXELS) = DDPF_ALPHAPIXELS then - begin - // Handle RGB with alpha formats - case BitCount of - 16: - begin - if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifA4R4G4B4).PixelFormat) then - SrcFormat := ifA4R4G4B4; - if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifA1R5G5B5).PixelFormat) then - SrcFormat := ifA1R5G5B5; - end; - 32: - begin - SrcFormat := ifA8R8G8B8; - if BlueMask = $00FF0000 then - NeedsSwapChannels := True; - end; - end; - end - else - begin - // Handle RGB without alpha formats - case BitCount of - 8: - if MasksEqual(Desc.PixelFormat, - GetFormatInfo(ifR3G3B2).PixelFormat) then - SrcFormat := ifR3G3B2; - 16: - begin - if MasksEqual(Desc.PixelFormat, - GetFormatInfo(ifX4R4G4B4).PixelFormat) then - SrcFormat := ifX4R4G4B4; - if MasksEqual(Desc.PixelFormat, - GetFormatInfo(ifX1R5G5B5).PixelFormat) then - SrcFormat := ifX1R5G5B5; - if MasksEqual(Desc.PixelFormat, - GetFormatInfo(ifR5G6B5).PixelFormat) then - SrcFormat := ifR5G6B5; - end; - 24: SrcFormat := ifR8G8B8; - 32: - begin - SrcFormat := ifX8R8G8B8; - if BlueMask = $00FF0000 then - NeedsSwapChannels := True; - end; - end; - end; - end - else if (Flags and DDPF_LUMINANCE) = DDPF_LUMINANCE then - begin - // Handle luminance formats - if (Flags and DDPF_ALPHAPIXELS) = DDPF_ALPHAPIXELS then - begin - // Handle luminance with alpha formats - if BitCount = 16 then - SrcFormat := ifA8Gray8; - end - else - begin - // Handle luminance without alpha formats - case BitCount of - 8: SrcFormat := ifGray8; - 16: SrcFormat := ifGray16; - end; - end; - end - else if (Flags and DDPF_BUMPLUMINANCE) = DDPF_BUMPLUMINANCE then - begin - // Handle mixed bump-luminance formats like D3DFMT_X8L8V8U8 - case BitCount of - 32: - if BlueMask = $00FF0000 then - begin - SrcFormat := ifX8R8G8B8; // D3DFMT_X8L8V8U8 - NeedsSwapChannels := True; - end; - end; - end - else if (Flags and DDPF_BUMPDUDV) = DDPF_BUMPDUDV then - begin - // Handle bumpmap formats like D3DFMT_Q8W8V8U8 - case BitCount of - 16: SrcFormat := ifA8Gray8; // D3DFMT_V8U8 - 32: - if AlphaMask = $FF000000 then - begin - SrcFormat := ifA8R8G8B8; // D3DFMT_Q8W8V8U8 - NeedsSwapChannels := True; - end; - 64: SrcFormat := ifA16B16G16R16; // D3DFMT_Q16W16V16U16 - end; - end; - - // If DDS format is not supported we will exit - if SrcFormat = ifUnknown then - Exit; - - // File contains mipmaps for each subimage. - { Some DDS writers ignore setting proper Caps and Flags so - this check is not usable: - if ((Desc.Caps.Caps1 and DDSCAPS_MIPMAP) = DDSCAPS_MIPMAP) and - ((Desc.Flags and DDSD_MIPMAPCOUNT) = DDSD_MIPMAPCOUNT) then} - if Desc.MipMaps > 1 then - begin - FLoadedMipMapCount := Desc.MipMaps; - FMetadata.SetMetaItem(SMetaDdsMipMapCount, Desc.MipMaps); - ImageCount := Desc.MipMaps; - end; - - // File stores volume texture - if ((Desc.Caps.Caps2 and DDSCAPS2_VOLUME) = DDSCAPS2_VOLUME) and - ((Desc.Flags and DDSD_DEPTH) = DDSD_DEPTH) then - begin - FLoadedVolume := True; - FLoadedDepth := Desc.Depth; - ImageCount := GetVolumeLevelCount(Desc.Depth, ImageCount); - end; - - // File stores cube texture - if (Desc.Caps.Caps2 and DDSCAPS2_CUBEMAP) = DDSCAPS2_CUBEMAP then - begin - FLoadedCubeMap := True; - I := 0; - if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEX) = DDSCAPS2_POSITIVEX then Inc(I); - if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEY) = DDSCAPS2_POSITIVEY then Inc(I); - if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEZ) = DDSCAPS2_POSITIVEZ then Inc(I); - if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEX) = DDSCAPS2_NEGATIVEX then Inc(I); - if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEY) = DDSCAPS2_NEGATIVEY then Inc(I); - if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEZ) = DDSCAPS2_NEGATIVEZ then Inc(I); - FLoadedDepth := I; - ImageCount := ImageCount * I; - end; - - // Allocate and load all images in file - FmtInfo := GetFormatInfo(SrcFormat); - SetLength(Images, ImageCount); - - // Compute the pitch or get if from file if present - UseAsPitch := (Desc.Flags and DDSD_PITCH) = DDSD_PITCH; - UseAsLinear := (Desc.Flags and DDSD_LINEARSIZE) = DDSD_LINEARSIZE; - // Use linear as default if none is set - if not UseAsPitch and not UseAsLinear then - UseAsLinear := True; - // Main image pitch or linear size - PitchOrLinear := Desc.PitchOrLinearSize; - - // Check: some writers just write garbage to pitch/linear size fields and flags - MainImageLinearSize := FmtInfo.GetPixelsSize(SrcFormat, Desc.Width, Desc.Height); - if UseAsLinear and ((PitchOrLinear < MainImageLinearSize) or - (PitchOrLinear * Integer(Desc.Height) = MainImageLinearSize)) then - begin - // Explicitly set linear size - PitchOrLinear := MainImageLinearSize; - end; - - for I := 0 to ImageCount - 1 do - begin - // Compute dimensions of surrent subimage based on texture type and - // number of mipmaps - ComputeSubDimensions(I, Desc.Width, Desc.Height, Desc.MipMaps, Desc.Depth, - FLoadedCubeMap, FLoadedVolume, CurrentWidth, CurrentHeight); - NewImage(CurrentWidth, CurrentHeight, SrcFormat, Images[I]); - - if (I > 0) or (PitchOrLinear = 0) then - begin - // Compute pitch or linear size for mipmap levels, or even for main image - // since some formats do not fill pitch nor size - if UseAsLinear then - PitchOrLinear := FmtInfo.GetPixelsSize(SrcFormat, CurrentWidth, CurrentHeight) - else - PitchOrLinear := (CurrentWidth * FmtInfo.BytesPerPixel + 3) div 4 * 4; // must be DWORD aligned - end; - - if UseAsLinear then - LoadSize := PitchOrLinear - else - LoadSize := CurrentHeight * PitchOrLinear; - - if UseAsLinear or (LoadSize = Images[I].Size) then - begin - // If DDS does not use Pitch we can simply copy data - Read(Handle, Images[I].Bits, LoadSize) - end - else - begin - // If DDS uses Pitch we must load aligned scanlines - // and then remove padding - GetMem(Data, LoadSize); - try - Read(Handle, Data, LoadSize); - RemovePadBytes(Data, Images[I].Bits, CurrentWidth, CurrentHeight, - FmtInfo.BytesPerPixel, PitchOrLinear); - finally - FreeMem(Data); - end; - end; - - if NeedsSwapChannels then - SwapChannels(Images[I], ChannelRed, ChannelBlue); - end; - Result := True; - end; -end; - -function TDDSFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - Hdr: TDDSFileHeader; - MainImage, ImageToSave: TImageData; - I, MainIdx, Len, ImageCount: LongInt; - J: LongWord; - FmtInfo: TImageFormatInfo; - MustBeFreed: Boolean; - Is2DTexture, IsCubeMap, IsVolume: Boolean; - MipMapCount, CurrentWidth, CurrentHeight: LongInt; - NeedsResize: Boolean; - NeedsConvert: Boolean; -begin - Result := False; - FillChar(Hdr, Sizeof(Hdr), 0); - - MainIdx := FFirstIdx; - Len := FLastIdx - MainIdx + 1; - // Some DDS saving rules: - // 2D textures: Len is used as mipmap count (FSaveMipMapCount not used!). - // Cube maps: FSaveDepth * FSaveMipMapCount images are used, if Len is - // smaller than this file is saved as regular 2D texture. - // Volume maps: GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) images are - // used, if Len is smaller than this file is - // saved as regular 2D texture. - - IsCubeMap := FSaveCubeMap; - IsVolume := FSaveVolume; - MipMapCount := FSaveMipMapCount; - - if IsCubeMap then - begin - // Check if we have enough images on Input to save cube map - if Len < FSaveDepth * FSaveMipMapCount then - IsCubeMap := False; - end - else if IsVolume then - begin - // Check if we have enough images on Input to save volume texture - if Len < GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) then - IsVolume := False; - end; - - Is2DTexture := not IsCubeMap and not IsVolume; - if Is2DTexture then - begin - // Get number of mipmaps used with 2D texture - MipMapCount := Min(Len, GetNumMipMapLevels(Images[MainIdx].Width, Images[MainIdx].Height)); - end; - - // we create compatible main image and fill headers - if MakeCompatible(Images[MainIdx], MainImage, MustBeFreed) then - with GetIO, MainImage, Hdr do - try - FmtInfo := GetFormatInfo(Format); - Magic := DDSMagic; - Desc.Size := SizeOf(Desc); - Desc.Width := Width; - Desc.Height := Height; - Desc.Flags := DDS_SAVE_FLAGS; - Desc.Caps.Caps1 := DDSCAPS_TEXTURE; - Desc.PixelFormat.Size := SizeOf(Desc.PixelFormat); - Desc.PitchOrLinearSize := MainImage.Size; - ImageCount := MipMapCount; - - if MipMapCount > 1 then - begin - // Set proper flags if we have some mipmaps to be saved - Desc.Flags := Desc.Flags or DDSD_MIPMAPCOUNT; - Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_MIPMAP or DDSCAPS_COMPLEX; - Desc.MipMaps := MipMapCount; - end; - - if IsCubeMap then - begin - // Set proper cube map flags - number of stored faces is taken - // from FSaveDepth - Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_COMPLEX; - Desc.Caps.Caps2 := Desc.Caps.Caps2 or DDSCAPS2_CUBEMAP; - J := DDSCAPS2_POSITIVEX; - for I := 0 to FSaveDepth - 1 do - begin - Desc.Caps.Caps2 := Desc.Caps.Caps2 or J; - J := J shl 1; - end; - ImageCount := FSaveDepth * FSaveMipMapCount; - end - else if IsVolume then - begin - // Set proper flags for volume texture - Desc.Flags := Desc.Flags or DDSD_DEPTH; - Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_COMPLEX; - Desc.Caps.Caps2 := Desc.Caps.Caps2 or DDSCAPS2_VOLUME; - Desc.Depth := FSaveDepth; - ImageCount := GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount); - end; - - // Now we set DDS pixel format for main image - if FmtInfo.IsSpecial or FmtInfo.IsFloatingPoint or - (FmtInfo.BytesPerPixel > 4) then - begin - Desc.PixelFormat.Flags := DDPF_FOURCC; - case Format of - ifA16B16G16R16: Desc.PixelFormat.FourCC := D3DFMT_A16B16G16R16; - ifR32F: Desc.PixelFormat.FourCC := D3DFMT_R32F; - ifA32B32G32R32F: Desc.PixelFormat.FourCC := D3DFMT_A32B32G32R32F; - ifR16F: Desc.PixelFormat.FourCC := D3DFMT_R16F; - ifA16B16G16R16F: Desc.PixelFormat.FourCC := D3DFMT_A16B16G16R16F; - ifDXT1: Desc.PixelFormat.FourCC := FOURCC_DXT1; - ifDXT3: Desc.PixelFormat.FourCC := FOURCC_DXT3; - ifDXT5: Desc.PixelFormat.FourCC := FOURCC_DXT5; - ifATI1N: Desc.PixelFormat.FourCC := FOURCC_ATI1; - ifATI2N: Desc.PixelFormat.FourCC := FOURCC_ATI2; - end; - end - else if FmtInfo.HasGrayChannel then - begin - Desc.PixelFormat.Flags := DDPF_LUMINANCE; - Desc.PixelFormat.BitCount := FmtInfo.BytesPerPixel * 8; - case Format of - ifGray8: Desc.PixelFormat.RedMask := 255; - ifGray16: Desc.PixelFormat.RedMask := 65535; - ifA8Gray8: - begin - Desc.PixelFormat.Flags := Desc.PixelFormat.Flags or DDPF_ALPHAPIXELS; - Desc.PixelFormat.RedMask := 255; - Desc.PixelFormat.AlphaMask := 65280; - end; - end; - end - else - begin - Desc.PixelFormat.Flags := DDPF_RGB; - Desc.PixelFormat.BitCount := FmtInfo.BytesPerPixel * 8; - if FmtInfo.HasAlphaChannel then - begin - Desc.PixelFormat.Flags := Desc.PixelFormat.Flags or DDPF_ALPHAPIXELS; - Desc.PixelFormat.AlphaMask := $FF000000; - end; - if FmtInfo.BytesPerPixel > 2 then - begin - Desc.PixelFormat.RedMask := $00FF0000; - Desc.PixelFormat.GreenMask := $0000FF00; - Desc.PixelFormat.BlueMask := $000000FF; - end - else - begin - Desc.PixelFormat.AlphaMask := FmtInfo.PixelFormat.ABitMask; - Desc.PixelFormat.RedMask := FmtInfo.PixelFormat.RBitMask; - Desc.PixelFormat.GreenMask := FmtInfo.PixelFormat.GBitMask; - Desc.PixelFormat.BlueMask := FmtInfo.PixelFormat.BBitMask; - end; - end; - - // Header and main image are written to output - Write(Handle, @Hdr, SizeOf(Hdr)); - Write(Handle, MainImage.Bits, MainImage.Size); - - // Write the rest of the images and convert them to - // the same format as main image if necessary and ensure proper mipmap - // simensions too. - for I := MainIdx + 1 to MainIdx + ImageCount - 1 do - begin - // Get proper dimensions for this level - ComputeSubDimensions(I, Desc.Width, Desc.Height, Desc.MipMaps, Desc.Depth, - IsCubeMap, IsVolume, CurrentWidth, CurrentHeight); - - // Check if input image for this level has the right size and format - NeedsResize := not ((Images[I].Width = CurrentWidth) and (Images[I].Height = CurrentHeight)); - NeedsConvert := not (Images[I].Format = Format); - - if NeedsResize or NeedsConvert then - begin - // Input image must be resized or converted to different format - // to become valid mipmap level - InitImage(ImageToSave); - CloneImage(Images[I], ImageToSave); - if NeedsConvert then - ConvertImage(ImageToSave, Format); - if NeedsResize then - ResizeImage(ImageToSave, CurrentWidth, CurrentHeight, rfBilinear); - end - else - // Input image can be used without any changes - ImageToSave := Images[I]; - - // Write level data and release temp image if necessary - Write(Handle, ImageToSave.Bits, ImageToSave.Size); - if Images[I].Bits <> ImageToSave.Bits then - FreeImage(ImageToSave); - end; - - Result := True; - finally - if MustBeFreed then - FreeImage(MainImage); - end; -end; - -procedure TDDSFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsIndexed or Info.IsSpecial then - // convert indexed and unsupported special formatd to A8R8G8B8 - ConvFormat := ifA8R8G8B8 - else if Info.IsFloatingPoint then - begin - if Info.Format = ifA16R16G16B16F then - // only swap channels here - ConvFormat := ifA16B16G16R16F - else - // convert other floating point formats to A32B32G32R32F - ConvFormat := ifA32B32G32R32F - end - else if Info.HasGrayChannel then - begin - if Info.HasAlphaChannel then - // convert grayscale with alpha to A8Gray8 - ConvFormat := ifA8Gray8 - else if Info.BytesPerPixel = 1 then - // convert 8bit grayscale to Gray8 - ConvFormat := ifGray8 - else - // convert 16-64bit grayscales to Gray16 - ConvFormat := ifGray16; - end - else if Info.BytesPerPixel > 4 then - ConvFormat := ifA16B16G16R16 - else if Info.HasAlphaChannel then - // convert the other images with alpha channel to A8R8G8B8 - ConvFormat := ifA8R8G8B8 - else - // convert the other formats to X8R8G8B8 - ConvFormat := ifX8R8G8B8; - - ConvertImage(Image, ConvFormat); -end; - -function TDDSFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Hdr: TDDSFileHeader; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - ReadCount := Read(Handle, @Hdr, SizeOf(Hdr)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (Hdr.Magic = DDSMagic) and (ReadCount = SizeOf(Hdr)) and - ((Hdr.Desc.Caps.Caps1 and DDSCAPS_TEXTURE) = DDSCAPS_TEXTURE); - end; -end; - -initialization - RegisterImageFileFormat(TDDSFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 ---------------------------------------------------- - - Texture and D3D specific info stored in DDS is now available as metadata - (loading). - - Added support for loading DDS files with DX10 extension - (http://msdn.microsoft.com/en-us/library/windows/desktop/bb943991(v=vs.85).aspx) - and few compatibility fixes. - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - Added support for 3Dc ATI1/2 formats. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Saved DDS with mipmaps now correctly defineds COMPLEX flag. - - Fixed loading of RGB DDS files that use pitch and have mipmaps - - mipmaps were loaded wrongly. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Changed saving behaviour a bit: mipmaps are inlcuded automatically for - 2D textures if input image array has more than 1 image (no need to - set SaveMipMapCount manually). - - Mipmap levels are now saved with proper dimensions when saving DDS files. - - Made some changes to not be so strict when loading DDS files. - Many programs seem to save them in non-standard format - (by MS DDS File Reference). - - Added missing ifX8R8G8B8 to SupportedFormats, MakeCompatible failed - when image was converted to this format (inside). - - MakeCompatible method moved to base class, put ConvertToSupported here. - GetSupportedFormats removed, it is now set in constructor. - - Fixed bug that sometimes saved non-standard DDS files and another - one that caused crash when these files were loaded. - - Changed extensions to filename masks. - - Changed SaveData, LoadData, and MakeCompatible methods according - to changes in base class in Imaging unit. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - added support for half-float image formats - - change in LoadData to allow support for more images - in one stream loading - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - fixed bug in TestFormat which does not recognize many DDS files - - changed pitch/linearsize handling in DDS loading code to - load DDS files produced by NVidia's Photoshop plugin -} - -end. - diff --git a/3rd/Imaging/Source/ImagingFormats.pas b/3rd/Imaging/Source/ImagingFormats.pas deleted file mode 100644 index f2b882def..000000000 --- a/3rd/Imaging/Source/ImagingFormats.pas +++ /dev/null @@ -1,4411 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit manages information about all image data formats and contains - low level format conversion, manipulation, and other related functions.} -unit ImagingFormats; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingUtility; - -type - TImageFormatInfoArray = array[TImageFormat] of PImageFormatInfo; - PImageFormatInfoArray = ^TImageFormatInfoArray; - - -{ Additional image manipulation functions (usually used internally by Imaging unit) } - -type - { Color reduction operations.} - TReduceColorsAction = (raCreateHistogram, raUpdateHistogram, raMakeColorMap, - raMapImage); - TReduceColorsActions = set of TReduceColorsAction; -const - AllReduceColorsActions = [raCreateHistogram, raUpdateHistogram, - raMakeColorMap, raMapImage]; -{ Reduces the number of colors of source. Src is bits of source image - (ARGB or floating point) and Dst is in some indexed format. MaxColors - is the number of colors to which reduce and DstPal is palette to which - the resulting colors are written and it must be allocated to at least - MaxColors entries. ChannelMask is 'anded' with every pixel's channel value - when creating color histogram. If $FF is used all 8bits of color channels - are used which can be slow for large images with many colors so you can - use lower masks to speed it up.} -procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte; - DstPal: PPalette32; Actions: TReduceColorsActions = AllReduceColorsActions); -{ Stretches rectangle in source image to rectangle in destination image - using nearest neighbor filtering. It is fast but results look blocky - because there is no interpolation used. SrcImage and DstImage must be - in the same data format. Works for all data formats except special formats.} -procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt); -type - { Built-in sampling filters.} - TSamplingFilter = (sfNearest, sfLinear, sfCosine, sfHermite, sfQuadratic, - sfGaussian, sfSpline, sfLanczos, sfMitchell, sfCatmullRom); - { Type of custom sampling function} - TFilterFunction = function(Value: Single): Single; -const - { Default resampling filter used for bicubic resizing.} - DefaultCubicFilter = sfCatmullRom; -var - { Built-in filter functions.} - SamplingFilterFunctions: array[TSamplingFilter] of TFilterFunction; - { Default radii of built-in filter functions.} - SamplingFilterRadii: array[TSamplingFilter] of Single; - -{ Stretches rectangle in source image to rectangle in destination image - with resampling. One of built-in resampling filters defined by - Filter is used. Set WrapEdges to True for seamlessly tileable images. - SrcImage and DstImage must be in the same data format. - Works for all data formats except special and indexed formats.} -procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean = False); overload; -{ Stretches rectangle in source image to rectangle in destination image - with resampling. You can use custom sampling function and filter radius. - Set WrapEdges to True for seamlessly tileable images. SrcImage and DstImage - must be in the same data format. - Works for all data formats except special and indexed formats.} -procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; - WrapEdges: Boolean = False); overload; -{ Helper for functions that create mipmap levels. BiggerLevel is - valid image and SmallerLevel is empty zeroed image. SmallerLevel is created - with Width and Height dimensions and it is filled with pixels of BiggerLevel - using resampling filter specified by ImagingMipMapFilter option. - Uses StretchNearest and StretchResample internally so the same image data format - limitations apply.} -procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt; - var SmallerLevel: TImageData); - - -{ Various helper & support functions } - -{ Copies Src pixel to Dest pixel. It is faster than System.Move procedure.} -procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Compares Src pixel and Dest pixel. It is faster than SysUtils.CompareMem function.} -function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Translates pixel color in SrcFormat to DstFormat.} -procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat, - DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32); -{ Clamps floating point pixel channel values to [0.0, 1.0] range.} -procedure ClampFloatPixel(var PixF: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Helper function that converts pixel in any format to 32bit ARGB pixel. - For common formats it's faster than calling GetPixel32 etc.} -procedure ConvertToPixel32(SrcPix: PByte; DestPix: PColor32Rec; - const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32 = nil); {$IFDEF USE_INLINE}inline;{$ENDIF} - -{ Adds padding bytes at the ends of scanlines. Bpp is the number of bytes per - pixel of source and WidthBytes is the number of bytes per scanlines of dest.} -procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, - Bpp, WidthBytes: LongInt); -{ Removes padding from image with scanlines that have aligned sizes. Bpp is - the number of bytes per pixel of dest and WidthBytes is the number of bytes - per scanlines of source.} -procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, - Bpp, WidthBytes: LongInt); - -{ Converts 1bit image data to 8bit. Used mostly by file loaders for formats - supporting 1bit images. Scaling of pixel values to 8bits is optional - (indexed formats don't need this).} -procedure Convert1To8(DataIn, DataOut: PByte; Width, Height, - WidthBytes: LongInt; ScaleTo8Bits: Boolean); -{ Converts 2bit image data to 8bit. Used mostly by file loaders for formats - supporting 2bit images. Scaling of pixel values to 8bits is optional - (indexed formats don't need this).} -procedure Convert2To8(DataIn, DataOut: PByte; Width, Height, - WidthBytes: LongInt; ScaleTo8Bits: Boolean); -{ Converts 4bit image data to 8bit. Used mostly by file loaders for formats - supporting 4bit images. Scaling of pixel values to 8bits is optional - (indexed formats don't need this).} -procedure Convert4To8(DataIn, DataOut: PByte; Width, Height, - WidthBytes: LongInt; ScaleTo8Bits: Boolean); - -{ Helper function for image file loaders. Some 15 bit images (targas, bitmaps) - may contain 1 bit alpha but there is no indication of it. This function checks - all 16 bit(should be X1R5G5B5 or A1R5G5B5 format) pixels and some of them have - alpha bit set it returns True, otherwise False.} -function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean; -{ Helper function for image file loaders. This function checks is similar - to Has16BitImageAlpha but works with A8R8G8B8/X8R8G8B8 format.} -function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean; -{ Checks if there is any relevant alpha data (any entry has alpha <> 255) - in the given palette.} -function PaletteHasAlpha(Palette: PPalette32; PaletteEntries: Integer): Boolean; - -{ Provides indexed access to each line of pixels. Does not work with special - format images.} -function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo; - LineWidth, Index: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns True if Format is valid image data format identifier.} -function IsImageFormatValid(Format: TImageFormat): Boolean; - -{ Converts 16bit half floating point value to 32bit Single.} -function HalfToFloat(Half: THalfFloat): Single; -{ Converts 32bit Single to 16bit half floating point.} -function FloatToHalf(Float: Single): THalfFloat; - -{ Converts half float color value to single-precision floating point color.} -function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Converts single-precision floating point color to half float color.} -function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF} - -{ Makes image PalEntries x 1 big where each pixel has color of one pal entry.} -procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData); - -type - TPointRec = record - Pos: LongInt; - Weight: Single; - end; - TCluster = array of TPointRec; - TMappingTable = array of TCluster; - -{ Helper function for resampling.} -function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt; - Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable; -{ Helper function for resampling.} -procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt); - - -{ Pixel readers/writers for different image formats } - -{ Returns pixel of image in any ARGB format. Channel values are scaled to 16 bits.} -procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Pix: TColor64Rec); -{ Sets pixel of image in any ARGB format. Channel values must be scaled to 16 bits.} -procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - const Pix: TColor64Rec); - -{ Returns pixel of image in any grayscale format. Gray value is scaled to 64 bits - and alpha to 16 bits.} -procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Gray: TColor64Rec; var Alpha: Word); -{ Sets pixel of image in any grayscale format. Gray value must be scaled to 64 bits - and alpha to 16 bits.} -procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - const Gray: TColor64Rec; Alpha: Word); - -{ Returns pixel of image in any floating point format. Channel values are - in range <0.0, 1.0>.} -procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Pix: TColorFPRec); -{ Sets pixel of image in any floating point format. Channel values must be - in range <0.0, 1.0>.} -procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - const Pix: TColorFPRec); - -{ Returns pixel of image in any indexed format. Returned value is index to - the palette.} -procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Index: LongWord); -{ Sets pixel of image in any indexed format. Index is index to the palette.} -procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - Index: LongWord); - - -{ Pixel readers/writers for 32bit and FP colors} - -{ Function for getting pixel colors. Native pixel is read from Image and - then translated to 32 bit ARGB.} -function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32): TColor32Rec; -{ Procedure for setting pixel colors. Input 32 bit ARGB color is translated to - native format and then written to Image.} -procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32; const Color: TColor32Rec); -{ Function for getting pixel colors. Native pixel is read from Image and - then translated to FP ARGB.} -function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32): TColorFPRec; -{ Procedure for setting pixel colors. Input FP ARGB color is translated to - native format and then written to Image.} -procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32; const Color: TColorFPRec); - - -{ Image format conversion functions } - -{ Converts any ARGB format to any ARGB format.} -procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any ARGB format to any grayscale format.} -procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any ARGB format to any floating point format.} -procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any ARGB format to any indexed format.} -procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; DstPal: PPalette32); - -{ Converts any grayscale format to any grayscale format.} -procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any grayscale format to any ARGB format.} -procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any grayscale format to any floating point format.} -procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any grayscale format to any indexed format.} -procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; DstPal: PPalette32); - -{ Converts any floating point format to any floating point format.} -procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any floating point format to any ARGB format.} -procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any floating point format to any grayscale format.} -procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -{ Converts any floating point format to any indexed format.} -procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; DstPal: PPalette32); - -{ Converts any indexed format to any indexed format.} -procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32); -{ Converts any indexed format to any ARGB format.} -procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal: PPalette32); -{ Converts any indexed format to any grayscale format.} -procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal: PPalette32); -{ Converts any indexed format to any floating point format.} -procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal: PPalette32); - - -{ Color constructor functions } - -{ Constructs TColor24Rec color.} -function Color24(R, G, B: Byte): TColor24Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Constructs TColor32Rec color.} -function Color32(A, R, G, B: Byte): TColor32Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Constructs TColor48Rec color.} -function Color48(R, G, B: Word): TColor48Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Constructs TColor64Rec color.} -function Color64(A, R, G, B: Word): TColor64Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Constructs TColorFPRec color.} -function ColorFP(A, R, G, B: Single): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Constructs TColorHFRec color.} -function ColorHF(A, R, G, B: THalfFloat): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF} - - -{ Special formats conversion functions } - -{ Converts image to/from/between special image formats (dxtc, ...).} -procedure ConvertSpecial(var Image: TImageData; SrcInfo, - DstInfo: PImageFormatInfo); - - -{ Inits all image format information. Called internally on startup.} -procedure InitImageFormats(var Infos: TImageFormatInfoArray); - -const - // Grayscale conversion channel weights - GrayConv: TColorFPRec = (B: 0.114; G: 0.587; R: 0.299; A: 0.0); - - // Contants for converting integer colors to floating point - OneDiv8Bit: Single = 1.0 / 255.0; - OneDiv16Bit: Single = 1.0 / 65535.0; - -implementation - -{ TImageFormatInfo member functions } - -{ Returns size in bytes of image in given standard format where - Size = Width * Height * Bpp.} -function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; -{ Checks if Width and Height are valid for given standard format.} -procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt); forward; -{ Returns size in bytes of image in given DXT format.} -function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; -{ Checks if Width and Height are valid for given DXT format. If they are - not valid, they are changed to pass the check.} -procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt); forward; -{ Returns size in bytes of image in BTC format.} -function GetBTCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; -{ Returns size in bytes of image in binary format (1bit image).} -function GetBinaryPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; - -{ Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo } - -function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward; -procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward; -function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward; -procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward; - -function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward; -procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward; -function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward; -procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward; - -function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward; -procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward; - -var - PFR3G3B2: TPixelFormatInfo; - PFX5R1G1B1: TPixelFormatInfo; - PFR5G6B5: TPixelFormatInfo; - PFA1R5G5B5: TPixelFormatInfo; - PFA4R4G4B4: TPixelFormatInfo; - PFX1R5G5B5: TPixelFormatInfo; - PFX4R4G4B4: TPixelFormatInfo; - FInfos: PImageFormatInfoArray; - -var - // Free Pascal generates hundreds of warnings here -{$WARNINGS OFF} - - // indexed formats - Index8Info: TImageFormatInfo = ( - Format: ifIndex8; - Name: 'Index8'; - BytesPerPixel: 1; - ChannelCount: 1; - PaletteEntries: 256; - HasAlphaChannel: True; - IsIndexed: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - // grayscale formats - Gray8Info: TImageFormatInfo = ( - Format: ifGray8; - Name: 'Gray8'; - BytesPerPixel: 1; - ChannelCount: 1; - HasGrayChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Channel8Bit; - GetPixelFP: GetPixelFPChannel8Bit; - SetPixel32: SetPixel32Channel8Bit; - SetPixelFP: SetPixelFPChannel8Bit); - - A8Gray8Info: TImageFormatInfo = ( - Format: ifA8Gray8; - Name: 'A8Gray8'; - BytesPerPixel: 2; - ChannelCount: 2; - HasGrayChannel: True; - HasAlphaChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Channel8Bit; - GetPixelFP: GetPixelFPChannel8Bit; - SetPixel32: SetPixel32Channel8Bit; - SetPixelFP: SetPixelFPChannel8Bit); - - Gray16Info: TImageFormatInfo = ( - Format: ifGray16; - Name: 'Gray16'; - BytesPerPixel: 2; - ChannelCount: 1; - HasGrayChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - Gray32Info: TImageFormatInfo = ( - Format: ifGray32; - Name: 'Gray32'; - BytesPerPixel: 4; - ChannelCount: 1; - HasGrayChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - Gray64Info: TImageFormatInfo = ( - Format: ifGray64; - Name: 'Gray64'; - BytesPerPixel: 8; - ChannelCount: 1; - HasGrayChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A16Gray16Info: TImageFormatInfo = ( - Format: ifA16Gray16; - Name: 'A16Gray16'; - BytesPerPixel: 4; - ChannelCount: 2; - HasGrayChannel: True; - HasAlphaChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - // ARGB formats - X5R1G1B1Info: TImageFormatInfo = ( - Format: ifX5R1G1B1; - Name: 'X5R1G1B1'; - BytesPerPixel: 1; - ChannelCount: 3; - UsePixelFormat: True; - PixelFormat: @PFX5R1G1B1; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - R3G3B2Info: TImageFormatInfo = ( - Format: ifR3G3B2; - Name: 'R3G3B2'; - BytesPerPixel: 1; - ChannelCount: 3; - UsePixelFormat: True; - PixelFormat: @PFR3G3B2; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - R5G6B5Info: TImageFormatInfo = ( - Format: ifR5G6B5; - Name: 'R5G6B5'; - BytesPerPixel: 2; - ChannelCount: 3; - UsePixelFormat: True; - PixelFormat: @PFR5G6B5; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A1R5G5B5Info: TImageFormatInfo = ( - Format: ifA1R5G5B5; - Name: 'A1R5G5B5'; - BytesPerPixel: 2; - ChannelCount: 4; - HasAlphaChannel: True; - UsePixelFormat: True; - PixelFormat: @PFA1R5G5B5; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A4R4G4B4Info: TImageFormatInfo = ( - Format: ifA4R4G4B4; - Name: 'A4R4G4B4'; - BytesPerPixel: 2; - ChannelCount: 4; - HasAlphaChannel: True; - UsePixelFormat: True; - PixelFormat: @PFA4R4G4B4; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - X1R5G5B5Info: TImageFormatInfo = ( - Format: ifX1R5G5B5; - Name: 'X1R5G5B5'; - BytesPerPixel: 2; - ChannelCount: 3; - UsePixelFormat: True; - PixelFormat: @PFX1R5G5B5; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - X4R4G4B4Info: TImageFormatInfo = ( - Format: ifX4R4G4B4; - Name: 'X4R4G4B4'; - BytesPerPixel: 2; - ChannelCount: 3; - UsePixelFormat: True; - PixelFormat: @PFX4R4G4B4; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - R8G8B8Info: TImageFormatInfo = ( - Format: ifR8G8B8; - Name: 'R8G8B8'; - BytesPerPixel: 3; - ChannelCount: 3; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Channel8Bit; - GetPixelFP: GetPixelFPChannel8Bit; - SetPixel32: SetPixel32Channel8Bit; - SetPixelFP: SetPixelFPChannel8Bit); - - A8R8G8B8Info: TImageFormatInfo = ( - Format: ifA8R8G8B8; - Name: 'A8R8G8B8'; - BytesPerPixel: 4; - ChannelCount: 4; - HasAlphaChannel: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32ifA8R8G8B8; - GetPixelFP: GetPixelFPifA8R8G8B8; - SetPixel32: SetPixel32ifA8R8G8B8; - SetPixelFP: SetPixelFPifA8R8G8B8); - - X8R8G8B8Info: TImageFormatInfo = ( - Format: ifX8R8G8B8; - Name: 'X8R8G8B8'; - BytesPerPixel: 4; - ChannelCount: 3; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Channel8Bit; - GetPixelFP: GetPixelFPChannel8Bit; - SetPixel32: SetPixel32Channel8Bit; - SetPixelFP: SetPixelFPChannel8Bit); - - R16G16B16Info: TImageFormatInfo = ( - Format: ifR16G16B16; - Name: 'R16G16B16'; - BytesPerPixel: 6; - ChannelCount: 3; - RBSwapFormat: ifB16G16R16; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A16R16G16B16Info: TImageFormatInfo = ( - Format: ifA16R16G16B16; - Name: 'A16R16G16B16'; - BytesPerPixel: 8; - ChannelCount: 4; - HasAlphaChannel: True; - RBSwapFormat: ifA16B16G16R16; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - B16G16R16Info: TImageFormatInfo = ( - Format: ifB16G16R16; - Name: 'B16G16R16'; - BytesPerPixel: 6; - ChannelCount: 3; - IsRBSwapped: True; - RBSwapFormat: ifR16G16B16; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A16B16G16R16Info: TImageFormatInfo = ( - Format: ifA16B16G16R16; - Name: 'A16B16G16R16'; - BytesPerPixel: 8; - ChannelCount: 4; - HasAlphaChannel: True; - IsRBSwapped: True; - RBSwapFormat: ifA16R16G16B16; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - // floating point formats - R32FInfo: TImageFormatInfo = ( - Format: ifR32F; - Name: 'R32F'; - BytesPerPixel: 4; - ChannelCount: 1; - IsFloatingPoint: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPFloat32; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPFloat32); - - A32R32G32B32FInfo: TImageFormatInfo = ( - Format: ifA32R32G32B32F; - Name: 'A32R32G32B32F'; - BytesPerPixel: 16; - ChannelCount: 4; - HasAlphaChannel: True; - IsFloatingPoint: True; - RBSwapFormat: ifA32B32G32R32F; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPFloat32; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPFloat32); - - A32B32G32R32FInfo: TImageFormatInfo = ( - Format: ifA32B32G32R32F; - Name: 'A32B32G32R32F'; - BytesPerPixel: 16; - ChannelCount: 4; - HasAlphaChannel: True; - IsFloatingPoint: True; - IsRBSwapped: True; - RBSwapFormat: ifA32R32G32B32F; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPFloat32; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPFloat32); - - R16FInfo: TImageFormatInfo = ( - Format: ifR16F; - Name: 'R16F'; - BytesPerPixel: 2; - ChannelCount: 1; - IsFloatingPoint: True; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A16R16G16B16FInfo: TImageFormatInfo = ( - Format: ifA16R16G16B16F; - Name: 'A16R16G16B16F'; - BytesPerPixel: 8; - ChannelCount: 4; - HasAlphaChannel: True; - IsFloatingPoint: True; - RBSwapFormat: ifA16B16G16R16F; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - A16B16G16R16FInfo: TImageFormatInfo = ( - Format: ifA16B16G16R16F; - Name: 'A16B16G16R16F'; - BytesPerPixel: 8; - ChannelCount: 4; - HasAlphaChannel: True; - IsFloatingPoint: True; - IsRBSwapped: True; - RBSwapFormat: ifA16R16G16B16F; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPGeneric; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPGeneric); - - R32G32B32FInfo: TImageFormatInfo = ( - Format: ifR32G32B32F; - Name: 'R32G32B32F'; - BytesPerPixel: 12; - ChannelCount: 3; - IsFloatingPoint: True; - RBSwapFormat: ifB32G32R32F; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPFloat32; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPFloat32); - - B32G32R32FInfo: TImageFormatInfo = ( - Format: ifB32G32R32F; - Name: 'B32G32R32F'; - BytesPerPixel: 12; - ChannelCount: 3; - IsFloatingPoint: True; - IsRBSwapped: True; - RBSwapFormat: ifR32G32B32F; - GetPixelsSize: GetStdPixelsSize; - CheckDimensions: CheckStdDimensions; - GetPixel32: GetPixel32Generic; - GetPixelFP: GetPixelFPFloat32; - SetPixel32: SetPixel32Generic; - SetPixelFP: SetPixelFPFloat32); - - // special formats - DXT1Info: TImageFormatInfo = ( - Format: ifDXT1; - Name: 'DXT1'; - ChannelCount: 4; - HasAlphaChannel: True; - IsSpecial: True; - GetPixelsSize: GetDXTPixelsSize; - CheckDimensions: CheckDXTDimensions; - SpecialNearestFormat: ifA8R8G8B8); - - DXT3Info: TImageFormatInfo = ( - Format: ifDXT3; - Name: 'DXT3'; - ChannelCount: 4; - HasAlphaChannel: True; - IsSpecial: True; - GetPixelsSize: GetDXTPixelsSize; - CheckDimensions: CheckDXTDimensions; - SpecialNearestFormat: ifA8R8G8B8); - - DXT5Info: TImageFormatInfo = ( - Format: ifDXT5; - Name: 'DXT5'; - ChannelCount: 4; - HasAlphaChannel: True; - IsSpecial: True; - GetPixelsSize: GetDXTPixelsSize; - CheckDimensions: CheckDXTDimensions; - SpecialNearestFormat: ifA8R8G8B8); - - BTCInfo: TImageFormatInfo = ( - Format: ifBTC; - Name: 'BTC'; - ChannelCount: 1; - HasAlphaChannel: False; - IsSpecial: True; - GetPixelsSize: GetBTCPixelsSize; - CheckDimensions: CheckDXTDimensions; - SpecialNearestFormat: ifGray8); - - ATI1NInfo: TImageFormatInfo = ( - Format: ifATI1N; - Name: 'ATI1N'; - ChannelCount: 1; - HasAlphaChannel: False; - IsSpecial: True; - GetPixelsSize: GetDXTPixelsSize; - CheckDimensions: CheckDXTDimensions; - SpecialNearestFormat: ifGray8); - - ATI2NInfo: TImageFormatInfo = ( - Format: ifATI2N; - Name: 'ATI2N'; - ChannelCount: 2; - HasAlphaChannel: False; - IsSpecial: True; - GetPixelsSize: GetDXTPixelsSize; - CheckDimensions: CheckDXTDimensions; - SpecialNearestFormat: ifA8R8G8B8); - - BinaryInfo: TImageFormatInfo = ( - Format: ifBinary; - Name: 'Binary'; - ChannelCount: 1; - HasAlphaChannel: False; - IsSpecial: True; - GetPixelsSize: GetBinaryPixelsSize; - CheckDimensions: CheckStdDimensions; - SpecialNearestFormat: ifGray8); - -{$WARNINGS ON} - -function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; forward; - -procedure InitImageFormats(var Infos: TImageFormatInfoArray); -begin - FInfos := @Infos; - - Infos[ifDefault] := @A8R8G8B8Info; - // indexed formats - Infos[ifIndex8] := @Index8Info; - // grayscale formats - Infos[ifGray8] := @Gray8Info; - Infos[ifA8Gray8] := @A8Gray8Info; - Infos[ifGray16] := @Gray16Info; - Infos[ifGray32] := @Gray32Info; - Infos[ifGray64] := @Gray64Info; - Infos[ifA16Gray16] := @A16Gray16Info; - // ARGB formats - Infos[ifX5R1G1B1] := @X5R1G1B1Info; - Infos[ifR3G3B2] := @R3G3B2Info; - Infos[ifR5G6B5] := @R5G6B5Info; - Infos[ifA1R5G5B5] := @A1R5G5B5Info; - Infos[ifA4R4G4B4] := @A4R4G4B4Info; - Infos[ifX1R5G5B5] := @X1R5G5B5Info; - Infos[ifX4R4G4B4] := @X4R4G4B4Info; - Infos[ifR8G8B8] := @R8G8B8Info; - Infos[ifA8R8G8B8] := @A8R8G8B8Info; - Infos[ifX8R8G8B8] := @X8R8G8B8Info; - Infos[ifR16G16B16] := @R16G16B16Info; - Infos[ifA16R16G16B16] := @A16R16G16B16Info; - Infos[ifB16G16R16] := @B16G16R16Info; - Infos[ifA16B16G16R16] := @A16B16G16R16Info; - // floating point formats - Infos[ifR32F] := @R32FInfo; - Infos[ifA32R32G32B32F] := @A32R32G32B32FInfo; - Infos[ifA32B32G32R32F] := @A32B32G32R32FInfo; - Infos[ifR16F] := @R16FInfo; - Infos[ifA16R16G16B16F] := @A16R16G16B16FInfo; - Infos[ifA16B16G16R16F] := @A16B16G16R16FInfo; - Infos[ifR32G32B32F] := @R32G32B32FInfo; - Infos[ifB32G32R32F] := @B32G32R32FInfo; - // special formats - Infos[ifDXT1] := @DXT1Info; - Infos[ifDXT3] := @DXT3Info; - Infos[ifDXT5] := @DXT5Info; - Infos[ifBTC] := @BTCInfo; - Infos[ifATI1N] := @ATI1NInfo; - Infos[ifATI2N] := @ATI2NInfo; - Infos[ifBinary] := @BinaryInfo; - - PFR3G3B2 := PixelFormat(0, 3, 3, 2); - PFX5R1G1B1 := PixelFormat(0, 1, 1, 1); - PFR5G6B5 := PixelFormat(0, 5, 6, 5); - PFA1R5G5B5 := PixelFormat(1, 5, 5, 5); - PFA4R4G4B4 := PixelFormat(4, 4, 4, 4); - PFX1R5G5B5 := PixelFormat(0, 5, 5, 5); - PFX4R4G4B4 := PixelFormat(0, 4, 4, 4); -end; - - -{ Internal unit helper functions } - -function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; -begin - Result.ABitMask := ((1 shl ABitCount) - 1) shl (RBitCount + GBitCount + - BBitCount); - Result.RBitMask := ((1 shl RBitCount) - 1) shl (GBitCount + BBitCount); - Result.GBitMask := ((1 shl GBitCount) - 1) shl (BBitCount); - Result.BBitMask := (1 shl BBitCount) - 1; - Result.ABitCount := ABitCount; - Result.RBitCount := RBitCount; - Result.GBitCount := GBitCount; - Result.BBitCount := BBitCount; - Result.AShift := RBitCount + GBitCount + BBitCount; - Result.RShift := GBitCount + BBitCount; - Result.GShift := BBitCount; - Result.BShift := 0; - Result.ARecDiv := Max(1, Pow2Int(Result.ABitCount) - 1); - Result.RRecDiv := Max(1, Pow2Int(Result.RBitCount) - 1); - Result.GRecDiv := Max(1, Pow2Int(Result.GBitCount) - 1); - Result.BRecDiv := Max(1, Pow2Int(Result.BBitCount) - 1); -end; - -function PixelFormatMask(ABitMask, RBitMask, GBitMask, BBitMask: LongWord): TPixelFormatInfo; - - function GetBitCount(B: LongWord): LongWord; - var - I: LongWord; - begin - I := 0; - while (I < 31) and (((1 shl I) and B) = 0) do - Inc(I); - Result := 0; - while ((1 shl I) and B) <> 0 do - begin - Inc(I); - Inc(Result); - end; - end; - -begin - Result := PixelFormat(GetBitCount(ABitMask), GetBitCount(RBitMask), - GetBitCount(GBitMask), GetBitCount(BBitMask)); -end; - -function PFSetARGB(const PF: TPixelFormatInfo; A, R, G, B: Byte): TColor32; -{$IFDEF USE_INLINE}inline;{$ENDIF} -begin - with PF do - Result := - (A shl ABitCount shr 8 shl AShift) or - (R shl RBitCount shr 8 shl RShift) or - (G shl GBitCount shr 8 shl GShift) or - (B shl BBitCount shr 8 shl BShift); -end; - -procedure PFGetARGB(const PF: TPixelFormatInfo; Color: LongWord; - var A, R, G, B: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF} -begin - with PF do - begin - A := (Color and ABitMask shr AShift) * 255 div ARecDiv; - R := (Color and RBitMask shr RShift) * 255 div RRecDiv; - G := (Color and GBitMask shr GShift) * 255 div GRecDiv; - B := (Color and BBitMask shl BShift) * 255 div BRecDiv; - end; -end; - -function PFSetColor(const PF: TPixelFormatInfo; ARGB: TColor32): LongWord; -{$IFDEF USE_INLINE}inline;{$ENDIF} -begin - with PF do - Result := - (Byte(ARGB shr 24) shl ABitCount shr 8 shl AShift) or - (Byte(ARGB shr 16) shl RBitCount shr 8 shl RShift) or - (Byte(ARGB shr 8) shl GBitCount shr 8 shl GShift) or - (Byte(ARGB) shl BBitCount shr 8 shl BShift); -end; - -function PFGetColor(const PF: TPixelFormatInfo; Color: LongWord): TColor32; -{$IFDEF USE_INLINE}inline;{$ENDIF} -begin - with PF, TColor32Rec(Result) do - begin - A := (Color and ABitMask shr AShift) * 255 div ARecDiv; - R := (Color and RBitMask shr RShift) * 255 div RRecDiv; - G := (Color and GBitMask shr GShift) * 255 div GRecDiv; - B := (Color and BBitMask shl BShift) * 255 div BRecDiv; - end; -end; - - -{ Color constructor functions } - - -function Color24(R, G, B: Byte): TColor24Rec; -begin - Result.R := R; - Result.G := G; - Result.B := B; -end; - -function Color32(A, R, G, B: Byte): TColor32Rec; -begin - Result.A := A; - Result.R := R; - Result.G := G; - Result.B := B; -end; - -function Color48(R, G, B: Word): TColor48Rec; -begin - Result.R := R; - Result.G := G; - Result.B := B; -end; - -function Color64(A, R, G, B: Word): TColor64Rec; -begin - Result.A := A; - Result.R := R; - Result.G := G; - Result.B := B; -end; - -function ColorFP(A, R, G, B: Single): TColorFPRec; -begin - Result.A := A; - Result.R := R; - Result.G := G; - Result.B := B; -end; - -function ColorHF(A, R, G, B: THalfFloat): TColorHFRec; -begin - Result.A := A; - Result.R := R; - Result.G := G; - Result.B := B; -end; - - -{ Additional image manipulation functions (usually used internally by Imaging unit) } - -const - MaxPossibleColors = 4096; - HashSize = 32768; - AlphaWeight = 1024; - RedWeight = 612; - GreenWeight = 1202; - BlueWeight = 234; - -type - PColorBin = ^TColorBin; - TColorBin = record - Color: TColor32Rec; - Number: LongInt; - Next: PColorBin; - end; - - THashTable = array[0..HashSize - 1] of PColorBin; - - TColorBox = record - AMin, AMax, - RMin, RMax, - GMin, GMax, - BMin, BMax: LongInt; - Total: LongInt; - Represented: TColor32Rec; - List: PColorBin; - end; - -var - Table: THashTable; - Box: array[0..MaxPossibleColors - 1] of TColorBox; - Boxes: LongInt; - BoxesCreated: Boolean = False; - -procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte; - DstPal: PPalette32; Actions: TReduceColorsActions); - - procedure CreateHistogram (Src: PByte; SrcInfo: PImageFormatInfo; - ChannelMask: Byte); - var - A, R, G, B: Byte; - I, Addr: LongInt; - PC: PColorBin; - Col: TColor32Rec; - begin - for I := 0 to NumPixels - 1 do - begin - Col := GetPixel32Generic(Src, SrcInfo, nil); - A := Col.A and ChannelMask; - R := Col.R and ChannelMask; - G := Col.G and ChannelMask; - B := Col.B and ChannelMask; - - Addr := (A + 11 * B + 59 * R + 119 * G) mod HashSize; - PC := Table[Addr]; - - while (PC <> nil) and ((PC.Color.R <> R) or (PC.Color.G <> G) or - (PC.Color.B <> B) or (PC.Color.A <> A)) do - PC := PC.Next; - - if PC = nil then - begin - New(PC); - PC.Color.R := R; - PC.Color.G := G; - PC.Color.B := B; - PC.Color.A := A; - PC.Number := 1; - PC.Next := Table[Addr]; - Table[Addr] := PC; - end - else - Inc(PC^.Number); - Inc(Src, SrcInfo.BytesPerPixel); - end; - end; - - procedure InitBox (var Box : TColorBox); - begin - Box.AMin := 256; - Box.RMin := 256; - Box.GMin := 256; - Box.BMin := 256; - Box.AMax := -1; - Box.RMax := -1; - Box.GMax := -1; - Box.BMax := -1; - Box.Total := 0; - Box.List := nil; - end; - - procedure ChangeBox (var Box: TColorBox; const C: TColorBin); - begin - with C.Color do - begin - if A < Box.AMin then Box.AMin := A; - if A > Box.AMax then Box.AMax := A; - if B < Box.BMin then Box.BMin := B; - if B > Box.BMax then Box.BMax := B; - if G < Box.GMin then Box.GMin := G; - if G > Box.GMax then Box.GMax := G; - if R < Box.RMin then Box.RMin := R; - if R > Box.RMax then Box.RMax := R; - end; - Inc(Box.Total, C.Number); - end; - - procedure MakeColormap; - var - I, J: LongInt; - CP, Pom: PColorBin; - Cut, LargestIdx, Largest, Size, S: LongInt; - CutA, CutR, CutG, CutB: Boolean; - SumA, SumR, SumG, SumB: LongInt; - Temp: TColorBox; - begin - I := 0; - Boxes := 1; - LargestIdx := 0; - while (I < HashSize) and (Table[I] = nil) do - Inc(i); - if I < HashSize then - begin - // put all colors into Box[0] - InitBox(Box[0]); - repeat - CP := Table[I]; - while CP.Next <> nil do - begin - ChangeBox(Box[0], CP^); - CP := CP.Next; - end; - ChangeBox(Box[0], CP^); - CP.Next := Box[0].List; - Box[0].List := Table[I]; - Table[I] := nil; - repeat - Inc(I) - until (I = HashSize) or (Table[I] <> nil); - until I = HashSize; - // now all colors are in Box[0] - repeat - // cut one color box - Largest := 0; - for I := 0 to Boxes - 1 do - with Box[I] do - begin - Size := (AMax - AMin) * AlphaWeight; - S := (RMax - RMin) * RedWeight; - if S > Size then - Size := S; - S := (GMax - GMin) * GreenWeight; - if S > Size then - Size := S; - S := (BMax - BMin) * BlueWeight; - if S > Size then - Size := S; - if Size > Largest then - begin - Largest := Size; - LargestIdx := I; - end; - end; - if Largest > 0 then - begin - // cutting Box[LargestIdx] into Box[LargestIdx] and Box[Boxes] - CutR := False; - CutG := False; - CutB := False; - CutA := False; - with Box[LargestIdx] do - begin - if (AMax - AMin) * AlphaWeight = Largest then - begin - Cut := (AMax + AMin) shr 1; - CutA := True; - end - else - if (RMax - RMin) * RedWeight = Largest then - begin - Cut := (RMax + RMin) shr 1; - CutR := True; - end - else - if (GMax - GMin) * GreenWeight = Largest then - begin - Cut := (GMax + GMin) shr 1; - CutG := True; - end - else - begin - Cut := (BMax + BMin) shr 1; - CutB := True; - end; - CP := List; - end; - InitBox(Box[LargestIdx]); - InitBox(Box[Boxes]); - repeat - // distribute one color - Pom := CP.Next; - with CP.Color do - begin - if (CutA and (A <= Cut)) or (CutR and (R <= Cut)) or - (CutG and (G <= Cut)) or (CutB and (B <= Cut)) then - I := LargestIdx - else - I := Boxes; - end; - CP.Next := Box[i].List; - Box[i].List := CP; - ChangeBox(Box[i], CP^); - CP := Pom; - until CP = nil; - Inc(Boxes); - end; - until (Boxes = MaxColors) or (Largest = 0); - // compute box representation - for I := 0 to Boxes - 1 do - begin - SumR := 0; - SumG := 0; - SumB := 0; - SumA := 0; - repeat - CP := Box[I].List; - Inc(SumR, CP.Color.R * CP.Number); - Inc(SumG, CP.Color.G * CP.Number); - Inc(SumB, CP.Color.B * CP.Number); - Inc(SumA, CP.Color.A * CP.Number); - Box[I].List := CP.Next; - Dispose(CP); - until Box[I].List = nil; - with Box[I] do - begin - Represented.A := SumA div Total; - Represented.R := SumR div Total; - Represented.G := SumG div Total; - Represented.B := SumB div Total; - AMin := AMin and ChannelMask; - RMin := RMin and ChannelMask; - GMin := GMin and ChannelMask; - BMin := BMin and ChannelMask; - AMax := (AMax and ChannelMask) + (not ChannelMask); - RMax := (RMax and ChannelMask) + (not ChannelMask); - GMax := (GMax and ChannelMask) + (not ChannelMask); - BMax := (BMax and ChannelMask) + (not ChannelMask); - end; - end; - // sort color boxes - for I := 0 to Boxes - 2 do - begin - Largest := 0; - for J := I to Boxes - 1 do - if Box[J].Total > Largest then - begin - Largest := Box[J].Total; - LargestIdx := J; - end; - if LargestIdx <> I then - begin - Temp := Box[I]; - Box[I] := Box[LargestIdx]; - Box[LargestIdx] := Temp; - end; - end; - end; - end; - - procedure FillOutputPalette; - var - I: LongInt; - begin - FillChar(DstPal^, SizeOf(TColor32Rec) * MaxColors, $FF); - for I := 0 to MaxColors - 1 do - begin - if I < Boxes then - with Box[I].Represented do - begin - DstPal[I].A := A; - DstPal[I].R := R; - DstPal[I].G := G; - DstPal[I].B := B; - end - else - DstPal[I].Color := $FF000000; - end; - end; - - function MapColor(const Col: TColor32Rec) : LongInt; - var - I: LongInt; - begin - I := 0; - with Col do - while (I < Boxes) and ((Box[I].AMin > A) or (Box[I].AMax < A) or - (Box[I].RMin > R) or (Box[I].RMax < R) or (Box[I].GMin > G) or - (Box[I].GMax < G) or (Box[I].BMin > B) or (Box[I].BMax < B)) do - Inc(I); - if I = Boxes then - MapColor := 0 - else - MapColor := I; - end; - - procedure MapImage(Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); - var - I: LongInt; - Col: TColor32Rec; - begin - for I := 0 to NumPixels - 1 do - begin - Col := GetPixel32Generic(Src, SrcInfo, nil); - IndexSetDstPixel(Dst, DstInfo, MapColor(Col)); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; - end; - -begin - MaxColors := ClampInt(MaxColors, 2, MaxPossibleColors); - - if (raUpdateHistogram in Actions) or (raMapImage in Actions) then - begin - Assert(not SrcInfo.IsSpecial); - Assert(not SrcInfo.IsIndexed); - end; - - if raCreateHistogram in Actions then - FillChar(Table, SizeOf(Table), 0); - - if raUpdateHistogram in Actions then - CreateHistogram(Src, SrcInfo, ChannelMask); - - if raMakeColorMap in Actions then - begin - MakeColorMap; - FillOutputPalette; - end; - - if raMapImage in Actions then - MapImage(Src, Dst, SrcInfo, DstInfo); -end; - -procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt); -var - Info: TImageFormatInfo; - ScaleX, ScaleY, X, Y, Xp, Yp: LongInt; - DstPixel, SrcLine: PByte; -begin - GetImageFormatInfo(SrcImage.Format, Info); - Assert(SrcImage.Format = DstImage.Format); - Assert(not Info.IsSpecial); - // Use integers instead of floats for source image pixel coords - // Xp and Yp coords must be shifted right to get read source image coords - ScaleX := (SrcWidth shl 16) div DstWidth; - ScaleY := (SrcHeight shl 16) div DstHeight; - Yp := 0; - for Y := 0 to DstHeight - 1 do - begin - Xp := 0; - SrcLine := @PByteArray(SrcImage.Bits)[((SrcY + Yp shr 16) * SrcImage.Width + SrcX) * Info.BytesPerPixel]; - DstPixel := @PByteArray(DstImage.Bits)[((DstY + Y) * DstImage.Width + DstX) * Info.BytesPerPixel]; - for X := 0 to DstWidth - 1 do - begin - case Info.BytesPerPixel of - 1: PByte(DstPixel)^ := PByteArray(SrcLine)[Xp shr 16]; - 2: PWord(DstPixel)^ := PWordArray(SrcLine)[Xp shr 16]; - 3: PColor24Rec(DstPixel)^ := PPalette24(SrcLine)[Xp shr 16]; - 4: PColor32(DstPixel)^ := PLongWordArray(SrcLine)[Xp shr 16]; - 6: PColor48Rec(DstPixel)^ := PColor48RecArray(SrcLine)[Xp shr 16]; - 8: PColor64(DstPixel)^ := PInt64Array(SrcLine)[Xp shr 16]; - 16: PColorFPRec(DstPixel)^ := PColorFPRecArray(SrcLine)[Xp shr 16]; - end; - Inc(DstPixel, Info.BytesPerPixel); - Inc(Xp, ScaleX); - end; - Inc(Yp, ScaleY); - end; -end; - -{ Filter function for nearest filtering. Also known as box filter.} -function FilterNearest(Value: Single): Single; -begin - if (Value > -0.5) and (Value <= 0.5) then - Result := 1 - else - Result := 0; -end; - -{ Filter function for linear filtering. Also known as triangle or Bartlett filter.} -function FilterLinear(Value: Single): Single; -begin - if Value < 0.0 then - Value := -Value; - if Value < 1.0 then - Result := 1.0 - Value - else - Result := 0.0; -end; - -{ Cosine filter.} -function FilterCosine(Value: Single): Single; -begin - Result := 0; - if Abs(Value) < 1 then - Result := (Cos(Value * Pi) + 1) / 2; -end; - -{ f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 } -function FilterHermite(Value: Single): Single; -begin - if Value < 0.0 then - Value := -Value; - if Value < 1 then - Result := (2 * Value - 3) * Sqr(Value) + 1 - else - Result := 0; -end; - -{ Quadratic filter. Also known as Bell.} -function FilterQuadratic(Value: Single): Single; -begin - if Value < 0.0 then - Value := -Value; - if Value < 0.5 then - Result := 0.75 - Sqr(Value) - else - if Value < 1.5 then - begin - Value := Value - 1.5; - Result := 0.5 * Sqr(Value); - end - else - Result := 0.0; -end; - -{ Gaussian filter.} -function FilterGaussian(Value: Single): Single; -begin - Result := Exp(-2.0 * Sqr(Value)) * Sqrt(2.0 / Pi); -end; - -{ 4th order (cubic) b-spline filter.} -function FilterSpline(Value: Single): Single; -var - Temp: Single; -begin - if Value < 0.0 then - Value := -Value; - if Value < 1.0 then - begin - Temp := Sqr(Value); - Result := 0.5 * Temp * Value - Temp + 2.0 / 3.0; - end - else - if Value < 2.0 then - begin - Value := 2.0 - Value; - Result := Sqr(Value) * Value / 6.0; - end - else - Result := 0.0; -end; - -{ Lanczos-windowed sinc filter.} -function FilterLanczos(Value: Single): Single; - - function SinC(Value: Single): Single; - begin - if Value <> 0.0 then - begin - Value := Value * Pi; - Result := Sin(Value) / Value; - end - else - Result := 1.0; - end; - -begin - if Value < 0.0 then - Value := -Value; - if Value < 3.0 then - Result := SinC(Value) * SinC(Value / 3.0) - else - Result := 0.0; -end; - -{ Micthell cubic filter.} -function FilterMitchell(Value: Single): Single; -const - B = 1.0 / 3.0; - C = 1.0 / 3.0; -var - Temp: Single; -begin - if Value < 0.0 then - Value := -Value; - Temp := Sqr(Value); - if Value < 1.0 then - begin - Value := (((12.0 - 9.0 * B - 6.0 * C) * (Value * Temp)) + - ((-18.0 + 12.0 * B + 6.0 * C) * Temp) + - (6.0 - 2.0 * B)); - Result := Value / 6.0; - end - else - if Value < 2.0 then - begin - Value := (((-B - 6.0 * C) * (Value * Temp)) + - ((6.0 * B + 30.0 * C) * Temp) + - ((-12.0 * B - 48.0 * C) * Value) + - (8.0 * B + 24.0 * C)); - Result := Value / 6.0; - end - else - Result := 0.0; -end; - -{ CatmullRom spline filter.} -function FilterCatmullRom(Value: Single): Single; -begin - if Value < 0.0 then - Value := -Value; - if Value < 1.0 then - Result := 0.5 * (2.0 + Sqr(Value) * (-5.0 + 3.0 * Value)) - else - if Value < 2.0 then - Result := 0.5 * (4.0 + Value * (-8.0 + Value * (5.0 - Value))) - else - Result := 0.0; -end; - -procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean); -begin - // Calls the other function with filter function and radius defined by Filter - StretchResample(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY, - DstWidth, DstHeight, SamplingFilterFunctions[Filter], SamplingFilterRadii[Filter], - WrapEdges); -end; - -var - FullEdge: Boolean = True; - -{ The following resampling code is modified and extended code from Graphics32 - library by Alex A. Denisov.} -function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt; - Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable; -var - I, J, K, N: LongInt; - Left, Right, SrcWidth, DstWidth: LongInt; - Weight, Scale, Center, Count: Single; -begin - Result := nil; - K := 0; - SrcWidth := SrcHigh - SrcLow; - DstWidth := DstHigh - DstLow; - - // Check some special cases - if SrcWidth = 1 then - begin - SetLength(Result, DstWidth); - for I := 0 to DstWidth - 1 do - begin - SetLength(Result[I], 1); - Result[I][0].Pos := 0; - Result[I][0].Weight := 1.0; - end; - Exit; - end - else - if (SrcWidth = 0) or (DstWidth = 0) then - Exit; - - if FullEdge then - Scale := DstWidth / SrcWidth - else - Scale := (DstWidth - 1) / (SrcWidth - 1); - - SetLength(Result, DstWidth); - - // Pre-calculate filter contributions for a row or column - if Scale = 0.0 then - begin - Assert(Length(Result) = 1); - SetLength(Result[0], 1); - Result[0][0].Pos := (SrcLow + SrcHigh) div 2; - Result[0][0].Weight := 1.0; - end - else if Scale < 1.0 then - begin - // Sub-sampling - scales from bigger to smaller - Radius := Radius / Scale; - for I := 0 to DstWidth - 1 do - begin - if FullEdge then - Center := SrcLow - 0.5 + (I + 0.5) / Scale - else - Center := SrcLow + I / Scale; - Left := Floor(Center - Radius); - Right := Ceil(Center + Radius); - Count := -1.0; - for J := Left to Right do - begin - Weight := Filter((Center - J) * Scale) * Scale; - if Weight <> 0.0 then - begin - Count := Count + Weight; - K := Length(Result[I]); - SetLength(Result[I], K + 1); - Result[I][K].Pos := ClampInt(J, SrcLow, SrcHigh - 1); - Result[I][K].Weight := Weight; - end; - end; - if Length(Result[I]) = 0 then - begin - SetLength(Result[I], 1); - Result[I][0].Pos := Floor(Center); - Result[I][0].Weight := 1.0; - end - else if Count <> 0.0 then - Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count; - end; - end - else // if Scale > 1.0 then - begin - // Super-sampling - scales from smaller to bigger - Scale := 1.0 / Scale; - for I := 0 to DstWidth - 1 do - begin - if FullEdge then - Center := SrcLow - 0.5 + (I + 0.5) * Scale - else - Center := SrcLow + I * Scale; - Left := Floor(Center - Radius); - Right := Ceil(Center + Radius); - Count := -1.0; - for J := Left to Right do - begin - Weight := Filter(Center - J); - if Weight <> 0.0 then - begin - Count := Count + Weight; - K := Length(Result[I]); - SetLength(Result[I], K + 1); - - if WrapEdges then - begin - if J < 0 then - N := SrcImageWidth + J - else if J >= SrcImageWidth then - N := J - SrcImageWidth - else - N := ClampInt(J, SrcLow, SrcHigh - 1); - end - else - N := ClampInt(J, SrcLow, SrcHigh - 1); - - Result[I][K].Pos := N; - Result[I][K].Weight := Weight; - end; - end; - if Count <> 0.0 then - Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count; - end; - end; -end; - -procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt); -var - I, J: LongInt; -begin - if Length(Map) > 0 then - begin - MinPos := Map[0][0].Pos; - MaxPos := MinPos; - for I := 0 to Length(Map) - 1 do - for J := 0 to Length(Map[I]) - 1 do - begin - if MinPos > Map[I][J].Pos then - MinPos := Map[I][J].Pos; - if MaxPos < Map[I][J].Pos then - MaxPos := Map[I][J].Pos; - end; - end; -end; - -procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, - SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, - DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean); -const - Channel8BitMax: Single = 255.0; -var - MapX, MapY: TMappingTable; - I, J, X, Y: LongInt; - XMinimum, XMaximum: LongInt; - LineBufferFP: array of TColorFPRec; - ClusterX, ClusterY: TCluster; - Weight, AccumA, AccumR, AccumG, AccumB: Single; - DstLine: PByte; - SrcFloat: TColorFPRec; - Info: TImageFormatInfo; - BytesPerChannel: LongInt; -begin - GetImageFormatInfo(SrcImage.Format, Info); - Assert(SrcImage.Format = DstImage.Format); - Assert(not Info.IsSpecial and not Info.IsIndexed); - BytesPerChannel := Info.BytesPerPixel div Info.ChannelCount; - - // Create horizontal and vertical mapping tables - MapX := BuildMappingTable(DstX, DstX + DstWidth, SrcX, SrcX + SrcWidth, - SrcImage.Width, Filter, Radius, WrapEdges); - MapY := BuildMappingTable(DstY, DstY + DstHeight, SrcY, SrcY + SrcHeight, - SrcImage.Height, Filter, Radius, WrapEdges); - - if (MapX = nil) or (MapY = nil) then - Exit; - - ClusterX := nil; - ClusterY := nil; - - try - // Find min and max X coords of pixels that will contribute to target image - FindExtremes(MapX, XMinimum, XMaximum); - - SetLength(LineBufferFP, XMaximum - XMinimum + 1); - // Following code works for the rest of data formats - for J := 0 to DstHeight - 1 do - begin - // First for each pixel in the current line sample vertically - // and store results in LineBuffer. Then sample horizontally - // using values in LineBuffer. - ClusterY := MapY[J]; - for X := XMinimum to XMaximum do - begin - // Clear accumulators - AccumA := 0; - AccumR := 0; - AccumG := 0; - AccumB := 0; - // For each pixel in line compute weighted sum of pixels - // in source column that will contribute to this pixel - for Y := 0 to Length(ClusterY) - 1 do - begin - // Accumulate this pixel's weighted value - Weight := ClusterY[Y].Weight; - SrcFloat := Info.GetPixelFP(@PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel], @Info, nil); - AccumB := AccumB + SrcFloat.B * Weight; - AccumG := AccumG + SrcFloat.G * Weight; - AccumR := AccumR + SrcFloat.R * Weight; - AccumA := AccumA + SrcFloat.A * Weight; - end; - // Store accumulated value for this pixel in buffer - with LineBufferFP[X - XMinimum] do - begin - A := AccumA; - R := AccumR; - G := AccumG; - B := AccumB; - end; - end; - - DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX) * Info.BytesPerPixel]; - // Now compute final colors for targte pixels in the current row - // by sampling horizontally - for I := 0 to DstWidth - 1 do - begin - ClusterX := MapX[I]; - // Clear accumulator - AccumA := 0; - AccumR := 0; - AccumG := 0; - AccumB := 0; - // Compute weighted sum of values (which are already - // computed weighted sums of pixels in source columns stored in LineBuffer) - // that will contribute to the current target pixel - for X := 0 to Length(ClusterX) - 1 do - begin - Weight := ClusterX[X].Weight; - with LineBufferFP[ClusterX[X].Pos - XMinimum] do - begin - AccumB := AccumB + B * Weight; - AccumG := AccumG + G * Weight; - AccumR := AccumR + R * Weight; - AccumA := AccumA + A * Weight; - end; - end; - - // Now compute final color to be written to dest image - SrcFloat.A := AccumA; - SrcFloat.R := AccumR; - SrcFloat.G := AccumG; - SrcFloat.B := AccumB; - - Info.SetPixelFP(DstLine, @Info, nil, SrcFloat); - Inc(DstLine, Info.BytesPerPixel); - end; - end; - - finally - MapX := nil; - MapY := nil; - end; -end; - -procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt; - var SmallerLevel: TImageData); -var - Filter: TSamplingFilter; - Info: TImageFormatInfo; - CompatibleCopy: TImageData; -begin - Assert(TestImage(BiggerLevel)); - Filter := TSamplingFilter(GetOption(ImagingMipMapFilter)); - - // If we have special format image we must create copy to allow pixel access - GetImageFormatInfo(BiggerLevel.Format, Info); - if Info.IsSpecial then - begin - InitImage(CompatibleCopy); - CloneImage(BiggerLevel, CompatibleCopy); - ConvertImage(CompatibleCopy, ifDefault); - end - else - CompatibleCopy := BiggerLevel; - - // Create new smaller image - NewImage(Width, Height, CompatibleCopy.Format, SmallerLevel); - GetImageFormatInfo(CompatibleCopy.Format, Info); - // If input is indexed we must copy its palette - if Info.IsIndexed then - CopyPalette(CompatibleCopy.Palette, SmallerLevel.Palette, 0, 0, Info.PaletteEntries); - - if (Filter = sfNearest) or Info.IsIndexed then - begin - StretchNearest(CompatibleCopy, 0, 0, CompatibleCopy.Width, CompatibleCopy.Height, - SmallerLevel, 0, 0, Width, Height); - end - else - begin - StretchResample(CompatibleCopy, 0, 0, CompatibleCopy.Width, CompatibleCopy.Height, - SmallerLevel, 0, 0, Width, Height, Filter); - end; - - // Free copy and convert result to special format if necessary - if CompatibleCopy.Format <> BiggerLevel.Format then - begin - ConvertImage(SmallerLevel, BiggerLevel.Format); - FreeImage(CompatibleCopy); - end; -end; - - -{ Various format support functions } - -procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); -begin - case BytesPerPixel of - 1: PByte(Dest)^ := PByte(Src)^; - 2: PWord(Dest)^ := PWord(Src)^; - 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^; - 4: PLongWord(Dest)^ := PLongWord(Src)^; - 6: PColor48Rec(Dest)^ := PColor48Rec(Src)^; - 8: PInt64(Dest)^ := PInt64(Src)^; - 12: PColor96FPRec(Dest)^ := PColor96FPRec(Src)^; - 16: PColorFPRec(Dest)^ := PColorFPRec(Src)^; - end; -end; - -function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean; -begin - case BytesPerPixel of - 1: Result := PByte(PixelA)^ = PByte(PixelB)^; - 2: Result := PWord(PixelA)^ = PWord(PixelB)^; - 3: Result := (PWord(PixelA)^ = PWord(PixelB)^) and (PColor24Rec(PixelA).R = PColor24Rec(PixelB).R); - 4: Result := PLongWord(PixelA)^ = PLongWord(PixelB)^; - 6: Result := (PLongWord(PixelA)^ = PLongWord(PixelB)^) and (PColor48Rec(PixelA).R = PColor48Rec(PixelB).R); - 8: Result := PInt64(PixelA)^ = PInt64(PixelB)^; - 12: Result := (PFloatHelper(PixelA).Data = PFloatHelper(PixelB).Data) and - (PFloatHelper(PixelA).Data32 = PFloatHelper(PixelB).Data32); - 16: Result := (PFloatHelper(PixelA).Data = PFloatHelper(PixelB).Data) and - (PFloatHelper(PixelA).Data64 = PFloatHelper(PixelB).Data64); - else - Result := False; - end; -end; - -procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat, - DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32); -var - SrcInfo, DstInfo: PImageFormatInfo; - PixFP: TColorFPRec; -begin - SrcInfo := FInfos[SrcFormat]; - DstInfo := FInfos[DstFormat]; - - PixFP := GetPixelFPGeneric(SrcPixel, SrcInfo, SrcPalette); - SetPixelFPGeneric(DstPixel, DstInfo, DstPalette, PixFP); -end; - -procedure ClampFloatPixel(var PixF: TColorFPRec); -begin - if PixF.A > 1.0 then - PixF.A := 1.0; - if PixF.R > 1.0 then - PixF.R := 1.0; - if PixF.G > 1.0 then - PixF.G := 1.0; - if PixF.B > 1.0 then - PixF.B := 1.0; - - if PixF.A < 0.0 then - PixF.A := 0.0; - if PixF.R < 0.0 then - PixF.R := 0.0; - if PixF.G < 0.0 then - PixF.G := 0.0; - if PixF.B < 0.0 then - PixF.B := 0.0; -end; - -procedure ConvertToPixel32(SrcPix: PByte; DestPix: PColor32Rec; - const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32); -begin - case SrcInfo.Format of - ifIndex8: - begin - DestPix^ := SrcPalette[SrcPix^]; - end; - ifGray8: - begin - DestPix.R := SrcPix^; - DestPix.G := SrcPix^; - DestPix.B := SrcPix^; - DestPix.A := 255; - end; - ifA8Gray8: - begin - DestPix.R := SrcPix^; - DestPix.G := SrcPix^; - DestPix.B := SrcPix^; - DestPix.A := PWordRec(SrcPix).High; - end; - ifGray16: - begin - DestPix.R := PWord(SrcPix)^ shr 8; - DestPix.G := DestPix.R; - DestPix.B := DestPix.R; - DestPix.A := 255; - end; - ifR8G8B8: - begin - DestPix.Color24Rec := PColor24Rec(SrcPix)^; - DestPix.A := 255; - end; - ifA8R8G8B8: - begin - DestPix^ := PColor32Rec(SrcPix)^; - end; - ifR16G16B16: - begin - DestPix.R := PColor48Rec(SrcPix).R shr 8; - DestPix.G := PColor48Rec(SrcPix).G shr 8; - DestPix.B := PColor48Rec(SrcPix).B shr 8; - DestPix.A := 255; - end; - ifA16R16G16B16: - begin - DestPix.R := PColor64Rec(SrcPix).R shr 8; - DestPix.G := PColor64Rec(SrcPix).G shr 8; - DestPix.B := PColor64Rec(SrcPix).B shr 8; - DestPix.A := PColor64Rec(SrcPix).A shr 8; - end; - else - DestPix^ := SrcInfo.GetPixel32(SrcPix, @SrcInfo, SrcPalette); - end; -end; - -procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, - Bpp, WidthBytes: LongInt); -var - I, W: LongInt; -begin - W := Width * Bpp; - for I := 0 to Height - 1 do - Move(PByteArray(DataIn)[I * W], PByteArray(DataOut)[I * WidthBytes], W); -end; - -procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, - Bpp, WidthBytes: LongInt); -var - I, W: LongInt; -begin - W := Width * Bpp; - for I := 0 to Height - 1 do - Move(PByteArray(DataIn)[I * WidthBytes], PByteArray(DataOut)[I * W], W); -end; - -procedure Convert1To8(DataIn, DataOut: PByte; Width, Height, - WidthBytes: LongInt; ScaleTo8Bits: Boolean); -const - Mask1: array[0..7] of Byte = ($80, $40, $20, $10, $08, $04, $02, $01); - Shift1: array[0..7] of Byte = (7, 6, 5, 4, 3, 2, 1, 0); - Scaling: Byte = 255; -var - X, Y: LongInt; - InArray: PByteArray absolute DataIn; -begin - for Y := 0 to Height - 1 do - for X := 0 to Width - 1 do - begin - DataOut^ := (InArray[Y * WidthBytes + X shr 3] and Mask1[X and 7]) shr Shift1[X and 7]; - if ScaleTo8Bits then - DataOut^ := DataOut^ * Scaling; - Inc(DataOut); - end; -end; - -procedure Convert2To8(DataIn, DataOut: PByte; Width, Height, - WidthBytes: LongInt; ScaleTo8Bits: Boolean); -const - Mask2: array[0..3] of Byte = ($C0, $30, $0C, $03); - Shift2: array[0..3] of Byte = (6, 4, 2, 0); - Scaling: Byte = 85; -var - X, Y: LongInt; - InArray: PByteArray absolute DataIn; -begin - for Y := 0 to Height - 1 do - for X := 0 to Width - 1 do - begin - DataOut^ := (InArray[Y * WidthBytes + X shr 2] and Mask2[X and 3]) shr Shift2[X and 3]; - if ScaleTo8Bits then - DataOut^ := DataOut^ * Scaling; - Inc(DataOut); - end; -end; - -procedure Convert4To8(DataIn, DataOut: PByte; Width, Height, - WidthBytes: LongInt; ScaleTo8Bits: Boolean); -const - Mask4: array[0..1] of Byte = ($F0, $0F); - Shift4: array[0..1] of Byte = (4, 0); - Scaling: Byte = 17; -var - X, Y: LongInt; - InArray: PByteArray absolute DataIn; -begin - for Y := 0 to Height - 1 do - for X := 0 to Width - 1 do - begin - DataOut^ := (InArray[Y * WidthBytes + X shr 1] and Mask4[X and 1]) shr Shift4[X and 1]; - if ScaleTo8Bits then - DataOut^ := DataOut^ * Scaling; - Inc(DataOut); - end; -end; - -function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean; -var - I: LongInt; -begin - Result := False; - for I := 0 to NumPixels - 1 do - begin - if Data^ >= 1 shl 15 then - begin - Result := True; - Exit; - end; - Inc(Data); - end; -end; - -function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean; -var - I: LongInt; -begin - Result := False; - for I := 0 to NumPixels - 1 do - begin - if Data^ >= 1 shl 24 then - begin - Result := True; - Exit; - end; - Inc(Data); - end; -end; - -function PaletteHasAlpha(Palette: PPalette32; PaletteEntries: Integer): Boolean; -var - I: Integer; -begin - for I := 0 to PaletteEntries - 1 do - begin - if Palette[I].A <> 255 then - begin - Result := True; - Exit; - end; - end; - Result := False; -end; - -function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo; - LineWidth, Index: LongInt): Pointer; -var - LineBytes: LongInt; -begin - Assert(not FormatInfo.IsSpecial); - LineBytes := FormatInfo.GetPixelsSize(FormatInfo.Format, LineWidth, 1); - Result := @PByteArray(ImageBits)[Index * LineBytes]; -end; - -function IsImageFormatValid(Format: TImageFormat): Boolean; -begin - Result := FInfos[Format] <> nil; -end; - -const - HalfMin: Single = 5.96046448e-08; // Smallest positive half - HalfMinNorm: Single = 6.10351562e-05; // Smallest positive normalized half - HalfMax: Single = 65504.0; // Largest positive half - HalfEpsilon: Single = 0.00097656; // Smallest positive e for which half (1.0 + e) != half (1.0) - HalfNaN: THalfFloat = 65535; - HalfPosInf: THalfFloat = 31744; - HalfNegInf: THalfFloat = 64512; - - -{ - Half/Float conversions inspired by half class from OpenEXR library. - - Float (Pascal Single type) is an IEEE 754 single-precision - floating point number. - - Bit layout of Single: - - 31 (msb) - | - | 30 23 - | | | - | | | 22 0 (lsb) - | | | | | - X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX - s e m - - Bit layout of half: - - 15 (msb) - | - | 14 10 - | | | - | | | 9 0 (lsb) - | | | | | - X XXXXX XXXXXXXXXX - s e m - - S is the sign-bit, e is the exponent and m is the significand (mantissa). -} - -function HalfToFloat(Half: THalfFloat): Single; -var - Dst, Sign, Mantissa: LongWord; - Exp: LongInt; -begin - // Extract sign, exponent, and mantissa from half number - Sign := Half shr 15; - Exp := (Half and $7C00) shr 10; - Mantissa := Half and 1023; - - if (Exp > 0) and (Exp < 31) then - begin - // Common normalized number - Exp := Exp + (127 - 15); - Mantissa := Mantissa shl 13; - Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa; - // Result := Power(-1, Sign) * Power(2, Exp - 15) * (1 + Mantissa / 1024); - end - else if (Exp = 0) and (Mantissa = 0) then - begin - // Zero - preserve sign - Dst := Sign shl 31; - end - else if (Exp = 0) and (Mantissa <> 0) then - begin - // Denormalized number - renormalize it - while (Mantissa and $00000400) = 0 do - begin - Mantissa := Mantissa shl 1; - Dec(Exp); - end; - Inc(Exp); - Mantissa := Mantissa and not $00000400; - // Now assemble normalized number - Exp := Exp + (127 - 15); - Mantissa := Mantissa shl 13; - Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa; - // Result := Power(-1, Sign) * Power(2, -14) * (Mantissa / 1024); - end - else if (Exp = 31) and (Mantissa = 0) then - begin - // +/- infinity - Dst := (Sign shl 31) or $7F800000; - end - else //if (Exp = 31) and (Mantisa <> 0) then - begin - // Not a number - preserve sign and mantissa - Dst := (Sign shl 31) or $7F800000 or (Mantissa shl 13); - end; - - // Reinterpret LongWord as Single - Result := PSingle(@Dst)^; -end; - -function FloatToHalf(Float: Single): THalfFloat; -var - Src: LongWord; - Sign, Exp, Mantissa: LongInt; -begin - Src := PLongWord(@Float)^; - // Extract sign, exponent, and mantissa from Single number - Sign := Src shr 31; - Exp := LongInt((Src and $7F800000) shr 23) - 127 + 15; - Mantissa := Src and $007FFFFF; - - if (Exp > 0) and (Exp < 30) then - begin - // Simple case - round the significand and combine it with the sign and exponent - Result := (Sign shl 15) or (Exp shl 10) or ((Mantissa + $00001000) shr 13); - end - else if Src = 0 then - begin - // Input float is zero - return zero - Result := 0; - end - else - begin - // Difficult case - lengthy conversion - if Exp <= 0 then - begin - if Exp < -10 then - begin - // Input float's value is less than HalfMin, return zero - Result := 0; - end - else - begin - // Float is a normalized Single whose magnitude is less than HalfNormMin. - // We convert it to denormalized half. - Mantissa := (Mantissa or $00800000) shr (1 - Exp); - // Round to nearest - if (Mantissa and $00001000) > 0 then - Mantissa := Mantissa + $00002000; - // Assemble Sign and Mantissa (Exp is zero to get denormalized number) - Result := (Sign shl 15) or (Mantissa shr 13); - end; - end - else if Exp = 255 - 127 + 15 then - begin - if Mantissa = 0 then - begin - // Input float is infinity, create infinity half with original sign - Result := (Sign shl 15) or $7C00; - end - else - begin - // Input float is NaN, create half NaN with original sign and mantissa - Result := (Sign shl 15) or $7C00 or (Mantissa shr 13); - end; - end - else - begin - // Exp is > 0 so input float is normalized Single - - // Round to nearest - if (Mantissa and $00001000) > 0 then - begin - Mantissa := Mantissa + $00002000; - if (Mantissa and $00800000) > 0 then - begin - Mantissa := 0; - Exp := Exp + 1; - end; - end; - - if Exp > 30 then - begin - // Exponent overflow - return infinity half - Result := (Sign shl 15) or $7C00; - end - else - // Assemble normalized half - Result := (Sign shl 15) or (Exp shl 10) or (Mantissa shr 13); - end; - end; -end; - -function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; -begin - Result.A := HalfToFloat(ColorHF.A); - Result.R := HalfToFloat(ColorHF.R); - Result.G := HalfToFloat(ColorHF.G); - Result.B := HalfToFloat(ColorHF.B); -end; - -function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; -begin - Result.A := FloatToHalf(ColorFP.A); - Result.R := FloatToHalf(ColorFP.R); - Result.G := FloatToHalf(ColorFP.G); - Result.B := FloatToHalf(ColorFP.B); -end; - -procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData); -var - I: Integer; - Pix: PColor32; -begin - InitImage(PalImage); - NewImage(Entries, 1, ifA8R8G8B8, PalImage); - Pix := PalImage.Bits; - for I := 0 to Entries - 1 do - begin - Pix^ := Pal[I].Color; - Inc(Pix); - end; -end; - - -{ Pixel readers/writers for different image formats } - -procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Pix: TColor64Rec); -var - A, R, G, B: Byte; -begin - FillChar(Pix, SizeOf(Pix), 0); - // returns 64 bit color value with 16 bits for each channel - case SrcInfo.BytesPerPixel of - 1: - begin - PFGetARGB(SrcInfo.PixelFormat^, Src^, A, R, G, B); - Pix.A := A shl 8; - Pix.R := R shl 8; - Pix.G := G shl 8; - Pix.B := B shl 8; - end; - 2: - begin - PFGetARGB(SrcInfo.PixelFormat^, PWord(Src)^, A, R, G, B); - Pix.A := A shl 8; - Pix.R := R shl 8; - Pix.G := G shl 8; - Pix.B := B shl 8; - end; - 3: - with Pix do - begin - R := MulDiv(PColor24Rec(Src).R, 65535, 255); - G := MulDiv(PColor24Rec(Src).G, 65535, 255); - B := MulDiv(PColor24Rec(Src).B, 65535, 255); - end; - 4: - with Pix do - begin - A := MulDiv(PColor32Rec(Src).A, 65535, 255); - R := MulDiv(PColor32Rec(Src).R, 65535, 255); - G := MulDiv(PColor32Rec(Src).G, 65535, 255); - B := MulDiv(PColor32Rec(Src).B, 65535, 255); - end; - 6: - with Pix do - begin - R := PColor48Rec(Src).R; - G := PColor48Rec(Src).G; - B := PColor48Rec(Src).B; - end; - 8: Pix.Color := PColor64(Src)^; - end; - // if src has no alpha, we set it to max (otherwise we would have to - // test if dest has alpha or not in each ChannelToXXX function) - if not SrcInfo.HasAlphaChannel then - Pix.A := 65535; - - if SrcInfo.IsRBSwapped then - SwapValues(Pix.R, Pix.B); -end; - -procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - const Pix: TColor64Rec); -var - PixW: TColor64Rec; -begin - PixW := Pix; - if DstInfo.IsRBSwapped then - SwapValues(PixW.R, PixW.B); - // Pix contains 64 bit color value with 16 bit for each channel - case DstInfo.BytesPerPixel of - 1: Dst^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8, - PixW.R shr 8, PixW.G shr 8, PixW.B shr 8); - 2: PWord(Dst)^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8, - PixW.R shr 8, PixW.G shr 8, PixW.B shr 8); - 3: - with PColor24Rec(Dst)^ do - begin - R := MulDiv(PixW.R, 255, 65535); - G := MulDiv(PixW.G, 255, 65535); - B := MulDiv(PixW.B, 255, 65535); - end; - 4: - with PColor32Rec(Dst)^ do - begin - A := MulDiv(PixW.A, 255, 65535); - R := MulDiv(PixW.R, 255, 65535); - G := MulDiv(PixW.G, 255, 65535); - B := MulDiv(PixW.B, 255, 65535); - end; - 6: - with PColor48Rec(Dst)^ do - begin - R := PixW.R; - G := PixW.G; - B := PixW.B; - end; - 8: PColor64(Dst)^ := PixW.Color; - end; -end; - -procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Gray: TColor64Rec; var Alpha: Word); -begin - FillChar(Gray, SizeOf(Gray), 0); - // Source alpha is scaled to 16 bits and stored in Alpha, - // grayscale value is scaled to 64 bits and stored in Gray - case SrcInfo.BytesPerPixel of - 1: Gray.A := MulDiv(Src^, 65535, 255); - 2: - if SrcInfo.HasAlphaChannel then - with PWordRec(Src)^ do - begin - Alpha := MulDiv(High, 65535, 255); - Gray.A := MulDiv(Low, 65535, 255); - end - else - Gray.A := PWord(Src)^; - 4: - if SrcInfo.HasAlphaChannel then - with PLongWordRec(Src)^ do - begin - Alpha := High; - Gray.A := Low; - end - else - with PLongWordRec(Src)^ do - begin - Gray.A := High; - Gray.R := Low; - end; - 8: Gray.Color := PColor64(Src)^; - end; - // if src has no alpha, we set it to max (otherwise we would have to - // test if dest has alpha or not in each GrayToXXX function) - if not SrcInfo.HasAlphaChannel then - Alpha := 65535; -end; - -procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - const Gray: TColor64Rec; Alpha: Word); -begin - // Gray contains grayscale value scaled to 64 bits, Alpha contains - // alpha value scaled to 16 bits - case DstInfo.BytesPerPixel of - 1: Dst^ := MulDiv(Gray.A, 255, 65535); - 2: - if DstInfo.HasAlphaChannel then - with PWordRec(Dst)^ do - begin - High := MulDiv(Alpha, 255, 65535); - Low := MulDiv(Gray.A, 255, 65535); - end - else - PWord(Dst)^ := Gray.A; - 4: - if DstInfo.HasAlphaChannel then - with PLongWordRec(Dst)^ do - begin - High := Alpha; - Low := Gray.A; - end - else - with PLongWordRec(Dst)^ do - begin - High := Gray.A; - Low := Gray.R; - end; - 8: PColor64(Dst)^ := Gray.Color; - end; -end; - -procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Pix: TColorFPRec); -var - PixHF: TColorHFRec; -begin - Assert(SrcInfo.BytesPerPixel in [2, 4, 8, 12, 16]); - - if SrcInfo.BytesPerPixel in [4, 12, 16] then - begin - // IEEE 754 single-precision channels - FillChar(Pix, SizeOf(Pix), 0); - case SrcInfo.BytesPerPixel of - 4: Pix.R := PSingle(Src)^; - 12: Pix.Color96Rec := PColor96FPRec(Src)^; - 16: Pix := PColorFPRec(Src)^; - end; - end - else - begin - // Half float channels - FillChar(PixHF, SizeOf(PixHF), 0); - case SrcInfo.BytesPerPixel of - 2: PixHF.R := PHalfFloat(Src)^; - 8: PixHF := PColorHFRec(Src)^; - end; - Pix := ColorHalfToFloat(PixHF); - end; - - // If src has no alpha, we set it to max (otherwise we would have to - // test if dest has alpha or not in each FloatToXXX function) - if not SrcInfo.HasAlphaChannel then - Pix.A := 1.0; - if SrcInfo.IsRBSwapped then - SwapValues(Pix.R, Pix.B); -end; - -procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - const Pix: TColorFPRec); -var - PixW: TColorFPRec; - PixHF: TColorHFRec; -begin - Assert(DstInfo.BytesPerPixel in [2, 4, 8, 12, 16]); - - PixW := Pix; - if DstInfo.IsRBSwapped then - SwapValues(PixW.R, PixW.B); - - if DstInfo.BytesPerPixel in [4, 12, 16] then - begin - case DstInfo.BytesPerPixel of - 4: PSingle(Dst)^ := PixW.R; - 12: PColor96FPRec(Dst)^:= PixW.Color96Rec; - 16: PColorFPRec(Dst)^ := PixW; - end; - end - else - begin - PixHF := ColorFloatToHalf(PixW); - case DstInfo.BytesPerPixel of - 2: PHalfFloat(Dst)^ := PixHF.R; - 8: PColorHFRec(Dst)^ := PixHF; - end; - end; -end; - -procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; - var Index: LongWord); -begin - case SrcInfo.BytesPerPixel of - 1: Index := Src^; - end; -end; - -procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; - Index: LongWord); -begin - case DstInfo.BytesPerPixel of - 1: Dst^ := Byte(Index); - 2: PWord(Dst)^ := Word(Index); - 4: PLongWord(Dst)^ := Index; - end; -end; - - -{ Pixel readers/writers for 32bit and FP colors} - -function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; -var - Pix64: TColor64Rec; - PixF: TColorFPRec; - Alpha: Word; - Index: LongWord; -begin - if Info.Format = ifA8R8G8B8 then - begin - Result := PColor32Rec(Bits)^ - end - else if Info.Format = ifR8G8B8 then - begin - PColor24Rec(@Result)^ := PColor24Rec(Bits)^; - Result.A := $FF; - end - else if Info.IsFloatingPoint then - begin - FloatGetSrcPixel(Bits, Info, PixF); - Result.A := ClampToByte(Round(PixF.A * 255.0)); - Result.R := ClampToByte(Round(PixF.R * 255.0)); - Result.G := ClampToByte(Round(PixF.G * 255.0)); - Result.B := ClampToByte(Round(PixF.B * 255.0)); - end - else if Info.HasGrayChannel then - begin - GrayGetSrcPixel(Bits, Info, Pix64, Alpha); - Result.A := MulDiv(Alpha, 255, 65535); - Result.R := MulDiv(Pix64.A, 255, 65535); - Result.G := MulDiv(Pix64.A, 255, 65535); - Result.B := MulDiv(Pix64.A, 255, 65535); - end - else if Info.IsIndexed then - begin - IndexGetSrcPixel(Bits, Info, Index); - Result := Palette[Index]; - end - else - begin - ChannelGetSrcPixel(Bits, Info, Pix64); - Result.A := MulDiv(Pix64.A, 255, 65535); - Result.R := MulDiv(Pix64.R, 255, 65535); - Result.G := MulDiv(Pix64.G, 255, 65535); - Result.B := MulDiv(Pix64.B, 255, 65535); - end; -end; - -procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); -var - Pix64: TColor64Rec; - PixF: TColorFPRec; - Alpha: Word; - Index: LongWord; -begin - if Info.Format = ifA8R8G8B8 then - begin - PColor32Rec(Bits)^ := Color - end - else if Info.Format = ifR8G8B8 then - begin - PColor24Rec(Bits)^ := Color.Color24Rec; - end - else if Info.IsFloatingPoint then - begin - PixF.A := Color.A * OneDiv8Bit; - PixF.R := Color.R * OneDiv8Bit; - PixF.G := Color.G * OneDiv8Bit; - PixF.B := Color.B * OneDiv8Bit; - FloatSetDstPixel(Bits, Info, PixF); - end - else if Info.HasGrayChannel then - begin - Alpha := MulDiv(Color.A, 65535, 255); - Pix64.Color := 0; - Pix64.A := MulDiv(Round(GrayConv.R * Color.R + GrayConv.G * Color.G + - GrayConv.B * Color.B), 65535, 255); - GraySetDstPixel(Bits, Info, Pix64, Alpha); - end - else if Info.IsIndexed then - begin - Index := FindColor(Palette, Info.PaletteEntries, Color.Color); - IndexSetDstPixel(Bits, Info, Index); - end - else - begin - Pix64.A := MulDiv(Color.A, 65535, 255); - Pix64.R := MulDiv(Color.R, 65535, 255); - Pix64.G := MulDiv(Color.G, 65535, 255); - Pix64.B := MulDiv(Color.B, 65535, 255); - ChannelSetDstPixel(Bits, Info, Pix64); - end; -end; - -function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; -var - Pix32: TColor32Rec; - Pix64: TColor64Rec; - Alpha: Word; - Index: LongWord; -begin - if Info.IsFloatingPoint then - begin - FloatGetSrcPixel(Bits, Info, Result); - end - else if Info.HasGrayChannel then - begin - GrayGetSrcPixel(Bits, Info, Pix64, Alpha); - Result.A := Alpha * OneDiv16Bit; - Result.R := Pix64.A * OneDiv16Bit; - Result.G := Pix64.A * OneDiv16Bit; - Result.B := Pix64.A * OneDiv16Bit; - end - else if Info.IsIndexed then - begin - IndexGetSrcPixel(Bits, Info, Index); - Pix32 := Palette[Index]; - Result.A := Pix32.A * OneDiv8Bit; - Result.R := Pix32.R * OneDiv8Bit; - Result.G := Pix32.G * OneDiv8Bit; - Result.B := Pix32.B * OneDiv8Bit; - end - else - begin - ChannelGetSrcPixel(Bits, Info, Pix64); - Result.A := Pix64.A * OneDiv16Bit; - Result.R := Pix64.R * OneDiv16Bit; - Result.G := Pix64.G * OneDiv16Bit; - Result.B := Pix64.B * OneDiv16Bit; - end; -end; - -procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); -var - Pix32: TColor32Rec; - Pix64: TColor64Rec; - Alpha: Word; - Index: LongWord; -begin - if Info.IsFloatingPoint then - begin - FloatSetDstPixel(Bits, Info, Color); - end - else if Info.HasGrayChannel then - begin - Alpha := ClampToWord(Round(Color.A * 65535.0)); - Pix64.Color := 0; - Pix64.A := ClampToWord(Round((GrayConv.R * Color.R + GrayConv.G * Color.G + - GrayConv.B * Color.B) * 65535.0)); - GraySetDstPixel(Bits, Info, Pix64, Alpha); - end - else if Info.IsIndexed then - begin - Pix32.A := ClampToByte(Round(Color.A * 255.0)); - Pix32.R := ClampToByte(Round(Color.R * 255.0)); - Pix32.G := ClampToByte(Round(Color.G * 255.0)); - Pix32.B := ClampToByte(Round(Color.B * 255.0)); - Index := FindColor(Palette, Info.PaletteEntries, Pix32.Color); - IndexSetDstPixel(Bits, Info, Index); - end - else - begin - Pix64.A := ClampToWord(Round(Color.A * 65535.0)); - Pix64.R := ClampToWord(Round(Color.R * 65535.0)); - Pix64.G := ClampToWord(Round(Color.G * 65535.0)); - Pix64.B := ClampToWord(Round(Color.B * 65535.0)); - ChannelSetDstPixel(Bits, Info, Pix64); - end; -end; - - -{ Image format conversion functions } - -procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Pix64: TColor64Rec; -begin - // two most common conversions (RGB->ARGB and ARGB->RGB for 24/32 bit - // images) are made separately from general ARGB conversion to - // make them faster - if (SrcInfo.BytesPerPixel = 3) and (DstInfo.BytesPerPixel = 4) then - for I := 0 to NumPixels - 1 do - begin - PColor24Rec(Dst)^ := PColor24Rec(Src)^; - if DstInfo.HasAlphaChannel then - PColor32Rec(Dst).A := 255; - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - else - if (SrcInfo.BytesPerPixel = 4) and (DstInfo.BytesPerPixel = 3) then - for I := 0 to NumPixels - 1 do - begin - PColor24Rec(Dst)^ := PColor24Rec(Src)^; - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - else - for I := 0 to NumPixels - 1 do - begin - // general ARGB conversion - ChannelGetSrcPixel(Src, SrcInfo, Pix64); - ChannelSetDstPixel(Dst, DstInfo, Pix64); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Pix64: TColor64Rec; - Alpha: Word; -begin - // two most common conversions (R8G8B8->Gray8 nad A8R8G8B8->Gray8) - // are made separately from general conversions to make them faster - if (SrcInfo.BytesPerPixel in [3, 4]) and (DstInfo.Format = ifGray8) then - for I := 0 to NumPixels - 1 do - begin - Dst^ := Round(GrayConv.R * PColor24Rec(Src).R + GrayConv.G * PColor24Rec(Src).G + - GrayConv.B * PColor24Rec(Src).B); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - else - for I := 0 to NumPixels - 1 do - begin - ChannelGetSrcPixel(Src, SrcInfo, Pix64); - - // alpha is saved from source pixel to Alpha, - // Gray value is computed and set to highest word of Pix64 so - // Pix64.Color contains grayscale value scaled to 64 bits - Alpha := Pix64.A; - with GrayConv do - Pix64.A := Round(R * Pix64.R + G * Pix64.G + B * Pix64.B); - - GraySetDstPixel(Dst, DstInfo, Pix64, Alpha); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Pix64: TColor64Rec; - PixF: TColorFPRec; -begin - for I := 0 to NumPixels - 1 do - begin - ChannelGetSrcPixel(Src, SrcInfo, Pix64); - - // floating point channel values are scaled to 1.0 - PixF.A := Pix64.A * OneDiv16Bit; - PixF.R := Pix64.R * OneDiv16Bit; - PixF.G := Pix64.G * OneDiv16Bit; - PixF.B := Pix64.B * OneDiv16Bit; - - FloatSetDstPixel(Dst, DstInfo, PixF); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; DstPal: PPalette32); -begin - ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries, - GetOption(ImagingColorReductionMask), DstPal); -end; - -procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Gray: TColor64Rec; - Alpha: Word; -begin - // two most common conversions (Gray8->Gray16 nad Gray16->Gray8) - // are made separately from general conversions to make them faster - if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifGray16) then - begin - for I := 0 to NumPixels - 1 do - PWordArray(Dst)[I] := PByteArray(Src)[I] shl 8; - end - else - begin - if (DstInfo.Format = ifGray8) and (SrcInfo.Format = ifGray16) then - begin - for I := 0 to NumPixels - 1 do - PByteArray(Dst)[I] := PWordArray(Src)[I] shr 8; - end - else - for I := 0 to NumPixels - 1 do - begin - // general grayscale conversion - GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha); - GraySetDstPixel(Dst, DstInfo, Gray, Alpha); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; - end; -end; - -procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Pix64: TColor64Rec; - Alpha: Word; -begin - // two most common conversions (Gray8->R8G8B8 nad Gray8->A8R8G8B8) - // are made separately from general conversions to make them faster - if (DstInfo.BytesPerPixel in [3, 4]) and (SrcInfo.Format = ifGray8) then - for I := 0 to NumPixels - 1 do - begin - PColor24Rec(Dst).R := Src^; - PColor24Rec(Dst).G := Src^; - PColor24Rec(Dst).B := Src^; - if DstInfo.HasAlphaChannel then - PColor32Rec(Dst).A := $FF; - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - else - for I := 0 to NumPixels - 1 do - begin - GrayGetSrcPixel(Src, SrcInfo, Pix64, Alpha); - - // most significant word of grayscale value is used for - // each channel and alpha channel is set to Alpha - Pix64.R := Pix64.A; - Pix64.G := Pix64.A; - Pix64.B := Pix64.A; - Pix64.A := Alpha; - - ChannelSetDstPixel(Dst, DstInfo, Pix64); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Gray: TColor64Rec; - PixF: TColorFPRec; - Alpha: Word; -begin - for I := 0 to NumPixels - 1 do - begin - GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha); - // most significant word of grayscale value is used for - // each channel and alpha channel is set to Alpha - // then all is scaled to 0..1 - PixF.R := Gray.A * OneDiv16Bit; - PixF.G := Gray.A * OneDiv16Bit; - PixF.B := Gray.A * OneDiv16Bit; - PixF.A := Alpha * OneDiv16Bit; - - FloatSetDstPixel(Dst, DstInfo, PixF); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; DstPal: PPalette32); -var - I: LongInt; - Idx: LongWord; - Gray: TColor64Rec; - Alpha, Shift: Word; -begin - FillGrayscalePalette(DstPal, DstInfo.PaletteEntries); - Shift := Log2Int(DstInfo.PaletteEntries); - // most common conversion (Gray8->Index8) - // is made separately from general conversions to make it faster - if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifIndex8) then - for I := 0 to NumPixels - 1 do - begin - Dst^ := Src^; - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - else - for I := 0 to NumPixels - 1 do - begin - // gray value is read from src and index to precomputed - // grayscale palette is computed and written to dst - // (we assume here that there will be no more than 65536 palette - // entries in dst format, gray value is shifted so the highest - // gray value match the highest possible index in palette) - GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha); - Idx := Gray.A shr (16 - Shift); - IndexSetDstPixel(Dst, DstInfo, Idx); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - PixF: TColorFPRec; -begin - for I := 0 to NumPixels - 1 do - begin - // general floating point conversion - FloatGetSrcPixel(Src, SrcInfo, PixF); - FloatSetDstPixel(Dst, DstInfo, PixF); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - Pix64: TColor64Rec; - PixF: TColorFPRec; -begin - for I := 0 to NumPixels - 1 do - begin - FloatGetSrcPixel(Src, SrcInfo, PixF); - ClampFloatPixel(PixF); - - // floating point channel values are scaled to 1.0 - Pix64.A := ClampToWord(Round(PixF.A * 65535)); - Pix64.R := ClampToWord(Round(PixF.R * 65535)); - Pix64.G := ClampToWord(Round(PixF.G * 65535)); - Pix64.B := ClampToWord(Round(PixF.B * 65535)); - - ChannelSetDstPixel(Dst, DstInfo, Pix64); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo); -var - I: LongInt; - PixF: TColorFPRec; - Gray: TColor64Rec; - Alpha: Word; -begin - for I := 0 to NumPixels - 1 do - begin - FloatGetSrcPixel(Src, SrcInfo, PixF); - ClampFloatPixel(PixF); - - // alpha is saved from source pixel to Alpha, - // Gray value is computed and set to highest word of Pix64 so - // Pix64.Color contains grayscale value scaled to 64 bits - Alpha := ClampToWord(Round(PixF.A * 65535.0)); - Gray.A := ClampToWord(Round((GrayConv.R * PixF.R + GrayConv.G * PixF.G + - GrayConv.B * PixF.B) * 65535.0)); - - GraySetDstPixel(Dst, DstInfo, Gray, Alpha); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; DstPal: PPalette32); -begin - ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries, - GetOption(ImagingColorReductionMask), DstPal); -end; - -procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32); -var - I: LongInt; -begin - // there is only one indexed format now, so it is just a copy - for I := 0 to NumPixels - 1 do - begin - Dst^ := Src^; - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; - for I := 0 to SrcInfo.PaletteEntries - 1 do - DstPal[I] := SrcPal[I]; -end; - -procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal: PPalette32); -var - I: LongInt; - Pix64: TColor64Rec; - Idx: LongWord; -begin - // two most common conversions (Index8->R8G8B8 nad Index8->A8R8G8B8) - // are made separately from general conversions to make them faster - if (SrcInfo.Format = ifIndex8) and (DstInfo.Format in [ifR8G8B8, ifA8R8G8B8]) then - for I := 0 to NumPixels - 1 do - begin - with PColor24Rec(Dst)^ do - begin - R := SrcPal[Src^].R; - G := SrcPal[Src^].G; - B := SrcPal[Src^].B; - end; - if DstInfo.Format = ifA8R8G8B8 then - PColor32Rec(Dst).A := SrcPal[Src^].A; - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - else - for I := 0 to NumPixels - 1 do - begin - // index to palette is read from source and color - // is retrieved from palette entry. Color is then - // scaled to 16bits and written to dest - IndexGetSrcPixel(Src, SrcInfo, Idx); - with Pix64 do - begin - A := SrcPal[Idx].A shl 8; - R := SrcPal[Idx].R shl 8; - G := SrcPal[Idx].G shl 8; - B := SrcPal[Idx].B shl 8; - end; - ChannelSetDstPixel(Dst, DstInfo, Pix64); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal: PPalette32); -var - I: LongInt; - Gray: TColor64Rec; - Alpha: Word; - Idx: LongWord; -begin - // most common conversion (Index8->Gray8) - // is made separately from general conversions to make it faster - if (SrcInfo.Format = ifIndex8) and (DstInfo.Format = ifGray8) then - begin - for I := 0 to NumPixels - 1 do - begin - Dst^ := Round(GrayConv.R * SrcPal[Src^].R + GrayConv.G * SrcPal[Src^].G + - GrayConv.B * SrcPal[Src^].B); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end - end - else - for I := 0 to NumPixels - 1 do - begin - // index to palette is read from source and color - // is retrieved from palette entry. Color is then - // transformed to grayscale and assigned to the highest - // byte of Gray value - IndexGetSrcPixel(Src, SrcInfo, Idx); - Alpha := SrcPal[Idx].A shl 8; - Gray.A := MulDiv(Round(GrayConv.R * SrcPal[Idx].R + GrayConv.G * SrcPal[Idx].G + - GrayConv.B * SrcPal[Idx].B), 65535, 255); - GraySetDstPixel(Dst, DstInfo, Gray, Alpha); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - -procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, - DstInfo: PImageFormatInfo; SrcPal: PPalette32); -var - I: LongInt; - Idx: LongWord; - PixF: TColorFPRec; -begin - for I := 0 to NumPixels - 1 do - begin - // index to palette is read from source and color - // is retrieved from palette entry. Color is then - // scaled to 0..1 and written to dest - IndexGetSrcPixel(Src, SrcInfo, Idx); - with PixF do - begin - A := SrcPal[Idx].A * OneDiv8Bit; - R := SrcPal[Idx].R * OneDiv8Bit; - G := SrcPal[Idx].G * OneDiv8Bit; - B := SrcPal[Idx].B * OneDiv8Bit; - end; - FloatSetDstPixel(Dst, DstInfo, PixF); - Inc(Src, SrcInfo.BytesPerPixel); - Inc(Dst, DstInfo.BytesPerPixel); - end; -end; - - -{ Special formats conversion functions } - -type - // DXT RGB color block - TDXTColorBlock = packed record - Color0, Color1: Word; - Mask: LongWord; - end; - PDXTColorBlock = ^TDXTColorBlock; - - // DXT explicit alpha for a block - TDXTAlphaBlockExp = packed record - Alphas: array[0..3] of Word; - end; - PDXTAlphaBlockExp = ^TDXTAlphaBlockExp; - - // DXT interpolated alpha for a block - TDXTAlphaBlockInt = packed record - Alphas: array[0..7] of Byte; - end; - PDXTAlphaBlockInt = ^TDXTAlphaBlockInt; - - TPixelInfo = record - Color: Word; - Alpha: Byte; - Orig: TColor32Rec; - end; - - TPixelBlock = array[0..15] of TPixelInfo; - -function DecodeCol(Color: Word): TColor32Rec; -{$IFDEF USE_INLINE} inline; {$ENDIF} -begin - Result.A := $FF; -{ Result.R := ((Color and $F800) shr 11) shl 3; - Result.G := ((Color and $07E0) shr 5) shl 2; - Result.B := (Color and $001F) shl 3;} - // this color expansion is slower but gives better results - Result.R := (Color shr 11) * 255 div 31; - Result.G := ((Color shr 5) and $3F) * 255 div 63; - Result.B := (Color and $1F) * 255 div 31; -end; - -procedure DecodeDXT1(SrcBits, DestBits: PByte; Width, Height: LongInt); -var - Sel, X, Y, I, J, K: LongInt; - Block: TDXTColorBlock; - Colors: array[0..3] of TColor32Rec; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - Block := PDXTColorBlock(SrcBits)^; - Inc(SrcBits, SizeOf(Block)); - // we read and decode endpoint colors - Colors[0] := DecodeCol(Block.Color0); - Colors[1] := DecodeCol(Block.Color1); - // and interpolate between them - if Block.Color0 > Block.Color1 then - begin - // interpolation for block without alpha - Colors[2].A := $FF; - Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; - Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; - Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; - Colors[3].A := $FF; - Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; - Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; - Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; - end - else - begin - // interpolation for block with alpha - Colors[2].A := $FF; - Colors[2].R := (Colors[0].R + Colors[1].R) shr 1; - Colors[2].G := (Colors[0].G + Colors[1].G) shr 1; - Colors[2].B := (Colors[0].B + Colors[1].B) shr 1; - Colors[3].A := 0; - Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; - Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; - Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; - end; - - // we distribute the dxt block colors across the 4x4 block of the - // destination image accroding to the dxt block mask - K := 0; - for J := 0 to 3 do - for I := 0 to 3 do - begin - Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1); - if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then - PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] := - Colors[Sel]; - Inc(K); - end; - end; -end; - -procedure DecodeDXT3(SrcBits, DestBits: PByte; Width, Height: LongInt); -var - Sel, X, Y, I, J, K: LongInt; - Block: TDXTColorBlock; - AlphaBlock: TDXTAlphaBlockExp; - Colors: array[0..3] of TColor32Rec; - AWord: Word; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - AlphaBlock := PDXTAlphaBlockExp(SrcBits)^; - Inc(SrcBits, SizeOf(AlphaBlock)); - Block := PDXTColorBlock(SrcBits)^; - Inc(SrcBits, SizeOf(Block)); - // we read and decode endpoint colors - Colors[0] := DecodeCol(Block.Color0); - Colors[1] := DecodeCol(Block.Color1); - // and interpolate between them - Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; - Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; - Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; - Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; - Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; - Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; - - // we distribute the dxt block colors and alphas - // across the 4x4 block of the destination image - // accroding to the dxt block mask and alpha block - K := 0; - for J := 0 to 3 do - begin - AWord := AlphaBlock.Alphas[J]; - for I := 0 to 3 do - begin - Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1); - if (X shl 2 + I < Width) and (Y shl 2 + J < Height) then - begin - Colors[Sel].A := AWord and $0F; - Colors[Sel].A := Colors[Sel].A or (Colors[Sel].A shl 4); - PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] := - Colors[Sel]; - end; - Inc(K); - AWord := AWord shr 4; - end; - end; - end; -end; - -procedure GetInterpolatedAlphas(var AlphaBlock: TDXTAlphaBlockInt); -begin - with AlphaBlock do - if Alphas[0] > Alphas[1] then - begin - // Interpolation of six alphas - Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7; - Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7; - Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7; - Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7; - Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7; - Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7; - end - else - begin - // Interpolation of four alphas, two alphas are set directly - Alphas[2] := (4 * Alphas[0] + 1 * Alphas[1] + 2) div 5; - Alphas[3] := (3 * Alphas[0] + 2 * Alphas[1] + 2) div 5; - Alphas[4] := (2 * Alphas[0] + 3 * Alphas[1] + 2) div 5; - Alphas[5] := (1 * Alphas[0] + 4 * Alphas[1] + 2) div 5; - Alphas[6] := 0; - Alphas[7] := $FF; - end; -end; - -procedure DecodeDXT5(SrcBits, DestBits: PByte; Width, Height: LongInt); -var - Sel, X, Y, I, J, K: LongInt; - Block: TDXTColorBlock; - AlphaBlock: TDXTAlphaBlockInt; - Colors: array[0..3] of TColor32Rec; - AMask: array[0..1] of LongWord; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - AlphaBlock := PDXTAlphaBlockInt(SrcBits)^; - Inc(SrcBits, SizeOf(AlphaBlock)); - Block := PDXTColorBlock(SrcBits)^; - Inc(SrcBits, SizeOf(Block)); - // we read and decode endpoint colors - Colors[0] := DecodeCol(Block.Color0); - Colors[1] := DecodeCol(Block.Color1); - // and interpolate between them - Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; - Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; - Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; - Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; - Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; - Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; - // 6 bit alpha mask is copied into two long words for - // easier usage - AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF; - AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF; - // alpha interpolation between two endpoint alphas - GetInterpolatedAlphas(AlphaBlock); - - // we distribute the dxt block colors and alphas - // across the 4x4 block of the destination image - // accroding to the dxt block mask and alpha block mask - K := 0; - for J := 0 to 3 do - for I := 0 to 3 do - begin - Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1); - if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then - begin - Colors[Sel].A := AlphaBlock.Alphas[AMask[J shr 1] and 7]; - PPalette32(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := - Colors[Sel]; - end; - Inc(K); - AMask[J shr 1] := AMask[J shr 1] shr 3; - end; - end; -end; - -procedure GetBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos, - Width, Height: LongInt); -var - X, Y, I: LongInt; - Src: PColor32Rec; -begin - I := 0; - // 4x4 pixel block is filled with information about every - // pixel in the block: alpha, original color, 565 color - for Y := 0 to 3 do - for X := 0 to 3 do - begin - Src := @PPalette32(SrcBits)[(YPos shl 2 + Y) * Width + XPos shl 2 + X]; - Block[I].Color := ((Src.R shr 3) shl 11) or ((Src.G shr 2) shl 5) or - (Src.B shr 3); - Block[I].Alpha := Src.A; - Block[I].Orig := Src^; - Inc(I); - end; -end; - -function ColorDistance(const C1, C2: TColor32Rec): LongInt; -{$IFDEF USE_INLINE} inline;{$ENDIF} -begin - Result := (C1.R - C2.R) * (C1.R - C2.R) + - (C1.G - C2.G) * (C1.G - C2.G) + (C1.B - C2.B) * (C1.B - C2.B); -end; - -procedure GetEndpoints(const Block: TPixelBlock; var Ep0, Ep1: Word); -var - I, J, Farthest, Dist: LongInt; - Colors: array[0..15] of TColor32Rec; -begin - // we choose two colors from the pixel block which has the - // largest distance between them - for I := 0 to 15 do - Colors[I] := Block[I].Orig; - Farthest := -1; - for I := 0 to 15 do - for J := I + 1 to 15 do - begin - Dist := ColorDistance(Colors[I], Colors[J]); - if Dist > Farthest then - begin - Farthest := Dist; - Ep0 := Block[I].Color; - Ep1 := Block[J].Color; - end; - end; -end; - -procedure GetAlphaEndpoints(const Block: TPixelBlock; var Min, Max: Byte); -var - I: LongInt; -begin - Min := 255; - Max := 0; - // we choose the lowest and the highest alpha values - for I := 0 to 15 do - begin - if Block[I].Alpha < Min then - Min := Block[I].Alpha; - if Block[I].Alpha > Max then - Max := Block[I].Alpha; - end; -end; - -procedure FixEndpoints(var Ep0, Ep1: Word; HasAlpha: Boolean); -var - Temp: Word; -begin - // if dxt block has alpha information, Ep0 must be smaller - // than Ep1, if the block has no alpha Ep1 must be smaller - if HasAlpha then - begin - if Ep0 > Ep1 then - begin - Temp := Ep0; - Ep0 := Ep1; - Ep1 := Temp; - end; - end - else - if Ep0 < Ep1 then - begin - Temp := Ep0; - Ep0 := Ep1; - Ep1 := Temp; - end; -end; - -function GetColorMask(Ep0, Ep1: Word; NumCols: LongInt; - const Block: TPixelBlock): LongWord; -var - I, J, Closest, Dist: LongInt; - Colors: array[0..3] of TColor32Rec; - Mask: array[0..15] of Byte; -begin - // we decode endpoint colors - Colors[0] := DecodeCol(Ep0); - Colors[1] := DecodeCol(Ep1); - // and interpolate colors between (3 for DXT1 with alpha, 4 for the others) - if NumCols = 3 then - begin - Colors[2].R := (Colors[0].R + Colors[1].R) shr 1; - Colors[2].G := (Colors[0].G + Colors[1].G) shr 1; - Colors[2].B := (Colors[0].B + Colors[1].B) shr 1; - Colors[3].R := (Colors[0].R + Colors[1].R) shr 1; - Colors[3].G := (Colors[0].G + Colors[1].G) shr 1; - Colors[3].B := (Colors[0].B + Colors[1].B) shr 1; - end - else - begin - Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; - Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; - Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; - Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; - Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; - Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; - end; - - for I := 0 to 15 do - begin - // this is only for DXT1 with alpha - if (Block[I].Alpha < 128) and (NumCols = 3) then - begin - Mask[I] := 3; - Continue; - end; - // for each of the 16 input pixels the nearest color in the - // 4 dxt colors is found - Closest := MaxInt; - for J := 0 to NumCols - 1 do - begin - Dist := ColorDistance(Block[I].Orig, Colors[J]); - if Dist < Closest then - begin - Closest := Dist; - Mask[I] := J; - end; - end; - end; - - Result := 0; - for I := 0 to 15 do - Result := Result or (Mask[I] shl (I shl 1)); -end; - -procedure GetAlphaMask(Ep0, Ep1: Byte; var Block: TPixelBlock; Mask: PByteArray); -var - Alphas: array[0..7] of Byte; - M: array[0..15] of Byte; - I, J, Closest, Dist: LongInt; -begin - Alphas[0] := Ep0; - Alphas[1] := Ep1; - // interpolation between two given alpha endpoints - // (I use 6 interpolated values mode) - Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7; - Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7; - Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7; - Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7; - Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7; - Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7; - - // the closest interpolated values for each of the input alpha - // is found - for I := 0 to 15 do - begin - Closest := MaxInt; - for J := 0 to 7 do - begin - Dist := Abs(Alphas[J] - Block[I].Alpha); - if Dist < Closest then - begin - Closest := Dist; - M[I] := J; - end; - end; - end; - - Mask[0] := M[0] or (M[1] shl 3) or ((M[2] and 3) shl 6); - Mask[1] := ((M[2] and 4) shr 2) or (M[3] shl 1) or (M[4] shl 4) or - ((M[5] and 1) shl 7); - Mask[2] := ((M[5] and 6) shr 1) or (M[6] shl 2) or (M[7] shl 5); - Mask[3] := M[8] or (M[9] shl 3) or ((M[10] and 3) shl 6); - Mask[4] := ((M[10] and 4) shr 2) or (M[11] shl 1) or (M[12] shl 4) or - ((M[13] and 1) shl 7); - Mask[5] := ((M[13] and 6) shr 1) or (M[14] shl 2) or (M[15] shl 5); -end; - - -procedure EncodeDXT1(SrcBits: PByte; DestBits: PByte; Width, Height: LongInt); -var - X, Y, I: LongInt; - HasAlpha: Boolean; - Block: TDXTColorBlock; - Pixels: TPixelBlock; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - GetBlock(Pixels, SrcBits, X, Y, Width, Height); - HasAlpha := False; - for I := 0 to 15 do - if Pixels[I].Alpha < 128 then - begin - HasAlpha := True; - Break; - end; - GetEndpoints(Pixels, Block.Color0, Block.Color1); - FixEndpoints(Block.Color0, Block.Color1, HasAlpha); - if HasAlpha then - Block.Mask := GetColorMask(Block.Color0, Block.Color1, 3, Pixels) - else - Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels); - PDXTColorBlock(DestBits)^ := Block; - Inc(DestBits, SizeOf(Block)); - end; -end; - -procedure EncodeDXT3(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt); -var - X, Y, I: LongInt; - Block: TDXTColorBlock; - AlphaBlock: TDXTAlphaBlockExp; - Pixels: TPixelBlock; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - GetBlock(Pixels, SrcBits, X, Y, Width, Height); - for I := 0 to 7 do - PByteArray(@AlphaBlock.Alphas)[I] := - (Pixels[I shl 1].Alpha shr 4) or ((Pixels[I shl 1 + 1].Alpha shr 4) shl 4); - GetEndpoints(Pixels, Block.Color0, Block.Color1); - FixEndpoints(Block.Color0, Block.Color1, False); - Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels); - PDXTAlphaBlockExp(DestBits)^ := AlphaBlock; - Inc(DestBits, SizeOf(AlphaBlock)); - PDXTColorBlock(DestBits)^ := Block; - Inc(DestBits, SizeOf(Block)); - end; -end; - -procedure EncodeDXT5(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt); -var - X, Y: LongInt; - Block: TDXTColorBlock; - AlphaBlock: TDXTAlphaBlockInt; - Pixels: TPixelBlock; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - GetBlock(Pixels, SrcBits, X, Y, Width, Height); - GetEndpoints(Pixels, Block.Color0, Block.Color1); - FixEndpoints(Block.Color0, Block.Color1, False); - Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels); - GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); - GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, - PByteArray(@AlphaBlock.Alphas[2])); - PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; - Inc(DestBits, SizeOf(AlphaBlock)); - PDXTColorBlock(DestBits)^ := Block; - Inc(DestBits, SizeOf(Block)); - end; -end; - -type - TBTCBlock = packed record - MLower, MUpper: Byte; - BitField: Word; - end; - PBTCBlock = ^TBTCBlock; - -procedure EncodeBTC(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); -var - X, Y, I, J: Integer; - Block: TBTCBlock; - M, MLower, MUpper, K: Integer; - Pixels: array[0..15] of Byte; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - M := 0; - MLower := 0; - MUpper := 0; - FillChar(Block, SizeOf(Block), 0); - K := 0; - - // Store 4x4 pixels and compute average, lower, and upper intensity levels - for I := 0 to 3 do - for J := 0 to 3 do - begin - Pixels[K] := PByteArray(SrcBits)[(Y shl 2 + I) * Width + X shl 2 + J]; - Inc(M, Pixels[K]); - Inc(K); - end; - - M := M div 16; - K := 0; - - // Now compute upper and lower levels, number of upper pixels, - // and update bit field (1 when pixel is above avg. level M) - for I := 0 to 15 do - begin - if Pixels[I] > M then - begin - Inc(MUpper, Pixels[I]); - Inc(K); - Block.BitField := Block.BitField or (1 shl I); - end - else - Inc(MLower, Pixels[I]); - end; - - // Scale levels and save them to block - if K > 0 then - Block.MUpper := ClampToByte(MUpper div K) - else - Block.MUpper := 0; - Block.MLower := ClampToByte(MLower div (16 - K)); - - // Finally save block to dest data - PBTCBlock(DestBits)^ := Block; - Inc(DestBits, SizeOf(Block)); - end; -end; - -procedure GetOneChannelBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos, - Width, Height, BytesPP, ChannelIdx: Integer); -var - X, Y, I: Integer; - Src: PByte; -begin - I := 0; - // 4x4 pixel block is filled with information about every pixel in the block, - // but only one channel value is stored in Alpha field - for Y := 0 to 3 do - for X := 0 to 3 do - begin - Src := @PByteArray(SrcBits)[(YPos * 4 + Y) * Width * BytesPP + - (XPos * 4 + X) * BytesPP + ChannelIdx]; - Block[I].Alpha := Src^; - Inc(I); - end; -end; - -procedure EncodeATI1N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); -var - X, Y: Integer; - AlphaBlock: TDXTAlphaBlockInt; - Pixels: TPixelBlock; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - // Encode one channel - GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 1, 0); - GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); - GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, - PByteArray(@AlphaBlock.Alphas[2])); - PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; - Inc(DestBits, SizeOf(AlphaBlock)); - end; -end; - -procedure EncodeATI2N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); -var - X, Y: Integer; - AlphaBlock: TDXTAlphaBlockInt; - Pixels: TPixelBlock; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - // Encode Red/X channel - GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelRed); - GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); - GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, - PByteArray(@AlphaBlock.Alphas[2])); - PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; - Inc(DestBits, SizeOf(AlphaBlock)); - // Encode Green/Y channel - GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelGreen); - GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); - GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, - PByteArray(@AlphaBlock.Alphas[2])); - PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; - Inc(DestBits, SizeOf(AlphaBlock)); - end; -end; - -procedure EncodeBinary(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); -var - Src: PByte absolute SrcBits; - Bitmap: PByteArray absolute DestBits; - X, Y, WidthBytes: Integer; - PixelTresholded, Treshold: Byte; -begin - Treshold := ClampToByte(GetOption(ImagingBinaryTreshold)); - WidthBytes := (Width + 7) div 8; - - for Y := 0 to Height - 1 do - for X := 0 to Width - 1 do - begin - if Src^ > Treshold then - PixelTresholded := 255 - else - PixelTresholded := 0; - - Bitmap[Y * WidthBytes + X div 8] := Bitmap[Y * WidthBytes + X div 8] or // OR current value of byte with following: - (PixelTresholded and 1) // To make 1 from 255, 0 remains 0 - shl (7 - (X mod 8)); // Put current bit to proper place in byte - - Inc(Src); - end; -end; - -procedure DecodeBTC(SrcBits, DestBits: PByte; Width, Height: Integer); -var - X, Y, I, J, K: Integer; - Block: TBTCBlock; - Dest: PByte; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - Block := PBTCBlock(SrcBits)^; - Inc(SrcBits, SizeOf(Block)); - K := 0; - - // Just write MUpper when there is '1' in bit field and MLower - // when there is '0' - for I := 0 to 3 do - for J := 0 to 3 do - begin - Dest := @PByteArray(DestBits)[(Y shl 2 + I) * Width + X shl 2 + J]; - if Block.BitField and (1 shl K) <> 0 then - Dest^ := Block.MUpper - else - Dest^ := Block.MLower; - Inc(K); - end; - end; -end; - -procedure DecodeATI1N(SrcBits, DestBits: PByte; Width, Height: Integer); -var - X, Y, I, J: Integer; - AlphaBlock: TDXTAlphaBlockInt; - AMask: array[0..1] of LongWord; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - AlphaBlock := PDXTAlphaBlockInt(SrcBits)^; - Inc(SrcBits, SizeOf(AlphaBlock)); - // 6 bit alpha mask is copied into two long words for - // easier usage - AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF; - AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF; - // alpha interpolation between two endpoint alphas - GetInterpolatedAlphas(AlphaBlock); - - // we distribute the dxt block alphas - // across the 4x4 block of the destination image - for J := 0 to 3 do - for I := 0 to 3 do - begin - PByteArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := - AlphaBlock.Alphas[AMask[J shr 1] and 7]; - AMask[J shr 1] := AMask[J shr 1] shr 3; - end; - end; -end; - -procedure DecodeATI2N(SrcBits, DestBits: PByte; Width, Height: Integer); -var - X, Y, I, J: Integer; - Color: TColor32Rec; - AlphaBlock1, AlphaBlock2: TDXTAlphaBlockInt; - AMask1: array[0..1] of LongWord; - AMask2: array[0..1] of LongWord; -begin - for Y := 0 to Height div 4 - 1 do - for X := 0 to Width div 4 - 1 do - begin - // Read the first alpha block and get masks - AlphaBlock1 := PDXTAlphaBlockInt(SrcBits)^; - Inc(SrcBits, SizeOf(AlphaBlock1)); - AMask1[0] := PLongWord(@AlphaBlock1.Alphas[2])^ and $00FFFFFF; - AMask1[1] := PLongWord(@AlphaBlock1.Alphas[5])^ and $00FFFFFF; - // Read the secind alpha block and get masks - AlphaBlock2 := PDXTAlphaBlockInt(SrcBits)^; - Inc(SrcBits, SizeOf(AlphaBlock2)); - AMask2[0] := PLongWord(@AlphaBlock2.Alphas[2])^ and $00FFFFFF; - AMask2[1] := PLongWord(@AlphaBlock2.Alphas[5])^ and $00FFFFFF; - // alpha interpolation between two endpoint alphas - GetInterpolatedAlphas(AlphaBlock1); - GetInterpolatedAlphas(AlphaBlock2); - - Color.A := $FF; - Color.B := 0; - - // Distribute alpha block values across 4x4 pixel block, - // first alpha block represents Red channel, second is Green. - for J := 0 to 3 do - for I := 0 to 3 do - begin - Color.R := AlphaBlock1.Alphas[AMask1[J shr 1] and 7]; - Color.G := AlphaBlock2.Alphas[AMask2[J shr 1] and 7]; - PColor32RecArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := Color; - AMask1[J shr 1] := AMask1[J shr 1] shr 3; - AMask2[J shr 1] := AMask2[J shr 1] shr 3; - end; - end; -end; - -procedure DecodeBinary(SrcBits, DestBits: PByte; Width, Height: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} -begin - Convert1To8(SrcBits, DestBits, Width, Height, (Width + 7) div 8, True); -end; - -procedure SpecialToUnSpecial(const SrcImage: TImageData; DestBits: Pointer; - SpecialFormat: TImageFormat); -begin - case SpecialFormat of - ifDXT1: DecodeDXT1(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - ifDXT3: DecodeDXT3(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - ifDXT5: DecodeDXT5(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - ifBTC: DecodeBTC (SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - ifATI1N: DecodeATI1N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - ifATI2N: DecodeATI2N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - ifBinary: DecodeBinary(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); - end; -end; - -procedure UnSpecialToSpecial(SrcBits: Pointer; const DestImage: TImageData; - SpecialFormat: TImageFormat); -begin - case SpecialFormat of - ifDXT1: EncodeDXT1(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - ifDXT3: EncodeDXT3(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - ifDXT5: EncodeDXT5(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - ifBTC: EncodeBTC (SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - ifATI1N: EncodeATI1N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - ifATI2N: EncodeATI2N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - ifBinary: EncodeBinary(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); - end; -end; - -procedure ConvertSpecial(var Image: TImageData; - SrcInfo, DstInfo: PImageFormatInfo); -var - WorkImage: TImageData; - - procedure CheckSize(var Img: TImageData; Info: PImageFormatInfo); - var - Width, Height: Integer; - begin - Width := Img.Width; - Height := Img.Height; - DstInfo.CheckDimensions(Info.Format, Width, Height); - ResizeImage(Img, Width, Height, rfNearest); - end; - -begin - if SrcInfo.IsSpecial and DstInfo.IsSpecial then - begin - // Convert source to nearest 'normal' format - InitImage(WorkImage); - NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage); - SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format); - FreeImage(Image); - // Make sure output of SpecialToUnSpecial is the same as input of - // UnSpecialToSpecial - if SrcInfo.SpecialNearestFormat <> DstInfo.SpecialNearestFormat then - ConvertImage(WorkImage, DstInfo.SpecialNearestFormat); - // Convert work image to dest special format - CheckSize(WorkImage, DstInfo); - NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image); - UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format); - FreeImage(WorkImage); - end - else if SrcInfo.IsSpecial and not DstInfo.IsSpecial then - begin - // Convert source to nearest 'normal' format - InitImage(WorkImage); - NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage); - SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format); - FreeImage(Image); - // Now convert to dest format - ConvertImage(WorkImage, DstInfo.Format); - Image := WorkImage; - end - else if not SrcInfo.IsSpecial and DstInfo.IsSpecial then - begin - // Convert source to nearest format - WorkImage := Image; - ConvertImage(WorkImage, DstInfo.SpecialNearestFormat); - // Now convert from nearest to dest - CheckSize(WorkImage, DstInfo); - InitImage(Image); - NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image); - UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format); - FreeImage(WorkImage); - end; -end; - -function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; -begin - if FInfos[Format] <> nil then - Result := Width * Height * FInfos[Format].BytesPerPixel - else - Result := 0; -end; - -procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt); -begin -end; - -function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; -begin - // DXT can be used only for images with dimensions that are - // multiples of four - CheckDXTDimensions(Format, Width, Height); - Result := Width * Height; - if Format in [ifDXT1, ifATI1N] then - Result := Result div 2; -end; - -procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt); -begin - // DXT image dimensions must be multiples of four - Width := (Width + 3) and not 3; // div 4 * 4; - Height := (Height + 3) and not 3; // div 4 * 4; -end; - -function GetBTCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; -begin - // BTC can be used only for images with dimensions that are - // multiples of four - CheckDXTDimensions(Format, Width, Height); - Result := Width * Height div 4; // 2bits/pixel -end; - -function GetBinaryPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; -begin - // Binary images are aligned on BYTE boundary - Result := ((Width + 7) div 8) * Height; // 1bit/pixel -end; - -{ Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo } - -function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; -begin - Result.Color := PLongWord(Bits)^; -end; - -procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); -begin - PLongWord(Bits)^ := Color.Color; -end; - -function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; -begin - Result.A := PColor32Rec(Bits).A * OneDiv8Bit; - Result.R := PColor32Rec(Bits).R * OneDiv8Bit; - Result.G := PColor32Rec(Bits).G * OneDiv8Bit; - Result.B := PColor32Rec(Bits).B * OneDiv8Bit; -end; - -procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); -begin - PColor32Rec(Bits).A := ClampToByte(Round(Color.A * 255.0)); - PColor32Rec(Bits).R := ClampToByte(Round(Color.R * 255.0)); - PColor32Rec(Bits).G := ClampToByte(Round(Color.G * 255.0)); - PColor32Rec(Bits).B := ClampToByte(Round(Color.B * 255.0)); -end; - -function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; -begin - case Info.Format of - ifR8G8B8, ifX8R8G8B8: - begin - Result.A := $FF; - PColor24Rec(@Result)^ := PColor24Rec(Bits)^; - end; - ifGray8, ifA8Gray8: - begin - if Info.HasAlphaChannel then - Result.A := PWordRec(Bits).High - else - Result.A := $FF; - Result.R := PWordRec(Bits).Low; - Result.G := PWordRec(Bits).Low; - Result.B := PWordRec(Bits).Low; - end; - end; -end; - -procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); -begin - case Info.Format of - ifR8G8B8, ifX8R8G8B8: - begin - PColor24Rec(Bits)^ := PColor24Rec(@Color)^; - end; - ifGray8, ifA8Gray8: - begin - if Info.HasAlphaChannel then - PWordRec(Bits).High := Color.A; - PWordRec(Bits).Low := Round(GrayConv.R * Color.R + GrayConv.G * Color.G + - GrayConv.B * Color.B); - end; - end; -end; - -function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; -begin - case Info.Format of - ifR8G8B8, ifX8R8G8B8: - begin - Result.A := 1.0; - Result.R := PColor24Rec(Bits).R * OneDiv8Bit; - Result.G := PColor24Rec(Bits).G * OneDiv8Bit; - Result.B := PColor24Rec(Bits).B * OneDiv8Bit; - end; - ifGray8, ifA8Gray8: - begin - if Info.HasAlphaChannel then - Result.A := PWordRec(Bits).High * OneDiv8Bit - else - Result.A := 1.0; - Result.R := PWordRec(Bits).Low * OneDiv8Bit; - Result.G := PWordRec(Bits).Low * OneDiv8Bit; - Result.B := PWordRec(Bits).Low * OneDiv8Bit; - end; - end; -end; - -procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); -begin - case Info.Format of - ifR8G8B8, ifX8R8G8B8: - begin - PColor24Rec(Bits).R := ClampToByte(Round(Color.R * 255.0)); - PColor24Rec(Bits).G := ClampToByte(Round(Color.G * 255.0)); - PColor24Rec(Bits).B := ClampToByte(Round(Color.B * 255.0)); - end; - ifGray8, ifA8Gray8: - begin - if Info.HasAlphaChannel then - PWordRec(Bits).High := ClampToByte(Round(Color.A * 255.0)); - PWordRec(Bits).Low := ClampToByte(Round((GrayConv.R * Color.R + GrayConv.G * Color.G + - GrayConv.B * Color.B) * 255.0)); - end; - end; -end; - -function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; -begin - case Info.Format of - ifA32R32G32B32F, ifA32B32G32R32F: - begin - Result := PColorFPRec(Bits)^; - end; - ifR32G32B32F, ifB32G32R32F: - begin - Result.A := 1.0; - Result.Color96Rec := PColor96FPRec(Bits)^; - end; - ifR32F: - begin - Result.A := 1.0; - Result.R := PSingle(Bits)^; - Result.G := 0.0; - Result.B := 0.0; - end; - end; - if Info.IsRBSwapped then - SwapValues(Result.R, Result.B); -end; - -procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); -begin - case Info.Format of - ifA32R32G32B32F, ifA32B32G32R32F: - begin - PColorFPRec(Bits)^ := Color; - end; - ifR32G32B32F, ifB32G32R32F: - begin - PColor96FPRec(Bits)^ := Color.Color96Rec; - end; - ifR32F: - begin - PSingle(Bits)^ := Color.R; - end; - end; - if Info.IsRBSwapped then - SwapValues(PColor96FPRec(Bits).R, PColor96FPRec(Bits).B); -end; - -initialization - // Initialize default sampling filter function pointers and radii - SamplingFilterFunctions[sfNearest] := FilterNearest; - SamplingFilterFunctions[sfLinear] := FilterLinear; - SamplingFilterFunctions[sfCosine] := FilterCosine; - SamplingFilterFunctions[sfHermite] := FilterHermite; - SamplingFilterFunctions[sfQuadratic] := FilterQuadratic; - SamplingFilterFunctions[sfGaussian] := FilterGaussian; - SamplingFilterFunctions[sfSpline] := FilterSpline; - SamplingFilterFunctions[sfLanczos] := FilterLanczos; - SamplingFilterFunctions[sfMitchell] := FilterMitchell; - SamplingFilterFunctions[sfCatmullRom] := FilterCatmullRom; - SamplingFilterRadii[sfNearest] := 1.0; - SamplingFilterRadii[sfLinear] := 1.0; - SamplingFilterRadii[sfCosine] := 1.0; - SamplingFilterRadii[sfHermite] := 1.0; - SamplingFilterRadii[sfQuadratic] := 1.5; - SamplingFilterRadii[sfGaussian] := 1.25; - SamplingFilterRadii[sfSpline] := 2.0; - SamplingFilterRadii[sfLanczos] := 3.0; - SamplingFilterRadii[sfMitchell] := 2.0; - SamplingFilterRadii[sfCatmullRom] := 2.0; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77 Changes/Bug Fixes ------------------------------------- - - Added ConvertToPixel32 helper function. - - -- 0.26.5 Changes/Bug Fixes ----------------------------------- - - Removed optimized codepatch for few data formats from StretchResample - function. It was quite buggy and not so much faster anyway. - - Added PaletteHasAlpha function. - - Added support functions for ifBinary data format. - - Added optional pixel scaling to Convert1To8, Convert2To8, - abd Convert4To8 functions. - - -- 0.26.3 Changes/Bug Fixes ----------------------------------- - - Filtered resampling ~10% faster now. - - Fixed DXT3 alpha encoding. - - ifIndex8 format now has HasAlphaChannel=True. - - -- 0.25.0 Changes/Bug Fixes ----------------------------------- - - Made some resampling stuff public so that it can be used in canvas class. - - Added some color constructors. - - Added VisualizePalette helper function. - - Fixed ConvertSpecial, not very readable before and error when - converting special->special. - - -- 0.24.3 Changes/Bug Fixes ----------------------------------- - - Some refactorings a changes to DXT based formats. - - Added ifATI1N and ifATI2N image data formats support structures and functions. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added ifBTC image format support structures and functions. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - FillMipMapLevel now works well with indexed and special formats too. - - Moved Convert1To8 and Convert4To8 functions from ImagingBitmaps here - and created new Convert2To8 function. They are now used by more than one - file format loader. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - StretchResample now uses pixel get/set functions stored in - TImageFormatInfo so it is much faster for formats that override - them with optimized ones - - added pixel set/get functions optimized for various image formats - (to be stored in TImageFormatInfo) - - bug in ConvertSpecial caused problems when converting DXTC images - to bitmaps in ImagingCoponents - - bug in StretchRect caused that it didn't work with ifR32F and - ifR16F formats - - removed leftover code in FillMipMapLevel which disabled - filtered resizing of images witch ChannelSize <> 8bits - - added half float converting functions and support for half based - image formats where needed - - added TranslatePixel and IsImageFormatValid functions - - fixed possible range overflows when converting from FP to integer images - - added pixel set/get functions: GetPixel32Generic, GetPixelFPGeneric, - SetPixel32Generic, SetPixelFPGeneric - - fixed occasional range overflows in StretchResample - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - added StretchNearest, StretchResample and some sampling functions - - added ChannelCount values to TImageFormatInfo constants - - added resolution validity check to GetDXTPixelsSize - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - added RBSwapFormat values to some TImageFromatInfo definitions - - fixed bug in ConvertSpecial (causing DXT images to convert only to 32bit) - - added CopyPixel, ComparePixels helper functions - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - replaced pixel format conversions for colors not to be - darkened when converting from low bit counts - - ReduceColorsMedianCut was updated to support creating one - optimal palette for more images and it is somewhat faster - now too - - there was ugly bug in DXTC dimensions checking -} - -end. - diff --git a/3rd/Imaging/Source/ImagingGif.pas b/3rd/Imaging/Source/ImagingGif.pas deleted file mode 100644 index 13a6555ca..000000000 --- a/3rd/Imaging/Source/ImagingGif.pas +++ /dev/null @@ -1,1291 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for GIF images.} -unit ImagingGif; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, Imaging, ImagingTypes, ImagingIO, ImagingUtility; - -type - { GIF (Graphics Interchange Format) loader/saver class. GIF was - (and is still used) popular format for storing images supporting - multiple images per file and single color transparency. - Pixel format is 8 bit indexed where each image frame can have - its own color palette. GIF uses lossless LZW compression - (patent expired few years ago). - Imaging can load and save all GIFs with all frames and supports - transparency. Imaging can load just raw ifIndex8 frames or - also animate them in ifA8R8G8B8 format. See ImagingGIFLoadAnimated option.} - TGIFFileFormat = class(TImageFileFormat) - private - FLoadAnimated: LongBool; - function InterlaceStep(Y, Height: Integer; var Pass: Integer): Integer; - procedure LZWDecompress(Stream: TStream; Handle: TImagingHandle; - Width, Height: Integer; Interlaced: Boolean; Data: Pointer); - procedure LZWCompress(const IO: TIOFunctions; Handle: TImagingHandle; - Width, Height, BitCount: Integer; Interlaced: Boolean; Data: Pointer); - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - published - property LoadAnimated: LongBool read FLoadAnimated write FLoadAnimated; - end; - -implementation - -const - SGIFFormatName = 'Graphics Interchange Format'; - SGIFMasks = '*.gif'; - GIFSupportedFormats: TImageFormats = [ifIndex8]; - GIFDefaultLoadAnimated = True; - -type - TGIFVersion = (gv87, gv89); - TDisposalMethod = (dmNoRemoval, dmLeave, dmRestoreBackground, - dmRestorePrevious, dmReserved4, dmReserved5, dmReserved6, dmReserved7); - -const - GIFSignature: TChar3 = 'GIF'; - GIFVersions: array[TGIFVersion] of TChar3 = ('87a', '89a'); - GIFDefaultDelay = 65; - - // Masks for accessing fields in PackedFields of TGIFHeader - GIFGlobalColorTable = $80; - GIFColorResolution = $70; - GIFColorTableSorted = $08; - GIFColorTableSize = $07; - - // Masks for accessing fields in PackedFields of TImageDescriptor - GIFLocalColorTable = $80; - GIFInterlaced = $40; - GIFLocalTableSorted = $20; - - // Block identifiers - GIFPlainText: Byte = $01; - GIFGraphicControlExtension: Byte = $F9; - GIFCommentExtension: Byte = $FE; - GIFApplicationExtension: Byte = $FF; - GIFImageDescriptor: Byte = Ord(','); - GIFExtensionIntroducer: Byte = Ord('!'); - GIFTrailer: Byte = Ord(';'); - GIFBlockTerminator: Byte = $00; - - // Masks for accessing fields in PackedFields of TGraphicControlExtension - GIFTransparent = $01; - GIFUserInput = $02; - GIFDisposalMethod = $1C; - -const - // Netscape sub block types - GIFAppLoopExtension = 1; - GIFAppBufferExtension = 2; - -type - TGIFHeader = packed record - // File header part - Signature: TChar3; // Header Signature (always "GIF") - Version: TChar3; // GIF format version("87a" or "89a") - // Logical Screen Descriptor part - ScreenWidth: Word; // Width of Display Screen in Pixels - ScreenHeight: Word; // Height of Display Screen in Pixels - PackedFields: Byte; // Screen and color map information - BackgroundColorIndex: Byte; // Background color index (in global color table) - AspectRatio: Byte; // Pixel aspect ratio, ratio = (AspectRatio + 15) / 64 - end; - - TImageDescriptor = packed record - //Separator: Byte; // leave that out since we always read one bye ahead - Left: Word; // X position of image with respect to logical screen - Top: Word; // Y position - Width: Word; - Height: Word; - PackedFields: Byte; - end; - -const - // GIF extension labels - GIFExtTypeGraphic = $F9; - GIFExtTypePlainText = $01; - GIFExtTypeApplication = $FF; - GIFExtTypeComment = $FE; - -type - TGraphicControlExtension = packed record - BlockSize: Byte; - PackedFields: Byte; - DelayTime: Word; - TransparentColorIndex: Byte; - Terminator: Byte; - end; - -type - TGIFIdentifierCode = array[0..7] of AnsiChar; - TGIFAuthenticationCode = array[0..2] of AnsiChar; - TGIFApplicationRec = packed record - Identifier: TGIFIdentifierCode; - Authentication: TGIFAuthenticationCode; - end; - -const - CodeTableSize = 4096; - HashTableSize = 17777; - -type - TReadContext = record - Inx: Integer; - Size: Integer; - Buf: array [0..255 + 4] of Byte; - CodeSize: Integer; - ReadMask: Integer; - end; - PReadContext = ^TReadContext; - - TWriteContext = record - Inx: Integer; - CodeSize: Integer; - Buf: array [0..255 + 4] of Byte; - end; - PWriteContext = ^TWriteContext; - - TOutputContext = record - W: Integer; - H: Integer; - X: Integer; - Y: Integer; - BitsPerPixel: Integer; - Pass: Integer; - Interlace: Boolean; - LineIdent: Integer; - Data: Pointer; - CurrLineData: Pointer; - end; - - TImageDict = record - Tail: Word; - Index: Word; - Col: Byte; - end; - PImageDict = ^TImageDict; - - PIntCodeTable = ^TIntCodeTable; - TIntCodeTable = array [0..CodeTableSize - 1] of Word; - - TDictTable = array [0..CodeTableSize - 1] of TImageDict; - PDictTable = ^TDictTable; - -resourcestring - SGIFDecodingError = 'Error when decoding GIF LZW data'; - -{ - TGIFFileFormat implementation -} - -procedure TGIFFileFormat.Define; -begin - inherited; - FName := SGIFFormatName; - FFeatures := [ffLoad, ffSave, ffMultiImage]; - FSupportedFormats := GIFSupportedFormats; - FLoadAnimated := GIFDefaultLoadAnimated; - - AddMasks(SGIFMasks); - RegisterOption(ImagingGIFLoadAnimated, @FLoadAnimated); -end; - -function TGIFFileFormat.InterlaceStep(Y, Height: Integer; var Pass: Integer): Integer; -begin - Result := Y; - case Pass of - 0, 1: - Inc(Result, 8); - 2: - Inc(Result, 4); - 3: - Inc(Result, 2); - end; - if Result >= Height then - begin - if Pass = 0 then - begin - Pass := 1; - Result := 4; - if Result < Height then - Exit; - end; - if Pass = 1 then - begin - Pass := 2; - Result := 2; - if Result < Height then - Exit; - end; - if Pass = 2 then - begin - Pass := 3; - Result := 1; - end; - end; -end; - -{ GIF LZW decompresion code is from JVCL JvGIF.pas unit.} -procedure TGIFFileFormat.LZWDecompress(Stream: TStream; Handle: TImagingHandle; Width, Height: Integer; - Interlaced: Boolean; Data: Pointer); -var - MinCodeSize: Byte; - MaxCode, BitMask, InitCodeSize: Integer; - ClearCode, EndingCode, FirstFreeCode, FreeCode: Word; - I, OutCount, Code: Integer; - CurCode, OldCode, InCode, FinalChar: Word; - Prefix, Suffix, OutCode: PIntCodeTable; - ReadCtxt: TReadContext; - OutCtxt: TOutputContext; - TableFull: Boolean; - - function ReadCode(var Context: TReadContext): Integer; - var - RawCode: Integer; - ByteIndex: Integer; - Bytes: Byte; - BytesToLose: Integer; - begin - while (Context.Inx + Context.CodeSize > Context.Size) and - (Stream.Position < Stream.Size) do - begin - // Not enough bits in buffer - refill it - Not very efficient, but infrequently called - BytesToLose := Context.Inx shr 3; - // Note biggest Code Size is 12 bits. And this can at worst span 3 Bytes - Move(Context.Buf[Word(BytesToLose)], Context.Buf[0], 3); - Context.Inx := Context.Inx and 7; - Context.Size := Context.Size - (BytesToLose shl 3); - Stream.Read(Bytes, 1); - if Bytes > 0 then - Stream.Read(Context.Buf[Word(Context.Size shr 3)], Bytes); - Context.Size := Context.Size + (Bytes shl 3); - end; - ByteIndex := Context.Inx shr 3; - RawCode := Context.Buf[Word(ByteIndex)] + - (Word(Context.Buf[Word(ByteIndex + 1)]) shl 8); - if Context.CodeSize > 8 then - RawCode := RawCode + (Integer(Context.Buf[ByteIndex + 2]) shl 16); - RawCode := RawCode shr (Context.Inx and 7); - Context.Inx := Context.Inx + Byte(Context.CodeSize); - Result := RawCode and Context.ReadMask; - end; - - procedure Output(Value: Byte; var Context: TOutputContext); - var - P: PByte; - begin - if Context.Y >= Context.H then - Exit; - - // Only ifIndex8 supported - P := @PByteArray(Context.CurrLineData)[Context.X]; - P^ := Value; - - {case Context.BitsPerPixel of - 1: - begin - P := @PByteArray(Context.CurrLineData)[Context.X shr 3]; - if (Context.X and $07) <> 0 then - P^ := P^ or Word(Value shl (7 - (Word(Context.X and 7)))) - else - P^ := Byte(Value shl 7); - end; - 4: - begin - P := @PByteArray(Context.CurrLineData)[Context.X shr 1]; - if (Context.X and 1) <> 0 then - P^ := P^ or Value - else - P^ := Byte(Value shl 4); - end; - 8: - begin - P := @PByteArray(Context.CurrLineData)[Context.X]; - P^ := Value; - end; - end;} - Inc(Context.X); - - if Context.X < Context.W then - Exit; - Context.X := 0; - if Context.Interlace then - Context.Y := InterlaceStep(Context.Y, Context.H, Context.Pass) - else - Inc(Context.Y); - - Context.CurrLineData := @PByteArray(Context.Data)[Context.Y * Context.LineIdent]; - end; - -begin - OutCount := 0; - OldCode := 0; - FinalChar := 0; - TableFull := False; - GetMem(Prefix, SizeOf(TIntCodeTable)); - GetMem(Suffix, SizeOf(TIntCodeTable)); - GetMem(OutCode, SizeOf(TIntCodeTable) + SizeOf(Word)); - try - Stream.Read(MinCodeSize, 1); - if (MinCodeSize < 2) or (MinCodeSize > 9) then - RaiseImaging(SGIFDecodingError, []); - // Initial read context - ReadCtxt.Inx := 0; - ReadCtxt.Size := 0; - ReadCtxt.CodeSize := MinCodeSize + 1; - ReadCtxt.ReadMask := (1 shl ReadCtxt.CodeSize) - 1; - // Initialise pixel-output context - OutCtxt.X := 0; - OutCtxt.Y := 0; - OutCtxt.Pass := 0; - OutCtxt.W := Width; - OutCtxt.H := Height; - OutCtxt.BitsPerPixel := MinCodeSize; - OutCtxt.Interlace := Interlaced; - OutCtxt.LineIdent := Width; - OutCtxt.Data := Data; - OutCtxt.CurrLineData := Data; - BitMask := (1 shl OutCtxt.BitsPerPixel) - 1; - // 2 ^ MinCodeSize accounts for all colours in file - ClearCode := 1 shl MinCodeSize; - EndingCode := ClearCode + 1; - FreeCode := ClearCode + 2; - FirstFreeCode := FreeCode; - // 2^ (MinCodeSize + 1) includes clear and eoi Code and space too - InitCodeSize := ReadCtxt.CodeSize; - MaxCode := 1 shl ReadCtxt.CodeSize; - Code := ReadCode(ReadCtxt); - while (Code <> EndingCode) and (Code <> $FFFF) and - (OutCtxt.Y < OutCtxt.H) do - begin - if Code = ClearCode then - begin - ReadCtxt.CodeSize := InitCodeSize; - MaxCode := 1 shl ReadCtxt.CodeSize; - ReadCtxt.ReadMask := MaxCode - 1; - FreeCode := FirstFreeCode; - Code := ReadCode(ReadCtxt); - CurCode := Code; - OldCode := Code; - if Code = $FFFF then - Break; - FinalChar := (CurCode and BitMask); - Output(Byte(FinalChar), OutCtxt); - TableFull := False; - end - else - begin - CurCode := Code; - InCode := Code; - if CurCode >= FreeCode then - begin - CurCode := OldCode; - OutCode^[OutCount] := FinalChar; - Inc(OutCount); - end; - while CurCode > BitMask do - begin - if OutCount > CodeTableSize then - RaiseImaging(SGIFDecodingError, []); - OutCode^[OutCount] := Suffix^[CurCode]; - Inc(OutCount); - CurCode := Prefix^[CurCode]; - end; - - FinalChar := CurCode and BitMask; - OutCode^[OutCount] := FinalChar; - Inc(OutCount); - for I := OutCount - 1 downto 0 do - Output(Byte(OutCode^[I]), OutCtxt); - OutCount := 0; - // Update dictionary - if not TableFull then - begin - Prefix^[FreeCode] := OldCode; - Suffix^[FreeCode] := FinalChar; - // Advance to next free slot - Inc(FreeCode); - if FreeCode >= MaxCode then - begin - if ReadCtxt.CodeSize < 12 then - begin - Inc(ReadCtxt.CodeSize); - MaxCode := MaxCode shl 1; - ReadCtxt.ReadMask := (1 shl ReadCtxt.CodeSize) - 1; - end - else - TableFull := True; - end; - end; - OldCode := InCode; - end; - Code := ReadCode(ReadCtxt); - end; - if Code = $FFFF then - RaiseImaging(SGIFDecodingError, []); - finally - FreeMem(Prefix); - FreeMem(OutCode); - FreeMem(Suffix); - end; -end; - -{ GIF LZW compresion code is from JVCL JvGIF.pas unit.} -procedure TGIFFileFormat.LZWCompress(const IO: TIOFunctions; Handle: TImagingHandle; Width, Height, BitCount: Integer; - Interlaced: Boolean; Data: Pointer); -var - LineIdent: Integer; - MinCodeSize, Col: Byte; - InitCodeSize, X, Y: Integer; - Pass: Integer; - MaxCode: Integer; { 1 shl CodeSize } - ClearCode, EndingCode, LastCode, Tail: Integer; - I, HashValue: Integer; - LenString: Word; - Dict: PDictTable; - HashTable: TList; - PData: PByte; - WriteCtxt: TWriteContext; - - function InitHash(P: Integer): Integer; - begin - Result := (P + 3) * 301; - end; - - procedure WriteCode(Code: Integer; var Context: TWriteContext); - var - BufIndex: Integer; - Bytes: Byte; - begin - BufIndex := Context.Inx shr 3; - Code := Code shl (Context.Inx and 7); - Context.Buf[BufIndex] := Context.Buf[BufIndex] or Byte(Code); - Context.Buf[BufIndex + 1] := Byte(Code shr 8); - Context.Buf[BufIndex + 2] := Byte(Code shr 16); - Context.Inx := Context.Inx + Context.CodeSize; - if Context.Inx >= 255 * 8 then - begin - // Flush out full buffer - Bytes := 255; - IO.Write(Handle, @Bytes, 1); - IO.Write(Handle, @Context.Buf, Bytes); - Move(Context.Buf[255], Context.Buf[0], 2); - FillChar(Context.Buf[2], 255, 0); - Context.Inx := Context.Inx - (255 * 8); - end; - end; - - procedure FlushCode(var Context: TWriteContext); - var - Bytes: Byte; - begin - Bytes := (Context.Inx + 7) shr 3; - if Bytes > 0 then - begin - IO.Write(Handle, @Bytes, 1); - IO.Write(Handle, @Context.Buf, Bytes); - end; - // Data block terminator - a block of zero Size - Bytes := 0; - IO.Write(Handle, @Bytes, 1); - end; - -begin - LineIdent := Width; - Tail := 0; - HashValue := 0; - Col := 0; - HashTable := TList.Create; - GetMem(Dict, SizeOf(TDictTable)); - try - for I := 0 to HashTableSize - 1 do - HashTable.Add(nil); - - // Initialise encoder variables - InitCodeSize := BitCount + 1; - if InitCodeSize = 2 then - Inc(InitCodeSize); - MinCodeSize := InitCodeSize - 1; - IO.Write(Handle, @MinCodeSize, 1); - ClearCode := 1 shl MinCodeSize; - EndingCode := ClearCode + 1; - LastCode := EndingCode; - MaxCode := 1 shl InitCodeSize; - LenString := 0; - // Setup write context - WriteCtxt.Inx := 0; - WriteCtxt.CodeSize := InitCodeSize; - FillChar(WriteCtxt.Buf, SizeOf(WriteCtxt.Buf), 0); - WriteCode(ClearCode, WriteCtxt); - Y := 0; - Pass := 0; - - while Y < Height do - begin - PData := @PByteArray(Data)[Y * LineIdent]; - for X := 0 to Width - 1 do - begin - // Only ifIndex8 support - case BitCount of - 8: - begin - Col := PData^; - PData := @PByteArray(PData)[1]; - end; - {4: - begin - if X and 1 <> 0 then - begin - Col := PData^ and $0F; - PData := @PByteArray(PData)[1]; - end - else - Col := PData^ shr 4; - end; - 1: - begin - if X and 7 = 7 then - begin - Col := PData^ and 1; - PData := @PByteArray(PData)[1]; - end - else - Col := (PData^ shr (7 - (X and $07))) and $01; - end;} - end; - Inc(LenString); - if LenString = 1 then - begin - Tail := Col; - HashValue := InitHash(Col); - end - else - begin - HashValue := HashValue * (Col + LenString + 4); - I := HashValue mod HashTableSize; - HashValue := HashValue mod HashTableSize; - while (HashTable[I] <> nil) and - ((PImageDict(HashTable[I])^.Tail <> Tail) or - (PImageDict(HashTable[I])^.Col <> Col)) do - begin - Inc(I); - if I >= HashTableSize then - I := 0; - end; - if HashTable[I] <> nil then // Found in the strings table - Tail := PImageDict(HashTable[I])^.Index - else - begin - // Not found - WriteCode(Tail, WriteCtxt); - Inc(LastCode); - HashTable[I] := @Dict^[LastCode]; - PImageDict(HashTable[I])^.Index := LastCode; - PImageDict(HashTable[I])^.Tail := Tail; - PImageDict(HashTable[I])^.Col := Col; - Tail := Col; - HashValue := InitHash(Col); - LenString := 1; - if LastCode >= MaxCode then - begin - // Next Code will be written longer - MaxCode := MaxCode shl 1; - Inc(WriteCtxt.CodeSize); - end - else - if LastCode >= CodeTableSize - 2 then - begin - // Reset tables - WriteCode(Tail, WriteCtxt); - WriteCode(ClearCode, WriteCtxt); - LenString := 0; - LastCode := EndingCode; - WriteCtxt.CodeSize := InitCodeSize; - MaxCode := 1 shl InitCodeSize; - for I := 0 to HashTableSize - 1 do - HashTable[I] := nil; - end; - end; - end; - end; - if Interlaced then - Y := InterlaceStep(Y, Height, Pass) - else - Inc(Y); - end; - WriteCode(Tail, WriteCtxt); - WriteCode(EndingCode, WriteCtxt); - FlushCode(WriteCtxt); - finally - HashTable.Free; - FreeMem(Dict); - end; -end; - -function TGIFFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -type - TFrameInfo = record - Left, Top: Integer; - Width, Height: Integer; - Disposal: TDisposalMethod; - HasTransparency: Boolean; - HasLocalPal: Boolean; - TransIndex: Integer; - BackIndex: Integer; - end; -var - Header: TGIFHeader; - HasGlobalPal: Boolean; - GlobalPalLength: Integer; - GlobalPal: TPalette32Size256; - ScreenWidth, ScreenHeight, I, CachedIndex: Integer; - BlockID: Byte; - HasGraphicExt: Boolean; - GraphicExt: TGraphicControlExtension; - FrameInfos: array of TFrameInfo; - AppRead: Boolean; - CachedFrame: TImageData; - AnimFrames: TDynImageDataArray; - - function ReadBlockID: Byte; - begin - Result := GIFTrailer; - if GetIO.Read(Handle, @Result, SizeOf(Result)) < SizeOf(Result) then - Result := GIFTrailer; - end; - - procedure ReadExtensions; - var - BlockSize, BlockType, ExtType: Byte; - AppRec: TGIFApplicationRec; - LoopCount: SmallInt; - - procedure SkipBytes; - begin - with GetIO do - repeat - // Read block sizes and skip them - Read(Handle, @BlockSize, SizeOf(BlockSize)); - Seek(Handle, BlockSize, smFromCurrent); - until BlockSize = 0; - end; - - begin - HasGraphicExt := False; - AppRead := False; - - // Read extensions until image descriptor is found. Only graphic extension - // is stored now (for transparency), others are skipped. - while BlockID = GIFExtensionIntroducer do - with GetIO do - begin - Read(Handle, @ExtType, SizeOf(ExtType)); - - while ExtType in [GIFGraphicControlExtension, GIFCommentExtension, GIFApplicationExtension, GIFPlainText] do - begin - if ExtType = GIFGraphicControlExtension then - begin - HasGraphicExt := True; - Read(Handle, @GraphicExt, SizeOf(GraphicExt)); - end - else if (ExtType = GIFApplicationExtension) and not AppRead then - begin - Read(Handle, @BlockSize, SizeOf(BlockSize)); - if BlockSize >= SizeOf(AppRec) then - begin - Read(Handle, @AppRec, SizeOf(AppRec)); - if ((AppRec.Identifier = 'NETSCAPE') and (AppRec.Authentication = '2.0')) or - ((AppRec.Identifier = 'ANIMEXTS') and (AppRec.Authentication = '1.0')) then - begin - Read(Handle, @BlockSize, SizeOf(BlockSize)); - while BlockSize <> 0 do - begin - BlockType := ReadBlockID; - Dec(BlockSize); - - case BlockType of - GIFAppLoopExtension: - if (BlockSize >= SizeOf(LoopCount)) then - begin - // Read loop count - Read(Handle, @LoopCount, SizeOf(LoopCount)); - Dec(BlockSize, SizeOf(LoopCount)); - if LoopCount > 0 then - Inc(LoopCount); // Netscape extension is really "repeats" not "loops" - FMetadata.SetMetaItem(SMetaAnimationLoops, LoopCount); - end; - GIFAppBufferExtension: - begin - Dec(BlockSize, SizeOf(Word)); - Seek(Handle, SizeOf(Word), smFromCurrent); - end; - end; - end; - SkipBytes; - AppRead := True; - end - else - begin - // Revert all bytes reading - Seek(Handle, - SizeOf(AppRec) - SizeOf(BlockSize), smFromCurrent); - SkipBytes; - end; - end - else - begin - Seek(Handle, - BlockSize - SizeOf(BlockSize), smFromCurrent); - SkipBytes; - end; - end - else if ExtType in [GIFCommentExtension, GIFApplicationExtension, GIFPlainText] then - repeat - // Read block sizes and skip them - Read(Handle, @BlockSize, SizeOf(BlockSize)); - Seek(Handle, BlockSize, smFromCurrent); - until BlockSize = 0; - - // Read ID of following block - BlockID := ReadBlockID; - ExtType := BlockID; - end - end; - end; - - procedure CopyLZWData(Dest: TStream); - var - CodeSize, BlockSize: Byte; - InputSize: Integer; - Buff: array[Byte] of Byte; - begin - InputSize := ImagingIO.GetInputSize(GetIO, Handle); - // Copy codesize to stream - GetIO.Read(Handle, @CodeSize, 1); - Dest.Write(CodeSize, 1); - repeat - // Read and write data blocks, last is block term value of 0 - GetIO.Read(Handle, @BlockSize, 1); - Dest.Write(BlockSize, 1); - if BlockSize > 0 then - begin - GetIO.Read(Handle, @Buff[0], BlockSize); - Dest.Write(Buff[0], BlockSize); - end; - until (BlockSize = 0) or (GetIO.Tell(Handle) >= InputSize); - end; - - procedure ReadFrame; - var - ImageDesc: TImageDescriptor; - Interlaced: Boolean; - I, Idx, LocalPalLength: Integer; - LocalPal: TPalette32Size256; - LZWStream: TMemoryStream; - - procedure RemoveBadFrame; - begin - FreeImage(Images[Idx]); - SetLength(Images, Length(Images) - 1); - end; - - begin - Idx := Length(Images); - SetLength(Images, Idx + 1); - SetLength(FrameInfos, Idx + 1); - FillChar(LocalPal, SizeOf(LocalPal), 0); - - with GetIO do - begin - // Read and parse image descriptor - Read(Handle, @ImageDesc, SizeOf(ImageDesc)); - FrameInfos[Idx].HasLocalPal := (ImageDesc.PackedFields and GIFLocalColorTable) = GIFLocalColorTable; - Interlaced := (ImageDesc.PackedFields and GIFInterlaced) = GIFInterlaced; - LocalPalLength := ImageDesc.PackedFields and GIFColorTableSize; - LocalPalLength := 1 shl (LocalPalLength + 1); // Total pal length is 2^(n+1) - - // From Mozilla source - if (ImageDesc.Width = 0) or (ImageDesc.Width > Header.ScreenWidth) then - ImageDesc.Width := Header.ScreenWidth; - if (ImageDesc.Height = 0) or (ImageDesc.Height > Header.ScreenHeight) then - ImageDesc.Height := Header.ScreenHeight; - - FrameInfos[Idx].Left := ImageDesc.Left; - FrameInfos[Idx].Top := ImageDesc.Top; - FrameInfos[Idx].Width := ImageDesc.Width; - FrameInfos[Idx].Height := ImageDesc.Height; - FrameInfos[Idx].BackIndex := Header.BackgroundColorIndex; - - // Create new image for this frame which would be later pasted onto logical screen - NewImage(ImageDesc.Width, ImageDesc.Height, ifIndex8, Images[Idx]); - - // Load local palette if there is any - if FrameInfos[Idx].HasLocalPal then - for I := 0 to LocalPalLength - 1 do - begin - LocalPal[I].A := 255; - Read(Handle, @LocalPal[I].R, SizeOf(LocalPal[I].R)); - Read(Handle, @LocalPal[I].G, SizeOf(LocalPal[I].G)); - Read(Handle, @LocalPal[I].B, SizeOf(LocalPal[I].B)); - end; - - // Use local pal if present or global pal if present or create - // default pal if neither of them is present - if FrameInfos[Idx].HasLocalPal then - Move(LocalPal, Images[Idx].Palette^, SizeOf(LocalPal)) - else if HasGlobalPal then - Move(GlobalPal, Images[Idx].Palette^, SizeOf(GlobalPal)) - else - FillCustomPalette(Images[Idx].Palette, GlobalPalLength, 3, 3, 2); - - if (ImageDesc.Left <= Header.ScreenWidth + 1) and (ImageDesc.Top <= Header.ScreenHeight + 1) then - begin - // Resize the screen if needed to fit the frame - ScreenWidth := Max(ScreenWidth, ImageDesc.Width + ImageDesc.Left); - ScreenHeight := Max(ScreenHeight, ImageDesc.Height + ImageDesc.Top); - end - else - begin - // Remove frame outside logical screen - RemoveBadFrame; - Exit; - end; - - // If Grahic Control Extension is present make use of it - if HasGraphicExt then - begin - FrameInfos[Idx].HasTransparency := (GraphicExt.PackedFields and GIFTransparent) = GIFTransparent; - FrameInfos[Idx].Disposal := TDisposalMethod((GraphicExt.PackedFields and GIFDisposalMethod) shr 2); - if FrameInfos[Idx].HasTransparency then - begin - FrameInfos[Idx].TransIndex := GraphicExt.TransparentColorIndex; - Images[Idx].Palette[FrameInfos[Idx].TransIndex].A := 0; - end; - FMetadata.SetMetaItem(SMetaFrameDelay, Integer(GraphicExt.DelayTime * 10), Idx); - end - else - FrameInfos[Idx].HasTransparency := False; - - LZWStream := TMemoryStream.Create; - try - try - // Copy LZW data to temp stream, needed for correct decompression - CopyLZWData(LZWStream); - LZWStream.Position := 0; - // Data decompression finally - LZWDecompress(LZWStream, Handle, ImageDesc.Width, ImageDesc.Height, Interlaced, Images[Idx].Bits); - except - RemoveBadFrame; - Exit; - end; - finally - LZWStream.Free; - end; - end; - end; - - procedure CopyFrameTransparent32(const Image, Frame: TImageData; Left, Top: Integer); - var - X, Y: Integer; - Src: PByte; - Dst: PColor32; - begin - Src := Frame.Bits; - - // Copy all pixels from frame to log screen but ignore the transparent ones - for Y := 0 to Frame.Height - 1 do - begin - Dst := @PColor32RecArray(Image.Bits)[(Top + Y) * Image.Width + Left]; - for X := 0 to Frame.Width - 1 do - begin - if (Frame.Palette[Src^].A <> 0) then - Dst^ := Frame.Palette[Src^].Color; - Inc(Src); - Inc(Dst); - end; - end; - end; - - procedure AnimateFrame(Index: Integer; var AnimFrame: TImageData); - var - I, First, Last: Integer; - UseCache: Boolean; - BGColor: TColor32; - begin - // We may need to use raw frame 0 to n to correctly animate n-th frame - Last := Index; - First := Max(0, Last); - // See if we can use last animate frame as a basis for this one - // (so we don't have to use previous raw frames). - UseCache := TestImage(CachedFrame) and (CachedIndex = Index - 1) and (CachedIndex >= 0) and - (FrameInfos[CachedIndex].Disposal <> dmRestorePrevious); - - // Reuse or release cache - if UseCache then - CloneImage(CachedFrame, AnimFrame) - else - FreeImage(CachedFrame); - - // Default color for clearing of the screen - BGColor := Images[Index].Palette[FrameInfos[Index].BackIndex].Color; - - // Now prepare logical screen for drawing of raw frame at Index. - // We may need to use all previous raw frames to get the screen - // to proper state (according to their disposal methods). - - if not UseCache then - begin - if FrameInfos[Index].HasTransparency then - BGColor := Images[Index].Palette[FrameInfos[Index].TransIndex].Color; - // Clear whole screen - FillMemoryLongWord(AnimFrame.Bits, AnimFrame.Size, BGColor); - - // Try to maximize First so we don't have to use all 0 to n raw frames - while First > 0 do - begin - if (ScreenWidth = Images[First].Width) and (ScreenHeight = Images[First].Height) then - begin - if (FrameInfos[First].Disposal = dmRestoreBackground) and (First < Last) then - Break; - end; - Dec(First); - end; - - for I := First to Last - 1 do - begin - case FrameInfos[I].Disposal of - dmNoRemoval, dmLeave: - begin - // Copy previous raw frame onto screen - CopyFrameTransparent32(AnimFrame, Images[I], FrameInfos[I].Left, FrameInfos[I].Top); - end; - dmRestoreBackground: - if (I > First) then - begin - // Restore background color - FillRect(AnimFrame, FrameInfos[I].Left, FrameInfos[I].Top, - FrameInfos[I].Width, FrameInfos[I].Height, @BGColor); - end; - dmRestorePrevious: ; // Do nothing - previous state is already on screen - end; - end; - end - else if FrameInfos[CachedIndex].Disposal = dmRestoreBackground then - begin - // We have our cached result but also need to restore - // background in a place of cached frame - if FrameInfos[CachedIndex].HasTransparency then - BGColor := Images[CachedIndex].Palette[FrameInfos[CachedIndex].TransIndex].Color; - FillRect(AnimFrame, FrameInfos[CachedIndex].Left, FrameInfos[CachedIndex].Top, - FrameInfos[CachedIndex].Width, FrameInfos[CachedIndex].Height, @BGColor); - end; - - // Copy current raw frame to prepared screen - CopyFrameTransparent32(AnimFrame, Images[Index], FrameInfos[Index].Left, FrameInfos[Index].Top); - - // Cache animated result - CloneImage(AnimFrame, CachedFrame); - CachedIndex := Index; - end; - -begin - AppRead := False; - - SetLength(Images, 0); - FillChar(GlobalPal, SizeOf(GlobalPal), 0); - - with GetIO do - begin - // Read GIF header - Read(Handle, @Header, SizeOf(Header)); - ScreenWidth := Header.ScreenWidth; - ScreenHeight := Header.ScreenHeight; - HasGlobalPal := Header.PackedFields and GIFGlobalColorTable = GIFGlobalColorTable; // Bit 7 - GlobalPalLength := Header.PackedFields and GIFColorTableSize; // Bits 0-2 - GlobalPalLength := 1 shl (GlobalPalLength + 1); // Total pal length is 2^(n+1) - - // Read global palette from file if present - if HasGlobalPal then - begin - for I := 0 to GlobalPalLength - 1 do - begin - GlobalPal[I].A := 255; - Read(Handle, @GlobalPal[I].R, SizeOf(GlobalPal[I].R)); - Read(Handle, @GlobalPal[I].G, SizeOf(GlobalPal[I].G)); - Read(Handle, @GlobalPal[I].B, SizeOf(GlobalPal[I].B)); - end; - end; - - // Read ID of the first block - BlockID := ReadBlockID; - - // Now read all data blocks in the file until file trailer is reached - while BlockID <> GIFTrailer do - begin - // Read blocks until we find the one of known type - while not (BlockID in [GIFTrailer, GIFExtensionIntroducer, GIFImageDescriptor]) do - BlockID := ReadBlockID; - // Read supported and skip unsupported extensions - ReadExtensions; - // If image frame is found read it - if BlockID = GIFImageDescriptor then - ReadFrame; - // Read next block's ID - BlockID := ReadBlockID; - // If block ID is unknown set it to end-of-GIF marker - if not (BlockID in [GIFExtensionIntroducer, GIFTrailer, GIFImageDescriptor]) then - BlockID := GIFTrailer; - end; - - if FLoadAnimated then - begin - // Aniated frames will be stored in AnimFrames - SetLength(AnimFrames, Length(Images)); - InitImage(CachedFrame); - CachedIndex := -1; - - for I := 0 to High(Images) do - begin - // Create new logical screen - NewImage(ScreenWidth, ScreenHeight, ifA8R8G8B8, AnimFrames[I]); - // Animate frames to current log screen - AnimateFrame(I, AnimFrames[I]); - end; - - // Now release raw 8bit frames and put animated 32bit ones - // to output array - FreeImage(CachedFrame); - for I := 0 to High(AnimFrames) do - begin - FreeImage(Images[I]); - Images[I] := AnimFrames[I]; - end; - end; - - Result := True; - end; -end; - -function TGIFFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -var - Header: TGIFHeader; - ImageDesc: TImageDescriptor; - ImageToSave: TImageData; - MustBeFreed: Boolean; - I, J: Integer; - GraphicExt: TGraphicControlExtension; - - procedure FindMaxDimensions(var MaxWidth, MaxHeight: Word); - var - I: Integer; - begin - MaxWidth := Images[FFirstIdx].Width; - MaxHeight := Images[FFirstIdx].Height; - - for I := FFirstIdx + 1 to FLastIdx do - begin - MaxWidth := Iff(Images[I].Width > MaxWidth, Images[I].Width, MaxWidth); - MaxHeight := Iff(Images[I].Height > MaxWidth, Images[I].Height, MaxHeight); - end; - end; - - procedure SetFrameDelay(Idx: Integer; var Ext: TGraphicControlExtension); - begin - if FMetadata.HasMetaItemForSaving(SMetaFrameDelay, Idx) then - Ext.DelayTime := FMetadata.MetaItemsForSavingMulti[SMetaFrameDelay, Idx] div 10 - else - Ext.DelayTime := GIFDefaultDelay; - end; - - procedure SaveGlobalMetadata; - var - AppExt: TGIFApplicationRec; - BlockSize, LoopExtId: Byte; - Repeats: Word; - begin - if FMetadata.HasMetaItemForSaving(SMetaAnimationLoops) then - with GetIO do - begin - FillChar(AppExt, SizeOf(AppExt), 0); - AppExt.Identifier := 'NETSCAPE'; - AppExt.Authentication := '2.0'; - Repeats := FMetadata.MetaItemsForSaving[SMetaAnimationLoops]; - if Repeats > 0 then - Dec(Repeats); - LoopExtId := GIFAppLoopExtension; - - Write(Handle, @GIFExtensionIntroducer, SizeOf(GIFExtensionIntroducer)); - Write(Handle, @GIFApplicationExtension, SizeOf(GIFApplicationExtension)); - BlockSize := 11; - Write(Handle, @BlockSize, SizeOf(BlockSize)); - Write(Handle, @AppExt, SizeOf(AppExt)); - BlockSize := 3; - Write(Handle, @BlockSize, SizeOf(BlockSize)); - Write(Handle, @LoopExtId, SizeOf(LoopExtId)); - Write(Handle, @Repeats, SizeOf(Repeats)); - Write(Handle, @GIFBlockTerminator, SizeOf(GIFBlockTerminator)); - end; - end; - -begin - // Fill header with data, select size of largest image in array as - // logical screen size - FillChar(Header, Sizeof(Header), 0); - Header.Signature := GIFSignature; - Header.Version := GIFVersions[gv89]; - FindMaxDimensions(Header.ScreenWidth, Header.ScreenHeight); - Header.PackedFields := GIFColorResolution; // Color resolution is 256 - GetIO.Write(Handle, @Header, SizeOf(Header)); - - // Prepare default GC extension with delay - FillChar(GraphicExt, Sizeof(GraphicExt), 0); - GraphicExt.DelayTime := GIFDefaultDelay; - GraphicExt.BlockSize := 4; - - SaveGlobalMetadata; - - for I := FFirstIdx to FLastIdx do - begin - if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - // Write Graphic Control Extension with default delay - Write(Handle, @GIFExtensionIntroducer, SizeOf(GIFExtensionIntroducer)); - Write(Handle, @GIFGraphicControlExtension, SizeOf(GIFGraphicControlExtension)); - SetFrameDelay(I, GraphicExt); - Write(Handle, @GraphicExt, SizeOf(GraphicExt)); - // Write frame marker and fill and write image descriptor for this frame - Write(Handle, @GIFImageDescriptor, SizeOf(GIFImageDescriptor)); - FillChar(ImageDesc, Sizeof(ImageDesc), 0); - ImageDesc.Width := Width; - ImageDesc.Height := Height; - ImageDesc.PackedFields := GIFLocalColorTable or GIFColorTableSize; // Use lccal color table with 256 entries - Write(Handle, @ImageDesc, SizeOf(ImageDesc)); - - // Write local color table for each frame - for J := 0 to 255 do - begin - Write(Handle, @Palette[J].R, SizeOf(Palette[J].R)); - Write(Handle, @Palette[J].G, SizeOf(Palette[J].G)); - Write(Handle, @Palette[J].B, SizeOf(Palette[J].B)); - end; - - // Finally compress image data - LZWCompress(GetIO, Handle, Width, Height, 8, False, Bits); - - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; - end; - - GetIO.Write(Handle, @GIFTrailer, SizeOf(GIFTrailer)); - Result := True; -end; - -procedure TGIFFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin - ConvertImage(Image, ifIndex8); -end; - -function TGIFFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Header: TGIFHeader; - ReadCount: Integer; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Header, SizeOf(Header)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount >= SizeOf(Header)) and - (Header.Signature = GIFSignature) and - ((Header.Version = GIFVersions[gv87]) or (Header.Version = GIFVersions[gv89])); - end; -end; - -initialization - RegisterImageFileFormat(TGIFFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77 Changes/Bug Fixes ----------------------------------- - - Fixed crash when resaving GIF with animation metadata. - - Writes frame delays of GIF animations from metadata. - - Reads and writes looping of GIF animations stored into/from metadata. - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Reads frame delays from GIF animations into metadata. - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Fixed bug - loading of GIF with NETSCAPE app extensions - failed with Delphi 2009. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - GIF loading and animation mostly rewritten, based on - modification by Sergey Galezdinov (ExtraGIF in Extras/Contrib). - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - Fixed loading of some rare GIFs, problems with LZW - decompression. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - Better solution to transparency for some GIFs. Background not - transparent by default. - - -- 0.24.1 Changes/Bug Fixes --------------------------------- - - Made backround color transparent by default (alpha = 0). - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Fixed other loading bugs (local pal size, transparency). - - Added GIF saving. - - Fixed bug when loading multiframe GIFs and implemented few animation - features (disposal methods, ...). - - Loading of GIFs working. - - Unit created with initial stuff! -} - -end. diff --git a/3rd/Imaging/Source/ImagingIO.pas b/3rd/Imaging/Source/ImagingIO.pas deleted file mode 100644 index 8ac877504..000000000 --- a/3rd/Imaging/Source/ImagingIO.pas +++ /dev/null @@ -1,647 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains default IO functions for reading from/writting to - files, streams and memory.} -unit ImagingIO; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility; - -type - TMemoryIORec = record - Data: ImagingUtility.PByteArray; - Position: LongInt; - Size: LongInt; - end; - PMemoryIORec = ^TMemoryIORec; - -var - OriginalFileIO: TIOFunctions; - FileIO: TIOFunctions; - StreamIO: TIOFunctions; - MemoryIO: TIOFunctions; - -{ Helper function that returns size of input (from current position to the end) - represented by Handle (and opened and operated on by members of IOFunctions).} -function GetInputSize(IOFunctions: TIOFunctions; Handle: TImagingHandle): LongInt; -{ Helper function that initializes TMemoryIORec with given params.} -function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec; -{ Reads one text line from input (CR+LF, CR, or LF as line delimiter).} -function ReadLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; - out Line: AnsiString; FailOnControlChars: Boolean = False): Boolean; -{ Writes one text line to input with optional line delimiter.} -procedure WriteLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; - const Line: AnsiString; const LineEnding: AnsiString = sLineBreak); - -implementation - -const - DefaultBufferSize = 16 * 1024; - -type - { Based on TaaBufferedStream - Copyright (c) Julian M Bucknall 1997, 1999 } - TBufferedStream = class - private - FBuffer: PByteArray; - FBufSize: Integer; - FBufStart: Integer; - FBufPos: Integer; - FBytesInBuf: Integer; - FSize: Integer; - FDirty: Boolean; - FStream: TStream; - function GetPosition: Integer; - function GetSize: Integer; - procedure ReadBuffer; - procedure WriteBuffer; - procedure SetPosition(const Value: Integer); - public - constructor Create(AStream: TStream); - destructor Destroy; override; - function Read(var Buffer; Count: Integer): Integer; - function Write(const Buffer; Count: Integer): Integer; - function Seek(Offset: Integer; Origin: Word): Integer; - procedure Commit; - property Stream: TStream read FStream; - property Position: Integer read GetPosition write SetPosition; - property Size: Integer read GetSize; - end; - -constructor TBufferedStream.Create(AStream: TStream); -begin - inherited Create; - FStream := AStream; - FBufSize := DefaultBufferSize; - GetMem(FBuffer, FBufSize); - FBufPos := 0; - FBytesInBuf := 0; - FBufStart := 0; - FDirty := False; - FSize := AStream.Size; -end; - -destructor TBufferedStream.Destroy; -begin - if FBuffer <> nil then - begin - Commit; - FreeMem(FBuffer); - end; - FStream.Position := Position; // Make sure source stream has right position - inherited Destroy; -end; - -function TBufferedStream.GetPosition: Integer; -begin - Result := FBufStart + FBufPos; -end; - -procedure TBufferedStream.SetPosition(const Value: Integer); -begin - Seek(Value, soFromCurrent); -end; - -function TBufferedStream.GetSize: Integer; -begin - Result := FSize; -end; - -procedure TBufferedStream.ReadBuffer; -var - SeekResult: Integer; -begin - SeekResult := FStream.Seek(FBufStart, 0); - if SeekResult = -1 then - raise Exception.Create('TBufferedStream.ReadBuffer: seek failed'); - FBytesInBuf := FStream.Read(FBuffer^, FBufSize); - if FBytesInBuf <= 0 then - raise Exception.Create('TBufferedStream.ReadBuffer: read failed'); -end; - -procedure TBufferedStream.WriteBuffer; -var - SeekResult: Integer; - BytesWritten: Integer; -begin - SeekResult := FStream.Seek(FBufStart, 0); - if SeekResult = -1 then - raise Exception.Create('TBufferedStream.WriteBuffer: seek failed'); - BytesWritten := FStream.Write(FBuffer^, FBytesInBuf); - if BytesWritten <> FBytesInBuf then - raise Exception.Create('TBufferedStream.WriteBuffer: write failed'); -end; - -procedure TBufferedStream.Commit; -begin - if FDirty then - begin - WriteBuffer; - FDirty := False; - end; -end; - -function TBufferedStream.Read(var Buffer; Count: Integer): Integer; -var - BufAsBytes : TByteArray absolute Buffer; - BufIdx, BytesToGo, BytesToRead: Integer; -begin - // Calculate the actual number of bytes we can read - this depends on - // the current position and size of the stream as well as the number - // of bytes requested. - BytesToGo := Count; - if FSize < (FBufStart + FBufPos + Count) then - BytesToGo := FSize - (FBufStart + FBufPos); - - if BytesToGo <= 0 then - begin - Result := 0; - Exit; - end; - // Remember to return the result of our calculation - Result := BytesToGo; - - BufIdx := 0; - if FBytesInBuf = 0 then - ReadBuffer; - // Calculate the number of bytes we can read prior to the loop - BytesToRead := FBytesInBuf - FBufPos; - if BytesToRead > BytesToGo then - BytesToRead := BytesToGo; - // Copy from the stream buffer to the caller's buffer - Move(FBuffer^[FBufPos], BufAsBytes[BufIdx], BytesToRead); - // Calculate the number of bytes still to read} - Dec(BytesToGo, BytesToRead); - - // while we have bytes to read, read them - while BytesToGo > 0 do - begin - Inc(BufIdx, BytesToRead); - // As we've exhausted this buffer-full, advance to the next, check - // to see whether we need to write the buffer out first - if FDirty then - begin - WriteBuffer; - FDirty := false; - end; - Inc(FBufStart, FBufSize); - FBufPos := 0; - ReadBuffer; - // Calculate the number of bytes we can read in this cycle - BytesToRead := FBytesInBuf; - if BytesToRead > BytesToGo then - BytesToRead := BytesToGo; - // Ccopy from the stream buffer to the caller's buffer - Move(FBuffer^, BufAsBytes[BufIdx], BytesToRead); - // Calculate the number of bytes still to read - Dec(BytesToGo, BytesToRead); - end; - // Remember our new position - Inc(FBufPos, BytesToRead); - if FBufPos = FBufSize then - begin - Inc(FBufStart, FBufSize); - FBufPos := 0; - FBytesInBuf := 0; - end; -end; - -function TBufferedStream.Seek(Offset: Integer; Origin: Word): Integer; -var - NewBufStart, NewPos: Integer; -begin - // Calculate the new position - case Origin of - soFromBeginning : NewPos := Offset; - soFromCurrent : NewPos := FBufStart + FBufPos + Offset; - soFromEnd : NewPos := FSize + Offset; - else - raise Exception.Create('TBufferedStream.Seek: invalid origin'); - end; - - if (NewPos < 0) or (NewPos > FSize) then - begin - //NewPos := ClampInt(NewPos, 0, FSize); don't do this - for writing - end; - // Calculate which page of the file we need to be at - NewBufStart := NewPos and not Pred(FBufSize); - // If the new page is different than the old, mark the buffer as being - // ready to be replenished, and if need be write out any dirty data - if NewBufStart <> FBufStart then - begin - if FDirty then - begin - WriteBuffer; - FDirty := False; - end; - FBufStart := NewBufStart; - FBytesInBuf := 0; - end; - // Save the new position - FBufPos := NewPos - NewBufStart; - Result := NewPos; -end; - -function TBufferedStream.Write(const Buffer; Count: Integer): Integer; -var - BufAsBytes: TByteArray absolute Buffer; - BufIdx, BytesToGo, BytesToWrite: Integer; -begin - // When we write to this stream we always assume that we can write the - // requested number of bytes: if we can't (eg, the disk is full) we'll - // get an exception somewhere eventually. - BytesToGo := Count; - // Remember to return the result of our calculation - Result := BytesToGo; - - BufIdx := 0; - if (FBytesInBuf = 0) and (FSize > FBufStart) then - ReadBuffer; - // Calculate the number of bytes we can write prior to the loop - BytesToWrite := FBufSize - FBufPos; - if BytesToWrite > BytesToGo then - BytesToWrite := BytesToGo; - // Copy from the caller's buffer to the stream buffer - Move(BufAsBytes[BufIdx], FBuffer^[FBufPos], BytesToWrite); - // Mark our stream buffer as requiring a save to the actual stream, - // note that this will suffice for the rest of the routine as well: no - // inner routine will turn off the dirty flag. - FDirty := True; - // Calculate the number of bytes still to write - Dec(BytesToGo, BytesToWrite); - - // While we have bytes to write, write them - while BytesToGo > 0 do - begin - Inc(BufIdx, BytesToWrite); - // As we've filled this buffer, write it out to the actual stream - // and advance to the next buffer, reading it if required - FBytesInBuf := FBufSize; - WriteBuffer; - Inc(FBufStart, FBufSize); - FBufPos := 0; - FBytesInBuf := 0; - if FSize > FBufStart then - ReadBuffer; - // Calculate the number of bytes we can write in this cycle - BytesToWrite := FBufSize; - if BytesToWrite > BytesToGo then - BytesToWrite := BytesToGo; - // Copy from the caller's buffer to our buffer - Move(BufAsBytes[BufIdx], FBuffer^, BytesToWrite); - // Calculate the number of bytes still to write - Dec(BytesToGo, BytesToWrite); - end; - // Remember our new position - Inc(FBufPos, BytesToWrite); - // Make sure the count of valid bytes is correct - if FBytesInBuf < FBufPos then - FBytesInBuf := FBufPos; - // Make sure the stream size is correct - if FSize < (FBufStart + FBytesInBuf) then - FSize := FBufStart + FBytesInBuf; - // If we're at the end of the buffer, write it out and advance to the - // start of the next page - if FBufPos = FBufSize then - begin - WriteBuffer; - FDirty := False; - Inc(FBufStart, FBufSize); - FBufPos := 0; - FBytesInBuf := 0; - end; -end; - -{ File IO functions } - -function FileOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl; -var - Stream: TStream; -begin - Stream := nil; - - case Mode of - omReadOnly: Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - omCreate: Stream := TFileStream.Create(FileName, fmCreate); - omReadWrite: - begin - if FileExists(FileName) then - Stream := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive) - else - Stream := TFileStream.Create(FileName, fmCreate); - end; - end; - - Assert(Stream <> nil); - Result := TBufferedStream.Create(Stream); -end; - -procedure FileClose(Handle: TImagingHandle); cdecl; -var - Stream: TStream; -begin - Stream := TBufferedStream(Handle).Stream; - TBufferedStream(Handle).Free; - Stream.Free; -end; - -function FileEof(Handle: TImagingHandle): Boolean; cdecl; -begin - Result := TBufferedStream(Handle).Position = TBufferedStream(Handle).Size; -end; - -function FileSeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): - LongInt; cdecl; -begin - Result := TBufferedStream(Handle).Seek(Offset, LongInt(Mode)); -end; - -function FileTell(Handle: TImagingHandle): LongInt; cdecl; -begin - Result := TBufferedStream(Handle).Position; -end; - -function FileRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): - LongInt; cdecl; -begin - Result := TBufferedStream(Handle).Read(Buffer^, Count); -end; - -function FileWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): - LongInt; cdecl; -begin - Result := TBufferedStream(Handle).Write(Buffer^, Count); -end; - -{ Stream IO functions } - -function StreamOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl; -begin - Result := FileName; -end; - -procedure StreamClose(Handle: TImagingHandle); cdecl; -begin -end; - -function StreamEof(Handle: TImagingHandle): Boolean; cdecl; -begin - Result := TStream(Handle).Position = TStream(Handle).Size; -end; - -function StreamSeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): - LongInt; cdecl; -begin - Result := TStream(Handle).Seek(Offset, LongInt(Mode)); -end; - -function StreamTell(Handle: TImagingHandle): LongInt; cdecl; -begin - Result := TStream(Handle).Position; -end; - -function StreamRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): - LongInt; cdecl; -begin - Result := TStream(Handle).Read(Buffer^, Count); -end; - -function StreamWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): - LongInt; cdecl; -begin - Result := TStream(Handle).Write(Buffer^, Count); -end; - -{ Memory IO functions } - -function MemoryOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl; -begin - Result := FileName; -end; - -procedure MemoryClose(Handle: TImagingHandle); cdecl; -begin -end; - -function MemoryEof(Handle: TImagingHandle): Boolean; cdecl; -begin - Result := PMemoryIORec(Handle).Position = PMemoryIORec(Handle).Size; -end; - -function MemorySeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): - LongInt; cdecl; -begin - Result := PMemoryIORec(Handle).Position; - case Mode of - smFromBeginning: Result := Offset; - smFromCurrent: Result := PMemoryIORec(Handle).Position + Offset; - smFromEnd: Result := PMemoryIORec(Handle).Size + Offset; - end; - //Result := ClampInt(Result, 0, PMemoryIORec(Handle).Size); don't do this - some file formats use it - PMemoryIORec(Handle).Position := Result; -end; - -function MemoryTell(Handle: TImagingHandle): LongInt; cdecl; -begin - Result := PMemoryIORec(Handle).Position; -end; - -function MemoryRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): - LongInt; cdecl; -var - Rec: PMemoryIORec; -begin - Rec := PMemoryIORec(Handle); - Result := Count; - if Rec.Position + Count > Rec.Size then - Result := Rec.Size - Rec.Position; - Move(Rec.Data[Rec.Position], Buffer^, Result); - Rec.Position := Rec.Position + Result; -end; - -function MemoryWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): - LongInt; cdecl; -var - Rec: PMemoryIORec; -begin - Rec := PMemoryIORec(Handle); - Result := Count; - if Rec.Position + Count > Rec.Size then - Result := Rec.Size - Rec.Position; - Move(Buffer^, Rec.Data[Rec.Position], Result); - Rec.Position := Rec.Position + Result; -end; - -{ Helper IO functions } - -function GetInputSize(IOFunctions: TIOFunctions; Handle: TImagingHandle): LongInt; -var - OldPos: Int64; -begin - OldPos := IOFunctions.Tell(Handle); - IOFunctions.Seek(Handle, 0, smFromEnd); - Result := IOFunctions.Tell(Handle); - IOFunctions.Seek(Handle, OldPos, smFromBeginning); -end; - -function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec; -begin - Result.Data := Data; - Result.Position := 0; - Result.Size := Size; -end; - -function ReadLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; - out Line: AnsiString; FailOnControlChars: Boolean): Boolean; -const - MaxLine = 1024; -var - EolPos, Pos: Integer; - C: AnsiChar; - EolReached: Boolean; - Endings: set of AnsiChar; -begin - Line := ''; - Pos := 0; - EolPos := 0; - EolReached := False; - Endings := [#10, #13]; - Result := True; - - while not IOFunctions.Eof(Handle) do - begin - IOFunctions.Read(Handle, @C, SizeOf(C)); - - if FailOnControlChars and (Byte(C) < $20) then - begin - Break; - end; - - if not (C in Endings) then - begin - if EolReached then - begin - IOFunctions.Seek(Handle, EolPos, smFromBeginning); - Exit; - end - else - begin - SetLength(Line, Length(Line) + 1); - Line[Length(Line)] := C; - end; - end - else if not EolReached then - begin - EolReached := True; - EolPos := IOFunctions.Tell(Handle); - end; - - Inc(Pos); - if Pos >= MaxLine then - begin - Break; - end; - end; - - Result := False; - IOFunctions.Seek(Handle, -Pos, smFromCurrent); -end; - -procedure WriteLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; - const Line: AnsiString; const LineEnding: AnsiString); -var - ToWrite: AnsiString; -begin - ToWrite := Line + LineEnding; - IOFunctions.Write(Handle, @ToWrite[1], Length(ToWrite)); -end; - -initialization - OriginalFileIO.Open := FileOpen; - OriginalFileIO.Close := FileClose; - OriginalFileIO.Eof := FileEof; - OriginalFileIO.Seek := FileSeek; - OriginalFileIO.Tell := FileTell; - OriginalFileIO.Read := FileRead; - OriginalFileIO.Write := FileWrite; - - StreamIO.Open := StreamOpen; - StreamIO.Close := StreamClose; - StreamIO.Eof := StreamEof; - StreamIO.Seek := StreamSeek; - StreamIO.Tell := StreamTell; - StreamIO.Read := StreamRead; - StreamIO.Write := StreamWrite; - - MemoryIO.Open := MemoryOpen; - MemoryIO.Close := MemoryClose; - MemoryIO.Eof := MemoryEof; - MemoryIO.Seek := MemorySeek; - MemoryIO.Tell := MemoryTell; - MemoryIO.Read := MemoryRead; - MemoryIO.Write := MemoryWrite; - - ResetFileIO; - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 --------------------------------------------------- - - Updated IO Open functions according to changes in ImagingTypes. - - Added ReadLine and WriteLine functions. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added merge between buffered read-only and write-only file - stream adapters - TIFF saving needed both reading and writing. - - Fixed bug causing wrong value of TBufferedWriteFile.Size - (needed to add buffer pos to size). - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Removed TMemoryIORec.Written, use Position to get proper memory - position (Written didn't take Seeks into account). - - Added TBufferedReadFile and TBufferedWriteFile classes for - buffered file reading/writting. File IO functions now use these - classes resulting in performance increase mainly in file formats - that read/write many small chunks. - - Added fmShareDenyWrite to FileOpenRead. You can now read - files opened for reading by Imaging from other apps. - - Added GetInputSize and PrepareMemIO helper functions. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - changed behaviour of MemorySeek to act as TStream - based Seeks -} -end. - diff --git a/3rd/Imaging/Source/ImagingJpeg.pas b/3rd/Imaging/Source/ImagingJpeg.pas deleted file mode 100644 index 94f537132..000000000 --- a/3rd/Imaging/Source/ImagingJpeg.pas +++ /dev/null @@ -1,769 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for Jpeg images.} -unit ImagingJpeg; - -{$I ImagingOptions.inc} - -{ You can choose which Pascal JpegLib implementation will be used. - IMJPEGLIB is version bundled with Imaging which works with all supported - compilers and platforms. - PASJPEG is original JpegLib translation or version modified for FPC - (and shipped with it). You can use PASJPEG if this version is already - linked with another part of your program and you don't want to have - two quite large almost the same libraries linked to your exe. - This is the case with Lazarus applications for example.} - -{$DEFINE IMJPEGLIB} -{ $DEFINE PASJPEG} - -{ Automatically use FPC's PasJpeg when compiling with Lazarus. But not when - WINDOWS is defined. See http://galfar.vevb.net/imaging/smf/index.php/topic,90.0.html. - Fixed in FPC revision 13963: http://bugs.freepascal.org/view.php?id=14928 } -{$IF Defined(LCL) and not Defined(WINDOWS)} - {$UNDEF IMJPEGLIB} - {$DEFINE PASJPEG} -{$IFEND} - -{ We usually want to skip the rest of the corrupted file when loading JEPG files - instead of getting exception. JpegLib's error handler can only be - exited using setjmp/longjmp ("non-local goto") functions to get error - recovery when loading corrupted JPEG files. This is implemented in assembler - and currently available only for 32bit Delphi targets and FPC.} -{$DEFINE ErrorJmpRecovery} -{$IF Defined(DCC) and not Defined(CPUX86)} - {$UNDEF ErrorJmpRecovery} -{$IFEND} - -interface - -uses - SysUtils, ImagingTypes, Imaging, ImagingColors, -{$IF Defined(IMJPEGLIB)} - imjpeglib, imjmorecfg, imjcomapi, imjdapimin, imjdeferr, imjerror, - imjdapistd, imjcapimin, imjcapistd, imjdmarker, imjcparam, -{$ELSEIF Defined(PASJPEG)} - jpeglib, jmorecfg, jcomapi, jdapimin, jdeferr, jerror, - jdapistd, jcapimin, jcapistd, jdmarker, jcparam, -{$IFEND} - ImagingUtility; - -{$IF Defined(FPC) and Defined(PASJPEG)} - { When using FPC's pasjpeg in FPC the channel order is BGR instead of RGB} - {$DEFINE RGBSWAPPED} -{$IFEND} - -type - { Class for loading/saving Jpeg images. Supports load/save of - 8 bit grayscale and 24 bit RGB images. Jpegs can be saved with optional - progressive encoding. - Based on IJG's JpegLib so doesn't support alpha channels and lossless - coding.} - TJpegFileFormat = class(TImageFileFormat) - private - FGrayScale: Boolean; - protected - FQuality: LongInt; - FProgressive: LongBool; - procedure SetJpegIO(const JpegIO: TIOFunctions); virtual; - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - procedure CheckOptionsValidity; override; - published - { Controls Jpeg save compression quality. It is number in range 1..100. - 1 means small/ugly file, 100 means large/nice file. Accessible trough - ImagingJpegQuality option.} - property Quality: LongInt read FQuality write FQuality; - { If True Jpeg images are saved in progressive format. Accessible trough - ImagingJpegProgressive option.} - property Progressive: LongBool read FProgressive write FProgressive; - end; - -implementation - -const - SJpegFormatName = 'Joint Photographic Experts Group Image'; - SJpegMasks = '*.jpg,*.jpeg,*.jfif,*.jpe,*.jif'; - JpegSupportedFormats: TImageFormats = [ifR8G8B8, ifGray8]; - JpegDefaultQuality = 90; - JpegDefaultProgressive = False; - -const - { Jpeg file identifiers.} - JpegMagic: TChar2 = #$FF#$D8; - BufferSize = 16384; - -resourcestring - SJpegError = 'JPEG Error'; - -type - TJpegContext = record - case Byte of - 0: (common: jpeg_common_struct); - 1: (d: jpeg_decompress_struct); - 2: (c: jpeg_compress_struct); - end; - - TSourceMgr = record - Pub: jpeg_source_mgr; - Input: TImagingHandle; - Buffer: JOCTETPTR; - StartOfFile: Boolean; - end; - PSourceMgr = ^TSourceMgr; - - TDestMgr = record - Pub: jpeg_destination_mgr; - Output: TImagingHandle; - Buffer: JOCTETPTR; - end; - PDestMgr = ^TDestMgr; - -var - JIO: TIOFunctions; - JpegErrorMgr: jpeg_error_mgr; - -{ Intenal unit jpeglib support functions } - -{$IFDEF ErrorJmpRecovery} - {$IFDEF DCC} - type - jmp_buf = record - EBX, - ESI, - EDI, - ESP, - EBP, - EIP: LongWord; - end; - pjmp_buf = ^jmp_buf; - - { JmpLib SetJmp/LongJmp Library - (C)Copyright 2003, 2004 Will DeWitt Jr. <edge@boink.net> } - function SetJmp(out jmpb: jmp_buf): Integer; - asm - { -> EAX jmpb } - { <- EAX Result } - MOV EDX, [ESP] // Fetch return address (EIP) - // Save task state - MOV [EAX+jmp_buf.&EBX], EBX - MOV [EAX+jmp_buf.&ESI], ESI - MOV [EAX+jmp_buf.&EDI], EDI - MOV [EAX+jmp_buf.&ESP], ESP - MOV [EAX+jmp_buf.&EBP], EBP - MOV [EAX+jmp_buf.&EIP], EDX - - SUB EAX, EAX - @@1: - end; - - procedure LongJmp(const jmpb: jmp_buf; retval: Integer); - asm - { -> EAX jmpb } - { EDX retval } - { <- EAX Result } - XCHG EDX, EAX - - MOV ECX, [EDX+jmp_buf.&EIP] - // Restore task state - MOV EBX, [EDX+jmp_buf.&EBX] - MOV ESI, [EDX+jmp_buf.&ESI] - MOV EDI, [EDX+jmp_buf.&EDI] - MOV ESP, [EDX+jmp_buf.&ESP] - MOV EBP, [EDX+jmp_buf.&EBP] - MOV [ESP], ECX // Restore return address (EIP) - - TEST EAX, EAX // Ensure retval is <> 0 - JNZ @@1 - MOV EAX, 1 - @@1: - end; - {$ENDIF} - -type - TJmpBuf = jmp_buf; - TErrorClientData = record - JmpBuf: TJmpBuf; - ScanlineReadReached: Boolean; - end; - PErrorClientData = ^TErrorClientData; -{$ENDIF} - -procedure JpegError(CInfo: j_common_ptr); - - procedure RaiseError; - var - Buffer: AnsiString; - begin - // Create the message and raise exception - CInfo.err.format_message(CInfo, Buffer); - // Warning: you can get "Invalid argument index in format" exception when - // using FPC (see http://bugs.freepascal.org/view.php?id=21229). - // Fixed in FPC 2.7.1 - {$IF Defined(FPC) and (FPC_FULLVERSION <= 20701)} - raise EImagingError.CreateFmt(SJPEGError + ' %d', [CInfo.err.msg_code]); - {$ELSE} - raise EImagingError.CreateFmt(SJPEGError + ' %d: ' + string(Buffer), [CInfo.err.msg_code]); - {$IFEND} - end; - -begin -{$IFDEF ErrorJmpRecovery} - // Only recovers on loads and when header is sucessfully loaded - // (error occurs when reading scanlines) - if (CInfo.client_data <> nil) and - PErrorClientData(CInfo.client_data).ScanlineReadReached then - begin - // Non-local jump to error handler in TJpegFileFormat.LoadData - longjmp(PErrorClientData(CInfo.client_data).JmpBuf, 1) - end - else - RaiseError; -{$ELSE} - RaiseError; -{$ENDIF} -end; - -procedure OutputMessage(CurInfo: j_common_ptr); -begin -end; - -procedure ReleaseContext(var jc: TJpegContext); -begin - if jc.common.err = nil then - Exit; - jpeg_destroy(@jc.common); - jpeg_destroy_decompress(@jc.d); - jpeg_destroy_compress(@jc.c); - jc.common.err := nil; -end; - -procedure InitSource(cinfo: j_decompress_ptr); -begin - PSourceMgr(cinfo.src).StartOfFile := True; -end; - -function FillInputBuffer(cinfo: j_decompress_ptr): Boolean; -var - NBytes: LongInt; - Src: PSourceMgr; -begin - Src := PSourceMgr(cinfo.src); - NBytes := JIO.Read(Src.Input, Src.Buffer, BufferSize); - - if NBytes <= 0 then - begin - PByteArray(Src.Buffer)[0] := $FF; - PByteArray(Src.Buffer)[1] := JPEG_EOI; - NBytes := 2; - end; - Src.Pub.next_input_byte := Src.Buffer; - Src.Pub.bytes_in_buffer := NBytes; - Src.StartOfFile := False; - Result := True; -end; - -procedure SkipInputData(cinfo: j_decompress_ptr; num_bytes: LongInt); -var - Src: PSourceMgr; -begin - Src := PSourceMgr(cinfo.src); - if num_bytes > 0 then - begin - while num_bytes > Src.Pub.bytes_in_buffer do - begin - Dec(num_bytes, Src.Pub.bytes_in_buffer); - FillInputBuffer(cinfo); - end; - Src.Pub.next_input_byte := @PByteArray(Src.Pub.next_input_byte)[num_bytes]; - //Inc(LongInt(Src.Pub.next_input_byte), num_bytes); - Dec(Src.Pub.bytes_in_buffer, num_bytes); - end; -end; - -procedure TermSource(cinfo: j_decompress_ptr); -var - Src: PSourceMgr; -begin - Src := PSourceMgr(cinfo.src); - // Move stream position back just after EOI marker so that more that one - // JPEG images can be loaded from one stream - JIO.Seek(Src.Input, -Src.Pub.bytes_in_buffer, smFromCurrent); -end; - -procedure JpegStdioSrc(var cinfo: jpeg_decompress_struct; Handle: - TImagingHandle); -var - Src: PSourceMgr; -begin - if cinfo.src = nil then - begin - cinfo.src := cinfo.mem.alloc_small(j_common_ptr(@cinfo), JPOOL_PERMANENT, - SizeOf(TSourceMgr)); - Src := PSourceMgr(cinfo.src); - Src.Buffer := cinfo.mem.alloc_small(j_common_ptr(@cinfo), JPOOL_PERMANENT, - BufferSize * SizeOf(JOCTET)); - end; - Src := PSourceMgr(cinfo.src); - Src.Pub.init_source := InitSource; - Src.Pub.fill_input_buffer := FillInputBuffer; - Src.Pub.skip_input_data := SkipInputData; - Src.Pub.resync_to_restart := jpeg_resync_to_restart; - Src.Pub.term_source := TermSource; - Src.Input := Handle; - Src.Pub.bytes_in_buffer := 0; - Src.Pub.next_input_byte := nil; -end; - -procedure InitDest(cinfo: j_compress_ptr); -var - Dest: PDestMgr; -begin - Dest := PDestMgr(cinfo.dest); - Dest.Pub.next_output_byte := Dest.Buffer; - Dest.Pub.free_in_buffer := BufferSize; -end; - -function EmptyOutput(cinfo: j_compress_ptr): Boolean; -var - Dest: PDestMgr; -begin - Dest := PDestMgr(cinfo.dest); - JIO.Write(Dest.Output, Dest.Buffer, BufferSize); - Dest.Pub.next_output_byte := Dest.Buffer; - Dest.Pub.free_in_buffer := BufferSize; - Result := True; -end; - -procedure TermDest(cinfo: j_compress_ptr); -var - Dest: PDestMgr; - DataCount: LongInt; -begin - Dest := PDestMgr(cinfo.dest); - DataCount := BufferSize - Dest.Pub.free_in_buffer; - if DataCount > 0 then - JIO.Write(Dest.Output, Dest.Buffer, DataCount); -end; - -procedure JpegStdioDest(var cinfo: jpeg_compress_struct; Handle: - TImagingHandle); -var - Dest: PDestMgr; -begin - if cinfo.dest = nil then - cinfo.dest := cinfo.mem.alloc_small(j_common_ptr(@cinfo), - JPOOL_PERMANENT, SizeOf(TDestMgr)); - Dest := PDestMgr(cinfo.dest); - Dest.Buffer := cinfo.mem.alloc_small(j_common_ptr(@cinfo), JPOOL_IMAGE, - BufferSize * SIZEOF(JOCTET)); - Dest.Pub.init_destination := InitDest; - Dest.Pub.empty_output_buffer := EmptyOutput; - Dest.Pub.term_destination := TermDest; - Dest.Output := Handle; -end; - -procedure SetupErrorMgr(var jc: TJpegContext); -begin - // Set standard error handlers and then override some - jc.common.err := jpeg_std_error(JpegErrorMgr); - jc.common.err.error_exit := JpegError; - jc.common.err.output_message := OutputMessage; -end; - -procedure InitDecompressor(Handle: TImagingHandle; var jc: TJpegContext); -begin - jpeg_CreateDecompress(@jc.d, JPEG_LIB_VERSION, sizeof(jc.d)); - JpegStdioSrc(jc.d, Handle); - jpeg_read_header(@jc.d, True); - jc.d.scale_num := 1; - jc.d.scale_denom := 1; - jc.d.do_block_smoothing := True; - if jc.d.out_color_space = JCS_GRAYSCALE then - begin - jc.d.quantize_colors := True; - jc.d.desired_number_of_colors := 256; - end; -end; - -procedure InitCompressor(Handle: TImagingHandle; var jc: TJpegContext; - Saver: TJpegFileFormat); -begin - jpeg_CreateCompress(@jc.c, JPEG_LIB_VERSION, sizeof(jc.c)); - JpegStdioDest(jc.c, Handle); - if Saver.FGrayScale then - jc.c.in_color_space := JCS_GRAYSCALE - else - jc.c.in_color_space := JCS_RGB; - jpeg_set_defaults(@jc.c); - jpeg_set_quality(@jc.c, Saver.FQuality, True); - if Saver.FProgressive then - jpeg_simple_progression(@jc.c); -end; - -{ TJpegFileFormat class implementation } - -procedure TJpegFileFormat.Define; -begin - FName := SJpegFormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := JpegSupportedFormats; - - FQuality := JpegDefaultQuality; - FProgressive := JpegDefaultProgressive; - - AddMasks(SJpegMasks); - RegisterOption(ImagingJpegQuality, @FQuality); - RegisterOption(ImagingJpegProgressive, @FProgressive); -end; - -procedure TJpegFileFormat.CheckOptionsValidity; -begin - // Check if option values are valid - if not (FQuality in [1..100]) then - FQuality := JpegDefaultQuality; -end; - -function TJpegFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - PtrInc, LinesPerCall, LinesRead, I: Integer; - Dest: PByte; - jc: TJpegContext; - Info: TImageFormatInfo; - Col32: PColor32Rec; - NeedsRedBlueSwap: Boolean; - Pix: PColor24Rec; -{$IFDEF ErrorJmpRecovery} - ErrorClient: TErrorClientData; -{$ENDIF} - - procedure LoadMetaData; - var - XDensity, YDensity: Single; - ResUnit: TResolutionUnit; - begin - // Density unit: 0 - undef, 1 - inch, 2 - cm - if jc.d.saw_JFIF_marker and (jc.d.density_unit > 0) and - (jc.d.X_density > 0) and (jc.d.Y_density > 0) then - begin - XDensity := jc.d.X_density; - YDensity := jc.d.Y_density; - ResUnit := ruDpi; - if jc.d.density_unit = 2 then - ResUnit := ruDpcm; - FMetadata.SetPhysicalPixelSize(ResUnit, XDensity, YDensity); - end; - end; - -begin - // Copy IO functions to global var used in JpegLib callbacks - Result := False; - SetJpegIO(GetIO); - SetLength(Images, 1); - - with JIO, Images[0] do - try - ZeroMemory(@jc, SizeOf(jc)); - SetupErrorMgr(jc); - {$IFDEF ErrorJmpRecovery} - ZeroMemory(@ErrorClient, SizeOf(ErrorClient)); - jc.common.client_data := @ErrorClient; - if setjmp(ErrorClient.JmpBuf) <> 0 then - begin - Result := True; - Exit; - end; - {$ENDIF} - InitDecompressor(Handle, jc); - - case jc.d.out_color_space of - JCS_GRAYSCALE: Format := ifGray8; - JCS_RGB: Format := ifR8G8B8; - JCS_CMYK: Format := ifA8R8G8B8; - else - Exit; - end; - - NewImage(jc.d.image_width, jc.d.image_height, Format, Images[0]); - jpeg_start_decompress(@jc.d); - GetImageFormatInfo(Format, Info); - PtrInc := Width * Info.BytesPerPixel; - LinesPerCall := 1; - Dest := Bits; - - // If Jpeg's colorspace is RGB and not YCbCr we need to swap - // R and B to get Imaging's native order - NeedsRedBlueSwap := jc.d.jpeg_color_space = JCS_RGB; - {$IFDEF RGBSWAPPED} - // Force R-B swap for FPC's PasJpeg - NeedsRedBlueSwap := True; - {$ENDIF} - - {$IFDEF ErrorJmpRecovery} - ErrorClient.ScanlineReadReached := True; - {$ENDIF} - - while jc.d.output_scanline < jc.d.output_height do - begin - LinesRead := jpeg_read_scanlines(@jc.d, @Dest, LinesPerCall); - if NeedsRedBlueSwap and (Format = ifR8G8B8) then - begin - Pix := PColor24Rec(Dest); - for I := 0 to Width - 1 do - begin - SwapValues(Pix.R, Pix.B); - Inc(Pix); - end; - end; - Inc(Dest, PtrInc * LinesRead); - end; - - if jc.d.out_color_space = JCS_CMYK then - begin - Col32 := Bits; - // Translate from CMYK to RGB - for I := 0 to Width * Height - 1 do - begin - CMYKToRGB(255 - Col32.B, 255 - Col32.G, 255 - Col32.R, 255 - Col32.A, - Col32.R, Col32.G, Col32.B); - Col32.A := 255; - Inc(Col32); - end; - end; - - // Store supported metadata - LoadMetaData; - - jpeg_finish_output(@jc.d); - jpeg_finish_decompress(@jc.d); - Result := True; - finally - ReleaseContext(jc); - end; -end; - -function TJpegFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - PtrInc, LinesWritten: LongInt; - Src, Line: PByte; - jc: TJpegContext; - ImageToSave: TImageData; - Info: TImageFormatInfo; - MustBeFreed: Boolean; -{$IFDEF RGBSWAPPED} - I: LongInt; - Pix: PColor24Rec; -{$ENDIF} - - procedure SaveMetaData; - var - XRes, YRes: Single; - begin - if FMetadata.GetPhysicalPixelSize(ruDpcm, XRes, YRes, True) then - begin - jc.c.density_unit := 2; // Dots per cm - jc.c.X_density := Round(XRes); - jc.c.Y_density := Round(YRes) - end; - end; - -begin - Result := False; - // Copy IO functions to global var used in JpegLib callbacks - SetJpegIO(GetIO); - - // Makes image to save compatible with Jpeg saving capabilities - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with JIO, ImageToSave do - try - ZeroMemory(@jc, SizeOf(jc)); - SetupErrorMgr(jc); - - GetImageFormatInfo(Format, Info); - FGrayScale := Format = ifGray8; - InitCompressor(Handle, jc, Self); - jc.c.image_width := Width; - jc.c.image_height := Height; - if FGrayScale then - begin - jc.c.input_components := 1; - jc.c.in_color_space := JCS_GRAYSCALE; - end - else - begin - jc.c.input_components := 3; - jc.c.in_color_space := JCS_RGB; - end; - - PtrInc := Width * Info.BytesPerPixel; - Src := Bits; - - {$IFDEF RGBSWAPPED} - GetMem(Line, PtrInc); - {$ENDIF} - - // Save supported metadata - SaveMetaData; - - jpeg_start_compress(@jc.c, True); - while (jc.c.next_scanline < jc.c.image_height) do - begin - {$IFDEF RGBSWAPPED} - if Format = ifR8G8B8 then - begin - Move(Src^, Line^, PtrInc); - Pix := PColor24Rec(Line); - for I := 0 to Width - 1 do - begin - SwapValues(Pix.R, Pix.B); - Inc(Pix, 1); - end; - end; - {$ELSE} - Line := Src; - {$ENDIF} - - LinesWritten := jpeg_write_scanlines(@jc.c, @Line, 1); - Inc(Src, PtrInc * LinesWritten); - end; - - jpeg_finish_compress(@jc.c); - Result := True; - finally - ReleaseContext(jc); - if MustBeFreed then - FreeImage(ImageToSave); - {$IFDEF RGBSWAPPED} - FreeMem(Line); - {$ENDIF} - end; -end; - -procedure TJpegFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin - if Info.HasGrayChannel then - ConvertImage(Image, ifGray8) - else - ConvertImage(Image, ifR8G8B8); -end; - -function TJpegFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - ReadCount: LongInt; - ID: array[0..9] of AnsiChar; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - FillChar(ID, SizeOf(ID), 0); - ReadCount := Read(Handle, @ID, SizeOf(ID)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(ID)) and - CompareMem(@ID, @JpegMagic, SizeOf(JpegMagic)); - end; -end; - -procedure TJpegFileFormat.SetJpegIO(const JpegIO: TIOFunctions); -begin - JIO := JpegIO; -end; - -initialization - RegisterImageFileFormat(TJpegFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 --------------------------------------------------- - - Able to read corrupted JPEG files - loads partial image - and skips the corrupted parts (FPC and x86 Delphi). - - Fixed reading of physical resolution metadata, could cause - "divided by zero" later on for some files. - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Fixed loading of some JPEGs with certain APPN markers (bug in JpegLib). - - Fixed swapped Red-Blue order when loading Jpegs with - jc.d.jpeg_color_space = JCS_RGB. - - Added loading and saving of physical pixel size metadata. - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Changed the Jpeg error manager, messages were not properly formated. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - Fixed wrong color space setting in InitCompressor. - - Fixed problem with progressive Jpegs in FPC (modified JpegLib, - can't use FPC's PasJpeg in Windows). - - -- 0.25.0 Changes/Bug Fixes --------------------------------- - - FPC's PasJpeg wasn't really used in last version, fixed. - - -- 0.24.1 Changes/Bug Fixes --------------------------------- - - Fixed loading of CMYK jpeg images. Could cause heap corruption - and loaded image looked wrong. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Removed JFIF/EXIF detection from TestFormat. Found JPEGs - with different headers (Lavc) which weren't recognized. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - MakeCompatible method moved to base class, put ConvertToSupported here. - GetSupportedFormats removed, it is now set in constructor. - - Made public properties for options registered to SetOption/GetOption - functions. - - Changed extensions to filename masks. - - Changed SaveData, LoadData, and MakeCompatible methods according - to changes in base class in Imaging unit. - - Changes in TestFormat, now reads JFIF and EXIF signatures too. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - input position is now set correctly to the end of the image - after loading is done. Loading of sequence of JPEG files stored in - single stream works now - - when loading and saving images in FPC with PASJPEG read and - blue channels are swapped to have the same chanel order as IMJPEGLIB - - you can now choose between IMJPEGLIB and PASJPEG implementations - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - added SetJpegIO method which is used by JNG image format -} -end. - diff --git a/3rd/Imaging/Source/ImagingNetworkGraphics.pas b/3rd/Imaging/Source/ImagingNetworkGraphics.pas deleted file mode 100644 index 9d5a23fbb..000000000 --- a/3rd/Imaging/Source/ImagingNetworkGraphics.pas +++ /dev/null @@ -1,2695 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loaders/savers for Network Graphics image - file formats PNG, MNG, and JNG.} -unit ImagingNetworkGraphics; - -interface - -{$I ImagingOptions.inc} - -{ If MNG support is enabled we must make sure PNG and JNG are enabled too.} -{$IFNDEF DONT_LINK_MNG} - {$UNDEF DONT_LINK_PNG} - {$UNDEF DONT_LINK_JNG} -{$ENDIF} - -uses - Types, SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility, ImagingFormats, dzlib; - -type - { Basic class for Network Graphics file formats loaders/savers.} - TNetworkGraphicsFileFormat = class(TImageFileFormat) - protected - FSignature: TChar8; - FPreFilter: LongInt; - FCompressLevel: LongInt; - FLossyCompression: LongBool; - FLossyAlpha: LongBool; - FQuality: LongInt; - FProgressive: LongBool; - FZLibStategy: Integer; - function GetSupportedFormats: TImageFormats; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - procedure Define; override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - procedure CheckOptionsValidity; override; - published - { Sets precompression filter used when saving images with lossless compression. - Allowed values are: 0 (none), 1 (sub), 2 (up), 3 (average), 4 (paeth), - 5 (use 0 for indexed/gray images and 4 for RGB/ARGB images), - 6 (adaptive filtering - use best filter for each scanline - very slow). - Note that filters 3 and 4 are much slower than filters 1 and 2. - Default value is 5.} - property PreFilter: LongInt read FPreFilter write FPreFilter; - { Sets ZLib compression level used when saving images with lossless compression. - Allowed values are in range 0 (no compresstion) to 9 (best compression). - Default value is 5.} - property CompressLevel: LongInt read FCompressLevel write FCompressLevel; - { Specifies whether MNG animation frames are saved with lossy or lossless - compression. Lossless frames are saved as PNG images and lossy frames are - saved as JNG images. Allowed values are 0 (False) and 1 (True). - Default value is 0.} - property LossyCompression: LongBool read FLossyCompression write FLossyCompression; - { Defines whether alpha channel of lossy MNG frames or JNG images - is lossy compressed too. Allowed values are 0 (False) and 1 (True). - Default value is 0.} - property LossyAlpha: LongBool read FLossyAlpha write FLossyAlpha; - { Specifies compression quality used when saving lossy MNG frames or JNG images. - For details look at ImagingJpegQuality option.} - property Quality: LongInt read FQuality write FQuality; - { Specifies whether images are saved in progressive format when saving lossy - MNG frames or JNG images. For details look at ImagingJpegProgressive.} - property Progressive: LongBool read FProgressive write FProgressive; - end; - - { Class for loading Portable Network Graphics Images. - Loads all types of this image format (all images in png test suite) - and saves all types with bitcount >= 8 (non-interlaced only). - Compression level and filtering can be set by options interface. - - Supported ancillary chunks (loading): - tRNS, bKGD - (for indexed images transparency contains alpha values for palette, - RGB/Gray images with transparency are converted to formats with alpha - and pixels with transparent color are replaced with background color - with alpha = 0).} - TPNGFileFormat = class(TNetworkGraphicsFileFormat) - private - FLoadAnimated: LongBool; - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - published - property LoadAnimated: LongBool read FLoadAnimated write FLoadAnimated; - end; - -{$IFNDEF DONT_LINK_MNG} - { Class for loading Multiple Network Graphics files. - This format has complex animation capabilities but Imaging only - extracts frames. Individual frames are stored as standard PNG or JNG - images. Loads all types of these frames stored in IHDR-IEND and - JHDR-IEND streams (Note that there are MNG chunks - like BASI which define images but does not contain image data itself, - those are ignored). - Imaging saves MNG files as MNG-VLC (very low complexity) so it is basicaly - an array of image frames without MNG animation chunks. Frames can be saved - as lossless PNG or lossy JNG images (look at TPNGFileFormat and - TJNGFileFormat for info). Every frame can be in different data format. - - Many frame compression settings can be modified by options interface.} - TMNGFileFormat = class(TNetworkGraphicsFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - end; -{$ENDIF} - -{$IFNDEF DONT_LINK_JNG} - { Class for loading JPEG Network Graphics Images. - Loads all types of this image format (all images in jng test suite) - and saves all types except 12 bit JPEGs. - Alpha channel in JNG images is stored separately from color/gray data and - can be lossy (as JPEG image) or lossless (as PNG image) compressed. - Type of alpha compression, compression level and quality, - and filtering can be set by options interface. - - Supported ancillary chunks (loading): - tRNS, bKGD - (Images with transparency are converted to formats with alpha - and pixels with transparent color are replaced with background color - with alpha = 0).} - TJNGFileFormat = class(TNetworkGraphicsFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - end; -{$ENDIF} - - -implementation - -uses -{$IFNDEF DONT_LINK_JNG} - ImagingJpeg, ImagingIO, -{$ENDIF} - ImagingCanvases; - -const - NGDefaultPreFilter = 5; - NGDefaultCompressLevel = 5; - NGDefaultLossyAlpha = False; - NGDefaultLossyCompression = False; - NGDefaultProgressive = False; - NGDefaultQuality = 90; - NGLosslessFormats: TImageFormats = [ifIndex8, ifGray8, ifA8Gray8, ifGray16, - ifA16Gray16, ifR8G8B8, ifA8R8G8B8, ifR16G16B16, ifA16R16G16B16, ifB16G16R16, - ifA16B16G16R16, ifBinary]; - NGLossyFormats: TImageFormats = [ifGray8, ifA8Gray8, ifR8G8B8, ifA8R8G8B8]; - PNGDefaultLoadAnimated = True; - NGDefaultZLibStartegy = 1; // Z_FILTERED - - SPNGFormatName = 'Portable Network Graphics'; - SPNGMasks = '*.png'; - SMNGFormatName = 'Multiple Network Graphics'; - SMNGMasks = '*.mng'; - SJNGFormatName = 'JPEG Network Graphics'; - SJNGMasks = '*.jng'; - -resourcestring - SErrorLoadingChunk = 'Error when reading %s chunk data. File may be corrupted.'; - -type - { Chunk header.} - TChunkHeader = packed record - DataSize: LongWord; - ChunkID: TChar4; - end; - - { IHDR chunk format - PNG header.} - TIHDR = packed record - Width: LongWord; // Image width - Height: LongWord; // Image height - BitDepth: Byte; // Bits per pixel or bits per sample (for truecolor) - ColorType: Byte; // 0 = grayscale, 2 = truecolor, 3 = palette, - // 4 = gray + alpha, 6 = truecolor + alpha - Compression: Byte; // Compression type: 0 = ZLib - Filter: Byte; // Used precompress filter - Interlacing: Byte; // Used interlacing: 0 = no int, 1 = Adam7 - end; - PIHDR = ^TIHDR; - - { MHDR chunk format - MNG header.} - TMHDR = packed record - FrameWidth: LongWord; // Frame width - FrameHeight: LongWord; // Frame height - TicksPerSecond: LongWord; // FPS of animation - NominalLayerCount: LongWord; // Number of layers in file - NominalFrameCount: LongWord; // Number of frames in file - NominalPlayTime: LongWord; // Play time of animation in ticks - SimplicityProfile: LongWord; // Defines which MNG features are used in this file - end; - PMHDR = ^TMHDR; - - { JHDR chunk format - JNG header.} - TJHDR = packed record - Width: LongWord; // Image width - Height: LongWord; // Image height - ColorType: Byte; // 8 = grayscale (Y), 10 = color (YCbCr), - // 12 = gray + alpha (Y-alpha), 14 = color + alpha (YCbCr-alpha) - SampleDepth: Byte; // 8, 12 or 20 (8 and 12 samples together) bit - Compression: Byte; // Compression type: 8 = Huffman coding - Interlacing: Byte; // 0 = single scan, 8 = progressive - AlphaSampleDepth: Byte; // 0, 1, 2, 4, 8, 16 if alpha compression is 0 (PNG) - // 8 if alpha compression is 8 (JNG) - AlphaCompression: Byte; // 0 = PNG graysscale IDAT, 8 = grayscale 8-bit JPEG - AlphaFilter: Byte; // 0 = PNG filter or no filter (JPEG) - AlphaInterlacing: Byte; // 0 = non interlaced - end; - PJHDR = ^TJHDR; - - { acTL chunk format - APNG animation control.} - TacTL = packed record - NumFrames: LongWord; // Number of frames - NumPlay: LongWord; // Number of times to loop the animation (0 = inf) - end; - PacTL =^TacTL; - - { fcTL chunk format - APNG frame control.} - TfcTL = packed record - SeqNumber: LongWord; // Sequence number of the animation chunk, starting from 0 - Width: LongWord; // Width of the following frame - Height: LongWord; // Height of the following frame - XOffset: LongWord; // X position at which to render the following frame - YOffset: LongWord; // Y position at which to render the following frame - DelayNumer: Word; // Frame delay fraction numerator - DelayDenom: Word; // Frame delay fraction denominator - DisposeOp: Byte; // Type of frame area disposal to be done after rendering this frame - BlendOp: Byte; // Type of frame area rendering for this frame - end; - PfcTL = ^TfcTL; - - { pHYs chunk format - encodes the absolute or relative dimensions of pixels.} - TpHYs = packed record - PixelsPerUnitX: LongWord; - PixelsPerUnitY: LongWord; - UnitSpecifier: Byte; - end; - PpHYs = ^TpHYs; - -const - { PNG file identifier.} - PNGSignature: TChar8 = #$89'PNG'#$0D#$0A#$1A#$0A; - { MNG file identifier.} - MNGSignature: TChar8 = #$8A'MNG'#$0D#$0A#$1A#$0A; - { JNG file identifier.} - JNGSignature: TChar8 = #$8B'JNG'#$0D#$0A#$1A#$0A; - - { Constants for chunk identifiers and signature identifiers. - They are in big-endian format.} - IHDRChunk: TChar4 = 'IHDR'; - IENDChunk: TChar4 = 'IEND'; - MHDRChunk: TChar4 = 'MHDR'; - MENDChunk: TChar4 = 'MEND'; - JHDRChunk: TChar4 = 'JHDR'; - IDATChunk: TChar4 = 'IDAT'; - JDATChunk: TChar4 = 'JDAT'; - JDAAChunk: TChar4 = 'JDAA'; - JSEPChunk: TChar4 = 'JSEP'; - PLTEChunk: TChar4 = 'PLTE'; - BACKChunk: TChar4 = 'BACK'; - DEFIChunk: TChar4 = 'DEFI'; - TERMChunk: TChar4 = 'TERM'; - tRNSChunk: TChar4 = 'tRNS'; - bKGDChunk: TChar4 = 'bKGD'; - gAMAChunk: TChar4 = 'gAMA'; - acTLChunk: TChar4 = 'acTL'; - fcTLChunk: TChar4 = 'fcTL'; - fdATChunk: TChar4 = 'fdAT'; - pHYsChunk: TChar4 = 'pHYs'; - - { APNG frame dispose operations.} - DisposeOpNone = 0; - DisposeOpBackground = 1; - DisposeOpPrevious = 2; - - { APNG frame blending modes} - BlendOpSource = 0; - BlendOpOver = 1; - - { Interlace start and offsets.} - RowStart: array[0..6] of LongInt = (0, 0, 4, 0, 2, 0, 1); - ColumnStart: array[0..6] of LongInt = (0, 4, 0, 2, 0, 1, 0); - RowIncrement: array[0..6] of LongInt = (8, 8, 8, 4, 4, 2, 2); - ColumnIncrement: array[0..6] of LongInt = (8, 8, 4, 4, 2, 2, 1); - -type - { Helper class that holds information about MNG frame in PNG or JNG format.} - TFrameInfo = class - public - Index: Integer; - FrameWidth, FrameHeight: LongInt; - IsJpegFrame: Boolean; - IHDR: TIHDR; - JHDR: TJHDR; - fcTL: TfcTL; - pHYs: TpHYs; - Palette: PPalette24; - PaletteEntries: LongInt; - Transparency: Pointer; - TransparencySize: LongInt; - Background: Pointer; - BackgroundSize: LongInt; - IDATMemory: TMemoryStream; - JDATMemory: TMemoryStream; - JDAAMemory: TMemoryStream; - constructor Create(AIndex: Integer); - destructor Destroy; override; - procedure AssignSharedProps(Source: TFrameInfo); - end; - - { Defines type of Network Graphics file.} - TNGFileType = (ngPNG, ngAPNG, ngMNG, ngJNG); - - TNGFileHandler = class - public - FileFormat: TNetworkGraphicsFileFormat; - FileType: TNGFileType; - Frames: array of TFrameInfo; - MHDR: TMHDR; // Main header for MNG files - acTL: TacTL; // Global anim control for APNG files - GlobalPalette: PPalette24; - GlobalPaletteEntries: LongInt; - GlobalTransparency: Pointer; - GlobalTransparencySize: LongInt; - constructor Create(AFileFormat: TNetworkGraphicsFileFormat); - destructor Destroy; override; - procedure Clear; - function GetLastFrame: TFrameInfo; - function AddFrameInfo: TFrameInfo; - procedure LoadMetaData; - end; - - { Network Graphics file parser and frame converter.} - TNGFileLoader = class(TNGFileHandler) - public - function LoadFile(Handle: TImagingHandle): Boolean; - procedure LoadImageFromPNGFrame(FrameWidth, FrameHeight: LongInt; const IHDR: TIHDR; IDATStream: TMemoryStream; var Image: TImageData); -{$IFNDEF DONT_LINK_JNG} - procedure LoadImageFromJNGFrame(FrameWidth, FrameHeight: LongInt; const JHDR: TJHDR; IDATStream, JDATStream, JDAAStream: TMemoryStream; var Image: TImageData); -{$ENDIF} - procedure ApplyFrameSettings(Frame: TFrameInfo; var Image: TImageData); - end; - - TNGFileSaver = class(TNGFileHandler) - public - PreFilter: LongInt; - CompressLevel: LongInt; - LossyAlpha: Boolean; - Quality: LongInt; - Progressive: Boolean; - ZLibStrategy: Integer; - function SaveFile(Handle: TImagingHandle): Boolean; - procedure AddFrame(const Image: TImageData; IsJpegFrame: Boolean); - procedure StoreImageToPNGFrame(const IHDR: TIHDR; Bits: Pointer; FmtInfo: TImageFormatInfo; IDATStream: TMemoryStream); -{$IFNDEF DONT_LINK_JNG} - procedure StoreImageToJNGFrame(const JHDR: TJHDR; const Image: TImageData; IDATStream, JDATStream, JDAAStream: TMemoryStream); -{$ENDIF} - procedure SetFileOptions; - end; - -{$IFNDEF DONT_LINK_JNG} - TCustomIOJpegFileFormat = class(TJpegFileFormat) - protected - FCustomIO: TIOFunctions; - procedure SetJpegIO(const JpegIO: TIOFunctions); override; - procedure SetCustomIO(const CustomIO: TIOFunctions); - end; -{$ENDIF} - - TAPNGAnimator = class - public - class procedure Animate(var Images: TDynImageDataArray; const acTL: TacTL; const SrcFrames: array of TFrameInfo); - end; - -{ Helper routines } - -function PaethPredictor(A, B, C: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -var - P, PA, PB, PC: LongInt; -begin - P := A + B - C; - PA := Abs(P - A); - PB := Abs(P - B); - PC := Abs(P - C); - if (PA <= PB) and (PA <= PC) then - Result := A - else - if PB <= PC then - Result := B - else - Result := C; -end; - -procedure SwapRGB(Line: PByte; Width, SampleDepth, BytesPerPixel: LongInt); -var - I: LongInt; - Tmp: Word; -begin - case SampleDepth of - 8: - for I := 0 to Width - 1 do - with PColor24Rec(Line)^ do - begin - Tmp := R; - R := B; - B := Tmp; - Inc(Line, BytesPerPixel); - end; - 16: - for I := 0 to Width - 1 do - with PColor48Rec(Line)^ do - begin - Tmp := R; - R := B; - B := Tmp; - Inc(Line, BytesPerPixel); - end; - end; - end; - -{$IFNDEF DONT_LINK_JNG} - -{ TCustomIOJpegFileFormat class implementation } - -procedure TCustomIOJpegFileFormat.SetCustomIO(const CustomIO: TIOFunctions); -begin - FCustomIO := CustomIO; -end; - -procedure TCustomIOJpegFileFormat.SetJpegIO(const JpegIO: TIOFunctions); -begin - inherited SetJpegIO(FCustomIO); -end; - -{$ENDIF} - -{ TFrameInfo class implementation } - -constructor TFrameInfo.Create(AIndex: Integer); -begin - Index := AIndex; - IDATMemory := TMemoryStream.Create; - JDATMemory := TMemoryStream.Create; - JDAAMemory := TMemoryStream.Create; -end; - -destructor TFrameInfo.Destroy; -begin - FreeMem(Palette); - FreeMem(Transparency); - FreeMem(Background); - IDATMemory.Free; - JDATMemory.Free; - JDAAMemory.Free; - inherited Destroy; -end; - -procedure TFrameInfo.AssignSharedProps(Source: TFrameInfo); -begin - IHDR := Source.IHDR; - JHDR := Source.JHDR; - PaletteEntries := Source.PaletteEntries; - GetMem(Palette, PaletteEntries * SizeOf(TColor24Rec)); - Move(Source.Palette^, Palette^, PaletteEntries * SizeOf(TColor24Rec)); - TransparencySize := Source.TransparencySize; - GetMem(Transparency, TransparencySize); - Move(Source.Transparency^, Transparency^, TransparencySize); -end; - -{ TNGFileHandler class implementation} - -destructor TNGFileHandler.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TNGFileHandler.Clear; -var - I: LongInt; -begin - for I := 0 to Length(Frames) - 1 do - Frames[I].Free; - SetLength(Frames, 0); - FreeMemNil(GlobalPalette); - GlobalPaletteEntries := 0; - FreeMemNil(GlobalTransparency); - GlobalTransparencySize := 0; -end; - -constructor TNGFileHandler.Create(AFileFormat: TNetworkGraphicsFileFormat); -begin - FileFormat := AFileFormat; -end; - -function TNGFileHandler.GetLastFrame: TFrameInfo; -var - Len: LongInt; -begin - Len := Length(Frames); - if Len > 0 then - Result := Frames[Len - 1] - else - Result := nil; -end; - -procedure TNGFileHandler.LoadMetaData; -var - I: Integer; - Delay, Denom: Integer; -begin - if FileType = ngAPNG then - begin - // Num plays of APNG animation - FileFormat.FMetadata.SetMetaItem(SMetaAnimationLoops, acTL.NumPlay); - end; - - for I := 0 to High(Frames) do - begin - if Frames[I].pHYs.UnitSpecifier = 1 then - begin - // Store physical pixel dimensions, in PNG stored as pixels per meter DPM - FileFormat.FMetadata.SetPhysicalPixelSize(ruDpm, Frames[I].pHYs.PixelsPerUnitX, - Frames[I].pHYs.PixelsPerUnitY); - end; - if FileType = ngAPNG then - begin - // Store frame delay of APNG file frame - Denom := Frames[I].fcTL.DelayDenom; - if Denom = 0 then - Denom := 100; - Delay := Round(1000 * (Frames[I].fcTL.DelayNumer / Denom)); - FileFormat.FMetadata.SetMetaItem(SMetaFrameDelay, Delay, I); - end; - end; -end; - -function TNGFileHandler.AddFrameInfo: TFrameInfo; -var - Len: LongInt; -begin - Len := Length(Frames); - SetLength(Frames, Len + 1); - Result := TFrameInfo.Create(Len); - Frames[Len] := Result; -end; - -{ TNGFileLoader class implementation} - -function TNGFileLoader.LoadFile(Handle: TImagingHandle): Boolean; -var - Sig: TChar8; - Chunk: TChunkHeader; - ChunkData: Pointer; - ChunkCrc: LongWord; - - procedure ReadChunk; - begin - GetIO.Read(Handle, @Chunk, SizeOf(Chunk)); - Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); - end; - - procedure ReadChunkData; - var - ReadBytes: LongWord; - begin - FreeMemNil(ChunkData); - GetMem(ChunkData, Chunk.DataSize); - ReadBytes := GetIO.Read(Handle, ChunkData, Chunk.DataSize); - GetIO.Read(Handle, @ChunkCrc, SizeOf(ChunkCrc)); - if ReadBytes <> Chunk.DataSize then - RaiseImaging(SErrorLoadingChunk, [string(Chunk.ChunkID)]); - end; - - procedure SkipChunkData; - begin - GetIO.Seek(Handle, Chunk.DataSize + SizeOf(ChunkCrc), smFromCurrent); - end; - - procedure StartNewPNGImage; - var - Frame: TFrameInfo; - begin - ReadChunkData; - - if Chunk.ChunkID = fcTLChunk then - begin - if (Length(Frames) = 1) and (Frames[0].IDATMemory.Size = 0) then - begin - // First fcTL chunk maybe for first IDAT frame which is alredy created - Frame := Frames[0]; - end - else - begin - // Subsequent APNG frames with data in fdAT - Frame := AddFrameInfo; - // Copy some shared props from first frame (IHDR is the same for all APNG frames, palette etc) - Frame.AssignSharedProps(Frames[0]); - end; - Frame.fcTL := PfcTL(ChunkData)^; - SwapEndianLongWord(@Frame.fcTL, 5); - Frame.fcTL.DelayNumer := SwapEndianWord(Frame.fcTL.DelayNumer); - Frame.fcTL.DelayDenom := SwapEndianWord(Frame.fcTL.DelayDenom); - Frame.FrameWidth := Frame.fcTL.Width; - Frame.FrameHeight := Frame.fcTL.Height; - end - else - begin - // This is frame defined by IHDR chunk - Frame := AddFrameInfo; - Frame.IHDR := PIHDR(ChunkData)^; - SwapEndianLongWord(@Frame.IHDR, 2); - Frame.FrameWidth := Frame.IHDR.Width; - Frame.FrameHeight := Frame.IHDR.Height; - end; - Frame.IsJpegFrame := False; - end; - - procedure StartNewJNGImage; - var - Frame: TFrameInfo; - begin - ReadChunkData; - Frame := AddFrameInfo; - Frame.IsJpegFrame := True; - Frame.JHDR := PJHDR(ChunkData)^; - SwapEndianLongWord(@Frame.JHDR, 2); - Frame.FrameWidth := Frame.JHDR.Width; - Frame.FrameHeight := Frame.JHDR.Height; - end; - - procedure AppendIDAT; - begin - ReadChunkData; - // Append current IDAT/fdAT chunk to storage stream - if Chunk.ChunkID = IDATChunk then - GetLastFrame.IDATMemory.Write(ChunkData^, Chunk.DataSize) - else if Chunk.ChunkID = fdATChunk then - GetLastFrame.IDATMemory.Write(PByteArray(ChunkData)[4], Chunk.DataSize - SizeOf(LongWord)); - end; - - procedure AppendJDAT; - begin - ReadChunkData; - // Append current JDAT chunk to storage stream - GetLastFrame.JDATMemory.Write(ChunkData^, Chunk.DataSize); - end; - - procedure AppendJDAA; - begin - ReadChunkData; - // Append current JDAA chunk to storage stream - GetLastFrame.JDAAMemory.Write(ChunkData^, Chunk.DataSize); - end; - - procedure LoadPLTE; - begin - ReadChunkData; - if GetLastFrame = nil then - begin - // Load global palette - GetMem(GlobalPalette, Chunk.DataSize); - Move(ChunkData^, GlobalPalette^, Chunk.DataSize); - GlobalPaletteEntries := Chunk.DataSize div 3; - end - else if GetLastFrame.Palette = nil then - begin - if (Chunk.DataSize = 0) and (GlobalPalette <> nil) then - begin - // Use global palette - GetMem(GetLastFrame.Palette, GlobalPaletteEntries * SizeOf(TColor24Rec)); - Move(GlobalPalette^, GetLastFrame.Palette^, GlobalPaletteEntries * SizeOf(TColor24Rec)); - GetLastFrame.PaletteEntries := GlobalPaletteEntries; - end - else - begin - // Load pal from PLTE chunk - GetMem(GetLastFrame.Palette, Chunk.DataSize); - Move(ChunkData^, GetLastFrame.Palette^, Chunk.DataSize); - GetLastFrame.PaletteEntries := Chunk.DataSize div 3; - end; - end; - end; - - procedure LoadtRNS; - begin - ReadChunkData; - if GetLastFrame = nil then - begin - // Load global transparency - GetMem(GlobalTransparency, Chunk.DataSize); - Move(ChunkData^, GlobalTransparency^, Chunk.DataSize); - GlobalTransparencySize := Chunk.DataSize; - end - else if GetLastFrame.Transparency = nil then - begin - if (Chunk.DataSize = 0) and (GlobalTransparency <> nil) then - begin - // Use global transparency - GetMem(GetLastFrame.Transparency, GlobalTransparencySize); - Move(GlobalTransparency^, GetLastFrame.Transparency^, Chunk.DataSize); - GetLastFrame.TransparencySize := GlobalTransparencySize; - end - else - begin - // Load pal from tRNS chunk - GetMem(GetLastFrame.Transparency, Chunk.DataSize); - Move(ChunkData^, GetLastFrame.Transparency^, Chunk.DataSize); - GetLastFrame.TransparencySize := Chunk.DataSize; - end; - end; - end; - - procedure LoadbKGD; - begin - ReadChunkData; - if GetLastFrame.Background = nil then - begin - GetMem(GetLastFrame.Background, Chunk.DataSize); - Move(ChunkData^, GetLastFrame.Background^, Chunk.DataSize); - GetLastFrame.BackgroundSize := Chunk.DataSize; - end; - end; - - procedure HandleacTL; - begin - FileType := ngAPNG; - ReadChunkData; - acTL := PacTL(ChunkData)^; - SwapEndianLongWord(@acTL, SizeOf(acTL) div SizeOf(LongWord)); - end; - - procedure LoadpHYs; - begin - ReadChunkData; - with GetLastFrame do - begin - pHYs := PpHYs(ChunkData)^; - SwapEndianLongWord(@pHYs, SizeOf(pHYs) div SizeOf(LongWord)); - end; - end; - -begin - Result := False; - Clear; - ChunkData := nil; - with GetIO do - try - Read(Handle, @Sig, SizeOf(Sig)); - // Set file type according to the signature - if Sig = PNGSignature then FileType := ngPNG - else if Sig = MNGSignature then FileType := ngMNG - else if Sig = JNGSignature then FileType := ngJNG - else Exit; - - if FileType = ngMNG then - begin - // Store MNG header if present - ReadChunk; - ReadChunkData; - MHDR := PMHDR(ChunkData)^; - SwapEndianLongWord(@MHDR, SizeOf(MHDR) div SizeOf(LongWord)); - end; - - // Read chunks until ending chunk or EOF is reached - repeat - ReadChunk; - if (Chunk.ChunkID = IHDRChunk) or (Chunk.ChunkID = fcTLChunk) then StartNewPNGImage - else if Chunk.ChunkID = JHDRChunk then StartNewJNGImage - else if (Chunk.ChunkID = IDATChunk) or (Chunk.ChunkID = fdATChunk) then AppendIDAT - else if Chunk.ChunkID = JDATChunk then AppendJDAT - else if Chunk.ChunkID = JDAAChunk then AppendJDAA - else if Chunk.ChunkID = PLTEChunk then LoadPLTE - else if Chunk.ChunkID = tRNSChunk then LoadtRNS - else if Chunk.ChunkID = bKGDChunk then LoadbKGD - else if Chunk.ChunkID = acTLChunk then HandleacTL - else if Chunk.ChunkID = pHYsChunk then LoadpHYs - else SkipChunkData; - until Eof(Handle) or (Chunk.ChunkID = MENDChunk) or - ((FileType <> ngMNG) and (Chunk.ChunkID = IENDChunk)); - - Result := True; - finally - FreeMemNil(ChunkData); - end; -end; - -procedure TNGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight: LongInt; const IHDR: TIHDR; - IDATStream: TMemoryStream; var Image: TImageData); -type - TGetPixelFunc = function(Line: PByteArray; X: LongInt): Byte; -var - LineBuffer: array[Boolean] of PByteArray; - ActLine: Boolean; - Data, TotalBuffer, ZeroLine, PrevLine: Pointer; - BitCount, TotalSize, TotalPos, BytesPerPixel, I, Pass, - SrcDataSize, BytesPerLine, InterlaceLineBytes, InterlaceWidth: LongInt; - Info: TImageFormatInfo; - - procedure DecodeAdam7; - const - BitTable: array[1..8] of LongInt = ($1, $3, 0, $F, 0, 0, 0, $FF); - StartBit: array[1..8] of LongInt = (7, 6, 0, 4, 0, 0, 0, 0); - var - Src, Dst, Dst2: PByte; - CurBit, Col: LongInt; - begin - Src := @LineBuffer[ActLine][1]; - Col := ColumnStart[Pass]; - with Image do - case BitCount of - 1, 2, 4: - begin - Dst := @PByteArray(Data)[I * BytesPerLine]; - repeat - CurBit := StartBit[BitCount]; - repeat - Dst2 := @PByteArray(Dst)[(BitCount * Col) shr 3]; - Dst2^ := Dst2^ or ((Src^ shr CurBit) and BitTable[BitCount]) - shl (StartBit[BitCount] - (Col * BitCount mod 8)); - Inc(Col, ColumnIncrement[Pass]); - Dec(CurBit, BitCount); - until CurBit < 0; - Inc(Src); - until Col >= Width; - end; - else - begin - Dst := @PByteArray(Data)[I * BytesPerLine + Col * BytesPerPixel]; - repeat - CopyPixel(Src, Dst, BytesPerPixel); - Inc(Dst, BytesPerPixel); - Inc(Src, BytesPerPixel); - Inc(Dst, ColumnIncrement[Pass] * BytesPerPixel - BytesPerPixel); - Inc(Col, ColumnIncrement[Pass]); - until Col >= Width; - end; - end; - end; - - procedure FilterScanline(Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray; - BytesPerLine: LongInt); - var - I: LongInt; - begin - case Filter of - 0: - begin - // No filter - Move(Line^, Target^, BytesPerLine); - end; - 1: - begin - // Sub filter - Move(Line^, Target^, BytesPerPixel); - for I := BytesPerPixel to BytesPerLine - 1 do - Target[I] := (Line[I] + Target[I - BytesPerPixel]) and $FF; - end; - 2: - begin - // Up filter - for I := 0 to BytesPerLine - 1 do - Target[I] := (Line[I] + PrevLine[I]) and $FF; - end; - 3: - begin - // Average filter - for I := 0 to BytesPerPixel - 1 do - Target[I] := (Line[I] + PrevLine[I] shr 1) and $FF; - for I := BytesPerPixel to BytesPerLine - 1 do - Target[I] := (Line[I] + (Target[I - BytesPerPixel] + PrevLine[I]) shr 1) and $FF; - end; - 4: - begin - // Paeth filter - for I := 0 to BytesPerPixel - 1 do - Target[I] := (Line[I] + PaethPredictor(0, PrevLine[I], 0)) and $FF; - for I := BytesPerPixel to BytesPerLine - 1 do - Target[I] := (Line[I] + PaethPredictor(Target[I - BytesPerPixel], PrevLine[I], PrevLine[I - BytesPerPixel])) and $FF; - end; - end; - end; - - procedure TransformLOCOToRGB(Data: PByte; NumPixels, BytesPerPixel: LongInt); - var - I: LongInt; - begin - for I := 0 to NumPixels - 1 do - begin - if IHDR.BitDepth = 8 then - begin - PColor32Rec(Data).R := Byte(PColor32Rec(Data).R + PColor32Rec(Data).G); - PColor32Rec(Data).B := Byte(PColor32Rec(Data).B + PColor32Rec(Data).G); - end - else - begin - PColor64Rec(Data).R := Word(PColor64Rec(Data).R + PColor64Rec(Data).G); - PColor64Rec(Data).B := Word(PColor64Rec(Data).B + PColor64Rec(Data).G); - end; - Inc(Data, BytesPerPixel); - end; - end; - - function CheckBinaryPalette: Boolean; - begin - with GetLastFrame do - Result := (PaletteEntries = 2) and - (Palette[0].R = 0) and (Palette[0].G = 0) and (Palette[0].B = 0) and - (Palette[1].R = 255) and (Palette[1].G = 255) and (Palette[1].B = 255); - end; - -begin - Image.Width := FrameWidth; - Image.Height := FrameHeight; - Image.Format := ifUnknown; - - case IHDR.ColorType of - 0: - begin - // Gray scale image - case IHDR.BitDepth of - 1: Image.Format := ifBinary; - 2, 4, 8: Image.Format := ifGray8; - 16: Image.Format := ifGray16; - end; - BitCount := IHDR.BitDepth; - end; - 2: - begin - // RGB image - case IHDR.BitDepth of - 8: Image.Format := ifR8G8B8; - 16: Image.Format := ifR16G16B16; - end; - BitCount := IHDR.BitDepth * 3; - end; - 3: - begin - // Indexed image - if (IHDR.BitDepth = 1) and CheckBinaryPalette then - Image.Format := ifBinary - else - Image.Format := ifIndex8; - BitCount := IHDR.BitDepth; - end; - 4: - begin - // Grayscale + alpha image - case IHDR.BitDepth of - 8: Image.Format := ifA8Gray8; - 16: Image.Format := ifA16Gray16; - end; - BitCount := IHDR.BitDepth * 2; - end; - 6: - begin - // ARGB image - case IHDR.BitDepth of - 8: Image.Format := ifA8R8G8B8; - 16: Image.Format := ifA16R16G16B16; - end; - BitCount := IHDR.BitDepth * 4; - end; - end; - - GetImageFormatInfo(Image.Format, Info); - BytesPerPixel := (BitCount + 7) div 8; - - LineBuffer[True] := nil; - LineBuffer[False] := nil; - TotalBuffer := nil; - ZeroLine := nil; - ActLine := True; - - // Start decoding - with Image do - try - BytesPerLine := (Width * BitCount + 7) div 8; - SrcDataSize := Height * BytesPerLine; - GetMem(Data, SrcDataSize); - FillChar(Data^, SrcDataSize, 0); - GetMem(ZeroLine, BytesPerLine); - FillChar(ZeroLine^, BytesPerLine, 0); - - if IHDR.Interlacing = 1 then - begin - // Decode interlaced images - TotalPos := 0; - DecompressBuf(IDATStream.Memory, IDATStream.Size, 0, - Pointer(TotalBuffer), TotalSize); - GetMem(LineBuffer[True], BytesPerLine + 1); - GetMem(LineBuffer[False], BytesPerLine + 1); - for Pass := 0 to 6 do - begin - // Prepare next interlace run - if Width <= ColumnStart[Pass] then - Continue; - InterlaceWidth := (Width + ColumnIncrement[Pass] - 1 - - ColumnStart[Pass]) div ColumnIncrement[Pass]; - InterlaceLineBytes := (InterlaceWidth * BitCount + 7) shr 3; - I := RowStart[Pass]; - FillChar(LineBuffer[True][0], BytesPerLine + 1, 0); - FillChar(LineBuffer[False][0], BytesPerLine + 1, 0); - while I < Height do - begin - // Copy line from decompressed data to working buffer - Move(PByteArray(TotalBuffer)[TotalPos], - LineBuffer[ActLine][0], InterlaceLineBytes + 1); - Inc(TotalPos, InterlaceLineBytes + 1); - // Swap red and blue channels if necessary - if (IHDR.ColorType in [2, 6]) then - SwapRGB(@LineBuffer[ActLine][1], InterlaceWidth, IHDR.BitDepth, BytesPerPixel); - // Reverse-filter current scanline - FilterScanline(LineBuffer[ActLine][0], BytesPerPixel, - @LineBuffer[ActLine][1], @LineBuffer[not ActLine][1], - @LineBuffer[ActLine][1], InterlaceLineBytes); - // Decode Adam7 interlacing - DecodeAdam7; - ActLine := not ActLine; - // Continue with next row in interlaced order - Inc(I, RowIncrement[Pass]); - end; - end; - end - else - begin - // Decode non-interlaced images - PrevLine := ZeroLine; - DecompressBuf(IDATStream.Memory, IDATStream.Size, SrcDataSize + Height, - Pointer(TotalBuffer), TotalSize); - for I := 0 to Height - 1 do - begin - // Swap red and blue channels if necessary - if IHDR.ColorType in [2, 6] then - SwapRGB(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], Width, - IHDR.BitDepth, BytesPerPixel); - // reverse-filter current scanline - FilterScanline(PByteArray(TotalBuffer)[I * (BytesPerLine + 1)], - BytesPerPixel, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], - PrevLine, @PByteArray(Data)[I * BytesPerLine], BytesPerLine); - PrevLine := @PByteArray(Data)[I * BytesPerLine]; - end; - end; - - Size := Info.GetPixelsSize(Info.Format, Width, Height); - - if Size <> SrcDataSize then - begin - // If source data size is different from size of image in assigned - // format we must convert it (it is in 1/2/4 bit count) - GetMem(Bits, Size); - case IHDR.BitDepth of - 1: - begin - // Convert only indexed, keep black and white in ifBinary - if IHDR.ColorType <> 0 then - Convert1To8(Data, Bits, Width, Height, BytesPerLine, False); - end; - 2: Convert2To8(Data, Bits, Width, Height, BytesPerLine, IHDR.ColorType = 0); - 4: Convert4To8(Data, Bits, Width, Height, BytesPerLine, IHDR.ColorType = 0); - end; - FreeMem(Data); - end - else - begin - // If source data size is the same as size of - // image Bits in assigned format we simply copy pointer reference - Bits := Data; - end; - - // LOCO transformation was used too (only for color types 2 and 6) - if (IHDR.Filter = 64) and (IHDR.ColorType in [2, 6]) then - TransformLOCOToRGB(Bits, Width * Height, BytesPerPixel); - - // Images with 16 bit channels must be swapped because of PNG's big endianity - if IHDR.BitDepth = 16 then - SwapEndianWord(Bits, Width * Height * BytesPerPixel div SizeOf(Word)); - finally - FreeMem(LineBuffer[True]); - FreeMem(LineBuffer[False]); - FreeMem(TotalBuffer); - FreeMem(ZeroLine); - end; -end; - -{$IFNDEF DONT_LINK_JNG} - -procedure TNGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight: LongInt; const JHDR: TJHDR; IDATStream, - JDATStream, JDAAStream: TMemoryStream; var Image: TImageData); -var - AlphaImage: TImageData; - FakeIHDR: TIHDR; - FmtInfo: TImageFormatInfo; - I: LongInt; - AlphaPtr: PByte; - GrayPtr: PWordRec; - ColorPtr: PColor32Rec; - - procedure LoadJpegFromStream(Stream: TStream; var DestImage: TImageData); - var - JpegFormat: TCustomIOJpegFileFormat; - Handle: TImagingHandle; - DynImages: TDynImageDataArray; - begin - if JHDR.SampleDepth <> 12 then - begin - JpegFormat := TCustomIOJpegFileFormat.Create; - JpegFormat.SetCustomIO(StreamIO); - Stream.Position := 0; - Handle := StreamIO.Open(Pointer(Stream), omReadOnly); - try - JpegFormat.LoadData(Handle, DynImages, True); - DestImage := DynImages[0]; - finally - StreamIO.Close(Handle); - JpegFormat.Free; - SetLength(DynImages, 0); - end; - end - else - NewImage(FrameWidth, FrameHeight, ifR8G8B8, DestImage); - end; - -begin - LoadJpegFromStream(JDATStream, Image); - - // If present separate alpha channel is processed - if (JHDR.ColorType in [12, 14]) and (Image.Format in [ifGray8, ifR8G8B8]) then - begin - InitImage(AlphaImage); - if JHDR.AlphaCompression = 0 then - begin - // Alpha channel is PNG compressed - FakeIHDR.Width := JHDR.Width; - FakeIHDR.Height := JHDR.Height; - FakeIHDR.ColorType := 0; - FakeIHDR.BitDepth := JHDR.AlphaSampleDepth; - FakeIHDR.Filter := JHDR.AlphaFilter; - FakeIHDR.Interlacing := JHDR.AlphaInterlacing; - - LoadImageFromPNGFrame(FrameWidth, FrameHeight, FakeIHDR, IDATStream, AlphaImage); - end - else - begin - // Alpha channel is JPEG compressed - LoadJpegFromStream(JDAAStream, AlphaImage); - end; - - // Check if alpha channel is the same size as image - if (Image.Width <> AlphaImage.Width) and (Image.Height <> AlphaImage.Height) then - ResizeImage(AlphaImage, Image.Width, Image.Height, rfNearest); - - // Check alpha channels data format - GetImageFormatInfo(AlphaImage.Format, FmtInfo); - if (FmtInfo.BytesPerPixel > 1) or (not FmtInfo.HasGrayChannel) then - ConvertImage(AlphaImage, ifGray8); - - // Convert image to fromat with alpha channel - if Image.Format = ifGray8 then - ConvertImage(Image, ifA8Gray8) - else - ConvertImage(Image, ifA8R8G8B8); - - // Combine alpha channel with image - AlphaPtr := AlphaImage.Bits; - if Image.Format = ifA8Gray8 then - begin - GrayPtr := Image.Bits; - for I := 0 to Image.Width * Image.Height - 1 do - begin - GrayPtr.High := AlphaPtr^; - Inc(GrayPtr); - Inc(AlphaPtr); - end; - end - else - begin - ColorPtr := Image.Bits; - for I := 0 to Image.Width * Image.Height - 1 do - begin - ColorPtr.A := AlphaPtr^; - Inc(ColorPtr); - Inc(AlphaPtr); - end; - end; - - FreeImage(AlphaImage); - end; -end; - -{$ENDIF} - -procedure TNGFileLoader.ApplyFrameSettings(Frame: TFrameInfo; var Image: TImageData); -var - FmtInfo: TImageFormatInfo; - BackGroundColor: TColor64Rec; - ColorKey: TColor64Rec; - Alphas: PByteArray; - AlphasSize: LongInt; - IsColorKeyPresent: Boolean; - IsBackGroundPresent: Boolean; - IsColorFormat: Boolean; - - procedure ConverttRNS; - begin - if FmtInfo.IsIndexed then - begin - if Alphas = nil then - begin - GetMem(Alphas, Frame.TransparencySize); - Move(Frame.Transparency^, Alphas^, Frame.TransparencySize); - AlphasSize := Frame.TransparencySize; - end; - end - else if not FmtInfo.HasAlphaChannel then - begin - FillChar(ColorKey, SizeOf(ColorKey), 0); - Move(Frame.Transparency^, ColorKey, Min(Frame.TransparencySize, SizeOf(ColorKey))); - if IsColorFormat then - SwapValues(ColorKey.R, ColorKey.B); - SwapEndianWord(@ColorKey, 3); - // 1/2/4 bit images were converted to 8 bit so we must convert color key too - if (not Frame.IsJpegFrame) and (Frame.IHDR.ColorType in [0, 4]) then - case Frame.IHDR.BitDepth of - 1: ColorKey.B := Word(ColorKey.B * 255); - 2: ColorKey.B := Word(ColorKey.B * 85); - 4: ColorKey.B := Word(ColorKey.B * 17); - end; - IsColorKeyPresent := True; - end; - end; - - procedure ConvertbKGD; - begin - FillChar(BackGroundColor, SizeOf(BackGroundColor), 0); - Move(Frame.Background^, BackGroundColor, Min(Frame.BackgroundSize, SizeOf(BackGroundColor))); - if IsColorFormat then - SwapValues(BackGroundColor.R, BackGroundColor.B); - SwapEndianWord(@BackGroundColor, 3); - // 1/2/4 bit images were converted to 8 bit so we must convert back color too - if (not Frame.IsJpegFrame) and (Frame.IHDR.ColorType in [0, 4]) then - case Frame.IHDR.BitDepth of - 1: BackGroundColor.B := Word(BackGroundColor.B * 255); - 2: BackGroundColor.B := Word(BackGroundColor.B * 85); - 4: BackGroundColor.B := Word(BackGroundColor.B * 17); - end; - IsBackGroundPresent := True; - end; - - procedure ReconstructPalette; - var - I: LongInt; - begin - with Image do - begin - GetMem(Palette, FmtInfo.PaletteEntries * SizeOf(TColor32Rec)); - FillChar(Palette^, FmtInfo.PaletteEntries * SizeOf(TColor32Rec), $FF); - // if RGB palette was loaded from file then use it - if Frame.Palette <> nil then - for I := 0 to Min(Frame.PaletteEntries, FmtInfo.PaletteEntries) - 1 do - with Palette[I] do - begin - R := Frame.Palette[I].B; - G := Frame.Palette[I].G; - B := Frame.Palette[I].R; - end; - // if palette alphas were loaded from file then use them - if Alphas <> nil then - begin - for I := 0 to Min(AlphasSize, FmtInfo.PaletteEntries) - 1 do - Palette[I].A := Alphas[I]; - end; - end; - end; - - procedure ApplyColorKey; - var - DestFmt: TImageFormat; - Col32, Bkg32: TColor32Rec; - OldPixel, NewPixel: Pointer; - begin - case Image.Format of - ifGray8: DestFmt := ifA8Gray8; - ifGray16: DestFmt := ifA16Gray16; - ifR8G8B8: DestFmt := ifA8R8G8B8; - ifR16G16B16: DestFmt := ifA16R16G16B16; - else - DestFmt := ifUnknown; - end; - - if DestFmt <> ifUnknown then - begin - if not IsBackGroundPresent then - BackGroundColor := ColorKey; - ConvertImage(Image, DestFmt); - - // Now back color and color key must be converted to image's data format, looks ugly - case Image.Format of - ifA8Gray8: - begin - Col32 := Color32(0, 0, $FF, Byte(ColorKey.B)); - Bkg32 := Color32(0, 0, 0, Byte(BackGroundColor.B)); - end; - ifA16Gray16: - begin - ColorKey.G := $FFFF; - end; - ifA8R8G8B8: - begin - Col32 := Color32($FF, Byte(ColorKey.R), Byte(ColorKey.G), Byte(ColorKey.B)); - Bkg32 := Color32(0, Byte(BackGroundColor.R), Byte(BackGroundColor.G), Byte(BackGroundColor.B)); - end; - ifA16R16G16B16: - begin - ColorKey.A := $FFFF; - end; - end; - - if Image.Format in [ifA8Gray8, ifA8R8G8B8] then - begin - OldPixel := @Col32; - NewPixel := @Bkg32; - end - else - begin - OldPixel := @ColorKey; - NewPixel := @BackGroundColor; - end; - - ReplaceColor(Image, 0, 0, Image.Width, Image.Height, OldPixel, NewPixel); - end; - end; - -begin - Alphas := nil; - IsColorKeyPresent := False; - IsBackGroundPresent := False; - GetImageFormatInfo(Image.Format, FmtInfo); - - IsColorFormat := (Frame.IsJpegFrame and (Frame.JHDR.ColorType in [10, 14])) or - (not Frame.IsJpegFrame and (Frame.IHDR.ColorType in [2, 6])); - - // Convert some chunk data to useful format - if Frame.TransparencySize > 0 then - ConverttRNS; - if Frame.BackgroundSize > 0 then - ConvertbKGD; - - // Build palette for indexed images - if FmtInfo.IsIndexed then - ReconstructPalette; - - // Apply color keying - if IsColorKeyPresent and not FmtInfo.HasAlphaChannel then - ApplyColorKey; - - FreeMemNil(Alphas); -end; - -{ TNGFileSaver class implementation } - -procedure TNGFileSaver.StoreImageToPNGFrame(const IHDR: TIHDR; Bits: Pointer; - FmtInfo: TImageFormatInfo; IDATStream: TMemoryStream); -var - TotalBuffer, CompBuffer, ZeroLine, PrevLine: Pointer; - FilterLines: array[0..4] of PByteArray; - TotalSize, CompSize, I, BytesPerLine, BytesPerPixel: LongInt; - Filter: Byte; - Adaptive: Boolean; - - procedure FilterScanline(Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray); - var - I: LongInt; - begin - case Filter of - 0: - begin - // No filter - Move(Line^, Target^, BytesPerLine); - end; - 1: - begin - // Sub filter - Move(Line^, Target^, BytesPerPixel); - for I := BytesPerPixel to BytesPerLine - 1 do - Target[I] := (Line[I] - Line[I - BytesPerPixel]) and $FF; - end; - 2: - begin - // Up filter - for I := 0 to BytesPerLine - 1 do - Target[I] := (Line[I] - PrevLine[I]) and $FF; - end; - 3: - begin - // Average filter - for I := 0 to BytesPerPixel - 1 do - Target[I] := (Line[I] - PrevLine[I] shr 1) and $FF; - for I := BytesPerPixel to BytesPerLine - 1 do - Target[I] := (Line[I] - (Line[I - BytesPerPixel] + PrevLine[I]) shr 1) and $FF; - end; - 4: - begin - // Paeth filter - for I := 0 to BytesPerPixel - 1 do - Target[I] := (Line[I] - PaethPredictor(0, PrevLine[I], 0)) and $FF; - for I := BytesPerPixel to BytesPerLine - 1 do - Target[I] := (Line[I] - PaethPredictor(Line[I - BytesPerPixel], PrevLine[I], PrevLine[I - BytesPerPixel])) and $FF; - end; - end; - end; - - procedure AdaptiveFilter(var Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray); - var - I, J, BestTest: LongInt; - Sums: array[0..4] of LongInt; - begin - // Compute the output scanline using all five filters, - // and select the filter that gives the smallest sum of - // absolute values of outputs - FillChar(Sums, SizeOf(Sums), 0); - BestTest := MaxInt; - for I := 0 to 4 do - begin - FilterScanline(I, BytesPerPixel, Line, PrevLine, FilterLines[I]); - for J := 0 to BytesPerLine - 1 do - Sums[I] := Sums[I] + Abs(ShortInt(FilterLines[I][J])); - if Sums[I] < BestTest then - begin - Filter := I; - BestTest := Sums[I]; - end; - end; - Move(FilterLines[Filter]^, Target^, BytesPerLine); - end; - -begin - // Select precompression filter and compression level - Adaptive := False; - Filter := 0; - case PreFilter of - 6: - if not ((IHDR.BitDepth < 8) or (IHDR.ColorType = 3)) then - Adaptive := True; - 0..4: Filter := PreFilter; - else - if IHDR.ColorType in [2, 6] then - Filter := 4 - end; - - // Prepare data for compression - CompBuffer := nil; - FillChar(FilterLines, SizeOf(FilterLines), 0); - BytesPerPixel := Max(1, FmtInfo.BytesPerPixel); - BytesPerLine := FmtInfo.GetPixelsSize(FmtInfo.Format, LongInt(IHDR.Width), 1); - TotalSize := (BytesPerLine + 1) * LongInt(IHDR.Height); - GetMem(TotalBuffer, TotalSize); - GetMem(ZeroLine, BytesPerLine); - FillChar(ZeroLine^, BytesPerLine, 0); - PrevLine := ZeroLine; - - if Adaptive then - begin - for I := 0 to 4 do - GetMem(FilterLines[I], BytesPerLine); - end; - - try - // Process next scanlines - for I := 0 to IHDR.Height - 1 do - begin - // Filter scanline - if Adaptive then - begin - AdaptiveFilter(Filter, BytesPerPixel, @PByteArray(Bits)[I * BytesPerLine], - PrevLine, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1]); - end - else - begin - FilterScanline(Filter, BytesPerPixel, @PByteArray(Bits)[I * BytesPerLine], - PrevLine, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1]); - end; - PrevLine := @PByteArray(Bits)[I * BytesPerLine]; - // Swap red and blue if necessary - if (IHDR.ColorType in [2, 6]) and not FmtInfo.IsRBSwapped then - begin - SwapRGB(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], - IHDR.Width, IHDR.BitDepth, BytesPerPixel); - end; - // Images with 16 bit channels must be swapped because of PNG's big endianess - if IHDR.BitDepth = 16 then - begin - SwapEndianWord(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], - BytesPerLine div SizeOf(Word)); - end; - // Set filter used for this scanline - PByteArray(TotalBuffer)[I * (BytesPerLine + 1)] := Filter; - end; - // Compress IDAT data - CompressBuf(TotalBuffer, TotalSize, CompBuffer, CompSize, - CompressLevel, ZLibStrategy); - // Write IDAT data to stream - IDATStream.WriteBuffer(CompBuffer^, CompSize); - finally - FreeMem(TotalBuffer); - FreeMem(CompBuffer); - FreeMem(ZeroLine); - if Adaptive then - for I := 0 to 4 do - FreeMem(FilterLines[I]); - end; -end; - -{$IFNDEF DONT_LINK_JNG} - -procedure TNGFileSaver.StoreImageToJNGFrame(const JHDR: TJHDR; - const Image: TImageData; IDATStream, JDATStream, - JDAAStream: TMemoryStream); -var - ColorImage, AlphaImage: TImageData; - FmtInfo: TImageFormatInfo; - AlphaPtr: PByte; - GrayPtr: PWordRec; - ColorPtr: PColor32Rec; - I: LongInt; - FakeIHDR: TIHDR; - - procedure SaveJpegToStream(Stream: TStream; const Image: TImageData); - var - JpegFormat: TCustomIOJpegFileFormat; - Handle: TImagingHandle; - DynImages: TDynImageDataArray; - begin - JpegFormat := TCustomIOJpegFileFormat.Create; - JpegFormat.SetCustomIO(StreamIO); - // Only JDAT stream can be saved progressive - if Stream = JDATStream then - JpegFormat.FProgressive := Progressive - else - JpegFormat.FProgressive := False; - JpegFormat.FQuality := Quality; - SetLength(DynImages, 1); - DynImages[0] := Image; - Handle := StreamIO.Open(Pointer(Stream), omCreate); - try - JpegFormat.SaveData(Handle, DynImages, 0); - finally - StreamIO.Close(Handle); - SetLength(DynImages, 0); - JpegFormat.Free; - end; - end; - -begin - GetImageFormatInfo(Image.Format, FmtInfo); - InitImage(ColorImage); - InitImage(AlphaImage); - - if FmtInfo.HasAlphaChannel then - begin - // Create new image for alpha channel and color image without alpha - CloneImage(Image, ColorImage); - NewImage(Image.Width, Image.Height, ifGray8, AlphaImage); - case Image.Format of - ifA8Gray8: ConvertImage(ColorImage, ifGray8); - ifA8R8G8B8: ConvertImage(ColorImage, ifR8G8B8); - end; - - // Store source image's alpha to separate image - AlphaPtr := AlphaImage.Bits; - if Image.Format = ifA8Gray8 then - begin - GrayPtr := Image.Bits; - for I := 0 to Image.Width * Image.Height - 1 do - begin - AlphaPtr^ := GrayPtr.High; - Inc(GrayPtr); - Inc(AlphaPtr); - end; - end - else - begin - ColorPtr := Image.Bits; - for I := 0 to Image.Width * Image.Height - 1 do - begin - AlphaPtr^ := ColorPtr.A; - Inc(ColorPtr); - Inc(AlphaPtr); - end; - end; - - // Write color image to stream as JPEG - SaveJpegToStream(JDATStream, ColorImage); - - if LossyAlpha then - begin - // Write alpha image to stream as JPEG - SaveJpegToStream(JDAAStream, AlphaImage); - end - else - begin - // Alpha channel is PNG compressed - FakeIHDR.Width := JHDR.Width; - FakeIHDR.Height := JHDR.Height; - FakeIHDR.ColorType := 0; - FakeIHDR.BitDepth := JHDR.AlphaSampleDepth; - FakeIHDR.Filter := JHDR.AlphaFilter; - FakeIHDR.Interlacing := JHDR.AlphaInterlacing; - - GetImageFormatInfo(AlphaImage.Format, FmtInfo); - StoreImageToPNGFrame(FakeIHDR, AlphaImage.Bits, FmtInfo, IDATStream); - end; - - FreeImage(ColorImage); - FreeImage(AlphaImage); - end - else - begin - // Simply write JPEG to stream - SaveJpegToStream(JDATStream, Image); - end; -end; - -{$ENDIF} - -procedure TNGFileSaver.AddFrame(const Image: TImageData; IsJpegFrame: Boolean); -var - Frame: TFrameInfo; - FmtInfo: TImageFormatInfo; - Index: Integer; - - procedure StorePalette; - var - Pal: PPalette24; - Alphas: PByteArray; - I, PalBytes: LongInt; - AlphasDiffer: Boolean; - begin - // Fill and save RGB part of palette to PLTE chunk - PalBytes := FmtInfo.PaletteEntries * SizeOf(TColor24Rec); - GetMem(Pal, PalBytes); - AlphasDiffer := False; - for I := 0 to FmtInfo.PaletteEntries - 1 do - begin - Pal[I].B := Image.Palette[I].R; - Pal[I].G := Image.Palette[I].G; - Pal[I].R := Image.Palette[I].B; - if Image.Palette[I].A < 255 then - AlphasDiffer := True; - end; - Frame.Palette := Pal; - Frame.PaletteEntries := FmtInfo.PaletteEntries; - // Fill and save alpha part (if there are any alphas < 255) of palette to tRNS chunk - if AlphasDiffer then - begin - PalBytes := FmtInfo.PaletteEntries * SizeOf(Byte); - GetMem(Alphas, PalBytes); - for I := 0 to FmtInfo.PaletteEntries - 1 do - Alphas[I] := Image.Palette[I].A; - Frame.Transparency := Alphas; - Frame.TransparencySize := PalBytes; - end; - end; - - procedure FillFrameControlChunk(const IHDR: TIHDR; var fcTL: TfcTL); - var - Delay: Integer; - begin - fcTL.SeqNumber := 0; // Decided when writing to file - fcTL.Width := IHDR.Width; - fcTL.Height := IHDR.Height; - fcTL.XOffset := 0; - fcTL.YOffset := 0; - fcTL.DelayNumer := 1; - fcTL.DelayDenom := 3; - if FileFormat.FMetadata.HasMetaItemForSaving(SMetaFrameDelay, Index) then - begin - // Metadata contains frame delay information in milliseconds - Delay := FileFormat.FMetadata.MetaItemsForSavingMulti[SMetaFrameDelay, Index]; - fcTL.DelayNumer := Delay; - fcTL.DelayDenom := 1000; - end; - fcTL.DisposeOp := DisposeOpNone; - fcTL.BlendOp := BlendOpSource; - SwapEndianLongWord(@fcTL, 5); - fcTL.DelayNumer := SwapEndianWord(fcTL.DelayNumer); - fcTL.DelayDenom := SwapEndianWord(fcTL.DelayDenom); - end; - -begin - // Add new frame - Frame := AddFrameInfo; - Frame.IsJpegFrame := IsJpegFrame; - Index := Length(Frames) - 1; - - with Frame do - begin - GetImageFormatInfo(Image.Format, FmtInfo); - - if IsJpegFrame then - begin -{$IFNDEF DONT_LINK_JNG} - // Fill JNG header - JHDR.Width := Image.Width; - JHDR.Height := Image.Height; - case Image.Format of - ifGray8: JHDR.ColorType := 8; - ifR8G8B8: JHDR.ColorType := 10; - ifA8Gray8: JHDR.ColorType := 12; - ifA8R8G8B8: JHDR.ColorType := 14; - end; - JHDR.SampleDepth := 8; // 8-bit samples and quantization tables - JHDR.Compression := 8; // Huffman coding - JHDR.Interlacing := Iff(Progressive, 8, 0); - JHDR.AlphaSampleDepth := Iff(FmtInfo.HasAlphaChannel, 8, 0); - JHDR.AlphaCompression := Iff(LossyAlpha, 8, 0); - JHDR.AlphaFilter := 0; - JHDR.AlphaInterlacing := 0; - - StoreImageToJNGFrame(JHDR, Image, IDATMemory, JDATMemory, JDAAMemory); - - // Finally swap endian - SwapEndianLongWord(@JHDR, 2); -{$ENDIF} - end - else - begin - // Fill PNG header - IHDR.Width := Image.Width; - IHDR.Height := Image.Height; - IHDR.Compression := 0; - IHDR.Filter := 0; - IHDR.Interlacing := 0; - IHDR.BitDepth := FmtInfo.BytesPerPixel * 8; - - // Select appropiate PNG color type and modify bitdepth - if FmtInfo.HasGrayChannel then - begin - IHDR.ColorType := 0; - if FmtInfo.HasAlphaChannel then - begin - IHDR.ColorType := 4; - IHDR.BitDepth := IHDR.BitDepth div 2; - end; - end - else if FmtInfo.Format = ifBinary then - begin - IHDR.ColorType := 0; - IHDR.BitDepth := 1; - end - else if FmtInfo.IsIndexed then - IHDR.ColorType := 3 - else if FmtInfo.HasAlphaChannel then - begin - IHDR.ColorType := 6; - IHDR.BitDepth := IHDR.BitDepth div 4; - end - else - begin - IHDR.ColorType := 2; - IHDR.BitDepth := IHDR.BitDepth div 3; - end; - - if FileType = ngAPNG then - begin - // Fill fcTL chunk of APNG file - FillFrameControlChunk(IHDR, fcTL); - end; - - // Compress PNG image and store it to stream - StoreImageToPNGFrame(IHDR, Image.Bits, FmtInfo, IDATMemory); - // Store palette if necesary - if FmtInfo.IsIndexed then - StorePalette; - - // Finally swap endian - SwapEndianLongWord(@IHDR, 2); - end; - end; -end; - -function TNGFileSaver.SaveFile(Handle: TImagingHandle): Boolean; -var - I: LongInt; - Chunk: TChunkHeader; - SeqNo: LongWord; - - function GetNextSeqNo: LongWord; - begin - // Seq numbers of fcTL and fdAT are "interleaved" as they share the counter. - // Example: first fcTL for IDAT has seq=0, next is fcTL for seond frame with - // seq=1, then first fdAT with seq=2, fcTL seq=3, fdAT=4, ... - Result := SwapEndianLongWord(SeqNo); - Inc(SeqNo); - end; - - function CalcChunkCrc(const ChunkHdr: TChunkHeader; Data: Pointer; - Size: LongInt): LongWord; - begin - Result := $FFFFFFFF; - CalcCrc32(Result, @ChunkHdr.ChunkID, SizeOf(ChunkHdr.ChunkID)); - CalcCrc32(Result, Data, Size); - Result := SwapEndianLongWord(Result xor $FFFFFFFF); - end; - - procedure WriteChunk(var Chunk: TChunkHeader; ChunkData: Pointer); - var - ChunkCrc: LongWord; - SizeToWrite: LongInt; - begin - SizeToWrite := Chunk.DataSize; - Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); - ChunkCrc := CalcChunkCrc(Chunk, ChunkData, SizeToWrite); - GetIO.Write(Handle, @Chunk, SizeOf(Chunk)); - if SizeToWrite <> 0 then - GetIO.Write(Handle, ChunkData, SizeToWrite); - GetIO.Write(Handle, @ChunkCrc, SizeOf(ChunkCrc)); - end; - - procedure WritefdAT(Frame: TFrameInfo); - var - ChunkCrc: LongWord; - ChunkSeqNo: LongWord; - begin - Chunk.ChunkID := fdATChunk; - ChunkSeqNo := GetNextSeqNo; - // fdAT saves seq number LongWord before compressed pixels - Chunk.DataSize := Frame.IDATMemory.Size + SizeOf(LongWord); - Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); - // Calc CRC - ChunkCrc := $FFFFFFFF; - CalcCrc32(ChunkCrc, @Chunk.ChunkID, SizeOf(Chunk.ChunkID)); - CalcCrc32(ChunkCrc, @ChunkSeqNo, SizeOf(ChunkSeqNo)); - CalcCrc32(ChunkCrc, Frame.IDATMemory.Memory, Frame.IDATMemory.Size); - ChunkCrc := SwapEndianLongWord(ChunkCrc xor $FFFFFFFF); - // Write out all fdAT data - GetIO.Write(Handle, @Chunk, SizeOf(Chunk)); - GetIO.Write(Handle, @ChunkSeqNo, SizeOf(ChunkSeqNo)); - GetIO.Write(Handle, Frame.IDATMemory.Memory, Frame.IDATMemory.Size); - GetIO.Write(Handle, @ChunkCrc, SizeOf(ChunkCrc)); - end; - - procedure WriteGlobalMetaDataChunks(Frame: TFrameInfo); - var - XRes, YRes: Single; - begin - if FileFormat.FMetadata.GetPhysicalPixelSize(ruDpm, XRes, YRes, True) then - begin - // Save pHYs chunk - Frame.pHYs.UnitSpecifier := 1; - // PNG stores physical resolution as dots per meter - Frame.pHYs.PixelsPerUnitX := Round(XRes); - Frame.pHYs.PixelsPerUnitY := Round(YRes); - - Chunk.DataSize := SizeOf(Frame.pHYs); - Chunk.ChunkID := pHYsChunk; - SwapEndianLongWord(@Frame.pHYs, SizeOf(Frame.pHYs) div SizeOf(LongWord)); - WriteChunk(Chunk, @Frame.pHYs); - end; - end; - - procedure WritePNGMainImageChunks(Frame: TFrameInfo); - begin - with Frame do - begin - // Write IHDR chunk - Chunk.DataSize := SizeOf(IHDR); - Chunk.ChunkID := IHDRChunk; - WriteChunk(Chunk, @IHDR); - // Write PLTE chunk if data is present - if Palette <> nil then - begin - Chunk.DataSize := PaletteEntries * SizeOf(TColor24Rec); - Chunk.ChunkID := PLTEChunk; - WriteChunk(Chunk, Palette); - end; - // Write tRNS chunk if data is present - if Transparency <> nil then - begin - Chunk.DataSize := TransparencySize; - Chunk.ChunkID := tRNSChunk; - WriteChunk(Chunk, Transparency); - end; - end; - // Write metadata related chunks - WriteGlobalMetaDataChunks(Frame); - end; - -begin - Result := False; - SeqNo := 0; - - case FileType of - ngPNG, ngAPNG: GetIO.Write(Handle, @PNGSignature, SizeOf(TChar8)); - ngMNG: GetIO.Write(Handle, @MNGSignature, SizeOf(TChar8)); - ngJNG: GetIO.Write(Handle, @JNGSignature, SizeOf(TChar8)); - end; - - if FileType = ngMNG then - begin - // MNG - main header before frames - SwapEndianLongWord(@MHDR, SizeOf(MHDR) div SizeOf(LongWord)); - Chunk.DataSize := SizeOf(MHDR); - Chunk.ChunkID := MHDRChunk; - WriteChunk(Chunk, @MHDR); - end - else if FileType = ngAPNG then - begin - // APNG - IHDR and global chunks for all frames, then acTL chunk, then frames - // (fcTL+IDAT, fcTL+fdAT, fcTL+fdAT, fcTL+fdAT, ....) - WritePNGMainImageChunks(Frames[0]); - - // Animation control chunk - acTL.NumFrames := Length(Frames); - if FileFormat.FMetadata.HasMetaItemForSaving(SMetaAnimationLoops) then - begin - // Number of plays of APNG animation - acTL.NumPlay:= FileFormat.FMetadata.MetaItemsForSaving[SMetaAnimationLoops]; - end - else - acTL.NumPlay := 0; - SwapEndianLongWord(@acTL, SizeOf(acTL) div SizeOf(LongWord)); - - Chunk.DataSize := SizeOf(acTL); - Chunk.ChunkID := acTLChunk; - WriteChunk(Chunk, @acTL); - end; - - for I := 0 to Length(Frames) - 1 do - with Frames[I] do - begin - if IsJpegFrame then - begin - // Write JHDR chunk - Chunk.DataSize := SizeOf(JHDR); - Chunk.ChunkID := JHDRChunk; - WriteChunk(Chunk, @JHDR); - // Write metadata related chunks - WriteGlobalMetaDataChunks(Frames[I]); - // Write JNG image data - Chunk.DataSize := JDATMemory.Size; - Chunk.ChunkID := JDATChunk; - WriteChunk(Chunk, JDATMemory.Memory); - // Write alpha channel if present - if JHDR.AlphaSampleDepth > 0 then - begin - if JHDR.AlphaCompression = 0 then - begin - // Alpha is PNG compressed - Chunk.DataSize := IDATMemory.Size; - Chunk.ChunkID := IDATChunk; - WriteChunk(Chunk, IDATMemory.Memory); - end - else - begin - // Alpha is JNG compressed - Chunk.DataSize := JDAAMemory.Size; - Chunk.ChunkID := JDAAChunk; - WriteChunk(Chunk, JDAAMemory.Memory); - end; - end; - // Write image end - Chunk.DataSize := 0; - Chunk.ChunkID := IENDChunk; - WriteChunk(Chunk, nil); - end - else if FileType <> ngAPNG then - begin - // Regular PNG frame (single PNG image or MNG frame) - WritePNGMainImageChunks(Frames[I]); - // Write PNG image data - Chunk.DataSize := IDATMemory.Size; - Chunk.ChunkID := IDATChunk; - WriteChunk(Chunk, IDATMemory.Memory); - // Write image end - Chunk.DataSize := 0; - Chunk.ChunkID := IENDChunk; - WriteChunk(Chunk, nil); - end - else if FileType = ngAPNG then - begin - // APNG frame - Write fcTL before frame data - Chunk.DataSize := SizeOf(fcTL); - Chunk.ChunkID := fcTLChunk; - fcTl.SeqNumber := GetNextSeqNo; - WriteChunk(Chunk, @fcTL); - // Write data - IDAT for first frame and fdAT for following ones - if I = 0 then - begin - Chunk.DataSize := IDATMemory.Size; - Chunk.ChunkID := IDATChunk; - WriteChunk(Chunk, IDATMemory.Memory); - end - else - WritefdAT(Frames[I]); - // Write image end after last frame - if I = Length(Frames) - 1 then - begin - Chunk.DataSize := 0; - Chunk.ChunkID := IENDChunk; - WriteChunk(Chunk, nil); - end; - end; - end; - - if FileType = ngMNG then - begin - Chunk.DataSize := 0; - Chunk.ChunkID := MENDChunk; - WriteChunk(Chunk, nil); - end; -end; - -procedure TNGFileSaver.SetFileOptions; -begin - PreFilter := FileFormat.FPreFilter; - CompressLevel := FileFormat.FCompressLevel; - LossyAlpha := FileFormat.FLossyAlpha; - Quality := FileFormat.FQuality; - Progressive := FileFormat.FProgressive; - ZLibStrategy := FileFormat.FZLibStategy; -end; - -{ TAPNGAnimator class implementation } - -class procedure TAPNGAnimator.Animate(var Images: TDynImageDataArray; - const acTL: TacTL; const SrcFrames: array of TFrameInfo); -var - I, SrcIdx, Offset, Len: Integer; - DestFrames: TDynImageDataArray; - SrcCanvas, DestCanvas: TImagingCanvas; - PreviousCache: TImageData; - - function AnimatingNeeded: Boolean; - var - I: Integer; - begin - Result := False; - for I := 0 to Len - 1 do - with SrcFrames[I] do - begin - if (FrameWidth <> Integer(IHDR.Width)) or (FrameHeight <> Integer(IHDR.Height)) or (Len <> Integer(acTL.NumFrames)) or - (not ((fcTL.DisposeOp = DisposeOpNone) and (fcTL.BlendOp = BlendOpSource)) and - not ((fcTL.DisposeOp = DisposeOpBackground) and (fcTL.BlendOp = BlendOpSource)) and - not ((fcTL.DisposeOp = DisposeOpBackground) and (fcTL.BlendOp = BlendOpOver))) then - begin - Result := True; - Exit; - end; - end; - end; - -begin - Len := Length(SrcFrames); - if (Len = 0) or not AnimatingNeeded then - Exit; - - if (Len = Integer(acTL.NumFrames) + 1) and (SrcFrames[0].fcTL.Width = 0) then - begin - // If default image (stored in IDAT chunk) isn't part of animation we ignore it - Offset := 1; - Len := Len - 1; - end - else - Offset := 0; - - SetLength(DestFrames, Len); - DestCanvas := ImagingCanvases.FindBestCanvasForImage(Images[0]).Create; - SrcCanvas := ImagingCanvases.FindBestCanvasForImage(Images[0]).Create; - InitImage(PreviousCache); - NewImage(SrcFrames[0].IHDR.Width, SrcFrames[0].IHDR.Height, Images[0].Format, PreviousCache); - - for I := 0 to Len - 1 do - begin - SrcIdx := I + Offset; - NewImage(SrcFrames[SrcIdx].IHDR.Width, SrcFrames[SrcIdx].IHDR.Height, - Images[SrcIdx].Format, DestFrames[I]); - if DestFrames[I].Format = ifIndex8 then - Move(Images[SrcIdx].Palette^, DestFrames[I].Palette^, 256 * SizeOf(TColor32)); - DestCanvas.CreateForData(@DestFrames[I]); - - if (SrcFrames[SrcIdx].fcTL.DisposeOp = DisposeOpPrevious) and (SrcFrames[SrcIdx - 1].fcTL.DisposeOp <> DisposeOpPrevious) then - begin - // Cache current output buffer so we may return to it later (previous dispose op) - CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height, - PreviousCache, 0, 0); - end; - - if (I = 0) or (SrcIdx = 0) then - begin - // Clear whole frame with transparent black color (default for first frame) - DestCanvas.FillColor32 := pcClear; - DestCanvas.Clear; - end - else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpBackground then - begin - // Restore background color (clear) on previous frame's area and leave previous content outside of it - CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height, - DestFrames[I], 0, 0); - DestCanvas.FillColor32 := pcClear; - DestCanvas.FillRect(BoundsToRect(SrcFrames[SrcIdx - 1].fcTL.XOffset, SrcFrames[SrcIdx - 1].fcTL.YOffset, - SrcFrames[SrcIdx - 1].FrameWidth, SrcFrames[SrcIdx - 1].FrameHeight)); - end - else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpNone then - begin - // Clone previous frame - no change to output buffer - CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height, - DestFrames[I], 0, 0); - end - else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpPrevious then - begin - // Revert to previous frame (cached, can't just restore DestFrames[I - 2]) - CopyRect(PreviousCache, 0, 0, PreviousCache.Width, PreviousCache.Height, - DestFrames[I], 0, 0); - end; - - // Copy pixels or alpha blend them over - if SrcFrames[SrcIdx].fcTL.BlendOp = BlendOpSource then - begin - CopyRect(Images[SrcIdx], 0, 0, Images[SrcIdx].Width, Images[SrcIdx].Height, - DestFrames[I], SrcFrames[SrcIdx].fcTL.XOffset, SrcFrames[SrcIdx].fcTL.YOffset); - end - else if SrcFrames[SrcIdx].fcTL.BlendOp = BlendOpOver then - begin - SrcCanvas.CreateForData(@Images[SrcIdx]); - SrcCanvas.DrawAlpha(SrcCanvas.ClipRect, DestCanvas, - SrcFrames[SrcIdx].fcTL.XOffset, SrcFrames[SrcIdx].fcTL.YOffset); - end; - - FreeImage(Images[SrcIdx]); - end; - - DestCanvas.Free; - SrcCanvas.Free; - FreeImage(PreviousCache); - - // Assign dest frames to final output images - Images := DestFrames; -end; - -{ TNetworkGraphicsFileFormat class implementation } - -procedure TNetworkGraphicsFileFormat.Define; -begin - inherited; - FFeatures := [ffLoad, ffSave]; - - FPreFilter := NGDefaultPreFilter; - FCompressLevel := NGDefaultCompressLevel; - FLossyAlpha := NGDefaultLossyAlpha; - FLossyCompression := NGDefaultLossyCompression; - FQuality := NGDefaultQuality; - FProgressive := NGDefaultProgressive; - FZLibStategy := NGDefaultZLibStartegy; -end; - -procedure TNetworkGraphicsFileFormat.CheckOptionsValidity; -begin - // Just check if save options has valid values - if not (FPreFilter in [0..6]) then - FPreFilter := NGDefaultPreFilter; - if not (FCompressLevel in [0..9]) then - FCompressLevel := NGDefaultCompressLevel; - if not (FQuality in [1..100]) then - FQuality := NGDefaultQuality; -end; - -function TNetworkGraphicsFileFormat.GetSupportedFormats: TImageFormats; -begin - if FLossyCompression then - Result := NGLossyFormats - else - Result := NGLosslessFormats; -end; - -procedure TNetworkGraphicsFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if not FLossyCompression then - begin - // Convert formats for lossless compression - if Info.HasGrayChannel then - begin - if Info.HasAlphaChannel then - begin - if Info.BytesPerPixel <= 2 then - // Convert <= 16bit grayscale images with alpha to ifA8Gray8 - ConvFormat := ifA8Gray8 - else - // Convert > 16bit grayscale images with alpha to ifA16Gray16 - ConvFormat := ifA16Gray16 - end - else - // Convert grayscale images without alpha to ifGray16 - ConvFormat := ifGray16; - end - else - if Info.IsFloatingPoint then - // Convert floating point images to 64 bit ARGB (or RGB if no alpha) - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16B16G16R16, ifB16G16R16) - else if Info.HasAlphaChannel or Info.IsSpecial then - // Convert all other images with alpha or special images to A8R8G8B8 - ConvFormat := ifA8R8G8B8 - else - // Convert images without alpha to R8G8B8 - ConvFormat := ifR8G8B8; - end - else - begin - // Convert formats for lossy compression - if Info.HasGrayChannel then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8Gray8, ifGray8) - else - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8); - end; - - ConvertImage(Image, ConvFormat); -end; - -function TNetworkGraphicsFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - ReadCount: LongInt; - Sig: TChar8; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - FillChar(Sig, SizeOf(Sig), 0); - ReadCount := Read(Handle, @Sig, SizeOf(Sig)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(Sig)) and (Sig = FSignature); - end; -end; - -{ TPNGFileFormat class implementation } - -procedure TPNGFileFormat.Define; -begin - inherited; - FName := SPNGFormatName; - FFeatures := FFeatures + [ffMultiImage]; - FLoadAnimated := PNGDefaultLoadAnimated; - AddMasks(SPNGMasks); - - FSignature := PNGSignature; - - RegisterOption(ImagingPNGPreFilter, @FPreFilter); - RegisterOption(ImagingPNGCompressLevel, @FCompressLevel); - RegisterOption(ImagingPNGLoadAnimated, @FLoadAnimated); - RegisterOption(ImagingPNGZLibStrategy, @FZLibStategy); -end; - -function TPNGFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - I, Len: LongInt; - NGFileLoader: TNGFileLoader; -begin - Result := False; - NGFileLoader := TNGFileLoader.Create(Self); - try - // Use NG file parser to load file - if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then - begin - Len := Length(NGFileLoader.Frames); - SetLength(Images, Len); - for I := 0 to Len - 1 do - with NGFileLoader.Frames[I] do - begin - // Build actual image bits - if not IsJpegFrame then - NGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight, IHDR, IDATMemory, Images[I]); - // Build palette, aply color key or background - - NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[I], Images[I]); - Result := True; - end; - // Animate APNG images - if (NGFileLoader.FileType = ngAPNG) and FLoadAnimated then - TAPNGAnimator.Animate(Images, NGFileLoader.acTL, NGFileLoader.Frames); - end; - finally - NGFileLoader.LoadMetaData; // Store metadata - NGFileLoader.Free; - end; -end; - -function TPNGFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - I: Integer; - ImageToSave: TImageData; - MustBeFreed: Boolean; - NGFileSaver: TNGFileSaver; - DefaultFormat: TImageFormat; - Screen: TImageData; - AnimWidth, AnimHeight: Integer; -begin - Result := False; - DefaultFormat := ifDefault; - AnimWidth := 0; - AnimHeight := 0; - NGFileSaver := TNGFileSaver.Create(Self); - - // Save images with more frames as APNG format - if Length(Images) > 1 then - begin - NGFileSaver.FileType := ngAPNG; - // Get max dimensions of frames - AnimWidth := Images[FFirstIdx].Width; - AnimHeight := Images[FFirstIdx].Height; - for I := FFirstIdx + 1 to FLastIdx do - begin - AnimWidth := Max(AnimWidth, Images[I].Width); - AnimHeight := Max(AnimHeight, Images[I].Height); - end; - end - else - NGFileSaver.FileType := ngPNG; - - NGFileSaver.SetFileOptions; - - with NGFileSaver do - try - // Store all frames to be saved frames file saver - for I := FFirstIdx to FLastIdx do - begin - if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then - try - if FileType = ngAPNG then - begin - // IHDR chunk is shared for all frames so all frames must have the - // same data format as the first image. - if I = FFirstIdx then - begin - DefaultFormat := ImageToSave.Format; - // Subsequenet frames may be bigger than the first one. - // APNG doens't support this - max allowed size is what's written in - // IHDR - size of main/default/first image. If some frame is - // bigger than the first one we need to resize (create empty bigger - // image and copy) the first frame so all following frames could fit to - // its area. - if (ImageToSave.Width <> AnimWidth) or (ImageToSave.Height <> AnimHeight) then - begin - InitImage(Screen); - NewImage(AnimWidth, AnimHeight, ImageToSave.Format, Screen); - CopyRect(ImageToSave, 0, 0, ImageToSave.Width, ImageToSave.Height, Screen, 0, 0); - if MustBeFreed then - FreeImage(ImageToSave); - ImageToSave := Screen; - end; - end - else if ImageToSave.Format <> DefaultFormat then - begin - if MustBeFreed then - ConvertImage(ImageToSave, DefaultFormat) - else - begin - CloneImage(Images[I], ImageToSave); - ConvertImage(ImageToSave, DefaultFormat); - MustBeFreed := True; - end; - end; - end; - - // Add image as PNG frame - AddFrame(ImageToSave, False); - finally - if MustBeFreed then - FreeImage(ImageToSave); - end - else - Exit; - end; - - // Finally save PNG file - SaveFile(Handle); - Result := True; - finally - NGFileSaver.Free; - end; -end; - -{$IFNDEF DONT_LINK_MNG} - -{ TMNGFileFormat class implementation } - -procedure TMNGFileFormat.Define; -begin - inherited; - FName := SMNGFormatName; - FFeatures := FFeatures + [ffMultiImage]; - AddMasks(SMNGMasks); - - FSignature := MNGSignature; - - RegisterOption(ImagingMNGLossyCompression, @FLossyCompression); - RegisterOption(ImagingMNGLossyAlpha, @FLossyAlpha); - RegisterOption(ImagingMNGPreFilter, @FPreFilter); - RegisterOption(ImagingMNGCompressLevel, @FCompressLevel); - RegisterOption(ImagingMNGQuality, @FQuality); - RegisterOption(ImagingMNGProgressive, @FProgressive); -end; - -function TMNGFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - NGFileLoader: TNGFileLoader; - I, Len: LongInt; -begin - Result := False; - NGFileLoader := TNGFileLoader.Create(Self); - try - // Use NG file parser to load file - if NGFileLoader.LoadFile(Handle) then - begin - Len := Length(NGFileLoader.Frames); - if Len > 0 then - begin - SetLength(Images, Len); - for I := 0 to Len - 1 do - with NGFileLoader.Frames[I] do - begin - // Build actual image bits - if IsJpegFrame then - NGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight, JHDR, IDATMemory, JDATMemory, JDAAMemory, Images[I]) - else - NGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight, IHDR, IDATMemory, Images[I]); - // Build palette, aply color key or background - NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[I], Images[I]); - end; - end - else - begin - // Some MNG files (with BASI-IEND streams) dont have actual pixel data - SetLength(Images, 1); - NewImage(NGFileLoader.MHDR.FrameWidth, NGFileLoader.MHDR.FrameWidth, ifDefault, Images[0]); - end; - Result := True; - end; - finally - NGFileLoader.LoadMetaData; // Store metadata - NGFileLoader.Free; - end; -end; - -function TMNGFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - NGFileSaver: TNGFileSaver; - I, LargestWidth, LargestHeight: LongInt; - ImageToSave: TImageData; - MustBeFreed: Boolean; -begin - Result := False; - LargestWidth := 0; - LargestHeight := 0; - - NGFileSaver := TNGFileSaver.Create(Self); - NGFileSaver.FileType := ngMNG; - NGFileSaver.SetFileOptions; - - with NGFileSaver do - try - // Store all frames to be saved frames file saver - for I := FFirstIdx to FLastIdx do - begin - if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then - try - // Add image as PNG or JNG frame - AddFrame(ImageToSave, FLossyCompression); - // Remember largest frame width and height - LargestWidth := Iff(LargestWidth < ImageToSave.Width, ImageToSave.Width, LargestWidth); - LargestHeight := Iff(LargestHeight < ImageToSave.Height, ImageToSave.Height, LargestHeight); - finally - if MustBeFreed then - FreeImage(ImageToSave); - end - else - Exit; - end; - - // Fill MNG header - MHDR.FrameWidth := LargestWidth; - MHDR.FrameHeight := LargestHeight; - MHDR.TicksPerSecond := 0; - MHDR.NominalLayerCount := 0; - MHDR.NominalFrameCount := Length(Frames); - MHDR.NominalPlayTime := 0; - MHDR.SimplicityProfile := 473; // 111011001 binary, defines MNG-VLC with transparency and JNG support - - // Finally save MNG file - SaveFile(Handle); - Result := True; - finally - NGFileSaver.Free; - end; -end; - -{$ENDIF} - -{$IFNDEF DONT_LINK_JNG} - -{ TJNGFileFormat class implementation } - -procedure TJNGFileFormat.Define; -begin - inherited; - FName := SJNGFormatName; - AddMasks(SJNGMasks); - - FSignature := JNGSignature; - FLossyCompression := True; - - RegisterOption(ImagingJNGLossyAlpha, @FLossyAlpha); - RegisterOption(ImagingJNGAlphaPreFilter, @FPreFilter); - RegisterOption(ImagingJNGAlphaCompressLevel, @FCompressLevel); - RegisterOption(ImagingJNGQuality, @FQuality); - RegisterOption(ImagingJNGProgressive, @FProgressive); - -end; - -function TJNGFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - NGFileLoader: TNGFileLoader; -begin - Result := False; - NGFileLoader := TNGFileLoader.Create(Self); - try - // Use NG file parser to load file - if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then - with NGFileLoader.Frames[0] do - begin - SetLength(Images, 1); - // Build actual image bits - if IsJpegFrame then - NGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight, JHDR, IDATMemory, JDATMemory, JDAAMemory, Images[0]); - // Build palette, aply color key or background - NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[0], Images[0]); - Result := True; - end; - finally - NGFileLoader.LoadMetaData; // Store metadata - NGFileLoader.Free; - end; -end; - -function TJNGFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - NGFileSaver: TNGFileSaver; - ImageToSave: TImageData; - MustBeFreed: Boolean; -begin - // Make image JNG compatible, store it in saver, and save it to file - Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed); - if Result then - begin - NGFileSaver := TNGFileSaver.Create(Self); - with NGFileSaver do - try - FileType := ngJNG; - SetFileOptions; - AddFrame(ImageToSave, True); - SaveFile(Handle); - finally - // Free NG saver and compatible image - NGFileSaver.Free; - if MustBeFreed then - FreeImage(ImageToSave); - end; - end; -end; - -{$ENDIF} - -initialization - RegisterImageFileFormat(TPNGFileFormat); -{$IFNDEF DONT_LINK_MNG} - RegisterImageFileFormat(TMNGFileFormat); -{$ENDIF} -{$IFNDEF DONT_LINK_JNG} - RegisterImageFileFormat(TJNGFileFormat); -{$ENDIF} -finalization - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77 Changes/Bug Fixes ----------------------------------- - - Reads and writes APNG animation loop count metadata. - - Writes frame delays of APNG from metadata. - - Fixed color keys in 8bit depth PNG/MNG loading. - - Fixed needless (and sometimes buggy) conversion to format with alpha - channel in FPC (GetMem(0) <> nil!). - - Added support for optional ZLib compression strategy. - - Added loading and saving of ifBinary (1bit black and white) - format images. During loading grayscale 1bpp and indexed 1bpp - (with only black and white colors in palette) are treated as ifBinary. - ifBinary are saved as 1bpp grayscale PNGs. - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Reads frame delays from APNG files into metadata. - - Added loading and saving of metadata from these chunks: pHYs. - - Simplified decoding of 1/2/4 bit images a bit (less code). - - -- 0.26.3 Changes/Bug Fixes --------------------------------- - - Added APNG saving support. - - Added APNG support to NG loader and animating to PNG loader. - - -- 0.26.1 Changes/Bug Fixes --------------------------------- - - Changed file format conditional compilation to reflect changes - in LINK symbols. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - Changes for better thread safety. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added loading of global palettes and transparencies in MNG files - (and by doing so fixed crash when loading images with global PLTE or tRNS). - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Small changes in converting to supported formats. - - MakeCompatible method moved to base class, put ConvertToSupported here. - GetSupportedFormats removed, it is now set in constructor. - - Made public properties for options registered to SetOption/GetOption - functions. - - Changed extensions to filename masks. - - Changed SaveData, LoadData, and MakeCompatible methods according - to changes in base class in Imaging unit. - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - MNG and JNG support added, PNG support redesigned to support NG file handlers - - added classes for working with NG file formats - - stuff from old ImagingPng unit added and that unit was deleted - - unit created and initial stuff added - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - when saving indexed images save alpha to tRNS? - - added some defines and ifdefs to dzlib unit to allow choosing - impaszlib, fpc's paszlib, zlibex or other zlib implementation - - added colorkeying support - - fixed 16bit channel image handling - pixels were not swapped - - fixed arithmetic overflow (in paeth filter) in FPC - - data of unknown chunks are skipped and not needlesly loaded - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - adaptive filtering added to PNG saving - - TPNGFileFormat class added -} - -end. diff --git a/3rd/Imaging/Source/ImagingOptions.inc b/3rd/Imaging/Source/ImagingOptions.inc deleted file mode 100644 index 36ffcae1b..000000000 --- a/3rd/Imaging/Source/ImagingOptions.inc +++ /dev/null @@ -1,214 +0,0 @@ -{ - User Options - Following defines and options can be changed by user. -} - -{ Source options } - -{$DEFINE USE_INLINE} // Use function inlining for some functions - // works in Free Pascal and Delphi 9+. -{$DEFINE USE_ASM} // Ff defined, assembler versions of some - // functions will be used (only for x86). - - // Debug options: If none of these two are defined - // your project settings are used. -{ $DEFINE IMAGING_DEBUG} // If defined, debug info, range/IO/overflow - // checking, stack frames, assertions, and - // other debugging options will be turned on. -{ $DEFINE IMAGING_RELEASE} // If defined, all debug info is off. - - - -(* File format support linking options. - Define formats which you don't want to be registred automatically. - Default: all formats are registered = no symbols defined. - Example: If you want to disable JPEG support just uncomment //{$DEFINE DONT_LINK_JPEG} line -*) - -//{$DEFINE DONT_LINK_JPEG} // link support for Jpeg images -//{$DEFINE DONT_LINK_PNG} // link support for PNG images -//{$DEFINE DONT_LINK_TARGA} // link support for Targa images -//{$DEFINE DONT_LINK_BITMAP} // link support for Windows Bitmap images -//{$DEFINE DONT_LINK_DDS} // link support for DDS images -//{$DEFINE DONT_LINK_GIF} // link support for GIF images -//{$DEFINE DONT_LINK_MNG} // link support for MNG images -//{$DEFINE DONT_LINK_JNG} // link support for JNG images -//{$DEFINE DONT_LINK_PNM} // link support for PortableMap images (PBM, PGM, PPM, PAM, PFM) -//{$DEFINE DONT_LINK_RADHDR} // link support for Radiance HDR/RGBE file format - -//{$DEFINE DONT_LINK_EXTRAS} // link support for file formats defined in - // Extras package. Exactly which formats will be - // registered depends on settings in - // ImagingExtras.pas unit. - -{ Component set used in ImagignComponents.pas unit. You usually don't need - to be concerned with this - proper component library is selected automatically - according to your compiler. } - -{$DEFINE COMPONENT_SET_VCL} // use Delphi VCL -{ $DEFINE COMPONENT_SET_LCL} // use Lazarus LCL (set automatically when compiling with FPC) - -{ - Auto Options - Following options and defines are set automatically and some - are required for Imaging to compile successfully. Do not change - anything here if you don't know what you are doing. -} - -{ Compiler options } - -{$ALIGN ON} // Field alignment: 8 Bytes (in D6+) -{$BOOLEVAL OFF} // Boolean eval: off -{$EXTENDEDSYNTAX ON} // Extended syntax: on -{$LONGSTRINGS ON} // string = AnsiString: on -{$MINENUMSIZE 4} // Min enum size: 4 B -{$TYPEDADDRESS OFF} // Typed pointers: off -{$WRITEABLECONST OFF} // Writeable constants: off - -{$IFNDEF FPC} - {$DEFINE DCC} // if not using FPC then DCC compiler is used (Delphi/BCB) - // others are not supported -{$ENDIF} - -{$IFDEF DCC} - {$DEFINE DELPHI} -{$ENDIF} - -{$IF (Defined(DCC) and (CompilerVersion >= 18.5))} - {$IFDEF RELEASE} - {$UNDEF DEBUG} // If we are using Delphi 2007+ where you can set - // DEBUG/RELEASE mode in project options and RELEASE - // is currently set we undef DEBUG mode - {$ENDIF} -{$IFEND} - -{$IF Defined(IMAGING_DEBUG)} - {$ASSERTIONS ON} - {$DEBUGINFO ON} - {$RANGECHECKS ON} - {$IOCHECKS ON} - {$OVERFLOWCHECKS ON} - {$IFDEF DCC} - {$OPTIMIZATION OFF} - {$STACKFRAMES ON} - {$LOCALSYMBOLS ON} - {$DEFINE MEMCHECK} - {$ENDIF} - {$IFDEF FPC} - {$S+} - {$CHECKPOINTER ON} - {$ENDIF} -{$ELSEIF Defined(IMAGING_RELEASE)} - {$ASSERTIONS OFF} - {$DEBUGINFO OFF} - {$RANGECHECKS OFF} - {$IOCHECKS OFF} - {$OVERFLOWCHECKS OFF} - {$IFDEF DCC} - {$OPTIMIZATION ON} - {$STACKFRAMES OFF} - {$LOCALSYMBOLS OFF} - {$ENDIF} - {$IFDEF FPC} - {$S-} - {$ENDIF} -{$IFEND} - -{$IF Defined (CPU86) and not Defined(CPUX86)} - {$DEFINE CPUX86} // Compatibility with Delphi -{$IFEND} - -{$IF Defined (CPUX86_64) and not Defined(CPUX64)} - {$DEFINE CPUX64} // Compatibility with Delphi -{$IFEND} - -{$IF Defined (DARWIN) and not Defined(MACOSX)} - {$DEFINE MACOS} // Compatibility with Delphi -{$IFEND} - -{$IF Defined(DCC) and (CompilerVersion < 23)} - {$DEFINE CPUX86} // Compatibility with older Delphi -{$IFEND} - -{ Compiler capabilities } - -// Define if compiler supports inlining of functions and procedures -{$IF (Defined(DCC) and (CompilerVersion >= 17)) or Defined(FPC)} - {$DEFINE HAS_INLINE} -{$IFEND} - -// Define if compiler supports advanced records with methods -{$IF (Defined(DCC) and (CompilerVersion >= 18)) or - (Defined(FPC) and (FPC_FULLVERSION >= 20600))} - {$DEFINE HAS_ADVANCED_RECORDS} -{$IFEND} - -// Define if compiler supports operator overloading -// (unfortunately Delphi and FPC operator overloading is not compatible). -// FPC supports Delphi compatible operator overloads since 2.6.0 -{$IF (Defined(DCC) and (CompilerVersion >= 18)) or - (Defined(FPC) and (FPC_FULLVERSION >= 20600))} - {$DEFINE HAS_OPERATOR_OVERLOADING} -{$IFEND} - -// Anonymous methods -{$IF Defined(DCC) and (CompilerVersion >= 20) } - {$DEFINE HAS_ANON_METHODS} -{$IFEND} - -// Generic types (Delphi and FPC implementations incompatible). -// Update: FPC supports Delphi compatible generics since 2.6.0 -{$IF (Defined(DCC) and (CompilerVersion >= 20)) or - (Defined(FPC) and (FPC_FULLVERSION >= 20600))} - {$DEFINE HAS_GENERICS} -{$IFEND} - -{ Imaging options check} - -{$IFNDEF HAS_INLINE} - {$UNDEF USE_INLINE} -{$ENDIF} - -{$IF not Defined(CPUX86)} - {$UNDEF USE_ASM} -{$IFEND} - -{$IFDEF FPC} - {$DEFINE COMPONENT_SET_LCL} - {$UNDEF COMPONENT_SET_VCL} -{$ENDIF} - -{$IFDEF DELPHI} - {$UNDEF COMPONENT_SET_LCL} - {$DEFINE COMPONENT_SET_VCL} -{$ENDIF} - -{ Platform options } - -{$IF Defined(WIN32) or Defined(WIN64)} - {$DEFINE MSWINDOWS} -{$IFEND} - -{$IFDEF LINUX} - {$DEFINE UNIX} -{$ENDIF} - -{ More compiler options } - -{$IFDEF FPC} // Free Pascal options - some options set above (like min enum size) - // are reset to defaults by setting {$MODE} so they are - // redeclared here - {$MODE DELPHI} // compatible with delphi - {$GOTO ON} // alow goto - {$PACKRECORDS 8} // same as ALING 8 for Delphi - {$PACKENUM 4} // Min enum size: 4 B - {$IFDEF CPU86} - {$ASMMODE INTEL} // intel assembler mode - {$ENDIF} -{$ENDIF} - -{$IFDEF HAS_INLINE} - {$INLINE ON} // turns inlining on for compilers that support it -{$ENDIF} - - diff --git a/3rd/Imaging/Source/ImagingPortableMaps.pas b/3rd/Imaging/Source/ImagingPortableMaps.pas deleted file mode 100644 index 531c1b277..000000000 --- a/3rd/Imaging/Source/ImagingPortableMaps.pas +++ /dev/null @@ -1,977 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains loader/saver for Portable Maps file format family (or PNM). - That includes PBM, PGM, PPM, PAM, and PFM formats.} -unit ImagingPortableMaps; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, ImagingTypes, Imaging, ImagingFormats, ImagingUtility; - -type - { Types of pixels of PNM images.} - TTupleType = (ttInvalid, ttBlackAndWhite, ttGrayScale, ttRGB, ttBlackAndWhiteAlpha, - ttGrayScaleAlpha, ttRGBAlpha, ttGrayScaleFP, ttRGBFP); - - { Record with info about PNM image used in both loading and saving functions.} - TPortableMapInfo = record - Width: LongInt; - Height: LongInt; - FormatId: AnsiChar; - MaxVal: LongInt; - BitCount: LongInt; - Depth: LongInt; - TupleType: TTupleType; - Binary: Boolean; - HasPAMHeader: Boolean; - IsBigEndian: Boolean; - end; - - { Base class for Portable Map file formats (or Portable AnyMaps or PNM). - There are several types of PNM file formats that share common - (simple) structure. This class can actually load all supported PNM formats. - Saving is also done by this class but descendants (each for different PNM - format) control it.} - TPortableMapFileFormat = class(TImageFileFormat) - protected - FIdNumbers: TChar2; - FSaveBinary: LongBool; - FUSFormat: TFormatSettings; - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveDataInternal(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt; var MapInfo: TPortableMapInfo): Boolean; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - published - { If set to True images will be saved in binary format. If it is False - they will be saved in text format (which could result in 5-10x bigger file). - Default is value True. Note that PAM and PFM files are always saved in binary.} - property SaveBinary: LongBool read FSaveBinary write FSaveBinary; - end; - - { Portable Bit Map is used to store monochrome 1bit images. Raster data - can be saved as text or binary data. Either way value of 0 represents white - and 1 is black. As Imaging does not have support for 1bit data formats - PBM images can be loaded but not saved. Loaded images are returned in - ifGray8 format (witch pixel values scaled from 1bit to 8bit).} - TPBMFileFormat = class(TPortableMapFileFormat) - protected - procedure Define; override; - end; - - { Portable Gray Map is used to store grayscale 8bit or 16bit images. - Raster data can be saved as text or binary data.} - TPGMFileFormat = class(TPortableMapFileFormat) - protected - procedure Define; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - end; - - { Portable Pixel Map is used to store RGB images with 8bit or 16bit channels. - Raster data can be saved as text or binary data.} - TPPMFileFormat = class(TPortableMapFileFormat) - protected - procedure Define; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - end; - - { Portable Arbitrary Map is format that can store image data formats - of PBM, PGM, and PPM formats with optional alpha channel. Raster data - can be stored only in binary format. All data formats supported - by this format are ifGray8, ifGray16, ifA8Gray8, ifA16Gray16, - ifR8G8B8, ifR16G16R16, ifA8R8G8B8, and ifA16R16G16B16.} - TPAMFileFormat = class(TPortableMapFileFormat) - protected - procedure Define; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - end; - - { Portable Float Map is unofficial extension of PNM format family which - can store images with floating point pixels. Raster data is saved in - binary format as array of IEEE 32 bit floating point numbers. One channel - or RGB images are supported by PFM format (so no alpha).} - TPFMFileFormat = class(TPortableMapFileFormat) - protected - procedure Define; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - end; - -implementation - -const - PortableMapDefaultBinary = True; - - SPBMFormatName = 'Portable Bit Map'; - SPBMMasks = '*.pbm'; - SPGMFormatName = 'Portable Gray Map'; - SPGMMasks = '*.pgm'; - PGMSupportedFormats = [ifGray8, ifGray16]; - SPPMFormatName = 'Portable Pixel Map'; - SPPMMasks = '*.ppm'; - PPMSupportedFormats = [ifR8G8B8, ifR16G16B16]; - SPAMFormatName = 'Portable Arbitrary Map'; - SPAMMasks = '*.pam'; - PAMSupportedFormats = [ifGray8, ifGray16, ifA8Gray8, ifA16Gray16, - ifR8G8B8, ifR16G16B16, ifA8R8G8B8, ifA16R16G16B16]; - SPFMFormatName = 'Portable Float Map'; - SPFMMasks = '*.pfm'; - PFMSupportedFormats = [ifR32F, ifB32G32R32F]; - -const - { TAB, CR, LF, and Space are used as seperators in Portable map headers and data.} - WhiteSpaces = [#9, #10, #13, #32]; - SPAMWidth = 'WIDTH'; - SPAMHeight = 'HEIGHT'; - SPAMDepth = 'DEPTH'; - SPAMMaxVal = 'MAXVAL'; - SPAMTupleType = 'TUPLTYPE'; - SPAMEndHdr = 'ENDHDR'; - - { Size of buffer used to speed up text PNM loading/saving.} - LineBufferCapacity = 16 * 1024; - - TupleTypeNames: array[TTupleType] of string = ( - 'INVALID', 'BLACKANDWHITE', 'GRAYSCALE', 'RGB', - 'BLACKANDWHITE_ALPHA', 'GRAYSCALE_ALPHA', 'RGB_ALPHA', 'GRAYSCALEFP', - 'RGBFP'); - -{ TPortableMapFileFormat } - -procedure TPortableMapFileFormat.Define; -begin - inherited; - FFeatures := [ffLoad, ffSave]; - FSaveBinary := PortableMapDefaultBinary; - FUSFormat := GetFormatSettingsForFloats; -end; - -function TPortableMapFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - I, ScanLineSize, MonoSize: LongInt; - Dest: PByte; - MonoData: Pointer; - Info: TImageFormatInfo; - LineBuffer: array[0..LineBufferCapacity - 1] of AnsiChar; - LineEnd, LinePos: LongInt; - MapInfo: TPortableMapInfo; - LineBreak: string; - - procedure CheckBuffer; - begin - if (LineEnd = 0) or (LinePos = LineEnd) then - begin - // Reload buffer if its is empty or its end was reached - LineEnd := GetIO.Read(Handle, @LineBuffer[0], LineBufferCapacity); - LinePos := 0; - end; - end; - - procedure FixInputPos; - begin - // Sets input's position to its real pos as it would be without buffering - if LineEnd > 0 then - begin - GetIO.Seek(Handle, -LineEnd + LinePos, smFromCurrent); - LineEnd := 0; - end; - end; - - function ReadString: string; - var - S: AnsiString; - C: AnsiChar; - begin - // First skip all whitespace chars - SetLength(S, 1); - repeat - CheckBuffer; - S[1] := LineBuffer[LinePos]; - Inc(LinePos); - if S[1] = '#' then - repeat - // Comment detected, skip everything until next line is reached - CheckBuffer; - S[1] := LineBuffer[LinePos]; - Inc(LinePos); - until S[1] = #10; - until not(S[1] in WhiteSpaces); - // Now we have reached some chars other than white space, read them until - // there is whitespace again - repeat - SetLength(S, Length(S) + 1); - CheckBuffer; - S[Length(S)] := LineBuffer[LinePos]; - Inc(LinePos); - // Repeat until current char is whitespace or end of file is reached - // (Line buffer has 0 bytes which happens only on EOF) - until (S[Length(S)] in WhiteSpaces) or (LineEnd = 0); - // Get rid of last char - whitespace or null - SetLength(S, Length(S) - 1); - // Move position to the beginning of next string (skip white space - needed - // to make the loader stop at the right input position) - repeat - CheckBuffer; - C := LineBuffer[LinePos]; - Inc(LinePos); - until not (C in WhiteSpaces) or (LineEnd = 0); - // Dec pos, current is the begining of the the string - Dec(LinePos); - - Result := string(S); - end; - - function ReadIntValue: LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} - begin - Result := StrToInt(ReadString); - end; - - procedure FindLineBreak; - var - C: AnsiChar; - begin - LineBreak := #10; - repeat - CheckBuffer; - C := LineBuffer[LinePos]; - Inc(LinePos); - - if C = #13 then - LineBreak := #13#10; - - until C = #10; - end; - - function ParseHeader: Boolean; - var - Id: TChar2; - I: TTupleType; - TupleTypeName: string; - Scale: Single; - begin - Result := False; - with GetIO do - begin - FillChar(MapInfo, SizeOf(MapInfo), 0); - Read(Handle, @Id, SizeOf(Id)); - FindLineBreak; - - if Id[1] in ['1'..'6'] then - begin - // Read header for PBM, PGM, and PPM files - MapInfo.Width := ReadIntValue; - MapInfo.Height := ReadIntValue; - - if Id[1] in ['1', '4'] then - begin - MapInfo.MaxVal := 1; - MapInfo.BitCount := 1 - end - else - begin - // Read channel max value, <=255 for 8bit images, >255 for 16bit images - // but some programs think its max colors so put <=256 here - MapInfo.MaxVal := ReadIntValue; - MapInfo.BitCount := Iff(MapInfo.MaxVal <= 256, 8, 16); - end; - - MapInfo.Depth := 1; - case Id[1] of - '1', '4': MapInfo.TupleType := ttBlackAndWhite; - '2', '5': MapInfo.TupleType := ttGrayScale; - '3', '6': - begin - MapInfo.TupleType := ttRGB; - MapInfo.Depth := 3; - end; - end; - end - else if Id[1] = '7' then - begin - // Read values from PAM header - // WIDTH - if (ReadString <> SPAMWidth) then Exit; - MapInfo.Width := ReadIntValue; - // HEIGHT - if (ReadString <> SPAMheight) then Exit; - MapInfo.Height := ReadIntValue; - // DEPTH - if (ReadString <> SPAMDepth) then Exit; - MapInfo.Depth := ReadIntValue; - // MAXVAL - if (ReadString <> SPAMMaxVal) then Exit; - MapInfo.MaxVal := ReadIntValue; - MapInfo.BitCount := Iff(MapInfo.MaxVal <= 256, 8, 16); - // TUPLETYPE - if (ReadString <> SPAMTupleType) then Exit; - TupleTypeName := ReadString; - for I := Low(TTupleType) to High(TTupleType) do - if SameText(TupleTypeName, TupleTypeNames[I]) then - begin - MapInfo.TupleType := I; - Break; - end; - // ENDHDR - if (ReadString <> SPAMEndHdr) then Exit; - end - else if Id[1] in ['F', 'f'] then - begin - // Read header of PFM file - MapInfo.Width := ReadIntValue; - MapInfo.Height := ReadIntValue; - Scale := StrToFloatDef(ReadString, 0, FUSFormat); - MapInfo.IsBigEndian := Scale > 0.0; - if Id[1] = 'F' then - MapInfo.TupleType := ttRGBFP - else - MapInfo.TupleType := ttGrayScaleFP; - MapInfo.Depth := Iff(MapInfo.TupleType = ttRGBFP, 3, 1); - MapInfo.BitCount := Iff(MapInfo.TupleType = ttRGBFP, 96, 32); - end; - - FixInputPos; - MapInfo.Binary := (Id[1] in ['4', '5', '6', '7', 'F', 'f']); - - if MapInfo.Binary and not (Id[1] in ['F', 'f']) then - begin - // Mimic the behaviour of Photoshop and other editors/viewers: - // If linenreaks in file are DOS CR/LF 16bit binary values are - // little endian, Unix LF only linebreak indicates big endian. - MapInfo.IsBigEndian := LineBreak = #10; - end; - - // Check if values found in header are valid - Result := (MapInfo.Width > 0) and (MapInfo.Height > 0) and - (MapInfo.BitCount in [1, 8, 16, 32, 96]) and (MapInfo.TupleType <> ttInvalid); - // Now check if image has proper number of channels (PAM) - if Result then - case MapInfo.TupleType of - ttBlackAndWhite, ttGrayScale: Result := MapInfo.Depth = 1; - ttBlackAndWhiteAlpha, ttGrayScaleAlpha: Result := MapInfo.Depth = 2; - ttRGB: Result := MapInfo.Depth = 3; - ttRGBAlpha: Result := MapInfo.Depth = 4; - end; - end; - end; - -begin - Result := False; - LineEnd := 0; - LinePos := 0; - SetLength(Images, 1); - - with GetIO, Images[0] do - begin - Format := ifUnknown; - // Try to parse file header - if not ParseHeader then Exit; - // Select appropriate data format based on values read from file header - case MapInfo.TupleType of - ttBlackAndWhite: Format := ifGray8; - ttBlackAndWhiteAlpha: Format := ifA8Gray8; - ttGrayScale: Format := IffFormat(MapInfo.BitCount = 8, ifGray8, ifGray16); - ttGrayScaleAlpha: Format := IffFormat(MapInfo.BitCount = 8, ifA8Gray8, ifA16Gray16); - ttRGB: Format := IffFormat(MapInfo.BitCount = 8, ifR8G8B8, ifR16G16B16); - ttRGBAlpha: Format := IffFormat(MapInfo.BitCount = 8, ifA8R8G8B8, ifA16R16G16B16); - ttGrayScaleFP: Format := ifR32F; - ttRGBFP: Format := ifB32G32R32F; - end; - // Exit if no matching data format was found - if Format = ifUnknown then Exit; - - NewImage(MapInfo.Width, MapInfo.Height, Format, Images[0]); - Info := GetFormatInfo(Format); - - // Now read pixels from file to dest image - if not MapInfo.Binary then - begin - Dest := Bits; - for I := 0 to Width * Height - 1 do - begin - case Format of - ifGray8: - begin - Dest^ := ReadIntValue; - if MapInfo.BitCount = 1 then - // If source is 1bit mono image (where 0=white, 1=black) - // we must scale it to 8bits - Dest^ := 255 - Dest^ * 255; - end; - ifGray16: PWord(Dest)^ := ReadIntValue; - ifR8G8B8: - with PColor24Rec(Dest)^ do - begin - R := ReadIntValue; - G := ReadIntValue; - B := ReadIntValue; - end; - ifR16G16B16: - with PColor48Rec(Dest)^ do - begin - R := ReadIntValue; - G := ReadIntValue; - B := ReadIntValue; - end; - end; - Inc(Dest, Info.BytesPerPixel); - end; - end - else - begin - if MapInfo.BitCount > 1 then - begin - if not (MapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then - begin - // Just copy bytes from binary Portable Maps (non 1bit, non FP) - Read(Handle, Bits, Size); - end - else - begin - Dest := Bits; - // FP images are in BGR order and endian swap maybe needed. - // Some programs store scanlines in bottom-up order but - // I will stick with Photoshops behaviour here - Read(Handle, Bits, Size); - if MapInfo.IsBigEndian then - SwapEndianLongWord(PLongWord(Dest), Size div SizeOf(LongWord)); - end; - - if MapInfo.TupleType in [ttBlackAndWhite, ttBlackAndWhiteAlpha] then - begin - // Black and white PAM files must be scaled to 8bits. Note that - // in PAM files 1=white, 0=black (reverse of PBM) - for I := 0 to Width * Height * Iff(MapInfo.TupleType = ttBlackAndWhiteAlpha, 2, 1) - 1 do - PByteArray(Bits)[I] := PByteArray(Bits)[I] * 255; - end - else if MapInfo.TupleType in [ttRGB, ttRGBAlpha] then - begin - // Swap channels of RGB/ARGB images. Binary RGB image files use BGR order. - SwapChannels(Images[0], ChannelBlue, ChannelRed); - end; - - // Swap byte order if needed - if (MapInfo.BitCount = 16) and MapInfo.IsBigEndian then - SwapEndianWord(Bits, Width * Height * Info.BytesPerPixel div SizeOf(Word)); - end - else - begin - // Handle binary PBM files (ttBlackAndWhite 1bit) - ScanLineSize := (Width + 7) div 8; - // Get total binary data size, read it from file to temp - // buffer and convert the data to Gray8 - MonoSize := ScanLineSize * Height; - GetMem(MonoData, MonoSize); - try - Read(Handle, MonoData, MonoSize); - Convert1To8(MonoData, Bits, Width, Height, ScanLineSize, False); - // 1bit mono images must be scaled to 8bit, but inverted (where 0=white, 1=black) - for I := 0 to Width * Height - 1 do - PByteArray(Bits)[I] := 255 - PByteArray(Bits)[I] * 255; - finally - FreeMem(MonoData); - end; - end; - end; - - FixInputPos; - - if (MapInfo.MaxVal <> Pow2Int(MapInfo.BitCount) - 1) and - (MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha, ttRGB, ttRGBAlpha]) then - begin - Dest := Bits; - // Scale color values according to MaxVal we got from header - // if necessary. - for I := 0 to Width * Height * Info.BytesPerPixel div (MapInfo.BitCount shr 3) - 1 do - begin - if MapInfo.BitCount = 8 then - Dest^ := Dest^ * 255 div MapInfo.MaxVal - else - PWord(Dest)^ := PWord(Dest)^ * 65535 div MapInfo.MaxVal; - Inc(Dest, MapInfo.BitCount shr 3); - end; - end; - - Result := True; - end; -end; - -function TPortableMapFileFormat.SaveDataInternal(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer; var MapInfo: TPortableMapInfo): Boolean; -const - // Use Unix linebreak, for many viewers/editors it means that - // 16bit samples are stored as big endian - so we need to swap byte order - // before saving - LineDelimiter = #10; - PixelDelimiter = #32; -var - ImageToSave: TImageData; - MustBeFreed: Boolean; - Info: TImageFormatInfo; - I, LineLength: LongInt; - Src: PByte; - Pixel32: TColor32Rec; - Pixel64: TColor64Rec; - W: Word; - - procedure WriteString(S: string; Delimiter: Char = LineDelimiter); - begin - SetLength(S, Length(S) + 1); - S[Length(S)] := Delimiter; - {$IF Defined(DCC) and Defined(UNICODE)} - GetIO.Write(Handle, @AnsiString(S)[1], Length(S)); - {$ELSE} - GetIO.Write(Handle, @S[1], Length(S)); - {$IFEND} - Inc(LineLength, Length(S)); - end; - - procedure WriteHeader; - begin - WriteString('P' + MapInfo.FormatId); - if not MapInfo.HasPAMHeader then - begin - // Write header of PGM, PPM, and PFM files - WriteString(IntToStr(ImageToSave.Width)); - WriteString(IntToStr(ImageToSave.Height)); - case MapInfo.TupleType of - ttGrayScale, ttRGB: WriteString(IntToStr(Pow2Int(MapInfo.BitCount) - 1)); - ttGrayScaleFP, ttRGBFP: - begin - // Negative value indicates that raster data is saved in little endian - WriteString(FloatToStr(-1.0, FUSFormat)); - end; - end; - end - else - begin - // Write PAM file header - WriteString(Format('%s %d', [SPAMWidth, ImageToSave.Width])); - WriteString(Format('%s %d', [SPAMHeight, ImageToSave.Height])); - WriteString(Format('%s %d', [SPAMDepth, MapInfo.Depth])); - WriteString(Format('%s %d', [SPAMMaxVal, Pow2Int(MapInfo.BitCount) - 1])); - WriteString(Format('%s %s', [SPAMTupleType, TupleTypeNames[MapInfo.TupleType]])); - WriteString(SPAMEndHdr); - end; - end; - -begin - Result := False; - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - Info := GetFormatInfo(Format); - // Fill values of MapInfo record that were not filled by - // descendants in their SaveData methods - MapInfo.BitCount := (Info.BytesPerPixel div Info.ChannelCount) * 8; - MapInfo.Depth := Info.ChannelCount; - if MapInfo.TupleType = ttInvalid then - begin - if Info.HasGrayChannel then - begin - if Info.HasAlphaChannel then - MapInfo.TupleType := ttGrayScaleAlpha - else - MapInfo.TupleType := ttGrayScale; - end - else - begin - if Info.HasAlphaChannel then - MapInfo.TupleType := ttRGBAlpha - else - MapInfo.TupleType := ttRGB; - end; - end; - // Write file header - WriteHeader; - - if not MapInfo.Binary then - begin - Src := Bits; - LineLength := 0; - // For each pixel find its text representation and write it to file - for I := 0 to Width * Height - 1 do - begin - case Format of - ifGray8: WriteString(IntToStr(Src^), PixelDelimiter); - ifGray16: WriteString(IntToStr(PWord(Src)^), PixelDelimiter); - ifR8G8B8: - with PColor24Rec(Src)^ do - WriteString(SysUtils.Format('%d %d %d', [R, G, B]), PixelDelimiter); - ifR16G16B16: - with PColor48Rec(Src)^ do - WriteString(SysUtils.Format('%d %d %d', [R, G, B]), PixelDelimiter); - end; - // Lines in text PNM images should have length <70 - if LineLength > 65 then - begin - LineLength := 0; - WriteString('', LineDelimiter); - end; - Inc(Src, Info.BytesPerPixel); - end; - end - else - begin - // Write binary images - if not (MapInfo.TupleType in [ttGrayScaleFP, ttRGBFP]) then - begin - // Save integer binary images - if MapInfo.BitCount = 8 then - begin - if MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then - begin - // 8bit grayscale images can be written in one Write call - Write(Handle, Bits, Size); - end - else - begin - // 8bit RGB/ARGB images: red and blue must be swapped and - // 3 or 4 bytes must be written - Src := Bits; - for I := 0 to Width * Height - 1 do - with PColor32Rec(Src)^ do - begin - if MapInfo.TupleType = ttRGBAlpha then - Pixel32.A := A; - Pixel32.R := B; - Pixel32.G := G; - Pixel32.B := R; - Write(Handle, @Pixel32, Info.BytesPerPixel); - Inc(Src, Info.BytesPerPixel); - end; - end; - end - else - begin - // Images with 16bit channels: make sure that channel values are saved in big endian - Src := Bits; - if MapInfo.TupleType in [ttGrayScale, ttGrayScaleAlpha] then - begin - // 16bit grayscale image - for I := 0 to Width * Height * Info.BytesPerPixel div SizeOf(Word) - 1 do - begin - W := SwapEndianWord(PWord(Src)^); - Write(Handle, @W, SizeOf(Word)); - Inc(Src, SizeOf(Word)); - end; - end - else - begin - // RGB images with 16bit channels: swap RB and endian too - for I := 0 to Width * Height - 1 do - with PColor64Rec(Src)^ do - begin - if MapInfo.TupleType = ttRGBAlpha then - Pixel64.A := SwapEndianWord(A); - Pixel64.R := SwapEndianWord(B); - Pixel64.G := SwapEndianWord(G); - Pixel64.B := SwapEndianWord(R); - Write(Handle, @Pixel64, Info.BytesPerPixel); - Inc(Src, Info.BytesPerPixel); - end; - end; - end; - end - else - begin - // Floating point images (no need to swap endian here - little - // endian is specified in file header) - Write(Handle, Bits, Size); - end; - end; - Result := True; - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -function TPortableMapFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Id: TChar4; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - with GetIO do - begin - ReadCount := Read(Handle, @Id, SizeOf(Id)); - Seek(Handle, -ReadCount, smFromCurrent); - Result := (Id[0] = 'P') and (Id[1] in [FIdNumbers[0], FIdNumbers[1]]) and - (Id[2] in WhiteSpaces); - end; -end; - -{ TPBMFileFormat } - -procedure TPBMFileFormat.Define; -begin - inherited; - FName := SPBMFormatName; - FFeatures := [ffLoad]; - AddMasks(SPBMMasks); - FIdNumbers := '14'; -end; - -{ TPGMFileFormat } - -procedure TPGMFileFormat.Define; -begin - inherited; - FName := SPGMFormatName; - FSupportedFormats := PGMSupportedFormats; - AddMasks(SPGMMasks); - RegisterOption(ImagingPGMSaveBinary, @FSaveBinary); - FIdNumbers := '25'; -end; - -function TPGMFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -var - MapInfo: TPortableMapInfo; -begin - FillChar(MapInfo, SizeOf(MapInfo), 0); - if FSaveBinary then - MapInfo.FormatId := FIdNumbers[1] - else - MapInfo.FormatId := FIdNumbers[0]; - MapInfo.Binary := FSaveBinary; - Result := SaveDataInternal(Handle, Images, Index, MapInfo); -end; - -procedure TPGMFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsFloatingPoint then - // All FP images go to 16bit - ConvFormat := ifGray16 - else if Info.HasGrayChannel then - // Grayscale will be 8 or 16 bit - depends on input's bitcount - ConvFormat := IffFormat(Info.BytesPerPixel div Info.ChannelCount > 1, - ifGray16, ifGray8) - else if Info.BytesPerPixel > 4 then - // Large bitcounts -> 16bit - ConvFormat := ifGray16 - else - // Rest of the formats -> 8bit - ConvFormat := ifGray8; - - ConvertImage(Image, ConvFormat); -end; - -{ TPPMFileFormat } - -procedure TPPMFileFormat.Define; -begin - inherited; - FName := SPPMFormatName; - FSupportedFormats := PPMSupportedFormats; - AddMasks(SPPMMasks); - RegisterOption(ImagingPPMSaveBinary, @FSaveBinary); - FIdNumbers := '36'; -end; - -function TPPMFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -var - MapInfo: TPortableMapInfo; -begin - FillChar(MapInfo, SizeOf(MapInfo), 0); - if FSaveBinary then - MapInfo.FormatId := FIdNumbers[1] - else - MapInfo.FormatId := FIdNumbers[0]; - MapInfo.Binary := FSaveBinary; - Result := SaveDataInternal(Handle, Images, Index, MapInfo); -end; - -procedure TPPMFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsFloatingPoint then - // All FP images go to 48bit RGB - ConvFormat := ifR16G16B16 - else if Info.HasGrayChannel then - // Grayscale will be 24 or 48 bit RGB - depends on input's bitcount - ConvFormat := IffFormat(Info.BytesPerPixel div Info.ChannelCount > 1, - ifR16G16B16, ifR8G8B8) - else if Info.BytesPerPixel > 4 then - // Large bitcounts -> 48bit RGB - ConvFormat := ifR16G16B16 - else - // Rest of the formats -> 24bit RGB - ConvFormat := ifR8G8B8; - - ConvertImage(Image, ConvFormat); -end; - -{ TPAMFileFormat } - -procedure TPAMFileFormat.Define; -begin - inherited; - FName := SPAMFormatName; - FSupportedFormats := PAMSupportedFormats; - AddMasks(SPAMMasks); - FIdNumbers := '77'; -end; - -function TPAMFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -var - MapInfo: TPortableMapInfo; -begin - FillChar(MapInfo, SizeOf(MapInfo), 0); - MapInfo.FormatId := FIdNumbers[0]; - MapInfo.Binary := True; - MapInfo.HasPAMHeader := True; - Result := SaveDataInternal(Handle, Images, Index, MapInfo); -end; - -procedure TPAMFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.IsFloatingPoint then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16) - else if Info.HasGrayChannel then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16Gray16, ifGray16) - else - begin - if Info.BytesPerPixel <= 4 then - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8) - else - ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16R16G16B16, ifR16G16B16); - end; - ConvertImage(Image, ConvFormat); -end; - -{ TPFMFileFormat } - -procedure TPFMFileFormat.Define; -begin - inherited; - FName := SPFMFormatName; - AddMasks(SPFMMasks); - FIdNumbers := 'Ff'; - FSupportedFormats := PFMSupportedFormats; -end; - -function TPFMFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -var - Info: TImageFormatInfo; - MapInfo: TPortableMapInfo; -begin - FillChar(MapInfo, SizeOf(MapInfo), 0); - Info := GetFormatInfo(Images[Index].Format); - - if (Info.ChannelCount > 1) or Info.IsIndexed then - MapInfo.TupleType := ttRGBFP - else - MapInfo.TupleType := ttGrayScaleFP; - - if MapInfo.TupleType = ttGrayScaleFP then - MapInfo.FormatId := FIdNumbers[1] - else - MapInfo.FormatId := FIdNumbers[0]; - - MapInfo.Binary := True; - Result := SaveDataInternal(Handle, Images, Index, MapInfo); -end; - -procedure TPFMFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin - if (Info.ChannelCount > 1) or Info.IsIndexed then - ConvertImage(Image, ifB32G32R32F) - else - ConvertImage(Image, ifR32F); -end; - -initialization - RegisterImageFileFormat(TPBMFileFormat); - RegisterImageFileFormat(TPGMFileFormat); - RegisterImageFileFormat(TPPMFileFormat); - RegisterImageFileFormat(TPAMFileFormat); - RegisterImageFileFormat(TPFMFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 Changes/Bug Fixes ----------------------------------- - - Native RGB floating point format of PFM is now supported by Imaging - so we use it now for saving instead of A32B32G32B32. - - String to float formatting changes (don't change global settings). - - -- 0.26.3 Changes/Bug Fixes ----------------------------------- - - Fixed D2009 Unicode related bug in PNM saving. - - -- 0.24.3 Changes/Bug Fixes ----------------------------------- - - Improved compatibility of 16bit/component image loading. - - Changes for better thread safety. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Made modifications to ASCII PNM loading to be more "stream-safe". - - Fixed bug: indexed images saved as grayscale in PFM. - - Changed converting to supported formats little bit. - - Added scaling of channel values (non-FP and non-mono images) according - to MaxVal. - - Added buffering to loading of PNM files. More than 10x faster now - for text files. - - Added saving support to PGM, PPM, PAM, and PFM format. - - Added PFM file format. - - Initial version created. -} - -end. diff --git a/3rd/Imaging/Source/ImagingRadiance.pas b/3rd/Imaging/Source/ImagingRadiance.pas deleted file mode 100644 index 122e0c226..000000000 --- a/3rd/Imaging/Source/ImagingRadiance.pas +++ /dev/null @@ -1,497 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for Radiance HDR/RGBE images.} -unit ImagingRadiance; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, Imaging, ImagingTypes, ImagingUtility; - -type - { Radiance is a suite of tools for performing lighting simulation. It's - development started in 1985 and it pioneered the concept of - high dynamic range imaging. Radiance defined an image format for storing - HDR images, now described as RGBE image format. Since it was the first - HDR image format, this format is supported by many other software packages. - - Radiance image file consists of three sections: a header, resolution string, - followed by the pixel data. Each pixel is stored as 4 bytes, one byte - mantissa for each r, g, b and a shared one byte exponent. - The pixel data may be stored uncompressed or using run length encoding. - - Imaging translates RGBE pixels to original float values and stores them - in ifR32G32B32F data format. It can read both compressed and uncompressed - files, and saves files as compressed.} - THdrFileFormat = class(TImageFileFormat) - protected - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - end; - -implementation - -uses - Math, ImagingIO; - -const - SHdrFormatName = 'Radiance HDR/RGBE'; - SHdrMasks = '*.hdr'; - HdrSupportedFormats: TImageFormats = [ifR32G32B32F]; - -type - TSignature = array[0..9] of AnsiChar; - THdrFormat = (hfRgb, hfXyz); - - THdrHeader = record - Format: THdrFormat; - Width: Integer; - Height: Integer; - end; - - TRgbe = packed record - R, G, B, E: Byte; - end; - PRgbe = ^TRgbe; - TDynRgbeArray = array of TRgbe; - -const - RadianceSignature: TSignature = '#?RADIANCE'; - RgbeSignature: TSignature = '#?RGBE'; - MaxLineLength = 256; - SFmtRgbeRle = '32-bit_rle_rgbe'; - SFmtXyzeRle = '32-bit_rle_xyze'; - -resourcestring - SErrorBadHeader = 'Bad HDR/RGBE header format.'; - SWrongScanLineWidth = 'Wrong scanline width.'; - SXyzNotSupported = 'XYZ color space not supported.'; - -{ THdrFileFormat } - -procedure THdrFileFormat.Define; -begin - inherited; - FName := SHdrFormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := HdrSupportedFormats; - - AddMasks(SHdrMasks); -end; - -function THdrFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Header: THdrHeader; - IO: TIOFunctions; - - function ReadHeader: Boolean; - const - CommentIds: TAnsiCharSet = ['#', '!']; - var - Line: AnsiString; - HasResolution: Boolean; - Count, Idx: Integer; - ValStr, NativeLine: string; - ValFloat: Double; - begin - Result := False; - HasResolution := False; - Count := 0; - - repeat - if not ReadLine(IO, Handle, Line) then - Exit; - - Inc(Count); - if Count > 16 then // Too long header for HDR - Exit; - - if Length(Line) = 0 then - Continue; - if Line[1] in CommentIds then - Continue; - - NativeLine := string(Line); - - if StrMaskMatch(NativeLine, 'Format=*') then - begin - // Data format parsing - ValStr := Copy(NativeLine, 8, MaxInt); - if ValStr = SFmtRgbeRle then - Header.Format := hfRgb - else if ValStr = SFmtXyzeRle then - Header.Format := hfXyz - else - Exit; - end; - - if StrMaskMatch(NativeLine, 'Gamma=*') then - begin - ValStr := Copy(NativeLine, 7, MaxInt); - if TryStrToFloat(ValStr, ValFloat, GetFormatSettingsForFloats) then - FMetadata.SetMetaItem(SMetaGamma, ValFloat); - end; - - if StrMaskMatch(NativeLine, 'Exposure=*') then - begin - ValStr := Copy(NativeLine, 10, MaxInt); - if TryStrToFloat(ValStr, ValFloat, GetFormatSettingsForFloats) then - FMetadata.SetMetaItem(SMetaExposure, ValFloat); - end; - - if StrMaskMatch(NativeLine, '?Y * ?X *') then - begin - Idx := Pos('X', NativeLine); - ValStr := SubString(NativeLine, 4, Idx - 2); - if not TryStrToInt(ValStr, Header.Height) then - Exit; - ValStr := Copy(NativeLine, Idx + 2, MaxInt); - if not TryStrToInt(ValStr, Header.Width) then - Exit; - - if (NativeLine[1] = '-') then - Header.Height := -Header.Height; - if (NativeLine[Idx - 1] = '-') then - Header.Width := -Header.Width; - - HasResolution := True; - end; - - until HasResolution; - Result := True; - end; - - procedure DecodeRgbe(const Src: TRgbe; Dest: PColor96FPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} - var - Mult: Single; - begin - if Src.E > 0 then - begin - Mult := Math.Ldexp(1, Src.E - 128); - Dest.R := Src.R / 255 * Mult; - Dest.G := Src.G / 255 * Mult; - Dest.B := Src.B / 255 * Mult; - end - else - begin - Dest.R := 0; - Dest.G := 0; - Dest.B := 0; - end; - end; - - procedure ReadCompressedLine(Width, Y: Integer; var DestBuffer: TDynRgbeArray); - var - Pos: Integer; - I, X, Count: Integer; - Code, Value: Byte; - LineBuff: TDynByteArray; - Rgbe: TRgbe; - Ptr: PByte; - begin - SetLength(LineBuff, Width); - IO.Read(Handle, @Rgbe, SizeOf(Rgbe)); - - if ((Rgbe.B shl 8) or Rgbe.E) <> Width then - RaiseImaging(SWrongScanLineWidth); - - for I := 0 to 3 do - begin - Pos := 0; - while Pos < Width do - begin - IO.Read(Handle, @Code, SizeOf(Byte)); - if Code > 128 then - begin - Count := Code - 128; - IO.Read(Handle, @Value, SizeOf(Byte)); - FillMemoryByte(@LineBuff[Pos], Count, Value); - end - else - begin - Count := Code; - IO.Read(Handle, @LineBuff[Pos], Count * SizeOf(Byte)); - end; - Inc(Pos, Count); - end; - - Ptr := @PByteArray(@DestBuffer[0])[I]; - for X := 0 to Width - 1 do - begin - Ptr^ := LineBuff[X]; - Inc(Ptr, 4); - end; - end; - end; - - procedure ReadPixels(var Image: TImageData); - var - Y, X, SrcLineLen: Integer; - Dest: PColor96FPRec; - Compressed: Boolean; - Rgbe: TRgbe; - Buffer: TDynRgbeArray; - begin - Dest := Image.Bits; - Compressed := not ((Image.Width < 8) or (Image.Width > $7FFFF)); - SrcLineLen := Image.Width * SizeOf(TRgbe); - - IO.Read(Handle, @Rgbe, SizeOf(Rgbe)); - IO.Seek(Handle, -SizeOf(Rgbe), smFromCurrent); - - if (Rgbe.R <> 2) or (Rgbe.G <> 2) or ((Rgbe.B and 128) > 0) then - Compressed := False; - - SetLength(Buffer, Image.Width); - - for Y := 0 to Image.Height - 1 do - begin - if Compressed then - ReadCompressedLine(Image.Width, Y, Buffer) - else - IO.Read(Handle, @Buffer[0], SrcLineLen); - - for X := 0 to Image.Width - 1 do - begin - DecodeRgbe(Buffer[X], Dest); - Inc(Dest); - end; - end; - end; - -begin - IO := GetIO; - SetLength(Images, 1); - - // Read header, allocate new image and, then read and convert the pixels - if not ReadHeader then - RaiseImaging(SErrorBadHeader); - if (Header.Format = hfXyz) then - RaiseImaging(SXyzNotSupported); - - NewImage(Abs(Header.Width), Abs(Header.Height), ifR32G32B32F, Images[0]); - ReadPixels(Images[0]); - - // Flip/mirror the image as needed (height < 0 is default top-down) - if Header.Width < 0 then - MirrorImage(Images[0]); - if Header.Height > 0 then - FlipImage(Images[0]); - - Result := True; -end; - -function THdrFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: Integer): Boolean; -const - LineEnd = #$0A; - SPrgComment = '#Made with Vampyre Imaging Library'; - SSizeFmt = '-Y %d +X %d'; -var - ImageToSave: TImageData; - MustBeFreed: Boolean; - IO: TIOFunctions; - - procedure SaveHeader; - begin - WriteLine(IO, Handle, RadianceSignature, LineEnd); - WriteLine(IO, Handle, SPrgComment, LineEnd); - WriteLine(IO, Handle, 'FORMAT=' + SFmtRgbeRle, LineEnd + LineEnd); - WriteLine(IO, Handle, AnsiString(Format(SSizeFmt, [ImageToSave.Height, ImageToSave.Width])), LineEnd); - end; - - procedure EncodeRgbe(const Src: TColor96FPRec; var DestR, DestG, DestB, DestE: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF} - var - V, M: {$IFDEF FPC}Float{$ELSE}Extended{$ENDIF}; - E: Integer; - begin - V := Src.R; - if (Src.G > V) then - V := Src.G; - if (Src.B > V) then - V := Src.B; - - if V < 1e-32 then - begin - DestR := 0; - DestG := 0; - DestB := 0; - DestE := 0; - end - else - begin - Frexp(V, M, E); - V := M * 256.0 / V; - DestR := ClampToByte(Round(Src.R * V)); - DestG := ClampToByte(Round(Src.G * V)); - DestB := ClampToByte(Round(Src.B * V)); - DestE := ClampToByte(E + 128); - end; - end; - - procedure WriteRleLine(const Line: array of Byte; Width: Integer); - const - MinRunLength = 4; - var - Cur, BeginRun, RunCount, OldRunCount, NonRunCount: Integer; - Buf: array[0..1] of Byte; - begin - Cur := 0; - while Cur < Width do - begin - BeginRun := Cur; - RunCount := 0; - OldRunCount := 0; - while (RunCount < MinRunLength) and (BeginRun < Width) do - begin - Inc(BeginRun, RunCount); - OldRunCount := RunCount; - RunCount := 1; - while (BeginRun + RunCount < Width) and (RunCount < 127) and (Line[BeginRun] = Line[BeginRun + RunCount]) do - Inc(RunCount); - end; - if (OldRunCount > 1) and (OldRunCount = BeginRun - Cur) then - begin - Buf[0] := 128 + OldRunCount; - Buf[1] := Line[Cur]; - IO.Write(Handle, @Buf, 2); - Cur := BeginRun; - end; - while Cur < BeginRun do - begin - NonRunCount := Min(128, BeginRun - Cur); - Buf[0] := NonRunCount; - IO.Write(Handle, @Buf, 1); - IO.Write(Handle, @Line[Cur], NonRunCount); - Inc(Cur, NonRunCount); - end; - if RunCount >= MinRunLength then - begin - Buf[0] := 128 + RunCount; - Buf[1] := Line[BeginRun]; - IO.Write(Handle, @Buf, 2); - Inc(Cur, RunCount); - end; - end; - end; - - procedure SavePixels; - var - Y, X, I, Width: Integer; - SrcPtr: PColor96FPRecArray; - Components: array of array of Byte; - StartLine: array[0..3] of Byte; - begin - Width := ImageToSave.Width; - // Save using RLE, each component is compressed separately - SetLength(Components, 4, Width); - - for Y := 0 to ImageToSave.Height - 1 do - begin - SrcPtr := @PColor96FPRecArray(ImageToSave.Bits)[ImageToSave.Width * Y]; - - // Identify line as using "new" RLE scheme (separate components) - StartLine[0] := 2; - StartLine[1] := 2; - StartLine[2] := Width shr 8; - StartLine[3] := Width and $FF; - IO.Write(Handle, @StartLine, SizeOf(StartLine)); - - for X := 0 to Width - 1 do - begin - EncodeRgbe(SrcPtr[X], Components[0, X], Components[1, X], - Components[2, X], Components[3, X]); - end; - - for I := 0 to 3 do - WriteRleLine(Components[I], Width); - end; - end; - -begin - Result := False; - IO := GetIO; - // Makes image to save compatible with Jpeg saving capabilities - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with ImageToSave do - try - // Save header - SaveHeader; - // Save uncompressed pixels - SavePixels; - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -procedure THdrFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -begin - ConvertImage(Image, ifR32G32B32F); -end; - -function THdrFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - FileSig: TSignature; - ReadCount: Integer; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @FileSig, SizeOf(FileSig)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount = SizeOf(FileSig)) and - ((FileSig = RadianceSignature) or CompareMem(@FileSig, @RgbeSignature, 6)); - end; -end; - -initialization - RegisterImageFileFormat(THdrFileFormat); - -{ - File Notes: - - -- 0.77.1 --------------------------------------------------- - - Added RLE compression to saving. - - Added image saving. - - Unit created with initial stuff (loading only). - -} - -end. diff --git a/3rd/Imaging/Source/ImagingTarga.pas b/3rd/Imaging/Source/ImagingTarga.pas deleted file mode 100644 index a1d4c753b..000000000 --- a/3rd/Imaging/Source/ImagingTarga.pas +++ /dev/null @@ -1,620 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains image format loader/saver for Targa images.} -unit ImagingTarga; - -{$I ImagingOptions.inc} - -interface - -uses - ImagingTypes, Imaging, ImagingFormats, ImagingUtility; - -type - { Class for loading and saving Truevision Targa images. - It can load/save 8bit indexed or grayscale, 16 bit RGB or grayscale, - 24 bit RGB and 32 bit ARGB images with or without RLE compression.} - TTargaFileFormat = class(TImageFileFormat) - protected - FUseRLE: LongBool; - procedure Define; override; - function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; - OnlyFirstLevel: Boolean): Boolean; override; - function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; - Index: LongInt): Boolean; override; - procedure ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); override; - public - function TestFormat(Handle: TImagingHandle): Boolean; override; - published - { Controls that RLE compression is used during saving. Accessible trough - ImagingTargaRLE option.} - property UseRLE: LongBool read FUseRLE write FUseRLE; - end; - -implementation - -const - STargaFormatName = 'Truevision Targa Image'; - STargaMasks = '*.tga'; - TargaSupportedFormats: TImageFormats = [ifIndex8, ifGray8, ifA1R5G5B5, - ifR8G8B8, ifA8R8G8B8]; - TargaDefaultRLE = False; - -const - STargaSignature = 'TRUEVISION-XFILE'; - -type - { Targa file header.} - TTargaHeader = packed record - IDLength: Byte; - ColorMapType: Byte; - ImageType: Byte; - ColorMapOff: Word; - ColorMapLength: Word; - ColorEntrySize: Byte; - XOrg: SmallInt; - YOrg: SmallInt; - Width: SmallInt; - Height: SmallInt; - PixelSize: Byte; - Desc: Byte; - end; - - { Footer at the end of TGA file.} - TTargaFooter = packed record - ExtOff: LongWord; // Extension Area Offset - DevDirOff: LongWord; // Developer Directory Offset - Signature: TChar16; // TRUEVISION-XFILE - Reserved: Byte; // ASCII period '.' - NullChar: Byte; // 0 - end; - - -{ TTargaFileFormat class implementation } - -procedure TTargaFileFormat.Define; -begin - inherited; - FName := STargaFormatName; - FFeatures := [ffLoad, ffSave]; - FSupportedFormats := TargaSupportedFormats; - - FUseRLE := TargaDefaultRLE; - - AddMasks(STargaMasks); - RegisterOption(ImagingTargaRLE, @FUseRLE); -end; - -function TTargaFileFormat.LoadData(Handle: TImagingHandle; - var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; -var - Hdr: TTargaHeader; - Foo: TTargaFooter; - FooterFound, ExtFound: Boolean; - I, PSize, PalSize: LongWord; - Pal: Pointer; - FmtInfo: TImageFormatInfo; - WordValue: Word; - - procedure LoadRLE; - var - I, CPixel, Cnt: LongInt; - Bpp, Rle: Byte; - Buffer, Dest, Src: PByte; - BufSize: LongInt; - begin - with GetIO, Images[0] do - begin - // Alocates buffer large enough to hold the worst case - // RLE compressed data and reads then from input - BufSize := Width * Height * FmtInfo.BytesPerPixel; - BufSize := BufSize + BufSize div 2 + 1; - GetMem(Buffer, BufSize); - Src := Buffer; - Dest := Bits; - BufSize := Read(Handle, Buffer, BufSize); - - Cnt := Width * Height; - Bpp := FmtInfo.BytesPerPixel; - CPixel := 0; - while CPixel < Cnt do - begin - Rle := Src^; - Inc(Src); - if Rle < 128 then - begin - // Process uncompressed pixel - Rle := Rle + 1; - CPixel := CPixel + Rle; - for I := 0 to Rle - 1 do - begin - // Copy pixel from src to dest - case Bpp of - 1: Dest^ := Src^; - 2: PWord(Dest)^ := PWord(Src)^; - 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^; - 4: PLongWord(Dest)^ := PLongWord(Src)^; - end; - Inc(Src, Bpp); - Inc(Dest, Bpp); - end; - end - else - begin - // Process compressed pixels - Rle := Rle - 127; - CPixel := CPixel + Rle; - // Copy one pixel from src to dest (many times there) - for I := 0 to Rle - 1 do - begin - case Bpp of - 1: Dest^ := Src^; - 2: PWord(Dest)^ := PWord(Src)^; - 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^; - 4: PLongWord(Dest)^ := PLongWord(Src)^; - end; - Inc(Dest, Bpp); - end; - Inc(Src, Bpp); - end; - end; - // set position in source to real end of compressed data - Seek(Handle, -(BufSize - LongInt(LongWord(Src) - LongWord(Buffer))), - smFromCurrent); - FreeMem(Buffer); - end; - end; - -begin - SetLength(Images, 1); - with GetIO, Images[0] do - begin - // Read targa header - Read(Handle, @Hdr, SizeOf(Hdr)); - // Skip image ID info - Seek(Handle, Hdr.IDLength, smFromCurrent); - // Determine image format - Format := ifUnknown; - case Hdr.ImageType of - 1, 9: Format := ifIndex8; - 2, 10: case Hdr.PixelSize of - 15: Format := ifX1R5G5B5; - 16: Format := ifA1R5G5B5; - 24: Format := ifR8G8B8; - 32: Format := ifA8R8G8B8; - end; - 3, 11: Format := ifGray8; - end; - // Format was not assigned by previous testing (it should be in - // well formed targas), so formats which reflects bit dept are selected - if Format = ifUnknown then - case Hdr.PixelSize of - 8: Format := ifGray8; - 15: Format := ifX1R5G5B5; - 16: Format := ifA1R5G5B5; - 24: Format := ifR8G8B8; - 32: Format := ifA8R8G8B8; - end; - NewImage(Hdr.Width, Hdr.Height, Format, Images[0]); - FmtInfo := GetFormatInfo(Format); - - if (Hdr.ColorMapType = 1) and (Hdr.ImageType in [1, 9]) then - begin - // Read palette - PSize := Hdr.ColorMapLength * (Hdr.ColorEntrySize shr 3); - GetMem(Pal, PSize); - try - Read(Handle, Pal, PSize); - // Process palette - PalSize := Iff(Hdr.ColorMapLength > FmtInfo.PaletteEntries, - FmtInfo.PaletteEntries, Hdr.ColorMapLength); - for I := 0 to PalSize - 1 do - case Hdr.ColorEntrySize of - 24: - with Palette[I] do - begin - A := $FF; - R := PPalette24(Pal)[I].R; - G := PPalette24(Pal)[I].G; - B := PPalette24(Pal)[I].B; - end; - // I've never seen tga with these palettes so they are untested - 16: - with Palette[I] do - begin - A := (PWordArray(Pal)[I] and $8000) shr 12; - R := (PWordArray(Pal)[I] and $FC00) shr 7; - G := (PWordArray(Pal)[I] and $03E0) shr 2; - B := (PWordArray(Pal)[I] and $001F) shl 3; - end; - 32: - with Palette[I] do - begin - A := PPalette32(Pal)[I].A; - R := PPalette32(Pal)[I].R; - G := PPalette32(Pal)[I].G; - B := PPalette32(Pal)[I].B; - end; - end; - finally - FreeMemNil(Pal); - end; - end; - - case Hdr.ImageType of - 0, 1, 2, 3: - // Load uncompressed mode images - Read(Handle, Bits, Size); - 9, 10, 11: - // Load RLE compressed mode images - LoadRLE; - end; - - // Check if there is alpha channel present in A1R5GB5 images, if it is not - // change format to X1R5G5B5 - if Format = ifA1R5G5B5 then - begin - if not Has16BitImageAlpha(Width * Height, Bits) then - Format := ifX1R5G5B5; - end; - - // We must find true end of file and set input' position to it - // paint programs appends extra info at the end of Targas - // some of them multiple times (PSP Pro 8) - repeat - ExtFound := False; - FooterFound := False; - - if Read(Handle, @WordValue, 2) = 2 then - begin - // 495 = size of Extension Area - if WordValue = 495 then - begin - Seek(Handle, 493, smFromCurrent); - ExtFound := True; - end - else - Seek(Handle, -2, smFromCurrent); - end; - - if Read(Handle, @Foo, SizeOf(Foo)) = SizeOf(Foo) then - begin - if Foo.Signature = STargaSignature then - FooterFound := True - else - Seek(Handle, -SizeOf(Foo), smFromCurrent); - end; - until (not ExtFound) and (not FooterFound); - - // Some editors save targas flipped - if Hdr.Desc < 31 then - FlipImage(Images[0]); - - Result := True; - end; -end; - -function TTargaFileFormat.SaveData(Handle: TImagingHandle; - const Images: TDynImageDataArray; Index: LongInt): Boolean; -var - I: LongInt; - Hdr: TTargaHeader; - FmtInfo: TImageFormatInfo; - Pal: PPalette24; - ImageToSave: TImageData; - MustBeFreed: Boolean; - - procedure SaveRLE; - var - Dest: PByte; - WidthBytes, Written, I, Total, DestSize: LongInt; - - function CountDiff(Data: PByte; Bpp, PixelCount: Longint): LongInt; - var - Pixel: LongWord; - NextPixel: LongWord; - N: LongInt; - begin - N := 0; - Pixel := 0; - NextPixel := 0; - if PixelCount = 1 then - begin - Result := PixelCount; - Exit; - end; - case Bpp of - 1: Pixel := Data^; - 2: Pixel := PWord(Data)^; - 3: PColor24Rec(@Pixel)^ := PColor24Rec(Data)^; - 4: Pixel := PLongWord(Data)^; - end; - while PixelCount > 1 do - begin - Inc(Data, Bpp); - case Bpp of - 1: NextPixel := Data^; - 2: NextPixel := PWord(Data)^; - 3: PColor24Rec(@NextPixel)^ := PColor24Rec(Data)^; - 4: NextPixel := PLongWord(Data)^; - end; - if NextPixel = Pixel then - Break; - Pixel := NextPixel; - N := N + 1; - PixelCount := PixelCount - 1; - end; - if NextPixel = Pixel then - Result := N - else - Result := N + 1; - end; - - function CountSame(Data: PByte; Bpp, PixelCount: LongInt): LongInt; - var - Pixel: LongWord; - NextPixel: LongWord; - N: LongInt; - begin - N := 1; - Pixel := 0; - NextPixel := 0; - case Bpp of - 1: Pixel := Data^; - 2: Pixel := PWord(Data)^; - 3: PColor24Rec(@Pixel)^ := PColor24Rec(Data)^; - 4: Pixel := PLongWord(Data)^; - end; - PixelCount := PixelCount - 1; - while PixelCount > 0 do - begin - Inc(Data, Bpp); - case Bpp of - 1: NextPixel := Data^; - 2: NextPixel := PWord(Data)^; - 3: PColor24Rec(@NextPixel)^ := PColor24Rec(Data)^; - 4: NextPixel := PLongWord(Data)^; - end; - if NextPixel <> Pixel then - Break; - N := N + 1; - PixelCount := PixelCount - 1; - end; - Result := N; - end; - - procedure RleCompressLine(Data: PByte; PixelCount, Bpp: LongInt; Dest: - PByte; var Written: LongInt); - const - MaxRun = 128; - var - DiffCount: LongInt; - SameCount: LongInt; - RleBufSize: LongInt; - begin - RleBufSize := 0; - while PixelCount > 0 do - begin - DiffCount := CountDiff(Data, Bpp, PixelCount); - SameCount := CountSame(Data, Bpp, PixelCount); - if (DiffCount > MaxRun) then - DiffCount := MaxRun; - if (SameCount > MaxRun) then - SameCount := MaxRun; - if (DiffCount > 0) then - begin - Dest^ := Byte(DiffCount - 1); - Inc(Dest); - PixelCount := PixelCount - DiffCount; - RleBufSize := RleBufSize + (DiffCount * Bpp) + 1; - Move(Data^, Dest^, DiffCount * Bpp); - Inc(Data, DiffCount * Bpp); - Inc(Dest, DiffCount * Bpp); - end; - if SameCount > 1 then - begin - Dest^ := Byte((SameCount - 1) or $80); - Inc(Dest); - PixelCount := PixelCount - SameCount; - RleBufSize := RleBufSize + Bpp + 1; - Inc(Data, (SameCount - 1) * Bpp); - case Bpp of - 1: Dest^ := Data^; - 2: PWord(Dest)^ := PWord(Data)^; - 3: PColor24Rec(Dest)^ := PColor24Rec(Data)^; - 4: PLongWord(Dest)^ := PLongWord(Data)^; - end; - Inc(Data, Bpp); - Inc(Dest, Bpp); - end; - end; - Written := RleBufSize; - end; - - begin - with ImageToSave do - begin - // Allocate enough space to hold the worst case compression - // result and then compress source's scanlines - WidthBytes := Width * FmtInfo.BytesPerPixel; - DestSize := WidthBytes * Height; - DestSize := DestSize + DestSize div 2 + 1; - GetMem(Dest, DestSize); - Total := 0; - try - for I := 0 to Height - 1 do - begin - RleCompressLine(@PByteArray(Bits)[I * WidthBytes], Width, - FmtInfo.BytesPerPixel, @PByteArray(Dest)[Total], Written); - Total := Total + Written; - end; - GetIO.Write(Handle, Dest, Total); - finally - FreeMem(Dest); - end; - end; - end; - -begin - Result := False; - if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then - with GetIO, ImageToSave do - try - FmtInfo := GetFormatInfo(Format); - // Fill targa header - FillChar(Hdr, SizeOf(Hdr), 0); - Hdr.IDLength := 0; - Hdr.ColorMapType := Iff(FmtInfo.PaletteEntries > 0, 1, 0); - Hdr.Width := Width; - Hdr.Height := Height; - Hdr.PixelSize := FmtInfo.BytesPerPixel * 8; - Hdr.ColorMapLength := FmtInfo.PaletteEntries; - Hdr.ColorEntrySize := Iff(FmtInfo.PaletteEntries > 0, 24, 0); - Hdr.ColorMapOff := 0; - // This indicates that targa is stored in top-left format - // as our images -> no flipping is needed. - Hdr.Desc := 32; - // Set alpha channel size in descriptor (mostly ignored by other software though) - if Format = ifA8R8G8B8 then - Hdr.Desc := Hdr.Desc or 8 - else if Format = ifA1R5G5B5 then - Hdr.Desc := Hdr.Desc or 1; - - // Choose image type - if FmtInfo.IsIndexed then - Hdr.ImageType := Iff(FUseRLE, 9, 1) - else - if FmtInfo.HasGrayChannel then - Hdr.ImageType := Iff(FUseRLE, 11, 3) - else - Hdr.ImageType := Iff(FUseRLE, 10, 2); - - Write(Handle, @Hdr, SizeOf(Hdr)); - - // Write palette - if FmtInfo.PaletteEntries > 0 then - begin - GetMem(Pal, FmtInfo.PaletteEntries * SizeOf(TColor24Rec)); - try - for I := 0 to FmtInfo.PaletteEntries - 1 do - with Pal[I] do - begin - R := Palette[I].R; - G := Palette[I].G; - B := Palette[I].B; - end; - Write(Handle, Pal, FmtInfo.PaletteEntries * SizeOf(TColor24Rec)); - finally - FreeMemNil(Pal); - end; - end; - - if FUseRLE then - // Save rle compressed mode images - SaveRLE - else - // Save uncompressed mode images - Write(Handle, Bits, Size); - - Result := True; - finally - if MustBeFreed then - FreeImage(ImageToSave); - end; -end; - -procedure TTargaFileFormat.ConvertToSupported(var Image: TImageData; - const Info: TImageFormatInfo); -var - ConvFormat: TImageFormat; -begin - if Info.HasGrayChannel then - // Convert all grayscale images to Gray8 (preserve alpha of AxGrayx formats) - ConvFormat := IffFormat(not Info.HasAlphaChannel, ifGray8, ifA8R8G8B8) - else if Info.IsIndexed then - // Convert all indexed images to Index8 - ConvFormat := ifIndex8 - else if Info.HasAlphaChannel then - // Convert images with alpha channel to A8R8G8B8 - ConvFormat := ifA8R8G8B8 - else if Info.UsePixelFormat then - // Convert 16bit images (without alpha channel) to A1R5G5B5 - ConvFormat := ifA1R5G5B5 - else - // Convert all other formats to R8G8B8 - ConvFormat := ifR8G8B8; - - ConvertImage(Image, ConvFormat); -end; - -function TTargaFileFormat.TestFormat(Handle: TImagingHandle): Boolean; -var - Hdr: TTargaHeader; - ReadCount: LongInt; -begin - Result := False; - if Handle <> nil then - begin - ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr)); - GetIO.Seek(Handle, -ReadCount, smFromCurrent); - Result := (ReadCount >= SizeOf(Hdr)) and - (Hdr.ImageType in [0, 1, 2, 3, 9, 10, 11]) and - (Hdr.PixelSize in [1, 8, 15, 16, 24, 32]) and - (Hdr.ColorEntrySize in [0, 16, 24, 32]); - end; -end; - -initialization - RegisterImageFileFormat(TTargaFileFormat); - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - MakeCompatible method moved to base class, put ConvertToSupported here. - GetSupportedFormats removed, it is now set in constructor. - - Made public properties for options registered to SetOption/GetOption - functions. - - Changed extensions to filename masks. - - Changed SaveData, LoadData, and MakeCompatible methods according - to changes in base class in Imaging unit. - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - 16 bit images are usually without alpha but some has alpha - channel and there is no indication of it - so I have added - a check: if all pixels of image are with alpha = 0 image is treated - as X1R5G5B5 otherwise as A1R5G5B5 - - fixed problems with some nonstandard 15 bit images -} - -end. - diff --git a/3rd/Imaging/Source/ImagingTypes.pas b/3rd/Imaging/Source/ImagingTypes.pas deleted file mode 100644 index e5da35fa7..000000000 --- a/3rd/Imaging/Source/ImagingTypes.pas +++ /dev/null @@ -1,567 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains basic types and constants used by Imaging library.} -unit ImagingTypes; - -{$I ImagingOptions.inc} - -interface - -const - { Current Major version of Imaging.} - ImagingVersionMajor = 0; - { Current Minor version of Imaging.} - ImagingVersionMinor = 77; - { Current patch of Imaging.} - ImagingVersionPatch = 1; - - { Imaging Option Ids whose values can be set/get by SetOption/ - GetOption functions.} - - { Defines Jpeg compression quality, ranges from 1 (ugly/small) to 100 (nice/large). - Default value is 90.} - ImagingJpegQuality = 10; - { Specifies whether Jpeg images are saved in progressive format, - can be 0 or 1. Default value is 0.} - ImagingJpegProgressive = 11; - - { Specifies whether Windows Bitmaps are saved using RLE compression - (only for 1/4/8 bit images), can be 0 or 1. Default value is 1.} - ImagingBitmapRLE = 12; - - { Specifies whether Targa images are saved using RLE compression, - can be 0 or 1. Default value is 0.} - ImagingTargaRLE = 13; - - { Value of this option is non-zero if last loaded DDS file was cube map.} - ImagingDDSLoadedCubeMap = 14; - { Value of this option is non-zero if last loaded DDS file was volume texture.} - ImagingDDSLoadedVolume = 15; - { Value of this option is number of mipmap levels of last loaded DDS image.} - ImagingDDSLoadedMipMapCount = 16; - { Value of this option is depth (slices of volume texture or faces of - cube map) of last loaded DDS image.} - ImagingDDSLoadedDepth = 17; - { If it is non-zero next saved DDS file should be stored as cube map.} - ImagingDDSSaveCubeMap = 18; - { If it is non-zero next saved DDS file should be stored as volume texture.} - ImagingDDSSaveVolume = 19; - { Sets the number of mipmaps which should be stored in the next saved DDS file. - Only applies to cube maps and volumes, ordinary 2D textures save all - levels present in input.} - ImagingDDSSaveMipMapCount = 20; - { Sets the depth (slices of volume texture or faces of cube map) - of the next saved DDS file.} - ImagingDDSSaveDepth = 21; - - { Sets precompression filter used when saving PNG images. Allowed values - are: 0 (none), 1 (sub), 2 (up), 3 (average), 4 (paeth), - 5 (use 0 for indexed/gray images and 4 for RGB/ARGB images), - 6 (adaptive filtering - use best filter for each scanline - very slow). - Note that filters 3 and 4 are much slower than filters 1 and 2. - Default value is 5.} - ImagingPNGPreFilter = 25; - { Sets ZLib compression level used when saving PNG images. - Allowed values are in range 0 (no compresstion) to 9 (best compression). - Default value is 5.} - ImagingPNGCompressLevel = 26; - { Boolean option that specifies whether PNG images with more frames (APNG format) - are animated by Imaging (according to frame disposal/blend methods) or just - raw frames are loaded and sent to user (if you want to animate APNG yourself). - Default value is 1.} - ImagingPNGLoadAnimated = 27; - { Sets ZLib compression strategy used when saving PNG files (see deflateInit2() - in ZLib for details). Allowed values are: 0 (default), 1 (filtered), - 2 (huffman only). Default value is 0.} - ImagingPNGZLibStrategy = 28; - - { Specifies whether MNG animation frames are saved with lossy or lossless - compression. Lossless frames are saved as PNG images and lossy frames are - saved as JNG images. Allowed values are 0 (False) and 1 (True). - Default value is 0.} - ImagingMNGLossyCompression = 32; - { Defines whether alpha channel of lossy compressed MNG frames - (when ImagingMNGLossyCompression is 1) is lossy compressed too. - Allowed values are 0 (False) and 1 (True). Default value is 0.} - ImagingMNGLossyAlpha = 33; - { Sets precompression filter used when saving MNG frames as PNG images. - For details look at ImagingPNGPreFilter.} - ImagingMNGPreFilter = 34; - { Sets ZLib compression level used when saving MNG frames as PNG images. - For details look at ImagingPNGCompressLevel.} - ImagingMNGCompressLevel = 35; - { Specifies compression quality used when saving MNG frames as JNG images. - For details look at ImagingJpegQuality.} - ImagingMNGQuality = 36; - { Specifies whether images are saved in progressive format when saving MNG - frames as JNG images. For details look at ImagingJpegProgressive.} - ImagingMNGProgressive = 37; - - { Specifies whether alpha channels of JNG images are lossy compressed. - Allowed values are 0 (False) and 1 (True). Default value is 0.} - ImagingJNGLossyAlpha = 40; - { Sets precompression filter used when saving lossless alpha channels. - For details look at ImagingPNGPreFilter.} - ImagingJNGAlphaPreFilter = 41; - { Sets ZLib compression level used when saving lossless alpha channels. - For details look at ImagingPNGCompressLevel.} - ImagingJNGAlphaCompressLevel = 42; - { Defines compression quality used when saving JNG images (and lossy alpha channels). - For details look at ImagingJpegQuality.} - ImagingJNGQuality = 43; - { Specifies whether JNG images are saved in progressive format. - For details look at ImagingJpegProgressive.} - ImagingJNGProgressive = 44; - - { Specifies whether PGM files are stored in text or in binary format. - Allowed values are 0 (store as text - very! large files) and 1 (save binary). - Default value is 1.} - ImagingPGMSaveBinary = 50; - - { Specifies whether PPM files are stored in text or in binary format. - Allowed values are 0 (store as text - very! large files) and 1 (save binary). - Default value is 1.} - ImagingPPMSaveBinary = 51; - - { Boolean option that specifies whether GIF images with more frames - are animated by Imaging (according to frame disposal methods) or just - raw frames are loaded and sent to user (if you want to animate GIF yourself). - Default value is 1. - Raw frames are 256 color indexed images (ifIndex8), whereas - animated frames are always in 32bit ifA8R8G8B8 format (simplifies animating).} - ImagingGIFLoadAnimated = 56; - - { This option is used when reducing number of colors used in - image (mainly when converting from ARGB image to indexed - format). Mask is 'anded' (bitwise AND) with every pixel's - channel value when creating color histogram. If $FF is used - all 8bits of color channels are used which can result in very - slow proccessing of large images with many colors so you can - use lower masks to speed it up (FC, F8 and F0 are good - choices). Allowed values are in range <0, $FF> and default is - $FE. } - ImagingColorReductionMask = 128; - { This option can be used to override image data format during image - loading. If set to format different from ifUnknown all loaded images - are automaticaly converted to this format. Useful when you have - many files in various formats but you want them all in one format for - further proccessing. Allowed values are in - range <Ord(Low(TImageFormat)), Ord(High(TImageFormat))> and - default value is ifUnknown.} - ImagingLoadOverrideFormat = 129; - { This option can be used to override image data format during image - saving. If set to format different from ifUnknown all images - to be saved are automaticaly internaly converted to this format. - Note that image file formats support only a subset of Imaging data formats - so final saved file may in different format than this override. - Allowed values are in range <Ord(Low(TImageFormat)), Ord(High(TImageFormat))> - and default value is ifUnknown.} - ImagingSaveOverrideFormat = 130; - { Specifies resampling filter used when generating mipmaps. It is used - in GenerateMipMaps low level function and Direct3D and OpenGL extensions. - Allowed values are in range - <Ord(Low(ImagingFormats.TSamplingFilter)), Ord(High(ImagingFormats.TSamplingFilter))> - and default value is 1 (linear filter).} - ImagingMipMapFilter = 131; - { Specifies treshold value used when automatically converting images to - ifBinary format. For adaptive tresholding see ImagingBinary.pas unit. - Default value is 128 and allowed range is 0..255.} - ImagingBinaryTreshold = 132; - - { Returned by GetOption if given Option Id is invalid.} - InvalidOption = -$7FFFFFFF; - - { Indices that can be used to access channel values in array parts - of structures like TColor32Rec. Note that this order can be - used only for ARGB images. For ABGR image you must swap Red and Blue.} - ChannelBlue = 0; - ChannelGreen = 1; - ChannelRed = 2; - ChannelAlpha = 3; - -type - { Enum defining image data format. In formats with more channels, - first channel after "if" is stored in the most significant bits and channel - before end is stored in the least significant.} - TImageFormat = ( - ifUnknown = 0, - ifDefault = 1, - { Indexed formats using palette } - ifIndex8 = 10, - { Grayscale/Luminance formats } - ifGray8 = 40, - ifA8Gray8 = 41, - ifGray16 = 42, - ifGray32 = 43, - ifGray64 = 44, - ifA16Gray16 = 45, - { ARGB formats } - ifX5R1G1B1 = 80, - ifR3G3B2 = 81, - ifR5G6B5 = 82, - ifA1R5G5B5 = 83, - ifA4R4G4B4 = 84, - ifX1R5G5B5 = 85, - ifX4R4G4B4 = 86, - ifR8G8B8 = 87, - ifA8R8G8B8 = 88, - ifX8R8G8B8 = 89, - ifR16G16B16 = 90, - ifA16R16G16B16 = 91, - ifB16G16R16 = 92, - ifA16B16G16R16 = 93, - { Floating point formats } - ifR32F = 160, - ifA32R32G32B32F = 161, - ifA32B32G32R32F = 162, - ifR16F = 163, - ifA16R16G16B16F = 164, - ifA16B16G16R16F = 165, - ifR32G32B32F = 166, - ifB32G32R32F = 167, - { Special formats } - ifDXT1 = 200, - ifDXT3 = 201, - ifDXT5 = 202, - ifBTC = 203, - ifATI1N = 204, - ifATI2N = 205, - ifBinary = 206, - { Passtrough formats } - ifETC1 = 220, - ifETC2RGB = 221, - ifETC2RGBA = 222, - ifETC2PA = 223, - ifDXBC6 = 224, - ifDXBC7 = 225, - ifMono = 250, - ifIndex2 = 251, - ifIndex4 = 252 - ); - - { Color value for 32 bit images.} - TColor32 = LongWord; - PColor32 = ^TColor32; - - { Color value for 64 bit images.} - TColor64 = type Int64; - PColor64 = ^TColor64; - - { Color record for 24 bit images, which allows access to individual color - channels.} - TColor24Rec = packed record - case LongInt of - 0: (B, G, R: Byte); - 1: (Channels: array[0..2] of Byte); - end; - PColor24Rec = ^TColor24Rec; - TColor24RecArray = array[0..MaxInt div SizeOf(TColor24Rec) - 1] of TColor24Rec; - PColor24RecArray = ^TColor24RecArray; - - { Color record for 32 bit images, which allows access to individual color - channels.} - TColor32Rec = packed record - case LongInt of - 0: (Color: TColor32); - 1: (B, G, R, A: Byte); - 2: (Channels: array[0..3] of Byte); - 3: (Color24Rec: TColor24Rec); - end; - PColor32Rec = ^TColor32Rec; - TColor32RecArray = array[0..MaxInt div SizeOf(TColor32Rec) - 1] of TColor32Rec; - PColor32RecArray = ^TColor32RecArray; - - { Color record for 48 bit images, which allows access to individual color - channels.} - TColor48Rec = packed record - case LongInt of - 0: (B, G, R: Word); - 1: (Channels: array[0..2] of Word); - end; - PColor48Rec = ^TColor48Rec; - TColor48RecArray = array[0..MaxInt div SizeOf(TColor48Rec) - 1] of TColor48Rec; - PColor48RecArray = ^TColor48RecArray; - - { Color record for 64 bit images, which allows access to individual color - channels.} - TColor64Rec = packed record - case LongInt of - 0: (Color: TColor64); - 1: (B, G, R, A: Word); - 2: (Channels: array[0..3] of Word); - 3: (Color48Rec: TColor48Rec); - end; - PColor64Rec = ^TColor64Rec; - TColor64RecArray = array[0..MaxInt div SizeOf(TColor64Rec) - 1] of TColor64Rec; - PColor64RecArray = ^TColor64RecArray; - - { Color record for 96 bit floating point images, which allows access to - individual color channels.} - TColor96FPRec = packed record - case Integer of - 0: (B, G, R: Single); - 1: (Channels: array[0..2] of Single); - end; - PColor96FPRec = ^TColor96FPRec; - TColor96FPRecArray = array[0..MaxInt div SizeOf(TColor96FPRec) - 1] of TColor96FPRec; - PColor96FPRecArray = ^TColor96FPRecArray; - - { Color record for 128 bit floating point images, which allows access to - individual color channels.} - TColorFPRec = packed record - case LongInt of - 0: (B, G, R, A: Single); - 1: (Channels: array[0..3] of Single); - 2: (Color96Rec: TColor96FPRec); - end; - PColorFPRec = ^TColorFPRec; - TColorFPRecArray = array[0..MaxInt div SizeOf(TColorFPRec) - 1] of TColorFPRec; - PColorFPRecArray = ^TColorFPRecArray; - - { 16 bit floating-point value. It has 1 sign bit, 5 exponent bits, - and 10 mantissa bits.} - THalfFloat = type Word; - PHalfFloat = ^THalfFloat; - - { Color record for 64 bit floating point images, which allows access to - individual color channels.} - TColorHFRec = packed record - case LongInt of - 0: (B, G, R, A: THalfFloat); - 1: (Channels: array[0..3] of THalfFloat); - end; - PColorHFRec = ^TColorHFRec; - TColorHFRecArray = array[0..MaxInt div SizeOf(TColorHFRec) - 1] of TColorHFRec; - PColorHFRecArray = ^TColorHFRecArray; - - { Palette for indexed mode images with 32 bit colors.} - TPalette32 = TColor32RecArray; - TPalette32Size256 = array[0..255] of TColor32Rec; - PPalette32 = ^TPalette32; - - { Palette for indexd mode images with 24 bit colors.} - TPalette24 = TColor24RecArray; - TPalette24Size256 = array[0..255] of TColor24Rec; - PPalette24 = ^TPalette24; - - { Record that stores single image data and information describing it.} - TImageData = packed record - Width: LongInt; // Width of image in pixels - Height: LongInt; // Height of image in pixels - Format: TImageFormat; // Data format of image - Size: LongInt; // Size of image bits in Bytes - Bits: Pointer; // Pointer to memory containing image bits - Palette: PPalette32; // Image palette for indexed images - Tag: Pointer; // User data - end; - PImageData = ^TImageData; - - { Pixel format information used in conversions to/from 16 and 8 bit ARGB - image formats.} - TPixelFormatInfo = packed record - ABitCount, RBitCount, GBitCount, BBitCount: Byte; - ABitMask, RBitMask, GBitMask, BBitMask: LongWord; - AShift, RShift, GShift, BShift: Byte; - ARecDiv, RRecDiv, GRecDiv, BRecDiv: Byte; - end; - PPixelFormatInfo = ^TPixelFormatInfo; - - PImageFormatInfo = ^TImageFormatInfo; - - { Look at TImageFormatInfo.GetPixelsSize for details.} - TFormatGetPixelsSizeFunc = function(Format: TImageFormat; Width, - Height: LongInt): LongInt; - { Look at TImageFormatInfo.CheckDimensions for details.} - TFormatCheckDimensionsProc = procedure(Format: TImageFormat; var Width, - Height: LongInt); - { Function for getting pixel colors. Native pixel is read from Image and - then translated to 32 bit ARGB.} - TGetPixel32Func = function(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32): TColor32Rec; - { Function for getting pixel colors. Native pixel is read from Image and - then translated to FP ARGB.} - TGetPixelFPFunc = function(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32): TColorFPRec; - { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to - native format and then written to Image.} - TSetPixel32Proc = procedure(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32;const Color: TColor32Rec); - { Procedure for setting pixel colors. Input FP ARGB color is translated to - native format and then written to Image.} - TSetPixelFPProc = procedure(Bits: Pointer; Info: PImageFormatInfo; - Palette: PPalette32; const Color: TColorFPRec); - - { Additional information for each TImageFormat value.} - TImageFormatInfo = packed record - Format: TImageFormat; // Format described by this record - Name: array[0..15] of Char; // Symbolic name of format - BytesPerPixel: LongInt; // Number of bytes per pixel (note: it is - // 0 for formats where BitsPerPixel < 8 (e.g. DXT). - // Use GetPixelsSize function to get size of - // image data. - ChannelCount: LongInt; // Number of image channels (R, G, B, A, Gray) - PaletteEntries: LongInt; // Number of palette entries - HasGrayChannel: Boolean; // True if image has grayscale channel - HasAlphaChannel: Boolean; // True if image has alpha channel - IsFloatingPoint: Boolean; // True if image has floating point pixels - UsePixelFormat: Boolean; // True if image uses pixel format - IsRBSwapped: Boolean; // True if Red and Blue channels are swapped - // e.g. A16B16G16R16 has IsRBSwapped True - RBSwapFormat: TImageFormat; // Indicates supported format with swapped - // Red and Blue channels, ifUnknown if such - // format does not exist - IsIndexed: Boolean; // True if image uses palette - IsSpecial: Boolean; // True if image is in special format - IsPasstrough: Boolean; // True if image is in passtrough program (Imaging - // iself doesn't know how to decode and encode it - - // complex texture compressions etc.) - PixelFormat: PPixelFormatInfo; // Pixel format structure - GetPixelsSize: TFormatGetPixelsSizeFunc; // Returns size in bytes of - // Width * Height pixels of image - CheckDimensions: TFormatCheckDimensionsProc; // some formats have limited - // values of Width and Height. This - // procedure checks and changes dimensions - // to be valid for given format. - GetPixel32: TGetPixel32Func; // 32bit ARGB pixel get function - GetPixelFP: TGetPixelFPFunc; // FP ARGB pixel get function - SetPixel32: TSetPixel32Proc; // 32bit ARGB pixel set procedure - SetPixelFP: TSetPixelFPProc; // FP ARGB pixel set procedure - SpecialNearestFormat: TImageFormat; // Regular image format used when - // compressing/decompressing special images - // as source/target - end; - - { Handle to list of image data records.} - TImageDataList = Pointer; - PImageDataList = ^TImageDataList; - - { Handle to input/output.} - TImagingHandle = Pointer; - - { Filters used in functions that resize images or their portions.} - TResizeFilter = ( - rfNearest = 0, - rfBilinear = 1, - rfBicubic = 2, - rfLanczos = 3); - - { Seek origin mode for IO function Seek.} - TSeekMode = ( - smFromBeginning = 0, - smFromCurrent = 1, - smFromEnd = 2); - - TOpenMode = ( - omReadOnly = 0, // Opens file for reading only - omCreate = 1, // Creates new file (overwriting any existing) and opens it for writing - omReadWrite = 2 // Opens for reading and writing. Non existing file is created. - ); - - { IO functions used for reading and writing images from/to input/output.} - TOpenProc = function(Source: PChar; Mode: TOpenMode): TImagingHandle; cdecl; - TCloseProc = procedure(Handle: TImagingHandle); cdecl; - TEofProc = function(Handle: TImagingHandle): Boolean; cdecl; - TSeekProc = function(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): LongInt; cdecl; - TTellProc = function(Handle: TImagingHandle): LongInt; cdecl; - TReadProc = function(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; - TWriteProc = function(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; - -{$IFNDEF FPC} -type -{$IF CompilerVersion <= 18.5} - PtrUInt = LongWord; -{$ELSE} - PtrUInt = NativeUInt; -{$IFEND} -{$ENDIF} - -implementation - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - add lookup tables to pixel formats for fast conversions - - -- 0.77.1 --------------------------------------------------- - - Added "Passtrough" image data formats. - - Added Tag to TImageData for storing user data. - - Added ImagingPNGZLibStrategy option. - - Changed IO functions. Merged open functions to one - and added third open mode R/W (for TIFF append etc.). - - Added new image data formats and related structures: - ifR32G32B32F, ifB32G32G32F. - - -- 0.26.5 Changes/Bug Fixes --------------------------------- - - Added ifBinary image format and ImagingBinaryTreshold option. - - Lanczos filter added to TResizeFilter enum. - - -- 0.24.3 Changes/Bug Fixes --------------------------------- - - Added ifATI1N and ifATI2N image data formats. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added ifBTC image format and SpecialNearestFormat field - to TImageFormatInfo. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Added option constants for PGM and PPM file formats. - - Added TPalette32Size256 and TPalette24Size256 types. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - added ImagingVersionPatch constant so bug fix only releases - can be distinguished from ordinary major/minor releases - - renamed TPixelFormat to TPixelFormatInfo to avoid name collisions - with Graphics.TPixelFormat - - added new image data formats: ifR16F, ifA16R16G16B16F, - ifA16B16G16R16F - - added pixel get/set function pointers to TImageFormatInfo - - added 16bit half float type and color record - - renamed TColorFRec to TColorFPRec (and related types too) - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - added option ImagingMipMapFilter which now controls resampling filter - used when generating mipmaps - - added TResizeFilter type - - added ChannelCount to TImageFormatInfo - - added new option constants for MNG and JNG images - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - added RBSwapFormat to TImageFormatInfo for faster conversions - between swapped formats (it just calls SwapChannels now if - RBSwapFormat is not ifUnknown) - - moved TImageFormatInfo and required types from Imaging unit - here, removed TImageFormatShortInfo - - added new options: ImagingLoadOverrideFormat, ImagingSaveOverrideFormat - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - new ImagingColorReductionMask option added - - new image format added: ifA16Gray16 - -} - -end. diff --git a/3rd/Imaging/Source/ImagingUtility.pas b/3rd/Imaging/Source/ImagingUtility.pas deleted file mode 100644 index 00f43e747..000000000 --- a/3rd/Imaging/Source/ImagingUtility.pas +++ /dev/null @@ -1,1693 +0,0 @@ -{ - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - The contents of this file are used with permission, subject to the Mozilla - Public License Version 1.1 (the "License"); you may not use this file except - in compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/MPL-1.1.html - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - Alternatively, the contents of this file may be used under the terms of the - GNU Lesser General Public License (the "LGPL License"), in which case the - provisions of the LGPL License are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the LGPL License and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the LGPL - License. If you do not delete the provisions above, a recipient may use - your version of this file under either the MPL or the LGPL License. - - For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html -} - -{ This unit contains utility functions and types for Imaging library.} -unit ImagingUtility; - -{$I ImagingOptions.inc} - -interface - -uses - SysUtils, Classes, Types; - -const - STrue = 'True'; - SFalse = 'False'; - -type - TByteArray = array[0..MaxInt - 1] of Byte; - PByteArray = ^TByteArray; - TWordArray = array[0..MaxInt div 2 - 1] of Word; - PWordArray = ^TWordArray; - TLongIntArray = array[0..MaxInt div 4 - 1] of LongInt; - PLongIntArray = ^TLongIntArray; - TLongWordArray = array[0..MaxInt div 4 - 1] of LongWord; - PLongWordArray = ^TLongWordArray; - TInt64Array = array[0..MaxInt div 8 - 1] of Int64; - PInt64Array = ^TInt64Array; - TSingleArray = array[0..MaxInt div 4 - 1] of Single; - PSingleArray = ^TSingleArray; - TBooleanArray = array[0..MaxInt - 1] of Boolean; - PBooleanArray = ^TBooleanArray; - - TDynByteArray = array of Byte; - TDynIntegerArray = array of Integer; - TDynBooleanArray = array of Boolean; - TDynStringArray = array of string; - - TWordRec = packed record - case Integer of - 0: (WordValue: Word); - 1: (Low, High: Byte); - end; - PWordRec = ^TWordRec; - TWordRecArray = array[0..MaxInt div 2 - 1] of TWordRec; - PWordRecArray = ^TWordRecArray; - - TLongWordRec = packed record - case Integer of - 0: (LongWordValue: LongWord); - 1: (Low, High: Word); - { Array variants - Index 0 means lowest significant byte (word, ...).} - 2: (Words: array[0..1] of Word); - 3: (Bytes: array[0..3] of Byte); - end; - PLongWordRec = ^TLongWordRec; - TLongWordRecArray = array[0..MaxInt div 4 - 1] of TLongWordRec; - PLongWordRecArray = ^TLongWordRecArray; - - TInt64Rec = packed record - case Integer of - 0: (Int64Value: Int64); - 1: (Low, High: LongWord); - { Array variants - Index 0 means lowest significant byte (word, ...).} - 2: (Words: array[0..3] of Word); - 3: (Bytes: array[0..7] of Byte); - end; - PInt64Rec = ^TInt64Rec; - TInt64RecArray = array[0..MaxInt div 8 - 1] of TInt64Rec; - PInt64RecArray = ^TInt64RecArray; - - TFloatHelper = record - Data: Int64; - case Integer of - 0: (Data64: Int64); - 1: (Data32: LongWord); - end; - PFloatHelper = ^TFloatHelper; - - TFloatRect = record - Left, Top, Right, Bottom: Single; - end; - - TChar2 = array[0..1] of AnsiChar; - TChar3 = array[0..2] of AnsiChar; - TChar4 = array[0..3] of AnsiChar; - TChar8 = array[0..7] of AnsiChar; - TChar16 = array[0..15] of AnsiChar; - TAnsiCharSet = set of AnsiChar; - - ENotImplemented = class(Exception) - public - constructor Create; - end; - - { Options for BuildFileList function: - flFullNames - file names in result will have full path names - (ExtractFileDir(Path) + FileName) - flRelNames - file names in result will have names relative to - ExtractFileDir(Path) dir - flRecursive - adds files in subdirectories found in Path.} - TFileListOption = (flFullNames, flRelNames, flRecursive); - TFileListOptions = set of TFileListOption; - - -{ Frees class instance and sets its reference to nil.} -procedure FreeAndNil(var Obj); -{ Frees pointer and sets it to nil.} -procedure FreeMemNil(var P); {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Replacement of standard System.FreeMem procedure which checks if P is nil - (this is only needed for Free Pascal, Delphi makes checks in its FreeMem).} -procedure FreeMem(P: Pointer); {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns current exception object. Do not call outside exception handler.} -function GetExceptObject: Exception; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns time value with microsecond resolution.} -function GetTimeMicroseconds: Int64; -{ Returns time value with milisecond resolution.} -function GetTimeMilliseconds: Int64; - -{ Returns file extension (without "." dot)} -function GetFileExt(const FileName: string): string; -{ Returns file name of application's executable.} -function GetAppExe: string; -{ Returns directory where application's exceutable is located without - path delimiter at the end.} -function GetAppDir: string; -{ Works like SysUtils.ExtractFileName but supports '/' and '\' dir delimiters - at the same time (whereas ExtractFileName supports on default delimiter on current platform).} -function GetFileName(const FileName: string): string; -{ Works like SysUtils.ExtractFileDir but supports '/' and '\' dir delimiters - at the same time (whereas ExtractFileDir supports on default delimiter on current platform).} -function GetFileDir(const FileName: string): string; -{ Returns True if Subject matches given Mask with optional case sensitivity. - Mask can contain ? and * special characters: ? matches - one character, * matches zero or more characters.} -function StrMaskMatch(const Subject, Mask: string; CaseSensitive: Boolean = False): Boolean; -{ This function fills Files string list with names of files found - with FindFirst/FindNext functions (See details on Path/Atrr here). - - BuildFileList('c:\*.*', faAnyFile, List, [flRecursive]) returns - list of all files (only name.ext - no path) on C drive - - BuildFileList('d:\*.*', faDirectory, List, [flFullNames]) returns - list of all directories (d:\dirxxx) in root of D drive.} -function BuildFileList(Path: string; Attr: LongInt; Files: TStrings; - Options: TFileListOptions = []): Boolean; -{ Similar to RTL's Pos function but with optional Offset where search will start. - This function is in the RTL StrUtils unit but } -function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt; -{ Same as PosEx but without case sensitivity.} -function PosNoCase(const SubStr, S: string; Offset: LongInt = 1): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns a sub-string from S which is followed by - Sep separator and deletes the sub-string from S including the separator.} -function StrToken(var S: string; Sep: Char): string; -{ Same as StrToken but searches from the end of S string.} -function StrTokenEnd(var S: string; Sep: Char): string; -{ Fills instance of TStrings with tokens from string S where tokens are separated by - one of Seps characters.} -procedure StrTokensToList(const S: string; Sep: Char; Tokens: TStrings); -{ Returns string representation of integer number (with digit grouping). - Uses current locale.} -function IntToStrFmt(const I: Int64): string; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns string representation of float number (with digit grouping). - Uses current locale.} -function FloatToStrFmt(const F: Double; Precision: Integer = 2): string; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns format settings for parsing floats (dot as decimal separator). - Useful when fomatting/parsing floats etc.} -function GetFormatSettingsForFloats: TFormatSettings; -{ Returns True if S contains at least one of the substrings in SubStrs array. Case sensitive.} -function ContainsAnySubStr(const S: string; const SubStrs: array of string): Boolean; -{ Extracts substring starting at IdxStart ending at IdxEnd. - S[IdxEnd] is not included in the result.} -function SubString(const S: string; IdxStart, IdxEnd: Integer): string; {$IFDEF USE_INLINE}inline;{$ENDIF} - -{ Clamps integer value to range <Min, Max>} -function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Clamps float value to range <Min, Max>} -function ClampFloat(Number: Single; Min, Max: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Clamps integer value to Byte boundaries.} -function ClampToByte(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Clamps integer value to Word boundaries.} -function ClampToWord(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns True if Num is power of 2.} -function IsPow2(Num: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns next power of 2 greater than or equal to Num - (if Num itself is power of 2 then it retuns Num).} -function NextPow2(Num: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Raises 2 to the given integer power (in range [0, 30]).} -function Pow2Int(Exponent: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Raises Base to any power.} -function Power(const Base, Exponent: Single): Single; -{ Returns log base 2 of integer X (max 2^30) or -1 if X is not power of 2.} -function Log2Int(X: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns log base 2 of X.} -function Log2(X: Single): Single; -{ Returns log base 10 of X.} -function Log10(X: Single): Single; -{ Returns largest integer <= Val (for 5.9 returns 5).} -function Floor(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns smallest integer >= Val (for 5.1 returns 6).} -function Ceil(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns lesser of two integer numbers.} -function Min(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns lesser of two float numbers.} -function MinFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns greater of two integer numbers.} -function Max(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns greater of two float numbers.} -function MaxFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns result from multiplying Number by Numerator and then dividing by Denominator. - Denominator must be greater than 0.} -function MulDiv(Number, Numerator, Denominator: Word): Word; {$IFDEF USE_INLINE}inline;{$ENDIF} - -{ Switches Boolean value.} -procedure Switch(var Value: Boolean); {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ If Condition is True then TruePart is retured, otherwise - FalsePart is returned.} -function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Swaps two Boolean values} -procedure SwapValues(var A, B: Boolean); overload; -{ Swaps two Byte values} -procedure SwapValues(var A, B: Byte); overload; -{ Swaps two Word values} -procedure SwapValues(var A, B: Word); overload; -{ Swaps two LongInt values} -procedure SwapValues(var A, B: LongInt); overload; -{ Swaps two Single values} -procedure SwapValues(var A, B: Single); overload; -{ Swaps two LongInt values if necessary to ensure that Min <= Max.} -procedure SwapMin(var Min, Max: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} -{ This function returns True if running on little endian machine.} -function IsLittleEndian: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Swaps byte order of Word value.} -function SwapEndianWord(Value: Word): Word; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Swaps byte order of multiple Word values.} -procedure SwapEndianWord(P: PWordArray; Count: LongInt); overload; -{ Swaps byte order of LongWord value.} -function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Swaps byte order of multiple LongWord values.} -procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); overload; - -{ Calculates CRC32 for the given data.} -procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt); -{ Fills given memory with given Byte value. Size is size of buffer in bytes.} -procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte); -{ Fills given memory with given Word value. Size is size of buffer in bytes.} -procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word); -{ Fills given memory with given LongWord value. Size is size of buffer in bytes.} -procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord); -{ Fills given memory zeroes.} -{$EXTERNALSYM ZeroMemory} // Conflicts with WinAPI ZeroMemory in C++ Builder -procedure ZeroMemory(Data: Pointer; Size: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} - -{ Returns how many mipmap levels can be created for image of given size.} -function GetNumMipMapLevels(Width, Height: LongInt): LongInt; -{ Returns total number of levels of volume texture with given depth and - mipmap count (this is not depth * mipmaps!).} -function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt; -{ Returns rectangle (X, Y, X + Width, Y + Height).} -function BoundsToRect(X, Y, Width, Height: LongInt): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns rectangle (R.Left, R.Top, R.Left + R.Right, R.Top + R.Bottom).} -function BoundsToRect(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Returns rectangle (R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top).} -function RectToBounds(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} -{ Clips given bounds to Clip rectangle.} -procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect); -{ Clips given source bounds and dest position. It is used by various CopyRect - functions that copy rect from one image to another. It handles clipping the same way - as Win32 BitBlt function. } -procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; - SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); -{ Clips given source bounds and dest bounds. It is used by various StretchRect - functions that stretch rectangle of pixels from one image to another. - It handles clipping the same way as Win32 StretchBlt function. } -procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, - DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); -{ Scales one rectangle to fit into another. Proportions are preserved so - it could be used for 'Stretch To Fit Window' image drawing for instance.} -function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect; -{ Scales given size to fit into max size while keeping the original ascpect ration. - Useful for calculating thumbnail dimensions etc.} -function ScaleSizeToFit(const CurrentSize, MaxSize: TSize): TSize; -{ Returns width of given rect. Part of RTL in newer Delphi.} -function RectWidth(const Rect: TRect): Integer; -{ Returns height of given rect. Part of RTL in newer Delphi.} -function RectHeight(const Rect: TRect): Integer; -{ Returns True if R1 fits into R2.} -function RectInRect(const R1, R2: TRect): Boolean; -{ Returns True if R1 and R2 intersects.} -function RectIntersects(const R1, R2: TRect): Boolean; - -{ Converts pixel size in micrometers to corrensponding DPI.} -function PixelSizeToDpi(SizeInMicroMeters: Single): Single; -{ Converts DPI to corrensponding pixel size in micrometers.} -function DpiToPixelSize(Dpi: Single): Single; - -function FloatRect(ALeft, ATop, ARight, ABottom: Single): TFloatRect; -function FloatRectWidth(const R: TFloatRect): Single; -function FloatRectHeight(const R: TFloatRect): Single; - -{ Formats given message for usage in Exception.Create(..). Use only - in except block - returned message contains message of last raised exception.} -function FormatExceptMsg(const Msg: string; const Args: array of const): string; -{ Outputs debug message - shows message dialog in Windows and writes to console - in Linux/Unix.} -procedure DebugMsg(const Msg: string; const Args: array of const); - -implementation - -uses -{$IF Defined(MSWINDOWS)} - Windows; -{$ELSEIF Defined(FPC)} - Dos, BaseUnix, Unix; -{$ELSEIF Defined(DELPHI)} - Posix.SysTime; -{$IFEND} - -var - FloatFormatSettings: TFormatSettings; - -constructor ENotImplemented.Create; -begin - inherited Create('Not implemented'); -end; - -procedure FreeAndNil(var Obj); -var - Temp: TObject; -begin - Temp := TObject(Obj); - Pointer(Obj) := nil; - Temp.Free; -end; - -procedure FreeMemNil(var P); -begin - FreeMem(Pointer(P)); - Pointer(P) := nil; -end; - -procedure FreeMem(P: Pointer); -begin - if P <> nil then - System.FreeMem(P); -end; - -function GetExceptObject: Exception; -begin - Result := Exception(ExceptObject); -end; - -{$IF Defined(MSWINDOWS)} -var - PerfFrequency: Int64; - InvPerfFrequency: Single; - -function GetTimeMicroseconds: Int64; -var - Time: Int64; -begin - QueryPerformanceCounter(Time); - Result := Round(1000000 * InvPerfFrequency * Time); -end; -{$ELSEIF Defined(DELPHI)} -function GetTimeMicroseconds: Int64; -var - Time: TimeVal; -begin - Posix.SysTime.GetTimeOfDay(Time, nil); - Result := Int64(Time.tv_sec) * 1000000 + Time.tv_usec; -end; -{$ELSEIF Defined(FPC)} -function GetTimeMicroseconds: Int64; -var - TimeVal: TTimeVal; -begin - fpGetTimeOfDay(@TimeVal, nil); - Result := Int64(TimeVal.tv_sec) * 1000000 + TimeVal.tv_usec; -end; -{$IFEND} - -function GetTimeMilliseconds: Int64; -begin - Result := GetTimeMicroseconds div 1000; -end; - -function GetFileExt(const FileName: string): string; -begin - Result := ExtractFileExt(FileName); - if Length(Result) > 1 then - Delete(Result, 1, 1); -end; - -function GetAppExe: string; -{$IF Defined(MSWINDOWS)} -var - FileName: array[0..MAX_PATH] of Char; -begin - SetString(Result, FileName, - Windows.GetModuleFileName(MainInstance, FileName, SizeOf(FileName))); -{$ELSEIF Defined(DELPHI)} // Delphi non Win targets -var - FileName: array[0..1024] of Char; -begin - SetString(Result, FileName, - System.GetModuleFileName(MainInstance, FileName, SizeOf(FileName))); -{$ELSE} -begin - Result := ParamStr(0); -{$IFEND} -end; - -function GetAppDir: string; -begin - Result := ExtractFileDir(GetAppExe); -end; - -function GetFileName(const FileName: string): string; -var - I: Integer; -begin - I := LastDelimiter('\/' + DriveDelim, FileName); - Result := Copy(FileName, I + 1, MaxInt); -end; - -function GetFileDir(const FileName: string): string; -const - Delims = '\/' + DriveDelim; -var - I: Integer; -begin - I := LastDelimiter(Delims, Filename); - if (I > 1) and - ((FileName[I] = Delims[1]) or (FileName[I] = Delims[2])) and - (not IsDelimiter(Delims, FileName, I - 1)) then Dec(I); - Result := Copy(FileName, 1, I); -end; - -function StrMaskMatch(const Subject, Mask: string; CaseSensitive: Boolean): Boolean; -var - MaskLen, KeyLen : LongInt; - - function CharMatch(A, B: Char): Boolean; - begin - if CaseSensitive then - Result := A = B - else - Result := AnsiUpperCase (A) = AnsiUpperCase (B); - end; - - function MatchAt(MaskPos, KeyPos: LongInt): Boolean; - begin - while (MaskPos <= MaskLen) and (KeyPos <= KeyLen) do - begin - case Mask[MaskPos] of - '?' : - begin - Inc(MaskPos); - Inc(KeyPos); - end; - '*' : - begin - while (MaskPos <= MaskLen) and (Mask[MaskPos] = '*') do - Inc(MaskPos); - if MaskPos > MaskLen then - begin - Result := True; - Exit; - end; - repeat - if MatchAt(MaskPos, KeyPos) then - begin - Result := True; - Exit; - end; - Inc(KeyPos); - until KeyPos > KeyLen; - Result := False; - Exit; - end; - else - if not CharMatch(Mask[MaskPos], Subject[KeyPos]) then - begin - Result := False; - Exit; - end - else - begin - Inc(MaskPos); - Inc(KeyPos); - end; - end; - end; - - while (MaskPos <= MaskLen) and (AnsiChar(Mask[MaskPos]) in ['?', '*']) do - Inc(MaskPos); - if (MaskPos <= MaskLen) or (KeyPos <= KeyLen) then - begin - Result := False; - Exit; - end; - - Result := True; - end; - -begin - MaskLen := Length(Mask); - KeyLen := Length(Subject); - if MaskLen = 0 then - begin - Result := True; - Exit; - end; - Result := MatchAt(1, 1); -end; - -function BuildFileList(Path: string; Attr: LongInt; - Files: TStrings; Options: TFileListOptions): Boolean; -var - FileMask: string; - RootDir: string; - Folders: TStringList; - CurrentItem: LongInt; - Counter: LongInt; - LocAttr: LongInt; - - procedure BuildFolderList; - var - FindInfo: TSearchRec; - Rslt: LongInt; - begin - Counter := Folders.Count - 1; - CurrentItem := 0; - while CurrentItem <= Counter do - begin - // Searching for subfolders - Rslt := SysUtils.FindFirst(Folders[CurrentItem] + '*', faDirectory, FindInfo); - try - while Rslt = 0 do - begin - if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') and - (FindInfo.Attr and faDirectory = faDirectory) then - Folders.Add(Folders[CurrentItem] + FindInfo.Name + PathDelim); - Rslt := SysUtils.FindNext(FindInfo); - end; - finally - SysUtils.FindClose(FindInfo); - end; - Counter := Folders.Count - 1; - Inc(CurrentItem); - end; - end; - - procedure FillFileList(CurrentCounter: LongInt); - var - FindInfo: TSearchRec; - Res: LongInt; - CurrentFolder: string; - begin - CurrentFolder := Folders[CurrentCounter]; - Res := SysUtils.FindFirst(CurrentFolder + FileMask, LocAttr, FindInfo); - if flRelNames in Options then - CurrentFolder := ExtractRelativePath(RootDir, CurrentFolder); - try - while Res = 0 do - begin - if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') then - begin - if (flFullNames in Options) or (flRelNames in Options) then - Files.Add(CurrentFolder + FindInfo.Name) - else - Files.Add(FindInfo.Name); - end; - Res := SysUtils.FindNext(FindInfo); - end; - finally - SysUtils.FindClose(FindInfo); - end; - end; - -begin - FileMask := ExtractFileName(Path); - RootDir := ExtractFilePath(Path); - Folders := TStringList.Create; - Folders.Add(RootDir); - Files.Clear; -{$IFDEF DCC} - {$WARN SYMBOL_PLATFORM OFF} -{$ENDIF} - if Attr = faAnyFile then - LocAttr := faSysFile or faHidden or faArchive or faReadOnly - else - LocAttr := Attr; -{$IFDEF DCC} - {$WARN SYMBOL_PLATFORM ON} -{$ENDIF} - // Here's the recursive search for nested folders - if flRecursive in Options then - BuildFolderList; - if Attr <> faDirectory then - for Counter := 0 to Folders.Count - 1 do - FillFileList(Counter) - else - Files.AddStrings(Folders); - Folders.Free; - Result := True; -end; - -function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt; -var - I, X: LongInt; - Len, LenSubStr: LongInt; -begin - I := Offset; - LenSubStr := Length(SubStr); - Len := Length(S) - LenSubStr + 1; - while I <= Len do - begin - if S[I] = SubStr[1] then - begin - X := 1; - while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do - Inc(X); - if (X = LenSubStr) then - begin - Result := I; - Exit; - end; - end; - Inc(I); - end; - Result := 0; -end; - -function PosNoCase(const SubStr, S: string; Offset: LongInt): LongInt; -begin - Result := PosEx(AnsiLowerCase(SubStr), AnsiLowerCase(S), Offset); -end; - -function StrToken(var S: string; Sep: Char): string; -var - I: LongInt; -begin - I := Pos(Sep, S); - if I <> 0 then - begin - Result := Copy(S, 1, I - 1); - Delete(S, 1, I); - end - else - begin - Result := S; - S := ''; - end; -end; - -function StrTokenEnd(var S: string; Sep: Char): string; -var - I, J: LongInt; -begin - J := 0; - I := Pos(Sep, S); - while I <> 0 do - begin - J := I; - I := PosEx(Sep, S, J + 1); - end; - if J <> 0 then - begin - Result := Copy(S, J + 1, MaxInt); - Delete(S, J, MaxInt); - end - else - begin - Result := S; - S := ''; - end; -end; - -procedure StrTokensToList(const S: string; Sep: Char; Tokens: TStrings); -var - Token, Str: string; -begin - Tokens.Clear; - Str := S; - while Str <> '' do - begin - Token := StrToken(Str, Sep); - Tokens.Add(Token); - end; -end; - -function IntToStrFmt(const I: Int64): string; -begin - Result := Format('%.0n', [I * 1.0]); -end; - -function FloatToStrFmt(const F: Double; Precision: Integer): string; -begin - Result := Format('%.' + IntToStr(Precision) + 'n', [F]); -end; - -function GetFormatSettingsForFloats: TFormatSettings; -begin - Result := FloatFormatSettings; -end; - -function ContainsAnySubStr(const S: string; const SubStrs: array of string): Boolean; -var - I: Integer; -begin - Result := False; - for I := 0 to High(SubStrs) do - begin - Result := Pos(SubStrs[I], S) > 0; - if Result then - Exit; - end; -end; - -function SubString(const S: string; IdxStart, IdxEnd: Integer): string; -begin - Result := Copy(S, IdxStart, IdxEnd - IdxStart); -end; - -function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; -begin - Result := Number; - if Result < Min then - Result := Min - else if Result > Max then - Result := Max; -end; - -function ClampFloat(Number: Single; Min, Max: Single): Single; -begin - Result := Number; - if Result < Min then - Result := Min - else if Result > Max then - Result := Max; -end; - -function ClampToByte(Value: LongInt): LongInt; -begin - Result := Value; - if Result > 255 then - Result := 255 - else if Result < 0 then - Result := 0; -end; - -function ClampToWord(Value: LongInt): LongInt; -begin - Result := Value; - if Result > 65535 then - Result := 65535 - else if Result < 0 then - Result := 0; -end; - -function IsPow2(Num: LongInt): Boolean; -begin - Result := (Num and -Num) = Num; -end; - -function NextPow2(Num: LongInt): LongInt; -begin - Result := Num and -Num; - while Result < Num do - Result := Result shl 1; -end; - -function Pow2Int(Exponent: LongInt): LongInt; -begin - Result := 1 shl Exponent; -end; - -function Power(const Base, Exponent: Single): Single; -begin - if Exponent = 0.0 then - Result := 1.0 - else if (Base = 0.0) and (Exponent > 0.0) then - Result := 0.0 - else - Result := Exp(Exponent * Ln(Base)); -end; - -function Log2Int(X: LongInt): LongInt; -begin - case X of - 1: Result := 0; - 2: Result := 1; - 4: Result := 2; - 8: Result := 3; - 16: Result := 4; - 32: Result := 5; - 64: Result := 6; - 128: Result := 7; - 256: Result := 8; - 512: Result := 9; - 1024: Result := 10; - 2048: Result := 11; - 4096: Result := 12; - 8192: Result := 13; - 16384: Result := 14; - 32768: Result := 15; - 65536: Result := 16; - 131072: Result := 17; - 262144: Result := 18; - 524288: Result := 19; - 1048576: Result := 20; - 2097152: Result := 21; - 4194304: Result := 22; - 8388608: Result := 23; - 16777216: Result := 24; - 33554432: Result := 25; - 67108864: Result := 26; - 134217728: Result := 27; - 268435456: Result := 28; - 536870912: Result := 29; - 1073741824: Result := 30; - else - Result := -1; - end; -end; - -function Log2(X: Single): Single; -{$IFDEF USE_ASM} -asm - FLD1 - FLD X - FYL2X - FWAIT -end; -{$ELSE} -const - Ln2: Single = 0.6931471; -begin - Result := Ln(X) / Ln2; -end; -{$ENDIF} - -function Log10(X: Single): Single; -{$IFDEF USE_ASM} -asm - FLDLG2 - FLD X - FYL2X - FWAIT -end; -{$ELSE} -const - Ln10: Single = 2.30258509299405; -begin - Result := Ln(X) / Ln10; -end; -{$ENDIF} - -function Floor(Value: Single): LongInt; -begin - Result := Trunc(Value); - if Frac(Value) < 0.0 then - Dec(Result); -end; - -function Ceil(Value: Single): LongInt; -begin - Result := Trunc(Value); - if Frac(Value) > 0.0 then - Inc(Result); -end; - -procedure Switch(var Value: Boolean); -begin - Value := not Value; -end; - -function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; -begin - if Condition then - Result := TruePart - else - Result := FalsePart; -end; - -procedure SwapValues(var A, B: Boolean); -var - Tmp: Boolean; -begin - Tmp := A; - A := B; - B := Tmp; -end; - -procedure SwapValues(var A, B: Byte); -var - Tmp: Byte; -begin - Tmp := A; - A := B; - B := Tmp; -end; - -procedure SwapValues(var A, B: Word); -var - Tmp: Word; -begin - Tmp := A; - A := B; - B := Tmp; -end; - -procedure SwapValues(var A, B: LongInt); -var - Tmp: LongInt; -begin - Tmp := A; - A := B; - B := Tmp; -end; - -procedure SwapValues(var A, B: Single); -var - Tmp: Single; -begin - Tmp := A; - A := B; - B := Tmp; -end; - -procedure SwapMin(var Min, Max: LongInt); -var - Tmp: LongInt; -begin - if Min > Max then - begin - Tmp := Min; - Min := Max; - Max := Tmp; - end; -end; - -function Min(A, B: LongInt): LongInt; -begin - if A < B then - Result := A - else - Result := B; -end; - -function MinFloat(A, B: Single): Single; -begin - if A < B then - Result := A - else - Result := B; -end; - -function Max(A, B: LongInt): LongInt; -begin - if A > B then - Result := A - else - Result := B; -end; - -function MaxFloat(A, B: Single): Single; -begin - if A > B then - Result := A - else - Result := B; -end; - -function MulDiv(Number, Numerator, Denominator: Word): Word; -{$IF Defined(USE_ASM) and (not Defined(USE_INLINE))} -asm - MUL DX - DIV CX -end; -{$ELSE} -begin - Result := Number * Numerator div Denominator; -end; -{$IFEND} - -function IsLittleEndian: Boolean; -var - W: Word; -begin - W := $00FF; - Result := PByte(@W)^ = $FF; -end; - -function SwapEndianWord(Value: Word): Word; -{$IF Defined(USE_ASM) and (not Defined(USE_INLINE))} -asm - XCHG AH, AL -end; -{$ELSE} -begin - TWordRec(Result).Low := TWordRec(Value).High; - TWordRec(Result).High := TWordRec(Value).Low; -end; -{$IFEND} - -procedure SwapEndianWord(P: PWordArray; Count: LongInt); -{$IFDEF USE_ASM} -asm -@Loop: - MOV CX, [EAX] - XCHG CH, CL - MOV [EAX], CX - ADD EAX, 2 - DEC EDX - JNZ @Loop -end; -{$ELSE} -var - I: LongInt; - Temp: Word; -begin - for I := 0 to Count - 1 do - begin - Temp := P[I]; - TWordRec(P[I]).Low := TWordRec(Temp).High; - TWordRec(P[I]).High := TWordRec(Temp).Low; - end; -end; -{$ENDIF} - -function SwapEndianLongWord(Value: LongWord): LongWord; -{$IF Defined(USE_ASM) and (not Defined(USE_INLINE))} -asm - BSWAP EAX -end; -{$ELSE} -begin - TLongWordRec(Result).Bytes[0] := TLongWordRec(Value).Bytes[3]; - TLongWordRec(Result).Bytes[1] := TLongWordRec(Value).Bytes[2]; - TLongWordRec(Result).Bytes[2] := TLongWordRec(Value).Bytes[1]; - TLongWordRec(Result).Bytes[3] := TLongWordRec(Value).Bytes[0]; -end; -{$IFEND} - -procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); -{$IFDEF USE_ASM} -asm -@Loop: - MOV ECX, [EAX] - BSWAP ECX - MOV [EAX], ECX - ADD EAX, 4 - DEC EDX - JNZ @Loop -end; -{$ELSE} -var - I: LongInt; - Temp: LongWord; -begin - for I := 0 to Count - 1 do - begin - Temp := PLongWordArray(P)[I]; - TLongWordRec(PLongWordArray(P)[I]).Bytes[0] := TLongWordRec(Temp).Bytes[3]; - TLongWordRec(PLongWordArray(P)[I]).Bytes[1] := TLongWordRec(Temp).Bytes[2]; - TLongWordRec(PLongWordArray(P)[I]).Bytes[2] := TLongWordRec(Temp).Bytes[1]; - TLongWordRec(PLongWordArray(P)[I]).Bytes[3] := TLongWordRec(Temp).Bytes[0]; - end; -end; -{$ENDIF} - -type - TCrcTable = array[Byte] of LongWord; -var - CrcTable: TCrcTable; - -procedure InitCrcTable; -const - Polynom = $EDB88320; -var - I, J: LongInt; - C: LongWord; -begin - for I := 0 to 255 do - begin - C := I; - for J := 0 to 7 do - begin - if (C and $01) <> 0 then - C := Polynom xor (C shr 1) - else - C := C shr 1; - end; - CrcTable[I] := C; - end; -end; - -procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt); -var - I: LongInt; - B: PByte; -begin - B := Data; - for I := 0 to Size - 1 do - begin - Crc := (Crc shr 8) xor CrcTable[B^ xor Byte(Crc)]; - Inc(B); - end -end; - -procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte); -{$IFDEF USE_ASM} -asm - PUSH EDI - MOV EDI, EAX - MOV EAX, ECX - MOV AH, AL - MOV CX, AX - SHL EAX, 16 - MOV AX, CX - MOV ECX, EDX - SAR ECX, 2 - JS @Exit - REP STOSD - MOV ECX, EDX - AND ECX, 3 - REP STOSB - POP EDI -@Exit: -end; -{$ELSE} -begin - FillChar(Data^, Size, Value); -end; -{$ENDIF} - -procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word); -{$IFDEF USE_ASM} -asm - PUSH EDI - PUSH EBX - MOV EBX, EDX - MOV EDI, EAX - MOV EAX, ECX - MOV CX, AX - SHL EAX, 16 - MOV AX, CX - MOV ECX, EDX - SHR ECX, 2 - JZ @Word - REP STOSD -@Word: - MOV ECX, EBX - AND ECX, 2 - JZ @Byte - MOV [EDI], AX - ADD EDI, 2 -@Byte: - MOV ECX, EBX - AND ECX, 1 - JZ @Exit - MOV [EDI], AL -@Exit: - POP EBX - POP EDI -end; -{$ELSE} -var - I, V: LongWord; -begin - V := Value * $10000 + Value; - for I := 0 to Size div 4 - 1 do - PLongWordArray(Data)[I] := V; - case Size mod 4 of - 1: PByteArray(Data)[Size - 1] := Lo(Value); - 2: PWordArray(Data)[Size div 2] := Value; - 3: - begin - PWordArray(Data)[Size div 2 - 1] := Value; - PByteArray(Data)[Size - 1] := Lo(Value); - end; - end; -end; -{$ENDIF} - -procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord); -{$IFDEF USE_ASM} -asm - PUSH EDI - PUSH EBX - MOV EBX, EDX - MOV EDI, EAX - MOV EAX, ECX - MOV ECX, EDX - SHR ECX, 2 - JZ @Word - REP STOSD -@Word: - MOV ECX, EBX - AND ECX, 2 - JZ @Byte - MOV [EDI], AX - ADD EDI, 2 -@Byte: - MOV ECX, EBX - AND ECX, 1 - JZ @Exit - MOV [EDI], AL -@Exit: - POP EBX - POP EDI -end; -{$ELSE} -var - I: LongInt; -begin - for I := 0 to Size div 4 - 1 do - PLongWordArray(Data)[I] := Value; - case Size mod 4 of - 1: PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0]; - 2: PWordArray(Data)[Size div 2] := TLongWordRec(Value).Words[0]; - 3: - begin - PWordArray(Data)[Size div 2 - 1] := TLongWordRec(Value).Words[0]; - PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0]; - end; - end; -end; -{$ENDIF} - -procedure ZeroMemory(Data: Pointer; Size: Integer); -begin - FillMemoryByte(Data, Size, 0); -end; - -function GetNumMipMapLevels(Width, Height: LongInt): LongInt; -begin - Result := 0; - if (Width > 0) and (Height > 0) then - begin - Result := 1; - while (Width <> 1) or (Height <> 1) do - begin - Width := Width div 2; - Height := Height div 2; - if Width < 1 then Width := 1; - if Height < 1 then Height := 1; - Inc(Result); - end; - end; -end; - -function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt; -var - I: LongInt; -begin - Result := Depth; - for I := 1 to MipMaps - 1 do - Inc(Result, ClampInt(Depth shr I, 1, Depth)); -end; - -function BoundsToRect(X, Y, Width, Height: LongInt): TRect; -begin - Result.Left := X; - Result.Top := Y; - Result.Right := X + Width; - Result.Bottom := Y + Height; -end; - -function BoundsToRect(const R: TRect): TRect; -begin - Result.Left := R.Left; - Result.Top := R.Top; - Result.Right := R.Left + R.Right; - Result.Bottom := R.Top + R.Bottom; -end; - -function RectToBounds(const R: TRect): TRect; -begin - Result.Left := R.Left; - Result.Top := R.Top; - Result.Right := R.Right - R.Left; - Result.Bottom := R.Bottom - R.Top; -end; - -procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect); - - procedure ClipDim(var AStart, ALength: LongInt; ClipMin, ClipMax: LongInt); - begin - if AStart < ClipMin then - begin - ALength := ALength - (ClipMin - AStart); - AStart := ClipMin; - end; - if AStart + ALength > ClipMax then ALength := Max(0, ClipMax - AStart); - end; - -begin - ClipDim(X, Width, Clip.Left, Clip.Right); - ClipDim(Y, Height, Clip.Top, Clip.Bottom); -end; - -procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); - - procedure ClipDim(var SrcPos, DstPos, Size: LongInt; SrcClipMax, - DstClipMin, DstClipMax: LongInt); - var - OldDstPos: LongInt; - Diff: LongInt; - begin - OldDstPos := Iff(DstPos < 0, DstPos, 0); - if DstPos < DstClipMin then - begin - Diff := DstClipMin - DstPos; - Size := Size - Diff; - SrcPos := SrcPos + Diff; - DstPos := DstClipMin; - end; - if SrcPos < 0 then - begin - Size := Size + SrcPos - OldDstPos; - DstPos := DstPos - SrcPos + OldDstPos; - SrcPos := 0; - end; - if SrcPos + Size > SrcClipMax then Size := SrcClipMax - SrcPos; - if DstPos + Size > DstClipMax then Size := DstClipMax - DstPos; - end; - -begin - ClipDim(SrcX, DstX, Width, SrcImageWidth, DstClip.Left, DstClip.Right); - ClipDim(SrcY, DstY, Height, SrcImageHeight, DstClip.Top, DstClip.Bottom); -end; - -procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, - DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); - - procedure ClipDim(var SrcPos, DstPos, SrcSize, DstSize: LongInt; SrcClipMax, - DstClipMin, DstClipMax: LongInt); - var - OldSize: LongInt; - Diff: LongInt; - Scale: Single; - begin - Scale := DstSize / SrcSize; - if DstPos < DstClipMin then - begin - Diff := DstClipMin - DstPos; - DstSize := DstSize - Diff; - SrcPos := SrcPos + Round(Diff / Scale); - SrcSize := SrcSize - Round(Diff / Scale); - DstPos := DstClipMin; - end; - if SrcPos < 0 then - begin - SrcSize := SrcSize + SrcPos; - DstPos := DstPos - Round(SrcPos * Scale); - DstSize := DstSize + Round(SrcPos * Scale); - SrcPos := 0; - end; - if SrcPos + SrcSize > SrcClipMax then - begin - OldSize := SrcSize; - SrcSize := SrcClipMax - SrcPos; - DstSize := Round(DstSize * (SrcSize / OldSize)); - end; - if DstPos + DstSize > DstClipMax then - begin - OldSize := DstSize; - DstSize := DstClipMax - DstPos; - SrcSize := Round(SrcSize * (DstSize / OldSize)); - end; - end; - -begin - ClipDim(SrcX, DstX, SrcWidth, DstWidth, SrcImageWidth, DstClip.Left, DstClip.Right); - ClipDim(SrcY, DstY, SrcHeight, DstHeight, SrcImageHeight, DstClip.Top, DstClip.Bottom); -end; - -function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect; -var - SourceWidth: LongInt; - SourceHeight: LongInt; - TargetWidth: LongInt; - TargetHeight: LongInt; - ScaledWidth: LongInt; - ScaledHeight: LongInt; -begin - SourceWidth := SourceRect.Right - SourceRect.Left; - SourceHeight := SourceRect.Bottom - SourceRect.Top; - TargetWidth := TargetRect.Right - TargetRect.Left; - TargetHeight := TargetRect.Bottom - TargetRect.Top; - - if SourceWidth * TargetHeight < SourceHeight * TargetWidth then - begin - ScaledWidth := (SourceWidth * TargetHeight) div SourceHeight; - Result := BoundsToRect(TargetRect.Left + ((TargetWidth - ScaledWidth) div 2), - TargetRect.Top, ScaledWidth, TargetHeight); - end - else - begin - ScaledHeight := (SourceHeight * TargetWidth) div SourceWidth; - Result := BoundsToRect(TargetRect.Left, TargetRect.Top + ((TargetHeight - ScaledHeight) div 2), - TargetWidth, ScaledHeight); - end; -end; - -function ScaleSizeToFit(const CurrentSize, MaxSize: Types.TSize): Types.TSize; -var - SR, TR, ScaledRect: TRect; -begin - SR := Types.Rect(0, 0, CurrentSize.CX, CurrentSize.CY); - TR := Types.Rect(0, 0, MaxSize.CX, MaxSize.CY); - ScaledRect := ScaleRectToRect(SR, TR); - Result.CX := ScaledRect.Right - ScaledRect.Left; - Result.CY := ScaledRect.Bottom - ScaledRect.Top; -end; - -function RectWidth(const Rect: TRect): Integer; -begin - Result := Rect.Right - Rect.Left; -end; - -function RectHeight(const Rect: TRect): Integer; -begin - Result := Rect.Bottom - Rect.Top; -end; - -function RectInRect(const R1, R2: TRect): Boolean; -begin - Result:= - (R1.Left >= R2.Left) and - (R1.Top >= R2.Top) and - (R1.Right <= R2.Right) and - (R1.Bottom <= R2.Bottom); -end; - -function RectIntersects(const R1, R2: TRect): Boolean; -begin - Result := - not (R1.Left > R2.Right) and - not (R1.Top > R2.Bottom) and - not (R1.Right < R2.Left) and - not (R1.Bottom < R2.Top); -end; - -function PixelSizeToDpi(SizeInMicroMeters: Single): Single; -begin - Result := 25400 / SizeInMicroMeters; -end; - -function DpiToPixelSize(Dpi: Single): Single; -begin - Result := 1e03 / (Dpi / 25.4); -end; - -function FloatRect(ALeft, ATop, ARight, ABottom: Single): TFloatRect; -begin - with Result do - begin - Left := ALeft; - Top := ATop; - Right := ARight; - Bottom := ABottom; - end; -end; - -function FloatRectWidth(const R: TFloatRect): Single; -begin - Result := R.Right - R.Left; -end; - -function FloatRectHeight(const R: TFloatRect): Single; -begin - Result := R.Bottom - R.Top; -end; - -function FormatExceptMsg(const Msg: string; const Args: array of const): string; -begin - Result := Format(Msg + SLineBreak + 'Message: ' + GetExceptObject.Message, Args); -end; - -procedure DebugMsg(const Msg: string; const Args: array of const); -var - FmtMsg: string; -begin - FmtMsg := Format(Msg, Args); -{$IFDEF MSWINDOWS} - if IsConsole then - WriteLn('DebugMsg: ' + FmtMsg) - else - MessageBox(GetActiveWindow, PChar(FmtMsg), 'DebugMsg', MB_OK); -{$ENDIF} -{$IFDEF UNIX} - WriteLn('DebugMsg: ' + FmtMsg); -{$ENDIF} -{$IFDEF MSDOS} - WriteLn('DebugMsg: ' + FmtMsg); -{$ENDIF} -end; - -initialization - InitCrcTable; -{$IFDEF MSWINDOWS} - QueryPerformanceFrequency(PerfFrequency); - InvPerfFrequency := 1.0 / PerfFrequency; -{$ENDIF} - -{$IF Defined(DELPHI)} - {$IF CompilerVersion >= 23} - FloatFormatSettings := TFormatSettings.Create('en-US'); - {$ELSE} - GetLocaleFormatSettings(1033, FloatFormatSettings); - {$IFEND} -{$ELSE FPC} - FloatFormatSettings := DefaultFormatSettings; - FloatFormatSettings.DecimalSeparator := '.'; -{$IFEND} - -{ - File Notes: - - -- TODOS ---------------------------------------------------- - - nothing now - - -- 0.77.1 ---------------------------------------------------- - - Added GetFileName, GetFileDir, RectWidth, RectHeight function. - - Added ScaleSizeToFit function. - - Added ZeroMemory and SwapValues for Booleans. - - Added Substring function. - - Renamed MatchFileNameMask to StrMaskMatch (it's for general use not - just filenames). - - Delphi XE2 new targets (Win64, OSX32) compatibility changes. - - Added GetFormatSettingsForFloats function. - - -- 0.26.5 Changes/Bug Fixes ----------------------------------- - - Added Log10 function. - - Added TFloatRect type and helper functions FloatRect, FloatRectWidth, - FloatRectHeight. - - Added string function ContainsAnySubStr. - - Added functions PixelSizeToDpi, DpiToPixelSize. - - -- 0.26.1 Changes/Bug Fixes ----------------------------------- - - Some formatting changes. - - Changed some string functions to work with localized strings. - - ASM version of PosEx had bugs, removed it. - - Added StrTokensToList function. - - -- 0.25.0 Changes/Bug Fixes ----------------------------------- - - Fixed error in ClipCopyBounds which was causing ... bad clipping! - - -- 0.24.3 Changes/Bug Fixes ----------------------------------- - - Added GetTimeMilliseconds function. - - Added IntToStrFmt and FloatToStrFmt helper functions. - - -- 0.23 Changes/Bug Fixes ----------------------------------- - - Added RectInRect and RectIntersects functions - - Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase. - - Moved BuildFileList here from DemoUtils. - - -- 0.21 Changes/Bug Fixes ----------------------------------- - - Moved GetVolumeLevelCount from ImagingDds here. - - Renamed FillMemory to FillMemoryByte to avoid name collision in C++ Builder. - - Added Iff function for Char, Pointer, and Int64 types. - - Added IsLittleEndian function. - - Added array types for TWordRec, TLongWordRec, and TInt64Rec. - - Added MatchFileNameMask function. - - -- 0.19 Changes/Bug Fixes ----------------------------------- - - added ScaleRectToRect (thanks to Paul Michell) - - added BoundsToRect, ClipBounds, ClipCopyBounds, ClipStretchBounds functions - - added MulDiv function - - FreeAndNil is not inline anymore - caused AV in one program - - -- 0.17 Changes/Bug Fixes ----------------------------------- - - - GetAppExe didn't return absolute path in FreeBSD, fixed - - added debug message output - - fixed Unix compatibility issues (thanks to Ales Katona). - Imaging now compiles in FreeBSD and maybe in other Unixes as well. - - -- 0.15 Changes/Bug Fixes ----------------------------------- - - added some new utility functions - - -- 0.13 Changes/Bug Fixes ----------------------------------- - - added many new utility functions - - minor change in SwapEndian to avoid range check error - -} -end. - - diff --git a/3rd/Imaging/Source/JpegLib/imjcapimin.pas b/3rd/Imaging/Source/JpegLib/imjcapimin.pas deleted file mode 100644 index d8be056f7..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcapimin.pas +++ /dev/null @@ -1,401 +0,0 @@ -unit imjcapimin; -{$N+} -{ This file contains application interface code for the compression half - of the JPEG library. These are the "minimum" API routines that may be - needed in either the normal full-compression case or the transcoding-only - case. - - Most of the routines intended to be called directly by an application - are in this file or in jcapistd.c. But also see jcparam.c for - parameter-setup helper routines, jcomapi.c for routines shared by - compression and decompression, and jctrans.c for the transcoding case. } - -{ jcapimin.c ; Copyright (C) 1994-1998, Thomas G. Lane. } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjcomapi, - imjmemmgr, - imjcmarker; - -{ Initialization of JPEG compression objects. - Nomssi: This is a macro in the original code. - - jpeg_create_compress() and jpeg_create_decompress() are the exported - names that applications should call. These expand to calls on - jpeg_CreateCompress and jpeg_CreateDecompress with additional information - passed for version mismatch checking. - NB: you must set up the error-manager BEFORE calling jpeg_create_xxx. } - -procedure jpeg_create_compress(cinfo : j_compress_ptr); - - -{ Initialization of a JPEG compression object. - The error manager must already be set up (in case memory manager fails). } - -{GLOBAL} -procedure jpeg_CreateCompress (cinfo : j_compress_ptr; - version : int; - structsize : size_t); - -{ Destruction of a JPEG compression object } - -{GLOBAL} -procedure jpeg_destroy_compress (cinfo : j_compress_ptr); - - -{ Abort processing of a JPEG compression operation, - but don't destroy the object itself. } - -{GLOBAL} -procedure jpeg_abort_compress (cinfo : j_compress_ptr); - - -{ Forcibly suppress or un-suppress all quantization and Huffman tables. - Marks all currently defined tables as already written (if suppress) - or not written (if !suppress). This will control whether they get emitted - by a subsequent jpeg_start_compress call. - - This routine is exported for use by applications that want to produce - abbreviated JPEG datastreams. It logically belongs in jcparam.c, but - since it is called by jpeg_start_compress, we put it here --- otherwise - jcparam.o would be linked whether the application used it or not. } - -{GLOBAL} -procedure jpeg_suppress_tables (cinfo : j_compress_ptr; - suppress : boolean); - - -{ Finish JPEG compression. - - If a multipass operating mode was selected, this may do a great deal of - work including most of the actual output. } - -{GLOBAL} -procedure jpeg_finish_compress (cinfo : j_compress_ptr); - -{ Write a special marker. - This is only recommended for writing COM or APPn markers. - Must be called after jpeg_start_compress() and before - first call to jpeg_write_scanlines() or jpeg_write_raw_data(). } - -{GLOBAL} -procedure jpeg_write_marker (cinfo : j_compress_ptr; - marker : int; - dataptr : JOCTETptr; - datalen : uInt); - -{GLOBAL} -procedure jpeg_write_m_header (cinfo : j_compress_ptr; - marker : int; - datalen : uint); -{GLOBAL} -procedure jpeg_write_m_byte (cinfo : j_compress_ptr; val : int); - -{ Alternate compression function: just write an abbreviated table file. - Before calling this, all parameters and a data destination must be set up. - - To produce a pair of files containing abbreviated tables and abbreviated - image data, one would proceed as follows: - - initialize JPEG object - set JPEG parameters - set destination to table file - jpeg_write_tables(cinfo); - set destination to image file - jpeg_start_compress(cinfo, FALSE); - write data... - jpeg_finish_compress(cinfo); - - jpeg_write_tables has the side effect of marking all tables written - (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress - will not re-emit the tables unless it is passed write_all_tables=TRUE. } - - - -{GLOBAL} -procedure jpeg_write_tables (cinfo : j_compress_ptr); - -implementation - -procedure jpeg_create_compress(cinfo : j_compress_ptr); -begin - jpeg_CreateCompress(cinfo, JPEG_LIB_VERSION, - size_t(sizeof(jpeg_compress_struct))); -end; - -{ Initialization of a JPEG compression object. - The error manager must already be set up (in case memory manager fails). } - -{GLOBAL} -procedure jpeg_CreateCompress (cinfo : j_compress_ptr; - version : int; - structsize : size_t); -var - i : int; -var - err : jpeg_error_mgr_ptr; - client_data : voidp; -begin - - { Guard against version mismatches between library and caller. } - cinfo^.mem := NIL; { so jpeg_destroy knows mem mgr not called } - if (version <> JPEG_LIB_VERSION) then - ERREXIT2(j_common_ptr(cinfo), JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); - if (structsize <> SIZEOF(jpeg_compress_struct)) then - ERREXIT2(j_common_ptr(cinfo), JERR_BAD_STRUCT_SIZE, - int(SIZEOF(jpeg_compress_struct)), int(structsize)); - - { For debugging purposes, we zero the whole master structure. - But the application has already set the err pointer, and may have set - client_data, so we have to save and restore those fields. - Note: if application hasn't set client_data, tools like Purify may - complain here. } - - err := cinfo^.err; - client_data := cinfo^.client_data; { ignore Purify complaint here } - MEMZERO(cinfo, SIZEOF(jpeg_compress_struct)); - cinfo^.err := err; - cinfo^.is_decompressor := FALSE; - - { Initialize a memory manager instance for this object } - jinit_memory_mgr(j_common_ptr(cinfo)); - - { Zero out pointers to permanent structures. } - cinfo^.progress := NIL; - cinfo^.dest := NIL; - - cinfo^.comp_info := NIL; - - for i := 0 to pred(NUM_QUANT_TBLS) do - cinfo^.quant_tbl_ptrs[i] := NIL; - - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - cinfo^.dc_huff_tbl_ptrs[i] := NIL; - cinfo^.ac_huff_tbl_ptrs[i] := NIL; - end; - - cinfo^.script_space := NIL; - - cinfo^.input_gamma := 1.0; { in case application forgets } - - { OK, I'm ready } - cinfo^.global_state := CSTATE_START; -end; - - -{ Destruction of a JPEG compression object } - -{GLOBAL} -procedure jpeg_destroy_compress (cinfo : j_compress_ptr); -begin - jpeg_destroy(j_common_ptr(cinfo)); { use common routine } -end; - - -{ Abort processing of a JPEG compression operation, - but don't destroy the object itself. } - -{GLOBAL} -procedure jpeg_abort_compress (cinfo : j_compress_ptr); -begin - jpeg_abort(j_common_ptr(cinfo)); { use common routine } -end; - - -{ Forcibly suppress or un-suppress all quantization and Huffman tables. - Marks all currently defined tables as already written (if suppress) - or not written (if !suppress). This will control whether they get emitted - by a subsequent jpeg_start_compress call. - - This routine is exported for use by applications that want to produce - abbreviated JPEG datastreams. It logically belongs in jcparam.c, but - since it is called by jpeg_start_compress, we put it here --- otherwise - jcparam.o would be linked whether the application used it or not. } - -{GLOBAL} -procedure jpeg_suppress_tables (cinfo : j_compress_ptr; - suppress : boolean); -var - i : int; - qtbl : JQUANT_TBL_PTR; - htbl : JHUFF_TBL_PTR; -begin - for i := 0 to pred(NUM_QUANT_TBLS) do - begin - qtbl := cinfo^.quant_tbl_ptrs[i]; - if (qtbl <> NIL) then - qtbl^.sent_table := suppress; - end; - - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - htbl := cinfo^.dc_huff_tbl_ptrs[i]; - if (htbl <> NIL) then - htbl^.sent_table := suppress; - htbl := cinfo^.ac_huff_tbl_ptrs[i]; - if (htbl <> NIL) then - htbl^.sent_table := suppress; - end; -end; - - -{ Finish JPEG compression. - - If a multipass operating mode was selected, this may do a great deal of - work including most of the actual output. } - -{GLOBAL} -procedure jpeg_finish_compress (cinfo : j_compress_ptr); -var - iMCU_row : JDIMENSION; -begin - if (cinfo^.global_state = CSTATE_SCANNING) or - (cinfo^.global_state = CSTATE_RAW_OK) then - begin - { Terminate first pass } - if (cinfo^.next_scanline < cinfo^.image_height) then - ERREXIT(j_common_ptr(cinfo), JERR_TOO_LITTLE_DATA); - cinfo^.master^.finish_pass (cinfo); - end - else - if (cinfo^.global_state <> CSTATE_WRCOEFS) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - { Perform any remaining passes } - while (not cinfo^.master^.is_last_pass) do - begin - cinfo^.master^.prepare_for_pass (cinfo); - for iMCU_row := 0 to pred(cinfo^.total_iMCU_rows) do - begin - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.pass_counter := long (iMCU_row); - cinfo^.progress^.pass_limit := long (cinfo^.total_iMCU_rows); - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - end; - { We bypass the main controller and invoke coef controller directly; - all work is being done from the coefficient buffer. } - - if (not cinfo^.coef^.compress_data (cinfo, JSAMPIMAGE(NIL))) then - ERREXIT(j_common_ptr(cinfo), JERR_CANT_SUSPEND); - end; - cinfo^.master^.finish_pass (cinfo); - end; - { Write EOI, do final cleanup } - cinfo^.marker^.write_file_trailer (cinfo); - cinfo^.dest^.term_destination (cinfo); - { We can use jpeg_abort to release memory and reset global_state } - jpeg_abort(j_common_ptr(cinfo)); -end; - - -{ Write a special marker. - This is only recommended for writing COM or APPn markers. - Must be called after jpeg_start_compress() and before - first call to jpeg_write_scanlines() or jpeg_write_raw_data(). } - -{GLOBAL} -procedure jpeg_write_marker (cinfo : j_compress_ptr; - marker : int; - dataptr : JOCTETptr; - datalen : uInt); -var - write_marker_byte : procedure(info : j_compress_ptr; val : int); -begin - if (cinfo^.next_scanline <> 0) or - ((cinfo^.global_state <> CSTATE_SCANNING) and - (cinfo^.global_state <> CSTATE_RAW_OK) and - (cinfo^.global_state <> CSTATE_WRCOEFS)) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - cinfo^.marker^.write_marker_header (cinfo, marker, datalen); - write_marker_byte := cinfo^.marker^.write_marker_byte; { copy for speed } - while (datalen <> 0) do - begin - Dec(datalen); - write_marker_byte (cinfo, dataptr^); - Inc(dataptr); - end; -end; - -{ Same, but piecemeal. } - -{GLOBAL} -procedure jpeg_write_m_header (cinfo : j_compress_ptr; - marker : int; - datalen : uint); -begin - if (cinfo^.next_scanline <> 0) or - ((cinfo^.global_state <> CSTATE_SCANNING) and - (cinfo^.global_state <> CSTATE_RAW_OK) and - (cinfo^.global_state <> CSTATE_WRCOEFS)) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - cinfo^.marker^.write_marker_header (cinfo, marker, datalen); -end; - -{GLOBAL} -procedure jpeg_write_m_byte (cinfo : j_compress_ptr; val : int); -begin - cinfo^.marker^.write_marker_byte (cinfo, val); -end; - - -{ Alternate compression function: just write an abbreviated table file. - Before calling this, all parameters and a data destination must be set up. - - To produce a pair of files containing abbreviated tables and abbreviated - image data, one would proceed as follows: - - initialize JPEG object - set JPEG parameters - set destination to table file - jpeg_write_tables(cinfo); - set destination to image file - jpeg_start_compress(cinfo, FALSE); - write data... - jpeg_finish_compress(cinfo); - - jpeg_write_tables has the side effect of marking all tables written - (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress - will not re-emit the tables unless it is passed write_all_tables=TRUE. } - -{GLOBAL} -procedure jpeg_write_tables (cinfo : j_compress_ptr); -begin - if (cinfo^.global_state <> CSTATE_START) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - { (Re)initialize error mgr and destination modules } - cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo)); - cinfo^.dest^.init_destination (cinfo); - { Initialize the marker writer ... bit of a crock to do it here. } - jinit_marker_writer(cinfo); - { Write them tables! } - cinfo^.marker^.write_tables_only (cinfo); - { And clean up. } - cinfo^.dest^.term_destination (cinfo); - - { In library releases up through v6a, we called jpeg_abort() here to free - any working memory allocated by the destination manager and marker - writer. Some applications had a problem with that: they allocated space - of their own from the library memory manager, and didn't want it to go - away during write_tables. So now we do nothing. This will cause a - memory leak if an app calls write_tables repeatedly without doing a full - compression cycle or otherwise resetting the JPEG object. However, that - seems less bad than unexpectedly freeing memory in the normal case. - An app that prefers the old behavior can call jpeg_abort for itself after - each call to jpeg_write_tables(). } -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcapistd.pas b/3rd/Imaging/Source/JpegLib/imjcapistd.pas deleted file mode 100644 index f9ae61392..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcapistd.pas +++ /dev/null @@ -1,222 +0,0 @@ -unit imjcapistd; - -{ Original : jcapistd.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This file is part of the Independent JPEG Group's software. - For conditions of distribution and use, see the accompanying README file. - - This file contains application interface code for the compression half - of the JPEG library. These are the "standard" API routines that are - used in the normal full-compression case. They are not used by a - transcoding-only application. Note that if an application links in - jpeg_start_compress, it will end up linking in the entire compressor. - We thus must separate this file from jcapimin.c to avoid linking the - whole compression library into a transcoder. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjcapimin, imjcinit; - - - -{ Compression initialization. - Before calling this, all parameters and a data destination must be set up. - - We require a write_all_tables parameter as a failsafe check when writing - multiple datastreams from the same compression object. Since prior runs - will have left all the tables marked sent_table=TRUE, a subsequent run - would emit an abbreviated stream (no tables) by default. This may be what - is wanted, but for safety's sake it should not be the default behavior: - programmers should have to make a deliberate choice to emit abbreviated - images. Therefore the documentation and examples should encourage people - to pass write_all_tables=TRUE; then it will take active thought to do the - wrong thing. } - -{GLOBAL} -procedure jpeg_start_compress (cinfo : j_compress_ptr; - write_all_tables : boolean); - - -{ Write some scanlines of data to the JPEG compressor. - - The return value will be the number of lines actually written. - This should be less than the supplied num_lines only in case that - the data destination module has requested suspension of the compressor, - or if more than image_height scanlines are passed in. - - Note: we warn about excess calls to jpeg_write_scanlines() since - this likely signals an application programmer error. However, - excess scanlines passed in the last valid call are *silently* ignored, - so that the application need not adjust num_lines for end-of-image - when using a multiple-scanline buffer. } - -{GLOBAL} -function jpeg_write_scanlines (cinfo : j_compress_ptr; - scanlines : JSAMPARRAY; - num_lines : JDIMENSION) : JDIMENSION; - -{ Alternate entry point to write raw data. - Processes exactly one iMCU row per call, unless suspended. } - -{GLOBAL} -function jpeg_write_raw_data (cinfo : j_compress_ptr; - data : JSAMPIMAGE; - num_lines : JDIMENSION) : JDIMENSION; - -implementation - -{ Compression initialization. - Before calling this, all parameters and a data destination must be set up. - - We require a write_all_tables parameter as a failsafe check when writing - multiple datastreams from the same compression object. Since prior runs - will have left all the tables marked sent_table=TRUE, a subsequent run - would emit an abbreviated stream (no tables) by default. This may be what - is wanted, but for safety's sake it should not be the default behavior: - programmers should have to make a deliberate choice to emit abbreviated - images. Therefore the documentation and examples should encourage people - to pass write_all_tables=TRUE; then it will take active thought to do the - wrong thing. } - -{GLOBAL} -procedure jpeg_start_compress (cinfo : j_compress_ptr; - write_all_tables : boolean); -begin - if (cinfo^.global_state <> CSTATE_START) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - if (write_all_tables) then - jpeg_suppress_tables(cinfo, FALSE); { mark all tables to be written } - - { (Re)initialize error mgr and destination modules } - cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo)); - cinfo^.dest^.init_destination (cinfo); - { Perform master selection of active modules } - jinit_compress_master(cinfo); - { Set up for the first pass } - cinfo^.master^.prepare_for_pass (cinfo); - { Ready for application to drive first pass through jpeg_write_scanlines - or jpeg_write_raw_data. } - - cinfo^.next_scanline := 0; - if cinfo^.raw_data_in then - cinfo^.global_state := CSTATE_RAW_OK - else - cinfo^.global_state := CSTATE_SCANNING; -end; - - -{ Write some scanlines of data to the JPEG compressor. - - The return value will be the number of lines actually written. - This should be less than the supplied num_lines only in case that - the data destination module has requested suspension of the compressor, - or if more than image_height scanlines are passed in. - - Note: we warn about excess calls to jpeg_write_scanlines() since - this likely signals an application programmer error. However, - excess scanlines passed in the last valid call are *silently* ignored, - so that the application need not adjust num_lines for end-of-image - when using a multiple-scanline buffer. } - -{GLOBAL} -function jpeg_write_scanlines (cinfo : j_compress_ptr; - scanlines : JSAMPARRAY; - num_lines : JDIMENSION) : JDIMENSION; -var - row_ctr, rows_left : JDIMENSION; -begin - if (cinfo^.global_state <> CSTATE_SCANNING) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - if (cinfo^.next_scanline >= cinfo^.image_height) then - WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA); - - { Call progress monitor hook if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.pass_counter := long (cinfo^.next_scanline); - cinfo^.progress^.pass_limit := long (cinfo^.image_height); - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - end; - - { Give master control module another chance if this is first call to - jpeg_write_scanlines. This lets output of the frame/scan headers be - delayed so that application can write COM, etc, markers between - jpeg_start_compress and jpeg_write_scanlines. } - if (cinfo^.master^.call_pass_startup) then - cinfo^.master^.pass_startup (cinfo); - - { Ignore any extra scanlines at bottom of image. } - rows_left := cinfo^.image_height - cinfo^.next_scanline; - if (num_lines > rows_left) then - num_lines := rows_left; - - row_ctr := 0; - cinfo^.main^.process_data (cinfo, scanlines, {var}row_ctr, num_lines); - Inc(cinfo^.next_scanline, row_ctr); - jpeg_write_scanlines := row_ctr; -end; - - -{ Alternate entry point to write raw data. - Processes exactly one iMCU row per call, unless suspended. } - -{GLOBAL} -function jpeg_write_raw_data (cinfo : j_compress_ptr; - data : JSAMPIMAGE; - num_lines : JDIMENSION) : JDIMENSION; -var - lines_per_iMCU_row : JDIMENSION; -begin - if (cinfo^.global_state <> CSTATE_RAW_OK) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - if (cinfo^.next_scanline >= cinfo^.image_height) then - begin - WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA); - jpeg_write_raw_data := 0; - exit; - end; - - { Call progress monitor hook if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.pass_counter := long(cinfo^.next_scanline); - cinfo^.progress^.pass_limit := long(cinfo^.image_height); - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - end; - - { Give master control module another chance if this is first call to - jpeg_write_raw_data. This lets output of the frame/scan headers be - delayed so that application can write COM, etc, markers between - jpeg_start_compress and jpeg_write_raw_data. } - - if (cinfo^.master^.call_pass_startup) then - cinfo^.master^.pass_startup (cinfo); - - { Verify that at least one iMCU row has been passed. } - lines_per_iMCU_row := cinfo^.max_v_samp_factor * DCTSIZE; - if (num_lines < lines_per_iMCU_row) then - ERREXIT(j_common_ptr(cinfo), JERR_BUFFER_SIZE); - - { Directly compress the row. } - if (not cinfo^.coef^.compress_data (cinfo, data)) then - begin - { If compressor did not consume the whole row, suspend processing. } - jpeg_write_raw_data := 0; - exit; - end; - - { OK, we processed one iMCU row. } - Inc(cinfo^.next_scanline, lines_per_iMCU_row); - jpeg_write_raw_data := lines_per_iMCU_row; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjccoefct.pas b/3rd/Imaging/Source/JpegLib/imjccoefct.pas deleted file mode 100644 index 7dd97e5e8..000000000 --- a/3rd/Imaging/Source/JpegLib/imjccoefct.pas +++ /dev/null @@ -1,521 +0,0 @@ -unit imjccoefct; - -{ This file contains the coefficient buffer controller for compression. - This controller is the top level of the JPEG compressor proper. - The coefficient buffer lies between forward-DCT and entropy encoding steps.} - -{ Original: jccoefct.c; Copyright (C) 1994-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjerror, - imjdeferr, - imjutils, - imjpeglib; - -{ We use a full-image coefficient buffer when doing Huffman optimization, - and also for writing multiple-scan JPEG files. In all cases, the DCT - step is run during the first pass, and subsequent passes need only read - the buffered coefficients. } -{$ifdef ENTROPY_OPT_SUPPORTED} - {$define FULL_COEF_BUFFER_SUPPORTED} -{$else} - {$ifdef C_MULTISCAN_FILES_SUPPORTED} - {$define FULL_COEF_BUFFER_SUPPORTED} - {$endif} -{$endif} - -{ Initialize coefficient buffer controller. } - -{GLOBAL} -procedure jinit_c_coef_controller (cinfo : j_compress_ptr; - need_full_buffer : boolean); - -implementation - -{ Private buffer controller object } - -type - my_coef_ptr = ^my_coef_controller; - my_coef_controller = record - pub : jpeg_c_coef_controller; { public fields } - - iMCU_row_num : JDIMENSION; { iMCU row # within image } - mcu_ctr : JDIMENSION; { counts MCUs processed in current row } - MCU_vert_offset : int; { counts MCU rows within iMCU row } - MCU_rows_per_iMCU_row : int; { number of such rows needed } - - { For single-pass compression, it's sufficient to buffer just one MCU - (although this may prove a bit slow in practice). We allocate a - workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each - MCU constructed and sent. (On 80x86, the workspace is FAR even though - it's not really very big; this is to keep the module interfaces unchanged - when a large coefficient buffer is necessary.) - In multi-pass modes, this array points to the current MCU's blocks - within the virtual arrays. } - - MCU_buffer : array[0..C_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW; - - { In multi-pass modes, we need a virtual block array for each component. } - whole_image : array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr; - end; - - -{ Forward declarations } -{METHODDEF} -function compress_data(cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; forward; -{$ifdef FULL_COEF_BUFFER_SUPPORTED} -{METHODDEF} -function compress_first_pass(cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; forward; -{METHODDEF} -function compress_output(cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; forward; -{$endif} - - -{LOCAL} -procedure start_iMCU_row (cinfo : j_compress_ptr); -{ Reset within-iMCU-row counters for a new row } -var - coef : my_coef_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - - { In an interleaved scan, an MCU row is the same as an iMCU row. - In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - But at the bottom of the image, process only what's left. } - if (cinfo^.comps_in_scan > 1) then - begin - coef^.MCU_rows_per_iMCU_row := 1; - end - else - begin - if (coef^.iMCU_row_num < (cinfo^.total_iMCU_rows-1)) then - coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor - else - coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height; - end; - - coef^.mcu_ctr := 0; - coef^.MCU_vert_offset := 0; -end; - - -{ Initialize for a processing pass. } - -{METHODDEF} -procedure start_pass_coef (cinfo : j_compress_ptr; - pass_mode : J_BUF_MODE); -var - coef : my_coef_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - - coef^.iMCU_row_num := 0; - start_iMCU_row(cinfo); - - case (pass_mode) of - JBUF_PASS_THRU: - begin - if (coef^.whole_image[0] <> NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - coef^.pub.compress_data := compress_data; - end; -{$ifdef FULL_COEF_BUFFER_SUPPORTED} - JBUF_SAVE_AND_PASS: - begin - if (coef^.whole_image[0] = NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - coef^.pub.compress_data := compress_first_pass; - end; - JBUF_CRANK_DEST: - begin - if (coef^.whole_image[0] = NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - coef^.pub.compress_data := compress_output; - end; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - end; -end; - - -{ Process some data in the single-pass case. - We process the equivalent of one fully interleaved MCU row ("iMCU" row) - per call, ie, v_samp_factor block rows for each component in the image. - Returns TRUE if the iMCU row is completed, FALSE if suspended. - - NB: input_buf contains a plane for each component in image, - which we index according to the component's SOF position. } - - -{METHODDEF} -function compress_data (cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; -var - coef : my_coef_ptr; - MCU_col_num : JDIMENSION; { index of current MCU within row } - last_MCU_col : JDIMENSION; - last_iMCU_row : JDIMENSION; - blkn, bi, ci, yindex, yoffset, blockcnt : int; - ypos, xpos : JDIMENSION; - compptr : jpeg_component_info_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - last_MCU_col := cinfo^.MCUs_per_row - 1; - last_iMCU_row := cinfo^.total_iMCU_rows - 1; - - { Loop to write as much as one whole iMCU row } - for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do - begin - for MCU_col_num := coef^.mcu_ctr to last_MCU_col do - begin - { Determine where data comes from in input_buf and do the DCT thing. - Each call on forward_DCT processes a horizontal row of DCT blocks - as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks - sequentially. Dummy blocks at the right or bottom edge are filled in - specially. The data in them does not matter for image reconstruction, - so we fill them with values that will encode to the smallest amount of - data, viz: all zeroes in the AC entries, DC entries equal to previous - block's DC value. (Thanks to Thomas Kinsman for this idea.) } - - blkn := 0; - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - if (MCU_col_num < last_MCU_col) then - blockcnt := compptr^.MCU_width - else - blockcnt := compptr^.last_col_width; - xpos := MCU_col_num * JDIMENSION(compptr^.MCU_sample_width); - ypos := yoffset * DCTSIZE; { ypos = (yoffset+yindex) * DCTSIZE } - for yindex := 0 to pred(compptr^.MCU_height) do - begin - if (coef^.iMCU_row_num < last_iMCU_row) or - (yoffset+yindex < compptr^.last_row_height) then - begin - cinfo^.fdct^.forward_DCT (cinfo, compptr, - input_buf^[compptr^.component_index], - coef^.MCU_buffer[blkn], - ypos, xpos, JDIMENSION (blockcnt)); - - if (blockcnt < compptr^.MCU_width) then - begin - { Create some dummy blocks at the right edge of the image. } - jzero_far({FAR}pointer(coef^.MCU_buffer[blkn + blockcnt]), - (compptr^.MCU_width - blockcnt) * SIZEOF(JBLOCK)); - for bi := blockcnt to pred(compptr^.MCU_width) do - begin - coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn+bi-1]^[0][0]; - end; - end; - end - else - begin - { Create a row of dummy blocks at the bottom of the image. } - jzero_far({FAR}pointer(coef^.MCU_buffer[blkn]), - compptr^.MCU_width * SIZEOF(JBLOCK)); - for bi := 0 to pred(compptr^.MCU_width) do - begin - coef^.MCU_buffer[blkn+bi]^[0][0] := coef^.MCU_buffer[blkn-1]^[0][0]; - end; - end; - Inc(blkn, compptr^.MCU_width); - Inc(ypos, DCTSIZE); - end; - end; - { Try to write the MCU. In event of a suspension failure, we will - re-DCT the MCU on restart (a bit inefficient, could be fixed...) } - - if (not cinfo^.entropy^.encode_mcu (cinfo, JBLOCKARRAY(@coef^.MCU_buffer)^)) then - begin - { Suspension forced; update state counters and exit } - coef^.MCU_vert_offset := yoffset; - coef^.mcu_ctr := MCU_col_num; - compress_data := FALSE; - exit; - end; - end; - { Completed an MCU row, but perhaps not an iMCU row } - coef^.mcu_ctr := 0; - end; - { Completed the iMCU row, advance counters for next one } - Inc(coef^.iMCU_row_num); - start_iMCU_row(cinfo); - compress_data := TRUE; -end; - - -{$ifdef FULL_COEF_BUFFER_SUPPORTED} - -{ Process some data in the first pass of a multi-pass case. - We process the equivalent of one fully interleaved MCU row ("iMCU" row) - per call, ie, v_samp_factor block rows for each component in the image. - This amount of data is read from the source buffer, DCT'd and quantized, - and saved into the virtual arrays. We also generate suitable dummy blocks - as needed at the right and lower edges. (The dummy blocks are constructed - in the virtual arrays, which have been padded appropriately.) This makes - it possible for subsequent passes not to worry about real vs. dummy blocks. - - We must also emit the data to the entropy encoder. This is conveniently - done by calling compress_output() after we've loaded the current strip - of the virtual arrays. - - NB: input_buf contains a plane for each component in image. All - components are DCT'd and loaded into the virtual arrays in this pass. - However, it may be that only a subset of the components are emitted to - the entropy encoder during this first pass; be careful about looking - at the scan-dependent variables (MCU dimensions, etc). } - -{METHODDEF} -function compress_first_pass (cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; -var - coef : my_coef_ptr; - last_iMCU_row : JDIMENSION; - blocks_across, MCUs_across, MCUindex : JDIMENSION; - bi, ci, h_samp_factor, block_row, block_rows, ndummy : int; - lastDC : JCOEF; - compptr : jpeg_component_info_ptr; - buffer : JBLOCKARRAY; - thisblockrow, lastblockrow : JBLOCKROW; -begin - coef := my_coef_ptr (cinfo^.coef); - last_iMCU_row := cinfo^.total_iMCU_rows - 1; - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Align the virtual buffer for this component. } - buffer := cinfo^.mem^.access_virt_barray - (j_common_ptr(cinfo), coef^.whole_image[ci], - coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor), - JDIMENSION (compptr^.v_samp_factor), TRUE); - { Count non-dummy DCT block rows in this iMCU row. } - if (coef^.iMCU_row_num < last_iMCU_row) then - block_rows := compptr^.v_samp_factor - else - begin - { NB: can't use last_row_height here, since may not be set! } - block_rows := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor; - if (block_rows = 0) then - block_rows := compptr^.v_samp_factor; - end; - blocks_across := compptr^.width_in_blocks; - h_samp_factor := compptr^.h_samp_factor; - { Count number of dummy blocks to be added at the right margin. } - ndummy := int (blocks_across) mod h_samp_factor; - if (ndummy > 0) then - ndummy := h_samp_factor - ndummy; - { Perform DCT for all non-dummy blocks in this iMCU row. Each call - on forward_DCT processes a complete horizontal row of DCT blocks. } - - for block_row := 0 to pred(block_rows) do - begin - thisblockrow := buffer^[block_row]; - cinfo^.fdct^.forward_DCT (cinfo, compptr, - input_buf^[ci], - thisblockrow, - JDIMENSION (block_row * DCTSIZE), - JDIMENSION (0), - blocks_across); - if (ndummy > 0) then - begin - { Create dummy blocks at the right edge of the image. } - Inc(JBLOCK_PTR(thisblockrow), blocks_across); { => first dummy block } - jzero_far({FAR}pointer(thisblockrow), ndummy * SIZEOF(JBLOCK)); - {lastDC := thisblockrow^[-1][0];} - { work around Range Checking } - Dec(JBLOCK_PTR(thisblockrow)); - lastDC := thisblockrow^[0][0]; - Inc(JBLOCK_PTR(thisblockrow)); - - for bi := 0 to pred(ndummy) do - begin - thisblockrow^[bi][0] := lastDC; - end; - end; - end; - { If at end of image, create dummy block rows as needed. - The tricky part here is that within each MCU, we want the DC values - of the dummy blocks to match the last real block's DC value. - This squeezes a few more bytes out of the resulting file... } - - if (coef^.iMCU_row_num = last_iMCU_row) then - begin - Inc(blocks_across, ndummy); { include lower right corner } - MCUs_across := blocks_across div JDIMENSION(h_samp_factor); - for block_row := block_rows to pred(compptr^.v_samp_factor) do - begin - thisblockrow := buffer^[block_row]; - lastblockrow := buffer^[block_row-1]; - jzero_far({FAR} pointer(thisblockrow), - size_t(blocks_across * SIZEOF(JBLOCK))); - for MCUindex := 0 to pred(MCUs_across) do - begin - lastDC := lastblockrow^[h_samp_factor-1][0]; - for bi := 0 to pred(h_samp_factor) do - begin - thisblockrow^[bi][0] := lastDC; - end; - Inc(JBLOCK_PTR(thisblockrow), h_samp_factor); { advance to next MCU in row } - Inc(JBLOCK_PTR(lastblockrow), h_samp_factor); - end; - end; - end; - Inc(compptr); - end; - { NB: compress_output will increment iMCU_row_num if successful. - A suspension return will result in redoing all the work above next time.} - - - { Emit data to the entropy encoder, sharing code with subsequent passes } - compress_first_pass := compress_output(cinfo, input_buf); -end; - - -{ Process some data in subsequent passes of a multi-pass case. - We process the equivalent of one fully interleaved MCU row ("iMCU" row) - per call, ie, v_samp_factor block rows for each component in the scan. - The data is obtained from the virtual arrays and fed to the entropy coder. - Returns TRUE if the iMCU row is completed, FALSE if suspended. - - NB: input_buf is ignored; it is likely to be a NIL pointer. } - -{METHODDEF} -function compress_output (cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; -var - coef : my_coef_ptr; - MCU_col_num : JDIMENSION; { index of current MCU within row } - blkn, ci, xindex, yindex, yoffset : int; - start_col : JDIMENSION; - buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY; - buffer_ptr : JBLOCKROW; - compptr : jpeg_component_info_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - - { Align the virtual buffers for the components used in this scan. - NB: during first pass, this is safe only because the buffers will - already be aligned properly, so jmemmgr.c won't need to do any I/O. } - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - buffer[ci] := cinfo^.mem^.access_virt_barray ( - j_common_ptr(cinfo), coef^.whole_image[compptr^.component_index], - coef^.iMCU_row_num * JDIMENSION(compptr^.v_samp_factor), - JDIMENSION (compptr^.v_samp_factor), FALSE); - end; - - { Loop to process one whole iMCU row } - for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do - begin - for MCU_col_num := coef^.mcu_ctr to pred(cinfo^.MCUs_per_row) do - begin - { Construct list of pointers to DCT blocks belonging to this MCU } - blkn := 0; { index of current DCT block within MCU } - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - start_col := MCU_col_num * JDIMENSION(compptr^.MCU_width); - for yindex := 0 to pred(compptr^.MCU_height) do - begin - buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]); - for xindex := 0 to pred(compptr^.MCU_width) do - begin - coef^.MCU_buffer[blkn] := buffer_ptr; - Inc(blkn); - Inc(JBLOCK_PTR(buffer_ptr)); - end; - end; - end; - { Try to write the MCU. } - if (not cinfo^.entropy^.encode_mcu (cinfo, coef^.MCU_buffer)) then - begin - { Suspension forced; update state counters and exit } - coef^.MCU_vert_offset := yoffset; - coef^.mcu_ctr := MCU_col_num; - compress_output := FALSE; - exit; - end; - end; - { Completed an MCU row, but perhaps not an iMCU row } - coef^.mcu_ctr := 0; - end; - { Completed the iMCU row, advance counters for next one } - Inc(coef^.iMCU_row_num); - start_iMCU_row(cinfo); - compress_output := TRUE; -end; - -{$endif} { FULL_COEF_BUFFER_SUPPORTED } - - -{ Initialize coefficient buffer controller. } - -{GLOBAL} -procedure jinit_c_coef_controller (cinfo : j_compress_ptr; - need_full_buffer : boolean); -var - coef : my_coef_ptr; -var - buffer : JBLOCKROW; - i : int; -var - ci : int; - compptr : jpeg_component_info_ptr; -begin - coef := my_coef_ptr ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_coef_controller)) ); - cinfo^.coef := jpeg_c_coef_controller_ptr(coef); - coef^.pub.start_pass := start_pass_coef; - - { Create the coefficient buffer. } - if (need_full_buffer) then - begin -{$ifdef FULL_COEF_BUFFER_SUPPORTED} - { Allocate a full-image virtual array for each component, } - { padded to a multiple of samp_factor DCT blocks in each direction. } - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray - (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE, - JDIMENSION (jround_up( long (compptr^.width_in_blocks), - long (compptr^.h_samp_factor) )), - JDIMENSION (jround_up(long (compptr^.height_in_blocks), - long (compptr^.v_samp_factor))), - JDIMENSION (compptr^.v_samp_factor)); - Inc(compptr); - end; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); -{$endif} - end - else - begin - { We only need a single-MCU buffer. } - buffer := JBLOCKROW ( - cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE, - C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) ); - for i := 0 to pred(C_MAX_BLOCKS_IN_MCU) do - begin - coef^.MCU_buffer[i] := JBLOCKROW(@ buffer^[i]); - end; - coef^.whole_image[0] := NIL; { flag for no virtual arrays } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjccolor.pas b/3rd/Imaging/Source/JpegLib/imjccolor.pas deleted file mode 100644 index 0e8e16a8b..000000000 --- a/3rd/Imaging/Source/JpegLib/imjccolor.pas +++ /dev/null @@ -1,530 +0,0 @@ -unit imjccolor; - -{ This file contains input colorspace conversion routines. } - -{ Original : jccolor.c ; Copyright (C) 1991-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib; - -{ Module initialization routine for input colorspace conversion. } - -{GLOBAL} -procedure jinit_color_converter (cinfo : j_compress_ptr); - -implementation - -{ Private subobject } -type - INT32_FIELD = array[0..MaxInt div SizeOf(INT32) - 1] of INT32; - INT32_FIELD_PTR = ^INT32_FIELD; - -type - my_cconvert_ptr = ^my_color_converter; - my_color_converter = record - pub : jpeg_color_converter; { public fields } - - { Private state for RGB -> YCC conversion } - rgb_ycc_tab : INT32_FIELD_PTR; { => table for RGB to YCbCr conversion } - end; {my_color_converter;} - - -{*************** RGB -> YCbCr conversion: most common case *************} - -{ - YCbCr is defined per CCIR 601-1, except that Cb and Cr are - normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. - The conversion equations to be implemented are therefore - Y = 0.29900 * R + 0.58700 * G + 0.11400 * B - Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE - Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE - (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) - Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2, - rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and - negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0) - were not represented exactly. Now we sacrifice exact representation of - maximum red and maximum blue in order to get exact grayscales. - - To avoid floating-point arithmetic, we represent the fractional constants - as integers scaled up by 2^16 (about 4 digits precision); we have to divide - the products by 2^16, with appropriate rounding, to get the correct answer. - - For even more speed, we avoid doing any multiplications in the inner loop - by precalculating the constants times R,G,B for all possible values. - For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); - for 12-bit samples it is still acceptable. It's not very reasonable for - 16-bit samples, but if you want lossless storage you shouldn't be changing - colorspace anyway. - The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included - in the tables to save adding them separately in the inner loop. } -const - SCALEBITS = 16; { speediest right-shift on some machines } - CBCR_OFFSET = INT32(CENTERJSAMPLE shl SCALEBITS); - ONE_HALF = INT32(1) shl (SCALEBITS-1); - - -{ We allocate one big table and divide it up into eight parts, instead of - doing eight alloc_small requests. This lets us use a single table base - address, which can be held in a register in the inner loops on many - machines (more than can hold all eight addresses, anyway). } - - R_Y_OFF = 0; { offset to R => Y section } - G_Y_OFF = 1*(MAXJSAMPLE+1); { offset to G => Y section } - B_Y_OFF = 2*(MAXJSAMPLE+1); { etc. } - R_CB_OFF = 3*(MAXJSAMPLE+1); - G_CB_OFF = 4*(MAXJSAMPLE+1); - B_CB_OFF = 5*(MAXJSAMPLE+1); - R_CR_OFF = B_CB_OFF; { B=>Cb, R=>Cr are the same } - G_CR_OFF = 6*(MAXJSAMPLE+1); - B_CR_OFF = 7*(MAXJSAMPLE+1); - TABLE_SIZE = 8*(MAXJSAMPLE+1); - - -{ Initialize for RGB->YCC colorspace conversion. } - -{METHODDEF} -procedure rgb_ycc_start (cinfo : j_compress_ptr); -const - FIX_0_29900 = INT32(Round(0.29900 * (1 shl SCALEBITS))); - FIX_0_58700 = INT32(Round(0.58700 * (1 shl SCALEBITS))); - FIX_0_11400 = INT32(Round(0.11400 * (1 shl SCALEBITS))); - FIX_0_16874 = INT32(Round(0.16874 * (1 shl SCALEBITS))); - FIX_0_33126 = INT32(Round(0.33126 * (1 shl SCALEBITS))); - FIX_0_50000 = INT32(Round(0.50000 * (1 shl SCALEBITS))); - FIX_0_41869 = INT32(Round(0.41869 * (1 shl SCALEBITS))); - FIX_0_08131 = INT32(Round(0.08131 * (1 shl SCALEBITS))); -var - cconvert : my_cconvert_ptr; - rgb_ycc_tab : INT32_FIELD_PTR; - i : INT32; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - - { Allocate and fill in the conversion tables. } - rgb_ycc_tab := INT32_FIELD_PTR( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - (TABLE_SIZE * SIZEOF(INT32))) ); - cconvert^.rgb_ycc_tab := rgb_ycc_tab; - - for i := 0 to MAXJSAMPLE do - begin - rgb_ycc_tab^[i+R_Y_OFF] := FIX_0_29900 * i; - rgb_ycc_tab^[i+G_Y_OFF] := FIX_0_58700 * i; - rgb_ycc_tab^[i+B_Y_OFF] := FIX_0_11400 * i + ONE_HALF; - rgb_ycc_tab^[i+R_CB_OFF] := (-FIX_0_16874) * i; - rgb_ycc_tab^[i+G_CB_OFF] := (-FIX_0_33126) * i; - { We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr. - This ensures that the maximum output will round to MAXJSAMPLE - not MAXJSAMPLE+1, and thus that we don't have to range-limit. } - - rgb_ycc_tab^[i+B_CB_OFF] := FIX_0_50000 * i + CBCR_OFFSET + ONE_HALF-1; -{ B=>Cb and R=>Cr tables are the same - rgb_ycc_tab^[i+R_CR_OFF] := FIX_0_50000 * i + CBCR_OFFSET + ONE_HALF-1; -} - rgb_ycc_tab^[i+G_CR_OFF] := (-FIX_0_41869) * i; - rgb_ycc_tab^[i+B_CR_OFF] := (-FIX_0_08131) * i; - end; -end; - - -{ Convert some rows of samples to the JPEG colorspace. - - Note that we change from the application's interleaved-pixel format - to our internal noninterleaved, one-plane-per-component format. - The input buffer is therefore three times as wide as the output buffer. - - A starting row offset is provided only for the output buffer. The caller - can easily adjust the passed input_buf value to accommodate any row - offset required on that side. } - -{METHODDEF} -procedure rgb_ycc_convert (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPIMAGE; - output_row : JDIMENSION; - num_rows : int); -var - cconvert : my_cconvert_ptr; - {register} r, g, b : int; - {register} ctab : INT32_FIELD_PTR; - {register} inptr : JSAMPROW; - {register} outptr0, outptr1, outptr2 : JSAMPROW; - {register} col : JDIMENSION; - num_cols : JDIMENSION; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - ctab := cconvert^.rgb_ycc_tab; - num_cols := cinfo^.image_width; - - while (num_rows > 0) do - begin - Dec(num_rows); - inptr := input_buf^[0]; - Inc(JSAMPROW_PTR(input_buf)); - outptr0 := output_buf^[0]^[output_row]; - outptr1 := output_buf^[1]^[output_row]; - outptr2 := output_buf^[2]^[output_row]; - Inc(output_row); - for col := 0 to pred(num_cols) do - begin - r := GETJSAMPLE(inptr^[RGB_RED]); - g := GETJSAMPLE(inptr^[RGB_GREEN]); - b := GETJSAMPLE(inptr^[RGB_BLUE]); - Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE); - { If the inputs are 0..MAXJSAMPLE, the outputs of these equations - must be too; we do not need an explicit range-limiting operation. - Hence the value being shifted is never negative, and we don't - need the general RIGHT_SHIFT macro. } - - { Y } - outptr0^[col] := JSAMPLE( - ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF]) - shr SCALEBITS) ); - { Cb } - outptr1^[col] := JSAMPLE( - ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF]) - shr SCALEBITS) ); - { Cr } - outptr2^[col] := JSAMPLE( - ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF]) - shr SCALEBITS) ); - end; - end; -end; - - -{*************** Cases other than RGB -> YCbCr *************} - - -{ Convert some rows of samples to the JPEG colorspace. - This version handles RGB -> grayscale conversion, which is the same - as the RGB -> Y portion of RGB -> YCbCr. - We assume rgb_ycc_start has been called (we only use the Y tables). } - -{METHODDEF} -procedure rgb_gray_convert (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPIMAGE; - output_row : JDIMENSION; - num_rows : int); -var - cconvert : my_cconvert_ptr; - {register} r, g, b : int; - {register} ctab :INT32_FIELD_PTR; - {register} inptr : JSAMPROW; - {register} outptr : JSAMPROW; - {register} col : JDIMENSION; - num_cols : JDIMENSION; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - ctab := cconvert^.rgb_ycc_tab; - num_cols := cinfo^.image_width; - - while (num_rows > 0) do - begin - Dec(num_rows); - inptr := input_buf[0]; - Inc(JSAMPROW_PTR(input_buf)); - outptr := output_buf[0][output_row]; - Inc(output_row); - for col := 0 to num_cols - 1 do - begin - r := GETJSAMPLE(inptr[RGB_RED]); - g := GETJSAMPLE(inptr[RGB_GREEN]); - b := GETJSAMPLE(inptr[RGB_BLUE]); - Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE); - (* Y *) - // kylix 3 compiler crashes on this - // it also crashes Delphi OSX compiler 9 years later :( - {$IF not (Defined(DCC) and not Defined(MSWINDOWS))} - outptr[col] := JSAMPLE(((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF]) shr SCALEBITS)); - {$IFEND} - end; - end; -end; - - -{ Convert some rows of samples to the JPEG colorspace. - This version handles Adobe-style CMYK -> YCCK conversion, - where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same - conversion as above, while passing K (black) unchanged. - We assume rgb_ycc_start has been called. } - -{METHODDEF} -procedure cmyk_ycck_convert (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPIMAGE; - output_row : JDIMENSION; - num_rows : int); -var - cconvert : my_cconvert_ptr; - {register} r, g, b : int; - {register} ctab : INT32_FIELD_PTR; - {register} inptr : JSAMPROW; - {register} outptr0, outptr1, outptr2, outptr3 : JSAMPROW; - {register} col : JDIMENSION; - num_cols : JDIMENSION; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - ctab := cconvert^.rgb_ycc_tab; - num_cols := cinfo^.image_width; - - while (num_rows > 0) do - begin - Dec(num_rows); - inptr := input_buf^[0]; - Inc(JSAMPROW_PTR(input_buf)); - outptr0 := output_buf^[0]^[output_row]; - outptr1 := output_buf^[1]^[output_row]; - outptr2 := output_buf^[2]^[output_row]; - outptr3 := output_buf^[3]^[output_row]; - Inc(output_row); - for col := 0 to pred(num_cols) do - begin - r := MAXJSAMPLE - GETJSAMPLE(inptr^[0]); - g := MAXJSAMPLE - GETJSAMPLE(inptr^[1]); - b := MAXJSAMPLE - GETJSAMPLE(inptr^[2]); - { K passes through as-is } - outptr3^[col] := inptr^[3]; { don't need GETJSAMPLE here } - Inc(JSAMPLE_PTR(inptr), 4); - { If the inputs are 0..MAXJSAMPLE, the outputs of these equations - must be too; we do not need an explicit range-limiting operation. - Hence the value being shifted is never negative, and we don't - need the general RIGHT_SHIFT macro. } - - { Y } - outptr0^[col] := JSAMPLE ( - ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF]) - shr SCALEBITS) ); - { Cb } - outptr1^[col] := JSAMPLE( - ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF]) - shr SCALEBITS) ); - { Cr } - outptr2^[col] := JSAMPLE ( - ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF]) - shr SCALEBITS) ); - end; - end; -end; - - -{ Convert some rows of samples to the JPEG colorspace. - This version handles grayscale output with no conversion. - The source can be either plain grayscale or YCbCr (since Y = gray). } - -{METHODDEF} -procedure grayscale_convert (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPIMAGE; - output_row : JDIMENSION; - num_rows: int); -var - {register} inptr : JSAMPROW; - {register} outptr : JSAMPROW; - {register} col : JDIMENSION; - num_cols :JDIMENSION; - instride : int; -begin - num_cols := cinfo^.image_width; - instride := cinfo^.input_components; - - while (num_rows > 0) do - begin - Dec(num_rows); - inptr := input_buf^[0]; - Inc(JSAMPROW_PTR(input_buf)); - outptr := output_buf^[0]^[output_row]; - Inc(output_row); - for col := 0 to pred(num_cols) do - begin - outptr^[col] := inptr^[0]; { don't need GETJSAMPLE() here } - Inc(JSAMPLE_PTR(inptr), instride); - end; - end; -end; - - -{ Convert some rows of samples to the JPEG colorspace. - This version handles multi-component colorspaces without conversion. - We assume input_components = num_components. } - -{METHODDEF} -procedure null_convert (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPIMAGE; - output_row : JDIMENSION; - num_rows : int); -var - {register} inptr : JSAMPROW; - {register} outptr : JSAMPROW; - {register} col : JDIMENSION; - {register} ci : int; - nc : int; - num_cols : JDIMENSION; -begin - nc := cinfo^.num_components; - num_cols := cinfo^.image_width; - - while (num_rows > 0) do - begin - Dec(num_rows); - { It seems fastest to make a separate pass for each component. } - for ci := 0 to pred(nc) do - begin - inptr := input_buf^[0]; - outptr := output_buf^[ci]^[output_row]; - for col := 0 to pred(num_cols) do - begin - outptr^[col] := inptr^[ci]; { don't need GETJSAMPLE() here } - Inc(JSAMPLE_PTR(inptr), nc); - end; - end; - Inc(JSAMPROW_PTR(input_buf)); - Inc(output_row); - end; -end; - - -{ Empty method for start_pass. } - -{METHODDEF} -procedure null_method (cinfo : j_compress_ptr); -begin - { no work needed } -end; - - -{ Module initialization routine for input colorspace conversion. } - -{GLOBAL} -procedure jinit_color_converter (cinfo : j_compress_ptr); -var - cconvert : my_cconvert_ptr; -begin - cconvert := my_cconvert_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_color_converter)) ); - cinfo^.cconvert := jpeg_color_converter_ptr(cconvert); - { set start_pass to null method until we find out differently } - cconvert^.pub.start_pass := null_method; - - { Make sure input_components agrees with in_color_space } - case (cinfo^.in_color_space) of - JCS_GRAYSCALE: - if (cinfo^.input_components <> 1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); - -{$ifdef RGB_PIXELSIZE <> 3} - JCS_RGB: - if (cinfo^.input_components <> RGB_PIXELSIZE) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); -{$else} { share code with YCbCr } - JCS_RGB, -{$endif} - JCS_YCbCr: - if (cinfo^.input_components <> 3) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); - - JCS_CMYK, - JCS_YCCK: - if (cinfo^.input_components <> 4) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); - - else { JCS_UNKNOWN can be anything } - if (cinfo^.input_components < 1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); - end; - - { Check num_components, set conversion method based on requested space } - case (cinfo^.jpeg_color_space) of - JCS_GRAYSCALE: - begin - if (cinfo^.num_components <> 1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - if (cinfo^.in_color_space = JCS_GRAYSCALE) then - cconvert^.pub.color_convert := grayscale_convert - else - if (cinfo^.in_color_space = JCS_RGB) then - begin - cconvert^.pub.start_pass := rgb_ycc_start; - cconvert^.pub.color_convert := rgb_gray_convert; - end - else - if (cinfo^.in_color_space = JCS_YCbCr) then - cconvert^.pub.color_convert := grayscale_convert - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - JCS_RGB: - begin - if (cinfo^.num_components <> 3) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - if (cinfo^.in_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then - cconvert^.pub.color_convert := null_convert - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - JCS_YCbCr: - begin - if (cinfo^.num_components <> 3) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - if (cinfo^.in_color_space = JCS_RGB) then - begin - cconvert^.pub.start_pass := rgb_ycc_start; - cconvert^.pub.color_convert := rgb_ycc_convert; - end - else - if (cinfo^.in_color_space = JCS_YCbCr) then - cconvert^.pub.color_convert := null_convert - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - JCS_CMYK: - begin - if (cinfo^.num_components <> 4) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - if (cinfo^.in_color_space = JCS_CMYK) then - cconvert^.pub.color_convert := null_convert - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - JCS_YCCK: - begin - if (cinfo^.num_components <> 4) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - if (cinfo^.in_color_space = JCS_CMYK) then - begin - cconvert^.pub.start_pass := rgb_ycc_start; - cconvert^.pub.color_convert := cmyk_ycck_convert; - end - else - if (cinfo^.in_color_space = JCS_YCCK) then - cconvert^.pub.color_convert := null_convert - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - else { allow null conversion of JCS_UNKNOWN } - begin - if (cinfo^.jpeg_color_space <> cinfo^.in_color_space) or - (cinfo^.num_components <> cinfo^.input_components) then - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - cconvert^.pub.color_convert := null_convert; - end; - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcdctmgr.pas b/3rd/Imaging/Source/JpegLib/imjcdctmgr.pas deleted file mode 100644 index 29c1dda99..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcdctmgr.pas +++ /dev/null @@ -1,514 +0,0 @@ -unit imjcdctmgr; - -{ Original : jcdctmgr.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This file is part of the Independent JPEG Group's software. - For conditions of distribution and use, see the accompanying README file. - - This file contains the forward-DCT management logic. - This code selects a particular DCT implementation to be used, - and it performs related housekeeping chores including coefficient - quantization. } - -interface - -{$N+} -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjdct, { Private declarations for DCT subsystem } - imjfdctint, imjfdctfst, imjfdctflt; - -{ Initialize FDCT manager. } - -{GLOBAL} -procedure jinit_forward_dct (cinfo : j_compress_ptr); - -implementation - - -{ Private subobject for this module } - -type - my_fdct_ptr = ^my_fdct_controller; - my_fdct_controller = record - pub : jpeg_forward_dct; { public fields } - - { Pointer to the DCT routine actually in use } - do_dct : forward_DCT_method_ptr; - - { The actual post-DCT divisors --- not identical to the quant table - entries, because of scaling (especially for an unnormalized DCT). - Each table is given in normal array order. } - - divisors : array[0..NUM_QUANT_TBLS-1] of DCTELEM_FIELD_PTR; - - {$ifdef DCT_FLOAT_SUPPORTED} - { Same as above for the floating-point case. } - do_float_dct : float_DCT_method_ptr; - float_divisors : array[0..NUM_QUANT_TBLS-1] of FAST_FLOAT_FIELD_PTR; - {$endif} - end; - - -{ Initialize for a processing pass. - Verify that all referenced Q-tables are present, and set up - the divisor table for each one. - In the current implementation, DCT of all components is done during - the first pass, even if only some components will be output in the - first scan. Hence all components should be examined here. } - -{METHODDEF} -procedure start_pass_fdctmgr (cinfo : j_compress_ptr); -var - fdct : my_fdct_ptr; - ci, qtblno, i : int; - compptr : jpeg_component_info_ptr; - qtbl : JQUANT_TBL_PTR; - dtbl : DCTELEM_FIELD_PTR; -{$ifdef DCT_IFAST_SUPPORTED} -const - CONST_BITS = 14; - aanscales : array[0..DCTSIZE2-1] of INT16 = - ({ precomputed values scaled up by 14 bits } - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247); - {SHIFT_TEMPS} - - { Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - - function DESCALE(x : INT32; n : int) : INT32; - var - shift_temp : INT32; - begin - shift_temp := x + (INT32(1) shl (n-1)); - {$ifdef RIGHT_SHIFT_IS_UNSIGNED} - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else - {$endif} - Descale := (shift_temp shr n); - end; - -{$endif} -{$ifdef DCT_FLOAT_SUPPORTED} -var - fdtbl : FAST_FLOAT_FIELD_PTR; - row, col : int; -const - aanscalefactor : array[0..DCTSIZE-1] of double = - (1.0, 1.387039845, 1.306562965, 1.175875602, - 1.0, 0.785694958, 0.541196100, 0.275899379); -{$endif} -begin - fdct := my_fdct_ptr (cinfo^.fdct); - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - qtblno := compptr^.quant_tbl_no; - { Make sure specified quantization table is present } - if (qtblno < 0) or (qtblno >= NUM_QUANT_TBLS) or - (cinfo^.quant_tbl_ptrs[qtblno] = NIL) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_QUANT_TABLE, qtblno); - qtbl := cinfo^.quant_tbl_ptrs[qtblno]; - { Compute divisors for this quant table } - { We may do this more than once for same table, but it's not a big deal } - case (cinfo^.dct_method) of -{$ifdef DCT_ISLOW_SUPPORTED} - JDCT_ISLOW: - begin - { For LL&M IDCT method, divisors are equal to raw quantization - coefficients multiplied by 8 (to counteract scaling). } - - if (fdct^.divisors[qtblno] = NIL) then - begin - fdct^.divisors[qtblno] := DCTELEM_FIELD_PTR( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - DCTSIZE2 * SIZEOF(DCTELEM)) ); - end; - dtbl := fdct^.divisors[qtblno]; - for i := 0 to pred(DCTSIZE2) do - begin - dtbl^[i] := (DCTELEM(qtbl^.quantval[i])) shl 3; - end; - end; -{$endif} -{$ifdef DCT_IFAST_SUPPORTED} - JDCT_IFAST: - begin - { For AA&N IDCT method, divisors are equal to quantization - coefficients scaled by scalefactor[row]*scalefactor[col], where - scalefactor[0] := 1 - scalefactor[k] := cos(k*PI/16) * sqrt(2) for k=1..7 - We apply a further scale factor of 8. } - - - if (fdct^.divisors[qtblno] = NIL) then - begin - fdct^.divisors[qtblno] := DCTELEM_FIELD_PTR( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - DCTSIZE2 * SIZEOF(DCTELEM)) ); - end; - dtbl := fdct^.divisors[qtblno]; - for i := 0 to pred(DCTSIZE2) do - begin - dtbl^[i] := DCTELEM( - {MULTIPLY16V16} - DESCALE( INT32(qtbl^.quantval[i]) * INT32 (aanscales[i]), - CONST_BITS-3) ); - end; - end; -{$endif} -{$ifdef DCT_FLOAT_SUPPORTED} - - JDCT_FLOAT: - begin - { For float AA&N IDCT method, divisors are equal to quantization - coefficients scaled by scalefactor[row]*scalefactor[col], where - scalefactor[0] := 1 - scalefactor[k] := cos(k*PI/16) * sqrt(2) for k=1..7 - We apply a further scale factor of 8. - What's actually stored is 1/divisor so that the inner loop can - use a multiplication rather than a division. } - - if (fdct^.float_divisors[qtblno] = NIL) then - begin - fdct^.float_divisors[qtblno] := FAST_FLOAT_FIELD_PTR( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - DCTSIZE2 * SIZEOF(FAST_FLOAT)) ); - end; - fdtbl := fdct^.float_divisors[qtblno]; - i := 0; - for row := 0 to pred(DCTSIZE) do - begin - for col := 0 to pred(DCTSIZE) do - begin - fdtbl^[i] := {FAST_FLOAT} - (1.0 / (( {double}(qtbl^.quantval[i]) * - aanscalefactor[row] * aanscalefactor[col] * 8.0))); - Inc(i); - end; - end; - end; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); - end; - Inc(compptr); - end; -end; - - -{ Perform forward DCT on one or more blocks of a component. - - The input samples are taken from the sample_data[] array starting at - position start_row/start_col, and moving to the right for any additional - blocks. The quantized coefficients are returned in coef_blocks[]. } - -{METHODDEF} -procedure forward_DCT (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - sample_data : JSAMPARRAY; - coef_blocks : JBLOCKROW; - start_row : JDIMENSION; - start_col : JDIMENSION; - num_blocks : JDIMENSION); -{ This version is used for integer DCT implementations. } -var - { This routine is heavily used, so it's worth coding it tightly. } - fdct : my_fdct_ptr; - do_dct : forward_DCT_method_ptr; - divisors : DCTELEM_FIELD_PTR; - workspace : array[0..DCTSIZE2-1] of DCTELEM; { work area for FDCT subroutine } - bi : JDIMENSION; -var - {register} workspaceptr : DCTELEMPTR; - {register} elemptr : JSAMPLE_PTR; - {register} elemr : int; -{$ifndef DCTSIZE_IS_8} -var - {register} elemc : int; -{$endif} -var - {register} temp, qval : DCTELEM; - {register} i : int; - {register} output_ptr : JCOEFPTR; -begin - fdct := my_fdct_ptr (cinfo^.fdct); - do_dct := fdct^.do_dct; - divisors := fdct^.divisors[compptr^.quant_tbl_no]; - - Inc(JSAMPROW_PTR(sample_data), start_row); { fold in the vertical offset once } - - for bi := 0 to pred(num_blocks) do - begin - - { Load data into workspace, applying unsigned->signed conversion } - - workspaceptr := @workspace[0]; - for elemr := 0 to pred(DCTSIZE) do - begin - elemptr := @sample_data^[elemr]^[start_col]; -{$ifdef DCTSIZE_IS_8} { unroll the inner loop } - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - {Inc(elemptr); - Value never used } -{$else} - for elemc := pred(DCTSIZE) downto 0 do - begin - workspaceptr^ := GETJSAMPLE(elemptr^) - CENTERJSAMPLE; - Inc(workspaceptr); - Inc(elemptr); - end; -{$endif} - end; - - { Perform the DCT } - do_dct (workspace); - - { Quantize/descale the coefficients, and store into coef_blocks[] } - - output_ptr := JCOEFPTR(@coef_blocks^[bi]); - for i := 0 to pred(DCTSIZE2) do - begin - qval := divisors^[i]; - temp := workspace[i]; - { Divide the coefficient value by qval, ensuring proper rounding. - Since C does not specify the direction of rounding for negative - quotients, we have to force the dividend positive for portability. - - In most files, at least half of the output values will be zero - (at default quantization settings, more like three-quarters...) - so we should ensure that this case is fast. On many machines, - a comparison is enough cheaper than a divide to make a special test - a win. Since both inputs will be nonnegative, we need only test - for a < b to discover whether a/b is 0. - If your machine's division is fast enough, define FAST_DIVIDE. } - - if (temp < 0) then - begin - temp := -temp; - Inc(temp, qval shr 1); { for rounding } - {DIVIDE_BY(temp, qval);} - {$ifdef FAST_DIVIDE} - temp := temp div qval; - {$else} - if (temp >= qval) then - temp := temp div qval - else - temp := 0; - {$endif} - temp := -temp; - end - else - begin - Inc(temp, qval shr 1); { for rounding } - {DIVIDE_BY(temp, qval);} - {$ifdef FAST_DIVIDE} - temp := temp div qval; - {$else} - if (temp >= qval) then - temp := temp div qval - else - temp := 0; - {$endif} - end; - output_ptr^[i] := JCOEF (temp); - end; - Inc(start_col, DCTSIZE); - end; -end; - - -{$ifdef DCT_FLOAT_SUPPORTED} - -{METHODDEF} -procedure forward_DCT_float (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - sample_data : JSAMPARRAY; - coef_blocks : JBLOCKROW; - start_row : JDIMENSION; - start_col : JDIMENSION; - num_blocks : JDIMENSION); -{ This version is used for floating-point DCT implementations. } -var - { This routine is heavily used, so it's worth coding it tightly. } - fdct : my_fdct_ptr; - do_dct : float_DCT_method_ptr; - divisors : FAST_FLOAT_FIELD_PTR; - workspace : array[0..DCTSIZE2-1] of FAST_FLOAT; { work area for FDCT subroutine } - bi : JDIMENSION; -var - {register} workspaceptr : FAST_FLOAT_PTR; - {register} elemptr : JSAMPLE_PTR; - {register} elemr : int; -{$ifndef DCTSIZE_IS_8} -var - {register} elemc : int; -{$endif} -var - {register} temp : FAST_FLOAT; - {register} i : int; - {register} output_ptr : JCOEFPTR; -begin - fdct := my_fdct_ptr (cinfo^.fdct); - do_dct := fdct^.do_float_dct; - divisors := fdct^.float_divisors[compptr^.quant_tbl_no]; - - Inc(JSAMPROW_PTR(sample_data), start_row); { fold in the vertical offset once } - - for bi := 0 to pred(num_blocks) do - begin - { Load data into workspace, applying unsigned->signed conversion } - - workspaceptr := @workspace[0]; - for elemr := 0 to pred(DCTSIZE) do - begin - elemptr := @(sample_data^[elemr]^[start_col]); -{$ifdef DCTSIZE_IS_8} { unroll the inner loop } - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - Inc(elemptr); - workspaceptr^ := {FAST_FLOAT}(GETJSAMPLE(elemptr^) - CENTERJSAMPLE); - Inc(workspaceptr); - {Inc(elemptr); - value never used } -{$else} - for elemc := pred(DCTSIZE) downto 0 do - begin - workspaceptr^ := {FAST_FLOAT}( - (GETJSAMPLE(elemptr^) - CENTERJSAMPLE) ); - Inc(workspaceptr); - Inc(elemptr); - end; -{$endif} - end; - - - { Perform the DCT } - do_dct (workspace); - - { Quantize/descale the coefficients, and store into coef_blocks[] } - - output_ptr := JCOEFPTR(@(coef_blocks^[bi])); - - for i := 0 to pred(DCTSIZE2) do - begin - { Apply the quantization and scaling factor } - temp := workspace[i] * divisors^[i]; - { Round to nearest integer. - Since C does not specify the direction of rounding for negative - quotients, we have to force the dividend positive for portability. - The maximum coefficient size is +-16K (for 12-bit data), so this - code should work for either 16-bit or 32-bit ints. } - output_ptr^[i] := JCOEF ( int(Trunc (temp + {FAST_FLOAT}(16384.5))) - 16384); - end; - Inc(start_col, DCTSIZE); - end; -end; - -{$endif} { DCT_FLOAT_SUPPORTED } - - -{ Initialize FDCT manager. } - -{GLOBAL} -procedure jinit_forward_dct (cinfo : j_compress_ptr); -var - fdct : my_fdct_ptr; - i : int; -begin - fdct := my_fdct_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_fdct_controller)) ); - cinfo^.fdct := jpeg_forward_dct_ptr (fdct); - fdct^.pub.start_pass := start_pass_fdctmgr; - - case (cinfo^.dct_method) of -{$ifdef DCT_ISLOW_SUPPORTED} - JDCT_ISLOW: - begin - fdct^.pub.forward_DCT := forward_DCT; - fdct^.do_dct := jpeg_fdct_islow; - end; -{$endif} -{$ifdef DCT_IFAST_SUPPORTED} - JDCT_IFAST: - begin - fdct^.pub.forward_DCT := forward_DCT; - fdct^.do_dct := jpeg_fdct_ifast; - end; -{$endif} -{$ifdef DCT_FLOAT_SUPPORTED} - JDCT_FLOAT: - begin - fdct^.pub.forward_DCT := forward_DCT_float; - fdct^.do_float_dct := jpeg_fdct_float; - end; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); - end; - - { Mark divisor tables unallocated } - for i := 0 to pred(NUM_QUANT_TBLS) do - begin - fdct^.divisors[i] := NIL; -{$ifdef DCT_FLOAT_SUPPORTED} - fdct^.float_divisors[i] := NIL; -{$endif} - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjchuff.pas b/3rd/Imaging/Source/JpegLib/imjchuff.pas deleted file mode 100644 index ff004a416..000000000 --- a/3rd/Imaging/Source/JpegLib/imjchuff.pas +++ /dev/null @@ -1,1116 +0,0 @@ -unit imjchuff; - -{ This file contains Huffman entropy encoding routines. - - Much of the complexity here has to do with supporting output suspension. - If the data destination module demands suspension, we want to be able to - back up to the start of the current MCU. To do this, we copy state - variables into local working storage, and update them back to the - permanent JPEG objects only upon successful completion of an MCU. } - -{ Original: jchuff.c; Copyright (C) 1991-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, { longptr definition missing } - imjpeglib, - imjdeferr, - imjerror, - imjutils, - imjinclude, - imjcomapi; - -{ The legal range of a DCT coefficient is - -1024 .. +1023 for 8-bit data; - -16384 .. +16383 for 12-bit data. - Hence the magnitude should always fit in 10 or 14 bits respectively. } - - -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - MAX_COEF_BITS = 10; -{$else} -const - MAX_COEF_BITS = 14; -{$endif} - -{ Derived data constructed for each Huffman table } -{ Declarations shared with jcphuff.c } -type - c_derived_tbl_ptr = ^c_derived_tbl; - c_derived_tbl = record - ehufco : array[0..256-1] of uInt; { code for each symbol } - ehufsi : array[0..256-1] of byte; { length of code for each symbol } - { If no code has been allocated for a symbol S, ehufsi[S] contains 0 } - end; -{ for JCHUFF und JCPHUFF } -type - TLongTable = array[0..256] of long; - TLongTablePtr = ^TLongTable; - -{ Compute the derived values for a Huffman table. - Note this is also used by jcphuff.c. } - -{GLOBAL} -procedure jpeg_make_c_derived_tbl (cinfo : j_compress_ptr; - isDC : boolean; - tblno : int; - var pdtbl : c_derived_tbl_ptr); - -{ Generate the optimal coding for the given counts, fill htbl. - Note this is also used by jcphuff.c. } - -{GLOBAL} -procedure jpeg_gen_optimal_table (cinfo : j_compress_ptr; - htbl : JHUFF_TBL_PTR; - var freq : TLongTable); { Nomssi } - -{ Module initialization routine for Huffman entropy encoding. } - -{GLOBAL} -procedure jinit_huff_encoder (cinfo : j_compress_ptr); - -implementation - -{ Expanded entropy encoder object for Huffman encoding. - - The savable_state subrecord contains fields that change within an MCU, - but must not be updated permanently until we complete the MCU. } - -type - savable_state = record - put_buffer : INT32; { current bit-accumulation buffer } - put_bits : int; { # of bits now in it } - last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int; - { last DC coef for each component } - end; - - -type - huff_entropy_ptr = ^huff_entropy_encoder; - huff_entropy_encoder = record - pub : jpeg_entropy_encoder; { public fields } - - saved : savable_state; { Bit buffer & DC state at start of MCU } - - { These fields are NOT loaded into local working state. } - restarts_to_go : uInt; { MCUs left in this restart interval } - next_restart_num : int; { next restart number to write (0-7) } - - { Pointers to derived tables (these workspaces have image lifespan) } - dc_derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr; - ac_derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr; - - {$ifdef ENTROPY_OPT_SUPPORTED} { Statistics tables for optimization } - dc_count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr; - ac_count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr; - {$endif} - end; - - - -{ Working state while writing an MCU. - This struct contains all the fields that are needed by subroutines. } - -type - working_state = record - next_output_byte : JOCTETptr; { => next byte to write in buffer } - free_in_buffer : size_t; { # of byte spaces remaining in buffer } - cur : savable_state; { Current bit buffer & DC state } - cinfo : j_compress_ptr; { dump_buffer needs access to this } - end; - - -{ Forward declarations } -{METHODDEF} -function encode_mcu_huff (cinfo : j_compress_ptr; - const MCU_data : array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -procedure finish_pass_huff (cinfo : j_compress_ptr); forward; -{$ifdef ENTROPY_OPT_SUPPORTED} -{METHODDEF} -function encode_mcu_gather (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - forward; - -{METHODDEF} -procedure finish_pass_gather (cinfo : j_compress_ptr); forward; -{$endif} - - -{ Initialize for a Huffman-compressed scan. - If gather_statistics is TRUE, we do not output anything during the scan, - just count the Huffman symbols used and generate Huffman code tables. } - -{METHODDEF} -procedure start_pass_huff (cinfo : j_compress_ptr; - gather_statistics : boolean); -var - entropy : huff_entropy_ptr; - ci, dctbl, actbl : int; - compptr : jpeg_component_info_ptr; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - - if (gather_statistics) then - begin -{$ifdef ENTROPY_OPT_SUPPORTED} - entropy^.pub.encode_mcu := encode_mcu_gather; - entropy^.pub.finish_pass := finish_pass_gather; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - begin - entropy^.pub.encode_mcu := encode_mcu_huff; - entropy^.pub.finish_pass := finish_pass_huff; - end; - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - dctbl := compptr^.dc_tbl_no; - actbl := compptr^.ac_tbl_no; - if (gather_statistics) then - begin -{$ifdef ENTROPY_OPT_SUPPORTED} - { Check for invalid table indexes } - { (make_c_derived_tbl does this in the other path) } - if (dctbl < 0) or (dctbl >= NUM_HUFF_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, dctbl); - if (actbl < 0) or (actbl >= NUM_HUFF_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, actbl); - { Allocate and zero the statistics tables } - { Note that jpeg_gen_optimal_table expects 257 entries in each table! } - if (entropy^.dc_count_ptrs[dctbl] = NIL) then - entropy^.dc_count_ptrs[dctbl] := TLongTablePtr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - 257 * SIZEOF(long)) ); - MEMZERO(entropy^.dc_count_ptrs[dctbl], 257 * SIZEOF(long)); - if (entropy^.ac_count_ptrs[actbl] = NIL) then - entropy^.ac_count_ptrs[actbl] := TLongTablePtr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - 257 * SIZEOF(long)) ); - MEMZERO(entropy^.ac_count_ptrs[actbl], 257 * SIZEOF(long)); -{$endif} - end - else - begin - { Compute derived values for Huffman tables } - { We may do this more than once for a table, but it's not expensive } - jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl, - entropy^.dc_derived_tbls[dctbl]); - jpeg_make_c_derived_tbl(cinfo, FALSE, actbl, - entropy^.ac_derived_tbls[actbl]); - end; - { Initialize DC predictions to 0 } - entropy^.saved.last_dc_val[ci] := 0; - end; - - { Initialize bit buffer to empty } - entropy^.saved.put_buffer := 0; - entropy^.saved.put_bits := 0; - - { Initialize restart stuff } - entropy^.restarts_to_go := cinfo^.restart_interval; - entropy^.next_restart_num := 0; -end; - - -{ Compute the derived values for a Huffman table. - This routine also performs some validation checks on the table. - - Note this is also used by jcphuff.c. } - -{GLOBAL} -procedure jpeg_make_c_derived_tbl (cinfo : j_compress_ptr; - isDC : boolean; - tblno : int; - var pdtbl : c_derived_tbl_ptr); -var - htbl : JHUFF_TBL_PTR; - dtbl : c_derived_tbl_ptr; - p, i, l, lastp, si, maxsymbol : int; - huffsize : array[0..257-1] of byte; - huffcode : array[0..257-1] of uInt; - code : uInt; -begin - { Note that huffsize[] and huffcode[] are filled in code-length order, - paralleling the order of the symbols themselves in htbl->huffval[]. } - - { Find the input Huffman table } - if (tblno < 0) or (tblno >= NUM_HUFF_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno); - if isDC then - htbl := cinfo^.dc_huff_tbl_ptrs[tblno] - else - htbl := cinfo^.ac_huff_tbl_ptrs[tblno]; - if (htbl = NIL) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno); - - { Allocate a workspace if we haven't already done so. } - if (pdtbl = NIL) then - pdtbl := c_derived_tbl_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(c_derived_tbl)) ); - dtbl := pdtbl; - - { Figure C.1: make table of Huffman code length for each symbol } - - p := 0; - for l := 1 to 16 do - begin - i := int(htbl^.bits[l]); - if (i < 0) and (p + i > 256) then { protect against table overrun } - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - while (i > 0) do - begin - huffsize[p] := byte(l); - Inc(p); - Dec(i); - end; - end; - huffsize[p] := 0; - lastp := p; - - { Figure C.2: generate the codes themselves } - { We also validate that the counts represent a legal Huffman code tree. } - - code := 0; - si := huffsize[0]; - p := 0; - while (huffsize[p] <> 0) do - begin - while (( int(huffsize[p]) ) = si) do - begin - huffcode[p] := code; - Inc(p); - Inc(code); - end; - { code is now 1 more than the last code used for codelength si; but - it must still fit in si bits, since no code is allowed to be all ones. } - - if (INT32(code) >= (INT32(1) shl si)) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - code := code shl 1; - Inc(si); - end; - - { Figure C.3: generate encoding tables } - { These are code and size indexed by symbol value } - - { Set all codeless symbols to have code length 0; - this lets us detect duplicate VAL entries here, and later - allows emit_bits to detect any attempt to emit such symbols. } - - MEMZERO(@dtbl^.ehufsi, SIZEOF(dtbl^.ehufsi)); - - { This is also a convenient place to check for out-of-range - and duplicated VAL entries. We allow 0..255 for AC symbols - but only 0..15 for DC. (We could constrain them further - based on data depth and mode, but this seems enough.) } - - if isDC then - maxsymbol := 15 - else - maxsymbol := 255; - - for p := 0 to pred(lastp) do - begin - i := htbl^.huffval[p]; - if (i < 0) or (i > maxsymbol) or (dtbl^.ehufsi[i] <> 0) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - dtbl^.ehufco[i] := huffcode[p]; - dtbl^.ehufsi[i] := huffsize[p]; - end; -end; - - -{ Outputting bytes to the file } - - -{LOCAL} -function dump_buffer (var state : working_state) : boolean; -{ Empty the output buffer; return TRUE if successful, FALSE if must suspend } -var - dest : jpeg_destination_mgr_ptr; -begin - dest := state.cinfo^.dest; - - if (not dest^.empty_output_buffer (state.cinfo)) then - begin - dump_buffer := FALSE; - exit; - end; - { After a successful buffer dump, must reset buffer pointers } - state.next_output_byte := dest^.next_output_byte; - state.free_in_buffer := dest^.free_in_buffer; - dump_buffer := TRUE; -end; - - -{ Outputting bits to the file } - -{ Only the right 24 bits of put_buffer are used; the valid bits are - left-justified in this part. At most 16 bits can be passed to emit_bits - in one call, and we never retain more than 7 bits in put_buffer - between calls, so 24 bits are sufficient. } - - -{LOCAL} -function emit_bits (var state : working_state; - code : uInt; - size : int) : boolean; {INLINE} -{ Emit some bits; return TRUE if successful, FALSE if must suspend } -var - { This routine is heavily used, so it's worth coding tightly. } - {register} put_buffer : INT32; - {register} put_bits : int; -var - c : int; -begin - put_buffer := INT32 (code); - put_bits := state.cur.put_bits; - - { if size is 0, caller used an invalid Huffman table entry } - if (size = 0) then - ERREXIT(j_common_ptr(state.cinfo), JERR_HUFF_MISSING_CODE); - - put_buffer := put_buffer and pred(INT32(1) shl size); - { mask off any extra bits in code } - - Inc(put_bits, size); { new number of bits in buffer } - - put_buffer := put_buffer shl (24 - put_bits); - { align incoming bits } - put_buffer := put_buffer or state.cur.put_buffer; - { and merge with old buffer contents } - while (put_bits >= 8) do - begin - c := int ((put_buffer shr 16) and $FF); - - {emit_byte(state, c, return FALSE);} - { Emit a byte, return FALSE if must suspend. } - state.next_output_byte^ := JOCTET (c); - Inc(state.next_output_byte); - Dec(state.free_in_buffer); - if (state.free_in_buffer = 0) then - if not dump_buffer(state) then - begin - emit_bits := FALSE; - exit; - end; - - if (c = $FF) then { need to stuff a zero byte? } - begin - {emit_byte(state, 0, return FALSE);} - state.next_output_byte^ := JOCTET (0); - Inc(state.next_output_byte); - Dec(state.free_in_buffer); - if (state.free_in_buffer = 0) then - if not dump_buffer(state) then - begin - emit_bits := FALSE; - exit; - end; - - end; - put_buffer := put_buffer shl 8; - Dec(put_bits, 8); - end; - - state.cur.put_buffer := put_buffer; { update state variables } - state.cur.put_bits := put_bits; - - emit_bits := TRUE; -end; - - -{LOCAL} -function flush_bits (var state : working_state) : boolean; -begin - if (not emit_bits(state, $7F, 7)) then { fill any partial byte with ones } - begin - flush_bits := FALSE; - exit; - end; - state.cur.put_buffer := 0; { and reset bit-buffer to empty } - state.cur.put_bits := 0; - flush_bits := TRUE; -end; - - -{ Encode a single block's worth of coefficients } - -{LOCAL} -function encode_one_block (var state : working_state; - const block : JBLOCK; - last_dc_val : int; - dctbl : c_derived_tbl_ptr; - actbl : c_derived_tbl_ptr) : boolean; -var - {register} temp, temp2 : int; - {register} nbits : int; - {register} k, r, i : int; -begin - { Encode the DC coefficient difference per section F.1.2.1 } - - temp2 := block[0] - last_dc_val; - temp := temp2; - - if (temp < 0) then - begin - temp := -temp; { temp is abs value of input } - { For a negative input, want temp2 := bitwise complement of abs(input) } - { This code assumes we are on a two's complement machine } - Dec(temp2); - end; - - { Find the number of bits needed for the magnitude of the coefficient } - nbits := 0; - while (temp <> 0) do - begin - Inc(nbits); - temp := temp shr 1; - end; - - { Check for out-of-range coefficient values. - Since we're encoding a difference, the range limit is twice as much. } - - if (nbits > MAX_COEF_BITS+1) then - ERREXIT(j_common_ptr(state.cinfo), JERR_BAD_DCT_COEF); - - { Emit the Huffman-coded symbol for the number of bits } - if not emit_bits(state, dctbl^.ehufco[nbits], dctbl^.ehufsi[nbits]) then - begin - encode_one_block := FALSE; - exit; - end; - - { Emit that number of bits of the value, if positive, } - { or the complement of its magnitude, if negative. } - if (nbits <> 0) then { emit_bits rejects calls with size 0 } - if not emit_bits(state, uInt(temp2), nbits) then - begin - encode_one_block := FALSE; - exit; - end; - - { Encode the AC coefficients per section F.1.2.2 } - - r := 0; { r := run length of zeros } - - for k := 1 to pred(DCTSIZE2) do - begin - temp := block[jpeg_natural_order[k]]; - if (temp = 0) then - begin - Inc(r); - end - else - begin - { if run length > 15, must emit special run-length-16 codes ($F0) } - while (r > 15) do - begin - if not emit_bits(state, actbl^.ehufco[$F0], actbl^.ehufsi[$F0]) then - begin - encode_one_block := FALSE; - exit; - end; - Dec(r, 16); - end; - - temp2 := temp; - if (temp < 0) then - begin - temp := -temp; { temp is abs value of input } - { This code assumes we are on a two's complement machine } - Dec(temp2); - end; - - { Find the number of bits needed for the magnitude of the coefficient } - nbits := 0; { there must be at least one 1 bit } - repeat - Inc(nbits); - temp := temp shr 1; - until (temp = 0); - - { Check for out-of-range coefficient values } - if (nbits > MAX_COEF_BITS) then - ERREXIT(j_common_ptr(state.cinfo), JERR_BAD_DCT_COEF); - - { Emit Huffman symbol for run length / number of bits } - i := (r shl 4) + nbits; - if not emit_bits(state, actbl^.ehufco[i], actbl^.ehufsi[i]) then - begin - encode_one_block := FALSE; - exit; - end; - - { Emit that number of bits of the value, if positive, } - { or the complement of its magnitude, if negative. } - if not emit_bits(state, uInt(temp2), nbits) then - begin - encode_one_block := FALSE; - exit; - end; - - r := 0; - end; - end; - - { If the last coef(s) were zero, emit an end-of-block code } - if (r > 0) then - if not emit_bits(state, actbl^.ehufco[0], actbl^.ehufsi[0]) then - begin - encode_one_block := FALSE; - exit; - end; - - encode_one_block := TRUE; -end; - - -{ Emit a restart marker & resynchronize predictions. } - -{LOCAL} -function emit_restart (var state : working_state; - restart_num : int) : boolean; -var - ci : int; -begin - if (not flush_bits(state)) then - begin - emit_restart := FALSE; - exit; - end; - - {emit_byte(state, $FF, return FALSE);} - { Emit a byte, return FALSE if must suspend. } - state.next_output_byte^ := JOCTET ($FF); - Inc(state.next_output_byte); - Dec(state.free_in_buffer); - if (state.free_in_buffer = 0) then - if not dump_buffer(state) then - begin - emit_restart := FALSE; - exit; - end; - - {emit_byte(state, JPEG_RST0 + restart_num, return FALSE);} - { Emit a byte, return FALSE if must suspend. } - state.next_output_byte^ := JOCTET (JPEG_RST0 + restart_num); - Inc(state.next_output_byte); - Dec(state.free_in_buffer); - if (state.free_in_buffer = 0) then - if not dump_buffer(state) then - begin - emit_restart := FALSE; - exit; - end; - - { Re-initialize DC predictions to 0 } - for ci := 0 to pred(state.cinfo^.comps_in_scan) do - state.cur.last_dc_val[ci] := 0; - - { The restart counter is not updated until we successfully write the MCU. } - - emit_restart := TRUE; -end; - - -{ Encode and output one MCU's worth of Huffman-compressed coefficients. } - -{METHODDEF} -function encode_mcu_huff (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; -var - entropy : huff_entropy_ptr; - state : working_state; - blkn, ci : int; - compptr : jpeg_component_info_ptr; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - { Load up working state } - state.next_output_byte := cinfo^.dest^.next_output_byte; - state.free_in_buffer := cinfo^.dest^.free_in_buffer; - {ASSIGN_STATE(state.cur, entropy^.saved);} - state.cur := entropy^.saved; - state.cinfo := cinfo; - - { Emit restart marker if needed } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - if not emit_restart(state, entropy^.next_restart_num) then - begin - encode_mcu_huff := FALSE; - exit; - end; - end; - - { Encode the MCU data blocks } - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - ci := cinfo^.MCU_membership[blkn]; - compptr := cinfo^.cur_comp_info[ci]; - if not encode_one_block(state, - MCU_data[blkn]^[0], - state.cur.last_dc_val[ci], - entropy^.dc_derived_tbls[compptr^.dc_tbl_no], - entropy^.ac_derived_tbls[compptr^.ac_tbl_no]) then - begin - encode_mcu_huff := FALSE; - exit; - end; - { Update last_dc_val } - state.cur.last_dc_val[ci] := MCU_data[blkn]^[0][0]; - end; - - { Completed MCU, so update state } - cinfo^.dest^.next_output_byte := state.next_output_byte; - cinfo^.dest^.free_in_buffer := state.free_in_buffer; - {ASSIGN_STATE(entropy^.saved, state.cur);} - entropy^.saved := state.cur; - - { Update restart-interval state too } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - begin - entropy^.restarts_to_go := cinfo^.restart_interval; - Inc(entropy^.next_restart_num); - with entropy^ do - next_restart_num := next_restart_num and 7; - end; - Dec(entropy^.restarts_to_go); - end; - - encode_mcu_huff := TRUE; -end; - - -{ Finish up at the end of a Huffman-compressed scan. } - -{METHODDEF} -procedure finish_pass_huff (cinfo : j_compress_ptr); -var - entropy : huff_entropy_ptr; - state : working_state; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - - { Load up working state ... flush_bits needs it } - state.next_output_byte := cinfo^.dest^.next_output_byte; - state.free_in_buffer := cinfo^.dest^.free_in_buffer; - {ASSIGN_STATE(state.cur, entropy^.saved);} - state.cur := entropy^.saved; - state.cinfo := cinfo; - - { Flush out the last data } - if not flush_bits(state) then - ERREXIT(j_common_ptr(cinfo), JERR_CANT_SUSPEND); - - { Update state } - cinfo^.dest^.next_output_byte := state.next_output_byte; - cinfo^.dest^.free_in_buffer := state.free_in_buffer; - {ASSIGN_STATE(entropy^.saved, state.cur);} - entropy^.saved := state.cur; -end; - - -{ Huffman coding optimization. - - We first scan the supplied data and count the number of uses of each symbol - that is to be Huffman-coded. (This process MUST agree with the code above.) - Then we build a Huffman coding tree for the observed counts. - Symbols which are not needed at all for the particular image are not - assigned any code, which saves space in the DHT marker as well as in - the compressed data. } - -{$ifdef ENTROPY_OPT_SUPPORTED} - - -{ Process a single block's worth of coefficients } - -{LOCAL} -procedure htest_one_block (cinfo : j_compress_ptr; - const block : JBLOCK; - last_dc_val : int; - dc_counts : TLongTablePtr; - ac_counts : TLongTablePtr); - -var - {register} temp : int; - {register} nbits : int; - {register} k, r : int; -begin - { Encode the DC coefficient difference per section F.1.2.1 } - temp := block[0] - last_dc_val; - if (temp < 0) then - temp := -temp; - - { Find the number of bits needed for the magnitude of the coefficient } - nbits := 0; - while (temp <> 0) do - begin - Inc(nbits); - temp := temp shr 1; - end; - - { Check for out-of-range coefficient values. - Since we're encoding a difference, the range limit is twice as much. } - - if (nbits > MAX_COEF_BITS+1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_DCT_COEF); - - { Count the Huffman symbol for the number of bits } - Inc(dc_counts^[nbits]); - - { Encode the AC coefficients per section F.1.2.2 } - - r := 0; { r := run length of zeros } - - for k := 1 to pred(DCTSIZE2) do - begin - temp := block[jpeg_natural_order[k]]; - if (temp = 0) then - begin - Inc(r); - end - else - begin - { if run length > 15, must emit special run-length-16 codes ($F0) } - while (r > 15) do - begin - Inc(ac_counts^[$F0]); - Dec(r, 16); - end; - - { Find the number of bits needed for the magnitude of the coefficient } - if (temp < 0) then - temp := -temp; - - { Find the number of bits needed for the magnitude of the coefficient } - nbits := 0; { there must be at least one 1 bit } - repeat - Inc(nbits); - temp := temp shr 1; - until (temp = 0); - - - { Count Huffman symbol for run length / number of bits } - Inc(ac_counts^[(r shl 4) + nbits]); - - r := 0; - end; - end; - - { If the last coef(s) were zero, emit an end-of-block code } - if (r > 0) then - Inc(ac_counts^[0]); -end; - - -{ Trial-encode one MCU's worth of Huffman-compressed coefficients. - No data is actually output, so no suspension return is possible. } - -{METHODDEF} -function encode_mcu_gather (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; -var - entropy : huff_entropy_ptr; - blkn, ci : int; - compptr : jpeg_component_info_ptr; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - { Take care of restart intervals if needed } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - begin - { Re-initialize DC predictions to 0 } - for ci := 0 to pred(cinfo^.comps_in_scan) do - entropy^.saved.last_dc_val[ci] := 0; - { Update restart state } - entropy^.restarts_to_go := cinfo^.restart_interval; - end; - Dec(entropy^.restarts_to_go); - end; - - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - ci := cinfo^.MCU_membership[blkn]; - compptr := cinfo^.cur_comp_info[ci]; - htest_one_block(cinfo, MCU_data[blkn]^[0], - entropy^.saved.last_dc_val[ci], - entropy^.dc_count_ptrs[compptr^.dc_tbl_no], - entropy^.ac_count_ptrs[compptr^.ac_tbl_no]); - entropy^.saved.last_dc_val[ci] := MCU_data[blkn]^[0][0]; - end; - - encode_mcu_gather := TRUE; -end; - - -{ Generate the best Huffman code table for the given counts, fill htbl. - Note this is also used by jcphuff.c. - - The JPEG standard requires that no symbol be assigned a codeword of all - one bits (so that padding bits added at the end of a compressed segment - can't look like a valid code). Because of the canonical ordering of - codewords, this just means that there must be an unused slot in the - longest codeword length category. Section K.2 of the JPEG spec suggests - reserving such a slot by pretending that symbol 256 is a valid symbol - with count 1. In theory that's not optimal; giving it count zero but - including it in the symbol set anyway should give a better Huffman code. - But the theoretically better code actually seems to come out worse in - practice, because it produces more all-ones bytes (which incur stuffed - zero bytes in the final file). In any case the difference is tiny. - - The JPEG standard requires Huffman codes to be no more than 16 bits long. - If some symbols have a very small but nonzero probability, the Huffman tree - must be adjusted to meet the code length restriction. We currently use - the adjustment method suggested in JPEG section K.2. This method is *not* - optimal; it may not choose the best possible limited-length code. But - typically only very-low-frequency symbols will be given less-than-optimal - lengths, so the code is almost optimal. Experimental comparisons against - an optimal limited-length-code algorithm indicate that the difference is - microscopic --- usually less than a hundredth of a percent of total size. - So the extra complexity of an optimal algorithm doesn't seem worthwhile. } - - -{GLOBAL} -procedure jpeg_gen_optimal_table (cinfo : j_compress_ptr; - htbl : JHUFF_TBL_PTR; - var freq : TLongTable); -const - MAX_CLEN = 32; { assumed maximum initial code length } -var - bits : array[0..MAX_CLEN+1-1] of UINT8; { bits[k] := # of symbols with code length k } - codesize : array[0..257-1] of int; { codesize[k] := code length of symbol k } - others : array[0..257-1] of int; { next symbol in current branch of tree } - c1, c2 : int; - p, i, j : int; - v : long; -begin - { This algorithm is explained in section K.2 of the JPEG standard } - - MEMZERO(@bits, SIZEOF(bits)); - MEMZERO(@codesize, SIZEOF(codesize)); - for i := 0 to 256 do - others[i] := -1; { init links to empty } - - freq[256] := 1; { make sure 256 has a nonzero count } - { Including the pseudo-symbol 256 in the Huffman procedure guarantees - that no real symbol is given code-value of all ones, because 256 - will be placed last in the largest codeword category. } - - { Huffman's basic algorithm to assign optimal code lengths to symbols } - - while TRUE do - begin - { Find the smallest nonzero frequency, set c1 := its symbol } - { In case of ties, take the larger symbol number } - c1 := -1; - v := long(1000000000); - for i := 0 to 256 do - begin - if (freq[i] <> 0) and (freq[i] <= v) then - begin - v := freq[i]; - c1 := i; - end; - end; - - { Find the next smallest nonzero frequency, set c2 := its symbol } - { In case of ties, take the larger symbol number } - c2 := -1; - v := long(1000000000); - for i := 0 to 256 do - begin - if (freq[i] <> 0) and (freq[i] <= v) and (i <> c1) then - begin - v := freq[i]; - c2 := i; - end; - end; - - { Done if we've merged everything into one frequency } - if (c2 < 0) then - break; - - { Else merge the two counts/trees } - Inc(freq[c1], freq[c2]); - freq[c2] := 0; - - { Increment the codesize of everything in c1's tree branch } - Inc(codesize[c1]); - while (others[c1] >= 0) do - begin - c1 := others[c1]; - Inc(codesize[c1]); - end; - - others[c1] := c2; { chain c2 onto c1's tree branch } - - { Increment the codesize of everything in c2's tree branch } - Inc(codesize[c2]); - while (others[c2] >= 0) do - begin - c2 := others[c2]; - Inc(codesize[c2]); - end; - end; - - { Now count the number of symbols of each code length } - for i := 0 to 256 do - begin - if (codesize[i]<>0) then - begin - { The JPEG standard seems to think that this can't happen, } - { but I'm paranoid... } - if (codesize[i] > MAX_CLEN) then - ERREXIT(j_common_ptr(cinfo), JERR_HUFF_CLEN_OVERFLOW); - - Inc(bits[codesize[i]]); - end; - end; - - { JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure - Huffman procedure assigned any such lengths, we must adjust the coding. - Here is what the JPEG spec says about how this next bit works: - Since symbols are paired for the longest Huffman code, the symbols are - removed from this length category two at a time. The prefix for the pair - (which is one bit shorter) is allocated to one of the pair; then, - skipping the BITS entry for that prefix length, a code word from the next - shortest nonzero BITS entry is converted into a prefix for two code words - one bit longer. } - - for i := MAX_CLEN downto 17 do - begin - while (bits[i] > 0) do - begin - j := i - 2; { find length of new prefix to be used } - while (bits[j] = 0) do - Dec(j); - - Dec(bits[i], 2); { remove two symbols } - Inc(bits[i-1]); { one goes in this length } - Inc(bits[j+1], 2); { two new symbols in this length } - Dec(bits[j]); { symbol of this length is now a prefix } - end; - end; - - { Delphi 2: FOR-loop variable 'i' may be undefined after loop } - i := 16; { Nomssi: work around } - - { Remove the count for the pseudo-symbol 256 from the largest codelength } - while (bits[i] = 0) do { find largest codelength still in use } - Dec(i); - Dec(bits[i]); - - { Return final symbol counts (only for lengths 0..16) } - MEMCOPY(@htbl^.bits, @bits, SIZEOF(htbl^.bits)); - - { Return a list of the symbols sorted by code length } - { It's not real clear to me why we don't need to consider the codelength - changes made above, but the JPEG spec seems to think this works. } - - p := 0; - for i := 1 to MAX_CLEN do - begin - for j := 0 to 255 do - begin - if (codesize[j] = i) then - begin - htbl^.huffval[p] := UINT8 (j); - Inc(p); - end; - end; - end; - - { Set sent_table FALSE so updated table will be written to JPEG file. } - htbl^.sent_table := FALSE; -end; - - -{ Finish up a statistics-gathering pass and create the new Huffman tables. } - -{METHODDEF} -procedure finish_pass_gather (cinfo : j_compress_ptr); -var - entropy : huff_entropy_ptr; - ci, dctbl, actbl : int; - compptr : jpeg_component_info_ptr; - htblptr : ^JHUFF_TBL_PTR; - did_dc : array[0..NUM_HUFF_TBLS-1] of boolean; - did_ac : array[0..NUM_HUFF_TBLS-1] of boolean; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - - { It's important not to apply jpeg_gen_optimal_table more than once - per table, because it clobbers the input frequency counts! } - - MEMZERO(@did_dc, SIZEOF(did_dc)); - MEMZERO(@did_ac, SIZEOF(did_ac)); - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - dctbl := compptr^.dc_tbl_no; - actbl := compptr^.ac_tbl_no; - if (not did_dc[dctbl]) then - begin - htblptr := @(cinfo^.dc_huff_tbl_ptrs[dctbl]); - if ( htblptr^ = NIL) then - htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo)); - jpeg_gen_optimal_table(cinfo, htblptr^, entropy^.dc_count_ptrs[dctbl]^); - did_dc[dctbl] := TRUE; - end; - if (not did_ac[actbl]) then - begin - htblptr := @(cinfo^.ac_huff_tbl_ptrs[actbl]); - if ( htblptr^ = NIL) then - htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo)); - jpeg_gen_optimal_table(cinfo, htblptr^, entropy^.ac_count_ptrs[actbl]^); - did_ac[actbl] := TRUE; - end; - end; -end; - -{$endif} { ENTROPY_OPT_SUPPORTED } - - -{ Module initialization routine for Huffman entropy encoding. } - -{GLOBAL} -procedure jinit_huff_encoder (cinfo : j_compress_ptr); -var - entropy : huff_entropy_ptr; - i : int; -begin - entropy := huff_entropy_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(huff_entropy_encoder)) ); - cinfo^.entropy := jpeg_entropy_encoder_ptr (entropy); - entropy^.pub.start_pass := start_pass_huff; - - { Mark tables unallocated } - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - entropy^.ac_derived_tbls[i] := NIL; - entropy^.dc_derived_tbls[i] := NIL; -{$ifdef ENTROPY_OPT_SUPPORTED} - entropy^.ac_count_ptrs[i] := NIL; - entropy^.dc_count_ptrs[i] := NIL; -{$endif} - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcinit.pas b/3rd/Imaging/Source/JpegLib/imjcinit.pas deleted file mode 100644 index 2a844e6b8..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcinit.pas +++ /dev/null @@ -1,95 +0,0 @@ -unit imjcinit; - -{ Original: jcinit.c ; Copyright (C) 1991-1997, Thomas G. Lane. } - -{ This file contains initialization logic for the JPEG compressor. - This routine is in charge of selecting the modules to be executed and - making an initialization call to each one. - - Logically, this code belongs in jcmaster.c. It's split out because - linking this routine implies linking the entire compression library. - For a transcoding-only application, we want to be able to use jcmaster.c - without linking in the whole library. } - -interface - -{$I imjconfig.inc} - -uses - imjinclude, - imjdeferr, - imjerror, - imjpeglib, -{$ifdef C_PROGRESSIVE_SUPPORTED} - imjcphuff, -{$endif} - imjchuff, imjcmaster, imjccolor, imjcsample, imjcprepct, - imjcdctmgr, imjccoefct, imjcmainct, imjcmarker; - -{ Master selection of compression modules. - This is done once at the start of processing an image. We determine - which modules will be used and give them appropriate initialization calls. } - -{GLOBAL} -procedure jinit_compress_master (cinfo : j_compress_ptr); - -implementation - - - -{ Master selection of compression modules. - This is done once at the start of processing an image. We determine - which modules will be used and give them appropriate initialization calls. } - -{GLOBAL} -procedure jinit_compress_master (cinfo : j_compress_ptr); -begin - { Initialize master control (includes parameter checking/processing) } - jinit_c_master_control(cinfo, FALSE { full compression }); - - { Preprocessing } - if (not cinfo^.raw_data_in) then - begin - jinit_color_converter(cinfo); - jinit_downsampler(cinfo); - jinit_c_prep_controller(cinfo, FALSE { never need full buffer here }); - end; - { Forward DCT } - jinit_forward_dct(cinfo); - { Entropy encoding: either Huffman or arithmetic coding. } - if (cinfo^.arith_code) then - begin - ERREXIT(j_common_ptr(cinfo), JERR_ARITH_NOTIMPL); - end - else - begin - if (cinfo^.progressive_mode) then - begin -{$ifdef C_PROGRESSIVE_SUPPORTED} - jinit_phuff_encoder(cinfo); -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - jinit_huff_encoder(cinfo); - end; - - { Need a full-image coefficient buffer in any multi-pass mode. } - jinit_c_coef_controller(cinfo, - (cinfo^.num_scans > 1) or (cinfo^.optimize_coding)); - jinit_c_main_controller(cinfo, FALSE { never need full buffer here }); - - jinit_marker_writer(cinfo); - - { We can now tell the memory manager to allocate virtual arrays. } - cinfo^.mem^.realize_virt_arrays (j_common_ptr(cinfo)); - - { Write the datastream header (SOI) immediately. - Frame and scan headers are postponed till later. - This lets application insert special markers after the SOI. } - - cinfo^.marker^.write_file_header (cinfo); -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcmainct.pas b/3rd/Imaging/Source/JpegLib/imjcmainct.pas deleted file mode 100644 index 196fad413..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcmainct.pas +++ /dev/null @@ -1,343 +0,0 @@ -unit imjcmainct; - -{ This file contains the main buffer controller for compression. - The main buffer lies between the pre-processor and the JPEG - compressor proper; it holds downsampled data in the JPEG colorspace. } - -{ Original : jcmainct.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -{ Note: currently, there is no operating mode in which a full-image buffer - is needed at this step. If there were, that mode could not be used with - "raw data" input, since this module is bypassed in that case. However, - we've left the code here for possible use in special applications. } - -{$undef FULL_MAIN_BUFFER_SUPPORTED} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} - imjutils, -{$endif} - imjpeglib; - -{ Initialize main buffer controller. } - -{GLOBAL} -procedure jinit_c_main_controller (cinfo : j_compress_ptr; - need_full_buffer : boolean); - -implementation - - -{ Private buffer controller object } - -type - my_main_ptr = ^my_main_controller; - my_main_controller = record - pub : jpeg_c_main_controller; { public fields } - - cur_iMCU_row : JDIMENSION; { number of current iMCU row } - rowgroup_ctr : JDIMENSION; { counts row groups received in iMCU row } - suspended : boolean; { remember if we suspended output } - pass_mode : J_BUF_MODE; { current operating mode } - - { If using just a strip buffer, this points to the entire set of buffers - (we allocate one for each component). In the full-image case, this - points to the currently accessible strips of the virtual arrays. } - - buffer : array[0..MAX_COMPONENTS-1] of JSAMPARRAY; - - {$ifdef FULL_MAIN_BUFFER_SUPPORTED} - { If using full-image storage, this array holds pointers to virtual-array - control blocks for each component. Unused if not full-image storage. } - - whole_image : array[0..MAX_COMPONENTS-1] of jvirt_sarray_ptr; - {$endif} - end; {my_main_controller} - - -{ Forward declarations } -{METHODDEF} -procedure process_data_simple_main(cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr: JDIMENSION; - in_rows_avail : JDIMENSION); forward; - -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} -{METHODDEF} -procedure process_data_buffer_main(cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION); forward; -{$endif} - - -{ Initialize for a processing pass. } - -{METHODDEF} -procedure start_pass_main (cinfo : j_compress_ptr; - pass_mode : J_BUF_MODE); -var - main : my_main_ptr; -begin - main := my_main_ptr (cinfo^.main); - - { Do nothing in raw-data mode. } - if (cinfo^.raw_data_in) then - exit; - - main^.cur_iMCU_row := 0; { initialize counters } - main^.rowgroup_ctr := 0; - main^.suspended := FALSE; - main^.pass_mode := pass_mode; { save mode for use by process_data } - - case (pass_mode) of - JBUF_PASS_THRU: - begin -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} - if (main^.whole_image[0] <> NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); -{$endif} - main^.pub.process_data := process_data_simple_main; - end; -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} - JBUF_SAVE_SOURCE, - JBUF_CRANK_DEST, - JBUF_SAVE_AND_PASS: - begin - if (main^.whole_image[0] = NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - main^.pub.process_data := process_data_buffer_main; - end; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - end; -end; - - -{ Process some data. - This routine handles the simple pass-through mode, - where we have only a strip buffer. } - -{METHODDEF} -procedure process_data_simple_main (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION); -var - main : my_main_ptr; -begin - main := my_main_ptr (cinfo^.main); - - while (main^.cur_iMCU_row < cinfo^.total_iMCU_rows) do - begin - { Read input data if we haven't filled the main buffer yet } - if (main^.rowgroup_ctr < DCTSIZE) then - cinfo^.prep^.pre_process_data (cinfo, - input_buf, - in_row_ctr, - in_rows_avail, - JSAMPIMAGE(@main^.buffer), - main^.rowgroup_ctr, - JDIMENSION(DCTSIZE)); - - { If we don't have a full iMCU row buffered, return to application for - more data. Note that preprocessor will always pad to fill the iMCU row - at the bottom of the image. } - if (main^.rowgroup_ctr <> DCTSIZE) then - exit; - - { Send the completed row to the compressor } - if (not cinfo^.coef^.compress_data (cinfo, JSAMPIMAGE(@main^.buffer))) then - begin - { If compressor did not consume the whole row, then we must need to - suspend processing and return to the application. In this situation - we pretend we didn't yet consume the last input row; otherwise, if - it happened to be the last row of the image, the application would - think we were done. } - - if (not main^.suspended) then - begin - Dec(in_row_ctr); - main^.suspended := TRUE; - end; - exit; - end; - { We did finish the row. Undo our little suspension hack if a previous - call suspended; then mark the main buffer empty. } - - if (main^.suspended) then - begin - Inc(in_row_ctr); - main^.suspended := FALSE; - end; - main^.rowgroup_ctr := 0; - Inc(main^.cur_iMCU_row); - end; -end; - - -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} - -{ Process some data. - This routine handles all of the modes that use a full-size buffer. } - -{METHODDEF} -procedure process_data_buffer_main (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION); -var - main : my_main_ptr; - ci : int; - compptr : jpeg_component_info_ptr; - writing : boolean; -begin - main := my_main_ptr (cinfo^.main); - writing := (main^.pass_mode <> JBUF_CRANK_DEST); - - while (main^.cur_iMCU_row < cinfo^.total_iMCU_rows) do - begin - { Realign the virtual buffers if at the start of an iMCU row. } - if (main^.rowgroup_ctr = 0) then - begin - compptr := cinfo^.comp_info; - for ci := 0 to pred(cinfo^.num_components) do - begin - main^.buffer[ci] := cinfo^.mem^.access_virt_sarray - (j_common_ptr (cinfo), main^.whole_image[ci], - main^.cur_iMCU_row * (compptr^.v_samp_factor * DCTSIZE), - JDIMENSION (compptr^.v_samp_factor * DCTSIZE), writing); - Inc(compptr); - end; - { In a read pass, pretend we just read some source data. } - if (not writing) then - begin - Inc(in_row_ctr, cinfo^.max_v_samp_factor * DCTSIZE); - main^.rowgroup_ctr := DCTSIZE; - end; - end; - - { If a write pass, read input data until the current iMCU row is full. } - { Note: preprocessor will pad if necessary to fill the last iMCU row. } - if (writing) then - begin - cinfo^.prep^.pre_process_data (cinfo, - input_buf, in_row_ctr, in_rows_avail, - JSAMPIMAGE(@main^.buffer), - main^.rowgroup_ctr, - JDIMENSION (DCTSIZE)); - - { Return to application if we need more data to fill the iMCU row. } - if (main^.rowgroup_ctr < DCTSIZE) then - exit; - end; - - { Emit data, unless this is a sink-only pass. } - if (main^.pass_mode <> JBUF_SAVE_SOURCE) then - begin - if (not cinfo^.coef^.compress_data (cinfo, - JSAMPIMAGE(@main^.buffer))) then - begin - { If compressor did not consume the whole row, then we must need to - suspend processing and return to the application. In this situation - we pretend we didn't yet consume the last input row; otherwise, if - it happened to be the last row of the image, the application would - think we were done. } - - if (not main^.suspended) then - begin - Dec(in_row_ctr); - main^.suspended := TRUE; - end; - exit; - end; - { We did finish the row. Undo our little suspension hack if a previous - call suspended; then mark the main buffer empty. } - - if (main^.suspended) then - begin - Inc(in_row_ctr); - main^.suspended := FALSE; - end; - end; - - { If get here, we are done with this iMCU row. Mark buffer empty. } - main^.rowgroup_ctr := 0; - Inc(main^.cur_iMCU_row); - end; -end; - -{$endif} { FULL_MAIN_BUFFER_SUPPORTED } - - -{ Initialize main buffer controller. } - -{GLOBAL} -procedure jinit_c_main_controller (cinfo : j_compress_ptr; - need_full_buffer : boolean); -var - main : my_main_ptr; - ci : int; - compptr : jpeg_component_info_ptr; -begin - main := my_main_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_main_controller)) ); - cinfo^.main := jpeg_c_main_controller_ptr(main); - main^.pub.start_pass := start_pass_main; - - { We don't need to create a buffer in raw-data mode. } - if (cinfo^.raw_data_in) then - exit; - - { Create the buffer. It holds downsampled data, so each component - may be of a different size. } - - if (need_full_buffer) then - begin -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} - { Allocate a full-image virtual array for each component } - { Note we pad the bottom to a multiple of the iMCU height } - compptr := cinfo^.comp_info; - for ci := 0 to pred(cinfo^.num_components) do - begin - main^.whole_image[ci] := cinfo^.mem^.request_virt_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE, - compptr^.width_in_blocks * DCTSIZE, - JDIMENSION (jround_up( long (compptr^.height_in_blocks), - long (compptr^.v_samp_factor)) * DCTSIZE), - JDIMENSION (compptr^.v_samp_factor * DCTSIZE)); - Inc(compptr); - end; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); -{$endif} - end - else - begin -{$ifdef FULL_MAIN_BUFFER_SUPPORTED} - main^.whole_image[0] := NIL; { flag for no virtual arrays } -{$endif} - { Allocate a strip buffer for each component } - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - main^.buffer[ci] := cinfo^.mem^.alloc_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, - compptr^.width_in_blocks * DCTSIZE, - JDIMENSION (compptr^.v_samp_factor * DCTSIZE)); - Inc(compptr); - end; - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcmarker.pas b/3rd/Imaging/Source/JpegLib/imjcmarker.pas deleted file mode 100644 index d41560761..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcmarker.pas +++ /dev/null @@ -1,724 +0,0 @@ -unit imjcmarker; - -{ This file contains routines to write JPEG datastream markers. } - -{ Original: jcmarker.c; Copyright (C) 1991-1998, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjinclude, imjmorecfg, imjerror, - imjdeferr, imjpeglib, imjutils; - - -const - { JPEG marker codes } - M_SOF0 = $c0; - M_SOF1 = $c1; - M_SOF2 = $c2; - M_SOF3 = $c3; - - M_SOF5 = $c5; - M_SOF6 = $c6; - M_SOF7 = $c7; - - M_JPG = $c8; - M_SOF9 = $c9; - M_SOF10 = $ca; - M_SOF11 = $cb; - - M_SOF13 = $cd; - M_SOF14 = $ce; - M_SOF15 = $cf; - - M_DHT = $c4; - - M_DAC = $cc; - - M_RST0 = $d0; - M_RST1 = $d1; - M_RST2 = $d2; - M_RST3 = $d3; - M_RST4 = $d4; - M_RST5 = $d5; - M_RST6 = $d6; - M_RST7 = $d7; - - M_SOI = $d8; - M_EOI = $d9; - M_SOS = $da; - M_DQT = $db; - M_DNL = $dc; - M_DRI = $dd; - M_DHP = $de; - M_EXP = $df; - - M_APP0 = $e0; - M_APP1 = $e1; - M_APP2 = $e2; - M_APP3 = $e3; - M_APP4 = $e4; - M_APP5 = $e5; - M_APP6 = $e6; - M_APP7 = $e7; - M_APP8 = $e8; - M_APP9 = $e9; - M_APP10 = $ea; - M_APP11 = $eb; - M_APP12 = $ec; - M_APP13 = $ed; - M_APP14 = $ee; - M_APP15 = $ef; - - M_JPG0 = $f0; - M_JPG13 = $fd; - M_COM = $fe; - - M_TEM = $01; - - M_ERROR = $100; - -type - JPEG_MARKER = Word; - -{ Private state } - -type - my_marker_ptr = ^my_marker_writer; - my_marker_writer = record - pub : jpeg_marker_writer; { public fields } - - last_restart_interval : uint; { last DRI value emitted; 0 after SOI } - end; - - - - -{GLOBAL} -procedure jinit_marker_writer (cinfo : j_compress_ptr); - -implementation - -{ Basic output routines. - - Note that we do not support suspension while writing a marker. - Therefore, an application using suspension must ensure that there is - enough buffer space for the initial markers (typ. 600-700 bytes) before - calling jpeg_start_compress, and enough space to write the trailing EOI - (a few bytes) before calling jpeg_finish_compress. Multipass compression - modes are not supported at all with suspension, so those two are the only - points where markers will be written. } - - -{LOCAL} -procedure emit_byte (cinfo : j_compress_ptr; val : int); -{ Emit a byte } -var - dest : jpeg_destination_mgr_ptr; -begin - dest := cinfo^.dest; - - dest^.next_output_byte^ := JOCTET(val); - Inc(dest^.next_output_byte); - - Dec(dest^.free_in_buffer); - if (dest^.free_in_buffer = 0) then - begin - if not dest^.empty_output_buffer(cinfo) then - ERREXIT(j_common_ptr(cinfo), JERR_CANT_SUSPEND); - end; -end; - - -{LOCAL} -procedure emit_marker(cinfo : j_compress_ptr; mark : JPEG_MARKER); -{ Emit a marker code } -begin - emit_byte(cinfo, $FF); - emit_byte(cinfo, int(mark)); -end; - - -{LOCAL} -procedure emit_2bytes (cinfo : j_compress_ptr; value : int); -{ Emit a 2-byte integer; these are always MSB first in JPEG files } -begin - emit_byte(cinfo, (value shr 8) and $FF); - emit_byte(cinfo, value and $FF); -end; - - -{ Routines to write specific marker types. } - -{LOCAL} -function emit_dqt (cinfo : j_compress_ptr; index : int) : int; -{ Emit a DQT marker } -{ Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking } -var - qtbl : JQUANT_TBL_PTR; - prec : int; - i : int; -var - qval : uint; -begin - qtbl := cinfo^.quant_tbl_ptrs[index]; - if (qtbl = NIL) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_QUANT_TABLE, index); - - prec := 0; - for i := 0 to Pred(DCTSIZE2) do - begin - if (qtbl^.quantval[i] > 255) then - prec := 1; - end; - - if not qtbl^.sent_table then - begin - emit_marker(cinfo, M_DQT); - - if (prec <> 0) then - emit_2bytes(cinfo, DCTSIZE2*2 + 1 + 2) - else - emit_2bytes(cinfo, DCTSIZE2 + 1 + 2); - - emit_byte(cinfo, index + (prec shl 4)); - - for i := 0 to Pred(DCTSIZE2) do - begin - { The table entries must be emitted in zigzag order. } - qval := qtbl^.quantval[jpeg_natural_order[i]]; - if (prec <> 0) then - emit_byte(cinfo, int(qval shr 8)); - emit_byte(cinfo, int(qval and $FF)); - end; - - qtbl^.sent_table := TRUE; - end; - - emit_dqt := prec; -end; - - -{LOCAL} -procedure emit_dht (cinfo : j_compress_ptr; index : int; is_ac : boolean); -{ Emit a DHT marker } -var - htbl : JHUFF_TBL_PTR; - length, i : int; -begin - if (is_ac) then - begin - htbl := cinfo^.ac_huff_tbl_ptrs[index]; - index := index + $10; { output index has AC bit set } - end - else - begin - htbl := cinfo^.dc_huff_tbl_ptrs[index]; - end; - - if (htbl = NIL) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, index); - - if not htbl^.sent_table then - begin - emit_marker(cinfo, M_DHT); - - length := 0; - for i := 1 to 16 do - length := length + htbl^.bits[i]; - - emit_2bytes(cinfo, length + 2 + 1 + 16); - emit_byte(cinfo, index); - - for i := 1 to 16 do - emit_byte(cinfo, htbl^.bits[i]); - - for i := 0 to Pred(length) do - emit_byte(cinfo, htbl^.huffval[i]); - - htbl^.sent_table := TRUE; - end; -end; - - -{LOCAL} -procedure emit_dac (cinfo : j_compress_ptr); -{ Emit a DAC marker } -{ Since the useful info is so small, we want to emit all the tables in } -{ one DAC marker. Therefore this routine does its own scan of the table. } -{$ifdef C_ARITH_CODING_SUPPORTED} -var - dc_in_use : array[0..NUM_ARITH_TBLS] of byte; - ac_in_use : array[0..NUM_ARITH_TBLS] of byte; - length, i : int; - compptr : jpeg_component_info_ptr; -begin - for i := 0 to pred(NUM_ARITH_TBLS) do - begin - dc_in_use[i] := 0; - ac_in_use[i] := 0; - end; - - for i := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[i]; - dc_in_use[compptr^.dc_tbl_no] := 1; - ac_in_use[compptr^.ac_tbl_no] := 1; - end; - - length := 0; - for i := 0 to pred(NUM_ARITH_TBLS) do - Inc(length, dc_in_use[i] + ac_in_use[i]); - - emit_marker(cinfo, M_DAC); - - emit_2bytes(cinfo, length*2 + 2); - - for i := 0 to pred(NUM_ARITH_TBLS) do - begin - if (dc_in_use[i] <> 0) then - begin - emit_byte(cinfo, i); - emit_byte(cinfo, cinfo^.arith_dc_L[i] + (cinfo^.arith_dc_U[i] shl 4)); - end; - if (ac_in_use[i] <> 0) then - begin - emit_byte(cinfo, i + $10); - emit_byte(cinfo, cinfo^.arith_ac_K[i]); - end; - end; -end; -{$else} -begin -end; -{$endif} {C_ARITH_CODING_SUPPORTED} - - -{LOCAL} -procedure emit_dri (cinfo : j_compress_ptr); -{ Emit a DRI marker } -begin - emit_marker(cinfo, M_DRI); - - emit_2bytes(cinfo, 4); { fixed length } - - emit_2bytes(cinfo, int(cinfo^.restart_interval)); -end; - - -{LOCAL} -procedure emit_sof (cinfo : j_compress_ptr; code : JPEG_MARKER); -{ Emit a SOF marker } -var - ci : int; - compptr : jpeg_component_info_ptr; -begin - emit_marker(cinfo, code); - - emit_2bytes(cinfo, 3 * cinfo^.num_components + 2 + 5 + 1); { length } - - { Make sure image isn't bigger than SOF field can handle } - if (long(cinfo^.image_height) > long(65535)) or - (long(cinfo^.image_width) > long(65535)) then - ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG, uInt(65535)); - - emit_byte(cinfo, cinfo^.data_precision); - emit_2bytes(cinfo, int(cinfo^.image_height)); - emit_2bytes(cinfo, int(cinfo^.image_width)); - - emit_byte(cinfo, cinfo^.num_components); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to Pred(cinfo^.num_components) do - begin - emit_byte(cinfo, compptr^.component_id); - emit_byte(cinfo, (compptr^.h_samp_factor shl 4) + compptr^.v_samp_factor); - emit_byte(cinfo, compptr^.quant_tbl_no); - Inc(compptr); - end; -end; - - -{LOCAL} -procedure emit_sos (cinfo : j_compress_ptr); -{ Emit a SOS marker } -var - i, td, ta : int; - compptr : jpeg_component_info_ptr; -begin - emit_marker(cinfo, M_SOS); - - emit_2bytes(cinfo, 2 * cinfo^.comps_in_scan + 2 + 1 + 3); { length } - - emit_byte(cinfo, cinfo^.comps_in_scan); - - for i := 0 to Pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[i]; - emit_byte(cinfo, compptr^.component_id); - td := compptr^.dc_tbl_no; - ta := compptr^.ac_tbl_no; - if (cinfo^.progressive_mode) then - begin - { Progressive mode: only DC or only AC tables are used in one scan; - furthermore, Huffman coding of DC refinement uses no table at all. - We emit 0 for unused field(s); this is recommended by the P&M text - but does not seem to be specified in the standard. } - - if (cinfo^.Ss = 0) then - begin - ta := 0; { DC scan } - if (cinfo^.Ah <> 0) and not cinfo^.arith_code then - td := 0; { no DC table either } - end - else - begin - td := 0; { AC scan } - end; - end; - emit_byte(cinfo, (td shl 4) + ta); - end; - - emit_byte(cinfo, cinfo^.Ss); - emit_byte(cinfo, cinfo^.Se); - emit_byte(cinfo, (cinfo^.Ah shl 4) + cinfo^.Al); -end; - - -{LOCAL} -procedure emit_jfif_app0 (cinfo : j_compress_ptr); -{ Emit a JFIF-compliant APP0 marker } -{ - Length of APP0 block (2 bytes) - Block ID (4 bytes - ASCII "JFIF") - Zero byte (1 byte to terminate the ID string) - Version Major, Minor (2 bytes - major first) - Units (1 byte - $00 = none, $01 = inch, $02 = cm) - Xdpu (2 bytes - dots per unit horizontal) - Ydpu (2 bytes - dots per unit vertical) - Thumbnail X size (1 byte) - Thumbnail Y size (1 byte) -} -begin - emit_marker(cinfo, M_APP0); - - emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); { length } - - emit_byte(cinfo, $4A); { Identifier: ASCII "JFIF" } - emit_byte(cinfo, $46); - emit_byte(cinfo, $49); - emit_byte(cinfo, $46); - emit_byte(cinfo, 0); - emit_byte(cinfo, cinfo^.JFIF_major_version); { Version fields } - emit_byte(cinfo, cinfo^.JFIF_minor_version); - emit_byte(cinfo, cinfo^.density_unit); { Pixel size information } - emit_2bytes(cinfo, int(cinfo^.X_density)); - emit_2bytes(cinfo, int(cinfo^.Y_density)); - emit_byte(cinfo, 0); { No thumbnail image } - emit_byte(cinfo, 0); -end; - - -{LOCAL} -procedure emit_adobe_app14 (cinfo : j_compress_ptr); -{ Emit an Adobe APP14 marker } -{ - Length of APP14 block (2 bytes) - Block ID (5 bytes - ASCII "Adobe") - Version Number (2 bytes - currently 100) - Flags0 (2 bytes - currently 0) - Flags1 (2 bytes - currently 0) - Color transform (1 byte) - - Although Adobe TN 5116 mentions Version = 101, all the Adobe files - now in circulation seem to use Version = 100, so that's what we write. - - We write the color transform byte as 1 if the JPEG color space is - YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with - whether the encoder performed a transformation, which is pretty useless. -} -begin - emit_marker(cinfo, M_APP14); - - emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); { length } - - emit_byte(cinfo, $41); { Identifier: ASCII "Adobe" } - emit_byte(cinfo, $64); - emit_byte(cinfo, $6F); - emit_byte(cinfo, $62); - emit_byte(cinfo, $65); - emit_2bytes(cinfo, 100); { Version } - emit_2bytes(cinfo, 0); { Flags0 } - emit_2bytes(cinfo, 0); { Flags1 } - case (cinfo^.jpeg_color_space) of - JCS_YCbCr: - emit_byte(cinfo, 1); { Color transform = 1 } - JCS_YCCK: - emit_byte(cinfo, 2); { Color transform = 2 } - else - emit_byte(cinfo, 0); { Color transform = 0 } - end; -end; - - -{ These routines allow writing an arbitrary marker with parameters. - The only intended use is to emit COM or APPn markers after calling - write_file_header and before calling write_frame_header. - Other uses are not guaranteed to produce desirable results. - Counting the parameter bytes properly is the caller's responsibility. } - -{METHODDEF} -procedure write_marker_header (cinfo : j_compress_ptr; - marker : int; - datalen : uint); -{ Emit an arbitrary marker header } -begin - if (datalen > uint(65533)) then { safety check } - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - - emit_marker(cinfo, JPEG_MARKER(marker)); - - emit_2bytes(cinfo, int(datalen + 2)); { total length } -end; - -{METHODDEF} -procedure write_marker_byte (cinfo : j_compress_ptr; val : int); -{ Emit one byte of marker parameters following write_marker_header } -begin - emit_byte(cinfo, val); -end; - -{ Write datastream header. - This consists of an SOI and optional APPn markers. - We recommend use of the JFIF marker, but not the Adobe marker, - when using YCbCr or grayscale data. The JFIF marker should NOT - be used for any other JPEG colorspace. The Adobe marker is helpful - to distinguish RGB, CMYK, and YCCK colorspaces. - Note that an application can write additional header markers after - jpeg_start_compress returns. } - - -{METHODDEF} -procedure write_file_header (cinfo : j_compress_ptr); -var - marker : my_marker_ptr; -begin - marker := my_marker_ptr(cinfo^.marker); - - emit_marker(cinfo, M_SOI); { first the SOI } - - { SOI is defined to reset restart interval to 0 } - marker^.last_restart_interval := 0; - - if (cinfo^.write_JFIF_header) then { next an optional JFIF APP0 } - emit_jfif_app0(cinfo); - if (cinfo^.write_Adobe_marker) then { next an optional Adobe APP14 } - emit_adobe_app14(cinfo); -end; - - -{ Write frame header. - This consists of DQT and SOFn markers. - Note that we do not emit the SOF until we have emitted the DQT(s). - This avoids compatibility problems with incorrect implementations that - try to error-check the quant table numbers as soon as they see the SOF. } - - -{METHODDEF} -procedure write_frame_header (cinfo : j_compress_ptr); -var - ci, prec : int; - is_baseline : boolean; - compptr : jpeg_component_info_ptr; -begin - { Emit DQT for each quantization table. - Note that emit_dqt() suppresses any duplicate tables. } - - prec := 0; - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to Pred(cinfo^.num_components) do - begin - prec := prec + emit_dqt(cinfo, compptr^.quant_tbl_no); - Inc(compptr); - end; - { now prec is nonzero iff there are any 16-bit quant tables. } - - { Check for a non-baseline specification. - Note we assume that Huffman table numbers won't be changed later. } - - if (cinfo^.arith_code) or (cinfo^.progressive_mode) - or (cinfo^.data_precision <> 8) then - begin - is_baseline := FALSE; - end - else - begin - is_baseline := TRUE; - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to Pred(cinfo^.num_components) do - begin - if (compptr^.dc_tbl_no > 1) or (compptr^.ac_tbl_no > 1) then - is_baseline := FALSE; - Inc(compptr); - end; - if (prec <> 0) and (is_baseline) then - begin - is_baseline := FALSE; - { If it's baseline except for quantizer size, warn the user } - {$IFDEF DEBUG} - TRACEMS(j_common_ptr(cinfo), 0, JTRC_16BIT_TABLES); - {$ENDIF} - end; - end; - - { Emit the proper SOF marker } - if (cinfo^.arith_code) then - begin - emit_sof(cinfo, M_SOF9); { SOF code for arithmetic coding } - end - else - begin - if (cinfo^.progressive_mode) then - emit_sof(cinfo, M_SOF2) { SOF code for progressive Huffman } - else if (is_baseline) then - emit_sof(cinfo, M_SOF0) { SOF code for baseline implementation } - else - emit_sof(cinfo, M_SOF1); { SOF code for non-baseline Huffman file } - end; -end; - - -{ Write scan header. - This consists of DHT or DAC markers, optional DRI, and SOS. - Compressed data will be written following the SOS. } - -{METHODDEF} -procedure write_scan_header (cinfo : j_compress_ptr); -var - marker : my_marker_ptr; - i : int; - compptr : jpeg_component_info_ptr; -begin - marker := my_marker_ptr(cinfo^.marker); - if (cinfo^.arith_code) then - begin - { Emit arith conditioning info. We may have some duplication - if the file has multiple scans, but it's so small it's hardly - worth worrying about. } - emit_dac(cinfo); - end - else - begin - { Emit Huffman tables. - Note that emit_dht() suppresses any duplicate tables. } - for i := 0 to Pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[i]; - if (cinfo^.progressive_mode) then - begin - { Progressive mode: only DC or only AC tables are used in one scan } - if (cinfo^.Ss = 0) then - begin - if (cinfo^.Ah = 0) then { DC needs no table for refinement scan } - emit_dht(cinfo, compptr^.dc_tbl_no, FALSE); - end - else - begin - emit_dht(cinfo, compptr^.ac_tbl_no, TRUE); - end; - end - else - begin - { Sequential mode: need both DC and AC tables } - emit_dht(cinfo, compptr^.dc_tbl_no, FALSE); - emit_dht(cinfo, compptr^.ac_tbl_no, TRUE); - end; - end; - end; - - { Emit DRI if required --- note that DRI value could change for each scan. - We avoid wasting space with unnecessary DRIs, however. } - - if (cinfo^.restart_interval <> marker^.last_restart_interval) then - begin - emit_dri(cinfo); - marker^.last_restart_interval := cinfo^.restart_interval; - end; - - emit_sos(cinfo); -end; - - - -{ Write datastream trailer. } - - -{METHODDEF} -procedure write_file_trailer (cinfo : j_compress_ptr); -begin - emit_marker(cinfo, M_EOI); -end; - - -{ Write an abbreviated table-specification datastream. - This consists of SOI, DQT and DHT tables, and EOI. - Any table that is defined and not marked sent_table = TRUE will be - emitted. Note that all tables will be marked sent_table = TRUE at exit. } - - -{METHODDEF} -procedure write_tables_only (cinfo : j_compress_ptr); -var - i : int; -begin - emit_marker(cinfo, M_SOI); - - for i := 0 to Pred(NUM_QUANT_TBLS) do - begin - if (cinfo^.quant_tbl_ptrs[i] <> NIL) then - emit_dqt(cinfo, i); { dummy := ... } - end; - - if (not cinfo^.arith_code) then - begin - for i := 0 to Pred(NUM_HUFF_TBLS) do - begin - if (cinfo^.dc_huff_tbl_ptrs[i] <> NIL) then - emit_dht(cinfo, i, FALSE); - if (cinfo^.ac_huff_tbl_ptrs[i] <> NIL) then - emit_dht(cinfo, i, TRUE); - end; - end; - - emit_marker(cinfo, M_EOI); -end; - - -{ Initialize the marker writer module. } - -{GLOBAL} -procedure jinit_marker_writer (cinfo : j_compress_ptr); -var - marker : my_marker_ptr; -begin - { Create the subobject } - marker := my_marker_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_marker_writer)) ); - cinfo^.marker := jpeg_marker_writer_ptr(marker); - { Initialize method pointers } - marker^.pub.write_file_header := write_file_header; - marker^.pub.write_frame_header := write_frame_header; - marker^.pub.write_scan_header := write_scan_header; - marker^.pub.write_file_trailer := write_file_trailer; - marker^.pub.write_tables_only := write_tables_only; - marker^.pub.write_marker_header := write_marker_header; - marker^.pub.write_marker_byte := write_marker_byte; - { Initialize private state } - marker^.last_restart_interval := 0; -end; - - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcmaster.pas b/3rd/Imaging/Source/JpegLib/imjcmaster.pas deleted file mode 100644 index 90faeb5f8..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcmaster.pas +++ /dev/null @@ -1,701 +0,0 @@ -unit imjcmaster; - -{ This file contains master control logic for the JPEG compressor. - These routines are concerned with parameter validation, initial setup, - and inter-pass control (determining the number of passes and the work - to be done in each pass). } - -{ Original: jcmaster.c ; Copyright (C) 1991-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjutils, - imjpeglib; - -{ Initialize master compression control. } - -{GLOBAL} -procedure jinit_c_master_control (cinfo : j_compress_ptr; - transcode_only : boolean); - -implementation - -{ Private state } - -type - c_pass_type = ( - main_pass, { input data, also do first output step } - huff_opt_pass, { Huffman code optimization pass } - output_pass { data output pass } - ); - -type - my_master_ptr = ^my_comp_master; - my_comp_master = record - pub : jpeg_comp_master; { public fields } - - pass_type : c_pass_type; { the type of the current pass } - - pass_number : int; { # of passes completed } - total_passes : int; { total # of passes needed } - - scan_number : int; { current index in scan_info[] } - end; - - -{ Support routines that do various essential calculations. } - -{LOCAL} -procedure initial_setup (cinfo : j_compress_ptr); -{ Do computations that are needed before master selection phase } -var - ci : int; - compptr : jpeg_component_info_ptr; - samplesperrow : long; - jd_samplesperrow : JDIMENSION; -begin - - { Sanity check on image dimensions } - if (cinfo^.image_height <= 0) or (cinfo^.image_width <= 0) or - (cinfo^.num_components <= 0) or (cinfo^.input_components <= 0) then - ERREXIT(j_common_ptr(cinfo), JERR_EMPTY_IMAGE); - - { Make sure image isn't bigger than I can handle } - if ( long(cinfo^.image_height) > long(JPEG_MAX_DIMENSION)) or - ( long(cinfo^.image_width) > long(JPEG_MAX_DIMENSION)) then - ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG, - uInt(JPEG_MAX_DIMENSION)); - - { Width of an input scanline must be representable as JDIMENSION. } - samplesperrow := long (cinfo^.image_width) * long (cinfo^.input_components); - jd_samplesperrow := JDIMENSION (samplesperrow); - if ( long(jd_samplesperrow) <> samplesperrow) then - ERREXIT(j_common_ptr(cinfo), JERR_WIDTH_OVERFLOW); - - { For now, precision must match compiled-in value... } - if (cinfo^.data_precision <> BITS_IN_JSAMPLE) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PRECISION, cinfo^.data_precision); - - { Check that number of components won't exceed internal array sizes } - if (cinfo^.num_components > MAX_COMPONENTS) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components, - MAX_COMPONENTS); - - { Compute maximum sampling factors; check factor validity } - cinfo^.max_h_samp_factor := 1; - cinfo^.max_v_samp_factor := 1; - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - if (compptr^.h_samp_factor<=0) or (compptr^.h_samp_factor>MAX_SAMP_FACTOR) - or (compptr^.v_samp_factor<=0) or (compptr^.v_samp_factor>MAX_SAMP_FACTOR) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_SAMPLING); - { MAX } - if cinfo^.max_h_samp_factor > compptr^.h_samp_factor then - cinfo^.max_h_samp_factor := cinfo^.max_h_samp_factor - else - cinfo^.max_h_samp_factor := compptr^.h_samp_factor; - { MAX } - if cinfo^.max_v_samp_factor > compptr^.v_samp_factor then - cinfo^.max_v_samp_factor := cinfo^.max_v_samp_factor - else - cinfo^.max_v_samp_factor := compptr^.v_samp_factor; - Inc(compptr); - end; - - { Compute dimensions of components } - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Fill in the correct component_index value; don't rely on application } - compptr^.component_index := ci; - { For compression, we never do DCT scaling. } - compptr^.DCT_scaled_size := DCTSIZE; - { Size in DCT blocks } - compptr^.width_in_blocks := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_width) * long (compptr^.h_samp_factor), - long (cinfo^.max_h_samp_factor * DCTSIZE)) ); - compptr^.height_in_blocks := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height) * long (compptr^.v_samp_factor), - long (cinfo^.max_v_samp_factor * DCTSIZE)) ); - { Size in samples } - compptr^.downsampled_width := JDIMENSION ( - jdiv_round_up(long(cinfo^.image_width) * long(compptr^.h_samp_factor), - long(cinfo^.max_h_samp_factor)) ); - compptr^.downsampled_height := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor), - long (cinfo^.max_v_samp_factor)) ); - { Mark component needed (this flag isn't actually used for compression) } - compptr^.component_needed := TRUE; - Inc(compptr); - end; - - { Compute number of fully interleaved MCU rows (number of times that - main controller will call coefficient controller). } - - cinfo^.total_iMCU_rows := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height), - long (cinfo^.max_v_samp_factor*DCTSIZE)) ); -end; - - -{$ifdef C_MULTISCAN_FILES_SUPPORTED} - -{LOCAL} -procedure validate_script (cinfo : j_compress_ptr); -{ Verify that the scan script in cinfo^.scan_info[] is valid; also - determine whether it uses progressive JPEG, and set cinfo^.progressive_mode. } -type - IntRow = array[0..DCTSIZE2-1] of int; - introw_ptr = ^IntRow; -var - {const}scanptr : jpeg_scan_info_ptr; - scanno, ncomps, ci, coefi, thisi : int; - Ss, Se, Ah, Al : int; - component_sent : array[0..MAX_COMPONENTS-1] of boolean; -{$ifdef C_PROGRESSIVE_SUPPORTED} - last_bitpos_int_ptr : int_ptr; - last_bitpos_ptr : introw_ptr; - last_bitpos : array[0..MAX_COMPONENTS-1] of IntRow; - { -1 until that coefficient has been seen; then last Al for it } - { The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that - seems wrong: the upper bound ought to depend on data precision. - Perhaps they really meant 0..N+1 for N-bit precision. - Here we allow 0..10 for 8-bit data; Al larger than 10 results in - out-of-range reconstructed DC values during the first DC scan, - which might cause problems for some decoders. } -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - MAX_AH_AL = 10; -{$else} -const - MAX_AH_AL = 13; -{$endif} -{$endif} -begin - - if (cinfo^.num_scans <= 0) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, 0); - - { For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1; - for progressive JPEG, no scan can have this. } - - scanptr := cinfo^.scan_info; - if (scanptr^.Ss <> 0) or (scanptr^.Se <> DCTSIZE2-1) then - begin -{$ifdef C_PROGRESSIVE_SUPPORTED} - cinfo^.progressive_mode := TRUE; - last_bitpos_int_ptr := @(last_bitpos[0][0]); - for ci := 0 to pred(cinfo^.num_components) do - for coefi := 0 to pred(DCTSIZE2) do - begin - last_bitpos_int_ptr^ := -1; - Inc(last_bitpos_int_ptr); - end; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - begin - cinfo^.progressive_mode := FALSE; - for ci := 0 to pred(cinfo^.num_components) do - component_sent[ci] := FALSE; - end; - - for scanno := 1 to cinfo^.num_scans do - begin - { Validate component indexes } - ncomps := scanptr^.comps_in_scan; - if (ncomps <= 0) or (ncomps > MAX_COMPS_IN_SCAN) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN); - for ci := 0 to pred(ncomps) do - begin - thisi := scanptr^.component_index[ci]; - if (thisi < 0) or (thisi >= cinfo^.num_components) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno); - { Components must appear in SOF order within each scan } - if (ci > 0) and (thisi <= scanptr^.component_index[ci-1]) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno); - end; - { Validate progression parameters } - Ss := scanptr^.Ss; - Se := scanptr^.Se; - Ah := scanptr^.Ah; - Al := scanptr^.Al; - if (cinfo^.progressive_mode) then - begin -{$ifdef C_PROGRESSIVE_SUPPORTED} - if (Ss < 0) or (Ss >= DCTSIZE2) or (Se < Ss) or (Se >= DCTSIZE2) or - (Ah < 0) or (Ah > MAX_AH_AL) or (Al < 0) or (Al > MAX_AH_AL) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - - if (Ss < 0) or (Ss >= DCTSIZE2) or (Se < Ss) or (Se >= DCTSIZE2) - or (Ah < 0) or (Ah > MAX_AH_AL) or (Al < 0) or (Al > MAX_AH_AL) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - if (Ss = 0) then - begin - if (Se <> 0) then { DC and AC together not OK } - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - end - else - begin - if (ncomps <> 1) then { AC scans must be for only one component } - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - end; - for ci := 0 to pred(ncomps) do - begin - last_bitpos_ptr := @( last_bitpos[scanptr^.component_index[ci]]); - if (Ss <> 0) and (last_bitpos_ptr^[0] < 0) then { AC without prior DC scan } - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - for coefi := Ss to Se do - begin - if (last_bitpos_ptr^[coefi] < 0) then - begin - { first scan of this coefficient } - if (Ah <> 0) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - end - else - begin - { not first scan } - if (Ah <> last_bitpos_ptr^[coefi]) or (Al <> Ah-1) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - end; - last_bitpos_ptr^[coefi] := Al; - end; - end; -{$endif} - end - else - begin - { For sequential JPEG, all progression parameters must be these: } - if (Ss <> 0) or (Se <> DCTSIZE2-1) or (Ah <> 0) or (Al <> 0) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PROG_SCRIPT, scanno); - { Make sure components are not sent twice } - for ci := 0 to pred(ncomps) do - begin - thisi := scanptr^.component_index[ci]; - if (component_sent[thisi]) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_SCAN_SCRIPT, scanno); - component_sent[thisi] := TRUE; - end; - end; - Inc(scanptr); - end; - - { Now verify that everything got sent. } - if (cinfo^.progressive_mode) then - begin -{$ifdef C_PROGRESSIVE_SUPPORTED} - { For progressive mode, we only check that at least some DC data - got sent for each component; the spec does not require that all bits - of all coefficients be transmitted. Would it be wiser to enforce - transmission of all coefficient bits?? } - - for ci := 0 to pred(cinfo^.num_components) do - begin - if (last_bitpos[ci][0] < 0) then - ERREXIT(j_common_ptr(cinfo), JERR_MISSING_DATA); - end; -{$endif} - end - else - begin - for ci := 0 to pred(cinfo^.num_components) do - begin - if (not component_sent[ci]) then - ERREXIT(j_common_ptr(cinfo), JERR_MISSING_DATA); - end; - end; -end; - -{$endif} { C_MULTISCAN_FILES_SUPPORTED } - - -{LOCAL} -procedure select_scan_parameters (cinfo : j_compress_ptr); -{ Set up the scan parameters for the current scan } -var - master : my_master_ptr; - {const} scanptr : jpeg_scan_info_ptr; - ci : int; -var - comp_infos : jpeg_component_info_list_ptr; -begin -{$ifdef C_MULTISCAN_FILES_SUPPORTED} - if (cinfo^.scan_info <> NIL) then - begin - { Prepare for current scan --- the script is already validated } - master := my_master_ptr (cinfo^.master); - scanptr := cinfo^.scan_info; - Inc(scanptr, master^.scan_number); - - cinfo^.comps_in_scan := scanptr^.comps_in_scan; - comp_infos := cinfo^.comp_info; - for ci := 0 to pred(scanptr^.comps_in_scan) do - begin - cinfo^.cur_comp_info[ci] := - @(comp_infos^[scanptr^.component_index[ci]]); - end; - cinfo^.Ss := scanptr^.Ss; - cinfo^.Se := scanptr^.Se; - cinfo^.Ah := scanptr^.Ah; - cinfo^.Al := scanptr^.Al; - end - else -{$endif} - begin - { Prepare for single sequential-JPEG scan containing all components } - if (cinfo^.num_components > MAX_COMPS_IN_SCAN) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components, - MAX_COMPS_IN_SCAN); - cinfo^.comps_in_scan := cinfo^.num_components; - comp_infos := cinfo^.comp_info; - for ci := 0 to pred(cinfo^.num_components) do - begin - cinfo^.cur_comp_info[ci] := @(comp_infos^[ci]); - end; - cinfo^.Ss := 0; - cinfo^.Se := DCTSIZE2-1; - cinfo^.Ah := 0; - cinfo^.Al := 0; - end; -end; - - -{LOCAL} -procedure per_scan_setup (cinfo : j_compress_ptr); -{ Do computations that are needed before processing a JPEG scan } -{ cinfo^.comps_in_scan and cinfo^.cur_comp_info[] are already set } -var - ci, mcublks, tmp : int; - compptr : jpeg_component_info_ptr; - nominal : long; -begin - if (cinfo^.comps_in_scan = 1) then - begin - - { Noninterleaved (single-component) scan } - compptr := cinfo^.cur_comp_info[0]; - - { Overall image size in MCUs } - cinfo^.MCUs_per_row := compptr^.width_in_blocks; - cinfo^.MCU_rows_in_scan := compptr^.height_in_blocks; - - { For noninterleaved scan, always one block per MCU } - compptr^.MCU_width := 1; - compptr^.MCU_height := 1; - compptr^.MCU_blocks := 1; - compptr^.MCU_sample_width := DCTSIZE; - compptr^.last_col_width := 1; - { For noninterleaved scans, it is convenient to define last_row_height - as the number of block rows present in the last iMCU row. } - - tmp := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor; - if (tmp = 0) then - tmp := compptr^.v_samp_factor; - compptr^.last_row_height := tmp; - - { Prepare array describing MCU composition } - cinfo^.blocks_in_MCU := 1; - cinfo^.MCU_membership[0] := 0; - - end - else - begin - - { Interleaved (multi-component) scan } - if (cinfo^.comps_in_scan <= 0) or - (cinfo^.comps_in_scan > MAX_COMPS_IN_SCAN) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, - cinfo^.comps_in_scan, MAX_COMPS_IN_SCAN); - - { Overall image size in MCUs } - cinfo^.MCUs_per_row := JDIMENSION ( - jdiv_round_up( long (cinfo^.image_width), - long (cinfo^.max_h_samp_factor*DCTSIZE)) ); - cinfo^.MCU_rows_in_scan := JDIMENSION ( - jdiv_round_up( long (cinfo^.image_height), - long (cinfo^.max_v_samp_factor*DCTSIZE)) ); - - cinfo^.blocks_in_MCU := 0; - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - { Sampling factors give # of blocks of component in each MCU } - compptr^.MCU_width := compptr^.h_samp_factor; - compptr^.MCU_height := compptr^.v_samp_factor; - compptr^.MCU_blocks := compptr^.MCU_width * compptr^.MCU_height; - compptr^.MCU_sample_width := compptr^.MCU_width * DCTSIZE; - { Figure number of non-dummy blocks in last MCU column & row } - tmp := int (compptr^.width_in_blocks) mod compptr^.MCU_width; - if (tmp = 0) then - tmp := compptr^.MCU_width; - compptr^.last_col_width := tmp; - tmp := int (compptr^.height_in_blocks) mod compptr^.MCU_height; - if (tmp = 0) then - tmp := compptr^.MCU_height; - compptr^.last_row_height := tmp; - { Prepare array describing MCU composition } - mcublks := compptr^.MCU_blocks; - if (cinfo^.blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_MCU_SIZE); - while (mcublks > 0) do - begin - Dec(mcublks); - cinfo^.MCU_membership[cinfo^.blocks_in_MCU] := ci; - Inc(cinfo^.blocks_in_MCU); - end; - end; - - end; - - { Convert restart specified in rows to actual MCU count. } - { Note that count must fit in 16 bits, so we provide limiting. } - if (cinfo^.restart_in_rows > 0) then - begin - nominal := long(cinfo^.restart_in_rows) * long(cinfo^.MCUs_per_row); - if nominal < long(65535) then - cinfo^.restart_interval := uInt (nominal) - else - cinfo^.restart_interval := long(65535); - end; -end; - - -{ Per-pass setup. - This is called at the beginning of each pass. We determine which modules - will be active during this pass and give them appropriate start_pass calls. - We also set is_last_pass to indicate whether any more passes will be - required. } - -{METHODDEF} -procedure prepare_for_pass (cinfo : j_compress_ptr); -var - master : my_master_ptr; -var - fallthrough : boolean; -begin - master := my_master_ptr (cinfo^.master); - fallthrough := true; - - case (master^.pass_type) of - main_pass: - begin - { Initial pass: will collect input data, and do either Huffman - optimization or data output for the first scan. } - select_scan_parameters(cinfo); - per_scan_setup(cinfo); - if (not cinfo^.raw_data_in) then - begin - cinfo^.cconvert^.start_pass (cinfo); - cinfo^.downsample^.start_pass (cinfo); - cinfo^.prep^.start_pass (cinfo, JBUF_PASS_THRU); - end; - cinfo^.fdct^.start_pass (cinfo); - cinfo^.entropy^.start_pass (cinfo, cinfo^.optimize_coding); - if master^.total_passes > 1 then - cinfo^.coef^.start_pass (cinfo, JBUF_SAVE_AND_PASS) - else - cinfo^.coef^.start_pass (cinfo, JBUF_PASS_THRU); - cinfo^.main^.start_pass (cinfo, JBUF_PASS_THRU); - if (cinfo^.optimize_coding) then - begin - { No immediate data output; postpone writing frame/scan headers } - master^.pub.call_pass_startup := FALSE; - end - else - begin - { Will write frame/scan headers at first jpeg_write_scanlines call } - master^.pub.call_pass_startup := TRUE; - end; - end; -{$ifdef ENTROPY_OPT_SUPPORTED} - huff_opt_pass, - output_pass: - begin - if (master^.pass_type = huff_opt_pass) then - begin - { Do Huffman optimization for a scan after the first one. } - select_scan_parameters(cinfo); - per_scan_setup(cinfo); - if (cinfo^.Ss <> 0) or (cinfo^.Ah = 0) or (cinfo^.arith_code) then - begin - cinfo^.entropy^.start_pass (cinfo, TRUE); - cinfo^.coef^.start_pass (cinfo, JBUF_CRANK_DEST); - master^.pub.call_pass_startup := FALSE; - fallthrough := false; - end; - { Special case: Huffman DC refinement scans need no Huffman table - and therefore we can skip the optimization pass for them. } - if fallthrough then - begin - master^.pass_type := output_pass; - Inc(master^.pass_number); - {FALLTHROUGH} - end; - end; -{$else} - output_pass: - begin -{$endif} - if fallthrough then - begin - { Do a data-output pass. } - { We need not repeat per-scan setup if prior optimization pass did it. } - if (not cinfo^.optimize_coding) then - begin - select_scan_parameters(cinfo); - per_scan_setup(cinfo); - end; - cinfo^.entropy^.start_pass (cinfo, FALSE); - cinfo^.coef^.start_pass (cinfo, JBUF_CRANK_DEST); - { We emit frame/scan headers now } - if (master^.scan_number = 0) then - cinfo^.marker^.write_frame_header (cinfo); - cinfo^.marker^.write_scan_header (cinfo); - master^.pub.call_pass_startup := FALSE; - end; - end; - else - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); - end; - - master^.pub.is_last_pass := (master^.pass_number = master^.total_passes-1); - - { Set up progress monitor's pass info if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.completed_passes := master^.pass_number; - cinfo^.progress^.total_passes := master^.total_passes; - end; -end; - - -{ Special start-of-pass hook. - This is called by jpeg_write_scanlines if call_pass_startup is TRUE. - In single-pass processing, we need this hook because we don't want to - write frame/scan headers during jpeg_start_compress; we want to let the - application write COM markers etc. between jpeg_start_compress and the - jpeg_write_scanlines loop. - In multi-pass processing, this routine is not used. } - -{METHODDEF} -procedure pass_startup (cinfo : j_compress_ptr); -begin - cinfo^.master^.call_pass_startup := FALSE; { reset flag so call only once } - - cinfo^.marker^.write_frame_header (cinfo); - cinfo^.marker^.write_scan_header (cinfo); -end; - - -{ Finish up at end of pass. } - -{METHODDEF} -procedure finish_pass_master (cinfo : j_compress_ptr); -var - master : my_master_ptr; -begin - master := my_master_ptr (cinfo^.master); - - { The entropy coder always needs an end-of-pass call, - either to analyze statistics or to flush its output buffer. } - cinfo^.entropy^.finish_pass (cinfo); - - { Update state for next pass } - case (master^.pass_type) of - main_pass: - begin - { next pass is either output of scan 0 (after optimization) - or output of scan 1 (if no optimization). } - - master^.pass_type := output_pass; - if (not cinfo^.optimize_coding) then - Inc(master^.scan_number); - end; - huff_opt_pass: - { next pass is always output of current scan } - master^.pass_type := output_pass; - output_pass: - begin - { next pass is either optimization or output of next scan } - if (cinfo^.optimize_coding) then - master^.pass_type := huff_opt_pass; - Inc(master^.scan_number); - end; - end; - - Inc(master^.pass_number); -end; - - -{ Initialize master compression control. } - -{GLOBAL} -procedure jinit_c_master_control (cinfo : j_compress_ptr; - transcode_only : boolean); -var - master : my_master_ptr; -begin - master := my_master_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_comp_master)) ); - cinfo^.master := jpeg_comp_master_ptr(master); - master^.pub.prepare_for_pass := prepare_for_pass; - master^.pub.pass_startup := pass_startup; - master^.pub.finish_pass := finish_pass_master; - master^.pub.is_last_pass := FALSE; - - { Validate parameters, determine derived values } - initial_setup(cinfo); - - if (cinfo^.scan_info <> NIL) then - begin -{$ifdef C_MULTISCAN_FILES_SUPPORTED} - validate_script(cinfo); -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - begin - cinfo^.progressive_mode := FALSE; - cinfo^.num_scans := 1; - end; - - if (cinfo^.progressive_mode) then { TEMPORARY HACK ??? } - cinfo^.optimize_coding := TRUE; { assume default tables no good for progressive mode } - - { Initialize my private state } - if (transcode_only) then - begin - { no main pass in transcoding } - if (cinfo^.optimize_coding) then - master^.pass_type := huff_opt_pass - else - master^.pass_type := output_pass; - end - else - begin - { for normal compression, first pass is always this type: } - master^.pass_type := main_pass; - end; - master^.scan_number := 0; - master^.pass_number := 0; - if (cinfo^.optimize_coding) then - master^.total_passes := cinfo^.num_scans * 2 - else - master^.total_passes := cinfo^.num_scans; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcomapi.pas b/3rd/Imaging/Source/JpegLib/imjcomapi.pas deleted file mode 100644 index c58a7ae8f..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcomapi.pas +++ /dev/null @@ -1,130 +0,0 @@ -unit imjcomapi; - -{ This file contains application interface routines that are used for both - compression and decompression. } - -{ Original: jcomapi.c; Copyright (C) 1994-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib; - -{ Abort processing of a JPEG compression or decompression operation, - but don't destroy the object itself. } - -{GLOBAL} -procedure jpeg_abort (cinfo : j_common_ptr); - - -{ Destruction of a JPEG object. } - -{GLOBAL} -procedure jpeg_destroy (cinfo : j_common_ptr); - -{GLOBAL} -function jpeg_alloc_quant_table (cinfo : j_common_ptr) : JQUANT_TBL_PTR; - -{GLOBAL} -function jpeg_alloc_huff_table (cinfo : j_common_ptr) : JHUFF_TBL_PTR; - -implementation - -{ Abort processing of a JPEG compression or decompression operation, - but don't destroy the object itself. - - For this, we merely clean up all the nonpermanent memory pools. - Note that temp files (virtual arrays) are not allowed to belong to - the permanent pool, so we will be able to close all temp files here. - Closing a data source or destination, if necessary, is the application's - responsibility. } - - -{GLOBAL} -procedure jpeg_abort (cinfo : j_common_ptr); -var - pool : int; -begin - { Do nothing if called on a not-initialized or destroyed JPEG object. } - if (cinfo^.mem = NIL) then - exit; - - { Releasing pools in reverse order might help avoid fragmentation - with some (brain-damaged) malloc libraries. } - - for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT+1 do - begin - cinfo^.mem^.free_pool (cinfo, pool); - end; - - { Reset overall state for possible reuse of object } - if (cinfo^.is_decompressor) then - begin - cinfo^.global_state := DSTATE_START; - { Try to keep application from accessing now-deleted marker list. - A bit kludgy to do it here, but this is the most central place. } - j_decompress_ptr(cinfo)^.marker_list := NIL; - end - else - begin - cinfo^.global_state := CSTATE_START; - end; -end; - - -{ Destruction of a JPEG object. - - Everything gets deallocated except the master jpeg_compress_struct itself - and the error manager struct. Both of these are supplied by the application - and must be freed, if necessary, by the application. (Often they are on - the stack and so don't need to be freed anyway.) - Closing a data source or destination, if necessary, is the application's - responsibility. } - - -{GLOBAL} -procedure jpeg_destroy (cinfo : j_common_ptr); -begin - { We need only tell the memory manager to release everything. } - { NB: mem pointer is NIL if memory mgr failed to initialize. } - if (cinfo^.mem <> NIL) then - cinfo^.mem^.self_destruct (cinfo); - cinfo^.mem := NIL; { be safe if jpeg_destroy is called twice } - cinfo^.global_state := 0; { mark it destroyed } -end; - - -{ Convenience routines for allocating quantization and Huffman tables. - (Would jutils.c be a more reasonable place to put these?) } - - -{GLOBAL} -function jpeg_alloc_quant_table (cinfo : j_common_ptr) : JQUANT_TBL_PTR; -var - tbl : JQUANT_TBL_PTR; -begin - tbl := JQUANT_TBL_PTR( - cinfo^.mem^.alloc_small (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)) - ); - tbl^.sent_table := FALSE; { make sure this is false in any new table } - jpeg_alloc_quant_table := tbl; -end; - - -{GLOBAL} -function jpeg_alloc_huff_table (cinfo : j_common_ptr) : JHUFF_TBL_PTR; -var - tbl : JHUFF_TBL_PTR; -begin - tbl := JHUFF_TBL_PTR( - cinfo^.mem^.alloc_small (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)) - ); - tbl^.sent_table := FALSE; { make sure this is false in any new table } - jpeg_alloc_huff_table := tbl; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjconfig.inc b/3rd/Imaging/Source/JpegLib/imjconfig.inc deleted file mode 100644 index bf5a0cf4f..000000000 --- a/3rd/Imaging/Source/JpegLib/imjconfig.inc +++ /dev/null @@ -1,126 +0,0 @@ -{ ----------------------- JPEG_INTERNAL_OPTIONS ---------------------- } - - -{ These defines indicate whether to include various optional functions. - Undefining some of these symbols will produce a smaller but less capable - library. Note that you can leave certain source files out of the - compilation/linking process if you've #undef'd the corresponding symbols. - (You may HAVE to do that if your compiler doesn't like null source files.)} - - -{ Arithmetic coding is unsupported for legal reasons. Complaints to IBM. } - -{ Capability options common to encoder and decoder: } - -{$define DCT_ISLOW_SUPPORTED} { slow but accurate integer algorithm } -{$define DCT_IFAST_SUPPORTED} { faster, less accurate integer method } -{$define DCT_FLOAT_SUPPORTED} { floating-point: accurate, fast on fast HW } - -{ Encoder capability options: } - -{$undef C_ARITH_CODING_SUPPORTED} { Arithmetic coding back end? } -{$define C_MULTISCAN_FILES_SUPPORTED} { Multiple-scan JPEG files? } -{$define C_PROGRESSIVE_SUPPORTED} { Progressive JPEG? (Requires MULTISCAN)} -{$define ENTROPY_OPT_SUPPORTED} { Optimization of entropy coding parms? } -{ Note: if you selected 12-bit data precision, it is dangerous to turn off - ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit - precision, so jchuff.c normally uses entropy optimization to compute - usable tables for higher precision. If you don't want to do optimization, - you'll have to supply different default Huffman tables. - The exact same statements apply for progressive JPEG: the default tables - don't work for progressive mode. (This may get fixed, however.) } - -{$define INPUT_SMOOTHING_SUPPORTED} { Input image smoothing option? } - -{ Decoder capability options: } - -{$undef D_ARITH_CODING_SUPPORTED} { Arithmetic coding back end? } -{$define D_MULTISCAN_FILES_SUPPORTED} { Multiple-scan JPEG files? } -{$define D_PROGRESSIVE_SUPPORTED} { Progressive JPEG? (Requires MULTISCAN)} -{$define SAVE_MARKERS_SUPPORTED} { jpeg_save_markers() needed? } -{$define BLOCK_SMOOTHING_SUPPORTED} { Block smoothing? (Progressive only) } -{$define IDCT_SCALING_SUPPORTED} { Output rescaling via IDCT? } -{$undef UPSAMPLE_SCALING_SUPPORTED} { Output rescaling at upsample stage? } -{$define UPSAMPLE_MERGING_SUPPORTED} { Fast path for sloppy upsampling? } -{$define QUANT_1PASS_SUPPORTED} { 1-pass color quantization? } -{$define QUANT_2PASS_SUPPORTED} { 2-pass color quantization? } - -{ If you happen not to want the image transform support, disable it here } -{$define TRANSFORMS_SUPPORTED} - -{ more capability options later, no doubt } - -{$ifopt I+} {$define IOcheck} {$endif} - -{ ------------------------------------------------------------------------ } - -{$define USE_FMEM} { Borland has _fmemcpy() and _fmemset() } - -{$define FMEMCOPY} -{$define FMEMZERO} - -{$define DCTSIZE_IS_8} { e.g. unroll the inner loop } -{$define RIGHT_SHIFT_IS_UNSIGNED} -{$undef AVOID_TABLES} -{$undef FAST_DIVIDE} - -{$define BITS_IN_JSAMPLE_IS_8} - -{----------------------------------------------------------------} -{ for test of 12 bit JPEG code only. !! } -{-- $undef BITS_IN_JSAMPLE_IS_8} -{----------------------------------------------------------------} - -//{$define RGB_RED_IS_0} -{ !CHANGE: This must be defined for Delphi/Kylix/FPC } -{$define RGB_RED_IS_2} { RGB byte order } - - -{$define RGB_PIXELSIZE_IS_3} -{$define SLOW_SHIFT_32} -{$undef NO_ZERO_ROW_TEST} - -{$define USE_MSDOS_MEMMGR} { Define this if you use jmemdos.c } -{$define XMS_SUPPORTED} -{$define EMS_SUPPORTED} - -{$undef MEM_STATS} { Write out memory usage } -{$define AM_MEMORY_MANAGER} { we define jvirt_Xarray_control structs } - -{$undef FULL_MAIN_BUFFER_SUPPORTED} - -{$define PROGRESS_REPORT} -{$define TWO_FILE_COMMANDLINE} -{$undef BMP_SUPPORTED} -{$undef PPM_SUPPORTED} -{$undef GIF_SUPPORTED} -{$undef RLE_SUPPORTED} -{$undef TARGA_SUPPORTED} -{$define EXT_SWITCH} - -{$ifndef BITS_IN_JSAMPLE_IS_8} { for 12 bit samples } -{$undef BMP_SUPPORTED} -{$undef RLE_SUPPORTED} -{$undef TARGA_SUPPORTED} -{$endif} - - -{!CHANGE: Allowed only for Delphi} -{$undef BASM16} { for TP7 - use BASM for fast multiply } -{$ifdef Win32} - {$ifndef FPC} - {$define BASM} { jidctint with BASM for Delphi 2/3 } - {$undef RGB_RED_IS_0} { BGR byte order in JQUANT2 } - {$endif} -{$endif} - -{$ifdef FPC} - {$MODE DELPHI} -{$endif} - -{!CHANGE: Added this} -{$define Delphi_Stream} -{$Q-} -{$MINENUMSIZE 4} -{$ALIGN 8} - diff --git a/3rd/Imaging/Source/JpegLib/imjcparam.pas b/3rd/Imaging/Source/JpegLib/imjcparam.pas deleted file mode 100644 index 345fc32ff..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcparam.pas +++ /dev/null @@ -1,701 +0,0 @@ -unit imjcparam; - -{ This file contains optional default-setting code for the JPEG compressor. - Applications do not have to use this file, but those that don't use it - must know a lot more about the innards of the JPEG code. } - -{ Original: jcparam.c ; Copyright (C) 1991-1998, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjcomapi, - imjpeglib; - -{ Quantization table setup routines } - -{GLOBAL} -procedure jpeg_add_quant_table (cinfo : j_compress_ptr; - which_tbl : int; - const basic_table : array of uInt; - scale_factor : int; - force_baseline : boolean); - -{GLOBAL} -procedure jpeg_set_linear_quality (cinfo : j_compress_ptr; - scale_factor : int; - force_baseline : boolean); -{ Set or change the 'quality' (quantization) setting, using default tables - and a straight percentage-scaling quality scale. In most cases it's better - to use jpeg_set_quality (below); this entry point is provided for - applications that insist on a linear percentage scaling. } - -{GLOBAL} -function jpeg_quality_scaling (quality : int) : int; -{ Convert a user-specified quality rating to a percentage scaling factor - for an underlying quantization table, using our recommended scaling curve. - The input 'quality' factor should be 0 (terrible) to 100 (very good). } - -{GLOBAL} -procedure jpeg_set_quality (cinfo : j_compress_ptr; - quality : int; - force_baseline : boolean); -{ Set or change the 'quality' (quantization) setting, using default tables. - This is the standard quality-adjusting entry point for typical user - interfaces; only those who want detailed control over quantization tables - would use the preceding three routines directly. } - -{GLOBAL} -procedure jpeg_set_defaults (cinfo : j_compress_ptr); - -{ Create a recommended progressive-JPEG script. - cinfo^.num_components and cinfo^.jpeg_color_space must be correct. } - -{ Set the JPEG colorspace, and choose colorspace-dependent default values. } - -{GLOBAL} -procedure jpeg_set_colorspace (cinfo : j_compress_ptr; - colorspace : J_COLOR_SPACE); - -{ Select an appropriate JPEG colorspace for in_color_space. } - -{GLOBAL} -procedure jpeg_default_colorspace (cinfo : j_compress_ptr); - -{GLOBAL} -procedure jpeg_simple_progression (cinfo : j_compress_ptr); - - -implementation - -{ Quantization table setup routines } - -{GLOBAL} -procedure jpeg_add_quant_table (cinfo : j_compress_ptr; - which_tbl : int; - const basic_table : array of uInt; - scale_factor : int; - force_baseline : boolean); -{ Define a quantization table equal to the basic_table times - a scale factor (given as a percentage). - If force_baseline is TRUE, the computed quantization table entries - are limited to 1..255 for JPEG baseline compatibility. } -var - qtblptr :^JQUANT_TBL_PTR; - i : int; - temp : long; -begin - { Safety check to ensure start_compress not called yet. } - if (cinfo^.global_state <> CSTATE_START) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - if (which_tbl < 0) or (which_tbl >= NUM_QUANT_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_DQT_INDEX, which_tbl); - - qtblptr := @(cinfo^.quant_tbl_ptrs[which_tbl]); - - if (qtblptr^ = NIL) then - qtblptr^ := jpeg_alloc_quant_table(j_common_ptr(cinfo)); - - for i := 0 to pred(DCTSIZE2) do - begin - temp := (long(basic_table[i]) * scale_factor + long(50)) div long(100); - { limit the values to the valid range } - if (temp <= long(0)) then - temp := long(1); - if (temp > long(32767)) then - temp := long(32767); { max quantizer needed for 12 bits } - if (force_baseline) and (temp > long(255)) then - temp := long(255); { limit to baseline range if requested } - (qtblptr^)^.quantval[i] := UINT16 (temp); - end; - - { Initialize sent_table FALSE so table will be written to JPEG file. } - (qtblptr^)^.sent_table := FALSE; -end; - - -{GLOBAL} -procedure jpeg_set_linear_quality (cinfo : j_compress_ptr; - scale_factor : int; - force_baseline : boolean); -{ Set or change the 'quality' (quantization) setting, using default tables - and a straight percentage-scaling quality scale. In most cases it's better - to use jpeg_set_quality (below); this entry point is provided for - applications that insist on a linear percentage scaling. } - -{ These are the sample quantization tables given in JPEG spec section K.1. - The spec says that the values given produce "good" quality, and - when divided by 2, "very good" quality. } - -const - std_luminance_quant_tbl : array[0..DCTSIZE2-1] of uInt = - (16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99); - -const - std_chrominance_quant_tbl : array[0..DCTSIZE2-1] of uInt = - (17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99); -begin - { Set up two quantization tables using the specified scaling } - jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, - scale_factor, force_baseline); - jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, - scale_factor, force_baseline); -end; - - -{GLOBAL} -function jpeg_quality_scaling (quality : int) : int; -{ Convert a user-specified quality rating to a percentage scaling factor - for an underlying quantization table, using our recommended scaling curve. - The input 'quality' factor should be 0 (terrible) to 100 (very good). } -begin - { Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. } - if (quality <= 0) then - quality := 1; - if (quality > 100) then - quality := 100; - - { The basic table is used as-is (scaling 100) for a quality of 50. - Qualities 50..100 are converted to scaling percentage 200 - 2*Q; - note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table - to make all the table entries 1 (hence, minimum quantization loss). - Qualities 1..50 are converted to scaling percentage 5000/Q. } - if (quality < 50) then - quality := 5000 div quality - else - quality := 200 - quality*2; - - jpeg_quality_scaling := quality; -end; - - -{GLOBAL} -procedure jpeg_set_quality (cinfo : j_compress_ptr; - quality : int; - force_baseline : boolean); -{ Set or change the 'quality' (quantization) setting, using default tables. - This is the standard quality-adjusting entry point for typical user - interfaces; only those who want detailed control over quantization tables - would use the preceding three routines directly. } -begin - { Convert user 0-100 rating to percentage scaling } - quality := jpeg_quality_scaling(quality); - - { Set up standard quality tables } - jpeg_set_linear_quality(cinfo, quality, force_baseline); -end; - - -{ Huffman table setup routines } - -{LOCAL} -procedure add_huff_table (cinfo : j_compress_ptr; - var htblptr : JHUFF_TBL_PTR; - var bits : array of UINT8; - var val : array of UINT8); -{ Define a Huffman table } -var - nsymbols, len : int; -begin - if (htblptr = NIL) then - htblptr := jpeg_alloc_huff_table(j_common_ptr(cinfo)); - - { Copy the number-of-symbols-of-each-code-length counts } - MEMCOPY(@htblptr^.bits, @bits, SIZEOF(htblptr^.bits)); - - - { Validate the counts. We do this here mainly so we can copy the right - number of symbols from the val[] array, without risking marching off - the end of memory. jchuff.c will do a more thorough test later. } - - nsymbols := 0; - for len := 1 to 16 do - Inc(nsymbols, bits[len]); - if (nsymbols < 1) or (nsymbols > 256) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - - MEMCOPY(@htblptr^.huffval, @val, nsymbols * SIZEOF(UINT8)); - - { Initialize sent_table FALSE so table will be written to JPEG file. } - (htblptr)^.sent_table := FALSE; -end; - - -{$J+} -{LOCAL} -procedure std_huff_tables (cinfo : j_compress_ptr); -{ Set up the standard Huffman tables (cf. JPEG standard section K.3) } -{ IMPORTANT: these are only valid for 8-bit data precision! } - const bits_dc_luminance : array[0..17-1] of UINT8 = - ({ 0-base } 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0); - const val_dc_luminance : array[0..11] of UINT8 = - (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); - - const bits_dc_chrominance : array[0..17-1] of UINT8 = - ( { 0-base } 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 ); - const val_dc_chrominance : array[0..11] of UINT8 = - ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ); - - const bits_ac_luminance : array[0..17-1] of UINT8 = - ( { 0-base } 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, $7d ); - const val_ac_luminance : array[0..161] of UINT8 = - ( $01, $02, $03, $00, $04, $11, $05, $12, - $21, $31, $41, $06, $13, $51, $61, $07, - $22, $71, $14, $32, $81, $91, $a1, $08, - $23, $42, $b1, $c1, $15, $52, $d1, $f0, - $24, $33, $62, $72, $82, $09, $0a, $16, - $17, $18, $19, $1a, $25, $26, $27, $28, - $29, $2a, $34, $35, $36, $37, $38, $39, - $3a, $43, $44, $45, $46, $47, $48, $49, - $4a, $53, $54, $55, $56, $57, $58, $59, - $5a, $63, $64, $65, $66, $67, $68, $69, - $6a, $73, $74, $75, $76, $77, $78, $79, - $7a, $83, $84, $85, $86, $87, $88, $89, - $8a, $92, $93, $94, $95, $96, $97, $98, - $99, $9a, $a2, $a3, $a4, $a5, $a6, $a7, - $a8, $a9, $aa, $b2, $b3, $b4, $b5, $b6, - $b7, $b8, $b9, $ba, $c2, $c3, $c4, $c5, - $c6, $c7, $c8, $c9, $ca, $d2, $d3, $d4, - $d5, $d6, $d7, $d8, $d9, $da, $e1, $e2, - $e3, $e4, $e5, $e6, $e7, $e8, $e9, $ea, - $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, - $f9, $fa ); - - const bits_ac_chrominance : array[0..17-1] of UINT8 = - ( { 0-base } 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, $77 ); - const val_ac_chrominance : array[0..161] of UINT8 = - ( $00, $01, $02, $03, $11, $04, $05, $21, - $31, $06, $12, $41, $51, $07, $61, $71, - $13, $22, $32, $81, $08, $14, $42, $91, - $a1, $b1, $c1, $09, $23, $33, $52, $f0, - $15, $62, $72, $d1, $0a, $16, $24, $34, - $e1, $25, $f1, $17, $18, $19, $1a, $26, - $27, $28, $29, $2a, $35, $36, $37, $38, - $39, $3a, $43, $44, $45, $46, $47, $48, - $49, $4a, $53, $54, $55, $56, $57, $58, - $59, $5a, $63, $64, $65, $66, $67, $68, - $69, $6a, $73, $74, $75, $76, $77, $78, - $79, $7a, $82, $83, $84, $85, $86, $87, - $88, $89, $8a, $92, $93, $94, $95, $96, - $97, $98, $99, $9a, $a2, $a3, $a4, $a5, - $a6, $a7, $a8, $a9, $aa, $b2, $b3, $b4, - $b5, $b6, $b7, $b8, $b9, $ba, $c2, $c3, - $c4, $c5, $c6, $c7, $c8, $c9, $ca, $d2, - $d3, $d4, $d5, $d6, $d7, $d8, $d9, $da, - $e2, $e3, $e4, $e5, $e6, $e7, $e8, $e9, - $ea, $f2, $f3, $f4, $f5, $f6, $f7, $f8, - $f9, $fa ); -begin - add_huff_table(cinfo, cinfo^.dc_huff_tbl_ptrs[0], - bits_dc_luminance, val_dc_luminance); - add_huff_table(cinfo, cinfo^.ac_huff_tbl_ptrs[0], - bits_ac_luminance, val_ac_luminance); - add_huff_table(cinfo, cinfo^.dc_huff_tbl_ptrs[1], - bits_dc_chrominance, val_dc_chrominance); - add_huff_table(cinfo, cinfo^.ac_huff_tbl_ptrs[1], - bits_ac_chrominance, val_ac_chrominance); -end; - - -{ Default parameter setup for compression. - - Applications that don't choose to use this routine must do their - own setup of all these parameters. Alternately, you can call this - to establish defaults and then alter parameters selectively. This - is the recommended approach since, if we add any new parameters, - your code will still work (they'll be set to reasonable defaults). } - -{GLOBAL} -procedure jpeg_set_defaults (cinfo : j_compress_ptr); -var - i : int; -begin - { Safety check to ensure start_compress not called yet. } - if (cinfo^.global_state <> CSTATE_START) then - ERREXIT1(J_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - { Allocate comp_info array large enough for maximum component count. - Array is made permanent in case application wants to compress - multiple images at same param settings. } - - if (cinfo^.comp_info = NIL) then - cinfo^.comp_info := jpeg_component_info_list_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT, - MAX_COMPONENTS * SIZEOF(jpeg_component_info)) ); - - { Initialize everything not dependent on the color space } - - cinfo^.data_precision := BITS_IN_JSAMPLE; - { Set up two quantization tables using default quality of 75 } - jpeg_set_quality(cinfo, 75, TRUE); - { Set up two Huffman tables } - std_huff_tables(cinfo); - - { Initialize default arithmetic coding conditioning } - for i := 0 to pred(NUM_ARITH_TBLS) do - begin - cinfo^.arith_dc_L[i] := 0; - cinfo^.arith_dc_U[i] := 1; - cinfo^.arith_ac_K[i] := 5; - end; - - { Default is no multiple-scan output } - cinfo^.scan_info := NIL; - cinfo^.num_scans := 0; - - { Expect normal source image, not raw downsampled data } - cinfo^.raw_data_in := FALSE; - - { Use Huffman coding, not arithmetic coding, by default } - cinfo^.arith_code := FALSE; - - { By default, don't do extra passes to optimize entropy coding } - cinfo^.optimize_coding := FALSE; - { The standard Huffman tables are only valid for 8-bit data precision. - If the precision is higher, force optimization on so that usable - tables will be computed. This test can be removed if default tables - are supplied that are valid for the desired precision. } - - if (cinfo^.data_precision > 8) then - cinfo^.optimize_coding := TRUE; - - { By default, use the simpler non-cosited sampling alignment } - cinfo^.CCIR601_sampling := FALSE; - - { No input smoothing } - cinfo^.smoothing_factor := 0; - - { DCT algorithm preference } - cinfo^.dct_method := JDCT_DEFAULT; - - { No restart markers } - cinfo^.restart_interval := 0; - cinfo^.restart_in_rows := 0; - - { Fill in default JFIF marker parameters. Note that whether the marker - will actually be written is determined by jpeg_set_colorspace. - - By default, the library emits JFIF version code 1.01. - An application that wants to emit JFIF 1.02 extension markers should set - JFIF_minor_version to 2. We could probably get away with just defaulting - to 1.02, but there may still be some decoders in use that will complain - about that; saying 1.01 should minimize compatibility problems. } - - cinfo^.JFIF_major_version := 1; { Default JFIF version = 1.01 } - cinfo^.JFIF_minor_version := 1; - cinfo^.density_unit := 0; { Pixel size is unknown by default } - cinfo^.X_density := 1; { Pixel aspect ratio is square by default } - cinfo^.Y_density := 1; - - { Choose JPEG colorspace based on input space, set defaults accordingly } - - jpeg_default_colorspace(cinfo); -end; - - -{ Select an appropriate JPEG colorspace for in_color_space. } - -{GLOBAL} -procedure jpeg_default_colorspace (cinfo : j_compress_ptr); -begin - case (cinfo^.in_color_space) of - JCS_GRAYSCALE: - jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); - JCS_RGB: - jpeg_set_colorspace(cinfo, JCS_YCbCr); - JCS_YCbCr: - jpeg_set_colorspace(cinfo, JCS_YCbCr); - JCS_CMYK: - jpeg_set_colorspace(cinfo, JCS_CMYK); { By default, no translation } - JCS_YCCK: - jpeg_set_colorspace(cinfo, JCS_YCCK); - JCS_UNKNOWN: - jpeg_set_colorspace(cinfo, JCS_UNKNOWN); - else - ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE); - end; -end; - - -{ Set the JPEG colorspace, and choose colorspace-dependent default values. } - -{GLOBAL} -procedure jpeg_set_colorspace (cinfo : j_compress_ptr; - colorspace : J_COLOR_SPACE); - { macro } - procedure SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl : int); - begin - with cinfo^.comp_info^[index] do - begin - component_id := (id); - h_samp_factor := (hsamp); - v_samp_factor := (vsamp); - quant_tbl_no := (quant); - dc_tbl_no := (dctbl); - ac_tbl_no := (actbl); - end; - end; - -var - ci : int; -begin - { Safety check to ensure start_compress not called yet. } - if (cinfo^.global_state <> CSTATE_START) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - { For all colorspaces, we use Q and Huff tables 0 for luminance components, - tables 1 for chrominance components. } - - cinfo^.jpeg_color_space := colorspace; - - cinfo^.write_JFIF_header := FALSE; { No marker for non-JFIF colorspaces } - cinfo^.write_Adobe_marker := FALSE; { write no Adobe marker by default } - - case (colorspace) of - JCS_GRAYSCALE: - begin - cinfo^.write_JFIF_header := TRUE; { Write a JFIF marker } - cinfo^.num_components := 1; - { JFIF specifies component ID 1 } - SET_COMP(0, 1, 1,1, 0, 0,0); - end; - JCS_RGB: - begin - cinfo^.write_Adobe_marker := TRUE; { write Adobe marker to flag RGB } - cinfo^.num_components := 3; - SET_COMP(0, $52 { 'R' }, 1,1, 0, 0,0); - SET_COMP(1, $47 { 'G' }, 1,1, 0, 0,0); - SET_COMP(2, $42 { 'B' }, 1,1, 0, 0,0); - end; - JCS_YCbCr: - begin - cinfo^.write_JFIF_header := TRUE; { Write a JFIF marker } - cinfo^.num_components := 3; - { JFIF specifies component IDs 1,2,3 } - { We default to 2x2 subsamples of chrominance } - SET_COMP(0, 1, 2,2, 0, 0,0); - SET_COMP(1, 2, 1,1, 1, 1,1); - SET_COMP(2, 3, 1,1, 1, 1,1); - end; - JCS_CMYK: - begin - cinfo^.write_Adobe_marker := TRUE; { write Adobe marker to flag CMYK } - cinfo^.num_components := 4; - SET_COMP(0, $43 { 'C' }, 1,1, 0, 0,0); - SET_COMP(1, $4D { 'M' }, 1,1, 0, 0,0); - SET_COMP(2, $59 { 'Y' }, 1,1, 0, 0,0); - SET_COMP(3, $4B { 'K' }, 1,1, 0, 0,0); - end; - JCS_YCCK: - begin - cinfo^.write_Adobe_marker := TRUE; { write Adobe marker to flag YCCK } - cinfo^.num_components := 4; - SET_COMP(0, 1, 2,2, 0, 0,0); - SET_COMP(1, 2, 1,1, 1, 1,1); - SET_COMP(2, 3, 1,1, 1, 1,1); - SET_COMP(3, 4, 2,2, 0, 0,0); - end; - JCS_UNKNOWN: - begin - cinfo^.num_components := cinfo^.input_components; - if (cinfo^.num_components < 1) - or (cinfo^.num_components > MAX_COMPONENTS) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, - cinfo^.num_components, MAX_COMPONENTS); - for ci := 0 to pred(cinfo^.num_components) do - begin - SET_COMP(ci, ci, 1,1, 0, 0,0); - end; - end; - else - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - end; -end; - - -{$ifdef C_PROGRESSIVE_SUPPORTED} - -{LOCAL} -function fill_a_scan (scanptr : jpeg_scan_info_ptr; - ci : int; Ss : int; - Se : int; Ah : int; - Al : int) : jpeg_scan_info_ptr; -{ Support routine: generate one scan for specified component } -begin - scanptr^.comps_in_scan := 1; - scanptr^.component_index[0] := ci; - scanptr^.Ss := Ss; - scanptr^.Se := Se; - scanptr^.Ah := Ah; - scanptr^.Al := Al; - Inc(scanptr); - fill_a_scan := scanptr; -end; - -{LOCAL} -function fill_scans (scanptr : jpeg_scan_info_ptr; - ncomps : int; - Ss : int; Se : int; - Ah : int; Al : int) : jpeg_scan_info_ptr; -{ Support routine: generate one scan for each component } -var - ci : int; -begin - - for ci := 0 to pred(ncomps) do - begin - scanptr^.comps_in_scan := 1; - scanptr^.component_index[0] := ci; - scanptr^.Ss := Ss; - scanptr^.Se := Se; - scanptr^.Ah := Ah; - scanptr^.Al := Al; - Inc(scanptr); - end; - fill_scans := scanptr; -end; - -{LOCAL} -function fill_dc_scans (scanptr : jpeg_scan_info_ptr; - ncomps : int; - Ah : int; Al : int) : jpeg_scan_info_ptr; -{ Support routine: generate interleaved DC scan if possible, else N scans } -var - ci : int; -begin - - if (ncomps <= MAX_COMPS_IN_SCAN) then - begin - { Single interleaved DC scan } - scanptr^.comps_in_scan := ncomps; - for ci := 0 to pred(ncomps) do - scanptr^.component_index[ci] := ci; - scanptr^.Ss := 0; - scanptr^.Se := 0; - scanptr^.Ah := Ah; - scanptr^.Al := Al; - Inc(scanptr); - end - else - begin - { Noninterleaved DC scan for each component } - scanptr := fill_scans(scanptr, ncomps, 0, 0, Ah, Al); - end; - fill_dc_scans := scanptr; -end; - - -{ Create a recommended progressive-JPEG script. - cinfo^.num_components and cinfo^.jpeg_color_space must be correct. } - -{GLOBAL} -procedure jpeg_simple_progression (cinfo : j_compress_ptr); -var - ncomps : int; - nscans : int; - scanptr : jpeg_scan_info_ptr; -begin - ncomps := cinfo^.num_components; - - { Safety check to ensure start_compress not called yet. } - if (cinfo^.global_state <> CSTATE_START) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - { Figure space needed for script. Calculation must match code below! } - if (ncomps = 3) and (cinfo^.jpeg_color_space = JCS_YCbCr) then - begin - { Custom script for YCbCr color images. } - nscans := 10; - end - else - begin - { All-purpose script for other color spaces. } - if (ncomps > MAX_COMPS_IN_SCAN) then - nscans := 6 * ncomps { 2 DC + 4 AC scans per component } - else - nscans := 2 + 4 * ncomps; { 2 DC scans; 4 AC scans per component } - end; - - { Allocate space for script. - We need to put it in the permanent pool in case the application performs - multiple compressions without changing the settings. To avoid a memory - leak if jpeg_simple_progression is called repeatedly for the same JPEG - object, we try to re-use previously allocated space, and we allocate - enough space to handle YCbCr even if initially asked for grayscale. } - - if (cinfo^.script_space = NIL) or (cinfo^.script_space_size < nscans) then - begin - if nscans > 10 then - cinfo^.script_space_size := nscans - else - cinfo^.script_space_size := 10; - - cinfo^.script_space := jpeg_scan_info_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT, - cinfo^.script_space_size * SIZEOF(jpeg_scan_info)) ); - end; - scanptr := cinfo^.script_space; - - cinfo^.scan_info := scanptr; - cinfo^.num_scans := nscans; - - if (ncomps = 3) and (cinfo^.jpeg_color_space = JCS_YCbCr) then - begin - { Custom script for YCbCr color images. } - { Initial DC scan } - scanptr := fill_dc_scans(scanptr, ncomps, 0, 1); - { Initial AC scan: get some luma data out in a hurry } - scanptr := fill_a_scan(scanptr, 0, 1, 5, 0, 2); - { Chroma data is too small to be worth expending many scans on } - scanptr := fill_a_scan(scanptr, 2, 1, 63, 0, 1); - scanptr := fill_a_scan(scanptr, 1, 1, 63, 0, 1); - { Complete spectral selection for luma AC } - scanptr := fill_a_scan(scanptr, 0, 6, 63, 0, 2); - { Refine next bit of luma AC } - scanptr := fill_a_scan(scanptr, 0, 1, 63, 2, 1); - { Finish DC successive approximation } - scanptr := fill_dc_scans(scanptr, ncomps, 1, 0); - { Finish AC successive approximation } - scanptr := fill_a_scan(scanptr, 2, 1, 63, 1, 0); - scanptr := fill_a_scan(scanptr, 1, 1, 63, 1, 0); - { Luma bottom bit comes last since it's usually largest scan } - scanptr := fill_a_scan(scanptr, 0, 1, 63, 1, 0); - end - else - begin - { All-purpose script for other color spaces. } - { Successive approximation first pass } - scanptr := fill_dc_scans(scanptr, ncomps, 0, 1); - scanptr := fill_scans(scanptr, ncomps, 1, 5, 0, 2); - scanptr := fill_scans(scanptr, ncomps, 6, 63, 0, 2); - { Successive approximation second pass } - scanptr := fill_scans(scanptr, ncomps, 1, 63, 2, 1); - { Successive approximation final pass } - scanptr := fill_dc_scans(scanptr, ncomps, 1, 0); - scanptr := fill_scans(scanptr, ncomps, 1, 63, 1, 0); - end; -end; - -{$endif} -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcphuff.pas b/3rd/Imaging/Source/JpegLib/imjcphuff.pas deleted file mode 100644 index 2b779ef51..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcphuff.pas +++ /dev/null @@ -1,962 +0,0 @@ -unit imjcphuff; - -{ This file contains Huffman entropy encoding routines for progressive JPEG. - - We do not support output suspension in this module, since the library - currently does not allow multiple-scan files to be written with output - suspension. } - -{ Original: jcphuff.c; Copyright (C) 1995-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdeferr, - imjerror, - imjutils, - imjcomapi, - imjchuff; { Declarations shared with jchuff.c } - -{ Module initialization routine for progressive Huffman entropy encoding. } - -{GLOBAL} -procedure jinit_phuff_encoder (cinfo : j_compress_ptr); - -implementation - -{ Expanded entropy encoder object for progressive Huffman encoding. } -type - phuff_entropy_ptr = ^phuff_entropy_encoder; - phuff_entropy_encoder = record - pub : jpeg_entropy_encoder; { public fields } - - { Mode flag: TRUE for optimization, FALSE for actual data output } - gather_statistics : boolean; - - { Bit-level coding status. - next_output_byte/free_in_buffer are local copies of cinfo^.dest fields.} - - next_output_byte : JOCTETptr; { => next byte to write in buffer } - free_in_buffer : size_t; { # of byte spaces remaining in buffer } - put_buffer : INT32; { current bit-accumulation buffer } - put_bits : int; { # of bits now in it } - cinfo : j_compress_ptr; { link to cinfo (needed for dump_buffer) } - - { Coding status for DC components } - last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int; - { last DC coef for each component } - - { Coding status for AC components } - ac_tbl_no : int; { the table number of the single component } - EOBRUN : uInt; { run length of EOBs } - BE : uInt; { # of buffered correction bits before MCU } - bit_buffer : JBytePtr; { buffer for correction bits (1 per char) } - { packing correction bits tightly would save some space but cost time... } - - restarts_to_go : uInt; { MCUs left in this restart interval } - next_restart_num : int; { next restart number to write (0-7) } - - { Pointers to derived tables (these workspaces have image lifespan). - Since any one scan codes only DC or only AC, we only need one set - of tables, not one for DC and one for AC. } - - derived_tbls : array[0..NUM_HUFF_TBLS-1] of c_derived_tbl_ptr; - - { Statistics tables for optimization; again, one set is enough } - count_ptrs : array[0..NUM_HUFF_TBLS-1] of TLongTablePtr; - end; - - -{ MAX_CORR_BITS is the number of bits the AC refinement correction-bit - buffer can hold. Larger sizes may slightly improve compression, but - 1000 is already well into the realm of overkill. - The minimum safe size is 64 bits. } - -const - MAX_CORR_BITS = 1000; { Max # of correction bits I can buffer } - - -{ Forward declarations } -{METHODDEF} -function encode_mcu_DC_first (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -function encode_mcu_AC_first (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -function encode_mcu_DC_refine (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -function encode_mcu_AC_refine (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - forward; - -{METHODDEF} -procedure finish_pass_phuff (cinfo : j_compress_ptr); forward; - -{METHODDEF} -procedure finish_pass_gather_phuff (cinfo : j_compress_ptr); forward; - - -{ Initialize for a Huffman-compressed scan using progressive JPEG. } - -{METHODDEF} -procedure start_pass_phuff (cinfo : j_compress_ptr; - gather_statistics : boolean); -var - entropy : phuff_entropy_ptr; - is_DC_band : boolean; - ci, tbl : int; - compptr : jpeg_component_info_ptr; -begin - tbl := 0; - entropy := phuff_entropy_ptr (cinfo^.entropy); - - entropy^.cinfo := cinfo; - entropy^.gather_statistics := gather_statistics; - - is_DC_band := (cinfo^.Ss = 0); - - { We assume jcmaster.c already validated the scan parameters. } - - { Select execution routines } - if (cinfo^.Ah = 0) then - begin - if (is_DC_band) then - entropy^.pub.encode_mcu := encode_mcu_DC_first - else - entropy^.pub.encode_mcu := encode_mcu_AC_first; - end - else - begin - if (is_DC_band) then - entropy^.pub.encode_mcu := encode_mcu_DC_refine - else - begin - entropy^.pub.encode_mcu := encode_mcu_AC_refine; - { AC refinement needs a correction bit buffer } - if (entropy^.bit_buffer = NIL) then - entropy^.bit_buffer := JBytePtr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - MAX_CORR_BITS * SIZEOF(byte)) ); - end; - end; - if (gather_statistics) then - entropy^.pub.finish_pass := finish_pass_gather_phuff - else - entropy^.pub.finish_pass := finish_pass_phuff; - - { Only DC coefficients may be interleaved, so cinfo^.comps_in_scan = 1 - for AC coefficients. } - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - { Initialize DC predictions to 0 } - entropy^.last_dc_val[ci] := 0; - { Get table index } - if (is_DC_band) then - begin - if (cinfo^.Ah <> 0) then { DC refinement needs no table } - continue; - tbl := compptr^.dc_tbl_no; - end - else - begin - tbl := compptr^.ac_tbl_no; - entropy^.ac_tbl_no := tbl; - end; - if (gather_statistics) then - begin - { Check for invalid table index } - { (make_c_derived_tbl does this in the other path) } - if (tbl < 0) or (tbl >= NUM_HUFF_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tbl); - { Allocate and zero the statistics tables } - { Note that jpeg_gen_optimal_table expects 257 entries in each table! } - if (entropy^.count_ptrs[tbl] = NIL) then - entropy^.count_ptrs[tbl] := TLongTablePtr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - 257 * SIZEOF(long)) ); - MEMZERO(entropy^.count_ptrs[tbl], 257 * SIZEOF(long)); - end else - begin - { Compute derived values for Huffman table } - { We may do this more than once for a table, but it's not expensive } - jpeg_make_c_derived_tbl(cinfo, is_DC_band, tbl, - entropy^.derived_tbls[tbl]); - end; - end; - - { Initialize AC stuff } - entropy^.EOBRUN := 0; - entropy^.BE := 0; - - { Initialize bit buffer to empty } - entropy^.put_buffer := 0; - entropy^.put_bits := 0; - - { Initialize restart stuff } - entropy^.restarts_to_go := cinfo^.restart_interval; - entropy^.next_restart_num := 0; -end; - - - - -{LOCAL} -procedure dump_buffer (entropy : phuff_entropy_ptr); -{ Empty the output buffer; we do not support suspension in this module. } -var - dest : jpeg_destination_mgr_ptr; -begin - dest := entropy^.cinfo^.dest; - - if (not dest^.empty_output_buffer (entropy^.cinfo)) then - ERREXIT(j_common_ptr(entropy^.cinfo), JERR_CANT_SUSPEND); - { After a successful buffer dump, must reset buffer pointers } - entropy^.next_output_byte := dest^.next_output_byte; - entropy^.free_in_buffer := dest^.free_in_buffer; -end; - - -{ Outputting bits to the file } - -{ Only the right 24 bits of put_buffer are used; the valid bits are - left-justified in this part. At most 16 bits can be passed to emit_bits - in one call, and we never retain more than 7 bits in put_buffer - between calls, so 24 bits are sufficient. } - - -{LOCAL} -procedure emit_bits (entropy : phuff_entropy_ptr; - code : uInt; - size : int); {INLINE} -{ Emit some bits, unless we are in gather mode } -var - {register} put_buffer : INT32; - {register} put_bits : int; -var - c : int; -begin - { This routine is heavily used, so it's worth coding tightly. } - put_buffer := INT32 (code); - put_bits := entropy^.put_bits; - - { if size is 0, caller used an invalid Huffman table entry } - if (size = 0) then - ERREXIT(j_common_ptr(entropy^.cinfo), JERR_HUFF_MISSING_CODE); - - if (entropy^.gather_statistics) then - exit; { do nothing if we're only getting stats } - - put_buffer := put_buffer and ((INT32(1) shl size) - 1); - { mask off any extra bits in code } - - Inc(put_bits, size); { new number of bits in buffer } - - put_buffer := put_buffer shl (24 - put_bits); { align incoming bits } - - put_buffer := put_buffer or entropy^.put_buffer; - { and merge with old buffer contents } - - while (put_bits >= 8) do - begin - c := int ((put_buffer shr 16) and $FF); - - {emit_byte(entropy, c);} - { Outputting bytes to the file. - NB: these must be called only when actually outputting, - that is, entropy^.gather_statistics = FALSE. } - { Emit a byte } - entropy^.next_output_byte^ := JOCTET(c); - Inc(entropy^.next_output_byte); - Dec(entropy^.free_in_buffer); - if (entropy^.free_in_buffer = 0) then - dump_buffer(entropy); - - if (c = $FF) then - begin { need to stuff a zero byte? } - {emit_byte(entropy, 0);} - entropy^.next_output_byte^ := JOCTET(0); - Inc(entropy^.next_output_byte); - Dec(entropy^.free_in_buffer); - if (entropy^.free_in_buffer = 0) then - dump_buffer(entropy); - end; - put_buffer := put_buffer shl 8; - Dec(put_bits, 8); - end; - - entropy^.put_buffer := put_buffer; { update variables } - entropy^.put_bits := put_bits; -end; - - -{LOCAL} -procedure flush_bits (entropy : phuff_entropy_ptr); -begin - emit_bits(entropy, $7F, 7); { fill any partial byte with ones } - entropy^.put_buffer := 0; { and reset bit-buffer to empty } - entropy^.put_bits := 0; -end; - -{ Emit (or just count) a Huffman symbol. } - - -{LOCAL} -procedure emit_symbol (entropy : phuff_entropy_ptr; - tbl_no : int; - symbol : int); {INLINE} -var - tbl : c_derived_tbl_ptr; -begin - if (entropy^.gather_statistics) then - Inc(entropy^.count_ptrs[tbl_no]^[symbol]) - else - begin - tbl := entropy^.derived_tbls[tbl_no]; - emit_bits(entropy, tbl^.ehufco[symbol], tbl^.ehufsi[symbol]); - end; -end; - - -{ Emit bits from a correction bit buffer. } - -{LOCAL} -procedure emit_buffered_bits (entropy : phuff_entropy_ptr; - bufstart : JBytePtr; - nbits : uInt); -var - bufptr : byteptr; -begin - if (entropy^.gather_statistics) then - exit; { no real work } - - bufptr := byteptr(bufstart); - while (nbits > 0) do - begin - emit_bits(entropy, uInt(bufptr^), 1); - Inc(bufptr); - Dec(nbits); - end; -end; - - -{ Emit any pending EOBRUN symbol. } - -{LOCAL} -procedure emit_eobrun (entropy : phuff_entropy_ptr); -var - {register} temp, nbits : int; -begin - if (entropy^.EOBRUN > 0) then - begin { if there is any pending EOBRUN } - temp := entropy^.EOBRUN; - nbits := 0; - temp := temp shr 1; - while (temp <> 0) do - begin - Inc(nbits); - temp := temp shr 1; - end; - - { safety check: shouldn't happen given limited correction-bit buffer } - if (nbits > 14) then - ERREXIT(j_common_ptr(entropy^.cinfo), JERR_HUFF_MISSING_CODE); - - emit_symbol(entropy, entropy^.ac_tbl_no, nbits shl 4); - if (nbits <> 0) then - emit_bits(entropy, entropy^.EOBRUN, nbits); - - entropy^.EOBRUN := 0; - - { Emit any buffered correction bits } - emit_buffered_bits(entropy, entropy^.bit_buffer, entropy^.BE); - entropy^.BE := 0; - end; -end; - - -{ Emit a restart marker & resynchronize predictions. } - -{LOCAL} -procedure emit_restart (entropy : phuff_entropy_ptr; - restart_num : int); -var - ci : int; -begin - emit_eobrun(entropy); - - if (not entropy^.gather_statistics) then - begin - flush_bits(entropy); - {emit_byte(entropy, $FF);} - { Outputting bytes to the file. - NB: these must be called only when actually outputting, - that is, entropy^.gather_statistics = FALSE. } - - entropy^.next_output_byte^ := JOCTET($FF); - Inc(entropy^.next_output_byte); - Dec(entropy^.free_in_buffer); - if (entropy^.free_in_buffer = 0) then - dump_buffer(entropy); - - {emit_byte(entropy, JPEG_RST0 + restart_num);} - entropy^.next_output_byte^ := JOCTET(JPEG_RST0 + restart_num); - Inc(entropy^.next_output_byte); - Dec(entropy^.free_in_buffer); - if (entropy^.free_in_buffer = 0) then - dump_buffer(entropy); - end; - - if (entropy^.cinfo^.Ss = 0) then - begin - { Re-initialize DC predictions to 0 } - for ci := 0 to pred(entropy^.cinfo^.comps_in_scan) do - entropy^.last_dc_val[ci] := 0; - end - else - begin - { Re-initialize all AC-related fields to 0 } - entropy^.EOBRUN := 0; - entropy^.BE := 0; - end; -end; - - -{ MCU encoding for DC initial scan (either spectral selection, - or first pass of successive approximation). } - -{METHODDEF} -function encode_mcu_DC_first (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; -var - entropy : phuff_entropy_ptr; - {register} temp, temp2 : int; - {register} nbits : int; - blkn, ci : int; - Al : int; - block : JBLOCK_PTR; - compptr : jpeg_component_info_ptr; - ishift_temp : int; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - Al := cinfo^.Al; - - entropy^.next_output_byte := cinfo^.dest^.next_output_byte; - entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer; - - { Emit restart marker if needed } - if (cinfo^.restart_interval <> 0) then - if (entropy^.restarts_to_go = 0) then - emit_restart(entropy, entropy^.next_restart_num); - - { Encode the MCU data blocks } - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - block := JBLOCK_PTR(MCU_data[blkn]); - ci := cinfo^.MCU_membership[blkn]; - compptr := cinfo^.cur_comp_info[ci]; - - { Compute the DC value after the required point transform by Al. - This is simply an arithmetic right shift. } - - {temp2 := IRIGHT_SHIFT( int(block^[0]), Al);} - {IRIGHT_SHIFT_IS_UNSIGNED} - ishift_temp := int(block^[0]); - if ishift_temp < 0 then - temp2 := (ishift_temp shr Al) or ((not 0) shl (16-Al)) - else - temp2 := ishift_temp shr Al; - - - { DC differences are figured on the point-transformed values. } - temp := temp2 - entropy^.last_dc_val[ci]; - entropy^.last_dc_val[ci] := temp2; - - { Encode the DC coefficient difference per section G.1.2.1 } - temp2 := temp; - if (temp < 0) then - begin - temp := -temp; { temp is abs value of input } - { For a negative input, want temp2 := bitwise complement of abs(input) } - { This code assumes we are on a two's complement machine } - Dec(temp2); - end; - - { Find the number of bits needed for the magnitude of the coefficient } - nbits := 0; - while (temp <> 0) do - begin - Inc(nbits); - temp := temp shr 1; - end; - - { Check for out-of-range coefficient values. - Since we're encoding a difference, the range limit is twice as much. } - - if (nbits > MAX_COEF_BITS+1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_DCT_COEF); - - { Count/emit the Huffman-coded symbol for the number of bits } - emit_symbol(entropy, compptr^.dc_tbl_no, nbits); - - { Emit that number of bits of the value, if positive, } - { or the complement of its magnitude, if negative. } - if (nbits <> 0) then { emit_bits rejects calls with size 0 } - emit_bits(entropy, uInt(temp2), nbits); - end; - - cinfo^.dest^.next_output_byte := entropy^.next_output_byte; - cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer; - - { Update restart-interval state too } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - begin - entropy^.restarts_to_go := cinfo^.restart_interval; - Inc(entropy^.next_restart_num); - with entropy^ do - next_restart_num := next_restart_num and 7; - end; - Dec(entropy^.restarts_to_go); - end; - - encode_mcu_DC_first := TRUE; -end; - - -{ MCU encoding for AC initial scan (either spectral selection, - or first pass of successive approximation). } - -{METHODDEF} -function encode_mcu_AC_first (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; -var - entropy : phuff_entropy_ptr; - {register} temp, temp2 : int; - {register} nbits : int; - {register} r, k : int; - Se : int; - Al : int; - block : JBLOCK_PTR; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - Se := cinfo^.Se; - Al := cinfo^.Al; - - entropy^.next_output_byte := cinfo^.dest^.next_output_byte; - entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer; - - { Emit restart marker if needed } - if (cinfo^.restart_interval <> 0) then - if (entropy^.restarts_to_go = 0) then - emit_restart(entropy, entropy^.next_restart_num); - - { Encode the MCU data block } - block := JBLOCK_PTR(MCU_data[0]); - - { Encode the AC coefficients per section G.1.2.2, fig. G.3 } - - r := 0; { r := run length of zeros } - - for k := cinfo^.Ss to Se do - begin - temp := (block^[jpeg_natural_order[k]]); - if (temp = 0) then - begin - Inc(r); - continue; - end; - { We must apply the point transform by Al. For AC coefficients this - is an integer division with rounding towards 0. To do this portably - in C, we shift after obtaining the absolute value; so the code is - interwoven with finding the abs value (temp) and output bits (temp2). } - - if (temp < 0) then - begin - temp := -temp; { temp is abs value of input } - temp := temp shr Al; { apply the point transform } - { For a negative coef, want temp2 := bitwise complement of abs(coef) } - temp2 := not temp; - end - else - begin - temp := temp shr Al; { apply the point transform } - temp2 := temp; - end; - { Watch out for case that nonzero coef is zero after point transform } - if (temp = 0) then - begin - Inc(r); - continue; - end; - - { Emit any pending EOBRUN } - if (entropy^.EOBRUN > 0) then - emit_eobrun(entropy); - { if run length > 15, must emit special run-length-16 codes ($F0) } - while (r > 15) do - begin - emit_symbol(entropy, entropy^.ac_tbl_no, $F0); - Dec(r, 16); - end; - - { Find the number of bits needed for the magnitude of the coefficient } - nbits := 0; { there must be at least one 1 bit } - repeat - Inc(nbits); - temp := temp shr 1; - until (temp = 0); - - { Check for out-of-range coefficient values } - if (nbits > MAX_COEF_BITS) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_DCT_COEF); - - { Count/emit Huffman symbol for run length / number of bits } - emit_symbol(entropy, entropy^.ac_tbl_no, (r shl 4) + nbits); - - { Emit that number of bits of the value, if positive, } - { or the complement of its magnitude, if negative. } - emit_bits(entropy, uInt(temp2), nbits); - - r := 0; { reset zero run length } - end; - - if (r > 0) then - begin { If there are trailing zeroes, } - Inc(entropy^.EOBRUN); { count an EOB } - if (entropy^.EOBRUN = $7FFF) then - emit_eobrun(entropy); { force it out to avoid overflow } - end; - - cinfo^.dest^.next_output_byte := entropy^.next_output_byte; - cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer; - - { Update restart-interval state too } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - begin - entropy^.restarts_to_go := cinfo^.restart_interval; - Inc(entropy^.next_restart_num); - with entropy^ do - next_restart_num := next_restart_num and 7; - end; - Dec(entropy^.restarts_to_go); - end; - - encode_mcu_AC_first := TRUE; -end; - - -{ MCU encoding for DC successive approximation refinement scan. - Note: we assume such scans can be multi-component, although the spec - is not very clear on the point. } - -{METHODDEF} -function encode_mcu_DC_refine (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; -var - entropy : phuff_entropy_ptr; - {register} temp : int; - blkn : int; - Al : int; - block : JBLOCK_PTR; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - Al := cinfo^.Al; - - entropy^.next_output_byte := cinfo^.dest^.next_output_byte; - entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer; - - { Emit restart marker if needed } - if (cinfo^.restart_interval <> 0) then - if (entropy^.restarts_to_go = 0) then - emit_restart(entropy, entropy^.next_restart_num); - - { Encode the MCU data blocks } - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - block := JBLOCK_PTR(MCU_data[blkn]); - - { We simply emit the Al'th bit of the DC coefficient value. } - temp := block^[0]; - emit_bits(entropy, uInt(temp shr Al), 1); - end; - - cinfo^.dest^.next_output_byte := entropy^.next_output_byte; - cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer; - - { Update restart-interval state too } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - begin - entropy^.restarts_to_go := cinfo^.restart_interval; - Inc(entropy^.next_restart_num); - with entropy^ do - next_restart_num := next_restart_num and 7; - end; - Dec(entropy^.restarts_to_go); - end; - - encode_mcu_DC_refine := TRUE; -end; - - -{ MCU encoding for AC successive approximation refinement scan. } - -{METHODDEF} -function encode_mcu_AC_refine (cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - -var - entropy : phuff_entropy_ptr; - {register} temp : int; - {register} r, k : int; - EOB : int; - BR_buffer : JBytePtr; - BR : uInt; - Se : int; - Al : int; - block : JBLOCK_PTR; - absvalues : array[0..DCTSIZE2-1] of int; -begin - entropy := phuff_entropy_ptr(cinfo^.entropy); - Se := cinfo^.Se; - Al := cinfo^.Al; - - entropy^.next_output_byte := cinfo^.dest^.next_output_byte; - entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer; - - { Emit restart marker if needed } - if (cinfo^.restart_interval <> 0) then - if (entropy^.restarts_to_go = 0) then - emit_restart(entropy, entropy^.next_restart_num); - - { Encode the MCU data block } - block := JBLOCK_PTR(MCU_data[0]); - - { It is convenient to make a pre-pass to determine the transformed - coefficients' absolute values and the EOB position. } - - EOB := 0; - for k := cinfo^.Ss to Se do - begin - temp := block^[jpeg_natural_order[k]]; - { We must apply the point transform by Al. For AC coefficients this - is an integer division with rounding towards 0. To do this portably - in C, we shift after obtaining the absolute value. } - - if (temp < 0) then - temp := -temp; { temp is abs value of input } - temp := temp shr Al; { apply the point transform } - absvalues[k] := temp; { save abs value for main pass } - if (temp = 1) then - EOB := k; { EOB := index of last newly-nonzero coef } - end; - - { Encode the AC coefficients per section G.1.2.3, fig. G.7 } - - r := 0; { r := run length of zeros } - BR := 0; { BR := count of buffered bits added now } - BR_buffer := JBytePtr(@(entropy^.bit_buffer^[entropy^.BE])); - { Append bits to buffer } - - for k := cinfo^.Ss to Se do - begin - temp := absvalues[k]; - if (temp = 0) then - begin - Inc(r); - continue; - end; - - { Emit any required ZRLs, but not if they can be folded into EOB } - while (r > 15) and (k <= EOB) do - begin - { emit any pending EOBRUN and the BE correction bits } - emit_eobrun(entropy); - { Emit ZRL } - emit_symbol(entropy, entropy^.ac_tbl_no, $F0); - Dec(r, 16); - { Emit buffered correction bits that must be associated with ZRL } - emit_buffered_bits(entropy, BR_buffer, BR); - BR_buffer := entropy^.bit_buffer; { BE bits are gone now } - BR := 0; - end; - - { If the coef was previously nonzero, it only needs a correction bit. - NOTE: a straight translation of the spec's figure G.7 would suggest - that we also need to test r > 15. But if r > 15, we can only get here - if k > EOB, which implies that this coefficient is not 1. } - if (temp > 1) then - begin - { The correction bit is the next bit of the absolute value. } - BR_buffer^[BR] := byte (temp and 1); - Inc(BR); - continue; - end; - - { Emit any pending EOBRUN and the BE correction bits } - emit_eobrun(entropy); - - { Count/emit Huffman symbol for run length / number of bits } - emit_symbol(entropy, entropy^.ac_tbl_no, (r shl 4) + 1); - - { Emit output bit for newly-nonzero coef } - if (block^[jpeg_natural_order[k]] < 0) then - temp := 0 - else - temp := 1; - emit_bits(entropy, uInt(temp), 1); - - { Emit buffered correction bits that must be associated with this code } - emit_buffered_bits(entropy, BR_buffer, BR); - BR_buffer := entropy^.bit_buffer; { BE bits are gone now } - BR := 0; - r := 0; { reset zero run length } - end; - - if (r > 0) or (BR > 0) then - begin { If there are trailing zeroes, } - Inc(entropy^.EOBRUN); { count an EOB } - Inc(entropy^.BE, BR); { concat my correction bits to older ones } - { We force out the EOB if we risk either: - 1. overflow of the EOB counter; - 2. overflow of the correction bit buffer during the next MCU. } - - if (entropy^.EOBRUN = $7FFF) or - (entropy^.BE > (MAX_CORR_BITS-DCTSIZE2+1)) then - emit_eobrun(entropy); - end; - - cinfo^.dest^.next_output_byte := entropy^.next_output_byte; - cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer; - - { Update restart-interval state too } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - begin - entropy^.restarts_to_go := cinfo^.restart_interval; - Inc(entropy^.next_restart_num); - with entropy^ do - next_restart_num := next_restart_num and 7; - end; - Dec(entropy^.restarts_to_go); - end; - - encode_mcu_AC_refine := TRUE; -end; - - -{ Finish up at the end of a Huffman-compressed progressive scan. } - -{METHODDEF} -procedure finish_pass_phuff (cinfo : j_compress_ptr); -var - entropy : phuff_entropy_ptr; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - - entropy^.next_output_byte := cinfo^.dest^.next_output_byte; - entropy^.free_in_buffer := cinfo^.dest^.free_in_buffer; - - { Flush out any buffered data } - emit_eobrun(entropy); - flush_bits(entropy); - - cinfo^.dest^.next_output_byte := entropy^.next_output_byte; - cinfo^.dest^.free_in_buffer := entropy^.free_in_buffer; -end; - - -{ Finish up a statistics-gathering pass and create the new Huffman tables. } - -{METHODDEF} -procedure finish_pass_gather_phuff (cinfo : j_compress_ptr); -var - entropy : phuff_entropy_ptr; - is_DC_band : boolean; - ci, tbl : int; - compptr : jpeg_component_info_ptr; - htblptr : ^JHUFF_TBL_PTR; - did : array[0..NUM_HUFF_TBLS-1] of boolean; -begin - tbl := 0; - entropy := phuff_entropy_ptr (cinfo^.entropy); - - { Flush out buffered data (all we care about is counting the EOB symbol) } - emit_eobrun(entropy); - - is_DC_band := (cinfo^.Ss = 0); - - { It's important not to apply jpeg_gen_optimal_table more than once - per table, because it clobbers the input frequency counts! } - - MEMZERO(@did, SIZEOF(did)); - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - if (is_DC_band) then - begin - if (cinfo^.Ah <> 0) then { DC refinement needs no table } - continue; - tbl := compptr^.dc_tbl_no; - end - else - begin - tbl := compptr^.ac_tbl_no; - end; - if (not did[tbl]) then - begin - if (is_DC_band) then - htblptr := @(cinfo^.dc_huff_tbl_ptrs[tbl]) - else - htblptr := @(cinfo^.ac_huff_tbl_ptrs[tbl]); - if (htblptr^ = NIL) then - htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo)); - jpeg_gen_optimal_table(cinfo, htblptr^, entropy^.count_ptrs[tbl]^); - did[tbl] := TRUE; - end; - end; -end; - - -{ Module initialization routine for progressive Huffman entropy encoding. } - -{GLOBAL} -procedure jinit_phuff_encoder (cinfo : j_compress_ptr); -var - entropy : phuff_entropy_ptr; - i : int; -begin - entropy := phuff_entropy_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(phuff_entropy_encoder)) ); - cinfo^.entropy := jpeg_entropy_encoder_ptr(entropy); - entropy^.pub.start_pass := start_pass_phuff; - - { Mark tables unallocated } - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - entropy^.derived_tbls[i] := NIL; - entropy^.count_ptrs[i] := NIL; - end; - entropy^.bit_buffer := NIL; { needed only in AC refinement scan } -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcprepct.pas b/3rd/Imaging/Source/JpegLib/imjcprepct.pas deleted file mode 100644 index 97506527f..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcprepct.pas +++ /dev/null @@ -1,406 +0,0 @@ -unit imjcprepct; - -{ Original : jcprepct.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This file contains the compression preprocessing controller. - This controller manages the color conversion, downsampling, - and edge expansion steps. - - Most of the complexity here is associated with buffering input rows - as required by the downsampler. See the comments at the head of - jcsample.c for the downsampler's needs. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjpeglib, - imjdeferr, - imjerror, - imjinclude, - imjutils; - -{GLOBAL} -procedure jinit_c_prep_controller (cinfo : j_compress_ptr; - need_full_buffer : boolean); - -implementation - - -{ At present, jcsample.c can request context rows only for smoothing. - In the future, we might also need context rows for CCIR601 sampling - or other more-complex downsampling procedures. The code to support - context rows should be compiled only if needed. } - -{$ifdef INPUT_SMOOTHING_SUPPORTED} - {$define CONTEXT_ROWS_SUPPORTED} -{$endif} - - -{ For the simple (no-context-row) case, we just need to buffer one - row group's worth of pixels for the downsampling step. At the bottom of - the image, we pad to a full row group by replicating the last pixel row. - The downsampler's last output row is then replicated if needed to pad - out to a full iMCU row. - - When providing context rows, we must buffer three row groups' worth of - pixels. Three row groups are physically allocated, but the row pointer - arrays are made five row groups high, with the extra pointers above and - below "wrapping around" to point to the last and first real row groups. - This allows the downsampler to access the proper context rows. - At the top and bottom of the image, we create dummy context rows by - copying the first or last real pixel row. This copying could be avoided - by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the - trouble on the compression side. } - - -{ Private buffer controller object } - -type - my_prep_ptr = ^my_prep_controller; - my_prep_controller = record - pub : jpeg_c_prep_controller; { public fields } - - { Downsampling input buffer. This buffer holds color-converted data - until we have enough to do a downsample step. } - - color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY; - - rows_to_go : JDIMENSION; { counts rows remaining in source image } - next_buf_row : int; { index of next row to store in color_buf } - - {$ifdef CONTEXT_ROWS_SUPPORTED} { only needed for context case } - this_row_group : int; { starting row index of group to process } - next_buf_stop : int; { downsample when we reach this index } - {$endif} - end; {my_prep_controller;} - - -{ Initialize for a processing pass. } - -{METHODDEF} -procedure start_pass_prep (cinfo : j_compress_ptr; - pass_mode : J_BUF_MODE ); -var - prep : my_prep_ptr; -begin - prep := my_prep_ptr (cinfo^.prep); - - if (pass_mode <> JBUF_PASS_THRU) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - - { Initialize total-height counter for detecting bottom of image } - prep^.rows_to_go := cinfo^.image_height; - { Mark the conversion buffer empty } - prep^.next_buf_row := 0; -{$ifdef CONTEXT_ROWS_SUPPORTED} - { Preset additional state variables for context mode. - These aren't used in non-context mode, so we needn't test which mode. } - prep^.this_row_group := 0; - { Set next_buf_stop to stop after two row groups have been read in. } - prep^.next_buf_stop := 2 * cinfo^.max_v_samp_factor; -{$endif} -end; - - -{ Expand an image vertically from height input_rows to height output_rows, - by duplicating the bottom row. } - -{LOCAL} -procedure expand_bottom_edge (image_data : JSAMPARRAY; - num_cols : JDIMENSION; - input_rows : int; - output_rows : int); -var - {register} row : int; -begin - for row := input_rows to pred(output_rows) do - begin - jcopy_sample_rows(image_data, input_rows-1, image_data, row, - 1, num_cols); - end; -end; - - -{ Process some data in the simple no-context case. - - Preprocessor output data is counted in "row groups". A row group - is defined to be v_samp_factor sample rows of each component. - Downsampling will produce this much data from each max_v_samp_factor - input rows. } - -{METHODDEF} -procedure pre_process_data (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION; - output_buf : JSAMPIMAGE; - var out_row_group_ctr : JDIMENSION; - out_row_groups_avail : JDIMENSION); -var - prep : my_prep_ptr; - numrows, ci : int; - inrows : JDIMENSION; - compptr : jpeg_component_info_ptr; -var - local_input_buf : JSAMPARRAY; -begin - prep := my_prep_ptr (cinfo^.prep); - - while (in_row_ctr < in_rows_avail) and - (out_row_group_ctr < out_row_groups_avail) do - begin - { Do color conversion to fill the conversion buffer. } - inrows := in_rows_avail - in_row_ctr; - numrows := cinfo^.max_v_samp_factor - prep^.next_buf_row; - {numrows := int( MIN(JDIMENSION(numrows), inrows) );} - if inrows < JDIMENSION(numrows) then - numrows := int(inrows); - local_input_buf := JSAMPARRAY(@(input_buf^[in_row_ctr])); - cinfo^.cconvert^.color_convert (cinfo, local_input_buf, - JSAMPIMAGE(@prep^.color_buf), - JDIMENSION(prep^.next_buf_row), - numrows); - Inc(in_row_ctr, numrows); - Inc(prep^.next_buf_row, numrows); - Dec(prep^.rows_to_go, numrows); - { If at bottom of image, pad to fill the conversion buffer. } - if (prep^.rows_to_go = 0) and - (prep^.next_buf_row < cinfo^.max_v_samp_factor) then - begin - for ci := 0 to pred(cinfo^.num_components) do - begin - expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width, - prep^.next_buf_row, cinfo^.max_v_samp_factor); - end; - prep^.next_buf_row := cinfo^.max_v_samp_factor; - end; - { If we've filled the conversion buffer, empty it. } - if (prep^.next_buf_row = cinfo^.max_v_samp_factor) then - begin - cinfo^.downsample^.downsample (cinfo, - JSAMPIMAGE(@prep^.color_buf), - JDIMENSION (0), - output_buf, - out_row_group_ctr); - prep^.next_buf_row := 0; - Inc(out_row_group_ctr);; - end; - { If at bottom of image, pad the output to a full iMCU height. - Note we assume the caller is providing a one-iMCU-height output buffer! } - if (prep^.rows_to_go = 0) and - (out_row_group_ctr < out_row_groups_avail) then - begin - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - expand_bottom_edge(output_buf^[ci], - compptr^.width_in_blocks * DCTSIZE, - int (out_row_group_ctr) * compptr^.v_samp_factor, - int (out_row_groups_avail) * compptr^.v_samp_factor); - Inc(compptr); - end; - out_row_group_ctr := out_row_groups_avail; - break; { can exit outer loop without test } - end; - end; -end; - - -{$ifdef CONTEXT_ROWS_SUPPORTED} - -{ Process some data in the context case. } - -{METHODDEF} -procedure pre_process_context (cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION; - output_buf : JSAMPIMAGE; - var out_row_group_ctr : JDIMENSION; - out_row_groups_avail : JDIMENSION); -var - prep : my_prep_ptr; - numrows, ci : int; - buf_height : int; - inrows : JDIMENSION; -var - row : int; - -begin - prep := my_prep_ptr (cinfo^.prep); - buf_height := cinfo^.max_v_samp_factor * 3; - - while (out_row_group_ctr < out_row_groups_avail) do - begin - if (in_row_ctr < in_rows_avail) then - begin - { Do color conversion to fill the conversion buffer. } - inrows := in_rows_avail - in_row_ctr; - numrows := prep^.next_buf_stop - prep^.next_buf_row; - {numrows := int ( MIN( JDIMENSION(numrows), inrows) );} - if inrows < JDIMENSION(numrows) then - numrows := int(inrows); - cinfo^.cconvert^.color_convert (cinfo, - JSAMPARRAY(@input_buf^[in_row_ctr]), - JSAMPIMAGE(@prep^.color_buf), - JDIMENSION (prep^.next_buf_row), - numrows); - { Pad at top of image, if first time through } - if (prep^.rows_to_go = cinfo^.image_height) then - begin - for ci := 0 to pred(cinfo^.num_components) do - begin - for row := 1 to cinfo^.max_v_samp_factor do - begin - jcopy_sample_rows(prep^.color_buf[ci], 0, - prep^.color_buf[ci], -row, - 1, cinfo^.image_width); - end; - end; - end; - Inc(in_row_ctr, numrows); - Inc(prep^.next_buf_row, numrows); - Dec(prep^.rows_to_go, numrows); - end - else - begin - { Return for more data, unless we are at the bottom of the image. } - if (prep^.rows_to_go <> 0) then - break; - { When at bottom of image, pad to fill the conversion buffer. } - if (prep^.next_buf_row < prep^.next_buf_stop) then - begin - for ci := 0 to pred(cinfo^.num_components) do - begin - expand_bottom_edge(prep^.color_buf[ci], cinfo^.image_width, - prep^.next_buf_row, prep^.next_buf_stop); - end; - prep^.next_buf_row := prep^.next_buf_stop; - end; - end; - { If we've gotten enough data, downsample a row group. } - if (prep^.next_buf_row = prep^.next_buf_stop) then - begin - cinfo^.downsample^.downsample (cinfo, - JSAMPIMAGE(@prep^.color_buf), - JDIMENSION(prep^.this_row_group), - output_buf, - out_row_group_ctr); - Inc(out_row_group_ctr); - { Advance pointers with wraparound as necessary. } - Inc(prep^.this_row_group, cinfo^.max_v_samp_factor); - if (prep^.this_row_group >= buf_height) then - prep^.this_row_group := 0; - if (prep^.next_buf_row >= buf_height) then - prep^.next_buf_row := 0; - prep^.next_buf_stop := prep^.next_buf_row + cinfo^.max_v_samp_factor; - end; - end; -end; - - -{ Create the wrapped-around downsampling input buffer needed for context mode. } - -{LOCAL} -procedure create_context_buffer (cinfo : j_compress_ptr); -var - prep : my_prep_ptr; - rgroup_height : int; - ci, i : int; - compptr : jpeg_component_info_ptr; - true_buffer, fake_buffer : JSAMPARRAY; -begin - prep := my_prep_ptr (cinfo^.prep); - rgroup_height := cinfo^.max_v_samp_factor; - { Grab enough space for fake row pointers for all the components; - we need five row groups' worth of pointers for each component. } - - fake_buffer := JSAMPARRAY( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - (cinfo^.num_components * 5 * rgroup_height) * - SIZEOF(JSAMPROW)) ); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Allocate the actual buffer space (3 row groups) for this component. - We make the buffer wide enough to allow the downsampler to edge-expand - horizontally within the buffer, if it so chooses. } - true_buffer := cinfo^.mem^.alloc_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, - JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE * - cinfo^.max_h_samp_factor) div compptr^.h_samp_factor), - JDIMENSION (3 * rgroup_height)); - { Copy true buffer row pointers into the middle of the fake row array } - MEMCOPY(JSAMPARRAY(@ fake_buffer^[rgroup_height]), true_buffer, - 3 * rgroup_height * SIZEOF(JSAMPROW)); - { Fill in the above and below wraparound pointers } - for i := 0 to pred(rgroup_height) do - begin - fake_buffer^[i] := true_buffer^[2 * rgroup_height + i]; - fake_buffer^[4 * rgroup_height + i] := true_buffer^[i]; - end; - prep^.color_buf[ci] := JSAMPARRAY(@ fake_buffer^[rgroup_height]); - Inc(JSAMPROW_PTR(fake_buffer), 5 * rgroup_height); { point to space for next component } - Inc(compptr); - end; -end; - -{$endif} { CONTEXT_ROWS_SUPPORTED } - - -{ Initialize preprocessing controller. } - -{GLOBAL} -procedure jinit_c_prep_controller (cinfo : j_compress_ptr; - need_full_buffer : boolean); -var - prep : my_prep_ptr; - ci : int; - compptr : jpeg_component_info_ptr; -begin - - if (need_full_buffer) then { safety check } - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - - prep := my_prep_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_prep_controller)) ); - cinfo^.prep := jpeg_c_prep_controller_ptr(prep); - prep^.pub.start_pass := start_pass_prep; - - { Allocate the color conversion buffer. - We make the buffer wide enough to allow the downsampler to edge-expand - horizontally within the buffer, if it so chooses. } - - if (cinfo^.downsample^.need_context_rows) then - begin - { Set up to provide context rows } -{$ifdef CONTEXT_ROWS_SUPPORTED} - prep^.pub.pre_process_data := pre_process_context; - create_context_buffer(cinfo); -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - begin - { No context, just make it tall enough for one row group } - prep^.pub.pre_process_data := pre_process_data; - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - prep^.color_buf[ci] := cinfo^.mem^.alloc_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, - JDIMENSION (( long(compptr^.width_in_blocks) * DCTSIZE * - cinfo^.max_h_samp_factor) div compptr^.h_samp_factor), - JDIMENSION(cinfo^.max_v_samp_factor) ); - Inc(compptr); - end; - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjcsample.pas b/3rd/Imaging/Source/JpegLib/imjcsample.pas deleted file mode 100644 index 5be2e8069..000000000 --- a/3rd/Imaging/Source/JpegLib/imjcsample.pas +++ /dev/null @@ -1,631 +0,0 @@ -unit imjcsample; - -{ This file contains downsampling routines. - - Downsampling input data is counted in "row groups". A row group - is defined to be max_v_samp_factor pixel rows of each component, - from which the downsampler produces v_samp_factor sample rows. - A single row group is processed in each call to the downsampler module. - - The downsampler is responsible for edge-expansion of its output data - to fill an integral number of DCT blocks horizontally. The source buffer - may be modified if it is helpful for this purpose (the source buffer is - allocated wide enough to correspond to the desired output width). - The caller (the prep controller) is responsible for vertical padding. - - The downsampler may request "context rows" by setting need_context_rows - during startup. In this case, the input arrays will contain at least - one row group's worth of pixels above and below the passed-in data; - the caller will create dummy rows at image top and bottom by replicating - the first or last real pixel row. - - An excellent reference for image resampling is - Digital Image Warping, George Wolberg, 1990. - Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. - - The downsampling algorithm used here is a simple average of the source - pixels covered by the output pixel. The hi-falutin sampling literature - refers to this as a "box filter". In general the characteristics of a box - filter are not very good, but for the specific cases we normally use (1:1 - and 2:1 ratios) the box is equivalent to a "triangle filter" which is not - nearly so bad. If you intend to use other sampling ratios, you'd be well - advised to improve this code. - - A simple input-smoothing capability is provided. This is mainly intended - for cleaning up color-dithered GIF input files (if you find it inadequate, - we suggest using an external filtering program such as pnmconvol). When - enabled, each input pixel P is replaced by a weighted sum of itself and its - eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF, - where SF := (smoothing_factor / 1024). - Currently, smoothing is only supported for 2h2v sampling factors. } - -{ Original: jcsample.c ; Copyright (C) 1991-1996, Thomas G. Lane. } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjutils, - imjdeferr, - imjerror, - imjpeglib; - - -{ Module initialization routine for downsampling. - Note that we must select a routine for each component. } - -{GLOBAL} -procedure jinit_downsampler (cinfo : j_compress_ptr); - -implementation - -{ Pointer to routine to downsample a single component } -type - downsample1_ptr = procedure(cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); - -{ Private subobject } - -type - my_downsample_ptr = ^my_downsampler; - my_downsampler = record - pub : jpeg_downsampler; { public fields } - - { Downsampling method pointers, one per component } - methods : array[0..MAX_COMPONENTS-1] of downsample1_ptr; - end; - -{ Initialize for a downsampling pass. } - -{METHODDEF} -procedure start_pass_downsample (cinfo : j_compress_ptr); -begin - { no work for now } -end; - - -{ Expand a component horizontally from width input_cols to width output_cols, - by duplicating the rightmost samples. } - -{LOCAL} -procedure expand_right_edge (image_data : JSAMPARRAY; - num_rows : int; - input_cols : JDIMENSION; - output_cols : JDIMENSION); -var - {register} ptr : JSAMPLE_PTR; - {register} pixval : JSAMPLE; - {register} count : int; - row : int; - numcols : int; -begin - numcols := int (output_cols - input_cols); - - if (numcols > 0) then - begin - for row := 0 to pred(num_rows) do - begin - ptr := JSAMPLE_PTR(@(image_data^[row]^[input_cols-1])); - pixval := ptr^; { don't need GETJSAMPLE() here } - for count := pred(numcols) downto 0 do - begin - Inc(ptr); - ptr^ := pixval; - end; - end; - end; -end; - - -{ Do downsampling for a whole row group (all components). - - In this version we simply downsample each component independently. } - -{METHODDEF} -procedure sep_downsample (cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE; - in_row_index : JDIMENSION; - output_buf : JSAMPIMAGE; - out_row_group_index : JDIMENSION); -var - downsample : my_downsample_ptr; - ci : int; - compptr : jpeg_component_info_ptr; - in_ptr, out_ptr : JSAMPARRAY; -begin - downsample := my_downsample_ptr (cinfo^.downsample); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - in_ptr := JSAMPARRAY(@ input_buf^[ci]^[in_row_index]); - out_ptr := JSAMPARRAY(@ output_buf^[ci]^ - [out_row_group_index * JDIMENSION(compptr^.v_samp_factor)]); - downsample^.methods[ci] (cinfo, compptr, in_ptr, out_ptr); - Inc(compptr); - end; -end; - - -{ Downsample pixel values of a single component. - One row group is processed per call. - This version handles arbitrary integral sampling ratios, without smoothing. - Note that this version is not actually used for customary sampling ratios. } - -{METHODDEF} -procedure int_downsample (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); -var - inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v : int; - outcol, outcol_h : JDIMENSION; { outcol_h = outcol*h_expand } - output_cols : JDIMENSION; - inptr, - outptr : JSAMPLE_PTR; - outvalue : INT32; -begin - output_cols := compptr^.width_in_blocks * DCTSIZE; - - h_expand := cinfo^.max_h_samp_factor div compptr^.h_samp_factor; - v_expand := cinfo^.max_v_samp_factor div compptr^.v_samp_factor; - numpix := h_expand * v_expand; - numpix2 := numpix div 2; - - { Expand input data enough to let all the output samples be generated - by the standard loop. Special-casing padded output would be more - efficient. } - - expand_right_edge(input_data, cinfo^.max_v_samp_factor, - cinfo^.image_width, output_cols * JDIMENSION(h_expand)); - - inrow := 0; - for outrow := 0 to pred(compptr^.v_samp_factor) do - begin - outptr := JSAMPLE_PTR(output_data^[outrow]); - outcol_h := 0; - for outcol := 0 to pred(output_cols) do - begin - outvalue := 0; - for v := 0 to pred(v_expand) do - begin - inptr := @(input_data^[inrow+v]^[outcol_h]); - for h := 0 to pred(h_expand) do - begin - Inc(outvalue, INT32 (GETJSAMPLE(inptr^)) ); - Inc(inptr); - end; - end; - outptr^ := JSAMPLE ((outvalue + numpix2) div numpix); - Inc(outptr); - Inc(outcol_h, h_expand); - end; - Inc(inrow, v_expand); - end; -end; - - -{ Downsample pixel values of a single component. - This version handles the special case of a full-size component, - without smoothing. } - -{METHODDEF} -procedure fullsize_downsample (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); -begin - { Copy the data } - jcopy_sample_rows(input_data, 0, output_data, 0, - cinfo^.max_v_samp_factor, cinfo^.image_width); - { Edge-expand } - expand_right_edge(output_data, cinfo^.max_v_samp_factor, - cinfo^.image_width, compptr^.width_in_blocks * DCTSIZE); -end; - - -{ Downsample pixel values of a single component. - This version handles the common case of 2:1 horizontal and 1:1 vertical, - without smoothing. - - A note about the "bias" calculations: when rounding fractional values to - integer, we do not want to always round 0.5 up to the next integer. - If we did that, we'd introduce a noticeable bias towards larger values. - Instead, this code is arranged so that 0.5 will be rounded up or down at - alternate pixel locations (a simple ordered dither pattern). } - -{METHODDEF} -procedure h2v1_downsample (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); -var - outrow : int; - outcol : JDIMENSION; - output_cols : JDIMENSION; - {register} inptr, outptr : JSAMPLE_PTR; - {register} bias : int; -begin - output_cols := compptr^.width_in_blocks * DCTSIZE; - - { Expand input data enough to let all the output samples be generated - by the standard loop. Special-casing padded output would be more - efficient. } - - expand_right_edge(input_data, cinfo^.max_v_samp_factor, - cinfo^.image_width, output_cols * 2); - - for outrow := 0 to pred(compptr^.v_samp_factor) do - begin - outptr := JSAMPLE_PTR(output_data^[outrow]); - inptr := JSAMPLE_PTR(input_data^[outrow]); - bias := 0; { bias := 0,1,0,1,... for successive samples } - for outcol := 0 to pred(output_cols) do - begin - outptr^ := JSAMPLE ((GETJSAMPLE(inptr^) + - GETJSAMPLE(JSAMPROW(inptr)^[1]) + bias) shr 1); - Inc(outptr); - bias := bias xor 1; { 0=>1, 1=>0 } - Inc(inptr, 2); - end; - end; -end; - - -{ Downsample pixel values of a single component. - This version handles the standard case of 2:1 horizontal and 2:1 vertical, - without smoothing. } - -{METHODDEF} -procedure h2v2_downsample (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); -var - inrow, outrow : int; - outcol : JDIMENSION; - output_cols : JDIMENSION; - {register} inptr0, inptr1, outptr : JSAMPLE_PTR; - {register} bias : int; -begin - output_cols := compptr^.width_in_blocks * DCTSIZE; - - { Expand input data enough to let all the output samples be generated - by the standard loop. Special-casing padded output would be more - efficient. } - - expand_right_edge(input_data, cinfo^.max_v_samp_factor, - cinfo^.image_width, output_cols * 2); - - inrow := 0; - for outrow := 0 to pred(compptr^.v_samp_factor) do - begin - outptr := JSAMPLE_PTR(output_data^[outrow]); - inptr0 := JSAMPLE_PTR(input_data^[inrow]); - inptr1 := JSAMPLE_PTR(input_data^[inrow+1]); - bias := 1; { bias := 1,2,1,2,... for successive samples } - for outcol := 0 to pred(output_cols) do - begin - outptr^ := JSAMPLE ((GETJSAMPLE(inptr0^) + - GETJSAMPLE(JSAMPROW(inptr0)^[1]) + - GETJSAMPLE(inptr1^) + - GETJSAMPLE(JSAMPROW(inptr1)^[1]) + bias) shr 2); - Inc(outptr); - bias := bias xor 3; { 1=>2, 2=>1 } - Inc(inptr0, 2); - Inc(inptr1, 2); - end; - Inc(inrow, 2); - end; -end; - - -{$ifdef INPUT_SMOOTHING_SUPPORTED} - -{ Downsample pixel values of a single component. - This version handles the standard case of 2:1 horizontal and 2:1 vertical, - with smoothing. One row of context is required. } - -{METHODDEF} -procedure h2v2_smooth_downsample (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); -var - inrow, outrow : int; - colctr : JDIMENSION; - output_cols : JDIMENSION; - {register} inptr0, inptr1, above_ptr, below_ptr, outptr : JSAMPLE_PTR; - membersum, neighsum, memberscale, neighscale : INT32; -var - prev_input_data : JSAMPARRAY; - prev_inptr0, prev_inptr1, prev_above_ptr, prev_below_ptr : JSAMPLE_PTR; -begin - output_cols := compptr^.width_in_blocks * DCTSIZE; - - { Expand input data enough to let all the output samples be generated - by the standard loop. Special-casing padded output would be more - efficient. } - - prev_input_data := input_data; - Dec(JSAMPROW_PTR(prev_input_data)); - expand_right_edge(prev_input_data, cinfo^.max_v_samp_factor + 2, - cinfo^.image_width, output_cols * 2); - - { We don't bother to form the individual "smoothed" input pixel values; - we can directly compute the output which is the average of the four - smoothed values. Each of the four member pixels contributes a fraction - (1-8*SF) to its own smoothed image and a fraction SF to each of the three - other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final - output. The four corner-adjacent neighbor pixels contribute a fraction - SF to just one smoothed pixel, or SF/4 to the final output; while the - eight edge-adjacent neighbors contribute SF to each of two smoothed - pixels, or SF/2 overall. In order to use integer arithmetic, these - factors are scaled by 2^16 := 65536. - Also recall that SF := smoothing_factor / 1024. } - - memberscale := 16384 - cinfo^.smoothing_factor * 80; { scaled (1-5*SF)/4 } - neighscale := cinfo^.smoothing_factor * 16; { scaled SF/4 } - - inrow := 0; - for outrow := 0 to pred(compptr^.v_samp_factor) do - begin - outptr := JSAMPLE_PTR(output_data^[outrow]); - inptr0 := JSAMPLE_PTR(input_data^[inrow]); - inptr1 := JSAMPLE_PTR(input_data^[inrow+1]); - above_ptr := JSAMPLE_PTR(input_data^[inrow-1]); - below_ptr := JSAMPLE_PTR(input_data^[inrow+2]); - - { Special case for first column: pretend column -1 is same as column 0 } - membersum := GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) + - GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]); - neighsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(JSAMPROW(above_ptr)^[1]) + - GETJSAMPLE(below_ptr^) + GETJSAMPLE(JSAMPROW(below_ptr)^[1]) + - GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[2]) + - GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[2]); - Inc(neighsum, neighsum); - Inc(neighsum, GETJSAMPLE(above_ptr^) + - GETJSAMPLE(JSAMPROW(above_ptr)^[2]) + - GETJSAMPLE(below_ptr^) + - GETJSAMPLE(JSAMPROW(below_ptr)^[2]) ); - membersum := membersum * memberscale + neighsum * neighscale; - outptr^ := JSAMPLE ((membersum + 32768) shr 16); - Inc(outptr); - prev_inptr0 := inptr0; - prev_inptr1 := inptr1; - Inc(prev_inptr0); - Inc(prev_inptr1); - Inc(inptr0, 2); - Inc(inptr1, 2); - prev_above_ptr := above_ptr; - prev_below_ptr := below_ptr; - Inc(above_ptr, 2); - Inc(below_ptr, 2); - Inc(prev_above_ptr, 1); - Inc(prev_below_ptr, 1); - - for colctr := pred(output_cols - 2) downto 0 do - begin - { sum of pixels directly mapped to this output element } - membersum := GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) + - GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]); - { sum of edge-neighbor pixels } - neighsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(JSAMPROW(above_ptr)^[1]) + - GETJSAMPLE(below_ptr^) + GETJSAMPLE(JSAMPROW(below_ptr)^[1]) + - GETJSAMPLE(prev_inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[2]) + - GETJSAMPLE(prev_inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[2]); - { The edge-neighbors count twice as much as corner-neighbors } - Inc(neighsum, neighsum); - { Add in the corner-neighbors } - Inc(neighsum, GETJSAMPLE(prev_above_ptr^) + - GETJSAMPLE(JSAMPROW(above_ptr)^[2]) + - GETJSAMPLE(prev_below_ptr^) + - GETJSAMPLE(JSAMPROW(below_ptr)^[2]) ); - { form final output scaled up by 2^16 } - membersum := membersum * memberscale + neighsum * neighscale; - { round, descale and output it } - outptr^ := JSAMPLE ((membersum + 32768) shr 16); - Inc(outptr); - Inc(inptr0, 2); - Inc(inptr1, 2); - Inc(prev_inptr0, 2); - Inc(prev_inptr1, 2); - Inc(above_ptr, 2); - Inc(below_ptr, 2); - Inc(prev_above_ptr, 2); - Inc(prev_below_ptr, 2); - end; - - { Special case for last column } - membersum := GETJSAMPLE(inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) + - GETJSAMPLE(inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]); - neighsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(JSAMPROW(above_ptr)^[1]) + - GETJSAMPLE(below_ptr^) + GETJSAMPLE(JSAMPROW(below_ptr)^[1]) + - GETJSAMPLE(prev_inptr0^) + GETJSAMPLE(JSAMPROW(inptr0)^[1]) + - GETJSAMPLE(prev_inptr1^) + GETJSAMPLE(JSAMPROW(inptr1)^[1]); - Inc(neighsum, neighsum); - Inc(neighsum, GETJSAMPLE(prev_above_ptr^) + - GETJSAMPLE(JSAMPROW(above_ptr)^[1]) + - GETJSAMPLE(prev_below_ptr^) + - GETJSAMPLE(JSAMPROW(below_ptr)^[1]) ); - membersum := membersum * memberscale + neighsum * neighscale; - outptr^ := JSAMPLE ((membersum + 32768) shr 16); - - Inc(inrow, 2); - end; -end; - - -{ Downsample pixel values of a single component. - This version handles the special case of a full-size component, - with smoothing. One row of context is required. } - -{METHODDEF} -procedure fullsize_smooth_downsample (cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - output_data : JSAMPARRAY); -var - outrow : int; - colctr : JDIMENSION; - output_cols : JDIMENSION; - {register} inptr, above_ptr, below_ptr, outptr : JSAMPLE_PTR; - membersum, neighsum, memberscale, neighscale : INT32; - colsum, lastcolsum, nextcolsum : int; -var - prev_input_data : JSAMPARRAY; -begin - output_cols := compptr^.width_in_blocks * DCTSIZE; - - { Expand input data enough to let all the output samples be generated - by the standard loop. Special-casing padded output would be more - efficient. } - - prev_input_data := input_data; - Dec(JSAMPROW_PTR(prev_input_data)); - expand_right_edge(prev_input_data, cinfo^.max_v_samp_factor + 2, - cinfo^.image_width, output_cols); - - { Each of the eight neighbor pixels contributes a fraction SF to the - smoothed pixel, while the main pixel contributes (1-8*SF). In order - to use integer arithmetic, these factors are multiplied by 2^16 := 65536. - Also recall that SF := smoothing_factor / 1024. } - - memberscale := long(65536) - cinfo^.smoothing_factor * long(512); { scaled 1-8*SF } - neighscale := cinfo^.smoothing_factor * 64; { scaled SF } - - for outrow := 0 to pred(compptr^.v_samp_factor) do - begin - outptr := JSAMPLE_PTR(output_data^[outrow]); - inptr := JSAMPLE_PTR(input_data^[outrow]); - above_ptr := JSAMPLE_PTR(input_data^[outrow-1]); - below_ptr := JSAMPLE_PTR(input_data^[outrow+1]); - - { Special case for first column } - colsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(below_ptr^) + - GETJSAMPLE(inptr^); - Inc(above_ptr); - Inc(below_ptr); - membersum := GETJSAMPLE(inptr^); - Inc(inptr); - nextcolsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(below_ptr^) + - GETJSAMPLE(inptr^); - neighsum := colsum + (colsum - membersum) + nextcolsum; - membersum := membersum * memberscale + neighsum * neighscale; - outptr^ := JSAMPLE ((membersum + 32768) shr 16); - Inc(outptr); - lastcolsum := colsum; colsum := nextcolsum; - - for colctr := pred(output_cols - 2) downto 0 do - begin - membersum := GETJSAMPLE(inptr^); - Inc(inptr); - Inc(above_ptr); - Inc(below_ptr); - nextcolsum := GETJSAMPLE(above_ptr^) + GETJSAMPLE(below_ptr^) + - GETJSAMPLE(inptr^); - neighsum := lastcolsum + (colsum - membersum) + nextcolsum; - membersum := membersum * memberscale + neighsum * neighscale; - outptr^ := JSAMPLE ((membersum + 32768) shr 16); - Inc(outptr); - lastcolsum := colsum; colsum := nextcolsum; - end; - - { Special case for last column } - membersum := GETJSAMPLE(inptr^); - neighsum := lastcolsum + (colsum - membersum) + colsum; - membersum := membersum * memberscale + neighsum * neighscale; - outptr^ := JSAMPLE ((membersum + 32768) shr 16); - end; -end; - -{$endif} { INPUT_SMOOTHING_SUPPORTED } - - -{ Module initialization routine for downsampling. - Note that we must select a routine for each component. } - -{GLOBAL} -procedure jinit_downsampler (cinfo : j_compress_ptr); -var - downsample : my_downsample_ptr; - ci : int; - compptr : jpeg_component_info_ptr; - smoothok : boolean; -begin - smoothok := TRUE; - - downsample := my_downsample_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_downsampler)) ); - cinfo^.downsample := jpeg_downsampler_ptr (downsample); - downsample^.pub.start_pass := start_pass_downsample; - downsample^.pub.downsample := sep_downsample; - downsample^.pub.need_context_rows := FALSE; - - if (cinfo^.CCIR601_sampling) then - ERREXIT(j_common_ptr(cinfo), JERR_CCIR601_NOTIMPL); - - { Verify we can handle the sampling factors, and set up method pointers } - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - if (compptr^.h_samp_factor = cinfo^.max_h_samp_factor) and - (compptr^.v_samp_factor = cinfo^.max_v_samp_factor) then - begin -{$ifdef INPUT_SMOOTHING_SUPPORTED} - if (cinfo^.smoothing_factor <> 0) then - begin - downsample^.methods[ci] := fullsize_smooth_downsample; - downsample^.pub.need_context_rows := TRUE; - end - else -{$endif} - downsample^.methods[ci] := fullsize_downsample; - end - else - if (compptr^.h_samp_factor * 2 = cinfo^.max_h_samp_factor) and - (compptr^.v_samp_factor = cinfo^.max_v_samp_factor) then - begin - smoothok := FALSE; - downsample^.methods[ci] := h2v1_downsample; - end - else - if (compptr^.h_samp_factor * 2 = cinfo^.max_h_samp_factor) and - (compptr^.v_samp_factor * 2 = cinfo^.max_v_samp_factor) then - begin - {$ifdef INPUT_SMOOTHING_SUPPORTED} - if (cinfo^.smoothing_factor <> 0) then - begin - downsample^.methods[ci] := h2v2_smooth_downsample; - downsample^.pub.need_context_rows := TRUE; - end - else - {$endif} - downsample^.methods[ci] := h2v2_downsample; - end - else - if ((cinfo^.max_h_samp_factor mod compptr^.h_samp_factor) = 0) and - ((cinfo^.max_v_samp_factor mod compptr^.v_samp_factor) = 0) then - begin - smoothok := FALSE; - downsample^.methods[ci] := int_downsample; - end - else - ERREXIT(j_common_ptr(cinfo), JERR_FRACT_SAMPLE_NOTIMPL); - Inc(compptr); - end; - -{$ifdef INPUT_SMOOTHING_SUPPORTED} - if (cinfo^.smoothing_factor <> 0) and (not smoothok) then - TRACEMS(j_common_ptr(cinfo), 0, JTRC_SMOOTH_NOTIMPL); -{$endif} -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdapimin.pas b/3rd/Imaging/Source/JpegLib/imjdapimin.pas deleted file mode 100644 index 367128eb8..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdapimin.pas +++ /dev/null @@ -1,505 +0,0 @@ -unit imjdapimin; - -{$N+} { Nomssi: cinfo^.output_gamma } - -{ This file contains application interface code for the decompression half - of the JPEG library. These are the "minimum" API routines that may be - needed in either the normal full-decompression case or the - transcoding-only case. - - Most of the routines intended to be called directly by an application - are in this file or in jdapistd.c. But also see jcomapi.c for routines - shared by compression and decompression, and jdtrans.c for the transcoding - case. } - -{ Original : jdapimin.c ; Copyright (C) 1994-1998, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjmemmgr, imjdmarker, imjdinput, imjcomapi; - -{ Nomssi } -procedure jpeg_create_decompress(cinfo : j_decompress_ptr); - -{ Initialization of a JPEG decompression object. - The error manager must already be set up (in case memory manager fails). } - -{GLOBAL} -procedure jpeg_CreateDecompress (cinfo : j_decompress_ptr; - version : int; - structsize : size_t); - -{ Destruction of a JPEG decompression object } - -{GLOBAL} -procedure jpeg_destroy_decompress (cinfo : j_decompress_ptr); - - -{ Decompression startup: read start of JPEG datastream to see what's there. - Need only initialize JPEG object and supply a data source before calling. - - This routine will read as far as the first SOS marker (ie, actual start of - compressed data), and will save all tables and parameters in the JPEG - object. It will also initialize the decompression parameters to default - values, and finally return JPEG_HEADER_OK. On return, the application may - adjust the decompression parameters and then call jpeg_start_decompress. - (Or, if the application only wanted to determine the image parameters, - the data need not be decompressed. In that case, call jpeg_abort or - jpeg_destroy to release any temporary space.) - If an abbreviated (tables only) datastream is presented, the routine will - return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then - re-use the JPEG object to read the abbreviated image datastream(s). - It is unnecessary (but OK) to call jpeg_abort in this case. - The JPEG_SUSPENDED return code only occurs if the data source module - requests suspension of the decompressor. In this case the application - should load more source data and then re-call jpeg_read_header to resume - processing. - If a non-suspending data source is used and require_image is TRUE, then the - return code need not be inspected since only JPEG_HEADER_OK is possible. - - This routine is now just a front end to jpeg_consume_input, with some - extra error checking. } - -{GLOBAL} -function jpeg_read_header (cinfo : j_decompress_ptr; - require_image : boolean) : int; - -{ Consume data in advance of what the decompressor requires. - This can be called at any time once the decompressor object has - been created and a data source has been set up. - - This routine is essentially a state machine that handles a couple - of critical state-transition actions, namely initial setup and - transition from header scanning to ready-for-start_decompress. - All the actual input is done via the input controller's consume_input - method. } - -{GLOBAL} -function jpeg_consume_input (cinfo : j_decompress_ptr) : int; - -{ Have we finished reading the input file? } - -{GLOBAL} -function jpeg_input_complete (cinfo : j_decompress_ptr) : boolean; - -{ Is there more than one scan? } - -{GLOBAL} -function jpeg_has_multiple_scans (cinfo : j_decompress_ptr) : boolean; - - -{ Finish JPEG decompression. - - This will normally just verify the file trailer and release temp storage. - - Returns FALSE if suspended. The return value need be inspected only if - a suspending data source is used. } - -{GLOBAL} -function jpeg_finish_decompress (cinfo : j_decompress_ptr) : boolean; - -implementation - -procedure jpeg_create_decompress(cinfo : j_decompress_ptr); -begin - jpeg_CreateDecompress(cinfo, JPEG_LIB_VERSION, - size_t(sizeof(jpeg_decompress_struct))); -end; - -{ Initialization of a JPEG decompression object. - The error manager must already be set up (in case memory manager fails). } - -{GLOBAL} -procedure jpeg_CreateDecompress (cinfo : j_decompress_ptr; - version : int; - structsize : size_t); -var - i : int; -var - err : jpeg_error_mgr_ptr; - client_data : voidp; -begin - { Guard against version mismatches between library and caller. } - cinfo^.mem := NIL; { so jpeg_destroy knows mem mgr not called } - if (version <> JPEG_LIB_VERSION) then - ERREXIT2(j_common_ptr(cinfo), JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version); - if (structsize <> SIZEOF(jpeg_decompress_struct)) then - ERREXIT2(j_common_ptr(cinfo), JERR_BAD_STRUCT_SIZE, - int(SIZEOF(jpeg_decompress_struct)), int(structsize)); - - { For debugging purposes, we zero the whole master structure. - But the application has already set the err pointer, and may have set - client_data, so we have to save and restore those fields. - Note: if application hasn't set client_data, tools like Purify may - complain here. } - begin - err := cinfo^.err; - client_data := cinfo^.client_data; { ignore Purify complaint here } - MEMZERO(j_common_ptr(cinfo), SIZEOF(jpeg_decompress_struct)); - cinfo^.err := err; - cinfo^.client_data := client_data; - end; - cinfo^.is_decompressor := TRUE; - - { Initialize a memory manager instance for this object } - jinit_memory_mgr(j_common_ptr(cinfo)); - - { Zero out pointers to permanent structures. } - cinfo^.progress := NIL; - cinfo^.src := NIL; - - for i := 0 to pred(NUM_QUANT_TBLS) do - cinfo^.quant_tbl_ptrs[i] := NIL; - - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - cinfo^.dc_huff_tbl_ptrs[i] := NIL; - cinfo^.ac_huff_tbl_ptrs[i] := NIL; - end; - - { Initialize marker processor so application can override methods - for COM, APPn markers before calling jpeg_read_header. } - cinfo^.marker_list := NIL; - jinit_marker_reader(cinfo); - - { And initialize the overall input controller. } - jinit_input_controller(cinfo); - - { OK, I'm ready } - cinfo^.global_state := DSTATE_START; -end; - - -{ Destruction of a JPEG decompression object } - -{GLOBAL} -procedure jpeg_destroy_decompress (cinfo : j_decompress_ptr); -begin - jpeg_destroy(j_common_ptr(cinfo)); { use common routine } -end; - - -{ Abort processing of a JPEG decompression operation, - but don't destroy the object itself. } - -{GLOBAL} -procedure jpeg_abort_decompress (cinfo : j_decompress_ptr); -begin - jpeg_abort(j_common_ptr(cinfo)); { use common routine } -end; - - -{ Set default decompression parameters. } - -{LOCAL} -procedure default_decompress_parms (cinfo : j_decompress_ptr); -var - cid0 : int; - cid1 : int; - cid2 : int; -begin - { Guess the input colorspace, and set output colorspace accordingly. } - { (Wish JPEG committee had provided a real way to specify this...) } - { Note application may override our guesses. } - case (cinfo^.num_components) of - 1: begin - cinfo^.jpeg_color_space := JCS_GRAYSCALE; - cinfo^.out_color_space := JCS_GRAYSCALE; - end; - - 3: begin - if (cinfo^.saw_JFIF_marker) then - begin - cinfo^.jpeg_color_space := JCS_YCbCr; { JFIF implies YCbCr } - end - else - if (cinfo^.saw_Adobe_marker) then - begin - case (cinfo^.Adobe_transform) of - 0: cinfo^.jpeg_color_space := JCS_RGB; - 1: cinfo^.jpeg_color_space := JCS_YCbCr; - else - begin - WARNMS1(j_common_ptr(cinfo), JWRN_ADOBE_XFORM, cinfo^.Adobe_transform); - cinfo^.jpeg_color_space := JCS_YCbCr; { assume it's YCbCr } - end; - end; - end - else - begin - { Saw no special markers, try to guess from the component IDs } - cid0 := cinfo^.comp_info^[0].component_id; - cid1 := cinfo^.comp_info^[1].component_id; - cid2 := cinfo^.comp_info^[2].component_id; - - if (cid0 = 1) and (cid1 = 2) and (cid2 = 3) then - cinfo^.jpeg_color_space := JCS_YCbCr { assume JFIF w/out marker } - else - if (cid0 = 82) and (cid1 = 71) and (cid2 = 66) then - cinfo^.jpeg_color_space := JCS_RGB { ASCII 'R', 'G', 'B' } - else - begin - {$IFDEF DEBUG} - TRACEMS3(j_common_ptr(cinfo), 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); - {$ENDIF} - cinfo^.jpeg_color_space := JCS_YCbCr; { assume it's YCbCr } - end; - end; - { Always guess RGB is proper output colorspace. } - cinfo^.out_color_space := JCS_RGB; - end; - - 4: begin - if (cinfo^.saw_Adobe_marker) then - begin - case (cinfo^.Adobe_transform) of - 0: cinfo^.jpeg_color_space := JCS_CMYK; - 2: cinfo^.jpeg_color_space := JCS_YCCK; - else - begin - WARNMS1(j_common_ptr(cinfo), JWRN_ADOBE_XFORM, cinfo^.Adobe_transform); - cinfo^.jpeg_color_space := JCS_YCCK; { assume it's YCCK } - end; - end; - end - else - begin - { No special markers, assume straight CMYK. } - cinfo^.jpeg_color_space := JCS_CMYK; - end; - cinfo^.out_color_space := JCS_CMYK; - end; - - else - begin - cinfo^.jpeg_color_space := JCS_UNKNOWN; - cinfo^.out_color_space := JCS_UNKNOWN; - end; - end; - - { Set defaults for other decompression parameters. } - cinfo^.scale_num := 1; { 1:1 scaling } - cinfo^.scale_denom := 1; - cinfo^.output_gamma := 1.0; - cinfo^.buffered_image := FALSE; - cinfo^.raw_data_out := FALSE; - cinfo^.dct_method := JDCT_DEFAULT; - cinfo^.do_fancy_upsampling := TRUE; - cinfo^.do_block_smoothing := TRUE; - cinfo^.quantize_colors := FALSE; - { We set these in case application only sets quantize_colors. } - cinfo^.dither_mode := JDITHER_FS; -{$ifdef QUANT_2PASS_SUPPORTED} - cinfo^.two_pass_quantize := TRUE; -{$else} - cinfo^.two_pass_quantize := FALSE; -{$endif} - cinfo^.desired_number_of_colors := 256; - cinfo^.colormap := NIL; - { Initialize for no mode change in buffered-image mode. } - cinfo^.enable_1pass_quant := FALSE; - cinfo^.enable_external_quant := FALSE; - cinfo^.enable_2pass_quant := FALSE; -end; - - -{ Decompression startup: read start of JPEG datastream to see what's there. - Need only initialize JPEG object and supply a data source before calling. - - This routine will read as far as the first SOS marker (ie, actual start of - compressed data), and will save all tables and parameters in the JPEG - object. It will also initialize the decompression parameters to default - values, and finally return JPEG_HEADER_OK. On return, the application may - adjust the decompression parameters and then call jpeg_start_decompress. - (Or, if the application only wanted to determine the image parameters, - the data need not be decompressed. In that case, call jpeg_abort or - jpeg_destroy to release any temporary space.) - If an abbreviated (tables only) datastream is presented, the routine will - return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then - re-use the JPEG object to read the abbreviated image datastream(s). - It is unnecessary (but OK) to call jpeg_abort in this case. - The JPEG_SUSPENDED return code only occurs if the data source module - requests suspension of the decompressor. In this case the application - should load more source data and then re-call jpeg_read_header to resume - processing. - If a non-suspending data source is used and require_image is TRUE, then the - return code need not be inspected since only JPEG_HEADER_OK is possible. - - This routine is now just a front end to jpeg_consume_input, with some - extra error checking. } - -{GLOBAL} -function jpeg_read_header (cinfo : j_decompress_ptr; - require_image : boolean) : int; -var - retcode : int; -begin - if (cinfo^.global_state <> DSTATE_START) and - (cinfo^.global_state <> DSTATE_INHEADER) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - retcode := jpeg_consume_input(cinfo); - - case (retcode) of - JPEG_REACHED_SOS: - retcode := JPEG_HEADER_OK; - JPEG_REACHED_EOI: - begin - if (require_image) then { Complain if application wanted an image } - ERREXIT(j_common_ptr(cinfo), JERR_NO_IMAGE); - { Reset to start state; it would be safer to require the application to - call jpeg_abort, but we can't change it now for compatibility reasons. - A side effect is to free any temporary memory (there shouldn't be any). } - - jpeg_abort(j_common_ptr(cinfo)); { sets state := DSTATE_START } - retcode := JPEG_HEADER_TABLES_ONLY; - end; - JPEG_SUSPENDED: ; { no work } - end; - - jpeg_read_header := retcode; -end; - - -{ Consume data in advance of what the decompressor requires. - This can be called at any time once the decompressor object has - been created and a data source has been set up. - - This routine is essentially a state machine that handles a couple - of critical state-transition actions, namely initial setup and - transition from header scanning to ready-for-start_decompress. - All the actual input is done via the input controller's consume_input - method. } - -{GLOBAL} -function jpeg_consume_input (cinfo : j_decompress_ptr) : int; -var - retcode : int; -begin - retcode := JPEG_SUSPENDED; - - { NB: every possible DSTATE value should be listed in this switch } - - if (cinfo^.global_state) = DSTATE_START then - begin {work around the FALLTHROUGH} - { Start-of-datastream actions: reset appropriate modules } - cinfo^.inputctl^.reset_input_controller (cinfo); - { Initialize application's data source module } - cinfo^.src^.init_source (cinfo); - cinfo^.global_state := DSTATE_INHEADER; - end; - - case (cinfo^.global_state) of - DSTATE_START, - DSTATE_INHEADER: - begin - retcode := cinfo^.inputctl^.consume_input (cinfo); - if (retcode = JPEG_REACHED_SOS) then - begin { Found SOS, prepare to decompress } - { Set up default parameters based on header data } - default_decompress_parms(cinfo); - { Set global state: ready for start_decompress } - cinfo^.global_state := DSTATE_READY; - end; - end; - DSTATE_READY: - { Can't advance past first SOS until start_decompress is called } - retcode := JPEG_REACHED_SOS; - - DSTATE_PRELOAD, - DSTATE_PRESCAN, - DSTATE_SCANNING, - DSTATE_RAW_OK, - DSTATE_BUFIMAGE, - DSTATE_BUFPOST, - DSTATE_STOPPING: - retcode := cinfo^.inputctl^.consume_input (cinfo); - else - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - end; - jpeg_consume_input := retcode; -end; - - -{ Have we finished reading the input file? } - -{GLOBAL} -function jpeg_input_complete (cinfo : j_decompress_ptr) : boolean; -begin - { Check for valid jpeg object } - if (cinfo^.global_state < DSTATE_START) or - (cinfo^.global_state > DSTATE_STOPPING) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - jpeg_input_complete := cinfo^.inputctl^.eoi_reached; -end; - - -{ Is there more than one scan? } - -{GLOBAL} -function jpeg_has_multiple_scans (cinfo : j_decompress_ptr) : boolean; -begin - { Only valid after jpeg_read_header completes } - if (cinfo^.global_state < DSTATE_READY) or - (cinfo^.global_state > DSTATE_STOPPING) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - jpeg_has_multiple_scans := cinfo^.inputctl^.has_multiple_scans; -end; - - -{ Finish JPEG decompression. - - This will normally just verify the file trailer and release temp storage. - - Returns FALSE if suspended. The return value need be inspected only if - a suspending data source is used. } - -{GLOBAL} -function jpeg_finish_decompress (cinfo : j_decompress_ptr) : boolean; -begin - if ((cinfo^.global_state = DSTATE_SCANNING) or - (cinfo^.global_state = DSTATE_RAW_OK) and (not cinfo^.buffered_image)) then - begin - { Terminate final pass of non-buffered mode } - if (cinfo^.output_scanline < cinfo^.output_height) then - ERREXIT(j_common_ptr(cinfo), JERR_TOO_LITTLE_DATA); - cinfo^.master^.finish_output_pass (cinfo); - cinfo^.global_state := DSTATE_STOPPING; - end - else - if (cinfo^.global_state = DSTATE_BUFIMAGE) then - begin - { Finishing after a buffered-image operation } - cinfo^.global_state := DSTATE_STOPPING; - end - else - if (cinfo^.global_state <> DSTATE_STOPPING) then - begin - { STOPPING := repeat call after a suspension, anything else is error } - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - end; - { Read until EOI } - while (not cinfo^.inputctl^.eoi_reached) do - begin - if (cinfo^.inputctl^.consume_input (cinfo) = JPEG_SUSPENDED) then - begin - jpeg_finish_decompress := FALSE; { Suspend, come back later } - exit; - end; - end; - { Do final cleanup } - cinfo^.src^.term_source (cinfo); - { We can use jpeg_abort to release memory and reset global_state } - jpeg_abort(j_common_ptr(cinfo)); - jpeg_finish_decompress := TRUE; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdapistd.pas b/3rd/Imaging/Source/JpegLib/imjdapistd.pas deleted file mode 100644 index cef249bec..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdapistd.pas +++ /dev/null @@ -1,377 +0,0 @@ -unit imjdapistd; - -{ Original : jdapistd.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This file is part of the Independent JPEG Group's software. - For conditions of distribution and use, see the accompanying README file. - - This file contains application interface code for the decompression half - of the JPEG library. These are the "standard" API routines that are - used in the normal full-decompression case. They are not used by a - transcoding-only application. Note that if an application links in - jpeg_start_decompress, it will end up linking in the entire decompressor. - We thus must separate this file from jdapimin.c to avoid linking the - whole decompression library into a transcoder. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjdmaster; - -{ Read some scanlines of data from the JPEG decompressor. - - The return value will be the number of lines actually read. - This may be less than the number requested in several cases, - including bottom of image, data source suspension, and operating - modes that emit multiple scanlines at a time. - - Note: we warn about excess calls to jpeg_read_scanlines() since - this likely signals an application programmer error. However, - an oversize buffer (max_lines > scanlines remaining) is not an error. } - -{GLOBAL} -function jpeg_read_scanlines (cinfo : j_decompress_ptr; - scanlines : JSAMPARRAY; - max_lines : JDIMENSION) : JDIMENSION; - - -{ Alternate entry point to read raw data. - Processes exactly one iMCU row per call, unless suspended. } - -{GLOBAL} -function jpeg_read_raw_data (cinfo : j_decompress_ptr; - data : JSAMPIMAGE; - max_lines : JDIMENSION) : JDIMENSION; - -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - -{ Initialize for an output pass in buffered-image mode. } - -{GLOBAL} -function jpeg_start_output (cinfo : j_decompress_ptr; - scan_number : int) : boolean; - -{ Finish up after an output pass in buffered-image mode. - - Returns FALSE if suspended. The return value need be inspected only if - a suspending data source is used. } - -{GLOBAL} -function jpeg_finish_output (cinfo : j_decompress_ptr) : boolean; - -{$endif} { D_MULTISCAN_FILES_SUPPORTED } - -{ Decompression initialization. - jpeg_read_header must be completed before calling this. - - If a multipass operating mode was selected, this will do all but the - last pass, and thus may take a great deal of time. - - Returns FALSE if suspended. The return value need be inspected only if - a suspending data source is used. } - -{GLOBAL} -function jpeg_start_decompress (cinfo : j_decompress_ptr) : boolean; - - -implementation - -{ Forward declarations } -{LOCAL} -function output_pass_setup (cinfo : j_decompress_ptr) : boolean; forward; - -{ Decompression initialization. - jpeg_read_header must be completed before calling this. - - If a multipass operating mode was selected, this will do all but the - last pass, and thus may take a great deal of time. - - Returns FALSE if suspended. The return value need be inspected only if - a suspending data source is used. } - -{GLOBAL} -function jpeg_start_decompress (cinfo : j_decompress_ptr) : boolean; -var - retcode : int; -begin - if (cinfo^.global_state = DSTATE_READY) then - begin - { First call: initialize master control, select active modules } - jinit_master_decompress(cinfo); - if (cinfo^.buffered_image) then - begin - { No more work here; expecting jpeg_start_output next } - cinfo^.global_state := DSTATE_BUFIMAGE; - jpeg_start_decompress := TRUE; - exit; - end; - cinfo^.global_state := DSTATE_PRELOAD; - end; - if (cinfo^.global_state = DSTATE_PRELOAD) then - begin - { If file has multiple scans, absorb them all into the coef buffer } - if (cinfo^.inputctl^.has_multiple_scans) then - begin -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - while TRUE do - begin - - { Call progress monitor hook if present } - if (cinfo^.progress <> NIL) then - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - { Absorb some more input } - retcode := cinfo^.inputctl^.consume_input (cinfo); - if (retcode = JPEG_SUSPENDED) then - begin - jpeg_start_decompress := FALSE; - exit; - end; - if (retcode = JPEG_REACHED_EOI) then - break; - { Advance progress counter if appropriate } - if (cinfo^.progress <> NIL) and - ((retcode = JPEG_ROW_COMPLETED) or (retcode = JPEG_REACHED_SOS)) then - begin - Inc(cinfo^.progress^.pass_counter); - if (cinfo^.progress^.pass_counter >= cinfo^.progress^.pass_limit) then - begin - { jdmaster underestimated number of scans; ratchet up one scan } - Inc(cinfo^.progress^.pass_limit, long(cinfo^.total_iMCU_rows)); - end; - end; - end; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} { D_MULTISCAN_FILES_SUPPORTED } - end; - cinfo^.output_scan_number := cinfo^.input_scan_number; - end - else - if (cinfo^.global_state <> DSTATE_PRESCAN) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - { Perform any dummy output passes, and set up for the final pass } - jpeg_start_decompress := output_pass_setup(cinfo); -end; - - -{ Set up for an output pass, and perform any dummy pass(es) needed. - Common subroutine for jpeg_start_decompress and jpeg_start_output. - Entry: global_state := DSTATE_PRESCAN only if previously suspended. - Exit: If done, returns TRUE and sets global_state for proper output mode. - If suspended, returns FALSE and sets global_state := DSTATE_PRESCAN. } - -{LOCAL} -function output_pass_setup (cinfo : j_decompress_ptr) : boolean; -var - last_scanline : JDIMENSION; -begin - if (cinfo^.global_state <> DSTATE_PRESCAN) then - begin - { First call: do pass setup } - cinfo^.master^.prepare_for_output_pass (cinfo); - cinfo^.output_scanline := 0; - cinfo^.global_state := DSTATE_PRESCAN; - end; - { Loop over any required dummy passes } - while (cinfo^.master^.is_dummy_pass) do - begin -{$ifdef QUANT_2PASS_SUPPORTED} - { Crank through the dummy pass } - while (cinfo^.output_scanline < cinfo^.output_height) do - begin - { Call progress monitor hook if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.pass_counter := long (cinfo^.output_scanline); - cinfo^.progress^.pass_limit := long (cinfo^.output_height); - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - end; - { Process some data } - last_scanline := cinfo^.output_scanline; - cinfo^.main^.process_data (cinfo, JSAMPARRAY(NIL), - cinfo^.output_scanline, {var} - JDIMENSION(0)); - if (cinfo^.output_scanline = last_scanline) then - begin - output_pass_setup := FALSE; { No progress made, must suspend } - exit; - end; - end; - { Finish up dummy pass, and set up for another one } - cinfo^.master^.finish_output_pass (cinfo); - cinfo^.master^.prepare_for_output_pass (cinfo); - cinfo^.output_scanline := 0; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} { QUANT_2PASS_SUPPORTED } - end; - { Ready for application to drive output pass through - jpeg_read_scanlines or jpeg_read_raw_data. } - if cinfo^.raw_data_out then - cinfo^.global_state := DSTATE_RAW_OK - else - cinfo^.global_state := DSTATE_SCANNING; - output_pass_setup := TRUE; -end; - - -{ Read some scanlines of data from the JPEG decompressor. - - The return value will be the number of lines actually read. - This may be less than the number requested in several cases, - including bottom of image, data source suspension, and operating - modes that emit multiple scanlines at a time. - - Note: we warn about excess calls to jpeg_read_scanlines() since - this likely signals an application programmer error. However, - an oversize buffer (max_lines > scanlines remaining) is not an error. } - -{GLOBAL} -function jpeg_read_scanlines (cinfo : j_decompress_ptr; - scanlines : JSAMPARRAY; - max_lines : JDIMENSION) : JDIMENSION; -var - row_ctr : JDIMENSION; -begin - if (cinfo^.global_state <> DSTATE_SCANNING) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - if (cinfo^.output_scanline >= cinfo^.output_height) then - begin - WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA); - jpeg_read_scanlines := 0; - exit; - end; - - { Call progress monitor hook if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.pass_counter := long (cinfo^.output_scanline); - cinfo^.progress^.pass_limit := long (cinfo^.output_height); - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - end; - - { Process some data } - row_ctr := 0; - cinfo^.main^.process_data (cinfo, scanlines, {var}row_ctr, max_lines); - Inc(cinfo^.output_scanline, row_ctr); - jpeg_read_scanlines := row_ctr; -end; - - -{ Alternate entry point to read raw data. - Processes exactly one iMCU row per call, unless suspended. } - -{GLOBAL} -function jpeg_read_raw_data (cinfo : j_decompress_ptr; - data : JSAMPIMAGE; - max_lines : JDIMENSION) : JDIMENSION; -var - lines_per_iMCU_row : JDIMENSION; -begin - if (cinfo^.global_state <> DSTATE_RAW_OK) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - if (cinfo^.output_scanline >= cinfo^.output_height) then - begin - WARNMS(j_common_ptr(cinfo), JWRN_TOO_MUCH_DATA); - jpeg_read_raw_data := 0; - exit; - end; - - { Call progress monitor hook if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.pass_counter := long (cinfo^.output_scanline); - cinfo^.progress^.pass_limit := long (cinfo^.output_height); - cinfo^.progress^.progress_monitor (j_common_ptr(cinfo)); - end; - - { Verify that at least one iMCU row can be returned. } - lines_per_iMCU_row := cinfo^.max_v_samp_factor * cinfo^.min_DCT_scaled_size; - if (max_lines < lines_per_iMCU_row) then - ERREXIT(j_common_ptr(cinfo), JERR_BUFFER_SIZE); - - { Decompress directly into user's buffer. } - if (cinfo^.coef^.decompress_data (cinfo, data) = 0) then - begin - jpeg_read_raw_data := 0; { suspension forced, can do nothing more } - exit; - end; - - { OK, we processed one iMCU row. } - Inc(cinfo^.output_scanline, lines_per_iMCU_row); - jpeg_read_raw_data := lines_per_iMCU_row; -end; - - -{ Additional entry points for buffered-image mode. } - -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - -{ Initialize for an output pass in buffered-image mode. } - -{GLOBAL} -function jpeg_start_output (cinfo : j_decompress_ptr; - scan_number : int) : boolean; -begin - if (cinfo^.global_state <> DSTATE_BUFIMAGE) and - (cinfo^.global_state <> DSTATE_PRESCAN) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - { Limit scan number to valid range } - if (scan_number <= 0) then - scan_number := 1; - if (cinfo^.inputctl^.eoi_reached) and - (scan_number > cinfo^.input_scan_number) then - scan_number := cinfo^.input_scan_number; - cinfo^.output_scan_number := scan_number; - { Perform any dummy output passes, and set up for the real pass } - jpeg_start_output := output_pass_setup(cinfo); -end; - - -{ Finish up after an output pass in buffered-image mode. - - Returns FALSE if suspended. The return value need be inspected only if - a suspending data source is used. } - -{GLOBAL} -function jpeg_finish_output (cinfo : j_decompress_ptr) : boolean; -begin - if ((cinfo^.global_state = DSTATE_SCANNING) or - (cinfo^.global_state = DSTATE_RAW_OK) and cinfo^.buffered_image) then - begin - { Terminate this pass. } - { We do not require the whole pass to have been completed. } - cinfo^.master^.finish_output_pass (cinfo); - cinfo^.global_state := DSTATE_BUFPOST; - end - else - if (cinfo^.global_state <> DSTATE_BUFPOST) then - begin - { BUFPOST := repeat call after a suspension, anything else is error } - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - end; - { Read markers looking for SOS or EOI } - while (cinfo^.input_scan_number <= cinfo^.output_scan_number) and - (not cinfo^.inputctl^.eoi_reached) do - begin - if (cinfo^.inputctl^.consume_input (cinfo) = JPEG_SUSPENDED) then - begin - jpeg_finish_output := FALSE; { Suspend, come back later } - exit; - end; - end; - cinfo^.global_state := DSTATE_BUFIMAGE; - jpeg_finish_output := TRUE; -end; - -{$endif} { D_MULTISCAN_FILES_SUPPORTED } - -end. - diff --git a/3rd/Imaging/Source/JpegLib/imjdcoefct.pas b/3rd/Imaging/Source/JpegLib/imjdcoefct.pas deleted file mode 100644 index caa69a2ad..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdcoefct.pas +++ /dev/null @@ -1,895 +0,0 @@ -unit imjdcoefct; - -{ This file contains the coefficient buffer controller for decompression. - This controller is the top level of the JPEG decompressor proper. - The coefficient buffer lies between entropy decoding and inverse-DCT steps. - - In buffered-image mode, this controller is the interface between - input-oriented processing and output-oriented processing. - Also, the input side (only) is used when reading a file for transcoding. } - -{ Original: jdcoefct.c ; Copyright (C) 1994-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjutils, - imjpeglib; - -{GLOBAL} -procedure jinit_d_coef_controller (cinfo : j_decompress_ptr; - need_full_buffer : boolean); - - -implementation - - -{ Block smoothing is only applicable for progressive JPEG, so: } -{$ifndef D_PROGRESSIVE_SUPPORTED} -{$undef BLOCK_SMOOTHING_SUPPORTED} -{$endif} - -{ Private buffer controller object } - -{$ifdef BLOCK_SMOOTHING_SUPPORTED} -const - SAVED_COEFS = 6; { we save coef_bits[0..5] } -type - Latch = array[0..SAVED_COEFS-1] of int; - Latch_ptr = ^Latch; -{$endif} - -type - my_coef_ptr = ^my_coef_controller; - my_coef_controller = record - pub : jpeg_d_coef_controller; { public fields } - - { These variables keep track of the current location of the input side. } - { cinfo^.input_iMCU_row is also used for this. } - MCU_ctr : JDIMENSION; { counts MCUs processed in current row } - MCU_vert_offset : int; { counts MCU rows within iMCU row } - MCU_rows_per_iMCU_row : int; { number of such rows needed } - - { The output side's location is represented by cinfo^.output_iMCU_row. } - - { In single-pass modes, it's sufficient to buffer just one MCU. - We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, - and let the entropy decoder write into that workspace each time. - (On 80x86, the workspace is FAR even though it's not really very big; - this is to keep the module interfaces unchanged when a large coefficient - buffer is necessary.) - In multi-pass modes, this array points to the current MCU's blocks - within the virtual arrays; it is used only by the input side. } - - MCU_buffer : array[0..D_MAX_BLOCKS_IN_MCU-1] of JBLOCKROW; - - {$ifdef D_MULTISCAN_FILES_SUPPORTED} - { In multi-pass modes, we need a virtual block array for each component. } - whole_image : jvirt_barray_tbl; - {$endif} - - {$ifdef BLOCK_SMOOTHING_SUPPORTED} - { When doing block smoothing, we latch coefficient Al values here } - coef_bits_latch : Latch_Ptr; - {$endif} - end; - -{ Forward declarations } -{METHODDEF} -function decompress_onepass (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; forward; -{$ifdef D_MULTISCAN_FILES_SUPPORTED} -{METHODDEF} -function decompress_data (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; forward; -{$endif} -{$ifdef BLOCK_SMOOTHING_SUPPORTED} -{LOCAL} -function smoothing_ok (cinfo : j_decompress_ptr) : boolean; forward; - -{METHODDEF} -function decompress_smooth_data (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; forward; -{$endif} - - -{LOCAL} -procedure start_iMCU_row (cinfo : j_decompress_ptr); -{ Reset within-iMCU-row counters for a new row (input side) } -var - coef : my_coef_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - - { In an interleaved scan, an MCU row is the same as an iMCU row. - In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. - But at the bottom of the image, process only what's left. } - - if (cinfo^.comps_in_scan > 1) then - begin - coef^.MCU_rows_per_iMCU_row := 1; - end - else - begin - if (cinfo^.input_iMCU_row < (cinfo^.total_iMCU_rows-1)) then - coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.v_samp_factor - else - coef^.MCU_rows_per_iMCU_row := cinfo^.cur_comp_info[0]^.last_row_height; - end; - - coef^.MCU_ctr := 0; - coef^.MCU_vert_offset := 0; -end; - - -{ Initialize for an input processing pass. } - -{METHODDEF} -procedure start_input_pass (cinfo : j_decompress_ptr); -begin - cinfo^.input_iMCU_row := 0; - start_iMCU_row(cinfo); -end; - - -{ Initialize for an output processing pass. } - -{METHODDEF} -procedure start_output_pass (cinfo : j_decompress_ptr); -var - coef : my_coef_ptr; -begin -{$ifdef BLOCK_SMOOTHING_SUPPORTED} - coef := my_coef_ptr (cinfo^.coef); - - { If multipass, check to see whether to use block smoothing on this pass } - if (coef^.pub.coef_arrays <> NIL) then - begin - if (cinfo^.do_block_smoothing) and smoothing_ok(cinfo) then - coef^.pub.decompress_data := decompress_smooth_data - else - coef^.pub.decompress_data := decompress_data; - end; -{$endif} - cinfo^.output_iMCU_row := 0; -end; - - -{ Decompress and return some data in the single-pass case. - Always attempts to emit one fully interleaved MCU row ("iMCU" row). - Input and output must run in lockstep since we have only a one-MCU buffer. - Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - - NB: output_buf contains a plane for each component in image, - which we index according to the component's SOF position.} - -{METHODDEF} -function decompress_onepass (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; -var - coef : my_coef_ptr; - MCU_col_num : JDIMENSION; { index of current MCU within row } - last_MCU_col : JDIMENSION; - last_iMCU_row : JDIMENSION; - blkn, ci, xindex, yindex, yoffset, useful_width : int; - output_ptr : JSAMPARRAY; - start_col, output_col : JDIMENSION; - compptr : jpeg_component_info_ptr; - inverse_DCT : inverse_DCT_method_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - last_MCU_col := cinfo^.MCUs_per_row - 1; - last_iMCU_row := cinfo^.total_iMCU_rows - 1; - - { Loop to process as much as one whole iMCU row } - for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do - begin - for MCU_col_num := coef^.MCU_ctr to last_MCU_col do - begin - { Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. } - jzero_far( coef^.MCU_buffer[0], - size_t (cinfo^.blocks_in_MCU * SIZEOF(JBLOCK))); - if (not cinfo^.entropy^.decode_mcu (cinfo, coef^.MCU_buffer)) then - begin - { Suspension forced; update state counters and exit } - coef^.MCU_vert_offset := yoffset; - coef^.MCU_ctr := MCU_col_num; - decompress_onepass := JPEG_SUSPENDED; - exit; - end; - { Determine where data should go in output_buf and do the IDCT thing. - We skip dummy blocks at the right and bottom edges (but blkn gets - incremented past them!). Note the inner loop relies on having - allocated the MCU_buffer[] blocks sequentially. } - - blkn := 0; { index of current DCT block within MCU } - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - { Don't bother to IDCT an uninteresting component. } - if (not compptr^.component_needed) then - begin - Inc(blkn, compptr^.MCU_blocks); - continue; - end; - inverse_DCT := cinfo^.idct^.inverse_DCT[compptr^.component_index]; - if (MCU_col_num < last_MCU_col) then - useful_width := compptr^.MCU_width - else - useful_width := compptr^.last_col_width; - - output_ptr := JSAMPARRAY(@ output_buf^[compptr^.component_index]^ - [yoffset * compptr^.DCT_scaled_size]); - start_col := LongInt(MCU_col_num) * compptr^.MCU_sample_width; - for yindex := 0 to pred(compptr^.MCU_height) do - begin - if (cinfo^.input_iMCU_row < last_iMCU_row) or - (yoffset+yindex < compptr^.last_row_height) then - begin - output_col := start_col; - for xindex := 0 to pred(useful_width) do - begin - inverse_DCT (cinfo, compptr, - JCOEFPTR(coef^.MCU_buffer[blkn+xindex]), - output_ptr, output_col); - Inc(output_col, compptr^.DCT_scaled_size); - end; - end; - Inc(blkn, compptr^.MCU_width); - Inc(JSAMPROW_PTR(output_ptr), compptr^.DCT_scaled_size); - end; - end; - end; - { Completed an MCU row, but perhaps not an iMCU row } - coef^.MCU_ctr := 0; - end; - { Completed the iMCU row, advance counters for next one } - Inc(cinfo^.output_iMCU_row); - - Inc(cinfo^.input_iMCU_row); - if (cinfo^.input_iMCU_row < cinfo^.total_iMCU_rows) then - begin - start_iMCU_row(cinfo); - decompress_onepass := JPEG_ROW_COMPLETED; - exit; - end; - { Completed the scan } - cinfo^.inputctl^.finish_input_pass (cinfo); - decompress_onepass := JPEG_SCAN_COMPLETED; -end; - -{ Dummy consume-input routine for single-pass operation. } - -{METHODDEF} -function dummy_consume_data (cinfo : j_decompress_ptr) : int; -begin - dummy_consume_data := JPEG_SUSPENDED; { Always indicate nothing was done } -end; - - -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - -{ Consume input data and store it in the full-image coefficient buffer. - We read as much as one fully interleaved MCU row ("iMCU" row) per call, - ie, v_samp_factor block rows for each component in the scan. - Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.} - -{METHODDEF} -function consume_data (cinfo : j_decompress_ptr) : int; -var - coef : my_coef_ptr; - MCU_col_num : JDIMENSION; { index of current MCU within row } - blkn, ci, xindex, yindex, yoffset : int; - start_col : JDIMENSION; - buffer : array[0..MAX_COMPS_IN_SCAN-1] of JBLOCKARRAY; - buffer_ptr : JBLOCKROW; - compptr : jpeg_component_info_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - - { Align the virtual buffers for the components used in this scan. } - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - buffer[ci] := cinfo^.mem^.access_virt_barray - (j_common_ptr (cinfo), coef^.whole_image[compptr^.component_index], - LongInt(cinfo^.input_iMCU_row) * compptr^.v_samp_factor, - JDIMENSION (compptr^.v_samp_factor), TRUE); - { Note: entropy decoder expects buffer to be zeroed, - but this is handled automatically by the memory manager - because we requested a pre-zeroed array. } - - end; - - { Loop to process one whole iMCU row } - for yoffset := coef^.MCU_vert_offset to pred(coef^.MCU_rows_per_iMCU_row) do - begin - for MCU_col_num := coef^.MCU_ctr to pred(cinfo^.MCUs_per_row) do - begin - { Construct list of pointers to DCT blocks belonging to this MCU } - blkn := 0; { index of current DCT block within MCU } - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - start_col := LongInt(MCU_col_num) * compptr^.MCU_width; - for yindex := 0 to pred(compptr^.MCU_height) do - begin - buffer_ptr := JBLOCKROW(@ buffer[ci]^[yindex+yoffset]^[start_col]); - for xindex := 0 to pred(compptr^.MCU_width) do - begin - coef^.MCU_buffer[blkn] := buffer_ptr; - Inc(blkn); - Inc(JBLOCK_PTR(buffer_ptr)); - end; - end; - end; - { Try to fetch the MCU. } - if (not cinfo^.entropy^.decode_mcu (cinfo, coef^.MCU_buffer)) then - begin - { Suspension forced; update state counters and exit } - coef^.MCU_vert_offset := yoffset; - coef^.MCU_ctr := MCU_col_num; - consume_data := JPEG_SUSPENDED; - exit; - end; - end; - { Completed an MCU row, but perhaps not an iMCU row } - coef^.MCU_ctr := 0; - end; - { Completed the iMCU row, advance counters for next one } - Inc(cinfo^.input_iMCU_row); - if (cinfo^.input_iMCU_row < cinfo^.total_iMCU_rows) then - begin - start_iMCU_row(cinfo); - consume_data := JPEG_ROW_COMPLETED; - exit; - end; - { Completed the scan } - cinfo^.inputctl^.finish_input_pass (cinfo); - consume_data := JPEG_SCAN_COMPLETED; -end; - - -{ Decompress and return some data in the multi-pass case. - Always attempts to emit one fully interleaved MCU row ("iMCU" row). - Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. - - NB: output_buf contains a plane for each component in image. } - -{METHODDEF} -function decompress_data (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; -var - coef : my_coef_ptr; - last_iMCU_row : JDIMENSION; - block_num : JDIMENSION; - ci, block_row, block_rows : int; - buffer : JBLOCKARRAY; - buffer_ptr : JBLOCKROW; - output_ptr : JSAMPARRAY; - output_col : JDIMENSION; - compptr : jpeg_component_info_ptr; - inverse_DCT : inverse_DCT_method_ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - last_iMCU_row := cinfo^.total_iMCU_rows - 1; - - { Force some input to be done if we are getting ahead of the input. } - while (cinfo^.input_scan_number < cinfo^.output_scan_number) or - ((cinfo^.input_scan_number = cinfo^.output_scan_number) and - (LongInt(cinfo^.input_iMCU_row) <= cinfo^.output_iMCU_row)) do - begin - if (cinfo^.inputctl^.consume_input(cinfo) = JPEG_SUSPENDED) then - begin - decompress_data := JPEG_SUSPENDED; - exit; - end; - end; - - { OK, output from the virtual arrays. } - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Don't bother to IDCT an uninteresting component. } - if (not compptr^.component_needed) then - continue; - { Align the virtual buffer for this component. } - buffer := cinfo^.mem^.access_virt_barray - (j_common_ptr (cinfo), coef^.whole_image[ci], - cinfo^.output_iMCU_row * compptr^.v_samp_factor, - JDIMENSION (compptr^.v_samp_factor), FALSE); - { Count non-dummy DCT block rows in this iMCU row. } - if (cinfo^.output_iMCU_row < LongInt(last_iMCU_row)) then - block_rows := compptr^.v_samp_factor - else - begin - { NB: can't use last_row_height here; it is input-side-dependent! } - block_rows := int(LongInt(compptr^.height_in_blocks) mod compptr^.v_samp_factor); - if (block_rows = 0) then - block_rows := compptr^.v_samp_factor; - end; - inverse_DCT := cinfo^.idct^.inverse_DCT[ci]; - output_ptr := output_buf^[ci]; - { Loop over all DCT blocks to be processed. } - for block_row := 0 to pred(block_rows) do - begin - buffer_ptr := buffer^[block_row]; - output_col := 0; - for block_num := 0 to pred(compptr^.width_in_blocks) do - begin - inverse_DCT (cinfo, compptr, JCOEFPTR (buffer_ptr), - output_ptr, output_col); - Inc(JBLOCK_PTR(buffer_ptr)); - Inc(output_col, compptr^.DCT_scaled_size); - end; - Inc(JSAMPROW_PTR(output_ptr), compptr^.DCT_scaled_size); - end; - Inc(compptr); - end; - - Inc(cinfo^.output_iMCU_row); - if (cinfo^.output_iMCU_row < LongInt(cinfo^.total_iMCU_rows)) then - begin - decompress_data := JPEG_ROW_COMPLETED; - exit; - end; - decompress_data := JPEG_SCAN_COMPLETED; -end; - -{$endif} { D_MULTISCAN_FILES_SUPPORTED } - - -{$ifdef BLOCK_SMOOTHING_SUPPORTED} - -{ This code applies interblock smoothing as described by section K.8 - of the JPEG standard: the first 5 AC coefficients are estimated from - the DC values of a DCT block and its 8 neighboring blocks. - We apply smoothing only for progressive JPEG decoding, and only if - the coefficients it can estimate are not yet known to full precision. } - -{ Natural-order array positions of the first 5 zigzag-order coefficients } -const - Q01_POS = 1; - Q10_POS = 8; - Q20_POS = 16; - Q11_POS = 9; - Q02_POS = 2; - -{ Determine whether block smoothing is applicable and safe. - We also latch the current states of the coef_bits[] entries for the - AC coefficients; otherwise, if the input side of the decompressor - advances into a new scan, we might think the coefficients are known - more accurately than they really are. } - -{LOCAL} -function smoothing_ok (cinfo : j_decompress_ptr) : boolean; -var - coef : my_coef_ptr; - smoothing_useful : boolean; - ci, coefi : int; - compptr : jpeg_component_info_ptr; - qtable : JQUANT_TBL_PTR; - coef_bits : coef_bits_ptr; - coef_bits_latch : Latch_Ptr; -begin - coef := my_coef_ptr (cinfo^.coef); - smoothing_useful := FALSE; - - if (not cinfo^.progressive_mode) or (cinfo^.coef_bits = NIL) then - begin - smoothing_ok := FALSE; - exit; - end; - - { Allocate latch area if not already done } - if (coef^.coef_bits_latch = NIL) then - coef^.coef_bits_latch := Latch_Ptr( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - cinfo^.num_components * - (SAVED_COEFS * SIZEOF(int))) ); - coef_bits_latch := (coef^.coef_bits_latch); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { All components' quantization values must already be latched. } - qtable := compptr^.quant_table; - if (qtable = NIL) then - begin - smoothing_ok := FALSE; - exit; - end; - { Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. } - if (qtable^.quantval[0] = 0) or - (qtable^.quantval[Q01_POS] = 0) or - (qtable^.quantval[Q10_POS] = 0) or - (qtable^.quantval[Q20_POS] = 0) or - (qtable^.quantval[Q11_POS] = 0) or - (qtable^.quantval[Q02_POS] = 0) then - begin - smoothing_ok := FALSE; - exit; - end; - { DC values must be at least partly known for all components. } - coef_bits := @cinfo^.coef_bits^[ci]; { Nomssi } - if (coef_bits^[0] < 0) then - begin - smoothing_ok := FALSE; - exit; - end; - { Block smoothing is helpful if some AC coefficients remain inaccurate. } - for coefi := 1 to 5 do - begin - coef_bits_latch^[coefi] := coef_bits^[coefi]; - if (coef_bits^[coefi] <> 0) then - smoothing_useful := TRUE; - end; - Inc(coef_bits_latch {SAVED_COEFS}); - Inc(compptr); - end; - - smoothing_ok := smoothing_useful; -end; - - -{ Variant of decompress_data for use when doing block smoothing. } - -{METHODDEF} -function decompress_smooth_data (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; -var - coef : my_coef_ptr; - last_iMCU_row : JDIMENSION; - block_num, last_block_column : JDIMENSION; - ci, block_row, block_rows, access_rows : int; - buffer : JBLOCKARRAY; - buffer_ptr, prev_block_row, next_block_row : JBLOCKROW; - output_ptr : JSAMPARRAY; - output_col : JDIMENSION; - compptr : jpeg_component_info_ptr; - inverse_DCT : inverse_DCT_method_ptr; - first_row, last_row : boolean; - workspace : JBLOCK; - coef_bits : Latch_Ptr; { coef_bits_ptr; } - quanttbl : JQUANT_TBL_PTR; - Q00,Q01,Q02,Q10,Q11,Q20, num : INT32; - DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9 : int; - Al, pred : int; -var - delta : JDIMENSION; -begin - coef := my_coef_ptr (cinfo^.coef); - last_iMCU_row := cinfo^.total_iMCU_rows - 1; - - { Force some input to be done if we are getting ahead of the input. } - while (cinfo^.input_scan_number <= cinfo^.output_scan_number) and - (not cinfo^.inputctl^.eoi_reached) do - begin - if (cinfo^.input_scan_number = cinfo^.output_scan_number) then - begin - { If input is working on current scan, we ordinarily want it to - have completed the current row. But if input scan is DC, - we want it to keep one row ahead so that next block row's DC - values are up to date. } - - if (cinfo^.Ss = 0) then - delta := 1 - else - delta := 0; - if (LongInt(cinfo^.input_iMCU_row) > cinfo^.output_iMCU_row+LongInt(delta)) then - break; - end; - if (cinfo^.inputctl^.consume_input(cinfo) = JPEG_SUSPENDED) then - begin - decompress_smooth_data := JPEG_SUSPENDED; - exit; - end; - end; - - { OK, output from the virtual arrays. } - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to (cinfo^.num_components-1) do - begin - { Don't bother to IDCT an uninteresting component. } - if (not compptr^.component_needed) then - continue; - { Count non-dummy DCT block rows in this iMCU row. } - if (cinfo^.output_iMCU_row < LongInt(last_iMCU_row)) then - begin - block_rows := compptr^.v_samp_factor; - access_rows := block_rows * 2; { this and next iMCU row } - last_row := FALSE; - end - else - begin - { NB: can't use last_row_height here; it is input-side-dependent! } - block_rows := int (compptr^.height_in_blocks) mod compptr^.v_samp_factor; - if (block_rows = 0) then - block_rows := compptr^.v_samp_factor; - access_rows := block_rows; { this iMCU row only } - last_row := TRUE; - end; - { Align the virtual buffer for this component. } - if (cinfo^.output_iMCU_row > 0) then - begin - Inc(access_rows, compptr^.v_samp_factor); { prior iMCU row too } - buffer := cinfo^.mem^.access_virt_barray - (j_common_ptr (cinfo), coef^.whole_image[ci], - (cinfo^.output_iMCU_row - 1) * compptr^.v_samp_factor, - JDIMENSION (access_rows), FALSE); - Inc(JBLOCKROW_PTR(buffer), compptr^.v_samp_factor); { point to current iMCU row } - first_row := FALSE; - end - else - begin - buffer := cinfo^.mem^.access_virt_barray - (j_common_ptr (cinfo), coef^.whole_image[ci], - JDIMENSION (0), JDIMENSION (access_rows), FALSE); - first_row := TRUE; - end; - { Fetch component-dependent info } - coef_bits := coef^.coef_bits_latch; - Inc(coef_bits, ci); { ci * SAVED_COEFS} - quanttbl := compptr^.quant_table; - Q00 := quanttbl^.quantval[0]; - Q01 := quanttbl^.quantval[Q01_POS]; - Q10 := quanttbl^.quantval[Q10_POS]; - Q20 := quanttbl^.quantval[Q20_POS]; - Q11 := quanttbl^.quantval[Q11_POS]; - Q02 := quanttbl^.quantval[Q02_POS]; - inverse_DCT := cinfo^.idct^.inverse_DCT[ci]; - output_ptr := output_buf^[ci]; - { Loop over all DCT blocks to be processed. } - for block_row := 0 to (block_rows-1) do - begin - buffer_ptr := buffer^[block_row]; - if (first_row) and (block_row = 0) then - prev_block_row := buffer_ptr - else - prev_block_row := buffer^[block_row-1]; - if (last_row) and (block_row = block_rows-1) then - next_block_row := buffer_ptr - else - next_block_row := buffer^[block_row+1]; - { We fetch the surrounding DC values using a sliding-register approach. - Initialize all nine here so as to do the right thing on narrow pics.} - - DC3 := int(prev_block_row^[0][0]); - DC2 := DC3; - DC1 := DC2; - DC6 := int(buffer_ptr^[0][0]); - DC5 := DC6; - DC4 := DC5; - DC9 := int(next_block_row^[0][0]); - DC8 := DC9; - DC7 := DC8 ; - output_col := 0; - last_block_column := compptr^.width_in_blocks - 1; - for block_num := 0 to last_block_column do - begin - { Fetch current DCT block into workspace so we can modify it. } - jcopy_block_row(buffer_ptr, JBLOCKROW (@workspace), JDIMENSION(1)); - { Update DC values } - if (block_num < last_block_column) then - begin - DC3 := int (prev_block_row^[1][0]); - DC6 := int (buffer_ptr^[1][0]); - DC9 := int (next_block_row^[1][0]); - end; - { Compute coefficient estimates per K.8. - An estimate is applied only if coefficient is still zero, - and is not known to be fully accurate. } - - { AC01 } - Al := coef_bits^[1]; - if (Al <> 0) and (workspace[1] = 0) then - begin - num := 36 * Q00 * (DC4 - DC6); - if (num >= 0) then - begin - pred := int (((Q01 shl 7) + num) div (Q01 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - end - else - begin - pred := int (((Q01 shl 7) - num) div (Q01 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - pred := -pred; - end; - workspace[1] := JCOEF (pred); - end; - { AC10 } - Al := coef_bits^[2]; - if (Al <> 0) and (workspace[8] = 0) then - begin - num := 36 * Q00 * (DC2 - DC8); - if (num >= 0) then - begin - pred := int (((Q10 shl 7) + num) div (Q10 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - end - else - begin - pred := int (((Q10 shl 7) - num) div (Q10 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - pred := -pred; - end; - workspace[8] := JCOEF (pred); - end; - { AC20 } - Al := coef_bits^[3]; - if (Al <> 0) and (workspace[16] = 0) then - begin - num := 9 * Q00 * (DC2 + DC8 - 2*DC5); - if (num >= 0) then - begin - pred := int (((Q20 shl 7) + num) div (Q20 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - end - else - begin - pred := int (((Q20 shl 7) - num) div (Q20 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - pred := -pred; - end; - workspace[16] := JCOEF (pred); - end; - { AC11 } - Al := coef_bits^[4]; - if (Al <> 0) and (workspace[9] = 0) then - begin - num := 5 * Q00 * (DC1 - DC3 - DC7 + DC9); - if (num >= 0) then - begin - pred := int (((Q11 shl 7) + num) div (Q11 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - end - else - begin - pred := int (((Q11 shl 7) - num) div (Q11 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - pred := -pred; - end; - workspace[9] := JCOEF (pred); - end; - { AC02 } - Al := coef_bits^[5]; - if (Al <> 0) and (workspace[2] = 0) then - begin - num := 9 * Q00 * (DC4 + DC6 - 2*DC5); - if (num >= 0) then - begin - pred := int (((Q02 shl 7) + num) div (Q02 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - end - else - begin - pred := int (((Q02 shl 7) - num) div (Q02 shl 8)); - if (Al > 0) and (pred >= (1 shl Al)) then - pred := (1 shl Al)-1; - pred := -pred; - end; - workspace[2] := JCOEF (pred); - end; - { OK, do the IDCT } - inverse_DCT (cinfo, compptr, JCOEFPTR (@workspace), - output_ptr, output_col); - { Advance for next column } - DC1 := DC2; DC2 := DC3; - DC4 := DC5; DC5 := DC6; - DC7 := DC8; DC8 := DC9; - Inc(JBLOCK_PTR(buffer_ptr)); - Inc(JBLOCK_PTR(prev_block_row)); - Inc(JBLOCK_PTR(next_block_row)); - Inc(output_col, compptr^.DCT_scaled_size); - end; - Inc(JSAMPROW_PTR(output_ptr), compptr^.DCT_scaled_size); - end; - Inc(compptr); - end; - - Inc(cinfo^.output_iMCU_row); - if (cinfo^.output_iMCU_row < LongInt(cinfo^.total_iMCU_rows)) then - begin - decompress_smooth_data := JPEG_ROW_COMPLETED; - exit; - end; - decompress_smooth_data := JPEG_SCAN_COMPLETED; -end; - -{$endif} { BLOCK_SMOOTHING_SUPPORTED } - - -{ Initialize coefficient buffer controller. } - -{GLOBAL} -procedure jinit_d_coef_controller (cinfo : j_decompress_ptr; - need_full_buffer : boolean); -var - coef : my_coef_ptr; -{$ifdef D_MULTISCAN_FILES_SUPPORTED} -var - ci, access_rows : int; - compptr : jpeg_component_info_ptr; -{$endif} -var - buffer : JBLOCK_PTR; - i : int; -begin - coef := my_coef_ptr( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - SIZEOF(my_coef_controller)) ); - cinfo^.coef := jpeg_d_coef_controller_ptr(coef); - coef^.pub.start_input_pass := start_input_pass; - coef^.pub.start_output_pass := start_output_pass; -{$ifdef BLOCK_SMOOTHING_SUPPORTED} - coef^.coef_bits_latch := NIL; -{$endif} - - { Create the coefficient buffer. } - if (need_full_buffer) then - begin -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - { Allocate a full-image virtual array for each component, } - { padded to a multiple of samp_factor DCT blocks in each direction. } - { Note we ask for a pre-zeroed array. } - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - access_rows := compptr^.v_samp_factor; -{$ifdef BLOCK_SMOOTHING_SUPPORTED} - { If block smoothing could be used, need a bigger window } - if (cinfo^.progressive_mode) then - access_rows := access_rows * 3; -{$endif} - coef^.whole_image[ci] := cinfo^.mem^.request_virt_barray - (j_common_ptr (cinfo), JPOOL_IMAGE, TRUE, - JDIMENSION (jround_up( long(compptr^.width_in_blocks), - long(compptr^.h_samp_factor) )), - JDIMENSION (jround_up( long(compptr^.height_in_blocks), - long(compptr^.v_samp_factor) )), - JDIMENSION (access_rows)); - Inc(compptr); - end; - coef^.pub.consume_data := consume_data; - coef^.pub.decompress_data := decompress_data; - coef^.pub.coef_arrays := @(coef^.whole_image); - { link to virtual arrays } -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - begin - { We only need a single-MCU buffer. } - buffer := JBLOCK_PTR ( - cinfo^.mem^.alloc_large (j_common_ptr (cinfo), JPOOL_IMAGE, - D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)) ); - for i := 0 to pred(D_MAX_BLOCKS_IN_MCU) do - begin - coef^.MCU_buffer[i] := JBLOCKROW(buffer); - Inc(buffer); - end; - coef^.pub.consume_data := dummy_consume_data; - coef^.pub.decompress_data := decompress_onepass; - coef^.pub.coef_arrays := NIL; { flag for no virtual arrays } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdcolor.pas b/3rd/Imaging/Source/JpegLib/imjdcolor.pas deleted file mode 100644 index 64c5f41df..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdcolor.pas +++ /dev/null @@ -1,501 +0,0 @@ -unit imjdcolor; - -{ This file contains output colorspace conversion routines. } - -{ Original: jdcolor.c ; Copyright (C) 1991-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjutils, - imjdeferr, - imjerror, - imjpeglib; - -{ Module initialization routine for output colorspace conversion. } - -{GLOBAL} -procedure jinit_color_deconverter (cinfo : j_decompress_ptr); - -implementation - -{ Private subobject } -type - int_Color_Table = array[0..MAXJSAMPLE+1-1] of int; - int_table_ptr = ^int_Color_Table; - INT32_Color_Table = array[0..MAXJSAMPLE+1-1] of INT32; - INT32_table_ptr = ^INT32_Color_Table; -type - my_cconvert_ptr = ^my_color_deconverter; - my_color_deconverter = record - pub : jpeg_color_deconverter; { public fields } - - { Private state for YCC^.RGB conversion } - Cr_r_tab : int_table_ptr; { => table for Cr to R conversion } - Cb_b_tab : int_table_ptr; { => table for Cb to B conversion } - Cr_g_tab : INT32_table_ptr; { => table for Cr to G conversion } - Cb_g_tab : INT32_table_ptr; { => table for Cb to G conversion } - end; - - - - -{*************** YCbCr ^. RGB conversion: most common case *************} - -{ YCbCr is defined per CCIR 601-1, except that Cb and Cr are - normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. - The conversion equations to be implemented are therefore - R = Y + 1.40200 * Cr - G = Y - 0.34414 * Cb - 0.71414 * Cr - B = Y + 1.77200 * Cb - where Cb and Cr represent the incoming values less CENTERJSAMPLE. - (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) - - To avoid floating-point arithmetic, we represent the fractional constants - as integers scaled up by 2^16 (about 4 digits precision); we have to divide - the products by 2^16, with appropriate rounding, to get the correct answer. - Notice that Y, being an integral input, does not contribute any fraction - so it need not participate in the rounding. - - For even more speed, we avoid doing any multiplications in the inner loop - by precalculating the constants times Cb and Cr for all possible values. - For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); - for 12-bit samples it is still acceptable. It's not very reasonable for - 16-bit samples, but if you want lossless storage you shouldn't be changing - colorspace anyway. - The Cr=>R and Cb=>B values can be rounded to integers in advance; the - values for the G calculation are left scaled up, since we must add them - together before rounding. } - -const - SCALEBITS = 16; { speediest right-shift on some machines } - ONE_HALF = (INT32(1) shl (SCALEBITS-1)); - - -{ Initialize tables for YCC->RGB colorspace conversion. } - -{LOCAL} -procedure build_ycc_rgb_table (cinfo : j_decompress_ptr); -const - FIX_1_40200 = INT32(Round( 1.40200 * (1 shl SCALEBITS))); - FIX_1_77200 = INT32(Round( 1.77200 * (1 shl SCALEBITS))); - FIX_0_71414 = INT32(Round( 0.71414 * (1 shl SCALEBITS))); - FIX_0_34414 = INT32(Round( 0.34414 * (1 shl SCALEBITS))); - -var - cconvert : my_cconvert_ptr; - i : int; - x : INT32; -var - shift_temp : INT32; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - - - cconvert^.Cr_r_tab := int_table_ptr( - cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)) ); - cconvert^.Cb_b_tab := int_table_ptr ( - cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)) ); - cconvert^.Cr_g_tab := INT32_table_ptr ( - cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)) ); - cconvert^.Cb_g_tab := INT32_table_ptr ( - cinfo^.mem^.alloc_small ( j_common_ptr(cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)) ); - - - x := -CENTERJSAMPLE; - for i := 0 to MAXJSAMPLE do - begin - { i is the actual input pixel value, in the range 0..MAXJSAMPLE } - { The Cb or Cr value we are thinking of is x := i - CENTERJSAMPLE } - { Cr=>R value is nearest int to 1.40200 * x } - - shift_temp := FIX_1_40200 * x + ONE_HALF; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - cconvert^.Cr_r_tab^[i] := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - cconvert^.Cr_r_tab^[i] := int(shift_temp shr SCALEBITS); - - { Cb=>B value is nearest int to 1.77200 * x } - shift_temp := FIX_1_77200 * x + ONE_HALF; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - cconvert^.Cb_b_tab^[i] := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - cconvert^.Cb_b_tab^[i] := int(shift_temp shr SCALEBITS); - - { Cr=>G value is scaled-up -0.71414 * x } - cconvert^.Cr_g_tab^[i] := (- FIX_0_71414 ) * x; - { Cb=>G value is scaled-up -0.34414 * x } - { We also add in ONE_HALF so that need not do it in inner loop } - cconvert^.Cb_g_tab^[i] := (- FIX_0_34414 ) * x + ONE_HALF; - Inc(x); - end; -end; - - -{ Convert some rows of samples to the output colorspace. - - Note that we change from noninterleaved, one-plane-per-component format - to interleaved-pixel format. The output buffer is therefore three times - as wide as the input buffer. - A starting row offset is provided only for the input buffer. The caller - can easily adjust the passed output_buf value to accommodate any row - offset required on that side. } - -{METHODDEF} -procedure ycc_rgb_convert (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - input_row : JDIMENSION; - output_buf : JSAMPARRAY; - num_rows : int); -var - cconvert : my_cconvert_ptr; - {register} y, cb, cr : int; - {register} outptr : JSAMPROW; - {register} inptr0, inptr1, inptr2 : JSAMPROW; - {register} col : JDIMENSION; - num_cols : JDIMENSION; - { copy these pointers into registers if possible } - {register} range_limit : range_limit_table_ptr; - {register} Crrtab : int_table_ptr; - {register} Cbbtab : int_table_ptr; - {register} Crgtab : INT32_table_ptr; - {register} Cbgtab : INT32_table_ptr; -var - shift_temp : INT32; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - num_cols := cinfo^.output_width; - range_limit := cinfo^.sample_range_limit; - Crrtab := cconvert^.Cr_r_tab; - Cbbtab := cconvert^.Cb_b_tab; - Crgtab := cconvert^.Cr_g_tab; - Cbgtab := cconvert^.Cb_g_tab; - - while (num_rows > 0) do - begin - Dec(num_rows); - inptr0 := input_buf^[0]^[input_row]; - inptr1 := input_buf^[1]^[input_row]; - inptr2 := input_buf^[2]^[input_row]; - Inc(input_row); - outptr := output_buf^[0]; - Inc(JSAMPROW_PTR(output_buf)); - for col := 0 to pred(num_cols) do - begin - y := GETJSAMPLE(inptr0^[col]); - cb := GETJSAMPLE(inptr1^[col]); - cr := GETJSAMPLE(inptr2^[col]); - { Range-limiting is essential due to noise introduced by DCT losses. } - outptr^[RGB_RED] := range_limit^[y + Crrtab^[cr]]; - shift_temp := Cbgtab^[cb] + Crgtab^[cr]; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - outptr^[RGB_GREEN] := range_limit^[y + int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS)))] - else - outptr^[RGB_GREEN] := range_limit^[y + int(shift_temp shr SCALEBITS)]; - - outptr^[RGB_BLUE] := range_limit^[y + Cbbtab^[cb]]; - Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE); - end; - end; -end; - - -{*************** Cases other than YCbCr -> RGB *************} - - -{ Color conversion for no colorspace change: just copy the data, - converting from separate-planes to interleaved representation. } - -{METHODDEF} -procedure null_convert (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - input_row : JDIMENSION; - output_buf : JSAMPARRAY; - num_rows : int); -var - {register} inptr, - outptr : JSAMPLE_PTR; - {register} count : JDIMENSION; - {register} num_components : int; - num_cols : JDIMENSION; - ci : int; -begin - num_components := cinfo^.num_components; - num_cols := cinfo^.output_width; - - while (num_rows > 0) do - begin - Dec(num_rows); - for ci := 0 to pred(num_components) do - begin - inptr := JSAMPLE_PTR(input_buf^[ci]^[input_row]); - outptr := JSAMPLE_PTR(@(output_buf^[0]^[ci])); - - for count := pred(num_cols) downto 0 do - begin - outptr^ := inptr^; { needn't bother with GETJSAMPLE() here } - Inc(inptr); - Inc(outptr, num_components); - end; - end; - Inc(input_row); - Inc(JSAMPROW_PTR(output_buf)); - end; -end; - - -{ Color conversion for grayscale: just copy the data. - This also works for YCbCr -> grayscale conversion, in which - we just copy the Y (luminance) component and ignore chrominance. } - -{METHODDEF} -procedure grayscale_convert (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - input_row : JDIMENSION; - output_buf : JSAMPARRAY; - num_rows : int); -begin - jcopy_sample_rows(input_buf^[0], int(input_row), output_buf, 0, - num_rows, cinfo^.output_width); -end; - -{ Convert grayscale to RGB: just duplicate the graylevel three times. - This is provided to support applications that don't want to cope - with grayscale as a separate case. } - -{METHODDEF} -procedure gray_rgb_convert (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - input_row : JDIMENSION; - output_buf : JSAMPARRAY; - num_rows : int); -var - {register} inptr, outptr : JSAMPLE_PTR; - {register} col : JDIMENSION; - num_cols : JDIMENSION; -begin - num_cols := cinfo^.output_width; - while (num_rows > 0) do - begin - inptr := JSAMPLE_PTR(input_buf^[0]^[input_row]); - Inc(input_row); - outptr := JSAMPLE_PTR(@output_buf^[0]); - Inc(JSAMPROW_PTR(output_buf)); - for col := 0 to pred(num_cols) do - begin - { We can dispense with GETJSAMPLE() here } - JSAMPROW(outptr)^[RGB_RED] := inptr^; - JSAMPROW(outptr)^[RGB_GREEN] := inptr^; - JSAMPROW(outptr)^[RGB_BLUE] := inptr^; - Inc(inptr); - Inc(outptr, RGB_PIXELSIZE); - end; - Dec(num_rows); - end; -end; - - -{ Adobe-style YCCK -> CMYK conversion. - We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same - conversion as above, while passing K (black) unchanged. - We assume build_ycc_rgb_table has been called. } - -{METHODDEF} -procedure ycck_cmyk_convert (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - input_row : JDIMENSION; - output_buf : JSAMPARRAY; - num_rows : int); -var - cconvert : my_cconvert_ptr; - {register} y, cb, cr : int; - {register} outptr : JSAMPROW; - {register} inptr0, inptr1, inptr2, inptr3 : JSAMPROW; - {register} col : JDIMENSION; - num_cols : JDIMENSION; - { copy these pointers into registers if possible } - {register} range_limit : range_limit_table_ptr; - {register} Crrtab : int_table_ptr; - {register} Cbbtab : int_table_ptr; - {register} Crgtab : INT32_table_ptr; - {register} Cbgtab : INT32_table_ptr; -var - shift_temp : INT32; -begin - cconvert := my_cconvert_ptr (cinfo^.cconvert); - num_cols := cinfo^.output_width; - { copy these pointers into registers if possible } - range_limit := cinfo^.sample_range_limit; - Crrtab := cconvert^.Cr_r_tab; - Cbbtab := cconvert^.Cb_b_tab; - Crgtab := cconvert^.Cr_g_tab; - Cbgtab := cconvert^.Cb_g_tab; - - while (num_rows > 0) do - begin - Dec(num_rows); - inptr0 := input_buf^[0]^[input_row]; - inptr1 := input_buf^[1]^[input_row]; - inptr2 := input_buf^[2]^[input_row]; - inptr3 := input_buf^[3]^[input_row]; - Inc(input_row); - outptr := output_buf^[0]; - Inc(JSAMPROW_PTR(output_buf)); - for col := 0 to pred(num_cols) do - begin - y := GETJSAMPLE(inptr0^[col]); - cb := GETJSAMPLE(inptr1^[col]); - cr := GETJSAMPLE(inptr2^[col]); - { Range-limiting is essential due to noise introduced by DCT losses. } - outptr^[0] := range_limit^[MAXJSAMPLE - (y + Crrtab^[cr])]; { red } - shift_temp := Cbgtab^[cb] + Crgtab^[cr]; - if shift_temp < 0 then - outptr^[1] := range_limit^[MAXJSAMPLE - (y + int( - (shift_temp shr SCALEBITS) or ((not INT32(0)) shl (32-SCALEBITS)) - ) )] - else - outptr^[1] := range_limit^[MAXJSAMPLE - { green } - (y + int(shift_temp shr SCALEBITS) )]; - outptr^[2] := range_limit^[MAXJSAMPLE - (y + Cbbtab^[cb])]; { blue } - { K passes through unchanged } - outptr^[3] := inptr3^[col]; { don't need GETJSAMPLE here } - Inc(JSAMPLE_PTR(outptr), 4); - end; - end; -end; - - -{ Empty method for start_pass. } - -{METHODDEF} -procedure start_pass_dcolor (cinfo : j_decompress_ptr); -begin - { no work needed } -end; - - -{ Module initialization routine for output colorspace conversion. } - -{GLOBAL} -procedure jinit_color_deconverter (cinfo : j_decompress_ptr); -var - cconvert : my_cconvert_ptr; - ci : int; -begin - cconvert := my_cconvert_ptr ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_color_deconverter)) ); - cinfo^.cconvert := jpeg_color_deconverter_ptr (cconvert); - cconvert^.pub.start_pass := start_pass_dcolor; - - { Make sure num_components agrees with jpeg_color_space } - case (cinfo^.jpeg_color_space) of - JCS_GRAYSCALE: - if (cinfo^.num_components <> 1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - - JCS_RGB, - JCS_YCbCr: - if (cinfo^.num_components <> 3) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - - JCS_CMYK, - JCS_YCCK: - if (cinfo^.num_components <> 4) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - - else { JCS_UNKNOWN can be anything } - if (cinfo^.num_components < 1) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE); - end; - - { Set out_color_components and conversion method based on requested space. - Also clear the component_needed flags for any unused components, - so that earlier pipeline stages can avoid useless computation. } - - case (cinfo^.out_color_space) of - JCS_GRAYSCALE: - begin - cinfo^.out_color_components := 1; - if (cinfo^.jpeg_color_space = JCS_GRAYSCALE) - or (cinfo^.jpeg_color_space = JCS_YCbCr) then - begin - cconvert^.pub.color_convert := grayscale_convert; - { For color -> grayscale conversion, only the - Y (0) component is needed } - for ci := 1 to pred(cinfo^.num_components) do - cinfo^.comp_info^[ci].component_needed := FALSE; - end - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - JCS_RGB: - begin - cinfo^.out_color_components := RGB_PIXELSIZE; - if (cinfo^.jpeg_color_space = JCS_YCbCr) then - begin - cconvert^.pub.color_convert := ycc_rgb_convert; - build_ycc_rgb_table(cinfo); - end - else - if (cinfo^.jpeg_color_space = JCS_GRAYSCALE) then - begin - cconvert^.pub.color_convert := gray_rgb_convert; - end - else - if (cinfo^.jpeg_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then - begin - cconvert^.pub.color_convert := null_convert; - end - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - JCS_CMYK: - begin - cinfo^.out_color_components := 4; - if (cinfo^.jpeg_color_space = JCS_YCCK) then - begin - cconvert^.pub.color_convert := ycck_cmyk_convert; - build_ycc_rgb_table(cinfo); - end - else - if (cinfo^.jpeg_color_space = JCS_CMYK) then - begin - cconvert^.pub.color_convert := null_convert; - end - else - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - - else - begin { Permit null conversion to same output space } - if (cinfo^.out_color_space = cinfo^.jpeg_color_space) then - begin - cinfo^.out_color_components := cinfo^.num_components; - cconvert^.pub.color_convert := null_convert; - end - else { unsupported non-null conversion } - ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL); - end; - end; - - if (cinfo^.quantize_colors) then - cinfo^.output_components := 1 { single colormapped output component } - else - cinfo^.output_components := cinfo^.out_color_components; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdct.pas b/3rd/Imaging/Source/JpegLib/imjdct.pas deleted file mode 100644 index 30d335672..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdct.pas +++ /dev/null @@ -1,109 +0,0 @@ -unit imjdct; - -{ Orignal: jdct.h; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This include file contains common declarations for the forward and - inverse DCT modules. These declarations are private to the DCT managers - (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. - The individual DCT algorithms are kept in separate files to ease - machine-dependent tuning (e.g., assembly coding). } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg; - - -{ A forward DCT routine is given a pointer to a work area of type DCTELEM[]; - the DCT is to be performed in-place in that buffer. Type DCTELEM is int - for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT - implementations use an array of type FAST_FLOAT, instead.) - The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). - The DCT outputs are returned scaled up by a factor of 8; they therefore - have a range of +-8K for 8-bit data, +-128K for 12-bit data. This - convention improves accuracy in integer implementations and saves some - work in floating-point ones. - Quantization of the output coefficients is done by jcdctmgr.c. } - - -{$ifdef BITS_IN_JSAMPLE_IS_8} -type - DCTELEM = int; { 16 or 32 bits is fine } -{$else} -type { must have 32 bits } - DCTELEM = INT32; -{$endif} -type - jTDctElem = 0..(MaxInt div SizeOf(DCTELEM))-1; - DCTELEM_FIELD = array[jTDctElem] of DCTELEM; - DCTELEM_FIELD_PTR = ^DCTELEM_FIELD; - DCTELEMPTR = ^DCTELEM; - -type - forward_DCT_method_ptr = procedure(var data : array of DCTELEM); - float_DCT_method_ptr = procedure(var data : array of FAST_FLOAT); - - -{ An inverse DCT routine is given a pointer to the input JBLOCK and a pointer - to an output sample array. The routine must dequantize the input data as - well as perform the IDCT; for dequantization, it uses the multiplier table - pointed to by compptr->dct_table. The output data is to be placed into the - sample array starting at a specified column. (Any row offset needed will - be applied to the array pointer before it is passed to the IDCT code.) - Note that the number of samples emitted by the IDCT routine is - DCT_scaled_size * DCT_scaled_size. } - - -{ typedef inverse_DCT_method_ptr is declared in jpegint.h } - - -{ Each IDCT routine has its own ideas about the best dct_table element type. } - - -type - ISLOW_MULT_TYPE = MULTIPLIER; { short or int, whichever is faster } - -{$ifdef BITS_IN_JSAMPLE_IS_8} -type - IFAST_MULT_TYPE = MULTIPLIER; { 16 bits is OK, use short if faster } -const - IFAST_SCALE_BITS = 2; { fractional bits in scale factors } -{$else} -type - IFAST_MULT_TYPE = INT32; { need 32 bits for scaled quantizers } -const - IFAST_SCALE_BITS = 13; { fractional bits in scale factors } -{$endif} -type - FLOAT_MULT_TYPE = FAST_FLOAT; { preferred floating type } - -const - RANGE_MASK = (MAXJSAMPLE * 4 + 3); { 2 bits wider than legal samples } - -type - jTMultType = 0..(MaxInt div SizeOf(ISLOW_MULT_TYPE))-1; - ISLOW_MULT_TYPE_FIELD = array[jTMultType] of ISLOW_MULT_TYPE; - ISLOW_MULT_TYPE_FIELD_PTR = ^ISLOW_MULT_TYPE_FIELD; - ISLOW_MULT_TYPE_PTR = ^ISLOW_MULT_TYPE; - - jTFloatType = 0..(MaxInt div SizeOf(FLOAT_MULT_TYPE))-1; - FLOAT_MULT_TYPE_FIELD = array[jTFloatType] of FLOAT_MULT_TYPE; - FLOAT_MULT_TYPE_FIELD_PTR = ^FLOAT_MULT_TYPE_FIELD; - FLOAT_MULT_TYPE_PTR = ^FLOAT_MULT_TYPE; - - jTFastType = 0..(MaxInt div SizeOf(IFAST_MULT_TYPE))-1; - IFAST_MULT_TYPE_FIELD = array[jTFastType] of IFAST_MULT_TYPE; - IFAST_MULT_TYPE_FIELD_PTR = ^IFAST_MULT_TYPE_FIELD; - IFAST_MULT_TYPE_PTR = ^IFAST_MULT_TYPE; - -type - jTFastFloat = 0..(MaxInt div SizeOf(FAST_FLOAT))-1; - FAST_FLOAT_FIELD = array[jTFastFloat] of FAST_FLOAT; - FAST_FLOAT_FIELD_PTR = ^FAST_FLOAT_FIELD; - FAST_FLOAT_PTR = ^FAST_FLOAT; - -implementation - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjddctmgr.pas b/3rd/Imaging/Source/JpegLib/imjddctmgr.pas deleted file mode 100644 index 5e62b3a3b..000000000 --- a/3rd/Imaging/Source/JpegLib/imjddctmgr.pas +++ /dev/null @@ -1,330 +0,0 @@ -unit imjddctmgr; - -{ Original : jddctmgr.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This file contains the inverse-DCT management logic. - This code selects a particular IDCT implementation to be used, - and it performs related housekeeping chores. No code in this file - is executed per IDCT step, only during output pass setup. - - Note that the IDCT routines are responsible for performing coefficient - dequantization as well as the IDCT proper. This module sets up the - dequantization multiplier table needed by the IDCT routine. } - -interface - -{$I imjconfig.inc} - -{$N+} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjdct, { Private declarations for DCT subsystem } - imjidctfst, - {$IFDEF BASM} - imjidctasm, - {$ELSE} - imjidctint, - {$ENDIF} - imjidctflt, - imjidctred; - - - -{ Initialize IDCT manager. } - -{GLOBAL} -procedure jinit_inverse_dct (cinfo : j_decompress_ptr); - - -implementation - -{ The decompressor input side (jdinput.c) saves away the appropriate - quantization table for each component at the start of the first scan - involving that component. (This is necessary in order to correctly - decode files that reuse Q-table slots.) - When we are ready to make an output pass, the saved Q-table is converted - to a multiplier table that will actually be used by the IDCT routine. - The multiplier table contents are IDCT-method-dependent. To support - application changes in IDCT method between scans, we can remake the - multiplier tables if necessary. - In buffered-image mode, the first output pass may occur before any data - has been seen for some components, and thus before their Q-tables have - been saved away. To handle this case, multiplier tables are preset - to zeroes; the result of the IDCT will be a neutral gray level. } - - -{ Private subobject for this module } - -type - my_idct_ptr = ^my_idct_controller; - my_idct_controller = record - pub : jpeg_inverse_dct; { public fields } - - { This array contains the IDCT method code that each multiplier table - is currently set up for, or -1 if it's not yet set up. - The actual multiplier tables are pointed to by dct_table in the - per-component comp_info structures. } - - cur_method : array[0..MAX_COMPONENTS-1] of int; - end; {my_idct_controller;} - - -{ Allocated multiplier tables: big enough for any supported variant } - -type - multiplier_table = record - case byte of - 0:(islow_array : array[0..DCTSIZE2-1] of ISLOW_MULT_TYPE); - {$ifdef DCT_IFAST_SUPPORTED} - 1:(ifast_array : array[0..DCTSIZE2-1] of IFAST_MULT_TYPE); - {$endif} - {$ifdef DCT_FLOAT_SUPPORTED} - 2:(float_array : array[0..DCTSIZE2-1] of FLOAT_MULT_TYPE); - {$endif} - end; - - -{ The current scaled-IDCT routines require ISLOW-style multiplier tables, - so be sure to compile that code if either ISLOW or SCALING is requested. } - -{$ifdef DCT_ISLOW_SUPPORTED} - {$define PROVIDE_ISLOW_TABLES} -{$else} - {$ifdef IDCT_SCALING_SUPPORTED} - {$define PROVIDE_ISLOW_TABLES} - {$endif} -{$endif} - - -{ Prepare for an output pass. - Here we select the proper IDCT routine for each component and build - a matching multiplier table. } - -{METHODDEF} -procedure start_pass (cinfo : j_decompress_ptr); -var - idct : my_idct_ptr; - ci, i : int; - compptr : jpeg_component_info_ptr; - method : J_DCT_METHOD; - method_ptr : inverse_DCT_method_ptr; - qtbl : JQUANT_TBL_PTR; -{$ifdef PROVIDE_ISLOW_TABLES} -var - ismtbl : ISLOW_MULT_TYPE_FIELD_PTR; -{$endif} -{$ifdef DCT_IFAST_SUPPORTED} -const - CONST_BITS = 14; -const - aanscales : array[0..DCTSIZE2-1] of INT16 = - ({ precomputed values scaled up by 14 bits } - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, - 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, - 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, - 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, - 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, - 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, - 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247); -var - ifmtbl : IFAST_MULT_TYPE_FIELD_PTR; - {SHIFT_TEMPS} - - { Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - - function DESCALE(x : INT32; n : int) : INT32; - var - shift_temp : INT32; - begin - {$ifdef RIGHT_SHIFT_IS_UNSIGNED} - shift_temp := x + (INT32(1) shl (n-1)); - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else - Descale := (shift_temp shr n); - {$else} - Descale := (x + (INT32(1) shl (n-1)) shr n; - {$endif} - end; - -{$endif} -{$ifdef DCT_FLOAT_SUPPORTED} -const - aanscalefactor : array[0..DCTSIZE-1] of double = - (1.0, 1.387039845, 1.306562965, 1.175875602, - 1.0, 0.785694958, 0.541196100, 0.275899379); -var - fmtbl : FLOAT_MULT_TYPE_FIELD_PTR; - row, col : int; -{$endif} -begin - idct := my_idct_ptr (cinfo^.idct); - method := J_DCT_METHOD(0); - method_ptr := NIL; - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - - for ci := 0 to pred(cinfo^.num_components) do - begin - { Select the proper IDCT routine for this component's scaling } - case (compptr^.DCT_scaled_size) of -{$ifdef IDCT_SCALING_SUPPORTED} - 1:begin - method_ptr := jpeg_idct_1x1; - method := JDCT_ISLOW; { jidctred uses islow-style table } - end; - 2:begin - method_ptr := jpeg_idct_2x2; - method := JDCT_ISLOW; { jidctred uses islow-style table } - end; - 4:begin - method_ptr := jpeg_idct_4x4; - method := JDCT_ISLOW; { jidctred uses islow-style table } - end; -{$endif} - DCTSIZE: - case (cinfo^.dct_method) of -{$ifdef DCT_ISLOW_SUPPORTED} - JDCT_ISLOW: - begin - method_ptr := @jpeg_idct_islow; - method := JDCT_ISLOW; - end; -{$endif} -{$ifdef DCT_IFAST_SUPPORTED} - JDCT_IFAST: - begin - method_ptr := @jpeg_idct_ifast; - method := JDCT_IFAST; - end; -{$endif} -{$ifdef DCT_FLOAT_SUPPORTED} - JDCT_FLOAT: - begin - method_ptr := @jpeg_idct_float; - method := JDCT_FLOAT; - end; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); - end; - else - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_DCTSIZE, compptr^.DCT_scaled_size); - end; - idct^.pub.inverse_DCT[ci] := method_ptr; - { Create multiplier table from quant table. - However, we can skip this if the component is uninteresting - or if we already built the table. Also, if no quant table - has yet been saved for the component, we leave the - multiplier table all-zero; we'll be reading zeroes from the - coefficient controller's buffer anyway. } - - if (not compptr^.component_needed) or (idct^.cur_method[ci] = int(method)) then - continue; - qtbl := compptr^.quant_table; - if (qtbl = NIL) then { happens if no data yet for component } - continue; - idct^.cur_method[ci] := int(method); - case (method) of -{$ifdef PROVIDE_ISLOW_TABLES} - JDCT_ISLOW: - begin - { For LL&M IDCT method, multipliers are equal to raw quantization - coefficients, but are stored as ints to ensure access efficiency. } - - ismtbl := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - for i := 0 to pred(DCTSIZE2) do - begin - ismtbl^[i] := ISLOW_MULT_TYPE (qtbl^.quantval[i]); - end; - end; -{$endif} -{$ifdef DCT_IFAST_SUPPORTED} - JDCT_IFAST: - begin - { For AA&N IDCT method, multipliers are equal to quantization - coefficients scaled by scalefactor[row]*scalefactor[col], where - scalefactor[0] := 1 - scalefactor[k] := cos(k*PI/16) * sqrt(2) for k=1..7 - For integer operation, the multiplier table is to be scaled by - IFAST_SCALE_BITS. } - - ifmtbl := IFAST_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - - for i := 0 to pred(DCTSIZE2) do - begin - ifmtbl^[i] := IFAST_MULT_TYPE( - DESCALE( INT32 (qtbl^.quantval[i]) * INT32 (aanscales[i]), - CONST_BITS-IFAST_SCALE_BITS) ); - end; - end; -{$endif} -{$ifdef DCT_FLOAT_SUPPORTED} - JDCT_FLOAT: - begin - { For float AA&N IDCT method, multipliers are equal to quantization - coefficients scaled by scalefactor[row]*scalefactor[col], where - scalefactor[0] := 1 - scalefactor[k] := cos(k*PI/16) * sqrt(2) for k=1..7 } - - fmtbl := FLOAT_MULT_TYPE_FIELD_PTR(compptr^.dct_table); - - i := 0; - for row := 0 to pred(DCTSIZE) do - begin - for col := 0 to pred(DCTSIZE) do - begin - fmtbl^[i] := {FLOAT_MULT_TYPE} ( - {double} qtbl^.quantval[i] * - aanscalefactor[row] * aanscalefactor[col] ); - Inc(i); - end; - end; - end; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); - break; - end; - Inc(compptr); - end; -end; - - -{ Initialize IDCT manager. } - -{GLOBAL} -procedure jinit_inverse_dct (cinfo : j_decompress_ptr); -var - idct : my_idct_ptr; - ci : int; - compptr : jpeg_component_info_ptr; -begin - idct := my_idct_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_idct_controller)) ); - cinfo^.idct := jpeg_inverse_dct_ptr (idct); - idct^.pub.start_pass := start_pass; - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Allocate and pre-zero a multiplier table for each component } - compptr^.dct_table := - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(multiplier_table)); - MEMZERO(compptr^.dct_table, SIZEOF(multiplier_table)); - { Mark multiplier table not yet set up for any method } - idct^.cur_method[ci] := -1; - Inc(compptr); - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdeferr.pas b/3rd/Imaging/Source/JpegLib/imjdeferr.pas deleted file mode 100644 index eeaf6f619..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdeferr.pas +++ /dev/null @@ -1,497 +0,0 @@ -unit imjdeferr; - -{ This file defines the error and message codes for the cjpeg/djpeg - applications. These strings are not needed as part of the JPEG library - proper. - Edit this file to add new codes, or to translate the message strings to - some other language. } - -{ Original cderror.h ; Copyright (C) 1994, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -{ To define the enum list of message codes, include this file without - defining macro JMESSAGE. To create a message string table, include it - again with a suitable JMESSAGE definition (see jerror.c for an example). } - - -{ Original: jversion.h ; Copyright (C) 1991-1996, Thomas G. Lane. } -{ This file contains software version identification. } - -const - JVERSION = '6a 7-Feb-96'; - - JCOPYRIGHT = 'Copyright (C) 1996, Thomas G. Lane'; - - JNOTICE = 'Pascal Translation, Copyright (C) 1996, Jacques Nomssi Nzali'; - -{ Create the message string table. - We do this from the master message list in jerror.h by re-reading - jerror.h with a suitable definition for macro JMESSAGE. - The message table is made an external symbol just in case any applications - want to refer to it directly. } - -type - J_MESSAGE_CODE =( - JMSG_NOMESSAGE, - JERR_ARITH_NOTIMPL, - JERR_BAD_ALIGN_TYPE, - JERR_BAD_ALLOC_CHUNK, - JERR_BAD_BUFFER_MODE, - JERR_BAD_COMPONENT_ID, - JERR_BAD_DCT_COEF, - JERR_BAD_DCTSIZE, - JERR_BAD_HUFF_TABLE, - JERR_BAD_IN_COLORSPACE, - JERR_BAD_J_COLORSPACE, - JERR_BAD_LENGTH, - JERR_BAD_LIB_VERSION, - JERR_BAD_MCU_SIZE, - JERR_BAD_POOL_ID, - JERR_BAD_PRECISION, - JERR_BAD_PROGRESSION, - JERR_BAD_PROG_SCRIPT, - JERR_BAD_SAMPLING, - JERR_BAD_SCAN_SCRIPT, - JERR_BAD_STATE, - JERR_BAD_STRUCT_SIZE, - JERR_BAD_VIRTUAL_ACCESS, - JERR_BUFFER_SIZE, - JERR_CANT_SUSPEND, - JERR_CCIR601_NOTIMPL, - JERR_COMPONENT_COUNT, - JERR_CONVERSION_NOTIMPL, - JERR_DAC_INDEX, - JERR_DAC_VALUE, - JERR_DHT_COUNTS, - JERR_DHT_INDEX, - JERR_DQT_INDEX, - JERR_EMPTY_IMAGE, - JERR_EMS_READ, - JERR_EMS_WRITE, - JERR_EOI_EXPECTED, - JERR_FILE_READ, - JERR_FILE_WRITE, - JERR_FRACT_SAMPLE_NOTIMPL, - JERR_HUFF_CLEN_OVERFLOW, - JERR_HUFF_MISSING_CODE, - JERR_IMAGE_TOO_BIG, - JERR_INPUT_EMPTY, - JERR_INPUT_EOF, - JERR_MISMATCHED_QUANT_TABLE, - JERR_MISSING_DATA, - JERR_MODE_CHANGE, - JERR_NOTIMPL, - JERR_NOT_COMPILED, - JERR_NO_BACKING_STORE, - JERR_NO_HUFF_TABLE, - JERR_NO_IMAGE, - JERR_NO_QUANT_TABLE, - JERR_NO_SOI, - JERR_OUT_OF_MEMORY, - JERR_QUANT_COMPONENTS, - JERR_QUANT_FEW_COLORS, - JERR_QUANT_MANY_COLORS, - JERR_SOF_DUPLICATE, - JERR_SOF_NO_SOS, - JERR_SOF_UNSUPPORTED, - JERR_SOI_DUPLICATE, - JERR_SOS_NO_SOF, - JERR_TFILE_CREATE, - JERR_TFILE_READ, - JERR_TFILE_SEEK, - JERR_TFILE_WRITE, - JERR_TOO_LITTLE_DATA, - JERR_UNKNOWN_MARKER, - JERR_VIRTUAL_BUG, - JERR_WIDTH_OVERFLOW, - JERR_XMS_READ, - JERR_XMS_WRITE, - JMSG_COPYRIGHT, - JMSG_VERSION, - JTRC_16BIT_TABLES, - JTRC_ADOBE, - JTRC_APP0, - JTRC_APP14, - JTRC_DAC, - JTRC_DHT, - JTRC_DQT, - JTRC_DRI, - JTRC_EMS_CLOSE, - JTRC_EMS_OPEN, - JTRC_EOI, - JTRC_HUFFBITS, - JTRC_JFIF, - JTRC_JFIF_BADTHUMBNAILSIZE, - JTRC_JFIF_EXTENSION, - JTRC_JFIF_THUMBNAIL, - JTRC_MISC_MARKER, - JTRC_PARMLESS_MARKER, - JTRC_QUANTVALS, - JTRC_QUANT_3_NCOLORS, - JTRC_QUANT_NCOLORS, - JTRC_QUANT_SELECTED, - JTRC_RECOVERY_ACTION, - JTRC_RST, - JTRC_SMOOTH_NOTIMPL, - JTRC_SOF, - JTRC_SOF_COMPONENT, - JTRC_SOI, - JTRC_SOS, - JTRC_SOS_COMPONENT, - JTRC_SOS_PARAMS, - JTRC_TFILE_CLOSE, - JTRC_TFILE_OPEN, - JTRC_THUMB_JPEG, - JTRC_THUMB_PALETTE, - JTRC_THUMB_RGB, - JTRC_UNKNOWN_IDS, - JTRC_XMS_CLOSE, - JTRC_XMS_OPEN, - JWRN_ADOBE_XFORM, - JWRN_BOGUS_PROGRESSION, - JWRN_EXTRANEOUS_DATA, - JWRN_HIT_MARKER, - JWRN_HUFF_BAD_CODE, - JWRN_JFIF_MAJOR, - JWRN_JPEG_EOF, - JWRN_MUST_RESYNC, - JWRN_NOT_SEQUENTIAL, - JWRN_TOO_MUCH_DATA, - - - JMSG_FIRSTADDONCODE, { Must be first entry! } - - {$ifdef BMP_SUPPORTED} - JERR_BMP_BADCMAP, { Unsupported BMP colormap format } - JERR_BMP_BADDEPTH, { Only 8- and 24-bit BMP files are supported } - JERR_BMP_BADHEADER, { Invalid BMP file: bad header length } - JERR_BMP_BADPLANES, { Invalid BMP file: biPlanes not equal to 1 } - JERR_BMP_COLORSPACE, { BMP output must be grayscale or RGB } - JERR_BMP_COMPRESSED, { Sorry, compressed BMPs not yet supported } - JERR_BMP_NOT, { Not a BMP file - does not start with BM } - JTRC_BMP, { %dx%d 24-bit BMP image } - JTRC_BMP_MAPPED, { %dx%d 8-bit colormapped BMP image } - JTRC_BMP_OS2, { %dx%d 24-bit OS2 BMP image } - JTRC_BMP_OS2_MAPPED, { %dx%d 8-bit colormapped OS2 BMP image } - {$endif} { BMP_SUPPORTED } - - {$ifdef GIF_SUPPORTED} - JERR_GIF_BUG, { GIF output got confused } - JERR_GIF_CODESIZE, { Bogus GIF codesize %d } - JERR_GIF_COLORSPACE, { GIF output must be grayscale or RGB } - JERR_GIF_IMAGENOTFOUND, { Too few images in GIF file } - JERR_GIF_NOT, { Not a GIF file } - JTRC_GIF, { %dx%dx%d GIF image } - JTRC_GIF_BADVERSION, - { Warning: unexpected GIF version number '%c%c%c' } - JTRC_GIF_EXTENSION, { Ignoring GIF extension block of type 0x%02x } - JTRC_GIF_NONSQUARE, { Caution: nonsquare pixels in input } - JWRN_GIF_BADDATA, { Corrupt data in GIF file } - JWRN_GIF_CHAR, { Bogus char 0x%02x in GIF file, ignoring } - JWRN_GIF_ENDCODE, { Premature end of GIF image } - JWRN_GIF_NOMOREDATA, { Ran out of GIF bits } - {$endif} { GIF_SUPPORTED } - - {$ifdef PPM_SUPPORTED} - JERR_PPM_COLORSPACE, { PPM output must be grayscale or RGB } - JERR_PPM_NONNUMERIC, { Nonnumeric data in PPM file } - JERR_PPM_NOT, { Not a PPM file } - JTRC_PGM, { %dx%d PGM image } - JTRC_PGM_TEXT, { %dx%d text PGM image } - JTRC_PPM, { %dx%d PPM image } - JTRC_PPM_TEXT, { %dx%d text PPM image } - {$endif} { PPM_SUPPORTED } - - {$ifdef RLE_SUPPORTED} - JERR_RLE_BADERROR, { Bogus error code from RLE library } - JERR_RLE_COLORSPACE, { RLE output must be grayscale or RGB } - JERR_RLE_DIMENSIONS, { Image dimensions (%dx%d) too large for RLE } - JERR_RLE_EMPTY, { Empty RLE file } - JERR_RLE_EOF, { Premature EOF in RLE header } - JERR_RLE_MEM, { Insufficient memory for RLE header } - JERR_RLE_NOT, { Not an RLE file } - JERR_RLE_TOOMANYCHANNELS, { Cannot handle %d output channels for RLE } - JERR_RLE_UNSUPPORTED, { Cannot handle this RLE setup } - JTRC_RLE, { %dx%d full-color RLE file } - JTRC_RLE_FULLMAP, { %dx%d full-color RLE file with map of length %d } - JTRC_RLE_GRAY, { %dx%d grayscale RLE file } - JTRC_RLE_MAPGRAY, { %dx%d grayscale RLE file with map of length %d } - JTRC_RLE_MAPPED, { %dx%d colormapped RLE file with map of length %d } - {$endif} { RLE_SUPPORTED } - - {$ifdef TARGA_SUPPORTED} - JERR_TGA_BADCMAP, { Unsupported Targa colormap format } - JERR_TGA_BADPARMS, { Invalid or unsupported Targa file } - JERR_TGA_COLORSPACE, { Targa output must be grayscale or RGB } - JTRC_TGA, { %dx%d RGB Targa image } - JTRC_TGA_GRAY, { %dx%d grayscale Targa image } - JTRC_TGA_MAPPED, { %dx%d colormapped Targa image } - {$else} - JERR_TGA_NOTCOMP, { Targa support was not compiled } - {$endif} { TARGA_SUPPORTED } - - JERR_BAD_CMAP_FILE, - { Color map file is invalid or of unsupported format } - JERR_TOO_MANY_COLORS, - { Output file format cannot handle %d colormap entries } - JERR_UNGETC_FAILED, { ungetc failed } - {$ifdef TARGA_SUPPORTED} - JERR_UNKNOWN_FORMAT, - { Unrecognized input file format --- perhaps you need -targa } - {$else} - JERR_UNKNOWN_FORMAT, { Unrecognized input file format } - {$endif} - JERR_UNSUPPORTED_FORMAT, { Unsupported output file format } - - JMSG_LASTADDONCODE - ); - - -const - JMSG_LASTMSGCODE : J_MESSAGE_CODE = JMSG_LASTADDONCODE; - -type - msg_table = Array[J_MESSAGE_CODE] of string[80]; -const - jpeg_std_message_table : msg_table = ( - - { JMSG_NOMESSAGE } 'Bogus message code %d', { Must be first entry! } - -{ For maintenance convenience, list is alphabetical by message code name } - { JERR_ARITH_NOTIMPL } - 'Sorry, there are legal restrictions on arithmetic coding', - { JERR_BAD_ALIGN_TYPE } 'ALIGN_TYPE is wrong, please fix', - { JERR_BAD_ALLOC_CHUNK } 'MAX_ALLOC_CHUNK is wrong, please fix', - { JERR_BAD_BUFFER_MODE } 'Bogus buffer control mode', - { JERR_BAD_COMPONENT_ID } 'Invalid component ID %d in SOS', - { JERR_BAD_DCT_COEF } 'DCT coefficient out of range', - { JERR_BAD_DCTSIZE } 'IDCT output block size %d not supported', - { JERR_BAD_HUFF_TABLE } 'Bogus Huffman table definition', - { JERR_BAD_IN_COLORSPACE } 'Bogus input colorspace', - { JERR_BAD_J_COLORSPACE } 'Bogus JPEG colorspace', - { JERR_BAD_LENGTH } 'Bogus marker length', - { JERR_BAD_LIB_VERSION } - 'Wrong JPEG library version: library is %d, caller expects %d', - { JERR_BAD_MCU_SIZE } 'Sampling factors too large for interleaved scan', - { JERR_BAD_POOL_ID } 'Invalid memory pool code %d', - { JERR_BAD_PRECISION } 'Unsupported JPEG data precision %d', - { JERR_BAD_PROGRESSION } - 'Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d', - { JERR_BAD_PROG_SCRIPT } - 'Invalid progressive parameters at scan script entry %d', - { JERR_BAD_SAMPLING } 'Bogus sampling factors', - { JERR_BAD_SCAN_SCRIPT } 'Invalid scan script at entry %d', - { JERR_BAD_STATE } 'Improper call to JPEG library in state %d', - { JERR_BAD_STRUCT_SIZE } - 'JPEG parameter struct mismatch: library thinks size is %d, caller expects %d', - { JERR_BAD_VIRTUAL_ACCESS } 'Bogus virtual array access', - { JERR_BUFFER_SIZE } 'Buffer passed to JPEG library is too small', - { JERR_CANT_SUSPEND } 'Suspension not allowed here', - { JERR_CCIR601_NOTIMPL } 'CCIR601 sampling not implemented yet', - { JERR_COMPONENT_COUNT } 'Too many color components: %d, max %d', - { JERR_CONVERSION_NOTIMPL } 'Unsupported color conversion request', - { JERR_DAC_INDEX } 'Bogus DAC index %d', - { JERR_DAC_VALUE } 'Bogus DAC value $%x', - { JERR_DHT_COUNTS } 'Bogus DHT counts', - { JERR_DHT_INDEX } 'Bogus DHT index %d', - { JERR_DQT_INDEX } 'Bogus DQT index %d', - { JERR_EMPTY_IMAGE } 'Empty JPEG image (DNL not supported)', - { JERR_EMS_READ } 'Read from EMS failed', - { JERR_EMS_WRITE } 'Write to EMS failed', - { JERR_EOI_EXPECTED } 'Didn''t expect more than one scan', - { JERR_FILE_READ } 'Input file read error', - { JERR_FILE_WRITE } 'Output file write error --- out of disk space?', - { JERR_FRACT_SAMPLE_NOTIMPL } 'Fractional sampling not implemented yet', - { JERR_HUFF_CLEN_OVERFLOW } 'Huffman code size table overflow', - { JERR_HUFF_MISSING_CODE } 'Missing Huffman code table entry', - { JERR_IMAGE_TOO_BIG } 'Maximum supported image dimension is %d pixels', - { JERR_INPUT_EMPTY } 'Empty input file', - { JERR_INPUT_EOF } 'Premature end of input file', - { JERR_MISMATCHED_QUANT_TABLE } - 'Cannot transcode due to multiple use of quantization table %d', - { JERR_MISSING_DATA } 'Scan script does not transmit all data', - { JERR_MODE_CHANGE } 'Invalid color quantization mode change', - { JERR_NOTIMPL } 'Not implemented yet', - { JERR_NOT_COMPILED } 'Requested feature was omitted at compile time', - { JERR_NO_BACKING_STORE } 'Backing store not supported', - { JERR_NO_HUFF_TABLE } 'Huffman table $%02x was not defined', - { JERR_NO_IMAGE } 'JPEG datastream contains no image', - { JERR_NO_QUANT_TABLE } 'Quantization table $%02x was not defined', - { JERR_NO_SOI } 'Not a JPEG file: starts with $%02x $%02x', - { JERR_OUT_OF_MEMORY } 'Insufficient memory (case %d)', - { JERR_QUANT_COMPONENTS } - 'Cannot quantize more than %d color components', - { JERR_QUANT_FEW_COLORS } 'Cannot quantize to fewer than %d colors', - { JERR_QUANT_MANY_COLORS } 'Cannot quantize to more than %d colors', - { JERR_SOF_DUPLICATE } 'Invalid JPEG file structure: two SOF markers', - { JERR_SOF_NO_SOS } 'Invalid JPEG file structure: missing SOS marker', - { JERR_SOF_UNSUPPORTED } 'Unsupported JPEG process: SOF type $%02x', - { JERR_SOI_DUPLICATE } 'Invalid JPEG file structure: two SOI markers', - { JERR_SOS_NO_SOF } 'Invalid JPEG file structure: SOS before SOF', - { JERR_TFILE_CREATE } 'Failed to create temporary file %s', - { JERR_TFILE_READ } 'Read failed on temporary file', - { JERR_TFILE_SEEK } 'Seek failed on temporary file', - { JERR_TFILE_WRITE } - 'Write failed on temporary file --- out of disk space?', - { JERR_TOO_LITTLE_DATA } 'Application transferred too few scanlines', - { JERR_UNKNOWN_MARKER } 'Unsupported marker type $%02x', - { JERR_VIRTUAL_BUG } 'Virtual array controller messed up', - { JERR_WIDTH_OVERFLOW } 'Image too wide for this implementation', - { JERR_XMS_READ } 'Read from XMS failed', - { JERR_XMS_WRITE } 'Write to XMS failed', - { JMSG_COPYRIGHT } JCOPYRIGHT, - { JMSG_VERSION } JVERSION, - { JTRC_16BIT_TABLES } - 'Caution: quantization tables are too coarse for baseline JPEG', - { JTRC_ADOBE } - 'Adobe APP14 marker: version %d, flags $%04x $%04x, transform %d', - { JTRC_APP0 } 'Unknown APP0 marker (not JFIF), length %d', - { JTRC_APP14 } 'Unknown APP14 marker (not Adobe), length %d', - { JTRC_DAC } 'Define Arithmetic Table $%02x: $%02x', - { JTRC_DHT } 'Define Huffman Table $%02x', - { JTRC_DQT } 'Define Quantization Table %d precision %d', - { JTRC_DRI } 'Define Restart Interval %d', - { JTRC_EMS_CLOSE } 'Freed EMS handle %d', - { JTRC_EMS_OPEN } 'Obtained EMS handle %d', - { JTRC_EOI } 'End Of Image', - { JTRC_HUFFBITS } ' %3d %3d %3d %3d %3d %3d %3d %3d', - { JTRC_JFIF } 'JFIF APP0 marker, density %dx%d %d', - { JTRC_JFIF_BADTHUMBNAILSIZE } - 'Warning: thumbnail image size does not match data length %d', - { JTRC_JFIF_EXTENSION } 'JFIF extension marker: type 0x%02x, length %u', - { JTRC_JFIF_THUMBNAIL } ' with %d x %d thumbnail image', - { JTRC_MISC_MARKER } 'Skipping marker $%02x, length %d', - { JTRC_PARMLESS_MARKER } 'Unexpected marker $%02x', - { JTRC_QUANTVALS } ' %4d %4d %4d %4d %4d %4d %4d %4d', - { JTRC_QUANT_3_NCOLORS } 'Quantizing to %d = %d*%d*%d colors', - { JTRC_QUANT_NCOLORS } 'Quantizing to %d colors', - { JTRC_QUANT_SELECTED } 'Selected %d colors for quantization', - { JTRC_RECOVERY_ACTION } 'At marker $%02x, recovery action %d', - { JTRC_RST } 'RST%d', - { JTRC_SMOOTH_NOTIMPL } - 'Smoothing not supported with nonstandard sampling ratios', - { JTRC_SOF } 'Start Of Frame $%02x: width=%d, height=%d, components=%d', - { JTRC_SOF_COMPONENT } ' Component %d: %dhx%dv q=%d', - { JTRC_SOI } 'Start of Image', - { JTRC_SOS } 'Start Of Scan: %d components', - { JTRC_SOS_COMPONENT } ' Component %d: dc=%d ac=%d', - { JTRC_SOS_PARAMS } ' Ss=%d, Se=%d, Ah=%d, Al=%d', - { JTRC_TFILE_CLOSE } 'Closed temporary file %s', - { JTRC_TFILE_OPEN } 'Opened temporary file %s', - { JTRC_THUMB_JPEG } - 'JFIF extension marker: JPEG-compressed thumbnail image, length %u', - { JMESSAGE(JTRC_THUMB_PALETTE } - 'JFIF extension marker: palette thumbnail image, length %u', - { JMESSAGE(JTRC_THUMB_RGB } - 'JFIF extension marker: RGB thumbnail image, length %u', - { JTRC_UNKNOWN_IDS } - 'Unrecognized component IDs %d %d %d, assuming YCbCr', - { JTRC_XMS_CLOSE } 'Freed XMS handle %d', - { JTRC_XMS_OPEN } 'Obtained XMS handle %d', - { JWRN_ADOBE_XFORM } 'Unknown Adobe color transform code %d', - { JWRN_BOGUS_PROGRESSION } - 'Inconsistent progression sequence for component %d coefficient %d', - { JWRN_EXTRANEOUS_DATA } - 'Corrupt JPEG data: %d extraneous bytes before marker $%02x', - { JWRN_HIT_MARKER } 'Corrupt JPEG data: premature end of data segment', - { JWRN_HUFF_BAD_CODE } 'Corrupt JPEG data: bad Huffman code', - { JWRN_JFIF_MAJOR } 'Warning: unknown JFIF revision number %d.%02d', - { JWRN_JPEG_EOF } 'Premature end of JPEG file', - { JWRN_MUST_RESYNC } - 'Corrupt JPEG data: found marker $%02x instead of RST%d', - { JWRN_NOT_SEQUENTIAL } 'Invalid SOS parameters for sequential JPEG', - { JWRN_TOO_MUCH_DATA } 'Application transferred too many scanlines', - - { JMSG_FIRSTADDONCODE } '', { Must be first entry! } - -{$ifdef BMP_SUPPORTED} - { JERR_BMP_BADCMAP } 'Unsupported BMP colormap format', - { JERR_BMP_BADDEPTH } 'Only 8- and 24-bit BMP files are supported', - { JERR_BMP_BADHEADER } 'Invalid BMP file: bad header length', - { JERR_BMP_BADPLANES } 'Invalid BMP file: biPlanes not equal to 1', - { JERR_BMP_COLORSPACE } 'BMP output must be grayscale or RGB', - { JERR_BMP_COMPRESSED } 'Sorry, compressed BMPs not yet supported', - { JERR_BMP_NOT } 'Not a BMP file - does not start with BM', - { JTRC_BMP } '%dx%d 24-bit BMP image', - { JTRC_BMP_MAPPED } '%dx%d 8-bit colormapped BMP image', - { JTRC_BMP_OS2 } '%dx%d 24-bit OS2 BMP image', - { JTRC_BMP_OS2_MAPPED } '%dx%d 8-bit colormapped OS2 BMP image', -{$endif} { BMP_SUPPORTED } - -{$ifdef GIF_SUPPORTED} - { JERR_GIF_BUG } 'GIF output got confused', - { JERR_GIF_CODESIZE } 'Bogus GIF codesize %d', - { JERR_GIF_COLORSPACE } 'GIF output must be grayscale or RGB', - { JERR_GIF_IMAGENOTFOUND } 'Too few images in GIF file', - { JERR_GIF_NOT } 'Not a GIF file', - { JTRC_GIF } '%dx%dx%d GIF image', - { JTRC_GIF_BADVERSION } - 'Warning: unexpected GIF version number "%c%c%c"', - { JTRC_GIF_EXTENSION } 'Ignoring GIF extension block of type 0x%02x', - { JTRC_GIF_NONSQUARE } 'Caution: nonsquare pixels in input', - { JWRN_GIF_BADDATA } 'Corrupt data in GIF file', - { JWRN_GIF_CHAR } 'Bogus char 0x%02x in GIF file, ignoring', - { JWRN_GIF_ENDCODE } 'Premature end of GIF image', - { JWRN_GIF_NOMOREDATA } 'Ran out of GIF bits', -{$endif} { GIF_SUPPORTED } - -{$ifdef PPM_SUPPORTED} - { JERR_PPM_COLORSPACE } 'PPM output must be grayscale or RGB', - { JERR_PPM_NONNUMERIC } 'Nonnumeric data in PPM file', - { JERR_PPM_NOT } 'Not a PPM file', - { JTRC_PGM } '%dx%d PGM image', - { JTRC_PGM_TEXT } '%dx%d text PGM image', - { JTRC_PPM } '%dx%d PPM image', - { JTRC_PPM_TEXT } '%dx%d text PPM image', -{$endif} { PPM_SUPPORTED } - -{$ifdef RLE_SUPPORTED} - { JERR_RLE_BADERROR } 'Bogus error code from RLE library', - { JERR_RLE_COLORSPACE } 'RLE output must be grayscale or RGB', - { JERR_RLE_DIMENSIONS } 'Image dimensions (%dx%d) too large for RLE', - { JERR_RLE_EMPTY } 'Empty RLE file', - { JERR_RLE_EOF } 'Premature EOF in RLE header', - { JERR_RLE_MEM } 'Insufficient memory for RLE header', - { JERR_RLE_NOT } 'Not an RLE file', - { JERR_RLE_TOOMANYCHANNELS } 'Cannot handle %d output channels for RLE', - { JERR_RLE_UNSUPPORTED } 'Cannot handle this RLE setup', - { JTRC_RLE } '%dx%d full-color RLE file', - { JTRC_RLE_FULLMAP } '%dx%d full-color RLE file with map of length %d', - { JTRC_RLE_GRAY } '%dx%d grayscale RLE file', - { JTRC_RLE_MAPGRAY } '%dx%d grayscale RLE file with map of length %d', - { JTRC_RLE_MAPPED } '%dx%d colormapped RLE file with map of length %d', -{$endif} { RLE_SUPPORTED } - -{$ifdef TARGA_SUPPORTED} - { JERR_TGA_BADCMAP } 'Unsupported Targa colormap format', - { JERR_TGA_BADPARMS } 'Invalid or unsupported Targa file', - { JERR_TGA_COLORSPACE } 'Targa output must be grayscale or RGB', - { JTRC_TGA } '%dx%d RGB Targa image', - { JTRC_TGA_GRAY } '%dx%d grayscale Targa image', - { JTRC_TGA_MAPPED } '%dx%d colormapped Targa image', -{$else} - { JERR_TGA_NOTCOMP } 'Targa support was not compiled', -{$endif} { TARGA_SUPPORTED } - - { JERR_BAD_CMAP_FILE } - 'Color map file is invalid or of unsupported format', - { JERR_TOO_MANY_COLORS } - 'Output file format cannot handle %d colormap entries', - { JERR_UNGETC_FAILED } 'ungetc failed', -{$ifdef TARGA_SUPPORTED} - { JERR_UNKNOWN_FORMAT } - 'Unrecognized input file format --- perhaps you need -targa', -{$else} - { JERR_UNKNOWN_FORMAT } 'Unrecognized input file format', -{$endif} - { JERR_UNSUPPORTED_FORMAT } 'Unsupported output file format', - - - { JMSG_LASTADDONCODE } ''); - -implementation - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdhuff.pas b/3rd/Imaging/Source/JpegLib/imjdhuff.pas deleted file mode 100644 index c653b717a..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdhuff.pas +++ /dev/null @@ -1,1205 +0,0 @@ -unit imjdhuff; - -{ This file contains declarations for Huffman entropy decoding routines - that are shared between the sequential decoder (jdhuff.c) and the - progressive decoder (jdphuff.c). No other modules need to see these. } - -{ This file contains Huffman entropy decoding routines. - - Much of the complexity here has to do with supporting input suspension. - If the data source module demands suspension, we want to be able to back - up to the start of the current MCU. To do this, we copy state variables - into local working storage, and update them back to the permanent - storage only upon successful completion of an MCU. } - -{ Original: jdhuff.h+jdhuff.c; Copyright (C) 1991-1997, Thomas G. Lane. } - - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjutils, - imjpeglib; - - -{ Declarations shared with jdphuff.c } - - - -{ Derived data constructed for each Huffman table } - -const - HUFF_LOOKAHEAD = 8; { # of bits of lookahead } - -type - d_derived_tbl_ptr = ^d_derived_tbl; - d_derived_tbl = record - { Basic tables: (element [0] of each array is unused) } - maxcode : array[0..18-1] of INT32; { largest code of length k (-1 if none) } - { (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) } - valoffset : array[0..17-1] of INT32; { huffval[] offset for codes of length k } - { valoffset[k] = huffval[] index of 1st symbol of code length k, less - the smallest code of length k; so given a code of length k, the - corresponding symbol is huffval[code + valoffset[k]] } - - { Link to public Huffman table (needed only in jpeg_huff_decode) } - pub : JHUFF_TBL_PTR; - - { Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of - the input data stream. If the next Huffman code is no more - than HUFF_LOOKAHEAD bits long, we can obtain its length and - the corresponding symbol directly from these tables. } - - look_nbits : array[0..(1 shl HUFF_LOOKAHEAD)-1] of int; - { # bits, or 0 if too long } - look_sym : array[0..(1 shl HUFF_LOOKAHEAD)-1] of UINT8; - { symbol, or unused } - end; - -{ Fetching the next N bits from the input stream is a time-critical operation - for the Huffman decoders. We implement it with a combination of inline - macros and out-of-line subroutines. Note that N (the number of bits - demanded at one time) never exceeds 15 for JPEG use. - - We read source bytes into get_buffer and dole out bits as needed. - If get_buffer already contains enough bits, they are fetched in-line - by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough - bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer - as full as possible (not just to the number of bits needed; this - prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer). - Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension. - On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains - at least the requested number of bits --- dummy zeroes are inserted if - necessary. } - - -type - bit_buf_type = INT32 ; { type of bit-extraction buffer } -const - BIT_BUF_SIZE = 32; { size of buffer in bits } - -{ If long is > 32 bits on your machine, and shifting/masking longs is - reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE - appropriately should be a win. Unfortunately we can't define the size - with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) - because not all machines measure sizeof in 8-bit bytes. } - -type - bitread_perm_state = record { Bitreading state saved across MCUs } - get_buffer : bit_buf_type; { current bit-extraction buffer } - bits_left : int; { # of unused bits in it } - end; - -type - bitread_working_state = record - { Bitreading working state within an MCU } - { current data source location } - { We need a copy, rather than munging the original, in case of suspension } - next_input_byte : JOCTETptr; { => next byte to read from source } - bytes_in_buffer : size_t; { # of bytes remaining in source buffer } - { Bit input buffer --- note these values are kept in register variables, - not in this struct, inside the inner loops. } - - get_buffer : bit_buf_type; { current bit-extraction buffer } - bits_left : int; { # of unused bits in it } - { Pointer needed by jpeg_fill_bit_buffer } - cinfo : j_decompress_ptr; { back link to decompress master record } - end; - -{ Module initialization routine for Huffman entropy decoding. } - -{GLOBAL} -procedure jinit_huff_decoder (cinfo : j_decompress_ptr); - -{GLOBAL} -function jpeg_huff_decode(var state : bitread_working_state; - get_buffer : bit_buf_type; {register} - bits_left : int; {register} - htbl : d_derived_tbl_ptr; - min_bits : int) : int; - -{ Compute the derived values for a Huffman table. - Note this is also used by jdphuff.c. } - -{GLOBAL} -procedure jpeg_make_d_derived_tbl (cinfo : j_decompress_ptr; - isDC : boolean; - tblno : int; - var pdtbl : d_derived_tbl_ptr); - -{ Load up the bit buffer to a depth of at least nbits } - -function jpeg_fill_bit_buffer (var state : bitread_working_state; - get_buffer : bit_buf_type; {register} - bits_left : int; {register} - nbits : int) : boolean; - -implementation - -{$IFDEF MACRO} - -{ Macros to declare and load/save bitread local variables. } -{$define BITREAD_STATE_VARS} - get_buffer : bit_buf_type ; {register} - bits_left : int; {register} - br_state : bitread_working_state; - -{$define BITREAD_LOAD_STATE(cinfop,permstate)} - br_state.cinfo := cinfop; - br_state.next_input_byte := cinfop^.src^.next_input_byte; - br_state.bytes_in_buffer := cinfop^.src^.bytes_in_buffer; - get_buffer := permstate.get_buffer; - bits_left := permstate.bits_left; - -{$define BITREAD_SAVE_STATE(cinfop,permstate) } - cinfop^.src^.next_input_byte := br_state.next_input_byte; - cinfop^.src^.bytes_in_buffer := br_state.bytes_in_buffer; - permstate.get_buffer := get_buffer; - permstate.bits_left := bits_left; - - -{ These macros provide the in-line portion of bit fetching. - Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer - before using GET_BITS, PEEK_BITS, or DROP_BITS. - The variables get_buffer and bits_left are assumed to be locals, - but the state struct might not be (jpeg_huff_decode needs this). - CHECK_BIT_BUFFER(state,n,action); - Ensure there are N bits in get_buffer; if suspend, take action. - val = GET_BITS(n); - Fetch next N bits. - val = PEEK_BITS(n); - Fetch next N bits without removing them from the buffer. - DROP_BITS(n); - Discard next N bits. - The value N should be a simple variable, not an expression, because it - is evaluated multiple times. } - - -{$define CHECK_BIT_BUFFER(state,nbits,action)} - if (bits_left < (nbits)) then - begin - if (not jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) then - begin - action; - exit; - end; - get_buffer := state.get_buffer; - bits_left := state.bits_left; - end; - - -{$define GET_BITS(nbits)} - Dec(bits_left, (nbits)); - ( (int(get_buffer shr bits_left)) and ( pred(1 shl (nbits)) ) ) - -{$define PEEK_BITS(nbits)} - int(get_buffer shr (bits_left - (nbits))) and pred(1 shl (nbits)) - -{$define DROP_BITS(nbits)} - Dec(bits_left, nbits); - - - - -{ Code for extracting next Huffman-coded symbol from input bit stream. - Again, this is time-critical and we make the main paths be macros. - - We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits - without looping. Usually, more than 95% of the Huffman codes will be 8 - or fewer bits long. The few overlength codes are handled with a loop, - which need not be inline code. - - Notes about the HUFF_DECODE macro: - 1. Near the end of the data segment, we may fail to get enough bits - for a lookahead. In that case, we do it the hard way. - 2. If the lookahead table contains no entry, the next code must be - more than HUFF_LOOKAHEAD bits long. - 3. jpeg_huff_decode returns -1 if forced to suspend. } - - - - -macro HUFF_DECODE(s,br_state,htbl,return FALSE,slowlabel); -label showlabel; -var - nb, look : int; {register} -begin - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto slowlabel; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := htbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := htbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; -slowlabel: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,htbl,nb)); - if (s < 0) then - begin - result := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; -end; - - -{$ENDIF} {MACRO} - -{ Expanded entropy decoder object for Huffman decoding. - - The savable_state subrecord contains fields that change within an MCU, - but must not be updated permanently until we complete the MCU. } - -type - savable_state = record - last_dc_val : array[0..MAX_COMPS_IN_SCAN-1] of int; { last DC coef for each component } - end; - - -type - huff_entropy_ptr = ^huff_entropy_decoder; - huff_entropy_decoder = record - pub : jpeg_entropy_decoder; { public fields } - - { These fields are loaded into local variables at start of each MCU. - In case of suspension, we exit WITHOUT updating them. } - - bitstate : bitread_perm_state; { Bit buffer at start of MCU } - saved : savable_state; { Other state at start of MCU } - - { These fields are NOT loaded into local working state. } - restarts_to_go : uInt; { MCUs left in this restart interval } - - { Pointers to derived tables (these workspaces have image lifespan) } - dc_derived_tbls : array[0..NUM_HUFF_TBLS] of d_derived_tbl_ptr; - ac_derived_tbls : array[0..NUM_HUFF_TBLS] of d_derived_tbl_ptr; - - { Precalculated info set up by start_pass for use in decode_mcu: } - - { Pointers to derived tables to be used for each block within an MCU } - dc_cur_tbls : array[0..D_MAX_BLOCKS_IN_MCU-1] of d_derived_tbl_ptr; - ac_cur_tbls : array[0..D_MAX_BLOCKS_IN_MCU-1] of d_derived_tbl_ptr; - { Whether we care about the DC and AC coefficient values for each block } - dc_needed : array[0..D_MAX_BLOCKS_IN_MCU-1] of boolean; - ac_needed : array[0..D_MAX_BLOCKS_IN_MCU-1] of boolean; - end; - - - -{ Initialize for a Huffman-compressed scan. } - -{METHODDEF} -procedure start_pass_huff_decoder (cinfo : j_decompress_ptr); -var - entropy : huff_entropy_ptr; - ci, blkn, dctbl, actbl : int; - compptr : jpeg_component_info_ptr; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - - { Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. - This ought to be an error condition, but we make it a warning because - there are some baseline files out there with all zeroes in these bytes. } - - if (cinfo^.Ss <> 0) or (cinfo^.Se <> DCTSIZE2-1) or - (cinfo^.Ah <> 0) or (cinfo^.Al <> 0) then - WARNMS(j_common_ptr(cinfo), JWRN_NOT_SEQUENTIAL); - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - dctbl := compptr^.dc_tbl_no; - actbl := compptr^.ac_tbl_no; - { Compute derived values for Huffman tables } - { We may do this more than once for a table, but it's not expensive } - jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl, - entropy^.dc_derived_tbls[dctbl]); - jpeg_make_d_derived_tbl(cinfo, FALSE, actbl, - entropy^.ac_derived_tbls[actbl]); - { Initialize DC predictions to 0 } - entropy^.saved.last_dc_val[ci] := 0; - end; - - { Precalculate decoding info for each block in an MCU of this scan } - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - ci := cinfo^.MCU_membership[blkn]; - compptr := cinfo^.cur_comp_info[ci]; - { Precalculate which table to use for each block } - entropy^.dc_cur_tbls[blkn] := entropy^.dc_derived_tbls[compptr^.dc_tbl_no]; - entropy^.ac_cur_tbls[blkn] := entropy^.ac_derived_tbls[compptr^.ac_tbl_no]; - { Decide whether we really care about the coefficient values } - if (compptr^.component_needed) then - begin - entropy^.dc_needed[blkn] := TRUE; - { we don't need the ACs if producing a 1/8th-size image } - entropy^.ac_needed[blkn] := (compptr^.DCT_scaled_size > 1); - end - else - begin - entropy^.ac_needed[blkn] := FALSE; - entropy^.dc_needed[blkn] := FALSE; - end; - end; - - { Initialize bitread state variables } - entropy^.bitstate.bits_left := 0; - entropy^.bitstate.get_buffer := 0; { unnecessary, but keeps Purify quiet } - entropy^.pub.insufficient_data := FALSE; - - { Initialize restart counter } - entropy^.restarts_to_go := cinfo^.restart_interval; -end; - - -{ Compute the derived values for a Huffman table. - This routine also performs some validation checks on the table. - - Note this is also used by jdphuff.c. } - -{GLOBAL} -procedure jpeg_make_d_derived_tbl (cinfo : j_decompress_ptr; - isDC : boolean; - tblno : int; - var pdtbl : d_derived_tbl_ptr); -var - htbl : JHUFF_TBL_PTR; - dtbl : d_derived_tbl_ptr; - p, i, l, si, numsymbols : int; - lookbits, ctr : int; - huffsize : array[0..257-1] of byte; - huffcode : array[0..257-1] of uInt; - code : uInt; -var - sym : int; -begin - { Note that huffsize[] and huffcode[] are filled in code-length order, - paralleling the order of the symbols themselves in htbl^.huffval[]. } - - { Find the input Huffman table } - if (tblno < 0) or (tblno >= NUM_HUFF_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno); - if isDC then - htbl := cinfo^.dc_huff_tbl_ptrs[tblno] - else - htbl := cinfo^.ac_huff_tbl_ptrs[tblno]; - if (htbl = NIL) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_HUFF_TABLE, tblno); - - { Allocate a workspace if we haven't already done so. } - if (pdtbl = NIL) then - pdtbl := d_derived_tbl_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(d_derived_tbl)) ); - dtbl := pdtbl; - dtbl^.pub := htbl; { fill in back link } - - { Figure C.1: make table of Huffman code length for each symbol } - - p := 0; - for l := 1 to 16 do - begin - i := int(htbl^.bits[l]); - if (i < 0) or (p + i > 256) then { protect against table overrun } - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - while (i > 0) do - begin - huffsize[p] := byte(l); - Inc(p); - Dec(i); - end; - end; - huffsize[p] := 0; - numsymbols := p; - - { Figure C.2: generate the codes themselves } - { We also validate that the counts represent a legal Huffman code tree. } - - code := 0; - si := huffsize[0]; - p := 0; - while (huffsize[p] <> 0) do - begin - while (( int (huffsize[p]) ) = si) do - begin - huffcode[p] := code; - Inc(p); - Inc(code); - end; - { code is now 1 more than the last code used for codelength si; but - it must still fit in si bits, since no code is allowed to be all ones. } - - if (INT32(code) >= (INT32(1) shl si)) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - - code := code shl 1; - Inc(si); - end; - - { Figure F.15: generate decoding tables for bit-sequential decoding } - - p := 0; - for l := 1 to 16 do - begin - if (htbl^.bits[l] <> 0) then - begin - { valoffset[l] = huffval[] index of 1st symbol of code length l, - minus the minimum code of length l } - - dtbl^.valoffset[l] := INT32(p) - INT32(huffcode[p]); - Inc(p, htbl^.bits[l]); - dtbl^.maxcode[l] := huffcode[p-1]; { maximum code of length l } - end - else - begin - dtbl^.maxcode[l] := -1; { -1 if no codes of this length } - end; - end; - dtbl^.maxcode[17] := long($FFFFF); { ensures jpeg_huff_decode terminates } - - { Compute lookahead tables to speed up decoding. - First we set all the table entries to 0, indicating "too long"; - then we iterate through the Huffman codes that are short enough and - fill in all the entries that correspond to bit sequences starting - with that code. } - - MEMZERO(@dtbl^.look_nbits, SIZEOF(dtbl^.look_nbits)); - - p := 0; - for l := 1 to HUFF_LOOKAHEAD do - begin - for i := 1 to int (htbl^.bits[l]) do - begin - { l := current code's length, p := its index in huffcode[] & huffval[]. } - { Generate left-justified code followed by all possible bit sequences } - lookbits := huffcode[p] shl (HUFF_LOOKAHEAD-l); - for ctr := pred(1 shl (HUFF_LOOKAHEAD-l)) downto 0 do - begin - dtbl^.look_nbits[lookbits] := l; - dtbl^.look_sym[lookbits] := htbl^.huffval[p]; - Inc(lookbits); - end; - Inc(p); - end; - end; - - { Validate symbols as being reasonable. - For AC tables, we make no check, but accept all byte values 0..255. - For DC tables, we require the symbols to be in range 0..15. - (Tighter bounds could be applied depending on the data depth and mode, - but this is sufficient to ensure safe decoding.) } - - if (isDC) then - begin - for i := 0 to pred(numsymbols) do - begin - sym := htbl^.huffval[i]; - if (sym < 0) or (sym > 15) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - end; - end; -end; - - -{ Out-of-line code for bit fetching (shared with jdphuff.c). - See jdhuff.h for info about usage. - Note: current values of get_buffer and bits_left are passed as parameters, - but are returned in the corresponding fields of the state struct. - - On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width - of get_buffer to be used. (On machines with wider words, an even larger - buffer could be used.) However, on some machines 32-bit shifts are - quite slow and take time proportional to the number of places shifted. - (This is true with most PC compilers, for instance.) In this case it may - be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the - average shift distance at the cost of more calls to jpeg_fill_bit_buffer. } - -{$ifdef SLOW_SHIFT_32} -const - MIN_GET_BITS = 15; { minimum allowable value } -{$else} -const - MIN_GET_BITS = (BIT_BUF_SIZE-7); -{$endif} - - -{GLOBAL} -function jpeg_fill_bit_buffer (var state : bitread_working_state; - {register} get_buffer : bit_buf_type; - {register} bits_left : int; - nbits : int) : boolean; -label - no_more_bytes; -{ Load up the bit buffer to a depth of at least nbits } -var - { Copy heavily used state fields into locals (hopefully registers) } - {register} next_input_byte : {const} JOCTETptr; - {register} bytes_in_buffer : size_t; -var - {register} c : int; -var - cinfo : j_decompress_ptr; -begin - next_input_byte := state.next_input_byte; - bytes_in_buffer := state.bytes_in_buffer; - cinfo := state.cinfo; - - { Attempt to load at least MIN_GET_BITS bits into get_buffer. } - { (It is assumed that no request will be for more than that many bits.) } - { We fail to do so only if we hit a marker or are forced to suspend. } - - if (cinfo^.unread_marker = 0) then { cannot advance past a marker } - begin - while (bits_left < MIN_GET_BITS) do - begin - { Attempt to read a byte } - if (bytes_in_buffer = 0) then - begin - if not cinfo^.src^.fill_input_buffer(cinfo) then - begin - jpeg_fill_bit_buffer := FALSE; - exit; - end; - next_input_byte := cinfo^.src^.next_input_byte; - bytes_in_buffer := cinfo^.src^.bytes_in_buffer; - end; - Dec(bytes_in_buffer); - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - - { If it's $FF, check and discard stuffed zero byte } - if (c = $FF) then - begin - { Loop here to discard any padding FF's on terminating marker, - so that we can save a valid unread_marker value. NOTE: we will - accept multiple FF's followed by a 0 as meaning a single FF data - byte. This data pattern is not valid according to the standard. } - - repeat - if (bytes_in_buffer = 0) then - begin - if (not state.cinfo^.src^.fill_input_buffer (state.cinfo)) then - begin - jpeg_fill_bit_buffer := FALSE; - exit; - end; - next_input_byte := state.cinfo^.src^.next_input_byte; - bytes_in_buffer := state.cinfo^.src^.bytes_in_buffer; - end; - Dec(bytes_in_buffer); - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - Until (c <> $FF); - - if (c = 0) then - begin - { Found FF/00, which represents an FF data byte } - c := $FF; - end - else - begin - { Oops, it's actually a marker indicating end of compressed data. - Save the marker code for later use. - Fine point: it might appear that we should save the marker into - bitread working state, not straight into permanent state. But - once we have hit a marker, we cannot need to suspend within the - current MCU, because we will read no more bytes from the data - source. So it is OK to update permanent state right away. } - - cinfo^.unread_marker := c; - { See if we need to insert some fake zero bits. } - goto no_more_bytes; - end; - end; - - { OK, load c into get_buffer } - get_buffer := (get_buffer shl 8) or c; - Inc(bits_left, 8); - end { end while } - end - else - begin - no_more_bytes: - { We get here if we've read the marker that terminates the compressed - data segment. There should be enough bits in the buffer register - to satisfy the request; if so, no problem. } - - if (nbits > bits_left) then - begin - { Uh-oh. Report corrupted data to user and stuff zeroes into - the data stream, so that we can produce some kind of image. - We use a nonvolatile flag to ensure that only one warning message - appears per data segment. } - - if not cinfo^.entropy^.insufficient_data then - begin - WARNMS(j_common_ptr(cinfo), JWRN_HIT_MARKER); - cinfo^.entropy^.insufficient_data := TRUE; - end; - { Fill the buffer with zero bits } - get_buffer := get_buffer shl (MIN_GET_BITS - bits_left); - bits_left := MIN_GET_BITS; - end; - end; - - { Unload the local registers } - state.next_input_byte := next_input_byte; - state.bytes_in_buffer := bytes_in_buffer; - state.get_buffer := get_buffer; - state.bits_left := bits_left; - - jpeg_fill_bit_buffer := TRUE; -end; - - -{ Out-of-line code for Huffman code decoding. - See jdhuff.h for info about usage. } - -{GLOBAL} -function jpeg_huff_decode (var state : bitread_working_state; - {register} get_buffer : bit_buf_type; - {register} bits_left : int; - htbl : d_derived_tbl_ptr; - min_bits : int) : int; -var - {register} l : int; - {register} code : INT32; -begin - l := min_bits; - - { HUFF_DECODE has determined that the code is at least min_bits } - { bits long, so fetch that many bits in one swoop. } - - {CHECK_BIT_BUFFER(state, l, return -1);} - if (bits_left < l) then - begin - if (not jpeg_fill_bit_buffer(state, get_buffer, bits_left, l)) then - begin - jpeg_huff_decode := -1; - exit; - end; - get_buffer := state.get_buffer; - bits_left := state.bits_left; - end; - - {code := GET_BITS(l);} - Dec(bits_left, l); - code := (int(get_buffer shr bits_left)) and ( pred(1 shl l) ); - - { Collect the rest of the Huffman code one bit at a time. } - { This is per Figure F.16 in the JPEG spec. } - - while (code > htbl^.maxcode[l]) do - begin - code := code shl 1; - {CHECK_BIT_BUFFER(state, 1, return -1);} - if (bits_left < 1) then - begin - if (not jpeg_fill_bit_buffer(state, get_buffer, bits_left, 1)) then - begin - jpeg_huff_decode := -1; - exit; - end; - get_buffer := state.get_buffer; - bits_left := state.bits_left; - end; - - {code := code or GET_BITS(1);} - Dec(bits_left); - code := code or ( (int(get_buffer shr bits_left)) and pred(1 shl 1) ); - - Inc(l); - end; - - { Unload the local registers } - state.get_buffer := get_buffer; - state.bits_left := bits_left; - - { With garbage input we may reach the sentinel value l := 17. } - - if (l > 16) then - begin - WARNMS(j_common_ptr(state.cinfo), JWRN_HUFF_BAD_CODE); - jpeg_huff_decode := 0; { fake a zero as the safest result } - exit; - end; - - jpeg_huff_decode := htbl^.pub^.huffval[ int (code + htbl^.valoffset[l]) ]; -end; - - -{ Figure F.12: extend sign bit. - On some machines, a shift and add will be faster than a table lookup. } - -{$ifdef AVOID_TABLES} - -#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) - -{$else} - -{$define HUFF_EXTEND(x,s) - if (x < extend_test[s]) then - := x + extend_offset[s] - else - x;} - -const - extend_test : array[0..16-1] of int = { entry n is 2**(n-1) } - ($0000, $0001, $0002, $0004, $0008, $0010, $0020, $0040, - $0080, $0100, $0200, $0400, $0800, $1000, $2000, $4000); - -const - extend_offset : array[0..16-1] of int = { entry n is (-1 << n) + 1 } -(0, ((-1) shl 1) + 1, ((-1) shl 2) + 1, ((-1) shl 3) + 1, ((-1) shl 4) + 1, - ((-1) shl 5) + 1, ((-1) shl 6) + 1, ((-1) shl 7) + 1, ((-1) shl 8) + 1, - ((-1) shl 9) + 1, ((-1) shl 10) + 1, ((-1) shl 11) + 1,((-1) shl 12) + 1, - ((-1) shl 13) + 1, ((-1) shl 14) + 1, ((-1) shl 15) + 1); - -{$endif} { AVOID_TABLES } - - -{ Check for a restart marker & resynchronize decoder. - Returns FALSE if must suspend. } - -{LOCAL} -function process_restart (cinfo : j_decompress_ptr) : boolean; -var - entropy : huff_entropy_ptr; - ci : int; -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - - { Throw away any unused bits remaining in bit buffer; } - { include any full bytes in next_marker's count of discarded bytes } - Inc(cinfo^.marker^.discarded_bytes, entropy^.bitstate.bits_left div 8); - entropy^.bitstate.bits_left := 0; - - { Advance past the RSTn marker } - if (not cinfo^.marker^.read_restart_marker (cinfo)) then - begin - process_restart := FALSE; - exit; - end; - - { Re-initialize DC predictions to 0 } - for ci := 0 to pred(cinfo^.comps_in_scan) do - entropy^.saved.last_dc_val[ci] := 0; - - { Reset restart counter } - entropy^.restarts_to_go := cinfo^.restart_interval; - - { Reset out-of-data flag, unless read_restart_marker left us smack up - against a marker. In that case we will end up treating the next data - segment as empty, and we can avoid producing bogus output pixels by - leaving the flag set. } - - if (cinfo^.unread_marker = 0) then - entropy^.pub.insufficient_data := FALSE; - - process_restart := TRUE; -end; - - -{ Decode and return one MCU's worth of Huffman-compressed coefficients. - The coefficients are reordered from zigzag order into natural array order, - but are not dequantized. - - The i'th block of the MCU is stored into the block pointed to by - MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. - (Wholesale zeroing is usually a little faster than retail...) - - Returns FALSE if data source requested suspension. In that case no - changes have been made to permanent state. (Exception: some output - coefficients may already have been assigned. This is harmless for - this module, since we'll just re-assign them on the next call.) } - -{METHODDEF} -function decode_mcu (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; -label - label1, label2, label3; -var - entropy : huff_entropy_ptr; - {register} s, k, r : int; - blkn, ci : int; - block : JBLOCK_PTR; - {BITREAD_STATE_VARS} - get_buffer : bit_buf_type ; {register} - bits_left : int; {register} - br_state : bitread_working_state; - - state : savable_state; - dctbl : d_derived_tbl_ptr; - actbl : d_derived_tbl_ptr; -var - nb, look : int; {register} -begin - entropy := huff_entropy_ptr (cinfo^.entropy); - - { Process restart marker if needed; may have to suspend } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - if (not process_restart(cinfo)) then - begin - decode_mcu := FALSE; - exit; - end; - end; - - { If we've run out of data, just leave the MCU set to zeroes. - This way, we return uniform gray for the remainder of the segment. } - - if not entropy^.pub.insufficient_data then - begin - - { Load up working state } - {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);} - br_state.cinfo := cinfo; - br_state.next_input_byte := cinfo^.src^.next_input_byte; - br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer; - get_buffer := entropy^.bitstate.get_buffer; - bits_left := entropy^.bitstate.bits_left; - - {ASSIGN_STATE(state, entropy^.saved);} - state := entropy^.saved; - - { Outer loop handles each block in the MCU } - - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - block := JBLOCK_PTR(MCU_data[blkn]); - dctbl := entropy^.dc_cur_tbls[blkn]; - actbl := entropy^.ac_cur_tbls[blkn]; - - { Decode a single block's worth of coefficients } - - { Section F.2.2.1: decode the DC coefficient difference } - {HUFF_DECODE(s, br_state, dctbl, return FALSE, label1);} - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - begin - decode_mcu := False; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto label1; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := dctbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := dctbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; - label1: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,dctbl,nb); - if (s < 0) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - if (s <> 0) then - begin - {CHECK_BIT_BUFFER(br_state, s, return FALSE);} - if (bits_left < s) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {r := GET_BITS(s);} - Dec(bits_left, s); - r := ( int(get_buffer shr bits_left)) and ( pred(1 shl s) ); - - {s := HUFF_EXTEND(r, s);} - if (r < extend_test[s]) then - s := r + extend_offset[s] - else - s := r; - end; - - if (entropy^.dc_needed[blkn]) then - begin - { Convert DC difference to actual value, update last_dc_val } - ci := cinfo^.MCU_membership[blkn]; - Inc(s, state.last_dc_val[ci]); - state.last_dc_val[ci] := s; - { Output the DC coefficient (assumes jpeg_natural_order[0] := 0) } - block^[0] := JCOEF (s); - end; - - if (entropy^.ac_needed[blkn]) then - begin - - { Section F.2.2.2: decode the AC coefficients } - { Since zeroes are skipped, output area must be cleared beforehand } - k := 1; - while (k < DCTSIZE2) do { Nomssi: k is incr. in the loop } - begin - {HUFF_DECODE(s, br_state, actbl, return FALSE, label2);} - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - begin - decode_mcu := False; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto label2; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := actbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := actbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; - label2: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb); - if (s < 0) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - r := s shr 4; - s := s and 15; - - if (s <> 0) then - begin - Inc(k, r); - {CHECK_BIT_BUFFER(br_state, s, return FALSE);} - if (bits_left < s) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {r := GET_BITS(s);} - Dec(bits_left, s); - r := (int(get_buffer shr bits_left)) and ( pred(1 shl s) ); - - {s := HUFF_EXTEND(r, s);} - if (r < extend_test[s]) then - s := r + extend_offset[s] - else - s := r; - { Output coefficient in natural (dezigzagged) order. - Note: the extra entries in jpeg_natural_order[] will save us - if k >= DCTSIZE2, which could happen if the data is corrupted. } - - block^[jpeg_natural_order[k]] := JCOEF (s); - end - else - begin - if (r <> 15) then - break; - Inc(k, 15); - end; - Inc(k); - end; - end - else - begin - - { Section F.2.2.2: decode the AC coefficients } - { In this path we just discard the values } - k := 1; - while (k < DCTSIZE2) do - begin - {HUFF_DECODE(s, br_state, actbl, return FALSE, label3);} - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - begin - decode_mcu := False; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto label3; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := actbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := actbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; - label3: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,actbl,nb); - if (s < 0) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - r := s shr 4; - s := s and 15; - - if (s <> 0) then - begin - Inc(k, r); - {CHECK_BIT_BUFFER(br_state, s, return FALSE);} - if (bits_left < s) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then - begin - decode_mcu := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {DROP_BITS(s);} - Dec(bits_left, s); - end - else - begin - if (r <> 15) then - break; - Inc(k, 15); - end; - Inc(k); - end; - - end; - end; - - { Completed MCU, so update state } - {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);} - cinfo^.src^.next_input_byte := br_state.next_input_byte; - cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer; - entropy^.bitstate.get_buffer := get_buffer; - entropy^.bitstate.bits_left := bits_left; - - {ASSIGN_STATE(entropy^.saved, state);} - entropy^.saved := state; - - end; - - { Account for restart interval (no-op if not using restarts) } - if entropy^.restarts_to_go > 0 then - Dec(entropy^.restarts_to_go); - - decode_mcu := TRUE; -end; - - -{ Module initialization routine for Huffman entropy decoding. } - -{GLOBAL} -procedure jinit_huff_decoder (cinfo : j_decompress_ptr); -var - entropy : huff_entropy_ptr; - i : int; -begin - entropy := huff_entropy_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(huff_entropy_decoder)) ); - cinfo^.entropy := jpeg_entropy_decoder_ptr (entropy); - entropy^.pub.start_pass := start_pass_huff_decoder; - entropy^.pub.decode_mcu := decode_mcu; - - { Mark tables unallocated } - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - entropy^.dc_derived_tbls[i] := NIL; - entropy^.ac_derived_tbls[i] := NIL; - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdinput.pas b/3rd/Imaging/Source/JpegLib/imjdinput.pas deleted file mode 100644 index 16a13e247..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdinput.pas +++ /dev/null @@ -1,416 +0,0 @@ -unit imjdinput; - -{ Original: jdinput.c ; Copyright (C) 1991-1997, Thomas G. Lane. } - -{ This file is part of the Independent JPEG Group's software. - For conditions of distribution and use, see the accompanying README file. - - This file contains input control logic for the JPEG decompressor. - These routines are concerned with controlling the decompressor's input - processing (marker reading and coefficient decoding). The actual input - reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjpeglib, - imjdeferr, - imjerror, - imjinclude, imjutils; - -{ Initialize the input controller module. - This is called only once, when the decompression object is created. } - -{GLOBAL} -procedure jinit_input_controller (cinfo : j_decompress_ptr); - -implementation - -{ Private state } - -type - my_inputctl_ptr = ^my_input_controller; - my_input_controller = record - pub : jpeg_input_controller; { public fields } - - inheaders : boolean; { TRUE until first SOS is reached } - end; {my_input_controller;} - - - -{ Forward declarations } -{METHODDEF} -function consume_markers (cinfo : j_decompress_ptr) : int; forward; - - -{ Routines to calculate various quantities related to the size of the image. } - -{LOCAL} -procedure initial_setup (cinfo : j_decompress_ptr); -{ Called once, when first SOS marker is reached } -var - ci : int; - compptr : jpeg_component_info_ptr; -begin - { Make sure image isn't bigger than I can handle } - if (long(cinfo^.image_height) > long (JPEG_MAX_DIMENSION)) or - (long(cinfo^.image_width) > long(JPEG_MAX_DIMENSION)) then - ERREXIT1(j_common_ptr(cinfo), JERR_IMAGE_TOO_BIG, uInt(JPEG_MAX_DIMENSION)); - - { For now, precision must match compiled-in value... } - if (cinfo^.data_precision <> BITS_IN_JSAMPLE) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_PRECISION, cinfo^.data_precision); - - { Check that number of components won't exceed internal array sizes } - if (cinfo^.num_components > MAX_COMPONENTS) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.num_components, - MAX_COMPONENTS); - - { Compute maximum sampling factors; check factor validity } - cinfo^.max_h_samp_factor := 1; - cinfo^.max_v_samp_factor := 1; - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - if (compptr^.h_samp_factor<=0) or (compptr^.h_samp_factor>MAX_SAMP_FACTOR) or - (compptr^.v_samp_factor<=0) or (compptr^.v_samp_factor>MAX_SAMP_FACTOR) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_SAMPLING); - {cinfo^.max_h_samp_factor := MAX(cinfo^.max_h_samp_factor, - compptr^.h_samp_factor); - cinfo^.max_v_samp_factor := MAX(cinfo^.max_v_samp_factor, - compptr^.v_samp_factor);} - if cinfo^.max_h_samp_factor < compptr^.h_samp_factor then - cinfo^.max_h_samp_factor := compptr^.h_samp_factor; - if cinfo^.max_v_samp_factor < compptr^.v_samp_factor then - cinfo^.max_v_samp_factor := compptr^.v_samp_factor; - Inc(compptr); - end; - - { We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE. - In the full decompressor, this will be overridden by jdmaster.c; - but in the transcoder, jdmaster.c is not used, so we must do it here. } - - cinfo^.min_DCT_scaled_size := DCTSIZE; - - { Compute dimensions of components } - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - compptr^.DCT_scaled_size := DCTSIZE; - { Size in DCT blocks } - compptr^.width_in_blocks := JDIMENSION( - jdiv_round_up( long(cinfo^.image_width) * long(compptr^.h_samp_factor), - long(cinfo^.max_h_samp_factor * DCTSIZE)) ); - compptr^.height_in_blocks := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor), - long (cinfo^.max_v_samp_factor * DCTSIZE)) ); - { downsampled_width and downsampled_height will also be overridden by - jdmaster.c if we are doing full decompression. The transcoder library - doesn't use these values, but the calling application might. } - - { Size in samples } - compptr^.downsampled_width := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_width) * long(compptr^.h_samp_factor), - long (cinfo^.max_h_samp_factor)) ); - compptr^.downsampled_height := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height) * long(compptr^.v_samp_factor), - long (cinfo^.max_v_samp_factor)) ); - { Mark component needed, until color conversion says otherwise } - compptr^.component_needed := TRUE; - { Mark no quantization table yet saved for component } - compptr^.quant_table := NIL; - Inc(compptr); - end; - - { Compute number of fully interleaved MCU rows. } - cinfo^.total_iMCU_rows := JDIMENSION( - jdiv_round_up(long(cinfo^.image_height), - long(cinfo^.max_v_samp_factor*DCTSIZE)) ); - - { Decide whether file contains multiple scans } - if (cinfo^.comps_in_scan < cinfo^.num_components) or - (cinfo^.progressive_mode) then - cinfo^.inputctl^.has_multiple_scans := TRUE - else - cinfo^.inputctl^.has_multiple_scans := FALSE; -end; - - -{LOCAL} -procedure per_scan_setup (cinfo : j_decompress_ptr); -{ Do computations that are needed before processing a JPEG scan } -{ cinfo^.comps_in_scan and cinfo^.cur_comp_info[] were set from SOS marker } -var - ci, mcublks, tmp : int; - compptr : jpeg_component_info_ptr; -begin - if (cinfo^.comps_in_scan = 1) then - begin - { Noninterleaved (single-component) scan } - compptr := cinfo^.cur_comp_info[0]; - - { Overall image size in MCUs } - cinfo^.MCUs_per_row := compptr^.width_in_blocks; - cinfo^.MCU_rows_in_scan := compptr^.height_in_blocks; - - { For noninterleaved scan, always one block per MCU } - compptr^.MCU_width := 1; - compptr^.MCU_height := 1; - compptr^.MCU_blocks := 1; - compptr^.MCU_sample_width := compptr^.DCT_scaled_size; - compptr^.last_col_width := 1; - { For noninterleaved scans, it is convenient to define last_row_height - as the number of block rows present in the last iMCU row. } - - tmp := int (LongInt(compptr^.height_in_blocks) mod compptr^.v_samp_factor); - if (tmp = 0) then - tmp := compptr^.v_samp_factor; - compptr^.last_row_height := tmp; - - { Prepare array describing MCU composition } - cinfo^.blocks_in_MCU := 1; - cinfo^.MCU_membership[0] := 0; - - end - else - begin - - { Interleaved (multi-component) scan } - if (cinfo^.comps_in_scan <= 0) or (cinfo^.comps_in_scan > MAX_COMPS_IN_SCAN) then - ERREXIT2(j_common_ptr(cinfo), JERR_COMPONENT_COUNT, cinfo^.comps_in_scan, - MAX_COMPS_IN_SCAN); - - { Overall image size in MCUs } - cinfo^.MCUs_per_row := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_width), - long (cinfo^.max_h_samp_factor*DCTSIZE)) ); - cinfo^.MCU_rows_in_scan := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height), - long (cinfo^.max_v_samp_factor*DCTSIZE)) ); - - cinfo^.blocks_in_MCU := 0; - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - { Sampling factors give # of blocks of component in each MCU } - compptr^.MCU_width := compptr^.h_samp_factor; - compptr^.MCU_height := compptr^.v_samp_factor; - compptr^.MCU_blocks := compptr^.MCU_width * compptr^.MCU_height; - compptr^.MCU_sample_width := compptr^.MCU_width * compptr^.DCT_scaled_size; - { Figure number of non-dummy blocks in last MCU column & row } - tmp := int (LongInt(compptr^.width_in_blocks) mod compptr^.MCU_width); - if (tmp = 0) then - tmp := compptr^.MCU_width; - compptr^.last_col_width := tmp; - tmp := int (LongInt(compptr^.height_in_blocks) mod compptr^.MCU_height); - if (tmp = 0) then - tmp := compptr^.MCU_height; - compptr^.last_row_height := tmp; - { Prepare array describing MCU composition } - mcublks := compptr^.MCU_blocks; - if (LongInt(cinfo^.blocks_in_MCU) + mcublks > D_MAX_BLOCKS_IN_MCU) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_MCU_SIZE); - while (mcublks > 0) do - begin - Dec(mcublks); - cinfo^.MCU_membership[cinfo^.blocks_in_MCU] := ci; - Inc(cinfo^.blocks_in_MCU); - end; - end; - - end; -end; - - -{ Save away a copy of the Q-table referenced by each component present - in the current scan, unless already saved during a prior scan. - - In a multiple-scan JPEG file, the encoder could assign different components - the same Q-table slot number, but change table definitions between scans - so that each component uses a different Q-table. (The IJG encoder is not - currently capable of doing this, but other encoders might.) Since we want - to be able to dequantize all the components at the end of the file, this - means that we have to save away the table actually used for each component. - We do this by copying the table at the start of the first scan containing - the component. - The JPEG spec prohibits the encoder from changing the contents of a Q-table - slot between scans of a component using that slot. If the encoder does so - anyway, this decoder will simply use the Q-table values that were current - at the start of the first scan for the component. - - The decompressor output side looks only at the saved quant tables, - not at the current Q-table slots. } - -{LOCAL} -procedure latch_quant_tables (cinfo : j_decompress_ptr); -var - ci, qtblno : int; - compptr : jpeg_component_info_ptr; - qtbl : JQUANT_TBL_PTR; -begin - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - { No work if we already saved Q-table for this component } - if (compptr^.quant_table <> NIL) then - continue; - { Make sure specified quantization table is present } - qtblno := compptr^.quant_tbl_no; - if (qtblno < 0) or (qtblno >= NUM_QUANT_TBLS) or - (cinfo^.quant_tbl_ptrs[qtblno] = NIL) then - ERREXIT1(j_common_ptr(cinfo), JERR_NO_QUANT_TABLE, qtblno); - { OK, save away the quantization table } - qtbl := JQUANT_TBL_PTR( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(JQUANT_TBL)) ); - MEMCOPY(qtbl, cinfo^.quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); - compptr^.quant_table := qtbl; - end; -end; - - -{ Initialize the input modules to read a scan of compressed data. - The first call to this is done by jdmaster.c after initializing - the entire decompressor (during jpeg_start_decompress). - Subsequent calls come from consume_markers, below. } - -{METHODDEF} -procedure start_input_pass (cinfo : j_decompress_ptr); -begin - per_scan_setup(cinfo); - latch_quant_tables(cinfo); - cinfo^.entropy^.start_pass (cinfo); - cinfo^.coef^.start_input_pass (cinfo); - cinfo^.inputctl^.consume_input := cinfo^.coef^.consume_data; -end; - - -{ Finish up after inputting a compressed-data scan. - This is called by the coefficient controller after it's read all - the expected data of the scan. } - -{METHODDEF} -procedure finish_input_pass (cinfo : j_decompress_ptr); -begin - cinfo^.inputctl^.consume_input := consume_markers; -end; - - -{ Read JPEG markers before, between, or after compressed-data scans. - Change state as necessary when a new scan is reached. - Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. - - The consume_input method pointer points either here or to the - coefficient controller's consume_data routine, depending on whether - we are reading a compressed data segment or inter-segment markers. } - -{METHODDEF} -function consume_markers (cinfo : j_decompress_ptr) : int; -var - val : int; - inputctl : my_inputctl_ptr; -begin - inputctl := my_inputctl_ptr (cinfo^.inputctl); - - if (inputctl^.pub.eoi_reached) then { After hitting EOI, read no further } - begin - consume_markers := JPEG_REACHED_EOI; - exit; - end; - - val := cinfo^.marker^.read_markers (cinfo); - - case (val) of - JPEG_REACHED_SOS: { Found SOS } - begin - if (inputctl^.inheaders) then - begin { 1st SOS } - initial_setup(cinfo); - inputctl^.inheaders := FALSE; - { Note: start_input_pass must be called by jdmaster.c - before any more input can be consumed. jdapimin.c is - responsible for enforcing this sequencing. } - end - else - begin { 2nd or later SOS marker } - if (not inputctl^.pub.has_multiple_scans) then - ERREXIT(j_common_ptr(cinfo), JERR_EOI_EXPECTED); { Oops, I wasn't expecting this! } - start_input_pass(cinfo); - end; - end; - JPEG_REACHED_EOI: { Found EOI } - begin - inputctl^.pub.eoi_reached := TRUE; - if (inputctl^.inheaders) then - begin { Tables-only datastream, apparently } - if (cinfo^.marker^.saw_SOF) then - ERREXIT(j_common_ptr(cinfo), JERR_SOF_NO_SOS); - end - else - begin - { Prevent infinite loop in coef ctlr's decompress_data routine - if user set output_scan_number larger than number of scans. } - - if (cinfo^.output_scan_number > cinfo^.input_scan_number) then - cinfo^.output_scan_number := cinfo^.input_scan_number; - end; - end; - JPEG_SUSPENDED:; - end; - - consume_markers := val; -end; - - -{ Reset state to begin a fresh datastream. } - -{METHODDEF} -procedure reset_input_controller (cinfo : j_decompress_ptr); -var - inputctl : my_inputctl_ptr; -begin - inputctl := my_inputctl_ptr (cinfo^.inputctl); - - inputctl^.pub.consume_input := consume_markers; - inputctl^.pub.has_multiple_scans := FALSE; { "unknown" would be better } - inputctl^.pub.eoi_reached := FALSE; - inputctl^.inheaders := TRUE; - { Reset other modules } - cinfo^.err^.reset_error_mgr (j_common_ptr(cinfo)); - cinfo^.marker^.reset_marker_reader (cinfo); - { Reset progression state -- would be cleaner if entropy decoder did this } - cinfo^.coef_bits := NIL; -end; - - -{ Initialize the input controller module. - This is called only once, when the decompression object is created. } - -{GLOBAL} -procedure jinit_input_controller (cinfo : j_decompress_ptr); -var - inputctl : my_inputctl_ptr; -begin - { Create subobject in permanent pool } - inputctl := my_inputctl_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT, - SIZEOF(my_input_controller)) ); - cinfo^.inputctl := jpeg_input_controller_ptr(inputctl); - { Initialize method pointers } - inputctl^.pub.consume_input := consume_markers; - inputctl^.pub.reset_input_controller := reset_input_controller; - inputctl^.pub.start_input_pass := start_input_pass; - inputctl^.pub.finish_input_pass := finish_input_pass; - { Initialize state: can't use reset_input_controller since we don't - want to try to reset other modules yet. } - - inputctl^.pub.has_multiple_scans := FALSE; { "unknown" would be better } - inputctl^.pub.eoi_reached := FALSE; - inputctl^.inheaders := TRUE; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdmainct.pas b/3rd/Imaging/Source/JpegLib/imjdmainct.pas deleted file mode 100644 index 8c04d7efc..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdmainct.pas +++ /dev/null @@ -1,610 +0,0 @@ -unit imjdmainct; - - -{ This file is part of the Independent JPEG Group's software. - For conditions of distribution and use, see the accompanying README file. - - This file contains the main buffer controller for decompression. - The main buffer lies between the JPEG decompressor proper and the - post-processor; it holds downsampled data in the JPEG colorspace. - - Note that this code is bypassed in raw-data mode, since the application - supplies the equivalent of the main buffer in that case. } - -{ Original: jdmainct.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - - -{ In the current system design, the main buffer need never be a full-image - buffer; any full-height buffers will be found inside the coefficient or - postprocessing controllers. Nonetheless, the main controller is not - trivial. Its responsibility is to provide context rows for upsampling/ - rescaling, and doing this in an efficient fashion is a bit tricky. - - Postprocessor input data is counted in "row groups". A row group - is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) - sample rows of each component. (We require DCT_scaled_size values to be - chosen such that these numbers are integers. In practice DCT_scaled_size - values will likely be powers of two, so we actually have the stronger - condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) - Upsampling will typically produce max_v_samp_factor pixel rows from each - row group (times any additional scale factor that the upsampler is - applying). - - The coefficient controller will deliver data to us one iMCU row at a time; - each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or - exactly min_DCT_scaled_size row groups. (This amount of data corresponds - to one row of MCUs when the image is fully interleaved.) Note that the - number of sample rows varies across components, but the number of row - groups does not. Some garbage sample rows may be included in the last iMCU - row at the bottom of the image. - - Depending on the vertical scaling algorithm used, the upsampler may need - access to the sample row(s) above and below its current input row group. - The upsampler is required to set need_context_rows TRUE at global - selection - time if so. When need_context_rows is FALSE, this controller can simply - obtain one iMCU row at a time from the coefficient controller and dole it - out as row groups to the postprocessor. - - When need_context_rows is TRUE, this controller guarantees that the buffer - passed to postprocessing contains at least one row group's worth of samples - above and below the row group(s) being processed. Note that the context - rows "above" the first passed row group appear at negative row offsets in - the passed buffer. At the top and bottom of the image, the required - context rows are manufactured by duplicating the first or last real sample - row; this avoids having special cases in the upsampling inner loops. - - The amount of context is fixed at one row group just because that's a - convenient number for this controller to work with. The existing - upsamplers really only need one sample row of context. An upsampler - supporting arbitrary output rescaling might wish for more than one row - group of context when shrinking the image; tough, we don't handle that. - (This is justified by the assumption that downsizing will be handled mostly - by adjusting the DCT_scaled_size values, so that the actual scale factor at - the upsample step needn't be much less than one.) - - To provide the desired context, we have to retain the last two row groups - of one iMCU row while reading in the next iMCU row. (The last row group - can't be processed until we have another row group for its below-context, - and so we have to save the next-to-last group too for its above-context.) - We could do this most simply by copying data around in our buffer, but - that'd be very slow. We can avoid copying any data by creating a rather - strange pointer structure. Here's how it works. We allocate a workspace - consisting of M+2 row groups (where M = min_DCT_scaled_size is the number - of row groups per iMCU row). We create two sets of redundant pointers to - the workspace. Labeling the physical row groups 0 to M+1, the synthesized - pointer lists look like this: - M+1 M-1 - master pointer --> 0 master pointer --> 0 - 1 1 - ... ... - M-3 M-3 - M-2 M - M-1 M+1 - M M-2 - M+1 M-1 - 0 0 - We read alternate iMCU rows using each master pointer; thus the last two - row groups of the previous iMCU row remain un-overwritten in the workspace. - The pointer lists are set up so that the required context rows appear to - be adjacent to the proper places when we pass the pointer lists to the - upsampler. - - The above pictures describe the normal state of the pointer lists. - At top and bottom of the image, we diddle the pointer lists to duplicate - the first or last sample row as necessary (this is cheaper than copying - sample rows around). - - This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that - situation each iMCU row provides only one row group so the buffering logic - must be different (eg, we must read two iMCU rows before we can emit the - first row group). For now, we simply do not support providing context - rows when min_DCT_scaled_size is 1. That combination seems unlikely to - be worth providing --- if someone wants a 1/8th-size preview, they probably - want it quick and dirty, so a context-free upsampler is sufficient. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, -{$ifdef QUANT_2PASS_SUPPORTED} - imjquant2, -{$endif} - imjdeferr, - imjerror, - imjpeglib; - - -{GLOBAL} -procedure jinit_d_main_controller (cinfo : j_decompress_ptr; - need_full_buffer : boolean); - - -implementation - -{ Private buffer controller object } - -type - my_main_ptr = ^my_main_controller; - my_main_controller = record - pub : jpeg_d_main_controller; { public fields } - - { Pointer to allocated workspace (M or M+2 row groups). } - buffer : array[0..MAX_COMPONENTS-1] of JSAMPARRAY; - - buffer_full : boolean; { Have we gotten an iMCU row from decoder? } - rowgroup_ctr : JDIMENSION ; { counts row groups output to postprocessor } - - { Remaining fields are only used in the context case. } - - { These are the master pointers to the funny-order pointer lists. } - xbuffer : array[0..2-1] of JSAMPIMAGE; { pointers to weird pointer lists } - - whichptr : int; { indicates which pointer set is now in use } - context_state : int; { process_data state machine status } - rowgroups_avail : JDIMENSION; { row groups available to postprocessor } - iMCU_row_ctr : JDIMENSION; { counts iMCU rows to detect image top/bot } - end; { my_main_controller; } - - -{ context_state values: } -const - CTX_PREPARE_FOR_IMCU = 0; { need to prepare for MCU row } - CTX_PROCESS_IMCU = 1; { feeding iMCU to postprocessor } - CTX_POSTPONED_ROW = 2; { feeding postponed row group } - - -{ Forward declarations } -{METHODDEF} -procedure process_data_simple_main(cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); forward; -{METHODDEF} -procedure process_data_context_main (cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); forward; - -{$ifdef QUANT_2PASS_SUPPORTED} -{METHODDEF} -procedure process_data_crank_post (cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); forward; -{$endif} - - -{LOCAL} -procedure alloc_funny_pointers (cinfo : j_decompress_ptr); -{ Allocate space for the funny pointer lists. - This is done only once, not once per pass. } -var - main : my_main_ptr; - ci, rgroup : int; - M : int; - compptr : jpeg_component_info_ptr; - xbuf : JSAMPARRAY; -begin - main := my_main_ptr (cinfo^.main); - M := cinfo^.min_DCT_scaled_size; - - { Get top-level space for component array pointers. - We alloc both arrays with one call to save a few cycles. } - - main^.xbuffer[0] := JSAMPIMAGE ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - cinfo^.num_components * 2 * SIZEOF(JSAMPARRAY)) ); - main^.xbuffer[1] := JSAMPIMAGE(@( main^.xbuffer[0]^[cinfo^.num_components] )); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div - cinfo^.min_DCT_scaled_size; { height of a row group of component } - { Get space for pointer lists --- M+4 row groups in each list. - We alloc both pointer lists with one call to save a few cycles. } - - xbuf := JSAMPARRAY ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)) ); - Inc(JSAMPROW_PTR(xbuf), rgroup); { want one row group at negative offsets } - main^.xbuffer[0]^[ci] := xbuf; - Inc(JSAMPROW_PTR(xbuf), rgroup * (M + 4)); - main^.xbuffer[1]^[ci] := xbuf; - Inc(compptr); - end; -end; - -{LOCAL} -procedure make_funny_pointers (cinfo : j_decompress_ptr); -{ Create the funny pointer lists discussed in the comments above. - The actual workspace is already allocated (in main^.buffer), - and the space for the pointer lists is allocated too. - This routine just fills in the curiously ordered lists. - This will be repeated at the beginning of each pass. } -var - main : my_main_ptr; - ci, i, rgroup : int; - M : int; - compptr : jpeg_component_info_ptr; - buf, xbuf0, xbuf1 : JSAMPARRAY; -var - help_xbuf0 : JSAMPARRAY; { work around negative offsets } -begin - main := my_main_ptr (cinfo^.main); - M := cinfo^.min_DCT_scaled_size; - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div - cinfo^.min_DCT_scaled_size; { height of a row group of component } - xbuf0 := main^.xbuffer[0]^[ci]; - xbuf1 := main^.xbuffer[1]^[ci]; - { First copy the workspace pointers as-is } - buf := main^.buffer[ci]; - for i := 0 to pred(rgroup * (M + 2)) do - begin - xbuf0^[i] := buf^[i]; - xbuf1^[i] := buf^[i]; - end; - { In the second list, put the last four row groups in swapped order } - for i := 0 to pred(rgroup * 2) do - begin - xbuf1^[rgroup*(M-2) + i] := buf^[rgroup*M + i]; - xbuf1^[rgroup*M + i] := buf^[rgroup*(M-2) + i]; - end; - { The wraparound pointers at top and bottom will be filled later - (see set_wraparound_pointers, below). Initially we want the "above" - pointers to duplicate the first actual data line. This only needs - to happen in xbuffer[0]. } - - help_xbuf0 := xbuf0; - Dec(JSAMPROW_PTR(help_xbuf0), rgroup); - - for i := 0 to pred(rgroup) do - begin - {xbuf0^[i - rgroup] := xbuf0^[0];} - help_xbuf0^[i] := xbuf0^[0]; - end; - Inc(compptr); - end; -end; - - -{LOCAL} -procedure set_wraparound_pointers (cinfo : j_decompress_ptr); -{ Set up the "wraparound" pointers at top and bottom of the pointer lists. - This changes the pointer list state from top-of-image to the normal state. } -var - main : my_main_ptr; - ci, i, rgroup : int; - M : int; - compptr : jpeg_component_info_ptr; - xbuf0, xbuf1 : JSAMPARRAY; -var - help_xbuf0, - help_xbuf1 : JSAMPARRAY; { work around negative offsets } -begin - main := my_main_ptr (cinfo^.main); - M := cinfo^.min_DCT_scaled_size; - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div - cinfo^.min_DCT_scaled_size; { height of a row group of component } - xbuf0 := main^.xbuffer[0]^[ci]; - xbuf1 := main^.xbuffer[1]^[ci]; - - help_xbuf0 := xbuf0; - Dec(JSAMPROW_PTR(help_xbuf0), rgroup); - help_xbuf1 := xbuf1; - Dec(JSAMPROW_PTR(help_xbuf1), rgroup); - - for i := 0 to pred(rgroup) do - begin - {xbuf0^[i - rgroup] := xbuf0^[rgroup*(M+1) + i]; - xbuf1^[i - rgroup] := xbuf1^[rgroup*(M+1) + i];} - - help_xbuf0^[i] := xbuf0^[rgroup*(M+1) + i]; - help_xbuf1^[i] := xbuf1^[rgroup*(M+1) + i]; - - xbuf0^[rgroup*(M+2) + i] := xbuf0^[i]; - xbuf1^[rgroup*(M+2) + i] := xbuf1^[i]; - end; - Inc(compptr); - end; -end; - - -{LOCAL} -procedure set_bottom_pointers (cinfo : j_decompress_ptr); -{ Change the pointer lists to duplicate the last sample row at the bottom - of the image. whichptr indicates which xbuffer holds the final iMCU row. - Also sets rowgroups_avail to indicate number of nondummy row groups in row. } -var - main : my_main_ptr; - ci, i, rgroup, iMCUheight, rows_left : int; - compptr : jpeg_component_info_ptr; - xbuf : JSAMPARRAY; -begin - main := my_main_ptr (cinfo^.main); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Count sample rows in one iMCU row and in one row group } - iMCUheight := compptr^.v_samp_factor * compptr^.DCT_scaled_size; - rgroup := iMCUheight div cinfo^.min_DCT_scaled_size; - { Count nondummy sample rows remaining for this component } - rows_left := int (compptr^.downsampled_height mod JDIMENSION (iMCUheight)); - if (rows_left = 0) then - rows_left := iMCUheight; - { Count nondummy row groups. Should get same answer for each component, - so we need only do it once. } - if (ci = 0) then - begin - main^.rowgroups_avail := JDIMENSION ((rows_left-1) div rgroup + 1); - end; - { Duplicate the last real sample row rgroup*2 times; this pads out the - last partial rowgroup and ensures at least one full rowgroup of context. } - - xbuf := main^.xbuffer[main^.whichptr]^[ci]; - for i := 0 to pred(rgroup * 2) do - begin - xbuf^[rows_left + i] := xbuf^[rows_left-1]; - end; - Inc(compptr); - end; -end; - - -{ Initialize for a processing pass. } - -{METHODDEF} -procedure start_pass_main (cinfo : j_decompress_ptr; - pass_mode : J_BUF_MODE); -var - main : my_main_ptr; -begin - main := my_main_ptr (cinfo^.main); - - case (pass_mode) of - JBUF_PASS_THRU: - begin - if (cinfo^.upsample^.need_context_rows) then - begin - main^.pub.process_data := process_data_context_main; - make_funny_pointers(cinfo); { Create the xbuffer[] lists } - main^.whichptr := 0; { Read first iMCU row into xbuffer[0] } - main^.context_state := CTX_PREPARE_FOR_IMCU; - main^.iMCU_row_ctr := 0; - end - else - begin - { Simple case with no context needed } - main^.pub.process_data := process_data_simple_main; - end; - main^.buffer_full := FALSE; { Mark buffer empty } - main^.rowgroup_ctr := 0; - end; -{$ifdef QUANT_2PASS_SUPPORTED} - JBUF_CRANK_DEST: - { For last pass of 2-pass quantization, just crank the postprocessor } - main^.pub.process_data := process_data_crank_post; -{$endif} - else - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - end; -end; - - -{ Process some data. - This handles the simple case where no context is required. } - -{METHODDEF} -procedure process_data_simple_main (cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -var - main : my_main_ptr; - rowgroups_avail : JDIMENSION; -var - main_buffer_ptr : JSAMPIMAGE; -begin - main := my_main_ptr (cinfo^.main); - main_buffer_ptr := JSAMPIMAGE(@(main^.buffer)); - - { Read input data if we haven't filled the main buffer yet } - if (not main^.buffer_full) then - begin - if (cinfo^.coef^.decompress_data (cinfo, main_buffer_ptr)=0) then - exit; { suspension forced, can do nothing more } - main^.buffer_full := TRUE; { OK, we have an iMCU row to work with } - end; - - { There are always min_DCT_scaled_size row groups in an iMCU row. } - rowgroups_avail := JDIMENSION (cinfo^.min_DCT_scaled_size); - { Note: at the bottom of the image, we may pass extra garbage row groups - to the postprocessor. The postprocessor has to check for bottom - of image anyway (at row resolution), so no point in us doing it too. } - - { Feed the postprocessor } - cinfo^.post^.post_process_data (cinfo, main_buffer_ptr, - main^.rowgroup_ctr, rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - - { Has postprocessor consumed all the data yet? If so, mark buffer empty } - if (main^.rowgroup_ctr >= rowgroups_avail) then - begin - main^.buffer_full := FALSE; - main^.rowgroup_ctr := 0; - end; -end; - - -{ Process some data. - This handles the case where context rows must be provided. } - -{METHODDEF} -procedure process_data_context_main (cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -var - main : my_main_ptr; -begin - main := my_main_ptr (cinfo^.main); - - { Read input data if we haven't filled the main buffer yet } - if (not main^.buffer_full) then - begin - if (cinfo^.coef^.decompress_data (cinfo, - main^.xbuffer[main^.whichptr])=0) then - exit; { suspension forced, can do nothing more } - main^.buffer_full := TRUE; { OK, we have an iMCU row to work with } - Inc(main^.iMCU_row_ctr); { count rows received } - end; - - { Postprocessor typically will not swallow all the input data it is handed - in one call (due to filling the output buffer first). Must be prepared - to exit and restart. This switch lets us keep track of how far we got. - Note that each case falls through to the next on successful completion. } - - case (main^.context_state) of - CTX_POSTPONED_ROW: - begin - { Call postprocessor using previously set pointers for postponed row } - cinfo^.post^.post_process_data (cinfo, main^.xbuffer[main^.whichptr], - main^.rowgroup_ctr, main^.rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - if (main^.rowgroup_ctr < main^.rowgroups_avail) then - exit; { Need to suspend } - main^.context_state := CTX_PREPARE_FOR_IMCU; - if (out_row_ctr >= out_rows_avail) then - exit; { Postprocessor exactly filled output buf } - end; - end; - case (main^.context_state) of - CTX_POSTPONED_ROW, - CTX_PREPARE_FOR_IMCU: {FALLTHROUGH} - begin - { Prepare to process first M-1 row groups of this iMCU row } - main^.rowgroup_ctr := 0; - main^.rowgroups_avail := JDIMENSION (cinfo^.min_DCT_scaled_size - 1); - { Check for bottom of image: if so, tweak pointers to "duplicate" - the last sample row, and adjust rowgroups_avail to ignore padding rows. } - - if (main^.iMCU_row_ctr = cinfo^.total_iMCU_rows) then - set_bottom_pointers(cinfo); - main^.context_state := CTX_PROCESS_IMCU; - - end; - end; - case (main^.context_state) of - CTX_POSTPONED_ROW, - CTX_PREPARE_FOR_IMCU, {FALLTHROUGH} - CTX_PROCESS_IMCU: - begin - { Call postprocessor using previously set pointers } - cinfo^.post^.post_process_data (cinfo, main^.xbuffer[main^.whichptr], - main^.rowgroup_ctr, main^.rowgroups_avail, - output_buf, out_row_ctr, out_rows_avail); - if (main^.rowgroup_ctr < main^.rowgroups_avail) then - exit; { Need to suspend } - { After the first iMCU, change wraparound pointers to normal state } - if (main^.iMCU_row_ctr = 1) then - set_wraparound_pointers(cinfo); - { Prepare to load new iMCU row using other xbuffer list } - main^.whichptr := main^.whichptr xor 1; { 0=>1 or 1=>0 } - main^.buffer_full := FALSE; - { Still need to process last row group of this iMCU row, } - { which is saved at index M+1 of the other xbuffer } - main^.rowgroup_ctr := JDIMENSION (cinfo^.min_DCT_scaled_size + 1); - main^.rowgroups_avail := JDIMENSION (cinfo^.min_DCT_scaled_size + 2); - main^.context_state := CTX_POSTPONED_ROW; - end; - end; -end; - - -{ Process some data. - Final pass of two-pass quantization: just call the postprocessor. - Source data will be the postprocessor controller's internal buffer. } - -{$ifdef QUANT_2PASS_SUPPORTED} - -{METHODDEF} -procedure process_data_crank_post (cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -var - in_row_group_ctr : JDIMENSION; -begin - in_row_group_ctr := 0; - cinfo^.post^.post_process_data (cinfo, JSAMPIMAGE (NIL), - in_row_group_ctr, - JDIMENSION(0), - output_buf, - out_row_ctr, - out_rows_avail); -end; - -{$endif} { QUANT_2PASS_SUPPORTED } - - -{ Initialize main buffer controller. } - -{GLOBAL} -procedure jinit_d_main_controller (cinfo : j_decompress_ptr; - need_full_buffer : boolean); -var - main : my_main_ptr; - ci, rgroup, ngroups : int; - compptr : jpeg_component_info_ptr; -begin - main := my_main_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_main_controller)) ); - cinfo^.main := jpeg_d_main_controller_ptr(main); - main^.pub.start_pass := start_pass_main; - - if (need_full_buffer) then { shouldn't happen } - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - - { Allocate the workspace. - ngroups is the number of row groups we need.} - - if (cinfo^.upsample^.need_context_rows) then - begin - if (cinfo^.min_DCT_scaled_size < 2) then { unsupported, see comments above } - ERREXIT(j_common_ptr(cinfo), JERR_NOTIMPL); - alloc_funny_pointers(cinfo); { Alloc space for xbuffer[] lists } - ngroups := cinfo^.min_DCT_scaled_size + 2; - end - else - begin - ngroups := cinfo^.min_DCT_scaled_size; - end; - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - rgroup := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div - cinfo^.min_DCT_scaled_size; { height of a row group of component } - main^.buffer[ci] := cinfo^.mem^.alloc_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, - compptr^.width_in_blocks * LongWord(compptr^.DCT_scaled_size), - JDIMENSION (rgroup * ngroups)); - Inc(compptr); - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdmarker.pas b/3rd/Imaging/Source/JpegLib/imjdmarker.pas deleted file mode 100644 index ad175b5dc..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdmarker.pas +++ /dev/null @@ -1,2648 +0,0 @@ -unit imjdmarker; - -{ This file contains routines to decode JPEG datastream markers. - Most of the complexity arises from our desire to support input - suspension: if not all of the data for a marker is available; - we must exit back to the application. On resumption; we reprocess - the marker. } - -{ Original: jdmarker.c; Copyright (C) 1991-1998; Thomas G. Lane. } -{ History - 9.7.96 Conversion to pascal started jnn - 22.3.98 updated to 6b jnn } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjcomapi, - imjpeglib; - -const { JPEG marker codes } - M_SOF0 = $c0; - M_SOF1 = $c1; - M_SOF2 = $c2; - M_SOF3 = $c3; - - M_SOF5 = $c5; - M_SOF6 = $c6; - M_SOF7 = $c7; - - M_JPG = $c8; - M_SOF9 = $c9; - M_SOF10 = $ca; - M_SOF11 = $cb; - - M_SOF13 = $cd; - M_SOF14 = $ce; - M_SOF15 = $cf; - - M_DHT = $c4; - - M_DAC = $cc; - - M_RST0 = $d0; - M_RST1 = $d1; - M_RST2 = $d2; - M_RST3 = $d3; - M_RST4 = $d4; - M_RST5 = $d5; - M_RST6 = $d6; - M_RST7 = $d7; - - M_SOI = $d8; - M_EOI = $d9; - M_SOS = $da; - M_DQT = $db; - M_DNL = $dc; - M_DRI = $dd; - M_DHP = $de; - M_EXP = $df; - - M_APP0 = $e0; - M_APP1 = $e1; - M_APP2 = $e2; - M_APP3 = $e3; - M_APP4 = $e4; - M_APP5 = $e5; - M_APP6 = $e6; - M_APP7 = $e7; - M_APP8 = $e8; - M_APP9 = $e9; - M_APP10 = $ea; - M_APP11 = $eb; - M_APP12 = $ec; - M_APP13 = $ed; - M_APP14 = $ee; - M_APP15 = $ef; - - M_JPG0 = $f0; - M_JPG13 = $fd; - M_COM = $fe; - - M_TEM = $01; - - M_ERROR = $100; - -type - JPEG_MARKER = uint; { JPEG marker codes } - -{ Private state } - -type - my_marker_ptr = ^my_marker_reader; - my_marker_reader = record - pub : jpeg_marker_reader; { public fields } - - { Application-overridable marker processing methods } - process_COM : jpeg_marker_parser_method; - process_APPn : array[0..16-1] of jpeg_marker_parser_method; - - { Limit on marker data length to save for each marker type } - length_limit_COM : uint; - length_limit_APPn : array[0..16-1] of uint; - - { Status of COM/APPn marker saving } - cur_marker : jpeg_saved_marker_ptr; { NIL if not processing a marker } - bytes_read : uint; { data bytes read so far in marker } - { Note: cur_marker is not linked into marker_list until it's all read. } - end; - -{GLOBAL} -function jpeg_resync_to_restart(cinfo : j_decompress_ptr; - desired : int) : boolean; -{GLOBAL} -procedure jinit_marker_reader (cinfo : j_decompress_ptr); - -{$ifdef SAVE_MARKERS_SUPPORTED} - -{GLOBAL} -procedure jpeg_save_markers (cinfo : j_decompress_ptr; - marker_code : int; - length_limit : uint); -{$ENDIF} - -{GLOBAL} -procedure jpeg_set_marker_processor (cinfo : j_decompress_ptr; - marker_code : int; - routine : jpeg_marker_parser_method); - -implementation - -uses - imjutils; - -{ At all times, cinfo1.src.next_input_byte and .bytes_in_buffer reflect - the current restart point; we update them only when we have reached a - suitable place to restart if a suspension occurs. } - - -{ Routines to process JPEG markers. - - Entry condition: JPEG marker itself has been read and its code saved - in cinfo^.unread_marker; input restart point is just after the marker. - - Exit: if return TRUE, have read and processed any parameters, and have - updated the restart point to point after the parameters. - If return FALSE, was forced to suspend before reaching end of - marker parameters; restart point has not been moved. Same routine - will be called again after application supplies more input data. - - This approach to suspension assumes that all of a marker's parameters - can fit into a single input bufferload. This should hold for "normal" - markers. Some COM/APPn markers might have large parameter segments - that might not fit. If we are simply dropping such a marker, we use - skip_input_data to get past it, and thereby put the problem on the - source manager's shoulders. If we are saving the marker's contents - into memory, we use a slightly different convention: when forced to - suspend, the marker processor updates the restart point to the end of - what it's consumed (ie, the end of the buffer) before returning FALSE. - On resumption, cinfo->unread_marker still contains the marker code, - but the data source will point to the next chunk of marker data. - The marker processor must retain internal state to deal with this. - - Note that we don't bother to avoid duplicate trace messages if a - suspension occurs within marker parameters. Other side effects - require more care. } - -{LOCAL} -function get_soi (cinfo : j_decompress_ptr) : boolean; -{ Process an SOI marker } -var - i : int; -begin - {$IFDEF DEBUG} - TRACEMS(j_common_ptr(cinfo), 1, JTRC_SOI); - {$ENDIF} - - if (cinfo^.marker^.saw_SOI) then - ERREXIT(j_common_ptr(cinfo), JERR_SOI_DUPLICATE); - - { Reset all parameters that are defined to be reset by SOI } - - for i := 0 to Pred(NUM_ARITH_TBLS) do - with cinfo^ do - begin - arith_dc_L[i] := 0; - arith_dc_U[i] := 1; - arith_ac_K[i] := 5; - end; - cinfo^.restart_interval := 0; - - { Set initial assumptions for colorspace etc } - - with cinfo^ do - begin - jpeg_color_space := JCS_UNKNOWN; - CCIR601_sampling := FALSE; { Assume non-CCIR sampling??? } - - saw_JFIF_marker := FALSE; - JFIF_major_version := 1; { set default JFIF APP0 values } - JFIF_minor_version := 1; - density_unit := 0; - X_density := 1; - Y_density := 1; - saw_Adobe_marker := FALSE; - Adobe_transform := 0; - - marker^.saw_SOI := TRUE; - end; - get_soi := TRUE; -end; { get_soi } - - -{LOCAL} -function get_sof(cinfo : j_decompress_ptr; - is_prog : boolean; - is_arith : boolean) : boolean; -{ Process a SOFn marker } -var - length : INT32; - c, ci : int; - compptr : jpeg_component_info_ptr; -{ Declare and initialize local copies of input pointer/count } -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; -{} - cinfo^.progressive_mode := is_prog; - cinfo^.arith_code := is_arith; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - - { Read a byte into variable cinfo^.data_precision. - If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - cinfo^.data_precision := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - -{ Read two bytes interpreted as an unsigned 16-bit integer. - cinfo^.image_height should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - cinfo^.image_height := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( cinfo^.image_height, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - -{ Read two bytes interpreted as an unsigned 16-bit integer. - cinfo^.image_width should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - cinfo^.image_width := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( cinfo^.image_width, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - { Read a byte into variable cinfo^.num_components. - If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - cinfo^.num_components := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - Dec(length, 8); - - {$IFDEF DEBUG} - TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOF, cinfo^.unread_marker, - int(cinfo^.image_width), int(cinfo^.image_height), - cinfo^.num_components); - {$ENDIF} - - if (cinfo^.marker^.saw_SOF) then - ERREXIT(j_common_ptr(cinfo), JERR_SOF_DUPLICATE); - - { We don't support files in which the image height is initially specified } - { as 0 and is later redefined by DNL. As long as we have to check that, } - { might as well have a general sanity check. } - if (cinfo^.image_height <= 0) or (cinfo^.image_width <= 0) - or (cinfo^.num_components <= 0) then - ERREXIT(j_common_ptr(cinfo), JERR_EMPTY_IMAGE); - - if (length <> (cinfo^.num_components * 3)) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - - if (cinfo^.comp_info = NIL) then { do only once, even if suspend } - cinfo^.comp_info := jpeg_component_info_list_ptr( - cinfo^.mem^.alloc_small(j_common_ptr(cinfo), JPOOL_IMAGE, - cinfo^.num_components * SIZEOF(jpeg_component_info))); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - compptr^.component_index := ci; - - { Read a byte into variable compptr^.component_id. - If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - compptr^.component_id := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - compptr^.h_samp_factor := (c shr 4) and 15; - compptr^.v_samp_factor := (c ) and 15; - - { Read a byte into variable compptr^.quant_tbl_no. - If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sof := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - compptr^.quant_tbl_no := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - {$IFDEF DEBUG} - TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOF_COMPONENT, - compptr^.component_id, compptr^.h_samp_factor, - compptr^.v_samp_factor, compptr^.quant_tbl_no); - {$ENDIF} - - Inc(compptr); - end; - - cinfo^.marker^.saw_SOF := TRUE; - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - get_sof := TRUE; -end; { get_sof } - - -{LOCAL} -function get_sos (cinfo : j_decompress_ptr) : boolean; -{ Process a SOS marker } -label - id_found; -var - length : INT32; - i, ci, n, c, cc : int; - compptr : jpeg_component_info_ptr; -{ Declare and initialize local copies of input pointer/count } -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; { Array[] of JOCTET; } - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{} - - if not cinfo^.marker^.saw_SOF then - ERREXIT(j_common_ptr(cinfo), JERR_SOS_NO_SOF); - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - - { Read a byte into variable n (Number of components). - If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - n := GETJOCTET(next_input_byte^); { Number of components } - Inc(next_input_byte); - - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_SOS, n); - {$ENDIF} - - if ((length <> (n * 2 + 6)) or (n < 1) or (n > MAX_COMPS_IN_SCAN)) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - - cinfo^.comps_in_scan := n; - - { Collect the component-spec parameters } - - for i := 0 to Pred(n) do - begin - { Read a byte into variable cc. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - cc := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to Pred(cinfo^.num_components) do - begin - if (cc = compptr^.component_id) then - goto id_found; - Inc(compptr); - end; - - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_COMPONENT_ID, cc); - - id_found: - - cinfo^.cur_comp_info[i] := compptr; - compptr^.dc_tbl_no := (c shr 4) and 15; - compptr^.ac_tbl_no := (c ) and 15; - - {$IFDEF DEBUG} - TRACEMS3(j_common_ptr(cinfo), 1, JTRC_SOS_COMPONENT, cc, - compptr^.dc_tbl_no, compptr^.ac_tbl_no); - {$ENDIF} - end; - - { Collect the additional scan parameters Ss, Se, Ah/Al. } - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - cinfo^.Ss := c; - - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - cinfo^.Se := c; - - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_sos := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - cinfo^.Ah := (c shr 4) and 15; - cinfo^.Al := (c ) and 15; - - {$IFDEF DEBUG} - TRACEMS4(j_common_ptr(cinfo), 1, JTRC_SOS_PARAMS, cinfo^.Ss, cinfo^.Se, - cinfo^.Ah, cinfo^.Al); - {$ENDIF} - - { Prepare to scan data & restart markers } - cinfo^.marker^.next_restart_num := 0; - - { Count another SOS marker } - Inc( cinfo^.input_scan_number ); - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - get_sos := TRUE; -end; { get_sos } - - -{METHODDEF} -function skip_variable (cinfo : j_decompress_ptr) : boolean; -{ Skip over an unknown or uninteresting variable-length marker } -var - length : INT32; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; { Array[] of JOCTET; } - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - skip_variable := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := uint(GETJOCTET(next_input_byte^)) shl 8; - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - skip_variable := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET(next_input_byte^)); - Inc( next_input_byte ); - - Dec(length, 2); - - {$IFDEF DEBUG} - TRACEMS2(j_common_ptr(cinfo), 1, JTRC_MISC_MARKER, - cinfo^.unread_marker, int(length)); - {$ENDIF} - - { Unload the local copies --- do this only at a restart boundary } - { do before skip_input_data } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - if (length > 0) then - cinfo^.src^.skip_input_data(cinfo, long(length)); - - skip_variable := TRUE; -end; { skip_variable } - - -{$IFDEF D_ARITH_CODING_SUPPORTED} - -{LOCAL} -function get_dac (cinfo : j_decompress_ptr) : boolean; -{ Process a DAC marker } -var - length : INT32; - index, val : int; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dac := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dac := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - Dec(length, 2); - - while (length > 0) do - begin - { Read a byte into variable index. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dac := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - index := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - { Read a byte into variable val. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dac := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - val := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - Dec( length, 2); - - {$IFDEF DEBUG} - TRACEMS2(j_common_ptr(cinfo), 1, JTRC_DAC, index, val); - {$ENDIF} - - if (index < 0) or (index >= (2*NUM_ARITH_TBLS)) then - ERREXIT1(j_common_ptr(cinfo) , JERR_DAC_INDEX, index); - - if (index >= NUM_ARITH_TBLS) then - begin { define AC table } - cinfo^.arith_ac_K[index-NUM_ARITH_TBLS] := UINT8(val); - end - else - begin { define DC table } - cinfo^.arith_dc_L[index] := UINT8(val and $0F); - cinfo^.arith_dc_U[index] := UINT8(val shr 4); - if (cinfo^.arith_dc_L[index] > cinfo^.arith_dc_U[index]) then - ERREXIT1(j_common_ptr(cinfo) , JERR_DAC_VALUE, val); - end; - end; - - if (length <> 0) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - get_dac := TRUE; -end; { get_dac } - -{$ELSE} - -{LOCAL} -function get_dac (cinfo : j_decompress_ptr) : boolean; -begin - get_dac := skip_variable(cinfo); -end; - -{$ENDIF} - -{LOCAL} -function get_dht (cinfo : j_decompress_ptr) : boolean; -{ Process a DHT marker } -var - length : INT32; - bits : Array[0..17-1] of UINT8; - huffval : Array[0..256-1] of UINT8; - i, index, count : int; - htblptr : ^JHUFF_TBL_PTR; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dht := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dht := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - Dec(length, 2); - - while (length > 16) do - begin - { Read a byte into variable index. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dht := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - index := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_DHT, index); - {$ENDIF} - - bits[0] := 0; - count := 0; - for i := 1 to 16 do - begin - { Read a byte into variable bits[i]. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dht := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - bits[i] := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - Inc( count, bits[i] ); - end; - - Dec( length, (1 + 16) ); - - {$IFDEF DEBUG} - TRACEMS8(j_common_ptr(cinfo), 2, JTRC_HUFFBITS, - bits[1], bits[2], bits[3], bits[4], - bits[5], bits[6], bits[7], bits[8]); - TRACEMS8(j_common_ptr(cinfo), 2, JTRC_HUFFBITS, - bits[9], bits[10], bits[11], bits[12], - bits[13], bits[14], bits[15], bits[16]); - {$ENDIF} - - { Here we just do minimal validation of the counts to avoid walking - off the end of our table space. jdhuff.c will check more carefully. } - - if (count > 256) or (INT32(count) > length) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_HUFF_TABLE); - - for i := 0 to Pred(count) do - begin - { Read a byte into variable huffval[i]. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dht := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - huffval[i] := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - end; - - Dec( length, count ); - - if (index and $10)<>0 then - begin { AC table definition } - Dec( index, $10 ); - htblptr := @cinfo^.ac_huff_tbl_ptrs[index]; - end - else - begin { DC table definition } - htblptr := @cinfo^.dc_huff_tbl_ptrs[index]; - end; - - if (index < 0) or (index >= NUM_HUFF_TBLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_DHT_INDEX, index); - - if (htblptr^ = NIL) then - htblptr^ := jpeg_alloc_huff_table(j_common_ptr(cinfo)); - - MEMCOPY(@(htblptr^)^.bits, @bits, SIZEOF((htblptr^)^.bits)); - MEMCOPY(@(htblptr^)^.huffval, @huffval, SIZEOF((htblptr^)^.huffval)); - end; - - if (length <> 0) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - get_dht := TRUE; -end; { get_dht } - - -{LOCAL} -function get_dqt (cinfo : j_decompress_ptr) : boolean; -{ Process a DQT marker } -var - length : INT32; - n, i, prec : int; - tmp : uint; - quant_ptr : JQUANT_TBL_PTR; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dqt := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dqt := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - Dec( length, 2 ); - - while (length > 0) do - begin - { Read a byte into variable n. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dqt := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - n := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - prec := n shr 4; - n := n and $0F; - - {$IFDEF DEBUG} - TRACEMS2(j_common_ptr(cinfo), 1, JTRC_DQT, n, prec); - {$ENDIF} - - if (n >= NUM_QUANT_TBLS) then - ERREXIT1(j_common_ptr(cinfo) , JERR_DQT_INDEX, n); - - if (cinfo^.quant_tbl_ptrs[n] = NIL) then - cinfo^.quant_tbl_ptrs[n] := jpeg_alloc_quant_table(j_common_ptr(cinfo)); - quant_ptr := cinfo^.quant_tbl_ptrs[n]; - - for i := 0 to Pred(DCTSIZE2) do - begin - if (prec <> 0) then - begin - { Read two bytes interpreted as an unsigned 16-bit integer. - tmp should be declared unsigned int or perhaps INT32. } - - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dqt := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - tmp := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dqt := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( tmp, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - end - else - begin - { Read a byte into variable tmp. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dqt := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - tmp := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - end; - - { We convert the zigzag-order table to natural array order. } - quant_ptr^.quantval[jpeg_natural_order[i]] := UINT16(tmp); - end; - - if (cinfo^.err^.trace_level >= 2) then - begin - i := 0; - while i < Pred(DCTSIZE2) do - begin - {$IFDEF DEBUG} - TRACEMS8(j_common_ptr(cinfo), 2, JTRC_QUANTVALS, - quant_ptr^.quantval[i], quant_ptr^.quantval[i+1], - quant_ptr^.quantval[i+2], quant_ptr^.quantval[i+3], - quant_ptr^.quantval[i+4], quant_ptr^.quantval[i+5], - quant_ptr^.quantval[i+6], quant_ptr^.quantval[i+7]); - {$ENDIF} - Inc(i, 8); - end; - end; - - Dec( length, DCTSIZE2+1 ); - if (prec <> 0) then - Dec( length, DCTSIZE2 ); - end; - - if (length <> 0) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - get_dqt := TRUE; -end; { get_dqt } - - -{LOCAL} -function get_dri (cinfo : j_decompress_ptr) : boolean; -{ Process a DRI marker } -var - length : INT32; - tmp : uint; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dri := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dri := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - if (length <> 4) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_LENGTH); - -{ Read two bytes interpreted as an unsigned 16-bit integer. - tmp should be declared unsigned int or perhaps INT32. } - -{ make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dri := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - tmp := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_dri := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( tmp, GETJOCTET( next_input_byte^)); - Inc( next_input_byte ); - - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_DRI, tmp); - {$ENDIF} - - cinfo^.restart_interval := tmp; - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - get_dri := TRUE; -end; { get_dri } - - -{ Routines for processing APPn and COM markers. - These are either saved in memory or discarded, per application request. - APP0 and APP14 are specially checked to see if they are - JFIF and Adobe markers, respectively. } - -const - APP0_DATA_LEN = 14; { Length of interesting data in APP0 } - APP14_DATA_LEN = 12; { Length of interesting data in APP14 } - APPN_DATA_LEN = 14; { Must be the largest of the above!! } - - -{LOCAL} -procedure examine_app0 (cinfo : j_decompress_ptr; - var data : array of JOCTET; - datalen : uint; - remaining : INT32); - -{ Examine first few bytes from an APP0. - Take appropriate action if it is a JFIF marker. - datalen is # of bytes at data[], remaining is length of rest of marker data. -} -{$IFDEF DEBUG} -var - totallen : INT32; -{$ENDIF} -begin - {$IFDEF DEBUG} - totallen := INT32(datalen) + remaining; - {$ENDIF} - if (datalen >= APP0_DATA_LEN) and - (GETJOCTET(data[0]) = $4A) and - (GETJOCTET(data[1]) = $46) and - (GETJOCTET(data[2]) = $49) and - (GETJOCTET(data[3]) = $46) and - (GETJOCTET(data[4]) = 0) then - begin - { Found JFIF APP0 marker: save info } - cinfo^.saw_JFIF_marker := TRUE; - cinfo^.JFIF_major_version := GETJOCTET(data[5]); - cinfo^.JFIF_minor_version := GETJOCTET(data[6]); - cinfo^.density_unit := GETJOCTET(data[7]); - cinfo^.X_density := (GETJOCTET(data[8]) shl 8) + GETJOCTET(data[9]); - cinfo^.Y_density := (GETJOCTET(data[10]) shl 8) + GETJOCTET(data[11]); - { Check version. - Major version must be 1, anything else signals an incompatible change. - (We used to treat this as an error, but now it's a nonfatal warning, - because some bozo at Hijaak couldn't read the spec.) - Minor version should be 0..2, but process anyway if newer. } - - if (cinfo^.JFIF_major_version <> 1) then - WARNMS2(j_common_ptr(cinfo), JWRN_JFIF_MAJOR, - cinfo^.JFIF_major_version, cinfo^.JFIF_minor_version); - { Generate trace messages } - {$IFDEF DEBUG} - TRACEMS5(j_common_ptr(cinfo), 1, JTRC_JFIF, - cinfo^.JFIF_major_version, cinfo^.JFIF_minor_version, - cinfo^.X_density, cinfo^.Y_density, cinfo^.density_unit); - { Validate thumbnail dimensions and issue appropriate messages } - if (GETJOCTET(data[12]) or GETJOCTET(data[13])) <> 0 then - TRACEMS2(j_common_ptr(cinfo), 1, JTRC_JFIF_THUMBNAIL, - GETJOCTET(data[12]), GETJOCTET(data[13])); - Dec(totallen, APP0_DATA_LEN); - if (totallen <> - ( INT32(GETJOCTET(data[12])) * INT32(GETJOCTET(data[13])) * INT32(3) )) then - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_JFIF_BADTHUMBNAILSIZE, int(totallen)); - {$ENDIF} - end - else - if (datalen >= 6) and - (GETJOCTET(data[0]) = $4A) and - (GETJOCTET(data[1]) = $46) and - (GETJOCTET(data[2]) = $58) and - (GETJOCTET(data[3]) = $58) and - (GETJOCTET(data[4]) = 0) then - begin - { Found JFIF "JFXX" extension APP0 marker } - { The library doesn't actually do anything with these, - but we try to produce a helpful trace message. } - {$IFDEF DEBUG} - case (GETJOCTET(data[5])) of - $10: - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_THUMB_JPEG, int(totallen)); - $11: - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_THUMB_PALETTE, int(totallen)); - $13: - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_THUMB_RGB, int(totallen)); - else - TRACEMS2(j_common_ptr(cinfo), 1, JTRC_JFIF_EXTENSION, - GETJOCTET(data[5]), int(totallen)); - end; - {$ENDIF} - end - else - begin - { Start of APP0 does not match "JFIF" or "JFXX", or too short } - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_APP0, int(totallen)); - {$ENDIF} - end; -end; - - -{LOCAL} -procedure examine_app14 (cinfo : j_decompress_ptr; - var data : array of JOCTET; - datalen : uint; - remaining : INT32); -{ Examine first few bytes from an APP14. - Take appropriate action if it is an Adobe marker. - datalen is # of bytes at data[], remaining is length of rest of marker data. - } -var - {$IFDEF DEBUG} - version, flags0, flags1, - {$ENDIF} - transform : uint; -begin - if (datalen >= APP14_DATA_LEN) and - (GETJOCTET(data[0]) = $41) and - (GETJOCTET(data[1]) = $64) and - (GETJOCTET(data[2]) = $6F) and - (GETJOCTET(data[3]) = $62) and - (GETJOCTET(data[4]) = $65) then - begin - { Found Adobe APP14 marker } - {$IFDEF DEBUG} - version := (GETJOCTET(data[5]) shl 8) + GETJOCTET(data[6]); - flags0 := (GETJOCTET(data[7]) shl 8) + GETJOCTET(data[8]); - flags1 := (GETJOCTET(data[9]) shl 8) + GETJOCTET(data[10]); - {$ENDIF} - transform := GETJOCTET(data[11]); - {$IFDEF DEBUG} - TRACEMS4(j_common_ptr(cinfo), 1, JTRC_ADOBE, version, flags0, flags1, transform); - {$ENDIF} - cinfo^.saw_Adobe_marker := TRUE; - cinfo^.Adobe_transform := UINT8 (transform); - end - else - begin - { Start of APP14 does not match "Adobe", or too short } - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_APP14, int (datalen + remaining)); - {$ENDIF} - end; -end; - - -{METHODDEF} -function get_interesting_appn (cinfo : j_decompress_ptr) : boolean; -{ Process an APP0 or APP14 marker without saving it } -var - length : INT32; - b : array[0..APPN_DATA_LEN-1] of JOCTET; - i, numtoread: uint; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - -{ Read two bytes interpreted as an unsigned 16-bit integer. - length should be declared unsigned int or perhaps INT32. } - - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_interesting_appn := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_interesting_appn := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET(next_input_byte^)); - Inc( next_input_byte ); - - Dec(length, 2); - - { get the interesting part of the marker data } - if (length >= APPN_DATA_LEN) then - numtoread := APPN_DATA_LEN - else - if (length > 0) then - numtoread := uint(length) - else - numtoread := 0; - - if numtoread > 0 then - begin - for i := 0 to numtoread-1 do - begin - { Read a byte into b[i]. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - get_interesting_appn := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - b[i] := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - end; - end; - - Dec(length, numtoread); - - { process it } - case (cinfo^.unread_marker) of - M_APP0: - examine_app0(cinfo, b, numtoread, length); - M_APP14: - examine_app14(cinfo, b, numtoread, length); - else - { can't get here unless jpeg_save_markers chooses wrong processor } - ERREXIT1(j_common_ptr(cinfo), JERR_UNKNOWN_MARKER, cinfo^.unread_marker); - end; - - { skip any remaining data -- could be lots } - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - if (length > 0) then - cinfo^.src^.skip_input_data(cinfo, long(length)); - - get_interesting_appn := TRUE; -end; - -{$ifdef SAVE_MARKERS_SUPPORTED} - -{METHODDEF} -function save_marker (cinfo : j_decompress_ptr) : boolean; -{ Save an APPn or COM marker into the marker list } -var - marker : my_marker_ptr; - cur_marker : jpeg_saved_marker_ptr; - bytes_read, data_length : uint; - data : JOCTET_FIELD_PTR; - length : INT32; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -var - limit : uint; -var - prev : jpeg_saved_marker_ptr; -begin - { local copies of input pointer/count } - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - - marker := my_marker_ptr(cinfo^.marker); - cur_marker := marker^.cur_marker; - length := 0; - - if (cur_marker = NIL) then - begin - { begin reading a marker } - { Read two bytes interpreted as an unsigned 16-bit integer. } - - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - save_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - length := (uint( GETJOCTET(next_input_byte^)) shl 8); - Inc( next_input_byte ); - - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - save_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - Inc( length, GETJOCTET(next_input_byte^)); - Inc( next_input_byte ); - - Dec(length, 2); - if (length >= 0) then - begin { watch out for bogus length word } - { figure out how much we want to save } - - if (cinfo^.unread_marker = int(M_COM)) then - limit := marker^.length_limit_COM - else - limit := marker^.length_limit_APPn[cinfo^.unread_marker - int(M_APP0)]; - if (uint(length) < limit) then - limit := uint(length); - { allocate and initialize the marker item } - cur_marker := jpeg_saved_marker_ptr( - cinfo^.mem^.alloc_large (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(jpeg_marker_struct) + limit) ); - cur_marker^.next := NIL; - cur_marker^.marker := UINT8 (cinfo^.unread_marker); - cur_marker^.original_length := uint(length); - cur_marker^.data_length := limit; - { data area is just beyond the jpeg_marker_struct } - cur_marker^.data := JOCTET_FIELD_PTR(cur_marker); - Inc(jpeg_saved_marker_ptr(cur_marker^.data)); - data := cur_marker^.data; - - marker^.cur_marker := cur_marker; - marker^.bytes_read := 0; - bytes_read := 0; - data_length := limit; - end - else - begin - { deal with bogus length word } - data_length := 0; - bytes_read := 0; - data := NIL; - end - end - else - begin - { resume reading a marker } - bytes_read := marker^.bytes_read; - data_length := cur_marker^.data_length; - data := cur_marker^.data; - Inc(data, bytes_read); - end; - - while (bytes_read < data_length) do - begin - { move the restart point to here } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - marker^.bytes_read := bytes_read; - { If there's not at least one byte in buffer, suspend } - if (bytes_in_buffer = 0) then - begin - if not datasrc^.fill_input_buffer (cinfo) then - begin - save_marker := FALSE; - exit; - end; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - - { Copy bytes with reasonable rapidity } - while (bytes_read < data_length) and (bytes_in_buffer > 0) do - begin - JOCTETPTR(data)^ := next_input_byte^; - Inc(JOCTETPTR(data)); - Inc(next_input_byte); - Dec(bytes_in_buffer); - Inc(bytes_read); - end; - end; - - { Done reading what we want to read } - if (cur_marker <> NIL) then - begin { will be NIL if bogus length word } - { Add new marker to end of list } - if (cinfo^.marker_list = NIL) then - begin - cinfo^.marker_list := cur_marker - end - else - begin - prev := cinfo^.marker_list; - while (prev^.next <> NIL) do - prev := prev^.next; - prev^.next := cur_marker; - end; - { Reset pointer & calc remaining data length } - data := cur_marker^.data; - length := cur_marker^.original_length - data_length; - end; - { Reset to initial state for next marker } - marker^.cur_marker := NIL; - - { Process the marker if interesting; else just make a generic trace msg } - case (cinfo^.unread_marker) of - M_APP0: - examine_app0(cinfo, data^, data_length, length); - M_APP14: - examine_app14(cinfo, data^, data_length, length); - else - {$IFDEF DEBUG} - TRACEMS2(j_common_ptr(cinfo), 1, JTRC_MISC_MARKER, cinfo^.unread_marker, - int(data_length + length)); - {$ENDIF} - end; - - { skip any remaining data -- could be lots } - { do before skip_input_data } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - if (length > 0) then - cinfo^.src^.skip_input_data (cinfo, long(length) ); - - save_marker := TRUE; -end; - -{$endif} { SAVE_MARKERS_SUPPORTED } - - -{ Find the next JPEG marker, save it in cinfo^.unread_marker. - Returns FALSE if had to suspend before reaching a marker; - in that case cinfo^.unread_marker is unchanged. - - Note that the result might not be a valid marker code, - but it will never be 0 or FF. } - -{LOCAL} -function next_marker (cinfo : j_decompress_ptr) : boolean; -var - c : int; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - - {while TRUE do} - repeat - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - next_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - { Skip any non-FF bytes. - This may look a bit inefficient, but it will not occur in a valid file. - We sync after each discarded byte so that a suspending data source - can discard the byte from its buffer. } - - while (c <> $FF) do - begin - Inc(cinfo^.marker^.discarded_bytes); - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - next_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - end; - { This loop swallows any duplicate FF bytes. Extra FFs are legal as - pad bytes, so don't count them in discarded_bytes. We assume there - will not be so many consecutive FF bytes as to overflow a suspending - data source's input buffer. } - - repeat - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - next_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - Until (c <> $FF); - if (c <> 0) then - break; { found a valid marker, exit loop } - { Reach here if we found a stuffed-zero data sequence (FF/00). - Discard it and loop back to try again. } - - Inc(cinfo^.marker^.discarded_bytes, 2); - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - Until False; - - if (cinfo^.marker^.discarded_bytes <> 0) then - begin - WARNMS2(j_common_ptr(cinfo), JWRN_EXTRANEOUS_DATA, - cinfo^.marker^.discarded_bytes, c); - cinfo^.marker^.discarded_bytes := 0; - end; - - cinfo^.unread_marker := c; - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - next_marker := TRUE; -end; { next_marker } - - -{LOCAL} -function first_marker (cinfo : j_decompress_ptr) : boolean; -{ Like next_marker, but used to obtain the initial SOI marker. } -{ For this marker, we do not allow preceding garbage or fill; otherwise, - we might well scan an entire input file before realizing it ain't JPEG. - If an application wants to process non-JFIF files, it must seek to the - SOI before calling the JPEG library. } -var - c, c2 : int; -var - datasrc : jpeg_source_mgr_ptr; - next_input_byte : JOCTETptr; - bytes_in_buffer : size_t; -begin - datasrc := cinfo^.src; - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - - { Read a byte into variable c. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - first_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - { Read a byte into variable c2. If must suspend, return FALSE. } - { make a byte available. - Note we do *not* do INPUT_SYNC before calling fill_input_buffer, - but we must reload the local copies after a successful fill. } - if (bytes_in_buffer = 0) then - begin - if (not datasrc^.fill_input_buffer(cinfo)) then - begin - first_marker := FALSE; - exit; - end; - { Reload the local copies } - next_input_byte := datasrc^.next_input_byte; - bytes_in_buffer := datasrc^.bytes_in_buffer; - end; - Dec( bytes_in_buffer ); - - c2 := GETJOCTET(next_input_byte^); - Inc(next_input_byte); - - if (c <> $FF) or (c2 <> int(M_SOI)) then - ERREXIT2(j_common_ptr(cinfo), JERR_NO_SOI, c, c2); - - cinfo^.unread_marker := c2; - - { Unload the local copies --- do this only at a restart boundary } - datasrc^.next_input_byte := next_input_byte; - datasrc^.bytes_in_buffer := bytes_in_buffer; - - first_marker := TRUE; -end; { first_marker } - - -{ Read markers until SOS or EOI. - - Returns same codes as are defined for jpeg_consume_input: - JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. } - -{METHODDEF} -function read_markers (cinfo : j_decompress_ptr) : int; -begin - { Outer loop repeats once for each marker. } - repeat - { Collect the marker proper, unless we already did. } - { NB: first_marker() enforces the requirement that SOI appear first. } - if (cinfo^.unread_marker = 0) then - begin - if not cinfo^.marker^.saw_SOI then - begin - if not first_marker(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - end - else - begin - if not next_marker(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - end; - end; - { At this point cinfo^.unread_marker contains the marker code and the - input point is just past the marker proper, but before any parameters. - A suspension will cause us to return with this state still true. } - - case (cinfo^.unread_marker) of - M_SOI: - if not get_soi(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_SOF0, { Baseline } - M_SOF1: { Extended sequential, Huffman } - if not get_sof(cinfo, FALSE, FALSE) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - M_SOF2: { Progressive, Huffman } - if not get_sof(cinfo, TRUE, FALSE) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_SOF9: { Extended sequential, arithmetic } - if not get_sof(cinfo, FALSE, TRUE) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_SOF10: { Progressive, arithmetic } - if not get_sof(cinfo, TRUE, TRUE) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - { Currently unsupported SOFn types } - M_SOF3, { Lossless, Huffman } - M_SOF5, { Differential sequential, Huffman } - M_SOF6, { Differential progressive, Huffman } - M_SOF7, { Differential lossless, Huffman } - M_JPG, { Reserved for JPEG extensions } - M_SOF11, { Lossless, arithmetic } - M_SOF13, { Differential sequential, arithmetic } - M_SOF14, { Differential progressive, arithmetic } - M_SOF15: { Differential lossless, arithmetic } - ERREXIT1(j_common_ptr(cinfo), JERR_SOF_UNSUPPORTED, cinfo^.unread_marker); - - M_SOS: - begin - if not get_sos(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - cinfo^.unread_marker := 0; { processed the marker } - read_markers := JPEG_REACHED_SOS; - exit; - end; - - M_EOI: - begin - {$IFDEF DEBUG} - TRACEMS(j_common_ptr(cinfo), 1, JTRC_EOI); - {$ENDIF} - cinfo^.unread_marker := 0; { processed the marker } - read_markers := JPEG_REACHED_EOI; - exit; - end; - - M_DAC: - if not get_dac(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_DHT: - if not get_dht(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_DQT: - if not get_dqt(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_DRI: - if not get_dri(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_APP0, - M_APP1, - M_APP2, - M_APP3, - M_APP4, - M_APP5, - M_APP6, - M_APP7, - M_APP8, - M_APP9, - M_APP10, - M_APP11, - M_APP12, - M_APP13, - M_APP14, - M_APP15: - if not my_marker_ptr(cinfo^.marker)^. - process_APPn[cinfo^.unread_marker - int(M_APP0)](cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_COM: - if not my_marker_ptr(cinfo^.marker)^.process_COM (cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - M_RST0, { these are all parameterless } - M_RST1, - M_RST2, - M_RST3, - M_RST4, - M_RST5, - M_RST6, - M_RST7, - M_TEM: - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_PARMLESS_MARKER, - cinfo^.unread_marker) - {$ENDIF} - ; - - M_DNL: { Ignore DNL ... perhaps the wrong thing } - if not skip_variable(cinfo) then - begin - read_markers := JPEG_SUSPENDED; - exit; - end; - - else { must be DHP, EXP, JPGn, or RESn } - { For now, we treat the reserved markers as fatal errors since they are - likely to be used to signal incompatible JPEG Part 3 extensions. - Once the JPEG 3 version-number marker is well defined, this code - ought to change! } - ERREXIT1(j_common_ptr(cinfo) , JERR_UNKNOWN_MARKER, - cinfo^.unread_marker); - end; { end of case } - { Successfully processed marker, so reset state variable } - cinfo^.unread_marker := 0; - Until false; -end; { read_markers } - - -{ Read a restart marker, which is expected to appear next in the datastream; - if the marker is not there, take appropriate recovery action. - Returns FALSE if suspension is required. - - This is called by the entropy decoder after it has read an appropriate - number of MCUs. cinfo^.unread_marker may be nonzero if the entropy decoder - has already read a marker from the data source. Under normal conditions - cinfo^.unread_marker will be reset to 0 before returning; if not reset, - it holds a marker which the decoder will be unable to read past. } - -{METHODDEF} -function read_restart_marker (cinfo : j_decompress_ptr) :boolean; -begin - { Obtain a marker unless we already did. } - { Note that next_marker will complain if it skips any data. } - if (cinfo^.unread_marker = 0) then - begin - if not next_marker(cinfo) then - begin - read_restart_marker := FALSE; - exit; - end; - end; - - if (cinfo^.unread_marker = (int(M_RST0) + cinfo^.marker^.next_restart_num)) then - begin - { Normal case --- swallow the marker and let entropy decoder continue } - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 3, JTRC_RST, - cinfo^.marker^.next_restart_num); - {$ENDIF} - cinfo^.unread_marker := 0; - end - else - begin - { Uh-oh, the restart markers have been messed up. } - { Let the data source manager determine how to resync. } - if not cinfo^.src^.resync_to_restart(cinfo, - cinfo^.marker^.next_restart_num) then - begin - read_restart_marker := FALSE; - exit; - end; - end; - - { Update next-restart state } - with cinfo^.marker^ do - next_restart_num := (next_restart_num + 1) and 7; - - read_restart_marker := TRUE; -end; { read_restart_marker } - - -{ This is the default resync_to_restart method for data source managers - to use if they don't have any better approach. Some data source managers - may be able to back up, or may have additional knowledge about the data - which permits a more intelligent recovery strategy; such managers would - presumably supply their own resync method. - - read_restart_marker calls resync_to_restart if it finds a marker other than - the restart marker it was expecting. (This code is *not* used unless - a nonzero restart interval has been declared.) cinfo^.unread_marker is - the marker code actually found (might be anything, except 0 or FF). - The desired restart marker number (0..7) is passed as a parameter. - This routine is supposed to apply whatever error recovery strategy seems - appropriate in order to position the input stream to the next data segment. - Note that cinfo^.unread_marker is treated as a marker appearing before - the current data-source input point; usually it should be reset to zero - before returning. - Returns FALSE if suspension is required. - - This implementation is substantially constrained by wanting to treat the - input as a data stream; this means we can't back up. Therefore, we have - only the following actions to work with: - 1. Simply discard the marker and let the entropy decoder resume at next - byte of file. - 2. Read forward until we find another marker, discarding intervening - data. (In theory we could look ahead within the current bufferload, - without having to discard data if we don't find the desired marker. - This idea is not implemented here, in part because it makes behavior - dependent on buffer size and chance buffer-boundary positions.) - 3. Leave the marker unread (by failing to zero cinfo^.unread_marker). - This will cause the entropy decoder to process an empty data segment, - inserting dummy zeroes, and then we will reprocess the marker. - - #2 is appropriate if we think the desired marker lies ahead, while #3 is - appropriate if the found marker is a future restart marker (indicating - that we have missed the desired restart marker, probably because it got - corrupted). - We apply #2 or #3 if the found marker is a restart marker no more than - two counts behind or ahead of the expected one. We also apply #2 if the - found marker is not a legal JPEG marker code (it's certainly bogus data). - If the found marker is a restart marker more than 2 counts away, we do #1 - (too much risk that the marker is erroneous; with luck we will be able to - resync at some future point). - For any valid non-restart JPEG marker, we apply #3. This keeps us from - overrunning the end of a scan. An implementation limited to single-scan - files might find it better to apply #2 for markers other than EOI, since - any other marker would have to be bogus data in that case. } - - -{GLOBAL} -function jpeg_resync_to_restart(cinfo : j_decompress_ptr; - desired : int) : boolean; -var - marker : int; - action : int; -begin - marker := cinfo^.unread_marker; - //action := 1; { never used } - { Always put up a warning. } - WARNMS2(j_common_ptr(cinfo), JWRN_MUST_RESYNC, marker, desired); - - { Outer loop handles repeated decision after scanning forward. } - repeat - if (marker < int(M_SOF0)) then - action := 2 { invalid marker } - else - if (marker < int(M_RST0)) or (marker > int(M_RST7)) then - action := 3 { valid non-restart marker } - else - begin - if (marker = (int(M_RST0) + ((desired+1) and 7))) or - (marker = (int(M_RST0) + ((desired+2) and 7))) then - action := 3 { one of the next two expected restarts } - else - if (marker = (int(M_RST0) + ((desired-1) and 7))) or - (marker = (int(M_RST0) + ((desired-2) and 7))) then - action := 2 { a prior restart, so advance } - else - action := 1; { desired restart or too far away } - end; - - {$IFDEF DEBUG} - TRACEMS2(j_common_ptr(cinfo), 4, JTRC_RECOVERY_ACTION, marker, action); - {$ENDIF} - case action of - 1: - { Discard marker and let entropy decoder resume processing. } - begin - cinfo^.unread_marker := 0; - jpeg_resync_to_restart := TRUE; - exit; - end; - 2: - { Scan to the next marker, and repeat the decision loop. } - begin - if not next_marker(cinfo) then - begin - jpeg_resync_to_restart := FALSE; - exit; - end; - marker := cinfo^.unread_marker; - end; - 3: - { Return without advancing past this marker. } - { Entropy decoder will be forced to process an empty segment. } - begin - jpeg_resync_to_restart := TRUE; - exit; - end; - end; { case } - Until false; { end loop } -end; { jpeg_resync_to_restart } - - -{ Reset marker processing state to begin a fresh datastream. } - -{METHODDEF} -procedure reset_marker_reader (cinfo : j_decompress_ptr); -var - marker : my_marker_ptr; -begin - marker := my_marker_ptr (cinfo^.marker); - with cinfo^ do - begin - comp_info := NIL; { until allocated by get_sof } - input_scan_number := 0; { no SOS seen yet } - unread_marker := 0; { no pending marker } - end; - marker^.pub.saw_SOI := FALSE; { set internal state too } - marker^.pub.saw_SOF := FALSE; - marker^.pub.discarded_bytes := 0; - marker^.cur_marker := NIL; -end; { reset_marker_reader } - - -{ Initialize the marker reader module. - This is called only once, when the decompression object is created. } - -{GLOBAL} -procedure jinit_marker_reader (cinfo : j_decompress_ptr); -var - marker : my_marker_ptr; - i : int; -begin - { Create subobject in permanent pool } - marker := my_marker_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_PERMANENT, - SIZEOF(my_marker_reader)) - ); - cinfo^.marker := jpeg_marker_reader_ptr(marker); - { Initialize method pointers } - marker^.pub.reset_marker_reader := reset_marker_reader; - marker^.pub.read_markers := read_markers; - marker^.pub.read_restart_marker := read_restart_marker; - { Initialize COM/APPn processing. - By default, we examine and then discard APP0 and APP14, - but simply discard COM and all other APPn. } - - marker^.process_COM := skip_variable; - marker^.length_limit_COM := 0; - for i := 0 to 16-1 do - begin - marker^.process_APPn[i] := skip_variable; - marker^.length_limit_APPn[i] := 0; - end; - marker^.process_APPn[0] := get_interesting_appn; - marker^.process_APPn[14] := get_interesting_appn; - { Reset marker processing state } - reset_marker_reader(cinfo); -end; { jinit_marker_reader } - - -{ Control saving of COM and APPn markers into marker_list. } - - -{$ifdef SAVE_MARKERS_SUPPORTED} - -{GLOBAL} -procedure jpeg_save_markers (cinfo : j_decompress_ptr; - marker_code : int; - length_limit : uint); -var - marker : my_marker_ptr; - maxlength : long; - processor : jpeg_marker_parser_method; -begin - marker := my_marker_ptr (cinfo^.marker); - - { Length limit mustn't be larger than what we can allocate - (should only be a concern in a 16-bit environment). } - - maxlength := cinfo^.mem^.max_alloc_chunk - SIZEOF(jpeg_marker_struct); - if (long(length_limit) > maxlength) then - length_limit := uint(maxlength); - - { Choose processor routine to use. - APP0/APP14 have special requirements. } - - if (length_limit <> 0) then - begin - processor := save_marker; - { If saving APP0/APP14, save at least enough for our internal use. } - if (marker_code = int(M_APP0)) and (length_limit < APP0_DATA_LEN) then - length_limit := APP0_DATA_LEN - else - if (marker_code = int(M_APP14)) and (length_limit < APP14_DATA_LEN) then - length_limit := APP14_DATA_LEN; - end - else - begin - processor := skip_variable; - { If discarding APP0/APP14, use our regular on-the-fly processor. } - if (marker_code = int(M_APP0)) or (marker_code = int(M_APP14)) then - processor := get_interesting_appn; - end; - - if (marker_code = int(M_COM)) then - begin - marker^.process_COM := processor; - marker^.length_limit_COM := length_limit; - end - else - if (marker_code >= int(M_APP0)) and (marker_code <= int(M_APP15)) then - begin - marker^.process_APPn[marker_code - int(M_APP0)] := processor; - marker^.length_limit_APPn[marker_code - int(M_APP0)] := length_limit; - end - else - ERREXIT1(j_common_ptr(cinfo), JERR_UNKNOWN_MARKER, marker_code); -end; - -{$endif} { SAVE_MARKERS_SUPPORTED } - -{ Install a special processing method for COM or APPn markers. } - -{GLOBAL} - -procedure jpeg_set_marker_processor (cinfo : j_decompress_ptr; - marker_code : int; - routine : jpeg_marker_parser_method); -var - marker : my_marker_ptr; -begin - marker := my_marker_ptr (cinfo^.marker); - if (marker_code = int(M_COM)) then - marker^.process_COM := routine - else - if (marker_code >= int(M_APP0)) and (marker_code <= int(M_APP15)) then - marker^.process_APPn[marker_code - int(M_APP0)] := routine - else - ERREXIT1(j_common_ptr(cinfo), JERR_UNKNOWN_MARKER, marker_code); -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdmaster.pas b/3rd/Imaging/Source/JpegLib/imjdmaster.pas deleted file mode 100644 index 076eeec70..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdmaster.pas +++ /dev/null @@ -1,679 +0,0 @@ -unit imjdmaster; - -{ This file contains master control logic for the JPEG decompressor. - These routines are concerned with selecting the modules to be executed - and with determining the number of passes and the work to be done in each - pass. } - -{ Original: jdmaster.c ; Copyright (C) 1991-1998, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjutils, - imjerror, - imjdeferr, - imjdcolor, imjdsample, imjdpostct, imjddctmgr, imjdphuff, - imjdhuff, imjdcoefct, imjdmainct, -{$ifdef QUANT_1PASS_SUPPORTED} - imjquant1, -{$endif} -{$ifdef QUANT_2PASS_SUPPORTED} - imjquant2, -{$endif} -{$ifdef UPSAMPLE_MERGING_SUPPORTED} - imjdmerge, -{$endif} - imjpeglib; - - -{ Compute output image dimensions and related values. - NOTE: this is exported for possible use by application. - Hence it mustn't do anything that can't be done twice. - Also note that it may be called before the master module is initialized! } - -{GLOBAL} -procedure jpeg_calc_output_dimensions (cinfo : j_decompress_ptr); -{ Do computations that are needed before master selection phase } - - -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - -{GLOBAL} -procedure jpeg_new_colormap (cinfo : j_decompress_ptr); - -{$endif} - -{ Initialize master decompression control and select active modules. - This is performed at the start of jpeg_start_decompress. } - -{GLOBAL} -procedure jinit_master_decompress (cinfo : j_decompress_ptr); - -implementation - -{ Private state } - -type - my_master_ptr = ^my_decomp_master; - my_decomp_master = record - pub : jpeg_decomp_master; { public fields } - - pass_number : int; { # of passes completed } - - using_merged_upsample : boolean; { TRUE if using merged upsample/cconvert } - - { Saved references to initialized quantizer modules, - in case we need to switch modes. } - - quantizer_1pass : jpeg_color_quantizer_ptr; - quantizer_2pass : jpeg_color_quantizer_ptr; - end; - -{ Determine whether merged upsample/color conversion should be used. - CRUCIAL: this must match the actual capabilities of jdmerge.c! } - -{LOCAL} -function use_merged_upsample (cinfo : j_decompress_ptr) : boolean; -var - compptr : jpeg_component_info_list_ptr; -begin - compptr := cinfo^.comp_info; - -{$ifdef UPSAMPLE_MERGING_SUPPORTED} - { Merging is the equivalent of plain box-filter upsampling } - if (cinfo^.do_fancy_upsampling) or (cinfo^.CCIR601_sampling) then - begin - use_merged_upsample := FALSE; - exit; - end; - { jdmerge.c only supports YCC=>RGB color conversion } - if (cinfo^.jpeg_color_space <> JCS_YCbCr) or (cinfo^.num_components <> 3) - or (cinfo^.out_color_space <> JCS_RGB) - or (cinfo^.out_color_components <> RGB_PIXELSIZE) then - begin - use_merged_upsample := FALSE; - exit; - end; - - { and it only handles 2h1v or 2h2v sampling ratios } - if (compptr^[0].h_samp_factor <> 2) or - (compptr^[1].h_samp_factor <> 1) or - (compptr^[2].h_samp_factor <> 1) or - (compptr^[0].v_samp_factor > 2) or - (compptr^[1].v_samp_factor <> 1) or - (compptr^[2].v_samp_factor <> 1) then - begin - use_merged_upsample := FALSE; - exit; - end; - { furthermore, it doesn't work if we've scaled the IDCTs differently } - if (compptr^[0].DCT_scaled_size <> cinfo^.min_DCT_scaled_size) or - (compptr^[1].DCT_scaled_size <> cinfo^.min_DCT_scaled_size) or - (compptr^[2].DCT_scaled_size <> cinfo^.min_DCT_scaled_size) then - begin - use_merged_upsample := FALSE; - exit; - end; - { ??? also need to test for upsample-time rescaling, when & if supported } - use_merged_upsample := TRUE; { by golly, it'll work... } -{$else} - use_merged_upsample := FALSE; -{$endif} -end; - - -{ Compute output image dimensions and related values. - NOTE: this is exported for possible use by application. - Hence it mustn't do anything that can't be done twice. - Also note that it may be called before the master module is initialized! } - -{GLOBAL} -procedure jpeg_calc_output_dimensions (cinfo : j_decompress_ptr); -{ Do computations that are needed before master selection phase } -{$ifdef IDCT_SCALING_SUPPORTED} -var - ci : int; - compptr : jpeg_component_info_ptr; -{$endif} -var - ssize : int; -begin - { Prevent application from calling me at wrong times } - if (cinfo^.global_state <> DSTATE_READY) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - -{$ifdef IDCT_SCALING_SUPPORTED} - - { Compute actual output image dimensions and DCT scaling choices. } - if (cinfo^.scale_num * 8 <= cinfo^.scale_denom) then - begin - { Provide 1/8 scaling } - cinfo^.output_width := JDIMENSION ( - jdiv_round_up( long(cinfo^.image_width), long(8)) ); - cinfo^.output_height := JDIMENSION ( - jdiv_round_up( long(cinfo^.image_height), long(8)) ); - cinfo^.min_DCT_scaled_size := 1; - end - else - if (cinfo^.scale_num * 4 <= cinfo^.scale_denom) then - begin - { Provide 1/4 scaling } - cinfo^.output_width := JDIMENSION ( - jdiv_round_up( long (cinfo^.image_width), long(4)) ); - cinfo^.output_height := JDIMENSION ( - jdiv_round_up( long (cinfo^.image_height), long(4)) ); - cinfo^.min_DCT_scaled_size := 2; - end - else - if (cinfo^.scale_num * 2 <= cinfo^.scale_denom) then - begin - { Provide 1/2 scaling } - cinfo^.output_width := JDIMENSION ( - jdiv_round_up( long(cinfo^.image_width), long(2)) ); - cinfo^.output_height := JDIMENSION ( - jdiv_round_up( long(cinfo^.image_height), long(2)) ); - cinfo^.min_DCT_scaled_size := 4; - end - else - begin - { Provide 1/1 scaling } - cinfo^.output_width := cinfo^.image_width; - cinfo^.output_height := cinfo^.image_height; - cinfo^.min_DCT_scaled_size := DCTSIZE; - end; - { In selecting the actual DCT scaling for each component, we try to - scale up the chroma components via IDCT scaling rather than upsampling. - This saves time if the upsampler gets to use 1:1 scaling. - Note this code assumes that the supported DCT scalings are powers of 2. } - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - ssize := cinfo^.min_DCT_scaled_size; - while (ssize < DCTSIZE) and - ((compptr^.h_samp_factor * ssize * 2 <= - cinfo^.max_h_samp_factor * cinfo^.min_DCT_scaled_size) and - (compptr^.v_samp_factor * ssize * 2 <= - cinfo^.max_v_samp_factor * cinfo^.min_DCT_scaled_size)) do - begin - ssize := ssize * 2; - end; - compptr^.DCT_scaled_size := ssize; - Inc(compptr); - end; - - { Recompute downsampled dimensions of components; - application needs to know these if using raw downsampled data. } - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Size in samples, after IDCT scaling } - compptr^.downsampled_width := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_width) * - long (compptr^.h_samp_factor * compptr^.DCT_scaled_size), - long (cinfo^.max_h_samp_factor * DCTSIZE)) ); - compptr^.downsampled_height := JDIMENSION ( - jdiv_round_up(long (cinfo^.image_height) * - long (compptr^.v_samp_factor * compptr^.DCT_scaled_size), - long (cinfo^.max_v_samp_factor * DCTSIZE)) ); - Inc(compptr); - end; - -{$else} { !IDCT_SCALING_SUPPORTED } - - { Hardwire it to "no scaling" } - cinfo^.output_width := cinfo^.image_width; - cinfo^.output_height := cinfo^.image_height; - { jdinput.c has already initialized DCT_scaled_size to DCTSIZE, - and has computed unscaled downsampled_width and downsampled_height. } - -{$endif} { IDCT_SCALING_SUPPORTED } - - { Report number of components in selected colorspace. } - { Probably this should be in the color conversion module... } - case (cinfo^.out_color_space) of - JCS_GRAYSCALE: - cinfo^.out_color_components := 1; -{$ifndef RGB_PIXELSIZE_IS_3} - JCS_RGB: - cinfo^.out_color_components := RGB_PIXELSIZE; -{$else} - JCS_RGB, -{$endif} { else share code with YCbCr } - JCS_YCbCr: - cinfo^.out_color_components := 3; - JCS_CMYK, - JCS_YCCK: - cinfo^.out_color_components := 4; - else { else must be same colorspace as in file } - cinfo^.out_color_components := cinfo^.num_components; - end; - if (cinfo^.quantize_colors) then - cinfo^.output_components := 1 - else - cinfo^.output_components := cinfo^.out_color_components; - - { See if upsampler will want to emit more than one row at a time } - if (use_merged_upsample(cinfo)) then - cinfo^.rec_outbuf_height := cinfo^.max_v_samp_factor - else - cinfo^.rec_outbuf_height := 1; -end; - - -{ Several decompression processes need to range-limit values to the range - 0..MAXJSAMPLE; the input value may fall somewhat outside this range - due to noise introduced by quantization, roundoff error, etc. These - processes are inner loops and need to be as fast as possible. On most - machines, particularly CPUs with pipelines or instruction prefetch, - a (subscript-check-less) C table lookup - x := sample_range_limit[x]; - is faster than explicit tests - if (x < 0) x := 0; - else if (x > MAXJSAMPLE) x := MAXJSAMPLE; - These processes all use a common table prepared by the routine below. - - For most steps we can mathematically guarantee that the initial value - of x is within MAXJSAMPLE+1 of the legal range, so a table running from - -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial - limiting step (just after the IDCT), a wildly out-of-range value is - possible if the input data is corrupt. To avoid any chance of indexing - off the end of memory and getting a bad-pointer trap, we perform the - post-IDCT limiting thus: - x := range_limit[x & MASK]; - where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit - samples. Under normal circumstances this is more than enough range and - a correct output will be generated; with bogus input data the mask will - cause wraparound, and we will safely generate a bogus-but-in-range output. - For the post-IDCT step, we want to convert the data from signed to unsigned - representation by adding CENTERJSAMPLE at the same time that we limit it. - So the post-IDCT limiting table ends up looking like this: - CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, - MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), - 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), - 0,1,...,CENTERJSAMPLE-1 - Negative inputs select values from the upper half of the table after - masking. - - We can save some space by overlapping the start of the post-IDCT table - with the simpler range limiting table. The post-IDCT table begins at - sample_range_limit + CENTERJSAMPLE. - - Note that the table is allocated in near data space on PCs; it's small - enough and used often enough to justify this. } - -{LOCAL} -procedure prepare_range_limit_table (cinfo : j_decompress_ptr); -{ Allocate and fill in the sample_range_limit table } -var - table : range_limit_table_ptr; - idct_table : JSAMPROW; - i : int; -begin - table := range_limit_table_ptr ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)) ); - - { First segment of "simple" table: limit[x] := 0 for x < 0 } - MEMZERO(table, (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); - - cinfo^.sample_range_limit := (table); - { allow negative subscripts of simple table } - { is noop, handled via type definition (Nomssi) } - { Main part of "simple" table: limit[x] := x } - for i := 0 to MAXJSAMPLE do - table^[i] := JSAMPLE (i); - idct_table := JSAMPROW(@ table^[CENTERJSAMPLE]); - { Point to where post-IDCT table starts } - { End of simple table, rest of first half of post-IDCT table } - for i := CENTERJSAMPLE to pred(2*(MAXJSAMPLE+1)) do - idct_table^[i] := MAXJSAMPLE; - { Second half of post-IDCT table } - MEMZERO(@(idct_table^[2 * (MAXJSAMPLE+1)]), - (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); - MEMCOPY(@(idct_table^[(4 * (MAXJSAMPLE+1) - CENTERJSAMPLE)]), - @cinfo^.sample_range_limit^[0], CENTERJSAMPLE * SIZEOF(JSAMPLE)); - -end; - - -{ Master selection of decompression modules. - This is done once at jpeg_start_decompress time. We determine - which modules will be used and give them appropriate initialization calls. - We also initialize the decompressor input side to begin consuming data. - - Since jpeg_read_header has finished, we know what is in the SOF - and (first) SOS markers. We also have all the application parameter - settings. } - -{LOCAL} -procedure master_selection (cinfo : j_decompress_ptr); -var - master : my_master_ptr; - use_c_buffer : boolean; - samplesperrow : long; - jd_samplesperrow : JDIMENSION; -var - nscans : int; -begin - master := my_master_ptr (cinfo^.master); - - { Initialize dimensions and other stuff } - jpeg_calc_output_dimensions(cinfo); - prepare_range_limit_table(cinfo); - - { Width of an output scanline must be representable as JDIMENSION. } - samplesperrow := long(cinfo^.output_width) * long (cinfo^.out_color_components); - jd_samplesperrow := JDIMENSION (samplesperrow); - if (long(jd_samplesperrow) <> samplesperrow) then - ERREXIT(j_common_ptr(cinfo), JERR_WIDTH_OVERFLOW); - - { Initialize my private state } - master^.pass_number := 0; - master^.using_merged_upsample := use_merged_upsample(cinfo); - - { Color quantizer selection } - master^.quantizer_1pass := NIL; - master^.quantizer_2pass := NIL; - { No mode changes if not using buffered-image mode. } - if (not cinfo^.quantize_colors) or (not cinfo^.buffered_image) then - begin - cinfo^.enable_1pass_quant := FALSE; - cinfo^.enable_external_quant := FALSE; - cinfo^.enable_2pass_quant := FALSE; - end; - if (cinfo^.quantize_colors) then - begin - if (cinfo^.raw_data_out) then - ERREXIT(j_common_ptr(cinfo), JERR_NOTIMPL); - { 2-pass quantizer only works in 3-component color space. } - if (cinfo^.out_color_components <> 3) then - begin - cinfo^.enable_1pass_quant := TRUE; - cinfo^.enable_external_quant := FALSE; - cinfo^.enable_2pass_quant := FALSE; - cinfo^.colormap := NIL; - end - else - if (cinfo^.colormap <> NIL) then - begin - cinfo^.enable_external_quant := TRUE; - end - else - if (cinfo^.two_pass_quantize) then - begin - cinfo^.enable_2pass_quant := TRUE; - end - else - begin - cinfo^.enable_1pass_quant := TRUE; - end; - - if (cinfo^.enable_1pass_quant) then - begin -{$ifdef QUANT_1PASS_SUPPORTED} - jinit_1pass_quantizer(cinfo); - master^.quantizer_1pass := cinfo^.cquantize; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end; - - { We use the 2-pass code to map to external colormaps. } - if (cinfo^.enable_2pass_quant) or (cinfo^.enable_external_quant) then - begin -{$ifdef QUANT_2PASS_SUPPORTED} - jinit_2pass_quantizer(cinfo); - master^.quantizer_2pass := cinfo^.cquantize; -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end; - { If both quantizers are initialized, the 2-pass one is left active; - this is necessary for starting with quantization to an external map. } - end; - - { Post-processing: in particular, color conversion first } - if (not cinfo^.raw_data_out) then - begin - if (master^.using_merged_upsample) then - begin -{$ifdef UPSAMPLE_MERGING_SUPPORTED} - jinit_merged_upsampler(cinfo); { does color conversion too } -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - begin - jinit_color_deconverter(cinfo); - jinit_upsampler(cinfo); - end; - jinit_d_post_controller(cinfo, cinfo^.enable_2pass_quant); - end; - { Inverse DCT } - jinit_inverse_dct(cinfo); - { Entropy decoding: either Huffman or arithmetic coding. } - if (cinfo^.arith_code) then - begin - ERREXIT(j_common_ptr(cinfo), JERR_ARITH_NOTIMPL); - end - else - begin - if (cinfo^.progressive_mode) then - begin -{$ifdef D_PROGRESSIVE_SUPPORTED} - jinit_phuff_decoder(cinfo); -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} - end - else - jinit_huff_decoder(cinfo); - end; - - { Initialize principal buffer controllers. } - use_c_buffer := cinfo^.inputctl^.has_multiple_scans or cinfo^.buffered_image; - jinit_d_coef_controller(cinfo, use_c_buffer); - - if (not cinfo^.raw_data_out) then - jinit_d_main_controller(cinfo, FALSE { never need full buffer here }); - - { We can now tell the memory manager to allocate virtual arrays. } - cinfo^.mem^.realize_virt_arrays (j_common_ptr(cinfo)); - - { Initialize input side of decompressor to consume first scan. } - cinfo^.inputctl^.start_input_pass (cinfo); - -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - { If jpeg_start_decompress will read the whole file, initialize - progress monitoring appropriately. The input step is counted - as one pass. } - - if (cinfo^.progress <> NIL) and (not cinfo^.buffered_image) and - (cinfo^.inputctl^.has_multiple_scans) then - begin - - { Estimate number of scans to set pass_limit. } - if (cinfo^.progressive_mode) then - begin - { Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. } - nscans := 2 + 3 * cinfo^.num_components; - end - else - begin - { For a nonprogressive multiscan file, estimate 1 scan per component. } - nscans := cinfo^.num_components; - end; - cinfo^.progress^.pass_counter := Long(0); - cinfo^.progress^.pass_limit := long (cinfo^.total_iMCU_rows) * nscans; - cinfo^.progress^.completed_passes := 0; - if cinfo^.enable_2pass_quant then - cinfo^.progress^.total_passes := 3 - else - cinfo^.progress^.total_passes := 2; - { Count the input pass as done } - Inc(master^.pass_number); - end; -{$endif} { D_MULTISCAN_FILES_SUPPORTED } -end; - - -{ Per-pass setup. - This is called at the beginning of each output pass. We determine which - modules will be active during this pass and give them appropriate - start_pass calls. We also set is_dummy_pass to indicate whether this - is a "real" output pass or a dummy pass for color quantization. - (In the latter case, jdapistd.c will crank the pass to completion.) } - -{METHODDEF} -procedure prepare_for_output_pass (cinfo : j_decompress_ptr); -var - master : my_master_ptr; -begin - master := my_master_ptr (cinfo^.master); - - if (master^.pub.is_dummy_pass) then - begin -{$ifdef QUANT_2PASS_SUPPORTED} - { Final pass of 2-pass quantization } - master^.pub.is_dummy_pass := FALSE; - cinfo^.cquantize^.start_pass (cinfo, FALSE); - cinfo^.post^.start_pass (cinfo, JBUF_CRANK_DEST); - cinfo^.main^.start_pass (cinfo, JBUF_CRANK_DEST); -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); -{$endif} { QUANT_2PASS_SUPPORTED } - end - else - begin - if (cinfo^.quantize_colors) and (cinfo^.colormap = NIL) then - begin - { Select new quantization method } - if (cinfo^.two_pass_quantize) and (cinfo^.enable_2pass_quant) then - begin - cinfo^.cquantize := master^.quantizer_2pass; - master^.pub.is_dummy_pass := TRUE; - end - else - if (cinfo^.enable_1pass_quant) then - begin - cinfo^.cquantize := master^.quantizer_1pass; - end - else - begin - ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE); - end; - end; - cinfo^.idct^.start_pass (cinfo); - cinfo^.coef^.start_output_pass (cinfo); - if (not cinfo^.raw_data_out) then - begin - if (not master^.using_merged_upsample) then - cinfo^.cconvert^.start_pass (cinfo); - cinfo^.upsample^.start_pass (cinfo); - if (cinfo^.quantize_colors) then - cinfo^.cquantize^.start_pass (cinfo, master^.pub.is_dummy_pass); - if master^.pub.is_dummy_pass then - cinfo^.post^.start_pass (cinfo, JBUF_SAVE_AND_PASS) - else - cinfo^.post^.start_pass (cinfo, JBUF_PASS_THRU); - cinfo^.main^.start_pass (cinfo, JBUF_PASS_THRU); - end; - end; - - { Set up progress monitor's pass info if present } - if (cinfo^.progress <> NIL) then - begin - cinfo^.progress^.completed_passes := master^.pass_number; - if master^.pub.is_dummy_pass then - cinfo^.progress^.total_passes := master^.pass_number + 2 - else - cinfo^.progress^.total_passes := master^.pass_number + 1; - { In buffered-image mode, we assume one more output pass if EOI not - yet reached, but no more passes if EOI has been reached. } - - if (cinfo^.buffered_image) and (not cinfo^.inputctl^.eoi_reached) then - begin - if cinfo^.enable_2pass_quant then - Inc(cinfo^.progress^.total_passes, 2) - else - Inc(cinfo^.progress^.total_passes, 1); - end; - end; -end; - - -{ Finish up at end of an output pass. } - -{METHODDEF} -procedure finish_output_pass (cinfo : j_decompress_ptr); -var - master : my_master_ptr; -begin - master := my_master_ptr (cinfo^.master); - - if (cinfo^.quantize_colors) then - cinfo^.cquantize^.finish_pass (cinfo); - Inc(master^.pass_number); -end; - - -{$ifdef D_MULTISCAN_FILES_SUPPORTED} - -{ Switch to a new external colormap between output passes. } - -{GLOBAL} -procedure jpeg_new_colormap (cinfo : j_decompress_ptr); -var - master : my_master_ptr; -begin - master := my_master_ptr (cinfo^.master); - - { Prevent application from calling me at wrong times } - if (cinfo^.global_state <> DSTATE_BUFIMAGE) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_STATE, cinfo^.global_state); - - if (cinfo^.quantize_colors) and (cinfo^.enable_external_quant) and - (cinfo^.colormap <> NIL) then - begin - { Select 2-pass quantizer for external colormap use } - cinfo^.cquantize := master^.quantizer_2pass; - { Notify quantizer of colormap change } - cinfo^.cquantize^.new_color_map (cinfo); - master^.pub.is_dummy_pass := FALSE; { just in case } - end - else - ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE); -end; - -{$endif} { D_MULTISCAN_FILES_SUPPORTED } - - -{ Initialize master decompression control and select active modules. - This is performed at the start of jpeg_start_decompress. } - -{GLOBAL} -procedure jinit_master_decompress (cinfo : j_decompress_ptr); -var - master : my_master_ptr; -begin - master := my_master_ptr ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_decomp_master)) ); - cinfo^.master := jpeg_decomp_master_ptr(master); - master^.pub.prepare_for_output_pass := prepare_for_output_pass; - master^.pub.finish_output_pass := finish_output_pass; - - master^.pub.is_dummy_pass := FALSE; - - master_selection(cinfo); -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdmerge.pas b/3rd/Imaging/Source/JpegLib/imjdmerge.pas deleted file mode 100644 index 3e9c7fbeb..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdmerge.pas +++ /dev/null @@ -1,514 +0,0 @@ -unit imjdmerge; - -{ This file contains code for merged upsampling/color conversion. - - This file combines functions from jdsample.c and jdcolor.c; - read those files first to understand what's going on. - - When the chroma components are to be upsampled by simple replication - (ie, box filtering), we can save some work in color conversion by - calculating all the output pixels corresponding to a pair of chroma - samples at one time. In the conversion equations - R := Y + K1 * Cr - G := Y + K2 * Cb + K3 * Cr - B := Y + K4 * Cb - only the Y term varies among the group of pixels corresponding to a pair - of chroma samples, so the rest of the terms can be calculated just once. - At typical sampling ratios, this eliminates half or three-quarters of the - multiplications needed for color conversion. - - This file currently provides implementations for the following cases: - YCbCr => RGB color conversion only. - Sampling ratios of 2h1v or 2h2v. - No scaling needed at upsample time. - Corner-aligned (non-CCIR601) sampling alignment. - Other special cases could be added, but in most applications these are - the only common cases. (For uncommon cases we fall back on the more - general code in jdsample.c and jdcolor.c.) } - -{ Original: jdmerge.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjutils; - -{ Module initialization routine for merged upsampling/color conversion. - - NB: this is called under the conditions determined by use_merged_upsample() - in jdmaster.c. That routine MUST correspond to the actual capabilities - of this module; no safety checks are made here. } - -{GLOBAL} -procedure jinit_merged_upsampler (cinfo : j_decompress_ptr); - -implementation - - -{ Private subobject } - -type { the same definition as in JdColor } - int_Color_Table = array[0..MAXJSAMPLE+1-1] of int; - int_CConvertPtr = ^int_Color_Table; - INT32_Color_Table = array[0..MAXJSAMPLE+1-1] of INT32; - INT32_CConvertPtr = ^INT32_Color_Table; - -type - my_upsample_ptr = ^my_upsampler; - my_upsampler = record - pub : jpeg_upsampler; { public fields } - - { Pointer to routine to do actual upsampling/conversion of one row group } - upmethod : procedure (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - in_row_group_ctr : JDIMENSION; - output_buf : JSAMPARRAY); - - { Private state for YCC->RGB conversion } - Cr_r_tab : int_CConvertPtr; { => table for Cr to R conversion } - Cb_b_tab : int_CConvertPtr; { => table for Cb to B conversion } - Cr_g_tab : INT32_CConvertPtr; { => table for Cr to G conversion } - Cb_g_tab : INT32_CConvertPtr; { => table for Cb to G conversion } - - { For 2:1 vertical sampling, we produce two output rows at a time. - We need a "spare" row buffer to hold the second output row if the - application provides just a one-row buffer; we also use the spare - to discard the dummy last row if the image height is odd. } - - spare_row : JSAMPROW; - spare_full : boolean; { TRUE if spare buffer is occupied } - - out_row_width : JDIMENSION; { samples per output row } - rows_to_go : JDIMENSION; { counts rows remaining in image } - end; {my_upsampler;} - - -const - SCALEBITS = 16; { speediest right-shift on some machines } - ONE_HALF = (INT32(1) shl (SCALEBITS-1)); - - -{ Initialize tables for YCC->RGB colorspace conversion. - This is taken directly from jdcolor.c; see that file for more info. } - -{LOCAL} -procedure build_ycc_rgb_table (cinfo : j_decompress_ptr); -const - FIX_1_40200 = INT32( Round(1.40200 * (INT32(1) shl SCALEBITS)) ); - FIX_1_77200 = INT32( Round(1.77200 * (INT32(1) shl SCALEBITS)) ); - FIX_0_71414 = INT32( Round(0.71414 * (INT32(1) shl SCALEBITS)) ); - FIX_0_34414 = INT32( Round(0.34414 * (INT32(1) shl SCALEBITS)) ); -var - upsample : my_upsample_ptr; - i : int; - x : INT32; -var - shift_temp : INT32; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - - upsample^.Cr_r_tab := int_CConvertPtr ( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)) ); - upsample^.Cb_b_tab := int_CConvertPtr ( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(int)) ); - upsample^.Cr_g_tab := INT32_CConvertPtr ( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)) ); - upsample^.Cb_g_tab := INT32_CConvertPtr ( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - (MAXJSAMPLE+1) * SIZEOF(INT32)) ); - - x := -CENTERJSAMPLE; - for i := 0 to pred(MAXJSAMPLE) do - begin - { i is the actual input pixel value, in the range 0..MAXJSAMPLE } - { The Cb or Cr value we are thinking of is x := i - CENTERJSAMPLE } - { Cr=>R value is nearest int to 1.40200 * x } - {upsample^.Cr_r_tab^[i] := int( - RIGHT_SHIFT(FIX_1_40200 * x + ONE_HALF, SCALEBITS) );} - shift_temp := FIX_1_40200 * x + ONE_HALF; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - upsample^.Cr_r_tab^[i] := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - upsample^.Cr_r_tab^[i] := int(shift_temp shr SCALEBITS); - - - { Cb=>B value is nearest int to 1.77200 * x } - {upsample^.Cb_b_tab^[i] := int( - RIGHT_SHIFT(FIX_1_77200 * x + ONE_HALF, SCALEBITS) );} - shift_temp := FIX_1_77200 * x + ONE_HALF; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - upsample^.Cb_b_tab^[i] := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - upsample^.Cb_b_tab^[i] := int(shift_temp shr SCALEBITS); - - { Cr=>G value is scaled-up -0.71414 * x } - upsample^.Cr_g_tab^[i] := (- FIX_0_71414) * x; - { Cb=>G value is scaled-up -0.34414 * x } - { We also add in ONE_HALF so that need not do it in inner loop } - upsample^.Cb_g_tab^[i] := (- FIX_0_34414) * x + ONE_HALF; - Inc(x); - end; -end; - - -{ Initialize for an upsampling pass. } - -{METHODDEF} -procedure start_pass_merged_upsample (cinfo : j_decompress_ptr); -var - upsample : my_upsample_ptr; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - - { Mark the spare buffer empty } - upsample^.spare_full := FALSE; - { Initialize total-height counter for detecting bottom of image } - upsample^.rows_to_go := cinfo^.output_height; -end; - - -{ Control routine to do upsampling (and color conversion). - - The control routine just handles the row buffering considerations. } - -{METHODDEF} -procedure merged_2v_upsample (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -{ 2:1 vertical sampling case: may need a spare row. } -var - upsample : my_upsample_ptr; - work_ptrs : array[0..2-1] of JSAMPROW; - num_rows : JDIMENSION; { number of rows returned to caller } -begin - upsample := my_upsample_ptr (cinfo^.upsample); - - if (upsample^.spare_full) then - begin - { If we have a spare row saved from a previous cycle, just return it. } - jcopy_sample_rows(JSAMPARRAY(@upsample^.spare_row), - 0, - JSAMPARRAY(@ output_buf^[out_row_ctr]), - 0, 1, upsample^.out_row_width); - num_rows := 1; - upsample^.spare_full := FALSE; - end - else - begin - { Figure number of rows to return to caller. } - num_rows := 2; - { Not more than the distance to the end of the image. } - if (num_rows > upsample^.rows_to_go) then - num_rows := upsample^.rows_to_go; - { And not more than what the client can accept: } - Dec(out_rows_avail, {var} out_row_ctr); - if (num_rows > out_rows_avail) then - num_rows := out_rows_avail; - { Create output pointer array for upsampler. } - work_ptrs[0] := output_buf^[out_row_ctr]; - if (num_rows > 1) then - begin - work_ptrs[1] := output_buf^[out_row_ctr + 1]; - end - else - begin - work_ptrs[1] := upsample^.spare_row; - upsample^.spare_full := TRUE; - end; - { Now do the upsampling. } - upsample^.upmethod (cinfo, input_buf, {var}in_row_group_ctr, - JSAMPARRAY(@work_ptrs)); - end; - - { Adjust counts } - Inc(out_row_ctr, num_rows); - Dec(upsample^.rows_to_go, num_rows); - { When the buffer is emptied, declare this input row group consumed } - if (not upsample^.spare_full) then - Inc(in_row_group_ctr); -end; - - -{METHODDEF} -procedure merged_1v_upsample (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -{ 1:1 vertical sampling case: much easier, never need a spare row. } -var - upsample : my_upsample_ptr; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - - { Just do the upsampling. } - upsample^.upmethod (cinfo, input_buf, in_row_group_ctr, - JSAMPARRAY(@ output_buf^[out_row_ctr])); - { Adjust counts } - Inc(out_row_ctr); - Inc(in_row_group_ctr); -end; - - -{ These are the routines invoked by the control routines to do - the actual upsampling/conversion. One row group is processed per call. - - Note: since we may be writing directly into application-supplied buffers, - we have to be honest about the output width; we can't assume the buffer - has been rounded up to an even width. } - - -{ Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical. } - -{METHODDEF} -procedure h2v1_merged_upsample (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - in_row_group_ctr : JDIMENSION; - output_buf : JSAMPARRAY); -var - upsample : my_upsample_ptr; - {register} y, cred, cgreen, cblue : int; - cb, cr : int; - {register} outptr : JSAMPROW; - inptr0, inptr1, inptr2 : JSAMPLE_PTR; - col : JDIMENSION; - { copy these pointers into registers if possible } - {register} range_limit : range_limit_table_ptr; - Crrtab : int_CConvertPtr; - Cbbtab : int_CConvertPtr; - Crgtab : INT32_CConvertPtr; - Cbgtab : INT32_CConvertPtr; -var - shift_temp : INT32; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - range_limit := cinfo^.sample_range_limit; - Crrtab := upsample^.Cr_r_tab; - Cbbtab := upsample^.Cb_b_tab; - Crgtab := upsample^.Cr_g_tab; - Cbgtab := upsample^.Cb_g_tab; - - inptr0 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr]); - inptr1 := JSAMPLE_PTR(input_buf^[1]^[in_row_group_ctr]); - inptr2 := JSAMPLE_PTR(input_buf^[2]^[in_row_group_ctr]); - outptr := output_buf^[0]; - { Loop for each pair of output pixels } - for col := pred(cinfo^.output_width shr 1) downto 0 do - begin - { Do the chroma part of the calculation } - cb := GETJSAMPLE(inptr1^); - Inc(inptr1); - cr := GETJSAMPLE(inptr2^); - Inc(inptr2); - cred := Crrtab^[cr]; - {cgreen := int( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );} - shift_temp := Cbgtab^[cb] + Crgtab^[cr]; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - cgreen := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - cgreen := int(shift_temp shr SCALEBITS); - - cblue := Cbbtab^[cb]; - { Fetch 2 Y values and emit 2 pixels } - y := GETJSAMPLE(inptr0^); - Inc(inptr0); - outptr^[RGB_RED] := range_limit^[y + cred]; - outptr^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr^[RGB_BLUE] := range_limit^[y + cblue]; - Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE); - y := GETJSAMPLE(inptr0^); - Inc(inptr0); - outptr^[RGB_RED] := range_limit^[y + cred]; - outptr^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr^[RGB_BLUE] := range_limit^[y + cblue]; - Inc(JSAMPLE_PTR(outptr), RGB_PIXELSIZE); - end; - { If image width is odd, do the last output column separately } - if Odd(cinfo^.output_width) then - begin - cb := GETJSAMPLE(inptr1^); - cr := GETJSAMPLE(inptr2^); - cred := Crrtab^[cr]; - {cgreen := int ( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );} - shift_temp := Cbgtab^[cb] + Crgtab^[cr]; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - cgreen := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - cgreen := int(shift_temp shr SCALEBITS); - - cblue := Cbbtab^[cb]; - y := GETJSAMPLE(inptr0^); - outptr^[RGB_RED] := range_limit^[y + cred]; - outptr^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr^[RGB_BLUE] := range_limit^[y + cblue]; - end; -end; - - -{ Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical. } - -{METHODDEF} -procedure h2v2_merged_upsample (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - in_row_group_ctr : JDIMENSION; - output_buf : JSAMPARRAY); -var - upsample : my_upsample_ptr; - {register} y, cred, cgreen, cblue : int; - cb, cr : int; - {register} outptr0, outptr1 : JSAMPROW; - inptr00, inptr01, inptr1, inptr2 : JSAMPLE_PTR; - col : JDIMENSION; - { copy these pointers into registers if possible } - {register} range_limit : range_limit_table_ptr; - Crrtab : int_CConvertPtr; - Cbbtab : int_CConvertPtr; - Crgtab : INT32_CConvertPtr; - Cbgtab : INT32_CConvertPtr; -var - shift_temp : INT32; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - range_limit := cinfo^.sample_range_limit; - Crrtab := upsample^.Cr_r_tab; - Cbbtab := upsample^.Cb_b_tab; - Crgtab := upsample^.Cr_g_tab; - Cbgtab := upsample^.Cb_g_tab; - - inptr00 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr*2]); - inptr01 := JSAMPLE_PTR(input_buf^[0]^[in_row_group_ctr*2 + 1]); - inptr1 := JSAMPLE_PTR(input_buf^[1]^[in_row_group_ctr]); - inptr2 := JSAMPLE_PTR(input_buf^[2]^[in_row_group_ctr]); - outptr0 := output_buf^[0]; - outptr1 := output_buf^[1]; - { Loop for each group of output pixels } - for col := pred(cinfo^.output_width shr 1) downto 0 do - begin - { Do the chroma part of the calculation } - cb := GETJSAMPLE(inptr1^); - Inc(inptr1); - cr := GETJSAMPLE(inptr2^); - Inc(inptr2); - cred := Crrtab^[cr]; - {cgreen := int( RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS) );} - shift_temp := Cbgtab^[cb] + Crgtab^[cr]; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - cgreen := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - cgreen := int(shift_temp shr SCALEBITS); - - cblue := Cbbtab^[cb]; - { Fetch 4 Y values and emit 4 pixels } - y := GETJSAMPLE(inptr00^); - Inc(inptr00); - outptr0^[RGB_RED] := range_limit^[y + cred]; - outptr0^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr0^[RGB_BLUE] := range_limit^[y + cblue]; - Inc(JSAMPLE_PTR(outptr0), RGB_PIXELSIZE); - y := GETJSAMPLE(inptr00^); - Inc(inptr00); - outptr0^[RGB_RED] := range_limit^[y + cred]; - outptr0^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr0^[RGB_BLUE] := range_limit^[y + cblue]; - Inc(JSAMPLE_PTR(outptr0), RGB_PIXELSIZE); - y := GETJSAMPLE(inptr01^); - Inc(inptr01); - outptr1^[RGB_RED] := range_limit^[y + cred]; - outptr1^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr1^[RGB_BLUE] := range_limit^[y + cblue]; - Inc(JSAMPLE_PTR(outptr1), RGB_PIXELSIZE); - y := GETJSAMPLE(inptr01^); - Inc(inptr01); - outptr1^[RGB_RED] := range_limit^[y + cred]; - outptr1^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr1^[RGB_BLUE] := range_limit^[y + cblue]; - Inc(JSAMPLE_PTR(outptr1), RGB_PIXELSIZE); - end; - { If image width is odd, do the last output column separately } - if Odd(cinfo^.output_width) then - begin - cb := GETJSAMPLE(inptr1^); - cr := GETJSAMPLE(inptr2^); - cred := Crrtab^[cr]; - {cgreen := int (RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS));} - shift_temp := Cbgtab^[cb] + Crgtab^[cr]; - if shift_temp < 0 then { SHIFT arithmetic RIGHT } - cgreen := int((shift_temp shr SCALEBITS) - or ( (not INT32(0)) shl (32-SCALEBITS))) - else - cgreen := int(shift_temp shr SCALEBITS); - - cblue := Cbbtab^[cb]; - y := GETJSAMPLE(inptr00^); - outptr0^[RGB_RED] := range_limit^[y + cred]; - outptr0^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr0^[RGB_BLUE] := range_limit^[y + cblue]; - y := GETJSAMPLE(inptr01^); - outptr1^[RGB_RED] := range_limit^[y + cred]; - outptr1^[RGB_GREEN] := range_limit^[y + cgreen]; - outptr1^[RGB_BLUE] := range_limit^[y + cblue]; - end; -end; - - -{ Module initialization routine for merged upsampling/color conversion. - - NB: this is called under the conditions determined by use_merged_upsample() - in jdmaster.c. That routine MUST correspond to the actual capabilities - of this module; no safety checks are made here. } - - -{GLOBAL} -procedure jinit_merged_upsampler (cinfo : j_decompress_ptr); -var - upsample : my_upsample_ptr; -begin - upsample := my_upsample_ptr ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_upsampler)) ); - cinfo^.upsample := jpeg_upsampler_ptr (upsample); - upsample^.pub.start_pass := start_pass_merged_upsample; - upsample^.pub.need_context_rows := FALSE; - - upsample^.out_row_width := cinfo^.output_width * JDIMENSION(cinfo^.out_color_components); - - if (cinfo^.max_v_samp_factor = 2) then - begin - upsample^.pub.upsample := merged_2v_upsample; - upsample^.upmethod := h2v2_merged_upsample; - { Allocate a spare row buffer } - upsample^.spare_row := JSAMPROW( - cinfo^.mem^.alloc_large ( j_common_ptr(cinfo), JPOOL_IMAGE, - size_t (upsample^.out_row_width * SIZEOF(JSAMPLE))) ); - end - else - begin - upsample^.pub.upsample := merged_1v_upsample; - upsample^.upmethod := h2v1_merged_upsample; - { No spare row needed } - upsample^.spare_row := NIL; - end; - - build_ycc_rgb_table(cinfo); -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdphuff.pas b/3rd/Imaging/Source/JpegLib/imjdphuff.pas deleted file mode 100644 index 4fa4d76ac..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdphuff.pas +++ /dev/null @@ -1,1065 +0,0 @@ -unit imjdphuff; - -{ This file contains Huffman entropy decoding routines for progressive JPEG. - - Much of the complexity here has to do with supporting input suspension. - If the data source module demands suspension, we want to be able to back - up to the start of the current MCU. To do this, we copy state variables - into local working storage, and update them back to the permanent - storage only upon successful completion of an MCU. } - -{ Original: jdphuff.c ; Copyright (C) 1995-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdeferr, - imjerror, - imjutils, - imjdhuff; { Declarations shared with jdhuff.c } - - -{GLOBAL} -procedure jinit_phuff_decoder (cinfo : j_decompress_ptr); - -implementation - -{ Expanded entropy decoder object for progressive Huffman decoding. - - The savable_state subrecord contains fields that change within an MCU, - but must not be updated permanently until we complete the MCU. } - -type - savable_state = record - EOBRUN : uInt; { remaining EOBs in EOBRUN } - last_dc_val : array[00..MAX_COMPS_IN_SCAN-1] of int; - { last DC coef for each component } - end; - - -type - phuff_entropy_ptr = ^phuff_entropy_decoder; - phuff_entropy_decoder = record - pub : jpeg_entropy_decoder; { public fields } - - { These fields are loaded into local variables at start of each MCU. - In case of suspension, we exit WITHOUT updating them. } - - bitstate : bitread_perm_state; { Bit buffer at start of MCU } - saved : savable_state; { Other state at start of MCU } - - { These fields are NOT loaded into local working state. } - restarts_to_go : uInt; { MCUs left in this restart interval } - - { Pointers to derived tables (these workspaces have image lifespan) } - derived_tbls : array[0..NUM_HUFF_TBLS-1] of d_derived_tbl_ptr; - - ac_derived_tbl : d_derived_tbl_ptr; { active table during an AC scan } - end; - - - -{ Forward declarations } -{METHODDEF} -function decode_mcu_DC_first (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -function decode_mcu_AC_first (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -function decode_mcu_DC_refine (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; - forward; -{METHODDEF} -function decode_mcu_AC_refine (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; - forward; - -{ Initialize for a Huffman-compressed scan. } - -{METHODDEF} -procedure start_pass_phuff_decoder (cinfo : j_decompress_ptr); -var - entropy : phuff_entropy_ptr; - is_DC_band, bad : boolean; - ci, coefi, tbl : int; - coef_bit_ptr : coef_bits_ptr; - compptr : jpeg_component_info_ptr; -var - cindex : int; - expected : int; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - - is_DC_band := (cinfo^.Ss = 0); - - { Validate scan parameters } - bad := FALSE; - if (is_DC_band) then - begin - if (cinfo^.Se <> 0) then - bad := TRUE; - end - else - begin - { need not check Ss/Se < 0 since they came from unsigned bytes } - if (cinfo^.Ss > cinfo^.Se) or (cinfo^.Se >= DCTSIZE2) then - bad := TRUE; - { AC scans may have only one component } - if (cinfo^.comps_in_scan <> 1) then - bad := TRUE; - end; - if (cinfo^.Ah <> 0) then - begin - { Successive approximation refinement scan: must have Al = Ah-1. } - if (cinfo^.Al <> cinfo^.Ah-1) then - bad := TRUE; - end; - if (cinfo^.Al > 13) then { need not check for < 0 } - bad := TRUE; - { Arguably the maximum Al value should be less than 13 for 8-bit precision, - but the spec doesn't say so, and we try to be liberal about what we - accept. Note: large Al values could result in out-of-range DC - coefficients during early scans, leading to bizarre displays due to - overflows in the IDCT math. But we won't crash. } - - if (bad) then - ERREXIT4(j_common_ptr(cinfo), JERR_BAD_PROGRESSION, - cinfo^.Ss, cinfo^.Se, cinfo^.Ah, cinfo^.Al); - { Update progression status, and verify that scan order is legal. - Note that inter-scan inconsistencies are treated as warnings - not fatal errors ... not clear if this is right way to behave. } - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - cindex := cinfo^.cur_comp_info[ci]^.component_index; - coef_bit_ptr := coef_bits_ptr(@(cinfo^.coef_bits^[cindex])); {^[0] ??? - Nomssi } - if (not is_DC_band) and (coef_bit_ptr^[0] < 0) then - { AC without prior DC scan } - WARNMS2(j_common_ptr(cinfo), JWRN_BOGUS_PROGRESSION, cindex, 0); - for coefi := cinfo^.Ss to cinfo^.Se do - begin - if (coef_bit_ptr^[coefi] < 0) then - expected := 0 - else - expected := coef_bit_ptr^[coefi]; - if (cinfo^.Ah <> expected) then - WARNMS2(j_common_ptr(cinfo), JWRN_BOGUS_PROGRESSION, cindex, coefi); - coef_bit_ptr^[coefi] := cinfo^.Al; - end; - end; - - { Select MCU decoding routine } - if (cinfo^.Ah = 0) then - begin - if (is_DC_band) then - entropy^.pub.decode_mcu := decode_mcu_DC_first - else - entropy^.pub.decode_mcu := decode_mcu_AC_first; - end - else - begin - if (is_DC_band) then - entropy^.pub.decode_mcu := decode_mcu_DC_refine - else - entropy^.pub.decode_mcu := decode_mcu_AC_refine; - end; - - for ci := 0 to pred(cinfo^.comps_in_scan) do - begin - compptr := cinfo^.cur_comp_info[ci]; - { Make sure requested tables are present, and compute derived tables. - We may build same derived table more than once, but it's not expensive. } - - if (is_DC_band) then - begin - if (cinfo^.Ah = 0) then - begin { DC refinement needs no table } - tbl := compptr^.dc_tbl_no; - jpeg_make_d_derived_tbl(cinfo, TRUE, tbl, - entropy^.derived_tbls[tbl]); - end; - end - else - begin - tbl := compptr^.ac_tbl_no; - jpeg_make_d_derived_tbl(cinfo, FALSE, tbl, - entropy^.derived_tbls[tbl]); - { remember the single active table } - entropy^.ac_derived_tbl := entropy^.derived_tbls[tbl]; - end; - { Initialize DC predictions to 0 } - entropy^.saved.last_dc_val[ci] := 0; - end; - - { Initialize bitread state variables } - entropy^.bitstate.bits_left := 0; - entropy^.bitstate.get_buffer := 0; { unnecessary, but keeps Purify quiet } - entropy^.pub.insufficient_data := FALSE; - - { Initialize private state variables } - entropy^.saved.EOBRUN := 0; - - { Initialize restart counter } - entropy^.restarts_to_go := cinfo^.restart_interval; -end; - - -{ Figure F.12: extend sign bit. - On some machines, a shift and add will be faster than a table lookup. } - -{$ifdef AVOID_TABLES} - -#define HUFF_EXTEND(x,s) - ((x) < (1shl((s)-1)) ? (x) + (((-1)shl(s)) + 1) : (x)) - -{$else} - -{ #define HUFF_EXTEND(x,s) - if (x) < extend_test[s] then - (x) + extend_offset[s] - else - (x)} - -const - extend_test : Array[0..16-1] of int = { entry n is 2**(n-1) } - ($0000, $0001, $0002, $0004, $0008, $0010, $0020, $0040, - $0080, $0100, $0200, $0400, $0800, $1000, $2000, $4000); - -const - extend_offset : array[0..16-1] of int = { entry n is (-1 shl n) + 1 } - ( 0, ((-1) shl 1) + 1, ((-1) shl 2) + 1, ((-1) shl 3) + 1, ((-1) shl 4) + 1, - ((-1) shl 5) + 1, ((-1) shl 6) + 1, ((-1) shl 7) + 1, ((-1) shl 8) + 1, - ((-1) shl 9) + 1, ((-1) shl 10) + 1, ((-1) shl 11) + 1, ((-1) shl 12) + 1, - ((-1) shl 13) + 1, ((-1) shl 14) + 1, ((-1) shl 15) + 1 ); - -{$endif} { AVOID_TABLES } - - -{ Check for a restart marker & resynchronize decoder. - return:=s FALSE if must suspend. } - -{LOCAL} -function process_restart (cinfo : j_decompress_ptr) : boolean; -var - entropy : phuff_entropy_ptr; - ci : int; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - - { Throw away any unused bits remaining in bit buffer; } - { include any full bytes in next_marker's count of discarded bytes } - Inc(cinfo^.marker^.discarded_bytes, entropy^.bitstate.bits_left div 8); - entropy^.bitstate.bits_left := 0; - - { Advance past the RSTn marker } - if (not cinfo^.marker^.read_restart_marker (cinfo)) then - begin - process_restart := FALSE; - exit; - end; - - { Re-initialize DC predictions to 0 } - for ci := 0 to pred(cinfo^.comps_in_scan) do - entropy^.saved.last_dc_val[ci] := 0; - { Re-init EOB run count, too } - entropy^.saved.EOBRUN := 0; - - { Reset restart counter } - entropy^.restarts_to_go := cinfo^.restart_interval; - - { Reset out-of-data flag, unless read_restart_marker left us smack up - against a marker. In that case we will end up treating the next data - segment as empty, and we can avoid producing bogus output pixels by - leaving the flag set. } - if (cinfo^.unread_marker = 0) then - entropy^.pub.insufficient_data := FALSE; - - process_restart := TRUE; -end; - - -{ Huffman MCU decoding. - Each of these routines decodes and returns one MCU's worth of - Huffman-compressed coefficients. - The coefficients are reordered from zigzag order into natural array order, - but are not dequantized. - - The i'th block of the MCU is stored into the block pointed to by - MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER. - - We return FALSE if data source requested suspension. In that case no - changes have been made to permanent state. (Exception: some output - coefficients may already have been assigned. This is harmless for - spectral selection, since we'll just re-assign them on the next call. - Successive approximation AC refinement has to be more careful, however.) } - - -{ MCU decoding for DC initial scan (either spectral selection, - or first pass of successive approximation). } - -{METHODDEF} -function decode_mcu_DC_first (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; -label - label1; -var - entropy : phuff_entropy_ptr; - Al : int; - {register} s, r : int; - blkn, ci : int; - block : JBLOCK_PTR; - {BITREAD_STATE_VARS;} - get_buffer : bit_buf_type ; {register} - bits_left : int; {register} - br_state : bitread_working_state; - - state : savable_state; - tbl : d_derived_tbl_ptr; - compptr : jpeg_component_info_ptr; -var - nb, look : int; {register} -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - Al := cinfo^.Al; - - { Process restart marker if needed; may have to suspend } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - if (not process_restart(cinfo)) then - begin - decode_mcu_DC_first := FALSE; - exit; - end; - end; - - { If we've run out of data, just leave the MCU set to zeroes. - This way, we return uniform gray for the remainder of the segment. } - - if not entropy^.pub.insufficient_data then - begin - - { Load up working state } - {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);} - br_state.cinfo := cinfo; - br_state.next_input_byte := cinfo^.src^.next_input_byte; - br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer; - get_buffer := entropy^.bitstate.get_buffer; - bits_left := entropy^.bitstate.bits_left; - - {ASSIGN_STATE(state, entropy^.saved);} - state := entropy^.saved; - - { Outer loop handles each block in the MCU } - - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - block := JBLOCK_PTR(MCU_data[blkn]); - ci := cinfo^.MCU_membership[blkn]; - compptr := cinfo^.cur_comp_info[ci]; - tbl := entropy^.derived_tbls[compptr^.dc_tbl_no]; - - { Decode a single block's worth of coefficients } - - { Section F.2.2.1: decode the DC coefficient difference } - {HUFF_DECODE(s, br_state, tbl, return FALSE, label1);} - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - begin - decode_mcu_DC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto label1; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := tbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := tbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; - label1: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb); - if (s < 0) then - begin - decode_mcu_DC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - if (s <> 0) then - begin - {CHECK_BIT_BUFFER(br_state, s, return FALSE);} - if (bits_left < s) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then - begin - decode_mcu_DC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {r := GET_BITS(s);} - Dec(bits_left, s); - r := (int(get_buffer shr bits_left)) and ( pred(1 shl s) ); - - {s := HUFF_EXTEND(r, s);} - if (r < extend_test[s]) then - s := r + extend_offset[s] - else - s := r; - end; - - { Convert DC difference to actual value, update last_dc_val } - Inc(s, state.last_dc_val[ci]); - state.last_dc_val[ci] := s; - { Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) } - block^[0] := JCOEF (s shl Al); - end; - - { Completed MCU, so update state } - {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);} - cinfo^.src^.next_input_byte := br_state.next_input_byte; - cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer; - entropy^.bitstate.get_buffer := get_buffer; - entropy^.bitstate.bits_left := bits_left; - - {ASSIGN_STATE(entropy^.saved, state);} - entropy^.saved := state; - end; - - { Account for restart interval (no-op if not using restarts) } - if entropy^.restarts_to_go > 0 then - Dec(entropy^.restarts_to_go); - - decode_mcu_DC_first := TRUE; -end; - - -{ MCU decoding for AC initial scan (either spectral selection, - or first pass of successive approximation). } - -{METHODDEF} -function decode_mcu_AC_first (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; -label - label2; -var - entropy : phuff_entropy_ptr; - Se : int; - Al : int; - {register} s, k, r : int; - EOBRUN : uInt; - block : JBLOCK_PTR; - {BITREAD_STATE_VARS;} - get_buffer : bit_buf_type ; {register} - bits_left : int; {register} - br_state : bitread_working_state; - - tbl : d_derived_tbl_ptr; -var - nb, look : int; {register} -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - Se := cinfo^.Se; - Al := cinfo^.Al; - - { Process restart marker if needed; may have to suspend } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - if (not process_restart(cinfo)) then - begin - decode_mcu_AC_first := FALSE; - exit; - end; - end; - - { If we've run out of data, just leave the MCU set to zeroes. - This way, we return uniform gray for the remainder of the segment. } - if not entropy^.pub.insufficient_data then - begin - - { Load up working state. - We can avoid loading/saving bitread state if in an EOB run. } - - EOBRUN := entropy^.saved.EOBRUN; { only part of saved state we care about } - - { There is always only one block per MCU } - - if (EOBRUN > 0) then { if it's a band of zeroes... } - Dec(EOBRUN) { ...process it now (we do nothing) } - else - begin - {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);} - br_state.cinfo := cinfo; - br_state.next_input_byte := cinfo^.src^.next_input_byte; - br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer; - get_buffer := entropy^.bitstate.get_buffer; - bits_left := entropy^.bitstate.bits_left; - - block := JBLOCK_PTR(MCU_data[0]); - tbl := entropy^.ac_derived_tbl; - - k := cinfo^.Ss; - while (k <= Se) do - begin - {HUFF_DECODE(s, br_state, tbl, return FALSE, label2);} - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - begin - decode_mcu_AC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto label2; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := tbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := tbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; - label2: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb); - if (s < 0) then - begin - decode_mcu_AC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - r := s shr 4; - s := s and 15; - if (s <> 0) then - begin - Inc(k, r); - {CHECK_BIT_BUFFER(br_state, s, return FALSE);} - if (bits_left < s) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,s)) then - begin - decode_mcu_AC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {r := GET_BITS(s);} - Dec(bits_left, s); - r := (int(get_buffer shr bits_left)) and ( pred(1 shl s) ); - - {s := HUFF_EXTEND(r, s);} - if (r < extend_test[s]) then - s := r + extend_offset[s] - else - s := r; - - { Scale and output coefficient in natural (dezigzagged) order } - block^[jpeg_natural_order[k]] := JCOEF (s shl Al); - end - else - begin - if (r = 15) then - begin { ZRL } - Inc(k, 15); { skip 15 zeroes in band } - end - else - begin { EOBr, run length is 2^r + appended bits } - EOBRUN := 1 shl r; - if (r <> 0) then - begin { EOBr, r > 0 } - {CHECK_BIT_BUFFER(br_state, r, return FALSE);} - if (bits_left < r) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,r)) then - begin - decode_mcu_AC_first := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {r := GET_BITS(r);} - Dec(bits_left, r); - r := (int(get_buffer shr bits_left)) and ( pred(1 shl r) ); - - Inc(EOBRUN, r); - end; - Dec(EOBRUN); { this band is processed at this moment } - break; { force end-of-band } - end; - end; - Inc(k); - end; - - {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);} - cinfo^.src^.next_input_byte := br_state.next_input_byte; - cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer; - entropy^.bitstate.get_buffer := get_buffer; - entropy^.bitstate.bits_left := bits_left; - end; - - { Completed MCU, so update state } - entropy^.saved.EOBRUN := EOBRUN; { only part of saved state we care about } - end; - - { Account for restart interval (no-op if not using restarts) } - if entropy^.restarts_to_go > 0 then - Dec(entropy^.restarts_to_go); - - decode_mcu_AC_first := TRUE; -end; - - -{ MCU decoding for DC successive approximation refinement scan. - Note: we assume such scans can be multi-component, although the spec - is not very clear on the point. } - -{METHODDEF} -function decode_mcu_DC_refine (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; - -var - entropy : phuff_entropy_ptr; - p1 : int; { 1 in the bit position being coded } - blkn : int; - block : JBLOCK_PTR; - {BITREAD_STATE_VARS;} - get_buffer : bit_buf_type ; {register} - bits_left : int; {register} - br_state : bitread_working_state; -begin - entropy := phuff_entropy_ptr (cinfo^.entropy); - p1 := 1 shl cinfo^.Al; - - { Process restart marker if needed; may have to suspend } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - if (not process_restart(cinfo)) then - begin - decode_mcu_DC_refine := FALSE; - exit; - end; - end; - - { Not worth the cycles to check insufficient_data here, - since we will not change the data anyway if we read zeroes. } - - { Load up working state } - {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);} - br_state.cinfo := cinfo; - br_state.next_input_byte := cinfo^.src^.next_input_byte; - br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer; - get_buffer := entropy^.bitstate.get_buffer; - bits_left := entropy^.bitstate.bits_left; - - { Outer loop handles each block in the MCU } - - for blkn := 0 to pred(cinfo^.blocks_in_MCU) do - begin - block := JBLOCK_PTR(MCU_data[blkn]); - - { Encoded data is simply the next bit of the two's-complement DC value } - {CHECK_BIT_BUFFER(br_state, 1, return FALSE);} - if (bits_left < 1) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then - begin - decode_mcu_DC_refine := FALSE; - exit; - end; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {if (GET_BITS(1)) then} - Dec(bits_left); - if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) ) <> 0 then - block^[0] := block^[0] or p1; - { Note: since we use OR, repeating the assignment later is safe } - end; - - { Completed MCU, so update state } - {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);} - cinfo^.src^.next_input_byte := br_state.next_input_byte; - cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer; - entropy^.bitstate.get_buffer := get_buffer; - entropy^.bitstate.bits_left := bits_left; - - { Account for restart interval (no-op if not using restarts) } - if entropy^.restarts_to_go > 0 then - Dec(entropy^.restarts_to_go); - - decode_mcu_DC_refine := TRUE; -end; - - -{ MCU decoding for AC successive approximation refinement scan. } - -{METHODDEF} -function decode_mcu_AC_refine (cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; -label - undoit, label3; -var - entropy : phuff_entropy_ptr; - Se : int; - p1 : int; { 1 in the bit position being coded } - m1 : int; { -1 in the bit position being coded } - {register} s, k, r : int; - EOBRUN : uInt; - block : JBLOCK_PTR; - thiscoef : JCOEF_PTR; - {BITREAD_STATE_VARS;} - get_buffer : bit_buf_type ; {register} - bits_left : int; {register} - br_state : bitread_working_state; - - tbl : d_derived_tbl_ptr; - num_newnz : int; - newnz_pos : array[0..DCTSIZE2-1] of int; -var - pos : int; -var - nb, look : int; {register} -begin - num_newnz := 0; - block := nil; - - entropy := phuff_entropy_ptr (cinfo^.entropy); - Se := cinfo^.Se; - p1 := 1 shl cinfo^.Al; { 1 in the bit position being coded } - m1 := (-1) shl cinfo^.Al; { -1 in the bit position being coded } - - { Process restart marker if needed; may have to suspend } - if (cinfo^.restart_interval <> 0) then - begin - if (entropy^.restarts_to_go = 0) then - if (not process_restart(cinfo)) then - begin - decode_mcu_AC_refine := FALSE; - exit; - end; - end; - - { If we've run out of data, don't modify the MCU. } - if not entropy^.pub.insufficient_data then - begin - - { Load up working state } - {BITREAD_LOAD_STATE(cinfo,entropy^.bitstate);} - br_state.cinfo := cinfo; - br_state.next_input_byte := cinfo^.src^.next_input_byte; - br_state.bytes_in_buffer := cinfo^.src^.bytes_in_buffer; - get_buffer := entropy^.bitstate.get_buffer; - bits_left := entropy^.bitstate.bits_left; - - EOBRUN := entropy^.saved.EOBRUN; { only part of saved state we care about } - - { There is always only one block per MCU } - block := JBLOCK_PTR(MCU_data[0]); - tbl := entropy^.ac_derived_tbl; - - { If we are forced to suspend, we must undo the assignments to any newly - nonzero coefficients in the block, because otherwise we'd get confused - next time about which coefficients were already nonzero. - But we need not undo addition of bits to already-nonzero coefficients; - instead, we can test the current bit position to see if we already did it.} - - num_newnz := 0; - - { initialize coefficient loop counter to start of band } - k := cinfo^.Ss; - - if (EOBRUN = 0) then - begin - while (k <= Se) do - begin - {HUFF_DECODE(s, br_state, tbl, goto undoit, label3);} - if (bits_left < HUFF_LOOKAHEAD) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left, 0)) then - goto undoit; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - if (bits_left < HUFF_LOOKAHEAD) then - begin - nb := 1; - goto label3; - end; - end; - {look := PEEK_BITS(HUFF_LOOKAHEAD);} - look := int(get_buffer shr (bits_left - HUFF_LOOKAHEAD)) and - pred(1 shl HUFF_LOOKAHEAD); - - nb := tbl^.look_nbits[look]; - if (nb <> 0) then - begin - {DROP_BITS(nb);} - Dec(bits_left, nb); - - s := tbl^.look_sym[look]; - end - else - begin - nb := HUFF_LOOKAHEAD+1; - label3: - s := jpeg_huff_decode(br_state,get_buffer,bits_left,tbl,nb); - if (s < 0) then - goto undoit; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - r := s shr 4; - s := s and 15; - if (s <> 0) then - begin - if (s <> 1) then { size of new coef should always be 1 } - WARNMS(j_common_ptr(cinfo), JWRN_HUFF_BAD_CODE); - {CHECK_BIT_BUFFER(br_state, 1, goto undoit);} - if (bits_left < 1) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then - goto undoit; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {if (GET_BITS(1)) then} - Dec(bits_left); - if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) )<>0 then - s := p1 { newly nonzero coef is positive } - else - s := m1; { newly nonzero coef is negative } - end - else - begin - if (r <> 15) then - begin - EOBRUN := 1 shl r; { EOBr, run length is 2^r + appended bits } - if (r <> 0) then - begin - {CHECK_BIT_BUFFER(br_state, r, goto undoit);} - if (bits_left < r) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,r)) then - goto undoit; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {r := GET_BITS(r);} - Dec(bits_left, r); - r := (int(get_buffer shr bits_left)) and ( pred(1 shl r) ); - - Inc(EOBRUN, r); - end; - break; { rest of block is handled by EOB logic } - end; - { note s := 0 for processing ZRL } - end; - { Advance over already-nonzero coefs and r still-zero coefs, - appending correction bits to the nonzeroes. A correction bit is 1 - if the absolute value of the coefficient must be increased. } - - repeat - thiscoef :=@(block^[jpeg_natural_order[k]]); - if (thiscoef^ <> 0) then - begin - {CHECK_BIT_BUFFER(br_state, 1, goto undoit);} - if (bits_left < 1) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then - goto undoit; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {if (GET_BITS(1)) then} - Dec(bits_left); - if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) )<>0 then - begin - if ((thiscoef^ and p1) = 0) then - begin { do nothing if already set it } - if (thiscoef^ >= 0) then - Inc(thiscoef^, p1) - else - Inc(thiscoef^, m1); - end; - end; - end - else - begin - Dec(r); - if (r < 0) then - break; { reached target zero coefficient } - end; - Inc(k); - until (k > Se); - if (s <> 0) then - begin - pos := jpeg_natural_order[k]; - { Output newly nonzero coefficient } - block^[pos] := JCOEF (s); - { Remember its position in case we have to suspend } - newnz_pos[num_newnz] := pos; - Inc(num_newnz); - end; - Inc(k); - end; - end; - - if (EOBRUN > 0) then - begin - { Scan any remaining coefficient positions after the end-of-band - (the last newly nonzero coefficient, if any). Append a correction - bit to each already-nonzero coefficient. A correction bit is 1 - if the absolute value of the coefficient must be increased. } - - while (k <= Se) do - begin - thiscoef := @(block^[jpeg_natural_order[k]]); - if (thiscoef^ <> 0) then - begin - {CHECK_BIT_BUFFER(br_state, 1, goto undoit);} - if (bits_left < 1) then - begin - if (not jpeg_fill_bit_buffer(br_state,get_buffer,bits_left,1)) then - goto undoit; - get_buffer := br_state.get_buffer; - bits_left := br_state.bits_left; - end; - - {if (GET_BITS(1)) then} - Dec(bits_left); - if (int(get_buffer shr bits_left)) and ( pred(1 shl 1) )<>0 then - begin - if ((thiscoef^ and p1) = 0) then - begin { do nothing if already changed it } - if (thiscoef^ >= 0) then - Inc(thiscoef^, p1) - else - Inc(thiscoef^, m1); - end; - end; - end; - Inc(k); - end; - { Count one block completed in EOB run } - Dec(EOBRUN); - end; - - { Completed MCU, so update state } - {BITREAD_SAVE_STATE(cinfo,entropy^.bitstate);} - cinfo^.src^.next_input_byte := br_state.next_input_byte; - cinfo^.src^.bytes_in_buffer := br_state.bytes_in_buffer; - entropy^.bitstate.get_buffer := get_buffer; - entropy^.bitstate.bits_left := bits_left; - - entropy^.saved.EOBRUN := EOBRUN; { only part of saved state we care about } - end; - - { Account for restart interval (no-op if not using restarts) } - if entropy^.restarts_to_go > 0 then - Dec(entropy^.restarts_to_go); - - decode_mcu_AC_refine := TRUE; - exit; - -undoit: - { Re-zero any output coefficients that we made newly nonzero } - while (num_newnz > 0) do - begin - Dec(num_newnz); - block^[newnz_pos[num_newnz]] := 0; - end; - - decode_mcu_AC_refine := FALSE; -end; - - -{ Module initialization routine for progressive Huffman entropy decoding. } - -{GLOBAL} -procedure jinit_phuff_decoder (cinfo : j_decompress_ptr); -var - entropy : phuff_entropy_ptr; - coef_bit_ptr : int_ptr; - ci, i : int; -begin - entropy := phuff_entropy_ptr( - cinfo^.mem^.alloc_small (j_common_ptr (cinfo), JPOOL_IMAGE, - SIZEOF(phuff_entropy_decoder)) ); - cinfo^.entropy := jpeg_entropy_decoder_ptr (entropy); - entropy^.pub.start_pass := start_pass_phuff_decoder; - - { Mark derived tables unallocated } - for i := 0 to pred(NUM_HUFF_TBLS) do - begin - entropy^.derived_tbls[i] := NIL; - end; - - { Create progression status table } - cinfo^.coef_bits := coef_bits_ptrrow ( - cinfo^.mem^.alloc_small ( j_common_ptr (cinfo), JPOOL_IMAGE, - cinfo^.num_components*DCTSIZE2*SIZEOF(int)) ); - coef_bit_ptr := @cinfo^.coef_bits^[0][0]; - for ci := 0 to pred(cinfo^.num_components) do - for i := 0 to pred(DCTSIZE2) do - begin - coef_bit_ptr^ := -1; - Inc(coef_bit_ptr); - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdpostct.pas b/3rd/Imaging/Source/JpegLib/imjdpostct.pas deleted file mode 100644 index f3078c356..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdpostct.pas +++ /dev/null @@ -1,341 +0,0 @@ -unit imjdpostct; - -{ Original: jdpostct.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -{ This file contains the decompression postprocessing controller. - This controller manages the upsampling, color conversion, and color - quantization/reduction steps; specifically, it controls the buffering - between upsample/color conversion and color quantization/reduction. - - If no color quantization/reduction is required, then this module has no - work to do, and it just hands off to the upsample/color conversion code. - An integrated upsample/convert/quantize process would replace this module - entirely. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjutils, - imjpeglib; - -{ Initialize postprocessing controller. } - -{GLOBAL} -procedure jinit_d_post_controller (cinfo : j_decompress_ptr; - need_full_buffer : boolean); -implementation - - -{ Private buffer controller object } - -type - my_post_ptr = ^my_post_controller; - my_post_controller = record - pub : jpeg_d_post_controller; { public fields } - - { Color quantization source buffer: this holds output data from - the upsample/color conversion step to be passed to the quantizer. - For two-pass color quantization, we need a full-image buffer; - for one-pass operation, a strip buffer is sufficient. } - - whole_image : jvirt_sarray_ptr; { virtual array, or NIL if one-pass } - buffer : JSAMPARRAY; { strip buffer, or current strip of virtual } - strip_height : JDIMENSION; { buffer size in rows } - { for two-pass mode only: } - starting_row : JDIMENSION; { row # of first row in current strip } - next_row : JDIMENSION; { index of next row to fill/empty in strip } - end; - -{ Forward declarations } -{METHODDEF} -procedure post_process_1pass(cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); forward; -{$ifdef QUANT_2PASS_SUPPORTED} -{METHODDEF} -procedure post_process_prepass(cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); forward; -{METHODDEF} -procedure post_process_2pass(cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); forward; -{$endif} - - -{ Initialize for a processing pass. } - -{METHODDEF} -procedure start_pass_dpost (cinfo : j_decompress_ptr; - pass_mode : J_BUF_MODE); -var - post : my_post_ptr; -begin - post := my_post_ptr(cinfo^.post); - - case (pass_mode) of - JBUF_PASS_THRU: - if (cinfo^.quantize_colors) then - begin - { Single-pass processing with color quantization. } - post^.pub.post_process_data := post_process_1pass; - { We could be doing buffered-image output before starting a 2-pass - color quantization; in that case, jinit_d_post_controller did not - allocate a strip buffer. Use the virtual-array buffer as workspace. } - if (post^.buffer = NIL) then - begin - post^.buffer := cinfo^.mem^.access_virt_sarray - (j_common_ptr(cinfo), post^.whole_image, - JDIMENSION(0), post^.strip_height, TRUE); - end; - end - else - begin - { For single-pass processing without color quantization, - I have no work to do; just call the upsampler directly. } - - post^.pub.post_process_data := cinfo^.upsample^.upsample; - end; - -{$ifdef QUANT_2PASS_SUPPORTED} - JBUF_SAVE_AND_PASS: - begin - { First pass of 2-pass quantization } - if (post^.whole_image = NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - post^.pub.post_process_data := post_process_prepass; - end; - JBUF_CRANK_DEST: - begin - { Second pass of 2-pass quantization } - if (post^.whole_image = NIL) then - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - post^.pub.post_process_data := post_process_2pass; - end; -{$endif} { QUANT_2PASS_SUPPORTED } - else - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); - end; - post^.next_row := 0; - post^.starting_row := 0; -end; - - -{ Process some data in the one-pass (strip buffer) case. - This is used for color precision reduction as well as one-pass quantization. } - -{METHODDEF} -procedure post_process_1pass (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -var - post : my_post_ptr; - num_rows, max_rows : JDIMENSION; -begin - post := my_post_ptr (cinfo^.post); - - { Fill the buffer, but not more than what we can dump out in one go. } - { Note we rely on the upsampler to detect bottom of image. } - max_rows := out_rows_avail - out_row_ctr; - if (max_rows > post^.strip_height) then - max_rows := post^.strip_height; - num_rows := 0; - cinfo^.upsample^.upsample (cinfo, - input_buf, - in_row_group_ctr, - in_row_groups_avail, - post^.buffer, - num_rows, { var } - max_rows); - { Quantize and emit data. } - - cinfo^.cquantize^.color_quantize (cinfo, - post^.buffer, - JSAMPARRAY(@ output_buf^[out_row_ctr]), - int(num_rows)); - - Inc(out_row_ctr, num_rows); -end; - - -{$ifdef QUANT_2PASS_SUPPORTED} - -{ Process some data in the first pass of 2-pass quantization. } - -{METHODDEF} -procedure post_process_prepass (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail:JDIMENSION); -var - post : my_post_ptr; - old_next_row, num_rows : JDIMENSION; -begin - post := my_post_ptr(cinfo^.post); - - { Reposition virtual buffer if at start of strip. } - if (post^.next_row = 0) then - begin - post^.buffer := cinfo^.mem^.access_virt_sarray - (j_common_ptr(cinfo), post^.whole_image, - post^.starting_row, post^.strip_height, TRUE); - end; - - { Upsample some data (up to a strip height's worth). } - old_next_row := post^.next_row; - cinfo^.upsample^.upsample (cinfo, - input_buf, in_row_group_ctr, in_row_groups_avail, - post^.buffer, post^.next_row, post^.strip_height); - - { Allow quantizer to scan new data. No data is emitted, } - { but we advance out_row_ctr so outer loop can tell when we're done. } - if (post^.next_row > old_next_row) then - begin - num_rows := post^.next_row - old_next_row; - - - cinfo^.cquantize^.color_quantize (cinfo, - JSAMPARRAY(@ post^.buffer^[old_next_row]), - JSAMPARRAY(NIL), - int(num_rows)); - Inc(out_row_ctr, num_rows); - end; - - { Advance if we filled the strip. } - if (post^.next_row >= post^.strip_height) then - begin - Inc(post^.starting_row, post^.strip_height); - post^.next_row := 0; - end; -end; - - -{ Process some data in the second pass of 2-pass quantization. } - -{METHODDEF} -procedure post_process_2pass (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -var - post : my_post_ptr; - num_rows, max_rows : JDIMENSION; -begin - post := my_post_ptr(cinfo^.post); - - { Reposition virtual buffer if at start of strip. } - if (post^.next_row = 0) then - begin - post^.buffer := cinfo^.mem^.access_virt_sarray - (j_common_ptr(cinfo), post^.whole_image, - post^.starting_row, post^.strip_height, FALSE); - end; - - { Determine number of rows to emit. } - num_rows := post^.strip_height - post^.next_row; { available in strip } - max_rows := out_rows_avail - out_row_ctr; { available in output area } - if (num_rows > max_rows) then - num_rows := max_rows; - { We have to check bottom of image here, can't depend on upsampler. } - max_rows := cinfo^.output_height - post^.starting_row; - if (num_rows > max_rows) then - num_rows := max_rows; - - { Quantize and emit data. } - cinfo^.cquantize^.color_quantize (cinfo, - JSAMPARRAY(@ post^.buffer^[post^.next_row]), - JSAMPARRAY(@ output_buf^[out_row_ctr]), - int(num_rows)); - Inc(out_row_ctr, num_rows); - - { Advance if we filled the strip. } - Inc(post^.next_row, num_rows); - if (post^.next_row >= post^.strip_height) then - begin - Inc(post^.starting_row, post^.strip_height); - post^.next_row := 0; - end; -end; - -{$endif} { QUANT_2PASS_SUPPORTED } - - -{ Initialize postprocessing controller. } - -{GLOBAL} -procedure jinit_d_post_controller (cinfo : j_decompress_ptr; - need_full_buffer : boolean); -var - post : my_post_ptr; -begin - post := my_post_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_post_controller)) ); - cinfo^.post := jpeg_d_post_controller_ptr (post); - post^.pub.start_pass := start_pass_dpost; - post^.whole_image := NIL; { flag for no virtual arrays } - post^.buffer := NIL; { flag for no strip buffer } - - { Create the quantization buffer, if needed } - if (cinfo^.quantize_colors) then - begin - { The buffer strip height is max_v_samp_factor, which is typically - an efficient number of rows for upsampling to return. - (In the presence of output rescaling, we might want to be smarter?) } - - post^.strip_height := JDIMENSION (cinfo^.max_v_samp_factor); - if (need_full_buffer) then - begin - { Two-pass color quantization: need full-image storage. } - { We round up the number of rows to a multiple of the strip height. } -{$ifdef QUANT_2PASS_SUPPORTED} - post^.whole_image := cinfo^.mem^.request_virt_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, FALSE, - LongInt(cinfo^.output_width) * cinfo^.out_color_components, - JDIMENSION (jround_up( long(cinfo^.output_height), - long(post^.strip_height)) ), - post^.strip_height); -{$else} - ERREXIT(j_common_ptr(cinfo), JERR_BAD_BUFFER_MODE); -{$endif} { QUANT_2PASS_SUPPORTED } - end - else - begin - { One-pass color quantization: just make a strip buffer. } - post^.buffer := cinfo^.mem^.alloc_sarray - (j_common_ptr (cinfo), JPOOL_IMAGE, - LongInt(cinfo^.output_width) * cinfo^.out_color_components, - post^.strip_height); - end; - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjdsample.pas b/3rd/Imaging/Source/JpegLib/imjdsample.pas deleted file mode 100644 index ed2488c95..000000000 --- a/3rd/Imaging/Source/JpegLib/imjdsample.pas +++ /dev/null @@ -1,592 +0,0 @@ -unit imjdsample; - -{ Original: jdsample.c; Copyright (C) 1991-1996, Thomas G. Lane. } - -{ This file contains upsampling routines. - - Upsampling input data is counted in "row groups". A row group - is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) - sample rows of each component. Upsampling will normally produce - max_v_samp_factor pixel rows from each row group (but this could vary - if the upsampler is applying a scale factor of its own). - - An excellent reference for image resampling is - Digital Image Warping, George Wolberg, 1990. - Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.} - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjutils, - imjpeglib, - imjdeferr, - imjerror; - - -{ Pointer to routine to upsample a single component } -type - upsample1_ptr = procedure (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); - -{ Module initialization routine for upsampling. } - -{GLOBAL} -procedure jinit_upsampler (cinfo : j_decompress_ptr); - -implementation - -{ Private subobject } - -type - my_upsample_ptr = ^my_upsampler; - my_upsampler = record - pub : jpeg_upsampler; { public fields } - - { Color conversion buffer. When using separate upsampling and color - conversion steps, this buffer holds one upsampled row group until it - has been color converted and output. - Note: we do not allocate any storage for component(s) which are full-size, - ie do not need rescaling. The corresponding entry of color_buf[] is - simply set to point to the input data array, thereby avoiding copying.} - - color_buf : array[0..MAX_COMPONENTS-1] of JSAMPARRAY; - - { Per-component upsampling method pointers } - methods : array[0..MAX_COMPONENTS-1] of upsample1_ptr; - - next_row_out : int; { counts rows emitted from color_buf } - rows_to_go : JDIMENSION; { counts rows remaining in image } - - { Height of an input row group for each component. } - rowgroup_height : array[0..MAX_COMPONENTS-1] of int; - - { These arrays save pixel expansion factors so that int_expand need not - recompute them each time. They are unused for other upsampling methods.} - h_expand : array[0..MAX_COMPONENTS-1] of UINT8 ; - v_expand : array[0..MAX_COMPONENTS-1] of UINT8 ; - end; - - -{ Initialize for an upsampling pass. } - -{METHODDEF} -procedure start_pass_upsample (cinfo : j_decompress_ptr); -var - upsample : my_upsample_ptr; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - - { Mark the conversion buffer empty } - upsample^.next_row_out := cinfo^.max_v_samp_factor; - { Initialize total-height counter for detecting bottom of image } - upsample^.rows_to_go := cinfo^.output_height; -end; - - -{ Control routine to do upsampling (and color conversion). - - In this version we upsample each component independently. - We upsample one row group into the conversion buffer, then apply - color conversion a row at a time. } - -{METHODDEF} -procedure sep_upsample (cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); -var - upsample : my_upsample_ptr; - ci : int; - compptr : jpeg_component_info_ptr; - num_rows : JDIMENSION; -begin - upsample := my_upsample_ptr (cinfo^.upsample); - - { Fill the conversion buffer, if it's empty } - if (upsample^.next_row_out >= cinfo^.max_v_samp_factor) then - begin - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Invoke per-component upsample method. Notice we pass a POINTER - to color_buf[ci], so that fullsize_upsample can change it. } - - upsample^.methods[ci] (cinfo, compptr, - JSAMPARRAY(@ input_buf^[ci]^ - [LongInt(in_row_group_ctr) * upsample^.rowgroup_height[ci]]), - upsample^.color_buf[ci]); - - Inc(compptr); - end; - upsample^.next_row_out := 0; - end; - - { Color-convert and emit rows } - - { How many we have in the buffer: } - num_rows := JDIMENSION (cinfo^.max_v_samp_factor - upsample^.next_row_out); - { Not more than the distance to the end of the image. Need this test - in case the image height is not a multiple of max_v_samp_factor: } - - if (num_rows > upsample^.rows_to_go) then - num_rows := upsample^.rows_to_go; - { And not more than what the client can accept: } - Dec(out_rows_avail, out_row_ctr); - if (num_rows > out_rows_avail) then - num_rows := out_rows_avail; - - cinfo^.cconvert^.color_convert (cinfo, - JSAMPIMAGE(@(upsample^.color_buf)), - JDIMENSION (upsample^.next_row_out), - JSAMPARRAY(@(output_buf^[out_row_ctr])), - int (num_rows)); - - { Adjust counts } - Inc(out_row_ctr, num_rows); - Dec(upsample^.rows_to_go, num_rows); - Inc(upsample^.next_row_out, num_rows); - { When the buffer is emptied, declare this input row group consumed } - if (upsample^.next_row_out >= cinfo^.max_v_samp_factor) then - Inc(in_row_group_ctr); -end; - - -{ These are the routines invoked by sep_upsample to upsample pixel values - of a single component. One row group is processed per call. } - - -{ For full-size components, we just make color_buf[ci] point at the - input buffer, and thus avoid copying any data. Note that this is - safe only because sep_upsample doesn't declare the input row group - "consumed" until we are done color converting and emitting it. } - -{METHODDEF} -procedure fullsize_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -begin - output_data_ptr := input_data; -end; - - -{ This is a no-op version used for "uninteresting" components. - These components will not be referenced by color conversion. } - -{METHODDEF} -procedure noop_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -begin - output_data_ptr := NIL; { safety check } -end; - - -{ This version handles any integral sampling ratios. - This is not used for typical JPEG files, so it need not be fast. - Nor, for that matter, is it particularly accurate: the algorithm is - simple replication of the input pixel onto the corresponding output - pixels. The hi-falutin sampling literature refers to this as a - "box filter". A box filter tends to introduce visible artifacts, - so if you are actually going to use 3:1 or 4:1 sampling ratios - you would be well advised to improve this code. } - -{METHODDEF} -procedure int_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -var - upsample : my_upsample_ptr; - output_data : JSAMPARRAY; - {register} inptr, outptr : JSAMPLE_PTR; - {register} invalue : JSAMPLE; - {register} h : int; - {outend} - h_expand, v_expand : int; - inrow, outrow : int; -var - outcount : int; { Nomssi: avoid pointer arithmetic } -begin - upsample := my_upsample_ptr (cinfo^.upsample); - output_data := output_data_ptr; - - h_expand := upsample^.h_expand[compptr^.component_index]; - v_expand := upsample^.v_expand[compptr^.component_index]; - - inrow := 0; - outrow := 0; - while (outrow < cinfo^.max_v_samp_factor) do - begin - { Generate one output row with proper horizontal expansion } - inptr := JSAMPLE_PTR(input_data^[inrow]); - outptr := JSAMPLE_PTR(output_data^[outrow]); - outcount := cinfo^.output_width; - while (outcount > 0) do { Nomssi } - begin - invalue := inptr^; { don't need GETJSAMPLE() here } - Inc(inptr); - for h := pred(h_expand) downto 0 do - begin - outptr^ := invalue; - inc(outptr); { <-- fix: this was left out in PasJpeg 1.0 } - Dec(outcount); { thanks to Jannie Gerber for the report } - end; - end; - - { Generate any additional output rows by duplicating the first one } - if (v_expand > 1) then - begin - jcopy_sample_rows(output_data, outrow, output_data, outrow+1, - v_expand-1, cinfo^.output_width); - end; - Inc(inrow); - Inc(outrow, v_expand); - end; -end; - - -{ Fast processing for the common case of 2:1 horizontal and 1:1 vertical. - It's still a box filter. } - -{METHODDEF} -procedure h2v1_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -var - output_data : JSAMPARRAY; - {register} inptr, outptr : JSAMPLE_PTR; - {register} invalue : JSAMPLE; - {outend : JSAMPROW;} - outcount : int; - inrow : int; -begin - output_data := output_data_ptr; - - for inrow := 0 to pred(cinfo^.max_v_samp_factor) do - begin - inptr := JSAMPLE_PTR(input_data^[inrow]); - outptr := JSAMPLE_PTR(output_data^[inrow]); - {outend := outptr + cinfo^.output_width;} - outcount := cinfo^.output_width; - while (outcount > 0) do - begin - invalue := inptr^; { don't need GETJSAMPLE() here } - Inc(inptr); - outptr^ := invalue; - Inc(outptr); - outptr^ := invalue; - Inc(outptr); - Dec(outcount, 2); { Nomssi: to avoid pointer arithmetic } - end; - end; -end; - - -{ Fast processing for the common case of 2:1 horizontal and 2:1 vertical. - It's still a box filter. } - -{METHODDEF} -procedure h2v2_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -var - output_data : JSAMPARRAY; - {register} inptr, outptr : JSAMPLE_PTR; - {register} invalue : JSAMPLE; - {outend : JSAMPROW;} - outcount : int; - inrow, outrow : int; -begin - output_data := output_data_ptr; - - inrow := 0; - outrow := 0; - while (outrow < cinfo^.max_v_samp_factor) do - begin - inptr := JSAMPLE_PTR(input_data^[inrow]); - outptr := JSAMPLE_PTR(output_data^[outrow]); - {outend := outptr + cinfo^.output_width;} - outcount := cinfo^.output_width; - while (outcount > 0) do - begin - invalue := inptr^; { don't need GETJSAMPLE() here } - Inc(inptr); - outptr^ := invalue; - Inc(outptr); - outptr^ := invalue; - Inc(outptr); - Dec(outcount, 2); - end; - jcopy_sample_rows(output_data, outrow, output_data, outrow+1, - 1, cinfo^.output_width); - Inc(inrow); - Inc(outrow, 2); - end; -end; - - -{ Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. - - The upsampling algorithm is linear interpolation between pixel centers, - also known as a "triangle filter". This is a good compromise between - speed and visual quality. The centers of the output pixels are 1/4 and 3/4 - of the way between input pixel centers. - - A note about the "bias" calculations: when rounding fractional values to - integer, we do not want to always round 0.5 up to the next integer. - If we did that, we'd introduce a noticeable bias towards larger values. - Instead, this code is arranged so that 0.5 will be rounded up or down at - alternate pixel locations (a simple ordered dither pattern). } - -{METHODDEF} -procedure h2v1_fancy_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -var - output_data : JSAMPARRAY; - {register} pre_inptr, inptr, outptr : JSAMPLE_PTR; - {register} invalue : int; - {register} colctr : JDIMENSION; - inrow : int; -begin - output_data := output_data_ptr; - - for inrow := 0 to pred(cinfo^.max_v_samp_factor) do - begin - inptr := JSAMPLE_PTR(input_data^[inrow]); - outptr := JSAMPLE_PTR(output_data^[inrow]); - { Special case for first column } - pre_inptr := inptr; - invalue := GETJSAMPLE(inptr^); - Inc(inptr); - outptr^ := JSAMPLE (invalue); - Inc(outptr); - outptr^ := JSAMPLE ((invalue * 3 + GETJSAMPLE(inptr^) + 2) shr 2); - Inc(outptr); - - for colctr := pred(compptr^.downsampled_width - 2) downto 0 do - begin - { General case: 3/4 * nearer pixel + 1/4 * further pixel } - invalue := GETJSAMPLE(inptr^) * 3; - Inc(inptr); - outptr^ := JSAMPLE ((invalue + GETJSAMPLE(pre_inptr^) + 1) shr 2); - Inc(pre_inptr); - Inc(outptr); - outptr^ := JSAMPLE ((invalue + GETJSAMPLE(inptr^) + 2) shr 2); - Inc(outptr); - end; - - { Special case for last column } - invalue := GETJSAMPLE(inptr^); - outptr^ := JSAMPLE ((invalue * 3 + GETJSAMPLE(pre_inptr^) + 1) shr 2); - Inc(outptr); - outptr^ := JSAMPLE (invalue); - {Inc(outptr); - value never used } - end; -end; - - -{ Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. - Again a triangle filter; see comments for h2v1 case, above. - - It is OK for us to reference the adjacent input rows because we demanded - context from the main buffer controller (see initialization code). } - -{METHODDEF} -procedure h2v2_fancy_upsample (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - input_data : JSAMPARRAY; - var output_data_ptr : JSAMPARRAY); -var - output_data : JSAMPARRAY; - {register} inptr0, inptr1, outptr : JSAMPLE_PTR; -{$ifdef BITS_IN_JSAMPLE_IS_8} - {register} thiscolsum, lastcolsum, nextcolsum : int; -{$else} - {register} thiscolsum, lastcolsum, nextcolsum : INT32; -{$endif} - {register} colctr : JDIMENSION; - inrow, outrow, v : int; -var - prev_input_data : JSAMPARRAY; { Nomssi work around } -begin - output_data := output_data_ptr; - - outrow := 0; - inrow := 0; - while (outrow < cinfo^.max_v_samp_factor) do - begin - for v := 0 to pred(2) do - begin - { inptr0 points to nearest input row, inptr1 points to next nearest } - inptr0 := JSAMPLE_PTR(input_data^[inrow]); - if (v = 0) then { next nearest is row above } - begin - {inptr1 := JSAMPLE_PTR(input_data^[inrow-1]);} - prev_input_data := input_data; { work around } - Dec(JSAMPROW_PTR(prev_input_data)); { negative offsets } - inptr1 := JSAMPLE_PTR(prev_input_data^[inrow]); - end - else { next nearest is row below } - inptr1 := JSAMPLE_PTR(input_data^[inrow+1]); - outptr := JSAMPLE_PTR(output_data^[outrow]); - Inc(outrow); - - { Special case for first column } - thiscolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^); - Inc(inptr0); - Inc(inptr1); - nextcolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^); - Inc(inptr0); - Inc(inptr1); - - outptr^ := JSAMPLE ((thiscolsum * 4 + 8) shr 4); - Inc(outptr); - outptr^ := JSAMPLE ((thiscolsum * 3 + nextcolsum + 7) shr 4); - Inc(outptr); - lastcolsum := thiscolsum; thiscolsum := nextcolsum; - - for colctr := pred(compptr^.downsampled_width - 2) downto 0 do - begin - { General case: 3/4 * nearer pixel + 1/4 * further pixel in each } - { dimension, thus 9/16, 3/16, 3/16, 1/16 overall } - nextcolsum := GETJSAMPLE(inptr0^) * 3 + GETJSAMPLE(inptr1^); - Inc(inptr0); - Inc(inptr1); - outptr^ := JSAMPLE ((thiscolsum * 3 + lastcolsum + 8) shr 4); - Inc(outptr); - outptr^ := JSAMPLE ((thiscolsum * 3 + nextcolsum + 7) shr 4); - Inc(outptr); - lastcolsum := thiscolsum; - thiscolsum := nextcolsum; - end; - - { Special case for last column } - outptr^ := JSAMPLE ((thiscolsum * 3 + lastcolsum + 8) shr 4); - Inc(outptr); - outptr^ := JSAMPLE ((thiscolsum * 4 + 7) shr 4); - {Inc(outptr); - value never used } - end; - Inc(inrow); - end; -end; - - -{ Module initialization routine for upsampling. } - -{GLOBAL} -procedure jinit_upsampler (cinfo : j_decompress_ptr); -var - upsample : my_upsample_ptr; - ci : int; - compptr : jpeg_component_info_ptr; - need_buffer, do_fancy : boolean; - h_in_group, v_in_group, h_out_group, v_out_group : int; -begin - upsample := my_upsample_ptr ( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_upsampler)) ); - cinfo^.upsample := jpeg_upsampler_ptr (upsample); - upsample^.pub.start_pass := start_pass_upsample; - upsample^.pub.upsample := sep_upsample; - upsample^.pub.need_context_rows := FALSE; { until we find out differently } - - if (cinfo^.CCIR601_sampling) then { this isn't supported } - ERREXIT(j_common_ptr(cinfo), JERR_CCIR601_NOTIMPL); - - { jdmainct.c doesn't support context rows when min_DCT_scaled_size := 1, - so don't ask for it. } - - do_fancy := cinfo^.do_fancy_upsampling and (cinfo^.min_DCT_scaled_size > 1); - - { Verify we can handle the sampling factors, select per-component methods, - and create storage as needed. } - - compptr := jpeg_component_info_ptr(cinfo^.comp_info); - for ci := 0 to pred(cinfo^.num_components) do - begin - { Compute size of an "input group" after IDCT scaling. This many samples - are to be converted to max_h_samp_factor * max_v_samp_factor pixels. } - - h_in_group := (compptr^.h_samp_factor * compptr^.DCT_scaled_size) div - cinfo^.min_DCT_scaled_size; - v_in_group := (compptr^.v_samp_factor * compptr^.DCT_scaled_size) div - cinfo^.min_DCT_scaled_size; - h_out_group := cinfo^.max_h_samp_factor; - v_out_group := cinfo^.max_v_samp_factor; - upsample^.rowgroup_height[ci] := v_in_group; { save for use later } - need_buffer := TRUE; - if (not compptr^.component_needed) then - begin - { Don't bother to upsample an uninteresting component. } - upsample^.methods[ci] := noop_upsample; - need_buffer := FALSE; - end - else - if (h_in_group = h_out_group) and (v_in_group = v_out_group) then - begin - { Fullsize components can be processed without any work. } - upsample^.methods[ci] := fullsize_upsample; - need_buffer := FALSE; - end - else - if (h_in_group * 2 = h_out_group) and - (v_in_group = v_out_group) then - begin - { Special cases for 2h1v upsampling } - if (do_fancy) and (compptr^.downsampled_width > 2) then - upsample^.methods[ci] := h2v1_fancy_upsample - else - upsample^.methods[ci] := h2v1_upsample; - end - else - if (h_in_group * 2 = h_out_group) and - (v_in_group * 2 = v_out_group) then - begin - { Special cases for 2h2v upsampling } - if (do_fancy) and (compptr^.downsampled_width > 2) then - begin - upsample^.methods[ci] := h2v2_fancy_upsample; - upsample^.pub.need_context_rows := TRUE; - end - else - upsample^.methods[ci] := h2v2_upsample; - end - else - if ((h_out_group mod h_in_group) = 0) and - ((v_out_group mod v_in_group) = 0) then - begin - { Generic integral-factors upsampling method } - upsample^.methods[ci] := int_upsample; - upsample^.h_expand[ci] := UINT8 (h_out_group div h_in_group); - upsample^.v_expand[ci] := UINT8 (v_out_group div v_in_group); - end - else - ERREXIT(j_common_ptr(cinfo), JERR_FRACT_SAMPLE_NOTIMPL); - if (need_buffer) then - begin - upsample^.color_buf[ci] := cinfo^.mem^.alloc_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, - JDIMENSION (jround_up( long (cinfo^.output_width), - long (cinfo^.max_h_samp_factor))), - JDIMENSION (cinfo^.max_v_samp_factor)); - end; - Inc(compptr); - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjerror.pas b/3rd/Imaging/Source/JpegLib/imjerror.pas deleted file mode 100644 index d1e4ebcbc..000000000 --- a/3rd/Imaging/Source/JpegLib/imjerror.pas +++ /dev/null @@ -1,462 +0,0 @@ -unit imjerror; - -{ This file contains simple error-reporting and trace-message routines. - These are suitable for Unix-like systems and others where writing to - stderr is the right thing to do. Many applications will want to replace - some or all of these routines. - - These routines are used by both the compression and decompression code. } - -{ Source: jerror.c; Copyright (C) 1991-1996, Thomas G. Lane. } -{ note: format_message still contains a hack } -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjdeferr, - imjpeglib; -{ - jversion; -} - -const - EXIT_FAILURE = 1; { define halt() codes if not provided } - -{GLOBAL} -function jpeg_std_error (var err : jpeg_error_mgr) : jpeg_error_mgr_ptr; - - - -procedure ERREXIT(cinfo : j_common_ptr; code : J_MESSAGE_CODE); - -procedure ERREXIT1(cinfo : j_common_ptr; code : J_MESSAGE_CODE; p1 : uInt); - -procedure ERREXIT2(cinfo : j_common_ptr; code : J_MESSAGE_CODE; p1 : int; p2 : int); - -procedure ERREXIT3(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int); - -procedure ERREXIT4(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int); - -procedure ERREXITS(cinfo : j_common_ptr;code : J_MESSAGE_CODE; - str : AnsiString); -{ Nonfatal errors (we can keep going, but the data is probably corrupt) } - -procedure WARNMS(cinfo : j_common_ptr; code : J_MESSAGE_CODE); - -procedure WARNMS1(cinfo : j_common_ptr;code : J_MESSAGE_CODE; p1 : int); - -procedure WARNMS2(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int); - -{ Informational/debugging messages } -procedure TRACEMS(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE); - -procedure TRACEMS1(cinfo : j_common_ptr; lvl : int; - code : J_MESSAGE_CODE; p1 : long); - -procedure TRACEMS2(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; - p2 : int); - -procedure TRACEMS3(cinfo : j_common_ptr; - lvl : int; - code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int); - -procedure TRACEMS4(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int); - -procedure TRACEMS5(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int; p5 : int); - -procedure TRACEMS8(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int; - p5 : int; p6 : int; p7 : int; p8 : int); - -procedure TRACEMSS(cinfo : j_common_ptr; lvl : int; - code : J_MESSAGE_CODE; str : AnsiString); - -implementation - - -{ How to format a message string, in format_message() ? } - -{$IFDEF OS2} - {$DEFINE NO_FORMAT} -{$ENDIF} -{$IFDEF FPC} - {$DEFINE NO_FORMAT} -{$ENDIF} - -uses -{$IFNDEF NO_FORMAT} - {$IFDEF VER70} - drivers, { Turbo Vision unit with FormatStr } - {$ELSE} - sysutils, { Delphi Unit with Format() } - {$ENDIF} -{$ENDIF} - imjcomapi; - -{ Error exit handler: must not return to caller. - - Applications may override this if they want to get control back after - an error. Typically one would longjmp somewhere instead of exiting. - The setjmp buffer can be made a private field within an expanded error - handler object. Note that the info needed to generate an error message - is stored in the error object, so you can generate the message now or - later, at your convenience. - You should make sure that the JPEG object is cleaned up (with jpeg_abort - or jpeg_destroy) at some point. } - - -{METHODDEF} -procedure error_exit (cinfo : j_common_ptr); -begin - { Always display the message } - cinfo^.err^.output_message(cinfo); - - { Let the memory manager delete any temp files before we die } - jpeg_destroy(cinfo); - - halt(EXIT_FAILURE); -end; - - -{ Actual output of an error or trace message. - Applications may override this method to send JPEG messages somewhere - other than stderr. } - -{ Macros to simplify using the error and trace message stuff } -{ The first parameter is either type of cinfo pointer } - -{ Fatal errors (print message and exit) } -procedure ERREXIT(cinfo : j_common_ptr; code : J_MESSAGE_CODE); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.error_exit(cinfo); -end; - -procedure ERREXIT1(cinfo : j_common_ptr; code : J_MESSAGE_CODE; p1 : uInt); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.error_exit (cinfo); -end; - -procedure ERREXIT2(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.msg_parm.i[1] := p2; - cinfo^.err^.error_exit (cinfo); -end; - -procedure ERREXIT3(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.msg_parm.i[1] := p2; - cinfo^.err^.msg_parm.i[2] := p3; - cinfo^.err^.error_exit (cinfo); -end; - -procedure ERREXIT4(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.msg_parm.i[1] := p2; - cinfo^.err^.msg_parm.i[2] := p3; - cinfo^.err^.msg_parm.i[3] := p4; - cinfo^.err^.error_exit (cinfo); -end; - -procedure ERREXITS(cinfo : j_common_ptr;code : J_MESSAGE_CODE; - str : AnsiString); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.s := str; { string[JMSG_STR_PARM_MAX] } - cinfo^.err^.error_exit (cinfo); -end; - -{ Nonfatal errors (we can keep going, but the data is probably corrupt) } - -procedure WARNMS(cinfo : j_common_ptr; code : J_MESSAGE_CODE); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.emit_message(cinfo, -1); -end; - -procedure WARNMS1(cinfo : j_common_ptr;code : J_MESSAGE_CODE; p1 : int); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.emit_message (cinfo, -1); -end; - -procedure WARNMS2(cinfo : j_common_ptr; code : J_MESSAGE_CODE; - p1 : int; p2 : int); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.msg_parm.i[1] := p2; - cinfo^.err^.emit_message (cinfo, -1); -end; - -{ Informational/debugging messages } -procedure TRACEMS(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.emit_message(cinfo, lvl); -end; - -procedure TRACEMS1(cinfo : j_common_ptr; lvl : int; - code : J_MESSAGE_CODE; p1 : long); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.emit_message (cinfo, lvl); -end; - -procedure TRACEMS2(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; - p2 : int); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.i[0] := p1; - cinfo^.err^.msg_parm.i[1] := p2; - cinfo^.err^.emit_message (cinfo, lvl); -end; - -procedure TRACEMS3(cinfo : j_common_ptr; - lvl : int; - code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int); -var - _mp : int8array; -begin - _mp[0] := p1; _mp[1] := p2; _mp[2] := p3; - cinfo^.err^.msg_parm.i := _mp; - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.emit_message (cinfo, lvl); -end; - - -procedure TRACEMS4(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int); -var - _mp : int8array; -begin - _mp[0] := p1; _mp[1] := p2; _mp[2] := p3; _mp[3] := p4; - cinfo^.err^.msg_parm.i := _mp; - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.emit_message (cinfo, lvl); -end; - -procedure TRACEMS5(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int; p5 : int); -var - _mp : ^int8array; -begin - _mp := @cinfo^.err^.msg_parm.i; - _mp^[0] := p1; _mp^[1] := p2; _mp^[2] := p3; - _mp^[3] := p4; _mp^[5] := p5; - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.emit_message (cinfo, lvl); -end; - -procedure TRACEMS8(cinfo : j_common_ptr; lvl : int; code : J_MESSAGE_CODE; - p1 : int; p2 : int; p3 : int; p4 : int; - p5 : int; p6 : int; p7 : int; p8 : int); -var - _mp : int8array; -begin - _mp[0] := p1; _mp[1] := p2; _mp[2] := p3; _mp[3] := p4; - _mp[4] := p5; _mp[5] := p6; _mp[6] := p7; _mp[7] := p8; - cinfo^.err^.msg_parm.i := _mp; - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.emit_message (cinfo, lvl); -end; - -procedure TRACEMSS(cinfo : j_common_ptr; lvl : int; - code : J_MESSAGE_CODE; str : AnsiString); -begin - cinfo^.err^.msg_code := ord(code); - cinfo^.err^.msg_parm.s := str; { string JMSG_STR_PARM_MAX } - cinfo^.err^.emit_message (cinfo, lvl); -end; - -{METHODDEF} -procedure output_message (cinfo : j_common_ptr); -var - buffer : AnsiString; {[JMSG_LENGTH_MAX];} -begin - { Create the message } - cinfo^.err^.format_message (cinfo, buffer); - - { Send it to stderr, adding a newline } - WriteLn(output, buffer); -end; - - - -{ Decide whether to emit a trace or warning message. - msg_level is one of: - -1: recoverable corrupt-data warning, may want to abort. - 0: important advisory messages (always display to user). - 1: first level of tracing detail. - 2,3,...: successively more detailed tracing messages. - An application might override this method if it wanted to abort on warnings - or change the policy about which messages to display. } - - -{METHODDEF} -procedure emit_message (cinfo : j_common_ptr; msg_level : int); -var - err : jpeg_error_mgr_ptr; -begin - err := cinfo^.err; - if (msg_level < 0) then - begin - { It's a warning message. Since corrupt files may generate many warnings, - the policy implemented here is to show only the first warning, - unless trace_level >= 3. } - - if (err^.num_warnings = 0) or (err^.trace_level >= 3) then - err^.output_message(cinfo); - { Always count warnings in num_warnings. } - Inc( err^.num_warnings ); - end - else - begin - { It's a trace message. Show it if trace_level >= msg_level. } - if (err^.trace_level >= msg_level) then - err^.output_message (cinfo); - end; -end; - - -{ Format a message string for the most recent JPEG error or message. - The message is stored into buffer, which should be at least JMSG_LENGTH_MAX - characters. Note that no '\n' character is added to the string. - Few applications should need to override this method. } - - -{METHODDEF} -procedure format_message (cinfo : j_common_ptr; var buffer : AnsiString); -var - err : jpeg_error_mgr_ptr; - msg_code : J_MESSAGE_CODE; - msgtext : AnsiString; - isstring : boolean; -begin - err := cinfo^.err; - msg_code := J_MESSAGE_CODE(err^.msg_code); - msgtext := ''; - - { Look up message string in proper table } - if (msg_code > JMSG_NOMESSAGE) - and (msg_code <= J_MESSAGE_CODE(err^.last_jpeg_message)) then - begin - msgtext := err^.jpeg_message_table^[msg_code]; - end - else - if (err^.addon_message_table <> NIL) and - (msg_code >= err^.first_addon_message) and - (msg_code <= err^.last_addon_message) then - begin - msgtext := err^.addon_message_table^[J_MESSAGE_CODE - (ord(msg_code) - ord(err^.first_addon_message))]; - end; - - { Defend against bogus message number } - if (msgtext = '') then - begin - err^.msg_parm.i[0] := int(msg_code); - msgtext := err^.jpeg_message_table^[JMSG_NOMESSAGE]; - end; - - { Check for string parameter, as indicated by %s in the message text } - isstring := Pos('%s', msgtext) > 0; - - { Format the message into the passed buffer } - if (isstring) then - buffer := Concat(msgtext, err^.msg_parm.s) - else - begin - {$IFDEF VER70} - FormatStr(buffer, msgtext, err^.msg_parm.i); - {$ELSE} - {$IFDEF NO_FORMAT} - buffer := msgtext; - {$ELSE} - buffer := Format(msgtext, [ - err^.msg_parm.i[0], err^.msg_parm.i[1], - err^.msg_parm.i[2], err^.msg_parm.i[3], - err^.msg_parm.i[4], err^.msg_parm.i[5], - err^.msg_parm.i[6], err^.msg_parm.i[7] ]); - {$ENDIF} - {$ENDIF} - end; -end; - - - -{ Reset error state variables at start of a new image. - This is called during compression startup to reset trace/error - processing to default state, without losing any application-specific - method pointers. An application might possibly want to override - this method if it has additional error processing state. } - - -{METHODDEF} -procedure reset_error_mgr (cinfo : j_common_ptr); -begin - cinfo^.err^.num_warnings := 0; - { trace_level is not reset since it is an application-supplied parameter } - cinfo^.err^.msg_code := 0; { may be useful as a flag for "no error" } -end; - - -{ Fill in the standard error-handling methods in a jpeg_error_mgr object. - Typical call is: - cinfo : jpeg_compress_struct; - err : jpeg_error_mgr; - - cinfo.err := jpeg_std_error(@err); - after which the application may override some of the methods. } - - -{GLOBAL} -function jpeg_std_error (var err : jpeg_error_mgr) : jpeg_error_mgr_ptr; -begin - err.error_exit := error_exit; - err.emit_message := emit_message; - err.output_message := output_message; - err.format_message := format_message; - err.reset_error_mgr := reset_error_mgr; - - err.trace_level := 0; { default := no tracing } - err.num_warnings := 0; { no warnings emitted yet } - err.msg_code := 0; { may be useful as a flag for "no error" } - - { Initialize message table pointers } - err.jpeg_message_table := @jpeg_std_message_table; - err.last_jpeg_message := pred(JMSG_LASTMSGCODE); - - err.addon_message_table := NIL; - err.first_addon_message := JMSG_NOMESSAGE; { for safety } - err.last_addon_message := JMSG_NOMESSAGE; - - jpeg_std_error := @err; -end; - - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjfdctflt.pas b/3rd/Imaging/Source/JpegLib/imjfdctflt.pas deleted file mode 100644 index 28f881b15..000000000 --- a/3rd/Imaging/Source/JpegLib/imjfdctflt.pas +++ /dev/null @@ -1,176 +0,0 @@ -unit imjfdctflt; - -{$N+} -{ This file contains a floating-point implementation of the - forward DCT (Discrete Cosine Transform). - - This implementation should be more accurate than either of the integer - DCT implementations. However, it may not give the same results on all - machines because of differences in roundoff behavior. Speed will depend - on the hardware's floating point capacity. - - A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT - on each column. Direct algorithms are also available, but they are - much more complex and seem not to be any faster when reduced to code. - - This implementation is based on Arai, Agui, and Nakajima's algorithm for - scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - Japanese, but the algorithm is described in the Pennebaker & Mitchell - JPEG textbook (see REFERENCES section in file README). The following code - is based directly on figure 4-8 in P&M. - While an 8-point DCT cannot be done in less than 11 multiplies, it is - possible to arrange the computation so that many of the multiplies are - simple scalings of the final outputs. These multiplies can then be - folded into the multiplications or divisions by the JPEG quantization - table entries. The AA&N method leaves only 5 multiplies and 29 adds - to be done in the DCT itself. - The primary disadvantage of this method is that with a fixed-point - implementation, accuracy is lost due to imprecise representation of the - scaled quantization values. However, that problem does not arise if - we use floating point arithmetic. } - -{ Original : jfdctflt.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - - -{ Perform the forward DCT on one block of samples.} - -{GLOBAL} -procedure jpeg_fdct_float (var data : array of FAST_FLOAT); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - - -{ Perform the forward DCT on one block of samples.} - -{GLOBAL} -procedure jpeg_fdct_float (var data : array of FAST_FLOAT); -type - PWorkspace = ^TWorkspace; - TWorkspace = array [0..DCTSIZE2-1] of FAST_FLOAT; -var - tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : FAST_FLOAT; - tmp10, tmp11, tmp12, tmp13 : FAST_FLOAT; - z1, z2, z3, z4, z5, z11, z13 : FAST_FLOAT; - dataptr : PWorkspace; - ctr : int; -begin - { Pass 1: process rows. } - - dataptr := PWorkspace(@data); - for ctr := DCTSIZE-1 downto 0 do - begin - tmp0 := dataptr^[0] + dataptr^[7]; - tmp7 := dataptr^[0] - dataptr^[7]; - tmp1 := dataptr^[1] + dataptr^[6]; - tmp6 := dataptr^[1] - dataptr^[6]; - tmp2 := dataptr^[2] + dataptr^[5]; - tmp5 := dataptr^[2] - dataptr^[5]; - tmp3 := dataptr^[3] + dataptr^[4]; - tmp4 := dataptr^[3] - dataptr^[4]; - - { Even part } - - tmp10 := tmp0 + tmp3; { phase 2 } - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - dataptr^[0] := tmp10 + tmp11; { phase 3 } - dataptr^[4] := tmp10 - tmp11; - - z1 := (tmp12 + tmp13) * ({FAST_FLOAT}(0.707106781)); { c4 } - dataptr^[2] := tmp13 + z1; { phase 5 } - dataptr^[6] := tmp13 - z1; - - { Odd part } - - tmp10 := tmp4 + tmp5; { phase 2 } - tmp11 := tmp5 + tmp6; - tmp12 := tmp6 + tmp7; - - { The rotator is modified from fig 4-8 to avoid extra negations. } - z5 := (tmp10 - tmp12) * ( {FAST_FLOAT}(0.382683433)); { c6 } - z2 := {FAST_FLOAT}(0.541196100) * tmp10 + z5; { c2-c6 } - z4 := {FAST_FLOAT}(1.306562965) * tmp12 + z5; { c2+c6 } - z3 := tmp11 * {FAST_FLOAT} (0.707106781); { c4 } - - z11 := tmp7 + z3; { phase 5 } - z13 := tmp7 - z3; - - dataptr^[5] := z13 + z2; { phase 6 } - dataptr^[3] := z13 - z2; - dataptr^[1] := z11 + z4; - dataptr^[7] := z11 - z4; - - Inc(FAST_FLOAT_PTR(dataptr), DCTSIZE); { advance pointer to next row } - end; - - { Pass 2: process columns. } - - dataptr := PWorkspace(@data); - for ctr := DCTSIZE-1 downto 0 do - begin - tmp0 := dataptr^[DCTSIZE*0] + dataptr^[DCTSIZE*7]; - tmp7 := dataptr^[DCTSIZE*0] - dataptr^[DCTSIZE*7]; - tmp1 := dataptr^[DCTSIZE*1] + dataptr^[DCTSIZE*6]; - tmp6 := dataptr^[DCTSIZE*1] - dataptr^[DCTSIZE*6]; - tmp2 := dataptr^[DCTSIZE*2] + dataptr^[DCTSIZE*5]; - tmp5 := dataptr^[DCTSIZE*2] - dataptr^[DCTSIZE*5]; - tmp3 := dataptr^[DCTSIZE*3] + dataptr^[DCTSIZE*4]; - tmp4 := dataptr^[DCTSIZE*3] - dataptr^[DCTSIZE*4]; - - { Even part } - - tmp10 := tmp0 + tmp3; { phase 2 } - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - dataptr^[DCTSIZE*0] := tmp10 + tmp11; { phase 3 } - dataptr^[DCTSIZE*4] := tmp10 - tmp11; - - z1 := (tmp12 + tmp13) * {FAST_FLOAT} (0.707106781); { c4 } - dataptr^[DCTSIZE*2] := tmp13 + z1; { phase 5 } - dataptr^[DCTSIZE*6] := tmp13 - z1; - - { Odd part } - - tmp10 := tmp4 + tmp5; { phase 2 } - tmp11 := tmp5 + tmp6; - tmp12 := tmp6 + tmp7; - - { The rotator is modified from fig 4-8 to avoid extra negations. } - z5 := (tmp10 - tmp12) * {FAST_FLOAT} (0.382683433); { c6 } - z2 := {FAST_FLOAT} (0.541196100) * tmp10 + z5; { c2-c6 } - z4 := {FAST_FLOAT} (1.306562965) * tmp12 + z5; { c2+c6 } - z3 := tmp11 * {FAST_FLOAT} (0.707106781); { c4 } - - z11 := tmp7 + z3; { phase 5 } - z13 := tmp7 - z3; - - dataptr^[DCTSIZE*5] := z13 + z2; { phase 6 } - dataptr^[DCTSIZE*3] := z13 - z2; - dataptr^[DCTSIZE*1] := z11 + z4; - dataptr^[DCTSIZE*7] := z11 - z4; - - Inc(FAST_FLOAT_PTR(dataptr)); { advance pointer to next column } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjfdctfst.pas b/3rd/Imaging/Source/JpegLib/imjfdctfst.pas deleted file mode 100644 index 51e4bc61b..000000000 --- a/3rd/Imaging/Source/JpegLib/imjfdctfst.pas +++ /dev/null @@ -1,237 +0,0 @@ -unit imjfdctfst; - -{ This file contains a fast, not so accurate integer implementation of the - forward DCT (Discrete Cosine Transform). - - A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT - on each column. Direct algorithms are also available, but they are - much more complex and seem not to be any faster when reduced to code. - - This implementation is based on Arai, Agui, and Nakajima's algorithm for - scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - Japanese, but the algorithm is described in the Pennebaker & Mitchell - JPEG textbook (see REFERENCES section in file README). The following code - is based directly on figure 4-8 in P&M. - While an 8-point DCT cannot be done in less than 11 multiplies, it is - possible to arrange the computation so that many of the multiplies are - simple scalings of the final outputs. These multiplies can then be - folded into the multiplications or divisions by the JPEG quantization - table entries. The AA&N method leaves only 5 multiplies and 29 adds - to be done in the DCT itself. - The primary disadvantage of this method is that with fixed-point math, - accuracy is lost due to imprecise representation of the scaled - quantization values. The smaller the quantization table entry, the less - precise the scaled value, so this implementation does worse with high- - quality-setting files than with low-quality ones. } - -{ Original: jfdctfst.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - - -{ Perform the forward DCT on one block of samples. } - -{GLOBAL} -procedure jpeg_fdct_ifast (var data : array of DCTELEM); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - - -{ Scaling decisions are generally the same as in the LL&M algorithm; - see jfdctint.c for more details. However, we choose to descale - (right shift) multiplication products as soon as they are formed, - rather than carrying additional fractional bits into subsequent additions. - This compromises accuracy slightly, but it lets us save a few shifts. - More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) - everywhere except in the multiplications proper; this saves a good deal - of work on 16-bit-int machines. - - Again to save a few shifts, the intermediate results between pass 1 and - pass 2 are not upscaled, but are represented only to integral precision. - - A final compromise is to represent the multiplicative constants to only - 8 fractional bits, rather than 13. This saves some shifting work on some - machines, and may also reduce the cost of multiplication (since there - are fewer one-bits in the constants). } - -const - CONST_BITS = 8; -const - CONST_SCALE = (INT32(1) shl CONST_BITS); - - -const - FIX_0_382683433 = INT32(Round(CONST_SCALE * 0.382683433)); {98} - FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100)); {139} - FIX_0_707106781 = INT32(Round(CONST_SCALE * 0.707106781)); {181} - FIX_1_306562965 = INT32(Round(CONST_SCALE * 1.306562965)); {334} - -{ Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - -function DESCALE(x : INT32; n : int) : INT32; -var - shift_temp : INT32; -begin -{ We can gain a little more speed, with a further compromise in accuracy, - by omitting the addition in a descaling shift. This yields an incorrectly - rounded result half the time... } -{$ifndef USE_ACCURATE_ROUNDING} - shift_temp := x; -{$else} - shift_temp := x + (INT32(1) shl (n-1)); -{$endif} - -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else -{$endif} - Descale := (shift_temp shr n); -end; - -{ Multiply a DCTELEM variable by an INT32 constant, and immediately - descale to yield a DCTELEM result. } - - - function MULTIPLY(X : DCTELEM; Y: INT32): DCTELEM; - begin - Multiply := DeScale((X) * (Y), CONST_BITS); - end; - - -{ Perform the forward DCT on one block of samples. } - -{GLOBAL} -procedure jpeg_fdct_ifast (var data : array of DCTELEM); -type - PWorkspace = ^TWorkspace; - TWorkspace = array [0..DCTSIZE2-1] of DCTELEM; -var - tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : DCTELEM; - tmp10, tmp11, tmp12, tmp13 : DCTELEM; - z1, z2, z3, z4, z5, z11, z13 : DCTELEM; - dataptr : PWorkspace; - ctr : int; - {SHIFT_TEMPS} -begin - { Pass 1: process rows. } - - dataptr := PWorkspace(@data); - for ctr := DCTSIZE-1 downto 0 do - begin - tmp0 := dataptr^[0] + dataptr^[7]; - tmp7 := dataptr^[0] - dataptr^[7]; - tmp1 := dataptr^[1] + dataptr^[6]; - tmp6 := dataptr^[1] - dataptr^[6]; - tmp2 := dataptr^[2] + dataptr^[5]; - tmp5 := dataptr^[2] - dataptr^[5]; - tmp3 := dataptr^[3] + dataptr^[4]; - tmp4 := dataptr^[3] - dataptr^[4]; - - { Even part } - - tmp10 := tmp0 + tmp3; { phase 2 } - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - dataptr^[0] := tmp10 + tmp11; { phase 3 } - dataptr^[4] := tmp10 - tmp11; - - z1 := MULTIPLY(tmp12 + tmp13, FIX_0_707106781); { c4 } - dataptr^[2] := tmp13 + z1; { phase 5 } - dataptr^[6] := tmp13 - z1; - - { Odd part } - - tmp10 := tmp4 + tmp5; { phase 2 } - tmp11 := tmp5 + tmp6; - tmp12 := tmp6 + tmp7; - - { The rotator is modified from fig 4-8 to avoid extra negations. } - z5 := MULTIPLY(tmp10 - tmp12, FIX_0_382683433); { c6 } - z2 := MULTIPLY(tmp10, FIX_0_541196100) + z5; { c2-c6 } - z4 := MULTIPLY(tmp12, FIX_1_306562965) + z5; { c2+c6 } - z3 := MULTIPLY(tmp11, FIX_0_707106781); { c4 } - - z11 := tmp7 + z3; { phase 5 } - z13 := tmp7 - z3; - - dataptr^[5] := z13 + z2; { phase 6 } - dataptr^[3] := z13 - z2; - dataptr^[1] := z11 + z4; - dataptr^[7] := z11 - z4; - - Inc(DCTELEMPTR(dataptr), DCTSIZE); { advance pointer to next row } - end; - - { Pass 2: process columns. } - - dataptr := PWorkspace(@data); - for ctr := DCTSIZE-1 downto 0 do - begin - tmp0 := dataptr^[DCTSIZE*0] + dataptr^[DCTSIZE*7]; - tmp7 := dataptr^[DCTSIZE*0] - dataptr^[DCTSIZE*7]; - tmp1 := dataptr^[DCTSIZE*1] + dataptr^[DCTSIZE*6]; - tmp6 := dataptr^[DCTSIZE*1] - dataptr^[DCTSIZE*6]; - tmp2 := dataptr^[DCTSIZE*2] + dataptr^[DCTSIZE*5]; - tmp5 := dataptr^[DCTSIZE*2] - dataptr^[DCTSIZE*5]; - tmp3 := dataptr^[DCTSIZE*3] + dataptr^[DCTSIZE*4]; - tmp4 := dataptr^[DCTSIZE*3] - dataptr^[DCTSIZE*4]; - - { Even part } - - tmp10 := tmp0 + tmp3; { phase 2 } - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - dataptr^[DCTSIZE*0] := tmp10 + tmp11; { phase 3 } - dataptr^[DCTSIZE*4] := tmp10 - tmp11; - - z1 := MULTIPLY(tmp12 + tmp13, FIX_0_707106781); { c4 } - dataptr^[DCTSIZE*2] := tmp13 + z1; { phase 5 } - dataptr^[DCTSIZE*6] := tmp13 - z1; - - { Odd part } - - tmp10 := tmp4 + tmp5; { phase 2 } - tmp11 := tmp5 + tmp6; - tmp12 := tmp6 + tmp7; - - { The rotator is modified from fig 4-8 to avoid extra negations. } - z5 := MULTIPLY(tmp10 - tmp12, FIX_0_382683433); { c6 } - z2 := MULTIPLY(tmp10, FIX_0_541196100) + z5; { c2-c6 } - z4 := MULTIPLY(tmp12, FIX_1_306562965) + z5; { c2+c6 } - z3 := MULTIPLY(tmp11, FIX_0_707106781); { c4 } - - z11 := tmp7 + z3; { phase 5 } - z13 := tmp7 - z3; - - dataptr^[DCTSIZE*5] := z13 + z2; { phase 6 } - dataptr^[DCTSIZE*3] := z13 - z2; - dataptr^[DCTSIZE*1] := z11 + z4; - dataptr^[DCTSIZE*7] := z11 - z4; - - Inc(DCTELEMPTR(dataptr)); { advance pointer to next column } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjfdctint.pas b/3rd/Imaging/Source/JpegLib/imjfdctint.pas deleted file mode 100644 index bc946383b..000000000 --- a/3rd/Imaging/Source/JpegLib/imjfdctint.pas +++ /dev/null @@ -1,297 +0,0 @@ -unit imjfdctint; - - -{ This file contains a slow-but-accurate integer implementation of the - forward DCT (Discrete Cosine Transform). - - A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT - on each column. Direct algorithms are also available, but they are - much more complex and seem not to be any faster when reduced to code. - - This implementation is based on an algorithm described in - C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - The primary algorithm described there uses 11 multiplies and 29 adds. - We use their alternate method with 12 multiplies and 32 adds. - The advantage of this method is that no data path contains more than one - multiplication; this allows a very simple and accurate implementation in - scaled fixed-point arithmetic, with a minimal number of shifts. } - -{ Original : jfdctint.c ; Copyright (C) 1991-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjutils, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - - -{ Perform the forward DCT on one block of samples. } - -{GLOBAL} -procedure jpeg_fdct_islow (var data : array of DCTELEM); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - - -{ The poop on this scaling stuff is as follows: - - Each 1-D DCT step produces outputs which are a factor of sqrt(N) - larger than the true DCT outputs. The final outputs are therefore - a factor of N larger than desired; since N=8 this can be cured by - a simple right shift at the end of the algorithm. The advantage of - this arrangement is that we save two multiplications per 1-D DCT, - because the y0 and y4 outputs need not be divided by sqrt(N). - In the IJG code, this factor of 8 is removed by the quantization step - (in jcdctmgr.c), NOT in this module. - - We have to do addition and subtraction of the integer inputs, which - is no problem, and multiplication by fractional constants, which is - a problem to do in integer arithmetic. We multiply all the constants - by CONST_SCALE and convert them to integer constants (thus retaining - CONST_BITS bits of precision in the constants). After doing a - multiplication we have to divide the product by CONST_SCALE, with proper - rounding, to produce the correct output. This division can be done - cheaply as a right shift of CONST_BITS bits. We postpone shifting - as long as possible so that partial sums can be added together with - full fractional precision. - - The outputs of the first pass are scaled up by PASS1_BITS bits so that - they are represented to better-than-integral precision. These outputs - require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word - with the recommended scaling. (For 12-bit sample data, the intermediate - array is INT32 anyway.) - - To avoid overflow of the 32-bit intermediate results in pass 2, we must - have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis - shows that the values given below are the most effective. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - CONST_BITS = 13; - PASS1_BITS = 2; -{$else} -const - CONST_BITS = 13; - PASS1_BITS = 1; { lose a little precision to avoid overflow } -{$endif} - -const - CONST_SCALE = (INT32(1) shl CONST_BITS); - -const - FIX_0_298631336 = INT32(Round(CONST_SCALE * 0.298631336)); {2446} - FIX_0_390180644 = INT32(Round(CONST_SCALE * 0.390180644)); {3196} - FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100)); {4433} - FIX_0_765366865 = INT32(Round(CONST_SCALE * 0.765366865)); {6270} - FIX_0_899976223 = INT32(Round(CONST_SCALE * 0.899976223)); {7373} - FIX_1_175875602 = INT32(Round(CONST_SCALE * 1.175875602)); {9633} - FIX_1_501321110 = INT32(Round(CONST_SCALE * 1.501321110)); {12299} - FIX_1_847759065 = INT32(Round(CONST_SCALE * 1.847759065)); {15137} - FIX_1_961570560 = INT32(Round(CONST_SCALE * 1.961570560)); {16069} - FIX_2_053119869 = INT32(Round(CONST_SCALE * 2.053119869)); {16819} - FIX_2_562915447 = INT32(Round(CONST_SCALE * 2.562915447)); {20995} - FIX_3_072711026 = INT32(Round(CONST_SCALE * 3.072711026)); {25172} - - -{ Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - For 8-bit samples with the recommended scaling, all the variable - and constant values involved are no more than 16 bits wide, so a - 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - For 12-bit samples, a full 32-bit multiplication will be needed. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} - - {MULTIPLY16C16(var,const)} - function Multiply(X, Y: int): INT32; - begin - Multiply := int(X) * INT32(Y); - end; - -{$else} - function Multiply(X, Y: INT32): INT32; - begin - Multiply := X * Y; - end; -{$endif} - -{ Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - -function DESCALE(x : INT32; n : int) : INT32; -var - shift_temp : INT32; -begin -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - shift_temp := x + (INT32(1) shl (n-1)); - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else - Descale := (shift_temp shr n); -{$else} - Descale := (x + (INT32(1) shl (n-1)) shr n; -{$endif} -end; - - -{ Perform the forward DCT on one block of samples. } - -{GLOBAL} -procedure jpeg_fdct_islow (var data : array of DCTELEM); -type - PWorkspace = ^TWorkspace; - TWorkspace = array [0..DCTSIZE2-1] of DCTELEM; -var - tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : INT32; - tmp10, tmp11, tmp12, tmp13 : INT32; - z1, z2, z3, z4, z5 : INT32; - dataptr : PWorkspace; - ctr : int; - {SHIFT_TEMPS} -begin - - { Pass 1: process rows. } - { Note results are scaled up by sqrt(8) compared to a true DCT; } - { furthermore, we scale the results by 2**PASS1_BITS. } - - dataptr := PWorkspace(@data); - for ctr := DCTSIZE-1 downto 0 do - begin - tmp0 := dataptr^[0] + dataptr^[7]; - tmp7 := dataptr^[0] - dataptr^[7]; - tmp1 := dataptr^[1] + dataptr^[6]; - tmp6 := dataptr^[1] - dataptr^[6]; - tmp2 := dataptr^[2] + dataptr^[5]; - tmp5 := dataptr^[2] - dataptr^[5]; - tmp3 := dataptr^[3] + dataptr^[4]; - tmp4 := dataptr^[3] - dataptr^[4]; - - { Even part per LL&M figure 1 --- note that published figure is faulty; - rotator "sqrt(2)*c1" should be "sqrt(2)*c6". } - - tmp10 := tmp0 + tmp3; - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - dataptr^[0] := DCTELEM ((tmp10 + tmp11) shl PASS1_BITS); - dataptr^[4] := DCTELEM ((tmp10 - tmp11) shl PASS1_BITS); - - z1 := MULTIPLY(tmp12 + tmp13, FIX_0_541196100); - dataptr^[2] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), - CONST_BITS-PASS1_BITS)); - dataptr^[6] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), - CONST_BITS-PASS1_BITS)); - - { Odd part per figure 8 --- note paper omits factor of sqrt(2). - cK represents cos(K*pi/16). - i0..i3 in the paper are tmp4..tmp7 here. } - - z1 := tmp4 + tmp7; - z2 := tmp5 + tmp6; - z3 := tmp4 + tmp6; - z4 := tmp5 + tmp7; - z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 } - - tmp4 := MULTIPLY(tmp4, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) } - tmp5 := MULTIPLY(tmp5, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) } - tmp6 := MULTIPLY(tmp6, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) } - tmp7 := MULTIPLY(tmp7, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) } - z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) } - z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) } - z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) } - z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) } - - Inc(z3, z5); - Inc(z4, z5); - - dataptr^[7] := DCTELEM(DESCALE(tmp4 + z1 + z3, CONST_BITS-PASS1_BITS)); - dataptr^[5] := DCTELEM(DESCALE(tmp5 + z2 + z4, CONST_BITS-PASS1_BITS)); - dataptr^[3] := DCTELEM(DESCALE(tmp6 + z2 + z3, CONST_BITS-PASS1_BITS)); - dataptr^[1] := DCTELEM(DESCALE(tmp7 + z1 + z4, CONST_BITS-PASS1_BITS)); - - Inc(DCTELEMPTR(dataptr), DCTSIZE); { advance pointer to next row } - end; - - { Pass 2: process columns. - We remove the PASS1_BITS scaling, but leave the results scaled up - by an overall factor of 8. } - - dataptr := PWorkspace(@data); - for ctr := DCTSIZE-1 downto 0 do - begin - tmp0 := dataptr^[DCTSIZE*0] + dataptr^[DCTSIZE*7]; - tmp7 := dataptr^[DCTSIZE*0] - dataptr^[DCTSIZE*7]; - tmp1 := dataptr^[DCTSIZE*1] + dataptr^[DCTSIZE*6]; - tmp6 := dataptr^[DCTSIZE*1] - dataptr^[DCTSIZE*6]; - tmp2 := dataptr^[DCTSIZE*2] + dataptr^[DCTSIZE*5]; - tmp5 := dataptr^[DCTSIZE*2] - dataptr^[DCTSIZE*5]; - tmp3 := dataptr^[DCTSIZE*3] + dataptr^[DCTSIZE*4]; - tmp4 := dataptr^[DCTSIZE*3] - dataptr^[DCTSIZE*4]; - - { Even part per LL&M figure 1 --- note that published figure is faulty; - rotator "sqrt(2)*c1" should be "sqrt(2)*c6". } - - tmp10 := tmp0 + tmp3; - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - dataptr^[DCTSIZE*0] := DCTELEM (DESCALE(tmp10 + tmp11, PASS1_BITS)); - dataptr^[DCTSIZE*4] := DCTELEM (DESCALE(tmp10 - tmp11, PASS1_BITS)); - - z1 := MULTIPLY(tmp12 + tmp13, FIX_0_541196100); - dataptr^[DCTSIZE*2] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp13, FIX_0_765366865), - CONST_BITS+PASS1_BITS)); - dataptr^[DCTSIZE*6] := DCTELEM (DESCALE(z1 + MULTIPLY(tmp12, - FIX_1_847759065), - CONST_BITS+PASS1_BITS)); - - { Odd part per figure 8 --- note paper omits factor of sqrt(2). - cK represents cos(K*pi/16). - i0..i3 in the paper are tmp4..tmp7 here. } - - z1 := tmp4 + tmp7; - z2 := tmp5 + tmp6; - z3 := tmp4 + tmp6; - z4 := tmp5 + tmp7; - z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 } - - tmp4 := MULTIPLY(tmp4, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) } - tmp5 := MULTIPLY(tmp5, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) } - tmp6 := MULTIPLY(tmp6, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) } - tmp7 := MULTIPLY(tmp7, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) } - z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) } - z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) } - z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) } - z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) } - - Inc(z3, z5); - Inc(z4, z5); - - dataptr^[DCTSIZE*7] := DCTELEM (DESCALE(tmp4 + z1 + z3, - CONST_BITS+PASS1_BITS)); - dataptr^[DCTSIZE*5] := DCTELEM (DESCALE(tmp5 + z2 + z4, - CONST_BITS+PASS1_BITS)); - dataptr^[DCTSIZE*3] := DCTELEM (DESCALE(tmp6 + z2 + z3, - CONST_BITS+PASS1_BITS)); - dataptr^[DCTSIZE*1] := DCTELEM (DESCALE(tmp7 + z1 + z4, - CONST_BITS+PASS1_BITS)); - - Inc(DCTELEMPTR(dataptr)); { advance pointer to next column } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjidctasm.pas b/3rd/Imaging/Source/JpegLib/imjidctasm.pas deleted file mode 100644 index 3cf4e703f..000000000 --- a/3rd/Imaging/Source/JpegLib/imjidctasm.pas +++ /dev/null @@ -1,793 +0,0 @@ -unit imjidctasm; - -{ This file contains a slow-but-accurate integer implementation of the - inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - must also perform dequantization of the input coefficients. - - A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - on each row (or vice versa, but it's more convenient to emit a row at - a time). Direct algorithms are also available, but they are much more - complex and seem not to be any faster when reduced to code. - - This implementation is based on an algorithm described in - C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - The primary algorithm described there uses 11 multiplies and 29 adds. - We use their alternate method with 12 multiplies and 32 adds. - The advantage of this method is that no data path contains more than one - multiplication; this allows a very simple and accurate implementation in - scaled fixed-point arithmetic, with a minimal number of shifts. } - -{ Original : jidctint.c ; Copyright (C) 1991-1996, Thomas G. Lane. } -{ ;------------------------------------------------------------------------- - ; JIDCTINT.ASM - ; 80386 protected mode assembly translation of JIDCTINT.C - ; **** Optimized to all hell by Jason M. Felice (jasonf@apk.net) **** - ; **** E-mail welcome **** - ; - ; ** This code does not make O/S calls -- use it for OS/2, Win95, WinNT, - ; ** DOS prot. mode., Linux, whatever... have fun. - ; - ; ** Note, this code is dependant on the structure member order in the .h - ; ** files for the following structures: - ; -- amazingly NOT j_decompress_struct... cool. - ; -- jpeg_component_info (dependant on position of dct_table element) - ; - ; Originally created with the /Fa option of MSVC 4.0 (why work when you - ; don't have to?) - ; - ; (this code, when compiled is 1K bytes smaller than the optimized MSVC - ; release build, not to mention 120-130 ms faster in my profile test with 1 - ; small color and and 1 medium black-and-white jpeg: stats using TASM 4.0 - ; and MSVC 4.0 to create a non-console app; jpeg_idct_islow accumulated - ; 5,760 hits on all trials) - ; - ; TASM -t -ml -os jidctint.asm, jidctint.obj - ;------------------------------------------------------------------------- - Converted to Delphi 2.0 BASM for PasJPEG - by Jacques NOMSSI NZALI <nomssi@physik.tu-chemnitz.de> - October 13th 1996 - * assumes Delphi "register" calling convention - first 3 parameter are in EAX,EDX,ECX - * register allocation revised -} - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_islow (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - -{ The poop on this scaling stuff is as follows: - - Each 1-D IDCT step produces outputs which are a factor of sqrt(N) - larger than the true IDCT outputs. The final outputs are therefore - a factor of N larger than desired; since N=8 this can be cured by - a simple right shift at the end of the algorithm. The advantage of - this arrangement is that we save two multiplications per 1-D IDCT, - because the y0 and y4 inputs need not be divided by sqrt(N). - - We have to do addition and subtraction of the integer inputs, which - is no problem, and multiplication by fractional constants, which is - a problem to do in integer arithmetic. We multiply all the constants - by CONST_SCALE and convert them to integer constants (thus retaining - CONST_BITS bits of precision in the constants). After doing a - multiplication we have to divide the product by CONST_SCALE, with proper - rounding, to produce the correct output. This division can be done - cheaply as a right shift of CONST_BITS bits. We postpone shifting - as long as possible so that partial sums can be added together with - full fractional precision. - - The outputs of the first pass are scaled up by PASS1_BITS bits so that - they are represented to better-than-integral precision. These outputs - require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word - with the recommended scaling. (To scale up 12-bit sample data further, an - intermediate INT32 array would be needed.) - - To avoid overflow of the 32-bit intermediate results in pass 2, we must - have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis - shows that the values given below are the most effective. } - -const - CONST_BITS = 13; - -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - PASS1_BITS = 2; -{$else} -const - PASS1_BITS = 1; { lose a little precision to avoid overflow } -{$endif} - -const - CONST_SCALE = (INT32(1) shl CONST_BITS); - -const - FIX_0_298631336 = INT32(Round(CONST_SCALE * 0.298631336)); {2446} - FIX_0_390180644 = INT32(Round(CONST_SCALE * 0.390180644)); {3196} - FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100)); {4433} - FIX_0_765366865 = INT32(Round(CONST_SCALE * 0.765366865)); {6270} - FIX_0_899976223 = INT32(Round(CONST_SCALE * 0.899976223)); {7373} - FIX_1_175875602 = INT32(Round(CONST_SCALE * 1.175875602)); {9633} - FIX_1_501321110 = INT32(Round(CONST_SCALE * 1.501321110)); {12299} - FIX_1_847759065 = INT32(Round(CONST_SCALE * 1.847759065)); {15137} - FIX_1_961570560 = INT32(Round(CONST_SCALE * 1.961570560)); {16069} - FIX_2_053119869 = INT32(Round(CONST_SCALE * 2.053119869)); {16819} - FIX_2_562915447 = INT32(Round(CONST_SCALE * 2.562915447)); {20995} - FIX_3_072711026 = INT32(Round(CONST_SCALE * 3.072711026)); {25172} - - -{ for DESCALE } -const - ROUND_CONST = (INT32(1) shl (CONST_BITS-PASS1_BITS-1)); -const - ROUND_CONST_2 = (INT32(1) shl (CONST_BITS+PASS1_BITS+3-1)); - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_islow (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -type - PWorkspace = ^TWorkspace; - TWorkspace = coef_bits_field; { buffers data between passes } -const - coefDCTSIZE = DCTSIZE*SizeOf(JCOEF); - wrkDCTSIZE = DCTSIZE*SizeOf(int); -var - tmp0, tmp1, tmp2, tmp3 : INT32; - tmp10, tmp11, tmp12, tmp13 : INT32; - z1, z2, z3, z4, z5 : INT32; -var - inptr : JCOEFPTR; - quantptr : ISLOW_MULT_TYPE_FIELD_PTR; - wsptr : PWorkspace; - outptr : JSAMPROW; -var - range_limit : JSAMPROW; - ctr : int; - workspace : TWorkspace; -var - dcval : int; -var - dcval_ : JSAMPLE; -asm - push edi - push esi - push ebx - - cld { The only direction we use, might as well set it now, as opposed } - { to inside 2 loops. } - -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - {range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE]));} - mov eax, [eax].jpeg_decompress_struct.sample_range_limit {eax=cinfo} - add eax, (MAXJSAMPLE+1 + CENTERJSAMPLE)*(Type JSAMPLE) - mov range_limit, eax - - { Pass 1: process columns from input, store into work array. } - { Note results are scaled up by sqrt(8) compared to a true IDCT; } - { furthermore, we scale the results by 2**PASS1_BITS. } - - {inptr := coef_block;} - mov esi, ecx { ecx=coef_block } - {quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table);} - mov edi, [edx].jpeg_component_info.dct_table { edx=compptr } - - {wsptr := PWorkspace(@workspace);} - lea ecx, workspace - - {for ctr := pred(DCTSIZE) downto 0 do - begin} - mov ctr, DCTSIZE -@loop518: - { Due to quantization, we will usually find that many of the input - coefficients are zero, especially the AC terms. We can exploit this - by short-circuiting the IDCT calculation for any column in which all - the AC terms are zero. In that case each output is equal to the - DC coefficient (with scale factor as needed). - With typical images and quantization tables, half or more of the - column DCT calculations can be simplified this way. } - - {if ((inptr^[DCTSIZE*1]) or (inptr^[DCTSIZE*2]) or (inptr^[DCTSIZE*3]) or - (inptr^[DCTSIZE*4]) or (inptr^[DCTSIZE*5]) or (inptr^[DCTSIZE*6]) or - (inptr^[DCTSIZE*7]) = 0) then - begin} - mov eax, DWORD PTR [esi+coefDCTSIZE*1] - or eax, DWORD PTR [esi+coefDCTSIZE*2] - or eax, DWORD PTR [esi+coefDCTSIZE*3] - mov edx, DWORD PTR [esi+coefDCTSIZE*4] - or eax, edx - or eax, DWORD PTR [esi+coefDCTSIZE*5] - or eax, DWORD PTR [esi+coefDCTSIZE*6] - or eax, DWORD PTR [esi+coefDCTSIZE*7] - jne @loop520 - - { AC terms all zero } - {dcval := ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * - (quantptr^[DCTSIZE*0]) shl PASS1_BITS;} - mov eax, DWORD PTR [esi+coefDCTSIZE*0] - imul eax, DWORD PTR [edi+wrkDCTSIZE*0] - shl eax, PASS1_BITS - - {wsptr^[DCTSIZE*0] := dcval; - wsptr^[DCTSIZE*1] := dcval; - wsptr^[DCTSIZE*2] := dcval; - wsptr^[DCTSIZE*3] := dcval; - wsptr^[DCTSIZE*4] := dcval; - wsptr^[DCTSIZE*5] := dcval; - wsptr^[DCTSIZE*6] := dcval; - wsptr^[DCTSIZE*7] := dcval;} - - mov DWORD PTR [ecx+ wrkDCTSIZE*0], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*1], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*2], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*3], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*4], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*5], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*6], eax - mov DWORD PTR [ecx+ wrkDCTSIZE*7], eax - - {Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - {Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - continue;} - dec ctr - je @loop519 - - add esi, Type JCOEF - add edi, Type ISLOW_MULT_TYPE - add ecx, Type int { int_ptr } - jmp @loop518 - -@loop520: - - {end;} - - { Even part: reverse the even part of the forward DCT. } - { The rotator is sqrt(2)*c(-6). } - - {z2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*2]) * quantptr^[DCTSIZE*2]; - z3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*6]) * quantptr^[DCTSIZE*6]; - - z1 := (z2 + z3) * INT32(FIX_0_541196100); - tmp2 := z1 + INT32(z3) * INT32(- FIX_1_847759065); - tmp3 := z1 + INT32(z2) * INT32(FIX_0_765366865);} - - mov edx, DWORD PTR [esi+coefDCTSIZE*2] - imul edx, DWORD PTR [edi+wrkDCTSIZE*2] {z2} - - mov eax, DWORD PTR [esi+coefDCTSIZE*6] - imul eax, DWORD PTR [edi+wrkDCTSIZE*6] {z3} - - lea ebx, [eax+edx] - imul ebx, FIX_0_541196100 {z1} - - imul eax, (-FIX_1_847759065) - add eax, ebx - mov tmp2, eax - - imul edx, FIX_0_765366865 - add edx, ebx - mov tmp3, edx - - {z2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * quantptr^[DCTSIZE*0]; - z3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*4]) * quantptr^[DCTSIZE*4];} - - mov edx, DWORD PTR [esi+coefDCTSIZE*4] - imul edx, DWORD PTR [edi+wrkDCTSIZE*4] { z3 = edx } - - mov eax, DWORD PTR [esi+coefDCTSIZE*0] - imul eax, DWORD PTR [edi+wrkDCTSIZE*0] { z2 = eax } - - {tmp0 := (z2 + z3) shl CONST_BITS; - tmp1 := (z2 - z3) shl CONST_BITS;} - lea ebx,[eax+edx] - sub eax, edx - shl ebx, CONST_BITS { tmp0 = ebx } - shl eax, CONST_BITS { tmp1 = eax } - - {tmp10 := tmp0 + tmp3; - tmp13 := tmp0 - tmp3;} - mov edx, tmp3 - sub ebx, edx - mov tmp13, ebx - add edx, edx - add ebx, edx - mov tmp10, ebx - - {tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2;} - mov ebx, tmp2 - sub eax, ebx - mov tmp12, eax - add ebx, ebx - add eax, ebx - mov tmp11, eax - - { Odd part per figure 8; the matrix is unitary and hence its - transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. } - - {tmp0 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*7]) * quantptr^[DCTSIZE*7];} - mov eax, DWORD PTR [esi+coefDCTSIZE*7] - imul eax, DWORD PTR [edi+wrkDCTSIZE*7] - mov edx, eax { edx = tmp0 } - {tmp0 := (tmp0) * INT32(FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) } - imul eax, FIX_0_298631336 - mov tmp0, eax - - {tmp3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*1]) * quantptr^[DCTSIZE*1];} - mov eax, DWORD PTR [esi+coefDCTSIZE*1] - imul eax, DWORD PTR [edi+wrkDCTSIZE*1] - mov tmp3, eax - - {z1 := tmp0 + tmp3;} - {z1 := (z1) * INT32(- FIX_0_899976223); { sqrt(2) * (c7-c3) } - add eax, edx - imul eax, (-FIX_0_899976223) - mov z1, eax - - {tmp1 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*5]) * quantptr^[DCTSIZE*5];} - mov eax, DWORD PTR [esi+coefDCTSIZE*5] - imul eax, DWORD PTR [edi+wrkDCTSIZE*5] - mov ebx, eax { ebx = tmp1 } - {tmp1 := (tmp1) * INT32(FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) } - imul eax, FIX_2_053119869 - mov tmp1, eax - - {tmp2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*3]) * quantptr^[DCTSIZE*3];} - mov eax, DWORD PTR [esi+coefDCTSIZE*3] - imul eax, DWORD PTR [edi+wrkDCTSIZE*3] - mov tmp2, eax - - {z3 := tmp0 + tmp2;} - add edx, eax { edx = z3 } - - {z2 := tmp1 + tmp2;} - {z2 := (z2) * INT32(- FIX_2_562915447); { sqrt(2) * (-c1-c3) } - add eax, ebx - imul eax, (-FIX_2_562915447) - mov z2, eax - - {z4 := tmp1 + tmp3;} - add ebx, tmp3 { ebx = z4 } - - {z5 := INT32(z3 + z4) * INT32(FIX_1_175875602); { sqrt(2) * c3 } - lea eax, [edx+ebx] - imul eax, FIX_1_175875602 { eax = z5 } - - {z4 := (z4) * INT32(- FIX_0_390180644); { sqrt(2) * (c5-c3) } - {Inc(z4, z5);} - imul ebx, (-FIX_0_390180644) - add ebx, eax - mov z4, ebx - - {z3 := (z3) * INT32(- FIX_1_961570560); { sqrt(2) * (-c3-c5) } - {Inc(z3, z5);} - imul edx, (-FIX_1_961570560) - add eax, edx { z3 = eax } - - {Inc(tmp0, z1 + z3);} - mov ebx, z1 - add ebx, eax - add tmp0, ebx - - {tmp2 := (tmp2) * INT32(FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) } - {Inc(tmp2, z2 + z3);} - mov ebx, tmp2 - imul ebx, FIX_3_072711026 - mov edx, z2 { z2 = edx } - add ebx, edx - add eax, ebx - mov tmp2, eax - - {Inc(tmp1, z2 + z4);} - mov eax, z4 { z4 = eax } - add edx, eax - add tmp1, edx - - {tmp3 := (tmp3) * INT32(FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) } - {Inc(tmp3, z1 + z4);} - mov edx, tmp3 - imul edx, FIX_1_501321110 - - add edx, eax - add edx, z1 { tmp3 = edx } - - { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 } - - {wsptr^[DCTSIZE*0] := int (DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS));} - {wsptr^[DCTSIZE*7] := int (DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS));} - mov eax, tmp10 - add eax, ROUND_CONST - lea ebx, [eax+edx] - sar ebx, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*0], ebx - - sub eax, edx - sar eax, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*7], eax - - {wsptr^[DCTSIZE*1] := int (DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS));} - {wsptr^[DCTSIZE*6] := int (DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS));} - mov eax, tmp11 - add eax, ROUND_CONST - mov edx, tmp2 - lea ebx, [eax+edx] - sar ebx, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*1], ebx - - sub eax, edx - sar eax, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*6], eax - - {wsptr^[DCTSIZE*2] := int (DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS));} - {wsptr^[DCTSIZE*5] := int (DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS));} - mov eax, tmp12 - add eax, ROUND_CONST - mov edx, tmp1 - lea ebx, [eax+edx] - sar ebx, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*2], ebx - - sub eax, edx - sar eax, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*5], eax - - {wsptr^[DCTSIZE*3] := int (DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS));} - {wsptr^[DCTSIZE*4] := int (DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS));} - mov eax, tmp13 - add eax, ROUND_CONST - mov edx, tmp0 - lea ebx, [eax+edx] - sar ebx, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*3], ebx - - sub eax, edx - sar eax, CONST_BITS-PASS1_BITS - mov DWORD PTR [ecx+wrkDCTSIZE*4], eax - - {Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - {Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr));} - dec ctr - je @loop519 - - add esi, Type JCOEF - add edi, Type ISLOW_MULT_TYPE - add ecx, Type int { int_ptr } - {end;} - jmp @loop518 -@loop519: - { Save to memory what we've registerized for the preceding loop. } - - { Pass 2: process rows from work array, store into output array. } - { Note that we must descale the results by a factor of 8 == 2**3, } - { and also undo the PASS1_BITS scaling. } - - {wsptr := @workspace;} - lea esi, workspace - - {for ctr := 0 to pred(DCTSIZE) do - begin} - mov ctr, 0 -@loop523: - - {outptr := output_buf^[ctr];} - mov eax, ctr - mov ebx, output_buf - mov edi, DWORD PTR [ebx+eax*4] { 4 = SizeOf(pointer) } - - {Inc(JSAMPLE_PTR(outptr), output_col);} - add edi, LongWord(output_col) - - { Rows of zeroes can be exploited in the same way as we did with columns. - However, the column calculation has created many nonzero AC terms, so - the simplification applies less often (typically 5% to 10% of the time). - On machines with very fast multiplication, it's possible that the - test takes more time than it's worth. In that case this section - may be commented out. } - -{$ifndef NO_ZERO_ROW_TEST} - {if ((wsptr^[1]) or (wsptr^[2]) or (wsptr^[3]) or (wsptr^[4]) or - (wsptr^[5]) or (wsptr^[6]) or (wsptr^[7]) = 0) then - begin} - mov eax, DWORD PTR [esi+4*1] - or eax, DWORD PTR [esi+4*2] - or eax, DWORD PTR [esi+4*3] - jne @loop525 { Nomssi: early exit path may help } - or eax, DWORD PTR [esi+4*4] - or eax, DWORD PTR [esi+4*5] - or eax, DWORD PTR [esi+4*6] - or eax, DWORD PTR [esi+4*7] - jne @loop525 - - { AC terms all zero } - {JSAMPLE(dcval_) := range_limit^[int(DESCALE(INT32(wsptr^[0]), - PASS1_BITS+3)) and RANGE_MASK];} - mov eax, DWORD PTR [esi+4*0] - add eax, (INT32(1) shl (PASS1_BITS+3-1)) - sar eax, PASS1_BITS+3 - and eax, RANGE_MASK - mov ebx, range_limit - mov al, BYTE PTR [ebx+eax] - mov ah, al - - {outptr^[0] := dcval_; - outptr^[1] := dcval_; - outptr^[2] := dcval_; - outptr^[3] := dcval_; - outptr^[4] := dcval_; - outptr^[5] := dcval_; - outptr^[6] := dcval_; - outptr^[7] := dcval_;} - - stosw - stosw - stosw - stosw - - {Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - {continue;} - add esi, wrkDCTSIZE - inc ctr - cmp ctr, DCTSIZE - jl @loop523 - jmp @loop524 - {end;} -@loop525: -{$endif} - - - { Even part: reverse the even part of the forward DCT. } - { The rotator is sqrt(2)*c(-6). } - - {z2 := INT32 (wsptr^[2]);} - mov edx, DWORD PTR [esi+4*2] { z2 = edx } - - {z3 := INT32 (wsptr^[6]);} - mov ecx, DWORD PTR [esi+4*6] { z3 = ecx } - - {z1 := (z2 + z3) * INT32(FIX_0_541196100);} - lea eax, [edx+ecx] - imul eax, FIX_0_541196100 - mov ebx, eax { z1 = ebx } - - {tmp2 := z1 + (z3) * INT32(- FIX_1_847759065);} - imul ecx, (-FIX_1_847759065) - add ecx, ebx { tmp2 = ecx } - - {tmp3 := z1 + (z2) * INT32(FIX_0_765366865);} - imul edx, FIX_0_765366865 - add ebx, edx { tmp3 = ebx } - - {tmp0 := (INT32(wsptr^[0]) + INT32(wsptr^[4])) shl CONST_BITS;} - {tmp1 := (INT32(wsptr^[0]) - INT32(wsptr^[4])) shl CONST_BITS;} - mov edx, DWORD PTR [esi+4*4] - mov eax, DWORD PTR [esi+4*0] - sub eax, edx - add edx, edx - add edx, eax - shl edx, CONST_BITS { tmp0 = edx } - shl eax, CONST_BITS { tmp1 = eax } - - {tmp10 := tmp0 + tmp3;} - {tmp13 := tmp0 - tmp3;} - sub edx, ebx - mov tmp13, edx - add ebx, ebx - add edx, ebx - mov tmp10, edx - - {tmp11 := tmp1 + tmp2;} - {tmp12 := tmp1 - tmp2;} - lea ebx, [ecx+eax] - mov tmp11, ebx - sub eax, ecx - mov tmp12, eax - - { Odd part per figure 8; the matrix is unitary and hence its - transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. } - -{ The following lines no longer produce code, since wsptr has been - optimized to esi, it is more efficient to access these values - directly. - tmp0 := INT32(wsptr^[7]); - tmp1 := INT32(wsptr^[5]); - tmp2 := INT32(wsptr^[3]); - tmp3 := INT32(wsptr^[1]); } - - {z2 := tmp1 + tmp2;} - {z2 := (z2) * INT32(- FIX_2_562915447); { sqrt(2) * (-c1-c3) } - mov ebx, DWORD PTR [esi+4*3] { tmp2 } - mov ecx, DWORD PTR [esi+4*5] { tmp1 } - lea eax, [ebx+ecx] - imul eax, (-FIX_2_562915447) - mov z2, eax - - {z3 := tmp0 + tmp2;} - mov edx, DWORD PTR [esi+4*7] { tmp0 } - add ebx, edx { old z3 = ebx } - mov eax, ebx - {z3 := (z3) * INT32(- FIX_1_961570560); { sqrt(2) * (-c3-c5) } - imul eax, (-FIX_1_961570560) - mov z3, eax - - {z1 := tmp0 + tmp3;} - {z1 := (z1) * INT32(- FIX_0_899976223); { sqrt(2) * (c7-c3) } - mov eax, DWORD PTR [esi+4*1] { tmp3 } - add edx, eax - imul edx, (-FIX_0_899976223) { z1 = edx } - - {z4 := tmp1 + tmp3;} - add eax, ecx { +tmp1 } - add ebx, eax { z3 + z4 = ebx } - {z4 := (z4) * INT32(- FIX_0_390180644); { sqrt(2) * (c5-c3) } - imul eax, (-FIX_0_390180644) { z4 = eax } - - {z5 := (z3 + z4) * INT32(FIX_1_175875602); { sqrt(2) * c3 } - {Inc(z3, z5);} - imul ebx, FIX_1_175875602 - mov ecx, z3 - add ecx, ebx { ecx = z3 } - - {Inc(z4, z5);} - add ebx, eax { z4 = ebx } - - {tmp0 := (tmp0) * INT32(FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) } - {Inc(tmp0, z1 + z3);} - mov eax, DWORD PTR [esi+4*7] - imul eax, FIX_0_298631336 - add eax, edx - add eax, ecx - mov tmp0, eax - - {tmp1 := (tmp1) * INT32(FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) } - {Inc(tmp1, z2 + z4);} - mov eax, DWORD PTR [esi+4*5] - imul eax, FIX_2_053119869 - add eax, z2 - add eax, ebx - mov tmp1, eax - - {tmp2 := (tmp2) * INT32(FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) } - {Inc(tmp2, z2 + z3);} - mov eax, DWORD PTR [esi+4*3] - imul eax, FIX_3_072711026 - add eax, z2 - add ecx, eax { ecx = tmp2 } - - {tmp3 := (tmp3) * INT32(FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) } - {Inc(tmp3, z1 + z4);} - mov eax, DWORD PTR [esi+4*1] - imul eax, FIX_1_501321110 - add eax, edx - add ebx, eax { ebx = tmp3 } - - { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 } - - {outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp3, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK]; } - {outptr^[7] := range_limit^[ int(DESCALE(tmp10 - tmp3, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - - mov edx, tmp10 - add edx, ROUND_CONST_2 - lea eax, [ebx+edx] - sub edx, ebx - - shr eax, CONST_BITS+PASS1_BITS+3 - and eax, RANGE_MASK - mov ebx, range_limit { once for all } - mov al, BYTE PTR [ebx+eax] - mov [edi+0], al - - shr edx, CONST_BITS+PASS1_BITS+3 - and edx, RANGE_MASK - mov al, BYTE PTR [ebx+edx] - mov [edi+7], al - - {outptr^[1] := range_limit^[ int(DESCALE(tmp11 + tmp2, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - mov eax, tmp11 - add eax, ROUND_CONST_2 - lea edx, [eax+ecx] - shr edx, CONST_BITS+PASS1_BITS+3 - and edx, RANGE_MASK - mov dl, BYTE PTR [ebx+edx] - mov [edi+1], dl - - {outptr^[6] := range_limit^[ int(DESCALE(tmp11 - tmp2, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - sub eax, ecx - shr eax, CONST_BITS+PASS1_BITS+3 - and eax, RANGE_MASK - mov al, BYTE PTR [ebx+eax] - mov [edi+6], al - - {outptr^[2] := range_limit^[ int(DESCALE(tmp12 + tmp1, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - mov eax, tmp12 - add eax, ROUND_CONST_2 - mov ecx, tmp1 - lea edx, [eax+ecx] - shr edx, CONST_BITS+PASS1_BITS+3 - and edx, RANGE_MASK - mov dl, BYTE PTR [ebx+edx] - mov [edi+2], dl - - {outptr^[5] := range_limit^[ int(DESCALE(tmp12 - tmp1, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - sub eax, ecx - shr eax, CONST_BITS+PASS1_BITS+3 - and eax, RANGE_MASK - mov al, BYTE PTR [ebx+eax] - mov [edi+5], al - - {outptr^[3] := range_limit^[ int(DESCALE(tmp13 + tmp0, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - mov eax, tmp13 - add eax, ROUND_CONST_2 - mov ecx, tmp0 - lea edx, [eax+ecx] - shr edx, CONST_BITS+PASS1_BITS+3 - and edx, RANGE_MASK - mov dl, BYTE PTR [ebx+edx] - mov [edi+3], dl - - {outptr^[4] := range_limit^[ int(DESCALE(tmp13 - tmp0, - CONST_BITS+PASS1_BITS+3)) and RANGE_MASK];} - sub eax, ecx - shr eax, CONST_BITS+PASS1_BITS+3 - and eax, RANGE_MASK - mov al, BYTE PTR [ebx+eax] - mov [edi+4], al - - {Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - add esi, wrkDCTSIZE - add edi, DCTSIZE - - {end;} - inc ctr - cmp ctr, DCTSIZE - jl @loop523 - -@loop524: -@loop496: - pop ebx - pop esi - pop edi -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjidctflt.pas b/3rd/Imaging/Source/JpegLib/imjidctflt.pas deleted file mode 100644 index 68e158849..000000000 --- a/3rd/Imaging/Source/JpegLib/imjidctflt.pas +++ /dev/null @@ -1,286 +0,0 @@ -unit imjidctflt; - -{$N+} -{ This file contains a floating-point implementation of the - inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - must also perform dequantization of the input coefficients. - - This implementation should be more accurate than either of the integer - IDCT implementations. However, it may not give the same results on all - machines because of differences in roundoff behavior. Speed will depend - on the hardware's floating point capacity. - - A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - on each row (or vice versa, but it's more convenient to emit a row at - a time). Direct algorithms are also available, but they are much more - complex and seem not to be any faster when reduced to code. - - This implementation is based on Arai, Agui, and Nakajima's algorithm for - scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - Japanese, but the algorithm is described in the Pennebaker & Mitchell - JPEG textbook (see REFERENCES section in file README). The following code - is based directly on figure 4-8 in P&M. - While an 8-point DCT cannot be done in less than 11 multiplies, it is - possible to arrange the computation so that many of the multiplies are - simple scalings of the final outputs. These multiplies can then be - folded into the multiplications or divisions by the JPEG quantization - table entries. The AA&N method leaves only 5 multiplies and 29 adds - to be done in the DCT itself. - The primary disadvantage of this method is that with a fixed-point - implementation, accuracy is lost due to imprecise representation of the - scaled quantization values. However, that problem does not arise if - we use floating point arithmetic. } - -{ Original: jidctflt.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_float (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - - -{ Dequantize a coefficient by multiplying it by the multiplier-table - entry; produce a float result. } - -function DEQUANTIZE(coef : int; quantval : FAST_FLOAT) : FAST_FLOAT; -begin - Dequantize := ( (coef) * quantval); -end; - -{ Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - -function DESCALE(x : INT32; n : int) : INT32; -var - shift_temp : INT32; -begin -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - shift_temp := x + (INT32(1) shl (n-1)); - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else - Descale := (shift_temp shr n); -{$else} - Descale := (x + (INT32(1) shl (n-1)) shr n; -{$endif} -end; - - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_float (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -type - PWorkspace = ^TWorkspace; - TWorkspace = array[0..DCTSIZE2-1] of FAST_FLOAT; -var - tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : FAST_FLOAT; - tmp10, tmp11, tmp12, tmp13 : FAST_FLOAT; - z5, z10, z11, z12, z13 : FAST_FLOAT; - inptr : JCOEFPTR; - quantptr : FLOAT_MULT_TYPE_FIELD_PTR; - wsptr : PWorkSpace; - outptr : JSAMPROW; - range_limit : JSAMPROW; - ctr : int; - workspace : TWorkspace; { buffers data between passes } - {SHIFT_TEMPS} -var - dcval : FAST_FLOAT; -begin -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE])); - - { Pass 1: process columns from input, store into work array. } - - inptr := coef_block; - quantptr := FLOAT_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - wsptr := @workspace; - for ctr := pred(DCTSIZE) downto 0 do - begin - { Due to quantization, we will usually find that many of the input - coefficients are zero, especially the AC terms. We can exploit this - by short-circuiting the IDCT calculation for any column in which all - the AC terms are zero. In that case each output is equal to the - DC coefficient (with scale factor as needed). - With typical images and quantization tables, half or more of the - column DCT calculations can be simplified this way. } - - if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and - (inptr^[DCTSIZE*3]=0) and (inptr^[DCTSIZE*4]=0) and - (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and - (inptr^[DCTSIZE*7]=0) then - begin - { AC terms all zero } - FAST_FLOAT(dcval) := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]); - - wsptr^[DCTSIZE*0] := dcval; - wsptr^[DCTSIZE*1] := dcval; - wsptr^[DCTSIZE*2] := dcval; - wsptr^[DCTSIZE*3] := dcval; - wsptr^[DCTSIZE*4] := dcval; - wsptr^[DCTSIZE*5] := dcval; - wsptr^[DCTSIZE*6] := dcval; - wsptr^[DCTSIZE*7] := dcval; - - Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - Inc(FLOAT_MULT_TYPE_PTR(quantptr)); - Inc(FAST_FLOAT_PTR(wsptr)); - continue; - end; - - { Even part } - - tmp0 := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]); - tmp1 := DEQUANTIZE(inptr^[DCTSIZE*2], quantptr^[DCTSIZE*2]); - tmp2 := DEQUANTIZE(inptr^[DCTSIZE*4], quantptr^[DCTSIZE*4]); - tmp3 := DEQUANTIZE(inptr^[DCTSIZE*6], quantptr^[DCTSIZE*6]); - - tmp10 := tmp0 + tmp2; { phase 3 } - tmp11 := tmp0 - tmp2; - - tmp13 := tmp1 + tmp3; { phases 5-3 } - tmp12 := (tmp1 - tmp3) * ({FAST_FLOAT}(1.414213562)) - tmp13; { 2*c4 } - - tmp0 := tmp10 + tmp13; { phase 2 } - tmp3 := tmp10 - tmp13; - tmp1 := tmp11 + tmp12; - tmp2 := tmp11 - tmp12; - - { Odd part } - - tmp4 := DEQUANTIZE(inptr^[DCTSIZE*1], quantptr^[DCTSIZE*1]); - tmp5 := DEQUANTIZE(inptr^[DCTSIZE*3], quantptr^[DCTSIZE*3]); - tmp6 := DEQUANTIZE(inptr^[DCTSIZE*5], quantptr^[DCTSIZE*5]); - tmp7 := DEQUANTIZE(inptr^[DCTSIZE*7], quantptr^[DCTSIZE*7]); - - z13 := tmp6 + tmp5; { phase 6 } - z10 := tmp6 - tmp5; - z11 := tmp4 + tmp7; - z12 := tmp4 - tmp7; - - tmp7 := z11 + z13; { phase 5 } - tmp11 := (z11 - z13) * ({FAST_FLOAT}(1.414213562)); { 2*c4 } - - z5 := (z10 + z12) * ({FAST_FLOAT}(1.847759065)); { 2*c2 } - tmp10 := ({FAST_FLOAT}(1.082392200)) * z12 - z5; { 2*(c2-c6) } - tmp12 := ({FAST_FLOAT}(-2.613125930)) * z10 + z5; { -2*(c2+c6) } - - tmp6 := tmp12 - tmp7; { phase 2 } - tmp5 := tmp11 - tmp6; - tmp4 := tmp10 + tmp5; - - wsptr^[DCTSIZE*0] := tmp0 + tmp7; - wsptr^[DCTSIZE*7] := tmp0 - tmp7; - wsptr^[DCTSIZE*1] := tmp1 + tmp6; - wsptr^[DCTSIZE*6] := tmp1 - tmp6; - wsptr^[DCTSIZE*2] := tmp2 + tmp5; - wsptr^[DCTSIZE*5] := tmp2 - tmp5; - wsptr^[DCTSIZE*4] := tmp3 + tmp4; - wsptr^[DCTSIZE*3] := tmp3 - tmp4; - - Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - Inc(FLOAT_MULT_TYPE_PTR(quantptr)); - Inc(FAST_FLOAT_PTR(wsptr)); - end; - - { Pass 2: process rows from work array, store into output array. } - { Note that we must descale the results by a factor of 8 = 2**3. } - - wsptr := @workspace; - for ctr := 0 to pred(DCTSIZE) do - begin - outptr := JSAMPROW(@(output_buf^[ctr]^[output_col])); - { Rows of zeroes can be exploited in the same way as we did with columns. - However, the column calculation has created many nonzero AC terms, so - the simplification applies less often (typically 5% to 10% of the time). - And testing floats for zero is relatively expensive, so we don't bother. } - - { Even part } - - tmp10 := wsptr^[0] + wsptr^[4]; - tmp11 := wsptr^[0] - wsptr^[4]; - - tmp13 := wsptr^[2] + wsptr^[6]; - tmp12 := (wsptr^[2] - wsptr^[6]) * ({FAST_FLOAT}(1.414213562)) - tmp13; - - tmp0 := tmp10 + tmp13; - tmp3 := tmp10 - tmp13; - tmp1 := tmp11 + tmp12; - tmp2 := tmp11 - tmp12; - - { Odd part } - - z13 := wsptr^[5] + wsptr^[3]; - z10 := wsptr^[5] - wsptr^[3]; - z11 := wsptr^[1] + wsptr^[7]; - z12 := wsptr^[1] - wsptr^[7]; - - tmp7 := z11 + z13; - tmp11 := (z11 - z13) * ({FAST_FLOAT}(1.414213562)); - - z5 := (z10 + z12) * ({FAST_FLOAT}(1.847759065)); { 2*c2 } - tmp10 := ({FAST_FLOAT}(1.082392200)) * z12 - z5; { 2*(c2-c6) } - tmp12 := ({FAST_FLOAT}(-2.613125930)) * z10 + z5; { -2*(c2+c6) } - - tmp6 := tmp12 - tmp7; - tmp5 := tmp11 - tmp6; - tmp4 := tmp10 + tmp5; - - { Final output stage: scale down by a factor of 8 and range-limit } - - outptr^[0] := range_limit^[ int(DESCALE( INT32(Round((tmp0 + tmp7))), 3)) - and RANGE_MASK]; - outptr^[7] := range_limit^[ int(DESCALE( INT32(Round((tmp0 - tmp7))), 3)) - and RANGE_MASK]; - outptr^[1] := range_limit^[ int(DESCALE( INT32(Round((tmp1 + tmp6))), 3)) - and RANGE_MASK]; - outptr^[6] := range_limit^[ int(DESCALE( INT32(Round((tmp1 - tmp6))), 3)) - and RANGE_MASK]; - outptr^[2] := range_limit^[ int(DESCALE( INT32(Round((tmp2 + tmp5))), 3)) - and RANGE_MASK]; - outptr^[5] := range_limit^[ int(DESCALE( INT32(Round((tmp2 - tmp5))), 3)) - and RANGE_MASK]; - outptr^[4] := range_limit^[ int(DESCALE( INT32(Round((tmp3 + tmp4))), 3)) - and RANGE_MASK]; - outptr^[3] := range_limit^[ int(DESCALE( INT32(Round((tmp3 - tmp4))), 3)) - and RANGE_MASK]; - - Inc(FAST_FLOAT_PTR(wsptr), DCTSIZE); { advance pointer to next row } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjidctfst.pas b/3rd/Imaging/Source/JpegLib/imjidctfst.pas deleted file mode 100644 index 6b1dd9b97..000000000 --- a/3rd/Imaging/Source/JpegLib/imjidctfst.pas +++ /dev/null @@ -1,410 +0,0 @@ -unit imjidctfst; - -{ This file contains a fast, not so accurate integer implementation of the - inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - must also perform dequantization of the input coefficients. - - A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - on each row (or vice versa, but it's more convenient to emit a row at - a time). Direct algorithms are also available, but they are much more - complex and seem not to be any faster when reduced to code. - - This implementation is based on Arai, Agui, and Nakajima's algorithm for - scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in - Japanese, but the algorithm is described in the Pennebaker & Mitchell - JPEG textbook (see REFERENCES section in file README). The following code - is based directly on figure 4-8 in P&M. - While an 8-point DCT cannot be done in less than 11 multiplies, it is - possible to arrange the computation so that many of the multiplies are - simple scalings of the final outputs. These multiplies can then be - folded into the multiplications or divisions by the JPEG quantization - table entries. The AA&N method leaves only 5 multiplies and 29 adds - to be done in the DCT itself. - The primary disadvantage of this method is that with fixed-point math, - accuracy is lost due to imprecise representation of the scaled - quantization values. The smaller the quantization table entry, the less - precise the scaled value, so this implementation does worse with high- - quality-setting files than with low-quality ones. } - -{ Original : jidctfst.c ; Copyright (C) 1994-1996, Thomas G. Lane. } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_ifast (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - -{ Scaling decisions are generally the same as in the LL&M algorithm; - see jidctint.c for more details. However, we choose to descale - (right shift) multiplication products as soon as they are formed, - rather than carrying additional fractional bits into subsequent additions. - This compromises accuracy slightly, but it lets us save a few shifts. - More importantly, 16-bit arithmetic is then adequate (for 8-bit samples) - everywhere except in the multiplications proper; this saves a good deal - of work on 16-bit-int machines. - - The dequantized coefficients are not integers because the AA&N scaling - factors have been incorporated. We represent them scaled up by PASS1_BITS, - so that the first and second IDCT rounds have the same input scaling. - For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to - avoid a descaling shift; this compromises accuracy rather drastically - for small quantization table entries, but it saves a lot of shifts. - For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway, - so we use a much larger scaling factor to preserve accuracy. - - A final compromise is to represent the multiplicative constants to only - 8 fractional bits, rather than 13. This saves some shifting work on some - machines, and may also reduce the cost of multiplication (since there - are fewer one-bits in the constants). } - -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - CONST_BITS = 8; - PASS1_BITS = 2; -{$else} -const - CONST_BITS = 8; - PASS1_BITS = 1; { lose a little precision to avoid overflow } -{$endif} - - -const - FIX_1_082392200 = INT32(Round((INT32(1) shl CONST_BITS)*1.082392200)); {277} - FIX_1_414213562 = INT32(Round((INT32(1) shl CONST_BITS)*1.414213562)); {362} - FIX_1_847759065 = INT32(Round((INT32(1) shl CONST_BITS)*1.847759065)); {473} - FIX_2_613125930 = INT32(Round((INT32(1) shl CONST_BITS)*2.613125930)); {669} - - -{ Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - -function DESCALE(x : INT32; n : int) : INT32; -var - shift_temp : INT32; -begin -{$ifdef USE_ACCURATE_ROUNDING} - shift_temp := x + (INT32(1) shl (n-1)); -{$else} -{ We can gain a little more speed, with a further compromise in accuracy, - by omitting the addition in a descaling shift. This yields an incorrectly - rounded result half the time... } - shift_temp := x; -{$endif} - -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else -{$endif} - Descale := (shift_temp shr n); -end; - - -{ Multiply a DCTELEM variable by an INT32 constant, and immediately - descale to yield a DCTELEM result. } - - {(DCTELEM( DESCALE((var) * (const), CONST_BITS))} - function Multiply(Avar, Aconst: Integer): DCTELEM; - begin - Multiply := DCTELEM( Avar*INT32(Aconst) div (INT32(1) shl CONST_BITS)); - end; - - -{ Dequantize a coefficient by multiplying it by the multiplier-table - entry; produce a DCTELEM result. For 8-bit data a 16x16->16 - multiplication will do. For 12-bit data, the multiplier table is - declared INT32, so a 32-bit multiply will be used. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} - function DEQUANTIZE(coef,quantval : int) : int; - begin - Dequantize := ( IFAST_MULT_TYPE(coef) * quantval); - end; -{$else} - function DEQUANTIZE(coef,quantval : INT32) : int; - begin - Dequantize := DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS); - end; -{$endif} - - -{ Like DESCALE, but applies to a DCTELEM and produces an int. - We assume that int right shift is unsigned if INT32 right shift is. } - -function IDESCALE(x : DCTELEM; n : int) : int; -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - DCTELEMBITS = 16; { DCTELEM may be 16 or 32 bits } -{$else} -const - DCTELEMBITS = 32; { DCTELEM must be 32 bits } -{$endif} -var - ishift_temp : DCTELEM; -begin -{$ifndef USE_ACCURATE_ROUNDING} - ishift_temp := x + (INT32(1) shl (n-1)); -{$else} -{ We can gain a little more speed, with a further compromise in accuracy, - by omitting the addition in a descaling shift. This yields an incorrectly - rounded result half the time... } - ishift_temp := x; -{$endif} - -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - if ishift_temp < 0 then - IDescale := (ishift_temp shr n) - or ((not DCTELEM(0)) shl (DCTELEMBITS-n)) - else -{$endif} - IDescale := (ishift_temp shr n); -end; - - - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_ifast (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -type - PWorkspace = ^TWorkspace; - TWorkspace = coef_bits_field; { buffers data between passes } -var - tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7 : DCTELEM; - tmp10, tmp11, tmp12, tmp13 : DCTELEM; - z5, z10, z11, z12, z13 : DCTELEM; - inptr : JCOEFPTR; - quantptr : IFAST_MULT_TYPE_FIELD_PTR; - wsptr : PWorkspace; - outptr : JSAMPROW; - range_limit : JSAMPROW; - ctr : int; - workspace : TWorkspace; { buffers data between passes } - {SHIFT_TEMPS} { for DESCALE } - {ISHIFT_TEMPS} { for IDESCALE } -var - dcval : int; -var - dcval_ : JSAMPLE; -begin -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE])); - { Pass 1: process columns from input, store into work array. } - - inptr := coef_block; - quantptr := IFAST_MULT_TYPE_FIELD_PTR(compptr^.dct_table); - wsptr := @workspace; - for ctr := pred(DCTSIZE) downto 0 do - begin - { Due to quantization, we will usually find that many of the input - coefficients are zero, especially the AC terms. We can exploit this - by short-circuiting the IDCT calculation for any column in which all - the AC terms are zero. In that case each output is equal to the - DC coefficient (with scale factor as needed). - With typical images and quantization tables, half or more of the - column DCT calculations can be simplified this way. } - - if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and (inptr^[DCTSIZE*3]=0) and - (inptr^[DCTSIZE*4]=0) and (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and - (inptr^[DCTSIZE*7]=0) then - begin - { AC terms all zero } - dcval := int(DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0])); - - wsptr^[DCTSIZE*0] := dcval; - wsptr^[DCTSIZE*1] := dcval; - wsptr^[DCTSIZE*2] := dcval; - wsptr^[DCTSIZE*3] := dcval; - wsptr^[DCTSIZE*4] := dcval; - wsptr^[DCTSIZE*5] := dcval; - wsptr^[DCTSIZE*6] := dcval; - wsptr^[DCTSIZE*7] := dcval; - - Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - Inc(IFAST_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - continue; - end; - - { Even part } - - tmp0 := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]); - tmp1 := DEQUANTIZE(inptr^[DCTSIZE*2], quantptr^[DCTSIZE*2]); - tmp2 := DEQUANTIZE(inptr^[DCTSIZE*4], quantptr^[DCTSIZE*4]); - tmp3 := DEQUANTIZE(inptr^[DCTSIZE*6], quantptr^[DCTSIZE*6]); - - tmp10 := tmp0 + tmp2; { phase 3 } - tmp11 := tmp0 - tmp2; - - tmp13 := tmp1 + tmp3; { phases 5-3 } - tmp12 := MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; { 2*c4 } - - tmp0 := tmp10 + tmp13; { phase 2 } - tmp3 := tmp10 - tmp13; - tmp1 := tmp11 + tmp12; - tmp2 := tmp11 - tmp12; - - { Odd part } - - tmp4 := DEQUANTIZE(inptr^[DCTSIZE*1], quantptr^[DCTSIZE*1]); - tmp5 := DEQUANTIZE(inptr^[DCTSIZE*3], quantptr^[DCTSIZE*3]); - tmp6 := DEQUANTIZE(inptr^[DCTSIZE*5], quantptr^[DCTSIZE*5]); - tmp7 := DEQUANTIZE(inptr^[DCTSIZE*7], quantptr^[DCTSIZE*7]); - - z13 := tmp6 + tmp5; { phase 6 } - z10 := tmp6 - tmp5; - z11 := tmp4 + tmp7; - z12 := tmp4 - tmp7; - - tmp7 := z11 + z13; { phase 5 } - tmp11 := MULTIPLY(z11 - z13, FIX_1_414213562); { 2*c4 } - - z5 := MULTIPLY(z10 + z12, FIX_1_847759065); { 2*c2 } - tmp10 := MULTIPLY(z12, FIX_1_082392200) - z5; { 2*(c2-c6) } - tmp12 := MULTIPLY(z10, - FIX_2_613125930) + z5; { -2*(c2+c6) } - - tmp6 := tmp12 - tmp7; { phase 2 } - tmp5 := tmp11 - tmp6; - tmp4 := tmp10 + tmp5; - - wsptr^[DCTSIZE*0] := int (tmp0 + tmp7); - wsptr^[DCTSIZE*7] := int (tmp0 - tmp7); - wsptr^[DCTSIZE*1] := int (tmp1 + tmp6); - wsptr^[DCTSIZE*6] := int (tmp1 - tmp6); - wsptr^[DCTSIZE*2] := int (tmp2 + tmp5); - wsptr^[DCTSIZE*5] := int (tmp2 - tmp5); - wsptr^[DCTSIZE*4] := int (tmp3 + tmp4); - wsptr^[DCTSIZE*3] := int (tmp3 - tmp4); - - Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - Inc(IFAST_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - end; - - { Pass 2: process rows from work array, store into output array. } - { Note that we must descale the results by a factor of 8 == 2**3, } - { and also undo the PASS1_BITS scaling. } - - wsptr := @workspace; - for ctr := 0 to pred(DCTSIZE) do - begin - outptr := JSAMPROW(@output_buf^[ctr]^[output_col]); - { Rows of zeroes can be exploited in the same way as we did with columns. - However, the column calculation has created many nonzero AC terms, so - the simplification applies less often (typically 5% to 10% of the time). - On machines with very fast multiplication, it's possible that the - test takes more time than it's worth. In that case this section - may be commented out. } - -{$ifndef NO_ZERO_ROW_TEST} - if (wsptr^[1]=0) and (wsptr^[2]=0) and (wsptr^[3]=0) and (wsptr^[4]=0) and - (wsptr^[5]=0) and (wsptr^[6]=0) and (wsptr^[7]=0) then - begin - { AC terms all zero } - dcval_ := range_limit^[IDESCALE(wsptr^[0], PASS1_BITS+3) - and RANGE_MASK]; - - outptr^[0] := dcval_; - outptr^[1] := dcval_; - outptr^[2] := dcval_; - outptr^[3] := dcval_; - outptr^[4] := dcval_; - outptr^[5] := dcval_; - outptr^[6] := dcval_; - outptr^[7] := dcval_; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - continue; - end; -{$endif} - - { Even part } - - tmp10 := (DCTELEM(wsptr^[0]) + DCTELEM(wsptr^[4])); - tmp11 := (DCTELEM(wsptr^[0]) - DCTELEM(wsptr^[4])); - - tmp13 := (DCTELEM(wsptr^[2]) + DCTELEM(wsptr^[6])); - tmp12 := MULTIPLY(DCTELEM(wsptr^[2]) - DCTELEM(wsptr^[6]), FIX_1_414213562) - - tmp13; - - tmp0 := tmp10 + tmp13; - tmp3 := tmp10 - tmp13; - tmp1 := tmp11 + tmp12; - tmp2 := tmp11 - tmp12; - - { Odd part } - - z13 := DCTELEM(wsptr^[5]) + DCTELEM(wsptr^[3]); - z10 := DCTELEM(wsptr^[5]) - DCTELEM(wsptr^[3]); - z11 := DCTELEM(wsptr^[1]) + DCTELEM(wsptr^[7]); - z12 := DCTELEM(wsptr^[1]) - DCTELEM(wsptr^[7]); - - tmp7 := z11 + z13; { phase 5 } - tmp11 := MULTIPLY(z11 - z13, FIX_1_414213562); { 2*c4 } - - z5 := MULTIPLY(z10 + z12, FIX_1_847759065); { 2*c2 } - tmp10 := MULTIPLY(z12, FIX_1_082392200) - z5; { 2*(c2-c6) } - tmp12 := MULTIPLY(z10, - FIX_2_613125930) + z5; { -2*(c2+c6) } - - tmp6 := tmp12 - tmp7; { phase 2 } - tmp5 := tmp11 - tmp6; - tmp4 := tmp10 + tmp5; - - { Final output stage: scale down by a factor of 8 and range-limit } - - outptr^[0] := range_limit^[IDESCALE(tmp0 + tmp7, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[7] := range_limit^[IDESCALE(tmp0 - tmp7, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[1] := range_limit^[IDESCALE(tmp1 + tmp6, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[6] := range_limit^[IDESCALE(tmp1 - tmp6, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[2] := range_limit^[IDESCALE(tmp2 + tmp5, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[5] := range_limit^[IDESCALE(tmp2 - tmp5, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[4] := range_limit^[IDESCALE(tmp3 + tmp4, PASS1_BITS+3) - and RANGE_MASK]; - outptr^[3] := range_limit^[IDESCALE(tmp3 - tmp4, PASS1_BITS+3) - and RANGE_MASK]; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjidctint.pas b/3rd/Imaging/Source/JpegLib/imjidctint.pas deleted file mode 100644 index f46cc8f9c..000000000 --- a/3rd/Imaging/Source/JpegLib/imjidctint.pas +++ /dev/null @@ -1,440 +0,0 @@ -unit imjidctint; -{$Q+} - -{ This file contains a slow-but-accurate integer implementation of the - inverse DCT (Discrete Cosine Transform). In the IJG code, this routine - must also perform dequantization of the input coefficients. - - A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT - on each row (or vice versa, but it's more convenient to emit a row at - a time). Direct algorithms are also available, but they are much more - complex and seem not to be any faster when reduced to code. - - This implementation is based on an algorithm described in - C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT - Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics, - Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991. - The primary algorithm described there uses 11 multiplies and 29 adds. - We use their alternate method with 12 multiplies and 32 adds. - The advantage of this method is that no data path contains more than one - multiplication; this allows a very simple and accurate implementation in - scaled fixed-point arithmetic, with a minimal number of shifts. } - -{ Original : jidctint.c ; Copyright (C) 1991-1998, Thomas G. Lane. } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_islow (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - -{ The poop on this scaling stuff is as follows: - - Each 1-D IDCT step produces outputs which are a factor of sqrt(N) - larger than the true IDCT outputs. The final outputs are therefore - a factor of N larger than desired; since N=8 this can be cured by - a simple right shift at the end of the algorithm. The advantage of - this arrangement is that we save two multiplications per 1-D IDCT, - because the y0 and y4 inputs need not be divided by sqrt(N). - - We have to do addition and subtraction of the integer inputs, which - is no problem, and multiplication by fractional constants, which is - a problem to do in integer arithmetic. We multiply all the constants - by CONST_SCALE and convert them to integer constants (thus retaining - CONST_BITS bits of precision in the constants). After doing a - multiplication we have to divide the product by CONST_SCALE, with proper - rounding, to produce the correct output. This division can be done - cheaply as a right shift of CONST_BITS bits. We postpone shifting - as long as possible so that partial sums can be added together with - full fractional precision. - - The outputs of the first pass are scaled up by PASS1_BITS bits so that - they are represented to better-than-integral precision. These outputs - require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word - with the recommended scaling. (To scale up 12-bit sample data further, an - intermediate INT32 array would be needed.) - - To avoid overflow of the 32-bit intermediate results in pass 2, we must - have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis - shows that the values given below are the most effective. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - CONST_BITS = 13; - PASS1_BITS = 2; -{$else} -const - CONST_BITS = 13; - PASS1_BITS = 1; { lose a little precision to avoid overflow } -{$endif} - -const - CONST_SCALE = (INT32(1) shl CONST_BITS); - -const - FIX_0_298631336 = INT32(Round(CONST_SCALE * 0.298631336)); {2446} - FIX_0_390180644 = INT32(Round(CONST_SCALE * 0.390180644)); {3196} - FIX_0_541196100 = INT32(Round(CONST_SCALE * 0.541196100)); {4433} - FIX_0_765366865 = INT32(Round(CONST_SCALE * 0.765366865)); {6270} - FIX_0_899976223 = INT32(Round(CONST_SCALE * 0.899976223)); {7373} - FIX_1_175875602 = INT32(Round(CONST_SCALE * 1.175875602)); {9633} - FIX_1_501321110 = INT32(Round(CONST_SCALE * 1.501321110)); {12299} - FIX_1_847759065 = INT32(Round(CONST_SCALE * 1.847759065)); {15137} - FIX_1_961570560 = INT32(Round(CONST_SCALE * 1.961570560)); {16069} - FIX_2_053119869 = INT32(Round(CONST_SCALE * 2.053119869)); {16819} - FIX_2_562915447 = INT32(Round(CONST_SCALE * 2.562915447)); {20995} - FIX_3_072711026 = INT32(Round(CONST_SCALE * 3.072711026)); {25172} - - - -{ Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - For 8-bit samples with the recommended scaling, all the variable - and constant values involved are no more than 16 bits wide, so a - 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - For 12-bit samples, a full 32-bit multiplication will be needed. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} - - {$IFDEF BASM16} - {$IFNDEF WIN32} - {MULTIPLY16C16(var,const)} - function Multiply(X, Y: Integer): integer; assembler; - asm - mov ax, X - imul Y - mov al, ah - mov ah, dl - end; - {$ENDIF} - {$ENDIF} - - function Multiply(X, Y: INT32): INT32; - begin - Multiply := INT32(X) * INT32(Y); - end; - - -{$else} - {#define MULTIPLY(var,const) ((var) * (const))} - function Multiply(X, Y: INT32): INT32; - begin - Multiply := INT32(X) * INT32(Y); - end; -{$endif} - - -{ Dequantize a coefficient by multiplying it by the multiplier-table - entry; produce an int result. In this module, both inputs and result - are 16 bits or less, so either int or short multiply will work. } - -function DEQUANTIZE(coef,quantval : int) : int; -begin - Dequantize := ( ISLOW_MULT_TYPE(coef) * quantval); -end; - -{ Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - -function DESCALE(x : INT32; n : int) : INT32; -var - shift_temp : INT32; -begin -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - shift_temp := x + (INT32(1) shl (n-1)); - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else - Descale := (shift_temp shr n); -{$else} - Descale := (x + (INT32(1) shl (n-1)) shr n; -{$endif} -end; - -{ Perform dequantization and inverse DCT on one block of coefficients. } - -{GLOBAL} -procedure jpeg_idct_islow (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -type - PWorkspace = ^TWorkspace; - TWorkspace = coef_bits_field; { buffers data between passes } -var - tmp0, tmp1, tmp2, tmp3 : INT32; - tmp10, tmp11, tmp12, tmp13 : INT32; - z1, z2, z3, z4, z5 : INT32; - inptr : JCOEFPTR; - quantptr : ISLOW_MULT_TYPE_FIELD_PTR; - wsptr : PWorkspace; - outptr : JSAMPROW; - range_limit : JSAMPROW; - ctr : int; - workspace : TWorkspace; - {SHIFT_TEMPS} -var - dcval : int; -var - dcval_ : JSAMPLE; -begin -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE])); - - - { Pass 1: process columns from input, store into work array. } - { Note results are scaled up by sqrt(8) compared to a true IDCT; } - { furthermore, we scale the results by 2**PASS1_BITS. } - - inptr := coef_block; - quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - wsptr := PWorkspace(@workspace); - for ctr := pred(DCTSIZE) downto 0 do - begin - { Due to quantization, we will usually find that many of the input - coefficients are zero, especially the AC terms. We can exploit this - by short-circuiting the IDCT calculation for any column in which all - the AC terms are zero. In that case each output is equal to the - DC coefficient (with scale factor as needed). - With typical images and quantization tables, half or more of the - column DCT calculations can be simplified this way. } - - if ((inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and - (inptr^[DCTSIZE*3]=0) and (inptr^[DCTSIZE*4]=0) and - (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and - (inptr^[DCTSIZE*7]=0)) then - begin - { AC terms all zero } - dcval := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]) shl PASS1_BITS; - - wsptr^[DCTSIZE*0] := dcval; - wsptr^[DCTSIZE*1] := dcval; - wsptr^[DCTSIZE*2] := dcval; - wsptr^[DCTSIZE*3] := dcval; - wsptr^[DCTSIZE*4] := dcval; - wsptr^[DCTSIZE*5] := dcval; - wsptr^[DCTSIZE*6] := dcval; - wsptr^[DCTSIZE*7] := dcval; - - Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - continue; - end; - - { Even part: reverse the even part of the forward DCT. } - { The rotator is sqrt(2)*c(-6). } - - z2 := DEQUANTIZE(inptr^[DCTSIZE*2], quantptr^[DCTSIZE*2]); - z3 := DEQUANTIZE(inptr^[DCTSIZE*6], quantptr^[DCTSIZE*6]); - - z1 := MULTIPLY(z2 + z3, FIX_0_541196100); - tmp2 := z1 + MULTIPLY(z3, - FIX_1_847759065); - tmp3 := z1 + MULTIPLY(z2, FIX_0_765366865); - - z2 := DEQUANTIZE(inptr^[DCTSIZE*0], quantptr^[DCTSIZE*0]); - z3 := DEQUANTIZE(inptr^[DCTSIZE*4], quantptr^[DCTSIZE*4]); - - tmp0 := (z2 + z3) shl CONST_BITS; - tmp1 := (z2 - z3) shl CONST_BITS; - - tmp10 := tmp0 + tmp3; - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - { Odd part per figure 8; the matrix is unitary and hence its - transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. } - - tmp0 := DEQUANTIZE(inptr^[DCTSIZE*7], quantptr^[DCTSIZE*7]); - tmp1 := DEQUANTIZE(inptr^[DCTSIZE*5], quantptr^[DCTSIZE*5]); - tmp2 := DEQUANTIZE(inptr^[DCTSIZE*3], quantptr^[DCTSIZE*3]); - tmp3 := DEQUANTIZE(inptr^[DCTSIZE*1], quantptr^[DCTSIZE*1]); - - z1 := tmp0 + tmp3; - z2 := tmp1 + tmp2; - z3 := tmp0 + tmp2; - z4 := tmp1 + tmp3; - z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 } - - tmp0 := MULTIPLY(tmp0, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) } - tmp1 := MULTIPLY(tmp1, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) } - tmp2 := MULTIPLY(tmp2, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) } - tmp3 := MULTIPLY(tmp3, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) } - z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) } - z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) } - z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) } - z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) } - - Inc(z3, z5); - Inc(z4, z5); - - Inc(tmp0, z1 + z3); - Inc(tmp1, z2 + z4); - Inc(tmp2, z2 + z3); - Inc(tmp3, z1 + z4); - - { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 } - - wsptr^[DCTSIZE*0] := int (DESCALE(tmp10 + tmp3, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*7] := int (DESCALE(tmp10 - tmp3, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*1] := int (DESCALE(tmp11 + tmp2, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*6] := int (DESCALE(tmp11 - tmp2, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*2] := int (DESCALE(tmp12 + tmp1, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*5] := int (DESCALE(tmp12 - tmp1, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*3] := int (DESCALE(tmp13 + tmp0, CONST_BITS-PASS1_BITS)); - wsptr^[DCTSIZE*4] := int (DESCALE(tmp13 - tmp0, CONST_BITS-PASS1_BITS)); - - Inc(JCOEF_PTR(inptr)); { advance pointers to next column } - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - end; - - { Pass 2: process rows from work array, store into output array. } - { Note that we must descale the results by a factor of 8 == 2**3, } - { and also undo the PASS1_BITS scaling. } - - wsptr := @workspace; - for ctr := 0 to pred(DCTSIZE) do - begin - outptr := output_buf^[ctr]; - Inc(JSAMPLE_PTR(outptr), output_col); - { Rows of zeroes can be exploited in the same way as we did with columns. - However, the column calculation has created many nonzero AC terms, so - the simplification applies less often (typically 5% to 10% of the time). - On machines with very fast multiplication, it's possible that the - test takes more time than it's worth. In that case this section - may be commented out. } - -{$ifndef NO_ZERO_ROW_TEST} - if ((wsptr^[1]=0) and (wsptr^[2]=0) and (wsptr^[3]=0) and (wsptr^[4]=0) - and (wsptr^[5]=0) and (wsptr^[6]=0) and (wsptr^[7]=0)) then - begin - { AC terms all zero } - JSAMPLE(dcval_) := range_limit^[int(DESCALE(INT32(wsptr^[0]), - PASS1_BITS+3)) and RANGE_MASK]; - - outptr^[0] := dcval_; - outptr^[1] := dcval_; - outptr^[2] := dcval_; - outptr^[3] := dcval_; - outptr^[4] := dcval_; - outptr^[5] := dcval_; - outptr^[6] := dcval_; - outptr^[7] := dcval_; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - continue; - end; -{$endif} - - { Even part: reverse the even part of the forward DCT. } - { The rotator is sqrt(2)*c(-6). } - - z2 := INT32 (wsptr^[2]); - z3 := INT32 (wsptr^[6]); - - z1 := MULTIPLY(z2 + z3, FIX_0_541196100); - tmp2 := z1 + MULTIPLY(z3, - FIX_1_847759065); - tmp3 := z1 + MULTIPLY(z2, FIX_0_765366865); - - tmp0 := (INT32(wsptr^[0]) + INT32(wsptr^[4])) shl CONST_BITS; - tmp1 := (INT32(wsptr^[0]) - INT32(wsptr^[4])) shl CONST_BITS; - - tmp10 := tmp0 + tmp3; - tmp13 := tmp0 - tmp3; - tmp11 := tmp1 + tmp2; - tmp12 := tmp1 - tmp2; - - { Odd part per figure 8; the matrix is unitary and hence its - transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. } - - tmp0 := INT32(wsptr^[7]); - tmp1 := INT32(wsptr^[5]); - tmp2 := INT32(wsptr^[3]); - tmp3 := INT32(wsptr^[1]); - - z1 := tmp0 + tmp3; - z2 := tmp1 + tmp2; - z3 := tmp0 + tmp2; - z4 := tmp1 + tmp3; - z5 := MULTIPLY(z3 + z4, FIX_1_175875602); { sqrt(2) * c3 } - - tmp0 := MULTIPLY(tmp0, FIX_0_298631336); { sqrt(2) * (-c1+c3+c5-c7) } - tmp1 := MULTIPLY(tmp1, FIX_2_053119869); { sqrt(2) * ( c1+c3-c5+c7) } - tmp2 := MULTIPLY(tmp2, FIX_3_072711026); { sqrt(2) * ( c1+c3+c5-c7) } - tmp3 := MULTIPLY(tmp3, FIX_1_501321110); { sqrt(2) * ( c1+c3-c5-c7) } - z1 := MULTIPLY(z1, - FIX_0_899976223); { sqrt(2) * (c7-c3) } - z2 := MULTIPLY(z2, - FIX_2_562915447); { sqrt(2) * (-c1-c3) } - z3 := MULTIPLY(z3, - FIX_1_961570560); { sqrt(2) * (-c3-c5) } - z4 := MULTIPLY(z4, - FIX_0_390180644); { sqrt(2) * (c5-c3) } - - Inc(z3, z5); - Inc(z4, z5); - - Inc(tmp0, z1 + z3); - Inc(tmp1, z2 + z4); - Inc(tmp2, z2 + z3); - Inc(tmp3, z1 + z4); - - { Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 } - - outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp3, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[7] := range_limit^[ int(DESCALE(tmp10 - tmp3, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[1] := range_limit^[ int(DESCALE(tmp11 + tmp2, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[6] := range_limit^[ int(DESCALE(tmp11 - tmp2, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[2] := range_limit^[ int(DESCALE(tmp12 + tmp1, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[5] := range_limit^[ int(DESCALE(tmp12 - tmp1, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[3] := range_limit^[ int(DESCALE(tmp13 + tmp0, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - outptr^[4] := range_limit^[ int(DESCALE(tmp13 - tmp0, - CONST_BITS+PASS1_BITS+3)) - and RANGE_MASK]; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - end; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjidctred.pas b/3rd/Imaging/Source/JpegLib/imjidctred.pas deleted file mode 100644 index dae7bfcbb..000000000 --- a/3rd/Imaging/Source/JpegLib/imjidctred.pas +++ /dev/null @@ -1,525 +0,0 @@ -unit imjidctred; - - -{ This file contains inverse-DCT routines that produce reduced-size output: - either 4x4, 2x2, or 1x1 pixels from an 8x8 DCT block. - - The implementation is based on the Loeffler, Ligtenberg and Moschytz (LL&M) - algorithm used in jidctint.c. We simply replace each 8-to-8 1-D IDCT step - with an 8-to-4 step that produces the four averages of two adjacent outputs - (or an 8-to-2 step producing two averages of four outputs, for 2x2 output). - These steps were derived by computing the corresponding values at the end - of the normal LL&M code, then simplifying as much as possible. - - 1x1 is trivial: just take the DC coefficient divided by 8. - - See jidctint.c for additional comments. } - - -{ Original : jidctred.c ; Copyright (C) 1994-1998, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib, - imjdct; { Private declarations for DCT subsystem } - -{ Perform dequantization and inverse DCT on one block of coefficients, - producing a reduced-size 1x1 output block. } - -{GLOBAL} -procedure jpeg_idct_1x1 (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -{ Perform dequantization and inverse DCT on one block of coefficients, - producing a reduced-size 2x2 output block. } - -{GLOBAL} -procedure jpeg_idct_2x2 (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -{ Perform dequantization and inverse DCT on one block of coefficients, - producing a reduced-size 4x4 output block. } - -{GLOBAL} -procedure jpeg_idct_4x4 (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); - -implementation - -{ This module is specialized to the case DCTSIZE = 8. } - -{$ifndef DCTSIZE_IS_8} - Sorry, this code only copes with 8x8 DCTs. { deliberate syntax err } -{$endif} - - -{ Scaling is the same as in jidctint.c. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} -const - CONST_BITS = 13; - PASS1_BITS = 2; -{$else} -const - CONST_BITS = 13; - PASS1_BITS = 1; { lose a little precision to avoid overflow } -{$endif} - -const - FIX_0_211164243 = INT32(Round((INT32(1) shl CONST_BITS) * 0.211164243)); {1730} - FIX_0_509795579 = INT32(Round((INT32(1) shl CONST_BITS) * 0.509795579)); {4176} - FIX_0_601344887 = INT32(Round((INT32(1) shl CONST_BITS) * 0.601344887)); {4926} - FIX_0_720959822 = INT32(Round((INT32(1) shl CONST_BITS) * 0.720959822)); {5906} - FIX_0_765366865 = INT32(Round((INT32(1) shl CONST_BITS) * 0.765366865)); {6270} - FIX_0_850430095 = INT32(Round((INT32(1) shl CONST_BITS) * 0.850430095)); {6967} - FIX_0_899976223 = INT32(Round((INT32(1) shl CONST_BITS) * 0.899976223)); {7373} - FIX_1_061594337 = INT32(Round((INT32(1) shl CONST_BITS) * 1.061594337)); {8697} - FIX_1_272758580 = INT32(Round((INT32(1) shl CONST_BITS) * 1.272758580)); {10426} - FIX_1_451774981 = INT32(Round((INT32(1) shl CONST_BITS) * 1.451774981)); {11893} - FIX_1_847759065 = INT32(Round((INT32(1) shl CONST_BITS) * 1.847759065)); {15137} - FIX_2_172734803 = INT32(Round((INT32(1) shl CONST_BITS) * 2.172734803)); {17799} - FIX_2_562915447 = INT32(Round((INT32(1) shl CONST_BITS) * 2.562915447)); {20995} - FIX_3_624509785 = INT32(Round((INT32(1) shl CONST_BITS) * 3.624509785)); {29692} - - -{ Multiply an INT32 variable by an INT32 constant to yield an INT32 result. - For 8-bit samples with the recommended scaling, all the variable - and constant values involved are no more than 16 bits wide, so a - 16x16->32 bit multiply can be used instead of a full 32x32 multiply. - For 12-bit samples, a full 32-bit multiplication will be needed. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} - - {function Multiply(X, Y: Integer): integer; assembler; - asm - mov ax, X - imul Y - mov al, ah - mov ah, dl - end;} - - {MULTIPLY16C16(var,const)} - function Multiply(X, Y: Integer): INT32; - begin - Multiply := X*INT32(Y); - end; - - -{$else} - function Multiply(X, Y: INT32): INT32; - begin - Multiply := X*Y; - end; -{$endif} - - -{ Dequantize a coefficient by multiplying it by the multiplier-table - entry; produce an int result. In this module, both inputs and result - are 16 bits or less, so either int or short multiply will work. } - -function DEQUANTIZE(coef,quantval : int) : int; -begin - Dequantize := ( ISLOW_MULT_TYPE(coef) * quantval); -end; - - -{ Descale and correctly round an INT32 value that's scaled by N bits. - We assume RIGHT_SHIFT rounds towards minus infinity, so adding - the fudge factor is correct for either sign of X. } - -function DESCALE(x : INT32; n : int) : INT32; -var - shift_temp : INT32; -begin -{$ifdef RIGHT_SHIFT_IS_UNSIGNED} - shift_temp := x + (INT32(1) shl (n-1)); - if shift_temp < 0 then - Descale := (shift_temp shr n) or ((not INT32(0)) shl (32-n)) - else - Descale := (shift_temp shr n); -{$else} - Descale := (x + (INT32(1) shl (n-1)) shr n; -{$endif} -end; - -{ Perform dequantization and inverse DCT on one block of coefficients, - producing a reduced-size 4x4 output block. } - -{GLOBAL} -procedure jpeg_idct_4x4 (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -type - PWorkspace = ^TWorkspace; - TWorkspace = array[0..(DCTSIZE*4)-1] of int; { buffers data between passes } -var - tmp0, tmp2, tmp10, tmp12 : INT32; - z1, z2, z3, z4 : INT32; - inptr : JCOEFPTR; - quantptr : ISLOW_MULT_TYPE_FIELD_PTR; - wsptr : PWorkspace; - outptr : JSAMPROW; - range_limit : JSAMPROW; - ctr : int; - workspace : TWorkspace; { buffers data between passes } - {SHIFT_TEMPS} -var - dcval : int; -var - dcval_ : JSAMPLE; -begin -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE])); - - { Pass 1: process columns from input, store into work array. } - - inptr := coef_block; - quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - wsptr := @workspace; - for ctr := DCTSIZE downto 1 do - begin - { Don't bother to process column 4, because second pass won't use it } - if (ctr = DCTSIZE-4) then - begin - Inc(JCOEF_PTR(inptr)); - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - - continue; - end; - if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*2]=0) and (inptr^[DCTSIZE*3]=0) and - (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*6]=0) and (inptr^[DCTSIZE*7]=0) then - begin - { AC terms all zero; we need not examine term 4 for 4x4 output } - dcval := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * - quantptr^[DCTSIZE*0]) shl PASS1_BITS; - - wsptr^[DCTSIZE*0] := dcval; - wsptr^[DCTSIZE*1] := dcval; - wsptr^[DCTSIZE*2] := dcval; - wsptr^[DCTSIZE*3] := dcval; - - Inc(JCOEF_PTR(inptr)); - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - - continue; - end; - - { Even part } - - tmp0 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * quantptr^[DCTSIZE*0]); - - tmp0 := tmp0 shl (CONST_BITS+1); - - z2 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*2]) * quantptr^[DCTSIZE*2]); - z3 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*6]) * quantptr^[DCTSIZE*6]); - - tmp2 := MULTIPLY(z2, FIX_1_847759065) + MULTIPLY(z3, - FIX_0_765366865); - - tmp10 := tmp0 + tmp2; - tmp12 := tmp0 - tmp2; - - { Odd part } - - z1 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*7]) * quantptr^[DCTSIZE*7]; - z2 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*5]) * quantptr^[DCTSIZE*5]; - z3 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*3]) * quantptr^[DCTSIZE*3]; - z4 := ISLOW_MULT_TYPE(inptr^[DCTSIZE*1]) * quantptr^[DCTSIZE*1]; - - tmp0 := MULTIPLY(z1, - FIX_0_211164243) { sqrt(2) * (c3-c1) } - + MULTIPLY(z2, FIX_1_451774981) { sqrt(2) * (c3+c7) } - + MULTIPLY(z3, - FIX_2_172734803) { sqrt(2) * (-c1-c5) } - + MULTIPLY(z4, FIX_1_061594337); { sqrt(2) * (c5+c7) } - - tmp2 := MULTIPLY(z1, - FIX_0_509795579) { sqrt(2) * (c7-c5) } - + MULTIPLY(z2, - FIX_0_601344887) { sqrt(2) * (c5-c1) } - + MULTIPLY(z3, FIX_0_899976223) { sqrt(2) * (c3-c7) } - + MULTIPLY(z4, FIX_2_562915447); { sqrt(2) * (c1+c3) } - - { Final output stage } - - wsptr^[DCTSIZE*0] := int(DESCALE(tmp10 + tmp2, CONST_BITS-PASS1_BITS+1)); - wsptr^[DCTSIZE*3] := int(DESCALE(tmp10 - tmp2, CONST_BITS-PASS1_BITS+1)); - wsptr^[DCTSIZE*1] := int(DESCALE(tmp12 + tmp0, CONST_BITS-PASS1_BITS+1)); - wsptr^[DCTSIZE*2] := int(DESCALE(tmp12 - tmp0, CONST_BITS-PASS1_BITS+1)); - - Inc(JCOEF_PTR(inptr)); - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - end; - - { Pass 2: process 4 rows from work array, store into output array. } - - wsptr := @workspace; - for ctr := 0 to pred(4) do - begin - outptr := JSAMPROW(@ output_buf^[ctr]^[output_col]); - { It's not clear whether a zero row test is worthwhile here ... } - -{$ifndef NO_ZERO_ROW_TEST} - if (wsptr^[1]=0) and (wsptr^[2]=0) and (wsptr^[3]=0) and - (wsptr^[5]=0) and (wsptr^[6]=0) and (wsptr^[7]=0) then - begin - { AC terms all zero } - dcval_ := range_limit^[int(DESCALE(INT32(wsptr^[0]), PASS1_BITS+3)) - and RANGE_MASK]; - - outptr^[0] := dcval_; - outptr^[1] := dcval_; - outptr^[2] := dcval_; - outptr^[3] := dcval_; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - continue; - end; -{$endif} - - { Even part } - - tmp0 := (INT32(wsptr^[0])) shl (CONST_BITS+1); - - tmp2 := MULTIPLY(INT32(wsptr^[2]), FIX_1_847759065) - + MULTIPLY(INT32(wsptr^[6]), - FIX_0_765366865); - - tmp10 := tmp0 + tmp2; - tmp12 := tmp0 - tmp2; - - { Odd part } - - z1 := INT32(wsptr^[7]); - z2 := INT32(wsptr^[5]); - z3 := INT32(wsptr^[3]); - z4 := INT32(wsptr^[1]); - - tmp0 := MULTIPLY(z1, - FIX_0_211164243) { sqrt(2) * (c3-c1) } - + MULTIPLY(z2, FIX_1_451774981) { sqrt(2) * (c3+c7) } - + MULTIPLY(z3, - FIX_2_172734803) { sqrt(2) * (-c1-c5) } - + MULTIPLY(z4, FIX_1_061594337); { sqrt(2) * (c5+c7) } - - tmp2 := MULTIPLY(z1, - FIX_0_509795579) { sqrt(2) * (c7-c5) } - + MULTIPLY(z2, - FIX_0_601344887) { sqrt(2) * (c5-c1) } - + MULTIPLY(z3, FIX_0_899976223) { sqrt(2) * (c3-c7) } - + MULTIPLY(z4, FIX_2_562915447); { sqrt(2) * (c1+c3) } - - { Final output stage } - - outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp2, - CONST_BITS+PASS1_BITS+3+1)) - and RANGE_MASK]; - outptr^[3] := range_limit^[ int(DESCALE(tmp10 - tmp2, - CONST_BITS+PASS1_BITS+3+1)) - and RANGE_MASK]; - outptr^[1] := range_limit^[ int(DESCALE(tmp12 + tmp0, - CONST_BITS+PASS1_BITS+3+1)) - and RANGE_MASK]; - outptr^[2] := range_limit^[ int(DESCALE(tmp12 - tmp0, - CONST_BITS+PASS1_BITS+3+1)) - and RANGE_MASK]; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - end; -end; - - -{ Perform dequantization and inverse DCT on one block of coefficients, - producing a reduced-size 2x2 output block. } - -{GLOBAL} -procedure jpeg_idct_2x2 (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -type - PWorkspace = ^TWorkspace; - TWorkspace = array[0..(DCTSIZE*2)-1] of int; { buffers data between passes } -var - tmp0, tmp10, z1 : INT32; - inptr : JCOEFPTR; - quantptr : ISLOW_MULT_TYPE_FIELD_PTR; - wsptr : PWorkspace; - outptr : JSAMPROW; - range_limit : JSAMPROW; - ctr : int; - workspace : TWorkspace; { buffers data between passes } - {SHIFT_TEMPS} -var - dcval : int; -var - dcval_ : JSAMPLE; -begin -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE])); - { Pass 1: process columns from input, store into work array. } - - inptr := coef_block; - quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - wsptr := @workspace; - for ctr := DCTSIZE downto 1 do - begin - { Don't bother to process columns 2,4,6 } - if (ctr = DCTSIZE-2) or (ctr = DCTSIZE-4) or (ctr = DCTSIZE-6) then - begin - Inc(JCOEF_PTR(inptr)); - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - - continue; - end; - if (inptr^[DCTSIZE*1]=0) and (inptr^[DCTSIZE*3]=0) and - (inptr^[DCTSIZE*5]=0) and (inptr^[DCTSIZE*7]=0) then - begin - { AC terms all zero; we need not examine terms 2,4,6 for 2x2 output } - dcval := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * - quantptr^[DCTSIZE*0]) shl PASS1_BITS; - - wsptr^[DCTSIZE*0] := dcval; - wsptr^[DCTSIZE*1] := dcval; - - Inc(JCOEF_PTR(inptr)); - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - - continue; - end; - - { Even part } - - z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*0]) * quantptr^[DCTSIZE*0]); - - tmp10 := z1 shl (CONST_BITS+2); - - { Odd part } - - z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*7]) * quantptr^[DCTSIZE*7]); - tmp0 := MULTIPLY(z1, - FIX_0_720959822); { sqrt(2) * (c7-c5+c3-c1) } - z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*5]) * quantptr^[DCTSIZE*5]); - Inc(tmp0, MULTIPLY(z1, FIX_0_850430095)); { sqrt(2) * (-c1+c3+c5+c7) } - z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*3]) * quantptr^[DCTSIZE*3]); - Inc(tmp0, MULTIPLY(z1, - FIX_1_272758580)); { sqrt(2) * (-c1+c3-c5-c7) } - z1 := (ISLOW_MULT_TYPE(inptr^[DCTSIZE*1]) * quantptr^[DCTSIZE*1]); - Inc(tmp0, MULTIPLY(z1, FIX_3_624509785)); { sqrt(2) * (c1+c3+c5+c7) } - - { Final output stage } - - wsptr^[DCTSIZE*0] := int (DESCALE(tmp10 + tmp0, CONST_BITS-PASS1_BITS+2)); - wsptr^[DCTSIZE*1] := int (DESCALE(tmp10 - tmp0, CONST_BITS-PASS1_BITS+2)); - - Inc(JCOEF_PTR(inptr)); - Inc(ISLOW_MULT_TYPE_PTR(quantptr)); - Inc(int_ptr(wsptr)); - end; - - { Pass 2: process 2 rows from work array, store into output array. } - - wsptr := @workspace; - for ctr := 0 to pred(2) do - begin - outptr := JSAMPROW(@ output_buf^[ctr]^[output_col]); - { It's not clear whether a zero row test is worthwhile here ... } - -{$ifndef NO_ZERO_ROW_TEST} - if (wsptr^[1]=0) and (wsptr^[3]=0) and (wsptr^[5]=0) and (wsptr^[7]= 0) then - begin - { AC terms all zero } - dcval_ := range_limit^[ int(DESCALE(INT32(wsptr^[0]), PASS1_BITS+3)) - and RANGE_MASK]; - - outptr^[0] := dcval_; - outptr^[1] := dcval_; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - continue; - end; -{$endif} - - { Even part } - - tmp10 := (INT32 (wsptr^[0])) shl (CONST_BITS+2); - - { Odd part } - - tmp0 := MULTIPLY( INT32(wsptr^[7]), - FIX_0_720959822) { sqrt(2) * (c7-c5+c3-c1) } - + MULTIPLY( INT32(wsptr^[5]), FIX_0_850430095) { sqrt(2) * (-c1+c3+c5+c7) } - + MULTIPLY( INT32(wsptr^[3]), - FIX_1_272758580) { sqrt(2) * (-c1+c3-c5-c7) } - + MULTIPLY( INT32(wsptr^[1]), FIX_3_624509785); { sqrt(2) * (c1+c3+c5+c7) } - - { Final output stage } - - outptr^[0] := range_limit^[ int(DESCALE(tmp10 + tmp0, - CONST_BITS+PASS1_BITS+3+2)) - and RANGE_MASK]; - outptr^[1] := range_limit^[ int(DESCALE(tmp10 - tmp0, - CONST_BITS+PASS1_BITS+3+2)) - and RANGE_MASK]; - - Inc(int_ptr(wsptr), DCTSIZE); { advance pointer to next row } - end; -end; - - -{ Perform dequantization and inverse DCT on one block of coefficients, - producing a reduced-size 1x1 output block. } - -{GLOBAL} -procedure jpeg_idct_1x1 (cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; - output_col : JDIMENSION); -var - dcval : int; - quantptr : ISLOW_MULT_TYPE_FIELD_PTR; - range_limit : JSAMPROW; - {SHIFT_TEMPS} -begin -{ Each IDCT routine is responsible for range-limiting its results and - converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could - be quite far out of range if the input data is corrupt, so a bulletproof - range-limiting step is required. We use a mask-and-table-lookup method - to do the combined operations quickly. See the comments with - prepare_range_limit_table (in jdmaster.c) for more info. } - - range_limit := JSAMPROW(@(cinfo^.sample_range_limit^[CENTERJSAMPLE])); - { Pass 1: process columns from input, store into work array. } - - { We hardly need an inverse DCT routine for this: just take the - average pixel value, which is one-eighth of the DC coefficient. } - - quantptr := ISLOW_MULT_TYPE_FIELD_PTR (compptr^.dct_table); - dcval := (ISLOW_MULT_TYPE(coef_block^[0]) * quantptr^[0]); - dcval := int (DESCALE( INT32(dcval), 3)); - - output_buf^[0]^[output_col] := range_limit^[dcval and RANGE_MASK]; -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjinclude.pas b/3rd/Imaging/Source/JpegLib/imjinclude.pas deleted file mode 100644 index dcaa684ba..000000000 --- a/3rd/Imaging/Source/JpegLib/imjinclude.pas +++ /dev/null @@ -1,126 +0,0 @@ -unit imjinclude; - -{ This file exists to provide a single place to fix any problems with - including the wrong system include files. (Common problems are taken - care of by the standard jconfig symbols, but on really weird systems - you may have to edit this file.) - - NOTE: this file is NOT intended to be included by applications using the - JPEG library. Most applications need only include jpeglib.h. } - -{ Original: jinclude.h Copyright (C) 1991-1994, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -{ Include auto-config file to find out which system include files we need. } - -uses -{$ifdef Delphi_Stream} - classes, -{$endif} - imjmorecfg; - -{ Nomssi: - To write a dest/source manager that handle streams rather than files, - you can edit the FILEptr definition and the JFREAD() and JFWRITE() - functions in this unit, you don't need to change the default managers - JDATASRC and JDATADST. } - -{$ifdef Delphi_Stream} -type - FILEptr = ^TStream; -{$else} - {$ifdef Delphi_Jpeg} - type - FILEptr = TCustomMemoryStream; - {$else} - type - FILEptr = ^File; - {$endif} -{$endif} - -{ We need the NULL macro and size_t typedef. - On an ANSI-conforming system it is sufficient to include <stddef.h>. - Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to - pull in <sys/types.h> as well. - Note that the core JPEG library does not require <stdio.h>; - only the default error handler and data source/destination modules do. - But we must pull it in because of the references to FILE in jpeglib.h. - You can remove those references if you want to compile without <stdio.h>.} - - - -{ We need memory copying and zeroing functions, plus strncpy(). - ANSI and System V implementations declare these in <string.h>. - BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). - Some systems may declare memset and memcpy in <memory.h>. - - NOTE: we assume the size parameters to these functions are of type size_t. - Change the casts in these macros if not! } - -procedure MEMZERO(target : pointer; size : size_t); - -procedure MEMCOPY(dest, src : pointer; size : size_t); - -{function SIZEOF(object) : size_t;} - -function JFREAD(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t; - -function JFWRITE(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t; - -implementation - -procedure MEMZERO(target : pointer; size : size_t); -begin - FillChar(target^, size, 0); -end; - -procedure MEMCOPY(dest, src : pointer; size : size_t); -begin - Move(src^, dest^, size); -end; - -{ In ANSI C, and indeed any rational implementation, size_t is also the - type returned by sizeof(). However, it seems there are some irrational - implementations out there, in which sizeof() returns an int even though - size_t is defined as long or unsigned long. To ensure consistent results - we always use this SIZEOF() macro in place of using sizeof() directly. } - - -{#define - SIZEOF(object) (size_t(sizeof(object))} - - -{ The modules that use fread() and fwrite() always invoke them through - these macros. On some systems you may need to twiddle the argument casts. - CAUTION: argument order is different from underlying functions! } - - -function JFREAD(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t; -var - count : uint; -begin - {$ifdef Delphi_Stream} - count := fp^.Read(buf^, sizeofbuf); - {$else} - blockread(fp^, buf^, sizeofbuf, count); - {$endif} - JFREAD := size_t(count); -end; - -function JFWRITE(fp : FILEptr; buf : pointer; sizeofbuf : size_t) : size_t; -var - count : uint; -begin - {$ifdef Delphi_Stream} - count := fp^.Write(buf^, sizeofbuf); - {$else} - blockwrite(fp^, buf^, sizeofbuf, count); - {$endif} - JFWRITE := size_t(count); -end; - - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjmemmgr.pas b/3rd/Imaging/Source/JpegLib/imjmemmgr.pas deleted file mode 100644 index b3122f67a..000000000 --- a/3rd/Imaging/Source/JpegLib/imjmemmgr.pas +++ /dev/null @@ -1,1283 +0,0 @@ -unit imjmemmgr; - -{ This file contains the JPEG system-independent memory management - routines. This code is usable across a wide variety of machines; most - of the system dependencies have been isolated in a separate file. - The major functions provided here are: - * pool-based allocation and freeing of memory; - * policy decisions about how to divide available memory among the - virtual arrays; - * control logic for swapping virtual arrays between main memory and - backing storage. - The separate system-dependent file provides the actual backing-storage - access code, and it contains the policy decision about how much total - main memory to use. - This file is system-dependent in the sense that some of its functions - are unnecessary in some systems. For example, if there is enough virtual - memory so that backing storage will never be used, much of the virtual - array control logic could be removed. (Of course, if you have that much - memory then you shouldn't care about a little bit of unused code...) } - -{ Original : jmemmgr.c ; Copyright (C) 1991-1997, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjdeferr, - imjerror, - imjpeglib, - imjutils, -{$IFDEF VER70} -{$ifndef NO_GETENV} - Dos, { DOS unit should declare getenv() } - { function GetEnv(name : string) : string; } -{$endif} - imjmemdos; { import the system-dependent declarations } -{$ELSE} - imjmemnobs; - {$DEFINE NO_GETENV} -{$ENDIF} - -{ Memory manager initialization. - When this is called, only the error manager pointer is valid in cinfo! } - -{GLOBAL} -procedure jinit_memory_mgr (cinfo : j_common_ptr); - -implementation - - -{ Some important notes: - The allocation routines provided here must never return NIL. - They should exit to error_exit if unsuccessful. - - It's not a good idea to try to merge the sarray and barray routines, - even though they are textually almost the same, because samples are - usually stored as bytes while coefficients are shorts or ints. Thus, - in machines where byte pointers have a different representation from - word pointers, the resulting machine code could not be the same. } - - -{ Many machines require storage alignment: longs must start on 4-byte - boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() - always returns pointers that are multiples of the worst-case alignment - requirement, and we had better do so too. - There isn't any really portable way to determine the worst-case alignment - requirement. This module assumes that the alignment requirement is - multiples of sizeof(ALIGN_TYPE). - By default, we define ALIGN_TYPE as double. This is necessary on some - workstations (where doubles really do need 8-byte alignment) and will work - fine on nearly everything. If your machine has lesser alignment needs, - you can save a few bytes by making ALIGN_TYPE smaller. - The only place I know of where this will NOT work is certain Macintosh - 680x0 compilers that define double as a 10-byte IEEE extended float. - Doing 10-byte alignment is counterproductive because longwords won't be - aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have - such a compiler. } - -{$ifndef ALIGN_TYPE} { so can override from jconfig.h } -type - ALIGN_TYPE = double; -{$endif} - - -{ We allocate objects from "pools", where each pool is gotten with a single - request to jpeg_get_small() or jpeg_get_large(). There is no per-object - overhead within a pool, except for alignment padding. Each pool has a - header with a link to the next pool of the same class. - Small and large pool headers are identical except that the latter's - link pointer must be FAR on 80x86 machines. - Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE - field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple - of the alignment requirement of ALIGN_TYPE. } - -type - small_pool_ptr = ^small_pool_hdr; - small_pool_hdr = record - case byte of - 0:(hdr : record - next : small_pool_ptr; { next in list of pools } - bytes_used : size_t; { how many bytes already used within pool } - bytes_left : size_t; { bytes still available in this pool } - end); - 1:(dummy : ALIGN_TYPE); { included in union to ensure alignment } - end; {small_pool_hdr;} - -type - large_pool_ptr = ^large_pool_hdr; {FAR} - large_pool_hdr = record - case byte of - 0:(hdr : record - next : large_pool_ptr; { next in list of pools } - bytes_used : size_t; { how many bytes already used within pool } - bytes_left : size_t; { bytes still available in this pool } - end); - 1:(dummy : ALIGN_TYPE); { included in union to ensure alignment } - end; {large_pool_hdr;} - - -{ Here is the full definition of a memory manager object. } - -type - my_mem_ptr = ^my_memory_mgr; - my_memory_mgr = record - pub : jpeg_memory_mgr; { public fields } - - { Each pool identifier (lifetime class) names a linked list of pools. } - small_list : array[0..JPOOL_NUMPOOLS-1] of small_pool_ptr ; - large_list : array[0..JPOOL_NUMPOOLS-1] of large_pool_ptr ; - - { Since we only have one lifetime class of virtual arrays, only one - linked list is necessary (for each datatype). Note that the virtual - array control blocks being linked together are actually stored somewhere - in the small-pool list. } - - virt_sarray_list : jvirt_sarray_ptr; - virt_barray_list : jvirt_barray_ptr; - - { This counts total space obtained from jpeg_get_small/large } - total_space_allocated : long; - - { alloc_sarray and alloc_barray set this value for use by virtual - array routines. } - - last_rowsperchunk : JDIMENSION; { from most recent alloc_sarray/barray } - end; {my_memory_mgr;} - - {$ifndef AM_MEMORY_MANAGER} { only jmemmgr.c defines these } - -{ The control blocks for virtual arrays. - Note that these blocks are allocated in the "small" pool area. - System-dependent info for the associated backing store (if any) is hidden - inside the backing_store_info struct. } -type - jvirt_sarray_control = record - mem_buffer : JSAMPARRAY; { => the in-memory buffer } - rows_in_array : JDIMENSION; { total virtual array height } - samplesperrow : JDIMENSION; { width of array (and of memory buffer) } - maxaccess : JDIMENSION; { max rows accessed by access_virt_sarray } - rows_in_mem : JDIMENSION; { height of memory buffer } - rowsperchunk : JDIMENSION; { allocation chunk size in mem_buffer } - cur_start_row : JDIMENSION; { first logical row # in the buffer } - first_undef_row : JDIMENSION; { row # of first uninitialized row } - pre_zero : boolean; { pre-zero mode requested? } - dirty : boolean; { do current buffer contents need written? } - b_s_open : boolean; { is backing-store data valid? } - next : jvirt_sarray_ptr; { link to next virtual sarray control block } - b_s_info : backing_store_info; { System-dependent control info } - end; - - jvirt_barray_control = record - mem_buffer : JBLOCKARRAY; { => the in-memory buffer } - rows_in_array : JDIMENSION; { total virtual array height } - blocksperrow : JDIMENSION; { width of array (and of memory buffer) } - maxaccess : JDIMENSION; { max rows accessed by access_virt_barray } - rows_in_mem : JDIMENSION; { height of memory buffer } - rowsperchunk : JDIMENSION; { allocation chunk size in mem_buffer } - cur_start_row : JDIMENSION; { first logical row # in the buffer } - first_undef_row : JDIMENSION; { row # of first uninitialized row } - pre_zero : boolean; { pre-zero mode requested? } - dirty : boolean; { do current buffer contents need written? } - b_s_open : boolean; { is backing-store data valid? } - next : jvirt_barray_ptr; { link to next virtual barray control block } - b_s_info : backing_store_info; { System-dependent control info } - end; - {$endif} { AM_MEMORY_MANAGER} - -{$ifdef MEM_STATS} { optional extra stuff for statistics } - -{LOCAL} -procedure print_mem_stats (cinfo : j_common_ptr; pool_id : int); -var - mem : my_mem_ptr; - shdr_ptr : small_pool_ptr; - lhdr_ptr : large_pool_ptr; -begin - mem := my_mem_ptr (cinfo^.mem); - - { Since this is only a debugging stub, we can cheat a little by using - fprintf directly rather than going through the trace message code. - This is helpful because message parm array can't handle longs. } - - WriteLn(output, 'Freeing pool ', pool_id,', total space := ', - mem^.total_space_allocated); - - lhdr_ptr := mem^.large_list[pool_id]; - while (lhdr_ptr <> NIL) do - begin - WriteLn(output, ' Large chunk used ', - long (lhdr_ptr^.hdr.bytes_used)); - lhdr_ptr := lhdr_ptr^.hdr.next; - end; - - shdr_ptr := mem^.small_list[pool_id]; - - while (shdr_ptr <> NIL) do - begin - WriteLn(output, ' Small chunk used ', - long (shdr_ptr^.hdr.bytes_used), ' free ', - long (shdr_ptr^.hdr.bytes_left) ); - shdr_ptr := shdr_ptr^.hdr.next; - end; -end; - -{$endif} { MEM_STATS } - - -{LOCAL} -procedure out_of_memory (cinfo : j_common_ptr; which : int); -{ Report an out-of-memory error and stop execution } -{ If we compiled MEM_STATS support, report alloc requests before dying } -begin -{$ifdef MEM_STATS} - cinfo^.err^.trace_level := 2; { force self_destruct to report stats } -{$endif} - ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); -end; - - -{ Allocation of "small" objects. - - For these, we use pooled storage. When a new pool must be created, - we try to get enough space for the current request plus a "slop" factor, - where the slop will be the amount of leftover space in the new pool. - The speed vs. space tradeoff is largely determined by the slop values. - A different slop value is provided for each pool class (lifetime), - and we also distinguish the first pool of a class from later ones. - NOTE: the values given work fairly well on both 16- and 32-bit-int - machines, but may be too small if longs are 64 bits or more. } - -const - first_pool_slop : array[0..JPOOL_NUMPOOLS-1] of size_t = - (1600, { first PERMANENT pool } - 16000); { first IMAGE pool } - -const - extra_pool_slop : array[0..JPOOL_NUMPOOLS-1] of size_t = - (0, { additional PERMANENT pools } - 5000); { additional IMAGE pools } - -const - MIN_SLOP = 50; { greater than 0 to avoid futile looping } - - -{METHODDEF} -function alloc_small (cinfo : j_common_ptr; - pool_id : int; - sizeofobject : size_t) : pointer; -type - byteptr = ^byte; -{ Allocate a "small" object } -var - mem : my_mem_ptr; - hdr_ptr, prev_hdr_ptr : small_pool_ptr; - data_ptr : byteptr; - odd_bytes, min_request, slop : size_t; -begin - mem := my_mem_ptr (cinfo^.mem); - - { Check for unsatisfiable request (do now to ensure no overflow below) } - if (sizeofobject > size_t(MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) then - out_of_memory(cinfo, 1); { request exceeds malloc's ability } - - { Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) } - odd_bytes := sizeofobject mod SIZEOF(ALIGN_TYPE); - if (odd_bytes > 0) then - Inc(sizeofobject, SIZEOF(ALIGN_TYPE) - odd_bytes); - - { See if space is available in any existing pool } - if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then - ERREXIT1(j_common_ptr(cinfo), JERR_BAD_POOL_ID, pool_id); { safety check } - prev_hdr_ptr := NIL; - hdr_ptr := mem^.small_list[pool_id]; - while (hdr_ptr <> NIL) do - begin - if (hdr_ptr^.hdr.bytes_left >= sizeofobject) then - break; { found pool with enough space } - prev_hdr_ptr := hdr_ptr; - hdr_ptr := hdr_ptr^.hdr.next; - end; - - { Time to make a new pool? } - if (hdr_ptr = NIL) then - begin - { min_request is what we need now, slop is what will be leftover } - min_request := sizeofobject + SIZEOF(small_pool_hdr); - if (prev_hdr_ptr = NIL) then { first pool in class? } - slop := first_pool_slop[pool_id] - else - slop := extra_pool_slop[pool_id]; - { Don't ask for more than MAX_ALLOC_CHUNK } - if (slop > size_t (MAX_ALLOC_CHUNK-min_request)) then - slop := size_t (MAX_ALLOC_CHUNK-min_request); - { Try to get space, if fail reduce slop and try again } - while TRUE do - begin - hdr_ptr := small_pool_ptr(jpeg_get_small(cinfo, min_request + slop)); - if (hdr_ptr <> NIL) then - break; - slop := slop div 2; - if (slop < MIN_SLOP) then { give up when it gets real small } - out_of_memory(cinfo, 2); { jpeg_get_small failed } - end; - Inc(mem^.total_space_allocated, min_request + slop); - { Success, initialize the new pool header and add to end of list } - hdr_ptr^.hdr.next := NIL; - hdr_ptr^.hdr.bytes_used := 0; - hdr_ptr^.hdr.bytes_left := sizeofobject + slop; - if (prev_hdr_ptr = NIL) then { first pool in class? } - mem^.small_list[pool_id] := hdr_ptr - else - prev_hdr_ptr^.hdr.next := hdr_ptr; - end; - - { OK, allocate the object from the current pool } - data_ptr := byteptr (hdr_ptr); - Inc(small_pool_ptr(data_ptr)); { point to first data byte in pool } - Inc(data_ptr, hdr_ptr^.hdr.bytes_used); { point to place for object } - Inc(hdr_ptr^.hdr.bytes_used, sizeofobject); - Dec(hdr_ptr^.hdr.bytes_left, sizeofobject); - - alloc_small := pointer(data_ptr); -end; - - -{ Allocation of "large" objects. - - The external semantics of these are the same as "small" objects, - except that FAR pointers are used on 80x86. However the pool - management heuristics are quite different. We assume that each - request is large enough that it may as well be passed directly to - jpeg_get_large; the pool management just links everything together - so that we can free it all on demand. - Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY - structures. The routines that create these structures (see below) - deliberately bunch rows together to ensure a large request size. } - -{METHODDEF} -function alloc_large (cinfo : j_common_ptr; - pool_id : int; - sizeofobject : size_t) : pointer; -{ Allocate a "large" object } -var - mem : my_mem_ptr; - hdr_ptr : large_pool_ptr; - odd_bytes : size_t; -var - dest_ptr : large_pool_ptr; -begin - mem := my_mem_ptr (cinfo^.mem); - - { Check for unsatisfiable request (do now to ensure no overflow below) } - if (sizeofobject > size_t (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) then - out_of_memory(cinfo, 3); { request exceeds malloc's ability } - - { Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) } - odd_bytes := sizeofobject mod SIZEOF(ALIGN_TYPE); - if (odd_bytes > 0) then - Inc(sizeofobject, SIZEOF(ALIGN_TYPE) - odd_bytes); - - { Always make a new pool } - if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check } - - hdr_ptr := large_pool_ptr (jpeg_get_large(cinfo, sizeofobject + - SIZEOF(large_pool_hdr))); - if (hdr_ptr = NIL) then - out_of_memory(cinfo, 4); { jpeg_get_large failed } - Inc(mem^.total_space_allocated, sizeofobject + SIZEOF(large_pool_hdr)); - - { Success, initialize the new pool header and add to list } - hdr_ptr^.hdr.next := mem^.large_list[pool_id]; - { We maintain space counts in each pool header for statistical purposes, - even though they are not needed for allocation. } - - hdr_ptr^.hdr.bytes_used := sizeofobject; - hdr_ptr^.hdr.bytes_left := 0; - mem^.large_list[pool_id] := hdr_ptr; - - {alloc_large := pointerFAR (hdr_ptr + 1); - point to first data byte in pool } - dest_ptr := hdr_ptr; - Inc(large_pool_ptr(dest_ptr)); - alloc_large := dest_ptr; -end; - - -{ Creation of 2-D sample arrays. - The pointers are in near heap, the samples themselves in FAR heap. - - To minimize allocation overhead and to allow I/O of large contiguous - blocks, we allocate the sample rows in groups of as many rows as possible - without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. - NB: the virtual array control routines, later in this file, know about - this chunking of rows. The rowsperchunk value is left in the mem manager - object so that it can be saved away if this sarray is the workspace for - a virtual array. } - -{METHODDEF} -function alloc_sarray (cinfo : j_common_ptr; - pool_id : int; - samplesperrow : JDIMENSION; - numrows : JDIMENSION) : JSAMPARRAY; -{ Allocate a 2-D sample array } -var - mem : my_mem_ptr; - the_result : JSAMPARRAY; - workspace : JSAMPROW; - rowsperchunk, currow, i : JDIMENSION; - ltemp : long; -begin - mem := my_mem_ptr(cinfo^.mem); - - { Calculate max # of rows allowed in one allocation chunk } - ltemp := (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) div - (long(samplesperrow) * SIZEOF(JSAMPLE)); - if (ltemp <= 0) then - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - if (ltemp < long(numrows)) then - rowsperchunk := JDIMENSION (ltemp) - else - rowsperchunk := numrows; - mem^.last_rowsperchunk := rowsperchunk; - - { Get space for row pointers (small object) } - the_result := JSAMPARRAY (alloc_small(cinfo, pool_id, - size_t (numrows * SIZEOF(JSAMPROW)))); - - { Get the rows themselves (large objects) } - currow := 0; - while (currow < numrows) do - begin - {rowsperchunk := MIN(rowsperchunk, numrows - currow);} - if rowsperchunk > numrows - currow then - rowsperchunk := numrows - currow; - - workspace := JSAMPROW (alloc_large(cinfo, pool_id, - size_t (size_t(rowsperchunk) * size_t(samplesperrow) - * SIZEOF(JSAMPLE))) ); - for i := pred(rowsperchunk) downto 0 do - begin - the_result^[currow] := workspace; - Inc(currow); - Inc(JSAMPLE_PTR(workspace), samplesperrow); - end; - end; - - alloc_sarray := the_result; -end; - - -{ Creation of 2-D coefficient-block arrays. - This is essentially the same as the code for sample arrays, above. } - -{METHODDEF} -function alloc_barray (cinfo : j_common_ptr; - pool_id : int; - blocksperrow : JDIMENSION; - numrows : JDIMENSION) : JBLOCKARRAY; -{ Allocate a 2-D coefficient-block array } -var - mem : my_mem_ptr; - the_result : JBLOCKARRAY; - workspace : JBLOCKROW; - rowsperchunk, currow, i : JDIMENSION; - ltemp : long; -begin - mem := my_mem_ptr(cinfo^.mem); - - { Calculate max # of rows allowed in one allocation chunk } - ltemp := (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) div - (long(blocksperrow) * SIZEOF(JBLOCK)); - - if (ltemp <= 0) then - ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); - if (ltemp < long(numrows)) then - rowsperchunk := JDIMENSION (ltemp) - else - rowsperchunk := numrows; - mem^.last_rowsperchunk := rowsperchunk; - - { Get space for row pointers (small object) } - the_result := JBLOCKARRAY (alloc_small(cinfo, pool_id, - size_t (numrows * SIZEOF(JBLOCKROW))) ); - - { Get the rows themselves (large objects) } - currow := 0; - while (currow < numrows) do - begin - {rowsperchunk := MIN(rowsperchunk, numrows - currow);} - if rowsperchunk > numrows - currow then - rowsperchunk := numrows - currow; - - workspace := JBLOCKROW (alloc_large(cinfo, pool_id, - size_t (size_t(rowsperchunk) * size_t(blocksperrow) - * SIZEOF(JBLOCK))) ); - for i := rowsperchunk downto 1 do - begin - the_result^[currow] := workspace; - Inc(currow); - Inc(JBLOCK_PTR(workspace), blocksperrow); - end; - end; - - alloc_barray := the_result; -end; - - -{ About virtual array management: - - The above "normal" array routines are only used to allocate strip buffers - (as wide as the image, but just a few rows high). Full-image-sized buffers - are handled as "virtual" arrays. The array is still accessed a strip at a - time, but the memory manager must save the whole array for repeated - accesses. The intended implementation is that there is a strip buffer in - memory (as high as is possible given the desired memory limit), plus a - backing file that holds the rest of the array. - - The request_virt_array routines are told the total size of the image and - the maximum number of rows that will be accessed at once. The in-memory - buffer must be at least as large as the maxaccess value. - - The request routines create control blocks but not the in-memory buffers. - That is postponed until realize_virt_arrays is called. At that time the - total amount of space needed is known (approximately, anyway), so free - memory can be divided up fairly. - - The access_virt_array routines are responsible for making a specific strip - area accessible (after reading or writing the backing file, if necessary). - Note that the access routines are told whether the caller intends to modify - the accessed strip; during a read-only pass this saves having to rewrite - data to disk. The access routines are also responsible for pre-zeroing - any newly accessed rows, if pre-zeroing was requested. - - In current usage, the access requests are usually for nonoverlapping - strips; that is, successive access start_row numbers differ by exactly - num_rows := maxaccess. This means we can get good performance with simple - buffer dump/reload logic, by making the in-memory buffer be a multiple - of the access height; then there will never be accesses across bufferload - boundaries. The code will still work with overlapping access requests, - but it doesn't handle bufferload overlaps very efficiently. } - - -{METHODDEF} -function request_virt_sarray (cinfo : j_common_ptr; - pool_id : int; - pre_zero : boolean; - samplesperrow : JDIMENSION; - numrows : JDIMENSION; - maxaccess : JDIMENSION) : jvirt_sarray_ptr; -{ Request a virtual 2-D sample array } -var - mem : my_mem_ptr; - the_result : jvirt_sarray_ptr; -begin - mem := my_mem_ptr (cinfo^.mem); - - { Only IMAGE-lifetime virtual arrays are currently supported } - if (pool_id <> JPOOL_IMAGE) then - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check } - - { get control block } - the_result := jvirt_sarray_ptr (alloc_small(cinfo, pool_id, - SIZEOF(jvirt_sarray_control)) ); - - the_result^.mem_buffer := NIL; { marks array not yet realized } - the_result^.rows_in_array := numrows; - the_result^.samplesperrow := samplesperrow; - the_result^.maxaccess := maxaccess; - the_result^.pre_zero := pre_zero; - the_result^.b_s_open := FALSE; { no associated backing-store object } - the_result^.next := mem^.virt_sarray_list; { add to list of virtual arrays } - mem^.virt_sarray_list := the_result; - - request_virt_sarray := the_result; -end; - - -{METHODDEF} -function request_virt_barray (cinfo : j_common_ptr; - pool_id : int; - pre_zero : boolean; - blocksperrow : JDIMENSION; - numrows : JDIMENSION; - maxaccess : JDIMENSION) : jvirt_barray_ptr; -{ Request a virtual 2-D coefficient-block array } -var - mem : my_mem_ptr; - the_result : jvirt_barray_ptr; -begin - mem := my_mem_ptr(cinfo^.mem); - - { Only IMAGE-lifetime virtual arrays are currently supported } - if (pool_id <> JPOOL_IMAGE) then - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check } - - { get control block } - the_result := jvirt_barray_ptr(alloc_small(cinfo, pool_id, - SIZEOF(jvirt_barray_control)) ); - - the_result^.mem_buffer := NIL; { marks array not yet realized } - the_result^.rows_in_array := numrows; - the_result^.blocksperrow := blocksperrow; - the_result^.maxaccess := maxaccess; - the_result^.pre_zero := pre_zero; - the_result^.b_s_open := FALSE; { no associated backing-store object } - the_result^.next := mem^.virt_barray_list; { add to list of virtual arrays } - mem^.virt_barray_list := the_result; - - request_virt_barray := the_result; -end; - - -{METHODDEF} -procedure realize_virt_arrays (cinfo : j_common_ptr); -{ Allocate the in-memory buffers for any unrealized virtual arrays } -var - mem : my_mem_ptr; - space_per_minheight, maximum_space, avail_mem : long; - minheights, max_minheights : long; - sptr : jvirt_sarray_ptr; - bptr : jvirt_barray_ptr; -begin - mem := my_mem_ptr (cinfo^.mem); - { Compute the minimum space needed (maxaccess rows in each buffer) - and the maximum space needed (full image height in each buffer). - These may be of use to the system-dependent jpeg_mem_available routine. } - - space_per_minheight := 0; - maximum_space := 0; - sptr := mem^.virt_sarray_list; - while (sptr <> NIL) do - begin - if (sptr^.mem_buffer = NIL) then - begin { if not realized yet } - Inc(space_per_minheight, long(sptr^.maxaccess) * - long(sptr^.samplesperrow) * SIZEOF(JSAMPLE)); - Inc(maximum_space, long(sptr^.rows_in_array) * - long(sptr^.samplesperrow) * SIZEOF(JSAMPLE)); - end; - sptr := sptr^.next; - end; - bptr := mem^.virt_barray_list; - while (bptr <> NIL) do - begin - if (bptr^.mem_buffer = NIL) then - begin { if not realized yet } - Inc(space_per_minheight, long(bptr^.maxaccess) * - long(bptr^.blocksperrow) * SIZEOF(JBLOCK)); - Inc(maximum_space, long(bptr^.rows_in_array) * - long(bptr^.blocksperrow) * SIZEOF(JBLOCK)); - end; - bptr := bptr^.next; - end; - - if (space_per_minheight <= 0) then - exit; { no unrealized arrays, no work } - - { Determine amount of memory to actually use; this is system-dependent. } - avail_mem := jpeg_mem_available(cinfo, space_per_minheight, maximum_space, - mem^.total_space_allocated); - - { If the maximum space needed is available, make all the buffers full - height; otherwise parcel it out with the same number of minheights - in each buffer. } - - if (avail_mem >= maximum_space) then - max_minheights := long(1000000000) - else - begin - max_minheights := avail_mem div space_per_minheight; - { If there doesn't seem to be enough space, try to get the minimum - anyway. This allows a "stub" implementation of jpeg_mem_available(). } - if (max_minheights <= 0) then - max_minheights := 1; - end; - - { Allocate the in-memory buffers and initialize backing store as needed. } - - sptr := mem^.virt_sarray_list; - while (sptr <> NIL) do - begin - if (sptr^.mem_buffer = NIL) then - begin { if not realized yet } - minheights := (long(sptr^.rows_in_array) - long(1)) div LongInt(sptr^.maxaccess) + long(1); - if (minheights <= max_minheights) then - begin - { This buffer fits in memory } - sptr^.rows_in_mem := sptr^.rows_in_array; - end - else - begin - { It doesn't fit in memory, create backing store. } - sptr^.rows_in_mem := JDIMENSION(max_minheights) * sptr^.maxaccess; - jpeg_open_backing_store(cinfo, - @sptr^.b_s_info, - long(sptr^.rows_in_array) * - long(sptr^.samplesperrow) * - long(SIZEOF(JSAMPLE))); - sptr^.b_s_open := TRUE; - end; - sptr^.mem_buffer := alloc_sarray(cinfo, JPOOL_IMAGE, - sptr^.samplesperrow, sptr^.rows_in_mem); - sptr^.rowsperchunk := mem^.last_rowsperchunk; - sptr^.cur_start_row := 0; - sptr^.first_undef_row := 0; - sptr^.dirty := FALSE; - end; - sptr := sptr^.next; - end; - - bptr := mem^.virt_barray_list; - while (bptr <> NIL) do - begin - if (bptr^.mem_buffer = NIL) then - begin { if not realized yet } - minheights := (long(bptr^.rows_in_array) - long(1)) div LongInt(bptr^.maxaccess) + long(1); - if (minheights <= max_minheights) then - begin - { This buffer fits in memory } - bptr^.rows_in_mem := bptr^.rows_in_array; - end - else - begin - { It doesn't fit in memory, create backing store. } - bptr^.rows_in_mem := JDIMENSION (max_minheights) * bptr^.maxaccess; - jpeg_open_backing_store(cinfo, - @bptr^.b_s_info, - long(bptr^.rows_in_array) * - long(bptr^.blocksperrow) * - long(SIZEOF(JBLOCK))); - bptr^.b_s_open := TRUE; - end; - bptr^.mem_buffer := alloc_barray(cinfo, JPOOL_IMAGE, - bptr^.blocksperrow, bptr^.rows_in_mem); - bptr^.rowsperchunk := mem^.last_rowsperchunk; - bptr^.cur_start_row := 0; - bptr^.first_undef_row := 0; - bptr^.dirty := FALSE; - end; - bptr := bptr^.next; - end; -end; - - -{LOCAL} -procedure do_sarray_io (cinfo : j_common_ptr; - ptr : jvirt_sarray_ptr; - writing : boolean); -{ Do backing store read or write of a virtual sample array } -var - bytesperrow, file_offset, byte_count, rows, thisrow, i : long; -begin - - bytesperrow := long(ptr^.samplesperrow * SIZEOF(JSAMPLE)); - file_offset := LongInt(ptr^.cur_start_row) * bytesperrow; - { Loop to read or write each allocation chunk in mem_buffer } - i := 0; - while i < long(ptr^.rows_in_mem) do - begin - - { One chunk, but check for short chunk at end of buffer } - {rows := MIN(long(ptr^.rowsperchunk), long(ptr^.rows_in_mem - i));} - rows := long(ptr^.rowsperchunk); - if rows > long(ptr^.rows_in_mem) - i then - rows := long(ptr^.rows_in_mem) - i; - { Transfer no more than is currently defined } - thisrow := long (ptr^.cur_start_row) + i; - {rows := MIN(rows, long(ptr^.first_undef_row) - thisrow);} - if (rows > long(ptr^.first_undef_row) - thisrow) then - rows := long(ptr^.first_undef_row) - thisrow; - { Transfer no more than fits in file } - {rows := MIN(rows, long(ptr^.rows_in_array) - thisrow);} - if (rows > long(ptr^.rows_in_array) - thisrow) then - rows := long(ptr^.rows_in_array) - thisrow; - - if (rows <= 0) then { this chunk might be past end of file! } - break; - byte_count := rows * bytesperrow; - if (writing) then - ptr^.b_s_info.write_backing_store (cinfo, - @ptr^.b_s_info, - pointer {FAR} (ptr^.mem_buffer^[i]), - file_offset, byte_count) - else - ptr^.b_s_info.read_backing_store (cinfo, - @ptr^.b_s_info, - pointer {FAR} (ptr^.mem_buffer^[i]), - file_offset, byte_count); - Inc(file_offset, byte_count); - Inc(i, ptr^.rowsperchunk); - end; -end; - - -{LOCAL} -procedure do_barray_io (cinfo : j_common_ptr; - ptr : jvirt_barray_ptr; - writing : boolean); -{ Do backing store read or write of a virtual coefficient-block array } -var - bytesperrow, file_offset, byte_count, rows, thisrow, i : long; -begin - bytesperrow := long (ptr^.blocksperrow) * SIZEOF(JBLOCK); - file_offset := LongInt(ptr^.cur_start_row) * bytesperrow; - { Loop to read or write each allocation chunk in mem_buffer } - i := 0; - while (i < long(ptr^.rows_in_mem)) do - begin - { One chunk, but check for short chunk at end of buffer } - {rows := MIN(long(ptr^.rowsperchunk), long(ptr^.rows_in_mem - i));} - rows := long(ptr^.rowsperchunk); - if rows > long(ptr^.rows_in_mem) - i then - rows := long(ptr^.rows_in_mem) - i; - { Transfer no more than is currently defined } - thisrow := long (ptr^.cur_start_row) + i; - {rows := MIN(rows, long(ptr^.first_undef_row - thisrow));} - if rows > long(ptr^.first_undef_row) - thisrow then - rows := long(ptr^.first_undef_row) - thisrow; - { Transfer no more than fits in file } - {rows := MIN(rows, long (ptr^.rows_in_array - thisrow));} - if (rows > long (ptr^.rows_in_array) - thisrow) then - rows := long (ptr^.rows_in_array) - thisrow; - - if (rows <= 0) then { this chunk might be past end of file! } - break; - byte_count := rows * bytesperrow; - if (writing) then - ptr^.b_s_info.write_backing_store (cinfo, - @ptr^.b_s_info, - {FAR} pointer(ptr^.mem_buffer^[i]), - file_offset, byte_count) - else - ptr^.b_s_info.read_backing_store (cinfo, - @ptr^.b_s_info, - {FAR} pointer(ptr^.mem_buffer^[i]), - file_offset, byte_count); - Inc(file_offset, byte_count); - Inc(i, ptr^.rowsperchunk); - end; -end; - - -{METHODDEF} -function access_virt_sarray (cinfo : j_common_ptr; - ptr : jvirt_sarray_ptr; - start_row : JDIMENSION; - num_rows : JDIMENSION; - writable : boolean ) : JSAMPARRAY; -{ Access the part of a virtual sample array starting at start_row } -{ and extending for num_rows rows. writable is true if } -{ caller intends to modify the accessed area. } -var - end_row : JDIMENSION; - undef_row : JDIMENSION; -var - bytesperrow : size_t; -var - ltemp : long; -begin - end_row := start_row + num_rows; - { debugging check } - if (end_row > ptr^.rows_in_array) or (num_rows > ptr^.maxaccess) or - (ptr^.mem_buffer = NIL) then - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - - { Make the desired part of the virtual array accessible } - if (start_row < ptr^.cur_start_row) or - (end_row > ptr^.cur_start_row+ptr^.rows_in_mem) then - begin - if (not ptr^.b_s_open) then - ERREXIT(cinfo, JERR_VIRTUAL_BUG); - { Flush old buffer contents if necessary } - if (ptr^.dirty) then - begin - do_sarray_io(cinfo, ptr, TRUE); - ptr^.dirty := FALSE; - end; - { Decide what part of virtual array to access. - Algorithm: if target address > current window, assume forward scan, - load starting at target address. If target address < current window, - assume backward scan, load so that target area is top of window. - Note that when switching from forward write to forward read, will have - start_row := 0, so the limiting case applies and we load from 0 anyway. } - if (start_row > ptr^.cur_start_row) then - begin - ptr^.cur_start_row := start_row; - end - else - begin - { use long arithmetic here to avoid overflow & unsigned problems } - - - ltemp := long(end_row) - long(ptr^.rows_in_mem); - if (ltemp < 0) then - ltemp := 0; { don't fall off front end of file } - ptr^.cur_start_row := JDIMENSION(ltemp); - end; - { Read in the selected part of the array. - During the initial write pass, we will do no actual read - because the selected part is all undefined. } - - do_sarray_io(cinfo, ptr, FALSE); - end; - { Ensure the accessed part of the array is defined; prezero if needed. - To improve locality of access, we only prezero the part of the array - that the caller is about to access, not the entire in-memory array. } - if (ptr^.first_undef_row < end_row) then - begin - if (ptr^.first_undef_row < start_row) then - begin - if (writable) then { writer skipped over a section of array } - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - undef_row := start_row; { but reader is allowed to read ahead } - end - else - begin - undef_row := ptr^.first_undef_row; - end; - if (writable) then - ptr^.first_undef_row := end_row; - if (ptr^.pre_zero) then - begin - bytesperrow := size_t(ptr^.samplesperrow) * SIZEOF(JSAMPLE); - Dec(undef_row, ptr^.cur_start_row); { make indexes relative to buffer } - Dec(end_row, ptr^.cur_start_row); - while (undef_row < end_row) do - begin - jzero_far({FAR} pointer(ptr^.mem_buffer^[undef_row]), bytesperrow); - Inc(undef_row); - end; - end - else - begin - if (not writable) then { reader looking at undefined data } - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - end; - end; - { Flag the buffer dirty if caller will write in it } - if (writable) then - ptr^.dirty := TRUE; - { Return address of proper part of the buffer } - access_virt_sarray := JSAMPARRAY(@ ptr^.mem_buffer^[start_row - ptr^.cur_start_row]); -end; - - -{METHODDEF} -function access_virt_barray (cinfo : j_common_ptr; - ptr : jvirt_barray_ptr; - start_row : JDIMENSION; - num_rows : JDIMENSION; - writable : boolean) : JBLOCKARRAY; -{ Access the part of a virtual block array starting at start_row } -{ and extending for num_rows rows. writable is true if } -{ caller intends to modify the accessed area. } -var - end_row : JDIMENSION; - undef_row : JDIMENSION; - ltemp : long; -var - bytesperrow : size_t; -begin - end_row := start_row + num_rows; - - { debugging check } - if (end_row > ptr^.rows_in_array) or (num_rows > ptr^.maxaccess) or - (ptr^.mem_buffer = NIL) then - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - - { Make the desired part of the virtual array accessible } - if (start_row < ptr^.cur_start_row) or - (end_row > ptr^.cur_start_row+ptr^.rows_in_mem) then - begin - if (not ptr^.b_s_open) then - ERREXIT(cinfo, JERR_VIRTUAL_BUG); - { Flush old buffer contents if necessary } - if (ptr^.dirty) then - begin - do_barray_io(cinfo, ptr, TRUE); - ptr^.dirty := FALSE; - end; - { Decide what part of virtual array to access. - Algorithm: if target address > current window, assume forward scan, - load starting at target address. If target address < current window, - assume backward scan, load so that target area is top of window. - Note that when switching from forward write to forward read, will have - start_row := 0, so the limiting case applies and we load from 0 anyway. } - - if (start_row > ptr^.cur_start_row) then - begin - ptr^.cur_start_row := start_row; - end - else - begin - { use long arithmetic here to avoid overflow & unsigned problems } - - ltemp := long(end_row) - long(ptr^.rows_in_mem); - if (ltemp < 0) then - ltemp := 0; { don't fall off front end of file } - ptr^.cur_start_row := JDIMENSION (ltemp); - end; - { Read in the selected part of the array. - During the initial write pass, we will do no actual read - because the selected part is all undefined. } - - do_barray_io(cinfo, ptr, FALSE); - end; - { Ensure the accessed part of the array is defined; prezero if needed. - To improve locality of access, we only prezero the part of the array - that the caller is about to access, not the entire in-memory array. } - - if (ptr^.first_undef_row < end_row) then - begin - if (ptr^.first_undef_row < start_row) then - begin - if (writable) then { writer skipped over a section of array } - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - undef_row := start_row; { but reader is allowed to read ahead } - end - else - begin - undef_row := ptr^.first_undef_row; - end; - if (writable) then - ptr^.first_undef_row := end_row; - if (ptr^.pre_zero) then - begin - bytesperrow := size_t (ptr^.blocksperrow) * SIZEOF(JBLOCK); - Dec(undef_row, ptr^.cur_start_row); { make indexes relative to buffer } - Dec(end_row, ptr^.cur_start_row); - while (undef_row < end_row) do - begin - jzero_far({FAR}pointer(ptr^.mem_buffer^[undef_row]), bytesperrow); - Inc(undef_row); - end; - end - else - begin - if (not writable) then { reader looking at undefined data } - ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); - end; - end; - { Flag the buffer dirty if caller will write in it } - if (writable) then - ptr^.dirty := TRUE; - { Return address of proper part of the buffer } - access_virt_barray := JBLOCKARRAY(@ ptr^.mem_buffer^[start_row - ptr^.cur_start_row]); -end; - - -{ Release all objects belonging to a specified pool. } - -{METHODDEF} -procedure free_pool (cinfo : j_common_ptr; pool_id : int); -var - mem : my_mem_ptr; - shdr_ptr : small_pool_ptr; - lhdr_ptr : large_pool_ptr; - space_freed : size_t; -var - sptr : jvirt_sarray_ptr; - bptr : jvirt_barray_ptr; -var - next_lhdr_ptr : large_pool_ptr; - next_shdr_ptr : small_pool_ptr; -begin - mem := my_mem_ptr(cinfo^.mem); - - if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then - ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check } - -{$ifdef MEM_STATS} - if (cinfo^.err^.trace_level > 1) then - print_mem_stats(cinfo, pool_id); { print pool's memory usage statistics } -{$endif} - - { If freeing IMAGE pool, close any virtual arrays first } - if (pool_id = JPOOL_IMAGE) then - begin - sptr := mem^.virt_sarray_list; - while (sptr <> NIL) do - begin - if (sptr^.b_s_open) then - begin { there may be no backing store } - sptr^.b_s_open := FALSE; { prevent recursive close if error } - sptr^.b_s_info.close_backing_store (cinfo, @sptr^.b_s_info); - end; - sptr := sptr^.next; - end; - mem^.virt_sarray_list := NIL; - bptr := mem^.virt_barray_list; - while (bptr <> NIL) do - begin - if (bptr^.b_s_open) then - begin { there may be no backing store } - bptr^.b_s_open := FALSE; { prevent recursive close if error } - bptr^.b_s_info.close_backing_store (cinfo, @bptr^.b_s_info); - end; - bptr := bptr^.next; - end; - mem^.virt_barray_list := NIL; - end; - - { Release large objects } - lhdr_ptr := mem^.large_list[pool_id]; - mem^.large_list[pool_id] := NIL; - - while (lhdr_ptr <> NIL) do - begin - next_lhdr_ptr := lhdr_ptr^.hdr.next; - space_freed := lhdr_ptr^.hdr.bytes_used + - lhdr_ptr^.hdr.bytes_left + - SIZEOF(large_pool_hdr); - jpeg_free_large(cinfo, {FAR} pointer(lhdr_ptr), space_freed); - Dec(mem^.total_space_allocated, space_freed); - lhdr_ptr := next_lhdr_ptr; - end; - - { Release small objects } - shdr_ptr := mem^.small_list[pool_id]; - mem^.small_list[pool_id] := NIL; - - while (shdr_ptr <> NIL) do - begin - next_shdr_ptr := shdr_ptr^.hdr.next; - space_freed := shdr_ptr^.hdr.bytes_used + - shdr_ptr^.hdr.bytes_left + - SIZEOF(small_pool_hdr); - jpeg_free_small(cinfo, pointer(shdr_ptr), space_freed); - Dec(mem^.total_space_allocated, space_freed); - shdr_ptr := next_shdr_ptr; - end; -end; - - -{ Close up shop entirely. - Note that this cannot be called unless cinfo^.mem is non-NIL. } - -{METHODDEF} -procedure self_destruct (cinfo : j_common_ptr); -var - pool : int; -begin - { Close all backing store, release all memory. - Releasing pools in reverse order might help avoid fragmentation - with some (brain-damaged) malloc libraries. } - - for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT do - begin - free_pool(cinfo, pool); - end; - - { Release the memory manager control block too. } - jpeg_free_small(cinfo, pointer(cinfo^.mem), SIZEOF(my_memory_mgr)); - cinfo^.mem := NIL; { ensures I will be called only once } - - jpeg_mem_term(cinfo); { system-dependent cleanup } -end; - - -{ Memory manager initialization. - When this is called, only the error manager pointer is valid in cinfo! } - -{GLOBAL} -procedure jinit_memory_mgr (cinfo : j_common_ptr); -var - mem : my_mem_ptr; - max_to_use : long; - pool : int; - test_mac : size_t; -{$ifndef NO_GETENV} -var - memenv : string; - code : integer; -{$endif} -begin - cinfo^.mem := NIL; { for safety if init fails } - - { Check for configuration errors. - SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably - doesn't reflect any real hardware alignment requirement. - The test is a little tricky: for X>0, X and X-1 have no one-bits - in common if and only if X is a power of 2, ie has only one one-bit. - Some compilers may give an "unreachable code" warning here; ignore it. } - if ((SIZEOF(ALIGN_TYPE) and (SIZEOF(ALIGN_TYPE)-1)) <> 0) then - ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); - { MAX_ALLOC_CHUNK must be representable as type size_t, and must be - a multiple of SIZEOF(ALIGN_TYPE). - Again, an "unreachable code" warning may be ignored here. - But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. } - - test_mac := size_t (MAX_ALLOC_CHUNK); - if (long (test_mac) <> MAX_ALLOC_CHUNK) or - ((MAX_ALLOC_CHUNK mod SIZEOF(ALIGN_TYPE)) <> 0) then - ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); - - max_to_use := jpeg_mem_init(cinfo); { system-dependent initialization } - - { Attempt to allocate memory manager's control block } - mem := my_mem_ptr (jpeg_get_small(cinfo, SIZEOF(my_memory_mgr))); - - if (mem = NIL) then - begin - jpeg_mem_term(cinfo); { system-dependent cleanup } - ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); - end; - - { OK, fill in the method pointers } - mem^.pub.alloc_small := alloc_small; - mem^.pub.alloc_large := alloc_large; - mem^.pub.alloc_sarray := alloc_sarray; - mem^.pub.alloc_barray := alloc_barray; - mem^.pub.request_virt_sarray := request_virt_sarray; - mem^.pub.request_virt_barray := request_virt_barray; - mem^.pub.realize_virt_arrays := realize_virt_arrays; - mem^.pub.access_virt_sarray := access_virt_sarray; - mem^.pub.access_virt_barray := access_virt_barray; - mem^.pub.free_pool := free_pool; - mem^.pub.self_destruct := self_destruct; - - { Make MAX_ALLOC_CHUNK accessible to other modules } - mem^.pub.max_alloc_chunk := MAX_ALLOC_CHUNK; - - { Initialize working state } - mem^.pub.max_memory_to_use := max_to_use; - - for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT do - begin - mem^.small_list[pool] := NIL; - mem^.large_list[pool] := NIL; - end; - mem^.virt_sarray_list := NIL; - mem^.virt_barray_list := NIL; - - mem^.total_space_allocated := SIZEOF(my_memory_mgr); - - { Declare ourselves open for business } - cinfo^.mem := @mem^.pub; - - { Check for an environment variable JPEGMEM; if found, override the - default max_memory setting from jpeg_mem_init. Note that the - surrounding application may again override this value. - If your system doesn't support getenv(), define NO_GETENV to disable - this feature. } - -{$ifndef NO_GETENV} - memenv := getenv('JPEGMEM'); - if (memenv <> '') then - begin - Val(memenv, max_to_use, code); - if (Code = 0) then - begin - max_to_use := max_to_use * long(1000); - mem^.pub.max_memory_to_use := max_to_use * long(1000); - end; - end; -{$endif} - -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjmemnobs.pas b/3rd/Imaging/Source/JpegLib/imjmemnobs.pas deleted file mode 100644 index 750fd807e..000000000 --- a/3rd/Imaging/Source/JpegLib/imjmemnobs.pas +++ /dev/null @@ -1,259 +0,0 @@ -unit imjmemnobs; -{ Delphi3 -- > jmemnobs from jmemwin } -{ This file provides an Win32-compatible implementation of the system- - dependent portion of the JPEG memory manager. } - -{ Check jmemnobs.c } -{ Copyright (C) 1996, Jacques Nomssi Nzali } - - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjdeferr, - imjerror, - imjpeglib; - -{ The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may - be requested in a single call to jpeg_get_large (and jpeg_get_small for that - matter, but that case should never come into play). This macro is needed - to model the 64Kb-segment-size limit of far addressing on 80x86 machines. - On those machines, we expect that jconfig.h will provide a proper value. - On machines with 32-bit flat address spaces, any large constant may be used. - - NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type - size_t and will be a multiple of sizeof(align_type). } - -const - MAX_ALLOC_CHUNK = long(1000000000); - -{GLOBAL} -procedure jpeg_open_backing_store (cinfo : j_common_ptr; - info : backing_store_ptr; - total_bytes_needed : long); - -{ These routines take care of any system-dependent initialization and - cleanup required. } - -{GLOBAL} -function jpeg_mem_init (cinfo : j_common_ptr) : long; - -{GLOBAL} -procedure jpeg_mem_term (cinfo : j_common_ptr); - -{ These two functions are used to allocate and release small chunks of - memory. (Typically the total amount requested through jpeg_get_small is - no more than 20K or so; this will be requested in chunks of a few K each.) - Behavior should be the same as for the standard library functions malloc - and free; in particular, jpeg_get_small must return NIL on failure. - On most systems, these ARE malloc and free. jpeg_free_small is passed the - size of the object being freed, just in case it's needed. - On an 80x86 machine using small-data memory model, these manage near heap. } - - -{ Near-memory allocation and freeing are controlled by the regular library - routines malloc() and free(). } - -{GLOBAL} -function jpeg_get_small (cinfo : j_common_ptr; - sizeofobject : size_t) : pointer; - -{GLOBAL} -{object is a reserved word in Borland Pascal } -procedure jpeg_free_small (cinfo : j_common_ptr; - an_object : pointer; - sizeofobject : size_t); - -{ These two functions are used to allocate and release large chunks of - memory (up to the total free space designated by jpeg_mem_available). - The interface is the same as above, except that on an 80x86 machine, - far pointers are used. On most other machines these are identical to - the jpeg_get/free_small routines; but we keep them separate anyway, - in case a different allocation strategy is desirable for large chunks. } - - -{ "Large" objects are allocated in far memory, if possible } - - -{GLOBAL} -function jpeg_get_large (cinfo : j_common_ptr; - sizeofobject : size_t) : voidp; {far} - -{GLOBAL} -procedure jpeg_free_large (cinfo : j_common_ptr; - {var?} an_object : voidp; {FAR} - sizeofobject : size_t); - -{ This routine computes the total memory space available for allocation. - It's impossible to do this in a portable way; our current solution is - to make the user tell us (with a default value set at compile time). - If you can actually get the available space, it's a good idea to subtract - a slop factor of 5% or so. } - -{GLOBAL} -function jpeg_mem_available (cinfo : j_common_ptr; - min_bytes_needed : long; - max_bytes_needed : long; - already_allocated : long) : long; - - -implementation - -{ This structure holds whatever state is needed to access a single - backing-store object. The read/write/close method pointers are called - by jmemmgr.c to manipulate the backing-store object; all other fields - are private to the system-dependent backing store routines. } - - - -{ These two functions are used to allocate and release small chunks of - memory. (Typically the total amount requested through jpeg_get_small is - no more than 20K or so; this will be requested in chunks of a few K each.) - Behavior should be the same as for the standard library functions malloc - and free; in particular, jpeg_get_small must return NIL on failure. - On most systems, these ARE malloc and free. jpeg_free_small is passed the - size of the object being freed, just in case it's needed. - On an 80x86 machine using small-data memory model, these manage near heap. } - - -{ Near-memory allocation and freeing are controlled by the regular library - routines malloc() and free(). } - -{GLOBAL} -function jpeg_get_small (cinfo : j_common_ptr; - sizeofobject : size_t) : pointer; -var - p : pointer; -begin - GetMem(p, sizeofobject); - jpeg_get_small := p; -end; - -{GLOBAL} -{object is a reserved word in Object Pascal } -procedure jpeg_free_small (cinfo : j_common_ptr; - an_object : pointer; - sizeofobject : size_t); -begin - FreeMem(an_object, sizeofobject); -end; - -{ These two functions are used to allocate and release large chunks of - memory (up to the total free space designated by jpeg_mem_available). - The interface is the same as above, except that on an 80x86 machine, - far pointers are used. On most other machines these are identical to - the jpeg_get/free_small routines; but we keep them separate anyway, - in case a different allocation strategy is desirable for large chunks. } - - - -{GLOBAL} -function jpeg_get_large (cinfo : j_common_ptr; - sizeofobject : size_t) : voidp; {far} -var - p : pointer; -begin - GetMem(p, sizeofobject); - jpeg_get_large := p; -end; - -{GLOBAL} -procedure jpeg_free_large (cinfo : j_common_ptr; - {var?} an_object : voidp; {FAR} - sizeofobject : size_t); -begin - Freemem(an_object, sizeofobject); -end; - -{ This routine computes the total space still available for allocation by - jpeg_get_large. If more space than this is needed, backing store will be - used. NOTE: any memory already allocated must not be counted. - - There is a minimum space requirement, corresponding to the minimum - feasible buffer sizes; jmemmgr.c will request that much space even if - jpeg_mem_available returns zero. The maximum space needed, enough to hold - all working storage in memory, is also passed in case it is useful. - Finally, the total space already allocated is passed. If no better - method is available, cinfo^.mem^.max_memory_to_use - already_allocated - is often a suitable calculation. - - It is OK for jpeg_mem_available to underestimate the space available - (that'll just lead to more backing-store access than is really necessary). - However, an overestimate will lead to failure. Hence it's wise to subtract - a slop factor from the true available space. 5% should be enough. - - On machines with lots of virtual memory, any large constant may be returned. - Conversely, zero may be returned to always use the minimum amount of memory.} - - - -{ This routine computes the total memory space available for allocation. - It's impossible to do this in a portable way; our current solution is - to make the user tell us (with a default value set at compile time). - If you can actually get the available space, it's a good idea to subtract - a slop factor of 5% or so. } - -const - DEFAULT_MAX_MEM = long(300000); { for total usage about 450K } - -{GLOBAL} -function jpeg_mem_available (cinfo : j_common_ptr; - min_bytes_needed : long; - max_bytes_needed : long; - already_allocated : long) : long; -begin - {jpeg_mem_available := cinfo^.mem^.max_memory_to_use - already_allocated;} - jpeg_mem_available := max_bytes_needed; -end; - - -{ Initial opening of a backing-store object. This must fill in the - read/write/close pointers in the object. The read/write routines - may take an error exit if the specified maximum file size is exceeded. - (If jpeg_mem_available always returns a large value, this routine can - just take an error exit.) } - - - -{ Initial opening of a backing-store object. } - -{GLOBAL} -procedure jpeg_open_backing_store (cinfo : j_common_ptr; - info : backing_store_ptr; - total_bytes_needed : long); -begin - ERREXIT(cinfo, JERR_NO_BACKING_STORE); -end; - -{ These routines take care of any system-dependent initialization and - cleanup required. jpeg_mem_init will be called before anything is - allocated (and, therefore, nothing in cinfo is of use except the error - manager pointer). It should return a suitable default value for - max_memory_to_use; this may subsequently be overridden by the surrounding - application. (Note that max_memory_to_use is only important if - jpeg_mem_available chooses to consult it ... no one else will.) - jpeg_mem_term may assume that all requested memory has been freed and that - all opened backing-store objects have been closed. } - - -{ These routines take care of any system-dependent initialization and - cleanup required. } - - -{GLOBAL} -function jpeg_mem_init (cinfo : j_common_ptr) : long; -begin - jpeg_mem_init := DEFAULT_MAX_MEM; { default for max_memory_to_use } -end; - -{GLOBAL} -procedure jpeg_mem_term (cinfo : j_common_ptr); -begin - -end; - - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjmorecfg.pas b/3rd/Imaging/Source/JpegLib/imjmorecfg.pas deleted file mode 100644 index fddf3f5b8..000000000 --- a/3rd/Imaging/Source/JpegLib/imjmorecfg.pas +++ /dev/null @@ -1,219 +0,0 @@ -unit imjmorecfg; - -{ This file contains additional configuration options that customize the - JPEG software for special applications or support machine-dependent - optimizations. Most users will not need to touch this file. } - -{ Source: jmorecfg.h; Copyright (C) 1991-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -type - int = Integer; - uInt = Cardinal; - short = SmallInt; - ushort = Word; - long = LongInt; - -type - voidp = pointer; - -type - int_ptr = ^int; - size_t = int; - -{ Define BITS_IN_JSAMPLE as either - 8 for 8-bit sample values (the usual setting) - 12 for 12-bit sample values - Only 8 and 12 are legal data precisions for lossy JPEG according to the - JPEG standard, and the IJG code does not support anything else! - We do not support run-time selection of data precision, sorry. } - - -{$ifdef BITS_IN_JSAMPLE_IS_8} { use 8 or 12 } -const - BITS_IN_JSAMPLE = 8; -{$else} -const - BITS_IN_JSAMPLE = 12; -{$endif} - - -{ Maximum number of components (color channels) allowed in JPEG image. - To meet the letter of the JPEG spec, set this to 255. However, darn - few applications need more than 4 channels (maybe 5 for CMYK + alpha - mask). We recommend 10 as a reasonable compromise; use 4 if you are - really short on memory. (Each allowed component costs a hundred or so - bytes of storage, whether actually used in an image or not.) } - - -const - MAX_COMPONENTS = 10; { maximum number of image components } - - -{ Basic data types. - You may need to change these if you have a machine with unusual data - type sizes; for example, "char" not 8 bits, "short" not 16 bits, - or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, - but it had better be at least 16. } - - -{ Representation of a single sample (pixel element value). - We frequently allocate large arrays of these, so it's important to keep - them small. But if you have memory to burn and access to char or short - arrays is very slow on your hardware, you might want to change these. } - - -{$ifdef BITS_IN_JSAMPLE_IS_8} -{ JSAMPLE should be the smallest type that will hold the values 0..255. - You can use a signed char by having GETJSAMPLE mask it with $FF. } - -{ CHAR_IS_UNSIGNED } -type - JSAMPLE = byte; { Pascal unsigned char } - GETJSAMPLE = int; - -const - MAXJSAMPLE = 255; - CENTERJSAMPLE = 128; - -{$endif} - -{$ifndef BITS_IN_JSAMPLE_IS_8} -{ JSAMPLE should be the smallest type that will hold the values 0..4095. - On nearly all machines "short" will do nicely. } - -type - JSAMPLE = short; - GETJSAMPLE = int; - -const - MAXJSAMPLE = 4095; - CENTERJSAMPLE = 2048; - -{$endif} { BITS_IN_JSAMPLE = 12 } - - -{ Representation of a DCT frequency coefficient. - This should be a signed value of at least 16 bits; "short" is usually OK. - Again, we allocate large arrays of these, but you can change to int - if you have memory to burn and "short" is really slow. } -type - JCOEF = int; - JCOEF_PTR = ^JCOEF; - - -{ Compressed datastreams are represented as arrays of JOCTET. - These must be EXACTLY 8 bits wide, at least once they are written to - external storage. Note that when using the stdio data source/destination - managers, this is also the data type passed to fread/fwrite. } - - -type - JOCTET = Byte; - jTOctet = 0..(MaxInt div SizeOf(JOCTET))-1; - JOCTET_FIELD = array[jTOctet] of JOCTET; - JOCTET_FIELD_PTR = ^JOCTET_FIELD; - JOCTETPTR = ^JOCTET; - - GETJOCTET = JOCTET; { A work around } - - -{ These typedefs are used for various table entries and so forth. - They must be at least as wide as specified; but making them too big - won't cost a huge amount of memory, so we don't provide special - extraction code like we did for JSAMPLE. (In other words, these - typedefs live at a different point on the speed/space tradeoff curve.) } - - -{ UINT8 must hold at least the values 0..255. } - -type - UINT8 = Byte; - -{ UINT16 must hold at least the values 0..65535. } - - UINT16 = Word; - -{ INT16 must hold at least the values -32768..32767. } - - INT16 = SmallInt; - -{ INT32 must hold at least signed 32-bit values. } - - INT32 = LongInt; -type - INT32PTR = ^INT32; - -{ Datatype used for image dimensions. The JPEG standard only supports - images up to 64K*64K due to 16-bit fields in SOF markers. Therefore - "unsigned int" is sufficient on all machines. However, if you need to - handle larger images and you don't mind deviating from the spec, you - can change this datatype. } - -type - JDIMENSION = uInt; - -const - JPEG_MAX_DIMENSION = 65500; { a tad under 64K to prevent overflows } - - -{ Ordering of RGB data in scanlines passed to or from the application. - If your application wants to deal with data in the order B,G,R, just - change these macros. You can also deal with formats such as R,G,B,X - (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing - the offsets will also change the order in which colormap data is organized. - RESTRICTIONS: - 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. - 2. These macros only affect RGB<=>YCbCr color conversion, so they are not - useful if you are using JPEG color spaces other than YCbCr or grayscale. - 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE - is not 3 (they don't understand about dummy color components!). So you - can't use color quantization if you change that value. } - -{$ifdef RGB_RED_IS_0} -const - RGB_RED = 0; { Offset of Red in an RGB scanline element } - RGB_GREEN = 1; { Offset of Green } - RGB_BLUE = 2; { Offset of Blue } -{$else} -const - RGB_RED = 2; { Offset of Red in an RGB scanline element } - RGB_GREEN = 1; { Offset of Green } - RGB_BLUE = 0; { Offset of Blue } -{$endif} - -{$ifdef RGB_PIXELSIZE_IS_3} -const - RGB_PIXELSIZE = 3; { JSAMPLEs per RGB scanline element } -{$else} -const - RGB_PIXELSIZE = ??; { Nomssi: deliberate syntax error. Set this value } -{$endif} - -{ Definitions for speed-related optimizations. } - -{ On some machines (notably 68000 series) "int" is 32 bits, but multiplying - two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER - as short on such a machine. MULTIPLIER must be at least 16 bits wide. } -type - MULTIPLIER = int; { type for fastest integer multiply } - - -{ FAST_FLOAT should be either float or double, whichever is done faster - by your compiler. (Note that this type is only used in the floating point - DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) - Typically, float is faster in ANSI C compilers, while double is faster in - pre-ANSI compilers (because they insist on converting to double anyway). - The code below therefore chooses float if we have ANSI-style prototypes. } - -type - FAST_FLOAT = double; {float} - - -implementation - - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjpeglib.pas b/3rd/Imaging/Source/JpegLib/imjpeglib.pas deleted file mode 100644 index f30ece662..000000000 --- a/3rd/Imaging/Source/JpegLib/imjpeglib.pas +++ /dev/null @@ -1,1300 +0,0 @@ -unit imjpeglib; - -{ This file defines the application interface for the JPEG library. - Most applications using the library need only include this file, - and perhaps jerror.h if they want to know the exact error codes. } - -{ Source:jpeglib.h+jpegint.h; Copyright (C) 1991-1998, Thomas G. Lane. } - - -interface - -{$I imjconfig.inc} - -{ First we include the configuration files that record how this - installation of the JPEG library is set up. jconfig.h can be - generated automatically for many systems. jmorecfg.h contains - manual configuration options that most people need not worry about. } - -uses - imjdeferr, - imjmorecfg; { seldom changed options } - -{ Version ID for the JPEG library. - Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". } - - -Const - JPEG_LIB_VERSION = 62; { Version 6b } - - -{ These marker codes are exported since applications and data source modules - are likely to want to use them. } - -const - JPEG_RST0 = $D0; { RST0 marker code } - JPEG_EOI = $D9; { EOI marker code } - JPEG_APP0 = $E0; { APP0 marker code } - JPEG_COM = $FE; { COM marker code } - - -{ Various constants determining the sizes of things. - All of these are specified by the JPEG standard, so don't change them - if you want to be compatible. } - -const - DCTSIZE = 8; { The basic DCT block is 8x8 samples } - DCTSIZE2 = 64; { DCTSIZE squared; # of elements in a block } - NUM_QUANT_TBLS = 4; { Quantization tables are numbered 0..3 } - NUM_HUFF_TBLS = 4; { Huffman tables are numbered 0..3 } - NUM_ARITH_TBLS = 16; { Arith-coding tables are numbered 0..15 } - MAX_COMPS_IN_SCAN = 4; { JPEG limit on # of components in one scan } - MAX_SAMP_FACTOR = 4; { JPEG limit on sampling factors } -{ Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; - the PostScript DCT filter can emit files with many more than 10 blocks/MCU. - If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU - to handle it. We even let you do this from the jconfig.h file. However, - we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe - sometimes emits noncompliant files doesn't mean you should too. } - C_MAX_BLOCKS_IN_MCU = 10; { compressor's limit on blocks per MCU } - D_MAX_BLOCKS_IN_MCU = 10; { decompressor's limit on blocks per MCU } - - -{ Data structures for images (arrays of samples and of DCT coefficients). - On 80x86 machines, the image arrays are too big for near pointers, - but the pointer arrays can fit in near memory. } - -type -{ for typecasting } - JSAMPLE_PTR = ^JSAMPLE; - JSAMPROW_PTR = ^JSAMPROW; - JBLOCKROW_PTR = ^JBLOCKROW; - - jTSample = 0..(MaxInt div SIZEOF(JSAMPLE))-1; - JSAMPLE_ARRAY = Array[jTSample] of JSAMPLE; {far} - JSAMPROW = ^JSAMPLE_ARRAY; { ptr to one image row of pixel samples. } - - jTRow = 0..(MaxInt div SIZEOF(JSAMPROW))-1; - JSAMPROW_ARRAY = Array[jTRow] of JSAMPROW; - JSAMPARRAY = ^JSAMPROW_ARRAY; { ptr to some rows (a 2-D sample array) } - - jTArray = 0..(MaxInt div SIZEOF(JSAMPARRAY))-1; - JSAMP_ARRAY = Array[jTArray] of JSAMPARRAY; - JSAMPIMAGE = ^JSAMP_ARRAY; { a 3-D sample array: top index is color } - - JBLOCK = Array[0..DCTSIZE2-1] of JCOEF; { one block of coefficients } - JBLOCK_PTR = ^JBLOCK; - - jTBlockRow = 0..(MaxInt div SIZEOF(JBLOCK))-1; - JBLOCK_ROWS = Array[jTBlockRow] of JBLOCK; - JBLOCKROW = ^JBLOCK_ROWS; {far} { pointer to one row of coefficient blocks } - - - jTBlockArray = 0..(MaxInt div SIZEOF(JBLOCKROW))-1; - JBLOCK_ARRAY = Array[jTBlockArray] of JBLOCKROW; - JBLOCKARRAY = ^JBLOCK_ARRAY; { a 2-D array of coefficient blocks } - - jTBlockImage = 0..(MaxInt div SIZEOF(JBLOCKARRAY))-1; - JBLOCK_IMAGE = Array[jTBlockImage] of JBLOCKARRAY; - JBLOCKIMAGE = ^JBLOCK_IMAGE; { a 3-D array of coefficient blocks } - - jTCoef = 0..(MaxInt div SIZEOF(JCOEF))-1; - JCOEF_ROW = Array[jTCoef] of JCOEF; - JCOEFPTR = ^JCOEF_ROW; {far} { useful in a couple of places } - - -type - jTByte = 0..(MaxInt div SIZEOF(byte))-1; - JByteArray = Array[jTByte] of byte; - JBytePtr = ^JByteArray; -type - byteptr = ^byte; - -{ Types for JPEG compression parameters and working tables. } - - -{ DCT coefficient quantization tables. } - -type - JQUANT_TBL_PTR = ^JQUANT_TBL; - JQUANT_TBL = record - { This array gives the coefficient quantizers in natural array order - (not the zigzag order in which they are stored in a JPEG DQT marker). - CAUTION: IJG versions prior to v6a kept this array in zigzag order. } - quantval : Array[0..DCTSIZE2-1] of UINT16; - { quantization step for each coefficient } - { This field is used only during compression. It's initialized FALSE when - the table is created, and set TRUE when it's been output to the file. - You could suppress output of a table by setting this to TRUE. - (See jpeg_suppress_tables for an example.) } - sent_table : boolean; { TRUE when table has been output } - end; - JQUANT_TBL_FIELD = Array[0..(MaxInt div SizeOf(JQUANT_TBL))-1] of JQUANT_TBL; - -{ Huffman coding tables. } - -type - JHUFF_TBL_PTR = ^JHUFF_TBL; - JHUFF_TBL = record - { These two fields directly represent the contents of a JPEG DHT marker } - bits : Array[0..17-1] of UINT8; { bits[k] = # of symbols with codes of } - { length k bits; bits[0] is unused } - huffval : Array[0..256-1] of UINT8; - { The symbols, in order of incr code length } - { This field is used only during compression. It's initialized FALSE when - the table is created, and set TRUE when it's been output to the file. - You could suppress output of a table by setting this to TRUE. - (See jpeg_suppress_tables for an example.) } - sent_table : boolean; { TRUE when table has been output } - end; - JHUFF_TBL_FIELD = Array[0..(MaxInt div SizeOf(JHUFF_TBL))-1] of JHUFF_TBL; - -{ Declarations for both compression & decompression } - -type - J_BUF_MODE = ( { Operating modes for buffer controllers } - JBUF_PASS_THRU, { Plain stripwise operation } - { Remaining modes require a full-image buffer to have been created } - JBUF_SAVE_SOURCE, { Run source subobject only, save output } - JBUF_CRANK_DEST, { Run dest subobject only, using saved data } - JBUF_SAVE_AND_PASS { Run both subobjects, save output } - ); - -{ Values of global_state field (jdapi.c has some dependencies on ordering!) } -const - CSTATE_START = 100; { after create_compress } - CSTATE_SCANNING = 101; { start_compress done, write_scanlines OK } - CSTATE_RAW_OK = 102; { start_compress done, write_raw_data OK } - CSTATE_WRCOEFS = 103; { jpeg_write_coefficients done } - DSTATE_START = 200; { after create_decompress } - DSTATE_INHEADER = 201; { reading header markers, no SOS yet } - DSTATE_READY = 202; { found SOS, ready for start_decompress } - DSTATE_PRELOAD = 203; { reading multiscan file in start_decompress} - DSTATE_PRESCAN = 204; { performing dummy pass for 2-pass quant } - DSTATE_SCANNING = 205; { start_decompress done, read_scanlines OK } - DSTATE_RAW_OK = 206; { start_decompress done, read_raw_data OK } - DSTATE_BUFIMAGE = 207; { expecting jpeg_start_output } - DSTATE_BUFPOST = 208; { looking for SOS/EOI in jpeg_finish_output } - DSTATE_RDCOEFS = 209; { reading file in jpeg_read_coefficients } - DSTATE_STOPPING = 210; { looking for EOI in jpeg_finish_decompress } - - - -{ Basic info about one component (color channel). } - -type - jpeg_component_info_ptr = ^jpeg_component_info; - jpeg_component_info = record - { These values are fixed over the whole image. } - { For compression, they must be supplied by parameter setup; } - { for decompression, they are read from the SOF marker. } - component_id : int; { identifier for this component (0..255) } - component_index : int; { its index in SOF or cinfo^.comp_info[] } - h_samp_factor : int; { horizontal sampling factor (1..4) } - v_samp_factor : int; { vertical sampling factor (1..4) } - quant_tbl_no : int; { quantization table selector (0..3) } - { These values may vary between scans. } - { For compression, they must be supplied by parameter setup; } - { for decompression, they are read from the SOS marker. } - { The decompressor output side may not use these variables. } - dc_tbl_no : int; { DC entropy table selector (0..3) } - ac_tbl_no : int; { AC entropy table selector (0..3) } - - { Remaining fields should be treated as private by applications. } - - { These values are computed during compression or decompression startup: } - { Component's size in DCT blocks. - Any dummy blocks added to complete an MCU are not counted; therefore - these values do not depend on whether a scan is interleaved or not. } - width_in_blocks : JDIMENSION; - height_in_blocks : JDIMENSION; - { Size of a DCT block in samples. Always DCTSIZE for compression. - For decompression this is the size of the output from one DCT block, - reflecting any scaling we choose to apply during the IDCT step. - Values of 1,2,4,8 are likely to be supported. Note that different - components may receive different IDCT scalings. } - - DCT_scaled_size : int; - { The downsampled dimensions are the component's actual, unpadded number - of samples at the main buffer (preprocessing/compression interface), thus - downsampled_width = ceil(image_width * Hi/Hmax) - and similarly for height. For decompression, IDCT scaling is included, so - downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE)} - - downsampled_width : JDIMENSION; { actual width in samples } - downsampled_height : JDIMENSION; { actual height in samples } - { This flag is used only for decompression. In cases where some of the - components will be ignored (eg grayscale output from YCbCr image), - we can skip most computations for the unused components. } - - component_needed : boolean; { do we need the value of this component? } - - { These values are computed before starting a scan of the component. } - { The decompressor output side may not use these variables. } - MCU_width : int; { number of blocks per MCU, horizontally } - MCU_height : int; { number of blocks per MCU, vertically } - MCU_blocks : int; { MCU_width * MCU_height } - MCU_sample_width : int; { MCU width in samples, MCU_width*DCT_scaled_size } - last_col_width : int; { # of non-dummy blocks across in last MCU } - last_row_height : int; { # of non-dummy blocks down in last MCU } - - { Saved quantization table for component; NIL if none yet saved. - See jdinput.c comments about the need for this information. - This field is currently used only for decompression. } - - quant_table : JQUANT_TBL_PTR; - - { Private per-component storage for DCT or IDCT subsystem. } - dct_table : pointer; - end; { record jpeg_component_info } - - jTCinfo = 0..(MaxInt div SizeOf(jpeg_component_info))-1; - jpeg_component_info_array = array[jTCinfo] of jpeg_component_info; - jpeg_component_info_list_ptr = ^jpeg_component_info_array; - - -{ The script for encoding a multiple-scan file is an array of these: } - -type - jpeg_scan_info_ptr = ^jpeg_scan_info; - jpeg_scan_info = record - comps_in_scan : int; { number of components encoded in this scan } - component_index : Array[0..MAX_COMPS_IN_SCAN-1] of int; - { their SOF/comp_info[] indexes } - Ss, Se : int; { progressive JPEG spectral selection parms } - Ah, Al : int; { progressive JPEG successive approx. parms } - end; - -{ The decompressor can save APPn and COM markers in a list of these: } - -type - jpeg_saved_marker_ptr = ^jpeg_marker_struct; - jpeg_marker_struct = record - next : jpeg_saved_marker_ptr; { next in list, or NULL } - marker : UINT8; { marker code: JPEG_COM, or JPEG_APP0+n } - original_length : uint; { # bytes of data in the file } - data_length : uint; { # bytes of data saved at data[] } - data : JOCTET_FIELD_PTR; { the data contained in the marker } - { the marker length word is not counted in data_length or original_length } - end; - -{ Known color spaces. } - -type - J_COLOR_SPACE = ( - JCS_UNKNOWN, { error/unspecified } - JCS_GRAYSCALE, { monochrome } - JCS_RGB, { red/green/blue } - JCS_YCbCr, { Y/Cb/Cr (also known as YUV) } - JCS_CMYK, { C/M/Y/K } - JCS_YCCK { Y/Cb/Cr/K } - ); - -{ DCT/IDCT algorithm options. } - -type - J_DCT_METHOD = ( - JDCT_ISLOW, { slow but accurate integer algorithm } - JDCT_IFAST, { faster, less accurate integer method } - JDCT_FLOAT { floating-point: accurate, fast on fast HW } - ); - -const - JDCT_DEFAULT = JDCT_ISLOW; - JDCT_FASTEST = JDCT_IFAST; - -{ Dithering options for decompression. } - -type - J_DITHER_MODE = ( - JDITHER_NONE, { no dithering } - JDITHER_ORDERED, { simple ordered dither } - JDITHER_FS { Floyd-Steinberg error diffusion dither } - ); - - -const - JPOOL_PERMANENT = 0; { lasts until master record is destroyed } - JPOOL_IMAGE = 1; { lasts until done with image/datastream } - JPOOL_NUMPOOLS = 2; - - -{ "Object" declarations for JPEG modules that may be supplied or called - directly by the surrounding application. - As with all objects in the JPEG library, these structs only define the - publicly visible methods and state variables of a module. Additional - private fields may exist after the public ones. } - - -{ Error handler object } - -const - JMSG_LENGTH_MAX = 200; { recommended size of format_message buffer } - JMSG_STR_PARM_MAX = 80; - -const - TEMP_NAME_LENGTH = 64; { max length of a temporary file's name } -type - TEMP_STRING = string[TEMP_NAME_LENGTH]; - -{$ifdef USE_MSDOS_MEMMGR} { DOS-specific junk } -type - XMSH = ushort; { type of extended-memory handles } - EMSH = ushort; { type of expanded-memory handles } - - handle_union = record - case byte of - 0:(file_handle : short); { DOS file handle if it's a temp file } - 1:(xms_handle : XMSH); { handle if it's a chunk of XMS } - 2:(ems_handle : EMSH); { handle if it's a chunk of EMS } - end; -{$endif} { USE_MSDOS_MEMMGR } - -type - jpeg_error_mgr_ptr = ^jpeg_error_mgr; - jpeg_memory_mgr_ptr = ^jpeg_memory_mgr; - jpeg_progress_mgr_ptr = ^jpeg_progress_mgr; - - -{$ifdef common} -{ Common fields between JPEG compression and decompression master structs. } - err : jpeg_error_mgr_ptr; { Error handler module } - mem : jpeg_memory_mgr_ptr; { Memory manager module } - progress : jpeg_progress_mgr_ptr; { Progress monitor, or NIL if none } - client_data : voidp; { Available for use by application } - is_decompressor : boolean; { so common code can tell which is which } - global_state : int; { for checking call sequence validity } -{$endif} - - j_common_ptr = ^jpeg_common_struct; - j_compress_ptr = ^jpeg_compress_struct; - j_decompress_ptr = ^jpeg_decompress_struct; - - {$ifdef AM_MEMORY_MANAGER} { only jmemmgr.c defines these } - -{ This structure holds whatever state is needed to access a single - backing-store object. The read/write/close method pointers are called - by jmemmgr.c to manipulate the backing-store object; all other fields - are private to the system-dependent backing store routines. } - - - backing_store_ptr = ^backing_store_info; - backing_store_info = record - { Methods for reading/writing/closing this backing-store object } - read_backing_store : procedure (cinfo : j_common_ptr; - info : backing_store_ptr; - buffer_address : pointer; {far} - file_offset : long; - byte_count : long); - write_backing_store : procedure (cinfo : j_common_ptr; - info : backing_store_ptr; - buffer_address : pointer; {far} - file_offset : long; - byte_count : long); - - close_backing_store : procedure (cinfo : j_common_ptr; - info : backing_store_ptr); - - { Private fields for system-dependent backing-store management } - {$ifdef USE_MSDOS_MEMMGR} - { For the MS-DOS manager (jmemdos.c), we need: } - handle : handle_union; { reference to backing-store storage object } - temp_name : TEMP_STRING; { name if it's a file } - {$else} - { For a typical implementation with temp files, we need: } - temp_file : file; { stdio reference to temp file } - temp_name : TEMP_STRING; { name of temp file } - {$endif} - end; - - -{ The control blocks for virtual arrays. - Note that these blocks are allocated in the "small" pool area. - System-dependent info for the associated backing store (if any) is hidden - inside the backing_store_info struct. } - - jvirt_sarray_ptr = ^jvirt_sarray_control; - jvirt_sarray_control = record - mem_buffer : JSAMPARRAY; { => the in-memory buffer } - rows_in_array : JDIMENSION; { total virtual array height } - samplesperrow : JDIMENSION; { width of array (and of memory buffer) } - maxaccess : JDIMENSION; { max rows accessed by access_virt_sarray } - rows_in_mem : JDIMENSION; { height of memory buffer } - rowsperchunk : JDIMENSION; { allocation chunk size in mem_buffer } - cur_start_row : JDIMENSION; { first logical row # in the buffer } - first_undef_row : JDIMENSION; { row # of first uninitialized row } - pre_zero : boolean; { pre-zero mode requested? } - dirty : boolean; { do current buffer contents need written? } - b_s_open : boolean; { is backing-store data valid? } - next : jvirt_sarray_ptr; { link to next virtual sarray control block } - b_s_info : backing_store_info; { System-dependent control info } - end; - - jvirt_barray_ptr = ^jvirt_barray_control; - jvirt_barray_control = record - mem_buffer : JBLOCKARRAY; { => the in-memory buffer } - rows_in_array : JDIMENSION; { total virtual array height } - blocksperrow : JDIMENSION; { width of array (and of memory buffer) } - maxaccess : JDIMENSION; { max rows accessed by access_virt_barray } - rows_in_mem : JDIMENSION; { height of memory buffer } - rowsperchunk : JDIMENSION; { allocation chunk size in mem_buffer } - cur_start_row : JDIMENSION; { first logical row # in the buffer } - first_undef_row : JDIMENSION; { row # of first uninitialized row } - pre_zero : boolean; { pre-zero mode requested? } - dirty : boolean; { do current buffer contents need written? } - b_s_open : boolean; { is backing-store data valid? } - next : jvirt_barray_ptr; { link to next virtual barray control block } - b_s_info : backing_store_info; { System-dependent control info } - end; - - {$endif} { AM_MEMORY_MANAGER } - -{ Declarations for compression modules } - -{ Master control module } - jpeg_comp_master_ptr = ^jpeg_comp_master; - jpeg_comp_master = record - prepare_for_pass : procedure(cinfo : j_compress_ptr); - pass_startup : procedure(cinfo : j_compress_ptr); - finish_pass : procedure(cinfo : j_compress_ptr); - - { State variables made visible to other modules } - call_pass_startup : Boolean; { True if pass_startup must be called } - is_last_pass : Boolean; { True during last pass } - end; - -{ Main buffer control (downsampled-data buffer) } - jpeg_c_main_controller_ptr = ^jpeg_c_main_controller; - jpeg_c_main_controller = record - start_pass : procedure(cinfo : j_compress_ptr; pass_mode : J_BUF_MODE); - process_data : procedure(cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION); - end; - -{ Compression preprocessing (downsampling input buffer control) } - jpeg_c_prep_controller_ptr = ^jpeg_c_prep_controller; - jpeg_c_prep_controller = record - start_pass : procedure(cinfo : j_compress_ptr; pass_mode : J_BUF_MODE); - pre_process_data : procedure(cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - var in_row_ctr : JDIMENSION; - in_rows_avail : JDIMENSION; - output_buf : JSAMPIMAGE; - var out_row_group_ctr : JDIMENSION; - out_row_groups_avail : JDIMENSION); - end; - -{ Coefficient buffer control } - jpeg_c_coef_controller_ptr = ^jpeg_c_coef_controller; - jpeg_c_coef_controller = record - start_pass : procedure(cinfo : j_compress_ptr; pass_mode : J_BUF_MODE); - compress_data : function(cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE) : boolean; - end; - -{ Colorspace conversion } - jpeg_color_converter_ptr = ^jpeg_color_converter; - jpeg_color_converter = record - start_pass : procedure(cinfo : j_compress_ptr); - color_convert : procedure(cinfo : j_compress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPIMAGE; - output_row : JDIMENSION; - num_rows : int); - end; - -{ Downsampling } - jpeg_downsampler_ptr = ^jpeg_downsampler; - jpeg_downsampler = record - start_pass : procedure(cinfo : j_compress_ptr); - downsample : procedure(cinfo : j_compress_ptr; - input_buf : JSAMPIMAGE; - in_row_index : JDIMENSION; - output_buf : JSAMPIMAGE; - out_row_group_index: JDIMENSION); - need_context_rows : Boolean; { TRUE if need rows above & below } - end; - -{ Forward DCT (also controls coefficient quantization) } - jpeg_forward_dct_ptr = ^jpeg_forward_dct; - jpeg_forward_dct = record - start_pass : procedure(cinfo : j_compress_ptr); - { perhaps this should be an array??? } - forward_DCT : procedure(cinfo : j_compress_ptr; - compptr : jpeg_component_info_ptr; - sample_data : JSAMPARRAY; - coef_blocks : JBLOCKROW; - start_row : JDIMENSION; - start_col : JDIMENSION; - num_blocks : JDIMENSION); - end; - -{ Entropy encoding } - - jpeg_entropy_encoder_ptr = ^jpeg_entropy_encoder; - jpeg_entropy_encoder = record - start_pass : procedure(cinfo : j_compress_ptr; gather_statistics : boolean); - encode_mcu : function(cinfo : j_compress_ptr; - const MCU_data: array of JBLOCKROW) : boolean; - finish_pass : procedure(cinfo : j_compress_ptr); - end; - -{ Marker writing } - jpeg_marker_writer_ptr = ^jpeg_marker_writer; - jpeg_marker_writer = record - write_file_header : procedure(cinfo : j_compress_ptr); - write_frame_header : procedure(cinfo : j_compress_ptr); - write_scan_header : procedure(cinfo : j_compress_ptr); - write_file_trailer : procedure(cinfo : j_compress_ptr); - write_tables_only : procedure(cinfo : j_compress_ptr); - { These routines are exported to allow insertion of extra markers } - { Probably only COM and APPn markers should be written this way } - write_marker_header : procedure (cinfo : j_compress_ptr; - marker : int; - datalen : uint); - write_marker_byte : procedure (cinfo : j_compress_ptr; val : int); - end; - -{ Declarations for decompression modules } - -{ Master control module } - jpeg_decomp_master_ptr = ^jpeg_decomp_master; - jpeg_decomp_master = record - prepare_for_output_pass : procedure( cinfo : j_decompress_ptr); - finish_output_pass : procedure(cinfo : j_decompress_ptr); - - { State variables made visible to other modules } - is_dummy_pass : Boolean; { True during 1st pass for 2-pass quant } - end; - -{ Input control module } - jpeg_input_controller_ptr = ^jpeg_input_controller; - jpeg_input_controller = record - consume_input : function (cinfo : j_decompress_ptr) : int; - reset_input_controller : procedure(cinfo : j_decompress_ptr); - start_input_pass : procedure(cinfo : j_decompress_ptr); - finish_input_pass : procedure(cinfo : j_decompress_ptr); - - { State variables made visible to other modules } - has_multiple_scans : Boolean; { True if file has multiple scans } - eoi_reached : Boolean; { True when EOI has been consumed } - end; - -{ Main buffer control (downsampled-data buffer) } - - jpeg_d_main_controller_ptr = ^jpeg_d_main_controller; - jpeg_d_main_controller = record - start_pass : procedure(cinfo : j_decompress_ptr; pass_mode : J_BUF_MODE); - process_data : procedure(cinfo : j_decompress_ptr; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); - end; - -{ Coefficient buffer control } - jvirt_barray_tbl = array[0..MAX_COMPONENTS-1] of jvirt_barray_ptr; - jvirt_barray_tbl_ptr = ^jvirt_barray_tbl; - jpeg_d_coef_controller_ptr = ^jpeg_d_coef_controller; - jpeg_d_coef_controller = record - start_input_pass : procedure(cinfo : j_decompress_ptr); - consume_data : function (cinfo : j_decompress_ptr) : int; - start_output_pass : procedure(cinfo : j_decompress_ptr); - decompress_data : function (cinfo : j_decompress_ptr; - output_buf : JSAMPIMAGE) : int; - { Pointer to array of coefficient virtual arrays, or NIL if none } - coef_arrays : jvirt_barray_tbl_ptr; - end; - -{ Decompression postprocessing (color quantization buffer control) } - jpeg_d_post_controller_ptr = ^jpeg_d_post_controller; - jpeg_d_post_controller = record - start_pass : procedure(cinfo : j_decompress_ptr; - pass_mode : J_BUF_MODE); - post_process_data : procedure(cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); - end; - - -{ Routine signature for application-supplied marker processing methods. - Need not pass marker code since it is stored in cinfo^.unread_marker. } - - jpeg_marker_parser_method = function(cinfo : j_decompress_ptr) : boolean; - -{ Marker reading & parsing } - jpeg_marker_reader_ptr = ^jpeg_marker_reader; - jpeg_marker_reader = record - reset_marker_reader : procedure(cinfo : j_decompress_ptr); - { Read markers until SOS or EOI. - Returns same codes as are defined for jpeg_consume_input: - JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. } - - read_markers : function (cinfo : j_decompress_ptr) : int; - { Read a restart marker --- exported for use by entropy decoder only } - read_restart_marker : jpeg_marker_parser_method; - - { State of marker reader --- nominally internal, but applications - supplying COM or APPn handlers might like to know the state. } - - saw_SOI : boolean; { found SOI? } - saw_SOF : boolean; { found SOF? } - next_restart_num : int; { next restart number expected (0-7) } - discarded_bytes : uint; { # of bytes skipped looking for a marker } - end; - -{ Entropy decoding } - jpeg_entropy_decoder_ptr = ^jpeg_entropy_decoder; - jpeg_entropy_decoder = record - start_pass : procedure(cinfo : j_decompress_ptr); - decode_mcu : function(cinfo : j_decompress_ptr; - var MCU_data : array of JBLOCKROW) : boolean; - { This is here to share code between baseline and progressive decoders; } - { other modules probably should not use it } - insufficient_data : BOOLEAN; { set TRUE after emitting warning } - end; - -{ Inverse DCT (also performs dequantization) } - inverse_DCT_method_ptr = procedure(cinfo : j_decompress_ptr; - compptr : jpeg_component_info_ptr; - coef_block : JCOEFPTR; - output_buf : JSAMPARRAY; output_col : JDIMENSION); - - jpeg_inverse_dct_ptr = ^jpeg_inverse_dct; - jpeg_inverse_dct = record - start_pass : procedure(cinfo : j_decompress_ptr); - { It is useful to allow each component to have a separate IDCT method. } - inverse_DCT : Array[0..MAX_COMPONENTS-1] of inverse_DCT_method_ptr; - end; - -{ Upsampling (note that upsampler must also call color converter) } - jpeg_upsampler_ptr = ^jpeg_upsampler; - jpeg_upsampler = record - start_pass : procedure(cinfo : j_decompress_ptr); - upsample : procedure(cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - var in_row_group_ctr : JDIMENSION; { array of } - in_row_groups_avail : JDIMENSION; - output_buf : JSAMPARRAY; - var out_row_ctr : JDIMENSION; - out_rows_avail : JDIMENSION); - - need_context_rows : boolean; { TRUE if need rows above & below } - end; - -{ Colorspace conversion } - jpeg_color_deconverter_ptr = ^jpeg_color_deconverter; - jpeg_color_deconverter = record - start_pass : procedure(cinfo: j_decompress_ptr); - color_convert : procedure(cinfo : j_decompress_ptr; - input_buf : JSAMPIMAGE; - input_row : JDIMENSION; - output_buf : JSAMPARRAY; - num_rows : int); - end; - -{ Color quantization or color precision reduction } - jpeg_color_quantizer_ptr = ^jpeg_color_quantizer; - jpeg_color_quantizer = record - start_pass : procedure(cinfo : j_decompress_ptr; is_pre_scan : boolean); - color_quantize : procedure(cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); - - finish_pass : procedure(cinfo : j_decompress_ptr); - new_color_map : procedure(cinfo : j_decompress_ptr); - end; - - {int8array = Array[0..8-1] of int;} - int8array = Array[0..8-1] of longint; { for TP FormatStr } - - jpeg_error_mgr = record - { Error exit handler: does not return to caller } - error_exit : procedure (cinfo : j_common_ptr); - { Conditionally emit a trace or warning message } - emit_message : procedure (cinfo : j_common_ptr; msg_level : int); - { Routine that actually outputs a trace or error message } - output_message : procedure (cinfo : j_common_ptr); - { Format a message string for the most recent JPEG error or message } - format_message : procedure (cinfo : j_common_ptr; var buffer : AnsiString); - - { Reset error state variables at start of a new image } - reset_error_mgr : procedure (cinfo : j_common_ptr); - - { The message ID code and any parameters are saved here. - A message can have one string parameter or up to 8 int parameters. } - - msg_code : int; - - msg_parm : record - case byte of - 0:(i : int8array); - 1:(s : string[JMSG_STR_PARM_MAX]); - end; - - { Standard state variables for error facility } - - trace_level : int; { max msg_level that will be displayed } - - { For recoverable corrupt-data errors, we emit a warning message, - but keep going unless emit_message chooses to abort. emit_message - should count warnings in num_warnings. The surrounding application - can check for bad data by seeing if num_warnings is nonzero at the - end of processing. } - - num_warnings : long; { number of corrupt-data warnings } - - { These fields point to the table(s) of error message strings. - An application can change the table pointer to switch to a different - message list (typically, to change the language in which errors are - reported). Some applications may wish to add additional error codes - that will be handled by the JPEG library error mechanism; the second - table pointer is used for this purpose. - - First table includes all errors generated by JPEG library itself. - Error code 0 is reserved for a "no such error string" message. } - - {const char * const * jpeg_message_table; } - jpeg_message_table : ^msg_table; { Library errors } - - last_jpeg_message : J_MESSAGE_CODE; - { Table contains strings 0..last_jpeg_message } - { Second table can be added by application (see cjpeg/djpeg for example). - It contains strings numbered first_addon_message..last_addon_message. } - - {const char * const * addon_message_table; } - addon_message_table : ^msg_table; { Non-library errors } - - first_addon_message : J_MESSAGE_CODE; { code for first string in addon table } - last_addon_message : J_MESSAGE_CODE; { code for last string in addon table } - end; - - -{ Progress monitor object } - - jpeg_progress_mgr = record - progress_monitor : procedure(cinfo : j_common_ptr); - - pass_counter : long; { work units completed in this pass } - pass_limit : long; { total number of work units in this pass } - completed_passes : int; { passes completed so far } - total_passes : int; { total number of passes expected } - end; - - -{ Data destination object for compression } - jpeg_destination_mgr_ptr = ^jpeg_destination_mgr; - jpeg_destination_mgr = record - next_output_byte : JOCTETptr; { => next byte to write in buffer } - free_in_buffer : size_t; { # of byte spaces remaining in buffer } - - init_destination : procedure (cinfo : j_compress_ptr); - empty_output_buffer : function (cinfo : j_compress_ptr) : boolean; - term_destination : procedure (cinfo : j_compress_ptr); - end; - - -{ Data source object for decompression } - - jpeg_source_mgr_ptr = ^jpeg_source_mgr; - jpeg_source_mgr = record - {const JOCTET * next_input_byte;} - next_input_byte : JOCTETptr; { => next byte to read from buffer } - bytes_in_buffer : size_t; { # of bytes remaining in buffer } - - init_source : procedure (cinfo : j_decompress_ptr); - fill_input_buffer : function (cinfo : j_decompress_ptr) : boolean; - skip_input_data : procedure (cinfo : j_decompress_ptr; num_bytes : long); - resync_to_restart : function (cinfo : j_decompress_ptr; - desired : int) : boolean; - term_source : procedure (cinfo : j_decompress_ptr); - end; - - -{ Memory manager object. - Allocates "small" objects (a few K total), "large" objects (tens of K), - and "really big" objects (virtual arrays with backing store if needed). - The memory manager does not allow individual objects to be freed; rather, - each created object is assigned to a pool, and whole pools can be freed - at once. This is faster and more convenient than remembering exactly what - to free, especially where malloc()/free() are not too speedy. - NB: alloc routines never return NIL. They exit to error_exit if not - successful. } - - - jpeg_memory_mgr = record - { Method pointers } - alloc_small : function (cinfo : j_common_ptr; pool_id : int; - sizeofobject : size_t) : pointer; - alloc_large : function (cinfo : j_common_ptr; pool_id : int; - sizeofobject : size_t) : pointer; {far} - alloc_sarray : function (cinfo : j_common_ptr; pool_id : int; - samplesperrow : JDIMENSION; - numrows : JDIMENSION) : JSAMPARRAY; - - alloc_barray : function (cinfo : j_common_ptr; pool_id : int; - blocksperrow : JDIMENSION; - numrows : JDIMENSION) : JBLOCKARRAY; - - request_virt_sarray : function(cinfo : j_common_ptr; - pool_id : int; - pre_zero : boolean; - samplesperrow : JDIMENSION; - numrows : JDIMENSION; - maxaccess : JDIMENSION) : jvirt_sarray_ptr; - - request_virt_barray : function(cinfo : j_common_ptr; - pool_id : int; - pre_zero : boolean; - blocksperrow : JDIMENSION; - numrows : JDIMENSION; - maxaccess : JDIMENSION) : jvirt_barray_ptr; - - realize_virt_arrays : procedure (cinfo : j_common_ptr); - - access_virt_sarray : function (cinfo : j_common_ptr; - ptr : jvirt_sarray_ptr; - start_row : JDIMENSION; - num_rows : JDIMENSION; - writable : boolean) : JSAMPARRAY; - - access_virt_barray : function (cinfo : j_common_ptr; - ptr : jvirt_barray_ptr; - start_row : JDIMENSION; - num_rows : JDIMENSION; - writable : boolean) : JBLOCKARRAY; - - free_pool : procedure (cinfo : j_common_ptr; pool_id : int); - self_destruct : procedure (cinfo : j_common_ptr); - - { Limit on memory allocation for this JPEG object. (Note that this is - merely advisory, not a guaranteed maximum; it only affects the space - used for virtual-array buffers.) May be changed by outer application - after creating the JPEG object. } - max_memory_to_use : long; - - { Maximum allocation request accepted by alloc_large. } - max_alloc_chunk : long; - end; - -{ Routines that are to be used by both halves of the library are declared - to receive a pointer to this structure. There are no actual instances of - jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.} - jpeg_common_struct = record - { Fields common to both master struct types } - err : jpeg_error_mgr_ptr; { Error handler module } - mem : jpeg_memory_mgr_ptr; { Memory manager module } - progress : jpeg_progress_mgr_ptr; { Progress monitor, or NIL if none } - client_data : voidp; { Available for use by application } - is_decompressor : boolean; { so common code can tell which is which } - global_state : int; { for checking call sequence validity } - - { Additional fields follow in an actual jpeg_compress_struct or - jpeg_decompress_struct. All three structs must agree on these - initial fields! (This would be a lot cleaner in C++.) } - end; - - -{ Master record for a compression instance } - - jpeg_compress_struct = record - { Fields shared with jpeg_decompress_struct } - err : jpeg_error_mgr_ptr; { Error handler module } - mem : jpeg_memory_mgr_ptr; { Memory manager module } - progress : jpeg_progress_mgr_ptr; { Progress monitor, or NIL if none } - client_data : voidp; { Available for use by application } - is_decompressor : boolean; { so common code can tell which is which } - global_state : int; { for checking call sequence validity } - - { Destination for compressed data } - dest : jpeg_destination_mgr_ptr; - - { Description of source image --- these fields must be filled in by - outer application before starting compression. in_color_space must - be correct before you can even call jpeg_set_defaults(). } - - - image_width : JDIMENSION; { input image width } - image_height : JDIMENSION; { input image height } - input_components : int; { # of color components in input image } - in_color_space : J_COLOR_SPACE; { colorspace of input image } - - input_gamma : double; { image gamma of input image } - - { Compression parameters --- these fields must be set before calling - jpeg_start_compress(). We recommend calling jpeg_set_defaults() to - initialize everything to reasonable defaults, then changing anything - the application specifically wants to change. That way you won't get - burnt when new parameters are added. Also note that there are several - helper routines to simplify changing parameters. } - - data_precision : int; { bits of precision in image data } - - num_components : int; { # of color components in JPEG image } - jpeg_color_space : J_COLOR_SPACE; { colorspace of JPEG image } - - comp_info : jpeg_component_info_list_ptr; - { comp_info^[i] describes component that appears i'th in SOF } - - quant_tbl_ptrs: Array[0..NUM_QUANT_TBLS-1] of JQUANT_TBL_PTR; - { ptrs to coefficient quantization tables, or NIL if not defined } - - dc_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR; - ac_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR; - { ptrs to Huffman coding tables, or NIL if not defined } - - arith_dc_L : Array[0..NUM_ARITH_TBLS-1] of UINT8; { L values for DC arith-coding tables } - arith_dc_U : Array[0..NUM_ARITH_TBLS-1] of UINT8; { U values for DC arith-coding tables } - arith_ac_K : Array[0..NUM_ARITH_TBLS-1] of UINT8; { Kx values for AC arith-coding tables } - - num_scans : int; { # of entries in scan_info array } - scan_info : jpeg_scan_info_ptr; { script for multi-scan file, or NIL } - { The default value of scan_info is NIL, which causes a single-scan - sequential JPEG file to be emitted. To create a multi-scan file, - set num_scans and scan_info to point to an array of scan definitions. } - - raw_data_in : boolean; { TRUE=caller supplies downsampled data } - arith_code : boolean; { TRUE=arithmetic coding, FALSE=Huffman } - optimize_coding : boolean; { TRUE=optimize entropy encoding parms } - CCIR601_sampling : boolean; { TRUE=first samples are cosited } - smoothing_factor : int; { 1..100, or 0 for no input smoothing } - dct_method : J_DCT_METHOD; { DCT algorithm selector } - - { The restart interval can be specified in absolute MCUs by setting - restart_interval, or in MCU rows by setting restart_in_rows - (in which case the correct restart_interval will be figured - for each scan). } - - restart_interval : uint; { MCUs per restart, or 0 for no restart } - restart_in_rows : int; { if > 0, MCU rows per restart interval } - - { Parameters controlling emission of special markers. } - - write_JFIF_header : boolean; { should a JFIF marker be written? } - JFIF_major_version : UINT8; { What to write for the JFIF version number } - JFIF_minor_version : UINT8; - { These three values are not used by the JPEG code, merely copied } - { into the JFIF APP0 marker. density_unit can be 0 for unknown, } - { 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect } - { ratio is defined by X_density/Y_density even when density_unit=0. } - density_unit : UINT8; { JFIF code for pixel size units } - X_density : UINT16; { Horizontal pixel density } - Y_density : UINT16; { Vertical pixel density } - write_Adobe_marker : boolean; { should an Adobe marker be written? } - - { State variable: index of next scanline to be written to - jpeg_write_scanlines(). Application may use this to control its - processing loop, e.g., "while (next_scanline < image_height)". } - - next_scanline : JDIMENSION; { 0 .. image_height-1 } - - { Remaining fields are known throughout compressor, but generally - should not be touched by a surrounding application. } - - { These fields are computed during compression startup } - progressive_mode : boolean; { TRUE if scan script uses progressive mode } - max_h_samp_factor : int; { largest h_samp_factor } - max_v_samp_factor : int; { largest v_samp_factor } - - total_iMCU_rows : JDIMENSION; { # of iMCU rows to be input to coef ctlr } - { The coefficient controller receives data in units of MCU rows as defined - for fully interleaved scans (whether the JPEG file is interleaved or not). - There are v_samp_factor * DCTSIZE sample rows of each component in an - "iMCU" (interleaved MCU) row. } - - { These fields are valid during any one scan. - They describe the components and MCUs actually appearing in the scan. } - - comps_in_scan : int; { # of JPEG components in this scan } - cur_comp_info : Array[0..MAX_COMPS_IN_SCAN-1] of jpeg_component_info_ptr; - { cur_comp_info[i]^ describes component that appears i'th in SOS } - - MCUs_per_row : JDIMENSION; { # of MCUs across the image } - MCU_rows_in_scan : JDIMENSION;{ # of MCU rows in the image } - - blocks_in_MCU : int; { # of DCT blocks per MCU } - MCU_membership : Array[0..C_MAX_BLOCKS_IN_MCU-1] of int; - { MCU_membership[i] is index in cur_comp_info of component owning } - { i'th block in an MCU } - - Ss, Se, Ah, Al : int; { progressive JPEG parameters for scan } - - { Links to compression subobjects (methods and private variables of modules) } - master : jpeg_comp_master_ptr; - main : jpeg_c_main_controller_ptr; - prep : jpeg_c_prep_controller_ptr; - coef : jpeg_c_coef_controller_ptr; - marker : jpeg_marker_writer_ptr; - cconvert : jpeg_color_converter_ptr; - downsample : jpeg_downsampler_ptr; - fdct : jpeg_forward_dct_ptr; - entropy : jpeg_entropy_encoder_ptr; - script_space : jpeg_scan_info_ptr; { workspace for jpeg_simple_progression } - script_space_size : int; - end; - - -{ Master record for a decompression instance } - - coef_bits_field = Array[0..DCTSIZE2-1] of int; - coef_bits_ptr = ^coef_bits_field; - coef_bits_ptrfield = Array[0..MAX_COMPS_IN_SCAN-1] of coef_bits_field; - coef_bits_ptrrow = ^coef_bits_ptrfield; - - range_limit_table = array[-(MAXJSAMPLE+1)..4*(MAXJSAMPLE+1) - + CENTERJSAMPLE -1] of JSAMPLE; - range_limit_table_ptr = ^range_limit_table; - - jpeg_decompress_struct = record - { Fields shared with jpeg_compress_struct } - err : jpeg_error_mgr_ptr; { Error handler module } - mem : jpeg_memory_mgr_ptr; { Memory manager module } - progress : jpeg_progress_mgr_ptr; { Progress monitor, or NIL if none } - client_data : voidp; { Available for use by application } - is_decompressor : boolean; { so common code can tell which is which } - global_state : int; { for checking call sequence validity } - - { Source of compressed data } - src : jpeg_source_mgr_ptr; - - { Basic description of image --- filled in by jpeg_read_header(). } - { Application may inspect these values to decide how to process image. } - - image_width : JDIMENSION; { nominal image width (from SOF marker) } - image_height : JDIMENSION; { nominal image height } - num_components : int; { # of color components in JPEG image } - jpeg_color_space : J_COLOR_SPACE; { colorspace of JPEG image } - - { Decompression processing parameters --- these fields must be set before - calling jpeg_start_decompress(). Note that jpeg_read_header() - initializes them to default values. } - - out_color_space : J_COLOR_SPACE; { colorspace for output } - - scale_num, scale_denom : uint ; { fraction by which to scale image } - - output_gamma : double; { image gamma wanted in output } - - buffered_image : boolean; { TRUE=multiple output passes } - raw_data_out : boolean; { TRUE=downsampled data wanted } - - dct_method : J_DCT_METHOD; { IDCT algorithm selector } - do_fancy_upsampling : boolean; { TRUE=apply fancy upsampling } - do_block_smoothing : boolean; { TRUE=apply interblock smoothing } - - quantize_colors : boolean; { TRUE=colormapped output wanted } - { the following are ignored if not quantize_colors: } - dither_mode : J_DITHER_MODE; { type of color dithering to use } - two_pass_quantize : boolean; { TRUE=use two-pass color quantization } - desired_number_of_colors : int; { max # colors to use in created colormap } - { these are significant only in buffered-image mode: } - enable_1pass_quant : boolean; { enable future use of 1-pass quantizer } - enable_external_quant : boolean; { enable future use of external colormap } - enable_2pass_quant : boolean; { enable future use of 2-pass quantizer } - - { Description of actual output image that will be returned to application. - These fields are computed by jpeg_start_decompress(). - You can also use jpeg_calc_output_dimensions() to determine these values - in advance of calling jpeg_start_decompress(). } - - output_width : JDIMENSION; { scaled image width } - output_height: JDIMENSION; { scaled image height } - out_color_components : int; { # of color components in out_color_space } - output_components : int; { # of color components returned } - { output_components is 1 (a colormap index) when quantizing colors; - otherwise it equals out_color_components. } - - rec_outbuf_height : int; { min recommended height of scanline buffer } - { If the buffer passed to jpeg_read_scanlines() is less than this many - rows high, space and time will be wasted due to unnecessary data - copying. Usually rec_outbuf_height will be 1 or 2, at most 4. } - - { When quantizing colors, the output colormap is described by these - fields. The application can supply a colormap by setting colormap - non-NIL before calling jpeg_start_decompress; otherwise a colormap - is created during jpeg_start_decompress or jpeg_start_output. The map - has out_color_components rows and actual_number_of_colors columns. } - - actual_number_of_colors : int; { number of entries in use } - colormap : JSAMPARRAY; { The color map as a 2-D pixel array } - - { State variables: these variables indicate the progress of decompression. - The application may examine these but must not modify them. } - - { Row index of next scanline to be read from jpeg_read_scanlines(). - Application may use this to control its processing loop, e.g., - "while (output_scanline < output_height)". } - - output_scanline : JDIMENSION; { 0 .. output_height-1 } - - { Current input scan number and number of iMCU rows completed in scan. - These indicate the progress of the decompressor input side. } - - input_scan_number : int; { Number of SOS markers seen so far } - input_iMCU_row : JDIMENSION; { Number of iMCU rows completed } - - { The "output scan number" is the notional scan being displayed by the - output side. The decompressor will not allow output scan/row number - to get ahead of input scan/row, but it can fall arbitrarily far behind.} - - output_scan_number : int; { Nominal scan number being displayed } - output_iMCU_row : int; { Number of iMCU rows read } - - { Current progression status. coef_bits[c][i] indicates the precision - with which component c's DCT coefficient i (in zigzag order) is known. - It is -1 when no data has yet been received, otherwise it is the point - transform (shift) value for the most recent scan of the coefficient - (thus, 0 at completion of the progression). - This pointer is NIL when reading a non-progressive file. } - - coef_bits : coef_bits_ptrrow; - { -1 or current Al value for each coef } - - { Internal JPEG parameters --- the application usually need not look at - these fields. Note that the decompressor output side may not use - any parameters that can change between scans. } - - { Quantization and Huffman tables are carried forward across input - datastreams when processing abbreviated JPEG datastreams. } - - quant_tbl_ptrs : Array[0..NUM_QUANT_TBLS-1] of JQUANT_TBL_PTR; - { ptrs to coefficient quantization tables, or NIL if not defined } - - dc_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR; - ac_huff_tbl_ptrs : Array[0..NUM_HUFF_TBLS-1] of JHUFF_TBL_PTR; - { ptrs to Huffman coding tables, or NIL if not defined } - - { These parameters are never carried across datastreams, since they - are given in SOF/SOS markers or defined to be reset by SOI. } - - data_precision : int; { bits of precision in image data } - - comp_info : jpeg_component_info_list_ptr; - { comp_info^[i] describes component that appears i'th in SOF } - - progressive_mode : boolean; { TRUE if SOFn specifies progressive mode } - arith_code : boolean; { TRUE=arithmetic coding, FALSE=Huffman } - - arith_dc_L : Array[0..NUM_ARITH_TBLS-1] of UINT8; { L values for DC arith-coding tables } - arith_dc_U : Array[0..NUM_ARITH_TBLS-1] of UINT8; { U values for DC arith-coding tables } - arith_ac_K : Array[0..NUM_ARITH_TBLS-1] of UINT8; { Kx values for AC arith-coding tables } - - restart_interval : uint; { MCUs per restart interval, or 0 for no restart } - - { These fields record data obtained from optional markers recognized by - the JPEG library. } - - saw_JFIF_marker : boolean; { TRUE iff a JFIF APP0 marker was found } - { Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: } - JFIF_major_version : UINT8; { JFIF version number } - JFIF_minor_version : UINT8; - density_unit : UINT8; { JFIF code for pixel size units } - X_density : UINT16; { Horizontal pixel density } - Y_density : UINT16; { Vertical pixel density } - saw_Adobe_marker : boolean; { TRUE iff an Adobe APP14 marker was found } - Adobe_transform : UINT8; { Color transform code from Adobe marker } - - CCIR601_sampling : boolean; { TRUE=first samples are cosited } - - { Aside from the specific data retained from APPn markers known to the - library, the uninterpreted contents of any or all APPn and COM markers - can be saved in a list for examination by the application. } - - marker_list : jpeg_saved_marker_ptr; { Head of list of saved markers } - - { Remaining fields are known throughout decompressor, but generally - should not be touched by a surrounding application. } - - - { These fields are computed during decompression startup } - - max_h_samp_factor : int; { largest h_samp_factor } - max_v_samp_factor : int; { largest v_samp_factor } - - min_DCT_scaled_size : int; { smallest DCT_scaled_size of any component } - - total_iMCU_rows : JDIMENSION; { # of iMCU rows in image } - { The coefficient controller's input and output progress is measured in - units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows - in fully interleaved JPEG scans, but are used whether the scan is - interleaved or not. We define an iMCU row as v_samp_factor DCT block - rows of each component. Therefore, the IDCT output contains - v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row.} - - sample_range_limit : range_limit_table_ptr; { table for fast range-limiting } - - - { These fields are valid during any one scan. - They describe the components and MCUs actually appearing in the scan. - Note that the decompressor output side must not use these fields. } - - comps_in_scan : int; { # of JPEG components in this scan } - cur_comp_info : Array[0..MAX_COMPS_IN_SCAN-1] of jpeg_component_info_ptr; - { cur_comp_info[i]^ describes component that appears i'th in SOS } - - MCUs_per_row : JDIMENSION; { # of MCUs across the image } - MCU_rows_in_scan : JDIMENSION; { # of MCU rows in the image } - - blocks_in_MCU : JDIMENSION; { # of DCT blocks per MCU } - MCU_membership : Array[0..D_MAX_BLOCKS_IN_MCU-1] of int; - { MCU_membership[i] is index in cur_comp_info of component owning } - { i'th block in an MCU } - - Ss, Se, Ah, Al : int; { progressive JPEG parameters for scan } - - { This field is shared between entropy decoder and marker parser. - It is either zero or the code of a JPEG marker that has been - read from the data source, but has not yet been processed. } - - unread_marker : int; - - { Links to decompression subobjects - (methods, private variables of modules) } - - master : jpeg_decomp_master_ptr; - main : jpeg_d_main_controller_ptr; - coef : jpeg_d_coef_controller_ptr; - post : jpeg_d_post_controller_ptr; - inputctl : jpeg_input_controller_ptr; - marker : jpeg_marker_reader_ptr; - entropy : jpeg_entropy_decoder_ptr; - idct : jpeg_inverse_dct_ptr; - upsample : jpeg_upsampler_ptr; - cconvert : jpeg_color_deconverter_ptr; - cquantize : jpeg_color_quantizer_ptr; - end; - -{ Decompression startup: read start of JPEG datastream to see what's there - function jpeg_read_header (cinfo : j_decompress_ptr; - require_image : boolean) : int; - Return value is one of: } -const - JPEG_SUSPENDED = 0; { Suspended due to lack of input data } - JPEG_HEADER_OK = 1; { Found valid image datastream } - JPEG_HEADER_TABLES_ONLY = 2; { Found valid table-specs-only datastream } -{ If you pass require_image = TRUE (normal case), you need not check for - a TABLES_ONLY return code; an abbreviated file will cause an error exit. - JPEG_SUSPENDED is only possible if you use a data source module that can - give a suspension return (the stdio source module doesn't). } - - -{ function jpeg_consume_input (cinfo : j_decompress_ptr) : int; - Return value is one of: } - - JPEG_REACHED_SOS = 1; { Reached start of new scan } - JPEG_REACHED_EOI = 2; { Reached end of image } - JPEG_ROW_COMPLETED = 3; { Completed one iMCU row } - JPEG_SCAN_COMPLETED = 4; { Completed last iMCU row of a scan } - - - - -implementation - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjquant1.pas b/3rd/Imaging/Source/JpegLib/imjquant1.pas deleted file mode 100644 index f15afa049..000000000 --- a/3rd/Imaging/Source/JpegLib/imjquant1.pas +++ /dev/null @@ -1,1009 +0,0 @@ -unit imjquant1; - -{ This file contains 1-pass color quantization (color mapping) routines. - These routines provide mapping to a fixed color map using equally spaced - color values. Optional Floyd-Steinberg or ordered dithering is available. } - -{ Original: jquant1.c; Copyright (C) 1991-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjpeglib; - -{GLOBAL} -procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr); - -implementation - -uses - imjmorecfg, - imjdeferr, - imjerror, - imjutils; - -{ The main purpose of 1-pass quantization is to provide a fast, if not very - high quality, colormapped output capability. A 2-pass quantizer usually - gives better visual quality; however, for quantized grayscale output this - quantizer is perfectly adequate. Dithering is highly recommended with this - quantizer, though you can turn it off if you really want to. - - In 1-pass quantization the colormap must be chosen in advance of seeing the - image. We use a map consisting of all combinations of Ncolors[i] color - values for the i'th component. The Ncolors[] values are chosen so that - their product, the total number of colors, is no more than that requested. - (In most cases, the product will be somewhat less.) - - Since the colormap is orthogonal, the representative value for each color - component can be determined without considering the other components; - then these indexes can be combined into a colormap index by a standard - N-dimensional-array-subscript calculation. Most of the arithmetic involved - can be precalculated and stored in the lookup table colorindex[]. - colorindex[i][j] maps pixel value j in component i to the nearest - representative value (grid plane) for that component; this index is - multiplied by the array stride for component i, so that the - index of the colormap entry closest to a given pixel value is just - sum( colorindex[component-number][pixel-component-value] ) - Aside from being fast, this scheme allows for variable spacing between - representative values with no additional lookup cost. - - If gamma correction has been applied in color conversion, it might be wise - to adjust the color grid spacing so that the representative colors are - equidistant in linear space. At this writing, gamma correction is not - implemented by jdcolor, so nothing is done here. } - - -{ Declarations for ordered dithering. - - We use a standard 16x16 ordered dither array. The basic concept of ordered - dithering is described in many references, for instance Dale Schumacher's - chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991). - In place of Schumacher's comparisons against a "threshold" value, we add a - "dither" value to the input pixel and then round the result to the nearest - output value. The dither value is equivalent to (0.5 - threshold) times - the distance between output values. For ordered dithering, we assume that - the output colors are equally spaced; if not, results will probably be - worse, since the dither may be too much or too little at a given point. - - The normal calculation would be to form pixel value + dither, range-limit - this to 0..MAXJSAMPLE, and then index into the colorindex table as usual. - We can skip the separate range-limiting step by extending the colorindex - table in both directions. } - - -const - ODITHER_SIZE = 16; { dimension of dither matrix } -{ NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break } - ODITHER_CELLS = (ODITHER_SIZE*ODITHER_SIZE); { # cells in matrix } - ODITHER_MASK = (ODITHER_SIZE-1); { mask for wrapping around counters } - -type - ODITHER_vector = Array[0..ODITHER_SIZE-1] of int; - ODITHER_MATRIX = Array[0..ODITHER_SIZE-1] of ODITHER_vector; - {ODITHER_MATRIX_PTR = ^array[0..ODITHER_SIZE-1] of int;} - ODITHER_MATRIX_PTR = ^ODITHER_MATRIX; - -const - base_dither_matrix : Array[0..ODITHER_SIZE-1,0..ODITHER_SIZE-1] of UINT8 - = ( - { Bayer's order-4 dither array. Generated by the code given in - Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. - The values in this array must range from 0 to ODITHER_CELLS-1. } - - ( 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 ), - ( 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 ), - ( 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 ), - ( 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 ), - ( 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 ), - ( 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 ), - ( 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 ), - ( 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 ), - ( 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 ), - ( 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 ), - ( 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 ), - ( 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 ), - ( 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 ), - ( 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 ), - ( 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 ), - ( 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 ) - ); - - -{ Declarations for Floyd-Steinberg dithering. - - Errors are accumulated into the array fserrors[], at a resolution of - 1/16th of a pixel count. The error at a given pixel is propagated - to its not-yet-processed neighbors using the standard F-S fractions, - ... (here) 7/16 - 3/16 5/16 1/16 - We work left-to-right on even rows, right-to-left on odd rows. - - We can get away with a single array (holding one row's worth of errors) - by using it to store the current row's errors at pixel columns not yet - processed, but the next row's errors at columns already processed. We - need only a few extra variables to hold the errors immediately around the - current column. (If we are lucky, those variables are in registers, but - even if not, they're probably cheaper to access than array elements are.) - - The fserrors[] array is indexed [component#][position]. - We provide (#columns + 2) entries per component; the extra entry at each - end saves us from special-casing the first and last pixels. - - Note: on a wide image, we might not have enough room in a PC's near data - segment to hold the error array; so it is allocated with alloc_large. } - -{$ifdef BITS_IN_JSAMPLE_IS_8} -type - FSERROR = INT16; { 16 bits should be enough } - LOCFSERROR = int; { use 'int' for calculation temps } -{$else} -type - FSERROR = INT32; { may need more than 16 bits } - LOCFSERROR = INT32; { be sure calculation temps are big enough } -{$endif} - -type - jFSError = 0..(MaxInt div SIZEOF(FSERROR))-1; - FS_ERROR_FIELD = array[jFSError] of FSERROR; - FS_ERROR_FIELD_PTR = ^FS_ERROR_FIELD;{far} - { pointer to error array (in FAR storage!) } - FSERRORPTR = ^FSERROR; - - -{ Private subobject } - -const - MAX_Q_COMPS = 4; { max components I can handle } - -type - my_cquantize_ptr = ^my_cquantizer; - my_cquantizer = record - pub : jpeg_color_quantizer; { public fields } - - { Initially allocated colormap is saved here } - sv_colormap : JSAMPARRAY; { The color map as a 2-D pixel array } - sv_actual : int; { number of entries in use } - - colorindex : JSAMPARRAY; { Precomputed mapping for speed } - { colorindex[i][j] = index of color closest to pixel value j in component i, - premultiplied as described above. Since colormap indexes must fit into - JSAMPLEs, the entries of this array will too. } - - is_padded : boolean; { is the colorindex padded for odither? } - - Ncolors : array[0..MAX_Q_COMPS-1] of int; - { # of values alloced to each component } - - { Variables for ordered dithering } - row_index : int; { cur row's vertical index in dither matrix } - odither : array[0..MAX_Q_COMPS-1] of ODITHER_MATRIX_PTR; - { one dither array per component } - { Variables for Floyd-Steinberg dithering } - fserrors : array[0..MAX_Q_COMPS-1] of FS_ERROR_FIELD_PTR; - { accumulated errors } - on_odd_row : boolean; { flag to remember which row we are on } - end; - - -{ Policy-making subroutines for create_colormap and create_colorindex. - These routines determine the colormap to be used. The rest of the module - only assumes that the colormap is orthogonal. - - * select_ncolors decides how to divvy up the available colors - among the components. - * output_value defines the set of representative values for a component. - * largest_input_value defines the mapping from input values to - representative values for a component. - Note that the latter two routines may impose different policies for - different components, though this is not currently done. } - - - -{LOCAL} -function select_ncolors (cinfo : j_decompress_ptr; - var Ncolors : array of int) : int; -{ Determine allocation of desired colors to components, } -{ and fill in Ncolors[] array to indicate choice. } -{ Return value is total number of colors (product of Ncolors[] values). } -var - nc : int; - max_colors : int; - total_colors, iroot, i, j : int; - changed : boolean; - temp : long; -const - RGB_order:array[0..2] of int = (RGB_GREEN, RGB_RED, RGB_BLUE); -begin - nc := cinfo^.out_color_components; { number of color components } - max_colors := cinfo^.desired_number_of_colors; - - { We can allocate at least the nc'th root of max_colors per component. } - { Compute floor(nc'th root of max_colors). } - iroot := 1; - repeat - Inc(iroot); - temp := iroot; { set temp = iroot ** nc } - for i := 1 to pred(nc) do - temp := temp * iroot; - until (temp > long(max_colors)); { repeat till iroot exceeds root } - Dec(iroot); { now iroot = floor(root) } - - { Must have at least 2 color values per component } - if (iroot < 2) then - ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_FEW_COLORS, int(temp)); - - { Initialize to iroot color values for each component } - total_colors := 1; - for i := 0 to pred(nc) do - begin - Ncolors[i] := iroot; - total_colors := total_colors * iroot; - end; - - { We may be able to increment the count for one or more components without - exceeding max_colors, though we know not all can be incremented. - Sometimes, the first component can be incremented more than once! - (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.) - In RGB colorspace, try to increment G first, then R, then B. } - - repeat - changed := FALSE; - for i := 0 to pred(nc) do - begin - if cinfo^.out_color_space = JCS_RGB then - j := RGB_order[i] - else - j := i; - { calculate new total_colors if Ncolors[j] is incremented } - temp := total_colors div Ncolors[j]; - temp := temp * (Ncolors[j]+1); { done in long arith to avoid oflo } - if (temp > long(max_colors)) then - break; { won't fit, done with this pass } - Inc(Ncolors[j]); { OK, apply the increment } - total_colors := int(temp); - changed := TRUE; - end; - until not changed; - - select_ncolors := total_colors; -end; - - -{LOCAL} -function output_value (cinfo : j_decompress_ptr; - ci : int; j : int; maxj : int) : int; -{ Return j'th output value, where j will range from 0 to maxj } -{ The output values must fall in 0..MAXJSAMPLE in increasing order } -begin - { We always provide values 0 and MAXJSAMPLE for each component; - any additional values are equally spaced between these limits. - (Forcing the upper and lower values to the limits ensures that - dithering can't produce a color outside the selected gamut.) } - - output_value := int (( INT32(j) * MAXJSAMPLE + maxj div 2) div maxj); -end; - - -{LOCAL} -function largest_input_value (cinfo : j_decompress_ptr; - ci : int; j : int; maxj : int) : int; -{ Return largest input value that should map to j'th output value } -{ Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE } -begin - { Breakpoints are halfway between values returned by output_value } - largest_input_value := int (( INT32(2*j + 1) * MAXJSAMPLE + - maxj) div (2*maxj)); -end; - - -{ Create the colormap. } - -{LOCAL} -procedure create_colormap (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; - colormap : JSAMPARRAY; { Created colormap } - - total_colors : int; { Number of distinct output colors } - i,j,k, nci, blksize, blkdist, ptr, val : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - - { Select number of colors for each component } - total_colors := select_ncolors(cinfo, cquantize^.Ncolors); - - { Report selected color counts } - {$IFDEF DEBUG} - if (cinfo^.out_color_components = 3) then - TRACEMS4(j_common_ptr(cinfo), 1, JTRC_QUANT_3_NCOLORS, - total_colors, cquantize^.Ncolors[0], - cquantize^.Ncolors[1], cquantize^.Ncolors[2]) - else - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_QUANT_NCOLORS, total_colors); - {$ENDIF} - - { Allocate and fill in the colormap. } - { The colors are ordered in the map in standard row-major order, } - { i.e. rightmost (highest-indexed) color changes most rapidly. } - - colormap := cinfo^.mem^.alloc_sarray( - j_common_ptr(cinfo), JPOOL_IMAGE, - JDIMENSION(total_colors), JDIMENSION(cinfo^.out_color_components)); - - { blksize is number of adjacent repeated entries for a component } - { blkdist is distance between groups of identical entries for a component } - blkdist := total_colors; - - for i := 0 to pred(cinfo^.out_color_components) do - begin - { fill in colormap entries for i'th color component } - nci := cquantize^.Ncolors[i]; { # of distinct values for this color } - blksize := blkdist div nci; - for j := 0 to pred(nci) do - begin - { Compute j'th output value (out of nci) for component } - val := output_value(cinfo, i, j, nci-1); - { Fill in all colormap entries that have this value of this component } - ptr := j * blksize; - while (ptr < total_colors) do - begin - { fill in blksize entries beginning at ptr } - for k := 0 to pred(blksize) do - colormap^[i]^[ptr+k] := JSAMPLE(val); - - Inc(ptr, blkdist); - end; - end; - blkdist := blksize; { blksize of this color is blkdist of next } - end; - - { Save the colormap in private storage, - where it will survive color quantization mode changes. } - - cquantize^.sv_colormap := colormap; - cquantize^.sv_actual := total_colors; -end; - -{ Create the color index table. } - -{LOCAL} -procedure create_colorindex (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; - indexptr, - help_indexptr : JSAMPROW; { for negative offsets } - i,j,k, nci, blksize, val, pad : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - { For ordered dither, we pad the color index tables by MAXJSAMPLE in - each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE). - This is not necessary in the other dithering modes. However, we - flag whether it was done in case user changes dithering mode. } - - if (cinfo^.dither_mode = JDITHER_ORDERED) then - begin - pad := MAXJSAMPLE*2; - cquantize^.is_padded := TRUE; - end - else - begin - pad := 0; - cquantize^.is_padded := FALSE; - end; - - cquantize^.colorindex := cinfo^.mem^.alloc_sarray - (j_common_ptr(cinfo), JPOOL_IMAGE, - JDIMENSION(MAXJSAMPLE+1 + pad), - JDIMENSION(cinfo^.out_color_components)); - - { blksize is number of adjacent repeated entries for a component } - blksize := cquantize^.sv_actual; - - for i := 0 to pred(cinfo^.out_color_components) do - begin - { fill in colorindex entries for i'th color component } - nci := cquantize^.Ncolors[i]; { # of distinct values for this color } - blksize := blksize div nci; - - { adjust colorindex pointers to provide padding at negative indexes. } - if (pad <> 0) then - Inc(JSAMPLE_PTR(cquantize^.colorindex^[i]), MAXJSAMPLE); - - { in loop, val = index of current output value, } - { and k = largest j that maps to current val } - indexptr := cquantize^.colorindex^[i]; - val := 0; - k := largest_input_value(cinfo, i, 0, nci-1); - for j := 0 to MAXJSAMPLE do - begin - while (j > k) do { advance val if past boundary } - begin - Inc(val); - k := largest_input_value(cinfo, i, val, nci-1); - end; - { premultiply so that no multiplication needed in main processing } - indexptr^[j] := JSAMPLE (val * blksize); - end; - { Pad at both ends if necessary } - if (pad <> 0) then - begin - help_indexptr := indexptr; - { adjust the help pointer to avoid negative offsets } - Dec(JSAMPLE_PTR(help_indexptr), MAXJSAMPLE); - - for j := 1 to MAXJSAMPLE do - begin - {indexptr^[-j] := indexptr^[0];} - help_indexptr^[MAXJSAMPLE-j] := indexptr^[0]; - indexptr^[MAXJSAMPLE+j] := indexptr^[MAXJSAMPLE]; - end; - end; - end; -end; - - -{ Create an ordered-dither array for a component having ncolors - distinct output values. } - -{LOCAL} -function make_odither_array (cinfo : j_decompress_ptr; - ncolors : int) : ODITHER_MATRIX_PTR; -var - odither : ODITHER_MATRIX_PTR; - j, k : int; - num, den : INT32; -begin - odither := ODITHER_MATRIX_PTR ( - cinfo^.mem^.alloc_small(j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(ODITHER_MATRIX))); - { The inter-value distance for this color is MAXJSAMPLE/(ncolors-1). - Hence the dither value for the matrix cell with fill order f - (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1). - On 16-bit-int machine, be careful to avoid overflow. } - - den := 2 * ODITHER_CELLS * ( INT32(ncolors - 1)); - for j := 0 to pred(ODITHER_SIZE) do - begin - for k := 0 to pred(ODITHER_SIZE) do - begin - num := ( INT32(ODITHER_CELLS-1 - 2*( int(base_dither_matrix[j][k])))) - * MAXJSAMPLE; - { Ensure round towards zero despite C's lack of consistency - about rounding negative values in integer division... } - - if num<0 then - odither^[j][k] := int (-((-num) div den)) - else - odither^[j][k] := int (num div den); - end; - end; - make_odither_array := odither; -end; - - -{ Create the ordered-dither tables. - Components having the same number of representative colors may - share a dither table. } - -{LOCAL} -procedure create_odither_tables (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; - odither : ODITHER_MATRIX_PTR; - i, j, nci : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - - for i := 0 to pred(cinfo^.out_color_components) do - begin - nci := cquantize^.Ncolors[i]; { # of distinct values for this color } - odither := NIL; { search for matching prior component } - for j := 0 to pred(i) do - begin - if (nci = cquantize^.Ncolors[j]) then - begin - odither := cquantize^.odither[j]; - break; - end; - end; - if (odither = NIL) then { need a new table? } - odither := make_odither_array(cinfo, nci); - cquantize^.odither[i] := odither; - end; -end; - - -{ Map some rows of pixels to the output colormapped representation. } - -{METHODDEF} -procedure color_quantize (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ General case, no dithering } -var - cquantize : my_cquantize_ptr; - colorindex : JSAMPARRAY; - pixcode, ci : int; {register} - ptrin, ptrout : JSAMPLE_PTR; {register} - row : int; - col : JDIMENSION; - width : JDIMENSION; - nc : int; {register} -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - colorindex := cquantize^.colorindex; - width := cinfo^.output_width; - nc := cinfo^.out_color_components; - - for row := 0 to pred(num_rows) do - begin - ptrin := JSAMPLE_PTR(input_buf^[row]); - ptrout := JSAMPLE_PTR(output_buf^[row]); - for col := pred(width) downto 0 do - begin - pixcode := 0; - for ci := 0 to pred(nc) do - begin - Inc(pixcode, GETJSAMPLE(colorindex^[ci]^[GETJSAMPLE(ptrin^)]) ); - Inc(ptrin); - end; - ptrout^ := JSAMPLE (pixcode); - Inc(ptrout); - end; - end; -end; - - -{METHODDEF} -procedure color_quantize3 (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ Fast path for out_color_components=3, no dithering } -var - cquantize : my_cquantize_ptr; - pixcode : int; {register} - ptrin, ptrout : JSAMPLE_PTR; {register} - colorindex0 : JSAMPROW; - colorindex1 : JSAMPROW; - colorindex2 : JSAMPROW; - row : int; - col : JDIMENSION; - width : JDIMENSION; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - colorindex0 := (cquantize^.colorindex)^[0]; - colorindex1 := (cquantize^.colorindex)^[1]; - colorindex2 := (cquantize^.colorindex)^[2]; - width := cinfo^.output_width; - - for row := 0 to pred(num_rows) do - begin - ptrin := JSAMPLE_PTR(input_buf^[row]); - ptrout := JSAMPLE_PTR(output_buf^[row]); - for col := pred(width) downto 0 do - begin - pixcode := GETJSAMPLE((colorindex0)^[GETJSAMPLE(ptrin^)]); - Inc(ptrin); - Inc( pixcode, GETJSAMPLE((colorindex1)^[GETJSAMPLE(ptrin^)]) ); - Inc(ptrin); - Inc( pixcode, GETJSAMPLE((colorindex2)^[GETJSAMPLE(ptrin^)]) ); - Inc(ptrin); - ptrout^ := JSAMPLE (pixcode); - Inc(ptrout); - end; - end; -end; - - -{METHODDEF} -procedure quantize_ord_dither (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ General case, with ordered dithering } -var - cquantize : my_cquantize_ptr; - input_ptr, {register} - output_ptr : JSAMPLE_PTR; {register} - colorindex_ci : JSAMPROW; - dither : ^ODITHER_vector; { points to active row of dither matrix } - row_index, col_index : int; { current indexes into dither matrix } - nc : int; - ci : int; - row : int; - col : JDIMENSION; - width : JDIMENSION; -var - pad_offset : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - nc := cinfo^.out_color_components; - width := cinfo^.output_width; - - { Nomssi: work around negative offset } - if my_cquantize_ptr (cinfo^.cquantize)^.is_padded then - pad_offset := MAXJSAMPLE - else - pad_offset := 0; - - for row := 0 to pred(num_rows) do - begin - { Initialize output values to 0 so can process components separately } - jzero_far( {far} pointer(output_buf^[row]), - size_t(width * SIZEOF(JSAMPLE))); - row_index := cquantize^.row_index; - for ci := 0 to pred(nc) do - begin - input_ptr := JSAMPLE_PTR(@ input_buf^[row]^[ci]); - output_ptr := JSAMPLE_PTR(output_buf^[row]); - colorindex_ci := cquantize^.colorindex^[ci]; - { Nomssi } - Dec(JSAMPLE_PTR(colorindex_ci), pad_offset); - - dither := @(cquantize^.odither[ci]^[row_index]); - col_index := 0; - - for col := pred(width) downto 0 do - begin - { Form pixel value + dither, range-limit to 0..MAXJSAMPLE, - select output value, accumulate into output code for this pixel. - Range-limiting need not be done explicitly, as we have extended - the colorindex table to produce the right answers for out-of-range - inputs. The maximum dither is +- MAXJSAMPLE; this sets the - required amount of padding. } - - Inc(output_ptr^, - colorindex_ci^[GETJSAMPLE(input_ptr^)+ pad_offset + - dither^[col_index]]); - Inc(output_ptr); - Inc(input_ptr, nc); - col_index := (col_index + 1) and ODITHER_MASK; - end; - end; - { Advance row index for next row } - row_index := (row_index + 1) and ODITHER_MASK; - cquantize^.row_index := row_index; - end; -end; - -{METHODDEF} -procedure quantize3_ord_dither (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ Fast path for out_color_components=3, with ordered dithering } -var - cquantize : my_cquantize_ptr; - pixcode : int; {register} - input_ptr : JSAMPLE_PTR; {register} - output_ptr : JSAMPLE_PTR; {register} - colorindex0 : JSAMPROW; - colorindex1 : JSAMPROW; - colorindex2 : JSAMPROW; - dither0 : ^ODITHER_vector; { points to active row of dither matrix } - dither1 : ^ODITHER_vector; - dither2 : ^ODITHER_vector; - row_index, col_index : int; { current indexes into dither matrix } - row : int; - col : JDIMENSION; - width : JDIMENSION; -var - pad_offset : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - colorindex0 := (cquantize^.colorindex)^[0]; - colorindex1 := (cquantize^.colorindex)^[1]; - colorindex2 := (cquantize^.colorindex)^[2]; - width := cinfo^.output_width; - - { Nomssi: work around negative offset } - if my_cquantize_ptr (cinfo^.cquantize)^.is_padded then - pad_offset := MAXJSAMPLE - else - pad_offset := 0; - - Dec(JSAMPLE_PTR(colorindex0), pad_offset); - Dec(JSAMPLE_PTR(colorindex1), pad_offset); - Dec(JSAMPLE_PTR(colorindex2), pad_offset); - - for row := 0 to pred(num_rows) do - begin - row_index := cquantize^.row_index; - input_ptr := JSAMPLE_PTR(input_buf^[row]); - output_ptr := JSAMPLE_PTR(output_buf^[row]); - dither0 := @(cquantize^.odither[0]^[row_index]); - dither1 := @(cquantize^.odither[1]^[row_index]); - dither2 := @(cquantize^.odither[2]^[row_index]); - col_index := 0; - - - for col := pred(width) downto 0 do - begin - pixcode := GETJSAMPLE(colorindex0^[GETJSAMPLE(input_ptr^) + pad_offset - + dither0^[col_index]]); - Inc(input_ptr); - Inc(pixcode, GETJSAMPLE(colorindex1^[GETJSAMPLE(input_ptr^) + pad_offset - + dither1^[col_index]])); - Inc(input_ptr); - Inc(pixcode, GETJSAMPLE(colorindex2^[GETJSAMPLE(input_ptr^) + pad_offset - + dither2^[col_index]])); - Inc(input_ptr); - output_ptr^ := JSAMPLE (pixcode); - Inc(output_ptr); - col_index := (col_index + 1) and ODITHER_MASK; - end; - row_index := (row_index + 1) and ODITHER_MASK; - cquantize^.row_index := row_index; - end; -end; - - -{METHODDEF} -procedure quantize_fs_dither (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ General case, with Floyd-Steinberg dithering } -var - cquantize : my_cquantize_ptr; - cur : LOCFSERROR; {register} { current error or pixel value } - belowerr : LOCFSERROR; { error for pixel below cur } - bpreverr : LOCFSERROR; { error for below/prev col } - bnexterr : LOCFSERROR; { error for below/next col } - delta : LOCFSERROR; - prev_errorptr, - errorptr : FSERRORPTR; {register} { => fserrors[] at column before current } - input_ptr, {register} - output_ptr : JSAMPLE_PTR; {register} - colorindex_ci : JSAMPROW; - colormap_ci : JSAMPROW; - pixcode : int; - nc : int; - dir : int; { 1 for left-to-right, -1 for right-to-left } - dirnc : int; { dir * nc } - ci : int; - row : int; - col : JDIMENSION; - width : JDIMENSION; - range_limit : range_limit_table_ptr; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - nc := cinfo^.out_color_components; - width := cinfo^.output_width; - range_limit := cinfo^.sample_range_limit; - - for row := 0 to pred(num_rows) do - begin - { Initialize output values to 0 so can process components separately } - jzero_far( (output_buf)^[row], - size_t(width * SIZEOF(JSAMPLE))); - for ci := 0 to pred(nc) do - begin - input_ptr := JSAMPLE_PTR(@ input_buf^[row]^[ci]); - output_ptr := JSAMPLE_PTR(output_buf^[row]); - errorptr := FSERRORPTR(cquantize^.fserrors[ci]); { => entry before first column } - if (cquantize^.on_odd_row) then - begin - { work right to left in this row } - Inc(input_ptr, (width-1) * JDIMENSION(nc)); { so point to rightmost pixel } - Inc(output_ptr, width-1); - dir := -1; - dirnc := -nc; - Inc(errorptr, (width+1)); { => entry after last column } - end - else - begin - { work left to right in this row } - dir := 1; - dirnc := nc; - {errorptr := cquantize^.fserrors[ci];} - end; - - colorindex_ci := cquantize^.colorindex^[ci]; - - colormap_ci := (cquantize^.sv_colormap)^[ci]; - { Preset error values: no error propagated to first pixel from left } - cur := 0; - { and no error propagated to row below yet } - belowerr := 0; - bpreverr := 0; - - for col := pred(width) downto 0 do - begin - prev_errorptr := errorptr; - Inc(errorptr, dir); { advance errorptr to current column } - - { cur holds the error propagated from the previous pixel on the - current line. Add the error propagated from the previous line - to form the complete error correction term for this pixel, and - round the error term (which is expressed * 16) to an integer. - RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - for either sign of the error value. - Note: errorptr points to *previous* column's array entry. } - - cur := (cur + errorptr^ + 8) div 16; - - { Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - The maximum error is +- MAXJSAMPLE; this sets the required size - of the range_limit array. } - - Inc( cur, GETJSAMPLE(input_ptr^)); - cur := GETJSAMPLE(range_limit^[cur]); - { Select output value, accumulate into output code for this pixel } - pixcode := GETJSAMPLE(colorindex_ci^[cur]); - Inc(output_ptr^, JSAMPLE (pixcode)); - { Compute actual representation error at this pixel } - { Note: we can do this even though we don't have the final } - { pixel code, because the colormap is orthogonal. } - Dec(cur, GETJSAMPLE(colormap_ci^[pixcode])); - { Compute error fractions to be propagated to adjacent pixels. - Add these into the running sums, and simultaneously shift the - next-line error sums left by 1 column. } - - bnexterr := cur; - delta := cur * 2; - Inc(cur, delta); { form error * 3 } - prev_errorptr^ := FSERROR (bpreverr + cur); - Inc(cur, delta); { form error * 5 } - bpreverr := belowerr + cur; - belowerr := bnexterr; - Inc(cur, delta); { form error * 7 } - { At this point cur contains the 7/16 error value to be propagated - to the next pixel on the current line, and all the errors for the - next line have been shifted over. We are therefore ready to move on. } - - Inc(input_ptr, dirnc); { advance input ptr to next column } - Inc(output_ptr, dir); { advance output ptr to next column } - - end; - { Post-loop cleanup: we must unload the final error value into the - final fserrors[] entry. Note we need not unload belowerr because - it is for the dummy column before or after the actual array. } - - errorptr^ := FSERROR (bpreverr); { unload prev err into array } - { Nomssi : ?? } - end; - cquantize^.on_odd_row := not cquantize^.on_odd_row; - end; -end; - - -{ Allocate workspace for Floyd-Steinberg errors. } - -{LOCAL} -procedure alloc_fs_workspace (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; - arraysize : size_t; - i : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - arraysize := size_t ((cinfo^.output_width + 2) * SIZEOF(FSERROR)); - for i := 0 to pred(cinfo^.out_color_components) do - begin - cquantize^.fserrors[i] := FS_ERROR_FIELD_PTR( - cinfo^.mem^.alloc_large(j_common_ptr(cinfo), JPOOL_IMAGE, arraysize)); - end; -end; - - -{ Initialize for one-pass color quantization. } - -{METHODDEF} -procedure start_pass_1_quant (cinfo : j_decompress_ptr; - is_pre_scan : boolean); -var - cquantize : my_cquantize_ptr; - arraysize : size_t; - i : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - { Install my colormap. } - cinfo^.colormap := cquantize^.sv_colormap; - cinfo^.actual_number_of_colors := cquantize^.sv_actual; - - { Initialize for desired dithering mode. } - case (cinfo^.dither_mode) of - JDITHER_NONE: - if (cinfo^.out_color_components = 3) then - cquantize^.pub.color_quantize := color_quantize3 - else - cquantize^.pub.color_quantize := color_quantize; - JDITHER_ORDERED: - begin - if (cinfo^.out_color_components = 3) then - cquantize^.pub.color_quantize := quantize3_ord_dither - else - cquantize^.pub.color_quantize := quantize_ord_dither; - cquantize^.row_index := 0; { initialize state for ordered dither } - { If user changed to ordered dither from another mode, - we must recreate the color index table with padding. - This will cost extra space, but probably isn't very likely. } - - if (not cquantize^.is_padded) then - create_colorindex(cinfo); - { Create ordered-dither tables if we didn't already. } - if (cquantize^.odither[0] = NIL) then - create_odither_tables(cinfo); - end; - JDITHER_FS: - begin - cquantize^.pub.color_quantize := quantize_fs_dither; - cquantize^.on_odd_row := FALSE; { initialize state for F-S dither } - { Allocate Floyd-Steinberg workspace if didn't already. } - if (cquantize^.fserrors[0] = NIL) then - alloc_fs_workspace(cinfo); - { Initialize the propagated errors to zero. } - arraysize := size_t ((cinfo^.output_width + 2) * SIZEOF(FSERROR)); - for i := 0 to pred(cinfo^.out_color_components) do - jzero_far({far} pointer( cquantize^.fserrors[i] ), arraysize); - end; - else - ERREXIT(j_common_ptr(cinfo), JERR_NOT_COMPILED); - end; -end; - - -{ Finish up at the end of the pass. } - -{METHODDEF} -procedure finish_pass_1_quant (cinfo : j_decompress_ptr); -begin - { no work in 1-pass case } -end; - - -{ Switch to a new external colormap between output passes. - Shouldn't get to this module! } - -{METHODDEF} -procedure new_color_map_1_quant (cinfo : j_decompress_ptr); -begin - ERREXIT(j_common_ptr(cinfo), JERR_MODE_CHANGE); -end; - - -{ Module initialization routine for 1-pass color quantization. } - -{GLOBAL} -procedure jinit_1pass_quantizer (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; -begin - cquantize := my_cquantize_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_cquantizer))); - cinfo^.cquantize := jpeg_color_quantizer_ptr(cquantize); - cquantize^.pub.start_pass := start_pass_1_quant; - cquantize^.pub.finish_pass := finish_pass_1_quant; - cquantize^.pub.new_color_map := new_color_map_1_quant; - cquantize^.fserrors[0] := NIL; { Flag FS workspace not allocated } - cquantize^.odither[0] := NIL; { Also flag odither arrays not allocated } - - { Make sure my internal arrays won't overflow } - if (cinfo^.out_color_components > MAX_Q_COMPS) then - ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_COMPONENTS, MAX_Q_COMPS); - { Make sure colormap indexes can be represented by JSAMPLEs } - if (cinfo^.desired_number_of_colors > (MAXJSAMPLE+1)) then - ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1); - - { Create the colormap and color index table. } - create_colormap(cinfo); - create_colorindex(cinfo); - - { Allocate Floyd-Steinberg workspace now if requested. - We do this now since it is FAR storage and may affect the memory - manager's space calculations. If the user changes to FS dither - mode in a later pass, we will allocate the space then, and will - possibly overrun the max_memory_to_use setting. } - - if (cinfo^.dither_mode = JDITHER_FS) then - alloc_fs_workspace(cinfo); -end; - - -end. diff --git a/3rd/Imaging/Source/JpegLib/imjquant2.pas b/3rd/Imaging/Source/JpegLib/imjquant2.pas deleted file mode 100644 index a1e7a4402..000000000 --- a/3rd/Imaging/Source/JpegLib/imjquant2.pas +++ /dev/null @@ -1,1551 +0,0 @@ -unit imjquant2; - - -{ This file contains 2-pass color quantization (color mapping) routines. - These routines provide selection of a custom color map for an image, - followed by mapping of the image to that color map, with optional - Floyd-Steinberg dithering. - It is also possible to use just the second pass to map to an arbitrary - externally-given color map. - - Note: ordered dithering is not supported, since there isn't any fast - way to compute intercolor distances; it's unclear that ordered dither's - fundamental assumptions even hold with an irregularly spaced color map. } - -{ Original: jquant2.c; Copyright (C) 1991-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjdeferr, - imjerror, - imjutils, - imjpeglib; - -{ Module initialization routine for 2-pass color quantization. } - - -{GLOBAL} -procedure jinit_2pass_quantizer (cinfo : j_decompress_ptr); - -implementation - -{ This module implements the well-known Heckbert paradigm for color - quantization. Most of the ideas used here can be traced back to - Heckbert's seminal paper - Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", - Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. - - In the first pass over the image, we accumulate a histogram showing the - usage count of each possible color. To keep the histogram to a reasonable - size, we reduce the precision of the input; typical practice is to retain - 5 or 6 bits per color, so that 8 or 4 different input values are counted - in the same histogram cell. - - Next, the color-selection step begins with a box representing the whole - color space, and repeatedly splits the "largest" remaining box until we - have as many boxes as desired colors. Then the mean color in each - remaining box becomes one of the possible output colors. - - The second pass over the image maps each input pixel to the closest output - color (optionally after applying a Floyd-Steinberg dithering correction). - This mapping is logically trivial, but making it go fast enough requires - considerable care. - - Heckbert-style quantizers vary a good deal in their policies for choosing - the "largest" box and deciding where to cut it. The particular policies - used here have proved out well in experimental comparisons, but better ones - may yet be found. - - In earlier versions of the IJG code, this module quantized in YCbCr color - space, processing the raw upsampled data without a color conversion step. - This allowed the color conversion math to be done only once per colormap - entry, not once per pixel. However, that optimization precluded other - useful optimizations (such as merging color conversion with upsampling) - and it also interfered with desired capabilities such as quantizing to an - externally-supplied colormap. We have therefore abandoned that approach. - The present code works in the post-conversion color space, typically RGB. - - To improve the visual quality of the results, we actually work in scaled - RGB space, giving G distances more weight than R, and R in turn more than - B. To do everything in integer math, we must use integer scale factors. - The 2/3/1 scale factors used here correspond loosely to the relative - weights of the colors in the NTSC grayscale equation. - If you want to use this code to quantize a non-RGB color space, you'll - probably need to change these scale factors. } - -const - R_SCALE = 2; { scale R distances by this much } - G_SCALE = 3; { scale G distances by this much } - B_SCALE = 1; { and B by this much } - -{ Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined - in jmorecfg.h. As the code stands, it will do the right thing for R,G,B - and B,G,R orders. If you define some other weird order in jmorecfg.h, - you'll get compile errors until you extend this logic. In that case - you'll probably want to tweak the histogram sizes too. } - -{$ifdef RGB_RED_IS_0} -const - C0_SCALE = R_SCALE; - C1_SCALE = G_SCALE; - C2_SCALE = B_SCALE; -{$else} -const - C0_SCALE = B_SCALE; - C1_SCALE = G_SCALE; - C2_SCALE = R_SCALE; -{$endif} - - -{ First we have the histogram data structure and routines for creating it. - - The number of bits of precision can be adjusted by changing these symbols. - We recommend keeping 6 bits for G and 5 each for R and B. - If you have plenty of memory and cycles, 6 bits all around gives marginally - better results; if you are short of memory, 5 bits all around will save - some space but degrade the results. - To maintain a fully accurate histogram, we'd need to allocate a "long" - (preferably unsigned long) for each cell. In practice this is overkill; - we can get by with 16 bits per cell. Few of the cell counts will overflow, - and clamping those that do overflow to the maximum value will give close- - enough results. This reduces the recommended histogram size from 256Kb - to 128Kb, which is a useful savings on PC-class machines. - (In the second pass the histogram space is re-used for pixel mapping data; - in that capacity, each cell must be able to store zero to the number of - desired colors. 16 bits/cell is plenty for that too.) - Since the JPEG code is intended to run in small memory model on 80x86 - machines, we can't just allocate the histogram in one chunk. Instead - of a true 3-D array, we use a row of pointers to 2-D arrays. Each - pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and - each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that - on 80x86 machines, the pointer row is in near memory but the actual - arrays are in far memory (same arrangement as we use for image arrays). } - - -const - MAXNUMCOLORS = (MAXJSAMPLE+1); { maximum size of colormap } - -{ These will do the right thing for either R,G,B or B,G,R color order, - but you may not like the results for other color orders. } - -const - HIST_C0_BITS = 5; { bits of precision in R/B histogram } - HIST_C1_BITS = 6; { bits of precision in G histogram } - HIST_C2_BITS = 5; { bits of precision in B/R histogram } - -{ Number of elements along histogram axes. } -const - HIST_C0_ELEMS = (1 shl HIST_C0_BITS); - HIST_C1_ELEMS = (1 shl HIST_C1_BITS); - HIST_C2_ELEMS = (1 shl HIST_C2_BITS); - -{ These are the amounts to shift an input value to get a histogram index. } -const - C0_SHIFT = (BITS_IN_JSAMPLE-HIST_C0_BITS); - C1_SHIFT = (BITS_IN_JSAMPLE-HIST_C1_BITS); - C2_SHIFT = (BITS_IN_JSAMPLE-HIST_C2_BITS); - - -type { Nomssi } - RGBptr = ^RGBtype; - RGBtype = packed record - r,g,b : JSAMPLE; - end; -type - histcell = UINT16; { histogram cell; prefer an unsigned type } - -type - histptr = ^histcell {FAR}; { for pointers to histogram cells } - -type - hist1d = array[0..HIST_C2_ELEMS-1] of histcell; { typedefs for the array } - {hist1d_ptr = ^hist1d;} - hist1d_field = array[0..HIST_C1_ELEMS-1] of hist1d; - { type for the 2nd-level pointers } - hist2d = ^hist1d_field; - hist2d_field = array[0..HIST_C0_ELEMS-1] of hist2d; - hist3d = ^hist2d_field; { type for top-level pointer } - - -{ Declarations for Floyd-Steinberg dithering. - - Errors are accumulated into the array fserrors[], at a resolution of - 1/16th of a pixel count. The error at a given pixel is propagated - to its not-yet-processed neighbors using the standard F-S fractions, - ... (here) 7/16 - 3/16 5/16 1/16 - We work left-to-right on even rows, right-to-left on odd rows. - - We can get away with a single array (holding one row's worth of errors) - by using it to store the current row's errors at pixel columns not yet - processed, but the next row's errors at columns already processed. We - need only a few extra variables to hold the errors immediately around the - current column. (If we are lucky, those variables are in registers, but - even if not, they're probably cheaper to access than array elements are.) - - The fserrors[] array has (#columns + 2) entries; the extra entry at - each end saves us from special-casing the first and last pixels. - Each entry is three values long, one value for each color component. - - Note: on a wide image, we might not have enough room in a PC's near data - segment to hold the error array; so it is allocated with alloc_large. } - - -{$ifdef BITS_IN_JSAMPLE_IS_8} -type - FSERROR = INT16; { 16 bits should be enough } - LOCFSERROR = int; { use 'int' for calculation temps } -{$else} -type - FSERROR = INT32; { may need more than 16 bits } - LOCFSERROR = INT32; { be sure calculation temps are big enough } -{$endif} -type { Nomssi } - RGB_FSERROR_PTR = ^RGB_FSERROR; - RGB_FSERROR = packed record - r,g,b : FSERROR; - end; - LOCRGB_FSERROR = packed record - r,g,b : LOCFSERROR; - end; - -type - FSERROR_PTR = ^FSERROR; - jFSError = 0..(MaxInt div SIZEOF(RGB_FSERROR))-1; - FS_ERROR_FIELD = array[jFSError] of RGB_FSERROR; - FS_ERROR_FIELD_PTR = ^FS_ERROR_FIELD;{far} - { pointer to error array (in FAR storage!) } - -type - error_limit_array = array[-MAXJSAMPLE..MAXJSAMPLE] of int; - { table for clamping the applied error } - error_limit_ptr = ^error_limit_array; - -{ Private subobject } -type - my_cquantize_ptr = ^my_cquantizer; - my_cquantizer = record - pub : jpeg_color_quantizer; { public fields } - - { Space for the eventually created colormap is stashed here } - sv_colormap : JSAMPARRAY; { colormap allocated at init time } - desired : int; { desired # of colors = size of colormap } - - { Variables for accumulating image statistics } - histogram : hist3d; { pointer to the histogram } - - needs_zeroed : boolean; { TRUE if next pass must zero histogram } - - { Variables for Floyd-Steinberg dithering } - fserrors : FS_ERROR_FIELD_PTR; { accumulated errors } - on_odd_row : boolean; { flag to remember which row we are on } - error_limiter : error_limit_ptr; { table for clamping the applied error } - end; - - - -{ Prescan some rows of pixels. - In this module the prescan simply updates the histogram, which has been - initialized to zeroes by start_pass. - An output_buf parameter is required by the method signature, but no data - is actually output (in fact the buffer controller is probably passing a - NIL pointer). } - -{METHODDEF} -procedure prescan_quantize (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -var - cquantize : my_cquantize_ptr; - {register} ptr : RGBptr; - {register} histp : histptr; - {register} histogram : hist3d; - row : int; - col : JDIMENSION; - width : JDIMENSION; -begin - cquantize := my_cquantize_ptr(cinfo^.cquantize); - histogram := cquantize^.histogram; - width := cinfo^.output_width; - - for row := 0 to pred(num_rows) do - begin - ptr := RGBptr(input_buf^[row]); - for col := pred(width) downto 0 do - begin - { get pixel value and index into the histogram } - histp := @(histogram^[GETJSAMPLE(ptr^.r) shr C0_SHIFT]^ - [GETJSAMPLE(ptr^.g) shr C1_SHIFT] - [GETJSAMPLE(ptr^.b) shr C2_SHIFT]); - { increment, check for overflow and undo increment if so. } - Inc(histp^); - if (histp^ <= 0) then - Dec(histp^); - Inc(ptr); - end; - end; -end; - -{ Next we have the really interesting routines: selection of a colormap - given the completed histogram. - These routines work with a list of "boxes", each representing a rectangular - subset of the input color space (to histogram precision). } - -type - box = record - { The bounds of the box (inclusive); expressed as histogram indexes } - c0min, c0max : int; - c1min, c1max : int; - c2min, c2max : int; - { The volume (actually 2-norm) of the box } - volume : INT32; - { The number of nonzero histogram cells within this box } - colorcount : long; - end; - -type - jBoxList = 0..(MaxInt div SizeOf(box))-1; - box_field = array[jBoxlist] of box; - boxlistptr = ^box_field; - boxptr = ^box; - -{LOCAL} -function find_biggest_color_pop (boxlist : boxlistptr; numboxes : int) : boxptr; -{ Find the splittable box with the largest color population } -{ Returns NIL if no splittable boxes remain } -var - boxp : boxptr ; {register} - i : int; {register} - maxc : long; {register} - which : boxptr; -begin - which := NIL; - boxp := @(boxlist^[0]); - maxc := 0; - for i := 0 to pred(numboxes) do - begin - if (boxp^.colorcount > maxc) and (boxp^.volume > 0) then - begin - which := boxp; - maxc := boxp^.colorcount; - end; - Inc(boxp); - end; - find_biggest_color_pop := which; -end; - - -{LOCAL} -function find_biggest_volume (boxlist : boxlistptr; numboxes : int) : boxptr; -{ Find the splittable box with the largest (scaled) volume } -{ Returns NULL if no splittable boxes remain } -var - {register} boxp : boxptr; - {register} i : int; - {register} maxv : INT32; - which : boxptr; -begin - maxv := 0; - which := NIL; - boxp := @(boxlist^[0]); - for i := 0 to pred(numboxes) do - begin - if (boxp^.volume > maxv) then - begin - which := boxp; - maxv := boxp^.volume; - end; - Inc(boxp); - end; - find_biggest_volume := which; -end; - - -{LOCAL} -procedure update_box (cinfo : j_decompress_ptr; var boxp : box); -label - have_c0min, have_c0max, - have_c1min, have_c1max, - have_c2min, have_c2max; -{ Shrink the min/max bounds of a box to enclose only nonzero elements, } -{ and recompute its volume and population } -var - cquantize : my_cquantize_ptr; - histogram : hist3d; - histp : histptr; - c0,c1,c2 : int; - c0min,c0max,c1min,c1max,c2min,c2max : int; - dist0,dist1,dist2 : INT32; - ccount : long; -begin - cquantize := my_cquantize_ptr(cinfo^.cquantize); - histogram := cquantize^.histogram; - - c0min := boxp.c0min; c0max := boxp.c0max; - c1min := boxp.c1min; c1max := boxp.c1max; - c2min := boxp.c2min; c2max := boxp.c2max; - - if (c0max > c0min) then - for c0 := c0min to c0max do - for c1 := c1min to c1max do - begin - histp := @(histogram^[c0]^[c1][c2min]); - for c2 := c2min to c2max do - begin - if (histp^ <> 0) then - begin - c0min := c0; - boxp.c0min := c0min; - goto have_c0min; - end; - Inc(histp); - end; - end; - have_c0min: - if (c0max > c0min) then - for c0 := c0max downto c0min do - for c1 := c1min to c1max do - begin - histp := @(histogram^[c0]^[c1][c2min]); - for c2 := c2min to c2max do - begin - if ( histp^ <> 0) then - begin - c0max := c0; - boxp.c0max := c0; - goto have_c0max; - end; - Inc(histp); - end; - end; - have_c0max: - if (c1max > c1min) then - for c1 := c1min to c1max do - for c0 := c0min to c0max do - begin - histp := @(histogram^[c0]^[c1][c2min]); - for c2 := c2min to c2max do - begin - if (histp^ <> 0) then - begin - c1min := c1; - boxp.c1min := c1; - goto have_c1min; - end; - Inc(histp); - end; - end; - have_c1min: - if (c1max > c1min) then - for c1 := c1max downto c1min do - for c0 := c0min to c0max do - begin - histp := @(histogram^[c0]^[c1][c2min]); - for c2 := c2min to c2max do - begin - if (histp^ <> 0) then - begin - c1max := c1; - boxp.c1max := c1; - goto have_c1max; - end; - Inc(histp); - end; - end; - have_c1max: - if (c2max > c2min) then - for c2 := c2min to c2max do - for c0 := c0min to c0max do - begin - histp := @(histogram^[c0]^[c1min][c2]); - for c1 := c1min to c1max do - begin - if (histp^ <> 0) then - begin - c2min := c2; - boxp.c2min := c2min; - goto have_c2min; - end; - Inc(histp, HIST_C2_ELEMS); - end; - end; - have_c2min: - if (c2max > c2min) then - for c2 := c2max downto c2min do - for c0 := c0min to c0max do - begin - histp := @(histogram^[c0]^[c1min][c2]); - for c1 := c1min to c1max do - begin - if (histp^ <> 0) then - begin - c2max := c2; - boxp.c2max := c2max; - goto have_c2max; - end; - Inc(histp, HIST_C2_ELEMS); - end; - end; - have_c2max: - - { Update box volume. - We use 2-norm rather than real volume here; this biases the method - against making long narrow boxes, and it has the side benefit that - a box is splittable iff norm > 0. - Since the differences are expressed in histogram-cell units, - we have to shift back to JSAMPLE units to get consistent distances; - after which, we scale according to the selected distance scale factors.} - - dist0 := ((c0max - c0min) shl C0_SHIFT) * C0_SCALE; - dist1 := ((c1max - c1min) shl C1_SHIFT) * C1_SCALE; - dist2 := ((c2max - c2min) shl C2_SHIFT) * C2_SCALE; - boxp.volume := dist0*dist0 + dist1*dist1 + dist2*dist2; - - { Now scan remaining volume of box and compute population } - ccount := 0; - for c0 := c0min to c0max do - for c1 := c1min to c1max do - begin - histp := @(histogram^[c0]^[c1][c2min]); - for c2 := c2min to c2max do - begin - if (histp^ <> 0) then - Inc(ccount); - Inc(histp); - end; - end; - boxp.colorcount := ccount; -end; - - -{LOCAL} -function median_cut (cinfo : j_decompress_ptr; boxlist : boxlistptr; - numboxes : int; desired_colors : int) : int; -{ Repeatedly select and split the largest box until we have enough boxes } -var - n,lb : int; - c0,c1,c2,cmax : int; - {register} b1,b2 : boxptr; -begin - while (numboxes < desired_colors) do - begin - { Select box to split. - Current algorithm: by population for first half, then by volume. } - - if (numboxes*2 <= desired_colors) then - b1 := find_biggest_color_pop(boxlist, numboxes) - else - b1 := find_biggest_volume(boxlist, numboxes); - - if (b1 = NIL) then { no splittable boxes left! } - break; - b2 := @(boxlist^[numboxes]); { where new box will go } - { Copy the color bounds to the new box. } - b2^.c0max := b1^.c0max; b2^.c1max := b1^.c1max; b2^.c2max := b1^.c2max; - b2^.c0min := b1^.c0min; b2^.c1min := b1^.c1min; b2^.c2min := b1^.c2min; - { Choose which axis to split the box on. - Current algorithm: longest scaled axis. - See notes in update_box about scaling distances. } - - c0 := ((b1^.c0max - b1^.c0min) shl C0_SHIFT) * C0_SCALE; - c1 := ((b1^.c1max - b1^.c1min) shl C1_SHIFT) * C1_SCALE; - c2 := ((b1^.c2max - b1^.c2min) shl C2_SHIFT) * C2_SCALE; - { We want to break any ties in favor of green, then red, blue last. - This code does the right thing for R,G,B or B,G,R color orders only. } - -{$ifdef RGB_RED_IS_0} - cmax := c1; n := 1; - if (c0 > cmax) then - begin - cmax := c0; - n := 0; - end; - if (c2 > cmax) then - n := 2; -{$else} - cmax := c1; - n := 1; - if (c2 > cmax) then - begin - cmax := c2; - n := 2; - end; - if (c0 > cmax) then - n := 0; -{$endif} - { Choose split point along selected axis, and update box bounds. - Current algorithm: split at halfway point. - (Since the box has been shrunk to minimum volume, - any split will produce two nonempty subboxes.) - Note that lb value is max for lower box, so must be < old max. } - - case n of - 0:begin - lb := (b1^.c0max + b1^.c0min) div 2; - b1^.c0max := lb; - b2^.c0min := lb+1; - end; - 1:begin - lb := (b1^.c1max + b1^.c1min) div 2; - b1^.c1max := lb; - b2^.c1min := lb+1; - end; - 2:begin - lb := (b1^.c2max + b1^.c2min) div 2; - b1^.c2max := lb; - b2^.c2min := lb+1; - end; - end; - { Update stats for boxes } - update_box(cinfo, b1^); - update_box(cinfo, b2^); - Inc(numboxes); - end; - median_cut := numboxes; -end; - - -{LOCAL} -procedure compute_color (cinfo : j_decompress_ptr; - const boxp : box; icolor : int); -{ Compute representative color for a box, put it in colormap[icolor] } -var - { Current algorithm: mean weighted by pixels (not colors) } - { Note it is important to get the rounding correct! } - cquantize : my_cquantize_ptr; - histogram : hist3d; - histp : histptr; - c0,c1,c2 : int; - c0min,c0max,c1min,c1max,c2min,c2max : int; - count : long; - total : long; - c0total : long; - c1total : long; - c2total : long; -begin - cquantize := my_cquantize_ptr(cinfo^.cquantize); - histogram := cquantize^.histogram; - total := 0; - c0total := 0; - c1total := 0; - c2total := 0; - - c0min := boxp.c0min; c0max := boxp.c0max; - c1min := boxp.c1min; c1max := boxp.c1max; - c2min := boxp.c2min; c2max := boxp.c2max; - - for c0 := c0min to c0max do - for c1 := c1min to c1max do - begin - histp := @(histogram^[c0]^[c1][c2min]); - for c2 := c2min to c2max do - begin - count := histp^; - Inc(histp); - if (count <> 0) then - begin - Inc(total, count); - Inc(c0total, ((c0 shl C0_SHIFT) + ((1 shl C0_SHIFT) shr 1)) * count); - Inc(c1total, ((c1 shl C1_SHIFT) + ((1 shl C1_SHIFT) shr 1)) * count); - Inc(c2total, ((c2 shl C2_SHIFT) + ((1 shl C2_SHIFT) shr 1)) * count); - end; - end; - end; - - cinfo^.colormap^[0]^[icolor] := JSAMPLE ((c0total + (total shr 1)) div total); - cinfo^.colormap^[1]^[icolor] := JSAMPLE ((c1total + (total shr 1)) div total); - cinfo^.colormap^[2]^[icolor] := JSAMPLE ((c2total + (total shr 1)) div total); -end; - - -{LOCAL} -procedure select_colors (cinfo : j_decompress_ptr; desired_colors : int); -{ Master routine for color selection } -var - boxlist : boxlistptr; - numboxes : int; - i : int; -begin - { Allocate workspace for box list } - boxlist := boxlistptr(cinfo^.mem^.alloc_small( - j_common_ptr(cinfo), JPOOL_IMAGE, desired_colors * SIZEOF(box))); - { Initialize one box containing whole space } - numboxes := 1; - boxlist^[0].c0min := 0; - boxlist^[0].c0max := MAXJSAMPLE shr C0_SHIFT; - boxlist^[0].c1min := 0; - boxlist^[0].c1max := MAXJSAMPLE shr C1_SHIFT; - boxlist^[0].c2min := 0; - boxlist^[0].c2max := MAXJSAMPLE shr C2_SHIFT; - { Shrink it to actually-used volume and set its statistics } - update_box(cinfo, boxlist^[0]); - { Perform median-cut to produce final box list } - numboxes := median_cut(cinfo, boxlist, numboxes, desired_colors); - { Compute the representative color for each box, fill colormap } - for i := 0 to pred(numboxes) do - compute_color(cinfo, boxlist^[i], i); - cinfo^.actual_number_of_colors := numboxes; - {$IFDEF DEBUG} - TRACEMS1(j_common_ptr(cinfo), 1, JTRC_QUANT_SELECTED, numboxes); - {$ENDIF} -end; - - -{ These routines are concerned with the time-critical task of mapping input - colors to the nearest color in the selected colormap. - - We re-use the histogram space as an "inverse color map", essentially a - cache for the results of nearest-color searches. All colors within a - histogram cell will be mapped to the same colormap entry, namely the one - closest to the cell's center. This may not be quite the closest entry to - the actual input color, but it's almost as good. A zero in the cache - indicates we haven't found the nearest color for that cell yet; the array - is cleared to zeroes before starting the mapping pass. When we find the - nearest color for a cell, its colormap index plus one is recorded in the - cache for future use. The pass2 scanning routines call fill_inverse_cmap - when they need to use an unfilled entry in the cache. - - Our method of efficiently finding nearest colors is based on the "locally - sorted search" idea described by Heckbert and on the incremental distance - calculation described by Spencer W. Thomas in chapter III.1 of Graphics - Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that - the distances from a given colormap entry to each cell of the histogram can - be computed quickly using an incremental method: the differences between - distances to adjacent cells themselves differ by a constant. This allows a - fairly fast implementation of the "brute force" approach of computing the - distance from every colormap entry to every histogram cell. Unfortunately, - it needs a work array to hold the best-distance-so-far for each histogram - cell (because the inner loop has to be over cells, not colormap entries). - The work array elements have to be INT32s, so the work array would need - 256Kb at our recommended precision. This is not feasible in DOS machines. - - To get around these problems, we apply Thomas' method to compute the - nearest colors for only the cells within a small subbox of the histogram. - The work array need be only as big as the subbox, so the memory usage - problem is solved. Furthermore, we need not fill subboxes that are never - referenced in pass2; many images use only part of the color gamut, so a - fair amount of work is saved. An additional advantage of this - approach is that we can apply Heckbert's locality criterion to quickly - eliminate colormap entries that are far away from the subbox; typically - three-fourths of the colormap entries are rejected by Heckbert's criterion, - and we need not compute their distances to individual cells in the subbox. - The speed of this approach is heavily influenced by the subbox size: too - small means too much overhead, too big loses because Heckbert's criterion - can't eliminate as many colormap entries. Empirically the best subbox - size seems to be about 1/512th of the histogram (1/8th in each direction). - - Thomas' article also describes a refined method which is asymptotically - faster than the brute-force method, but it is also far more complex and - cannot efficiently be applied to small subboxes. It is therefore not - useful for programs intended to be portable to DOS machines. On machines - with plenty of memory, filling the whole histogram in one shot with Thomas' - refined method might be faster than the present code --- but then again, - it might not be any faster, and it's certainly more complicated. } - - - -{ log2(histogram cells in update box) for each axis; this can be adjusted } -const - BOX_C0_LOG = (HIST_C0_BITS-3); - BOX_C1_LOG = (HIST_C1_BITS-3); - BOX_C2_LOG = (HIST_C2_BITS-3); - - BOX_C0_ELEMS = (1 shl BOX_C0_LOG); { # of hist cells in update box } - BOX_C1_ELEMS = (1 shl BOX_C1_LOG); - BOX_C2_ELEMS = (1 shl BOX_C2_LOG); - - BOX_C0_SHIFT = (C0_SHIFT + BOX_C0_LOG); - BOX_C1_SHIFT = (C1_SHIFT + BOX_C1_LOG); - BOX_C2_SHIFT = (C2_SHIFT + BOX_C2_LOG); - - -{ The next three routines implement inverse colormap filling. They could - all be folded into one big routine, but splitting them up this way saves - some stack space (the mindist[] and bestdist[] arrays need not coexist) - and may allow some compilers to produce better code by registerizing more - inner-loop variables. } - -{LOCAL} -function find_nearby_colors (cinfo : j_decompress_ptr; - minc0 : int; minc1 : int; minc2 : int; - var colorlist : array of JSAMPLE) : int; -{ Locate the colormap entries close enough to an update box to be candidates - for the nearest entry to some cell(s) in the update box. The update box - is specified by the center coordinates of its first cell. The number of - candidate colormap entries is returned, and their colormap indexes are - placed in colorlist[]. - This routine uses Heckbert's "locally sorted search" criterion to select - the colors that need further consideration. } - -var - numcolors : int; - maxc0, maxc1, maxc2 : int; - centerc0, centerc1, centerc2 : int; - i, x, ncolors : int; - minmaxdist, min_dist, max_dist, tdist : INT32; - mindist : array[0..MAXNUMCOLORS-1] of INT32; - { min distance to colormap entry i } -begin - numcolors := cinfo^.actual_number_of_colors; - - { Compute true coordinates of update box's upper corner and center. - Actually we compute the coordinates of the center of the upper-corner - histogram cell, which are the upper bounds of the volume we care about. - Note that since ">>" rounds down, the "center" values may be closer to - min than to max; hence comparisons to them must be "<=", not "<". } - - maxc0 := minc0 + ((1 shl BOX_C0_SHIFT) - (1 shl C0_SHIFT)); - centerc0 := (minc0 + maxc0) shr 1; - maxc1 := minc1 + ((1 shl BOX_C1_SHIFT) - (1 shl C1_SHIFT)); - centerc1 := (minc1 + maxc1) shr 1; - maxc2 := minc2 + ((1 shl BOX_C2_SHIFT) - (1 shl C2_SHIFT)); - centerc2 := (minc2 + maxc2) shr 1; - - { For each color in colormap, find: - 1. its minimum squared-distance to any point in the update box - (zero if color is within update box); - 2. its maximum squared-distance to any point in the update box. - Both of these can be found by considering only the corners of the box. - We save the minimum distance for each color in mindist[]; - only the smallest maximum distance is of interest. } - - minmaxdist := long($7FFFFFFF); - - for i := 0 to pred(numcolors) do - begin - { We compute the squared-c0-distance term, then add in the other two. } - x := GETJSAMPLE(cinfo^.colormap^[0]^[i]); - if (x < minc0) then - begin - tdist := (x - minc0) * C0_SCALE; - min_dist := tdist*tdist; - tdist := (x - maxc0) * C0_SCALE; - max_dist := tdist*tdist; - end - else - if (x > maxc0) then - begin - tdist := (x - maxc0) * C0_SCALE; - min_dist := tdist*tdist; - tdist := (x - minc0) * C0_SCALE; - max_dist := tdist*tdist; - end - else - begin - { within cell range so no contribution to min_dist } - min_dist := 0; - if (x <= centerc0) then - begin - tdist := (x - maxc0) * C0_SCALE; - max_dist := tdist*tdist; - end - else - begin - tdist := (x - minc0) * C0_SCALE; - max_dist := tdist*tdist; - end; - end; - - x := GETJSAMPLE(cinfo^.colormap^[1]^[i]); - if (x < minc1) then - begin - tdist := (x - minc1) * C1_SCALE; - Inc(min_dist, tdist*tdist); - tdist := (x - maxc1) * C1_SCALE; - Inc(max_dist, tdist*tdist); - end - else - if (x > maxc1) then - begin - tdist := (x - maxc1) * C1_SCALE; - Inc(min_dist, tdist*tdist); - tdist := (x - minc1) * C1_SCALE; - Inc(max_dist, tdist*tdist); - end - else - begin - { within cell range so no contribution to min_dist } - if (x <= centerc1) then - begin - tdist := (x - maxc1) * C1_SCALE; - Inc(max_dist, tdist*tdist); - end - else - begin - tdist := (x - minc1) * C1_SCALE; - Inc(max_dist, tdist*tdist); - end - end; - - x := GETJSAMPLE(cinfo^.colormap^[2]^[i]); - if (x < minc2) then - begin - tdist := (x - minc2) * C2_SCALE; - Inc(min_dist, tdist*tdist); - tdist := (x - maxc2) * C2_SCALE; - Inc(max_dist, tdist*tdist); - end - else - if (x > maxc2) then - begin - tdist := (x - maxc2) * C2_SCALE; - Inc(min_dist, tdist*tdist); - tdist := (x - minc2) * C2_SCALE; - Inc(max_dist, tdist*tdist); - end - else - begin - { within cell range so no contribution to min_dist } - if (x <= centerc2) then - begin - tdist := (x - maxc2) * C2_SCALE; - Inc(max_dist, tdist*tdist); - end - else - begin - tdist := (x - minc2) * C2_SCALE; - Inc(max_dist, tdist*tdist); - end; - end; - - mindist[i] := min_dist; { save away the results } - if (max_dist < minmaxdist) then - minmaxdist := max_dist; - end; - - { Now we know that no cell in the update box is more than minmaxdist - away from some colormap entry. Therefore, only colors that are - within minmaxdist of some part of the box need be considered. } - - ncolors := 0; - for i := 0 to pred(numcolors) do - begin - if (mindist[i] <= minmaxdist) then - begin - colorlist[ncolors] := JSAMPLE(i); - Inc(ncolors); - end; - end; - find_nearby_colors := ncolors; -end; - - -{LOCAL} -procedure find_best_colors (cinfo : j_decompress_ptr; - minc0 : int; minc1 : int; minc2 : int; - numcolors : int; - var colorlist : array of JSAMPLE; - var bestcolor : array of JSAMPLE); -{ Find the closest colormap entry for each cell in the update box, - given the list of candidate colors prepared by find_nearby_colors. - Return the indexes of the closest entries in the bestcolor[] array. - This routine uses Thomas' incremental distance calculation method to - find the distance from a colormap entry to successive cells in the box. } -const - { Nominal steps between cell centers ("x" in Thomas article) } - STEP_C0 = ((1 shl C0_SHIFT) * C0_SCALE); - STEP_C1 = ((1 shl C1_SHIFT) * C1_SCALE); - STEP_C2 = ((1 shl C2_SHIFT) * C2_SCALE); -var - ic0, ic1, ic2 : int; - i, icolor : int; - {register} bptr : INT32PTR; { pointer into bestdist[] array } - cptr : JSAMPLE_PTR; { pointer into bestcolor[] array } - dist0, dist1 : INT32; { initial distance values } - {register} dist2 : INT32; { current distance in inner loop } - xx0, xx1 : INT32; { distance increments } - {register} xx2 : INT32; - inc0, inc1, inc2 : INT32; { initial values for increments } - { This array holds the distance to the nearest-so-far color for each cell } - bestdist : array[0..BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS-1] of INT32; -begin - { Initialize best-distance for each cell of the update box } - for i := BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1 downto 0 do - bestdist[i] := $7FFFFFFF; - - { For each color selected by find_nearby_colors, - compute its distance to the center of each cell in the box. - If that's less than best-so-far, update best distance and color number. } - - - - for i := 0 to pred(numcolors) do - begin - icolor := GETJSAMPLE(colorlist[i]); - { Compute (square of) distance from minc0/c1/c2 to this color } - inc0 := (minc0 - GETJSAMPLE(cinfo^.colormap^[0]^[icolor])) * C0_SCALE; - dist0 := inc0*inc0; - inc1 := (minc1 - GETJSAMPLE(cinfo^.colormap^[1]^[icolor])) * C1_SCALE; - Inc(dist0, inc1*inc1); - inc2 := (minc2 - GETJSAMPLE(cinfo^.colormap^[2]^[icolor])) * C2_SCALE; - Inc(dist0, inc2*inc2); - { Form the initial difference increments } - inc0 := inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; - inc1 := inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; - inc2 := inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; - { Now loop over all cells in box, updating distance per Thomas method } - bptr := @bestdist[0]; - cptr := @bestcolor[0]; - xx0 := inc0; - for ic0 := BOX_C0_ELEMS-1 downto 0 do - begin - dist1 := dist0; - xx1 := inc1; - for ic1 := BOX_C1_ELEMS-1 downto 0 do - begin - dist2 := dist1; - xx2 := inc2; - for ic2 := BOX_C2_ELEMS-1 downto 0 do - begin - if (dist2 < bptr^) then - begin - bptr^ := dist2; - cptr^ := JSAMPLE (icolor); - end; - Inc(dist2, xx2); - Inc(xx2, 2 * STEP_C2 * STEP_C2); - Inc(bptr); - Inc(cptr); - end; - Inc(dist1, xx1); - Inc(xx1, 2 * STEP_C1 * STEP_C1); - end; - Inc(dist0, xx0); - Inc(xx0, 2 * STEP_C0 * STEP_C0); - end; - end; -end; - - -{LOCAL} -procedure fill_inverse_cmap (cinfo : j_decompress_ptr; - c0 : int; c1 : int; c2 : int); -{ Fill the inverse-colormap entries in the update box that contains } -{ histogram cell c0/c1/c2. (Only that one cell MUST be filled, but } -{ we can fill as many others as we wish.) } -var - cquantize : my_cquantize_ptr; - histogram : hist3d; - minc0, minc1, minc2 : int; { lower left corner of update box } - ic0, ic1, ic2 : int; - {register} cptr : JSAMPLE_PTR; { pointer into bestcolor[] array } - {register} cachep : histptr; { pointer into main cache array } - { This array lists the candidate colormap indexes. } - colorlist : array[0..MAXNUMCOLORS-1] of JSAMPLE; - numcolors : int; { number of candidate colors } - { This array holds the actually closest colormap index for each cell. } - bestcolor : array[0..BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS-1] of JSAMPLE; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - histogram := cquantize^.histogram; - - { Convert cell coordinates to update box ID } - c0 := c0 shr BOX_C0_LOG; - c1 := c1 shr BOX_C1_LOG; - c2 := c2 shr BOX_C2_LOG; - - { Compute true coordinates of update box's origin corner. - Actually we compute the coordinates of the center of the corner - histogram cell, which are the lower bounds of the volume we care about.} - - minc0 := (c0 shl BOX_C0_SHIFT) + ((1 shl C0_SHIFT) shr 1); - minc1 := (c1 shl BOX_C1_SHIFT) + ((1 shl C1_SHIFT) shr 1); - minc2 := (c2 shl BOX_C2_SHIFT) + ((1 shl C2_SHIFT) shr 1); - - { Determine which colormap entries are close enough to be candidates - for the nearest entry to some cell in the update box. } - - numcolors := find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); - - { Determine the actually nearest colors. } - find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, - bestcolor); - - { Save the best color numbers (plus 1) in the main cache array } - c0 := c0 shl BOX_C0_LOG; { convert ID back to base cell indexes } - c1 := c1 shl BOX_C1_LOG; - c2 := c2 shl BOX_C2_LOG; - cptr := @(bestcolor[0]); - for ic0 := 0 to pred(BOX_C0_ELEMS) do - for ic1 := 0 to pred(BOX_C1_ELEMS) do - begin - cachep := @(histogram^[c0+ic0]^[c1+ic1][c2]); - for ic2 := 0 to pred(BOX_C2_ELEMS) do - begin - cachep^ := histcell (GETJSAMPLE(cptr^) + 1); - Inc(cachep); - Inc(cptr); - end; - end; -end; - - -{ Map some rows of pixels to the output colormapped representation. } - -{METHODDEF} -procedure pass2_no_dither (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ This version performs no dithering } -var - cquantize : my_cquantize_ptr; - histogram : hist3d; - {register} inptr : RGBptr; - outptr : JSAMPLE_PTR; - {register} cachep : histptr; - {register} c0, c1, c2 : int; - row : int; - col : JDIMENSION; - width : JDIMENSION; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - histogram := cquantize^.histogram; - width := cinfo^.output_width; - - for row := 0 to pred(num_rows) do - begin - inptr := RGBptr(input_buf^[row]); - outptr := JSAMPLE_PTR(output_buf^[row]); - for col := pred(width) downto 0 do - begin - { get pixel value and index into the cache } - c0 := GETJSAMPLE(inptr^.r) shr C0_SHIFT; - c1 := GETJSAMPLE(inptr^.g) shr C1_SHIFT; - c2 := GETJSAMPLE(inptr^.b) shr C2_SHIFT; - Inc(inptr); - cachep := @(histogram^[c0]^[c1][c2]); - { If we have not seen this color before, find nearest colormap entry } - { and update the cache } - if (cachep^ = 0) then - fill_inverse_cmap(cinfo, c0,c1,c2); - { Now emit the colormap index for this cell } - outptr^ := JSAMPLE (cachep^ - 1); - Inc(outptr); - end; - end; -end; - - -{METHODDEF} -procedure pass2_fs_dither (cinfo : j_decompress_ptr; - input_buf : JSAMPARRAY; - output_buf : JSAMPARRAY; - num_rows : int); -{ This version performs Floyd-Steinberg dithering } -var - cquantize : my_cquantize_ptr; - histogram : hist3d; - {register} cur : LOCRGB_FSERROR; { current error or pixel value } - belowerr : LOCRGB_FSERROR; { error for pixel below cur } - bpreverr : LOCRGB_FSERROR; { error for below/prev col } - prev_errorptr, - {register} errorptr : RGB_FSERROR_PTR; { => fserrors[] at column before current } - inptr : RGBptr; { => current input pixel } - outptr : JSAMPLE_PTR; { => current output pixel } - cachep : histptr; - dir : int; { +1 or -1 depending on direction } - row : int; - col : JDIMENSION; - width : JDIMENSION; - range_limit : range_limit_table_ptr; - error_limit : error_limit_ptr; - colormap0 : JSAMPROW; - colormap1 : JSAMPROW; - colormap2 : JSAMPROW; - {register} pixcode : int; - {register} bnexterr, delta : LOCFSERROR; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - histogram := cquantize^.histogram; - width := cinfo^.output_width; - range_limit := cinfo^.sample_range_limit; - error_limit := cquantize^.error_limiter; - colormap0 := cinfo^.colormap^[0]; - colormap1 := cinfo^.colormap^[1]; - colormap2 := cinfo^.colormap^[2]; - - for row := 0 to pred(num_rows) do - begin - inptr := RGBptr(input_buf^[row]); - outptr := JSAMPLE_PTR(output_buf^[row]); - errorptr := RGB_FSERROR_PTR(cquantize^.fserrors); { => entry before first real column } - if (cquantize^.on_odd_row) then - begin - { work right to left in this row } - Inc(inptr, (width-1)); { so point to rightmost pixel } - Inc(outptr, width-1); - dir := -1; - Inc(errorptr, (width+1)); { => entry after last column } - cquantize^.on_odd_row := FALSE; { flip for next time } - end - else - begin - { work left to right in this row } - dir := 1; - cquantize^.on_odd_row := TRUE; { flip for next time } - end; - - { Preset error values: no error propagated to first pixel from left } - cur.r := 0; - cur.g := 0; - cur.b := 0; - { and no error propagated to row below yet } - belowerr.r := 0; - belowerr.g := 0; - belowerr.b := 0; - bpreverr.r := 0; - bpreverr.g := 0; - bpreverr.b := 0; - - for col := pred(width) downto 0 do - begin - prev_errorptr := errorptr; - Inc(errorptr, dir); { advance errorptr to current column } - - { curN holds the error propagated from the previous pixel on the - current line. Add the error propagated from the previous line - to form the complete error correction term for this pixel, and - round the error term (which is expressed * 16) to an integer. - RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - for either sign of the error value. - Note: prev_errorptr points to *previous* column's array entry. } - - { Nomssi Note: Borland Pascal SHR is unsigned } - cur.r := (cur.r + errorptr^.r + 8) div 16; - cur.g := (cur.g + errorptr^.g + 8) div 16; - cur.b := (cur.b + errorptr^.b + 8) div 16; - { Limit the error using transfer function set by init_error_limit. - See comments with init_error_limit for rationale. } - - cur.r := error_limit^[cur.r]; - cur.g := error_limit^[cur.g]; - cur.b := error_limit^[cur.b]; - { Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - The maximum error is +- MAXJSAMPLE (or less with error limiting); - this sets the required size of the range_limit array. } - - Inc(cur.r, GETJSAMPLE(inptr^.r)); - Inc(cur.g, GETJSAMPLE(inptr^.g)); - Inc(cur.b, GETJSAMPLE(inptr^.b)); - - cur.r := GETJSAMPLE(range_limit^[cur.r]); - cur.g := GETJSAMPLE(range_limit^[cur.g]); - cur.b := GETJSAMPLE(range_limit^[cur.b]); - { Index into the cache with adjusted pixel value } - cachep := @(histogram^[cur.r shr C0_SHIFT]^ - [cur.g shr C1_SHIFT][cur.b shr C2_SHIFT]); - { If we have not seen this color before, find nearest colormap } - { entry and update the cache } - if (cachep^ = 0) then - fill_inverse_cmap(cinfo, cur.r shr C0_SHIFT, - cur.g shr C1_SHIFT, - cur.b shr C2_SHIFT); - { Now emit the colormap index for this cell } - - pixcode := cachep^ - 1; - outptr^ := JSAMPLE (pixcode); - - { Compute representation error for this pixel } - Dec(cur.r, GETJSAMPLE(colormap0^[pixcode])); - Dec(cur.g, GETJSAMPLE(colormap1^[pixcode])); - Dec(cur.b, GETJSAMPLE(colormap2^[pixcode])); - - { Compute error fractions to be propagated to adjacent pixels. - Add these into the running sums, and simultaneously shift the - next-line error sums left by 1 column. } - - bnexterr := cur.r; { Process component 0 } - delta := cur.r * 2; - Inc(cur.r, delta); { form error * 3 } - prev_errorptr^.r := FSERROR (bpreverr.r + cur.r); - Inc(cur.r, delta); { form error * 5 } - bpreverr.r := belowerr.r + cur.r; - belowerr.r := bnexterr; - Inc(cur.r, delta); { form error * 7 } - bnexterr := cur.g; { Process component 1 } - delta := cur.g * 2; - Inc(cur.g, delta); { form error * 3 } - prev_errorptr^.g := FSERROR (bpreverr.g + cur.g); - Inc(cur.g, delta); { form error * 5 } - bpreverr.g := belowerr.g + cur.g; - belowerr.g := bnexterr; - Inc(cur.g, delta); { form error * 7 } - bnexterr := cur.b; { Process component 2 } - delta := cur.b * 2; - Inc(cur.b, delta); { form error * 3 } - prev_errorptr^.b := FSERROR (bpreverr.b + cur.b); - Inc(cur.b, delta); { form error * 5 } - bpreverr.b := belowerr.b + cur.b; - belowerr.b := bnexterr; - Inc(cur.b, delta); { form error * 7 } - - { At this point curN contains the 7/16 error value to be propagated - to the next pixel on the current line, and all the errors for the - next line have been shifted over. We are therefore ready to move on.} - - Inc(inptr, dir); { Advance pixel pointers to next column } - Inc(outptr, dir); - end; - { Post-loop cleanup: we must unload the final error values into the - final fserrors[] entry. Note we need not unload belowerrN because - it is for the dummy column before or after the actual array. } - - errorptr^.r := FSERROR (bpreverr.r); { unload prev errs into array } - errorptr^.g := FSERROR (bpreverr.g); - errorptr^.b := FSERROR (bpreverr.b); - end; -end; - - -{ Initialize the error-limiting transfer function (lookup table). - The raw F-S error computation can potentially compute error values of up to - +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be - much less, otherwise obviously wrong pixels will be created. (Typical - effects include weird fringes at color-area boundaries, isolated bright - pixels in a dark area, etc.) The standard advice for avoiding this problem - is to ensure that the "corners" of the color cube are allocated as output - colors; then repeated errors in the same direction cannot cause cascading - error buildup. However, that only prevents the error from getting - completely out of hand; Aaron Giles reports that error limiting improves - the results even with corner colors allocated. - A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty - well, but the smoother transfer function used below is even better. Thanks - to Aaron Giles for this idea. } - -{LOCAL} -procedure init_error_limit (cinfo : j_decompress_ptr); -const - STEPSIZE = ((MAXJSAMPLE+1) div 16); -{ Allocate and fill in the error_limiter table } -var - cquantize : my_cquantize_ptr; - table : error_limit_ptr; - inp, out : int; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - table := error_limit_ptr (cinfo^.mem^.alloc_small - (j_common_ptr (cinfo), JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int))); - { not needed: Inc(table, MAXJSAMPLE); - so can index -MAXJSAMPLE .. +MAXJSAMPLE } - cquantize^.error_limiter := table; - { Map errors 1:1 up to +- MAXJSAMPLE/16 } - out := 0; - for inp := 0 to pred(STEPSIZE) do - begin - table^[inp] := out; - table^[-inp] := -out; - Inc(out); - end; - { Map errors 1:2 up to +- 3*MAXJSAMPLE/16 } - inp := STEPSIZE; { Nomssi: avoid problems with Delphi2 optimizer } - while (inp < STEPSIZE*3) do - begin - table^[inp] := out; - table^[-inp] := -out; - Inc(inp); - if Odd(inp) then - Inc(out); - end; - { Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) } - inp := STEPSIZE*3; { Nomssi: avoid problems with Delphi 2 optimizer } - while inp <= MAXJSAMPLE do - begin - table^[inp] := out; - table^[-inp] := -out; - Inc(inp); - end; -end; - -{ Finish up at the end of each pass. } - -{METHODDEF} -procedure finish_pass1 (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - - { Select the representative colors and fill in cinfo^.colormap } - cinfo^.colormap := cquantize^.sv_colormap; - select_colors(cinfo, cquantize^.desired); - { Force next pass to zero the color index table } - cquantize^.needs_zeroed := TRUE; -end; - - -{METHODDEF} -procedure finish_pass2 (cinfo : j_decompress_ptr); -begin - { no work } -end; - - -{ Initialize for each processing pass. } - -{METHODDEF} -procedure start_pass_2_quant (cinfo : j_decompress_ptr; - is_pre_scan : boolean); -var - cquantize : my_cquantize_ptr; - histogram : hist3d; - i : int; -var - arraysize : size_t; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - histogram := cquantize^.histogram; - { Only F-S dithering or no dithering is supported. } - { If user asks for ordered dither, give him F-S. } - if (cinfo^.dither_mode <> JDITHER_NONE) then - cinfo^.dither_mode := JDITHER_FS; - - if (is_pre_scan) then - begin - { Set up method pointers } - cquantize^.pub.color_quantize := prescan_quantize; - cquantize^.pub.finish_pass := finish_pass1; - cquantize^.needs_zeroed := TRUE; { Always zero histogram } - end - else - begin - { Set up method pointers } - if (cinfo^.dither_mode = JDITHER_FS) then - cquantize^.pub.color_quantize := pass2_fs_dither - else - cquantize^.pub.color_quantize := pass2_no_dither; - cquantize^.pub.finish_pass := finish_pass2; - - { Make sure color count is acceptable } - i := cinfo^.actual_number_of_colors; - if (i < 1) then - ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_FEW_COLORS, 1); - if (i > MAXNUMCOLORS) then - ERREXIT1(j_common_ptr(cinfo), JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); - - if (cinfo^.dither_mode = JDITHER_FS) then - begin - arraysize := size_t ((cinfo^.output_width + 2) * - (3 * SIZEOF(FSERROR))); - { Allocate Floyd-Steinberg workspace if we didn't already. } - if (cquantize^.fserrors = NIL) then - cquantize^.fserrors := FS_ERROR_FIELD_PTR (cinfo^.mem^.alloc_large - (j_common_ptr(cinfo), JPOOL_IMAGE, arraysize)); - { Initialize the propagated errors to zero. } - jzero_far(cquantize^.fserrors, arraysize); - { Make the error-limit table if we didn't already. } - if (cquantize^.error_limiter = NIL) then - init_error_limit(cinfo); - cquantize^.on_odd_row := FALSE; - end; - - end; - { Zero the histogram or inverse color map, if necessary } - if (cquantize^.needs_zeroed) then - begin - for i := 0 to pred(HIST_C0_ELEMS) do - begin - jzero_far( histogram^[i], - HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell)); - end; - cquantize^.needs_zeroed := FALSE; - end; -end; - - -{ Switch to a new external colormap between output passes. } - -{METHODDEF} -procedure new_color_map_2_quant (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; -begin - cquantize := my_cquantize_ptr (cinfo^.cquantize); - - { Reset the inverse color map } - cquantize^.needs_zeroed := TRUE; -end; - - -{ Module initialization routine for 2-pass color quantization. } - - -{GLOBAL} -procedure jinit_2pass_quantizer (cinfo : j_decompress_ptr); -var - cquantize : my_cquantize_ptr; - i : int; -var - desired : int; -begin - cquantize := my_cquantize_ptr( - cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE, - SIZEOF(my_cquantizer))); - cinfo^.cquantize := jpeg_color_quantizer_ptr(cquantize); - cquantize^.pub.start_pass := start_pass_2_quant; - cquantize^.pub.new_color_map := new_color_map_2_quant; - cquantize^.fserrors := NIL; { flag optional arrays not allocated } - cquantize^.error_limiter := NIL; - - { Make sure jdmaster didn't give me a case I can't handle } - if (cinfo^.out_color_components <> 3) then - ERREXIT(j_common_ptr(cinfo), JERR_NOTIMPL); - - { Allocate the histogram/inverse colormap storage } - cquantize^.histogram := hist3d (cinfo^.mem^.alloc_small - (j_common_ptr (cinfo), JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d))); - for i := 0 to pred(HIST_C0_ELEMS) do - begin - cquantize^.histogram^[i] := hist2d (cinfo^.mem^.alloc_large - (j_common_ptr (cinfo), JPOOL_IMAGE, - HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell))); - end; - cquantize^.needs_zeroed := TRUE; { histogram is garbage now } - - { Allocate storage for the completed colormap, if required. - We do this now since it is FAR storage and may affect - the memory manager's space calculations. } - - if (cinfo^.enable_2pass_quant) then - begin - { Make sure color count is acceptable } - desired := cinfo^.desired_number_of_colors; - { Lower bound on # of colors ... somewhat arbitrary as long as > 0 } - if (desired < 8) then - ERREXIT1(j_common_ptr (cinfo), JERR_QUANT_FEW_COLORS, 8); - { Make sure colormap indexes can be represented by JSAMPLEs } - if (desired > MAXNUMCOLORS) then - ERREXIT1(j_common_ptr (cinfo), JERR_QUANT_MANY_COLORS, MAXNUMCOLORS); - cquantize^.sv_colormap := cinfo^.mem^.alloc_sarray - (j_common_ptr (cinfo),JPOOL_IMAGE, JDIMENSION(desired), JDIMENSION(3)); - cquantize^.desired := desired; - end - else - cquantize^.sv_colormap := NIL; - - { Only F-S dithering or no dithering is supported. } - { If user asks for ordered dither, give him F-S. } - if (cinfo^.dither_mode <> JDITHER_NONE) then - cinfo^.dither_mode := JDITHER_FS; - - { Allocate Floyd-Steinberg workspace if necessary. - This isn't really needed until pass 2, but again it is FAR storage. - Although we will cope with a later change in dither_mode, - we do not promise to honor max_memory_to_use if dither_mode changes. } - - if (cinfo^.dither_mode = JDITHER_FS) then - begin - cquantize^.fserrors := FS_ERROR_FIELD_PTR (cinfo^.mem^.alloc_large - (j_common_ptr(cinfo), JPOOL_IMAGE, - size_t ((cinfo^.output_width + 2) * (3 * SIZEOF(FSERROR))) ) ); - { Might as well create the error-limiting table too. } - init_error_limit(cinfo); - end; -end; -{ QUANT_2PASS_SUPPORTED } -end. diff --git a/3rd/Imaging/Source/JpegLib/imjutils.pas b/3rd/Imaging/Source/JpegLib/imjutils.pas deleted file mode 100644 index eb147b9c8..000000000 --- a/3rd/Imaging/Source/JpegLib/imjutils.pas +++ /dev/null @@ -1,232 +0,0 @@ -unit imjutils; - -{ This file contains tables and miscellaneous utility routines needed - for both compression and decompression. - Note we prefix all global names with "j" to minimize conflicts with - a surrounding application. } - -{ Source: jutils.c; Copyright (C) 1991-1996, Thomas G. Lane. } - -interface - -{$I imjconfig.inc} - -uses - imjmorecfg, - imjinclude, - imjpeglib; - - -{ jpeg_zigzag_order[i] is the zigzag-order position of the i'th element - of a DCT block read in natural order (left to right, top to bottom). } - - -{$ifdef FALSE} { This table is not actually needed in v6a } - -const - jpeg_zigzag_order : array[0..DCTSIZE2] of int = - (0, 1, 5, 6, 14, 15, 27, 28, - 2, 4, 7, 13, 16, 26, 29, 42, - 3, 8, 12, 17, 25, 30, 41, 43, - 9, 11, 18, 24, 31, 40, 44, 53, - 10, 19, 23, 32, 39, 45, 52, 54, - 20, 22, 33, 38, 46, 51, 55, 60, - 21, 34, 37, 47, 50, 56, 59, 61, - 35, 36, 48, 49, 57, 58, 62, 63); - -{$endif} - - -{ jpeg_natural_order[i] is the natural-order position of the i'th element - of zigzag order. - - When reading corrupted data, the Huffman decoders could attempt - to reference an entry beyond the end of this array (if the decoded - zero run length reaches past the end of the block). To prevent - wild stores without adding an inner-loop test, we put some extra - "63"s after the real entries. This will cause the extra coefficient - to be stored in location 63 of the block, not somewhere random. - The worst case would be a run-length of 15, which means we need 16 - fake entries. } - - -const - jpeg_natural_order : array[0..DCTSIZE2+16-1] of int = - (0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - 63, 63, 63, 63, 63, 63, 63, 63, { extra entries for safety in decoder } - 63, 63, 63, 63, 63, 63, 63, 63); - - - -{ Arithmetic utilities } - -{GLOBAL} -function jdiv_round_up (a : long; b : long) : long; - -{GLOBAL} -function jround_up (a : long; b : long) : long; - -{GLOBAL} -procedure jcopy_sample_rows (input_array : JSAMPARRAY; - source_row : int; - output_array : JSAMPARRAY; dest_row : int; - num_rows : int; num_cols : JDIMENSION); - -{GLOBAL} -procedure jcopy_block_row (input_row : JBLOCKROW; - output_row : JBLOCKROW; - num_blocks : JDIMENSION); - -{GLOBAL} -procedure jzero_far (target : pointer;{far} bytestozero : size_t); - -procedure FMEMZERO(target : pointer; size : size_t); - -procedure FMEMCOPY(dest,src : pointer; size : size_t); - -implementation - -{GLOBAL} -function jdiv_round_up (a : long; b : long) : long; -{ Compute a/b rounded up to next integer, ie, ceil(a/b) } -{ Assumes a >= 0, b > 0 } -begin - jdiv_round_up := (a + b - long(1)) div b; -end; - - -{GLOBAL} -function jround_up (a : long; b : long) : long; -{ Compute a rounded up to next multiple of b, ie, ceil(a/b)*b } -{ Assumes a >= 0, b > 0 } -begin - Inc(a, b - long(1)); - jround_up := a - (a mod b); -end; - -{ On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays - and coefficient-block arrays. This won't work on 80x86 because the arrays - are FAR and we're assuming a small-pointer memory model. However, some - DOS compilers provide far-pointer versions of memcpy() and memset() even - in the small-model libraries. These will be used if USE_FMEM is defined. - Otherwise, the routines below do it the hard way. (The performance cost - is not all that great, because these routines aren't very heavily used.) } - - -{$ifndef NEED_FAR_POINTERS} { normal case, same as regular macros } -procedure FMEMZERO(target : pointer; size : size_t); -begin - FillChar(target^, size, 0); -end; - -procedure FMEMCOPY(dest,src : pointer; size : size_t); -begin - Move(src^, dest^, size); -end; - - -{$else} { 80x86 case, define if we can } - {$ifdef USE_FMEM} - FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) - FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) - {$endif} -{$endif} - - -{GLOBAL} -procedure jcopy_sample_rows (input_array : JSAMPARRAY; source_row : int; - output_array : JSAMPARRAY; dest_row : int; - num_rows : int; num_cols : JDIMENSION); -{ Copy some rows of samples from one place to another. - num_rows rows are copied from input_array[source_row++] - to output_array[dest_row++]; these areas may overlap for duplication. - The source and destination arrays must be at least as wide as num_cols. } -var - inptr, outptr : JSAMPLE_PTR; {register} -{$ifdef FMEMCOPY} - count : size_t; {register} -{$else} - count : JDIMENSION; {register} -{$endif} - row : int; {register} -begin -{$ifdef FMEMCOPY} - count := size_t(num_cols * SIZEOF(JSAMPLE)); -{$endif} - Inc(JSAMPROW_PTR(input_array), source_row); - Inc(JSAMPROW_PTR(output_array), dest_row); - - for row := pred(num_rows) downto 0 do - begin - inptr := JSAMPLE_PTR(input_array^[0]); - Inc(JSAMPROW_PTR(input_array)); - outptr := JSAMPLE_PTR(output_array^[0]); - Inc(JSAMPROW_PTR(output_array)); -{$ifdef FMEMCOPY} - FMEMCOPY(outptr, inptr, count); -{$else} - for count := pred(num_cols) downto 0 do - begin - outptr^ := inptr^; { needn't bother with GETJSAMPLE() here } - Inc(inptr); - Inc(outptr); - end; -{$endif} - end; -end; - - -{GLOBAL} -procedure jcopy_block_row (input_row : JBLOCKROW; - output_row : JBLOCKROW; - num_blocks : JDIMENSION); -{ Copy a row of coefficient blocks from one place to another. } -{$ifdef FMEMCOPY} -begin - FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); -{$else} -var - inptr, outptr : JCOEFPTR; {register} - count : long; {register} -begin - inptr := JCOEFPTR (input_row); - outptr := JCOEFPTR (output_row); - for count := long(num_blocks) * DCTSIZE2 -1 downto 0 do - begin - outptr^ := inptr^; - Inc(outptr); - Inc(inptr); - end; -{$endif} -end; - - -{GLOBAL} -procedure jzero_far (target : pointer;{far} bytestozero : size_t); -{ Zero out a chunk of FAR memory. } -{ This might be sample-array data, block-array data, or alloc_large data. } -{$ifdef FMEMZERO} -begin - FMEMZERO(target, bytestozero); -{$else} -var - ptr : byteptr; - count : size_t; {register} -begin - ptr := target; - for count := bytestozero-1 downto 0 do - begin - ptr^ := 0; - Inc(ptr); - end; -{$endif} -end; - -end. diff --git a/3rd/Imaging/Source/JpegLib/readme.txt b/3rd/Imaging/Source/JpegLib/readme.txt deleted file mode 100644 index 3cbe89077..000000000 --- a/3rd/Imaging/Source/JpegLib/readme.txt +++ /dev/null @@ -1,381 +0,0 @@ -_____________________________________________________________________________ - -PASJPEG 1.1 May 29th, 1999 - -Based on the Independent JPEG Group's JPEG software release 6b - -Copyright (C) 1996,1998,1999 by NOMSSI NZALI Jacques H. C. -[kn&n DES] See "Legal issues" for conditions of distribution and use. -_____________________________________________________________________________ - - -Information in this file -======================== - - o Introduction - o Notes - o File list - o Translation - o Legal issues - o Archive Locations - -Introduction -============ - -PASJPEG is a port of the sixth public release of the IJG C source (release -6b of 27-Mar-98) [3], that implements JPEG baseline, extended-sequential, and -progressive compression processes to Turbo Pascal 7.0 for DOS (TP). The code -has been tested under Delphi 3.0, it can be ported to other Pascal -environments, since many compilers try to be compatible to TP. - -JPEG (pronounced "jay-peg") is a standardized familly of algorithms for -compression of continous tone still images. Most JPEG processes are lossy, -the output image is not exactly identical to the input image. However, on -typical photographic images, very good compression levels can be obtained -with no visible change, and remarkably high compression levels are possible -if you can tolerate a low-quality image [1],[2]. The Independent JPEG Group -(IJG) has created a free, portable C library for JPEG compression and -decompression of JPEG images. - -The IJG documentation (system architecture, using the IJG JPEG library, -usage and file list) is a must read. The files DEMO.PAS, TEST.PAS, CJPEG.PAS, -DJPEG.PAS and EXAMPLE.PAS demonstrate the usage of the JPEG decompression -and compression library. The RDJPGCOM application shows how to parse a JFIF -file. - -Notes: -====== - -* Please report any errors/problems you may find in code and in the - documentation (e.g. this README.TXT file). - -* The sample applications (CJPEG, DJPEG) doesn't support all the options - of the original C code. WRJPGCOM is not ported. - -* Environment variable JPEGMEM syntax changed; - -* You can modify the jpeg.pas unit from the Delphi 3 distribution to - use PasJPEG. - -Change log -========== - -1. bugs fixed: - * in procedure read_gif_map(), unit RDCOLMAP.PAS (used by DJPEG sample - application). Davie Lee Reed <smatters@iquest.net> - * -dct int and -dct fast now bytewise equal to the IJG output. - * -dct float produced large files - -2. Support for scripts - -3. BASM version of JIDCTINT.PAS for Delphi 2 and 3. - -4. images with integral sampling ratios were not decoded correctly. - Create a jpeg file with cjpeg and the option "-sample 4x1" and try to decode - it with any software that uses PasJpeg. Thanks to Jannie Gerber for reporting - this with a fix: In JDSAMPLE.PAS, procedure int_upsample(), - - for h := pred(h_expand) downto 0 do - begin - outptr^ := invalue; - +=> inc(outptr); { this is the culprit that was left out!!! } - Dec(outcount); - end; - -File list -========= - -Here is a road map to the files in the PasJPEG distribution. The -distribution includes the JPEG library proper, plus two application -programs ("cjpeg" and "djpeg") which use the library to convert JPEG -files to and from some other popular image formats. A third application -"jpegtran" uses the library to do lossless conversion between different -variants of JPEG. There is also the stand-alone applications "rdjpgcom". - -Documentation(see README for a guide to the documentation files): - -readme.txt Introduction, Documentation - -Additional files - -demo.pas Demo program, uses example.pas -example.pas Sample code for calling JPEG library. -test.pas Sample application code for demo.pas - -Configuration/installation files and programs (see install.doc for more info): - -jconfig.inc Configuration declarations. - -*.ijg script files - -Pascal source code files: - -jinclude.pas Central include file used by all IJG .c files to reference - system include files. -jpeglib.pas JPEG library's internal data structures, exported data - and function declarations. -jmorecfg.pas Additional configuration declarations; need not be changed - for a standard installation. -jdeferr.pas defines the error and message text. -jerror.pas Declares JPEG library's error and trace message codes. -jinclude.pas the place to specify system depedent input/output code. -jdct.pas Private declarations for forward & reverse DCT subsystems. - -These files contain most of the functions intended to be called directly by -an application program: - -jcapimin.pas Application program interface: core routines for compression. -jcapistd.pas Application program interface: standard compression. -jdapimin.pas Application program interface: core routines for decompression. -jdapistd.pas Application program interface: standard decompression. -jcomapi.pas Application program interface routines common to compression - and decompression. -jcparam.pas Compression parameter setting helper routines. -jctrans.pas API and library routines for transcoding compression. -jdtrans.pas API and library routines for transcoding decompression. - -Compression side of the library: - -jcinit.pas Initialization: determines which other modules to use. -jcmaster.pas Master control: setup and inter-pass sequencing logic. -jcmainct.pas Main buffer controller (preprocessor => JPEG compressor). -jcprepct.pas Preprocessor buffer controller. -jccoefct.pas Buffer controller for DCT coefficient buffer. -jccolor.pas Color space conversion. -jcsample.pas Downsampling. -jcdctmgr.pas DCT manager (DCT implementation selection & control). -jfdctint.pas Forward DCT using slow-but-accurate integer method. -jfdctfst.pas Forward DCT using faster, less accurate integer method. -jfdctflt.pas Forward DCT using floating-point arithmetic. -jchuff.pas Huffman entropy coding for sequential JPEG. -jcphuff.pas Huffman entropy coding for progressive JPEG. -jcmarker.pas JPEG marker writing. -jdatadst.pas Data destination manager for stdio output. - -Decompression side of the library: - -jdmaster.pas Master control: determines which other modules to use. -jdinput.pas Input controller: controls input processing modules. -jdmainct.pas Main buffer controller (JPEG decompressor => postprocessor). -jdcoefct.pas Buffer controller for DCT coefficient buffer. -jdpostct.pas Postprocessor buffer controller. -jdmarker.pas JPEG marker reading. -jdhuff.pas Huffman entropy decoding for sequential JPEG. -jdphuff.pas Huffman entropy decoding for progressive JPEG. -jddctmgr.pas IDCT manager (IDCT implementation selection & control). -jidctint.pas Inverse DCT using slow-but-accurate integer method. -jidctasm.pas BASM specific version of jidctint.pas for 32bit Delphi. -jidctfst.pas Inverse DCT using faster, less accurate integer method. -jidctflt.pas Inverse DCT using floating-point arithmetic. -jidctred.pas Inverse DCTs with reduced-size outputs. -jidct2d.pas How to for a direct 2D Inverse DCT - not used -jdsample.pas Upsampling. -jdcolor.pas Color space conversion. -jdmerge.pas Merged upsampling/color conversion (faster, lower quality). -jquant1.pas One-pass color quantization using a fixed-spacing colormap. -jquant2.pas Two-pass color quantization using a custom-generated colormap. - Also handles one-pass quantization to an externally given map. -jdatasrc.pas Data source manager for stdio input. - -Support files for both compression and decompression: - -jerror.pas Standard error handling routines (application replaceable). -jmemmgr.pas System-independent (more or less) memory management code. -jutils.pas Miscellaneous utility routines. - -jmemmgr.pas relies on a system-dependent memory management module. The -PASJPEG distribution includes the following implementations of the system- -dependent module: - -jmemnobs.pas "No backing store": assumes adequate virtual memory exists. -jmemdos.pas Custom implementation for MS-DOS (16-bit environment only): - can use extended and expanded memory as well as temporary - files. -jmemsys.pas A skeleton with all the declaration you need to create a - working system-dependent JPEG memory manager on unusual - systems. - -Exactly one of the system-dependent units should be used in jmemmgr.pas. - -jmemdosa.pas BASM 80x86 assembly code support for jmemdos.pas; used only - in MS-DOS-specific configurations of the JPEG library. - - -Applications using the library should use jmorecfg, jerror, jpeglib, and -include jconfig.inc. - -CJPEG/DJPEG/JPEGTRAN - -Pascal source code files: - -cderror.pas Additional error and trace message codes for cjpeg/djpeg. - Not used, Those errors have been added to jdeferr. -cjpeg.pas Main program for cjpeg. -djpeg.pas Main program for djpeg. -jpegtran.pas Main program for jpegtran. -cdjpeg.pas Utility routines used by all three programs. -rdcolmap.pas Code to read a colormap file for djpeg's "-map" switch. -rdswitch.pas Code to process some of cjpeg's more complex switches. - Also used by jpegtran. -transupp.pas Support code for jpegtran: lossless image manipulations. - -fcache.pas -rdswitch.pas Code to process some of cjpeg's more complex switches. - Also used by jpegtran. - -Image file writer modules for djpeg: - -wrbmp.pas BMP file output. -wrppm.pas PPM/PGM file output. -wrtarga.pas Targa file output. - -Image file reader modules for cjpeg: - -rdbmp.pas BMP file input. -rdppm.pas PPM/PGM file input. -rdtarga.pas Targa file input. - NOT READY YET - -This program does not depend on the JPEG library - -rdjpgcom.pas Stand-alone rdjpgcom application. - - -Translation -=========== - -TP is unit-centric, exported type definitions and routines are declared -in the "interface" part of the unit, "make" files are not needed. -Macros are not supported, they were either copied as needed or translated -to Pascal routines (procedure). The procedures will be replaced by code in -later releases. -Conditional defines that indicate whether to include various optional -functions are defined in the file JCONFIG.INC. This file is included first -in all source files. - -The base type definitions are in the unit JMORECFG.PAS. The error handling -macros have been converted to procedures in JERROR.PAS. The error codes are -in JDEFERR.PAS. jpegint.h and jpeglib.h were merged into one large unit -JPEGLIB.PAS containing type definitions with global scope. - -The translation of the header file is the most sophisticated work, a good -understanding of the syntax is required. Once the header files are done, -the translation turns into a lot of editing work. Each C source file was -converted to a unit by editing the syntax (separate variable definition -and usage, define labels, group variable definitions, expanding macros, etc). - -The IJG source labels routines GLOBAL, METHODDEF and LOCAL. All globals -routines are in the interface section of the units. The "far" directive is -used for methods (METHODDEF). - -Some C -> Pascal examples. - -* "{" -> "begin" "->" -> "^." " = " -> " := " "<<" -> " shl " - "}" -> "end;" "!=" -> "<>" " == " -> " = " ">>" -> " shr " - "/*" -> "{" routine -> function "0x" -> "$" - "*/" -> "}" (void) procedure "NULL" -> "NIL" - -* structs are records, Unions are variable records, pointers are always far, - the operators && and || (and/or) have not the same priority in both - languages, so parenthesis are important. The Pascal "case" doesn't have the - falltrough option of the C "switch" statement, my work around is to split - one "switch" statement into many case statements. -* The pointer type in C is not readily interchangeable. It is used to address - an array (Pascal pointer to an array) or in pointer arithmetic a pointer to - a single element. I've used the Inc() statement with type casting to - translate pointer arithmetic most of the time. - - C example: - typedef JSAMPLE* JSAMPROW; /* ptr to one image row of pixel samples. */ - - Pascal - type - JSAMPLE_PTR = ^JSAMPLE; { ptr to a single pixel sample. } - jTSample = 0..(MaxInt div SIZEOF(JSAMPLE))-1; - JSAMPLE_ARRAY = Array[jTSample] of JSAMPLE; {far} - JSAMPROW = ^JSAMPLE_ARRAY; { ptr to one image row of pixel samples. } - - The following code - - JSAMPROW buffer0, buffer1; /* ptr to a JSAMPLE buffer. */ - - ... - - buffer1 = buffer0 + i; - - can be translated to - - var - buffer0, buffer1 : JSAMPROW; - - ... - - buffer1 := buffer0; - Inc(JSAMPLE_PTR(buffer1), i); - - or - - buffer1 := JSAMPROW(@ buffer0^[i]); - - Declaring the variables as JSAMPLE_PTR may reduce type casting in some - places. I use help pointers to handle negative array offsets. - -While translating the type of function parameter from C to Pascal, one can -often use "var", "const", or "array of" parameters instead of pointers. - -While translating for(;;)-loops with more than one induction variable to -Pascal "for to/downto do"-loops, the extra induction variables have to be -manually updated at the end of the loop and before "continue"-statements. - - -Legal issues -============ - -Copyright (C) 1996,1998 by Jacques Nomssi Nzali - - This software is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -Archive Locations: -================== - -[1] Thomas G. Lane, JPEG FAQ - - in comp.graphics.misc and related newsgroups - -[2] Wallace, Gregory K.: The JPEG Still Picture Compression Standard - - ftp.uu.net, graphics/jpeg/wallace.ps.Z - -[3] The Independent JPEG Group C library for JPEG encoding and decoding, - rev 6b. - - ftp://ftp.uu.net/graphics/jpeg/ - - or SimTel in msdos/graphics/ - -[4] JPEG implementation, written by the PVRG group at Stanford, - ftp havefun.stanford.edu:/pub/jpeg/JPEGv1.2.tar.Z. - -[5] PASJPEG.ZIP at NView ftp site - - ftp://druckfix.physik.tu-chemnitz.de/pub/nv/ - http://www.tu-chemnitz.de/~nomssi/pub/pasjpeg.zip - -[6] The PasJPEG home page with links - - http://www.tu-chemnitz.de/~nomssi/pasjpeg.html -_____________________________________________________________________________ \ No newline at end of file diff --git a/3rd/Imaging/Source/ZLib/dzlib.pas b/3rd/Imaging/Source/ZLib/dzlib.pas deleted file mode 100644 index 37a0da0af..000000000 --- a/3rd/Imaging/Source/ZLib/dzlib.pas +++ /dev/null @@ -1,523 +0,0 @@ -{*******************************************************} -{ } -{ Delphi Supplemental Components } -{ ZLIB Data Compression Interface Unit } -{ } -{ Copyright (c) 1997 Borland International } -{ Copyright (c) 1998 Jacques Nomssi Nzali } -{ } -{*******************************************************} - -{ - Modified for - Vampyre Imaging Library - by Marek Mauder - http://imaginglib.sourceforge.net - - You can choose which pascal zlib implementation will be - used. IMPASZLIB and FPCPASZLIB are translations of zlib - to pascal so they don't need any *.obj files. - The others are interfaces to *.obj files (Windows) or - *.so libraries (Linux). - Default implementation is IMPASZLIB because it can be compiled - by all supported compilers and works on all supported platforms. - I usually use implementation with the fastest decompression - when building release Win32 binaries. - FPCPASZLIB is useful for Lazarus applications. FPC's zlib is linked - to exe by default so there is no need to link additional (and almost identical) - IMPASZLIB. - - There is a small speed comparison table of some of the - supported implementations (TGA image 28�311�570 bytes, compression level = 6, - Delphi 9, Win32, Athlon XP 1900). - - ZLib version Decompression Compression Comp. Size - IMPASZLIB | 1.1.2 | 824 ms | 4 280 ms | 18 760 133 B - ZLIBEX | 1.2.2 | 710 ms | 1 590 ms* | 19 056 621 B - DELPHIZLIB | 1.0.4 | 976 ms | 9 190 ms | 18 365 562 B - ZLIBPAS | 1.2.3 | 680 ms | 3 790 ms | 18 365 387 B - * obj files are compiled with compression level hardcoded to 1 (fastest) -} - -unit dzlib; - -{$I ImagingOptions.inc} - -interface - -{$DEFINE IMPASZLIB} -{ $DEFINE ZLIBPAS} -{ $DEFINE FPCPASZLIB} -{ $DEFINE ZLIBEX} -{ $DEFINE DELPHIZLIB} - -{ Automatically use FPC's PasZLib when compiling with FPC.} - -{$IFDEF FPC} - {$UNDEF IMPASZLIB} - {$DEFINE FPCPASZLIB} -{$ENDIF} - -uses -{$IF Defined(IMPASZLIB)} - { Use paszlib modified by me for Delphi and FPC } - imzdeflate, imzinflate, impaszlib, -{$ELSEIF Defined(FPCPASZLIB)} - { Use FPC's paszlib } - zbase, paszlib, -{$ELSEIF Defined(ZLIBPAS)} - { Pascal interface to ZLib shipped with ZLib C source } - zlibpas, -{$ELSEIF Defined(ZLIBEX)} - { Use ZlibEx unit } - ZLibEx, -{$ELSEIF Defined(DELPHIZLIB)} - { Use ZLib unit shipped with Delphi } - ZLib, -{$IFEND} - ImagingTypes, SysUtils, Classes; - -{$IF Defined(IMPASZLIB) or Defined(FPCPASZLIB) or Defined(ZLIBPAS)} -type - TZStreamRec = z_stream; -{$IFEND} - -const - Z_NO_FLUSH = 0; - Z_PARTIAL_FLUSH = 1; - Z_SYNC_FLUSH = 2; - Z_FULL_FLUSH = 3; - Z_FINISH = 4; - - Z_OK = 0; - Z_STREAM_END = 1; - Z_NEED_DICT = 2; - Z_ERRNO = -1; - Z_STREAM_ERROR = -2; - Z_DATA_ERROR = -3; - Z_MEM_ERROR = -4; - Z_BUF_ERROR = -5; - Z_VERSION_ERROR = -6; - - Z_NO_COMPRESSION = 0; - Z_BEST_SPEED = 1; - Z_BEST_COMPRESSION = 9; - Z_DEFAULT_COMPRESSION = -1; - - Z_FILTERED = 1; - Z_HUFFMAN_ONLY = 2; - Z_RLE = 3; - Z_DEFAULT_STRATEGY = 0; - - Z_BINARY = 0; - Z_ASCII = 1; - Z_UNKNOWN = 2; - - Z_DEFLATED = 8; - -type - { Abstract ancestor class } - TCustomZlibStream = class(TStream) - private - FStrm: TStream; - FStrmPos: Integer; - FOnProgress: TNotifyEvent; - FZRec: TZStreamRec; - FBuffer: array [Word] of Byte; - protected - procedure Progress(Sender: TObject); dynamic; - property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; - constructor Create(Strm: TStream); - end; - -{ TCompressionStream compresses data on the fly as data is written to it, and - stores the compressed data to another stream. - - TCompressionStream is write-only and strictly sequential. Reading from the - stream will raise an exception. Using Seek to move the stream pointer - will raise an exception. - - Output data is cached internally, written to the output stream only when - the internal output buffer is full. All pending output data is flushed - when the stream is destroyed. - - The Position property returns the number of uncompressed bytes of - data that have been written to the stream so far. - - CompressionRate returns the on-the-fly percentage by which the original - data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 - If raw data size = 100 and compressed data size = 25, the CompressionRate - is 75% - - The OnProgress event is called each time the output buffer is filled and - written to the output stream. This is useful for updating a progress - indicator when you are writing a large chunk of data to the compression - stream in a single call.} - - - TCompressionLevel = (clNone, clFastest, clDefault, clMax); - - TCompressionStream = class(TCustomZlibStream) - private - function GetCompressionRate: Single; - public - constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream); - destructor Destroy; override; - function Read(var Buffer; Count: Longint): Longint; override; - function Write(const Buffer; Count: Longint): Longint; override; - function Seek(Offset: Longint; Origin: Word): Longint; override; - property CompressionRate: Single read GetCompressionRate; - property OnProgress; - end; - -{ TDecompressionStream decompresses data on the fly as data is read from it. - - Compressed data comes from a separate source stream. TDecompressionStream - is read-only and unidirectional; you can seek forward in the stream, but not - backwards. The special case of setting the stream position to zero is - allowed. Seeking forward decompresses data until the requested position in - the uncompressed data has been reached. Seeking backwards, seeking relative - to the end of the stream, requesting the size of the stream, and writing to - the stream will raise an exception. - - The Position property returns the number of bytes of uncompressed data that - have been read from the stream so far. - - The OnProgress event is called each time the internal input buffer of - compressed data is exhausted and the next block is read from the input stream. - This is useful for updating a progress indicator when you are reading a - large chunk of data from the decompression stream in a single call.} - - TDecompressionStream = class(TCustomZlibStream) - public - constructor Create(Source: TStream); - destructor Destroy; override; - function Read(var Buffer; Count: Longint): Longint; override; - function Write(const Buffer; Count: Longint): Longint; override; - function Seek(Offset: Longint; Origin: Word): Longint; override; - property OnProgress; - end; - - - -{ CompressBuf compresses data, buffer to buffer, in one call. - In: InBuf = ptr to compressed data - InBytes = number of bytes in InBuf - Out: OutBuf = ptr to newly allocated buffer containing decompressed data - OutBytes = number of bytes in OutBuf } -procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; - var OutBuf: Pointer; var OutBytes: Integer; - CompressLevel: Integer = Z_DEFAULT_COMPRESSION; - CompressStrategy: Integer = Z_DEFAULT_STRATEGY); - -{ DecompressBuf decompresses data, buffer to buffer, in one call. - In: InBuf = ptr to compressed data - InBytes = number of bytes in InBuf - OutEstimate = zero, or est. size of the decompressed data - Out: OutBuf = ptr to newly allocated buffer containing decompressed data - OutBytes = number of bytes in OutBuf } -procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; - OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer); - - -type - EZlibError = class(Exception); - ECompressionError = class(EZlibError); - EDecompressionError = class(EZlibError); - -implementation - -const - ZErrorMessages: array[0..9] of PAnsiChar = ( - 'need dictionary', // Z_NEED_DICT (2) - 'stream end', // Z_STREAM_END (1) - '', // Z_OK (0) - 'file error', // Z_ERRNO (-1) - 'stream error', // Z_STREAM_ERROR (-2) - 'data error', // Z_DATA_ERROR (-3) - 'insufficient memory', // Z_MEM_ERROR (-4) - 'buffer error', // Z_BUF_ERROR (-5) - 'incompatible version', // Z_VERSION_ERROR (-6) - ''); - -function zlibAllocMem(AppData: Pointer; Items, Size: Cardinal): Pointer; -begin - GetMem(Result, Items*Size); -end; - -procedure zlibFreeMem(AppData, Block: Pointer); -begin - FreeMem(Block); -end; - -function CCheck(code: Integer): Integer; -begin - Result := code; - if code < 0 then - raise ECompressionError.Create('zlib: ' + ZErrorMessages[2 - code]); -end; - -function DCheck(code: Integer): Integer; -begin - Result := code; - if code < 0 then - raise EDecompressionError.Create('zlib: ' + ZErrorMessages[2 - code]); -end; - -procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; - var OutBuf: Pointer; var OutBytes: Integer; - CompressLevel, CompressStrategy: Integer); -var - strm: TZStreamRec; - P: Pointer; -begin - FillChar(strm, sizeof(strm), 0); -{$IFNDEF FPCPASZLIB} - strm.zalloc := @zlibAllocMem; - strm.zfree := @zlibFreeMem; -{$ENDIF} - OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; - GetMem(OutBuf, OutBytes); - try - strm.next_in := InBuf; - strm.avail_in := InBytes; - strm.next_out := OutBuf; - strm.avail_out := OutBytes; - - CCheck(deflateInit2(strm, CompressLevel, Z_DEFLATED, MAX_WBITS, - DEF_MEM_LEVEL, CompressStrategy)); - - try - while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do - begin - P := OutBuf; - Inc(OutBytes, 256); - ReallocMem(OutBuf, OutBytes); - strm.next_out := Pointer(PtrUInt(OutBuf) + (PtrUInt(strm.next_out) - PtrUInt(P))); - strm.avail_out := 256; - end; - finally - CCheck(deflateEnd(strm)); - end; - ReallocMem(OutBuf, strm.total_out); - OutBytes := strm.total_out; - except - zlibFreeMem(nil, OutBuf); - raise - end; -end; - -procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; - OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer); -var - strm: TZStreamRec; - P: Pointer; - BufInc: Integer; -begin - FillChar(strm, sizeof(strm), 0); -{$IFNDEF FPCPASZLIB} - strm.zalloc := @zlibAllocMem; - strm.zfree := @zlibFreeMem; -{$ENDIF} - BufInc := (InBytes + 255) and not 255; - if OutEstimate = 0 then - OutBytes := BufInc - else - OutBytes := OutEstimate; - GetMem(OutBuf, OutBytes); - try - strm.next_in := InBuf; - strm.avail_in := InBytes; - strm.next_out := OutBuf; - strm.avail_out := OutBytes; - DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); - try - while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do - begin - P := OutBuf; - Inc(OutBytes, BufInc); - ReallocMem(OutBuf, OutBytes); - strm.next_out := Pointer(PtrUInt(OutBuf) + (PtrUInt(strm.next_out) - PtrUInt(P))); - strm.avail_out := BufInc; - end; - finally - DCheck(inflateEnd(strm)); - end; - ReallocMem(OutBuf, strm.total_out); - OutBytes := strm.total_out; - except - zlibFreeMem(nil, OutBuf); - raise - end; -end; - - -{ TCustomZlibStream } - -constructor TCustomZLibStream.Create(Strm: TStream); -begin - inherited Create; - FStrm := Strm; - FStrmPos := Strm.Position; -{$IFNDEF FPCPASZLIB} - FZRec.zalloc := @zlibAllocMem; - FZRec.zfree := @zlibFreeMem; -{$ENDIF} -end; - -procedure TCustomZLibStream.Progress(Sender: TObject); -begin - if Assigned(FOnProgress) then FOnProgress(Sender); -end; - -{ TCompressionStream } - -constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel; - Dest: TStream); -const - Levels: array [TCompressionLevel] of ShortInt = - (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); -begin - inherited Create(Dest); - FZRec.next_out := @FBuffer; - FZRec.avail_out := sizeof(FBuffer); - CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec))); -end; - -destructor TCompressionStream.Destroy; -begin - FZRec.next_in := nil; - FZRec.avail_in := 0; - try - if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; - while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END) - and (FZRec.avail_out = 0) do - begin - FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); - FZRec.next_out := @FBuffer; - FZRec.avail_out := sizeof(FBuffer); - end; - if FZRec.avail_out < sizeof(FBuffer) then - FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out); - finally - deflateEnd(FZRec); - end; - inherited Destroy; -end; - -function TCompressionStream.Read(var Buffer; Count: Longint): Longint; -begin - raise ECompressionError.Create('Invalid stream operation'); -end; - -function TCompressionStream.Write(const Buffer; Count: Longint): Longint; -begin - FZRec.next_in := @Buffer; - FZRec.avail_in := Count; - if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; - while (FZRec.avail_in > 0) do - begin - CCheck(deflate(FZRec, 0)); - if FZRec.avail_out = 0 then - begin - FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); - FZRec.next_out := @FBuffer; - FZRec.avail_out := sizeof(FBuffer); - FStrmPos := FStrm.Position; - Progress(Self); - end; - end; - Result := Count; -end; - -function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; -begin - if (Offset = 0) and (Origin = soFromCurrent) then - Result := FZRec.total_in - else - raise ECompressionError.Create('Invalid stream operation'); -end; - -function TCompressionStream.GetCompressionRate: Single; -begin - if FZRec.total_in = 0 then - Result := 0 - else - Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0; -end; - -{ TDecompressionStream } - -constructor TDecompressionStream.Create(Source: TStream); -begin - inherited Create(Source); - FZRec.next_in := @FBuffer; - FZRec.avail_in := 0; - DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec))); -end; - -destructor TDecompressionStream.Destroy; -begin - inflateEnd(FZRec); - inherited Destroy; -end; - -function TDecompressionStream.Read(var Buffer; Count: Longint): Longint; -begin - FZRec.next_out := @Buffer; - FZRec.avail_out := Count; - if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; - while (FZRec.avail_out > 0) do - begin - if FZRec.avail_in = 0 then - begin - FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); - if FZRec.avail_in = 0 then - begin - Result := Count - Integer(FZRec.avail_out); - Exit; - end; - FZRec.next_in := @FBuffer; - FStrmPos := FStrm.Position; - Progress(Self); - end; - CCheck(inflate(FZRec, 0)); - end; - Result := Count; -end; - -function TDecompressionStream.Write(const Buffer; Count: Longint): Longint; -begin - raise EDecompressionError.Create('Invalid stream operation'); -end; - -function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; -var - I: Integer; - Buf: array [0..4095] of Byte; -begin - if (Offset = 0) and (Origin = soFromBeginning) then - begin - DCheck(inflateReset(FZRec)); - FZRec.next_in := @FBuffer; - FZRec.avail_in := 0; - FStrm.Position := 0; - FStrmPos := 0; - end - else if ( (Offset >= 0) and (Origin = soFromCurrent)) or - ( ((Offset - Integer(FZRec.total_out)) > 0) and (Origin = soFromBeginning)) then - begin - if Origin = soFromBeginning then Dec(Offset, FZRec.total_out); - if Offset > 0 then - begin - for I := 1 to Offset div sizeof(Buf) do - ReadBuffer(Buf, sizeof(Buf)); - ReadBuffer(Buf, Offset mod sizeof(Buf)); - end; - end - else - raise EDecompressionError.Create('Invalid stream operation'); - Result := FZRec.total_out; -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/imadler.pas b/3rd/Imaging/Source/ZLib/imadler.pas deleted file mode 100644 index 4438056cc..000000000 --- a/3rd/Imaging/Source/ZLib/imadler.pas +++ /dev/null @@ -1,114 +0,0 @@ -Unit imadler; - -{ - adler32.c -- compute the Adler-32 checksum of a data stream - Copyright (C) 1995-1998 Mark Adler - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -uses - imzutil; - -function adler32(adler : uLong; buf : pBytef; len : uInt) : uLong; - -{ Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NIL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - var - adler : uLong; - begin - adler := adler32(0, Z_NULL, 0); - - while (read_buffer(buffer, length) <> EOF) do - adler := adler32(adler, buffer, length); - - if (adler <> original_adler) then - error(); - end; -} - -implementation - -const - BASE = uLong(65521); { largest prime smaller than 65536 } - {NMAX = 5552; original code with unsigned 32 bit integer } - { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 } - NMAX = 3854; { code with signed 32 bit integer } - { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 } - { The penalty is the time loss in the extra MOD-calls. } - - -{ ========================================================================= } - -function adler32(adler : uLong; buf : pBytef; len : uInt) : uLong; -var - s1, s2 : uLong; - k : int; -begin - s1 := adler and $ffff; - s2 := (adler shr 16) and $ffff; - - if not Assigned(buf) then - begin - adler32 := uLong(1); - exit; - end; - - while (len > 0) do - begin - if len < NMAX then - k := len - else - k := NMAX; - Dec(len, k); - { - while (k >= 16) do - begin - DO16(buf); - Inc(buf, 16); - Dec(k, 16); - end; - if (k <> 0) then - repeat - Inc(s1, buf^); - Inc(puf); - Inc(s2, s1); - Dec(k); - until (k = 0); - } - while (k > 0) do - begin - Inc(s1, buf^); - Inc(s2, s1); - Inc(buf); - Dec(k); - end; - s1 := s1 mod BASE; - s2 := s2 mod BASE; - end; - adler32 := (s2 shl 16) or s1; -end; - -{ -#define DO1(buf,i) - begin - Inc(s1, buf[i]); - Inc(s2, s1); - end; -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); -} -end. - diff --git a/3rd/Imaging/Source/ZLib/iminfblock.pas b/3rd/Imaging/Source/ZLib/iminfblock.pas deleted file mode 100644 index 7ab003ff0..000000000 --- a/3rd/Imaging/Source/ZLib/iminfblock.pas +++ /dev/null @@ -1,951 +0,0 @@ -Unit iminfblock; - -{ infblock.h and - infblock.c -- interpret and process block types to last block - Copyright (C) 1995-1998 Mark Adler - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -uses - {$IFDEF DEBUG} - SysUtils, strutils, - {$ENDIF} - imzutil, impaszlib; - -function inflate_blocks_new(var z : z_stream; - c : check_func; { check function } - w : uInt { window size } - ) : pInflate_blocks_state; - -function inflate_blocks (var s : inflate_blocks_state; - var z : z_stream; - r : int { initial return code } - ) : int; - -procedure inflate_blocks_reset (var s : inflate_blocks_state; - var z : z_stream; - c : puLong); { check value on output } - - -function inflate_blocks_free(s : pInflate_blocks_state; - var z : z_stream) : int; - -procedure inflate_set_dictionary(var s : inflate_blocks_state; - const d : array of byte; { dictionary } - n : uInt); { dictionary length } - -function inflate_blocks_sync_point(var s : inflate_blocks_state) : int; - -implementation - -uses - iminfcodes, iminftrees, iminfutil; - -{ Tables for deflate from PKZIP's appnote.txt. } -Const - border : Array [0..18] Of Word { Order of the bit length code lengths } - = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15); - -{ Notes beyond the 1.93a appnote.txt: - - 1. Distance pointers never point before the beginning of the output - stream. - 2. Distance pointers can point back across blocks, up to 32k away. - 3. There is an implied maximum of 7 bits for the bit length table and - 15 bits for the actual data. - 4. If only one code exists, then it is encoded using one bit. (Zero - would be more efficient, but perhaps a little confusing.) If two - codes exist, they are coded using one bit each (0 and 1). - 5. There is no way of sending zero distance codes--a dummy must be - sent if there are none. (History: a pre 2.0 version of PKZIP would - store blocks with no distance codes, but this was discovered to be - too harsh a criterion.) Valid only for 1.93a. 2.04c does allow - zero distance codes, which is sent as one code of zero bits in - length. - 6. There are up to 286 literal/length codes. Code 256 represents the - end-of-block. Note however that the static length tree defines - 288 codes just to fill out the Huffman codes. Codes 286 and 287 - cannot be used though, since there is no length base or extra bits - defined for them. Similarily, there are up to 30 distance codes. - However, static trees define 32 codes (all 5 bits) to fill out the - Huffman codes, but the last two had better not show up in the data. - 7. Unzip can check dynamic Huffman blocks for complete code sets. - The exception is that a single code would not be complete (see #4). - 8. The five bits following the block type is really the number of - literal codes sent minus 257. - 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits - (1+6+6). Therefore, to output three times the length, you output - three codes (1+1+1), whereas to output four times the same length, - you only need two codes (1+3). Hmm. - 10. In the tree reconstruction algorithm, Code = Code + Increment - only if BitLength(i) is not zero. (Pretty obvious.) - 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) - 12. Note: length code 284 can represent 227-258, but length code 285 - really is 258. The last length deserves its own, short code - since it gets used a lot in very redundant files. The length - 258 is special since 258 - 3 (the min match length) is 255. - 13. The literal/length and distance code bit lengths are read as a - single stream of lengths. It is possible (and advantageous) for - a repeat code (16, 17, or 18) to go across the boundary between - the two sets of lengths. } - - -procedure inflate_blocks_reset (var s : inflate_blocks_state; - var z : z_stream; - c : puLong); { check value on output } -begin - if (c <> Z_NULL) then - c^ := s.check; - if (s.mode = BTREE) or (s.mode = DTREE) then - ZFREE(z, s.sub.trees.blens); - if (s.mode = CODES) then - inflate_codes_free(s.sub.decode.codes, z); - - s.mode := ZTYPE; - s.bitk := 0; - s.bitb := 0; - - s.write := s.window; - s.read := s.window; - if Assigned(s.checkfn) then - begin - s.check := s.checkfn(uLong(0), pBytef(NIL), 0); - z.adler := s.check; - end; - {$IFDEF DEBUG} - Tracev('inflate: blocks reset'); - {$ENDIF} -end; - - -function inflate_blocks_new(var z : z_stream; - c : check_func; { check function } - w : uInt { window size } - ) : pInflate_blocks_state; -var - s : pInflate_blocks_state; -begin - s := pInflate_blocks_state( ZALLOC(z,1, sizeof(inflate_blocks_state)) ); - if (s = Z_NULL) then - begin - inflate_blocks_new := s; - exit; - end; - s^.hufts := huft_ptr( ZALLOC(z, sizeof(inflate_huft), MANY) ); - - if (s^.hufts = Z_NULL) then - begin - ZFREE(z, s); - inflate_blocks_new := Z_NULL; - exit; - end; - - s^.window := pBytef( ZALLOC(z, 1, w) ); - if (s^.window = Z_NULL) then - begin - ZFREE(z, s^.hufts); - ZFREE(z, s); - inflate_blocks_new := Z_NULL; - exit; - end; - s^.zend := s^.window; - Inc(s^.zend, w); - s^.checkfn := c; - s^.mode := ZTYPE; - {$IFDEF DEBUG} - Tracev('inflate: blocks allocated'); - {$ENDIF} - inflate_blocks_reset(s^, z, Z_NULL); - inflate_blocks_new := s; -end; - - -function inflate_blocks (var s : inflate_blocks_state; - var z : z_stream; - r : int) : int; { initial return code } -label - start_btree, start_dtree, - start_blkdone, start_dry, - start_codes; - -var - t : uInt; { temporary storage } - b : uLong; { bit buffer } - k : uInt; { bits in bit buffer } - p : pBytef; { input data pointer } - n : uInt; { bytes available there } - q : pBytef; { output window write pointer } - m : uInt; { bytes to end of window or read pointer } -{ fixed code blocks } -var - bl, bd : uInt; - tl, td : pInflate_huft; -var - h : pInflate_huft; - i, j, c : uInt; -var - cs : pInflate_codes_state; -begin - { copy input/output information to locals } - p := z.next_in; - n := z.avail_in; - b := s.bitb; - k := s.bitk; - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - -{ decompress an inflated block } - - - { process input based on current state } - while True do - Case s.mode of - ZTYPE: - begin - {NEEDBITS(3);} - while (k < 3) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - t := uInt(b) and 7; - s.last := boolean(t and 1); - case (t shr 1) of - 0: { stored } - begin - {$IFDEF DEBUG} - if s.last then - Tracev('inflate: stored block (last)') - else - Tracev('inflate: stored block'); - {$ENDIF} - {DUMPBITS(3);} - b := b shr 3; - Dec(k, 3); - - t := k and 7; { go to byte boundary } - {DUMPBITS(t);} - b := b shr t; - Dec(k, t); - - s.mode := LENS; { get length of stored block } - end; - 1: { fixed } - begin - begin - {$IFDEF DEBUG} - if s.last then - Tracev('inflate: fixed codes blocks (last)') - else - Tracev('inflate: fixed codes blocks'); - {$ENDIF} - inflate_trees_fixed(bl, bd, tl, td, z); - s.sub.decode.codes := inflate_codes_new(bl, bd, tl, td, z); - if (s.sub.decode.codes = Z_NULL) then - begin - r := Z_MEM_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - end; - {DUMPBITS(3);} - b := b shr 3; - Dec(k, 3); - - s.mode := CODES; - end; - 2: { dynamic } - begin - {$IFDEF DEBUG} - if s.last then - Tracev('inflate: dynamic codes block (last)') - else - Tracev('inflate: dynamic codes block'); - {$ENDIF} - {DUMPBITS(3);} - b := b shr 3; - Dec(k, 3); - - s.mode := TABLE; - end; - 3: - begin { illegal } - {DUMPBITS(3);} - b := b shr 3; - Dec(k, 3); - - s.mode := BLKBAD; - z.msg := 'invalid block type'; - r := Z_DATA_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - end; - end; - LENS: - begin - {NEEDBITS(32);} - while (k < 32) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - if (((not b) shr 16) and $ffff) <> (b and $ffff) then - begin - s.mode := BLKBAD; - z.msg := 'invalid stored block lengths'; - r := Z_DATA_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - s.sub.left := uInt(b) and $ffff; - k := 0; - b := 0; { dump bits } - {$IFDEF DEBUG} - Tracev('inflate: stored length '+IntToStr(s.sub.left)); - {$ENDIF} - if s.sub.left <> 0 then - s.mode := STORED - else - if s.last then - s.mode := DRY - else - s.mode := ZTYPE; - end; - STORED: - begin - if (n = 0) then - begin - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - {NEEDOUT} - if (m = 0) then - begin - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - end; - - if (m = 0) then - begin - {FLUSH} - s.write := q; - r := inflate_flush(s,z,r); - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - end; - - if (m = 0) then - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - end; - end; - r := Z_OK; - - t := s.sub.left; - if (t > n) then - t := n; - if (t > m) then - t := m; - zmemcpy(q, p, t); - Inc(p, t); Dec(n, t); - Inc(q, t); Dec(m, t); - Dec(s.sub.left, t); - if (s.sub.left = 0) then - begin - {$IFDEF DEBUG} - if (ptr2int(q) >= ptr2int(s.read)) then - Tracev('inflate: stored end '+ - IntToStr(z.total_out + ptr2int(q) - ptr2int(s.read)) + ' total out') - else - Tracev('inflate: stored end '+ - IntToStr(z.total_out + ptr2int(s.zend) - ptr2int(s.read) + - ptr2int(q) - ptr2int(s.window)) + ' total out'); - {$ENDIF} - if s.last then - s.mode := DRY - else - s.mode := ZTYPE; - end; - end; - TABLE: - begin - {NEEDBITS(14);} - while (k < 14) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - t := uInt(b) and $3fff; - s.sub.trees.table := t; - {$ifndef PKZIP_BUG_WORKAROUND} - if ((t and $1f) > 29) or (((t shr 5) and $1f) > 29) then - begin - s.mode := BLKBAD; - z.msg := 'too many length or distance symbols'; - r := Z_DATA_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - {$endif} - t := 258 + (t and $1f) + ((t shr 5) and $1f); - s.sub.trees.blens := puIntArray( ZALLOC(z, t, sizeof(uInt)) ); - if (s.sub.trees.blens = Z_NULL) then - begin - r := Z_MEM_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - {DUMPBITS(14);} - b := b shr 14; - Dec(k, 14); - - s.sub.trees.index := 0; - {$IFDEF DEBUG} - Tracev('inflate: table sizes ok'); - {$ENDIF} - s.mode := BTREE; - { fall trough case is handled by the while } - { try GOTO for speed - Nomssi } - goto start_btree; - end; - BTREE: - begin - start_btree: - while (s.sub.trees.index < 4 + (s.sub.trees.table shr 10)) do - begin - {NEEDBITS(3);} - while (k < 3) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - s.sub.trees.blens^[border[s.sub.trees.index]] := uInt(b) and 7; - Inc(s.sub.trees.index); - {DUMPBITS(3);} - b := b shr 3; - Dec(k, 3); - end; - while (s.sub.trees.index < 19) do - begin - s.sub.trees.blens^[border[s.sub.trees.index]] := 0; - Inc(s.sub.trees.index); - end; - s.sub.trees.bb := 7; - t := inflate_trees_bits(s.sub.trees.blens^, s.sub.trees.bb, - s.sub.trees.tb, s.hufts^, z); - if (t <> Z_OK) then - begin - ZFREE(z, s.sub.trees.blens); - r := t; - if (r = Z_DATA_ERROR) then - s.mode := BLKBAD; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - s.sub.trees.index := 0; - {$IFDEF DEBUG} - Tracev('inflate: bits tree ok'); - {$ENDIF} - s.mode := DTREE; - { fall through again } - goto start_dtree; - end; - DTREE: - begin - start_dtree: - while TRUE do - begin - t := s.sub.trees.table; - if not (s.sub.trees.index < 258 + - (t and $1f) + ((t shr 5) and $1f)) then - break; - t := s.sub.trees.bb; - {NEEDBITS(t);} - while (k < t) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - h := s.sub.trees.tb; - Inc(h, uInt(b) and inflate_mask[t]); - t := h^.Bits; - c := h^.Base; - - if (c < 16) then - begin - {DUMPBITS(t);} - b := b shr t; - Dec(k, t); - - s.sub.trees.blens^[s.sub.trees.index] := c; - Inc(s.sub.trees.index); - end - else { c = 16..18 } - begin - if c = 18 then - begin - i := 7; - j := 11; - end - else - begin - i := c - 14; - j := 3; - end; - {NEEDBITS(t + i);} - while (k < t + i) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - {DUMPBITS(t);} - b := b shr t; - Dec(k, t); - - Inc(j, uInt(b) and inflate_mask[i]); - {DUMPBITS(i);} - b := b shr i; - Dec(k, i); - - i := s.sub.trees.index; - t := s.sub.trees.table; - if (i + j > 258 + (t and $1f) + ((t shr 5) and $1f)) or - ((c = 16) and (i < 1)) then - begin - ZFREE(z, s.sub.trees.blens); - s.mode := BLKBAD; - z.msg := 'invalid bit length repeat'; - r := Z_DATA_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - if c = 16 then - c := s.sub.trees.blens^[i - 1] - else - c := 0; - repeat - s.sub.trees.blens^[i] := c; - Inc(i); - Dec(j); - until (j=0); - s.sub.trees.index := i; - end; - end; { while } - s.sub.trees.tb := Z_NULL; - begin - bl := 9; { must be <= 9 for lookahead assumptions } - bd := 6; { must be <= 9 for lookahead assumptions } - t := s.sub.trees.table; - t := inflate_trees_dynamic(257 + (t and $1f), - 1 + ((t shr 5) and $1f), - s.sub.trees.blens^, bl, bd, tl, td, s.hufts^, z); - ZFREE(z, s.sub.trees.blens); - if (t <> Z_OK) then - begin - if (t = uInt(Z_DATA_ERROR)) then - s.mode := BLKBAD; - r := t; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - {$IFDEF DEBUG} - Tracev('inflate: trees ok'); - {$ENDIF} - { c renamed to cs } - cs := inflate_codes_new(bl, bd, tl, td, z); - if (cs = Z_NULL) then - begin - r := Z_MEM_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - s.sub.decode.codes := cs; - end; - s.mode := CODES; - { yet another falltrough } - goto start_codes; - end; - CODES: - begin - start_codes: - { update pointers } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - - r := inflate_codes(s, z, r); - if (r <> Z_STREAM_END) then - begin - inflate_blocks := inflate_flush(s, z, r); - exit; - end; - r := Z_OK; - inflate_codes_free(s.sub.decode.codes, z); - { load local pointers } - p := z.next_in; - n := z.avail_in; - b := s.bitb; - k := s.bitk; - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - {$IFDEF DEBUG} - if (ptr2int(q) >= ptr2int(s.read)) then - Tracev('inflate: codes end '+ - IntToStr(z.total_out + ptr2int(q) - ptr2int(s.read)) + ' total out') - else - Tracev('inflate: codes end '+ - IntToStr(z.total_out + ptr2int(s.zend) - ptr2int(s.read) + - ptr2int(q) - ptr2int(s.window)) + ' total out'); - {$ENDIF} - if (not s.last) then - begin - s.mode := ZTYPE; - continue; { break for switch statement in C-code } - end; - {$ifndef patch112} - if (k > 7) then { return unused byte, if any } - begin - {$IFDEF DEBUG} - Assert(k < 16, 'inflate_codes grabbed too many bytes'); - {$ENDIF} - Dec(k, 8); - Inc(n); - Dec(p); { can always return one } - end; - {$endif} - s.mode := DRY; - { another falltrough } - goto start_dry; - end; - DRY: - begin - start_dry: - {FLUSH} - s.write := q; - r := inflate_flush(s,z,r); - q := s.write; - - { not needed anymore, we are done: - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - } - - if (s.read <> s.write) then - begin - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - s.mode := BLKDONE; - goto start_blkdone; - end; - BLKDONE: - begin - start_blkdone: - r := Z_STREAM_END; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - BLKBAD: - begin - r := Z_DATA_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - else - begin - r := Z_STREAM_ERROR; - { update pointers and return } - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_blocks := inflate_flush(s,z,r); - exit; - end; - end; { Case s.mode of } - -end; - - -function inflate_blocks_free(s : pInflate_blocks_state; - var z : z_stream) : int; -begin - inflate_blocks_reset(s^, z, Z_NULL); - ZFREE(z, s^.window); - ZFREE(z, s^.hufts); - ZFREE(z, s); - {$IFDEF DEBUG} - Trace('inflate: blocks freed'); - {$ENDIF} - inflate_blocks_free := Z_OK; -end; - - -procedure inflate_set_dictionary(var s : inflate_blocks_state; - const d : array of byte; { dictionary } - n : uInt); { dictionary length } -begin - zmemcpy(s.window, pBytef(@d), n); - s.write := s.window; - Inc(s.write, n); - s.read := s.write; -end; - - -{ Returns true if inflate is currently at the end of a block generated - by Z_SYNC_FLUSH or Z_FULL_FLUSH. - IN assertion: s <> Z_NULL } - -function inflate_blocks_sync_point(var s : inflate_blocks_state) : int; -begin - inflate_blocks_sync_point := int(s.mode = LENS); -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/iminfcodes.pas b/3rd/Imaging/Source/ZLib/iminfcodes.pas deleted file mode 100644 index 5a1a78183..000000000 --- a/3rd/Imaging/Source/ZLib/iminfcodes.pas +++ /dev/null @@ -1,576 +0,0 @@ -Unit iminfcodes; - -{ infcodes.c -- process literals and length/distance pairs - Copyright (C) 1995-1998 Mark Adler - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -uses - {$IFDEF DEBUG} - SysUtils, strutils, - {$ENDIF} - imzutil, impaszlib; - -function inflate_codes_new (bl : uInt; - bd : uInt; - tl : pInflate_huft; - td : pInflate_huft; - var z : z_stream): pInflate_codes_state; - -function inflate_codes(var s : inflate_blocks_state; - var z : z_stream; - r : int) : int; - -procedure inflate_codes_free(c : pInflate_codes_state; - var z : z_stream); - -implementation - -uses - iminfutil, iminffast; - - -function inflate_codes_new (bl : uInt; - bd : uInt; - tl : pInflate_huft; - td : pInflate_huft; - var z : z_stream): pInflate_codes_state; -var - c : pInflate_codes_state; -begin - c := pInflate_codes_state( ZALLOC(z,1,sizeof(inflate_codes_state)) ); - if (c <> Z_NULL) then - begin - c^.mode := START; - c^.lbits := Byte(bl); - c^.dbits := Byte(bd); - c^.ltree := tl; - c^.dtree := td; - {$IFDEF DEBUG} - Tracev('inflate: codes new'); - {$ENDIF} - end; - inflate_codes_new := c; -end; - - -function inflate_codes(var s : inflate_blocks_state; - var z : z_stream; - r : int) : int; -var - j : uInt; { temporary storage } - t : pInflate_huft; { temporary pointer } - e : uInt; { extra bits or operation } - b : uLong; { bit buffer } - k : uInt; { bits in bit buffer } - p : pBytef; { input data pointer } - n : uInt; { bytes available there } - q : pBytef; { output window write pointer } - m : uInt; { bytes to end of window or read pointer } - f : pBytef; { pointer to copy strings from } -var - c : pInflate_codes_state; -begin - c := s.sub.decode.codes; { codes state } - - { copy input/output information to locals } - p := z.next_in; - n := z.avail_in; - b := s.bitb; - k := s.bitk; - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - { process input and output based on current state } - while True do - case (c^.mode) of - { waiting for "i:"=input, "o:"=output, "x:"=nothing } - START: { x: set up for LEN } - begin -{$ifndef SLOW} - if (m >= 258) and (n >= 10) then - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - - r := inflate_fast(c^.lbits, c^.dbits, c^.ltree, c^.dtree, s, z); - {LOAD} - p := z.next_in; - n := z.avail_in; - b := s.bitb; - k := s.bitk; - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - if (r <> Z_OK) then - begin - if (r = Z_STREAM_END) then - c^.mode := WASH - else - c^.mode := BADCODE; - continue; { break for switch-statement in C } - end; - end; -{$endif} { not SLOW } - c^.sub.code.need := c^.lbits; - c^.sub.code.tree := c^.ltree; - c^.mode := LEN; { falltrough } - end; - LEN: { i: get length/literal/eob next } - begin - j := c^.sub.code.need; - {NEEDBITS(j);} - while (k < j) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - t := c^.sub.code.tree; - Inc(t, uInt(b) and inflate_mask[j]); - {DUMPBITS(t^.bits);} - b := b shr t^.bits; - Dec(k, t^.bits); - - e := uInt(t^.exop); - if (e = 0) then { literal } - begin - c^.sub.lit := t^.base; - {$IFDEF DEBUG} - if (t^.base >= $20) and (t^.base < $7f) then - Tracevv('inflate: literal '+AnsiChar(t^.base)) - else - Tracevv('inflate: literal '+IntToStr(t^.base)); - {$ENDIF} - c^.mode := LIT; - continue; { break switch statement } - end; - if (e and 16 <> 0) then { length } - begin - c^.sub.copy.get := e and 15; - c^.len := t^.base; - c^.mode := LENEXT; - continue; { break C-switch statement } - end; - if (e and 64 = 0) then { next table } - begin - c^.sub.code.need := e; - c^.sub.code.tree := @huft_ptr(t)^[t^.base]; - continue; { break C-switch statement } - end; - if (e and 32 <> 0) then { end of block } - begin - {$IFDEF DEBUG} - Tracevv('inflate: end of block'); - {$ENDIF} - c^.mode := WASH; - continue; { break C-switch statement } - end; - c^.mode := BADCODE; { invalid code } - z.msg := 'invalid literal/length code'; - r := Z_DATA_ERROR; - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - LENEXT: { i: getting length extra (have base) } - begin - j := c^.sub.copy.get; - {NEEDBITS(j);} - while (k < j) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - Inc(c^.len, uInt(b and inflate_mask[j])); - {DUMPBITS(j);} - b := b shr j; - Dec(k, j); - - c^.sub.code.need := c^.dbits; - c^.sub.code.tree := c^.dtree; - {$IFDEF DEBUG} - Tracevv('inflate: length '+IntToStr(c^.len)); - {$ENDIF} - c^.mode := DIST; - { falltrough } - end; - DIST: { i: get distance next } - begin - j := c^.sub.code.need; - {NEEDBITS(j);} - while (k < j) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - t := @huft_ptr(c^.sub.code.tree)^[uInt(b) and inflate_mask[j]]; - {DUMPBITS(t^.bits);} - b := b shr t^.bits; - Dec(k, t^.bits); - - e := uInt(t^.exop); - if (e and 16 <> 0) then { distance } - begin - c^.sub.copy.get := e and 15; - c^.sub.copy.dist := t^.base; - c^.mode := DISTEXT; - continue; { break C-switch statement } - end; - if (e and 64 = 0) then { next table } - begin - c^.sub.code.need := e; - c^.sub.code.tree := @huft_ptr(t)^[t^.base]; - continue; { break C-switch statement } - end; - c^.mode := BADCODE; { invalid code } - z.msg := 'invalid distance code'; - r := Z_DATA_ERROR; - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - DISTEXT: { i: getting distance extra } - begin - j := c^.sub.copy.get; - {NEEDBITS(j);} - while (k < j) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - Inc(c^.sub.copy.dist, uInt(b) and inflate_mask[j]); - {DUMPBITS(j);} - b := b shr j; - Dec(k, j); - {$IFDEF DEBUG} - Tracevv('inflate: distance '+ IntToStr(c^.sub.copy.dist)); - {$ENDIF} - c^.mode := COPY; - { falltrough } - end; - COPY: { o: copying bytes in window, waiting for space } - begin - f := q; - Dec(f, c^.sub.copy.dist); - if (uInt(ptr2int(q) - ptr2int(s.window)) < c^.sub.copy.dist) then - begin - f := s.zend; - Dec(f, c^.sub.copy.dist - uInt(ptr2int(q) - ptr2int(s.window))); - end; - - while (c^.len <> 0) do - begin - {NEEDOUT} - if (m = 0) then - begin - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - end; - - if (m = 0) then - begin - {FLUSH} - s.write := q; - r := inflate_flush(s,z,r); - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - end; - - if (m = 0) then - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - end; - end; - r := Z_OK; - - {OUTBYTE( *f++)} - q^ := f^; - Inc(q); - Inc(f); - Dec(m); - - if (f = s.zend) then - f := s.window; - Dec(c^.len); - end; - c^.mode := START; - { C-switch break; not needed } - end; - LIT: { o: got literal, waiting for output space } - begin - {NEEDOUT} - if (m = 0) then - begin - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - end; - - if (m = 0) then - begin - {FLUSH} - s.write := q; - r := inflate_flush(s,z,r); - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - end; - - if (m = 0) then - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - end; - end; - r := Z_OK; - - {OUTBYTE(c^.sub.lit);} - q^ := c^.sub.lit; - Inc(q); - Dec(m); - - c^.mode := START; - {break;} - end; - WASH: { o: got eob, possibly more output } - begin - {$ifdef patch112} - if (k > 7) then { return unused byte, if any } - begin - {$IFDEF DEBUG} - Assert(k < 16, 'inflate_codes grabbed too many bytes'); - {$ENDIF} - Dec(k, 8); - Inc(n); - Dec(p); { can always return one } - end; - {$endif} - {FLUSH} - s.write := q; - r := inflate_flush(s,z,r); - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - if (s.read <> s.write) then - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - c^.mode := ZEND; - { falltrough } - end; - - ZEND: - begin - r := Z_STREAM_END; - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - BADCODE: { x: got error } - begin - r := Z_DATA_ERROR; - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - else - begin - r := Z_STREAM_ERROR; - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_codes := inflate_flush(s,z,r); - exit; - end; - end; -{NEED_DUMMY_RETURN - Delphi2+ dumb compilers complain without this } - inflate_codes := Z_STREAM_ERROR; -end; - - -procedure inflate_codes_free(c : pInflate_codes_state; - var z : z_stream); -begin - ZFREE(z, c); - {$IFDEF DEBUG} - Tracev('inflate: codes free'); - {$ENDIF} -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/iminffast.pas b/3rd/Imaging/Source/ZLib/iminffast.pas deleted file mode 100644 index 400b0fcff..000000000 --- a/3rd/Imaging/Source/ZLib/iminffast.pas +++ /dev/null @@ -1,318 +0,0 @@ -Unit iminffast; - -{ - inffast.h and - inffast.c -- process literals and length/distance pairs fast - Copyright (C) 1995-1998 Mark Adler - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - - -interface - -{$I imzconf.inc} - -uses - {$ifdef DEBUG} - SysUtils, strutils, - {$ENDIF} - imzutil, impaszlib; - -function inflate_fast( bl : uInt; - bd : uInt; - tl : pInflate_huft; - td : pInflate_huft; - var s : inflate_blocks_state; - var z : z_stream) : int; - - -implementation - -uses - iminfutil; - - -{ Called with number of bytes left to write in window at least 258 - (the maximum string length) and number of input bytes available - at least ten. The ten bytes are six bytes for the longest length/ - distance pair plus four bytes for overloading the bit buffer. } - -function inflate_fast( bl : uInt; - bd : uInt; - tl : pInflate_huft; - td : pInflate_huft; - var s : inflate_blocks_state; - var z : z_stream) : int; - -var - t : pInflate_huft; { temporary pointer } - e : uInt; { extra bits or operation } - b : uLong; { bit buffer } - k : uInt; { bits in bit buffer } - p : pBytef; { input data pointer } - n : uInt; { bytes available there } - q : pBytef; { output window write pointer } - m : uInt; { bytes to end of window or read pointer } - ml : uInt; { mask for literal/length tree } - md : uInt; { mask for distance tree } - c : uInt; { bytes to copy } - d : uInt; { distance back to copy from } - r : pBytef; { copy source pointer } -begin - { load input, output, bit values (macro LOAD) } - p := z.next_in; - n := z.avail_in; - b := s.bitb; - k := s.bitk; - q := s.write; - if ptr2int(q) < ptr2int(s.read) then - m := uInt(ptr2int(s.read)-ptr2int(q)-1) - else - m := uInt(ptr2int(s.zend)-ptr2int(q)); - - { initialize masks } - ml := inflate_mask[bl]; - md := inflate_mask[bd]; - - { do until not enough input or output space for fast loop } - repeat { assume called with (m >= 258) and (n >= 10) } - { get literal/length code } - {GRABBITS(20);} { max bits for literal/length code } - while (k < 20) do - begin - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - t := @(huft_ptr(tl)^[uInt(b) and ml]); - - e := t^.exop; - if (e = 0) then - begin - {DUMPBITS(t^.bits);} - b := b shr t^.bits; - Dec(k, t^.bits); - {$IFDEF DEBUG} - if (t^.base >= $20) and (t^.base < $7f) then - Tracevv('inflate: * literal '+AnsiChar(t^.base)) - else - Tracevv('inflate: * literal '+ IntToStr(t^.base)); - {$ENDIF} - q^ := Byte(t^.base); - Inc(q); - Dec(m); - continue; - end; - repeat - {DUMPBITS(t^.bits);} - b := b shr t^.bits; - Dec(k, t^.bits); - - if (e and 16 <> 0) then - begin - { get extra bits for length } - e := e and 15; - c := t^.base + (uInt(b) and inflate_mask[e]); - {DUMPBITS(e);} - b := b shr e; - Dec(k, e); - {$IFDEF DEBUG} - Tracevv('inflate: * length ' + IntToStr(c)); - {$ENDIF} - { decode distance base of block to copy } - {GRABBITS(15);} { max bits for distance code } - while (k < 15) do - begin - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - t := @huft_ptr(td)^[uInt(b) and md]; - e := t^.exop; - repeat - {DUMPBITS(t^.bits);} - b := b shr t^.bits; - Dec(k, t^.bits); - - if (e and 16 <> 0) then - begin - { get extra bits to add to distance base } - e := e and 15; - {GRABBITS(e);} { get extra bits (up to 13) } - while (k < e) do - begin - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - - d := t^.base + (uInt(b) and inflate_mask[e]); - {DUMPBITS(e);} - b := b shr e; - Dec(k, e); - - {$IFDEF DEBUG} - Tracevv('inflate: * distance '+IntToStr(d)); - {$ENDIF} - { do the copy } - Dec(m, c); - if (uInt(ptr2int(q) - ptr2int(s.window)) >= d) then { offset before dest } - begin { just copy } - r := q; - Dec(r, d); - q^ := r^; Inc(q); Inc(r); Dec(c); { minimum count is three, } - q^ := r^; Inc(q); Inc(r); Dec(c); { so unroll loop a little } - end - else { else offset after destination } - begin - e := d - uInt(ptr2int(q) - ptr2int(s.window)); { bytes from offset to end } - r := s.zend; - Dec(r, e); { pointer to offset } - if (c > e) then { if source crosses, } - begin - Dec(c, e); { copy to end of window } - repeat - q^ := r^; - Inc(q); - Inc(r); - Dec(e); - until (e=0); - r := s.window; { copy rest from start of window } - end; - end; - repeat { copy all or what's left } - q^ := r^; - Inc(q); - Inc(r); - Dec(c); - until (c = 0); - break; - end - else - if (e and 64 = 0) then - begin - Inc(t, t^.base + (uInt(b) and inflate_mask[e])); - e := t^.exop; - end - else - begin - z.msg := 'invalid distance code'; - {UNGRAB} - c := z.avail_in-n; - if (k shr 3) < c then - c := k shr 3; - Inc(n, c); - Dec(p, c); - Dec(k, c shl 3); - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - - inflate_fast := Z_DATA_ERROR; - exit; - end; - until FALSE; - break; - end; - if (e and 64 = 0) then - begin - {t += t->base; - e = (t += ((uInt)b & inflate_mask[e]))->exop;} - - Inc(t, t^.base + (uInt(b) and inflate_mask[e])); - e := t^.exop; - if (e = 0) then - begin - {DUMPBITS(t^.bits);} - b := b shr t^.bits; - Dec(k, t^.bits); - - {$IFDEF DEBUG} - if (t^.base >= $20) and (t^.base < $7f) then - Tracevv('inflate: * literal '+AnsiChar(t^.base)) - else - Tracevv('inflate: * literal '+IntToStr(t^.base)); - {$ENDIF} - q^ := Byte(t^.base); - Inc(q); - Dec(m); - break; - end; - end - else - if (e and 32 <> 0) then - begin - {$IFDEF DEBUG} - Tracevv('inflate: * end of block'); - {$ENDIF} - {UNGRAB} - c := z.avail_in-n; - if (k shr 3) < c then - c := k shr 3; - Inc(n, c); - Dec(p, c); - Dec(k, c shl 3); - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_fast := Z_STREAM_END; - exit; - end - else - begin - z.msg := 'invalid literal/length code'; - {UNGRAB} - c := z.avail_in-n; - if (k shr 3) < c then - c := k shr 3; - Inc(n, c); - Dec(p, c); - Dec(k, c shl 3); - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_fast := Z_DATA_ERROR; - exit; - end; - until FALSE; - until (m < 258) or (n < 10); - - { not enough input or output--restore pointers and return } - {UNGRAB} - c := z.avail_in-n; - if (k shr 3) < c then - c := k shr 3; - Inc(n, c); - Dec(p, c); - Dec(k, c shl 3); - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); - z.next_in := p; - s.write := q; - inflate_fast := Z_OK; -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/iminftrees.pas b/3rd/Imaging/Source/ZLib/iminftrees.pas deleted file mode 100644 index 6949a63fd..000000000 --- a/3rd/Imaging/Source/ZLib/iminftrees.pas +++ /dev/null @@ -1,781 +0,0 @@ -Unit iminftrees; - -{ inftrees.h -- header to use inftrees.c - inftrees.c -- generate Huffman trees for efficient decoding - Copyright (C) 1995-1998 Mark Adler - - WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -Interface - -{$I imzconf.inc} - -uses - imzutil, impaszlib; - - -{ Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1004 huft structures (850 for length/literals - and 154 for distances, the latter actually the result of an - exhaustive search). The actual maximum is not known, but the - value below is more than safe. } -const - MANY = 1440; - - -{$ifdef DEBUG} -var - inflate_hufts : uInt; -{$endif} - -function inflate_trees_bits( - var c : array of uIntf; { 19 code lengths } - var bb : uIntf; { bits tree desired/actual depth } - var tb : pinflate_huft; { bits tree result } - var hp : array of Inflate_huft; { space for trees } - var z : z_stream { for messages } - ) : int; - -function inflate_trees_dynamic( - nl : uInt; { number of literal/length codes } - nd : uInt; { number of distance codes } - var c : Array of uIntf; { that many (total) code lengths } - var bl : uIntf; { literal desired/actual bit depth } - var bd : uIntf; { distance desired/actual bit depth } -var tl : pInflate_huft; { literal/length tree result } -var td : pInflate_huft; { distance tree result } -var hp : array of Inflate_huft; { space for trees } -var z : z_stream { for messages } - ) : int; - -function inflate_trees_fixed ( - var bl : uInt; { literal desired/actual bit depth } - var bd : uInt; { distance desired/actual bit depth } - var tl : pInflate_huft; { literal/length tree result } - var td : pInflate_huft; { distance tree result } - var z : z_stream { for memory allocation } - ) : int; - - -implementation - -const - inflate_copyright = 'inflate 1.1.2 Copyright 1995-1998 Mark Adler'; - -{ - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. -} - - -const -{ Tables for deflate from PKZIP's appnote.txt. } - cplens : Array [0..30] Of uInt { Copy lengths for literal codes 257..285 } - = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0); - { actually lengths - 2; also see note #13 above about 258 } - - invalid_code = 112; - - cplext : Array [0..30] Of uInt { Extra bits for literal codes 257..285 } - = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, invalid_code, invalid_code); - - cpdist : Array [0..29] Of uInt { Copy offsets for distance codes 0..29 } - = (1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577); - - cpdext : Array [0..29] Of uInt { Extra bits for distance codes } - = (0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13); - -{ Huffman code decoding is performed using a multi-level table lookup. - The fastest way to decode is to simply build a lookup table whose - size is determined by the longest code. However, the time it takes - to build this table can also be a factor if the data being decoded - is not very long. The most common codes are necessarily the - shortest codes, so those codes dominate the decoding time, and hence - the speed. The idea is you can have a shorter table that decodes the - shorter, more probable codes, and then point to subsidiary tables for - the longer codes. The time it costs to decode the longer codes is - then traded against the time it takes to make longer tables. - - This results of this trade are in the variables lbits and dbits - below. lbits is the number of bits the first level table for literal/ - length codes can decode in one step, and dbits is the same thing for - the distance codes. Subsequent tables are also less than or equal to - those sizes. These values may be adjusted either when all of the - codes are shorter than that, in which case the longest code length in - bits is used, or when the shortest code is *longer* than the requested - table size, in which case the length of the shortest code in bits is - used. - - There are two different values for the two tables, since they code a - different number of possibilities each. The literal/length table - codes 286 possible values, or in a flat code, a little over eight - bits. The distance table codes 30 possible values, or a little less - than five bits, flat. The optimum values for speed end up being - about one bit more than those, so lbits is 8+1 and dbits is 5+1. - The optimum values may differ though from machine to machine, and - possibly even between compilers. Your mileage may vary. } - - -{ If BMAX needs to be larger than 16, then h and x[] should be uLong. } -const - BMAX = 15; { maximum bit length of any code } - -{$DEFINE USE_PTR} - -function huft_build( -var b : array of uIntf; { code lengths in bits (all assumed <= BMAX) } - n : uInt; { number of codes (assumed <= N_MAX) } - s : uInt; { number of simple-valued codes (0..s-1) } -const d : array of uIntf; { list of base values for non-simple codes } -{ array of word } -const e : array of uIntf; { list of extra bits for non-simple codes } -{ array of byte } - t : ppInflate_huft; { result: starting table } -var m : uIntf; { maximum lookup bits, returns actual } -var hp : array of inflate_huft; { space for trees } -var hn : uInt; { hufts used in space } -var v : array of uIntf { working area: values in order of bit length } - ) : int; -{ Given a list of code lengths and a maximum table size, make a set of - tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR - if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. } -Var - a : uInt; { counter for codes of length k } - c : Array [0..BMAX] Of uInt; { bit length count table } - f : uInt; { i repeats in table every f entries } - g : int; { maximum code length } - h : int; { table level } - i : uInt; {register} { counter, current code } - j : uInt; {register} { counter } - k : Int; {register} { number of bits in current code } - l : int; { bits per table (returned in m) } - mask : uInt; { (1 shl w) - 1, to avoid cc -O bug on HP } - p : ^uIntf; {register} { pointer into c[], b[], or v[] } - q : pInflate_huft; { points to current table } - r : inflate_huft; { table entry for structure assignment } - u : Array [0..BMAX-1] Of pInflate_huft; { table stack } - w : int; {register} { bits before this table = (l*h) } - x : Array [0..BMAX] Of uInt; { bit offsets, then code stack } - {$IFDEF USE_PTR} - xp : puIntf; { pointer into x } - {$ELSE} - xp : uInt; - {$ENDIF} - y : int; { number of dummy codes added } - z : uInt; { number of entries in current table } -Begin - { Generate counts for each bit length } - FillChar(c,SizeOf(c),0) ; { clear c[] } - - for i := 0 to n-1 do - Inc (c[b[i]]); { assume all entries <= BMAX } - - If (c[0] = n) Then { null input--all zero length codes } - Begin - t^ := pInflate_huft(NIL); - m := 0 ; - huft_build := Z_OK ; - Exit; - End ; - - { Find minimum and maximum length, bound [m] by those } - l := m; - for j:=1 To BMAX do - if (c[j] <> 0) then - break; - k := j ; { minimum code length } - if (uInt(l) < j) then - l := j; - for i := BMAX downto 1 do - if (c[i] <> 0) then - break ; - g := i ; { maximum code length } - if (uInt(l) > i) then - l := i; - m := l; - - { Adjust last length count to fill out codes, if needed } - y := 1 shl j ; - while (j < i) do - begin - Dec(y, c[j]) ; - if (y < 0) then - begin - huft_build := Z_DATA_ERROR; { bad input: more codes than bits } - exit; - end ; - Inc(j) ; - y := y shl 1 - end; - Dec (y, c[i]) ; - if (y < 0) then - begin - huft_build := Z_DATA_ERROR; { bad input: more codes than bits } - exit; - end; - Inc(c[i], y); - - { Generate starting offsets into the value table FOR each length } - {$IFDEF USE_PTR} - x[1] := 0; - j := 0; - - p := @c[1]; - xp := @x[2]; - - dec(i); { note that i = g from above } - WHILE (i > 0) DO - BEGIN - inc(j, p^); - xp^ := j; - inc(p); - inc(xp); - dec(i); - END; - {$ELSE} - x[1] := 0; - j := 0 ; - for i := 1 to g do - begin - x[i] := j; - Inc(j, c[i]); - end; - {$ENDIF} - - { Make a table of values in order of bit lengths } - for i := 0 to n-1 do - begin - j := b[i]; - if (j <> 0) then - begin - v[ x[j] ] := i; - Inc(x[j]); - end; - end; - n := x[g]; { set n to length of v } - - { Generate the Huffman codes and for each, make the table entries } - i := 0 ; - x[0] := 0 ; { first Huffman code is zero } - p := Addr(v) ; { grab values in bit order } - h := -1 ; { no tables yet--level -1 } - w := -l ; { bits decoded = (l*h) } - - u[0] := pInflate_huft(NIL); { just to keep compilers happy } - q := pInflate_huft(NIL); { ditto } - z := 0 ; { ditto } - - { go through the bit lengths (k already is bits in shortest code) } - while (k <= g) Do - begin - a := c[k] ; - while (a<>0) Do - begin - Dec (a) ; - { here i is the Huffman code of length k bits for value p^ } - { make tables up to required level } - while (k > w + l) do - begin - - Inc (h) ; - Inc (w, l); { add bits already decoded } - { previous table always l bits } - { compute minimum size table less than or equal to l bits } - - { table size upper limit } - z := g - w; - If (z > uInt(l)) Then - z := l; - - { try a k-w bit table } - j := k - w; - f := 1 shl j; - if (f > a+1) Then { too few codes for k-w bit table } - begin - Dec(f, a+1); { deduct codes from patterns left } - {$IFDEF USE_PTR} - xp := Addr(c[k]); - - if (j < z) then - begin - Inc(j); - while (j < z) do - begin { try smaller tables up to z bits } - f := f shl 1; - Inc (xp) ; - If (f <= xp^) Then - break; { enough codes to use up j bits } - Dec(f, xp^); { else deduct codes from patterns } - Inc(j); - end; - end; - {$ELSE} - xp := k; - - if (j < z) then - begin - Inc (j) ; - While (j < z) Do - begin { try smaller tables up to z bits } - f := f * 2; - Inc (xp) ; - if (f <= c[xp]) then - Break ; { enough codes to use up j bits } - Dec (f, c[xp]) ; { else deduct codes from patterns } - Inc (j); - end; - end; - {$ENDIF} - end; - - z := 1 shl j; { table entries for j-bit table } - - { allocate new table } - if (hn + z > MANY) then { (note: doesn't matter for fixed) } - begin - huft_build := Z_MEM_ERROR; { not enough memory } - exit; - end; - - q := @hp[hn]; - u[h] := q; - Inc(hn, z); - - { connect to last table, if there is one } - if (h <> 0) then - begin - x[h] := i; { save pattern for backing up } - r.bits := Byte(l); { bits to dump before this table } - r.exop := Byte(j); { bits in this table } - j := i shr (w - l); - {r.base := uInt( q - u[h-1] -j);} { offset to this table } - r.base := (ptr2int(q) - ptr2int(u[h-1]) ) div sizeof(q^) - j; - huft_Ptr(u[h-1])^[j] := r; { connect to last table } - end - else - t^ := q; { first table is returned result } - end; - - { set up table entry in r } - r.bits := Byte(k - w); - - { C-code: if (p >= v + n) - see ZUTIL.PAS for comments } - - if ptr2int(p)>=ptr2int(@(v[n])) then { also works under DPMI ?? } - r.exop := 128 + 64 { out of values--invalid code } - else - if (p^ < s) then - begin - if (p^ < 256) then { 256 is end-of-block code } - r.exop := 0 - Else - r.exop := 32 + 64; { EOB_code; } - r.base := p^; { simple code is just the value } - Inc(p); - end - Else - begin - r.exop := Byte(e[p^-s] + 16 + 64); { non-simple--look up in lists } - r.base := d[p^-s]; - Inc (p); - end ; - - { fill code-like entries with r } - f := 1 shl (k - w); - j := i shr w; - while (j < z) do - begin - huft_Ptr(q)^[j] := r; - Inc(j, f); - end; - - { backwards increment the k-bit code i } - j := 1 shl (k-1) ; - while (i and j) <> 0 do - begin - i := i xor j; { bitwise exclusive or } - j := j shr 1 - end ; - i := i xor j; - - { backup over finished tables } - mask := (1 shl w) - 1; { needed on HP, cc -O bug } - while ((i and mask) <> x[h]) do - begin - Dec(h); { don't need to update q } - Dec(w, l); - mask := (1 shl w) - 1; - end; - - end; - - Inc(k); - end; - - { Return Z_BUF_ERROR if we were given an incomplete table } - if (y <> 0) And (g <> 1) then - huft_build := Z_BUF_ERROR - else - huft_build := Z_OK; -end; { huft_build} - - -function inflate_trees_bits( - var c : array of uIntf; { 19 code lengths } - var bb : uIntf; { bits tree desired/actual depth } - var tb : pinflate_huft; { bits tree result } - var hp : array of Inflate_huft; { space for trees } - var z : z_stream { for messages } - ) : int; -var - r : int; - hn : uInt; { hufts used in space } - v : PuIntArray; { work area for huft_build } -begin - hn := 0; - v := PuIntArray( ZALLOC(z, 19, sizeof(uInt)) ); - if (v = Z_NULL) then - begin - inflate_trees_bits := Z_MEM_ERROR; - exit; - end; - - r := huft_build(c, 19, 19, cplens, cplext, - {puIntf(Z_NULL), puIntf(Z_NULL),} - @tb, bb, hp, hn, v^); - if (r = Z_DATA_ERROR) then - z.msg := 'oversubscribed dynamic bit lengths tree' - else - if (r = Z_BUF_ERROR) or (bb = 0) then - begin - z.msg := 'incomplete dynamic bit lengths tree'; - r := Z_DATA_ERROR; - end; - ZFREE(z, v); - inflate_trees_bits := r; -end; - - -function inflate_trees_dynamic( - nl : uInt; { number of literal/length codes } - nd : uInt; { number of distance codes } - var c : Array of uIntf; { that many (total) code lengths } - var bl : uIntf; { literal desired/actual bit depth } - var bd : uIntf; { distance desired/actual bit depth } -var tl : pInflate_huft; { literal/length tree result } -var td : pInflate_huft; { distance tree result } -var hp : array of Inflate_huft; { space for trees } -var z : z_stream { for messages } - ) : int; -var - r : int; - hn : uInt; { hufts used in space } - v : PuIntArray; { work area for huft_build } -begin - hn := 0; - { allocate work area } - v := PuIntArray( ZALLOC(z, 288, sizeof(uInt)) ); - if (v = Z_NULL) then - begin - inflate_trees_dynamic := Z_MEM_ERROR; - exit; - end; - - { build literal/length tree } - r := huft_build(c, nl, 257, cplens, cplext, @tl, bl, hp, hn, v^); - if (r <> Z_OK) or (bl = 0) then - begin - if (r = Z_DATA_ERROR) then - z.msg := 'oversubscribed literal/length tree' - else - if (r <> Z_MEM_ERROR) then - begin - z.msg := 'incomplete literal/length tree'; - r := Z_DATA_ERROR; - end; - - ZFREE(z, v); - inflate_trees_dynamic := r; - exit; - end; - - { build distance tree } - r := huft_build(puIntArray(@c[nl])^, nd, 0, - cpdist, cpdext, @td, bd, hp, hn, v^); - if (r <> Z_OK) or ((bd = 0) and (nl > 257)) then - begin - if (r = Z_DATA_ERROR) then - z.msg := 'oversubscribed literal/length tree' - else - if (r = Z_BUF_ERROR) then - begin -{$ifdef PKZIP_BUG_WORKAROUND} - r := Z_OK; - end; -{$else} - z.msg := 'incomplete literal/length tree'; - r := Z_DATA_ERROR; - end - else - if (r <> Z_MEM_ERROR) then - begin - z.msg := 'empty distance tree with lengths'; - r := Z_DATA_ERROR; - end; - ZFREE(z, v); - inflate_trees_dynamic := r; - exit; -{$endif} - end; - - { done } - ZFREE(z, v); - inflate_trees_dynamic := Z_OK; -end; - -{$UNDEF BUILDFIXED} - -{ build fixed tables only once--keep them here } -{$IFNDEF BUILDFIXED} -{ locals } -var - fixed_built : Boolean = false; -const - FIXEDH = 544; { number of hufts used by fixed tables } -var - fixed_mem : array[0..FIXEDH-1] of inflate_huft; - fixed_bl : uInt; - fixed_bd : uInt; - fixed_tl : pInflate_huft; - fixed_td : pInflate_huft; - -{$ELSE} - -{ inffixed.h -- table for decoding fixed codes } - -{local} -const - fixed_bl = uInt(9); -{local} -const - fixed_bd = uInt(5); -{local} -const - fixed_tl : array [0..288-1] of inflate_huft = ( - Exop, { number of extra bits or operation } - bits : Byte; { number of bits in this code or subcode } - {pad : uInt;} { pad structure to a power of 2 (4 bytes for } - { 16-bit, 8 bytes for 32-bit int's) } - base : uInt; { literal, length base, or distance base } - { or table offset } - - ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115), ((82,7),31), - ((0,8),112), ((0,8),48), ((0,9),192), ((80,7),10), ((0,8),96), - ((0,8),32), ((0,9),160), ((0,8),0), ((0,8),128), ((0,8),64), - ((0,9),224), ((80,7),6), ((0,8),88), ((0,8),24), ((0,9),144), - ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),208), ((81,7),17), - ((0,8),104), ((0,8),40), ((0,9),176), ((0,8),8), ((0,8),136), - ((0,8),72), ((0,9),240), ((80,7),4), ((0,8),84), ((0,8),20), - ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52), ((0,9),200), - ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),168), ((0,8),4), - ((0,8),132), ((0,8),68), ((0,9),232), ((80,7),8), ((0,8),92), - ((0,8),28), ((0,9),152), ((84,7),83), ((0,8),124), ((0,8),60), - ((0,9),216), ((82,7),23), ((0,8),108), ((0,8),44), ((0,9),184), - ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),248), ((80,7),3), - ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35), ((0,8),114), - ((0,8),50), ((0,9),196), ((81,7),11), ((0,8),98), ((0,8),34), - ((0,9),164), ((0,8),2), ((0,8),130), ((0,8),66), ((0,9),228), - ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),148), ((84,7),67), - ((0,8),122), ((0,8),58), ((0,9),212), ((82,7),19), ((0,8),106), - ((0,8),42), ((0,9),180), ((0,8),10), ((0,8),138), ((0,8),74), - ((0,9),244), ((80,7),5), ((0,8),86), ((0,8),22), ((192,8),0), - ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),204), ((81,7),15), - ((0,8),102), ((0,8),38), ((0,9),172), ((0,8),6), ((0,8),134), - ((0,8),70), ((0,9),236), ((80,7),9), ((0,8),94), ((0,8),30), - ((0,9),156), ((84,7),99), ((0,8),126), ((0,8),62), ((0,9),220), - ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),188), ((0,8),14), - ((0,8),142), ((0,8),78), ((0,9),252), ((96,7),256), ((0,8),81), - ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113), ((0,8),49), - ((0,9),194), ((80,7),10), ((0,8),97), ((0,8),33), ((0,9),162), - ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),226), ((80,7),6), - ((0,8),89), ((0,8),25), ((0,9),146), ((83,7),59), ((0,8),121), - ((0,8),57), ((0,9),210), ((81,7),17), ((0,8),105), ((0,8),41), - ((0,9),178), ((0,8),9), ((0,8),137), ((0,8),73), ((0,9),242), - ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258), ((83,7),43), - ((0,8),117), ((0,8),53), ((0,9),202), ((81,7),13), ((0,8),101), - ((0,8),37), ((0,9),170), ((0,8),5), ((0,8),133), ((0,8),69), - ((0,9),234), ((80,7),8), ((0,8),93), ((0,8),29), ((0,9),154), - ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),218), ((82,7),23), - ((0,8),109), ((0,8),45), ((0,9),186), ((0,8),13), ((0,8),141), - ((0,8),77), ((0,9),250), ((80,7),3), ((0,8),83), ((0,8),19), - ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51), ((0,9),198), - ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),166), ((0,8),3), - ((0,8),131), ((0,8),67), ((0,9),230), ((80,7),7), ((0,8),91), - ((0,8),27), ((0,9),150), ((84,7),67), ((0,8),123), ((0,8),59), - ((0,9),214), ((82,7),19), ((0,8),107), ((0,8),43), ((0,9),182), - ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),246), ((80,7),5), - ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51), ((0,8),119), - ((0,8),55), ((0,9),206), ((81,7),15), ((0,8),103), ((0,8),39), - ((0,9),174), ((0,8),7), ((0,8),135), ((0,8),71), ((0,9),238), - ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),158), ((84,7),99), - ((0,8),127), ((0,8),63), ((0,9),222), ((82,7),27), ((0,8),111), - ((0,8),47), ((0,9),190), ((0,8),15), ((0,8),143), ((0,8),79), - ((0,9),254), ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115), - ((82,7),31), ((0,8),112), ((0,8),48), ((0,9),193), ((80,7),10), - ((0,8),96), ((0,8),32), ((0,9),161), ((0,8),0), ((0,8),128), - ((0,8),64), ((0,9),225), ((80,7),6), ((0,8),88), ((0,8),24), - ((0,9),145), ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),209), - ((81,7),17), ((0,8),104), ((0,8),40), ((0,9),177), ((0,8),8), - ((0,8),136), ((0,8),72), ((0,9),241), ((80,7),4), ((0,8),84), - ((0,8),20), ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52), - ((0,9),201), ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),169), - ((0,8),4), ((0,8),132), ((0,8),68), ((0,9),233), ((80,7),8), - ((0,8),92), ((0,8),28), ((0,9),153), ((84,7),83), ((0,8),124), - ((0,8),60), ((0,9),217), ((82,7),23), ((0,8),108), ((0,8),44), - ((0,9),185), ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),249), - ((80,7),3), ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35), - ((0,8),114), ((0,8),50), ((0,9),197), ((81,7),11), ((0,8),98), - ((0,8),34), ((0,9),165), ((0,8),2), ((0,8),130), ((0,8),66), - ((0,9),229), ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),149), - ((84,7),67), ((0,8),122), ((0,8),58), ((0,9),213), ((82,7),19), - ((0,8),106), ((0,8),42), ((0,9),181), ((0,8),10), ((0,8),138), - ((0,8),74), ((0,9),245), ((80,7),5), ((0,8),86), ((0,8),22), - ((192,8),0), ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),205), - ((81,7),15), ((0,8),102), ((0,8),38), ((0,9),173), ((0,8),6), - ((0,8),134), ((0,8),70), ((0,9),237), ((80,7),9), ((0,8),94), - ((0,8),30), ((0,9),157), ((84,7),99), ((0,8),126), ((0,8),62), - ((0,9),221), ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),189), - ((0,8),14), ((0,8),142), ((0,8),78), ((0,9),253), ((96,7),256), - ((0,8),81), ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113), - ((0,8),49), ((0,9),195), ((80,7),10), ((0,8),97), ((0,8),33), - ((0,9),163), ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),227), - ((80,7),6), ((0,8),89), ((0,8),25), ((0,9),147), ((83,7),59), - ((0,8),121), ((0,8),57), ((0,9),211), ((81,7),17), ((0,8),105), - ((0,8),41), ((0,9),179), ((0,8),9), ((0,8),137), ((0,8),73), - ((0,9),243), ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258), - ((83,7),43), ((0,8),117), ((0,8),53), ((0,9),203), ((81,7),13), - ((0,8),101), ((0,8),37), ((0,9),171), ((0,8),5), ((0,8),133), - ((0,8),69), ((0,9),235), ((80,7),8), ((0,8),93), ((0,8),29), - ((0,9),155), ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),219), - ((82,7),23), ((0,8),109), ((0,8),45), ((0,9),187), ((0,8),13), - ((0,8),141), ((0,8),77), ((0,9),251), ((80,7),3), ((0,8),83), - ((0,8),19), ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51), - ((0,9),199), ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),167), - ((0,8),3), ((0,8),131), ((0,8),67), ((0,9),231), ((80,7),7), - ((0,8),91), ((0,8),27), ((0,9),151), ((84,7),67), ((0,8),123), - ((0,8),59), ((0,9),215), ((82,7),19), ((0,8),107), ((0,8),43), - ((0,9),183), ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),247), - ((80,7),5), ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51), - ((0,8),119), ((0,8),55), ((0,9),207), ((81,7),15), ((0,8),103), - ((0,8),39), ((0,9),175), ((0,8),7), ((0,8),135), ((0,8),71), - ((0,9),239), ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),159), - ((84,7),99), ((0,8),127), ((0,8),63), ((0,9),223), ((82,7),27), - ((0,8),111), ((0,8),47), ((0,9),191), ((0,8),15), ((0,8),143), - ((0,8),79), ((0,9),255) - ); - -{local} -const - fixed_td : array[0..32-1] of inflate_huft = ( -(Exop:80;bits:5;base:1), (Exop:87;bits:5;base:257), (Exop:83;bits:5;base:17), -(Exop:91;bits:5;base:4097), (Exop:81;bits:5;base), (Exop:89;bits:5;base:1025), -(Exop:85;bits:5;base:65), (Exop:93;bits:5;base:16385), (Exop:80;bits:5;base:3), -(Exop:88;bits:5;base:513), (Exop:84;bits:5;base:33), (Exop:92;bits:5;base:8193), -(Exop:82;bits:5;base:9), (Exop:90;bits:5;base:2049), (Exop:86;bits:5;base:129), -(Exop:192;bits:5;base:24577), (Exop:80;bits:5;base:2), (Exop:87;bits:5;base:385), -(Exop:83;bits:5;base:25), (Exop:91;bits:5;base:6145), (Exop:81;bits:5;base:7), -(Exop:89;bits:5;base:1537), (Exop:85;bits:5;base:97), (Exop:93;bits:5;base:24577), -(Exop:80;bits:5;base:4), (Exop:88;bits:5;base:769), (Exop:84;bits:5;base:49), -(Exop:92;bits:5;base:12289), (Exop:82;bits:5;base:13), (Exop:90;bits:5;base:3073), -(Exop:86;bits:5;base:193), (Exop:192;bits:5;base:24577) - ); -{$ENDIF} - -function inflate_trees_fixed( -var bl : uInt; { literal desired/actual bit depth } -var bd : uInt; { distance desired/actual bit depth } -var tl : pInflate_huft; { literal/length tree result } -var td : pInflate_huft; { distance tree result } -var z : z_stream { for memory allocation } - ) : int; -type - pFixed_table = ^fixed_table; - fixed_table = array[0..288-1] of uIntf; -var - k : int; { temporary variable } - c : pFixed_table; { length list for huft_build } - v : PuIntArray; { work area for huft_build } -var - f : uInt; { number of hufts used in fixed_mem } -begin - { build fixed tables if not already (multiple overlapped executions ok) } - if not fixed_built then - begin - f := 0; - - { allocate memory } - c := pFixed_table( ZALLOC(z, 288, sizeof(uInt)) ); - if (c = Z_NULL) then - begin - inflate_trees_fixed := Z_MEM_ERROR; - exit; - end; - v := PuIntArray( ZALLOC(z, 288, sizeof(uInt)) ); - if (v = Z_NULL) then - begin - ZFREE(z, c); - inflate_trees_fixed := Z_MEM_ERROR; - exit; - end; - - { literal table } - for k := 0 to Pred(144) do - c^[k] := 8; - for k := 144 to Pred(256) do - c^[k] := 9; - for k := 256 to Pred(280) do - c^[k] := 7; - for k := 280 to Pred(288) do - c^[k] := 8; - fixed_bl := 9; - huft_build(c^, 288, 257, cplens, cplext, @fixed_tl, fixed_bl, - fixed_mem, f, v^); - - { distance table } - for k := 0 to Pred(30) do - c^[k] := 5; - fixed_bd := 5; - huft_build(c^, 30, 0, cpdist, cpdext, @fixed_td, fixed_bd, - fixed_mem, f, v^); - - { done } - ZFREE(z, v); - ZFREE(z, c); - fixed_built := True; - end; - bl := fixed_bl; - bd := fixed_bd; - tl := fixed_tl; - td := fixed_td; - inflate_trees_fixed := Z_OK; -end; { inflate_trees_fixed } - - -end. \ No newline at end of file diff --git a/3rd/Imaging/Source/ZLib/iminfutil.pas b/3rd/Imaging/Source/ZLib/iminfutil.pas deleted file mode 100644 index 384f0d3ca..000000000 --- a/3rd/Imaging/Source/ZLib/iminfutil.pas +++ /dev/null @@ -1,222 +0,0 @@ -Unit iminfutil; - -{ types and macros common to blocks and codes - Copyright (C) 1995-1998 Mark Adler - - WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -uses - imzutil, impaszlib; - -{ copy as much as possible from the sliding window to the output area } -function inflate_flush(var s : inflate_blocks_state; - var z : z_stream; - r : int) : int; - -{ And'ing with mask[n] masks the lower n bits } -const - inflate_mask : array[0..17-1] of uInt = ( - $0000, - $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff, - $01ff, $03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff); - -{procedure GRABBITS(j : int);} -{procedure DUMPBITS(j : int);} -{procedure NEEDBITS(j : int);} - -implementation - -{ macros for bit input with no checking and for returning unused bytes } -procedure GRABBITS(j : int); -begin - {while (k < j) do - begin - Dec(z^.avail_in); - Inc(z^.total_in); - b := b or (uLong(z^.next_in^) shl k); - Inc(z^.next_in); - Inc(k, 8); - end;} -end; - -procedure DUMPBITS(j : int); -begin - {b := b shr j; - Dec(k, j);} -end; - -procedure NEEDBITS(j : int); -begin - (* - while (k < j) do - begin - {NEEDBYTE;} - if (n <> 0) then - r :=Z_OK - else - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, LongInt(p)-LongInt(z.next_in)); - z.next_in := p; - s.write := q; - result := inflate_flush(s,z,r); - exit; - end; - Dec(n); - b := b or (uLong(p^) shl k); - Inc(p); - Inc(k, 8); - end; - *) -end; - -procedure NEEDOUT; -begin - (* - if (m = 0) then - begin - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if LongInt(q) < LongInt(s.read) then - m := uInt(LongInt(s.read)-LongInt(q)-1) - else - m := uInt(LongInt(s.zend)-LongInt(q)); - end; - - if (m = 0) then - begin - {FLUSH} - s.write := q; - r := inflate_flush(s,z,r); - q := s.write; - if LongInt(q) < LongInt(s.read) then - m := uInt(LongInt(s.read)-LongInt(q)-1) - else - m := uInt(LongInt(s.zend)-LongInt(q)); - - {WRAP} - if (q = s.zend) and (s.read <> s.window) then - begin - q := s.window; - if LongInt(q) < LongInt(s.read) then - m := uInt(LongInt(s.read)-LongInt(q)-1) - else - m := uInt(LongInt(s.zend)-LongInt(q)); - end; - - if (m = 0) then - begin - {UPDATE} - s.bitb := b; - s.bitk := k; - z.avail_in := n; - Inc(z.total_in, LongInt(p)-LongInt(z.next_in)); - z.next_in := p; - s.write := q; - result := inflate_flush(s,z,r); - exit; - end; - end; - end; - r := Z_OK; - *) -end; - -{ copy as much as possible from the sliding window to the output area } -function inflate_flush(var s : inflate_blocks_state; - var z : z_stream; - r : int) : int; -var - n : uInt; - p : pBytef; - q : pBytef; -begin - { local copies of source and destination pointers } - p := z.next_out; - q := s.read; - - { compute number of bytes to copy as far as end of window } - if ptr2int(q) <= ptr2int(s.write) then - n := uInt(ptr2int(s.write) - ptr2int(q)) - else - n := uInt(ptr2int(s.zend) - ptr2int(q)); - if (n > z.avail_out) then - n := z.avail_out; - if (n <> 0) and (r = Z_BUF_ERROR) then - r := Z_OK; - - { update counters } - Dec(z.avail_out, n); - Inc(z.total_out, n); - - - { update check information } - if Assigned(s.checkfn) then - begin - s.check := s.checkfn(s.check, q, n); - z.adler := s.check; - end; - - { copy as far as end of window } - zmemcpy(p, q, n); - Inc(p, n); - Inc(q, n); - - { see if more to copy at beginning of window } - if (q = s.zend) then - begin - { wrap pointers } - q := s.window; - if (s.write = s.zend) then - s.write := s.window; - - { compute bytes to copy } - n := uInt(ptr2int(s.write) - ptr2int(q)); - if (n > z.avail_out) then - n := z.avail_out; - if (n <> 0) and (r = Z_BUF_ERROR) then - r := Z_OK; - - { update counters } - Dec( z.avail_out, n); - Inc( z.total_out, n); - - { update check information } - if Assigned(s.checkfn) then - begin - s.check := s.checkfn(s.check, q, n); - z.adler := s.check; - end; - - { copy } - zmemcpy(p, q, n); - Inc(p, n); - Inc(q, n); - end; - - - { update pointers } - z.next_out := p; - s.read := q; - - { done } - inflate_flush := r; -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/impaszlib.pas b/3rd/Imaging/Source/ZLib/impaszlib.pas deleted file mode 100644 index 555634c57..000000000 --- a/3rd/Imaging/Source/ZLib/impaszlib.pas +++ /dev/null @@ -1,520 +0,0 @@ -Unit impaszlib; - - -{ Original: - zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.0, Feb 24th, 1998 - - Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). - - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -uses - imzutil; - -{ zconf.h -- configuration of the zlib compression library } -{ zutil.c -- target dependent utility functions for the compression library } - -{ The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. } - - - -{ Compile with -DMAXSEG_64K if the alloc function cannot allocate more - than 64k bytes at a time (needed on systems with 16-bit int). } - -{ Maximum value for memLevel in deflateInit2 } -const - MAX_MEM_LEVEL = 9; - DEF_MEM_LEVEL = 8; { if MAX_MEM_LEVEL > 8 } - -{ Maximum value for windowBits in deflateInit2 and inflateInit2 } -const - MAX_WBITS = 15; { 32K LZ77 window } - -{ default windowBits for decompression. MAX_WBITS is for compression only } -const - DEF_WBITS = MAX_WBITS; - -{ The memory requirements for deflate are (in bytes): - 1 shl (windowBits+2) + 1 shl (memLevel+9) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - DMAX_WBITS=14 DMAX_MEM_LEVEL=7 - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 shl windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. } - - -{ Huffman code lookup table entry--this entry is four bytes for machines - that have 16-bit pointers (e.g. PC's in the small or medium model). } - -type - pInflate_huft = ^inflate_huft; - inflate_huft = Record - Exop, { number of extra bits or operation } - bits : Byte; { number of bits in this code or subcode } - {pad : uInt;} { pad structure to a power of 2 (4 bytes for } - { 16-bit, 8 bytes for 32-bit int's) } - base : uInt; { literal, length base, or distance base } - { or table offset } - End; - -type - huft_field = Array[0..(MaxInt div SizeOf(inflate_huft))-1] of inflate_huft; - huft_ptr = ^huft_field; -type - ppInflate_huft = ^pInflate_huft; - -type - inflate_codes_mode = ( { waiting for "i:"=input, "o:"=output, "x:"=nothing } - START, { x: set up for LEN } - LEN, { i: get length/literal/eob next } - LENEXT, { i: getting length extra (have base) } - DIST, { i: get distance next } - DISTEXT, { i: getting distance extra } - COPY, { o: copying bytes in window, waiting for space } - LIT, { o: got literal, waiting for output space } - WASH, { o: got eob, possibly still output waiting } - ZEND, { x: got eob and all data flushed } - BADCODE); { x: got error } - -{ inflate codes private state } -type - pInflate_codes_state = ^inflate_codes_state; - inflate_codes_state = record - - mode : inflate_codes_mode; { current inflate_codes mode } - - { mode dependent information } - len : uInt; - sub : record { submode } - Case Byte of - 0:(code : record { if LEN or DIST, where in tree } - tree : pInflate_huft; { pointer into tree } - need : uInt; { bits needed } - end); - 1:(lit : uInt); { if LIT, literal } - 2:(copy: record { if EXT or COPY, where and how much } - get : uInt; { bits to get for extra } - dist : uInt; { distance back to copy from } - end); - end; - - { mode independent information } - lbits : Byte; { ltree bits decoded per branch } - dbits : Byte; { dtree bits decoder per branch } - ltree : pInflate_huft; { literal/length/eob tree } - dtree : pInflate_huft; { distance tree } - end; - -type - check_func = function(check : uLong; - buf : pBytef; - {const buf : array of byte;} - len : uInt) : uLong; -type - inflate_block_mode = - (ZTYPE, { get type bits (3, including end bit) } - LENS, { get lengths for stored } - STORED, { processing stored block } - TABLE, { get table lengths } - BTREE, { get bit lengths tree for a dynamic block } - DTREE, { get length, distance trees for a dynamic block } - CODES, { processing fixed or dynamic block } - DRY, { output remaining window bytes } - BLKDONE, { finished last block, done } - BLKBAD); { got a data error--stuck here } - -type - pInflate_blocks_state = ^inflate_blocks_state; - -{ inflate blocks semi-private state } - inflate_blocks_state = record - - mode : inflate_block_mode; { current inflate_block mode } - - { mode dependent information } - sub : record { submode } - case Byte of - 0:(left : uInt); { if STORED, bytes left to copy } - 1:(trees : record { if DTREE, decoding info for trees } - table : uInt; { table lengths (14 bits) } - index : uInt; { index into blens (or border) } - blens : PuIntArray; { bit lengths of codes } - bb : uInt; { bit length tree depth } - tb : pInflate_huft; { bit length decoding tree } - end); - 2:(decode : record { if CODES, current state } - tl : pInflate_huft; - td : pInflate_huft; { trees to free } - codes : pInflate_codes_state; - end); - end; - last : boolean; { true if this block is the last block } - - { mode independent information } - bitk : uInt; { bits in bit buffer } - bitb : uLong; { bit buffer } - hufts : huft_ptr; {pInflate_huft;} { single malloc for tree space } - window : pBytef; { sliding window } - zend : pBytef; { one byte after sliding window } - read : pBytef; { window read pointer } - write : pBytef; { window write pointer } - checkfn : check_func; { check function } - check : uLong; { check on output } - end; - -type - inflate_mode = ( - METHOD, { waiting for method byte } - FLAG, { waiting for flag byte } - DICT4, { four dictionary check bytes to go } - DICT3, { three dictionary check bytes to go } - DICT2, { two dictionary check bytes to go } - DICT1, { one dictionary check byte to go } - DICT0, { waiting for inflateSetDictionary } - BLOCKS, { decompressing blocks } - CHECK4, { four check bytes to go } - CHECK3, { three check bytes to go } - CHECK2, { two check bytes to go } - CHECK1, { one check byte to go } - DONE, { finished check, done } - BAD); { got an error--stay here } - -{ inflate private state } -type - pInternal_state = ^internal_state; { or point to a deflate_state record } - internal_state = record - - mode : inflate_mode; { current inflate mode } - - { mode dependent information } - sub : record { submode } - case byte of - 0:(method : uInt); { if FLAGS, method byte } - 1:(check : record { if CHECK, check values to compare } - was : uLong; { computed check value } - need : uLong; { stream check value } - end); - 2:(marker : uInt); { if BAD, inflateSync's marker bytes count } - end; - - { mode independent information } - nowrap : boolean; { flag for no wrapper } - wbits : uInt; { log2(window size) (8..15, defaults to 15) } - blocks : pInflate_blocks_state; { current inflate_blocks state } - end; - -type - alloc_func = function(opaque : voidpf; items : uInt; size : uInt) : voidpf; - free_func = procedure(opaque : voidpf; address : voidpf); - -type - z_streamp = ^z_stream; - z_stream = record - next_in : pBytef; { next input byte } - avail_in : uInt; { number of bytes available at next_in } - total_in : uLong; { total nb of input bytes read so far } - - next_out : pBytef; { next output byte should be put there } - avail_out : uInt; { remaining free space at next_out } - total_out : uLong; { total nb of bytes output so far } - - msg : string[255]; { last error message, '' if no error } - state : pInternal_state; { not visible by applications } - - zalloc : alloc_func; { used to allocate the internal state } - zfree : free_func; { used to free the internal state } - opaque : voidpf; { private data object passed to zalloc and zfree } - - data_type : int; { best guess about the data type: ascii or binary } - adler : uLong; { adler32 value of the uncompressed data } - reserved : uLong; { reserved for future use } - end; - - -{ The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). } - -const { constants } - Z_NO_FLUSH = 0; - Z_PARTIAL_FLUSH = 1; - Z_SYNC_FLUSH = 2; - Z_FULL_FLUSH = 3; - Z_FINISH = 4; -{ Allowed flush values; see deflate() below for details } - - Z_OK = 0; - Z_STREAM_END = 1; - Z_NEED_DICT = 2; - Z_ERRNO = (-1); - Z_STREAM_ERROR = (-2); - Z_DATA_ERROR = (-3); - Z_MEM_ERROR = (-4); - Z_BUF_ERROR = (-5); - Z_VERSION_ERROR = (-6); -{ Return codes for the compression/decompression functions. Negative - values are errors, positive values are used for special but normal events.} - - Z_NO_COMPRESSION = 0; - Z_BEST_SPEED = 1; - Z_BEST_COMPRESSION = 9; - Z_DEFAULT_COMPRESSION = (-1); -{ compression levels } - - Z_FILTERED = 1; - Z_HUFFMAN_ONLY = 2; - Z_DEFAULT_STRATEGY = 0; -{ compression strategy; see deflateInit2() below for details } - - Z_BINARY = 0; - Z_ASCII = 1; - Z_UNKNOWN = 2; -{ Possible values of the data_type field } - - Z_DEFLATED = 8; -{ The deflate compression method (the only one supported in this version) } - - Z_NULL = NIL; { for initializing zalloc, zfree, opaque } - - {$IFDEF GZIO} -var - errno : int; - {$ENDIF} - - { common constants } - - -{ The three kinds of block type } -const - STORED_BLOCK = 0; - STATIC_TREES = 1; - DYN_TREES = 2; -{ The minimum and maximum match lengths } -const - MIN_MATCH = 3; - MAX_MATCH = 258; - -const - PRESET_DICT = $20; { preset dictionary flag in zlib header } - - - {$IFDEF DEBUG} - procedure Assert(cond : boolean; msg : AnsiString); - {$ENDIF} - - procedure Trace(x : AnsiString); - procedure Tracev(x : AnsiString); - procedure Tracevv(x : AnsiString); - procedure Tracevvv(x : AnsiString); - procedure Tracec(c : boolean; x : AnsiString); - procedure Tracecv(c : boolean; x : AnsiString); - -function zlibVersion : AnsiString; -{ The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is - not compatible with the zlib.h header file used by the application. - This check is automatically made by deflateInit and inflateInit. } - -function zError(err : int) : AnsiString; -function ZALLOC (var strm : z_stream; items : uInt; size : uInt) : voidpf; -procedure ZFREE (var strm : z_stream; ptr : voidpf); -procedure TRY_FREE (var strm : z_stream; ptr : voidpf); - -const - ZLIB_VERSION : string[10] = '1.1.2'; - -const - z_errbase = Z_NEED_DICT; - z_errmsg : Array[0..9] of string[21] = { indexed by 2-zlib_error } - ('need dictionary', { Z_NEED_DICT 2 } - 'stream end', { Z_STREAM_END 1 } - '', { Z_OK 0 } - 'file error', { Z_ERRNO (-1) } - 'stream error', { Z_STREAM_ERROR (-2) } - 'data error', { Z_DATA_ERROR (-3) } - 'insufficient memory', { Z_MEM_ERROR (-4) } - 'buffer error', { Z_BUF_ERROR (-5) } - 'incompatible version',{ Z_VERSION_ERROR (-6) } - ''); -const - z_verbose : int = 1; - -function deflateInit_(var Stream: z_stream; Level: LongInt; const Version: AnsiString; - Stream_size: LongInt): LongInt; -function inflateInit_(var Stream: z_stream; const Version: AnsiString; - Stream_size: Longint): LongInt; - -{$IFDEF DEBUG} -procedure z_error (m : string); -{$ENDIF} - -implementation - -uses - imzdeflate, imzinflate; - -function deflateInit_(var Stream: z_stream; Level: LongInt; const Version: AnsiString; - Stream_size: LongInt): LongInt; -begin - Result := imzdeflate.deflateInit_(@Stream, Level, Version, Stream_size); -end; - -function inflateInit_(var Stream: z_stream; const Version: AnsiString; - Stream_size: Longint): LongInt; -begin - Result := imzinflate.inflateInit_(@Stream, Version, Stream_size); -end; - -function zError(err : int) : AnsiString; -begin - zError := z_errmsg[Z_NEED_DICT-err]; -end; - -function zlibVersion : AnsiString; -begin - zlibVersion := ZLIB_VERSION; -end; - -procedure z_error (m : AnsiString); -begin - WriteLn(output, m); - Write('Zlib - Halt...'); - ReadLn; - Halt(1); -end; - -procedure Assert(cond : boolean; msg : AnsiString); -begin - if not cond then - z_error(msg); -end; - -procedure Trace(x : AnsiString); -begin - WriteLn(x); -end; - -procedure Tracev(x : AnsiString); -begin - if (z_verbose>0) then - WriteLn(x); -end; - -procedure Tracevv(x : AnsiString); -begin - if (z_verbose>1) then - WriteLn(x); -end; - -procedure Tracevvv(x : AnsiString); -begin - if (z_verbose>2) then - WriteLn(x); -end; - -procedure Tracec(c : boolean; x : AnsiString); -begin - if (z_verbose>0) and (c) then - WriteLn(x); -end; - -procedure Tracecv(c : boolean; x : AnsiString); -begin - if (z_verbose>1) and c then - WriteLn(x); -end; - -function ZALLOC (var strm : z_stream; items : uInt; size : uInt) : voidpf; -begin - ZALLOC := strm.zalloc(strm.opaque, items, size); -end; - -procedure ZFREE (var strm : z_stream; ptr : voidpf); -begin - strm.zfree(strm.opaque, ptr); -end; - -procedure TRY_FREE (var strm : z_stream; ptr : voidpf); -begin - {if @strm <> Z_NULL then} - strm.zfree(strm.opaque, ptr); -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/imtrees.pas b/3rd/Imaging/Source/ZLib/imtrees.pas deleted file mode 100644 index 04c0ebf3d..000000000 --- a/3rd/Imaging/Source/ZLib/imtrees.pas +++ /dev/null @@ -1,2249 +0,0 @@ -Unit imtrees; - -{$T-} -{$define ORG_DEBUG} -{ - trees.c -- output deflated data using Huffman coding - Copyright (C) 1995-1998 Jean-loup Gailly - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -{ - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - } - -interface - -{$I imzconf.inc} - -uses - {$ifdef DEBUG} - SysUtils, strutils, - {$ENDIF} - imzutil, impaszlib; - -{ =========================================================================== - Internal compression state. } - -const - LENGTH_CODES = 29; -{ number of length codes, not counting the special END_BLOCK code } - - LITERALS = 256; -{ number of literal bytes 0..255 } - - L_CODES = (LITERALS+1+LENGTH_CODES); -{ number of Literal or Length codes, including the END_BLOCK code } - - D_CODES = 30; -{ number of distance codes } - - BL_CODES = 19; -{ number of codes used to transfer the bit lengths } - - HEAP_SIZE = (2*L_CODES+1); -{ maximum heap size } - - MAX_BITS = 15; -{ All codes must not exceed MAX_BITS bits } - -const - INIT_STATE = 42; - BUSY_STATE = 113; - FINISH_STATE = 666; -{ Stream status } - - -{ Data structure describing a single value and its code string. } -type - ct_data_ptr = ^ct_data; - ct_data = record - fc : record - case byte of - 0:(freq : ush); { frequency count } - 1:(code : ush); { bit string } - end; - dl : record - case byte of - 0:(dad : ush); { father node in Huffman tree } - 1:(len : ush); { length of bit string } - end; - end; - -{ Freq = fc.freq - Code = fc.code - Dad = dl.dad - Len = dl.len } - -type - ltree_type = array[0..HEAP_SIZE-1] of ct_data; { literal and length tree } - dtree_type = array[0..2*D_CODES+1-1] of ct_data; { distance tree } - htree_type = array[0..2*BL_CODES+1-1] of ct_data; { Huffman tree for bit lengths } - { generic tree type } - tree_type = array[0..(MaxInt div SizeOf(ct_data))-1] of ct_data; - - tree_ptr = ^tree_type; - ltree_ptr = ^ltree_type; - dtree_ptr = ^dtree_type; - htree_ptr = ^htree_type; - - -type - static_tree_desc_ptr = ^static_tree_desc; - static_tree_desc = - record - {const} static_tree : tree_ptr; { static tree or NIL } - {const} extra_bits : pzIntfArray; { extra bits for each code or NIL } - extra_base : int; { base index for extra_bits } - elems : int; { max number of elements in the tree } - max_length : int; { max bit length for the codes } - end; - - tree_desc_ptr = ^tree_desc; - tree_desc = record - dyn_tree : tree_ptr; { the dynamic tree } - max_code : int; { largest code with non zero frequency } - stat_desc : static_tree_desc_ptr; { the corresponding static tree } - end; - -type - Pos = ush; - Posf = Pos; {FAR} - IPos = uInt; - - pPosf = ^Posf; - - zPosfArray = array[0..(MaxInt div SizeOf(Posf))-1] of Posf; - pzPosfArray = ^zPosfArray; - -{ A Pos is an index in the character window. We use short instead of int to - save space in the various tables. IPos is used only for parameter passing.} - -type - deflate_state_ptr = ^deflate_state; - deflate_state = record - strm : z_streamp; { pointer back to this zlib stream } - status : int; { as the name implies } - pending_buf : pzByteArray; { output still pending } - pending_buf_size : ulg; { size of pending_buf } - pending_out : pBytef; { next pending byte to output to the stream } - pending : int; { nb of bytes in the pending buffer } - noheader : int; { suppress zlib header and adler32 } - data_type : Byte; { UNKNOWN, BINARY or ASCII } - method : Byte; { STORED (for zip only) or DEFLATED } - last_flush : int; { value of flush param for previous deflate call } - - { used by deflate.pas: } - - w_size : uInt; { LZ77 window size (32K by default) } - w_bits : uInt; { log2(w_size) (8..16) } - w_mask : uInt; { w_size - 1 } - - window : pzByteArray; - { Sliding window. Input bytes are read into the second half of the window, - and move to the first half later to keep a dictionary of at least wSize - bytes. With this organization, matches are limited to a distance of - wSize-MAX_MATCH bytes, but this ensures that IO is always - performed with a length multiple of the block size. Also, it limits - the window size to 64K, which is quite useful on MSDOS. - To do: use the user input buffer as sliding window. } - - window_size : ulg; - { Actual size of window: 2*wSize, except when the user input buffer - is directly used as sliding window. } - - prev : pzPosfArray; - { Link to older string with same hash index. To limit the size of this - array to 64K, this link is maintained only for the last 32K strings. - An index in this array is thus a window index modulo 32K. } - - head : pzPosfArray; { Heads of the hash chains or NIL. } - - ins_h : uInt; { hash index of string to be inserted } - hash_size : uInt; { number of elements in hash table } - hash_bits : uInt; { log2(hash_size) } - hash_mask : uInt; { hash_size-1 } - - hash_shift : uInt; - { Number of bits by which ins_h must be shifted at each input - step. It must be such that after MIN_MATCH steps, the oldest - byte no longer takes part in the hash key, that is: - hash_shift * MIN_MATCH >= hash_bits } - - block_start : long; - { Window position at the beginning of the current output block. Gets - negative when the window is moved backwards. } - - match_length : uInt; { length of best match } - prev_match : IPos; { previous match } - match_available : boolean; { set if previous match exists } - strstart : uInt; { start of string to insert } - match_start : uInt; { start of matching string } - lookahead : uInt; { number of valid bytes ahead in window } - - prev_length : uInt; - { Length of the best match at previous step. Matches not greater than this - are discarded. This is used in the lazy match evaluation. } - - max_chain_length : uInt; - { To speed up deflation, hash chains are never searched beyond this - length. A higher limit improves compression ratio but degrades the - speed. } - - { moved to the end because Borland Pascal won't accept the following: - max_lazy_match : uInt; - max_insert_length : uInt absolute max_lazy_match; - } - - level : int; { compression level (1..9) } - strategy : int; { favor or force Huffman coding} - - good_match : uInt; - { Use a faster search when the previous match is longer than this } - - nice_match : int; { Stop searching when current match exceeds this } - - { used by trees.pas: } - { Didn't use ct_data typedef below to supress compiler warning } - dyn_ltree : ltree_type; { literal and length tree } - dyn_dtree : dtree_type; { distance tree } - bl_tree : htree_type; { Huffman tree for bit lengths } - - l_desc : tree_desc; { desc. for literal tree } - d_desc : tree_desc; { desc. for distance tree } - bl_desc : tree_desc; { desc. for bit length tree } - - bl_count : array[0..MAX_BITS+1-1] of ush; - { number of codes at each bit length for an optimal tree } - - heap : array[0..2*L_CODES+1-1] of int; { heap used to build the Huffman trees } - heap_len : int; { number of elements in the heap } - heap_max : int; { element of largest frequency } - { The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - The same heap array is used to build all trees. } - - depth : array[0..2*L_CODES+1-1] of uch; - { Depth of each subtree used as tie breaker for trees of equal frequency } - - - l_buf : puchfArray; { buffer for literals or lengths } - - lit_bufsize : uInt; - { Size of match buffer for literals/lengths. There are 4 reasons for - limiting lit_bufsize to 64K: - - frequencies can be kept in 16 bit counters - - if compression is not successful for the first block, all input - data is still in the window so we can still emit a stored block even - when input comes from standard input. (This can also be done for - all blocks if lit_bufsize is not greater than 32K.) - - if compression is not successful for a file smaller than 64K, we can - even emit a stored file instead of a stored block (saving 5 bytes). - This is applicable only for zip (not gzip or zlib). - - creating new Huffman trees less frequently may not provide fast - adaptation to changes in the input data statistics. (Take for - example a binary file with poorly compressible code followed by - a highly compressible string table.) Smaller buffer sizes give - fast adaptation but have of course the overhead of transmitting - trees more frequently. - - I can't count above 4 } - - - last_lit : uInt; { running index in l_buf } - - d_buf : pushfArray; - { Buffer for distances. To simplify the code, d_buf and l_buf have - the same number of elements. To use different lengths, an extra flag - array would be necessary. } - - opt_len : ulg; { bit length of current block with optimal trees } - static_len : ulg; { bit length of current block with static trees } - compressed_len : ulg; { total bit length of compressed file } - matches : uInt; { number of string matches in current block } - last_eob_len : int; { bit length of EOB code for last block } - -{$ifdef DEBUG} - bits_sent : ulg; { bit length of the compressed data } -{$endif} - - bi_buf : ush; - { Output buffer. bits are inserted starting at the bottom (least - significant bits). } - - bi_valid : int; - { Number of valid bits in bi_buf. All bits above the last valid bit - are always zero. } - - case byte of - 0:(max_lazy_match : uInt); - { Attempt to find a better match only when the current match is strictly - smaller than this value. This mechanism is used only for compression - levels >= 4. } - - 1:(max_insert_length : uInt); - { Insert new strings in the hash table only if the match length is not - greater than this length. This saves time but degrades compression. - max_insert_length is used only for compression levels <= 3. } - end; - -procedure _tr_init (var s : deflate_state); - -function _tr_tally (var s : deflate_state; - dist : unsigned; - lc : unsigned) : boolean; - -function _tr_flush_block (var s : deflate_state; - buf : pcharf; - stored_len : ulg; - eof : boolean) : ulg; - -procedure _tr_align(var s : deflate_state); - -procedure _tr_stored_block(var s : deflate_state; - buf : pcharf; - stored_len : ulg; - eof : boolean); - -implementation - -{ #define GEN_TREES_H } - -{$ifndef GEN_TREES_H} -{ header created automatically with -DGEN_TREES_H } - -const - DIST_CODE_LEN = 512; { see definition of array dist_code below } - -{ The static literal tree. Since the bit lengths are imposed, there is no - need for the L_CODES extra codes used during heap construction. However - The codes 286 and 287 are needed to build a canonical tree (see _tr_init - below). } -var - static_ltree : array[0..L_CODES+2-1] of ct_data = ( -{ fc:(freq, code) dl:(dad,len) } -(fc:(freq: 12);dl:(len: 8)), (fc:(freq:140);dl:(len: 8)), (fc:(freq: 76);dl:(len: 8)), -(fc:(freq:204);dl:(len: 8)), (fc:(freq: 44);dl:(len: 8)), (fc:(freq:172);dl:(len: 8)), -(fc:(freq:108);dl:(len: 8)), (fc:(freq:236);dl:(len: 8)), (fc:(freq: 28);dl:(len: 8)), -(fc:(freq:156);dl:(len: 8)), (fc:(freq: 92);dl:(len: 8)), (fc:(freq:220);dl:(len: 8)), -(fc:(freq: 60);dl:(len: 8)), (fc:(freq:188);dl:(len: 8)), (fc:(freq:124);dl:(len: 8)), -(fc:(freq:252);dl:(len: 8)), (fc:(freq: 2);dl:(len: 8)), (fc:(freq:130);dl:(len: 8)), -(fc:(freq: 66);dl:(len: 8)), (fc:(freq:194);dl:(len: 8)), (fc:(freq: 34);dl:(len: 8)), -(fc:(freq:162);dl:(len: 8)), (fc:(freq: 98);dl:(len: 8)), (fc:(freq:226);dl:(len: 8)), -(fc:(freq: 18);dl:(len: 8)), (fc:(freq:146);dl:(len: 8)), (fc:(freq: 82);dl:(len: 8)), -(fc:(freq:210);dl:(len: 8)), (fc:(freq: 50);dl:(len: 8)), (fc:(freq:178);dl:(len: 8)), -(fc:(freq:114);dl:(len: 8)), (fc:(freq:242);dl:(len: 8)), (fc:(freq: 10);dl:(len: 8)), -(fc:(freq:138);dl:(len: 8)), (fc:(freq: 74);dl:(len: 8)), (fc:(freq:202);dl:(len: 8)), -(fc:(freq: 42);dl:(len: 8)), (fc:(freq:170);dl:(len: 8)), (fc:(freq:106);dl:(len: 8)), -(fc:(freq:234);dl:(len: 8)), (fc:(freq: 26);dl:(len: 8)), (fc:(freq:154);dl:(len: 8)), -(fc:(freq: 90);dl:(len: 8)), (fc:(freq:218);dl:(len: 8)), (fc:(freq: 58);dl:(len: 8)), -(fc:(freq:186);dl:(len: 8)), (fc:(freq:122);dl:(len: 8)), (fc:(freq:250);dl:(len: 8)), -(fc:(freq: 6);dl:(len: 8)), (fc:(freq:134);dl:(len: 8)), (fc:(freq: 70);dl:(len: 8)), -(fc:(freq:198);dl:(len: 8)), (fc:(freq: 38);dl:(len: 8)), (fc:(freq:166);dl:(len: 8)), -(fc:(freq:102);dl:(len: 8)), (fc:(freq:230);dl:(len: 8)), (fc:(freq: 22);dl:(len: 8)), -(fc:(freq:150);dl:(len: 8)), (fc:(freq: 86);dl:(len: 8)), (fc:(freq:214);dl:(len: 8)), -(fc:(freq: 54);dl:(len: 8)), (fc:(freq:182);dl:(len: 8)), (fc:(freq:118);dl:(len: 8)), -(fc:(freq:246);dl:(len: 8)), (fc:(freq: 14);dl:(len: 8)), (fc:(freq:142);dl:(len: 8)), -(fc:(freq: 78);dl:(len: 8)), (fc:(freq:206);dl:(len: 8)), (fc:(freq: 46);dl:(len: 8)), -(fc:(freq:174);dl:(len: 8)), (fc:(freq:110);dl:(len: 8)), (fc:(freq:238);dl:(len: 8)), -(fc:(freq: 30);dl:(len: 8)), (fc:(freq:158);dl:(len: 8)), (fc:(freq: 94);dl:(len: 8)), -(fc:(freq:222);dl:(len: 8)), (fc:(freq: 62);dl:(len: 8)), (fc:(freq:190);dl:(len: 8)), -(fc:(freq:126);dl:(len: 8)), (fc:(freq:254);dl:(len: 8)), (fc:(freq: 1);dl:(len: 8)), -(fc:(freq:129);dl:(len: 8)), (fc:(freq: 65);dl:(len: 8)), (fc:(freq:193);dl:(len: 8)), -(fc:(freq: 33);dl:(len: 8)), (fc:(freq:161);dl:(len: 8)), (fc:(freq: 97);dl:(len: 8)), -(fc:(freq:225);dl:(len: 8)), (fc:(freq: 17);dl:(len: 8)), (fc:(freq:145);dl:(len: 8)), -(fc:(freq: 81);dl:(len: 8)), (fc:(freq:209);dl:(len: 8)), (fc:(freq: 49);dl:(len: 8)), -(fc:(freq:177);dl:(len: 8)), (fc:(freq:113);dl:(len: 8)), (fc:(freq:241);dl:(len: 8)), -(fc:(freq: 9);dl:(len: 8)), (fc:(freq:137);dl:(len: 8)), (fc:(freq: 73);dl:(len: 8)), -(fc:(freq:201);dl:(len: 8)), (fc:(freq: 41);dl:(len: 8)), (fc:(freq:169);dl:(len: 8)), -(fc:(freq:105);dl:(len: 8)), (fc:(freq:233);dl:(len: 8)), (fc:(freq: 25);dl:(len: 8)), -(fc:(freq:153);dl:(len: 8)), (fc:(freq: 89);dl:(len: 8)), (fc:(freq:217);dl:(len: 8)), -(fc:(freq: 57);dl:(len: 8)), (fc:(freq:185);dl:(len: 8)), (fc:(freq:121);dl:(len: 8)), -(fc:(freq:249);dl:(len: 8)), (fc:(freq: 5);dl:(len: 8)), (fc:(freq:133);dl:(len: 8)), -(fc:(freq: 69);dl:(len: 8)), (fc:(freq:197);dl:(len: 8)), (fc:(freq: 37);dl:(len: 8)), -(fc:(freq:165);dl:(len: 8)), (fc:(freq:101);dl:(len: 8)), (fc:(freq:229);dl:(len: 8)), -(fc:(freq: 21);dl:(len: 8)), (fc:(freq:149);dl:(len: 8)), (fc:(freq: 85);dl:(len: 8)), -(fc:(freq:213);dl:(len: 8)), (fc:(freq: 53);dl:(len: 8)), (fc:(freq:181);dl:(len: 8)), -(fc:(freq:117);dl:(len: 8)), (fc:(freq:245);dl:(len: 8)), (fc:(freq: 13);dl:(len: 8)), -(fc:(freq:141);dl:(len: 8)), (fc:(freq: 77);dl:(len: 8)), (fc:(freq:205);dl:(len: 8)), -(fc:(freq: 45);dl:(len: 8)), (fc:(freq:173);dl:(len: 8)), (fc:(freq:109);dl:(len: 8)), -(fc:(freq:237);dl:(len: 8)), (fc:(freq: 29);dl:(len: 8)), (fc:(freq:157);dl:(len: 8)), -(fc:(freq: 93);dl:(len: 8)), (fc:(freq:221);dl:(len: 8)), (fc:(freq: 61);dl:(len: 8)), -(fc:(freq:189);dl:(len: 8)), (fc:(freq:125);dl:(len: 8)), (fc:(freq:253);dl:(len: 8)), -(fc:(freq: 19);dl:(len: 9)), (fc:(freq:275);dl:(len: 9)), (fc:(freq:147);dl:(len: 9)), -(fc:(freq:403);dl:(len: 9)), (fc:(freq: 83);dl:(len: 9)), (fc:(freq:339);dl:(len: 9)), -(fc:(freq:211);dl:(len: 9)), (fc:(freq:467);dl:(len: 9)), (fc:(freq: 51);dl:(len: 9)), -(fc:(freq:307);dl:(len: 9)), (fc:(freq:179);dl:(len: 9)), (fc:(freq:435);dl:(len: 9)), -(fc:(freq:115);dl:(len: 9)), (fc:(freq:371);dl:(len: 9)), (fc:(freq:243);dl:(len: 9)), -(fc:(freq:499);dl:(len: 9)), (fc:(freq: 11);dl:(len: 9)), (fc:(freq:267);dl:(len: 9)), -(fc:(freq:139);dl:(len: 9)), (fc:(freq:395);dl:(len: 9)), (fc:(freq: 75);dl:(len: 9)), -(fc:(freq:331);dl:(len: 9)), (fc:(freq:203);dl:(len: 9)), (fc:(freq:459);dl:(len: 9)), -(fc:(freq: 43);dl:(len: 9)), (fc:(freq:299);dl:(len: 9)), (fc:(freq:171);dl:(len: 9)), -(fc:(freq:427);dl:(len: 9)), (fc:(freq:107);dl:(len: 9)), (fc:(freq:363);dl:(len: 9)), -(fc:(freq:235);dl:(len: 9)), (fc:(freq:491);dl:(len: 9)), (fc:(freq: 27);dl:(len: 9)), -(fc:(freq:283);dl:(len: 9)), (fc:(freq:155);dl:(len: 9)), (fc:(freq:411);dl:(len: 9)), -(fc:(freq: 91);dl:(len: 9)), (fc:(freq:347);dl:(len: 9)), (fc:(freq:219);dl:(len: 9)), -(fc:(freq:475);dl:(len: 9)), (fc:(freq: 59);dl:(len: 9)), (fc:(freq:315);dl:(len: 9)), -(fc:(freq:187);dl:(len: 9)), (fc:(freq:443);dl:(len: 9)), (fc:(freq:123);dl:(len: 9)), -(fc:(freq:379);dl:(len: 9)), (fc:(freq:251);dl:(len: 9)), (fc:(freq:507);dl:(len: 9)), -(fc:(freq: 7);dl:(len: 9)), (fc:(freq:263);dl:(len: 9)), (fc:(freq:135);dl:(len: 9)), -(fc:(freq:391);dl:(len: 9)), (fc:(freq: 71);dl:(len: 9)), (fc:(freq:327);dl:(len: 9)), -(fc:(freq:199);dl:(len: 9)), (fc:(freq:455);dl:(len: 9)), (fc:(freq: 39);dl:(len: 9)), -(fc:(freq:295);dl:(len: 9)), (fc:(freq:167);dl:(len: 9)), (fc:(freq:423);dl:(len: 9)), -(fc:(freq:103);dl:(len: 9)), (fc:(freq:359);dl:(len: 9)), (fc:(freq:231);dl:(len: 9)), -(fc:(freq:487);dl:(len: 9)), (fc:(freq: 23);dl:(len: 9)), (fc:(freq:279);dl:(len: 9)), -(fc:(freq:151);dl:(len: 9)), (fc:(freq:407);dl:(len: 9)), (fc:(freq: 87);dl:(len: 9)), -(fc:(freq:343);dl:(len: 9)), (fc:(freq:215);dl:(len: 9)), (fc:(freq:471);dl:(len: 9)), -(fc:(freq: 55);dl:(len: 9)), (fc:(freq:311);dl:(len: 9)), (fc:(freq:183);dl:(len: 9)), -(fc:(freq:439);dl:(len: 9)), (fc:(freq:119);dl:(len: 9)), (fc:(freq:375);dl:(len: 9)), -(fc:(freq:247);dl:(len: 9)), (fc:(freq:503);dl:(len: 9)), (fc:(freq: 15);dl:(len: 9)), -(fc:(freq:271);dl:(len: 9)), (fc:(freq:143);dl:(len: 9)), (fc:(freq:399);dl:(len: 9)), -(fc:(freq: 79);dl:(len: 9)), (fc:(freq:335);dl:(len: 9)), (fc:(freq:207);dl:(len: 9)), -(fc:(freq:463);dl:(len: 9)), (fc:(freq: 47);dl:(len: 9)), (fc:(freq:303);dl:(len: 9)), -(fc:(freq:175);dl:(len: 9)), (fc:(freq:431);dl:(len: 9)), (fc:(freq:111);dl:(len: 9)), -(fc:(freq:367);dl:(len: 9)), (fc:(freq:239);dl:(len: 9)), (fc:(freq:495);dl:(len: 9)), -(fc:(freq: 31);dl:(len: 9)), (fc:(freq:287);dl:(len: 9)), (fc:(freq:159);dl:(len: 9)), -(fc:(freq:415);dl:(len: 9)), (fc:(freq: 95);dl:(len: 9)), (fc:(freq:351);dl:(len: 9)), -(fc:(freq:223);dl:(len: 9)), (fc:(freq:479);dl:(len: 9)), (fc:(freq: 63);dl:(len: 9)), -(fc:(freq:319);dl:(len: 9)), (fc:(freq:191);dl:(len: 9)), (fc:(freq:447);dl:(len: 9)), -(fc:(freq:127);dl:(len: 9)), (fc:(freq:383);dl:(len: 9)), (fc:(freq:255);dl:(len: 9)), -(fc:(freq:511);dl:(len: 9)), (fc:(freq: 0);dl:(len: 7)), (fc:(freq: 64);dl:(len: 7)), -(fc:(freq: 32);dl:(len: 7)), (fc:(freq: 96);dl:(len: 7)), (fc:(freq: 16);dl:(len: 7)), -(fc:(freq: 80);dl:(len: 7)), (fc:(freq: 48);dl:(len: 7)), (fc:(freq:112);dl:(len: 7)), -(fc:(freq: 8);dl:(len: 7)), (fc:(freq: 72);dl:(len: 7)), (fc:(freq: 40);dl:(len: 7)), -(fc:(freq:104);dl:(len: 7)), (fc:(freq: 24);dl:(len: 7)), (fc:(freq: 88);dl:(len: 7)), -(fc:(freq: 56);dl:(len: 7)), (fc:(freq:120);dl:(len: 7)), (fc:(freq: 4);dl:(len: 7)), -(fc:(freq: 68);dl:(len: 7)), (fc:(freq: 36);dl:(len: 7)), (fc:(freq:100);dl:(len: 7)), -(fc:(freq: 20);dl:(len: 7)), (fc:(freq: 84);dl:(len: 7)), (fc:(freq: 52);dl:(len: 7)), -(fc:(freq:116);dl:(len: 7)), (fc:(freq: 3);dl:(len: 8)), (fc:(freq:131);dl:(len: 8)), -(fc:(freq: 67);dl:(len: 8)), (fc:(freq:195);dl:(len: 8)), (fc:(freq: 35);dl:(len: 8)), -(fc:(freq:163);dl:(len: 8)), (fc:(freq: 99);dl:(len: 8)), (fc:(freq:227);dl:(len: 8)) -); - - -{ The static distance tree. (Actually a trivial tree since all lens use - 5 bits.) } - static_dtree : array[0..D_CODES-1] of ct_data = ( -(fc:(freq: 0); dl:(len:5)), (fc:(freq:16); dl:(len:5)), (fc:(freq: 8); dl:(len:5)), -(fc:(freq:24); dl:(len:5)), (fc:(freq: 4); dl:(len:5)), (fc:(freq:20); dl:(len:5)), -(fc:(freq:12); dl:(len:5)), (fc:(freq:28); dl:(len:5)), (fc:(freq: 2); dl:(len:5)), -(fc:(freq:18); dl:(len:5)), (fc:(freq:10); dl:(len:5)), (fc:(freq:26); dl:(len:5)), -(fc:(freq: 6); dl:(len:5)), (fc:(freq:22); dl:(len:5)), (fc:(freq:14); dl:(len:5)), -(fc:(freq:30); dl:(len:5)), (fc:(freq: 1); dl:(len:5)), (fc:(freq:17); dl:(len:5)), -(fc:(freq: 9); dl:(len:5)), (fc:(freq:25); dl:(len:5)), (fc:(freq: 5); dl:(len:5)), -(fc:(freq:21); dl:(len:5)), (fc:(freq:13); dl:(len:5)), (fc:(freq:29); dl:(len:5)), -(fc:(freq: 3); dl:(len:5)), (fc:(freq:19); dl:(len:5)), (fc:(freq:11); dl:(len:5)), -(fc:(freq:27); dl:(len:5)), (fc:(freq: 7); dl:(len:5)), (fc:(freq:23); dl:(len:5)) -); - -{ Distance codes. The first 256 values correspond to the distances - 3 .. 258, the last 256 values correspond to the top 8 bits of - the 15 bit distances. } - _dist_code : array[0..DIST_CODE_LEN-1] of uch = ( - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -); - -{ length code for each normalized match length (0 == MIN_MATCH) } - _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of uch = ( - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -); - - -{ First normalized length for each code (0 = MIN_MATCH) } - base_length : array[0..LENGTH_CODES-1] of int = ( -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -); - - -{ First normalized distance for each code (0 = distance of 1) } - base_dist : array[0..D_CODES-1] of int = ( - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -); -{$endif} - -{ Output a byte on the stream. - IN assertion: there is enough room in pending_buf. -macro put_byte(s, c) -begin - s^.pending_buf^[s^.pending] := (c); - Inc(s^.pending); -end -} - -const - MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1); -{ Minimum amount of lookahead, except at the end of the input file. - See deflate.c for comments about the MIN_MATCH+1. } - -{macro d_code(dist) - if (dist) < 256 then - := _dist_code[dist] - else - := _dist_code[256+((dist) shr 7)]); - Mapping from a distance to a distance code. dist is the distance - 1 and - must not have side effects. _dist_code[256] and _dist_code[257] are never - used. } - -{$ifndef ORG_DEBUG} -{ Inline versions of _tr_tally for speed: } - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch _length_code[]; - extern uch _dist_code[]; -#else - extern const uch _length_code[]; - extern const uch _dist_code[]; -#endif - -macro _tr_tally_lit(s, c, flush) -var - cc : uch; -begin - cc := (c); - s^.d_buf[s^.last_lit] := 0; - s^.l_buf[s^.last_lit] := cc; - Inc(s^.last_lit); - Inc(s^.dyn_ltree[cc].fc.Freq); - flush := (s^.last_lit = s^.lit_bufsize-1); -end; - -macro _tr_tally_dist(s, distance, length, flush) \ -var - len : uch; - dist : ush; -begin - len := (length); - dist := (distance); - s^.d_buf[s^.last_lit] := dist; - s^.l_buf[s^.last_lit] = len; - Inc(s^.last_lit); - Dec(dist); - Inc(s^.dyn_ltree[_length_code[len]+LITERALS+1].fc.Freq); - Inc(s^.dyn_dtree[d_code(dist)].Freq); - flush := (s^.last_lit = s^.lit_bufsize-1); -end; - -{$endif} - -{ =========================================================================== - Constants } - -const - MAX_BL_BITS = 7; -{ Bit length codes must not exceed MAX_BL_BITS bits } - -const - END_BLOCK = 256; -{ end of block literal code } - -const - REP_3_6 = 16; -{ repeat previous bit length 3-6 times (2 bits of repeat count) } - -const - REPZ_3_10 = 17; -{ repeat a zero length 3-10 times (3 bits of repeat count) } - -const - REPZ_11_138 = 18; -{ repeat a zero length 11-138 times (7 bits of repeat count) } - -{local} -const - extra_lbits : array[0..LENGTH_CODES-1] of int - { extra bits for each length code } - = (0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0); - -{local} -const - extra_dbits : array[0..D_CODES-1] of int - { extra bits for each distance code } - = (0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13); - -{local} -const - extra_blbits : array[0..BL_CODES-1] of int { extra bits for each bit length code } - = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7); - -{local} -const - bl_order : array[0..BL_CODES-1] of uch - = (16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15); -{ The lengths of the bit length codes are sent in order of decreasing - probability, to avoid transmitting the lengths for unused bit length codes. - } - -const - Buf_size = (8 * 2*sizeof(uch)); -{ Number of bits used within bi_buf. (bi_buf might be implemented on - more than 16 bits on some systems.) } - -{ =========================================================================== - Local data. These are initialized only once. } - - -{$ifdef GEN_TREES_H)} -{ non ANSI compilers may not accept trees.h } - -const - DIST_CODE_LEN = 512; { see definition of array dist_code below } - -{local} -var - static_ltree : array[0..L_CODES+2-1] of ct_data; -{ The static literal tree. Since the bit lengths are imposed, there is no - need for the L_CODES extra codes used during heap construction. However - The codes 286 and 287 are needed to build a canonical tree (see _tr_init - below). } - -{local} - static_dtree : array[0..D_CODES-1] of ct_data; -{ The static distance tree. (Actually a trivial tree since all codes use - 5 bits.) } - - _dist_code : array[0..DIST_CODE_LEN-1] of uch; -{ Distance codes. The first 256 values correspond to the distances - 3 .. 258, the last 256 values correspond to the top 8 bits of - the 15 bit distances. } - - _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of uch; -{ length code for each normalized match length (0 == MIN_MATCH) } - -{local} - base_length : array[0..LENGTH_CODES-1] of int; -{ First normalized length for each code (0 = MIN_MATCH) } - -{local} - base_dist : array[0..D_CODES-1] of int; -{ First normalized distance for each code (0 = distance of 1) } - -{$endif} { GEN_TREES_H } - -{local} -const - static_l_desc : static_tree_desc = - (static_tree: {tree_ptr}(@(static_ltree)); { pointer to array of ct_data } - extra_bits: {pzIntfArray}(@(extra_lbits)); { pointer to array of int } - extra_base: LITERALS+1; - elems: L_CODES; - max_length: MAX_BITS); - -{local} -const - static_d_desc : static_tree_desc = - (static_tree: {tree_ptr}(@(static_dtree)); - extra_bits: {pzIntfArray}(@(extra_dbits)); - extra_base : 0; - elems: D_CODES; - max_length: MAX_BITS); - -{local} -const - static_bl_desc : static_tree_desc = - (static_tree: {tree_ptr}(NIL); - extra_bits: {pzIntfArray}@(extra_blbits); - extra_base : 0; - elems: BL_CODES; - max_length: MAX_BL_BITS); - -(* =========================================================================== - Local (static) routines in this file. } - -procedure tr_static_init; -procedure init_block(var deflate_state); -procedure pqdownheap(var s : deflate_state; - var tree : ct_data; - k : int); -procedure gen_bitlen(var s : deflate_state; - var desc : tree_desc); -procedure gen_codes(var tree : ct_data; - max_code : int; - bl_count : pushf); -procedure build_tree(var s : deflate_state; - var desc : tree_desc); -procedure scan_tree(var s : deflate_state; - var tree : ct_data; - max_code : int); -procedure send_tree(var s : deflate_state; - var tree : ct_data; - max_code : int); -function build_bl_tree(var deflate_state) : int; -procedure send_all_trees(var deflate_state; - lcodes : int; - dcodes : int; - blcodes : int); -procedure compress_block(var s : deflate_state; - var ltree : ct_data; - var dtree : ct_data); -procedure set_data_type(var s : deflate_state); -function bi_reverse(value : unsigned; - length : int) : unsigned; -procedure bi_windup(var deflate_state); -procedure bi_flush(var deflate_state); -procedure copy_block(var deflate_state; - buf : pcharf; - len : unsigned; - header : int); -*) - -{$ifdef GEN_TREES_H} -{local} -procedure gen_trees_header; -{$endif} - -(* -{ =========================================================================== - Output a short LSB first on the stream. - IN assertion: there is enough room in pendingBuf. } - -macro put_short(s, w) -begin - {put_byte(s, (uch)((w) & 0xff));} - s.pending_buf^[s.pending] := uch((w) and $ff); - Inc(s.pending); - - {put_byte(s, (uch)((ush)(w) >> 8));} - s.pending_buf^[s.pending] := uch(ush(w) shr 8);; - Inc(s.pending); -end -*) - -{ =========================================================================== - Send a value on a given number of bits. - IN assertion: length <= 16 and value fits in length bits. } - -{$ifdef ORG_DEBUG} - -{local} -procedure send_bits(var s : deflate_state; - value : int; { value to send } - length : int); { number of bits } -begin - {$ifdef DEBUG} - Tracevv(' l '+IntToStr(length)+ ' v '+IntToStr(value)); - Assert((length > 0) and (length <= 15), 'invalid length'); - Inc(s.bits_sent, ulg(length)); - {$ENDIF} - - { If not enough room in bi_buf, use (valid) bits from bi_buf and - (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - unused bits in value. } - {$IFOPT Q+} {$Q-} {$DEFINE NoOverflowCheck} {$ENDIF} - {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} - if (s.bi_valid > int(Buf_size) - length) then - begin - s.bi_buf := s.bi_buf or int(value shl s.bi_valid); - {put_short(s, s.bi_buf);} - s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); - Inc(s.pending); - s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; - Inc(s.pending); - - s.bi_buf := ush(value) shr (Buf_size - s.bi_valid); - Inc(s.bi_valid, length - Buf_size); - end - else - begin - s.bi_buf := s.bi_buf or int(value shl s.bi_valid); - Inc(s.bi_valid, length); - end; - {$IFDEF NoOverflowCheck} {$Q+} {$UNDEF NoOverflowCheck} {$ENDIF} - {$IFDEF NoRangeCheck} {$Q+} {$UNDEF NoRangeCheck} {$ENDIF} -end; - -{$else} { !DEBUG } - - -macro send_code(s, c, tree) -begin - send_bits(s, tree[c].Code, tree[c].Len); - { Send a code of the given tree. c and tree must not have side effects } -end - -macro send_bits(s, value, length) \ -begin int len := length;\ - if (s^.bi_valid > (int)Buf_size - len) begin\ - int val := value;\ - s^.bi_buf |= (val << s^.bi_valid);\ - {put_short(s, s.bi_buf);} - s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); - Inc(s.pending); - s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; - Inc(s.pending); - - s^.bi_buf := (ush)val >> (Buf_size - s^.bi_valid);\ - s^.bi_valid += len - Buf_size;\ - end else begin\ - s^.bi_buf |= (value) << s^.bi_valid;\ - s^.bi_valid += len;\ - end\ -end; -{$endif} { DEBUG } - -{ =========================================================================== - Reverse the first len bits of a code, using straightforward code (a faster - method would use a table) - IN assertion: 1 <= len <= 15 } - -{local} -function bi_reverse(code : unsigned; { the value to invert } - len : int) : unsigned; { its bit length } - -var - res : unsigned; {register} -begin - res := 0; - repeat - res := res or (code and 1); - code := code shr 1; - res := res shl 1; - Dec(len); - until (len <= 0); - bi_reverse := res shr 1; -end; - -{ =========================================================================== - Generate the codes for a given tree and bit counts (which need not be - optimal). - IN assertion: the array bl_count contains the bit length statistics for - the given tree and the field len is set for all tree elements. - OUT assertion: the field code is set for all tree elements of non - zero code length. } - -{local} -procedure gen_codes(tree : tree_ptr; { the tree to decorate } - max_code : int; { largest code with non zero frequency } - var bl_count : array of ushf); { number of codes at each bit length } - -var - next_code : array[0..MAX_BITS+1-1] of ush; { next code value for each bit length } - code : ush; { running code value } - bits : int; { bit index } - n : int; { code index } -var - len : int; -begin - code := 0; - - { The distribution counts are first used to generate the code values - without bit reversal. } - - for bits := 1 to MAX_BITS do - begin - code := ((code + bl_count[bits-1]) shl 1); - next_code[bits] := code; - end; - { Check that the bit counts in bl_count are consistent. The last code - must be all ones. } - - {$IFDEF DEBUG} - Assert (code + bl_count[MAX_BITS]-1 = (1 shl MAX_BITS)-1, - 'inconsistent bit counts'); - Tracev(#13'gen_codes: max_code '+IntToStr(max_code)); - {$ENDIF} - - for n := 0 to max_code do - begin - len := tree^[n].dl.Len; - if (len = 0) then - continue; - { Now reverse the bits } - tree^[n].fc.Code := bi_reverse(next_code[len], len); - Inc(next_code[len]); - {$ifdef DEBUG} - if (n>31) and (n<128) then - Tracecv(tree <> tree_ptr(@static_ltree), - (^M'n #'+IntToStr(n)+' '+AnsiChar(n)+' l '+IntToStr(len)+' c '+ - IntToStr(tree^[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')')) - else - Tracecv(tree <> tree_ptr(@static_ltree), - (^M'n #'+IntToStr(n)+' l '+IntToStr(len)+' c '+ - IntToStr(tree^[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')')); - {$ENDIF} - end; -end; - -{ =========================================================================== - Genererate the file trees.h describing the static trees. } -{$ifdef GEN_TREES_H} - -macro SEPARATOR(i, last, width) - if (i) = (last) then - ( ^M');'^M^M - else \ - if (i) mod (width) = (width)-1 then - ','^M - else - ', ' - -procedure gen_trees_header; -var - header : system.text; - i : int; -begin - system.assign(header, 'trees.inc'); - {$I-} - ReWrite(header); - {$I+} - Assert (IOresult <> 0, 'Can''t open trees.h'); - WriteLn(header, - '{ header created automatically with -DGEN_TREES_H }'^M); - - WriteLn(header, 'local const ct_data static_ltree[L_CODES+2] := ('); - for i := 0 to L_CODES+2-1 do - begin - WriteLn(header, '((%3u),(%3u))%s', static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - end; - - WriteLn(header, 'local const ct_data static_dtree[D_CODES] := ('); - for i := 0 to D_CODES-1 do - begin - WriteLn(header, '((%2u),(%2u))%s', static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - end; - - WriteLn(header, 'const uch _dist_code[DIST_CODE_LEN] := ('); - for i := 0 to DIST_CODE_LEN-1 do - begin - WriteLn(header, '%2u%s', _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - end; - - WriteLn(header, 'const uch _length_code[MAX_MATCH-MIN_MATCH+1]= ('); - for i := 0 to MAX_MATCH-MIN_MATCH+1-1 do - begin - WriteLn(header, '%2u%s', _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - end; - - WriteLn(header, 'local const int base_length[LENGTH_CODES] := ('); - for i := 0 to LENGTH_CODES-1 do - begin - WriteLn(header, '%1u%s', base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - end; - - WriteLn(header, 'local const int base_dist[D_CODES] := ('); - for i := 0 to D_CODES-1 do - begin - WriteLn(header, '%5u%s', base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - end; - - close(header); -end; -{$endif} { GEN_TREES_H } - - -{ =========================================================================== - Initialize the various 'constant' tables. } - -{local} -procedure tr_static_init; - -{$ifdef GEN_TREES_H} -const - static_init_done : boolean = FALSE; -var - n : int; { iterates over tree elements } - bits : int; { bit counter } - length : int; { length value } - code : int; { code value } - dist : int; { distance index } - bl_count : array[0..MAX_BITS+1-1] of ush; - { number of codes at each bit length for an optimal tree } -begin - if (static_init_done) then - exit; - - { Initialize the mapping length (0..255) -> length code (0..28) } - length := 0; - for code := 0 to LENGTH_CODES-1-1 do - begin - base_length[code] := length; - for n := 0 to (1 shl extra_lbits[code])-1 do - begin - _length_code[length] := uch(code); - Inc(length); - end; - end; - Assert (length = 256, 'tr_static_init: length <> 256'); - { Note that the length 255 (match length 258) can be represented - in two different ways: code 284 + 5 bits or code 285, so we - overwrite length_code[255] to use the best encoding: } - - _length_code[length-1] := uch(code); - - { Initialize the mapping dist (0..32K) -> dist code (0..29) } - dist := 0; - for code := 0 to 16-1 do - begin - base_dist[code] := dist; - for n := 0 to (1 shl extra_dbits[code])-1 do - begin - _dist_code[dist] := uch(code); - Inc(dist); - end; - end; - Assert (dist = 256, 'tr_static_init: dist <> 256'); - dist := dist shr 7; { from now on, all distances are divided by 128 } - for code := 16 to D_CODES-1 do - begin - base_dist[code] := dist shl 7; - for n := 0 to (1 shl (extra_dbits[code]-7))-1 do - begin - _dist_code[256 + dist] := uch(code); - Inc(dist); - end; - end; - Assert (dist = 256, 'tr_static_init: 256+dist <> 512'); - - { Construct the codes of the static literal tree } - for bits := 0 to MAX_BITS do - bl_count[bits] := 0; - n := 0; - while (n <= 143) do - begin - static_ltree[n].dl.Len := 8; - Inc(n); - Inc(bl_count[8]); - end; - while (n <= 255) do - begin - static_ltree[n].dl.Len := 9; - Inc(n); - Inc(bl_count[9]); - end; - while (n <= 279) do - begin - static_ltree[n].dl.Len := 7; - Inc(n); - Inc(bl_count[7]); - end; - while (n <= 287) do - begin - static_ltree[n].dl.Len := 8; - Inc(n); - Inc(bl_count[8]); - end; - - { Codes 286 and 287 do not exist, but we must include them in the - tree construction to get a canonical Huffman tree (longest code - all ones) } - - gen_codes(tree_ptr(@static_ltree), L_CODES+1, bl_count); - - { The static distance tree is trivial: } - for n := 0 to D_CODES-1 do - begin - static_dtree[n].dl.Len := 5; - static_dtree[n].fc.Code := bi_reverse(unsigned(n), 5); - end; - static_init_done := TRUE; - - gen_trees_header; { save to include file } -{$else} -begin -{$endif} { GEN_TREES_H) } -end; - -{ =========================================================================== - Initialize a new block. } -{local} - -procedure init_block(var s : deflate_state); -var - n : int; { iterates over tree elements } -begin - { Initialize the trees. } - for n := 0 to L_CODES-1 do - s.dyn_ltree[n].fc.Freq := 0; - for n := 0 to D_CODES-1 do - s.dyn_dtree[n].fc.Freq := 0; - for n := 0 to BL_CODES-1 do - s.bl_tree[n].fc.Freq := 0; - - s.dyn_ltree[END_BLOCK].fc.Freq := 1; - s.static_len := Long(0); - s.opt_len := Long(0); - s.matches := 0; - s.last_lit := 0; -end; - -const - SMALLEST = 1; -{ Index within the heap array of least frequent node in the Huffman tree } - -{ =========================================================================== - Initialize the tree data structures for a new zlib stream. } -procedure _tr_init(var s : deflate_state); -begin - tr_static_init; - - s.compressed_len := Long(0); - - s.l_desc.dyn_tree := tree_ptr(@s.dyn_ltree); - s.l_desc.stat_desc := @static_l_desc; - - s.d_desc.dyn_tree := tree_ptr(@s.dyn_dtree); - s.d_desc.stat_desc := @static_d_desc; - - s.bl_desc.dyn_tree := tree_ptr(@s.bl_tree); - s.bl_desc.stat_desc := @static_bl_desc; - - s.bi_buf := 0; - s.bi_valid := 0; - s.last_eob_len := 8; { enough lookahead for inflate } -{$ifdef DEBUG} - s.bits_sent := Long(0); -{$endif} - - { Initialize the first block of the first file: } - init_block(s); -end; - -{ =========================================================================== - Remove the smallest element from the heap and recreate the heap with - one less element. Updates heap and heap_len. - -macro pqremove(s, tree, top) -begin - top := s.heap[SMALLEST]; - s.heap[SMALLEST] := s.heap[s.heap_len]; - Dec(s.heap_len); - pqdownheap(s, tree, SMALLEST); -end -} - -{ =========================================================================== - Compares to subtrees, using the tree depth as tie breaker when - the subtrees have equal frequency. This minimizes the worst case length. - -macro smaller(tree, n, m, depth) - ( (tree[n].Freq < tree[m].Freq) or - ((tree[n].Freq = tree[m].Freq) and (depth[n] <= depth[m])) ) -} - -{ =========================================================================== - Restore the heap property by moving down the tree starting at node k, - exchanging a node with the smallest of its two sons if necessary, stopping - when the heap property is re-established (each father smaller than its - two sons). } -{local} - -procedure pqdownheap(var s : deflate_state; - var tree : tree_type; { the tree to restore } - k : int); { node to move down } -var - v : int; - j : int; -begin - v := s.heap[k]; - j := k shl 1; { left son of k } - while (j <= s.heap_len) do - begin - { Set j to the smallest of the two sons: } - if (j < s.heap_len) and - {smaller(tree, s.heap[j+1], s.heap[j], s.depth)} - ( (tree[s.heap[j+1]].fc.Freq < tree[s.heap[j]].fc.Freq) or - ((tree[s.heap[j+1]].fc.Freq = tree[s.heap[j]].fc.Freq) and - (s.depth[s.heap[j+1]] <= s.depth[s.heap[j]])) ) then - begin - Inc(j); - end; - { Exit if v is smaller than both sons } - if {(smaller(tree, v, s.heap[j], s.depth))} - ( (tree[v].fc.Freq < tree[s.heap[j]].fc.Freq) or - ((tree[v].fc.Freq = tree[s.heap[j]].fc.Freq) and - (s.depth[v] <= s.depth[s.heap[j]])) ) then - break; - { Exchange v with the smallest son } - s.heap[k] := s.heap[j]; - k := j; - - { And continue down the tree, setting j to the left son of k } - j := j shl 1; - end; - s.heap[k] := v; -end; - -{ =========================================================================== - Compute the optimal bit lengths for a tree and update the total bit length - for the current block. - IN assertion: the fields freq and dad are set, heap[heap_max] and - above are the tree nodes sorted by increasing frequency. - OUT assertions: the field len is set to the optimal bit length, the - array bl_count contains the frequencies for each bit length. - The length opt_len is updated; static_len is also updated if stree is - not null. } - -{local} -procedure gen_bitlen(var s : deflate_state; - var desc : tree_desc); { the tree descriptor } -var - tree : tree_ptr; - max_code : int; - stree : tree_ptr; {const} - extra : pzIntfArray; {const} - base : int; - max_length : int; - h : int; { heap index } - n, m : int; { iterate over the tree elements } - bits : int; { bit length } - xbits : int; { extra bits } - f : ush; { frequency } - overflow : int; { number of elements with bit length too large } -begin - tree := desc.dyn_tree; - max_code := desc.max_code; - stree := desc.stat_desc^.static_tree; - extra := desc.stat_desc^.extra_bits; - base := desc.stat_desc^.extra_base; - max_length := desc.stat_desc^.max_length; - overflow := 0; - - for bits := 0 to MAX_BITS do - s.bl_count[bits] := 0; - - { In a first pass, compute the optimal bit lengths (which may - overflow in the case of the bit length tree). } - - tree^[s.heap[s.heap_max]].dl.Len := 0; { root of the heap } - - for h := s.heap_max+1 to HEAP_SIZE-1 do - begin - n := s.heap[h]; - bits := tree^[tree^[n].dl.Dad].dl.Len + 1; - if (bits > max_length) then - begin - bits := max_length; - Inc(overflow); - end; - tree^[n].dl.Len := ush(bits); - { We overwrite tree[n].dl.Dad which is no longer needed } - - if (n > max_code) then - continue; { not a leaf node } - - Inc(s.bl_count[bits]); - xbits := 0; - if (n >= base) then - xbits := extra^[n-base]; - f := tree^[n].fc.Freq; - Inc(s.opt_len, ulg(f) * (bits + xbits)); - if (stree <> NIL) then - Inc(s.static_len, ulg(f) * (stree^[n].dl.Len + xbits)); - end; - if (overflow = 0) then - exit; - {$ifdef DEBUG} - Tracev(^M'bit length overflow'); - {$endif} - { This happens for example on obj2 and pic of the Calgary corpus } - - { Find the first bit length which could increase: } - repeat - bits := max_length-1; - while (s.bl_count[bits] = 0) do - Dec(bits); - Dec(s.bl_count[bits]); { move one leaf down the tree } - Inc(s.bl_count[bits+1], 2); { move one overflow item as its brother } - Dec(s.bl_count[max_length]); - { The brother of the overflow item also moves one step up, - but this does not affect bl_count[max_length] } - - Dec(overflow, 2); - until (overflow <= 0); - - { Now recompute all bit lengths, scanning in increasing frequency. - h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - lengths instead of fixing only the wrong ones. This idea is taken - from 'ar' written by Haruhiko Okumura.) } - h := HEAP_SIZE; { Delphi3: compiler warning w/o this } - for bits := max_length downto 1 do - begin - n := s.bl_count[bits]; - while (n <> 0) do - begin - Dec(h); - m := s.heap[h]; - if (m > max_code) then - continue; - if (tree^[m].dl.Len <> unsigned(bits)) then - begin - {$ifdef DEBUG} - Trace('code '+IntToStr(m)+' bits '+IntToStr(tree^[m].dl.Len) - +'.'+IntToStr(bits)); - {$ENDIF} - Inc(s.opt_len, (long(bits) - long(tree^[m].dl.Len)) - * long(tree^[m].fc.Freq) ); - tree^[m].dl.Len := ush(bits); - end; - Dec(n); - end; - end; -end; - -{ =========================================================================== - Construct one Huffman tree and assigns the code bit strings and lengths. - Update the total bit length for the current block. - IN assertion: the field freq is set for all tree elements. - OUT assertions: the fields len and code are set to the optimal bit length - and corresponding code. The length opt_len is updated; static_len is - also updated if stree is not null. The field max_code is set. } - -{local} -procedure build_tree(var s : deflate_state; - var desc : tree_desc); { the tree descriptor } - -var - tree : tree_ptr; - stree : tree_ptr; {const} - elems : int; - n, m : int; { iterate over heap elements } - max_code : int; { largest code with non zero frequency } - node : int; { new node being created } -begin - tree := desc.dyn_tree; - stree := desc.stat_desc^.static_tree; - elems := desc.stat_desc^.elems; - max_code := -1; - - { Construct the initial heap, with least frequent element in - heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - heap[0] is not used. } - s.heap_len := 0; - s.heap_max := HEAP_SIZE; - - for n := 0 to elems-1 do - begin - if (tree^[n].fc.Freq <> 0) then - begin - max_code := n; - Inc(s.heap_len); - s.heap[s.heap_len] := n; - s.depth[n] := 0; - end - else - begin - tree^[n].dl.Len := 0; - end; - end; - - { The pkzip format requires that at least one distance code exists, - and that at least one bit should be sent even if there is only one - possible code. So to avoid special checks later on we force at least - two codes of non zero frequency. } - - while (s.heap_len < 2) do - begin - Inc(s.heap_len); - if (max_code < 2) then - begin - Inc(max_code); - s.heap[s.heap_len] := max_code; - node := max_code; - end - else - begin - s.heap[s.heap_len] := 0; - node := 0; - end; - tree^[node].fc.Freq := 1; - s.depth[node] := 0; - Dec(s.opt_len); - if (stree <> NIL) then - Dec(s.static_len, stree^[node].dl.Len); - { node is 0 or 1 so it does not have extra bits } - end; - desc.max_code := max_code; - - { The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - establish sub-heaps of increasing lengths: } - - for n := s.heap_len div 2 downto 1 do - pqdownheap(s, tree^, n); - - { Construct the Huffman tree by repeatedly combining the least two - frequent nodes. } - - node := elems; { next internal node of the tree } - repeat - {pqremove(s, tree, n);} { n := node of least frequency } - n := s.heap[SMALLEST]; - s.heap[SMALLEST] := s.heap[s.heap_len]; - Dec(s.heap_len); - pqdownheap(s, tree^, SMALLEST); - - m := s.heap[SMALLEST]; { m := node of next least frequency } - - Dec(s.heap_max); - s.heap[s.heap_max] := n; { keep the nodes sorted by frequency } - Dec(s.heap_max); - s.heap[s.heap_max] := m; - - { Create a new node father of n and m } - tree^[node].fc.Freq := tree^[n].fc.Freq + tree^[m].fc.Freq; - { maximum } - if (s.depth[n] >= s.depth[m]) then - s.depth[node] := uch (s.depth[n] + 1) - else - s.depth[node] := uch (s.depth[m] + 1); - - tree^[m].dl.Dad := ush(node); - tree^[n].dl.Dad := ush(node); -{$ifdef DUMP_BL_TREE} - if (tree = tree_ptr(@s.bl_tree)) then - begin - WriteLn(#13'node ',node,'(',tree^[node].fc.Freq,') sons ',n, - '(',tree^[n].fc.Freq,') ', m, '(',tree^[m].fc.Freq,')'); - end; -{$endif} - { and insert the new node in the heap } - s.heap[SMALLEST] := node; - Inc(node); - pqdownheap(s, tree^, SMALLEST); - - until (s.heap_len < 2); - - Dec(s.heap_max); - s.heap[s.heap_max] := s.heap[SMALLEST]; - - { At this point, the fields freq and dad are set. We can now - generate the bit lengths. } - - gen_bitlen(s, desc); - - { The field len is now set, we can generate the bit codes } - gen_codes (tree, max_code, s.bl_count); -end; - -{ =========================================================================== - Scan a literal or distance tree to determine the frequencies of the codes - in the bit length tree. } - -{local} -procedure scan_tree(var s : deflate_state; - var tree : array of ct_data; { the tree to be scanned } - max_code : int); { and its largest code of non zero frequency } -var - n : int; { iterates over all tree elements } - prevlen : int; { last emitted length } - curlen : int; { length of current code } - nextlen : int; { length of next code } - count : int; { repeat count of the current code } - max_count : int; { max repeat count } - min_count : int; { min repeat count } -begin - prevlen := -1; - nextlen := tree[0].dl.Len; - count := 0; - max_count := 7; - min_count := 4; - - if (nextlen = 0) then - begin - max_count := 138; - min_count := 3; - end; - tree[max_code+1].dl.Len := ush($ffff); { guard } - - for n := 0 to max_code do - begin - curlen := nextlen; - nextlen := tree[n+1].dl.Len; - Inc(count); - if (count < max_count) and (curlen = nextlen) then - continue - else - if (count < min_count) then - Inc(s.bl_tree[curlen].fc.Freq, count) - else - if (curlen <> 0) then - begin - if (curlen <> prevlen) then - Inc(s.bl_tree[curlen].fc.Freq); - Inc(s.bl_tree[REP_3_6].fc.Freq); - end - else - if (count <= 10) then - Inc(s.bl_tree[REPZ_3_10].fc.Freq) - else - Inc(s.bl_tree[REPZ_11_138].fc.Freq); - - count := 0; - prevlen := curlen; - if (nextlen = 0) then - begin - max_count := 138; - min_count := 3; - end - else - if (curlen = nextlen) then - begin - max_count := 6; - min_count := 3; - end - else - begin - max_count := 7; - min_count := 4; - end; - end; -end; - -{ =========================================================================== - Send a literal or distance tree in compressed form, using the codes in - bl_tree. } - -{local} -procedure send_tree(var s : deflate_state; - var tree : array of ct_data; { the tree to be scanned } - max_code : int); { and its largest code of non zero frequency } - -var - n : int; { iterates over all tree elements } - prevlen : int; { last emitted length } - curlen : int; { length of current code } - nextlen : int; { length of next code } - count : int; { repeat count of the current code } - max_count : int; { max repeat count } - min_count : int; { min repeat count } -begin - prevlen := -1; - nextlen := tree[0].dl.Len; - count := 0; - max_count := 7; - min_count := 4; - - { tree[max_code+1].dl.Len := -1; } { guard already set } - if (nextlen = 0) then - begin - max_count := 138; - min_count := 3; - end; - - for n := 0 to max_code do - begin - curlen := nextlen; - nextlen := tree[n+1].dl.Len; - Inc(count); - if (count < max_count) and (curlen = nextlen) then - continue - else - if (count < min_count) then - begin - repeat - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(curlen)); - {$ENDIF} - send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len); - Dec(count); - until (count = 0); - end - else - if (curlen <> 0) then - begin - if (curlen <> prevlen) then - begin - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(curlen)); - {$ENDIF} - send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len); - Dec(count); - end; - {$IFDEF DEBUG} - Assert((count >= 3) and (count <= 6), ' 3_6?'); - {$ENDIF} - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(REP_3_6)); - {$ENDIF} - send_bits(s, s.bl_tree[REP_3_6].fc.Code, s.bl_tree[REP_3_6].dl.Len); - send_bits(s, count-3, 2); - end - else - if (count <= 10) then - begin - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(REPZ_3_10)); - {$ENDIF} - send_bits(s, s.bl_tree[REPZ_3_10].fc.Code, s.bl_tree[REPZ_3_10].dl.Len); - send_bits(s, count-3, 3); - end - else - begin - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(REPZ_11_138)); - {$ENDIF} - send_bits(s, s.bl_tree[REPZ_11_138].fc.Code, s.bl_tree[REPZ_11_138].dl.Len); - send_bits(s, count-11, 7); - end; - count := 0; - prevlen := curlen; - if (nextlen = 0) then - begin - max_count := 138; - min_count := 3; - end - else - if (curlen = nextlen) then - begin - max_count := 6; - min_count := 3; - end - else - begin - max_count := 7; - min_count := 4; - end; - end; -end; - -{ =========================================================================== - Construct the Huffman tree for the bit lengths and return the index in - bl_order of the last bit length code to send. } - -{local} -function build_bl_tree(var s : deflate_state) : int; -var - max_blindex : int; { index of last bit length code of non zero freq } -begin - { Determine the bit length frequencies for literal and distance trees } - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - - { Build the bit length tree: } - build_tree(s, s.bl_desc); - { opt_len now includes the length of the tree representations, except - the lengths of the bit lengths codes and the 5+5+4 bits for the counts. } - - { Determine the number of bit length codes to send. The pkzip format - requires that at least 4 bit length codes be sent. (appnote.txt says - 3 but the actual value used is 4.) } - - for max_blindex := BL_CODES-1 downto 3 do - begin - if (s.bl_tree[bl_order[max_blindex]].dl.Len <> 0) then - break; - end; - { Update opt_len to include the bit length tree and counts } - Inc(s.opt_len, 3*(max_blindex+1) + 5+5+4); - {$ifdef DEBUG} - Tracev(^M'dyn trees: dyn %ld, stat %ld {s.opt_len, s.static_len}'); - {$ENDIF} - - build_bl_tree := max_blindex; -end; - -{ =========================================================================== - Send the header for a block using dynamic Huffman trees: the counts, the - lengths of the bit length codes, the literal tree and the distance tree. - IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. } - -{local} -procedure send_all_trees(var s : deflate_state; - lcodes : int; - dcodes : int; - blcodes : int); { number of codes for each tree } -var - rank : int; { index in bl_order } -begin - {$IFDEF DEBUG} - Assert ((lcodes >= 257) and (dcodes >= 1) and (blcodes >= 4), - 'not enough codes'); - Assert ((lcodes <= L_CODES) and (dcodes <= D_CODES) - and (blcodes <= BL_CODES), 'too many codes'); - Tracev(^M'bl counts: '); - {$ENDIF} - send_bits(s, lcodes-257, 5); { not +255 as stated in appnote.txt } - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); { not -3 as stated in appnote.txt } - for rank := 0 to blcodes-1 do - begin - {$ifdef DEBUG} - Tracev(^M'bl code '+IntToStr(bl_order[rank])); - {$ENDIF} - send_bits(s, s.bl_tree[bl_order[rank]].dl.Len, 3); - end; - {$ifdef DEBUG} - Tracev(^M'bl tree: sent '+IntToStr(s.bits_sent)); - {$ENDIF} - - send_tree(s, s.dyn_ltree, lcodes-1); { literal tree } - {$ifdef DEBUG} - Tracev(^M'lit tree: sent '+IntToStr(s.bits_sent)); - {$ENDIF} - - send_tree(s, s.dyn_dtree, dcodes-1); { distance tree } - {$ifdef DEBUG} - Tracev(^M'dist tree: sent '+IntToStr(s.bits_sent)); - {$ENDIF} -end; - -{ =========================================================================== - Flush the bit buffer and align the output on a byte boundary } - -{local} -procedure bi_windup(var s : deflate_state); -begin - if (s.bi_valid > 8) then - begin - {put_short(s, s.bi_buf);} - s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); - Inc(s.pending); - s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; - Inc(s.pending); - end - else - if (s.bi_valid > 0) then - begin - {put_byte(s, (Byte)s^.bi_buf);} - s.pending_buf^[s.pending] := Byte(s.bi_buf); - Inc(s.pending); - end; - s.bi_buf := 0; - s.bi_valid := 0; -{$ifdef DEBUG} - s.bits_sent := (s.bits_sent+7) and (not 7); -{$endif} -end; - -{ =========================================================================== - Copy a stored block, storing first the length and its - one's complement if requested. } - -{local} -procedure copy_block(var s : deflate_state; - buf : pcharf; { the input data } - len : unsigned; { its length } - header : boolean); { true if block header must be written } -begin - bi_windup(s); { align on byte boundary } - s.last_eob_len := 8; { enough lookahead for inflate } - - if (header) then - begin - {put_short(s, (ush)len);} - s.pending_buf^[s.pending] := uch(ush(len) and $ff); - Inc(s.pending); - s.pending_buf^[s.pending] := uch(ush(len) shr 8);; - Inc(s.pending); - {put_short(s, (ush)~len);} - s.pending_buf^[s.pending] := uch(ush(not len) and $ff); - Inc(s.pending); - s.pending_buf^[s.pending] := uch(ush(not len) shr 8);; - Inc(s.pending); - -{$ifdef DEBUG} - Inc(s.bits_sent, 2*16); -{$endif} - end; -{$ifdef DEBUG} - Inc(s.bits_sent, ulg(len shl 3)); -{$endif} - while (len <> 0) do - begin - Dec(len); - {put_byte(s, *buf++);} - s.pending_buf^[s.pending] := buf^; - Inc(buf); - Inc(s.pending); - end; -end; - - -{ =========================================================================== - Send a stored block } - -procedure _tr_stored_block(var s : deflate_state; - buf : pcharf; { input block } - stored_len : ulg; { length of input block } - eof : boolean); { true if this is the last block for a file } - -begin - send_bits(s, (STORED_BLOCK shl 1)+ord(eof), 3); { send block type } - s.compressed_len := (s.compressed_len + 3 + 7) and ulg(not Long(7)); - Inc(s.compressed_len, (stored_len + 4) shl 3); - - copy_block(s, buf, unsigned(stored_len), TRUE); { with header } -end; - -{ =========================================================================== - Flush the bit buffer, keeping at most 7 bits in it. } - -{local} -procedure bi_flush(var s : deflate_state); -begin - if (s.bi_valid = 16) then - begin - {put_short(s, s.bi_buf);} - s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); - Inc(s.pending); - s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; - Inc(s.pending); - - s.bi_buf := 0; - s.bi_valid := 0; - end - else - if (s.bi_valid >= 8) then - begin - {put_byte(s, (Byte)s^.bi_buf);} - s.pending_buf^[s.pending] := Byte(s.bi_buf); - Inc(s.pending); - - s.bi_buf := s.bi_buf shr 8; - Dec(s.bi_valid, 8); - end; -end; - - -{ =========================================================================== - Send one empty static block to give enough lookahead for inflate. - This takes 10 bits, of which 7 may remain in the bit buffer. - The current inflate code requires 9 bits of lookahead. If the - last two codes for the previous block (real code plus EOB) were coded - on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - the last real code. In this case we send two empty static blocks instead - of one. (There are no problems if the previous block is stored or fixed.) - To simplify the code, we assume the worst case of last real code encoded - on one bit only. } - -procedure _tr_align(var s : deflate_state); -begin - send_bits(s, STATIC_TREES shl 1, 3); - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(END_BLOCK)); - {$ENDIF} - send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len); - Inc(s.compressed_len, Long(10)); { 3 for block type, 7 for EOB } - bi_flush(s); - { Of the 10 bits for the empty block, we have already sent - (10 - bi_valid) bits. The lookahead for the last real code (before - the EOB of the previous block) was thus at least one plus the length - of the EOB plus what we have just sent of the empty static block. } - if (1 + s.last_eob_len + 10 - s.bi_valid < 9) then - begin - send_bits(s, STATIC_TREES shl 1, 3); - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(END_BLOCK)); - {$ENDIF} - send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len); - Inc(s.compressed_len, Long(10)); - bi_flush(s); - end; - s.last_eob_len := 7; -end; - -{ =========================================================================== - Set the data type to ASCII or BINARY, using a crude approximation: - binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - IN assertion: the fields freq of dyn_ltree are set and the total of all - frequencies does not exceed 64K (to fit in an int on 16 bit machines). } - -{local} -procedure set_data_type(var s : deflate_state); -var - n : int; - ascii_freq : unsigned; - bin_freq : unsigned; -begin - n := 0; - ascii_freq := 0; - bin_freq := 0; - - while (n < 7) do - begin - Inc(bin_freq, s.dyn_ltree[n].fc.Freq); - Inc(n); - end; - while (n < 128) do - begin - Inc(ascii_freq, s.dyn_ltree[n].fc.Freq); - Inc(n); - end; - while (n < LITERALS) do - begin - Inc(bin_freq, s.dyn_ltree[n].fc.Freq); - Inc(n); - end; - if (bin_freq > (ascii_freq shr 2)) then - s.data_type := Byte(Z_BINARY) - else - s.data_type := Byte(Z_ASCII); -end; - -{ =========================================================================== - Send the block data compressed using the given Huffman trees } - -{local} -procedure compress_block(var s : deflate_state; - var ltree : array of ct_data; { literal tree } - var dtree : array of ct_data); { distance tree } -var - dist : unsigned; { distance of matched string } - lc : int; { match length or unmatched char (if dist == 0) } - lx : unsigned; { running index in l_buf } - code : unsigned; { the code to send } - extra : int; { number of extra bits to send } -begin - lx := 0; - if (s.last_lit <> 0) then - repeat - dist := s.d_buf^[lx]; - lc := s.l_buf^[lx]; - Inc(lx); - if (dist = 0) then - begin - { send a literal byte } - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(lc)); - Tracecv((lc > 31) and (lc < 128), ' '+AnsiChar(lc)+' '); - {$ENDIF} - send_bits(s, ltree[lc].fc.Code, ltree[lc].dl.Len); - end - else - begin - { Here, lc is the match length - MIN_MATCH } - code := _length_code[lc]; - { send the length code } - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(code+LITERALS+1)); - {$ENDIF} - send_bits(s, ltree[code+LITERALS+1].fc.Code, ltree[code+LITERALS+1].dl.Len); - extra := extra_lbits[code]; - if (extra <> 0) then - begin - Dec(lc, base_length[code]); - send_bits(s, lc, extra); { send the extra length bits } - end; - Dec(dist); { dist is now the match distance - 1 } - {code := d_code(dist);} - if (dist < 256) then - code := _dist_code[dist] - else - code := _dist_code[256+(dist shr 7)]; - - {$IFDEF DEBUG} - Assert (code < D_CODES, 'bad d_code'); - {$ENDIF} - - { send the distance code } - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(code)); - {$ENDIF} - send_bits(s, dtree[code].fc.Code, dtree[code].dl.Len); - extra := extra_dbits[code]; - if (extra <> 0) then - begin - Dec(dist, base_dist[code]); - send_bits(s, dist, extra); { send the extra distance bits } - end; - end; { literal or match pair ? } - - { Check that the overlay between pending_buf and d_buf+l_buf is ok: } - {$IFDEF DEBUG} - Assert(s.pending < s.lit_bufsize + 2*lx, 'pendingBuf overflow'); - {$ENDIF} - until (lx >= s.last_lit); - - {$ifdef DEBUG} - Tracevvv(#13'cd '+IntToStr(END_BLOCK)); - {$ENDIF} - send_bits(s, ltree[END_BLOCK].fc.Code, ltree[END_BLOCK].dl.Len); - s.last_eob_len := ltree[END_BLOCK].dl.Len; -end; - - -{ =========================================================================== - Determine the best encoding for the current block: dynamic trees, static - trees or store, and output the encoded block to the zip file. This function - returns the total compressed length for the file so far. } - -function _tr_flush_block (var s : deflate_state; - buf : pcharf; { input block, or NULL if too old } - stored_len : ulg; { length of input block } - eof : boolean) : ulg; { true if this is the last block for a file } -var - opt_lenb, static_lenb : ulg; { opt_len and static_len in bytes } - max_blindex : int; { index of last bit length code of non zero freq } -begin - max_blindex := 0; - - { Build the Huffman trees unless a stored block is forced } - if (s.level > 0) then - begin - { Check if the file is ascii or binary } - if (s.data_type = Z_UNKNOWN) then - set_data_type(s); - - { Construct the literal and distance trees } - build_tree(s, s.l_desc); - {$ifdef DEBUG} - Tracev(^M'lit data: dyn %ld, stat %ld {s.opt_len, s.static_len}'); - {$ENDIF} - - build_tree(s, s.d_desc); - {$ifdef DEBUG} - Tracev(^M'dist data: dyn %ld, stat %ld {s.opt_len, s.static_len}'); - {$ENDIF} - { At this point, opt_len and static_len are the total bit lengths of - the compressed block data, excluding the tree representations. } - - { Build the bit length tree for the above two trees, and get the index - in bl_order of the last bit length code to send. } - max_blindex := build_bl_tree(s); - - { Determine the best encoding. Compute first the block length in bytes} - opt_lenb := (s.opt_len+3+7) shr 3; - static_lenb := (s.static_len+3+7) shr 3; - - {$ifdef DEBUG} - Tracev(^M'opt %lu(%lu) stat %lu(%lu) stored %lu lit %u '+ - '{opt_lenb, s.opt_len, static_lenb, s.static_len, stored_len,'+ - 's.last_lit}'); - {$ENDIF} - - if (static_lenb <= opt_lenb) then - opt_lenb := static_lenb; - - end - else - begin - {$IFDEF DEBUG} - Assert(buf <> pcharf(NIL), 'lost buf'); - {$ENDIF} - static_lenb := stored_len + 5; - opt_lenb := static_lenb; { force a stored block } - end; - - { If compression failed and this is the first and last block, - and if the .zip file can be seeked (to rewrite the local header), - the whole file is transformed into a stored file: } - -{$ifdef STORED_FILE_OK} -{$ifdef FORCE_STORED_FILE} - if eof and (s.compressed_len = Long(0)) then - begin { force stored file } -{$else} - if (stored_len <= opt_lenb) and eof and (s.compressed_len=Long(0)) - and seekable()) do - begin -{$endif} - { Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: } - if (buf = pcharf(0)) then - error ('block vanished'); - - copy_block(buf, unsigned(stored_len), 0); { without header } - s.compressed_len := stored_len shl 3; - s.method := STORED; - end - else -{$endif} { STORED_FILE_OK } - -{$ifdef FORCE_STORED} - if (buf <> pcharf(0)) then - begin { force stored block } -{$else} - if (stored_len+4 <= opt_lenb) and (buf <> pcharf(0)) then - begin - { 4: two words for the lengths } -{$endif} - { The test buf <> NULL is only necessary if LIT_BUFSIZE > WSIZE. - Otherwise we can't have processed more than WSIZE input bytes since - the last block flush, because compression would have been - successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - transform a block into a stored block. } - - _tr_stored_block(s, buf, stored_len, eof); - -{$ifdef FORCE_STATIC} - end - else - if (static_lenb >= 0) then - begin { force static trees } -{$else} - end - else - if (static_lenb = opt_lenb) then - begin -{$endif} - send_bits(s, (STATIC_TREES shl 1)+ord(eof), 3); - compress_block(s, static_ltree, static_dtree); - Inc(s.compressed_len, 3 + s.static_len); - end - else - begin - send_bits(s, (DYN_TREES shl 1)+ord(eof), 3); - send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, - max_blindex+1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); - Inc(s.compressed_len, 3 + s.opt_len); - end; - {$ifdef DEBUG} - Assert (s.compressed_len = s.bits_sent, 'bad compressed size'); - {$ENDIF} - init_block(s); - - if (eof) then - begin - bi_windup(s); - Inc(s.compressed_len, 7); { align on byte boundary } - end; - {$ifdef DEBUG} - Tracev(#13'comprlen %lu(%lu) {s.compressed_len shr 3,'+ - 's.compressed_len-7*ord(eof)}'); - {$ENDIF} - - _tr_flush_block := s.compressed_len shr 3; -end; - - -{ =========================================================================== - Save the match info and tally the frequency counts. Return true if - the current block must be flushed. } - -function _tr_tally (var s : deflate_state; - dist : unsigned; { distance of matched string } - lc : unsigned) : boolean; { match length-MIN_MATCH or unmatched char (if dist=0) } -var - {$IFDEF DEBUG} - MAX_DIST : ush; - {$ENDIF} - code : ush; -{$ifdef TRUNCATE_BLOCK} -var - out_length : ulg; - in_length : ulg; - dcode : int; -{$endif} -begin - s.d_buf^[s.last_lit] := ush(dist); - s.l_buf^[s.last_lit] := uch(lc); - Inc(s.last_lit); - if (dist = 0) then - begin - { lc is the unmatched char } - Inc(s.dyn_ltree[lc].fc.Freq); - end - else - begin - Inc(s.matches); - { Here, lc is the match length - MIN_MATCH } - Dec(dist); { dist := match distance - 1 } - - {macro d_code(dist)} - if (dist) < 256 then - code := _dist_code[dist] - else - code := _dist_code[256+(dist shr 7)]; - {$IFDEF DEBUG} -{macro MAX_DIST(s) <=> ((s)^.w_size-MIN_LOOKAHEAD) - In order to simplify the code, particularly on 16 bit machines, match - distances are limited to MAX_DIST instead of WSIZE. } - MAX_DIST := ush(s.w_size-MIN_LOOKAHEAD); - Assert((dist < ush(MAX_DIST)) and - (ush(lc) <= ush(MAX_MATCH-MIN_MATCH)) and - (ush(code) < ush(D_CODES)), '_tr_tally: bad match'); - {$ENDIF} - Inc(s.dyn_ltree[_length_code[lc]+LITERALS+1].fc.Freq); - {s.dyn_dtree[d_code(dist)].Freq++;} - Inc(s.dyn_dtree[code].fc.Freq); - end; - -{$ifdef TRUNCATE_BLOCK} - { Try to guess if it is profitable to stop the current block here } - if (s.last_lit and $1fff = 0) and (s.level > 2) then - begin - { Compute an upper bound for the compressed length } - out_length := ulg(s.last_lit)*Long(8); - in_length := ulg(long(s.strstart) - s.block_start); - for dcode := 0 to D_CODES-1 do - begin - Inc(out_length, ulg(s.dyn_dtree[dcode].fc.Freq * - (Long(5)+extra_dbits[dcode])) ); - end; - out_length := out_length shr 3; - {$ifdef DEBUG} - Tracev(^M'last_lit %u, in %ld, out ~%ld(%ld%%) '); - { s.last_lit, in_length, out_length, - Long(100) - out_length*Long(100) div in_length)); } - {$ENDIF} - if (s.matches < s.last_lit div 2) and (out_length < in_length div 2) then - begin - _tr_tally := TRUE; - exit; - end; - end; -{$endif} - _tr_tally := (s.last_lit = s.lit_bufsize-1); - { We avoid equality with lit_bufsize because of wraparound at 64K - on 16 bit machines and because stored blocks are restricted to - 64K-1 bytes. } -end; - -end. \ No newline at end of file diff --git a/3rd/Imaging/Source/ZLib/imzconf.inc b/3rd/Imaging/Source/ZLib/imzconf.inc deleted file mode 100644 index d688a4bf2..000000000 --- a/3rd/Imaging/Source/ZLib/imzconf.inc +++ /dev/null @@ -1,25 +0,0 @@ -{ -------------------------------------------------------------------- } - -{$DEFINE MAX_MATCH_IS_258} - -{ Compile with -DMAXSEG_64K if the alloc function cannot allocate more - than 64k bytes at a time (needed on systems with 16-bit int). } - -{$UNDEF MAXSEG_64K} -{$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } -{$UNDEF DYNAMIC_CRC_TABLE} -{$UNDEF FASTEST} -{$DEFINE Use32} -{$DEFINE patch112} { apply patch from the zlib home page } - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} - -{$UNDEF DEBUG} // for Delphi 2007 in DEBUG mode - -{$RANGECHECKS OFF} -{$OVERFLOWCHECKS OFF} -{ -------------------------------------------------------------------- } - - diff --git a/3rd/Imaging/Source/ZLib/imzdeflate.pas b/3rd/Imaging/Source/ZLib/imzdeflate.pas deleted file mode 100644 index dc5e96fd0..000000000 --- a/3rd/Imaging/Source/ZLib/imzdeflate.pas +++ /dev/null @@ -1,2129 +0,0 @@ -Unit imzdeflate; - -{ Orginal: deflate.h -- internal compression state - deflate.c -- compress data using the deflation algorithm - Copyright (C) 1995-1996 Jean-loup Gailly. - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - - -{ ALGORITHM - - The "deflation" process depends on being able to identify portions - of the input text which are identical to earlier input (within a - sliding window trailing behind the input currently being processed). - - The most straightforward technique turns out to be the fastest for - most input files: try all possible matches and select the longest. - The key feature of this algorithm is that insertions into the string - dictionary are very simple and thus fast, and deletions are avoided - completely. Insertions are performed at each input character, whereas - string matches are performed only when the previous match ends. So it - is preferable to spend more time in matches to allow very fast string - insertions and avoid deletions. The matching algorithm for small - strings is inspired from that of Rabin & Karp. A brute force approach - is used to find longer strings when a small match has been found. - A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - (by Leonid Broukhis). - A previous version of this file used a more sophisticated algorithm - (by Fiala and Greene) which is guaranteed to run in linear amortized - time, but has a larger average cost, uses more memory and is patented. - However the F&G algorithm may be faster for some highly redundant - files if the parameter max_chain_length (described below) is too large. - - ACKNOWLEDGEMENTS - - The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - I found it in 'freeze' written by Leonid Broukhis. - Thanks to many people for bug reports and testing. - - REFERENCES - - Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - - A description of the Rabin and Karp algorithm is given in the book - "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - - Fiala,E.R., and Greene,D.H. - Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595} - -interface - -{$I imzconf.inc} - -uses - imzutil, impaszlib; - - -function deflateInit_(strm : z_streamp; - level : int; - const version : AnsiString; - stream_size : int) : int; - - -function deflateInit (var strm : z_stream; level : int) : int; - -{ Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). } - - -{EXPORT} -function deflate (var strm : z_stream; flush : int) : int; - -{ Performs one or both of the following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression - block is terminated and flushed to the output buffer so that the - decompressor can get all input data available so far. For method 9, a future - variant on method 8, the current block will be flushed but not terminated. - Z_SYNC_FLUSH has the same effect as partial flush except that the compressed - output is byte aligned (the compressor can clear its internal bit buffer) - and the current block is always terminated; this can be useful if the - compressor has to be restarted from scratch after an interruption (in which - case the internal state of the compressor may be lost). - If flush is set to Z_FULL_FLUSH, the compression block is terminated, a - special marker is output and the compression dictionary is discarded; this - is useful to allow the decompressor to synchronize if one compressed block - has been damaged (see inflateSync below). Flushing degrades compression and - so should be used only when necessary. Using Z_FULL_FLUSH too often can - seriously degrade the compression. If deflate returns with avail_out == 0, - this function must be called again with the same value of the flush - parameter and more output space (updated avail_out), until the flush is - complete (deflate returns with non-zero avail_out). - - If the parameter flush is set to Z_FINISH, all pending input is processed, - all pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. } - - -function deflateEnd (var strm : z_stream) : int; - -{ All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). } - - - - - { Advanced functions } - -{ The following functions are needed only in some special applications. } - - -{EXPORT} -function deflateInit2 (var strm : z_stream; - level : int; - method : int; - windowBits : int; - memLevel : int; - strategy : int) : int; - -{ This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. (Method 9 will allow a 64K history buffer and - partial block flushes.) - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library (the value 16 will be allowed for method 9). Larger - values of this parameter result in better compression at the expense of - memory usage. The default value is 15 if deflateInit is used instead. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. - - If next_in is not null, the library will use this buffer to hold also - some history information; the buffer must either hold the entire input - data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in - is null, the library will allocate its own history buffer (and leave next_in - null). next_out need not be provided here but must be provided by the - application for the next call of deflate(). - - If the history buffer is provided by the application, next_in must - must never be changed by the application since the compressor maintains - information inside this buffer from call to call; the application - must provide more input only by increasing avail_in. next_in is always - reset by the library in this case. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was - not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as - an invalid method). msg is set to null if there is no error message. - deflateInit2 does not perform any compression: this will be done by - deflate(). } - - -{EXPORT} -function deflateSetDictionary (var strm : z_stream; - dictionary : pBytef; {const bytes} - dictLength : uint) : int; - -{ Initializes the compression dictionary (history buffer) from the given - byte sequence without producing any compressed output. This function must - be called immediately after deflateInit or deflateInit2, before any call - of deflate. The compressor and decompressor must use exactly the same - dictionary (see inflateSetDictionary). - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and - can be predicted with good accuracy; the data can then be compressed better - than with the default empty dictionary. In this version of the library, - only the last 32K bytes of the dictionary are used. - Upon return of this function, strm->adler is set to the Adler32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state - is inconsistent (for example if deflate has already been called for this - stream). deflateSetDictionary does not perform any compression: this will - be done by deflate(). } - -{EXPORT} -function deflateCopy (dest : z_streamp; - source : z_streamp) : int; - -{ Sets the destination stream as a complete copy of the source stream. If - the source stream is using an application-supplied history buffer, a new - buffer is allocated for the destination stream. The compressed output - buffer is always application-supplied. It's the responsibility of the - application to provide the correct values of next_out and avail_out for the - next call of deflate. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and - can consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being NULL). msg is left unchanged in both source and - destination. } - -{EXPORT} -function deflateReset (var strm : z_stream) : int; - -{ This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NIL). } - - -{EXPORT} -function deflateParams (var strm : z_stream; level : int; strategy : int) : int; - -{ Dynamically update the compression level and compression strategy. - This can be used to switch between compression and straight copy of - the input data, or to switch to a different kind of input data requiring - a different strategy. If the compression level is changed, the input - available so far is compressed with the old level (and may be flushed); - the new level will take effect only at the next call of deflate(). - - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to - be compressed and flushed. In particular, strm->avail_out must be non-zero. - - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR - if strm->avail_out was zero. } - - -const - deflate_copyright : string = ' deflate 1.1.2 Copyright 1995-1998 Jean-loup Gailly '; - -{ If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. } - -implementation - -uses - imtrees, imadler; - -{ =========================================================================== - Function prototypes. } - -type - block_state = ( - need_more, { block not completed, need more input or more output } - block_done, { block flush performed } - finish_started, { finish started, need only more output at next deflate } - finish_done); { finish done, accept no more input or output } - -{ Compression function. Returns the block state after the call. } -type - compress_func = function(var s : deflate_state; flush : int) : block_state; - -{local} -procedure fill_window(var s : deflate_state); forward; -{local} -function deflate_stored(var s : deflate_state; flush : int) : block_state; forward; -{local} -function deflate_fast(var s : deflate_state; flush : int) : block_state; forward; -{local} -function deflate_slow(var s : deflate_state; flush : int) : block_state; forward; -{local} -procedure lm_init(var s : deflate_state); forward; - -{local} -procedure putShortMSB(var s : deflate_state; b : uInt); forward; -{local} -procedure flush_pending (var strm : z_stream); forward; -{local} -function read_buf(strm : z_streamp; - buf : pBytef; - size : unsigned) : int; forward; -{$ifdef ASMV} -procedure match_init; { asm code initialization } -function longest_match(var deflate_state; cur_match : IPos) : uInt; forward; -{$else} -{local} -function longest_match(var s : deflate_state; cur_match : IPos) : uInt; - forward; -{$endif} - -{$ifdef DEBUG} -{local} -procedure check_match(var s : deflate_state; - start, match : IPos; - length : int); forward; -{$endif} - -{ ========================================================================== - local data } - -const - ZNIL = 0; -{ Tail of hash chains } - -const - TOO_FAR = 4096; -{ Matches of length 3 are discarded if their distance exceeds TOO_FAR } - -const - MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1); -{ Minimum amount of lookahead, except at the end of the input file. - See deflate.c for comments about the MIN_MATCH+1. } - -{macro MAX_DIST(var s : deflate_state) : uInt; -begin - MAX_DIST := (s.w_size - MIN_LOOKAHEAD); -end; - In order to simplify the code, particularly on 16 bit machines, match - distances are limited to MAX_DIST instead of WSIZE. } - - -{ Values for max_lazy_match, good_match and max_chain_length, depending on - the desired pack level (0..9). The values given below have been tuned to - exclude worst case performance for pathological files. Better values may be - found for specific files. } - -type - config = record - good_length : ush; { reduce lazy search above this match length } - max_lazy : ush; { do not perform lazy search above this match length } - nice_length : ush; { quit search above this match length } - max_chain : ush; - func : compress_func; - end; - -{local} -const - configuration_table : array[0..10-1] of config = ( -{ good lazy nice chain } -{0} (good_length:0; max_lazy:0; nice_length:0; max_chain:0; func:deflate_stored), { store only } -{1} (good_length:4; max_lazy:4; nice_length:8; max_chain:4; func:deflate_fast), { maximum speed, no lazy matches } -{2} (good_length:4; max_lazy:5; nice_length:16; max_chain:8; func:deflate_fast), -{3} (good_length:4; max_lazy:6; nice_length:32; max_chain:32; func:deflate_fast), - -{4} (good_length:4; max_lazy:4; nice_length:16; max_chain:16; func:deflate_slow), { lazy matches } -{5} (good_length:8; max_lazy:16; nice_length:32; max_chain:32; func:deflate_slow), -{6} (good_length:8; max_lazy:16; nice_length:128; max_chain:128; func:deflate_slow), -{7} (good_length:8; max_lazy:32; nice_length:128; max_chain:256; func:deflate_slow), -{8} (good_length:32; max_lazy:128; nice_length:258; max_chain:1024; func:deflate_slow), -{9} (good_length:32; max_lazy:258; nice_length:258; max_chain:4096; func:deflate_slow)); { maximum compression } - -{ Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - For deflate_fast() (levels <= 3) good is ignored and lazy has a different - meaning. } - -const - EQUAL = 0; -{ result of memcmp for equal strings } - -{ ========================================================================== - Update a hash value with the given input byte - IN assertion: all calls to to UPDATE_HASH are made with consecutive - input characters, so that a running hash key can be computed from the - previous key instead of complete recalculation each time. - -macro UPDATE_HASH(s,h,c) - h := (( (h) shl s^.hash_shift) xor (c)) and s^.hash_mask; -} - -{ =========================================================================== - Insert string str in the dictionary and set match_head to the previous head - of the hash chain (the most recent string with same hash key). Return - the previous length of the hash chain. - If this file is compiled with -DFASTEST, the compression level is forced - to 1, and no hash chains are maintained. - IN assertion: all calls to to INSERT_STRING are made with consecutive - input characters and the first MIN_MATCH bytes of str are valid - (except for the last MIN_MATCH-1 bytes of the input file). } - -procedure INSERT_STRING(var s : deflate_state; - str : uInt; - var match_head : IPos); -begin -{$ifdef FASTEST} - {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])} - s.ins_h := ((s.ins_h shl s.hash_shift) xor - (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask; - match_head := s.head[s.ins_h] - s.head[s.ins_h] := Pos(str); -{$else} - {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])} - s.ins_h := ((s.ins_h shl s.hash_shift) xor - (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask; - - match_head := s.head^[s.ins_h]; - s.prev^[(str) and s.w_mask] := match_head; - s.head^[s.ins_h] := Pos(str); -{$endif} -end; - -{ ========================================================================= - Initialize the hash table (avoiding 64K overflow for 16 bit systems). - prev[] will be initialized on the fly. - -macro CLEAR_HASH(s) - s^.head[s^.hash_size-1] := ZNIL; - zmemzero(pBytef(s^.head), unsigned(s^.hash_size-1)*sizeof(s^.head^[0])); -} - -{ ======================================================================== } - -function deflateInit2_(var strm : z_stream; - level : int; - method : int; - windowBits : int; - memLevel : int; - strategy : int; - const version : AnsiString; - stream_size : int) : int; -var - s : deflate_state_ptr; - noheader : int; - - overlay : pushfArray; - { We overlay pending_buf and d_buf+l_buf. This works since the average - output size for (length,distance) codes is <= 24 bits. } -begin - noheader := 0; - if (version = '') or (version[1] <> ZLIB_VERSION[1]) or - (stream_size <> sizeof(z_stream)) then - begin - deflateInit2_ := Z_VERSION_ERROR; - exit; - end; - { - if (strm = Z_NULL) then - begin - deflateInit2_ := Z_STREAM_ERROR; - exit; - end; - } - { SetLength(strm.msg, 255); } - strm.msg := ''; - if not Assigned(strm.zalloc) then - begin - {$IFDEF FPC} strm.zalloc := @zcalloc; {$ELSE} - strm.zalloc := zcalloc; - {$ENDIF} - strm.opaque := voidpf(0); - end; - if not Assigned(strm.zfree) then - {$IFDEF FPC} strm.zfree := @zcfree; {$ELSE} - strm.zfree := zcfree; - {$ENDIF} - - if (level = Z_DEFAULT_COMPRESSION) then - level := 6; -{$ifdef FASTEST} - level := 1; -{$endif} - - if (windowBits < 0) then { undocumented feature: suppress zlib header } - begin - noheader := 1; - windowBits := -windowBits; - end; - if (memLevel < 1) or (memLevel > MAX_MEM_LEVEL) or (method <> Z_DEFLATED) - or (windowBits < 8) or (windowBits > 15) or (level < 0) - or (level > 9) or (strategy < 0) or (strategy > Z_HUFFMAN_ONLY) then - begin - deflateInit2_ := Z_STREAM_ERROR; - exit; - end; - - s := deflate_state_ptr (ZALLOC(strm, 1, sizeof(deflate_state))); - if (s = Z_NULL) then - begin - deflateInit2_ := Z_MEM_ERROR; - exit; - end; - strm.state := pInternal_state(s); - s^.strm := @strm; - - s^.noheader := noheader; - s^.w_bits := windowBits; - s^.w_size := 1 shl s^.w_bits; - s^.w_mask := s^.w_size - 1; - - s^.hash_bits := memLevel + 7; - s^.hash_size := 1 shl s^.hash_bits; - s^.hash_mask := s^.hash_size - 1; - s^.hash_shift := ((s^.hash_bits+MIN_MATCH-1) div MIN_MATCH); - - s^.window := pzByteArray (ZALLOC(strm, s^.w_size, 2*sizeof(Byte))); - s^.prev := pzPosfArray (ZALLOC(strm, s^.w_size, sizeof(Pos))); - s^.head := pzPosfArray (ZALLOC(strm, s^.hash_size, sizeof(Pos))); - - s^.lit_bufsize := 1 shl (memLevel + 6); { 16K elements by default } - - overlay := pushfArray (ZALLOC(strm, s^.lit_bufsize, sizeof(ush)+2)); - s^.pending_buf := pzByteArray (overlay); - s^.pending_buf_size := ulg(s^.lit_bufsize) * (sizeof(ush)+Long(2)); - - if (s^.window = Z_NULL) or (s^.prev = Z_NULL) or (s^.head = Z_NULL) - or (s^.pending_buf = Z_NULL) then - begin - {ERR_MSG(Z_MEM_ERROR);} - strm.msg := z_errmsg[z_errbase-Z_MEM_ERROR]; - deflateEnd (strm); - deflateInit2_ := Z_MEM_ERROR; - exit; - end; - s^.d_buf := pushfArray( @overlay^[s^.lit_bufsize div sizeof(ush)] ); - s^.l_buf := puchfArray( @s^.pending_buf^[(1+sizeof(ush))*s^.lit_bufsize] ); - - s^.level := level; - s^.strategy := strategy; - s^.method := Byte(method); - - deflateInit2_ := deflateReset(strm); -end; - -{ ========================================================================= } - -function deflateInit2(var strm : z_stream; - level : int; - method : int; - windowBits : int; - memLevel : int; - strategy : int) : int; -{ a macro } -begin - deflateInit2 := deflateInit2_(strm, level, method, windowBits, - memLevel, strategy, ZLIB_VERSION, sizeof(z_stream)); -end; - -{ ========================================================================= } - -function deflateInit_(strm : z_streamp; - level : int; - const version : AnsiString; - stream_size : int) : int; -begin - if (strm = Z_NULL) then - deflateInit_ := Z_STREAM_ERROR - else - deflateInit_ := deflateInit2_(strm^, level, Z_DEFLATED, MAX_WBITS, - DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); - { To do: ignore strm^.next_in if we use it as window } -end; - -{ ========================================================================= } - -function deflateInit(var strm : z_stream; level : int) : int; -{ deflateInit is a macro to allow checking the zlib version - and the compiler's view of z_stream: } -begin - deflateInit := deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, - DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(z_stream)); -end; - -{ ======================================================================== } -function deflateSetDictionary (var strm : z_stream; - dictionary : pBytef; - dictLength : uInt) : int; -var - s : deflate_state_ptr; - length : uInt; - n : uInt; - hash_head : IPos; -var - MAX_DIST : uInt; {macro} -begin - length := dictLength; - hash_head := 0; - - if {(@strm = Z_NULL) or} - (strm.state = Z_NULL) or (dictionary = Z_NULL) - or (deflate_state_ptr(strm.state)^.status <> INIT_STATE) then - begin - deflateSetDictionary := Z_STREAM_ERROR; - exit; - end; - - s := deflate_state_ptr(strm.state); - strm.adler := adler32(strm.adler, dictionary, dictLength); - - if (length < MIN_MATCH) then - begin - deflateSetDictionary := Z_OK; - exit; - end; - MAX_DIST := (s^.w_size - MIN_LOOKAHEAD); - if (length > MAX_DIST) then - begin - length := MAX_DIST; -{$ifndef USE_DICT_HEAD} - Inc(dictionary, dictLength - length); { use the tail of the dictionary } -{$endif} - end; - - zmemcpy( pBytef(s^.window), dictionary, length); - s^.strstart := length; - s^.block_start := long(length); - - { Insert all strings in the hash table (except for the last two bytes). - s^.lookahead stays null, so s^.ins_h will be recomputed at the next - call of fill_window. } - - s^.ins_h := s^.window^[0]; - {UPDATE_HASH(s, s^.ins_h, s^.window[1]);} - s^.ins_h := ((s^.ins_h shl s^.hash_shift) xor (s^.window^[1])) - and s^.hash_mask; - - for n := 0 to length - MIN_MATCH do - begin - INSERT_STRING(s^, n, hash_head); - end; - {if (hash_head <> 0) then - hash_head := 0; - to make compiler happy } - deflateSetDictionary := Z_OK; -end; - -{ ======================================================================== } -function deflateReset (var strm : z_stream) : int; -var - s : deflate_state_ptr; -begin - if {(@strm = Z_NULL) or} - (strm.state = Z_NULL) - or (not Assigned(strm.zalloc)) or (not Assigned(strm.zfree)) then - begin - deflateReset := Z_STREAM_ERROR; - exit; - end; - - strm.total_out := 0; - strm.total_in := 0; - strm.msg := ''; { use zfree if we ever allocate msg dynamically } - strm.data_type := Z_UNKNOWN; - - s := deflate_state_ptr(strm.state); - s^.pending := 0; - s^.pending_out := pBytef(s^.pending_buf); - - if (s^.noheader < 0) then - begin - s^.noheader := 0; { was set to -1 by deflate(..., Z_FINISH); } - end; - if s^.noheader <> 0 then - s^.status := BUSY_STATE - else - s^.status := INIT_STATE; - strm.adler := 1; - s^.last_flush := Z_NO_FLUSH; - - _tr_init(s^); - lm_init(s^); - - deflateReset := Z_OK; -end; - -{ ======================================================================== } -function deflateParams(var strm : z_stream; - level : int; - strategy : int) : int; -var - s : deflate_state_ptr; - func : compress_func; - err : int; -begin - err := Z_OK; - if {(@strm = Z_NULL) or} (strm.state = Z_NULL) then - begin - deflateParams := Z_STREAM_ERROR; - exit; - end; - - s := deflate_state_ptr(strm.state); - - if (level = Z_DEFAULT_COMPRESSION) then - begin - level := 6; - end; - if (level < 0) or (level > 9) or (strategy < 0) - or (strategy > Z_HUFFMAN_ONLY) then - begin - deflateParams := Z_STREAM_ERROR; - exit; - end; - func := configuration_table[s^.level].func; - - if (@func <> @configuration_table[level].func) - and (strm.total_in <> 0) then - begin - { Flush the last buffer: } - err := deflate(strm, Z_PARTIAL_FLUSH); - end; - if (s^.level <> level) then - begin - s^.level := level; - s^.max_lazy_match := configuration_table[level].max_lazy; - s^.good_match := configuration_table[level].good_length; - s^.nice_match := configuration_table[level].nice_length; - s^.max_chain_length := configuration_table[level].max_chain; - end; - s^.strategy := strategy; - deflateParams := err; -end; - -{ ========================================================================= - Put a short in the pending buffer. The 16-bit value is put in MSB order. - IN assertion: the stream state is correct and there is enough room in - pending_buf. } - -{local} -procedure putShortMSB (var s : deflate_state; b : uInt); -begin - s.pending_buf^[s.pending] := Byte(b shr 8); - Inc(s.pending); - s.pending_buf^[s.pending] := Byte(b and $ff); - Inc(s.pending); -end; - -{ ========================================================================= - Flush as much pending output as possible. All deflate() output goes - through this function so some applications may wish to modify it - to avoid allocating a large strm^.next_out buffer and copying into it. - (See also read_buf()). } - -{local} -procedure flush_pending(var strm : z_stream); -var - len : unsigned; - s : deflate_state_ptr; -begin - s := deflate_state_ptr(strm.state); - len := s^.pending; - - if (len > strm.avail_out) then - len := strm.avail_out; - if (len = 0) then - exit; - - zmemcpy(strm.next_out, s^.pending_out, len); - Inc(strm.next_out, len); - Inc(s^.pending_out, len); - Inc(strm.total_out, len); - Dec(strm.avail_out, len); - Dec(s^.pending, len); - if (s^.pending = 0) then - begin - s^.pending_out := pBytef(s^.pending_buf); - end; -end; - -{ ========================================================================= } -function deflate (var strm : z_stream; flush : int) : int; -var - old_flush : int; { value of flush param for previous deflate call } - s : deflate_state_ptr; -var - header : uInt; - level_flags : uInt; -var - bstate : block_state; -begin - if {(@strm = Z_NULL) or} (strm.state = Z_NULL) - or (flush > Z_FINISH) or (flush < 0) then - begin - deflate := Z_STREAM_ERROR; - exit; - end; - s := deflate_state_ptr(strm.state); - - if (strm.next_out = Z_NULL) or - ((strm.next_in = Z_NULL) and (strm.avail_in <> 0)) or - ((s^.status = FINISH_STATE) and (flush <> Z_FINISH)) then - begin - {ERR_RETURN(strm^, Z_STREAM_ERROR);} - strm.msg := z_errmsg[z_errbase - Z_STREAM_ERROR]; - deflate := Z_STREAM_ERROR; - exit; - end; - if (strm.avail_out = 0) then - begin - {ERR_RETURN(strm^, Z_BUF_ERROR);} - strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR]; - deflate := Z_BUF_ERROR; - exit; - end; - - s^.strm := @strm; { just in case } - old_flush := s^.last_flush; - s^.last_flush := flush; - - { Write the zlib header } - if (s^.status = INIT_STATE) then - begin - - header := (Z_DEFLATED + ((s^.w_bits-8) shl 4)) shl 8; - level_flags := (s^.level-1) shr 1; - - if (level_flags > 3) then - level_flags := 3; - header := header or (level_flags shl 6); - if (s^.strstart <> 0) then - header := header or PRESET_DICT; - Inc(header, 31 - (header mod 31)); - - s^.status := BUSY_STATE; - putShortMSB(s^, header); - - { Save the adler32 of the preset dictionary: } - if (s^.strstart <> 0) then - begin - putShortMSB(s^, uInt(strm.adler shr 16)); - putShortMSB(s^, uInt(strm.adler and $ffff)); - end; - strm.adler := long(1); - end; - - { Flush as much pending output as possible } - if (s^.pending <> 0) then - begin - flush_pending(strm); - if (strm.avail_out = 0) then - begin - { Since avail_out is 0, deflate will be called again with - more output space, but possibly with both pending and - avail_in equal to zero. There won't be anything to do, - but this is not an error situation so make sure we - return OK instead of BUF_ERROR at next call of deflate: } - - s^.last_flush := -1; - deflate := Z_OK; - exit; - end; - - { Make sure there is something to do and avoid duplicate consecutive - flushes. For repeated and useless calls with Z_FINISH, we keep - returning Z_STREAM_END instead of Z_BUFF_ERROR. } - - end - else - if (strm.avail_in = 0) and (flush <= old_flush) - and (flush <> Z_FINISH) then - begin - {ERR_RETURN(strm^, Z_BUF_ERROR);} - strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR]; - deflate := Z_BUF_ERROR; - exit; - end; - - { User must not provide more input after the first FINISH: } - if (s^.status = FINISH_STATE) and (strm.avail_in <> 0) then - begin - {ERR_RETURN(strm^, Z_BUF_ERROR);} - strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR]; - deflate := Z_BUF_ERROR; - exit; - end; - - { Start a new block or continue the current one. } - if (strm.avail_in <> 0) or (s^.lookahead <> 0) - or ((flush <> Z_NO_FLUSH) and (s^.status <> FINISH_STATE)) then - begin - bstate := configuration_table[s^.level].func(s^, flush); - - if (bstate = finish_started) or (bstate = finish_done) then - s^.status := FINISH_STATE; - - if (bstate = need_more) or (bstate = finish_started) then - begin - if (strm.avail_out = 0) then - s^.last_flush := -1; { avoid BUF_ERROR next call, see above } - - deflate := Z_OK; - exit; - { If flush != Z_NO_FLUSH && avail_out == 0, the next call - of deflate should use the same flush parameter to make sure - that the flush is complete. So we don't have to output an - empty block here, this will be done at next call. This also - ensures that for a very small output buffer, we emit at most - one empty block. } - end; - if (bstate = block_done) then - begin - if (flush = Z_PARTIAL_FLUSH) then - _tr_align(s^) - else - begin { FULL_FLUSH or SYNC_FLUSH } - _tr_stored_block(s^, pcharf(NIL), Long(0), FALSE); - { For a full flush, this empty block will be recognized - as a special marker by inflate_sync(). } - - if (flush = Z_FULL_FLUSH) then - begin - {macro CLEAR_HASH(s);} { forget history } - s^.head^[s^.hash_size-1] := ZNIL; - zmemzero(pBytef(s^.head), unsigned(s^.hash_size-1)*sizeof(s^.head^[0])); - end; - end; - - flush_pending(strm); - if (strm.avail_out = 0) then - begin - s^.last_flush := -1; { avoid BUF_ERROR at next call, see above } - deflate := Z_OK; - exit; - end; - - end; - end; - {$IFDEF DEBUG} - Assert(strm.avail_out > 0, 'bug2'); - {$ENDIF} - if (flush <> Z_FINISH) then - begin - deflate := Z_OK; - exit; - end; - - if (s^.noheader <> 0) then - begin - deflate := Z_STREAM_END; - exit; - end; - - { Write the zlib trailer (adler32) } - putShortMSB(s^, uInt(strm.adler shr 16)); - putShortMSB(s^, uInt(strm.adler and $ffff)); - flush_pending(strm); - { If avail_out is zero, the application will call deflate again - to flush the rest. } - - s^.noheader := -1; { write the trailer only once! } - if s^.pending <> 0 then - deflate := Z_OK - else - deflate := Z_STREAM_END; -end; - -{ ========================================================================= } -function deflateEnd (var strm : z_stream) : int; -var - status : int; - s : deflate_state_ptr; -begin - if {(@strm = Z_NULL) or} (strm.state = Z_NULL) then - begin - deflateEnd := Z_STREAM_ERROR; - exit; - end; - - s := deflate_state_ptr(strm.state); - status := s^.status; - if (status <> INIT_STATE) and (status <> BUSY_STATE) and - (status <> FINISH_STATE) then - begin - deflateEnd := Z_STREAM_ERROR; - exit; - end; - - { Deallocate in reverse order of allocations: } - TRY_FREE(strm, s^.pending_buf); - TRY_FREE(strm, s^.head); - TRY_FREE(strm, s^.prev); - TRY_FREE(strm, s^.window); - - ZFREE(strm, s); - strm.state := Z_NULL; - - if status = BUSY_STATE then - deflateEnd := Z_DATA_ERROR - else - deflateEnd := Z_OK; -end; - -{ ========================================================================= - Copy the source state to the destination state. - To simplify the source, this is not supported for 16-bit MSDOS (which - doesn't have enough memory anyway to duplicate compression states). } - - -{ ========================================================================= } -function deflateCopy (dest, source : z_streamp) : int; -{$ifndef MAXSEG_64K} -var - ds : deflate_state_ptr; - ss : deflate_state_ptr; - overlay : pushfArray; -{$endif} -begin -{$ifdef MAXSEG_64K} - deflateCopy := Z_STREAM_ERROR; - exit; -{$else} - - if (source = Z_NULL) or (dest = Z_NULL) or (source^.state = Z_NULL) then - begin - deflateCopy := Z_STREAM_ERROR; - exit; - end; - ss := deflate_state_ptr(source^.state); - dest^ := source^; - - ds := deflate_state_ptr( ZALLOC(dest^, 1, sizeof(deflate_state)) ); - if (ds = Z_NULL) then - begin - deflateCopy := Z_MEM_ERROR; - exit; - end; - dest^.state := pInternal_state(ds); - ds^ := ss^; - ds^.strm := dest; - - ds^.window := pzByteArray ( ZALLOC(dest^, ds^.w_size, 2*sizeof(Byte)) ); - ds^.prev := pzPosfArray ( ZALLOC(dest^, ds^.w_size, sizeof(Pos)) ); - ds^.head := pzPosfArray ( ZALLOC(dest^, ds^.hash_size, sizeof(Pos)) ); - overlay := pushfArray ( ZALLOC(dest^, ds^.lit_bufsize, sizeof(ush)+2) ); - ds^.pending_buf := pzByteArray ( overlay ); - - if (ds^.window = Z_NULL) or (ds^.prev = Z_NULL) or (ds^.head = Z_NULL) - or (ds^.pending_buf = Z_NULL) then - begin - deflateEnd (dest^); - deflateCopy := Z_MEM_ERROR; - exit; - end; - { following zmemcpy do not work for 16-bit MSDOS } - zmemcpy(pBytef(ds^.window), pBytef(ss^.window), ds^.w_size * 2 * sizeof(Byte)); - zmemcpy(pBytef(ds^.prev), pBytef(ss^.prev), ds^.w_size * sizeof(Pos)); - zmemcpy(pBytef(ds^.head), pBytef(ss^.head), ds^.hash_size * sizeof(Pos)); - zmemcpy(pBytef(ds^.pending_buf), pBytef(ss^.pending_buf), uInt(ds^.pending_buf_size)); - - ds^.pending_out := @ds^.pending_buf^[ptr2int(ss^.pending_out) - ptr2int(ss^.pending_buf)]; - ds^.d_buf := pushfArray (@overlay^[ds^.lit_bufsize div sizeof(ush)] ); - ds^.l_buf := puchfArray (@ds^.pending_buf^[(1+sizeof(ush))*ds^.lit_bufsize]); - - ds^.l_desc.dyn_tree := tree_ptr(@ds^.dyn_ltree); - ds^.d_desc.dyn_tree := tree_ptr(@ds^.dyn_dtree); - ds^.bl_desc.dyn_tree := tree_ptr(@ds^.bl_tree); - - deflateCopy := Z_OK; -{$endif} -end; - - -{ =========================================================================== - Read a new buffer from the current input stream, update the adler32 - and total number of bytes read. All deflate() input goes through - this function so some applications may wish to modify it to avoid - allocating a large strm^.next_in buffer and copying from it. - (See also flush_pending()). } - -{local} -function read_buf(strm : z_streamp; buf : pBytef; size : unsigned) : int; -var - len : unsigned; -begin - len := strm^.avail_in; - - if (len > size) then - len := size; - if (len = 0) then - begin - read_buf := 0; - exit; - end; - - Dec(strm^.avail_in, len); - - if deflate_state_ptr(strm^.state)^.noheader = 0 then - begin - strm^.adler := adler32(strm^.adler, strm^.next_in, len); - end; - zmemcpy(buf, strm^.next_in, len); - Inc(strm^.next_in, len); - Inc(strm^.total_in, len); - - read_buf := int(len); -end; - -{ =========================================================================== - Initialize the "longest match" routines for a new zlib stream } - -{local} -procedure lm_init (var s : deflate_state); -begin - s.window_size := ulg( uLong(2)*s.w_size); - - {macro CLEAR_HASH(s);} - s.head^[s.hash_size-1] := ZNIL; - zmemzero(pBytef(s.head), unsigned(s.hash_size-1)*sizeof(s.head^[0])); - - { Set the default configuration parameters: } - - s.max_lazy_match := configuration_table[s.level].max_lazy; - s.good_match := configuration_table[s.level].good_length; - s.nice_match := configuration_table[s.level].nice_length; - s.max_chain_length := configuration_table[s.level].max_chain; - - s.strstart := 0; - s.block_start := long(0); - s.lookahead := 0; - s.prev_length := MIN_MATCH-1; - s.match_length := MIN_MATCH-1; - s.match_available := FALSE; - s.ins_h := 0; -{$ifdef ASMV} - match_init; { initialize the asm code } -{$endif} -end; - -{ =========================================================================== - Set match_start to the longest match starting at the given string and - return its length. Matches shorter or equal to prev_length are discarded, - in which case the result is equal to prev_length and match_start is - garbage. - IN assertions: cur_match is the head of the hash chain for the current - string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - OUT assertion: the match length is not greater than s^.lookahead. } - - -{$ifndef ASMV} -{ For 80x86 and 680x0, an optimized version will be provided in match.asm or - match.S. The code will be functionally equivalent. } - -{$ifndef FASTEST} - -{local} -function longest_match(var s : deflate_state; - cur_match : IPos { current match } - ) : uInt; -label - nextstep; -var - chain_length : unsigned; { max hash chain length } - {register} scan : pBytef; { current string } - {register} match : pBytef; { matched string } - {register} len : int; { length of current match } - best_len : int; { best match length so far } - nice_match : int; { stop if match long enough } - limit : IPos; - - prev : pzPosfArray; - wmask : uInt; -{$ifdef UNALIGNED_OK} - {register} strend : pBytef; - {register} scan_start : ush; - {register} scan_end : ush; -{$else} - {register} strend : pBytef; - {register} scan_end1 : Byte; - {register} scan_end : Byte; -{$endif} -var - MAX_DIST : uInt; -begin - chain_length := s.max_chain_length; { max hash chain length } - scan := @(s.window^[s.strstart]); - best_len := s.prev_length; { best match length so far } - nice_match := s.nice_match; { stop if match long enough } - - - MAX_DIST := s.w_size - MIN_LOOKAHEAD; -{In order to simplify the code, particularly on 16 bit machines, match -distances are limited to MAX_DIST instead of WSIZE. } - - if s.strstart > IPos(MAX_DIST) then - limit := s.strstart - IPos(MAX_DIST) - else - limit := ZNIL; - { Stop when cur_match becomes <= limit. To simplify the code, - we prevent matches with the string of window index 0. } - - prev := s.prev; - wmask := s.w_mask; - -{$ifdef UNALIGNED_OK} - { Compare two bytes at a time. Note: this is not always beneficial. - Try with and without -DUNALIGNED_OK to check. } - - strend := pBytef(@(s.window^[s.strstart + MAX_MATCH - 1])); - scan_start := pushf(scan)^; - scan_end := pushfArray(scan)^[best_len-1]; { fix } -{$else} - strend := pBytef(@(s.window^[s.strstart + MAX_MATCH])); - {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} - scan_end1 := pzByteArray(scan)^[best_len-1]; - {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} - scan_end := pzByteArray(scan)^[best_len]; -{$endif} - - { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - It is easy to get rid of this optimization if necessary. } - {$IFDEF DEBUG} - Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever'); - {$ENDIF} - { Do not waste too much time if we already have a good match: } - if (s.prev_length >= s.good_match) then - begin - chain_length := chain_length shr 2; - end; - - { Do not look for matches beyond the end of the input. This is necessary - to make deflate deterministic. } - - if (uInt(nice_match) > s.lookahead) then - nice_match := s.lookahead; - {$IFDEF DEBUG} - Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead'); - {$ENDIF} - repeat - {$IFDEF DEBUG} - Assert(cur_match < s.strstart, 'no future'); - {$ENDIF} - match := @(s.window^[cur_match]); - - { Skip to next match if the match length cannot increase - or if the match length is less than 2: } - -{$undef DO_UNALIGNED_OK} -{$ifdef UNALIGNED_OK} - {$ifdef MAX_MATCH_IS_258} - {$define DO_UNALIGNED_OK} - {$endif} -{$endif} - -{$ifdef DO_UNALIGNED_OK} - { This code assumes sizeof(unsigned short) = 2. Do not use - UNALIGNED_OK if your compiler uses a different size. } - {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} - if (pushfArray(match)^[best_len-1] <> scan_end) or - (pushf(match)^ <> scan_start) then - goto nextstep; {continue;} - {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} - - { It is not necessary to compare scan[2] and match[2] since they are - always equal when the other bytes match, given that the hash keys - are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - strstart+3, +5, ... up to strstart+257. We check for insufficient - lookahead only every 4th comparison; the 128th check will be made - at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - necessary to put more guard bytes at the end of the window, or - to check more often for insufficient lookahead. } - {$IFDEF DEBUG} - Assert(pzByteArray(scan)^[2] = pzByteArray(match)^[2], 'scan[2]?'); - {$ENDIF} - Inc(scan); - Inc(match); - - repeat - Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; - Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; - Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; - Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; - until (ptr2int(scan) >= ptr2int(strend)); - { The funny "do while" generates better code on most compilers } - - { Here, scan <= window+strstart+257 } - {$IFDEF DEBUG} - {$ifopt R+} {$define RangeCheck} {$endif} {$R-} - Assert(ptr2int(scan) <= - ptr2int(@(s.window^[unsigned(s.window_size-1)])), - 'wild scan'); - {$ifdef RangeCheck} {$R+} {$undef RangeCheck} {$endif} - {$ENDIF} - if (scan^ = match^) then - Inc(scan); - - len := (MAX_MATCH - 1) - int(ptr2int(strend)) + int(ptr2int(scan)); - scan := strend; - Dec(scan, (MAX_MATCH-1)); - -{$else} { UNALIGNED_OK } - - {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} - if (pzByteArray(match)^[best_len] <> scan_end) or - (pzByteArray(match)^[best_len-1] <> scan_end1) or - (match^ <> scan^) then - goto nextstep; {continue;} - {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} - Inc(match); - if (match^ <> pzByteArray(scan)^[1]) then - goto nextstep; {continue;} - - { The check at best_len-1 can be removed because it will be made - again later. (This heuristic is not always a win.) - It is not necessary to compare scan[2] and match[2] since they - are always equal when the other bytes match, given that - the hash keys are equal and that HASH_BITS >= 8. } - - Inc(scan, 2); - Inc(match); - {$IFDEF DEBUG} - Assert( scan^ = match^, 'match[2]?'); - {$ENDIF} - { We check for insufficient lookahead only every 8th comparison; - the 256th check will be made at strstart+258. } - - repeat - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - Inc(scan); Inc(match); if (scan^ <> match^) then break; - until (ptr2int(scan) >= ptr2int(strend)); - - {$IFDEF DEBUG} - Assert(ptr2int(scan) <= - ptr2int(@(s.window^[unsigned(s.window_size-1)])), - 'wild scan'); - {$ENDIF} - - len := MAX_MATCH - int(ptr2int(strend) - ptr2int(scan)); - scan := strend; - Dec(scan, MAX_MATCH); - -{$endif} { UNALIGNED_OK } - - if (len > best_len) then - begin - s.match_start := cur_match; - best_len := len; - if (len >= nice_match) then - break; - {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} -{$ifdef UNALIGNED_OK} - scan_end := pzByteArray(scan)^[best_len-1]; -{$else} - scan_end1 := pzByteArray(scan)^[best_len-1]; - scan_end := pzByteArray(scan)^[best_len]; -{$endif} - {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} - end; - nextstep: - cur_match := prev^[cur_match and wmask]; - Dec(chain_length); - until (cur_match <= limit) or (chain_length = 0); - - if (uInt(best_len) <= s.lookahead) then - longest_match := uInt(best_len) - else - longest_match := s.lookahead; -end; -{$endif} { ASMV } - -{$else} { FASTEST } -{ --------------------------------------------------------------------------- - Optimized version for level = 1 only } - -{local} -function longest_match(var s : deflate_state; - cur_match : IPos { current match } - ) : uInt; -var - {register} scan : pBytef; { current string } - {register} match : pBytef; { matched string } - {register} len : int; { length of current match } - {register} strend : pBytef; -begin - scan := @s.window^[s.strstart]; - strend := @s.window^[s.strstart + MAX_MATCH]; - - - { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - It is easy to get rid of this optimization if necessary. } - {$IFDEF DEBUG} - Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever'); - - Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead'); - - Assert(cur_match < s.strstart, 'no future'); - {$ENDIF} - match := s.window + cur_match; - - { Return failure if the match length is less than 2: } - - if (match[0] <> scan[0]) or (match[1] <> scan[1]) then - begin - longest_match := MIN_MATCH-1; - exit; - end; - - { The check at best_len-1 can be removed because it will be made - again later. (This heuristic is not always a win.) - It is not necessary to compare scan[2] and match[2] since they - are always equal when the other bytes match, given that - the hash keys are equal and that HASH_BITS >= 8. } - - scan += 2, match += 2; - Assert(scan^ = match^, 'match[2]?'); - - { We check for insufficient lookahead only every 8th comparison; - the 256th check will be made at strstart+258. } - - repeat - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - Inc(scan); Inc(match); if scan^<>match^ then break; - until (ptr2int(scan) >= ptr2int(strend)); - - Assert(scan <= s.window+unsigned(s.window_size-1), 'wild scan'); - - len := MAX_MATCH - int(strend - scan); - - if (len < MIN_MATCH) then - begin - return := MIN_MATCH - 1; - exit; - end; - - s.match_start := cur_match; - if len <= s.lookahead then - longest_match := len - else - longest_match := s.lookahead; -end; -{$endif} { FASTEST } - -{$ifdef DEBUG} -{ =========================================================================== - Check that the match at match_start is indeed a match. } - -{local} -procedure check_match(var s : deflate_state; - start, match : IPos; - length : int); -begin - exit; - { check that the match is indeed a match } - if (zmemcmp(pBytef(@s.window^[match]), - pBytef(@s.window^[start]), length) <> EQUAL) then - begin - WriteLn(' start ',start,', match ',match ,' length ', length); - repeat - Write(AnsiChar(s.window^[match]), AnsiChar(s.window^[start])); - Inc(match); - Inc(start); - Dec(length); - Until (length = 0); - z_error('invalid match'); - end; - if (z_verbose > 1) then - begin - Write('\\[',start-match,',',length,']'); - repeat - Write(AnsiChar(s.window^[start])); - Inc(start); - Dec(length); - Until (length = 0); - end; -end; -{$endif} - -{ =========================================================================== - Fill the window when the lookahead becomes insufficient. - Updates strstart and lookahead. - - IN assertion: lookahead < MIN_LOOKAHEAD - OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - At least one byte has been read, or avail_in = 0; reads are - performed for at least two bytes (required for the zip translate_eol - option -- not supported here). } - -{local} -procedure fill_window(var s : deflate_state); -var - {register} n, m : unsigned; - {register} p : pPosf; - more : unsigned; { Amount of free space at the end of the window. } - wsize : uInt; -begin - wsize := s.w_size; - repeat - more := unsigned(s.window_size -ulg(s.lookahead) -ulg(s.strstart)); - - { Deal with !@#$% 64K limit: } - if (more = 0) and (s.strstart = 0) and (s.lookahead = 0) then - more := wsize - else - if (more = unsigned(-1)) then - begin - { Very unlikely, but possible on 16 bit machine if strstart = 0 - and lookahead = 1 (input done one byte at time) } - Dec(more); - - { If the window is almost full and there is insufficient lookahead, - move the upper half to the lower one to make room in the upper half.} - end - else - if (s.strstart >= wsize+ {MAX_DIST}(wsize-MIN_LOOKAHEAD)) then - begin - zmemcpy( pBytef(s.window), pBytef(@(s.window^[wsize])), - unsigned(wsize)); - Dec(s.match_start, wsize); - Dec(s.strstart, wsize); { we now have strstart >= MAX_DIST } - Dec(s.block_start, long(wsize)); - - { Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level = 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) } - - n := s.hash_size; - p := @s.head^[n]; - repeat - Dec(p); - m := p^; - if (m >= wsize) then - p^ := Pos(m-wsize) - else - p^ := Pos(ZNIL); - Dec(n); - Until (n=0); - - n := wsize; -{$ifndef FASTEST} - p := @s.prev^[n]; - repeat - Dec(p); - m := p^; - if (m >= wsize) then - p^ := Pos(m-wsize) - else - p^:= Pos(ZNIL); - { If n is not on any hash chain, prev^[n] is garbage but - its value will never be used. } - Dec(n); - Until (n=0); -{$endif} - Inc(more, wsize); - end; - if (s.strm^.avail_in = 0) then - exit; - - {* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. } - - {$IFDEF DEBUG} - Assert(more >= 2, 'more < 2'); - {$ENDIF} - - n := read_buf(s.strm, pBytef(@(s.window^[s.strstart + s.lookahead])), - more); - Inc(s.lookahead, n); - - { Initialize the hash value now that we have some input: } - if (s.lookahead >= MIN_MATCH) then - begin - s.ins_h := s.window^[s.strstart]; - {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);} - s.ins_h := ((s.ins_h shl s.hash_shift) xor s.window^[s.strstart+1]) - and s.hash_mask; -{$ifdef MIN_MATCH <> 3} - Call UPDATE_HASH() MIN_MATCH-3 more times -{$endif} - end; - { If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - but this is not important since only literal bytes will be emitted. } - - until (s.lookahead >= MIN_LOOKAHEAD) or (s.strm^.avail_in = 0); -end; - -{ =========================================================================== - Flush the current block, with given end-of-file flag. - IN assertion: strstart is set to the end of the current match. } - -procedure FLUSH_BLOCK_ONLY(var s : deflate_state; eof : boolean); {macro} -begin - if (s.block_start >= Long(0)) then - _tr_flush_block(s, pcharf(@s.window^[unsigned(s.block_start)]), - ulg(long(s.strstart) - s.block_start), eof) - else - _tr_flush_block(s, pcharf(Z_NULL), - ulg(long(s.strstart) - s.block_start), eof); - - s.block_start := s.strstart; - flush_pending(s.strm^); - {$IFDEF DEBUG} - Tracev('[FLUSH]'); - {$ENDIF} -end; - -{ Same but force premature exit if necessary. -macro FLUSH_BLOCK(var s : deflate_state; eof : boolean) : boolean; -var - result : block_state; -begin - FLUSH_BLOCK_ONLY(s, eof); - if (s.strm^.avail_out = 0) then - begin - if eof then - result := finish_started - else - result := need_more; - exit; - end; -end; -} - -{ =========================================================================== - Copy without compression as much as possible from the input stream, return - the current block state. - This function does not insert new strings in the dictionary since - uncompressible data is probably not useful. This function is used - only for the level=0 compression option. - NOTE: this function should be optimized to avoid extra copying from - window to pending_buf. } - - -{local} -function deflate_stored(var s : deflate_state; flush : int) : block_state; -{ Stored blocks are limited to 0xffff bytes, pending_buf is limited - to pending_buf_size, and each stored block has a 5 byte header: } -var - max_block_size : ulg; - max_start : ulg; -begin - max_block_size := $ffff; - if (max_block_size > s.pending_buf_size - 5) then - max_block_size := s.pending_buf_size - 5; - - { Copy as much as possible from input to output: } - while TRUE do - begin - { Fill the window as much as possible: } - if (s.lookahead <= 1) then - begin - {$IFDEF DEBUG} - Assert( (s.strstart < s.w_size + {MAX_DIST}s.w_size-MIN_LOOKAHEAD) or - (s.block_start >= long(s.w_size)), 'slide too late'); - {$ENDIF} - fill_window(s); - if (s.lookahead = 0) and (flush = Z_NO_FLUSH) then - begin - deflate_stored := need_more; - exit; - end; - - if (s.lookahead = 0) then - break; { flush the current block } - end; - {$IFDEF DEBUG} - Assert(s.block_start >= long(0), 'block gone'); - {$ENDIF} - Inc(s.strstart, s.lookahead); - s.lookahead := 0; - - { Emit a stored block if pending_buf will be full: } - max_start := s.block_start + max_block_size; - if (s.strstart = 0) or (ulg(s.strstart) >= max_start) then - begin - { strstart = 0 is possible when wraparound on 16-bit machine } - s.lookahead := s.strstart - uInt(max_start); - s.strstart := uInt(max_start); - {FLUSH_BLOCK(s, FALSE);} - FLUSH_BLOCK_ONLY(s, FALSE); - if (s.strm^.avail_out = 0) then - begin - deflate_stored := need_more; - exit; - end; - end; - - { Flush if we may have to slide, otherwise block_start may become - negative and the data will be gone: } - - if (s.strstart - uInt(s.block_start) >= {MAX_DIST} - s.w_size-MIN_LOOKAHEAD) then - begin - {FLUSH_BLOCK(s, FALSE);} - FLUSH_BLOCK_ONLY(s, FALSE); - if (s.strm^.avail_out = 0) then - begin - deflate_stored := need_more; - exit; - end; - end; - end; - - {FLUSH_BLOCK(s, flush = Z_FINISH);} - FLUSH_BLOCK_ONLY(s, flush = Z_FINISH); - if (s.strm^.avail_out = 0) then - begin - if flush = Z_FINISH then - deflate_stored := finish_started - else - deflate_stored := need_more; - exit; - end; - - if flush = Z_FINISH then - deflate_stored := finish_done - else - deflate_stored := block_done; -end; - -{ =========================================================================== - Compress as much as possible from the input stream, return the current - block state. - This function does not perform lazy evaluation of matches and inserts - new strings in the dictionary only for unmatched strings or for short - matches. It is used only for the fast compression options. } - -{local} -function deflate_fast(var s : deflate_state; flush : int) : block_state; -var - hash_head : IPos; { head of the hash chain } - bflush : boolean; { set if current block must be flushed } -begin - hash_head := ZNIL; - while TRUE do - begin - { Make sure that we always have enough lookahead, except - at the end of the input file. We need MAX_MATCH bytes - for the next match, plus MIN_MATCH bytes to insert the - string following the next match. } - - if (s.lookahead < MIN_LOOKAHEAD) then - begin - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then - begin - deflate_fast := need_more; - exit; - end; - - if (s.lookahead = 0) then - break; { flush the current block } - end; - - - { Insert the string window[strstart .. strstart+2] in the - dictionary, and set hash_head to the head of the hash chain: } - - if (s.lookahead >= MIN_MATCH) then - begin - INSERT_STRING(s, s.strstart, hash_head); - end; - - { Find the longest match, discarding those <= prev_length. - At this point we have always match_length < MIN_MATCH } - if (hash_head <> ZNIL) and - (s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD){MAX_DIST}) then - begin - { To simplify the code, we prevent matches with the string - of window index 0 (in particular we have to avoid a match - of the string with itself at the start of the input file). } - if (s.strategy <> Z_HUFFMAN_ONLY) then - begin - s.match_length := longest_match (s, hash_head); - end; - { longest_match() sets match_start } - end; - if (s.match_length >= MIN_MATCH) then - begin - {$IFDEF DEBUG} - check_match(s, s.strstart, s.match_start, s.match_length); - {$ENDIF} - - {_tr_tally_dist(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH, bflush);} - bflush := _tr_tally(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH); - - Dec(s.lookahead, s.match_length); - - { Insert new strings in the hash table only if the match length - is not too large. This saves time but degrades compression. } - -{$ifndef FASTEST} - if (s.match_length <= s.max_insert_length) - and (s.lookahead >= MIN_MATCH) then - begin - Dec(s.match_length); { string at strstart already in hash table } - repeat - Inc(s.strstart); - INSERT_STRING(s, s.strstart, hash_head); - { strstart never exceeds WSIZE-MAX_MATCH, so there are - always MIN_MATCH bytes ahead. } - Dec(s.match_length); - until (s.match_length = 0); - Inc(s.strstart); - end - else -{$endif} - - begin - Inc(s.strstart, s.match_length); - s.match_length := 0; - s.ins_h := s.window^[s.strstart]; - {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);} - s.ins_h := (( s.ins_h shl s.hash_shift) xor - s.window^[s.strstart+1]) and s.hash_mask; -if MIN_MATCH <> 3 then { the linker removes this } -begin - {Call UPDATE_HASH() MIN_MATCH-3 more times} -end; - - { If lookahead < MIN_MATCH, ins_h is garbage, but it does not - matter since it will be recomputed at next deflate call. } - - end; - end - else - begin - { No match, output a literal byte } - {$IFDEF DEBUG} - Tracevv(AnsiChar(s.window^[s.strstart])); - {$ENDIF} - {_tr_tally_lit (s, 0, s.window^[s.strstart], bflush);} - bflush := _tr_tally (s, 0, s.window^[s.strstart]); - - Dec(s.lookahead); - Inc(s.strstart); - end; - if bflush then - begin {FLUSH_BLOCK(s, FALSE);} - FLUSH_BLOCK_ONLY(s, FALSE); - if (s.strm^.avail_out = 0) then - begin - deflate_fast := need_more; - exit; - end; - end; - end; - {FLUSH_BLOCK(s, flush = Z_FINISH);} - FLUSH_BLOCK_ONLY(s, flush = Z_FINISH); - if (s.strm^.avail_out = 0) then - begin - if flush = Z_FINISH then - deflate_fast := finish_started - else - deflate_fast := need_more; - exit; - end; - - if flush = Z_FINISH then - deflate_fast := finish_done - else - deflate_fast := block_done; -end; - -{ =========================================================================== - Same as above, but achieves better compression. We use a lazy - evaluation for matches: a match is finally adopted only if there is - no better match at the next window position. } - -{local} -function deflate_slow(var s : deflate_state; flush : int) : block_state; -var - hash_head : IPos; { head of hash chain } - bflush : boolean; { set if current block must be flushed } -var - max_insert : uInt; -begin - hash_head := ZNIL; - - { Process the input block. } - while TRUE do - begin - { Make sure that we always have enough lookahead, except - at the end of the input file. We need MAX_MATCH bytes - for the next match, plus MIN_MATCH bytes to insert the - string following the next match. } - - if (s.lookahead < MIN_LOOKAHEAD) then - begin - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then - begin - deflate_slow := need_more; - exit; - end; - - if (s.lookahead = 0) then - break; { flush the current block } - end; - - { Insert the string window[strstart .. strstart+2] in the - dictionary, and set hash_head to the head of the hash chain: } - - if (s.lookahead >= MIN_MATCH) then - begin - INSERT_STRING(s, s.strstart, hash_head); - end; - - { Find the longest match, discarding those <= prev_length. } - - s.prev_length := s.match_length; - s.prev_match := s.match_start; - s.match_length := MIN_MATCH-1; - - if (hash_head <> ZNIL) and (s.prev_length < s.max_lazy_match) and - (s.strstart - hash_head <= {MAX_DIST}(s.w_size-MIN_LOOKAHEAD)) then - begin - { To simplify the code, we prevent matches with the string - of window index 0 (in particular we have to avoid a match - of the string with itself at the start of the input file). } - - if (s.strategy <> Z_HUFFMAN_ONLY) then - begin - s.match_length := longest_match (s, hash_head); - end; - { longest_match() sets match_start } - - if (s.match_length <= 5) and ((s.strategy = Z_FILTERED) or - ((s.match_length = MIN_MATCH) and - (s.strstart - s.match_start > TOO_FAR))) then - begin - { If prev_match is also MIN_MATCH, match_start is garbage - but we will ignore the current match anyway. } - - s.match_length := MIN_MATCH-1; - end; - end; - { If there was a match at the previous step and the current - match is not better, output the previous match: } - - if (s.prev_length >= MIN_MATCH) - and (s.match_length <= s.prev_length) then - begin - max_insert := s.strstart + s.lookahead - MIN_MATCH; - { Do not insert strings in hash table beyond this. } - {$ifdef DEBUG} - check_match(s, s.strstart-1, s.prev_match, s.prev_length); - {$endif} - - {_tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush);} - bflush := _tr_tally(s, s.strstart -1 - s.prev_match, - s.prev_length - MIN_MATCH); - - { Insert in hash table all strings up to the end of the match. - strstart-1 and strstart are already inserted. If there is not - enough lookahead, the last two strings are not inserted in - the hash table. } - - Dec(s.lookahead, s.prev_length-1); - Dec(s.prev_length, 2); - repeat - Inc(s.strstart); - if (s.strstart <= max_insert) then - begin - INSERT_STRING(s, s.strstart, hash_head); - end; - Dec(s.prev_length); - until (s.prev_length = 0); - s.match_available := FALSE; - s.match_length := MIN_MATCH-1; - Inc(s.strstart); - - if (bflush) then {FLUSH_BLOCK(s, FALSE);} - begin - FLUSH_BLOCK_ONLY(s, FALSE); - if (s.strm^.avail_out = 0) then - begin - deflate_slow := need_more; - exit; - end; - end; - end - else - if (s.match_available) then - begin - { If there was no match at the previous position, output a - single literal. If there was a match but the current match - is longer, truncate the previous match to a single literal. } - {$IFDEF DEBUG} - Tracevv(AnsiChar(s.window^[s.strstart-1])); - {$ENDIF} - bflush := _tr_tally (s, 0, s.window^[s.strstart-1]); - - if bflush then - begin - FLUSH_BLOCK_ONLY(s, FALSE); - end; - Inc(s.strstart); - Dec(s.lookahead); - if (s.strm^.avail_out = 0) then - begin - deflate_slow := need_more; - exit; - end; - end - else - begin - { There is no previous match to compare with, wait for - the next step to decide. } - - s.match_available := TRUE; - Inc(s.strstart); - Dec(s.lookahead); - end; - end; - - {$IFDEF DEBUG} - Assert (flush <> Z_NO_FLUSH, 'no flush?'); - {$ENDIF} - if (s.match_available) then - begin - {$IFDEF DEBUG} - Tracevv(AnsiChar(s.window^[s.strstart-1])); - bflush := - {$ENDIF} - _tr_tally (s, 0, s.window^[s.strstart-1]); - s.match_available := FALSE; - end; - {FLUSH_BLOCK(s, flush = Z_FINISH);} - FLUSH_BLOCK_ONLY(s, flush = Z_FINISH); - if (s.strm^.avail_out = 0) then - begin - if flush = Z_FINISH then - deflate_slow := finish_started - else - deflate_slow := need_more; - exit; - end; - if flush = Z_FINISH then - deflate_slow := finish_done - else - deflate_slow := block_done; -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/imzinflate.pas b/3rd/Imaging/Source/ZLib/imzinflate.pas deleted file mode 100644 index 69849508f..000000000 --- a/3rd/Imaging/Source/ZLib/imzinflate.pas +++ /dev/null @@ -1,750 +0,0 @@ -Unit imzinflate; - -{ inflate.c -- zlib interface to inflate modules - Copyright (C) 1995-1998 Mark Adler - - Pascal tranlastion - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -uses - imzutil, impaszlib, iminfblock, iminfutil; - -function inflateInit(var z : z_stream) : int; - -{ Initializes the internal stream state for decompression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, inflateInit updates them to use default - allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_VERSION_ERROR if the zlib library version is incompatible - with the version assumed by the caller. msg is set to null if there is no - error message. inflateInit does not perform any decompression: this will be - done by inflate(). } - - - -function inflateInit_(z : z_streamp; - const version : AnsiString; - stream_size : int) : int; - - -function inflateInit2_(var z: z_stream; - w : int; - const version : AnsiString; - stream_size : int) : int; - -function inflateInit2(var z: z_stream; - windowBits : int) : int; - -{ - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. If a compressed stream with a larger window size is given as - input, inflate() will return with the error code Z_DATA_ERROR instead of - trying to allocate a larger window. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) -} - - - -function inflateEnd(var z : z_stream) : int; - -{ - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -} - -function inflateReset(var z : z_stream) : int; - -{ - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -} - - -function inflate(var z : z_stream; - f : int) : int; -{ - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) - except when forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much - output as possible to the output buffer. The flushing behavior of inflate is - not specified for values of the flush parameter other than Z_SYNC_FLUSH - and Z_FINISH, but the current implementation actually flushes as much output - as possible anyway. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster routine - may be used for the single inflate() call. - - If a preset dictionary is needed at this point (see inflateSetDictionary - below), inflate sets strm-adler to the adler32 checksum of the - dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise - it sets strm->adler to the adler32 checksum of all output produced - so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or - an error code as described below. At the end of the stream, inflate() - checks that its computed adler32 checksum is equal to that saved by the - compressor and returns Z_STREAM_END only if the checksum is correct. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect - adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent - (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if no progress is possible or if there was not - enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR - case, the application may then call inflateSync to look for a good - compression block. -} - - -function inflateSetDictionary(var z : z_stream; - dictionary : pBytef; {const array of byte} - dictLength : uInt) : int; - -{ - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (such as NULL dictionary) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -} - -function inflateSync(var z : z_stream) : int; - -{ - Skips invalid compressed data until a full flush point (see above the - description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR - if no more input was provided, Z_DATA_ERROR if no flush point has been found, - or Z_STREAM_ERROR if the stream structure was inconsistent. In the success - case, the application may save the current current value of total_in which - indicates where valid compressed data was found. In the error case, the - application may repeatedly call inflateSync, providing more input each time, - until success or end of the input data. -} - - -function inflateSyncPoint(var z : z_stream) : int; - - -implementation - -uses - imadler; - -function inflateReset(var z : z_stream) : int; -begin - if (z.state = Z_NULL) then - begin - inflateReset := Z_STREAM_ERROR; - exit; - end; - z.total_out := 0; - z.total_in := 0; - z.msg := ''; - if z.state^.nowrap then - z.state^.mode := BLOCKS - else - z.state^.mode := METHOD; - inflate_blocks_reset(z.state^.blocks^, z, Z_NULL); - {$IFDEF DEBUG} - Tracev('inflate: reset'); - {$ENDIF} - inflateReset := Z_OK; -end; - - -function inflateEnd(var z : z_stream) : int; -begin - if (z.state = Z_NULL) or not Assigned(z.zfree) then - begin - inflateEnd := Z_STREAM_ERROR; - exit; - end; - if (z.state^.blocks <> Z_NULL) then - inflate_blocks_free(z.state^.blocks, z); - ZFREE(z, z.state); - z.state := Z_NULL; - {$IFDEF DEBUG} - Tracev('inflate: end'); - {$ENDIF} - inflateEnd := Z_OK; -end; - - -function inflateInit2_(var z: z_stream; - w : int; - const version : AnsiString; - stream_size : int) : int; -begin - if (version = '') or (version[1] <> ZLIB_VERSION[1]) or - (stream_size <> sizeof(z_stream)) then - begin - inflateInit2_ := Z_VERSION_ERROR; - exit; - end; - { initialize state } - { SetLength(strm.msg, 255); } - z.msg := ''; - if not Assigned(z.zalloc) then - begin - {$IFDEF FPC} z.zalloc := @zcalloc; {$ELSE} - z.zalloc := zcalloc; - {$endif} - z.opaque := voidpf(0); - end; - if not Assigned(z.zfree) then - {$IFDEF FPC} z.zfree := @zcfree; {$ELSE} - z.zfree := zcfree; - {$ENDIF} - - z.state := pInternal_state( ZALLOC(z,1,sizeof(internal_state)) ); - if (z.state = Z_NULL) then - begin - inflateInit2_ := Z_MEM_ERROR; - exit; - end; - - z.state^.blocks := Z_NULL; - - { handle undocumented nowrap option (no zlib header or check) } - z.state^.nowrap := FALSE; - if (w < 0) then - begin - w := - w; - z.state^.nowrap := TRUE; - end; - - { set window size } - if (w < 8) or (w > 15) then - begin - inflateEnd(z); - inflateInit2_ := Z_STREAM_ERROR; - exit; - end; - z.state^.wbits := uInt(w); - - { create inflate_blocks state } - if z.state^.nowrap then - z.state^.blocks := inflate_blocks_new(z, NIL, uInt(1) shl w) - else - {$IFDEF FPC} - z.state^.blocks := inflate_blocks_new(z, @adler32, uInt(1) shl w); - {$ELSE} - z.state^.blocks := inflate_blocks_new(z, adler32, uInt(1) shl w); - {$ENDIF} - if (z.state^.blocks = Z_NULL) then - begin - inflateEnd(z); - inflateInit2_ := Z_MEM_ERROR; - exit; - end; - {$IFDEF DEBUG} - Tracev('inflate: allocated'); - {$ENDIF} - { reset state } - inflateReset(z); - inflateInit2_ := Z_OK; -end; - -function inflateInit2(var z: z_stream; windowBits : int) : int; -begin - inflateInit2 := inflateInit2_(z, windowBits, ZLIB_VERSION, sizeof(z_stream)); -end; - - -function inflateInit(var z : z_stream) : int; -{ inflateInit is a macro to allow checking the zlib version - and the compiler's view of z_stream: } -begin - inflateInit := inflateInit2_(z, DEF_WBITS, ZLIB_VERSION, sizeof(z_stream)); -end; - -function inflateInit_(z : z_streamp; - const version : AnsiString; - stream_size : int) : int; -begin - { initialize state } - if (z = Z_NULL) then - inflateInit_ := Z_STREAM_ERROR - else - inflateInit_ := inflateInit2_(z^, DEF_WBITS, version, stream_size); -end; - -function inflate(var z : z_stream; - f : int) : int; -var - r : int; - b : uInt; -begin - if (z.state = Z_NULL) or (z.next_in = Z_NULL) then - begin - inflate := Z_STREAM_ERROR; - exit; - end; - if f = Z_FINISH then - f := Z_BUF_ERROR - else - f := Z_OK; - r := Z_BUF_ERROR; - while True do - case (z.state^.mode) of - BLOCKS: - begin - r := inflate_blocks(z.state^.blocks^, z, r); - if (r = Z_DATA_ERROR) then - begin - z.state^.mode := BAD; - z.state^.sub.marker := 0; { can try inflateSync } - continue; { break C-switch } - end; - if (r = Z_OK) then - r := f; - if (r <> Z_STREAM_END) then - begin - inflate := r; - exit; - end; - r := f; - inflate_blocks_reset(z.state^.blocks^, z, @z.state^.sub.check.was); - if (z.state^.nowrap) then - begin - z.state^.mode := DONE; - continue; { break C-switch } - end; - z.state^.mode := CHECK4; { falltrough } - end; - CHECK4: - begin - {NEEDBYTE} - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - - {z.state^.sub.check.need := uLong(NEXTBYTE(z)) shl 24;} - Dec(z.avail_in); - Inc(z.total_in); - z.state^.sub.check.need := uLong(z.next_in^) shl 24; - Inc(z.next_in); - - z.state^.mode := CHECK3; { falltrough } - end; - CHECK3: - begin - {NEEDBYTE} - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 16);} - Dec(z.avail_in); - Inc(z.total_in); - Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 16); - Inc(z.next_in); - - z.state^.mode := CHECK2; { falltrough } - end; - CHECK2: - begin - {NEEDBYTE} - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - - {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 8);} - Dec(z.avail_in); - Inc(z.total_in); - Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 8); - Inc(z.next_in); - - z.state^.mode := CHECK1; { falltrough } - end; - CHECK1: - begin - {NEEDBYTE} - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) );} - Dec(z.avail_in); - Inc(z.total_in); - Inc(z.state^.sub.check.need, uLong(z.next_in^) ); - Inc(z.next_in); - - - if (z.state^.sub.check.was <> z.state^.sub.check.need) then - begin - z.state^.mode := BAD; - z.msg := 'incorrect data check'; - z.state^.sub.marker := 5; { can't try inflateSync } - continue; { break C-switch } - end; - {$IFDEF DEBUG} - Tracev('inflate: zlib check ok'); - {$ENDIF} - z.state^.mode := DONE; { falltrough } - end; - DONE: - begin - inflate := Z_STREAM_END; - exit; - end; - METHOD: - begin - {NEEDBYTE} - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; {} - - {z.state^.sub.method := NEXTBYTE(z);} - Dec(z.avail_in); - Inc(z.total_in); - z.state^.sub.method := z.next_in^; - Inc(z.next_in); - - if ((z.state^.sub.method and $0f) <> Z_DEFLATED) then - begin - z.state^.mode := BAD; - z.msg := 'unknown compression method'; - z.state^.sub.marker := 5; { can't try inflateSync } - continue; { break C-switch } - end; - if ((z.state^.sub.method shr 4) + 8 > z.state^.wbits) then - begin - z.state^.mode := BAD; - z.msg := 'invalid window size'; - z.state^.sub.marker := 5; { can't try inflateSync } - continue; { break C-switch } - end; - z.state^.mode := FLAG; - { fall trough } - end; - FLAG: - begin - {NEEDBYTE} - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; {} - {b := NEXTBYTE(z);} - Dec(z.avail_in); - Inc(z.total_in); - b := z.next_in^; - Inc(z.next_in); - - if (((z.state^.sub.method shl 8) + b) mod 31) <> 0 then {% mod ?} - begin - z.state^.mode := BAD; - z.msg := 'incorrect header check'; - z.state^.sub.marker := 5; { can't try inflateSync } - continue; { break C-switch } - end; - {$IFDEF DEBUG} - Tracev('inflate: zlib header ok'); - {$ENDIF} - if ((b and PRESET_DICT) = 0) then - begin - z.state^.mode := BLOCKS; - continue; { break C-switch } - end; - z.state^.mode := DICT4; - { falltrough } - end; - DICT4: - begin - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - - {z.state^.sub.check.need := uLong(NEXTBYTE(z)) shl 24;} - Dec(z.avail_in); - Inc(z.total_in); - z.state^.sub.check.need := uLong(z.next_in^) shl 24; - Inc(z.next_in); - - z.state^.mode := DICT3; { falltrough } - end; - DICT3: - begin - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 16);} - Dec(z.avail_in); - Inc(z.total_in); - Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 16); - Inc(z.next_in); - - z.state^.mode := DICT2; { falltrough } - end; - DICT2: - begin - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - r := f; - - {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 8);} - Dec(z.avail_in); - Inc(z.total_in); - Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 8); - Inc(z.next_in); - - z.state^.mode := DICT1; { falltrough } - end; - DICT1: - begin - if (z.avail_in = 0) then - begin - inflate := r; - exit; - end; - { r := f; --- wird niemals benutzt } - {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) );} - Dec(z.avail_in); - Inc(z.total_in); - Inc(z.state^.sub.check.need, uLong(z.next_in^) ); - Inc(z.next_in); - - z.adler := z.state^.sub.check.need; - z.state^.mode := DICT0; - inflate := Z_NEED_DICT; - exit; - end; - DICT0: - begin - z.state^.mode := BAD; - z.msg := 'need dictionary'; - z.state^.sub.marker := 0; { can try inflateSync } - inflate := Z_STREAM_ERROR; - exit; - end; - BAD: - begin - inflate := Z_DATA_ERROR; - exit; - end; - else - begin - inflate := Z_STREAM_ERROR; - exit; - end; - end; -{$ifdef NEED_DUMMY_result} - result := Z_STREAM_ERROR; { Some dumb compilers complain without this } -{$endif} -end; - -function inflateSetDictionary(var z : z_stream; - dictionary : pBytef; {const array of byte} - dictLength : uInt) : int; -var - length : uInt; -begin - length := dictLength; - - if (z.state = Z_NULL) or (z.state^.mode <> DICT0) then - begin - inflateSetDictionary := Z_STREAM_ERROR; - exit; - end; - if (adler32(Long(1), dictionary, dictLength) <> z.adler) then - begin - inflateSetDictionary := Z_DATA_ERROR; - exit; - end; - z.adler := Long(1); - - if (length >= (uInt(1) shl z.state^.wbits)) then - begin - length := (1 shl z.state^.wbits)-1; - Inc( dictionary, dictLength - length); - end; - inflate_set_dictionary(z.state^.blocks^, dictionary^, length); - z.state^.mode := BLOCKS; - inflateSetDictionary := Z_OK; -end; - - -function inflateSync(var z : z_stream) : int; -const - mark : packed array[0..3] of byte = (0, 0, $ff, $ff); -var - n : uInt; { number of bytes to look at } - p : pBytef; { pointer to bytes } - m : uInt; { number of marker bytes found in a row } - r, w : uLong; { temporaries to save total_in and total_out } -begin - { set up } - if (z.state = Z_NULL) then - begin - inflateSync := Z_STREAM_ERROR; - exit; - end; - if (z.state^.mode <> BAD) then - begin - z.state^.mode := BAD; - z.state^.sub.marker := 0; - end; - n := z.avail_in; - if (n = 0) then - begin - inflateSync := Z_BUF_ERROR; - exit; - end; - p := z.next_in; - m := z.state^.sub.marker; - - { search } - while (n <> 0) and (m < 4) do - begin - if (p^ = mark[m]) then - Inc(m) - else - if (p^ <> 0) then - m := 0 - else - m := 4 - m; - Inc(p); - Dec(n); - end; - - { restore } - Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); - z.next_in := p; - z.avail_in := n; - z.state^.sub.marker := m; - - - { return no joy or set up to restart on a new block } - if (m <> 4) then - begin - inflateSync := Z_DATA_ERROR; - exit; - end; - r := z.total_in; - w := z.total_out; - inflateReset(z); - z.total_in := r; - z.total_out := w; - z.state^.mode := BLOCKS; - inflateSync := Z_OK; -end; - - -{ - returns true if inflate is currently at the end of a block generated - by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH - but removes the length bytes of the resulting empty stored block. When - decompressing, PPP checks that at the end of input packet, inflate is - waiting for these length bytes. -} - -function inflateSyncPoint(var z : z_stream) : int; -begin - if (z.state = Z_NULL) or (z.state^.blocks = Z_NULL) then - begin - inflateSyncPoint := Z_STREAM_ERROR; - exit; - end; - inflateSyncPoint := inflate_blocks_sync_point(z.state^.blocks^); -end; - -end. diff --git a/3rd/Imaging/Source/ZLib/imzutil.pas b/3rd/Imaging/Source/ZLib/imzutil.pas deleted file mode 100644 index 420b5fbd0..000000000 --- a/3rd/Imaging/Source/ZLib/imzutil.pas +++ /dev/null @@ -1,191 +0,0 @@ -Unit imzutil; - -{ - Copyright (C) 1998 by Jacques Nomssi Nzali - For conditions of distribution and use, see copyright notice in readme.txt -} - -interface - -{$I imzconf.inc} - -{ Type declarations } - -type - {Byte = usigned char; 8 bits} - Bytef = byte; - charf = byte; - - int = longint; - intf = int; - uInt = cardinal; { 16 bits or more } - uIntf = uInt; - - Long = longint; - uLong = Cardinal; - uLongf = uLong; - - voidp = pointer; - voidpf = voidp; - pBytef = ^Bytef; - pIntf = ^intf; - puIntf = ^uIntf; - puLong = ^uLongf; - - ptr2int = uInt; -{ a pointer to integer casting is used to do pointer arithmetic. - ptr2int must be an integer type and sizeof(ptr2int) must be less - than sizeof(pointer) - Nomssi } - -type - zByteArray = array[0..(MaxInt div SizeOf(Bytef))-1] of Bytef; - pzByteArray = ^zByteArray; -type - zIntfArray = array[0..(MaxInt div SizeOf(Intf))-1] of Intf; - pzIntfArray = ^zIntfArray; -type - zuIntArray = array[0..(MaxInt div SizeOf(uInt))-1] of uInt; - PuIntArray = ^zuIntArray; - -{ Type declarations - only for deflate } - -type - uch = Byte; - uchf = uch; { FAR } - ush = Word; - ushf = ush; - ulg = LongInt; - - unsigned = uInt; - - pcharf = ^charf; - puchf = ^uchf; - pushf = ^ushf; - -type - zuchfArray = zByteArray; - puchfArray = ^zuchfArray; -type - zushfArray = array[0..(MaxInt div SizeOf(ushf))-1] of ushf; - pushfArray = ^zushfArray; - -procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt); -function zmemcmp(s1p, s2p : pBytef; len : uInt) : int; -procedure zmemzero(destp : pBytef; len : uInt); -procedure zcfree(opaque : voidpf; ptr : voidpf); -function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf; - -implementation - -procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt); -begin - Move(sourcep^, destp^, len); -end; - -function zmemcmp(s1p, s2p : pBytef; len : uInt) : int; -var - j : uInt; - source, - dest : pBytef; -begin - source := s1p; - dest := s2p; - for j := 0 to pred(len) do - begin - if (source^ <> dest^) then - begin - zmemcmp := 2*Ord(source^ > dest^)-1; - exit; - end; - Inc(source); - Inc(dest); - end; - zmemcmp := 0; -end; - -procedure zmemzero(destp : pBytef; len : uInt); -begin - FillChar(destp^, len, 0); -end; - -procedure zcfree(opaque : voidpf; ptr : voidpf); -{$ifdef Delphi16} -var - Handle : THandle; -{$endif} -{$IFDEF FPC} -var - memsize : uint; -{$ENDIF} -begin - (* - {$IFDEF DPMI} - {h :=} GlobalFreePtr(ptr); - {$ELSE} - {$IFDEF CALL_DOS} - dosFree(ptr); - {$ELSE} - {$ifdef HugeMem} - FreeMemHuge(ptr); - {$else} - {$ifdef Delphi16} - Handle := GlobalHandle(LH(ptr).H); { HiWord(LongInt(ptr)) } - GlobalUnLock(Handle); - GlobalFree(Handle); - {$else} - {$IFDEF FPC} - Dec(puIntf(ptr)); - memsize := puIntf(ptr)^; - FreeMem(ptr, memsize+SizeOf(uInt)); - {$ELSE} - FreeMem(ptr); { Delphi 2,3,4 } - {$ENDIF} - {$endif} - {$endif} - {$ENDIF} - {$ENDIF} - *) - FreeMem(ptr); -end; - -function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf; -var - p : voidpf; - memsize : uLong; -{$ifdef Delphi16} - handle : THandle; -{$endif} -begin - memsize := uLong(items) * size; - (* - { $IFDEF DPMI} - p := GlobalAllocPtr(gmem_moveable, memsize); - { $ELSE} - { $IFDEF CALLDOS} - p := dosAlloc(memsize); - { $ELSE} - {$ifdef HugeMem} - GetMemHuge(p, memsize); - { $else} - { $ifdef Delphi16} - Handle := GlobalAlloc(HeapAllocFlags, memsize); - p := GlobalLock(Handle); - { $else} - { $IFDEF FPC} - GetMem(p, memsize+SizeOf(uInt)); - puIntf(p)^:= memsize; - Inc(puIntf(p)); - { $ELSE} - GetMem(p, memsize); { Delphi: p := AllocMem(memsize); } - { $ENDIF} - { $endif} - { $endif} - { $ENDIF} - { $ENDIF} - *) - GetMem(p, memsize); - zcalloc := p; -end; - -end. - diff --git a/3rd/Imaging/Source/ZLib/readme.txt b/3rd/Imaging/Source/ZLib/readme.txt deleted file mode 100644 index f9d80877e..000000000 --- a/3rd/Imaging/Source/ZLib/readme.txt +++ /dev/null @@ -1,129 +0,0 @@ -_____________________________________________________________________________ - -PASZLIB 1.0 May 11th, 1998 - -Based on the zlib 1.1.2, a general purpose data compression library. - -Copyright (C) 1998,1999,2000 by NOMSSI NZALI Jacques H. C. -[kn&n DES] See "Legal issues" for conditions of distribution and use. -_____________________________________________________________________________ - - -Introduction -============ - -The 'zlib' compression library provides in-memory compression and -decompression functions, including integrity checks of the uncompressed -data. This version of the library supports only one compression method -(deflation) but other algorithms will be added later and will have the same -stream interface. - -Compression can be done in a single step if the buffers are large -enough (for example if an input file is mmap'ed), or can be done by -repeated calls of the compression function. In the latter case, the -application must provide more input and/or consume the output -(providing more output space) before each call. - -The default memory requirements for deflate are 256K plus a few kilobytes -for small objects. The default memory requirements for inflate are 32K -plus a few kilobytes for small objects. - -Change Log -========== - -March 24th 2000 - minizip code by Gilles Vollant ported to Pascal. - z_stream.msg defined as string[255] to avoid problems - with Delphi 2+ dynamic string handling. - changes to silence Delphi 5 compiler warning. If you - have Delphi 5, defines Delphi5 in zconf.inc - -May 7th 1999 - Some changes for FPC - deflateCopy() has new parameters - trees.pas - record constant definition -June 17th 1998 - Applied official 1.1.2 patch. - Memcheck turned off by default. - zutil.pas patch for Delphi 1 memory allocation corrected. - dzlib.txt file added. - compress2() is now exported - -June 25th 1998 - fixed a conversion bug: in inftrees.pas, ZFREE(z, v) was - missing in line 574; - -File list -========= - -Here is a road map to the files in the Paszlib distribution. - -readme.txt Introduction, Documentation -dzlib.txt Changes to Delphi sources for Paszlib stream classes - -include file - -zconf.inc Configuration declarations. - -Pascal source code files: - -adler.pas compute the Adler-32 checksum of a data stream -crc.pas compute the CRC-32 of a data stream -gzio.pas IO on .gz files -infblock.pas interpret and process block types to last block -infcodes.pas process literals and length/distance pairs -inffast.pas process literals and length/distance pairs fast -inftrees.pas generate Huffman trees for efficient decoding -infutil.pas types and macros common to blocks and codes -strutils.pas string utilities -trees.pas output deflated data using Huffman coding -zcompres.pas compress a memory buffer -zdeflate.pas compress data using the deflation algorithm -zinflate.pas zlib interface to inflate modules -zlib.pas zlib data structures. read the comments there! -zuncompr.pas decompress a memory buffer -zutil.pas - -minizip/ziputils.pas data structure and IO on .zip file -minizip/unzip.pas -minizip/zip.pas - -Test applications - -example.pas usage example of the zlib compression library -minigzip.pas simulate gzip using the zlib compression library -minizip/miniunz.pas simulates unzip using the zlib compression library -minizip/minizip.pas simulates zip using the zlib compression library - -Legal issues -============ - -Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali - - This software is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - -Archive Locations: -================== - -Check the Paszlib home page with links - - http://www.tu-chemnitz.de/~nomssi/paszlib.html - -The data format used by the zlib library is described by RFCs (Request for -Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt -(zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -These documents are also available in other formats from -ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html. -____________________________________________________________________________ -Jacques Nomssi Nzali <mailto:nomssi@physik.tu-chemnitz.de> March 24th, 2000 \ No newline at end of file diff --git a/3rd/synapse/README.txt b/3rd/synapse/README.txt deleted file mode 100644 index 722c14b61..000000000 --- a/3rd/synapse/README.txt +++ /dev/null @@ -1,45 +0,0 @@ -Synapse -The synchronyous socket library. - -File content: - -1.) About Synapse -2.) Distribution package -3.) Installation instructions -4.) Usage notes - -Synapse homesite is at http://synapse.ararat.cz/ -On homesite is Wiki documentation system and other informations. - -1.) About Synapse - -SYNAPSE library aims to create complete library of classes and functions -that would markedly simplify application programming of network communication -using Winsock. - -2.) Distribution package - -Package must be unpacked with subdirectories. -There are these derectories: - -\Html - Off-line version of Synapse support WEB -\Source - Synapse source code -\Source\Lib - shared units -\Source\Demo - Synapse demo applications - - -3.) Installation instructions - -There aren't any difficulties with current distribution other than add -\Source\Lib directory to library or search path. (...or you can simply put all -required Synapse files into your project directory.) - -4.) Usage notes - -Simply write BLCKSOCK to USES section in your source code -(or any other unit from package, when you need it). -To read documentation, simply open INDEX.HTM file (in HTML subdirectory) -on your HTML browser. - -Last update 2006-09-12 - diff --git a/3rd/synapse/Release.txt b/3rd/synapse/Release.txt deleted file mode 100644 index 8a744cf1d..000000000 --- a/3rd/synapse/Release.txt +++ /dev/null @@ -1,2 +0,0 @@ -Release 39 -2009-10-08 diff --git a/3rd/synapse/licence.txt b/3rd/synapse/licence.txt deleted file mode 100644 index f1f925535..000000000 --- a/3rd/synapse/licence.txt +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c)1999-2002, Lukas Gebauer -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -Neither the name of Lukas Gebauer nor the names of its contributors may -be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. diff --git a/3rd/synapse/source/asn1util.pas b/3rd/synapse/source/asn1util.pas deleted file mode 100644 index 57780868d..000000000 --- a/3rd/synapse/source/asn1util.pas +++ /dev/null @@ -1,520 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.001.000 | -|==============================================================================| -| Content: support for ASN.1 BER coding and decoding | -|==============================================================================| -| Copyright (c)1999-2014, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2014 | -| Portions created by Hernan Sanchez are Copyright (c) 2000. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Hernan Sanchez (hernan.sanchez@iname.com) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(Utilities for handling ASN.1 BER encoding) -By this unit you can parse ASN.1 BER encoded data to elements or build back any - elements to ASN.1 BER encoded buffer. You can dump ASN.1 BER encoded data to - human readable form for easy debugging, too. - -Supported element types are: ASN1_BOOL, ASN1_INT, ASN1_OCTSTR, ASN1_NULL, - ASN1_OBJID, ASN1_ENUM, ASN1_SEQ, ASN1_SETOF, ASN1_IPADDR, ASN1_COUNTER, - ASN1_GAUGE, ASN1_TIMETICKS, ASN1_OPAQUE - -For sample of using, look to @link(TSnmpSend) or @link(TLdapSend)class. -} - -{$Q-} -{$H+} -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit asn1util; - -interface - -uses - SysUtils, Classes, synautil; - -const - ASN1_BOOL = $01; - ASN1_INT = $02; - ASN1_OCTSTR = $04; - ASN1_NULL = $05; - ASN1_OBJID = $06; - ASN1_ENUM = $0a; - ASN1_SEQ = $30; - ASN1_SETOF = $31; - ASN1_IPADDR = $40; - ASN1_COUNTER = $41; - ASN1_GAUGE = $42; - ASN1_TIMETICKS = $43; - ASN1_OPAQUE = $44; - ASN1_COUNTER64 = $46; - -{:Encodes OID item to binary form.} -function ASNEncOIDItem(Value: Int64): AnsiString; - -{:Decodes an OID item of the next element in the "Buffer" from the "Start" - position.} -function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Int64; - -{:Encodes the length of ASN.1 element to binary.} -function ASNEncLen(Len: Integer): AnsiString; - -{:Decodes length of next element in "Buffer" from the "Start" position.} -function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer; - -{:Encodes a signed integer to ASN.1 binary} -function ASNEncInt(Value: Int64): AnsiString; - -{:Encodes unsigned integer into ASN.1 binary} -function ASNEncUInt(Value: Integer): AnsiString; - -{:Encodes ASN.1 object to binary form.} -function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString; - -{:Beginning with the "Start" position, decode the ASN.1 item of the next element - in "Buffer". Type of item is stored in "ValueType."} -function ASNItem(var Start: Integer; const Buffer: AnsiString; - var ValueType: Integer): AnsiString; - -{:Encodes an MIB OID string to binary form.} -function MibToId(Mib: String): AnsiString; - -{:Decodes MIB OID from binary form to string form.} -function IdToMib(const Id: AnsiString): String; - -{:Encodes an one number from MIB OID to binary form. (used internally from -@link(MibToId))} -function IntMibToStr(const Value: AnsiString): AnsiString; - -{:Convert ASN.1 BER encoded buffer to human readable form for debugging.} -function ASNdump(const Value: AnsiString): AnsiString; - -implementation - -{==============================================================================} -function ASNEncOIDItem(Value: Int64): AnsiString; -var - x: Int64; - xm: Byte; - b: Boolean; -begin - x := Value; - b := False; - Result := ''; - repeat - xm := x mod 128; - x := x div 128; - if b then - xm := xm or $80; - if x > 0 then - b := True; - Result := AnsiChar(xm) + Result; - until x = 0; -end; - -{==============================================================================} -function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Int64; -var - x: Integer; - b: Boolean; -begin - Result := 0; - repeat - Result := Result * 128; - x := Ord(Buffer[Start]); - Inc(Start); - b := x > $7F; - x := x and $7F; - Result := Result + x; - until not b; -end; - -{==============================================================================} -function ASNEncLen(Len: Integer): AnsiString; -var - x, y: Integer; -begin - if Len < $80 then - Result := AnsiChar(Len) - else - begin - x := Len; - Result := ''; - repeat - y := x mod 256; - x := x div 256; - Result := AnsiChar(y) + Result; - until x = 0; - y := Length(Result); - y := y or $80; - Result := AnsiChar(y) + Result; - end; -end; - -{==============================================================================} -function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer; -var - x, n: Integer; -begin - x := Ord(Buffer[Start]); - Inc(Start); - if x < $80 then - Result := x - else - begin - Result := 0; - x := x and $7F; - for n := 1 to x do - begin - Result := Result * 256; - x := Ord(Buffer[Start]); - Inc(Start); - Result := Result + x; - end; - end; -end; - -{==============================================================================} -function ASNEncInt(Value: Int64): AnsiString; -var - x: Int64; - y: byte; - neg: Boolean; -begin - neg := Value < 0; - x := Abs(Value); - if neg then - x := x - 1; - Result := ''; - repeat - y := x mod 256; - x := x div 256; - if neg then - y := not y; - Result := AnsiChar(y) + Result; - until x = 0; - if (not neg) and (Result[1] > #$7F) then - Result := #0 + Result; - if (neg) and (Result[1] < #$80) then - Result := #$FF + Result; -end; - -{==============================================================================} -function ASNEncUInt(Value: Integer): AnsiString; -var - x, y: Integer; - neg: Boolean; -begin - neg := Value < 0; - x := Value; - if neg then - x := x and $7FFFFFFF; - Result := ''; - repeat - y := x mod 256; - x := x div 256; - Result := AnsiChar(y) + Result; - until x = 0; - if neg then - Result[1] := AnsiChar(Ord(Result[1]) or $80); -end; - -{==============================================================================} -function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString; -begin - Result := AnsiChar(ASNType) + ASNEncLen(Length(Data)) + Data; -end; - -{==============================================================================} -function ASNItem(var Start: Integer; const Buffer: AnsiString; - var ValueType: Integer): AnsiString; -var - ASNType: Integer; - ASNSize: Integer; - y: int64; - n: Integer; - x: byte; - s: AnsiString; - c: AnsiChar; - neg: Boolean; - l: Integer; -begin - Result := ''; - ValueType := ASN1_NULL; - l := Length(Buffer); - if l < (Start + 1) then - Exit; - ASNType := Ord(Buffer[Start]); - ValueType := ASNType; - Inc(Start); - ASNSize := ASNDecLen(Start, Buffer); - if (Start + ASNSize - 1) > l then - Exit; - if (ASNType and $20) > 0 then -// Result := '$' + IntToHex(ASNType, 2) - Result := Copy(Buffer, Start, ASNSize) - else - case ASNType of - ASN1_INT, ASN1_ENUM, ASN1_BOOL: - begin - y := 0; - neg := False; - for n := 1 to ASNSize do - begin - x := Ord(Buffer[Start]); - if (n = 1) and (x > $7F) then - neg := True; - if neg then - x := not x; - y := y * 256 + x; - Inc(Start); - end; - if neg then - y := -(y + 1); - Result := IntToStr(y); - end; - ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS, ASN1_COUNTER64: - begin - y := 0; - for n := 1 to ASNSize do - begin - y := y * 256 + Ord(Buffer[Start]); - Inc(Start); - end; - Result := IntToStr(y); - end; - ASN1_OCTSTR, ASN1_OPAQUE: - begin - for n := 1 to ASNSize do - begin - c := AnsiChar(Buffer[Start]); - Inc(Start); - s := s + c; - end; - Result := s; - end; - ASN1_OBJID: - begin - for n := 1 to ASNSize do - begin - c := AnsiChar(Buffer[Start]); - Inc(Start); - s := s + c; - end; - Result := IdToMib(s); - end; - ASN1_IPADDR: - begin - s := ''; - for n := 1 to ASNSize do - begin - if (n <> 1) then - s := s + '.'; - y := Ord(Buffer[Start]); - Inc(Start); - s := s + IntToStr(y); - end; - Result := s; - end; - ASN1_NULL: - begin - Result := ''; - Start := Start + ASNSize; - end; - else // unknown - begin - for n := 1 to ASNSize do - begin - c := AnsiChar(Buffer[Start]); - Inc(Start); - s := s + c; - end; - Result := s; - end; - end; -end; - -{==============================================================================} -function MibToId(Mib: String): AnsiString; -var - x: Integer; - - function WalkInt(var s: String): Integer; - var - x: Integer; - t: AnsiString; - begin - x := Pos('.', s); - if x < 1 then - begin - t := s; - s := ''; - end - else - begin - t := Copy(s, 1, x - 1); - s := Copy(s, x + 1, Length(s) - x); - end; - Result := StrToIntDef(t, 0); - end; - -begin - Result := ''; - x := WalkInt(Mib); - x := x * 40 + WalkInt(Mib); - Result := ASNEncOIDItem(x); - while Mib <> '' do - begin - x := WalkInt(Mib); - Result := Result + ASNEncOIDItem(x); - end; -end; - -{==============================================================================} -function IdToMib(const Id: AnsiString): String; -var - x, y, n: Integer; -begin - Result := ''; - n := 1; - while Length(Id) + 1 > n do - begin - x := ASNDecOIDItem(n, Id); - if (n - 1) = 1 then - begin - y := x div 40; - x := x mod 40; - Result := IntToStr(y); - end; - Result := Result + '.' + IntToStr(x); - end; -end; - -{==============================================================================} -function IntMibToStr(const Value: AnsiString): AnsiString; -var - n, y: Integer; -begin - y := 0; - for n := 1 to Length(Value) - 1 do - y := y * 256 + Ord(Value[n]); - Result := IntToStr(y); -end; - -{==============================================================================} -function ASNdump(const Value: AnsiString): AnsiString; -var - i, at, x, n: integer; - s, indent: AnsiString; - il: TStringList; -begin - il := TStringList.Create; - try - Result := ''; - i := 1; - indent := ''; - while i < Length(Value) do - begin - for n := il.Count - 1 downto 0 do - begin - x := StrToIntDef(il[n], 0); - if x <= i then - begin - il.Delete(n); - Delete(indent, 1, 2); - end; - end; - s := ASNItem(i, Value, at); - Result := Result + indent + '$' + IntToHex(at, 2); - if (at and $20) > 0 then - begin - x := Length(s); - Result := Result + ' constructed: length ' + IntToStr(x); - indent := indent + ' '; - il.Add(IntToStr(x + i - 1)); - end - else - begin - case at of - ASN1_BOOL: - Result := Result + ' BOOL: '; - ASN1_INT: - Result := Result + ' INT: '; - ASN1_ENUM: - Result := Result + ' ENUM: '; - ASN1_COUNTER: - Result := Result + ' COUNTER: '; - ASN1_GAUGE: - Result := Result + ' GAUGE: '; - ASN1_TIMETICKS: - Result := Result + ' TIMETICKS: '; - ASN1_OCTSTR: - Result := Result + ' OCTSTR: '; - ASN1_OPAQUE: - Result := Result + ' OPAQUE: '; - ASN1_OBJID: - Result := Result + ' OBJID: '; - ASN1_IPADDR: - Result := Result + ' IPADDR: '; - ASN1_NULL: - Result := Result + ' NULL: '; - ASN1_COUNTER64: - Result := Result + ' COUNTER64: '; - else // other - Result := Result + ' unknown: '; - end; - if IsBinaryString(s) then - s := DumpExStr(s); - Result := Result + s; - end; - Result := Result + #$0d + #$0a; - end; - finally - il.Free; - end; -end; - -{==============================================================================} - -end. diff --git a/3rd/synapse/source/blcksock.pas b/3rd/synapse/source/blcksock.pas deleted file mode 100644 index c1f4d3d32..000000000 --- a/3rd/synapse/source/blcksock.pas +++ /dev/null @@ -1,4354 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 009.009.001 | -|==============================================================================| -| Content: Library base | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)1999-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{ -Special thanks to Gregor Ibic <gregor.ibic@intelicom.si> - (Intelicom d.o.o., http://www.intelicom.si) - for good inspiration about SSL programming. -} - -{$DEFINE ONCEWINSOCK} -{Note about define ONCEWINSOCK: -If you remove this compiler directive, then socket interface is loaded and -initialized on constructor of TBlockSocket class for each socket separately. -Socket interface is used only if your need it. - -If you leave this directive here, then socket interface is loaded and -initialized only once at start of your program! It boost performace on high -count of created and destroyed sockets. It eliminate possible small resource -leak on Windows systems too. -} - -//{$DEFINE RAISEEXCEPT} -{When you enable this define, then is Raiseexcept property is on by default -} - -{:@abstract(Synapse's library core) - -Core with implementation basic socket classes. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$IFDEF VER125} - {$DEFINE BCB} -{$ENDIF} -{$IFDEF BCB} - {$ObjExportAll On} -{$ENDIF} -{$Q-} -{$H+} -{$M+} -{$TYPEDADDRESS OFF} - - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit blcksock; - -interface - -uses - SysUtils, Classes, - synafpc, - synsock, synautil, synacode, synaip -{$IFDEF CIL} - ,System.Net - ,System.Net.Sockets - ,System.Text -{$ENDIF} - ; - -const - - SynapseRelease = '40'; - - cLocalhost = '127.0.0.1'; - cAnyHost = '0.0.0.0'; - cBroadcast = '255.255.255.255'; - c6Localhost = '::1'; - c6AnyHost = '::0'; - c6Broadcast = 'ffff::1'; - cAnyPort = '0'; - CR = #$0d; - LF = #$0a; - CRLF = CR + LF; - c64k = 65536; - -type - - {:@abstract(Exception clas used by Synapse) - When you enable generating of exceptions, this exception is raised by - Synapse's units.} - ESynapseError = class(Exception) - private - FErrorCode: Integer; - FErrorMessage: string; - published - {:Code of error. Value depending on used operating system} - property ErrorCode: Integer read FErrorCode Write FErrorCode; - {:Human readable description of error.} - property ErrorMessage: string read FErrorMessage Write FErrorMessage; - end; - - {:Types of OnStatus events} - THookSocketReason = ( - {:Resolving is begin. Resolved IP and port is in parameter in format like: - 'localhost.somewhere.com:25'.} - HR_ResolvingBegin, - {:Resolving is done. Resolved IP and port is in parameter in format like: - 'localhost.somewhere.com:25'. It is always same as in HR_ResolvingBegin!} - HR_ResolvingEnd, - {:Socket created by CreateSocket method. It reporting Family of created - socket too!} - HR_SocketCreate, - {:Socket closed by CloseSocket method.} - HR_SocketClose, - {:Socket binded to IP and Port. Binded IP and Port is in parameter in format - like: 'localhost.somewhere.com:25'.} - HR_Bind, - {:Socket connected to IP and Port. Connected IP and Port is in parameter in - format like: 'localhost.somewhere.com:25'.} - HR_Connect, - {:Called when CanRead method is used with @True result.} - HR_CanRead, - {:Called when CanWrite method is used with @True result.} - HR_CanWrite, - {:Socket is swithed to Listen mode. (TCP socket only)} - HR_Listen, - {:Socket Accepting client connection. (TCP socket only)} - HR_Accept, - {:report count of bytes readed from socket. Number is in parameter string. - If you need is in integer, you must use StrToInt function!} - HR_ReadCount, - {:report count of bytes writed to socket. Number is in parameter string. If - you need is in integer, you must use StrToInt function!} - HR_WriteCount, - {:If is limiting of bandwidth on, then this reason is called when sending or - receiving is stopped for satisfy bandwidth limit. Parameter is count of - waiting milliseconds.} - HR_Wait, - {:report situation where communication error occured. When raiseexcept is - @true, then exception is called after this Hook reason.} - HR_Error - ); - - {:Procedural type for OnStatus event. Sender is calling TBlockSocket object, - Reason is one of set Status events and value is optional data.} - THookSocketStatus = procedure(Sender: TObject; Reason: THookSocketReason; - const Value: String) of object; - - {:This procedural type is used for DataFilter hooks.} - THookDataFilter = procedure(Sender: TObject; var Value: AnsiString) of object; - - {:This procedural type is used for hook OnCreateSocket. By this hook you can - insert your code after initialisation of socket. (you can set special socket - options, etc.)} - THookCreateSocket = procedure(Sender: TObject) of object; - - {:This procedural type is used for monitoring of communication.} - THookMonitor = procedure(Sender: TObject; Writing: Boolean; - const Buffer: TMemory; Len: Integer) of object; - - {:This procedural type is used for hook OnAfterConnect. By this hook you can - insert your code after TCP socket has been sucessfully connected.} - THookAfterConnect = procedure(Sender: TObject) of object; - - {:This procedural type is used for hook OnVerifyCert. By this hook you can - insert your additional certificate verification code. Usefull to verify server - CN against URL. } - - THookVerifyCert = function(Sender: TObject):boolean of object; - - {:This procedural type is used for hook OnHeartbeat. By this hook you can - call your code repeately during long socket operations. - You must enable heartbeats by @Link(HeartbeatRate) property!} - THookHeartbeat = procedure(Sender: TObject) of object; - - {:Specify family of socket.} - TSocketFamily = ( - {:Default mode. Socket family is defined by target address for connection. - It allows instant access to IPv4 and IPv6 nodes. When you need IPv6 address - as destination, then is used IPv6 mode. othervise is used IPv4 mode. - However this mode not working properly with preliminary IPv6 supports!} - SF_Any, - {:Turn this class to pure IPv4 mode. This mode is totally compatible with - previous Synapse releases.} - SF_IP4, - {:Turn to only IPv6 mode.} - SF_IP6 - ); - - {:specify possible values of SOCKS modes.} - TSocksType = ( - ST_Socks5, - ST_Socks4 - ); - - {:Specify requested SSL/TLS version for secure connection.} - TSSLType = ( - LT_all, - LT_SSLv2, - LT_SSLv3, - LT_TLSv1, - LT_TLSv1_1, - LT_SSHv2 - ); - - {:Specify type of socket delayed option.} - TSynaOptionType = ( - SOT_Linger, - SOT_RecvBuff, - SOT_SendBuff, - SOT_NonBlock, - SOT_RecvTimeout, - SOT_SendTimeout, - SOT_Reuse, - SOT_TTL, - SOT_Broadcast, - SOT_MulticastTTL, - SOT_MulticastLoop - ); - - {:@abstract(this object is used for remember delayed socket option set.)} - TSynaOption = class(TObject) - public - Option: TSynaOptionType; - Enabled: Boolean; - Value: Integer; - end; - - TCustomSSL = class; - TSSLClass = class of TCustomSSL; - - {:@abstract(Basic IP object.) - This is parent class for other class with protocol implementations. Do not - use this class directly! Use @link(TICMPBlockSocket), @link(TRAWBlockSocket), - @link(TTCPBlockSocket) or @link(TUDPBlockSocket) instead.} - TBlockSocket = class(TObject) - private - FOnStatus: THookSocketStatus; - FOnReadFilter: THookDataFilter; - FOnCreateSocket: THookCreateSocket; - FOnMonitor: THookMonitor; - FOnHeartbeat: THookHeartbeat; - FLocalSin: TVarSin; - FRemoteSin: TVarSin; - FTag: integer; - FBuffer: AnsiString; - FRaiseExcept: Boolean; - FNonBlockMode: Boolean; - FMaxLineLength: Integer; - FMaxSendBandwidth: Integer; - FNextSend: LongWord; - FMaxRecvBandwidth: Integer; - FNextRecv: LongWord; - FConvertLineEnd: Boolean; - FLastCR: Boolean; - FLastLF: Boolean; - FBinded: Boolean; - FFamily: TSocketFamily; - FFamilySave: TSocketFamily; - FIP6used: Boolean; - FPreferIP4: Boolean; - FDelayedOptions: TList; - FInterPacketTimeout: Boolean; - {$IFNDEF CIL} - FFDSet: TFDSet; - {$ENDIF} - FRecvCounter: Integer; - FSendCounter: Integer; - FSendMaxChunk: Integer; - FStopFlag: Boolean; - FNonblockSendTimeout: Integer; - FHeartbeatRate: integer; - FConnectionTimeout: integer; - {$IFNDEF ONCEWINSOCK} - FWsaDataOnce: TWSADATA; - {$ENDIF} - function GetSizeRecvBuffer: Integer; - procedure SetSizeRecvBuffer(Size: Integer); - function GetSizeSendBuffer: Integer; - procedure SetSizeSendBuffer(Size: Integer); - procedure SetNonBlockMode(Value: Boolean); - procedure SetTTL(TTL: integer); - function GetTTL:integer; - procedure SetFamily(Value: TSocketFamily); virtual; - procedure SetSocket(Value: TSocket); virtual; - function GetWsaData: TWSAData; - function FamilyToAF(f: TSocketFamily): TAddrFamily; - protected - FSocket: TSocket; - FLastError: Integer; - FLastErrorDesc: string; - FOwner: TObject; - procedure SetDelayedOption(const Value: TSynaOption); - procedure DelayedOption(const Value: TSynaOption); - procedure ProcessDelayedOptions; - procedure InternalCreateSocket(Sin: TVarSin); - procedure SetSin(var Sin: TVarSin; IP, Port: string); - function GetSinIP(Sin: TVarSin): string; - function GetSinPort(Sin: TVarSin): Integer; - procedure DoStatus(Reason: THookSocketReason; const Value: string); - procedure DoReadFilter(Buffer: TMemory; var Len: Integer); - procedure DoMonitor(Writing: Boolean; const Buffer: TMemory; Len: Integer); - procedure DoCreateSocket; - procedure DoHeartbeat; - procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); - procedure SetBandwidth(Value: Integer); - function TestStopFlag: Boolean; - procedure InternalSendStream(const Stream: TStream; WithSize, Indy: boolean); virtual; - function InternalCanRead(Timeout: Integer): Boolean; virtual; - public - constructor Create; - - {:Create object and load all necessary socket library. What library is - loaded is described by STUB parameter. If STUB is empty string, then is - loaded default libraries.} - constructor CreateAlternate(Stub: string); - destructor Destroy; override; - - {:If @link(family) is not SF_Any, then create socket with type defined in - @link(Family) property. If family is SF_Any, then do nothing! (socket is - created automaticly when you know what type of socket you need to create. - (i.e. inside @link(Connect) or @link(Bind) call.) When socket is created, - then is aplyed all stored delayed socket options.} - procedure CreateSocket; - - {:It create socket. Address resolving of Value tells what type of socket is - created. If Value is resolved as IPv4 IP, then is created IPv4 socket. If - value is resolved as IPv6 address, then is created IPv6 socket.} - procedure CreateSocketByName(const Value: String); - - {:Destroy socket in use. This method is also automatically called from - object destructor.} - procedure CloseSocket; virtual; - - {:Abort any work on Socket and destroy them.} - procedure AbortSocket; virtual; - - {:Connects socket to local IP address and PORT. IP address may be numeric or - symbolic ('192.168.74.50', 'cosi.nekde.cz', 'ff08::1'). The same for PORT - - it may be number or mnemonic port ('23', 'telnet'). - - If port value is '0', system chooses itself and conects unused port in the - range 1024 to 4096 (this depending by operating system!). Structure - LocalSin is filled after calling this method. - - Note: If you call this on non-created socket, then socket is created - automaticly. - - Warning: when you call : Bind('0.0.0.0','0'); then is nothing done! In this - case is used implicit system bind instead.} - procedure Bind(IP, Port: string); - - {:Connects socket to remote IP address and PORT. The same rules as with - @link(BIND) method are valid. The only exception is that PORT with 0 value - will not be connected! - - Structures LocalSin and RemoteSin will be filled with valid values. - - When you call this on non-created socket, then socket is created - automaticly. Type of created socket is by @link(Family) property. If is - used SF_IP4, then is created socket for IPv4. If is used SF_IP6, then is - created socket for IPv6. When you have family on SF_Any (default!), then - type of created socket is determined by address resolving of destination - address. (Not work properly on prilimitary winsock IPv6 support!)} - procedure Connect(IP, Port: string); virtual; - - {:Sets socket to receive mode for new incoming connections. It is necessary - to use @link(TBlockSocket.BIND) function call before this method to select - receiving port!} - procedure Listen; virtual; - - {:Waits until new incoming connection comes. After it comes a new socket is - automatically created (socket handler is returned by this function as - result).} - function Accept: TSocket; virtual; - - {:Sends data of LENGTH from BUFFER address via connected socket. System - automatically splits data to packets.} - function SendBuffer(Buffer: Tmemory; Length: Integer): Integer; virtual; - - {:One data BYTE is sent via connected socket.} - procedure SendByte(Data: Byte); virtual; - - {:Send data string via connected socket. Any terminator is not added! If you - need send true string with CR-LF termination, you must add CR-LF characters - to sended string! Because any termination is not added automaticly, you can - use this function for sending any binary data in binary string.} - procedure SendString(Data: AnsiString); virtual; - - {:Send integer as four bytes to socket.} - procedure SendInteger(Data: integer); virtual; - - {:Send data as one block to socket. Each block begin with 4 bytes with - length of data in block. This 4 bytes is added automaticly by this - function.} - procedure SendBlock(const Data: AnsiString); virtual; - - {:Send data from stream to socket.} - procedure SendStreamRaw(const Stream: TStream); virtual; - - {:Send content of stream to socket. It using @link(SendBlock) method} - procedure SendStream(const Stream: TStream); virtual; - - {:Send content of stream to socket. It using @link(SendBlock) method and - this is compatible with streams in Indy library.} - procedure SendStreamIndy(const Stream: TStream); virtual; - - {:Note: This is low-level receive function. You must be sure if data is - waiting for read before call this function for avoid deadlock! - - Waits until allocated buffer is filled by received data. Returns number of - data received, which equals to LENGTH value under normal operation. If it - is not equal the communication channel is possibly broken. - - On stream oriented sockets if is received 0 bytes, it mean 'socket is - closed!" - - On datagram socket is readed first waiting datagram.} - function RecvBuffer(Buffer: TMemory; Length: Integer): Integer; virtual; - - {:Note: This is high-level receive function. It using internal - @link(LineBuffer) and you can combine this function freely with other - high-level functions! - - Method waits until data is received. If no data is received within TIMEOUT - (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT. Methods - serves for reading any size of data (i.e. one megabyte...). This method is - preffered for reading from stream sockets (like TCP).} - function RecvBufferEx(Buffer: Tmemory; Len: Integer; - Timeout: Integer): Integer; virtual; - - {:Similar to @link(RecvBufferEx), but readed data is stored in binary - string, not in memory buffer.} - function RecvBufferStr(Len: Integer; Timeout: Integer): AnsiString; virtual; - - {:Note: This is high-level receive function. It using internal - @link(LineBuffer) and you can combine this function freely with other - high-level functions. - - Waits until one data byte is received which is also returned as function - result. If no data is received within TIMEOUT (in milliseconds)period, - @link(LastError) is set to WSAETIMEDOUT and result have value 0.} - function RecvByte(Timeout: Integer): Byte; virtual; - - {:Note: This is high-level receive function. It using internal - @link(LineBuffer) and you can combine this function freely with other - high-level functions. - - Waits until one four bytes are received and return it as one Ineger Value. - If no data is received within TIMEOUT (in milliseconds)period, - @link(LastError) is set to WSAETIMEDOUT and result have value 0.} - function RecvInteger(Timeout: Integer): Integer; virtual; - - {:Note: This is high-level receive function. It using internal - @link(LineBuffer) and you can combine this function freely with other - high-level functions. - - Method waits until data string is received. This string is terminated by - CR-LF characters. The resulting string is returned without this termination - (CR-LF)! If @link(ConvertLineEnd) is used, then CR-LF sequence may not be - exactly CR-LF. See @link(ConvertLineEnd) description. If no data is - received within TIMEOUT (in milliseconds) period, @link(LastError) is set - to WSAETIMEDOUT. You may also specify maximum length of reading data by - @link(MaxLineLength) property.} - function RecvString(Timeout: Integer): AnsiString; virtual; - - {:Note: This is high-level receive function. It using internal - @link(LineBuffer) and you can combine this function freely with other - high-level functions. - - Method waits until data string is received. This string is terminated by - Terminator string. The resulting string is returned without this - termination. If no data is received within TIMEOUT (in milliseconds) - period, @link(LastError) is set to WSAETIMEDOUT. You may also specify - maximum length of reading data by @link(MaxLineLength) property.} - function RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; virtual; - - {:Note: This is high-level receive function. It using internal - @link(LineBuffer) and you can combine this function freely with other - high-level functions. - - Method reads all data waiting for read. If no data is received within - TIMEOUT (in milliseconds) period, @link(LastError) is set to WSAETIMEDOUT. - Methods serves for reading unknown size of data. Because before call this - function you don't know size of received data, returned data is stored in - dynamic size binary string. This method is preffered for reading from - stream sockets (like TCP). It is very goot for receiving datagrams too! - (UDP protocol)} - function RecvPacket(Timeout: Integer): AnsiString; virtual; - - {:Read one block of data from socket. Each block begin with 4 bytes with - length of data in block. This function read first 4 bytes for get lenght, - then it wait for reported count of bytes.} - function RecvBlock(Timeout: Integer): AnsiString; virtual; - - {:Read all data from socket to stream until socket is closed (or any error - occured.)} - procedure RecvStreamRaw(const Stream: TStream; Timeout: Integer); virtual; - {:Read requested count of bytes from socket to stream.} - procedure RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); - - {:Receive data to stream. It using @link(RecvBlock) method.} - procedure RecvStream(const Stream: TStream; Timeout: Integer); virtual; - - {:Receive data to stream. This function is compatible with similar function - in Indy library. It using @link(RecvBlock) method.} - procedure RecvStreamIndy(const Stream: TStream; Timeout: Integer); virtual; - - {:Same as @link(RecvBuffer), but readed data stays in system input buffer. - Warning: this function not respect data in @link(LineBuffer)! Is not - recommended to use this function!} - function PeekBuffer(Buffer: TMemory; Length: Integer): Integer; virtual; - - {:Same as @link(RecvByte), but readed data stays in input system buffer. - Warning: this function not respect data in @link(LineBuffer)! Is not - recommended to use this function!} - function PeekByte(Timeout: Integer): Byte; virtual; - - {:On stream sockets it returns number of received bytes waiting for picking. - 0 is returned when there is no such data. On datagram socket it returns - length of the first waiting datagram. Returns 0 if no datagram is waiting.} - function WaitingData: Integer; virtual; - - {:Same as @link(WaitingData), but if exists some of data in @link(Linebuffer), - return their length instead.} - function WaitingDataEx: Integer; - - {:Clear all waiting data for read from buffers.} - procedure Purge; - - {:Sets linger. Enabled linger means that the system waits another LINGER - (in milliseconds) time for delivery of sent data. This function is only for - stream type of socket! (TCP)} - procedure SetLinger(Enable: Boolean; Linger: Integer); - - {:Actualize values in @link(LocalSin).} - procedure GetSinLocal; - - {:Actualize values in @link(RemoteSin).} - procedure GetSinRemote; - - {:Actualize values in @link(LocalSin) and @link(RemoteSin).} - procedure GetSins; - - {:Reset @link(LastError) and @link(LastErrorDesc) to non-error state.} - procedure ResetLastError; - - {:If you "manually" call Socket API functions, forward their return code as - parameter to this function, which evaluates it, eventually calls - GetLastError and found error code returns and stores to @link(LastError).} - function SockCheck(SockResult: Integer): Integer; virtual; - - {:If @link(LastError) contains some error code and @link(RaiseExcept) - property is @true, raise adequate exception.} - procedure ExceptCheck; - - {:Returns local computer name as numerical or symbolic value. It try get - fully qualified domain name. Name is returned in the format acceptable by - functions demanding IP as input parameter.} - function LocalName: string; - - {:Try resolve name to all possible IP address. i.e. If you pass as name - result of @link(LocalName) method, you get all IP addresses used by local - system.} - procedure ResolveNameToIP(Name: string; const IPList: TStrings); - - {:Try resolve name to primary IP address. i.e. If you pass as name result of - @link(LocalName) method, you get primary IP addresses used by local system.} - function ResolveName(Name: string): string; - - {:Try resolve IP to their primary domain name. If IP not have domain name, - then is returned original IP.} - function ResolveIPToName(IP: string): string; - - {:Try resolve symbolic port name to port number. (i.e. 'Echo' to 8)} - function ResolvePort(Port: string): Word; - - {:Set information about remote side socket. It is good for seting remote - side for sending UDP packet, etc.} - procedure SetRemoteSin(IP, Port: string); - - {:Picks IP socket address from @link(LocalSin).} - function GetLocalSinIP: string; virtual; - - {:Picks IP socket address from @link(RemoteSin).} - function GetRemoteSinIP: string; virtual; - - {:Picks socket PORT number from @link(LocalSin).} - function GetLocalSinPort: Integer; virtual; - - {:Picks socket PORT number from @link(RemoteSin).} - function GetRemoteSinPort: Integer; virtual; - - {:Return @TRUE, if you can read any data from socket or is incoming - connection on TCP based socket. Status is tested for time Timeout (in - milliseconds). If value in Timeout is 0, status is only tested and - continue. If value in Timeout is -1, run is breaked and waiting for read - data maybe forever. - - This function is need only on special cases, when you need use - @link(RecvBuffer) function directly! read functioms what have timeout as - calling parameter, calling this function internally.} - function CanRead(Timeout: Integer): Boolean; virtual; - - {:Same as @link(CanRead), but additionally return @TRUE if is some data in - @link(LineBuffer).} - function CanReadEx(Timeout: Integer): Boolean; virtual; - - {:Return @TRUE, if you can to socket write any data (not full sending - buffer). Status is tested for time Timeout (in milliseconds). If value in - Timeout is 0, status is only tested and continue. If value in Timeout is - -1, run is breaked and waiting for write data maybe forever. - - This function is need only on special cases!} - function CanWrite(Timeout: Integer): Boolean; virtual; - - {:Same as @link(SendBuffer), but send datagram to address from - @link(RemoteSin). Usefull for sending reply to datagram received by - function @link(RecvBufferFrom).} - function SendBufferTo(Buffer: TMemory; Length: Integer): Integer; virtual; - - {:Note: This is low-lever receive function. You must be sure if data is - waiting for read before call this function for avoid deadlock! - - Receives first waiting datagram to allocated buffer. If there is no waiting - one, then waits until one comes. Returns length of datagram stored in - BUFFER. If length exceeds buffer datagram is truncated. After this - @link(RemoteSin) structure contains information about sender of UDP packet.} - function RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; virtual; -{$IFNDEF CIL} - {:This function is for check for incoming data on set of sockets. Whitch - sockets is checked is decribed by SocketList Tlist with TBlockSocket - objects. TList may have maximal number of objects defined by FD_SETSIZE - constant. Return @TRUE, if you can from some socket read any data or is - incoming connection on TCP based socket. Status is tested for time Timeout - (in milliseconds). If value in Timeout is 0, status is only tested and - continue. If value in Timeout is -1, run is breaked and waiting for read - data maybe forever. If is returned @TRUE, CanReadList TList is filled by all - TBlockSocket objects what waiting for read.} - function GroupCanRead(const SocketList: TList; Timeout: Integer; - const CanReadList: TList): Boolean; -{$ENDIF} - {:By this method you may turn address reuse mode for local @link(bind). It - is good specially for UDP protocol. Using this with TCP protocol is - hazardous!} - procedure EnableReuse(Value: Boolean); - - {:Try set timeout for all sending and receiving operations, if socket - provider can do it. (It not supported by all socket providers!)} - procedure SetTimeout(Timeout: Integer); - - {:Try set timeout for all sending operations, if socket provider can do it. - (It not supported by all socket providers!)} - procedure SetSendTimeout(Timeout: Integer); - - {:Try set timeout for all receiving operations, if socket provider can do - it. (It not supported by all socket providers!)} - procedure SetRecvTimeout(Timeout: Integer); - - {:Return value of socket type.} - function GetSocketType: integer; Virtual; - - {:Return value of protocol type for socket creation.} - function GetSocketProtocol: integer; Virtual; - - {:WSA structure with information about socket provider. On non-windows - platforms this structure is simulated!} - property WSAData: TWSADATA read GetWsaData; - - {:FDset structure prepared for usage with this socket.} - property FDset: TFDSet read FFDset; - - {:Structure describing local socket side.} - property LocalSin: TVarSin read FLocalSin write FLocalSin; - - {:Structure describing remote socket side.} - property RemoteSin: TVarSin read FRemoteSin write FRemoteSin; - - {:Socket handler. Suitable for "manual" calls to socket API or manual - connection of socket to a previously created socket (i.e by Accept method - on TCP socket)} - property Socket: TSocket read FSocket write SetSocket; - - {:Last socket operation error code. Error codes are described in socket - documentation. Human readable error description is stored in - @link(LastErrorDesc) property.} - property LastError: Integer read FLastError; - - {:Human readable error description of @link(LastError) code.} - property LastErrorDesc: string read FLastErrorDesc; - - {:Buffer used by all high-level receiving functions. This buffer is used for - optimized reading of data from socket. In normal cases you not need access - to this buffer directly!} - property LineBuffer: AnsiString read FBuffer write FBuffer; - - {:Size of Winsock receive buffer. If it is not supported by socket provider, - it return as size one kilobyte.} - property SizeRecvBuffer: Integer read GetSizeRecvBuffer write SetSizeRecvBuffer; - - {:Size of Winsock send buffer. If it is not supported by socket provider, it - return as size one kilobyte.} - property SizeSendBuffer: Integer read GetSizeSendBuffer write SetSizeSendBuffer; - - {:If @True, turn class to non-blocking mode. Not all functions are working - properly in this mode, you must know exactly what you are doing! However - when you have big experience with non-blocking programming, then you can - optimise your program by non-block mode!} - property NonBlockMode: Boolean read FNonBlockMode Write SetNonBlockMode; - - {:Set Time-to-live value. (if system supporting it!)} - property TTL: Integer read GetTTL Write SetTTL; - - {:If is @true, then class in in IPv6 mode.} - property IP6used: Boolean read FIP6used; - - {:Return count of received bytes on this socket from begin of current - connection.} - property RecvCounter: Integer read FRecvCounter; - - {:Return count of sended bytes on this socket from begin of current - connection.} - property SendCounter: Integer read FSendCounter; - published - {:Return descriptive string for given error code. This is class function. - You may call it without created object!} - class function GetErrorDesc(ErrorCode: Integer): string; - - {:Return descriptive string for @link(LastError).} - function GetErrorDescEx: string; virtual; - - {:this value is for free use.} - property Tag: Integer read FTag write FTag; - - {:If @true, winsock errors raises exception. Otherwise is setted - @link(LastError) value only and you must check it from your program! Default - value is @false.} - property RaiseExcept: Boolean read FRaiseExcept write FRaiseExcept; - - {:Define maximum length in bytes of @link(LineBuffer) for high-level - receiving functions. If this functions try to read more data then this - limit, error is returned! If value is 0 (default), no limitation is used. - This is very good protection for stupid attacks to your server by sending - lot of data without proper terminator... until all your memory is allocated - by LineBuffer! - - Note: This maximum length is checked only in functions, what read unknown - number of bytes! (like @link(RecvString) or @link(RecvTerminated))} - property MaxLineLength: Integer read FMaxLineLength Write FMaxLineLength; - - {:Define maximal bandwidth for all sending operations in bytes per second. - If value is 0 (default), bandwidth limitation is not used.} - property MaxSendBandwidth: Integer read FMaxSendBandwidth Write FMaxSendBandwidth; - - {:Define maximal bandwidth for all receiving operations in bytes per second. - If value is 0 (default), bandwidth limitation is not used.} - property MaxRecvBandwidth: Integer read FMaxRecvBandwidth Write FMaxRecvBandwidth; - - {:Define maximal bandwidth for all sending and receiving operations in bytes - per second. If value is 0 (default), bandwidth limitation is not used.} - property MaxBandwidth: Integer Write SetBandwidth; - - {:Do a conversion of non-standard line terminators to CRLF. (Off by default) - If @True, then terminators like sigle CR, single LF or LFCR are converted - to CRLF internally. This have effect only in @link(RecvString) method!} - property ConvertLineEnd: Boolean read FConvertLineEnd Write FConvertLineEnd; - - {:Specified Family of this socket. When you are using Windows preliminary - support for IPv6, then I recommend to set this property!} - property Family: TSocketFamily read FFamily Write SetFamily; - - {:When resolving of domain name return both IPv4 and IPv6 addresses, then - specify if is used IPv4 (dafault - @true) or IPv6.} - property PreferIP4: Boolean read FPreferIP4 Write FPreferIP4; - - {:By default (@true) is all timeouts used as timeout between two packets in - reading operations. If you set this to @false, then Timeouts is for overall - reading operation!} - property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout; - - {:All sended datas was splitted by this value.} - property SendMaxChunk: Integer read FSendMaxChunk Write FSendMaxChunk; - - {:By setting this property to @true you can stop any communication. You can - use this property for soft abort of communication.} - property StopFlag: Boolean read FStopFlag Write FStopFlag; - - {:Timeout for data sending by non-blocking socket mode.} - property NonblockSendTimeout: Integer read FNonblockSendTimeout Write FNonblockSendTimeout; - - {:Timeout for @link(Connect) call. Default value 0 means default system timeout. - Non-zero value means timeout in millisecond.} - property ConnectionTimeout: Integer read FConnectionTimeout write FConnectionTimeout; - - {:This event is called by various reasons. It is good for monitoring socket, - create gauges for data transfers, etc.} - property OnStatus: THookSocketStatus read FOnStatus write FOnStatus; - - {:this event is good for some internal thinks about filtering readed datas. - It is used by telnet client by example.} - property OnReadFilter: THookDataFilter read FOnReadFilter write FOnReadFilter; - - {:This event is called after real socket creation for setting special socket - options, because you not know when socket is created. (it is depended on - Ipv4, IPv6 or automatic mode)} - property OnCreateSocket: THookCreateSocket read FOnCreateSocket write FOnCreateSocket; - - {:This event is good for monitoring content of readed or writed datas.} - property OnMonitor: THookMonitor read FOnMonitor write FOnMonitor; - - {:This event is good for calling your code during long socket operations. - (Example, for refresing UI if class in not called within the thread.) - Rate of heartbeats can be modified by @link(HeartbeatRate) property.} - property OnHeartbeat: THookHeartbeat read FOnHeartbeat write FOnHeartbeat; - - {:Specify typical rate of @link(OnHeartbeat) event and @link(StopFlag) testing. - Default value 0 disabling heartbeats! Value is in milliseconds. - Real rate can be higher or smaller then this value, because it depending - on real socket operations too! - Note: Each heartbeat slowing socket processing.} - property HeartbeatRate: integer read FHeartbeatRate Write FHeartbeatRate; - {:What class own this socket? Used by protocol implementation classes.} - property Owner: TObject read FOwner Write FOwner; - end; - - {:@abstract(Support for SOCKS4 and SOCKS5 proxy) - Layer with definition all necessary properties and functions for - implementation SOCKS proxy client. Do not use this class directly.} - TSocksBlockSocket = class(TBlockSocket) - protected - FSocksIP: string; - FSocksPort: string; - FSocksTimeout: integer; - FSocksUsername: string; - FSocksPassword: string; - FUsingSocks: Boolean; - FSocksResolver: Boolean; - FSocksLastError: integer; - FSocksResponseIP: string; - FSocksResponsePort: string; - FSocksLocalIP: string; - FSocksLocalPort: string; - FSocksRemoteIP: string; - FSocksRemotePort: string; - FBypassFlag: Boolean; - FSocksType: TSocksType; - function SocksCode(IP, Port: string): Ansistring; - function SocksDecode(Value: Ansistring): integer; - public - constructor Create; - - {:Open connection to SOCKS proxy and if @link(SocksUsername) is set, do - authorisation to proxy. This is needed only in special cases! (it is called - internally!)} - function SocksOpen: Boolean; - - {:Send specified request to SOCKS proxy. This is needed only in special - cases! (it is called internally!)} - function SocksRequest(Cmd: Byte; const IP, Port: string): Boolean; - - {:Receive response to previosly sended request. This is needed only in - special cases! (it is called internally!)} - function SocksResponse: Boolean; - - {:Is @True when class is using SOCKS proxy.} - property UsingSocks: Boolean read FUsingSocks; - - {:If SOCKS proxy failed, here is error code returned from SOCKS proxy.} - property SocksLastError: integer read FSocksLastError; - published - {:Address of SOCKS server. If value is empty string, SOCKS support is - disabled. Assingning any value to this property enable SOCKS mode. - Warning: You cannot combine this mode with HTTP-tunneling mode!} - property SocksIP: string read FSocksIP write FSocksIP; - - {:Port of SOCKS server. Default value is '1080'.} - property SocksPort: string read FSocksPort write FSocksPort; - - {:If you need authorisation on SOCKS server, set username here.} - property SocksUsername: string read FSocksUsername write FSocksUsername; - - {:If you need authorisation on SOCKS server, set password here.} - property SocksPassword: string read FSocksPassword write FSocksPassword; - - {:Specify timeout for communicatin with SOCKS server. Default is one minute.} - property SocksTimeout: integer read FSocksTimeout write FSocksTimeout; - - {:If @True, all symbolic names of target hosts is not translated to IP's - locally, but resolving is by SOCKS proxy. Default is @True.} - property SocksResolver: Boolean read FSocksResolver write FSocksResolver; - - {:Specify SOCKS type. By default is used SOCKS5, but you can use SOCKS4 too. - When you select SOCKS4, then if @link(SOCKSResolver) is enabled, then is - used SOCKS4a. Othervise is used pure SOCKS4.} - property SocksType: TSocksType read FSocksType write FSocksType; - end; - - {:@abstract(Implementation of TCP socket.) - Supported features: IPv4, IPv6, SSL/TLS or SSH (depending on used plugin), - SOCKS5 proxy (outgoing connections and limited incomming), SOCKS4/4a proxy - (outgoing connections and limited incomming), TCP through HTTP proxy tunnel.} - TTCPBlockSocket = class(TSocksBlockSocket) - protected - FOnAfterConnect: THookAfterConnect; - FSSL: TCustomSSL; - FHTTPTunnelIP: string; - FHTTPTunnelPort: string; - FHTTPTunnel: Boolean; - FHTTPTunnelRemoteIP: string; - FHTTPTunnelRemotePort: string; - FHTTPTunnelUser: string; - FHTTPTunnelPass: string; - FHTTPTunnelTimeout: integer; - procedure SocksDoConnect(IP, Port: string); - procedure HTTPTunnelDoConnect(IP, Port: string); - procedure DoAfterConnect; - public - {:Create TCP socket class with default plugin for SSL/TSL/SSH implementation - (see @link(SSLImplementation))} - constructor Create; - - {:Create TCP socket class with desired plugin for SSL/TSL/SSH implementation} - constructor CreateWithSSL(SSLPlugin: TSSLClass); - destructor Destroy; override; - - {:See @link(TBlockSocket.CloseSocket)} - procedure CloseSocket; override; - - {:See @link(TBlockSocket.WaitingData)} - function WaitingData: Integer; override; - - {:Sets socket to receive mode for new incoming connections. It is necessary - to use @link(TBlockSocket.BIND) function call before this method to select - receiving port! - - If you use SOCKS, activate incoming TCP connection by this proxy. (By BIND - method of SOCKS.)} - procedure Listen; override; - - {:Waits until new incoming connection comes. After it comes a new socket is - automatically created (socket handler is returned by this function as - result). - - If you use SOCKS, new socket is not created! In this case is used same - socket as socket for listening! So, you can accept only one connection in - SOCKS mode.} - function Accept: TSocket; override; - - {:Connects socket to remote IP address and PORT. The same rules as with - @link(TBlockSocket.BIND) method are valid. The only exception is that PORT - with 0 value will not be connected. After call to this method - a communication channel between local and remote socket is created. Local - socket is assigned automatically if not controlled by previous call to - @link(TBlockSocket.BIND) method. Structures @link(TBlockSocket.LocalSin) - and @link(TBlockSocket.RemoteSin) will be filled with valid values. - - If you use SOCKS, activate outgoing TCP connection by SOCKS proxy specified - in @link(TSocksBlockSocket.SocksIP). (By CONNECT method of SOCKS.) - - If you use HTTP-tunnel mode, activate outgoing TCP connection by HTTP - tunnel specified in @link(HTTPTunnelIP). (By CONNECT method of HTTP - protocol.) - - Note: If you call this on non-created socket, then socket is created - automaticly.} - procedure Connect(IP, Port: string); override; - - {:If you need upgrade existing TCP connection to SSL/TLS (or SSH2, if plugin - allows it) mode, then call this method. This method switch this class to - SSL mode and do SSL/TSL handshake.} - procedure SSLDoConnect; - - {:By this method you can downgrade existing SSL/TLS connection to normal TCP - connection.} - procedure SSLDoShutdown; - - {:If you need use this component as SSL/TLS TCP server, then after accepting - of inbound connection you need start SSL/TLS session by this method. Before - call this function, you must have assigned all neeeded certificates and - keys!} - function SSLAcceptConnection: Boolean; - - {:See @link(TBlockSocket.GetLocalSinIP)} - function GetLocalSinIP: string; override; - - {:See @link(TBlockSocket.GetRemoteSinIP)} - function GetRemoteSinIP: string; override; - - {:See @link(TBlockSocket.GetLocalSinPort)} - function GetLocalSinPort: Integer; override; - - {:See @link(TBlockSocket.GetRemoteSinPort)} - function GetRemoteSinPort: Integer; override; - - {:See @link(TBlockSocket.SendBuffer)} - function SendBuffer(Buffer: TMemory; Length: Integer): Integer; override; - - {:See @link(TBlockSocket.RecvBuffer)} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - - {:Return value of socket type. For TCP return SOCK_STREAM.} - function GetSocketType: integer; override; - - {:Return value of protocol type for socket creation. For TCP return - IPPROTO_TCP.} - function GetSocketProtocol: integer; override; - - {:Class implementing SSL/TLS support. It is allways some descendant - of @link(TCustomSSL) class. When programmer not select some SSL plugin - class, then is used @link(TSSLNone)} - property SSL: TCustomSSL read FSSL; - - {:@True if is used HTTP tunnel mode.} - property HTTPTunnel: Boolean read FHTTPTunnel; - published - {:Return descriptive string for @link(LastError). On case of error - in SSL/TLS subsystem, it returns right error description.} - function GetErrorDescEx: string; override; - - {:Specify IP address of HTTP proxy. Assingning non-empty value to this - property enable HTTP-tunnel mode. This mode is for tunnelling any outgoing - TCP connection through HTTP proxy server. (If policy on HTTP proxy server - allow this!) Warning: You cannot combine this mode with SOCK5 mode!} - property HTTPTunnelIP: string read FHTTPTunnelIP Write FHTTPTunnelIP; - - {:Specify port of HTTP proxy for HTTP-tunneling.} - property HTTPTunnelPort: string read FHTTPTunnelPort Write FHTTPTunnelPort; - - {:Specify authorisation username for access to HTTP proxy in HTTP-tunnel - mode. If you not need authorisation, then let this property empty.} - property HTTPTunnelUser: string read FHTTPTunnelUser Write FHTTPTunnelUser; - - {:Specify authorisation password for access to HTTP proxy in HTTP-tunnel - mode.} - property HTTPTunnelPass: string read FHTTPTunnelPass Write FHTTPTunnelPass; - - {:Specify timeout for communication with HTTP proxy in HTTPtunnel mode.} - property HTTPTunnelTimeout: integer read FHTTPTunnelTimeout Write FHTTPTunnelTimeout; - - {:This event is called after sucessful TCP socket connection.} - property OnAfterConnect: THookAfterConnect read FOnAfterConnect write FOnAfterConnect; - end; - - {:@abstract(Datagram based communication) - This class implementing datagram based communication instead default stream - based communication style.} - TDgramBlockSocket = class(TSocksBlockSocket) - public - {:Fill @link(TBlockSocket.RemoteSin) structure. This address is used for - sending data.} - procedure Connect(IP, Port: string); override; - - {:Silently redirected to @link(TBlockSocket.SendBufferTo).} - function SendBuffer(Buffer: TMemory; Length: Integer): Integer; override; - - {:Silently redirected to @link(TBlockSocket.RecvBufferFrom).} - function RecvBuffer(Buffer: TMemory; Length: Integer): Integer; override; - end; - - {:@abstract(Implementation of UDP socket.) - NOTE: in this class is all receiving redirected to RecvBufferFrom. You can - use for reading any receive function. Preffered is RecvPacket! Similary all - sending is redirected to SendbufferTo. You can use for sending UDP packet any - sending function, like SendString. - - Supported features: IPv4, IPv6, unicasts, broadcasts, multicasts, SOCKS5 - proxy (only unicasts! Outgoing and incomming.)} - TUDPBlockSocket = class(TDgramBlockSocket) - protected - FSocksControlSock: TTCPBlockSocket; - function UdpAssociation: Boolean; - procedure SetMulticastTTL(TTL: integer); - function GetMulticastTTL:integer; - public - destructor Destroy; override; - - {:Enable or disable sending of broadcasts. If seting OK, result is @true. - This method is not supported in SOCKS5 mode! IPv6 does not support - broadcasts! In this case you must use Multicasts instead.} - procedure EnableBroadcast(Value: Boolean); - - {:See @link(TBlockSocket.SendBufferTo)} - function SendBufferTo(Buffer: TMemory; Length: Integer): Integer; override; - - {:See @link(TBlockSocket.RecvBufferFrom)} - function RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; override; -{$IFNDEF CIL} - {:Add this socket to given multicast group. You cannot use Multicasts in - SOCKS mode!} - procedure AddMulticast(MCastIP:string); - - {:Remove this socket from given multicast group.} - procedure DropMulticast(MCastIP:string); -{$ENDIF} - {:All sended multicast datagrams is loopbacked to your interface too. (you - can read your sended datas.) You can disable this feature by this function. - This function not working on some Windows systems!} - procedure EnableMulticastLoop(Value: Boolean); - - {:Return value of socket type. For UDP return SOCK_DGRAM.} - function GetSocketType: integer; override; - - {:Return value of protocol type for socket creation. For UDP return - IPPROTO_UDP.} - function GetSocketProtocol: integer; override; - - {:Set Time-to-live value for multicasts packets. It define number of routers - for transfer of datas. If you set this to 1 (dafault system value), then - multicasts packet goes only to you local network. If you need transport - multicast packet to worldwide, then increase this value, but be carefull, - lot of routers on internet does not transport multicasts packets!} - property MulticastTTL: Integer read GetMulticastTTL Write SetMulticastTTL; - end; - - {:@abstract(Implementation of RAW ICMP socket.) - For this object you must have rights for creating RAW sockets!} - TICMPBlockSocket = class(TDgramBlockSocket) - public - {:Return value of socket type. For RAW and ICMP return SOCK_RAW.} - function GetSocketType: integer; override; - - {:Return value of protocol type for socket creation. For ICMP returns - IPPROTO_ICMP or IPPROTO_ICMPV6} - function GetSocketProtocol: integer; override; - end; - - {:@abstract(Implementation of RAW socket.) - For this object you must have rights for creating RAW sockets!} - TRAWBlockSocket = class(TBlockSocket) - public - {:Return value of socket type. For RAW and ICMP return SOCK_RAW.} - function GetSocketType: integer; override; - - {:Return value of protocol type for socket creation. For RAW returns - IPPROTO_RAW.} - function GetSocketProtocol: integer; override; - end; - - {:@abstract(Implementation of PGM-message socket.) - Not all systems supports this protocol!} - TPGMMessageBlockSocket = class(TBlockSocket) - public - {:Return value of socket type. For PGM-message return SOCK_RDM.} - function GetSocketType: integer; override; - - {:Return value of protocol type for socket creation. For PGM-message returns - IPPROTO_RM.} - function GetSocketProtocol: integer; override; - end; - - {:@abstract(Implementation of PGM-stream socket.) - Not all systems supports this protocol!} - TPGMStreamBlockSocket = class(TBlockSocket) - public - {:Return value of socket type. For PGM-stream return SOCK_STREAM.} - function GetSocketType: integer; override; - - {:Return value of protocol type for socket creation. For PGM-stream returns - IPPROTO_RM.} - function GetSocketProtocol: integer; override; - end; - - {:@abstract(Parent class for all SSL plugins.) - This is abstract class defining interface for other SSL plugins. - - Instance of this class will be created for each @link(TTCPBlockSocket). - - Warning: not all methods and propertis can work in all existing SSL plugins! - Please, read documentation of used SSL plugin.} - TCustomSSL = class(TObject) - private - protected - FOnVerifyCert: THookVerifyCert; - FSocket: TTCPBlockSocket; - FSSLEnabled: Boolean; - FLastError: integer; - FLastErrorDesc: string; - FSSLType: TSSLType; - FKeyPassword: string; - FCiphers: string; - FCertificateFile: string; - FPrivateKeyFile: string; - FCertificate: Ansistring; - FPrivateKey: Ansistring; - FPFX: Ansistring; - FPFXfile: string; - FCertCA: Ansistring; - FCertCAFile: string; - FTrustCertificate: Ansistring; - FTrustCertificateFile: string; - FVerifyCert: Boolean; - FUsername: string; - FPassword: string; - FSSHChannelType: string; - FSSHChannelArg1: string; - FSSHChannelArg2: string; - FCertComplianceLevel: integer; - FSNIHost: string; - procedure ReturnError; - procedure SetCertCAFile(const Value: string); virtual; - function DoVerifyCert:boolean; - function CreateSelfSignedCert(Host: string): Boolean; virtual; - public - {: Create plugin class. it is called internally from @link(TTCPBlockSocket)} - constructor Create(const Value: TTCPBlockSocket); virtual; - - {: Assign settings (certificates and configuration) from another SSL plugin - class.} - procedure Assign(const Value: TCustomSSL); virtual; - - {: return description of used plugin. It usually return name and version - of used SSL library.} - function LibVersion: String; virtual; - - {: return name of used plugin.} - function LibName: String; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for start SSL connection.} - function Connect: boolean; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for acept new SSL connection.} - function Accept: boolean; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for hard shutdown of SSL connection. (for example, - before socket is closed)} - function Shutdown: boolean; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for soft shutdown of SSL connection. (for example, - when you need to continue with unprotected connection.)} - function BiShutdown: boolean; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for sending some datas by SSL connection.} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for receiving some datas by SSL connection.} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; virtual; - - {: Do not call this directly. It is used internally by @link(TTCPBlockSocket)! - - Here is needed code for getting count of datas what waiting for read. - If SSL plugin not allows this, then it should return 0.} - function WaitingData: Integer; virtual; - - {:Return string with identificator of SSL/TLS version of existing - connection.} - function GetSSLVersion: string; virtual; - - {:Return subject of remote SSL peer.} - function GetPeerSubject: string; virtual; - - {:Return Serial number if remote X509 certificate.} - function GetPeerSerialNo: integer; virtual; - - {:Return issuer certificate of remote SSL peer.} - function GetPeerIssuer: string; virtual; - - {:Return peer name from remote side certificate. This is good for verify, - if certificate is generated for remote side IP name.} - function GetPeerName: string; virtual; - - {:Returns has of peer name from remote side certificate. This is good - for fast remote side authentication.} - function GetPeerNameHash: cardinal; virtual; - - {:Return fingerprint of remote SSL peer.} - function GetPeerFingerprint: string; virtual; - - {:Return all detailed information about certificate from remote side of - SSL/TLS connection. Result string can be multilined! Each plugin can return - this informations in different format!} - function GetCertInfo: string; virtual; - - {:Return currently used Cipher.} - function GetCipherName: string; virtual; - - {:Return currently used number of bits in current Cipher algorythm.} - function GetCipherBits: integer; virtual; - - {:Return number of bits in current Cipher algorythm.} - function GetCipherAlgBits: integer; virtual; - - {:Return result value of verify remote side certificate. Look to OpenSSL - documentation for possible values. For example 0 is successfuly verified - certificate, or 18 is self-signed certificate.} - function GetVerifyCert: integer; virtual; - - {: Resurn @true if SSL mode is enabled on existing cvonnection.} - property SSLEnabled: Boolean read FSSLEnabled; - - {:Return error code of last SSL operation. 0 is OK.} - property LastError: integer read FLastError; - - {:Return error description of last SSL operation.} - property LastErrorDesc: string read FLastErrorDesc; - published - {:Here you can specify requested SSL/TLS mode. Default is autodetection, but - on some servers autodetection not working properly. In this case you must - specify requested SSL/TLS mode by your hand!} - property SSLType: TSSLType read FSSLType write FSSLType; - - {:Password for decrypting of encoded certificate or key.} - property KeyPassword: string read FKeyPassword write FKeyPassword; - - {:Username for possible credentials.} - property Username: string read FUsername write FUsername; - - {:password for possible credentials.} - property Password: string read FPassword write FPassword; - - {:By this property you can modify default set of SSL/TLS ciphers.} - property Ciphers: string read FCiphers write FCiphers; - - {:Used for loading certificate from disk file. See to plugin documentation - if this method is supported and how!} - property CertificateFile: string read FCertificateFile write FCertificateFile; - - {:Used for loading private key from disk file. See to plugin documentation - if this method is supported and how!} - property PrivateKeyFile: string read FPrivateKeyFile write FPrivateKeyFile; - - {:Used for loading certificate from binary string. See to plugin documentation - if this method is supported and how!} - property Certificate: Ansistring read FCertificate write FCertificate; - - {:Used for loading private key from binary string. See to plugin documentation - if this method is supported and how!} - property PrivateKey: Ansistring read FPrivateKey write FPrivateKey; - - {:Used for loading PFX from binary string. See to plugin documentation - if this method is supported and how!} - property PFX: Ansistring read FPFX write FPFX; - - {:Used for loading PFX from disk file. See to plugin documentation - if this method is supported and how!} - property PFXfile: string read FPFXfile write FPFXfile; - - {:Used for loading trusted certificates from disk file. See to plugin documentation - if this method is supported and how!} - property TrustCertificateFile: string read FTrustCertificateFile write FTrustCertificateFile; - - {:Used for loading trusted certificates from binary string. See to plugin documentation - if this method is supported and how!} - property TrustCertificate: Ansistring read FTrustCertificate write FTrustCertificate; - - {:Used for loading CA certificates from binary string. See to plugin documentation - if this method is supported and how!} - property CertCA: Ansistring read FCertCA write FCertCA; - - {:Used for loading CA certificates from disk file. See to plugin documentation - if this method is supported and how!} - property CertCAFile: string read FCertCAFile write SetCertCAFile; - - {:If @true, then is verified client certificate. (it is good for writing - SSL/TLS servers.) When you are not server, but you are client, then if this - property is @true, verify servers certificate.} - property VerifyCert: Boolean read FVerifyCert write FVerifyCert; - - {:channel type for possible SSH connections} - property SSHChannelType: string read FSSHChannelType write FSSHChannelType; - - {:First argument of channel type for possible SSH connections} - property SSHChannelArg1: string read FSSHChannelArg1 write FSSHChannelArg1; - - {:Second argument of channel type for possible SSH connections} - property SSHChannelArg2: string read FSSHChannelArg2 write FSSHChannelArg2; - - {: Level of standards compliance level - (CryptLib: values in cryptlib.pas, -1: use default value ) } - property CertComplianceLevel:integer read FCertComplianceLevel write FCertComplianceLevel; - - {:This event is called when verifying the server certificate immediatally after - a successfull verification in the ssl library.} - property OnVerifyCert: THookVerifyCert read FOnVerifyCert write FOnVerifyCert; - - {: Server Name Identification. Host name to send to server. If empty the host name - found in URL will be used, which should be the normal use (http Header Host = SNI Host). - The value is cleared after the connection is established. - (SNI support requires OpenSSL 0.9.8k or later. Cryptlib not supported, yet ) } - property SNIHost:string read FSNIHost write FSNIHost; - end; - - {:@abstract(Default SSL plugin with no SSL support.) - Dummy SSL plugin implementation for applications without SSL/TLS support.} - TSSLNone = class (TCustomSSL) - public - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - end; - - {:@abstract(Record with definition of IP packet header.) - For reading data from ICMP or RAW sockets.} - TIPHeader = record - VerLen: Byte; - TOS: Byte; - TotalLen: Word; - Identifer: Word; - FragOffsets: Word; - TTL: Byte; - Protocol: Byte; - CheckSum: Word; - SourceIp: LongWord; - DestIp: LongWord; - Options: LongWord; - end; - - {:@abstract(Parent class of application protocol implementations.) - By this class is defined common properties.} - TSynaClient = Class(TObject) - protected - FTargetHost: string; - FTargetPort: string; - FIPInterface: string; - FTimeout: integer; - FUserName: string; - FPassword: string; - public - constructor Create; - published - {:Specify terget server IP (or symbolic name). Default is 'localhost'.} - property TargetHost: string read FTargetHost Write FTargetHost; - - {:Specify terget server port (or symbolic name).} - property TargetPort: string read FTargetPort Write FTargetPort; - - {:Defined local socket address. (outgoing IP address). By default is used - '0.0.0.0' as wildcard for default IP.} - property IPInterface: string read FIPInterface Write FIPInterface; - - {:Specify default timeout for socket operations.} - property Timeout: integer read FTimeout Write FTimeout; - - {:If protocol need user authorization, then fill here username.} - property UserName: string read FUserName Write FUserName; - - {:If protocol need user authorization, then fill here password.} - property Password: string read FPassword Write FPassword; - end; - -var - {:Selected SSL plugin. Default is @link(TSSLNone). - - Do not change this value directly!!! - - Just add your plugin unit to your project uses instead. Each plugin unit have - initialization code what modify this variable.} - SSLImplementation: TSSLClass = TSSLNone; - -implementation - -{$IFDEF ONCEWINSOCK} -var - WsaDataOnce: TWSADATA; - e: ESynapseError; -{$ENDIF} - - -constructor TBlockSocket.Create; -begin - CreateAlternate(''); -end; - -constructor TBlockSocket.CreateAlternate(Stub: string); -{$IFNDEF ONCEWINSOCK} -var - e: ESynapseError; -{$ENDIF} -begin - inherited Create; - FDelayedOptions := TList.Create; - FRaiseExcept := False; -{$IFDEF RAISEEXCEPT} - FRaiseExcept := True; -{$ENDIF} - FSocket := INVALID_SOCKET; - FBuffer := ''; - FLastCR := False; - FLastLF := False; - FBinded := False; - FNonBlockMode := False; - FMaxLineLength := 0; - FMaxSendBandwidth := 0; - FNextSend := 0; - FMaxRecvBandwidth := 0; - FNextRecv := 0; - FConvertLineEnd := False; - FFamily := SF_Any; - FFamilySave := SF_Any; - FIP6used := False; - FPreferIP4 := True; - FInterPacketTimeout := True; - FRecvCounter := 0; - FSendCounter := 0; - FSendMaxChunk := c64k; - FStopFlag := False; - FNonblockSendTimeout := 15000; - FHeartbeatRate := 0; - FConnectionTimeout := 0; - FOwner := nil; -{$IFNDEF ONCEWINSOCK} - if Stub = '' then - Stub := DLLStackName; - if not InitSocketInterface(Stub) then - begin - e := ESynapseError.Create('Error loading Socket interface (' + Stub + ')!'); - e.ErrorCode := 0; - e.ErrorMessage := 'Error loading Socket interface (' + Stub + ')!'; - raise e; - end; - SockCheck(synsock.WSAStartup(WinsockLevel, FWsaDataOnce)); - ExceptCheck; -{$ENDIF} -end; - -destructor TBlockSocket.Destroy; -var - n: integer; - p: TSynaOption; -begin - CloseSocket; -{$IFNDEF ONCEWINSOCK} - synsock.WSACleanup; - DestroySocketInterface; -{$ENDIF} - for n := FDelayedOptions.Count - 1 downto 0 do - begin - p := TSynaOption(FDelayedOptions[n]); - p.Free; - end; - FDelayedOptions.Free; - inherited Destroy; -end; - -function TBlockSocket.FamilyToAF(f: TSocketFamily): TAddrFamily; -begin - case f of - SF_ip4: - Result := AF_INET; - SF_ip6: - Result := AF_INET6; - else - Result := AF_UNSPEC; - end; -end; - -procedure TBlockSocket.SetDelayedOption(const Value: TSynaOption); -var - li: TLinger; - x: integer; - buf: TMemory; -{$IFNDEF MSWINDOWS} - timeval: TTimeval; -{$ENDIF} -begin - case value.Option of - SOT_Linger: - begin - {$IFDEF CIL} - li := TLinger.Create(Value.Enabled, Value.Value div 1000); - synsock.SetSockOptObj(FSocket, integer(SOL_SOCKET), integer(SO_LINGER), li); - {$ELSE} - li.l_onoff := Ord(Value.Enabled); - li.l_linger := Value.Value div 1000; - buf := @li; - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_LINGER), buf, SizeOf(li)); - {$ENDIF} - end; - SOT_RecvBuff: - begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(value.Value); - {$ELSE} - buf := @Value.Value; - {$ENDIF} - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVBUF), - buf, SizeOf(Value.Value)); - end; - SOT_SendBuff: - begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(value.Value); - {$ELSE} - buf := @Value.Value; - {$ENDIF} - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDBUF), - buf, SizeOf(Value.Value)); - end; - SOT_NonBlock: - begin - FNonBlockMode := Value.Enabled; - x := Ord(FNonBlockMode); - synsock.IoctlSocket(FSocket, FIONBIO, x); - end; - SOT_RecvTimeout: - begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(value.Value); - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVTIMEO), - buf, SizeOf(Value.Value)); - {$ELSE} - {$IFDEF MSWINDOWS} - buf := @Value.Value; - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVTIMEO), - buf, SizeOf(Value.Value)); - {$ELSE} - timeval.tv_sec:=Value.Value div 1000; - timeval.tv_usec:=(Value.Value mod 1000) * 1000; - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVTIMEO), - @timeval, SizeOf(timeval)); - {$ENDIF} - {$ENDIF} - end; - SOT_SendTimeout: - begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(value.Value); - {$ELSE} - {$IFDEF MSWINDOWS} - buf := @Value.Value; - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDTIMEO), - buf, SizeOf(Value.Value)); - {$ELSE} - timeval.tv_sec:=Value.Value div 1000; - timeval.tv_usec:=(Value.Value mod 1000) * 1000; - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDTIMEO), - @timeval, SizeOf(timeval)); - {$ENDIF} - {$ENDIF} - end; - SOT_Reuse: - begin - x := Ord(Value.Enabled); - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(x); - {$ELSE} - buf := @x; - {$ENDIF} - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_REUSEADDR), buf, SizeOf(x)); - end; - SOT_TTL: - begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(value.Value); - {$ELSE} - buf := @Value.Value; - {$ENDIF} - if FIP6Used then - synsock.SetSockOpt(FSocket, integer(IPPROTO_IPV6), integer(IPV6_UNICAST_HOPS), - buf, SizeOf(Value.Value)) - else - synsock.SetSockOpt(FSocket, integer(IPPROTO_IP), integer(IP_TTL), - buf, SizeOf(Value.Value)); - end; - SOT_Broadcast: - begin -//#todo1 broadcasty na IP6 - x := Ord(Value.Enabled); - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(x); - {$ELSE} - buf := @x; - {$ENDIF} - synsock.SetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_BROADCAST), buf, SizeOf(x)); - end; - SOT_MulticastTTL: - begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(value.Value); - {$ELSE} - buf := @Value.Value; - {$ENDIF} - if FIP6Used then - synsock.SetSockOpt(FSocket, integer(IPPROTO_IPV6), integer(IPV6_MULTICAST_HOPS), - buf, SizeOf(Value.Value)) - else - synsock.SetSockOpt(FSocket, integer(IPPROTO_IP), integer(IP_MULTICAST_TTL), - buf, SizeOf(Value.Value)); - end; - SOT_MulticastLoop: - begin - x := Ord(Value.Enabled); - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(x); - {$ELSE} - buf := @x; - {$ENDIF} - if FIP6Used then - synsock.SetSockOpt(FSocket, integer(IPPROTO_IPV6), integer(IPV6_MULTICAST_LOOP), buf, SizeOf(x)) - else - synsock.SetSockOpt(FSocket, integer(IPPROTO_IP), integer(IP_MULTICAST_LOOP), buf, SizeOf(x)); - end; - end; - Value.free; -end; - -procedure TBlockSocket.DelayedOption(const Value: TSynaOption); -begin - if FSocket = INVALID_SOCKET then - begin - FDelayedOptions.Insert(0, Value); - end - else - SetDelayedOption(Value); -end; - -procedure TBlockSocket.ProcessDelayedOptions; -var - n: integer; - d: TSynaOption; -begin - for n := FDelayedOptions.Count - 1 downto 0 do - begin - d := TSynaOption(FDelayedOptions[n]); - SetDelayedOption(d); - end; - FDelayedOptions.Clear; -end; - -procedure TBlockSocket.SetSin(var Sin: TVarSin; IP, Port: string); -var - f: TSocketFamily; -begin - DoStatus(HR_ResolvingBegin, IP + ':' + Port); - ResetLastError; - //if socket exists, then use their type, else use users selection - f := SF_Any; - if (FSocket = INVALID_SOCKET) and (FFamily = SF_any) then - begin - if IsIP(IP) then - f := SF_IP4 - else - if IsIP6(IP) then - f := SF_IP6; - end - else - f := FFamily; - FLastError := synsock.SetVarSin(sin, ip, port, FamilyToAF(f), - GetSocketprotocol, GetSocketType, FPreferIP4); - DoStatus(HR_ResolvingEnd, GetSinIP(sin) + ':' + IntTostr(GetSinPort(sin))); -end; - -function TBlockSocket.GetSinIP(Sin: TVarSin): string; -begin - Result := synsock.GetSinIP(sin); -end; - -function TBlockSocket.GetSinPort(Sin: TVarSin): Integer; -begin - Result := synsock.GetSinPort(sin); -end; - -procedure TBlockSocket.CreateSocket; -var - sin: TVarSin; -begin - //dummy for SF_Any Family mode - ResetLastError; - if (FFamily <> SF_Any) and (FSocket = INVALID_SOCKET) then - begin - {$IFDEF CIL} - if FFamily = SF_IP6 then - sin := TVarSin.Create(IPAddress.Parse('::0'), 0) - else - sin := TVarSin.Create(IPAddress.Parse('0.0.0.0'), 0); - {$ELSE} - FillChar(Sin, Sizeof(Sin), 0); - if FFamily = SF_IP6 then - sin.sin_family := AF_INET6 - else - sin.sin_family := AF_INET; - {$ENDIF} - InternalCreateSocket(Sin); - end; -end; - -procedure TBlockSocket.CreateSocketByName(const Value: String); -var - sin: TVarSin; -begin - ResetLastError; - if FSocket = INVALID_SOCKET then - begin - SetSin(sin, value, '0'); - if FLastError = 0 then - InternalCreateSocket(Sin); - end; -end; - -procedure TBlockSocket.InternalCreateSocket(Sin: TVarSin); -begin - FStopFlag := False; - FRecvCounter := 0; - FSendCounter := 0; - ResetLastError; - if FSocket = INVALID_SOCKET then - begin - FBuffer := ''; - FBinded := False; - FIP6Used := Sin.AddressFamily = AF_INET6; - FSocket := synsock.Socket(integer(Sin.AddressFamily), GetSocketType, GetSocketProtocol); - if FSocket = INVALID_SOCKET then - FLastError := synsock.WSAGetLastError; - {$IFNDEF CIL} - FD_ZERO(FFDSet); - FD_SET(FSocket, FFDSet); - {$ENDIF} - ExceptCheck; - if FIP6used then - DoStatus(HR_SocketCreate, 'IPv6') - else - DoStatus(HR_SocketCreate, 'IPv4'); - ProcessDelayedOptions; - DoCreateSocket; - end; -end; - -procedure TBlockSocket.CloseSocket; -begin - AbortSocket; -end; - -procedure TBlockSocket.AbortSocket; -var - n: integer; - p: TSynaOption; -begin - if FSocket <> INVALID_SOCKET then - synsock.CloseSocket(FSocket); - FSocket := INVALID_SOCKET; - for n := FDelayedOptions.Count - 1 downto 0 do - begin - p := TSynaOption(FDelayedOptions[n]); - p.Free; - end; - FDelayedOptions.Clear; - FFamily := FFamilySave; - DoStatus(HR_SocketClose, ''); -end; - -procedure TBlockSocket.Bind(IP, Port: string); -var - Sin: TVarSin; -begin - ResetLastError; - if (FSocket <> INVALID_SOCKET) - or not((FFamily = SF_ANY) and (IP = cAnyHost) and (Port = cAnyPort)) then - begin - SetSin(Sin, IP, Port); - if FLastError = 0 then - begin - if FSocket = INVALID_SOCKET then - InternalCreateSocket(Sin); - SockCheck(synsock.Bind(FSocket, Sin)); - GetSinLocal; - FBuffer := ''; - FBinded := True; - end; - ExceptCheck; - DoStatus(HR_Bind, IP + ':' + Port); - end; -end; - -procedure TBlockSocket.Connect(IP, Port: string); -var - Sin: TVarSin; - b: boolean; -begin - SetSin(Sin, IP, Port); - if FLastError = 0 then - begin - if FSocket = INVALID_SOCKET then - InternalCreateSocket(Sin); - if FConnectionTimeout > 0 then - begin - // connect in non-blocking mode - b := NonBlockMode; - NonBlockMode := true; - SockCheck(synsock.Connect(FSocket, Sin)); - if (FLastError = WSAEINPROGRESS) OR (FLastError = WSAEWOULDBLOCK) then - if not CanWrite(FConnectionTimeout) then - FLastError := WSAETIMEDOUT; - NonBlockMode := b; - end - else - SockCheck(synsock.Connect(FSocket, Sin)); - if FLastError = 0 then - GetSins; - FBuffer := ''; - FLastCR := False; - FLastLF := False; - end; - ExceptCheck; - DoStatus(HR_Connect, IP + ':' + Port); -end; - -procedure TBlockSocket.Listen; -begin - SockCheck(synsock.Listen(FSocket, SOMAXCONN)); - GetSins; - ExceptCheck; - DoStatus(HR_Listen, ''); -end; - -function TBlockSocket.Accept: TSocket; -begin - Result := synsock.Accept(FSocket, FRemoteSin); -/// SockCheck(Result); - ExceptCheck; - DoStatus(HR_Accept, ''); -end; - -procedure TBlockSocket.GetSinLocal; -begin - synsock.GetSockName(FSocket, FLocalSin); -end; - -procedure TBlockSocket.GetSinRemote; -begin - synsock.GetPeerName(FSocket, FRemoteSin); -end; - -procedure TBlockSocket.GetSins; -begin - GetSinLocal; - GetSinRemote; -end; - -procedure TBlockSocket.SetBandwidth(Value: Integer); -begin - MaxSendBandwidth := Value; - MaxRecvBandwidth := Value; -end; - -procedure TBlockSocket.LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); -var - x: LongWord; - y: LongWord; - n: integer; -begin - if FStopFlag then - exit; - if MaxB > 0 then - begin - y := GetTick; - if Next > y then - begin - x := Next - y; - if x > 0 then - begin - DoStatus(HR_Wait, IntToStr(x)); - sleep(x mod 250); - for n := 1 to x div 250 do - if FStopFlag then - Break - else - sleep(250); - end; - end; - Next := GetTick + Trunc((Length / MaxB) * 1000); - end; -end; - -function TBlockSocket.TestStopFlag: Boolean; -begin - DoHeartbeat; - Result := FStopFlag; - if Result then - begin - FStopFlag := False; - FLastError := WSAECONNABORTED; - ExceptCheck; - end; -end; - - -function TBlockSocket.SendBuffer(Buffer: TMemory; Length: Integer): Integer; -{$IFNDEF CIL} -var - x, y: integer; - l, r: integer; - p: Pointer; -{$ENDIF} -begin - Result := 0; - if TestStopFlag then - Exit; - DoMonitor(True, Buffer, Length); -{$IFDEF CIL} - Result := synsock.Send(FSocket, Buffer, Length, 0); -{$ELSE} - l := Length; - x := 0; - while x < l do - begin - y := l - x; - if y > FSendMaxChunk then - y := FSendMaxChunk; - if y > 0 then - begin - LimitBandwidth(y, FMaxSendBandwidth, FNextsend); - p := IncPoint(Buffer, x); - r := synsock.Send(FSocket, p, y, MSG_NOSIGNAL); - SockCheck(r); - if FLastError = WSAEWOULDBLOCK then - begin - if CanWrite(FNonblockSendTimeout) then - begin - r := synsock.Send(FSocket, p, y, MSG_NOSIGNAL); - SockCheck(r); - end - else - FLastError := WSAETIMEDOUT; - end; - if FLastError <> 0 then - Break; - Inc(x, r); - Inc(Result, r); - Inc(FSendCounter, r); - DoStatus(HR_WriteCount, IntToStr(r)); - end - else - break; - end; -{$ENDIF} - ExceptCheck; -end; - -procedure TBlockSocket.SendByte(Data: Byte); -{$IFDEF CIL} -var - buf: TMemory; -{$ENDIF} -begin -{$IFDEF CIL} - setlength(buf, 1); - buf[0] := Data; - SendBuffer(buf, 1); -{$ELSE} - SendBuffer(@Data, 1); -{$ENDIF} -end; - -procedure TBlockSocket.SendString(Data: AnsiString); -var - buf: TMemory; -begin - {$IFDEF CIL} - buf := BytesOf(Data); - {$ELSE} - buf := Pointer(data); - {$ENDIF} - SendBuffer(buf, Length(Data)); -end; - -procedure TBlockSocket.SendInteger(Data: integer); -var - buf: TMemory; -begin - {$IFDEF CIL} - buf := System.BitConverter.GetBytes(Data); - {$ELSE} - buf := @Data; - {$ENDIF} - SendBuffer(buf, SizeOf(Data)); -end; - -procedure TBlockSocket.SendBlock(const Data: AnsiString); -var - i: integer; -begin - i := SwapBytes(Length(data)); - SendString(Codelongint(i) + Data); -end; - -procedure TBlockSocket.InternalSendStream(const Stream: TStream; WithSize, Indy: boolean); -var - l: integer; - yr: integer; - s: AnsiString; - b: boolean; -{$IFDEF CIL} - buf: TMemory; -{$ENDIF} -begin - b := true; - l := 0; - if WithSize then - begin - l := Stream.Size - Stream.Position;; - if not Indy then - l := synsock.HToNL(l); - end; - repeat - {$IFDEF CIL} - Setlength(buf, FSendMaxChunk); - yr := Stream.read(buf, FSendMaxChunk); - if yr > 0 then - begin - if WithSize and b then - begin - b := false; - SendString(CodeLongInt(l)); - end; - SendBuffer(buf, yr); - if FLastError <> 0 then - break; - end - {$ELSE} - Setlength(s, FSendMaxChunk); - yr := Stream.read(Pointer(s)^, FSendMaxChunk); - if yr > 0 then - begin - SetLength(s, yr); - if WithSize and b then - begin - b := false; - SendString(CodeLongInt(l) + s); - end - else - SendString(s); - if FLastError <> 0 then - break; - end - {$ENDIF} - until yr <= 0; -end; - -procedure TBlockSocket.SendStreamRaw(const Stream: TStream); -begin - InternalSendStream(Stream, false, false); -end; - -procedure TBlockSocket.SendStreamIndy(const Stream: TStream); -begin - InternalSendStream(Stream, true, true); -end; - -procedure TBlockSocket.SendStream(const Stream: TStream); -begin - InternalSendStream(Stream, true, false); -end; - -function TBlockSocket.RecvBuffer(Buffer: TMemory; Length: Integer): Integer; -begin - Result := 0; - if TestStopFlag then - Exit; - LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); -// Result := synsock.Recv(FSocket, Buffer^, Length, MSG_NOSIGNAL); - Result := synsock.Recv(FSocket, Buffer, Length, MSG_NOSIGNAL); - if Result = 0 then - FLastError := WSAECONNRESET - else - SockCheck(Result); - ExceptCheck; - if Result > 0 then - begin - Inc(FRecvCounter, Result); - DoStatus(HR_ReadCount, IntToStr(Result)); - DoMonitor(False, Buffer, Result); - DoReadFilter(Buffer, Result); - end; -end; - -function TBlockSocket.RecvBufferEx(Buffer: TMemory; Len: Integer; - Timeout: Integer): Integer; -var - s: AnsiString; - rl, l: integer; - ti: LongWord; -{$IFDEF CIL} - n: integer; - b: TMemory; -{$ENDIF} -begin - ResetLastError; - Result := 0; - if Len > 0 then - begin - rl := 0; - repeat - ti := GetTick; - s := RecvPacket(Timeout); - l := Length(s); - if (rl + l) > Len then - l := Len - rl; - {$IFDEF CIL} - b := BytesOf(s); - for n := 0 to l do - Buffer[rl + n] := b[n]; - {$ELSE} - Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); - {$ENDIF} - rl := rl + l; - if FLastError <> 0 then - Break; - if rl >= Len then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - FLastError := WSAETIMEDOUT; - Break; - end; - end; - until False; - delete(s, 1, l); - FBuffer := s; - Result := rl; - end; -end; - -function TBlockSocket.RecvBufferStr(Len: Integer; Timeout: Integer): AnsiString; -var - x: integer; -{$IFDEF CIL} - buf: Tmemory; -{$ENDIF} -begin - Result := ''; - if Len > 0 then - begin - {$IFDEF CIL} - Setlength(Buf, Len); - x := RecvBufferEx(buf, Len , Timeout); - if FLastError = 0 then - begin - SetLength(Buf, x); - Result := StringOf(buf); - end - else - Result := ''; - {$ELSE} - Setlength(Result, Len); - x := RecvBufferEx(Pointer(Result), Len , Timeout); - if FLastError = 0 then - SetLength(Result, x) - else - Result := ''; - {$ENDIF} - end; -end; - -function TBlockSocket.RecvPacket(Timeout: Integer): AnsiString; -var - x: integer; -{$IFDEF CIL} - buf: TMemory; -{$ENDIF} -begin - Result := ''; - ResetLastError; - if FBuffer <> '' then - begin - Result := FBuffer; - FBuffer := ''; - end - else - begin - {$IFDEF MSWINDOWS} - //not drain CPU on large downloads... - Sleep(0); - {$ENDIF} - x := WaitingData; - if x > 0 then - begin - {$IFDEF CIL} - SetLength(Buf, x); - x := RecvBuffer(Buf, x); - if x >= 0 then - begin - SetLength(Buf, x); - Result := StringOf(Buf); - end; - {$ELSE} - SetLength(Result, x); - x := RecvBuffer(Pointer(Result), x); - if x >= 0 then - SetLength(Result, x); - {$ENDIF} - end - else - begin - if CanRead(Timeout) then - begin - x := WaitingData; - if x = 0 then - FLastError := WSAECONNRESET; - if x > 0 then - begin - {$IFDEF CIL} - SetLength(Buf, x); - x := RecvBuffer(Buf, x); - if x >= 0 then - begin - SetLength(Buf, x); - result := StringOf(Buf); - end; - {$ELSE} - SetLength(Result, x); - x := RecvBuffer(Pointer(Result), x); - if x >= 0 then - SetLength(Result, x); - {$ENDIF} - end; - end - else - FLastError := WSAETIMEDOUT; - end; - end; - if FConvertLineEnd and (Result <> '') then - begin - if FLastCR and (Result[1] = LF) then - Delete(Result, 1, 1); - if FLastLF and (Result[1] = CR) then - Delete(Result, 1, 1); - FLastCR := False; - FLastLF := False; - end; - ExceptCheck; -end; - - -function TBlockSocket.RecvByte(Timeout: Integer): Byte; -begin - Result := 0; - ResetLastError; - if FBuffer = '' then - FBuffer := RecvPacket(Timeout); - if (FLastError = 0) and (FBuffer <> '') then - begin - Result := Ord(FBuffer[1]); - Delete(FBuffer, 1, 1); - end; - ExceptCheck; -end; - -function TBlockSocket.RecvInteger(Timeout: Integer): Integer; -var - s: AnsiString; -begin - Result := 0; - s := RecvBufferStr(4, Timeout); - if FLastError = 0 then - Result := (ord(s[1]) + ord(s[2]) * 256) + (ord(s[3]) + ord(s[4]) * 256) * 65536; -end; - -function TBlockSocket.RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; -var - x: Integer; - s: AnsiString; - l: Integer; - CorCRLF: Boolean; - t: AnsiString; - tl: integer; - ti: LongWord; -begin - ResetLastError; - Result := ''; - l := Length(Terminator); - if l = 0 then - Exit; - tl := l; - CorCRLF := FConvertLineEnd and (Terminator = CRLF); - s := ''; - x := 0; - repeat - //get rest of FBuffer or incomming new data... - ti := GetTick; - s := s + RecvPacket(Timeout); - if FLastError <> 0 then - Break; - x := 0; - if Length(s) > 0 then - if CorCRLF then - begin - t := ''; - x := PosCRLF(s, t); - tl := Length(t); - if t = CR then - FLastCR := True; - if t = LF then - FLastLF := True; - end - else - begin - x := pos(Terminator, s); - tl := l; - end; - if (FMaxLineLength <> 0) and (Length(s) > FMaxLineLength) then - begin - FLastError := WSAENOBUFS; - Break; - end; - if x > 0 then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - FLastError := WSAETIMEDOUT; - Break; - end; - end; - until False; - if x > 0 then - begin - Result := Copy(s, 1, x - 1); - Delete(s, 1, x + tl - 1); - end; - FBuffer := s; - ExceptCheck; -end; - -function TBlockSocket.RecvString(Timeout: Integer): AnsiString; -var - s: AnsiString; -begin - Result := ''; - s := RecvTerminated(Timeout, CRLF); - if FLastError = 0 then - Result := s; -end; - -function TBlockSocket.RecvBlock(Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - x := RecvInteger(Timeout); - if FLastError = 0 then - Result := RecvBufferStr(x, Timeout); -end; - -procedure TBlockSocket.RecvStreamRaw(const Stream: TStream; Timeout: Integer); -var - s: AnsiString; -begin - repeat - s := RecvPacket(Timeout); - if FLastError = 0 then - WriteStrToStream(Stream, s); - until FLastError <> 0; -end; - -procedure TBlockSocket.RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); -var - s: AnsiString; - n: integer; -{$IFDEF CIL} - buf: TMemory; -{$ENDIF} -begin - for n := 1 to (Size div FSendMaxChunk) do - begin - {$IFDEF CIL} - SetLength(buf, FSendMaxChunk); - RecvBufferEx(buf, FSendMaxChunk, Timeout); - if FLastError <> 0 then - Exit; - Stream.Write(buf, FSendMaxChunk); - {$ELSE} - s := RecvBufferStr(FSendMaxChunk, Timeout); - if FLastError <> 0 then - Exit; - WriteStrToStream(Stream, s); - {$ENDIF} - end; - n := Size mod FSendMaxChunk; - if n > 0 then - begin - {$IFDEF CIL} - SetLength(buf, n); - RecvBufferEx(buf, n, Timeout); - if FLastError <> 0 then - Exit; - Stream.Write(buf, n); - {$ELSE} - s := RecvBufferStr(n, Timeout); - if FLastError <> 0 then - Exit; - WriteStrToStream(Stream, s); - {$ENDIF} - end; -end; - -procedure TBlockSocket.RecvStreamIndy(const Stream: TStream; Timeout: Integer); -var - x: integer; -begin - x := RecvInteger(Timeout); - x := synsock.NToHL(x); - if FLastError = 0 then - RecvStreamSize(Stream, Timeout, x); -end; - -procedure TBlockSocket.RecvStream(const Stream: TStream; Timeout: Integer); -var - x: integer; -begin - x := RecvInteger(Timeout); - if FLastError = 0 then - RecvStreamSize(Stream, Timeout, x); -end; - -function TBlockSocket.PeekBuffer(Buffer: TMemory; Length: Integer): Integer; -begin - {$IFNDEF CIL} -// Result := synsock.Recv(FSocket, Buffer^, Length, MSG_PEEK + MSG_NOSIGNAL); - Result := synsock.Recv(FSocket, Buffer, Length, MSG_PEEK + MSG_NOSIGNAL); - SockCheck(Result); - ExceptCheck; - {$ENDIF} -end; - -function TBlockSocket.PeekByte(Timeout: Integer): Byte; -var - s: string; -begin - {$IFNDEF CIL} - Result := 0; - if CanRead(Timeout) then - begin - SetLength(s, 1); - PeekBuffer(Pointer(s), 1); - if s <> '' then - Result := Ord(s[1]); - end - else - FLastError := WSAETIMEDOUT; - ExceptCheck; - {$ENDIF} -end; - -procedure TBlockSocket.ResetLastError; -begin - FLastError := 0; - FLastErrorDesc := ''; -end; - -function TBlockSocket.SockCheck(SockResult: Integer): Integer; -begin - ResetLastError; - if SockResult = integer(SOCKET_ERROR) then - begin - FLastError := synsock.WSAGetLastError; - FLastErrorDesc := GetErrorDescEx; - end; - Result := FLastError; -end; - -procedure TBlockSocket.ExceptCheck; -var - e: ESynapseError; -begin - FLastErrorDesc := GetErrorDescEx; - if (LastError <> 0) and (LastError <> WSAEINPROGRESS) - and (LastError <> WSAEWOULDBLOCK) then - begin - DoStatus(HR_Error, IntToStr(FLastError) + ',' + FLastErrorDesc); - if FRaiseExcept then - begin - e := ESynapseError.Create(Format('Synapse TCP/IP Socket error %d: %s', - [FLastError, FLastErrorDesc])); - e.ErrorCode := FLastError; - e.ErrorMessage := FLastErrorDesc; - raise e; - end; - end; -end; - -function TBlockSocket.WaitingData: Integer; -var - x: Integer; -begin - Result := 0; - if synsock.IoctlSocket(FSocket, FIONREAD, x) = 0 then - Result := x; - if Result > c64k then - Result := c64k; -end; - -function TBlockSocket.WaitingDataEx: Integer; -begin - if FBuffer <> '' then - Result := Length(FBuffer) - else - Result := WaitingData; -end; - -procedure TBlockSocket.Purge; -begin - Sleep(1); - try - while (Length(FBuffer) > 0) or (WaitingData > 0) do - begin - RecvPacket(0); - if FLastError <> 0 then - break; - end; - except - on exception do; - end; - ResetLastError; -end; - -procedure TBlockSocket.SetLinger(Enable: Boolean; Linger: Integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_Linger; - d.Enabled := Enable; - d.Value := Linger; - DelayedOption(d); -end; - -function TBlockSocket.LocalName: string; -begin - Result := synsock.GetHostName; - if Result = '' then - Result := '127.0.0.1'; -end; - -procedure TBlockSocket.ResolveNameToIP(Name: string; const IPList: TStrings); -begin - IPList.Clear; - synsock.ResolveNameToIP(Name, FamilyToAF(FFamily), GetSocketprotocol, GetSocketType, IPList); - if IPList.Count = 0 then - IPList.Add(cAnyHost); -end; - -function TBlockSocket.ResolveName(Name: string): string; -var - l: TStringList; -begin - l := TStringList.Create; - try - ResolveNameToIP(Name, l); - Result := l[0]; - finally - l.Free; - end; -end; - -function TBlockSocket.ResolvePort(Port: string): Word; -begin - Result := synsock.ResolvePort(Port, FamilyToAF(FFamily), GetSocketProtocol, GetSocketType); -end; - -function TBlockSocket.ResolveIPToName(IP: string): string; -begin - if not IsIP(IP) and not IsIp6(IP) then - IP := ResolveName(IP); - Result := synsock.ResolveIPToName(IP, FamilyToAF(FFamily), GetSocketProtocol, GetSocketType); -end; - -procedure TBlockSocket.SetRemoteSin(IP, Port: string); -begin - SetSin(FRemoteSin, IP, Port); -end; - -function TBlockSocket.GetLocalSinIP: string; -begin - Result := GetSinIP(FLocalSin); -end; - -function TBlockSocket.GetRemoteSinIP: string; -begin - Result := GetSinIP(FRemoteSin); -end; - -function TBlockSocket.GetLocalSinPort: Integer; -begin - Result := GetSinPort(FLocalSin); -end; - -function TBlockSocket.GetRemoteSinPort: Integer; -begin - Result := GetSinPort(FRemoteSin); -end; - -function TBlockSocket.InternalCanRead(Timeout: Integer): Boolean; -{$IFDEF CIL} -begin - Result := FSocket.Poll(Timeout * 1000, SelectMode.SelectRead); -{$ELSE} -var - TimeVal: PTimeVal; - TimeV: TTimeVal; - x: Integer; - FDSet: TFDSet; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - FDSet := FFdSet; - x := synsock.Select(FSocket + 1, @FDSet, nil, nil, TimeVal); - SockCheck(x); - if FLastError <> 0 then - x := 0; - Result := x > 0; -{$ENDIF} -end; - -function TBlockSocket.CanRead(Timeout: Integer): Boolean; -var - ti, tr: Integer; - n: integer; -begin - if (FHeartbeatRate <> 0) and (Timeout <> -1) then - begin - ti := Timeout div FHeartbeatRate; - tr := Timeout mod FHeartbeatRate; - end - else - begin - ti := 0; - tr := Timeout; - end; - Result := InternalCanRead(tr); - if not Result then - for n := 0 to ti do - begin - DoHeartbeat; - if FStopFlag then - begin - Result := False; - FStopFlag := False; - Break; - end; - Result := InternalCanRead(FHeartbeatRate); - if Result then - break; - end; - ExceptCheck; - if Result then - DoStatus(HR_CanRead, ''); -end; - -function TBlockSocket.CanWrite(Timeout: Integer): Boolean; -{$IFDEF CIL} -begin - Result := FSocket.Poll(Timeout * 1000, SelectMode.SelectWrite); -{$ELSE} -var - TimeVal: PTimeVal; - TimeV: TTimeVal; - x: Integer; - FDSet: TFDSet; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - FDSet := FFdSet; - x := synsock.Select(FSocket + 1, nil, @FDSet, nil, TimeVal); - SockCheck(x); - if FLastError <> 0 then - x := 0; - Result := x > 0; -{$ENDIF} - ExceptCheck; - if Result then - DoStatus(HR_CanWrite, ''); -end; - -function TBlockSocket.CanReadEx(Timeout: Integer): Boolean; -begin - if FBuffer <> '' then - Result := True - else - Result := CanRead(Timeout); -end; - -function TBlockSocket.SendBufferTo(Buffer: TMemory; Length: Integer): Integer; -begin - Result := 0; - if TestStopFlag then - Exit; - DoMonitor(True, Buffer, Length); - LimitBandwidth(Length, FMaxSendBandwidth, FNextsend); - Result := synsock.SendTo(FSocket, Buffer, Length, MSG_NOSIGNAL, FRemoteSin); - SockCheck(Result); - ExceptCheck; - Inc(FSendCounter, Result); - DoStatus(HR_WriteCount, IntToStr(Result)); -end; - -function TBlockSocket.RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; -begin - Result := 0; - if TestStopFlag then - Exit; - LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); - Result := synsock.RecvFrom(FSocket, Buffer, Length, MSG_NOSIGNAL, FRemoteSin); - SockCheck(Result); - ExceptCheck; - Inc(FRecvCounter, Result); - DoStatus(HR_ReadCount, IntToStr(Result)); - DoMonitor(False, Buffer, Result); -end; - -function TBlockSocket.GetSizeRecvBuffer: Integer; -var - l: Integer; -{$IFDEF CIL} - buf: TMemory; -{$ENDIF} -begin -{$IFDEF CIL} - setlength(buf, 4); - SockCheck(synsock.GetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_RCVBUF), buf, l)); - Result := System.BitConverter.ToInt32(buf,0); -{$ELSE} - l := SizeOf(Result); - SockCheck(synsock.GetSockOpt(FSocket, SOL_SOCKET, SO_RCVBUF, @Result, l)); - if FLastError <> 0 then - Result := 1024; - ExceptCheck; -{$ENDIF} -end; - -procedure TBlockSocket.SetSizeRecvBuffer(Size: Integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_RecvBuff; - d.Value := Size; - DelayedOption(d); -end; - -function TBlockSocket.GetSizeSendBuffer: Integer; -var - l: Integer; -{$IFDEF CIL} - buf: TMemory; -{$ENDIF} -begin -{$IFDEF CIL} - setlength(buf, 4); - SockCheck(synsock.GetSockOpt(FSocket, integer(SOL_SOCKET), integer(SO_SNDBUF), buf, l)); - Result := System.BitConverter.ToInt32(buf,0); -{$ELSE} - l := SizeOf(Result); - SockCheck(synsock.GetSockOpt(FSocket, SOL_SOCKET, SO_SNDBUF, @Result, l)); - if FLastError <> 0 then - Result := 1024; - ExceptCheck; -{$ENDIF} -end; - -procedure TBlockSocket.SetSizeSendBuffer(Size: Integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_SendBuff; - d.Value := Size; - DelayedOption(d); -end; - -procedure TBlockSocket.SetNonBlockMode(Value: Boolean); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_nonblock; - d.Enabled := Value; - DelayedOption(d); -end; - -procedure TBlockSocket.SetTimeout(Timeout: Integer); -begin - SetSendTimeout(Timeout); - SetRecvTimeout(Timeout); -end; - -procedure TBlockSocket.SetSendTimeout(Timeout: Integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_sendtimeout; - d.Value := Timeout; - DelayedOption(d); -end; - -procedure TBlockSocket.SetRecvTimeout(Timeout: Integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_recvtimeout; - d.Value := Timeout; - DelayedOption(d); -end; - -{$IFNDEF CIL} -function TBlockSocket.GroupCanRead(const SocketList: TList; Timeout: Integer; - const CanReadList: TList): boolean; -var - FDSet: TFDSet; - TimeVal: PTimeVal; - TimeV: TTimeVal; - x, n: Integer; - Max: Integer; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - FD_ZERO(FDSet); - Max := 0; - for n := 0 to SocketList.Count - 1 do - if TObject(SocketList.Items[n]) is TBlockSocket then - begin - if TBlockSocket(SocketList.Items[n]).Socket > Max then - Max := TBlockSocket(SocketList.Items[n]).Socket; - FD_SET(TBlockSocket(SocketList.Items[n]).Socket, FDSet); - end; - x := synsock.Select(Max + 1, @FDSet, nil, nil, TimeVal); - SockCheck(x); - ExceptCheck; - if FLastError <> 0 then - x := 0; - Result := x > 0; - CanReadList.Clear; - if Result then - for n := 0 to SocketList.Count - 1 do - if TObject(SocketList.Items[n]) is TBlockSocket then - if FD_ISSET(TBlockSocket(SocketList.Items[n]).Socket, FDSet) then - CanReadList.Add(TBlockSocket(SocketList.Items[n])); -end; -{$ENDIF} - -procedure TBlockSocket.EnableReuse(Value: Boolean); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_reuse; - d.Enabled := Value; - DelayedOption(d); -end; - -procedure TBlockSocket.SetTTL(TTL: integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_TTL; - d.Value := TTL; - DelayedOption(d); -end; - -function TBlockSocket.GetTTL:integer; -var - l: Integer; -begin -{$IFNDEF CIL} - l := SizeOf(Result); - if FIP6Used then - synsock.GetSockOpt(FSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, @Result, l) - else - synsock.GetSockOpt(FSocket, IPPROTO_IP, IP_TTL, @Result, l); -{$ENDIF} -end; - -procedure TBlockSocket.SetFamily(Value: TSocketFamily); -begin - FFamily := Value; - FFamilySave := Value; -end; - -procedure TBlockSocket.SetSocket(Value: TSocket); -begin - FRecvCounter := 0; - FSendCounter := 0; - FSocket := Value; -{$IFNDEF CIL} - FD_ZERO(FFDSet); - FD_SET(FSocket, FFDSet); -{$ENDIF} - GetSins; - FIP6Used := FRemoteSin.AddressFamily = AF_INET6; -end; - -function TBlockSocket.GetWsaData: TWSAData; -begin - {$IFDEF ONCEWINSOCK} - Result := WsaDataOnce; - {$ELSE} - Result := FWsaDataOnce; - {$ENDIF} -end; - -function TBlockSocket.GetSocketType: integer; -begin - Result := 0; -end; - -function TBlockSocket.GetSocketProtocol: integer; -begin - Result := integer(IPPROTO_IP); -end; - -procedure TBlockSocket.DoStatus(Reason: THookSocketReason; const Value: string); -begin - if assigned(OnStatus) then - OnStatus(Self, Reason, Value); -end; - -procedure TBlockSocket.DoReadFilter(Buffer: TMemory; var Len: Integer); -var - s: AnsiString; -begin - if assigned(OnReadFilter) then - if Len > 0 then - begin - {$IFDEF CIL} - s := StringOf(Buffer); - {$ELSE} - SetLength(s, Len); - Move(Buffer^, Pointer(s)^, Len); - {$ENDIF} - OnReadFilter(Self, s); - if Length(s) > Len then - SetLength(s, Len); - Len := Length(s); - {$IFDEF CIL} - Buffer := BytesOf(s); - {$ELSE} - Move(Pointer(s)^, Buffer^, Len); - {$ENDIF} - end; -end; - -procedure TBlockSocket.DoCreateSocket; -begin - if assigned(OnCreateSocket) then - OnCreateSocket(Self); -end; - -procedure TBlockSocket.DoMonitor(Writing: Boolean; const Buffer: TMemory; Len: Integer); -begin - if assigned(OnMonitor) then - begin - OnMonitor(Self, Writing, Buffer, Len); - end; -end; - -procedure TBlockSocket.DoHeartbeat; -begin - if assigned(OnHeartbeat) and (FHeartbeatRate <> 0) then - begin - OnHeartbeat(Self); - end; -end; - -function TBlockSocket.GetErrorDescEx: string; -begin - Result := GetErrorDesc(FLastError); -end; - -class function TBlockSocket.GetErrorDesc(ErrorCode: Integer): string; -begin -{$IFDEF CIL} - if ErrorCode = 0 then - Result := '' - else - begin - Result := WSAGetLastErrorDesc; - if Result = '' then - Result := 'Other Winsock error (' + IntToStr(ErrorCode) + ')'; - end; -{$ELSE} - case ErrorCode of - 0: - Result := ''; - WSAEINTR: {10004} - Result := 'Interrupted system call'; - WSAEBADF: {10009} - Result := 'Bad file number'; - WSAEACCES: {10013} - Result := 'Permission denied'; - WSAEFAULT: {10014} - Result := 'Bad address'; - WSAEINVAL: {10022} - Result := 'Invalid argument'; - WSAEMFILE: {10024} - Result := 'Too many open files'; - WSAEWOULDBLOCK: {10035} - Result := 'Operation would block'; - WSAEINPROGRESS: {10036} - Result := 'Operation now in progress'; - WSAEALREADY: {10037} - Result := 'Operation already in progress'; - WSAENOTSOCK: {10038} - Result := 'Socket operation on nonsocket'; - WSAEDESTADDRREQ: {10039} - Result := 'Destination address required'; - WSAEMSGSIZE: {10040} - Result := 'Message too long'; - WSAEPROTOTYPE: {10041} - Result := 'Protocol wrong type for Socket'; - WSAENOPROTOOPT: {10042} - Result := 'Protocol not available'; - WSAEPROTONOSUPPORT: {10043} - Result := 'Protocol not supported'; - WSAESOCKTNOSUPPORT: {10044} - Result := 'Socket not supported'; - WSAEOPNOTSUPP: {10045} - Result := 'Operation not supported on Socket'; - WSAEPFNOSUPPORT: {10046} - Result := 'Protocol family not supported'; - WSAEAFNOSUPPORT: {10047} - Result := 'Address family not supported'; - WSAEADDRINUSE: {10048} - Result := 'Address already in use'; - WSAEADDRNOTAVAIL: {10049} - Result := 'Can''t assign requested address'; - WSAENETDOWN: {10050} - Result := 'Network is down'; - WSAENETUNREACH: {10051} - Result := 'Network is unreachable'; - WSAENETRESET: {10052} - Result := 'Network dropped connection on reset'; - WSAECONNABORTED: {10053} - Result := 'Software caused connection abort'; - WSAECONNRESET: {10054} - Result := 'Connection reset by peer'; - WSAENOBUFS: {10055} - Result := 'No Buffer space available'; - WSAEISCONN: {10056} - Result := 'Socket is already connected'; - WSAENOTCONN: {10057} - Result := 'Socket is not connected'; - WSAESHUTDOWN: {10058} - Result := 'Can''t send after Socket shutdown'; - WSAETOOMANYREFS: {10059} - Result := 'Too many references:can''t splice'; - WSAETIMEDOUT: {10060} - Result := 'Connection timed out'; - WSAECONNREFUSED: {10061} - Result := 'Connection refused'; - WSAELOOP: {10062} - Result := 'Too many levels of symbolic links'; - WSAENAMETOOLONG: {10063} - Result := 'File name is too long'; - WSAEHOSTDOWN: {10064} - Result := 'Host is down'; - WSAEHOSTUNREACH: {10065} - Result := 'No route to host'; - WSAENOTEMPTY: {10066} - Result := 'Directory is not empty'; - WSAEPROCLIM: {10067} - Result := 'Too many processes'; - WSAEUSERS: {10068} - Result := 'Too many users'; - WSAEDQUOT: {10069} - Result := 'Disk quota exceeded'; - WSAESTALE: {10070} - Result := 'Stale NFS file handle'; - WSAEREMOTE: {10071} - Result := 'Too many levels of remote in path'; - WSASYSNOTREADY: {10091} - Result := 'Network subsystem is unusable'; - WSAVERNOTSUPPORTED: {10092} - Result := 'Winsock DLL cannot support this application'; - WSANOTINITIALISED: {10093} - Result := 'Winsock not initialized'; - WSAEDISCON: {10101} - Result := 'Disconnect'; - WSAHOST_NOT_FOUND: {11001} - Result := 'Host not found'; - WSATRY_AGAIN: {11002} - Result := 'Non authoritative - host not found'; - WSANO_RECOVERY: {11003} - Result := 'Non recoverable error'; - WSANO_DATA: {11004} - Result := 'Valid name, no data record of requested type' - else - Result := 'Other Winsock error (' + IntToStr(ErrorCode) + ')'; - end; -{$ENDIF} -end; - -{======================================================================} - -constructor TSocksBlockSocket.Create; -begin - inherited Create; - FSocksIP:= ''; - FSocksPort:= '1080'; - FSocksTimeout:= 60000; - FSocksUsername:= ''; - FSocksPassword:= ''; - FUsingSocks := False; - FSocksResolver := True; - FSocksLastError := 0; - FSocksResponseIP := ''; - FSocksResponsePort := ''; - FSocksLocalIP := ''; - FSocksLocalPort := ''; - FSocksRemoteIP := ''; - FSocksRemotePort := ''; - FBypassFlag := False; - FSocksType := ST_Socks5; -end; - -function TSocksBlockSocket.SocksOpen: boolean; -var - Buf: AnsiString; - n: integer; -begin - Result := False; - FUsingSocks := False; - if FSocksType <> ST_Socks5 then - begin - FUsingSocks := True; - Result := True; - end - else - begin - FBypassFlag := True; - try - if FSocksUsername = '' then - Buf := #5 + #1 + #0 - else - Buf := #5 + #2 + #2 +#0; - SendString(Buf); - Buf := RecvBufferStr(2, FSocksTimeout); - if Length(Buf) < 2 then - Exit; - if Buf[1] <> #5 then - Exit; - n := Ord(Buf[2]); - case n of - 0: //not need authorisation - ; - 2: - begin - Buf := #1 + AnsiChar(Length(FSocksUsername)) + FSocksUsername - + AnsiChar(Length(FSocksPassword)) + FSocksPassword; - SendString(Buf); - Buf := RecvBufferStr(2, FSocksTimeout); - if Length(Buf) < 2 then - Exit; - if Buf[2] <> #0 then - Exit; - end; - else - //other authorisation is not supported! - Exit; - end; - FUsingSocks := True; - Result := True; - finally - FBypassFlag := False; - end; - end; -end; - -function TSocksBlockSocket.SocksRequest(Cmd: Byte; - const IP, Port: string): Boolean; -var - Buf: AnsiString; -begin - FBypassFlag := True; - try - if FSocksType <> ST_Socks5 then - Buf := #4 + AnsiChar(Cmd) + SocksCode(IP, Port) - else - Buf := #5 + AnsiChar(Cmd) + #0 + SocksCode(IP, Port); - SendString(Buf); - Result := FLastError = 0; - finally - FBypassFlag := False; - end; -end; - -function TSocksBlockSocket.SocksResponse: Boolean; -var - Buf, s: AnsiString; - x: integer; -begin - Result := False; - FBypassFlag := True; - try - FSocksResponseIP := ''; - FSocksResponsePort := ''; - FSocksLastError := -1; - if FSocksType <> ST_Socks5 then - begin - Buf := RecvBufferStr(8, FSocksTimeout); - if FLastError <> 0 then - Exit; - if Buf[1] <> #0 then - Exit; - FSocksLastError := Ord(Buf[2]); - end - else - begin - Buf := RecvBufferStr(4, FSocksTimeout); - if FLastError <> 0 then - Exit; - if Buf[1] <> #5 then - Exit; - case Ord(Buf[4]) of - 1: - s := RecvBufferStr(4, FSocksTimeout); - 3: - begin - x := RecvByte(FSocksTimeout); - if FLastError <> 0 then - Exit; - s := AnsiChar(x) + RecvBufferStr(x, FSocksTimeout); - end; - 4: - s := RecvBufferStr(16, FSocksTimeout); - else - Exit; - end; - Buf := Buf + s + RecvBufferStr(2, FSocksTimeout); - if FLastError <> 0 then - Exit; - FSocksLastError := Ord(Buf[2]); - end; - if ((FSocksLastError <> 0) and (FSocksLastError <> 90)) then - Exit; - SocksDecode(Buf); - Result := True; - finally - FBypassFlag := False; - end; -end; - -function TSocksBlockSocket.SocksCode(IP, Port: string): Ansistring; -var - ip6: TIp6Bytes; - n: integer; -begin - if FSocksType <> ST_Socks5 then - begin - Result := CodeInt(ResolvePort(Port)); - if not FSocksResolver then - IP := ResolveName(IP); - if IsIP(IP) then - begin - Result := Result + IPToID(IP); - Result := Result + FSocksUsername + #0; - end - else - begin - Result := Result + IPToID('0.0.0.1'); - Result := Result + FSocksUsername + #0; - Result := Result + IP + #0; - end; - end - else - begin - if not FSocksResolver then - IP := ResolveName(IP); - if IsIP(IP) then - Result := #1 + IPToID(IP) - else - if IsIP6(IP) then - begin - ip6 := StrToIP6(IP); - Result := #4; - for n := 0 to 15 do - Result := Result + AnsiChar(ip6[n]); - end - else - Result := #3 + AnsiChar(Length(IP)) + IP; - Result := Result + CodeInt(ResolvePort(Port)); - end; -end; - -function TSocksBlockSocket.SocksDecode(Value: Ansistring): integer; -var - Atyp: Byte; - y, n: integer; - w: Word; - ip6: TIp6Bytes; -begin - FSocksResponsePort := '0'; - Result := 0; - if FSocksType <> ST_Socks5 then - begin - if Length(Value) < 8 then - Exit; - Result := 3; - w := DecodeInt(Value, Result); - FSocksResponsePort := IntToStr(w); - FSocksResponseIP := Format('%d.%d.%d.%d', - [Ord(Value[5]), Ord(Value[6]), Ord(Value[7]), Ord(Value[8])]); - Result := 9; - end - else - begin - if Length(Value) < 4 then - Exit; - Atyp := Ord(Value[4]); - Result := 5; - case Atyp of - 1: - begin - if Length(Value) < 10 then - Exit; - FSocksResponseIP := Format('%d.%d.%d.%d', - [Ord(Value[5]), Ord(Value[6]), Ord(Value[7]), Ord(Value[8])]); - Result := 9; - end; - 3: - begin - y := Ord(Value[5]); - if Length(Value) < (5 + y + 2) then - Exit; - for n := 6 to 6 + y - 1 do - FSocksResponseIP := FSocksResponseIP + Value[n]; - Result := 5 + y + 1; - end; - 4: - begin - if Length(Value) < 22 then - Exit; - for n := 0 to 15 do - ip6[n] := ord(Value[n + 5]); - FSocksResponseIP := IP6ToStr(ip6); - Result := 21; - end; - else - Exit; - end; - w := DecodeInt(Value, Result); - FSocksResponsePort := IntToStr(w); - Result := Result + 2; - end; -end; - -{======================================================================} - -procedure TDgramBlockSocket.Connect(IP, Port: string); -begin - SetRemoteSin(IP, Port); - InternalCreateSocket(FRemoteSin); - FBuffer := ''; - DoStatus(HR_Connect, IP + ':' + Port); -end; - -function TDgramBlockSocket.RecvBuffer(Buffer: TMemory; Length: Integer): Integer; -begin - Result := RecvBufferFrom(Buffer, Length); -end; - -function TDgramBlockSocket.SendBuffer(Buffer: TMemory; Length: Integer): Integer; -begin - Result := SendBufferTo(Buffer, Length); -end; - -{======================================================================} - -destructor TUDPBlockSocket.Destroy; -begin - if Assigned(FSocksControlSock) then - FSocksControlSock.Free; - inherited; -end; - -procedure TUDPBlockSocket.EnableBroadcast(Value: Boolean); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_Broadcast; - d.Enabled := Value; - DelayedOption(d); -end; - -function TUDPBlockSocket.UdpAssociation: Boolean; -var - b: Boolean; -begin - Result := True; - FUsingSocks := False; - if FSocksIP <> '' then - begin - Result := False; - if not Assigned(FSocksControlSock) then - FSocksControlSock := TTCPBlockSocket.Create; - FSocksControlSock.CloseSocket; - FSocksControlSock.CreateSocketByName(FSocksIP); - FSocksControlSock.Connect(FSocksIP, FSocksPort); - if FSocksControlSock.LastError <> 0 then - Exit; - // if not assigned local port, assign it! - if not FBinded then - Bind(cAnyHost, cAnyPort); - //open control TCP connection to SOCKS - FSocksControlSock.FSocksUsername := FSocksUsername; - FSocksControlSock.FSocksPassword := FSocksPassword; - b := FSocksControlSock.SocksOpen; - if b then - b := FSocksControlSock.SocksRequest(3, GetLocalSinIP, IntToStr(GetLocalSinPort)); - if b then - b := FSocksControlSock.SocksResponse; - if not b and (FLastError = 0) then - FLastError := WSANO_RECOVERY; - FUsingSocks :=FSocksControlSock.UsingSocks; - FSocksRemoteIP := FSocksControlSock.FSocksResponseIP; - FSocksRemotePort := FSocksControlSock.FSocksResponsePort; - Result := b and (FLastError = 0); - end; -end; - -function TUDPBlockSocket.SendBufferTo(Buffer: TMemory; Length: Integer): Integer; -var - SIp: string; - SPort: integer; - Buf: Ansistring; -begin - Result := 0; - FUsingSocks := False; - if (FSocksIP <> '') and (not UdpAssociation) then - FLastError := WSANO_RECOVERY - else - begin - if FUsingSocks then - begin -{$IFNDEF CIL} - Sip := GetRemoteSinIp; - SPort := GetRemoteSinPort; - SetRemoteSin(FSocksRemoteIP, FSocksRemotePort); - SetLength(Buf,Length); - Move(Buffer^, Pointer(Buf)^, Length); - Buf := #0 + #0 + #0 + SocksCode(Sip, IntToStr(SPort)) + Buf; - Result := inherited SendBufferTo(Pointer(Buf), System.Length(buf)); - SetRemoteSin(Sip, IntToStr(SPort)); -{$ENDIF} - end - else - Result := inherited SendBufferTo(Buffer, Length); - end; -end; - -function TUDPBlockSocket.RecvBufferFrom(Buffer: TMemory; Length: Integer): Integer; -var - Buf: Ansistring; - x: integer; -begin - Result := inherited RecvBufferFrom(Buffer, Length); - if FUsingSocks then - begin -{$IFNDEF CIL} - SetLength(Buf, Result); - Move(Buffer^, Pointer(Buf)^, Result); - x := SocksDecode(Buf); - Result := Result - x + 1; - Buf := Copy(Buf, x, Result); - Move(Pointer(Buf)^, Buffer^, Result); - SetRemoteSin(FSocksResponseIP, FSocksResponsePort); -{$ENDIF} - end; -end; - -{$IFNDEF CIL} -procedure TUDPBlockSocket.AddMulticast(MCastIP: string); -var - Multicast: TIP_mreq; - Multicast6: TIPv6_mreq; - n: integer; - ip6: Tip6bytes; -begin - if FIP6Used then - begin - ip6 := StrToIp6(MCastIP); - for n := 0 to 15 do - Multicast6.ipv6mr_multiaddr.u6_addr8[n] := Ip6[n]; - Multicast6.ipv6mr_interface := 0; - SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IPV6, IPV6_JOIN_GROUP, - PAnsiChar(@Multicast6), SizeOf(Multicast6))); - end - else - begin - Multicast.imr_multiaddr.S_addr := swapbytes(strtoip(MCastIP)); -// Multicast.imr_interface.S_addr := INADDR_ANY; - Multicast.imr_interface.S_addr := FLocalSin.sin_addr.S_addr; - SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, - PAnsiChar(@Multicast), SizeOf(Multicast))); - end; - ExceptCheck; -end; - -procedure TUDPBlockSocket.DropMulticast(MCastIP: string); -var - Multicast: TIP_mreq; - Multicast6: TIPv6_mreq; - n: integer; - ip6: Tip6bytes; -begin - if FIP6Used then - begin - ip6 := StrToIp6(MCastIP); - for n := 0 to 15 do - Multicast6.ipv6mr_multiaddr.u6_addr8[n] := Ip6[n]; - Multicast6.ipv6mr_interface := 0; - SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, - PAnsiChar(@Multicast6), SizeOf(Multicast6))); - end - else - begin - Multicast.imr_multiaddr.S_addr := swapbytes(strtoip(MCastIP)); -// Multicast.imr_interface.S_addr := INADDR_ANY; - Multicast.imr_interface.S_addr := FLocalSin.sin_addr.S_addr; - SockCheck(synsock.SetSockOpt(FSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP, - PAnsiChar(@Multicast), SizeOf(Multicast))); - end; - ExceptCheck; -end; -{$ENDIF} - -procedure TUDPBlockSocket.SetMulticastTTL(TTL: integer); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_MulticastTTL; - d.Value := TTL; - DelayedOption(d); -end; - -function TUDPBlockSocket.GetMulticastTTL:integer; -var - l: Integer; -begin -{$IFNDEF CIL} - l := SizeOf(Result); - if FIP6Used then - synsock.GetSockOpt(FSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, @Result, l) - else - synsock.GetSockOpt(FSocket, IPPROTO_IP, IP_MULTICAST_TTL, @Result, l); -{$ENDIF} -end; - -procedure TUDPBlockSocket.EnableMulticastLoop(Value: Boolean); -var - d: TSynaOption; -begin - d := TSynaOption.Create; - d.Option := SOT_MulticastLoop; - d.Enabled := Value; - DelayedOption(d); -end; - -function TUDPBlockSocket.GetSocketType: integer; -begin - Result := integer(SOCK_DGRAM); -end; - -function TUDPBlockSocket.GetSocketProtocol: integer; -begin - Result := integer(IPPROTO_UDP); -end; - -{======================================================================} -constructor TTCPBlockSocket.CreateWithSSL(SSLPlugin: TSSLClass); -begin - inherited Create; - FSSL := SSLPlugin.Create(self); - FHTTPTunnelIP := ''; - FHTTPTunnelPort := ''; - FHTTPTunnel := False; - FHTTPTunnelRemoteIP := ''; - FHTTPTunnelRemotePort := ''; - FHTTPTunnelUser := ''; - FHTTPTunnelPass := ''; - FHTTPTunnelTimeout := 30000; -end; - -constructor TTCPBlockSocket.Create; -begin - CreateWithSSL(SSLImplementation); -end; - -destructor TTCPBlockSocket.Destroy; -begin - inherited Destroy; - FSSL.Free; -end; - -function TTCPBlockSocket.GetErrorDescEx: string; -begin - Result := inherited GetErrorDescEx; - if (FLastError = WSASYSNOTREADY) and (self.SSL.LastError <> 0) then - begin - Result := self.SSL.LastErrorDesc; - end; -end; - -procedure TTCPBlockSocket.CloseSocket; -begin - if FSSL.SSLEnabled then - FSSL.Shutdown; - if (FSocket <> INVALID_SOCKET) and (FLastError = 0) then - begin - Synsock.Shutdown(FSocket, 1); - Purge; - end; - inherited CloseSocket; -end; - -procedure TTCPBlockSocket.DoAfterConnect; -begin - if assigned(OnAfterConnect) then - begin - OnAfterConnect(Self); - end; -end; - -function TTCPBlockSocket.WaitingData: Integer; -begin - Result := 0; - if FSSL.SSLEnabled and (FSocket <> INVALID_SOCKET) then - Result := FSSL.WaitingData; - if Result = 0 then - Result := inherited WaitingData; -end; - -procedure TTCPBlockSocket.Listen; -var - b: Boolean; - Sip,SPort: string; -begin - if FSocksIP = '' then - begin - inherited Listen; - end - else - begin - Sip := GetLocalSinIP; - if Sip = cAnyHost then - Sip := LocalName; - SPort := IntToStr(GetLocalSinPort); - inherited Connect(FSocksIP, FSocksPort); - b := SocksOpen; - if b then - b := SocksRequest(2, Sip, SPort); - if b then - b := SocksResponse; - if not b and (FLastError = 0) then - FLastError := WSANO_RECOVERY; - FSocksLocalIP := FSocksResponseIP; - if FSocksLocalIP = cAnyHost then - FSocksLocalIP := FSocksIP; - FSocksLocalPort := FSocksResponsePort; - FSocksRemoteIP := ''; - FSocksRemotePort := ''; - ExceptCheck; - DoStatus(HR_Listen, ''); - end; -end; - -function TTCPBlockSocket.Accept: TSocket; -begin - if FUsingSocks then - begin - if not SocksResponse and (FLastError = 0) then - FLastError := WSANO_RECOVERY; - FSocksRemoteIP := FSocksResponseIP; - FSocksRemotePort := FSocksResponsePort; - Result := FSocket; - ExceptCheck; - DoStatus(HR_Accept, ''); - end - else - begin - result := inherited Accept; - end; -end; - -procedure TTCPBlockSocket.Connect(IP, Port: string); -begin - if FSocksIP <> '' then - SocksDoConnect(IP, Port) - else - if FHTTPTunnelIP <> '' then - HTTPTunnelDoConnect(IP, Port) - else - inherited Connect(IP, Port); - if FLasterror = 0 then - DoAfterConnect; -end; - -procedure TTCPBlockSocket.SocksDoConnect(IP, Port: string); -var - b: Boolean; -begin - inherited Connect(FSocksIP, FSocksPort); - if FLastError = 0 then - begin - b := SocksOpen; - if b then - b := SocksRequest(1, IP, Port); - if b then - b := SocksResponse; - if not b and (FLastError = 0) then - FLastError := WSASYSNOTREADY; - FSocksLocalIP := FSocksResponseIP; - FSocksLocalPort := FSocksResponsePort; - FSocksRemoteIP := IP; - FSocksRemotePort := Port; - end; - ExceptCheck; - DoStatus(HR_Connect, IP + ':' + Port); -end; - -procedure TTCPBlockSocket.HTTPTunnelDoConnect(IP, Port: string); -//bugfixed by Mike Green (mgreen@emixode.com) -var - s: string; -begin - Port := IntToStr(ResolvePort(Port)); - inherited Connect(FHTTPTunnelIP, FHTTPTunnelPort); - if FLastError <> 0 then - Exit; - FHTTPTunnel := False; - if IsIP6(IP) then - IP := '[' + IP + ']'; - SendString('CONNECT ' + IP + ':' + Port + ' HTTP/1.0' + CRLF); - if FHTTPTunnelUser <> '' then - Sendstring('Proxy-Authorization: Basic ' + - EncodeBase64(FHTTPTunnelUser + ':' + FHTTPTunnelPass) + CRLF); - SendString(CRLF); - repeat - s := RecvTerminated(FHTTPTunnelTimeout, #$0a); - if FLastError <> 0 then - Break; - if (Pos('HTTP/', s) = 1) and (Length(s) > 11) then - FHTTPTunnel := s[10] = '2'; - until (s = '') or (s = #$0d); - if (FLasterror = 0) and not FHTTPTunnel then - FLastError := WSAECONNREFUSED; - FHTTPTunnelRemoteIP := IP; - FHTTPTunnelRemotePort := Port; - ExceptCheck; -end; - -procedure TTCPBlockSocket.SSLDoConnect; -begin - ResetLastError; - if not FSSL.Connect then - FLastError := WSASYSNOTREADY; - ExceptCheck; -end; - -procedure TTCPBlockSocket.SSLDoShutdown; -begin - ResetLastError; - FSSL.BiShutdown; -end; - -function TTCPBlockSocket.GetLocalSinIP: string; -begin - if FUsingSocks then - Result := FSocksLocalIP - else - Result := inherited GetLocalSinIP; -end; - -function TTCPBlockSocket.GetRemoteSinIP: string; -begin - if FUsingSocks then - Result := FSocksRemoteIP - else - if FHTTPTunnel then - Result := FHTTPTunnelRemoteIP - else - Result := inherited GetRemoteSinIP; -end; - -function TTCPBlockSocket.GetLocalSinPort: Integer; -begin - if FUsingSocks then - Result := StrToIntDef(FSocksLocalPort, 0) - else - Result := inherited GetLocalSinPort; -end; - -function TTCPBlockSocket.GetRemoteSinPort: Integer; -begin - if FUsingSocks then - Result := ResolvePort(FSocksRemotePort) - else - if FHTTPTunnel then - Result := StrToIntDef(FHTTPTunnelRemotePort, 0) - else - Result := inherited GetRemoteSinPort; -end; - -function TTCPBlockSocket.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -begin - if FSSL.SSLEnabled then - begin - Result := 0; - if TestStopFlag then - Exit; - ResetLastError; - LimitBandwidth(Len, FMaxRecvBandwidth, FNextRecv); - Result := FSSL.RecvBuffer(Buffer, Len); - if FSSL.LastError <> 0 then - FLastError := WSASYSNOTREADY; - ExceptCheck; - Inc(FRecvCounter, Result); - DoStatus(HR_ReadCount, IntToStr(Result)); - DoMonitor(False, Buffer, Result); - DoReadFilter(Buffer, Result); - end - else - Result := inherited RecvBuffer(Buffer, Len); -end; - -function TTCPBlockSocket.SendBuffer(Buffer: TMemory; Length: Integer): Integer; -var - x, y: integer; - l, r: integer; -{$IFNDEF CIL} - p: Pointer; -{$ENDIF} -begin - if FSSL.SSLEnabled then - begin - Result := 0; - if TestStopFlag then - Exit; - ResetLastError; - DoMonitor(True, Buffer, Length); -{$IFDEF CIL} - Result := FSSL.SendBuffer(Buffer, Length); - if FSSL.LastError <> 0 then - FLastError := WSASYSNOTREADY; - Inc(FSendCounter, Result); - DoStatus(HR_WriteCount, IntToStr(Result)); -{$ELSE} - l := Length; - x := 0; - while x < l do - begin - y := l - x; - if y > FSendMaxChunk then - y := FSendMaxChunk; - if y > 0 then - begin - LimitBandwidth(y, FMaxSendBandwidth, FNextsend); - p := IncPoint(Buffer, x); - r := FSSL.SendBuffer(p, y); - if FSSL.LastError <> 0 then - FLastError := WSASYSNOTREADY; - if Flasterror <> 0 then - Break; - Inc(x, r); - Inc(Result, r); - Inc(FSendCounter, r); - DoStatus(HR_WriteCount, IntToStr(r)); - end - else - break; - end; -{$ENDIF} - ExceptCheck; - end - else - Result := inherited SendBuffer(Buffer, Length); -end; - -function TTCPBlockSocket.SSLAcceptConnection: Boolean; -begin - ResetLastError; - if not FSSL.Accept then - FLastError := WSASYSNOTREADY; - ExceptCheck; - Result := FLastError = 0; -end; - -function TTCPBlockSocket.GetSocketType: integer; -begin - Result := integer(SOCK_STREAM); -end; - -function TTCPBlockSocket.GetSocketProtocol: integer; -begin - Result := integer(IPPROTO_TCP); -end; - -{======================================================================} - -function TICMPBlockSocket.GetSocketType: integer; -begin - Result := integer(SOCK_RAW); -end; - -function TICMPBlockSocket.GetSocketProtocol: integer; -begin - if FIP6Used then - Result := integer(IPPROTO_ICMPV6) - else - Result := integer(IPPROTO_ICMP); -end; - -{======================================================================} - -function TRAWBlockSocket.GetSocketType: integer; -begin - Result := integer(SOCK_RAW); -end; - -function TRAWBlockSocket.GetSocketProtocol: integer; -begin - Result := integer(IPPROTO_RAW); -end; - -{======================================================================} - -function TPGMmessageBlockSocket.GetSocketType: integer; -begin - Result := integer(SOCK_RDM); -end; - -function TPGMmessageBlockSocket.GetSocketProtocol: integer; -begin - Result := integer(IPPROTO_RM); -end; - -{======================================================================} - -function TPGMstreamBlockSocket.GetSocketType: integer; -begin - Result := integer(SOCK_STREAM); -end; - -function TPGMstreamBlockSocket.GetSocketProtocol: integer; -begin - Result := integer(IPPROTO_RM); -end; - -{======================================================================} - -constructor TSynaClient.Create; -begin - inherited Create; - FIPInterface := cAnyHost; - FTargetHost := cLocalhost; - FTargetPort := cAnyPort; - FTimeout := 5000; - FUsername := ''; - FPassword := ''; -end; - -{======================================================================} - -constructor TCustomSSL.Create(const Value: TTCPBlockSocket); -begin - inherited Create; - FSocket := Value; - FSSLEnabled := False; - FUsername := ''; - FPassword := ''; - FLastError := 0; - FLastErrorDesc := ''; - FVerifyCert := False; - FSSLType := LT_all; - FKeyPassword := ''; - FCiphers := ''; - FCertificateFile := ''; - FPrivateKeyFile := ''; - FCertCAFile := ''; - FCertCA := ''; - FTrustCertificate := ''; - FTrustCertificateFile := ''; - FCertificate := ''; - FPrivateKey := ''; - FPFX := ''; - FPFXfile := ''; - FSSHChannelType := ''; - FSSHChannelArg1 := ''; - FSSHChannelArg2 := ''; - FCertComplianceLevel := -1; //default - FSNIHost := ''; -end; - -procedure TCustomSSL.Assign(const Value: TCustomSSL); -begin - FUsername := Value.Username; - FPassword := Value.Password; - FVerifyCert := Value.VerifyCert; - FSSLType := Value.SSLType; - FKeyPassword := Value.KeyPassword; - FCiphers := Value.Ciphers; - FCertificateFile := Value.CertificateFile; - FPrivateKeyFile := Value.PrivateKeyFile; - FCertCAFile := Value.CertCAFile; - FCertCA := Value.CertCA; - FTrustCertificate := Value.TrustCertificate; - FTrustCertificateFile := Value.TrustCertificateFile; - FCertificate := Value.Certificate; - FPrivateKey := Value.PrivateKey; - FPFX := Value.PFX; - FPFXfile := Value.PFXfile; - FCertComplianceLevel := Value.CertComplianceLevel; - FSNIHost := Value.FSNIHost; -end; - -procedure TCustomSSL.ReturnError; -begin - FLastError := -1; - FLastErrorDesc := 'SSL/TLS support is not compiled!'; -end; - -function TCustomSSL.LibVersion: String; -begin - Result := ''; -end; - -function TCustomSSL.LibName: String; -begin - Result := ''; -end; - -function TCustomSSL.CreateSelfSignedCert(Host: string): Boolean; -begin - Result := False; -end; - -function TCustomSSL.Connect: boolean; -begin - ReturnError; - Result := False; -end; - -function TCustomSSL.Accept: boolean; -begin - ReturnError; - Result := False; -end; - -function TCustomSSL.Shutdown: boolean; -begin - ReturnError; - Result := False; -end; - -function TCustomSSL.BiShutdown: boolean; -begin - ReturnError; - Result := False; -end; - -function TCustomSSL.SendBuffer(Buffer: TMemory; Len: Integer): Integer; -begin - ReturnError; - Result := integer(SOCKET_ERROR); -end; - -procedure TCustomSSL.SetCertCAFile(const Value: string); -begin - FCertCAFile := Value; -end; - -function TCustomSSL.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -begin - ReturnError; - Result := integer(SOCKET_ERROR); -end; - -function TCustomSSL.WaitingData: Integer; -begin - ReturnError; - Result := 0; -end; - -function TCustomSSL.GetSSLVersion: string; -begin - Result := ''; -end; - -function TCustomSSL.GetPeerSubject: string; -begin - Result := ''; -end; - -function TCustomSSL.GetPeerSerialNo: integer; -begin - Result := -1; -end; - -function TCustomSSL.GetPeerName: string; -begin - Result := ''; -end; - -function TCustomSSL.GetPeerNameHash: cardinal; -begin - Result := 0; -end; - -function TCustomSSL.GetPeerIssuer: string; -begin - Result := ''; -end; - -function TCustomSSL.GetPeerFingerprint: string; -begin - Result := ''; -end; - -function TCustomSSL.GetCertInfo: string; -begin - Result := ''; -end; - -function TCustomSSL.GetCipherName: string; -begin - Result := ''; -end; - -function TCustomSSL.GetCipherBits: integer; -begin - Result := 0; -end; - -function TCustomSSL.GetCipherAlgBits: integer; -begin - Result := 0; -end; - -function TCustomSSL.GetVerifyCert: integer; -begin - Result := 1; -end; - -function TCustomSSL.DoVerifyCert:boolean; -begin - if assigned(OnVerifyCert) then - begin - result:=OnVerifyCert(Self); - end - else - result:=true; -end; - - -{======================================================================} - -function TSSLNone.LibVersion: String; -begin - Result := 'Without SSL support'; -end; - -function TSSLNone.LibName: String; -begin - Result := 'ssl_none'; -end; - -{======================================================================} - -initialization -begin -{$IFDEF ONCEWINSOCK} - if not InitSocketInterface(DLLStackName) then - begin - e := ESynapseError.Create('Error loading Socket interface (' + DLLStackName + ')!'); - e.ErrorCode := 0; - e.ErrorMessage := 'Error loading Socket interface (' + DLLStackName + ')!'; - raise e; - end; - synsock.WSAStartup(WinsockLevel, WsaDataOnce); -{$ENDIF} -end; - -finalization -begin -{$IFDEF ONCEWINSOCK} - synsock.WSACleanup; - DestroySocketInterface; -{$ENDIF} -end; - -end. diff --git a/3rd/synapse/source/clamsend.pas b/3rd/synapse/source/clamsend.pas deleted file mode 100644 index 8d3c2d649..000000000 --- a/3rd/synapse/source/clamsend.pas +++ /dev/null @@ -1,277 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.001 | -|==============================================================================| -| Content: ClamAV-daemon client | -|==============================================================================| -| Copyright (c)2005-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2005-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract( ClamAV-daemon client) - -This unit is capable to do antivirus scan of your data by TCP channel to ClamD -daemon from ClamAV. See more about ClamAV on @LINK(http://www.clamav.net) -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit clamsend; - -interface - -uses - SysUtils, Classes, - synsock, blcksock, synautil; - -const - cClamProtocol = '3310'; - -type - - {:@abstract(Implementation of ClamAV-daemon client protocol) - By this class you can scan any your data by ClamAV opensource antivirus. - - This class can connect to ClamD by TCP channel, send your data to ClamD - and read result.} - TClamSend = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FDSock: TTCPBlockSocket; - FSession: boolean; - function Login: boolean; virtual; - function Logout: Boolean; virtual; - function OpenStream: Boolean; virtual; - public - constructor Create; - destructor Destroy; override; - - {:Call any command to ClamD. Used internally by other methods.} - function DoCommand(const Value: AnsiString): AnsiString; virtual; - - {:Return ClamAV version and version of loaded databases.} - function GetVersion: AnsiString; virtual; - - {:Scan content of TStrings.} - function ScanStrings(const Value: TStrings): AnsiString; virtual; - - {:Scan content of TStream.} - function ScanStream(const Value: TStream): AnsiString; virtual; - - {:Scan content of TStrings by new 0.95 API.} - function ScanStrings2(const Value: TStrings): AnsiString; virtual; - - {:Scan content of TStream by new 0.95 API.} - function ScanStream2(const Value: TStream): AnsiString; virtual; - published - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - - {:Socket object used for TCP data transfer operation. Good for seting OnStatus hook, etc.} - property DSock: TTCPBlockSocket read FDSock; - - {:Can turn-on session mode of communication with ClamD. Default is @false, - because ClamAV developers design their TCP code very badly and session mode - is broken now (CVS-20051031). Maybe ClamAV developers fix their bugs - and this mode will be possible in future.} - property Session: boolean read FSession write FSession; - end; - -implementation - -constructor TClamSend.Create; -begin - inherited Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FDSock := TTCPBlockSocket.Create; - FDSock.Owner := self; - FTimeout := 60000; - FTargetPort := cClamProtocol; - FSession := false; -end; - -destructor TClamSend.Destroy; -begin - Logout; - FDSock.Free; - FSock.Free; - inherited Destroy; -end; - -function TClamSend.DoCommand(const Value: AnsiString): AnsiString; -begin - Result := ''; - if not FSession then - FSock.CloseSocket - else - FSock.SendString(Value + LF); - if not FSession or (FSock.LastError <> 0) then - begin - if Login then - FSock.SendString(Value + LF) - else - Exit; - end; - Result := FSock.RecvTerminated(FTimeout, LF); -end; - -function TClamSend.Login: boolean; -begin - Result := False; - Sock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError <> 0 then - Exit; - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError <> 0 then - Exit; - if FSession then - FSock.SendString('SESSION' + LF); - Result := FSock.LastError = 0; -end; - -function TClamSend.Logout: Boolean; -begin - FSock.SendString('END' + LF); - Result := FSock.LastError = 0; - FSock.CloseSocket; -end; - -function TClamSend.GetVersion: AnsiString; -begin - Result := DoCommand('nVERSION'); -end; - -function TClamSend.OpenStream: Boolean; -var - S: AnsiString; -begin - Result := False; - s := DoCommand('nSTREAM'); - if (s <> '') and (Copy(s, 1, 4) = 'PORT') then - begin - s := SeparateRight(s, ' '); - FDSock.CloseSocket; - FDSock.Bind(FIPInterface, cAnyPort); - if FDSock.LastError <> 0 then - Exit; - FDSock.Connect(FTargetHost, s); - if FDSock.LastError <> 0 then - Exit; - Result := True; - end; -end; - -function TClamSend.ScanStrings(const Value: TStrings): AnsiString; -begin - Result := ''; - if OpenStream then - begin - DSock.SendString(Value.Text); - DSock.CloseSocket; - Result := FSock.RecvTerminated(FTimeout, LF); - end; -end; - -function TClamSend.ScanStream(const Value: TStream): AnsiString; -begin - Result := ''; - if OpenStream then - begin - DSock.SendStreamRaw(Value); - DSock.CloseSocket; - Result := FSock.RecvTerminated(FTimeout, LF); - end; -end; - -function TClamSend.ScanStrings2(const Value: TStrings): AnsiString; -var - i: integer; - s: AnsiString; -begin - Result := ''; - if not FSession then - FSock.CloseSocket - else - FSock.sendstring('nINSTREAM' + LF); - if not FSession or (FSock.LastError <> 0) then - begin - if Login then - FSock.sendstring('nINSTREAM' + LF) - else - Exit; - end; - s := Value.text; - i := length(s); - FSock.SendString(CodeLongint(i) + s + #0#0#0#0); - Result := FSock.RecvTerminated(FTimeout, LF); -end; - -function TClamSend.ScanStream2(const Value: TStream): AnsiString; -var - i: integer; -begin - Result := ''; - if not FSession then - FSock.CloseSocket - else - FSock.sendstring('nINSTREAM' + LF); - if not FSession or (FSock.LastError <> 0) then - begin - if Login then - FSock.sendstring('nINSTREAM' + LF) - else - Exit; - end; - i := value.Size; - FSock.SendString(CodeLongint(i)); - FSock.SendStreamRaw(Value); - FSock.SendString(#0#0#0#0); - Result := FSock.RecvTerminated(FTimeout, LF); -end; - -end. diff --git a/3rd/synapse/source/dnssend.pas b/3rd/synapse/source/dnssend.pas deleted file mode 100644 index 84c14cc76..000000000 --- a/3rd/synapse/source/dnssend.pas +++ /dev/null @@ -1,603 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.007.006 | -|==============================================================================| -| Content: DNS client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} -{: @abstract(DNS client by UDP or TCP) -Support for sending DNS queries by UDP or TCP protocol. It can retrieve zone - transfers too! - -Used RFC: RFC-1035, RFC-1183, RFC1706, RFC1712, RFC2163, RFC2230 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit dnssend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil, synaip, synsock; - -const - cDnsProtocol = '53'; - - QTYPE_A = 1; - QTYPE_NS = 2; - QTYPE_MD = 3; - QTYPE_MF = 4; - QTYPE_CNAME = 5; - QTYPE_SOA = 6; - QTYPE_MB = 7; - QTYPE_MG = 8; - QTYPE_MR = 9; - QTYPE_NULL = 10; - QTYPE_WKS = 11; // - QTYPE_PTR = 12; - QTYPE_HINFO = 13; - QTYPE_MINFO = 14; - QTYPE_MX = 15; - QTYPE_TXT = 16; - - QTYPE_RP = 17; - QTYPE_AFSDB = 18; - QTYPE_X25 = 19; - QTYPE_ISDN = 20; - QTYPE_RT = 21; - QTYPE_NSAP = 22; - QTYPE_NSAPPTR = 23; - QTYPE_SIG = 24; // RFC-2065 - QTYPE_KEY = 25; // RFC-2065 - QTYPE_PX = 26; - QTYPE_GPOS = 27; - QTYPE_AAAA = 28; - QTYPE_LOC = 29; // RFC-1876 - QTYPE_NXT = 30; // RFC-2065 - - QTYPE_SRV = 33; - QTYPE_NAPTR = 35; // RFC-2168 - QTYPE_KX = 36; - QTYPE_SPF = 99; - - QTYPE_AXFR = 252; - QTYPE_MAILB = 253; // - QTYPE_MAILA = 254; // - QTYPE_ALL = 255; - -type - {:@abstract(Implementation of DNS protocol by UDP or TCP protocol.) - - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TDNSSend = class(TSynaClient) - private - FID: Word; - FRCode: Integer; - FBuffer: AnsiString; - FSock: TUDPBlockSocket; - FTCPSock: TTCPBlockSocket; - FUseTCP: Boolean; - FAnswerInfo: TStringList; - FNameserverInfo: TStringList; - FAdditionalInfo: TStringList; - FAuthoritative: Boolean; - FTruncated: Boolean; - function CompressName(const Value: AnsiString): AnsiString; - function CodeHeader: AnsiString; - function CodeQuery(const Name: AnsiString; QType: Integer): AnsiString; - function DecodeLabels(var From: Integer): AnsiString; - function DecodeString(var From: Integer): AnsiString; - function DecodeResource(var i: Integer; const Info: TStringList; - QType: Integer): AnsiString; - function RecvTCPResponse(const WorkSock: TBlockSocket): AnsiString; - function DecodeResponse(const Buf: AnsiString; const Reply: TStrings; - QType: Integer):boolean; - public - constructor Create; - destructor Destroy; override; - - {:Query a DNSHost for QType resources correspond to a name. Supported QType - values are: Qtype_A, Qtype_NS, Qtype_MD, Qtype_MF, Qtype_CNAME, Qtype_SOA, - Qtype_MB, Qtype_MG, Qtype_MR, Qtype_NULL, Qtype_PTR, Qtype_HINFO, - Qtype_MINFO, Qtype_MX, Qtype_TXT, Qtype_RP, Qtype_AFSDB, Qtype_X25, - Qtype_ISDN, Qtype_RT, Qtype_NSAP, Qtype_NSAPPTR, Qtype_PX, Qtype_GPOS, - Qtype_KX. - - Type for zone transfers QTYPE_AXFR is supported too, but only in TCP mode! - - "Name" is domain name or host name for queried resource. If "name" is - IP address, automatically convert to reverse domain form (.in-addr.arpa). - - If result is @true, Reply contains resource records. One record on one line. - If Resource record have multiple fields, they are stored on line divided by - comma. (example: MX record contains value 'rs.cesnet.cz' with preference - number 10, string in Reply is: '10,rs.cesnet.cz'). All numbers or IP address - in resource are converted to string form.} - function DNSQuery(Name: AnsiString; QType: Integer; - const Reply: TStrings): Boolean; - published - - {:Socket object used for UDP operation. Good for seting OnStatus hook, etc.} - property Sock: TUDPBlockSocket read FSock; - - {:Socket object used for TCP operation. Good for seting OnStatus hook, etc.} - property TCPSock: TTCPBlockSocket read FTCPSock; - - {:if @true, then is used TCP protocol instead UDP. It is needed for zone - transfers, etc.} - property UseTCP: Boolean read FUseTCP Write FUseTCP; - - {:After DNS operation contains ResultCode of DNS operation. - Values are: 0-no error, 1-format error, 2-server failure, 3-name error, - 4-not implemented, 5-refused.} - property RCode: Integer read FRCode; - - {:@True, if answer is authoritative.} - property Authoritative: Boolean read FAuthoritative; - - {:@True, if answer is truncated to 512 bytes.} - property Truncated: Boolean read FTRuncated; - - {:Detailed informations from name server reply. One record per line. Record - have comma delimited entries with type number, TTL and data filelds. - This information contains detailed information about query reply.} - property AnswerInfo: TStringList read FAnswerInfo; - - {:Detailed informations from name server reply. One record per line. Record - have comma delimited entries with type number, TTL and data filelds. - This information contains detailed information about nameserver.} - property NameserverInfo: TStringList read FNameserverInfo; - - {:Detailed informations from name server reply. One record per line. Record - have comma delimited entries with type number, TTL and data filelds. - This information contains detailed additional information.} - property AdditionalInfo: TStringList read FAdditionalInfo; - end; - -{:A very useful function, and example of it's use is found in the TDNSSend object. - This function is used to get mail servers for a domain and sort them by - preference numbers. "Servers" contains only the domain names of the mail - servers in the right order (without preference number!). The first domain name - will always be the highest preferenced mail server. Returns boolean @TRUE if - all went well.} -function GetMailServers(const DNSHost, Domain: AnsiString; - const Servers: TStrings): Boolean; - -implementation - -constructor TDNSSend.Create; -begin - inherited Create; - FSock := TUDPBlockSocket.Create; - FSock.Owner := self; - FTCPSock := TTCPBlockSocket.Create; - FTCPSock.Owner := self; - FUseTCP := False; - FTimeout := 10000; - FTargetPort := cDnsProtocol; - FAnswerInfo := TStringList.Create; - FNameserverInfo := TStringList.Create; - FAdditionalInfo := TStringList.Create; - Randomize; -end; - -destructor TDNSSend.Destroy; -begin - FAnswerInfo.Free; - FNameserverInfo.Free; - FAdditionalInfo.Free; - FTCPSock.Free; - FSock.Free; - inherited Destroy; -end; - -function TDNSSend.CompressName(const Value: AnsiString): AnsiString; -var - n: Integer; - s: AnsiString; -begin - Result := ''; - if Value = '' then - Result := #0 - else - begin - s := ''; - for n := 1 to Length(Value) do - if Value[n] = '.' then - begin - Result := Result + AnsiChar(Length(s)) + s; - s := ''; - end - else - s := s + Value[n]; - if s <> '' then - Result := Result + AnsiChar(Length(s)) + s; - Result := Result + #0; - end; -end; - -function TDNSSend.CodeHeader: AnsiString; -begin - FID := Random(32767); - Result := CodeInt(FID); // ID - Result := Result + CodeInt($0100); // flags - Result := Result + CodeInt(1); // QDCount - Result := Result + CodeInt(0); // ANCount - Result := Result + CodeInt(0); // NSCount - Result := Result + CodeInt(0); // ARCount -end; - -function TDNSSend.CodeQuery(const Name: AnsiString; QType: Integer): AnsiString; -begin - Result := CompressName(Name); - Result := Result + CodeInt(QType); - Result := Result + CodeInt(1); // Type INTERNET -end; - -function TDNSSend.DecodeString(var From: Integer): AnsiString; -var - Len: integer; -begin - Len := Ord(FBuffer[From]); - Inc(From); - Result := Copy(FBuffer, From, Len); - Inc(From, Len); -end; - -function TDNSSend.DecodeLabels(var From: Integer): AnsiString; -var - l, f: Integer; -begin - Result := ''; - while True do - begin - if From >= Length(FBuffer) then - Break; - l := Ord(FBuffer[From]); - Inc(From); - if l = 0 then - Break; - if Result <> '' then - Result := Result + '.'; - if (l and $C0) = $C0 then - begin - f := l and $3F; - f := f * 256 + Ord(FBuffer[From]) + 1; - Inc(From); - Result := Result + DecodeLabels(f); - Break; - end - else - begin - Result := Result + Copy(FBuffer, From, l); - Inc(From, l); - end; - end; -end; - -function TDNSSend.DecodeResource(var i: Integer; const Info: TStringList; - QType: Integer): AnsiString; -var - Rname: AnsiString; - RType, Len, j, x, y, z, n: Integer; - R: AnsiString; - t1, t2, ttl: integer; - ip6: TIp6bytes; -begin - Result := ''; - R := ''; - Rname := DecodeLabels(i); - RType := DecodeInt(FBuffer, i); - Inc(i, 4); - t1 := DecodeInt(FBuffer, i); - Inc(i, 2); - t2 := DecodeInt(FBuffer, i); - Inc(i, 2); - ttl := t1 * 65536 + t2; - Len := DecodeInt(FBuffer, i); - Inc(i, 2); // i point to begin of data - j := i; - i := i + len; // i point to next record - if Length(FBuffer) >= (i - 1) then - case RType of - QTYPE_A: - begin - R := IntToStr(Ord(FBuffer[j])); - Inc(j); - R := R + '.' + IntToStr(Ord(FBuffer[j])); - Inc(j); - R := R + '.' + IntToStr(Ord(FBuffer[j])); - Inc(j); - R := R + '.' + IntToStr(Ord(FBuffer[j])); - end; - QTYPE_AAAA: - begin - for n := 0 to 15 do - ip6[n] := ord(FBuffer[j + n]); - R := IP6ToStr(ip6); - end; - QTYPE_NS, QTYPE_MD, QTYPE_MF, QTYPE_CNAME, QTYPE_MB, - QTYPE_MG, QTYPE_MR, QTYPE_PTR, QTYPE_X25, QTYPE_NSAP, - QTYPE_NSAPPTR: - R := DecodeLabels(j); - QTYPE_SOA: - begin - R := DecodeLabels(j); - R := R + ',' + DecodeLabels(j); - for n := 1 to 5 do - begin - x := DecodeInt(FBuffer, j) * 65536 + DecodeInt(FBuffer, j + 2); - Inc(j, 4); - R := R + ',' + IntToStr(x); - end; - end; - QTYPE_NULL: - begin - end; - QTYPE_WKS: - begin - end; - QTYPE_HINFO: - begin - R := DecodeString(j); - R := R + ',' + DecodeString(j); - end; - QTYPE_MINFO, QTYPE_RP, QTYPE_ISDN: - begin - R := DecodeLabels(j); - R := R + ',' + DecodeLabels(j); - end; - QTYPE_MX, QTYPE_AFSDB, QTYPE_RT, QTYPE_KX: - begin - x := DecodeInt(FBuffer, j); - Inc(j, 2); - R := IntToStr(x); - R := R + ',' + DecodeLabels(j); - end; - QTYPE_TXT, QTYPE_SPF: - begin - R := ''; - while j < i do - R := R + DecodeString(j); - end; - QTYPE_GPOS: - begin - R := DecodeLabels(j); - R := R + ',' + DecodeLabels(j); - R := R + ',' + DecodeLabels(j); - end; - QTYPE_PX: - begin - x := DecodeInt(FBuffer, j); - Inc(j, 2); - R := IntToStr(x); - R := R + ',' + DecodeLabels(j); - R := R + ',' + DecodeLabels(j); - end; - QTYPE_SRV: - // Author: Dan <ml@mutox.org> - begin - x := DecodeInt(FBuffer, j); - Inc(j, 2); - y := DecodeInt(FBuffer, j); - Inc(j, 2); - z := DecodeInt(FBuffer, j); - Inc(j, 2); - R := IntToStr(x); // Priority - R := R + ',' + IntToStr(y); // Weight - R := R + ',' + IntToStr(z); // Port - R := R + ',' + DecodeLabels(j); // Server DNS Name - end; - end; - if R <> '' then - Info.Add(RName + ',' + IntToStr(RType) + ',' + IntToStr(ttl) + ',' + R); - if QType = RType then - Result := R; -end; - -function TDNSSend.RecvTCPResponse(const WorkSock: TBlockSocket): AnsiString; -var - l: integer; -begin - Result := ''; - l := WorkSock.recvbyte(FTimeout) * 256 + WorkSock.recvbyte(FTimeout); - if l > 0 then - Result := WorkSock.RecvBufferStr(l, FTimeout); -end; - -function TDNSSend.DecodeResponse(const Buf: AnsiString; const Reply: TStrings; - QType: Integer):boolean; -var - n, i: Integer; - flag, qdcount, ancount, nscount, arcount: Integer; - s: AnsiString; -begin - Result := False; - Reply.Clear; - FAnswerInfo.Clear; - FNameserverInfo.Clear; - FAdditionalInfo.Clear; - FAuthoritative := False; - if (Length(Buf) > 13) and (FID = DecodeInt(Buf, 1)) then - begin - Result := True; - flag := DecodeInt(Buf, 3); - FRCode := Flag and $000F; - FAuthoritative := (Flag and $0400) > 0; - FTruncated := (Flag and $0200) > 0; - if FRCode = 0 then - begin - qdcount := DecodeInt(Buf, 5); - ancount := DecodeInt(Buf, 7); - nscount := DecodeInt(Buf, 9); - arcount := DecodeInt(Buf, 11); - i := 13; //begin of body - if (qdcount > 0) and (Length(Buf) > i) then //skip questions - for n := 1 to qdcount do - begin - while (Buf[i] <> #0) and ((Ord(Buf[i]) and $C0) <> $C0) do - Inc(i); - Inc(i, 5); - end; - if (ancount > 0) and (Length(Buf) > i) then // decode reply - for n := 1 to ancount do - begin - s := DecodeResource(i, FAnswerInfo, QType); - if s <> '' then - Reply.Add(s); - end; - if (nscount > 0) and (Length(Buf) > i) then // decode nameserver info - for n := 1 to nscount do - DecodeResource(i, FNameserverInfo, QType); - if (arcount > 0) and (Length(Buf) > i) then // decode additional info - for n := 1 to arcount do - DecodeResource(i, FAdditionalInfo, QType); - end; - end; -end; - -function TDNSSend.DNSQuery(Name: AnsiString; QType: Integer; - const Reply: TStrings): Boolean; -var - WorkSock: TBlockSocket; - t: TStringList; - b: boolean; -begin - Result := False; - if IsIP(Name) then - Name := ReverseIP(Name) + '.in-addr.arpa'; - if IsIP6(Name) then - Name := ReverseIP6(Name) + '.ip6.arpa'; - FBuffer := CodeHeader + CodeQuery(Name, QType); - if FUseTCP then - WorkSock := FTCPSock - else - WorkSock := FSock; - WorkSock.Bind(FIPInterface, cAnyPort); - WorkSock.Connect(FTargetHost, FTargetPort); - if FUseTCP then - FBuffer := Codeint(length(FBuffer)) + FBuffer; - WorkSock.SendString(FBuffer); - if FUseTCP then - FBuffer := RecvTCPResponse(WorkSock) - else - FBuffer := WorkSock.RecvPacket(FTimeout); - if FUseTCP and (QType = QTYPE_AXFR) then //zone transfer - begin - t := TStringList.Create; - try - repeat - b := DecodeResponse(FBuffer, Reply, QType); - if (t.Count > 1) and (AnswerInfo.Count > 0) then //find end of transfer - b := b and (t[0] <> AnswerInfo[AnswerInfo.count - 1]); - if b then - begin - t.AddStrings(AnswerInfo); - FBuffer := RecvTCPResponse(WorkSock); - if FBuffer = '' then - Break; - if WorkSock.LastError <> 0 then - Break; - end; - until not b; - Reply.Assign(t); - Result := True; - finally - t.free; - end; - end - else //normal query - if WorkSock.LastError = 0 then - Result := DecodeResponse(FBuffer, Reply, QType); -end; - -{==============================================================================} - -function GetMailServers(const DNSHost, Domain: AnsiString; - const Servers: TStrings): Boolean; -var - DNS: TDNSSend; - t: TStringList; - n, m, x: Integer; -begin - Result := False; - Servers.Clear; - t := TStringList.Create; - DNS := TDNSSend.Create; - try - DNS.TargetHost := DNSHost; - if DNS.DNSQuery(Domain, QType_MX, t) then - begin - { normalize preference number to 5 digits } - for n := 0 to t.Count - 1 do - begin - x := Pos(',', t[n]); - if x > 0 then - for m := 1 to 6 - x do - t[n] := '0' + t[n]; - end; - { sort server list } - t.Sorted := True; - { result is sorted list without preference numbers } - for n := 0 to t.Count - 1 do - begin - x := Pos(',', t[n]); - Servers.Add(Copy(t[n], x + 1, Length(t[n]) - x)); - end; - Result := True; - end; - finally - DNS.Free; - t.Free; - end; -end; - -end. diff --git a/3rd/synapse/source/ftpsend.pas b/3rd/synapse/source/ftpsend.pas deleted file mode 100644 index 0d3683500..000000000 --- a/3rd/synapse/source/ftpsend.pas +++ /dev/null @@ -1,1964 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 004.000.000 | -|==============================================================================| -| Content: FTP client | -|==============================================================================| -| Copyright (c)1999-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Petr Esner <petr.esner@atlas.cz> | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(FTP client protocol) - -Used RFC: RFC-959, RFC-2228, RFC-2428 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$TYPEINFO ON}// Borland changed defualt Visibility from Public to Published - // and it requires RTTI to be generated $M+ -{$M+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit ftpsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil, synaip, synsock; - -const - cFtpProtocol = '21'; - cFtpDataProtocol = '20'; - - {:Terminating value for TLogonActions} - FTP_OK = 255; - {:Terminating value for TLogonActions} - FTP_ERR = 254; - -type - {:Array for holding definition of logon sequence.} - TLogonActions = array [0..17] of byte; - - {:Procedural type for OnStatus event. Sender is calling @link(TFTPSend) object. - Value is FTP command or reply to this comand. (if it is reply, Response - is @True).} - TFTPStatus = procedure(Sender: TObject; Response: Boolean; - const Value: string) of object; - - {: @abstract(Object for holding file information) parsed from directory - listing of FTP server.} - TFTPListRec = class(TObject) - private - FFileName: String; - FDirectory: Boolean; - FReadable: Boolean; - FFileSize: int64; - FFileTime: TDateTime; - FOriginalLine: string; - FMask: string; - FPermission: String; - public - {: You can assign another TFTPListRec to this object.} - procedure Assign(Value: TFTPListRec); virtual; - {:name of file} - property FileName: string read FFileName write FFileName; - {:if name is subdirectory not file.} - property Directory: Boolean read FDirectory write FDirectory; - {:if you have rights to read} - property Readable: Boolean read FReadable write FReadable; - {:size of file in bytes} - property FileSize: int64 read FFileSize write FFileSize; - {:date and time of file. Local server timezone is used. Any timezone - conversions was not done!} - property FileTime: TDateTime read FFileTime write FFileTime; - {:original unparsed line} - property OriginalLine: string read FOriginalLine write FOriginalLine; - {:mask what was used for parsing} - property Mask: string read FMask write FMask; - {:permission string (depending on used mask!)} - property Permission: string read FPermission write FPermission; - end; - - {:@abstract(This is TList of TFTPListRec objects.) - This object is used for holding lististing of all files information in listed - directory on FTP server.} - TFTPList = class(TObject) - protected - FList: TList; - FLines: TStringList; - FMasks: TStringList; - FUnparsedLines: TStringList; - Monthnames: string; - BlockSize: string; - DirFlagValue: string; - FileName: string; - VMSFileName: string; - Day: string; - Month: string; - ThreeMonth: string; - YearTime: string; - Year: string; - Hours: string; - HoursModif: Ansistring; - Minutes: string; - Seconds: string; - Size: Ansistring; - Permissions: Ansistring; - DirFlag: string; - function GetListItem(Index: integer): TFTPListRec; virtual; - function ParseEPLF(Value: string): Boolean; virtual; - procedure ClearStore; virtual; - function ParseByMask(Value, NextValue, Mask: ansistring): Integer; virtual; - function CheckValues: Boolean; virtual; - procedure FillRecord(const Value: TFTPListRec); virtual; - public - {:Constructor. You not need create this object, it is created by TFTPSend - class as their property.} - constructor Create; - destructor Destroy; override; - - {:Clear list.} - procedure Clear; virtual; - - {:count of holded @link(TFTPListRec) objects} - function Count: integer; virtual; - - {:Assigns one list to another} - procedure Assign(Value: TFTPList); virtual; - - {:try to parse raw directory listing in @link(lines) to list of - @link(TFTPListRec).} - procedure ParseLines; virtual; - - {:By this property you have access to list of @link(TFTPListRec). - This is for compatibility only. Please, use @link(Items) instead.} - property List: TList read FList; - - {:By this property you have access to list of @link(TFTPListRec).} - property Items[Index: Integer]: TFTPListRec read GetListItem; default; - - {:Set of lines with RAW directory listing for @link(parseLines)} - property Lines: TStringList read FLines; - - {:Set of masks for directory listing parser. It is predefined by default, - however you can modify it as you need. (for example, you can add your own - definition mask.) Mask is same as mask used in TotalCommander.} - property Masks: TStringList read FMasks; - - {:After @link(ParseLines) it holding lines what was not sucessfully parsed.} - property UnparsedLines: TStringList read FUnparsedLines; - end; - - {:@abstract(Implementation of FTP protocol.) - Note: Are you missing properties for setting Username and Password? Look to - parent @link(TSynaClient) object! (Username and Password have default values - for "anonymous" FTP login) - - Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TFTPSend = class(TSynaClient) - protected - FOnStatus: TFTPStatus; - FSock: TTCPBlockSocket; - FDSock: TTCPBlockSocket; - FResultCode: Integer; - FResultString: string; - FFullResult: TStringList; - FAccount: string; - FFWHost: string; - FFWPort: string; - FFWUsername: string; - FFWPassword: string; - FFWMode: integer; - FDataStream: TMemoryStream; - FDataIP: string; - FDataPort: string; - FDirectFile: Boolean; - FDirectFileName: string; - FCanResume: Boolean; - FPassiveMode: Boolean; - FForceDefaultPort: Boolean; - FForceOldPort: Boolean; - FFtpList: TFTPList; - FBinaryMode: Boolean; - FAutoTLS: Boolean; - FIsTLS: Boolean; - FIsDataTLS: Boolean; - FTLSonData: Boolean; - FFullSSL: Boolean; - function Auth(Mode: integer): Boolean; virtual; - function Connect: Boolean; virtual; - function InternalStor(const Command: string; RestoreAt: int64): Boolean; virtual; - function DataSocket: Boolean; virtual; - function AcceptDataSocket: Boolean; virtual; - procedure DoStatus(Response: Boolean; const Value: string); virtual; - public - {:Custom definition of login sequence. You can use this when you set - @link(FWMode) to value -1.} - CustomLogon: TLogonActions; - - constructor Create; - destructor Destroy; override; - - {:Waits and read FTP server response. You need this only in special cases!} - function ReadResult: Integer; virtual; - - {:Parse remote side information of data channel from value string (returned - by PASV command). This function you need only in special cases!} - procedure ParseRemote(Value: string); virtual; - - {:Parse remote side information of data channel from value string (returned - by EPSV command). This function you need only in special cases!} - procedure ParseRemoteEPSV(Value: string); virtual; - - {:Send Value as FTP command to FTP server. Returned result code is result of - this function. - This command is good for sending site specific command, or non-standard - commands.} - function FTPCommand(const Value: string): integer; virtual; - - {:Connect and logon to FTP server. If you specify any FireWall, connect to - firewall and throw them connect to FTP server. Login sequence depending on - @link(FWMode).} - function Login: Boolean; virtual; - - {:Logoff and disconnect from FTP server.} - function Logout: Boolean; virtual; - - {:Break current transmission of data. (You can call this method from - Sock.OnStatus event, or from another thread.)} - procedure Abort; virtual; - - {:Break current transmission of data. It is same as Abort, but it send abort - telnet commands prior ABOR FTP command. Some servers need it. (You can call - this method from Sock.OnStatus event, or from another thread.)} - procedure TelnetAbort; virtual; - - {:Download directory listing of Directory on FTP server. If Directory is - empty string, download listing of current working directory. - If NameList is @true, download only names of files in directory. - (internally use NLST command instead LIST command) - If NameList is @false, returned list is also parsed to @link(FTPList) - property.} - function List(Directory: string; NameList: Boolean): Boolean; virtual; - - {:Read data from FileName on FTP server. If Restore is @true and server - supports resume dowloads, download is resumed. (received is only rest - of file)} - function RetrieveFile(const FileName: string; Restore: Boolean): Boolean; virtual; - - {:Send data to FileName on FTP server. If Restore is @true and server - supports resume upload, upload is resumed. (send only rest of file) - In this case if remote file is same length as local file, nothing will be - done. If remote file is larger then local, resume is disabled and file is - transfered from begin!} - function StoreFile(const FileName: string; Restore: Boolean): Boolean; virtual; - - {:Send data to FTP server and assing unique name for this file.} - function StoreUniqueFile: Boolean; virtual; - - {:Append data to FileName on FTP server.} - function AppendFile(const FileName: string): Boolean; virtual; - - {:Rename on FTP server file with OldName to NewName.} - function RenameFile(const OldName, NewName: string): Boolean; virtual; - - {:Delete file FileName on FTP server.} - function DeleteFile(const FileName: string): Boolean; virtual; - - {:Return size of Filename file on FTP server. If command failed (i.e. not - implemented), return -1.} - function FileSize(const FileName: string): int64; virtual; - - {:Send NOOP command to FTP server for preserve of disconnect by inactivity - timeout.} - function NoOp: Boolean; virtual; - - {:Change currect working directory to Directory on FTP server.} - function ChangeWorkingDir(const Directory: string): Boolean; virtual; - - {:walk to upper directory on FTP server.} - function ChangeToParentDir: Boolean; virtual; - - {:walk to root directory on FTP server. (May not work with all servers properly!)} - function ChangeToRootDir: Boolean; virtual; - - {:Delete Directory on FTP server.} - function DeleteDir(const Directory: string): Boolean; virtual; - - {:Create Directory on FTP server.} - function CreateDir(const Directory: string): Boolean; virtual; - - {:Return current working directory on FTP server.} - function GetCurrentDir: String; virtual; - - {:Establish data channel to FTP server and retrieve data. - This function you need only in special cases, i.e. when you need to implement - some special unsupported FTP command!} - function DataRead(const DestStream: TStream): Boolean; virtual; - - {:Establish data channel to FTP server and send data. - This function you need only in special cases, i.e. when you need to implement - some special unsupported FTP command.} - function DataWrite(const SourceStream: TStream): Boolean; virtual; - published - {:After FTP command contains result number of this operation.} - property ResultCode: Integer read FResultCode; - - {:After FTP command contains main line of result.} - property ResultString: string read FResultString; - - {:After any FTP command it contains all lines of FTP server reply.} - property FullResult: TStringList read FFullResult; - - {:Account information used in some cases inside login sequence.} - property Account: string read FAccount Write FAccount; - - {:Address of firewall. If empty string (default), firewall not used.} - property FWHost: string read FFWHost Write FFWHost; - - {:port of firewall. standard value is same port as ftp server used. (21)} - property FWPort: string read FFWPort Write FFWPort; - - {:Username for login to firewall. (if needed)} - property FWUsername: string read FFWUsername Write FFWUsername; - - {:password for login to firewall. (if needed)} - property FWPassword: string read FFWPassword Write FFWPassword; - - {:Type of Firewall. Used only if you set some firewall address. Supported - predefined firewall login sequences are described by comments in source - file where you can see pseudocode decribing each sequence.} - property FWMode: integer read FFWMode Write FFWMode; - - {:Socket object used for TCP/IP operation on control channel. Good for - seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - - {:Socket object used for TCP/IP operation on data channel. Good for seting - OnStatus hook, etc.} - property DSock: TTCPBlockSocket read FDSock; - - {:If you not use @link(DirectFile) mode, all data transfers is made to or - from this stream.} - property DataStream: TMemoryStream read FDataStream; - - {:After data connection is established, contains remote side IP of this - connection.} - property DataIP: string read FDataIP; - - {:After data connection is established, contains remote side port of this - connection.} - property DataPort: string read FDataPort; - - {:Mode of data handling by data connection. If @False, all data operations - are made to or from @link(DataStream) TMemoryStream. - If @true, data operations is made directly to file in your disk. (filename - is specified by @link(DirectFileName) property.) Dafault is @False!} - property DirectFile: Boolean read FDirectFile Write FDirectFile; - - {:Filename for direct disk data operations.} - property DirectFileName: string read FDirectFileName Write FDirectFileName; - - {:Indicate after @link(Login) if remote server support resume downloads and - uploads.} - property CanResume: Boolean read FCanResume; - - {:If true (default value), all transfers is made by passive method. - It is safer method for various firewalls.} - property PassiveMode: Boolean read FPassiveMode Write FPassiveMode; - - {:Force to listen for dataconnection on standard port (20). Default is @false, - dataconnections will be made to any non-standard port reported by PORT FTP - command. This setting is not used, if you use passive mode.} - property ForceDefaultPort: Boolean read FForceDefaultPort Write FForceDefaultPort; - - {:When is @true, then is disabled EPSV and EPRT support. However without this - commands you cannot use IPv6! (Disabling of this commands is needed only - when you are behind some crap firewall/NAT.} - property ForceOldPort: Boolean read FForceOldPort Write FForceOldPort; - - {:You may set this hook for monitoring FTP commands and replies.} - property OnStatus: TFTPStatus read FOnStatus write FOnStatus; - - {:After LIST command is here parsed list of files in given directory.} - property FtpList: TFTPList read FFtpList; - - {:if @true (default), then data transfers is in binary mode. If this is set - to @false, then ASCII mode is used.} - property BinaryMode: Boolean read FBinaryMode Write FBinaryMode; - - {:if is true, then if server support upgrade to SSL/TLS mode, then use them.} - property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; - - {:if server listen on SSL/TLS port, then you set this to true.} - property FullSSL: Boolean read FFullSSL Write FFullSSL; - - {:Signalise, if control channel is in SSL/TLS mode.} - property IsTLS: Boolean read FIsTLS; - - {:Signalise, if data transfers is in SSL/TLS mode.} - property IsDataTLS: Boolean read FIsDataTLS; - - {:If @true (default), then try to use SSL/TLS on data transfers too. - If @false, then SSL/TLS is used only for control connection.} - property TLSonData: Boolean read FTLSonData write FTLSonData; - end; - -{:A very useful function, and example of use can be found in the TFtpSend object. - Dowload specified file from FTP server to LocalFile.} -function FtpGetFile(const IP, Port, FileName, LocalFile, - User, Pass: string): Boolean; - -{:A very useful function, and example of use can be found in the TFtpSend object. - Upload specified LocalFile to FTP server.} -function FtpPutFile(const IP, Port, FileName, LocalFile, - User, Pass: string): Boolean; - -{:A very useful function, and example of use can be found in the TFtpSend object. - Initiate transfer of file between two FTP servers.} -function FtpInterServerTransfer( - const FromIP, FromPort, FromFile, FromUser, FromPass: string; - const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean; - -implementation - -constructor TFTPSend.Create; -begin - inherited Create; - FFullResult := TStringList.Create; - FDataStream := TMemoryStream.Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.ConvertLineEnd := True; - FDSock := TTCPBlockSocket.Create; - FDSock.Owner := self; - FFtpList := TFTPList.Create; - FTimeout := 300000; - FTargetPort := cFtpProtocol; - FUsername := 'anonymous'; - FPassword := 'anonymous@' + FSock.LocalName; - FDirectFile := False; - FPassiveMode := True; - FForceDefaultPort := False; - FForceOldPort := false; - FAccount := ''; - FFWHost := ''; - FFWPort := cFtpProtocol; - FFWUsername := ''; - FFWPassword := ''; - FFWMode := 0; - FBinaryMode := True; - FAutoTLS := False; - FFullSSL := False; - FIsTLS := False; - FIsDataTLS := False; - FTLSonData := True; -end; - -destructor TFTPSend.Destroy; -begin - FDSock.Free; - FSock.Free; - FFTPList.Free; - FDataStream.Free; - FFullResult.Free; - inherited Destroy; -end; - -procedure TFTPSend.DoStatus(Response: Boolean; const Value: string); -begin - if assigned(OnStatus) then - OnStatus(Self, Response, Value); -end; - -function TFTPSend.ReadResult: Integer; -var - s, c: AnsiString; -begin - FFullResult.Clear; - c := ''; - repeat - s := FSock.RecvString(FTimeout); - if c = '' then - if length(s) > 3 then - if s[4] in [' ', '-'] then - c :=Copy(s, 1, 3); - FResultString := s; - FFullResult.Add(s); - DoStatus(True, s); - if FSock.LastError <> 0 then - Break; - until (c <> '') and (Pos(c + ' ', s) = 1); - Result := StrToIntDef(c, 0); - FResultCode := Result; -end; - -function TFTPSend.FTPCommand(const Value: string): integer; -begin - FSock.Purge; - FSock.SendString(Value + CRLF); - DoStatus(False, Value); - Result := ReadResult; -end; - -// based on idea by Petr Esner <petr.esner@atlas.cz> -function TFTPSend.Auth(Mode: integer): Boolean; -const - //if not USER <username> then - // if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action0: TLogonActions = - (0, FTP_OK, 3, - 1, FTP_OK, 6, - 2, FTP_OK, FTP_ERR, - 0, 0, 0, 0, 0, 0, 0, 0, 0); - - //if not USER <FWusername> then - // if not PASS <FWPassword> then ERROR! - //if SITE <FTPServer> then ERROR! - //if not USER <username> then - // if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action1: TLogonActions = - (3, 6, 3, - 4, 6, FTP_ERR, - 5, FTP_ERR, 9, - 0, FTP_OK, 12, - 1, FTP_OK, 15, - 2, FTP_OK, FTP_ERR); - - //if not USER <FWusername> then - // if not PASS <FWPassword> then ERROR! - //if USER <UserName>'@'<FTPServer> then OK! - //if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action2: TLogonActions = - (3, 6, 3, - 4, 6, FTP_ERR, - 6, FTP_OK, 9, - 1, FTP_OK, 12, - 2, FTP_OK, FTP_ERR, - 0, 0, 0); - - //if not USER <FWusername> then - // if not PASS <FWPassword> then ERROR! - //if not USER <username> then - // if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action3: TLogonActions = - (3, 6, 3, - 4, 6, FTP_ERR, - 0, FTP_OK, 9, - 1, FTP_OK, 12, - 2, FTP_OK, FTP_ERR, - 0, 0, 0); - - //OPEN <FTPserver> - //if not USER <username> then - // if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action4: TLogonActions = - (7, 3, 3, - 0, FTP_OK, 6, - 1, FTP_OK, 9, - 2, FTP_OK, FTP_ERR, - 0, 0, 0, 0, 0, 0); - - //if USER <UserName>'@'<FTPServer> then OK! - //if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action5: TLogonActions = - (6, FTP_OK, 3, - 1, FTP_OK, 6, - 2, FTP_OK, FTP_ERR, - 0, 0, 0, 0, 0, 0, 0, 0, 0); - - //if not USER <FWUserName>@<FTPServer> then - // if not PASS <FWPassword> then ERROR! - //if not USER <username> then - // if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action6: TLogonActions = - (8, 6, 3, - 4, 6, FTP_ERR, - 0, FTP_OK, 9, - 1, FTP_OK, 12, - 2, FTP_OK, FTP_ERR, - 0, 0, 0); - - //if USER <UserName>@<FTPServer> <FWUserName> then ERROR! - //if not PASS <password> then - // if not ACCT <account> then ERROR! - //OK! - Action7: TLogonActions = - (9, FTP_ERR, 3, - 1, FTP_OK, 6, - 2, FTP_OK, FTP_ERR, - 0, 0, 0, 0, 0, 0, 0, 0, 0); - - //if not USER <UserName>@<FWUserName>@<FTPServer> then - // if not PASS <Password>@<FWPassword> then - // if not ACCT <account> then ERROR! - //OK! - Action8: TLogonActions = - (10, FTP_OK, 3, - 11, FTP_OK, 6, - 2, FTP_OK, FTP_ERR, - 0, 0, 0, 0, 0, 0, 0, 0, 0); -var - FTPServer: string; - LogonActions: TLogonActions; - i: integer; - s: string; - x: integer; -begin - Result := False; - if FFWHost = '' then - Mode := 0; - if (FTargetPort = cFtpProtocol) or (FTargetPort = '21') then - FTPServer := FTargetHost - else - FTPServer := FTargetHost + ':' + FTargetPort; - case Mode of - -1: - LogonActions := CustomLogon; - 1: - LogonActions := Action1; - 2: - LogonActions := Action2; - 3: - LogonActions := Action3; - 4: - LogonActions := Action4; - 5: - LogonActions := Action5; - 6: - LogonActions := Action6; - 7: - LogonActions := Action7; - 8: - LogonActions := Action8; - else - LogonActions := Action0; - end; - i := 0; - repeat - case LogonActions[i] of - 0: s := 'USER ' + FUserName; - 1: s := 'PASS ' + FPassword; - 2: s := 'ACCT ' + FAccount; - 3: s := 'USER ' + FFWUserName; - 4: s := 'PASS ' + FFWPassword; - 5: s := 'SITE ' + FTPServer; - 6: s := 'USER ' + FUserName + '@' + FTPServer; - 7: s := 'OPEN ' + FTPServer; - 8: s := 'USER ' + FFWUserName + '@' + FTPServer; - 9: s := 'USER ' + FUserName + '@' + FTPServer + ' ' + FFWUserName; - 10: s := 'USER ' + FUserName + '@' + FFWUserName + '@' + FTPServer; - 11: s := 'PASS ' + FPassword + '@' + FFWPassword; - end; - x := FTPCommand(s); - x := x div 100; - if (x <> 2) and (x <> 3) then - Exit; - i := LogonActions[i + x - 1]; - case i of - FTP_ERR: - Exit; - FTP_OK: - begin - Result := True; - Exit; - end; - end; - until False; -end; - - -function TFTPSend.Connect: Boolean; -begin - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError = 0 then - if FFWHost = '' then - FSock.Connect(FTargetHost, FTargetPort) - else - FSock.Connect(FFWHost, FFWPort); - if FSock.LastError = 0 then - if FFullSSL then - FSock.SSLDoConnect; - Result := FSock.LastError = 0; -end; - -function TFTPSend.Login: Boolean; -var - x: integer; -begin - Result := False; - FCanResume := False; - if not Connect then - Exit; - FIsTLS := FFullSSL; - FIsDataTLS := False; - repeat - x := ReadResult div 100; - until x <> 1; - if x <> 2 then - Exit; - if FAutoTLS and not(FIsTLS) then - if (FTPCommand('AUTH TLS') div 100) = 2 then - begin - FSock.SSLDoConnect; - FIsTLS := FSock.LastError = 0; - if not FIsTLS then - begin - Result := False; - Exit; - end; - end; - if not Auth(FFWMode) then - Exit; - if FIsTLS then - begin - FTPCommand('PBSZ 0'); - if FTLSonData then - FIsDataTLS := (FTPCommand('PROT P') div 100) = 2; - if not FIsDataTLS then - FTPCommand('PROT C'); - end; - FTPCommand('TYPE I'); - FTPCommand('STRU F'); - FTPCommand('MODE S'); - if FTPCommand('REST 0') = 350 then - if FTPCommand('REST 1') = 350 then - begin - FTPCommand('REST 0'); - FCanResume := True; - end; - Result := True; -end; - -function TFTPSend.Logout: Boolean; -begin - Result := (FTPCommand('QUIT') div 100) = 2; - FSock.CloseSocket; -end; - -procedure TFTPSend.ParseRemote(Value: string); -var - n: integer; - nb, ne: integer; - s: string; - x: integer; -begin - Value := trim(Value); - nb := Pos('(',Value); - ne := Pos(')',Value); - if (nb = 0) or (ne = 0) then - begin - nb:=RPos(' ',Value); - s:=Copy(Value, nb + 1, Length(Value) - nb); - end - else - begin - s:=Copy(Value,nb+1,ne-nb-1); - end; - for n := 1 to 4 do - if n = 1 then - FDataIP := Fetch(s, ',') - else - FDataIP := FDataIP + '.' + Fetch(s, ','); - x := StrToIntDef(Fetch(s, ','), 0) * 256; - x := x + StrToIntDef(Fetch(s, ','), 0); - FDataPort := IntToStr(x); -end; - -procedure TFTPSend.ParseRemoteEPSV(Value: string); -var - n: integer; - s, v: AnsiString; -begin - s := SeparateRight(Value, '('); - s := Trim(SeparateLeft(s, ')')); - Delete(s, Length(s), 1); - v := ''; - for n := Length(s) downto 1 do - if s[n] in ['0'..'9'] then - v := s[n] + v - else - Break; - FDataPort := v; - FDataIP := FTargetHost; -end; - -function TFTPSend.DataSocket: boolean; -var - s: string; -begin - Result := False; - if FIsDataTLS then - FPassiveMode := True; - if FPassiveMode then - begin - if FSock.IP6used then - s := '2' - else - s := '1'; - if FSock.IP6used and not(FForceOldPort) and ((FTPCommand('EPSV ' + s) div 100) = 2) then - begin - ParseRemoteEPSV(FResultString); - end - else - if FSock.IP6used then - Exit - else - begin - if (FTPCommand('PASV') div 100) <> 2 then - Exit; - ParseRemote(FResultString); - end; - FDSock.CloseSocket; - FDSock.Bind(FIPInterface, cAnyPort); - FDSock.Connect(FDataIP, FDataPort); - Result := FDSock.LastError = 0; - end - else - begin - FDSock.CloseSocket; - if FForceDefaultPort then - s := cFtpDataProtocol - else - s := '0'; - //data conection from same interface as command connection - FDSock.Bind(FSock.GetLocalSinIP, s); - if FDSock.LastError <> 0 then - Exit; - FDSock.SetLinger(True, 10000); - FDSock.Listen; - FDSock.GetSins; - FDataIP := FDSock.GetLocalSinIP; - FDataIP := FDSock.ResolveName(FDataIP); - FDataPort := IntToStr(FDSock.GetLocalSinPort); - if FSock.IP6used and (not FForceOldPort) then - begin - if IsIp6(FDataIP) then - s := '2' - else - s := '1'; - s := 'EPRT |' + s +'|' + FDataIP + '|' + FDataPort + '|'; - Result := (FTPCommand(s) div 100) = 2; - end; - if not Result and IsIP(FDataIP) then - begin - s := ReplaceString(FDataIP, '.', ','); - s := 'PORT ' + s + ',' + IntToStr(FDSock.GetLocalSinPort div 256) - + ',' + IntToStr(FDSock.GetLocalSinPort mod 256); - Result := (FTPCommand(s) div 100) = 2; - end; - end; -end; - -function TFTPSend.AcceptDataSocket: Boolean; -var - x: TSocket; -begin - if FPassiveMode then - Result := True - else - begin - Result := False; - if FDSock.CanRead(FTimeout) then - begin - x := FDSock.Accept; - if not FDSock.UsingSocks then - FDSock.CloseSocket; - FDSock.Socket := x; - Result := True; - end; - end; - if Result and FIsDataTLS then - begin - FDSock.SSL.Assign(FSock.SSL); - FDSock.SSLDoConnect; - Result := FDSock.LastError = 0; - end; -end; - -function TFTPSend.DataRead(const DestStream: TStream): Boolean; -var - x: integer; -begin - Result := False; - try - if not AcceptDataSocket then - Exit; - FDSock.RecvStreamRaw(DestStream, FTimeout); - FDSock.CloseSocket; - x := ReadResult; - Result := (x div 100) = 2; - finally - FDSock.CloseSocket; - end; -end; - -function TFTPSend.DataWrite(const SourceStream: TStream): Boolean; -var - x: integer; - b: Boolean; -begin - Result := False; - try - if not AcceptDataSocket then - Exit; - FDSock.SendStreamRaw(SourceStream); - b := FDSock.LastError = 0; - FDSock.CloseSocket; - x := ReadResult; - Result := b and ((x div 100) = 2); - finally - FDSock.CloseSocket; - end; -end; - -function TFTPSend.List(Directory: string; NameList: Boolean): Boolean; -var - x: integer; -begin - Result := False; - FDataStream.Clear; - FFTPList.Clear; - if Directory <> '' then - Directory := ' ' + Directory; - FTPCommand('TYPE A'); - if not DataSocket then - Exit; - if NameList then - x := FTPCommand('NLST' + Directory) - else - x := FTPCommand('LIST' + Directory); - if (x div 100) <> 1 then - Exit; - Result := DataRead(FDataStream); - if (not NameList) and Result then - begin - FDataStream.Position := 0; - FFTPList.Lines.LoadFromStream(FDataStream); - FFTPList.ParseLines; - end; - FDataStream.Position := 0; -end; - -function TFTPSend.RetrieveFile(const FileName: string; Restore: Boolean): Boolean; -var - RetrStream: TStream; -begin - Result := False; - if FileName = '' then - Exit; - if not DataSocket then - Exit; - Restore := Restore and FCanResume; - if FDirectFile then - if Restore and FileExists(FDirectFileName) then - RetrStream := TFileStream.Create(FDirectFileName, - fmOpenReadWrite or fmShareExclusive) - else - RetrStream := TFileStream.Create(FDirectFileName, - fmCreate or fmShareDenyWrite) - else - RetrStream := FDataStream; - try - if FBinaryMode then - FTPCommand('TYPE I') - else - FTPCommand('TYPE A'); - if Restore then - begin - RetrStream.Position := RetrStream.Size; - if (FTPCommand('REST ' + IntToStr(RetrStream.Size)) div 100) <> 3 then - Exit; - end - else - if RetrStream is TMemoryStream then - TMemoryStream(RetrStream).Clear; - if (FTPCommand('RETR ' + FileName) div 100) <> 1 then - Exit; - Result := DataRead(RetrStream); - if not FDirectFile then - RetrStream.Position := 0; - finally - if FDirectFile then - RetrStream.Free; - end; -end; - -function TFTPSend.InternalStor(const Command: string; RestoreAt: int64): Boolean; -var - SendStream: TStream; - StorSize: int64; -begin - Result := False; - if FDirectFile then - if not FileExists(FDirectFileName) then - Exit - else - SendStream := TFileStream.Create(FDirectFileName, - fmOpenRead or fmShareDenyWrite) - else - SendStream := FDataStream; - try - if not DataSocket then - Exit; - if FBinaryMode then - FTPCommand('TYPE I') - else - FTPCommand('TYPE A'); - StorSize := SendStream.Size; - if not FCanResume then - RestoreAt := 0; - if (StorSize > 0) and (RestoreAt = StorSize) then - begin - Result := True; - Exit; - end; - if RestoreAt > StorSize then - RestoreAt := 0; - FTPCommand('ALLO ' + IntToStr(StorSize - RestoreAt)); - if FCanResume then - if (FTPCommand('REST ' + IntToStr(RestoreAt)) div 100) <> 3 then - Exit; - SendStream.Position := RestoreAt; - if (FTPCommand(Command) div 100) <> 1 then - Exit; - Result := DataWrite(SendStream); - finally - if FDirectFile then - SendStream.Free; - end; -end; - -function TFTPSend.StoreFile(const FileName: string; Restore: Boolean): Boolean; -var - RestoreAt: int64; -begin - Result := False; - if FileName = '' then - Exit; - RestoreAt := 0; - Restore := Restore and FCanResume; - if Restore then - begin - RestoreAt := Self.FileSize(FileName); - if RestoreAt < 0 then - RestoreAt := 0; - end; - Result := InternalStor('STOR ' + FileName, RestoreAt); -end; - -function TFTPSend.StoreUniqueFile: Boolean; -begin - Result := InternalStor('STOU', 0); -end; - -function TFTPSend.AppendFile(const FileName: string): Boolean; -begin - Result := False; - if FileName = '' then - Exit; - Result := InternalStor('APPE ' + FileName, 0); -end; - -function TFTPSend.NoOp: Boolean; -begin - Result := (FTPCommand('NOOP') div 100) = 2; -end; - -function TFTPSend.RenameFile(const OldName, NewName: string): Boolean; -begin - Result := False; - if (FTPCommand('RNFR ' + OldName) div 100) <> 3 then - Exit; - Result := (FTPCommand('RNTO ' + NewName) div 100) = 2; -end; - -function TFTPSend.DeleteFile(const FileName: string): Boolean; -begin - Result := (FTPCommand('DELE ' + FileName) div 100) = 2; -end; - -function TFTPSend.FileSize(const FileName: string): int64; -var - s: string; -begin - Result := -1; - if (FTPCommand('SIZE ' + FileName) div 100) = 2 then - begin - s := Trim(SeparateRight(ResultString, ' ')); - s := Trim(SeparateLeft(s, ' ')); - {$IFDEF VER100} - Result := StrToIntDef(s, -1); - {$ELSE} - Result := StrToInt64Def(s, -1); - {$ENDIF} - end; -end; - -function TFTPSend.ChangeWorkingDir(const Directory: string): Boolean; -begin - Result := (FTPCommand('CWD ' + Directory) div 100) = 2; -end; - -function TFTPSend.ChangeToParentDir: Boolean; -begin - Result := (FTPCommand('CDUP') div 100) = 2; -end; - -function TFTPSend.ChangeToRootDir: Boolean; -begin - Result := ChangeWorkingDir('/'); -end; - -function TFTPSend.DeleteDir(const Directory: string): Boolean; -begin - Result := (FTPCommand('RMD ' + Directory) div 100) = 2; -end; - -function TFTPSend.CreateDir(const Directory: string): Boolean; -begin - Result := (FTPCommand('MKD ' + Directory) div 100) = 2; -end; - -function TFTPSend.GetCurrentDir: String; -begin - Result := ''; - if (FTPCommand('PWD') div 100) = 2 then - begin - Result := SeparateRight(FResultString, '"'); - Result := Trim(Separateleft(Result, '"')); - end; -end; - -procedure TFTPSend.Abort; -begin - FSock.SendString('ABOR' + CRLF); - FDSock.StopFlag := True; -end; - -procedure TFTPSend.TelnetAbort; -begin - FSock.SendString(#$FF + #$F4 + #$FF + #$F2); - Abort; -end; - -{==============================================================================} - -procedure TFTPListRec.Assign(Value: TFTPListRec); -begin - FFileName := Value.FileName; - FDirectory := Value.Directory; - FReadable := Value.Readable; - FFileSize := Value.FileSize; - FFileTime := Value.FileTime; - FOriginalLine := Value.OriginalLine; - FMask := Value.Mask; -end; - -constructor TFTPList.Create; -begin - inherited Create; - FList := TList.Create; - FLines := TStringList.Create; - FMasks := TStringList.Create; - FUnparsedLines := TStringList.Create; - //various UNIX - FMasks.add('pppppppppp $!!!S*$TTT$DD$hh mm ss$YYYY$n*'); - FMasks.add('pppppppppp $!!!S*$DD$TTT$hh mm ss$YYYY$n*'); - FMasks.add('pppppppppp $!!!S*$TTT$DD$UUUUU$n*'); //mostly used UNIX format - FMasks.add('pppppppppp $!!!S*$DD$TTT$UUUUU$n*'); - //MacOS - FMasks.add('pppppppppp $!!S*$TTT$DD$UUUUU$n*'); - FMasks.add('pppppppppp $!S*$TTT$DD$UUUUU$n*'); - //Novell - FMasks.add('d $!S*$TTT$DD$UUUUU$n*'); - //Windows - FMasks.add('MM DD YY hh mmH !S* n*'); - FMasks.add('MM DD YY hh mmH $ d!n*'); - FMasks.add('MM DD YYYY hh mmH !S* n*'); - FMasks.add('MM DD YYYY hh mmH $ d!n*'); - FMasks.add('DD MM YYYY hh mmH !S* n*'); - FMasks.add('DD MM YYYY hh mmH $ d!n*'); - //VMS - FMasks.add('v*$ DD TTT YYYY hh mm'); - FMasks.add('v*$!DD TTT YYYY hh mm'); - FMasks.add('n*$ YYYY MM DD hh mm$S*'); - //AS400 - FMasks.add('!S*$MM DD YY hh mm ss !n*'); - FMasks.add('!S*$DD MM YY hh mm ss !n*'); - FMasks.add('n*!S*$MM DD YY hh mm ss d'); - FMasks.add('n*!S*$DD MM YY hh mm ss d'); - //VxWorks - FMasks.add('$S* TTT DD YYYY hh mm ss $n* $ d'); - FMasks.add('$S* TTT DD YYYY hh mm ss $n*'); - //Distinct - FMasks.add('d $S*$TTT DD YYYY hh mm$n*'); - FMasks.add('d $S*$TTT DD$hh mm$n*'); - //PC-NFSD - FMasks.add('nnnnnnnn.nnn dSSSSSSSSSSS MM DD YY hh mmH'); - //VOS - FMasks.add('- SSSSS YY MM DD hh mm ss n*'); - FMasks.add('- d= SSSSS YY MM DD hh mm ss n*'); - //Unissys ClearPath - FMasks.add('nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn SSSSSSSSS MM DD YYYY hh mm'); - FMasks.add('n*\x SSSSSSSSS MM DD YYYY hh mm'); - //IBM - FMasks.add('- SSSSSSSSSSSS d MM DD YYYY hh mm n*'); - //OS9 - FMasks.add('- YY MM DD hhmm d SSSSSSSSS n*'); - //tandem - FMasks.add('nnnnnnnn SSSSSSS DD TTT YY hh mm ss'); - //MVS - FMasks.add('- YYYY MM DD SSSSS d=O n*'); - //BullGCOS8 - FMasks.add(' $S* MM DD YY hh mm ss !n*'); - FMasks.add('d $S* MM DD YY !n*'); - //BullGCOS7 - FMasks.add(' TTT DD YYYY n*'); - FMasks.add(' d n*'); -end; - -destructor TFTPList.Destroy; -begin - Clear; - FList.Free; - FLines.Free; - FMasks.Free; - FUnparsedLines.Free; - inherited Destroy; -end; - -procedure TFTPList.Clear; -var - n:integer; -begin - for n := 0 to FList.Count - 1 do - if Assigned(FList[n]) then - TFTPListRec(FList[n]).Free; - FList.Clear; - FLines.Clear; - FUnparsedLines.Clear; -end; - -function TFTPList.Count: integer; -begin - Result := FList.Count; -end; - -function TFTPList.GetListItem(Index: integer): TFTPListRec; -begin - Result := nil; - if Index < Count then - Result := TFTPListRec(FList[Index]); -end; - -procedure TFTPList.Assign(Value: TFTPList); -var - flr: TFTPListRec; - n: integer; -begin - Clear; - for n := 0 to Value.Count - 1 do - begin - flr := TFTPListRec.Create; - flr.Assign(Value[n]); - Flist.Add(flr); - end; - Lines.Assign(Value.Lines); - Masks.Assign(Value.Masks); - UnparsedLines.Assign(Value.UnparsedLines); -end; - -procedure TFTPList.ClearStore; -begin - Monthnames := ''; - BlockSize := ''; - DirFlagValue := ''; - FileName := ''; - VMSFileName := ''; - Day := ''; - Month := ''; - ThreeMonth := ''; - YearTime := ''; - Year := ''; - Hours := ''; - HoursModif := ''; - Minutes := ''; - Seconds := ''; - Size := ''; - Permissions := ''; - DirFlag := ''; -end; - -function TFTPList.ParseByMask(Value, NextValue, Mask: AnsiString): Integer; -var - Ivalue, IMask: integer; - MaskC, LastMaskC: AnsiChar; - c: AnsiChar; - s: string; -begin - ClearStore; - Result := 0; - if Value = '' then - Exit; - if Mask = '' then - Exit; - Ivalue := 1; - IMask := 1; - Result := 1; - LastMaskC := ' '; - while Imask <= Length(mask) do - begin - if (Mask[Imask] <> '*') and (Ivalue > Length(Value)) then - begin - Result := 0; - Exit; - end; - MaskC := Mask[Imask]; - if Ivalue > Length(Value) then - Exit; - c := Value[Ivalue]; - case MaskC of - 'n': - FileName := FileName + c; - 'v': - VMSFileName := VMSFileName + c; - '.': - begin - if c in ['.', ' '] then - FileName := TrimSP(FileName) + '.' - else - begin - Result := 0; - Exit; - end; - end; - 'D': - Day := Day + c; - 'M': - Month := Month + c; - 'T': - ThreeMonth := ThreeMonth + c; - 'U': - YearTime := YearTime + c; - 'Y': - Year := Year + c; - 'h': - Hours := Hours + c; - 'H': - HoursModif := HoursModif + c; - 'm': - Minutes := Minutes + c; - 's': - Seconds := Seconds + c; - 'S': - Size := Size + c; - 'p': - Permissions := Permissions + c; - 'd': - DirFlag := DirFlag + c; - 'x': - if c <> ' ' then - begin - Result := 0; - Exit; - end; - '*': - begin - s := ''; - if LastMaskC in ['n', 'v'] then - begin - if Imask = Length(Mask) then - s := Copy(Value, IValue, Maxint) - else - while IValue <= Length(Value) do - begin - if Value[Ivalue] = ' ' then - break; - s := s + Value[Ivalue]; - Inc(Ivalue); - end; - if LastMaskC = 'n' then - FileName := FileName + s - else - VMSFileName := VMSFileName + s; - end - else - begin - while IValue <= Length(Value) do - begin - if not(Value[Ivalue] in ['0'..'9']) then - break; - s := s + Value[Ivalue]; - Inc(Ivalue); - end; - case LastMaskC of - 'S': - Size := Size + s; - end; - end; - Dec(IValue); - end; - '!': - begin - while IValue <= Length(Value) do - begin - if Value[Ivalue] = ' ' then - break; - Inc(Ivalue); - end; - while IValue <= Length(Value) do - begin - if Value[Ivalue] <> ' ' then - break; - Inc(Ivalue); - end; - Dec(IValue); - end; - '$': - begin - while IValue <= Length(Value) do - begin - if not(Value[Ivalue] in [' ', #9]) then - break; - Inc(Ivalue); - end; - Dec(IValue); - end; - '=': - begin - s := ''; - case LastmaskC of - 'S': - begin - while Imask <= Length(Mask) do - begin - if not(Mask[Imask] in ['0'..'9']) then - break; - s := s + Mask[Imask]; - Inc(Imask); - end; - Dec(Imask); - BlockSize := s; - end; - 'T': - begin - Monthnames := Copy(Mask, IMask, 12 * 3); - Inc(IMask, 12 * 3); - end; - 'd': - begin - Inc(Imask); - DirFlagValue := Mask[Imask]; - end; - end; - end; - '\': - begin - Value := NextValue; - IValue := 0; - Result := 2; - end; - end; - Inc(Ivalue); - Inc(Imask); - LastMaskC := MaskC; - end; -end; - -function TFTPList.CheckValues: Boolean; -var - x, n: integer; -begin - Result := false; - if FileName <> '' then - begin - if pos('?', VMSFilename) > 0 then - Exit; - if pos('*', VMSFilename) > 0 then - Exit; - end; - if VMSFileName <> '' then - if pos(';', VMSFilename) <= 0 then - Exit; - if (FileName = '') and (VMSFileName = '') then - Exit; - if Permissions <> '' then - begin - if length(Permissions) <> 10 then - Exit; - for n := 1 to 10 do - if not(Permissions[n] in - ['a', 'b', 'c', 'd', 'h', 'l', 'p', 'r', 's', 't', 'w', 'x', 'y', '-']) then - Exit; - end; - if Day <> '' then - begin - Day := TrimSP(Day); - x := StrToIntDef(day, -1); - if (x < 1) or (x > 31) then - Exit; - end; - if Month <> '' then - begin - Month := TrimSP(Month); - x := StrToIntDef(Month, -1); - if (x < 1) or (x > 12) then - Exit; - end; - if Hours <> '' then - begin - Hours := TrimSP(Hours); - x := StrToIntDef(Hours, -1); - if (x < 0) or (x > 24) then - Exit; - end; - if HoursModif <> '' then - begin - if not (HoursModif[1] in ['a', 'A', 'p', 'P']) then - Exit; - end; - if Minutes <> '' then - begin - Minutes := TrimSP(Minutes); - x := StrToIntDef(Minutes, -1); - if (x < 0) or (x > 59) then - Exit; - end; - if Seconds <> '' then - begin - Seconds := TrimSP(Seconds); - x := StrToIntDef(Seconds, -1); - if (x < 0) or (x > 59) then - Exit; - end; - if Size <> '' then - begin - Size := TrimSP(Size); - for n := 1 to Length(Size) do - if not (Size[n] in ['0'..'9']) then - Exit; - end; - - if length(Monthnames) = (12 * 3) then - for n := 1 to 12 do - CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3); - if ThreeMonth <> '' then - begin - x := GetMonthNumber(ThreeMonth); - if (x = 0) then - Exit; - end; - if YearTime <> '' then - begin - YearTime := ReplaceString(YearTime, '-', ':'); - if pos(':', YearTime) > 0 then - begin - if (GetTimeFromstr(YearTime) = -1) then - Exit; - end - else - begin - YearTime := TrimSP(YearTime); - x := StrToIntDef(YearTime, -1); - if (x = -1) then - Exit; - if (x < 1900) or (x > 2100) then - Exit; - end; - end; - if Year <> '' then - begin - Year := TrimSP(Year); - x := StrToIntDef(Year, -1); - if (x = -1) then - Exit; - if Length(Year) = 4 then - begin - if not((x > 1900) and (x < 2100)) then - Exit; - end - else - if Length(Year) = 2 then - begin - if not((x >= 0) and (x <= 99)) then - Exit; - end - else - if Length(Year) = 3 then - begin - if not((x >= 100) and (x <= 110)) then - Exit; - end - else - Exit; - end; - Result := True; -end; - -procedure TFTPList.FillRecord(const Value: TFTPListRec); -var - s: string; - x: integer; - myear: Word; - mmonth: Word; - mday: Word; - mhours, mminutes, mseconds: word; - n: integer; -begin - s := DirFlagValue; - if s = '' then - s := 'D'; - s := Uppercase(s); - Value.Directory := s = Uppercase(DirFlag); - if FileName <> '' then - Value.FileName := SeparateLeft(Filename, ' -> '); - if VMSFileName <> '' then - begin - Value.FileName := VMSFilename; - Value.Directory := Pos('.DIR;',VMSFilename) > 0; - end; - Value.FileName := TrimSPRight(Value.FileName); - Value.Readable := not Value.Directory; - if BlockSize <> '' then - x := StrToIntDef(BlockSize, 1) - else - x := 1; - {$IFDEF VER100} - Value.FileSize := x * StrToIntDef(Size, 0); - {$ELSE} - Value.FileSize := x * StrToInt64Def(Size, 0); - {$ENDIF} - - DecodeDate(Date,myear,mmonth,mday); - mhours := 0; - mminutes := 0; - mseconds := 0; - - if Day <> '' then - mday := StrToIntDef(day, 1); - if Month <> '' then - mmonth := StrToIntDef(Month, 1); - if length(Monthnames) = (12 * 3) then - for n := 1 to 12 do - CustomMonthNames[n] := Copy(Monthnames, ((n - 1) * 3) + 1, 3); - if ThreeMonth <> '' then - mmonth := GetMonthNumber(ThreeMonth); - if Year <> '' then - begin - myear := StrToIntDef(Year, 0); - if (myear <= 99) and (myear > 50) then - myear := myear + 1900; - if myear <= 50 then - myear := myear + 2000; - end; - if YearTime <> '' then - begin - if pos(':', YearTime) > 0 then - begin - YearTime := TrimSP(YearTime); - mhours := StrToIntDef(Separateleft(YearTime, ':'), 0); - mminutes := StrToIntDef(SeparateRight(YearTime, ':'), 0); - if (Encodedate(myear, mmonth, mday) - + EncodeTime(mHours, mminutes, 0, 0)) > now then - Dec(mYear); - end - else - myear := StrToIntDef(YearTime, 0); - end; - if Minutes <> '' then - mminutes := StrToIntDef(Minutes, 0); - if Seconds <> '' then - mseconds := StrToIntDef(Seconds, 0); - if Hours <> '' then - begin - mHours := StrToIntDef(Hours, 0); - if HoursModif <> '' then - if Uppercase(HoursModif[1]) = 'P' then - if mHours <> 12 then - mHours := MHours + 12; - end; - Value.FileTime := Encodedate(myear, mmonth, mday) - + EncodeTime(mHours, mminutes, mseconds, 0); - if Permissions <> '' then - begin - Value.Permission := Permissions; - Value.Readable := Uppercase(permissions)[2] = 'R'; - if Uppercase(permissions)[1] = 'D' then - begin - Value.Directory := True; - Value.Readable := false; - end - else - if Uppercase(permissions)[1] = 'L' then - Value.Directory := True; - end; -end; - -function TFTPList.ParseEPLF(Value: string): Boolean; -var - s, os: string; - flr: TFTPListRec; -begin - Result := False; - if Value <> '' then - if Value[1] = '+' then - begin - os := Value; - Delete(Value, 1, 1); - flr := TFTPListRec.create; - flr.FileName := SeparateRight(Value, #9); - s := Fetch(Value, ','); - while s <> '' do - begin - if s[1] = #9 then - Break; - case s[1] of - '/': - flr.Directory := true; - 'r': - flr.Readable := true; - 's': - {$IFDEF VER100} - flr.FileSize := StrToIntDef(Copy(s, 2, Length(s) - 1), 0); - {$ELSE} - flr.FileSize := StrToInt64Def(Copy(s, 2, Length(s) - 1), 0); - {$ENDIF} - 'm': - flr.FileTime := (StrToIntDef(Copy(s, 2, Length(s) - 1), 0) / 86400) - + 25569; - end; - s := Fetch(Value, ','); - end; - if flr.FileName <> '' then - if (flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..'))) - or (flr.FileName = '') then - flr.free - else - begin - flr.OriginalLine := os; - flr.Mask := 'EPLF'; - Flist.Add(flr); - Result := True; - end; - end; -end; - -procedure TFTPList.ParseLines; -var - flr: TFTPListRec; - n, m: Integer; - S: string; - x: integer; - b: Boolean; -begin - n := 0; - while n < Lines.Count do - begin - if n = Lines.Count - 1 then - s := '' - else - s := Lines[n + 1]; - b := False; - x := 0; - if ParseEPLF(Lines[n]) then - begin - b := True; - x := 1; - end - else - for m := 0 to Masks.Count - 1 do - begin - x := ParseByMask(Lines[n], s, Masks[m]); - if x > 0 then - if CheckValues then - begin - flr := TFTPListRec.create; - FillRecord(flr); - flr.OriginalLine := Lines[n]; - flr.Mask := Masks[m]; - if flr.Directory and ((flr.FileName = '.') or (flr.FileName = '..')) then - flr.free - else - Flist.Add(flr); - b := True; - Break; - end; - end; - if not b then - FUnparsedLines.Add(Lines[n]); - Inc(n); - if x > 1 then - Inc(n, x - 1); - end; -end; - -{==============================================================================} - -function FtpGetFile(const IP, Port, FileName, LocalFile, - User, Pass: string): Boolean; -begin - Result := False; - with TFTPSend.Create do - try - if User <> '' then - begin - Username := User; - Password := Pass; - end; - TargetHost := IP; - TargetPort := Port; - if not Login then - Exit; - DirectFileName := LocalFile; - DirectFile:=True; - Result := RetrieveFile(FileName, False); - Logout; - finally - Free; - end; -end; - -function FtpPutFile(const IP, Port, FileName, LocalFile, - User, Pass: string): Boolean; -begin - Result := False; - with TFTPSend.Create do - try - if User <> '' then - begin - Username := User; - Password := Pass; - end; - TargetHost := IP; - TargetPort := Port; - if not Login then - Exit; - DirectFileName := LocalFile; - DirectFile:=True; - Result := StoreFile(FileName, False); - Logout; - finally - Free; - end; -end; - -function FtpInterServerTransfer( - const FromIP, FromPort, FromFile, FromUser, FromPass: string; - const ToIP, ToPort, ToFile, ToUser, ToPass: string): Boolean; -var - FromFTP, ToFTP: TFTPSend; - s: string; - x: integer; -begin - Result := False; - FromFTP := TFTPSend.Create; - toFTP := TFTPSend.Create; - try - if FromUser <> '' then - begin - FromFTP.Username := FromUser; - FromFTP.Password := FromPass; - end; - if ToUser <> '' then - begin - ToFTP.Username := ToUser; - ToFTP.Password := ToPass; - end; - FromFTP.TargetHost := FromIP; - FromFTP.TargetPort := FromPort; - ToFTP.TargetHost := ToIP; - ToFTP.TargetPort := ToPort; - if not FromFTP.Login then - Exit; - if not ToFTP.Login then - Exit; - if (FromFTP.FTPCommand('PASV') div 100) <> 2 then - Exit; - FromFTP.ParseRemote(FromFTP.ResultString); - s := ReplaceString(FromFTP.DataIP, '.', ','); - s := 'PORT ' + s + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) div 256) - + ',' + IntToStr(StrToIntDef(FromFTP.DataPort, 0) mod 256); - if (ToFTP.FTPCommand(s) div 100) <> 2 then - Exit; - x := ToFTP.FTPCommand('RETR ' + FromFile); - if (x div 100) <> 1 then - Exit; - x := FromFTP.FTPCommand('STOR ' + ToFile); - if (x div 100) <> 1 then - Exit; - FromFTP.Timeout := 21600000; - x := FromFTP.ReadResult; - if (x div 100) <> 2 then - Exit; - ToFTP.Timeout := 21600000; - x := ToFTP.ReadResult; - if (x div 100) <> 2 then - Exit; - Result := True; - finally - ToFTP.Free; - FromFTP.Free; - end; -end; - -end. diff --git a/3rd/synapse/source/ftptsend.pas b/3rd/synapse/source/ftptsend.pas deleted file mode 100644 index 6ab4173cd..000000000 --- a/3rd/synapse/source/ftptsend.pas +++ /dev/null @@ -1,403 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.001 | -|==============================================================================| -| Content: Trivial FTP (TFTP) client and server | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(TFTP client and server protocol) - -Used RFC: RFC-1350 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit ftptsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil; - -const - cTFTPProtocol = '69'; - - cTFTP_RRQ = word(1); - cTFTP_WRQ = word(2); - cTFTP_DTA = word(3); - cTFTP_ACK = word(4); - cTFTP_ERR = word(5); - -type - {:@abstract(Implementation of TFTP client and server) - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TTFTPSend = class(TSynaClient) - private - FSock: TUDPBlockSocket; - FErrorCode: integer; - FErrorString: string; - FData: TMemoryStream; - FRequestIP: string; - FRequestPort: string; - function SendPacket(Cmd: word; Serial: word; const Value: string): Boolean; - function RecvPacket(Serial: word; var Value: string): Boolean; - public - constructor Create; - destructor Destroy; override; - - {:Upload @link(data) as file to TFTP server.} - function SendFile(const Filename: string): Boolean; - - {:Download file from TFTP server to @link(data).} - function RecvFile(const Filename: string): Boolean; - - {:Acts as TFTP server and wait for client request. When some request - incoming within Timeout, result is @true and parametres is filled with - information from request. You must handle this request, validate it, and - call @link(ReplyError), @link(ReplyRecv) or @link(ReplySend) for send reply - to TFTP Client.} - function WaitForRequest(var Req: word; var filename: string): Boolean; - - {:send error to TFTP client, when you acts as TFTP server.} - procedure ReplyError(Error: word; Description: string); - - {:Accept uploaded file from TFTP client to @link(data), when you acts as - TFTP server.} - function ReplyRecv: Boolean; - - {:Accept download request file from TFTP client and send content of - @link(data), when you acts as TFTP server.} - function ReplySend: Boolean; - published - {:Code of TFTP error.} - property ErrorCode: integer read FErrorCode; - - {:Human readable decription of TFTP error. (if is sended by remote side)} - property ErrorString: string read FErrorString; - - {:MemoryStream with datas for sending or receiving} - property Data: TMemoryStream read FData; - - {:Address of TFTP remote side.} - property RequestIP: string read FRequestIP write FRequestIP; - - {:Port of TFTP remote side.} - property RequestPort: string read FRequestPort write FRequestPort; - end; - -implementation - -constructor TTFTPSend.Create; -begin - inherited Create; - FSock := TUDPBlockSocket.Create; - FSock.Owner := self; - FTargetPort := cTFTPProtocol; - FData := TMemoryStream.Create; - FErrorCode := 0; - FErrorString := ''; -end; - -destructor TTFTPSend.Destroy; -begin - FSock.Free; - FData.Free; - inherited Destroy; -end; - -function TTFTPSend.SendPacket(Cmd: word; Serial: word; const Value: string): Boolean; -var - s, sh: string; -begin - FErrorCode := 0; - FErrorString := ''; - Result := false; - if Cmd <> 2 then - s := CodeInt(Cmd) + CodeInt(Serial) + Value - else - s := CodeInt(Cmd) + Value; - FSock.SendString(s); - s := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - if length(s) >= 4 then - begin - sh := CodeInt(4) + CodeInt(Serial); - if Pos(sh, s) = 1 then - Result := True - else - if s[1] = #5 then - begin - FErrorCode := DecodeInt(s, 3); - Delete(s, 1, 4); - FErrorString := SeparateLeft(s, #0); - end; - end; -end; - -function TTFTPSend.RecvPacket(Serial: word; var Value: string): Boolean; -var - s: string; - ser: word; -begin - FErrorCode := 0; - FErrorString := ''; - Result := False; - Value := ''; - s := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - if length(s) >= 4 then - if DecodeInt(s, 1) = 3 then - begin - ser := DecodeInt(s, 3); - if ser = Serial then - begin - Delete(s, 1, 4); - Value := s; - S := CodeInt(4) + CodeInt(ser); - FSock.SendString(s); - Result := FSock.LastError = 0; - end - else - begin - S := CodeInt(5) + CodeInt(5) + 'Unexcepted serial#' + #0; - FSock.SendString(s); - end; - end; - if DecodeInt(s, 1) = 5 then - begin - FErrorCode := DecodeInt(s, 3); - Delete(s, 1, 4); - FErrorString := SeparateLeft(s, #0); - end; -end; - -function TTFTPSend.SendFile(const Filename: string): Boolean; -var - s: string; - ser: word; - n, n1, n2: integer; -begin - Result := False; - FErrorCode := 0; - FErrorString := ''; - FSock.CloseSocket; - FSock.Connect(FTargetHost, FTargetPort); - try - if FSock.LastError = 0 then - begin - s := Filename + #0 + 'octet' + #0; - if not Sendpacket(2, 0, s) then - Exit; - ser := 1; - FData.Position := 0; - n1 := FData.Size div 512; - n2 := FData.Size mod 512; - for n := 1 to n1 do - begin - s := ReadStrFromStream(FData, 512); -// SetLength(s, 512); -// FData.Read(pointer(s)^, 512); - if not Sendpacket(3, ser, s) then - Exit; - inc(ser); - end; - s := ReadStrFromStream(FData, n2); -// SetLength(s, n2); -// FData.Read(pointer(s)^, n2); - if not Sendpacket(3, ser, s) then - Exit; - Result := True; - end; - finally - FSock.CloseSocket; - end; -end; - -function TTFTPSend.RecvFile(const Filename: string): Boolean; -var - s: string; - ser: word; -begin - Result := False; - FErrorCode := 0; - FErrorString := ''; - FSock.CloseSocket; - FSock.Connect(FTargetHost, FTargetPort); - try - if FSock.LastError = 0 then - begin - s := CodeInt(1) + Filename + #0 + 'octet' + #0; - FSock.SendString(s); - if FSock.LastError <> 0 then - Exit; - FData.Clear; - ser := 1; - repeat - if not RecvPacket(ser, s) then - Exit; - inc(ser); - WriteStrToStream(FData, s); -// FData.Write(pointer(s)^, length(s)); - until length(s) <> 512; - FData.Position := 0; - Result := true; - end; - finally - FSock.CloseSocket; - end; -end; - -function TTFTPSend.WaitForRequest(var Req: word; var filename: string): Boolean; -var - s: string; -begin - Result := False; - FErrorCode := 0; - FErrorString := ''; - FSock.CloseSocket; - FSock.Bind('0.0.0.0', FTargetPort); - if FSock.LastError = 0 then - begin - s := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - if Length(s) >= 4 then - begin - FRequestIP := FSock.GetRemoteSinIP; - FRequestPort := IntToStr(FSock.GetRemoteSinPort); - Req := DecodeInt(s, 1); - delete(s, 1, 2); - filename := Trim(SeparateLeft(s, #0)); - s := SeparateRight(s, #0); - s := SeparateLeft(s, #0); - Result := lowercase(trim(s)) = 'octet'; - end; - end; -end; - -procedure TTFTPSend.ReplyError(Error: word; Description: string); -var - s: string; -begin - FSock.CloseSocket; - FSock.Connect(FRequestIP, FRequestPort); - s := CodeInt(5) + CodeInt(Error) + Description + #0; - FSock.SendString(s); - FSock.CloseSocket; -end; - -function TTFTPSend.ReplyRecv: Boolean; -var - s: string; - ser: integer; -begin - Result := False; - FErrorCode := 0; - FErrorString := ''; - FSock.CloseSocket; - FSock.Connect(FRequestIP, FRequestPort); - try - s := CodeInt(4) + CodeInt(0); - FSock.SendString(s); - FData.Clear; - ser := 1; - repeat - if not RecvPacket(ser, s) then - Exit; - inc(ser); - WriteStrToStream(FData, s); -// FData.Write(pointer(s)^, length(s)); - until length(s) <> 512; - FData.Position := 0; - Result := true; - finally - FSock.CloseSocket; - end; -end; - -function TTFTPSend.ReplySend: Boolean; -var - s: string; - ser: word; - n, n1, n2: integer; -begin - Result := False; - FErrorCode := 0; - FErrorString := ''; - FSock.CloseSocket; - FSock.Connect(FRequestIP, FRequestPort); - try - ser := 1; - FData.Position := 0; - n1 := FData.Size div 512; - n2 := FData.Size mod 512; - for n := 1 to n1 do - begin - s := ReadStrFromStream(FData, 512); -// SetLength(s, 512); -// FData.Read(pointer(s)^, 512); - if not Sendpacket(3, ser, s) then - Exit; - inc(ser); - end; - s := ReadStrFromStream(FData, n2); -// SetLength(s, n2); -// FData.Read(pointer(s)^, n2); - if not Sendpacket(3, ser, s) then - Exit; - Result := True; - finally - FSock.CloseSocket; - end; -end; - -{==============================================================================} - -end. diff --git a/3rd/synapse/source/httpsend.pas b/3rd/synapse/source/httpsend.pas deleted file mode 100644 index 695a00ac8..000000000 --- a/3rd/synapse/source/httpsend.pas +++ /dev/null @@ -1,848 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 003.012.008 | -|==============================================================================| -| Content: HTTP client | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(HTTP protocol client) - -Used RFC: RFC-1867, RFC-1947, RFC-2388, RFC-2616 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit httpsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil, synaip, synacode, synsock; - -const - cHttpProtocol = '80'; - -type - {:These encoding types are used internally by the THTTPSend object to identify - the transfer data types.} - TTransferEncoding = (TE_UNKNOWN, TE_IDENTITY, TE_CHUNKED); - - {:abstract(Implementation of HTTP protocol.)} - THTTPSend = class(TSynaClient) - protected - FSock: TTCPBlockSocket; - FTransferEncoding: TTransferEncoding; - FAliveHost: string; - FAlivePort: string; - FHeaders: TStringList; - FDocument: TMemoryStream; - FMimeType: string; - FProtocol: string; - FKeepAlive: Boolean; - FKeepAliveTimeout: integer; - FStatus100: Boolean; - FProxyHost: string; - FProxyPort: string; - FProxyUser: string; - FProxyPass: string; - FResultCode: Integer; - FResultString: string; - FUserAgent: string; - FCookies: TStringList; - FDownloadSize: integer; - FUploadSize: integer; - FRangeStart: integer; - FRangeEnd: integer; - FAddPortNumberToHost: Boolean; - function ReadUnknown: Boolean; virtual; - function ReadIdentity(Size: Integer): Boolean; - function ReadChunked: Boolean; - procedure ParseCookies; - function PrepareHeaders: AnsiString; - function InternalDoConnect(needssl: Boolean): Boolean; - function InternalConnect(needssl: Boolean): Boolean; - public - constructor Create; - destructor Destroy; override; - - {:Reset headers, document and Mimetype.} - procedure Clear; - - {:Decode ResultCode and ResultString from Value.} - procedure DecodeStatus(const Value: string); - - {:Connects to host defined in URL and accesses resource defined in URL by - method. If Document is not empty, send it to the server as part of the HTTP - request. Server response is in Document and headers. Connection may be - authorised by username and password in URL. If you define proxy properties, - connection is made by this proxy. - If all OK, result is @true, else result is @false. - - If you use 'https:' instead of 'http:' in the URL, your request is made - by SSL/TLS connection (if you do not specify port, then port 443 is used - instead of standard port 80). If you use SSL/TLS request and you have - defined HTTP proxy, then HTTP-tunnel mode is automatically used .} - function HTTPMethod(const Method, URL: string): Boolean; - - {:You can call this method from OnStatus event to break current data - transfer. (or from another thread.)} - procedure Abort; - published - {:Before HTTP operation you may define any non-standard headers for HTTP - request, except: 'Expect: 100-continue', 'Content-Length', 'Content-Type', - 'Connection', 'Authorization', 'Proxy-Authorization' and 'Host' headers. - After HTTP operation, it contains full headers of the returned document.} - property Headers: TStringList read FHeaders; - - {:Stringlist with name-value stringlist pairs. Each pair is one cookie. - After the HTTP request is returned, cookies are parsed to this stringlist. - You can leave these cookies untouched for next HTTP requests. You can also - save this stringlist for later use.} - property Cookies: TStringList read FCookies; - - {:Stream with document to send (before request), or with document received - from HTTP server (after request).} - property Document: TMemoryStream read FDocument; - - {:If you need to download only part of a requested document, specify here - the position of subpart begin. If 0, the full document is requested.} - property RangeStart: integer read FRangeStart Write FRangeStart; - - {:If you need to download only part of a requested document, specify here - the position of subpart end. If 0, the document from rangeStart to end of - document is requested. - (Useful for resuming broken downloads, for example.)} - property RangeEnd: integer read FRangeEnd Write FRangeEnd; - - {:Mime type of sending data. Default is: 'text/html'.} - property MimeType: string read FMimeType Write FMimeType; - - {:Define protocol version. Possible values are: '1.1', '1.0' (default) - and '0.9'.} - property Protocol: string read FProtocol Write FProtocol; - - {:If @true (default value), keepalives in HTTP protocol 1.1 is enabled.} - property KeepAlive: Boolean read FKeepAlive Write FKeepAlive; - - {:Define timeout for keepalives in seconds!} - property KeepAliveTimeout: integer read FKeepAliveTimeout Write FKeepAliveTimeout; - - {:if @true, then the server is requested for 100status capability when - uploading data. Default is @false (off).} - property Status100: Boolean read FStatus100 Write FStatus100; - - {:Address of proxy server (IP address or domain name) where you want to - connect in @link(HTTPMethod) method.} - property ProxyHost: string read FProxyHost Write FProxyHost; - - {:Port number for proxy connection. Default value is 8080.} - property ProxyPort: string read FProxyPort Write FProxyPort; - - {:Username for connection to proxy server used in HTTPMethod method.} - property ProxyUser: string read FProxyUser Write FProxyUser; - - {:Password for connection to proxy server used in HTTPMethod method.} - property ProxyPass: string read FProxyPass Write FProxyPass; - - {:Here you can specify custom User-Agent identification. - Default: 'Mozilla/4.0 (compatible; Synapse)'} - property UserAgent: string read FUserAgent Write FUserAgent; - - {:Operation result code after successful @link(HTTPMethod) method.} - property ResultCode: Integer read FResultCode; - - {:Operation result string after successful @link(HTTPMethod) method.} - property ResultString: string read FResultString; - - {:if this value is not 0, then data download is pending. In this case you - have here the total size of downloaded data. Useful for drawing download - progressbar from OnStatus event.} - property DownloadSize: integer read FDownloadSize; - - {:if this value is not 0, then data upload is pending. In this case you have - here the total size of uploaded data. Useful for drawing upload progressbar - from OnStatus event.} - property UploadSize: integer read FUploadSize; - - {:Socket object used for TCP/IP operation. - Good for setting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - - {:Allows to switch off port number in 'Host:' HTTP header. By default @TRUE. - Some buggy servers do not like port informations in this header.} - property AddPortNumberToHost: Boolean read FAddPortNumberToHost write FAddPortNumberToHost; - end; - -{:A very useful function, and example of use can be found in the THTTPSend - object. It implements the GET method of the HTTP protocol. This function sends - the GET method for URL document to an HTTP server. Returned document is in the - "Response" stringlist (without any headers). Returns boolean TRUE if all went - well.} -function HttpGetText(const URL: string; const Response: TStrings): Boolean; - -{:A very useful function, and example of use can be found in the THTTPSend - object. It implements the GET method of the HTTP protocol. This function sends - the GET method for URL document to an HTTP server. Returned document is in the - "Response" stream. Returns boolean TRUE if all went well.} -function HttpGetBinary(const URL: string; const Response: TStream): Boolean; - -{:A very useful function, and example of use can be found in the THTTPSend - object. It implements the POST method of the HTTP protocol. This function sends - the SEND method for a URL document to an HTTP server. The document to be sent - is located in the "Data" stream. The returned document is in the "Data" stream. - Returns boolean TRUE if all went well.} -function HttpPostBinary(const URL: string; const Data: TStream): Boolean; - -{:A very useful function, and example of use can be found in the THTTPSend - object. It implements the POST method of the HTTP protocol. This function is - good for POSTing form data. It sends the POST method for a URL document to - an HTTP server. You must prepare the form data in the same manner as you would - the URL data, and pass this prepared data to "URLdata". The following is - a sample of how the data would appear: 'name=Lukas&field1=some%20data'. - The information in the field must be encoded by the EncodeURLElement function. - The returned document is in the "Data" stream. Returns boolean TRUE if all - went well.} -function HttpPostURL(const URL, URLData: string; const Data: TStream): Boolean; - -{:A very useful function, and example of use can be found in the THTTPSend - object. It implements the POST method of the HTTP protocol. This function sends - the POST method for a URL document to an HTTP server. This function simulates - posting of file by HTML form using the 'multipart/form-data' method. The posted - file is in the DATA stream. Its name is Filename string. Fieldname is for the - name of the form field with the file. (simulates HTML INPUT FILE) The returned - document is in the ResultData Stringlist. Returns boolean TRUE if all - went well.} -function HttpPostFile(const URL, FieldName, FileName: string; - const Data: TStream; const ResultData: TStrings): Boolean; - -implementation - -constructor THTTPSend.Create; -begin - inherited Create; - FHeaders := TStringList.Create; - FCookies := TStringList.Create; - FDocument := TMemoryStream.Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.ConvertLineEnd := True; - FSock.SizeRecvBuffer := c64k; - FSock.SizeSendBuffer := c64k; - FTimeout := 90000; - FTargetPort := cHttpProtocol; - FProxyHost := ''; - FProxyPort := '8080'; - FProxyUser := ''; - FProxyPass := ''; - FAliveHost := ''; - FAlivePort := ''; - FProtocol := '1.0'; - FKeepAlive := True; - FStatus100 := False; - FUserAgent := 'Mozilla/4.0 (compatible; Synapse)'; - FDownloadSize := 0; - FUploadSize := 0; - FAddPortNumberToHost := true; - FKeepAliveTimeout := 300; - Clear; -end; - -destructor THTTPSend.Destroy; -begin - FSock.Free; - FDocument.Free; - FCookies.Free; - FHeaders.Free; - inherited Destroy; -end; - -procedure THTTPSend.Clear; -begin - FRangeStart := 0; - FRangeEnd := 0; - FDocument.Clear; - FHeaders.Clear; - FMimeType := 'text/html'; -end; - -procedure THTTPSend.DecodeStatus(const Value: string); -var - s, su: string; -begin - s := Trim(SeparateRight(Value, ' ')); - su := Trim(SeparateLeft(s, ' ')); - FResultCode := StrToIntDef(su, 0); - FResultString := Trim(SeparateRight(s, ' ')); - if FResultString = s then - FResultString := ''; -end; - -function THTTPSend.PrepareHeaders: AnsiString; -begin - if FProtocol = '0.9' then - Result := FHeaders[0] + CRLF - else -{$IFNDEF MSWINDOWS} - Result := {$IFDEF UNICODE}AnsiString{$ENDIF}(AdjustLineBreaks(FHeaders.Text, tlbsCRLF)); -{$ELSE} - Result := FHeaders.Text; -{$ENDIF} -end; - -function THTTPSend.InternalDoConnect(needssl: Boolean): Boolean; -begin - Result := False; - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError <> 0 then - Exit; - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError <> 0 then - Exit; - if needssl then - begin - if (FSock.SSL.SNIHost='') then - FSock.SSL.SNIHost:=FTargetHost; - FSock.SSLDoConnect; - FSock.SSL.SNIHost:=''; //don't need it anymore and don't wan't to reuse it in next connection - if FSock.LastError <> 0 then - Exit; - end; - FAliveHost := FTargetHost; - FAlivePort := FTargetPort; - Result := True; -end; - -function THTTPSend.InternalConnect(needssl: Boolean): Boolean; -begin - if FSock.Socket = INVALID_SOCKET then - Result := InternalDoConnect(needssl) - else - if (FAliveHost <> FTargetHost) or (FAlivePort <> FTargetPort) - or FSock.CanRead(0) then - Result := InternalDoConnect(needssl) - else - Result := True; -end; - -function THTTPSend.HTTPMethod(const Method, URL: string): Boolean; -var - Sending, Receiving: Boolean; - status100: Boolean; - status100error: string; - ToClose: Boolean; - Size: Integer; - Prot, User, Pass, Host, Port, Path, Para, URI: string; - s, su: AnsiString; - HttpTunnel: Boolean; - n: integer; - pp: string; - UsingProxy: boolean; - l: TStringList; - x: integer; -begin - {initial values} - Result := False; - FResultCode := 500; - FResultString := ''; - FDownloadSize := 0; - FUploadSize := 0; - - URI := ParseURL(URL, Prot, User, Pass, Host, Port, Path, Para); - User := DecodeURL(user); - Pass := DecodeURL(pass); - if User = '' then - begin - User := FUsername; - Pass := FPassword; - end; - if UpperCase(Prot) = 'HTTPS' then - begin - HttpTunnel := FProxyHost <> ''; - FSock.HTTPTunnelIP := FProxyHost; - FSock.HTTPTunnelPort := FProxyPort; - FSock.HTTPTunnelUser := FProxyUser; - FSock.HTTPTunnelPass := FProxyPass; - end - else - begin - HttpTunnel := False; - FSock.HTTPTunnelIP := ''; - FSock.HTTPTunnelPort := ''; - FSock.HTTPTunnelUser := ''; - FSock.HTTPTunnelPass := ''; - end; - UsingProxy := (FProxyHost <> '') and not(HttpTunnel); - Sending := FDocument.Size > 0; - {Headers for Sending data} - status100 := FStatus100 and Sending and (FProtocol = '1.1'); - if status100 then - FHeaders.Insert(0, 'Expect: 100-continue'); - if Sending then - begin - FHeaders.Insert(0, 'Content-Length: ' + IntToStr(FDocument.Size)); - if FMimeType <> '' then - FHeaders.Insert(0, 'Content-Type: ' + FMimeType); - end; - { setting User-agent } - if FUserAgent <> '' then - FHeaders.Insert(0, 'User-Agent: ' + FUserAgent); - { setting Ranges } - if (FRangeStart > 0) or (FRangeEnd > 0) then - begin - if FRangeEnd >= FRangeStart then - FHeaders.Insert(0, 'Range: bytes=' + IntToStr(FRangeStart) + '-' + IntToStr(FRangeEnd)) - else - FHeaders.Insert(0, 'Range: bytes=' + IntToStr(FRangeStart) + '-'); - end; - { setting Cookies } - s := ''; - for n := 0 to FCookies.Count - 1 do - begin - if s <> '' then - s := s + '; '; - s := s + FCookies[n]; - end; - if s <> '' then - FHeaders.Insert(0, 'Cookie: ' + s); - { setting KeepAlives } - pp := ''; - if UsingProxy then - pp := 'Proxy-'; - if FKeepAlive then - begin - FHeaders.Insert(0, pp + 'Connection: keep-alive'); - FHeaders.Insert(0, 'Keep-Alive: ' + IntToStr(FKeepAliveTimeout)); - end - else - FHeaders.Insert(0, pp + 'Connection: close'); - { set target servers/proxy, authorizations, etc... } - if User <> '' then - FHeaders.Insert(0, 'Authorization: Basic ' + EncodeBase64(User + ':' + Pass)); - if UsingProxy and (FProxyUser <> '') then - FHeaders.Insert(0, 'Proxy-Authorization: Basic ' + - EncodeBase64(FProxyUser + ':' + FProxyPass)); - if isIP6(Host) then - s := '[' + Host + ']' - else - s := Host; - if FAddPortNumberToHost - and (((Port <> '80') and (UpperCase(Prot) = 'HTTP')) - or ((Port <> '443') and (UpperCase(Prot) = 'HTTPS'))) then - FHeaders.Insert(0, 'Host: ' + s + ':' + Port) - else - FHeaders.Insert(0, 'Host: ' + s); - if UsingProxy then - URI := Prot + '://' + s + ':' + Port + URI; - if URI = '/*' then - URI := '*'; - if FProtocol = '0.9' then - FHeaders.Insert(0, UpperCase(Method) + ' ' + URI) - else - FHeaders.Insert(0, UpperCase(Method) + ' ' + URI + ' HTTP/' + FProtocol); - if UsingProxy then - begin - FTargetHost := FProxyHost; - FTargetPort := FProxyPort; - end - else - begin - FTargetHost := Host; - FTargetPort := Port; - end; - if FHeaders[FHeaders.Count - 1] <> '' then - FHeaders.Add(''); - - { connect } - if not InternalConnect(UpperCase(Prot) = 'HTTPS') then - begin - FAliveHost := ''; - FAlivePort := ''; - Exit; - end; - - { reading Status } - FDocument.Position := 0; - Status100Error := ''; - if status100 then - begin - { send Headers } - FSock.SendString(PrepareHeaders); - if FSock.LastError <> 0 then - Exit; - repeat - s := FSock.RecvString(FTimeout); - if s <> '' then - Break; - until FSock.LastError <> 0; - DecodeStatus(s); - Status100Error := s; - repeat - s := FSock.recvstring(FTimeout); - if s = '' then - Break; - until FSock.LastError <> 0; - if (FResultCode >= 100) and (FResultCode < 200) then - begin - { we can upload content } - Status100Error := ''; - FUploadSize := FDocument.Size; - FSock.SendBuffer(FDocument.Memory, FDocument.Size); - end; - end - else - { upload content } - if sending then - begin - if FDocument.Size >= c64k then - begin - FSock.SendString(PrepareHeaders); - FUploadSize := FDocument.Size; - FSock.SendBuffer(FDocument.Memory, FDocument.Size); - end - else - begin - s := PrepareHeaders + ReadStrFromStream(FDocument, FDocument.Size); - FUploadSize := Length(s); - FSock.SendString(s); - end; - end - else - begin - { we not need to upload document, send headers only } - FSock.SendString(PrepareHeaders); - end; - - if FSock.LastError <> 0 then - Exit; - - Clear; - Size := -1; - FTransferEncoding := TE_UNKNOWN; - - { read status } - if Status100Error = '' then - begin - repeat - repeat - s := FSock.RecvString(FTimeout); - if s <> '' then - Break; - until FSock.LastError <> 0; - if Pos('HTTP/', UpperCase(s)) = 1 then - begin - FHeaders.Add(s); - DecodeStatus(s); - end - else - begin - { old HTTP 0.9 and some buggy servers not send result } - s := s + CRLF; - WriteStrToStream(FDocument, s); - FResultCode := 0; - end; - until (FSock.LastError <> 0) or (FResultCode <> 100); - end - else - FHeaders.Add(Status100Error); - - { if need receive headers, receive and parse it } - ToClose := FProtocol <> '1.1'; - if FHeaders.Count > 0 then - begin - l := TStringList.Create; - try - repeat - s := FSock.RecvString(FTimeout); - l.Add(s); - if s = '' then - Break; - until FSock.LastError <> 0; - x := 0; - while l.Count > x do - begin - s := NormalizeHeader(l, x); - FHeaders.Add(s); - su := UpperCase(s); - if Pos('CONTENT-LENGTH:', su) = 1 then - begin - Size := StrToIntDef(Trim(SeparateRight(s, ':')), -1); - if (Size <> -1) and (FTransferEncoding = TE_UNKNOWN) then - FTransferEncoding := TE_IDENTITY; - end; - if Pos('CONTENT-TYPE:', su) = 1 then - FMimeType := Trim(SeparateRight(s, ':')); - if Pos('TRANSFER-ENCODING:', su) = 1 then - begin - s := Trim(SeparateRight(su, ':')); - if Pos('CHUNKED', s) > 0 then - FTransferEncoding := TE_CHUNKED; - end; - if UsingProxy then - begin - if Pos('PROXY-CONNECTION:', su) = 1 then - if Pos('CLOSE', su) > 0 then - ToClose := True; - end - else - begin - if Pos('CONNECTION:', su) = 1 then - if Pos('CLOSE', su) > 0 then - ToClose := True; - end; - end; - finally - l.free; - end; - end; - - Result := FSock.LastError = 0; - if not Result then - Exit; - - {if need receive response body, read it} - Receiving := Method <> 'HEAD'; - Receiving := Receiving and (FResultCode <> 204); - Receiving := Receiving and (FResultCode <> 304); - if Receiving then - case FTransferEncoding of - TE_UNKNOWN: - Result := ReadUnknown; - TE_IDENTITY: - Result := ReadIdentity(Size); - TE_CHUNKED: - Result := ReadChunked; - end; - - FDocument.Seek(0, soFromBeginning); - if ToClose then - begin - FSock.CloseSocket; - FAliveHost := ''; - FAlivePort := ''; - end; - ParseCookies; -end; - -function THTTPSend.ReadUnknown: Boolean; -var - s: ansistring; -begin - Result := false; - repeat - s := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - WriteStrToStream(FDocument, s); - until FSock.LastError <> 0; - if FSock.LastError = WSAECONNRESET then - begin - Result := true; - FSock.ResetLastError; - end; -end; - -function THTTPSend.ReadIdentity(Size: Integer): Boolean; -begin - if Size > 0 then - begin - FDownloadSize := Size; - FSock.RecvStreamSize(FDocument, FTimeout, Size); - FDocument.Position := FDocument.Size; - Result := FSock.LastError = 0; - end - else - Result := true; -end; - -function THTTPSend.ReadChunked: Boolean; -var - s: ansistring; - Size: Integer; -begin - repeat - repeat - s := FSock.RecvString(FTimeout); - until (s <> '') or (FSock.LastError <> 0); - if FSock.LastError <> 0 then - Break; - s := Trim(SeparateLeft(s, ' ')); - s := Trim(SeparateLeft(s, ';')); - Size := StrToIntDef('$' + s, 0); - if Size = 0 then - Break; - if not ReadIdentity(Size) then - break; - until False; - Result := FSock.LastError = 0; -end; - -procedure THTTPSend.ParseCookies; -var - n: integer; - s: string; - sn, sv: string; -begin - for n := 0 to FHeaders.Count - 1 do - if Pos('set-cookie:', lowercase(FHeaders[n])) = 1 then - begin - s := SeparateRight(FHeaders[n], ':'); - s := trim(SeparateLeft(s, ';')); - sn := trim(SeparateLeft(s, '=')); - sv := trim(SeparateRight(s, '=')); - FCookies.Values[sn] := sv; - end; -end; - -procedure THTTPSend.Abort; -begin - FSock.StopFlag := True; -end; - -{==============================================================================} - -function HttpGetText(const URL: string; const Response: TStrings): Boolean; -var - HTTP: THTTPSend; -begin - HTTP := THTTPSend.Create; - try - Result := HTTP.HTTPMethod('GET', URL); - if Result then - Response.LoadFromStream(HTTP.Document); - finally - HTTP.Free; - end; -end; - -function HttpGetBinary(const URL: string; const Response: TStream): Boolean; -var - HTTP: THTTPSend; -begin - HTTP := THTTPSend.Create; - try - Result := HTTP.HTTPMethod('GET', URL); - if Result then - begin - Response.Seek(0, soFromBeginning); - Response.CopyFrom(HTTP.Document, 0); - end; - finally - HTTP.Free; - end; -end; - -function HttpPostBinary(const URL: string; const Data: TStream): Boolean; -var - HTTP: THTTPSend; -begin - HTTP := THTTPSend.Create; - try - HTTP.Document.CopyFrom(Data, 0); - HTTP.MimeType := 'Application/octet-stream'; - Result := HTTP.HTTPMethod('POST', URL); - Data.Size := 0; - if Result then - begin - Data.Seek(0, soFromBeginning); - Data.CopyFrom(HTTP.Document, 0); - end; - finally - HTTP.Free; - end; -end; - -function HttpPostURL(const URL, URLData: string; const Data: TStream): Boolean; -var - HTTP: THTTPSend; -begin - HTTP := THTTPSend.Create; - try - WriteStrToStream(HTTP.Document, URLData); - HTTP.MimeType := 'application/x-www-form-urlencoded'; - Result := HTTP.HTTPMethod('POST', URL); - if Result then - Data.CopyFrom(HTTP.Document, 0); - finally - HTTP.Free; - end; -end; - -function HttpPostFile(const URL, FieldName, FileName: string; - const Data: TStream; const ResultData: TStrings): Boolean; -var - HTTP: THTTPSend; - Bound, s: string; -begin - Bound := IntToHex(Random(MaxInt), 8) + '_Synapse_boundary'; - HTTP := THTTPSend.Create; - try - s := '--' + Bound + CRLF; - s := s + 'content-disposition: form-data; name="' + FieldName + '";'; - s := s + ' filename="' + FileName +'"' + CRLF; - s := s + 'Content-Type: Application/octet-string' + CRLF + CRLF; - WriteStrToStream(HTTP.Document, s); - HTTP.Document.CopyFrom(Data, 0); - s := CRLF + '--' + Bound + '--' + CRLF; - WriteStrToStream(HTTP.Document, s); - HTTP.MimeType := 'multipart/form-data; boundary=' + Bound; - Result := HTTP.HTTPMethod('POST', URL); - if Result then - ResultData.LoadFromStream(HTTP.Document); - finally - HTTP.Free; - end; -end; - -end. diff --git a/3rd/synapse/source/imapsend.pas b/3rd/synapse/source/imapsend.pas deleted file mode 100644 index 85ac3fa23..000000000 --- a/3rd/synapse/source/imapsend.pas +++ /dev/null @@ -1,869 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.005.003 | -|==============================================================================| -| Content: IMAP4rev1 client | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(IMAP4 rev1 protocol client) - -Used RFC: RFC-2060, RFC-2595 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit imapsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil; - -const - cIMAPProtocol = '143'; - -type - {:@abstract(Implementation of IMAP4 protocol.) - Note: Are you missing properties for setting Username and Password? Look to - parent @link(TSynaClient) object! - - Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TIMAPSend = class(TSynaClient) - protected - FSock: TTCPBlockSocket; - FTagCommand: integer; - FResultString: string; - FFullResult: TStringList; - FIMAPcap: TStringList; - FAuthDone: Boolean; - FSelectedFolder: string; - FSelectedCount: integer; - FSelectedRecent: integer; - FSelectedUIDvalidity: integer; - FUID: Boolean; - FAutoTLS: Boolean; - FFullSSL: Boolean; - function ReadResult: string; - function AuthLogin: Boolean; - function Connect: Boolean; - procedure ParseMess(Value:TStrings); - procedure ParseFolderList(Value:TStrings); - procedure ParseSelect; - procedure ParseSearch(Value:TStrings); - procedure ProcessLiterals; - public - constructor Create; - destructor Destroy; override; - - {:By this function you can call any IMAP command. Result of this command is - in adequate properties.} - function IMAPcommand(Value: string): string; - - {:By this function you can call any IMAP command what need upload any data. - Result of this command is in adequate properties.} - function IMAPuploadCommand(Value: string; const Data:TStrings): string; - - {:Call CAPABILITY command and fill IMAPcap property by new values.} - function Capability: Boolean; - - {:Connect to IMAP server and do login to this server. This command begin - session.} - function Login: Boolean; - - {:Disconnect from IMAP server and terminate session session. If exists some - deleted and non-purged messages, these messages are not deleted!} - function Logout: Boolean; - - {:Do NOOP. It is for prevent disconnect by timeout.} - function NoOp: Boolean; - - {:Lists folder names. You may specify level of listing. If you specify - FromFolder as empty string, return is all folders in system.} - function List(FromFolder: string; const FolderList: TStrings): Boolean; - - {:Lists folder names what match search criteria. You may specify level of - listing. If you specify FromFolder as empty string, return is all folders - in system.} - function ListSearch(FromFolder, Search: string; const FolderList: TStrings): Boolean; - - {:Lists subscribed folder names. You may specify level of listing. If you - specify FromFolder as empty string, return is all subscribed folders in - system.} - function ListSubscribed(FromFolder: string; const FolderList: TStrings): Boolean; - - {:Lists subscribed folder names what matching search criteria. You may - specify level of listing. If you specify FromFolder as empty string, return - is all subscribed folders in system.} - function ListSearchSubscribed(FromFolder, Search: string; const FolderList: TStrings): Boolean; - - {:Create a new folder.} - function CreateFolder(FolderName: string): Boolean; - - {:Delete a folder.} - function DeleteFolder(FolderName: string): Boolean; - - {:Rename folder names.} - function RenameFolder(FolderName, NewFolderName: string): Boolean; - - {:Subscribe folder.} - function SubscribeFolder(FolderName: string): Boolean; - - {:Unsubscribe folder.} - function UnsubscribeFolder(FolderName: string): Boolean; - - {:Select folder.} - function SelectFolder(FolderName: string): Boolean; - - {:Select folder, but only for reading. Any changes are not allowed!} - function SelectROFolder(FolderName: string): Boolean; - - {:Close a folder. (end of Selected state)} - function CloseFolder: Boolean; - - {:Ask for given status of folder. I.e. if you specify as value 'UNSEEN', - result is number of unseen messages in folder. For another status - indentificator check IMAP documentation and documentation of your IMAP - server (each IMAP server can have their own statuses.)} - function StatusFolder(FolderName, Value: string): integer; - - {:Hardly delete all messages marked as 'deleted' in current selected folder.} - function ExpungeFolder: Boolean; - - {:Touch to folder. (use as update status of folder, etc.)} - function CheckFolder: Boolean; - - {:Append given message to specified folder.} - function AppendMess(ToFolder: string; const Mess: TStrings): Boolean; - - {:'Delete' message from current selected folder. It mark message as Deleted. - Real deleting will be done after sucessfull @link(CloseFolder) or - @link(ExpungeFolder)} - function DeleteMess(MessID: integer): boolean; - - {:Get full message from specified message in selected folder.} - function FetchMess(MessID: integer; const Mess: TStrings): Boolean; - - {:Get message headers only from specified message in selected folder.} - function FetchHeader(MessID: integer; const Headers: TStrings): Boolean; - - {:Return message size of specified message from current selected folder.} - function MessageSize(MessID: integer): integer; - - {:Copy message from current selected folder to another folder.} - function CopyMess(MessID: integer; ToFolder: string): Boolean; - - {:Return message numbers from currently selected folder as result - of searching. Search criteria is very complex language (see to IMAP - specification) similar to SQL (but not same syntax!).} - function SearchMess(Criteria: string; const FoundMess: TStrings): Boolean; - - {:Sets flags of message from current selected folder.} - function SetFlagsMess(MessID: integer; Flags: string): Boolean; - - {:Gets flags of message from current selected folder.} - function GetFlagsMess(MessID: integer; var Flags: string): Boolean; - - {:Add flags to message's flags.} - function AddFlagsMess(MessID: integer; Flags: string): Boolean; - - {:Remove flags from message's flags.} - function DelFlagsMess(MessID: integer; Flags: string): Boolean; - - {:Call STARTTLS command for upgrade connection to SSL/TLS mode.} - function StartTLS: Boolean; - - {:return UID of requested message ID.} - function GetUID(MessID: integer; var UID : Integer): Boolean; - - {:Try to find given capabily in capabilty string returned from IMAP server.} - function FindCap(const Value: string): string; - published - {:Status line with result of last operation.} - property ResultString: string read FResultString; - - {:Full result of last IMAP operation.} - property FullResult: TStringList read FFullResult; - - {:List of server capabilites.} - property IMAPcap: TStringList read FIMAPcap; - - {:Authorization is successful done.} - property AuthDone: Boolean read FAuthDone; - - {:Turn on or off usage of UID (unicate identificator) of messages instead - only sequence numbers.} - property UID: Boolean read FUID Write FUID; - - {:Name of currently selected folder.} - property SelectedFolder: string read FSelectedFolder; - - {:Count of messages in currently selected folder.} - property SelectedCount: integer read FSelectedCount; - - {:Count of not-visited messages in currently selected folder.} - property SelectedRecent: integer read FSelectedRecent; - - {:This number with name of folder is unique indentificator of folder. - (If someone delete folder and next create new folder with exactly same name - of folder, this number is must be different!)} - property SelectedUIDvalidity: integer read FSelectedUIDvalidity; - - {:If is set to true, then upgrade to SSL/TLS mode if remote server support it.} - property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; - - {:SSL/TLS mode is used from first contact to server. Servers with full - SSL/TLS mode usualy using non-standard TCP port!} - property FullSSL: Boolean read FFullSSL Write FFullSSL; - - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - end; - -implementation - -constructor TIMAPSend.Create; -begin - inherited Create; - FFullResult := TStringList.Create; - FIMAPcap := TStringList.Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.ConvertLineEnd := True; - FSock.SizeRecvBuffer := 32768; - FSock.SizeSendBuffer := 32768; - FTimeout := 60000; - FTargetPort := cIMAPProtocol; - FTagCommand := 0; - FSelectedFolder := ''; - FSelectedCount := 0; - FSelectedRecent := 0; - FSelectedUIDvalidity := 0; - FUID := False; - FAutoTLS := False; - FFullSSL := False; -end; - -destructor TIMAPSend.Destroy; -begin - FSock.Free; - FIMAPcap.Free; - FFullResult.Free; - inherited Destroy; -end; - - -function TIMAPSend.ReadResult: string; -var - s: string; - x, l: integer; -begin - Result := ''; - FFullResult.Clear; - FResultString := ''; - repeat - s := FSock.RecvString(FTimeout); - if Pos('S' + IntToStr(FTagCommand) + ' ', s) = 1 then - begin - FResultString := s; - break; - end - else - FFullResult.Add(s); - if (s <> '') and (s[Length(s)]='}') then - begin - s := Copy(s, 1, Length(s) - 1); - x := RPos('{', s); - s := Copy(s, x + 1, Length(s) - x); - l := StrToIntDef(s, -1); - if l <> -1 then - begin - s := FSock.RecvBufferStr(l, FTimeout); - FFullResult.Add(s); - end; - end; - until FSock.LastError <> 0; - s := Trim(separateright(FResultString, ' ')); - Result:=uppercase(Trim(separateleft(s, ' '))); -end; - -procedure TIMAPSend.ProcessLiterals; -var - l: TStringList; - n, x: integer; - b: integer; - s: string; -begin - l := TStringList.Create; - try - l.Assign(FFullResult); - FFullResult.Clear; - b := 0; - for n := 0 to l.Count - 1 do - begin - s := l[n]; - if b > 0 then - begin - FFullResult[FFullresult.Count - 1] := - FFullResult[FFullresult.Count - 1] + s; - inc(b); - if b > 2 then - b := 0; - end - else - begin - if (s <> '') and (s[Length(s)]='}') then - begin - x := RPos('{', s); - Delete(s, x, Length(s) - x + 1); - b := 1; - end - else - b := 0; - FFullResult.Add(s); - end; - end; - finally - l.Free; - end; -end; - -function TIMAPSend.IMAPcommand(Value: string): string; -begin - Inc(FTagCommand); - FSock.SendString('S' + IntToStr(FTagCommand) + ' ' + Value + CRLF); - Result := ReadResult; -end; - -function TIMAPSend.IMAPuploadCommand(Value: string; const Data:TStrings): string; -var - l: integer; -begin - Inc(FTagCommand); - l := Length(Data.Text); - FSock.SendString('S' + IntToStr(FTagCommand) + ' ' + Value + ' {'+ IntToStr(l) + '}' + CRLF); - FSock.RecvString(FTimeout); - FSock.SendString(Data.Text + CRLF); - Result := ReadResult; -end; - -procedure TIMAPSend.ParseMess(Value:TStrings); -var - n: integer; -begin - Value.Clear; - for n := 0 to FFullResult.Count - 2 do - if (length(FFullResult[n]) > 0) and (FFullResult[n][Length(FFullResult[n])] = '}') then - begin - Value.Text := FFullResult[n + 1]; - Break; - end; -end; - -procedure TIMAPSend.ParseFolderList(Value:TStrings); -var - n, x: integer; - s: string; -begin - ProcessLiterals; - Value.Clear; - for n := 0 to FFullResult.Count - 1 do - begin - s := FFullResult[n]; - if (s <> '') and (Pos('\NOSELECT', UpperCase(s)) = 0) then - begin - if s[Length(s)] = '"' then - begin - Delete(s, Length(s), 1); - x := RPos('"', s); - end - else - x := RPos(' ', s); - if (x > 0) then - Value.Add(Copy(s, x + 1, Length(s) - x)); - end; - end; -end; - -procedure TIMAPSend.ParseSelect; -var - n: integer; - s, t: string; -begin - ProcessLiterals; - FSelectedCount := 0; - FSelectedRecent := 0; - FSelectedUIDvalidity := 0; - for n := 0 to FFullResult.Count - 1 do - begin - s := uppercase(FFullResult[n]); - if Pos(' EXISTS', s) > 0 then - begin - t := Trim(separateleft(s, ' EXISTS')); - t := Trim(separateright(t, '* ')); - FSelectedCount := StrToIntDef(t, 0); - end; - if Pos(' RECENT', s) > 0 then - begin - t := Trim(separateleft(s, ' RECENT')); - t := Trim(separateright(t, '* ')); - FSelectedRecent := StrToIntDef(t, 0); - end; - if Pos('UIDVALIDITY', s) > 0 then - begin - t := Trim(separateright(s, 'UIDVALIDITY ')); - t := Trim(separateleft(t, ']')); - FSelectedUIDvalidity := StrToIntDef(t, 0); - end; - end; -end; - -procedure TIMAPSend.ParseSearch(Value:TStrings); -var - n: integer; - s: string; -begin - ProcessLiterals; - Value.Clear; - for n := 0 to FFullResult.Count - 1 do - begin - s := uppercase(FFullResult[n]); - if Pos('* SEARCH', s) = 1 then - begin - s := Trim(SeparateRight(s, '* SEARCH')); - while s <> '' do - Value.Add(Fetch(s, ' ')); - end; - end; -end; - -function TIMAPSend.FindCap(const Value: string): string; -var - n: Integer; - s: string; -begin - s := UpperCase(Value); - Result := ''; - for n := 0 to FIMAPcap.Count - 1 do - if Pos(s, UpperCase(FIMAPcap[n])) = 1 then - begin - Result := FIMAPcap[n]; - Break; - end; -end; - -function TIMAPSend.AuthLogin: Boolean; -begin - Result := IMAPcommand('LOGIN "' + FUsername + '" "' + FPassword + '"') = 'OK'; -end; - -function TIMAPSend.Connect: Boolean; -begin - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError = 0 then - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError = 0 then - if FFullSSL then - FSock.SSLDoConnect; - Result := FSock.LastError = 0; -end; - -function TIMAPSend.Capability: Boolean; -var - n: Integer; - s, t: string; -begin - Result := False; - FIMAPcap.Clear; - s := IMAPcommand('CAPABILITY'); - if s = 'OK' then - begin - ProcessLiterals; - for n := 0 to FFullResult.Count - 1 do - if Pos('* CAPABILITY ', FFullResult[n]) = 1 then - begin - s := Trim(SeparateRight(FFullResult[n], '* CAPABILITY ')); - while not (s = '') do - begin - t := Trim(separateleft(s, ' ')); - s := Trim(separateright(s, ' ')); - if s = t then - s := ''; - FIMAPcap.Add(t); - end; - end; - Result := True; - end; -end; - -function TIMAPSend.Login: Boolean; -var - s: string; -begin - FSelectedFolder := ''; - FSelectedCount := 0; - FSelectedRecent := 0; - FSelectedUIDvalidity := 0; - Result := False; - FAuthDone := False; - if not Connect then - Exit; - s := FSock.RecvString(FTimeout); - if Pos('* PREAUTH', s) = 1 then - FAuthDone := True - else - if Pos('* OK', s) = 1 then - FAuthDone := False - else - Exit; - if Capability then - begin - if Findcap('IMAP4rev1') = '' then - Exit; - if FAutoTLS and (Findcap('STARTTLS') <> '') then - if StartTLS then - Capability; - end; - Result := AuthLogin; -end; - -function TIMAPSend.Logout: Boolean; -begin - Result := IMAPcommand('LOGOUT') = 'OK'; - FSelectedFolder := ''; - FSock.CloseSocket; -end; - -function TIMAPSend.NoOp: Boolean; -begin - Result := IMAPcommand('NOOP') = 'OK'; -end; - -function TIMAPSend.List(FromFolder: string; const FolderList: TStrings): Boolean; -begin - Result := IMAPcommand('LIST "' + FromFolder + '" *') = 'OK'; - ParseFolderList(FolderList); -end; - -function TIMAPSend.ListSearch(FromFolder, Search: string; const FolderList: TStrings): Boolean; -begin - Result := IMAPcommand('LIST "' + FromFolder + '" "' + Search +'"') = 'OK'; - ParseFolderList(FolderList); -end; - -function TIMAPSend.ListSubscribed(FromFolder: string; const FolderList: TStrings): Boolean; -begin - Result := IMAPcommand('LSUB "' + FromFolder + '" *') = 'OK'; - ParseFolderList(FolderList); -end; - -function TIMAPSend.ListSearchSubscribed(FromFolder, Search: string; const FolderList: TStrings): Boolean; -begin - Result := IMAPcommand('LSUB "' + FromFolder + '" "' + Search +'"') = 'OK'; - ParseFolderList(FolderList); -end; - -function TIMAPSend.CreateFolder(FolderName: string): Boolean; -begin - Result := IMAPcommand('CREATE "' + FolderName + '"') = 'OK'; -end; - -function TIMAPSend.DeleteFolder(FolderName: string): Boolean; -begin - Result := IMAPcommand('DELETE "' + FolderName + '"') = 'OK'; -end; - -function TIMAPSend.RenameFolder(FolderName, NewFolderName: string): Boolean; -begin - Result := IMAPcommand('RENAME "' + FolderName + '" "' + NewFolderName + '"') = 'OK'; -end; - -function TIMAPSend.SubscribeFolder(FolderName: string): Boolean; -begin - Result := IMAPcommand('SUBSCRIBE "' + FolderName + '"') = 'OK'; -end; - -function TIMAPSend.UnsubscribeFolder(FolderName: string): Boolean; -begin - Result := IMAPcommand('UNSUBSCRIBE "' + FolderName + '"') = 'OK'; -end; - -function TIMAPSend.SelectFolder(FolderName: string): Boolean; -begin - Result := IMAPcommand('SELECT "' + FolderName + '"') = 'OK'; - FSelectedFolder := FolderName; - ParseSelect; -end; - -function TIMAPSend.SelectROFolder(FolderName: string): Boolean; -begin - Result := IMAPcommand('EXAMINE "' + FolderName + '"') = 'OK'; - FSelectedFolder := FolderName; - ParseSelect; -end; - -function TIMAPSend.CloseFolder: Boolean; -begin - Result := IMAPcommand('CLOSE') = 'OK'; - FSelectedFolder := ''; -end; - -function TIMAPSend.StatusFolder(FolderName, Value: string): integer; -var - n: integer; - s, t: string; -begin - Result := -1; - Value := Uppercase(Value); - if IMAPcommand('STATUS "' + FolderName + '" (' + Value + ')' ) = 'OK' then - begin - ProcessLiterals; - for n := 0 to FFullResult.Count - 1 do - begin - s := FFullResult[n]; -// s := UpperCase(FFullResult[n]); - if (Pos('* ', s) = 1) and (Pos(FolderName, s) >= 1) and (Pos(Value, s) > 0 ) then - begin - t := SeparateRight(s, Value); - t := SeparateLeft(t, ')'); - t := trim(t); - Result := StrToIntDef(t, -1); - Break; - end; - end; - end; -end; - -function TIMAPSend.ExpungeFolder: Boolean; -begin - Result := IMAPcommand('EXPUNGE') = 'OK'; -end; - -function TIMAPSend.CheckFolder: Boolean; -begin - Result := IMAPcommand('CHECK') = 'OK'; -end; - -function TIMAPSend.AppendMess(ToFolder: string; const Mess: TStrings): Boolean; -begin - Result := IMAPuploadCommand('APPEND "' + ToFolder + '"', Mess) = 'OK'; -end; - -function TIMAPSend.DeleteMess(MessID: integer): boolean; -var - s: string; -begin - s := 'STORE ' + IntToStr(MessID) + ' +FLAGS.SILENT (\Deleted)'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; -end; - -function TIMAPSend.FetchMess(MessID: integer; const Mess: TStrings): Boolean; -var - s: string; -begin - s := 'FETCH ' + IntToStr(MessID) + ' (RFC822)'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; - ParseMess(Mess); -end; - -function TIMAPSend.FetchHeader(MessID: integer; const Headers: TStrings): Boolean; -var - s: string; -begin - s := 'FETCH ' + IntToStr(MessID) + ' (RFC822.HEADER)'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; - ParseMess(Headers); -end; - -function TIMAPSend.MessageSize(MessID: integer): integer; -var - n: integer; - s, t: string; -begin - Result := -1; - s := 'FETCH ' + IntToStr(MessID) + ' (RFC822.SIZE)'; - if FUID then - s := 'UID ' + s; - if IMAPcommand(s) = 'OK' then - begin - ProcessLiterals; - for n := 0 to FFullResult.Count - 1 do - begin - s := UpperCase(FFullResult[n]); - if (Pos('* ', s) = 1) and (Pos('RFC822.SIZE', s) > 0 ) then - begin - t := SeparateRight(s, 'RFC822.SIZE '); - t := Trim(SeparateLeft(t, ')')); - t := Trim(SeparateLeft(t, ' ')); - Result := StrToIntDef(t, -1); - Break; - end; - end; - end; -end; - -function TIMAPSend.CopyMess(MessID: integer; ToFolder: string): Boolean; -var - s: string; -begin - s := 'COPY ' + IntToStr(MessID) + ' "' + ToFolder + '"'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; -end; - -function TIMAPSend.SearchMess(Criteria: string; const FoundMess: TStrings): Boolean; -var - s: string; -begin - s := 'SEARCH ' + Criteria; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; - ParseSearch(FoundMess); -end; - -function TIMAPSend.SetFlagsMess(MessID: integer; Flags: string): Boolean; -var - s: string; -begin - s := 'STORE ' + IntToStr(MessID) + ' FLAGS.SILENT (' + Flags + ')'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; -end; - -function TIMAPSend.AddFlagsMess(MessID: integer; Flags: string): Boolean; -var - s: string; -begin - s := 'STORE ' + IntToStr(MessID) + ' +FLAGS.SILENT (' + Flags + ')'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; -end; - -function TIMAPSend.DelFlagsMess(MessID: integer; Flags: string): Boolean; -var - s: string; -begin - s := 'STORE ' + IntToStr(MessID) + ' -FLAGS.SILENT (' + Flags + ')'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; -end; - -function TIMAPSend.GetFlagsMess(MessID: integer; var Flags: string): Boolean; -var - s: string; - n: integer; -begin - Flags := ''; - s := 'FETCH ' + IntToStr(MessID) + ' (FLAGS)'; - if FUID then - s := 'UID ' + s; - Result := IMAPcommand(s) = 'OK'; - ProcessLiterals; - for n := 0 to FFullResult.Count - 1 do - begin - s := uppercase(FFullResult[n]); - if (Pos('* ', s) = 1) and (Pos('FLAGS', s) > 0 ) then - begin - s := SeparateRight(s, 'FLAGS'); - s := Separateright(s, '('); - Flags := Trim(SeparateLeft(s, ')')); - end; - end; -end; - -function TIMAPSend.StartTLS: Boolean; -begin - Result := False; - if FindCap('STARTTLS') <> '' then - begin - if IMAPcommand('STARTTLS') = 'OK' then - begin - Fsock.SSLDoConnect; - Result := FSock.LastError = 0; - end; - end; -end; - -//Paul Buskermolen <p.buskermolen@pinkroccade.com> -function TIMAPSend.GetUID(MessID: integer; var UID : Integer): boolean; -var - s, sUid: string; - n: integer; -begin - sUID := ''; - s := 'FETCH ' + IntToStr(MessID) + ' UID'; - Result := IMAPcommand(s) = 'OK'; - ProcessLiterals; - for n := 0 to FFullResult.Count - 1 do - begin - s := uppercase(FFullResult[n]); - if Pos('FETCH (UID', s) >= 1 then - begin - s := Separateright(s, '(UID '); - sUID := Trim(SeparateLeft(s, ')')); - end; - end; - UID := StrToIntDef(sUID, 0); -end; - -{==============================================================================} - -end. diff --git a/3rd/synapse/source/jedi.inc b/3rd/synapse/source/jedi.inc deleted file mode 100644 index d1b456302..000000000 --- a/3rd/synapse/source/jedi.inc +++ /dev/null @@ -1,1430 +0,0 @@ -{$IFNDEF JEDI_INC} -{$DEFINE JEDI_INC} - -{**************************************************************************************************} -{ } -{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License");} -{ you may not use this file except in compliance with the License. You may obtain a copy of the } -{ License at http://www.mozilla.org/MPL/ } -{ } -{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } -{ ANY KIND, either express or implied. See the License for the specific language governing rights } -{ and limitations under the License. } -{ } -{ The Original Code is: jedi.inc. } -{ The Initial Developer of the Original Code is Project JEDI http://www.delphi-jedi.org } -{ } -{ Alternatively, the contents of this file may be used under the terms of the GNU Lesser General } -{ Public License (the "LGPL License"), in which case the provisions of the LGPL License are } -{ applicable instead of those above. If you wish to allow use of your version of this file only } -{ under the terms of the LGPL License and not to allow others to use your version of this file } -{ under the MPL, indicate your decision by deleting the provisions above and replace them with } -{ the notice and other provisions required by the LGPL License. If you do not delete the } -{ provisions above, a recipient may use your version of this file under either the MPL or the } -{ LGPL License. } -{ } -{ For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } -{ } -{**************************************************************************************************} -{ } -{ This file defines various generic compiler directives used in different libraries, e.g. in the } -{ JEDI Code Library (JCL) and JEDI Visual Component Library Library (JVCL). The directives in } -{ this file are of generic nature and consist mostly of mappings from the VERXXX directives } -{ defined by Delphi, C++Builder and FPC to friendly names such as DELPHI5 and } -{ SUPPORTS_WIDESTRING. These friendly names are subsequently used in the libraries to test for } -{ compiler versions and/or whether the compiler supports certain features (such as widestrings or } -{ 64 bit integers. The libraries provide an additional, library specific, include file. For the } -{ JCL e.g. this is jcl.inc. These files should be included in source files instead of this file } -{ (which is pulled in automatically). } -{ } -{**************************************************************************************************} -{ } -{ Last modified: $Date:: 2012-09-04 16:01:38 +0200 (út, 04 9 2012) $ } -{ Revision: $Rev:: 161 $ } -{ Author: $Author:: outchy $ } -{ } -{**************************************************************************************************} - -(* - -- Development environment directives - - This file defines two directives to indicate which development environment the - library is being compiled with. Currently this can either be Delphi, Kylix, - C++Builder or FPC. - - Directive Description - ------------------------------------------------------------------------------ - DELPHI Defined if compiled with Delphi - KYLIX Defined if compiled with Kylix - DELPHICOMPILER Defined if compiled with Delphi or Kylix/Delphi - BCB Defined if compiled with C++Builder - CPPBUILDER Defined if compiled with C++Builder (alias for BCB) - BCBCOMPILER Defined if compiled with C++Builder or Kylix/C++ - DELPHILANGUAGE Defined if compiled with Delphi, Kylix or C++Builder - BORLAND Defined if compiled with Delphi, Kylix or C++Builder - FPC Defined if compiled with FPC - -- Platform Directives - - Platform directives are not all explicitly defined in this file, some are - defined by the compiler itself. They are listed here only for completeness. - - Directive Description - ------------------------------------------------------------------------------ - WIN32 Defined when target platform is 32 bit Windows - WIN64 Defined when target platform is 64 bit Windows - MSWINDOWS Defined when target platform is 32 bit Windows - LINUX Defined when target platform is Linux - UNIX Defined when target platform is Unix-like (including Linux) - CLR Defined when target platform is .NET - -- Architecture directives. These are auto-defined by FPC - CPU32 and CPU64 are mostly for generic pointer size dependant differences rather - than for a specific architecture. - - CPU386 Defined when target platform is native x86 (win32) - CPUx86_64 Defined when target platform is native x86_64 (win64) - CPU32 Defined when target is 32-bit - CPU64 Defined when target is 64-bit - CPUASM Defined when target assembler is available - -- Visual library Directives - - The following directives indicate for a visual library. In a Delphi/BCB - (Win32) application you need to define the VisualCLX symbol in the project - options, if you want to use the VisualCLX library. Alternatively you can use - the IDE expert, which is distributed with the JCL to do this automatically. - - Directive Description - ------------------------------------------------------------------------------ - VCL Defined for Delphi/BCB (Win32) exactly if VisualCLX is not defined - VisualCLX Defined for Kylix; needs to be defined for Delphi/BCB to - use JCL with VisualCLX applications. - - -- Other cross-platform related defines - - These symbols are intended to help in writing portable code. - - Directive Description - ------------------------------------------------------------------------------ - PUREPASCAL Code is machine-independent (as opposed to assembler code) - Win32API Code is specific for the Win32 API; - use instead of "{$IFNDEF CLR} {$IFDEF MSWINDOWS}" constructs - - -- Delphi Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. These directives are only defined if - the compiler is Delphi (ie DELPHI is defined). - - Directive Description - ------------------------------------------------------------------------------ - DELPHI1 Defined when compiling with Delphi 1 (Codename WASABI/MANGO) - DELPHI2 Defined when compiling with Delphi 2 (Codename POLARIS) - DELPHI3 Defined when compiling with Delphi 3 (Codename IVORY) - DELPHI4 Defined when compiling with Delphi 4 (Codename ALLEGRO) - DELPHI5 Defined when compiling with Delphi 5 (Codename ARGUS) - DELPHI6 Defined when compiling with Delphi 6 (Codename ILLIAD) - DELPHI7 Defined when compiling with Delphi 7 (Codename AURORA) - DELPHI8 Defined when compiling with Delphi 8 (Codename OCTANE) - DELPHI2005 Defined when compiling with Delphi 2005 (Codename DIAMONDBACK) - DELPHI9 Alias for DELPHI2005 - DELPHI10 Defined when compiling with Delphi 2006 (Codename DEXTER) - DELPHI2006 Alias for DELPHI10 - DELPHI11 Defined when compiling with Delphi 2007 for Win32 (Codename SPACELY) - DELPHI2007 Alias for DELPHI11 - DELPHI12 Defined when compiling with Delphi 2009 for Win32 (Codename TIBURON) - DELPHI2009 Alias for DELPHI12 - DELPHI14 Defined when compiling with Delphi 2010 for Win32 (Codename WEAVER) - DELPHI2010 Alias for DELPHI14 - DELPHI15 Defined when compiling with Delphi XE for Win32 (Codename FULCRUM) - DELPHIXE Alias for DELPHI15 - DELPHI16 Defined when compiling with Delphi XE2 for Win32 (Codename PULSAR) - DELPHIXE2 Alias for DELPHI16 - DELPHI17 Defined when compiling with Delphi XE3 for Win32 (Codename WATERDRAGON) - DELPHIXE3 Alias for DELPHI17 - DELPHI1_UP Defined when compiling with Delphi 1 or higher - DELPHI2_UP Defined when compiling with Delphi 2 or higher - DELPHI3_UP Defined when compiling with Delphi 3 or higher - DELPHI4_UP Defined when compiling with Delphi 4 or higher - DELPHI5_UP Defined when compiling with Delphi 5 or higher - DELPHI6_UP Defined when compiling with Delphi 6 or higher - DELPHI7_UP Defined when compiling with Delphi 7 or higher - DELPHI8_UP Defined when compiling with Delphi 8 or higher - DELPHI2005_UP Defined when compiling with Delphi 2005 or higher - DELPHI9_UP Alias for DELPHI2005_UP - DELPHI10_UP Defined when compiling with Delphi 2006 or higher - DELPHI2006_UP Alias for DELPHI10_UP - DELPHI11_UP Defined when compiling with Delphi 2007 for Win32 or higher - DELPHI2007_UP Alias for DELPHI11_UP - DELPHI12_UP Defined when compiling with Delphi 2009 for Win32 or higher - DELPHI2009_UP Alias for DELPHI12_UP - DELPHI14_UP Defined when compiling with Delphi 2010 for Win32 or higher - DELPHI2010_UP Alias for DELPHI14_UP - DELPHI15_UP Defined when compiling with Delphi XE for Win32 or higher - DELPHIXE_UP Alias for DELPHI15_UP - DELPHI16_UP Defined when compiling with Delphi XE2 for Win32 or higher - DELPHIXE2_UP Alias for DELPHI16_UP - DELPHI17_UP Defined when compiling with Delphi XE3 for Win32 or higher - DELPHIXE3_UP Alias for DELPHI17_UP - - -- Kylix Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. These directives are only defined if - the compiler is Kylix (ie KYLIX is defined). - - Directive Description - ------------------------------------------------------------------------------ - KYLIX1 Defined when compiling with Kylix 1 - KYLIX2 Defined when compiling with Kylix 2 - KYLIX3 Defined when compiling with Kylix 3 (Codename CORTEZ) - KYLIX1_UP Defined when compiling with Kylix 1 or higher - KYLIX2_UP Defined when compiling with Kylix 2 or higher - KYLIX3_UP Defined when compiling with Kylix 3 or higher - - -- Delphi Compiler Versions (Delphi / Kylix, not in BCB mode) - - Directive Description - ------------------------------------------------------------------------------ - DELPHICOMPILER1 Defined when compiling with Delphi 1 - DELPHICOMPILER2 Defined when compiling with Delphi 2 - DELPHICOMPILER3 Defined when compiling with Delphi 3 - DELPHICOMPILER4 Defined when compiling with Delphi 4 - DELPHICOMPILER5 Defined when compiling with Delphi 5 - DELPHICOMPILER6 Defined when compiling with Delphi 6 or Kylix 1, 2 or 3 - DELPHICOMPILER7 Defined when compiling with Delphi 7 - DELPHICOMPILER8 Defined when compiling with Delphi 8 - DELPHICOMPILER9 Defined when compiling with Delphi 2005 - DELPHICOMPILER10 Defined when compiling with Delphi Personality of BDS 4.0 - DELPHICOMPILER11 Defined when compiling with Delphi 2007 for Win32 - DELPHICOMPILER12 Defined when compiling with Delphi Personality of BDS 6.0 - DELPHICOMPILER14 Defined when compiling with Delphi Personality of BDS 7.0 - DELPHICOMPILER15 Defined when compiling with Delphi Personality of BDS 8.0 - DELPHICOMPILER16 Defined when compiling with Delphi Personality of BDS 9.0 - DELPHICOMPILER17 Defined when compiling with Delphi Personality of BDS 10.0 - DELPHICOMPILER1_UP Defined when compiling with Delphi 1 or higher - DELPHICOMPILER2_UP Defined when compiling with Delphi 2 or higher - DELPHICOMPILER3_UP Defined when compiling with Delphi 3 or higher - DELPHICOMPILER4_UP Defined when compiling with Delphi 4 or higher - DELPHICOMPILER5_UP Defined when compiling with Delphi 5 or higher - DELPHICOMPILER6_UP Defined when compiling with Delphi 6 or Kylix 1, 2 or 3 or higher - DELPHICOMPILER7_UP Defined when compiling with Delphi 7 or higher - DELPHICOMPILER8_UP Defined when compiling with Delphi 8 or higher - DELPHICOMPILER9_UP Defined when compiling with Delphi 2005 - DELPHICOMPILER10_UP Defined when compiling with Delphi 2006 or higher - DELPHICOMPILER11_UP Defined when compiling with Delphi 2007 for Win32 or higher - DELPHICOMPILER12_UP Defined when compiling with Delphi 2009 for Win32 or higher - DELPHICOMPILER14_UP Defined when compiling with Delphi 2010 for Win32 or higher - DELPHICOMPILER15_UP Defined when compiling with Delphi XE for Win32 or higher - DELPHICOMPILER16_UP Defined when compiling with Delphi XE2 for Win32 or higher - DELPHICOMPILER17_UP Defined when compiling with Delphi XE3 for Win32 or higher - - -- C++Builder Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. These directives are only defined if - the compiler is C++Builder (ie BCB is defined). - - Directive Description - ------------------------------------------------------------------------------ - BCB1 Defined when compiling with C++Builder 1 - BCB3 Defined when compiling with C++Builder 3 - BCB4 Defined when compiling with C++Builder 4 - BCB5 Defined when compiling with C++Builder 5 (Codename RAMPAGE) - BCB6 Defined when compiling with C++Builder 6 (Codename RIPTIDE) - BCB10 Defined when compiling with C++Builder Personality of BDS 4.0 (also known as C++Builder 2006) (Codename DEXTER) - BCB11 Defined when compiling with C++Builder Personality of RAD Studio 2007 (also known as C++Builder 2007) (Codename COGSWELL) - BCB12 Defined when compiling with C++Builder Personality of RAD Studio 2009 (also known as C++Builder 2009) (Codename TIBURON) - BCB14 Defined when compiling with C++Builder Personality of RAD Studio 2010 (also known as C++Builder 2010) (Codename WEAVER) - BCB15 Defined when compiling with C++Builder Personality of RAD Studio XE (also known as C++Builder XE) (Codename FULCRUM) - BCB16 Defined when compiling with C++Builder Personality of RAD Studio XE2 (also known as C++Builder XE2) (Codename PULSAR) - BCB17 Defined when compiling with C++Builder Personality of RAD Studio XE3 (also known as C++Builder XE3) (Codename WATERDRAGON) - BCB1_UP Defined when compiling with C++Builder 1 or higher - BCB3_UP Defined when compiling with C++Builder 3 or higher - BCB4_UP Defined when compiling with C++Builder 4 or higher - BCB5_UP Defined when compiling with C++Builder 5 or higher - BCB6_UP Defined when compiling with C++Builder 6 or higher - BCB10_UP Defined when compiling with C++Builder Personality of BDS 4.0 or higher - BCB11_UP Defined when compiling with C++Builder Personality of RAD Studio 2007 or higher - BCB12_UP Defined when compiling with C++Builder Personality of RAD Studio 2009 or higher - BCB14_UP Defined when compiling with C++Builder Personality of RAD Studio 2010 or higher - BCB15_UP Defined when compiling with C++Builder Personality of RAD Studio XE or higher - BCB16_UP Defined when compiling with C++Builder Personality of RAD Studio XE2 or higher - BCB17_UP Defined when compiling with C++Builder Personality of RAD Studio XE3 or higher - - -- RAD Studio / Borland Developer Studio Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated IDE. These directives are only defined if - the IDE is Borland Developer Studio Version 2 or above. - - Note: Borland Developer Studio 2006 is marketed as Delphi 2006 or C++Builder 2006, - but those provide only different labels for identical content. - - Directive Description - ------------------------------------------------------------------------------ - BDS Defined when compiling with BDS version of dcc32.exe (Codename SIDEWINDER) - BDS2 Defined when compiling with BDS 2.0 (Delphi 8) (Codename OCTANE) - BDS3 Defined when compiling with BDS 3.0 (Delphi 2005) (Codename DIAMONDBACK) - BDS4 Defined when compiling with BDS 4.0 (Borland Developer Studio 2006) (Codename DEXTER) - BDS5 Defined when compiling with BDS 5.0 (CodeGear RAD Studio 2007) (Codename HIGHLANDER) - BDS6 Defined when compiling with BDS 6.0 (CodeGear RAD Studio 2009) (Codename TIBURON) - BDS7 Defined when compiling with BDS 7.0 (Embarcadero RAD Studio 2010) (Codename WEAVER) - BDS8 Defined when compiling with BDS 8.0 (Embarcadero RAD Studio XE) (Codename FULCRUM) - BDS9 Defined when compiling with BDS 9.0 (Embarcadero RAD Studio XE2) (Codename PULSAR) - BDS10 Defined when compiling with BDS 10.0 (Embarcadero RAD Studio XE3) (Codename WATERDRAGON) - BDS2_UP Defined when compiling with BDS 2.0 or higher - BDS3_UP Defined when compiling with BDS 3.0 or higher - BDS4_UP Defined when compiling with BDS 4.0 or higher - BDS5_UP Defined when compiling with BDS 5.0 or higher - BDS6_UP Defined when compiling with BDS 6.0 or higher - BDS7_UP Defined when compiling with BDS 7.0 or higher - BDS8_UP Defined when compiling with BDS 8.0 or higher - BDS9_UP Defined when compiling with BDS 9.0 or higher - BDS10_UP Defined when compiling with BDS 10.0 or higher - -- Compiler Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. Unlike the DELPHI_X and BCB_X - directives, these directives are indepedent of the development environment. - That is, they are defined regardless of whether compilation takes place using - Delphi or C++Builder. - - Directive Description - ------------------------------------------------------------------------------ - COMPILER1 Defined when compiling with Delphi 1 - COMPILER2 Defined when compiling with Delphi 2 or C++Builder 1 - COMPILER3 Defined when compiling with Delphi 3 - COMPILER35 Defined when compiling with C++Builder 3 - COMPILER4 Defined when compiling with Delphi 4 or C++Builder 4 - COMPILER5 Defined when compiling with Delphi 5 or C++Builder 5 - COMPILER6 Defined when compiling with Delphi 6 or C++Builder 6 - COMPILER7 Defined when compiling with Delphi 7 - COMPILER8 Defined when compiling with Delphi 8 - COMPILER9 Defined when compiling with Delphi 9 - COMPILER10 Defined when compiling with Delphi or C++Builder Personalities of BDS 4.0 - COMPILER11 Defined when compiling with Delphi or C++Builder Personalities of BDS 5.0 - COMPILER12 Defined when compiling with Delphi or C++Builder Personalities of BDS 6.0 - COMPILER14 Defined when compiling with Delphi or C++Builder Personalities of BDS 7.0 - COMPILER15 Defined when compiling with Delphi or C++Builder Personalities of BDS 8.0 - COMPILER16 Defined when compiling with Delphi or C++Builder Personalities of BDS 9.0 - COMPILER17 Defined when compiling with Delphi or C++Builder Personalities of BDS 10.0 - COMPILER1_UP Defined when compiling with Delphi 1 or higher - COMPILER2_UP Defined when compiling with Delphi 2 or C++Builder 1 or higher - COMPILER3_UP Defined when compiling with Delphi 3 or higher - COMPILER35_UP Defined when compiling with C++Builder 3 or higher - COMPILER4_UP Defined when compiling with Delphi 4 or C++Builder 4 or higher - COMPILER5_UP Defined when compiling with Delphi 5 or C++Builder 5 or higher - COMPILER6_UP Defined when compiling with Delphi 6 or C++Builder 6 or higher - COMPILER7_UP Defined when compiling with Delphi 7 - COMPILER8_UP Defined when compiling with Delphi 8 - COMPILER9_UP Defined when compiling with Delphi Personalities of BDS 3.0 - COMPILER10_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 4.0 or higher - COMPILER11_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 5.0 or higher - COMPILER12_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 6.0 or higher - COMPILER14_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 7.0 or higher - COMPILER15_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 8.0 or higher - COMPILER16_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 9.0 or higher - COMPILER17_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 10.0 or higher - - -- RTL Versions - - Use e.g. following to determine the exact RTL version since version 14.0: - {$IFDEF CONDITIONALEXPRESSIONS} - {$IF Declared(RTLVersion) and (RTLVersion >= 14.2)} - // code for Delphi 6.02 or higher, Kylix 2 or higher, C++Builder 6 or higher - ... - {$IFEND} - {$ENDIF} - - Directive Description - ------------------------------------------------------------------------------ - RTL80_UP Defined when compiling with Delphi 1 or higher - RTL90_UP Defined when compiling with Delphi 2 or higher - RTL93_UP Defined when compiling with C++Builder 1 or higher - RTL100_UP Defined when compiling with Delphi 3 or higher - RTL110_UP Defined when compiling with C++Builder 3 or higher - RTL120_UP Defined when compiling with Delphi 4 or higher - RTL125_UP Defined when compiling with C++Builder 4 or higher - RTL130_UP Defined when compiling with Delphi 5 or C++Builder 5 or higher - RTL140_UP Defined when compiling with Delphi 6, Kylix 1, 2 or 3 or C++Builder 6 or higher - RTL150_UP Defined when compiling with Delphi 7 or higher - RTL160_UP Defined when compiling with Delphi 8 or higher - RTL170_UP Defined when compiling with Delphi Personalities of BDS 3.0 or higher - RTL180_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 4.0 or higher - RTL185_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 5.0 or higher - RTL190_UP Defined when compiling with Delphi.NET of BDS 5.0 or higher - RTL200_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 6.0 or higher - RTL210_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 7.0 or higher - RTL220_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 8.0 or higher - RTL230_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 9.0 or higher - RTL240_UP Defined when compiling with Delphi or C++Builder Personalities of BDS 10.0 or higher - - -- CLR Versions - - Directive Description - ------------------------------------------------------------------------------ - CLR Defined when compiling for .NET - CLR10 Defined when compiling for .NET 1.0 (may be overriden by FORCE_CLR10) - CLR10_UP Defined when compiling for .NET 1.0 or higher - CLR11 Defined when compiling for .NET 1.1 (may be overriden by FORCE_CLR11) - CLR11_UP Defined when compiling for .NET 1.1 or higher - CLR20 Defined when compiling for .NET 2.0 (may be overriden by FORCE_CLR20) - CLR20_UP Defined when compiling for .NET 2.0 or higher - - -- Feature Directives - - The features directives are used to test if the compiler supports specific - features, such as method overloading, and adjust the sources accordingly. Use - of these directives is preferred over the use of the DELPHI and COMPILER - directives. - - Directive Description - ------------------------------------------------------------------------------ - SUPPORTS_CONSTPARAMS Compiler supports const parameters (D1+) - SUPPORTS_SINGLE Compiler supports the Single type (D1+) - SUPPORTS_DOUBLE Compiler supports the Double type (D1+) - SUPPORTS_EXTENDED Compiler supports the Extended type (D1+) - SUPPORTS_CURRENCY Compiler supports the Currency type (D2+) - SUPPORTS_THREADVAR Compiler supports threadvar declarations (D2+) - SUPPORTS_OUTPARAMS Compiler supports out parameters (D3+) - SUPPORTS_VARIANT Compiler supports variant (D2+) - SUPPORTS_WIDECHAR Compiler supports the WideChar type (D2+) - SUPPORTS_WIDESTRING Compiler supports the WideString type (D3+/BCB3+) - SUPPORTS_INTERFACE Compiler supports interfaces (D3+/BCB3+) - SUPPORTS_DISPINTERFACE Compiler supports dispatch interfaces (D3+/BCB3+) - SUPPORTS_DISPID Compiler supports dispatch ids (D3+/BCB3+/FPC) - SUPPORTS_EXTSYM Compiler supports the $EXTERNALSYM directive (D4+/BCB3+) - SUPPORTS_NODEFINE Compiler supports the $NODEFINE directive (D4+/BCB3+) - SUPPORTS_LONGWORD Compiler supports the LongWord type (unsigned 32 bit) (D4+/BCB4+) - SUPPORTS_INT64 Compiler supports the Int64 type (D4+/BCB4+) - SUPPORTS_UINT64 Compiler supports the UInt64 type (D XE+ ?) - SUPPORTS_DYNAMICARRAYS Compiler supports dynamic arrays (D4+/BCB4+) - SUPPORTS_DEFAULTPARAMS Compiler supports default parameters (D4+/BCB4+) - SUPPORTS_OVERLOAD Compiler supports overloading (D4+/BCB4+) - SUPPORTS_IMPLEMENTS Compiler supports implements (D4+/BCB4+) - SUPPORTS_DEPRECATED Compiler supports the deprecated directive (D6+/BCB6+) - SUPPORTS_PLATFORM Compiler supports the platform directive (D6+/BCB6+) - SUPPORTS_LIBRARY Compiler supports the library directive (D6+/BCB6+/FPC) - SUPPORTS_LOCAL Compiler supports the local directive (D6+/BCB6+) - SUPPORTS_SETPEFLAGS Compiler supports the SetPEFlags directive (D6+/BCB6+) - SUPPORTS_EXPERIMENTAL_WARNINGS Compiler supports the WARN SYMBOL_EXPERIMENTAL and WARN UNIT_EXPERIMENTAL directives (D6+/BCB6+) - SUPPORTS_INLINE Compiler supports the inline directive (D9+/FPC) - SUPPORTS_FOR_IN Compiler supports for in loops (D9+) - SUPPORTS_NESTED_CONSTANTS Compiler supports nested constants (D9+) - SUPPORTS_NESTED_TYPES Compiler supports nested types (D9+) - SUPPORTS_REGION Compiler supports the REGION and ENDREGION directives (D9+) - SUPPORTS_ENHANCED_RECORDS Compiler supports class [operator|function|procedure] for record types (D9.NET, D10+) - SUPPORTS_CLASS_FIELDS Compiler supports class fields (D9.NET, D10+) - SUPPORTS_CLASS_HELPERS Compiler supports class helpers (D9.NET, D10+) - SUPPORTS_CLASS_OPERATORS Compiler supports class operators (D9.NET, D10+) - SUPPORTS_CLASS_CTORDTORS Compiler supports class contructors/destructors (D14+) - SUPPORTS_STRICT Compiler supports strict keyword (D9.NET, D10+) - SUPPORTS_STATIC Compiler supports static keyword (D9.NET, D10+) - SUPPORTS_FINAL Compiler supports final keyword (D9.NET, D10+) - SUPPORTS_METHODINFO Compiler supports the METHODINFO directives (D10+) - SUPPORTS_GENERICS Compiler supports generic implementations (D11.NET, D12+) - SUPPORTS_DEPRECATED_DETAILS Compiler supports additional text for the deprecated directive (D11.NET, D12+) - ACCEPT_DEPRECATED Compiler supports or ignores the deprecated directive (D6+/BCB6+/FPC) - ACCEPT_PLATFORM Compiler supports or ignores the platform directive (D6+/BCB6+/FPC) - ACCEPT_LIBRARY Compiler supports or ignores the library directive (D6+/BCB6+) - SUPPORTS_CUSTOMVARIANTS Compiler supports custom variants (D6+/BCB6+) - SUPPORTS_VARARGS Compiler supports varargs (D6+/BCB6+) - SUPPORTS_ENUMVALUE Compiler supports assigning ordinalities to values of enums (D6+/BCB6+) - SUPPORTS_DEPRECATED_WARNINGS Compiler supports deprecated warnings (D6+/BCB6+) - SUPPORTS_LIBRARY_WARNINGS Compiler supports library warnings (D6+/BCB6+) - SUPPORTS_PLATFORM_WARNINGS Compiler supports platform warnings (D6+/BCB6+) - SUPPORTS_UNSAFE_WARNINGS Compiler supports unsafe warnings (D7) - SUPPORTS_WEAKPACKAGEUNIT Compiler supports the WEAKPACKAGEUNIT directive - SUPPORTS_COMPILETIME_MESSAGES Compiler supports the MESSAGE directive - SUPPORTS_PACKAGES Compiler supports Packages - HAS_UNIT_LIBC Unit Libc exists (Kylix, FPC on Linux/x86) - HAS_UNIT_RTLCONSTS Unit RTLConsts exists (D6+/BCB6+/FPC) - HAS_UNIT_TYPES Unit Types exists (D6+/BCB6+/FPC) - HAS_UNIT_VARIANTS Unit Variants exists (D6+/BCB6+/FPC) - HAS_UNIT_STRUTILS Unit StrUtils exists (D6+/BCB6+/FPC) - HAS_UNIT_DATEUTILS Unit DateUtils exists (D6+/BCB6+/FPC) - HAS_UNIT_CONTNRS Unit contnrs exists (D6+/BCB6+/FPC) - HAS_UNIT_HTTPPROD Unit HTTPProd exists (D9+) - HAS_UNIT_GIFIMG Unit GifImg exists (D11+) - HAS_UNIT_ANSISTRINGS Unit AnsiStrings exists (D12+) - HAS_UNIT_PNGIMAGE Unit PngImage exists (D12+) - HAS_UNIT_CHARACTER Unit Character exists (D12+) - XPLATFORM_RTL The RTL supports crossplatform function names (e.g. RaiseLastOSError) (D6+/BCB6+/FPC) - SUPPORTS_UNICODE string type is aliased to an unicode string (WideString or UnicodeString) (DX.NET, D12+) - SUPPORTS_UNICODE_STRING Compiler supports UnicodeString (D12+) - SUPPORTS_INT_ALIASES Types Int8, Int16, Int32, UInt8, UInt16 and UInt32 are defined in the unit System (D12+) - HAS_UNIT_RTTI Unit RTTI is available (D14+) - SUPPORTS_CAST_INTERFACE_TO_OBJ The compiler supports casts from interfaces to objects (D14+) - SUPPORTS_DELAYED_LOADING The compiler generates stubs for delaying imported function loads (D14+) - HAS_UNIT_REGULAREXPRESSIONSAPI Unit RegularExpressionsAPI is available (D15+) - HAS_UNIT_SYSTEM_UITYPES Unit System.UITypes is available (D16+) - HAS_UNIT_SYSTEM_ACTIONS Unit System.Actions is available (D17+) - - -- Compiler Settings - - The compiler settings directives indicate whether a specific compiler setting - is in effect. This facilitates changing compiler settings locally in a more - compact and readible manner. - - Directive Description - ------------------------------------------------------------------------------ - ALIGN_ON Compiling in the A+ state (no alignment) - BOOLEVAL_ON Compiling in the B+ state (complete boolean evaluation) - ASSERTIONS_ON Compiling in the C+ state (assertions on) - DEBUGINFO_ON Compiling in the D+ state (debug info generation on) - IMPORTEDDATA_ON Compiling in the G+ state (creation of imported data references) - LONGSTRINGS_ON Compiling in the H+ state (string defined as AnsiString) - IOCHECKS_ON Compiling in the I+ state (I/O checking enabled) - WRITEABLECONST_ON Compiling in the J+ state (typed constants can be modified) - LOCALSYMBOLS Compiling in the L+ state (local symbol generation) - LOCALSYMBOLS_ON Alias of LOCALSYMBOLS - TYPEINFO_ON Compiling in the M+ state (RTTI generation on) - OPTIMIZATION_ON Compiling in the O+ state (code optimization on) - OPENSTRINGS_ON Compiling in the P+ state (variable string parameters are openstrings) - OVERFLOWCHECKS_ON Compiling in the Q+ state (overflow checing on) - RANGECHECKS_ON Compiling in the R+ state (range checking on) - TYPEDADDRESS_ON Compiling in the T+ state (pointers obtained using the @ operator are typed) - SAFEDIVIDE_ON Compiling in the U+ state (save FDIV instruction through RTL emulation) - VARSTRINGCHECKS_ON Compiling in the V+ state (type checking of shortstrings) - STACKFRAMES_ON Compiling in the W+ state (generation of stack frames) - EXTENDEDSYNTAX_ON Compiling in the X+ state (Delphi extended syntax enabled) -*) - -{$DEFINE BORLAND} - -{ Set FreePascal to Delphi mode } -{$IFDEF FPC} - {$MODE DELPHI} -// {$ASMMODE Intel} //Not needed and raise error on non-intel platforms! - {$UNDEF BORLAND} - {$DEFINE CPUASM} - // FPC defines CPU32, CPU64 and Unix automatically -{$ENDIF} - -{$IFDEF BORLAND} - {$IFDEF LINUX} - {$DEFINE KYLIX} - {$ENDIF LINUX} - {$IFNDEF CLR} - {$IFNDEF CPUX86} - {$IFNDEF CPUX64} - {$DEFINE CPU386} // For Borland compilers select the x86 compat assembler by default - {$DEFINE CPU32} // Assume Borland compilers are 32-bit (rather than 64-bit) - {$DEFINE CPUASM} - {$ELSE ~CPUX64} - {$DEFINE CPU64} - {$DEFINE CPUASM} - {$DEFINE DELPHI64_TEMPORARY} - {$ENDIF ~CPUX64} - {$ELSE ~CPUX86} - {$DEFINE CPU386} - {$DEFINE CPU32} - {$DEFINE CPUASM} - {$ENDIF ~CPUX86} - {$ENDIF ~CLR} -{$ENDIF BORLAND} - -{------------------------------------------------------------------------------} -{ VERXXX to COMPILERX, DELPHIX and BCBX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BORLAND} - {$IFDEF KYLIX} - {$I kylix.inc} // FPC incompatible stuff - {$ELSE ~KYLIX} - - {$DEFINE UNKNOWN_COMPILER_VERSION} - - {$IFDEF VER80} - {$DEFINE COMPILER1} - {$DEFINE DELPHI1} - {$DEFINE DELPHICOMPILER1} - {$DEFINE RTL80_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER90} - {$DEFINE COMPILER2} - {$DEFINE DELPHI2} - {$DEFINE DELPHICOMPILER2} - {$DEFINE RTL90_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER93} - {$DEFINE COMPILER2} - {$DEFINE BCB1} - {$DEFINE BCB} - {$DEFINE RTL93_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER100} - {$DEFINE COMPILER3} - {$DEFINE DELPHI3} - {$DEFINE DELPHICOMPILER3} - {$DEFINE RTL100_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER110} - {$DEFINE COMPILER35} - {$DEFINE BCB3} - {$DEFINE BCB} - {$DEFINE RTL110_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER120} - {$DEFINE COMPILER4} - {$DEFINE DELPHI4} - {$DEFINE DELPHICOMPILER4} - {$DEFINE RTL120_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER125} - {$DEFINE COMPILER4} - {$DEFINE BCB4} - {$DEFINE BCB} - {$DEFINE RTL125_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER130} - {$DEFINE COMPILER5} - {$IFDEF BCB} - {$DEFINE BCB5} - {$ELSE} - {$DEFINE DELPHI5} - {$DEFINE DELPHICOMPILER5} - {$ENDIF} - {$DEFINE RTL130_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER140} - {$DEFINE COMPILER6} - {$IFDEF BCB} - {$DEFINE BCB6} - {$ELSE} - {$DEFINE DELPHI6} - {$DEFINE DELPHICOMPILER6} - {$ENDIF} - {$DEFINE RTL140_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER150} - {$DEFINE COMPILER7} - {$DEFINE DELPHI7} - {$DEFINE DELPHICOMPILER7} - {$DEFINE RTL150_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER160} - {$DEFINE BDS2} - {$DEFINE BDS} - {$IFDEF CLR} - {$DEFINE CLR10} - {$ENDIF CLR} - {$DEFINE COMPILER8} - {$DEFINE DELPHI8} - {$DEFINE DELPHICOMPILER8} - {$DEFINE RTL160_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER170} - {$DEFINE BDS3} - {$DEFINE BDS} - {$IFDEF CLR} - {$DEFINE CLR11} - {$ENDIF CLR} - {$DEFINE COMPILER9} - {$DEFINE DELPHI9} - {$DEFINE DELPHI2005} // synonym to DELPHI9 - {$DEFINE DELPHICOMPILER9} - {$DEFINE RTL170_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER180} - {$DEFINE BDS} - {$IFDEF CLR} - {$DEFINE CLR11} - {$ENDIF CLR} - {$IFDEF VER185} - {$DEFINE BDS5} - {$DEFINE COMPILER11} - {$IFDEF BCB} - {$DEFINE BCB11} - {$ELSE} - {$DEFINE DELPHI11} - {$DEFINE DELPHI2007} // synonym to DELPHI11 - {$DEFINE DELPHICOMPILER11} - {$ENDIF} - {$DEFINE RTL185_UP} - {$ELSE ~~VER185} - {$DEFINE BDS4} - {$DEFINE COMPILER10} - {$IFDEF BCB} - {$DEFINE BCB10} - {$ELSE} - {$DEFINE DELPHI10} - {$DEFINE DELPHI2006} // synonym to DELPHI10 - {$DEFINE DELPHICOMPILER10} - {$ENDIF} - {$DEFINE RTL180_UP} - {$ENDIF ~VER185} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER190} // Delphi 2007 for .NET - {$DEFINE BDS} - {$DEFINE BDS5} - {$IFDEF CLR} - {$DEFINE CLR20} - {$ENDIF CLR} - {$DEFINE COMPILER11} - {$DEFINE DELPHI11} - {$DEFINE DELPHI2007} // synonym to DELPHI11 - {$DEFINE DELPHICOMPILER11} - {$DEFINE RTL190_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER190} - - {$IFDEF VER200} // RAD Studio 2009 - {$DEFINE BDS} - {$DEFINE BDS6} - {$IFDEF CLR} - {$DEFINE CLR20} - {$ENDIF CLR} - {$DEFINE COMPILER12} - {$IFDEF BCB} - {$DEFINE BCB12} - {$ELSE} - {$DEFINE DELPHI12} - {$DEFINE DELPHI2009} // synonym to DELPHI12 - {$DEFINE DELPHICOMPILER12} - {$ENDIF BCB} - {$IFDEF CLR} - {$DEFINE RTL190_UP} - {$ELSE} - {$DEFINE RTL200_UP} - {$ENDIF} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER200} - - {$IFDEF VER210} // RAD Studio 2010 - {$DEFINE BDS} - {$DEFINE BDS7} - {$DEFINE COMPILER14} - {$IFDEF BCB} - {$DEFINE BCB14} - {$ELSE} - {$DEFINE DELPHI14} - {$DEFINE DELPHI2010} // synonym to DELPHI14 - {$DEFINE DELPHICOMPILER14} - {$ENDIF BCB} - {$DEFINE RTL210_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER210} - - {$IFDEF VER220} // RAD Studio XE - {$DEFINE BDS} - {$DEFINE BDS8} - {$DEFINE COMPILER15} - {$IFDEF BCB} - {$DEFINE BCB15} - {$ELSE} - {$DEFINE DELPHI15} - {$DEFINE DELPHIXE} // synonym to DELPHI15 - {$DEFINE DELPHICOMPILER15} - {$ENDIF BCB} - {$DEFINE RTL220_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER220} - - {$IFDEF VER230} // RAD Studio XE2 - {$DEFINE BDS} - {$DEFINE BDS9} - {$DEFINE COMPILER16} - {$IFDEF BCB} - {$DEFINE BCB16} - {$ELSE} - {$DEFINE DELPHI16} - {$DEFINE DELPHIXE2} // synonym to DELPHI16 - {$DEFINE DELPHICOMPILER16} - {$ENDIF BCB} - {$DEFINE RTL230_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER230} - - {$IFDEF VER240} // RAD Studio XE3 - {$DEFINE BDS} - {$DEFINE BDS10} - {$DEFINE COMPILER17} - {$IFDEF BCB} - {$DEFINE BCB17} - {$ELSE} - {$DEFINE DELPHI17} - {$DEFINE DELPHIXE3} // synonym to DELPHI17 - {$DEFINE DELPHICOMPILER17} - {$ENDIF BCB} - {$DEFINE RTL240_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER240} - - {$IFDEF UNKNOWN_COMPILER_VERSION} // adjust for newer version (always use latest version) - {$DEFINE BDS} - {$DEFINE BDS10} - {$DEFINE COMPILER17} - {$IFDEF BCB} - {$DEFINE BCB17} - {$ELSE} - {$DEFINE DELPHI17} - {$DEFINE DELPHIXE3} // synonym to DELPHI17 - {$DEFINE DELPHICOMPILER17} - {$ENDIF BCB} - {$DEFINE RTL240_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$ENDIF ~KYLIX} - - {$IFDEF BCB} - {$DEFINE CPPBUILDER} - {$DEFINE BCBCOMPILER} - {$ELSE ~BCB} - {$DEFINE DELPHI} - {$DEFINE DELPHICOMPILER} - {$ENDIF ~BCB} - -{$ENDIF BORLAND} - -{------------------------------------------------------------------------------} -{ DELPHIX_UP from DELPHIX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHI17} {$DEFINE DELPHI17_UP} {$ENDIF} -{$IFDEF DELPHI16} {$DEFINE DELPHI16_UP} {$ENDIF} -{$IFDEF DELPHI15} {$DEFINE DELPHI15_UP} {$ENDIF} -{$IFDEF DELPHI14} {$DEFINE DELPHI14_UP} {$ENDIF} -{$IFDEF DELPHI12} {$DEFINE DELPHI12_UP} {$ENDIF} -{$IFDEF DELPHI11} {$DEFINE DELPHI11_UP} {$ENDIF} -{$IFDEF DELPHI10} {$DEFINE DELPHI10_UP} {$ENDIF} -{$IFDEF DELPHI9} {$DEFINE DELPHI9_UP} {$ENDIF} -{$IFDEF DELPHI8} {$DEFINE DELPHI8_UP} {$ENDIF} -{$IFDEF DELPHI7} {$DEFINE DELPHI7_UP} {$ENDIF} -{$IFDEF DELPHI6} {$DEFINE DELPHI6_UP} {$ENDIF} -{$IFDEF DELPHI5} {$DEFINE DELPHI5_UP} {$ENDIF} -{$IFDEF DELPHI4} {$DEFINE DELPHI4_UP} {$ENDIF} -{$IFDEF DELPHI3} {$DEFINE DELPHI3_UP} {$ENDIF} -{$IFDEF DELPHI2} {$DEFINE DELPHI2_UP} {$ENDIF} -{$IFDEF DELPHI1} {$DEFINE DELPHI1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ DELPHIX_UP from DELPHIX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHI17_UP} - {$DEFINE DELPHIXE3_UP} // synonym to DELPHI17_UP - {$DEFINE DELPHI16_UP} -{$ENDIF} - -{$IFDEF DELPHI16_UP} - {$DEFINE DELPHIXE2_UP} // synonym to DELPHI16_UP - {$DEFINE DELPHI15_UP} -{$ENDIF} - -{$IFDEF DELPHI15_UP} - {$DEFINE DELPHIXE_UP} // synonym to DELPHI15_UP - {$DEFINE DELPHI14_UP} -{$ENDIF} - -{$IFDEF DELPHI14_UP} - {$DEFINE DELPHI2010_UP} // synonym to DELPHI14_UP - {$DEFINE DELPHI12_UP} -{$ENDIF} - -{$IFDEF DELPHI12_UP} - {$DEFINE DELPHI2009_UP} // synonym to DELPHI12_UP - {$DEFINE DELPHI11_UP} -{$ENDIF} - -{$IFDEF DELPHI11_UP} - {$DEFINE DELPHI2007_UP} // synonym to DELPHI11_UP - {$DEFINE DELPHI10_UP} -{$ENDIF} - -{$IFDEF DELPHI10_UP} - {$DEFINE DELPHI2006_UP} // synonym to DELPHI10_UP - {$DEFINE DELPHI9_UP} -{$ENDIF} - -{$IFDEF DELPHI9_UP} - {$DEFINE DELPHI2005_UP} // synonym to DELPHI9_UP - {$DEFINE DELPHI8_UP} -{$ENDIF} - -{$IFDEF DELPHI8_UP} {$DEFINE DELPHI7_UP} {$ENDIF} -{$IFDEF DELPHI7_UP} {$DEFINE DELPHI6_UP} {$ENDIF} -{$IFDEF DELPHI6_UP} {$DEFINE DELPHI5_UP} {$ENDIF} -{$IFDEF DELPHI5_UP} {$DEFINE DELPHI4_UP} {$ENDIF} -{$IFDEF DELPHI4_UP} {$DEFINE DELPHI3_UP} {$ENDIF} -{$IFDEF DELPHI3_UP} {$DEFINE DELPHI2_UP} {$ENDIF} -{$IFDEF DELPHI2_UP} {$DEFINE DELPHI1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BCBX_UP from BCBX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BCB17} {$DEFINE BCB17_UP} {$ENDIF} -{$IFDEF BCB16} {$DEFINE BCB16_UP} {$ENDIF} -{$IFDEF BCB15} {$DEFINE BCB15_UP} {$ENDIF} -{$IFDEF BCB14} {$DEFINE BCB14_UP} {$ENDIF} -{$IFDEF BCB12} {$DEFINE BCB12_UP} {$ENDIF} -{$IFDEF BCB11} {$DEFINE BCB11_UP} {$ENDIF} -{$IFDEF BCB10} {$DEFINE BCB10_UP} {$ENDIF} -{$IFDEF BCB6} {$DEFINE BCB6_UP} {$ENDIF} -{$IFDEF BCB5} {$DEFINE BCB5_UP} {$ENDIF} -{$IFDEF BCB4} {$DEFINE BCB4_UP} {$ENDIF} -{$IFDEF BCB3} {$DEFINE BCB3_UP} {$ENDIF} -{$IFDEF BCB1} {$DEFINE BCB1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BCBX_UP from BCBX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BCB17_UP} {$DEFINE BCB16_UP} {$ENDIF} -{$IFDEF BCB16_UP} {$DEFINE BCB15_UP} {$ENDIF} -{$IFDEF BCB15_UP} {$DEFINE BCB14_UP} {$ENDIF} -{$IFDEF BCB14_UP} {$DEFINE BCB12_UP} {$ENDIF} -{$IFDEF BCB12_UP} {$DEFINE BCB11_UP} {$ENDIF} -{$IFDEF BCB11_UP} {$DEFINE BCB10_UP} {$ENDIF} -{$IFDEF BCB10_UP} {$DEFINE BCB6_UP} {$ENDIF} -{$IFDEF BCB6_UP} {$DEFINE BCB5_UP} {$ENDIF} -{$IFDEF BCB5_UP} {$DEFINE BCB4_UP} {$ENDIF} -{$IFDEF BCB4_UP} {$DEFINE BCB3_UP} {$ENDIF} -{$IFDEF BCB3_UP} {$DEFINE BCB1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BDSX_UP from BDSX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BDS10} {$DEFINE BDS10_UP} {$ENDIF} -{$IFDEF BDS9} {$DEFINE BDS9_UP} {$ENDIF} -{$IFDEF BDS8} {$DEFINE BDS8_UP} {$ENDIF} -{$IFDEF BDS7} {$DEFINE BDS7_UP} {$ENDIF} -{$IFDEF BDS6} {$DEFINE BDS6_UP} {$ENDIF} -{$IFDEF BDS5} {$DEFINE BDS5_UP} {$ENDIF} -{$IFDEF BDS4} {$DEFINE BDS4_UP} {$ENDIF} -{$IFDEF BDS3} {$DEFINE BDS3_UP} {$ENDIF} -{$IFDEF BDS2} {$DEFINE BDS2_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BDSX_UP from BDSX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BDS10_UP} {$DEFINE BDS9_UP} {$ENDIF} -{$IFDEF BDS9_UP} {$DEFINE BDS8_UP} {$ENDIF} -{$IFDEF BDS8_UP} {$DEFINE BDS7_UP} {$ENDIF} -{$IFDEF BDS7_UP} {$DEFINE BDS6_UP} {$ENDIF} -{$IFDEF BDS6_UP} {$DEFINE BDS5_UP} {$ENDIF} -{$IFDEF BDS5_UP} {$DEFINE BDS4_UP} {$ENDIF} -{$IFDEF BDS4_UP} {$DEFINE BDS3_UP} {$ENDIF} -{$IFDEF BDS3_UP} {$DEFINE BDS2_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ DELPHICOMPILERX_UP from DELPHICOMPILERX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHICOMPILER17} {$DEFINE DELPHICOMPILER17_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER16} {$DEFINE DELPHICOMPILER16_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER15} {$DEFINE DELPHICOMPILER15_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER14} {$DEFINE DELPHICOMPILER14_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER12} {$DEFINE DELPHICOMPILER12_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER11} {$DEFINE DELPHICOMPILER11_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER10} {$DEFINE DELPHICOMPILER10_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER9} {$DEFINE DELPHICOMPILER9_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER8} {$DEFINE DELPHICOMPILER8_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER7} {$DEFINE DELPHICOMPILER7_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER6} {$DEFINE DELPHICOMPILER6_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER5} {$DEFINE DELPHICOMPILER5_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER4} {$DEFINE DELPHICOMPILER4_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER3} {$DEFINE DELPHICOMPILER3_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER2} {$DEFINE DELPHICOMPILER2_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER1} {$DEFINE DELPHICOMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ DELPHICOMPILERX_UP from DELPHICOMPILERX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHICOMPILER17_UP} {$DEFINE DELPHICOMPILER16_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER16_UP} {$DEFINE DELPHICOMPILER15_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER15_UP} {$DEFINE DELPHICOMPILER14_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER14_UP} {$DEFINE DELPHICOMPILER12_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER12_UP} {$DEFINE DELPHICOMPILER11_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER11_UP} {$DEFINE DELPHICOMPILER10_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER10_UP} {$DEFINE DELPHICOMPILER9_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER9_UP} {$DEFINE DELPHICOMPILER8_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER8_UP} {$DEFINE DELPHICOMPILER7_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER8_UP} {$DEFINE DELPHICOMPILER7_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER7_UP} {$DEFINE DELPHICOMPILER6_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER6_UP} {$DEFINE DELPHICOMPILER5_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER5_UP} {$DEFINE DELPHICOMPILER4_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER4_UP} {$DEFINE DELPHICOMPILER3_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER3_UP} {$DEFINE DELPHICOMPILER2_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER2_UP} {$DEFINE DELPHICOMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ COMPILERX_UP from COMPILERX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF COMPILER17} {$DEFINE COMPILER17_UP} {$ENDIF} -{$IFDEF COMPILER16} {$DEFINE COMPILER16_UP} {$ENDIF} -{$IFDEF COMPILER15} {$DEFINE COMPILER15_UP} {$ENDIF} -{$IFDEF COMPILER14} {$DEFINE COMPILER14_UP} {$ENDIF} -{$IFDEF COMPILER12} {$DEFINE COMPILER12_UP} {$ENDIF} -{$IFDEF COMPILER11} {$DEFINE COMPILER11_UP} {$ENDIF} -{$IFDEF COMPILER10} {$DEFINE COMPILER10_UP} {$ENDIF} -{$IFDEF COMPILER9} {$DEFINE COMPILER9_UP} {$ENDIF} -{$IFDEF COMPILER8} {$DEFINE COMPILER8_UP} {$ENDIF} -{$IFDEF COMPILER7} {$DEFINE COMPILER7_UP} {$ENDIF} -{$IFDEF COMPILER6} {$DEFINE COMPILER6_UP} {$ENDIF} -{$IFDEF COMPILER5} {$DEFINE COMPILER5_UP} {$ENDIF} -{$IFDEF COMPILER4} {$DEFINE COMPILER4_UP} {$ENDIF} -{$IFDEF COMPILER35} {$DEFINE COMPILER35_UP} {$ENDIF} -{$IFDEF COMPILER3} {$DEFINE COMPILER3_UP} {$ENDIF} -{$IFDEF COMPILER2} {$DEFINE COMPILER2_UP} {$ENDIF} -{$IFDEF COMPILER1} {$DEFINE COMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ COMPILERX_UP from COMPILERX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF COMPILER17_UP} {$DEFINE COMPILER16_UP} {$ENDIF} -{$IFDEF COMPILER16_UP} {$DEFINE COMPILER15_UP} {$ENDIF} -{$IFDEF COMPILER15_UP} {$DEFINE COMPILER14_UP} {$ENDIF} -{$IFDEF COMPILER14_UP} {$DEFINE COMPILER12_UP} {$ENDIF} -{$IFDEF COMPILER12_UP} {$DEFINE COMPILER11_UP} {$ENDIF} -{$IFDEF COMPILER11_UP} {$DEFINE COMPILER10_UP} {$ENDIF} -{$IFDEF COMPILER10_UP} {$DEFINE COMPILER9_UP} {$ENDIF} -{$IFDEF COMPILER9_UP} {$DEFINE COMPILER8_UP} {$ENDIF} -{$IFDEF COMPILER8_UP} {$DEFINE COMPILER7_UP} {$ENDIF} -{$IFDEF COMPILER7_UP} {$DEFINE COMPILER6_UP} {$ENDIF} -{$IFDEF COMPILER6_UP} {$DEFINE COMPILER5_UP} {$ENDIF} -{$IFDEF COMPILER5_UP} {$DEFINE COMPILER4_UP} {$ENDIF} -{$IFDEF COMPILER4_UP} {$DEFINE COMPILER35_UP} {$ENDIF} -{$IFDEF COMPILER35_UP} {$DEFINE COMPILER3_UP} {$ENDIF} -{$IFDEF COMPILER3_UP} {$DEFINE COMPILER2_UP} {$ENDIF} -{$IFDEF COMPILER2_UP} {$DEFINE COMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ RTLX_UP from RTLX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF RTL240_UP} {$DEFINE RTL230_UP} {$ENDIF} -{$IFDEF RTL230_UP} {$DEFINE RTL220_UP} {$ENDIF} -{$IFDEF RTL220_UP} {$DEFINE RTL210_UP} {$ENDIF} -{$IFDEF RTL210_UP} {$DEFINE RTL200_UP} {$ENDIF} -{$IFDEF RTL200_UP} {$DEFINE RTL190_UP} {$ENDIF} -{$IFDEF RTL190_UP} {$DEFINE RTL185_UP} {$ENDIF} -{$IFDEF RTL185_UP} {$DEFINE RTL180_UP} {$ENDIF} -{$IFDEF RTL180_UP} {$DEFINE RTL170_UP} {$ENDIF} -{$IFDEF RTL170_UP} {$DEFINE RTL160_UP} {$ENDIF} -{$IFDEF RTL160_UP} {$DEFINE RTL150_UP} {$ENDIF} -{$IFDEF RTL150_UP} {$DEFINE RTL145_UP} {$ENDIF} -{$IFDEF RTL145_UP} {$DEFINE RTL142_UP} {$ENDIF} -{$IFDEF RTL142_UP} {$DEFINE RTL140_UP} {$ENDIF} -{$IFDEF RTL140_UP} {$DEFINE RTL130_UP} {$ENDIF} -{$IFDEF RTL130_UP} {$DEFINE RTL125_UP} {$ENDIF} -{$IFDEF RTL125_UP} {$DEFINE RTL120_UP} {$ENDIF} -{$IFDEF RTL120_UP} {$DEFINE RTL110_UP} {$ENDIF} -{$IFDEF RTL110_UP} {$DEFINE RTL100_UP} {$ENDIF} -{$IFDEF RTL100_UP} {$DEFINE RTL93_UP} {$ENDIF} -{$IFDEF RTL93_UP} {$DEFINE RTL90_UP} {$ENDIF} -{$IFDEF RTL90_UP} {$DEFINE RTL80_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ Check for CLR overrides of default detection } -{------------------------------------------------------------------------------} - -{$IFDEF CLR} - {$IFDEF FORCE_CLR10} - {$DEFINE CLR10} - {$UNDEF CLR11} - {$UNDEF CLR20} - {$ENDIF FORCE_CLR10} - - {$IFDEF FORCE_CLR11} - {$UNDEF CLR10} - {$DEFINE CLR11} - {$UNDEF CLR20} - {$ENDIF FORCE_CLR11} - - {$IFDEF FORCE_CLR20} - {$UNDEF CLR10} - {$UNDEF CLR11} - {$DEFINE CLR20} - {$ENDIF FORCE_CLR20} -{$ENDIF CLR} - -{------------------------------------------------------------------------------} -{ CLRX from CLRX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF CLR10} {$DEFINE CLR10_UP} {$ENDIF} -{$IFDEF CLR11} {$DEFINE CLR11_UP} {$ENDIF} -{$IFDEF CLR20} {$DEFINE CLR20_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ CLRX_UP from CLRX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF CLR20_UP} {$DEFINE CLR11_UP} {$ENDIF} -{$IFDEF CLR11_UP} {$DEFINE CLR10_UP} {$ENDIF} - -{------------------------------------------------------------------------------} - -{$IFDEF DELPHICOMPILER} - {$DEFINE DELPHILANGUAGE} -{$ENDIF} - -{$IFDEF BCBCOMPILER} - {$DEFINE DELPHILANGUAGE} -{$ENDIF} - -{------------------------------------------------------------------------------} -{ KYLIXX_UP from KYLIXX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF KYLIX3} {$DEFINE KYLIX3_UP} {$ENDIF} -{$IFDEF KYLIX2} {$DEFINE KYLIX2_UP} {$ENDIF} -{$IFDEF KYLIX1} {$DEFINE KYLIX1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ KYLIXX_UP from KYLIXX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF KYLIX3_UP} {$DEFINE KYLIX2_UP} {$ENDIF} -{$IFDEF KYLIX2_UP} {$DEFINE KYLIX1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ Map COMPILERX_UP to friendly feature names } -{------------------------------------------------------------------------------} - -{$IFDEF FPC} - {$IFDEF VER1_0} - Please use FPC 2.0 or higher to compile this. - {$ELSE} - {$DEFINE SUPPORTS_OUTPARAMS} - {$DEFINE SUPPORTS_WIDECHAR} - {$DEFINE SUPPORTS_WIDESTRING} - {$IFDEF HASINTF} - {$DEFINE SUPPORTS_INTERFACE} - {$ENDIF} - {$IFDEF HASVARIANT} - {$DEFINE SUPPORTS_VARIANT} - {$ENDIF} - {$IFDEF FPC_HAS_TYPE_SINGLE} - {$DEFINE SUPPORTS_SINGLE} - {$ENDIF} - {$IFDEF FPC_HAS_TYPE_DOUBLE} - {$DEFINE SUPPORTS_DOUBLE} - {$ENDIF} - {$IFDEF FPC_HAS_TYPE_EXTENDED} - {$DEFINE SUPPORTS_EXTENDED} - {$ENDIF} - {$IFDEF HASCURRENCY} - {$DEFINE SUPPORTS_CURRENCY} - {$ENDIF} - {$DEFINE SUPPORTS_THREADVAR} - {$DEFINE SUPPORTS_CONSTPARAMS} - {$DEFINE SUPPORTS_LONGWORD} - {$DEFINE SUPPORTS_INT64} - {$DEFINE SUPPORTS_DYNAMICARRAYS} - {$DEFINE SUPPORTS_DEFAULTPARAMS} - {$DEFINE SUPPORTS_OVERLOAD} - {$DEFINE ACCEPT_DEPRECATED} // 2.2 also gives warnings - {$DEFINE ACCEPT_PLATFORM} // 2.2 also gives warnings - {$DEFINE ACCEPT_LIBRARY} - {$DEFINE SUPPORTS_EXTSYM} - {$DEFINE SUPPORTS_NODEFINE} - - {$DEFINE SUPPORTS_CUSTOMVARIANTS} - {$DEFINE SUPPORTS_VARARGS} - {$DEFINE SUPPORTS_ENUMVALUE} - {$IFDEF LINUX} - {$DEFINE HAS_UNIT_LIBC} - {$ENDIF LINUX} - {$DEFINE HAS_UNIT_CONTNRS} - {$DEFINE HAS_UNIT_TYPES} - {$DEFINE HAS_UNIT_VARIANTS} - {$DEFINE HAS_UNIT_STRUTILS} - {$DEFINE HAS_UNIT_DATEUTILS} - {$DEFINE HAS_UNIT_RTLCONSTS} - - {$DEFINE XPLATFORM_RTL} - - {$IFDEF VER2_2} - {$DEFINE SUPPORTS_DISPINTERFACE} - {$DEFINE SUPPORTS_IMPLEMENTS} - {$DEFINE SUPPORTS_DISPID} - {$ELSE} - {$UNDEF SUPPORTS_DISPINTERFACE} - {$UNDEF SUPPORTS_IMPLEMENTS} - {$endif} - {$UNDEF SUPPORTS_UNSAFE_WARNINGS} - {$ENDIF} -{$ENDIF FPC} - -{$IFDEF CLR} - {$DEFINE SUPPORTS_UNICODE} -{$ENDIF CLR} - -{$IFDEF COMPILER1_UP} - {$DEFINE SUPPORTS_CONSTPARAMS} - {$DEFINE SUPPORTS_SINGLE} - {$DEFINE SUPPORTS_DOUBLE} - {$DEFINE SUPPORTS_EXTENDED} - {$DEFINE SUPPORTS_PACKAGES} -{$ENDIF COMPILER1_UP} - -{$IFDEF COMPILER2_UP} - {$DEFINE SUPPORTS_CURRENCY} - {$DEFINE SUPPORTS_THREADVAR} - {$DEFINE SUPPORTS_VARIANT} - {$DEFINE SUPPORTS_WIDECHAR} -{$ENDIF COMPILER2_UP} - -{$IFDEF COMPILER3_UP} - {$DEFINE SUPPORTS_OUTPARAMS} - {$DEFINE SUPPORTS_WIDESTRING} - {$DEFINE SUPPORTS_INTERFACE} - {$DEFINE SUPPORTS_DISPINTERFACE} - {$DEFINE SUPPORTS_DISPID} - {$DEFINE SUPPORTS_WEAKPACKAGEUNIT} -{$ENDIF COMPILER3_UP} - -{$IFDEF COMPILER35_UP} - {$DEFINE SUPPORTS_EXTSYM} - {$DEFINE SUPPORTS_NODEFINE} -{$ENDIF COMPILER35_UP} - -{$IFDEF COMPILER4_UP} - {$DEFINE SUPPORTS_LONGWORD} - {$DEFINE SUPPORTS_INT64} - {$DEFINE SUPPORTS_DYNAMICARRAYS} - {$DEFINE SUPPORTS_DEFAULTPARAMS} - {$DEFINE SUPPORTS_OVERLOAD} - {$DEFINE SUPPORTS_IMPLEMENTS} -{$ENDIF COMPILER4_UP} - -{$IFDEF COMPILER6_UP} - {$DEFINE SUPPORTS_DEPRECATED} - {$DEFINE SUPPORTS_LIBRARY} - {$DEFINE SUPPORTS_PLATFORM} - {$DEFINE SUPPORTS_LOCAL} - {$DEFINE SUPPORTS_SETPEFLAGS} - {$DEFINE SUPPORTS_EXPERIMENTAL_WARNINGS} - {$DEFINE ACCEPT_DEPRECATED} - {$DEFINE ACCEPT_PLATFORM} - {$DEFINE ACCEPT_LIBRARY} - {$DEFINE SUPPORTS_DEPRECATED_WARNINGS} - {$DEFINE SUPPORTS_LIBRARY_WARNINGS} - {$DEFINE SUPPORTS_PLATFORM_WARNINGS} - {$DEFINE SUPPORTS_CUSTOMVARIANTS} - {$DEFINE SUPPORTS_VARARGS} - {$DEFINE SUPPORTS_ENUMVALUE} - {$DEFINE SUPPORTS_COMPILETIME_MESSAGES} -{$ENDIF COMPILER6_UP} - -{$IFDEF COMPILER7_UP} - {$DEFINE SUPPORTS_UNSAFE_WARNINGS} -{$ENDIF COMPILER7_UP} - -{$IFDEF COMPILER9_UP} - {$DEFINE SUPPORTS_FOR_IN} - {$DEFINE SUPPORTS_INLINE} - {$DEFINE SUPPORTS_NESTED_CONSTANTS} - {$DEFINE SUPPORTS_NESTED_TYPES} - {$DEFINE SUPPORTS_REGION} - {$IFDEF CLR} - {$DEFINE SUPPORTS_ENHANCED_RECORDS} - {$DEFINE SUPPORTS_CLASS_FIELDS} - {$DEFINE SUPPORTS_CLASS_HELPERS} - {$DEFINE SUPPORTS_CLASS_OPERATORS} - {$DEFINE SUPPORTS_STRICT} - {$DEFINE SUPPORTS_STATIC} - {$DEFINE SUPPORTS_FINAL} - {$ENDIF CLR} -{$ENDIF COMPILER9_UP} - -{$IFDEF COMPILER10_UP} - {$DEFINE SUPPORTS_ENHANCED_RECORDS} - {$DEFINE SUPPORTS_CLASS_FIELDS} - {$DEFINE SUPPORTS_CLASS_HELPERS} - {$DEFINE SUPPORTS_CLASS_OPERATORS} - {$DEFINE SUPPORTS_STRICT} - {$DEFINE SUPPORTS_STATIC} - {$DEFINE SUPPORTS_FINAL} - {$DEFINE SUPPORTS_METHODINFO} -{$ENDIF COMPILER10_UP} - -{$IFDEF COMPILER11_UP} - {$IFDEF CLR} - {$DEFINE SUPPORTS_GENERICS} - {$DEFINE SUPPORTS_DEPRECATED_DETAILS} - {$ENDIF CLR} -{$ENDIF COMPILER11_UP} - -{$IFDEF COMPILER12_UP} - {$DEFINE SUPPORTS_GENERICS} - {$DEFINE SUPPORTS_DEPRECATED_DETAILS} - {$DEFINE SUPPORTS_INT_ALIASES} - {$IFNDEF CLR} - {$DEFINE SUPPORTS_UNICODE} - {$DEFINE SUPPORTS_UNICODE_STRING} - {$ENDIF CLR} -{$ENDIF COMPILER12_UP} - -{$IFDEF COMPILER14_UP} - {$DEFINE SUPPORTS_CLASS_CTORDTORS} - {$DEFINE HAS_UNIT_RTTI} - {$DEFINE SUPPORTS_CAST_INTERFACE_TO_OBJ} - {$DEFINE SUPPORTS_DELAYED_LOADING} -{$ENDIF COMPILER14_UP} - -{$IFDEF COMPILER16_UP} - {$DEFINE USE_64BIT_TYPES} -{$ENDIF COMPILER16_UP} - -{$IFDEF RTL130_UP} - {$DEFINE HAS_UNIT_CONTNRS} -{$ENDIF RTL130_UP} - -{$IFDEF RTL140_UP} - {$IFDEF LINUX} - {$DEFINE HAS_UNIT_LIBC} - {$ENDIF LINUX} - {$DEFINE HAS_UNIT_RTLCONSTS} - {$DEFINE HAS_UNIT_TYPES} - {$DEFINE HAS_UNIT_VARIANTS} - {$DEFINE HAS_UNIT_STRUTILS} - {$DEFINE HAS_UNIT_DATEUTILS} - {$DEFINE XPLATFORM_RTL} -{$ENDIF RTL140_UP} - -{$IFDEF RTL170_UP} - {$DEFINE HAS_UNIT_HTTPPROD} -{$ENDIF RTL170_UP} - -{$IFDEF RTL185_UP} - {$DEFINE HAS_UNIT_GIFIMG} -{$ENDIF RTL185_UP} - -{$IFDEF RTL200_UP} - {$DEFINE HAS_UNIT_ANSISTRINGS} - {$DEFINE HAS_UNIT_PNGIMAGE} - {$DEFINE HAS_UNIT_CHARACTER} -{$ENDIF RTL200_UP} - -{$IFDEF RTL220_UP} - {$DEFINE SUPPORTS_UINT64} - {$DEFINE HAS_UNIT_REGULAREXPRESSIONSAPI} -{$ENDIF RTL220_UP} - -{$IFDEF RTL230_UP} - {$DEFINE HAS_UNITSCOPE} - {$DEFINE HAS_UNIT_SYSTEM_UITYPES} -{$ENDIF RTL230_UP} - -{$IFDEF RTL240_UP} - {$DEFINE HAS_UNIT_SYSTEM_ACTIONS} -{$ENDIF RTL240_UP} - -{------------------------------------------------------------------------------} -{ Cross-platform related defines } -{------------------------------------------------------------------------------} - -{$IFNDEF CPUASM} - {$DEFINE PUREPASCAL} -{$ENDIF ~CPUASM} - -{$IFDEF WIN32} - {$DEFINE MSWINDOWS} // predefined for D6+/BCB6+ - {$DEFINE Win32API} -{$ENDIF} - -{$IFDEF DELPHILANGUAGE} - {$IFDEF LINUX} - {$DEFINE UNIX} - {$ENDIF} - - {$IFNDEF CONSOLE} - {$IFDEF LINUX} - {$DEFINE VisualCLX} - {$ENDIF} - {$IFNDEF VisualCLX} - {$DEFINE VCL} - {$ENDIF} - {$ENDIF ~CONSOLE} -{$ENDIF DELPHILANGUAGE} - -{------------------------------------------------------------------------------} -{ Compiler settings } -{------------------------------------------------------------------------------} - -{$IFOPT A+} {$DEFINE ALIGN_ON} {$ENDIF} -{$IFOPT B+} {$DEFINE BOOLEVAL_ON} {$ENDIF} -{$IFDEF COMPILER2_UP} - {$IFOPT C+} {$DEFINE ASSERTIONS_ON} {$ENDIF} -{$ENDIF} -{$IFOPT D+} {$DEFINE DEBUGINFO_ON} {$ENDIF} -{$IFOPT G+} {$DEFINE IMPORTEDDATA_ON} {$ENDIF} -{$IFDEF COMPILER2_UP} - {$IFOPT H+} {$DEFINE LONGSTRINGS_ON} {$ENDIF} -{$ENDIF} - -// Hints -{$IFOPT I+} {$DEFINE IOCHECKS_ON} {$ENDIF} -{$IFDEF COMPILER2_UP} - {$IFOPT J+} {$DEFINE WRITEABLECONST_ON} {$ENDIF} -{$ENDIF} -{$IFOPT L+} {$DEFINE LOCALSYMBOLS} {$DEFINE LOCALSYMBOLS_ON} {$ENDIF} -{$IFOPT M+} {$DEFINE TYPEINFO_ON} {$ENDIF} -{$IFOPT O+} {$DEFINE OPTIMIZATION_ON} {$ENDIF} -{$IFOPT P+} {$DEFINE OPENSTRINGS_ON} {$ENDIF} -{$IFOPT Q+} {$DEFINE OVERFLOWCHECKS_ON} {$ENDIF} -{$IFOPT R+} {$DEFINE RANGECHECKS_ON} {$ENDIF} - -// Real compatibility -{$IFOPT T+} {$DEFINE TYPEDADDRESS_ON} {$ENDIF} -{$IFOPT U+} {$DEFINE SAFEDIVIDE_ON} {$ENDIF} -{$IFOPT V+} {$DEFINE VARSTRINGCHECKS_ON} {$ENDIF} -{$IFOPT W+} {$DEFINE STACKFRAMES_ON} {$ENDIF} - -// Warnings -{$IFOPT X+} {$DEFINE EXTENDEDSYNTAX_ON} {$ENDIF} - -// for Delphi/BCB trial versions remove the point from the line below -{.$UNDEF SUPPORTS_WEAKPACKAGEUNIT} - -{$ENDIF ~JEDI_INC} diff --git a/3rd/synapse/source/kylix.inc b/3rd/synapse/source/kylix.inc deleted file mode 100644 index 55f095e1d..000000000 --- a/3rd/synapse/source/kylix.inc +++ /dev/null @@ -1,30 +0,0 @@ -// -// This is FPC-incompatible code and was excluded from jedi.inc for this reason -// -// Kylix 3/C++ for some reason evaluates CompilerVersion comparisons to False, -// if the constant to compare with is a floating point value - weird. -// The "+" sign prevents Kylix/Delphi from issueing a warning about comparing -// signed and unsigned values. -// - {$IF not Declared(CompilerVersion)} - {$DEFINE KYLIX1} - {$DEFINE COMPILER6} - {$DEFINE DELPHICOMPILER6} - {$DEFINE RTL140_UP} - {$ELSEIF Declared(CompilerVersion) and (CompilerVersion > +14)} - {$DEFINE KYLIX2} - {$DEFINE COMPILER6} - {$DEFINE DELPHICOMPILER6} - {$DEFINE RTL142_UP} - {$ELSEIF Declared(CompilerVersion) and (CompilerVersion < +15)} - {$DEFINE KYLIX3} - {$DEFINE COMPILER6} - {$IFNDEF BCB} - {$DEFINE DELPHICOMPILER6} - {$ENDIF} - {$DEFINE RTL145_UP} - {$ELSE} - Add new Kylix version - {$IFEND} - - diff --git a/3rd/synapse/source/laz_synapse.lpk b/3rd/synapse/source/laz_synapse.lpk deleted file mode 100644 index b7151a0f8..000000000 --- a/3rd/synapse/source/laz_synapse.lpk +++ /dev/null @@ -1,167 +0,0 @@ -<?xml version="1.0"?> -<CONFIG> - <Package Version="4"> - <Name Value="laz_synapse"/> - <Author Value="Lukas Gebauer"/> - <CompilerOptions> - <Version Value="11"/> - <SearchPaths> - <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Other> - <CompilerPath Value="$(CompPath)"/> - </Other> - </CompilerOptions> - <Description Value="Ararat Synapse: network communications suite"/> - <Version Major="40" Minor="1"/> - <Files Count="33"> - <Item1> - <Filename Value="asn1util.pas"/> - <UnitName Value="asn1util"/> - </Item1> - <Item2> - <Filename Value="blcksock.pas"/> - <UnitName Value="blcksock"/> - </Item2> - <Item3> - <Filename Value="clamsend.pas"/> - <UnitName Value="clamsend"/> - </Item3> - <Item4> - <Filename Value="dnssend.pas"/> - <UnitName Value="dnssend"/> - </Item4> - <Item5> - <Filename Value="ftpsend.pas"/> - <UnitName Value="ftpsend"/> - </Item5> - <Item6> - <Filename Value="ftptsend.pas"/> - <UnitName Value="ftptsend"/> - </Item6> - <Item7> - <Filename Value="httpsend.pas"/> - <UnitName Value="httpsend"/> - </Item7> - <Item8> - <Filename Value="imapsend.pas"/> - <UnitName Value="imapsend"/> - </Item8> - <Item9> - <Filename Value="ldapsend.pas"/> - <UnitName Value="ldapsend"/> - </Item9> - <Item10> - <Filename Value="mimeinln.pas"/> - <UnitName Value="mimeinln"/> - </Item10> - <Item11> - <Filename Value="mimemess.pas"/> - <UnitName Value="mimemess"/> - </Item11> - <Item12> - <Filename Value="mimepart.pas"/> - <UnitName Value="mimepart"/> - </Item12> - <Item13> - <Filename Value="nntpsend.pas"/> - <UnitName Value="nntpsend"/> - </Item13> - <Item14> - <Filename Value="pingsend.pas"/> - <UnitName Value="pingsend"/> - </Item14> - <Item15> - <Filename Value="pop3send.pas"/> - <UnitName Value="pop3send"/> - </Item15> - <Item16> - <Filename Value="slogsend.pas"/> - <UnitName Value="slogsend"/> - </Item16> - <Item17> - <Filename Value="smtpsend.pas"/> - <UnitName Value="smtpsend"/> - </Item17> - <Item18> - <Filename Value="snmpsend.pas"/> - <UnitName Value="snmpsend"/> - </Item18> - <Item19> - <Filename Value="sntpsend.pas"/> - <UnitName Value="sntpsend"/> - </Item19> - <Item20> - <Filename Value="ssfpc.inc"/> - <Type Value="Include"/> - <UnitName Value="ssfpc"/> - </Item20> - <Item21> - <Filename Value="sswin32.inc"/> - <Type Value="Include"/> - <UnitName Value="sswin32"/> - </Item21> - <Item22> - <Filename Value="synachar.pas"/> - <UnitName Value="synachar"/> - </Item22> - <Item23> - <Filename Value="synacode.pas"/> - <UnitName Value="synacode"/> - </Item23> - <Item24> - <Filename Value="synacrypt.pas"/> - <UnitName Value="synacrypt"/> - </Item24> - <Item25> - <Filename Value="synadbg.pas"/> - <UnitName Value="synadbg"/> - </Item25> - <Item26> - <Filename Value="synafpc.pas"/> - <UnitName Value="synafpc"/> - </Item26> - <Item27> - <Filename Value="synaicnv.pas"/> - <UnitName Value="synaicnv"/> - </Item27> - <Item28> - <Filename Value="synaip.pas"/> - <UnitName Value="synaip"/> - </Item28> - <Item29> - <Filename Value="synamisc.pas"/> - <UnitName Value="synamisc"/> - </Item29> - <Item30> - <Filename Value="synaser.pas"/> - <UnitName Value="synaser"/> - </Item30> - <Item31> - <Filename Value="synautil.pas"/> - <UnitName Value="synautil"/> - </Item31> - <Item32> - <Filename Value="synsock.pas"/> - <UnitName Value="synsock"/> - </Item32> - <Item33> - <Filename Value="tlntsend.pas"/> - <UnitName Value="tlntsend"/> - </Item33> - </Files> - <RequiredPkgs Count="1"> - <Item1> - <PackageName Value="FCL"/> - <MinVersion Major="1" Valid="True"/> - </Item1> - </RequiredPkgs> - <UsageOptions> - <UnitPath Value="$(PkgOutDir)"/> - </UsageOptions> - <PublishOptions> - <Version Value="2"/> - <IgnoreBinaries Value="False"/> - </PublishOptions> - </Package> -</CONFIG> diff --git a/3rd/synapse/source/laz_synapse.pas b/3rd/synapse/source/laz_synapse.pas deleted file mode 100644 index 62d0f113c..000000000 --- a/3rd/synapse/source/laz_synapse.pas +++ /dev/null @@ -1,18 +0,0 @@ -{ This file was automatically created by Lazarus. Do not edit! - This source is only used to compile and install the package. - } - -unit laz_synapse; - -interface - -uses - asn1util, blcksock, clamsend, dnssend, ftpsend, ftptsend, httpsend, - imapsend, ldapsend, mimeinln, mimemess, mimepart, nntpsend, pingsend, - pop3send, slogsend, smtpsend, snmpsend, sntpsend, synachar, synacode, - synacrypt, synadbg, synafpc, synaicnv, synaip, synamisc, synaser, synautil, - synsock, tlntsend; - -implementation - -end. diff --git a/3rd/synapse/source/ldapsend.pas b/3rd/synapse/source/ldapsend.pas deleted file mode 100644 index 0bcac3958..000000000 --- a/3rd/synapse/source/ldapsend.pas +++ /dev/null @@ -1,1261 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.007.001 | -|==============================================================================| -| Content: LDAP client | -|==============================================================================| -| Copyright (c)1999-2014, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2014. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(LDAP client) - -Used RFC: RFC-2251, RFC-2254, RFC-2696, RFC-2829, RFC-2830 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit ldapsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil, asn1util, synacode; - -const - cLDAPProtocol = '389'; - - LDAP_ASN1_BIND_REQUEST = $60; - LDAP_ASN1_BIND_RESPONSE = $61; - LDAP_ASN1_UNBIND_REQUEST = $42; - LDAP_ASN1_SEARCH_REQUEST = $63; - LDAP_ASN1_SEARCH_ENTRY = $64; - LDAP_ASN1_SEARCH_DONE = $65; - LDAP_ASN1_SEARCH_REFERENCE = $73; - LDAP_ASN1_MODIFY_REQUEST = $66; - LDAP_ASN1_MODIFY_RESPONSE = $67; - LDAP_ASN1_ADD_REQUEST = $68; - LDAP_ASN1_ADD_RESPONSE = $69; - LDAP_ASN1_DEL_REQUEST = $4A; - LDAP_ASN1_DEL_RESPONSE = $6B; - LDAP_ASN1_MODIFYDN_REQUEST = $6C; - LDAP_ASN1_MODIFYDN_RESPONSE = $6D; - LDAP_ASN1_COMPARE_REQUEST = $6E; - LDAP_ASN1_COMPARE_RESPONSE = $6F; - LDAP_ASN1_ABANDON_REQUEST = $70; - LDAP_ASN1_EXT_REQUEST = $77; - LDAP_ASN1_EXT_RESPONSE = $78; - LDAP_ASN1_CONTROLS = $A0; - - -type - - {:@abstract(LDAP attribute with list of their values) - This class holding name of LDAP attribute and list of their values. This is - descendant of TStringList class enhanced by some new properties.} - TLDAPAttribute = class(TStringList) - private - FAttributeName: AnsiString; - FIsBinary: Boolean; - protected - function Get(Index: integer): string; override; - procedure Put(Index: integer; const Value: string); override; - procedure SetAttributeName(Value: AnsiString); - public - function Add(const S: string): Integer; override; - published - {:Name of LDAP attribute.} - property AttributeName: AnsiString read FAttributeName Write SetAttributeName; - {:Return @true when attribute contains binary data.} - property IsBinary: Boolean read FIsBinary; - end; - - {:@abstract(List of @link(TLDAPAttribute)) - This object can hold list of TLDAPAttribute objects.} - TLDAPAttributeList = class(TObject) - private - FAttributeList: TList; - function GetAttribute(Index: integer): TLDAPAttribute; - public - constructor Create; - destructor Destroy; override; - {:Clear list.} - procedure Clear; - {:Return count of TLDAPAttribute objects in list.} - function Count: integer; - {:Add new TLDAPAttribute object to list.} - function Add: TLDAPAttribute; - {:Delete one TLDAPAttribute object from list.} - procedure Del(Index: integer); - {:Find and return attribute with requested name. Returns nil if not found.} - function Find(AttributeName: AnsiString): TLDAPAttribute; - {:Find and return attribute value with requested name. Returns empty string if not found.} - function Get(AttributeName: AnsiString): string; - {:List of TLDAPAttribute objects.} - property Items[Index: Integer]: TLDAPAttribute read GetAttribute; default; - end; - - {:@abstract(LDAP result object) - This object can hold LDAP object. (their name and all their attributes with - values)} - TLDAPResult = class(TObject) - private - FObjectName: AnsiString; - FAttributes: TLDAPAttributeList; - public - constructor Create; - destructor Destroy; override; - published - {:Name of this LDAP object.} - property ObjectName: AnsiString read FObjectName write FObjectName; - {:Here is list of object attributes.} - property Attributes: TLDAPAttributeList read FAttributes; - end; - - {:@abstract(List of LDAP result objects) - This object can hold list of LDAP objects. (for example result of LDAP SEARCH.)} - TLDAPResultList = class(TObject) - private - FResultList: TList; - function GetResult(Index: integer): TLDAPResult; - public - constructor Create; - destructor Destroy; override; - {:Clear all TLDAPResult objects in list.} - procedure Clear; - {:Return count of TLDAPResult objects in list.} - function Count: integer; - {:Create and add new TLDAPResult object to list.} - function Add: TLDAPResult; - {:List of TLDAPResult objects.} - property Items[Index: Integer]: TLDAPResult read GetResult; default; - end; - - {:Define possible operations for LDAP MODIFY operations.} - TLDAPModifyOp = ( - MO_Add, - MO_Delete, - MO_Replace - ); - - {:Specify possible values for search scope.} - TLDAPSearchScope = ( - SS_BaseObject, - SS_SingleLevel, - SS_WholeSubtree - ); - - {:Specify possible values about alias dereferencing.} - TLDAPSearchAliases = ( - SA_NeverDeref, - SA_InSearching, - SA_FindingBaseObj, - SA_Always - ); - - {:@abstract(Implementation of LDAP client) - (version 2 and 3) - - Note: Are you missing properties for setting Username and Password? Look to - parent @link(TSynaClient) object! - - Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TLDAPSend = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FResultCode: Integer; - FResultString: AnsiString; - FFullResult: AnsiString; - FAutoTLS: Boolean; - FFullSSL: Boolean; - FSeq: integer; - FResponseCode: integer; - FResponseDN: AnsiString; - FReferals: TStringList; - FVersion: integer; - FSearchScope: TLDAPSearchScope; - FSearchAliases: TLDAPSearchAliases; - FSearchSizeLimit: integer; - FSearchTimeLimit: integer; - FSearchPageSize: integer; - FSearchCookie: AnsiString; - FSearchResult: TLDAPResultList; - FExtName: AnsiString; - FExtValue: AnsiString; - function Connect: Boolean; - function BuildPacket(const Value: AnsiString): AnsiString; - function ReceiveResponse: AnsiString; - function DecodeResponse(const Value: AnsiString): AnsiString; - function LdapSasl(Value: AnsiString): AnsiString; - function TranslateFilter(Value: AnsiString): AnsiString; - function GetErrorString(Value: integer): AnsiString; - public - constructor Create; - destructor Destroy; override; - - {:Try to connect to LDAP server and start secure channel, when it is required.} - function Login: Boolean; - - {:Try to bind to LDAP server with @link(TSynaClient.Username) and - @link(TSynaClient.Password). If this is empty strings, then it do annonymous - Bind. When you not call Bind on LDAPv3, then is automaticly used anonymous - mode. - - This method using plaintext transport of password! It is not secure!} - function Bind: Boolean; - - {:Try to bind to LDAP server with @link(TSynaClient.Username) and - @link(TSynaClient.Password). If this is empty strings, then it do annonymous - Bind. When you not call Bind on LDAPv3, then is automaticly used anonymous - mode. - - This method using SASL with DIGEST-MD5 method for secure transfer of your - password.} - function BindSasl: Boolean; - - {:Close connection to LDAP server.} - function Logout: Boolean; - - {:Modify content of LDAP attribute on this object.} - function Modify(obj: AnsiString; Op: TLDAPModifyOp; const Value: TLDAPAttribute): Boolean; - - {:Add list of attributes to specified object.} - function Add(obj: AnsiString; const Value: TLDAPAttributeList): Boolean; - - {:Delete this LDAP object from server.} - function Delete(obj: AnsiString): Boolean; - - {:Modify object name of this LDAP object.} - function ModifyDN(obj, newRDN, newSuperior: AnsiString; DeleteoldRDN: Boolean): Boolean; - - {:Try to compare Attribute value with this LDAP object.} - function Compare(obj, AttributeValue: AnsiString): Boolean; - - {:Search LDAP base for LDAP objects by Filter.} - function Search(obj: AnsiString; TypesOnly: Boolean; Filter: AnsiString; - const Attributes: TStrings): Boolean; - - {:Call any LDAPv3 extended command.} - function Extended(const Name, Value: AnsiString): Boolean; - - {:Try to start SSL/TLS connection to LDAP server.} - function StartTLS: Boolean; - published - {:Specify version of used LDAP protocol. Default value is 3.} - property Version: integer read FVersion Write FVersion; - - {:Result code of last LDAP operation.} - property ResultCode: Integer read FResultCode; - - {:Human readable description of result code of last LDAP operation.} - property ResultString: AnsiString read FResultString; - - {:Binary string with full last response of LDAP server. This string is - encoded by ASN.1 BER encoding! You need this only for debugging.} - property FullResult: AnsiString read FFullResult; - - {:If @true, then try to start TSL mode in Login procedure.} - property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; - - {:If @true, then use connection to LDAP server through SSL/TLS tunnel.} - property FullSSL: Boolean read FFullSSL Write FFullSSL; - - {:Sequence number of last LDAp command. It is incremented by any LDAP command.} - property Seq: integer read FSeq; - - {:Specify what search scope is used in search command.} - property SearchScope: TLDAPSearchScope read FSearchScope Write FSearchScope; - - {:Specify how to handle aliases in search command.} - property SearchAliases: TLDAPSearchAliases read FSearchAliases Write FSearchAliases; - - {:Specify result size limit in search command. Value 0 means without limit.} - property SearchSizeLimit: integer read FSearchSizeLimit Write FSearchSizeLimit; - - {:Specify search time limit in search command (seconds). Value 0 means - without limit.} - property SearchTimeLimit: integer read FSearchTimeLimit Write FSearchTimeLimit; - - {:Specify number of results to return per search request. Value 0 means - no paging.} - property SearchPageSize: integer read FSearchPageSize Write FSearchPageSize; - - {:Cookie returned by paged search results. Use an empty string for the first - search request.} - property SearchCookie: AnsiString read FSearchCookie Write FSearchCookie; - - {:Here is result of search command.} - property SearchResult: TLDAPResultList read FSearchResult; - - {:On each LDAP operation can LDAP server return some referals URLs. Here is - their list.} - property Referals: TStringList read FReferals; - - {:When you call @link(Extended) operation, then here is result Name returned - by server.} - property ExtName: AnsiString read FExtName; - - {:When you call @link(Extended) operation, then here is result Value returned - by server.} - property ExtValue: AnsiString read FExtValue; - - {:TCP socket used by all LDAP operations.} - property Sock: TTCPBlockSocket read FSock; - end; - -{:Dump result of LDAP SEARCH into human readable form. Good for debugging.} -function LDAPResultDump(const Value: TLDAPResultList): AnsiString; - -implementation - -{==============================================================================} -function TLDAPAttribute.Add(const S: string): Integer; -begin - Result := inherited Add(''); - Put(Result,S); -end; - -function TLDAPAttribute.Get(Index: integer): string; -begin - Result := inherited Get(Index); - if FIsbinary then - Result := DecodeBase64(Result); -end; - -procedure TLDAPAttribute.Put(Index: integer; const Value: string); -var - s: AnsiString; -begin - s := Value; - if FIsbinary then - s := EncodeBase64(Value) - else - s :=UnquoteStr(s, '"'); - inherited Put(Index, s); -end; - -procedure TLDAPAttribute.SetAttributeName(Value: AnsiString); -begin - FAttributeName := Value; - FIsBinary := Pos(';binary', Lowercase(value)) > 0; -end; - -{==============================================================================} -constructor TLDAPAttributeList.Create; -begin - inherited Create; - FAttributeList := TList.Create; -end; - -destructor TLDAPAttributeList.Destroy; -begin - Clear; - FAttributeList.Free; - inherited Destroy; -end; - -procedure TLDAPAttributeList.Clear; -var - n: integer; - x: TLDAPAttribute; -begin - for n := Count - 1 downto 0 do - begin - x := GetAttribute(n); - if Assigned(x) then - x.Free; - end; - FAttributeList.Clear; -end; - -function TLDAPAttributeList.Count: integer; -begin - Result := FAttributeList.Count; -end; - -function TLDAPAttributeList.Get(AttributeName: AnsiString): string; -var - x: TLDAPAttribute; -begin - Result := ''; - x := self.Find(AttributeName); - if x <> nil then - if x.Count > 0 then - Result := x[0]; -end; - -function TLDAPAttributeList.GetAttribute(Index: integer): TLDAPAttribute; -begin - Result := nil; - if Index < Count then - Result := TLDAPAttribute(FAttributeList[Index]); -end; - -function TLDAPAttributeList.Add: TLDAPAttribute; -begin - Result := TLDAPAttribute.Create; - FAttributeList.Add(Result); -end; - -procedure TLDAPAttributeList.Del(Index: integer); -var - x: TLDAPAttribute; -begin - x := GetAttribute(Index); - if Assigned(x) then - x.free; - FAttributeList.Delete(Index); -end; - -function TLDAPAttributeList.Find(AttributeName: AnsiString): TLDAPAttribute; -var - n: integer; - x: TLDAPAttribute; -begin - Result := nil; - AttributeName := lowercase(AttributeName); - for n := 0 to Count - 1 do - begin - x := GetAttribute(n); - if Assigned(x) then - if lowercase(x.AttributeName) = Attributename then - begin - result := x; - break; - end; - end; -end; - -{==============================================================================} -constructor TLDAPResult.Create; -begin - inherited Create; - FAttributes := TLDAPAttributeList.Create; -end; - -destructor TLDAPResult.Destroy; -begin - FAttributes.Free; - inherited Destroy; -end; - -{==============================================================================} -constructor TLDAPResultList.Create; -begin - inherited Create; - FResultList := TList.Create; -end; - -destructor TLDAPResultList.Destroy; -begin - Clear; - FResultList.Free; - inherited Destroy; -end; - -procedure TLDAPResultList.Clear; -var - n: integer; - x: TLDAPResult; -begin - for n := Count - 1 downto 0 do - begin - x := GetResult(n); - if Assigned(x) then - x.Free; - end; - FResultList.Clear; -end; - -function TLDAPResultList.Count: integer; -begin - Result := FResultList.Count; -end; - -function TLDAPResultList.GetResult(Index: integer): TLDAPResult; -begin - Result := nil; - if Index < Count then - Result := TLDAPResult(FResultList[Index]); -end; - -function TLDAPResultList.Add: TLDAPResult; -begin - Result := TLDAPResult.Create; - FResultList.Add(Result); -end; - -{==============================================================================} -constructor TLDAPSend.Create; -begin - inherited Create; - FReferals := TStringList.Create; - FFullResult := ''; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FTimeout := 60000; - FTargetPort := cLDAPProtocol; - FAutoTLS := False; - FFullSSL := False; - FSeq := 0; - FVersion := 3; - FSearchScope := SS_WholeSubtree; - FSearchAliases := SA_Always; - FSearchSizeLimit := 0; - FSearchTimeLimit := 0; - FSearchPageSize := 0; - FSearchCookie := ''; - FSearchResult := TLDAPResultList.Create; -end; - -destructor TLDAPSend.Destroy; -begin - FSock.Free; - FSearchResult.Free; - FReferals.Free; - inherited Destroy; -end; - -function TLDAPSend.GetErrorString(Value: integer): AnsiString; -begin - case Value of - 0: - Result := 'Success'; - 1: - Result := 'Operations error'; - 2: - Result := 'Protocol error'; - 3: - Result := 'Time limit Exceeded'; - 4: - Result := 'Size limit Exceeded'; - 5: - Result := 'Compare FALSE'; - 6: - Result := 'Compare TRUE'; - 7: - Result := 'Auth method not supported'; - 8: - Result := 'Strong auth required'; - 9: - Result := '-- reserved --'; - 10: - Result := 'Referal'; - 11: - Result := 'Admin limit exceeded'; - 12: - Result := 'Unavailable critical extension'; - 13: - Result := 'Confidentality required'; - 14: - Result := 'Sasl bind in progress'; - 16: - Result := 'No such attribute'; - 17: - Result := 'Undefined attribute type'; - 18: - Result := 'Inappropriate matching'; - 19: - Result := 'Constraint violation'; - 20: - Result := 'Attribute or value exists'; - 21: - Result := 'Invalid attribute syntax'; - 32: - Result := 'No such object'; - 33: - Result := 'Alias problem'; - 34: - Result := 'Invalid DN syntax'; - 36: - Result := 'Alias dereferencing problem'; - 48: - Result := 'Inappropriate authentication'; - 49: - Result := 'Invalid credentials'; - 50: - Result := 'Insufficient access rights'; - 51: - Result := 'Busy'; - 52: - Result := 'Unavailable'; - 53: - Result := 'Unwilling to perform'; - 54: - Result := 'Loop detect'; - 64: - Result := 'Naming violation'; - 65: - Result := 'Object class violation'; - 66: - Result := 'Not allowed on non leaf'; - 67: - Result := 'Not allowed on RDN'; - 68: - Result := 'Entry already exists'; - 69: - Result := 'Object class mods prohibited'; - 71: - Result := 'Affects multiple DSAs'; - 80: - Result := 'Other'; - else - Result := '--unknown--'; - end; -end; - -function TLDAPSend.Connect: Boolean; -begin - // Do not call this function! It is calling by LOGIN method! - FSock.CloseSocket; - FSock.LineBuffer := ''; - FSeq := 0; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError = 0 then - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError = 0 then - if FFullSSL then - FSock.SSLDoConnect; - Result := FSock.LastError = 0; -end; - -function TLDAPSend.BuildPacket(const Value: AnsiString): AnsiString; -begin - Inc(FSeq); - Result := ASNObject(ASNObject(ASNEncInt(FSeq), ASN1_INT) + Value, ASN1_SEQ); -end; - -function TLDAPSend.ReceiveResponse: AnsiString; -var - x: Byte; - i,j: integer; -begin - Result := ''; - FFullResult := ''; - x := FSock.RecvByte(FTimeout); - if x <> ASN1_SEQ then - Exit; - Result := AnsiChar(x); - x := FSock.RecvByte(FTimeout); - Result := Result + AnsiChar(x); - if x < $80 then - i := 0 - else - i := x and $7F; - if i > 0 then - Result := Result + FSock.RecvBufferStr(i, Ftimeout); - if FSock.LastError <> 0 then - begin - Result := ''; - Exit; - end; - //get length of LDAP packet - j := 2; - i := ASNDecLen(j, Result); - //retreive rest of LDAP packet - if i > 0 then - Result := Result + FSock.RecvBufferStr(i, Ftimeout); - if FSock.LastError <> 0 then - begin - Result := ''; - Exit; - end; - FFullResult := Result; -end; - -function TLDAPSend.DecodeResponse(const Value: AnsiString): AnsiString; -var - i, x: integer; - Svt: Integer; - s, t: AnsiString; -begin - Result := ''; - FResultCode := -1; - FResultstring := ''; - FResponseCode := -1; - FResponseDN := ''; - FReferals.Clear; - i := 1; - ASNItem(i, Value, Svt); - x := StrToIntDef(ASNItem(i, Value, Svt), 0); - if (svt <> ASN1_INT) or (x <> FSeq) then - Exit; - s := ASNItem(i, Value, Svt); - FResponseCode := svt; - if FResponseCode in [LDAP_ASN1_BIND_RESPONSE, LDAP_ASN1_SEARCH_DONE, - LDAP_ASN1_MODIFY_RESPONSE, LDAP_ASN1_ADD_RESPONSE, LDAP_ASN1_DEL_RESPONSE, - LDAP_ASN1_MODIFYDN_RESPONSE, LDAP_ASN1_COMPARE_RESPONSE, - LDAP_ASN1_EXT_RESPONSE] then - begin - FResultCode := StrToIntDef(ASNItem(i, Value, Svt), -1); - FResponseDN := ASNItem(i, Value, Svt); - FResultString := ASNItem(i, Value, Svt); - if FResultString = '' then - FResultString := GetErrorString(FResultCode); - if FResultCode = 10 then - begin - s := ASNItem(i, Value, Svt); - if svt = $A3 then - begin - x := 1; - while x < Length(s) do - begin - t := ASNItem(x, s, Svt); - FReferals.Add(t); - end; - end; - end; - end; - Result := Copy(Value, i, Length(Value) - i + 1); -end; - -function TLDAPSend.LdapSasl(Value: AnsiString): AnsiString; -var - nonce, cnonce, nc, realm, qop, uri, response: AnsiString; - s: AnsiString; - a1, a2: AnsiString; - l: TStringList; - n: integer; -begin - l := TStringList.Create; - try - nonce := ''; - realm := ''; - l.CommaText := Value; - n := IndexByBegin('nonce=', l); - if n >= 0 then - nonce := UnQuoteStr(Trim(SeparateRight(l[n], 'nonce=')), '"'); - n := IndexByBegin('realm=', l); - if n >= 0 then - realm := UnQuoteStr(Trim(SeparateRight(l[n], 'realm=')), '"'); - cnonce := IntToHex(GetTick, 8); - nc := '00000001'; - qop := 'auth'; - uri := 'ldap/' + FSock.ResolveIpToName(FSock.GetRemoteSinIP); - a1 := md5(FUsername + ':' + realm + ':' + FPassword) - + ':' + nonce + ':' + cnonce; - a2 := 'AUTHENTICATE:' + uri; - s := strtohex(md5(a1))+':' + nonce + ':' + nc + ':' + cnonce + ':' - + qop +':'+strtohex(md5(a2)); - response := strtohex(md5(s)); - - Result := 'username="' + Fusername + '",realm="' + realm + '",nonce="'; - Result := Result + nonce + '",cnonce="' + cnonce + '",nc=' + nc + ',qop='; - Result := Result + qop + ',digest-uri="' + uri + '",response=' + response; - finally - l.Free; - end; -end; - -function TLDAPSend.TranslateFilter(Value: AnsiString): AnsiString; -var - x: integer; - s, t, l: AnsiString; - r: string; - c: Ansichar; - attr, rule: AnsiString; - dn: Boolean; -begin - Result := ''; - if Value = '' then - Exit; - s := Value; - if Value[1] = '(' then - begin - x := RPos(')', Value); - s := Copy(Value, 2, x - 2); - end; - if s = '' then - Exit; - case s[1] of - '!': - // NOT rule (recursive call) - begin - Result := ASNOBject(TranslateFilter(GetBetween('(', ')', s)), $A2); - end; - '&': - // AND rule (recursive call) - begin - repeat - t := GetBetween('(', ')', s); - s := Trim(SeparateRight(s, t)); - if s <> '' then - if s[1] = ')' then - {$IFDEF CIL}Borland.Delphi.{$ENDIF}System.Delete(s, 1, 1); - Result := Result + TranslateFilter(t); - until s = ''; - Result := ASNOBject(Result, $A0); - end; - '|': - // OR rule (recursive call) - begin - repeat - t := GetBetween('(', ')', s); - s := Trim(SeparateRight(s, t)); - if s <> '' then - if s[1] = ')' then - {$IFDEF CIL}Borland.Delphi.{$ENDIF}System.Delete(s, 1, 1); - Result := Result + TranslateFilter(t); - until s = ''; - Result := ASNOBject(Result, $A1); - end; - else - begin - l := Trim(SeparateLeft(s, '=')); - r := Trim(SeparateRight(s, '=')); - if l <> '' then - begin - c := l[Length(l)]; - case c of - ':': - // Extensible match - begin - {$IFDEF CIL}Borland.Delphi.{$ENDIF}System.Delete(l, Length(l), 1); - dn := False; - attr := ''; - rule := ''; - if Pos(':dn', l) > 0 then - begin - dn := True; - l := ReplaceString(l, ':dn', ''); - end; - attr := Trim(SeparateLeft(l, ':')); - rule := Trim(SeparateRight(l, ':')); - if rule = l then - rule := ''; - if rule <> '' then - Result := ASNObject(rule, $81); - if attr <> '' then - Result := Result + ASNObject(attr, $82); - Result := Result + ASNObject(DecodeTriplet(r, '\'), $83); - if dn then - Result := Result + ASNObject(AsnEncInt($ff), $84) - else - Result := Result + ASNObject(AsnEncInt(0), $84); - Result := ASNOBject(Result, $a9); - end; - '~': - // Approx match - begin - {$IFDEF CIL}Borland.Delphi.{$ENDIF}System.Delete(l, Length(l), 1); - Result := ASNOBject(l, ASN1_OCTSTR) - + ASNOBject(DecodeTriplet(r, '\'), ASN1_OCTSTR); - Result := ASNOBject(Result, $a8); - end; - '>': - // Greater or equal match - begin - {$IFDEF CIL}Borland.Delphi.{$ENDIF}System.Delete(l, Length(l), 1); - Result := ASNOBject(l, ASN1_OCTSTR) - + ASNOBject(DecodeTriplet(r, '\'), ASN1_OCTSTR); - Result := ASNOBject(Result, $a5); - end; - '<': - // Less or equal match - begin - {$IFDEF CIL}Borland.Delphi.{$ENDIF}System.Delete(l, Length(l), 1); - Result := ASNOBject(l, ASN1_OCTSTR) - + ASNOBject(DecodeTriplet(r, '\'), ASN1_OCTSTR); - Result := ASNOBject(Result, $a6); - end; - else - // present - if r = '*' then - Result := ASNOBject(l, $87) - else - if Pos('*', r) > 0 then - // substrings - begin - s := Fetch(r, '*'); - if s <> '' then - Result := ASNOBject(DecodeTriplet(s, '\'), $80); - while r <> '' do - begin - if Pos('*', r) <= 0 then - break; - s := Fetch(r, '*'); - Result := Result + ASNOBject(DecodeTriplet(s, '\'), $81); - end; - if r <> '' then - Result := Result + ASNOBject(DecodeTriplet(r, '\'), $82); - Result := ASNOBject(l, ASN1_OCTSTR) - + ASNOBject(Result, ASN1_SEQ); - Result := ASNOBject(Result, $a4); - end - else - begin - // Equality match - Result := ASNOBject(l, ASN1_OCTSTR) - + ASNOBject(DecodeTriplet(r, '\'), ASN1_OCTSTR); - Result := ASNOBject(Result, $a3); - end; - end; - end; - end; - end; -end; - -function TLDAPSend.Login: Boolean; -begin - Result := False; - if not Connect then - Exit; - Result := True; - if FAutoTLS then - Result := StartTLS; -end; - -function TLDAPSend.Bind: Boolean; -var - s: AnsiString; -begin - s := ASNObject(ASNEncInt(FVersion), ASN1_INT) - + ASNObject(FUsername, ASN1_OCTSTR) - + ASNObject(FPassword, $80); - s := ASNObject(s, LDAP_ASN1_BIND_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - Result := FResultCode = 0; -end; - -function TLDAPSend.BindSasl: Boolean; -var - s, t: AnsiString; - x, xt: integer; - digreq: AnsiString; -begin - Result := False; - if FPassword = '' then - Result := Bind - else - begin - digreq := ASNObject(ASNEncInt(FVersion), ASN1_INT) - + ASNObject('', ASN1_OCTSTR) - + ASNObject(ASNObject('DIGEST-MD5', ASN1_OCTSTR), $A3); - digreq := ASNObject(digreq, LDAP_ASN1_BIND_REQUEST); - Fsock.SendString(BuildPacket(digreq)); - s := ReceiveResponse; - t := DecodeResponse(s); - if FResultCode = 14 then - begin - s := t; - x := 1; - t := ASNItem(x, s, xt); - s := ASNObject(ASNEncInt(FVersion), ASN1_INT) - + ASNObject('', ASN1_OCTSTR) - + ASNObject(ASNObject('DIGEST-MD5', ASN1_OCTSTR) - + ASNObject(LdapSasl(t), ASN1_OCTSTR), $A3); - s := ASNObject(s, LDAP_ASN1_BIND_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - if FResultCode = 14 then - begin - Fsock.SendString(BuildPacket(digreq)); - s := ReceiveResponse; - DecodeResponse(s); - end; - Result := FResultCode = 0; - end; - end; -end; - -function TLDAPSend.Logout: Boolean; -begin - Fsock.SendString(BuildPacket(ASNObject('', LDAP_ASN1_UNBIND_REQUEST))); - FSock.CloseSocket; - Result := True; -end; - -function TLDAPSend.Modify(obj: AnsiString; Op: TLDAPModifyOp; const Value: TLDAPAttribute): Boolean; -var - s: AnsiString; - n: integer; -begin - s := ''; - for n := 0 to Value.Count -1 do - s := s + ASNObject(Value[n], ASN1_OCTSTR); - s := ASNObject(Value.AttributeName, ASN1_OCTSTR) + ASNObject(s, ASN1_SETOF); - s := ASNObject(ASNEncInt(Ord(Op)), ASN1_ENUM) + ASNObject(s, ASN1_SEQ); - s := ASNObject(s, ASN1_SEQ); - s := ASNObject(obj, ASN1_OCTSTR) + ASNObject(s, ASN1_SEQ); - s := ASNObject(s, LDAP_ASN1_MODIFY_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - Result := FResultCode = 0; -end; - -function TLDAPSend.Add(obj: AnsiString; const Value: TLDAPAttributeList): Boolean; -var - s, t: AnsiString; - n, m: integer; -begin - s := ''; - for n := 0 to Value.Count - 1 do - begin - t := ''; - for m := 0 to Value[n].Count - 1 do - t := t + ASNObject(Value[n][m], ASN1_OCTSTR); - t := ASNObject(Value[n].AttributeName, ASN1_OCTSTR) - + ASNObject(t, ASN1_SETOF); - s := s + ASNObject(t, ASN1_SEQ); - end; - s := ASNObject(obj, ASN1_OCTSTR) + ASNObject(s, ASN1_SEQ); - s := ASNObject(s, LDAP_ASN1_ADD_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - Result := FResultCode = 0; -end; - -function TLDAPSend.Delete(obj: AnsiString): Boolean; -var - s: AnsiString; -begin - s := ASNObject(obj, LDAP_ASN1_DEL_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - Result := FResultCode = 0; -end; - -function TLDAPSend.ModifyDN(obj, newRDN, newSuperior: AnsiString; DeleteOldRDN: Boolean): Boolean; -var - s: AnsiString; -begin - s := ASNObject(obj, ASN1_OCTSTR) + ASNObject(newRDN, ASN1_OCTSTR); - if DeleteOldRDN then - s := s + ASNObject(ASNEncInt($ff), ASN1_BOOL) - else - s := s + ASNObject(ASNEncInt(0), ASN1_BOOL); - if newSuperior <> '' then - s := s + ASNObject(newSuperior, $80); - s := ASNObject(s, LDAP_ASN1_MODIFYDN_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - Result := FResultCode = 0; -end; - -function TLDAPSend.Compare(obj, AttributeValue: AnsiString): Boolean; -var - s: AnsiString; -begin - s := ASNObject(Trim(SeparateLeft(AttributeValue, '=')), ASN1_OCTSTR) - + ASNObject(Trim(SeparateRight(AttributeValue, '=')), ASN1_OCTSTR); - s := ASNObject(obj, ASN1_OCTSTR) + ASNObject(s, ASN1_SEQ); - s := ASNObject(s, LDAP_ASN1_COMPARE_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - DecodeResponse(s); - Result := FResultCode = 0; -end; - -function TLDAPSend.Search(obj: AnsiString; TypesOnly: Boolean; Filter: AnsiString; - const Attributes: TStrings): Boolean; -var - s, t, u, c: AnsiString; - n, i, x: integer; - r: TLDAPResult; - a: TLDAPAttribute; -begin - FSearchResult.Clear; - FReferals.Clear; - s := ASNObject(obj, ASN1_OCTSTR); - s := s + ASNObject(ASNEncInt(Ord(FSearchScope)), ASN1_ENUM); - s := s + ASNObject(ASNEncInt(Ord(FSearchAliases)), ASN1_ENUM); - s := s + ASNObject(ASNEncInt(FSearchSizeLimit), ASN1_INT); - s := s + ASNObject(ASNEncInt(FSearchTimeLimit), ASN1_INT); - if TypesOnly then - s := s + ASNObject(ASNEncInt($ff), ASN1_BOOL) - else - s := s + ASNObject(ASNEncInt(0), ASN1_BOOL); - if Filter = '' then - Filter := '(objectclass=*)'; - t := TranslateFilter(Filter); - if t = '' then - s := s + ASNObject('', ASN1_NULL) - else - s := s + t; - t := ''; - for n := 0 to Attributes.Count - 1 do - t := t + ASNObject(Attributes[n], ASN1_OCTSTR); - s := s + ASNObject(t, ASN1_SEQ); - s := ASNObject(s, LDAP_ASN1_SEARCH_REQUEST); - if FSearchPageSize > 0 then - begin - c := ASNObject('1.2.840.113556.1.4.319', ASN1_OCTSTR); // controlType: pagedResultsControl - c := c + ASNObject(ASNEncInt(0), ASN1_BOOL); // criticality: FALSE - t := ASNObject(ASNEncInt(FSearchPageSize), ASN1_INT); // page size - t := t + ASNObject(FSearchCookie, ASN1_OCTSTR); // search cookie - t := ASNObject(t, ASN1_SEQ); // wrap with SEQUENCE - c := c + ASNObject(t, ASN1_OCTSTR); // add searchControlValue as OCTET STRING - c := ASNObject(c, ASN1_SEQ); // wrap with SEQUENCE - s := s + ASNObject(c, LDAP_ASN1_CONTROLS); // append Controls to SearchRequest - end; - Fsock.SendString(BuildPacket(s)); - repeat - s := ReceiveResponse; - t := DecodeResponse(s); - if FResponseCode = LDAP_ASN1_SEARCH_ENTRY then - begin - //dekoduj zaznam - r := FSearchResult.Add; - n := 1; - r.ObjectName := ASNItem(n, t, x); - ASNItem(n, t, x); - if x = ASN1_SEQ then - begin - while n < Length(t) do - begin - s := ASNItem(n, t, x); - if x = ASN1_SEQ then - begin - i := n + Length(s); - a := r.Attributes.Add; - u := ASNItem(n, t, x); - a.AttributeName := u; - ASNItem(n, t, x); - if x = ASN1_SETOF then - while n < i do - begin - u := ASNItem(n, t, x); - a.Add(u); - end; - end; - end; - end; - end; - if FResponseCode = LDAP_ASN1_SEARCH_REFERENCE then - begin - n := 1; - while n < Length(t) do - FReferals.Add(ASNItem(n, t, x)); - end; - until FResponseCode = LDAP_ASN1_SEARCH_DONE; - n := 1; - ASNItem(n, t, x); - if x = LDAP_ASN1_CONTROLS then - begin - ASNItem(n, t, x); - if x = ASN1_SEQ then - begin - s := ASNItem(n, t, x); - if s = '1.2.840.113556.1.4.319' then - begin - s := ASNItem(n, t, x); // searchControlValue - n := 1; - ASNItem(n, s, x); - if x = ASN1_SEQ then - begin - ASNItem(n, s, x); // total number of result records, if known, otherwise 0 - FSearchCookie := ASNItem(n, s, x); // active search cookie, empty when done - end; - end; - end; - end; - Result := FResultCode = 0; -end; - -function TLDAPSend.Extended(const Name, Value: AnsiString): Boolean; -var - s, t: AnsiString; - x, xt: integer; -begin - s := ASNObject(Name, $80); - if Value <> '' then - s := s + ASNObject(Value, $81); - s := ASNObject(s, LDAP_ASN1_EXT_REQUEST); - Fsock.SendString(BuildPacket(s)); - s := ReceiveResponse; - t := DecodeResponse(s); - Result := FResultCode = 0; - if Result then - begin - x := 1; - FExtName := ASNItem(x, t, xt); - FExtValue := ASNItem(x, t, xt); - end; -end; - - -function TLDAPSend.StartTLS: Boolean; -begin - Result := Extended('1.3.6.1.4.1.1466.20037', ''); - if Result then - begin - Fsock.SSLDoConnect; - Result := FSock.LastError = 0; - end; -end; - -{==============================================================================} -function LDAPResultDump(const Value: TLDAPResultList): AnsiString; -var - n, m, o: integer; - r: TLDAPResult; - a: TLDAPAttribute; -begin - Result := 'Results: ' + IntToStr(Value.Count) + CRLF +CRLF; - for n := 0 to Value.Count - 1 do - begin - Result := Result + 'Result: ' + IntToStr(n) + CRLF; - r := Value[n]; - Result := Result + ' Object: ' + r.ObjectName + CRLF; - for m := 0 to r.Attributes.Count - 1 do - begin - a := r.Attributes[m]; - Result := Result + ' Attribute: ' + a.AttributeName + CRLF; - for o := 0 to a.Count - 1 do - Result := Result + ' ' + a[o] + CRLF; - end; - end; -end; - -end. diff --git a/3rd/synapse/source/mimeinln.pas b/3rd/synapse/source/mimeinln.pas deleted file mode 100644 index 924dd5fd2..000000000 --- a/3rd/synapse/source/mimeinln.pas +++ /dev/null @@ -1,263 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.011 | -|==============================================================================| -| Content: Inline MIME support procedures and functions | -|==============================================================================| -| Copyright (c)1999-2006, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2006. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Utilities for inline MIME) -Support for Inline MIME encoding and decoding. - -Used RFC: RFC-2047, RFC-2231 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit mimeinln; - -interface - -uses - SysUtils, Classes, - synachar, synacode, synautil; - -{:Decodes mime inline encoding (i.e. in headers) uses target characterset "CP".} -function InlineDecode(const Value: string; CP: TMimeChar): string; - -{:Encodes string to MIME inline encoding. The source characterset is "CP", and - the target charset is "MimeP".} -function InlineEncode(const Value: string; CP, MimeP: TMimeChar): string; - -{:Returns @true, if "Value" contains characters needed for inline coding.} -function NeedInline(const Value: AnsiString): boolean; - -{:Inline mime encoding similar to @link(InlineEncode), but you can specify - source charset, and the target characterset is automatically assigned.} -function InlineCodeEx(const Value: string; FromCP: TMimeChar): string; - -{:Inline MIME encoding similar to @link(InlineEncode), but the source charset - is automatically set to the system default charset, and the target charset is - automatically assigned from set of allowed encoding for MIME.} -function InlineCode(const Value: string): string; - -{:Converts e-mail address to canonical mime form. You can specify source charset.} -function InlineEmailEx(const Value: string; FromCP: TMimeChar): string; - -{:Converts e-mail address to canonical mime form. Source charser it system - default charset.} -function InlineEmail(const Value: string): string; - -implementation - -{==============================================================================} - -function InlineDecode(const Value: string; CP: TMimeChar): string; -var - s, su, v: string; - x, y, z, n: Integer; - ichar: TMimeChar; - c: Char; - - function SearchEndInline(const Value: string; be: Integer): Integer; - var - n, q: Integer; - begin - q := 0; - Result := 0; - for n := be + 2 to Length(Value) - 1 do - if Value[n] = '?' then - begin - Inc(q); - if (q > 2) and (Value[n + 1] = '=') then - begin - Result := n; - Break; - end; - end; - end; - -begin - Result := ''; - v := Value; - x := Pos('=?', v); - y := SearchEndInline(v, x); - //fix for broken coding with begin, but not with end. - if (x > 0) and (y <= 0) then - y := Length(Result); - while (y > x) and (x > 0) do - begin - s := Copy(v, 1, x - 1); - if Trim(s) <> '' then - Result := Result + s; - s := Copy(v, x, y - x + 2); - Delete(v, 1, y + 1); - su := Copy(s, 3, Length(s) - 4); - z := Pos('?', su); - if (Length(su) >= (z + 2)) and (su[z + 2] = '?') then - begin - ichar := GetCPFromID(SeparateLeft(Copy(su, 1, z - 1), '*')); - c := UpperCase(su)[z + 1]; - su := Copy(su, z + 3, Length(su) - z - 2); - if c = 'B' then - begin - s := DecodeBase64(su); - s := CharsetConversion(s, ichar, CP); - end; - if c = 'Q' then - begin - s := ''; - for n := 1 to Length(su) do - if su[n] = '_' then - s := s + ' ' - else - s := s + su[n]; - s := DecodeQuotedPrintable(s); - s := CharsetConversion(s, ichar, CP); - end; - end; - Result := Result + s; - x := Pos('=?', v); - y := SearchEndInline(v, x); - end; - Result := Result + v; -end; - -{==============================================================================} - -function InlineEncode(const Value: string; CP, MimeP: TMimeChar): string; -var - s, s1, e: string; - n: Integer; -begin - s := CharsetConversion(Value, CP, MimeP); - s := EncodeSafeQuotedPrintable(s); - e := GetIdFromCP(MimeP); - s1 := ''; - Result := ''; - for n := 1 to Length(s) do - if s[n] = ' ' then - begin -// s1 := s1 + '=20'; - s1 := s1 + '_'; - if Length(s1) > 32 then - begin - if Result <> '' then - Result := Result + ' '; - Result := Result + '=?' + e + '?Q?' + s1 + '?='; - s1 := ''; - end; - end - else - s1 := s1 + s[n]; - if s1 <> '' then - begin - if Result <> '' then - Result := Result + ' '; - Result := Result + '=?' + e + '?Q?' + s1 + '?='; - end; -end; - -{==============================================================================} - -function NeedInline(const Value: AnsiString): boolean; -var - n: Integer; -begin - Result := False; - for n := 1 to Length(Value) do - if Value[n] in (SpecialChar + NonAsciiChar - ['_']) then - begin - Result := True; - Break; - end; -end; - -{==============================================================================} - -function InlineCodeEx(const Value: string; FromCP: TMimeChar): string; -var - c: TMimeChar; -begin - if NeedInline(Value) then - begin - c := IdealCharsetCoding(Value, FromCP, IdealCharsets); - Result := InlineEncode(Value, FromCP, c); - end - else - Result := Value; -end; - -{==============================================================================} - -function InlineCode(const Value: string): string; -begin - Result := InlineCodeEx(Value, GetCurCP); -end; - -{==============================================================================} - -function InlineEmailEx(const Value: string; FromCP: TMimeChar): string; -var - sd, se: string; -begin - sd := GetEmailDesc(Value); - se := GetEmailAddr(Value); - if sd = '' then - Result := se - else - Result := '"' + InlineCodeEx(sd, FromCP) + '" <' + se + '>'; -end; - -{==============================================================================} - -function InlineEmail(const Value: string): string; -begin - Result := InlineEmailEx(Value, GetCurCP); -end; - -end. diff --git a/3rd/synapse/source/mimemess.pas b/3rd/synapse/source/mimemess.pas deleted file mode 100644 index 0067b4ab8..000000000 --- a/3rd/synapse/source/mimemess.pas +++ /dev/null @@ -1,851 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.006.000 | -|==============================================================================| -| Content: MIME message object | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2012. | -| Portions created by Petr Fejfar are Copyright (c)2011-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM From distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(MIME message handling) -Classes for easy handling with e-mail message. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$M+} - -unit mimemess; - -interface - -uses - Classes, SysUtils, - mimepart, synachar, synautil, mimeinln; - -type - - {:Possible values for message priority} - TMessPriority = (MP_unknown, MP_low, MP_normal, MP_high); - - {:@abstract(Object for basic e-mail header fields.)} - TMessHeader = class(TObject) - private - FFrom: string; - FToList: TStringList; - FCCList: TStringList; - FSubject: string; - FOrganization: string; - FCustomHeaders: TStringList; - FDate: TDateTime; - FXMailer: string; - FCharsetCode: TMimeChar; - FReplyTo: string; - FMessageID: string; - FPriority: TMessPriority; - Fpri: TMessPriority; - Fxpri: TMessPriority; - Fxmspri: TMessPriority; - protected - function ParsePriority(value: string): TMessPriority; - function DecodeHeader(value: string): boolean; virtual; - public - constructor Create; virtual; - destructor Destroy; override; - - {:Clears all data fields.} - procedure Clear; virtual; - - {Add headers from from this object to Value.} - procedure EncodeHeaders(const Value: TStrings); virtual; - - {:Parse header from Value to this object.} - procedure DecodeHeaders(const Value: TStrings); - - {:Try find specific header in CustomHeader. Search is case insensitive. - This is good for reading any non-parsed header.} - function FindHeader(Value: string): string; - - {:Try find specific headers in CustomHeader. This metod is for repeatly used - headers like 'received' header, etc. Search is case insensitive. - This is good for reading ano non-parsed header.} - procedure FindHeaderList(Value: string; const HeaderList: TStrings); - published - {:Sender of message.} - property From: string read FFrom Write FFrom; - - {:Stringlist with receivers of message. (one per line)} - property ToList: TStringList read FToList; - - {:Stringlist with Carbon Copy receivers of message. (one per line)} - property CCList: TStringList read FCCList; - - {:Subject of message.} - property Subject: string read FSubject Write FSubject; - - {:Organization string.} - property Organization: string read FOrganization Write FOrganization; - - {:After decoding contains all headers lines witch not have parsed to any - other structures in this object. It mean: this conatins all other headers - except: - - X-MAILER, FROM, SUBJECT, ORGANIZATION, TO, CC, DATE, MIME-VERSION, - CONTENT-TYPE, CONTENT-DESCRIPTION, CONTENT-DISPOSITION, CONTENT-ID, - CONTENT-TRANSFER-ENCODING, REPLY-TO, MESSAGE-ID, X-MSMAIL-PRIORITY, - X-PRIORITY, PRIORITY - - When you encode headers, all this lines is added as headers. Be carefull - for duplicites!} - property CustomHeaders: TStringList read FCustomHeaders; - - {:Date and time of message.} - property Date: TDateTime read FDate Write FDate; - - {:Mailer identification.} - property XMailer: string read FXMailer Write FXMailer; - - {:Address for replies} - property ReplyTo: string read FReplyTo Write FReplyTo; - - {:message indetifier} - property MessageID: string read FMessageID Write FMessageID; - - {:message priority} - property Priority: TMessPriority read FPriority Write FPriority; - - {:Specify base charset. By default is used system charset.} - property CharsetCode: TMimeChar read FCharsetCode Write FCharsetCode; - end; - - TMessHeaderClass = class of TMessHeader; - - {:@abstract(Object for handling of e-mail message.)} - TMimeMess = class(TObject) - private - FMessagePart: TMimePart; - FLines: TStringList; - FHeader: TMessHeader; - public - constructor Create; - {:create this object and assign your own descendant of @link(TMessHeader) - object to @link(header) property. So, you can create your own message - headers parser and use it by this object.} - constructor CreateAltHeaders(HeadClass: TMessHeaderClass); - destructor Destroy; override; - - {:Reset component to default state.} - procedure Clear; virtual; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then one subpart, - you must have PartParent of multipart type!} - function AddPart(const PartParent: TMimePart): TMimePart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, you - must have PartParent of multipart type! - - This part is marked as multipart with secondary MIME type specified by - MultipartType parameter. (typical value is 'mixed') - - This part can be used as PartParent for another parts (include next - multipart). If you need only one part, then you not need Multipart part.} - function AddPartMultipart(const MultipartType: String; const PartParent: TMimePart): TMimePart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, you - must have PartParent of multipart type! - - After creation of part set type to text part and set all necessary - properties. Content of part is readed from value stringlist.} - function AddPartText(const Value: TStrings; const PartParent: TMimePart): TMimepart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, you - must have PartParent of multipart type! - - After creation of part set type to text part and set all necessary - properties. Content of part is readed from value stringlist. You can select - your charset and your encoding type. If Raw is @true, then it not doing - charset conversion!} - function AddPartTextEx(const Value: TStrings; const PartParent: TMimePart; - PartCharset: TMimeChar; Raw: Boolean; PartEncoding: TMimeEncoding): TMimepart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, you - must have PartParent of multipart type! - - After creation of part set type to text part to HTML type and set all - necessary properties. Content of HTML part is readed from Value stringlist.} - function AddPartHTML(const Value: TStrings; const PartParent: TMimePart): TMimepart; - - {:Same as @link(AddPartText), but content is readed from file} - function AddPartTextFromFile(const FileName: String; const PartParent: TMimePart): TMimepart; - - {:Same as @link(AddPartHTML), but content is readed from file} - function AddPartHTMLFromFile(const FileName: String; const PartParent: TMimePart): TMimepart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, - you must have PartParent of multipart type! - - After creation of part set type to binary and set all necessary properties. - MIME primary and secondary types defined automaticly by filename extension. - Content of binary part is readed from Stream. This binary part is encoded - as file attachment.} - function AddPartBinary(const Stream: TStream; const FileName: string; const PartParent: TMimePart): TMimepart; - - {:Same as @link(AddPartBinary), but content is readed from file} - function AddPartBinaryFromFile(const FileName: string; const PartParent: TMimePart): TMimepart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, you - must have PartParent of multipart type! - - After creation of part set type to binary and set all necessary properties. - MIME primary and secondary types defined automaticly by filename extension. - Content of binary part is readed from Stream. - - This binary part is encoded as inline data with given Conten ID (cid). - Content ID can be used as reference ID in HTML source in HTML part.} - function AddPartHTMLBinary(const Stream: TStream; const FileName, Cid: string; const PartParent: TMimePart): TMimepart; - - {:Same as @link(AddPartHTMLBinary), but content is readed from file} - function AddPartHTMLBinaryFromFile(const FileName, Cid: string; const PartParent: TMimePart): TMimepart; - - {:Add MIME part as subpart of PartParent. If you need set root MIME part, - then set as PartParent @NIL value. If you need set more then 1 subpart, you - must have PartParent of multipart type! - - After creation of part set type to message and set all necessary properties. - MIME primary and secondary types are setted to 'message/rfc822'. - Content of raw RFC-822 message is readed from Stream.} - function AddPartMess(const Value: TStrings; const PartParent: TMimePart): TMimepart; - - {:Same as @link(AddPartMess), but content is readed from file} - function AddPartMessFromFile(const FileName: string; const PartParent: TMimePart): TMimepart; - - {:Compose message from @link(MessagePart) to @link(Lines). Headers from - @link(Header) object is added also.} - procedure EncodeMessage; virtual; - - {:Decode message from @link(Lines) to @link(MessagePart). Massage headers - are parsed into @link(Header) object.} - procedure DecodeMessage; virtual; - - {pf} - {: HTTP message is received by @link(THTTPSend) component in two parts: - headers are stored in @link(THTTPSend.Headers) and a body in memory stream - @link(THTTPSend.Document). - - On the top of it, HTTP connections are always 8-bit, hence data are - transferred in native format i.e. no transfer encoding is applied. - - This method operates the similiar way and produces the same - result as @link(DecodeMessage). - } - procedure DecodeMessageBinary(AHeader:TStrings; AData:TMemoryStream); - {/pf} - published - {:@link(TMimePart) object with decoded MIME message. This object can handle - any number of nested @link(TMimePart) objects itself. It is used for handle - any tree of MIME subparts.} - property MessagePart: TMimePart read FMessagePart; - - {:Raw MIME encoded message.} - property Lines: TStringList read FLines; - - {:Object for e-mail header fields. This object is created automaticly. - Do not free this object!} - property Header: TMessHeader read FHeader; - end; - -implementation - -{==============================================================================} - -constructor TMessHeader.Create; -begin - inherited Create; - FToList := TStringList.Create; - FCCList := TStringList.Create; - FCustomHeaders := TStringList.Create; - FCharsetCode := GetCurCP; -end; - -destructor TMessHeader.Destroy; -begin - FCustomHeaders.Free; - FCCList.Free; - FToList.Free; - inherited Destroy; -end; - -{==============================================================================} - -procedure TMessHeader.Clear; -begin - FFrom := ''; - FToList.Clear; - FCCList.Clear; - FSubject := ''; - FOrganization := ''; - FCustomHeaders.Clear; - FDate := 0; - FXMailer := ''; - FReplyTo := ''; - FMessageID := ''; - FPriority := MP_unknown; -end; - -procedure TMessHeader.EncodeHeaders(const Value: TStrings); -var - n: Integer; - s: string; -begin - if FDate = 0 then - FDate := Now; - for n := FCustomHeaders.Count - 1 downto 0 do - if FCustomHeaders[n] <> '' then - Value.Insert(0, FCustomHeaders[n]); - if FPriority <> MP_unknown then - case FPriority of - MP_high: - begin - Value.Insert(0, 'X-MSMAIL-Priority: High'); - Value.Insert(0, 'X-Priority: 1'); - Value.Insert(0, 'Priority: urgent'); - end; - MP_low: - begin - Value.Insert(0, 'X-MSMAIL-Priority: low'); - Value.Insert(0, 'X-Priority: 5'); - Value.Insert(0, 'Priority: non-urgent'); - end; - end; - if FReplyTo <> '' then - Value.Insert(0, 'Reply-To: ' + GetEmailAddr(FReplyTo)); - if FMessageID <> '' then - Value.Insert(0, 'Message-ID: <' + trim(FMessageID) + '>'); - if FXMailer = '' then - Value.Insert(0, 'X-mailer: Synapse - Pascal TCP/IP library by Lukas Gebauer') - else - Value.Insert(0, 'X-mailer: ' + FXMailer); - Value.Insert(0, 'MIME-Version: 1.0 (produced by Synapse)'); - if FOrganization <> '' then - Value.Insert(0, 'Organization: ' + InlineCodeEx(FOrganization, FCharsetCode)); - s := ''; - for n := 0 to FCCList.Count - 1 do - if s = '' then - s := InlineEmailEx(FCCList[n], FCharsetCode) - else - s := s + ', ' + InlineEmailEx(FCCList[n], FCharsetCode); - if s <> '' then - Value.Insert(0, 'CC: ' + s); - Value.Insert(0, 'Date: ' + Rfc822DateTime(FDate)); - if FSubject <> '' then - Value.Insert(0, 'Subject: ' + InlineCodeEx(FSubject, FCharsetCode)); - s := ''; - for n := 0 to FToList.Count - 1 do - if s = '' then - s := InlineEmailEx(FToList[n], FCharsetCode) - else - s := s + ', ' + InlineEmailEx(FToList[n], FCharsetCode); - if s <> '' then - Value.Insert(0, 'To: ' + s); - Value.Insert(0, 'From: ' + InlineEmailEx(FFrom, FCharsetCode)); -end; - -function TMessHeader.ParsePriority(value: string): TMessPriority; -var - s: string; - x: integer; -begin - Result := MP_unknown; - s := Trim(separateright(value, ':')); - s := Separateleft(s, ' '); - x := StrToIntDef(s, -1); - if x >= 0 then - case x of - 1, 2: - Result := MP_High; - 3: - Result := MP_Normal; - 4, 5: - Result := MP_Low; - end - else - begin - s := lowercase(s); - if (s = 'urgent') or (s = 'high') or (s = 'highest') then - Result := MP_High; - if (s = 'normal') or (s = 'medium') then - Result := MP_Normal; - if (s = 'low') or (s = 'lowest') - or (s = 'no-priority') or (s = 'non-urgent') then - Result := MP_Low; - end; -end; - -function TMessHeader.DecodeHeader(value: string): boolean; -var - s, t: string; - cp: TMimeChar; -begin - Result := True; - cp := FCharsetCode; - s := uppercase(value); - if Pos('X-MAILER:', s) = 1 then - begin - FXMailer := Trim(SeparateRight(Value, ':')); - Exit; - end; - if Pos('FROM:', s) = 1 then - begin - FFrom := InlineDecode(Trim(SeparateRight(Value, ':')), cp); - Exit; - end; - if Pos('SUBJECT:', s) = 1 then - begin - FSubject := InlineDecode(Trim(SeparateRight(Value, ':')), cp); - Exit; - end; - if Pos('ORGANIZATION:', s) = 1 then - begin - FOrganization := InlineDecode(Trim(SeparateRight(Value, ':')), cp); - Exit; - end; - if Pos('TO:', s) = 1 then - begin - s := Trim(SeparateRight(Value, ':')); - repeat - t := InlineDecode(Trim(FetchEx(s, ',', '"')), cp); - if t <> '' then - FToList.Add(t); - until s = ''; - Exit; - end; - if Pos('CC:', s) = 1 then - begin - s := Trim(SeparateRight(Value, ':')); - repeat - t := InlineDecode(Trim(FetchEx(s, ',', '"')), cp); - if t <> '' then - FCCList.Add(t); - until s = ''; - Exit; - end; - if Pos('DATE:', s) = 1 then - begin - FDate := DecodeRfcDateTime(Trim(SeparateRight(Value, ':'))); - Exit; - end; - if Pos('REPLY-TO:', s) = 1 then - begin - FReplyTo := InlineDecode(Trim(SeparateRight(Value, ':')), cp); - Exit; - end; - if Pos('MESSAGE-ID:', s) = 1 then - begin - FMessageID := GetEmailAddr(Trim(SeparateRight(Value, ':'))); - Exit; - end; - if Pos('PRIORITY:', s) = 1 then - begin - FPri := ParsePriority(value); - Exit; - end; - if Pos('X-PRIORITY:', s) = 1 then - begin - FXPri := ParsePriority(value); - Exit; - end; - if Pos('X-MSMAIL-PRIORITY:', s) = 1 then - begin - FXmsPri := ParsePriority(value); - Exit; - end; - if Pos('MIME-VERSION:', s) = 1 then - Exit; - if Pos('CONTENT-TYPE:', s) = 1 then - Exit; - if Pos('CONTENT-DESCRIPTION:', s) = 1 then - Exit; - if Pos('CONTENT-DISPOSITION:', s) = 1 then - Exit; - if Pos('CONTENT-ID:', s) = 1 then - Exit; - if Pos('CONTENT-TRANSFER-ENCODING:', s) = 1 then - Exit; - Result := False; -end; - -procedure TMessHeader.DecodeHeaders(const Value: TStrings); -var - s: string; - x: Integer; -begin - Clear; - Fpri := MP_unknown; - Fxpri := MP_unknown; - Fxmspri := MP_unknown; - x := 0; - while Value.Count > x do - begin - s := NormalizeHeader(Value, x); - if s = '' then - Break; - if not DecodeHeader(s) then - FCustomHeaders.Add(s); - end; - if Fpri <> MP_unknown then - FPriority := Fpri - else - if Fxpri <> MP_unknown then - FPriority := Fxpri - else - if Fxmspri <> MP_unknown then - FPriority := Fxmspri -end; - -function TMessHeader.FindHeader(Value: string): string; -var - n: integer; -begin - Result := ''; - for n := 0 to FCustomHeaders.Count - 1 do - if Pos(UpperCase(Value), UpperCase(FCustomHeaders[n])) = 1 then - begin - Result := Trim(SeparateRight(FCustomHeaders[n], ':')); - break; - end; -end; - -procedure TMessHeader.FindHeaderList(Value: string; const HeaderList: TStrings); -var - n: integer; -begin - HeaderList.Clear; - for n := 0 to FCustomHeaders.Count - 1 do - if Pos(UpperCase(Value), UpperCase(FCustomHeaders[n])) = 1 then - begin - HeaderList.Add(Trim(SeparateRight(FCustomHeaders[n], ':'))); - end; -end; - -{==============================================================================} - -constructor TMimeMess.Create; -begin - CreateAltHeaders(TMessHeader); -end; - -constructor TMimeMess.CreateAltHeaders(HeadClass: TMessHeaderClass); -begin - inherited Create; - FMessagePart := TMimePart.Create; - FLines := TStringList.Create; - FHeader := HeadClass.Create; -end; - -destructor TMimeMess.Destroy; -begin - FMessagePart.Free; - FHeader.Free; - FLines.Free; - inherited Destroy; -end; - -{==============================================================================} - -procedure TMimeMess.Clear; -begin - FMessagePart.Clear; - FLines.Clear; - FHeader.Clear; -end; - -{==============================================================================} - -function TMimeMess.AddPart(const PartParent: TMimePart): TMimePart; -begin - if PartParent = nil then - Result := FMessagePart - else - Result := PartParent.AddSubPart; - Result.Clear; -end; - -{==============================================================================} - -function TMimeMess.AddPartMultipart(const MultipartType: String; const PartParent: TMimePart): TMimePart; -begin - Result := AddPart(PartParent); - with Result do - begin - Primary := 'Multipart'; - Secondary := MultipartType; - Description := 'Multipart message'; - Boundary := GenerateBoundary; - EncodePartHeader; - end; -end; - -function TMimeMess.AddPartText(const Value: TStrings; const PartParent: TMimePart): TMimepart; -begin - Result := AddPart(PartParent); - with Result do - begin - Value.SaveToStream(DecodedLines); - Primary := 'text'; - Secondary := 'plain'; - Description := 'Message text'; - Disposition := 'inline'; - CharsetCode := IdealCharsetCoding(Value.Text, TargetCharset, IdealCharsets); - EncodingCode := ME_QUOTED_PRINTABLE; - EncodePart; - EncodePartHeader; - end; -end; - -function TMimeMess.AddPartTextEx(const Value: TStrings; const PartParent: TMimePart; - PartCharset: TMimeChar; Raw: Boolean; PartEncoding: TMimeEncoding): TMimepart; -begin - Result := AddPart(PartParent); - with Result do - begin - Value.SaveToStream(DecodedLines); - Primary := 'text'; - Secondary := 'plain'; - Description := 'Message text'; - Disposition := 'inline'; - CharsetCode := PartCharset; - EncodingCode := PartEncoding; - ConvertCharset := not Raw; - EncodePart; - EncodePartHeader; - end; -end; - -function TMimeMess.AddPartHTML(const Value: TStrings; const PartParent: TMimePart): TMimepart; -begin - Result := AddPart(PartParent); - with Result do - begin - Value.SaveToStream(DecodedLines); - Primary := 'text'; - Secondary := 'html'; - Description := 'HTML text'; - Disposition := 'inline'; - CharsetCode := UTF_8; - EncodingCode := ME_QUOTED_PRINTABLE; - EncodePart; - EncodePartHeader; - end; -end; - -function TMimeMess.AddPartTextFromFile(const FileName: String; const PartParent: TMimePart): TMimepart; -var - tmp: TStrings; -begin - tmp := TStringList.Create; - try - tmp.LoadFromFile(FileName); - Result := AddPartText(tmp, PartParent); - Finally - tmp.Free; - end; -end; - -function TMimeMess.AddPartHTMLFromFile(const FileName: String; const PartParent: TMimePart): TMimepart; -var - tmp: TStrings; -begin - tmp := TStringList.Create; - try - tmp.LoadFromFile(FileName); - Result := AddPartHTML(tmp, PartParent); - Finally - tmp.Free; - end; -end; - -function TMimeMess.AddPartBinary(const Stream: TStream; const FileName: string; const PartParent: TMimePart): TMimepart; -begin - Result := AddPart(PartParent); - Result.DecodedLines.LoadFromStream(Stream); - Result.MimeTypeFromExt(FileName); - Result.Description := 'Attached file: ' + FileName; - Result.Disposition := 'attachment'; - Result.FileName := FileName; - Result.EncodingCode := ME_BASE64; - Result.EncodePart; - Result.EncodePartHeader; -end; - -function TMimeMess.AddPartBinaryFromFile(const FileName: string; const PartParent: TMimePart): TMimepart; -var - tmp: TMemoryStream; -begin - tmp := TMemoryStream.Create; - try - tmp.LoadFromFile(FileName); - Result := AddPartBinary(tmp, ExtractFileName(FileName), PartParent); - finally - tmp.Free; - end; -end; - -function TMimeMess.AddPartHTMLBinary(const Stream: TStream; const FileName, Cid: string; const PartParent: TMimePart): TMimepart; -begin - Result := AddPart(PartParent); - Result.DecodedLines.LoadFromStream(Stream); - Result.MimeTypeFromExt(FileName); - Result.Description := 'Included file: ' + FileName; - Result.Disposition := 'inline'; - Result.ContentID := Cid; - Result.FileName := FileName; - Result.EncodingCode := ME_BASE64; - Result.EncodePart; - Result.EncodePartHeader; -end; - -function TMimeMess.AddPartHTMLBinaryFromFile(const FileName, Cid: string; const PartParent: TMimePart): TMimepart; -var - tmp: TMemoryStream; -begin - tmp := TMemoryStream.Create; - try - tmp.LoadFromFile(FileName); - Result :=AddPartHTMLBinary(tmp, ExtractFileName(FileName), Cid, PartParent); - finally - tmp.Free; - end; -end; - -function TMimeMess.AddPartMess(const Value: TStrings; const PartParent: TMimePart): TMimepart; -var - part: Tmimepart; -begin - Result := AddPart(PartParent); - part := AddPart(result); - part.lines.addstrings(Value); - part.DecomposeParts; - with Result do - begin - Primary := 'message'; - Secondary := 'rfc822'; - Description := 'E-mail Message'; - EncodePart; - EncodePartHeader; - end; -end; - -function TMimeMess.AddPartMessFromFile(const FileName: String; const PartParent: TMimePart): TMimepart; -var - tmp: TStrings; -begin - tmp := TStringList.Create; - try - tmp.LoadFromFile(FileName); - Result := AddPartMess(tmp, PartParent); - Finally - tmp.Free; - end; -end; - -{==============================================================================} - -procedure TMimeMess.EncodeMessage; -var - l: TStringList; - x: integer; -begin - //merge headers from THeaders and header field from MessagePart - l := TStringList.Create; - try - FHeader.EncodeHeaders(l); - x := IndexByBegin('CONTENT-TYPE', FMessagePart.Headers); - if x >= 0 then - l.add(FMessagePart.Headers[x]); - x := IndexByBegin('CONTENT-DESCRIPTION', FMessagePart.Headers); - if x >= 0 then - l.add(FMessagePart.Headers[x]); - x := IndexByBegin('CONTENT-DISPOSITION', FMessagePart.Headers); - if x >= 0 then - l.add(FMessagePart.Headers[x]); - x := IndexByBegin('CONTENT-ID', FMessagePart.Headers); - if x >= 0 then - l.add(FMessagePart.Headers[x]); - x := IndexByBegin('CONTENT-TRANSFER-ENCODING', FMessagePart.Headers); - if x >= 0 then - l.add(FMessagePart.Headers[x]); - FMessagePart.Headers.Assign(l); - finally - l.Free; - end; - FMessagePart.ComposeParts; - FLines.Assign(FMessagePart.Lines); -end; - -{==============================================================================} - -procedure TMimeMess.DecodeMessage; -begin - FHeader.Clear; - FHeader.DecodeHeaders(FLines); - FMessagePart.Lines.Assign(FLines); - FMessagePart.DecomposeParts; -end; - -{pf} -procedure TMimeMess.DecodeMessageBinary(AHeader:TStrings; AData:TMemoryStream); -begin - FHeader.Clear; - FLines.Clear; - FLines.Assign(AHeader); - FHeader.DecodeHeaders(FLines); - FMessagePart.DecomposePartsBinary(AHeader,PANSIChar(AData.Memory),PANSIChar(AData.Memory)+AData.Size); -end; -{/pf} - -end. diff --git a/3rd/synapse/source/mimepart.pas b/3rd/synapse/source/mimepart.pas deleted file mode 100644 index a637e676b..000000000 --- a/3rd/synapse/source/mimepart.pas +++ /dev/null @@ -1,1227 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.009.000 | -|==============================================================================| -| Content: MIME support procedures and functions | -|==============================================================================| -| Copyright (c)1999-200812 | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2012. | -| Portions created by Petr Fejfar are Copyright (c)2011-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(MIME part handling) -Handling with MIME parts. - -Used RFC: RFC-2045 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$Q-} -{$R-} -{$M+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit mimepart; - -interface - -uses - SysUtils, Classes, - synafpc, - synachar, synacode, synautil, mimeinln; - -type - - TMimePart = class; - - {:@abstract(Procedural type for @link(TMimepart.Walkpart) hook). This hook is used for - easy walking through MIME subparts.} - THookWalkPart = procedure(const Sender: TMimePart) of object; - - {:The four types of MIME parts. (textual, multipart, message or any other - binary data.)} - TMimePrimary = (MP_TEXT, MP_MULTIPART, MP_MESSAGE, MP_BINARY); - - {:The various types of possible part encodings.} - TMimeEncoding = (ME_7BIT, ME_8BIT, ME_QUOTED_PRINTABLE, - ME_BASE64, ME_UU, ME_XX); - - {:@abstract(Object for working with parts of MIME e-mail.) - Each TMimePart object can handle any number of nested subparts as new - TMimepart objects. It can handle any tree hierarchy structure of nested MIME - subparts itself. - - Basic tasks are: - - Decoding of MIME message: - - store message into Lines property - - call DecomposeParts. Now you have decomposed MIME parts in all nested levels! - - now you can explore all properties and subparts. (You can use WalkPart method) - - if you need decode part, call DecodePart. - - Encoding of MIME message: - - - if you need multipart message, you must create subpart by AddSubPart. - - set all properties of all parts. - - set content of part into DecodedLines stream - - encode this stream by EncodePart. - - compose full message by ComposeParts. (it build full MIME message from all subparts. Do not call this method for each subpart! It is needed on root part!) - - encoded MIME message is stored in Lines property. - } - TMimePart = class(TObject) - private - FPrimary: string; - FPrimaryCode: TMimePrimary; - FSecondary: string; - FEncoding: string; - FEncodingCode: TMimeEncoding; - FDefaultCharset: string; - FCharset: string; - FCharsetCode: TMimeChar; - FTargetCharset: TMimeChar; - FDescription: string; - FDisposition: string; - FContentID: string; - FBoundary: string; - FFileName: string; - FLines: TStringList; - FPartBody: TStringList; - FHeaders: TStringList; - FPrePart: TStringList; - FPostPart: TStringList; - FDecodedLines: TMemoryStream; - FSubParts: TList; - FOnWalkPart: THookWalkPart; - FMaxLineLength: integer; - FSubLevel: integer; - FMaxSubLevel: integer; - FAttachInside: boolean; - FConvertCharset: Boolean; - FForcedHTMLConvert: Boolean; - FBinaryDecomposer: boolean; - procedure SetPrimary(Value: string); - procedure SetEncoding(Value: string); - procedure SetCharset(Value: string); - function IsUUcode(Value: string): boolean; - public - constructor Create; - destructor Destroy; override; - - {:Assign content of another object to this object. (Only this part, - not subparts!)} - procedure Assign(Value: TMimePart); - - {:Assign content of another object to this object. (With all subparts!)} - procedure AssignSubParts(Value: TMimePart); - - {:Clear all data values to default values. It also call @link(ClearSubparts).} - procedure Clear; - - {:Decode Mime part from @link(Lines) to @link(DecodedLines).} - procedure DecodePart; - - {:Parse header lines from Headers property into another properties.} - procedure DecodePartHeader; - - {:Encode mime part from @link(DecodedLines) to @link(Lines) and build mime - headers.} - procedure EncodePart; - - {:Build header lines in Headers property from another properties.} - procedure EncodePartHeader; - - {:generate primary and secondary mime type from filename extension in value. - If type not recognised, it return 'Application/octet-string' type.} - procedure MimeTypeFromExt(Value: string); - - {:Return number of decomposed subparts. (On this level! Each of this - subparts can hold any number of their own nested subparts!)} - function GetSubPartCount: integer; - - {:Get nested subpart object as new TMimePart. For getting maximum possible - index you can use @link(GetSubPartCount) method.} - function GetSubPart(index: integer): TMimePart; - - {:delete subpart on given index.} - procedure DeleteSubPart(index: integer); - - {:Clear and destroy all subpart TMimePart objects.} - procedure ClearSubParts; - - {:Add and create new subpart.} - function AddSubPart: TMimePart; - - {:E-mail message in @link(Lines) property is parsed into this object. - E-mail headers are stored in @link(Headers) property and is parsed into - another properties automaticly. Not need call @link(DecodePartHeader)! - Content of message (part) is stored into @link(PartBody) property. This - part is in undecoded form! If you need decode it, then you must call - @link(DecodePart) method by your hands. Lot of another properties is filled - also. - - Decoding of parts you must call separately due performance reasons. (Not - needed to decode all parts in all reasons.) - - For each MIME subpart is created new TMimepart object (accessible via - method @link(GetSubPart)).} - procedure DecomposeParts; - - {pf} - {: HTTP message is received by @link(THTTPSend) component in two parts: - headers are stored in @link(THTTPSend.Headers) and a body in memory stream - @link(THTTPSend.Document). - - On the top of it, HTTP connections are always 8-bit, hence data are - transferred in native format i.e. no transfer encoding is applied. - - This method operates the similiar way and produces the same - result as @link(DecomposeParts). - } - procedure DecomposePartsBinary(AHeader:TStrings; AStx,AEtx:PANSIChar); - {/pf} - - {:This part and all subparts is composed into one MIME message stored in - @link(Lines) property.} - procedure ComposeParts; - - {:By calling this method is called @link(OnWalkPart) event for each part - and their subparts. It is very good for calling some code for each part in - MIME message} - procedure WalkPart; - - {:Return @true when is possible create next subpart. (@link(maxSublevel) - is still not reached)} - function CanSubPart: boolean; - published - {:Primary Mime type of part. (i.e. 'application') Writing to this property - automaticly generate value of @link(PrimaryCode).} - property Primary: string read FPrimary write SetPrimary; - - {:String representation of used Mime encoding in part. (i.e. 'base64') - Writing to this property automaticly generate value of @link(EncodingCode).} - property Encoding: string read FEncoding write SetEncoding; - - {:String representation of used Mime charset in part. (i.e. 'iso-8859-1') - Writing to this property automaticly generate value of @link(CharsetCode). - Charset is used only for text parts.} - property Charset: string read FCharset write SetCharset; - - {:Define default charset for decoding text MIME parts without charset - specification. Default value is 'ISO-8859-1' by RCF documents. - But Microsoft Outlook use windows codings as default. This property allows - properly decode textual parts from some broken versions of Microsoft - Outlook. (this is bad software!)} - property DefaultCharset: string read FDefaultCharset write FDefaultCharset; - - {:Decoded primary type. Possible values are: MP_TEXT, MP_MULTIPART, - MP_MESSAGE and MP_BINARY. If type not recognised, result is MP_BINARY.} - property PrimaryCode: TMimePrimary read FPrimaryCode Write FPrimaryCode; - - {:Decoded encoding type. Possible values are: ME_7BIT, ME_8BIT, - ME_QUOTED_PRINTABLE and ME_BASE64. If type not recognised, result is - ME_7BIT.} - property EncodingCode: TMimeEncoding read FEncodingCode Write FEncodingCode; - - {:Decoded charset type. Possible values are defined in @link(SynaChar) unit.} - property CharsetCode: TMimeChar read FCharsetCode Write FCharsetCode; - - {:System charset type. Default value is charset used by default in your - operating system.} - property TargetCharset: TMimeChar read FTargetCharset Write FTargetCharset; - - {:If @true, then do internal charset translation of part content between @link(CharsetCode) - and @link(TargetCharset)} - property ConvertCharset: Boolean read FConvertCharset Write FConvertCharset; - - {:If @true, then allways do internal charset translation of HTML parts - by MIME even it have their own charset in META tag. Default is @false.} - property ForcedHTMLConvert: Boolean read FForcedHTMLConvert Write FForcedHTMLConvert; - - {:Secondary Mime type of part. (i.e. 'mixed')} - property Secondary: string read FSecondary Write FSecondary; - - {:Description of Mime part.} - property Description: string read FDescription Write FDescription; - - {:Value of content disposition field. (i.e. 'inline' or 'attachment')} - property Disposition: string read FDisposition Write FDisposition; - - {:Content ID.} - property ContentID: string read FContentID Write FContentID; - - {:Boundary delimiter of multipart Mime part. Used only in multipart part.} - property Boundary: string read FBoundary Write FBoundary; - - {:Filename of file in binary part.} - property FileName: string read FFileName Write FFileName; - - {:String list with lines contains mime part (It can be a full message).} - property Lines: TStringList read FLines; - - {:Encoded form of MIME part data.} - property PartBody: TStringList read FPartBody; - - {:All header lines of MIME part.} - property Headers: TStringList read FHeaders; - - {:On multipart this contains part of message between first line of message - and first boundary.} - property PrePart: TStringList read FPrePart; - - {:On multipart this contains part of message between last boundary and end - of message.} - property PostPart: TStringList read FPostPart; - - {:Stream with decoded form of budy part.} - property DecodedLines: TMemoryStream read FDecodedLines; - - {:Show nested level in subpart tree. Value 0 means root part. 1 means - subpart from this root. etc.} - property SubLevel: integer read FSubLevel write FSubLevel; - - {:Specify maximum sublevel value for decomposing.} - property MaxSubLevel: integer read FMaxSubLevel write FMaxSubLevel; - - {:When is @true, then this part maybe(!) have included some uuencoded binary - data.} - property AttachInside: boolean read FAttachInside; - - {:Here you can assign hook procedure for walking through all part and their - subparts.} - property OnWalkPart: THookWalkPart read FOnWalkPart write FOnWalkPart; - - {:Here you can specify maximum line length for encoding of MIME part. - If line is longer, then is splitted by standard of MIME. Correct MIME - mailers can de-split this line into original length.} - property MaxLineLength: integer read FMaxLineLength Write FMaxLineLength; - end; - -const - MaxMimeType = 25; - MimeType: array[0..MaxMimeType, 0..2] of string = - ( - ('AU', 'audio', 'basic'), - ('AVI', 'video', 'x-msvideo'), - ('BMP', 'image', 'BMP'), - ('DOC', 'application', 'MSWord'), - ('EPS', 'application', 'Postscript'), - ('GIF', 'image', 'GIF'), - ('JPEG', 'image', 'JPEG'), - ('JPG', 'image', 'JPEG'), - ('MID', 'audio', 'midi'), - ('MOV', 'video', 'quicktime'), - ('MPEG', 'video', 'MPEG'), - ('MPG', 'video', 'MPEG'), - ('MP2', 'audio', 'mpeg'), - ('MP3', 'audio', 'mpeg'), - ('PDF', 'application', 'PDF'), - ('PNG', 'image', 'PNG'), - ('PS', 'application', 'Postscript'), - ('QT', 'video', 'quicktime'), - ('RA', 'audio', 'x-realaudio'), - ('RTF', 'application', 'RTF'), - ('SND', 'audio', 'basic'), - ('TIF', 'image', 'TIFF'), - ('TIFF', 'image', 'TIFF'), - ('WAV', 'audio', 'x-wav'), - ('WPD', 'application', 'Wordperfect5.1'), - ('ZIP', 'application', 'ZIP') - ); - -{:Generates a unique boundary string.} -function GenerateBoundary: string; - -implementation - -{==============================================================================} - -constructor TMIMEPart.Create; -begin - inherited Create; - FOnWalkPart := nil; - FLines := TStringList.Create; - FPartBody := TStringList.Create; - FHeaders := TStringList.Create; - FPrePart := TStringList.Create; - FPostPart := TStringList.Create; - FDecodedLines := TMemoryStream.Create; - FSubParts := TList.Create; - FTargetCharset := GetCurCP; - //was 'US-ASCII' before, but RFC-ignorant Outlook sometimes using default - //system charset instead. - FDefaultCharset := GetIDFromCP(GetCurCP); - FMaxLineLength := 78; - FSubLevel := 0; - FMaxSubLevel := -1; - FAttachInside := false; - FConvertCharset := true; - FForcedHTMLConvert := false; -end; - -destructor TMIMEPart.Destroy; -begin - ClearSubParts; - FSubParts.Free; - FDecodedLines.Free; - FPartBody.Free; - FLines.Free; - FHeaders.Free; - FPrePart.Free; - FPostPart.Free; - inherited Destroy; -end; - -{==============================================================================} - -procedure TMIMEPart.Clear; -begin - FPrimary := ''; - FEncoding := ''; - FCharset := ''; - FPrimaryCode := MP_TEXT; - FEncodingCode := ME_7BIT; - FCharsetCode := ISO_8859_1; - FTargetCharset := GetCurCP; - FSecondary := ''; - FDisposition := ''; - FContentID := ''; - FDescription := ''; - FBoundary := ''; - FFileName := ''; - FAttachInside := False; - FPartBody.Clear; - FHeaders.Clear; - FPrePart.Clear; - FPostPart.Clear; - FDecodedLines.Clear; - FConvertCharset := true; - FForcedHTMLConvert := false; - ClearSubParts; -end; - -{==============================================================================} - -procedure TMIMEPart.Assign(Value: TMimePart); -begin - Primary := Value.Primary; - Encoding := Value.Encoding; - Charset := Value.Charset; - DefaultCharset := Value.DefaultCharset; - PrimaryCode := Value.PrimaryCode; - EncodingCode := Value.EncodingCode; - CharsetCode := Value.CharsetCode; - TargetCharset := Value.TargetCharset; - Secondary := Value.Secondary; - Description := Value.Description; - Disposition := Value.Disposition; - ContentID := Value.ContentID; - Boundary := Value.Boundary; - FileName := Value.FileName; - Lines.Assign(Value.Lines); - PartBody.Assign(Value.PartBody); - Headers.Assign(Value.Headers); - PrePart.Assign(Value.PrePart); - PostPart.Assign(Value.PostPart); - MaxLineLength := Value.MaxLineLength; - FAttachInside := Value.AttachInside; - FConvertCharset := Value.ConvertCharset; -end; - -{==============================================================================} - -procedure TMIMEPart.AssignSubParts(Value: TMimePart); -var - n: integer; - p: TMimePart; -begin - Assign(Value); - for n := 0 to Value.GetSubPartCount - 1 do - begin - p := AddSubPart; - p.AssignSubParts(Value.GetSubPart(n)); - end; -end; - -{==============================================================================} - -function TMIMEPart.GetSubPartCount: integer; -begin - Result := FSubParts.Count; -end; - -{==============================================================================} - -function TMIMEPart.GetSubPart(index: integer): TMimePart; -begin - Result := nil; - if Index < GetSubPartCount then - Result := TMimePart(FSubParts[Index]); -end; - -{==============================================================================} - -procedure TMIMEPart.DeleteSubPart(index: integer); -begin - if Index < GetSubPartCount then - begin - GetSubPart(Index).Free; - FSubParts.Delete(Index); - end; -end; - -{==============================================================================} - -procedure TMIMEPart.ClearSubParts; -var - n: integer; -begin - for n := 0 to GetSubPartCount - 1 do - TMimePart(FSubParts[n]).Free; - FSubParts.Clear; -end; - -{==============================================================================} - -function TMIMEPart.AddSubPart: TMimePart; -begin - Result := TMimePart.Create; - Result.DefaultCharset := FDefaultCharset; - FSubParts.Add(Result); - Result.SubLevel := FSubLevel + 1; - Result.MaxSubLevel := FMaxSubLevel; -end; - -{==============================================================================} - -procedure TMIMEPart.DecomposeParts; -var - x: integer; - s: string; - Mime: TMimePart; - - procedure SkipEmpty; - begin - while FLines.Count > x do - begin - s := TrimRight(FLines[x]); - if s <> '' then - Break; - Inc(x); - end; - end; - -begin - FBinaryDecomposer := false; - x := 0; - Clear; - //extract headers - while FLines.Count > x do - begin - s := NormalizeHeader(FLines, x); - if s = '' then - Break; - FHeaders.Add(s); - end; - DecodePartHeader; - //extract prepart - if FPrimaryCode = MP_MULTIPART then - begin - while FLines.Count > x do - begin - s := FLines[x]; - Inc(x); - if TrimRight(s) = '--' + FBoundary then - Break; - FPrePart.Add(s); - if not FAttachInside then - FAttachInside := IsUUcode(s); - end; - end; - //extract body part - if FPrimaryCode = MP_MULTIPART then - begin - repeat - if CanSubPart then - begin - Mime := AddSubPart; - while FLines.Count > x do - begin - s := FLines[x]; - Inc(x); - if Pos('--' + FBoundary, s) = 1 then - Break; - Mime.Lines.Add(s); - end; - Mime.DecomposeParts; - end - else - begin - s := FLines[x]; - Inc(x); - FPartBody.Add(s); - end; - if x >= FLines.Count then - break; - until s = '--' + FBoundary + '--'; - end; - if (FPrimaryCode = MP_MESSAGE) and CanSubPart then - begin - Mime := AddSubPart; - SkipEmpty; - while FLines.Count > x do - begin - s := TrimRight(FLines[x]); - Inc(x); - Mime.Lines.Add(s); - end; - Mime.DecomposeParts; - end - else - begin - while FLines.Count > x do - begin - s := FLines[x]; - Inc(x); - FPartBody.Add(s); - if not FAttachInside then - FAttachInside := IsUUcode(s); - end; - end; - //extract postpart - if FPrimaryCode = MP_MULTIPART then - begin - while FLines.Count > x do - begin - s := TrimRight(FLines[x]); - Inc(x); - FPostPart.Add(s); - if not FAttachInside then - FAttachInside := IsUUcode(s); - end; - end; -end; - -procedure TMIMEPart.DecomposePartsBinary(AHeader:TStrings; AStx,AEtx:PANSIChar); -var - x: integer; - s: ANSIString; - Mime: TMimePart; - BOP: PANSIChar; // Beginning of Part - EOP: PANSIChar; // End of Part - - function ___HasUUCode(ALines:TStrings): boolean; - var - x: integer; - begin - Result := FALSE; - for x:=0 to ALines.Count-1 do - if IsUUcode(ALInes[x]) then - begin - Result := TRUE; - exit; - end; - end; - -begin - FBinaryDecomposer := true; - Clear; - // Parse passed headers (THTTPSend returns HTTP headers and body separately) - x := 0; - while x<AHeader.Count do - begin - s := NormalizeHeader(AHeader,x); - if s = '' then - Break; - FHeaders.Add(s); - end; - DecodePartHeader; - // Extract prepart - if FPrimaryCode=MP_MULTIPART then - begin - CopyLinesFromStreamUntilBoundary(AStx,AEtx,FPrePart,FBoundary); - FAttachInside := FAttachInside or ___HasUUCode(FPrePart); - end; - // Extract body part - if FPrimaryCode=MP_MULTIPART then - begin - repeat - if CanSubPart then - begin - Mime := AddSubPart; - BOP := AStx; - EOP := SearchForBoundary(AStx,AEtx,FBoundary); - CopyLinesFromStreamUntilNullLine(BOP,EOP,Mime.Lines); - Mime.DecomposePartsBinary(Mime.Lines,BOP,EOP); - end - else - begin - EOP := SearchForBoundary(AStx,AEtx,FBoundary); - FPartBody.Add(BuildStringFromBuffer(AStx,EOP)); - end; - // - BOP := MatchLastBoundary(EOP,AEtx,FBoundary); - if Assigned(BOP) then - begin - AStx := BOP; - Break; - end; - until FALSE; - end; - // Extract nested MIME message - if (FPrimaryCode=MP_MESSAGE) and CanSubPart then - begin - Mime := AddSubPart; - SkipNullLines(AStx,AEtx); - CopyLinesFromStreamUntilNullLine(AStx,AEtx,Mime.Lines); - Mime.DecomposePartsBinary(Mime.Lines,AStx,AEtx); - end - // Extract body of single part - else - begin - FPartBody.Add(BuildStringFromBuffer(AStx,AEtx)); - FAttachInside := FAttachInside or ___HasUUCode(FPartBody); - end; - // Extract postpart - if FPrimaryCode=MP_MULTIPART then - begin - CopyLinesFromStreamUntilBoundary(AStx,AEtx,FPostPart,''); - FAttachInside := FAttachInside or ___HasUUCode(FPostPart); - end; -end; -{/pf} - -{==============================================================================} - -procedure TMIMEPart.ComposeParts; -var - n: integer; - mime: TMimePart; - s, t: string; - d1, d2, d3: integer; - x: integer; -begin - FLines.Clear; - //add headers - for n := 0 to FHeaders.Count -1 do - begin - s := FHeaders[n]; - repeat - if Length(s) < FMaxLineLength then - begin - t := s; - s := ''; - end - else - begin - d1 := RPosEx('; ', s, FMaxLineLength); - d2 := RPosEx(' ', s, FMaxLineLength); - d3 := RPosEx(', ', s, FMaxLineLength); - if (d1 <= 1) and (d2 <= 1) and (d3 <= 1) then - begin - x := Pos(' ', Copy(s, 2, Length(s) - 1)); - if x < 1 then - x := Length(s); - end - else - if d1 > 0 then - x := d1 - else - if d3 > 0 then - x := d3 - else - x := d2 - 1; - t := Copy(s, 1, x); - Delete(s, 1, x); - end; - Flines.Add(t); - until s = ''; - end; - - Flines.Add(''); - //add body - //if multipart - if FPrimaryCode = MP_MULTIPART then - begin - Flines.AddStrings(FPrePart); - for n := 0 to GetSubPartCount - 1 do - begin - Flines.Add('--' + FBoundary); - mime := GetSubPart(n); - mime.ComposeParts; - FLines.AddStrings(mime.Lines); - end; - Flines.Add('--' + FBoundary + '--'); - Flines.AddStrings(FPostPart); - end; - //if message - if FPrimaryCode = MP_MESSAGE then - begin - if GetSubPartCount > 0 then - begin - mime := GetSubPart(0); - mime.ComposeParts; - FLines.AddStrings(mime.Lines); - end; - end - else - //if normal part - begin - FLines.AddStrings(FPartBody); - end; -end; - -{==============================================================================} - -procedure TMIMEPart.DecodePart; -var - n: Integer; - s, t, t2: string; - b: Boolean; -begin - FDecodedLines.Clear; - {pf} - // The part decomposer passes data via TStringList which appends trailing line - // break inherently. But in a case of native 8-bit data transferred withouth - // encoding (default e.g. for HTTP protocol), the redundant line terminators - // has to be removed - if FBinaryDecomposer and (FPartBody.Count=1) then - begin - case FEncodingCode of - ME_QUOTED_PRINTABLE: - s := DecodeQuotedPrintable(FPartBody[0]); - ME_BASE64: - s := DecodeBase64(FPartBody[0]); - ME_UU, ME_XX: - begin - s := ''; - for n := 0 to FPartBody.Count - 1 do - if FEncodingCode = ME_UU then - s := s + DecodeUU(FPartBody[n]) - else - s := s + DecodeXX(FPartBody[n]); - end; - else - s := FPartBody[0]; - end; - end - else - {/pf} - case FEncodingCode of - ME_QUOTED_PRINTABLE: - s := DecodeQuotedPrintable(FPartBody.Text); - ME_BASE64: - s := DecodeBase64(FPartBody.Text); - ME_UU, ME_XX: - begin - s := ''; - for n := 0 to FPartBody.Count - 1 do - if FEncodingCode = ME_UU then - s := s + DecodeUU(FPartBody[n]) - else - s := s + DecodeXX(FPartBody[n]); - end; - else - s := FPartBody.Text; - end; - if FConvertCharset and (FPrimaryCode = MP_TEXT) then - if (not FForcedHTMLConvert) and (uppercase(FSecondary) = 'HTML') then - begin - b := false; - t2 := uppercase(s); - t := SeparateLeft(t2, '</HEAD>'); - if length(t) <> length(s) then - begin - t := SeparateRight(t, '<HEAD>'); - t := ReplaceString(t, '"', ''); - t := ReplaceString(t, ' ', ''); - b := Pos('HTTP-EQUIV=CONTENT-TYPE', t) > 0; - end; - //workaround for shitty M$ Outlook 11 which is placing this information - //outside <head> section - if not b then - begin - t := Copy(t2, 1, 2048); - t := ReplaceString(t, '"', ''); - t := ReplaceString(t, ' ', ''); - b := Pos('HTTP-EQUIV=CONTENT-TYPE', t) > 0; - end; - if not b then - s := CharsetConversion(s, FCharsetCode, FTargetCharset); - end - else - s := CharsetConversion(s, FCharsetCode, FTargetCharset); - WriteStrToStream(FDecodedLines, s); - FDecodedLines.Seek(0, soFromBeginning); -end; - -{==============================================================================} - -procedure TMIMEPart.DecodePartHeader; -var - n: integer; - s, su, fn: string; - st, st2: string; -begin - Primary := 'text'; - FSecondary := 'plain'; - FDescription := ''; - Charset := FDefaultCharset; - FFileName := ''; - //was 7bit before, but this is more compatible with RFC-ignorant outlook - Encoding := '8BIT'; - FDisposition := ''; - FContentID := ''; - fn := ''; - for n := 0 to FHeaders.Count - 1 do - if FHeaders[n] <> '' then - begin - s := FHeaders[n]; - su := UpperCase(s); - if Pos('CONTENT-TYPE:', su) = 1 then - begin - st := Trim(SeparateRight(su, ':')); - st2 := Trim(SeparateLeft(st, ';')); - Primary := Trim(SeparateLeft(st2, '/')); - FSecondary := Trim(SeparateRight(st2, '/')); - if (FSecondary = Primary) and (Pos('/', st2) < 1) then - FSecondary := ''; - case FPrimaryCode of - MP_TEXT: - begin - Charset := UpperCase(GetParameter(s, 'charset')); - FFileName := GetParameter(s, 'name'); - end; - MP_MULTIPART: - FBoundary := GetParameter(s, 'Boundary'); - MP_MESSAGE: - begin - end; - MP_BINARY: - FFileName := GetParameter(s, 'name'); - end; - end; - if Pos('CONTENT-TRANSFER-ENCODING:', su) = 1 then - Encoding := Trim(SeparateRight(su, ':')); - if Pos('CONTENT-DESCRIPTION:', su) = 1 then - FDescription := Trim(SeparateRight(s, ':')); - if Pos('CONTENT-DISPOSITION:', su) = 1 then - begin - FDisposition := SeparateRight(su, ':'); - FDisposition := Trim(SeparateLeft(FDisposition, ';')); - fn := GetParameter(s, 'FileName'); - end; - if Pos('CONTENT-ID:', su) = 1 then - FContentID := Trim(SeparateRight(s, ':')); - end; - if fn <> '' then - FFileName := fn; - FFileName := InlineDecode(FFileName, FTargetCharset); - FFileName := ExtractFileName(FFileName); -end; - -{==============================================================================} - -procedure TMIMEPart.EncodePart; -var - l: TStringList; - s, t: string; - n, x: Integer; - d1, d2: integer; -begin - if (FEncodingCode = ME_UU) or (FEncodingCode = ME_XX) then - Encoding := 'base64'; - l := TStringList.Create; - FPartBody.Clear; - FDecodedLines.Seek(0, soFromBeginning); - try - case FPrimaryCode of - MP_MULTIPART, MP_MESSAGE: - FPartBody.LoadFromStream(FDecodedLines); - MP_TEXT, MP_BINARY: - begin - s := ReadStrFromStream(FDecodedLines, FDecodedLines.Size); - if FConvertCharset and (FPrimaryCode = MP_TEXT) and (FEncodingCode <> ME_7BIT) then - s := GetBOM(FCharSetCode) + CharsetConversion(s, FTargetCharset, FCharsetCode); - if FEncodingCode = ME_BASE64 then - begin - x := 1; - while x <= length(s) do - begin - t := copy(s, x, 54); - x := x + length(t); - t := EncodeBase64(t); - FPartBody.Add(t); - end; - end - else - begin - if FPrimaryCode = MP_BINARY then - l.Add(s) - else - l.Text := s; - for n := 0 to l.Count - 1 do - begin - s := l[n]; - if FEncodingCode = ME_QUOTED_PRINTABLE then - begin - s := EncodeQuotedPrintable(s); - repeat - if Length(s) < FMaxLineLength then - begin - t := s; - s := ''; - end - else - begin - d1 := RPosEx('=', s, FMaxLineLength); - d2 := RPosEx(' ', s, FMaxLineLength); - if (d1 = 0) and (d2 = 0) then - x := FMaxLineLength - else - if d1 > d2 then - x := d1 - 1 - else - x := d2 - 1; - if x = 0 then - x := FMaxLineLength; - t := Copy(s, 1, x); - Delete(s, 1, x); - if s <> '' then - t := t + '='; - end; - FPartBody.Add(t); - until s = ''; - end - else - FPartBody.Add(s); - end; - if (FPrimaryCode = MP_BINARY) - and (FEncodingCode = ME_QUOTED_PRINTABLE) then - FPartBody[FPartBody.Count - 1] := FPartBody[FPartBody.Count - 1] + '='; - end; - end; - end; - finally - l.Free; - end; -end; - -{==============================================================================} - -procedure TMIMEPart.EncodePartHeader; -var - s: string; -begin - FHeaders.Clear; - if FSecondary = '' then - case FPrimaryCode of - MP_TEXT: - FSecondary := 'plain'; - MP_MULTIPART: - FSecondary := 'mixed'; - MP_MESSAGE: - FSecondary := 'rfc822'; - MP_BINARY: - FSecondary := 'octet-stream'; - end; - if FDescription <> '' then - FHeaders.Insert(0, 'Content-Description: ' + FDescription); - if FDisposition <> '' then - begin - s := ''; - if FFileName <> '' then - s := '; FileName=' + QuoteStr(InlineCodeEx(FileName, FTargetCharset), '"'); - FHeaders.Insert(0, 'Content-Disposition: ' + LowerCase(FDisposition) + s); - end; - if FContentID <> '' then - FHeaders.Insert(0, 'Content-ID: ' + FContentID); - - case FEncodingCode of - ME_7BIT: - s := '7bit'; - ME_8BIT: - s := '8bit'; - ME_QUOTED_PRINTABLE: - s := 'Quoted-printable'; - ME_BASE64: - s := 'Base64'; - end; - case FPrimaryCode of - MP_TEXT, - MP_BINARY: FHeaders.Insert(0, 'Content-Transfer-Encoding: ' + s); - end; - case FPrimaryCode of - MP_TEXT: - s := FPrimary + '/' + FSecondary + '; charset=' + GetIDfromCP(FCharsetCode); - MP_MULTIPART: - s := FPrimary + '/' + FSecondary + '; boundary="' + FBoundary + '"'; - MP_MESSAGE, MP_BINARY: - s := FPrimary + '/' + FSecondary; - end; - if FFileName <> '' then - s := s + '; name=' + QuoteStr(InlineCodeEx(FileName, FTargetCharset), '"'); - FHeaders.Insert(0, 'Content-type: ' + s); -end; - -{==============================================================================} - -procedure TMIMEPart.MimeTypeFromExt(Value: string); -var - s: string; - n: Integer; -begin - Primary := ''; - FSecondary := ''; - s := UpperCase(ExtractFileExt(Value)); - if s = '' then - s := UpperCase(Value); - s := SeparateRight(s, '.'); - for n := 0 to MaxMimeType do - if MimeType[n, 0] = s then - begin - Primary := MimeType[n, 1]; - FSecondary := MimeType[n, 2]; - Break; - end; - if Primary = '' then - Primary := 'application'; - if FSecondary = '' then - FSecondary := 'octet-stream'; -end; - -{==============================================================================} - -procedure TMIMEPart.WalkPart; -var - n: integer; - m: TMimepart; -begin - if assigned(OnWalkPart) then - begin - OnWalkPart(self); - for n := 0 to GetSubPartCount - 1 do - begin - m := GetSubPart(n); - m.OnWalkPart := OnWalkPart; - m.WalkPart; - end; - end; -end; - -{==============================================================================} - -procedure TMIMEPart.SetPrimary(Value: string); -var - s: string; -begin - FPrimary := Value; - s := UpperCase(Value); - FPrimaryCode := MP_BINARY; - if Pos('TEXT', s) = 1 then - FPrimaryCode := MP_TEXT; - if Pos('MULTIPART', s) = 1 then - FPrimaryCode := MP_MULTIPART; - if Pos('MESSAGE', s) = 1 then - FPrimaryCode := MP_MESSAGE; -end; - -procedure TMIMEPart.SetEncoding(Value: string); -var - s: string; -begin - FEncoding := Value; - s := UpperCase(Value); - FEncodingCode := ME_7BIT; - if Pos('8BIT', s) = 1 then - FEncodingCode := ME_8BIT; - if Pos('QUOTED-PRINTABLE', s) = 1 then - FEncodingCode := ME_QUOTED_PRINTABLE; - if Pos('BASE64', s) = 1 then - FEncodingCode := ME_BASE64; - if Pos('X-UU', s) = 1 then - FEncodingCode := ME_UU; - if Pos('X-XX', s) = 1 then - FEncodingCode := ME_XX; -end; - -procedure TMIMEPart.SetCharset(Value: string); -begin - if value <> '' then - begin - FCharset := Value; - FCharsetCode := GetCPFromID(Value); - end; -end; - -function TMIMEPart.CanSubPart: boolean; -begin - Result := True; - if FMaxSubLevel <> -1 then - Result := FMaxSubLevel > FSubLevel; -end; - -function TMIMEPart.IsUUcode(Value: string): boolean; -begin - Value := UpperCase(Value); - Result := (pos('BEGIN ', Value) = 1) and (Trim(SeparateRight(Value, ' ')) <> ''); -end; - -{==============================================================================} - -function GenerateBoundary: string; -var - x, y: Integer; -begin - y := GetTick; - x := y; - while TickDelta(y, x) = 0 do - begin - Sleep(1); - x := GetTick; - end; - Randomize; - y := Random(MaxInt); - Result := IntToHex(x, 8) + '_' + IntToHex(y, 8) + '_Synapse_boundary'; -end; - -end. diff --git a/3rd/synapse/source/nntpsend.pas b/3rd/synapse/source/nntpsend.pas deleted file mode 100644 index ec1af16ed..000000000 --- a/3rd/synapse/source/nntpsend.pas +++ /dev/null @@ -1,483 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.005.003 | -|==============================================================================| -| Content: NNTP client | -|==============================================================================| -| Copyright (c)1999-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2011. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(NNTP client) -NNTP (network news transfer protocol) - -Used RFC: RFC-977, RFC-2980 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit nntpsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil; - -const - cNNTPProtocol = '119'; - -type - - {:abstract(Implementation of Network News Transfer Protocol. - - Note: Are you missing properties for setting Username and Password? Look to - parent @link(TSynaClient) object! - - Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TNNTPSend = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FResultCode: Integer; - FResultString: string; - FData: TStringList; - FDataToSend: TStringList; - FAutoTLS: Boolean; - FFullSSL: Boolean; - FNNTPcap: TStringList; - function ReadResult: Integer; - function ReadData: boolean; - function SendData: boolean; - function Connect: Boolean; - public - constructor Create; - destructor Destroy; override; - - {:Connects to NNTP server and begin session.} - function Login: Boolean; - - {:Logout from NNTP server and terminate session.} - function Logout: Boolean; - - {:By this you can call any NNTP command.} - function DoCommand(const Command: string): boolean; - - {:by this you can call any NNTP command. This variant is used for commands - for download information from server.} - function DoCommandRead(const Command: string): boolean; - - {:by this you can call any NNTP command. This variant is used for commands - for upload information to server.} - function DoCommandWrite(const Command: string): boolean; - - {:Download full message to @link(data) property. Value can be number of - message or message-id (in brackets).} - function GetArticle(const Value: string): Boolean; - - {:Download only body of message to @link(data) property. Value can be number - of message or message-id (in brackets).} - function GetBody(const Value: string): Boolean; - - {:Download only headers of message to @link(data) property. Value can be - number of message or message-id (in brackets).} - function GetHead(const Value: string): Boolean; - - {:Get message status. Value can be number of message or message-id - (in brackets).} - function GetStat(const Value: string): Boolean; - - {:Select given group.} - function SelectGroup(const Value: string): Boolean; - - {:Tell to server 'I have mesage with given message-ID.' If server need this - message, message is uploaded to server.} - function IHave(const MessID: string): Boolean; - - {:Move message pointer to last item in group.} - function GotoLast: Boolean; - - {:Move message pointer to next item in group.} - function GotoNext: Boolean; - - {:Download to @link(data) property list of all groups on NNTP server.} - function ListGroups: Boolean; - - {:Download to @link(data) property list of all groups created after given time.} - function ListNewGroups(Since: TDateTime): Boolean; - - {:Download to @link(data) property list of message-ids in given group since - given time.} - function NewArticles(const Group: string; Since: TDateTime): Boolean; - - {:Upload new article to server. (for new messages by you)} - function PostArticle: Boolean; - - {:Tells to remote NNTP server 'I am not NNTP client, but I am another NNTP - server'.} - function SwitchToSlave: Boolean; - - {:Call NNTP XOVER command.} - function Xover(xoStart, xoEnd: string): boolean; - - {:Call STARTTLS command for upgrade connection to SSL/TLS mode.} - function StartTLS: Boolean; - - {:Try to find given capability in extension list. This list is getted after - successful login to NNTP server. If extension capability is not found, - then return is empty string.} - function FindCap(const Value: string): string; - - {:Try get list of server extensions. List is returned in @link(data) property.} - function ListExtensions: Boolean; - published - {:Result code number of last operation.} - property ResultCode: Integer read FResultCode; - - {:String description of last result code from NNTP server.} - property ResultString: string read FResultString; - - {:Readed data. (message, etc.)} - property Data: TStringList read FData; - - {:If is set to @true, then upgrade to SSL/TLS mode after login if remote - server support it.} - property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; - - {:SSL/TLS mode is used from first contact to server. Servers with full - SSL/TLS mode usualy using non-standard TCP port!} - property FullSSL: Boolean read FFullSSL Write FFullSSL; - - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - end; - -implementation - -constructor TNNTPSend.Create; -begin - inherited Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FData := TStringList.Create; - FDataToSend := TStringList.Create; - FNNTPcap := TStringList.Create; - FSock.ConvertLineEnd := True; - FTimeout := 60000; - FTargetPort := cNNTPProtocol; - FAutoTLS := False; - FFullSSL := False; -end; - -destructor TNNTPSend.Destroy; -begin - FSock.Free; - FDataToSend.Free; - FData.Free; - FNNTPcap.Free; - inherited Destroy; -end; - -function TNNTPSend.ReadResult: Integer; -var - s: string; -begin - Result := 0; - FData.Clear; - s := FSock.RecvString(FTimeout); - FResultString := Copy(s, 5, Length(s) - 4); - if FSock.LastError <> 0 then - Exit; - if Length(s) >= 3 then - Result := StrToIntDef(Copy(s, 1, 3), 0); - FResultCode := Result; -end; - -function TNNTPSend.ReadData: boolean; -var - s: string; -begin - repeat - s := FSock.RecvString(FTimeout); - if s = '.' then - break; - if (s <> '') and (s[1] = '.') then - s := Copy(s, 2, Length(s) - 1); - FData.Add(s); - until FSock.LastError <> 0; - Result := FSock.LastError = 0; -end; - -function TNNTPSend.SendData: boolean; -var - s: string; - n: integer; -begin - for n := 0 to FDataToSend.Count - 1 do - begin - s := FDataToSend[n]; - if (s <> '') and (s[1] = '.') then - s := s + '.'; - FSock.SendString(s + CRLF); - if FSock.LastError <> 0 then - break; - end; - if FDataToSend.Count = 0 then - FSock.SendString(CRLF); - if FSock.LastError = 0 then - FSock.SendString('.' + CRLF); - FDataToSend.Clear; - Result := FSock.LastError = 0; -end; - -function TNNTPSend.Connect: Boolean; -begin - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError = 0 then - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError = 0 then - if FFullSSL then - FSock.SSLDoConnect; - Result := FSock.LastError = 0; -end; - -function TNNTPSend.Login: Boolean; -begin - Result := False; - FNNTPcap.Clear; - if not Connect then - Exit; - Result := (ReadResult div 100) = 2; - if Result then - begin - ListExtensions; - FNNTPcap.Assign(Fdata); - if (not FullSSL) and FAutoTLS and (FindCap('STARTTLS') <> '') then - Result := StartTLS; - end; - if (FUsername <> '') and Result then - begin - FSock.SendString('AUTHINFO USER ' + FUsername + CRLF); - if (ReadResult div 100) = 3 then - begin - FSock.SendString('AUTHINFO PASS ' + FPassword + CRLF); - Result := (ReadResult div 100) = 2; - end; - end; -end; - -function TNNTPSend.Logout: Boolean; -begin - FSock.SendString('QUIT' + CRLF); - Result := (ReadResult div 100) = 2; - FSock.CloseSocket; -end; - -function TNNTPSend.DoCommand(const Command: string): Boolean; -begin - FSock.SendString(Command + CRLF); - Result := (ReadResult div 100) = 2; - Result := Result and (FSock.LastError = 0); -end; - -function TNNTPSend.DoCommandRead(const Command: string): Boolean; -begin - Result := DoCommand(Command); - if Result then - begin - Result := ReadData; - Result := Result and (FSock.LastError = 0); - end; -end; - -function TNNTPSend.DoCommandWrite(const Command: string): Boolean; -var - x: integer; -begin - FDataToSend.Assign(FData); - FSock.SendString(Command + CRLF); - x := (ReadResult div 100); - if x = 3 then - begin - SendData; - x := (ReadResult div 100); - end; - Result := x = 2; - Result := Result and (FSock.LastError = 0); -end; - -function TNNTPSend.GetArticle(const Value: string): Boolean; -var - s: string; -begin - s := 'ARTICLE'; - if Value <> '' then - s := s + ' ' + Value; - Result := DoCommandRead(s); -end; - -function TNNTPSend.GetBody(const Value: string): Boolean; -var - s: string; -begin - s := 'BODY'; - if Value <> '' then - s := s + ' ' + Value; - Result := DoCommandRead(s); -end; - -function TNNTPSend.GetHead(const Value: string): Boolean; -var - s: string; -begin - s := 'HEAD'; - if Value <> '' then - s := s + ' ' + Value; - Result := DoCommandRead(s); -end; - -function TNNTPSend.GetStat(const Value: string): Boolean; -var - s: string; -begin - s := 'STAT'; - if Value <> '' then - s := s + ' ' + Value; - Result := DoCommand(s); -end; - -function TNNTPSend.SelectGroup(const Value: string): Boolean; -begin - Result := DoCommand('GROUP ' + Value); -end; - -function TNNTPSend.IHave(const MessID: string): Boolean; -begin - Result := DoCommandWrite('IHAVE ' + MessID); -end; - -function TNNTPSend.GotoLast: Boolean; -begin - Result := DoCommand('LAST'); -end; - -function TNNTPSend.GotoNext: Boolean; -begin - Result := DoCommand('NEXT'); -end; - -function TNNTPSend.ListGroups: Boolean; -begin - Result := DoCommandRead('LIST'); -end; - -function TNNTPSend.ListNewGroups(Since: TDateTime): Boolean; -begin - Result := DoCommandRead('NEWGROUPS ' + SimpleDateTime(Since) + ' GMT'); -end; - -function TNNTPSend.NewArticles(const Group: string; Since: TDateTime): Boolean; -begin - Result := DoCommandRead('NEWNEWS ' + Group + ' ' + SimpleDateTime(Since) + ' GMT'); -end; - -function TNNTPSend.PostArticle: Boolean; -begin - Result := DoCommandWrite('POST'); -end; - -function TNNTPSend.SwitchToSlave: Boolean; -begin - Result := DoCommand('SLAVE'); -end; - -function TNNTPSend.Xover(xoStart, xoEnd: string): Boolean; -var - s: string; -begin - s := 'XOVER ' + xoStart; - if xoEnd <> xoStart then - s := s + '-' + xoEnd; - Result := DoCommandRead(s); -end; - -function TNNTPSend.StartTLS: Boolean; -begin - Result := False; - if FindCap('STARTTLS') <> '' then - begin - if DoCommand('STARTTLS') then - begin - Fsock.SSLDoConnect; - Result := FSock.LastError = 0; - end; - end; -end; - -function TNNTPSend.ListExtensions: Boolean; -begin - Result := DoCommandRead('LIST EXTENSIONS'); -end; - -function TNNTPSend.FindCap(const Value: string): string; -var - n: Integer; - s: string; -begin - s := UpperCase(Value); - Result := ''; - for n := 0 to FNNTPcap.Count - 1 do - if Pos(s, UpperCase(FNNTPcap[n])) = 1 then - begin - Result := FNNTPcap[n]; - Break; - end; -end; - -{==============================================================================} - -end. diff --git a/3rd/synapse/source/pingsend.pas b/3rd/synapse/source/pingsend.pas deleted file mode 100644 index 1a4e331f8..000000000 --- a/3rd/synapse/source/pingsend.pas +++ /dev/null @@ -1,720 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 004.000.002 | -|==============================================================================| -| Content: PING sender | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(ICMP PING implementation.) -Allows create PING and TRACEROUTE. Or you can diagnose your network. - -This unit using IpHlpApi (on WinXP or higher) if available. Otherwise it trying - to use RAW sockets. - -Warning: For use of RAW sockets you must have some special rights on some - systems. So, it working allways when you have administator/root rights. - Otherwise you can have problems! - -Note: This unit is NOT portable to .NET! - Use native .NET classes for Ping instead. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} - -{$IFDEF CIL} - Sorry, this unit is not for .NET! -{$ENDIF} -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit pingsend; - -interface - -uses - SysUtils, - synsock, blcksock, synautil, synafpc, synaip -{$IFDEF MSWINDOWS} - , windows -{$ENDIF} - ; - -const - ICMP_ECHO = 8; - ICMP_ECHOREPLY = 0; - ICMP_UNREACH = 3; - ICMP_TIME_EXCEEDED = 11; -//rfc-2292 - ICMP6_ECHO = 128; - ICMP6_ECHOREPLY = 129; - ICMP6_UNREACH = 1; - ICMP6_TIME_EXCEEDED = 3; - -type - {:List of possible ICMP reply packet types.} - TICMPError = ( - IE_NoError, - IE_Other, - IE_TTLExceed, - IE_UnreachOther, - IE_UnreachRoute, - IE_UnreachAdmin, - IE_UnreachAddr, - IE_UnreachPort - ); - - {:@abstract(Implementation of ICMP PING and ICMPv6 PING.)} - TPINGSend = class(TSynaClient) - private - FSock: TICMPBlockSocket; - FBuffer: Ansistring; - FSeq: Integer; - FId: Integer; - FPacketSize: Integer; - FPingTime: Integer; - FIcmpEcho: Byte; - FIcmpEchoReply: Byte; - FIcmpUnreach: Byte; - FReplyFrom: string; - FReplyType: byte; - FReplyCode: byte; - FReplyError: TICMPError; - FReplyErrorDesc: string; - FTTL: Byte; - Fsin: TVarSin; - function Checksum(Value: AnsiString): Word; - function Checksum6(Value: AnsiString): Word; - function ReadPacket: Boolean; - procedure TranslateError; - procedure TranslateErrorIpHlp(value: integer); - function InternalPing(const Host: string): Boolean; - function InternalPingIpHlp(const Host: string): Boolean; - function IsHostIP6(const Host: string): Boolean; - procedure GenErrorDesc; - public - {:Send ICMP ping to host and count @link(pingtime). If ping OK, result is - @true.} - function Ping(const Host: string): Boolean; - constructor Create; - destructor Destroy; override; - published - {:Size of PING packet. Default size is 32 bytes.} - property PacketSize: Integer read FPacketSize Write FPacketSize; - - {:Time between request and reply.} - property PingTime: Integer read FPingTime; - - {:From this address is sended reply for your PING request. It maybe not your - requested destination, when some error occured!} - property ReplyFrom: string read FReplyFrom; - - {:ICMP type of PING reply. Each protocol using another values! For IPv4 and - IPv6 are used different values!} - property ReplyType: byte read FReplyType; - - {:ICMP code of PING reply. Each protocol using another values! For IPv4 and - IPv6 are used different values! For protocol independent value look to - @link(ReplyError)} - property ReplyCode: byte read FReplyCode; - - {:Return type of returned ICMP message. This value is independent on used - protocol!} - property ReplyError: TICMPError read FReplyError; - - {:Return human readable description of returned packet type.} - property ReplyErrorDesc: string read FReplyErrorDesc; - - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TICMPBlockSocket read FSock; - - {:TTL value for ICMP query} - property TTL: byte read FTTL write FTTL; - end; - -{:A very useful function and example of its use would be found in the TPINGSend - object. Use it to ping to any host. If successful, returns the ping time in - milliseconds. Returns -1 if an error occurred.} -function PingHost(const Host: string): Integer; - -{:A very useful function and example of its use would be found in the TPINGSend - object. Use it to TraceRoute to any host.} -function TraceRouteHost(const Host: string): string; - -implementation - -type - {:Record for ICMP ECHO packet header.} - TIcmpEchoHeader = packed record - i_type: Byte; - i_code: Byte; - i_checkSum: Word; - i_Id: Word; - i_seq: Word; - TimeStamp: integer; - end; - - {:record used internally by TPingSend for compute checksum of ICMPv6 packet - pseudoheader.} - TICMP6Packet = packed record - in_source: TInAddr6; - in_dest: TInAddr6; - Length: integer; - free0: Byte; - free1: Byte; - free2: Byte; - proto: Byte; - end; - -{$IFDEF MSWINDOWS} -const - DLLIcmpName = 'iphlpapi.dll'; -type - TIP_OPTION_INFORMATION = record - TTL: Byte; - TOS: Byte; - Flags: Byte; - OptionsSize: Byte; - OptionsData: PAnsiChar; - end; - PIP_OPTION_INFORMATION = ^TIP_OPTION_INFORMATION; - - TICMP_ECHO_REPLY = record - Address: TInAddr; - Status: integer; - RoundTripTime: integer; - DataSize: Word; - Reserved: Word; - Data: pointer; - Options: TIP_OPTION_INFORMATION; - end; - PICMP_ECHO_REPLY = ^TICMP_ECHO_REPLY; - - TICMPV6_ECHO_REPLY = record - Address: TSockAddrIn6; - Status: integer; - RoundTripTime: integer; - end; - PICMPV6_ECHO_REPLY = ^TICMPV6_ECHO_REPLY; - - TIcmpCreateFile = function: integer; stdcall; - TIcmpCloseHandle = function(handle: integer): boolean; stdcall; - TIcmpSendEcho2 = function(handle: integer; Event: pointer; ApcRoutine: pointer; - ApcContext: pointer; DestinationAddress: TInAddr; RequestData: pointer; - RequestSize: integer; RequestOptions: PIP_OPTION_INFORMATION; - ReplyBuffer: pointer; ReplySize: integer; Timeout: Integer): integer; stdcall; - TIcmp6CreateFile = function: integer; stdcall; - TIcmp6SendEcho2 = function(handle: integer; Event: pointer; ApcRoutine: pointer; - ApcContext: pointer; SourceAddress: PSockAddrIn6; DestinationAddress: PSockAddrIn6; - RequestData: pointer; RequestSize: integer; RequestOptions: PIP_OPTION_INFORMATION; - ReplyBuffer: pointer; ReplySize: integer; Timeout: Integer): integer; stdcall; - -var - IcmpDllHandle: TLibHandle = 0; - IcmpHelper4: boolean = false; - IcmpHelper6: boolean = false; - IcmpCreateFile: TIcmpCreateFile = nil; - IcmpCloseHandle: TIcmpCloseHandle = nil; - IcmpSendEcho2: TIcmpSendEcho2 = nil; - Icmp6CreateFile: TIcmp6CreateFile = nil; - Icmp6SendEcho2: TIcmp6SendEcho2 = nil; -{$ENDIF} -{==============================================================================} - -constructor TPINGSend.Create; -begin - inherited Create; - FSock := TICMPBlockSocket.Create; - FSock.Owner := self; - FTimeout := 5000; - FPacketSize := 32; - FSeq := 0; - Randomize; - FTTL := 128; -end; - -destructor TPINGSend.Destroy; -begin - FSock.Free; - inherited Destroy; -end; - -function TPINGSend.ReadPacket: Boolean; -begin - FBuffer := FSock.RecvPacket(Ftimeout); - Result := FSock.LastError = 0; -end; - -procedure TPINGSend.GenErrorDesc; -begin - case FReplyError of - IE_NoError: - FReplyErrorDesc := ''; - IE_Other: - FReplyErrorDesc := 'Unknown error'; - IE_TTLExceed: - FReplyErrorDesc := 'TTL Exceeded'; - IE_UnreachOther: - FReplyErrorDesc := 'Unknown unreachable'; - IE_UnreachRoute: - FReplyErrorDesc := 'No route to destination'; - IE_UnreachAdmin: - FReplyErrorDesc := 'Administratively prohibited'; - IE_UnreachAddr: - FReplyErrorDesc := 'Address unreachable'; - IE_UnreachPort: - FReplyErrorDesc := 'Port unreachable'; - end; -end; - -function TPINGSend.IsHostIP6(const Host: string): Boolean; -var - f: integer; -begin - f := AF_UNSPEC; - if IsIp(Host) then - f := AF_INET - else - if IsIp6(Host) then - f := AF_INET6; - synsock.SetVarSin(Fsin, host, '0', f, - IPPROTO_UDP, SOCK_DGRAM, Fsock.PreferIP4); - result := Fsin.sin_family = AF_INET6; -end; - -function TPINGSend.Ping(const Host: string): Boolean; -var - b: boolean; -begin - FPingTime := -1; - FReplyFrom := ''; - FReplyType := 0; - FReplyCode := 0; - FReplyError := IE_Other; - GenErrorDesc; - FBuffer := StringOfChar(#55, SizeOf(TICMPEchoHeader) + FPacketSize); -{$IFDEF MSWINDOWS} - b := IsHostIP6(host); - if not(b) and IcmpHelper4 then - result := InternalPingIpHlp(host) - else - if b and IcmpHelper6 then - result := InternalPingIpHlp(host) - else - result := InternalPing(host); -{$ELSE} - result := InternalPing(host); -{$ENDIF} -end; - -function TPINGSend.InternalPing(const Host: string): Boolean; -var - IPHeadPtr: ^TIPHeader; - IpHdrLen: Integer; - IcmpEchoHeaderPtr: ^TICMPEchoHeader; - t: Boolean; - x: cardinal; - IcmpReqHead: string; -begin - Result := False; - FSock.TTL := FTTL; - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(Host, '0'); - if FSock.LastError <> 0 then - Exit; - FSock.SizeRecvBuffer := 60 * 1024; - if FSock.IP6used then - begin - FIcmpEcho := ICMP6_ECHO; - FIcmpEchoReply := ICMP6_ECHOREPLY; - FIcmpUnreach := ICMP6_UNREACH; - end - else - begin - FIcmpEcho := ICMP_ECHO; - FIcmpEchoReply := ICMP_ECHOREPLY; - FIcmpUnreach := ICMP_UNREACH; - end; - IcmpEchoHeaderPtr := Pointer(FBuffer); - with IcmpEchoHeaderPtr^ do - begin - i_type := FIcmpEcho; - i_code := 0; - i_CheckSum := 0; - FId := System.Random(32767); - i_Id := FId; - TimeStamp := GetTick; - Inc(FSeq); - i_Seq := FSeq; - if fSock.IP6used then - i_CheckSum := CheckSum6(FBuffer) - else - i_CheckSum := CheckSum(FBuffer); - end; - FSock.SendString(FBuffer); - // remember first 8 bytes of ICMP packet - IcmpReqHead := Copy(FBuffer, 1, 8); - x := GetTick; - repeat - t := ReadPacket; - if not t then - break; - if fSock.IP6used then - begin -{$IFNDEF MSWINDOWS} - IcmpEchoHeaderPtr := Pointer(FBuffer); -{$ELSE} -//WinXP SP1 with networking update doing this think by another way ;-O -// FBuffer := StringOfChar(#0, 4) + FBuffer; - IcmpEchoHeaderPtr := Pointer(FBuffer); -// IcmpEchoHeaderPtr^.i_type := FIcmpEchoReply; -{$ENDIF} - end - else - begin - IPHeadPtr := Pointer(FBuffer); - IpHdrLen := (IPHeadPtr^.VerLen and $0F) * 4; - IcmpEchoHeaderPtr := @FBuffer[IpHdrLen + 1]; - end; - //check for timeout - if TickDelta(x, GetTick) > FTimeout then - begin - t := false; - Break; - end; - //it discard sometimes possible 'echoes' of previosly sended packet - //or other unwanted ICMP packets... - until (IcmpEchoHeaderPtr^.i_type <> FIcmpEcho) - and ((IcmpEchoHeaderPtr^.i_id = FId) - or (Pos(IcmpReqHead, FBuffer) > 0)); - if t then - begin - FPingTime := TickDelta(x, GetTick); - FReplyFrom := FSock.GetRemoteSinIP; - FReplyType := IcmpEchoHeaderPtr^.i_type; - FReplyCode := IcmpEchoHeaderPtr^.i_code; - TranslateError; - Result := True; - end; -end; - -function TPINGSend.Checksum(Value: AnsiString): Word; -var - CkSum: integer; - Num, Remain: Integer; - n, i: Integer; -begin - Num := Length(Value) div 2; - Remain := Length(Value) mod 2; - CkSum := 0; - i := 1; - for n := 0 to Num - 1 do - begin - CkSum := CkSum + Synsock.HtoNs(DecodeInt(Value, i)); - inc(i, 2); - end; - if Remain <> 0 then - CkSum := CkSum + Ord(Value[Length(Value)]); - CkSum := (CkSum shr 16) + (CkSum and $FFFF); - CkSum := CkSum + (CkSum shr 16); - Result := Word(not CkSum); -end; - -function TPINGSend.Checksum6(Value: AnsiString): Word; -const - IOC_OUT = $40000000; - IOC_IN = $80000000; - IOC_INOUT = (IOC_IN or IOC_OUT); - IOC_WS2 = $08000000; - SIO_ROUTING_INTERFACE_QUERY = 20 or IOC_WS2 or IOC_INOUT; -var - ICMP6Ptr: ^TICMP6Packet; - s: AnsiString; - b: integer; - ip6: TSockAddrIn6; - x: integer; -begin - Result := 0; -{$IFDEF MSWINDOWS} - s := StringOfChar(#0, SizeOf(TICMP6Packet)) + Value; - ICMP6Ptr := Pointer(s); - x := synsock.WSAIoctl(FSock.Socket, SIO_ROUTING_INTERFACE_QUERY, - @FSock.RemoteSin, SizeOf(FSock.RemoteSin), - @ip6, SizeOf(ip6), @b, nil, nil); - if x <> -1 then - ICMP6Ptr^.in_dest := ip6.sin6_addr - else - ICMP6Ptr^.in_dest := FSock.LocalSin.sin6_addr; - ICMP6Ptr^.in_source := FSock.RemoteSin.sin6_addr; - ICMP6Ptr^.Length := synsock.htonl(Length(Value)); - ICMP6Ptr^.proto := IPPROTO_ICMPV6; - Result := Checksum(s); -{$ENDIF} -end; - -procedure TPINGSend.TranslateError; -begin - if fSock.IP6used then - begin - case FReplyType of - ICMP6_ECHOREPLY: - FReplyError := IE_NoError; - ICMP6_TIME_EXCEEDED: - FReplyError := IE_TTLExceed; - ICMP6_UNREACH: - case FReplyCode of - 0: - FReplyError := IE_UnreachRoute; - 3: - FReplyError := IE_UnreachAddr; - 4: - FReplyError := IE_UnreachPort; - 1: - FReplyError := IE_UnreachAdmin; - else - FReplyError := IE_UnreachOther; - end; - else - FReplyError := IE_Other; - end; - end - else - begin - case FReplyType of - ICMP_ECHOREPLY: - FReplyError := IE_NoError; - ICMP_TIME_EXCEEDED: - FReplyError := IE_TTLExceed; - ICMP_UNREACH: - case FReplyCode of - 0: - FReplyError := IE_UnreachRoute; - 1: - FReplyError := IE_UnreachAddr; - 3: - FReplyError := IE_UnreachPort; - 13: - FReplyError := IE_UnreachAdmin; - else - FReplyError := IE_UnreachOther; - end; - else - FReplyError := IE_Other; - end; - end; - GenErrorDesc; -end; - -procedure TPINGSend.TranslateErrorIpHlp(value: integer); -begin - case value of - 11000, 0: - FReplyError := IE_NoError; - 11013: - FReplyError := IE_TTLExceed; - 11002: - FReplyError := IE_UnreachRoute; - 11003: - FReplyError := IE_UnreachAddr; - 11005: - FReplyError := IE_UnreachPort; - 11004: - FReplyError := IE_UnreachAdmin; - else - FReplyError := IE_Other; - end; - GenErrorDesc; -end; - -function TPINGSend.InternalPingIpHlp(const Host: string): Boolean; -{$IFDEF MSWINDOWS} -var - PingIp6: boolean; - PingHandle: integer; - r: integer; - ipo: TIP_OPTION_INFORMATION; - RBuff: Ansistring; - ip4reply: PICMP_ECHO_REPLY; - ip6reply: PICMPV6_ECHO_REPLY; - ip6: TSockAddrIn6; -begin - Result := False; - PingIp6 := Fsin.sin_family = AF_INET6; - if pingIp6 then - PingHandle := Icmp6CreateFile - else - PingHandle := IcmpCreateFile; - if PingHandle <> -1 then - begin - try - ipo.TTL := FTTL; - ipo.TOS := 0; - ipo.Flags := 0; - ipo.OptionsSize := 0; - ipo.OptionsData := nil; - setlength(RBuff, 4096); - if pingIp6 then - begin - FillChar(ip6, sizeof(ip6), 0); - r := Icmp6SendEcho2(PingHandle, nil, nil, nil, @ip6, @Fsin, - PAnsichar(FBuffer), length(FBuffer), @ipo, pAnsichar(RBuff), length(RBuff), FTimeout); - if r > 0 then - begin - RBuff := #0 + #0 + RBuff; - ip6reply := PICMPV6_ECHO_REPLY(pointer(RBuff)); - FPingTime := ip6reply^.RoundTripTime; - ip6reply^.Address.sin6_family := AF_INET6; - FReplyFrom := GetSinIp(TVarSin(ip6reply^.Address)); - TranslateErrorIpHlp(ip6reply^.Status); - Result := True; - end; - end - else - begin - r := IcmpSendEcho2(PingHandle, nil, nil, nil, Fsin.sin_addr, - PAnsichar(FBuffer), length(FBuffer), @ipo, pAnsichar(RBuff), length(RBuff), FTimeout); - if r > 0 then - begin - ip4reply := PICMP_ECHO_REPLY(pointer(RBuff)); - FPingTime := ip4reply^.RoundTripTime; - FReplyFrom := IpToStr(swapbytes(ip4reply^.Address.S_addr)); - TranslateErrorIpHlp(ip4reply^.Status); - Result := True; - end; - end - finally - IcmpCloseHandle(PingHandle); - end; - end; -end; -{$ELSE} -begin - result := false; -end; -{$ENDIF} - -{==============================================================================} - -function PingHost(const Host: string): Integer; -begin - with TPINGSend.Create do - try - Result := -1; - if Ping(Host) then - if ReplyError = IE_NoError then - Result := PingTime; - finally - Free; - end; -end; - -function TraceRouteHost(const Host: string): string; -var - Ping: TPingSend; - ttl : byte; -begin - Result := ''; - Ping := TPINGSend.Create; - try - ttl := 1; - repeat - ping.TTL := ttl; - inc(ttl); - if ttl > 30 then - Break; - if not ping.Ping(Host) then - begin - Result := Result + cAnyHost+ ' Timeout' + CRLF; - continue; - end; - if (ping.ReplyError <> IE_NoError) - and (ping.ReplyError <> IE_TTLExceed) then - begin - Result := Result + Ping.ReplyFrom + ' ' + Ping.ReplyErrorDesc + CRLF; - break; - end; - Result := Result + Ping.ReplyFrom + ' ' + IntToStr(Ping.PingTime) + CRLF; - until ping.ReplyError = IE_NoError; - finally - Ping.Free; - end; -end; - -{$IFDEF MSWINDOWS} -initialization -begin - IcmpHelper4 := false; - IcmpHelper6 := false; - IcmpDllHandle := LoadLibrary(DLLIcmpName); - if IcmpDllHandle <> 0 then - begin - IcmpCreateFile := GetProcAddress(IcmpDLLHandle, 'IcmpCreateFile'); - IcmpCloseHandle := GetProcAddress(IcmpDLLHandle, 'IcmpCloseHandle'); - IcmpSendEcho2 := GetProcAddress(IcmpDLLHandle, 'IcmpSendEcho2'); - Icmp6CreateFile := GetProcAddress(IcmpDLLHandle, 'Icmp6CreateFile'); - Icmp6SendEcho2 := GetProcAddress(IcmpDLLHandle, 'Icmp6SendEcho2'); - IcmpHelper4 := assigned(IcmpCreateFile) - and assigned(IcmpCloseHandle) - and assigned(IcmpSendEcho2); - IcmpHelper6 := assigned(Icmp6CreateFile) - and assigned(Icmp6SendEcho2); - end; -end; - -finalization -begin - FreeLibrary(IcmpDllHandle); -end; -{$ENDIF} - -end. diff --git a/3rd/synapse/source/pop3send.pas b/3rd/synapse/source/pop3send.pas deleted file mode 100644 index 05c5ac0dc..000000000 --- a/3rd/synapse/source/pop3send.pas +++ /dev/null @@ -1,483 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.006.002 | -|==============================================================================| -| Content: POP3 client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(POP3 protocol client) - -Used RFC: RFC-1734, RFC-1939, RFC-2195, RFC-2449, RFC-2595 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$M+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit pop3send; - -interface - -uses - SysUtils, Classes, - blcksock, synautil, synacode; - -const - cPop3Protocol = '110'; - -type - - {:The three types of possible authorization methods for "logging in" to a POP3 - server.} - TPOP3AuthType = (POP3AuthAll, POP3AuthLogin, POP3AuthAPOP); - - {:@abstract(Implementation of POP3 client protocol.) - - Note: Are you missing properties for setting Username and Password? Look to - parent @link(TSynaClient) object! - - Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TPOP3Send = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FResultCode: Integer; - FResultString: string; - FFullResult: TStringList; - FStatCount: Integer; - FStatSize: Integer; - FListSize: Integer; - FTimeStamp: string; - FAuthType: TPOP3AuthType; - FPOP3cap: TStringList; - FAutoTLS: Boolean; - FFullSSL: Boolean; - function ReadResult(Full: Boolean): Integer; - function Connect: Boolean; - function AuthLogin: Boolean; - function AuthApop: Boolean; - public - constructor Create; - destructor Destroy; override; - - {:You can call any custom by this method. Call Command without trailing CRLF. - If MultiLine parameter is @true, multilined response are expected. - Result is @true on sucess.} - function CustomCommand(const Command: string; MultiLine: Boolean): boolean; - - {:Call CAPA command for get POP3 server capabilites. - note: not all servers support this command!} - function Capability: Boolean; - - {:Connect to remote POP3 host. If all OK, result is @true.} - function Login: Boolean; - - {:Disconnects from POP3 server.} - function Logout: Boolean; - - {:Send RSET command. If all OK, result is @true.} - function Reset: Boolean; - - {:Send NOOP command. If all OK, result is @true.} - function NoOp: Boolean; - - {:Send STAT command and fill @link(StatCount) and @link(StatSize) property. - If all OK, result is @true.} - function Stat: Boolean; - - {:Send LIST command. If Value is 0, LIST is for all messages. After - successful operation is listing in FullResult. If all OK, result is @True.} - function List(Value: Integer): Boolean; - - {:Send RETR command. After successful operation dowloaded message in - @link(FullResult). If all OK, result is @true.} - function Retr(Value: Integer): Boolean; - - {:Send RETR command. After successful operation dowloaded message in - @link(Stream). If all OK, result is @true.} - function RetrStream(Value: Integer; Stream: TStream): Boolean; - - {:Send DELE command for delete specified message. If all OK, result is @true.} - function Dele(Value: Integer): Boolean; - - {:Send TOP command. After successful operation dowloaded headers of message - and maxlines count of message in @link(FullResult). If all OK, result is - @true.} - function Top(Value, Maxlines: Integer): Boolean; - - {:Send UIDL command. If Value is 0, UIDL is for all messages. After - successful operation is listing in FullResult. If all OK, result is @True.} - function Uidl(Value: Integer): Boolean; - - {:Call STLS command for upgrade connection to SSL/TLS mode.} - function StartTLS: Boolean; - - {:Try to find given capabily in capabilty string returned from POP3 server - by CAPA command.} - function FindCap(const Value: string): string; - published - {:Result code of last POP3 operation. 0 - error, 1 - OK.} - property ResultCode: Integer read FResultCode; - - {:Result string of last POP3 operation.} - property ResultString: string read FResultString; - - {:Stringlist with full lines returned as result of POP3 operation. I.e. if - operation is LIST, this property is filled by list of messages. If - operation is RETR, this property have downloaded message.} - property FullResult: TStringList read FFullResult; - - {:After STAT command is there count of messages in inbox.} - property StatCount: Integer read FStatCount; - - {:After STAT command is there size of all messages in inbox.} - property StatSize: Integer read FStatSize; - - {:After LIST 0 command size of all messages on server, After LIST x size of message x on server} - property ListSize: Integer read FListSize; - - {:If server support this, after comnnect is in this property timestamp of - remote server.} - property TimeStamp: string read FTimeStamp; - - {:Type of authorisation for login to POP3 server. Dafault is autodetect one - of possible authorisation. Autodetect do this: - - If remote POP3 server support APOP, try login by APOP method. If APOP is - not supported, or if APOP login failed, try classic USER+PASS login method.} - property AuthType: TPOP3AuthType read FAuthType Write FAuthType; - - {:If is set to @true, then upgrade to SSL/TLS mode if remote server support it.} - property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; - - {:SSL/TLS mode is used from first contact to server. Servers with full - SSL/TLS mode usualy using non-standard TCP port!} - property FullSSL: Boolean read FFullSSL Write FFullSSL; - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - end; - -implementation - -constructor TPOP3Send.Create; -begin - inherited Create; - FFullResult := TStringList.Create; - FPOP3cap := TStringList.Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.ConvertLineEnd := true; - FTimeout := 60000; - FTargetPort := cPop3Protocol; - FStatCount := 0; - FStatSize := 0; - FListSize := 0; - FAuthType := POP3AuthAll; - FAutoTLS := False; - FFullSSL := False; -end; - -destructor TPOP3Send.Destroy; -begin - FSock.Free; - FPOP3cap.Free; - FullResult.Free; - inherited Destroy; -end; - -function TPOP3Send.ReadResult(Full: Boolean): Integer; -var - s: AnsiString; -begin - Result := 0; - FFullResult.Clear; - s := FSock.RecvString(FTimeout); - if Pos('+OK', s) = 1 then - Result := 1; - FResultString := s; - if Full and (Result = 1) then - repeat - s := FSock.RecvString(FTimeout); - if s = '.' then - Break; - if s <> '' then - if s[1] = '.' then - Delete(s, 1, 1); - FFullResult.Add(s); - until FSock.LastError <> 0; - if not Full and (Result = 1) then - FFullResult.Add(SeparateRight(FResultString, ' ')); - if FSock.LastError <> 0 then - Result := 0; - FResultCode := Result; -end; - -function TPOP3Send.CustomCommand(const Command: string; MultiLine: Boolean): boolean; -begin - FSock.SendString(Command + CRLF); - Result := ReadResult(MultiLine) <> 0; -end; - -function TPOP3Send.AuthLogin: Boolean; -begin - Result := False; - if not CustomCommand('USER ' + FUserName, False) then - exit; - Result := CustomCommand('PASS ' + FPassword, False) -end; - -function TPOP3Send.AuthAPOP: Boolean; -var - s: string; -begin - s := StrToHex(MD5(FTimeStamp + FPassWord)); - Result := CustomCommand('APOP ' + FUserName + ' ' + s, False); -end; - -function TPOP3Send.Connect: Boolean; -begin - // Do not call this function! It is calling by LOGIN method! - FStatCount := 0; - FStatSize := 0; - FSock.CloseSocket; - FSock.LineBuffer := ''; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError = 0 then - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError = 0 then - if FFullSSL then - FSock.SSLDoConnect; - Result := FSock.LastError = 0; -end; - -function TPOP3Send.Capability: Boolean; -begin - FPOP3cap.Clear; - Result := CustomCommand('CAPA', True); - if Result then - FPOP3cap.AddStrings(FFullResult); -end; - -function TPOP3Send.Login: Boolean; -var - s, s1: string; -begin - Result := False; - FTimeStamp := ''; - if not Connect then - Exit; - if ReadResult(False) <> 1 then - Exit; - s := SeparateRight(FResultString, '<'); - if s <> FResultString then - begin - s1 := Trim(SeparateLeft(s, '>')); - if s1 <> s then - FTimeStamp := '<' + s1 + '>'; - end; - Result := False; - if Capability then - if FAutoTLS and (Findcap('STLS') <> '') then - if StartTLS then - Capability - else - begin - Result := False; - Exit; - end; - if (FTimeStamp <> '') and not (FAuthType = POP3AuthLogin) then - begin - Result := AuthApop; - if not Result then - begin - if not Connect then - Exit; - if ReadResult(False) <> 1 then - Exit; - end; - end; - if not Result and not (FAuthType = POP3AuthAPOP) then - Result := AuthLogin; -end; - -function TPOP3Send.Logout: Boolean; -begin - Result := CustomCommand('QUIT', False); - FSock.CloseSocket; -end; - -function TPOP3Send.Reset: Boolean; -begin - Result := CustomCommand('RSET', False); -end; - -function TPOP3Send.NoOp: Boolean; -begin - Result := CustomCommand('NOOP', False); -end; - -function TPOP3Send.Stat: Boolean; -var - s: string; -begin - Result := CustomCommand('STAT', False); - if Result then - begin - s := SeparateRight(ResultString, '+OK '); - FStatCount := StrToIntDef(Trim(SeparateLeft(s, ' ')), 0); - FStatSize := StrToIntDef(Trim(SeparateRight(s, ' ')), 0); - end; -end; - -function TPOP3Send.List(Value: Integer): Boolean; -var - s: string; - n: integer; -begin - if Value = 0 then - s := 'LIST' - else - s := 'LIST ' + IntToStr(Value); - Result := CustomCommand(s, Value = 0); - FListSize := 0; - if Result then - if Value <> 0 then - begin - s := SeparateRight(ResultString, '+OK '); - FListSize := StrToIntDef(SeparateLeft(SeparateRight(s, ' '), ' '), 0); - end - else - for n := 0 to FFullResult.Count - 1 do - FListSize := FListSize + StrToIntDef(SeparateLeft(SeparateRight(s, ' '), ' '), 0); -end; - -function TPOP3Send.Retr(Value: Integer): Boolean; -begin - Result := CustomCommand('RETR ' + IntToStr(Value), True); -end; - -//based on code by Miha Vrhovnik -function TPOP3Send.RetrStream(Value: Integer; Stream: TStream): Boolean; -var - s: string; -begin - Result := False; - FFullResult.Clear; - Stream.Size := 0; - FSock.SendString('RETR ' + IntToStr(Value) + CRLF); - - s := FSock.RecvString(FTimeout); - if Pos('+OK', s) = 1 then - Result := True; - FResultString := s; - if Result then begin - repeat - s := FSock.RecvString(FTimeout); - if s = '.' then - Break; - if s <> '' then begin - if s[1] = '.' then - Delete(s, 1, 1); - end; - WriteStrToStream(Stream, s); - WriteStrToStream(Stream, CRLF); - until FSock.LastError <> 0; - end; - - if Result then - FResultCode := 1 - else - FResultCode := 0; -end; - -function TPOP3Send.Dele(Value: Integer): Boolean; -begin - Result := CustomCommand('DELE ' + IntToStr(Value), False); -end; - -function TPOP3Send.Top(Value, Maxlines: Integer): Boolean; -begin - Result := CustomCommand('TOP ' + IntToStr(Value) + ' ' + IntToStr(Maxlines), True); -end; - -function TPOP3Send.Uidl(Value: Integer): Boolean; -var - s: string; -begin - if Value = 0 then - s := 'UIDL' - else - s := 'UIDL ' + IntToStr(Value); - Result := CustomCommand(s, Value = 0); -end; - -function TPOP3Send.StartTLS: Boolean; -begin - Result := False; - if CustomCommand('STLS', False) then - begin - Fsock.SSLDoConnect; - Result := FSock.LastError = 0; - end; -end; - -function TPOP3Send.FindCap(const Value: string): string; -var - n: Integer; - s: string; -begin - s := UpperCase(Value); - Result := ''; - for n := 0 to FPOP3cap.Count - 1 do - if Pos(s, UpperCase(FPOP3cap[n])) = 1 then - begin - Result := FPOP3cap[n]; - Break; - end; -end; - -end. diff --git a/3rd/synapse/source/slogsend.pas b/3rd/synapse/source/slogsend.pas deleted file mode 100644 index 900f6c01a..000000000 --- a/3rd/synapse/source/slogsend.pas +++ /dev/null @@ -1,320 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.002.003 | -|==============================================================================| -| Content: SysLog client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Christian Brosius | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(BSD SYSLOG protocol) - -Used RFC: RFC-3164 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -unit slogsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil; - -const - cSysLogProtocol = '514'; - - FCL_Kernel = 0; - FCL_UserLevel = 1; - FCL_MailSystem = 2; - FCL_System = 3; - FCL_Security = 4; - FCL_Syslogd = 5; - FCL_Printer = 6; - FCL_News = 7; - FCL_UUCP = 8; - FCL_Clock = 9; - FCL_Authorization = 10; - FCL_FTP = 11; - FCL_NTP = 12; - FCL_LogAudit = 13; - FCL_LogAlert = 14; - FCL_Time = 15; - FCL_Local0 = 16; - FCL_Local1 = 17; - FCL_Local2 = 18; - FCL_Local3 = 19; - FCL_Local4 = 20; - FCL_Local5 = 21; - FCL_Local6 = 22; - FCL_Local7 = 23; - -type - {:@abstract(Define possible priority of Syslog message)} - TSyslogSeverity = (Emergency, Alert, Critical, Error, Warning, Notice, Info, - Debug); - - {:@abstract(encoding or decoding of SYSLOG message)} - TSyslogMessage = class(TObject) - private - FFacility:Byte; - FSeverity:TSyslogSeverity; - FDateTime:TDateTime; - FTag:String; - FMessage:String; - FLocalIP:String; - function GetPacketBuf:String; - procedure SetPacketBuf(Value:String); - public - {:Reset values to defaults} - procedure Clear; - published - {:Define facilicity of Syslog message. For specify you may use predefined - FCL_* constants. Default is "FCL_Local0".} - property Facility:Byte read FFacility write FFacility; - - {:Define possible priority of Syslog message. Default is "Debug".} - property Severity:TSyslogSeverity read FSeverity write FSeverity; - - {:date and time of Syslog message} - property DateTime:TDateTime read FDateTime write FDateTime; - - {:This is used for identify process of this message. Default is filename - of your executable file.} - property Tag:String read FTag write FTag; - - {:Text of your message for log.} - property LogMessage:String read FMessage write FMessage; - - {:IP address of message sender.} - property LocalIP:String read FLocalIP write FLocalIP; - - {:This property holds encoded binary SYSLOG packet} - property PacketBuf:String read GetPacketBuf write SetPacketBuf; - end; - - {:@abstract(This object implement BSD SysLog client) - - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TSyslogSend = class(TSynaClient) - private - FSock: TUDPBlockSocket; - FSysLogMessage: TSysLogMessage; - public - constructor Create; - destructor Destroy; override; - {:Send Syslog UDP packet defined by @link(SysLogMessage).} - function DoIt: Boolean; - published - {:Syslog message for send} - property SysLogMessage:TSysLogMessage read FSysLogMessage write FSysLogMessage; - end; - -{:Simply send packet to specified Syslog server.} -function ToSysLog(const SyslogServer: string; Facil: Byte; - Sever: TSyslogSeverity; const Content: string): Boolean; - -implementation - -function TSyslogMessage.GetPacketBuf:String; -begin - Result := '<' + IntToStr((FFacility * 8) + Ord(FSeverity)) + '>'; - Result := Result + CDateTime(FDateTime) + ' '; - Result := Result + FLocalIP + ' '; - Result := Result + FTag + ': ' + FMessage; -end; - -procedure TSyslogMessage.SetPacketBuf(Value:String); -var StrBuf:String; - IntBuf,Pos:Integer; -begin - if Length(Value) < 1 then exit; - Pos := 1; - if Value[Pos] <> '<' then exit; - Inc(Pos); - // Facility and Severity - StrBuf := ''; - while (Value[Pos] <> '>')do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - IntBuf := StrToInt(StrBuf); - FFacility := IntBuf div 8; - case (IntBuf mod 8)of - 0:FSeverity := Emergency; - 1:FSeverity := Alert; - 2:FSeverity := Critical; - 3:FSeverity := Error; - 4:FSeverity := Warning; - 5:FSeverity := Notice; - 6:FSeverity := Info; - 7:FSeverity := Debug; - end; - // DateTime - Inc(Pos); - StrBuf := ''; - // Month - while (Value[Pos] <> ' ')do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - // Day - while (Value[Pos] <> ' ')do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - // Time - while (Value[Pos] <> ' ')do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - FDateTime := DecodeRFCDateTime(StrBuf); - Inc(Pos); - - // LocalIP - StrBuf := ''; - while (Value[Pos] <> ' ')do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - FLocalIP := StrBuf; - Inc(Pos); - // Tag - StrBuf := ''; - while (Value[Pos] <> ':')do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - FTag := StrBuf; - // LogMessage - Inc(Pos); - StrBuf := ''; - while (Pos <= Length(Value))do - begin - StrBuf := StrBuf + Value[Pos]; - Inc(Pos); - end; - FMessage := TrimSP(StrBuf); -end; - -procedure TSysLogMessage.Clear; -begin - FFacility := FCL_Local0; - FSeverity := Debug; - FTag := ExtractFileName(ParamStr(0)); - FMessage := ''; - FLocalIP := '0.0.0.0'; -end; - -//------------------------------------------------------------------------------ - -constructor TSyslogSend.Create; -begin - inherited Create; - FSock := TUDPBlockSocket.Create; - FSock.Owner := self; - FSysLogMessage := TSysLogMessage.Create; - FTargetPort := cSysLogProtocol; -end; - -destructor TSyslogSend.Destroy; -begin - FSock.Free; - FSysLogMessage.Free; - inherited Destroy; -end; - -function TSyslogSend.DoIt: Boolean; -var - L: TStringList; -begin - Result := False; - L := TStringList.Create; - try - FSock.ResolveNameToIP(FSock.Localname, L); - if L.Count < 1 then - FSysLogMessage.LocalIP := '0.0.0.0' - else - FSysLogMessage.LocalIP := L[0]; - finally - L.Free; - end; - FSysLogMessage.DateTime := Now; - if Length(FSysLogMessage.PacketBuf) <= 1024 then - begin - FSock.Connect(FTargetHost, FTargetPort); - FSock.SendString(FSysLogMessage.PacketBuf); - Result := FSock.LastError = 0; - end; -end; - -{==============================================================================} - -function ToSysLog(const SyslogServer: string; Facil: Byte; - Sever: TSyslogSeverity; const Content: string): Boolean; -begin - with TSyslogSend.Create do - try - TargetHost :=SyslogServer; - SysLogMessage.Facility := Facil; - SysLogMessage.Severity := Sever; - SysLogMessage.LogMessage := Content; - Result := DoIt; - finally - Free; - end; -end; - -end. diff --git a/3rd/synapse/source/smtpsend.pas b/3rd/synapse/source/smtpsend.pas deleted file mode 100644 index e023a38ff..000000000 --- a/3rd/synapse/source/smtpsend.pas +++ /dev/null @@ -1,724 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 003.005.001 | -|==============================================================================| -| Content: SMTP client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(SMTP client) - -Used RFC: RFC-1869, RFC-1870, RFC-1893, RFC-2034, RFC-2104, RFC-2195, RFC-2487, - RFC-2554, RFC-2821 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit smtpsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil, synacode; - -const - cSmtpProtocol = '25'; - -type - {:@abstract(Implementation of SMTP and ESMTP procotol), - include some ESMTP extensions, include SSL/TLS too. - - Note: Are you missing properties for setting Username and Password for ESMTP? - Look to parent @link(TSynaClient) object! - - Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TSMTPSend = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FResultCode: Integer; - FResultString: string; - FFullResult: TStringList; - FESMTPcap: TStringList; - FESMTP: Boolean; - FAuthDone: Boolean; - FESMTPSize: Boolean; - FMaxSize: Integer; - FEnhCode1: Integer; - FEnhCode2: Integer; - FEnhCode3: Integer; - FSystemName: string; - FAutoTLS: Boolean; - FFullSSL: Boolean; - procedure EnhancedCode(const Value: string); - function ReadResult: Integer; - function AuthLogin: Boolean; - function AuthCram: Boolean; - function AuthPlain: Boolean; - function Helo: Boolean; - function Ehlo: Boolean; - function Connect: Boolean; - public - constructor Create; - destructor Destroy; override; - - {:Connects to SMTP server (defined in @link(TSynaClient.TargetHost)) and - begin SMTP session. (First try ESMTP EHLO, next old HELO handshake). Parses - ESMTP capabilites and if you specified Username and password and remote - server can handle AUTH command, try login by AUTH command. Preffered login - method is CRAM-MD5 (if safer!). If all OK, result is @true, else result is - @false.} - function Login: Boolean; - - {:Close SMTP session (QUIT command) and disconnect from SMTP server.} - function Logout: Boolean; - - {:Send RSET SMTP command for reset SMTP session. If all OK, result is @true, - else result is @false.} - function Reset: Boolean; - - {:Send NOOP SMTP command for keep SMTP session. If all OK, result is @true, - else result is @false.} - function NoOp: Boolean; - - {:Send MAIL FROM SMTP command for set sender e-mail address. If sender's - e-mail address is empty string, transmited message is error message. - - If size not 0 and remote server can handle SIZE parameter, append SIZE - parameter to request. If all OK, result is @true, else result is @false.} - function MailFrom(const Value: string; Size: Integer): Boolean; - - {:Send RCPT TO SMTP command for set receiver e-mail address. It cannot be an - empty string. If all OK, result is @true, else result is @false.} - function MailTo(const Value: string): Boolean; - - {:Send DATA SMTP command and transmit message data. If all OK, result is - @true, else result is @false.} - function MailData(const Value: Tstrings): Boolean; - - {:Send ETRN SMTP command for start sending of remote queue for domain in - Value. If all OK, result is @true, else result is @false.} - function Etrn(const Value: string): Boolean; - - {:Send VRFY SMTP command for check receiver e-mail address. It cannot be - an empty string. If all OK, result is @true, else result is @false.} - function Verify(const Value: string): Boolean; - - {:Call STARTTLS command for upgrade connection to SSL/TLS mode.} - function StartTLS: Boolean; - - {:Return string descriptive text for enhanced result codes stored in - @link(EnhCode1), @link(EnhCode2) and @link(EnhCode3).} - function EnhCodeString: string; - - {:Try to find specified capability in ESMTP response.} - function FindCap(const Value: string): string; - published - {:result code of last SMTP command.} - property ResultCode: Integer read FResultCode; - - {:result string of last SMTP command (begin with string representation of - result code).} - property ResultString: string read FResultString; - - {:All result strings of last SMTP command (result is maybe multiline!).} - property FullResult: TStringList read FFullResult; - - {:List of ESMTP capabilites of remote ESMTP server. (If you connect to ESMTP - server only!).} - property ESMTPcap: TStringList read FESMTPcap; - - {:@TRUE if you successfuly logged to ESMTP server.} - property ESMTP: Boolean read FESMTP; - - {:@TRUE if you successfuly pass authorisation to remote server.} - property AuthDone: Boolean read FAuthDone; - - {:@TRUE if remote server can handle SIZE parameter.} - property ESMTPSize: Boolean read FESMTPSize; - - {:When @link(ESMTPsize) is @TRUE, contains max length of message that remote - server can handle.} - property MaxSize: Integer read FMaxSize; - - {:First digit of Enhanced result code. If last operation does not have - enhanced result code, values is 0.} - property EnhCode1: Integer read FEnhCode1; - - {:Second digit of Enhanced result code. If last operation does not have - enhanced result code, values is 0.} - property EnhCode2: Integer read FEnhCode2; - - {:Third digit of Enhanced result code. If last operation does not have - enhanced result code, values is 0.} - property EnhCode3: Integer read FEnhCode3; - - {:name of our system used in HELO and EHLO command. Implicit value is - internet address of your machine.} - property SystemName: string read FSystemName Write FSystemName; - - {:If is set to true, then upgrade to SSL/TLS mode if remote server support it.} - property AutoTLS: Boolean read FAutoTLS Write FAutoTLS; - - {:SSL/TLS mode is used from first contact to server. Servers with full - SSL/TLS mode usualy using non-standard TCP port!} - property FullSSL: Boolean read FFullSSL Write FFullSSL; - - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - end; - -{:A very useful function and example of its use would be found in the TSMTPsend - object. Send maildata (text of e-mail with all SMTP headers! For example when - text of message is created by @link(TMimemess) object) from "MailFrom" e-mail - address to "MailTo" e-mail address (If you need more then one receiver, then - separate their addresses by comma). - - Function sends e-mail to a SMTP server defined in "SMTPhost" parameter. - Username and password are used for authorization to the "SMTPhost". If you - don't want authorization, set "Username" and "Password" to empty strings. If - e-mail message is successfully sent, the result returns @true. - - If you need use different port number then standard, then add this port number - to SMTPhost after colon. (i.e. '127.0.0.1:1025')} -function SendToRaw(const MailFrom, MailTo, SMTPHost: string; - const MailData: TStrings; const Username, Password: string): Boolean; - -{:A very useful function and example of its use would be found in the TSMTPsend - object. Send "Maildata" (text of e-mail without any SMTP headers!) from - "MailFrom" e-mail address to "MailTo" e-mail address with "Subject". (If you - need more then one receiver, then separate their addresses by comma). - - This function constructs all needed SMTP headers (with DATE header) and sends - the e-mail to the SMTP server defined in the "SMTPhost" parameter. If the - e-mail message is successfully sent, the result will be @TRUE. - - If you need use different port number then standard, then add this port number - to SMTPhost after colon. (i.e. '127.0.0.1:1025')} -function SendTo(const MailFrom, MailTo, Subject, SMTPHost: string; - const MailData: TStrings): Boolean; - -{:A very useful function and example of its use would be found in the TSMTPsend - object. Sends "MailData" (text of e-mail without any SMTP headers!) from - "MailFrom" e-mail address to "MailTo" e-mail address (If you need more then one - receiver, then separate their addresses by comma). - - This function sends the e-mail to the SMTP server defined in the "SMTPhost" - parameter. Username and password are used for authorization to the "SMTPhost". - If you dont want authorization, set "Username" and "Password" to empty Strings. - If the e-mail message is successfully sent, the result will be @TRUE. - - If you need use different port number then standard, then add this port number - to SMTPhost after colon. (i.e. '127.0.0.1:1025')} -function SendToEx(const MailFrom, MailTo, Subject, SMTPHost: string; - const MailData: TStrings; const Username, Password: string): Boolean; - -implementation - -constructor TSMTPSend.Create; -begin - inherited Create; - FFullResult := TStringList.Create; - FESMTPcap := TStringList.Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.ConvertLineEnd := true; - FTimeout := 60000; - FTargetPort := cSmtpProtocol; - FSystemName := FSock.LocalName; - FAutoTLS := False; - FFullSSL := False; -end; - -destructor TSMTPSend.Destroy; -begin - FSock.Free; - FESMTPcap.Free; - FFullResult.Free; - inherited Destroy; -end; - -procedure TSMTPSend.EnhancedCode(const Value: string); -var - s, t: string; - e1, e2, e3: Integer; -begin - FEnhCode1 := 0; - FEnhCode2 := 0; - FEnhCode3 := 0; - s := Copy(Value, 5, Length(Value) - 4); - t := Trim(SeparateLeft(s, '.')); - s := Trim(SeparateRight(s, '.')); - if t = '' then - Exit; - if Length(t) > 1 then - Exit; - e1 := StrToIntDef(t, 0); - if e1 = 0 then - Exit; - t := Trim(SeparateLeft(s, '.')); - s := Trim(SeparateRight(s, '.')); - if t = '' then - Exit; - if Length(t) > 3 then - Exit; - e2 := StrToIntDef(t, 0); - t := Trim(SeparateLeft(s, ' ')); - if t = '' then - Exit; - if Length(t) > 3 then - Exit; - e3 := StrToIntDef(t, 0); - FEnhCode1 := e1; - FEnhCode2 := e2; - FEnhCode3 := e3; -end; - -function TSMTPSend.ReadResult: Integer; -var - s: String; -begin - Result := 0; - FFullResult.Clear; - repeat - s := FSock.RecvString(FTimeout); - FResultString := s; - FFullResult.Add(s); - if FSock.LastError <> 0 then - Break; - until Pos('-', s) <> 4; - s := FFullResult[0]; - if Length(s) >= 3 then - Result := StrToIntDef(Copy(s, 1, 3), 0); - FResultCode := Result; - EnhancedCode(s); -end; - -function TSMTPSend.AuthLogin: Boolean; -begin - Result := False; - FSock.SendString('AUTH LOGIN' + CRLF); - if ReadResult <> 334 then - Exit; - FSock.SendString(EncodeBase64(FUsername) + CRLF); - if ReadResult <> 334 then - Exit; - FSock.SendString(EncodeBase64(FPassword) + CRLF); - Result := ReadResult = 235; -end; - -function TSMTPSend.AuthCram: Boolean; -var - s: ansistring; -begin - Result := False; - FSock.SendString('AUTH CRAM-MD5' + CRLF); - if ReadResult <> 334 then - Exit; - s := Copy(FResultString, 5, Length(FResultString) - 4); - s := DecodeBase64(s); - s := HMAC_MD5(s, FPassword); - s := FUsername + ' ' + StrToHex(s); - FSock.SendString(EncodeBase64(s) + CRLF); - Result := ReadResult = 235; -end; - -function TSMTPSend.AuthPlain: Boolean; -var - s: ansistring; -begin - s := ansichar(0) + FUsername + ansichar(0) + FPassword; - FSock.SendString('AUTH PLAIN ' + EncodeBase64(s) + CRLF); - Result := ReadResult = 235; -end; - -function TSMTPSend.Connect: Boolean; -begin - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - if FSock.LastError = 0 then - FSock.Connect(FTargetHost, FTargetPort); - if FSock.LastError = 0 then - if FFullSSL then - FSock.SSLDoConnect; - Result := FSock.LastError = 0; -end; - -function TSMTPSend.Helo: Boolean; -var - x: Integer; -begin - FSock.SendString('HELO ' + FSystemName + CRLF); - x := ReadResult; - Result := (x >= 250) and (x <= 259); -end; - -function TSMTPSend.Ehlo: Boolean; -var - x: Integer; -begin - FSock.SendString('EHLO ' + FSystemName + CRLF); - x := ReadResult; - Result := (x >= 250) and (x <= 259); -end; - -function TSMTPSend.Login: Boolean; -var - n: Integer; - auths: string; - s: string; -begin - Result := False; - FESMTP := True; - FAuthDone := False; - FESMTPcap.clear; - FESMTPSize := False; - FMaxSize := 0; - if not Connect then - Exit; - if ReadResult <> 220 then - Exit; - if not Ehlo then - begin - FESMTP := False; - if not Helo then - Exit; - end; - Result := True; - if FESMTP then - begin - for n := 1 to FFullResult.Count - 1 do - FESMTPcap.Add(Copy(FFullResult[n], 5, Length(FFullResult[n]) - 4)); - if (not FullSSL) and FAutoTLS and (FindCap('STARTTLS') <> '') then - if StartTLS then - begin - Ehlo; - FESMTPcap.Clear; - for n := 1 to FFullResult.Count - 1 do - FESMTPcap.Add(Copy(FFullResult[n], 5, Length(FFullResult[n]) - 4)); - end - else - begin - Result := False; - Exit; - end; - if not ((FUsername = '') and (FPassword = '')) then - begin - s := FindCap('AUTH '); - if s = '' then - s := FindCap('AUTH='); - auths := UpperCase(s); - if s <> '' then - begin - if Pos('CRAM-MD5', auths) > 0 then - FAuthDone := AuthCram; - if (not FauthDone) and (Pos('PLAIN', auths) > 0) then - FAuthDone := AuthPlain; - if (not FauthDone) and (Pos('LOGIN', auths) > 0) then - FAuthDone := AuthLogin; - end; - end; - s := FindCap('SIZE'); - if s <> '' then - begin - FESMTPsize := True; - FMaxSize := StrToIntDef(Copy(s, 6, Length(s) - 5), 0); - end; - end; -end; - -function TSMTPSend.Logout: Boolean; -begin - FSock.SendString('QUIT' + CRLF); - Result := ReadResult = 221; - FSock.CloseSocket; -end; - -function TSMTPSend.Reset: Boolean; -begin - FSock.SendString('RSET' + CRLF); - Result := ReadResult div 100 = 2; -end; - -function TSMTPSend.NoOp: Boolean; -begin - FSock.SendString('NOOP' + CRLF); - Result := ReadResult div 100 = 2; -end; - -function TSMTPSend.MailFrom(const Value: string; Size: Integer): Boolean; -var - s: string; -begin - s := 'MAIL FROM:<' + Value + '>'; - if FESMTPsize and (Size > 0) then - s := s + ' SIZE=' + IntToStr(Size); - FSock.SendString(s + CRLF); - Result := ReadResult div 100 = 2; -end; - -function TSMTPSend.MailTo(const Value: string): Boolean; -begin - FSock.SendString('RCPT TO:<' + Value + '>' + CRLF); - Result := ReadResult div 100 = 2; -end; - -function TSMTPSend.MailData(const Value: TStrings): Boolean; -var - n: Integer; - s: string; - t: string; - x: integer; -begin - Result := False; - FSock.SendString('DATA' + CRLF); - if ReadResult <> 354 then - Exit; - t := ''; - x := 1500; - for n := 0 to Value.Count - 1 do - begin - s := Value[n]; - if Length(s) >= 1 then - if s[1] = '.' then - s := '.' + s; - if Length(t) + Length(s) >= x then - begin - FSock.SendString(t); - t := ''; - end; - t := t + s + CRLF; - end; - if t <> '' then - FSock.SendString(t); - FSock.SendString('.' + CRLF); - Result := ReadResult div 100 = 2; -end; - -function TSMTPSend.Etrn(const Value: string): Boolean; -var - x: Integer; -begin - FSock.SendString('ETRN ' + Value + CRLF); - x := ReadResult; - Result := (x >= 250) and (x <= 259); -end; - -function TSMTPSend.Verify(const Value: string): Boolean; -var - x: Integer; -begin - FSock.SendString('VRFY ' + Value + CRLF); - x := ReadResult; - Result := (x >= 250) and (x <= 259); -end; - -function TSMTPSend.StartTLS: Boolean; -begin - Result := False; - if FindCap('STARTTLS') <> '' then - begin - FSock.SendString('STARTTLS' + CRLF); - if (ReadResult = 220) and (FSock.LastError = 0) then - begin - Fsock.SSLDoConnect; - Result := FSock.LastError = 0; - end; - end; -end; - -function TSMTPSend.EnhCodeString: string; -var - s, t: string; -begin - s := IntToStr(FEnhCode2) + '.' + IntToStr(FEnhCode3); - t := ''; - if s = '0.0' then t := 'Other undefined Status'; - if s = '1.0' then t := 'Other address status'; - if s = '1.1' then t := 'Bad destination mailbox address'; - if s = '1.2' then t := 'Bad destination system address'; - if s = '1.3' then t := 'Bad destination mailbox address syntax'; - if s = '1.4' then t := 'Destination mailbox address ambiguous'; - if s = '1.5' then t := 'Destination mailbox address valid'; - if s = '1.6' then t := 'Mailbox has moved'; - if s = '1.7' then t := 'Bad sender''s mailbox address syntax'; - if s = '1.8' then t := 'Bad sender''s system address'; - if s = '2.0' then t := 'Other or undefined mailbox status'; - if s = '2.1' then t := 'Mailbox disabled, not accepting messages'; - if s = '2.2' then t := 'Mailbox full'; - if s = '2.3' then t := 'Message Length exceeds administrative limit'; - if s = '2.4' then t := 'Mailing list expansion problem'; - if s = '3.0' then t := 'Other or undefined mail system status'; - if s = '3.1' then t := 'Mail system full'; - if s = '3.2' then t := 'System not accepting network messages'; - if s = '3.3' then t := 'System not capable of selected features'; - if s = '3.4' then t := 'Message too big for system'; - if s = '3.5' then t := 'System incorrectly configured'; - if s = '4.0' then t := 'Other or undefined network or routing status'; - if s = '4.1' then t := 'No answer from host'; - if s = '4.2' then t := 'Bad connection'; - if s = '4.3' then t := 'Routing server failure'; - if s = '4.4' then t := 'Unable to route'; - if s = '4.5' then t := 'Network congestion'; - if s = '4.6' then t := 'Routing loop detected'; - if s = '4.7' then t := 'Delivery time expired'; - if s = '5.0' then t := 'Other or undefined protocol status'; - if s = '5.1' then t := 'Invalid command'; - if s = '5.2' then t := 'Syntax error'; - if s = '5.3' then t := 'Too many recipients'; - if s = '5.4' then t := 'Invalid command arguments'; - if s = '5.5' then t := 'Wrong protocol version'; - if s = '6.0' then t := 'Other or undefined media error'; - if s = '6.1' then t := 'Media not supported'; - if s = '6.2' then t := 'Conversion required and prohibited'; - if s = '6.3' then t := 'Conversion required but not supported'; - if s = '6.4' then t := 'Conversion with loss performed'; - if s = '6.5' then t := 'Conversion failed'; - if s = '7.0' then t := 'Other or undefined security status'; - if s = '7.1' then t := 'Delivery not authorized, message refused'; - if s = '7.2' then t := 'Mailing list expansion prohibited'; - if s = '7.3' then t := 'Security conversion required but not possible'; - if s = '7.4' then t := 'Security features not supported'; - if s = '7.5' then t := 'Cryptographic failure'; - if s = '7.6' then t := 'Cryptographic algorithm not supported'; - if s = '7.7' then t := 'Message integrity failure'; - s := '???-'; - if FEnhCode1 = 2 then s := 'Success-'; - if FEnhCode1 = 4 then s := 'Persistent Transient Failure-'; - if FEnhCode1 = 5 then s := 'Permanent Failure-'; - Result := s + t; -end; - -function TSMTPSend.FindCap(const Value: string): string; -var - n: Integer; - s: string; -begin - s := UpperCase(Value); - Result := ''; - for n := 0 to FESMTPcap.Count - 1 do - if Pos(s, UpperCase(FESMTPcap[n])) = 1 then - begin - Result := FESMTPcap[n]; - Break; - end; -end; - -{==============================================================================} - -function SendToRaw(const MailFrom, MailTo, SMTPHost: string; - const MailData: TStrings; const Username, Password: string): Boolean; -var - SMTP: TSMTPSend; - s, t: string; -begin - Result := False; - SMTP := TSMTPSend.Create; - try -// if you need SOCKS5 support, uncomment next lines: - // SMTP.Sock.SocksIP := '127.0.0.1'; - // SMTP.Sock.SocksPort := '1080'; -// if you need support for upgrade session to TSL/SSL, uncomment next lines: - // SMTP.AutoTLS := True; -// if you need support for TSL/SSL tunnel, uncomment next lines: - // SMTP.FullSSL := True; - SMTP.TargetHost := Trim(SeparateLeft(SMTPHost, ':')); - s := Trim(SeparateRight(SMTPHost, ':')); - if (s <> '') and (s <> SMTPHost) then - SMTP.TargetPort := s; - SMTP.Username := Username; - SMTP.Password := Password; - if SMTP.Login then - begin - if SMTP.MailFrom(GetEmailAddr(MailFrom), Length(MailData.Text)) then - begin - s := MailTo; - repeat - t := GetEmailAddr(Trim(FetchEx(s, ',', '"'))); - if t <> '' then - Result := SMTP.MailTo(t); - if not Result then - Break; - until s = ''; - if Result then - Result := SMTP.MailData(MailData); - end; - SMTP.Logout; - end; - finally - SMTP.Free; - end; -end; - -function SendToEx(const MailFrom, MailTo, Subject, SMTPHost: string; - const MailData: TStrings; const Username, Password: string): Boolean; -var - t: TStrings; -begin - t := TStringList.Create; - try - t.Assign(MailData); - t.Insert(0, ''); - t.Insert(0, 'X-mailer: Synapse - Delphi & Kylix TCP/IP library by Lukas Gebauer'); - t.Insert(0, 'Subject: ' + Subject); - t.Insert(0, 'Date: ' + Rfc822DateTime(now)); - t.Insert(0, 'To: ' + MailTo); - t.Insert(0, 'From: ' + MailFrom); - Result := SendToRaw(MailFrom, MailTo, SMTPHost, t, Username, Password); - finally - t.Free; - end; -end; - -function SendTo(const MailFrom, MailTo, Subject, SMTPHost: string; - const MailData: TStrings): Boolean; -begin - Result := SendToEx(MailFrom, MailTo, Subject, SMTPHost, MailData, '', ''); -end; - -end. diff --git a/3rd/synapse/source/snmpsend.pas b/3rd/synapse/source/snmpsend.pas deleted file mode 100644 index 6e44c04e5..000000000 --- a/3rd/synapse/source/snmpsend.pas +++ /dev/null @@ -1,1266 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 004.000.000 | -|==============================================================================| -| Content: SNMP client | -|==============================================================================| -| Copyright (c)1999-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2011. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Jean-Fabien Connault (cycocrew@worldnet.fr) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(SNMP client) -Supports SNMPv1 include traps, SNMPv2c and SNMPv3 include authorization -and privacy encryption. - -Used RFC: RFC-1157, RFC-1901, RFC-3412, RFC-3414, RFC-3416, RFC-3826 - -Supported Authorization hashes: MD5, SHA1 -Supported Privacy encryptions: DES, 3DES, AES -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit snmpsend; - -interface - -uses - Classes, SysUtils, - blcksock, synautil, asn1util, synaip, synacode, synacrypt; - -const - cSnmpProtocol = '161'; - cSnmpTrapProtocol = '162'; - - SNMP_V1 = 0; - SNMP_V2C = 1; - SNMP_V3 = 3; - - //PDU type - PDUGetRequest = $A0; - PDUGetNextRequest = $A1; - PDUGetResponse = $A2; - PDUSetRequest = $A3; - PDUTrap = $A4; //Obsolete - //for SNMPv2 - PDUGetBulkRequest = $A5; - PDUInformRequest = $A6; - PDUTrapV2 = $A7; - PDUReport = $A8; - - //errors - ENoError = 0; - ETooBig = 1; - ENoSuchName = 2; - EBadValue = 3; - EReadOnly = 4; - EGenErr = 5; - //errors SNMPv2 - ENoAccess = 6; - EWrongType = 7; - EWrongLength = 8; - EWrongEncoding = 9; - EWrongValue = 10; - ENoCreation = 11; - EInconsistentValue = 12; - EResourceUnavailable = 13; - ECommitFailed = 14; - EUndoFailed = 15; - EAuthorizationError = 16; - ENotWritable = 17; - EInconsistentName = 18; - -type - - {:@abstract(Possible values for SNMPv3 flags.) - This flags specify level of authorization and encryption.} - TV3Flags = ( - NoAuthNoPriv, - AuthNoPriv, - AuthPriv); - - {:@abstract(Type of SNMPv3 authorization)} - TV3Auth = ( - AuthMD5, - AuthSHA1); - - {:@abstract(Type of SNMPv3 privacy)} - TV3Priv = ( - PrivDES, - Priv3DES, - PrivAES); - - {:@abstract(Data object with one record of MIB OID and corresponding values.)} - TSNMPMib = class(TObject) - protected - FOID: AnsiString; - FValue: AnsiString; - FValueType: Integer; - published - {:OID number in string format.} - property OID: AnsiString read FOID write FOID; - - {:Value of OID object in string format.} - property Value: AnsiString read FValue write FValue; - - {:Define type of Value. Supported values are defined in @link(asn1util). - For queries use ASN1_NULL, becouse you don't know type in response!} - property ValueType: Integer read FValueType write FValueType; - end; - - {:@abstract(It holding all information for SNMPv3 agent synchronization) - Used internally.} - TV3Sync = record - EngineID: AnsiString; - EngineBoots: integer; - EngineTime: integer; - EngineStamp: Cardinal; - end; - - {:@abstract(Data object abstracts SNMP data packet)} - TSNMPRec = class(TObject) - protected - FVersion: Integer; - FPDUType: Integer; - FID: Integer; - FErrorStatus: Integer; - FErrorIndex: Integer; - FCommunity: AnsiString; - FSNMPMibList: TList; - FMaxSize: Integer; - FFlags: TV3Flags; - FFlagReportable: Boolean; - FContextEngineID: AnsiString; - FContextName: AnsiString; - FAuthMode: TV3Auth; - FAuthEngineID: AnsiString; - FAuthEngineBoots: integer; - FAuthEngineTime: integer; - FAuthEngineTimeStamp: cardinal; - FUserName: AnsiString; - FPassword: AnsiString; - FAuthKey: AnsiString; - FPrivMode: TV3Priv; - FPrivPassword: AnsiString; - FPrivKey: AnsiString; - FPrivSalt: AnsiString; - FPrivSaltCounter: integer; - FOldTrapEnterprise: AnsiString; - FOldTrapHost: AnsiString; - FOldTrapGen: Integer; - FOldTrapSpec: Integer; - FOldTrapTimeTicks: Integer; - function Pass2Key(const Value: AnsiString): AnsiString; - function EncryptPDU(const value: AnsiString): AnsiString; - function DecryptPDU(const value: AnsiString): AnsiString; - public - constructor Create; - destructor Destroy; override; - - {:Decode SNMP packet in buffer to object properties.} - function DecodeBuf(Buffer: AnsiString): Boolean; - - {:Encode obeject properties to SNMP packet.} - function EncodeBuf: AnsiString; - - {:Clears all object properties to default values.} - procedure Clear; - - {:Add entry to @link(SNMPMibList). For queries use value as empty string, - and ValueType as ASN1_NULL.} - procedure MIBAdd(const MIB, Value: AnsiString; ValueType: Integer); - - {:Delete entry from @link(SNMPMibList).} - procedure MIBDelete(Index: Integer); - - {:Search @link(SNMPMibList) list for MIB and return correspond value.} - function MIBGet(const MIB: AnsiString): AnsiString; - - {:return number of entries in MIB array.} - function MIBCount: integer; - - {:Return MIB information from given row of MIB array.} - function MIBByIndex(Index: Integer): TSNMPMib; - - {:List of @link(TSNMPMib) objects.} - property SNMPMibList: TList read FSNMPMibList; - published - {:Version of SNMP packet. Default value is 0 (SNMP ver. 1). You can use - value 1 for SNMPv2c or value 3 for SNMPv3.} - property Version: Integer read FVersion write FVersion; - - {:Community string for autorize access to SNMP server. (Case sensitive!) - Community string is not used in SNMPv3! Use @link(Username) and - @link(password) instead!} - property Community: AnsiString read FCommunity write FCommunity; - - {:Define type of SNMP operation.} - property PDUType: Integer read FPDUType write FPDUType; - - {:Contains ID number. Not need to use.} - property ID: Integer read FID write FID; - - {:When packet is reply, contains error code. Supported values are defined by - E* constants.} - property ErrorStatus: Integer read FErrorStatus write FErrorStatus; - - {:Point to error position in reply packet. Not usefull for users. It only - good for debugging!} - property ErrorIndex: Integer read FErrorIndex write FErrorIndex; - - {:special value for GetBulkRequest of SNMPv2 and v3.} - property NonRepeaters: Integer read FErrorStatus write FErrorStatus; - - {:special value for GetBulkRequest of SNMPv2 and v3.} - property MaxRepetitions: Integer read FErrorIndex write FErrorIndex; - - {:Maximum message size in bytes for SNMPv3. For sending is default 1472 bytes.} - property MaxSize: Integer read FMaxSize write FMaxSize; - - {:Specify if message is authorised or encrypted. Used only in SNMPv3.} - property Flags: TV3Flags read FFlags write FFlags; - - {:For SNMPv3.... If is @true, SNMP agent must send reply (at least with some - error).} - property FlagReportable: Boolean read FFlagReportable write FFlagReportable; - - {:For SNMPv3. If not specified, is used value from @link(AuthEngineID)} - property ContextEngineID: AnsiString read FContextEngineID write FContextEngineID; - - {:For SNMPv3.} - property ContextName: AnsiString read FContextName write FContextName; - - {:For SNMPv3. Specify Authorization mode. (specify used hash for - authorization)} - property AuthMode: TV3Auth read FAuthMode write FAuthMode; - - {:For SNMPv3. Specify Privacy mode.} - property PrivMode: TV3Priv read FPrivMode write FPrivMode; - - {:value used by SNMPv3 authorisation for synchronization with SNMP agent.} - property AuthEngineID: AnsiString read FAuthEngineID write FAuthEngineID; - - {:value used by SNMPv3 authorisation for synchronization with SNMP agent.} - property AuthEngineBoots: Integer read FAuthEngineBoots write FAuthEngineBoots; - - {:value used by SNMPv3 authorisation for synchronization with SNMP agent.} - property AuthEngineTime: Integer read FAuthEngineTime write FAuthEngineTime; - - {:value used by SNMPv3 authorisation for synchronization with SNMP agent.} - property AuthEngineTimeStamp: Cardinal read FAuthEngineTimeStamp Write FAuthEngineTimeStamp; - - {:SNMPv3 authorization username} - property UserName: AnsiString read FUserName write FUserName; - - {:SNMPv3 authorization password} - property Password: AnsiString read FPassword write FPassword; - - {:For SNMPv3. Computed Athorization key from @link(password).} - property AuthKey: AnsiString read FAuthKey write FAuthKey; - - {:SNMPv3 privacy password} - property PrivPassword: AnsiString read FPrivPassword write FPrivPassword; - - {:For SNMPv3. Computed Privacy key from @link(PrivPassword).} - property PrivKey: AnsiString read FPrivKey write FPrivKey; - - {:MIB value to identify the object that sent the TRAPv1.} - property OldTrapEnterprise: AnsiString read FOldTrapEnterprise write FOldTrapEnterprise; - - {:Address of TRAPv1 sender (IP address).} - property OldTrapHost: AnsiString read FOldTrapHost write FOldTrapHost; - - {:Generic TRAPv1 identification.} - property OldTrapGen: Integer read FOldTrapGen write FOldTrapGen; - - {:Specific TRAPv1 identification.} - property OldTrapSpec: Integer read FOldTrapSpec write FOldTrapSpec; - - {:Number of 1/100th of seconds since last reboot or power up. (for TRAPv1)} - property OldTrapTimeTicks: Integer read FOldTrapTimeTicks write FOldTrapTimeTicks; - end; - - {:@abstract(Implementation of SNMP protocol.) - - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TSNMPSend = class(TSynaClient) - protected - FSock: TUDPBlockSocket; - FBuffer: AnsiString; - FHostIP: AnsiString; - FQuery: TSNMPRec; - FReply: TSNMPRec; - function InternalSendSnmp(const Value: TSNMPRec): Boolean; - function InternalRecvSnmp(const Value: TSNMPRec): Boolean; - function InternalSendRequest(const QValue, RValue: TSNMPRec): Boolean; - function GetV3EngineID: AnsiString; - function GetV3Sync: TV3Sync; - public - constructor Create; - destructor Destroy; override; - - {:Connects to a Host and send there query. If in timeout SNMP server send - back query, result is @true. If is used SNMPv3, then it synchronize self - with SNMPv3 agent first. (It is needed for SNMPv3 auhorization!)} - function SendRequest: Boolean; - - {:Send SNMP packet only, but not waits for reply. Good for sending traps.} - function SendTrap: Boolean; - - {:Receive SNMP packet only. Good for receiving traps.} - function RecvTrap: Boolean; - - {:Mapped to @link(SendRequest) internally. This function is only for - backward compatibility.} - function DoIt: Boolean; - published - {:contains raw binary form of SNMP packet. Good for debugging.} - property Buffer: AnsiString read FBuffer write FBuffer; - - {:After SNMP operation hold IP address of remote side.} - property HostIP: AnsiString read FHostIP; - - {:Data object contains SNMP query.} - property Query: TSNMPRec read FQuery; - - {:Data object contains SNMP reply.} - property Reply: TSNMPRec read FReply; - - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TUDPBlockSocket read FSock; - end; - -{:A very useful function and example of its use would be found in the TSNMPSend - object. It implements basic GET method of the SNMP protocol. The MIB value is - located in the "OID" variable, and is sent to the requested "SNMPHost" with - the proper "Community" access identifier. Upon a successful retrieval, "Value" - will contain the information requested. If the SNMP operation is successful, - the result returns @true.} -function SNMPGet(const OID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean; - -{:This is useful function and example of use TSNMPSend object. It implements - the basic SET method of the SNMP protocol. If the SNMP operation is successful, - the result is @true. "Value" is value of MIB Oid for "SNMPHost" with "Community" - access identifier. You must specify "ValueType" too.} -function SNMPSet(const OID, Community, SNMPHost, Value: AnsiString; ValueType: Integer): Boolean; - -{:A very useful function and example of its use would be found in the TSNMPSend - object. It implements basic GETNEXT method of the SNMP protocol. The MIB value - is located in the "OID" variable, and is sent to the requested "SNMPHost" with - the proper "Community" access identifier. Upon a successful retrieval, "Value" - will contain the information requested. If the SNMP operation is successful, - the result returns @true.} -function SNMPGetNext(var OID: AnsiString; const Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean; - -{:A very useful function and example of its use would be found in the TSNMPSend - object. It implements basic read of SNMP MIB tables. As BaseOID you must - specify basic MIB OID of requested table (base IOD is OID without row and - column specificator!) - Table is readed into stringlist, where each string is comma delimited string. - - Warning: this function is not have best performance. For better performance - you must write your own function. best performace you can get by knowledge - of structuture of table and by more then one MIB on one query. } -function SNMPGetTable(const BaseOID, Community, SNMPHost: AnsiString; const Value: TStrings): Boolean; - -{:A very useful function and example of its use would be found in the TSNMPSend - object. It implements basic read of SNMP MIB table element. As BaseOID you must - specify basic MIB OID of requested table (base IOD is OID without row and - column specificator!) - As next you must specify identificator of row and column for specify of needed - field of table.} -function SNMPGetTableElement(const BaseOID, RowID, ColID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean; - -{:A very useful function and example of its use would be found in the TSNMPSend - object. It implements a TRAPv1 to send with all data in the parameters.} -function SendTrap(const Dest, Source, Enterprise, Community: AnsiString; - Generic, Specific, Seconds: Integer; const MIBName, MIBValue: AnsiString; - MIBtype: Integer): Integer; - -{:A very useful function and example of its use would be found in the TSNMPSend - object. It receives a TRAPv1 and returns all the data that comes with it.} -function RecvTrap(var Dest, Source, Enterprise, Community: AnsiString; - var Generic, Specific, Seconds: Integer; const MIBName, - MIBValue: TStringList): Integer; - -implementation - -{==============================================================================} - -constructor TSNMPRec.Create; -begin - inherited Create; - FSNMPMibList := TList.Create; - Clear; - FAuthMode := AuthMD5; - FPassword := ''; - FPrivMode := PrivDES; - FPrivPassword := ''; - FID := 1; - FMaxSize := 1472; -end; - -destructor TSNMPRec.Destroy; -var - i: Integer; -begin - for i := 0 to FSNMPMibList.Count - 1 do - TSNMPMib(FSNMPMibList[i]).Free; - FSNMPMibList.Clear; - FSNMPMibList.Free; - inherited Destroy; -end; - -function TSNMPRec.Pass2Key(const Value: AnsiString): AnsiString; -var - key: AnsiString; -begin - case FAuthMode of - AuthMD5: - begin - key := MD5LongHash(Value, 1048576); - Result := MD5(key + FAuthEngineID + key); - end; - AuthSHA1: - begin - key := SHA1LongHash(Value, 1048576); - Result := SHA1(key + FAuthEngineID + key); - end; - else - Result := ''; - end; -end; - -function TSNMPRec.DecryptPDU(const value: AnsiString): AnsiString; -var - des: TSynaDes; - des3: TSyna3Des; - aes: TSynaAes; - s: string; -begin - FPrivKey := ''; - if FFlags <> AuthPriv then - Result := value - else - begin - case FPrivMode of - Priv3DES: - begin - FPrivKey := Pass2Key(FPrivPassword); - FPrivKey := FPrivKey + Pass2Key(FPrivKey); - des3 := TSyna3Des.Create(PadString(FPrivKey, 24, #0)); - try - s := PadString(FPrivKey, 32, #0); - delete(s, 1, 24); - des3.SetIV(xorstring(s, FPrivSalt)); - s := des3.DecryptCBC(value); - Result := s; - finally - des3.free; - end; - end; - PrivAES: - begin - FPrivKey := Pass2Key(FPrivPassword); - aes := TSynaAes.Create(PadString(FPrivKey, 16, #0)); - try - s := CodeLongInt(FAuthEngineBoots) + CodeLongInt(FAuthEngineTime) + FPrivSalt; - aes.SetIV(s); - s := aes.DecryptCFBblock(value); - Result := s; - finally - aes.free; - end; - end; - else //PrivDES as default - begin - FPrivKey := Pass2Key(FPrivPassword); - des := TSynaDes.Create(PadString(FPrivKey, 8, #0)); - try - s := PadString(FPrivKey, 16, #0); - delete(s, 1, 8); - des.SetIV(xorstring(s, FPrivSalt)); - s := des.DecryptCBC(value); - Result := s; - finally - des.free; - end; - end; - end; - end; -end; - -function TSNMPRec.DecodeBuf(Buffer: AnsiString): Boolean; -var - Pos: Integer; - EndPos: Integer; - sm, sv: AnsiString; - Svt: Integer; - s: AnsiString; - Spos: integer; - x: Byte; -begin - Clear; - Result := False; - if Length(Buffer) < 2 then - Exit; - if (Ord(Buffer[1]) and $20) = 0 then - Exit; - Pos := 2; - EndPos := ASNDecLen(Pos, Buffer); - if Length(Buffer) < (EndPos + 2) then - Exit; - Self.FVersion := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - - if FVersion = 3 then - begin - ASNItem(Pos, Buffer, Svt); //header data seq - ASNItem(Pos, Buffer, Svt); //ID - FMaxSize := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - s := ASNItem(Pos, Buffer, Svt); - x := 0; - if s <> '' then - x := Ord(s[1]); - FFlagReportable := (x and 4) > 0; - x := x and 3; - case x of - 1: - FFlags := AuthNoPriv; - 3: - FFlags := AuthPriv; - else - FFlags := NoAuthNoPriv; - end; - - x := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - s := ASNItem(Pos, Buffer, Svt); //SecurityParameters - //if SecurityModel is USM, then try to decode SecurityParameters - if (x = 3) and (s <> '') then - begin - spos := 1; - ASNItem(SPos, s, Svt); - FAuthEngineID := ASNItem(SPos, s, Svt); - FAuthEngineBoots := StrToIntDef(ASNItem(SPos, s, Svt), 0); - FAuthEngineTime := StrToIntDef(ASNItem(SPos, s, Svt), 0); - FAuthEngineTimeStamp := GetTick; - FUserName := ASNItem(SPos, s, Svt); - FAuthKey := ASNItem(SPos, s, Svt); - FPrivSalt := ASNItem(SPos, s, Svt); - end; - //scopedPDU - if FFlags = AuthPriv then - begin - x := Pos; - s := ASNItem(Pos, Buffer, Svt); - if Svt <> ASN1_OCTSTR then - exit; - s := DecryptPDU(s); - //replace encoded content by decoded version and continue - Buffer := copy(Buffer, 1, x - 1); - Buffer := Buffer + s; - Pos := x; - if length(Buffer) < EndPos then - EndPos := length(buffer); - end; - ASNItem(Pos, Buffer, Svt); //skip sequence mark - FContextEngineID := ASNItem(Pos, Buffer, Svt); - FContextName := ASNItem(Pos, Buffer, Svt); - end - else - begin - //old packet - Self.FCommunity := ASNItem(Pos, Buffer, Svt); - end; - - ASNItem(Pos, Buffer, Svt); - Self.FPDUType := Svt; - if Self.FPDUType = PDUTrap then - begin - FOldTrapEnterprise := ASNItem(Pos, Buffer, Svt); - FOldTrapHost := ASNItem(Pos, Buffer, Svt); - FOldTrapGen := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - FOldTrapSpec := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - FOldTrapTimeTicks := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - end - else - begin - Self.FID := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - Self.FErrorStatus := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - Self.FErrorIndex := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0); - end; - ASNItem(Pos, Buffer, Svt); - while Pos < EndPos do - begin - ASNItem(Pos, Buffer, Svt); - Sm := ASNItem(Pos, Buffer, Svt); - Sv := ASNItem(Pos, Buffer, Svt); - if sm <> '' then - Self.MIBAdd(sm, sv, Svt); - end; - Result := True; -end; - -function TSNMPRec.EncryptPDU(const value: AnsiString): AnsiString; -var - des: TSynaDes; - des3: TSyna3Des; - aes: TSynaAes; - s: string; - x: integer; -begin - FPrivKey := ''; - if FFlags <> AuthPriv then - Result := Value - else - begin - case FPrivMode of - Priv3DES: - begin - FPrivKey := Pass2Key(FPrivPassword); - FPrivKey := FPrivKey + Pass2Key(FPrivKey); - des3 := TSyna3Des.Create(PadString(FPrivKey, 24, #0)); - try - s := PadString(FPrivKey, 32, #0); - delete(s, 1, 24); - FPrivSalt := CodeLongInt(FAuthEngineBoots) + CodeLongInt(FPrivSaltCounter); - inc(FPrivSaltCounter); - s := xorstring(s, FPrivSalt); - des3.SetIV(s); - x := length(value) mod 8; - x := 8 - x; - if x = 8 then - x := 0; - s := des3.EncryptCBC(value + Stringofchar(#0, x)); - Result := ASNObject(s, ASN1_OCTSTR); - finally - des3.free; - end; - end; - PrivAES: - begin - FPrivKey := Pass2Key(FPrivPassword); - aes := TSynaAes.Create(PadString(FPrivKey, 16, #0)); - try - FPrivSalt := CodeLongInt(0) + CodeLongInt(FPrivSaltCounter); - inc(FPrivSaltCounter); - s := CodeLongInt(FAuthEngineBoots) + CodeLongInt(FAuthEngineTime) + FPrivSalt; - aes.SetIV(s); - s := aes.EncryptCFBblock(value); - Result := ASNObject(s, ASN1_OCTSTR); - finally - aes.free; - end; - end; - else //PrivDES as default - begin - FPrivKey := Pass2Key(FPrivPassword); - des := TSynaDes.Create(PadString(FPrivKey, 8, #0)); - try - s := PadString(FPrivKey, 16, #0); - delete(s, 1, 8); - FPrivSalt := CodeLongInt(FAuthEngineBoots) + CodeLongInt(FPrivSaltCounter); - inc(FPrivSaltCounter); - s := xorstring(s, FPrivSalt); - des.SetIV(s); - x := length(value) mod 8; - x := 8 - x; - if x = 8 then - x := 0; - s := des.EncryptCBC(value + Stringofchar(#0, x)); - Result := ASNObject(s, ASN1_OCTSTR); - finally - des.free; - end; - end; - end; - end; -end; - -function TSNMPRec.EncodeBuf: AnsiString; -var - s: AnsiString; - SNMPMib: TSNMPMib; - n: Integer; - pdu, head, auth, authbeg: AnsiString; - x: Byte; -begin - pdu := ''; - for n := 0 to FSNMPMibList.Count - 1 do - begin - SNMPMib := TSNMPMib(FSNMPMibList[n]); - case SNMPMib.ValueType of - ASN1_INT: - s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) + - ASNObject(ASNEncInt(StrToIntDef(SNMPMib.Value, 0)), SNMPMib.ValueType); - ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS: - s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) + - ASNObject(ASNEncUInt(StrToIntDef(SNMPMib.Value, 0)), SNMPMib.ValueType); - ASN1_OBJID: - s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) + - ASNObject(MibToID(SNMPMib.Value), SNMPMib.ValueType); - ASN1_IPADDR: - s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) + - ASNObject(IPToID(SNMPMib.Value), SNMPMib.ValueType); - ASN1_NULL: - s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) + - ASNObject('', ASN1_NULL); - else - s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) + - ASNObject(SNMPMib.Value, SNMPMib.ValueType); - end; - pdu := pdu + ASNObject(s, ASN1_SEQ); - end; - pdu := ASNObject(pdu, ASN1_SEQ); - - if Self.FPDUType = PDUTrap then - pdu := ASNObject(MibToID(FOldTrapEnterprise), ASN1_OBJID) + - ASNObject(IPToID(FOldTrapHost), ASN1_IPADDR) + - ASNObject(ASNEncInt(FOldTrapGen), ASN1_INT) + - ASNObject(ASNEncInt(FOldTrapSpec), ASN1_INT) + - ASNObject(ASNEncUInt(FOldTrapTimeTicks), ASN1_TIMETICKS) + - pdu - else - pdu := ASNObject(ASNEncInt(Self.FID), ASN1_INT) + - ASNObject(ASNEncInt(Self.FErrorStatus), ASN1_INT) + - ASNObject(ASNEncInt(Self.FErrorIndex), ASN1_INT) + - pdu; - pdu := ASNObject(pdu, Self.FPDUType); - - if FVersion = 3 then - begin - if FContextEngineID = '' then - FContextEngineID := FAuthEngineID; - //complete PDUv3... - pdu := ASNObject(FContextEngineID, ASN1_OCTSTR) - + ASNObject(FContextName, ASN1_OCTSTR) - + pdu; - pdu := ASNObject(pdu, ASN1_SEQ); - //encrypt PDU if Priv mode is enabled - pdu := EncryptPDU(pdu); - - //prepare flags - case FFlags of - AuthNoPriv: - x := 1; - AuthPriv: - x := 3; - else - x := 0; - end; - if FFlagReportable then - x := x or 4; - head := ASNObject(ASNEncInt(Self.FVersion), ASN1_INT); - s := ASNObject(ASNEncInt(FID), ASN1_INT) - + ASNObject(ASNEncInt(FMaxSize), ASN1_INT) - + ASNObject(AnsiChar(x), ASN1_OCTSTR) - //encode security model USM - + ASNObject(ASNEncInt(3), ASN1_INT); - head := head + ASNObject(s, ASN1_SEQ); - - //compute engine time difference - if FAuthEngineTimeStamp = 0 then //out of sync - x := 0 - else - x := TickDelta(FAuthEngineTimeStamp, GetTick) div 1000; - - authbeg := ASNObject(FAuthEngineID, ASN1_OCTSTR) - + ASNObject(ASNEncInt(FAuthEngineBoots), ASN1_INT) - + ASNObject(ASNEncInt(FAuthEngineTime + x), ASN1_INT) - + ASNObject(FUserName, ASN1_OCTSTR); - - - case FFlags of - AuthNoPriv, - AuthPriv: - begin - s := authbeg + ASNObject(StringOfChar(#0, 12), ASN1_OCTSTR) - + ASNObject(FPrivSalt, ASN1_OCTSTR); - s := ASNObject(s, ASN1_SEQ); - s := head + ASNObject(s, ASN1_OCTSTR); - s := ASNObject(s + pdu, ASN1_SEQ); - //in s is entire packet without auth info... - case FAuthMode of - AuthMD5: - begin - s := HMAC_MD5(s, Pass2Key(FPassword) + StringOfChar(#0, 48)); - //strip to HMAC-MD5-96 - delete(s, 13, 4); - end; - AuthSHA1: - begin - s := HMAC_SHA1(s, Pass2Key(FPassword) + StringOfChar(#0, 44)); - //strip to HMAC-SHA-96 - delete(s, 13, 8); - end; - else - s := ''; - end; - FAuthKey := s; - end; - end; - - auth := authbeg + ASNObject(FAuthKey, ASN1_OCTSTR) - + ASNObject(FPrivSalt, ASN1_OCTSTR); - auth := ASNObject(auth, ASN1_SEQ); - - head := head + ASNObject(auth, ASN1_OCTSTR); - Result := ASNObject(head + pdu, ASN1_SEQ); - end - else - begin - head := ASNObject(ASNEncInt(Self.FVersion), ASN1_INT) + - ASNObject(Self.FCommunity, ASN1_OCTSTR); - Result := ASNObject(head + pdu, ASN1_SEQ); - end; - inc(self.FID); -end; - -procedure TSNMPRec.Clear; -var - i: Integer; -begin - FVersion := SNMP_V1; - FCommunity := 'public'; - FUserName := ''; - FPDUType := 0; - FErrorStatus := 0; - FErrorIndex := 0; - for i := 0 to FSNMPMibList.Count - 1 do - TSNMPMib(FSNMPMibList[i]).Free; - FSNMPMibList.Clear; - FOldTrapEnterprise := ''; - FOldTrapHost := ''; - FOldTrapGen := 0; - FOldTrapSpec := 0; - FOldTrapTimeTicks := 0; - FFlags := NoAuthNoPriv; - FFlagReportable := false; - FContextEngineID := ''; - FContextName := ''; - FAuthEngineID := ''; - FAuthEngineBoots := 0; - FAuthEngineTime := 0; - FAuthEngineTimeStamp := 0; - FAuthKey := ''; - FPrivKey := ''; - FPrivSalt := ''; - FPrivSaltCounter := random(maxint); -end; - -procedure TSNMPRec.MIBAdd(const MIB, Value: AnsiString; ValueType: Integer); -var - SNMPMib: TSNMPMib; -begin - SNMPMib := TSNMPMib.Create; - SNMPMib.OID := MIB; - SNMPMib.Value := Value; - SNMPMib.ValueType := ValueType; - FSNMPMibList.Add(SNMPMib); -end; - -procedure TSNMPRec.MIBDelete(Index: Integer); -begin - if (Index >= 0) and (Index < MIBCount) then - begin - TSNMPMib(FSNMPMibList[Index]).Free; - FSNMPMibList.Delete(Index); - end; -end; - -function TSNMPRec.MIBCount: integer; -begin - Result := FSNMPMibList.Count; -end; - -function TSNMPRec.MIBByIndex(Index: Integer): TSNMPMib; -begin - Result := nil; - if (Index >= 0) and (Index < MIBCount) then - Result := TSNMPMib(FSNMPMibList[Index]); -end; - -function TSNMPRec.MIBGet(const MIB: AnsiString): AnsiString; -var - i: Integer; -begin - Result := ''; - for i := 0 to MIBCount - 1 do - begin - if ((TSNMPMib(FSNMPMibList[i])).OID = MIB) then - begin - Result := (TSNMPMib(FSNMPMibList[i])).Value; - Break; - end; - end; -end; - -{==============================================================================} - -constructor TSNMPSend.Create; -begin - inherited Create; - FQuery := TSNMPRec.Create; - FReply := TSNMPRec.Create; - FQuery.Clear; - FReply.Clear; - FSock := TUDPBlockSocket.Create; - FSock.Owner := self; - FTimeout := 5000; - FTargetPort := cSnmpProtocol; - FHostIP := ''; -end; - -destructor TSNMPSend.Destroy; -begin - FSock.Free; - FReply.Free; - FQuery.Free; - inherited Destroy; -end; - -function TSNMPSend.InternalSendSnmp(const Value: TSNMPRec): Boolean; -begin - FBuffer := Value.EncodeBuf; - FSock.SendString(FBuffer); - Result := FSock.LastError = 0; -end; - -function TSNMPSend.InternalRecvSnmp(const Value: TSNMPRec): Boolean; -begin - Result := False; - FReply.Clear; - FHostIP := cAnyHost; - FBuffer := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - begin - FHostIP := FSock.GetRemoteSinIP; - Result := Value.DecodeBuf(FBuffer); - end; -end; - -function TSNMPSend.InternalSendRequest(const QValue, RValue: TSNMPRec): Boolean; -begin - Result := False; - RValue.AuthMode := QValue.AuthMode; - RValue.Password := QValue.Password; - RValue.PrivMode := QValue.PrivMode; - RValue.PrivPassword := QValue.PrivPassword; - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(FTargetHost, FTargetPort); - if InternalSendSnmp(QValue) then - Result := InternalRecvSnmp(RValue); -end; - -function TSNMPSend.SendRequest: Boolean; -var - sync: TV3Sync; -begin - Result := False; - if FQuery.FVersion = 3 then - begin - sync := GetV3Sync; - FQuery.AuthEngineBoots := Sync.EngineBoots; - FQuery.AuthEngineTime := Sync.EngineTime; - FQuery.AuthEngineTimeStamp := Sync.EngineStamp; - FQuery.AuthEngineID := Sync.EngineID; - end; - Result := InternalSendRequest(FQuery, FReply); -end; - -function TSNMPSend.SendTrap: Boolean; -begin - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(FTargetHost, FTargetPort); - Result := InternalSendSnmp(FQuery); -end; - -function TSNMPSend.RecvTrap: Boolean; -begin - FSock.Bind(FIPInterface, FTargetPort); - Result := InternalRecvSnmp(FReply); -end; - -function TSNMPSend.DoIt: Boolean; -begin - Result := SendRequest; -end; - -function TSNMPSend.GetV3EngineID: AnsiString; -var - DisQuery: TSNMPRec; -begin - Result := ''; - DisQuery := TSNMPRec.Create; - try - DisQuery.Version := 3; - DisQuery.UserName := ''; - DisQuery.FlagReportable := True; - DisQuery.PDUType := PDUGetRequest; - if InternalSendRequest(DisQuery, FReply) then - Result := FReply.FAuthEngineID; - finally - DisQuery.Free; - end; -end; - -function TSNMPSend.GetV3Sync: TV3Sync; -var - SyncQuery: TSNMPRec; -begin - Result.EngineID := GetV3EngineID; - Result.EngineBoots := FReply.AuthEngineBoots; - Result.EngineTime := FReply.AuthEngineTime; - Result.EngineStamp := FReply.AuthEngineTimeStamp; - if Result.EngineTime = 0 then - begin - //still not have sync... - SyncQuery := TSNMPRec.Create; - try - SyncQuery.Version := 3; - SyncQuery.UserName := FQuery.UserName; - SyncQuery.Password := FQuery.Password; - SyncQuery.FlagReportable := True; - SyncQuery.Flags := FQuery.Flags; - SyncQuery.AuthMode := FQuery.AuthMode; - SyncQuery.PrivMode := FQuery.PrivMode; - SyncQuery.PrivPassword := FQuery.PrivPassword; - SyncQuery.PDUType := PDUGetRequest; - SyncQuery.AuthEngineID := FReply.FAuthEngineID; - if InternalSendRequest(SyncQuery, FReply) then - begin - Result.EngineBoots := FReply.AuthEngineBoots; - Result.EngineTime := FReply.AuthEngineTime; - Result.EngineStamp := FReply.AuthEngineTimeStamp; - end; - finally - SyncQuery.Free; - end; - end; -end; - -{==============================================================================} - -function SNMPGet(const OID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean; -var - SNMPSend: TSNMPSend; -begin - SNMPSend := TSNMPSend.Create; - try - SNMPSend.Query.Clear; - SNMPSend.Query.Community := Community; - SNMPSend.Query.PDUType := PDUGetRequest; - SNMPSend.Query.MIBAdd(OID, '', ASN1_NULL); - SNMPSend.TargetHost := SNMPHost; - Result := SNMPSend.SendRequest; - Value := ''; - if Result then - Value := SNMPSend.Reply.MIBGet(OID); - finally - SNMPSend.Free; - end; -end; - -function SNMPSet(const OID, Community, SNMPHost, Value: AnsiString; ValueType: Integer): Boolean; -var - SNMPSend: TSNMPSend; -begin - SNMPSend := TSNMPSend.Create; - try - SNMPSend.Query.Clear; - SNMPSend.Query.Community := Community; - SNMPSend.Query.PDUType := PDUSetRequest; - SNMPSend.Query.MIBAdd(OID, Value, ValueType); - SNMPSend.TargetHost := SNMPHost; - Result := SNMPSend.Sendrequest = True; - finally - SNMPSend.Free; - end; -end; - -function InternalGetNext(const SNMPSend: TSNMPSend; var OID: AnsiString; - const Community: AnsiString; var Value: AnsiString): Boolean; -begin - SNMPSend.Query.Clear; - SNMPSend.Query.ID := SNMPSend.Query.ID + 1; - SNMPSend.Query.Community := Community; - SNMPSend.Query.PDUType := PDUGetNextRequest; - SNMPSend.Query.MIBAdd(OID, '', ASN1_NULL); - Result := SNMPSend.Sendrequest; - Value := ''; - if Result then - if SNMPSend.Reply.SNMPMibList.Count > 0 then - begin - OID := TSNMPMib(SNMPSend.Reply.SNMPMibList[0]).OID; - Value := TSNMPMib(SNMPSend.Reply.SNMPMibList[0]).Value; - end; -end; - -function SNMPGetNext(var OID: AnsiString; const Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean; -var - SNMPSend: TSNMPSend; -begin - SNMPSend := TSNMPSend.Create; - try - SNMPSend.TargetHost := SNMPHost; - Result := InternalGetNext(SNMPSend, OID, Community, Value); - finally - SNMPSend.Free; - end; -end; - -function SNMPGetTable(const BaseOID, Community, SNMPHost: AnsiString; const Value: TStrings): Boolean; -var - OID: AnsiString; - s: AnsiString; - col,row: String; - x: integer; - SNMPSend: TSNMPSend; - RowList: TStringList; -begin - Value.Clear; - SNMPSend := TSNMPSend.Create; - RowList := TStringList.Create; - try - SNMPSend.TargetHost := SNMPHost; - OID := BaseOID; - repeat - Result := InternalGetNext(SNMPSend, OID, Community, s); - if Pos(BaseOID, OID) <> 1 then - break; - row := separateright(oid, baseoid + '.'); - col := fetch(row, '.'); - - if IsBinaryString(s) then - s := StrToHex(s); - x := RowList.indexOf(Row); - if x < 0 then - begin - x := RowList.add(Row); - Value.Add(''); - end; - if (Value[x] <> '') then - Value[x] := Value[x] + ','; - Value[x] := Value[x] + AnsiQuotedStr(s, '"'); - until not result; - finally - SNMPSend.Free; - RowList.Free; - end; -end; - -function SNMPGetTableElement(const BaseOID, RowID, ColID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean; -var - s: AnsiString; -begin - s := BaseOID + '.' + ColID + '.' + RowID; - Result := SnmpGet(s, Community, SNMPHost, Value); -end; - -function SendTrap(const Dest, Source, Enterprise, Community: AnsiString; - Generic, Specific, Seconds: Integer; const MIBName, MIBValue: AnsiString; - MIBtype: Integer): Integer; -var - SNMPSend: TSNMPSend; -begin - SNMPSend := TSNMPSend.Create; - try - SNMPSend.TargetHost := Dest; - SNMPSend.TargetPort := cSnmpTrapProtocol; - SNMPSend.Query.Community := Community; - SNMPSend.Query.Version := SNMP_V1; - SNMPSend.Query.PDUType := PDUTrap; - SNMPSend.Query.OldTrapHost := Source; - SNMPSend.Query.OldTrapEnterprise := Enterprise; - SNMPSend.Query.OldTrapGen := Generic; - SNMPSend.Query.OldTrapSpec := Specific; - SNMPSend.Query.OldTrapTimeTicks := Seconds; - SNMPSend.Query.MIBAdd(MIBName, MIBValue, MIBType); - Result := Ord(SNMPSend.SendTrap); - finally - SNMPSend.Free; - end; -end; - -function RecvTrap(var Dest, Source, Enterprise, Community: AnsiString; - var Generic, Specific, Seconds: Integer; - const MIBName, MIBValue: TStringList): Integer; -var - SNMPSend: TSNMPSend; - i: Integer; -begin - SNMPSend := TSNMPSend.Create; - try - Result := 0; - SNMPSend.TargetPort := cSnmpTrapProtocol; - if SNMPSend.RecvTrap then - begin - Result := 1; - Dest := SNMPSend.HostIP; - Community := SNMPSend.Reply.Community; - Source := SNMPSend.Reply.OldTrapHost; - Enterprise := SNMPSend.Reply.OldTrapEnterprise; - Generic := SNMPSend.Reply.OldTrapGen; - Specific := SNMPSend.Reply.OldTrapSpec; - Seconds := SNMPSend.Reply.OldTrapTimeTicks; - MIBName.Clear; - MIBValue.Clear; - for i := 0 to SNMPSend.Reply.SNMPMibList.Count - 1 do - begin - MIBName.Add(TSNMPMib(SNMPSend.Reply.SNMPMibList[i]).OID); - MIBValue.Add(TSNMPMib(SNMPSend.Reply.SNMPMibList[i]).Value); - end; - end; - finally - SNMPSend.Free; - end; -end; - - -end. - - diff --git a/3rd/synapse/source/sntpsend.pas b/3rd/synapse/source/sntpsend.pas deleted file mode 100644 index 4aa0bbf94..000000000 --- a/3rd/synapse/source/sntpsend.pas +++ /dev/null @@ -1,374 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 003.000.003 | -|==============================================================================| -| Content: SNTP client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Patrick Chevalley | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract( NTP and SNTP client) - -Used RFC: RFC-1305, RFC-2030 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -unit sntpsend; - -interface - -uses - SysUtils, - synsock, blcksock, synautil; - -const - cNtpProtocol = '123'; - -type - - {:@abstract(Record containing the NTP packet.)} - TNtp = packed record - mode: Byte; - stratum: Byte; - poll: Byte; - Precision: Byte; - RootDelay: Longint; - RootDisperson: Longint; - RefID: Longint; - Ref1: Longint; - Ref2: Longint; - Org1: Longint; - Org2: Longint; - Rcv1: Longint; - Rcv2: Longint; - Xmit1: Longint; - Xmit2: Longint; - end; - - {:@abstract(Implementation of NTP and SNTP client protocol), - include time synchronisation. It can send NTP or SNTP time queries, or it - can receive NTP broadcasts too. - - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TSNTPSend = class(TSynaClient) - private - FNTPReply: TNtp; - FNTPTime: TDateTime; - FNTPOffset: double; - FNTPDelay: double; - FMaxSyncDiff: double; - FSyncTime: Boolean; - FSock: TUDPBlockSocket; - FBuffer: AnsiString; - FLi, FVn, Fmode : byte; - function StrToNTP(const Value: AnsiString): TNtp; - function NTPtoStr(const Value: Tntp): AnsiString; - procedure ClearNTP(var Value: Tntp); - public - constructor Create; - destructor Destroy; override; - - {:Decode 128 bit timestamp used in NTP packet to TDateTime type.} - function DecodeTs(Nsec, Nfrac: Longint): TDateTime; - - {:Decode TDateTime type to 128 bit timestamp used in NTP packet.} - procedure EncodeTs(dt: TDateTime; var Nsec, Nfrac: Longint); - - {:Send request to @link(TSynaClient.TargetHost) and wait for reply. If all - is OK, then result is @true and @link(NTPReply) and @link(NTPTime) are - valid.} - function GetSNTP: Boolean; - - {:Send request to @link(TSynaClient.TargetHost) and wait for reply. If all - is OK, then result is @true and @link(NTPReply) and @link(NTPTime) are - valid. Result time is after all needed corrections.} - function GetNTP: Boolean; - - {:Wait for broadcast NTP packet. If all OK, result is @true and - @link(NTPReply) and @link(NTPTime) are valid.} - function GetBroadcastNTP: Boolean; - - {:Holds last received NTP packet.} - property NTPReply: TNtp read FNTPReply; - published - {:Date and time of remote NTP or SNTP server. (UTC time!!!)} - property NTPTime: TDateTime read FNTPTime; - - {:Offset between your computer and remote NTP or SNTP server.} - property NTPOffset: Double read FNTPOffset; - - {:Delay between your computer and remote NTP or SNTP server.} - property NTPDelay: Double read FNTPDelay; - - {:Define allowed maximum difference between your time and remote time for - synchronising time. If difference is bigger, your system time is not - changed!} - property MaxSyncDiff: double read FMaxSyncDiff write FMaxSyncDiff; - - {:If @true, after successfull getting time is local computer clock - synchronised to given time. - For synchronising time you must have proper rights! (Usually Administrator)} - property SyncTime: Boolean read FSyncTime write FSyncTime; - - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TUDPBlockSocket read FSock; - end; - -implementation - -constructor TSNTPSend.Create; -begin - inherited Create; - FSock := TUDPBlockSocket.Create; - FSock.Owner := self; - FTimeout := 5000; - FTargetPort := cNtpProtocol; - FMaxSyncDiff := 3600; - FSyncTime := False; -end; - -destructor TSNTPSend.Destroy; -begin - FSock.Free; - inherited Destroy; -end; - -function TSNTPSend.StrToNTP(const Value: AnsiString): TNtp; -begin - if length(FBuffer) >= SizeOf(Result) then - begin - Result.mode := ord(Value[1]); - Result.stratum := ord(Value[2]); - Result.poll := ord(Value[3]); - Result.Precision := ord(Value[4]); - Result.RootDelay := DecodeLongInt(value, 5); - Result.RootDisperson := DecodeLongInt(value, 9); - Result.RefID := DecodeLongInt(value, 13); - Result.Ref1 := DecodeLongInt(value, 17); - Result.Ref2 := DecodeLongInt(value, 21); - Result.Org1 := DecodeLongInt(value, 25); - Result.Org2 := DecodeLongInt(value, 29); - Result.Rcv1 := DecodeLongInt(value, 33); - Result.Rcv2 := DecodeLongInt(value, 37); - Result.Xmit1 := DecodeLongInt(value, 41); - Result.Xmit2 := DecodeLongInt(value, 45); - end; - -end; - -function TSNTPSend.NTPtoStr(const Value: Tntp): AnsiString; -begin - SetLength(Result, 4); - Result[1] := AnsiChar(Value.mode); - Result[2] := AnsiChar(Value.stratum); - Result[3] := AnsiChar(Value.poll); - Result[4] := AnsiChar(Value.precision); - Result := Result + CodeLongInt(Value.RootDelay); - Result := Result + CodeLongInt(Value.RootDisperson); - Result := Result + CodeLongInt(Value.RefID); - Result := Result + CodeLongInt(Value.Ref1); - Result := Result + CodeLongInt(Value.Ref2); - Result := Result + CodeLongInt(Value.Org1); - Result := Result + CodeLongInt(Value.Org2); - Result := Result + CodeLongInt(Value.Rcv1); - Result := Result + CodeLongInt(Value.Rcv2); - Result := Result + CodeLongInt(Value.Xmit1); - Result := Result + CodeLongInt(Value.Xmit2); -end; - -procedure TSNTPSend.ClearNTP(var Value: Tntp); -begin - Value.mode := 0; - Value.stratum := 0; - Value.poll := 0; - Value.Precision := 0; - Value.RootDelay := 0; - Value.RootDisperson := 0; - Value.RefID := 0; - Value.Ref1 := 0; - Value.Ref2 := 0; - Value.Org1 := 0; - Value.Org2 := 0; - Value.Rcv1 := 0; - Value.Rcv2 := 0; - Value.Xmit1 := 0; - Value.Xmit2 := 0; -end; - -function TSNTPSend.DecodeTs(Nsec, Nfrac: Longint): TDateTime; -const - maxi = 4294967295.0; -var - d, d1: Double; -begin - d := Nsec; - if d < 0 then - d := maxi + d + 1; - d1 := Nfrac; - if d1 < 0 then - d1 := maxi + d1 + 1; - d1 := d1 / maxi; - d1 := Trunc(d1 * 10000) / 10000; - Result := (d + d1) / 86400; - Result := Result + 2; -end; - -procedure TSNTPSend.EncodeTs(dt: TDateTime; var Nsec, Nfrac: Longint); -const - maxi = 4294967295.0; - maxilongint = 2147483647; -var - d, d1: Double; -begin - d := (dt - 2) * 86400; - d1 := frac(d); - if d > maxilongint then - d := d - maxi - 1; - d := trunc(d); - d1 := Trunc(d1 * 10000) / 10000; - d1 := d1 * maxi; - if d1 > maxilongint then - d1 := d1 - maxi - 1; - Nsec:=trunc(d); - Nfrac:=trunc(d1); -end; - -function TSNTPSend.GetBroadcastNTP: Boolean; -var - x: Integer; -begin - Result := False; - FSock.Bind(FIPInterface, FTargetPort); - FBuffer := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - begin - x := Length(FBuffer); - if (FTargetHost = '0.0.0.0') or (FSock.GetRemoteSinIP = FSock.ResolveName(FTargetHost)) then - if x >= SizeOf(NTPReply) then - begin - FNTPReply := StrToNTP(FBuffer); - FNTPTime := DecodeTs(NTPReply.Xmit1, NTPReply.Xmit2); - if FSyncTime and ((abs(FNTPTime - GetUTTime) * 86400) <= FMaxSyncDiff) then - SetUTTime(FNTPTime); - Result := True; - end; - end; -end; - -function TSNTPSend.GetSNTP: Boolean; -var - q: TNtp; - x: Integer; -begin - Result := False; - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(FTargetHost, FTargetPort); - ClearNtp(q); - q.mode := $1B; - FBuffer := NTPtoStr(q); - FSock.SendString(FBuffer); - FBuffer := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - begin - x := Length(FBuffer); - if x >= SizeOf(NTPReply) then - begin - FNTPReply := StrToNTP(FBuffer); - FNTPTime := DecodeTs(NTPReply.Xmit1, NTPReply.Xmit2); - if FSyncTime and ((abs(FNTPTime - GetUTTime) * 86400) <= FMaxSyncDiff) then - SetUTTime(FNTPTime); - Result := True; - end; - end; -end; - -function TSNTPSend.GetNTP: Boolean; -var - q: TNtp; - x: Integer; - t1, t2, t3, t4 : TDateTime; -begin - Result := False; - FSock.CloseSocket; - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(FTargetHost, FTargetPort); - ClearNtp(q); - q.mode := $1B; - t1 := GetUTTime; - EncodeTs(t1, q.org1, q.org2); - FBuffer := NTPtoStr(q); - FSock.SendString(FBuffer); - FBuffer := FSock.RecvPacket(FTimeout); - if FSock.LastError = 0 then - begin - x := Length(FBuffer); - t4 := GetUTTime; - if x >= SizeOf(NTPReply) then - begin - FNTPReply := StrToNTP(FBuffer); - FLi := (NTPReply.mode and $C0) shr 6; - FVn := (NTPReply.mode and $38) shr 3; - Fmode := NTPReply.mode and $07; - if (Fli < 3) and (Fmode = 4) and - (NTPReply.stratum >= 1) and (NTPReply.stratum <= 15) and - (NTPReply.Rcv1 <> 0) and (NTPReply.Xmit1 <> 0) - then begin - t2 := DecodeTs(NTPReply.Rcv1, NTPReply.Rcv2); - t3 := DecodeTs(NTPReply.Xmit1, NTPReply.Xmit2); - FNTPDelay := (T4 - T1) - (T2 - T3); - FNTPTime := t3 + FNTPDelay / 2; - FNTPOffset := (((T2 - T1) + (T3 - T4)) / 2) * 86400; - FNTPDelay := FNTPDelay * 86400; - if FSyncTime and ((abs(FNTPTime - t1) * 86400) <= FMaxSyncDiff) then - SetUTTime(FNTPTime); - Result := True; - end - else result:=false; - end; - end; -end; - -end. diff --git a/3rd/synapse/source/ssdotnet.inc b/3rd/synapse/source/ssdotnet.inc deleted file mode 100644 index 8a54cd8a1..000000000 --- a/3rd/synapse/source/ssdotnet.inc +++ /dev/null @@ -1,1099 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.000.002 | -|==============================================================================| -| Content: Socket Independent Platform Layer - .NET definition include | -|==============================================================================| -| Copyright (c)2004, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2004. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$IFDEF CIL} - -interface - -uses - SyncObjs, SysUtils, Classes, - System.Net, - System.Net.Sockets; - -const - DLLStackName = ''; - WinsockLevel = $0202; - -function InitSocketInterface(stack: string): Boolean; -function DestroySocketInterface: Boolean; - -type - u_char = Char; - u_short = Word; - u_int = Integer; - u_long = Longint; - pu_long = ^u_long; - pu_short = ^u_short; - PSockAddr = IPEndPoint; - DWORD = integer; - ULong = cardinal; - TMemory = Array of byte; - TLinger = LingerOption; - TSocket = socket; - TAddrFamily = AddressFamily; - -const - WSADESCRIPTION_LEN = 256; - WSASYS_STATUS_LEN = 128; -type - PWSAData = ^TWSAData; - TWSAData = packed record - wVersion: Word; - wHighVersion: Word; - szDescription: array[0..WSADESCRIPTION_LEN] of Char; - szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; - iMaxSockets: Word; - iMaxUdpDg: Word; -// lpVendorInfo: PChar; - end; - -const - MSG_NOSIGNAL = 0; - INVALID_SOCKET = nil; - AF_UNSPEC = AddressFamily.Unspecified; - AF_INET = AddressFamily.InterNetwork; - AF_INET6 = AddressFamily.InterNetworkV6; - SOCKET_ERROR = integer(-1); - - FIONREAD = integer($4004667f); - FIONBIO = integer($8004667e); - FIOASYNC = integer($8004667d); - - SOMAXCONN = integer($7fffffff); - - IPPROTO_IP = ProtocolType.IP; - IPPROTO_ICMP = ProtocolType.Icmp; - IPPROTO_IGMP = ProtocolType.Igmp; - IPPROTO_TCP = ProtocolType.Tcp; - IPPROTO_UDP = ProtocolType.Udp; - IPPROTO_RAW = ProtocolType.Raw; - IPPROTO_IPV6 = ProtocolType.IPV6; -// - IPPROTO_ICMPV6 = ProtocolType.Icmp; //?? - - SOCK_STREAM = SocketType.Stream; - SOCK_DGRAM = SocketType.Dgram; - SOCK_RAW = SocketType.Raw; - SOCK_RDM = SocketType.Rdm; - SOCK_SEQPACKET = SocketType.Seqpacket; - - SOL_SOCKET = SocketOptionLevel.Socket; - SOL_IP = SocketOptionLevel.Ip; - - - IP_OPTIONS = SocketOptionName.IPOptions; - IP_HDRINCL = SocketOptionName.HeaderIncluded; - IP_TOS = SocketOptionName.TypeOfService; { set/get IP Type Of Service } - IP_TTL = SocketOptionName.IpTimeToLive; { set/get IP Time To Live } - IP_MULTICAST_IF = SocketOptionName.MulticastInterface; { set/get IP multicast interface } - IP_MULTICAST_TTL = SocketOptionName.MulticastTimeToLive; { set/get IP multicast timetolive } - IP_MULTICAST_LOOP = SocketOptionName.MulticastLoopback; { set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = SocketOptionName.AddMembership; { add an IP group membership } - IP_DROP_MEMBERSHIP = SocketOptionName.DropMembership; { drop an IP group membership } - IP_DONTFRAGMENT = SocketOptionName.DontFragment; { set/get IP Don't Fragment flag } - - IPV6_UNICAST_HOPS = 8; // TTL - IPV6_MULTICAST_IF = 9; // set/get IP multicast i/f - IPV6_MULTICAST_HOPS = 10; // set/get IP multicast ttl - IPV6_MULTICAST_LOOP = 11; // set/get IP multicast loopback - IPV6_JOIN_GROUP = 12; // add an IP group membership - IPV6_LEAVE_GROUP = 13; // drop an IP group membership - - SO_DEBUG = SocketOptionName.Debug; { turn on debugging info recording } - SO_ACCEPTCONN = SocketOptionName.AcceptConnection; { socket has had listen() } - SO_REUSEADDR = SocketOptionName.ReuseAddress; { allow local address reuse } - SO_KEEPALIVE = SocketOptionName.KeepAlive; { keep connections alive } - SO_DONTROUTE = SocketOptionName.DontRoute; { just use interface addresses } - SO_BROADCAST = SocketOptionName.Broadcast; { permit sending of broadcast msgs } - SO_USELOOPBACK = SocketOptionName.UseLoopback; { bypass hardware when possible } - SO_LINGER = SocketOptionName.Linger; { linger on close if data present } - SO_OOBINLINE = SocketOptionName.OutOfBandInline; { leave received OOB data in line } - SO_DONTLINGER = SocketOptionName.DontLinger; -{ Additional options. } - SO_SNDBUF = SocketOptionName.SendBuffer; { send buffer size } - SO_RCVBUF = SocketOptionName.ReceiveBuffer; { receive buffer size } - SO_SNDLOWAT = SocketOptionName.SendLowWater; { send low-water mark } - SO_RCVLOWAT = SocketOptionName.ReceiveLowWater; { receive low-water mark } - SO_SNDTIMEO = SocketOptionName.SendTimeout; { send timeout } - SO_RCVTIMEO = SocketOptionName.ReceiveTimeout; { receive timeout } - SO_ERROR = SocketOptionName.Error; { get error status and clear } - SO_TYPE = SocketOptionName.Type; { get socket type } - -{ WinSock 2 extension -- new options } -// SO_GROUP_ID = $2001; { ID of a socket group} -// SO_GROUP_PRIORITY = $2002; { the relative priority within a group} -// SO_MAX_MSG_SIZE = $2003; { maximum message size } -// SO_PROTOCOL_INFOA = $2004; { WSAPROTOCOL_INFOA structure } -// SO_PROTOCOL_INFOW = $2005; { WSAPROTOCOL_INFOW structure } -// SO_PROTOCOL_INFO = SO_PROTOCOL_INFOA; -// PVD_CONFIG = $3001; {configuration info for service provider } -{ Option for opening sockets for synchronous access. } -// SO_OPENTYPE = $7008; -// SO_SYNCHRONOUS_ALERT = $10; -// SO_SYNCHRONOUS_NONALERT = $20; -{ Other NT-specific options. } -// SO_MAXDG = $7009; -// SO_MAXPATHDG = $700A; -// SO_UPDATE_ACCEPT_CONTEXT = $700B; -// SO_CONNECT_TIME = $700C; - - - { All Windows Sockets error constants are biased by WSABASEERR from the "normal" } - WSABASEERR = 10000; - -{ Windows Sockets definitions of regular Microsoft C error constants } - - WSAEINTR = (WSABASEERR+4); - WSAEBADF = (WSABASEERR+9); - WSAEACCES = (WSABASEERR+13); - WSAEFAULT = (WSABASEERR+14); - WSAEINVAL = (WSABASEERR+22); - WSAEMFILE = (WSABASEERR+24); - -{ Windows Sockets definitions of regular Berkeley error constants } - - WSAEWOULDBLOCK = (WSABASEERR+35); - WSAEINPROGRESS = (WSABASEERR+36); - WSAEALREADY = (WSABASEERR+37); - WSAENOTSOCK = (WSABASEERR+38); - WSAEDESTADDRREQ = (WSABASEERR+39); - WSAEMSGSIZE = (WSABASEERR+40); - WSAEPROTOTYPE = (WSABASEERR+41); - WSAENOPROTOOPT = (WSABASEERR+42); - WSAEPROTONOSUPPORT = (WSABASEERR+43); - WSAESOCKTNOSUPPORT = (WSABASEERR+44); - WSAEOPNOTSUPP = (WSABASEERR+45); - WSAEPFNOSUPPORT = (WSABASEERR+46); - WSAEAFNOSUPPORT = (WSABASEERR+47); - WSAEADDRINUSE = (WSABASEERR+48); - WSAEADDRNOTAVAIL = (WSABASEERR+49); - WSAENETDOWN = (WSABASEERR+50); - WSAENETUNREACH = (WSABASEERR+51); - WSAENETRESET = (WSABASEERR+52); - WSAECONNABORTED = (WSABASEERR+53); - WSAECONNRESET = (WSABASEERR+54); - WSAENOBUFS = (WSABASEERR+55); - WSAEISCONN = (WSABASEERR+56); - WSAENOTCONN = (WSABASEERR+57); - WSAESHUTDOWN = (WSABASEERR+58); - WSAETOOMANYREFS = (WSABASEERR+59); - WSAETIMEDOUT = (WSABASEERR+60); - WSAECONNREFUSED = (WSABASEERR+61); - WSAELOOP = (WSABASEERR+62); - WSAENAMETOOLONG = (WSABASEERR+63); - WSAEHOSTDOWN = (WSABASEERR+64); - WSAEHOSTUNREACH = (WSABASEERR+65); - WSAENOTEMPTY = (WSABASEERR+66); - WSAEPROCLIM = (WSABASEERR+67); - WSAEUSERS = (WSABASEERR+68); - WSAEDQUOT = (WSABASEERR+69); - WSAESTALE = (WSABASEERR+70); - WSAEREMOTE = (WSABASEERR+71); - -{ Extended Windows Sockets error constant definitions } - - WSASYSNOTREADY = (WSABASEERR+91); - WSAVERNOTSUPPORTED = (WSABASEERR+92); - WSANOTINITIALISED = (WSABASEERR+93); - WSAEDISCON = (WSABASEERR+101); - WSAENOMORE = (WSABASEERR+102); - WSAECANCELLED = (WSABASEERR+103); - WSAEEINVALIDPROCTABLE = (WSABASEERR+104); - WSAEINVALIDPROVIDER = (WSABASEERR+105); - WSAEPROVIDERFAILEDINIT = (WSABASEERR+106); - WSASYSCALLFAILURE = (WSABASEERR+107); - WSASERVICE_NOT_FOUND = (WSABASEERR+108); - WSATYPE_NOT_FOUND = (WSABASEERR+109); - WSA_E_NO_MORE = (WSABASEERR+110); - WSA_E_CANCELLED = (WSABASEERR+111); - WSAEREFUSED = (WSABASEERR+112); - -{ Error return codes from gethostbyname() and gethostbyaddr() - (when using the resolver). Note that these errors are - retrieved via WSAGetLastError() and must therefore follow - the rules for avoiding clashes with error numbers from - specific implementations or language run-time systems. - For this reason the codes are based at WSABASEERR+1001. - Note also that [WSA]NO_ADDRESS is defined only for - compatibility purposes. } - -{ Authoritative Answer: Host not found } - WSAHOST_NOT_FOUND = (WSABASEERR+1001); - HOST_NOT_FOUND = WSAHOST_NOT_FOUND; -{ Non-Authoritative: Host not found, or SERVERFAIL } - WSATRY_AGAIN = (WSABASEERR+1002); - TRY_AGAIN = WSATRY_AGAIN; -{ Non recoverable errors, FORMERR, REFUSED, NOTIMP } - WSANO_RECOVERY = (WSABASEERR+1003); - NO_RECOVERY = WSANO_RECOVERY; -{ Valid name, no data record of requested type } - WSANO_DATA = (WSABASEERR+1004); - NO_DATA = WSANO_DATA; -{ no address, look for MX record } - WSANO_ADDRESS = WSANO_DATA; - NO_ADDRESS = WSANO_ADDRESS; - - EWOULDBLOCK = WSAEWOULDBLOCK; - EINPROGRESS = WSAEINPROGRESS; - EALREADY = WSAEALREADY; - ENOTSOCK = WSAENOTSOCK; - EDESTADDRREQ = WSAEDESTADDRREQ; - EMSGSIZE = WSAEMSGSIZE; - EPROTOTYPE = WSAEPROTOTYPE; - ENOPROTOOPT = WSAENOPROTOOPT; - EPROTONOSUPPORT = WSAEPROTONOSUPPORT; - ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT; - EOPNOTSUPP = WSAEOPNOTSUPP; - EPFNOSUPPORT = WSAEPFNOSUPPORT; - EAFNOSUPPORT = WSAEAFNOSUPPORT; - EADDRINUSE = WSAEADDRINUSE; - EADDRNOTAVAIL = WSAEADDRNOTAVAIL; - ENETDOWN = WSAENETDOWN; - ENETUNREACH = WSAENETUNREACH; - ENETRESET = WSAENETRESET; - ECONNABORTED = WSAECONNABORTED; - ECONNRESET = WSAECONNRESET; - ENOBUFS = WSAENOBUFS; - EISCONN = WSAEISCONN; - ENOTCONN = WSAENOTCONN; - ESHUTDOWN = WSAESHUTDOWN; - ETOOMANYREFS = WSAETOOMANYREFS; - ETIMEDOUT = WSAETIMEDOUT; - ECONNREFUSED = WSAECONNREFUSED; - ELOOP = WSAELOOP; - ENAMETOOLONG = WSAENAMETOOLONG; - EHOSTDOWN = WSAEHOSTDOWN; - EHOSTUNREACH = WSAEHOSTUNREACH; - ENOTEMPTY = WSAENOTEMPTY; - EPROCLIM = WSAEPROCLIM; - EUSERS = WSAEUSERS; - EDQUOT = WSAEDQUOT; - ESTALE = WSAESTALE; - EREMOTE = WSAEREMOTE; - - -type - TVarSin = IPEndpoint; - -{ function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; - function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; - procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); - procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -var - in6addr_any, in6addr_loopback : TInAddr6; -} - -{procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -procedure FD_ZERO(var FDSet: TFDSet); -} -{=============================================================================} - - function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; - function WSACleanup: Integer; - function WSAGetLastError: Integer; - function WSAGetLastErrorDesc: String; - function GetHostName: string; - function Shutdown(s: TSocket; how: Integer): Integer; -// function SetSockOpt(s: TSocket; level, optname: Integer; optval: PChar; -// optlen: Integer): Integer; - function SetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; - optlen: Integer): Integer; - function SetSockOptObj(s: TSocket; level, optname: Integer; optval: TObject): Integer; - function GetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; - var optlen: Integer): Integer; -// function SendTo(s: TSocket; const Buf; len, flags: Integer; addrto: PSockAddr; -// tolen: Integer): Integer; -/// function SendTo(s: TSocket; const Buf; len, flags: Integer; addrto: TVarSin): Integer; -/// function Send(s: TSocket; const Buf; len, flags: Integer): Integer; -/// function Recv(s: TSocket; var Buf; len, flags: Integer): Integer; -// function RecvFrom(s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; -// var fromlen: Integer): Integer; -/// function RecvFrom(s: TSocket; var Buf; len, flags: Integer; from: TVarSin): Integer; -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; - function ntohs(netshort: u_short): u_short; - function ntohl(netlong: u_long): u_long; - function Listen(s: TSocket; backlog: Integer): Integer; - function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; - function htons(hostshort: u_short): u_short; - function htonl(hostlong: u_long): u_long; -// function GetSockName(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - function GetSockName(s: TSocket; var name: TVarSin): Integer; -// function GetPeerName(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - function GetPeerName(s: TSocket; var name: TVarSin): Integer; -// function Connect(s: TSocket; name: PSockAddr; namelen: Integer): Integer; - function Connect(s: TSocket; const name: TVarSin): Integer; - function CloseSocket(s: TSocket): Integer; -// function Bind(s: TSocket; addr: PSockAddr; namelen: Integer): Integer; - function Bind(s: TSocket; const addr: TVarSin): Integer; -// function Accept(s: TSocket; addr: PSockAddr; var addrlen: Integer): TSocket; - function Accept(s: TSocket; var addr: TVarSin): TSocket; - function Socket(af, Struc, Protocol: Integer): TSocket; -// Select = function(nfds: Integer; readfds, writefds, exceptfds: PFDSet; -// timeout: PTimeVal): Longint; -// {$IFDEF LINUX}cdecl{$ELSE}stdcall{$ENDIF}; - -// TWSAIoctl = function (s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; -// cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD; -// lpcbBytesReturned: PDWORD; lpOverlapped: Pointer; -// lpCompletionRoutine: pointer): u_int; -// stdcall; - - function GetPortService(value: string): integer; - -function IsNewApi(Family: TAddrFamily): Boolean; -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family: TAddrFamily; SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -function GetSinIP(Sin: TVarSin): string; -function GetSinPort(Sin: TVarSin): Integer; -procedure ResolveNameToIP(Name: string; Family: TAddrFamily; SockProtocol, SockType: integer; const IPList: TStrings); -function ResolveIPToName(IP: string; Family: TAddrFamily; SockProtocol, SockType: integer): string; -function ResolvePort(Port: string; Family: TAddrFamily; SockProtocol, SockType: integer): Word; - -var - SynSockCS: SyncObjs.TCriticalSection; - SockEnhancedApi: Boolean; - SockWship6Api: Boolean; - -{==============================================================================} -implementation - -threadvar - WSALastError: integer; - WSALastErrorDesc: string; - -var - services: Array [0..139, 0..1] of string = - ( - ('echo', '7'), - ('discard', '9'), - ('sink', '9'), - ('null', '9'), - ('systat', '11'), - ('users', '11'), - ('daytime', '13'), - ('qotd', '17'), - ('quote', '17'), - ('chargen', '19'), - ('ttytst', '19'), - ('source', '19'), - ('ftp-data', '20'), - ('ftp', '21'), - ('telnet', '23'), - ('smtp', '25'), - ('mail', '25'), - ('time', '37'), - ('timeserver', '37'), - ('rlp', '39'), - ('nameserver', '42'), - ('name', '42'), - ('nickname', '43'), - ('whois', '43'), - ('domain', '53'), - ('bootps', '67'), - ('dhcps', '67'), - ('bootpc', '68'), - ('dhcpc', '68'), - ('tftp', '69'), - ('gopher', '70'), - ('finger', '79'), - ('http', '80'), - ('www', '80'), - ('www-http', '80'), - ('kerberos', '88'), - ('hostname', '101'), - ('hostnames', '101'), - ('iso-tsap', '102'), - ('rtelnet', '107'), - ('pop2', '109'), - ('postoffice', '109'), - ('pop3', '110'), - ('sunrpc', '111'), - ('rpcbind', '111'), - ('portmap', '111'), - ('auth', '113'), - ('ident', '113'), - ('tap', '113'), - ('uucp-path', '117'), - ('nntp', '119'), - ('usenet', '119'), - ('ntp', '123'), - ('epmap', '135'), - ('loc-srv', '135'), - ('netbios-ns', '137'), - ('nbname', '137'), - ('netbios-dgm', '138'), - ('nbdatagram', '138'), - ('netbios-ssn', '139'), - ('nbsession', '139'), - ('imap', '143'), - ('imap4', '143'), - ('pcmail-srv', '158'), - ('snmp', '161'), - ('snmptrap', '162'), - ('snmp-trap', '162'), - ('print-srv', '170'), - ('bgp', '179'), - ('irc', '194'), - ('ipx', '213'), - ('ldap', '389'), - ('https', '443'), - ('mcom', '443'), - ('microsoft-ds', '445'), - ('kpasswd', '464'), - ('isakmp', '500'), - ('ike', '500'), - ('exec', '512'), - ('biff', '512'), - ('comsat', '512'), - ('login', '513'), - ('who', '513'), - ('whod', '513'), - ('cmd', '514'), - ('shell', '514'), - ('syslog', '514'), - ('printer', '515'), - ('spooler', '515'), - ('talk', '517'), - ('ntalk', '517'), - ('efs', '520'), - ('router', '520'), - ('route', '520'), - ('routed', '520'), - ('timed', '525'), - ('timeserver', '525'), - ('tempo', '526'), - ('newdate', '526'), - ('courier', '530'), - ('rpc', '530'), - ('conference', '531'), - ('chat', '531'), - ('netnews', '532'), - ('readnews', '532'), - ('netwall', '533'), - ('uucp', '540'), - ('uucpd', '540'), - ('klogin', '543'), - ('kshell', '544'), - ('krcmd', '544'), - ('new-rwho', '550'), - ('new-who', '550'), - ('remotefs', '556'), - ('rfs', '556'), - ('rfs_server', '556'), - ('rmonitor', '560'), - ('rmonitord', '560'), - ('monitor', '561'), - ('ldaps', '636'), - ('sldap', '636'), - ('doom', '666'), - ('kerberos-adm', '749'), - ('kerberos-iv', '750'), - ('kpop', '1109'), - ('phone', '1167'), - ('ms-sql-s', '1433'), - ('ms-sql-m', '1434'), - ('wins', '1512'), - ('ingreslock', '1524'), - ('ingres', '1524'), - ('l2tp', '1701'), - ('pptp', '1723'), - ('radius', '1812'), - ('radacct', '1813'), - ('nfsd', '2049'), - ('nfs', '2049'), - ('knetd', '2053'), - ('gds_db', '3050'), - ('man', '9535') - ); - -{function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; -begin - Result := ((a^.s_un_dw.s_dw1 = 0) and (a^.s_un_dw.s_dw2 = 0) and - (a^.s_un_dw.s_dw3 = 0) and (a^.s_un_dw.s_dw4 = 0)); -end; - -function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; -begin - Result := ((a^.s_un_dw.s_dw1 = 0) and (a^.s_un_dw.s_dw2 = 0) and - (a^.s_un_dw.s_dw3 = 0) and - (a^.s_un_b.s_b13 = char(0)) and (a^.s_un_b.s_b14 = char(0)) and - (a^.s_un_b.s_b15 = char(0)) and (a^.s_un_b.s_b16 = char(1))); -end; - -function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.s_un_b.s_b1 = u_char($FE)) and (a^.s_un_b.s_b2 = u_char($80))); -end; - -function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.s_un_b.s_b1 = u_char($FE)) and (a^.s_un_b.s_b2 = u_char($C0))); -end; - -function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; -begin - Result := (a^.s_un_b.s_b1 = char($FF)); -end; - -function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; -begin - Result := (CompareMem( a, b, sizeof(TInAddr6))); -end; - -procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); -end; - -procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); - a^.s_un_b.s_b16 := char(1); -end; -} - -{=============================================================================} - -procedure NullErr; -begin - WSALastError := 0; - WSALastErrorDesc := ''; -end; - -procedure GetErrCode(E: System.Exception); -var - SE: System.Net.Sockets.SocketException; -begin - if E is System.Net.Sockets.SocketException then - begin - SE := E as System.Net.Sockets.SocketException; - WSALastError := SE.ErrorCode; - WSALastErrorDesc := SE.Message; - end -end; - -function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; -begin - NullErr; - with WSData do - begin - wVersion := wVersionRequired; - wHighVersion := $202; - szDescription := 'Synsock - Synapse Platform Independent Socket Layer'; - szSystemStatus := 'Running on .NET'; - iMaxSockets := 32768; - iMaxUdpDg := 8192; - end; - Result := 0; -end; - -function WSACleanup: Integer; -begin - NullErr; - Result := 0; -end; - -function WSAGetLastError: Integer; -begin - Result := WSALastError; -end; - -function WSAGetLastErrorDesc: String; -begin - Result := WSALastErrorDesc; -end; - -function GetHostName: string; -begin - Result := System.Net.DNS.GetHostName; -end; - -function Shutdown(s: TSocket; how: Integer): Integer; -begin - Result := 0; - NullErr; - try - s.ShutDown(SocketShutdown(how)); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function SetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; - optlen: Integer): Integer; -begin - Result := 0; - NullErr; - try - s.SetSocketOption(SocketOptionLevel(level), SocketOptionName(optname), optval); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function SetSockOptObj(s: TSocket; level, optname: Integer; optval: TObject): Integer; -begin - Result := 0; - NullErr; - try - s.SetSocketOption(SocketOptionLevel(level), SocketOptionName(optname), optval); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function GetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; - var optlen: Integer): Integer; -begin - Result := 0; - NullErr; - try - s.GetSocketOption(SocketOptionLevel(level), SocketOptionName(optname), optval); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -//function SendTo(s: TSocket; const Buf; len, flags: Integer; addrto: TVarSin): Integer; -begin - NullErr; - try - result := s.SendTo(Buf, len, SocketFlags(flags), addrto); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -//function Send(s: TSocket; const Buf; len, flags: Integer): Integer; -begin - NullErr; - try - result := s.Send(Buf, len, SocketFlags(flags)); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -//function Recv(s: TSocket; var Buf; len, flags: Integer): Integer; -begin - NullErr; - try - result := s.Receive(Buf, len, SocketFlags(flags)); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -//function RecvFrom(s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; -// var fromlen: Integer): Integer; -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -//function RecvFrom(s: TSocket; var Buf; len, flags: Integer; from: TVarSin): Integer; -var - EP: EndPoint; -begin - NullErr; - try - EP := from; - result := s.ReceiveFrom(Buf, len, SocketFlags(flags), EndPoint(EP)); - from := EP as IPEndPoint; - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function ntohs(netshort: u_short): u_short; -begin - Result := IPAddress.NetworkToHostOrder(NetShort); -end; - -function ntohl(netlong: u_long): u_long; -begin - Result := IPAddress.NetworkToHostOrder(NetLong); -end; - -function Listen(s: TSocket; backlog: Integer): Integer; -begin - Result := 0; - NullErr; - try - s.Listen(backlog); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; -var - inv, outv: TMemory; -begin - Result := 0; - NullErr; - try - if cmd = DWORD(FIONBIO) then - s.Blocking := arg = 0 - else - begin - inv := BitConverter.GetBytes(arg); - outv := BitConverter.GetBytes(integer(0)); - s.IOControl(cmd, inv, outv); - arg := BitConverter.ToInt32(outv, 0); - end; - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function htons(hostshort: u_short): u_short; -begin - Result := IPAddress.HostToNetworkOrder(Hostshort); -end; - -function htonl(hostlong: u_long): u_long; -begin - Result := IPAddress.HostToNetworkOrder(HostLong); -end; - -//function GetSockName(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; -function GetSockName(s: TSocket; var name: TVarSin): Integer; -begin - Result := 0; - NullErr; - try - Name := s.localEndPoint as IPEndpoint; - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -//function GetPeerName(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -begin - Result := 0; - NullErr; - try - Name := s.RemoteEndPoint as IPEndpoint; - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -//function Connect(s: TSocket; name: PSockAddr; namelen: Integer): Integer; -function Connect(s: TSocket; const name: TVarSin): Integer; -begin - Result := 0; - NullErr; - try - s.Connect(name); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -function CloseSocket(s: TSocket): Integer; -begin - Result := 0; - NullErr; - try - s.Close; - except - on e: System.Net.Sockets.SocketException do - begin - Result := integer(SOCKET_ERROR); - end; - end; -end; - -//function Bind(s: TSocket; addr: PSockAddr; namelen: Integer): Integer; -function Bind(s: TSocket; const addr: TVarSin): Integer; -begin - Result := 0; - NullErr; - try - s.Bind(addr); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := integer(SOCKET_ERROR); - end; - end; -end; - -//function Accept(s: TSocket; addr: PSockAddr; var addrlen: Integer): TSocket; -function Accept(s: TSocket; var addr: TVarSin): TSocket; -begin - NullErr; - try - result := s.Accept(); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := nil; - end; - end; -end; - -function Socket(af, Struc, Protocol: Integer): TSocket; -begin - NullErr; - try - result := TSocket.Create(AddressFamily(af), SocketType(Struc), ProtocolType(Protocol)); - except - on e: System.Net.Sockets.SocketException do - begin - GetErrCode(e); - Result := nil; - end; - end; -end; - -{=============================================================================} -function GetPortService(value: string): integer; -var - n: integer; -begin - Result := 0; - value := Lowercase(value); - for n := 0 to High(Services) do - if services[n, 0] = value then - begin - Result := strtointdef(services[n, 1], 0); - break; - end; - if Result = 0 then - Result := StrToIntDef(value, 0); -end; - -{=============================================================================} -function IsNewApi(Family: TAddrFamily): Boolean; -begin - Result := true; -end; - -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family: TAddrFamily; SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -var - IPs: array of IPAddress; - n: integer; - ip4, ip6: string; - sip: string; -begin - sip := ''; - ip4 := ''; - ip6 := ''; - IPs := Dns.Resolve(IP).AddressList; - for n :=low(IPs) to high(IPs) do begin - if (ip4 = '') and (IPs[n].AddressFamily = AF_INET) then - ip4 := IPs[n].toString; - if (ip6 = '') and (IPs[n].AddressFamily = AF_INET6) then - ip6 := IPs[n].toString; - if (ip4 <> '') and (ip6 <> '') then - break; - end; - case Family of - AF_UNSPEC: - begin - if (ip4 <> '') and (ip6 <> '') then - begin - if PreferIP4 then - sip := ip4 - else - Sip := ip6; - end - else - begin - sip := ip4; - if (ip6 <> '') then - sip := ip6; - end; - end; - AF_INET: - sip := ip4; - AF_INET6: - sip := ip6; - end; - sin := TVarSin.Create(IPAddress.Parse(sip), GetPortService(Port)); -end; - -function GetSinIP(Sin: TVarSin): string; -begin - Result := Sin.Address.ToString; -end; - -function GetSinPort(Sin: TVarSin): Integer; -begin - Result := Sin.Port; -end; - -procedure ResolveNameToIP(Name: string; Family: TAddrFamily; SockProtocol, SockType: integer; const IPList: TStrings); -var - IPs :array of IPAddress; - n: integer; -begin - IPList.Clear; - IPs := Dns.Resolve(Name).AddressList; - for n := low(IPs) to high(IPs) do - begin - if not(((Family = AF_INET6) and (IPs[n].AddressFamily = AF_INET)) - or ((Family = AF_INET) and (IPs[n].AddressFamily = AF_INET6))) then - begin - IPList.Add(IPs[n].toString); - end; - end; -end; - -function ResolvePort(Port: string; Family: TAddrFamily; SockProtocol, SockType: integer): Word; -var - n: integer; -begin - Result := StrToIntDef(port, 0); - if Result = 0 then - begin - port := Lowercase(port); - for n := 0 to High(Services) do - if services[n, 0] = port then - begin - Result := strtointdef(services[n, 1], 0); - break; - end; - end; -end; - -function ResolveIPToName(IP: string; Family: TAddrFamily; SockProtocol, SockType: integer): string; -begin - Result := Dns.GetHostByAddress(IP).HostName; -end; - - -{=============================================================================} -function InitSocketInterface(stack: string): Boolean; -begin - Result := True; -end; - -function DestroySocketInterface: Boolean; -begin - NullErr; - Result := True; -end; - -initialization -begin - SynSockCS := SyncObjs.TCriticalSection.Create; -// SET_IN6_IF_ADDR_ANY (@in6addr_any); -// SET_LOOPBACK_ADDR6 (@in6addr_loopback); -end; - -finalization -begin - NullErr; - SynSockCS.Free; -end; - -{$ENDIF} diff --git a/3rd/synapse/source/ssfpc.inc b/3rd/synapse/source/ssfpc.inc deleted file mode 100644 index 34f7af82f..000000000 --- a/3rd/synapse/source/ssfpc.inc +++ /dev/null @@ -1,925 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.005 | -|==============================================================================| -| Content: Socket Independent Platform Layer - FreePascal definition include | -|==============================================================================| -| Copyright (c)2006-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2006-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$IFDEF FPC} -{For FreePascal 2.x.x} - -//{$DEFINE FORCEOLDAPI} -{Note about define FORCEOLDAPI: -If you activate this compiler directive, then is allways used old socket API -for name resolution. If you leave this directive inactive, then the new API -is used, when running system allows it. - -For IPv6 support you must have new API! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$ifdef FreeBSD} -{$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr -{$endif} -{$ifdef darwin} -{$DEFINE SOCK_HAS_SINLEN} // BSD definition of scoketaddr -{$endif} - -interface - -uses - SyncObjs, SysUtils, Classes, - synafpc, BaseUnix, Unix, termio, sockets, netdb; - -function InitSocketInterface(stack: string): Boolean; -function DestroySocketInterface: Boolean; - -const - DLLStackName = ''; - WinsockLevel = $0202; - - cLocalHost = '127.0.0.1'; - cAnyHost = '0.0.0.0'; - c6AnyHost = '::0'; - c6Localhost = '::1'; - cLocalHostStr = 'localhost'; - -type - TSocket = longint; - TAddrFamily = integer; - - TMemory = pointer; - - -type - TFDSet = Baseunix.TFDSet; - PFDSet = ^TFDSet; - Ptimeval = Baseunix.ptimeval; - Ttimeval = Baseunix.ttimeval; - -const - FIONREAD = termio.FIONREAD; - FIONBIO = termio.FIONBIO; - FIOASYNC = termio.FIOASYNC; - -const - IPPROTO_IP = 0; { Dummy } - IPPROTO_ICMP = 1; { Internet Control Message Protocol } - IPPROTO_IGMP = 2; { Internet Group Management Protocol} - IPPROTO_TCP = 6; { TCP } - IPPROTO_UDP = 17; { User Datagram Protocol } - IPPROTO_IPV6 = 41; - IPPROTO_ICMPV6 = 58; - IPPROTO_RM = 113; - - IPPROTO_RAW = 255; - IPPROTO_MAX = 256; - -type - PInAddr = ^TInAddr; - TInAddr = sockets.in_addr; - - PSockAddrIn = ^TSockAddrIn; - TSockAddrIn = sockets.TInetSockAddr; - - - TIP_mreq = record - imr_multiaddr: TInAddr; // IP multicast address of group - imr_interface: TInAddr; // local IP address of interface - end; - - - PInAddr6 = ^TInAddr6; - TInAddr6 = sockets.Tin6_addr; - - PSockAddrIn6 = ^TSockAddrIn6; - TSockAddrIn6 = sockets.TInetSockAddr6; - - - TIPv6_mreq = record - ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: integer; // Interface index. - end; - -const - INADDR_ANY = $00000000; - INADDR_LOOPBACK = $7F000001; - INADDR_BROADCAST = $FFFFFFFF; - INADDR_NONE = $FFFFFFFF; - ADDR_ANY = INADDR_ANY; - INVALID_SOCKET = TSocket(NOT(0)); - SOCKET_ERROR = -1; - -Const - IP_TOS = sockets.IP_TOS; { int; IP type of service and precedence. } - IP_TTL = sockets.IP_TTL; { int; IP time to live. } - IP_HDRINCL = sockets.IP_HDRINCL; { int; Header is included with data. } - IP_OPTIONS = sockets.IP_OPTIONS; { ip_opts; IP per-packet options. } -// IP_ROUTER_ALERT = sockets.IP_ROUTER_ALERT; { bool } - IP_RECVOPTS = sockets.IP_RECVOPTS; { bool } - IP_RETOPTS = sockets.IP_RETOPTS; { bool } -// IP_PKTINFO = sockets.IP_PKTINFO; { bool } -// IP_PKTOPTIONS = sockets.IP_PKTOPTIONS; -// IP_PMTUDISC = sockets.IP_PMTUDISC; { obsolete name? } -// IP_MTU_DISCOVER = sockets.IP_MTU_DISCOVER; { int; see below } -// IP_RECVERR = sockets.IP_RECVERR; { bool } -// IP_RECVTTL = sockets.IP_RECVTTL; { bool } -// IP_RECVTOS = sockets.IP_RECVTOS; { bool } - IP_MULTICAST_IF = sockets.IP_MULTICAST_IF; { in_addr; set/get IP multicast i/f } - IP_MULTICAST_TTL = sockets.IP_MULTICAST_TTL; { u_char; set/get IP multicast ttl } - IP_MULTICAST_LOOP = sockets.IP_MULTICAST_LOOP; { i_char; set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = sockets.IP_ADD_MEMBERSHIP; { ip_mreq; add an IP group membership } - IP_DROP_MEMBERSHIP = sockets.IP_DROP_MEMBERSHIP; { ip_mreq; drop an IP group membership } - - SOL_SOCKET = sockets.SOL_SOCKET; - - SO_DEBUG = sockets.SO_DEBUG; - SO_REUSEADDR = sockets.SO_REUSEADDR; - SO_TYPE = sockets.SO_TYPE; - SO_ERROR = sockets.SO_ERROR; - SO_DONTROUTE = sockets.SO_DONTROUTE; - SO_BROADCAST = sockets.SO_BROADCAST; - SO_SNDBUF = sockets.SO_SNDBUF; - SO_RCVBUF = sockets.SO_RCVBUF; - SO_KEEPALIVE = sockets.SO_KEEPALIVE; - SO_OOBINLINE = sockets.SO_OOBINLINE; -// SO_NO_CHECK = sockets.SO_NO_CHECK; -// SO_PRIORITY = sockets.SO_PRIORITY; - SO_LINGER = sockets.SO_LINGER; -// SO_BSDCOMPAT = sockets.SO_BSDCOMPAT; -// SO_REUSEPORT = sockets.SO_REUSEPORT; -// SO_PASSCRED = sockets.SO_PASSCRED; -// SO_PEERCRED = sockets.SO_PEERCRED; - SO_RCVLOWAT = sockets.SO_RCVLOWAT; - SO_SNDLOWAT = sockets.SO_SNDLOWAT; - SO_RCVTIMEO = sockets.SO_RCVTIMEO; - SO_SNDTIMEO = sockets.SO_SNDTIMEO; -{ Security levels - as per NRL IPv6 - don't actually do anything } -// SO_SECURITY_AUTHENTICATION = sockets.SO_SECURITY_AUTHENTICATION; -// SO_SECURITY_ENCRYPTION_TRANSPORT = sockets.SO_SECURITY_ENCRYPTION_TRANSPORT; -// SO_SECURITY_ENCRYPTION_NETWORK = sockets.SO_SECURITY_ENCRYPTION_NETWORK; -// SO_BINDTODEVICE = sockets.SO_BINDTODEVICE; -{ Socket filtering } -// SO_ATTACH_FILTER = sockets.SO_ATTACH_FILTER; -// SO_DETACH_FILTER = sockets.SO_DETACH_FILTER; - -{$IFDEF DARWIN} - SO_NOSIGPIPE = $1022; -{$ENDIF} - - SOMAXCONN = 1024; - - IPV6_UNICAST_HOPS = sockets.IPV6_UNICAST_HOPS; - IPV6_MULTICAST_IF = sockets.IPV6_MULTICAST_IF; - IPV6_MULTICAST_HOPS = sockets.IPV6_MULTICAST_HOPS; - IPV6_MULTICAST_LOOP = sockets.IPV6_MULTICAST_LOOP; - IPV6_JOIN_GROUP = sockets.IPV6_JOIN_GROUP; - IPV6_LEAVE_GROUP = sockets.IPV6_LEAVE_GROUP; - -const - SOCK_STREAM = 1; { stream socket } - SOCK_DGRAM = 2; { datagram socket } - SOCK_RAW = 3; { raw-protocol interface } - SOCK_RDM = 4; { reliably-delivered message } - SOCK_SEQPACKET = 5; { sequenced packet stream } - -{ TCP options. } - TCP_NODELAY = $0001; - -{ Address families. } - - AF_UNSPEC = 0; { unspecified } - AF_INET = 2; { internetwork: UDP, TCP, etc. } - AF_INET6 = 10; { Internetwork Version 6 } - AF_MAX = 24; - -{ Protocol families, same as address families for now. } - PF_UNSPEC = AF_UNSPEC; - PF_INET = AF_INET; - PF_INET6 = AF_INET6; - PF_MAX = AF_MAX; - -type -{ Structure used for manipulating linger option. } - PLinger = ^TLinger; - TLinger = packed record - l_onoff: integer; - l_linger: integer; - end; - -const - - MSG_OOB = sockets.MSG_OOB; // Process out-of-band data. - MSG_PEEK = sockets.MSG_PEEK; // Peek at incoming messages. - {$ifdef DARWIN} - MSG_NOSIGNAL = $20000; // Do not generate SIGPIPE. - // Works under MAC OS X, but is undocumented, - // So FPC doesn't include it - {$else} - MSG_NOSIGNAL = sockets.MSG_NOSIGNAL; // Do not generate SIGPIPE. - {$endif} - -const - WSAEINTR = ESysEINTR; - WSAEBADF = ESysEBADF; - WSAEACCES = ESysEACCES; - WSAEFAULT = ESysEFAULT; - WSAEINVAL = ESysEINVAL; - WSAEMFILE = ESysEMFILE; - WSAEWOULDBLOCK = ESysEWOULDBLOCK; - WSAEINPROGRESS = ESysEINPROGRESS; - WSAEALREADY = ESysEALREADY; - WSAENOTSOCK = ESysENOTSOCK; - WSAEDESTADDRREQ = ESysEDESTADDRREQ; - WSAEMSGSIZE = ESysEMSGSIZE; - WSAEPROTOTYPE = ESysEPROTOTYPE; - WSAENOPROTOOPT = ESysENOPROTOOPT; - WSAEPROTONOSUPPORT = ESysEPROTONOSUPPORT; - WSAESOCKTNOSUPPORT = ESysESOCKTNOSUPPORT; - WSAEOPNOTSUPP = ESysEOPNOTSUPP; - WSAEPFNOSUPPORT = ESysEPFNOSUPPORT; - WSAEAFNOSUPPORT = ESysEAFNOSUPPORT; - WSAEADDRINUSE = ESysEADDRINUSE; - WSAEADDRNOTAVAIL = ESysEADDRNOTAVAIL; - WSAENETDOWN = ESysENETDOWN; - WSAENETUNREACH = ESysENETUNREACH; - WSAENETRESET = ESysENETRESET; - WSAECONNABORTED = ESysECONNABORTED; - WSAECONNRESET = ESysECONNRESET; - WSAENOBUFS = ESysENOBUFS; - WSAEISCONN = ESysEISCONN; - WSAENOTCONN = ESysENOTCONN; - WSAESHUTDOWN = ESysESHUTDOWN; - WSAETOOMANYREFS = ESysETOOMANYREFS; - WSAETIMEDOUT = ESysETIMEDOUT; - WSAECONNREFUSED = ESysECONNREFUSED; - WSAELOOP = ESysELOOP; - WSAENAMETOOLONG = ESysENAMETOOLONG; - WSAEHOSTDOWN = ESysEHOSTDOWN; - WSAEHOSTUNREACH = ESysEHOSTUNREACH; - WSAENOTEMPTY = ESysENOTEMPTY; - WSAEPROCLIM = -1; - WSAEUSERS = ESysEUSERS; - WSAEDQUOT = ESysEDQUOT; - WSAESTALE = ESysESTALE; - WSAEREMOTE = ESysEREMOTE; - WSASYSNOTREADY = -2; - WSAVERNOTSUPPORTED = -3; - WSANOTINITIALISED = -4; - WSAEDISCON = -5; - WSAHOST_NOT_FOUND = 1; - WSATRY_AGAIN = 2; - WSANO_RECOVERY = 3; - WSANO_DATA = -6; - -const - WSADESCRIPTION_LEN = 256; - WSASYS_STATUS_LEN = 128; -type - PWSAData = ^TWSAData; - TWSAData = packed record - wVersion: Word; - wHighVersion: Word; - szDescription: array[0..WSADESCRIPTION_LEN] of Char; - szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; - iMaxSockets: Word; - iMaxUdpDg: Word; - lpVendorInfo: PChar; - end; - - function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; - function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; - procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); - procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); - -var - in6addr_any, in6addr_loopback : TInAddr6; - -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -procedure FD_ZERO(var FDSet: TFDSet); - -{=============================================================================} - -var - SynSockCS: SyncObjs.TCriticalSection; - SockEnhancedApi: Boolean; - SockWship6Api: Boolean; - -type - TVarSin = packed record - {$ifdef SOCK_HAS_SINLEN} - sin_len : cuchar; - {$endif} - case integer of - 0: (AddressFamily: sa_family_t); - 1: ( - case sin_family: sa_family_t of - AF_INET: (sin_port: word; - sin_addr: TInAddr; - sin_zero: array[0..7] of Char); - AF_INET6: (sin6_port: word; - sin6_flowinfo: longword; - sin6_addr: TInAddr6; - sin6_scope_id: longword); - ); - end; - -function SizeOfVarSin(sin: TVarSin): integer; - - function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; - function WSACleanup: Integer; - function WSAGetLastError: Integer; - function GetHostName: string; - function Shutdown(s: TSocket; how: Integer): Integer; - function SetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; - optlen: Integer): Integer; - function GetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; - var optlen: Integer): Integer; - function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; - function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; - function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; - function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; - function ntohs(netshort: word): word; - function ntohl(netlong: longword): longword; - function Listen(s: TSocket; backlog: Integer): Integer; - function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; - function htons(hostshort: word): word; - function htonl(hostlong: longword): longword; - function GetSockName(s: TSocket; var name: TVarSin): Integer; - function GetPeerName(s: TSocket; var name: TVarSin): Integer; - function Connect(s: TSocket; const name: TVarSin): Integer; - function CloseSocket(s: TSocket): Integer; - function Bind(s: TSocket; const addr: TVarSin): Integer; - function Accept(s: TSocket; var addr: TVarSin): TSocket; - function Socket(af, Struc, Protocol: Integer): TSocket; - function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; - -function IsNewApi(Family: integer): Boolean; -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -function GetSinIP(Sin: TVarSin): string; -function GetSinPort(Sin: TVarSin): Integer; -procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); -function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; -function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; - - -{==============================================================================} -implementation - - -function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); -end; - -function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and - (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and - (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); -end; - -function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); -end; - -function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); -end; - -function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; -begin - Result := (a^.u6_addr8[0] = $FF); -end; - -function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; -begin - Result := (CompareMem( a, b, sizeof(TInAddr6))); -end; - -procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); -end; - -procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); - a^.u6_addr8[15] := 1; -end; - -{=============================================================================} - -function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; -begin - with WSData do - begin - wVersion := wVersionRequired; - wHighVersion := $202; - szDescription := 'Synsock - Synapse Platform Independent Socket Layer'; - szSystemStatus := 'Running on Unix/Linux by FreePascal'; - iMaxSockets := 32768; - iMaxUdpDg := 8192; - end; - Result := 0; -end; - -function WSACleanup: Integer; -begin - Result := 0; -end; - -function WSAGetLastError: Integer; -begin - Result := fpGetErrno; -end; - -function FD_ISSET(Socket: TSocket; var fdset: TFDSet): Boolean; -begin - Result := fpFD_ISSET(socket, fdset) <> 0; -end; - -procedure FD_SET(Socket: TSocket; var fdset: TFDSet); -begin - fpFD_SET(Socket, fdset); -end; - -procedure FD_CLR(Socket: TSocket; var fdset: TFDSet); -begin - fpFD_CLR(Socket, fdset); -end; - -procedure FD_ZERO(var fdset: TFDSet); -begin - fpFD_ZERO(fdset); -end; - -{=============================================================================} - -function SizeOfVarSin(sin: TVarSin): integer; -begin - case sin.sin_family of - AF_INET: - Result := SizeOf(TSockAddrIn); - AF_INET6: - Result := SizeOf(TSockAddrIn6); - else - Result := 0; - end; -end; - -{=============================================================================} - -function Bind(s: TSocket; const addr: TVarSin): Integer; -begin - if fpBind(s, @addr, SizeOfVarSin(addr)) = 0 then - Result := 0 - else - Result := SOCKET_ERROR; -end; - -function Connect(s: TSocket; const name: TVarSin): Integer; -begin - if fpConnect(s, @name, SizeOfVarSin(name)) = 0 then - Result := 0 - else - Result := SOCKET_ERROR; -end; - -function GetSockName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := fpGetSockName(s, @name, @Len); -end; - -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := fpGetPeerName(s, @name, @Len); -end; - -function GetHostName: string; -begin - Result := unix.GetHostName; -end; - -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := fpSend(s, pointer(Buf), len, flags); -end; - -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := fpRecv(s, pointer(Buf), len, flags); -end; - -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -begin - Result := fpSendTo(s, pointer(Buf), len, flags, @addrto, SizeOfVarSin(addrto)); -end; - -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -var - x: integer; -begin - x := SizeOf(from); - Result := fpRecvFrom(s, pointer(Buf), len, flags, @from, @x); -end; - -function Accept(s: TSocket; var addr: TVarSin): TSocket; -var - x: integer; -begin - x := SizeOf(addr); - Result := fpAccept(s, @addr, @x); -end; - -function Shutdown(s: TSocket; how: Integer): Integer; -begin - Result := fpShutdown(s, how); -end; - -function SetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; - optlen: Integer): Integer; -begin - Result := fpsetsockopt(s, level, optname, pointer(optval), optlen); -end; - -function GetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; - var optlen: Integer): Integer; -begin - Result := fpgetsockopt(s, level, optname, pointer(optval), @optlen); -end; - -function ntohs(netshort: word): word; -begin - Result := sockets.ntohs(NetShort); -end; - -function ntohl(netlong: longword): longword; -begin - Result := sockets.ntohl(NetLong); -end; - -function Listen(s: TSocket; backlog: Integer): Integer; -begin - if fpListen(s, backlog) = 0 then - Result := 0 - else - Result := SOCKET_ERROR; -end; - -function IoctlSocket(s: TSocket; cmd: DWORD; var arg: integer): Integer; -begin - Result := fpIoctl(s, cmd, @arg); -end; - -function htons(hostshort: word): word; -begin - Result := sockets.htons(Hostshort); -end; - -function htonl(hostlong: longword): longword; -begin - Result := sockets.htonl(HostLong); -end; - -function CloseSocket(s: TSocket): Integer; -begin - Result := sockets.CloseSocket(s); -end; - -function Socket(af, Struc, Protocol: Integer): TSocket; -{$IFDEF DARWIN} -var - on_off: integer; -{$ENDIF} -begin - Result := fpSocket(af, struc, protocol); -// ##### Patch for Mac OS to avoid "Project XXX raised exception class 'External: SIGPIPE'" error. -{$IFDEF DARWIN} - if Result <> INVALID_SOCKET then - begin - on_off := 1; - synsock.SetSockOpt(Result, integer(SOL_SOCKET), integer(SO_NOSIGPIPE), @on_off, SizeOf(integer)); - end; -{$ENDIF} -end; - -function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; -begin - Result := fpSelect(nfds, readfds, writefds, exceptfds, timeout); -end; - -{=============================================================================} -function IsNewApi(Family: integer): Boolean; -begin - Result := SockEnhancedApi; - if not Result then - Result := (Family = AF_INET6) and SockWship6Api; -end; - -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -var - TwoPass: boolean; - f1, f2: integer; - - function GetAddr(f:integer): integer; - var - a4: array [1..1] of in_addr; - a6: array [1..1] of Tin6_addr; - he: THostEntry; - begin - Result := WSAEPROTONOSUPPORT; - case f of - AF_INET: - begin - if IP = cAnyHost then - begin - Sin.sin_family := AF_INET; - Result := 0; - end - else - begin - if lowercase(IP) = cLocalHostStr then - a4[1].s_addr := htonl(INADDR_LOOPBACK) - else - begin - a4[1].s_addr := 0; - Result := WSAHOST_NOT_FOUND; - a4[1] := StrTonetAddr(IP); - if a4[1].s_addr = INADDR_ANY then - if GetHostByName(ip, he) then - a4[1]:=HostToNet(he.Addr) - else - Resolvename(ip, a4); - end; - if a4[1].s_addr <> INADDR_ANY then - begin - Sin.sin_family := AF_INET; - sin.sin_addr := a4[1]; - Result := 0; - end; - end; - end; - AF_INET6: - begin - if IP = c6AnyHost then - begin - Sin.sin_family := AF_INET6; - Result := 0; - end - else - begin - if lowercase(IP) = cLocalHostStr then - SET_LOOPBACK_ADDR6(@a6[1]) - else - begin - Result := WSAHOST_NOT_FOUND; - SET_IN6_IF_ADDR_ANY(@a6[1]); - a6[1] := StrTonetAddr6(IP); - if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then - Resolvename6(ip, a6); - end; - if not IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then - begin - Sin.sin_family := AF_INET6; - sin.sin6_addr := a6[1]; - Result := 0; - end; - end; - end; - end; - end; -begin - Result := 0; - FillChar(Sin, Sizeof(Sin), 0); - Sin.sin_port := Resolveport(port, family, SockProtocol, SockType); - TwoPass := False; - if Family = AF_UNSPEC then - begin - if PreferIP4 then - begin - f1 := AF_INET; - f2 := AF_INET6; - TwoPass := True; - end - else - begin - f2 := AF_INET; - f1 := AF_INET6; - TwoPass := True; - end; - end - else - f1 := Family; - Result := GetAddr(f1); - if Result <> 0 then - if TwoPass then - Result := GetAddr(f2); -end; - -function GetSinIP(Sin: TVarSin): string; -begin - Result := ''; - case sin.AddressFamily of - AF_INET: - begin - result := NetAddrToStr(sin.sin_addr); - end; - AF_INET6: - begin - result := NetAddrToStr6(sin.sin6_addr); - end; - end; -end; - -function GetSinPort(Sin: TVarSin): Integer; -begin - if (Sin.sin_family = AF_INET6) then - Result := synsock.ntohs(Sin.sin6_port) - else - Result := synsock.ntohs(Sin.sin_port); -end; - -procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); -var - x, n: integer; - a4: array [1..255] of in_addr; - a6: array [1..255] of Tin6_addr; - he: THostEntry; -begin - IPList.Clear; - if (family = AF_INET) or (family = AF_UNSPEC) then - begin - if lowercase(name) = cLocalHostStr then - IpList.Add(cLocalHost) - else - begin - a4[1] := StrTonetAddr(name); - if a4[1].s_addr = INADDR_ANY then - if GetHostByName(name, he) then - begin - a4[1]:=HostToNet(he.Addr); - x := 1; - end - else - x := Resolvename(name, a4) - else - x := 1; - for n := 1 to x do - IpList.Add(netaddrToStr(a4[n])); - end; - end; - - if (family = AF_INET6) or (family = AF_UNSPEC) then - begin - if lowercase(name) = cLocalHostStr then - IpList.Add(c6LocalHost) - else - begin - a6[1] := StrTonetAddr6(name); - if IN6_IS_ADDR_UNSPECIFIED(@a6[1]) then - x := Resolvename6(name, a6) - else - x := 1; - for n := 1 to x do - IpList.Add(netaddrToStr6(a6[n])); - end; - end; - - if IPList.Count = 0 then - IPList.Add(cLocalHost); -end; - -function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; -var - ProtoEnt: TProtocolEntry; - ServEnt: TServiceEntry; -begin - Result := synsock.htons(StrToIntDef(Port, 0)); - if Result = 0 then - begin - ProtoEnt.Name := ''; - GetProtocolByNumber(SockProtocol, ProtoEnt); - ServEnt.port := 0; - GetServiceByName(Port, ProtoEnt.Name, ServEnt); - Result := ServEnt.port; - end; -end; - -function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; -var - n: integer; - a4: array [1..1] of in_addr; - a6: array [1..1] of Tin6_addr; - a: array [1..1] of string; -begin - Result := IP; - a4[1] := StrToNetAddr(IP); - if a4[1].s_addr <> INADDR_ANY then - begin -//why ResolveAddress need address in HOST order? :-O - n := ResolveAddress(nettohost(a4[1]), a); - if n > 0 then - Result := a[1]; - end - else - begin - a6[1] := StrToNetAddr6(IP); - n := ResolveAddress6(a6[1], a); - if n > 0 then - Result := a[1]; - end; -end; - -{=============================================================================} - -function InitSocketInterface(stack: string): Boolean; -begin - SockEnhancedApi := False; - SockWship6Api := False; -// Libc.Signal(Libc.SIGPIPE, TSignalHandler(Libc.SIG_IGN)); - Result := True; -end; - -function DestroySocketInterface: Boolean; -begin - Result := True; -end; - -initialization -begin - SynSockCS := SyncObjs.TCriticalSection.Create; - SET_IN6_IF_ADDR_ANY (@in6addr_any); - SET_LOOPBACK_ADDR6 (@in6addr_loopback); -end; - -finalization -begin - SynSockCS.Free; -end; - -{$ENDIF} - diff --git a/3rd/synapse/source/ssl_cryptlib.pas b/3rd/synapse/source/ssl_cryptlib.pas deleted file mode 100644 index b9be4decd..000000000 --- a/3rd/synapse/source/ssl_cryptlib.pas +++ /dev/null @@ -1,677 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.000 | -|==============================================================================| -| Content: SSL/SSH support by Peter Gutmann's CryptLib | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2005-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(SSL/SSH plugin for CryptLib) - -This plugin requires cl32.dll at least version 3.2.0! It can be used on Win32 -and Linux. This library is staticly linked - when you compile your application -with this plugin, you MUST distribute it with Cryptib library, otherwise you -cannot run your application! - -It can work with keys and certificates stored as PKCS#15 only! It must be stored -as disk file only, you cannot load them from memory! Each file can hold multiple -keys and certificates. You must identify it by 'label' stored in -@link(TSSLCryptLib.PrivateKeyLabel). - -If you need to use secure connection and authorize self by certificate -(each SSL/TLS server or client with client authorization), then use -@link(TCustomSSL.PrivateKeyFile), @link(TSSLCryptLib.PrivateKeyLabel) and -@link(TCustomSSL.KeyPassword) properties. - -If you need to use server what verifying client certificates, then use -@link(TCustomSSL.CertCAFile) as PKCS#15 file with public keyas of allowed clients. Clients -with non-matching certificates will be rejected by cryptLib. - -This plugin is capable to create Ad-Hoc certificates. When you start SSL/TLS -server without explicitly assigned key and certificate, then this plugin create -Ad-Hoc key and certificate for each incomming connection by self. It slowdown -accepting of new connections! - -You can use this plugin for SSHv2 connections too! You must explicitly set -@link(TCustomSSL.SSLType) to value LT_SSHv2 and set @link(TCustomSSL.username) -and @link(TCustomSSL.password). You can use special SSH channels too, see -@link(TCustomSSL). -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -unit ssl_cryptlib; - -interface - -uses - Windows, - SysUtils, - blcksock, synsock, synautil, synacode, - cryptlib; - -type - {:@abstract(class implementing CryptLib SSL/SSH plugin.) - Instance of this class will be created for each @link(TTCPBlockSocket). - You not need to create instance of this class, all is done by Synapse itself!} - TSSLCryptLib = class(TCustomSSL) - protected - FCryptSession: CRYPT_SESSION; - FPrivateKeyLabel: string; - FDelCert: Boolean; - FReadBuffer: string; - FTrustedCAs: array of integer; - function SSLCheck(Value: integer): Boolean; - function Init(server:Boolean): Boolean; - function DeInit: Boolean; - function Prepare(server:Boolean): Boolean; - function GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string; - function CreateSelfSignedCert(Host: string): Boolean; override; - function PopAll: string; - public - {:See @inherited} - constructor Create(const Value: TTCPBlockSocket); override; - destructor Destroy; override; - {:Load trusted CA's in PEM format} - procedure SetCertCAFile(const Value: string); override; - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - {:See @inherited} - procedure Assign(const Value: TCustomSSL); override; - {:See @inherited and @link(ssl_cryptlib) for more details.} - function Connect: boolean; override; - {:See @inherited and @link(ssl_cryptlib) for more details.} - function Accept: boolean; override; - {:See @inherited} - function Shutdown: boolean; override; - {:See @inherited} - function BiShutdown: boolean; override; - {:See @inherited} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function WaitingData: Integer; override; - {:See @inherited} - function GetSSLVersion: string; override; - {:See @inherited} - function GetPeerSubject: string; override; - {:See @inherited} - function GetPeerIssuer: string; override; - {:See @inherited} - function GetPeerName: string; override; - {:See @inherited} - function GetPeerFingerprint: string; override; - {:See @inherited} - function GetVerifyCert: integer; override; - published - {:name of certificate/key within PKCS#15 file. It can hold more then one - certificate/key and each certificate/key must have unique label within one file.} - property PrivateKeyLabel: string read FPrivateKeyLabel Write FPrivateKeyLabel; - end; - -implementation - -{==============================================================================} - -constructor TSSLCryptLib.Create(const Value: TTCPBlockSocket); -begin - inherited Create(Value); - FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE); - FPrivateKeyLabel := 'synapse'; - FDelCert := false; - FTrustedCAs := nil; -end; - -destructor TSSLCryptLib.Destroy; -begin - SetCertCAFile(''); // destroy certificates - DeInit; - inherited Destroy; -end; - -procedure TSSLCryptLib.Assign(const Value: TCustomSSL); -begin - inherited Assign(Value); - if Value is TSSLCryptLib then - begin - FPrivateKeyLabel := TSSLCryptLib(Value).privatekeyLabel; - end; -end; - -function TSSLCryptLib.GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string; -var - l: integer; -begin - l := 0; - cryptGetAttributeString(cryptHandle, attributeType, nil, l); - setlength(Result, l); - cryptGetAttributeString(cryptHandle, attributeType, pointer(Result), l); - setlength(Result, l); -end; - -function TSSLCryptLib.LibVersion: String; -var - x: integer; -begin - Result := GetString(CRYPT_UNUSED, CRYPT_OPTION_INFO_DESCRIPTION); - cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION, x); - Result := Result + ' v' + IntToStr(x); - cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION, x); - Result := Result + '.' + IntToStr(x); - cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_STEPPING, x); - Result := Result + '.' + IntToStr(x); -end; - -function TSSLCryptLib.LibName: String; -begin - Result := 'ssl_cryptlib'; -end; - -function TSSLCryptLib.SSLCheck(Value: integer): Boolean; -begin - Result := true; - FLastErrorDesc := ''; - if Value = CRYPT_ERROR_COMPLETE then - Value := 0; - FLastError := Value; - if FLastError <> 0 then - begin - Result := False; -{$IF CRYPTLIB_VERSION >= 3400} - FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_ERRORMESSAGE); -{$ELSE} - FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_INT_ERRORMESSAGE); -{$IFEND} - end; -end; - -function TSSLCryptLib.CreateSelfSignedCert(Host: string): Boolean; -var - privateKey: CRYPT_CONTEXT; - keyset: CRYPT_KEYSET; - cert: CRYPT_CERTIFICATE; - publicKey: CRYPT_CONTEXT; -begin - if FPrivatekeyFile = '' then - FPrivatekeyFile := GetTempFile('', 'key'); - cryptCreateContext(privateKey, CRYPT_UNUSED, CRYPT_ALGO_RSA); - cryptSetAttributeString(privateKey, CRYPT_CTXINFO_LABEL, Pointer(FPrivatekeyLabel), - Length(FPrivatekeyLabel)); - cryptSetAttribute(privateKey, CRYPT_CTXINFO_KEYSIZE, 1024); - cryptGenerateKey(privateKey); - cryptKeysetOpen(keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, PChar(FPrivatekeyFile), CRYPT_KEYOPT_CREATE); - FDelCert := True; - cryptAddPrivateKey(keyset, privateKey, PChar(FKeyPassword)); - cryptCreateCert(cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE); - cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1); - cryptGetPublicKey(keyset, publicKey, CRYPT_KEYID_NAME, PChar(FPrivatekeyLabel)); - cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, publicKey); - cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, Pointer(host), Length(host)); - cryptSignCert(cert, privateKey); - cryptAddPublicKey(keyset, cert); - cryptKeysetClose(keyset); - cryptDestroyCert(cert); - cryptDestroyContext(privateKey); - cryptDestroyContext(publicKey); - Result := True; -end; - -function TSSLCryptLib.PopAll: string; -const - BufferMaxSize = 32768; -var - Outbuffer: string; - WriteLen: integer; -begin - Result := ''; - repeat - setlength(outbuffer, BufferMaxSize); - Writelen := 0; - SSLCheck(CryptPopData(FCryptSession, @OutBuffer[1], BufferMaxSize, Writelen)); - if FLastError <> 0 then - Break; - if WriteLen > 0 then - begin - setlength(outbuffer, WriteLen); - Result := Result + outbuffer; - end; - until WriteLen = 0; -end; - -function TSSLCryptLib.Init(server:Boolean): Boolean; -var - st: CRYPT_SESSION_TYPE; - keysetobj: CRYPT_KEYSET; - cryptContext: CRYPT_CONTEXT; - x: integer; -begin - Result := False; - FLastErrorDesc := ''; - FLastError := 0; - FDelCert := false; - FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE); - if server then - case FSSLType of - LT_all, LT_SSLv3, LT_TLSv1, LT_TLSv1_1: - st := CRYPT_SESSION_SSL_SERVER; - LT_SSHv2: - st := CRYPT_SESSION_SSH_SERVER; - else - Exit; - end - else - case FSSLType of - LT_all, LT_SSLv3, LT_TLSv1, LT_TLSv1_1: - st := CRYPT_SESSION_SSL; - LT_SSHv2: - st := CRYPT_SESSION_SSH; - else - Exit; - end; - if not SSLCheck(cryptCreateSession(FcryptSession, CRYPT_UNUSED, st)) then - Exit; - x := -1; - case FSSLType of - LT_SSLv3: - x := 0; - LT_TLSv1: - x := 1; - LT_TLSv1_1: - x := 2; - end; - if x >= 0 then - if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x)) then - Exit; - - if (FCertComplianceLevel <> -1) then - if not SSLCheck(cryptSetAttribute (CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL, - FCertComplianceLevel)) then - Exit; - - if FUsername <> '' then - begin - cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_USERNAME, - Pointer(FUsername), Length(FUsername)); - cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_PASSWORD, - Pointer(FPassword), Length(FPassword)); - end; - if FSSLType = LT_SSHv2 then - if FSSHChannelType <> '' then - begin - cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED); - cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_TYPE, - Pointer(FSSHChannelType), Length(FSSHChannelType)); - if FSSHChannelArg1 <> '' then - cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG1, - Pointer(FSSHChannelArg1), Length(FSSHChannelArg1)); - if FSSHChannelArg2 <> '' then - cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG2, - Pointer(FSSHChannelArg2), Length(FSSHChannelArg2)); - end; - - - if server and (FPrivatekeyFile = '') then - begin - if FPrivatekeyLabel = '' then - FPrivatekeyLabel := 'synapse'; - if FkeyPassword = '' then - FkeyPassword := 'synapse'; - CreateSelfSignedcert(FSocket.ResolveIPToName(FSocket.GetRemoteSinIP)); - end; - - if (FPrivatekeyLabel <> '') and (FPrivatekeyFile <> '') then - begin - if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE, - PChar(FPrivatekeyFile), CRYPT_KEYOPT_READONLY)) then - Exit; - try - if not SSLCheck(cryptGetPrivateKey(KeySetObj, cryptcontext, CRYPT_KEYID_NAME, - PChar(FPrivatekeyLabel), PChar(FKeyPassword))) then - Exit; - if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_PRIVATEKEY, - cryptcontext)) then - Exit; - finally - cryptKeysetClose(keySetObj); - cryptDestroyContext(cryptcontext); - end; - end; - if server and FVerifyCert then - begin - if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE, - PChar(FCertCAFile), CRYPT_KEYOPT_READONLY)) then - Exit; - try - if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_KEYSET, - keySetObj)) then - Exit; - finally - cryptKeysetClose(keySetObj); - end; - end; - Result := true; -end; - -function TSSLCryptLib.DeInit: Boolean; -begin - Result := True; - if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then - CryptDestroySession(FcryptSession); - FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE); - FSSLEnabled := False; - if FDelCert then - SysUtils.DeleteFile(FPrivatekeyFile); -end; - -function TSSLCryptLib.Prepare(server:Boolean): Boolean; -begin - Result := false; - DeInit; - if Init(server) then - Result := true - else - DeInit; -end; - -function TSSLCryptLib.Connect: boolean; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(false) then - begin - if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then - Exit; - if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then - Exit; - if FverifyCert then - if (GetVerifyCert <> 0) or (not DoVerifyCert) then - Exit; - FSSLEnabled := True; - Result := True; - FReadBuffer := ''; - end; -end; - -function TSSLCryptLib.Accept: boolean; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(true) then - begin - if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then - Exit; - if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then - Exit; - FSSLEnabled := True; - Result := True; - FReadBuffer := ''; - end; -end; - -function TSSLCryptLib.Shutdown: boolean; -begin - Result := BiShutdown; -end; - -function TSSLCryptLib.BiShutdown: boolean; -begin - if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then - cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 0); - DeInit; - FReadBuffer := ''; - Result := True; -end; - -function TSSLCryptLib.SendBuffer(Buffer: TMemory; Len: Integer): Integer; -var - l: integer; -begin - FLastError := 0; - FLastErrorDesc := ''; - SSLCheck(cryptPushData(FCryptSession, Buffer, Len, L)); - cryptFlushData(FcryptSession); - Result := l; -end; - -function TSSLCryptLib.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -begin - FLastError := 0; - FLastErrorDesc := ''; - if Length(FReadBuffer) = 0 then - FReadBuffer := PopAll; - if Len > Length(FReadBuffer) then - Len := Length(FReadBuffer); - Move(Pointer(FReadBuffer)^, buffer^, Len); - Delete(FReadBuffer, 1, Len); - Result := Len; -end; - -function TSSLCryptLib.WaitingData: Integer; -begin - Result := Length(FReadBuffer); -end; - -function TSSLCryptLib.GetSSLVersion: string; -var - x: integer; -begin - Result := ''; - if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then - Exit; - cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x); - if FSSLType in [LT_SSLv3, LT_TLSv1, LT_TLSv1_1, LT_all] then - case x of - 0: - Result := 'SSLv3'; - 1: - Result := 'TLSv1'; - 2: - Result := 'TLSv1.1'; - end; - if FSSLType in [LT_SSHv2] then - case x of - 0: - Result := 'SSHv1'; - 1: - Result := 'SSHv2'; - end; -end; - -function TSSLCryptLib.GetPeerSubject: string; -var - cert: CRYPT_CERTIFICATE; -begin - Result := ''; - if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then - Exit; - cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert); - cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME); - Result := GetString(cert, CRYPT_CERTINFO_DN); - cryptDestroyCert(cert); -end; - -function TSSLCryptLib.GetPeerName: string; -var - cert: CRYPT_CERTIFICATE; -begin - Result := ''; - if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then - Exit; - cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert); - cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME); - Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME); - cryptDestroyCert(cert); -end; - -function TSSLCryptLib.GetPeerIssuer: string; -var - cert: CRYPT_CERTIFICATE; -begin - Result := ''; - if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then - Exit; - cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert); - cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_ISSUERNAME); - Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME); - cryptDestroyCert(cert); -end; - -function TSSLCryptLib.GetPeerFingerprint: string; -var - cert: CRYPT_CERTIFICATE; -begin - Result := ''; - if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then - Exit; - cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert); - Result := GetString(cert, CRYPT_CERTINFO_FINGERPRINT); - cryptDestroyCert(cert); -end; - - -procedure TSSLCryptLib.SetCertCAFile(const Value: string); - -var F:textfile; - bInCert:boolean; - s,sCert:string; - cert: CRYPT_CERTIFICATE; - idx:integer; - -begin -if assigned(FTrustedCAs) then - begin - for idx := 0 to High(FTrustedCAs) do - cryptDestroyCert(FTrustedCAs[idx]); - FTrustedCAs:=nil; - end; -if Value<>'' then - begin - AssignFile(F,Value); - reset(F); - bInCert:=false; - idx:=0; - while not eof(F) do - begin - readln(F,s); - if pos('-----END CERTIFICATE-----',s)>0 then - begin - bInCert:=false; - cert:=0; - if (cryptImportCert(PAnsiChar(sCert),length(sCert)-2,CRYPT_UNUSED,cert)=CRYPT_OK) then - begin - cryptSetAttribute( cert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 ); - SetLength(FTrustedCAs,idx+1); - FTrustedCAs[idx]:=cert; - idx:=idx+1; - end; - end; - if bInCert then - sCert:=sCert+s+#13#10; - if pos('-----BEGIN CERTIFICATE-----',s)>0 then - begin - bInCert:=true; - sCert:=''; - end; - end; - CloseFile(F); - end; -end; - -function TSSLCryptLib.GetVerifyCert: integer; -var - cert: CRYPT_CERTIFICATE; - itype,ilocus:integer; -begin - Result := -1; - if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then - Exit; - cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert); - result:=cryptCheckCert(cert,CRYPT_UNUSED); - if result<>CRYPT_OK then - begin - //get extended error info if available - cryptGetAttribute(cert,CRYPT_ATTRIBUTE_ERRORtype,itype); - cryptGetAttribute(cert,CRYPT_ATTRIBUTE_ERRORLOCUS,ilocus); - cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME); - FLastError := Result; - FLastErrorDesc := format('SSL/TLS certificate verification failed for "%s"'#13#10'Status: %d. ERRORTYPE: %d. ERRORLOCUS: %d.', - [GetString(cert, CRYPT_CERTINFO_COMMONNAME),result,itype,ilocus]); - end; - cryptDestroyCert(cert); -end; - -{==============================================================================} - -var imajor,iminor,iver:integer; -// e: ESynapseError; - -initialization - if cryptInit = CRYPT_OK then - SSLImplementation := TSSLCryptLib; - cryptAddRandom(nil, CRYPT_RANDOM_SLOWPOLL); - cryptGetAttribute (CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION,imajor); - cryptGetAttribute (CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION,iminor); -// according to the documentation CRYPTLIB version has 3 digits. recent versions use 4 digits - if CRYPTLIB_VERSION >1000 then - iver:=CRYPTLIB_VERSION div 100 - else - iver:=CRYPTLIB_VERSION div 10; - if (iver <> imajor*10+iminor) then - begin - SSLImplementation :=TSSLNone; -// e := ESynapseError.Create(format('Error wrong cryptlib version (is %d.%d expected %d.%d). ', -// [imajor,iminor,iver div 10, iver mod 10])); -// e.ErrorCode := 0; -// e.ErrorMessage := format('Error wrong cryptlib version (%d.%d expected %d.%d)', -// [imajor,iminor,iver div 10, iver mod 10]); -// raise e; - end; -finalization - cryptEnd; -end. - - diff --git a/3rd/synapse/source/ssl_libssh2.pas b/3rd/synapse/source/ssl_libssh2.pas deleted file mode 100644 index e0154c068..000000000 --- a/3rd/synapse/source/ssl_libssh2.pas +++ /dev/null @@ -1,251 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.000.000 | -|==============================================================================| -| Content: SSH support by LibSSH2 | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Alexey Suhinin. | -| Portions created by Alexey Suhinin are Copyright (c)2012-2013. | -| Portions created by Lukas Gebauer are Copyright (c)2013-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -//requires LibSSH2 libraries! http://libssh2.org - -{:@abstract(SSH plugin for LibSSH2) - -Requires libssh2.dll or libssh2.so. -You can download binaries as part of the CURL project from -http://curl.haxx.se/download.html - -You need Pascal bindings for the library too! You can find one at: - http://www.lazarus.freepascal.org/index.php/topic,15935.msg86465.html#msg86465 - -This plugin implements the client part only. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -unit ssl_libssh2; - -interface - -uses - SysUtils, - blcksock, synsock, - libssh2; - -type - {:@abstract(class implementing LibSSH2 SSH plugin.) - Instance of this class will be created for each @link(TTCPBlockSocket). - You not need to create instance of this class, all is done by Synapse itself!} - TSSLLibSSH2 = class(TCustomSSL) - protected - FSession: PLIBSSH2_SESSION; - FChannel: PLIBSSH2_CHANNEL; - function SSHCheck(Value: integer): Boolean; - function DeInit: Boolean; - public - {:See @inherited} - constructor Create(const Value: TTCPBlockSocket); override; - destructor Destroy; override; - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - {:See @inherited} - function Connect: boolean; override; - {:See @inherited} - function Shutdown: boolean; override; - {:See @inherited} - function BiShutdown: boolean; override; - {:See @inherited} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function WaitingData: Integer; override; - {:See @inherited} - function GetSSLVersion: string; override; - published - end; - -implementation - -{==============================================================================} -function TSSLLibSSH2.SSHCheck(Value: integer): Boolean; -var - PLastError: PAnsiChar; - ErrMsgLen: Integer; -begin - Result := true; - FLastError := 0; - FLastErrorDesc := ''; - if Value<0 then - begin - FLastError := libssh2_session_last_error(FSession, PLastError, ErrMsglen, 0); - FLastErrorDesc := PLastError; - Result := false; - end; -end; - - -function TSSLLibSSH2.DeInit: Boolean; -begin - if Assigned(FChannel) then - begin - libssh2_channel_free(FChannel); - FChannel := nil; - end; - if Assigned(FSession) then - begin - libssh2_session_disconnect(FSession,'Goodbye'); - libssh2_session_free(FSession); - FSession := nil; - end; - FSSLEnabled := False; - Result := true; -end; - -constructor TSSLLibSSH2.Create(const Value: TTCPBlockSocket); -begin - inherited Create(Value); - FSession := nil; - FChannel := nil; -end; - -destructor TSSLLibSSH2.Destroy; -begin - DeInit; - inherited Destroy; -end; - -function TSSLLibSSH2.Connect: boolean; -begin - Result := False; - if SSLEnabled then DeInit; - if (FSocket.Socket <> INVALID_SOCKET) and (FSocket.SSL.SSLType = LT_SSHv2) then - begin - FSession := libssh2_session_init(); - if not Assigned(FSession) then - begin - FLastError := -999; - FLastErrorDesc := 'Cannot initialize SSH session'; - exit; - end; - if not SSHCheck(libssh2_session_startup(FSession, FSocket.Socket)) then - exit; - // Attempt private key authentication, then fall back to username/password but - // do not forget original private key auth error. This avoids giving spurious errors like - // Authentication failed (username/password) - // instead of e.g. - // Unable to extract public key from private key file: Method unimplemented in libgcrypt backend - if FSocket.SSL.PrivateKeyFile<>'' then - if (not SSHCheck(libssh2_userauth_publickey_fromfile(FSession, PChar(FSocket.SSL.Username), nil, PChar(FSocket.SSL.PrivateKeyFile), PChar(FSocket.SSL.KeyPassword)))) - and (libssh2_userauth_password(FSession, PChar(FSocket.SSL.Username), PChar(FSocket.SSL.Password))<0) then - exit; - FChannel := libssh2_channel_open_session(FSession); - if not assigned(FChannel) then - begin -// SSHCheck(-1); - FLastError:=-999; - FLastErrorDesc := 'Cannot open session'; - exit; - end; - if not SSHCheck(libssh2_channel_request_pty(FChannel, 'vanilla')) then - exit; - if not SSHCheck(libssh2_channel_shell(FChannel)) then - exit; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLLibSSH2.LibName: String; -begin - Result := 'ssl_libssh2'; -end; - -function TSSLLibSSH2.Shutdown: boolean; -begin - Result := DeInit; -end; - - -function TSSLLibSSH2.BiShutdown: boolean; -begin - Result := DeInit; -end; - -function TSSLLibSSH2.SendBuffer(Buffer: TMemory; Len: Integer): Integer; -begin - Result:=libssh2_channel_write(FChannel, PAnsiChar(Buffer), Len); - SSHCheck(Result); -end; - -function TSSLLibSSH2.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -begin - result:=libssh2_channel_read(FChannel, PAnsiChar(Buffer), Len); - SSHCheck(Result); -end; - -function TSSLLibSSH2.WaitingData: Integer; -begin - if libssh2_poll_channel_read(FChannel, Result) <> 1 then - Result := 0; -end; - -function TSSLLibSSH2.GetSSLVersion: string; -begin - Result := 'SSH2'; -end; - -function TSSLLibSSH2.LibVersion: String; -begin - Result := libssh2_version(0); -end; - -initialization - if libssh2_init(0)=0 then - SSLImplementation := TSSLLibSSH2; - -finalization - libssh2_exit; - -end. diff --git a/3rd/synapse/source/ssl_openssl.pas b/3rd/synapse/source/ssl_openssl.pas deleted file mode 100644 index 26c6a7492..000000000 --- a/3rd/synapse/source/ssl_openssl.pas +++ /dev/null @@ -1,922 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.002.001 | -|==============================================================================| -| Content: SSL support by OpenSSL | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2005-2012. | -| Portions created by Petr Fejfar are Copyright (c)2011-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -//requires OpenSSL libraries! - -{:@abstract(SSL plugin for OpenSSL) - -You need OpenSSL libraries version 0.9.7. It can work with 0.9.6 too, but -application mysteriously crashing when you are using freePascal on Linux. -Use Kylix on Linux is OK! If you have version 0.9.7 on Linux, then I not see -any problems with FreePascal. - -OpenSSL libraries are loaded dynamicly - you not need OpenSSl librares even you -compile your application with this unit. SSL just not working when you not have -OpenSSL libraries. - -This plugin have limited support for .NET too! Because is not possible to use -callbacks with CDECL calling convention under .NET, is not supported -key/certificate passwords and multithread locking. :-( - -For handling keys and certificates you can use this properties: - -@link(TCustomSSL.CertificateFile) for PEM or ASN1 DER (cer) format. @br -@link(TCustomSSL.Certificate) for ASN1 DER format only. @br -@link(TCustomSSL.PrivateKeyFile) for PEM or ASN1 DER (key) format. @br -@link(TCustomSSL.PrivateKey) for ASN1 DER format only. @br -@link(TCustomSSL.CertCAFile) for PEM CA certificate bundle. @br -@link(TCustomSSL.PFXFile) for PFX format. @br -@link(TCustomSSL.PFX) for PFX format from binary string. @br - -This plugin is capable to create Ad-Hoc certificates. When you start SSL/TLS -server without explicitly assigned key and certificate, then this plugin create -Ad-Hoc key and certificate for each incomming connection by self. It slowdown -accepting of new connections! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit ssl_openssl; - -interface - -uses - SysUtils, Classes, - blcksock, synsock, synautil, -{$IFDEF CIL} - System.Text, -{$ENDIF} - ssl_openssl_lib; - -type - {:@abstract(class implementing OpenSSL SSL plugin.) - Instance of this class will be created for each @link(TTCPBlockSocket). - You not need to create instance of this class, all is done by Synapse itself!} - TSSLOpenSSL = class(TCustomSSL) - protected - FSsl: PSSL; - Fctx: PSSL_CTX; - function SSLCheck: Boolean; - function SetSslKeys: boolean; - function Init(server:Boolean): Boolean; - function DeInit: Boolean; - function Prepare(server:Boolean): Boolean; - function LoadPFX(pfxdata: ansistring): Boolean; - function CreateSelfSignedCert(Host: string): Boolean; override; - public - {:See @inherited} - constructor Create(const Value: TTCPBlockSocket); override; - destructor Destroy; override; - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - {:See @inherited and @link(ssl_cryptlib) for more details.} - function Connect: boolean; override; - {:See @inherited and @link(ssl_cryptlib) for more details.} - function Accept: boolean; override; - {:See @inherited} - function Shutdown: boolean; override; - {:See @inherited} - function BiShutdown: boolean; override; - {:See @inherited} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function WaitingData: Integer; override; - {:See @inherited} - function GetSSLVersion: string; override; - {:See @inherited} - function GetPeerSubject: string; override; - {:See @inherited} - function GetPeerSerialNo: integer; override; {pf} - {:See @inherited} - function GetPeerIssuer: string; override; - {:See @inherited} - function GetPeerName: string; override; - {:See @inherited} - function GetPeerNameHash: cardinal; override; {pf} - {:See @inherited} - function GetPeerFingerprint: string; override; - {:See @inherited} - function GetCertInfo: string; override; - {:See @inherited} - function GetCipherName: string; override; - {:See @inherited} - function GetCipherBits: integer; override; - {:See @inherited} - function GetCipherAlgBits: integer; override; - {:See @inherited} - function GetVerifyCert: integer; override; - end; - -implementation - -{==============================================================================} - -{$IFNDEF CIL} -function PasswordCallback(buf:PAnsiChar; size:Integer; rwflag:Integer; userdata: Pointer):Integer; cdecl; -var - Password: AnsiString; -begin - Password := ''; - if TCustomSSL(userdata) is TCustomSSL then - Password := TCustomSSL(userdata).KeyPassword; - if Length(Password) > (Size - 1) then - SetLength(Password, Size - 1); - Result := Length(Password); - StrLCopy(buf, PAnsiChar(Password + #0), Result + 1); -end; -{$ENDIF} - -{==============================================================================} - -constructor TSSLOpenSSL.Create(const Value: TTCPBlockSocket); -begin - inherited Create(Value); - FCiphers := 'DEFAULT'; - FSsl := nil; - Fctx := nil; -end; - -destructor TSSLOpenSSL.Destroy; -begin - DeInit; - inherited Destroy; -end; - -function TSSLOpenSSL.LibVersion: String; -begin - Result := SSLeayversion(0); -end; - -function TSSLOpenSSL.LibName: String; -begin - Result := 'ssl_openssl'; -end; - -function TSSLOpenSSL.SSLCheck: Boolean; -var -{$IFDEF CIL} - sb: StringBuilder; -{$ENDIF} - s : AnsiString; -begin - Result := true; - FLastErrorDesc := ''; - FLastError := ErrGetError; - ErrClearError; - if FLastError <> 0 then - begin - Result := False; -{$IFDEF CIL} - sb := StringBuilder.Create(256); - ErrErrorString(FLastError, sb, 256); - FLastErrorDesc := Trim(sb.ToString); -{$ELSE} - s := StringOfChar(#0, 256); - ErrErrorString(FLastError, s, Length(s)); - FLastErrorDesc := s; -{$ENDIF} - end; -end; - -function TSSLOpenSSL.CreateSelfSignedCert(Host: string): Boolean; -var - pk: EVP_PKEY; - x: PX509; - rsa: PRSA; - t: PASN1_UTCTIME; - name: PX509_NAME; - b: PBIO; - xn, y: integer; - s: AnsiString; -{$IFDEF CIL} - sb: StringBuilder; -{$ENDIF} -begin - Result := True; - pk := EvpPkeynew; - x := X509New; - try - rsa := RsaGenerateKey(1024, $10001, nil, nil); - EvpPkeyAssign(pk, EVP_PKEY_RSA, rsa); - X509SetVersion(x, 2); - Asn1IntegerSet(X509getSerialNumber(x), 0); - t := Asn1UtctimeNew; - try - X509GmtimeAdj(t, -60 * 60 *24); - X509SetNotBefore(x, t); - X509GmtimeAdj(t, 60 * 60 * 60 *24); - X509SetNotAfter(x, t); - finally - Asn1UtctimeFree(t); - end; - X509SetPubkey(x, pk); - Name := X509GetSubjectName(x); - X509NameAddEntryByTxt(Name, 'C', $1001, 'CZ', -1, -1, 0); - X509NameAddEntryByTxt(Name, 'CN', $1001, host, -1, -1, 0); - x509SetIssuerName(x, Name); - x509Sign(x, pk, EvpGetDigestByName('SHA1')); - b := BioNew(BioSMem); - try - i2dX509Bio(b, x); - xn := bioctrlpending(b); -{$IFDEF CIL} - sb := StringBuilder.Create(xn); - y := bioread(b, sb, xn); - if y > 0 then - begin - sb.Length := y; - s := sb.ToString; - end; -{$ELSE} - setlength(s, xn); - y := bioread(b, s, xn); - if y > 0 then - setlength(s, y); -{$ENDIF} - finally - BioFreeAll(b); - end; - FCertificate := s; - b := BioNew(BioSMem); - try - i2dPrivatekeyBio(b, pk); - xn := bioctrlpending(b); -{$IFDEF CIL} - sb := StringBuilder.Create(xn); - y := bioread(b, sb, xn); - if y > 0 then - begin - sb.Length := y; - s := sb.ToString; - end; -{$ELSE} - setlength(s, xn); - y := bioread(b, s, xn); - if y > 0 then - setlength(s, y); -{$ENDIF} - finally - BioFreeAll(b); - end; - FPrivatekey := s; - finally - X509free(x); - EvpPkeyFree(pk); - end; -end; - -function TSSLOpenSSL.LoadPFX(pfxdata: Ansistring): Boolean; -var - cert, pkey, ca: SslPtr; - b: PBIO; - p12: SslPtr; -begin - Result := False; - b := BioNew(BioSMem); - try - BioWrite(b, pfxdata, Length(PfxData)); - p12 := d2iPKCS12bio(b, nil); - if not Assigned(p12) then - Exit; - try - cert := nil; - pkey := nil; - ca := nil; - try {pf} - if PKCS12parse(p12, FKeyPassword, pkey, cert, ca) > 0 then - if SSLCTXusecertificate(Fctx, cert) > 0 then - if SSLCTXusePrivateKey(Fctx, pkey) > 0 then - Result := True; - {pf} - finally - EvpPkeyFree(pkey); - X509free(cert); - SkX509PopFree(ca,_X509Free); // for ca=nil a new STACK was allocated... - end; - {/pf} - finally - PKCS12free(p12); - end; - finally - BioFreeAll(b); - end; -end; - -function TSSLOpenSSL.SetSslKeys: boolean; -var - st: TFileStream; - s: string; -begin - Result := False; - if not assigned(FCtx) then - Exit; - try - if FCertificateFile <> '' then - if SslCtxUseCertificateChainFile(FCtx, FCertificateFile) <> 1 then - if SslCtxUseCertificateFile(FCtx, FCertificateFile, SSL_FILETYPE_PEM) <> 1 then - if SslCtxUseCertificateFile(FCtx, FCertificateFile, SSL_FILETYPE_ASN1) <> 1 then - Exit; - if FCertificate <> '' then - if SslCtxUseCertificateASN1(FCtx, length(FCertificate), FCertificate) <> 1 then - Exit; - SSLCheck; - if FPrivateKeyFile <> '' then - if SslCtxUsePrivateKeyFile(FCtx, FPrivateKeyFile, SSL_FILETYPE_PEM) <> 1 then - if SslCtxUsePrivateKeyFile(FCtx, FPrivateKeyFile, SSL_FILETYPE_ASN1) <> 1 then - Exit; - if FPrivateKey <> '' then - if SslCtxUsePrivateKeyASN1(EVP_PKEY_RSA, FCtx, FPrivateKey, length(FPrivateKey)) <> 1 then - Exit; - SSLCheck; - if FCertCAFile <> '' then - if SslCtxLoadVerifyLocations(FCtx, FCertCAFile, '') <> 1 then - Exit; - if FPFXfile <> '' then - begin - try - st := TFileStream.Create(FPFXfile, fmOpenRead or fmShareDenyNone); - try - s := ReadStrFromStream(st, st.Size); - finally - st.Free; - end; - if not LoadPFX(s) then - Exit; - except - on Exception do - Exit; - end; - end; - if FPFX <> '' then - if not LoadPFX(FPfx) then - Exit; - SSLCheck; - Result := True; - finally - SSLCheck; - end; -end; - -function TSSLOpenSSL.Init(server:Boolean): Boolean; -var - s: AnsiString; -begin - Result := False; - FLastErrorDesc := ''; - FLastError := 0; - Fctx := nil; - case FSSLType of - LT_SSLv2: - Fctx := SslCtxNew(SslMethodV2); - LT_SSLv3: - Fctx := SslCtxNew(SslMethodV3); - LT_TLSv1: - Fctx := SslCtxNew(SslMethodTLSV1); - LT_all: - Fctx := SslCtxNew(SslMethodV23); - else - Exit; - end; - if Fctx = nil then - begin - SSLCheck; - Exit; - end - else - begin - s := FCiphers; - SslCtxSetCipherList(Fctx, s); - if FVerifyCert then - SslCtxSetVerify(FCtx, SSL_VERIFY_PEER, nil) - else - SslCtxSetVerify(FCtx, SSL_VERIFY_NONE, nil); -{$IFNDEF CIL} - SslCtxSetDefaultPasswdCb(FCtx, @PasswordCallback); - SslCtxSetDefaultPasswdCbUserdata(FCtx, self); -{$ENDIF} - - if server and (FCertificateFile = '') and (FCertificate = '') - and (FPFXfile = '') and (FPFX = '') then - begin - CreateSelfSignedcert(FSocket.ResolveIPToName(FSocket.GetRemoteSinIP)); - end; - - if not SetSSLKeys then - Exit - else - begin - Fssl := nil; - Fssl := SslNew(Fctx); - if Fssl = nil then - begin - SSLCheck; - exit; - end; - end; - end; - Result := true; -end; - -function TSSLOpenSSL.DeInit: Boolean; -begin - Result := True; - if assigned (Fssl) then - sslfree(Fssl); - Fssl := nil; - if assigned (Fctx) then - begin - SslCtxFree(Fctx); - Fctx := nil; - ErrRemoveState(0); - end; - FSSLEnabled := False; -end; - -function TSSLOpenSSL.Prepare(server:Boolean): Boolean; -begin - Result := false; - DeInit; - if Init(server) then - Result := true - else - DeInit; -end; - -function TSSLOpenSSL.Connect: boolean; -var - x: integer; - b: boolean; - err: integer; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(False) then - begin -{$IFDEF CIL} - if sslsetfd(FSsl, FSocket.Socket.Handle.ToInt32) < 1 then -{$ELSE} - if sslsetfd(FSsl, FSocket.Socket) < 1 then -{$ENDIF} - begin - SSLCheck; - Exit; - end; - if SNIHost<>'' then - SSLCtrl(Fssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, PAnsiChar(AnsiString(SNIHost))); - if FSocket.ConnectionTimeout <= 0 then //do blocking call of SSL_Connect - begin - x := sslconnect(FSsl); - if x < 1 then - begin - SSLcheck; - Exit; - end; - end - else //do non-blocking call of SSL_Connect - begin - b := Fsocket.NonBlockMode; - Fsocket.NonBlockMode := true; - repeat - x := sslconnect(FSsl); - err := SslGetError(FSsl, x); - if err = SSL_ERROR_WANT_READ then - if not FSocket.CanRead(FSocket.ConnectionTimeout) then - break; - if err = SSL_ERROR_WANT_WRITE then - if not FSocket.CanWrite(FSocket.ConnectionTimeout) then - break; - until (err <> SSL_ERROR_WANT_READ) and (err <> SSL_ERROR_WANT_WRITE); - Fsocket.NonBlockMode := b; - if err <> SSL_ERROR_NONE then - begin - SSLcheck; - Exit; - end; - end; - if FverifyCert then - if (GetVerifyCert <> 0) or (not DoVerifyCert) then - Exit; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLOpenSSL.Accept: boolean; -var - x: integer; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(True) then - begin -{$IFDEF CIL} - if sslsetfd(FSsl, FSocket.Socket.Handle.ToInt32) < 1 then -{$ELSE} - if sslsetfd(FSsl, FSocket.Socket) < 1 then -{$ENDIF} - begin - SSLCheck; - Exit; - end; - x := sslAccept(FSsl); - if x < 1 then - begin - SSLcheck; - Exit; - end; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLOpenSSL.Shutdown: boolean; -begin - if assigned(FSsl) then - sslshutdown(FSsl); - DeInit; - Result := True; -end; - -function TSSLOpenSSL.BiShutdown: boolean; -var - x: integer; -begin - if assigned(FSsl) then - begin - x := sslshutdown(FSsl); - if x = 0 then - begin - Synsock.Shutdown(FSocket.Socket, 1); - sslshutdown(FSsl); - end; - end; - DeInit; - Result := True; -end; - -function TSSLOpenSSL.SendBuffer(Buffer: TMemory; Len: Integer): Integer; -var - err: integer; -{$IFDEF CIL} - s: ansistring; -{$ENDIF} -begin - FLastError := 0; - FLastErrorDesc := ''; - repeat -{$IFDEF CIL} - s := StringOf(Buffer); - Result := SslWrite(FSsl, s, Len); -{$ELSE} - Result := SslWrite(FSsl, Buffer , Len); -{$ENDIF} - err := SslGetError(FSsl, Result); - until (err <> SSL_ERROR_WANT_READ) and (err <> SSL_ERROR_WANT_WRITE); - if err = SSL_ERROR_ZERO_RETURN then - Result := 0 - else - if (err <> 0) then - FLastError := err; -end; - -function TSSLOpenSSL.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -var - err: integer; -{$IFDEF CIL} - sb: stringbuilder; - s: ansistring; -{$ENDIF} -begin - FLastError := 0; - FLastErrorDesc := ''; - repeat -{$IFDEF CIL} - sb := StringBuilder.Create(Len); - Result := SslRead(FSsl, sb, Len); - if Result > 0 then - begin - sb.Length := Result; - s := sb.ToString; - System.Array.Copy(BytesOf(s), Buffer, length(s)); - end; -{$ELSE} - Result := SslRead(FSsl, Buffer , Len); -{$ENDIF} - err := SslGetError(FSsl, Result); - until (err <> SSL_ERROR_WANT_READ) and (err <> SSL_ERROR_WANT_WRITE); - if err = SSL_ERROR_ZERO_RETURN then - Result := 0 - {pf}// Verze 1.1.0 byla s else tak jak to ted mam, - // ve verzi 1.1.1 bylo ELSE zruseno, ale pak je SSL_ERROR_ZERO_RETURN - // propagovano jako Chyba. - {pf} else {/pf} if (err <> 0) then - FLastError := err; -end; - -function TSSLOpenSSL.WaitingData: Integer; -begin - Result := sslpending(Fssl); -end; - -function TSSLOpenSSL.GetSSLVersion: string; -begin - if not assigned(FSsl) then - Result := '' - else - Result := SSlGetVersion(FSsl); -end; - -function TSSLOpenSSL.GetPeerSubject: string; -var - cert: PX509; - s: ansistring; -{$IFDEF CIL} - sb: StringBuilder; -{$ENDIF} -begin - if not assigned(FSsl) then - begin - Result := ''; - Exit; - end; - cert := SSLGetPeerCertificate(Fssl); - if not assigned(cert) then - begin - Result := ''; - Exit; - end; -{$IFDEF CIL} - sb := StringBuilder.Create(4096); - Result := X509NameOneline(X509GetSubjectName(cert), sb, 4096); -{$ELSE} - setlength(s, 4096); - Result := X509NameOneline(X509GetSubjectName(cert), s, Length(s)); -{$ENDIF} - X509Free(cert); -end; - - -function TSSLOpenSSL.GetPeerSerialNo: integer; {pf} -var - cert: PX509; - SN: PASN1_INTEGER; -begin - if not assigned(FSsl) then - begin - Result := -1; - Exit; - end; - cert := SSLGetPeerCertificate(Fssl); - try - if not assigned(cert) then - begin - Result := -1; - Exit; - end; - SN := X509GetSerialNumber(cert); - Result := Asn1IntegerGet(SN); - finally - X509Free(cert); - end; -end; - -function TSSLOpenSSL.GetPeerName: string; -var - s: ansistring; -begin - s := GetPeerSubject; - s := SeparateRight(s, '/CN='); - Result := Trim(SeparateLeft(s, '/')); -end; - -function TSSLOpenSSL.GetPeerNameHash: cardinal; {pf} -var - cert: PX509; -begin - if not assigned(FSsl) then - begin - Result := 0; - Exit; - end; - cert := SSLGetPeerCertificate(Fssl); - try - if not assigned(cert) then - begin - Result := 0; - Exit; - end; - Result := X509NameHash(X509GetSubjectName(cert)); - finally - X509Free(cert); - end; -end; - -function TSSLOpenSSL.GetPeerIssuer: string; -var - cert: PX509; - s: ansistring; -{$IFDEF CIL} - sb: StringBuilder; -{$ENDIF} -begin - if not assigned(FSsl) then - begin - Result := ''; - Exit; - end; - cert := SSLGetPeerCertificate(Fssl); - if not assigned(cert) then - begin - Result := ''; - Exit; - end; -{$IFDEF CIL} - sb := StringBuilder.Create(4096); - Result := X509NameOneline(X509GetIssuerName(cert), sb, 4096); -{$ELSE} - setlength(s, 4096); - Result := X509NameOneline(X509GetIssuerName(cert), s, Length(s)); -{$ENDIF} - X509Free(cert); -end; - -function TSSLOpenSSL.GetPeerFingerprint: string; -var - cert: PX509; - x: integer; -{$IFDEF CIL} - sb: StringBuilder; -{$ENDIF} -begin - if not assigned(FSsl) then - begin - Result := ''; - Exit; - end; - cert := SSLGetPeerCertificate(Fssl); - if not assigned(cert) then - begin - Result := ''; - Exit; - end; -{$IFDEF CIL} - sb := StringBuilder.Create(EVP_MAX_MD_SIZE); - X509Digest(cert, EvpGetDigestByName('MD5'), sb, x); - sb.Length := x; - Result := sb.ToString; -{$ELSE} - setlength(Result, EVP_MAX_MD_SIZE); - X509Digest(cert, EvpGetDigestByName('MD5'), Result, x); - SetLength(Result, x); -{$ENDIF} - X509Free(cert); -end; - -function TSSLOpenSSL.GetCertInfo: string; -var - cert: PX509; - x, y: integer; - b: PBIO; - s: AnsiString; -{$IFDEF CIL} - sb: stringbuilder; -{$ENDIF} -begin - if not assigned(FSsl) then - begin - Result := ''; - Exit; - end; - cert := SSLGetPeerCertificate(Fssl); - if not assigned(cert) then - begin - Result := ''; - Exit; - end; - try {pf} - b := BioNew(BioSMem); - try - X509Print(b, cert); - x := bioctrlpending(b); - {$IFDEF CIL} - sb := StringBuilder.Create(x); - y := bioread(b, sb, x); - if y > 0 then - begin - sb.Length := y; - s := sb.ToString; - end; - {$ELSE} - setlength(s,x); - y := bioread(b,s,x); - if y > 0 then - setlength(s, y); - {$ENDIF} - Result := ReplaceString(s, LF, CRLF); - finally - BioFreeAll(b); - end; - {pf} - finally - X509Free(cert); - end; - {/pf} -end; - -function TSSLOpenSSL.GetCipherName: string; -begin - if not assigned(FSsl) then - Result := '' - else - Result := SslCipherGetName(SslGetCurrentCipher(FSsl)); -end; - -function TSSLOpenSSL.GetCipherBits: integer; -var - x: integer; -begin - if not assigned(FSsl) then - Result := 0 - else - Result := SSLCipherGetBits(SslGetCurrentCipher(FSsl), x); -end; - -function TSSLOpenSSL.GetCipherAlgBits: integer; -begin - if not assigned(FSsl) then - Result := 0 - else - SSLCipherGetBits(SslGetCurrentCipher(FSsl), Result); -end; - -function TSSLOpenSSL.GetVerifyCert: integer; -begin - if not assigned(FSsl) then - Result := 1 - else - Result := SslGetVerifyResult(FSsl); -end; - -{==============================================================================} - -initialization - if InitSSLInterface then - SSLImplementation := TSSLOpenSSL; - -end. diff --git a/3rd/synapse/source/ssl_openssl_lib.pas b/3rd/synapse/source/ssl_openssl_lib.pas deleted file mode 100644 index 9fa6e8cd7..000000000 --- a/3rd/synapse/source/ssl_openssl_lib.pas +++ /dev/null @@ -1,2160 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 003.007.002 | -|==============================================================================| -| Content: SSL support by OpenSSL | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2002-2013. | -| Portions created by Petr Fejfar are Copyright (c)2011-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{ -Special thanks to Gregor Ibic <gregor.ibic@intelicom.si> - (Intelicom d.o.o., http://www.intelicom.si) - for good inspiration about begin with SSL programming. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$IFDEF VER125} - {$DEFINE BCB} -{$ENDIF} -{$IFDEF BCB} - {$ObjExportAll On} - (*$HPPEMIT 'namespace ssl_openssl_lib { using System::Shortint; }' *) -{$ENDIF} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{:@abstract(OpenSSL support) - -This unit is Pascal interface to OpenSSL library (used by @link(ssl_openssl) unit). -OpenSSL is loaded dynamicly on-demand. If this library is not found in system, -requested OpenSSL function just return errorcode. -} -unit ssl_openssl_lib; - -interface - -uses -{$IFDEF CIL} - System.Runtime.InteropServices, - System.Text, -{$ENDIF} - Classes, - synafpc, -{$IFNDEF MSWINDOWS} - {$IFDEF FPC} - {$IFDEF UNIX} - BaseUnix, - {$ENDIF UNIX} - {$ELSE} - Libc, - {$ENDIF} - SysUtils; -{$ELSE} - Windows; -{$ENDIF} - - -{$IFDEF CIL} -const - {$IFDEF LINUX} - DLLSSLName = 'libssl.so'; - DLLUtilName = 'libcrypto.so'; - {$ELSE} - DLLSSLName = 'ssleay32.dll'; - DLLUtilName = 'libeay32.dll'; - {$ENDIF} -{$ELSE} -var - {$IFNDEF MSWINDOWS} - {$IFDEF DARWIN} - DLLSSLName: string = 'libssl.dylib'; - DLLUtilName: string = 'libcrypto.dylib'; - {$ELSE} - {$IFDEF OS2} - {$IFDEF OS2GCC} - DLLSSLName: string = 'kssl.dll'; - DLLUtilName: string = 'kcrypto.dll'; - {$ELSE OS2GCC} - DLLSSLName: string = 'ssl.dll'; - DLLUtilName: string = 'crypto.dll'; - {$ENDIF OS2GCC} - {$ELSE OS2} - DLLSSLName: string = 'libssl.so'; - DLLUtilName: string = 'libcrypto.so'; - {$ENDIF OS2} - {$ENDIF} - {$ELSE} - DLLSSLName: string = 'ssleay32.dll'; - DLLSSLName2: string = 'libssl32.dll'; - DLLUtilName: string = 'libeay32.dll'; - {$ENDIF} -{$ENDIF} - -type -{$IFDEF CIL} - SslPtr = IntPtr; -{$ELSE} - SslPtr = Pointer; -{$ENDIF} - PSslPtr = ^SslPtr; - PSSL_CTX = SslPtr; - PSSL = SslPtr; - PSSL_METHOD = SslPtr; - PX509 = SslPtr; - PX509_NAME = SslPtr; - PEVP_MD = SslPtr; - PInteger = ^Integer; - PBIO_METHOD = SslPtr; - PBIO = SslPtr; - EVP_PKEY = SslPtr; - PRSA = SslPtr; - PASN1_UTCTIME = SslPtr; - PASN1_INTEGER = SslPtr; - PPasswdCb = SslPtr; - PFunction = procedure; - PSTACK = SslPtr; {pf} - TSkPopFreeFunc = procedure(p:SslPtr); cdecl; {pf} - TX509Free = procedure(x: PX509); cdecl; {pf} - - DES_cblock = array[0..7] of Byte; - PDES_cblock = ^DES_cblock; - des_ks_struct = packed record - ks: DES_cblock; - weak_key: Integer; - end; - des_key_schedule = array[1..16] of des_ks_struct; - -const - EVP_MAX_MD_SIZE = 16 + 20; - - SSL_ERROR_NONE = 0; - SSL_ERROR_SSL = 1; - SSL_ERROR_WANT_READ = 2; - SSL_ERROR_WANT_WRITE = 3; - SSL_ERROR_WANT_X509_LOOKUP = 4; - SSL_ERROR_SYSCALL = 5; //look at error stack/return value/errno - SSL_ERROR_ZERO_RETURN = 6; - SSL_ERROR_WANT_CONNECT = 7; - SSL_ERROR_WANT_ACCEPT = 8; - - SSL_OP_NO_SSLv2 = $01000000; - SSL_OP_NO_SSLv3 = $02000000; - SSL_OP_NO_TLSv1 = $04000000; - SSL_OP_ALL = $000FFFFF; - SSL_VERIFY_NONE = $00; - SSL_VERIFY_PEER = $01; - - OPENSSL_DES_DECRYPT = 0; - OPENSSL_DES_ENCRYPT = 1; - - X509_V_OK = 0; - X509_V_ILLEGAL = 1; - X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2; - X509_V_ERR_UNABLE_TO_GET_CRL = 3; - X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4; - X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5; - X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6; - X509_V_ERR_CERT_SIGNATURE_FAILURE = 7; - X509_V_ERR_CRL_SIGNATURE_FAILURE = 8; - X509_V_ERR_CERT_NOT_YET_VALID = 9; - X509_V_ERR_CERT_HAS_EXPIRED = 10; - X509_V_ERR_CRL_NOT_YET_VALID = 11; - X509_V_ERR_CRL_HAS_EXPIRED = 12; - X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13; - X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14; - X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15; - X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16; - X509_V_ERR_OUT_OF_MEM = 17; - X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18; - X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19; - X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20; - X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21; - X509_V_ERR_CERT_CHAIN_TOO_LONG = 22; - X509_V_ERR_CERT_REVOKED = 23; - X509_V_ERR_INVALID_CA = 24; - X509_V_ERR_PATH_LENGTH_EXCEEDED = 25; - X509_V_ERR_INVALID_PURPOSE = 26; - X509_V_ERR_CERT_UNTRUSTED = 27; - X509_V_ERR_CERT_REJECTED = 28; - //These are 'informational' when looking for issuer cert - X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29; - X509_V_ERR_AKID_SKID_MISMATCH = 30; - X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31; - X509_V_ERR_KEYUSAGE_NO_CERTSIGN = 32; - X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = 33; - X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = 34; - //The application is not happy - X509_V_ERR_APPLICATION_VERIFICATION = 50; - - SSL_FILETYPE_ASN1 = 2; - SSL_FILETYPE_PEM = 1; - EVP_PKEY_RSA = 6; - - SSL_CTRL_SET_TLSEXT_HOSTNAME = 55; - TLSEXT_NAMETYPE_host_name = 0; - -var - SSLLibHandle: TLibHandle = 0; - SSLUtilHandle: TLibHandle = 0; - SSLLibFile: string = ''; - SSLUtilFile: string = ''; - -{$IFDEF CIL} - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_get_error')] - function SslGetError(s: PSSL; ret_code: Integer): Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_library_init')] - function SslLibraryInit: Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_load_error_strings')] - procedure SslLoadErrorStrings; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_set_cipher_list')] - function SslCtxSetCipherList(arg0: PSSL_CTX; var str: String): Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_new')] - function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_free')] - procedure SslCtxFree (arg0: PSSL_CTX); external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_set_fd')] - function SslSetFd(s: PSSL; fd: Integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSLv2_method')] - function SslMethodV2 : PSSL_METHOD; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSLv3_method')] - function SslMethodV3 : PSSL_METHOD; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'TLSv1_method')] - function SslMethodTLSV1:PSSL_METHOD; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSLv23_method')] - function SslMethodV23 : PSSL_METHOD; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_PrivateKey')] - function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_PrivateKey_ASN1')] - function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: String; len: integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_RSAPrivateKey_file')] - function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_certificate')] - function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_certificate_ASN1')] - function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: String):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_certificate_file')] - function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: String; _type: Integer):Integer;external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_use_certificate_chain_file')] - function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: String):Integer;external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_check_private_key')] - function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_set_default_passwd_cb')] - procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb); external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_set_default_passwd_cb_userdata')] - procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: IntPtr); external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_load_verify_locations')] - function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; CAfile: string; CApath: String):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_ctrl')] - function SslCtxCtrl(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: IntPtr): integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_new')] - function SslNew(ctx: PSSL_CTX):PSSL; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_free')] - procedure SslFree(ssl: PSSL); external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_accept')] - function SslAccept(ssl: PSSL):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_connect')] - function SslConnect(ssl: PSSL):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_shutdown')] - function SslShutdown(s: PSSL):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_read')] - function SslRead(ssl: PSSL; buf: StringBuilder; num: Integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_peek')] - function SslPeek(ssl: PSSL; buf: StringBuilder; num: Integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_write')] - function SslWrite(ssl: PSSL; buf: String; num: Integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_pending')] - function SslPending(ssl: PSSL):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_get_version')] - function SslGetVersion(ssl: PSSL):String; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_get_peer_certificate')] - function SslGetPeerCertificate(s: PSSL):PX509; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CTX_set_verify')] - procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction); external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_get_current_cipher')] - function SSLGetCurrentCipher(s: PSSL): SslPtr; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CIPHER_get_name')] - function SSLCipherGetName(c: SslPtr):String; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_CIPHER_get_bits')] - function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer; external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_get_verify_result')] - function SSLGetVerifyResult(ssl: PSSL):Integer;external; - - [DllImport(DLLSSLName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSL_ctrl')] - function SslCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: IntPtr): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_new')] - function X509New: PX509; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_free')] - procedure X509Free(x: PX509); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_NAME_oneline')] - function X509NameOneline(a: PX509_NAME; buf: StringBuilder; size: Integer): String; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_get_subject_name')] - function X509GetSubjectName(a: PX509):PX509_NAME; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_get_issuer_name')] - function X509GetIssuerName(a: PX509):PX509_NAME; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_NAME_hash')] - function X509NameHash(x: PX509_NAME):Cardinal; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_digest')] - function X509Digest (data: PX509; _type: PEVP_MD; md: StringBuilder; var len: Integer):Integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_set_version')] - function X509SetVersion(x: PX509; version: integer): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_set_pubkey')] - function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_set_issuer_name')] - function X509SetIssuerName(x: PX509; name: PX509_NAME): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_NAME_add_entry_by_txt')] - function X509NameAddEntryByTxt(name: PX509_NAME; field: string; _type: integer; - bytes: string; len, loc, _set: integer): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_sign')] - function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_print')] - function X509print(b: PBIO; a: PX509): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_gmtime_adj')] - function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_set_notBefore')] - function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_set_notAfter')] - function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'X509_get_serialNumber')] - function X509GetSerialNumber(x: PX509): PASN1_INTEGER; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'EVP_PKEY_new')] - function EvpPkeyNew: EVP_PKEY; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'EVP_PKEY_free')] - procedure EvpPkeyFree(pk: EVP_PKEY); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'EVP_PKEY_assign')] - function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'EVP_get_digestbyname')] - function EvpGetDigestByName(Name: String): PEVP_MD; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'EVP_cleanup')] - procedure EVPcleanup; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'SSLeay_version')] - function SSLeayversion(t: integer): String; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ERR_error_string_n')] - procedure ErrErrorString(e: integer; buf: StringBuilder; len: integer); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ERR_get_error')] - function ErrGetError: integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ERR_clear_error')] - procedure ErrClearError; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ERR_free_strings')] - procedure ErrFreeStrings; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ERR_remove_state')] - procedure ErrRemoveState(pid: integer); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'OPENSSL_add_all_algorithms_noconf')] - procedure OPENSSLaddallalgorithms; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'CRYPTO_cleanup_all_ex_data')] - procedure CRYPTOcleanupAllExData; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'RAND_screen')] - procedure RandScreen; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'BIO_new')] - function BioNew(b: PBIO_METHOD): PBIO; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'BIO_free_all')] - procedure BioFreeAll(b: PBIO); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'BIO_s_mem')] - function BioSMem: PBIO_METHOD; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'BIO_ctrl_pending')] - function BioCtrlPending(b: PBIO): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'BIO_read')] - function BioRead(b: PBIO; Buf: StringBuilder; Len: integer): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'BIO_write')] - function BioWrite(b: PBIO; var Buf: String; Len: integer): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'd2i_PKCS12_bio')] - function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'PKCS12_parse')] - function PKCS12parse(p12: SslPtr; pass: string; var pkey, cert, ca: SslPtr): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'PKCS12_free')] - procedure PKCS12free(p12: SslPtr); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'RSA_generate_key')] - function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ASN1_UTCTIME_new')] - function Asn1UtctimeNew: PASN1_UTCTIME; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ASN1_UTCTIME_free')] - procedure Asn1UtctimeFree(a: PASN1_UTCTIME); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'ASN1_INTEGER_set')] - function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'i2d_X509_bio')] - function i2dX509bio(b: PBIO; x: PX509): integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'i2d_PrivateKey_bio')] - function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer; external; - - // 3DES functions - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'DES_set_odd_parity')] - procedure DESsetoddparity(Key: des_cblock); external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'DES_set_key_checked')] - function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer; external; - - [DllImport(DLLUtilName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'DES_ecb_encrypt')] - procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); external; - -{$ELSE} -// libssl.dll - function SslGetError(s: PSSL; ret_code: Integer):Integer; - function SslLibraryInit:Integer; - procedure SslLoadErrorStrings; -// function SslCtxSetCipherList(arg0: PSSL_CTX; str: PChar):Integer; - function SslCtxSetCipherList(arg0: PSSL_CTX; var str: AnsiString):Integer; - function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX; - procedure SslCtxFree(arg0: PSSL_CTX); - function SslSetFd(s: PSSL; fd: Integer):Integer; - function SslMethodV2:PSSL_METHOD; - function SslMethodV3:PSSL_METHOD; - function SslMethodTLSV1:PSSL_METHOD; - function SslMethodV23:PSSL_METHOD; - function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer; - function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: AnsiString; len: integer):Integer; -// function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer; - function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; - function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer; - function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: AnsiString):Integer; - function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; -// function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: PChar):Integer; - function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: AnsiString):Integer; - function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer; - procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb); - procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: SslPtr); -// function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer; - function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: AnsiString; const CApath: AnsiString):Integer; - function SslCtxCtrl(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: SslPtr): integer; - function SslNew(ctx: PSSL_CTX):PSSL; - procedure SslFree(ssl: PSSL); - function SslAccept(ssl: PSSL):Integer; - function SslConnect(ssl: PSSL):Integer; - function SslShutdown(ssl: PSSL):Integer; - function SslRead(ssl: PSSL; buf: SslPtr; num: Integer):Integer; - function SslPeek(ssl: PSSL; buf: SslPtr; num: Integer):Integer; - function SslWrite(ssl: PSSL; buf: SslPtr; num: Integer):Integer; - function SslPending(ssl: PSSL):Integer; - function SslGetVersion(ssl: PSSL):AnsiString; - function SslGetPeerCertificate(ssl: PSSL):PX509; - procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction); - function SSLGetCurrentCipher(s: PSSL):SslPtr; - function SSLCipherGetName(c: SslPtr): AnsiString; - function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer; - function SSLGetVerifyResult(ssl: PSSL):Integer; - function SSLCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; - -// libeay.dll - function X509New: PX509; - procedure X509Free(x: PX509); - function X509NameOneline(a: PX509_NAME; var buf: AnsiString; size: Integer):AnsiString; - function X509GetSubjectName(a: PX509):PX509_NAME; - function X509GetIssuerName(a: PX509):PX509_NAME; - function X509NameHash(x: PX509_NAME):Cardinal; -// function SslX509Digest(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer; - function X509Digest(data: PX509; _type: PEVP_MD; md: AnsiString; var len: Integer):Integer; - function X509print(b: PBIO; a: PX509): integer; - function X509SetVersion(x: PX509; version: integer): integer; - function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer; - function X509SetIssuerName(x: PX509; name: PX509_NAME): integer; - function X509NameAddEntryByTxt(name: PX509_NAME; field: Ansistring; _type: integer; - bytes: Ansistring; len, loc, _set: integer): integer; - function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; - function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; - function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer; - function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer; - function X509GetSerialNumber(x: PX509): PASN1_INTEGER; - function EvpPkeyNew: EVP_PKEY; - procedure EvpPkeyFree(pk: EVP_PKEY); - function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; - function EvpGetDigestByName(Name: AnsiString): PEVP_MD; - procedure EVPcleanup; -// function ErrErrorString(e: integer; buf: PChar): PChar; - function SSLeayversion(t: integer): Ansistring; - procedure ErrErrorString(e: integer; var buf: Ansistring; len: integer); - function ErrGetError: integer; - procedure ErrClearError; - procedure ErrFreeStrings; - procedure ErrRemoveState(pid: integer); - procedure OPENSSLaddallalgorithms; - procedure CRYPTOcleanupAllExData; - procedure RandScreen; - function BioNew(b: PBIO_METHOD): PBIO; - procedure BioFreeAll(b: PBIO); - function BioSMem: PBIO_METHOD; - function BioCtrlPending(b: PBIO): integer; - function BioRead(b: PBIO; var Buf: AnsiString; Len: integer): integer; - function BioWrite(b: PBIO; Buf: AnsiString; Len: integer): integer; - function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr; - function PKCS12parse(p12: SslPtr; pass: Ansistring; var pkey, cert, ca: SslPtr): integer; - procedure PKCS12free(p12: SslPtr); - function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; - function Asn1UtctimeNew: PASN1_UTCTIME; - procedure Asn1UtctimeFree(a: PASN1_UTCTIME); - function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer; - function Asn1IntegerGet(a: PASN1_INTEGER): integer; {pf} - function i2dX509bio(b: PBIO; x: PX509): integer; - function d2iX509bio(b:PBIO; x:PX509): PX509; {pf} - function PEMReadBioX509(b:PBIO; {var x:PX509;}x:PSslPtr; callback:PFunction; cb_arg: SslPtr): PX509; {pf} - procedure SkX509PopFree(st: PSTACK; func: TSkPopFreeFunc); {pf} - - - function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer; - - // 3DES functions - procedure DESsetoddparity(Key: des_cblock); - function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer; - procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); - -{$ENDIF} - -function IsSSLloaded: Boolean; -function InitSSLInterface: Boolean; -function DestroySSLInterface: Boolean; - -var - _X509Free: TX509Free = nil; {pf} - -implementation - -uses -{$IFDEF OS2} - Sockets, -{$ENDIF OS2} - SyncObjs; - -{$IFNDEF CIL} -type -// libssl.dll - TSslGetError = function(s: PSSL; ret_code: Integer):Integer; cdecl; - TSslLibraryInit = function:Integer; cdecl; - TSslLoadErrorStrings = procedure; cdecl; - TSslCtxSetCipherList = function(arg0: PSSL_CTX; str: PAnsiChar):Integer; cdecl; - TSslCtxNew = function(meth: PSSL_METHOD):PSSL_CTX; cdecl; - TSslCtxFree = procedure(arg0: PSSL_CTX); cdecl; - TSslSetFd = function(s: PSSL; fd: Integer):Integer; cdecl; - TSslMethodV2 = function:PSSL_METHOD; cdecl; - TSslMethodV3 = function:PSSL_METHOD; cdecl; - TSslMethodTLSV1 = function:PSSL_METHOD; cdecl; - TSslMethodV23 = function:PSSL_METHOD; cdecl; - TSslCtxUsePrivateKey = function(ctx: PSSL_CTX; pkey: sslptr):Integer; cdecl; - TSslCtxUsePrivateKeyASN1 = function(pk: integer; ctx: PSSL_CTX; d: sslptr; len: integer):Integer; cdecl; - TSslCtxUsePrivateKeyFile = function(ctx: PSSL_CTX; const _file: PAnsiChar; _type: Integer):Integer; cdecl; - TSslCtxUseCertificate = function(ctx: PSSL_CTX; x: SslPtr):Integer; cdecl; - TSslCtxUseCertificateASN1 = function(ctx: PSSL_CTX; len: Integer; d: SslPtr):Integer; cdecl; - TSslCtxUseCertificateFile = function(ctx: PSSL_CTX; const _file: PAnsiChar; _type: Integer):Integer; cdecl; - TSslCtxUseCertificateChainFile = function(ctx: PSSL_CTX; const _file: PAnsiChar):Integer; cdecl; - TSslCtxCheckPrivateKeyFile = function(ctx: PSSL_CTX):Integer; cdecl; - TSslCtxSetDefaultPasswdCb = procedure(ctx: PSSL_CTX; cb: SslPtr); cdecl; - TSslCtxSetDefaultPasswdCbUserdata = procedure(ctx: PSSL_CTX; u: SslPtr); cdecl; - TSslCtxLoadVerifyLocations = function(ctx: PSSL_CTX; const CAfile: PAnsiChar; const CApath: PAnsiChar):Integer; cdecl; - TSslCtxCtrl = function(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: SslPtr): integer; cdecl; - TSslNew = function(ctx: PSSL_CTX):PSSL; cdecl; - TSslFree = procedure(ssl: PSSL); cdecl; - TSslAccept = function(ssl: PSSL):Integer; cdecl; - TSslConnect = function(ssl: PSSL):Integer; cdecl; - TSslShutdown = function(ssl: PSSL):Integer; cdecl; - TSslRead = function(ssl: PSSL; buf: PAnsiChar; num: Integer):Integer; cdecl; - TSslPeek = function(ssl: PSSL; buf: PAnsiChar; num: Integer):Integer; cdecl; - TSslWrite = function(ssl: PSSL; const buf: PAnsiChar; num: Integer):Integer; cdecl; - TSslPending = function(ssl: PSSL):Integer; cdecl; - TSslGetVersion = function(ssl: PSSL):PAnsiChar; cdecl; - TSslGetPeerCertificate = function(ssl: PSSL):PX509; cdecl; - TSslCtxSetVerify = procedure(ctx: PSSL_CTX; mode: Integer; arg2: SslPtr); cdecl; - TSSLGetCurrentCipher = function(s: PSSL):SslPtr; cdecl; - TSSLCipherGetName = function(c: Sslptr):PAnsiChar; cdecl; - TSSLCipherGetBits = function(c: SslPtr; alg_bits: PInteger):Integer; cdecl; - TSSLGetVerifyResult = function(ssl: PSSL):Integer; cdecl; - TSSLCtrl = function(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; cdecl; - - TSSLSetTlsextHostName = function(ssl: PSSL; buf: PAnsiChar):Integer; cdecl; - -// libeay.dll - TX509New = function: PX509; cdecl; - TX509NameOneline = function(a: PX509_NAME; buf: PAnsiChar; size: Integer):PAnsiChar; cdecl; - TX509GetSubjectName = function(a: PX509):PX509_NAME; cdecl; - TX509GetIssuerName = function(a: PX509):PX509_NAME; cdecl; - TX509NameHash = function(x: PX509_NAME):Cardinal; cdecl; - TX509Digest = function(data: PX509; _type: PEVP_MD; md: PAnsiChar; len: PInteger):Integer; cdecl; - TX509print = function(b: PBIO; a: PX509): integer; cdecl; - TX509SetVersion = function(x: PX509; version: integer): integer; cdecl; - TX509SetPubkey = function(x: PX509; pkey: EVP_PKEY): integer; cdecl; - TX509SetIssuerName = function(x: PX509; name: PX509_NAME): integer; cdecl; - TX509NameAddEntryByTxt = function(name: PX509_NAME; field: PAnsiChar; _type: integer; - bytes: PAnsiChar; len, loc, _set: integer): integer; cdecl; - TX509Sign = function(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; cdecl; - TX509GmtimeAdj = function(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; cdecl; - TX509SetNotBefore = function(x: PX509; tm: PASN1_UTCTIME): integer; cdecl; - TX509SetNotAfter = function(x: PX509; tm: PASN1_UTCTIME): integer; cdecl; - TX509GetSerialNumber = function(x: PX509): PASN1_INTEGER; cdecl; - TEvpPkeyNew = function: EVP_PKEY; cdecl; - TEvpPkeyFree = procedure(pk: EVP_PKEY); cdecl; - TEvpPkeyAssign = function(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; cdecl; - TEvpGetDigestByName = function(Name: PAnsiChar): PEVP_MD; cdecl; - TEVPcleanup = procedure; cdecl; - TSSLeayversion = function(t: integer): PAnsiChar; cdecl; - TErrErrorString = procedure(e: integer; buf: PAnsiChar; len: integer); cdecl; - TErrGetError = function: integer; cdecl; - TErrClearError = procedure; cdecl; - TErrFreeStrings = procedure; cdecl; - TErrRemoveState = procedure(pid: integer); cdecl; - TOPENSSLaddallalgorithms = procedure; cdecl; - TCRYPTOcleanupAllExData = procedure; cdecl; - TRandScreen = procedure; cdecl; - TBioNew = function(b: PBIO_METHOD): PBIO; cdecl; - TBioFreeAll = procedure(b: PBIO); cdecl; - TBioSMem = function: PBIO_METHOD; cdecl; - TBioCtrlPending = function(b: PBIO): integer; cdecl; - TBioRead = function(b: PBIO; Buf: PAnsiChar; Len: integer): integer; cdecl; - TBioWrite = function(b: PBIO; Buf: PAnsiChar; Len: integer): integer; cdecl; - Td2iPKCS12bio = function(b:PBIO; Pkcs12: SslPtr): SslPtr; cdecl; - TPKCS12parse = function(p12: SslPtr; pass: PAnsiChar; var pkey, cert, ca: SslPtr): integer; cdecl; - TPKCS12free = procedure(p12: SslPtr); cdecl; - TRsaGenerateKey = function(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; cdecl; - TAsn1UtctimeNew = function: PASN1_UTCTIME; cdecl; - TAsn1UtctimeFree = procedure(a: PASN1_UTCTIME); cdecl; - TAsn1IntegerSet = function(a: PASN1_INTEGER; v: integer): integer; cdecl; - TAsn1IntegerGet = function(a: PASN1_INTEGER): integer; cdecl; {pf} - Ti2dX509bio = function(b: PBIO; x: PX509): integer; cdecl; - Td2iX509bio = function(b:PBIO; x:PX509): PX509; cdecl; {pf} - TPEMReadBioX509 = function(b:PBIO; {var x:PX509;}x:PSslPtr; callback:PFunction; cb_arg:SslPtr): PX509; cdecl; {pf} - TSkX509PopFree = procedure(st: PSTACK; func: TSkPopFreeFunc); cdecl; {pf} - Ti2dPrivateKeyBio= function(b: PBIO; pkey: EVP_PKEY): integer; cdecl; - - // 3DES functions - TDESsetoddparity = procedure(Key: des_cblock); cdecl; - TDESsetkeychecked = function(key: des_cblock; schedule: des_key_schedule): Integer; cdecl; - TDESecbencrypt = procedure(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); cdecl; - //thread lock functions - TCRYPTOnumlocks = function: integer; cdecl; - TCRYPTOSetLockingCallback = procedure(cb: Sslptr); cdecl; - -var -// libssl.dll - _SslGetError: TSslGetError = nil; - _SslLibraryInit: TSslLibraryInit = nil; - _SslLoadErrorStrings: TSslLoadErrorStrings = nil; - _SslCtxSetCipherList: TSslCtxSetCipherList = nil; - _SslCtxNew: TSslCtxNew = nil; - _SslCtxFree: TSslCtxFree = nil; - _SslSetFd: TSslSetFd = nil; - _SslMethodV2: TSslMethodV2 = nil; - _SslMethodV3: TSslMethodV3 = nil; - _SslMethodTLSV1: TSslMethodTLSV1 = nil; - _SslMethodV23: TSslMethodV23 = nil; - _SslCtxUsePrivateKey: TSslCtxUsePrivateKey = nil; - _SslCtxUsePrivateKeyASN1: TSslCtxUsePrivateKeyASN1 = nil; - _SslCtxUsePrivateKeyFile: TSslCtxUsePrivateKeyFile = nil; - _SslCtxUseCertificate: TSslCtxUseCertificate = nil; - _SslCtxUseCertificateASN1: TSslCtxUseCertificateASN1 = nil; - _SslCtxUseCertificateFile: TSslCtxUseCertificateFile = nil; - _SslCtxUseCertificateChainFile: TSslCtxUseCertificateChainFile = nil; - _SslCtxCheckPrivateKeyFile: TSslCtxCheckPrivateKeyFile = nil; - _SslCtxSetDefaultPasswdCb: TSslCtxSetDefaultPasswdCb = nil; - _SslCtxSetDefaultPasswdCbUserdata: TSslCtxSetDefaultPasswdCbUserdata = nil; - _SslCtxLoadVerifyLocations: TSslCtxLoadVerifyLocations = nil; - _SslCtxCtrl: TSslCtxCtrl = nil; - _SslNew: TSslNew = nil; - _SslFree: TSslFree = nil; - _SslAccept: TSslAccept = nil; - _SslConnect: TSslConnect = nil; - _SslShutdown: TSslShutdown = nil; - _SslRead: TSslRead = nil; - _SslPeek: TSslPeek = nil; - _SslWrite: TSslWrite = nil; - _SslPending: TSslPending = nil; - _SslGetVersion: TSslGetVersion = nil; - _SslGetPeerCertificate: TSslGetPeerCertificate = nil; - _SslCtxSetVerify: TSslCtxSetVerify = nil; - _SSLGetCurrentCipher: TSSLGetCurrentCipher = nil; - _SSLCipherGetName: TSSLCipherGetName = nil; - _SSLCipherGetBits: TSSLCipherGetBits = nil; - _SSLGetVerifyResult: TSSLGetVerifyResult = nil; - _SSLCtrl: TSSLCtrl = nil; - -// libeay.dll - _X509New: TX509New = nil; - _X509NameOneline: TX509NameOneline = nil; - _X509GetSubjectName: TX509GetSubjectName = nil; - _X509GetIssuerName: TX509GetIssuerName = nil; - _X509NameHash: TX509NameHash = nil; - _X509Digest: TX509Digest = nil; - _X509print: TX509print = nil; - _X509SetVersion: TX509SetVersion = nil; - _X509SetPubkey: TX509SetPubkey = nil; - _X509SetIssuerName: TX509SetIssuerName = nil; - _X509NameAddEntryByTxt: TX509NameAddEntryByTxt = nil; - _X509Sign: TX509Sign = nil; - _X509GmtimeAdj: TX509GmtimeAdj = nil; - _X509SetNotBefore: TX509SetNotBefore = nil; - _X509SetNotAfter: TX509SetNotAfter = nil; - _X509GetSerialNumber: TX509GetSerialNumber = nil; - _EvpPkeyNew: TEvpPkeyNew = nil; - _EvpPkeyFree: TEvpPkeyFree = nil; - _EvpPkeyAssign: TEvpPkeyAssign = nil; - _EvpGetDigestByName: TEvpGetDigestByName = nil; - _EVPcleanup: TEVPcleanup = nil; - _SSLeayversion: TSSLeayversion = nil; - _ErrErrorString: TErrErrorString = nil; - _ErrGetError: TErrGetError = nil; - _ErrClearError: TErrClearError = nil; - _ErrFreeStrings: TErrFreeStrings = nil; - _ErrRemoveState: TErrRemoveState = nil; - _OPENSSLaddallalgorithms: TOPENSSLaddallalgorithms = nil; - _CRYPTOcleanupAllExData: TCRYPTOcleanupAllExData = nil; - _RandScreen: TRandScreen = nil; - _BioNew: TBioNew = nil; - _BioFreeAll: TBioFreeAll = nil; - _BioSMem: TBioSMem = nil; - _BioCtrlPending: TBioCtrlPending = nil; - _BioRead: TBioRead = nil; - _BioWrite: TBioWrite = nil; - _d2iPKCS12bio: Td2iPKCS12bio = nil; - _PKCS12parse: TPKCS12parse = nil; - _PKCS12free: TPKCS12free = nil; - _RsaGenerateKey: TRsaGenerateKey = nil; - _Asn1UtctimeNew: TAsn1UtctimeNew = nil; - _Asn1UtctimeFree: TAsn1UtctimeFree = nil; - _Asn1IntegerSet: TAsn1IntegerSet = nil; - _Asn1IntegerGet: TAsn1IntegerGet = nil; {pf} - _i2dX509bio: Ti2dX509bio = nil; - _d2iX509bio: Td2iX509bio = nil; {pf} - _PEMReadBioX509: TPEMReadBioX509 = nil; {pf} - _SkX509PopFree: TSkX509PopFree = nil; {pf} - _i2dPrivateKeyBio: Ti2dPrivateKeyBio = nil; - - // 3DES functions - _DESsetoddparity: TDESsetoddparity = nil; - _DESsetkeychecked: TDESsetkeychecked = nil; - _DESecbencrypt: TDESecbencrypt = nil; - //thread lock functions - _CRYPTOnumlocks: TCRYPTOnumlocks = nil; - _CRYPTOSetLockingCallback: TCRYPTOSetLockingCallback = nil; -{$ENDIF} - -var - SSLCS: TCriticalSection; - SSLloaded: boolean = false; -{$IFNDEF CIL} - Locks: TList; -{$ENDIF} - -{$IFNDEF CIL} -// libssl.dll -function SslGetError(s: PSSL; ret_code: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslGetError) then - Result := _SslGetError(s, ret_code) - else - Result := SSL_ERROR_SSL; -end; - -function SslLibraryInit:Integer; -begin - if InitSSLInterface and Assigned(_SslLibraryInit) then - Result := _SslLibraryInit - else - Result := 1; -end; - -procedure SslLoadErrorStrings; -begin - if InitSSLInterface and Assigned(_SslLoadErrorStrings) then - _SslLoadErrorStrings; -end; - -//function SslCtxSetCipherList(arg0: PSSL_CTX; str: PChar):Integer; -function SslCtxSetCipherList(arg0: PSSL_CTX; var str: AnsiString):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxSetCipherList) then - Result := _SslCtxSetCipherList(arg0, PAnsiChar(str)) - else - Result := 0; -end; - -function SslCtxNew(meth: PSSL_METHOD):PSSL_CTX; -begin - if InitSSLInterface and Assigned(_SslCtxNew) then - Result := _SslCtxNew(meth) - else - Result := nil; -end; - -procedure SslCtxFree(arg0: PSSL_CTX); -begin - if InitSSLInterface and Assigned(_SslCtxFree) then - _SslCtxFree(arg0); -end; - -function SslSetFd(s: PSSL; fd: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslSetFd) then - Result := _SslSetFd(s, fd) - else - Result := 0; -end; - -function SslMethodV2:PSSL_METHOD; -begin - if InitSSLInterface and Assigned(_SslMethodV2) then - Result := _SslMethodV2 - else - Result := nil; -end; - -function SslMethodV3:PSSL_METHOD; -begin - if InitSSLInterface and Assigned(_SslMethodV3) then - Result := _SslMethodV3 - else - Result := nil; -end; - -function SslMethodTLSV1:PSSL_METHOD; -begin - if InitSSLInterface and Assigned(_SslMethodTLSV1) then - Result := _SslMethodTLSV1 - else - Result := nil; -end; - -function SslMethodV23:PSSL_METHOD; -begin - if InitSSLInterface and Assigned(_SslMethodV23) then - Result := _SslMethodV23 - else - Result := nil; -end; - -function SslCtxUsePrivateKey(ctx: PSSL_CTX; pkey: SslPtr):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUsePrivateKey) then - Result := _SslCtxUsePrivateKey(ctx, pkey) - else - Result := 0; -end; - -function SslCtxUsePrivateKeyASN1(pk: integer; ctx: PSSL_CTX; d: AnsiString; len: integer):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUsePrivateKeyASN1) then - Result := _SslCtxUsePrivateKeyASN1(pk, ctx, Sslptr(d), len) - else - Result := 0; -end; - -//function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: PChar; _type: Integer):Integer; -function SslCtxUsePrivateKeyFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUsePrivateKeyFile) then - Result := _SslCtxUsePrivateKeyFile(ctx, PAnsiChar(_file), _type) - else - Result := 0; -end; - -function SslCtxUseCertificate(ctx: PSSL_CTX; x: SslPtr):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUseCertificate) then - Result := _SslCtxUseCertificate(ctx, x) - else - Result := 0; -end; - -function SslCtxUseCertificateASN1(ctx: PSSL_CTX; len: integer; d: AnsiString):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUseCertificateASN1) then - Result := _SslCtxUseCertificateASN1(ctx, len, SslPtr(d)) - else - Result := 0; -end; - -function SslCtxUseCertificateFile(ctx: PSSL_CTX; const _file: AnsiString; _type: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUseCertificateFile) then - Result := _SslCtxUseCertificateFile(ctx, PAnsiChar(_file), _type) - else - Result := 0; -end; - -//function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: PChar):Integer; -function SslCtxUseCertificateChainFile(ctx: PSSL_CTX; const _file: AnsiString):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxUseCertificateChainFile) then - Result := _SslCtxUseCertificateChainFile(ctx, PAnsiChar(_file)) - else - Result := 0; -end; - -function SslCtxCheckPrivateKeyFile(ctx: PSSL_CTX):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxCheckPrivateKeyFile) then - Result := _SslCtxCheckPrivateKeyFile(ctx) - else - Result := 0; -end; - -procedure SslCtxSetDefaultPasswdCb(ctx: PSSL_CTX; cb: PPasswdCb); -begin - if InitSSLInterface and Assigned(_SslCtxSetDefaultPasswdCb) then - _SslCtxSetDefaultPasswdCb(ctx, cb); -end; - -procedure SslCtxSetDefaultPasswdCbUserdata(ctx: PSSL_CTX; u: SslPtr); -begin - if InitSSLInterface and Assigned(_SslCtxSetDefaultPasswdCbUserdata) then - _SslCtxSetDefaultPasswdCbUserdata(ctx, u); -end; - -//function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: PChar; const CApath: PChar):Integer; -function SslCtxLoadVerifyLocations(ctx: PSSL_CTX; const CAfile: AnsiString; const CApath: AnsiString):Integer; -begin - if InitSSLInterface and Assigned(_SslCtxLoadVerifyLocations) then - Result := _SslCtxLoadVerifyLocations(ctx, SslPtr(CAfile), SslPtr(CApath)) - else - Result := 0; -end; - -function SslCtxCtrl(ctx: PSSL_CTX; cmd: integer; larg: integer; parg: SslPtr): integer; -begin - if InitSSLInterface and Assigned(_SslCtxCtrl) then - Result := _SslCtxCtrl(ctx, cmd, larg, parg) - else - Result := 0; -end; - -function SslNew(ctx: PSSL_CTX):PSSL; -begin - if InitSSLInterface and Assigned(_SslNew) then - Result := _SslNew(ctx) - else - Result := nil; -end; - -procedure SslFree(ssl: PSSL); -begin - if InitSSLInterface and Assigned(_SslFree) then - _SslFree(ssl); -end; - -function SslAccept(ssl: PSSL):Integer; -begin - if InitSSLInterface and Assigned(_SslAccept) then - Result := _SslAccept(ssl) - else - Result := -1; -end; - -function SslConnect(ssl: PSSL):Integer; -begin - if InitSSLInterface and Assigned(_SslConnect) then - Result := _SslConnect(ssl) - else - Result := -1; -end; - -function SslShutdown(ssl: PSSL):Integer; -begin - if InitSSLInterface and Assigned(_SslShutdown) then - Result := _SslShutdown(ssl) - else - Result := -1; -end; - -//function SslRead(ssl: PSSL; buf: PChar; num: Integer):Integer; -function SslRead(ssl: PSSL; buf: SslPtr; num: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslRead) then - Result := _SslRead(ssl, PAnsiChar(buf), num) - else - Result := -1; -end; - -//function SslPeek(ssl: PSSL; buf: PChar; num: Integer):Integer; -function SslPeek(ssl: PSSL; buf: SslPtr; num: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslPeek) then - Result := _SslPeek(ssl, PAnsiChar(buf), num) - else - Result := -1; -end; - -//function SslWrite(ssl: PSSL; const buf: PChar; num: Integer):Integer; -function SslWrite(ssl: PSSL; buf: SslPtr; num: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SslWrite) then - Result := _SslWrite(ssl, PAnsiChar(buf), num) - else - Result := -1; -end; - -function SslPending(ssl: PSSL):Integer; -begin - if InitSSLInterface and Assigned(_SslPending) then - Result := _SslPending(ssl) - else - Result := 0; -end; - -//function SslGetVersion(ssl: PSSL):PChar; -function SslGetVersion(ssl: PSSL):AnsiString; -begin - if InitSSLInterface and Assigned(_SslGetVersion) then - Result := _SslGetVersion(ssl) - else - Result := ''; -end; - -function SslGetPeerCertificate(ssl: PSSL):PX509; -begin - if InitSSLInterface and Assigned(_SslGetPeerCertificate) then - Result := _SslGetPeerCertificate(ssl) - else - Result := nil; -end; - -//procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: SslPtr); -procedure SslCtxSetVerify(ctx: PSSL_CTX; mode: Integer; arg2: PFunction); -begin - if InitSSLInterface and Assigned(_SslCtxSetVerify) then - _SslCtxSetVerify(ctx, mode, @arg2); -end; - -function SSLGetCurrentCipher(s: PSSL):SslPtr; -begin - if InitSSLInterface and Assigned(_SSLGetCurrentCipher) then -{$IFDEF CIL} -{$ELSE} - Result := _SSLGetCurrentCipher(s) -{$ENDIF} - else - Result := nil; -end; - -//function SSLCipherGetName(c: SslPtr):PChar; -function SSLCipherGetName(c: SslPtr):AnsiString; -begin - if InitSSLInterface and Assigned(_SSLCipherGetName) then - Result := _SSLCipherGetName(c) - else - Result := ''; -end; - -//function SSLCipherGetBits(c: SslPtr; alg_bits: PInteger):Integer; -function SSLCipherGetBits(c: SslPtr; var alg_bits: Integer):Integer; -begin - if InitSSLInterface and Assigned(_SSLCipherGetBits) then - Result := _SSLCipherGetBits(c, @alg_bits) - else - Result := 0; -end; - -function SSLGetVerifyResult(ssl: PSSL):Integer; -begin - if InitSSLInterface and Assigned(_SSLGetVerifyResult) then - Result := _SSLGetVerifyResult(ssl) - else - Result := X509_V_ERR_APPLICATION_VERIFICATION; -end; - - -function SSLCtrl(ssl: PSSL; cmd: integer; larg: integer; parg: SslPtr):Integer; -begin - if InitSSLInterface and Assigned(_SSLCtrl) then - Result := _SSLCtrl(ssl, cmd, larg, parg) - else - Result := X509_V_ERR_APPLICATION_VERIFICATION; -end; - -// libeay.dll -function X509New: PX509; -begin - if InitSSLInterface and Assigned(_X509New) then - Result := _X509New - else - Result := nil; -end; - -procedure X509Free(x: PX509); -begin - if InitSSLInterface and Assigned(_X509Free) then - _X509Free(x); -end; - -//function SslX509NameOneline(a: PX509_NAME; buf: PChar; size: Integer):PChar; -function X509NameOneline(a: PX509_NAME; var buf: AnsiString; size: Integer):AnsiString; -begin - if InitSSLInterface and Assigned(_X509NameOneline) then - Result := _X509NameOneline(a, PAnsiChar(buf),size) - else - Result := ''; -end; - -function X509GetSubjectName(a: PX509):PX509_NAME; -begin - if InitSSLInterface and Assigned(_X509GetSubjectName) then - Result := _X509GetSubjectName(a) - else - Result := nil; -end; - -function X509GetIssuerName(a: PX509):PX509_NAME; -begin - if InitSSLInterface and Assigned(_X509GetIssuerName) then - Result := _X509GetIssuerName(a) - else - Result := nil; -end; - -function X509NameHash(x: PX509_NAME):Cardinal; -begin - if InitSSLInterface and Assigned(_X509NameHash) then - Result := _X509NameHash(x) - else - Result := 0; -end; - -//function SslX509Digest(data: PX509; _type: PEVP_MD; md: PChar; len: PInteger):Integer; -function X509Digest(data: PX509; _type: PEVP_MD; md: AnsiString; var len: Integer):Integer; -begin - if InitSSLInterface and Assigned(_X509Digest) then - Result := _X509Digest(data, _type, PAnsiChar(md), @len) - else - Result := 0; -end; - -function EvpPkeyNew: EVP_PKEY; -begin - if InitSSLInterface and Assigned(_EvpPkeyNew) then - Result := _EvpPkeyNew - else - Result := nil; -end; - -procedure EvpPkeyFree(pk: EVP_PKEY); -begin - if InitSSLInterface and Assigned(_EvpPkeyFree) then - _EvpPkeyFree(pk); -end; - -function SSLeayversion(t: integer): Ansistring; -begin - if InitSSLInterface and Assigned(_SSLeayversion) then - Result := PAnsiChar(_SSLeayversion(t)) - else - Result := ''; -end; - -procedure ErrErrorString(e: integer; var buf: Ansistring; len: integer); -begin - if InitSSLInterface and Assigned(_ErrErrorString) then - _ErrErrorString(e, Pointer(buf), len); - buf := PAnsiChar(Buf); -end; - -function ErrGetError: integer; -begin - if InitSSLInterface and Assigned(_ErrGetError) then - Result := _ErrGetError - else - Result := SSL_ERROR_SSL; -end; - -procedure ErrClearError; -begin - if InitSSLInterface and Assigned(_ErrClearError) then - _ErrClearError; -end; - -procedure ErrFreeStrings; -begin - if InitSSLInterface and Assigned(_ErrFreeStrings) then - _ErrFreeStrings; -end; - -procedure ErrRemoveState(pid: integer); -begin - if InitSSLInterface and Assigned(_ErrRemoveState) then - _ErrRemoveState(pid); -end; - -procedure OPENSSLaddallalgorithms; -begin - if InitSSLInterface and Assigned(_OPENSSLaddallalgorithms) then - _OPENSSLaddallalgorithms; -end; - -procedure EVPcleanup; -begin - if InitSSLInterface and Assigned(_EVPcleanup) then - _EVPcleanup; -end; - -procedure CRYPTOcleanupAllExData; -begin - if InitSSLInterface and Assigned(_CRYPTOcleanupAllExData) then - _CRYPTOcleanupAllExData; -end; - -procedure RandScreen; -begin - if InitSSLInterface and Assigned(_RandScreen) then - _RandScreen; -end; - -function BioNew(b: PBIO_METHOD): PBIO; -begin - if InitSSLInterface and Assigned(_BioNew) then - Result := _BioNew(b) - else - Result := nil; -end; - -procedure BioFreeAll(b: PBIO); -begin - if InitSSLInterface and Assigned(_BioFreeAll) then - _BioFreeAll(b); -end; - -function BioSMem: PBIO_METHOD; -begin - if InitSSLInterface and Assigned(_BioSMem) then - Result := _BioSMem - else - Result := nil; -end; - -function BioCtrlPending(b: PBIO): integer; -begin - if InitSSLInterface and Assigned(_BioCtrlPending) then - Result := _BioCtrlPending(b) - else - Result := 0; -end; - -//function BioRead(b: PBIO; Buf: PChar; Len: integer): integer; -function BioRead(b: PBIO; var Buf: AnsiString; Len: integer): integer; -begin - if InitSSLInterface and Assigned(_BioRead) then - Result := _BioRead(b, PAnsiChar(Buf), Len) - else - Result := -2; -end; - -//function BioWrite(b: PBIO; Buf: PChar; Len: integer): integer; -function BioWrite(b: PBIO; Buf: AnsiString; Len: integer): integer; -begin - if InitSSLInterface and Assigned(_BioWrite) then - Result := _BioWrite(b, PAnsiChar(Buf), Len) - else - Result := -2; -end; - -function X509print(b: PBIO; a: PX509): integer; -begin - if InitSSLInterface and Assigned(_X509print) then - Result := _X509print(b, a) - else - Result := 0; -end; - -function d2iPKCS12bio(b:PBIO; Pkcs12: SslPtr): SslPtr; -begin - if InitSSLInterface and Assigned(_d2iPKCS12bio) then - Result := _d2iPKCS12bio(b, Pkcs12) - else - Result := nil; -end; - -function PKCS12parse(p12: SslPtr; pass: Ansistring; var pkey, cert, ca: SslPtr): integer; -begin - if InitSSLInterface and Assigned(_PKCS12parse) then - Result := _PKCS12parse(p12, SslPtr(pass), pkey, cert, ca) - else - Result := 0; -end; - -procedure PKCS12free(p12: SslPtr); -begin - if InitSSLInterface and Assigned(_PKCS12free) then - _PKCS12free(p12); -end; - -function RsaGenerateKey(bits, e: integer; callback: PFunction; cb_arg: SslPtr): PRSA; -begin - if InitSSLInterface and Assigned(_RsaGenerateKey) then - Result := _RsaGenerateKey(bits, e, callback, cb_arg) - else - Result := nil; -end; - -function EvpPkeyAssign(pkey: EVP_PKEY; _type: integer; key: Prsa): integer; -begin - if InitSSLInterface and Assigned(_EvpPkeyAssign) then - Result := _EvpPkeyAssign(pkey, _type, key) - else - Result := 0; -end; - -function X509SetVersion(x: PX509; version: integer): integer; -begin - if InitSSLInterface and Assigned(_X509SetVersion) then - Result := _X509SetVersion(x, version) - else - Result := 0; -end; - -function X509SetPubkey(x: PX509; pkey: EVP_PKEY): integer; -begin - if InitSSLInterface and Assigned(_X509SetPubkey) then - Result := _X509SetPubkey(x, pkey) - else - Result := 0; -end; - -function X509SetIssuerName(x: PX509; name: PX509_NAME): integer; -begin - if InitSSLInterface and Assigned(_X509SetIssuerName) then - Result := _X509SetIssuerName(x, name) - else - Result := 0; -end; - -function X509NameAddEntryByTxt(name: PX509_NAME; field: Ansistring; _type: integer; - bytes: Ansistring; len, loc, _set: integer): integer; -begin - if InitSSLInterface and Assigned(_X509NameAddEntryByTxt) then - Result := _X509NameAddEntryByTxt(name, PAnsiChar(field), _type, PAnsiChar(Bytes), len, loc, _set) - else - Result := 0; -end; - -function X509Sign(x: PX509; pkey: EVP_PKEY; const md: PEVP_MD): integer; -begin - if InitSSLInterface and Assigned(_X509Sign) then - Result := _X509Sign(x, pkey, md) - else - Result := 0; -end; - -function Asn1UtctimeNew: PASN1_UTCTIME; -begin - if InitSSLInterface and Assigned(_Asn1UtctimeNew) then - Result := _Asn1UtctimeNew - else - Result := nil; -end; - -procedure Asn1UtctimeFree(a: PASN1_UTCTIME); -begin - if InitSSLInterface and Assigned(_Asn1UtctimeFree) then - _Asn1UtctimeFree(a); -end; - -function X509GmtimeAdj(s: PASN1_UTCTIME; adj: integer): PASN1_UTCTIME; -begin - if InitSSLInterface and Assigned(_X509GmtimeAdj) then - Result := _X509GmtimeAdj(s, adj) - else - Result := nil; -end; - -function X509SetNotBefore(x: PX509; tm: PASN1_UTCTIME): integer; -begin - if InitSSLInterface and Assigned(_X509SetNotBefore) then - Result := _X509SetNotBefore(x, tm) - else - Result := 0; -end; - -function X509SetNotAfter(x: PX509; tm: PASN1_UTCTIME): integer; -begin - if InitSSLInterface and Assigned(_X509SetNotAfter) then - Result := _X509SetNotAfter(x, tm) - else - Result := 0; -end; - -function i2dX509bio(b: PBIO; x: PX509): integer; -begin - if InitSSLInterface and Assigned(_i2dX509bio) then - Result := _i2dX509bio(b, x) - else - Result := 0; -end; - -function d2iX509bio(b: PBIO; x: PX509): PX509; {pf} -begin - if InitSSLInterface and Assigned(_d2iX509bio) then - Result := _d2iX509bio(x,b) - else - Result := nil; -end; - -function PEMReadBioX509(b:PBIO; {var x:PX509;}x:PSslPtr; callback:PFunction; cb_arg: SslPtr): PX509; {pf} -begin - if InitSSLInterface and Assigned(_PEMReadBioX509) then - Result := _PEMReadBioX509(b,x,callback,cb_arg) - else - Result := nil; -end; - -procedure SkX509PopFree(st: PSTACK; func:TSkPopFreeFunc); {pf} -begin - if InitSSLInterface and Assigned(_SkX509PopFree) then - _SkX509PopFree(st,func); -end; - -function i2dPrivateKeyBio(b: PBIO; pkey: EVP_PKEY): integer; -begin - if InitSSLInterface and Assigned(_i2dPrivateKeyBio) then - Result := _i2dPrivateKeyBio(b, pkey) - else - Result := 0; -end; - -function EvpGetDigestByName(Name: AnsiString): PEVP_MD; -begin - if InitSSLInterface and Assigned(_EvpGetDigestByName) then - Result := _EvpGetDigestByName(PAnsiChar(Name)) - else - Result := nil; -end; - -function Asn1IntegerSet(a: PASN1_INTEGER; v: integer): integer; -begin - if InitSSLInterface and Assigned(_Asn1IntegerSet) then - Result := _Asn1IntegerSet(a, v) - else - Result := 0; -end; - -function Asn1IntegerGet(a: PASN1_INTEGER): integer; {pf} -begin - if InitSSLInterface and Assigned(_Asn1IntegerGet) then - Result := _Asn1IntegerGet(a) - else - Result := 0; -end; - -function X509GetSerialNumber(x: PX509): PASN1_INTEGER; -begin - if InitSSLInterface and Assigned(_X509GetSerialNumber) then - Result := _X509GetSerialNumber(x) - else - Result := nil; -end; - -// 3DES functions -procedure DESsetoddparity(Key: des_cblock); -begin - if InitSSLInterface and Assigned(_DESsetoddparity) then - _DESsetoddparity(Key); -end; - -function DESsetkeychecked(key: des_cblock; schedule: des_key_schedule): Integer; -begin - if InitSSLInterface and Assigned(_DESsetkeychecked) then - Result := _DESsetkeychecked(key, schedule) - else - Result := -1; -end; - -procedure DESecbencrypt(Input: des_cblock; output: des_cblock; ks: des_key_schedule; enc: Integer); -begin - if InitSSLInterface and Assigned(_DESecbencrypt) then - _DESecbencrypt(Input, output, ks, enc); -end; - -procedure locking_callback(mode, ltype: integer; lfile: PChar; line: integer); cdecl; -begin - if (mode and 1) > 0 then - TCriticalSection(Locks[ltype]).Enter - else - TCriticalSection(Locks[ltype]).Leave; -end; - -procedure InitLocks; -var - n: integer; - max: integer; -begin - Locks := TList.Create; - max := _CRYPTOnumlocks; - for n := 1 to max do - Locks.Add(TCriticalSection.Create); - _CRYPTOsetlockingcallback(@locking_callback); -end; - -procedure FreeLocks; -var - n: integer; -begin - _CRYPTOsetlockingcallback(nil); - for n := 0 to Locks.Count - 1 do - TCriticalSection(Locks[n]).Free; - Locks.Free; -end; - -{$ENDIF} - -function LoadLib(const Value: String): HModule; -begin -{$IFDEF CIL} - Result := LoadLibrary(Value); -{$ELSE} - Result := LoadLibrary(PChar(Value)); -{$ENDIF} -end; - -function GetProcAddr(module: HModule; const ProcName: string): SslPtr; -begin -{$IFDEF CIL} - Result := GetProcAddress(module, ProcName); -{$ELSE} - Result := GetProcAddress(module, PChar(ProcName)); -{$ENDIF} -end; - -function InitSSLInterface: Boolean; -var - s: string; - x: integer; -begin - {pf} - if SSLLoaded then - begin - Result := TRUE; - exit; - end; - {/pf} - SSLCS.Enter; - try - if not IsSSLloaded then - begin -{$IFDEF CIL} - SSLLibHandle := 1; - SSLUtilHandle := 1; -{$ELSE} - SSLUtilHandle := LoadLib(DLLUtilName); - SSLLibHandle := LoadLib(DLLSSLName); - {$IFDEF MSWINDOWS} - if (SSLLibHandle = 0) then - SSLLibHandle := LoadLib(DLLSSLName2); - {$ENDIF} -{$ENDIF} - if (SSLLibHandle <> 0) and (SSLUtilHandle <> 0) then - begin -{$IFNDEF CIL} - _SslGetError := GetProcAddr(SSLLibHandle, 'SSL_get_error'); - _SslLibraryInit := GetProcAddr(SSLLibHandle, 'SSL_library_init'); - _SslLoadErrorStrings := GetProcAddr(SSLLibHandle, 'SSL_load_error_strings'); - _SslCtxSetCipherList := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_cipher_list'); - _SslCtxNew := GetProcAddr(SSLLibHandle, 'SSL_CTX_new'); - _SslCtxFree := GetProcAddr(SSLLibHandle, 'SSL_CTX_free'); - _SslSetFd := GetProcAddr(SSLLibHandle, 'SSL_set_fd'); - _SslMethodV2 := GetProcAddr(SSLLibHandle, 'SSLv2_method'); - _SslMethodV3 := GetProcAddr(SSLLibHandle, 'SSLv3_method'); - _SslMethodTLSV1 := GetProcAddr(SSLLibHandle, 'TLSv1_method'); - _SslMethodV23 := GetProcAddr(SSLLibHandle, 'SSLv23_method'); - _SslCtxUsePrivateKey := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_PrivateKey'); - _SslCtxUsePrivateKeyASN1 := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_PrivateKey_ASN1'); - //use SSL_CTX_use_RSAPrivateKey_file instead SSL_CTX_use_PrivateKey_file, - //because SSL_CTX_use_PrivateKey_file not support DER format. :-O - _SslCtxUsePrivateKeyFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_RSAPrivateKey_file'); - _SslCtxUseCertificate := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate'); - _SslCtxUseCertificateASN1 := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_ASN1'); - _SslCtxUseCertificateFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_file'); - _SslCtxUseCertificateChainFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_use_certificate_chain_file'); - _SslCtxCheckPrivateKeyFile := GetProcAddr(SSLLibHandle, 'SSL_CTX_check_private_key'); - _SslCtxSetDefaultPasswdCb := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_default_passwd_cb'); - _SslCtxSetDefaultPasswdCbUserdata := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_default_passwd_cb_userdata'); - _SslCtxLoadVerifyLocations := GetProcAddr(SSLLibHandle, 'SSL_CTX_load_verify_locations'); - _SslCtxCtrl := GetProcAddr(SSLLibHandle, 'SSL_CTX_ctrl'); - _SslNew := GetProcAddr(SSLLibHandle, 'SSL_new'); - _SslFree := GetProcAddr(SSLLibHandle, 'SSL_free'); - _SslAccept := GetProcAddr(SSLLibHandle, 'SSL_accept'); - _SslConnect := GetProcAddr(SSLLibHandle, 'SSL_connect'); - _SslShutdown := GetProcAddr(SSLLibHandle, 'SSL_shutdown'); - _SslRead := GetProcAddr(SSLLibHandle, 'SSL_read'); - _SslPeek := GetProcAddr(SSLLibHandle, 'SSL_peek'); - _SslWrite := GetProcAddr(SSLLibHandle, 'SSL_write'); - _SslPending := GetProcAddr(SSLLibHandle, 'SSL_pending'); - _SslGetPeerCertificate := GetProcAddr(SSLLibHandle, 'SSL_get_peer_certificate'); - _SslGetVersion := GetProcAddr(SSLLibHandle, 'SSL_get_version'); - _SslCtxSetVerify := GetProcAddr(SSLLibHandle, 'SSL_CTX_set_verify'); - _SslGetCurrentCipher := GetProcAddr(SSLLibHandle, 'SSL_get_current_cipher'); - _SslCipherGetName := GetProcAddr(SSLLibHandle, 'SSL_CIPHER_get_name'); - _SslCipherGetBits := GetProcAddr(SSLLibHandle, 'SSL_CIPHER_get_bits'); - _SslGetVerifyResult := GetProcAddr(SSLLibHandle, 'SSL_get_verify_result'); - _SslCtrl := GetProcAddr(SSLLibHandle, 'SSL_ctrl'); - - _X509New := GetProcAddr(SSLUtilHandle, 'X509_new'); - _X509Free := GetProcAddr(SSLUtilHandle, 'X509_free'); - _X509NameOneline := GetProcAddr(SSLUtilHandle, 'X509_NAME_oneline'); - _X509GetSubjectName := GetProcAddr(SSLUtilHandle, 'X509_get_subject_name'); - _X509GetIssuerName := GetProcAddr(SSLUtilHandle, 'X509_get_issuer_name'); - _X509NameHash := GetProcAddr(SSLUtilHandle, 'X509_NAME_hash'); - _X509Digest := GetProcAddr(SSLUtilHandle, 'X509_digest'); - _X509print := GetProcAddr(SSLUtilHandle, 'X509_print'); - _X509SetVersion := GetProcAddr(SSLUtilHandle, 'X509_set_version'); - _X509SetPubkey := GetProcAddr(SSLUtilHandle, 'X509_set_pubkey'); - _X509SetIssuerName := GetProcAddr(SSLUtilHandle, 'X509_set_issuer_name'); - _X509NameAddEntryByTxt := GetProcAddr(SSLUtilHandle, 'X509_NAME_add_entry_by_txt'); - _X509Sign := GetProcAddr(SSLUtilHandle, 'X509_sign'); - _X509GmtimeAdj := GetProcAddr(SSLUtilHandle, 'X509_gmtime_adj'); - _X509SetNotBefore := GetProcAddr(SSLUtilHandle, 'X509_set_notBefore'); - _X509SetNotAfter := GetProcAddr(SSLUtilHandle, 'X509_set_notAfter'); - _X509GetSerialNumber := GetProcAddr(SSLUtilHandle, 'X509_get_serialNumber'); - _EvpPkeyNew := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_new'); - _EvpPkeyFree := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_free'); - _EvpPkeyAssign := GetProcAddr(SSLUtilHandle, 'EVP_PKEY_assign'); - _EVPCleanup := GetProcAddr(SSLUtilHandle, 'EVP_cleanup'); - _EvpGetDigestByName := GetProcAddr(SSLUtilHandle, 'EVP_get_digestbyname'); - _SSLeayversion := GetProcAddr(SSLUtilHandle, 'SSLeay_version'); - _ErrErrorString := GetProcAddr(SSLUtilHandle, 'ERR_error_string_n'); - _ErrGetError := GetProcAddr(SSLUtilHandle, 'ERR_get_error'); - _ErrClearError := GetProcAddr(SSLUtilHandle, 'ERR_clear_error'); - _ErrFreeStrings := GetProcAddr(SSLUtilHandle, 'ERR_free_strings'); - _ErrRemoveState := GetProcAddr(SSLUtilHandle, 'ERR_remove_state'); - _OPENSSLaddallalgorithms := GetProcAddr(SSLUtilHandle, 'OPENSSL_add_all_algorithms_noconf'); - _CRYPTOcleanupAllExData := GetProcAddr(SSLUtilHandle, 'CRYPTO_cleanup_all_ex_data'); - _RandScreen := GetProcAddr(SSLUtilHandle, 'RAND_screen'); - _BioNew := GetProcAddr(SSLUtilHandle, 'BIO_new'); - _BioFreeAll := GetProcAddr(SSLUtilHandle, 'BIO_free_all'); - _BioSMem := GetProcAddr(SSLUtilHandle, 'BIO_s_mem'); - _BioCtrlPending := GetProcAddr(SSLUtilHandle, 'BIO_ctrl_pending'); - _BioRead := GetProcAddr(SSLUtilHandle, 'BIO_read'); - _BioWrite := GetProcAddr(SSLUtilHandle, 'BIO_write'); - _d2iPKCS12bio := GetProcAddr(SSLUtilHandle, 'd2i_PKCS12_bio'); - _PKCS12parse := GetProcAddr(SSLUtilHandle, 'PKCS12_parse'); - _PKCS12free := GetProcAddr(SSLUtilHandle, 'PKCS12_free'); - _RsaGenerateKey := GetProcAddr(SSLUtilHandle, 'RSA_generate_key'); - _Asn1UtctimeNew := GetProcAddr(SSLUtilHandle, 'ASN1_UTCTIME_new'); - _Asn1UtctimeFree := GetProcAddr(SSLUtilHandle, 'ASN1_UTCTIME_free'); - _Asn1IntegerSet := GetProcAddr(SSLUtilHandle, 'ASN1_INTEGER_set'); - _Asn1IntegerGet := GetProcAddr(SSLUtilHandle, 'ASN1_INTEGER_get'); {pf} - _i2dX509bio := GetProcAddr(SSLUtilHandle, 'i2d_X509_bio'); - _d2iX509bio := GetProcAddr(SSLUtilHandle, 'd2i_X509_bio'); {pf} - _PEMReadBioX509 := GetProcAddr(SSLUtilHandle, 'PEM_read_bio_X509'); {pf} - _SkX509PopFree := GetProcAddr(SSLUtilHandle, 'SK_X509_POP_FREE'); {pf} - _i2dPrivateKeyBio := GetProcAddr(SSLUtilHandle, 'i2d_PrivateKey_bio'); - - // 3DES functions - _DESsetoddparity := GetProcAddr(SSLUtilHandle, 'DES_set_odd_parity'); - _DESsetkeychecked := GetProcAddr(SSLUtilHandle, 'DES_set_key_checked'); - _DESecbencrypt := GetProcAddr(SSLUtilHandle, 'DES_ecb_encrypt'); - // - _CRYPTOnumlocks := GetProcAddr(SSLUtilHandle, 'CRYPTO_num_locks'); - _CRYPTOsetlockingcallback := GetProcAddr(SSLUtilHandle, 'CRYPTO_set_locking_callback'); -{$ENDIF} -{$IFDEF CIL} - SslLibraryInit; - SslLoadErrorStrings; - OPENSSLaddallalgorithms; - RandScreen; -{$ELSE} - SetLength(s, 1024); - x := GetModuleFilename(SSLLibHandle,PChar(s),Length(s)); - SetLength(s, x); - SSLLibFile := s; - SetLength(s, 1024); - x := GetModuleFilename(SSLUtilHandle,PChar(s),Length(s)); - SetLength(s, x); - SSLUtilFile := s; - //init library - if assigned(_SslLibraryInit) then - _SslLibraryInit; - if assigned(_SslLoadErrorStrings) then - _SslLoadErrorStrings; - if assigned(_OPENSSLaddallalgorithms) then - _OPENSSLaddallalgorithms; - if assigned(_RandScreen) then - _RandScreen; - if assigned(_CRYPTOnumlocks) and assigned(_CRYPTOsetlockingcallback) then - InitLocks; -{$ENDIF} - SSLloaded := True; -{$IFDEF OS2} - Result := InitEMXHandles; -{$ELSE OS2} - Result := True; -{$ENDIF OS2} - end - else - begin - //load failed! - if SSLLibHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(SSLLibHandle); -{$ENDIF} - SSLLibHandle := 0; - end; - if SSLUtilHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(SSLUtilHandle); -{$ENDIF} - SSLLibHandle := 0; - end; - Result := False; - end; - end - else - //loaded before... - Result := true; - finally - SSLCS.Leave; - end; -end; - -function DestroySSLInterface: Boolean; -begin - SSLCS.Enter; - try - if IsSSLLoaded then - begin - //deinit library -{$IFNDEF CIL} - if assigned(_CRYPTOnumlocks) and assigned(_CRYPTOsetlockingcallback) then - FreeLocks; -{$ENDIF} - EVPCleanup; - CRYPTOcleanupAllExData; - ErrRemoveState(0); - end; - SSLloaded := false; - if SSLLibHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(SSLLibHandle); -{$ENDIF} - SSLLibHandle := 0; - end; - if SSLUtilHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(SSLUtilHandle); -{$ENDIF} - SSLLibHandle := 0; - end; - -{$IFNDEF CIL} - _SslGetError := nil; - _SslLibraryInit := nil; - _SslLoadErrorStrings := nil; - _SslCtxSetCipherList := nil; - _SslCtxNew := nil; - _SslCtxFree := nil; - _SslSetFd := nil; - _SslMethodV2 := nil; - _SslMethodV3 := nil; - _SslMethodTLSV1 := nil; - _SslMethodV23 := nil; - _SslCtxUsePrivateKey := nil; - _SslCtxUsePrivateKeyASN1 := nil; - _SslCtxUsePrivateKeyFile := nil; - _SslCtxUseCertificate := nil; - _SslCtxUseCertificateASN1 := nil; - _SslCtxUseCertificateFile := nil; - _SslCtxUseCertificateChainFile := nil; - _SslCtxCheckPrivateKeyFile := nil; - _SslCtxSetDefaultPasswdCb := nil; - _SslCtxSetDefaultPasswdCbUserdata := nil; - _SslCtxLoadVerifyLocations := nil; - _SslCtxCtrl := nil; - _SslNew := nil; - _SslFree := nil; - _SslAccept := nil; - _SslConnect := nil; - _SslShutdown := nil; - _SslRead := nil; - _SslPeek := nil; - _SslWrite := nil; - _SslPending := nil; - _SslGetPeerCertificate := nil; - _SslGetVersion := nil; - _SslCtxSetVerify := nil; - _SslGetCurrentCipher := nil; - _SslCipherGetName := nil; - _SslCipherGetBits := nil; - _SslGetVerifyResult := nil; - _SslCtrl := nil; - - _X509New := nil; - _X509Free := nil; - _X509NameOneline := nil; - _X509GetSubjectName := nil; - _X509GetIssuerName := nil; - _X509NameHash := nil; - _X509Digest := nil; - _X509print := nil; - _X509SetVersion := nil; - _X509SetPubkey := nil; - _X509SetIssuerName := nil; - _X509NameAddEntryByTxt := nil; - _X509Sign := nil; - _X509GmtimeAdj := nil; - _X509SetNotBefore := nil; - _X509SetNotAfter := nil; - _X509GetSerialNumber := nil; - _EvpPkeyNew := nil; - _EvpPkeyFree := nil; - _EvpPkeyAssign := nil; - _EVPCleanup := nil; - _EvpGetDigestByName := nil; - _SSLeayversion := nil; - _ErrErrorString := nil; - _ErrGetError := nil; - _ErrClearError := nil; - _ErrFreeStrings := nil; - _ErrRemoveState := nil; - _OPENSSLaddallalgorithms := nil; - _CRYPTOcleanupAllExData := nil; - _RandScreen := nil; - _BioNew := nil; - _BioFreeAll := nil; - _BioSMem := nil; - _BioCtrlPending := nil; - _BioRead := nil; - _BioWrite := nil; - _d2iPKCS12bio := nil; - _PKCS12parse := nil; - _PKCS12free := nil; - _RsaGenerateKey := nil; - _Asn1UtctimeNew := nil; - _Asn1UtctimeFree := nil; - _Asn1IntegerSet := nil; - _Asn1IntegerGet := nil; {pf} - _SkX509PopFree := nil; {pf} - _i2dX509bio := nil; - _i2dPrivateKeyBio := nil; - - // 3DES functions - _DESsetoddparity := nil; - _DESsetkeychecked := nil; - _DESecbencrypt := nil; - // - _CRYPTOnumlocks := nil; - _CRYPTOsetlockingcallback := nil; -{$ENDIF} - finally - SSLCS.Leave; - end; - Result := True; -end; - -function IsSSLloaded: Boolean; -begin - Result := SSLLoaded; -end; - -initialization -begin - SSLCS:= TCriticalSection.Create; -end; - -finalization -begin -{$IFNDEF CIL} - DestroySSLInterface; -{$ENDIF} - SSLCS.Free; -end; - -end. diff --git a/3rd/synapse/source/ssl_sbb.pas b/3rd/synapse/source/ssl_sbb.pas deleted file mode 100644 index c9380a481..000000000 --- a/3rd/synapse/source/ssl_sbb.pas +++ /dev/null @@ -1,697 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.000.003 | -|==============================================================================| -| Content: SSL support for SecureBlackBox | -|==============================================================================| -| Copyright (c)1999-2005, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2005. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Allen Drennan (adrennan@wiredred.com) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(SSL plugin for Eldos SecureBlackBox) - -For handling keys and certificates you can use this properties: -@link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA), -@link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate), -@link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey), -@link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate), -@link(TCustomSSL.PFXFile). For usage of this properties and for possible formats -of keys and certificates refer to SecureBlackBox documentation. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -unit ssl_sbb; - -interface - -uses - SysUtils, Classes, Windows, blcksock, synsock, synautil, synacode, - SBClient, SBServer, SBX509, SBWinCertStorage, SBCustomCertStorage, - SBUtils, SBConstants, SBSessionPool; - -const - DEFAULT_RECV_BUFFER=32768; - -type - {:@abstract(class implementing SecureBlackbox SSL plugin.) - Instance of this class will be created for each @link(TTCPBlockSocket). - You not need to create instance of this class, all is done by Synapse itself!} - TSSLSBB=class(TCustomSSL) - protected - FServer: Boolean; - FElSecureClient:TElSecureClient; - FElSecureServer:TElSecureServer; - FElCertStorage:TElMemoryCertStorage; - FElX509Certificate:TElX509Certificate; - FElX509CACertificate:TElX509Certificate; - FCipherSuites:TBits; - private - FRecvBuffer:String; - FRecvBuffers:String; - FRecvBuffersLock:TRTLCriticalSection; - FRecvDecodedBuffers:String; - function GetCipherSuite:Integer; - procedure Reset; - function Prepare(Server:Boolean):Boolean; - procedure OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean); - procedure OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt); - procedure OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt); - procedure OnData(Sender:TObject;Buffer:Pointer;Size:LongInt); - public - constructor Create(const Value: TTCPBlockSocket); override; - destructor Destroy; override; - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - {:See @inherited and @link(ssl_sbb) for more details.} - function Connect: boolean; override; - {:See @inherited and @link(ssl_sbb) for more details.} - function Accept: boolean; override; - {:See @inherited} - function Shutdown: boolean; override; - {:See @inherited} - function BiShutdown: boolean; override; - {:See @inherited} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function WaitingData: Integer; override; - {:See @inherited} - function GetSSLVersion: string; override; - {:See @inherited} - function GetPeerSubject: string; override; - {:See @inherited} - function GetPeerIssuer: string; override; - {:See @inherited} - function GetPeerName: string; override; - {:See @inherited} - function GetPeerFingerprint: string; override; - {:See @inherited} - function GetCertInfo: string; override; - published - property ElSecureClient:TElSecureClient read FElSecureClient write FElSecureClient; - property ElSecureServer:TElSecureServer read FElSecureServer write FElSecureServer; - property CipherSuites:TBits read FCipherSuites write FCipherSuites; - property CipherSuite:Integer read GetCipherSuite; - end; - -implementation - -var - FAcceptThread:THandle=0; - -// on error -procedure TSSLSBB.OnError(Sender:TObject; ErrorCode:Integer; Fatal:Boolean; Remote:Boolean); - -begin - FLastErrorDesc:=''; - FLastError:=ErrorCode; -end; - -// on send -procedure TSSLSBB.OnSend(Sender:TObject;Buffer:Pointer;Size:LongInt); - -var - lResult:Integer; - -begin - if FSocket.Socket=INVALID_SOCKET then - Exit; - lResult:=Send(FSocket.Socket,Buffer,Size,0); - if lResult=SOCKET_ERROR then - begin - FLastErrorDesc:=''; - FLastError:=WSAGetLastError; - end; -end; - -// on receive -procedure TSSLSBB.OnReceive(Sender:TObject;Buffer:Pointer;MaxSize:LongInt;var Written:LongInt); - -begin - if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock); - try - if Length(FRecvBuffers)<=MaxSize then - begin - Written:=Length(FRecvBuffers); - Move(FRecvBuffers[1],Buffer^,Written); - FRecvBuffers:=''; - end - else - begin - Written:=MaxSize; - Move(FRecvBuffers[1],Buffer^,Written); - Delete(FRecvBuffers,1,Written); - end; - finally - if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock); - end; -end; - -// on data -procedure TSSLSBB.OnData(Sender:TObject;Buffer:Pointer;Size:LongInt); - -var - lString:String; - -begin - SetLength(lString,Size); - Move(Buffer^,lString[1],Size); - FRecvDecodedBuffers:=FRecvDecodedBuffers+lString; -end; - -{ inherited } - -constructor TSSLSBB.Create(const Value: TTCPBlockSocket); - -var - loop1:Integer; - -begin - inherited Create(Value); - FServer:=FALSE; - FElSecureClient:=NIL; - FElSecureServer:=NIL; - FElCertStorage:=NIL; - FElX509Certificate:=NIL; - FElX509CACertificate:=NIL; - SetLength(FRecvBuffer,DEFAULT_RECV_BUFFER); - FRecvBuffers:=''; - InitializeCriticalSection(FRecvBuffersLock); - FRecvDecodedBuffers:=''; - FCipherSuites:=TBits.Create; - if FCipherSuites<>NIL then - begin - FCipherSuites.Size:=SB_SUITE_LAST+1; - for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do - FCipherSuites[loop1]:=TRUE; - end; -end; - -destructor TSSLSBB.Destroy; - -begin - Reset; - inherited Destroy; - if FCipherSuites<>NIL then - FreeAndNIL(FCipherSuites); - DeleteCriticalSection(FRecvBuffersLock); -end; - -function TSSLSBB.LibVersion: String; - -begin - Result:='SecureBlackBox'; -end; - -function TSSLSBB.LibName: String; - -begin - Result:='ssl_sbb'; -end; - -function FileToString(lFile:String):String; - -var - lStream:TMemoryStream; - -begin - Result:=''; - lStream:=TMemoryStream.Create; - if lStream<>NIL then - begin - lStream.LoadFromFile(lFile); - if lStream.Size>0 then - begin - lStream.Position:=0; - SetLength(Result,lStream.Size); - Move(lStream.Memory^,Result[1],lStream.Size); - end; - lStream.Free; - end; -end; - -function TSSLSBB.GetCipherSuite:Integer; - -begin - if FServer then - Result:=FElSecureServer.CipherSuite - else - Result:=FElSecureClient.CipherSuite; -end; - -procedure TSSLSBB.Reset; - -begin - if FElSecureServer<>NIL then - FreeAndNIL(FElSecureServer); - if FElSecureClient<>NIL then - FreeAndNIL(FElSecureClient); - if FElX509Certificate<>NIL then - FreeAndNIL(FElX509Certificate); - if FElX509CACertificate<>NIL then - FreeAndNIL(FElX509CACertificate); - if FElCertStorage<>NIL then - FreeAndNIL(FElCertStorage); - FSSLEnabled:=FALSE; -end; - -function TSSLSBB.Prepare(Server:Boolean): Boolean; - -var - loop1:Integer; - lStream:TMemoryStream; - lCertificate,lPrivateKey,lCertCA:String; - -begin - Result:=FALSE; - FServer:=Server; - - // reset, if necessary - Reset; - - // init, certificate - if FCertificateFile<>'' then - lCertificate:=FileToString(FCertificateFile) - else - lCertificate:=FCertificate; - if FPrivateKeyFile<>'' then - lPrivateKey:=FileToString(FPrivateKeyFile) - else - lPrivateKey:=FPrivateKey; - if FCertCAFile<>'' then - lCertCA:=FileToString(FCertCAFile) - else - lCertCA:=FCertCA; - if (lCertificate<>'') and (lPrivateKey<>'') then - begin - FElCertStorage:=TElMemoryCertStorage.Create(NIL); - if FElCertStorage<>NIL then - FElCertStorage.Clear; - - // apply ca certificate - if lCertCA<>'' then - begin - FElX509CACertificate:=TElX509Certificate.Create(NIL); - if FElX509CACertificate<>NIL then - begin - with FElX509CACertificate do - begin - lStream:=TMemoryStream.Create; - try - WriteStrToStream(lStream,lCertCA); - lStream.Seek(0,soFromBeginning); - LoadFromStream(lStream); - finally - lStream.Free; - end; - end; - if FElCertStorage<>NIL then - FElCertStorage.Add(FElX509CACertificate); - end; - end; - - // apply certificate - FElX509Certificate:=TElX509Certificate.Create(NIL); - if FElX509Certificate<>NIL then - begin - with FElX509Certificate do - begin - lStream:=TMemoryStream.Create; - try - WriteStrToStream(lStream,lCertificate); - lStream.Seek(0,soFromBeginning); - LoadFromStream(lStream); - finally - lStream.Free; - end; - lStream:=TMemoryStream.Create; - try - WriteStrToStream(lStream,lPrivateKey); - lStream.Seek(0,soFromBeginning); - LoadKeyFromStream(lStream); - finally - lStream.Free; - end; - if FElCertStorage<>NIL then - FElCertStorage.Add(FElX509Certificate); - end; - end; - end; - - // init, as server - if FServer then - begin - FElSecureServer:=TElSecureServer.Create(NIL); - if FElSecureServer<>NIL then - begin - // init, ciphers - for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do - FElSecureServer.CipherSuites[loop1]:=FCipherSuites[loop1]; - FElSecureServer.Versions:=[sbSSL2,sbSSL3,sbTLS1]; - FElSecureServer.ClientAuthentication:=FALSE; - FElSecureServer.OnError:=OnError; - FElSecureServer.OnSend:=OnSend; - FElSecureServer.OnReceive:=OnReceive; - FElSecureServer.OnData:=OnData; - FElSecureServer.CertStorage:=FElCertStorage; - Result:=TRUE; - end; - end - else - // init, as client - begin - FElSecureClient:=TElSecureClient.Create(NIL); - if FElSecureClient<>NIL then - begin - // init, ciphers - for loop1:=SB_SUITE_FIRST to SB_SUITE_LAST do - FElSecureClient.CipherSuites[loop1]:=FCipherSuites[loop1]; - FElSecureClient.Versions:=[sbSSL3,sbTLS1]; - FElSecureClient.OnError:=OnError; - FElSecureClient.OnSend:=OnSend; - FElSecureClient.OnReceive:=OnReceive; - FElSecureClient.OnData:=OnData; - FElSecureClient.CertStorage:=FElCertStorage; - Result:=TRUE; - end; - end; -end; - -function TSSLSBB.Connect:Boolean; - -var - lResult:Integer; - -begin - Result:=FALSE; - if FSocket.Socket=INVALID_SOCKET then - Exit; - if Prepare(FALSE) then - begin - FElSecureClient.Open; - - // reset - FRecvBuffers:=''; - FRecvDecodedBuffers:=''; - - // wait for open or error - while (not FElSecureClient.Active) and - (FLastError=0) do - begin - // data available? - if FRecvBuffers<>'' then - FElSecureClient.DataAvailable - else - begin - // socket recv - lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0); - if lResult=SOCKET_ERROR then - begin - FLastErrorDesc:=''; - FLastError:=WSAGetLastError; - end - else - begin - if lResult>0 then - FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult) - else - Break; - end; - end; - end; - if FLastError<>0 then - Exit; - FSSLEnabled:=FElSecureClient.Active; - Result:=FSSLEnabled; - end; -end; - -function TSSLSBB.Accept:Boolean; - -var - lResult:Integer; - -begin - Result:=FALSE; - if FSocket.Socket=INVALID_SOCKET then - Exit; - if Prepare(TRUE) then - begin - FAcceptThread:=GetCurrentThreadId; - FElSecureServer.Open; - - // reset - FRecvBuffers:=''; - FRecvDecodedBuffers:=''; - - // wait for open or error - while (not FElSecureServer.Active) and - (FLastError=0) do - begin - // data available? - if FRecvBuffers<>'' then - FElSecureServer.DataAvailable - else - begin - // socket recv - lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0); - if lResult=SOCKET_ERROR then - begin - FLastErrorDesc:=''; - FLastError:=WSAGetLastError; - end - else - begin - if lResult>0 then - FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult) - else - Break; - end; - end; - end; - if FLastError<>0 then - Exit; - FSSLEnabled:=FElSecureServer.Active; - Result:=FSSLEnabled; - end; -end; - -function TSSLSBB.Shutdown:Boolean; - -begin - Result:=BiShutdown; -end; - -function TSSLSBB.BiShutdown: boolean; - -begin - Reset; - Result:=TRUE; -end; - -function TSSLSBB.SendBuffer(Buffer: TMemory; Len: Integer): Integer; - -begin - if FServer then - FElSecureServer.SendData(Buffer,Len) - else - FElSecureClient.SendData(Buffer,Len); - Result:=Len; -end; - -function TSSLSBB.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; - -begin - Result:=0; - try - // recv waiting, if necessary - if FRecvDecodedBuffers='' then - WaitingData; - - // received - if Length(FRecvDecodedBuffers)<Len then - begin - Result:=Length(FRecvDecodedBuffers); - Move(FRecvDecodedBuffers[1],Buffer^,Result); - FRecvDecodedBuffers:=''; - end - else - begin - Result:=Len; - Move(FRecvDecodedBuffers[1],Buffer^,Result); - Delete(FRecvDecodedBuffers,1,Result); - end; - except - // ignore - end; -end; - -function TSSLSBB.WaitingData: Integer; - -var - lResult:Integer; - lRecvBuffers:Boolean; - -begin - Result:=0; - if FSocket.Socket=INVALID_SOCKET then - Exit; - // data available? - if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock); - try - lRecvBuffers:=FRecvBuffers<>''; - finally - if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock); - end; - if lRecvBuffers then - begin - if FServer then - FElSecureServer.DataAvailable - else - FElSecureClient.DataAvailable; - end - else - begin - // socket recv - lResult:=Recv(FSocket.Socket,@FRecvBuffer[1],Length(FRecvBuffer),0); - if lResult=SOCKET_ERROR then - begin - FLastErrorDesc:=''; - FLastError:=WSAGetLastError; - end - else - begin - if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock); - try - FRecvBuffers:=FRecvBuffers+Copy(FRecvBuffer,1,lResult); - finally - if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock); - end; - - // data available? - if GetCurrentThreadId<>FAcceptThread then EnterCriticalSection(FRecvBuffersLock); - try - lRecvBuffers:=FRecvBuffers<>''; - finally - if GetCurrentThreadId<>FAcceptThread then LeaveCriticalSection(FRecvBuffersLock); - end; - if lRecvBuffers then - begin - if FServer then - FElSecureServer.DataAvailable - else - FElSecureClient.DataAvailable; - end; - end; - end; - - // decoded buffers result - Result:=Length(FRecvDecodedBuffers); -end; - -function TSSLSBB.GetSSLVersion: string; - -begin - Result:='SSLv3 or TLSv1'; -end; - -function TSSLSBB.GetPeerSubject: string; - -begin - Result := ''; -// if FServer then - // must return subject of the client certificate -// else - // must return subject of the server certificate -end; - -function TSSLSBB.GetPeerName: string; - -begin - Result := ''; -// if FServer then - // must return commonname of the client certificate -// else - // must return commonname of the server certificate -end; - -function TSSLSBB.GetPeerIssuer: string; - -begin - Result := ''; -// if FServer then - // must return issuer of the client certificate -// else - // must return issuer of the server certificate -end; - -function TSSLSBB.GetPeerFingerprint: string; - -begin - Result := ''; -// if FServer then - // must return a unique hash string of the client certificate -// else - // must return a unique hash string of the server certificate -end; - -function TSSLSBB.GetCertInfo: string; - -begin - Result := ''; -// if FServer then - // must return a text representation of the ASN of the client certificate -// else - // must return a text representation of the ASN of the server certificate -end; - -{==============================================================================} - -initialization - SSLImplementation := TSSLSBB; - -finalization - -end. diff --git a/3rd/synapse/source/ssl_streamsec.pas b/3rd/synapse/source/ssl_streamsec.pas deleted file mode 100644 index 1dc67f95b..000000000 --- a/3rd/synapse/source/ssl_streamsec.pas +++ /dev/null @@ -1,539 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.000.006 | -|==============================================================================| -| Content: SSL support by StreamSecII | -|==============================================================================| -| Copyright (c)1999-2005, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2005. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Henrick Hellstr�m <henrick@streamsec.se> | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(SSL plugin for StreamSecII or OpenStreamSecII) - -StreamSecII is native pascal library, you not need any external libraries! - -You can tune lot of StreamSecII properties by using your GlobalServer. If you not -using your GlobalServer, then this plugin create own TSimpleTLSInternalServer -instance for each TCP connection. Formore information about GlobalServer usage -refer StreamSecII documentation. - -If you are not using key and certificate by GlobalServer, then you can use -properties of this plugin instead, but this have limited features and -@link(TCustomSSL.KeyPassword) not working properly yet! - -For handling keys and certificates you can use this properties: -@link(TCustomSSL.CertCAFile), @link(TCustomSSL.CertCA), -@link(TCustomSSL.TrustCertificateFile), @link(TCustomSSL.TrustCertificate), -@link(TCustomSSL.PrivateKeyFile), @link(TCustomSSL.PrivateKey), -@link(TCustomSSL.CertificateFile), @link(TCustomSSL.Certificate), -@link(TCustomSSL.PFXFile). For usage of this properties and for possible formats -of keys and certificates refer to StreamSecII documentation. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -unit ssl_streamsec; - -interface - -uses - SysUtils, Classes, - blcksock, synsock, synautil, synacode, - TlsInternalServer, TlsSynaSock, TlsConst, StreamSecII, Asn1, X509Base, - SecUtils; - -type - {:@exclude} - TMyTLSSynSockSlave = class(TTLSSynSockSlave) - protected - procedure SetMyTLSServer(const Value: TCustomTLSInternalServer); - function GetMyTLSServer: TCustomTLSInternalServer; - published - property MyTLSServer: TCustomTLSInternalServer read GetMyTLSServer write SetMyTLSServer; - end; - - {:@abstract(class implementing StreamSecII SSL plugin.) - Instance of this class will be created for each @link(TTCPBlockSocket). - You not need to create instance of this class, all is done by Synapse itself!} - TSSLStreamSec = class(TCustomSSL) - protected - FSlave: TMyTLSSynSockSlave; - FIsServer: Boolean; - FTLSServer: TCustomTLSInternalServer; - FServerCreated: Boolean; - function SSLCheck: Boolean; - function Init(server:Boolean): Boolean; - function DeInit: Boolean; - function Prepare(server:Boolean): Boolean; - procedure NotTrustEvent(Sender: TObject; Cert: TASN1Struct; var ExplicitTrust: Boolean); - function X500StrToStr(const Prefix: string; const Value: TX500String): string; - function X501NameToStr(const Value: TX501Name): string; - function GetCert: PASN1Struct; - public - constructor Create(const Value: TTCPBlockSocket); override; - destructor Destroy; override; - {:See @inherited} - function LibVersion: String; override; - {:See @inherited} - function LibName: String; override; - {:See @inherited and @link(ssl_streamsec) for more details.} - function Connect: boolean; override; - {:See @inherited and @link(ssl_streamsec) for more details.} - function Accept: boolean; override; - {:See @inherited} - function Shutdown: boolean; override; - {:See @inherited} - function BiShutdown: boolean; override; - {:See @inherited} - function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override; - {:See @inherited} - function WaitingData: Integer; override; - {:See @inherited} - function GetSSLVersion: string; override; - {:See @inherited} - function GetPeerSubject: string; override; - {:See @inherited} - function GetPeerIssuer: string; override; - {:See @inherited} - function GetPeerName: string; override; - {:See @inherited} - function GetPeerFingerprint: string; override; - {:See @inherited} - function GetCertInfo: string; override; - published - {:TLS server for tuning of StreamSecII.} - property TLSServer: TCustomTLSInternalServer read FTLSServer write FTLSServer; - end; - -implementation - -{==============================================================================} -procedure TMyTLSSynSockSlave.SetMyTLSServer(const Value: TCustomTLSInternalServer); -begin - TLSServer := Value; -end; - -function TMyTLSSynSockSlave.GetMyTLSServer: TCustomTLSInternalServer; -begin - Result := TLSServer; -end; - -{==============================================================================} - -constructor TSSLStreamSec.Create(const Value: TTCPBlockSocket); -begin - inherited Create(Value); - FSlave := nil; - FIsServer := False; - FTLSServer := nil; -end; - -destructor TSSLStreamSec.Destroy; -begin - DeInit; - inherited Destroy; -end; - -function TSSLStreamSec.LibVersion: String; -begin - Result := 'StreamSecII'; -end; - -function TSSLStreamSec.LibName: String; -begin - Result := 'ssl_streamsec'; -end; - -function TSSLStreamSec.SSLCheck: Boolean; -begin - Result := true; - FLastErrorDesc := ''; - if not Assigned(FSlave) then - Exit; - FLastError := FSlave.ErrorCode; - if FLastError <> 0 then - begin - FLastErrorDesc := TlsConst.AlertMsg(FLastError); - end; -end; - -procedure TSSLStreamSec.NotTrustEvent(Sender: TObject; Cert: TASN1Struct; var ExplicitTrust: Boolean); -begin - ExplicitTrust := true; -end; - -function TSSLStreamSec.Init(server:Boolean): Boolean; -var - st: TMemoryStream; - pass: ISecretKey; - ws: WideString; -begin - Result := False; - ws := FKeyPassword; - pass := TSecretKey.CreateBmpStr(PWideChar(ws), length(ws)); - try - FIsServer := Server; - FSlave := TMyTLSSynSockSlave.CreateSocket(FSocket.Socket); - if Assigned(FTLSServer) then - FSlave.MyTLSServer := FTLSServer - else - if Assigned(TLSInternalServer.GlobalServer) then - FSlave.MyTLSServer := TLSInternalServer.GlobalServer - else begin - FSlave.MyTLSServer := TSimpleTLSInternalServer.Create(nil); - FServerCreated := True; - end; - if server then - FSlave.MyTLSServer.ClientOrServer := cosServerSide - else - FSlave.MyTLSServer.ClientOrServer := cosClientSide; - if not FVerifyCert then - begin - FSlave.MyTLSServer.OnCertNotTrusted := NotTrustEvent; - end; - FSlave.MyTLSServer.Options.VerifyServerName := []; - FSlave.MyTLSServer.Options.Export40Bit := prAllowed; - FSlave.MyTLSServer.Options.Export56Bit := prAllowed; - FSlave.MyTLSServer.Options.RequestClientCertificate := False; - FSlave.MyTLSServer.Options.RequireClientCertificate := False; - if server and FVerifyCert then - begin - FSlave.MyTLSServer.Options.RequestClientCertificate := True; - FSlave.MyTLSServer.Options.RequireClientCertificate := True; - end; - if FCertCAFile <> '' then - FSlave.MyTLSServer.LoadRootCertsFromFile(CertCAFile); - if FCertCA <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FCertCA); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadRootCertsFromStream(st); - finally - st.free; - end; - end; - if FTrustCertificateFile <> '' then - FSlave.MyTLSServer.LoadTrustedCertsFromFile(FTrustCertificateFile); - if FTrustCertificate <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FTrustCertificate); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadTrustedCertsFromStream(st); - finally - st.free; - end; - end; - if FPrivateKeyFile <> '' then - FSlave.MyTLSServer.LoadPrivateKeyRingFromFile(FPrivateKeyFile, pass); -// FSlave.MyTLSServer.PrivateKeyRing.LoadPrivateKeyFromFile(FPrivateKeyFile, pass); - if FPrivateKey <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FPrivateKey); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadPrivateKeyRingFromStream(st, pass); - finally - st.free; - end; - end; - if FCertificateFile <> '' then - FSlave.MyTLSServer.LoadMyCertsFromFile(FCertificateFile); - if FCertificate <> '' then - begin - st := TMemoryStream.Create; - try - WriteStrToStream(st, FCertificate); - st.Seek(0, soFromBeginning); - FSlave.MyTLSServer.LoadMyCertsFromStream(st); - finally - st.free; - end; - end; - if FPFXfile <> '' then - FSlave.MyTLSServer.ImportFromPFX(FPFXfile, pass); - if server and FServerCreated then - begin - FSlave.MyTLSServer.Options.BulkCipherAES128 := prPrefer; - FSlave.MyTLSServer.Options.BulkCipherAES256 := prAllowed; - FSlave.MyTLSServer.Options.EphemeralECDHKeySize := ecs256; - FSlave.MyTLSServer.Options.SignatureRSA := prPrefer; - FSlave.MyTLSServer.Options.KeyAgreementRSA := prAllowed; - FSlave.MyTLSServer.Options.KeyAgreementECDHE := prAllowed; - FSlave.MyTLSServer.Options.KeyAgreementDHE := prPrefer; - FSlave.MyTLSServer.TLSSetupServer; - end; - Result := true; - finally - pass := nil; - end; -end; - -function TSSLStreamSec.DeInit: Boolean; -var - obj: TObject; -begin - Result := True; - if assigned(FSlave) then - begin - FSlave.Close; - if FServerCreated then - obj := FSlave.TLSServer - else - obj := nil; - FSlave.Free; - obj.Free; - FSlave := nil; - end; - FSSLEnabled := false; -end; - -function TSSLStreamSec.Prepare(server:Boolean): Boolean; -begin - Result := false; - DeInit; - if Init(server) then - Result := true - else - DeInit; -end; - -function TSSLStreamSec.Connect: boolean; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(false) then - begin - FSlave.Open; - SSLCheck; - if FLastError <> 0 then - Exit; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLStreamSec.Accept: boolean; -begin - Result := False; - if FSocket.Socket = INVALID_SOCKET then - Exit; - if Prepare(true) then - begin - FSlave.DoConnect; - SSLCheck; - if FLastError <> 0 then - Exit; - FSSLEnabled := True; - Result := True; - end; -end; - -function TSSLStreamSec.Shutdown: boolean; -begin - Result := BiShutdown; -end; - -function TSSLStreamSec.BiShutdown: boolean; -begin - DeInit; - Result := True; -end; - -function TSSLStreamSec.SendBuffer(Buffer: TMemory; Len: Integer): Integer; -var - l: integer; -begin - l := len; - FSlave.SendBuf(Buffer^, l, true); - Result := l; - SSLCheck; -end; - -function TSSLStreamSec.RecvBuffer(Buffer: TMemory; Len: Integer): Integer; -var - l: integer; -begin - l := Len; - Result := FSlave.ReceiveBuf(Buffer^, l); - SSLCheck; -end; - -function TSSLStreamSec.WaitingData: Integer; -begin - Result := 0; - while FSlave.Connected do begin - Result := FSlave.ReceiveLength; - if Result > 0 then - Break; - Sleep(1); - end; -end; - -function TSSLStreamSec.GetSSLVersion: string; -begin - Result := 'SSLv3 or TLSv1'; -end; - -function TSSLStreamSec.GetCert: PASN1Struct; -begin - if FIsServer then - Result := FSlave.GetClientCert - else - Result := FSlave.GetServerCert; -end; - -function TSSLStreamSec.GetPeerSubject: string; -var - XName: TX501Name; - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - ExtractSubject(Cert^,XName, false); - Result := X501NameToStr(XName); - end; -end; - -function TSSLStreamSec.GetPeerName: string; -var - XName: TX501Name; - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - ExtractSubject(Cert^,XName, false); - Result := XName.commonName.Str; - end; -end; - -function TSSLStreamSec.GetPeerIssuer: string; -var - XName: TX501Name; - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - ExtractIssuer(Cert^, XName, false); - Result := X501NameToStr(XName); - end; -end; - -function TSSLStreamSec.GetPeerFingerprint: string; -var - Cert: PASN1Struct; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - Result := MD5(Cert.ContentAsOctetString); -end; - -function TSSLStreamSec.GetCertInfo: string; -var - Cert: PASN1Struct; - l: Tstringlist; -begin - Result := ''; - Cert := GetCert; - if Assigned(cert) then - begin - l := TStringList.Create; - try - Asn1.RenderAsText(cert^, l, true, true, true, 2); - Result := l.Text; - finally - l.free; - end; - end; -end; - -function TSSLStreamSec.X500StrToStr(const Prefix: string; - const Value: TX500String): string; -begin - if Value.Str = '' then - Result := '' - else - Result := '/' + Prefix + '=' + Value.Str; -end; - -function TSSLStreamSec.X501NameToStr(const Value: TX501Name): string; -begin - Result := X500StrToStr('CN',Value.commonName) + - X500StrToStr('C',Value.countryName) + - X500StrToStr('L',Value.localityName) + - X500StrToStr('ST',Value.stateOrProvinceName) + - X500StrToStr('O',Value.organizationName) + - X500StrToStr('OU',Value.organizationalUnitName) + - X500StrToStr('T',Value.title) + - X500StrToStr('N',Value.name) + - X500StrToStr('G',Value.givenName) + - X500StrToStr('I',Value.initials) + - X500StrToStr('SN',Value.surname) + - X500StrToStr('GQ',Value.generationQualifier) + - X500StrToStr('DNQ',Value.dnQualifier) + - X500StrToStr('E',Value.emailAddress); -end; - - -{==============================================================================} - -initialization - SSLImplementation := TSSLStreamSec; - -finalization - -end. - - diff --git a/3rd/synapse/source/sslinux.inc b/3rd/synapse/source/sslinux.inc deleted file mode 100644 index 54236b6a2..000000000 --- a/3rd/synapse/source/sslinux.inc +++ /dev/null @@ -1,1313 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.000.009 | -|==============================================================================| -| Content: Socket Independent Platform Layer - Linux definition include | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$IFDEF LINUX} - -//{$DEFINE FORCEOLDAPI} -{Note about define FORCEOLDAPI: -If you activate this compiler directive, then is allways used old socket API -for name resolution. If you leave this directive inactive, then the new API -is used, when running system allows it. - -For IPv6 support you must have new API! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -interface - -uses - SyncObjs, SysUtils, Classes, - synafpc, - Libc; - -function InitSocketInterface(stack: string): Boolean; -function DestroySocketInterface: Boolean; - -const - WinsockLevel = $0202; - -type - u_char = Char; - u_short = Word; - u_int = Integer; - u_long = Longint; - pu_long = ^u_long; - pu_short = ^u_short; - TSocket = u_int; - TAddrFamily = integer; - - TMemory = pointer; - - -const - DLLStackName = 'libc.so.6'; - - cLocalhost = '127.0.0.1'; - cAnyHost = '0.0.0.0'; - cBroadcast = '255.255.255.255'; - c6Localhost = '::1'; - c6AnyHost = '::0'; - c6Broadcast = 'ffff::1'; - cAnyPort = '0'; - -type - DWORD = Integer; - __fd_mask = LongWord; -const - __FD_SETSIZE = 1024; - __NFDBITS = 8 * sizeof(__fd_mask); -type - __fd_set = {packed} record - fds_bits: packed array[0..(__FD_SETSIZE div __NFDBITS)-1] of __fd_mask; - end; - TFDSet = __fd_set; - PFDSet = ^TFDSet; - -const - FIONREAD = $541B; - FIONBIO = $5421; - FIOASYNC = $5452; - -type - PTimeVal = ^TTimeVal; - TTimeVal = packed record - tv_sec: Longint; - tv_usec: Longint; - end; - -const - IPPROTO_IP = 0; { Dummy } - IPPROTO_ICMP = 1; { Internet Control Message Protocol } - IPPROTO_IGMP = 2; { Internet Group Management Protocol} - IPPROTO_TCP = 6; { TCP } - IPPROTO_UDP = 17; { User Datagram Protocol } - IPPROTO_IPV6 = 41; - IPPROTO_ICMPV6 = 58; - IPPROTO_RM = 113; - - IPPROTO_RAW = 255; - IPPROTO_MAX = 256; - -type - PInAddr = ^TInAddr; - TInAddr = packed record - case integer of - 0: (S_bytes: packed array [0..3] of byte); - 1: (S_addr: u_long); - end; - - PSockAddrIn = ^TSockAddrIn; - TSockAddrIn = packed record - case Integer of - 0: (sin_family: u_short; - sin_port: u_short; - sin_addr: TInAddr; - sin_zero: array[0..7] of Char); - 1: (sa_family: u_short; - sa_data: array[0..13] of Char) - end; - - TIP_mreq = record - imr_multiaddr: TInAddr; { IP multicast address of group } - imr_interface: TInAddr; { local IP address of interface } - end; - - PInAddr6 = ^TInAddr6; - TInAddr6 = packed record - case integer of - 0: (S6_addr: packed array [0..15] of byte); - 1: (u6_addr8: packed array [0..15] of byte); - 2: (u6_addr16: packed array [0..7] of word); - 3: (u6_addr32: packed array [0..3] of integer); - end; - - PSockAddrIn6 = ^TSockAddrIn6; - TSockAddrIn6 = packed record - sin6_family: u_short; // AF_INET6 - sin6_port: u_short; // Transport level port number - sin6_flowinfo: u_long; // IPv6 flow information - sin6_addr: TInAddr6; // IPv6 address - sin6_scope_id: u_long; // Scope Id: IF number for link-local - // SITE id for site-local - end; - - TIPv6_mreq = record - ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: integer; // Interface index. - padding: u_long; - end; - - PHostEnt = ^THostEnt; - THostent = record - h_name: PChar; - h_aliases: PPChar; - h_addrtype: Integer; - h_length: Cardinal; - case Byte of - 0: (h_addr_list: PPChar); - 1: (h_addr: PPChar); - end; - - PNetEnt = ^TNetEnt; - TNetEnt = record - n_name: PChar; - n_aliases: PPChar; - n_addrtype: Integer; - n_net: uint32_t; - end; - - PServEnt = ^TServEnt; - TServEnt = record - s_name: PChar; - s_aliases: PPChar; - s_port: Integer; - s_proto: PChar; - end; - - PProtoEnt = ^TProtoEnt; - TProtoEnt = record - p_name: PChar; - p_aliases: ^PChar; - p_proto: u_short; - end; - -const - INADDR_ANY = $00000000; - INADDR_LOOPBACK = $7F000001; - INADDR_BROADCAST = $FFFFFFFF; - INADDR_NONE = $FFFFFFFF; - ADDR_ANY = INADDR_ANY; - INVALID_SOCKET = TSocket(NOT(0)); - SOCKET_ERROR = -1; - -Const - IP_TOS = 1; { int; IP type of service and precedence. } - IP_TTL = 2; { int; IP time to live. } - IP_HDRINCL = 3; { int; Header is included with data. } - IP_OPTIONS = 4; { ip_opts; IP per-packet options. } - IP_ROUTER_ALERT = 5; { bool } - IP_RECVOPTS = 6; { bool } - IP_RETOPTS = 7; { bool } - IP_PKTINFO = 8; { bool } - IP_PKTOPTIONS = 9; - IP_PMTUDISC = 10; { obsolete name? } - IP_MTU_DISCOVER = 10; { int; see below } - IP_RECVERR = 11; { bool } - IP_RECVTTL = 12; { bool } - IP_RECVTOS = 13; { bool } - IP_MULTICAST_IF = 32; { in_addr; set/get IP multicast i/f } - IP_MULTICAST_TTL = 33; { u_char; set/get IP multicast ttl } - IP_MULTICAST_LOOP = 34; { i_char; set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = 35; { ip_mreq; add an IP group membership } - IP_DROP_MEMBERSHIP = 36; { ip_mreq; drop an IP group membership } - - SOL_SOCKET = 1; - - SO_DEBUG = 1; - SO_REUSEADDR = 2; - SO_TYPE = 3; - SO_ERROR = 4; - SO_DONTROUTE = 5; - SO_BROADCAST = 6; - SO_SNDBUF = 7; - SO_RCVBUF = 8; - SO_KEEPALIVE = 9; - SO_OOBINLINE = 10; - SO_NO_CHECK = 11; - SO_PRIORITY = 12; - SO_LINGER = 13; - SO_BSDCOMPAT = 14; - SO_REUSEPORT = 15; - SO_PASSCRED = 16; - SO_PEERCRED = 17; - SO_RCVLOWAT = 18; - SO_SNDLOWAT = 19; - SO_RCVTIMEO = 20; - SO_SNDTIMEO = 21; -{ Security levels - as per NRL IPv6 - don't actually do anything } - SO_SECURITY_AUTHENTICATION = 22; - SO_SECURITY_ENCRYPTION_TRANSPORT = 23; - SO_SECURITY_ENCRYPTION_NETWORK = 24; - SO_BINDTODEVICE = 25; -{ Socket filtering } - SO_ATTACH_FILTER = 26; - SO_DETACH_FILTER = 27; - - SOMAXCONN = 128; - - IPV6_UNICAST_HOPS = 16; - IPV6_MULTICAST_IF = 17; - IPV6_MULTICAST_HOPS = 18; - IPV6_MULTICAST_LOOP = 19; - IPV6_JOIN_GROUP = 20; - IPV6_LEAVE_GROUP = 21; - - MSG_NOSIGNAL = $4000; // Do not generate SIGPIPE. - - // getnameinfo constants - NI_MAXHOST = 1025; - NI_MAXSERV = 32; - NI_NOFQDN = $4; - NI_NUMERICHOST = $1; - NI_NAMEREQD = $8; - NI_NUMERICSERV = $2; - NI_DGRAM = $10; - -const - SOCK_STREAM = 1; { stream socket } - SOCK_DGRAM = 2; { datagram socket } - SOCK_RAW = 3; { raw-protocol interface } - SOCK_RDM = 4; { reliably-delivered message } - SOCK_SEQPACKET = 5; { sequenced packet stream } - -{ TCP options. } - TCP_NODELAY = $0001; - -{ Address families. } - - AF_UNSPEC = 0; { unspecified } - AF_INET = 2; { internetwork: UDP, TCP, etc. } - AF_INET6 = 10; { Internetwork Version 6 } - AF_MAX = 24; - -{ Protocol families, same as address families for now. } - PF_UNSPEC = AF_UNSPEC; - PF_INET = AF_INET; - PF_INET6 = AF_INET6; - PF_MAX = AF_MAX; - -type - { Structure used by kernel to store most addresses. } - PSockAddr = ^TSockAddr; - TSockAddr = TSockAddrIn; - - { Structure used by kernel to pass protocol information in raw sockets. } - PSockProto = ^TSockProto; - TSockProto = packed record - sp_family: u_short; - sp_protocol: u_short; - end; - -type - PAddrInfo = ^TAddrInfo; - TAddrInfo = record - ai_flags: integer; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST. - ai_family: integer; // PF_xxx. - ai_socktype: integer; // SOCK_xxx. - ai_protocol: integer; // 0 or IPPROTO_xxx for IPv4 and IPv6. - ai_addrlen: u_int; // Length of ai_addr. - ai_addr: PSockAddr; // Binary address. - ai_canonname: PChar; // Canonical name for nodename. - ai_next: PAddrInfo; // Next structure in linked list. - end; - -const - // Flags used in "hints" argument to getaddrinfo(). - AI_PASSIVE = $1; // Socket address will be used in bind() call. - AI_CANONNAME = $2; // Return canonical name in first ai_canonname. - AI_NUMERICHOST = $4; // Nodename must be a numeric address string. - -type -{ Structure used for manipulating linger option. } - PLinger = ^TLinger; - TLinger = packed record - l_onoff: integer; - l_linger: integer; - end; - -const - - MSG_OOB = $01; // Process out-of-band data. - MSG_PEEK = $02; // Peek at incoming messages. - -const - WSAEINTR = EINTR; - WSAEBADF = EBADF; - WSAEACCES = EACCES; - WSAEFAULT = EFAULT; - WSAEINVAL = EINVAL; - WSAEMFILE = EMFILE; - WSAEWOULDBLOCK = EWOULDBLOCK; - WSAEINPROGRESS = EINPROGRESS; - WSAEALREADY = EALREADY; - WSAENOTSOCK = ENOTSOCK; - WSAEDESTADDRREQ = EDESTADDRREQ; - WSAEMSGSIZE = EMSGSIZE; - WSAEPROTOTYPE = EPROTOTYPE; - WSAENOPROTOOPT = ENOPROTOOPT; - WSAEPROTONOSUPPORT = EPROTONOSUPPORT; - WSAESOCKTNOSUPPORT = ESOCKTNOSUPPORT; - WSAEOPNOTSUPP = EOPNOTSUPP; - WSAEPFNOSUPPORT = EPFNOSUPPORT; - WSAEAFNOSUPPORT = EAFNOSUPPORT; - WSAEADDRINUSE = EADDRINUSE; - WSAEADDRNOTAVAIL = EADDRNOTAVAIL; - WSAENETDOWN = ENETDOWN; - WSAENETUNREACH = ENETUNREACH; - WSAENETRESET = ENETRESET; - WSAECONNABORTED = ECONNABORTED; - WSAECONNRESET = ECONNRESET; - WSAENOBUFS = ENOBUFS; - WSAEISCONN = EISCONN; - WSAENOTCONN = ENOTCONN; - WSAESHUTDOWN = ESHUTDOWN; - WSAETOOMANYREFS = ETOOMANYREFS; - WSAETIMEDOUT = ETIMEDOUT; - WSAECONNREFUSED = ECONNREFUSED; - WSAELOOP = ELOOP; - WSAENAMETOOLONG = ENAMETOOLONG; - WSAEHOSTDOWN = EHOSTDOWN; - WSAEHOSTUNREACH = EHOSTUNREACH; - WSAENOTEMPTY = ENOTEMPTY; - WSAEPROCLIM = -1; - WSAEUSERS = EUSERS; - WSAEDQUOT = EDQUOT; - WSAESTALE = ESTALE; - WSAEREMOTE = EREMOTE; - WSASYSNOTREADY = -2; - WSAVERNOTSUPPORTED = -3; - WSANOTINITIALISED = -4; - WSAEDISCON = -5; - WSAHOST_NOT_FOUND = HOST_NOT_FOUND; - WSATRY_AGAIN = TRY_AGAIN; - WSANO_RECOVERY = NO_RECOVERY; - WSANO_DATA = -6; - - EAI_BADFLAGS = -1; { Invalid value for `ai_flags' field. } - EAI_NONAME = -2; { NAME or SERVICE is unknown. } - EAI_AGAIN = -3; { Temporary failure in name resolution. } - EAI_FAIL = -4; { Non-recoverable failure in name res. } - EAI_NODATA = -5; { No address associated with NAME. } - EAI_FAMILY = -6; { `ai_family' not supported. } - EAI_SOCKTYPE = -7; { `ai_socktype' not supported. } - EAI_SERVICE = -8; { SERVICE not supported for `ai_socktype'. } - EAI_ADDRFAMILY = -9; { Address family for NAME not supported. } - EAI_MEMORY = -10; { Memory allocation failure. } - EAI_SYSTEM = -11; { System error returned in `errno'. } - -const - WSADESCRIPTION_LEN = 256; - WSASYS_STATUS_LEN = 128; -type - PWSAData = ^TWSAData; - TWSAData = packed record - wVersion: Word; - wHighVersion: Word; - szDescription: array[0..WSADESCRIPTION_LEN] of Char; - szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; - iMaxSockets: Word; - iMaxUdpDg: Word; - lpVendorInfo: PChar; - end; - - function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; - function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; - procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); - procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -var - in6addr_any, in6addr_loopback : TInAddr6; - -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -procedure FD_ZERO(var FDSet: TFDSet); - -{=============================================================================} - -type - TWSAStartup = function(wVersionRequired: Word; var WSData: TWSAData): Integer; - cdecl; - TWSACleanup = function: Integer; - cdecl; - TWSAGetLastError = function: Integer; - cdecl; - TGetServByName = function(name, proto: PChar): PServEnt; - cdecl; - TGetServByPort = function(port: Integer; proto: PChar): PServEnt; - cdecl; - TGetProtoByName = function(name: PChar): PProtoEnt; - cdecl; - TGetProtoByNumber = function(proto: Integer): PProtoEnt; - cdecl; - TGetHostByName = function(name: PChar): PHostEnt; - cdecl; - TGetHostByAddr = function(addr: Pointer; len, Struc: Integer): PHostEnt; - cdecl; - TGetHostName = function(name: PChar; len: Integer): Integer; - cdecl; - TShutdown = function(s: TSocket; how: Integer): Integer; - cdecl; - TSetSockOpt = function(s: TSocket; level, optname: Integer; optval: PChar; - optlen: Integer): Integer; - cdecl; - TGetSockOpt = function(s: TSocket; level, optname: Integer; optval: PChar; - var optlen: Integer): Integer; - cdecl; - TSendTo = function(s: TSocket; const Buf; len, flags: Integer; addrto: PSockAddr; - tolen: Integer): Integer; - cdecl; - TSend = function(s: TSocket; const Buf; len, flags: Integer): Integer; - cdecl; - TRecv = function(s: TSocket; var Buf; len, flags: Integer): Integer; - cdecl; - TRecvFrom = function(s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; - var fromlen: Integer): Integer; - cdecl; - Tntohs = function(netshort: u_short): u_short; - cdecl; - Tntohl = function(netlong: u_long): u_long; - cdecl; - TListen = function(s: TSocket; backlog: Integer): Integer; - cdecl; - TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: integer): Integer; - cdecl; - TInet_ntoa = function(inaddr: TInAddr): PChar; - cdecl; - TInet_addr = function(cp: PChar): u_long; - cdecl; - Thtons = function(hostshort: u_short): u_short; - cdecl; - Thtonl = function(hostlong: u_long): u_long; - cdecl; - TGetSockName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - cdecl; - TGetPeerName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - cdecl; - TConnect = function(s: TSocket; name: PSockAddr; namelen: Integer): Integer; - cdecl; - TCloseSocket = function(s: TSocket): Integer; - cdecl; - TBind = function(s: TSocket; addr: PSockAddr; namelen: Integer): Integer; - cdecl; - TAccept = function(s: TSocket; addr: PSockAddr; var addrlen: Integer): TSocket; - cdecl; - TTSocket = function(af, Struc, Protocol: Integer): TSocket; - cdecl; - TSelect = function(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; - cdecl; - - TGetAddrInfo = function(NodeName: PChar; ServName: PChar; Hints: PAddrInfo; - var Addrinfo: PAddrInfo): integer; - cdecl; - TFreeAddrInfo = procedure(ai: PAddrInfo); - cdecl; - TGetNameInfo = function( addr: PSockAddr; namelen: Integer; host: PChar; - hostlen: DWORD; serv: PChar; servlen: DWORD; flags: integer): integer; - cdecl; - -var - WSAStartup: TWSAStartup = nil; - WSACleanup: TWSACleanup = nil; - WSAGetLastError: TWSAGetLastError = nil; - GetServByName: TGetServByName = nil; - GetServByPort: TGetServByPort = nil; - GetProtoByName: TGetProtoByName = nil; - GetProtoByNumber: TGetProtoByNumber = nil; - GetHostByName: TGetHostByName = nil; - GetHostByAddr: TGetHostByAddr = nil; - ssGetHostName: TGetHostName = nil; - Shutdown: TShutdown = nil; - SetSockOpt: TSetSockOpt = nil; - GetSockOpt: TGetSockOpt = nil; - ssSendTo: TSendTo = nil; - ssSend: TSend = nil; - ssRecv: TRecv = nil; - ssRecvFrom: TRecvFrom = nil; - ntohs: Tntohs = nil; - ntohl: Tntohl = nil; - Listen: TListen = nil; - IoctlSocket: TIoctlSocket = nil; - Inet_ntoa: TInet_ntoa = nil; - Inet_addr: TInet_addr = nil; - htons: Thtons = nil; - htonl: Thtonl = nil; - ssGetSockName: TGetSockName = nil; - ssGetPeerName: TGetPeerName = nil; - ssConnect: TConnect = nil; - CloseSocket: TCloseSocket = nil; - ssBind: TBind = nil; - ssAccept: TAccept = nil; - Socket: TTSocket = nil; - Select: TSelect = nil; - - GetAddrInfo: TGetAddrInfo = nil; - FreeAddrInfo: TFreeAddrInfo = nil; - GetNameInfo: TGetNameInfo = nil; - -function LSWSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; cdecl; -function LSWSACleanup: Integer; cdecl; -function LSWSAGetLastError: Integer; cdecl; - -var - SynSockCS: SyncObjs.TCriticalSection; - SockEnhancedApi: Boolean; - SockWship6Api: Boolean; - -type - TVarSin = packed record - case integer of - 0: (AddressFamily: u_short); - 1: ( - case sin_family: u_short of - AF_INET: (sin_port: u_short; - sin_addr: TInAddr; - sin_zero: array[0..7] of Char); - AF_INET6: (sin6_port: u_short; - sin6_flowinfo: u_long; - sin6_addr: TInAddr6; - sin6_scope_id: u_long); - ); - end; - -function SizeOfVarSin(sin: TVarSin): integer; - -function Bind(s: TSocket; const addr: TVarSin): Integer; -function Connect(s: TSocket; const name: TVarSin): Integer; -function GetSockName(s: TSocket; var name: TVarSin): Integer; -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -function GetHostName: string; -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -function Accept(s: TSocket; var addr: TVarSin): TSocket; - -function IsNewApi(Family: integer): Boolean; -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -function GetSinIP(Sin: TVarSin): string; -function GetSinPort(Sin: TVarSin): Integer; -procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); -function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; -function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; - -{==============================================================================} -implementation - -var - SynSockCount: Integer = 0; - LibHandle: TLibHandle = 0; - Libwship6Handle: TLibHandle = 0; - -function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); -end; - -function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and - (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and - (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); -end; - -function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); -end; - -function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); -end; - -function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; -begin - Result := (a^.u6_addr8[0] = $FF); -end; - -function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; -begin - Result := (CompareMem( a, b, sizeof(TInAddr6))); -end; - -procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); -end; - -procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); - a^.u6_addr8[15] := 1; -end; - -{=============================================================================} -var -{$IFNDEF VER1_0} //FTP version 1.0.x - errno_loc: function: PInteger cdecl = nil; -{$ELSE} - errno_loc: function: PInteger = nil; cdecl; -{$ENDIF} - -function LSWSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; -begin - with WSData do - begin - wVersion := wVersionRequired; - wHighVersion := $202; - szDescription := 'Synsock - Synapse Platform Independent Socket Layer'; - szSystemStatus := 'Running on Linux'; - iMaxSockets := 32768; - iMaxUdpDg := 8192; - end; - Result := 0; -end; - -function LSWSACleanup: Integer; -begin - Result := 0; -end; - -function LSWSAGetLastError: Integer; -var - p: PInteger; -begin - p := errno_loc; - Result := p^; -end; - -function __FDELT(Socket: TSocket): Integer; -begin - Result := Socket div __NFDBITS; -end; - -function __FDMASK(Socket: TSocket): __fd_mask; -begin - Result := LongWord(1) shl (Socket mod __NFDBITS); -end; - -function FD_ISSET(Socket: TSocket; var fdset: TFDSet): Boolean; -begin - Result := (fdset.fds_bits[__FDELT(Socket)] and __FDMASK(Socket)) <> 0; -end; - -procedure FD_SET(Socket: TSocket; var fdset: TFDSet); -begin - fdset.fds_bits[__FDELT(Socket)] := fdset.fds_bits[__FDELT(Socket)] or __FDMASK(Socket); -end; - -procedure FD_CLR(Socket: TSocket; var fdset: TFDSet); -begin - fdset.fds_bits[__FDELT(Socket)] := fdset.fds_bits[__FDELT(Socket)] and (not __FDMASK(Socket)); -end; - -procedure FD_ZERO(var fdset: TFDSet); -var - I: Integer; -begin - with fdset do - for I := Low(fds_bits) to High(fds_bits) do - fds_bits[I] := 0; -end; - -{=============================================================================} - -function SizeOfVarSin(sin: TVarSin): integer; -begin - case sin.sin_family of - AF_INET: - Result := SizeOf(TSockAddrIn); - AF_INET6: - Result := SizeOf(TSockAddrIn6); - else - Result := 0; - end; -end; - -{=============================================================================} - -function Bind(s: TSocket; const addr: TVarSin): Integer; -begin - Result := ssBind(s, @addr, SizeOfVarSin(addr)); -end; - -function Connect(s: TSocket; const name: TVarSin): Integer; -begin - Result := ssConnect(s, @name, SizeOfVarSin(name)); -end; - -function GetSockName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := ssGetSockName(s, @name, Len); -end; - -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := ssGetPeerName(s, @name, Len); -end; - -function GetHostName: string; -var - s: string; -begin - Result := ''; - setlength(s, 255); - ssGetHostName(pchar(s), Length(s) - 1); - Result := Pchar(s); -end; - -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := ssSend(s, Buf^, len, flags); -end; - -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := ssRecv(s, Buf^, len, flags); -end; - -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -begin - Result := ssSendTo(s, Buf^, len, flags, @addrto, SizeOfVarSin(addrto)); -end; - -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -var - x: integer; -begin - x := SizeOf(from); - Result := ssRecvFrom(s, Buf^, len, flags, @from, x); -end; - -function Accept(s: TSocket; var addr: TVarSin): TSocket; -var - x: integer; -begin - x := SizeOf(addr); - Result := ssAccept(s, @addr, x); -end; - -{=============================================================================} -function IsNewApi(Family: integer): Boolean; -begin - Result := SockEnhancedApi; - if not Result then - Result := (Family = AF_INET6) and SockWship6Api; -end; - -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -type - pu_long = ^u_long; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - HostEnt: PHostEnt; - r: integer; - Hints1, Hints2: TAddrInfo; - Sin1, Sin2: TVarSin; - TwoPass: boolean; - - function GetAddr(const IP, port: string; Hints: TAddrInfo; var Sin: TVarSin): integer; - var - Addr: PAddrInfo; - begin - Addr := nil; - try - FillChar(Sin, Sizeof(Sin), 0); - if Hints.ai_socktype = SOCK_RAW then - begin - Hints.ai_socktype := 0; - Hints.ai_protocol := 0; - Result := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); - end - else - begin - if (IP = cAnyHost) or (IP = c6AnyHost) then - begin - Hints.ai_flags := AI_PASSIVE; - Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); - end - else - if (IP = cLocalhost) or (IP = c6Localhost) then - begin - Result := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); - end - else - begin - Result := synsock.GetAddrInfo(PChar(IP), PChar(Port), @Hints, Addr); - end; - end; - if Result = 0 then - if (Addr <> nil) then - Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - -begin - Result := 0; - FillChar(Sin, Sizeof(Sin), 0); - if not IsNewApi(family) then - begin - SynSockCS.Enter; - try - Sin.sin_family := AF_INET; - ProtoEnt := synsock.GetProtoByNumber(SockProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Sin.sin_port := synsock.htons(StrToIntDef(Port, 0)) - else - Sin.sin_port := ServEnt^.s_port; - if IP = cBroadcast then - Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) - else - begin - Sin.sin_addr.s_addr := synsock.inet_addr(PChar(IP)); - if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then - begin - HostEnt := synsock.GetHostByName(PChar(IP)); - Result := synsock.WSAGetLastError; - if HostEnt <> nil then - Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - begin - FillChar(Hints1, Sizeof(Hints1), 0); - FillChar(Hints2, Sizeof(Hints2), 0); - TwoPass := False; - if Family = AF_UNSPEC then - begin - if PreferIP4 then - begin - Hints1.ai_family := AF_INET; - Hints2.ai_family := AF_INET6; - TwoPass := True; - end - else - begin - Hints2.ai_family := AF_INET; - Hints1.ai_family := AF_INET6; - TwoPass := True; - end; - end - else - Hints1.ai_family := Family; - - Hints1.ai_socktype := SockType; - Hints1.ai_protocol := SockProtocol; - Hints2.ai_socktype := Hints1.ai_socktype; - Hints2.ai_protocol := Hints1.ai_protocol; - - r := GetAddr(IP, Port, Hints1, Sin1); - Result := r; - sin := sin1; - if r <> 0 then - if TwoPass then - begin - r := GetAddr(IP, Port, Hints2, Sin2); - Result := r; - if r = 0 then - sin := sin2; - end; - end; -end; - -function GetSinIP(Sin: TVarSin): string; -var - p: PChar; - host, serv: string; - hostlen, servlen: integer; - r: integer; -begin - Result := ''; - if not IsNewApi(Sin.AddressFamily) then - begin - p := synsock.inet_ntoa(Sin.sin_addr); - if p <> nil then - Result := p; - end - else - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(@sin, SizeOfVarSin(sin), PChar(host), hostlen, - PChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - Result := PChar(host); - end; -end; - -function GetSinPort(Sin: TVarSin): Integer; -begin - if (Sin.sin_family = AF_INET6) then - Result := synsock.ntohs(Sin.sin6_port) - else - Result := synsock.ntohs(Sin.sin_port); -end; - -procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); -type - TaPInAddr = array[0..250] of PInAddr; - PaPInAddr = ^TaPInAddr; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - AddrNext: PAddrInfo; - r: integer; - host, serv: string; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IP: u_long; - PAdrPtr: PaPInAddr; - i: Integer; - s: string; - InAddr: TInAddr; -begin - IPList.Clear; - if not IsNewApi(Family) then - begin - IP := synsock.inet_addr(PChar(Name)); - if IP = u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := synsock.GetHostByName(PChar(Name)); - if RemoteHost <> nil then - begin - PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); - i := 0; - while PAdrPtr^[i] <> nil do - begin - InAddr := PAdrPtr^[i]^; - s := Format('%d.%d.%d.%d', [InAddr.S_bytes[0], InAddr.S_bytes[1], - InAddr.S_bytes[2], InAddr.S_bytes[3]]); - IPList.Add(s); - Inc(i); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - IPList.Add(Name); - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PChar(Name), nil, @Hints, Addr); - if r = 0 then - begin - AddrNext := Addr; - while not(AddrNext = nil) do - begin - if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) - or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, - PChar(host), hostlen, PChar(serv), servlen, - NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - begin - host := PChar(host); - IPList.Add(host); - end; - end; - AddrNext := AddrNext^.ai_next; - end; - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - if IPList.Count = 0 then - IPList.Add(cAnyHost); -end; - -function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; -begin - Result := 0; - if not IsNewApi(Family) then - begin - SynSockCS.Enter; - try - ProtoEnt := synsock.GetProtoByNumber(SockProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := synsock.GetServByName(PChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Result := StrToIntDef(Port, 0) - else - Result := synsock.htons(ServEnt^.s_port); - finally - SynSockCS.Leave; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := Sockprotocol; - Hints.ai_flags := AI_PASSIVE; - r := synsock.GetAddrInfo(nil, PChar(Port), @Hints, Addr); - if (r = 0) and Assigned(Addr) then - begin - if Addr^.ai_family = AF_INET then - Result := synsock.htons(Addr^.ai_addr^.sin_port); - if Addr^.ai_family = AF_INET6 then - Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; - -function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; - host, serv: string; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IPn: u_long; -begin - Result := IP; - if not IsNewApi(Family) then - begin - IPn := synsock.inet_addr(PChar(IP)); - if IPn <> u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); - if RemoteHost <> nil then - Result := RemoteHost^.h_name; - finally - SynSockCS.Leave; - end; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PChar(IP), nil, @Hints, Addr); - if (r = 0) and Assigned(Addr)then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, - PChar(host), hostlen, PChar(serv), servlen, - NI_NUMERICSERV); - if r = 0 then - Result := PChar(host); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; - -{=============================================================================} - -function InitSocketInterface(stack: string): Boolean; -begin - Result := False; - if stack = '' then - stack := DLLStackName; - SynSockCS.Enter; - try - if SynSockCount = 0 then - begin - SockEnhancedApi := False; - SockWship6Api := False; - Libc.Signal(Libc.SIGPIPE, TSignalHandler(Libc.SIG_IGN)); - LibHandle := LoadLibrary(PChar(Stack)); - if LibHandle <> 0 then - begin - errno_loc := GetProcAddress(LibHandle, PChar('__errno_location')); - CloseSocket := GetProcAddress(LibHandle, PChar('close')); - IoctlSocket := GetProcAddress(LibHandle, PChar('ioctl')); - WSAGetLastError := LSWSAGetLastError; - WSAStartup := LSWSAStartup; - WSACleanup := LSWSACleanup; - ssAccept := GetProcAddress(LibHandle, PChar('accept')); - ssBind := GetProcAddress(LibHandle, PChar('bind')); - ssConnect := GetProcAddress(LibHandle, PChar('connect')); - ssGetPeerName := GetProcAddress(LibHandle, PChar('getpeername')); - ssGetSockName := GetProcAddress(LibHandle, PChar('getsockname')); - GetSockOpt := GetProcAddress(LibHandle, PChar('getsockopt')); - Htonl := GetProcAddress(LibHandle, PChar('htonl')); - Htons := GetProcAddress(LibHandle, PChar('htons')); - Inet_Addr := GetProcAddress(LibHandle, PChar('inet_addr')); - Inet_Ntoa := GetProcAddress(LibHandle, PChar('inet_ntoa')); - Listen := GetProcAddress(LibHandle, PChar('listen')); - Ntohl := GetProcAddress(LibHandle, PChar('ntohl')); - Ntohs := GetProcAddress(LibHandle, PChar('ntohs')); - ssRecv := GetProcAddress(LibHandle, PChar('recv')); - ssRecvFrom := GetProcAddress(LibHandle, PChar('recvfrom')); - Select := GetProcAddress(LibHandle, PChar('select')); - ssSend := GetProcAddress(LibHandle, PChar('send')); - ssSendTo := GetProcAddress(LibHandle, PChar('sendto')); - SetSockOpt := GetProcAddress(LibHandle, PChar('setsockopt')); - ShutDown := GetProcAddress(LibHandle, PChar('shutdown')); - Socket := GetProcAddress(LibHandle, PChar('socket')); - GetHostByAddr := GetProcAddress(LibHandle, PChar('gethostbyaddr')); - GetHostByName := GetProcAddress(LibHandle, PChar('gethostbyname')); - GetProtoByName := GetProcAddress(LibHandle, PChar('getprotobyname')); - GetProtoByNumber := GetProcAddress(LibHandle, PChar('getprotobynumber')); - GetServByName := GetProcAddress(LibHandle, PChar('getservbyname')); - GetServByPort := GetProcAddress(LibHandle, PChar('getservbyport')); - ssGetHostName := GetProcAddress(LibHandle, PChar('gethostname')); - -{$IFNDEF FORCEOLDAPI} - GetAddrInfo := GetProcAddress(LibHandle, PChar('getaddrinfo')); - FreeAddrInfo := GetProcAddress(LibHandle, PChar('freeaddrinfo')); - GetNameInfo := GetProcAddress(LibHandle, PChar('getnameinfo')); - SockEnhancedApi := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) - and Assigned(GetNameInfo); -{$ENDIF} - Result := True; - end; - end - else Result := True; - if Result then - Inc(SynSockCount); - finally - SynSockCS.Leave; - end; -end; - -function DestroySocketInterface: Boolean; -begin - SynSockCS.Enter; - try - Dec(SynSockCount); - if SynSockCount < 0 then - SynSockCount := 0; - if SynSockCount = 0 then - begin - if LibHandle <> 0 then - begin - FreeLibrary(libHandle); - LibHandle := 0; - end; - if LibWship6Handle <> 0 then - begin - FreeLibrary(LibWship6Handle); - LibWship6Handle := 0; - end; - end; - finally - SynSockCS.Leave; - end; - Result := True; -end; - -initialization -begin - SynSockCS := SyncObjs.TCriticalSection.Create; - SET_IN6_IF_ADDR_ANY (@in6addr_any); - SET_LOOPBACK_ADDR6 (@in6addr_loopback); -end; - -finalization -begin - SynSockCS.Free; -end; - -{$ENDIF} - diff --git a/3rd/synapse/source/ssos2ws1.inc b/3rd/synapse/source/ssos2ws1.inc deleted file mode 100644 index 1a52b7039..000000000 --- a/3rd/synapse/source/ssos2ws1.inc +++ /dev/null @@ -1,1843 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.000.000 | -|==============================================================================| -| Content: Socket Independent Platform Layer - OS/2 winsock1 | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$MACRO ON} - -{$IFNDEF ODIN} - {$DEFINE WINSOCK1} - {$DEFINE PMWSOCK} -{$ENDIF ODIN} - -{$IFDEF PMWSOCK} - {$DEFINE extdecl := cdecl} -{$ELSE PMWSOCK} - {$DEFINE extdecl := stdcall} -{$ENDIF PMWSOCK} - -//{$DEFINE WINSOCK1} -{Note about define WINSOCK1: -If you activate this compiler directive, then socket interface level 1.1 is -used instead default level 2.2. Level 2.2 is not available on old W95, however -you can install update. -} - -//{$DEFINE FORCEOLDAPI} -{Note about define FORCEOLDAPI: -If you activate this compiler directive, then is allways used old socket API -for name resolution. If you leave this directive inactive, then the new API -is used, when running system allows it. - -For IPv6 support you must have new API! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$IFDEF VER125} - {$DEFINE BCB} -{$ENDIF} -{$IFDEF BCB} - {$ObjExportAll On} - (*$HPPEMIT '/* EDE 2003-02-19 */' *) - (*$HPPEMIT 'namespace Synsock { using System::Shortint; }' *) - (*$HPPEMIT '#undef h_addr' *) - (*$HPPEMIT '#undef IOCPARM_MASK' *) - (*$HPPEMIT '#undef FD_SETSIZE' *) - (*$HPPEMIT '#undef IOC_VOID' *) - (*$HPPEMIT '#undef IOC_OUT' *) - (*$HPPEMIT '#undef IOC_IN' *) - (*$HPPEMIT '#undef IOC_INOUT' *) - (*$HPPEMIT '#undef FIONREAD' *) - (*$HPPEMIT '#undef FIONBIO' *) - (*$HPPEMIT '#undef FIOASYNC' *) - (*$HPPEMIT '#undef IPPROTO_IP' *) - (*$HPPEMIT '#undef IPPROTO_ICMP' *) - (*$HPPEMIT '#undef IPPROTO_IGMP' *) - (*$HPPEMIT '#undef IPPROTO_TCP' *) - (*$HPPEMIT '#undef IPPROTO_UDP' *) - (*$HPPEMIT '#undef IPPROTO_RAW' *) - (*$HPPEMIT '#undef IPPROTO_MAX' *) - (*$HPPEMIT '#undef INADDR_ANY' *) - (*$HPPEMIT '#undef INADDR_LOOPBACK' *) - (*$HPPEMIT '#undef INADDR_BROADCAST' *) - (*$HPPEMIT '#undef INADDR_NONE' *) - (*$HPPEMIT '#undef INVALID_SOCKET' *) - (*$HPPEMIT '#undef SOCKET_ERROR' *) - (*$HPPEMIT '#undef WSADESCRIPTION_LEN' *) - (*$HPPEMIT '#undef WSASYS_STATUS_LEN' *) - (*$HPPEMIT '#undef IP_OPTIONS' *) - (*$HPPEMIT '#undef IP_TOS' *) - (*$HPPEMIT '#undef IP_TTL' *) - (*$HPPEMIT '#undef IP_MULTICAST_IF' *) - (*$HPPEMIT '#undef IP_MULTICAST_TTL' *) - (*$HPPEMIT '#undef IP_MULTICAST_LOOP' *) - (*$HPPEMIT '#undef IP_ADD_MEMBERSHIP' *) - (*$HPPEMIT '#undef IP_DROP_MEMBERSHIP' *) - (*$HPPEMIT '#undef IP_DONTFRAGMENT' *) - (*$HPPEMIT '#undef IP_DEFAULT_MULTICAST_TTL' *) - (*$HPPEMIT '#undef IP_DEFAULT_MULTICAST_LOOP' *) - (*$HPPEMIT '#undef IP_MAX_MEMBERSHIPS' *) - (*$HPPEMIT '#undef SOL_SOCKET' *) - (*$HPPEMIT '#undef SO_DEBUG' *) - (*$HPPEMIT '#undef SO_ACCEPTCONN' *) - (*$HPPEMIT '#undef SO_REUSEADDR' *) - (*$HPPEMIT '#undef SO_KEEPALIVE' *) - (*$HPPEMIT '#undef SO_DONTROUTE' *) - (*$HPPEMIT '#undef SO_BROADCAST' *) - (*$HPPEMIT '#undef SO_USELOOPBACK' *) - (*$HPPEMIT '#undef SO_LINGER' *) - (*$HPPEMIT '#undef SO_OOBINLINE' *) - (*$HPPEMIT '#undef SO_DONTLINGER' *) - (*$HPPEMIT '#undef SO_SNDBUF' *) - (*$HPPEMIT '#undef SO_RCVBUF' *) - (*$HPPEMIT '#undef SO_SNDLOWAT' *) - (*$HPPEMIT '#undef SO_RCVLOWAT' *) - (*$HPPEMIT '#undef SO_SNDTIMEO' *) - (*$HPPEMIT '#undef SO_RCVTIMEO' *) - (*$HPPEMIT '#undef SO_ERROR' *) - (*$HPPEMIT '#undef SO_OPENTYPE' *) - (*$HPPEMIT '#undef SO_SYNCHRONOUS_ALERT' *) - (*$HPPEMIT '#undef SO_SYNCHRONOUS_NONALERT' *) - (*$HPPEMIT '#undef SO_MAXDG' *) - (*$HPPEMIT '#undef SO_MAXPATHDG' *) - (*$HPPEMIT '#undef SO_UPDATE_ACCEPT_CONTEXT' *) - (*$HPPEMIT '#undef SO_CONNECT_TIME' *) - (*$HPPEMIT '#undef SO_TYPE' *) - (*$HPPEMIT '#undef SOCK_STREAM' *) - (*$HPPEMIT '#undef SOCK_DGRAM' *) - (*$HPPEMIT '#undef SOCK_RAW' *) - (*$HPPEMIT '#undef SOCK_RDM' *) - (*$HPPEMIT '#undef SOCK_SEQPACKET' *) - (*$HPPEMIT '#undef TCP_NODELAY' *) - (*$HPPEMIT '#undef AF_UNSPEC' *) - (*$HPPEMIT '#undef SOMAXCONN' *) - (*$HPPEMIT '#undef AF_INET' *) - (*$HPPEMIT '#undef AF_MAX' *) - (*$HPPEMIT '#undef PF_UNSPEC' *) - (*$HPPEMIT '#undef PF_INET' *) - (*$HPPEMIT '#undef PF_MAX' *) - (*$HPPEMIT '#undef MSG_OOB' *) - (*$HPPEMIT '#undef MSG_PEEK' *) - (*$HPPEMIT '#undef WSABASEERR' *) - (*$HPPEMIT '#undef WSAEINTR' *) - (*$HPPEMIT '#undef WSAEBADF' *) - (*$HPPEMIT '#undef WSAEACCES' *) - (*$HPPEMIT '#undef WSAEFAULT' *) - (*$HPPEMIT '#undef WSAEINVAL' *) - (*$HPPEMIT '#undef WSAEMFILE' *) - (*$HPPEMIT '#undef WSAEWOULDBLOCK' *) - (*$HPPEMIT '#undef WSAEINPROGRESS' *) - (*$HPPEMIT '#undef WSAEALREADY' *) - (*$HPPEMIT '#undef WSAENOTSOCK' *) - (*$HPPEMIT '#undef WSAEDESTADDRREQ' *) - (*$HPPEMIT '#undef WSAEMSGSIZE' *) - (*$HPPEMIT '#undef WSAEPROTOTYPE' *) - (*$HPPEMIT '#undef WSAENOPROTOOPT' *) - (*$HPPEMIT '#undef WSAEPROTONOSUPPORT' *) - (*$HPPEMIT '#undef WSAESOCKTNOSUPPORT' *) - (*$HPPEMIT '#undef WSAEOPNOTSUPP' *) - (*$HPPEMIT '#undef WSAEPFNOSUPPORT' *) - (*$HPPEMIT '#undef WSAEAFNOSUPPORT' *) - (*$HPPEMIT '#undef WSAEADDRINUSE' *) - (*$HPPEMIT '#undef WSAEADDRNOTAVAIL' *) - (*$HPPEMIT '#undef WSAENETDOWN' *) - (*$HPPEMIT '#undef WSAENETUNREACH' *) - (*$HPPEMIT '#undef WSAENETRESET' *) - (*$HPPEMIT '#undef WSAECONNABORTED' *) - (*$HPPEMIT '#undef WSAECONNRESET' *) - (*$HPPEMIT '#undef WSAENOBUFS' *) - (*$HPPEMIT '#undef WSAEISCONN' *) - (*$HPPEMIT '#undef WSAENOTCONN' *) - (*$HPPEMIT '#undef WSAESHUTDOWN' *) - (*$HPPEMIT '#undef WSAETOOMANYREFS' *) - (*$HPPEMIT '#undef WSAETIMEDOUT' *) - (*$HPPEMIT '#undef WSAECONNREFUSED' *) - (*$HPPEMIT '#undef WSAELOOP' *) - (*$HPPEMIT '#undef WSAENAMETOOLONG' *) - (*$HPPEMIT '#undef WSAEHOSTDOWN' *) - (*$HPPEMIT '#undef WSAEHOSTUNREACH' *) - (*$HPPEMIT '#undef WSAENOTEMPTY' *) - (*$HPPEMIT '#undef WSAEPROCLIM' *) - (*$HPPEMIT '#undef WSAEUSERS' *) - (*$HPPEMIT '#undef WSAEDQUOT' *) - (*$HPPEMIT '#undef WSAESTALE' *) - (*$HPPEMIT '#undef WSAEREMOTE' *) - (*$HPPEMIT '#undef WSASYSNOTREADY' *) - (*$HPPEMIT '#undef WSAVERNOTSUPPORTED' *) - (*$HPPEMIT '#undef WSANOTINITIALISED' *) - (*$HPPEMIT '#undef WSAEDISCON' *) - (*$HPPEMIT '#undef WSAENOMORE' *) - (*$HPPEMIT '#undef WSAECANCELLED' *) - (*$HPPEMIT '#undef WSAEEINVALIDPROCTABLE' *) - (*$HPPEMIT '#undef WSAEINVALIDPROVIDER' *) - (*$HPPEMIT '#undef WSAEPROVIDERFAILEDINIT' *) - (*$HPPEMIT '#undef WSASYSCALLFAILURE' *) - (*$HPPEMIT '#undef WSASERVICE_NOT_FOUND' *) - (*$HPPEMIT '#undef WSATYPE_NOT_FOUND' *) - (*$HPPEMIT '#undef WSA_E_NO_MORE' *) - (*$HPPEMIT '#undef WSA_E_CANCELLED' *) - (*$HPPEMIT '#undef WSAEREFUSED' *) - (*$HPPEMIT '#undef WSAHOST_NOT_FOUND' *) - (*$HPPEMIT '#undef HOST_NOT_FOUND' *) - (*$HPPEMIT '#undef WSATRY_AGAIN' *) - (*$HPPEMIT '#undef TRY_AGAIN' *) - (*$HPPEMIT '#undef WSANO_RECOVERY' *) - (*$HPPEMIT '#undef NO_RECOVERY' *) - (*$HPPEMIT '#undef WSANO_DATA' *) - (*$HPPEMIT '#undef NO_DATA' *) - (*$HPPEMIT '#undef WSANO_ADDRESS' *) - (*$HPPEMIT '#undef ENAMETOOLONG' *) - (*$HPPEMIT '#undef ENOTEMPTY' *) - (*$HPPEMIT '#undef FD_CLR' *) - (*$HPPEMIT '#undef FD_ISSET' *) - (*$HPPEMIT '#undef FD_SET' *) - (*$HPPEMIT '#undef FD_ZERO' *) - (*$HPPEMIT '#undef NO_ADDRESS' *) - (*$HPPEMIT '#undef ADDR_ANY' *) - (*$HPPEMIT '#undef SO_GROUP_ID' *) - (*$HPPEMIT '#undef SO_GROUP_PRIORITY' *) - (*$HPPEMIT '#undef SO_MAX_MSG_SIZE' *) - (*$HPPEMIT '#undef SO_PROTOCOL_INFOA' *) - (*$HPPEMIT '#undef SO_PROTOCOL_INFOW' *) - (*$HPPEMIT '#undef SO_PROTOCOL_INFO' *) - (*$HPPEMIT '#undef PVD_CONFIG' *) - (*$HPPEMIT '#undef AF_INET6' *) - (*$HPPEMIT '#undef PF_INET6' *) -{$ENDIF} - -{$IFDEF FPC} - {$IFDEF WIN32} - {$ALIGN OFF} - {$ELSE} - {$PACKRECORDS C} - {$ENDIF} -{$ELSE} - {$IFDEF WIN64} - {$ALIGN ON} - {$MINENUMSIZE 4} - {$ELSE} - {$MINENUMSIZE 4} - {$ALIGN OFF} - {$ENDIF} -{$ENDIF} - -interface - -uses - SyncObjs, SysUtils, Classes, -{$IFDEF OS2} - Sockets, Dynlibs -{$ELSE OS2} - Windows -{$ENDIF OS2} -; - -function InitSocketInterface(stack: String): Boolean; -function DestroySocketInterface: Boolean; - -const -{$IFDEF WINSOCK1} - WinsockLevel = $0101; -{$ELSE} - WinsockLevel = $0202; -{$ENDIF} - -type -{$IFDEF OS2} - Bool = longint; -{$ENDIF OS2} - u_short = Word; - u_int = Integer; - u_long = Longint; - pu_long = ^u_long; - pu_short = ^u_short; -{$IFDEF FPC} - TSocket = ptruint; -{$ELSE} - {$IFDEF WIN64} - TSocket = UINT_PTR; - {$ELSE} - TSocket = u_int; - {$ENDIF} -{$ENDIF} - TAddrFamily = integer; - - TMemory = pointer; - -const - {$IFDEF WINCE} - DLLStackName = 'ws2.dll'; - {$ELSE} - {$IFDEF WINSOCK1} - {$IFDEF OS2} - {$IFDEF DAPWSOCK} - DLLStackName = 'dapwsock.dll'; - {$ELSE DAPWSOCK} - DLLStackName = 'pmwsock.dll'; - {$ENDIF DAPWSOCK} - {$ELSE OS2} - DLLStackName = 'wsock32.dll'; - {$ENDIF OS2} - {$ELSE} - DLLStackName = 'ws2_32.dll'; - {$ENDIF} - {$ENDIF} - DLLwship6 = 'wship6.dll'; - - cLocalhost = '127.0.0.1'; - cAnyHost = '0.0.0.0'; - cBroadcast = '255.255.255.255'; - c6Localhost = '::1'; - c6AnyHost = '::0'; - c6Broadcast = 'ffff::1'; - cAnyPort = '0'; - - -const - FD_SETSIZE = 64; -type - PFDSet = ^TFDSet; - TFDSet = record - fd_count: u_int; - fd_array: array[0..FD_SETSIZE-1] of TSocket; - end; - -const - FIONREAD = $4004667f; - FIONBIO = $8004667e; - FIOASYNC = $8004667d; - -type - PTimeVal = ^TTimeVal; - TTimeVal = record - tv_sec: Longint; - tv_usec: Longint; - end; - -const - IPPROTO_IP = 0; { Dummy } - IPPROTO_ICMP = 1; { Internet Control Message Protocol } - IPPROTO_IGMP = 2; { Internet Group Management Protocol} - IPPROTO_TCP = 6; { TCP } - IPPROTO_UDP = 17; { User Datagram Protocol } - IPPROTO_IPV6 = 41; - IPPROTO_ICMPV6 = 58; - IPPROTO_RM = 113; - - IPPROTO_RAW = 255; - IPPROTO_MAX = 256; - -type - - PInAddr = ^TInAddr; - TInAddr = record - case integer of - 0: (S_bytes: packed array [0..3] of byte); - 1: (S_addr: u_long); - end; - - PSockAddrIn = ^TSockAddrIn; - TSockAddrIn = record - case Integer of - 0: (sin_family: u_short; - sin_port: u_short; - sin_addr: TInAddr; - sin_zero: array[0..7] of byte); - 1: (sa_family: u_short; - sa_data: array[0..13] of byte) - end; - - TIP_mreq = record - imr_multiaddr: TInAddr; { IP multicast address of group } - imr_interface: TInAddr; { local IP address of interface } - end; - - PInAddr6 = ^TInAddr6; - TInAddr6 = record - case integer of - 0: (S6_addr: packed array [0..15] of byte); - 1: (u6_addr8: packed array [0..15] of byte); - 2: (u6_addr16: packed array [0..7] of word); - 3: (u6_addr32: packed array [0..3] of integer); - end; - - PSockAddrIn6 = ^TSockAddrIn6; - TSockAddrIn6 = record - sin6_family: u_short; // AF_INET6 - sin6_port: u_short; // Transport level port number - sin6_flowinfo: u_long; // IPv6 flow information - sin6_addr: TInAddr6; // IPv6 address - sin6_scope_id: u_long; // Scope Id: IF number for link-local - // SITE id for site-local - end; - - TIPv6_mreq = record - ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: integer; // Interface index. - padding: integer; - end; - - PHostEnt = ^THostEnt; - THostEnt = record - h_name: PAnsiChar; - h_aliases: ^PAnsiChar; -{$IFDEF PMWSOCK} - h_addrtype: longint; - h_length: longint; -{$ELSE PMWSOCK} - h_addrtype: Smallint; - h_length: Smallint; -{$ENDIF PMWSOCK} - case integer of - 0: (h_addr_list: ^PAnsiChar); - 1: (h_addr: ^PInAddr); - end; - - PNetEnt = ^TNetEnt; - TNetEnt = record - n_name: PAnsiChar; - n_aliases: ^PAnsiChar; -{$IFDEF PMWSOCK} - n_addrtype: longint; -{$ELSE PMWSOCK} - n_addrtype: Smallint; -{$ENDIF PMWSOCK} - n_net: u_long; - end; - - PServEnt = ^TServEnt; - TServEnt = record - s_name: PAnsiChar; - s_aliases: ^PAnsiChar; -{$ifdef WIN64} - s_proto: PAnsiChar; - s_port: Smallint; -{$else} -{$IFDEF PMWSOCK} - s_port: longint; -{$ELSE PMWSOCK} - s_port: Smallint; -{$ENDIF PMWSOCK} - s_proto: PAnsiChar; -{$endif} - end; - - PProtoEnt = ^TProtoEnt; - TProtoEnt = record - p_name: PAnsiChar; - p_aliases: ^PAnsichar; -{$IFDEF PMWSOCK} - p_proto: longint; -{$ELSE PMWSOCK} - p_proto: Smallint; -{$ENDIF PMWSOCK} - end; - -const - INADDR_ANY = $00000000; - INADDR_LOOPBACK = $7F000001; - INADDR_BROADCAST = $FFFFFFFF; - INADDR_NONE = $FFFFFFFF; - ADDR_ANY = INADDR_ANY; - INVALID_SOCKET = TSocket(NOT(0)); - SOCKET_ERROR = -1; - -Const - {$IFDEF WINSOCK1} - IP_OPTIONS = 1; - IP_MULTICAST_IF = 2; { set/get IP multicast interface } - IP_MULTICAST_TTL = 3; { set/get IP multicast timetolive } - IP_MULTICAST_LOOP = 4; { set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = 5; { add an IP group membership } - IP_DROP_MEMBERSHIP = 6; { drop an IP group membership } - IP_TTL = 7; { set/get IP Time To Live } - IP_TOS = 8; { set/get IP Type Of Service } - IP_DONTFRAGMENT = 9; { set/get IP Don't Fragment flag } - {$ELSE} - IP_OPTIONS = 1; - IP_HDRINCL = 2; - IP_TOS = 3; { set/get IP Type Of Service } - IP_TTL = 4; { set/get IP Time To Live } - IP_MULTICAST_IF = 9; { set/get IP multicast interface } - IP_MULTICAST_TTL = 10; { set/get IP multicast timetolive } - IP_MULTICAST_LOOP = 11; { set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = 12; { add an IP group membership } - IP_DROP_MEMBERSHIP = 13; { drop an IP group membership } - IP_DONTFRAGMENT = 14; { set/get IP Don't Fragment flag } - {$ENDIF} - - IP_DEFAULT_MULTICAST_TTL = 1; { normally limit m'casts to 1 hop } - IP_DEFAULT_MULTICAST_LOOP = 1; { normally hear sends if a member } - IP_MAX_MEMBERSHIPS = 20; { per socket; must fit in one mbuf } - - SOL_SOCKET = $ffff; {options for socket level } -{ Option flags per-socket. } - SO_DEBUG = $0001; { turn on debugging info recording } - SO_ACCEPTCONN = $0002; { socket has had listen() } - SO_REUSEADDR = $0004; { allow local address reuse } - SO_KEEPALIVE = $0008; { keep connections alive } - SO_DONTROUTE = $0010; { just use interface addresses } - SO_BROADCAST = $0020; { permit sending of broadcast msgs } - SO_USELOOPBACK = $0040; { bypass hardware when possible } - SO_LINGER = $0080; { linger on close if data present } - SO_OOBINLINE = $0100; { leave received OOB data in line } - SO_DONTLINGER = $ff7f; -{ Additional options. } - SO_SNDBUF = $1001; { send buffer size } - SO_RCVBUF = $1002; { receive buffer size } - SO_SNDLOWAT = $1003; { send low-water mark } - SO_RCVLOWAT = $1004; { receive low-water mark } - SO_SNDTIMEO = $1005; { send timeout } - SO_RCVTIMEO = $1006; { receive timeout } - SO_ERROR = $1007; { get error status and clear } - SO_TYPE = $1008; { get socket type } -{ WinSock 2 extension -- new options } - SO_GROUP_ID = $2001; { ID of a socket group} - SO_GROUP_PRIORITY = $2002; { the relative priority within a group} - SO_MAX_MSG_SIZE = $2003; { maximum message size } - SO_PROTOCOL_INFOA = $2004; { WSAPROTOCOL_INFOA structure } - SO_PROTOCOL_INFOW = $2005; { WSAPROTOCOL_INFOW structure } - SO_PROTOCOL_INFO = SO_PROTOCOL_INFOA; - PVD_CONFIG = $3001; {configuration info for service provider } -{ Option for opening sockets for synchronous access. } - SO_OPENTYPE = $7008; - SO_SYNCHRONOUS_ALERT = $10; - SO_SYNCHRONOUS_NONALERT = $20; -{ Other NT-specific options. } - SO_MAXDG = $7009; - SO_MAXPATHDG = $700A; - SO_UPDATE_ACCEPT_CONTEXT = $700B; - SO_CONNECT_TIME = $700C; - - SOMAXCONN = $7fffffff; - - IPV6_UNICAST_HOPS = 8; // ??? - IPV6_MULTICAST_IF = 9; // set/get IP multicast i/f - IPV6_MULTICAST_HOPS = 10; // set/get IP multicast ttl - IPV6_MULTICAST_LOOP = 11; // set/get IP multicast loopback - IPV6_JOIN_GROUP = 12; // add an IP group membership - IPV6_LEAVE_GROUP = 13; // drop an IP group membership - - MSG_NOSIGNAL = 0; - - // getnameinfo constants - NI_MAXHOST = 1025; - NI_MAXSERV = 32; - NI_NOFQDN = $1; - NI_NUMERICHOST = $2; - NI_NAMEREQD = $4; - NI_NUMERICSERV = $8; - NI_DGRAM = $10; - - -const - SOCK_STREAM = 1; { stream socket } - SOCK_DGRAM = 2; { datagram socket } - SOCK_RAW = 3; { raw-protocol interface } - SOCK_RDM = 4; { reliably-delivered message } - SOCK_SEQPACKET = 5; { sequenced packet stream } - -{ TCP options. } - TCP_NODELAY = $0001; - -{ Address families. } - - AF_UNSPEC = 0; { unspecified } - AF_INET = 2; { internetwork: UDP, TCP, etc. } - AF_INET6 = 23; { Internetwork Version 6 } - AF_MAX = 24; - -{ Protocol families, same as address families for now. } - PF_UNSPEC = AF_UNSPEC; - PF_INET = AF_INET; - PF_INET6 = AF_INET6; - PF_MAX = AF_MAX; - -type - { Structure used by kernel to store most addresses. } - PSockAddr = ^TSockAddr; - TSockAddr = TSockAddrIn; - - { Structure used by kernel to pass protocol information in raw sockets. } - PSockProto = ^TSockProto; - TSockProto = record - sp_family: u_short; - sp_protocol: u_short; - end; - -type - PAddrInfo = ^TAddrInfo; - TAddrInfo = record - ai_flags: integer; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST. - ai_family: integer; // PF_xxx. - ai_socktype: integer; // SOCK_xxx. - ai_protocol: integer; // 0 or IPPROTO_xxx for IPv4 and IPv6. - ai_addrlen: u_int; // Length of ai_addr. - ai_canonname: PAnsiChar; // Canonical name for nodename. - ai_addr: PSockAddr; // Binary address. - ai_next: PAddrInfo; // Next structure in linked list. - end; - -const - // Flags used in "hints" argument to getaddrinfo(). - AI_PASSIVE = $1; // Socket address will be used in bind() call. - AI_CANONNAME = $2; // Return canonical name in first ai_canonname. - AI_NUMERICHOST = $4; // Nodename must be a numeric address string. - -type -{ Structure used for manipulating linger option. } - PLinger = ^TLinger; - TLinger = record -{$IFDEF PMWSOCK} - l_onoff: longint; - l_linger: longint; -{$ELSE PMWSOCK} - l_onoff: u_short; - l_linger: u_short; -{$ENDIF PMWSOCK} - end; - -const - - MSG_OOB = $01; // Process out-of-band data. - MSG_PEEK = $02; // Peek at incoming messages. - -const - -{ All Windows Sockets error constants are biased by WSABASEERR from the "normal" } - WSABASEERR = 10000; - -{ Windows Sockets definitions of regular Microsoft C error constants } - - WSAEINTR = (WSABASEERR+4); - WSAEBADF = (WSABASEERR+9); - WSAEACCES = (WSABASEERR+13); - WSAEFAULT = (WSABASEERR+14); - WSAEINVAL = (WSABASEERR+22); - WSAEMFILE = (WSABASEERR+24); - -{ Windows Sockets definitions of regular Berkeley error constants } - - WSAEWOULDBLOCK = (WSABASEERR+35); - WSAEINPROGRESS = (WSABASEERR+36); - WSAEALREADY = (WSABASEERR+37); - WSAENOTSOCK = (WSABASEERR+38); - WSAEDESTADDRREQ = (WSABASEERR+39); - WSAEMSGSIZE = (WSABASEERR+40); - WSAEPROTOTYPE = (WSABASEERR+41); - WSAENOPROTOOPT = (WSABASEERR+42); - WSAEPROTONOSUPPORT = (WSABASEERR+43); - WSAESOCKTNOSUPPORT = (WSABASEERR+44); - WSAEOPNOTSUPP = (WSABASEERR+45); - WSAEPFNOSUPPORT = (WSABASEERR+46); - WSAEAFNOSUPPORT = (WSABASEERR+47); - WSAEADDRINUSE = (WSABASEERR+48); - WSAEADDRNOTAVAIL = (WSABASEERR+49); - WSAENETDOWN = (WSABASEERR+50); - WSAENETUNREACH = (WSABASEERR+51); - WSAENETRESET = (WSABASEERR+52); - WSAECONNABORTED = (WSABASEERR+53); - WSAECONNRESET = (WSABASEERR+54); - WSAENOBUFS = (WSABASEERR+55); - WSAEISCONN = (WSABASEERR+56); - WSAENOTCONN = (WSABASEERR+57); - WSAESHUTDOWN = (WSABASEERR+58); - WSAETOOMANYREFS = (WSABASEERR+59); - WSAETIMEDOUT = (WSABASEERR+60); - WSAECONNREFUSED = (WSABASEERR+61); - WSAELOOP = (WSABASEERR+62); - WSAENAMETOOLONG = (WSABASEERR+63); - WSAEHOSTDOWN = (WSABASEERR+64); - WSAEHOSTUNREACH = (WSABASEERR+65); - WSAENOTEMPTY = (WSABASEERR+66); - WSAEPROCLIM = (WSABASEERR+67); - WSAEUSERS = (WSABASEERR+68); - WSAEDQUOT = (WSABASEERR+69); - WSAESTALE = (WSABASEERR+70); - WSAEREMOTE = (WSABASEERR+71); - -{ Extended Windows Sockets error constant definitions } - - WSASYSNOTREADY = (WSABASEERR+91); - WSAVERNOTSUPPORTED = (WSABASEERR+92); - WSANOTINITIALISED = (WSABASEERR+93); - WSAEDISCON = (WSABASEERR+101); - WSAENOMORE = (WSABASEERR+102); - WSAECANCELLED = (WSABASEERR+103); - WSAEEINVALIDPROCTABLE = (WSABASEERR+104); - WSAEINVALIDPROVIDER = (WSABASEERR+105); - WSAEPROVIDERFAILEDINIT = (WSABASEERR+106); - WSASYSCALLFAILURE = (WSABASEERR+107); - WSASERVICE_NOT_FOUND = (WSABASEERR+108); - WSATYPE_NOT_FOUND = (WSABASEERR+109); - WSA_E_NO_MORE = (WSABASEERR+110); - WSA_E_CANCELLED = (WSABASEERR+111); - WSAEREFUSED = (WSABASEERR+112); - -{ Error return codes from gethostbyname() and gethostbyaddr() - (when using the resolver). Note that these errors are - retrieved via WSAGetLastError() and must therefore follow - the rules for avoiding clashes with error numbers from - specific implementations or language run-time systems. - For this reason the codes are based at WSABASEERR+1001. - Note also that [WSA]NO_ADDRESS is defined only for - compatibility purposes. } - -{ Authoritative Answer: Host not found } - WSAHOST_NOT_FOUND = (WSABASEERR+1001); - HOST_NOT_FOUND = WSAHOST_NOT_FOUND; -{ Non-Authoritative: Host not found, or SERVERFAIL } - WSATRY_AGAIN = (WSABASEERR+1002); - TRY_AGAIN = WSATRY_AGAIN; -{ Non recoverable errors, FORMERR, REFUSED, NOTIMP } - WSANO_RECOVERY = (WSABASEERR+1003); - NO_RECOVERY = WSANO_RECOVERY; -{ Valid name, no data record of requested type } - WSANO_DATA = (WSABASEERR+1004); - NO_DATA = WSANO_DATA; -{ no address, look for MX record } - WSANO_ADDRESS = WSANO_DATA; - NO_ADDRESS = WSANO_ADDRESS; - - EWOULDBLOCK = WSAEWOULDBLOCK; - EINPROGRESS = WSAEINPROGRESS; - EALREADY = WSAEALREADY; - ENOTSOCK = WSAENOTSOCK; - EDESTADDRREQ = WSAEDESTADDRREQ; - EMSGSIZE = WSAEMSGSIZE; - EPROTOTYPE = WSAEPROTOTYPE; - ENOPROTOOPT = WSAENOPROTOOPT; - EPROTONOSUPPORT = WSAEPROTONOSUPPORT; - ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT; - EOPNOTSUPP = WSAEOPNOTSUPP; - EPFNOSUPPORT = WSAEPFNOSUPPORT; - EAFNOSUPPORT = WSAEAFNOSUPPORT; - EADDRINUSE = WSAEADDRINUSE; - EADDRNOTAVAIL = WSAEADDRNOTAVAIL; - ENETDOWN = WSAENETDOWN; - ENETUNREACH = WSAENETUNREACH; - ENETRESET = WSAENETRESET; - ECONNABORTED = WSAECONNABORTED; - ECONNRESET = WSAECONNRESET; - ENOBUFS = WSAENOBUFS; - EISCONN = WSAEISCONN; - ENOTCONN = WSAENOTCONN; - ESHUTDOWN = WSAESHUTDOWN; - ETOOMANYREFS = WSAETOOMANYREFS; - ETIMEDOUT = WSAETIMEDOUT; - ECONNREFUSED = WSAECONNREFUSED; - ELOOP = WSAELOOP; - ENAMETOOLONG = WSAENAMETOOLONG; - EHOSTDOWN = WSAEHOSTDOWN; - EHOSTUNREACH = WSAEHOSTUNREACH; - ENOTEMPTY = WSAENOTEMPTY; - EPROCLIM = WSAEPROCLIM; - EUSERS = WSAEUSERS; - EDQUOT = WSAEDQUOT; - ESTALE = WSAESTALE; - EREMOTE = WSAEREMOTE; - - EAI_ADDRFAMILY = 1; // Address family for nodename not supported. - EAI_AGAIN = 2; // Temporary failure in name resolution. - EAI_BADFLAGS = 3; // Invalid value for ai_flags. - EAI_FAIL = 4; // Non-recoverable failure in name resolution. - EAI_FAMILY = 5; // Address family ai_family not supported. - EAI_MEMORY = 6; // Memory allocation failure. - EAI_NODATA = 7; // No address associated with nodename. - EAI_NONAME = 8; // Nodename nor servname provided, or not known. - EAI_SERVICE = 9; // Servname not supported for ai_socktype. - EAI_SOCKTYPE = 10; // Socket type ai_socktype not supported. - EAI_SYSTEM = 11; // System error returned in errno. - -const - WSADESCRIPTION_LEN = 256; - WSASYS_STATUS_LEN = 128; -type - PWSAData = ^TWSAData; - TWSAData = record - wVersion: Word; - wHighVersion: Word; -{$ifdef win64} - iMaxSockets : Word; - iMaxUdpDg : Word; - lpVendorInfo : PAnsiChar; - szDescription : array[0..WSADESCRIPTION_LEN] of AnsiChar; - szSystemStatus : array[0..WSASYS_STATUS_LEN] of AnsiChar; -{$else} - szDescription: array[0..WSADESCRIPTION_LEN] of AnsiChar; - szSystemStatus: array[0..WSASYS_STATUS_LEN] of AnsiChar; - iMaxSockets: Word; - iMaxUdpDg: Word; - lpVendorInfo: PAnsiChar; -{$endif} - end; - - function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; - function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; - procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); - procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -var - in6addr_any, in6addr_loopback : TInAddr6; - -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -procedure FD_ZERO(var FDSet: TFDSet); - -{=============================================================================} - -type - TWSAStartup = function(wVersionRequired: Word; var WSData: TWSAData): Integer; - extdecl; - TWSACleanup = function: Integer; - extdecl; - TWSAGetLastError = function: Integer; - extdecl; - TGetServByName = function(name, proto: PAnsiChar): PServEnt; - extdecl; - TGetServByPort = function(port: Integer; proto: PAnsiChar): PServEnt; - extdecl; - TGetProtoByName = function(name: PAnsiChar): PProtoEnt; - extdecl; - TGetProtoByNumber = function(proto: Integer): PProtoEnt; - extdecl; - TGetHostByName = function(name: PAnsiChar): PHostEnt; - extdecl; - TGetHostByAddr = function(addr: Pointer; len, Struc: Integer): PHostEnt; - extdecl; - TGetHostName = function(name: PAnsiChar; len: Integer): Integer; - extdecl; - TShutdown = function(s: TSocket; how: Integer): Integer; - extdecl; - TSetSockOpt = function(s: TSocket; level, optname: Integer; optval: PAnsiChar; - optlen: Integer): Integer; - extdecl; - TGetSockOpt = function(s: TSocket; level, optname: Integer; optval: PAnsiChar; - var optlen: Integer): Integer; - extdecl; - TSendTo = function(s: TSocket; const Buf; len, flags: Integer; addrto: PSockAddr; - tolen: Integer): Integer; - extdecl; - TSend = function(s: TSocket; const Buf; len, flags: Integer): Integer; - extdecl; - TRecv = function(s: TSocket; var Buf; len, flags: Integer): Integer; - extdecl; - TRecvFrom = function(s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; - var fromlen: Integer): Integer; - extdecl; - Tntohs = function(netshort: u_short): u_short; - extdecl; - Tntohl = function(netlong: u_long): u_long; - extdecl; - TListen = function(s: TSocket; backlog: Integer): Integer; - extdecl; - TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: Integer): Integer; - extdecl; - TInet_ntoa = function(inaddr: TInAddr): PAnsiChar; - extdecl; - TInet_addr = function(cp: PAnsiChar): u_long; - extdecl; - Thtons = function(hostshort: u_short): u_short; - extdecl; - Thtonl = function(hostlong: u_long): u_long; - extdecl; - TGetSockName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - extdecl; - TGetPeerName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - extdecl; - TConnect = function(s: TSocket; name: PSockAddr; namelen: Integer): Integer; - extdecl; - TCloseSocket = function(s: TSocket): Integer; - extdecl; - TBind = function(s: TSocket; addr: PSockAddr; namelen: Integer): Integer; - extdecl; - TAccept = function(s: TSocket; addr: PSockAddr; var addrlen: Integer): TSocket; - extdecl; - TTSocket = function(af, Struc, Protocol: Integer): TSocket; - extdecl; - TSelect = function(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; - extdecl; - - TGetAddrInfo = function(NodeName: PAnsiChar; ServName: PAnsiChar; Hints: PAddrInfo; - var Addrinfo: PAddrInfo): integer; - extdecl; - TFreeAddrInfo = procedure(ai: PAddrInfo); - extdecl; - TGetNameInfo = function( addr: PSockAddr; namelen: Integer; host: PAnsiChar; - hostlen: DWORD; serv: PAnsiChar; servlen: DWORD; flags: integer): integer; - extdecl; - - T__WSAFDIsSet = function (s: TSocket; var FDSet: TFDSet): Bool; - extdecl; - - TWSAIoctl = function (s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; - cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD; - lpcbBytesReturned: PDWORD; lpOverlapped: Pointer; - lpCompletionRoutine: pointer): u_int; - extdecl; - -var - WSAStartup: TWSAStartup = nil; - WSACleanup: TWSACleanup = nil; - WSAGetLastError: TWSAGetLastError = nil; - GetServByName: TGetServByName = nil; - GetServByPort: TGetServByPort = nil; - GetProtoByName: TGetProtoByName = nil; - GetProtoByNumber: TGetProtoByNumber = nil; - GetHostByName: TGetHostByName = nil; - GetHostByAddr: TGetHostByAddr = nil; - ssGetHostName: TGetHostName = nil; -{$IFDEF OS2} - ssShutdown: TShutdown = nil; - ssSetSockOpt: TSetSockOpt = nil; - ssGetSockOpt: TGetSockOpt = nil; -{$ELSE OS2} - Shutdown: TShutdown = nil; - SetSockOpt: TSetSockOpt = nil; - GetSockOpt: TGetSockOpt = nil; -{$ENDIF OS2} - ssSendTo: TSendTo = nil; - ssSend: TSend = nil; - ssRecv: TRecv = nil; - ssRecvFrom: TRecvFrom = nil; - ntohs: Tntohs = nil; - ntohl: Tntohl = nil; -{$IFDEF OS2} - ssListen: TListen = nil; - ssIoctlSocket: TIoctlSocket = nil; -{$ELSE OS2} - Listen: TListen = nil; - IoctlSocket: TIoctlSocket = nil; -{$ENDIF OS2} - Inet_ntoa: TInet_ntoa = nil; - Inet_addr: TInet_addr = nil; - htons: Thtons = nil; - htonl: Thtonl = nil; - ssGetSockName: TGetSockName = nil; - ssGetPeerName: TGetPeerName = nil; - ssConnect: TConnect = nil; -{$IFDEF OS2} - ssCloseSocket: TCloseSocket = nil; -{$ELSE OS2} - CloseSocket: TCloseSocket = nil; -{$ENDIF OS2} - ssBind: TBind = nil; - ssAccept: TAccept = nil; -{$IFDEF OS2} - ssSocket: TTSocket = nil; -{$ELSE OS2} - Socket: TTSocket = nil; -{$ENDIF OS2} - Select: TSelect = nil; - - GetAddrInfo: TGetAddrInfo = nil; - FreeAddrInfo: TFreeAddrInfo = nil; - GetNameInfo: TGetNameInfo = nil; - -{$IFDEF OS2} - ss__WSAFDIsSet: T__WSAFDIsSet = nil; - - ssWSAIoctl: TWSAIoctl = nil; -{$ELSE OS2} - __WSAFDIsSet: T__WSAFDIsSet = nil; - - WSAIoctl: TWSAIoctl = nil; -{$ENDIF OS2} - -var - SynSockCS: SyncObjs.TCriticalSection; - SockEnhancedApi: Boolean; - SockWship6Api: Boolean; - -type - TVarSin = packed record - case integer of - 0: (AddressFamily: u_short); - 1: ( - case sin_family: u_short of - AF_INET: (sin_port: u_short; - sin_addr: TInAddr; - sin_zero: array[0..7] of byte); - AF_INET6: (sin6_port: u_short; - sin6_flowinfo: u_long; - sin6_addr: TInAddr6; - sin6_scope_id: u_long); - ); - end; - -function SizeOfVarSin(sin: TVarSin): integer; - -function Bind(s: TSocket; const addr: TVarSin): Integer; -function Connect(s: TSocket; const name: TVarSin): Integer; -function GetSockName(s: TSocket; var name: TVarSin): Integer; -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -function GetHostName: AnsiString; -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -function Accept(s: TSocket; var addr: TVarSin): TSocket; - -function IsNewApi(Family: integer): Boolean; -function SetVarSin(var Sin: TVarSin; IP, Port: AnsiString; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -function GetSinIP(Sin: TVarSin): AnsiString; -function GetSinPort(Sin: TVarSin): Integer; -procedure ResolveNameToIP(Name: AnsiString; Family, SockProtocol, SockType: integer; const IPList: TStrings); -function ResolveIPToName(IP: AnsiString; Family, SockProtocol, SockType: integer): AnsiString; -function ResolvePort(Port: AnsiString; Family, SockProtocol, SockType: integer): Word; -{$IFDEF OS2} -function Socket (af, Struc, Protocol: Integer): TSocket; -function Shutdown (s: TSocket; how: Integer): Integer; -function SetSockOpt (s: TSocket; level, optname: Integer; optval: PAnsiChar; - optlen: Integer): Integer; -function GetSockOpt (s: TSocket; level, optname: Integer; optval: PAnsiChar; - var optlen: Integer): Integer; -function Listen (s: TSocket; backlog: Integer): Integer; -function IoctlSocket (s: TSocket; cmd: DWORD; var arg: Integer): Integer; -function CloseSocket (s: TSocket): Integer; - -function __WSAFDIsSet (s: TSocket; var FDSet: TFDSet): Bool; - -function WSAIoctl (s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; - cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD; - lpcbBytesReturned: PDWORD; lpOverlapped: Pointer; - lpCompletionRoutine: pointer): u_int; -{$ENDIF OS2} - -{==============================================================================} -implementation - -var - SynSockCount: Integer = 0; - LibHandle: THandle = 0; - Libwship6Handle: THandle = 0; - -function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); -end; - -function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and - (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and - (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); -end; - -function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); -end; - -function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); -end; - -function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; -begin - Result := (a^.u6_addr8[0] = $FF); -end; - -function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; -begin - Result := (CompareMem( a, b, sizeof(TInAddr6))); -end; - -procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); -end; - -procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); - a^.u6_addr8[15] := 1; -end; - -{=============================================================================} -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -var - I: Integer; -begin -{$IFDEF OS2} - Socket := TSocket (NativeSocket (cInt (Socket))); -{$ENDIF OS2} - I := 0; - while I < FDSet.fd_count do - begin - if FDSet.fd_array[I] = Socket then - begin - while I < FDSet.fd_count - 1 do - begin - FDSet.fd_array[I] := FDSet.fd_array[I + 1]; - Inc(I); - end; - Dec(FDSet.fd_count); - Break; - end; - Inc(I); - end; -end; - -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -begin -{$IFDEF OS2} - Socket := TSocket (NativeSocket (cInt (Socket))); -{$ENDIF OS2} - Result := __WSAFDIsSet(Socket, FDSet) -{$IFDEF OS2} - <> 0 -{$ENDIF OS2} ; -end; - -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -begin -{$IFDEF OS2} - Socket := TSocket (NativeSocket (cInt (Socket))); -{$ENDIF OS2} - if FDSet.fd_count < FD_SETSIZE then - begin - FDSet.fd_array[FDSet.fd_count] := Socket; - Inc(FDSet.fd_count); - end; -end; - -procedure FD_ZERO(var FDSet: TFDSet); -begin - FDSet.fd_count := 0; -end; - -{=============================================================================} - -function SizeOfVarSin(sin: TVarSin): integer; -begin - case sin.sin_family of - AF_INET: - Result := SizeOf(TSockAddrIn); - AF_INET6: - Result := SizeOf(TSockAddrIn6); - else - Result := 0; - end; -end; - -{=============================================================================} - -function Bind(s: TSocket; const addr: TVarSin): Integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - Result := ssBind(s, @addr, SizeOfVarSin(addr)); -end; - -function Connect(s: TSocket; const name: TVarSin): Integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - Result := ssConnect(s, @name, SizeOfVarSin(name)); -end; - -function GetSockName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - len := SizeOf(name); - FillChar(name, len, 0); - Result := ssGetSockName(s, @name, Len); -end; - -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - len := SizeOf(name); - FillChar(name, len, 0); - Result := ssGetPeerName(s, @name, Len); -end; - -function GetHostName: AnsiString; -var - s: AnsiString; -begin - Result := ''; - setlength(s, 255); - ssGetHostName(pAnsichar(s), Length(s) - 1); - Result := PAnsichar(s); -end; - -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - Result := ssSend(s, Buf^, len, flags); -end; - -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - Result := ssRecv(s, Buf^, len, flags); -end; - -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - Result := ssSendTo(s, Buf^, len, flags, @addrto, SizeOfVarSin(addrto)); -end; - -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -var - x: integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - x := SizeOf(from); - Result := ssRecvFrom(s, Buf^, len, flags, @from, x); -end; - -function Accept(s: TSocket; var addr: TVarSin): TSocket; -var - x: integer; -begin -{$IFDEF OS2} - S := TSocket (NativeSocket (cInt (S))); -{$ENDIF OS2} - x := SizeOf(addr); -{$IFDEF OS2} - Result := TSocket (EMXSocket (cInt (ssAccept (S, @Addr, X)))); -{$ELSE OS2} - Result := ssAccept(s, @addr, x); -{$ENDIF OS2} -end; - -{$IFDEF OS2} -function Shutdown (s: TSocket; how: Integer): Integer; -begin - S := TSocket (NativeSocket (cInt (S))); - Shutdown := ssShutdown (s, how); -end; - -function Socket (af, Struc, Protocol: Integer): TSocket; -begin - Socket := TSocket (EMXSocket (cInt (ssSocket (af, Struc, Protocol)))); -end; - -function SetSockOpt (s: TSocket; level, optname: Integer; optval: PAnsiChar; - optlen: Integer): Integer; -begin - S := TSocket (NativeSocket (cInt (S))); - SetSockOpt := ssSetSockOpt (S, Level, OptName, OptVal, OptLen); -end; - -function GetSockOpt (s: TSocket; level, optname: Integer; optval: PAnsiChar; - var optlen: Integer): Integer; -begin - S := TSocket (NativeSocket (cInt (S))); - GetSockOpt := ssGetSockOpt (S, Level, OptName, OptVal, OptLen); -end; - -function Listen (s: TSocket; backlog: Integer): Integer; -begin - S := TSocket (NativeSocket (cInt (S))); - Listen := ssListen (S, BackLog); -end; - -function IoctlSocket (s: TSocket; cmd: DWORD; var arg: Integer): Integer; -begin - S := TSocket (NativeSocket (cInt (S))); - IOCtlSocket := ssIOCtlSocket (S, Cmd, Arg); -end; - -function CloseSocket (s: TSocket): Integer; -begin - S := TSocket (NativeSocket (cInt (S))); - CloseSocket := ssCloseSocket (S); -end; - -function __WSAFDIsSet (s: TSocket; var FDSet: TFDSet): Bool; -begin - S := TSocket (NativeSocket (cInt (S))); - __WSAFDIsSet := ss__WSAFDIsSet (S, FDSet); -end; - -function WSAIoctl (s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; - cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD; - lpcbBytesReturned: PDWORD; lpOverlapped: Pointer; - lpCompletionRoutine: pointer): u_int; -begin - S := TSocket (NativeSocket (cInt (S))); - WSAIOCtl := ssWSAIOCtl (S, dwIoControlCode, lpvInBuffer, cbInBuffer, - lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpOverlapped, - lpCompletionRoutine); -end; -{$ENDIF OS2} - -{=============================================================================} -function IsNewApi(Family: integer): Boolean; -begin - Result := SockEnhancedApi; - if not Result then - Result := (Family = AF_INET6) and SockWship6Api; -end; - -function SetVarSin(var Sin: TVarSin; IP, Port: AnsiString; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -type - pu_long = ^u_long; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - HostEnt: PHostEnt; - r: integer; - Hints1, Hints2: TAddrInfo; - Sin1, Sin2: TVarSin; - TwoPass: boolean; - - function GetAddr(const IP, port: AnsiString; Hints: TAddrInfo; var Sin: TVarSin): integer; - var - Addr: PAddrInfo; - begin - Addr := nil; - try - FillChar(Sin, Sizeof(Sin), 0); - if Hints.ai_socktype = SOCK_RAW then - begin - Hints.ai_socktype := 0; - Hints.ai_protocol := 0; - Result := synsock.GetAddrInfo(PAnsiChar(IP), nil, @Hints, Addr); - end - else - begin - if (IP = cAnyHost) or (IP = c6AnyHost) then - begin - Hints.ai_flags := AI_PASSIVE; - Result := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); - end - else - if (IP = cLocalhost) or (IP = c6Localhost) then - begin - Result := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); - end - else - begin - Result := synsock.GetAddrInfo(PAnsiChar(IP), PAnsiChar(Port), @Hints, Addr); - end; - end; - if Result = 0 then - if (Addr <> nil) then - Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - -begin - Result := 0; - FillChar(Sin, Sizeof(Sin), 0); - if not IsNewApi(family) then - begin - SynSockCS.Enter; - try - Sin.sin_family := AF_INET; - ProtoEnt := synsock.GetProtoByNumber(SockProtocol); - ServEnt := nil; - if (ProtoEnt <> nil) and (StrToIntDef(string(Port),-1) =-1) then - ServEnt := synsock.GetServByName(PAnsiChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Sin.sin_port := synsock.htons(StrToIntDef(string(Port), 0)) - else - Sin.sin_port := ServEnt^.s_port; - if IP = cBroadcast then - Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) - else - begin - Sin.sin_addr.s_addr := synsock.inet_addr(PAnsiChar(IP)); - if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then - begin - HostEnt := synsock.GetHostByName(PAnsiChar(IP)); - Result := synsock.WSAGetLastError; - if HostEnt <> nil then - Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - begin - FillChar(Hints1, Sizeof(Hints1), 0); - FillChar(Hints2, Sizeof(Hints2), 0); - TwoPass := False; - if Family = AF_UNSPEC then - begin - if PreferIP4 then - begin - Hints1.ai_family := AF_INET; - Hints2.ai_family := AF_INET6; - TwoPass := True; - end - else - begin - Hints2.ai_family := AF_INET; - Hints1.ai_family := AF_INET6; - TwoPass := True; - end; - end - else - Hints1.ai_family := Family; - - Hints1.ai_socktype := SockType; - Hints1.ai_protocol := SockProtocol; - Hints2.ai_socktype := Hints1.ai_socktype; - Hints2.ai_protocol := Hints1.ai_protocol; - - r := GetAddr(IP, Port, Hints1, Sin1); - Result := r; - sin := sin1; - if r <> 0 then - if TwoPass then - begin - r := GetAddr(IP, Port, Hints2, Sin2); - Result := r; - if r = 0 then - sin := sin2; - end; - end; -end; - -function GetSinIP(Sin: TVarSin): AnsiString; -var - p: PAnsiChar; - host, serv: AnsiString; - hostlen, servlen: integer; - r: integer; -begin - Result := ''; - if not IsNewApi(Sin.AddressFamily) then - begin - p := synsock.inet_ntoa(Sin.sin_addr); - if p <> nil then - Result := p; - end - else - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(@sin, SizeOfVarSin(sin), PAnsiChar(host), hostlen, - PAnsiChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - Result := PAnsiChar(host); - end; -end; - -function GetSinPort(Sin: TVarSin): Integer; -begin - if (Sin.sin_family = AF_INET6) then - Result := synsock.ntohs(Sin.sin6_port) - else - Result := synsock.ntohs(Sin.sin_port); -end; - -procedure ResolveNameToIP(Name: AnsiString; Family, SockProtocol, SockType: integer; const IPList: TStrings); -type - TaPInAddr = array[0..250] of PInAddr; - PaPInAddr = ^TaPInAddr; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - AddrNext: PAddrInfo; - r: integer; - host, serv: AnsiString; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IP: u_long; - PAdrPtr: PaPInAddr; - i: Integer; - s: String; - InAddr: TInAddr; -begin - IPList.Clear; - if not IsNewApi(Family) then - begin - IP := synsock.inet_addr(PAnsiChar(Name)); - if IP = u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := synsock.GetHostByName(PAnsiChar(Name)); - if RemoteHost <> nil then - begin - PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); - i := 0; - while PAdrPtr^[i] <> nil do - begin - InAddr := PAdrPtr^[i]^; - s := Format('%d.%d.%d.%d', [InAddr.S_bytes[0], InAddr.S_bytes[1], - InAddr.S_bytes[2], InAddr.S_bytes[3]]); - IPList.Add(s); - Inc(i); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - IPList.Add(string(Name)); - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PAnsiChar(Name), nil, @Hints, Addr); - if r = 0 then - begin - AddrNext := Addr; - while not(AddrNext = nil) do - begin - if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) - or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, - PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, - NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - begin - host := PAnsiChar(host); - IPList.Add(string(host)); - end; - end; - AddrNext := AddrNext^.ai_next; - end; - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - if IPList.Count = 0 then - IPList.Add(cAnyHost); -end; - -function ResolvePort(Port: AnsiString; Family, SockProtocol, SockType: integer): Word; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; -begin - Result := 0; - if not IsNewApi(Family) then - begin - SynSockCS.Enter; - try - ProtoEnt := synsock.GetProtoByNumber(SockProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := synsock.GetServByName(PAnsiChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Result := StrToIntDef(string(Port), 0) - else - Result := synsock.htons(ServEnt^.s_port); - finally - SynSockCS.Leave; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := Sockprotocol; - Hints.ai_flags := AI_PASSIVE; - r := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); - if (r = 0) and Assigned(Addr) then - begin - if Addr^.ai_family = AF_INET then - Result := synsock.htons(Addr^.ai_addr^.sin_port); - if Addr^.ai_family = AF_INET6 then - Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; - -function ResolveIPToName(IP: AnsiString; Family, SockProtocol, SockType: integer): AnsiString; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; - host, serv: AnsiString; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IPn: u_long; -begin - Result := IP; - if not IsNewApi(Family) then - begin - IPn := synsock.inet_addr(PAnsiChar(IP)); - if IPn <> u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); - if RemoteHost <> nil then - Result := RemoteHost^.h_name; - finally - SynSockCS.Leave; - end; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PAnsiChar(IP), nil, @Hints, Addr); - if (r = 0) and Assigned(Addr)then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, - PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, - NI_NUMERICSERV); - if r = 0 then - Result := PAnsiChar(host); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; - -{=============================================================================} - -function InitSocketInterface(stack: String): Boolean; -begin - Result := False; - if stack = '' then - stack := DLLStackName; - SynSockCS.Enter; - try - if SynSockCount = 0 then - begin - SockEnhancedApi := False; - SockWship6Api := False; - LibHandle := LoadLibrary(PChar(Stack)); - if LibHandle <> 0 then - begin -{$IFDEF OS2} - ssWSAIoctl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAIoctl'))); - ss__WSAFDIsSet := GetProcAddress(LibHandle, PAnsiChar(AnsiString('__WSAFDIsSet'))); - ssCloseSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('closesocket'))); - ssIoctlSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ioctlsocket'))); -{$ELSE OS2} - WSAIoctl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAIoctl'))); - __WSAFDIsSet := GetProcAddress(LibHandle, PAnsiChar(AnsiString('__WSAFDIsSet'))); - CloseSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('closesocket'))); - IoctlSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ioctlsocket'))); -{$ENDIF OS2} - WSAGetLastError := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAGetLastError'))); - WSAStartup := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAStartup'))); - WSACleanup := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSACleanup'))); - ssAccept := GetProcAddress(LibHandle, PAnsiChar(AnsiString('accept'))); - ssBind := GetProcAddress(LibHandle, PAnsiChar(AnsiString('bind'))); - ssConnect := GetProcAddress(LibHandle, PAnsiChar(AnsiString('connect'))); - ssGetPeerName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getpeername'))); - ssGetSockName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockname'))); -{$IFDEF OS2} - ssGetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockopt'))); -{$ELSE OS2} - GetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockopt'))); -{$ENDIF OS2} - Htonl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('htonl'))); - Htons := GetProcAddress(LibHandle, PAnsiChar(AnsiString('htons'))); - Inet_Addr := GetProcAddress(LibHandle, PAnsiChar(AnsiString('inet_addr'))); - Inet_Ntoa := GetProcAddress(LibHandle, PAnsiChar(AnsiString('inet_ntoa'))); -{$IFDEF OS2} - ssListen := GetProcAddress(LibHandle, PAnsiChar(AnsiString('listen'))); -{$ELSE OS2} - Listen := GetProcAddress(LibHandle, PAnsiChar(AnsiString('listen'))); -{$ENDIF OS2} - Ntohl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ntohl'))); - Ntohs := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ntohs'))); - ssRecv := GetProcAddress(LibHandle, PAnsiChar(AnsiString('recv'))); - ssRecvFrom := GetProcAddress(LibHandle, PAnsiChar(AnsiString('recvfrom'))); - Select := GetProcAddress(LibHandle, PAnsiChar(AnsiString('select'))); - ssSend := GetProcAddress(LibHandle, PAnsiChar(AnsiString('send'))); - ssSendTo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('sendto'))); -{$IFDEF OS2} - ssSetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('setsockopt'))); - ssShutDown := GetProcAddress(LibHandle, PAnsiChar(AnsiString('shutdown'))); - ssSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('socket'))); -{$ELSE OS2} - SetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('setsockopt'))); - ShutDown := GetProcAddress(LibHandle, PAnsiChar(AnsiString('shutdown'))); - Socket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('socket'))); -{$ENDIF OS2} - GetHostByAddr := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostbyaddr'))); - GetHostByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostbyname'))); - GetProtoByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getprotobyname'))); - GetProtoByNumber := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getprotobynumber'))); - GetServByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getservbyname'))); - GetServByPort := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getservbyport'))); - ssGetHostName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostname'))); - -{$IFNDEF FORCEOLDAPI} - GetAddrInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getaddrinfo'))); - FreeAddrInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('freeaddrinfo'))); - GetNameInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getnameinfo'))); - SockEnhancedApi := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) - and Assigned(GetNameInfo); - if not SockEnhancedApi then - begin - LibWship6Handle := LoadLibrary(PChar(DLLWship6)); - if LibWship6Handle <> 0 then - begin - GetAddrInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('getaddrinfo'))); - FreeAddrInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('freeaddrinfo'))); - GetNameInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('getnameinfo'))); - SockWship6Api := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) - and Assigned(GetNameInfo); - end; - end; -{$ENDIF} - Result := True; - end; - end - else Result := True; - if Result then - Inc(SynSockCount); - finally - SynSockCS.Leave; - end; -end; - -function DestroySocketInterface: Boolean; -begin - SynSockCS.Enter; - try - Dec(SynSockCount); - if SynSockCount < 0 then - SynSockCount := 0; - if SynSockCount = 0 then - begin - if LibHandle <> 0 then - begin - FreeLibrary(libHandle); - LibHandle := 0; - end; - if LibWship6Handle <> 0 then - begin - FreeLibrary(LibWship6Handle); - LibWship6Handle := 0; - end; - end; - finally - SynSockCS.Leave; - end; - Result := True; -end; - -initialization -begin - SynSockCS := SyncObjs.TCriticalSection.Create; - SET_IN6_IF_ADDR_ANY (@in6addr_any); - SET_LOOPBACK_ADDR6 (@in6addr_loopback); -end; - -finalization -begin - SynSockCS.Free; -end; \ No newline at end of file diff --git a/3rd/synapse/source/ssposix.inc b/3rd/synapse/source/ssposix.inc deleted file mode 100644 index 977462d75..000000000 --- a/3rd/synapse/source/ssposix.inc +++ /dev/null @@ -1,1144 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.004 | -|==============================================================================| -| Content: Socket Independent Platform Layer - Delphi Posix definition include | -|==============================================================================| -| Copyright (c)2006-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2006-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Radek Cervinka | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$IFDEF POSIX} -{for delphi XE2+} - -//{$DEFINE FORCEOLDAPI} -{Note about define FORCEOLDAPI: -If you activate this compiler directive, then is allways used old socket API -for name resolution. If you leave this directive inactive, then the new API -is used, when running system allows it. - -For IPv6 support you must have new API! -} - -{ -note RC: -partially compatible with NextGen Delphi compiler - iOS - - -} - - -interface - -uses - SyncObjs, SysUtils, Classes, - Posix.SysSocket, Posix.SysSelect, Posix.SysTime, Posix.NetinetIn, - Posix.StrOpts, Posix.Errno; - -function InitSocketInterface(stack: string): Boolean; -function DestroySocketInterface: Boolean; - -const - DLLStackName = ''; - WinsockLevel = $0202; - - cLocalHost = '127.0.0.1'; - cBroadcast = '255.255.255.255'; - cAnyHost = '0.0.0.0'; - c6AnyHost = '::0'; - c6Localhost = '::1'; - cLocalHostStr = 'localhost'; - -type - TSocket = longint; - TAddrFamily = integer; - - TMemory = pointer; - - -type - TFDSet = fd_set; - PFDSet = Pfd_set; - Ptimeval = Posix.SysTime.ptimeval; - Ttimeval = Posix.SysTime.timeval; - -const - // - FIONREAD = $4004667F; // oSX FIONREAD = Posix.StrOpts.FIONREAD; - - FIONBIO = $8004667E; //OSX FIONBIO = Posix.StrOpts.FIONBIO; - FIOASYNC = $8004667D; //OSX FIOASYNC = Posix.StrOpts.FIOASYNC; // not defined in XE2 - - { FIONREAD = $541B; // LINUX? - FIONBIO = $5421; - FIOASYNC = $5452; } - -const - IPPROTO_IP = Posix.NetinetIn.IPPROTO_IP; { Dummy } - IPPROTO_ICMP = Posix.NetinetIn.IPPROTO_ICMP; { Internet Control Message Protocol } - IPPROTO_IGMP = Posix.NetinetIn.IPPROTO_IGMP; { Internet Group Management Protocol} - IPPROTO_TCP = Posix.NetinetIn.IPPROTO_TCP; { TCP } - IPPROTO_UDP = Posix.NetinetIn.IPPROTO_UDP; { User Datagram Protocol } - IPPROTO_IPV6 = Posix.NetinetIn.IPPROTO_IPV6; - IPPROTO_ICMPV6 = 58; - IPPROTO_RM = 113; - - IPPROTO_RAW = Posix.NetinetIn.IPPROTO_RAW; - IPPROTO_MAX = Posix.NetinetIn.IPPROTO_MAX; - -type - PInAddr = ^TInAddr; - TInAddr = Posix.NetinetIn.in_addr; - - PSockAddrIn = ^TSockAddrIn; - TSockAddrIn = Posix.NetinetIn.sockaddr_in; - - - TIP_mreq = record - imr_multiaddr: TInAddr; // IP multicast address of group - imr_interface: TInAddr; // local IP address of interface - end; - - - PInAddr6 = ^TInAddr6; - TInAddr6 = Posix.NetinetIn.in6_addr; - - PSockAddrIn6 = ^TSockAddrIn6; - TSockAddrIn6 = Posix.NetinetIn.sockaddr_in6; - - - TIPv6_mreq = record - ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: integer; // Interface index. - end; - -const - INADDR_ANY = $00000000; - INADDR_LOOPBACK = $7F000001; - INADDR_BROADCAST = $FFFFFFFF; - INADDR_NONE = $FFFFFFFF; - ADDR_ANY = INADDR_ANY; - INVALID_SOCKET = TSocket(NOT(0)); - SOCKET_ERROR = -1; - -Const - IP_TOS = Posix.NetinetIn.IP_TOS; { int; IP type of service and precedence. } - IP_TTL = Posix.NetinetIn.IP_TTL; { int; IP time to live. } - IP_HDRINCL = Posix.NetinetIn.IP_HDRINCL; { int; Header is included with data. } - IP_OPTIONS = Posix.NetinetIn.IP_OPTIONS; { ip_opts; IP per-packet options. } -// IP_ROUTER_ALERT = sockets.IP_ROUTER_ALERT; { bool } - IP_RECVOPTS = Posix.NetinetIn.IP_RECVOPTS; { bool } - IP_RETOPTS = Posix.NetinetIn.IP_RETOPTS; { bool } -// IP_PKTINFO = sockets.IP_PKTINFO; { bool } -// IP_PKTOPTIONS = sockets.IP_PKTOPTIONS; -// IP_PMTUDISC = sockets.IP_PMTUDISC; { obsolete name? } -// IP_MTU_DISCOVER = sockets.IP_MTU_DISCOVER; { int; see below } -// IP_RECVERR = sockets.IP_RECVERR; { bool } -// IP_RECVTTL = sockets.IP_RECVTTL; { bool } -// IP_RECVTOS = sockets.IP_RECVTOS; { bool } - IP_MULTICAST_IF = Posix.NetinetIn.IP_MULTICAST_IF; { in_addr; set/get IP multicast i/f } - IP_MULTICAST_TTL = Posix.NetinetIn.IP_MULTICAST_TTL; { u_char; set/get IP multicast ttl } - IP_MULTICAST_LOOP = Posix.NetinetIn.IP_MULTICAST_LOOP; { i_char; set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = Posix.NetinetIn.IP_ADD_MEMBERSHIP; { ip_mreq; add an IP group membership } - IP_DROP_MEMBERSHIP = Posix.NetinetIn.IP_DROP_MEMBERSHIP; { ip_mreq; drop an IP group membership } - - SOL_SOCKET = Posix.SysSocket.SOL_SOCKET; - - SO_DEBUG = Posix.SysSocket.SO_DEBUG; - SO_REUSEADDR = Posix.SysSocket.SO_REUSEADDR; - SO_TYPE = Posix.SysSocket.SO_TYPE; - SO_ERROR = Posix.SysSocket.SO_ERROR; - SO_DONTROUTE = Posix.SysSocket.SO_DONTROUTE; - SO_BROADCAST = Posix.SysSocket.SO_BROADCAST; - SO_SNDBUF = Posix.SysSocket.SO_SNDBUF; - SO_RCVBUF = Posix.SysSocket.SO_RCVBUF; - SO_KEEPALIVE = Posix.SysSocket.SO_KEEPALIVE; - SO_OOBINLINE = Posix.SysSocket.SO_OOBINLINE; -// SO_NO_CHECK = SysSocket.SO_NO_CHECK; -// SO_PRIORITY = SysSocket.SO_PRIORITY; - SO_LINGER = Posix.SysSocket.SO_LINGER; -// SO_BSDCOMPAT = SysSocket.SO_BSDCOMPAT; -// SO_REUSEPORT = SysSocket.SO_REUSEPORT; -// SO_PASSCRED = SysSocket.SO_PASSCRED; -// SO_PEERCRED = SysSocket.SO_PEERCRED; - SO_RCVLOWAT = Posix.SysSocket.SO_RCVLOWAT; - SO_SNDLOWAT = Posix.SysSocket.SO_SNDLOWAT; - SO_RCVTIMEO = Posix.SysSocket.SO_RCVTIMEO; - SO_SNDTIMEO = Posix.SysSocket.SO_SNDTIMEO; -{ Security levels - as per NRL IPv6 - don't actually do anything } -// SO_SECURITY_AUTHENTICATION = SysSocket.SO_SECURITY_AUTHENTICATION; -// SO_SECURITY_ENCRYPTION_TRANSPORT = SysSocket.SO_SECURITY_ENCRYPTION_TRANSPORT; -// SO_SECURITY_ENCRYPTION_NETWORK = SysSocket.SO_SECURITY_ENCRYPTION_NETWORK; -// SO_BINDTODEVICE = SysSocket.SO_BINDTODEVICE; -{ Socket filtering } -// SO_ATTACH_FILTER = SysSocket.SO_ATTACH_FILTER; -// SO_DETACH_FILTER = SysSocket.SO_DETACH_FILTER; - - SOMAXCONN = 1024; - - IPV6_UNICAST_HOPS = Posix.NetinetIn.IPV6_UNICAST_HOPS; - IPV6_MULTICAST_IF = Posix.NetinetIn.IPV6_MULTICAST_IF; - IPV6_MULTICAST_HOPS = Posix.NetinetIn.IPV6_MULTICAST_HOPS; - IPV6_MULTICAST_LOOP = Posix.NetinetIn.IPV6_MULTICAST_LOOP; - IPV6_JOIN_GROUP = Posix.NetinetIn.IPV6_JOIN_GROUP; - IPV6_LEAVE_GROUP = Posix.NetinetIn.IPV6_LEAVE_GROUP; - -const - SOCK_STREAM = Posix.SysSocket.SOCK_STREAM;// 1; { stream socket } - SOCK_DGRAM = Posix.SysSocket.SOCK_DGRAM;// 2; { datagram socket } - SOCK_RAW = Posix.SysSocket.SOCK_RAW;// 3; { raw-protocol interface } - SOCK_RDM = Posix.SysSocket.SOCK_RDM;// 4; { reliably-delivered message } - SOCK_SEQPACKET = Posix.SysSocket.SOCK_SEQPACKET;// 5; { sequenced packet stream } - -{ TCP options. } - TCP_NODELAY = $0001; //netinettcp.pas - -{ Address families. } - - AF_UNSPEC = Posix.SysSocket.AF_UNSPEC;// 0; { unspecified } - AF_INET = Posix.SysSocket.AF_INET; // 2; { internetwork: UDP, TCP, etc. } - AF_INET6 = Posix.SysSocket.AF_INET6; // !! 30 { Internetwork Version 6 } - AF_MAX = Posix.SysSocket.AF_MAX; // !! - variable by OS - -{ Protocol families, same as address families for now. } - PF_UNSPEC = AF_UNSPEC; - PF_INET = AF_INET; - PF_INET6 = AF_INET6; - PF_MAX = AF_MAX; - -type -{ Structure used for manipulating linger option. } - PLinger = ^TLinger; - TLinger = Posix.SysSocket.linger; - -const - - MSG_OOB = Posix.SysSocket.MSG_OOB; // Process out-of-band data. - MSG_PEEK = Posix.SysSocket.MSG_PEEK; // Peek at incoming messages. - {$IFDEF MACOS} - MSG_NOSIGNAL = $20000; // Do not generate SIGPIPE. - // Works under MAC OS X, but is undocumented, - // So FPC doesn't include it - {$ELSE} - MSG_NOSIGNAL = $4000; // Do not generate SIGPIPE. - {$ENDIF} - -const - WSAEINTR = EINTR; - WSAEBADF = EBADF; - WSAEACCES = EACCES; - WSAEFAULT = EFAULT; - WSAEINVAL = EINVAL; - WSAEMFILE = EMFILE; - WSAEWOULDBLOCK = EWOULDBLOCK; - WSAEINPROGRESS = EINPROGRESS; - WSAEALREADY = EALREADY; - WSAENOTSOCK = ENOTSOCK; - WSAEDESTADDRREQ = EDESTADDRREQ; - WSAEMSGSIZE = EMSGSIZE; - WSAEPROTOTYPE = EPROTOTYPE; - WSAENOPROTOOPT = ENOPROTOOPT; - WSAEPROTONOSUPPORT = EPROTONOSUPPORT; - WSAESOCKTNOSUPPORT = ESOCKTNOSUPPORT; - WSAEOPNOTSUPP = EOPNOTSUPP; - WSAEPFNOSUPPORT = EPFNOSUPPORT; - WSAEAFNOSUPPORT = EAFNOSUPPORT; - WSAEADDRINUSE = EADDRINUSE; - WSAEADDRNOTAVAIL = EADDRNOTAVAIL; - WSAENETDOWN = ENETDOWN; - WSAENETUNREACH = ENETUNREACH; - WSAENETRESET = ENETRESET; - WSAECONNABORTED = ECONNABORTED; - WSAECONNRESET = ECONNRESET; - WSAENOBUFS = ENOBUFS; - WSAEISCONN = EISCONN; - WSAENOTCONN = ENOTCONN; - WSAESHUTDOWN = ESHUTDOWN; - WSAETOOMANYREFS = ETOOMANYREFS; - WSAETIMEDOUT = ETIMEDOUT; - WSAECONNREFUSED = ECONNREFUSED; - WSAELOOP = ELOOP; - WSAENAMETOOLONG = ENAMETOOLONG; - WSAEHOSTDOWN = EHOSTDOWN; - WSAEHOSTUNREACH = EHOSTUNREACH; - WSAENOTEMPTY = ENOTEMPTY; - WSAEPROCLIM = -1; - WSAEUSERS = EUSERS; - WSAEDQUOT = EDQUOT; - WSAESTALE = ESTALE; - WSAEREMOTE = EREMOTE; - WSASYSNOTREADY = -2; - WSAVERNOTSUPPORTED = -3; - WSANOTINITIALISED = -4; - WSAEDISCON = -5; - WSAHOST_NOT_FOUND = 1; - WSATRY_AGAIN = 2; - WSANO_RECOVERY = 3; - WSANO_DATA = -6; - -const - WSADESCRIPTION_LEN = 256; - WSASYS_STATUS_LEN = 128; -type - PWSAData = ^TWSAData; - TWSAData = packed record - wVersion: Word; - wHighVersion: Word; - szDescription: array[0..WSADESCRIPTION_LEN] of Char; - szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; - iMaxSockets: Word; - iMaxUdpDg: Word; - lpVendorInfo: PChar; - end; - - function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; - function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; - procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); - procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); - -var - in6addr_any, in6addr_loopback : TInAddr6; - -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -procedure FD_ZERO(var FDSet: TFDSet); - -{=============================================================================} - -var - SynSockCS: SyncObjs.TCriticalSection; - SockEnhancedApi: Boolean; - SockWship6Api: Boolean; - - {$DEFINE SOCK_HAS_SINLEN} // OSX - -type - TVarSin = packed record - {$ifdef SOCK_HAS_SINLEN} - sin_len : UInt8; - {$endif} - - case integer of - 0: (AddressFamily: sa_family_t); - 1: ( - case sin_family: sa_family_t of - AF_INET: (sin_port: word; - sin_addr: TInAddr; - sin_zero: array[0..7] of Char); - AF_INET6: (sin6_port: word; - sin6_flowinfo: longword; - sin6_addr: TInAddr6; - sin6_scope_id: longword); - ); - end; - -function SizeOfVarSin(sin: TVarSin): integer; - - function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; - function WSACleanup: Integer; - function WSAGetLastError: Integer; - function GetHostName: string; - function Shutdown(s: TSocket; how: Integer): Integer; - function SetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; - optlen: Integer): Integer; - function GetSockOpt(s: TSocket; level, optname: Integer; optval: TMemory; - var optlen: Integer): Integer; - function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; - function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; - function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; - function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; - function ntohs(netshort: word): word; - function ntohl(netlong: longword): longword; - function Listen(s: TSocket; backlog: Integer): Integer; - function IoctlSocket(s: TSocket; cmd: Integer; var arg: integer): Integer; - function htons(hostshort: word): word; - function htonl(hostlong: longword): longword; - function GetSockName(s: TSocket; var name: TVarSin): Integer; - function GetPeerName(s: TSocket; var name: TVarSin): Integer; - function Connect(s: TSocket; const name: TVarSin): Integer; - function CloseSocket(s: TSocket): Integer; - function Bind(s: TSocket; const addr: TVarSin): Integer; - function Accept(s: TSocket; var addr: TVarSin): TSocket; - function Socket(af, Struc, Protocol: Integer): TSocket; - function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; - -function IsNewApi(Family: integer): Boolean; -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -function GetSinIP(Sin: TVarSin): string; -function GetSinPort(Sin: TVarSin): Integer; -procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); -function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; -function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; - - -{==============================================================================} -implementation -uses - Posix.Base, Posix.Unistd, Posix.ArpaInet, Posix.NetDB; - -function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; -begin - Result := Posix.NetinetIn.IN6_IS_ADDR_UNSPECIFIED(a^); -{ Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0));} -end; - -function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; -begin - Result := Posix.NetinetIn.IN6_IS_ADDR_LOOPBACK(a^); -{ Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and - (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and - (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1));} -end; - -function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; -begin - Result := Posix.NetinetIn.IN6_IS_ADDR_LINKLOCAL(a^); -{ Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80));} -end; - -function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; -begin - Result := Posix.NetinetIn.IN6_IS_ADDR_SITELOCAL(a^); -// Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); -end; - -function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; -begin - Result := Posix.NetinetIn.IN6_IS_ADDR_MULTICAST(a^); -// Result := (a^.u6_addr8[0] = $FF); -end; - -function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; -begin - Result := (CompareMem( a, b, sizeof(TInAddr6))); -end; - -procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); -end; - -procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); - a^.__s6_addr8[15] := 1; -end; - -{$IFDEF NEXTGEN} -function GetHostByName(const name: string):Phostent; -var - h: Phostent; -begin - h := Posix.NetDB.gethostbyname(MarshaledAString(TMarshal.AsAnsi(name))); -end; -{$ENDIF} -{=============================================================================} - -function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer; -begin - with WSData do - begin - wVersion := wVersionRequired; - wHighVersion := $202; - szDescription := 'Synsock - Synapse Platform Independent Socket Layer'; - szSystemStatus := 'Running on Posix by Delphi'; - iMaxSockets := 32768; - iMaxUdpDg := 8192; - end; - Result := 0; -end; - -function WSACleanup: Integer; -begin - Result := 0; -end; - -function WSAGetLastError: Integer; -begin - Result := Posix.Errno.errno; -end; - -function FD_ISSET(Socket: TSocket; var fdset: TFDSet): Boolean; -begin - Result := __FD_ISSET(socket, fdset); -end; - -procedure FD_SET(Socket: TSocket; var fdset: TFDSet); -begin - __FD_SET(Socket, fdset); -end; - -procedure FD_CLR(Socket: TSocket; var fdset: TFDSet); -begin - __FD_CLR(Socket, fdset); -end; - -procedure FD_ZERO(var fdset: TFDSet); -begin - __FD_ZERO(fdset); -end; - -{=============================================================================} - -function SizeOfVarSin(sin: TVarSin): integer; -begin - case sin.sin_family of - AF_INET: - Result := SizeOf(TSockAddrIn); - AF_INET6: - Result := SizeOf(TSockAddrIn6); - else - Result := 0; - end; -end; - -{=============================================================================} - -function Bind(s: TSocket; const addr: TVarSin): Integer; -var - sa: sockaddr absolute addr; -begin - Result := Posix.SysSocket.Bind(s, sa, SizeOfVarSin(addr)); -end; - -function Connect(s: TSocket; const name: TVarSin): Integer; -var - sa: sockaddr absolute name; -begin - Result := Posix.SysSocket.Connect(s, sa, SizeOfVarSin(name)); -end; - -function GetSockName(s: TSocket; var name: TVarSin): Integer; -var - len: socklen_t; - address : sockaddr absolute name; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := Posix.SysSocket.GetSockName(s, address, Len); -end; - -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -var - len: socklen_t; - address : sockaddr absolute name; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := Posix.SysSocket.GetPeerName(s, address, Len); -end; - -function GetHostName: string; -{$IFDEF NEXTGEN} -var - name: TArray<Byte>; -const - cMaxHostLength = 255; -begin - SetLength(name, cMaxHostLength); - if Posix.Unistd.GetHostName(MarshaledAString(name), cMaxHostLength) = 0 then - Result := TEncoding.UTF8.GetString(name).ToUpper; -{$ELSE} -var - s: AnsiString; -begin - Result := ''; - setlength(s, 255); - Posix.Unistd.GetHostName(PAnsiChar(s), Length(s) - 1); - Result := PChar(string(s)); -{$ENDIF} -end; - -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := Posix.SysSocket.Send(s, Buf^, len, flags); -end; - -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := Posix.SysSocket.Recv(s, Buf^, len, flags); -end; - -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -var - sa: sockaddr absolute addrto; -begin - Result := Posix.SysSocket.SendTo(s, Buf^, len, flags, sa, SizeOfVarSin(addrto)); -end; - -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -var - x: socklen_t; - address : sockaddr absolute from; -begin - x := SizeOf(from); - Result := Posix.SysSocket.RecvFrom(s, Buf^, len, flags, address, x); -end; - -function Accept(s: TSocket; var addr: TVarSin): TSocket; -var - x: socklen_t; - address : sockaddr absolute addr; -begin - x := SizeOf(addr); - Result := Posix.SysSocket.Accept(s, address, x); -end; - -function Shutdown(s: TSocket; how: Integer): Integer; -begin - Result := Posix.SysSocket.Shutdown(s, how); -end; - -function SetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; - optlen: Integer): Integer; -begin - Result := Posix.SysSocket.setsockopt(s, level, optname, pointer(optval), optlen); -end; - -function GetSockOpt(s: TSocket; level, optname: Integer; optval: Tmemory; - var optlen: Integer): Integer; -var - x: socklen_t; -begin - x := optlen; - Result := Posix.SysSocket.getsockopt(s, level, optname, pointer(optval), x); - optlen := x; -end; - -function ntohs(netshort: word): word; -begin - Result := Posix.ArpaInet.ntohs(NetShort); -end; - -function ntohl(netlong: longword): longword; -begin - Result := Posix.ArpaInet.ntohl(NetLong); -end; - -function Listen(s: TSocket; backlog: Integer): Integer; -begin - if Posix.SysSocket.Listen(s, backlog) = 0 then - Result := 0 - else - Result := SOCKET_ERROR; -end; - -function IoctlSocket(s: TSocket; cmd: Integer; var arg: integer): Integer; -begin - Result := Posix.StrOpts.Ioctl(s, cmd, @arg); -end; - -function htons(hostshort: word): word; -begin - Result := Posix.ArpaInet.htons(Hostshort); -end; - -function htonl(hostlong: longword): longword; -begin - Result := Posix.ArpaInet.htonl(HostLong); -end; - -function CloseSocket(s: TSocket): Integer; -begin - Result := Posix.Unistd.__close(s); -end; - -function Socket(af, Struc, Protocol: Integer): TSocket; -begin - Result := Posix.SysSocket.Socket(af, struc, protocol); -end; - -function Select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; -begin - Result := Posix.SysSelect.Select(nfds, readfds, writefds, exceptfds, timeout); -end; - -{=============================================================================} -function IsNewApi(Family: integer): Boolean; -begin - Result := SockEnhancedApi; - if not Result then - Result := (Family = AF_INET6) and SockWship6Api; -end; - -{$IFDEF NEXTGEN} -function GetAddrInfo(hostname, servname: string; - const hints: addrinfo; out res: Paddrinfo): Integer; -begin - -end; -{$ENDIF} - -function gethostbyname(const name: PAnsiChar): PHostEnt; cdecl; - external libc name _PU + 'gethostbyname'; -function gethostbyaddr(var addr; len: socklen_t; atype: integer): PHostEnt; cdecl; - external libc name _PU + 'gethostbyaddr'; - -function SetVarSin(var Sin: TVarSin; IP, Port: string; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - HostEnt: PHostEnt; - r: integer; - Hints1, Hints2: AddrInfo; - Sin1, Sin2: TVarSin; - TwoPass: boolean; - - function GetAddr(const IP, port: string; Hints: AddrInfo; var Sin: TVarSin): integer; - var - Addr: PAddrInfo; - begin - Addr := nil; - try - FillChar(Sin, Sizeof(Sin), 0); - if Hints.ai_socktype = SOCK_RAW then - begin - Hints.ai_socktype := 0; - Hints.ai_protocol := 0; - Result := GetAddrInfo(PAnsiChar(AnsiString(IP)), nil, Hints, Addr); - end - else - begin - if (IP = cAnyHost) or (IP = c6AnyHost) then - begin - Hints.ai_flags := AI_PASSIVE; - Result := GetAddrInfo(nil, PAnsiChar(AnsiString(Port)), Hints, Addr); - end - else - if (IP = cLocalhost) or (IP = c6Localhost) then - begin - Result := GetAddrInfo(nil, PAnsiChar(AnsiString(Port)), Hints, Addr); - end - else - begin - Result := GetAddrInfo(PAnsiChar(AnsiString(IP)), PAnsiChar(AnsiString(Port)), Hints, Addr); - end; - end; - if Result = 0 then - if (Addr <> nil) then - Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); - finally - if Assigned(Addr) then - FreeAddrInfo(Addr^); - end; - end; - -begin - Result := 0; - FillChar(Sin, Sizeof(Sin), 0); - if not IsNewApi(family) then - begin - SynSockCS.Enter; - try - Sin.sin_family := AF_INET; - ProtoEnt := GetProtoByNumber(SockProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - {$IFDEF NEXTGEN} - ServEnt := GetServByName(MarshaledAString(TMarshal.AsAnsi(Port)), ProtoEnt^.p_name); - {$ELSE} - ServEnt := GetServByName(PAnsiChar(AnsiString(Port)), ProtoEnt^.p_name); - {$ENDIF} - if ServEnt = nil then - Sin.sin_port := htons(StrToIntDef(Port, 0)) - else - Sin.sin_port := ServEnt^.s_port; - if IP = cBroadcast then - Sin.sin_addr.s_addr := UInt32(INADDR_BROADCAST) - else - begin - {$IFDEF NEXTGEN} - Sin.sin_addr.s_addr := inet_addr(MarshaledAString(TMarshal.AsAnsi(IP))); - {$ELSE} - Sin.sin_addr.s_addr := inet_addr(PAnsiChar(AnsiString(IP))); - {$ENDIF} - if Sin.sin_addr.s_addr = UInt32(INADDR_NONE) then - begin - {$IFDEF NEXTGEN} - HostEnt := GetHostByName(MarshaledAString(TMarshal.AsAnsi(IP))); - {$ELSE} - HostEnt := GetHostByName(PAnsiChar(AnsiString(IP))); - {$ENDIF} - Result := WSAGetLastError; - if HostEnt <> nil then - Sin.sin_addr.S_addr := UInt32(HostEnt.h_addr_list); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - begin - FillChar(Hints1, Sizeof(Hints1), 0); - FillChar(Hints2, Sizeof(Hints2), 0); - TwoPass := False; - if Family = AF_UNSPEC then - begin - if PreferIP4 then - begin - Hints1.ai_family := AF_INET; - Hints2.ai_family := AF_INET6; - TwoPass := True; - end - else - begin - Hints2.ai_family := AF_INET; - Hints1.ai_family := AF_INET6; - TwoPass := True; - end; - end - else - Hints1.ai_family := Family; - - Hints1.ai_socktype := SockType; - Hints1.ai_protocol := SockProtocol; - Hints2.ai_socktype := Hints1.ai_socktype; - Hints2.ai_protocol := Hints1.ai_protocol; - - r := GetAddr(IP, Port, Hints1, Sin1); - Result := r; - sin := sin1; - if r <> 0 then - if TwoPass then - begin - r := GetAddr(IP, Port, Hints2, Sin2); - Result := r; - if r = 0 then - sin := sin2; - end; - end; -end; - -function GetSinIP(Sin: TVarSin): string; -var - p: PAnsiChar; - hostlen, servlen: integer; - r: integer; - sa:sockaddr absolute Sin; - byHost, byServ: TBytes; - HostWrapper, ServWrapper: TPtrWrapper; -begin - Result := ''; - if not IsNewApi(Sin.AddressFamily) then - begin - p := inet_ntoa(Sin.sin_addr); - if p <> nil then - Result := string(p); - end - else - begin - // NEXTGEN compatible - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - Setlength(byHost, hostLen); - Setlength(byServ, hostLen); - HostWrapper := TPtrWrapper.Create(@byHost[0]); - ServWrapper := TPtrWrapper.Create(@byServ[0]); - r := getnameinfo(sa, SizeOfVarSin(sin), HostWrapper.ToPointer, hostlen, - ServWrapper.ToPointer, servlen, NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - Result := TMarshal.ReadStringAsAnsi(HostWrapper{, NI_MAXHOST}); - end; -end; - -function GetSinPort(Sin: TVarSin): Integer; -begin - if (Sin.sin_family = AF_INET6) then - Result := synsock.ntohs(Sin.sin6_port) - else - Result := synsock.ntohs(Sin.sin_port); -end; - -procedure ResolveNameToIP(Name: string; Family, SockProtocol, SockType: integer; const IPList: TStrings); -type - TaPInAddr = array[0..250] of PInAddr; - PaPInAddr = ^TaPInAddr; -var - Hints: AddrInfo; - Addr: PAddrInfo; - AddrNext: PAddrInfo; - r: integer; - host, serv: string; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IP: UINT32; - PAdrPtr: PaPInAddr; - i: Integer; - s: string; - InAddr: TInAddr; - aby:TArray<Byte>; -begin - IPList.Clear; - if not IsNewApi(Family) then - begin - {$IFDEF NEXTGEN} - IP := inet_addr(MarshaledAString(TMarshal.AsAnsi(Name))); - {$ELSE} - IP := inet_addr(PAnsiChar(AnsiString(Name))); - {$ENDIF} - if IP = UINT32(INADDR_NONE) then - begin - SynSockCS.Enter; - try - {$IFDEF NEXTGEN} - RemoteHost := GetHostByName(MarshaledAString(TMarshal.AsAnsi(Name))); - {$ELSE} - RemoteHost := GetHostByName(PAnsiChar(AnsiString(Name))); - {$ENDIF} - if RemoteHost <> nil then - begin - PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); - i := 0; - while PAdrPtr^[i] <> nil do - begin - InAddr := PAdrPtr^[i]^; - aby := TArray<byte>(InAddr); - s := Format('%d.%d.%d.%d', [aby[0], aby[1], - aby[2], aby[3]]); - IPList.Add(s); - Inc(i); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - IPList.Add(Name); - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := GetAddrInfo(PAnsiChar(AnsiString(Name)), nil, Hints, Addr); - if r = 0 then - begin - AddrNext := Addr; - while not(AddrNext = nil) do - begin - if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) - or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); -{$IFDEF NEXTGEN} - r := getnameinfo(AddrNext^.ai_addr^, AddrNext^.ai_addrlen, - MarshaledAString(TMarshal.AsAnsi(host)), hostlen, MarshaledAString(TMarshal.AsAnsi(serv)), servlen, - NI_NUMERICHOST + NI_NUMERICSERV); -{$ELSE} - r := getnameinfo(AddrNext^.ai_addr^, AddrNext^.ai_addrlen, - PAnsiChar(AnsiString(host)), hostlen, PAnsiChar(AnsiString(serv)), servlen, - NI_NUMERICHOST + NI_NUMERICSERV); -{$ENDIF} - if r = 0 then - begin - host := PChar(host); - IPList.Add(host); - end; - end; - AddrNext := AddrNext^.ai_next; - end; - end; - finally - if Assigned(Addr) then - FreeAddrInfo(Addr^); - end; - end; - if IPList.Count = 0 then - IPList.Add(cAnyHost); -end; - -function ResolvePort(Port: string; Family, SockProtocol, SockType: integer): Word; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - Hints: AddrInfo; - Addr: PAddrInfo; - _Addr: AddrInfo; - r: integer; -begin - Result := 0; - if not IsNewApi(Family) then - begin - SynSockCS.Enter; - try - ProtoEnt := GetProtoByNumber(SockProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := GetServByName(PAnsiChar(AnsiString(Port)), ProtoEnt^.p_name); - if ServEnt = nil then - Result := StrToIntDef(Port, 0) - else - Result := htons(ServEnt^.s_port); - finally - SynSockCS.Leave; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := Sockprotocol; - Hints.ai_flags := AI_PASSIVE; - r := GetAddrInfo(nil, PAnsiChar(AnsiString(Port)), Hints, Addr); - if (r = 0) and Assigned(Addr) then - begin - if Addr^.ai_family = AF_INET then - Result := htons(Addr^.ai_addr^.sa_data[0]); // port - if Addr^.ai_family = AF_INET6 then - Result := htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); - end; - finally - if Assigned(Addr) then - begin - _Addr := Addr^; - FreeAddrInfo(_Addr); - end; - end; - end; -end; - -function ResolveIPToName(IP: string; Family, SockProtocol, SockType: integer): string; -var - Hints: AddrInfo; - Addr: PAddrInfo; - _Addr: AddrInfo; - r: integer; - host, serv: string; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IPn: UINT32; -begin - Result := IP; - if not IsNewApi(Family) then - begin - IPn := inet_addr(PAnsiChar(AnsiString(IP))); - if IPn <> UINT32(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := GetHostByAddr(IPn, SizeOf(IPn), AF_INET); - if RemoteHost <> nil then - Result := string(RemoteHost^.hname); - finally - SynSockCS.Leave; - end; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := GetAddrInfo(PAnsiChar(AnsiString(IP)), nil, Hints, Addr); - if (r = 0) and Assigned(Addr)then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(Addr^.ai_addr^, Addr^.ai_addrlen, - PAnsiChar(AnsiString(host)), hostlen, PAnsiChar(AnsiString(serv)), servlen, - NI_NUMERICSERV); - if r = 0 then - Result := PChar(host); - end; - finally - if Assigned(Addr) then - begin - _Addr := Addr^; - FreeAddrInfo(_Addr); - end; - end; - end; -end; - -{=============================================================================} - -function InitSocketInterface(stack: string): Boolean; -begin - SockEnhancedApi := True; - SockWship6Api := False; -// Libc.Signal(Libc.SIGPIPE, TSignalHandler(Libc.SIG_IGN)); - Result := True; -end; - -function DestroySocketInterface: Boolean; -begin - Result := True; -end; - -initialization -begin - SynSockCS := SyncObjs.TCriticalSection.Create; - SET_IN6_IF_ADDR_ANY (@in6addr_any); - SET_LOOPBACK_ADDR6 (@in6addr_loopback); -end; - -finalization -begin - SynSockCS.Free; -end; - -{$ENDIF} diff --git a/3rd/synapse/source/sswin32.inc b/3rd/synapse/source/sswin32.inc deleted file mode 100644 index b234db847..000000000 --- a/3rd/synapse/source/sswin32.inc +++ /dev/null @@ -1,1622 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.003.001 | -|==============================================================================| -| Content: Socket Independent Platform Layer - Win32/64 definition include | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -//{$DEFINE WINSOCK1} -{Note about define WINSOCK1: -If you activate this compiler directive, then socket interface level 1.1 is -used instead default level 2.2. Level 2.2 is not available on old W95, however -you can install update. -} - -//{$DEFINE FORCEOLDAPI} -{Note about define FORCEOLDAPI: -If you activate this compiler directive, then is allways used old socket API -for name resolution. If you leave this directive inactive, then the new API -is used, when running system allows it. - -For IPv6 support you must have new API! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -{$IFDEF VER125} - {$DEFINE BCB} -{$ENDIF} -{$IFDEF BCB} - {$ObjExportAll On} - (*$HPPEMIT '/* EDE 2003-02-19 */' *) - (*$HPPEMIT 'namespace Synsock { using System::Shortint; }' *) - (*$HPPEMIT '#undef h_addr' *) - (*$HPPEMIT '#undef IOCPARM_MASK' *) - (*$HPPEMIT '#undef FD_SETSIZE' *) - (*$HPPEMIT '#undef IOC_VOID' *) - (*$HPPEMIT '#undef IOC_OUT' *) - (*$HPPEMIT '#undef IOC_IN' *) - (*$HPPEMIT '#undef IOC_INOUT' *) - (*$HPPEMIT '#undef FIONREAD' *) - (*$HPPEMIT '#undef FIONBIO' *) - (*$HPPEMIT '#undef FIOASYNC' *) - (*$HPPEMIT '#undef IPPROTO_IP' *) - (*$HPPEMIT '#undef IPPROTO_ICMP' *) - (*$HPPEMIT '#undef IPPROTO_IGMP' *) - (*$HPPEMIT '#undef IPPROTO_TCP' *) - (*$HPPEMIT '#undef IPPROTO_UDP' *) - (*$HPPEMIT '#undef IPPROTO_RAW' *) - (*$HPPEMIT '#undef IPPROTO_MAX' *) - (*$HPPEMIT '#undef INADDR_ANY' *) - (*$HPPEMIT '#undef INADDR_LOOPBACK' *) - (*$HPPEMIT '#undef INADDR_BROADCAST' *) - (*$HPPEMIT '#undef INADDR_NONE' *) - (*$HPPEMIT '#undef INVALID_SOCKET' *) - (*$HPPEMIT '#undef SOCKET_ERROR' *) - (*$HPPEMIT '#undef WSADESCRIPTION_LEN' *) - (*$HPPEMIT '#undef WSASYS_STATUS_LEN' *) - (*$HPPEMIT '#undef IP_OPTIONS' *) - (*$HPPEMIT '#undef IP_TOS' *) - (*$HPPEMIT '#undef IP_TTL' *) - (*$HPPEMIT '#undef IP_MULTICAST_IF' *) - (*$HPPEMIT '#undef IP_MULTICAST_TTL' *) - (*$HPPEMIT '#undef IP_MULTICAST_LOOP' *) - (*$HPPEMIT '#undef IP_ADD_MEMBERSHIP' *) - (*$HPPEMIT '#undef IP_DROP_MEMBERSHIP' *) - (*$HPPEMIT '#undef IP_DONTFRAGMENT' *) - (*$HPPEMIT '#undef IP_DEFAULT_MULTICAST_TTL' *) - (*$HPPEMIT '#undef IP_DEFAULT_MULTICAST_LOOP' *) - (*$HPPEMIT '#undef IP_MAX_MEMBERSHIPS' *) - (*$HPPEMIT '#undef SOL_SOCKET' *) - (*$HPPEMIT '#undef SO_DEBUG' *) - (*$HPPEMIT '#undef SO_ACCEPTCONN' *) - (*$HPPEMIT '#undef SO_REUSEADDR' *) - (*$HPPEMIT '#undef SO_KEEPALIVE' *) - (*$HPPEMIT '#undef SO_DONTROUTE' *) - (*$HPPEMIT '#undef SO_BROADCAST' *) - (*$HPPEMIT '#undef SO_USELOOPBACK' *) - (*$HPPEMIT '#undef SO_LINGER' *) - (*$HPPEMIT '#undef SO_OOBINLINE' *) - (*$HPPEMIT '#undef SO_DONTLINGER' *) - (*$HPPEMIT '#undef SO_SNDBUF' *) - (*$HPPEMIT '#undef SO_RCVBUF' *) - (*$HPPEMIT '#undef SO_SNDLOWAT' *) - (*$HPPEMIT '#undef SO_RCVLOWAT' *) - (*$HPPEMIT '#undef SO_SNDTIMEO' *) - (*$HPPEMIT '#undef SO_RCVTIMEO' *) - (*$HPPEMIT '#undef SO_ERROR' *) - (*$HPPEMIT '#undef SO_OPENTYPE' *) - (*$HPPEMIT '#undef SO_SYNCHRONOUS_ALERT' *) - (*$HPPEMIT '#undef SO_SYNCHRONOUS_NONALERT' *) - (*$HPPEMIT '#undef SO_MAXDG' *) - (*$HPPEMIT '#undef SO_MAXPATHDG' *) - (*$HPPEMIT '#undef SO_UPDATE_ACCEPT_CONTEXT' *) - (*$HPPEMIT '#undef SO_CONNECT_TIME' *) - (*$HPPEMIT '#undef SO_TYPE' *) - (*$HPPEMIT '#undef SOCK_STREAM' *) - (*$HPPEMIT '#undef SOCK_DGRAM' *) - (*$HPPEMIT '#undef SOCK_RAW' *) - (*$HPPEMIT '#undef SOCK_RDM' *) - (*$HPPEMIT '#undef SOCK_SEQPACKET' *) - (*$HPPEMIT '#undef TCP_NODELAY' *) - (*$HPPEMIT '#undef AF_UNSPEC' *) - (*$HPPEMIT '#undef SOMAXCONN' *) - (*$HPPEMIT '#undef AF_INET' *) - (*$HPPEMIT '#undef AF_MAX' *) - (*$HPPEMIT '#undef PF_UNSPEC' *) - (*$HPPEMIT '#undef PF_INET' *) - (*$HPPEMIT '#undef PF_MAX' *) - (*$HPPEMIT '#undef MSG_OOB' *) - (*$HPPEMIT '#undef MSG_PEEK' *) - (*$HPPEMIT '#undef WSABASEERR' *) - (*$HPPEMIT '#undef WSAEINTR' *) - (*$HPPEMIT '#undef WSAEBADF' *) - (*$HPPEMIT '#undef WSAEACCES' *) - (*$HPPEMIT '#undef WSAEFAULT' *) - (*$HPPEMIT '#undef WSAEINVAL' *) - (*$HPPEMIT '#undef WSAEMFILE' *) - (*$HPPEMIT '#undef WSAEWOULDBLOCK' *) - (*$HPPEMIT '#undef WSAEINPROGRESS' *) - (*$HPPEMIT '#undef WSAEALREADY' *) - (*$HPPEMIT '#undef WSAENOTSOCK' *) - (*$HPPEMIT '#undef WSAEDESTADDRREQ' *) - (*$HPPEMIT '#undef WSAEMSGSIZE' *) - (*$HPPEMIT '#undef WSAEPROTOTYPE' *) - (*$HPPEMIT '#undef WSAENOPROTOOPT' *) - (*$HPPEMIT '#undef WSAEPROTONOSUPPORT' *) - (*$HPPEMIT '#undef WSAESOCKTNOSUPPORT' *) - (*$HPPEMIT '#undef WSAEOPNOTSUPP' *) - (*$HPPEMIT '#undef WSAEPFNOSUPPORT' *) - (*$HPPEMIT '#undef WSAEAFNOSUPPORT' *) - (*$HPPEMIT '#undef WSAEADDRINUSE' *) - (*$HPPEMIT '#undef WSAEADDRNOTAVAIL' *) - (*$HPPEMIT '#undef WSAENETDOWN' *) - (*$HPPEMIT '#undef WSAENETUNREACH' *) - (*$HPPEMIT '#undef WSAENETRESET' *) - (*$HPPEMIT '#undef WSAECONNABORTED' *) - (*$HPPEMIT '#undef WSAECONNRESET' *) - (*$HPPEMIT '#undef WSAENOBUFS' *) - (*$HPPEMIT '#undef WSAEISCONN' *) - (*$HPPEMIT '#undef WSAENOTCONN' *) - (*$HPPEMIT '#undef WSAESHUTDOWN' *) - (*$HPPEMIT '#undef WSAETOOMANYREFS' *) - (*$HPPEMIT '#undef WSAETIMEDOUT' *) - (*$HPPEMIT '#undef WSAECONNREFUSED' *) - (*$HPPEMIT '#undef WSAELOOP' *) - (*$HPPEMIT '#undef WSAENAMETOOLONG' *) - (*$HPPEMIT '#undef WSAEHOSTDOWN' *) - (*$HPPEMIT '#undef WSAEHOSTUNREACH' *) - (*$HPPEMIT '#undef WSAENOTEMPTY' *) - (*$HPPEMIT '#undef WSAEPROCLIM' *) - (*$HPPEMIT '#undef WSAEUSERS' *) - (*$HPPEMIT '#undef WSAEDQUOT' *) - (*$HPPEMIT '#undef WSAESTALE' *) - (*$HPPEMIT '#undef WSAEREMOTE' *) - (*$HPPEMIT '#undef WSASYSNOTREADY' *) - (*$HPPEMIT '#undef WSAVERNOTSUPPORTED' *) - (*$HPPEMIT '#undef WSANOTINITIALISED' *) - (*$HPPEMIT '#undef WSAEDISCON' *) - (*$HPPEMIT '#undef WSAENOMORE' *) - (*$HPPEMIT '#undef WSAECANCELLED' *) - (*$HPPEMIT '#undef WSAEEINVALIDPROCTABLE' *) - (*$HPPEMIT '#undef WSAEINVALIDPROVIDER' *) - (*$HPPEMIT '#undef WSAEPROVIDERFAILEDINIT' *) - (*$HPPEMIT '#undef WSASYSCALLFAILURE' *) - (*$HPPEMIT '#undef WSASERVICE_NOT_FOUND' *) - (*$HPPEMIT '#undef WSATYPE_NOT_FOUND' *) - (*$HPPEMIT '#undef WSA_E_NO_MORE' *) - (*$HPPEMIT '#undef WSA_E_CANCELLED' *) - (*$HPPEMIT '#undef WSAEREFUSED' *) - (*$HPPEMIT '#undef WSAHOST_NOT_FOUND' *) - (*$HPPEMIT '#undef HOST_NOT_FOUND' *) - (*$HPPEMIT '#undef WSATRY_AGAIN' *) - (*$HPPEMIT '#undef TRY_AGAIN' *) - (*$HPPEMIT '#undef WSANO_RECOVERY' *) - (*$HPPEMIT '#undef NO_RECOVERY' *) - (*$HPPEMIT '#undef WSANO_DATA' *) - (*$HPPEMIT '#undef NO_DATA' *) - (*$HPPEMIT '#undef WSANO_ADDRESS' *) - (*$HPPEMIT '#undef ENAMETOOLONG' *) - (*$HPPEMIT '#undef ENOTEMPTY' *) - (*$HPPEMIT '#undef FD_CLR' *) - (*$HPPEMIT '#undef FD_ISSET' *) - (*$HPPEMIT '#undef FD_SET' *) - (*$HPPEMIT '#undef FD_ZERO' *) - (*$HPPEMIT '#undef NO_ADDRESS' *) - (*$HPPEMIT '#undef ADDR_ANY' *) - (*$HPPEMIT '#undef SO_GROUP_ID' *) - (*$HPPEMIT '#undef SO_GROUP_PRIORITY' *) - (*$HPPEMIT '#undef SO_MAX_MSG_SIZE' *) - (*$HPPEMIT '#undef SO_PROTOCOL_INFOA' *) - (*$HPPEMIT '#undef SO_PROTOCOL_INFOW' *) - (*$HPPEMIT '#undef SO_PROTOCOL_INFO' *) - (*$HPPEMIT '#undef PVD_CONFIG' *) - (*$HPPEMIT '#undef AF_INET6' *) - (*$HPPEMIT '#undef PF_INET6' *) -{$ENDIF} - -{$IFDEF FPC} - {$IFDEF WIN32} - {$ALIGN OFF} - {$ELSE} - {$PACKRECORDS C} - {$ENDIF} -{$ELSE} - {$IFDEF WIN64} - {$ALIGN ON} - {$MINENUMSIZE 4} - {$ELSE} - {$MINENUMSIZE 4} - {$ALIGN OFF} - {$ENDIF} -{$ENDIF} - -interface - -uses - SyncObjs, SysUtils, Classes, - Windows; - -function InitSocketInterface(stack: String): Boolean; -function DestroySocketInterface: Boolean; - -const -{$IFDEF WINSOCK1} - WinsockLevel = $0101; -{$ELSE} - WinsockLevel = $0202; -{$ENDIF} - -type - u_short = Word; - u_int = Integer; - u_long = Longint; - pu_long = ^u_long; - pu_short = ^u_short; -{$IFDEF FPC} - TSocket = ptruint; -{$ELSE} - {$IFDEF WIN64} - TSocket = UINT_PTR; - {$ELSE} - TSocket = u_int; - {$ENDIF} -{$ENDIF} - TAddrFamily = integer; - - TMemory = pointer; - -const - {$IFDEF WINCE} - DLLStackName = 'ws2.dll'; - {$ELSE} - {$IFDEF WINSOCK1} - DLLStackName = 'wsock32.dll'; - {$ELSE} - DLLStackName = 'ws2_32.dll'; - {$ENDIF} - {$ENDIF} - DLLwship6 = 'wship6.dll'; - - cLocalhost = '127.0.0.1'; - cAnyHost = '0.0.0.0'; - cBroadcast = '255.255.255.255'; - c6Localhost = '::1'; - c6AnyHost = '::0'; - c6Broadcast = 'ffff::1'; - cAnyPort = '0'; - - -const - FD_SETSIZE = 64; -type - PFDSet = ^TFDSet; - TFDSet = record - fd_count: u_int; - fd_array: array[0..FD_SETSIZE-1] of TSocket; - end; - -const - FIONREAD = $4004667f; - FIONBIO = $8004667e; - FIOASYNC = $8004667d; - -type - PTimeVal = ^TTimeVal; - TTimeVal = record - tv_sec: Longint; - tv_usec: Longint; - end; - -const - IPPROTO_IP = 0; { Dummy } - IPPROTO_ICMP = 1; { Internet Control Message Protocol } - IPPROTO_IGMP = 2; { Internet Group Management Protocol} - IPPROTO_TCP = 6; { TCP } - IPPROTO_UDP = 17; { User Datagram Protocol } - IPPROTO_IPV6 = 41; - IPPROTO_ICMPV6 = 58; - IPPROTO_RM = 113; - - IPPROTO_RAW = 255; - IPPROTO_MAX = 256; - -type - - PInAddr = ^TInAddr; - TInAddr = record - case integer of - 0: (S_bytes: packed array [0..3] of byte); - 1: (S_addr: u_long); - end; - - PSockAddrIn = ^TSockAddrIn; - TSockAddrIn = record - case Integer of - 0: (sin_family: u_short; - sin_port: u_short; - sin_addr: TInAddr; - sin_zero: array[0..7] of byte); - 1: (sa_family: u_short; - sa_data: array[0..13] of byte) - end; - - TIP_mreq = record - imr_multiaddr: TInAddr; { IP multicast address of group } - imr_interface: TInAddr; { local IP address of interface } - end; - - PInAddr6 = ^TInAddr6; - TInAddr6 = record - case integer of - 0: (S6_addr: packed array [0..15] of byte); - 1: (u6_addr8: packed array [0..15] of byte); - 2: (u6_addr16: packed array [0..7] of word); - 3: (u6_addr32: packed array [0..3] of integer); - end; - - PSockAddrIn6 = ^TSockAddrIn6; - TSockAddrIn6 = record - sin6_family: u_short; // AF_INET6 - sin6_port: u_short; // Transport level port number - sin6_flowinfo: u_long; // IPv6 flow information - sin6_addr: TInAddr6; // IPv6 address - sin6_scope_id: u_long; // Scope Id: IF number for link-local - // SITE id for site-local - end; - - TIPv6_mreq = record - ipv6mr_multiaddr: TInAddr6; // IPv6 multicast address. - ipv6mr_interface: integer; // Interface index. - padding: integer; - end; - - PHostEnt = ^THostEnt; - THostEnt = record - h_name: PAnsiChar; - h_aliases: ^PAnsiChar; - h_addrtype: Smallint; - h_length: Smallint; - case integer of - 0: (h_addr_list: ^PAnsiChar); - 1: (h_addr: ^PInAddr); - end; - - PNetEnt = ^TNetEnt; - TNetEnt = record - n_name: PAnsiChar; - n_aliases: ^PAnsiChar; - n_addrtype: Smallint; - n_net: u_long; - end; - - PServEnt = ^TServEnt; - TServEnt = record - s_name: PAnsiChar; - s_aliases: ^PAnsiChar; -{$ifdef WIN64} - s_proto: PAnsiChar; - s_port: Smallint; -{$else} - s_port: Smallint; - s_proto: PAnsiChar; -{$endif} - end; - - PProtoEnt = ^TProtoEnt; - TProtoEnt = record - p_name: PAnsiChar; - p_aliases: ^PAnsichar; - p_proto: Smallint; - end; - -const - INADDR_ANY = $00000000; - INADDR_LOOPBACK = $7F000001; - INADDR_BROADCAST = $FFFFFFFF; - INADDR_NONE = $FFFFFFFF; - ADDR_ANY = INADDR_ANY; - INVALID_SOCKET = TSocket(NOT(0)); - SOCKET_ERROR = -1; - -Const - {$IFDEF WINSOCK1} - IP_OPTIONS = 1; - IP_MULTICAST_IF = 2; { set/get IP multicast interface } - IP_MULTICAST_TTL = 3; { set/get IP multicast timetolive } - IP_MULTICAST_LOOP = 4; { set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = 5; { add an IP group membership } - IP_DROP_MEMBERSHIP = 6; { drop an IP group membership } - IP_TTL = 7; { set/get IP Time To Live } - IP_TOS = 8; { set/get IP Type Of Service } - IP_DONTFRAGMENT = 9; { set/get IP Don't Fragment flag } - {$ELSE} - IP_OPTIONS = 1; - IP_HDRINCL = 2; - IP_TOS = 3; { set/get IP Type Of Service } - IP_TTL = 4; { set/get IP Time To Live } - IP_MULTICAST_IF = 9; { set/get IP multicast interface } - IP_MULTICAST_TTL = 10; { set/get IP multicast timetolive } - IP_MULTICAST_LOOP = 11; { set/get IP multicast loopback } - IP_ADD_MEMBERSHIP = 12; { add an IP group membership } - IP_DROP_MEMBERSHIP = 13; { drop an IP group membership } - IP_DONTFRAGMENT = 14; { set/get IP Don't Fragment flag } - {$ENDIF} - - IP_DEFAULT_MULTICAST_TTL = 1; { normally limit m'casts to 1 hop } - IP_DEFAULT_MULTICAST_LOOP = 1; { normally hear sends if a member } - IP_MAX_MEMBERSHIPS = 20; { per socket; must fit in one mbuf } - - SOL_SOCKET = $ffff; {options for socket level } -{ Option flags per-socket. } - SO_DEBUG = $0001; { turn on debugging info recording } - SO_ACCEPTCONN = $0002; { socket has had listen() } - SO_REUSEADDR = $0004; { allow local address reuse } - SO_KEEPALIVE = $0008; { keep connections alive } - SO_DONTROUTE = $0010; { just use interface addresses } - SO_BROADCAST = $0020; { permit sending of broadcast msgs } - SO_USELOOPBACK = $0040; { bypass hardware when possible } - SO_LINGER = $0080; { linger on close if data present } - SO_OOBINLINE = $0100; { leave received OOB data in line } - SO_DONTLINGER = $ff7f; -{ Additional options. } - SO_SNDBUF = $1001; { send buffer size } - SO_RCVBUF = $1002; { receive buffer size } - SO_SNDLOWAT = $1003; { send low-water mark } - SO_RCVLOWAT = $1004; { receive low-water mark } - SO_SNDTIMEO = $1005; { send timeout } - SO_RCVTIMEO = $1006; { receive timeout } - SO_ERROR = $1007; { get error status and clear } - SO_TYPE = $1008; { get socket type } -{ WinSock 2 extension -- new options } - SO_GROUP_ID = $2001; { ID of a socket group} - SO_GROUP_PRIORITY = $2002; { the relative priority within a group} - SO_MAX_MSG_SIZE = $2003; { maximum message size } - SO_PROTOCOL_INFOA = $2004; { WSAPROTOCOL_INFOA structure } - SO_PROTOCOL_INFOW = $2005; { WSAPROTOCOL_INFOW structure } - SO_PROTOCOL_INFO = SO_PROTOCOL_INFOA; - PVD_CONFIG = $3001; {configuration info for service provider } -{ Option for opening sockets for synchronous access. } - SO_OPENTYPE = $7008; - SO_SYNCHRONOUS_ALERT = $10; - SO_SYNCHRONOUS_NONALERT = $20; -{ Other NT-specific options. } - SO_MAXDG = $7009; - SO_MAXPATHDG = $700A; - SO_UPDATE_ACCEPT_CONTEXT = $700B; - SO_CONNECT_TIME = $700C; - - SOMAXCONN = $7fffffff; - - IPV6_UNICAST_HOPS = 8; // ??? - IPV6_MULTICAST_IF = 9; // set/get IP multicast i/f - IPV6_MULTICAST_HOPS = 10; // set/get IP multicast ttl - IPV6_MULTICAST_LOOP = 11; // set/get IP multicast loopback - IPV6_JOIN_GROUP = 12; // add an IP group membership - IPV6_LEAVE_GROUP = 13; // drop an IP group membership - - MSG_NOSIGNAL = 0; - - // getnameinfo constants - NI_MAXHOST = 1025; - NI_MAXSERV = 32; - NI_NOFQDN = $1; - NI_NUMERICHOST = $2; - NI_NAMEREQD = $4; - NI_NUMERICSERV = $8; - NI_DGRAM = $10; - - -const - SOCK_STREAM = 1; { stream socket } - SOCK_DGRAM = 2; { datagram socket } - SOCK_RAW = 3; { raw-protocol interface } - SOCK_RDM = 4; { reliably-delivered message } - SOCK_SEQPACKET = 5; { sequenced packet stream } - -{ TCP options. } - TCP_NODELAY = $0001; - -{ Address families. } - - AF_UNSPEC = 0; { unspecified } - AF_INET = 2; { internetwork: UDP, TCP, etc. } - AF_INET6 = 23; { Internetwork Version 6 } - AF_MAX = 24; - -{ Protocol families, same as address families for now. } - PF_UNSPEC = AF_UNSPEC; - PF_INET = AF_INET; - PF_INET6 = AF_INET6; - PF_MAX = AF_MAX; - -type - { Structure used by kernel to store most addresses. } - PSockAddr = ^TSockAddr; - TSockAddr = TSockAddrIn; - - { Structure used by kernel to pass protocol information in raw sockets. } - PSockProto = ^TSockProto; - TSockProto = record - sp_family: u_short; - sp_protocol: u_short; - end; - -type - PAddrInfo = ^TAddrInfo; - TAddrInfo = record - ai_flags: integer; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST. - ai_family: integer; // PF_xxx. - ai_socktype: integer; // SOCK_xxx. - ai_protocol: integer; // 0 or IPPROTO_xxx for IPv4 and IPv6. - ai_addrlen: u_int; // Length of ai_addr. - ai_canonname: PAnsiChar; // Canonical name for nodename. - ai_addr: PSockAddr; // Binary address. - ai_next: PAddrInfo; // Next structure in linked list. - end; - -const - // Flags used in "hints" argument to getaddrinfo(). - AI_PASSIVE = $1; // Socket address will be used in bind() call. - AI_CANONNAME = $2; // Return canonical name in first ai_canonname. - AI_NUMERICHOST = $4; // Nodename must be a numeric address string. - -type -{ Structure used for manipulating linger option. } - PLinger = ^TLinger; - TLinger = record - l_onoff: u_short; - l_linger: u_short; - end; - -const - - MSG_OOB = $01; // Process out-of-band data. - MSG_PEEK = $02; // Peek at incoming messages. - -const - -{ All Windows Sockets error constants are biased by WSABASEERR from the "normal" } - WSABASEERR = 10000; - -{ Windows Sockets definitions of regular Microsoft C error constants } - - WSAEINTR = (WSABASEERR+4); - WSAEBADF = (WSABASEERR+9); - WSAEACCES = (WSABASEERR+13); - WSAEFAULT = (WSABASEERR+14); - WSAEINVAL = (WSABASEERR+22); - WSAEMFILE = (WSABASEERR+24); - -{ Windows Sockets definitions of regular Berkeley error constants } - - WSAEWOULDBLOCK = (WSABASEERR+35); - WSAEINPROGRESS = (WSABASEERR+36); - WSAEALREADY = (WSABASEERR+37); - WSAENOTSOCK = (WSABASEERR+38); - WSAEDESTADDRREQ = (WSABASEERR+39); - WSAEMSGSIZE = (WSABASEERR+40); - WSAEPROTOTYPE = (WSABASEERR+41); - WSAENOPROTOOPT = (WSABASEERR+42); - WSAEPROTONOSUPPORT = (WSABASEERR+43); - WSAESOCKTNOSUPPORT = (WSABASEERR+44); - WSAEOPNOTSUPP = (WSABASEERR+45); - WSAEPFNOSUPPORT = (WSABASEERR+46); - WSAEAFNOSUPPORT = (WSABASEERR+47); - WSAEADDRINUSE = (WSABASEERR+48); - WSAEADDRNOTAVAIL = (WSABASEERR+49); - WSAENETDOWN = (WSABASEERR+50); - WSAENETUNREACH = (WSABASEERR+51); - WSAENETRESET = (WSABASEERR+52); - WSAECONNABORTED = (WSABASEERR+53); - WSAECONNRESET = (WSABASEERR+54); - WSAENOBUFS = (WSABASEERR+55); - WSAEISCONN = (WSABASEERR+56); - WSAENOTCONN = (WSABASEERR+57); - WSAESHUTDOWN = (WSABASEERR+58); - WSAETOOMANYREFS = (WSABASEERR+59); - WSAETIMEDOUT = (WSABASEERR+60); - WSAECONNREFUSED = (WSABASEERR+61); - WSAELOOP = (WSABASEERR+62); - WSAENAMETOOLONG = (WSABASEERR+63); - WSAEHOSTDOWN = (WSABASEERR+64); - WSAEHOSTUNREACH = (WSABASEERR+65); - WSAENOTEMPTY = (WSABASEERR+66); - WSAEPROCLIM = (WSABASEERR+67); - WSAEUSERS = (WSABASEERR+68); - WSAEDQUOT = (WSABASEERR+69); - WSAESTALE = (WSABASEERR+70); - WSAEREMOTE = (WSABASEERR+71); - -{ Extended Windows Sockets error constant definitions } - - WSASYSNOTREADY = (WSABASEERR+91); - WSAVERNOTSUPPORTED = (WSABASEERR+92); - WSANOTINITIALISED = (WSABASEERR+93); - WSAEDISCON = (WSABASEERR+101); - WSAENOMORE = (WSABASEERR+102); - WSAECANCELLED = (WSABASEERR+103); - WSAEEINVALIDPROCTABLE = (WSABASEERR+104); - WSAEINVALIDPROVIDER = (WSABASEERR+105); - WSAEPROVIDERFAILEDINIT = (WSABASEERR+106); - WSASYSCALLFAILURE = (WSABASEERR+107); - WSASERVICE_NOT_FOUND = (WSABASEERR+108); - WSATYPE_NOT_FOUND = (WSABASEERR+109); - WSA_E_NO_MORE = (WSABASEERR+110); - WSA_E_CANCELLED = (WSABASEERR+111); - WSAEREFUSED = (WSABASEERR+112); - -{ Error return codes from gethostbyname() and gethostbyaddr() - (when using the resolver). Note that these errors are - retrieved via WSAGetLastError() and must therefore follow - the rules for avoiding clashes with error numbers from - specific implementations or language run-time systems. - For this reason the codes are based at WSABASEERR+1001. - Note also that [WSA]NO_ADDRESS is defined only for - compatibility purposes. } - -{ Authoritative Answer: Host not found } - WSAHOST_NOT_FOUND = (WSABASEERR+1001); - HOST_NOT_FOUND = WSAHOST_NOT_FOUND; -{ Non-Authoritative: Host not found, or SERVERFAIL } - WSATRY_AGAIN = (WSABASEERR+1002); - TRY_AGAIN = WSATRY_AGAIN; -{ Non recoverable errors, FORMERR, REFUSED, NOTIMP } - WSANO_RECOVERY = (WSABASEERR+1003); - NO_RECOVERY = WSANO_RECOVERY; -{ Valid name, no data record of requested type } - WSANO_DATA = (WSABASEERR+1004); - NO_DATA = WSANO_DATA; -{ no address, look for MX record } - WSANO_ADDRESS = WSANO_DATA; - NO_ADDRESS = WSANO_ADDRESS; - - EWOULDBLOCK = WSAEWOULDBLOCK; - EINPROGRESS = WSAEINPROGRESS; - EALREADY = WSAEALREADY; - ENOTSOCK = WSAENOTSOCK; - EDESTADDRREQ = WSAEDESTADDRREQ; - EMSGSIZE = WSAEMSGSIZE; - EPROTOTYPE = WSAEPROTOTYPE; - ENOPROTOOPT = WSAENOPROTOOPT; - EPROTONOSUPPORT = WSAEPROTONOSUPPORT; - ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT; - EOPNOTSUPP = WSAEOPNOTSUPP; - EPFNOSUPPORT = WSAEPFNOSUPPORT; - EAFNOSUPPORT = WSAEAFNOSUPPORT; - EADDRINUSE = WSAEADDRINUSE; - EADDRNOTAVAIL = WSAEADDRNOTAVAIL; - ENETDOWN = WSAENETDOWN; - ENETUNREACH = WSAENETUNREACH; - ENETRESET = WSAENETRESET; - ECONNABORTED = WSAECONNABORTED; - ECONNRESET = WSAECONNRESET; - ENOBUFS = WSAENOBUFS; - EISCONN = WSAEISCONN; - ENOTCONN = WSAENOTCONN; - ESHUTDOWN = WSAESHUTDOWN; - ETOOMANYREFS = WSAETOOMANYREFS; - ETIMEDOUT = WSAETIMEDOUT; - ECONNREFUSED = WSAECONNREFUSED; - ELOOP = WSAELOOP; - ENAMETOOLONG = WSAENAMETOOLONG; - EHOSTDOWN = WSAEHOSTDOWN; - EHOSTUNREACH = WSAEHOSTUNREACH; - ENOTEMPTY = WSAENOTEMPTY; - EPROCLIM = WSAEPROCLIM; - EUSERS = WSAEUSERS; - EDQUOT = WSAEDQUOT; - ESTALE = WSAESTALE; - EREMOTE = WSAEREMOTE; - - EAI_ADDRFAMILY = 1; // Address family for nodename not supported. - EAI_AGAIN = 2; // Temporary failure in name resolution. - EAI_BADFLAGS = 3; // Invalid value for ai_flags. - EAI_FAIL = 4; // Non-recoverable failure in name resolution. - EAI_FAMILY = 5; // Address family ai_family not supported. - EAI_MEMORY = 6; // Memory allocation failure. - EAI_NODATA = 7; // No address associated with nodename. - EAI_NONAME = 8; // Nodename nor servname provided, or not known. - EAI_SERVICE = 9; // Servname not supported for ai_socktype. - EAI_SOCKTYPE = 10; // Socket type ai_socktype not supported. - EAI_SYSTEM = 11; // System error returned in errno. - -const - WSADESCRIPTION_LEN = 256; - WSASYS_STATUS_LEN = 128; -type - PWSAData = ^TWSAData; - TWSAData = record - wVersion: Word; - wHighVersion: Word; -{$ifdef win64} - iMaxSockets : Word; - iMaxUdpDg : Word; - lpVendorInfo : PAnsiChar; - szDescription : array[0..WSADESCRIPTION_LEN] of AnsiChar; - szSystemStatus : array[0..WSASYS_STATUS_LEN] of AnsiChar; -{$else} - szDescription: array[0..WSADESCRIPTION_LEN] of AnsiChar; - szSystemStatus: array[0..WSASYS_STATUS_LEN] of AnsiChar; - iMaxSockets: Word; - iMaxUdpDg: Word; - lpVendorInfo: PAnsiChar; -{$endif} - end; - - function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; - function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; - function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; - function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6):boolean; - procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); - procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -var - in6addr_any, in6addr_loopback : TInAddr6; - -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -procedure FD_ZERO(var FDSet: TFDSet); - -{=============================================================================} - -type - TWSAStartup = function(wVersionRequired: Word; var WSData: TWSAData): Integer; - stdcall; - TWSACleanup = function: Integer; - stdcall; - TWSAGetLastError = function: Integer; - stdcall; - TGetServByName = function(name, proto: PAnsiChar): PServEnt; - stdcall; - TGetServByPort = function(port: Integer; proto: PAnsiChar): PServEnt; - stdcall; - TGetProtoByName = function(name: PAnsiChar): PProtoEnt; - stdcall; - TGetProtoByNumber = function(proto: Integer): PProtoEnt; - stdcall; - TGetHostByName = function(name: PAnsiChar): PHostEnt; - stdcall; - TGetHostByAddr = function(addr: Pointer; len, Struc: Integer): PHostEnt; - stdcall; - TGetHostName = function(name: PAnsiChar; len: Integer): Integer; - stdcall; - TShutdown = function(s: TSocket; how: Integer): Integer; - stdcall; - TSetSockOpt = function(s: TSocket; level, optname: Integer; optval: PAnsiChar; - optlen: Integer): Integer; - stdcall; - TGetSockOpt = function(s: TSocket; level, optname: Integer; optval: PAnsiChar; - var optlen: Integer): Integer; - stdcall; - TSendTo = function(s: TSocket; const Buf; len, flags: Integer; addrto: PSockAddr; - tolen: Integer): Integer; - stdcall; - TSend = function(s: TSocket; const Buf; len, flags: Integer): Integer; - stdcall; - TRecv = function(s: TSocket; var Buf; len, flags: Integer): Integer; - stdcall; - TRecvFrom = function(s: TSocket; var Buf; len, flags: Integer; from: PSockAddr; - var fromlen: Integer): Integer; - stdcall; - Tntohs = function(netshort: u_short): u_short; - stdcall; - Tntohl = function(netlong: u_long): u_long; - stdcall; - TListen = function(s: TSocket; backlog: Integer): Integer; - stdcall; - TIoctlSocket = function(s: TSocket; cmd: DWORD; var arg: Integer): Integer; - stdcall; - TInet_ntoa = function(inaddr: TInAddr): PAnsiChar; - stdcall; - TInet_addr = function(cp: PAnsiChar): u_long; - stdcall; - Thtons = function(hostshort: u_short): u_short; - stdcall; - Thtonl = function(hostlong: u_long): u_long; - stdcall; - TGetSockName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - stdcall; - TGetPeerName = function(s: TSocket; name: PSockAddr; var namelen: Integer): Integer; - stdcall; - TConnect = function(s: TSocket; name: PSockAddr; namelen: Integer): Integer; - stdcall; - TCloseSocket = function(s: TSocket): Integer; - stdcall; - TBind = function(s: TSocket; addr: PSockAddr; namelen: Integer): Integer; - stdcall; - TAccept = function(s: TSocket; addr: PSockAddr; var addrlen: Integer): TSocket; - stdcall; - TTSocket = function(af, Struc, Protocol: Integer): TSocket; - stdcall; - TSelect = function(nfds: Integer; readfds, writefds, exceptfds: PFDSet; - timeout: PTimeVal): Longint; - stdcall; - - TGetAddrInfo = function(NodeName: PAnsiChar; ServName: PAnsiChar; Hints: PAddrInfo; - var Addrinfo: PAddrInfo): integer; - stdcall; - TFreeAddrInfo = procedure(ai: PAddrInfo); - stdcall; - TGetNameInfo = function( addr: PSockAddr; namelen: Integer; host: PAnsiChar; - hostlen: DWORD; serv: PAnsiChar; servlen: DWORD; flags: integer): integer; - stdcall; - - T__WSAFDIsSet = function (s: TSocket; var FDSet: TFDSet): Bool; - stdcall; - - TWSAIoctl = function (s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: Pointer; - cbInBuffer: DWORD; lpvOutBuffer: Pointer; cbOutBuffer: DWORD; - lpcbBytesReturned: PDWORD; lpOverlapped: Pointer; - lpCompletionRoutine: pointer): u_int; - stdcall; - -var - WSAStartup: TWSAStartup = nil; - WSACleanup: TWSACleanup = nil; - WSAGetLastError: TWSAGetLastError = nil; - GetServByName: TGetServByName = nil; - GetServByPort: TGetServByPort = nil; - GetProtoByName: TGetProtoByName = nil; - GetProtoByNumber: TGetProtoByNumber = nil; - GetHostByName: TGetHostByName = nil; - GetHostByAddr: TGetHostByAddr = nil; - ssGetHostName: TGetHostName = nil; - Shutdown: TShutdown = nil; - SetSockOpt: TSetSockOpt = nil; - GetSockOpt: TGetSockOpt = nil; - ssSendTo: TSendTo = nil; - ssSend: TSend = nil; - ssRecv: TRecv = nil; - ssRecvFrom: TRecvFrom = nil; - ntohs: Tntohs = nil; - ntohl: Tntohl = nil; - Listen: TListen = nil; - IoctlSocket: TIoctlSocket = nil; - Inet_ntoa: TInet_ntoa = nil; - Inet_addr: TInet_addr = nil; - htons: Thtons = nil; - htonl: Thtonl = nil; - ssGetSockName: TGetSockName = nil; - ssGetPeerName: TGetPeerName = nil; - ssConnect: TConnect = nil; - CloseSocket: TCloseSocket = nil; - ssBind: TBind = nil; - ssAccept: TAccept = nil; - Socket: TTSocket = nil; - Select: TSelect = nil; - - GetAddrInfo: TGetAddrInfo = nil; - FreeAddrInfo: TFreeAddrInfo = nil; - GetNameInfo: TGetNameInfo = nil; - - __WSAFDIsSet: T__WSAFDIsSet = nil; - - WSAIoctl: TWSAIoctl = nil; - -var - SynSockCS: SyncObjs.TCriticalSection; - SockEnhancedApi: Boolean; - SockWship6Api: Boolean; - -type - TVarSin = packed record - case integer of - 0: (AddressFamily: u_short); - 1: ( - case sin_family: u_short of - AF_INET: (sin_port: u_short; - sin_addr: TInAddr; - sin_zero: array[0..7] of byte); - AF_INET6: (sin6_port: u_short; - sin6_flowinfo: u_long; - sin6_addr: TInAddr6; - sin6_scope_id: u_long); - ); - end; - -function SizeOfVarSin(sin: TVarSin): integer; - -function Bind(s: TSocket; const addr: TVarSin): Integer; -function Connect(s: TSocket; const name: TVarSin): Integer; -function GetSockName(s: TSocket; var name: TVarSin): Integer; -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -function GetHostName: AnsiString; -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -function Accept(s: TSocket; var addr: TVarSin): TSocket; - -function IsNewApi(Family: integer): Boolean; -function SetVarSin(var Sin: TVarSin; IP, Port: AnsiString; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -function GetSinIP(Sin: TVarSin): AnsiString; -function GetSinPort(Sin: TVarSin): Integer; -procedure ResolveNameToIP(Name: AnsiString; Family, SockProtocol, SockType: integer; const IPList: TStrings); -function ResolveIPToName(IP: AnsiString; Family, SockProtocol, SockType: integer): AnsiString; -function ResolvePort(Port: AnsiString; Family, SockProtocol, SockType: integer): Word; - -{==============================================================================} -implementation - -var - SynSockCount: Integer = 0; - LibHandle: THandle = 0; - Libwship6Handle: THandle = 0; - -function IN6_IS_ADDR_UNSPECIFIED(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and (a^.u6_addr32[3] = 0)); -end; - -function IN6_IS_ADDR_LOOPBACK(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr32[0] = 0) and (a^.u6_addr32[1] = 0) and - (a^.u6_addr32[2] = 0) and - (a^.u6_addr8[12] = 0) and (a^.u6_addr8[13] = 0) and - (a^.u6_addr8[14] = 0) and (a^.u6_addr8[15] = 1)); -end; - -function IN6_IS_ADDR_LINKLOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $80)); -end; - -function IN6_IS_ADDR_SITELOCAL(const a: PInAddr6): boolean; -begin - Result := ((a^.u6_addr8[0] = $FE) and (a^.u6_addr8[1] = $C0)); -end; - -function IN6_IS_ADDR_MULTICAST(const a: PInAddr6): boolean; -begin - Result := (a^.u6_addr8[0] = $FF); -end; - -function IN6_ADDR_EQUAL(const a: PInAddr6; const b: PInAddr6): boolean; -begin - Result := (CompareMem( a, b, sizeof(TInAddr6))); -end; - -procedure SET_IN6_IF_ADDR_ANY (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); -end; - -procedure SET_LOOPBACK_ADDR6 (const a: PInAddr6); -begin - FillChar(a^, sizeof(TInAddr6), 0); - a^.u6_addr8[15] := 1; -end; - -{=============================================================================} -procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet); -var - I: Integer; -begin - I := 0; - while I < FDSet.fd_count do - begin - if FDSet.fd_array[I] = Socket then - begin - while I < FDSet.fd_count - 1 do - begin - FDSet.fd_array[I] := FDSet.fd_array[I + 1]; - Inc(I); - end; - Dec(FDSet.fd_count); - Break; - end; - Inc(I); - end; -end; - -function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean; -begin - Result := __WSAFDIsSet(Socket, FDSet); -end; - -procedure FD_SET(Socket: TSocket; var FDSet: TFDSet); -begin - if FDSet.fd_count < FD_SETSIZE then - begin - FDSet.fd_array[FDSet.fd_count] := Socket; - Inc(FDSet.fd_count); - end; -end; - -procedure FD_ZERO(var FDSet: TFDSet); -begin - FDSet.fd_count := 0; -end; - -{=============================================================================} - -function SizeOfVarSin(sin: TVarSin): integer; -begin - case sin.sin_family of - AF_INET: - Result := SizeOf(TSockAddrIn); - AF_INET6: - Result := SizeOf(TSockAddrIn6); - else - Result := 0; - end; -end; - -{=============================================================================} - -function Bind(s: TSocket; const addr: TVarSin): Integer; -begin - Result := ssBind(s, @addr, SizeOfVarSin(addr)); -end; - -function Connect(s: TSocket; const name: TVarSin): Integer; -begin - Result := ssConnect(s, @name, SizeOfVarSin(name)); -end; - -function GetSockName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := ssGetSockName(s, @name, Len); -end; - -function GetPeerName(s: TSocket; var name: TVarSin): Integer; -var - len: integer; -begin - len := SizeOf(name); - FillChar(name, len, 0); - Result := ssGetPeerName(s, @name, Len); -end; - -function GetHostName: AnsiString; -var - s: AnsiString; -begin - Result := ''; - setlength(s, 255); - ssGetHostName(pAnsichar(s), Length(s) - 1); - Result := PAnsichar(s); -end; - -function Send(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := ssSend(s, Buf^, len, flags); -end; - -function Recv(s: TSocket; Buf: TMemory; len, flags: Integer): Integer; -begin - Result := ssRecv(s, Buf^, len, flags); -end; - -function SendTo(s: TSocket; Buf: TMemory; len, flags: Integer; addrto: TVarSin): Integer; -begin - Result := ssSendTo(s, Buf^, len, flags, @addrto, SizeOfVarSin(addrto)); -end; - -function RecvFrom(s: TSocket; Buf: TMemory; len, flags: Integer; var from: TVarSin): Integer; -var - x: integer; -begin - x := SizeOf(from); - Result := ssRecvFrom(s, Buf^, len, flags, @from, x); -end; - -function Accept(s: TSocket; var addr: TVarSin): TSocket; -var - x: integer; -begin - x := SizeOf(addr); - Result := ssAccept(s, @addr, x); -end; - -{=============================================================================} -function IsNewApi(Family: integer): Boolean; -begin - Result := SockEnhancedApi; - if not Result then - Result := (Family = AF_INET6) and SockWship6Api; -end; - -function SetVarSin(var Sin: TVarSin; IP, Port: AnsiString; Family, SockProtocol, SockType: integer; PreferIP4: Boolean): integer; -type - pu_long = ^u_long; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - HostEnt: PHostEnt; - r: integer; - Hints1, Hints2: TAddrInfo; - Sin1, Sin2: TVarSin; - TwoPass: boolean; - - function GetAddr(const IP, port: AnsiString; Hints: TAddrInfo; var Sin: TVarSin): integer; - var - Addr: PAddrInfo; - begin - Addr := nil; - try - FillChar(Sin, Sizeof(Sin), 0); - if Hints.ai_socktype = SOCK_RAW then - begin - Hints.ai_socktype := 0; - Hints.ai_protocol := 0; - Result := synsock.GetAddrInfo(PAnsiChar(IP), nil, @Hints, Addr); - end - else - begin - if (IP = cAnyHost) or (IP = c6AnyHost) then - begin - Hints.ai_flags := AI_PASSIVE; - Result := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); - end - else - if (IP = cLocalhost) or (IP = c6Localhost) then - begin - Result := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); - end - else - begin - Result := synsock.GetAddrInfo(PAnsiChar(IP), PAnsiChar(Port), @Hints, Addr); - end; - end; - if Result = 0 then - if (Addr <> nil) then - Move(Addr^.ai_addr^, Sin, Addr^.ai_addrlen); - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - -begin - Result := 0; - FillChar(Sin, Sizeof(Sin), 0); - if not IsNewApi(family) then - begin - SynSockCS.Enter; - try - Sin.sin_family := AF_INET; - ProtoEnt := synsock.GetProtoByNumber(SockProtocol); - ServEnt := nil; - if (ProtoEnt <> nil) and (StrToIntDef(string(Port),-1) =-1) then - ServEnt := synsock.GetServByName(PAnsiChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Sin.sin_port := synsock.htons(StrToIntDef(string(Port), 0)) - else - Sin.sin_port := ServEnt^.s_port; - if IP = cBroadcast then - Sin.sin_addr.s_addr := u_long(INADDR_BROADCAST) - else - begin - Sin.sin_addr.s_addr := synsock.inet_addr(PAnsiChar(IP)); - if Sin.sin_addr.s_addr = u_long(INADDR_NONE) then - begin - HostEnt := synsock.GetHostByName(PAnsiChar(IP)); - Result := synsock.WSAGetLastError; - if HostEnt <> nil then - Sin.sin_addr.S_addr := u_long(Pu_long(HostEnt^.h_addr_list^)^); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - begin - FillChar(Hints1, Sizeof(Hints1), 0); - FillChar(Hints2, Sizeof(Hints2), 0); - TwoPass := False; - if Family = AF_UNSPEC then - begin - if PreferIP4 then - begin - Hints1.ai_family := AF_INET; - Hints2.ai_family := AF_INET6; - TwoPass := True; - end - else - begin - Hints2.ai_family := AF_INET; - Hints1.ai_family := AF_INET6; - TwoPass := True; - end; - end - else - Hints1.ai_family := Family; - - Hints1.ai_socktype := SockType; - Hints1.ai_protocol := SockProtocol; - Hints2.ai_socktype := Hints1.ai_socktype; - Hints2.ai_protocol := Hints1.ai_protocol; - - r := GetAddr(IP, Port, Hints1, Sin1); - Result := r; - sin := sin1; - if r <> 0 then - if TwoPass then - begin - r := GetAddr(IP, Port, Hints2, Sin2); - Result := r; - if r = 0 then - sin := sin2; - end; - end; -end; - -function GetSinIP(Sin: TVarSin): AnsiString; -var - p: PAnsiChar; - host, serv: AnsiString; - hostlen, servlen: integer; - r: integer; -begin - Result := ''; - if not IsNewApi(Sin.AddressFamily) then - begin - p := synsock.inet_ntoa(Sin.sin_addr); - if p <> nil then - Result := p; - end - else - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(@sin, SizeOfVarSin(sin), PAnsiChar(host), hostlen, - PAnsiChar(serv), servlen, NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - Result := PAnsiChar(host); - end; -end; - -function GetSinPort(Sin: TVarSin): Integer; -begin - if (Sin.sin_family = AF_INET6) then - Result := synsock.ntohs(Sin.sin6_port) - else - Result := synsock.ntohs(Sin.sin_port); -end; - -procedure ResolveNameToIP(Name: AnsiString; Family, SockProtocol, SockType: integer; const IPList: TStrings); -type - TaPInAddr = array[0..250] of PInAddr; - PaPInAddr = ^TaPInAddr; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - AddrNext: PAddrInfo; - r: integer; - host, serv: AnsiString; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IP: u_long; - PAdrPtr: PaPInAddr; - i: Integer; - s: String; - InAddr: TInAddr; -begin - IPList.Clear; - if not IsNewApi(Family) then - begin - IP := synsock.inet_addr(PAnsiChar(Name)); - if IP = u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := synsock.GetHostByName(PAnsiChar(Name)); - if RemoteHost <> nil then - begin - PAdrPtr := PAPInAddr(RemoteHost^.h_addr_list); - i := 0; - while PAdrPtr^[i] <> nil do - begin - InAddr := PAdrPtr^[i]^; - s := Format('%d.%d.%d.%d', [InAddr.S_bytes[0], InAddr.S_bytes[1], - InAddr.S_bytes[2], InAddr.S_bytes[3]]); - IPList.Add(s); - Inc(i); - end; - end; - finally - SynSockCS.Leave; - end; - end - else - IPList.Add(string(Name)); - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PAnsiChar(Name), nil, @Hints, Addr); - if r = 0 then - begin - AddrNext := Addr; - while not(AddrNext = nil) do - begin - if not(((Family = AF_INET6) and (AddrNext^.ai_family = AF_INET)) - or ((Family = AF_INET) and (AddrNext^.ai_family = AF_INET6))) then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(AddrNext^.ai_addr, AddrNext^.ai_addrlen, - PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, - NI_NUMERICHOST + NI_NUMERICSERV); - if r = 0 then - begin - host := PAnsiChar(host); - IPList.Add(string(host)); - end; - end; - AddrNext := AddrNext^.ai_next; - end; - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; - if IPList.Count = 0 then - IPList.Add(cAnyHost); -end; - -function ResolvePort(Port: AnsiString; Family, SockProtocol, SockType: integer): Word; -var - ProtoEnt: PProtoEnt; - ServEnt: PServEnt; - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; -begin - Result := 0; - if not IsNewApi(Family) then - begin - SynSockCS.Enter; - try - ProtoEnt := synsock.GetProtoByNumber(SockProtocol); - ServEnt := nil; - if ProtoEnt <> nil then - ServEnt := synsock.GetServByName(PAnsiChar(Port), ProtoEnt^.p_name); - if ServEnt = nil then - Result := StrToIntDef(string(Port), 0) - else - Result := synsock.htons(ServEnt^.s_port); - finally - SynSockCS.Leave; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := Sockprotocol; - Hints.ai_flags := AI_PASSIVE; - r := synsock.GetAddrInfo(nil, PAnsiChar(Port), @Hints, Addr); - if (r = 0) and Assigned(Addr) then - begin - if Addr^.ai_family = AF_INET then - Result := synsock.htons(Addr^.ai_addr^.sin_port); - if Addr^.ai_family = AF_INET6 then - Result := synsock.htons(PSockAddrIn6(Addr^.ai_addr)^.sin6_port); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; - -function ResolveIPToName(IP: AnsiString; Family, SockProtocol, SockType: integer): AnsiString; -var - Hints: TAddrInfo; - Addr: PAddrInfo; - r: integer; - host, serv: AnsiString; - hostlen, servlen: integer; - RemoteHost: PHostEnt; - IPn: u_long; -begin - Result := IP; - if not IsNewApi(Family) then - begin - IPn := synsock.inet_addr(PAnsiChar(IP)); - if IPn <> u_long(INADDR_NONE) then - begin - SynSockCS.Enter; - try - RemoteHost := GetHostByAddr(@IPn, SizeOf(IPn), AF_INET); - if RemoteHost <> nil then - Result := RemoteHost^.h_name; - finally - SynSockCS.Leave; - end; - end; - end - else - begin - Addr := nil; - try - FillChar(Hints, Sizeof(Hints), 0); - Hints.ai_family := AF_UNSPEC; - Hints.ai_socktype := SockType; - Hints.ai_protocol := SockProtocol; - Hints.ai_flags := 0; - r := synsock.GetAddrInfo(PAnsiChar(IP), nil, @Hints, Addr); - if (r = 0) and Assigned(Addr)then - begin - hostlen := NI_MAXHOST; - servlen := NI_MAXSERV; - setlength(host, hostlen); - setlength(serv, servlen); - r := getnameinfo(Addr^.ai_addr, Addr^.ai_addrlen, - PAnsiChar(host), hostlen, PAnsiChar(serv), servlen, - NI_NUMERICSERV); - if r = 0 then - Result := PAnsiChar(host); - end; - finally - if Assigned(Addr) then - synsock.FreeAddrInfo(Addr); - end; - end; -end; - -{=============================================================================} - -function InitSocketInterface(stack: String): Boolean; -begin - Result := False; - if stack = '' then - stack := DLLStackName; - SynSockCS.Enter; - try - if SynSockCount = 0 then - begin - SockEnhancedApi := False; - SockWship6Api := False; - LibHandle := LoadLibrary(PChar(Stack)); - if LibHandle <> 0 then - begin - WSAIoctl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAIoctl'))); - __WSAFDIsSet := GetProcAddress(LibHandle, PAnsiChar(AnsiString('__WSAFDIsSet'))); - CloseSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('closesocket'))); - IoctlSocket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ioctlsocket'))); - WSAGetLastError := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAGetLastError'))); - WSAStartup := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSAStartup'))); - WSACleanup := GetProcAddress(LibHandle, PAnsiChar(AnsiString('WSACleanup'))); - ssAccept := GetProcAddress(LibHandle, PAnsiChar(AnsiString('accept'))); - ssBind := GetProcAddress(LibHandle, PAnsiChar(AnsiString('bind'))); - ssConnect := GetProcAddress(LibHandle, PAnsiChar(AnsiString('connect'))); - ssGetPeerName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getpeername'))); - ssGetSockName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockname'))); - GetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getsockopt'))); - Htonl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('htonl'))); - Htons := GetProcAddress(LibHandle, PAnsiChar(AnsiString('htons'))); - Inet_Addr := GetProcAddress(LibHandle, PAnsiChar(AnsiString('inet_addr'))); - Inet_Ntoa := GetProcAddress(LibHandle, PAnsiChar(AnsiString('inet_ntoa'))); - Listen := GetProcAddress(LibHandle, PAnsiChar(AnsiString('listen'))); - Ntohl := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ntohl'))); - Ntohs := GetProcAddress(LibHandle, PAnsiChar(AnsiString('ntohs'))); - ssRecv := GetProcAddress(LibHandle, PAnsiChar(AnsiString('recv'))); - ssRecvFrom := GetProcAddress(LibHandle, PAnsiChar(AnsiString('recvfrom'))); - Select := GetProcAddress(LibHandle, PAnsiChar(AnsiString('select'))); - ssSend := GetProcAddress(LibHandle, PAnsiChar(AnsiString('send'))); - ssSendTo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('sendto'))); - SetSockOpt := GetProcAddress(LibHandle, PAnsiChar(AnsiString('setsockopt'))); - ShutDown := GetProcAddress(LibHandle, PAnsiChar(AnsiString('shutdown'))); - Socket := GetProcAddress(LibHandle, PAnsiChar(AnsiString('socket'))); - GetHostByAddr := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostbyaddr'))); - GetHostByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostbyname'))); - GetProtoByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getprotobyname'))); - GetProtoByNumber := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getprotobynumber'))); - GetServByName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getservbyname'))); - GetServByPort := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getservbyport'))); - ssGetHostName := GetProcAddress(LibHandle, PAnsiChar(AnsiString('gethostname'))); - -{$IFNDEF FORCEOLDAPI} - GetAddrInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getaddrinfo'))); - FreeAddrInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('freeaddrinfo'))); - GetNameInfo := GetProcAddress(LibHandle, PAnsiChar(AnsiString('getnameinfo'))); - SockEnhancedApi := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) - and Assigned(GetNameInfo); - if not SockEnhancedApi then - begin - LibWship6Handle := LoadLibrary(PChar(DLLWship6)); - if LibWship6Handle <> 0 then - begin - GetAddrInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('getaddrinfo'))); - FreeAddrInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('freeaddrinfo'))); - GetNameInfo := GetProcAddress(LibWship6Handle, PAnsiChar(AnsiString('getnameinfo'))); - SockWship6Api := Assigned(GetAddrInfo) and Assigned(FreeAddrInfo) - and Assigned(GetNameInfo); - end; - end; -{$ENDIF} - Result := True; - end; - end - else Result := True; - if Result then - Inc(SynSockCount); - finally - SynSockCS.Leave; - end; -end; - -function DestroySocketInterface: Boolean; -begin - SynSockCS.Enter; - try - Dec(SynSockCount); - if SynSockCount < 0 then - SynSockCount := 0; - if SynSockCount = 0 then - begin - if LibHandle <> 0 then - begin - FreeLibrary(libHandle); - LibHandle := 0; - end; - if LibWship6Handle <> 0 then - begin - FreeLibrary(LibWship6Handle); - LibWship6Handle := 0; - end; - end; - finally - SynSockCS.Leave; - end; - Result := True; -end; - -initialization -begin - SynSockCS := SyncObjs.TCriticalSection.Create; - SET_IN6_IF_ADDR_ANY (@in6addr_any); - SET_LOOPBACK_ADDR6 (@in6addr_loopback); -end; - -finalization -begin - SynSockCS.Free; -end; \ No newline at end of file diff --git a/3rd/synapse/source/synachar.pas b/3rd/synapse/source/synachar.pas deleted file mode 100644 index 9a9d2dd26..000000000 --- a/3rd/synapse/source/synachar.pas +++ /dev/null @@ -1,2038 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 005.002.003 | -|==============================================================================| -| Content: Charset conversion support | -|==============================================================================| -| Copyright (c)1999-2012, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(Charset conversion support) -This unit contains a routines for lot of charset conversions. - -It using built-in conversion tables or external Iconv library. Iconv is used - when needed conversion is known by Iconv library. When Iconv library is not - found or Iconv not know requested conversion, then are internal routines used - for conversion. (You can disable Iconv support from your program too!) - -Internal routines knows all major charsets for Europe or America. For East-Asian - charsets you must use Iconv library! -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synachar; - -interface - -uses -{$IFNDEF MSWINDOWS} - {$IFNDEF FPC} - Libc, - {$ENDIF} -{$ELSE} - Windows, -{$ENDIF} - SysUtils, - synautil, synacode, synaicnv; - -type - {:Type with all supported charsets.} - TMimeChar = (ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, - ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, ISO_8859_13, - ISO_8859_14, ISO_8859_15, CP1250, CP1251, CP1252, CP1253, CP1254, CP1255, - CP1256, CP1257, CP1258, KOI8_R, CP895, CP852, UCS_2, UCS_4, UTF_8, UTF_7, - UTF_7mod, UCS_2LE, UCS_4LE, - //next is supported by Iconv only... - UTF_16, UTF_16LE, UTF_32, UTF_32LE, C99, JAVA, ISO_8859_16, KOI8_U, KOI8_RU, - CP862, CP866, MAC, MACCE, MACICE, MACCRO, MACRO, MACCYR, MACUK, MACGR, MACTU, - MACHEB, MACAR, MACTH, ROMAN8, NEXTSTEP, ARMASCII, GEORGIAN_AC, GEORGIAN_PS, - KOI8_T, MULELAO, CP1133, TIS620, CP874, VISCII, TCVN, ISO_IR_14, JIS_X0201, - JIS_X0208, JIS_X0212, GB1988_80, GB2312_80, ISO_IR_165, ISO_IR_149, EUC_JP, - SHIFT_JIS, CP932, ISO_2022_JP, ISO_2022_JP1, ISO_2022_JP2, GB2312, CP936, - GB18030, ISO_2022_CN, ISO_2022_CNE, HZ, EUC_TW, BIG5, CP950, BIG5_HKSCS, - EUC_KR, CP949, CP1361, ISO_2022_KR, CP737, CP775, CP853, CP855, CP857, - CP858, CP860, CP861, CP863, CP864, CP865, CP869, CP1125); - - {:Set of any charsets.} - TMimeSetChar = set of TMimeChar; - -const - {:Set of charsets supported by Iconv library only.} - IconvOnlyChars: set of TMimeChar = [UTF_16, UTF_16LE, UTF_32, UTF_32LE, - C99, JAVA, ISO_8859_16, KOI8_U, KOI8_RU, CP862, CP866, MAC, MACCE, MACICE, - MACCRO, MACRO, MACCYR, MACUK, MACGR, MACTU, MACHEB, MACAR, MACTH, ROMAN8, - NEXTSTEP, ARMASCII, GEORGIAN_AC, GEORGIAN_PS, KOI8_T, MULELAO, CP1133, - TIS620, CP874, VISCII, TCVN, ISO_IR_14, JIS_X0201, JIS_X0208, JIS_X0212, - GB1988_80, GB2312_80, ISO_IR_165, ISO_IR_149, EUC_JP, SHIFT_JIS, CP932, - ISO_2022_JP, ISO_2022_JP1, ISO_2022_JP2, GB2312, CP936, GB18030, - ISO_2022_CN, ISO_2022_CNE, HZ, EUC_TW, BIG5, CP950, BIG5_HKSCS, EUC_KR, - CP949, CP1361, ISO_2022_KR, CP737, CP775, CP853, CP855, CP857, CP858, - CP860, CP861, CP863, CP864, CP865, CP869, CP1125]; - - {:Set of charsets supported by internal routines only.} - NoIconvChars: set of TMimeChar = [CP895, UTF_7mod]; - - {:null character replace table. (Usable for disable charater replacing.)} - Replace_None: array[0..0] of Word = - (0); - - {:Character replace table for remove Czech diakritics.} - Replace_Czech: array[0..59] of Word = - ( - $00E1, $0061, - $010D, $0063, - $010F, $0064, - $010E, $0044, - $00E9, $0065, - $011B, $0065, - $00ED, $0069, - $0148, $006E, - $00F3, $006F, - $0159, $0072, - $0161, $0073, - $0165, $0074, - $00FA, $0075, - $016F, $0075, - $00FD, $0079, - $017E, $007A, - $00C1, $0041, - $010C, $0043, - $00C9, $0045, - $011A, $0045, - $00CD, $0049, - $0147, $004E, - $00D3, $004F, - $0158, $0052, - $0160, $0053, - $0164, $0054, - $00DA, $0055, - $016E, $0055, - $00DD, $0059, - $017D, $005A - ); - -var - {:By this you can generally disable/enable Iconv support.} - DisableIconv: Boolean = False; - - {:Default set of charsets for @link(IdealCharsetCoding) function.} - IdealCharsets: TMimeSetChar = - [ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, - ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, - KOI8_R, KOI8_U - {$IFNDEF CIL} //error URW778 ??? :-O - , GB2312, EUC_KR, ISO_2022_JP, EUC_TW - {$ENDIF} - ]; - -{==============================================================================} -{:Convert Value from one charset to another. See: @link(CharsetConversionEx)} -function CharsetConversion(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar): AnsiString; - -{:Convert Value from one charset to another with additional character conversion. -see: @link(Replace_None) and @link(Replace_Czech)} -function CharsetConversionEx(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word): AnsiString; - -{:Convert Value from one charset to another with additional character conversion. - This funtion is similar to @link(CharsetConversionEx), but you can disable - transliteration of unconvertible characters.} -function CharsetConversionTrans(Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word; Translit: Boolean): AnsiString; - -{:Returns charset used by operating system.} -function GetCurCP: TMimeChar; - -{:Returns charset used by operating system as OEM charset. (in Windows DOS box, - for example)} -function GetCurOEMCP: TMimeChar; - -{:Converting string with charset name to TMimeChar.} -function GetCPFromID(Value: AnsiString): TMimeChar; - -{:Converting TMimeChar to string with name of charset.} -function GetIDFromCP(Value: TMimeChar): AnsiString; - -{:return @true when value need to be converted. (It is not 7-bit ASCII)} -function NeedCharsetConversion(const Value: AnsiString): Boolean; - -{:Finding best target charset from set of TMimeChars with minimal count of - unconvertible characters.} -function IdealCharsetCoding(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeSetChar): TMimeChar; - -{:Return BOM (Byte Order Mark) for given unicode charset.} -function GetBOM(Value: TMimeChar): AnsiString; - -{:Convert binary string with unicode content to WideString.} -function StringToWide(const Value: AnsiString): WideString; - -{:Convert WideString to binary string with unicode content.} -function WideToString(const Value: WideString): AnsiString; - -function GetIconvIDFromCP(Value: TMimeChar): AnsiString; -function GetCPFromIconvID(Value: AnsiString): TMimeChar; - -{==============================================================================} -implementation - -//character transcoding tables X to UCS-2 -{ -//dummy table -$0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, -$0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, -$0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, -$0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, -$00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, -$00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, -$00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, -$00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, -$00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, -$00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, -$00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, -$00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, -$00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, -$00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, -$00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, -$00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF -} - -const - -{Latin-1 - Danish, Dutch, English, Faeroese, Finnish, French, German, Icelandic, - Irish, Italian, Norwegian, Portuguese, Spanish and Swedish. -} - CharISO_8859_1: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF - ); - -{Latin-2 - Albanian, Czech, English, German, Hungarian, Polish, Rumanian, - Serbo-Croatian, Slovak, Slovene and Swedish. -} - CharISO_8859_2: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $02D8, $0141, $00A4, $013D, $015A, $00A7, - $00A8, $0160, $015E, $0164, $0179, $00AD, $017D, $017B, - $00B0, $0105, $02DB, $0142, $00B4, $013E, $015B, $02C7, - $00B8, $0161, $015F, $0165, $017A, $02DD, $017E, $017C, - $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, - $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, - $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7, - $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF, - $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7, - $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F, - $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7, - $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9 - ); - -{Latin-3 - Afrikaans, Catalan, English, Esperanto, French, Galician, - German, Italian, Maltese and Turkish. -} - CharISO_8859_3: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0126, $02D8, $00A3, $00A4, $FFFD, $0124, $00A7, - $00A8, $0130, $015E, $011E, $0134, $00AD, $FFFD, $017B, - $00B0, $0127, $00B2, $00B3, $00B4, $00B5, $0125, $00B7, - $00B8, $0131, $015F, $011F, $0135, $00BD, $FFFD, $017C, - $00C0, $00C1, $00C2, $FFFD, $00C4, $010A, $0108, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $FFFD, $00D1, $00D2, $00D3, $00D4, $0120, $00D6, $00D7, - $011C, $00D9, $00DA, $00DB, $00DC, $016C, $015C, $00DF, - $00E0, $00E1, $00E2, $FFFD, $00E4, $010B, $0109, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $FFFD, $00F1, $00F2, $00F3, $00F4, $0121, $00F6, $00F7, - $011D, $00F9, $00FA, $00FB, $00FC, $016D, $015D, $02D9 - ); - -{Latin-4 - Danish, English, Estonian, Finnish, German, Greenlandic, - Lappish, Latvian, Lithuanian, Norwegian and Swedish. -} - CharISO_8859_4: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $0138, $0156, $00A4, $0128, $013B, $00A7, - $00A8, $0160, $0112, $0122, $0166, $00AD, $017D, $00AF, - $00B0, $0105, $02DB, $0157, $00B4, $0129, $013C, $02C7, - $00B8, $0161, $0113, $0123, $0167, $014A, $017E, $014B, - $0100, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $012E, - $010C, $00C9, $0118, $00CB, $0116, $00CD, $00CE, $012A, - $0110, $0145, $014C, $0136, $00D4, $00D5, $00D6, $00D7, - $00D8, $0172, $00DA, $00DB, $00DC, $0168, $016A, $00DF, - $0101, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $012F, - $010D, $00E9, $0119, $00EB, $0117, $00ED, $00EE, $012B, - $0111, $0146, $014D, $0137, $00F4, $00F5, $00F6, $00F7, - $00F8, $0173, $00FA, $00FB, $00FC, $0169, $016B, $02D9 - ); - -{CYRILLIC - Bulgarian, Bielorussian, English, Macedonian, Russian, - Serbo-Croatian and Ukrainian. -} - CharISO_8859_5: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0401, $0402, $0403, $0404, $0405, $0406, $0407, - $0408, $0409, $040A, $040B, $040C, $00AD, $040E, $040F, - $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417, - $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, - $0420, $0421, $0422, $0423, $0424, $0425, $0426, $0427, - $0428, $0429, $042A, $042B, $042C, $042D, $042E, $042F, - $0430, $0431, $0432, $0433, $0434, $0435, $0436, $0437, - $0438, $0439, $043A, $043B, $043C, $043D, $043E, $043F, - $0440, $0441, $0442, $0443, $0444, $0445, $0446, $0447, - $0448, $0449, $044A, $044B, $044C, $044D, $044E, $044F, - $2116, $0451, $0452, $0453, $0454, $0455, $0456, $0457, - $0458, $0459, $045A, $045B, $045C, $00A7, $045E, $045F - ); - -{ARABIC -} - CharISO_8859_6: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $FFFD, $FFFD, $FFFD, $00A4, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $060C, $00AD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $061B, $FFFD, $FFFD, $FFFD, $061F, - $FFFD, $0621, $0622, $0623, $0624, $0625, $0626, $0627, - $0628, $0629, $062A, $062B, $062C, $062D, $062E, $062F, - $0630, $0631, $0632, $0633, $0634, $0635, $0636, $0637, - $0638, $0639, $063A, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $0640, $0641, $0642, $0643, $0644, $0645, $0646, $0647, - $0648, $0649, $064A, $064B, $064C, $064D, $064E, $064F, - $0650, $0651, $0652, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD - ); - -{GREEK -} - CharISO_8859_7: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $2018, $2019, $00A3, $FFFD, $FFFD, $00A6, $00A7, - $00A8, $00A9, $FFFD, $00AB, $00AC, $00AD, $FFFD, $2015, - $00B0, $00B1, $00B2, $00B3, $0384, $0385, $0386, $00B7, - $0388, $0389, $038A, $00BB, $038C, $00BD, $038E, $038F, - $0390, $0391, $0392, $0393, $0394, $0395, $0396, $0397, - $0398, $0399, $039A, $039B, $039C, $039D, $039E, $039F, - $03A0, $03A1, $FFFD, $03A3, $03A4, $03A5, $03A6, $03A7, - $03A8, $03A9, $03AA, $03AB, $03AC, $03AD, $03AE, $03AF, - $03B0, $03B1, $03B2, $03B3, $03B4, $03B5, $03B6, $03B7, - $03B8, $03B9, $03BA, $03BB, $03BC, $03BD, $03BE, $03BF, - $03C0, $03C1, $03C2, $03C3, $03C4, $03C5, $03C6, $03C7, - $03C8, $03C9, $03CA, $03CB, $03CC, $03CD, $03CE, $FFFD - ); - -{HEBREW -} - CharISO_8859_8: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $FFFD, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00D7, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00F7, $00BB, $00BC, $00BD, $00BE, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $2017, - $05D0, $05D1, $05D2, $05D3, $05D4, $05D5, $05D6, $05D7, - $05D8, $05D9, $05DA, $05DB, $05DC, $05DD, $05DE, $05DF, - $05E0, $05E1, $05E2, $05E3, $05E4, $05E5, $05E6, $05E7, - $05E8, $05E9, $05EA, $FFFD, $FFFD, $200E, $200F, $FFFD - ); - -{Latin-5 - English, Finnish, French, German, Irish, Italian, Norwegian, - Portuguese, Spanish, Swedish and Turkish. -} - CharISO_8859_9: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $02D8, $0141, $00A4, $013D, $015A, $00A7, - $00A8, $0160, $015E, $0164, $0179, $00AD, $017D, $017B, - $00B0, $0105, $02DB, $0142, $00B4, $013E, $015B, $02C7, - $00B8, $0161, $015F, $0165, $017A, $02DD, $017E, $017C, - $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, - $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, - $011E, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $0130, $015E, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $011F, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $0131, $015F, $00FF - ); - -{Latin-6 - Danish, English, Estonian, Faeroese, Finnish, German, Greenlandic, - Icelandic, Lappish, Latvian, Lithuanian, Norwegian and Swedish. -} - CharISO_8859_10: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $0104, $0112, $0122, $012A, $0128, $0136, $00A7, - $013B, $0110, $0160, $0166, $017D, $00AD, $016A, $014A, - $00B0, $0105, $0113, $0123, $012B, $0129, $0137, $00B7, - $013C, $0111, $0161, $0167, $017E, $2015, $016B, $014B, - $0100, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $012E, - $010C, $00C9, $0118, $00CB, $0116, $00CD, $00CE, $00CF, - $00D0, $0145, $014C, $00D3, $00D4, $00D5, $00D6, $0168, - $00D8, $0172, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $0101, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $012F, - $010D, $00E9, $0119, $00EB, $0117, $00ED, $00EE, $00EF, - $00F0, $0146, $014D, $00F3, $00F4, $00F5, $00F6, $0169, - $00F8, $0173, $00FA, $00FB, $00FC, $00FD, $00FE, $0138 - ); - - CharISO_8859_13: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $201D, $00A2, $00A3, $00A4, $201E, $00A6, $00A7, - $00D8, $00A9, $0156, $00AB, $00AC, $00AD, $00AE, $00C6, - $00B0, $00B1, $00B2, $00B3, $201C, $00B5, $00B6, $00B7, - $00F8, $00B9, $0157, $00BB, $00BC, $00BD, $00BE, $00E6, - $0104, $012E, $0100, $0106, $00C4, $00C5, $0118, $0112, - $010C, $00C9, $0179, $0116, $0122, $0136, $012A, $013B, - $0160, $0143, $0145, $00D3, $014C, $00D5, $00D6, $00D7, - $0172, $0141, $015A, $016A, $00DC, $017B, $017D, $00DF, - $0105, $012F, $0101, $0107, $00E4, $00E5, $0119, $0113, - $010D, $00E9, $017A, $0117, $0123, $0137, $012B, $013C, - $0161, $0144, $0146, $00F3, $014D, $00F5, $00F6, $00F7, - $0173, $0142, $015B, $016B, $00FC, $017C, $017E, $2019 - ); - - CharISO_8859_14: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $1E02, $1E03, $00A3, $010A, $010B, $1E0A, $00A7, - $1E80, $00A9, $1E82, $1E0B, $1EF2, $00AD, $00AE, $0178, - $1E1E, $1E1F, $0120, $0121, $1E40, $1E41, $00B6, $1E56, - $1E81, $1E57, $1E83, $1E60, $1EF3, $1E84, $1E85, $1E61, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $0174, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $1E6A, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $0176, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $0175, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $1E6B, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $0177, $00FF - ); - - CharISO_8859_15: array[128..255] of Word = - ( - $0080, $0081, $0082, $0083, $0084, $0085, $0086, $0087, - $0088, $0089, $008A, $008B, $008C, $008D, $008E, $008F, - $0090, $0091, $0092, $0093, $0094, $0095, $0096, $0097, - $0098, $0099, $009A, $009B, $009C, $009D, $009E, $009F, - $00A0, $00A1, $00A2, $00A3, $20AC, $00A5, $0160, $00A7, - $0161, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $017D, $00B5, $00B6, $00B7, - $017E, $00B9, $00BA, $00BB, $0152, $0153, $0178, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF - ); - -{Eastern European -} - CharCP_1250: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $FFFD, $201E, $2026, $2020, $2021, - $FFFD, $2030, $0160, $2039, $015A, $0164, $017D, $0179, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $0161, $203A, $015B, $0165, $017E, $017A, - $00A0, $02C7, $02D8, $0141, $00A4, $0104, $00A6, $00A7, - $00A8, $00A9, $015E, $00AB, $00AC, $00AD, $00AE, $017B, - $00B0, $00B1, $02DB, $0142, $00B4, $00B5, $00B6, $00B7, - $00B8, $0105, $015F, $00BB, $013D, $02DD, $013E, $017C, - $0154, $00C1, $00C2, $0102, $00C4, $0139, $0106, $00C7, - $010C, $00C9, $0118, $00CB, $011A, $00CD, $00CE, $010E, - $0110, $0143, $0147, $00D3, $00D4, $0150, $00D6, $00D7, - $0158, $016E, $00DA, $0170, $00DC, $00DD, $0162, $00DF, - $0155, $00E1, $00E2, $0103, $00E4, $013A, $0107, $00E7, - $010D, $00E9, $0119, $00EB, $011B, $00ED, $00EE, $010F, - $0111, $0144, $0148, $00F3, $00F4, $0151, $00F6, $00F7, - $0159, $016F, $00FA, $0171, $00FC, $00FD, $0163, $02D9 - ); - -{Cyrillic -} - CharCP_1251: array[128..255] of Word = - ( - $0402, $0403, $201A, $0453, $201E, $2026, $2020, $2021, - $20AC, $2030, $0409, $2039, $040A, $040C, $040B, $040F, - $0452, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $0459, $203A, $045A, $045C, $045B, $045F, - $00A0, $040E, $045E, $0408, $00A4, $0490, $00A6, $00A7, - $0401, $00A9, $0404, $00AB, $00AC, $00AD, $00AE, $0407, - $00B0, $00B1, $0406, $0456, $0491, $00B5, $00B6, $00B7, - $0451, $2116, $0454, $00BB, $0458, $0405, $0455, $0457, - $0410, $0411, $0412, $0413, $0414, $0415, $0416, $0417, - $0418, $0419, $041A, $041B, $041C, $041D, $041E, $041F, - $0420, $0421, $0422, $0423, $0424, $0425, $0426, $0427, - $0428, $0429, $042A, $042B, $042C, $042D, $042E, $042F, - $0430, $0431, $0432, $0433, $0434, $0435, $0436, $0437, - $0438, $0439, $043A, $043B, $043C, $043D, $043E, $043F, - $0440, $0441, $0442, $0443, $0444, $0445, $0446, $0447, - $0448, $0449, $044A, $044B, $044C, $044D, $044E, $044F - ); - -{Latin-1 (US, Western Europe) -} - CharCP_1252: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $0160, $2039, $0152, $FFFD, $017D, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $0161, $203A, $0153, $FFFD, $017E, $0178, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $00D0, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $00DD, $00DE, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $00F0, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $00FD, $00FE, $00FF - ); - -{Greek -} - CharCP_1253: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $FFFD, $2030, $FFFD, $2039, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $FFFD, $203A, $FFFD, $FFFD, $FFFD, $FFFD, - $00A0, $0385, $0386, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $FFFD, $00AB, $00AC, $00AD, $00AE, $2015, - $00B0, $00B1, $00B2, $00B3, $0384, $00B5, $00B6, $00B7, - $0388, $0389, $038A, $00BB, $038C, $00BD, $038E, $038F, - $0390, $0391, $0392, $0393, $0394, $0395, $0396, $0397, - $0398, $0399, $039A, $039B, $039C, $039D, $039E, $039F, - $03A0, $03A1, $FFFD, $03A3, $03A4, $03A5, $03A6, $03A7, - $03A8, $03A9, $03AA, $03AB, $03AC, $03AD, $03AE, $03AF, - $03B0, $03B1, $03B2, $03B3, $03B4, $03B5, $03B6, $03B7, - $03B8, $03B9, $03BA, $03BB, $03BC, $03BD, $03BE, $03BF, - $03C0, $03C1, $03C2, $03C3, $03C4, $03C5, $03C6, $03C7, - $03C8, $03C9, $03CA, $03CB, $03CC, $03CD, $03CE, $FFFD - ); - -{Turkish -} - CharCP_1254: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $0160, $2039, $0152, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $0161, $203A, $0153, $FFFD, $FFFD, $0178, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $00C3, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $00CC, $00CD, $00CE, $00CF, - $011E, $00D1, $00D2, $00D3, $00D4, $00D5, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $0130, $015E, $00DF, - $00E0, $00E1, $00E2, $00E3, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $00EC, $00ED, $00EE, $00EF, - $011F, $00F1, $00F2, $00F3, $00F4, $00F5, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $0131, $015F, $00FF - ); - -{Hebrew -} - CharCP_1255: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $FFFD, $2039, $FFFD, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $FFFD, $203A, $FFFD, $FFFD, $FFFD, $FFFD, - $00A0, $00A1, $00A2, $00A3, $20AA, $00A5, $00A6, $00A7, - $00A8, $00A9, $00D7, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00F7, $00BB, $00BC, $00BD, $00BE, $00BF, - $05B0, $05B1, $05B2, $05B3, $05B4, $05B5, $05B6, $05B7, - $05B8, $05B9, $FFFD, $05BB, $05BC, $05BD, $05BE, $05BF, - $05C0, $05C1, $05C2, $05C3, $05F0, $05F1, $05F2, $05F3, - $05F4, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, $FFFD, - $05D0, $05D1, $05D2, $05D3, $05D4, $05D5, $05D6, $05D7, - $05D8, $05D9, $05DA, $05DB, $05DC, $05DD, $05DE, $05DF, - $05E0, $05E1, $05E2, $05E3, $05E4, $05E5, $05E6, $05E7, - $05E8, $05E9, $05EA, $FFFD, $FFFD, $200E, $200F, $FFFD - ); - -{Arabic -} - CharCP_1256: array[128..255] of Word = - ( - $20AC, $067E, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $0679, $2039, $0152, $0686, $0698, $0688, - $06AF, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $06A9, $2122, $0691, $203A, $0153, $200C, $200D, $06BA, - $00A0, $060C, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $06BE, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $061B, $00BB, $00BC, $00BD, $00BE, $061F, - $06C1, $0621, $0622, $0623, $0624, $0625, $0626, $0627, - $0628, $0629, $062A, $062B, $062C, $062D, $062E, $062F, - $0630, $0631, $0632, $0633, $0634, $0635, $0636, $00D7, - $0637, $0638, $0639, $063A, $0640, $0641, $0642, $0643, - $00E0, $0644, $00E2, $0645, $0646, $0647, $0648, $00E7, - $00E8, $00E9, $00EA, $00EB, $0649, $064A, $00EE, $00EF, - $064B, $064C, $064D, $064E, $00F4, $064F, $0650, $00F7, - $0651, $00F9, $0652, $00FB, $00FC, $200E, $200F, $06D2 - ); - -{Baltic -} - CharCP_1257: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $FFFD, $201E, $2026, $2020, $2021, - $FFFD, $2030, $FFFD, $2039, $FFFD, $00A8, $02C7, $00B8, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $FFFD, $2122, $FFFD, $203A, $FFFD, $00AF, $02DB, $FFFD, - $00A0, $FFFD, $00A2, $00A3, $00A4, $FFFD, $00A6, $00A7, - $00D8, $00A9, $0156, $00AB, $00AC, $00AD, $00AE, $00C6, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00F8, $00B9, $0157, $00BB, $00BC, $00BD, $00BE, $00E6, - $0104, $012E, $0100, $0106, $00C4, $00C5, $0118, $0112, - $010C, $00C9, $0179, $0116, $0122, $0136, $012A, $013B, - $0160, $0143, $0145, $00D3, $014C, $00D5, $00D6, $00D7, - $0172, $0141, $015A, $016A, $00DC, $017B, $017D, $00DF, - $0105, $012F, $0101, $0107, $00E4, $00E5, $0119, $0113, - $010D, $00E9, $017A, $0117, $0123, $0137, $012B, $013C, - $0161, $0144, $0146, $00F3, $014D, $00F5, $00F6, $00F7, - $0173, $0142, $015B, $016B, $00FC, $017C, $017E, $02D9 - ); - -{Vietnamese -} - CharCP_1258: array[128..255] of Word = - ( - $20AC, $FFFD, $201A, $0192, $201E, $2026, $2020, $2021, - $02C6, $2030, $FFFD, $2039, $0152, $FFFD, $FFFD, $FFFD, - $FFFD, $2018, $2019, $201C, $201D, $2022, $2013, $2014, - $02DC, $2122, $FFFD, $203A, $0153, $FFFD, $FFFD, $0178, - $00A0, $00A1, $00A2, $00A3, $00A4, $00A5, $00A6, $00A7, - $00A8, $00A9, $00AA, $00AB, $00AC, $00AD, $00AE, $00AF, - $00B0, $00B1, $00B2, $00B3, $00B4, $00B5, $00B6, $00B7, - $00B8, $00B9, $00BA, $00BB, $00BC, $00BD, $00BE, $00BF, - $00C0, $00C1, $00C2, $0102, $00C4, $00C5, $00C6, $00C7, - $00C8, $00C9, $00CA, $00CB, $0300, $00CD, $00CE, $00CF, - $0110, $00D1, $0309, $00D3, $00D4, $01A0, $00D6, $00D7, - $00D8, $00D9, $00DA, $00DB, $00DC, $01AF, $0303, $00DF, - $00E0, $00E1, $00E2, $0103, $00E4, $00E5, $00E6, $00E7, - $00E8, $00E9, $00EA, $00EB, $0301, $00ED, $00EE, $00EF, - $0111, $00F1, $0323, $00F3, $00F4, $01A1, $00F6, $00F7, - $00F8, $00F9, $00FA, $00FB, $00FC, $01B0, $20AB, $00FF - ); - -{Cyrillic -} - CharKOI8_R: array[128..255] of Word = - ( - $2500, $2502, $250C, $2510, $2514, $2518, $251C, $2524, - $252C, $2534, $253C, $2580, $2584, $2588, $258C, $2590, - $2591, $2592, $2593, $2320, $25A0, $2219, $221A, $2248, - $2264, $2265, $00A0, $2321, $00B0, $00B2, $00B7, $00F7, - $2550, $2551, $2552, $0451, $2553, $2554, $2555, $2556, - $2557, $2558, $2559, $255A, $255B, $255C, $255D, $255E, - $255F, $2560, $2561, $0401, $2562, $2563, $2564, $2565, - $2566, $2567, $2568, $2569, $256A, $256B, $256C, $00A9, - $044E, $0430, $0431, $0446, $0434, $0435, $0444, $0433, - $0445, $0438, $0439, $043A, $043B, $043C, $043D, $043E, - $043F, $044F, $0440, $0441, $0442, $0443, $0436, $0432, - $044C, $044B, $0437, $0448, $044D, $0449, $0447, $044A, - $042E, $0410, $0411, $0426, $0414, $0415, $0424, $0413, - $0425, $0418, $0419, $041A, $041B, $041C, $041D, $041E, - $041F, $042F, $0420, $0421, $0422, $0423, $0416, $0412, - $042C, $042B, $0417, $0428, $042D, $0429, $0427, $042A - ); - -{Czech (Kamenicky) -} - CharCP_895: array[128..255] of Word = - ( - $010C, $00FC, $00E9, $010F, $00E4, $010E, $0164, $010D, - $011B, $011A, $0139, $00CD, $013E, $013A, $00C4, $00C1, - $00C9, $017E, $017D, $00F4, $00F6, $00D3, $016F, $00DA, - $00FD, $00D6, $00DC, $0160, $013D, $00DD, $0158, $0165, - $00E1, $00ED, $00F3, $00FA, $0148, $0147, $016E, $00D4, - $0161, $0159, $0155, $0154, $00BC, $00A7, $00AB, $00BB, - $2591, $2592, $2593, $2502, $2524, $2561, $2562, $2556, - $2555, $2563, $2551, $2557, $255D, $255C, $255B, $2510, - $2514, $2534, $252C, $251C, $2500, $253C, $255E, $255F, - $255A, $2554, $2569, $2566, $2560, $2550, $256C, $2567, - $2568, $2564, $2565, $2559, $2558, $2552, $2553, $256B, - $256A, $2518, $250C, $2588, $2584, $258C, $2590, $2580, - $03B1, $03B2, $0393, $03C0, $03A3, $03C3, $03BC, $03C4, - $03A6, $0398, $03A9, $03B4, $221E, $2205, $03B5, $2229, - $2261, $00B1, $2265, $2264, $2320, $2321, $00F7, $2248, - $2218, $00B7, $2219, $221A, $207F, $00B2, $25A0, $00A0 - ); - -{Eastern European -} - CharCP_852: array[128..255] of Word = - ( - $00C7, $00FC, $00E9, $00E2, $00E4, $016F, $0107, $00E7, - $0142, $00EB, $0150, $0151, $00EE, $0179, $00C4, $0106, - $00C9, $0139, $013A, $00F4, $00F6, $013D, $013E, $015A, - $015B, $00D6, $00DC, $0164, $0165, $0141, $00D7, $010D, - $00E1, $00ED, $00F3, $00FA, $0104, $0105, $017D, $017E, - $0118, $0119, $00AC, $017A, $010C, $015F, $00AB, $00BB, - $2591, $2592, $2593, $2502, $2524, $00C1, $00C2, $011A, - $015E, $2563, $2551, $2557, $255D, $017B, $017C, $2510, - $2514, $2534, $252C, $251C, $2500, $253C, $0102, $0103, - $255A, $2554, $2569, $2566, $2560, $2550, $256C, $00A4, - $0111, $0110, $010E, $00CB, $010F, $0147, $00CD, $00CE, - $011B, $2518, $250C, $2588, $2584, $0162, $016E, $2580, - $00D3, $00DF, $00D4, $0143, $0144, $0148, $0160, $0161, - $0154, $00DA, $0155, $0170, $00FD, $00DD, $0163, $00B4, - $00AD, $02DD, $02DB, $02C7, $02D8, $00A7, $00F7, $00B8, - $00B0, $00A8, $02D9, $0171, $0158, $0159, $25A0, $00A0 - ); - -{==============================================================================} -type - TIconvChar = record - Charset: TMimeChar; - CharName: string; - end; - TIconvArr = array [0..112] of TIconvChar; - -const - NotFoundChar = '_'; - -var - SetTwo: set of TMimeChar = [UCS_2, UCS_2LE, UTF_7, UTF_7mod]; - SetFour: set of TMimeChar = [UCS_4, UCS_4LE, UTF_8]; - SetLE: set of TMimeChar = [UCS_2LE, UCS_4LE]; - - IconvArr: TIconvArr; - -{==============================================================================} -function FindIconvID(const Value, Charname: string): Boolean; -var - s: string; -begin - Result := True; - //exact match - if Value = Charname then - Exit; - //Value is on begin of charname - s := Value + ' '; - if s = Copy(Charname, 1, Length(s)) then - Exit; - //Value is on end of charname - s := ' ' + Value; - if s = Copy(Charname, Length(Charname) - Length(s) + 1, Length(s)) then - Exit; - //value is somewhere inside charname - if Pos( s + ' ', Charname) > 0 then - Exit; - Result := False; -end; - -function GetCPFromIconvID(Value: AnsiString): TMimeChar; -var - n: integer; -begin - Result := ISO_8859_1; - Value := UpperCase(Value); - for n := 0 to High(IconvArr) do - if FindIconvID(Value, IconvArr[n].Charname) then - begin - Result := IconvArr[n].Charset; - Break; - end; -end; - -{==============================================================================} -function GetIconvIDFromCP(Value: TMimeChar): AnsiString; -var - n: integer; -begin - Result := 'ISO-8859-1'; - for n := 0 to High(IconvArr) do - if IconvArr[n].Charset = Value then - begin - Result := Separateleft(IconvArr[n].Charname, ' '); - Break; - end; -end; - -{==============================================================================} -function ReplaceUnicode(Value: Word; const TransformTable: array of Word): Word; -var - n: integer; -begin - if High(TransformTable) <> 0 then - for n := 0 to High(TransformTable) do - if not odd(n) then - if TransformTable[n] = Value then - begin - Value := TransformTable[n+1]; - break; - end; - Result := Value; -end; - -{==============================================================================} -procedure CopyArray(const SourceTable: array of Word; - var TargetTable: array of Word); -var - n: Integer; -begin - for n := 0 to 127 do - TargetTable[n] := SourceTable[n]; -end; - -{==============================================================================} -procedure GetArray(CharSet: TMimeChar; var Result: array of Word); -begin - case CharSet of - ISO_8859_2: - CopyArray(CharISO_8859_2, Result); - ISO_8859_3: - CopyArray(CharISO_8859_3, Result); - ISO_8859_4: - CopyArray(CharISO_8859_4, Result); - ISO_8859_5: - CopyArray(CharISO_8859_5, Result); - ISO_8859_6: - CopyArray(CharISO_8859_6, Result); - ISO_8859_7: - CopyArray(CharISO_8859_7, Result); - ISO_8859_8: - CopyArray(CharISO_8859_8, Result); - ISO_8859_9: - CopyArray(CharISO_8859_9, Result); - ISO_8859_10: - CopyArray(CharISO_8859_10, Result); - ISO_8859_13: - CopyArray(CharISO_8859_13, Result); - ISO_8859_14: - CopyArray(CharISO_8859_14, Result); - ISO_8859_15: - CopyArray(CharISO_8859_15, Result); - CP1250: - CopyArray(CharCP_1250, Result); - CP1251: - CopyArray(CharCP_1251, Result); - CP1252: - CopyArray(CharCP_1252, Result); - CP1253: - CopyArray(CharCP_1253, Result); - CP1254: - CopyArray(CharCP_1254, Result); - CP1255: - CopyArray(CharCP_1255, Result); - CP1256: - CopyArray(CharCP_1256, Result); - CP1257: - CopyArray(CharCP_1257, Result); - CP1258: - CopyArray(CharCP_1258, Result); - KOI8_R: - CopyArray(CharKOI8_R, Result); - CP895: - CopyArray(CharCP_895, Result); - CP852: - CopyArray(CharCP_852, Result); - else - CopyArray(CharISO_8859_1, Result); - end; -end; - -{==============================================================================} -procedure ReadMulti(const Value: AnsiString; var Index: Integer; mb: Byte; - var b1, b2, b3, b4: Byte; le: boolean); -Begin - b1 := 0; - b2 := 0; - b3 := 0; - b4 := 0; - if Index < 0 then - Index := 1; - if mb > 4 then - mb := 1; - if (Index + mb - 1) <= Length(Value) then - begin - if le then - Case mb Of - 1: - b1 := Ord(Value[Index]); - 2: - Begin - b1 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - End; - 3: - Begin - b1 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - b3 := Ord(Value[Index + 2]); - End; - 4: - Begin - b1 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - b3 := Ord(Value[Index + 2]); - b4 := Ord(Value[Index + 3]); - End; - end - else - Case mb Of - 1: - b1 := Ord(Value[Index]); - 2: - Begin - b2 := Ord(Value[Index]); - b1 := Ord(Value[Index + 1]); - End; - 3: - Begin - b3 := Ord(Value[Index]); - b2 := Ord(Value[Index + 1]); - b1 := Ord(Value[Index + 2]); - End; - 4: - Begin - b4 := Ord(Value[Index]); - b3 := Ord(Value[Index + 1]); - b2 := Ord(Value[Index + 2]); - b1 := Ord(Value[Index + 3]); - End; - end; - end; - Inc(Index, mb); -end; - -{==============================================================================} -function WriteMulti(b1, b2, b3, b4: Byte; mb: Byte; le: boolean): AnsiString; -begin - if mb > 4 then - mb := 1; - SetLength(Result, mb); - if le then - case mb Of - 1: - Result[1] := AnsiChar(b1); - 2: - begin - Result[1] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - end; - 3: - begin - Result[1] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - Result[3] := AnsiChar(b3); - end; - 4: - begin - Result[1] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - Result[3] := AnsiChar(b3); - Result[4] := AnsiChar(b4); - end; - end - else - case mb Of - 1: - Result[1] := AnsiChar(b1); - 2: - begin - Result[2] := AnsiChar(b1); - Result[1] := AnsiChar(b2); - end; - 3: - begin - Result[3] := AnsiChar(b1); - Result[2] := AnsiChar(b2); - Result[1] := AnsiChar(b3); - end; - 4: - begin - Result[4] := AnsiChar(b1); - Result[3] := AnsiChar(b2); - Result[2] := AnsiChar(b3); - Result[1] := AnsiChar(b4); - end; - end; -end; - -{==============================================================================} -function UTF8toUCS4(const Value: AnsiString): AnsiString; -var - n, x, ul, m: Integer; - s: AnsiString; - w1, w2: Word; -begin - Result := ''; - n := 1; - while Length(Value) >= n do - begin - x := Ord(Value[n]); - Inc(n); - if x < 128 then - Result := Result + WriteMulti(x, 0, 0, 0, 4, false) - else - begin - m := 0; - if (x and $E0) = $C0 then - m := $1F; - if (x and $F0) = $E0 then - m := $0F; - if (x and $F8) = $F0 then - m := $07; - if (x and $FC) = $F8 then - m := $03; - if (x and $FE) = $FC then - m := $01; - ul := x and m; - s := IntToBin(ul, 0); - while Length(Value) >= n do - begin - x := Ord(Value[n]); - Inc(n); - if (x and $C0) = $80 then - s := s + IntToBin(x and $3F, 6) - else - begin - Dec(n); - Break; - end; - end; - ul := BinToInt(s); - w1 := ul div 65536; - w2 := ul mod 65536; - Result := Result + WriteMulti(Lo(w2), Hi(w2), Lo(w1), Hi(w1), 4, false); - end; - end; -end; - -{==============================================================================} -function UCS4toUTF8(const Value: AnsiString): AnsiString; -var - s, l, k: AnsiString; - b1, b2, b3, b4: Byte; - n, m, x, y: Integer; - b: Byte; -begin - Result := ''; - n := 1; - while Length(Value) >= n do - begin - ReadMulti(Value, n, 4, b1, b2, b3, b4, false); - if (b2 = 0) and (b3 = 0) and (b4 = 0) and (b1 < 128) then - Result := Result + AnsiChar(b1) - else - begin - x := (b1 + 256 * b2) + (b3 + 256 * b4) * 65536; - l := IntToBin(x, 0); - y := Length(l) div 6; - s := ''; - for m := 1 to y do - begin - k := Copy(l, Length(l) - 5, 6); - l := Copy(l, 1, Length(l) - 6); - b := BinToInt(k) or $80; - s := AnsiChar(b) + s; - end; - b := BinToInt(l); - case y of - 5: - b := b or $FC; - 4: - b := b or $F8; - 3: - b := b or $F0; - 2: - b := b or $E0; - 1: - b := b or $C0; - end; - s := AnsiChar(b) + s; - Result := Result + s; - end; - end; -end; - -{==============================================================================} -function UTF7toUCS2(const Value: AnsiString; Modified: Boolean): AnsiString; -var - n, i: Integer; - c: AnsiChar; - s, t: AnsiString; - shift: AnsiChar; - table: String; -begin - Result := ''; - n := 1; - if modified then - begin - shift := '&'; - table := TableBase64mod; - end - else - begin - shift := '+'; - table := TableBase64; - end; - while Length(Value) >= n do - begin - c := Value[n]; - Inc(n); - if c <> shift then - Result := Result + WriteMulti(Ord(c), 0, 0, 0, 2, false) - else - begin - s := ''; - while Length(Value) >= n do - begin - c := Value[n]; - Inc(n); - if c = '-' then - Break; - if (c = '=') or (Pos(c, table) < 1) then - begin - Dec(n); - Break; - end; - s := s + c; - end; - if s = '' then - s := WriteMulti(Ord(shift), 0, 0, 0, 2, false) - else - begin - if modified then - t := DecodeBase64mod(s) - else - t := DecodeBase64(s); - if not odd(length(t)) then - s := t - else - begin //ill-formed sequence - t := s; - s := WriteMulti(Ord(shift), 0, 0, 0, 2, false); - for i := 1 to length(t) do - s := s + WriteMulti(Ord(t[i]), 0, 0, 0, 2, false); - end; - end; - Result := Result + s; - end; - end; -end; - -{==============================================================================} -function UCS2toUTF7(const Value: AnsiString; Modified: Boolean): AnsiString; -var - s: AnsiString; - b1, b2, b3, b4: Byte; - n, m: Integer; - shift: AnsiChar; -begin - Result := ''; - n := 1; - if modified then - shift := '&' - else - shift := '+'; - while Length(Value) >= n do - begin - ReadMulti(Value, n, 2, b1, b2, b3, b4, false); - if (b2 = 0) and (b1 < 128) then - if AnsiChar(b1) = shift then - Result := Result + shift + '-' - else - Result := Result + AnsiChar(b1) - else - begin - s := AnsiChar(b2) + AnsiChar(b1); - while Length(Value) >= n do - begin - ReadMulti(Value, n, 2, b1, b2, b3, b4, false); - if (b2 = 0) and (b1 < 128) then - begin - Dec(n, 2); - Break; - end; - s := s + AnsiChar(b2) + AnsiChar(b1); - end; - if modified then - s := EncodeBase64mod(s) - else - s := EncodeBase64(s); - m := Pos('=', s); - if m > 0 then - s := Copy(s, 1, m - 1); - Result := Result + shift + s + '-'; - end; - end; -end; - -{==============================================================================} -function CharsetConversion(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar): AnsiString; -begin - Result := CharsetConversionEx(Value, CharFrom, CharTo, Replace_None); -end; - -{==============================================================================} -function CharsetConversionEx(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word): AnsiString; -begin - Result := CharsetConversionTrans(Value, CharFrom, CharTo, TransformTable, True); -end; - -{==============================================================================} - -function InternalToUcs(const Value: AnsiString; Charfrom: TMimeChar): AnsiString; -var - uni: Word; - n: Integer; - b1, b2, b3, b4: Byte; - SourceTable: array[128..255] of Word; - mbf: Byte; - lef: Boolean; - s: AnsiString; -begin - if CharFrom = UTF_8 then - s := UTF8toUCS4(Value) - else - if CharFrom = UTF_7 then - s := UTF7toUCS2(Value, False) - else - if CharFrom = UTF_7mod then - s := UTF7toUCS2(Value, True) - else - s := Value; - GetArray(CharFrom, SourceTable); - mbf := 1; - if CharFrom in SetTwo then - mbf := 2; - if CharFrom in SetFour then - mbf := 4; - lef := CharFrom in SetLe; - Result := ''; - n := 1; - while Length(s) >= n do - begin - ReadMulti(s, n, mbf, b1, b2, b3, b4, lef); - //handle BOM - if (b3 = 0) and (b4 = 0) then - begin - if (b1 = $FE) and (b2 = $FF) then - begin - lef := not lef; - continue; - end; - if (b1 = $FF) and (b2 = $FE) then - continue; - end; - if mbf = 1 then - if b1 > 127 then - begin - uni := SourceTable[b1]; - b1 := Lo(uni); - b2 := Hi(uni); - end; - Result := Result + WriteMulti(b1, b2, b3, b4, 2, False); - end; -end; - -function CharsetConversionTrans(Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeChar; const TransformTable: array of Word; Translit: Boolean): AnsiString; -var - uni: Word; - n, m: Integer; - b: Byte; - b1, b2, b3, b4: Byte; - TargetTable: array[128..255] of Word; - mbt: Byte; - let: Boolean; - ucsstring, s, t: AnsiString; - cd: iconv_t; - f: Boolean; - NotNeedTransform: Boolean; - FromID, ToID: string; -begin - NotNeedTransform := (High(TransformTable) = 0); - if (CharFrom = CharTo) and NotNeedTransform then - begin - Result := Value; - Exit; - end; - FromID := GetIDFromCP(CharFrom); - ToID := GetIDFromCP(CharTo); - cd := Iconv_t(-1); - //do two-pass conversion. Transform to UCS-2 first. - if not DisableIconv then - cd := SynaIconvOpenIgnore('UCS-2BE', FromID); - try - if cd <> iconv_t(-1) then - SynaIconv(cd, Value, ucsstring) - else - ucsstring := InternalToUcs(Value, CharFrom); - finally - SynaIconvClose(cd); - end; - //here we allways have ucstring with UCS-2 encoding - //second pass... from UCS-2 to target encoding. - if not DisableIconv then - if translit then - cd := SynaIconvOpenTranslit(ToID, 'UCS-2BE') - else - cd := SynaIconvOpenIgnore(ToID, 'UCS-2BE'); - try - if (cd <> iconv_t(-1)) and NotNeedTransform then - begin - if CharTo = UTF_7 then - ucsstring := ucsstring + #0 + '-'; - //when transformtable is not needed and Iconv know target charset, - //do it fast by one call. - SynaIconv(cd, ucsstring, Result); - if CharTo = UTF_7 then - Delete(Result, Length(Result), 1); - end - else - begin - GetArray(CharTo, TargetTable); - mbt := 1; - if CharTo in SetTwo then - mbt := 2; - if CharTo in SetFour then - mbt := 4; - let := CharTo in SetLe; - b3 := 0; - b4 := 0; - Result := ''; - for n:= 0 to (Length(ucsstring) div 2) - 1 do - begin - s := Copy(ucsstring, n * 2 + 1, 2); - b2 := Ord(s[1]); - b1 := Ord(s[2]); - uni := b2 * 256 + b1; - if not NotNeedTransform then - begin - uni := ReplaceUnicode(uni, TransformTable); - b1 := Lo(uni); - b2 := Hi(uni); - s[1] := AnsiChar(b2); - s[2] := AnsiChar(b1); - end; - if cd <> iconv_t(-1) then - begin - if CharTo = UTF_7 then - s := s + #0 + '-'; - SynaIconv(cd, s, t); - if CharTo = UTF_7 then - Delete(t, Length(t), 1); - Result := Result + t; - end - else - begin - f := True; - if mbt = 1 then - if uni > 127 then - begin - f := False; - b := 0; - for m := 128 to 255 do - if TargetTable[m] = uni then - begin - b := m; - f := True; - Break; - end; - b1 := b; - b2 := 0; - end - else - b1 := Lo(uni); - if not f then - if translit then - begin - b1 := Ord(NotFoundChar); - b2 := 0; - f := True; - end; - if f then - Result := Result + WriteMulti(b1, b2, b3, b4, mbt, let) - end; - end; - if cd = iconv_t(-1) then - begin - if CharTo = UTF_7 then - Result := UCS2toUTF7(Result, false); - if CharTo = UTF_7mod then - Result := UCS2toUTF7(Result, true); - if CharTo = UTF_8 then - Result := UCS4toUTF8(Result); - end; - end; - finally - SynaIconvClose(cd); - end; -end; - -{==============================================================================} -{$IFNDEF MSWINDOWS} - -function GetCurCP: TMimeChar; -begin - {$IFNDEF FPC} - Result := GetCPFromID(nl_langinfo(_NL_CTYPE_CODESET_NAME)); - {$ELSE} - //How to get system codepage without LIBC? - Result := UTF_8; -{ TODO : Waiting for FPC 2.8 solution } - {$ENDIF} -end; - -function GetCurOEMCP: TMimeChar; -begin - Result := GetCurCP; -end; - -{$ELSE} - -function CPToMimeChar(Value: Integer): TMimeChar; -begin - case Value of - 437, 850, 20127: - Result := ISO_8859_1; //I know, it is not ideal! - 737: - Result := CP737; - 775: - Result := CP775; - 852: - Result := CP852; - 855: - Result := CP855; - 857: - Result := CP857; - 858: - Result := CP858; - 860: - Result := CP860; - 861: - Result := CP861; - 862: - Result := CP862; - 863: - Result := CP863; - 864: - Result := CP864; - 865: - Result := CP865; - 866: - Result := CP866; - 869: - Result := CP869; - 874: - Result := ISO_8859_15; - 895: - Result := CP895; - 932: - Result := CP932; - 936: - Result := CP936; - 949: - Result := CP949; - 950: - Result := CP950; - 1200: - Result := UCS_2LE; - 1201: - Result := UCS_2; - 1250: - Result := CP1250; - 1251: - Result := CP1251; - 1253: - Result := CP1253; - 1254: - Result := CP1254; - 1255: - Result := CP1255; - 1256: - Result := CP1256; - 1257: - Result := CP1257; - 1258: - Result := CP1258; - 1361: - Result := CP1361; - 10000: - Result := MAC; - 10004: - Result := MACAR; - 10005: - Result := MACHEB; - 10006: - Result := MACGR; - 10007: - Result := MACCYR; - 10010: - Result := MACRO; - 10017: - Result := MACUK; - 10021: - Result := MACTH; - 10029: - Result := MACCE; - 10079: - Result := MACICE; - 10081: - Result := MACTU; - 10082: - Result := MACCRO; - 12000: - Result := UCS_4LE; - 12001: - Result := UCS_4; - 20866: - Result := KOI8_R; - 20932: - Result := JIS_X0208; - 20936: - Result := GB2312; - 21866: - Result := KOI8_U; - 28591: - Result := ISO_8859_1; - 28592: - Result := ISO_8859_2; - 28593: - Result := ISO_8859_3; - 28594: - Result := ISO_8859_4; - 28595: - Result := ISO_8859_5; - 28596, 708: - Result := ISO_8859_6; - 28597: - Result := ISO_8859_7; - 28598, 38598: - Result := ISO_8859_8; - 28599: - Result := ISO_8859_9; - 28605: - Result := ISO_8859_15; - 50220: - Result := ISO_2022_JP; //? ISO 2022 Japanese with no halfwidth Katakana - 50221: - Result := ISO_2022_JP1;//? Japanese with halfwidth Katakana - 50222: - Result := ISO_2022_JP2;//? Japanese JIS X 0201-1989 - 50225: - Result := ISO_2022_KR; - 50227: - Result := ISO_2022_CN;//? ISO 2022 Simplified Chinese - 50229: - Result := ISO_2022_CNE;//? ISO 2022 Traditional Chinese - 51932: - Result := EUC_JP; - 51936: - Result := GB2312; - 51949: - Result := EUC_KR; - 52936: - Result := HZ; - 54936: - Result := GB18030; - 65000: - Result := UTF_7; - 65001: - Result := UTF_8; - 0: - Result := UCS_2LE; - else - Result := CP1252; - end; -end; - -function GetCurCP: TMimeChar; -begin - Result := CPToMimeChar(GetACP); -end; - -function GetCurOEMCP: TMimeChar; -begin - Result := CPToMimeChar(GetOEMCP); -end; -{$ENDIF} - -{==============================================================================} -function NeedCharsetConversion(const Value: AnsiString): Boolean; -var - n: Integer; -begin - Result := False; - for n := 1 to Length(Value) do - if (Ord(Value[n]) > 127) or (Ord(Value[n]) = 0) then - begin - Result := True; - Break; - end; -end; - -{==============================================================================} -function IdealCharsetCoding(const Value: AnsiString; CharFrom: TMimeChar; - CharTo: TMimeSetChar): TMimeChar; -var - n: Integer; - max: Integer; - s, t, u: AnsiString; - CharSet: TMimeChar; -begin - Result := ISO_8859_1; - s := Copy(Value, 1, 1024); //max first 1KB for next procedure - max := 0; - for n := Ord(Low(TMimeChar)) to Ord(High(TMimeChar)) do - begin - CharSet := TMimeChar(n); - if CharSet in CharTo then - begin - t := CharsetConversionTrans(s, CharFrom, CharSet, Replace_None, False); - u := CharsetConversionTrans(t, CharSet, CharFrom, Replace_None, False); - if s = u then - begin - Result := CharSet; - Exit; - end; - if Length(u) > max then - begin - Result := CharSet; - max := Length(u); - end; - end; - end; -end; - -{==============================================================================} -function GetBOM(Value: TMimeChar): AnsiString; -begin - Result := ''; - case Value of - UCS_2: - Result := #$fe + #$ff; - UCS_4: - Result := #$00 + #$00 + #$fe + #$ff; - UCS_2LE: - Result := #$ff + #$fe; - UCS_4LE: - Result := #$ff + #$fe + #$00 + #$00; - UTF_8: - Result := #$ef + #$bb + #$bf; - end; -end; - -{==============================================================================} -function GetCPFromID(Value: AnsiString): TMimeChar; -begin - Value := UpperCase(Value); - if (Pos('KAMENICKY', Value) > 0) or (Pos('895', Value) > 0) then - Result := CP895 - else - if Pos('MUTF-7', Value) > 0 then - Result := UTF_7mod - else - Result := GetCPFromIconvID(Value); -end; - -{==============================================================================} -function GetIDFromCP(Value: TMimeChar): AnsiString; -begin - case Value of - CP895: - Result := 'CP-895'; - UTF_7mod: - Result := 'mUTF-7'; - else - Result := GetIconvIDFromCP(Value); - end; -end; - -{==============================================================================} -function StringToWide(const Value: AnsiString): WideString; -var - n: integer; - x, y: integer; -begin - SetLength(Result, Length(Value) div 2); - for n := 1 to Length(Value) div 2 do - begin - x := Ord(Value[((n-1) * 2) + 1]); - y := Ord(Value[((n-1) * 2) + 2]); - Result[n] := WideChar(x * 256 + y); - end; -end; - -{==============================================================================} -function WideToString(const Value: WideString): AnsiString; -var - n: integer; - x: integer; -begin - SetLength(Result, Length(Value) * 2); - for n := 1 to Length(Value) do - begin - x := Ord(Value[n]); - Result[((n-1) * 2) + 1] := AnsiChar(x div 256); - Result[((n-1) * 2) + 2] := AnsiChar(x mod 256); - end; -end; - -{==============================================================================} -initialization -begin - IconvArr[0].Charset := ISO_8859_1; - IconvArr[0].Charname := 'ISO-8859-1 CP819 IBM819 ISO-IR-100 ISO8859-1 ISO_8859-1 ISO_8859-1:1987 L1 LATIN1 CSISOLATIN1'; - IconvArr[1].Charset := UTF_8; - IconvArr[1].Charname := 'UTF-8'; - IconvArr[2].Charset := UCS_2; - IconvArr[2].Charname := 'ISO-10646-UCS-2 UCS-2 CSUNICODE'; - IconvArr[3].Charset := UCS_2; - IconvArr[3].Charname := 'UCS-2BE UNICODE-1-1 UNICODEBIG CSUNICODE11'; - IconvArr[4].Charset := UCS_2LE; - IconvArr[4].Charname := 'UCS-2LE UNICODELITTLE'; - IconvArr[5].Charset := UCS_4; - IconvArr[5].Charname := 'ISO-10646-UCS-4 UCS-4 CSUCS4'; - IconvArr[6].Charset := UCS_4; - IconvArr[6].Charname := 'UCS-4BE'; - IconvArr[7].Charset := UCS_2LE; - IconvArr[7].Charname := 'UCS-4LE'; - IconvArr[8].Charset := UTF_16; - IconvArr[8].Charname := 'UTF-16'; - IconvArr[9].Charset := UTF_16; - IconvArr[9].Charname := 'UTF-16BE'; - IconvArr[10].Charset := UTF_16LE; - IconvArr[10].Charname := 'UTF-16LE'; - IconvArr[11].Charset := UTF_32; - IconvArr[11].Charname := 'UTF-32'; - IconvArr[12].Charset := UTF_32; - IconvArr[12].Charname := 'UTF-32BE'; - IconvArr[13].Charset := UTF_32; - IconvArr[13].Charname := 'UTF-32LE'; - IconvArr[14].Charset := UTF_7; - IconvArr[14].Charname := 'UNICODE-1-1-UTF-7 UTF-7 CSUNICODE11UTF7'; - IconvArr[15].Charset := C99; - IconvArr[15].Charname := 'C99'; - IconvArr[16].Charset := JAVA; - IconvArr[16].Charname := 'JAVA'; - IconvArr[17].Charset := ISO_8859_1; - IconvArr[17].Charname := 'US-ASCII ANSI_X3.4-1968 ANSI_X3.4-1986 ASCII CP367 IBM367 ISO-IR-6 ISO646-US ISO_646.IRV:1991 US CSASCII'; - IconvArr[18].Charset := ISO_8859_2; - IconvArr[18].Charname := 'ISO-8859-2 ISO-IR-101 ISO8859-2 ISO_8859-2 ISO_8859-2:1987 L2 LATIN2 CSISOLATIN2'; - IconvArr[19].Charset := ISO_8859_3; - IconvArr[19].Charname := 'ISO-8859-3 ISO-IR-109 ISO8859-3 ISO_8859-3 ISO_8859-3:1988 L3 LATIN3 CSISOLATIN3'; - IconvArr[20].Charset := ISO_8859_4; - IconvArr[20].Charname := 'ISO-8859-4 ISO-IR-110 ISO8859-4 ISO_8859-4 ISO_8859-4:1988 L4 LATIN4 CSISOLATIN4'; - IconvArr[21].Charset := ISO_8859_5; - IconvArr[21].Charname := 'ISO-8859-5 CYRILLIC ISO-IR-144 ISO8859-5 ISO_8859-5 ISO_8859-5:1988 CSISOLATINCYRILLIC'; - IconvArr[22].Charset := ISO_8859_6; - IconvArr[22].Charname := 'ISO-8859-6 ARABIC ASMO-708 ECMA-114 ISO-IR-127 ISO8859-6 ISO_8859-6 ISO_8859-6:1987 CSISOLATINARABIC'; - IconvArr[23].Charset := ISO_8859_7; - IconvArr[23].Charname := 'ISO-8859-7 ECMA-118 ELOT_928 GREEK GREEK8 ISO-IR-126 ISO8859-7 ISO_8859-7 ISO_8859-7:1987 CSISOLATINGREEK'; - IconvArr[24].Charset := ISO_8859_8; - IconvArr[24].Charname := 'ISO-8859-8 HEBREW ISO_8859-8 ISO-IR-138 ISO8859-8 ISO_8859-8:1988 CSISOLATINHEBREW ISO-8859-8-I'; - IconvArr[25].Charset := ISO_8859_9; - IconvArr[25].Charname := 'ISO-8859-9 ISO-IR-148 ISO8859-9 ISO_8859-9 ISO_8859-9:1989 L5 LATIN5 CSISOLATIN5'; - IconvArr[26].Charset := ISO_8859_10; - IconvArr[26].Charname := 'ISO-8859-10 ISO-IR-157 ISO8859-10 ISO_8859-10 ISO_8859-10:1992 L6 LATIN6 CSISOLATIN6'; - IconvArr[27].Charset := ISO_8859_13; - IconvArr[27].Charname := 'ISO-8859-13 ISO-IR-179 ISO8859-13 ISO_8859-13 L7 LATIN7'; - IconvArr[28].Charset := ISO_8859_14; - IconvArr[28].Charname := 'ISO-8859-14 ISO-CELTIC ISO-IR-199 ISO8859-14 ISO_8859-14 ISO_8859-14:1998 L8 LATIN8'; - IconvArr[29].Charset := ISO_8859_15; - IconvArr[29].Charname := 'ISO-8859-15 ISO-IR-203 ISO8859-15 ISO_8859-15 ISO_8859-15:1998'; - IconvArr[30].Charset := ISO_8859_16; - IconvArr[30].Charname := 'ISO-8859-16 ISO-IR-226 ISO8859-16 ISO_8859-16 ISO_8859-16:2000'; - IconvArr[31].Charset := KOI8_R; - IconvArr[31].Charname := 'KOI8-R CSKOI8R'; - IconvArr[32].Charset := KOI8_U; - IconvArr[32].Charname := 'KOI8-U'; - IconvArr[33].Charset := KOI8_RU; - IconvArr[33].Charname := 'KOI8-RU'; - IconvArr[34].Charset := CP1250; - IconvArr[34].Charname := 'WINDOWS-1250 CP1250 MS-EE'; - IconvArr[35].Charset := CP1251; - IconvArr[35].Charname := 'WINDOWS-1251 CP1251 MS-CYRL'; - IconvArr[36].Charset := CP1252; - IconvArr[36].Charname := 'WINDOWS-1252 CP1252 MS-ANSI'; - IconvArr[37].Charset := CP1253; - IconvArr[37].Charname := 'WINDOWS-1253 CP1253 MS-GREEK'; - IconvArr[38].Charset := CP1254; - IconvArr[38].Charname := 'WINDOWS-1254 CP1254 MS-TURK'; - IconvArr[39].Charset := CP1255; - IconvArr[39].Charname := 'WINDOWS-1255 CP1255 MS-HEBR'; - IconvArr[40].Charset := CP1256; - IconvArr[40].Charname := 'WINDOWS-1256 CP1256 MS-ARAB'; - IconvArr[41].Charset := CP1257; - IconvArr[41].Charname := 'WINDOWS-1257 CP1257 WINBALTRIM'; - IconvArr[42].Charset := CP1258; - IconvArr[42].Charname := 'WINDOWS-1258 CP1258'; - IconvArr[43].Charset := ISO_8859_1; - IconvArr[43].Charname := '850 CP850 IBM850 CSPC850MULTILINGUAL'; - IconvArr[44].Charset := CP862; - IconvArr[44].Charname := '862 CP862 IBM862 CSPC862LATINHEBREW'; - IconvArr[45].Charset := CP866; - IconvArr[45].Charname := '866 CP866 IBM866 CSIBM866'; - IconvArr[46].Charset := MAC; - IconvArr[46].Charname := 'MAC MACINTOSH MACROMAN CSMACINTOSH'; - IconvArr[47].Charset := MACCE; - IconvArr[47].Charname := 'MACCENTRALEUROPE'; - IconvArr[48].Charset := MACICE; - IconvArr[48].Charname := 'MACICELAND'; - IconvArr[49].Charset := MACCRO; - IconvArr[49].Charname := 'MACCROATIAN'; - IconvArr[50].Charset := MACRO; - IconvArr[50].Charname := 'MACROMANIA'; - IconvArr[51].Charset := MACCYR; - IconvArr[51].Charname := 'MACCYRILLIC'; - IconvArr[52].Charset := MACUK; - IconvArr[52].Charname := 'MACUKRAINE'; - IconvArr[53].Charset := MACGR; - IconvArr[53].Charname := 'MACGREEK'; - IconvArr[54].Charset := MACTU; - IconvArr[54].Charname := 'MACTURKISH'; - IconvArr[55].Charset := MACHEB; - IconvArr[55].Charname := 'MACHEBREW'; - IconvArr[56].Charset := MACAR; - IconvArr[56].Charname := 'MACARABIC'; - IconvArr[57].Charset := MACTH; - IconvArr[57].Charname := 'MACTHAI'; - IconvArr[58].Charset := ROMAN8; - IconvArr[58].Charname := 'HP-ROMAN8 R8 ROMAN8 CSHPROMAN8'; - IconvArr[59].Charset := NEXTSTEP; - IconvArr[59].Charname := 'NEXTSTEP'; - IconvArr[60].Charset := ARMASCII; - IconvArr[60].Charname := 'ARMSCII-8'; - IconvArr[61].Charset := GEORGIAN_AC; - IconvArr[61].Charname := 'GEORGIAN-ACADEMY'; - IconvArr[62].Charset := GEORGIAN_PS; - IconvArr[62].Charname := 'GEORGIAN-PS'; - IconvArr[63].Charset := KOI8_T; - IconvArr[63].Charname := 'KOI8-T'; - IconvArr[64].Charset := MULELAO; - IconvArr[64].Charname := 'MULELAO-1'; - IconvArr[65].Charset := CP1133; - IconvArr[65].Charname := 'CP1133 IBM-CP1133'; - IconvArr[66].Charset := TIS620; - IconvArr[66].Charname := 'TIS-620 ISO-IR-166 TIS620 TIS620-0 TIS620.2529-1 TIS620.2533-0 TIS620.2533-1'; - IconvArr[67].Charset := CP874; - IconvArr[67].Charname := 'CP874 WINDOWS-874'; - IconvArr[68].Charset := VISCII; - IconvArr[68].Charname := 'VISCII VISCII1.1-1 CSVISCII'; - IconvArr[69].Charset := TCVN; - IconvArr[69].Charname := 'TCVN TCVN-5712 TCVN5712-1 TCVN5712-1:1993'; - IconvArr[70].Charset := ISO_IR_14; - IconvArr[70].Charname := 'ISO-IR-14 ISO646-JP JIS_C6220-1969-RO JP CSISO14JISC6220RO'; - IconvArr[71].Charset := JIS_X0201; - IconvArr[71].Charname := 'JISX0201-1976 JIS_X0201 X0201 CSHALFWIDTHKATAKANA'; - IconvArr[72].Charset := JIS_X0208; - IconvArr[72].Charname := 'ISO-IR-87 JIS0208 JIS_C6226-1983 JIS_X0208 JIS_X0208-1983 JIS_X0208-1990 X0208 CSISO87JISX0208'; - IconvArr[73].Charset := JIS_X0212; - IconvArr[73].Charname := 'ISO-IR-159 JIS_X0212 JIS_X0212-1990 JIS_X0212.1990-0 X0212 CSISO159JISX02121990'; - IconvArr[74].Charset := GB1988_80; - IconvArr[74].Charname := 'CN GB_1988-80 ISO-IR-57 ISO646-CN CSISO57GB1988'; - IconvArr[75].Charset := GB2312_80; - IconvArr[75].Charname := 'CHINESE GB_2312-80 ISO-IR-58 CSISO58GB231280'; - IconvArr[76].Charset := ISO_IR_165; - IconvArr[76].Charname := 'CN-GB-ISOIR165 ISO-IR-165'; - IconvArr[77].Charset := ISO_IR_149; - IconvArr[77].Charname := 'ISO-IR-149 KOREAN KSC_5601 KS_C_5601-1987 KS_C_5601-1989 CSKSC56011987'; - IconvArr[78].Charset := EUC_JP; - IconvArr[78].Charname := 'EUC-JP EUCJP EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE CSEUCPKDFMTJAPANESE'; - IconvArr[79].Charset := SHIFT_JIS; - IconvArr[79].Charname := 'SHIFT-JIS MS_KANJI SHIFT_JIS SJIS CSSHIFTJIS'; - IconvArr[80].Charset := CP932; - IconvArr[80].Charname := 'CP932'; - IconvArr[81].Charset := ISO_2022_JP; - IconvArr[81].Charname := 'ISO-2022-JP CSISO2022JP'; - IconvArr[82].Charset := ISO_2022_JP1; - IconvArr[82].Charname := 'ISO-2022-JP-1'; - IconvArr[83].Charset := ISO_2022_JP2; - IconvArr[83].Charname := 'ISO-2022-JP-2 CSISO2022JP2'; - IconvArr[84].Charset := GB2312; - IconvArr[84].Charname := 'CN-GB EUC-CN EUCCN GB2312 CSGB2312'; - IconvArr[85].Charset := CP936; - IconvArr[85].Charname := 'CP936 GBK'; - IconvArr[86].Charset := GB18030; - IconvArr[86].Charname := 'GB18030'; - IconvArr[87].Charset := ISO_2022_CN; - IconvArr[87].Charname := 'ISO-2022-CN CSISO2022CN'; - IconvArr[88].Charset := ISO_2022_CNE; - IconvArr[88].Charname := 'ISO-2022-CN-EXT'; - IconvArr[89].Charset := HZ; - IconvArr[89].Charname := 'HZ HZ-GB-2312'; - IconvArr[90].Charset := EUC_TW; - IconvArr[90].Charname := 'EUC-TW EUCTW CSEUCTW'; - IconvArr[91].Charset := BIG5; - IconvArr[91].Charname := 'BIG5 BIG-5 BIG-FIVE BIGFIVE CN-BIG5 CSBIG5'; - IconvArr[92].Charset := CP950; - IconvArr[92].Charname := 'CP950'; - IconvArr[93].Charset := BIG5_HKSCS; - IconvArr[93].Charname := 'BIG5-HKSCS BIG5HKSCS'; - IconvArr[94].Charset := EUC_KR; - IconvArr[94].Charname := 'EUC-KR EUCKR CSEUCKR'; - IconvArr[95].Charset := CP949; - IconvArr[95].Charname := 'CP949 UHC'; - IconvArr[96].Charset := CP1361; - IconvArr[96].Charname := 'CP1361 JOHAB'; - IconvArr[97].Charset := ISO_2022_KR; - IconvArr[97].Charname := 'ISO-2022-KR CSISO2022KR'; - IconvArr[98].Charset := ISO_8859_1; - IconvArr[98].Charname := '437 CP437 IBM437 CSPC8CODEPAGE437'; - IconvArr[99].Charset := CP737; - IconvArr[99].Charname := 'CP737'; - IconvArr[100].Charset := CP775; - IconvArr[100].Charname := 'CP775 IBM775 CSPC775BALTIC'; - IconvArr[101].Charset := CP852; - IconvArr[101].Charname := '852 CP852 IBM852 CSPCP852'; - IconvArr[102].Charset := CP853; - IconvArr[102].Charname := 'CP853'; - IconvArr[103].Charset := CP855; - IconvArr[103].Charname := '855 CP855 IBM855 CSIBM855'; - IconvArr[104].Charset := CP857; - IconvArr[104].Charname := '857 CP857 IBM857 CSIBM857'; - IconvArr[105].Charset := CP858; - IconvArr[105].Charname := 'CP858'; - IconvArr[106].Charset := CP860; - IconvArr[106].Charname := '860 CP860 IBM860 CSIBM860'; - IconvArr[107].Charset := CP861; - IconvArr[107].Charname := '861 CP-IS CP861 IBM861 CSIBM861'; - IconvArr[108].Charset := CP863; - IconvArr[108].Charname := '863 CP863 IBM863 CSIBM863'; - IconvArr[109].Charset := CP864; - IconvArr[109].Charname := 'CP864 IBM864 CSIBM864'; - IconvArr[110].Charset := CP865; - IconvArr[110].Charname := '865 CP865 IBM865 CSIBM865'; - IconvArr[111].Charset := CP869; - IconvArr[111].Charname := '869 CP-GR CP869 IBM869 CSIBM869'; - IconvArr[112].Charset := CP1125; - IconvArr[112].Charname := 'CP1125'; -end; - -end. diff --git a/3rd/synapse/source/synacode.pas b/3rd/synapse/source/synacode.pas deleted file mode 100644 index 6ab39c1ab..000000000 --- a/3rd/synapse/source/synacode.pas +++ /dev/null @@ -1,1467 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 002.002.003 | -|==============================================================================| -| Content: Coding and decoding support | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2000-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Various encoding and decoding support)} -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} -{$TYPEDADDRESS OFF} - -{$IFDEF CIL} - {$DEFINE SYNACODE_NATIVE} -{$ENDIF} -{$IFDEF FPC_BIG_ENDIAN} - {$DEFINE SYNACODE_NATIVE} -{$ENDIF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit synacode; - -interface - -uses - SysUtils; - -type - TSpecials = set of AnsiChar; - -const - - SpecialChar: TSpecials = - ['=', '(', ')', '[', ']', '<', '>', ':', ';', ',', '@', '/', '?', '\', - '"', '_']; - NonAsciiChar: TSpecials = - [#0..#31, #127..#255]; - URLFullSpecialChar: TSpecials = - [';', '/', '?', ':', '@', '=', '&', '#', '+']; - URLSpecialChar: TSpecials = - [#$00..#$20, '<', '>', '"', '%', '{', '}', '|', '\', '^', '[', ']', '`', #$7F..#$FF]; - TableBase64 = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - TableBase64mod = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,='; - TableUU = - '`!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'; - TableXX = - '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - ReTablebase64 = - #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$3E +#$40 - +#$40 +#$40 +#$3F +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C - +#$3D +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$01 +#$02 +#$03 - +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C +#$0D +#$0E +#$0F - +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 - +#$22 +#$23 +#$24 +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D - +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; - ReTableUU = - #$01 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A +#$0B +#$0C - +#$0D +#$0E +#$0F +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 - +#$19 +#$1A +#$1B +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 - +#$25 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D +#$2E +#$2F +#$30 - +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 +#$3A +#$3B +#$3C - +#$3D +#$3E +#$3F +#$00 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; - ReTableXX = - #$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$00 +#$40 - +#$01 +#$40 +#$40 +#$02 +#$03 +#$04 +#$05 +#$06 +#$07 +#$08 +#$09 +#$0A - +#$0B +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$40 +#$0C +#$0D +#$0E +#$0F - +#$10 +#$11 +#$12 +#$13 +#$14 +#$15 +#$16 +#$17 +#$18 +#$19 +#$1A +#$1B - +#$1C +#$1D +#$1E +#$1F +#$20 +#$21 +#$22 +#$23 +#$24 +#$25 +#$40 +#$40 - +#$40 +#$40 +#$40 +#$40 +#$26 +#$27 +#$28 +#$29 +#$2A +#$2B +#$2C +#$2D - +#$2E +#$2F +#$30 +#$31 +#$32 +#$33 +#$34 +#$35 +#$36 +#$37 +#$38 +#$39 - +#$3A +#$3B +#$3C +#$3D +#$3E +#$3F +#$40 +#$40 +#$40 +#$40 +#$40 +#$40; - -{:Decodes triplet encoding with a given character delimiter. It is used for - decoding quoted-printable or URL encoding.} -function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; - -{:Decodes a string from quoted printable form. (also decodes triplet sequences - like '=7F')} -function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; - -{:Decodes a string of URL encoding. (also decodes triplet sequences like '%7F')} -function DecodeURL(const Value: AnsiString): AnsiString; - -{:Performs triplet encoding with a given character delimiter. Used for encoding - quoted-printable or URL encoding.} -function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; - Specials: TSpecials): AnsiString; - -{:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) - are encoded.} -function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; - -{:Encodes a string to triplet quoted printable form. All @link(NonAsciiChar) and - @link(SpecialChar) are encoded.} -function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; - -{:Encodes a string to URL format. Used for encoding data from a form field in - HTTP, etc. (Encodes all critical characters including characters used as URL - delimiters ('/',':', etc.)} -function EncodeURLElement(const Value: AnsiString): AnsiString; - -{:Encodes a string to URL format. Used to encode critical characters in all - URLs.} -function EncodeURL(const Value: AnsiString): AnsiString; - -{:Decode 4to3 encoding with given table. If some element is not found in table, - first item from table is used. This is good for buggy coded items by Microsoft - Outlook. This software sometimes using wrong table for UUcode, where is used - ' ' instead '`'.} -function Decode4to3(const Value, Table: AnsiString): AnsiString; - -{:Decode 4to3 encoding with given REVERSE table. Using this function with -reverse table is much faster then @link(Decode4to3). This function is used -internally for Base64, UU or XX decoding.} -function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; - -{:Encode by system 3to4 (used by Base64, UU coding, etc) by given table.} -function Encode3to4(const Value, Table: AnsiString): AnsiString; - -{:Decode string from base64 format.} -function DecodeBase64(const Value: AnsiString): AnsiString; - -{:Encodes a string to base64 format.} -function EncodeBase64(const Value: AnsiString): AnsiString; - -{:Decode string from modified base64 format. (used in IMAP, for example.)} -function DecodeBase64mod(const Value: AnsiString): AnsiString; - -{:Encodes a string to modified base64 format. (used in IMAP, for example.)} -function EncodeBase64mod(const Value: AnsiString): AnsiString; - -{:Decodes a string from UUcode format.} -function DecodeUU(const Value: AnsiString): AnsiString; - -{:encode UUcode. it encode only datas, you must also add header and footer for - proper encode.} -function EncodeUU(const Value: AnsiString): AnsiString; - -{:Decodes a string from XXcode format.} -function DecodeXX(const Value: AnsiString): AnsiString; - -{:decode line with Yenc code. This code is sometimes used in newsgroups.} -function DecodeYEnc(const Value: AnsiString): AnsiString; - -{:Returns a new CRC32 value after adding a new byte of data.} -function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; - -{:return CRC32 from a value string.} -function Crc32(const Value: AnsiString): Integer; - -{:Returns a new CRC16 value after adding a new byte of data.} -function UpdateCrc16(Value: Byte; Crc16: Word): Word; - -{:return CRC16 from a value string.} -function Crc16(const Value: AnsiString): Word; - -{:Returns a binary string with a RSA-MD5 hashing of "Value" string.} -function MD5(const Value: AnsiString): AnsiString; - -{:Returns a binary string with HMAC-MD5 hash.} -function HMAC_MD5(Text, Key: AnsiString): AnsiString; - -{:Returns a binary string with a RSA-MD5 hashing of string what is constructed - by repeating "value" until length is "Len".} -function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; - -{:Returns a binary string with a SHA-1 hashing of "Value" string.} -function SHA1(const Value: AnsiString): AnsiString; - -{:Returns a binary string with HMAC-SHA1 hash.} -function HMAC_SHA1(Text, Key: AnsiString): AnsiString; - -{:Returns a binary string with a SHA-1 hashing of string what is constructed - by repeating "value" until length is "Len".} -function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; - -{:Returns a binary string with a RSA-MD4 hashing of "Value" string.} -function MD4(const Value: AnsiString): AnsiString; - -implementation - -const - - Crc32Tab: array[0..255] of Integer = ( - Integer($00000000), Integer($77073096), Integer($EE0E612C), Integer($990951BA), - Integer($076DC419), Integer($706AF48F), Integer($E963A535), Integer($9E6495A3), - Integer($0EDB8832), Integer($79DCB8A4), Integer($E0D5E91E), Integer($97D2D988), - Integer($09B64C2B), Integer($7EB17CBD), Integer($E7B82D07), Integer($90BF1D91), - Integer($1DB71064), Integer($6AB020F2), Integer($F3B97148), Integer($84BE41DE), - Integer($1ADAD47D), Integer($6DDDE4EB), Integer($F4D4B551), Integer($83D385C7), - Integer($136C9856), Integer($646BA8C0), Integer($FD62F97A), Integer($8A65C9EC), - Integer($14015C4F), Integer($63066CD9), Integer($FA0F3D63), Integer($8D080DF5), - Integer($3B6E20C8), Integer($4C69105E), Integer($D56041E4), Integer($A2677172), - Integer($3C03E4D1), Integer($4B04D447), Integer($D20D85FD), Integer($A50AB56B), - Integer($35B5A8FA), Integer($42B2986C), Integer($DBBBC9D6), Integer($ACBCF940), - Integer($32D86CE3), Integer($45DF5C75), Integer($DCD60DCF), Integer($ABD13D59), - Integer($26D930AC), Integer($51DE003A), Integer($C8D75180), Integer($BFD06116), - Integer($21B4F4B5), Integer($56B3C423), Integer($CFBA9599), Integer($B8BDA50F), - Integer($2802B89E), Integer($5F058808), Integer($C60CD9B2), Integer($B10BE924), - Integer($2F6F7C87), Integer($58684C11), Integer($C1611DAB), Integer($B6662D3D), - Integer($76DC4190), Integer($01DB7106), Integer($98D220BC), Integer($EFD5102A), - Integer($71B18589), Integer($06B6B51F), Integer($9FBFE4A5), Integer($E8B8D433), - Integer($7807C9A2), Integer($0F00F934), Integer($9609A88E), Integer($E10E9818), - Integer($7F6A0DBB), Integer($086D3D2D), Integer($91646C97), Integer($E6635C01), - Integer($6B6B51F4), Integer($1C6C6162), Integer($856530D8), Integer($F262004E), - Integer($6C0695ED), Integer($1B01A57B), Integer($8208F4C1), Integer($F50FC457), - Integer($65B0D9C6), Integer($12B7E950), Integer($8BBEB8EA), Integer($FCB9887C), - Integer($62DD1DDF), Integer($15DA2D49), Integer($8CD37CF3), Integer($FBD44C65), - Integer($4DB26158), Integer($3AB551CE), Integer($A3BC0074), Integer($D4BB30E2), - Integer($4ADFA541), Integer($3DD895D7), Integer($A4D1C46D), Integer($D3D6F4FB), - Integer($4369E96A), Integer($346ED9FC), Integer($AD678846), Integer($DA60B8D0), - Integer($44042D73), Integer($33031DE5), Integer($AA0A4C5F), Integer($DD0D7CC9), - Integer($5005713C), Integer($270241AA), Integer($BE0B1010), Integer($C90C2086), - Integer($5768B525), Integer($206F85B3), Integer($B966D409), Integer($CE61E49F), - Integer($5EDEF90E), Integer($29D9C998), Integer($B0D09822), Integer($C7D7A8B4), - Integer($59B33D17), Integer($2EB40D81), Integer($B7BD5C3B), Integer($C0BA6CAD), - Integer($EDB88320), Integer($9ABFB3B6), Integer($03B6E20C), Integer($74B1D29A), - Integer($EAD54739), Integer($9DD277AF), Integer($04DB2615), Integer($73DC1683), - Integer($E3630B12), Integer($94643B84), Integer($0D6D6A3E), Integer($7A6A5AA8), - Integer($E40ECF0B), Integer($9309FF9D), Integer($0A00AE27), Integer($7D079EB1), - Integer($F00F9344), Integer($8708A3D2), Integer($1E01F268), Integer($6906C2FE), - Integer($F762575D), Integer($806567CB), Integer($196C3671), Integer($6E6B06E7), - Integer($FED41B76), Integer($89D32BE0), Integer($10DA7A5A), Integer($67DD4ACC), - Integer($F9B9DF6F), Integer($8EBEEFF9), Integer($17B7BE43), Integer($60B08ED5), - Integer($D6D6A3E8), Integer($A1D1937E), Integer($38D8C2C4), Integer($4FDFF252), - Integer($D1BB67F1), Integer($A6BC5767), Integer($3FB506DD), Integer($48B2364B), - Integer($D80D2BDA), Integer($AF0A1B4C), Integer($36034AF6), Integer($41047A60), - Integer($DF60EFC3), Integer($A867DF55), Integer($316E8EEF), Integer($4669BE79), - Integer($CB61B38C), Integer($BC66831A), Integer($256FD2A0), Integer($5268E236), - Integer($CC0C7795), Integer($BB0B4703), Integer($220216B9), Integer($5505262F), - Integer($C5BA3BBE), Integer($B2BD0B28), Integer($2BB45A92), Integer($5CB36A04), - Integer($C2D7FFA7), Integer($B5D0CF31), Integer($2CD99E8B), Integer($5BDEAE1D), - Integer($9B64C2B0), Integer($EC63F226), Integer($756AA39C), Integer($026D930A), - Integer($9C0906A9), Integer($EB0E363F), Integer($72076785), Integer($05005713), - Integer($95BF4A82), Integer($E2B87A14), Integer($7BB12BAE), Integer($0CB61B38), - Integer($92D28E9B), Integer($E5D5BE0D), Integer($7CDCEFB7), Integer($0BDBDF21), - Integer($86D3D2D4), Integer($F1D4E242), Integer($68DDB3F8), Integer($1FDA836E), - Integer($81BE16CD), Integer($F6B9265B), Integer($6FB077E1), Integer($18B74777), - Integer($88085AE6), Integer($FF0F6A70), Integer($66063BCA), Integer($11010B5C), - Integer($8F659EFF), Integer($F862AE69), Integer($616BFFD3), Integer($166CCF45), - Integer($A00AE278), Integer($D70DD2EE), Integer($4E048354), Integer($3903B3C2), - Integer($A7672661), Integer($D06016F7), Integer($4969474D), Integer($3E6E77DB), - Integer($AED16A4A), Integer($D9D65ADC), Integer($40DF0B66), Integer($37D83BF0), - Integer($A9BCAE53), Integer($DEBB9EC5), Integer($47B2CF7F), Integer($30B5FFE9), - Integer($BDBDF21C), Integer($CABAC28A), Integer($53B39330), Integer($24B4A3A6), - Integer($BAD03605), Integer($CDD70693), Integer($54DE5729), Integer($23D967BF), - Integer($B3667A2E), Integer($C4614AB8), Integer($5D681B02), Integer($2A6F2B94), - Integer($B40BBE37), Integer($C30C8EA1), Integer($5A05DF1B), Integer($2D02EF8D) - ); - - Crc16Tab: array[0..255] of Word = ( - $0000, $1189, $2312, $329B, $4624, $57AD, $6536, $74BF, - $8C48, $9DC1, $AF5A, $BED3, $CA6C, $DBE5, $E97E, $F8F7, - $1081, $0108, $3393, $221A, $56A5, $472C, $75B7, $643E, - $9CC9, $8D40, $BFDB, $AE52, $DAED, $CB64, $F9FF, $E876, - $2102, $308B, $0210, $1399, $6726, $76AF, $4434, $55BD, - $AD4A, $BCC3, $8E58, $9FD1, $EB6E, $FAE7, $C87C, $D9F5, - $3183, $200A, $1291, $0318, $77A7, $662E, $54B5, $453C, - $BDCB, $AC42, $9ED9, $8F50, $FBEF, $EA66, $D8FD, $C974, - $4204, $538D, $6116, $709F, $0420, $15A9, $2732, $36BB, - $CE4C, $DFC5, $ED5E, $FCD7, $8868, $99E1, $AB7A, $BAF3, - $5285, $430C, $7197, $601E, $14A1, $0528, $37B3, $263A, - $DECD, $CF44, $FDDF, $EC56, $98E9, $8960, $BBFB, $AA72, - $6306, $728F, $4014, $519D, $2522, $34AB, $0630, $17B9, - $EF4E, $FEC7, $CC5C, $DDD5, $A96A, $B8E3, $8A78, $9BF1, - $7387, $620E, $5095, $411C, $35A3, $242A, $16B1, $0738, - $FFCF, $EE46, $DCDD, $CD54, $B9EB, $A862, $9AF9, $8B70, - $8408, $9581, $A71A, $B693, $C22C, $D3A5, $E13E, $F0B7, - $0840, $19C9, $2B52, $3ADB, $4E64, $5FED, $6D76, $7CFF, - $9489, $8500, $B79B, $A612, $D2AD, $C324, $F1BF, $E036, - $18C1, $0948, $3BD3, $2A5A, $5EE5, $4F6C, $7DF7, $6C7E, - $A50A, $B483, $8618, $9791, $E32E, $F2A7, $C03C, $D1B5, - $2942, $38CB, $0A50, $1BD9, $6F66, $7EEF, $4C74, $5DFD, - $B58B, $A402, $9699, $8710, $F3AF, $E226, $D0BD, $C134, - $39C3, $284A, $1AD1, $0B58, $7FE7, $6E6E, $5CF5, $4D7C, - $C60C, $D785, $E51E, $F497, $8028, $91A1, $A33A, $B2B3, - $4A44, $5BCD, $6956, $78DF, $0C60, $1DE9, $2F72, $3EFB, - $D68D, $C704, $F59F, $E416, $90A9, $8120, $B3BB, $A232, - $5AC5, $4B4C, $79D7, $685E, $1CE1, $0D68, $3FF3, $2E7A, - $E70E, $F687, $C41C, $D595, $A12A, $B0A3, $8238, $93B1, - $6B46, $7ACF, $4854, $59DD, $2D62, $3CEB, $0E70, $1FF9, - $F78F, $E606, $D49D, $C514, $B1AB, $A022, $92B9, $8330, - $7BC7, $6A4E, $58D5, $495C, $3DE3, $2C6A, $1EF1, $0F78 - ); - -procedure ArrByteToLong(var ArByte: Array of byte; var ArLong: Array of Integer); -{$IFDEF SYNACODE_NATIVE} -var - n: integer; -{$ENDIF} -begin - if (High(ArByte) + 1) > ((High(ArLong) + 1) * 4) then - Exit; - {$IFDEF SYNACODE_NATIVE} - for n := 0 to ((high(ArByte) + 1) div 4) - 1 do - ArLong[n] := ArByte[n * 4 + 0] - + (ArByte[n * 4 + 1] shl 8) - + (ArByte[n * 4 + 2] shl 16) - + (ArByte[n * 4 + 3] shl 24); - {$ELSE} - Move(ArByte[0], ArLong[0], High(ArByte) + 1); - {$ENDIF} -end; - -procedure ArrLongToByte(var ArLong: Array of Integer; var ArByte: Array of byte); -{$IFDEF SYNACODE_NATIVE} -var - n: integer; -{$ENDIF} -begin - if (High(ArByte) + 1) < ((High(ArLong) + 1) * 4) then - Exit; - {$IFDEF SYNACODE_NATIVE} - for n := 0 to high(ArLong) do - begin - ArByte[n * 4 + 0] := ArLong[n] and $000000FF; - ArByte[n * 4 + 1] := (ArLong[n] shr 8) and $000000FF; - ArByte[n * 4 + 2] := (ArLong[n] shr 16) and $000000FF; - ArByte[n * 4 + 3] := (ArLong[n] shr 24) and $000000FF; - end; - {$ELSE} - Move(ArLong[0], ArByte[0], High(ArByte) + 1); - {$ENDIF} -end; - -type - TMDCtx = record - State: array[0..3] of Integer; - Count: array[0..1] of Integer; - BufAnsiChar: array[0..63] of Byte; - BufLong: array[0..15] of Integer; - end; - TSHA1Ctx= record - Hi, Lo: integer; - Buffer: array[0..63] of byte; - Index: integer; - Hash: array[0..4] of Integer; - HashByte: array[0..19] of byte; - end; - - TMDTransform = procedure(var Buf: array of LongInt; const Data: array of LongInt); - -{==============================================================================} - -function DecodeTriplet(const Value: AnsiString; Delimiter: AnsiChar): AnsiString; -var - x, l, lv: Integer; - c: AnsiChar; - b: Byte; - bad: Boolean; -begin - lv := Length(Value); - SetLength(Result, lv); - x := 1; - l := 1; - while x <= lv do - begin - c := Value[x]; - Inc(x); - if c <> Delimiter then - begin - Result[l] := c; - Inc(l); - end - else - if x < lv then - begin - Case Value[x] Of - #13: - if (Value[x + 1] = #10) then - Inc(x, 2) - else - Inc(x); - #10: - if (Value[x + 1] = #13) then - Inc(x, 2) - else - Inc(x); - else - begin - bad := False; - Case Value[x] Of - '0'..'9': b := (Byte(Value[x]) - 48) Shl 4; - 'a'..'f', 'A'..'F': b := ((Byte(Value[x]) And 7) + 9) shl 4; - else - begin - b := 0; - bad := True; - end; - end; - Case Value[x + 1] Of - '0'..'9': b := b Or (Byte(Value[x + 1]) - 48); - 'a'..'f', 'A'..'F': b := b Or ((Byte(Value[x + 1]) And 7) + 9); - else - bad := True; - end; - if bad then - begin - Result[l] := c; - Inc(l); - end - else - begin - Inc(x, 2); - Result[l] := AnsiChar(b); - Inc(l); - end; - end; - end; - end - else - break; - end; - Dec(l); - SetLength(Result, l); -end; - -{==============================================================================} - -function DecodeQuotedPrintable(const Value: AnsiString): AnsiString; -begin - Result := DecodeTriplet(Value, '='); -end; - -{==============================================================================} - -function DecodeURL(const Value: AnsiString): AnsiString; -begin - Result := DecodeTriplet(Value, '%'); -end; - -{==============================================================================} - -function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; - Specials: TSpecials): AnsiString; -var - n, l: Integer; - s: AnsiString; - c: AnsiChar; -begin - SetLength(Result, Length(Value) * 3); - l := 1; - for n := 1 to Length(Value) do - begin - c := Value[n]; - if c in Specials then - begin - Result[l] := Delimiter; - Inc(l); - s := IntToHex(Ord(c), 2); - Result[l] := s[1]; - Inc(l); - Result[l] := s[2]; - Inc(l); - end - else - begin - Result[l] := c; - Inc(l); - end; - end; - Dec(l); - SetLength(Result, l); -end; - -{==============================================================================} - -function EncodeQuotedPrintable(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '=', ['='] + NonAsciiChar); -end; - -{==============================================================================} - -function EncodeSafeQuotedPrintable(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '=', SpecialChar + NonAsciiChar); -end; - -{==============================================================================} - -function EncodeURLElement(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '%', URLSpecialChar + URLFullSpecialChar); -end; - -{==============================================================================} - -function EncodeURL(const Value: AnsiString): AnsiString; -begin - Result := EncodeTriplet(Value, '%', URLSpecialChar); -end; - -{==============================================================================} - -function Decode4to3(const Value, Table: AnsiString): AnsiString; -var - x, y, n, l: Integer; - d: array[0..3] of Byte; -begin - SetLength(Result, Length(Value)); - x := 1; - l := 1; - while x <= Length(Value) do - begin - for n := 0 to 3 do - begin - if x > Length(Value) then - d[n] := 64 - else - begin - y := Pos(Value[x], Table); - if y < 1 then - y := 1; - d[n] := y - 1; - end; - Inc(x); - end; - Result[l] := AnsiChar((D[0] and $3F) shl 2 + (D[1] and $30) shr 4); - Inc(l); - if d[2] <> 64 then - begin - Result[l] := AnsiChar((D[1] and $0F) shl 4 + (D[2] and $3C) shr 2); - Inc(l); - if d[3] <> 64 then - begin - Result[l] := AnsiChar((D[2] and $03) shl 6 + (D[3] and $3F)); - Inc(l); - end; - end; - end; - Dec(l); - SetLength(Result, l); -end; - -{==============================================================================} -function Decode4to3Ex(const Value, Table: AnsiString): AnsiString; -var - x, y, lv: Integer; - d: integer; - dl: integer; - c: byte; - p: integer; -begin - lv := Length(Value); - SetLength(Result, lv); - x := 1; - dl := 4; - d := 0; - p := 1; - while x <= lv do - begin - y := Ord(Value[x]); - if y in [33..127] then - c := Ord(Table[y - 32]) - else - c := 64; - Inc(x); - if c > 63 then - continue; - d := (d shl 6) or c; - dec(dl); - if dl <> 0 then - continue; - Result[p] := AnsiChar((d shr 16) and $ff); - inc(p); - Result[p] := AnsiChar((d shr 8) and $ff); - inc(p); - Result[p] := AnsiChar(d and $ff); - inc(p); - d := 0; - dl := 4; - end; - case dl of - 1: - begin - d := d shr 2; - Result[p] := AnsiChar((d shr 8) and $ff); - inc(p); - Result[p] := AnsiChar(d and $ff); - inc(p); - end; - 2: - begin - d := d shr 4; - Result[p] := AnsiChar(d and $ff); - inc(p); - end; - end; - SetLength(Result, p - 1); -end; - -{==============================================================================} - -function Encode3to4(const Value, Table: AnsiString): AnsiString; -var - c: Byte; - n, l: Integer; - Count: Integer; - DOut: array[0..3] of Byte; -begin - setlength(Result, ((Length(Value) + 2) div 3) * 4); - l := 1; - Count := 1; - while Count <= Length(Value) do - begin - c := Ord(Value[Count]); - Inc(Count); - DOut[0] := (c and $FC) shr 2; - DOut[1] := (c and $03) shl 4; - if Count <= Length(Value) then - begin - c := Ord(Value[Count]); - Inc(Count); - DOut[1] := DOut[1] + (c and $F0) shr 4; - DOut[2] := (c and $0F) shl 2; - if Count <= Length(Value) then - begin - c := Ord(Value[Count]); - Inc(Count); - DOut[2] := DOut[2] + (c and $C0) shr 6; - DOut[3] := (c and $3F); - end - else - begin - DOut[3] := $40; - end; - end - else - begin - DOut[2] := $40; - DOut[3] := $40; - end; - for n := 0 to 3 do - begin - if (DOut[n] + 1) <= Length(Table) then - begin - Result[l] := Table[DOut[n] + 1]; - Inc(l); - end; - end; - end; - SetLength(Result, l - 1); -end; - -{==============================================================================} - -function DecodeBase64(const Value: AnsiString): AnsiString; -begin - Result := Decode4to3Ex(Value, ReTableBase64); -end; - -{==============================================================================} - -function EncodeBase64(const Value: AnsiString): AnsiString; -begin - Result := Encode3to4(Value, TableBase64); -end; - -{==============================================================================} - -function DecodeBase64mod(const Value: AnsiString): AnsiString; -begin - Result := Decode4to3(Value, TableBase64mod); -end; - -{==============================================================================} - -function EncodeBase64mod(const Value: AnsiString): AnsiString; -begin - Result := Encode3to4(Value, TableBase64mod); -end; - -{==============================================================================} - -function DecodeUU(const Value: AnsiString): AnsiString; -var - s: AnsiString; - uut: AnsiString; - x: Integer; -begin - Result := ''; - uut := TableUU; - s := trim(UpperCase(Value)); - if s = '' then Exit; - if Pos('BEGIN', s) = 1 then - Exit; - if Pos('END', s) = 1 then - Exit; - if Pos('TABLE', s) = 1 then - Exit; //ignore Table yet (set custom UUT) - //begin decoding - x := Pos(Value[1], uut) - 1; - case (x mod 3) of - 0: x :=(x div 3)* 4; - 1: x :=((x div 3) * 4) + 2; - 2: x :=((x div 3) * 4) + 3; - end; - //x - lenght UU line - s := Copy(Value, 2, x); - if s = '' then - Exit; - s := s + StringOfChar(' ', x - length(s)); - Result := Decode4to3(s, uut); -end; - -{==============================================================================} - -function EncodeUU(const Value: AnsiString): AnsiString; -begin - Result := ''; - if Length(Value) < Length(TableUU) then - Result := TableUU[Length(Value) + 1] + Encode3to4(Value, TableUU); -end; - -{==============================================================================} - -function DecodeXX(const Value: AnsiString): AnsiString; -var - s: AnsiString; - x: Integer; -begin - Result := ''; - s := trim(UpperCase(Value)); - if s = '' then - Exit; - if Pos('BEGIN', s) = 1 then - Exit; - if Pos('END', s) = 1 then - Exit; - //begin decoding - x := Pos(Value[1], TableXX) - 1; - case (x mod 3) of - 0: x :=(x div 3)* 4; - 1: x :=((x div 3) * 4) + 2; - 2: x :=((x div 3) * 4) + 3; - end; - //x - lenght XX line - s := Copy(Value, 2, x); - if s = '' then - Exit; - s := s + StringOfChar(' ', x - length(s)); - Result := Decode4to3(s, TableXX); -end; - -{==============================================================================} - -function DecodeYEnc(const Value: AnsiString): AnsiString; -var - C : Byte; - i: integer; -begin - Result := ''; - i := 1; - while i <= Length(Value) do - begin - c := Ord(Value[i]); - Inc(i); - if c = Ord('=') then - begin - c := Ord(Value[i]); - Inc(i); - Dec(c, 64); - end; - Dec(C, 42); - Result := Result + AnsiChar(C); - end; -end; - -{==============================================================================} - -function UpdateCrc32(Value: Byte; Crc32: Integer): Integer; -begin - Result := (Crc32 shr 8) - xor crc32tab[Byte(Value xor (Crc32 and Integer($000000FF)))]; -end; - -{==============================================================================} - -function Crc32(const Value: AnsiString): Integer; -var - n: Integer; -begin - Result := Integer($FFFFFFFF); - for n := 1 to Length(Value) do - Result := UpdateCrc32(Ord(Value[n]), Result); - Result := not Result; -end; - -{==============================================================================} - -function UpdateCrc16(Value: Byte; Crc16: Word): Word; -begin - Result := ((Crc16 shr 8) and $00FF) xor - crc16tab[Byte(Crc16 xor (Word(Value)) and $00FF)]; -end; - -{==============================================================================} - -function Crc16(const Value: AnsiString): Word; -var - n: Integer; -begin - Result := $FFFF; - for n := 1 to Length(Value) do - Result := UpdateCrc16(Ord(Value[n]), Result); -end; - -{==============================================================================} - -procedure MDInit(var MDContext: TMDCtx); -var - n: integer; -begin - MDContext.Count[0] := 0; - MDContext.Count[1] := 0; - for n := 0 to high(MDContext.BufAnsiChar) do - MDContext.BufAnsiChar[n] := 0; - for n := 0 to high(MDContext.BufLong) do - MDContext.BufLong[n] := 0; - MDContext.State[0] := Integer($67452301); - MDContext.State[1] := Integer($EFCDAB89); - MDContext.State[2] := Integer($98BADCFE); - MDContext.State[3] := Integer($10325476); -end; - -procedure MD5Transform(var Buf: array of LongInt; const Data: array of LongInt); -var - A, B, C, D: LongInt; - - procedure Round1(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (Z xor (X and (Y xor Z))) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; - - procedure Round2(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (Y xor (Z and (X xor Y))) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; - - procedure Round3(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (X xor Y xor Z) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; - - procedure Round4(var W: LongInt; X, Y, Z, Data: LongInt; S: Byte); - begin - Inc(W, (Y xor (X or not Z)) + Data); - W := (W shl S) or (W shr (32 - S)); - Inc(W, X); - end; -begin - A := Buf[0]; - B := Buf[1]; - C := Buf[2]; - D := Buf[3]; - - Round1(A, B, C, D, Data[0] + Longint($D76AA478), 7); - Round1(D, A, B, C, Data[1] + Longint($E8C7B756), 12); - Round1(C, D, A, B, Data[2] + Longint($242070DB), 17); - Round1(B, C, D, A, Data[3] + Longint($C1BDCEEE), 22); - Round1(A, B, C, D, Data[4] + Longint($F57C0FAF), 7); - Round1(D, A, B, C, Data[5] + Longint($4787C62A), 12); - Round1(C, D, A, B, Data[6] + Longint($A8304613), 17); - Round1(B, C, D, A, Data[7] + Longint($FD469501), 22); - Round1(A, B, C, D, Data[8] + Longint($698098D8), 7); - Round1(D, A, B, C, Data[9] + Longint($8B44F7AF), 12); - Round1(C, D, A, B, Data[10] + Longint($FFFF5BB1), 17); - Round1(B, C, D, A, Data[11] + Longint($895CD7BE), 22); - Round1(A, B, C, D, Data[12] + Longint($6B901122), 7); - Round1(D, A, B, C, Data[13] + Longint($FD987193), 12); - Round1(C, D, A, B, Data[14] + Longint($A679438E), 17); - Round1(B, C, D, A, Data[15] + Longint($49B40821), 22); - - Round2(A, B, C, D, Data[1] + Longint($F61E2562), 5); - Round2(D, A, B, C, Data[6] + Longint($C040B340), 9); - Round2(C, D, A, B, Data[11] + Longint($265E5A51), 14); - Round2(B, C, D, A, Data[0] + Longint($E9B6C7AA), 20); - Round2(A, B, C, D, Data[5] + Longint($D62F105D), 5); - Round2(D, A, B, C, Data[10] + Longint($02441453), 9); - Round2(C, D, A, B, Data[15] + Longint($D8A1E681), 14); - Round2(B, C, D, A, Data[4] + Longint($E7D3FBC8), 20); - Round2(A, B, C, D, Data[9] + Longint($21E1CDE6), 5); - Round2(D, A, B, C, Data[14] + Longint($C33707D6), 9); - Round2(C, D, A, B, Data[3] + Longint($F4D50D87), 14); - Round2(B, C, D, A, Data[8] + Longint($455A14ED), 20); - Round2(A, B, C, D, Data[13] + Longint($A9E3E905), 5); - Round2(D, A, B, C, Data[2] + Longint($FCEFA3F8), 9); - Round2(C, D, A, B, Data[7] + Longint($676F02D9), 14); - Round2(B, C, D, A, Data[12] + Longint($8D2A4C8A), 20); - - Round3(A, B, C, D, Data[5] + Longint($FFFA3942), 4); - Round3(D, A, B, C, Data[8] + Longint($8771F681), 11); - Round3(C, D, A, B, Data[11] + Longint($6D9D6122), 16); - Round3(B, C, D, A, Data[14] + Longint($FDE5380C), 23); - Round3(A, B, C, D, Data[1] + Longint($A4BEEA44), 4); - Round3(D, A, B, C, Data[4] + Longint($4BDECFA9), 11); - Round3(C, D, A, B, Data[7] + Longint($F6BB4B60), 16); - Round3(B, C, D, A, Data[10] + Longint($BEBFBC70), 23); - Round3(A, B, C, D, Data[13] + Longint($289B7EC6), 4); - Round3(D, A, B, C, Data[0] + Longint($EAA127FA), 11); - Round3(C, D, A, B, Data[3] + Longint($D4EF3085), 16); - Round3(B, C, D, A, Data[6] + Longint($04881D05), 23); - Round3(A, B, C, D, Data[9] + Longint($D9D4D039), 4); - Round3(D, A, B, C, Data[12] + Longint($E6DB99E5), 11); - Round3(C, D, A, B, Data[15] + Longint($1FA27CF8), 16); - Round3(B, C, D, A, Data[2] + Longint($C4AC5665), 23); - - Round4(A, B, C, D, Data[0] + Longint($F4292244), 6); - Round4(D, A, B, C, Data[7] + Longint($432AFF97), 10); - Round4(C, D, A, B, Data[14] + Longint($AB9423A7), 15); - Round4(B, C, D, A, Data[5] + Longint($FC93A039), 21); - Round4(A, B, C, D, Data[12] + Longint($655B59C3), 6); - Round4(D, A, B, C, Data[3] + Longint($8F0CCC92), 10); - Round4(C, D, A, B, Data[10] + Longint($FFEFF47D), 15); - Round4(B, C, D, A, Data[1] + Longint($85845DD1), 21); - Round4(A, B, C, D, Data[8] + Longint($6FA87E4F), 6); - Round4(D, A, B, C, Data[15] + Longint($FE2CE6E0), 10); - Round4(C, D, A, B, Data[6] + Longint($A3014314), 15); - Round4(B, C, D, A, Data[13] + Longint($4E0811A1), 21); - Round4(A, B, C, D, Data[4] + Longint($F7537E82), 6); - Round4(D, A, B, C, Data[11] + Longint($BD3AF235), 10); - Round4(C, D, A, B, Data[2] + Longint($2AD7D2BB), 15); - Round4(B, C, D, A, Data[9] + Longint($EB86D391), 21); - - Inc(Buf[0], A); - Inc(Buf[1], B); - Inc(Buf[2], C); - Inc(Buf[3], D); -end; - -//fixed by James McAdams -procedure MDUpdate(var MDContext: TMDCtx; const Data: AnsiString; transform: TMDTransform); -var - Index, partLen, InputLen, I: integer; -{$IFDEF SYNACODE_NATIVE} - n: integer; -{$ENDIF} -begin - InputLen := Length(Data); - with MDContext do - begin - Index := (Count[0] shr 3) and $3F; - Inc(Count[0], InputLen shl 3); - if Count[0] < (InputLen shl 3) then - Inc(Count[1]); - Inc(Count[1], InputLen shr 29); - partLen := 64 - Index; - if InputLen >= partLen then - begin - ArrLongToByte(BufLong, BufAnsiChar); - {$IFDEF SYNACODE_NATIVE} - for n := 1 to partLen do - BufAnsiChar[index - 1 + n] := Ord(Data[n]); - {$ELSE} - Move(Data[1], BufAnsiChar[Index], partLen); - {$ENDIF} - ArrByteToLong(BufAnsiChar, BufLong); - Transform(State, Buflong); - I := partLen; - while I + 63 < InputLen do - begin - ArrLongToByte(BufLong, BufAnsiChar); - {$IFDEF SYNACODE_NATIVE} - for n := 1 to 64 do - BufAnsiChar[n - 1] := Ord(Data[i + n]); - {$ELSE} - Move(Data[I+1], BufAnsiChar, 64); - {$ENDIF} - ArrByteToLong(BufAnsiChar, BufLong); - Transform(State, Buflong); - inc(I, 64); - end; - Index := 0; - end - else - I := 0; - ArrLongToByte(BufLong, BufAnsiChar); - {$IFDEF SYNACODE_NATIVE} - for n := 1 to InputLen-I do - BufAnsiChar[Index + n - 1] := Ord(Data[i + n]); - {$ELSE} - Move(Data[I+1], BufAnsiChar[Index], InputLen-I); - {$ENDIF} - ArrByteToLong(BufAnsiChar, BufLong); - end -end; - -function MDFinal(var MDContext: TMDCtx; transform: TMDTransform): AnsiString; -var - Cnt: Word; - P: Byte; - digest: array[0..15] of Byte; - i: Integer; - n: integer; -begin - for I := 0 to 15 do - Digest[I] := I + 1; - with MDContext do - begin - Cnt := (Count[0] shr 3) and $3F; - P := Cnt; - BufAnsiChar[P] := $80; - Inc(P); - Cnt := 64 - 1 - Cnt; - if Cnt < 8 then - begin - for n := 0 to cnt - 1 do - BufAnsiChar[P + n] := 0; - ArrByteToLong(BufAnsiChar, BufLong); -// FillChar(BufAnsiChar[P], Cnt, #0); - Transform(State, BufLong); - ArrLongToByte(BufLong, BufAnsiChar); - for n := 0 to 55 do - BufAnsiChar[n] := 0; - ArrByteToLong(BufAnsiChar, BufLong); -// FillChar(BufAnsiChar, 56, #0); - end - else - begin - for n := 0 to Cnt - 8 - 1 do - BufAnsiChar[p + n] := 0; - ArrByteToLong(BufAnsiChar, BufLong); -// FillChar(BufAnsiChar[P], Cnt - 8, #0); - end; - BufLong[14] := Count[0]; - BufLong[15] := Count[1]; - Transform(State, BufLong); - ArrLongToByte(State, Digest); -// Move(State, Digest, 16); - Result := ''; - for i := 0 to 15 do - Result := Result + AnsiChar(digest[i]); - end; -// FillChar(MD5Context, SizeOf(TMD5Ctx), #0) -end; - -{==============================================================================} - -function MD5(const Value: AnsiString): AnsiString; -var - MDContext: TMDCtx; -begin - MDInit(MDContext); - MDUpdate(MDContext, Value, @MD5Transform); - Result := MDFinal(MDContext, @MD5Transform); -end; - -{==============================================================================} - -function HMAC_MD5(Text, Key: AnsiString): AnsiString; -var - ipad, opad, s: AnsiString; - n: Integer; - MDContext: TMDCtx; -begin - if Length(Key) > 64 then - Key := md5(Key); - ipad := StringOfChar(#$36, 64); - opad := StringOfChar(#$5C, 64); - for n := 1 to Length(Key) do - begin - ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); - opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); - end; - MDInit(MDContext); - MDUpdate(MDContext, ipad, @MD5Transform); - MDUpdate(MDContext, Text, @MD5Transform); - s := MDFinal(MDContext, @MD5Transform); - MDInit(MDContext); - MDUpdate(MDContext, opad, @MD5Transform); - MDUpdate(MDContext, s, @MD5Transform); - Result := MDFinal(MDContext, @MD5Transform); -end; - -{==============================================================================} - -function MD5LongHash(const Value: AnsiString; Len: integer): AnsiString; -var - cnt, rest: integer; - l: integer; - n: integer; - MDContext: TMDCtx; -begin - l := length(Value); - cnt := Len div l; - rest := Len mod l; - MDInit(MDContext); - for n := 1 to cnt do - MDUpdate(MDContext, Value, @MD5Transform); - if rest > 0 then - MDUpdate(MDContext, Copy(Value, 1, rest), @MD5Transform); - Result := MDFinal(MDContext, @MD5Transform); -end; - -{==============================================================================} -// SHA1 is based on sources by Dave Barton (davebarton@bigfoot.com) - -procedure SHA1init( var SHA1Context: TSHA1Ctx ); -var - n: integer; -begin - SHA1Context.Hi := 0; - SHA1Context.Lo := 0; - SHA1Context.Index := 0; - for n := 0 to High(SHA1Context.Buffer) do - SHA1Context.Buffer[n] := 0; - for n := 0 to High(SHA1Context.HashByte) do - SHA1Context.HashByte[n] := 0; -// FillChar(SHA1Context, SizeOf(TSHA1Ctx), #0); - SHA1Context.Hash[0] := integer($67452301); - SHA1Context.Hash[1] := integer($EFCDAB89); - SHA1Context.Hash[2] := integer($98BADCFE); - SHA1Context.Hash[3] := integer($10325476); - SHA1Context.Hash[4] := integer($C3D2E1F0); -end; - -//****************************************************************************** -function RB(A: integer): integer; -begin - Result := (A shr 24) or ((A shr 8) and $FF00) or ((A shl 8) and $FF0000) or (A shl 24); -end; - -procedure SHA1Compress(var Data: TSHA1Ctx); -var - A, B, C, D, E, T: integer; - W: array[0..79] of integer; - i: integer; - n: integer; - - function F1(x, y, z: integer): integer; - begin - Result := z xor (x and (y xor z)); - end; - function F2(x, y, z: integer): integer; - begin - Result := x xor y xor z; - end; - function F3(x, y, z: integer): integer; - begin - Result := (x and y) or (z and (x or y)); - end; - function LRot32(X: integer; c: integer): integer; - begin - result := (x shl c) or (x shr (32 - c)); - end; -begin - ArrByteToLong(Data.Buffer, W); -// Move(Data.Buffer, W, Sizeof(Data.Buffer)); - for i := 0 to 15 do - W[i] := RB(W[i]); - for i := 16 to 79 do - W[i] := LRot32(W[i-3] xor W[i-8] xor W[i-14] xor W[i-16], 1); - A := Data.Hash[0]; - B := Data.Hash[1]; - C := Data.Hash[2]; - D := Data.Hash[3]; - E := Data.Hash[4]; - for i := 0 to 19 do - begin - T := LRot32(A, 5) + F1(B, C, D) + E + W[i] + integer($5A827999); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for i := 20 to 39 do - begin - T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($6ED9EBA1); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for i := 40 to 59 do - begin - T := LRot32(A, 5) + F3(B, C, D) + E + W[i] + integer($8F1BBCDC); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - for i := 60 to 79 do - begin - T := LRot32(A, 5) + F2(B, C, D) + E + W[i] + integer($CA62C1D6); - E := D; - D := C; - C := LRot32(B, 30); - B := A; - A := T; - end; - Data.Hash[0] := Data.Hash[0] + A; - Data.Hash[1] := Data.Hash[1] + B; - Data.Hash[2] := Data.Hash[2] + C; - Data.Hash[3] := Data.Hash[3] + D; - Data.Hash[4] := Data.Hash[4] + E; - for n := 0 to high(w) do - w[n] := 0; -// FillChar(W, Sizeof(W), 0); - for n := 0 to high(Data.Buffer) do - Data.Buffer[n] := 0; -// FillChar(Data.Buffer, Sizeof(Data.Buffer), 0); -end; - -//****************************************************************************** -procedure SHA1Update(var Context: TSHA1Ctx; const Data: AnsiString); -var - Len: integer; - n: integer; - i, k: integer; -begin - Len := Length(data); - for k := 0 to 7 do - begin - i := Context.Lo; - Inc(Context.Lo, Len); - if Context.Lo < i then - Inc(Context.Hi); - end; - for n := 1 to len do - begin - Context.Buffer[Context.Index] := byte(Data[n]); - Inc(Context.Index); - if Context.Index = 64 then - begin - Context.Index := 0; - SHA1Compress(Context); - end; - end; -end; - -//****************************************************************************** -function SHA1Final(var Context: TSHA1Ctx): AnsiString; -type - Pinteger = ^integer; -var - i: integer; - procedure ItoArr(var Ar: Array of byte; I, value: Integer); - begin - Ar[i + 0] := Value and $000000FF; - Ar[i + 1] := (Value shr 8) and $000000FF; - Ar[i + 2] := (Value shr 16) and $000000FF; - Ar[i + 3] := (Value shr 24) and $000000FF; - end; -begin - Context.Buffer[Context.Index] := $80; - if Context.Index >= 56 then - SHA1Compress(Context); - ItoArr(Context.Buffer, 56, RB(Context.Hi)); - ItoArr(Context.Buffer, 60, RB(Context.Lo)); -// Pinteger(@Context.Buffer[56])^ := RB(Context.Hi); -// Pinteger(@Context.Buffer[60])^ := RB(Context.Lo); - SHA1Compress(Context); - Context.Hash[0] := RB(Context.Hash[0]); - Context.Hash[1] := RB(Context.Hash[1]); - Context.Hash[2] := RB(Context.Hash[2]); - Context.Hash[3] := RB(Context.Hash[3]); - Context.Hash[4] := RB(Context.Hash[4]); - ArrLongToByte(Context.Hash, Context.HashByte); - Result := ''; - for i := 0 to 19 do - Result := Result + AnsiChar(Context.HashByte[i]); -end; - -function SHA1(const Value: AnsiString): AnsiString; -var - SHA1Context: TSHA1Ctx; -begin - SHA1Init(SHA1Context); - SHA1Update(SHA1Context, Value); - Result := SHA1Final(SHA1Context); -end; - -{==============================================================================} - -function HMAC_SHA1(Text, Key: AnsiString): AnsiString; -var - ipad, opad, s: AnsiString; - n: Integer; - SHA1Context: TSHA1Ctx; -begin - if Length(Key) > 64 then - Key := SHA1(Key); - ipad := StringOfChar(#$36, 64); - opad := StringOfChar(#$5C, 64); - for n := 1 to Length(Key) do - begin - ipad[n] := AnsiChar(Byte(ipad[n]) xor Byte(Key[n])); - opad[n] := AnsiChar(Byte(opad[n]) xor Byte(Key[n])); - end; - SHA1Init(SHA1Context); - SHA1Update(SHA1Context, ipad); - SHA1Update(SHA1Context, Text); - s := SHA1Final(SHA1Context); - SHA1Init(SHA1Context); - SHA1Update(SHA1Context, opad); - SHA1Update(SHA1Context, s); - Result := SHA1Final(SHA1Context); -end; - -{==============================================================================} - -function SHA1LongHash(const Value: AnsiString; Len: integer): AnsiString; -var - cnt, rest: integer; - l: integer; - n: integer; - SHA1Context: TSHA1Ctx; -begin - l := length(Value); - cnt := Len div l; - rest := Len mod l; - SHA1Init(SHA1Context); - for n := 1 to cnt do - SHA1Update(SHA1Context, Value); - if rest > 0 then - SHA1Update(SHA1Context, Copy(Value, 1, rest)); - Result := SHA1Final(SHA1Context); -end; - -{==============================================================================} - -procedure MD4Transform(var Buf: array of LongInt; const Data: array of LongInt); -var - A, B, C, D: LongInt; - function LRot32(a, b: longint): longint; - begin - Result:= (a shl b) or (a shr (32 - b)); - end; -begin - A := Buf[0]; - B := Buf[1]; - C := Buf[2]; - D := Buf[3]; - - A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 0], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 1], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 2], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 3], 19); - A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 4], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 5], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[ 6], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[ 7], 19); - A:= LRot32(A + (D xor (B and (C xor D))) + Data[ 8], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[ 9], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[10], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[11], 19); - A:= LRot32(A + (D xor (B and (C xor D))) + Data[12], 3); - D:= LRot32(D + (C xor (A and (B xor C))) + Data[13], 7); - C:= LRot32(C + (B xor (D and (A xor B))) + Data[14], 11); - B:= LRot32(B + (A xor (C and (D xor A))) + Data[15], 19); - - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 0] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 4] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 8] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[12] + longint($5a827999), 13); - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 1] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 5] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[ 9] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[13] + longint($5a827999), 13); - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 2] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 6] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[10] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[14] + longint($5a827999), 13); - A:= LRot32(A + ((B and C) or (B and D) or (C and D)) + Data[ 3] + longint($5a827999), 3); - D:= LRot32(D + ((A and B) or (A and C) or (B and C)) + Data[ 7] + longint($5a827999), 5); - C:= LRot32(C + ((D and A) or (D and B) or (A and B)) + Data[11] + longint($5a827999), 9); - B:= LRot32(B + ((C and D) or (C and A) or (D and A)) + Data[15] + longint($5a827999), 13); - - A:= LRot32(A + (B xor C xor D) + Data[ 0] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[ 8] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 4] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[12] + longint($6ed9eba1), 15); - A:= LRot32(A + (B xor C xor D) + Data[ 2] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[10] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 6] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[14] + longint($6ed9eba1), 15); - A:= LRot32(A + (B xor C xor D) + Data[ 1] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[ 9] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 5] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[13] + longint($6ed9eba1), 15); - A:= LRot32(A + (B xor C xor D) + Data[ 3] + longint($6ed9eba1), 3); - D:= LRot32(D + (A xor B xor C) + Data[11] + longint($6ed9eba1), 9); - C:= LRot32(C + (D xor A xor B) + Data[ 7] + longint($6ed9eba1), 11); - B:= LRot32(B + (C xor D xor A) + Data[15] + longint($6ed9eba1), 15); - - Inc(Buf[0], A); - Inc(Buf[1], B); - Inc(Buf[2], C); - Inc(Buf[3], D); -end; - -{==============================================================================} - -function MD4(const Value: AnsiString): AnsiString; -var - MDContext: TMDCtx; -begin - MDInit(MDContext); - MDUpdate(MDContext, Value, @MD4Transform); - Result := MDFinal(MDContext, @MD4Transform); -end; - -{==============================================================================} - - -end. diff --git a/3rd/synapse/source/synacrypt.pas b/3rd/synapse/source/synacrypt.pas deleted file mode 100644 index 31e915d0e..000000000 --- a/3rd/synapse/source/synacrypt.pas +++ /dev/null @@ -1,2412 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.000 | -|==============================================================================| -| Content: Encryption support | -|==============================================================================| -| Copyright (c)2007-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2007-2011. | -| All Rights Reserved. | -| Based on work of David Barton and Eric Young | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Encryption support) - -Implemented are DES and 3DES encryption/decryption by ECB, CBC, CFB-8bit, - CFB-block, OFB and CTR methods. -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synacrypt; - -interface - -uses - SysUtils, Classes, synautil, synafpc; - -type - {:@abstract(Implementation of common routines block ciphers (dafault size is 64-bits)) - - Do not use this class directly, use descendants only!} - TSynaBlockCipher= class(TObject) - protected - procedure InitKey(Key: AnsiString); virtual; - function GetSize: byte; virtual; - private - IV, CV: AnsiString; - procedure IncCounter; - public - {:Sets the IV to Value and performs a reset} - procedure SetIV(const Value: AnsiString); virtual; - {:Returns the current chaining information, not the actual IV} - function GetIV: AnsiString; virtual; - {:Reset any stored chaining information} - procedure Reset; virtual; - {:Encrypt a 64-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; virtual; - {:Decrypt a 64-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; virtual; - {:Encrypt data using the CBC method of encryption} - function EncryptCBC(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CBC method of decryption} - function DecryptCBC(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the CFB (8 bit) method of encryption} - function EncryptCFB8bit(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CFB (8 bit) method of decryption} - function DecryptCFB8bit(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the CFB (block) method of encryption} - function EncryptCFBblock(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CFB (block) method of decryption} - function DecryptCFBblock(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the OFB method of encryption} - function EncryptOFB(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the OFB method of decryption} - function DecryptOFB(const Indata: AnsiString): AnsiString; virtual; - {:Encrypt data using the CTR method of encryption} - function EncryptCTR(const Indata: AnsiString): AnsiString; virtual; - {:Decrypt data using the CTR method of decryption} - function DecryptCTR(const Indata: AnsiString): AnsiString; virtual; - {:Create a encryptor/decryptor instance and initialize it by the Key.} - constructor Create(Key: AnsiString); - end; - - {:@abstract(Datatype for holding one DES key data) - - This data type is used internally.} - TDesKeyData = array[0..31] of integer; - - {:@abstract(Implementation of common routines for DES encryption) - - Do not use this class directly, use descendants only!} - TSynaCustomDes = class(TSynaBlockcipher) - protected - procedure DoInit(KeyB: AnsiString; var KeyData: TDesKeyData); - function EncryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; - function DecryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; - end; - - {:@abstract(Implementation of DES encryption)} - TSynaDes= class(TSynaCustomDes) - protected - KeyData: TDesKeyData; - procedure InitKey(Key: AnsiString); override; - public - {:Encrypt a 64-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; override; - {:Decrypt a 64-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; override; - end; - - {:@abstract(Implementation of 3DES encryption)} - TSyna3Des= class(TSynaCustomDes) - protected - KeyData: array[0..2] of TDesKeyData; - procedure InitKey(Key: AnsiString); override; - public - {:Encrypt a 64-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; override; - {:Decrypt a 64-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; override; - end; - -const - BC = 4; - MAXROUNDS = 14; -type - {:@abstract(Implementation of AES encryption)} - TSynaAes= class(TSynaBlockcipher) - protected - numrounds: longword; - rk, drk: array[0..MAXROUNDS,0..7] of longword; - procedure InitKey(Key: AnsiString); override; - function GetSize: byte; override; - public - {:Encrypt a 128-bit block of data using the ECB method of encryption} - function EncryptECB(const InData: AnsiString): AnsiString; override; - {:Decrypt a 128-bit block of data using the ECB method of decryption} - function DecryptECB(const InData: AnsiString): AnsiString; override; - end; - -{:Call internal test of all DES encryptions. Returns @true if all is OK.} -function TestDes: boolean; -{:Call internal test of all 3DES encryptions. Returns @true if all is OK.} -function Test3Des: boolean; -{:Call internal test of all AES encryptions. Returns @true if all is OK.} -function TestAes: boolean; - -{==============================================================================} -implementation - -//DES consts -const - shifts2: array[0..15]of byte= - (0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0); - - des_skb: array[0..7,0..63]of integer=( - ( - (* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 *) - integer($00000000),integer($00000010),integer($20000000),integer($20000010), - integer($00010000),integer($00010010),integer($20010000),integer($20010010), - integer($00000800),integer($00000810),integer($20000800),integer($20000810), - integer($00010800),integer($00010810),integer($20010800),integer($20010810), - integer($00000020),integer($00000030),integer($20000020),integer($20000030), - integer($00010020),integer($00010030),integer($20010020),integer($20010030), - integer($00000820),integer($00000830),integer($20000820),integer($20000830), - integer($00010820),integer($00010830),integer($20010820),integer($20010830), - integer($00080000),integer($00080010),integer($20080000),integer($20080010), - integer($00090000),integer($00090010),integer($20090000),integer($20090010), - integer($00080800),integer($00080810),integer($20080800),integer($20080810), - integer($00090800),integer($00090810),integer($20090800),integer($20090810), - integer($00080020),integer($00080030),integer($20080020),integer($20080030), - integer($00090020),integer($00090030),integer($20090020),integer($20090030), - integer($00080820),integer($00080830),integer($20080820),integer($20080830), - integer($00090820),integer($00090830),integer($20090820),integer($20090830) - ),( - (* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 *) - integer($00000000),integer($02000000),integer($00002000),integer($02002000), - integer($00200000),integer($02200000),integer($00202000),integer($02202000), - integer($00000004),integer($02000004),integer($00002004),integer($02002004), - integer($00200004),integer($02200004),integer($00202004),integer($02202004), - integer($00000400),integer($02000400),integer($00002400),integer($02002400), - integer($00200400),integer($02200400),integer($00202400),integer($02202400), - integer($00000404),integer($02000404),integer($00002404),integer($02002404), - integer($00200404),integer($02200404),integer($00202404),integer($02202404), - integer($10000000),integer($12000000),integer($10002000),integer($12002000), - integer($10200000),integer($12200000),integer($10202000),integer($12202000), - integer($10000004),integer($12000004),integer($10002004),integer($12002004), - integer($10200004),integer($12200004),integer($10202004),integer($12202004), - integer($10000400),integer($12000400),integer($10002400),integer($12002400), - integer($10200400),integer($12200400),integer($10202400),integer($12202400), - integer($10000404),integer($12000404),integer($10002404),integer($12002404), - integer($10200404),integer($12200404),integer($10202404),integer($12202404) - ),( - (* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 *) - integer($00000000),integer($00000001),integer($00040000),integer($00040001), - integer($01000000),integer($01000001),integer($01040000),integer($01040001), - integer($00000002),integer($00000003),integer($00040002),integer($00040003), - integer($01000002),integer($01000003),integer($01040002),integer($01040003), - integer($00000200),integer($00000201),integer($00040200),integer($00040201), - integer($01000200),integer($01000201),integer($01040200),integer($01040201), - integer($00000202),integer($00000203),integer($00040202),integer($00040203), - integer($01000202),integer($01000203),integer($01040202),integer($01040203), - integer($08000000),integer($08000001),integer($08040000),integer($08040001), - integer($09000000),integer($09000001),integer($09040000),integer($09040001), - integer($08000002),integer($08000003),integer($08040002),integer($08040003), - integer($09000002),integer($09000003),integer($09040002),integer($09040003), - integer($08000200),integer($08000201),integer($08040200),integer($08040201), - integer($09000200),integer($09000201),integer($09040200),integer($09040201), - integer($08000202),integer($08000203),integer($08040202),integer($08040203), - integer($09000202),integer($09000203),integer($09040202),integer($09040203) - ),( - (* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 *) - integer($00000000),integer($00100000),integer($00000100),integer($00100100), - integer($00000008),integer($00100008),integer($00000108),integer($00100108), - integer($00001000),integer($00101000),integer($00001100),integer($00101100), - integer($00001008),integer($00101008),integer($00001108),integer($00101108), - integer($04000000),integer($04100000),integer($04000100),integer($04100100), - integer($04000008),integer($04100008),integer($04000108),integer($04100108), - integer($04001000),integer($04101000),integer($04001100),integer($04101100), - integer($04001008),integer($04101008),integer($04001108),integer($04101108), - integer($00020000),integer($00120000),integer($00020100),integer($00120100), - integer($00020008),integer($00120008),integer($00020108),integer($00120108), - integer($00021000),integer($00121000),integer($00021100),integer($00121100), - integer($00021008),integer($00121008),integer($00021108),integer($00121108), - integer($04020000),integer($04120000),integer($04020100),integer($04120100), - integer($04020008),integer($04120008),integer($04020108),integer($04120108), - integer($04021000),integer($04121000),integer($04021100),integer($04121100), - integer($04021008),integer($04121008),integer($04021108),integer($04121108) - ),( - (* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 *) - integer($00000000),integer($10000000),integer($00010000),integer($10010000), - integer($00000004),integer($10000004),integer($00010004),integer($10010004), - integer($20000000),integer($30000000),integer($20010000),integer($30010000), - integer($20000004),integer($30000004),integer($20010004),integer($30010004), - integer($00100000),integer($10100000),integer($00110000),integer($10110000), - integer($00100004),integer($10100004),integer($00110004),integer($10110004), - integer($20100000),integer($30100000),integer($20110000),integer($30110000), - integer($20100004),integer($30100004),integer($20110004),integer($30110004), - integer($00001000),integer($10001000),integer($00011000),integer($10011000), - integer($00001004),integer($10001004),integer($00011004),integer($10011004), - integer($20001000),integer($30001000),integer($20011000),integer($30011000), - integer($20001004),integer($30001004),integer($20011004),integer($30011004), - integer($00101000),integer($10101000),integer($00111000),integer($10111000), - integer($00101004),integer($10101004),integer($00111004),integer($10111004), - integer($20101000),integer($30101000),integer($20111000),integer($30111000), - integer($20101004),integer($30101004),integer($20111004),integer($30111004) - ),( - (* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 *) - integer($00000000),integer($08000000),integer($00000008),integer($08000008), - integer($00000400),integer($08000400),integer($00000408),integer($08000408), - integer($00020000),integer($08020000),integer($00020008),integer($08020008), - integer($00020400),integer($08020400),integer($00020408),integer($08020408), - integer($00000001),integer($08000001),integer($00000009),integer($08000009), - integer($00000401),integer($08000401),integer($00000409),integer($08000409), - integer($00020001),integer($08020001),integer($00020009),integer($08020009), - integer($00020401),integer($08020401),integer($00020409),integer($08020409), - integer($02000000),integer($0A000000),integer($02000008),integer($0A000008), - integer($02000400),integer($0A000400),integer($02000408),integer($0A000408), - integer($02020000),integer($0A020000),integer($02020008),integer($0A020008), - integer($02020400),integer($0A020400),integer($02020408),integer($0A020408), - integer($02000001),integer($0A000001),integer($02000009),integer($0A000009), - integer($02000401),integer($0A000401),integer($02000409),integer($0A000409), - integer($02020001),integer($0A020001),integer($02020009),integer($0A020009), - integer($02020401),integer($0A020401),integer($02020409),integer($0A020409) - ),( - (* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 *) - integer($00000000),integer($00000100),integer($00080000),integer($00080100), - integer($01000000),integer($01000100),integer($01080000),integer($01080100), - integer($00000010),integer($00000110),integer($00080010),integer($00080110), - integer($01000010),integer($01000110),integer($01080010),integer($01080110), - integer($00200000),integer($00200100),integer($00280000),integer($00280100), - integer($01200000),integer($01200100),integer($01280000),integer($01280100), - integer($00200010),integer($00200110),integer($00280010),integer($00280110), - integer($01200010),integer($01200110),integer($01280010),integer($01280110), - integer($00000200),integer($00000300),integer($00080200),integer($00080300), - integer($01000200),integer($01000300),integer($01080200),integer($01080300), - integer($00000210),integer($00000310),integer($00080210),integer($00080310), - integer($01000210),integer($01000310),integer($01080210),integer($01080310), - integer($00200200),integer($00200300),integer($00280200),integer($00280300), - integer($01200200),integer($01200300),integer($01280200),integer($01280300), - integer($00200210),integer($00200310),integer($00280210),integer($00280310), - integer($01200210),integer($01200310),integer($01280210),integer($01280310) - ),( - (* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 *) - integer($00000000),integer($04000000),integer($00040000),integer($04040000), - integer($00000002),integer($04000002),integer($00040002),integer($04040002), - integer($00002000),integer($04002000),integer($00042000),integer($04042000), - integer($00002002),integer($04002002),integer($00042002),integer($04042002), - integer($00000020),integer($04000020),integer($00040020),integer($04040020), - integer($00000022),integer($04000022),integer($00040022),integer($04040022), - integer($00002020),integer($04002020),integer($00042020),integer($04042020), - integer($00002022),integer($04002022),integer($00042022),integer($04042022), - integer($00000800),integer($04000800),integer($00040800),integer($04040800), - integer($00000802),integer($04000802),integer($00040802),integer($04040802), - integer($00002800),integer($04002800),integer($00042800),integer($04042800), - integer($00002802),integer($04002802),integer($00042802),integer($04042802), - integer($00000820),integer($04000820),integer($00040820),integer($04040820), - integer($00000822),integer($04000822),integer($00040822),integer($04040822), - integer($00002820),integer($04002820),integer($00042820),integer($04042820), - integer($00002822),integer($04002822),integer($00042822),integer($04042822) - )); - - des_sptrans: array[0..7,0..63] of integer=( - ( - (* nibble 0 *) - integer($02080800), integer($00080000), integer($02000002), integer($02080802), - integer($02000000), integer($00080802), integer($00080002), integer($02000002), - integer($00080802), integer($02080800), integer($02080000), integer($00000802), - integer($02000802), integer($02000000), integer($00000000), integer($00080002), - integer($00080000), integer($00000002), integer($02000800), integer($00080800), - integer($02080802), integer($02080000), integer($00000802), integer($02000800), - integer($00000002), integer($00000800), integer($00080800), integer($02080002), - integer($00000800), integer($02000802), integer($02080002), integer($00000000), - integer($00000000), integer($02080802), integer($02000800), integer($00080002), - integer($02080800), integer($00080000), integer($00000802), integer($02000800), - integer($02080002), integer($00000800), integer($00080800), integer($02000002), - integer($00080802), integer($00000002), integer($02000002), integer($02080000), - integer($02080802), integer($00080800), integer($02080000), integer($02000802), - integer($02000000), integer($00000802), integer($00080002), integer($00000000), - integer($00080000), integer($02000000), integer($02000802), integer($02080800), - integer($00000002), integer($02080002), integer($00000800), integer($00080802) - ),( - (* nibble 1 *) - integer($40108010), integer($00000000), integer($00108000), integer($40100000), - integer($40000010), integer($00008010), integer($40008000), integer($00108000), - integer($00008000), integer($40100010), integer($00000010), integer($40008000), - integer($00100010), integer($40108000), integer($40100000), integer($00000010), - integer($00100000), integer($40008010), integer($40100010), integer($00008000), - integer($00108010), integer($40000000), integer($00000000), integer($00100010), - integer($40008010), integer($00108010), integer($40108000), integer($40000010), - integer($40000000), integer($00100000), integer($00008010), integer($40108010), - integer($00100010), integer($40108000), integer($40008000), integer($00108010), - integer($40108010), integer($00100010), integer($40000010), integer($00000000), - integer($40000000), integer($00008010), integer($00100000), integer($40100010), - integer($00008000), integer($40000000), integer($00108010), integer($40008010), - integer($40108000), integer($00008000), integer($00000000), integer($40000010), - integer($00000010), integer($40108010), integer($00108000), integer($40100000), - integer($40100010), integer($00100000), integer($00008010), integer($40008000), - integer($40008010), integer($00000010), integer($40100000), integer($00108000) - ),( - (* nibble 2 *) - integer($04000001), integer($04040100), integer($00000100), integer($04000101), - integer($00040001), integer($04000000), integer($04000101), integer($00040100), - integer($04000100), integer($00040000), integer($04040000), integer($00000001), - integer($04040101), integer($00000101), integer($00000001), integer($04040001), - integer($00000000), integer($00040001), integer($04040100), integer($00000100), - integer($00000101), integer($04040101), integer($00040000), integer($04000001), - integer($04040001), integer($04000100), integer($00040101), integer($04040000), - integer($00040100), integer($00000000), integer($04000000), integer($00040101), - integer($04040100), integer($00000100), integer($00000001), integer($00040000), - integer($00000101), integer($00040001), integer($04040000), integer($04000101), - integer($00000000), integer($04040100), integer($00040100), integer($04040001), - integer($00040001), integer($04000000), integer($04040101), integer($00000001), - integer($00040101), integer($04000001), integer($04000000), integer($04040101), - integer($00040000), integer($04000100), integer($04000101), integer($00040100), - integer($04000100), integer($00000000), integer($04040001), integer($00000101), - integer($04000001), integer($00040101), integer($00000100), integer($04040000) - ),( - (* nibble 3 *) - integer($00401008), integer($10001000), integer($00000008), integer($10401008), - integer($00000000), integer($10400000), integer($10001008), integer($00400008), - integer($10401000), integer($10000008), integer($10000000), integer($00001008), - integer($10000008), integer($00401008), integer($00400000), integer($10000000), - integer($10400008), integer($00401000), integer($00001000), integer($00000008), - integer($00401000), integer($10001008), integer($10400000), integer($00001000), - integer($00001008), integer($00000000), integer($00400008), integer($10401000), - integer($10001000), integer($10400008), integer($10401008), integer($00400000), - integer($10400008), integer($00001008), integer($00400000), integer($10000008), - integer($00401000), integer($10001000), integer($00000008), integer($10400000), - integer($10001008), integer($00000000), integer($00001000), integer($00400008), - integer($00000000), integer($10400008), integer($10401000), integer($00001000), - integer($10000000), integer($10401008), integer($00401008), integer($00400000), - integer($10401008), integer($00000008), integer($10001000), integer($00401008), - integer($00400008), integer($00401000), integer($10400000), integer($10001008), - integer($00001008), integer($10000000), integer($10000008), integer($10401000) - ),( - (* nibble 4 *) - integer($08000000), integer($00010000), integer($00000400), integer($08010420), - integer($08010020), integer($08000400), integer($00010420), integer($08010000), - integer($00010000), integer($00000020), integer($08000020), integer($00010400), - integer($08000420), integer($08010020), integer($08010400), integer($00000000), - integer($00010400), integer($08000000), integer($00010020), integer($00000420), - integer($08000400), integer($00010420), integer($00000000), integer($08000020), - integer($00000020), integer($08000420), integer($08010420), integer($00010020), - integer($08010000), integer($00000400), integer($00000420), integer($08010400), - integer($08010400), integer($08000420), integer($00010020), integer($08010000), - integer($00010000), integer($00000020), integer($08000020), integer($08000400), - integer($08000000), integer($00010400), integer($08010420), integer($00000000), - integer($00010420), integer($08000000), integer($00000400), integer($00010020), - integer($08000420), integer($00000400), integer($00000000), integer($08010420), - integer($08010020), integer($08010400), integer($00000420), integer($00010000), - integer($00010400), integer($08010020), integer($08000400), integer($00000420), - integer($00000020), integer($00010420), integer($08010000), integer($08000020) - ),( - (* nibble 5 *) - integer($80000040), integer($00200040), integer($00000000), integer($80202000), - integer($00200040), integer($00002000), integer($80002040), integer($00200000), - integer($00002040), integer($80202040), integer($00202000), integer($80000000), - integer($80002000), integer($80000040), integer($80200000), integer($00202040), - integer($00200000), integer($80002040), integer($80200040), integer($00000000), - integer($00002000), integer($00000040), integer($80202000), integer($80200040), - integer($80202040), integer($80200000), integer($80000000), integer($00002040), - integer($00000040), integer($00202000), integer($00202040), integer($80002000), - integer($00002040), integer($80000000), integer($80002000), integer($00202040), - integer($80202000), integer($00200040), integer($00000000), integer($80002000), - integer($80000000), integer($00002000), integer($80200040), integer($00200000), - integer($00200040), integer($80202040), integer($00202000), integer($00000040), - integer($80202040), integer($00202000), integer($00200000), integer($80002040), - integer($80000040), integer($80200000), integer($00202040), integer($00000000), - integer($00002000), integer($80000040), integer($80002040), integer($80202000), - integer($80200000), integer($00002040), integer($00000040), integer($80200040) - ),( - (* nibble 6 *) - integer($00004000), integer($00000200), integer($01000200), integer($01000004), - integer($01004204), integer($00004004), integer($00004200), integer($00000000), - integer($01000000), integer($01000204), integer($00000204), integer($01004000), - integer($00000004), integer($01004200), integer($01004000), integer($00000204), - integer($01000204), integer($00004000), integer($00004004), integer($01004204), - integer($00000000), integer($01000200), integer($01000004), integer($00004200), - integer($01004004), integer($00004204), integer($01004200), integer($00000004), - integer($00004204), integer($01004004), integer($00000200), integer($01000000), - integer($00004204), integer($01004000), integer($01004004), integer($00000204), - integer($00004000), integer($00000200), integer($01000000), integer($01004004), - integer($01000204), integer($00004204), integer($00004200), integer($00000000), - integer($00000200), integer($01000004), integer($00000004), integer($01000200), - integer($00000000), integer($01000204), integer($01000200), integer($00004200), - integer($00000204), integer($00004000), integer($01004204), integer($01000000), - integer($01004200), integer($00000004), integer($00004004), integer($01004204), - integer($01000004), integer($01004200), integer($01004000), integer($00004004) - ),( - (* nibble 7 *) - integer($20800080), integer($20820000), integer($00020080), integer($00000000), - integer($20020000), integer($00800080), integer($20800000), integer($20820080), - integer($00000080), integer($20000000), integer($00820000), integer($00020080), - integer($00820080), integer($20020080), integer($20000080), integer($20800000), - integer($00020000), integer($00820080), integer($00800080), integer($20020000), - integer($20820080), integer($20000080), integer($00000000), integer($00820000), - integer($20000000), integer($00800000), integer($20020080), integer($20800080), - integer($00800000), integer($00020000), integer($20820000), integer($00000080), - integer($00800000), integer($00020000), integer($20000080), integer($20820080), - integer($00020080), integer($20000000), integer($00000000), integer($00820000), - integer($20800080), integer($20020080), integer($20020000), integer($00800080), - integer($20820000), integer($00000080), integer($00800080), integer($20020000), - integer($20820080), integer($00800000), integer($20800000), integer($20000080), - integer($00820000), integer($00020080), integer($20020080), integer($20800000), - integer($00000080), integer($20820000), integer($00820080), integer($00000000), - integer($20000000), integer($20800080), integer($00020000), integer($00820080) - )); - -//AES consts -const - MAXBC= 8; - MAXKC= 8; - - S: array[0..255] of byte= ( - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, - 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, - 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, - 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, - 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, - 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, - 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, - 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, - 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, - 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, - 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, - 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22); - T1: array[0..255,0..3] of byte= ( - ($c6,$63,$63,$a5), ($f8,$7c,$7c,$84), ($ee,$77,$77,$99), ($f6,$7b,$7b,$8d), - ($ff,$f2,$f2,$0d), ($d6,$6b,$6b,$bd), ($de,$6f,$6f,$b1), ($91,$c5,$c5,$54), - ($60,$30,$30,$50), ($02,$01,$01,$03), ($ce,$67,$67,$a9), ($56,$2b,$2b,$7d), - ($e7,$fe,$fe,$19), ($b5,$d7,$d7,$62), ($4d,$ab,$ab,$e6), ($ec,$76,$76,$9a), - ($8f,$ca,$ca,$45), ($1f,$82,$82,$9d), ($89,$c9,$c9,$40), ($fa,$7d,$7d,$87), - ($ef,$fa,$fa,$15), ($b2,$59,$59,$eb), ($8e,$47,$47,$c9), ($fb,$f0,$f0,$0b), - ($41,$ad,$ad,$ec), ($b3,$d4,$d4,$67), ($5f,$a2,$a2,$fd), ($45,$af,$af,$ea), - ($23,$9c,$9c,$bf), ($53,$a4,$a4,$f7), ($e4,$72,$72,$96), ($9b,$c0,$c0,$5b), - ($75,$b7,$b7,$c2), ($e1,$fd,$fd,$1c), ($3d,$93,$93,$ae), ($4c,$26,$26,$6a), - ($6c,$36,$36,$5a), ($7e,$3f,$3f,$41), ($f5,$f7,$f7,$02), ($83,$cc,$cc,$4f), - ($68,$34,$34,$5c), ($51,$a5,$a5,$f4), ($d1,$e5,$e5,$34), ($f9,$f1,$f1,$08), - ($e2,$71,$71,$93), ($ab,$d8,$d8,$73), ($62,$31,$31,$53), ($2a,$15,$15,$3f), - ($08,$04,$04,$0c), ($95,$c7,$c7,$52), ($46,$23,$23,$65), ($9d,$c3,$c3,$5e), - ($30,$18,$18,$28), ($37,$96,$96,$a1), ($0a,$05,$05,$0f), ($2f,$9a,$9a,$b5), - ($0e,$07,$07,$09), ($24,$12,$12,$36), ($1b,$80,$80,$9b), ($df,$e2,$e2,$3d), - ($cd,$eb,$eb,$26), ($4e,$27,$27,$69), ($7f,$b2,$b2,$cd), ($ea,$75,$75,$9f), - ($12,$09,$09,$1b), ($1d,$83,$83,$9e), ($58,$2c,$2c,$74), ($34,$1a,$1a,$2e), - ($36,$1b,$1b,$2d), ($dc,$6e,$6e,$b2), ($b4,$5a,$5a,$ee), ($5b,$a0,$a0,$fb), - ($a4,$52,$52,$f6), ($76,$3b,$3b,$4d), ($b7,$d6,$d6,$61), ($7d,$b3,$b3,$ce), - ($52,$29,$29,$7b), ($dd,$e3,$e3,$3e), ($5e,$2f,$2f,$71), ($13,$84,$84,$97), - ($a6,$53,$53,$f5), ($b9,$d1,$d1,$68), ($00,$00,$00,$00), ($c1,$ed,$ed,$2c), - ($40,$20,$20,$60), ($e3,$fc,$fc,$1f), ($79,$b1,$b1,$c8), ($b6,$5b,$5b,$ed), - ($d4,$6a,$6a,$be), ($8d,$cb,$cb,$46), ($67,$be,$be,$d9), ($72,$39,$39,$4b), - ($94,$4a,$4a,$de), ($98,$4c,$4c,$d4), ($b0,$58,$58,$e8), ($85,$cf,$cf,$4a), - ($bb,$d0,$d0,$6b), ($c5,$ef,$ef,$2a), ($4f,$aa,$aa,$e5), ($ed,$fb,$fb,$16), - ($86,$43,$43,$c5), ($9a,$4d,$4d,$d7), ($66,$33,$33,$55), ($11,$85,$85,$94), - ($8a,$45,$45,$cf), ($e9,$f9,$f9,$10), ($04,$02,$02,$06), ($fe,$7f,$7f,$81), - ($a0,$50,$50,$f0), ($78,$3c,$3c,$44), ($25,$9f,$9f,$ba), ($4b,$a8,$a8,$e3), - ($a2,$51,$51,$f3), ($5d,$a3,$a3,$fe), ($80,$40,$40,$c0), ($05,$8f,$8f,$8a), - ($3f,$92,$92,$ad), ($21,$9d,$9d,$bc), ($70,$38,$38,$48), ($f1,$f5,$f5,$04), - ($63,$bc,$bc,$df), ($77,$b6,$b6,$c1), ($af,$da,$da,$75), ($42,$21,$21,$63), - ($20,$10,$10,$30), ($e5,$ff,$ff,$1a), ($fd,$f3,$f3,$0e), ($bf,$d2,$d2,$6d), - ($81,$cd,$cd,$4c), ($18,$0c,$0c,$14), ($26,$13,$13,$35), ($c3,$ec,$ec,$2f), - ($be,$5f,$5f,$e1), ($35,$97,$97,$a2), ($88,$44,$44,$cc), ($2e,$17,$17,$39), - ($93,$c4,$c4,$57), ($55,$a7,$a7,$f2), ($fc,$7e,$7e,$82), ($7a,$3d,$3d,$47), - ($c8,$64,$64,$ac), ($ba,$5d,$5d,$e7), ($32,$19,$19,$2b), ($e6,$73,$73,$95), - ($c0,$60,$60,$a0), ($19,$81,$81,$98), ($9e,$4f,$4f,$d1), ($a3,$dc,$dc,$7f), - ($44,$22,$22,$66), ($54,$2a,$2a,$7e), ($3b,$90,$90,$ab), ($0b,$88,$88,$83), - ($8c,$46,$46,$ca), ($c7,$ee,$ee,$29), ($6b,$b8,$b8,$d3), ($28,$14,$14,$3c), - ($a7,$de,$de,$79), ($bc,$5e,$5e,$e2), ($16,$0b,$0b,$1d), ($ad,$db,$db,$76), - ($db,$e0,$e0,$3b), ($64,$32,$32,$56), ($74,$3a,$3a,$4e), ($14,$0a,$0a,$1e), - ($92,$49,$49,$db), ($0c,$06,$06,$0a), ($48,$24,$24,$6c), ($b8,$5c,$5c,$e4), - ($9f,$c2,$c2,$5d), ($bd,$d3,$d3,$6e), ($43,$ac,$ac,$ef), ($c4,$62,$62,$a6), - ($39,$91,$91,$a8), ($31,$95,$95,$a4), ($d3,$e4,$e4,$37), ($f2,$79,$79,$8b), - ($d5,$e7,$e7,$32), ($8b,$c8,$c8,$43), ($6e,$37,$37,$59), ($da,$6d,$6d,$b7), - ($01,$8d,$8d,$8c), ($b1,$d5,$d5,$64), ($9c,$4e,$4e,$d2), ($49,$a9,$a9,$e0), - ($d8,$6c,$6c,$b4), ($ac,$56,$56,$fa), ($f3,$f4,$f4,$07), ($cf,$ea,$ea,$25), - ($ca,$65,$65,$af), ($f4,$7a,$7a,$8e), ($47,$ae,$ae,$e9), ($10,$08,$08,$18), - ($6f,$ba,$ba,$d5), ($f0,$78,$78,$88), ($4a,$25,$25,$6f), ($5c,$2e,$2e,$72), - ($38,$1c,$1c,$24), ($57,$a6,$a6,$f1), ($73,$b4,$b4,$c7), ($97,$c6,$c6,$51), - ($cb,$e8,$e8,$23), ($a1,$dd,$dd,$7c), ($e8,$74,$74,$9c), ($3e,$1f,$1f,$21), - ($96,$4b,$4b,$dd), ($61,$bd,$bd,$dc), ($0d,$8b,$8b,$86), ($0f,$8a,$8a,$85), - ($e0,$70,$70,$90), ($7c,$3e,$3e,$42), ($71,$b5,$b5,$c4), ($cc,$66,$66,$aa), - ($90,$48,$48,$d8), ($06,$03,$03,$05), ($f7,$f6,$f6,$01), ($1c,$0e,$0e,$12), - ($c2,$61,$61,$a3), ($6a,$35,$35,$5f), ($ae,$57,$57,$f9), ($69,$b9,$b9,$d0), - ($17,$86,$86,$91), ($99,$c1,$c1,$58), ($3a,$1d,$1d,$27), ($27,$9e,$9e,$b9), - ($d9,$e1,$e1,$38), ($eb,$f8,$f8,$13), ($2b,$98,$98,$b3), ($22,$11,$11,$33), - ($d2,$69,$69,$bb), ($a9,$d9,$d9,$70), ($07,$8e,$8e,$89), ($33,$94,$94,$a7), - ($2d,$9b,$9b,$b6), ($3c,$1e,$1e,$22), ($15,$87,$87,$92), ($c9,$e9,$e9,$20), - ($87,$ce,$ce,$49), ($aa,$55,$55,$ff), ($50,$28,$28,$78), ($a5,$df,$df,$7a), - ($03,$8c,$8c,$8f), ($59,$a1,$a1,$f8), ($09,$89,$89,$80), ($1a,$0d,$0d,$17), - ($65,$bf,$bf,$da), ($d7,$e6,$e6,$31), ($84,$42,$42,$c6), ($d0,$68,$68,$b8), - ($82,$41,$41,$c3), ($29,$99,$99,$b0), ($5a,$2d,$2d,$77), ($1e,$0f,$0f,$11), - ($7b,$b0,$b0,$cb), ($a8,$54,$54,$fc), ($6d,$bb,$bb,$d6), ($2c,$16,$16,$3a)); - T2: array[0..255,0..3] of byte= ( - ($a5,$c6,$63,$63), ($84,$f8,$7c,$7c), ($99,$ee,$77,$77), ($8d,$f6,$7b,$7b), - ($0d,$ff,$f2,$f2), ($bd,$d6,$6b,$6b), ($b1,$de,$6f,$6f), ($54,$91,$c5,$c5), - ($50,$60,$30,$30), ($03,$02,$01,$01), ($a9,$ce,$67,$67), ($7d,$56,$2b,$2b), - ($19,$e7,$fe,$fe), ($62,$b5,$d7,$d7), ($e6,$4d,$ab,$ab), ($9a,$ec,$76,$76), - ($45,$8f,$ca,$ca), ($9d,$1f,$82,$82), ($40,$89,$c9,$c9), ($87,$fa,$7d,$7d), - ($15,$ef,$fa,$fa), ($eb,$b2,$59,$59), ($c9,$8e,$47,$47), ($0b,$fb,$f0,$f0), - ($ec,$41,$ad,$ad), ($67,$b3,$d4,$d4), ($fd,$5f,$a2,$a2), ($ea,$45,$af,$af), - ($bf,$23,$9c,$9c), ($f7,$53,$a4,$a4), ($96,$e4,$72,$72), ($5b,$9b,$c0,$c0), - ($c2,$75,$b7,$b7), ($1c,$e1,$fd,$fd), ($ae,$3d,$93,$93), ($6a,$4c,$26,$26), - ($5a,$6c,$36,$36), ($41,$7e,$3f,$3f), ($02,$f5,$f7,$f7), ($4f,$83,$cc,$cc), - ($5c,$68,$34,$34), ($f4,$51,$a5,$a5), ($34,$d1,$e5,$e5), ($08,$f9,$f1,$f1), - ($93,$e2,$71,$71), ($73,$ab,$d8,$d8), ($53,$62,$31,$31), ($3f,$2a,$15,$15), - ($0c,$08,$04,$04), ($52,$95,$c7,$c7), ($65,$46,$23,$23), ($5e,$9d,$c3,$c3), - ($28,$30,$18,$18), ($a1,$37,$96,$96), ($0f,$0a,$05,$05), ($b5,$2f,$9a,$9a), - ($09,$0e,$07,$07), ($36,$24,$12,$12), ($9b,$1b,$80,$80), ($3d,$df,$e2,$e2), - ($26,$cd,$eb,$eb), ($69,$4e,$27,$27), ($cd,$7f,$b2,$b2), ($9f,$ea,$75,$75), - ($1b,$12,$09,$09), ($9e,$1d,$83,$83), ($74,$58,$2c,$2c), ($2e,$34,$1a,$1a), - ($2d,$36,$1b,$1b), ($b2,$dc,$6e,$6e), ($ee,$b4,$5a,$5a), ($fb,$5b,$a0,$a0), - ($f6,$a4,$52,$52), ($4d,$76,$3b,$3b), ($61,$b7,$d6,$d6), ($ce,$7d,$b3,$b3), - ($7b,$52,$29,$29), ($3e,$dd,$e3,$e3), ($71,$5e,$2f,$2f), ($97,$13,$84,$84), - ($f5,$a6,$53,$53), ($68,$b9,$d1,$d1), ($00,$00,$00,$00), ($2c,$c1,$ed,$ed), - ($60,$40,$20,$20), ($1f,$e3,$fc,$fc), ($c8,$79,$b1,$b1), ($ed,$b6,$5b,$5b), - ($be,$d4,$6a,$6a), ($46,$8d,$cb,$cb), ($d9,$67,$be,$be), ($4b,$72,$39,$39), - ($de,$94,$4a,$4a), ($d4,$98,$4c,$4c), ($e8,$b0,$58,$58), ($4a,$85,$cf,$cf), - ($6b,$bb,$d0,$d0), ($2a,$c5,$ef,$ef), ($e5,$4f,$aa,$aa), ($16,$ed,$fb,$fb), - ($c5,$86,$43,$43), ($d7,$9a,$4d,$4d), ($55,$66,$33,$33), ($94,$11,$85,$85), - ($cf,$8a,$45,$45), ($10,$e9,$f9,$f9), ($06,$04,$02,$02), ($81,$fe,$7f,$7f), - ($f0,$a0,$50,$50), ($44,$78,$3c,$3c), ($ba,$25,$9f,$9f), ($e3,$4b,$a8,$a8), - ($f3,$a2,$51,$51), ($fe,$5d,$a3,$a3), ($c0,$80,$40,$40), ($8a,$05,$8f,$8f), - ($ad,$3f,$92,$92), ($bc,$21,$9d,$9d), ($48,$70,$38,$38), ($04,$f1,$f5,$f5), - ($df,$63,$bc,$bc), ($c1,$77,$b6,$b6), ($75,$af,$da,$da), ($63,$42,$21,$21), - ($30,$20,$10,$10), ($1a,$e5,$ff,$ff), ($0e,$fd,$f3,$f3), ($6d,$bf,$d2,$d2), - ($4c,$81,$cd,$cd), ($14,$18,$0c,$0c), ($35,$26,$13,$13), ($2f,$c3,$ec,$ec), - ($e1,$be,$5f,$5f), ($a2,$35,$97,$97), ($cc,$88,$44,$44), ($39,$2e,$17,$17), - ($57,$93,$c4,$c4), ($f2,$55,$a7,$a7), ($82,$fc,$7e,$7e), ($47,$7a,$3d,$3d), - ($ac,$c8,$64,$64), ($e7,$ba,$5d,$5d), ($2b,$32,$19,$19), ($95,$e6,$73,$73), - ($a0,$c0,$60,$60), ($98,$19,$81,$81), ($d1,$9e,$4f,$4f), ($7f,$a3,$dc,$dc), - ($66,$44,$22,$22), ($7e,$54,$2a,$2a), ($ab,$3b,$90,$90), ($83,$0b,$88,$88), - ($ca,$8c,$46,$46), ($29,$c7,$ee,$ee), ($d3,$6b,$b8,$b8), ($3c,$28,$14,$14), - ($79,$a7,$de,$de), ($e2,$bc,$5e,$5e), ($1d,$16,$0b,$0b), ($76,$ad,$db,$db), - ($3b,$db,$e0,$e0), ($56,$64,$32,$32), ($4e,$74,$3a,$3a), ($1e,$14,$0a,$0a), - ($db,$92,$49,$49), ($0a,$0c,$06,$06), ($6c,$48,$24,$24), ($e4,$b8,$5c,$5c), - ($5d,$9f,$c2,$c2), ($6e,$bd,$d3,$d3), ($ef,$43,$ac,$ac), ($a6,$c4,$62,$62), - ($a8,$39,$91,$91), ($a4,$31,$95,$95), ($37,$d3,$e4,$e4), ($8b,$f2,$79,$79), - ($32,$d5,$e7,$e7), ($43,$8b,$c8,$c8), ($59,$6e,$37,$37), ($b7,$da,$6d,$6d), - ($8c,$01,$8d,$8d), ($64,$b1,$d5,$d5), ($d2,$9c,$4e,$4e), ($e0,$49,$a9,$a9), - ($b4,$d8,$6c,$6c), ($fa,$ac,$56,$56), ($07,$f3,$f4,$f4), ($25,$cf,$ea,$ea), - ($af,$ca,$65,$65), ($8e,$f4,$7a,$7a), ($e9,$47,$ae,$ae), ($18,$10,$08,$08), - ($d5,$6f,$ba,$ba), ($88,$f0,$78,$78), ($6f,$4a,$25,$25), ($72,$5c,$2e,$2e), - ($24,$38,$1c,$1c), ($f1,$57,$a6,$a6), ($c7,$73,$b4,$b4), ($51,$97,$c6,$c6), - ($23,$cb,$e8,$e8), ($7c,$a1,$dd,$dd), ($9c,$e8,$74,$74), ($21,$3e,$1f,$1f), - ($dd,$96,$4b,$4b), ($dc,$61,$bd,$bd), ($86,$0d,$8b,$8b), ($85,$0f,$8a,$8a), - ($90,$e0,$70,$70), ($42,$7c,$3e,$3e), ($c4,$71,$b5,$b5), ($aa,$cc,$66,$66), - ($d8,$90,$48,$48), ($05,$06,$03,$03), ($01,$f7,$f6,$f6), ($12,$1c,$0e,$0e), - ($a3,$c2,$61,$61), ($5f,$6a,$35,$35), ($f9,$ae,$57,$57), ($d0,$69,$b9,$b9), - ($91,$17,$86,$86), ($58,$99,$c1,$c1), ($27,$3a,$1d,$1d), ($b9,$27,$9e,$9e), - ($38,$d9,$e1,$e1), ($13,$eb,$f8,$f8), ($b3,$2b,$98,$98), ($33,$22,$11,$11), - ($bb,$d2,$69,$69), ($70,$a9,$d9,$d9), ($89,$07,$8e,$8e), ($a7,$33,$94,$94), - ($b6,$2d,$9b,$9b), ($22,$3c,$1e,$1e), ($92,$15,$87,$87), ($20,$c9,$e9,$e9), - ($49,$87,$ce,$ce), ($ff,$aa,$55,$55), ($78,$50,$28,$28), ($7a,$a5,$df,$df), - ($8f,$03,$8c,$8c), ($f8,$59,$a1,$a1), ($80,$09,$89,$89), ($17,$1a,$0d,$0d), - ($da,$65,$bf,$bf), ($31,$d7,$e6,$e6), ($c6,$84,$42,$42), ($b8,$d0,$68,$68), - ($c3,$82,$41,$41), ($b0,$29,$99,$99), ($77,$5a,$2d,$2d), ($11,$1e,$0f,$0f), - ($cb,$7b,$b0,$b0), ($fc,$a8,$54,$54), ($d6,$6d,$bb,$bb), ($3a,$2c,$16,$16)); - T3: array[0..255,0..3] of byte= ( - ($63,$a5,$c6,$63), ($7c,$84,$f8,$7c), ($77,$99,$ee,$77), ($7b,$8d,$f6,$7b), - ($f2,$0d,$ff,$f2), ($6b,$bd,$d6,$6b), ($6f,$b1,$de,$6f), ($c5,$54,$91,$c5), - ($30,$50,$60,$30), ($01,$03,$02,$01), ($67,$a9,$ce,$67), ($2b,$7d,$56,$2b), - ($fe,$19,$e7,$fe), ($d7,$62,$b5,$d7), ($ab,$e6,$4d,$ab), ($76,$9a,$ec,$76), - ($ca,$45,$8f,$ca), ($82,$9d,$1f,$82), ($c9,$40,$89,$c9), ($7d,$87,$fa,$7d), - ($fa,$15,$ef,$fa), ($59,$eb,$b2,$59), ($47,$c9,$8e,$47), ($f0,$0b,$fb,$f0), - ($ad,$ec,$41,$ad), ($d4,$67,$b3,$d4), ($a2,$fd,$5f,$a2), ($af,$ea,$45,$af), - ($9c,$bf,$23,$9c), ($a4,$f7,$53,$a4), ($72,$96,$e4,$72), ($c0,$5b,$9b,$c0), - ($b7,$c2,$75,$b7), ($fd,$1c,$e1,$fd), ($93,$ae,$3d,$93), ($26,$6a,$4c,$26), - ($36,$5a,$6c,$36), ($3f,$41,$7e,$3f), ($f7,$02,$f5,$f7), ($cc,$4f,$83,$cc), - ($34,$5c,$68,$34), ($a5,$f4,$51,$a5), ($e5,$34,$d1,$e5), ($f1,$08,$f9,$f1), - ($71,$93,$e2,$71), ($d8,$73,$ab,$d8), ($31,$53,$62,$31), ($15,$3f,$2a,$15), - ($04,$0c,$08,$04), ($c7,$52,$95,$c7), ($23,$65,$46,$23), ($c3,$5e,$9d,$c3), - ($18,$28,$30,$18), ($96,$a1,$37,$96), ($05,$0f,$0a,$05), ($9a,$b5,$2f,$9a), - ($07,$09,$0e,$07), ($12,$36,$24,$12), ($80,$9b,$1b,$80), ($e2,$3d,$df,$e2), - ($eb,$26,$cd,$eb), ($27,$69,$4e,$27), ($b2,$cd,$7f,$b2), ($75,$9f,$ea,$75), - ($09,$1b,$12,$09), ($83,$9e,$1d,$83), ($2c,$74,$58,$2c), ($1a,$2e,$34,$1a), - ($1b,$2d,$36,$1b), ($6e,$b2,$dc,$6e), ($5a,$ee,$b4,$5a), ($a0,$fb,$5b,$a0), - ($52,$f6,$a4,$52), ($3b,$4d,$76,$3b), ($d6,$61,$b7,$d6), ($b3,$ce,$7d,$b3), - ($29,$7b,$52,$29), ($e3,$3e,$dd,$e3), ($2f,$71,$5e,$2f), ($84,$97,$13,$84), - ($53,$f5,$a6,$53), ($d1,$68,$b9,$d1), ($00,$00,$00,$00), ($ed,$2c,$c1,$ed), - ($20,$60,$40,$20), ($fc,$1f,$e3,$fc), ($b1,$c8,$79,$b1), ($5b,$ed,$b6,$5b), - ($6a,$be,$d4,$6a), ($cb,$46,$8d,$cb), ($be,$d9,$67,$be), ($39,$4b,$72,$39), - ($4a,$de,$94,$4a), ($4c,$d4,$98,$4c), ($58,$e8,$b0,$58), ($cf,$4a,$85,$cf), - ($d0,$6b,$bb,$d0), ($ef,$2a,$c5,$ef), ($aa,$e5,$4f,$aa), ($fb,$16,$ed,$fb), - ($43,$c5,$86,$43), ($4d,$d7,$9a,$4d), ($33,$55,$66,$33), ($85,$94,$11,$85), - ($45,$cf,$8a,$45), ($f9,$10,$e9,$f9), ($02,$06,$04,$02), ($7f,$81,$fe,$7f), - ($50,$f0,$a0,$50), ($3c,$44,$78,$3c), ($9f,$ba,$25,$9f), ($a8,$e3,$4b,$a8), - ($51,$f3,$a2,$51), ($a3,$fe,$5d,$a3), ($40,$c0,$80,$40), ($8f,$8a,$05,$8f), - ($92,$ad,$3f,$92), ($9d,$bc,$21,$9d), ($38,$48,$70,$38), ($f5,$04,$f1,$f5), - ($bc,$df,$63,$bc), ($b6,$c1,$77,$b6), ($da,$75,$af,$da), ($21,$63,$42,$21), - ($10,$30,$20,$10), ($ff,$1a,$e5,$ff), ($f3,$0e,$fd,$f3), ($d2,$6d,$bf,$d2), - ($cd,$4c,$81,$cd), ($0c,$14,$18,$0c), ($13,$35,$26,$13), ($ec,$2f,$c3,$ec), - ($5f,$e1,$be,$5f), ($97,$a2,$35,$97), ($44,$cc,$88,$44), ($17,$39,$2e,$17), - ($c4,$57,$93,$c4), ($a7,$f2,$55,$a7), ($7e,$82,$fc,$7e), ($3d,$47,$7a,$3d), - ($64,$ac,$c8,$64), ($5d,$e7,$ba,$5d), ($19,$2b,$32,$19), ($73,$95,$e6,$73), - ($60,$a0,$c0,$60), ($81,$98,$19,$81), ($4f,$d1,$9e,$4f), ($dc,$7f,$a3,$dc), - ($22,$66,$44,$22), ($2a,$7e,$54,$2a), ($90,$ab,$3b,$90), ($88,$83,$0b,$88), - ($46,$ca,$8c,$46), ($ee,$29,$c7,$ee), ($b8,$d3,$6b,$b8), ($14,$3c,$28,$14), - ($de,$79,$a7,$de), ($5e,$e2,$bc,$5e), ($0b,$1d,$16,$0b), ($db,$76,$ad,$db), - ($e0,$3b,$db,$e0), ($32,$56,$64,$32), ($3a,$4e,$74,$3a), ($0a,$1e,$14,$0a), - ($49,$db,$92,$49), ($06,$0a,$0c,$06), ($24,$6c,$48,$24), ($5c,$e4,$b8,$5c), - ($c2,$5d,$9f,$c2), ($d3,$6e,$bd,$d3), ($ac,$ef,$43,$ac), ($62,$a6,$c4,$62), - ($91,$a8,$39,$91), ($95,$a4,$31,$95), ($e4,$37,$d3,$e4), ($79,$8b,$f2,$79), - ($e7,$32,$d5,$e7), ($c8,$43,$8b,$c8), ($37,$59,$6e,$37), ($6d,$b7,$da,$6d), - ($8d,$8c,$01,$8d), ($d5,$64,$b1,$d5), ($4e,$d2,$9c,$4e), ($a9,$e0,$49,$a9), - ($6c,$b4,$d8,$6c), ($56,$fa,$ac,$56), ($f4,$07,$f3,$f4), ($ea,$25,$cf,$ea), - ($65,$af,$ca,$65), ($7a,$8e,$f4,$7a), ($ae,$e9,$47,$ae), ($08,$18,$10,$08), - ($ba,$d5,$6f,$ba), ($78,$88,$f0,$78), ($25,$6f,$4a,$25), ($2e,$72,$5c,$2e), - ($1c,$24,$38,$1c), ($a6,$f1,$57,$a6), ($b4,$c7,$73,$b4), ($c6,$51,$97,$c6), - ($e8,$23,$cb,$e8), ($dd,$7c,$a1,$dd), ($74,$9c,$e8,$74), ($1f,$21,$3e,$1f), - ($4b,$dd,$96,$4b), ($bd,$dc,$61,$bd), ($8b,$86,$0d,$8b), ($8a,$85,$0f,$8a), - ($70,$90,$e0,$70), ($3e,$42,$7c,$3e), ($b5,$c4,$71,$b5), ($66,$aa,$cc,$66), - ($48,$d8,$90,$48), ($03,$05,$06,$03), ($f6,$01,$f7,$f6), ($0e,$12,$1c,$0e), - ($61,$a3,$c2,$61), ($35,$5f,$6a,$35), ($57,$f9,$ae,$57), ($b9,$d0,$69,$b9), - ($86,$91,$17,$86), ($c1,$58,$99,$c1), ($1d,$27,$3a,$1d), ($9e,$b9,$27,$9e), - ($e1,$38,$d9,$e1), ($f8,$13,$eb,$f8), ($98,$b3,$2b,$98), ($11,$33,$22,$11), - ($69,$bb,$d2,$69), ($d9,$70,$a9,$d9), ($8e,$89,$07,$8e), ($94,$a7,$33,$94), - ($9b,$b6,$2d,$9b), ($1e,$22,$3c,$1e), ($87,$92,$15,$87), ($e9,$20,$c9,$e9), - ($ce,$49,$87,$ce), ($55,$ff,$aa,$55), ($28,$78,$50,$28), ($df,$7a,$a5,$df), - ($8c,$8f,$03,$8c), ($a1,$f8,$59,$a1), ($89,$80,$09,$89), ($0d,$17,$1a,$0d), - ($bf,$da,$65,$bf), ($e6,$31,$d7,$e6), ($42,$c6,$84,$42), ($68,$b8,$d0,$68), - ($41,$c3,$82,$41), ($99,$b0,$29,$99), ($2d,$77,$5a,$2d), ($0f,$11,$1e,$0f), - ($b0,$cb,$7b,$b0), ($54,$fc,$a8,$54), ($bb,$d6,$6d,$bb), ($16,$3a,$2c,$16)); - T4: array[0..255,0..3] of byte= ( - ($63,$63,$a5,$c6), ($7c,$7c,$84,$f8), ($77,$77,$99,$ee), ($7b,$7b,$8d,$f6), - ($f2,$f2,$0d,$ff), ($6b,$6b,$bd,$d6), ($6f,$6f,$b1,$de), ($c5,$c5,$54,$91), - ($30,$30,$50,$60), ($01,$01,$03,$02), ($67,$67,$a9,$ce), ($2b,$2b,$7d,$56), - ($fe,$fe,$19,$e7), ($d7,$d7,$62,$b5), ($ab,$ab,$e6,$4d), ($76,$76,$9a,$ec), - ($ca,$ca,$45,$8f), ($82,$82,$9d,$1f), ($c9,$c9,$40,$89), ($7d,$7d,$87,$fa), - ($fa,$fa,$15,$ef), ($59,$59,$eb,$b2), ($47,$47,$c9,$8e), ($f0,$f0,$0b,$fb), - ($ad,$ad,$ec,$41), ($d4,$d4,$67,$b3), ($a2,$a2,$fd,$5f), ($af,$af,$ea,$45), - ($9c,$9c,$bf,$23), ($a4,$a4,$f7,$53), ($72,$72,$96,$e4), ($c0,$c0,$5b,$9b), - ($b7,$b7,$c2,$75), ($fd,$fd,$1c,$e1), ($93,$93,$ae,$3d), ($26,$26,$6a,$4c), - ($36,$36,$5a,$6c), ($3f,$3f,$41,$7e), ($f7,$f7,$02,$f5), ($cc,$cc,$4f,$83), - ($34,$34,$5c,$68), ($a5,$a5,$f4,$51), ($e5,$e5,$34,$d1), ($f1,$f1,$08,$f9), - ($71,$71,$93,$e2), ($d8,$d8,$73,$ab), ($31,$31,$53,$62), ($15,$15,$3f,$2a), - ($04,$04,$0c,$08), ($c7,$c7,$52,$95), ($23,$23,$65,$46), ($c3,$c3,$5e,$9d), - ($18,$18,$28,$30), ($96,$96,$a1,$37), ($05,$05,$0f,$0a), ($9a,$9a,$b5,$2f), - ($07,$07,$09,$0e), ($12,$12,$36,$24), ($80,$80,$9b,$1b), ($e2,$e2,$3d,$df), - ($eb,$eb,$26,$cd), ($27,$27,$69,$4e), ($b2,$b2,$cd,$7f), ($75,$75,$9f,$ea), - ($09,$09,$1b,$12), ($83,$83,$9e,$1d), ($2c,$2c,$74,$58), ($1a,$1a,$2e,$34), - ($1b,$1b,$2d,$36), ($6e,$6e,$b2,$dc), ($5a,$5a,$ee,$b4), ($a0,$a0,$fb,$5b), - ($52,$52,$f6,$a4), ($3b,$3b,$4d,$76), ($d6,$d6,$61,$b7), ($b3,$b3,$ce,$7d), - ($29,$29,$7b,$52), ($e3,$e3,$3e,$dd), ($2f,$2f,$71,$5e), ($84,$84,$97,$13), - ($53,$53,$f5,$a6), ($d1,$d1,$68,$b9), ($00,$00,$00,$00), ($ed,$ed,$2c,$c1), - ($20,$20,$60,$40), ($fc,$fc,$1f,$e3), ($b1,$b1,$c8,$79), ($5b,$5b,$ed,$b6), - ($6a,$6a,$be,$d4), ($cb,$cb,$46,$8d), ($be,$be,$d9,$67), ($39,$39,$4b,$72), - ($4a,$4a,$de,$94), ($4c,$4c,$d4,$98), ($58,$58,$e8,$b0), ($cf,$cf,$4a,$85), - ($d0,$d0,$6b,$bb), ($ef,$ef,$2a,$c5), ($aa,$aa,$e5,$4f), ($fb,$fb,$16,$ed), - ($43,$43,$c5,$86), ($4d,$4d,$d7,$9a), ($33,$33,$55,$66), ($85,$85,$94,$11), - ($45,$45,$cf,$8a), ($f9,$f9,$10,$e9), ($02,$02,$06,$04), ($7f,$7f,$81,$fe), - ($50,$50,$f0,$a0), ($3c,$3c,$44,$78), ($9f,$9f,$ba,$25), ($a8,$a8,$e3,$4b), - ($51,$51,$f3,$a2), ($a3,$a3,$fe,$5d), ($40,$40,$c0,$80), ($8f,$8f,$8a,$05), - ($92,$92,$ad,$3f), ($9d,$9d,$bc,$21), ($38,$38,$48,$70), ($f5,$f5,$04,$f1), - ($bc,$bc,$df,$63), ($b6,$b6,$c1,$77), ($da,$da,$75,$af), ($21,$21,$63,$42), - ($10,$10,$30,$20), ($ff,$ff,$1a,$e5), ($f3,$f3,$0e,$fd), ($d2,$d2,$6d,$bf), - ($cd,$cd,$4c,$81), ($0c,$0c,$14,$18), ($13,$13,$35,$26), ($ec,$ec,$2f,$c3), - ($5f,$5f,$e1,$be), ($97,$97,$a2,$35), ($44,$44,$cc,$88), ($17,$17,$39,$2e), - ($c4,$c4,$57,$93), ($a7,$a7,$f2,$55), ($7e,$7e,$82,$fc), ($3d,$3d,$47,$7a), - ($64,$64,$ac,$c8), ($5d,$5d,$e7,$ba), ($19,$19,$2b,$32), ($73,$73,$95,$e6), - ($60,$60,$a0,$c0), ($81,$81,$98,$19), ($4f,$4f,$d1,$9e), ($dc,$dc,$7f,$a3), - ($22,$22,$66,$44), ($2a,$2a,$7e,$54), ($90,$90,$ab,$3b), ($88,$88,$83,$0b), - ($46,$46,$ca,$8c), ($ee,$ee,$29,$c7), ($b8,$b8,$d3,$6b), ($14,$14,$3c,$28), - ($de,$de,$79,$a7), ($5e,$5e,$e2,$bc), ($0b,$0b,$1d,$16), ($db,$db,$76,$ad), - ($e0,$e0,$3b,$db), ($32,$32,$56,$64), ($3a,$3a,$4e,$74), ($0a,$0a,$1e,$14), - ($49,$49,$db,$92), ($06,$06,$0a,$0c), ($24,$24,$6c,$48), ($5c,$5c,$e4,$b8), - ($c2,$c2,$5d,$9f), ($d3,$d3,$6e,$bd), ($ac,$ac,$ef,$43), ($62,$62,$a6,$c4), - ($91,$91,$a8,$39), ($95,$95,$a4,$31), ($e4,$e4,$37,$d3), ($79,$79,$8b,$f2), - ($e7,$e7,$32,$d5), ($c8,$c8,$43,$8b), ($37,$37,$59,$6e), ($6d,$6d,$b7,$da), - ($8d,$8d,$8c,$01), ($d5,$d5,$64,$b1), ($4e,$4e,$d2,$9c), ($a9,$a9,$e0,$49), - ($6c,$6c,$b4,$d8), ($56,$56,$fa,$ac), ($f4,$f4,$07,$f3), ($ea,$ea,$25,$cf), - ($65,$65,$af,$ca), ($7a,$7a,$8e,$f4), ($ae,$ae,$e9,$47), ($08,$08,$18,$10), - ($ba,$ba,$d5,$6f), ($78,$78,$88,$f0), ($25,$25,$6f,$4a), ($2e,$2e,$72,$5c), - ($1c,$1c,$24,$38), ($a6,$a6,$f1,$57), ($b4,$b4,$c7,$73), ($c6,$c6,$51,$97), - ($e8,$e8,$23,$cb), ($dd,$dd,$7c,$a1), ($74,$74,$9c,$e8), ($1f,$1f,$21,$3e), - ($4b,$4b,$dd,$96), ($bd,$bd,$dc,$61), ($8b,$8b,$86,$0d), ($8a,$8a,$85,$0f), - ($70,$70,$90,$e0), ($3e,$3e,$42,$7c), ($b5,$b5,$c4,$71), ($66,$66,$aa,$cc), - ($48,$48,$d8,$90), ($03,$03,$05,$06), ($f6,$f6,$01,$f7), ($0e,$0e,$12,$1c), - ($61,$61,$a3,$c2), ($35,$35,$5f,$6a), ($57,$57,$f9,$ae), ($b9,$b9,$d0,$69), - ($86,$86,$91,$17), ($c1,$c1,$58,$99), ($1d,$1d,$27,$3a), ($9e,$9e,$b9,$27), - ($e1,$e1,$38,$d9), ($f8,$f8,$13,$eb), ($98,$98,$b3,$2b), ($11,$11,$33,$22), - ($69,$69,$bb,$d2), ($d9,$d9,$70,$a9), ($8e,$8e,$89,$07), ($94,$94,$a7,$33), - ($9b,$9b,$b6,$2d), ($1e,$1e,$22,$3c), ($87,$87,$92,$15), ($e9,$e9,$20,$c9), - ($ce,$ce,$49,$87), ($55,$55,$ff,$aa), ($28,$28,$78,$50), ($df,$df,$7a,$a5), - ($8c,$8c,$8f,$03), ($a1,$a1,$f8,$59), ($89,$89,$80,$09), ($0d,$0d,$17,$1a), - ($bf,$bf,$da,$65), ($e6,$e6,$31,$d7), ($42,$42,$c6,$84), ($68,$68,$b8,$d0), - ($41,$41,$c3,$82), ($99,$99,$b0,$29), ($2d,$2d,$77,$5a), ($0f,$0f,$11,$1e), - ($b0,$b0,$cb,$7b), ($54,$54,$fc,$a8), ($bb,$bb,$d6,$6d), ($16,$16,$3a,$2c)); - T5: array[0..255,0..3] of byte= ( - ($51,$f4,$a7,$50), ($7e,$41,$65,$53), ($1a,$17,$a4,$c3), ($3a,$27,$5e,$96), - ($3b,$ab,$6b,$cb), ($1f,$9d,$45,$f1), ($ac,$fa,$58,$ab), ($4b,$e3,$03,$93), - ($20,$30,$fa,$55), ($ad,$76,$6d,$f6), ($88,$cc,$76,$91), ($f5,$02,$4c,$25), - ($4f,$e5,$d7,$fc), ($c5,$2a,$cb,$d7), ($26,$35,$44,$80), ($b5,$62,$a3,$8f), - ($de,$b1,$5a,$49), ($25,$ba,$1b,$67), ($45,$ea,$0e,$98), ($5d,$fe,$c0,$e1), - ($c3,$2f,$75,$02), ($81,$4c,$f0,$12), ($8d,$46,$97,$a3), ($6b,$d3,$f9,$c6), - ($03,$8f,$5f,$e7), ($15,$92,$9c,$95), ($bf,$6d,$7a,$eb), ($95,$52,$59,$da), - ($d4,$be,$83,$2d), ($58,$74,$21,$d3), ($49,$e0,$69,$29), ($8e,$c9,$c8,$44), - ($75,$c2,$89,$6a), ($f4,$8e,$79,$78), ($99,$58,$3e,$6b), ($27,$b9,$71,$dd), - ($be,$e1,$4f,$b6), ($f0,$88,$ad,$17), ($c9,$20,$ac,$66), ($7d,$ce,$3a,$b4), - ($63,$df,$4a,$18), ($e5,$1a,$31,$82), ($97,$51,$33,$60), ($62,$53,$7f,$45), - ($b1,$64,$77,$e0), ($bb,$6b,$ae,$84), ($fe,$81,$a0,$1c), ($f9,$08,$2b,$94), - ($70,$48,$68,$58), ($8f,$45,$fd,$19), ($94,$de,$6c,$87), ($52,$7b,$f8,$b7), - ($ab,$73,$d3,$23), ($72,$4b,$02,$e2), ($e3,$1f,$8f,$57), ($66,$55,$ab,$2a), - ($b2,$eb,$28,$07), ($2f,$b5,$c2,$03), ($86,$c5,$7b,$9a), ($d3,$37,$08,$a5), - ($30,$28,$87,$f2), ($23,$bf,$a5,$b2), ($02,$03,$6a,$ba), ($ed,$16,$82,$5c), - ($8a,$cf,$1c,$2b), ($a7,$79,$b4,$92), ($f3,$07,$f2,$f0), ($4e,$69,$e2,$a1), - ($65,$da,$f4,$cd), ($06,$05,$be,$d5), ($d1,$34,$62,$1f), ($c4,$a6,$fe,$8a), - ($34,$2e,$53,$9d), ($a2,$f3,$55,$a0), ($05,$8a,$e1,$32), ($a4,$f6,$eb,$75), - ($0b,$83,$ec,$39), ($40,$60,$ef,$aa), ($5e,$71,$9f,$06), ($bd,$6e,$10,$51), - ($3e,$21,$8a,$f9), ($96,$dd,$06,$3d), ($dd,$3e,$05,$ae), ($4d,$e6,$bd,$46), - ($91,$54,$8d,$b5), ($71,$c4,$5d,$05), ($04,$06,$d4,$6f), ($60,$50,$15,$ff), - ($19,$98,$fb,$24), ($d6,$bd,$e9,$97), ($89,$40,$43,$cc), ($67,$d9,$9e,$77), - ($b0,$e8,$42,$bd), ($07,$89,$8b,$88), ($e7,$19,$5b,$38), ($79,$c8,$ee,$db), - ($a1,$7c,$0a,$47), ($7c,$42,$0f,$e9), ($f8,$84,$1e,$c9), ($00,$00,$00,$00), - ($09,$80,$86,$83), ($32,$2b,$ed,$48), ($1e,$11,$70,$ac), ($6c,$5a,$72,$4e), - ($fd,$0e,$ff,$fb), ($0f,$85,$38,$56), ($3d,$ae,$d5,$1e), ($36,$2d,$39,$27), - ($0a,$0f,$d9,$64), ($68,$5c,$a6,$21), ($9b,$5b,$54,$d1), ($24,$36,$2e,$3a), - ($0c,$0a,$67,$b1), ($93,$57,$e7,$0f), ($b4,$ee,$96,$d2), ($1b,$9b,$91,$9e), - ($80,$c0,$c5,$4f), ($61,$dc,$20,$a2), ($5a,$77,$4b,$69), ($1c,$12,$1a,$16), - ($e2,$93,$ba,$0a), ($c0,$a0,$2a,$e5), ($3c,$22,$e0,$43), ($12,$1b,$17,$1d), - ($0e,$09,$0d,$0b), ($f2,$8b,$c7,$ad), ($2d,$b6,$a8,$b9), ($14,$1e,$a9,$c8), - ($57,$f1,$19,$85), ($af,$75,$07,$4c), ($ee,$99,$dd,$bb), ($a3,$7f,$60,$fd), - ($f7,$01,$26,$9f), ($5c,$72,$f5,$bc), ($44,$66,$3b,$c5), ($5b,$fb,$7e,$34), - ($8b,$43,$29,$76), ($cb,$23,$c6,$dc), ($b6,$ed,$fc,$68), ($b8,$e4,$f1,$63), - ($d7,$31,$dc,$ca), ($42,$63,$85,$10), ($13,$97,$22,$40), ($84,$c6,$11,$20), - ($85,$4a,$24,$7d), ($d2,$bb,$3d,$f8), ($ae,$f9,$32,$11), ($c7,$29,$a1,$6d), - ($1d,$9e,$2f,$4b), ($dc,$b2,$30,$f3), ($0d,$86,$52,$ec), ($77,$c1,$e3,$d0), - ($2b,$b3,$16,$6c), ($a9,$70,$b9,$99), ($11,$94,$48,$fa), ($47,$e9,$64,$22), - ($a8,$fc,$8c,$c4), ($a0,$f0,$3f,$1a), ($56,$7d,$2c,$d8), ($22,$33,$90,$ef), - ($87,$49,$4e,$c7), ($d9,$38,$d1,$c1), ($8c,$ca,$a2,$fe), ($98,$d4,$0b,$36), - ($a6,$f5,$81,$cf), ($a5,$7a,$de,$28), ($da,$b7,$8e,$26), ($3f,$ad,$bf,$a4), - ($2c,$3a,$9d,$e4), ($50,$78,$92,$0d), ($6a,$5f,$cc,$9b), ($54,$7e,$46,$62), - ($f6,$8d,$13,$c2), ($90,$d8,$b8,$e8), ($2e,$39,$f7,$5e), ($82,$c3,$af,$f5), - ($9f,$5d,$80,$be), ($69,$d0,$93,$7c), ($6f,$d5,$2d,$a9), ($cf,$25,$12,$b3), - ($c8,$ac,$99,$3b), ($10,$18,$7d,$a7), ($e8,$9c,$63,$6e), ($db,$3b,$bb,$7b), - ($cd,$26,$78,$09), ($6e,$59,$18,$f4), ($ec,$9a,$b7,$01), ($83,$4f,$9a,$a8), - ($e6,$95,$6e,$65), ($aa,$ff,$e6,$7e), ($21,$bc,$cf,$08), ($ef,$15,$e8,$e6), - ($ba,$e7,$9b,$d9), ($4a,$6f,$36,$ce), ($ea,$9f,$09,$d4), ($29,$b0,$7c,$d6), - ($31,$a4,$b2,$af), ($2a,$3f,$23,$31), ($c6,$a5,$94,$30), ($35,$a2,$66,$c0), - ($74,$4e,$bc,$37), ($fc,$82,$ca,$a6), ($e0,$90,$d0,$b0), ($33,$a7,$d8,$15), - ($f1,$04,$98,$4a), ($41,$ec,$da,$f7), ($7f,$cd,$50,$0e), ($17,$91,$f6,$2f), - ($76,$4d,$d6,$8d), ($43,$ef,$b0,$4d), ($cc,$aa,$4d,$54), ($e4,$96,$04,$df), - ($9e,$d1,$b5,$e3), ($4c,$6a,$88,$1b), ($c1,$2c,$1f,$b8), ($46,$65,$51,$7f), - ($9d,$5e,$ea,$04), ($01,$8c,$35,$5d), ($fa,$87,$74,$73), ($fb,$0b,$41,$2e), - ($b3,$67,$1d,$5a), ($92,$db,$d2,$52), ($e9,$10,$56,$33), ($6d,$d6,$47,$13), - ($9a,$d7,$61,$8c), ($37,$a1,$0c,$7a), ($59,$f8,$14,$8e), ($eb,$13,$3c,$89), - ($ce,$a9,$27,$ee), ($b7,$61,$c9,$35), ($e1,$1c,$e5,$ed), ($7a,$47,$b1,$3c), - ($9c,$d2,$df,$59), ($55,$f2,$73,$3f), ($18,$14,$ce,$79), ($73,$c7,$37,$bf), - ($53,$f7,$cd,$ea), ($5f,$fd,$aa,$5b), ($df,$3d,$6f,$14), ($78,$44,$db,$86), - ($ca,$af,$f3,$81), ($b9,$68,$c4,$3e), ($38,$24,$34,$2c), ($c2,$a3,$40,$5f), - ($16,$1d,$c3,$72), ($bc,$e2,$25,$0c), ($28,$3c,$49,$8b), ($ff,$0d,$95,$41), - ($39,$a8,$01,$71), ($08,$0c,$b3,$de), ($d8,$b4,$e4,$9c), ($64,$56,$c1,$90), - ($7b,$cb,$84,$61), ($d5,$32,$b6,$70), ($48,$6c,$5c,$74), ($d0,$b8,$57,$42)); - T6: array[0..255,0..3] of byte= ( - ($50,$51,$f4,$a7), ($53,$7e,$41,$65), ($c3,$1a,$17,$a4), ($96,$3a,$27,$5e), - ($cb,$3b,$ab,$6b), ($f1,$1f,$9d,$45), ($ab,$ac,$fa,$58), ($93,$4b,$e3,$03), - ($55,$20,$30,$fa), ($f6,$ad,$76,$6d), ($91,$88,$cc,$76), ($25,$f5,$02,$4c), - ($fc,$4f,$e5,$d7), ($d7,$c5,$2a,$cb), ($80,$26,$35,$44), ($8f,$b5,$62,$a3), - ($49,$de,$b1,$5a), ($67,$25,$ba,$1b), ($98,$45,$ea,$0e), ($e1,$5d,$fe,$c0), - ($02,$c3,$2f,$75), ($12,$81,$4c,$f0), ($a3,$8d,$46,$97), ($c6,$6b,$d3,$f9), - ($e7,$03,$8f,$5f), ($95,$15,$92,$9c), ($eb,$bf,$6d,$7a), ($da,$95,$52,$59), - ($2d,$d4,$be,$83), ($d3,$58,$74,$21), ($29,$49,$e0,$69), ($44,$8e,$c9,$c8), - ($6a,$75,$c2,$89), ($78,$f4,$8e,$79), ($6b,$99,$58,$3e), ($dd,$27,$b9,$71), - ($b6,$be,$e1,$4f), ($17,$f0,$88,$ad), ($66,$c9,$20,$ac), ($b4,$7d,$ce,$3a), - ($18,$63,$df,$4a), ($82,$e5,$1a,$31), ($60,$97,$51,$33), ($45,$62,$53,$7f), - ($e0,$b1,$64,$77), ($84,$bb,$6b,$ae), ($1c,$fe,$81,$a0), ($94,$f9,$08,$2b), - ($58,$70,$48,$68), ($19,$8f,$45,$fd), ($87,$94,$de,$6c), ($b7,$52,$7b,$f8), - ($23,$ab,$73,$d3), ($e2,$72,$4b,$02), ($57,$e3,$1f,$8f), ($2a,$66,$55,$ab), - ($07,$b2,$eb,$28), ($03,$2f,$b5,$c2), ($9a,$86,$c5,$7b), ($a5,$d3,$37,$08), - ($f2,$30,$28,$87), ($b2,$23,$bf,$a5), ($ba,$02,$03,$6a), ($5c,$ed,$16,$82), - ($2b,$8a,$cf,$1c), ($92,$a7,$79,$b4), ($f0,$f3,$07,$f2), ($a1,$4e,$69,$e2), - ($cd,$65,$da,$f4), ($d5,$06,$05,$be), ($1f,$d1,$34,$62), ($8a,$c4,$a6,$fe), - ($9d,$34,$2e,$53), ($a0,$a2,$f3,$55), ($32,$05,$8a,$e1), ($75,$a4,$f6,$eb), - ($39,$0b,$83,$ec), ($aa,$40,$60,$ef), ($06,$5e,$71,$9f), ($51,$bd,$6e,$10), - ($f9,$3e,$21,$8a), ($3d,$96,$dd,$06), ($ae,$dd,$3e,$05), ($46,$4d,$e6,$bd), - ($b5,$91,$54,$8d), ($05,$71,$c4,$5d), ($6f,$04,$06,$d4), ($ff,$60,$50,$15), - ($24,$19,$98,$fb), ($97,$d6,$bd,$e9), ($cc,$89,$40,$43), ($77,$67,$d9,$9e), - ($bd,$b0,$e8,$42), ($88,$07,$89,$8b), ($38,$e7,$19,$5b), ($db,$79,$c8,$ee), - ($47,$a1,$7c,$0a), ($e9,$7c,$42,$0f), ($c9,$f8,$84,$1e), ($00,$00,$00,$00), - ($83,$09,$80,$86), ($48,$32,$2b,$ed), ($ac,$1e,$11,$70), ($4e,$6c,$5a,$72), - ($fb,$fd,$0e,$ff), ($56,$0f,$85,$38), ($1e,$3d,$ae,$d5), ($27,$36,$2d,$39), - ($64,$0a,$0f,$d9), ($21,$68,$5c,$a6), ($d1,$9b,$5b,$54), ($3a,$24,$36,$2e), - ($b1,$0c,$0a,$67), ($0f,$93,$57,$e7), ($d2,$b4,$ee,$96), ($9e,$1b,$9b,$91), - ($4f,$80,$c0,$c5), ($a2,$61,$dc,$20), ($69,$5a,$77,$4b), ($16,$1c,$12,$1a), - ($0a,$e2,$93,$ba), ($e5,$c0,$a0,$2a), ($43,$3c,$22,$e0), ($1d,$12,$1b,$17), - ($0b,$0e,$09,$0d), ($ad,$f2,$8b,$c7), ($b9,$2d,$b6,$a8), ($c8,$14,$1e,$a9), - ($85,$57,$f1,$19), ($4c,$af,$75,$07), ($bb,$ee,$99,$dd), ($fd,$a3,$7f,$60), - ($9f,$f7,$01,$26), ($bc,$5c,$72,$f5), ($c5,$44,$66,$3b), ($34,$5b,$fb,$7e), - ($76,$8b,$43,$29), ($dc,$cb,$23,$c6), ($68,$b6,$ed,$fc), ($63,$b8,$e4,$f1), - ($ca,$d7,$31,$dc), ($10,$42,$63,$85), ($40,$13,$97,$22), ($20,$84,$c6,$11), - ($7d,$85,$4a,$24), ($f8,$d2,$bb,$3d), ($11,$ae,$f9,$32), ($6d,$c7,$29,$a1), - ($4b,$1d,$9e,$2f), ($f3,$dc,$b2,$30), ($ec,$0d,$86,$52), ($d0,$77,$c1,$e3), - ($6c,$2b,$b3,$16), ($99,$a9,$70,$b9), ($fa,$11,$94,$48), ($22,$47,$e9,$64), - ($c4,$a8,$fc,$8c), ($1a,$a0,$f0,$3f), ($d8,$56,$7d,$2c), ($ef,$22,$33,$90), - ($c7,$87,$49,$4e), ($c1,$d9,$38,$d1), ($fe,$8c,$ca,$a2), ($36,$98,$d4,$0b), - ($cf,$a6,$f5,$81), ($28,$a5,$7a,$de), ($26,$da,$b7,$8e), ($a4,$3f,$ad,$bf), - ($e4,$2c,$3a,$9d), ($0d,$50,$78,$92), ($9b,$6a,$5f,$cc), ($62,$54,$7e,$46), - ($c2,$f6,$8d,$13), ($e8,$90,$d8,$b8), ($5e,$2e,$39,$f7), ($f5,$82,$c3,$af), - ($be,$9f,$5d,$80), ($7c,$69,$d0,$93), ($a9,$6f,$d5,$2d), ($b3,$cf,$25,$12), - ($3b,$c8,$ac,$99), ($a7,$10,$18,$7d), ($6e,$e8,$9c,$63), ($7b,$db,$3b,$bb), - ($09,$cd,$26,$78), ($f4,$6e,$59,$18), ($01,$ec,$9a,$b7), ($a8,$83,$4f,$9a), - ($65,$e6,$95,$6e), ($7e,$aa,$ff,$e6), ($08,$21,$bc,$cf), ($e6,$ef,$15,$e8), - ($d9,$ba,$e7,$9b), ($ce,$4a,$6f,$36), ($d4,$ea,$9f,$09), ($d6,$29,$b0,$7c), - ($af,$31,$a4,$b2), ($31,$2a,$3f,$23), ($30,$c6,$a5,$94), ($c0,$35,$a2,$66), - ($37,$74,$4e,$bc), ($a6,$fc,$82,$ca), ($b0,$e0,$90,$d0), ($15,$33,$a7,$d8), - ($4a,$f1,$04,$98), ($f7,$41,$ec,$da), ($0e,$7f,$cd,$50), ($2f,$17,$91,$f6), - ($8d,$76,$4d,$d6), ($4d,$43,$ef,$b0), ($54,$cc,$aa,$4d), ($df,$e4,$96,$04), - ($e3,$9e,$d1,$b5), ($1b,$4c,$6a,$88), ($b8,$c1,$2c,$1f), ($7f,$46,$65,$51), - ($04,$9d,$5e,$ea), ($5d,$01,$8c,$35), ($73,$fa,$87,$74), ($2e,$fb,$0b,$41), - ($5a,$b3,$67,$1d), ($52,$92,$db,$d2), ($33,$e9,$10,$56), ($13,$6d,$d6,$47), - ($8c,$9a,$d7,$61), ($7a,$37,$a1,$0c), ($8e,$59,$f8,$14), ($89,$eb,$13,$3c), - ($ee,$ce,$a9,$27), ($35,$b7,$61,$c9), ($ed,$e1,$1c,$e5), ($3c,$7a,$47,$b1), - ($59,$9c,$d2,$df), ($3f,$55,$f2,$73), ($79,$18,$14,$ce), ($bf,$73,$c7,$37), - ($ea,$53,$f7,$cd), ($5b,$5f,$fd,$aa), ($14,$df,$3d,$6f), ($86,$78,$44,$db), - ($81,$ca,$af,$f3), ($3e,$b9,$68,$c4), ($2c,$38,$24,$34), ($5f,$c2,$a3,$40), - ($72,$16,$1d,$c3), ($0c,$bc,$e2,$25), ($8b,$28,$3c,$49), ($41,$ff,$0d,$95), - ($71,$39,$a8,$01), ($de,$08,$0c,$b3), ($9c,$d8,$b4,$e4), ($90,$64,$56,$c1), - ($61,$7b,$cb,$84), ($70,$d5,$32,$b6), ($74,$48,$6c,$5c), ($42,$d0,$b8,$57)); - T7: array[0..255,0..3] of byte= ( - ($a7,$50,$51,$f4), ($65,$53,$7e,$41), ($a4,$c3,$1a,$17), ($5e,$96,$3a,$27), - ($6b,$cb,$3b,$ab), ($45,$f1,$1f,$9d), ($58,$ab,$ac,$fa), ($03,$93,$4b,$e3), - ($fa,$55,$20,$30), ($6d,$f6,$ad,$76), ($76,$91,$88,$cc), ($4c,$25,$f5,$02), - ($d7,$fc,$4f,$e5), ($cb,$d7,$c5,$2a), ($44,$80,$26,$35), ($a3,$8f,$b5,$62), - ($5a,$49,$de,$b1), ($1b,$67,$25,$ba), ($0e,$98,$45,$ea), ($c0,$e1,$5d,$fe), - ($75,$02,$c3,$2f), ($f0,$12,$81,$4c), ($97,$a3,$8d,$46), ($f9,$c6,$6b,$d3), - ($5f,$e7,$03,$8f), ($9c,$95,$15,$92), ($7a,$eb,$bf,$6d), ($59,$da,$95,$52), - ($83,$2d,$d4,$be), ($21,$d3,$58,$74), ($69,$29,$49,$e0), ($c8,$44,$8e,$c9), - ($89,$6a,$75,$c2), ($79,$78,$f4,$8e), ($3e,$6b,$99,$58), ($71,$dd,$27,$b9), - ($4f,$b6,$be,$e1), ($ad,$17,$f0,$88), ($ac,$66,$c9,$20), ($3a,$b4,$7d,$ce), - ($4a,$18,$63,$df), ($31,$82,$e5,$1a), ($33,$60,$97,$51), ($7f,$45,$62,$53), - ($77,$e0,$b1,$64), ($ae,$84,$bb,$6b), ($a0,$1c,$fe,$81), ($2b,$94,$f9,$08), - ($68,$58,$70,$48), ($fd,$19,$8f,$45), ($6c,$87,$94,$de), ($f8,$b7,$52,$7b), - ($d3,$23,$ab,$73), ($02,$e2,$72,$4b), ($8f,$57,$e3,$1f), ($ab,$2a,$66,$55), - ($28,$07,$b2,$eb), ($c2,$03,$2f,$b5), ($7b,$9a,$86,$c5), ($08,$a5,$d3,$37), - ($87,$f2,$30,$28), ($a5,$b2,$23,$bf), ($6a,$ba,$02,$03), ($82,$5c,$ed,$16), - ($1c,$2b,$8a,$cf), ($b4,$92,$a7,$79), ($f2,$f0,$f3,$07), ($e2,$a1,$4e,$69), - ($f4,$cd,$65,$da), ($be,$d5,$06,$05), ($62,$1f,$d1,$34), ($fe,$8a,$c4,$a6), - ($53,$9d,$34,$2e), ($55,$a0,$a2,$f3), ($e1,$32,$05,$8a), ($eb,$75,$a4,$f6), - ($ec,$39,$0b,$83), ($ef,$aa,$40,$60), ($9f,$06,$5e,$71), ($10,$51,$bd,$6e), - ($8a,$f9,$3e,$21), ($06,$3d,$96,$dd), ($05,$ae,$dd,$3e), ($bd,$46,$4d,$e6), - ($8d,$b5,$91,$54), ($5d,$05,$71,$c4), ($d4,$6f,$04,$06), ($15,$ff,$60,$50), - ($fb,$24,$19,$98), ($e9,$97,$d6,$bd), ($43,$cc,$89,$40), ($9e,$77,$67,$d9), - ($42,$bd,$b0,$e8), ($8b,$88,$07,$89), ($5b,$38,$e7,$19), ($ee,$db,$79,$c8), - ($0a,$47,$a1,$7c), ($0f,$e9,$7c,$42), ($1e,$c9,$f8,$84), ($00,$00,$00,$00), - ($86,$83,$09,$80), ($ed,$48,$32,$2b), ($70,$ac,$1e,$11), ($72,$4e,$6c,$5a), - ($ff,$fb,$fd,$0e), ($38,$56,$0f,$85), ($d5,$1e,$3d,$ae), ($39,$27,$36,$2d), - ($d9,$64,$0a,$0f), ($a6,$21,$68,$5c), ($54,$d1,$9b,$5b), ($2e,$3a,$24,$36), - ($67,$b1,$0c,$0a), ($e7,$0f,$93,$57), ($96,$d2,$b4,$ee), ($91,$9e,$1b,$9b), - ($c5,$4f,$80,$c0), ($20,$a2,$61,$dc), ($4b,$69,$5a,$77), ($1a,$16,$1c,$12), - ($ba,$0a,$e2,$93), ($2a,$e5,$c0,$a0), ($e0,$43,$3c,$22), ($17,$1d,$12,$1b), - ($0d,$0b,$0e,$09), ($c7,$ad,$f2,$8b), ($a8,$b9,$2d,$b6), ($a9,$c8,$14,$1e), - ($19,$85,$57,$f1), ($07,$4c,$af,$75), ($dd,$bb,$ee,$99), ($60,$fd,$a3,$7f), - ($26,$9f,$f7,$01), ($f5,$bc,$5c,$72), ($3b,$c5,$44,$66), ($7e,$34,$5b,$fb), - ($29,$76,$8b,$43), ($c6,$dc,$cb,$23), ($fc,$68,$b6,$ed), ($f1,$63,$b8,$e4), - ($dc,$ca,$d7,$31), ($85,$10,$42,$63), ($22,$40,$13,$97), ($11,$20,$84,$c6), - ($24,$7d,$85,$4a), ($3d,$f8,$d2,$bb), ($32,$11,$ae,$f9), ($a1,$6d,$c7,$29), - ($2f,$4b,$1d,$9e), ($30,$f3,$dc,$b2), ($52,$ec,$0d,$86), ($e3,$d0,$77,$c1), - ($16,$6c,$2b,$b3), ($b9,$99,$a9,$70), ($48,$fa,$11,$94), ($64,$22,$47,$e9), - ($8c,$c4,$a8,$fc), ($3f,$1a,$a0,$f0), ($2c,$d8,$56,$7d), ($90,$ef,$22,$33), - ($4e,$c7,$87,$49), ($d1,$c1,$d9,$38), ($a2,$fe,$8c,$ca), ($0b,$36,$98,$d4), - ($81,$cf,$a6,$f5), ($de,$28,$a5,$7a), ($8e,$26,$da,$b7), ($bf,$a4,$3f,$ad), - ($9d,$e4,$2c,$3a), ($92,$0d,$50,$78), ($cc,$9b,$6a,$5f), ($46,$62,$54,$7e), - ($13,$c2,$f6,$8d), ($b8,$e8,$90,$d8), ($f7,$5e,$2e,$39), ($af,$f5,$82,$c3), - ($80,$be,$9f,$5d), ($93,$7c,$69,$d0), ($2d,$a9,$6f,$d5), ($12,$b3,$cf,$25), - ($99,$3b,$c8,$ac), ($7d,$a7,$10,$18), ($63,$6e,$e8,$9c), ($bb,$7b,$db,$3b), - ($78,$09,$cd,$26), ($18,$f4,$6e,$59), ($b7,$01,$ec,$9a), ($9a,$a8,$83,$4f), - ($6e,$65,$e6,$95), ($e6,$7e,$aa,$ff), ($cf,$08,$21,$bc), ($e8,$e6,$ef,$15), - ($9b,$d9,$ba,$e7), ($36,$ce,$4a,$6f), ($09,$d4,$ea,$9f), ($7c,$d6,$29,$b0), - ($b2,$af,$31,$a4), ($23,$31,$2a,$3f), ($94,$30,$c6,$a5), ($66,$c0,$35,$a2), - ($bc,$37,$74,$4e), ($ca,$a6,$fc,$82), ($d0,$b0,$e0,$90), ($d8,$15,$33,$a7), - ($98,$4a,$f1,$04), ($da,$f7,$41,$ec), ($50,$0e,$7f,$cd), ($f6,$2f,$17,$91), - ($d6,$8d,$76,$4d), ($b0,$4d,$43,$ef), ($4d,$54,$cc,$aa), ($04,$df,$e4,$96), - ($b5,$e3,$9e,$d1), ($88,$1b,$4c,$6a), ($1f,$b8,$c1,$2c), ($51,$7f,$46,$65), - ($ea,$04,$9d,$5e), ($35,$5d,$01,$8c), ($74,$73,$fa,$87), ($41,$2e,$fb,$0b), - ($1d,$5a,$b3,$67), ($d2,$52,$92,$db), ($56,$33,$e9,$10), ($47,$13,$6d,$d6), - ($61,$8c,$9a,$d7), ($0c,$7a,$37,$a1), ($14,$8e,$59,$f8), ($3c,$89,$eb,$13), - ($27,$ee,$ce,$a9), ($c9,$35,$b7,$61), ($e5,$ed,$e1,$1c), ($b1,$3c,$7a,$47), - ($df,$59,$9c,$d2), ($73,$3f,$55,$f2), ($ce,$79,$18,$14), ($37,$bf,$73,$c7), - ($cd,$ea,$53,$f7), ($aa,$5b,$5f,$fd), ($6f,$14,$df,$3d), ($db,$86,$78,$44), - ($f3,$81,$ca,$af), ($c4,$3e,$b9,$68), ($34,$2c,$38,$24), ($40,$5f,$c2,$a3), - ($c3,$72,$16,$1d), ($25,$0c,$bc,$e2), ($49,$8b,$28,$3c), ($95,$41,$ff,$0d), - ($01,$71,$39,$a8), ($b3,$de,$08,$0c), ($e4,$9c,$d8,$b4), ($c1,$90,$64,$56), - ($84,$61,$7b,$cb), ($b6,$70,$d5,$32), ($5c,$74,$48,$6c), ($57,$42,$d0,$b8)); - T8: array[0..255,0..3] of byte= ( - ($f4,$a7,$50,$51), ($41,$65,$53,$7e), ($17,$a4,$c3,$1a), ($27,$5e,$96,$3a), - ($ab,$6b,$cb,$3b), ($9d,$45,$f1,$1f), ($fa,$58,$ab,$ac), ($e3,$03,$93,$4b), - ($30,$fa,$55,$20), ($76,$6d,$f6,$ad), ($cc,$76,$91,$88), ($02,$4c,$25,$f5), - ($e5,$d7,$fc,$4f), ($2a,$cb,$d7,$c5), ($35,$44,$80,$26), ($62,$a3,$8f,$b5), - ($b1,$5a,$49,$de), ($ba,$1b,$67,$25), ($ea,$0e,$98,$45), ($fe,$c0,$e1,$5d), - ($2f,$75,$02,$c3), ($4c,$f0,$12,$81), ($46,$97,$a3,$8d), ($d3,$f9,$c6,$6b), - ($8f,$5f,$e7,$03), ($92,$9c,$95,$15), ($6d,$7a,$eb,$bf), ($52,$59,$da,$95), - ($be,$83,$2d,$d4), ($74,$21,$d3,$58), ($e0,$69,$29,$49), ($c9,$c8,$44,$8e), - ($c2,$89,$6a,$75), ($8e,$79,$78,$f4), ($58,$3e,$6b,$99), ($b9,$71,$dd,$27), - ($e1,$4f,$b6,$be), ($88,$ad,$17,$f0), ($20,$ac,$66,$c9), ($ce,$3a,$b4,$7d), - ($df,$4a,$18,$63), ($1a,$31,$82,$e5), ($51,$33,$60,$97), ($53,$7f,$45,$62), - ($64,$77,$e0,$b1), ($6b,$ae,$84,$bb), ($81,$a0,$1c,$fe), ($08,$2b,$94,$f9), - ($48,$68,$58,$70), ($45,$fd,$19,$8f), ($de,$6c,$87,$94), ($7b,$f8,$b7,$52), - ($73,$d3,$23,$ab), ($4b,$02,$e2,$72), ($1f,$8f,$57,$e3), ($55,$ab,$2a,$66), - ($eb,$28,$07,$b2), ($b5,$c2,$03,$2f), ($c5,$7b,$9a,$86), ($37,$08,$a5,$d3), - ($28,$87,$f2,$30), ($bf,$a5,$b2,$23), ($03,$6a,$ba,$02), ($16,$82,$5c,$ed), - ($cf,$1c,$2b,$8a), ($79,$b4,$92,$a7), ($07,$f2,$f0,$f3), ($69,$e2,$a1,$4e), - ($da,$f4,$cd,$65), ($05,$be,$d5,$06), ($34,$62,$1f,$d1), ($a6,$fe,$8a,$c4), - ($2e,$53,$9d,$34), ($f3,$55,$a0,$a2), ($8a,$e1,$32,$05), ($f6,$eb,$75,$a4), - ($83,$ec,$39,$0b), ($60,$ef,$aa,$40), ($71,$9f,$06,$5e), ($6e,$10,$51,$bd), - ($21,$8a,$f9,$3e), ($dd,$06,$3d,$96), ($3e,$05,$ae,$dd), ($e6,$bd,$46,$4d), - ($54,$8d,$b5,$91), ($c4,$5d,$05,$71), ($06,$d4,$6f,$04), ($50,$15,$ff,$60), - ($98,$fb,$24,$19), ($bd,$e9,$97,$d6), ($40,$43,$cc,$89), ($d9,$9e,$77,$67), - ($e8,$42,$bd,$b0), ($89,$8b,$88,$07), ($19,$5b,$38,$e7), ($c8,$ee,$db,$79), - ($7c,$0a,$47,$a1), ($42,$0f,$e9,$7c), ($84,$1e,$c9,$f8), ($00,$00,$00,$00), - ($80,$86,$83,$09), ($2b,$ed,$48,$32), ($11,$70,$ac,$1e), ($5a,$72,$4e,$6c), - ($0e,$ff,$fb,$fd), ($85,$38,$56,$0f), ($ae,$d5,$1e,$3d), ($2d,$39,$27,$36), - ($0f,$d9,$64,$0a), ($5c,$a6,$21,$68), ($5b,$54,$d1,$9b), ($36,$2e,$3a,$24), - ($0a,$67,$b1,$0c), ($57,$e7,$0f,$93), ($ee,$96,$d2,$b4), ($9b,$91,$9e,$1b), - ($c0,$c5,$4f,$80), ($dc,$20,$a2,$61), ($77,$4b,$69,$5a), ($12,$1a,$16,$1c), - ($93,$ba,$0a,$e2), ($a0,$2a,$e5,$c0), ($22,$e0,$43,$3c), ($1b,$17,$1d,$12), - ($09,$0d,$0b,$0e), ($8b,$c7,$ad,$f2), ($b6,$a8,$b9,$2d), ($1e,$a9,$c8,$14), - ($f1,$19,$85,$57), ($75,$07,$4c,$af), ($99,$dd,$bb,$ee), ($7f,$60,$fd,$a3), - ($01,$26,$9f,$f7), ($72,$f5,$bc,$5c), ($66,$3b,$c5,$44), ($fb,$7e,$34,$5b), - ($43,$29,$76,$8b), ($23,$c6,$dc,$cb), ($ed,$fc,$68,$b6), ($e4,$f1,$63,$b8), - ($31,$dc,$ca,$d7), ($63,$85,$10,$42), ($97,$22,$40,$13), ($c6,$11,$20,$84), - ($4a,$24,$7d,$85), ($bb,$3d,$f8,$d2), ($f9,$32,$11,$ae), ($29,$a1,$6d,$c7), - ($9e,$2f,$4b,$1d), ($b2,$30,$f3,$dc), ($86,$52,$ec,$0d), ($c1,$e3,$d0,$77), - ($b3,$16,$6c,$2b), ($70,$b9,$99,$a9), ($94,$48,$fa,$11), ($e9,$64,$22,$47), - ($fc,$8c,$c4,$a8), ($f0,$3f,$1a,$a0), ($7d,$2c,$d8,$56), ($33,$90,$ef,$22), - ($49,$4e,$c7,$87), ($38,$d1,$c1,$d9), ($ca,$a2,$fe,$8c), ($d4,$0b,$36,$98), - ($f5,$81,$cf,$a6), ($7a,$de,$28,$a5), ($b7,$8e,$26,$da), ($ad,$bf,$a4,$3f), - ($3a,$9d,$e4,$2c), ($78,$92,$0d,$50), ($5f,$cc,$9b,$6a), ($7e,$46,$62,$54), - ($8d,$13,$c2,$f6), ($d8,$b8,$e8,$90), ($39,$f7,$5e,$2e), ($c3,$af,$f5,$82), - ($5d,$80,$be,$9f), ($d0,$93,$7c,$69), ($d5,$2d,$a9,$6f), ($25,$12,$b3,$cf), - ($ac,$99,$3b,$c8), ($18,$7d,$a7,$10), ($9c,$63,$6e,$e8), ($3b,$bb,$7b,$db), - ($26,$78,$09,$cd), ($59,$18,$f4,$6e), ($9a,$b7,$01,$ec), ($4f,$9a,$a8,$83), - ($95,$6e,$65,$e6), ($ff,$e6,$7e,$aa), ($bc,$cf,$08,$21), ($15,$e8,$e6,$ef), - ($e7,$9b,$d9,$ba), ($6f,$36,$ce,$4a), ($9f,$09,$d4,$ea), ($b0,$7c,$d6,$29), - ($a4,$b2,$af,$31), ($3f,$23,$31,$2a), ($a5,$94,$30,$c6), ($a2,$66,$c0,$35), - ($4e,$bc,$37,$74), ($82,$ca,$a6,$fc), ($90,$d0,$b0,$e0), ($a7,$d8,$15,$33), - ($04,$98,$4a,$f1), ($ec,$da,$f7,$41), ($cd,$50,$0e,$7f), ($91,$f6,$2f,$17), - ($4d,$d6,$8d,$76), ($ef,$b0,$4d,$43), ($aa,$4d,$54,$cc), ($96,$04,$df,$e4), - ($d1,$b5,$e3,$9e), ($6a,$88,$1b,$4c), ($2c,$1f,$b8,$c1), ($65,$51,$7f,$46), - ($5e,$ea,$04,$9d), ($8c,$35,$5d,$01), ($87,$74,$73,$fa), ($0b,$41,$2e,$fb), - ($67,$1d,$5a,$b3), ($db,$d2,$52,$92), ($10,$56,$33,$e9), ($d6,$47,$13,$6d), - ($d7,$61,$8c,$9a), ($a1,$0c,$7a,$37), ($f8,$14,$8e,$59), ($13,$3c,$89,$eb), - ($a9,$27,$ee,$ce), ($61,$c9,$35,$b7), ($1c,$e5,$ed,$e1), ($47,$b1,$3c,$7a), - ($d2,$df,$59,$9c), ($f2,$73,$3f,$55), ($14,$ce,$79,$18), ($c7,$37,$bf,$73), - ($f7,$cd,$ea,$53), ($fd,$aa,$5b,$5f), ($3d,$6f,$14,$df), ($44,$db,$86,$78), - ($af,$f3,$81,$ca), ($68,$c4,$3e,$b9), ($24,$34,$2c,$38), ($a3,$40,$5f,$c2), - ($1d,$c3,$72,$16), ($e2,$25,$0c,$bc), ($3c,$49,$8b,$28), ($0d,$95,$41,$ff), - ($a8,$01,$71,$39), ($0c,$b3,$de,$08), ($b4,$e4,$9c,$d8), ($56,$c1,$90,$64), - ($cb,$84,$61,$7b), ($32,$b6,$70,$d5), ($6c,$5c,$74,$48), ($b8,$57,$42,$d0)); - S5: array[0..255] of byte= ( - $52,$09,$6a,$d5, - $30,$36,$a5,$38, - $bf,$40,$a3,$9e, - $81,$f3,$d7,$fb, - $7c,$e3,$39,$82, - $9b,$2f,$ff,$87, - $34,$8e,$43,$44, - $c4,$de,$e9,$cb, - $54,$7b,$94,$32, - $a6,$c2,$23,$3d, - $ee,$4c,$95,$0b, - $42,$fa,$c3,$4e, - $08,$2e,$a1,$66, - $28,$d9,$24,$b2, - $76,$5b,$a2,$49, - $6d,$8b,$d1,$25, - $72,$f8,$f6,$64, - $86,$68,$98,$16, - $d4,$a4,$5c,$cc, - $5d,$65,$b6,$92, - $6c,$70,$48,$50, - $fd,$ed,$b9,$da, - $5e,$15,$46,$57, - $a7,$8d,$9d,$84, - $90,$d8,$ab,$00, - $8c,$bc,$d3,$0a, - $f7,$e4,$58,$05, - $b8,$b3,$45,$06, - $d0,$2c,$1e,$8f, - $ca,$3f,$0f,$02, - $c1,$af,$bd,$03, - $01,$13,$8a,$6b, - $3a,$91,$11,$41, - $4f,$67,$dc,$ea, - $97,$f2,$cf,$ce, - $f0,$b4,$e6,$73, - $96,$ac,$74,$22, - $e7,$ad,$35,$85, - $e2,$f9,$37,$e8, - $1c,$75,$df,$6e, - $47,$f1,$1a,$71, - $1d,$29,$c5,$89, - $6f,$b7,$62,$0e, - $aa,$18,$be,$1b, - $fc,$56,$3e,$4b, - $c6,$d2,$79,$20, - $9a,$db,$c0,$fe, - $78,$cd,$5a,$f4, - $1f,$dd,$a8,$33, - $88,$07,$c7,$31, - $b1,$12,$10,$59, - $27,$80,$ec,$5f, - $60,$51,$7f,$a9, - $19,$b5,$4a,$0d, - $2d,$e5,$7a,$9f, - $93,$c9,$9c,$ef, - $a0,$e0,$3b,$4d, - $ae,$2a,$f5,$b0, - $c8,$eb,$bb,$3c, - $83,$53,$99,$61, - $17,$2b,$04,$7e, - $ba,$77,$d6,$26, - $e1,$69,$14,$63, - $55,$21,$0c,$7d); - U1: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($0e,$09,$0d,$0b), ($1c,$12,$1a,$16), ($12,$1b,$17,$1d), - ($38,$24,$34,$2c), ($36,$2d,$39,$27), ($24,$36,$2e,$3a), ($2a,$3f,$23,$31), - ($70,$48,$68,$58), ($7e,$41,$65,$53), ($6c,$5a,$72,$4e), ($62,$53,$7f,$45), - ($48,$6c,$5c,$74), ($46,$65,$51,$7f), ($54,$7e,$46,$62), ($5a,$77,$4b,$69), - ($e0,$90,$d0,$b0), ($ee,$99,$dd,$bb), ($fc,$82,$ca,$a6), ($f2,$8b,$c7,$ad), - ($d8,$b4,$e4,$9c), ($d6,$bd,$e9,$97), ($c4,$a6,$fe,$8a), ($ca,$af,$f3,$81), - ($90,$d8,$b8,$e8), ($9e,$d1,$b5,$e3), ($8c,$ca,$a2,$fe), ($82,$c3,$af,$f5), - ($a8,$fc,$8c,$c4), ($a6,$f5,$81,$cf), ($b4,$ee,$96,$d2), ($ba,$e7,$9b,$d9), - ($db,$3b,$bb,$7b), ($d5,$32,$b6,$70), ($c7,$29,$a1,$6d), ($c9,$20,$ac,$66), - ($e3,$1f,$8f,$57), ($ed,$16,$82,$5c), ($ff,$0d,$95,$41), ($f1,$04,$98,$4a), - ($ab,$73,$d3,$23), ($a5,$7a,$de,$28), ($b7,$61,$c9,$35), ($b9,$68,$c4,$3e), - ($93,$57,$e7,$0f), ($9d,$5e,$ea,$04), ($8f,$45,$fd,$19), ($81,$4c,$f0,$12), - ($3b,$ab,$6b,$cb), ($35,$a2,$66,$c0), ($27,$b9,$71,$dd), ($29,$b0,$7c,$d6), - ($03,$8f,$5f,$e7), ($0d,$86,$52,$ec), ($1f,$9d,$45,$f1), ($11,$94,$48,$fa), - ($4b,$e3,$03,$93), ($45,$ea,$0e,$98), ($57,$f1,$19,$85), ($59,$f8,$14,$8e), - ($73,$c7,$37,$bf), ($7d,$ce,$3a,$b4), ($6f,$d5,$2d,$a9), ($61,$dc,$20,$a2), - ($ad,$76,$6d,$f6), ($a3,$7f,$60,$fd), ($b1,$64,$77,$e0), ($bf,$6d,$7a,$eb), - ($95,$52,$59,$da), ($9b,$5b,$54,$d1), ($89,$40,$43,$cc), ($87,$49,$4e,$c7), - ($dd,$3e,$05,$ae), ($d3,$37,$08,$a5), ($c1,$2c,$1f,$b8), ($cf,$25,$12,$b3), - ($e5,$1a,$31,$82), ($eb,$13,$3c,$89), ($f9,$08,$2b,$94), ($f7,$01,$26,$9f), - ($4d,$e6,$bd,$46), ($43,$ef,$b0,$4d), ($51,$f4,$a7,$50), ($5f,$fd,$aa,$5b), - ($75,$c2,$89,$6a), ($7b,$cb,$84,$61), ($69,$d0,$93,$7c), ($67,$d9,$9e,$77), - ($3d,$ae,$d5,$1e), ($33,$a7,$d8,$15), ($21,$bc,$cf,$08), ($2f,$b5,$c2,$03), - ($05,$8a,$e1,$32), ($0b,$83,$ec,$39), ($19,$98,$fb,$24), ($17,$91,$f6,$2f), - ($76,$4d,$d6,$8d), ($78,$44,$db,$86), ($6a,$5f,$cc,$9b), ($64,$56,$c1,$90), - ($4e,$69,$e2,$a1), ($40,$60,$ef,$aa), ($52,$7b,$f8,$b7), ($5c,$72,$f5,$bc), - ($06,$05,$be,$d5), ($08,$0c,$b3,$de), ($1a,$17,$a4,$c3), ($14,$1e,$a9,$c8), - ($3e,$21,$8a,$f9), ($30,$28,$87,$f2), ($22,$33,$90,$ef), ($2c,$3a,$9d,$e4), - ($96,$dd,$06,$3d), ($98,$d4,$0b,$36), ($8a,$cf,$1c,$2b), ($84,$c6,$11,$20), - ($ae,$f9,$32,$11), ($a0,$f0,$3f,$1a), ($b2,$eb,$28,$07), ($bc,$e2,$25,$0c), - ($e6,$95,$6e,$65), ($e8,$9c,$63,$6e), ($fa,$87,$74,$73), ($f4,$8e,$79,$78), - ($de,$b1,$5a,$49), ($d0,$b8,$57,$42), ($c2,$a3,$40,$5f), ($cc,$aa,$4d,$54), - ($41,$ec,$da,$f7), ($4f,$e5,$d7,$fc), ($5d,$fe,$c0,$e1), ($53,$f7,$cd,$ea), - ($79,$c8,$ee,$db), ($77,$c1,$e3,$d0), ($65,$da,$f4,$cd), ($6b,$d3,$f9,$c6), - ($31,$a4,$b2,$af), ($3f,$ad,$bf,$a4), ($2d,$b6,$a8,$b9), ($23,$bf,$a5,$b2), - ($09,$80,$86,$83), ($07,$89,$8b,$88), ($15,$92,$9c,$95), ($1b,$9b,$91,$9e), - ($a1,$7c,$0a,$47), ($af,$75,$07,$4c), ($bd,$6e,$10,$51), ($b3,$67,$1d,$5a), - ($99,$58,$3e,$6b), ($97,$51,$33,$60), ($85,$4a,$24,$7d), ($8b,$43,$29,$76), - ($d1,$34,$62,$1f), ($df,$3d,$6f,$14), ($cd,$26,$78,$09), ($c3,$2f,$75,$02), - ($e9,$10,$56,$33), ($e7,$19,$5b,$38), ($f5,$02,$4c,$25), ($fb,$0b,$41,$2e), - ($9a,$d7,$61,$8c), ($94,$de,$6c,$87), ($86,$c5,$7b,$9a), ($88,$cc,$76,$91), - ($a2,$f3,$55,$a0), ($ac,$fa,$58,$ab), ($be,$e1,$4f,$b6), ($b0,$e8,$42,$bd), - ($ea,$9f,$09,$d4), ($e4,$96,$04,$df), ($f6,$8d,$13,$c2), ($f8,$84,$1e,$c9), - ($d2,$bb,$3d,$f8), ($dc,$b2,$30,$f3), ($ce,$a9,$27,$ee), ($c0,$a0,$2a,$e5), - ($7a,$47,$b1,$3c), ($74,$4e,$bc,$37), ($66,$55,$ab,$2a), ($68,$5c,$a6,$21), - ($42,$63,$85,$10), ($4c,$6a,$88,$1b), ($5e,$71,$9f,$06), ($50,$78,$92,$0d), - ($0a,$0f,$d9,$64), ($04,$06,$d4,$6f), ($16,$1d,$c3,$72), ($18,$14,$ce,$79), - ($32,$2b,$ed,$48), ($3c,$22,$e0,$43), ($2e,$39,$f7,$5e), ($20,$30,$fa,$55), - ($ec,$9a,$b7,$01), ($e2,$93,$ba,$0a), ($f0,$88,$ad,$17), ($fe,$81,$a0,$1c), - ($d4,$be,$83,$2d), ($da,$b7,$8e,$26), ($c8,$ac,$99,$3b), ($c6,$a5,$94,$30), - ($9c,$d2,$df,$59), ($92,$db,$d2,$52), ($80,$c0,$c5,$4f), ($8e,$c9,$c8,$44), - ($a4,$f6,$eb,$75), ($aa,$ff,$e6,$7e), ($b8,$e4,$f1,$63), ($b6,$ed,$fc,$68), - ($0c,$0a,$67,$b1), ($02,$03,$6a,$ba), ($10,$18,$7d,$a7), ($1e,$11,$70,$ac), - ($34,$2e,$53,$9d), ($3a,$27,$5e,$96), ($28,$3c,$49,$8b), ($26,$35,$44,$80), - ($7c,$42,$0f,$e9), ($72,$4b,$02,$e2), ($60,$50,$15,$ff), ($6e,$59,$18,$f4), - ($44,$66,$3b,$c5), ($4a,$6f,$36,$ce), ($58,$74,$21,$d3), ($56,$7d,$2c,$d8), - ($37,$a1,$0c,$7a), ($39,$a8,$01,$71), ($2b,$b3,$16,$6c), ($25,$ba,$1b,$67), - ($0f,$85,$38,$56), ($01,$8c,$35,$5d), ($13,$97,$22,$40), ($1d,$9e,$2f,$4b), - ($47,$e9,$64,$22), ($49,$e0,$69,$29), ($5b,$fb,$7e,$34), ($55,$f2,$73,$3f), - ($7f,$cd,$50,$0e), ($71,$c4,$5d,$05), ($63,$df,$4a,$18), ($6d,$d6,$47,$13), - ($d7,$31,$dc,$ca), ($d9,$38,$d1,$c1), ($cb,$23,$c6,$dc), ($c5,$2a,$cb,$d7), - ($ef,$15,$e8,$e6), ($e1,$1c,$e5,$ed), ($f3,$07,$f2,$f0), ($fd,$0e,$ff,$fb), - ($a7,$79,$b4,$92), ($a9,$70,$b9,$99), ($bb,$6b,$ae,$84), ($b5,$62,$a3,$8f), - ($9f,$5d,$80,$be), ($91,$54,$8d,$b5), ($83,$4f,$9a,$a8), ($8d,$46,$97,$a3)); - U2: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($0b,$0e,$09,$0d), ($16,$1c,$12,$1a), ($1d,$12,$1b,$17), - ($2c,$38,$24,$34), ($27,$36,$2d,$39), ($3a,$24,$36,$2e), ($31,$2a,$3f,$23), - ($58,$70,$48,$68), ($53,$7e,$41,$65), ($4e,$6c,$5a,$72), ($45,$62,$53,$7f), - ($74,$48,$6c,$5c), ($7f,$46,$65,$51), ($62,$54,$7e,$46), ($69,$5a,$77,$4b), - ($b0,$e0,$90,$d0), ($bb,$ee,$99,$dd), ($a6,$fc,$82,$ca), ($ad,$f2,$8b,$c7), - ($9c,$d8,$b4,$e4), ($97,$d6,$bd,$e9), ($8a,$c4,$a6,$fe), ($81,$ca,$af,$f3), - ($e8,$90,$d8,$b8), ($e3,$9e,$d1,$b5), ($fe,$8c,$ca,$a2), ($f5,$82,$c3,$af), - ($c4,$a8,$fc,$8c), ($cf,$a6,$f5,$81), ($d2,$b4,$ee,$96), ($d9,$ba,$e7,$9b), - ($7b,$db,$3b,$bb), ($70,$d5,$32,$b6), ($6d,$c7,$29,$a1), ($66,$c9,$20,$ac), - ($57,$e3,$1f,$8f), ($5c,$ed,$16,$82), ($41,$ff,$0d,$95), ($4a,$f1,$04,$98), - ($23,$ab,$73,$d3), ($28,$a5,$7a,$de), ($35,$b7,$61,$c9), ($3e,$b9,$68,$c4), - ($0f,$93,$57,$e7), ($04,$9d,$5e,$ea), ($19,$8f,$45,$fd), ($12,$81,$4c,$f0), - ($cb,$3b,$ab,$6b), ($c0,$35,$a2,$66), ($dd,$27,$b9,$71), ($d6,$29,$b0,$7c), - ($e7,$03,$8f,$5f), ($ec,$0d,$86,$52), ($f1,$1f,$9d,$45), ($fa,$11,$94,$48), - ($93,$4b,$e3,$03), ($98,$45,$ea,$0e), ($85,$57,$f1,$19), ($8e,$59,$f8,$14), - ($bf,$73,$c7,$37), ($b4,$7d,$ce,$3a), ($a9,$6f,$d5,$2d), ($a2,$61,$dc,$20), - ($f6,$ad,$76,$6d), ($fd,$a3,$7f,$60), ($e0,$b1,$64,$77), ($eb,$bf,$6d,$7a), - ($da,$95,$52,$59), ($d1,$9b,$5b,$54), ($cc,$89,$40,$43), ($c7,$87,$49,$4e), - ($ae,$dd,$3e,$05), ($a5,$d3,$37,$08), ($b8,$c1,$2c,$1f), ($b3,$cf,$25,$12), - ($82,$e5,$1a,$31), ($89,$eb,$13,$3c), ($94,$f9,$08,$2b), ($9f,$f7,$01,$26), - ($46,$4d,$e6,$bd), ($4d,$43,$ef,$b0), ($50,$51,$f4,$a7), ($5b,$5f,$fd,$aa), - ($6a,$75,$c2,$89), ($61,$7b,$cb,$84), ($7c,$69,$d0,$93), ($77,$67,$d9,$9e), - ($1e,$3d,$ae,$d5), ($15,$33,$a7,$d8), ($08,$21,$bc,$cf), ($03,$2f,$b5,$c2), - ($32,$05,$8a,$e1), ($39,$0b,$83,$ec), ($24,$19,$98,$fb), ($2f,$17,$91,$f6), - ($8d,$76,$4d,$d6), ($86,$78,$44,$db), ($9b,$6a,$5f,$cc), ($90,$64,$56,$c1), - ($a1,$4e,$69,$e2), ($aa,$40,$60,$ef), ($b7,$52,$7b,$f8), ($bc,$5c,$72,$f5), - ($d5,$06,$05,$be), ($de,$08,$0c,$b3), ($c3,$1a,$17,$a4), ($c8,$14,$1e,$a9), - ($f9,$3e,$21,$8a), ($f2,$30,$28,$87), ($ef,$22,$33,$90), ($e4,$2c,$3a,$9d), - ($3d,$96,$dd,$06), ($36,$98,$d4,$0b), ($2b,$8a,$cf,$1c), ($20,$84,$c6,$11), - ($11,$ae,$f9,$32), ($1a,$a0,$f0,$3f), ($07,$b2,$eb,$28), ($0c,$bc,$e2,$25), - ($65,$e6,$95,$6e), ($6e,$e8,$9c,$63), ($73,$fa,$87,$74), ($78,$f4,$8e,$79), - ($49,$de,$b1,$5a), ($42,$d0,$b8,$57), ($5f,$c2,$a3,$40), ($54,$cc,$aa,$4d), - ($f7,$41,$ec,$da), ($fc,$4f,$e5,$d7), ($e1,$5d,$fe,$c0), ($ea,$53,$f7,$cd), - ($db,$79,$c8,$ee), ($d0,$77,$c1,$e3), ($cd,$65,$da,$f4), ($c6,$6b,$d3,$f9), - ($af,$31,$a4,$b2), ($a4,$3f,$ad,$bf), ($b9,$2d,$b6,$a8), ($b2,$23,$bf,$a5), - ($83,$09,$80,$86), ($88,$07,$89,$8b), ($95,$15,$92,$9c), ($9e,$1b,$9b,$91), - ($47,$a1,$7c,$0a), ($4c,$af,$75,$07), ($51,$bd,$6e,$10), ($5a,$b3,$67,$1d), - ($6b,$99,$58,$3e), ($60,$97,$51,$33), ($7d,$85,$4a,$24), ($76,$8b,$43,$29), - ($1f,$d1,$34,$62), ($14,$df,$3d,$6f), ($09,$cd,$26,$78), ($02,$c3,$2f,$75), - ($33,$e9,$10,$56), ($38,$e7,$19,$5b), ($25,$f5,$02,$4c), ($2e,$fb,$0b,$41), - ($8c,$9a,$d7,$61), ($87,$94,$de,$6c), ($9a,$86,$c5,$7b), ($91,$88,$cc,$76), - ($a0,$a2,$f3,$55), ($ab,$ac,$fa,$58), ($b6,$be,$e1,$4f), ($bd,$b0,$e8,$42), - ($d4,$ea,$9f,$09), ($df,$e4,$96,$04), ($c2,$f6,$8d,$13), ($c9,$f8,$84,$1e), - ($f8,$d2,$bb,$3d), ($f3,$dc,$b2,$30), ($ee,$ce,$a9,$27), ($e5,$c0,$a0,$2a), - ($3c,$7a,$47,$b1), ($37,$74,$4e,$bc), ($2a,$66,$55,$ab), ($21,$68,$5c,$a6), - ($10,$42,$63,$85), ($1b,$4c,$6a,$88), ($06,$5e,$71,$9f), ($0d,$50,$78,$92), - ($64,$0a,$0f,$d9), ($6f,$04,$06,$d4), ($72,$16,$1d,$c3), ($79,$18,$14,$ce), - ($48,$32,$2b,$ed), ($43,$3c,$22,$e0), ($5e,$2e,$39,$f7), ($55,$20,$30,$fa), - ($01,$ec,$9a,$b7), ($0a,$e2,$93,$ba), ($17,$f0,$88,$ad), ($1c,$fe,$81,$a0), - ($2d,$d4,$be,$83), ($26,$da,$b7,$8e), ($3b,$c8,$ac,$99), ($30,$c6,$a5,$94), - ($59,$9c,$d2,$df), ($52,$92,$db,$d2), ($4f,$80,$c0,$c5), ($44,$8e,$c9,$c8), - ($75,$a4,$f6,$eb), ($7e,$aa,$ff,$e6), ($63,$b8,$e4,$f1), ($68,$b6,$ed,$fc), - ($b1,$0c,$0a,$67), ($ba,$02,$03,$6a), ($a7,$10,$18,$7d), ($ac,$1e,$11,$70), - ($9d,$34,$2e,$53), ($96,$3a,$27,$5e), ($8b,$28,$3c,$49), ($80,$26,$35,$44), - ($e9,$7c,$42,$0f), ($e2,$72,$4b,$02), ($ff,$60,$50,$15), ($f4,$6e,$59,$18), - ($c5,$44,$66,$3b), ($ce,$4a,$6f,$36), ($d3,$58,$74,$21), ($d8,$56,$7d,$2c), - ($7a,$37,$a1,$0c), ($71,$39,$a8,$01), ($6c,$2b,$b3,$16), ($67,$25,$ba,$1b), - ($56,$0f,$85,$38), ($5d,$01,$8c,$35), ($40,$13,$97,$22), ($4b,$1d,$9e,$2f), - ($22,$47,$e9,$64), ($29,$49,$e0,$69), ($34,$5b,$fb,$7e), ($3f,$55,$f2,$73), - ($0e,$7f,$cd,$50), ($05,$71,$c4,$5d), ($18,$63,$df,$4a), ($13,$6d,$d6,$47), - ($ca,$d7,$31,$dc), ($c1,$d9,$38,$d1), ($dc,$cb,$23,$c6), ($d7,$c5,$2a,$cb), - ($e6,$ef,$15,$e8), ($ed,$e1,$1c,$e5), ($f0,$f3,$07,$f2), ($fb,$fd,$0e,$ff), - ($92,$a7,$79,$b4), ($99,$a9,$70,$b9), ($84,$bb,$6b,$ae), ($8f,$b5,$62,$a3), - ($be,$9f,$5d,$80), ($b5,$91,$54,$8d), ($a8,$83,$4f,$9a), ($a3,$8d,$46,$97)); - U3: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($0d,$0b,$0e,$09), ($1a,$16,$1c,$12), ($17,$1d,$12,$1b), - ($34,$2c,$38,$24), ($39,$27,$36,$2d), ($2e,$3a,$24,$36), ($23,$31,$2a,$3f), - ($68,$58,$70,$48), ($65,$53,$7e,$41), ($72,$4e,$6c,$5a), ($7f,$45,$62,$53), - ($5c,$74,$48,$6c), ($51,$7f,$46,$65), ($46,$62,$54,$7e), ($4b,$69,$5a,$77), - ($d0,$b0,$e0,$90), ($dd,$bb,$ee,$99), ($ca,$a6,$fc,$82), ($c7,$ad,$f2,$8b), - ($e4,$9c,$d8,$b4), ($e9,$97,$d6,$bd), ($fe,$8a,$c4,$a6), ($f3,$81,$ca,$af), - ($b8,$e8,$90,$d8), ($b5,$e3,$9e,$d1), ($a2,$fe,$8c,$ca), ($af,$f5,$82,$c3), - ($8c,$c4,$a8,$fc), ($81,$cf,$a6,$f5), ($96,$d2,$b4,$ee), ($9b,$d9,$ba,$e7), - ($bb,$7b,$db,$3b), ($b6,$70,$d5,$32), ($a1,$6d,$c7,$29), ($ac,$66,$c9,$20), - ($8f,$57,$e3,$1f), ($82,$5c,$ed,$16), ($95,$41,$ff,$0d), ($98,$4a,$f1,$04), - ($d3,$23,$ab,$73), ($de,$28,$a5,$7a), ($c9,$35,$b7,$61), ($c4,$3e,$b9,$68), - ($e7,$0f,$93,$57), ($ea,$04,$9d,$5e), ($fd,$19,$8f,$45), ($f0,$12,$81,$4c), - ($6b,$cb,$3b,$ab), ($66,$c0,$35,$a2), ($71,$dd,$27,$b9), ($7c,$d6,$29,$b0), - ($5f,$e7,$03,$8f), ($52,$ec,$0d,$86), ($45,$f1,$1f,$9d), ($48,$fa,$11,$94), - ($03,$93,$4b,$e3), ($0e,$98,$45,$ea), ($19,$85,$57,$f1), ($14,$8e,$59,$f8), - ($37,$bf,$73,$c7), ($3a,$b4,$7d,$ce), ($2d,$a9,$6f,$d5), ($20,$a2,$61,$dc), - ($6d,$f6,$ad,$76), ($60,$fd,$a3,$7f), ($77,$e0,$b1,$64), ($7a,$eb,$bf,$6d), - ($59,$da,$95,$52), ($54,$d1,$9b,$5b), ($43,$cc,$89,$40), ($4e,$c7,$87,$49), - ($05,$ae,$dd,$3e), ($08,$a5,$d3,$37), ($1f,$b8,$c1,$2c), ($12,$b3,$cf,$25), - ($31,$82,$e5,$1a), ($3c,$89,$eb,$13), ($2b,$94,$f9,$08), ($26,$9f,$f7,$01), - ($bd,$46,$4d,$e6), ($b0,$4d,$43,$ef), ($a7,$50,$51,$f4), ($aa,$5b,$5f,$fd), - ($89,$6a,$75,$c2), ($84,$61,$7b,$cb), ($93,$7c,$69,$d0), ($9e,$77,$67,$d9), - ($d5,$1e,$3d,$ae), ($d8,$15,$33,$a7), ($cf,$08,$21,$bc), ($c2,$03,$2f,$b5), - ($e1,$32,$05,$8a), ($ec,$39,$0b,$83), ($fb,$24,$19,$98), ($f6,$2f,$17,$91), - ($d6,$8d,$76,$4d), ($db,$86,$78,$44), ($cc,$9b,$6a,$5f), ($c1,$90,$64,$56), - ($e2,$a1,$4e,$69), ($ef,$aa,$40,$60), ($f8,$b7,$52,$7b), ($f5,$bc,$5c,$72), - ($be,$d5,$06,$05), ($b3,$de,$08,$0c), ($a4,$c3,$1a,$17), ($a9,$c8,$14,$1e), - ($8a,$f9,$3e,$21), ($87,$f2,$30,$28), ($90,$ef,$22,$33), ($9d,$e4,$2c,$3a), - ($06,$3d,$96,$dd), ($0b,$36,$98,$d4), ($1c,$2b,$8a,$cf), ($11,$20,$84,$c6), - ($32,$11,$ae,$f9), ($3f,$1a,$a0,$f0), ($28,$07,$b2,$eb), ($25,$0c,$bc,$e2), - ($6e,$65,$e6,$95), ($63,$6e,$e8,$9c), ($74,$73,$fa,$87), ($79,$78,$f4,$8e), - ($5a,$49,$de,$b1), ($57,$42,$d0,$b8), ($40,$5f,$c2,$a3), ($4d,$54,$cc,$aa), - ($da,$f7,$41,$ec), ($d7,$fc,$4f,$e5), ($c0,$e1,$5d,$fe), ($cd,$ea,$53,$f7), - ($ee,$db,$79,$c8), ($e3,$d0,$77,$c1), ($f4,$cd,$65,$da), ($f9,$c6,$6b,$d3), - ($b2,$af,$31,$a4), ($bf,$a4,$3f,$ad), ($a8,$b9,$2d,$b6), ($a5,$b2,$23,$bf), - ($86,$83,$09,$80), ($8b,$88,$07,$89), ($9c,$95,$15,$92), ($91,$9e,$1b,$9b), - ($0a,$47,$a1,$7c), ($07,$4c,$af,$75), ($10,$51,$bd,$6e), ($1d,$5a,$b3,$67), - ($3e,$6b,$99,$58), ($33,$60,$97,$51), ($24,$7d,$85,$4a), ($29,$76,$8b,$43), - ($62,$1f,$d1,$34), ($6f,$14,$df,$3d), ($78,$09,$cd,$26), ($75,$02,$c3,$2f), - ($56,$33,$e9,$10), ($5b,$38,$e7,$19), ($4c,$25,$f5,$02), ($41,$2e,$fb,$0b), - ($61,$8c,$9a,$d7), ($6c,$87,$94,$de), ($7b,$9a,$86,$c5), ($76,$91,$88,$cc), - ($55,$a0,$a2,$f3), ($58,$ab,$ac,$fa), ($4f,$b6,$be,$e1), ($42,$bd,$b0,$e8), - ($09,$d4,$ea,$9f), ($04,$df,$e4,$96), ($13,$c2,$f6,$8d), ($1e,$c9,$f8,$84), - ($3d,$f8,$d2,$bb), ($30,$f3,$dc,$b2), ($27,$ee,$ce,$a9), ($2a,$e5,$c0,$a0), - ($b1,$3c,$7a,$47), ($bc,$37,$74,$4e), ($ab,$2a,$66,$55), ($a6,$21,$68,$5c), - ($85,$10,$42,$63), ($88,$1b,$4c,$6a), ($9f,$06,$5e,$71), ($92,$0d,$50,$78), - ($d9,$64,$0a,$0f), ($d4,$6f,$04,$06), ($c3,$72,$16,$1d), ($ce,$79,$18,$14), - ($ed,$48,$32,$2b), ($e0,$43,$3c,$22), ($f7,$5e,$2e,$39), ($fa,$55,$20,$30), - ($b7,$01,$ec,$9a), ($ba,$0a,$e2,$93), ($ad,$17,$f0,$88), ($a0,$1c,$fe,$81), - ($83,$2d,$d4,$be), ($8e,$26,$da,$b7), ($99,$3b,$c8,$ac), ($94,$30,$c6,$a5), - ($df,$59,$9c,$d2), ($d2,$52,$92,$db), ($c5,$4f,$80,$c0), ($c8,$44,$8e,$c9), - ($eb,$75,$a4,$f6), ($e6,$7e,$aa,$ff), ($f1,$63,$b8,$e4), ($fc,$68,$b6,$ed), - ($67,$b1,$0c,$0a), ($6a,$ba,$02,$03), ($7d,$a7,$10,$18), ($70,$ac,$1e,$11), - ($53,$9d,$34,$2e), ($5e,$96,$3a,$27), ($49,$8b,$28,$3c), ($44,$80,$26,$35), - ($0f,$e9,$7c,$42), ($02,$e2,$72,$4b), ($15,$ff,$60,$50), ($18,$f4,$6e,$59), - ($3b,$c5,$44,$66), ($36,$ce,$4a,$6f), ($21,$d3,$58,$74), ($2c,$d8,$56,$7d), - ($0c,$7a,$37,$a1), ($01,$71,$39,$a8), ($16,$6c,$2b,$b3), ($1b,$67,$25,$ba), - ($38,$56,$0f,$85), ($35,$5d,$01,$8c), ($22,$40,$13,$97), ($2f,$4b,$1d,$9e), - ($64,$22,$47,$e9), ($69,$29,$49,$e0), ($7e,$34,$5b,$fb), ($73,$3f,$55,$f2), - ($50,$0e,$7f,$cd), ($5d,$05,$71,$c4), ($4a,$18,$63,$df), ($47,$13,$6d,$d6), - ($dc,$ca,$d7,$31), ($d1,$c1,$d9,$38), ($c6,$dc,$cb,$23), ($cb,$d7,$c5,$2a), - ($e8,$e6,$ef,$15), ($e5,$ed,$e1,$1c), ($f2,$f0,$f3,$07), ($ff,$fb,$fd,$0e), - ($b4,$92,$a7,$79), ($b9,$99,$a9,$70), ($ae,$84,$bb,$6b), ($a3,$8f,$b5,$62), - ($80,$be,$9f,$5d), ($8d,$b5,$91,$54), ($9a,$a8,$83,$4f), ($97,$a3,$8d,$46)); - U4: array[0..255,0..3] of byte= ( - ($00,$00,$00,$00), ($09,$0d,$0b,$0e), ($12,$1a,$16,$1c), ($1b,$17,$1d,$12), - ($24,$34,$2c,$38), ($2d,$39,$27,$36), ($36,$2e,$3a,$24), ($3f,$23,$31,$2a), - ($48,$68,$58,$70), ($41,$65,$53,$7e), ($5a,$72,$4e,$6c), ($53,$7f,$45,$62), - ($6c,$5c,$74,$48), ($65,$51,$7f,$46), ($7e,$46,$62,$54), ($77,$4b,$69,$5a), - ($90,$d0,$b0,$e0), ($99,$dd,$bb,$ee), ($82,$ca,$a6,$fc), ($8b,$c7,$ad,$f2), - ($b4,$e4,$9c,$d8), ($bd,$e9,$97,$d6), ($a6,$fe,$8a,$c4), ($af,$f3,$81,$ca), - ($d8,$b8,$e8,$90), ($d1,$b5,$e3,$9e), ($ca,$a2,$fe,$8c), ($c3,$af,$f5,$82), - ($fc,$8c,$c4,$a8), ($f5,$81,$cf,$a6), ($ee,$96,$d2,$b4), ($e7,$9b,$d9,$ba), - ($3b,$bb,$7b,$db), ($32,$b6,$70,$d5), ($29,$a1,$6d,$c7), ($20,$ac,$66,$c9), - ($1f,$8f,$57,$e3), ($16,$82,$5c,$ed), ($0d,$95,$41,$ff), ($04,$98,$4a,$f1), - ($73,$d3,$23,$ab), ($7a,$de,$28,$a5), ($61,$c9,$35,$b7), ($68,$c4,$3e,$b9), - ($57,$e7,$0f,$93), ($5e,$ea,$04,$9d), ($45,$fd,$19,$8f), ($4c,$f0,$12,$81), - ($ab,$6b,$cb,$3b), ($a2,$66,$c0,$35), ($b9,$71,$dd,$27), ($b0,$7c,$d6,$29), - ($8f,$5f,$e7,$03), ($86,$52,$ec,$0d), ($9d,$45,$f1,$1f), ($94,$48,$fa,$11), - ($e3,$03,$93,$4b), ($ea,$0e,$98,$45), ($f1,$19,$85,$57), ($f8,$14,$8e,$59), - ($c7,$37,$bf,$73), ($ce,$3a,$b4,$7d), ($d5,$2d,$a9,$6f), ($dc,$20,$a2,$61), - ($76,$6d,$f6,$ad), ($7f,$60,$fd,$a3), ($64,$77,$e0,$b1), ($6d,$7a,$eb,$bf), - ($52,$59,$da,$95), ($5b,$54,$d1,$9b), ($40,$43,$cc,$89), ($49,$4e,$c7,$87), - ($3e,$05,$ae,$dd), ($37,$08,$a5,$d3), ($2c,$1f,$b8,$c1), ($25,$12,$b3,$cf), - ($1a,$31,$82,$e5), ($13,$3c,$89,$eb), ($08,$2b,$94,$f9), ($01,$26,$9f,$f7), - ($e6,$bd,$46,$4d), ($ef,$b0,$4d,$43), ($f4,$a7,$50,$51), ($fd,$aa,$5b,$5f), - ($c2,$89,$6a,$75), ($cb,$84,$61,$7b), ($d0,$93,$7c,$69), ($d9,$9e,$77,$67), - ($ae,$d5,$1e,$3d), ($a7,$d8,$15,$33), ($bc,$cf,$08,$21), ($b5,$c2,$03,$2f), - ($8a,$e1,$32,$05), ($83,$ec,$39,$0b), ($98,$fb,$24,$19), ($91,$f6,$2f,$17), - ($4d,$d6,$8d,$76), ($44,$db,$86,$78), ($5f,$cc,$9b,$6a), ($56,$c1,$90,$64), - ($69,$e2,$a1,$4e), ($60,$ef,$aa,$40), ($7b,$f8,$b7,$52), ($72,$f5,$bc,$5c), - ($05,$be,$d5,$06), ($0c,$b3,$de,$08), ($17,$a4,$c3,$1a), ($1e,$a9,$c8,$14), - ($21,$8a,$f9,$3e), ($28,$87,$f2,$30), ($33,$90,$ef,$22), ($3a,$9d,$e4,$2c), - ($dd,$06,$3d,$96), ($d4,$0b,$36,$98), ($cf,$1c,$2b,$8a), ($c6,$11,$20,$84), - ($f9,$32,$11,$ae), ($f0,$3f,$1a,$a0), ($eb,$28,$07,$b2), ($e2,$25,$0c,$bc), - ($95,$6e,$65,$e6), ($9c,$63,$6e,$e8), ($87,$74,$73,$fa), ($8e,$79,$78,$f4), - ($b1,$5a,$49,$de), ($b8,$57,$42,$d0), ($a3,$40,$5f,$c2), ($aa,$4d,$54,$cc), - ($ec,$da,$f7,$41), ($e5,$d7,$fc,$4f), ($fe,$c0,$e1,$5d), ($f7,$cd,$ea,$53), - ($c8,$ee,$db,$79), ($c1,$e3,$d0,$77), ($da,$f4,$cd,$65), ($d3,$f9,$c6,$6b), - ($a4,$b2,$af,$31), ($ad,$bf,$a4,$3f), ($b6,$a8,$b9,$2d), ($bf,$a5,$b2,$23), - ($80,$86,$83,$09), ($89,$8b,$88,$07), ($92,$9c,$95,$15), ($9b,$91,$9e,$1b), - ($7c,$0a,$47,$a1), ($75,$07,$4c,$af), ($6e,$10,$51,$bd), ($67,$1d,$5a,$b3), - ($58,$3e,$6b,$99), ($51,$33,$60,$97), ($4a,$24,$7d,$85), ($43,$29,$76,$8b), - ($34,$62,$1f,$d1), ($3d,$6f,$14,$df), ($26,$78,$09,$cd), ($2f,$75,$02,$c3), - ($10,$56,$33,$e9), ($19,$5b,$38,$e7), ($02,$4c,$25,$f5), ($0b,$41,$2e,$fb), - ($d7,$61,$8c,$9a), ($de,$6c,$87,$94), ($c5,$7b,$9a,$86), ($cc,$76,$91,$88), - ($f3,$55,$a0,$a2), ($fa,$58,$ab,$ac), ($e1,$4f,$b6,$be), ($e8,$42,$bd,$b0), - ($9f,$09,$d4,$ea), ($96,$04,$df,$e4), ($8d,$13,$c2,$f6), ($84,$1e,$c9,$f8), - ($bb,$3d,$f8,$d2), ($b2,$30,$f3,$dc), ($a9,$27,$ee,$ce), ($a0,$2a,$e5,$c0), - ($47,$b1,$3c,$7a), ($4e,$bc,$37,$74), ($55,$ab,$2a,$66), ($5c,$a6,$21,$68), - ($63,$85,$10,$42), ($6a,$88,$1b,$4c), ($71,$9f,$06,$5e), ($78,$92,$0d,$50), - ($0f,$d9,$64,$0a), ($06,$d4,$6f,$04), ($1d,$c3,$72,$16), ($14,$ce,$79,$18), - ($2b,$ed,$48,$32), ($22,$e0,$43,$3c), ($39,$f7,$5e,$2e), ($30,$fa,$55,$20), - ($9a,$b7,$01,$ec), ($93,$ba,$0a,$e2), ($88,$ad,$17,$f0), ($81,$a0,$1c,$fe), - ($be,$83,$2d,$d4), ($b7,$8e,$26,$da), ($ac,$99,$3b,$c8), ($a5,$94,$30,$c6), - ($d2,$df,$59,$9c), ($db,$d2,$52,$92), ($c0,$c5,$4f,$80), ($c9,$c8,$44,$8e), - ($f6,$eb,$75,$a4), ($ff,$e6,$7e,$aa), ($e4,$f1,$63,$b8), ($ed,$fc,$68,$b6), - ($0a,$67,$b1,$0c), ($03,$6a,$ba,$02), ($18,$7d,$a7,$10), ($11,$70,$ac,$1e), - ($2e,$53,$9d,$34), ($27,$5e,$96,$3a), ($3c,$49,$8b,$28), ($35,$44,$80,$26), - ($42,$0f,$e9,$7c), ($4b,$02,$e2,$72), ($50,$15,$ff,$60), ($59,$18,$f4,$6e), - ($66,$3b,$c5,$44), ($6f,$36,$ce,$4a), ($74,$21,$d3,$58), ($7d,$2c,$d8,$56), - ($a1,$0c,$7a,$37), ($a8,$01,$71,$39), ($b3,$16,$6c,$2b), ($ba,$1b,$67,$25), - ($85,$38,$56,$0f), ($8c,$35,$5d,$01), ($97,$22,$40,$13), ($9e,$2f,$4b,$1d), - ($e9,$64,$22,$47), ($e0,$69,$29,$49), ($fb,$7e,$34,$5b), ($f2,$73,$3f,$55), - ($cd,$50,$0e,$7f), ($c4,$5d,$05,$71), ($df,$4a,$18,$63), ($d6,$47,$13,$6d), - ($31,$dc,$ca,$d7), ($38,$d1,$c1,$d9), ($23,$c6,$dc,$cb), ($2a,$cb,$d7,$c5), - ($15,$e8,$e6,$ef), ($1c,$e5,$ed,$e1), ($07,$f2,$f0,$f3), ($0e,$ff,$fb,$fd), - ($79,$b4,$92,$a7), ($70,$b9,$99,$a9), ($6b,$ae,$84,$bb), ($62,$a3,$8f,$b5), - ($5d,$80,$be,$9f), ($54,$8d,$b5,$91), ($4f,$9a,$a8,$83), ($46,$97,$a3,$8d)); - - rcon: array[0..29] of cardinal= ( - $01, $02, $04, $08, $10, $20, $40, $80, $1b, $36, $6c, $d8, $ab, $4d, $9a, - $2f, $5e, $bc, $63, $c6, $97, $35, $6a, $d4, $b3, $7d, $fa, $ef, $c5, $91); - -{==============================================================================} -type - PDWord = ^LongWord; - -procedure hperm_op(var a, t: integer; n, m: integer); -begin - t:= ((a shl (16 - n)) xor a) and m; - a:= a xor t xor (t shr (16 - n)); -end; - -procedure perm_op(var a, b, t: integer; n, m: integer); -begin - t:= ((a shr n) xor b) and m; - b:= b xor t; - a:= a xor (t shl n); -end; - -{==============================================================================} -function TSynaBlockCipher.GetSize: byte; -begin - Result := 8; -end; - -procedure TSynaBlockCipher.IncCounter; -var - i: integer; -begin - Inc(CV[GetSize]); - i:= GetSize -1; - while (i> 0) and (CV[i + 1] = #0) do - begin - Inc(CV[i]); - Dec(i); - end; -end; - -procedure TSynaBlockCipher.Reset; -begin - CV := IV; -end; - -procedure TSynaBlockCipher.InitKey(Key: AnsiString); -begin -end; - -procedure TSynaBlockCipher.SetIV(const Value: AnsiString); -begin - IV := PadString(Value, GetSize, #0); - Reset; -end; - -function TSynaBlockCipher.GetIV: AnsiString; -begin - Result := CV; -end; - -function TSynaBlockCipher.EncryptECB(const InData: AnsiString): AnsiString; -begin - Result := InData; -end; - -function TSynaBlockCipher.DecryptECB(const InData: AnsiString): AnsiString; -begin - Result := InData; -end; - -function TSynaBlockCipher.EncryptCBC(const Indata: AnsiString): AnsiString; -var - i: integer; - s: ansistring; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - s := EncryptECB(s); - CV := s; - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptCBC(const Indata: AnsiString): AnsiString; -var - i: integer; - s, temp: ansistring; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - s := copy(Indata, (i - 1) * bs + 1, bs); - temp := s; - s := DecryptECB(s); - s := XorString(s, CV); - Result := Result + s; - CV := Temp; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.EncryptCFB8bit(const Indata: AnsiString): AnsiString; -var - i: integer; - Temp: AnsiString; - c: AnsiChar; -begin - Result := ''; - for i:= 1 to Length(Indata) do - begin - Temp := EncryptECB(CV); - c := AnsiChar(ord(InData[i]) xor ord(temp[1])); - Result := Result + c; - Delete(CV, 1, 1); - CV := CV + c; - end; -end; - -function TSynaBlockCipher.DecryptCFB8bit(const Indata: AnsiString): AnsiString; -var - i: integer; - Temp: AnsiString; - c: AnsiChar; -begin - Result := ''; - for i:= 1 to length(Indata) do - begin - c:= Indata[i]; - Temp := EncryptECB(CV); - Result := Result + AnsiChar(ord(InData[i]) xor ord(temp[1])); - Delete(CV, 1, 1); - CV := CV + c; - end; -end; - -function TSynaBlockCipher.EncryptCFBblock(const Indata: AnsiString): AnsiString; -var - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - CV := EncryptECB(CV); - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - Result := Result + s; - CV := s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptCFBblock(const Indata: AnsiString): AnsiString; -var - i: integer; - S, Temp: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - s := copy(Indata, (i - 1) * bs + 1, bs); - Temp := s; - CV := EncryptECB(CV); - s := XorString(s, CV); - Result := result + s; - CV := temp; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.EncryptOFB(const Indata: AnsiString): AnsiString; -var - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - CV := EncryptECB(CV); - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptOFB(const Indata: AnsiString): AnsiString; -var - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - Cv := EncryptECB(CV); - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, CV); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - CV := EncryptECB(CV); - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, CV); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.EncryptCTR(const Indata: AnsiString): AnsiString; -var - temp: AnsiString; - i: integer; - s: AnsiString; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, temp); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, temp); - Result := Result + s; - end; -end; - -function TSynaBlockCipher.DecryptCTR(const Indata: AnsiString): AnsiString; -var - temp: AnsiString; - s: AnsiString; - i: integer; - l: integer; - bs: byte; -begin - Result := ''; - l := Length(InData); - bs := GetSize; - for i:= 1 to (l div bs) do - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (i - 1) * bs + 1, bs); - s := XorString(s, temp); - Result := Result + s; - end; - if (l mod bs)<> 0 then - begin - temp := EncryptECB(CV); - IncCounter; - s := copy(Indata, (l div bs) * bs + 1, l mod bs); - s := XorString(s, temp); - Result := Result + s; - end; -end; - -constructor TSynaBlockCipher.Create(Key: AnsiString); -begin - inherited Create; - InitKey(Key); - IV := StringOfChar(#0, GetSize); - IV := EncryptECB(IV); - Reset; -end; - -{==============================================================================} - -procedure TSynaCustomDes.DoInit(KeyB: AnsiString; var KeyData: TDesKeyData); -var - c, d, t, s, t2, i: integer; -begin - KeyB := PadString(KeyB, 8, #0); - c:= ord(KeyB[1]) or (ord(KeyB[2]) shl 8) or (ord(KeyB[3]) shl 16) or (ord(KeyB[4]) shl 24); - d:= ord(KeyB[5]) or (ord(KeyB[6]) shl 8) or (ord(KeyB[7]) shl 16) or (ord(KeyB[8]) shl 24); - perm_op(d,c,t,4,integer($0f0f0f0f)); - hperm_op(c,t,integer(-2),integer($cccc0000)); - hperm_op(d,t,integer(-2),integer($cccc0000)); - perm_op(d,c,t,1,integer($55555555)); - perm_op(c,d,t,8,integer($00ff00ff)); - perm_op(d,c,t,1,integer($55555555)); - d:= ((d and $ff) shl 16) or (d and $ff00) or ((d and $ff0000) shr 16) or - ((c and integer($f0000000)) shr 4); - c:= c and $fffffff; - for i:= 0 to 15 do - begin - if shifts2[i]<> 0 then - begin - c:= ((c shr 2) or (c shl 26)); - d:= ((d shr 2) or (d shl 26)); - end - else - begin - c:= ((c shr 1) or (c shl 27)); - d:= ((d shr 1) or (d shl 27)); - end; - c:= c and $fffffff; - d:= d and $fffffff; - s:= des_skb[0,c and $3f] or - des_skb[1,((c shr 6) and $03) or ((c shr 7) and $3c)] or - des_skb[2,((c shr 13) and $0f) or ((c shr 14) and $30)] or - des_skb[3,((c shr 20) and $01) or ((c shr 21) and $06) or ((c shr 22) and $38)]; - t:= des_skb[4,d and $3f] or - des_skb[5,((d shr 7) and $03) or ((d shr 8) and $3c)] or - des_skb[6, (d shr 15) and $3f ] or - des_skb[7,((d shr 21) and $0f) or ((d shr 22) and $30)]; - t2:= ((t shl 16) or (s and $ffff)); - KeyData[(i shl 1)]:= ((t2 shl 2) or (t2 shr 30)); - t2:= ((s shr 16) or (t and integer($ffff0000))); - KeyData[(i shl 1)+1]:= ((t2 shl 6) or (t2 shr 26)); - end; -end; - -function TSynaCustomDes.EncryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; -var - l, r, t, u: integer; - i: longint; -begin - r := Swapbytes(DecodeLongint(Indata, 1)); - l := swapbytes(DecodeLongint(Indata, 5)); - t:= ((l shr 4) xor r) and $0f0f0f0f; - r:= r xor t; - l:= l xor (t shl 4); - t:= ((r shr 16) xor l) and $0000ffff; - l:= l xor t; - r:= r xor (t shl 16); - t:= ((l shr 2) xor r) and $33333333; - r:= r xor t; - l:= l xor (t shl 2); - t:= ((r shr 8) xor l) and $00ff00ff; - l:= l xor t; - r:= r xor (t shl 8); - t:= ((l shr 1) xor r) and $55555555; - r:= r xor t; - l:= l xor (t shl 1); - r:= (r shr 29) or (r shl 3); - l:= (l shr 29) or (l shl 3); - i:= 0; - while i< 32 do - begin - u:= r xor KeyData[i ]; - t:= r xor KeyData[i+1]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i+2]; - t:= l xor KeyData[i+3]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= r xor KeyData[i+4]; - t:= r xor KeyData[i+5]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i+6]; - t:= l xor KeyData[i+7]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - Inc(i,8); - end; - r:= (r shr 3) or (r shl 29); - l:= (l shr 3) or (l shl 29); - t:= ((r shr 1) xor l) and $55555555; - l:= l xor t; - r:= r xor (t shl 1); - t:= ((l shr 8) xor r) and $00ff00ff; - r:= r xor t; - l:= l xor (t shl 8); - t:= ((r shr 2) xor l) and $33333333; - l:= l xor t; - r:= r xor (t shl 2); - t:= ((l shr 16) xor r) and $0000ffff; - r:= r xor t; - l:= l xor (t shl 16); - t:= ((r shr 4) xor l) and $0f0f0f0f; - l:= l xor t; - r:= r xor (t shl 4); - Result := CodeLongInt(Swapbytes(l)) + CodeLongInt(Swapbytes(r)); -end; - -function TSynaCustomDes.DecryptBlock(const InData: AnsiString; var KeyData: TDesKeyData): AnsiString; -var - l, r, t, u: integer; - i: longint; -begin - r := Swapbytes(DecodeLongint(Indata, 1)); - l := Swapbytes(DecodeLongint(Indata, 5)); - t:= ((l shr 4) xor r) and $0f0f0f0f; - r:= r xor t; - l:= l xor (t shl 4); - t:= ((r shr 16) xor l) and $0000ffff; - l:= l xor t; - r:= r xor (t shl 16); - t:= ((l shr 2) xor r) and $33333333; - r:= r xor t; - l:= l xor (t shl 2); - t:= ((r shr 8) xor l) and $00ff00ff; - l:= l xor t; - r:= r xor (t shl 8); - t:= ((l shr 1) xor r) and $55555555; - r:= r xor t; - l:= l xor (t shl 1); - r:= (r shr 29) or (r shl 3); - l:= (l shr 29) or (l shl 3); - i:= 30; - while i> 0 do - begin - u:= r xor KeyData[i ]; - t:= r xor KeyData[i+1]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i-2]; - t:= l xor KeyData[i-1]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= r xor KeyData[i-4]; - t:= r xor KeyData[i-3]; - t:= (t shr 4) or (t shl 28); - l:= l xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - u:= l xor KeyData[i-6]; - t:= l xor KeyData[i-5]; - t:= (t shr 4) or (t shl 28); - r:= r xor des_SPtrans[0,(u shr 2) and $3f] xor - des_SPtrans[2,(u shr 10) and $3f] xor - des_SPtrans[4,(u shr 18) and $3f] xor - des_SPtrans[6,(u shr 26) and $3f] xor - des_SPtrans[1,(t shr 2) and $3f] xor - des_SPtrans[3,(t shr 10) and $3f] xor - des_SPtrans[5,(t shr 18) and $3f] xor - des_SPtrans[7,(t shr 26) and $3f]; - Dec(i,8); - end; - r:= (r shr 3) or (r shl 29); - l:= (l shr 3) or (l shl 29); - t:= ((r shr 1) xor l) and $55555555; - l:= l xor t; - r:= r xor (t shl 1); - t:= ((l shr 8) xor r) and $00ff00ff; - r:= r xor t; - l:= l xor (t shl 8); - t:= ((r shr 2) xor l) and $33333333; - l:= l xor t; - r:= r xor (t shl 2); - t:= ((l shr 16) xor r) and $0000ffff; - r:= r xor t; - l:= l xor (t shl 16); - t:= ((r shr 4) xor l) and $0f0f0f0f; - l:= l xor t; - r:= r xor (t shl 4); - Result := CodeLongInt(Swapbytes(l)) + CodeLongInt(Swapbytes(r)); -end; - -{==============================================================================} - -procedure TSynaDes.InitKey(Key: AnsiString); -begin - Key := PadString(Key, 8, #0); - DoInit(Key,KeyData); -end; - -function TSynaDes.EncryptECB(const InData: AnsiString): AnsiString; -begin - Result := EncryptBlock(InData,KeyData); -end; - -function TSynaDes.DecryptECB(const InData: AnsiString): AnsiString; -begin - Result := DecryptBlock(Indata,KeyData); -end; - -{==============================================================================} - -procedure TSyna3Des.InitKey(Key: AnsiString); -var - Size: integer; - n: integer; -begin - Size := length(Key); - key := PadString(key, 3 * 8, #0); - DoInit(Copy(key, 1, 8),KeyData[0]); - DoInit(Copy(key, 9, 8),KeyData[1]); - if Size > 16 then - DoInit(Copy(key, 17, 8),KeyData[2]) - else - for n := 0 to high(KeyData[0]) do - KeyData[2][n] := Keydata[0][n]; -end; - -function TSyna3Des.EncryptECB(const InData: AnsiString): AnsiString; -begin - Result := EncryptBlock(Indata,KeyData[0]); - Result := DecryptBlock(Result,KeyData[1]); - Result := EncryptBlock(Result,KeyData[2]); -end; - -function TSyna3Des.DecryptECB(const InData: AnsiString): AnsiString; -begin - Result := DecryptBlock(InData,KeyData[2]); - Result := EncryptBlock(Result,KeyData[1]); - Result := DecryptBlock(Result,KeyData[0]); -end; - -{==============================================================================} - -procedure InvMixColumn(a: PByteArray; BC: byte); -var - j: longword; -begin - for j:= 0 to (BC-1) do - PDWord(@(a^[j*4]))^:= PDWord(@U1[a^[j*4+0]])^ - xor PDWord(@U2[a^[j*4+1]])^ - xor PDWord(@U3[a^[j*4+2]])^ - xor PDWord(@U4[a^[j*4+3]])^; -end; - -{==============================================================================} - -function TSynaAes.GetSize: byte; -begin - Result := 16; -end; - -procedure TSynaAes.InitKey(Key: AnsiString); -var - Size: integer; - KC, ROUNDS, j, r, t, rconpointer: longword; - tk: array[0..MAXKC-1,0..3] of byte; - n: integer; -begin - FillChar(tk,Sizeof(tk),0); - //key must have at least 128 bits and max 256 bits - if length(key) < 16 then - key := PadString(key, 16, #0); - if length(key) > 32 then - delete(key, 33, maxint); - Size := length(Key); - Move(PAnsiChar(Key)^, tk, Size); - if Size<= 16 then - begin - KC:= 4; - Rounds:= 10; - end - else if Size<= 24 then - begin - KC:= 6; - Rounds:= 12; - end - else - begin - KC:= 8; - Rounds:= 14; - end; - numrounds:= rounds; - r:= 0; - t:= 0; - j:= 0; - while (j< KC) and (r< (rounds+1)) do - begin - while (j< KC) and (t< BC) do - begin - rk[r,t]:= PDWord(@tk[j])^; - Inc(j); - Inc(t); - end; - if t= BC then - begin - t:= 0; - Inc(r); - end; - end; - rconpointer:= 0; - while (r< (rounds+1)) do - begin - tk[0,0]:= tk[0,0] xor S[tk[KC-1,1]]; - tk[0,1]:= tk[0,1] xor S[tk[KC-1,2]]; - tk[0,2]:= tk[0,2] xor S[tk[KC-1,3]]; - tk[0,3]:= tk[0,3] xor S[tk[KC-1,0]]; - tk[0,0]:= tk[0,0] xor rcon[rconpointer]; - Inc(rconpointer); - if KC<> 8 then - begin - for j:= 1 to (KC-1) do - PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; - end - else - begin - for j:= 1 to ((KC div 2)-1) do - PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; - tk[KC div 2,0]:= tk[KC div 2,0] xor S[tk[KC div 2 - 1,0]]; - tk[KC div 2,1]:= tk[KC div 2,1] xor S[tk[KC div 2 - 1,1]]; - tk[KC div 2,2]:= tk[KC div 2,2] xor S[tk[KC div 2 - 1,2]]; - tk[KC div 2,3]:= tk[KC div 2,3] xor S[tk[KC div 2 - 1,3]]; - for j:= ((KC div 2) + 1) to (KC-1) do - PDWord(@tk[j])^:= PDWord(@tk[j])^ xor PDWord(@tk[j-1])^; - end; - j:= 0; - while (j< KC) and (r< (rounds+1)) do - begin - while (j< KC) and (t< BC) do - begin - rk[r,t]:= PDWord(@tk[j])^; - Inc(j); - Inc(t); - end; - if t= BC then - begin - Inc(r); - t:= 0; - end; - end; - end; - Move(rk,drk,Sizeof(rk)); - for r:= 1 to (numrounds-1) do - InvMixColumn(@drk[r],BC); -end; - -function TSynaAes.EncryptECB(const InData: AnsiString): AnsiString; -var - r: longword; - tempb: array[0..MAXBC-1,0..3] of byte; - a: array[0..MAXBC,0..3] of byte; - p: pointer; -begin - p := @a[0,0]; - move(pointer(InData)^, p^, 16); - for r:= 0 to (numrounds-2) do - begin - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor rk[r,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor rk[r,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor rk[r,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor rk[r,3]; - PDWord(@a[0])^:= PDWord(@T1[tempb[0,0]])^ xor - PDWord(@T2[tempb[1,1]])^ xor - PDWord(@T3[tempb[2,2]])^ xor - PDWord(@T4[tempb[3,3]])^; - PDWord(@a[1])^:= PDWord(@T1[tempb[1,0]])^ xor - PDWord(@T2[tempb[2,1]])^ xor - PDWord(@T3[tempb[3,2]])^ xor - PDWord(@T4[tempb[0,3]])^; - PDWord(@a[2])^:= PDWord(@T1[tempb[2,0]])^ xor - PDWord(@T2[tempb[3,1]])^ xor - PDWord(@T3[tempb[0,2]])^ xor - PDWord(@T4[tempb[1,3]])^; - PDWord(@a[3])^:= PDWord(@T1[tempb[3,0]])^ xor - PDWord(@T2[tempb[0,1]])^ xor - PDWord(@T3[tempb[1,2]])^ xor - PDWord(@T4[tempb[2,3]])^; - end; - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor rk[numrounds-1,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor rk[numrounds-1,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor rk[numrounds-1,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor rk[numrounds-1,3]; - a[0,0]:= T1[tempb[0,0],1]; - a[0,1]:= T1[tempb[1,1],1]; - a[0,2]:= T1[tempb[2,2],1]; - a[0,3]:= T1[tempb[3,3],1]; - a[1,0]:= T1[tempb[1,0],1]; - a[1,1]:= T1[tempb[2,1],1]; - a[1,2]:= T1[tempb[3,2],1]; - a[1,3]:= T1[tempb[0,3],1]; - a[2,0]:= T1[tempb[2,0],1]; - a[2,1]:= T1[tempb[3,1],1]; - a[2,2]:= T1[tempb[0,2],1]; - a[2,3]:= T1[tempb[1,3],1]; - a[3,0]:= T1[tempb[3,0],1]; - a[3,1]:= T1[tempb[0,1],1]; - a[3,2]:= T1[tempb[1,2],1]; - a[3,3]:= T1[tempb[2,3],1]; - PDWord(@a[0])^:= PDWord(@a[0])^ xor rk[numrounds,0]; - PDWord(@a[1])^:= PDWord(@a[1])^ xor rk[numrounds,1]; - PDWord(@a[2])^:= PDWord(@a[2])^ xor rk[numrounds,2]; - PDWord(@a[3])^:= PDWord(@a[3])^ xor rk[numrounds,3]; - - Result := StringOfChar(#0, 16); - move(p^, pointer(Result)^, 16); -end; - -function TSynaAes.DecryptECB(const InData: AnsiString): AnsiString; -var - r: longword; - tempb: array[0..MAXBC-1,0..3] of byte; - a: array[0..MAXBC,0..3] of byte; - p: pointer; -begin - p := @a[0,0]; - move(pointer(InData)^, p^, 16); - for r:= NumRounds downto 2 do - begin - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor drk[r,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor drk[r,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor drk[r,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor drk[r,3]; - PDWord(@a[0])^:= PDWord(@T5[tempb[0,0]])^ xor - PDWord(@T6[tempb[3,1]])^ xor - PDWord(@T7[tempb[2,2]])^ xor - PDWord(@T8[tempb[1,3]])^; - PDWord(@a[1])^:= PDWord(@T5[tempb[1,0]])^ xor - PDWord(@T6[tempb[0,1]])^ xor - PDWord(@T7[tempb[3,2]])^ xor - PDWord(@T8[tempb[2,3]])^; - PDWord(@a[2])^:= PDWord(@T5[tempb[2,0]])^ xor - PDWord(@T6[tempb[1,1]])^ xor - PDWord(@T7[tempb[0,2]])^ xor - PDWord(@T8[tempb[3,3]])^; - PDWord(@a[3])^:= PDWord(@T5[tempb[3,0]])^ xor - PDWord(@T6[tempb[2,1]])^ xor - PDWord(@T7[tempb[1,2]])^ xor - PDWord(@T8[tempb[0,3]])^; - end; - PDWord(@tempb[0])^:= PDWord(@a[0])^ xor drk[1,0]; - PDWord(@tempb[1])^:= PDWord(@a[1])^ xor drk[1,1]; - PDWord(@tempb[2])^:= PDWord(@a[2])^ xor drk[1,2]; - PDWord(@tempb[3])^:= PDWord(@a[3])^ xor drk[1,3]; - a[0,0]:= S5[tempb[0,0]]; - a[0,1]:= S5[tempb[3,1]]; - a[0,2]:= S5[tempb[2,2]]; - a[0,3]:= S5[tempb[1,3]]; - a[1,0]:= S5[tempb[1,0]]; - a[1,1]:= S5[tempb[0,1]]; - a[1,2]:= S5[tempb[3,2]]; - a[1,3]:= S5[tempb[2,3]]; - a[2,0]:= S5[tempb[2,0]]; - a[2,1]:= S5[tempb[1,1]]; - a[2,2]:= S5[tempb[0,2]]; - a[2,3]:= S5[tempb[3,3]]; - a[3,0]:= S5[tempb[3,0]]; - a[3,1]:= S5[tempb[2,1]]; - a[3,2]:= S5[tempb[1,2]]; - a[3,3]:= S5[tempb[0,3]]; - PDWord(@a[0])^:= PDWord(@a[0])^ xor drk[0,0]; - PDWord(@a[1])^:= PDWord(@a[1])^ xor drk[0,1]; - PDWord(@a[2])^:= PDWord(@a[2])^ xor drk[0,2]; - PDWord(@a[3])^:= PDWord(@a[3])^ xor drk[0,3]; - Result := StringOfChar(#0, 16); - move(p^, pointer(Result)^, 16); -end; - -{==============================================================================} - -function TestDes: boolean; -var - des: TSynaDes; - s, t: string; -const - key = '01234567'; - data1= '01234567'; - data2= '0123456789abcdefghij'; -begin - //ECB - des := TSynaDes.Create(key); - try - s := des.EncryptECB(data1); - t := strtohex(s); - result := t = 'c50ad028c6da9800'; - s := des.DecryptECB(s); - result := result and (data1 = s); - finally - des.free; - end; - //CBC - des := TSynaDes.Create(key); - try - s := des.EncryptCBC(data2); - t := strtohex(s); - result := result and (t = 'eec50f6353115ad6dee90a22ed1b6a88a0926e35'); - des.Reset; - s := des.DecryptCBC(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-8bit - des := TSynaDes.Create(key); - try - s := des.EncryptCFB8bit(data2); - t := strtohex(s); - result := result and (t = 'eb6aa12c2f0ff634b4dfb6da6cb2af8f9c5c1452'); - des.Reset; - s := des.DecryptCFB8bit(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-block - des := TSynaDes.Create(key); - try - s := des.EncryptCFBblock(data2); - t := strtohex(s); - result := result and (t = 'ebdbbaa7f9286cdec28605e07f9b7f3be1053257'); - des.Reset; - s := des.DecryptCFBblock(s); - result := result and (data2 = s); - finally - des.free; - end; - //OFB - des := TSynaDes.Create(key); - try - s := des.EncryptOFB(data2); - t := strtohex(s); - result := result and (t = 'ebdbbaa7f9286cdee0b8b3798c4c34baac87dbdc'); - des.Reset; - s := des.DecryptOFB(s); - result := result and (data2 = s); - finally - des.free; - end; - //CTR - des := TSynaDes.Create(key); - try - s := des.EncryptCTR(data2); - t := strtohex(s); - result := result and (t = 'ebdbbaa7f9286cde0dd20b45f3afd9aa1b91b87e'); - des.Reset; - s := des.DecryptCTR(s); - result := result and (data2 = s); - finally - des.free; - end; -end; - -function Test3Des: boolean; -var - des: TSyna3Des; - s, t: string; -const - key = '0123456789abcdefghijklmn'; - data1= '01234567'; - data2= '0123456789abcdefghij'; -begin - //ECB - des := TSyna3Des.Create(key); - try - s := des.EncryptECB(data1); - t := strtohex(s); - result := t = 'e0dee91008dc460c'; - s := des.DecryptECB(s); - result := result and (data1 = s); - finally - des.free; - end; - //CBC - des := TSyna3Des.Create(key); - try - s := des.EncryptCBC(data2); - t := strtohex(s); - result := result and (t = 'ee844a2a4f49c01b91a1599b8eba29128c1ad87a'); - des.Reset; - s := des.DecryptCBC(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-8bit - des := TSyna3Des.Create(key); - try - s := des.EncryptCFB8bit(data2); - t := strtohex(s); - result := result and (t = '935bbf5210c32cfa1faf61f91e8dc02dfa0ff1e8'); - des.Reset; - s := des.DecryptCFB8bit(s); - result := result and (data2 = s); - finally - des.free; - end; - //CFB-block - des := TSyna3Des.Create(key); - try - s := des.EncryptCFBblock(data2); - t := strtohex(s); - result := result and (t = '93754e3d54828fbf4bd81f1739419e8d2cfe1671'); - des.Reset; - s := des.DecryptCFBblock(s); - result := result and (data2 = s); - finally - des.free; - end; - //OFB - des := TSyna3Des.Create(key); - try - s := des.EncryptOFB(data2); - t := strtohex(s); - result := result and (t = '93754e3d54828fbf04ef0a5efc926ebdf2d95f20'); - des.Reset; - s := des.DecryptOFB(s); - result := result and (data2 = s); - finally - des.free; - end; - //CTR - des := TSyna3Des.Create(key); - try - s := des.EncryptCTR(data2); - t := strtohex(s); - result := result and (t = '93754e3d54828fbf1c51a121d2c93f989e70b3ad'); - des.Reset; - s := des.DecryptCTR(s); - result := result and (data2 = s); - finally - des.free; - end; -end; - -function TestAes: boolean; -var - aes: TSynaAes; - s, t: string; -const - key1 = #$00#$01#$02#$03#$05#$06#$07#$08#$0A#$0B#$0C#$0D#$0F#$10#$11#$12; - data1= #$50#$68#$12#$A4#$5F#$08#$C8#$89#$B9#$7F#$59#$80#$03#$8B#$83#$59; - key2 = #$A0#$A1#$A2#$A3#$A5#$A6#$A7#$A8#$AA#$AB#$AC#$AD#$AF#$B0#$B1#$B2#$B4#$B5#$B6#$B7#$B9#$BA#$BB#$BC; - data2= #$4F#$1C#$76#$9D#$1E#$5B#$05#$52#$C7#$EC#$A8#$4D#$EA#$26#$A5#$49; - key3 = #$00#$01#$02#$03#$05#$06#$07#$08#$0A#$0B#$0C#$0D#$0F#$10#$11#$12#$14#$15#$16#$17#$19#$1A#$1B#$1C#$1E#$1F#$20#$21#$23#$24#$25#$26; - data3= #$5E#$25#$CA#$78#$F0#$DE#$55#$80#$25#$24#$D3#$8D#$A3#$FE#$44#$56; -begin - //ECB - aes := TSynaAes.Create(key1); - try - t := aes.EncryptECB(data1); - result := t = #$D8#$F5#$32#$53#$82#$89#$EF#$7D#$06#$B5#$06#$A4#$FD#$5B#$E9#$C9; - s := aes.DecryptECB(t); - result := result and (data1 = s); - finally - aes.free; - end; - aes := TSynaAes.Create(key2); - try - t := aes.EncryptECB(data2); - result := result and (t = #$F3#$84#$72#$10#$D5#$39#$1E#$23#$60#$60#$8E#$5A#$CB#$56#$05#$81); - s := aes.DecryptECB(t); - result := result and (data2 = s); - finally - aes.free; - end; - aes := TSynaAes.Create(key3); - try - t := aes.EncryptECB(data3); - result := result and (t = #$E8#$B7#$2B#$4E#$8B#$E2#$43#$43#$8C#$9F#$FF#$1F#$0E#$20#$58#$72); - s := aes.DecryptECB(t); - result := result and (data3 = s); - finally - aes.free; - end; -end; - -{==============================================================================} - -end. diff --git a/3rd/synapse/source/synadbg.pas b/3rd/synapse/source/synadbg.pas deleted file mode 100644 index c587c3adf..000000000 --- a/3rd/synapse/source/synadbg.pas +++ /dev/null @@ -1,156 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.002 | -|==============================================================================| -| Content: Socket debug tools | -|==============================================================================| -| Copyright (c)2008-2011, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2008-2011. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Socket debug tools) - -Routines for help with debugging of events on the Sockets. -} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synadbg; - -interface - -uses - blcksock, synsock, synautil, classes, sysutils, synafpc; - -type - TSynaDebug = class(TObject) - class procedure HookStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); - class procedure HookMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer); - end; - -procedure AppendToLog(const value: Ansistring); - -var - LogFile: string; - -implementation - -procedure AppendToLog(const value: Ansistring); -var - st: TFileStream; - s: string; - h, m, ss, ms: word; - dt: Tdatetime; -begin - if fileexists(LogFile) then - st := TFileStream.Create(LogFile, fmOpenReadWrite or fmShareDenyWrite) - else - st := TFileStream.Create(LogFile, fmCreate or fmShareDenyWrite); - try - st.Position := st.Size; - dt := now; - decodetime(dt, h, m, ss, ms); - s := formatdatetime('yyyymmdd-hhnnss', dt) + format('.%.3d', [ms]) + ' ' + value; - WriteStrToStream(st, s); - finally - st.free; - end; -end; - -class procedure TSynaDebug.HookStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); -var - s: string; -begin - case Reason of - HR_ResolvingBegin: - s := 'HR_ResolvingBegin'; - HR_ResolvingEnd: - s := 'HR_ResolvingEnd'; - HR_SocketCreate: - s := 'HR_SocketCreate'; - HR_SocketClose: - s := 'HR_SocketClose'; - HR_Bind: - s := 'HR_Bind'; - HR_Connect: - s := 'HR_Connect'; - HR_CanRead: - s := 'HR_CanRead'; - HR_CanWrite: - s := 'HR_CanWrite'; - HR_Listen: - s := 'HR_Listen'; - HR_Accept: - s := 'HR_Accept'; - HR_ReadCount: - s := 'HR_ReadCount'; - HR_WriteCount: - s := 'HR_WriteCount'; - HR_Wait: - s := 'HR_Wait'; - HR_Error: - s := 'HR_Error'; - else - s := '-unknown-'; - end; - s := inttohex(PtrInt(Sender), 8) + s + ': ' + value + CRLF; - AppendToLog(s); -end; - -class procedure TSynaDebug.HookMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer); -var - s, d: Ansistring; -begin - setlength(s, len); - move(Buffer^, pointer(s)^, len); - if writing then - d := '-> ' - else - d := '<- '; - s :=inttohex(PtrInt(Sender), 8) + d + s + CRLF; - AppendToLog(s); -end; - -initialization -begin - Logfile := changefileext(paramstr(0), '.slog'); -end; - -end. diff --git a/3rd/synapse/source/synafpc.pas b/3rd/synapse/source/synafpc.pas deleted file mode 100644 index b63335d6b..000000000 --- a/3rd/synapse/source/synafpc.pas +++ /dev/null @@ -1,148 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.003.001 | -|==============================================================================| -| Content: Utils for FreePascal compatibility | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2003-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -unit synafpc; - -interface - -uses -{$IFDEF FPC} - dynlibs, sysutils; -{$ELSE} - {$IFDEF MSWINDOWS} - Windows; - {$ELSE} - SysUtils; - {$ENDIF} -{$ENDIF} - -{$IFDEF FPC} -type - TLibHandle = dynlibs.TLibHandle; - -function LoadLibrary(ModuleName: PChar): TLibHandle; -function FreeLibrary(Module: TLibHandle): LongBool; -function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; -function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; -{$ELSE} //not FPC -type - {$IFDEF CIL} - TLibHandle = Integer; - PtrInt = Integer; - {$ELSE} - TLibHandle = HModule; - {$IFDEF WIN64} - PtrInt = NativeInt; - {$ELSE} - PtrInt = Integer; - {$ENDIF} - {$ENDIF} - {$IFDEF VER100} - LongWord = DWord; - {$ENDIF} -{$ENDIF} - -procedure Sleep(milliseconds: Cardinal); - - -implementation - -{==============================================================================} -{$IFDEF FPC} -function LoadLibrary(ModuleName: PChar): TLibHandle; -begin - Result := dynlibs.LoadLibrary(Modulename); -end; - -function FreeLibrary(Module: TLibHandle): LongBool; -begin - Result := dynlibs.UnloadLibrary(Module); -end; - -function GetProcAddress(Module: TLibHandle; Proc: PChar): Pointer; -begin -{$IFDEF OS2GCC} - Result := dynlibs.GetProcedureAddress(Module, '_' + Proc); -{$ELSE OS2GCC} - Result := dynlibs.GetProcedureAddress(Module, Proc); -{$ENDIF OS2GCC} -end; - -function GetModuleFileName(Module: TLibHandle; Buffer: PChar; BufLen: Integer): Integer; -begin - Result := 0; -end; - -{$ELSE} -{$ENDIF} - -procedure Sleep(milliseconds: Cardinal); -begin -{$IFDEF MSWINDOWS} - {$IFDEF FPC} - sysutils.sleep(milliseconds); - {$ELSE} - windows.sleep(milliseconds); - {$ENDIF} -{$ELSE} - sysutils.sleep(milliseconds); -{$ENDIF} - -end; - -end. diff --git a/3rd/synapse/source/synaicnv.pas b/3rd/synapse/source/synaicnv.pas deleted file mode 100644 index cbe0bfcc0..000000000 --- a/3rd/synapse/source/synaicnv.pas +++ /dev/null @@ -1,368 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.001.002 | -|==============================================================================| -| Content: ICONV support for Win32, OS/2, Linux and .NET | -|==============================================================================| -| Copyright (c)2004-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2004-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{:@abstract(LibIconv support) - -This unit is Pascal interface to LibIconv library for charset translations. -LibIconv is loaded dynamicly on-demand. If this library is not found in system, -requested LibIconv function just return errorcode. -} -unit synaicnv; - -interface - -uses -{$IFDEF CIL} - System.Runtime.InteropServices, - System.Text, -{$ENDIF} - synafpc, -{$IFNDEF MSWINDOWS} - {$IFNDEF FPC} - Libc, - {$ENDIF} - SysUtils; -{$ELSE} - Windows; -{$ENDIF} - - -const - {$IFNDEF MSWINDOWS} - {$IFDEF OS2} - DLLIconvName = 'iconv.dll'; - {$ELSE OS2} - DLLIconvName = 'libiconv.so'; - {$ENDIF OS2} - {$ELSE} - DLLIconvName = 'iconv.dll'; - {$ENDIF} - -type - size_t = Cardinal; -{$IFDEF CIL} - iconv_t = IntPtr; -{$ELSE} - iconv_t = Pointer; -{$ENDIF} - argptr = iconv_t; - -var - iconvLibHandle: TLibHandle = 0; - -function SynaIconvOpen(const tocode, fromcode: Ansistring): iconv_t; -function SynaIconvOpenTranslit(const tocode, fromcode: Ansistring): iconv_t; -function SynaIconvOpenIgnore(const tocode, fromcode: Ansistring): iconv_t; -function SynaIconv(cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer; -function SynaIconvClose(var cd: iconv_t): integer; -function SynaIconvCtl(cd: iconv_t; request: integer; argument: argptr): integer; - -function IsIconvloaded: Boolean; -function InitIconvInterface: Boolean; -function DestroyIconvInterface: Boolean; - -const - ICONV_TRIVIALP = 0; // int *argument - ICONV_GET_TRANSLITERATE = 1; // int *argument - ICONV_SET_TRANSLITERATE = 2; // const int *argument - ICONV_GET_DISCARD_ILSEQ = 3; // int *argument - ICONV_SET_DISCARD_ILSEQ = 4; // const int *argument - - -implementation - -uses SyncObjs; - -{$IFDEF CIL} - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconv_open')] - function _iconv_open(tocode: string; fromcode: string): iconv_t; external; - - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconv')] - function _iconv(cd: iconv_t; var inbuf: IntPtr; var inbytesleft: size_t; - var outbuf: IntPtr; var outbytesleft: size_t): size_t; external; - - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconv_close')] - function _iconv_close(cd: iconv_t): integer; external; - - [DllImport(DLLIconvName, CharSet = CharSet.Ansi, - SetLastError = False, CallingConvention= CallingConvention.cdecl, - EntryPoint = 'libiconvctl')] - function _iconvctl(cd: iconv_t; request: integer; argument: argptr): integer; external; - -{$ELSE} -type - Ticonv_open = function(tocode: pAnsichar; fromcode: pAnsichar): iconv_t; cdecl; - Ticonv = function(cd: iconv_t; var inbuf: pointer; var inbytesleft: size_t; - var outbuf: pointer; var outbytesleft: size_t): size_t; cdecl; - Ticonv_close = function(cd: iconv_t): integer; cdecl; - Ticonvctl = function(cd: iconv_t; request: integer; argument: argptr): integer; cdecl; -var - _iconv_open: Ticonv_open = nil; - _iconv: Ticonv = nil; - _iconv_close: Ticonv_close = nil; - _iconvctl: Ticonvctl = nil; -{$ENDIF} - - -var - IconvCS: TCriticalSection; - Iconvloaded: boolean = false; - -function SynaIconvOpen (const tocode, fromcode: Ansistring): iconv_t; -begin -{$IFDEF CIL} - try - Result := _iconv_open(tocode, fromcode); - except - on Exception do - Result := iconv_t(-1); - end; -{$ELSE} - if InitIconvInterface and Assigned(_iconv_open) then - Result := _iconv_open(PAnsiChar(tocode), PAnsiChar(fromcode)) - else - Result := iconv_t(-1); -{$ENDIF} -end; - -function SynaIconvOpenTranslit (const tocode, fromcode: Ansistring): iconv_t; -begin - Result := SynaIconvOpen(tocode + '//IGNORE//TRANSLIT', fromcode); -end; - -function SynaIconvOpenIgnore (const tocode, fromcode: Ansistring): iconv_t; -begin - Result := SynaIconvOpen(tocode + '//IGNORE', fromcode); -end; - -function SynaIconv (cd: iconv_t; inbuf: AnsiString; var outbuf: AnsiString): integer; -var -{$IFDEF CIL} - ib, ob: IntPtr; - ibsave, obsave: IntPtr; - l: integer; -{$ELSE} - ib, ob: Pointer; -{$ENDIF} - ix, ox: size_t; -begin -{$IFDEF CIL} - l := Length(inbuf) * 4; - ibsave := IntPtr.Zero; - obsave := IntPtr.Zero; - try - ibsave := Marshal.StringToHGlobalAnsi(inbuf); - obsave := Marshal.AllocHGlobal(l); - ib := ibsave; - ob := obsave; - ix := Length(inbuf); - ox := l; - _iconv(cd, ib, ix, ob, ox); - Outbuf := Marshal.PtrToStringAnsi(obsave, l); - setlength(Outbuf, l - ox); - Result := Length(inbuf) - ix; - finally - Marshal.FreeCoTaskMem(ibsave); - Marshal.FreeHGlobal(obsave); - end; -{$ELSE} - if InitIconvInterface and Assigned(_iconv) then - begin - setlength(Outbuf, Length(inbuf) * 4); - ib := Pointer(inbuf); - ob := Pointer(Outbuf); - ix := Length(inbuf); - ox := Length(Outbuf); - _iconv(cd, ib, ix, ob, ox); - setlength(Outbuf, cardinal(Length(Outbuf)) - ox); - Result := Cardinal(Length(inbuf)) - ix; - end - else - begin - Outbuf := ''; - Result := 0; - end; -{$ENDIF} -end; - -function SynaIconvClose(var cd: iconv_t): integer; -begin - if cd = iconv_t(-1) then - begin - Result := 0; - Exit; - end; -{$IFDEF CIL} - try; - Result := _iconv_close(cd) - except - on Exception do - Result := -1; - end; - cd := iconv_t(-1); -{$ELSE} - if InitIconvInterface and Assigned(_iconv_close) then - Result := _iconv_close(cd) - else - Result := -1; - cd := iconv_t(-1); -{$ENDIF} -end; - -function SynaIconvCtl (cd: iconv_t; request: integer; argument: argptr): integer; -begin -{$IFDEF CIL} - Result := _iconvctl(cd, request, argument) -{$ELSE} - if InitIconvInterface and Assigned(_iconvctl) then - Result := _iconvctl(cd, request, argument) - else - Result := 0; -{$ENDIF} -end; - -function InitIconvInterface: Boolean; -begin - IconvCS.Enter; - try - if not IsIconvloaded then - begin -{$IFDEF CIL} - IconvLibHandle := 1; -{$ELSE} - IconvLibHandle := LoadLibrary(PChar(DLLIconvName)); -{$ENDIF} - if (IconvLibHandle <> 0) then - begin -{$IFNDEF CIL} - _iconv_open := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_open'))); - _iconv := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv'))); - _iconv_close := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconv_close'))); - _iconvctl := GetProcAddress(IconvLibHandle, PAnsiChar(AnsiString('libiconvctl'))); -{$ENDIF} - Result := True; - Iconvloaded := True; - end - else - begin - //load failed! - if IconvLibHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(IconvLibHandle); -{$ENDIF} - IconvLibHandle := 0; - end; - Result := False; - end; - end - else - //loaded before... - Result := true; - finally - IconvCS.Leave; - end; -end; - -function DestroyIconvInterface: Boolean; -begin - IconvCS.Enter; - try - Iconvloaded := false; - if IconvLibHandle <> 0 then - begin -{$IFNDEF CIL} - FreeLibrary(IconvLibHandle); -{$ENDIF} - IconvLibHandle := 0; - end; -{$IFNDEF CIL} - _iconv_open := nil; - _iconv := nil; - _iconv_close := nil; - _iconvctl := nil; -{$ENDIF} - finally - IconvCS.Leave; - end; - Result := True; -end; - -function IsIconvloaded: Boolean; -begin - Result := IconvLoaded; -end; - - initialization -begin - IconvCS:= TCriticalSection.Create; -end; - -finalization -begin -{$IFNDEF CIL} - DestroyIconvInterface; -{$ENDIF} - IconvCS.Free; -end; - -end. diff --git a/3rd/synapse/source/synaip.pas b/3rd/synapse/source/synaip.pas deleted file mode 100644 index f13372321..000000000 --- a/3rd/synapse/source/synaip.pas +++ /dev/null @@ -1,422 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.002.001 | -|==============================================================================| -| Content: IP address support procedures and functions | -|==============================================================================| -| Copyright (c)2006-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 2006-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(IP adress support procedures and functions)} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$R-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit synaip; - -interface - -uses - SysUtils, SynaUtil; - -type -{:binary form of IPv6 adress (for string conversion routines)} - TIp6Bytes = array [0..15] of Byte; -{:binary form of IPv6 adress (for string conversion routines)} - TIp6Words = array [0..7] of Word; - -{:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!} -function IsIP(const Value: string): Boolean; - -{:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!} -function IsIP6(const Value: string): Boolean; - -{:Returns a string with the "Host" ip address converted to binary form.} -function IPToID(Host: string): Ansistring; - -{:Convert IPv6 address from their string form to binary byte array.} -function StrToIp6(value: string): TIp6Bytes; - -{:Convert IPv6 address from binary byte array to string form.} -function Ip6ToStr(value: TIp6Bytes): string; - -{:Convert IPv4 address from their string form to binary.} -function StrToIp(value: string): integer; - -{:Convert IPv4 address from binary to string form.} -function IpToStr(value: integer): string; - -{:Convert IPv4 address to reverse form.} -function ReverseIP(Value: AnsiString): AnsiString; - -{:Convert IPv6 address to reverse form.} -function ReverseIP6(Value: AnsiString): AnsiString; - -{:Expand short form of IPv6 address to long form.} -function ExpandIP6(Value: AnsiString): AnsiString; - - -implementation - -{==============================================================================} - -function IsIP(const Value: string): Boolean; -var - TempIP: string; - function ByteIsOk(const Value: string): Boolean; - var - x, n: integer; - begin - x := StrToIntDef(Value, -1); - Result := (x >= 0) and (x < 256); - // X may be in correct range, but value still may not be correct value! - // i.e. "$80" - if Result then - for n := 1 to length(Value) do - if not (AnsiChar(Value[n]) in ['0'..'9']) then - begin - Result := False; - Break; - end; - end; -begin - TempIP := Value; - Result := False; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if not ByteIsOk(Fetch(TempIP, '.')) then - Exit; - if ByteIsOk(TempIP) then - Result := True; -end; - -{==============================================================================} - -function IsIP6(const Value: string): Boolean; -var - TempIP: string; - s,t: string; - x: integer; - partcount: integer; - zerocount: integer; - First: Boolean; -begin - TempIP := Value; - Result := False; - if Value = '::' then - begin - Result := True; - Exit; - end; - partcount := 0; - zerocount := 0; - First := True; - while tempIP <> '' do - begin - s := fetch(TempIP, ':'); - if not(First) and (s = '') then - Inc(zerocount); - First := False; - if zerocount > 1 then - break; - Inc(partCount); - if s = '' then - Continue; - if partCount > 8 then - break; - if tempIP = '' then - begin - t := SeparateRight(s, '%'); - s := SeparateLeft(s, '%'); - x := StrToIntDef('$' + t, -1); - if (x < 0) or (x > $ffff) then - break; - end; - x := StrToIntDef('$' + s, -1); - if (x < 0) or (x > $ffff) then - break; - if tempIP = '' then - if not((PartCount = 1) and (ZeroCount = 0)) then - Result := True; - end; -end; - -{==============================================================================} -function IPToID(Host: string): Ansistring; -var - s: string; - i, x: Integer; -begin - Result := ''; - for x := 0 to 3 do - begin - s := Fetch(Host, '.'); - i := StrToIntDef(s, 0); - Result := Result + AnsiChar(i); - end; -end; - -{==============================================================================} - -function StrToIp(value: string): integer; -var - s: string; - i, x: Integer; -begin - Result := 0; - for x := 0 to 3 do - begin - s := Fetch(value, '.'); - i := StrToIntDef(s, 0); - Result := (256 * Result) + i; - end; -end; - -{==============================================================================} - -function IpToStr(value: integer): string; -var - x1, x2: word; - y1, y2: byte; -begin - Result := ''; - x1 := value shr 16; - x2 := value and $FFFF; - y1 := x1 div $100; - y2 := x1 mod $100; - Result := inttostr(y1) + '.' + inttostr(y2) + '.'; - y1 := x2 div $100; - y2 := x2 mod $100; - Result := Result + inttostr(y1) + '.' + inttostr(y2); -end; - -{==============================================================================} - -function ExpandIP6(Value: AnsiString): AnsiString; -var - n: integer; - s: ansistring; - x: integer; -begin - Result := ''; - if value = '' then - exit; - x := countofchar(value, ':'); - if x > 7 then - exit; - if value[1] = ':' then - value := '0' + value; - if value[length(value)] = ':' then - value := value + '0'; - x := 8 - x; - s := ''; - for n := 1 to x do - s := s + ':0'; - s := s + ':'; - Result := replacestring(value, '::', s); -end; -{==============================================================================} - -function StrToIp6(Value: string): TIp6Bytes; -var - IPv6: TIp6Words; - Index: Integer; - n: integer; - b1, b2: byte; - s: string; - x: integer; -begin - for n := 0 to 15 do - Result[n] := 0; - for n := 0 to 7 do - Ipv6[n] := 0; - Index := 0; - Value := ExpandIP6(value); - if value = '' then - exit; - while Value <> '' do - begin - if Index > 7 then - Exit; - s := fetch(value, ':'); - if s = '@' then - break; - if s = '' then - begin - IPv6[Index] := 0; - end - else - begin - x := StrToIntDef('$' + s, -1); - if (x > 65535) or (x < 0) then - Exit; - IPv6[Index] := x; - end; - Inc(Index); - end; - for n := 0 to 7 do - begin - b1 := ipv6[n] div 256; - b2 := ipv6[n] mod 256; - Result[n * 2] := b1; - Result[(n * 2) + 1] := b2; - end; -end; - -{==============================================================================} -//based on routine by the Free Pascal development team -function Ip6ToStr(value: TIp6Bytes): string; -var - i, x: byte; - zr1,zr2: set of byte; - zc1,zc2: byte; - have_skipped: boolean; - ip6w: TIp6words; -begin - zr1 := []; - zr2 := []; - zc1 := 0; - zc2 := 0; - for i := 0 to 7 do - begin - x := i * 2; - ip6w[i] := value[x] * 256 + value[x + 1]; - if ip6w[i] = 0 then - begin - include(zr2, i); - inc(zc2); - end - else - begin - if zc1 < zc2 then - begin - zc1 := zc2; - zr1 := zr2; - zc2 := 0; - zr2 := []; - end; - end; - end; - if zc1 < zc2 then - begin - zr1 := zr2; - end; - SetLength(Result, 8*5-1); - SetLength(Result, 0); - have_skipped := false; - for i := 0 to 7 do - begin - if not(i in zr1) then - begin - if have_skipped then - begin - if Result = '' then - Result := '::' - else - Result := Result + ':'; - have_skipped := false; - end; - Result := Result + IntToHex(Ip6w[i], 1) + ':'; - end - else - begin - have_skipped := true; - end; - end; - if have_skipped then - if Result = '' then - Result := '::0' - else - Result := Result + ':'; - - if Result = '' then - Result := '::0'; - if not (7 in zr1) then - SetLength(Result, Length(Result)-1); - Result := LowerCase(result); -end; - -{==============================================================================} -function ReverseIP(Value: AnsiString): AnsiString; -var - x: Integer; -begin - Result := ''; - repeat - x := LastDelimiter('.', Value); - Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x); - Delete(Value, x, Length(Value) - x + 1); - until x < 1; - if Length(Result) > 0 then - if Result[1] = '.' then - Delete(Result, 1, 1); -end; - -{==============================================================================} -function ReverseIP6(Value: AnsiString): AnsiString; -var - ip6: TIp6bytes; - n: integer; - x, y: integer; -begin - ip6 := StrToIP6(Value); - x := ip6[15] div 16; - y := ip6[15] mod 16; - Result := IntToHex(y, 1) + '.' + IntToHex(x, 1); - for n := 14 downto 0 do - begin - x := ip6[n] div 16; - y := ip6[n] mod 16; - Result := Result + '.' + IntToHex(y, 1) + '.' + IntToHex(x, 1); - end; -end; - -{==============================================================================} -end. diff --git a/3rd/synapse/source/synamisc.pas b/3rd/synapse/source/synamisc.pas deleted file mode 100644 index bf3e5d29a..000000000 --- a/3rd/synapse/source/synamisc.pas +++ /dev/null @@ -1,408 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.003.001 | -|==============================================================================| -| Content: misc. procedures and functions | -|==============================================================================| -| Copyright (c)1999-2014, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 2002-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Miscellaneous network based utilities)} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$Q-} -{$H+} - -//Kylix does not known UNIX define -{$IFDEF LINUX} - {$IFNDEF UNIX} - {$DEFINE UNIX} - {$ENDIF} -{$ENDIF} - -{$TYPEDADDRESS OFF} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit synamisc; - -interface - -{$IFDEF VER125} - {$DEFINE BCB} -{$ENDIF} -{$IFDEF BCB} - {$ObjExportAll On} - {$HPPEMIT '#pragma comment( lib , "wininet.lib" )'} -{$ENDIF} - -uses - synautil, blcksock, SysUtils, Classes -{$IFDEF UNIX} - {$IFNDEF FPC} - , Libc - {$ENDIF} -{$ELSE} - , Windows -{$ENDIF} -; - -Type - {:@abstract(This record contains information about proxy settings.)} - TProxySetting = record - Host: string; - Port: string; - Bypass: string; - end; - -{:With this function you can turn on a computer on the network, if this computer - supports Wake-on-LAN feature. You need the MAC address - (network card identifier) of the computer. You can also assign a target IP - addres. If you do not specify it, then broadcast is used to deliver magic - wake-on-LAN packet. - However broadcasts work only on your local network. When you need to wake-up a - computer on another network, you must specify any existing IP addres on same - network segment as targeting computer.} -procedure WakeOnLan(MAC, IP: string); - -{:Autodetect current DNS servers used by the system. If more than one DNS server - is defined, then the result is comma-delimited.} -function GetDNS: string; - -{:Autodetect InternetExplorer proxy setting for given protocol. This function -works only on windows!} -function GetIEProxy(protocol: string): TProxySetting; - -{:Return all known IP addresses on the local system. Addresses are divided by -comma/comma-delimited.} -function GetLocalIPs: string; - -implementation - -{==============================================================================} -procedure WakeOnLan(MAC, IP: string); -var - sock: TUDPBlockSocket; - HexMac: Ansistring; - data: Ansistring; - n: integer; - b: Byte; -begin - if MAC <> '' then - begin - MAC := ReplaceString(MAC, '-', ''); - MAC := ReplaceString(MAC, ':', ''); - if Length(MAC) < 12 then - Exit; - HexMac := ''; - for n := 0 to 5 do - begin - b := StrToIntDef('$' + MAC[n * 2 + 1] + MAC[n * 2 + 2], 0); - HexMac := HexMac + char(b); - end; - if IP = '' then - IP := cBroadcast; - sock := TUDPBlockSocket.Create; - try - sock.CreateSocket; - sock.EnableBroadcast(true); - sock.Connect(IP, '9'); - data := #$FF + #$FF + #$FF + #$FF + #$FF + #$FF; - for n := 1 to 16 do - data := data + HexMac; - sock.SendString(data); - finally - sock.Free; - end; - end; -end; - -{==============================================================================} - -{$IFNDEF UNIX} -function GetDNSbyIpHlp: string; -type - PTIP_ADDRESS_STRING = ^TIP_ADDRESS_STRING; - TIP_ADDRESS_STRING = array[0..15] of Ansichar; - PTIP_ADDR_STRING = ^TIP_ADDR_STRING; - TIP_ADDR_STRING = packed record - Next: PTIP_ADDR_STRING; - IpAddress: TIP_ADDRESS_STRING; - IpMask: TIP_ADDRESS_STRING; - Context: DWORD; - end; - PTFixedInfo = ^TFixedInfo; - TFixedInfo = packed record - HostName: array[1..128 + 4] of Ansichar; - DomainName: array[1..128 + 4] of Ansichar; - CurrentDNSServer: PTIP_ADDR_STRING; - DNSServerList: TIP_ADDR_STRING; - NodeType: UINT; - ScopeID: array[1..256 + 4] of Ansichar; - EnableRouting: UINT; - EnableProxy: UINT; - EnableDNS: UINT; - end; -const - IpHlpDLL = 'IPHLPAPI.DLL'; -var - IpHlpModule: THandle; - FixedInfo: PTFixedInfo; - InfoSize: Longint; - PDnsServer: PTIP_ADDR_STRING; - err: integer; - GetNetworkParams: function(FixedInfo: PTFixedInfo; pOutPutLen: PULONG): DWORD; stdcall; -begin - InfoSize := 0; - Result := '...'; - IpHlpModule := LoadLibrary(IpHlpDLL); - if IpHlpModule = 0 then - exit; - try - GetNetworkParams := GetProcAddress(IpHlpModule,PAnsiChar(AnsiString('GetNetworkParams'))); - if @GetNetworkParams = nil then - Exit; - err := GetNetworkParams(Nil, @InfoSize); - if err <> ERROR_BUFFER_OVERFLOW then - Exit; - Result := ''; - GetMem (FixedInfo, InfoSize); - try - err := GetNetworkParams(FixedInfo, @InfoSize); - if err <> ERROR_SUCCESS then - exit; - with FixedInfo^ do - begin - Result := DnsServerList.IpAddress; - PDnsServer := DnsServerList.Next; - while PDnsServer <> Nil do - begin - if Result <> '' then - Result := Result + ','; - Result := Result + PDnsServer^.IPAddress; - PDnsServer := PDnsServer.Next; - end; - end; - finally - FreeMem(FixedInfo); - end; - finally - FreeLibrary(IpHlpModule); - end; -end; - -function ReadReg(SubKey, Vn: PChar): string; -var - OpenKey: HKEY; - DataType, DataSize: integer; - Temp: array [0..2048] of char; -begin - Result := ''; - if RegOpenKeyEx(HKEY_LOCAL_MACHINE, SubKey, REG_OPTION_NON_VOLATILE, - KEY_READ, OpenKey) = ERROR_SUCCESS then - begin - DataType := REG_SZ; - DataSize := SizeOf(Temp); - if RegQueryValueEx(OpenKey, Vn, nil, @DataType, @Temp, @DataSize) = ERROR_SUCCESS then - SetString(Result, Temp, DataSize div SizeOf(Char) - 1); - RegCloseKey(OpenKey); - end; -end ; -{$ENDIF} - -function GetDNS: string; -{$IFDEF UNIX} -var - l: TStringList; - n: integer; -begin - Result := ''; - l := TStringList.Create; - try - l.LoadFromFile('/etc/resolv.conf'); - for n := 0 to l.Count - 1 do - if Pos('NAMESERVER', uppercase(l[n])) = 1 then - begin - if Result <> '' then - Result := Result + ','; - Result := Result + SeparateRight(l[n], ' '); - end; - finally - l.Free; - end; -end; -{$ELSE} -const - NTdyn = 'System\CurrentControlSet\Services\Tcpip\Parameters\Temporary'; - NTfix = 'System\CurrentControlSet\Services\Tcpip\Parameters'; - W9xfix = 'System\CurrentControlSet\Services\MSTCP'; -begin - Result := GetDNSbyIpHlp; - if Result = '...' then - begin - if Win32Platform = VER_PLATFORM_WIN32_NT then - begin - Result := ReadReg(NTdyn, 'NameServer'); - if result = '' then - Result := ReadReg(NTfix, 'NameServer'); - if result = '' then - Result := ReadReg(NTfix, 'DhcpNameServer'); - end - else - Result := ReadReg(W9xfix, 'NameServer'); - Result := ReplaceString(trim(Result), ' ', ','); - end; -end; -{$ENDIF} - -{==============================================================================} - -function GetIEProxy(protocol: string): TProxySetting; -{$IFDEF UNIX} -begin - Result.Host := ''; - Result.Port := ''; - Result.Bypass := ''; -end; -{$ELSE} -type - PInternetProxyInfo = ^TInternetProxyInfo; - TInternetProxyInfo = packed record - dwAccessType: DWORD; - lpszProxy: LPCSTR; - lpszProxyBypass: LPCSTR; - end; -const - INTERNET_OPTION_PROXY = 38; - INTERNET_OPEN_TYPE_PROXY = 3; - WininetDLL = 'WININET.DLL'; -var - WininetModule: THandle; - ProxyInfo: PInternetProxyInfo; - Err: Boolean; - Len: DWORD; - Proxy: string; - DefProxy: string; - ProxyList: TStringList; - n: integer; - InternetQueryOption: function (hInet: Pointer; dwOption: DWORD; - lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL; stdcall; -begin - Result.Host := ''; - Result.Port := ''; - Result.Bypass := ''; - WininetModule := LoadLibrary(WininetDLL); - if WininetModule = 0 then - exit; - try - InternetQueryOption := GetProcAddress(WininetModule,PAnsiChar(AnsiString('InternetQueryOptionA'))); - if @InternetQueryOption = nil then - Exit; - - if protocol = '' then - protocol := 'http'; - Len := 4096; - GetMem(ProxyInfo, Len); - ProxyList := TStringList.Create; - try - Err := InternetQueryOption(nil, INTERNET_OPTION_PROXY, ProxyInfo, Len); - if Err then - if ProxyInfo^.dwAccessType = INTERNET_OPEN_TYPE_PROXY then - begin - ProxyList.CommaText := ReplaceString(ProxyInfo^.lpszProxy, ' ', ','); - Proxy := ''; - DefProxy := ''; - for n := 0 to ProxyList.Count -1 do - begin - if Pos(lowercase(protocol) + '=', lowercase(ProxyList[n])) = 1 then - begin - Proxy := SeparateRight(ProxyList[n], '='); - break; - end; - if Pos('=', ProxyList[n]) < 1 then - DefProxy := ProxyList[n]; - end; - if Proxy = '' then - Proxy := DefProxy; - if Proxy <> '' then - begin - Result.Host := Trim(SeparateLeft(Proxy, ':')); - Result.Port := Trim(SeparateRight(Proxy, ':')); - end; - Result.Bypass := ReplaceString(ProxyInfo^.lpszProxyBypass, ' ', ','); - end; - finally - ProxyList.Free; - FreeMem(ProxyInfo); - end; - finally - FreeLibrary(WininetModule); - end; -end; -{$ENDIF} - -{==============================================================================} - -function GetLocalIPs: string; -var - TcpSock: TTCPBlockSocket; - ipList: TStringList; -begin - Result := ''; - ipList := TStringList.Create; - try - TcpSock := TTCPBlockSocket.create; - try - TcpSock.ResolveNameToIP(TcpSock.LocalName, ipList); - Result := ipList.CommaText; - finally - TcpSock.Free; - end; - finally - ipList.Free; - end; -end; - -{==============================================================================} - -end. diff --git a/3rd/synapse/source/synaser.pas b/3rd/synapse/source/synaser.pas deleted file mode 100644 index 160e9b059..000000000 --- a/3rd/synapse/source/synaser.pas +++ /dev/null @@ -1,2336 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 007.005.006 | -|==============================================================================| -| Content: Serial port support | -|==============================================================================| -| Copyright (c)2001-2014, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2014. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| (c)2002, Hans-Georg Joepgen (cpom Comport Ownership Manager and bugfixes) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{: @abstract(Serial port communication library) -This unit contains a class that implements serial port communication - for Windows, Linux, Unix or MacOSx. This class provides numerous methods with - same name and functionality as methods of the Ararat Synapse TCP/IP library. - -The following is a small example how establish a connection by modem (in this -case with my USB modem): -@longcode(# - ser:=TBlockSerial.Create; - try - ser.Connect('COM3'); - ser.config(460800,8,'N',0,false,true); - ser.ATCommand('AT'); - if (ser.LastError <> 0) or (not ser.ATResult) then - Exit; - ser.ATConnect('ATDT+420971200111'); - if (ser.LastError <> 0) or (not ser.ATResult) then - Exit; - // you are now connected to a modem at +420971200111 - // you can transmit or receive data now - finally - ser.free; - end; -#) -} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -//Kylix does not known UNIX define -{$IFDEF LINUX} - {$IFNDEF UNIX} - {$DEFINE UNIX} - {$ENDIF} -{$ENDIF} - -{$IFDEF FPC} - {$MODE DELPHI} - {$IFDEF MSWINDOWS} - {$ASMMODE intel} - {$ENDIF} - {define working mode w/o LIBC for fpc} - {$DEFINE NO_LIBC} -{$ENDIF} -{$Q-} -{$H+} -{$M+} - -unit synaser; - -interface - -uses -{$IFNDEF MSWINDOWS} - {$IFNDEF NO_LIBC} - Libc, - KernelIoctl, - {$ELSE} - termio, baseunix, unix, - {$ENDIF} - {$IFNDEF FPC} - Types, - {$ENDIF} -{$ELSE} - Windows, registry, - {$IFDEF FPC} - winver, - {$ENDIF} -{$ENDIF} - synafpc, - Classes, SysUtils, synautil; - -const - CR = #$0d; - LF = #$0a; - CRLF = CR + LF; - cSerialChunk = 8192; - - LockfileDirectory = '/var/lock'; {HGJ} - PortIsClosed = -1; {HGJ} - ErrAlreadyOwned = 9991; {HGJ} - ErrAlreadyInUse = 9992; {HGJ} - ErrWrongParameter = 9993; {HGJ} - ErrPortNotOpen = 9994; {HGJ} - ErrNoDeviceAnswer = 9995; {HGJ} - ErrMaxBuffer = 9996; - ErrTimeout = 9997; - ErrNotRead = 9998; - ErrFrame = 9999; - ErrOverrun = 10000; - ErrRxOver = 10001; - ErrRxParity = 10002; - ErrTxFull = 10003; - - dcb_Binary = $00000001; - dcb_ParityCheck = $00000002; - dcb_OutxCtsFlow = $00000004; - dcb_OutxDsrFlow = $00000008; - dcb_DtrControlMask = $00000030; - dcb_DtrControlDisable = $00000000; - dcb_DtrControlEnable = $00000010; - dcb_DtrControlHandshake = $00000020; - dcb_DsrSensivity = $00000040; - dcb_TXContinueOnXoff = $00000080; - dcb_OutX = $00000100; - dcb_InX = $00000200; - dcb_ErrorChar = $00000400; - dcb_NullStrip = $00000800; - dcb_RtsControlMask = $00003000; - dcb_RtsControlDisable = $00000000; - dcb_RtsControlEnable = $00001000; - dcb_RtsControlHandshake = $00002000; - dcb_RtsControlToggle = $00003000; - dcb_AbortOnError = $00004000; - dcb_Reserveds = $FFFF8000; - - {:stopbit value for 1 stopbit} - SB1 = 0; - {:stopbit value for 1.5 stopbit} - SB1andHalf = 1; - {:stopbit value for 2 stopbits} - SB2 = 2; - -{$IFNDEF MSWINDOWS} -const - INVALID_HANDLE_VALUE = THandle(-1); - CS7fix = $0000020; - -type - TDCB = record - DCBlength: DWORD; - BaudRate: DWORD; - Flags: Longint; - wReserved: Word; - XonLim: Word; - XoffLim: Word; - ByteSize: Byte; - Parity: Byte; - StopBits: Byte; - XonChar: CHAR; - XoffChar: CHAR; - ErrorChar: CHAR; - EofChar: CHAR; - EvtChar: CHAR; - wReserved1: Word; - end; - PDCB = ^TDCB; - -const -{$IFDEF UNIX} - {$IFDEF BSD} - MaxRates = 18; //MAC - {$ELSE} - MaxRates = 30; //UNIX - {$ENDIF} -{$ELSE} - MaxRates = 19; //WIN -{$ENDIF} - Rates: array[0..MaxRates, 0..1] of cardinal = - ( - (0, B0), - (50, B50), - (75, B75), - (110, B110), - (134, B134), - (150, B150), - (200, B200), - (300, B300), - (600, B600), - (1200, B1200), - (1800, B1800), - (2400, B2400), - (4800, B4800), - (9600, B9600), - (19200, B19200), - (38400, B38400), - (57600, B57600), - (115200, B115200), - (230400, B230400) -{$IFNDEF BSD} - ,(460800, B460800) - {$IFDEF UNIX} - ,(500000, B500000), - (576000, B576000), - (921600, B921600), - (1000000, B1000000), - (1152000, B1152000), - (1500000, B1500000), - (2000000, B2000000), - (2500000, B2500000), - (3000000, B3000000), - (3500000, B3500000), - (4000000, B4000000) - {$ENDIF} -{$ENDIF} - ); -{$ENDIF} - -{$IFDEF BSD} -const // From fcntl.h - O_SYNC = $0080; { synchronous writes } -{$ENDIF} - -const - sOK = 0; - sErr = integer(-1); - -type - - {:Possible status event types for @link(THookSerialStatus)} - THookSerialReason = ( - HR_SerialClose, - HR_Connect, - HR_CanRead, - HR_CanWrite, - HR_ReadCount, - HR_WriteCount, - HR_Wait - ); - - {:procedural prototype for status event hooking} - THookSerialStatus = procedure(Sender: TObject; Reason: THookSerialReason; - const Value: string) of object; - - {:@abstract(Exception type for SynaSer errors)} - ESynaSerError = class(Exception) - public - ErrorCode: integer; - ErrorMessage: string; - end; - - {:@abstract(Main class implementing all communication routines)} - TBlockSerial = class(TObject) - protected - FOnStatus: THookSerialStatus; - Fhandle: THandle; - FTag: integer; - FDevice: string; - FLastError: integer; - FLastErrorDesc: string; - FBuffer: AnsiString; - FRaiseExcept: boolean; - FRecvBuffer: integer; - FSendBuffer: integer; - FModemWord: integer; - FRTSToggle: Boolean; - FDeadlockTimeout: integer; - FInstanceActive: boolean; {HGJ} - FTestDSR: Boolean; - FTestCTS: Boolean; - FLastCR: Boolean; - FLastLF: Boolean; - FMaxLineLength: Integer; - FLinuxLock: Boolean; - FMaxSendBandwidth: Integer; - FNextSend: LongWord; - FMaxRecvBandwidth: Integer; - FNextRecv: LongWord; - FConvertLineEnd: Boolean; - FATResult: Boolean; - FAtTimeout: integer; - FInterPacketTimeout: Boolean; - FComNr: integer; -{$IFDEF MSWINDOWS} - FPortAddr: Word; - function CanEvent(Event: dword; Timeout: integer): boolean; - procedure DecodeCommError(Error: DWord); virtual; - {$IFDEF WIN32} - function GetPortAddr: Word; virtual; - function ReadTxEmpty(PortAddr: Word): Boolean; virtual; - {$ENDIF} -{$ENDIF} - procedure SetSizeRecvBuffer(size: integer); virtual; - function GetDSR: Boolean; virtual; - procedure SetDTRF(Value: Boolean); virtual; - function GetCTS: Boolean; virtual; - procedure SetRTSF(Value: Boolean); virtual; - function GetCarrier: Boolean; virtual; - function GetRing: Boolean; virtual; - procedure DoStatus(Reason: THookSerialReason; const Value: string); virtual; - procedure GetComNr(Value: string); virtual; - function PreTestFailing: boolean; virtual;{HGJ} - function TestCtrlLine: Boolean; virtual; -{$IFDEF UNIX} - procedure DcbToTermios(const dcb: TDCB; var term: termios); virtual; - procedure TermiosToDcb(const term: termios; var dcb: TDCB); virtual; - function ReadLockfile: integer; virtual; - function LockfileName: String; virtual; - procedure CreateLockfile(PidNr: integer); virtual; -{$ENDIF} - procedure LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); virtual; - procedure SetBandwidth(Value: Integer); virtual; - public - {: data Control Block with communication parameters. Usable only when you - need to call API directly.} - DCB: Tdcb; -{$IFDEF UNIX} - TermiosStruc: termios; -{$ENDIF} - {:Object constructor.} - constructor Create; - {:Object destructor.} - destructor Destroy; override; - - {:Returns a string containing the version number of the library.} - class function GetVersion: string; virtual; - - {:Destroy handle in use. It close connection to serial port.} - procedure CloseSocket; virtual; - - {:Reconfigure communication parameters on the fly. You must be connected to - port before! - @param(baud Define connection speed. Baud rate can be from 50 to 4000000 - bits per second. (it depends on your hardware!)) - @param(bits Number of bits in communication.) - @param(parity Define communication parity (N - None, O - Odd, E - Even, M - Mark or S - Space).) - @param(stop Define number of stopbits. Use constants @link(SB1), - @link(SB1andHalf) and @link(SB2).) - @param(softflow Enable XON/XOFF handshake.) - @param(hardflow Enable CTS/RTS handshake.)} - procedure Config(baud, bits: integer; parity: char; stop: integer; - softflow, hardflow: boolean); virtual; - - {:Connects to the port indicated by comport. Comport can be used in Windows - style (COM2), or in Linux style (/dev/ttyS1). When you use windows style - in Linux, then it will be converted to Linux name. And vice versa! However - you can specify any device name! (other device names then standart is not - converted!) - - After successfull connection the DTR signal is set (if you not set hardware - handshake, then the RTS signal is set, too!) - - Connection parameters is predefined by your system configuration. If you - need use another parameters, then you can use Config method after. - Notes: - - - Remember, the commonly used serial Laplink cable does not support - hardware handshake. - - - Before setting any handshake you must be sure that it is supported by - your hardware. - - - Some serial devices are slow. In some cases you must wait up to a few - seconds after connection for the device to respond. - - - when you connect to a modem device, then is best to test it by an empty - AT command. (call ATCommand('AT'))} - procedure Connect(comport: string); virtual; - - {:Set communication parameters from the DCB structure (the DCB structure is - simulated under Linux).} - procedure SetCommState; virtual; - - {:Read communication parameters into the DCB structure (DCB structure is - simulated under Linux).} - procedure GetCommState; virtual; - - {:Sends Length bytes of data from Buffer through the connected port.} - function SendBuffer(buffer: pointer; length: integer): integer; virtual; - - {:One data BYTE is sent.} - procedure SendByte(data: byte); virtual; - - {:Send the string in the data parameter. No terminator is appended by this - method. If you need to send a string with CR/LF terminator, you must append - the CR/LF characters to the data string! - - Since no terminator is appended, you can use this function for sending - binary data too.} - procedure SendString(data: AnsiString); virtual; - - {:send four bytes as integer.} - procedure SendInteger(Data: integer); virtual; - - {:send data as one block. Each block begins with integer value with Length - of block.} - procedure SendBlock(const Data: AnsiString); virtual; - - {:send content of stream from current position} - procedure SendStreamRaw(const Stream: TStream); virtual; - - {:send content of stream as block. see @link(SendBlock)} - procedure SendStream(const Stream: TStream); virtual; - - {:send content of stream as block, but this is compatioble with Indy library. - (it have swapped lenght of block). See @link(SendStream)} - procedure SendStreamIndy(const Stream: TStream); virtual; - - {:Waits until the allocated buffer is filled by received data. Returns number - of data bytes received, which equals to the Length value under normal - operation. If it is not equal, the communication channel is possibly broken. - - This method not using any internal buffering, like all others receiving - methods. You cannot freely combine this method with all others receiving - methods!} - function RecvBuffer(buffer: pointer; length: integer): integer; virtual; - - {:Method waits until data is received. If no data is received within - the Timeout (in milliseconds) period, @link(LastError) is set to - @link(ErrTimeout). This method is used to read any amount of data - (e. g. 1MB), and may be freely combined with all receviving methods what - have Timeout parameter, like the @link(RecvString), @link(RecvByte) or - @link(RecvTerminated) methods.} - function RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; virtual; - - {:It is like recvBufferEx, but data is readed to dynamicly allocated binary - string.} - function RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; virtual; - - {:Read all available data and return it in the function result string. This - function may be combined with @link(RecvString), @link(RecvByte) or related - methods.} - function RecvPacket(Timeout: Integer): AnsiString; virtual; - - {:Waits until one data byte is received which is returned as the function - result. If no data is received within the Timeout (in milliseconds) period, - @link(LastError) is set to @link(ErrTimeout).} - function RecvByte(timeout: integer): byte; virtual; - - {:This method waits until a terminated data string is received. This string - is terminated by the Terminator string. The resulting string is returned - without this termination string! If no data is received within the Timeout - (in milliseconds) period, @link(LastError) is set to @link(ErrTimeout).} - function RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; virtual; - - {:This method waits until a terminated data string is received. The string - is terminated by a CR/LF sequence. The resulting string is returned without - the terminator (CR/LF)! If no data is received within the Timeout (in - milliseconds) period, @link(LastError) is set to @link(ErrTimeout). - - If @link(ConvertLineEnd) is used, then the CR/LF sequence may not be exactly - CR/LF. See the description of @link(ConvertLineEnd). - - This method serves for line protocol implementation and uses its own - buffers to maximize performance. Therefore do NOT use this method with the - @link(RecvBuffer) method to receive data as it may cause data loss.} - function Recvstring(timeout: integer): AnsiString; virtual; - - {:Waits until four data bytes are received which is returned as the function - integer result. If no data is received within the Timeout (in milliseconds) period, - @link(LastError) is set to @link(ErrTimeout).} - function RecvInteger(Timeout: Integer): Integer; virtual; - - {:Waits until one data block is received. See @link(sendblock). If no data - is received within the Timeout (in milliseconds) period, @link(LastError) - is set to @link(ErrTimeout).} - function RecvBlock(Timeout: Integer): AnsiString; virtual; - - {:Receive all data to stream, until some error occured. (for example timeout)} - procedure RecvStreamRaw(const Stream: TStream; Timeout: Integer); virtual; - - {:receive requested count of bytes to stream} - procedure RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); virtual; - - {:receive block of data to stream. (Data can be sended by @link(sendstream)} - procedure RecvStream(const Stream: TStream; Timeout: Integer); virtual; - - {:receive block of data to stream. (Data can be sended by @link(sendstreamIndy)} - procedure RecvStreamIndy(const Stream: TStream; Timeout: Integer); virtual; - - {:Returns the number of received bytes waiting for reading. 0 is returned - when there is no data waiting.} - function WaitingData: integer; virtual; - - {:Same as @link(WaitingData), but in respect to data in the internal - @link(LineBuffer).} - function WaitingDataEx: integer; virtual; - - {:Returns the number of bytes waiting to be sent in the output buffer. - 0 is returned when the output buffer is empty.} - function SendingData: integer; virtual; - - {:Enable or disable RTS driven communication (half-duplex). It can be used - to communicate with RS485 converters, or other special equipment. If you - enable this feature, the system automatically controls the RTS signal. - - Notes: - - - On Windows NT (or higher) ir RTS signal driven by system driver. - - - On Win9x family is used special code for waiting until last byte is - sended from your UART. - - - On Linux you must have kernel 2.1 or higher!} - procedure EnableRTSToggle(value: boolean); virtual; - - {:Waits until all data to is sent and buffers are emptied. - Warning: On Windows systems is this method returns when all buffers are - flushed to the serial port controller, before the last byte is sent!} - procedure Flush; virtual; - - {:Unconditionally empty all buffers. It is good when you need to interrupt - communication and for cleanups.} - procedure Purge; virtual; - - {:Returns @True, if you can from read any data from the port. Status is - tested for a period of time given by the Timeout parameter (in milliseconds). - If the value of the Timeout parameter is 0, the status is tested only once - and the function returns immediately. If the value of the Timeout parameter - is set to -1, the function returns only after it detects data on the port - (this may cause the process to hang).} - function CanRead(Timeout: integer): boolean; virtual; - - {:Returns @True, if you can write any data to the port (this function is not - sending the contents of the buffer). Status is tested for a period of time - given by the Timeout parameter (in milliseconds). If the value of - the Timeout parameter is 0, the status is tested only once and the function - returns immediately. If the value of the Timeout parameter is set to -1, - the function returns only after it detects that it can write data to - the port (this may cause the process to hang).} - function CanWrite(Timeout: integer): boolean; virtual; - - {:Same as @link(CanRead), but the test is against data in the internal - @link(LineBuffer) too.} - function CanReadEx(Timeout: integer): boolean; virtual; - - {:Returns the status word of the modem. Decoding the status word could yield - the status of carrier detect signaland other signals. This method is used - internally by the modem status reading properties. You usually do not need - to call this method directly.} - function ModemStatus: integer; virtual; - - {:Send a break signal to the communication device for Duration milliseconds.} - procedure SetBreak(Duration: integer); virtual; - - {:This function is designed to send AT commands to the modem. The AT command - is sent in the Value parameter and the response is returned in the function - return value (may contain multiple lines!). - If the AT command is processed successfully (modem returns OK), then the - @link(ATResult) property is set to True. - - This function is designed only for AT commands that return OK or ERROR - response! To call connection commands the @link(ATConnect) method. - Remember, when you connect to a modem device, it is in AT command mode. - Now you can send AT commands to the modem. If you need to transfer data to - the modem on the other side of the line, you must first switch to data mode - using the @link(ATConnect) method.} - function ATCommand(value: AnsiString): AnsiString; virtual; - - {:This function is used to send connect type AT commands to the modem. It is - for commands to switch to connected state. (ATD, ATA, ATO,...) - It sends the AT command in the Value parameter and returns the modem's - response (may be multiple lines - usually with connection parameters info). - If the AT command is processed successfully (the modem returns CONNECT), - then the ATResult property is set to @True. - - This function is designed only for AT commands which respond by CONNECT, - BUSY, NO DIALTONE NO CARRIER or ERROR. For other AT commands use the - @link(ATCommand) method. - - The connect timeout is 90*@link(ATTimeout). If this command is successful - (@link(ATresult) is @true), then the modem is in data state. When you now - send or receive some data, it is not to or from your modem, but from the - modem on other side of the line. Now you can transfer your data. - If the connection attempt failed (@link(ATResult) is @False), then the - modem is still in AT command mode.} - function ATConnect(value: AnsiString): AnsiString; virtual; - - {:If you "manually" call API functions, forward their return code in - the SerialResult parameter to this function, which evaluates it and sets - @link(LastError) and @link(LastErrorDesc).} - function SerialCheck(SerialResult: integer): integer; virtual; - - {:If @link(Lasterror) is not 0 and exceptions are enabled, then this procedure - raises an exception. This method is used internally. You may need it only - in special cases.} - procedure ExceptCheck; virtual; - - {:Set Synaser to error state with ErrNumber code. Usually used by internal - routines.} - procedure SetSynaError(ErrNumber: integer); virtual; - - {:Raise Synaser error with ErrNumber code. Usually used by internal routines.} - procedure RaiseSynaError(ErrNumber: integer); virtual; -{$IFDEF UNIX} - function cpomComportAccessible: boolean; virtual;{HGJ} - procedure cpomReleaseComport; virtual; {HGJ} -{$ENDIF} - {:True device name of currently used port} - property Device: string read FDevice; - - {:Error code of last operation. Value is defined by the host operating - system, but value 0 is always OK.} - property LastError: integer read FLastError; - - {:Human readable description of LastError code.} - property LastErrorDesc: string read FLastErrorDesc; - - {:Indicates if the last @link(ATCommand) or @link(ATConnect) method was successful} - property ATResult: Boolean read FATResult; - - {:Read the value of the RTS signal.} - property RTS: Boolean write SetRTSF; - - {:Indicates the presence of the CTS signal} - property CTS: boolean read GetCTS; - - {:Use this property to set the value of the DTR signal.} - property DTR: Boolean write SetDTRF; - - {:Exposes the status of the DSR signal.} - property DSR: boolean read GetDSR; - - {:Indicates the presence of the Carrier signal} - property Carrier: boolean read GetCarrier; - - {:Reflects the status of the Ring signal.} - property Ring: boolean read GetRing; - - {:indicates if this instance of SynaSer is active. (Connected to some port)} - property InstanceActive: boolean read FInstanceActive; {HGJ} - - {:Defines maximum bandwidth for all sending operations in bytes per second. - If this value is set to 0 (default), bandwidth limitation is not used.} - property MaxSendBandwidth: Integer read FMaxSendBandwidth Write FMaxSendBandwidth; - - {:Defines maximum bandwidth for all receiving operations in bytes per second. - If this value is set to 0 (default), bandwidth limitation is not used.} - property MaxRecvBandwidth: Integer read FMaxRecvBandwidth Write FMaxRecvBandwidth; - - {:Defines maximum bandwidth for all sending and receiving operations - in bytes per second. If this value is set to 0 (default), bandwidth - limitation is not used.} - property MaxBandwidth: Integer Write SetBandwidth; - - {:Size of the Windows internal receive buffer. Default value is usually - 4096 bytes. Note: Valid only in Windows versions!} - property SizeRecvBuffer: integer read FRecvBuffer write SetSizeRecvBuffer; - published - {:Returns the descriptive text associated with ErrorCode. You need this - method only in special cases. Description of LastError is now accessible - through the LastErrorDesc property.} - class function GetErrorDesc(ErrorCode: integer): string; - - {:Freely usable property} - property Tag: integer read FTag write FTag; - - {:Contains the handle of the open communication port. - You may need this value to directly call communication functions outside - SynaSer.} - property Handle: THandle read Fhandle write FHandle; - - {:Internally used read buffer.} - property LineBuffer: AnsiString read FBuffer write FBuffer; - - {:If @true, communication errors raise exceptions. If @false (default), only - the @link(LastError) value is set.} - property RaiseExcept: boolean read FRaiseExcept write FRaiseExcept; - - {:This event is triggered when the communication status changes. It can be - used to monitor communication status.} - property OnStatus: THookSerialStatus read FOnStatus write FOnStatus; - - {:If you set this property to @true, then the value of the DSR signal - is tested before every data transfer. It can be used to detect the presence - of a communications device.} - property TestDSR: boolean read FTestDSR write FTestDSR; - - {:If you set this property to @true, then the value of the CTS signal - is tested before every data transfer. It can be used to detect the presence - of a communications device. Warning: This property cannot be used if you - need hardware handshake!} - property TestCTS: boolean read FTestCTS write FTestCTS; - - {:Use this property you to limit the maximum size of LineBuffer - (as a protection against unlimited memory allocation for LineBuffer). - Default value is 0 - no limit.} - property MaxLineLength: Integer read FMaxLineLength Write FMaxLineLength; - - {:This timeout value is used as deadlock protection when trying to send data - to (or receive data from) a device that stopped communicating during data - transmission (e.g. by physically disconnecting the device). - The timeout value is in milliseconds. The default value is 30,000 (30 seconds).} - property DeadlockTimeout: Integer read FDeadlockTimeout Write FDeadlockTimeout; - - {:If set to @true (default value), port locking is enabled (under Linux only). - WARNING: To use this feature, the application must run by a user with full - permission to the /var/lock directory!} - property LinuxLock: Boolean read FLinuxLock write FLinuxLock; - - {:Indicates if non-standard line terminators should be converted to a CR/LF pair - (standard DOS line terminator). If @TRUE, line terminators CR, single LF - or LF/CR are converted to CR/LF. Defaults to @FALSE. - This property has effect only on the behavior of the RecvString method.} - property ConvertLineEnd: Boolean read FConvertLineEnd Write FConvertLineEnd; - - {:Timeout for AT modem based operations} - property AtTimeout: integer read FAtTimeout Write FAtTimeout; - - {:If @true (default), then all timeouts is timeout between two characters. - If @False, then timeout is overall for whoole reading operation.} - property InterPacketTimeout: Boolean read FInterPacketTimeout Write FInterPacketTimeout; - end; - -{:Returns list of existing computer serial ports. Working properly only in Windows!} -function GetSerialPortNames: string; - -implementation - -constructor TBlockSerial.Create; -begin - inherited create; - FRaiseExcept := false; - FHandle := INVALID_HANDLE_VALUE; - FDevice := ''; - FComNr:= PortIsClosed; {HGJ} - FInstanceActive:= false; {HGJ} - Fbuffer := ''; - FRTSToggle := False; - FMaxLineLength := 0; - FTestDSR := False; - FTestCTS := False; - FDeadlockTimeout := 30000; - FLinuxLock := True; - FMaxSendBandwidth := 0; - FNextSend := 0; - FMaxRecvBandwidth := 0; - FNextRecv := 0; - FConvertLineEnd := False; - SetSynaError(sOK); - FRecvBuffer := 4096; - FLastCR := False; - FLastLF := False; - FAtTimeout := 1000; - FInterPacketTimeout := True; -end; - -destructor TBlockSerial.Destroy; -begin - CloseSocket; - inherited destroy; -end; - -class function TBlockSerial.GetVersion: string; -begin - Result := 'SynaSer 7.5.4'; -end; - -procedure TBlockSerial.CloseSocket; -begin - if Fhandle <> INVALID_HANDLE_VALUE then - begin - Purge; - RTS := False; - DTR := False; - FileClose(FHandle); - end; - if InstanceActive then - begin - {$IFDEF UNIX} - if FLinuxLock then - cpomReleaseComport; - {$ENDIF} - FInstanceActive:= false - end; - Fhandle := INVALID_HANDLE_VALUE; - FComNr:= PortIsClosed; - SetSynaError(sOK); - DoStatus(HR_SerialClose, FDevice); -end; - -{$IFDEF WIN32} -function TBlockSerial.GetPortAddr: Word; -begin - Result := 0; - if Win32Platform <> VER_PLATFORM_WIN32_NT then - begin - EscapeCommFunction(FHandle, 10); - asm - MOV @Result, DX; - end; - end; -end; - -function TBlockSerial.ReadTxEmpty(PortAddr: Word): Boolean; -begin - Result := True; - if Win32Platform <> VER_PLATFORM_WIN32_NT then - begin - asm - MOV DX, PortAddr; - ADD DX, 5; - IN AL, DX; - AND AL, $40; - JZ @K; - MOV AL,1; - @K: MOV @Result, AL; - end; - end; -end; -{$ENDIF} - -procedure TBlockSerial.GetComNr(Value: string); -begin - FComNr := PortIsClosed; - if pos('COM', uppercase(Value)) = 1 then - FComNr := StrToIntdef(copy(Value, 4, Length(Value) - 3), PortIsClosed + 1) - 1; - if pos('/DEV/TTYS', uppercase(Value)) = 1 then - FComNr := StrToIntdef(copy(Value, 10, Length(Value) - 9), PortIsClosed - 1); -end; - -procedure TBlockSerial.SetBandwidth(Value: Integer); -begin - MaxSendBandwidth := Value; - MaxRecvBandwidth := Value; -end; - -procedure TBlockSerial.LimitBandwidth(Length: Integer; MaxB: integer; var Next: LongWord); -var - x: LongWord; - y: LongWord; -begin - if MaxB > 0 then - begin - y := GetTick; - if Next > y then - begin - x := Next - y; - if x > 0 then - begin - DoStatus(HR_Wait, IntToStr(x)); - sleep(x); - end; - end; - Next := GetTick + Trunc((Length / MaxB) * 1000); - end; -end; - -procedure TBlockSerial.Config(baud, bits: integer; parity: char; stop: integer; - softflow, hardflow: boolean); -begin - FillChar(dcb, SizeOf(dcb), 0); - GetCommState; - dcb.DCBlength := SizeOf(dcb); - dcb.BaudRate := baud; - dcb.ByteSize := bits; - case parity of - 'N', 'n': dcb.parity := 0; - 'O', 'o': dcb.parity := 1; - 'E', 'e': dcb.parity := 2; - 'M', 'm': dcb.parity := 3; - 'S', 's': dcb.parity := 4; - end; - dcb.StopBits := stop; - dcb.XonChar := #17; - dcb.XoffChar := #19; - dcb.XonLim := FRecvBuffer div 4; - dcb.XoffLim := FRecvBuffer div 4; - dcb.Flags := dcb_Binary; - if softflow then - dcb.Flags := dcb.Flags or dcb_OutX or dcb_InX; - if hardflow then - dcb.Flags := dcb.Flags or dcb_OutxCtsFlow or dcb_RtsControlHandshake - else - dcb.Flags := dcb.Flags or dcb_RtsControlEnable; - dcb.Flags := dcb.Flags or dcb_DtrControlEnable; - if dcb.Parity > 0 then - dcb.Flags := dcb.Flags or dcb_ParityCheck; - SetCommState; -end; - -procedure TBlockSerial.Connect(comport: string); -{$IFDEF MSWINDOWS} -var - CommTimeouts: TCommTimeouts; -{$ENDIF} -begin - // Is this TBlockSerial Instance already busy? - if InstanceActive then {HGJ} - begin {HGJ} - RaiseSynaError(ErrAlreadyInUse); - Exit; {HGJ} - end; {HGJ} - FBuffer := ''; - FDevice := comport; - GetComNr(comport); -{$IFDEF MSWINDOWS} - SetLastError (sOK); -{$ELSE} - {$IFNDEF FPC} - SetLastError (sOK); - {$ELSE} - fpSetErrno(sOK); - {$ENDIF} -{$ENDIF} -{$IFNDEF MSWINDOWS} - if FComNr <> PortIsClosed then - FDevice := '/dev/ttyS' + IntToStr(FComNr); - // Comport already owned by another process? {HGJ} - if FLinuxLock then - if not cpomComportAccessible then - begin - RaiseSynaError(ErrAlreadyOwned); - Exit; - end; -{$IFNDEF FPC} - FHandle := THandle(Libc.open(pchar(FDevice), O_RDWR or O_SYNC)); -{$ELSE} - FHandle := THandle(fpOpen(FDevice, O_RDWR or O_SYNC)); -{$ENDIF} - if FHandle = INVALID_HANDLE_VALUE then //because THandle is not integer on all platforms! - SerialCheck(-1) - else - SerialCheck(0); - {$IFDEF UNIX} - if FLastError <> sOK then - if FLinuxLock then - cpomReleaseComport; - {$ENDIF} - ExceptCheck; - if FLastError <> sOK then - Exit; -{$ELSE} - if FComNr <> PortIsClosed then - FDevice := '\\.\COM' + IntToStr(FComNr + 1); - FHandle := THandle(CreateFile(PChar(FDevice), GENERIC_READ or GENERIC_WRITE, - 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0)); - if FHandle = INVALID_HANDLE_VALUE then //because THandle is not integer on all platforms! - SerialCheck(-1) - else - SerialCheck(0); - ExceptCheck; - if FLastError <> sOK then - Exit; - SetCommMask(FHandle, 0); - SetupComm(Fhandle, FRecvBuffer, 0); - CommTimeOuts.ReadIntervalTimeout := MAXWORD; - CommTimeOuts.ReadTotalTimeoutMultiplier := 0; - CommTimeOuts.ReadTotalTimeoutConstant := 0; - CommTimeOuts.WriteTotalTimeoutMultiplier := 0; - CommTimeOuts.WriteTotalTimeoutConstant := 0; - SetCommTimeOuts(FHandle, CommTimeOuts); - {$IFDEF WIN32} - FPortAddr := GetPortAddr; - {$ENDIF} -{$ENDIF} - SetSynaError(sOK); - if not TestCtrlLine then {HGJ} - begin - SetSynaError(ErrNoDeviceAnswer); - FileClose(FHandle); {HGJ} - {$IFDEF UNIX} - if FLinuxLock then - cpomReleaseComport; {HGJ} - {$ENDIF} {HGJ} - Fhandle := INVALID_HANDLE_VALUE; {HGJ} - FComNr:= PortIsClosed; {HGJ} - end - else - begin - FInstanceActive:= True; - RTS := True; - DTR := True; - Purge; - end; - ExceptCheck; - DoStatus(HR_Connect, FDevice); -end; - -function TBlockSerial.SendBuffer(buffer: pointer; length: integer): integer; -{$IFDEF MSWINDOWS} -var - Overlapped: TOverlapped; - x, y, Err: DWord; -{$ENDIF} -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - LimitBandwidth(Length, FMaxSendBandwidth, FNextsend); - if FRTSToggle then - begin - Flush; - RTS := True; - end; -{$IFNDEF MSWINDOWS} - result := FileWrite(Fhandle, Buffer^, Length); - serialcheck(result); -{$ELSE} - FillChar(Overlapped, Sizeof(Overlapped), 0); - SetSynaError(sOK); - y := 0; - if not WriteFile(FHandle, Buffer^, Length, DWord(Result), @Overlapped) then - y := GetLastError; - if y = ERROR_IO_PENDING then - begin - x := WaitForSingleObject(FHandle, FDeadlockTimeout); - if x = WAIT_TIMEOUT then - begin - PurgeComm(FHandle, PURGE_TXABORT); - SetSynaError(ErrTimeout); - end; - GetOverlappedResult(FHandle, Overlapped, Dword(Result), False); - end - else - SetSynaError(y); - ClearCommError(FHandle, err, nil); - if err <> 0 then - DecodeCommError(err); -{$ENDIF} - if FRTSToggle then - begin - Flush; - CanWrite(255); - RTS := False; - end; - ExceptCheck; - DoStatus(HR_WriteCount, IntToStr(Result)); -end; - -procedure TBlockSerial.SendByte(data: byte); -begin - SendBuffer(@Data, 1); -end; - -procedure TBlockSerial.SendString(data: AnsiString); -begin - SendBuffer(Pointer(Data), Length(Data)); -end; - -procedure TBlockSerial.SendInteger(Data: integer); -begin - SendBuffer(@data, SizeOf(Data)); -end; - -procedure TBlockSerial.SendBlock(const Data: AnsiString); -begin - SendInteger(Length(data)); - SendString(Data); -end; - -procedure TBlockSerial.SendStreamRaw(const Stream: TStream); -var - si: integer; - x, y, yr: integer; - s: AnsiString; -begin - si := Stream.Size - Stream.Position; - x := 0; - while x < si do - begin - y := si - x; - if y > cSerialChunk then - y := cSerialChunk; - Setlength(s, y); - yr := Stream.read(PAnsiChar(s)^, y); - if yr > 0 then - begin - SetLength(s, yr); - SendString(s); - Inc(x, yr); - end - else - break; - end; -end; - -procedure TBlockSerial.SendStreamIndy(const Stream: TStream); -var - si: integer; -begin - si := Stream.Size - Stream.Position; - si := Swapbytes(si); - SendInteger(si); - SendStreamRaw(Stream); -end; - -procedure TBlockSerial.SendStream(const Stream: TStream); -var - si: integer; -begin - si := Stream.Size - Stream.Position; - SendInteger(si); - SendStreamRaw(Stream); -end; - -function TBlockSerial.RecvBuffer(buffer: pointer; length: integer): integer; -{$IFNDEF MSWINDOWS} -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); - result := FileRead(FHandle, Buffer^, length); - serialcheck(result); -{$ELSE} -var - Overlapped: TOverlapped; - x, y, Err: DWord; -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - LimitBandwidth(Length, FMaxRecvBandwidth, FNextRecv); - FillChar(Overlapped, Sizeof(Overlapped), 0); - SetSynaError(sOK); - y := 0; - if not ReadFile(FHandle, Buffer^, length, Dword(Result), @Overlapped) then - y := GetLastError; - if y = ERROR_IO_PENDING then - begin - x := WaitForSingleObject(FHandle, FDeadlockTimeout); - if x = WAIT_TIMEOUT then - begin - PurgeComm(FHandle, PURGE_RXABORT); - SetSynaError(ErrTimeout); - end; - GetOverlappedResult(FHandle, Overlapped, Dword(Result), False); - end - else - SetSynaError(y); - ClearCommError(FHandle, err, nil); - if err <> 0 then - DecodeCommError(err); -{$ENDIF} - ExceptCheck; - DoStatus(HR_ReadCount, IntToStr(Result)); -end; - -function TBlockSerial.RecvBufferEx(buffer: pointer; length: integer; timeout: integer): integer; -var - s: AnsiString; - rl, l: integer; - ti: LongWord; -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - rl := 0; - repeat - ti := GetTick; - s := RecvPacket(Timeout); - l := System.Length(s); - if (rl + l) > Length then - l := Length - rl; - Move(Pointer(s)^, IncPoint(Buffer, rl)^, l); - rl := rl + l; - if FLastError <> sOK then - Break; - if rl >= Length then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - SetSynaError(ErrTimeout); - Break; - end; - end; - until False; - delete(s, 1, l); - FBuffer := s; - Result := rl; -end; - -function TBlockSerial.RecvBufferStr(Length: Integer; Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - if Length > 0 then - begin - Setlength(Result, Length); - x := RecvBufferEx(PAnsiChar(Result), Length , Timeout); - if FLastError = sOK then - SetLength(Result, x) - else - Result := ''; - end; -end; - -function TBlockSerial.RecvPacket(Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - if FBuffer <> '' then - begin - Result := FBuffer; - FBuffer := ''; - end - else - begin - //not drain CPU on large downloads... - Sleep(0); - x := WaitingData; - if x > 0 then - begin - SetLength(Result, x); - x := RecvBuffer(Pointer(Result), x); - if x >= 0 then - SetLength(Result, x); - end - else - begin - if CanRead(Timeout) then - begin - x := WaitingData; - if x = 0 then - SetSynaError(ErrTimeout); - if x > 0 then - begin - SetLength(Result, x); - x := RecvBuffer(Pointer(Result), x); - if x >= 0 then - SetLength(Result, x); - end; - end - else - SetSynaError(ErrTimeout); - end; - end; - ExceptCheck; -end; - - -function TBlockSerial.RecvByte(timeout: integer): byte; -begin - Result := 0; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - if FBuffer = '' then - FBuffer := RecvPacket(Timeout); - if (FLastError = sOK) and (FBuffer <> '') then - begin - Result := Ord(FBuffer[1]); - System.Delete(FBuffer, 1, 1); - end; - ExceptCheck; -end; - -function TBlockSerial.RecvTerminated(Timeout: Integer; const Terminator: AnsiString): AnsiString; -var - x: Integer; - s: AnsiString; - l: Integer; - CorCRLF: Boolean; - t: ansistring; - tl: integer; - ti: LongWord; -begin - Result := ''; - if PreTestFailing then {HGJ} - Exit; {HGJ} - SetSynaError(sOK); - l := system.Length(Terminator); - if l = 0 then - Exit; - tl := l; - CorCRLF := FConvertLineEnd and (Terminator = CRLF); - s := ''; - x := 0; - repeat - ti := GetTick; - //get rest of FBuffer or incomming new data... - s := s + RecvPacket(Timeout); - if FLastError <> sOK then - Break; - x := 0; - if Length(s) > 0 then - if CorCRLF then - begin - if FLastCR and (s[1] = LF) then - Delete(s, 1, 1); - if FLastLF and (s[1] = CR) then - Delete(s, 1, 1); - FLastCR := False; - FLastLF := False; - t := ''; - x := PosCRLF(s, t); - tl := system.Length(t); - if t = CR then - FLastCR := True; - if t = LF then - FLastLF := True; - end - else - begin - x := pos(Terminator, s); - tl := l; - end; - if (FMaxLineLength <> 0) and (system.Length(s) > FMaxLineLength) then - begin - SetSynaError(ErrMaxBuffer); - Break; - end; - if x > 0 then - Break; - if not FInterPacketTimeout then - begin - Timeout := Timeout - integer(TickDelta(ti, GetTick)); - if Timeout <= 0 then - begin - SetSynaError(ErrTimeout); - Break; - end; - end; - until False; - if x > 0 then - begin - Result := Copy(s, 1, x - 1); - System.Delete(s, 1, x + tl - 1); - end; - FBuffer := s; - ExceptCheck; -end; - - -function TBlockSerial.RecvString(Timeout: Integer): AnsiString; -var - s: AnsiString; -begin - Result := ''; - s := RecvTerminated(Timeout, #13 + #10); - if FLastError = sOK then - Result := s; -end; - -function TBlockSerial.RecvInteger(Timeout: Integer): Integer; -var - s: AnsiString; -begin - Result := 0; - s := RecvBufferStr(4, Timeout); - if FLastError = 0 then - Result := (ord(s[1]) + ord(s[2]) * 256) + (ord(s[3]) + ord(s[4]) * 256) * 65536; -end; - -function TBlockSerial.RecvBlock(Timeout: Integer): AnsiString; -var - x: integer; -begin - Result := ''; - x := RecvInteger(Timeout); - if FLastError = 0 then - Result := RecvBufferStr(x, Timeout); -end; - -procedure TBlockSerial.RecvStreamRaw(const Stream: TStream; Timeout: Integer); -var - s: AnsiString; -begin - repeat - s := RecvPacket(Timeout); - if FLastError = 0 then - WriteStrToStream(Stream, s); - until FLastError <> 0; -end; - -procedure TBlockSerial.RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer); -var - s: AnsiString; - n: integer; -begin - for n := 1 to (Size div cSerialChunk) do - begin - s := RecvBufferStr(cSerialChunk, Timeout); - if FLastError <> 0 then - Exit; - Stream.Write(PAnsichar(s)^, cSerialChunk); - end; - n := Size mod cSerialChunk; - if n > 0 then - begin - s := RecvBufferStr(n, Timeout); - if FLastError <> 0 then - Exit; - Stream.Write(PAnsichar(s)^, n); - end; -end; - -procedure TBlockSerial.RecvStreamIndy(const Stream: TStream; Timeout: Integer); -var - x: integer; -begin - x := RecvInteger(Timeout); - x := SwapBytes(x); - if FLastError = 0 then - RecvStreamSize(Stream, Timeout, x); -end; - -procedure TBlockSerial.RecvStream(const Stream: TStream; Timeout: Integer); -var - x: integer; -begin - x := RecvInteger(Timeout); - if FLastError = 0 then - RecvStreamSize(Stream, Timeout, x); -end; - -{$IFNDEF MSWINDOWS} -function TBlockSerial.WaitingData: integer; -begin -{$IFNDEF FPC} - serialcheck(ioctl(FHandle, FIONREAD, @result)); -{$ELSE} - serialcheck(fpIoctl(FHandle, FIONREAD, @result)); -{$ENDIF} - if FLastError <> 0 then - Result := 0; - ExceptCheck; -end; -{$ELSE} -function TBlockSerial.WaitingData: integer; -var - stat: TComStat; - err: DWORD; -begin - if ClearCommError(FHandle, err, @stat) then - begin - SetSynaError(sOK); - Result := stat.cbInQue; - end - else - begin - SerialCheck(sErr); - Result := 0; - end; - ExceptCheck; -end; -{$ENDIF} - -function TBlockSerial.WaitingDataEx: integer; -begin - if FBuffer <> '' then - Result := Length(FBuffer) - else - Result := Waitingdata; -end; - -{$IFNDEF MSWINDOWS} -function TBlockSerial.SendingData: integer; -begin - SetSynaError(sOK); - Result := 0; -end; -{$ELSE} -function TBlockSerial.SendingData: integer; -var - stat: TComStat; - err: DWORD; -begin - SetSynaError(sOK); - if not ClearCommError(FHandle, err, @stat) then - serialcheck(sErr); - ExceptCheck; - result := stat.cbOutQue; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.DcbToTermios(const dcb: TDCB; var term: termios); -var - n: integer; - x: cardinal; -begin - //others - cfmakeraw(term); - term.c_cflag := term.c_cflag or CREAD; - term.c_cflag := term.c_cflag or CLOCAL; - term.c_cflag := term.c_cflag or HUPCL; - //hardware handshake - if (dcb.flags and dcb_RtsControlHandshake) > 0 then - term.c_cflag := term.c_cflag or CRTSCTS - else - term.c_cflag := term.c_cflag and (not CRTSCTS); - //software handshake - if (dcb.flags and dcb_OutX) > 0 then - term.c_iflag := term.c_iflag or IXON or IXOFF or IXANY - else - term.c_iflag := term.c_iflag and (not (IXON or IXOFF or IXANY)); - //size of byte - term.c_cflag := term.c_cflag and (not CSIZE); - case dcb.bytesize of - 5: - term.c_cflag := term.c_cflag or CS5; - 6: - term.c_cflag := term.c_cflag or CS6; - 7: -{$IFDEF FPC} - term.c_cflag := term.c_cflag or CS7; -{$ELSE} - term.c_cflag := term.c_cflag or CS7fix; -{$ENDIF} - 8: - term.c_cflag := term.c_cflag or CS8; - end; - //parity - if (dcb.flags and dcb_ParityCheck) > 0 then - term.c_cflag := term.c_cflag or PARENB - else - term.c_cflag := term.c_cflag and (not PARENB); - case dcb.parity of - 1: //'O' - term.c_cflag := term.c_cflag or PARODD; - 2: //'E' - term.c_cflag := term.c_cflag and (not PARODD); - end; - //stop bits - if dcb.stopbits > 0 then - term.c_cflag := term.c_cflag or CSTOPB - else - term.c_cflag := term.c_cflag and (not CSTOPB); - //set baudrate; - x := 0; - for n := 0 to Maxrates do - if rates[n, 0] = dcb.BaudRate then - begin - x := rates[n, 1]; - break; - end; - cfsetospeed(term, x); - cfsetispeed(term, x); -end; - -procedure TBlockSerial.TermiosToDcb(const term: termios; var dcb: TDCB); -var - n: integer; - x: cardinal; -begin - //set baudrate; - dcb.baudrate := 0; - {$IFDEF FPC} - //why FPC not have cfgetospeed??? - x := term.c_oflag and $0F; - {$ELSE} - x := cfgetospeed(term); - {$ENDIF} - for n := 0 to Maxrates do - if rates[n, 1] = x then - begin - dcb.baudrate := rates[n, 0]; - break; - end; - //hardware handshake - if (term.c_cflag and CRTSCTS) > 0 then - dcb.flags := dcb.flags or dcb_RtsControlHandshake or dcb_OutxCtsFlow - else - dcb.flags := dcb.flags and (not (dcb_RtsControlHandshake or dcb_OutxCtsFlow)); - //software handshake - if (term.c_cflag and IXOFF) > 0 then - dcb.flags := dcb.flags or dcb_OutX or dcb_InX - else - dcb.flags := dcb.flags and (not (dcb_OutX or dcb_InX)); - //size of byte - case term.c_cflag and CSIZE of - CS5: - dcb.bytesize := 5; - CS6: - dcb.bytesize := 6; - CS7fix: - dcb.bytesize := 7; - CS8: - dcb.bytesize := 8; - end; - //parity - if (term.c_cflag and PARENB) > 0 then - dcb.flags := dcb.flags or dcb_ParityCheck - else - dcb.flags := dcb.flags and (not dcb_ParityCheck); - dcb.parity := 0; - if (term.c_cflag and PARODD) > 0 then - dcb.parity := 1 - else - dcb.parity := 2; - //stop bits - if (term.c_cflag and CSTOPB) > 0 then - dcb.stopbits := 2 - else - dcb.stopbits := 0; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.SetCommState; -begin - DcbToTermios(dcb, termiosstruc); - SerialCheck(tcsetattr(FHandle, TCSANOW, termiosstruc)); - ExceptCheck; -end; -{$ELSE} -procedure TBlockSerial.SetCommState; -begin - SetSynaError(sOK); - if not windows.SetCommState(Fhandle, dcb) then - SerialCheck(sErr); - ExceptCheck; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.GetCommState; -begin - SerialCheck(tcgetattr(FHandle, termiosstruc)); - ExceptCheck; - TermiostoDCB(termiosstruc, dcb); -end; -{$ELSE} -procedure TBlockSerial.GetCommState; -begin - SetSynaError(sOK); - if not windows.GetCommState(Fhandle, dcb) then - SerialCheck(sErr); - ExceptCheck; -end; -{$ENDIF} - -procedure TBlockSerial.SetSizeRecvBuffer(size: integer); -begin -{$IFDEF MSWINDOWS} - SetupComm(Fhandle, size, 0); - GetCommState; - dcb.XonLim := size div 4; - dcb.XoffLim := size div 4; - SetCommState; -{$ENDIF} - FRecvBuffer := size; -end; - -function TBlockSerial.GetDSR: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_DSR) > 0; -{$ELSE} - Result := (FModemWord and MS_DSR_ON) > 0; -{$ENDIF} -end; - -procedure TBlockSerial.SetDTRF(Value: Boolean); -begin -{$IFNDEF MSWINDOWS} - ModemStatus; - if Value then - FModemWord := FModemWord or TIOCM_DTR - else - FModemWord := FModemWord and not TIOCM_DTR; - {$IFNDEF FPC} - ioctl(FHandle, TIOCMSET, @FModemWord); - {$ELSE} - fpioctl(FHandle, TIOCMSET, @FModemWord); - {$ENDIF} -{$ELSE} - if Value then - EscapeCommFunction(FHandle, SETDTR) - else - EscapeCommFunction(FHandle, CLRDTR); -{$ENDIF} -end; - -function TBlockSerial.GetCTS: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_CTS) > 0; -{$ELSE} - Result := (FModemWord and MS_CTS_ON) > 0; -{$ENDIF} -end; - -procedure TBlockSerial.SetRTSF(Value: Boolean); -begin -{$IFNDEF MSWINDOWS} - ModemStatus; - if Value then - FModemWord := FModemWord or TIOCM_RTS - else - FModemWord := FModemWord and not TIOCM_RTS; - {$IFNDEF FPC} - ioctl(FHandle, TIOCMSET, @FModemWord); - {$ELSE} - fpioctl(FHandle, TIOCMSET, @FModemWord); - {$ENDIF} -{$ELSE} - if Value then - EscapeCommFunction(FHandle, SETRTS) - else - EscapeCommFunction(FHandle, CLRRTS); -{$ENDIF} -end; - -function TBlockSerial.GetCarrier: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_CAR) > 0; -{$ELSE} - Result := (FModemWord and MS_RLSD_ON) > 0; -{$ENDIF} -end; - -function TBlockSerial.GetRing: Boolean; -begin - ModemStatus; -{$IFNDEF MSWINDOWS} - Result := (FModemWord and TIOCM_RNG) > 0; -{$ELSE} - Result := (FModemWord and MS_RING_ON) > 0; -{$ENDIF} -end; - -{$IFDEF MSWINDOWS} -function TBlockSerial.CanEvent(Event: dword; Timeout: integer): boolean; -var - ex: DWord; - y: Integer; - Overlapped: TOverlapped; -begin - FillChar(Overlapped, Sizeof(Overlapped), 0); - Overlapped.hEvent := CreateEvent(nil, True, False, nil); - try - SetCommMask(FHandle, Event); - SetSynaError(sOK); - if (Event = EV_RXCHAR) and (Waitingdata > 0) then - Result := True - else - begin - y := 0; - if not WaitCommEvent(FHandle, ex, @Overlapped) then - y := GetLastError; - if y = ERROR_IO_PENDING then - begin - //timedout - WaitForSingleObject(Overlapped.hEvent, Timeout); - SetCommMask(FHandle, 0); - GetOverlappedResult(FHandle, Overlapped, DWord(y), True); - end; - Result := (ex and Event) = Event; - end; - finally - SetCommMask(FHandle, 0); - CloseHandle(Overlapped.hEvent); - end; -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -function TBlockSerial.CanRead(Timeout: integer): boolean; -var - FDSet: TFDSet; - TimeVal: PTimeVal; - TimeV: TTimeVal; - x: Integer; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - {$IFNDEF FPC} - FD_ZERO(FDSet); - FD_SET(FHandle, FDSet); - x := Select(FHandle + 1, @FDSet, nil, nil, TimeVal); - {$ELSE} - fpFD_ZERO(FDSet); - fpFD_SET(FHandle, FDSet); - x := fpSelect(FHandle + 1, @FDSet, nil, nil, TimeVal); - {$ENDIF} - SerialCheck(x); - if FLastError <> sOK then - x := 0; - Result := x > 0; - ExceptCheck; - if Result then - DoStatus(HR_CanRead, ''); -end; -{$ELSE} -function TBlockSerial.CanRead(Timeout: integer): boolean; -begin - Result := WaitingData > 0; - if not Result then - Result := CanEvent(EV_RXCHAR, Timeout) or (WaitingData > 0); - //check WaitingData again due some broken virtual ports - if Result then - DoStatus(HR_CanRead, ''); -end; -{$ENDIF} - -{$IFNDEF MSWINDOWS} -function TBlockSerial.CanWrite(Timeout: integer): boolean; -var - FDSet: TFDSet; - TimeVal: PTimeVal; - TimeV: TTimeVal; - x: Integer; -begin - TimeV.tv_usec := (Timeout mod 1000) * 1000; - TimeV.tv_sec := Timeout div 1000; - TimeVal := @TimeV; - if Timeout = -1 then - TimeVal := nil; - {$IFNDEF FPC} - FD_ZERO(FDSet); - FD_SET(FHandle, FDSet); - x := Select(FHandle + 1, nil, @FDSet, nil, TimeVal); - {$ELSE} - fpFD_ZERO(FDSet); - fpFD_SET(FHandle, FDSet); - x := fpSelect(FHandle + 1, nil, @FDSet, nil, TimeVal); - {$ENDIF} - SerialCheck(x); - if FLastError <> sOK then - x := 0; - Result := x > 0; - ExceptCheck; - if Result then - DoStatus(HR_CanWrite, ''); -end; -{$ELSE} -function TBlockSerial.CanWrite(Timeout: integer): boolean; -var - t: LongWord; -begin - Result := SendingData = 0; - if not Result then - Result := CanEvent(EV_TXEMPTY, Timeout); - {$IFDEF WIN32} - if Result and (Win32Platform <> VER_PLATFORM_WIN32_NT) then - begin - t := GetTick; - while not ReadTxEmpty(FPortAddr) do - begin - if TickDelta(t, GetTick) > 255 then - Break; - Sleep(0); - end; - end; - {$ENDIF} - if Result then - DoStatus(HR_CanWrite, ''); -end; -{$ENDIF} - -function TBlockSerial.CanReadEx(Timeout: integer): boolean; -begin - if Fbuffer <> '' then - Result := True - else - Result := CanRead(Timeout); -end; - -procedure TBlockSerial.EnableRTSToggle(Value: boolean); -begin - SetSynaError(sOK); -{$IFNDEF MSWINDOWS} - FRTSToggle := Value; - if Value then - RTS:=False; -{$ELSE} - if Win32Platform = VER_PLATFORM_WIN32_NT then - begin - GetCommState; - if value then - dcb.Flags := dcb.Flags or dcb_RtsControlToggle - else - dcb.flags := dcb.flags and (not dcb_RtsControlToggle); - SetCommState; - end - else - begin - FRTSToggle := Value; - if Value then - RTS:=False; - end; -{$ENDIF} -end; - -procedure TBlockSerial.Flush; -begin -{$IFNDEF MSWINDOWS} - SerialCheck(tcdrain(FHandle)); -{$ELSE} - SetSynaError(sOK); - if not Flushfilebuffers(FHandle) then - SerialCheck(sErr); -{$ENDIF} - ExceptCheck; -end; - -{$IFNDEF MSWINDOWS} -procedure TBlockSerial.Purge; -begin - {$IFNDEF FPC} - SerialCheck(ioctl(FHandle, TCFLSH, TCIOFLUSH)); - {$ELSE} - {$IFDEF DARWIN} - SerialCheck(fpioctl(FHandle, TCIOflush, Pointer(TCIOFLUSH))); - {$ELSE} - SerialCheck(fpioctl(FHandle, {$IFDEF FreeBSD}TCIOFLUSH{$ELSE}TCFLSH{$ENDIF}, Pointer(PtrInt(TCIOFLUSH)))); - {$ENDIF} - {$ENDIF} - FBuffer := ''; - ExceptCheck; -end; -{$ELSE} -procedure TBlockSerial.Purge; -var - x: integer; -begin - SetSynaError(sOK); - x := PURGE_TXABORT or PURGE_TXCLEAR or PURGE_RXABORT or PURGE_RXCLEAR; - if not PurgeComm(FHandle, x) then - SerialCheck(sErr); - FBuffer := ''; - ExceptCheck; -end; -{$ENDIF} - -function TBlockSerial.ModemStatus: integer; -begin - Result := 0; -{$IFNDEF MSWINDOWS} - {$IFNDEF FPC} - SerialCheck(ioctl(FHandle, TIOCMGET, @Result)); - {$ELSE} - SerialCheck(fpioctl(FHandle, TIOCMGET, @Result)); - {$ENDIF} -{$ELSE} - SetSynaError(sOK); - if not GetCommModemStatus(FHandle, dword(Result)) then - SerialCheck(sErr); -{$ENDIF} - ExceptCheck; - FModemWord := Result; -end; - -procedure TBlockSerial.SetBreak(Duration: integer); -begin -{$IFNDEF MSWINDOWS} - SerialCheck(tcsendbreak(FHandle, Duration)); -{$ELSE} - SetCommBreak(FHandle); - Sleep(Duration); - SetSynaError(sOK); - if not ClearCommBreak(FHandle) then - SerialCheck(sErr); -{$ENDIF} -end; - -{$IFDEF MSWINDOWS} -procedure TBlockSerial.DecodeCommError(Error: DWord); -begin - if (Error and DWord(CE_FRAME)) > 1 then - FLastError := ErrFrame; - if (Error and DWord(CE_OVERRUN)) > 1 then - FLastError := ErrOverrun; - if (Error and DWord(CE_RXOVER)) > 1 then - FLastError := ErrRxOver; - if (Error and DWord(CE_RXPARITY)) > 1 then - FLastError := ErrRxParity; - if (Error and DWord(CE_TXFULL)) > 1 then - FLastError := ErrTxFull; -end; -{$ENDIF} - -//HGJ -function TBlockSerial.PreTestFailing: Boolean; -begin - if not FInstanceActive then - begin - RaiseSynaError(ErrPortNotOpen); - result:= true; - Exit; - end; - Result := not TestCtrlLine; - if result then - RaiseSynaError(ErrNoDeviceAnswer) -end; - -function TBlockSerial.TestCtrlLine: Boolean; -begin - result := ((not FTestDSR) or DSR) and ((not FTestCTS) or CTS); -end; - -function TBlockSerial.ATCommand(value: AnsiString): AnsiString; -var - s: AnsiString; - ConvSave: Boolean; -begin - result := ''; - FAtResult := False; - ConvSave := FConvertLineEnd; - try - FConvertLineEnd := True; - SendString(value + #$0D); - repeat - s := RecvString(FAtTimeout); - if s <> Value then - result := result + s + CRLF; - if s = 'OK' then - begin - FAtResult := True; - break; - end; - if s = 'ERROR' then - break; - until FLastError <> sOK; - finally - FConvertLineEnd := Convsave; - end; -end; - - -function TBlockSerial.ATConnect(value: AnsiString): AnsiString; -var - s: AnsiString; - ConvSave: Boolean; -begin - result := ''; - FAtResult := False; - ConvSave := FConvertLineEnd; - try - FConvertLineEnd := True; - SendString(value + #$0D); - repeat - s := RecvString(90 * FAtTimeout); - if s <> Value then - result := result + s + CRLF; - if s = 'NO CARRIER' then - break; - if s = 'ERROR' then - break; - if s = 'BUSY' then - break; - if s = 'NO DIALTONE' then - break; - if Pos('CONNECT', s) = 1 then - begin - FAtResult := True; - break; - end; - until FLastError <> sOK; - finally - FConvertLineEnd := Convsave; - end; -end; - -function TBlockSerial.SerialCheck(SerialResult: integer): integer; -begin - if SerialResult = integer(INVALID_HANDLE_VALUE) then -{$IFDEF MSWINDOWS} - result := GetLastError -{$ELSE} - {$IFNDEF FPC} - result := GetLastError - {$ELSE} - result := fpGetErrno - {$ENDIF} -{$ENDIF} - else - result := sOK; - FLastError := result; - FLastErrorDesc := GetErrorDesc(FLastError); -end; - -procedure TBlockSerial.ExceptCheck; -var - e: ESynaSerError; - s: string; -begin - if FRaiseExcept and (FLastError <> sOK) then - begin - s := GetErrorDesc(FLastError); - e := ESynaSerError.CreateFmt('Communication error %d: %s', [FLastError, s]); - e.ErrorCode := FLastError; - e.ErrorMessage := s; - raise e; - end; -end; - -procedure TBlockSerial.SetSynaError(ErrNumber: integer); -begin - FLastError := ErrNumber; - FLastErrorDesc := GetErrorDesc(FLastError); -end; - -procedure TBlockSerial.RaiseSynaError(ErrNumber: integer); -begin - SetSynaError(ErrNumber); - ExceptCheck; -end; - -procedure TBlockSerial.DoStatus(Reason: THookSerialReason; const Value: string); -begin - if assigned(OnStatus) then - OnStatus(Self, Reason, Value); -end; - -{======================================================================} - -class function TBlockSerial.GetErrorDesc(ErrorCode: integer): string; -begin - Result:= ''; - case ErrorCode of - sOK: Result := 'OK'; - ErrAlreadyOwned: Result := 'Port owned by other process';{HGJ} - ErrAlreadyInUse: Result := 'Instance already in use'; {HGJ} - ErrWrongParameter: Result := 'Wrong parameter at call'; {HGJ} - ErrPortNotOpen: Result := 'Instance not yet connected'; {HGJ} - ErrNoDeviceAnswer: Result := 'No device answer detected'; {HGJ} - ErrMaxBuffer: Result := 'Maximal buffer length exceeded'; - ErrTimeout: Result := 'Timeout during operation'; - ErrNotRead: Result := 'Reading of data failed'; - ErrFrame: Result := 'Receive framing error'; - ErrOverrun: Result := 'Receive Overrun Error'; - ErrRxOver: Result := 'Receive Queue overflow'; - ErrRxParity: Result := 'Receive Parity Error'; - ErrTxFull: Result := 'Tranceive Queue is full'; - end; - if Result = '' then - begin - Result := SysErrorMessage(ErrorCode); - end; -end; - - -{---------- cpom Comport Ownership Manager Routines ------------- - by Hans-Georg Joepgen of Stuttgart, Germany. - Copyright (c) 2002, by Hans-Georg Joepgen - - Stefan Krauss of Stuttgart, Germany, contributed literature and Internet - research results, invaluable advice and excellent answers to the Comport - Ownership Manager. -} - -{$IFDEF UNIX} - -function TBlockSerial.LockfileName: String; -var - s: string; -begin - s := SeparateRight(FDevice, '/dev/'); - result := LockfileDirectory + '/LCK..' + s; -end; - -procedure TBlockSerial.CreateLockfile(PidNr: integer); -var - f: TextFile; - s: string; -begin - // Create content for file - s := IntToStr(PidNr); - while length(s) < 10 do - s := ' ' + s; - // Create file - try - AssignFile(f, LockfileName); - try - Rewrite(f); - writeln(f, s); - finally - CloseFile(f); - end; - // Allow all users to enjoy the benefits of cpom - s := 'chmod a+rw ' + LockfileName; -{$IFNDEF FPC} - FileSetReadOnly( LockfileName, False ) ; - // Libc.system(pchar(s)); -{$ELSE} - fpSystem(s); -{$ENDIF} - except - // not raise exception, if you not have write permission for lock. - on Exception do - ; - end; -end; - -function TBlockSerial.ReadLockfile: integer; -{Returns PID from Lockfile. Lockfile must exist.} -var - f: TextFile; - s: string; -begin - AssignFile(f, LockfileName); - Reset(f); - try - readln(f, s); - finally - CloseFile(f); - end; - Result := StrToIntDef(s, -1) -end; - -function TBlockSerial.cpomComportAccessible: boolean; -var - MyPid: integer; - Filename: string; -begin - Filename := LockfileName; - {$IFNDEF FPC} - MyPid := Libc.getpid; - {$ELSE} - MyPid := fpGetPid; - {$ENDIF} - // Make sure, the Lock Files Directory exists. We need it. - if not DirectoryExists(LockfileDirectory) then - CreateDir(LockfileDirectory); - // Check the Lockfile - if not FileExists (Filename) then - begin // comport is not locked. Lock it for us. - CreateLockfile(MyPid); - result := true; - exit; // done. - end; - // Is port owned by orphan? Then it's time for error recovery. - //FPC forgot to add getsid.. :-( - {$IFNDEF FPC} - if Libc.getsid(ReadLockfile) = -1 then - begin // Lockfile was left from former desaster - DeleteFile(Filename); // error recovery - CreateLockfile(MyPid); - result := true; - exit; - end; - {$ENDIF} - result := false // Sorry, port is owned by living PID and locked -end; - -procedure TBlockSerial.cpomReleaseComport; -begin - DeleteFile(LockfileName); -end; - -{$ENDIF} -{----------------------------------------------------------------} - -{$IFDEF MSWINDOWS} -function GetSerialPortNames: string; -var - reg: TRegistry; - l, v: TStringList; - n: integer; -begin - l := TStringList.Create; - v := TStringList.Create; - reg := TRegistry.Create; - try -{$IFNDEF VER100} -{$IFNDEF VER120} - reg.Access := KEY_READ; -{$ENDIF} -{$ENDIF} - reg.RootKey := HKEY_LOCAL_MACHINE; - reg.OpenKey('\HARDWARE\DEVICEMAP\SERIALCOMM', false); - reg.GetValueNames(l); - for n := 0 to l.Count - 1 do - v.Add(reg.ReadString(l[n])); - Result := v.CommaText; - finally - reg.Free; - l.Free; - v.Free; - end; -end; -{$ENDIF} -{$IFNDEF MSWINDOWS} -function GetSerialPortNames: string; -var - sr : TSearchRec; -begin - Result := ''; - if FindFirst('/dev/ttyS*', $FFFFFFFF, sr) = 0 then - begin - repeat - if (sr.Attr and $FFFFFFFF) = Sr.Attr then - begin - if Result <> '' then - Result := Result + ','; - Result := Result + sr.Name; - end; - until FindNext(sr) <> 0; - end; - FindClose(sr); -end; -{$ENDIF} - -end. \ No newline at end of file diff --git a/3rd/synapse/source/synautil.pas b/3rd/synapse/source/synautil.pas deleted file mode 100644 index 6b39d31c9..000000000 --- a/3rd/synapse/source/synautil.pas +++ /dev/null @@ -1,2124 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 004.015.006 | -|==============================================================================| -| Content: support procedures and functions | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c) 1999-2013. | -| Portions created by Hernan Sanchez are Copyright (c) 2000. | -| Portions created by Petr Fejfar are Copyright (c)2011-2012. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Hernan Sanchez (hernan.sanchez@iname.com) | -| Tomas Hajny (OS2 support) | -| Radek Cervinka (POSIX support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Support procedures and functions)} - -{$I jedi.inc} // load common compiler defines - -{$Q-} -{$R-} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} - {$WARN SUSPICIOUS_TYPECAST OFF} -{$ENDIF} - -unit synautil; - -interface - -uses -{$IFDEF MSWINDOWS} - Windows, -{$ELSE MSWINDOWS} - {$IFDEF FPC} - {$IFDEF OS2} - Dos, TZUtil, - {$ELSE OS2} - UnixUtil, Unix, BaseUnix, - {$ENDIF OS2} - {$ELSE FPC} - {$IFDEF POSIX} - Posix.Base, Posix.Time, Posix.SysTypes, Posix.SysTime, Posix.Stdio, - {$ELSE} - Libc, - {$ENDIF} - {$ENDIF} -{$ENDIF} -{$IFDEF CIL} - System.IO, -{$ENDIF} - SysUtils, Classes, SynaFpc; - -{$IFDEF VER100} -type - int64 = integer; -{$ENDIF} -{$IFDEF POSIX} -type - TTimeVal = Posix.SysTime.timeval; - Ttimezone = record - tz_minuteswest: Integer ; // minutes west of Greenwich - tz_dsttime: integer ; // type of DST correction - end; - - PTimeZone = ^Ttimezone; -{$ENDIF} - - -{:Return your timezone bias from UTC time in minutes.} -function TimeZoneBias: integer; - -{:Return your timezone bias from UTC time in string representation like "+0200".} -function TimeZone: string; - -{:Returns current time in format defined in RFC-822. Useful for SMTP messages, - but other protocols use this time format as well. Results contains the timezone - specification. Four digit year is used to break any Y2K concerns. (Example - 'Fri, 15 Oct 1999 21:14:56 +0200')} -function Rfc822DateTime(t: TDateTime): string; - -{:Returns date and time in format defined in C compilers in format "mmm dd hh:nn:ss"} -function CDateTime(t: TDateTime): string; - -{:Returns date and time in format defined in format 'yymmdd hhnnss'} -function SimpleDateTime(t: TDateTime): string; - -{:Returns date and time in format defined in ANSI C compilers in format - "ddd mmm d hh:nn:ss yyyy" } -function AnsiCDateTime(t: TDateTime): string; - -{:Decode three-letter string with name of month to their month number. If string - not match any month name, then is returned 0. For parsing are used predefined - names for English, French and German and names from system locale too.} -function GetMonthNumber(Value: String): integer; - -{:Return decoded time from given string. Time must be witch separator ':'. You - can use "hh:mm" or "hh:mm:ss".} -function GetTimeFromStr(Value: string): TDateTime; - -{:Decode string representation of TimeZone (CEST, GMT, +0200, -0800, etc.) - to timezone offset.} -function DecodeTimeZone(Value: string; var Zone: integer): Boolean; - -{:Decode string in format "m-d-y" to TDateTime type.} -function GetDateMDYFromStr(Value: string): TDateTime; - -{:Decode various string representations of date and time to Tdatetime type. - This function do all timezone corrections too! This function can decode lot of - formats like: - @longcode(# - ddd, d mmm yyyy hh:mm:ss - ddd, d mmm yy hh:mm:ss - ddd, mmm d yyyy hh:mm:ss - ddd mmm dd hh:mm:ss yyyy #) - -and more with lot of modifications, include: -@longcode(# -Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 -Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 -Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format -#) -Timezone corrections known lot of symbolic timezone names (like CEST, EDT, etc.) -or numeric representation (like +0200). By convention defined in RFC timezone - +0000 is GMT and -0000 is current your system timezone.} -function DecodeRfcDateTime(Value: string): TDateTime; - -{:Return current system date and time in UTC timezone.} -function GetUTTime: TDateTime; - -{:Set Newdt as current system date and time in UTC timezone. This function work - only if you have administrator rights!} -function SetUTTime(Newdt: TDateTime): Boolean; - -{:Return current value of system timer with precizion 1 millisecond. Good for - measure time difference.} -function GetTick: LongWord; - -{:Return difference between two timestamps. It working fine only for differences - smaller then maxint. (difference must be smaller then 24 days.)} -function TickDelta(TickOld, TickNew: LongWord): LongWord; - -{:Return two characters, which ordinal values represents the value in byte - format. (High-endian)} -function CodeInt(Value: Word): Ansistring; - -{:Decodes two characters located at "Index" offset position of the "Value" - string to Word values.} -function DecodeInt(const Value: Ansistring; Index: Integer): Word; - -{:Return four characters, which ordinal values represents the value in byte - format. (High-endian)} -function CodeLongInt(Value: LongInt): Ansistring; - -{:Decodes four characters located at "Index" offset position of the "Value" - string to LongInt values.} -function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; - -{:Dump binary buffer stored in a string to a result string.} -function DumpStr(const Buffer: Ansistring): string; - -{:Dump binary buffer stored in a string to a result string. All bytes with code - of character is written as character, not as hexadecimal value.} -function DumpExStr(const Buffer: Ansistring): string; - -{:Dump binary buffer stored in a string to a file with DumpFile filename.} -procedure Dump(const Buffer: AnsiString; DumpFile: string); - -{:Dump binary buffer stored in a string to a file with DumpFile filename. All - bytes with code of character is written as character, not as hexadecimal value.} -procedure DumpEx(const Buffer: AnsiString; DumpFile: string); - -{:Like TrimLeft, but remove only spaces, not control characters!} -function TrimSPLeft(const S: string): string; - -{:Like TrimRight, but remove only spaces, not control characters!} -function TrimSPRight(const S: string): string; - -{:Like Trim, but remove only spaces, not control characters!} -function TrimSP(const S: string): string; - -{:Returns a portion of the "Value" string located to the left of the "Delimiter" - string. If a delimiter is not found, results is original string.} -function SeparateLeft(const Value, Delimiter: string): string; - -{:Returns the portion of the "Value" string located to the right of the - "Delimiter" string. If a delimiter is not found, results is original string.} -function SeparateRight(const Value, Delimiter: string): string; - -{:Returns parameter value from string in format: - parameter1="value1"; parameter2=value2} -function GetParameter(const Value, Parameter: string): string; - -{:parse value string with elements differed by Delimiter into stringlist.} -procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); - -{:parse value string with elements differed by ';' into stringlist.} -procedure ParseParameters(Value: string; const Parameters: TStrings); - -{:Index of string in stringlist with same beginning as Value is returned.} -function IndexByBegin(Value: string; const List: TStrings): integer; - -{:Returns only the e-mail portion of an address from the full address format. - i.e. returns 'nobody@@somewhere.com' from '"someone" <nobody@@somewhere.com>'} -function GetEmailAddr(const Value: string): string; - -{:Returns only the description part from a full address format. i.e. returns - 'someone' from '"someone" <nobody@@somewhere.com>'} -function GetEmailDesc(Value: string): string; - -{:Returns a string with hexadecimal digits representing the corresponding values - of the bytes found in "Value" string.} -function StrToHex(const Value: Ansistring): string; - -{:Returns a string of binary "Digits" representing "Value".} -function IntToBin(Value: Integer; Digits: Byte): string; - -{:Returns an integer equivalent of the binary string in "Value". - (i.e. ('10001010') returns 138)} -function BinToInt(const Value: string): Integer; - -{:Parses a URL to its various components.} -function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, - Para: string): string; - -{:Replaces all "Search" string values found within "Value" string, with the - "Replace" string value.} -function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; - -{:It is like RPos, but search is from specified possition.} -function RPosEx(const Sub, Value: string; From: integer): Integer; - -{:It is like POS function, but from right side of Value string.} -function RPos(const Sub, Value: String): Integer; - -{:Like @link(fetch), but working with binary strings, not with text.} -function FetchBin(var Value: string; const Delimiter: string): string; - -{:Fetch string from left of Value string.} -function Fetch(var Value: string; const Delimiter: string): string; - -{:Fetch string from left of Value string. This function ignore delimitesr inside - quotations.} -function FetchEx(var Value: string; const Delimiter, Quotation: string): string; - -{:If string is binary string (contains non-printable characters), then is - returned true.} -function IsBinaryString(const Value: AnsiString): Boolean; - -{:return position of string terminator in string. If terminator found, then is - returned in terminator parameter. - Possible line terminators are: CRLF, LFCR, CR, LF} -function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; - -{:Delete empty strings from end of stringlist.} -Procedure StringsTrim(const value: TStrings); - -{:Like Pos function, buf from given string possition.} -function PosFrom(const SubStr, Value: String; From: integer): integer; - -{$IFNDEF CIL} -{:Increase pointer by value.} -function IncPoint(const p: pointer; Value: integer): pointer; -{$ENDIF} - -{:Get string between PairBegin and PairEnd. This function respect nesting. - For example: - @longcode(# - Value is: 'Hi! (hello(yes!))' - pairbegin is: '(' - pairend is: ')' - In this case result is: 'hello(yes!)'#)} -function GetBetween(const PairBegin, PairEnd, Value: string): string; - -{:Return count of Chr in Value string.} -function CountOfChar(const Value: string; Chr: char): integer; - -{:Remove quotation from Value string. If Value is not quoted, then return same - string without any modification. } -function UnquoteStr(const Value: string; Quote: Char): string; - -{:Quote Value string. If Value contains some Quote chars, then it is doubled.} -function QuoteStr(const Value: string; Quote: Char): string; - -{:Convert lines in stringlist from 'name: value' form to 'name=value' form.} -procedure HeadersToList(const Value: TStrings); - -{:Convert lines in stringlist from 'name=value' form to 'name: value' form.} -procedure ListToHeaders(const Value: TStrings); - -{:swap bytes in integer.} -function SwapBytes(Value: integer): integer; - -{:read string with requested length form stream.} -function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; - -{:write string to stream.} -procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); - -{:Return filename of new temporary file in Dir (if empty, then default temporary - directory is used) and with optional filename prefix.} -function GetTempFile(const Dir, prefix: String): String; - -{:Return padded string. If length is greater, string is truncated. If length is - smaller, string is padded by Pad character.} -function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; - -{:XOR each byte in the strings} -function XorString(Indata1, Indata2: AnsiString): AnsiString; - -{:Read header from "Value" stringlist beginning at "Index" position. If header - is Splitted into multiple lines, then this procedure de-split it into one line.} -function NormalizeHeader(Value: TStrings; var Index: Integer): string; - -{pf} -{:Search for one of line terminators CR, LF or NUL. Return position of the - line beginning and length of text.} -procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); -{:Skip both line terminators CR LF (if any). Move APtr position forward.} -procedure SkipLineBreak(var APtr:PANSIChar; AEtx:PANSIChar); -{:Skip all blank lines in a buffer starting at APtr and move APtr position forward.} -procedure SkipNullLines (var APtr:PANSIChar; AEtx:PANSIChar); -{:Copy all lines from a buffer starting at APtr to ALines until empty line - or end of the buffer is reached. Move APtr position forward).} -procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); -{:Copy all lines from a buffer starting at APtr to ALines until ABoundary - or end of the buffer is reached. Move APtr position forward).} -procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); -{:Search ABoundary in a buffer starting at APtr. - Return beginning of the ABoundary. Move APtr forward behind a trailing CRLF if any).} -function SearchForBoundary (var APtr:PANSIChar; AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; -{:Compare a text at position ABOL with ABoundary and return position behind the - match (including a trailing CRLF if any).} -function MatchBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; -{:Compare a text at position ABOL with ABoundary + the last boundary suffix - and return position behind the match (including a trailing CRLF if any).} -function MatchLastBoundary (ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; -{:Copy data from a buffer starting at position APtr and delimited by AEtx - position into ANSIString.} -function BuildStringFromBuffer (AStx,AEtx:PANSIChar): ANSIString; -{/pf} - -var - {:can be used for your own months strings for @link(getmonthnumber)} - CustomMonthNames: array[1..12] of string; - -implementation - -{==============================================================================} - -const - MyDayNames: array[1..7] of AnsiString = - ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); -var - MyMonthNames: array[0..6, 1..12] of String = - ( - ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //rewrited by system locales - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), - ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //English - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), - ('jan', 'fév', 'mar', 'avr', 'mai', 'jun', //French - 'jul', 'aoû', 'sep', 'oct', 'nov', 'déc'), - ('jan', 'fev', 'mar', 'avr', 'mai', 'jun', //French#2 - 'jul', 'aou', 'sep', 'oct', 'nov', 'dec'), - ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', //German - 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), - ('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', //German#2 - 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'), - ('Led', 'Úno', 'Bøe', 'Dub', 'Kvì', 'Èen', //Czech - 'Èec', 'Srp', 'Záø', 'Øíj', 'Lis', 'Pro') - ); - - -{==============================================================================} - -function TimeZoneBias: integer; -{$IFNDEF MSWINDOWS} -{$IFNDEF FPC} -var -{$IFDEF POSIX} - t: Posix.SysTypes.time_t; - UT: Posix.time.tm; -{$ELSE} - t: TTime_T; - UT: TUnixTime; -{$ENDIF} -begin - {$IFDEF POSIX} - __time(T); - localtime_r(T, UT); - Result := UT.tm_gmtoff div 60; - {$ELSE} - __time(@T); - localtime_r(@T, UT); - Result := ut.__tm_gmtoff div 60; - {$ENDIF} -{$ELSE} -begin - Result := TZSeconds div 60; -{$ENDIF} -{$ELSE} -var - zoneinfo: TTimeZoneInformation; - bias: Integer; -begin - case GetTimeZoneInformation(Zoneinfo) of - 2: - bias := zoneinfo.Bias + zoneinfo.DaylightBias; - 1: - bias := zoneinfo.Bias + zoneinfo.StandardBias; - else - bias := zoneinfo.Bias; - end; - Result := bias * (-1); -{$ENDIF} -end; - -{==============================================================================} - -function TimeZone: string; -var - bias: Integer; - h, m: Integer; -begin - bias := TimeZoneBias; - if bias >= 0 then - Result := '+' - else - Result := '-'; - bias := Abs(bias); - h := bias div 60; - m := bias mod 60; - Result := Result + Format('%.2d%.2d', [h, m]); -end; - -{==============================================================================} - -function Rfc822DateTime(t: TDateTime): string; -var - wYear, wMonth, wDay: word; -begin - DecodeDate(t, wYear, wMonth, wDay); - Result := Format('%s, %d %s %s %s', [MyDayNames[DayOfWeek(t)], wDay, - MyMonthNames[1, wMonth], FormatDateTime('yyyy hh":"nn":"ss', t), TimeZone]); -end; - -{==============================================================================} - -function CDateTime(t: TDateTime): string; -var - wYear, wMonth, wDay: word; -begin - DecodeDate(t, wYear, wMonth, wDay); - Result:= Format('%s %2d %s', [MyMonthNames[1, wMonth], wDay, - FormatDateTime('hh":"nn":"ss', t)]); -end; - -{==============================================================================} - -function SimpleDateTime(t: TDateTime): string; -begin - Result := FormatDateTime('yymmdd hhnnss', t); -end; - -{==============================================================================} - -function AnsiCDateTime(t: TDateTime): string; -var - wYear, wMonth, wDay: word; -begin - DecodeDate(t, wYear, wMonth, wDay); - Result := Format('%s %s %d %s', [MyDayNames[DayOfWeek(t)], MyMonthNames[1, wMonth], - wDay, FormatDateTime('hh":"nn":"ss yyyy ', t)]); -end; - -{==============================================================================} - -function DecodeTimeZone(Value: string; var Zone: integer): Boolean; -var - x: integer; - zh, zm: integer; - s: string; -begin - Result := false; - s := Value; - if (Pos('+', s) = 1) or (Pos('-',s) = 1) then - begin - if s = '-0000' then - Zone := TimeZoneBias - else - if Length(s) > 4 then - begin - zh := StrToIntdef(s[2] + s[3], 0); - zm := StrToIntdef(s[4] + s[5], 0); - zone := zh * 60 + zm; - if s[1] = '-' then - zone := zone * (-1); - end; - Result := True; - end - else - begin - x := 32767; - if s = 'NZDT' then x := 13; - if s = 'IDLE' then x := 12; - if s = 'NZST' then x := 12; - if s = 'NZT' then x := 12; - if s = 'EADT' then x := 11; - if s = 'GST' then x := 10; - if s = 'JST' then x := 9; - if s = 'CCT' then x := 8; - if s = 'WADT' then x := 8; - if s = 'WAST' then x := 7; - if s = 'ZP6' then x := 6; - if s = 'ZP5' then x := 5; - if s = 'ZP4' then x := 4; - if s = 'BT' then x := 3; - if s = 'EET' then x := 2; - if s = 'MEST' then x := 2; - if s = 'MESZ' then x := 2; - if s = 'SST' then x := 2; - if s = 'FST' then x := 2; - if s = 'CEST' then x := 2; - if s = 'CET' then x := 1; - if s = 'FWT' then x := 1; - if s = 'MET' then x := 1; - if s = 'MEWT' then x := 1; - if s = 'SWT' then x := 1; - if s = 'UT' then x := 0; - if s = 'UTC' then x := 0; - if s = 'GMT' then x := 0; - if s = 'WET' then x := 0; - if s = 'WAT' then x := -1; - if s = 'BST' then x := -1; - if s = 'AT' then x := -2; - if s = 'ADT' then x := -3; - if s = 'AST' then x := -4; - if s = 'EDT' then x := -4; - if s = 'EST' then x := -5; - if s = 'CDT' then x := -5; - if s = 'CST' then x := -6; - if s = 'MDT' then x := -6; - if s = 'MST' then x := -7; - if s = 'PDT' then x := -7; - if s = 'PST' then x := -8; - if s = 'YDT' then x := -8; - if s = 'YST' then x := -9; - if s = 'HDT' then x := -9; - if s = 'AHST' then x := -10; - if s = 'CAT' then x := -10; - if s = 'HST' then x := -10; - if s = 'EAST' then x := -10; - if s = 'NT' then x := -11; - if s = 'IDLW' then x := -12; - if x <> 32767 then - begin - zone := x * 60; - Result := True; - end; - end; -end; - -{==============================================================================} - -function GetMonthNumber(Value: String): integer; -var - n: integer; - function TestMonth(Value: String; Index: Integer): Boolean; - var - n: integer; - begin - Result := False; - for n := 0 to 6 do - if Value = AnsiUppercase(MyMonthNames[n, Index]) then - begin - Result := True; - Break; - end; - end; -begin - Result := 0; - Value := AnsiUppercase(Value); - for n := 1 to 12 do - if TestMonth(Value, n) or (Value = AnsiUppercase(CustomMonthNames[n])) then - begin - Result := n; - Break; - end; -end; - -{==============================================================================} - -function GetTimeFromStr(Value: string): TDateTime; -var - x: integer; -begin - x := rpos(':', Value); - if (x > 0) and ((Length(Value) - x) > 2) then - Value := Copy(Value, 1, x + 2); - Value := ReplaceString(Value, ':', {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}TimeSeparator); - Result := -1; - try - Result := StrToTime(Value); - except - on Exception do ; - end; -end; - -{==============================================================================} - -function GetDateMDYFromStr(Value: string): TDateTime; -var - wYear, wMonth, wDay: word; - s: string; -begin - Result := 0; - s := Fetch(Value, '-'); - wMonth := StrToIntDef(s, 12); - s := Fetch(Value, '-'); - wDay := StrToIntDef(s, 30); - wYear := StrToIntDef(Value, 1899); - if wYear < 1000 then - if (wYear > 99) then - wYear := wYear + 1900 - else - if wYear > 50 then - wYear := wYear + 1900 - else - wYear := wYear + 2000; - try - Result := EncodeDate(wYear, wMonth, wDay); - except - on Exception do ; - end; -end; - -{==============================================================================} - -function DecodeRfcDateTime(Value: string): TDateTime; -var - day, month, year: Word; - zone: integer; - x, y: integer; - s: string; - t: TDateTime; -begin -// ddd, d mmm yyyy hh:mm:ss -// ddd, d mmm yy hh:mm:ss -// ddd, mmm d yyyy hh:mm:ss -// ddd mmm dd hh:mm:ss yyyy -// Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 -// Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 -// Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format - - Result := 0; - if Value = '' then - Exit; - day := 0; - month := 0; - year := 0; - zone := 0; - Value := ReplaceString(Value, ' -', ' #'); - Value := ReplaceString(Value, '-', ' '); - Value := ReplaceString(Value, ' #', ' -'); - while Value <> '' do - begin - s := Fetch(Value, ' '); - s := uppercase(s); - // timezone - if DecodetimeZone(s, x) then - begin - zone := x; - continue; - end; - x := StrToIntDef(s, 0); - // day or year - if x > 0 then - if (x < 32) and (day = 0) then - begin - day := x; - continue; - end - else - begin - if (year = 0) and ((month > 0) or (x > 12)) then - begin - year := x; - if year < 32 then - year := year + 2000; - if year < 1000 then - year := year + 1900; - continue; - end; - end; - // time - if rpos(':', s) > Pos(':', s) then - begin - t := GetTimeFromStr(s); - if t <> -1 then - Result := t; - continue; - end; - //timezone daylight saving time - if s = 'DST' then - begin - zone := zone + 60; - continue; - end; - // month - y := GetMonthNumber(s); - if (y > 0) and (month = 0) then - month := y; - end; - if year = 0 then - year := 1980; - if month < 1 then - month := 1; - if month > 12 then - month := 12; - if day < 1 then - day := 1; - x := MonthDays[IsLeapYear(year), month]; - if day > x then - day := x; - Result := Result + Encodedate(year, month, day); - zone := zone - TimeZoneBias; - x := zone div 1440; - Result := Result - x; - zone := zone mod 1440; - t := EncodeTime(Abs(zone) div 60, Abs(zone) mod 60, 0, 0); - if zone < 0 then - t := 0 - t; - Result := Result - t; -end; - -{==============================================================================} - -function GetUTTime: TDateTime; -{$IFDEF MSWINDOWS} -{$IFNDEF FPC} -var - st: TSystemTime; -begin - GetSystemTime(st); - result := SystemTimeToDateTime(st); -{$ELSE} -var - st: SysUtils.TSystemTime; - stw: Windows.TSystemTime; -begin - GetSystemTime(stw); - st.Year := stw.wYear; - st.Month := stw.wMonth; - st.Day := stw.wDay; - st.Hour := stw.wHour; - st.Minute := stw.wMinute; - st.Second := stw.wSecond; - st.Millisecond := stw.wMilliseconds; - result := SystemTimeToDateTime(st); -{$ENDIF} -{$ELSE MSWINDOWS} -{$IFNDEF FPC} -var - TV: TTimeVal; -begin - gettimeofday(TV, nil); - Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; -{$ELSE FPC} - {$IFDEF UNIX} -var - TV: TimeVal; -begin - fpgettimeofday(@TV, nil); - Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400; - {$ELSE UNIX} - {$IFDEF OS2} -var - ST: TSystemTime; -begin - GetLocalTime (ST); - Result := SystemTimeToDateTime (ST); - {$ENDIF OS2} - {$ENDIF UNIX} -{$ENDIF FPC} -{$ENDIF MSWINDOWS} -end; - -{==============================================================================} - -function SetUTTime(Newdt: TDateTime): Boolean; -{$IFDEF MSWINDOWS} -{$IFNDEF FPC} -var - st: TSystemTime; -begin - DateTimeToSystemTime(newdt,st); - Result := SetSystemTime(st); -{$ELSE} -var - st: SysUtils.TSystemTime; - stw: Windows.TSystemTime; -begin - DateTimeToSystemTime(newdt,st); - stw.wYear := st.Year; - stw.wMonth := st.Month; - stw.wDay := st.Day; - stw.wHour := st.Hour; - stw.wMinute := st.Minute; - stw.wSecond := st.Second; - stw.wMilliseconds := st.Millisecond; - Result := SetSystemTime(stw); -{$ENDIF} -{$ELSE MSWINDOWS} -{$IFNDEF FPC} -var - TV: TTimeVal; - d: double; - TZ: Ttimezone; - PZ: PTimeZone; -begin - TZ.tz_minuteswest := 0; - TZ.tz_dsttime := 0; - PZ := @TZ; - gettimeofday(TV, PZ); - d := (newdt - UnixDateDelta) * 86400; - TV.tv_sec := trunc(d); - TV.tv_usec := trunc(frac(d) * 1000000); - {$IFNDEF POSIX} - Result := settimeofday(TV, TZ) <> -1; - {$ELSE} - Result := False; // in POSIX settimeofday is not defined? http://www.kernel.org/doc/man-pages/online/pages/man2/gettimeofday.2.html - {$ENDIF} -{$ELSE FPC} - {$IFDEF UNIX} -var - TV: TimeVal; - d: double; -begin - d := (newdt - UnixDateDelta) * 86400; - TV.tv_sec := trunc(d); - TV.tv_usec := trunc(frac(d) * 1000000); - Result := fpsettimeofday(@TV, nil) <> -1; - {$ELSE UNIX} - {$IFDEF OS2} -var - ST: TSystemTime; -begin - DateTimeToSystemTime (NewDT, ST); - SetTime (ST.Hour, ST.Minute, ST.Second, ST.Millisecond div 10); - Result := true; - {$ENDIF OS2} - {$ENDIF UNIX} -{$ENDIF FPC} -{$ENDIF MSWINDOWS} -end; - -{==============================================================================} - -{$IFNDEF MSWINDOWS} -function GetTick: LongWord; -var - Stamp: TTimeStamp; -begin - Stamp := DateTimeToTimeStamp(Now); - Result := Stamp.Time; -end; -{$ELSE} -function GetTick: LongWord; -var - tick, freq: TLargeInteger; -{$IFDEF VER100} - x: TLargeInteger; -{$ENDIF} -begin - if Windows.QueryPerformanceFrequency(freq) then - begin - Windows.QueryPerformanceCounter(tick); -{$IFDEF VER100} - x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000; - Result := x.LowPart; -{$ELSE} - Result := Trunc((tick / freq) * 1000) and High(LongWord) -{$ENDIF} - end - else - Result := Windows.GetTickCount; -end; -{$ENDIF} - -{==============================================================================} - -function TickDelta(TickOld, TickNew: LongWord): LongWord; -begin -//if DWord is signed type (older Deplhi), -// then it not work properly on differencies larger then maxint! - Result := 0; - if TickOld <> TickNew then - begin - if TickNew < TickOld then - begin - TickNew := TickNew + LongWord(MaxInt) + 1; - TickOld := TickOld + LongWord(MaxInt) + 1; - end; - Result := TickNew - TickOld; - if TickNew < TickOld then - if Result > 0 then - Result := 0 - Result; - end; -end; - -{==============================================================================} - -function CodeInt(Value: Word): Ansistring; -begin - setlength(result, 2); - result[1] := AnsiChar(Value div 256); - result[2] := AnsiChar(Value mod 256); -// Result := AnsiChar(Value div 256) + AnsiChar(Value mod 256) -end; - -{==============================================================================} - -function DecodeInt(const Value: Ansistring; Index: Integer): Word; -var - x, y: Byte; -begin - if Length(Value) > Index then - x := Ord(Value[Index]) - else - x := 0; - if Length(Value) >= (Index + 1) then - y := Ord(Value[Index + 1]) - else - y := 0; - Result := x * 256 + y; -end; - -{==============================================================================} - -function CodeLongInt(Value: Longint): Ansistring; -var - x, y: word; -begin - // this is fix for negative numbers on systems where longint = integer - x := (Value shr 16) and integer($ffff); - y := Value and integer($ffff); - setlength(result, 4); - result[1] := AnsiChar(x div 256); - result[2] := AnsiChar(x mod 256); - result[3] := AnsiChar(y div 256); - result[4] := AnsiChar(y mod 256); -end; - -{==============================================================================} - -function DecodeLongInt(const Value: Ansistring; Index: Integer): LongInt; -var - x, y: Byte; - xl, yl: Byte; -begin - if Length(Value) > Index then - x := Ord(Value[Index]) - else - x := 0; - if Length(Value) >= (Index + 1) then - y := Ord(Value[Index + 1]) - else - y := 0; - if Length(Value) >= (Index + 2) then - xl := Ord(Value[Index + 2]) - else - xl := 0; - if Length(Value) >= (Index + 3) then - yl := Ord(Value[Index + 3]) - else - yl := 0; - Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); -end; - -{==============================================================================} - -function DumpStr(const Buffer: Ansistring): string; -var - n: Integer; -begin - Result := ''; - for n := 1 to Length(Buffer) do - Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); -end; - -{==============================================================================} - -function DumpExStr(const Buffer: Ansistring): string; -var - n: Integer; - x: Byte; -begin - Result := ''; - for n := 1 to Length(Buffer) do - begin - x := Ord(Buffer[n]); - if x in [65..90, 97..122] then - Result := Result + ' +''' + char(x) + '''' - else - Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2); - end; -end; - -{==============================================================================} - -procedure Dump(const Buffer: AnsiString; DumpFile: string); -var - f: Text; -begin - AssignFile(f, DumpFile); - if FileExists(DumpFile) then - DeleteFile(DumpFile); - Rewrite(f); - try - Writeln(f, DumpStr(Buffer)); - finally - CloseFile(f); - end; -end; - -{==============================================================================} - -procedure DumpEx(const Buffer: AnsiString; DumpFile: string); -var - f: Text; -begin - AssignFile(f, DumpFile); - if FileExists(DumpFile) then - DeleteFile(DumpFile); - Rewrite(f); - try - Writeln(f, DumpExStr(Buffer)); - finally - CloseFile(f); - end; -end; - -{==============================================================================} - -function TrimSPLeft(const S: string): string; -var - I, L: Integer; -begin - Result := ''; - if S = '' then - Exit; - L := Length(S); - I := 1; - while (I <= L) and (S[I] = ' ') do - Inc(I); - Result := Copy(S, I, Maxint); -end; - -{==============================================================================} - -function TrimSPRight(const S: string): string; -var - I: Integer; -begin - Result := ''; - if S = '' then - Exit; - I := Length(S); - while (I > 0) and (S[I] = ' ') do - Dec(I); - Result := Copy(S, 1, I); -end; - -{==============================================================================} - -function TrimSP(const S: string): string; -begin - Result := TrimSPLeft(s); - Result := TrimSPRight(Result); -end; - -{==============================================================================} - -function SeparateLeft(const Value, Delimiter: string): string; -var - x: Integer; -begin - x := Pos(Delimiter, Value); - if x < 1 then - Result := Value - else - Result := Copy(Value, 1, x - 1); -end; - -{==============================================================================} - -function SeparateRight(const Value, Delimiter: string): string; -var - x: Integer; -begin - x := Pos(Delimiter, Value); - if x > 0 then - x := x + Length(Delimiter) - 1; - Result := Copy(Value, x + 1, Length(Value) - x); -end; - -{==============================================================================} - -function GetParameter(const Value, Parameter: string): string; -var - s: string; - v: string; -begin - Result := ''; - v := Value; - while v <> '' do - begin - s := Trim(FetchEx(v, ';', '"')); - if Pos(Uppercase(parameter), Uppercase(s)) = 1 then - begin - Delete(s, 1, Length(Parameter)); - s := Trim(s); - if s = '' then - Break; - if s[1] = '=' then - begin - Result := Trim(SeparateRight(s, '=')); - Result := UnquoteStr(Result, '"'); - break; - end; - end; - end; -end; - -{==============================================================================} - -procedure ParseParametersEx(Value, Delimiter: string; const Parameters: TStrings); -var - s: string; -begin - Parameters.Clear; - while Value <> '' do - begin - s := Trim(FetchEx(Value, Delimiter, '"')); - Parameters.Add(s); - end; -end; - -{==============================================================================} - -procedure ParseParameters(Value: string; const Parameters: TStrings); -begin - ParseParametersEx(Value, ';', Parameters); -end; - -{==============================================================================} - -function IndexByBegin(Value: string; const List: TStrings): integer; -var - n: integer; - s: string; -begin - Result := -1; - Value := uppercase(Value); - for n := 0 to List.Count -1 do - begin - s := UpperCase(List[n]); - if Pos(Value, s) = 1 then - begin - Result := n; - Break; - end; - end; -end; - -{==============================================================================} - -function GetEmailAddr(const Value: string): string; -var - s: string; -begin - s := SeparateRight(Value, '<'); - s := SeparateLeft(s, '>'); - Result := Trim(s); -end; - -{==============================================================================} - -function GetEmailDesc(Value: string): string; -var - s: string; -begin - Value := Trim(Value); - s := SeparateRight(Value, '"'); - if s <> Value then - s := SeparateLeft(s, '"') - else - begin - s := SeparateLeft(Value, '<'); - if s = Value then - begin - s := SeparateRight(Value, '('); - if s <> Value then - s := SeparateLeft(s, ')') - else - s := ''; - end; - end; - Result := Trim(s); -end; - -{==============================================================================} - -function StrToHex(const Value: Ansistring): string; -var - n: Integer; -begin - Result := ''; - for n := 1 to Length(Value) do - Result := Result + IntToHex(Byte(Value[n]), 2); - Result := LowerCase(Result); -end; - -{==============================================================================} - -function IntToBin(Value: Integer; Digits: Byte): string; -var - x, y, n: Integer; -begin - Result := ''; - x := Value; - repeat - y := x mod 2; - x := x div 2; - if y > 0 then - Result := '1' + Result - else - Result := '0' + Result; - until x = 0; - x := Length(Result); - for n := x to Digits - 1 do - Result := '0' + Result; -end; - -{==============================================================================} - -function BinToInt(const Value: string): Integer; -var - n: Integer; -begin - Result := 0; - for n := 1 to Length(Value) do - begin - if Value[n] = '0' then - Result := Result * 2 - else - if Value[n] = '1' then - Result := Result * 2 + 1 - else - Break; - end; -end; - -{==============================================================================} - -function ParseURL(URL: string; var Prot, User, Pass, Host, Port, Path, - Para: string): string; -var - x, y: Integer; - sURL: string; - s: string; - s1, s2: string; -begin - Prot := 'http'; - User := ''; - Pass := ''; - Port := '80'; - Para := ''; - - x := Pos('://', URL); - if x > 0 then - begin - Prot := SeparateLeft(URL, '://'); - sURL := SeparateRight(URL, '://'); - end - else - sURL := URL; - if UpperCase(Prot) = 'HTTPS' then - Port := '443'; - if UpperCase(Prot) = 'FTP' then - Port := '21'; - x := Pos('@', sURL); - y := Pos('/', sURL); - if (x > 0) and ((x < y) or (y < 1))then - begin - s := SeparateLeft(sURL, '@'); - sURL := SeparateRight(sURL, '@'); - x := Pos(':', s); - if x > 0 then - begin - User := SeparateLeft(s, ':'); - Pass := SeparateRight(s, ':'); - end - else - User := s; - end; - x := Pos('/', sURL); - if x > 0 then - begin - s1 := SeparateLeft(sURL, '/'); - s2 := SeparateRight(sURL, '/'); - end - else - begin - s1 := sURL; - s2 := ''; - end; - if Pos('[', s1) = 1 then - begin - Host := Separateleft(s1, ']'); - Delete(Host, 1, 1); - s1 := SeparateRight(s1, ']'); - if Pos(':', s1) = 1 then - Port := SeparateRight(s1, ':'); - end - else - begin - x := Pos(':', s1); - if x > 0 then - begin - Host := SeparateLeft(s1, ':'); - Port := SeparateRight(s1, ':'); - end - else - Host := s1; - end; - Result := '/' + s2; - x := Pos('?', s2); - if x > 0 then - begin - Path := '/' + SeparateLeft(s2, '?'); - Para := SeparateRight(s2, '?'); - end - else - Path := '/' + s2; - if Host = '' then - Host := 'localhost'; -end; - -{==============================================================================} - -function ReplaceString(Value, Search, Replace: AnsiString): AnsiString; -var - x, l, ls, lr: Integer; -begin - if (Value = '') or (Search = '') then - begin - Result := Value; - Exit; - end; - ls := Length(Search); - lr := Length(Replace); - Result := ''; - x := Pos(Search, Value); - while x > 0 do - begin - {$IFNDEF CIL} - l := Length(Result); - SetLength(Result, l + x - 1); - Move(Pointer(Value)^, Pointer(@Result[l + 1])^, x - 1); - {$ELSE} - Result:=Result+Copy(Value,1,x-1); - {$ENDIF} - {$IFNDEF CIL} - l := Length(Result); - SetLength(Result, l + lr); - Move(Pointer(Replace)^, Pointer(@Result[l + 1])^, lr); - {$ELSE} - Result:=Result+Replace; - {$ENDIF} - Delete(Value, 1, x - 1 + ls); - x := Pos(Search, Value); - end; - Result := Result + Value; -end; - -{==============================================================================} - -function RPosEx(const Sub, Value: string; From: integer): Integer; -var - n: Integer; - l: Integer; -begin - result := 0; - l := Length(Sub); - for n := From - l + 1 downto 1 do - begin - if Copy(Value, n, l) = Sub then - begin - result := n; - break; - end; - end; -end; - -{==============================================================================} - -function RPos(const Sub, Value: String): Integer; -begin - Result := RPosEx(Sub, Value, Length(Value)); -end; - -{==============================================================================} - -function FetchBin(var Value: string; const Delimiter: string): string; -var - s: string; -begin - Result := SeparateLeft(Value, Delimiter); - s := SeparateRight(Value, Delimiter); - if s = Value then - Value := '' - else - Value := s; -end; - -{==============================================================================} - -function Fetch(var Value: string; const Delimiter: string): string; -begin - Result := FetchBin(Value, Delimiter); - Result := TrimSP(Result); - Value := TrimSP(Value); -end; - -{==============================================================================} - -function FetchEx(var Value: string; const Delimiter, Quotation: string): string; -var - b: Boolean; -begin - Result := ''; - b := False; - while Length(Value) > 0 do - begin - if b then - begin - if Pos(Quotation, Value) = 1 then - b := False; - Result := Result + Value[1]; - Delete(Value, 1, 1); - end - else - begin - if Pos(Delimiter, Value) = 1 then - begin - Delete(Value, 1, Length(delimiter)); - break; - end; - b := Pos(Quotation, Value) = 1; - Result := Result + Value[1]; - Delete(Value, 1, 1); - end; - end; -end; - -{==============================================================================} - -function IsBinaryString(const Value: AnsiString): Boolean; -var - n: integer; -begin - Result := False; - for n := 1 to Length(Value) do - if Value[n] in [#0..#8, #10..#31] then - //ignore null-terminated strings - if not ((n = Length(value)) and (Value[n] = AnsiChar(#0))) then - begin - Result := True; - Break; - end; -end; - -{==============================================================================} - -function PosCRLF(const Value: AnsiString; var Terminator: AnsiString): integer; -var - n, l: integer; -begin - Result := -1; - Terminator := ''; - l := length(value); - for n := 1 to l do - if value[n] in [#$0d, #$0a] then - begin - Result := n; - Terminator := Value[n]; - if n <> l then - case value[n] of - #$0d: - if value[n + 1] = #$0a then - Terminator := #$0d + #$0a; - #$0a: - if value[n + 1] = #$0d then - Terminator := #$0a + #$0d; - end; - Break; - end; -end; - -{==============================================================================} - -Procedure StringsTrim(const Value: TStrings); -var - n: integer; -begin - for n := Value.Count - 1 downto 0 do - if Value[n] = '' then - Value.Delete(n) - else - Break; -end; - -{==============================================================================} - -function PosFrom(const SubStr, Value: String; From: integer): integer; -var - ls,lv: integer; -begin - Result := 0; - ls := Length(SubStr); - lv := Length(Value); - if (ls = 0) or (lv = 0) then - Exit; - if From < 1 then - From := 1; - while (ls + from - 1) <= (lv) do - begin - {$IFNDEF CIL} - if CompareMem(@SubStr[1],@Value[from],ls) then - {$ELSE} - if SubStr = copy(Value, from, ls) then - {$ENDIF} - begin - result := from; - break; - end - else - inc(from); - end; -end; - -{==============================================================================} - -{$IFNDEF CIL} -function IncPoint(const p: pointer; Value: integer): pointer; -begin - Result := PAnsiChar(p) + Value; -end; -{$ENDIF} - -{==============================================================================} -//improved by 'DoggyDawg' -function GetBetween(const PairBegin, PairEnd, Value: string): string; -var - n: integer; - x: integer; - s: string; - lenBegin: integer; - lenEnd: integer; - str: string; - max: integer; -begin - lenBegin := Length(PairBegin); - lenEnd := Length(PairEnd); - n := Length(Value); - if (Value = PairBegin + PairEnd) then - begin - Result := '';//nothing between - exit; - end; - if (n < lenBegin + lenEnd) then - begin - Result := Value; - exit; - end; - s := SeparateRight(Value, PairBegin); - if (s = Value) then - begin - Result := Value; - exit; - end; - n := Pos(PairEnd, s); - if (n = 0) then - begin - Result := Value; - exit; - end; - Result := ''; - x := 1; - max := Length(s) - lenEnd + 1; - for n := 1 to max do - begin - str := copy(s, n, lenEnd); - if (str = PairEnd) then - begin - Dec(x); - if (x <= 0) then - Break; - end; - str := copy(s, n, lenBegin); - if (str = PairBegin) then - Inc(x); - Result := Result + s[n]; - end; -end; - -{==============================================================================} - -function CountOfChar(const Value: string; Chr: char): integer; -var - n: integer; -begin - Result := 0; - for n := 1 to Length(Value) do - if Value[n] = chr then - Inc(Result); -end; - -{==============================================================================} -// ! do not use AnsiExtractQuotedStr, it's very buggy and can crash application! -function UnquoteStr(const Value: string; Quote: Char): string; -var - n: integer; - inq, dq: Boolean; - c, cn: char; -begin - Result := ''; - if Value = '' then - Exit; - if Value = Quote + Quote then - Exit; - inq := False; - dq := False; - for n := 1 to Length(Value) do - begin - c := Value[n]; - if n <> Length(Value) then - cn := Value[n + 1] - else - cn := #0; - if c = quote then - if dq then - dq := False - else - if not inq then - inq := True - else - if cn = quote then - begin - Result := Result + Quote; - dq := True; - end - else - inq := False - else - Result := Result + c; - end; -end; - -{==============================================================================} - -function QuoteStr(const Value: string; Quote: Char): string; -var - n: integer; -begin - Result := ''; - for n := 1 to length(value) do - begin - Result := result + Value[n]; - if value[n] = Quote then - Result := Result + Quote; - end; - Result := Quote + Result + Quote; -end; - -{==============================================================================} - -procedure HeadersToList(const Value: TStrings); -var - n, x, y: integer; - s: string; -begin - for n := 0 to Value.Count -1 do - begin - s := Value[n]; - x := Pos(':', s); - if x > 0 then - begin - y:= Pos('=',s); - if not ((y > 0) and (y < x)) then - begin - s[x] := '='; - Value[n] := s; - end; - end; - end; -end; - -{==============================================================================} - -procedure ListToHeaders(const Value: TStrings); -var - n, x: integer; - s: string; -begin - for n := 0 to Value.Count -1 do - begin - s := Value[n]; - x := Pos('=', s); - if x > 0 then - begin - s[x] := ':'; - Value[n] := s; - end; - end; -end; - -{==============================================================================} - -function SwapBytes(Value: integer): integer; -var - s: AnsiString; - x, y, xl, yl: Byte; -begin - s := CodeLongInt(Value); - x := Ord(s[4]); - y := Ord(s[3]); - xl := Ord(s[2]); - yl := Ord(s[1]); - Result := ((x * 256 + y) * 65536) + (xl * 256 + yl); -end; - -{==============================================================================} - -function ReadStrFromStream(const Stream: TStream; len: integer): AnsiString; -var - x: integer; -{$IFDEF CIL} - buf: Array of Byte; -{$ENDIF} -begin -{$IFDEF CIL} - Setlength(buf, Len); - x := Stream.read(buf, Len); - SetLength(buf, x); - Result := StringOf(Buf); -{$ELSE} - Setlength(Result, Len); - x := Stream.read(PAnsiChar(Result)^, Len); - SetLength(Result, x); -{$ENDIF} -end; - -{==============================================================================} - -procedure WriteStrToStream(const Stream: TStream; Value: AnsiString); -{$IFDEF CIL} -var - buf: Array of Byte; -{$ENDIF} -begin -{$IFDEF CIL} - buf := BytesOf(Value); - Stream.Write(buf,length(Value)); -{$ELSE} - Stream.Write(PAnsiChar(Value)^, Length(Value)); -{$ENDIF} -end; - -{==============================================================================} - -{$IFDEF POSIX} -function tempnam(const Path: PAnsiChar; const Prefix: PAnsiChar): PAnsiChar; cdecl; - external libc name _PU + 'tempnam'; -{$ENDIF} - -function GetTempFile(const Dir, prefix: String): String; -{$IFNDEF FPC} -{$IFDEF MSWINDOWS} -var - Path: String; - x: integer; -{$ENDIF} -{$ENDIF} -begin -{$IFDEF FPC} - Result := GetTempFileName(Dir, Prefix); -{$ELSE} - {$IFNDEF MSWINDOWS} - Result := tempnam(Pointer(Dir), Pointer(prefix)); - {$ELSE} - {$IFDEF CIL} - Result := System.IO.Path.GetTempFileName; - {$ELSE} - if Dir = '' then - begin - SetLength(Path, MAX_PATH); - x := GetTempPath(Length(Path), PChar(Path)); - SetLength(Path, x); - end - else - Path := Dir; - x := Length(Path); - if Path[x] <> '\' then - Path := Path + '\'; - SetLength(Result, MAX_PATH + 1); - GetTempFileName(PChar(Path), PChar(Prefix), 0, PChar(Result)); - Result := PChar(Result); - SetFileattributes(PChar(Result), GetFileAttributes(PChar(Result)) or FILE_ATTRIBUTE_TEMPORARY); - {$ENDIF} - {$ENDIF} -{$ENDIF} -end; - -{==============================================================================} - -function PadString(const Value: AnsiString; len: integer; Pad: AnsiChar): AnsiString; -begin - if length(value) >= len then - Result := Copy(value, 1, len) - else - Result := Value + StringOfChar(Pad, len - length(value)); -end; - -{==============================================================================} - -function XorString(Indata1, Indata2: AnsiString): AnsiString; -var - i: integer; -begin - Indata2 := PadString(Indata2, length(Indata1), #0); - Result := ''; - for i := 1 to length(Indata1) do - Result := Result + AnsiChar(ord(Indata1[i]) xor ord(Indata2[i])); -end; - -{==============================================================================} - -function NormalizeHeader(Value: TStrings; var Index: Integer): string; -var - s, t: string; - n: Integer; -begin - s := Value[Index]; - Inc(Index); - if s <> '' then - while (Value.Count - 1) > Index do - begin - t := Value[Index]; - if t = '' then - Break; - for n := 1 to Length(t) do - if t[n] = #9 then - t[n] := ' '; - if not(AnsiChar(t[1]) in [' ', '"', ':', '=']) then - Break - else - begin - s := s + ' ' + Trim(t); - Inc(Index); - end; - end; - Result := TrimRight(s); -end; - -{==============================================================================} - -{pf} -procedure SearchForLineBreak(var APtr:PANSIChar; AEtx:PANSIChar; out ABol:PANSIChar; out ALength:integer); -begin - ABol := APtr; - while (APtr<AEtx) and not (APtr^ in [#0,#10,#13]) do - inc(APtr); - ALength := APtr-ABol; -end; -{/pf} - -{pf} -procedure SkipLineBreak(var APtr:PANSIChar; AEtx:PANSIChar); -begin - if (APtr<AEtx) and (APtr^=#13) then - inc(APtr); - if (APtr<AEtx) and (APtr^=#10) then - inc(APtr); -end; -{/pf} - -{pf} -procedure SkipNullLines(var APtr:PANSIChar; AEtx:PANSIChar); -var - bol: PANSIChar; - lng: integer; -begin - while (APtr<AEtx) do - begin - SearchForLineBreak(APtr,AEtx,bol,lng); - SkipLineBreak(APtr,AEtx); - if lng>0 then - begin - APtr := bol; - Break; - end; - end; -end; -{/pf} - -{pf} -procedure CopyLinesFromStreamUntilNullLine(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings); -var - bol: PANSIChar; - lng: integer; - s: ANSIString; -begin - // Copying until body separator will be reached - while (APtr<AEtx) and (APtr^<>#0) do - begin - SearchForLineBreak(APtr,AEtx,bol,lng); - SkipLineBreak(APtr,AEtx); - if lng=0 then - Break; - SetString(s,bol,lng); - ALines.Add(s); - end; -end; -{/pf} - -{pf} -procedure CopyLinesFromStreamUntilBoundary(var APtr:PANSIChar; AEtx:PANSIChar; ALines:TStrings; const ABoundary:ANSIString); -var - bol: PANSIChar; - lng: integer; - s: ANSIString; - BackStop: ANSIString; - eob1: PANSIChar; - eob2: PANSIChar; -begin - BackStop := '--'+ABoundary; - eob2 := nil; - // Copying until Boundary will be reached - while (APtr<AEtx) do - begin - SearchForLineBreak(APtr,AEtx,bol,lng); - SkipLineBreak(APtr,AEtx); - eob1 := MatchBoundary(bol,APtr,ABoundary); - if Assigned(eob1) then - eob2 := MatchLastBoundary(bol,AEtx,ABoundary); - if Assigned(eob2) then - begin - APtr := eob2; - Break; - end - else if Assigned(eob1) then - begin - APtr := eob1; - Break; - end - else - begin - SetString(s,bol,lng); - ALines.Add(s); - end; - end; -end; -{/pf} - -{pf} -function SearchForBoundary(var APtr:PANSIChar; AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; -var - eob: PANSIChar; - Step: integer; -begin - Result := nil; - // Moving Aptr position forward until boundary will be reached - while (APtr<AEtx) do - begin - if strlcomp(APtr,#13#10'--',4)=0 then - begin - eob := MatchBoundary(APtr,AEtx,ABoundary); - Step := 4; - end - else if strlcomp(APtr,'--',2)=0 then - begin - eob := MatchBoundary(APtr,AEtx,ABoundary); - Step := 2; - end - else - begin - eob := nil; - Step := 1; - end; - if Assigned(eob) then - begin - Result := APtr; // boundary beginning - APtr := eob; // boundary end - exit; - end - else - inc(APtr,Step); - end; -end; -{/pf} - -{pf} -function MatchBoundary(ABol,AEtx:PANSIChar; const ABoundary:ANSIString): PANSIChar; -var - MatchPos: PANSIChar; - Lng: integer; -begin - Result := nil; - MatchPos := ABol; - Lng := length(ABoundary); - if (MatchPos+2+Lng)>AETX then - exit; - if strlcomp(MatchPos,#13#10,2)=0 then - inc(MatchPos,2); - if (MatchPos+2+Lng)>AETX then - exit; - if strlcomp(MatchPos,'--',2)<>0 then - exit; - inc(MatchPos,2); - if strlcomp(MatchPos,PANSIChar(ABoundary),Lng)<>0 then - exit; - inc(MatchPos,Lng); - if ((MatchPos+2)<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then - inc(MatchPos,2); - Result := MatchPos; -end; -{/pf} - -{pf} -function MatchLastBoundary(ABOL,AETX:PANSIChar; const ABoundary:ANSIString): PANSIChar; -var - MatchPos: PANSIChar; -begin - Result := nil; - MatchPos := MatchBoundary(ABOL,AETX,ABoundary); - if not Assigned(MatchPos) then - exit; - if strlcomp(MatchPos,'--',2)<>0 then - exit; - inc(MatchPos,2); - if (MatchPos+2<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then - inc(MatchPos,2); - Result := MatchPos; -end; -{/pf} - -{pf} -function BuildStringFromBuffer(AStx,AEtx:PANSIChar): ANSIString; -var - lng: integer; -begin - Lng := 0; - if Assigned(AStx) and Assigned(AEtx) then - begin - Lng := AEtx-AStx; - if Lng<0 then - Lng := 0; - end; - SetString(Result,AStx,lng); -end; -{/pf} - - - - -{==============================================================================} -var - n: integer; -begin - for n := 1 to 12 do - begin - CustomMonthNames[n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n]; - MyMonthNames[0, n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n]; - end; -end. diff --git a/3rd/synapse/source/synsock.pas b/3rd/synapse/source/synsock.pas deleted file mode 100644 index 640115eac..000000000 --- a/3rd/synapse/source/synsock.pas +++ /dev/null @@ -1,86 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 005.002.003 | -|==============================================================================| -| Content: Socket Independent Platform Layer | -|==============================================================================| -| Copyright (c)1999-2013, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2001-2013. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -| Tomas Hajny (OS2 support) | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@exclude} - -unit synsock; - -{$MINENUMSIZE 4} - -//old Delphi does not have MSWINDOWS define. -{$IFDEF WIN32} - {$IFNDEF MSWINDOWS} - {$DEFINE MSWINDOWS} - {$ENDIF} -{$ENDIF} - -{$IFDEF CIL} - {$I ssdotnet.inc} -{$ELSE} - {$IFDEF MSWINDOWS} - {$I sswin32.inc} - {$ELSE} - {$IFDEF WINCE} - {$I sswin32.inc} //not complete yet! - {$ELSE} - {$IFDEF FPC} - {$IFDEF OS2} - {$I ssos2ws1.inc} - {$ELSE OS2} - {$I ssfpc.inc} - {$ENDIF OS2} - {$ELSE} - {$I sslinux.inc} - {$ENDIF} - {$ENDIF} - {$ENDIF} -{$ENDIF} -{$IFDEF POSIX} -//Posix.SysSocket - {$I ssposix.inc} //experimental! -{$ENDIF} - -end. - diff --git a/3rd/synapse/source/tlntsend.pas b/3rd/synapse/source/tlntsend.pas deleted file mode 100644 index 1cac10f98..000000000 --- a/3rd/synapse/source/tlntsend.pas +++ /dev/null @@ -1,364 +0,0 @@ -{==============================================================================| -| Project : Ararat Synapse | 001.003.001 | -|==============================================================================| -| Content: TELNET and SSH2 client | -|==============================================================================| -| Copyright (c)1999-2010, Lukas Gebauer | -| All rights reserved. | -| | -| Redistribution and use in source and binary forms, with or without | -| modification, are permitted provided that the following conditions are met: | -| | -| Redistributions of source code must retain the above copyright notice, this | -| list of conditions and the following disclaimer. | -| | -| Redistributions in binary form must reproduce the above copyright notice, | -| this list of conditions and the following disclaimer in the documentation | -| and/or other materials provided with the distribution. | -| | -| Neither the name of Lukas Gebauer nor the names of its contributors may | -| be used to endorse or promote products derived from this software without | -| specific prior written permission. | -| | -| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | -| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | -| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | -| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR | -| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | -| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | -| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | -| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | -| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | -| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | -| DAMAGE. | -|==============================================================================| -| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).| -| Portions created by Lukas Gebauer are Copyright (c)2002-2010. | -| All Rights Reserved. | -|==============================================================================| -| Contributor(s): | -|==============================================================================| -| History: see HISTORY.HTM from distribution package | -| (Found at URL: http://www.ararat.cz/synapse/) | -|==============================================================================} - -{:@abstract(Telnet script client) - -Used RFC: RFC-854 -} - -{$IFDEF FPC} - {$MODE DELPHI} -{$ENDIF} -{$H+} - -{$IFDEF UNICODE} - {$WARN IMPLICIT_STRING_CAST OFF} - {$WARN IMPLICIT_STRING_CAST_LOSS OFF} -{$ENDIF} - -unit tlntsend; - -interface - -uses - SysUtils, Classes, - blcksock, synautil; - -const - cTelnetProtocol = '23'; - cSSHProtocol = '22'; - - TLNT_EOR = #239; - TLNT_SE = #240; - TLNT_NOP = #241; - TLNT_DATA_MARK = #242; - TLNT_BREAK = #243; - TLNT_IP = #244; - TLNT_AO = #245; - TLNT_AYT = #246; - TLNT_EC = #247; - TLNT_EL = #248; - TLNT_GA = #249; - TLNT_SB = #250; - TLNT_WILL = #251; - TLNT_WONT = #252; - TLNT_DO = #253; - TLNT_DONT = #254; - TLNT_IAC = #255; - -type - {:@abstract(State of telnet protocol). Used internaly by TTelnetSend.} - TTelnetState =(tsDATA, tsIAC, tsIAC_SB, tsIAC_WILL, tsIAC_DO, tsIAC_WONT, - tsIAC_DONT, tsIAC_SBIAC, tsIAC_SBDATA, tsSBDATA_IAC); - - {:@abstract(Class with implementation of Telnet/SSH script client.) - - Note: Are you missing properties for specify server address and port? Look to - parent @link(TSynaClient) too!} - TTelnetSend = class(TSynaClient) - private - FSock: TTCPBlockSocket; - FBuffer: Ansistring; - FState: TTelnetState; - FSessionLog: Ansistring; - FSubNeg: Ansistring; - FSubType: Ansichar; - FTermType: Ansistring; - function Connect: Boolean; - function Negotiate(const Buf: Ansistring): Ansistring; - procedure FilterHook(Sender: TObject; var Value: AnsiString); - public - constructor Create; - destructor Destroy; override; - - {:Connects to Telnet server.} - function Login: Boolean; - - {:Connects to SSH2 server and login by Username and Password properties. - - You must use some of SSL plugins with SSH support. For exammple CryptLib.} - function SSHLogin: Boolean; - - {:Logout from telnet server.} - procedure Logout; - - {:Send this data to telnet server.} - procedure Send(const Value: string); - - {:Reading data from telnet server until Value is readed. If it is not readed - until timeout, result is @false. Otherwise result is @true.} - function WaitFor(const Value: string): Boolean; - - {:Read data terminated by terminator from telnet server.} - function RecvTerminated(const Terminator: string): string; - - {:Read string from telnet server.} - function RecvString: string; - published - {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.} - property Sock: TTCPBlockSocket read FSock; - - {:all readed datas in this session (from connect) is stored in this large - string.} - property SessionLog: Ansistring read FSessionLog write FSessionLog; - - {:Terminal type indentification. By default is 'SYNAPSE'.} - property TermType: Ansistring read FTermType write FTermType; - end; - -implementation - -constructor TTelnetSend.Create; -begin - inherited Create; - FSock := TTCPBlockSocket.Create; - FSock.Owner := self; - FSock.OnReadFilter := FilterHook; - FTimeout := 60000; - FTargetPort := cTelnetProtocol; - FSubNeg := ''; - FSubType := #0; - FTermType := 'SYNAPSE'; -end; - -destructor TTelnetSend.Destroy; -begin - FSock.Free; - inherited Destroy; -end; - -function TTelnetSend.Connect: Boolean; -begin - // Do not call this function! It is calling by LOGIN method! - FBuffer := ''; - FSessionLog := ''; - FState := tsDATA; - FSock.CloseSocket; - FSock.LineBuffer := ''; - FSock.Bind(FIPInterface, cAnyPort); - FSock.Connect(FTargetHost, FTargetPort); - Result := FSock.LastError = 0; -end; - -function TTelnetSend.RecvTerminated(const Terminator: string): string; -begin - Result := FSock.RecvTerminated(FTimeout, Terminator); -end; - -function TTelnetSend.RecvString: string; -begin - Result := FSock.RecvTerminated(FTimeout, CRLF); -end; - -function TTelnetSend.WaitFor(const Value: string): Boolean; -begin - Result := FSock.RecvTerminated(FTimeout, Value) <> ''; -end; - -procedure TTelnetSend.FilterHook(Sender: TObject; var Value: AnsiString); -begin - Value := Negotiate(Value); - FSessionLog := FSessionLog + Value; -end; - -function TTelnetSend.Negotiate(const Buf: Ansistring): Ansistring; -var - n: integer; - c: Ansichar; - Reply: Ansistring; - SubReply: Ansistring; -begin - Result := ''; - for n := 1 to Length(Buf) do - begin - c := Buf[n]; - Reply := ''; - case FState of - tsData: - if c = TLNT_IAC then - FState := tsIAC - else - Result := Result + c; - - tsIAC: - case c of - TLNT_IAC: - begin - FState := tsData; - Result := Result + TLNT_IAC; - end; - TLNT_WILL: - FState := tsIAC_WILL; - TLNT_WONT: - FState := tsIAC_WONT; - TLNT_DONT: - FState := tsIAC_DONT; - TLNT_DO: - FState := tsIAC_DO; - TLNT_EOR: - FState := tsDATA; - TLNT_SB: - begin - FState := tsIAC_SB; - FSubType := #0; - FSubNeg := ''; - end; - else - FState := tsData; - end; - - tsIAC_WILL: - begin - case c of - #3: //suppress GA - Reply := TLNT_DO; - else - Reply := TLNT_DONT; - end; - FState := tsData; - end; - - tsIAC_WONT: - begin - Reply := TLNT_DONT; - FState := tsData; - end; - - tsIAC_DO: - begin - case c of - #24: //termtype - Reply := TLNT_WILL; - else - Reply := TLNT_WONT; - end; - FState := tsData; - end; - - tsIAC_DONT: - begin - Reply := TLNT_WONT; - FState := tsData; - end; - - tsIAC_SB: - begin - FSubType := c; - FState := tsIAC_SBDATA; - end; - - tsIAC_SBDATA: - begin - if c = TLNT_IAC then - FState := tsSBDATA_IAC - else - FSubNeg := FSubNeg + c; - end; - - tsSBDATA_IAC: - case c of - TLNT_IAC: - begin - FState := tsIAC_SBDATA; - FSubNeg := FSubNeg + c; - end; - TLNT_SE: - begin - SubReply := ''; - case FSubType of - #24: //termtype - begin - if (FSubNeg <> '') and (FSubNeg[1] = #1) then - SubReply := #0 + FTermType; - end; - end; - Sock.SendString(TLNT_IAC + TLNT_SB + FSubType + SubReply + TLNT_IAC + TLNT_SE); - FState := tsDATA; - end; - else - FState := tsDATA; - end; - - else - FState := tsData; - end; - if Reply <> '' then - Sock.SendString(TLNT_IAC + Reply + c); - end; - -end; - -procedure TTelnetSend.Send(const Value: string); -begin - Sock.SendString(ReplaceString(Value, TLNT_IAC, TLNT_IAC + TLNT_IAC)); -end; - -function TTelnetSend.Login: Boolean; -begin - Result := False; - if not Connect then - Exit; - Result := True; -end; - -function TTelnetSend.SSHLogin: Boolean; -begin - Result := False; - if Connect then - begin - FSock.SSL.SSLType := LT_SSHv2; - FSock.SSL.Username := FUsername; - FSock.SSL.Password := FPassword; - FSock.SSLDoConnect; - Result := FSock.LastError = 0; - end; -end; - -procedure TTelnetSend.Logout; -begin - FSock.CloseSocket; -end; - - -end. diff --git a/3rd/synapse/source/tzutil.pas b/3rd/synapse/source/tzutil.pas deleted file mode 100644 index 782402847..000000000 --- a/3rd/synapse/source/tzutil.pas +++ /dev/null @@ -1,702 +0,0 @@ -//Unit with timezone support for some Freepascal platforms. -//Tomas Hajny - -unit tzutil; - - -interface - -type - DSTSpecType = (DSTMonthWeekDay, DSTMonthDay, DSTJulian, DSTJulianX); - -(* Initialized to default values *) -const - TZName: string = ''; - TZDSTName: string = ''; - TZOffset: longint = 0; - DSTOffset: longint = 0; - DSTStartMonth: byte = 4; - DSTStartWeek: shortint = 1; - DSTStartDay: word = 0; - DSTStartSec: cardinal = 7200; - DSTEndMonth: byte = 10; - DSTEndWeek: shortint = -1; - DSTEndDay: word = 0; - DSTEndSec: cardinal = 10800; - DSTStartSpecType: DSTSpecType = DSTMonthWeekDay; - DSTEndSpecType: DSTSpecType = DSTMonthWeekDay; - -function TZSeconds: longint; -(* Return current offset from UTC in seconds while respecting DST *) - -implementation - -uses - Dos; - -function TZSeconds: longint; -const - MonthDays: array [1..12] of byte = - (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); - MonthEnds: array [1..12] of word = - (31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365); -var - Y, Mo, D, WD, H, Mi, S, S100: word; - MS, DS, ME, DE: byte; - L: longint; - Second: cardinal; - AfterDSTStart, BeforeDSTEnd: boolean; - -function LeapDay: byte; -begin - if (Y mod 400 = 0) or (Y mod 100 <> 0) and (Y mod 4 = 0) then - LeapDay := 1 - else - LeapDay := 0; -end; - -function FirstDay (MM: byte): byte; -(* What day of week (0-6) is the first day of month MM? *) -var - DD: longint; -begin - if MM < Mo then - begin - DD := D + MonthEnds [Pred (Mo)]; - if MM > 1 then - Dec (DD, MonthEnds [Pred (MM)]); - if (MM <= 2) and (Mo > 2) then - Inc (DD, LeapDay); - end - else - if MM > Mo then - begin - DD := - MonthDays [Mo] + D - MonthEnds [Pred (MM)] + MonthEnds [Mo]; - if (Mo <= 2) and (MM > 2) then - Dec (DD, LeapDay); - end - else -(* M = MM *) - DD := D; - DD := WD - DD mod 7 + 1; - if DD < 0 then - FirstDay := DD + 7 - else - FirstDay := DD mod 7; -end; - -begin - TZSeconds := TZOffset; - if DSTOffset <> TZOffset then - begin - GetDate (Y, Mo, D, WD); - GetTime (H, Mi, S, S100); - Second := cardinal (H) * 3600 + Mi * 60 + S; - - if (DSTStartSpecType = DSTMonthWeekDay) or (DSTStartSpecType = DSTMonthDay) - then - begin - MS := DSTStartMonth; - if DSTStartSpecType = DSTMonthDay then - DS := DSTStartDay - else - begin - DS := FirstDay (DSTStartMonth); - if (DSTStartWeek >= 1) and (DSTStartWeek <= 4) then - if DSTStartDay < DS then - DS := DSTStartWeek * 7 + DSTStartDay - DS + 1 - else - DS := Pred (DSTStartWeek) * 7 + DSTStartDay - DS + 1 - else -(* Last week in month *) - begin - DS := DS + MonthDays [MS] - 1; - if MS = 2 then - Inc (DS, LeapDay); - DS := DS mod 7; - if DS < DSTStartDay then - DS := DS + 7 - DSTStartDay - else - DS := DS - DSTStartDay; - DS := MonthDays [MS] - DS; - end; - end; - end - else - begin -(* Julian day *) - L := DSTStartDay; - if (DSTStartSpecType = DSTJulian) then -(* 0-based *) - if (L + LeapDay <= 59) then - Inc (L) - else - L := L + 1 - LeapDay; - if L <= 31 then - begin - MS := 1; - DS := L; - end - else - if (L <= 59) or - (DSTStartSpecType = DSTJulian) and (L - LeapDay <= 59) then - begin - MS := 2; - DS := DSTStartDay - 31; - end - else - begin - MS := 3; - while (MS < 12) and (MonthEnds [MS] > L) do - Inc (MS); - DS := L - MonthEnds [Pred (MS)]; - end; - end; - - if (DSTEndSpecType = DSTMonthWeekDay) or (DSTEndSpecType = DSTMonthDay) then - begin - ME := DSTEndMonth; - if DSTEndSpecType = DSTMonthDay then - DE := DSTEndDay - else - begin - DE := FirstDay (DSTEndMonth); - if (DSTEndWeek >= 1) and (DSTEndWeek <= 4) then - if DSTEndDay < DE then - DE := DSTEndWeek * 7 + DSTEndDay - DE + 1 - else - DE := Pred (DSTEndWeek) * 7 + DSTEndDay - DE + 1 - else -(* Last week in month *) - begin - DE := DE + MonthDays [ME] - 1; - if ME = 2 then - Inc (DE, LeapDay); - DE := DE mod 7; - if DE < DSTEndDay then - DE := DE + 7 - DSTEndDay - else - DE := DE - DSTEndDay; - DE := MonthDays [ME] - DE; - end; - end; - end - else - begin -(* Julian day *) - L := DSTEndDay; - if (DSTEndSpecType = DSTJulian) then -(* 0-based *) - if (L + LeapDay <= 59) then - Inc (L) - else - L := L + 1 - LeapDay; - if L <= 31 then - begin - ME := 1; - DE := L; - end - else - if (L <= 59) or - (DSTEndSpecType = DSTJulian) and (L - LeapDay <= 59) then - begin - ME := 2; - DE := DSTEndDay - 31; - end - else - begin - ME := 3; - while (ME < 12) and (MonthEnds [ME] > L) do - Inc (ME); - DE := L - MonthEnds [Pred (ME)]; - end; - end; - - if Mo < MS then - AfterDSTStart := false - else - if Mo > MS then - AfterDSTStart := true - else - if D < DS then - AfterDSTStart := false - else - if D > DS then - AfterDSTStart := true - else - AfterDSTStart := Second > DSTStartSec; - if Mo > ME then - BeforeDSTEnd := false - else - if Mo < ME then - BeforeDSTEnd := true - else - if D > DE then - BeforeDSTEnd := false - else - if D < DE then - BeforeDSTEnd := true - else - BeforeDSTEnd := Second < DSTEndSec; - if AfterDSTStart and BeforeDSTEnd then - TZSeconds := DSTOffset; - end; -end; - -procedure InitTZ; -const - TZEnvName = 'TZ'; - EMXTZEnvName = 'EMXTZ'; -var - TZ, S: string; - I, J: byte; - Err: longint; - GnuFmt: boolean; - ADSTStartMonth: byte; - ADSTStartWeek: shortint; - ADSTStartDay: word; - ADSTStartSec: cardinal; - ADSTEndMonth: byte; - ADSTEndWeek: shortint; - ADSTEndDay: word; - ADSTEndSec: cardinal; - ADSTStartSpecType: DSTSpecType; - ADSTEndSpecType: DSTSpecType; - ADSTChangeSec: cardinal; - - function ParseOffset (OffStr: string): longint; - (* Parse time offset given as [-|+]HH[:MI[:SS]] and return in seconds *) - var - TZShiftHH, TZShiftDir: shortint; - TZShiftMI, TZShiftSS: byte; - N1, N2: byte; - begin - TZShiftHH := 0; - TZShiftMI := 0; - TZShiftSS := 0; - TZShiftDir := 1; - N1 := 1; - while (N1 <= Length (OffStr)) and (OffStr [N1] <> ':') do - Inc (N1); - Val (Copy (OffStr, 1, Pred (N1)), TZShiftHH, Err); - if (Err = 0) and (TZShiftHH >= -24) and (TZShiftHH <= 23) then - begin -(* Normalize the hour offset to -12..11 if necessary *) - if TZShiftHH > 11 then - Dec (TZShiftHH, 24) else - if TZShiftHH < -12 then - Inc (TZShiftHH, 24); - if TZShiftHH < 0 then - TZShiftDir := -1; - if (N1 <= Length (OffStr)) then - begin - N2 := Succ (N1); - while (N2 <= Length (OffStr)) and (OffStr [N2] <> ':') do - Inc (N2); - Val (Copy (OffStr, Succ (N1), N2 - N1), TZShiftMI, Err); - if (Err = 0) and (TZShiftMI <= 59) then - begin - if (N2 <= Length (OffStr)) then - begin - Val (Copy (OffStr, Succ (N2), Length (OffStr) - N2), TZShiftSS, Err); - if (Err <> 0) or (TZShiftSS > 59) then - TZShiftSS := 0; - end - end - else - TZShiftMI := 0; - end; - end - else - TZShiftHH := 0; - ParseOffset := longint (TZShiftHH) * 3600 + - TZShiftDir * (longint (TZShiftMI) * 60 + TZShiftSS); - end; - -begin - TZ := GetEnv (TZEnvName); - if TZ = '' then - TZ := GetEnv (EMXTZEnvName); - if TZ <> '' then - begin - TZ := Upcase (TZ); -(* Timezone name *) - I := 1; - while (I <= Length (TZ)) and (TZ [I] in ['A'..'Z']) do - Inc (I); - TZName := Copy (TZ, 1, Pred (I)); - if I <= Length (TZ) then - begin -(* Timezone shift *) - J := Succ (I); - while (J <= Length (TZ)) and not (TZ [J] in ['A'..'Z']) do - Inc (J); - TZOffset := ParseOffset (Copy (TZ, I, J - I)); -(* DST timezone name *) - I := J; - while (J <= Length (TZ)) and (TZ [J] in ['A'..'Z']) do - Inc (J); - if J > I then - begin - TZDSTName := Copy (TZ, I, J - I); -(* DST timezone name provided; if equal to the standard timezone *) -(* name then DSTOffset is set to be equal to TZOffset by default, *) -(* otherwise it is set to TZOffset - 3600 seconds. *) - if TZDSTName <> TZName then - DSTOffset := -3600 + TZOffset - else - DSTOffset := TZOffset; - end - else - begin - TZDSTName := TZName; -(* No DST timezone name provided => DSTOffset is equal to TZOffset *) - DSTOffset := TZOffset; - end; - if J <= Length (TZ) then - begin -(* Check if DST offset is specified here; *) -(* if not, default value set above is used. *) - if TZ [J] <> ',' then - begin - I := J; - Inc (J); - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - DSTOffset := ParseOffset (Copy (TZ, I, J - I)); - end; - if J < Length (TZ) then - begin - Inc (J); -(* DST switching details *) - case TZ [J] of - 'M': - begin -(* Mmonth.week.dayofweek[/StartHour] *) - ADSTStartSpecType := DSTMonthWeekDay; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTStartMonth, Err); - if (Err > 0) or (ADSTStartMonth > 12) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTStartWeek, Err); - if (Err > 0) or (ADSTStartWeek < 1) or (ADSTStartWeek > 5) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay < 0) or (ADSTStartDay > 6) - or (J >= Length (TZ)) then - Exit; - if TZ [J] = '/' then - begin - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) - then - Exit - else - ADSTStartSec := ADSTStartSec * 3600; - end - else - (* Use the preset default *) - ADSTStartSec := DSTStartSec; - Inc (J); - end; - 'J': - begin -(* Jjulianday[/StartHour] *) - ADSTStartSpecType := DSTJulianX; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in [',', '/']) do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay = 0) or (ADSTStartDay > 365) - or (J >= Length (TZ)) then - Exit; - if TZ [J] = '/' then - begin - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) - then - Exit - else - ADSTStartSec := ADSTStartSec * 3600; - end - else - (* Use the preset default *) - ADSTStartSec := DSTStartSec; - Inc (J); - end - else - begin -(* Check the used format first - GNU libc / GCC / EMX expect *) -(* "NameOffsetDstname[Dstoffset],Start[/StartHour],End[/EndHour]"; *) -(* if more than one comma (',') is found, the following format is assumed: *) -(* "NameOffsetDstname[Dstoffset],StartMonth,StartWeek,StartDay,StartSecond, *) -(* EndMonth,EndWeek,EndDay,EndSecond,DSTDifference". *) - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - S := Copy (TZ, I, J - I); - if J < Length (TZ) then - begin - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - GnuFmt := J > Length (TZ); - end - else - Exit; - if GnuFmt then - begin - ADSTStartSpecType := DSTJulian; - J := Pos ('/', S); - if J = 0 then - begin - Val (S, ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay > 365) then - Exit; - (* Use the preset default *) - ADSTStartSec := DSTStartSec; - end - else - begin - if J = Length (S) then - Exit; - Val (Copy (S, 1, Pred (J)), ADSTStartDay, Err); - if (Err > 0) or (ADSTStartDay > 365) then - Exit; - Val (Copy (S, Succ (J), Length (S) - J), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) then - Exit - else - ADSTStartSec := ADSTStartSec * 3600; - end; - J := I; - end - else - begin - Val (S, ADSTStartMonth, Err); - if (Err > 0) or (ADSTStartMonth > 12) then - Exit; - Val (Copy (TZ, I, J - I), ADSTStartWeek, Err); - if (Err > 0) or (ADSTStartWeek < -1) or (ADSTStartWeek > 5) or - (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartDay, Err); - if (DSTStartWeek = 0) then - begin - if (Err > 0) or (ADSTStartDay < 1) or (ADSTStartDay > 31) - or (ADSTStartDay > 30) and (ADSTStartMonth in [4, 6, 9, 11]) - or (ADSTStartMonth = 2) and (ADSTStartDay > 29) then - Exit; - ADSTStartSpecType := DSTMonthDay; - end - else - begin - if (Err > 0) or (ADSTStartDay < 0) or (ADSTStartDay > 6) then - Exit; - ADSTStartSpecType := DSTMonthWeekDay; - end; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTStartSec, Err); - if (Err > 0) or (ADSTStartSec > 86399) or (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndMonth, Err); - if (Err > 0) or (ADSTEndMonth > 12) or (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndWeek, Err); - if (Err > 0) or (ADSTEndWeek < -1) or (ADSTEndWeek > 5) - or (J >= Length (TZ)) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndDay, Err); - if (DSTEndWeek = 0) then - begin - if (Err > 0) or (ADSTEndDay < 1) or (ADSTEndDay > 31) - or (ADSTEndDay > 30) and (ADSTEndMonth in [4, 6, 9, 11]) - or (ADSTEndMonth = 2) and (ADSTEndDay > 29) then - Exit; - ADSTEndSpecType := DSTMonthDay; - end - else - begin - if (Err > 0) or (ADSTEndDay < 0) or (ADSTEndDay > 6) then - Exit; - ADSTEndSpecType := DSTMonthWeekDay; - end; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> ',') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndSec, Err); - if (Err > 0) or (ADSTEndSec > 86399) or (J >= Length (TZ)) then - Exit; - Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTChangeSec, Err); - if (Err = 0) and (ADSTChangeSec < 86400) then - begin -(* Format complete, all checks successful => accept the parsed values. *) - DSTStartMonth := ADSTStartMonth; - DSTStartWeek := ADSTStartWeek; - DSTStartDay := ADSTStartDay; - DSTStartSec := ADSTStartSec; - DSTEndMonth := ADSTEndMonth; - DSTEndWeek := ADSTEndWeek; - DSTEndDay := ADSTEndDay; - DSTEndSec := ADSTEndSec; - DSTStartSpecType := ADSTStartSpecType; - DSTEndSpecType := ADSTEndSpecType; - DSTOffset := TZOffset - ADSTChangeSec; - end; -(* Parsing finished *) - Exit; - end; - end; - end; -(* GnuFmt - DST end specification *) - if TZ [J] = 'M' then - begin -(* Mmonth.week.dayofweek *) - ADSTEndSpecType := DSTMonthWeekDay; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTEndMonth, Err); - if (Err > 0) or (ADSTEndMonth > 12) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and not (TZ [J] in ['.', ',', '/']) do - Inc (J); - if (J >= Length (TZ)) or (TZ [J] <> '.') then - Exit; - Val (Copy (TZ, I, J - I), ADSTEndWeek, Err); - if (Err > 0) or (ADSTEndWeek < 1) or (ADSTEndWeek > 5) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> '/') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndDay, Err); - if (Err > 0) or (ADSTEndDay < 0) or (ADSTEndDay > 6) then - Exit; - end - else - begin - if TZ [J] = 'J' then - begin -(* Jjulianday *) - if J = Length (TZ) then - Exit; - Inc (J); - ADSTEndSpecType := DSTJulianX - end - else - ADSTEndSpecType := DSTJulian; - if J >= Length (TZ) then - Exit; - Inc (J); - I := J; - while (J <= Length (TZ)) and (TZ [J] <> '/') do - Inc (J); - Val (Copy (TZ, I, J - I), ADSTEndDay, Err); - if (Err > 0) or (ADSTEndDay = 0) and (ADSTEndSpecType = DSTJulianX) - or (ADSTEndDay > 365) then - Exit; - end; - if (J <= Length (TZ)) and (TZ [J] = '/') then - begin - if J = Length (TZ) then - Exit; - Val (Copy (TZ, Succ (J), Length (TZ) - J), ADSTEndSec, Err); - if (Err > 0) or (ADSTEndSec > 86399) then - Exit - else - ADSTEndSec := ADSTEndSec * 3600; - end - else - (* Use the preset default *) - ADSTEndSec := DSTEndSec; - -(* Format complete, all checks successful => accept the parsed values. *) - if ADSTStartSpecType = DSTMonthWeekDay then - begin - DSTStartMonth := ADSTStartMonth; - DSTStartWeek := ADSTStartWeek; - end; - DSTStartDay := ADSTStartDay; - DSTStartSec := ADSTStartSec; - if ADSTStartSpecType = DSTMonthWeekDay then - begin - DSTEndMonth := ADSTEndMonth; - DSTEndWeek := ADSTEndWeek; - end; - DSTEndDay := ADSTEndDay; - DSTEndSec := ADSTEndSec; - DSTStartSpecType := ADSTStartSpecType; - DSTEndSpecType := ADSTEndSpecType; - end; - end - else - DSTOffset := -3600 + TZOffset; - end; - end; -end; - - -begin - InitTZ; -end. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5cea285e6..1cbfdbdd7 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -33,9 +33,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> - <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -78,9 +77,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> - <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -126,9 +124,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> - <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -171,9 +168,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> - <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -229,22 +225,28 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="5"> + <RequiredPackages Count="7"> <Item1> - <PackageName Value="internettools"/> + <PackageName Value="laz_synapse"/> </Item1> <Item2> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="VampyreImagingPackage"/> </Item2> <Item3> - <PackageName Value="richmemopackage"/> + <PackageName Value="internettools"/> </Item3> <Item4> - <PackageName Value="virtualtreeview_package"/> + <PackageName Value="TAChartLazarusPkg"/> </Item4> <Item5> - <PackageName Value="LCL"/> + <PackageName Value="richmemopackage"/> </Item5> + <Item6> + <PackageName Value="virtualtreeview_package"/> + </Item6> + <Item7> + <PackageName Value="LCL"/> + </Item7> </RequiredPackages> <Units Count="9"> <Unit0> @@ -316,9 +318,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\Pururin;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\includes\MangaStreamTo"/> - <Libraries Value="..\3rd\Imaging\Extras\Extensions\J2KObjects"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\3rd\Imaging\Source;..\3rd\Imaging\Source\ZLib;..\3rd\Imaging\Source\JpegLib;..\3rd\Imaging\Extras\Extensions;..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 9db8a6226..cc61cb7ac 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -14,8 +14,8 @@ cthreads, {$ENDIF} {$ENDIF} - Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, sqlite3dyn, - uBaseUnit, frmMain; + Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, + sqlite3dyn, uBaseUnit, frmMain; var CheckInstance: Boolean = True; From ac3fb46301ea248b09275652562113b9dc0a3604 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jan 2016 23:13:45 +0800 Subject: [PATCH 0885/2794] update readme --- readme.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/readme.txt b/readme.txt index e97a36e1b..3d3ab3967 100644 --- a/readme.txt +++ b/readme.txt @@ -21,11 +21,12 @@ The Free Manga Downloader is a free open source application written in Object Pa 2.) Build instructions In order to build FMD from the source code, you must install Lazarus latest version and Free Pascal Compiler v2.6.4. Then you must install the following 3rd party libraries and components: - - RichMemo, - - Virtual TreeView, - - Synapse, - - Vampyre Imaging Library, - - InternetTools. + - RichMemo, https://sourceforge.net/projects/lazarus-ccr/ + - Virtual TreeView, https://sourceforge.net/projects/lazarus-ccr/ + - Synapse, http://synapse.ararat.cz/ + - Vampyre Imaging Library, http://imaginglib.sourceforge.net/ + - InternetTools, https://github.com/benibela/internettools + - BESEN, https://github.com/BeRo1985/besen After everything is installed, open the file md.lpi by using Lazarus IDE, select Run->Build to build the source code. If everything is ok, the binary file should be in FMD_source_code_folder/bin @@ -35,4 +36,4 @@ Translations are stored inside "languages" folder with .po extension. In order t --------------------------------- -Last update 06-08-2015 +Last update 27-01-2016 From 4be52ab57d8c0cf1110d1b9cf44b4131b90e0c28 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jan 2016 23:37:27 +0800 Subject: [PATCH 0886/2794] cleanup project add besen as submodule --- 3rd/besen/src/BESENStringUtils.pas | 2 +- 3rd/besen/src/BESENTypes.pas | 2 +- 3rd/besen/src/BESENUnicodeTables.pas | 2 +- 3rd/besen/src/BESENUtils.pas | 2 +- 3rd/besen/src/BESENValue.pas | 2 +- 3rd/besen/src/BESENValueContainer.pas | 2 +- 3rd/besen/src/BESENVersionConstants.pas | 2 +- baseunits/fasthtmlparser/jsFastHTMLParser.pas | 376 ------------------ baseunits/fasthtmlparser/jsHTMLUtil.pas | 174 -------- 9 files changed, 7 insertions(+), 557 deletions(-) delete mode 100644 baseunits/fasthtmlparser/jsFastHTMLParser.pas delete mode 100644 baseunits/fasthtmlparser/jsHTMLUtil.pas diff --git a/3rd/besen/src/BESENStringUtils.pas b/3rd/besen/src/BESENStringUtils.pas index 3f608dcc6..f3f773f1c 100644 --- a/3rd/besen/src/BESENStringUtils.pas +++ b/3rd/besen/src/BESENStringUtils.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENTypes.pas b/3rd/besen/src/BESENTypes.pas index 3919fafed..583f54934 100644 --- a/3rd/besen/src/BESENTypes.pas +++ b/3rd/besen/src/BESENTypes.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENUnicodeTables.pas b/3rd/besen/src/BESENUnicodeTables.pas index 7e258ccc1..c13093a02 100644 --- a/3rd/besen/src/BESENUnicodeTables.pas +++ b/3rd/besen/src/BESENUnicodeTables.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENUtils.pas b/3rd/besen/src/BESENUtils.pas index cc18900cd..23f7339df 100644 --- a/3rd/besen/src/BESENUtils.pas +++ b/3rd/besen/src/BESENUtils.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENValue.pas b/3rd/besen/src/BESENValue.pas index a9d22b2ad..040937e5b 100644 --- a/3rd/besen/src/BESENValue.pas +++ b/3rd/besen/src/BESENValue.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENValueContainer.pas b/3rd/besen/src/BESENValueContainer.pas index 2212b131a..633232ca7 100644 --- a/3rd/besen/src/BESENValueContainer.pas +++ b/3rd/besen/src/BESENValueContainer.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/3rd/besen/src/BESENVersionConstants.pas b/3rd/besen/src/BESENVersionConstants.pas index d124514c5..45c0da006 100644 --- a/3rd/besen/src/BESENVersionConstants.pas +++ b/3rd/besen/src/BESENVersionConstants.pas @@ -3,7 +3,7 @@ ******************************************************************************** BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2015, Benjamin 'BeRo' Rosseaux +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux The source code of the BESEN ecmascript engine library and helper tools are distributed under the Library GNU Lesser General Public License Version 2.1 diff --git a/baseunits/fasthtmlparser/jsFastHTMLParser.pas b/baseunits/fasthtmlparser/jsFastHTMLParser.pas deleted file mode 100644 index b916e9658..000000000 --- a/baseunits/fasthtmlparser/jsFastHTMLParser.pas +++ /dev/null @@ -1,376 +0,0 @@ -{$MODE Delphi} -{ - This is a FastHTMLParser unit to parse HTML - (disect html into its tags and text.) - - - Modified for use as a pure command line unit (no dialogs) for freepascal. - - Also added UPPERCASE tags so that when you check for <font> it returns all - tags like <FONT> and <FoNt> and <font> - - Regards, - Lars aka L505 - http://z505.com - - - Use it to: - -Make your own web browsers, - -make your own text web browsers (something like Lynx for linux maybe) - -Parse websites - -Grab content from websites -without- using regular expressions - -Seems to be MUCH MUCH FASTER than regular expressions, from what I tested. - -convert website tables into spreadsheets (you have to do the work after parsing it) - -convert websites into text files (you have to do the work after parsing it) - -convert website tables into CSV/Database (you have to do the work after parsing it) - -find certain info from a web page.. i.e. all the table cells, all the bold text. - -Parse websites remotely from a CGI app using something like Synapse and SynWrap - to first get the HTML site, then parse it with these fasthtmlparse units. - This would allow you to dynamically parse info from websites and display - data on your site in real time. -} - -//////////////////////////////////////////////////////////////////////////////// -// // -// TITLE : Fast HTML Parser // -// CLASS : TjsFastHTMLParser // -// VERSION : 0.4 // -// AUTHOR : James Azarja // -// WEBSITE : http://www.jazarsoft.com/ // -// LEGAL : Copyright (C) 2004 Jazarsoft, All Rights Reserved. // -// // -//////////////////////////////////////////////////////////////////////////////// -// // -// This code may be used and modified by anyone so long as this header and // -// copyright information remains intact. // -// // -// The code is provided "AS-IS" and without WARRANTY OF ANY KIND, // -// expressed, implied or otherwise, including and without limitation, any // -// warranty of merchantability or fitness for a particular purpose. // -// // -// In no event shall the author be liable for any special, incidental, // -// indirect or consequential damages whatsoever (including, without // -// limitation, damages for loss of profits, business interruption, loss // -// of information, or any other loss), whether or not advised of the // -// possibility of damage, and on any theory of liability, arising out of // -// or in connection with the use or inability to use this software. // -// // -//////////////////////////////////////////////////////////////////////////////// -// // -// HISTORY: // -// 0.1 - [o] Initial Development // -// mostly based on Peter Irlam works & ideas // -// 0.2 - [*] Some minor bug has fixed // -// 0.3 - [*] Some jsHTMLUtil function bug has been fixed // -// 0.4 - [*] jsHTMLUtil Tag Attributes bug has been fixed // -// thanks to Dmitry [mail@vader.ru] // -// // -// LEGEND: // -// [o] : Information // -// [+] : Add something // -// [-] : Remove something // -// [*] : Fix // -// // -//////////////////////////////////////////////////////////////////////////////// -{ $Id: jsFastHTMLParser.pas,v 1.2 2004/09/10 02:25:56 jazar Exp $ } - -unit jsFastHTMLParser; - -interface - -Uses SysUtils; - -type - TOnFoundTag = procedure(Tag: string) of object; - TOnFoundText = procedure(Text: string) of object; - - TjsFastHTMLParser = class(TObject) - public - OnFoundTag : TOnFoundTag; - OnFoundText : TOnFoundText; - Raw : Pchar; - constructor Create(sRaw:String);overload; - constructor Create(pRaw:PChar);overload; - destructor Destroy; override; - procedure Exec; - procedure SlowExec; - procedure ExecUpCase; //same as Exec, but all tags are now converted to UPPERCASE (consistent) - end; - -implementation - -function CopyBuffer(StartIndex: PChar;Length:Integer):String; -Var - S : String; -begin - SetLength(S, Length); - StrLCopy(@S[1], StartIndex, Length); - Result := S; - S:= ''; -end; - -constructor TjsFastHTMLParser.Create(sRaw:String); -begin - inherited Create; - Raw := Pchar(sRaw); -end; - -constructor TjsFastHTMLParser.Create(pRaw:Pchar); -begin - inherited Create; - Raw := pRaw; -end; - -destructor TjsFastHTMLParser.Destroy; -begin - Raw:= ''; - inherited Destroy; -end; - -procedure TjsFastHTMLParser.Exec; -Var - L : Integer; - TL : Integer; - I : Integer; - Done : Boolean; - TagStart, - TextStart, - P : PChar; // Pointer to current char. - C : Char; -begin - TL := StrLen(Raw); - I := 0; - P := Raw; - Done := False; - if P<>nil then - begin - TagStart := nil; - repeat - TextStart := P; - { Get next tag position } - while Not (P^ in [ '<', #0 ]) do - begin - Inc(P);Inc(I); - if I>=TL then - begin - Done := True; - Break; - end; - end; - if Done then Break; - - { Is there any text before ? } - if (TextStart<>nil) and (P>TextStart) then - begin - - L := P-TextStart; - { Yes, copy to buffer } - - if (assigned(OnFoundText)) then - OnFoundText(CopyBuffer( TextStart, L )); - - end else - begin - TextStart:=nil; - end; - { No } - - TagStart := P; - while Not (P^ in [ '>', #0]) do - begin - - // Find string in tag - if (P^='"') or (P^='''') then - begin - C:= P^; - Inc(P);Inc(I); // Skip current char " or ' - - // Skip until string end - while Not (P^ in [C, #0]) do - begin - Inc(P);Inc(I); - end; - end; - - Inc(P);Inc(I); - if I>=TL then - begin - Done := True; - Break; - end; - end; - if Done then Break; - { Copy this tag to buffer } - L := P-TagStart+1; - - if (Assigned(OnFoundTag)) then - OnFoundTag(CopyBuffer( TagStart, L )); - - Inc(P);Inc(I); - if I>=TL then Break; - - until (Done); - end; -end; - -procedure TjsFastHTMLParser.SlowExec; -Var - L : Integer; - TL : Integer; - I : Integer; - Done : Boolean; - TagStart, - TextStart, - P : PChar; // Pointer to current char. -begin - TL := StrLen(Raw); - I := 0; - P := Raw; - Done := False; - if P<>nil then - begin - TagStart := nil; - repeat - TextStart := P; - { Get next tag position } - while Not (P^ in [ '<', #0 ]) do - begin - Inc(P);Inc(I); - if I>=TL then - begin - Done := True; - Break; - end; - end; - if Done then Break; - - { Is there any text before ? } - if (TextStart<>nil) and (P>TextStart) then - begin - - L := P-TextStart; - { Yes, copy to buffer } - - if (assigned(OnFoundText)) then - OnFoundText(CopyBuffer( TextStart, L )); - - end else - begin - TextStart:=nil; - end; - { No } - - TagStart := P; - while Not (P^ in [ '>', #0]) do - begin - - Inc(P);Inc(I); - if I>=TL then - begin - Done := True; - Break; - end; - end; - if Done then Break; - { Copy this tag to buffer } - L := P-TagStart+1; - - if (Assigned(OnFoundTag)) then - OnFoundTag(CopyBuffer( TagStart, L )); - - Inc(P);Inc(I); - if I>=TL then Break; - - until (Done); - end; -end; - - -{L505: Added this function so we can parse HTML converting alltags to UPPERCASE - This makes it easier in those cases where an html file has mixed <b> and - <B> and <FONT> and <font>} -procedure TjsFastHTMLParser.ExecUpCase; -Var - L : Integer; - TL : Integer; - I : Integer; - Done : Boolean; - TagStart, - TextStart, - P : PChar; // Pointer to current char. - C : Char; -begin - TL := StrLen(Raw); - I := 0; - P := Raw; - Done := False; - if P<>nil then - begin - TagStart := nil; - repeat - TextStart := P; - { Get next tag position } - while Not (P^ in [ '<', #0 ]) do - begin - Inc(P);Inc(I); - if I>=TL then - begin - Done := True; - Break; - end; - end; - if Done then Break; - - { Is there any text before ? } - if (TextStart<>nil) and (P>TextStart) then - begin - - L := P-TextStart; - { Yes, copy to buffer } - - if (assigned(OnFoundText)) then - OnFoundText(CopyBuffer( TextStart, L )); - - end else - begin - TextStart:=nil; - end; - { No } - - TagStart := P; - while Not (P^ in [ '>', #0]) do - begin - - // Find string in tag - if (P^='"') or (P^='''') then - begin - C:= P^; - Inc(P);Inc(I); // Skip current char " or ' - - // Skip until string end - while Not (P^ in [C, #0]) do - begin - Inc(P);Inc(I); - end; - end; - - Inc(P);Inc(I); - if I>=TL then - begin - Done := True; - Break; - end; - end; - if Done then Break; - { Copy this tag to buffer } - L := P-TagStart+1; - - if (Assigned(OnFoundTag)) then - OnFoundTag(uppercase(CopyBuffer( TagStart, L )));//L505: added upppercase - - Inc(P);Inc(I); - if I>=TL then Break; - - until (Done); - end; -end; - -end. diff --git a/baseunits/fasthtmlparser/jsHTMLUtil.pas b/baseunits/fasthtmlparser/jsHTMLUtil.pas deleted file mode 100644 index 778336928..000000000 --- a/baseunits/fasthtmlparser/jsHTMLUtil.pas +++ /dev/null @@ -1,174 +0,0 @@ -{$MODE Delphi} -{ $Id: jsHTMLUtil.pas,v 1.2 2004/09/10 02:25:56 jazar Exp $ } -unit jsHTMLUtil; - -interface - -Uses SysUtils; - -Function GetTagName(Tag:String):String; - { Return tag name in upper/lowercase! } - -Function GetTagAttribute(Tag, Attribute: String):String; - -Function GetTagAttributei(Tag, Attribute: String):String; - -Function GetAttributeValue(Attribute: String):String; - { Get value of attribute, e.g WIDTH=36 -return-> 36 } - - -implementation - -Function CopyBuffer(StartIndex: PChar;Length:Integer):String; -Var - S : String; -Begin - SetLength(S, Length); - StrLCopy(@S[1], StartIndex, Length); - Result := S; -End; - -Function GetTagName(Tag:String):String; -Var - P : Pchar; - S : Pchar; -Begin - P := Pchar(Tag); - While P^ in ['<',' ',#9] do Inc(P); - S := P; - While Not (P^ in [' ','>',#0]) do Inc(P); - If P > S then - Result := CopyBuffer( S, P-S) - else - Result := ''; -End; - -Function GetTagAttribute(Tag, Attribute: String):String; -Var - P : Pchar; - S : Pchar; - C : Char; -Begin - P := Pchar(Tag); - S := StrPos(P, Pchar(Attribute)); - If S<>nil then - Begin - P := S; - - // Skip attribute name - While not (P^ in ['=',' ','>',#0]) do - Inc(P); - - If (P^='=') then inc(P); - - While not (P^ in [' ','>',#0]) do - Begin - - If (P^ in ['"','''']) then - Begin - C:= P^; - Inc(P); { Skip current character } - End else - C:= ' '; - - { thanks to Dmitry [mail@vader.ru] } - While not (P^ in [C, '>', #0]) do - Inc(P); - - If (P^<>'>') then Inc(P); { Skip current character, except '>' } - Break; - End; - - If P > S then - Result := CopyBuffer(S, P-S) else - Result := ''; - End; -End; - -Function GetTagAttributei(Tag, Attribute: String):String; -Var - P : Pchar; - S : Pchar; - UT, - UA : String; - Start: Integer; - L : Integer; - C : Char; -Begin - UA := Uppercase(Attribute); - UT := Uppercase(Tag); - P := Pchar(UT); - S := StrPos(P, Pchar(UA)); - If S<>nil then - Begin - - P := S; - - // Skip attribute name - While not (P^ in ['=',' ','>',#0]) do - Inc(P); - - If (P^='=') then inc(P); - - While not (P^ in [' ','>',#0]) do - Begin - - If (P^ in ['"','''']) then - Begin - C:= P^; - Inc(P); { Skip current character } - End else - C:= ' '; - - { thanks to Dmitry [mail@vader.ru] } - While not (P^ in [C, '>', #0]) do - Inc(P); - - If (P^<>'>') then Inc(P); { Skip current character, except '>' } - Break; - End; - - L := P-S; - Start := S - Pchar(UT); - P := Pchar(Tag); - S := P; - Inc(S,Start); - Result := CopyBuffer(S, L); - End; -End; - -Function GetAttributeValue(Attribute: String):String; -Var - P : Pchar; - S : Pchar; - C : Char; -Begin - P := Pchar(Attribute); - S := StrPos(P, '='); - If S<>nil then - Begin - - Inc(S); - P := S; // set P to a character after = - - If (P^ in ['"','''']) then - Begin - C := P^; - Inc(P); { Skip current character } - End else - C := ' '; - - S := P; - While not (P^ in [C, #0]) do - Inc(P); - - If (P<>S) then { Thanks to Dave Keighan (keighand@yahoo.com) } - Result := CopyBuffer(S, P-S) else - Result := ''; - - End; - -End; - - -end. From 5051c30cad2ec30d276085486335565d65dc6785 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jan 2016 23:52:40 +0800 Subject: [PATCH 0887/2794] cleanup project --- 3rd/besen/LICENSE | 505 -- 3rd/besen/copying.besen | 31 - 3rd/besen/copying.txt | 504 -- 3rd/besen/src/BESEN.inc | 263 - 3rd/besen/src/BESEN.pas | 1866 ----- 3rd/besen/src/BESENASTNodes.pas | 2191 ------ 3rd/besen/src/BESENArrayUtils.pas | 123 - 3rd/besen/src/BESENBaseObject.pas | 59 - 3rd/besen/src/BESENCharset.pas | 421 -- 3rd/besen/src/BESENCode.pas | 699 -- 3rd/besen/src/BESENCodeContext.pas | 4011 ---------- 3rd/besen/src/BESENCodeGeneratorContext.pas | 531 -- 3rd/besen/src/BESENCodeJIT.pas | 89 - 3rd/besen/src/BESENCodeJITx64.pas | 2229 ------ 3rd/besen/src/BESENCodeJITx86.pas | 2552 ------- 3rd/besen/src/BESENCodeSnapshot.pas | 1387 ---- 3rd/besen/src/BESENCollector.pas | 73 - 3rd/besen/src/BESENCollectorObject.pas | 80 - 3rd/besen/src/BESENCompiler.pas | 6597 ----------------- 3rd/besen/src/BESENConstants.pas | 103 - 3rd/besen/src/BESENContext.pas | 452 -- 3rd/besen/src/BESENDateUtils.pas | 1368 ---- .../src/BESENDeclarativeEnvironmentRecord.pas | 612 -- 3rd/besen/src/BESENDecompiler.pas | 1017 --- 3rd/besen/src/BESENDoubleList.pas | 229 - 3rd/besen/src/BESENEnvironmentRecord.pas | 201 - 3rd/besen/src/BESENErrors.pas | 630 -- 3rd/besen/src/BESENEvalCache.pas | 142 - 3rd/besen/src/BESENEvalCacheItem.pas | 85 - 3rd/besen/src/BESENGarbageCollector.pas | 991 --- 3rd/besen/src/BESENGlobals.pas | 42 - 3rd/besen/src/BESENHashMap.pas | 308 - 3rd/besen/src/BESENHashUtils.pas | 159 - 3rd/besen/src/BESENInt64SelfBalancedTree.pas | 632 -- 3rd/besen/src/BESENIntegerList.pas | 230 - 3rd/besen/src/BESENKeyIDManager.pas | 120 - 3rd/besen/src/BESENLexer.pas | 1416 ---- 3rd/besen/src/BESENLexicalEnvironment.pas | 80 - 3rd/besen/src/BESENLocale.pas | 225 - .../src/BESENNativeCodeMemoryManager.pas | 335 - 3rd/besen/src/BESENNativeObject.pas | 612 -- 3rd/besen/src/BESENNumberUtils.pas | 4419 ----------- 3rd/besen/src/BESENObject.pas | 2513 ------- .../src/BESENObjectArgGetterFunction.pas | 94 - .../src/BESENObjectArgSetterFunction.pas | 99 - 3rd/besen/src/BESENObjectArray.pas | 362 - 3rd/besen/src/BESENObjectArrayConstructor.pas | 123 - 3rd/besen/src/BESENObjectArrayPrototype.pas | 1330 ---- 3rd/besen/src/BESENObjectBindingFunction.pas | 191 - 3rd/besen/src/BESENObjectBoolean.pas | 74 - .../src/BESENObjectBooleanConstructor.pas | 103 - 3rd/besen/src/BESENObjectBooleanPrototype.pas | 101 - 3rd/besen/src/BESENObjectConsole.pas | 155 - 3rd/besen/src/BESENObjectConstructor.pas | 457 -- 3rd/besen/src/BESENObjectDate.pas | 95 - 3rd/besen/src/BESENObjectDateConstructor.pas | 231 - 3rd/besen/src/BESENObjectDatePrototype.pas | 1082 --- 3rd/besen/src/BESENObjectDeclaredFunction.pas | 235 - .../src/BESENObjectEnvironmentRecord.pas | 168 - 3rd/besen/src/BESENObjectError.pas | 74 - 3rd/besen/src/BESENObjectErrorConstructor.pas | 108 - 3rd/besen/src/BESENObjectErrorPrototype.pas | 99 - 3rd/besen/src/BESENObjectFunction.pas | 122 - .../src/BESENObjectFunctionArguments.pas | 230 - .../src/BESENObjectFunctionConstructor.pas | 124 - .../src/BESENObjectFunctionPrototype.pas | 237 - 3rd/besen/src/BESENObjectGlobal.pas | 516 -- 3rd/besen/src/BESENObjectJSON.pas | 439 -- 3rd/besen/src/BESENObjectMath.pas | 524 -- 3rd/besen/src/BESENObjectNativeFunction.pas | 102 - 3rd/besen/src/BESENObjectNumber.pas | 75 - .../src/BESENObjectNumberConstructor.pas | 130 - 3rd/besen/src/BESENObjectNumberPrototype.pas | 281 - .../src/BESENObjectPropertyDescriptor.pas | 146 - 3rd/besen/src/BESENObjectPrototype.pas | 223 - 3rd/besen/src/BESENObjectRegExp.pas | 199 - .../src/BESENObjectRegExpConstructor.pas | 188 - 3rd/besen/src/BESENObjectRegExpPrototype.pas | 228 - 3rd/besen/src/BESENObjectString.pas | 133 - .../src/BESENObjectStringConstructor.pas | 119 - 3rd/besen/src/BESENObjectStringPrototype.pas | 1108 --- .../src/BESENObjectThrowTypeErrorFunction.pas | 74 - 3rd/besen/src/BESENOpcodes.pas | 365 - 3rd/besen/src/BESENParser.pas | 2698 ------- 3rd/besen/src/BESENPointerList.pas | 230 - .../src/BESENPointerSelfBalancedTree.pas | 630 -- 3rd/besen/src/BESENRandomGenerator.pas | 274 - 3rd/besen/src/BESENRegExp.pas | 2550 ------- 3rd/besen/src/BESENRegExpCache.pas | 152 - 3rd/besen/src/BESENScope.pas | 83 - 3rd/besen/src/BESENSelfBalancedTree.pas | 678 -- 3rd/besen/src/BESENShell.cfg | 38 - 3rd/besen/src/BESENShell.dof | 136 - 3rd/besen/src/BESENShell.dpr | 942 --- 3rd/besen/src/BESENShell.dproj | 214 - 3rd/besen/src/BESENShell.lpi | 113 - 3rd/besen/src/BESENShell.lpr | 942 --- 3rd/besen/src/BESENStringList.pas | 231 - 3rd/besen/src/BESENStringTree.pas | 356 - 3rd/besen/src/BESENStringUtils.pas | 2618 ------- 3rd/besen/src/BESENTypes.pas | 200 - 3rd/besen/src/BESENUnicodeTables.pas | 1274 ---- 3rd/besen/src/BESENUtils.pas | 76 - 3rd/besen/src/BESENValue.pas | 705 -- 3rd/besen/src/BESENValueContainer.pas | 77 - 3rd/besen/src/BESENVersionConstants.pas | 42 - mangadownloader/md.lpi | 10 +- 107 files changed, 5 insertions(+), 67140 deletions(-) delete mode 100644 3rd/besen/LICENSE delete mode 100644 3rd/besen/copying.besen delete mode 100644 3rd/besen/copying.txt delete mode 100644 3rd/besen/src/BESEN.inc delete mode 100644 3rd/besen/src/BESEN.pas delete mode 100644 3rd/besen/src/BESENASTNodes.pas delete mode 100644 3rd/besen/src/BESENArrayUtils.pas delete mode 100644 3rd/besen/src/BESENBaseObject.pas delete mode 100644 3rd/besen/src/BESENCharset.pas delete mode 100644 3rd/besen/src/BESENCode.pas delete mode 100644 3rd/besen/src/BESENCodeContext.pas delete mode 100644 3rd/besen/src/BESENCodeGeneratorContext.pas delete mode 100644 3rd/besen/src/BESENCodeJIT.pas delete mode 100644 3rd/besen/src/BESENCodeJITx64.pas delete mode 100644 3rd/besen/src/BESENCodeJITx86.pas delete mode 100644 3rd/besen/src/BESENCodeSnapshot.pas delete mode 100644 3rd/besen/src/BESENCollector.pas delete mode 100644 3rd/besen/src/BESENCollectorObject.pas delete mode 100644 3rd/besen/src/BESENCompiler.pas delete mode 100644 3rd/besen/src/BESENConstants.pas delete mode 100644 3rd/besen/src/BESENContext.pas delete mode 100644 3rd/besen/src/BESENDateUtils.pas delete mode 100644 3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas delete mode 100644 3rd/besen/src/BESENDecompiler.pas delete mode 100644 3rd/besen/src/BESENDoubleList.pas delete mode 100644 3rd/besen/src/BESENEnvironmentRecord.pas delete mode 100644 3rd/besen/src/BESENErrors.pas delete mode 100644 3rd/besen/src/BESENEvalCache.pas delete mode 100644 3rd/besen/src/BESENEvalCacheItem.pas delete mode 100644 3rd/besen/src/BESENGarbageCollector.pas delete mode 100644 3rd/besen/src/BESENGlobals.pas delete mode 100644 3rd/besen/src/BESENHashMap.pas delete mode 100644 3rd/besen/src/BESENHashUtils.pas delete mode 100644 3rd/besen/src/BESENInt64SelfBalancedTree.pas delete mode 100644 3rd/besen/src/BESENIntegerList.pas delete mode 100644 3rd/besen/src/BESENKeyIDManager.pas delete mode 100644 3rd/besen/src/BESENLexer.pas delete mode 100644 3rd/besen/src/BESENLexicalEnvironment.pas delete mode 100644 3rd/besen/src/BESENLocale.pas delete mode 100644 3rd/besen/src/BESENNativeCodeMemoryManager.pas delete mode 100644 3rd/besen/src/BESENNativeObject.pas delete mode 100644 3rd/besen/src/BESENNumberUtils.pas delete mode 100644 3rd/besen/src/BESENObject.pas delete mode 100644 3rd/besen/src/BESENObjectArgGetterFunction.pas delete mode 100644 3rd/besen/src/BESENObjectArgSetterFunction.pas delete mode 100644 3rd/besen/src/BESENObjectArray.pas delete mode 100644 3rd/besen/src/BESENObjectArrayConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectArrayPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectBindingFunction.pas delete mode 100644 3rd/besen/src/BESENObjectBoolean.pas delete mode 100644 3rd/besen/src/BESENObjectBooleanConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectBooleanPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectConsole.pas delete mode 100644 3rd/besen/src/BESENObjectConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectDate.pas delete mode 100644 3rd/besen/src/BESENObjectDateConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectDatePrototype.pas delete mode 100644 3rd/besen/src/BESENObjectDeclaredFunction.pas delete mode 100644 3rd/besen/src/BESENObjectEnvironmentRecord.pas delete mode 100644 3rd/besen/src/BESENObjectError.pas delete mode 100644 3rd/besen/src/BESENObjectErrorConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectErrorPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectFunction.pas delete mode 100644 3rd/besen/src/BESENObjectFunctionArguments.pas delete mode 100644 3rd/besen/src/BESENObjectFunctionConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectFunctionPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectGlobal.pas delete mode 100644 3rd/besen/src/BESENObjectJSON.pas delete mode 100644 3rd/besen/src/BESENObjectMath.pas delete mode 100644 3rd/besen/src/BESENObjectNativeFunction.pas delete mode 100644 3rd/besen/src/BESENObjectNumber.pas delete mode 100644 3rd/besen/src/BESENObjectNumberConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectNumberPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectPropertyDescriptor.pas delete mode 100644 3rd/besen/src/BESENObjectPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectRegExp.pas delete mode 100644 3rd/besen/src/BESENObjectRegExpConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectRegExpPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectString.pas delete mode 100644 3rd/besen/src/BESENObjectStringConstructor.pas delete mode 100644 3rd/besen/src/BESENObjectStringPrototype.pas delete mode 100644 3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas delete mode 100644 3rd/besen/src/BESENOpcodes.pas delete mode 100644 3rd/besen/src/BESENParser.pas delete mode 100644 3rd/besen/src/BESENPointerList.pas delete mode 100644 3rd/besen/src/BESENPointerSelfBalancedTree.pas delete mode 100644 3rd/besen/src/BESENRandomGenerator.pas delete mode 100644 3rd/besen/src/BESENRegExp.pas delete mode 100644 3rd/besen/src/BESENRegExpCache.pas delete mode 100644 3rd/besen/src/BESENScope.pas delete mode 100644 3rd/besen/src/BESENSelfBalancedTree.pas delete mode 100644 3rd/besen/src/BESENShell.cfg delete mode 100644 3rd/besen/src/BESENShell.dof delete mode 100644 3rd/besen/src/BESENShell.dpr delete mode 100644 3rd/besen/src/BESENShell.dproj delete mode 100644 3rd/besen/src/BESENShell.lpi delete mode 100644 3rd/besen/src/BESENShell.lpr delete mode 100644 3rd/besen/src/BESENStringList.pas delete mode 100644 3rd/besen/src/BESENStringTree.pas delete mode 100644 3rd/besen/src/BESENStringUtils.pas delete mode 100644 3rd/besen/src/BESENTypes.pas delete mode 100644 3rd/besen/src/BESENUnicodeTables.pas delete mode 100644 3rd/besen/src/BESENUtils.pas delete mode 100644 3rd/besen/src/BESENValue.pas delete mode 100644 3rd/besen/src/BESENValueContainer.pas delete mode 100644 3rd/besen/src/BESENVersionConstants.pas diff --git a/3rd/besen/LICENSE b/3rd/besen/LICENSE deleted file mode 100644 index 40c8ae627..000000000 --- a/3rd/besen/LICENSE +++ /dev/null @@ -1,505 +0,0 @@ -GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -(This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.) - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random - Hacker. - - {signature of Ty Coon}, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - diff --git a/3rd/besen/copying.besen b/3rd/besen/copying.besen deleted file mode 100644 index 1b5999b7b..000000000 --- a/3rd/besen/copying.besen +++ /dev/null @@ -1,31 +0,0 @@ - -This is the file copying.besen, it applies to the BESEN ecmascript engine -library distributed by Benjamin 'BeRo' Rosseaux. - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2014, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - - - diff --git a/3rd/besen/copying.txt b/3rd/besen/copying.txt deleted file mode 100644 index b1e3f5a26..000000000 --- a/3rd/besen/copying.txt +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/3rd/besen/src/BESEN.inc b/3rd/besen/src/BESEN.inc deleted file mode 100644 index f23723ff9..000000000 --- a/3rd/besen/src/BESEN.inc +++ /dev/null @@ -1,263 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -{$ifdef fpc} - {$mode delphi} - {$ifdef cpui386} - {$define cpu386} - {$endif} - {$ifdef cpu386} - {$asmmode intel} - {$endif} - {$ifdef cpuamd64} - {$asmmode intel} - {$endif} - {$ifdef FPC_LITTLE_ENDIAN} - {$define LITTLE_ENDIAN} - {$else} - {$ifdef FPC_BIG_ENDIAN} - {$define BIG_ENDIAN} - {$endif} - {$endif} - {$pic off} - {$define caninline} - {$ifdef FPC_HAS_TYPE_EXTENDED} - {$define HAS_TYPE_EXTENDED} - {$else} - {$undef HAS_TYPE_EXTENDED} - {$endif} - {$ifdef FPC_HAS_TYPE_DOUBLE} - {$define HAS_TYPE_DOUBLE} - {$else} - {$undef HAS_TYPE_DOUBLE} - {$endif} - {$ifdef FPC_HAS_TYPE_SINGLE} - {$define HAS_TYPE_SINGLE} - {$else} - {$undef HAS_TYPE_SINGLE} - {$endif} -{$else} - {$realcompatibility off} - {$localsymbols on} - {$define LITTLE_ENDIAN} - {$ifndef cpu64} - {$define cpu32} - {$endif} - {$define HAS_TYPE_EXTENDED} - {$define HAS_TYPE_DOUBLE} - {$define HAS_TYPE_SINGLE} - {$ifndef BCB} - {$ifdef ver120} - {$define Delphi4or5} - {$endif} - {$ifdef ver130} - {$define Delphi4or5} - {$endif} - {$ifdef ver140} - {$define Delphi6} - {$endif} - {$ifdef ver150} - {$define Delphi7} - {$endif} - {$ifdef ver170} - {$define Delphi2005} - {$endif} - {$else} - {$ifdef ver120} - {$define Delphi4or5} - {$define BCB4} - {$endif} - {$ifdef ver130} - {$define Delphi4or5} - {$endif} - {$endif} - {$ifdef ver180} - {$define BDS2006} - {$define Delphi2006} - {$endif} - {$ifdef ver185} - {$define Delphi2007} - {$endif} - {$ifdef ver190} - {$define Delphi2007Net} - {$endif} - {$ifdef ver200} - {$define Delphi2009} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver210} - {$define Delphi2010} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver220} - {$define DelphiXE} - {$define DelphiXEAndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver230} - {$define DelphiXE2} - {$define DelphiXEAndUp} - {$define DelphiXE2AndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver240} - {$define DelphiXE3} - {$define DelphiXEAndUp} - {$define DelphiXE2AndUp} - {$define DelphiXE3AndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver250} - {$define DelphiXE4} - {$define DelphiXEAndUp} - {$define DelphiXE2AndUp} - {$define DelphiXE3AndUp} - {$define DelphiXE4AndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver260} - {$define DelphiXE5} - {$define DelphiXEAndUp} - {$define DelphiXE2AndUp} - {$define DelphiXE3AndUp} - {$define DelphiXE4AndUp} - {$define DelphiXE5AndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver270} - {$define DelphiXE6} - {$define DelphiXEAndUp} - {$define DelphiXE2AndUp} - {$define DelphiXE3AndUp} - {$define DelphiXE4AndUp} - {$define DelphiXE5AndUp} - {$define DelphiXE6AndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifdef ver280} - {$define DelphiXE7} - {$define DelphiXEAndUp} - {$define DelphiXE2AndUp} - {$define DelphiXE3AndUp} - {$define DelphiXE4AndUp} - {$define DelphiXE5AndUp} - {$define DelphiXE6AndUp} - {$define DelphiXE7AndUp} - {$define Delphi2009AndUp} - {$endif} - {$ifndef Delphi4or5} - {$ifndef BCB} - {$define Delphi6AndUp} - {$endif} - {$ifndef Delphi6} - {$define BCB6OrDelphi7AndUp} - {$ifndef BCB} - {$define Delphi7AndUp} - {$endif} - {$ifndef BCB} - {$ifndef Delphi7} - {$ifndef Delphi2005} - {$define BDS2006AndUp} - {$endif} - {$endif} - {$endif} - {$endif} - {$endif} - {$ifdef Delphi6AndUp} - {$warn symbol_platform off} - {$warn symbol_deprecated off} - {$endif} -{$endif} -{$ifdef win32} - {$define windows} -{$endif} -{$ifdef win64} - {$define windows} -{$endif} -{$ifdef wince} - {$define windows} -{$endif} -{$rangechecks off} -{$extendedsyntax on} -{$writeableconst on} -{$hints off} -{$booleval off} -{$typedaddress off} -{$stackframes off} -{$varstringchecks on} -{$typeinfo on} -{$overflowchecks off} -{$longstrings on} -{$openstrings on} -{$undef UseSafeStringEquals} -{$define strictutf8} -{$define UseOptimizedHashing} -{$define UseAssert} -{$define UseSafeOperations} -{$undef HasJIT} -{$ifdef cpu386} - {$define UseRegister} - {$define HasJIT} - {$undef UseSafeOperations} -{$endif} -{$ifdef cpuamd64} - {$define UseRegister} - {$ifndef windows} - {$define HasJIT} - {$endif} -{$endif} -{$ifdef NextGen} - {$define BESENEmbarcaderoNextGen} - {$define BESENSingleStringType} - {$define PurePascal} - {$ZeroBasedStrings off} -{$endif} -{$ifdef PurePascal} - {$define DisableJIT} - {$undef ForceJIT} -{$endif} -{$ifdef DisableJIT} - {$undef HasJIT} -{$endif} -{$ifdef ForceJIT} - {$define HasJIT} -{$endif} -{$ifdef ForceUseSafeOperations} - {$define UseSafeOperations} -{$endif} -{$ifndef HAS_TYPE_DOUBLE} - {$error No double floating point precision } -{$endif} -{$ifdef DelphiXE2AndUp} - {$ifdef MacOS} - {$define BESENDelphiHasNoSystemTimeMore} - {$endif} -{$endif} - diff --git a/3rd/besen/src/BESEN.pas b/3rd/besen/src/BESEN.pas deleted file mode 100644 index b4b5b51e7..000000000 --- a/3rd/besen/src/BESEN.pas +++ /dev/null @@ -1,1866 +0,0 @@ -(******************************************************************************* - B E S E N -******************************************************************************** - Version: See at line in BESENVersionConstants.pas, which contains "BESENVersion" --------------------------------------------------------------------------------- - - Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux <benjamin@rosseaux.com> - - Website: www.rosseaux.com - -******************************************************************************** - -BESEN is an acronym for "Bero's EcmaScript Engine", and it is a complete -ECMAScript Fifth Edition Implemention in Object Pascal, which is compilable -with Delphi >=7 and FreePascal >= 2.5.1 (maybe also 2.4.1). - -BESEN contains the following features: - -- Complete implementation of the ECMAScript Fifth Edition standard -- Own bytecode-based ECMA262-complaint Regular Expression Engine -- Incremental praise/exact mark-and-sweep garbage collector -- Unicode UTF8/UCS2/UTF16/UCS4/UTF32 support (on ECMAScript level, UCS2/UTF16) -- Compatibility modes, for example also a facile JavaScript compatibility mode -- Bytecode compiler -- Call-Subroutine-Threaded Register-based virtual machine -- Context-Threaded 32-bit x86 and 64-bit x64/AMD64 Just-in-Time Compiler -- Constant folding -- Dead code elimination -- Abstract-Syntax-Tree based optimizations -- Type inference (both exact and speculative) -- Polymorphic Inline Cache based on object structure and property key IDs -- Perfomance optimized hash maps -- Self balanced trees - -To-Do: - -- Bytecode peephole optimization -- Aggressive bytecode copy propagation (for less read/write register access) -- Optimizing bytecode opcode set, adding more specialized combined superopcodes -- Implement ARM EABI VFPv3 Just-In-time Compiler -- Regular Expression Just-In-Compiler -- Checking/testing the code -- Fix bugs :-) - -******************************************************************************** - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESEN; -{$i BESEN.inc} - -interface - -uses SysUtils,Classes,Math,SyncObjs,TypInfo,Variants,BESENVersionConstants, - BESENConstants,BESENTypes,BESENCharset,BESENStringUtils,BESENOpcodes, - BESENNativeCodeMemoryManager,BESENValueContainer,BESENObject, - BESENSelfBalancedTree,BESENGlobals,BESENErrors, - BESENPointerSelfBalancedTree,BESENInt64SelfBalancedTree, - BESENPointerList,BESENStringList,BESENIntegerList,BESENHashUtils, - BESENHashMap,BESENBaseObject,BESENCollectorObject,BESENCollector, - BESENGarbageCollector,BESENValue,BESENObjectPropertyDescriptor, - BESENRegExp,BESENCode,BESENCodeContext,BESENContext, - BESENEnvironmentRecord,BESENDeclarativeEnvironmentRecord, - BESENObjectEnvironmentRecord,BESENLexicalEnvironment, - BESENASTNodes,BESENCodeGeneratorContext,BESENParser, - BESENObjectPrototype,BESENObjectFunction, - BESENObjectConstructor,BESENObjectGlobal, - BESENObjectJSON,BESENObjectMath,BESENObjectFunctionArguments, - BESENObjectFunctionPrototype,BESENObjectFunctionConstructor, - BESENObjectDeclaredFunction,BESENObjectThrowTypeErrorFunction, - BESENObjectArgGetterFunction,BESENObjectArgSetterFunction, - BESENObjectBindingFunction,BESENObjectBoolean, - BESENObjectBooleanPrototype,BESENObjectBooleanConstructor, - BESENObjectRegExp,BESENObjectRegExpPrototype, - BESENObjectRegExpConstructor,BESENObjectDate, - BESENObjectDatePrototype,BESENObjectDateConstructor, - BESENObjectError,BESENObjectErrorPrototype, - BESENObjectErrorConstructor,BESENObjectNumber, - BESENObjectNumberPrototype,BESENObjectNumberConstructor, - BESENObjectString,BESENObjectStringPrototype, - BESENObjectStringConstructor,BESENObjectArray, - BESENObjectArrayPrototype,BESENObjectArrayConstructor, - BESENNativeObject,BESENRandomGenerator,BESENKeyIDManager, - BESENRegExpCache,BESENEvalCacheItem,BESENEvalCache, - BESENCompiler,BESENDecompiler,BESENLocale, - BESENCodeSnapshot; - -type TBESEN=class; - - TBESENTransitSecurityDomain=procedure(const Instance:TBESEN;const NewSecurityDomain:pointer) of object; - - TBESENTraceHook=function(const Instance:TBESEN;const Context:TBESENContext;const FunctionBody:TBESENASTNodeFunctionBody;PC:TBESENUINT32;const TraceType:TBESENTraceType):boolean of object; - - TBESENPeriodicHook=function(const Instance:TBESEN):boolean of object; - - TBESENRegExpDebugOutputHook=procedure(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN) of object; - - TBESEN=class - public - CriticalSection:TCriticalSection; - Collector:TBESENCollector; - GarbageCollector:TBESENGarbageCollector; - KeyIDManager:TBESENKeyIDManager; - ObjectStructureIDManager:TBESENObjectStructureIDManager; - RegExpCache:TBESENRegExpCache; - DefaultRegExp:TBESENRegExp; - EvalCache:TBESENEvalCache; - Compiler:TBESENCompiler; - Decompiler:TBESENDecompiler; - CodeSnapshot:TBESENCodeSnapshot; - NativeCodeMemoryManager:TBESENNativeCodeMemoryManager; - InlineCacheEnabled:TBESENBoolean; - ContextFirst,ContextLast:TBESENContext; - CodeFirst,CodeLast:TBESENCode; - ProgramNodes:TBESENPointerSelfBalancedTree; - IsStrict:longbool; - Compatibility:longword; - RecursionLimit:integer; - SecurityDomain:pointer; - TransitSecurityDomain:TBESENTransitSecurityDomain; - UseSecurity:TBESENBoolean; - CodeLineInfo:TBESENBoolean; - CodeTracable:TBESENBoolean; - RegExpDebug:TBESENUINT32; - RegExpTimeOutSteps:TBESENINT64; - TraceHook:TBESENTraceHook; - PeriodicHook:TBESENPeriodicHook; - RegExpDebugOutputHook:TBESENRegExpDebugOutputHook; - LineNumber:TBESENUINT32; - RandomGenerator:TBESENRandomGenerator; - RegExpMaxStatesHoldInMemory:integer; - JITLoopCompileThreshold:longword; - MaxCountOfFreeCodeContexts:integer; - MaxCountOfFreeContexts:integer; - ObjectPrototype:TBESENObjectPrototype; - ObjectConstructor:TBESENObjectConstructor; - ObjectFunctionPrototype:TBESENObjectFunctionPrototype; - ObjectFunctionConstructor:TBESENObjectFunctionConstructor; - ObjectBooleanPrototype:TBESENObjectBooleanPrototype; - ObjectBooleanConstructor:TBESENObjectBooleanConstructor; - ObjectRegExpPrototype:TBESENObjectRegExpPrototype; - ObjectRegExpConstructor:TBESENObjectRegExpConstructor; - ObjectDatePrototype:TBESENObjectDatePrototype; - ObjectDateConstructor:TBESENObjectDateConstructor; - ObjectErrorPrototype:TBESENObjectErrorPrototype; - ObjectEvalErrorPrototype:TBESENObjectErrorPrototype; - ObjectRangeErrorPrototype:TBESENObjectErrorPrototype; - ObjectReferenceErrorPrototype:TBESENObjectErrorPrototype; - ObjectSyntaxErrorPrototype:TBESENObjectErrorPrototype; - ObjectTypeErrorPrototype:TBESENObjectErrorPrototype; - ObjectURIErrorPrototype:TBESENObjectErrorPrototype; - ObjectErrorConstructor:TBESENObjectErrorConstructor; - ObjectEvalErrorConstructor:TBESENObjectErrorConstructor; - ObjectRangeErrorConstructor:TBESENObjectErrorConstructor; - ObjectReferenceErrorConstructor:TBESENObjectErrorConstructor; - ObjectSyntaxErrorConstructor:TBESENObjectErrorConstructor; - ObjectTypeErrorConstructor:TBESENObjectErrorConstructor; - ObjectURIErrorConstructor:TBESENObjectErrorConstructor; - ObjectNumberConstructor:TBESENObjectNumberConstructor; - ObjectNumberPrototype:TBESENObjectNumberPrototype; - ObjectStringPrototype:TBESENObjectStringPrototype; - ObjectStringConstructor:TBESENObjectStringConstructor; - ObjectArrayPrototype:TBESENObjectArrayPrototype; - ObjectArrayConstructor:TBESENObjectArrayConstructor; - ObjectJSON:TBESENObjectJSON; - ObjectMath:TBESENObjectMath; - ObjectEmpty:TBESENObject; - ObjectThrowTypeErrorFunction:TBESENObjectThrowTypeErrorFunction; - ObjectGlobal:TBESENObjectGlobal; - ObjectGlobalEval:TBESENObjectFunction; - GlobalLexicalEnvironment:TBESENLexicalEnvironment; - ObjectNumberConstructorValue:TBESENValue; - ObjectStringConstructorValue:TBESENValue; - constructor Create(ACompatibility:longword=0); overload; - destructor Destroy; override; - procedure Lock; - procedure Unlock; - procedure LockObject(Obj:TBESENGarbageCollectorObject); - procedure UnlockObject(Obj:TBESENGarbageCollectorObject); - procedure LockValue(const Value:TBESENValue); - procedure UnlockValue(const Value:TBESENValue); - function GetRandom:longword; - procedure RegisterNativeObject(const AName:TBESENString;const AClass:TBESENNativeObjectClass;const Attributes:TBESENObjectPropertyDescriptorAttributes=[bopaWRITABLE,bopaCONFIGURABLE]); - procedure FunctionCall(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); - procedure FunctionConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); - function MakeError(const Name:TBESENString;var ConstructorObject:TBESENObjectErrorConstructor;const ProtoProto:TBESENObject):TBESENObjectErrorPrototype; - function LoadFromStream(const Stream:TStream):TBESENASTNode; - procedure SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); - function Compile(InputSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const Parameters:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; - function Decompile(RootNode:TBESENASTNode):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; - function ObjectInstanceOf(const v:TBESENValue;Obj:TBESENObject):boolean; - function MakeFunction(Node:TBESENASTNodeFunctionLiteral;Name:TBESENString;ParentLexicalEnvironment:TBESENLexicalEnvironment=nil):TBESENObjectDeclaredFunction; - function Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; overload; - function Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; overload; - function Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; - function Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; - function JSONEval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; - function JSONStringify(const Value:TBESENValue):TBESENValue; overload; - function JSONStringify(const Value,Replacer:TBESENValue):TBESENValue; overload; - function JSONStringify(const Value,Replacer,Space:TBESENValue):TBESENValue; overload; - procedure InjectObject(Name,Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); - function NewDeclarativeEnvironment(const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; - function NewObjectEnvironment(const BindingObject:TBESENObject;const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; - function ParseNumber(const s:TBESENString):TBESENNumber; - procedure ToPrimitiveValue(const AValue,AType:TBESENValue;var AResult:TBESENValue); overload; - procedure ToPrimitiveValue(const AValue:TBESENValue;var AResult:TBESENValue); overload; - procedure ToBooleanValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure ToNumberValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure ToIntegerValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure ToStringValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure ToObjectValue(const AValue:TBESENValue;var AResult:TBESENValue); - function ToInt(const AValue:TBESENValue):int64; - function ToInt32(const AValue:TBESENValue):TBESENINT32; - function ToUInt32(const AValue:TBESENValue):TBESENUINT32; - function ToInt16(const AValue:TBESENValue):TBESENINT16; - function ToUInt16(const AValue:TBESENValue):TBESENUINT16; - function ToBool(const AValue:TBESENValue):TBESENBoolean; - function ToNum(const AValue:TBESENValue):TBESENNumber; - function ToStr(const AValue:TBESENValue):TBESENString; - function ToObj(const AValue:TBESENValue):TBESENObject; - procedure EqualityExpressionSub(const a,b:TBESENValue;var AResult:TBESENValue); - function EqualityExpressionEquals(const a,b:TBESENValue):boolean; - function EqualityExpressionCompare(const a,b:TBESENValue):integer; - procedure FromPropertyDescriptor(const Descriptor:TBESENObjectPropertyDescriptor;var AResult:TBESENValue); - procedure ToPropertyDescriptor(const v:TBESENValue;var AResult:TBESENObjectPropertyDescriptor); - function SameValue(const va,vb:TBESENValue):TBESENBoolean; overload; - function SameValue(const oa,ob:TBESENObject):TBESENBoolean; overload; - function SameObject(const oa,ob:TBESENObject):TBESENBoolean; - procedure AddProgramNode(Node:TBESENASTNodeProgram); - procedure RemoveProgramNode(Node:TBESENASTNodeProgram); - procedure GlobalEval(const Context:TBESENContext;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;const DirectCall:boolean;var AResult:TBESENValue); - procedure ObjectCallConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;Construct:boolean;var AResult:TBESENValue); - procedure ObjectCall(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); - procedure ObjectConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); - property PropertyCacheEnabled:TBESENBoolean read InlineCacheEnabled write InlineCacheEnabled; - end; - -implementation - -uses BESENLexer,BESENNumberUtils,BESENUtils,BESENStringTree,BESENDateUtils,BESENArrayUtils; - -constructor TBESEN.Create(ACompatibility:longword=0); -var v:TBESENValue; -begin - inherited Create; - InlineCacheEnabled:=true; - ContextFirst:=nil; - ContextLast:=nil; - CodeFirst:=nil; - CodeLast:=nil; - CriticalSection:=TCriticalSection.Create; - Collector:=TBESENCollector.Create(self); - GarbageCollector:=TBESENGarbageCollector.Create(self); - KeyIDManager:=TBESENKeyIDManager.Create(self); - ObjectStructureIDManager:=TBESENObjectStructureIDManager.Create(self); - Compiler:=TBESENCompiler.Create(self); - Decompiler:=TBESENDecompiler.Create(self); - CodeSnapshot:=TBESENCodeSnapshot.Create(self); - NativeCodeMemoryManager:=TBESENNativeCodeMemoryManager.Create; - ProgramNodes:=TBESENPointerSelfBalancedTree.Create; - IsStrict:=false; - Compatibility:=ACompatibility; - RecursionLimit:=-1; - SecurityDomain:=nil; - TransitSecurityDomain:=nil; - UseSecurity:=false; - CodeLineInfo:=true; - CodeTracable:=false; - RegExpDebug:=0; - RegExpTimeOutSteps:=0; - TraceHook:=nil; - PeriodicHook:=nil; - RegExpDebugOutputHook:=nil; - LineNumber:=0; - RandomGenerator:=TBESENRandomGenerator.Create(self); - RegExpMaxStatesHoldInMemory:=breMAXSTATESHOLDINMEMORY; - JITLoopCompileThreshold:=BESEN_JIT_LOOPCOMPILETHRESHOLD; - MaxCountOfFreeCodeContexts:=BESENMaxCountOfFreeCodeContexts; - MaxCountOfFreeContexts:=BESENMaxCountOfFreeContexts; - - RegExpCache:=TBESENRegExpCache.Create(self); - DefaultRegExp:=TBESENRegExp.Create(selF); - - EvalCache:=TBESENEvalCache.Create(self); - - v:=BESENEmptyValue; - - ObjectPrototype:=nil; - - begin - ObjectFunctionPrototype:=TBESENObjectFunctionPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectFunctionPrototype); - ObjectFunctionPrototype.RegisterNativeFunction('toString',ObjectFunctionPrototype.NativeToString,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - ObjectFunctionPrototype.RegisterNativeFunction('apply',ObjectFunctionPrototype.NativeApply,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - ObjectFunctionPrototype.RegisterNativeFunction('call',ObjectFunctionPrototype.NativeCall,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - ObjectFunctionPrototype.RegisterNativeFunction('bind',ObjectFunctionPrototype.NativeBind,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - - ObjectPrototype:=TBESENObjectPrototype.Create(self,nil,false); - GarbageCollector.AddRoot(ObjectPrototype); - - ObjectFunctionPrototype.Prototype:=ObjectPrototype; - - ObjectFunctionConstructor:=TBESENObjectFunctionConstructor.Create(self,ObjectFunctionPrototype,true); - GarbageCollector.AddRoot(ObjectFunctionConstructor); - - ObjectFunctionPrototype.OverwriteData('constructor',BESENObjectValue(ObjectFunctionConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectBooleanPrototype:=TBESENObjectBooleanPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectBooleanPrototype); - - ObjectBooleanConstructor:=TBESENObjectBooleanConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectBooleanConstructor); - - ObjectBooleanConstructor.OverwriteData('prototype',BESENObjectValue(ObjectBooleanPrototype),[]); - - ObjectBooleanPrototype.OverwriteData('constructor',BESENObjectValue(ObjectBooleanConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectRegExpPrototype:=TBESENObjectRegExpPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectRegExpPrototype); - - ObjectRegExpConstructor:=TBESENObjectRegExpConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectRegExpConstructor); - - ObjectRegExpConstructor.OverwriteData('prototype',BESENObjectValue(ObjectRegExpPrototype),[]); - - ObjectRegExpPrototype.OverwriteData('constructor',BESENObjectValue(ObjectRegExpConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectDatePrototype:=TBESENObjectDatePrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectDatePrototype); - - ObjectDateConstructor:=TBESENObjectDateConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectDateConstructor); - - ObjectDateConstructor.OverwriteData('prototype',BESENObjectValue(ObjectDatePrototype),[]); - - ObjectDatePrototype.OverwriteData('constructor',BESENObjectValue(ObjectDateConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectErrorPrototype:=TBESENObjectErrorPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectErrorPrototype); - - ObjectErrorConstructor:=TBESENObjectErrorConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectErrorConstructor); - ObjectErrorConstructor.OverwriteData('prototype',BESENObjectValueEx(ObjectErrorPrototype),[]); - v:=BESENStringValue('Error'); - ObjectErrorConstructor.OverwriteData('name',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectErrorConstructor); - ObjectErrorPrototype.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - ObjectEvalErrorPrototype:=MakeError('EvalError',ObjectEvalErrorConstructor,ObjectErrorPrototype); - ObjectRangeErrorPrototype:=MakeError('RangeError',ObjectRangeErrorConstructor,ObjectErrorPrototype); - ObjectReferenceErrorPrototype:=MakeError('ReferenceError',ObjectReferenceErrorConstructor,ObjectErrorPrototype); - ObjectSyntaxErrorPrototype:=MakeError('SyntaxError',ObjectSyntaxErrorConstructor,ObjectErrorPrototype); - ObjectTypeErrorPrototype:=MakeError('TypeError',ObjectTypeErrorConstructor,ObjectErrorPrototype); - ObjectURIErrorPrototype:=MakeError('URIError',ObjectURIErrorConstructor,ObjectErrorPrototype); - - GarbageCollector.AddRoot(ObjectEvalErrorPrototype); - GarbageCollector.AddRoot(ObjectRangeErrorPrototype); - GarbageCollector.AddRoot(ObjectReferenceErrorPrototype); - GarbageCollector.AddRoot(ObjectSyntaxErrorPrototype); - GarbageCollector.AddRoot(ObjectTypeErrorPrototype); - GarbageCollector.AddRoot(ObjectURIErrorPrototype); - - GarbageCollector.AddRoot(ObjectEvalErrorConstructor); - GarbageCollector.AddRoot(ObjectRangeErrorConstructor); - GarbageCollector.AddRoot(ObjectReferenceErrorConstructor); - GarbageCollector.AddRoot(ObjectSyntaxErrorConstructor); - GarbageCollector.AddRoot(ObjectTypeErrorConstructor); - GarbageCollector.AddRoot(ObjectURIErrorConstructor); - end; - - begin - ObjectNumberPrototype:=TBESENObjectNumberPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectNumberPrototype); - - ObjectNumberConstructor:=TBESENObjectNumberConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectNumberConstructor); - - ObjectNumberConstructor.OverwriteData('prototype',BESENObjectValue(ObjectNumberPrototype),[]); - - ObjectNumberPrototype.OverwriteData('constructor',BESENObjectValue(ObjectNumberConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectStringPrototype:=TBESENObjectStringPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectStringPrototype); - - ObjectStringConstructor:=TBESENObjectStringConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectStringConstructor); - - ObjectStringConstructor.OverwriteData('prototype',BESENObjectValue(ObjectStringPrototype),[]); - - ObjectStringPrototype.OverwriteData('constructor',BESENObjectValue(ObjectStringConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectArrayPrototype:=TBESENObjectArrayPrototype.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectArrayPrototype); - - ObjectArrayConstructor:=TBESENObjectArrayConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectArrayConstructor); - - ObjectArrayConstructor.OverwriteData('prototype',BESENObjectValue(ObjectArrayPrototype),[]); - - ObjectArrayPrototype.OverwriteData('constructor',BESENObjectValue(ObjectArrayConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - begin - ObjectJSON:=TBESENObjectJSON.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectJSON); - end; - - begin - ObjectMath:=TBESENObjectMath.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectMath); - end; - - begin - ObjectEmpty:=TBESENObject.Create(self,ObjectPrototype,false); - GarbageCollector.AddRoot(ObjectEmpty); - end; - - begin - ObjectThrowTypeErrorFunction:=TBESENObjectThrowTypeErrorFunction.Create(self,ObjectFunctionPrototype,true); - GarbageCollector.AddRoot(ObjectThrowTypeErrorFunction); - end; - - begin - ObjectConstructor:=TBESENObjectConstructor.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.AddRoot(ObjectConstructor); - - ObjectConstructor.OverwriteData('prototype',BESENObjectValue(ObjectPrototype),[]); - - ObjectPrototype.OverwriteData('constructor',BESENObjectValue(ObjectConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - if (Compatibility and COMPAT_JS)<>0 then begin - ObjectGlobal:=TBESENObjectGlobal.Create(self,ObjectPrototype,true); - end else begin - ObjectGlobal:=TBESENObjectGlobal.Create(self,nil,false); - end; - GarbageCollector.AddRoot(ObjectGlobal); - - ObjectGlobal.Get('eval',v); - if v.ValueType=bvtOBJECT then begin - ObjectGlobalEval:=TBESENObjectFunction(TBESENObject(v.Obj)); - end else begin - ObjectGlobalEval:=nil; - end; - if (Compatibility and COMPAT_JS)<>0 then begin - ObjectPrototype.OverwriteData('eval',v,[bopaWRITABLE,bopaCONFIGURABLE]); - end; - - v:=BESENObjectValue(ObjectConstructor); - ObjectGlobal.OverwriteData('Object',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectFunctionConstructor); - ObjectGlobal.OverwriteData('Function',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectBooleanConstructor); - ObjectGlobal.OverwriteData('Boolean',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectRegExpConstructor); - ObjectGlobal.OverwriteData('RegExp',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectDateConstructor); - ObjectGlobal.OverwriteData('Date',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectNumberConstructor); - ObjectGlobal.OverwriteData('Number',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectStringConstructor); - ObjectGlobal.OverwriteData('String',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectArrayConstructor); - ObjectGlobal.OverwriteData('Array',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectJSON); - ObjectGlobal.OverwriteData('JSON',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectMath); - ObjectGlobal.OverwriteData('Math',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectErrorConstructor); - ObjectGlobal.OverwriteData('Error',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectEvalErrorConstructor); - ObjectGlobal.OverwriteData('EvalError',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectRangeErrorConstructor); - ObjectGlobal.OverwriteData('RangeError',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectReferenceErrorConstructor); - ObjectGlobal.OverwriteData('ReferenceError',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectSyntaxErrorConstructor); - ObjectGlobal.OverwriteData('SyntaxError',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectTypeErrorConstructor); - ObjectGlobal.OverwriteData('TypeError',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(ObjectURIErrorConstructor); - ObjectGlobal.OverwriteData('URIError',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - GlobalLexicalEnvironment:=NewObjectEnvironment(ObjectGlobal,nil,false,false); - GarbageCollector.AddRoot(GlobalLexicalEnvironment); - - ObjectNumberConstructorValue:=BESENObjectValue(ObjectNumberConstructor); - ObjectStringConstructorValue:=BESENObjectValue(ObjectStringConstructor); -end; - -destructor TBESEN.Destroy; -begin - TBESENObjectEnvironmentRecord(GlobalLexicalEnvironment.EnvironmentRecord).BindingObject:=nil; - - EvalCache.Free; - - GarbageCollector.Free; - - ProgramNodes.Free; - - DefaultRegExp.Free; - - RegExpCache.Free; - - Collector.Free; - - NativeCodeMemoryManager.Free; - - CodeSnapshot.Free; - - Decompiler.Free; - - Compiler.Free; - - ObjectStructureIDManager.Free; - - KeyIDManager.Free; - - CriticalSection.Free; - - inherited Destroy; -end; - -procedure TBESEN.Lock; -begin - CriticalSection.Enter; -end; - -procedure TBESEN.Unlock; -begin - CriticalSection.Leave; -end; - -procedure TBESEN.LockObject(Obj:TBESENGarbageCollectorObject); -begin - GarbageCollector.LockObject(Obj); -end; - -procedure TBESEN.UnlockObject(Obj:TBESENGarbageCollectorObject); -begin - GarbageCollector.UnlockObject(Obj); -end; - -procedure TBESEN.LockValue(const Value:TBESENValue); -begin - GarbageCollector.LockValue(Value); -end; - -procedure TBESEN.UnlockValue(const Value:TBESENValue); -begin - GarbageCollector.UnlockValue(Value); -end; - -function TBESEN.GetRandom:longword; -begin - result:=RandomGenerator.Get; -end; - -procedure TBESEN.RegisterNativeObject(const AName:TBESENString;const AClass:TBESENNativeObjectClass;const Attributes:TBESENObjectPropertyDescriptorAttributes=[bopaWRITABLE,bopaCONFIGURABLE]); -var v:TBESENValue; -begin - v.ValueType:=bvtOBJECT; - TBESENObject(v.Obj):=AClass.Create(self,ObjectPrototype); - GarbageCollector.AddRoot(TBESENObject(v.Obj)); - ObjectGlobal.OverwriteData(AName,v,Attributes); -end; - -function TBESEN.MakeError(const Name:TBESENString;var ConstructorObject:TBESENObjectErrorConstructor;const ProtoProto:TBESENObject):TBESENObjectErrorPrototype; -var v:TBESENValue; -begin - result:=TBESENObjectErrorPrototype.Create(self,ProtoProto,false); - - ConstructorObject:=TBESENObjectErrorConstructor.Create(self,ObjectFunctionPrototype,false); - ConstructorObject.OverwriteData('prototype',BESENObjectValueEx(result),[]); - - v:=BESENEmptyValue; - v:=BESENObjectValue(ConstructorObject); - result.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENStringValue(Name); - result.OverwriteData('name',v,[bopaWRITABLE,bopaCONFIGURABLE]); - result.OverwriteData('message',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENNumberValue(1); - result.OverwriteData('length',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENObjectValue(result); - ConstructorObject.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); -end; - -function TBESEN.LoadFromStream(const Stream:TStream):TBESENASTNode; -begin - result:=CodeSnapshot.LoadFromStream(Stream); -end; - -procedure TBESEN.SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); -begin - CodeSnapshot.SaveToStream(Stream,RootNode); -end; - -function TBESEN.Compile(InputSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const Parameters:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; -begin - result:=Compiler.Compile(InputSource,Parameters,IsFunction,IsJSON); -end; - -function TBESEN.Decompile(RootNode:TBESENASTNode):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; -begin - result:=Decompiler.Decompile(RootNode); -end; - -function TBESEN.ObjectInstanceOf(const v:TBESENValue;Obj:TBESENObject):boolean; -var vp:TBESENValue; - o:TBESENObject; -begin - if not assigned(Obj) then begin - raise EBESENTypeError.Create('Null object'); - end; - if Obj.HasHasInstance then begin - result:=Obj.HasInstance(v); - end else if (Compatibility and COMPAT_JS)<>0 then begin - if (v.ValueType<>bvtOBJECT) or not assigned(TBESENObject(v.Obj)) then begin - result:=false; - end else begin - Obj.Get('prototype',vp); - result:=false; - if (vp.ValueType=bvtOBJECT) and assigned(vp.Obj) then begin - o:=TBESENObject(v.Obj); - while assigned(o) do begin - if o.Prototype=vp.Obj then begin - result:=true; - break; - end; - o:=o.Prototype; - end; - end; - end; - end else begin - raise EBESENTypeError.Create('No hasInstance'); - end; -end; - -procedure TBESEN.ObjectCallConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;Construct:boolean;var AResult:TBESENValue); -var OldRecursionLimit:integer; - OldSecurityDomain:pointer; -begin - if not assigned(Obj) then begin - BESENThrowTypeError('Null object'); - end; - OldRecursionLimit:=RecursionLimit; - OldSecurityDomain:=SecurityDomain; - if RecursionLimit=0 then begin - BESENThrowRecursionLimitReached; - end else if RecursionLimit>0 then begin - dec(RecursionLimit); - end; - if UseSecurity and assigned(TransitSecurityDomain) and Obj.HasGetSecurityDomain then begin - SecurityDomain:=Obj.GetSecurityDomain; - if SecurityDomain<>OldSecurityDomain then begin - TransitSecurityDomain(self,SecurityDomain); - end; - end; - try - if Construct then begin - if Obj.HasConstruct then begin - Obj.Construct(ThisArgument,Arguments,CountArguments,AResult); - end else begin - BESENThrowTypeError('No constructable'); - end; - end else begin - if Obj.HasCall then begin - Obj.Call(ThisArgument,Arguments,CountArguments,AResult); - end else begin - BESENThrowTypeError('No callable'); - end; - end; - finally - SecurityDomain:=OldSecurityDomain; - RecursionLimit:=OldRecursionLimit; - end; -end; - -procedure TBESEN.ObjectCall(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if UseSecurity or (RecursionLimit>=0) then begin - ObjectCallConstruct(Obj,ThisArgument,Arguments,CountArguments,false,AResult); - end else begin - if assigned(Obj) then begin - if Obj.HasCall then begin - Obj.Call(ThisArgument,Arguments,CountArguments,AResult); - end else begin - BESENThrowTypeError('No callable'); - end; - end else begin - BESENThrowTypeError('Null object'); - end; - end; -end; - -procedure TBESEN.ObjectConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if UseSecurity or (RecursionLimit>=0) then begin - ObjectCallConstruct(Obj,ThisArgument,Arguments,CountArguments,true,AResult); - end else begin - if assigned(Obj) then begin - if Obj.HasConstruct then begin - Obj.Construct(ThisArgument,Arguments,CountArguments,AResult); - end else begin - BESENThrowTypeError('No constructable'); - end; - end else begin - BESENThrowTypeError('Null object'); - end; - end; -end; - -procedure TBESEN.FunctionCall(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); -var pArguments:TBESENValuePointers; - i:integer; -begin - pArguments:=nil; - SetLength(pArguments,length(Arguments)); - try - for i:=0 to length(Arguments)-1 do begin - pArguments[i]:=@Arguments[i]; - end; - ObjectCallConstruct(Obj,ThisArgument,@pArguments[0],length(pArguments),false,AResult); - finally - SetLength(pArguments,0); - end; -end; - -procedure TBESEN.FunctionConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); -var pArguments:TBESENValuePointers; - i:integer; -begin - pArguments:=nil; - SetLength(pArguments,length(Arguments)); - try - for i:=0 to length(Arguments)-1 do begin - pArguments[i]:=@Arguments[i]; - end; - ObjectCallConstruct(Obj,ThisArgument,@pArguments[0],length(pArguments),true,AResult); - finally - SetLength(pArguments,0); - end; -end; - -function TBESEN.MakeFunction(Node:TBESENASTNodeFunctionLiteral;Name:TBESENString;ParentLexicalEnvironment:TBESENLexicalEnvironment=nil):TBESENObjectDeclaredFunction; -var i:integer; - Prototype:TBESENObject; - Body:TBESENASTNodeFunctionBody; -begin - if not assigned(ParentLexicalEnvironment) then begin - ParentLexicalEnvironment:=GlobalLexicalEnvironment; - end; - result:=TBESENObjectDeclaredFunction.Create(self,ObjectFunctionPrototype,false); - GarbageCollector.Add(result); - result.GarbageCollectorLock; - try - result.SecurityDomain:=SecurityDomain; - result.Node:=Node; - result.Container:=Node.Container; - result.ObjectName:=Name; - result.LexicalEnvironment:=ParentLexicalEnvironment; - result.Extensible:=true; - - Body:=Node.Body; - SetLength(result.Parameters,length(Body.Parameters)); - for i:=0 to length(result.Parameters)-1 do begin - if assigned(Body.Parameters[i]) then begin - result.Parameters[i]:=Body.Parameters[i].Name; - end else begin - result.Parameters[i]:='param#'+inttostr(i); - end; - end; - - if (Compatibility and COMPAT_JS)<>0 then begin - result.OverwriteData('name',BESENStringValue(Name),[]); - end; - - result.OverwriteData('length',BESENNumberValue(length(result.Parameters)),[]); - - Prototype:=TBESENObject.Create(self,ObjectPrototype,false); - GarbageCollector.Add(Prototype); - - Prototype.OverwriteData('constructor',BESENObjectValue(result),[bopaWRITABLE,bopaCONFIGURABLE]); - - result.OverwriteData('prototype',BESENObjectValue(Prototype),[bopaWRITABLE]); - - if IsStrict then begin - result.OverwriteAccessor('caller',ObjectThrowTypeErrorFunction,ObjectThrowTypeErrorFunction,[],false); - result.OverwriteAccessor('arguments',ObjectThrowTypeErrorFunction,ObjectThrowTypeErrorFunction,[],false); - end else if (Compatibility and COMPAT_JS)<>0 then begin - result.OverwriteData('arguments',BESENNullValue,[]); - end; - finally - result.GarbageCollectorUnlock; - end; -end; - -procedure TBESEN.AddProgramNode(Node:TBESENASTNodeProgram); -var Value:TBESENPointerSelfBalancedTreeValue; -begin - if assigned(Node) then begin - if not ProgramNodes.Find(Node,Value) then begin - Value.p:=Node; - ProgramNodes.Insert(Node,Value); - end; - end; -end; - -procedure TBESEN.RemoveProgramNode(Node:TBESENASTNodeProgram); -begin - if assigned(Node) then begin - ProgramNodes.Remove(Node); - end; -end; - -procedure TBESEN.GlobalEval(const Context:TBESENContext;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;const DirectCall:boolean;var AResult:TBESENValue); -var Node:TBESENASTNode; - v:TBESENValue; - Lex:TBESENLexicalEnvironment; - NewContext:TBESENContext; - CacheItem:TBESENEvalCacheItem; - Source:TBESENString; - OldIsStrict:TBESENBoolean; -begin - AResult.ValueType:=bvtUNDEFINED; - v.ValueType:=bvtuNDEFINED; - if CountArguments>0 then begin - BESENCopyValue(v,Arguments^[0]^); - end; - if v.ValueType<>bvtSTRING then begin - BESENCopyValue(AResult,v); - end else begin - OldIsStrict:=IsStrict; - try - if not DirectCall then begin - IsStrict:=false; - end; - Source:=ToStr(v); - try - if (EvalCache.HashSize>0) and (length(Source)<=EvalCache.MaxSourceLength) then begin - CacheItem:=EvalCache.Get(Source,IsStrict); - end else begin - CacheItem:=nil; - end; - if assigned(CacheItem) then begin - CacheItem.IncRef; - Node:=TBESENASTNode(CacheItem.Node); - end else begin - Node:=Compile(BESENUTF16ToUTF8(Source)); - end; - finally - Source:=''; - end; - NewContext:=TBESENContext.Create(self); - try - if assigned(Node) then begin - try - if Node is TBESENASTNodeProgram then begin - AddProgramNode(TBESENASTNodeProgram(Node)); - if DirectCall then begin - NewContext.LexicalEnvironment:=Context.LexicalEnvironment; - NewContext.VariableEnvironment:=Context.VariableEnvironment; - BESENCopyValue(NewContext.ThisBinding,Context.ThisBinding); - end else begin - NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; - NewContext.VariableEnvironment:=GlobalLexicalEnvironment; - NewContext.ThisBinding.ValueType:=bvtOBJECT; - NewContext.ThisBinding.Obj:=ObjectGlobal; - end; - if IsStrict or TBESENASTNodeProgram(Node).Body.IsStrict then begin - Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,true,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); - GarbageCollector.Add(Lex); - NewContext.LexicalEnvironment:=Lex; - NewContext.VariableEnvironment:=Lex; - end; - NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,true,nil,0,false); - Node.ExecuteCode(NewContext,AResult); - end; - finally - if not assigned(CacheItem) then begin - BesenFreeAndNil(Node); - end; - end; - end; - finally - if assigned(CacheItem) then begin - CacheItem.DecRef; - end; - NewContext.Free; - end; - finally - IsStrict:=OldIsStrict; - end; - end; - if (AResult.ValueType=bvtOBJECT) and assigned(AResult.Obj) then begin - TBESENObject(AResult.Obj).GarbageCollectorLock; - try - GarbageCollector.CollectAll; - finally - TBESENObject(AResult.Obj).GarbageCollectorUnlock; - end; - end else begin - GarbageCollector.CollectAll; - end; -end; - -function TBESEN.Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; -var Node:TBESENASTNode; - Lex:TBESENLexicalEnvironment; - NewContext:TBESENContext; -begin - result:=BESENEmptyValue; - if assigned(PrecompiledASTNode) then begin - Node:=PrecompiledASTNode; - end else begin - Node:=Compile(Source); - end; - NewContext:=TBESENContext.Create(self); - try - if assigned(Node) then begin - try - if Node is TBESENASTNodeProgram then begin - AddProgramNode(TBESENASTNodeProgram(Node)); - if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj)<>ObjectGlobal) then begin - NewContext.LexicalEnvironment:=NewObjectEnvironment(TBESENObject(ThisArgument.Obj),GlobalLexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); - NewContext.VariableEnvironment:=NewDeclarativeEnvironment(GlobalLexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); - BESENCopyValue(NewContext.ThisBinding,ThisArgument); - GarbageCollector.Add(NewContext.LexicalEnvironment); - GarbageCollector.Add(NewContext.VariableEnvironment); - end else begin - NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; - NewContext.VariableEnvironment:=GlobalLexicalEnvironment; - NewContext.ThisBinding.ValueType:=bvtOBJECT; - NewContext.ThisBinding.Obj:=ObjectGlobal; - end; - if IsEval and (IsStrict or TBESENASTNodeProgram(Node).Body.IsStrict) then begin - Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,true,(assigned(Node) and ((Node is TBESENASTNodeProgram) and assigned(TBESENASTNodeProgram(Node).Body) and TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval))); - GarbageCollector.Add(Lex); - NewContext.LexicalEnvironment:=Lex; - NewContext.VariableEnvironment:=Lex; - end; - NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,IsEval,nil,0,false); - Node.ExecuteCode(NewContext,result); - end; - finally - if not assigned(PrecompiledASTNode) then begin - BesenFreeAndNil(Node); - end; - end; - end; - finally - NewContext.Free; - end; - if (result.ValueType=bvtOBJECT) and assigned(result.Obj) then begin - TBESENObject(result.Obj).GarbageCollectorLock; - try - GarbageCollector.CollectAll; - finally - TBESENObject(result.Obj).GarbageCollectorUnlock; - end; - end else begin - GarbageCollector.CollectAll; - end; -end; - -function TBESEN.Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; -begin - BesenCopyValue(result,Execute(Source,BESENUndefinedValue,PrecompiledASTNode,IsEval)); -end; - -function TBESEN.Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; -begin - BesenCopyValue(result,Execute(Source,ThisArgument,PrecompiledASTNode,true)); -end; - -function TBESEN.Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; -begin - BesenCopyValue(result,Execute(Source,BESENUndefinedValue,PrecompiledASTNode,true)); -end; - -function TBESEN.JSONEval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; -var Node:TBESENASTNode; - Lex:TBESENLexicalEnvironment; - NewContext:TBESENContext; -begin - result:=BESENEmptyValue; - if assigned(PrecompiledASTNode) then begin - Node:=PrecompiledASTNode; - end else begin - Node:=Compile(Source,'',false,true); - end; - NewContext:=TBESENContext.Create(self); - try - if assigned(Node) then begin - try - if Node is TBESENASTNodeProgram then begin - AddProgramNode(TBESENASTNodeProgram(Node)); - NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; - NewContext.VariableEnvironment:=GlobalLexicalEnvironment; - NewContext.ThisBinding.ValueType:=bvtNULL; - Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); - GarbageCollector.Add(Lex); - NewContext.LexicalEnvironment:=Lex; - NewContext.VariableEnvironment:=Lex; - NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,true,nil,0,false); - Node.ExecuteCode(NewContext,result); - end; - finally - if not assigned(PrecompiledASTNode) then begin - BesenFreeAndNil(Node); - end; - end; - end; - finally - NewContext.Free; - end; - if (result.ValueType=bvtOBJECT) and assigned(result.Obj) then begin - TBESENObject(result.Obj).GarbageCollectorLock; - try - GarbageCollector.CollectAll; - finally - TBESENObject(result.Obj).GarbageCollectorUnlock; - end; - end else begin - GarbageCollector.CollectAll; - end; -end; - -function TBESEN.JSONStringify(const Value:TBESENValue):TBESENValue; -var Arguments:array[0..0] of TBESENValue; - ValuePointers:array[0..0] of PBESENValue; -begin - result:=BESENEmptyValue; - GarbageCollector.LockValue(Value); - try - Arguments[0]:=Value; - ValuePointers[0]:=@Arguments[0]; - ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],1,result); - finally - GarbageCollector.UnlockValue(Value); - end; -end; - -function TBESEN.JSONStringify(const Value,Replacer:TBESENValue):TBESENValue; -var Arguments:array[0..1] of TBESENValue; - ValuePointers:array[0..1] of PBESENValue; -begin - result:=BESENEmptyValue; - GarbageCollector.LockValue(Value); - GarbageCollector.LockValue(Replacer); - try - Arguments[0]:=Value; - Arguments[1]:=Replacer; - ValuePointers[0]:=@Arguments[0]; - ValuePointers[1]:=@Arguments[1]; - ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],2,result); - finally - GarbageCollector.UnlockValue(Value); - GarbageCollector.UnlockValue(Replacer); - end; -end; - -function TBESEN.JSONStringify(const Value,Replacer,Space:TBESENValue):TBESENValue; -var Arguments:array[0..2] of TBESENValue; - ValuePointers:array[0..2] of PBESENValue; -begin - result:=BESENEmptyValue; - GarbageCollector.LockValue(Value); - GarbageCollector.LockValue(Replacer); - GarbageCollector.LockValue(Space); - try - Arguments[0]:=Value; - Arguments[1]:=Replacer; - Arguments[2]:=Space; - ValuePointers[0]:=@Arguments[0]; - ValuePointers[1]:=@Arguments[1]; - ValuePointers[2]:=@Arguments[2]; - ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],3,result); - finally - GarbageCollector.UnlockValue(Value); - GarbageCollector.UnlockValue(Replacer); - GarbageCollector.UnlockValue(Space); - end; -end; - -procedure TBESEN.InjectObject(Name,Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); -var v:TBESENValue; -begin - Execute(Source); - v:=Execute(Name); - if v.ValueType=bvtOBJECT then begin - GarbageCollector.AddRoot(TBESENObject(v.Obj)); - GarbageCollector.CollectAll; - end; -end; - -function TBESEN.NewDeclarativeEnvironment(const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; -begin - result:=TBESENLexicalEnvironment.Create(self); - result.EnvironmentRecord:=TBESENDeclarativeEnvironmentRecord.Create(self); - result.EnvironmentRecord.IsStrict:=IsItStrict; - result.EnvironmentRecord.HasMaybeDirectEval:=HasMaybeDirectEval; - result.EnvironmentRecord.UpdateImplicitThisValue; - result.Outer:=Environment; -end; - -function TBESEN.NewObjectEnvironment(const BindingObject:TBESENObject;const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; -begin - result:=TBESENLexicalEnvironment.Create(self); - result.EnvironmentRecord:=TBESENObjectEnvironmentRecord.Create(self); - result.EnvironmentRecord.IsStrict:=IsItStrict; - result.EnvironmentRecord.HasMaybeDirectEval:=HasMaybeDirectEval; - TBESENObjectEnvironmentRecord(result.EnvironmentRecord).BindingObject:=BindingObject; - result.EnvironmentRecord.UpdateImplicitThisValue; - result.Outer:=Environment; -end; - -function TBESEN.ParseNumber(const s:TBESENString):TBESENNumber; -begin - result:=BESENStringToNumber(s,true,true,true,false); -end; - -procedure TBESEN.ToPrimitiveValue(const AValue,AType:TBESENValue;var AResult:TBESENValue); - procedure BESENThrowIt; - begin - BESENThrowTypeError('Bad object'); - end; -begin - if AValue.ValueType=bvtOBJECT then begin - if assigned(AValue.Obj) then begin - TBESENObject(AValue.Obj).DefaultValue(AType,AResult); - end else begin - BESENThrowIt; - end; - end else if @AResult<>@AValue then begin - BESENCopyValue(AResult,AValue); - end; -end; - -procedure TBESEN.ToPrimitiveValue(const AValue:TBESENValue;var AResult:TBESENValue); -begin - ToPrimitiveValue(AValue,BESENUndefinedValue,AResult); -end; - -procedure TBESEN.ToBooleanValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure BESENThrowIt; - begin - BESENThrowTypeError('Bad to boolean conversation'); - end; -var bo:TBESENObject; - vo:TBESENValue; -begin - case AValue.ValueType of - bvtUNDEFINED:begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=false; - end; - bvtNULL:begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=false; - end; - bvtBOOLEAN:begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=AValue.Bool; - end; - bvtNUMBER:begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=BESENIsInfinite(AValue.Num) or not (BESENIsNaN(AValue.Num) or (abs(AValue.Num)=0)); - end; - bvtSTRING:begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=length(AValue.Str)>0; - end; - bvtOBJECT:begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=true; - if (Compatibility and COMPAT_JS)<>0 then begin - bo:=TBESENObject(AValue.Obj); - if bo is TBESENObjectBoolean then begin - vo:=BESENEmptyValue; - bo.Get('valueOf',vo); - if (vo.ValueType=bvtOBJECT) and assigned(TBESENObject(vo.Obj)) and (TBESENObject(vo.Obj).HasCall) then begin - ObjectCall(TBESENObject(vo.Obj),BESENObjectValue(bo),nil,0,AResult); - end; - end; - end; - end; - else begin - BESENThrowIt; - end; - end; -{$ifdef UseAssert} - Assert(AResult.ValueType=bvtBOOLEAN); -{$endif} -end; - -procedure TBESEN.ToNumberValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure BESENThrowIt; - begin - BESENThrowTypeError('Bad to number conversation'); - end; -const BooleanToNumber:array[boolean] of TBESENNumber=(0.0,1.0); -var v:TBESENValue; -begin - case AValue.ValueType of - bvtUNDEFINED:begin - AResult.ValueType:=bvtNUMBER; - int64(pointer(@AResult.Num)^):=int64(pointer(@BESENDoubleNAN)^); - end; - bvtNULL:begin - AResult.ValueType:=bvtNUMBER; - AResult.Num:=0; - end; - bvtBOOLEAN:begin - AResult.ValueType:=bvtNUMBER; - AResult.Num:=BooleanToNumber[boolean(AValue.Bool)]; - end; - bvtNUMBER:begin - AResult.ValueType:=bvtNUMBER; - int64(pointer(@AResult.Num)^):=int64(pointer(@AValue.Num)^); - end; - bvtSTRING:begin - AResult.ValueType:=bvtNUMBER; - AResult.Num:=ParseNumber(AValue.Str); - end; - bvtOBJECT:begin - ToPrimitiveValue(AValue,ObjectNumberConstructorValue,v); - ToNumberValue(v,AResult); - end; - else begin - BESENThrowIt; - end; - end; -{$ifdef UseAssert} - Assert(AResult.ValueType=bvtNUMBER); -{$endif} -end; - -procedure TBESEN.ToIntegerValue(const AValue:TBESENValue;var AResult:TBESENValue); -var Sign:longword; -begin - ToNumberValue(AValue,AResult); - if BESENIsNaN(AResult.Num) then begin - AResult.Num:=0.0; - end else if not (BESENIsInfinite(AResult.Num) or BESENIsZero(AResult.Num)) then begin - Sign:=PBESENDoubleHiLo(@AResult.Num)^.Hi and $80000000; - PBESENDoubleHiLo(@AResult.Num)^.Hi:=PBESENDoubleHiLo(@AResult.Num)^.Hi and $7fffffff; - AResult.Num:=BESENFloor(AResult.Num); - PBESENDoubleHiLo(@AResult.Num)^.Hi:=PBESENDoubleHiLo(@AResult.Num)^.Hi or Sign; - end; -end; - -procedure TBESEN.ToStringValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure BESENThrowIt; - begin - BESENThrowTypeError('Bad to string conversation'); - end; -var v:TBESENValue; -begin - case AValue.ValueType of - bvtUNDEFINED:begin - AResult.ValueType:=bvtSTRING; - AResult.Str:='undefined'; - end; - bvtNULL:begin - AResult.ValueType:=bvtSTRING; - AResult.Str:='null'; - end; - bvtBOOLEAN:begin - AResult.ValueType:=bvtSTRING; - if AValue.Bool then begin - AResult.Str:='true'; - end else begin - AResult.Str:='false'; - end; - end; - bvtNUMBER:begin - AResult.ValueType:=bvtSTRING; - AResult.Str:=BESENFloatToStr(AValue.Num); - end; - bvtSTRING:begin - AResult.ValueType:=bvtSTRING; - AResult.Str:=AValue.Str; - end; - bvtOBJECT:begin - ToPrimitiveValue(AValue,ObjectStringConstructorValue,v); - ToStringValue(v,AResult); - end; - else begin - BESENThrowIt; - end; - end; -{$ifdef UseAssert} - Assert(AResult.ValueType=bvtSTRING); -{$endif} -end; - -procedure TBESEN.ToObjectValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure BESENThrowIt; - begin - BESENThrowTypeError('Bad to object conversation'); - end; -begin - case AValue.ValueType of - bvtUNDEFINED:begin - raise EBESENTypeError.Create('ToObjectValue undefined'); - end; - bvtNULL:begin - raise EBESENTypeError.Create('ToObjectValue null'); - end; - bvtBOOLEAN:begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=TBESENObjectBoolean.Create(self,ObjectBooleanPrototype,false); - GarbageCollector.Add(TBESENObject(AResult.Obj)); - TBESENObjectBoolean(AResult.Obj).Value:=AValue.Bool; - end; - bvtNUMBER:begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=TBESENObjectNumber.Create(self,ObjectNumberPrototype,false); - GarbageCollector.Add(TBESENObject(AResult.Obj)); - TBESENObjectNumber(AResult.Obj).Value:=AValue.Num; - end; - bvtSTRING:begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=TBESENObjectString.Create(self,ObjectStringPrototype,false); - GarbageCollector.Add(TBESENObject(AResult.Obj)); - TBESENObjectString(AResult.Obj).Value:=AValue.Str; - TBESENObjectString(AResult.Obj).UpdateLength; - end; - bvtOBJECT:begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=AValue.Obj; - end; - else begin - BESENThrowIt; - end; - end; -{$ifdef UseAssert} - Assert(AResult.ValueType=bvtOBJECT); -{$endif} -end; - -function TBESEN.ToInt(const AValue:TBESENValue):int64; -var v:TBESENValue; -begin - ToIntegerValue(AValue,v); - result:=trunc(v.Num); -end; - -function TBESEN.ToInt32(const AValue:TBESENValue):TBESENINT32; -var v:TBESENValue; - Sign:longword; -begin - ToNumberValue(AValue,v); - if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin - v.Num:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; - v.Num:=BESENFloor(v.Num); - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; - v.Num:=BESENModulo(System.int(v.Num),4294967296.0); - if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin - v.Num:=v.Num+4294967296.0; - end; - if v.Num>=2147483648.0 then begin - v.Num:=v.Num-4294967296.0; - end; - end; - result:=trunc(v.Num); -end; - -function TBESEN.ToUInt32(const AValue:TBESENValue):TBESENUINT32; -var v:TBESENValue; - Sign:longword; -begin - ToNumberValue(AValue,v); - if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin - v.Num:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; - v.Num:=BESENFloor(v.Num); - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; - v.Num:=BESENModulo(System.int(v.Num),4294967296.0); - if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin - v.Num:=v.Num+4294967296.0; - end; - end; - result:=trunc(v.Num); -end; - -function TBESEN.ToInt16(const AValue:TBESENValue):TBESENINT16; -var v:TBESENValue; - Sign:longword; -begin - ToNumberValue(AValue,v); - if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin - v.Num:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; - v.Num:=BESENFloor(v.Num); - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; - v.Num:=BESENModulo(System.int(v.Num),65536.0); - if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin - v.Num:=v.Num+65536.0; - end; - if v.Num>=32768.0 then begin - v.Num:=v.Num-65536.0; - end; - end; - result:=trunc(v.Num); -end; - -function TBESEN.ToUInt16(const AValue:TBESENValue):TBESENUINT16; -var v:TBESENValue; - Sign:longword; -begin - ToNumberValue(AValue,v); - if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin - v.Num:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; - v.Num:=BESENFloor(v.Num); - PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; - v.Num:=BESENModulo(System.int(v.Num),65536.0); - if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin - v.Num:=v.Num+65536.0; - end; - end; - result:=trunc(v.Num); -end; - -function TBESEN.ToBool(const AValue:TBESENValue):TBESENBoolean; -var b:TBESENValue; -begin - ToBooleanValue(AValue,b); - result:=b.Bool; -end; - -function TBESEN.ToNum(const AValue:TBESENValue):TBESENNumber; -var n:TBESENValue; -begin - ToNumberValue(AValue,n); - result:=n.Num; -end; - -function TBESEN.ToStr(const AValue:TBESENValue):TBESENString; -var s:TBESENValue; -begin - ToStringValue(AValue,s); - result:=s.Str; -end; - -function TBESEN.ToObj(const AValue:TBESENValue):TBESENObject; -var o:TBESENValue; -begin - ToObjectValue(AValue,o); - result:=TBESENObject(o.Obj); -end; - -procedure TBESEN.EqualityExpressionSub(const a,b:TBESENValue;var AResult:TBESENValue); -var r1,r2:TBESENValue; - n1,n2:TBESENNumber; -begin - ToPrimitiveValue(a,ObjectNumberConstructorValue,r1); - ToPrimitiveValue(b,ObjectNumberConstructorValue,r2); - if (r1.ValueType=bvtSTRING) and (r2.ValueType=bvtSTRING) then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=r1.Str<r2.Str; - end else begin - n1:=ToNum(r1); - n2:=ToNum(r2); - if BESENIsNaN(n1) or BESENIsNaN(n2) then begin - AResult.ValueType:=bvtUNDEFINED; - end else if n1=n2 then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=false; - end else if BESENIsPosInfinite(n1) then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=false; - end else if BESENIsPosInfinite(n2) then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=true; - end else if BESENIsNegInfinite(n1) then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=true; - end else if BESENIsNegInfinite(n2) then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=false; - end else begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=n1<n2; - end; - end; -end; - -function TBESEN.EqualityExpressionEquals(const a,b:TBESENValue):boolean; - function BooleanAgainstAllAnother:boolean; - var TempValue:TBESENValue; - begin - ToNumberValue(a,TempValue); - result:=EqualityExpressionEquals(TempValue,b); - end; - function AllAnotherAgainstBoolean:boolean; - var TempValue:TBESENValue; - begin - ToNumberValue(b,TempValue); - result:=EqualityExpressionEquals(a,TempValue); - end; - function NumberAgainstString:boolean; - var TempValue:TBESENValue; - begin - ToNumberValue(b,TempValue); - result:=EqualityExpressionEquals(a,TempValue); - end; - function StringAgainstNumber:boolean; - var TempValue:TBESENValue; - begin - ToNumberValue(a,TempValue); - result:=EqualityExpressionEquals(TempValue,b); - end; - function StringNumberAgainstObject:boolean; - var TempValue:TBESENValue; - begin - ToPrimitiveValue(b,BESENUndefinedValue,TempValue); - result:=EqualityExpressionEquals(a,TempValue); - end; - function ObjectAgainstStringNumber:boolean; - var TempValue:TBESENValue; - begin - ToPrimitiveValue(a,BESENUndefinedValue,TempValue); - result:=EqualityExpressionEquals(TempValue,b); - end; -begin - if a.ValueType=b.ValueType then begin - case a.ValueType of - bvtUNDEFINED:begin - result:=true; - end; - bvtNULL:begin - result:=true; - end; - bvtNUMBER:begin -{$ifdef UseSafeOperations} - if BESENIsNaN(a.Num) then begin - result:=false; - end else if BESENIsNaN(b.Num) then begin - result:=false; - end else begin - result:=(a.Num=b.Num) or (BESENIsZero(a.Num) and BESENIsZero(b.Num)); - end; -{$else} - result:=(not (BESENIsNaN(a.Num) or BESENIsNaN(b.Num))) and (a.Num=b.Num); -{$endif} - end; - bvtSTRING:begin - result:=a.Str=b.Str; - end; - bvtBOOLEAN:begin - result:=a.Bool=b.Bool; - end; - bvtOBJECT:begin - result:=a.Obj=b.Obj; - end; - else begin - result:=false; - end; - end; - end else begin - if (a.ValueType=bvtNULL) and (b.ValueType=bvtUNDEFINED) then begin - result:=true; - end else if (a.ValueType=bvtUNDEFINED) and (b.ValueType=bvtNULL) then begin - result:=true; - end else if (a.ValueType=bvtNUMBER) and (b.ValueType=bvtSTRING) then begin - result:=NumberAgainstString; - end else if (a.ValueType=bvtSTRING) and (b.ValueType=bvtNUMBER) then begin - result:=StringAgainstNumber; - end else if a.ValueType=bvtBOOLEAN then begin - result:=BooleanAgainstAllAnother; - end else if b.ValueType=bvtBOOLEAN then begin - result:=AllAnotherAgainstBoolean; - end else if ((a.ValueType=bvtSTRING) or (a.ValueType=bvtNUMBER)) and (b.ValueType=bvtOBJECT) then begin - result:=StringNumberAgainstObject; - end else if (a.ValueType=bvtOBJECT) and ((b.ValueType=bvtSTRING) or (b.ValueType=bvtNUMBER)) then begin - result:=ObjectAgainstStringNumber; - end else begin - result:=false; - end; - end; -end; - -function TBESEN.EqualityExpressionCompare(const a,b:TBESENValue):integer; - function DoItSafe:integer; - var v:TBESENValue; - begin - try - EqualityExpressionSub(a,b,v); - if (v.ValueType=bvtBOOLEAN) and v.Bool then begin - result:=-1; - end else begin - result:=1; - end; - except - result:=0; - end; - end; - function DoItForNumbers:integer; - var n1,n2:TBESENNumber; - begin - n1:=a.Num; - n2:=b.Num; - if BESENIsNaN(n1) or BESENIsNaN(n2) then begin - result:=1; - end else if BESENIsSameValue(n1,n2) then begin - result:=1; - end else if (BESENIsZero(n1) and BESENIsZero(n2)) and (BESENIsNegative(n1)<>BESENIsNegative(n2)) then begin - result:=1; - end else if BESENIsPosInfinite(n1) then begin - result:=1; - end else if BESENIsPosInfinite(n2) then begin - result:=-1; - end else if BESENIsNegInfinite(n1) then begin - result:=-1; - end else if BESENIsNegInfinite(n2) then begin - result:=1; - end else begin - if n1<n2 then begin - result:=-1; - end else begin - result:=1; - end; - end; - end; -begin - if EqualityExpressionEquals(a,b) then begin - result:=0; - end else begin - if (a.ValueType=bvtNUMBER) and (b.ValueType=bvtNUMBER) then begin - result:=DoItForNumbers; - end else begin - result:=DoItSafe; - end; - end; -end; - -procedure TBESEN.FromPropertyDescriptor(const Descriptor:TBESENObjectPropertyDescriptor;var AResult:TBESENValue); -var bv:TBESENValue; -begin - if Descriptor.Presents=[] then begin - AResult:=BESENUndefinedValue; - end else begin - AResult:=BESENObjectValue(TBESENObject.Create(self,ObjectPrototype)); - bv.ValueType:=bvtBOOLEAN; - if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin - TBESENObject(AResult.Obj).OverwriteData('value',Descriptor.Value,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - bv.Bool:=bopaWRITABLE in Descriptor.Attributes; - TBESENObject(AResult.Obj).OverwriteData('writable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - if boppGETTER in Descriptor.Presents then begin - if assigned(Descriptor.Getter) then begin - TBESENObject(AResult.Obj).OverwriteData('get',BESENObjectValueEx(Descriptor.Getter),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - end else begin - TBESENObject(AResult.Obj).OverwriteData('get',BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - end; - end; - if boppSETTER in Descriptor.Presents then begin - if assigned(Descriptor.Setter) then begin - TBESENObject(AResult.Obj).OverwriteData('set',BESENObjectValueEx(Descriptor.Setter),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - end else begin - TBESENObject(AResult.Obj).OverwriteData('set',BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - end; - end; - end else begin - BESENFreeAndNil(AResult.Obj); - raise EBESENInternalError.Create('201003121938-0001'); - end; - GarbageCollector.Add(TBESENObject(AResult.Obj)); - TBESENObject(AResult.Obj).GarbageCollectorLock; - try - bv.Bool:=bopaENUMERABLE in Descriptor.Attributes; - TBESENObject(AResult.Obj).OverwriteData('enumerable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - bv.Bool:=bopaCONFIGURABLE in Descriptor.Attributes; - TBESENObject(AResult.Obj).OverwriteData('configurable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); - finally - TBESENObject(AResult.Obj).GarbageCollectorUnlock; - end; - end; -end; - -procedure TBESEN.ToPropertyDescriptor(const v:TBESENValue;var AResult:TBESENObjectPropertyDescriptor); -var t:TBESENValue; -begin - if not ((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj))) then begin - raise EBESENTypeError.Create('ToPropertyDescriptor failed'); - end; - AResult:=BESENUndefinedPropertyDescriptor; - if TBESENObject(v.Obj).Get('enumerable',t) then begin - if ToBool(t) then begin - AResult.Attributes:=AResult.Attributes+[bopaENUMERABLE]; - end; - AResult.Presents:=AResult.Presents+[boppENUMERABLE]; - end; - if TBESENObject(v.Obj).Get('configurable',t) then begin - if ToBool(t) then begin - AResult.Attributes:=AResult.Attributes+[bopaCONFIGURABLE]; - end; - AResult.Presents:=AResult.Presents+[boppCONFIGURABLE]; - end; - if TBESENObject(v.Obj).Get('value',AResult.Value) then begin - AResult.Presents:=AResult.Presents+[boppVALUE]; - end; - if TBESENObject(v.Obj).Get('writable',t) then begin - if ToBool(t) then begin - AResult.Attributes:=AResult.Attributes+[bopaWRITABLE]; - end; - AResult.Presents:=AResult.Presents+[boppWRITABLE]; - end; - if TBESENObject(v.Obj).Get('get',t) then begin - if BESENIsCallable(t) then begin - AResult.Getter:=TBESENObject(t.Obj); - end else if t.ValueType<>bvtUNDEFINED then begin - raise EBESENTypeError.Create('ToPropertyDescriptor failed'); - end; - AResult.Presents:=AResult.Presents+[boppGETTER]; - end; - if TBESENObject(v.Obj).Get('set',t) then begin - if BESENIsCallable(t) then begin - AResult.Setter:=TBESENObject(t.Obj); - end else if t.ValueType<>bvtUNDEFINED then begin - raise EBESENTypeError.Create('ToPropertyDescriptor failed'); - end; - AResult.Presents:=AResult.Presents+[boppSETTER]; - end; - if BESENIsInconsistentDescriptor(AResult) then begin - raise EBESENTypeError.Create('ToPropertyDescriptor failed'); - end; -end; - -function TBESEN.SameValue(const va,vb:TBESENValue):TBESENBoolean; -var vaNAN,vbNAN:boolean; -begin - if va.ValueType<>vb.ValueType then begin - result:=false; - end else begin - case va.ValueType of - bvtUNDEFINED:begin - result:=true; - end; - bvtNULL:begin - result:=true; - end; - bvtNUMBER:begin - vaNAN:=BESENIsNaN(va.Num); - vbNAN:=BESENIsNaN(vb.Num); - if vaNAN or vbNAN then begin - result:=vaNAN and vbNAN; - end else if (abs(va.Num)=0) and (abs(vb.Num)=0) then begin - result:=(int64(pointer(@va.Num)^) shr 63)=(int64(pointer(@vb.Num)^) shr 63); - end else begin - result:=(int64(pointer(@va.Num)^)=int64(pointer(@vb.Num)^)) or (va.Num=vb.Num); - end; - end; - bvtSTRING:begin - result:=va.Str=vb.Str; - end; - bvtBOOLEAN:begin - result:=va.Bool=vb.Bool; - end; - bvtOBJECT:begin - result:=va.Obj=vb.Obj; - end; - else begin - result:=false; - end; - end; - end; -end; - -function TBESEN.SameValue(const oa,ob:TBESENObject):TBESENBoolean; -begin - result:=oa=ob; -end; - -function TBESEN.SameObject(const oa,ob:TBESENObject):TBESENBoolean; -begin - result:=oa=ob; -end; - -procedure InitBESEN; -const BESENSignature:TBESENANSISTRING='BESEN - A ECMAScript 5th edition engine - Version '+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux - benjamin@rosseaux.com - http://www.rosseaux.com '; -begin - if length(BESENSignature)>0 then begin - BESENLengthHash:=BESENHashKey('length'); - end; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENASTNodes.pas b/3rd/besen/src/BESENASTNodes.pas deleted file mode 100644 index bc1877728..000000000 --- a/3rd/besen/src/BESENASTNodes.pas +++ /dev/null @@ -1,2191 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENASTNodes; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENGarbageCollector; - -const bntNONE=0; - bntEXPRESSION=1; - bntLITERAL=2; - bntIDENTIFIER=3; - bntVARIABLEDECLARATION=4; - bntVARIABLEEXPRESSION=5; - bntFUNCTIONBODY=6; - bntFUNCTIONLITERAL=7; - bntSTATEMENT=8; - bntVARIABLESTATEMENT=9; - bntFUNCTIONDECLARATION=10; - bntEXPRESSIONSTATEMENT=11; - bntEMPTYSTATEMENT=12; - bntBLOCKSTATEMENT=13; - bntDEBUGGERSTATEMENT=14; - bntBREAKSTATEMENT=15; - bntCONTINUESTATEMENT=16; - bntDOSTATEMENT=17; - bntWHILESTATEMENT=18; - bntWITHSTATEMENT=19; - bntFORSTATEMENT=20; - bntFORINSTATEMENT=21; - bntIFSTATEMENT=22; - bntLABELLEDSTATEMENT=23; - bntCASESTATEMENT=24; - bntSWITCHSTATEMENT=25; - bntTHROWSTATEMENT=26; - bntTRYSTATEMENT=27; - bntARRAYLITERAL=28; - bntBINARYEXPRESSION=29; - bntASSIGNMENTEXPRESSION=30; - bntASSIGNMENTOPERATOREXPRESSION=31; - bntASSIGNMENTMULTIPLYEXPRESSION=32; - bntASSIGNMENTDIVIDEEXPRESSION=33; - bntASSIGNMENTMODULOEXPRESSION=34; - bntASSIGNMENTPLUSEXPRESSION=35; - bntASSIGNMENTMINUSEXPRESSION=36; - bntASSIGNMENTSHIFTLEFTEXPRESSION=37; - bntASSIGNMENTSHIFTRIGHTEXPRESSION=38; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION=39; - bntASSIGNMENTBITWISEANDEXPRESSION=40; - bntASSIGNMENTBITWISEXOREXPRESSION=41; - bntASSIGNMENTBITWISEOREXPRESSION=42; - bntBINARYOPERATOREXPRESSION=43; - bntBINARYCOMMAEXPRESSION=44; - bntBINARYDIVIDEEXPRESSION=45; - bntBINARYMODULOEXPRESSION=46; - bntBINARYMULTIPLYEXPRESSION=47; - bntBINARYPLUSEXPRESSION=48; - bntBINARYMINUSEXPRESSION=49; - bntBINARYSHIFTLEFTEXPRESSION=50; - bntBINARYSHIFTRIGHTEXPRESSION=51; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION=52; - bntBINARYGREATERTHANEXPRESSION=53; - bntBINARYGREATERTHANOREQUALEXPRESSION=54; - bntBINARYLESSTHANEXPRESSION=55; - bntBINARYLESSTHANOREQUALEXPRESSION=56; - bntBINARYINSTANCEOFEXPRESSION=57; - bntBINARYINEXPRESSION=58; - bntBINARYEQUALEQUALEXPRESSION=59; - bntBINARYEQUALEQUALEQUALEXPRESSION=60; - bntBINARYNOTEQUALEXPRESSION=61; - bntBINARYNOTEQUALEQUALEXPRESSION=62; - bntBINARYBITWISEANDEXPRESSION=63; - bntBINARYBITWISEXOREXPRESSION=64; - bntBINARYBITWISEOREXPRESSION=65; - bntBOOLEANLITERAL=66; - bntCALLEXPRESSION=67; - bntNEWEXPRESSION=68; - bntCONDITIONALEXPRESSION=69; - bntUNARYEXPRESSION=70; - bntUNARYOPERATOREXPRESSION=71; - bntUNARYPLUSEXPRESSION=72; - bntUNARYMINUSEXPRESSION=73; - bntUNARYBITWISENOTEXPRESSION=74; - bntUNARYLOGICALNOTEXPRESSION=75; - bntUNARYVOIDEXPRESSION=76; - bntUNARYTYPEOFEXPRESSION=77; - bntPROPERTYEXPRESSION=78; - bntLOGICALANDEXPRESSION=79; - bntLOGICALOREXPRESSION=80; - bntDELETEEXPRESSION=81; - bntPOSTFIXINCEXPRESSION=82; - bntPOSTFIXDECEXPRESSION=83; - bntPREFIXINCEXPRESSION=84; - bntPREFIXDECEXPRESSION=85; - bntNULLLITERAL=86; - bntNUMBERLITERAL=87; - bntREGEXPLITERAL=88; - bntSTRINGLITERAL=89; - bntTHISLITERAL=90; - bntOBJECTLITERALPROPERTY=91; - bntOBJECTLITERAL=92; - bntRETURNSTATEMENT=93; - bntPROGRAM=94; - bntFUNCTIONEXPRESSION=95; - -type TBESENFunctionLiteralContainer=class; - - TBESENFunctionLiteralContainers=array of TBESENFunctionLiteralContainer; - - TBESENASTNodeFunctionLiteral=class; - - TBESENFunctionLiteralContainer=class(TBESENGarbageCollectorObject) - public - Literal:TBESENASTNodeFunctionLiteral; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - - TBESENASTNodeType=byte; - - TBESENASTNodeCodeGenData=record - RegNr:integer; - end; - - TBESENASTNode=class; - - TBESENASTNodes=array of TBESENASTNode; - - TBESENASTNode=class(TBESENCollectorObject) - public - NodeType:TBESENASTNodeType; - Target:TBESENTarget; - Location:TBESENLocation; - CodeGenData:TBESENASTNodeCodeGenData; - TrashNodes:TBESENASTNodes; - CountTrashNodes:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); virtual; - end; - - TBESENASTNodeClass=class of TBESENASTNode; - - TBESENASTNodeExpression=class(TBESENASTNode) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeExpressions=array of TBESENASTNodeExpression; - - TBESENASTNodeLiteral=class(TBESENASTNodeExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeIdentifier=class(TBESENASTNodeLiteral) - public - Name:TBESENString; - Index:integer; - ParameterIndex:integer; - ID:TBESENINT32; - IsParameter:longbool; - IsLocal:longbool; - IsReached:longbool; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeIdentifiers=array of TBESENASTNodeIdentifier; - - TBESENASTNodeVariableDeclaration=class(TBESENASTNodeExpression) - public - Identifier:TBESENASTNodeIdentifier; - Expression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeVariableDeclarations=array of TBESENASTNodeVariableDeclaration; - - TBESENASTNodeVariableExpression=class(TBESENASTNodeExpression) - public - Declarations:TBESENASTNodeVariableDeclarations; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeStatement=class; - - TBESENASTNodeStatements=array of TBESENASTNodeStatement; - - TBESENASTNodeBlockStatement=class; - - TBESENASTNodeFunctionBody=class(TBESENASTNode) - public - Variables:TBESENASTNodeIdentifiers; - Parameters:TBESENASTNodeIdentifiers; - Functions:TBESENASTNodeStatements; - Statements:TBESENASTNodeStatements; - IsFunction:longbool; - IsEmpty:longbool; - EnableLocalsOptimization:longbool; - DisableArgumentsObject:longbool; - IsStrict:longbool; - Code:TObject; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; - end; - - TBESENASTNodeFunctionLiteral=class(TBESENASTNodeLiteral) - public - Name:TBESENASTNodeIdentifier; - Container:TBESENFunctionLiteralContainer; - Body:TBESENASTNodeFunctionBody; - Index:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; - end; - - TBESENASTNodeStatement=class(TBESENASTNode) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeVariableStatement=class(TBESENASTNodeStatement) - public - Declarations:TBESENASTNodeVariableDeclarations; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeFunctionDeclaration=class(TBESENASTNodeStatement) - public - Container:TBESENFunctionLiteralContainer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeFunctionExpression=class(TBESENASTNodeExpression) - public - Container:TBESENFunctionLiteralContainer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeExpressionStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeEmptyStatement=class(TBESENASTNodeStatement) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBlockStatement=class(TBESENASTNodeStatement) - public - Statements:TBESENASTNodeStatements; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeDebuggerStatement=class(TBESENASTNodeStatement) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBreakStatement=class(TBESENASTNodeStatement) - public - Identifier:TBESENASTNodeIdentifier; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeContinueStatement=class(TBESENASTNodeStatement) - public - Identifier:TBESENASTNodeIdentifier; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeDoStatement=class(TBESENASTNodeStatement) - public - Statement:TBESENASTNodeStatement; - Expression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeWhileStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - Statement:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeWithStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - Statement:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeForStatement=class(TBESENASTNodeStatement) - public - Initial:TBESENASTNodeExpression; - Condition:TBESENASTNodeExpression; - Increment:TBESENASTNodeExpression; - Statement:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeForInStatement=class(TBESENASTNodeStatement) - public - Variable:TBESENASTNodeExpression; - Expression:TBESENASTNodeExpression; - Statement:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeIfStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - TrueStatement:TBESENASTNodeStatement; - FalseStatement:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeLabelledStatement=class(TBESENASTNodeStatement) - public - Identifiers:TBESENASTNodeIdentifiers; - Statement:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeCaseStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - Statements:TBESENASTNodeStatements; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeCaseStatements=array of TBESENASTNodeCaseStatement; - - TBESENASTNodeSwitchStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - CaseStatements:TBESENASTNodeCaseStatements; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeThrowStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeTryStatement=class(TBESENASTNodeStatement) - public - TryBlock:TBESENASTNodeStatement; - CatchIdentifier:TBESENASTNodeIdentifier; - CatchBlock:TBESENASTNodeStatement; - FinallyBlock:TBESENASTNodeStatement; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeArrayLiteral=class(TBESENASTNodeLiteral) - public - Elements:TBESENASTNodeExpressions; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryExpression=class(TBESENASTNodeExpression) - public - LeftExpression:TBESENASTNodeExpression; - RightExpression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentExpression=class(TBESENASTNodeBinaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentOperatorExpression=class(TBESENASTNodeBinaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentMultiplyExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentDivideExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentModuloExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentPlusExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentMinusExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentShiftLeftExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentShiftRightExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentShiftRightUnsignedExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentBitwiseAndExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentBitwiseXorExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeAssignmentBitwiseOrExpression=class(TBESENASTNodeAssignmentOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryOperatorExpression=class(TBESENASTNodeBinaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryCommaExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryDivideExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryModuloExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryMultiplyExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryPlusExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryMinusExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryShiftLeftExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryShiftRightExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryShiftRightUnsignedExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryGreaterThanExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryGreaterThanOrEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryLessThanExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryLessThanOrEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryInstanceOfExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryInExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryEqualEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryNotEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryNotEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryBitwiseAndExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryBitwiseXorExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBinaryBitwiseOrExpression=class(TBESENASTNodeBinaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeBooleanLiteral=class(TBESENASTNodeLiteral) - public - Value:longbool; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeCallExpression=class(TBESENASTNodeExpression) - public - TheFunction:TBESENASTNodeExpression; - Arguments:TBESENASTNodeExpressions; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeNewExpression=class(TBESENASTNodeExpression) - public - TheFunction:TBESENASTNodeExpression; - Arguments:TBESENASTNodeExpressions; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeConditionalExpression=class(TBESENASTNodeExpression) - public - Expression:TBESENASTNodeExpression; - TrueExpression:TBESENASTNodeExpression; - FalseExpression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryExpression=class(TBESENASTNodeExpression) - public - SubExpression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryOperatorExpression=class(TBESENASTNodeUnaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryPlusExpression=class(TBESENASTNodeUnaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryMinusExpression=class(TBESENASTNodeUnaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryBitwiseNotExpression=class(TBESENASTNodeUnaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryLogicalNotExpression=class(TBESENASTNodeUnaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryVoidExpression=class(TBESENASTNodeUnaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeUnaryTypeOfExpression=class(TBESENASTNodeUnaryOperatorExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodePropertyExpression=class(TBESENASTNodeBinaryExpression) - public - Dot:longbool; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeLogicalAndExpression=class(TBESENASTNodeBinaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeLogicalOrExpression=class(TBESENASTNodeBinaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeDeleteExpression=class(TBESENASTNodeUnaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodePostfixIncExpression=class(TBESENASTNodeUnaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodePostfixDecExpression=class(TBESENASTNodeUnaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodePrefixIncExpression=class(TBESENASTNodeUnaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodePrefixDecExpression=class(TBESENASTNodeUnaryExpression) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeNullLiteral=class(TBESENASTNodeLiteral) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeNumberLiteral=class(TBESENASTNodeLiteral) - public - Value:double; - Index:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeRegExpLiteral=class(TBESENASTNodeLiteral) - public - Source,Flags:TBESENString; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeStringLiteral=class(TBESENASTNodeLiteral) - public - Value:TBESENString; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeThisLiteral=class(TBESENASTNodeLiteral) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeObjectLiteralPropertyType=(banolptNONE,banolptACCESSOR,banolptDATA); - - TBESENASTNodeObjectLiteralPropertyAccessorType=(banolpatNONE,banolpatGET,banolpatSET); - - TBESENASTNodeObjectLiteralProperty=class(TBESENASTNodeLiteral) - public - PropertyType:TBESENASTNodeObjectLiteralPropertyType; - PropertyAccessorType:TBESENASTNodeObjectLiteralPropertyAccessorType; - Name:TBESENString; - Value:TBESENASTNodeExpression; - Container:TBESENFunctionLiteralContainer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeObjectLiteralProperties=array of TBESENASTNodeObjectLiteralProperty; - - TBESENASTNodeObjectLiteral=class(TBESENASTNodeLiteral) - public - Properties:TBESENASTNodeObjectLiteralProperties; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeReturnStatement=class(TBESENASTNodeStatement) - public - Expression:TBESENASTNodeExpression; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENASTNodeProgram=class(TBESENASTNode) - public - Body:TBESENASTNodeFunctionBody; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; - end; - -implementation - -uses BESEN,BESENUtils,BESENCode; - -constructor TBESENFunctionLiteralContainer.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Literal:=nil; -end; - -destructor TBESENFunctionLiteralContainer.Destroy; -begin - BESENFreeAndNil(Literal); - inherited Destroy; -end; - -procedure TBESENFunctionLiteralContainer.Finalize; -begin - if assigned(Literal) then begin - Literal.Container:=nil; - BESENFreeAndNil(Literal); - end; - inherited Finalize; -end; - -procedure TBESENFunctionLiteralContainer.Mark; -begin - inherited Mark; - if (assigned(Literal) and assigned(Literal.Body)) and assigned(Literal.Body.Code) then begin - TBESENCode(Literal.Body.Code).Mark; - end; -end; - -constructor TBESENASTNode.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntNONE; - Target:=-1; - Location.LineNumber:=-1; - fillchar(CodeGenData,sizeof(TBESENASTNodeCodeGenData),#0); - TrashNodes:=nil; - CountTrashNodes:=0; -end; - -destructor TBESENASTNode.Destroy; -var i:integer; -begin - for i:=0 to CountTrashNodes-1 do begin - BESENFreeAndNil(TrashNodes[i]); - end; - SetLength(TrashNodes,0); - inherited Destroy; -end; - -procedure TBESENASTNode.ExecuteCode(const Context:TObject;var AResult:TBESENValue); -begin - AResult:=BESENUndefinedValue; -end; - -constructor TBESENASTNodeExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntEXPRESSION; -end; - -destructor TBESENASTNodeExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntLITERAL; -end; - -destructor TBESENASTNodeLiteral.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeIdentifier.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntIDENTIFIER; - Name:=''; - Index:=-1; - ParameterIndex:=-1; - ID:=-1; - IsParameter:=false; - IsLocal:=false; - IsReached:=false; -end; - -destructor TBESENASTNodeIdentifier.Destroy; -begin - Name:=''; - inherited Destroy; -end; - -constructor TBESENASTNodeVariableDeclaration.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntVARIABLEDECLARATION; - Identifier:=nil; - Expression:=nil; -end; - -destructor TBESENASTNodeVariableDeclaration.Destroy; -begin - Identifier.Free; - Expression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeVariableExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntVARIABLEEXPRESSION; - Declarations:=nil; -end; - -destructor TBESENASTNodeVariableExpression.Destroy; -var i:integer; -begin - for i:=0 to length(Declarations)-1 do begin - BESENFreeAndNil(Declarations[i]); - end; - SetLength(Declarations,0); - inherited Destroy; -end; - -constructor TBESENASTNodeVariableStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntVARIABLESTATEMENT; - Declarations:=nil; -end; - -destructor TBESENASTNodeVariableStatement.Destroy; -var i:integer; -begin - for i:=0 to length(Declarations)-1 do begin - BESENFreeAndNil(Declarations[i]); - end; - SetLength(Declarations,0); - inherited Destroy; -end; - -constructor TBESENASTNodeFunctionBody.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntFUNCTIONBODY; - Variables:=nil; - Parameters:=nil; - Functions:=nil; - Statements:=nil; - IsFunction:=false; - IsEmpty:=false; - EnableLocalsOptimization:=false; - DisableArgumentsObject:=false; - IsStrict:=false; - Code:=TBESENCode.Create(Instance); - TBESENCode(Code).Body:=self; -end; - -destructor TBESENASTNodeFunctionBody.Destroy; -var i:integer; -begin -{$ifdef BESENEmbarcaderoNextGen} - Code:=nil; -{$else} - Code.Free; -{$endif} - for i:=0 to length(Parameters)-1 do begin - BESENFreeAndNil(Parameters[i]); - end; - for i:=0 to length(Functions)-1 do begin - BESENFreeAndNil(Functions[i]); - end; - for i:=0 to length(Statements)-1 do begin - BESENFreeAndNil(Statements[i]); - end; - SetLength(Parameters,0); - SetLength(Variables,0); - SetLength(Functions,0); - SetLength(Statements,0); - inherited Destroy; -end; - -procedure TBESENASTNodeFunctionBody.ExecuteCode(const Context:TObject;var AResult:TBESENValue); -begin - TBESENCode(Code).Execute(Context,AResult); -end; - -constructor TBESENASTNodeFunctionLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntFUNCTIONLITERAL; - Name:=nil; - Container:=TBESENFunctionLiteralContainer.Create(Instance); - Container.Literal:=self; - Body:=TBESENASTNodeFunctionBody.Create(Instance); - Body.IsFunction:=true; - Index:=-1; -end; - -destructor TBESENASTNodeFunctionLiteral.Destroy; -begin - BESENFreeAndNil(Name); - BESENFreeAndNil(Body); - if assigned(Container) then begin - Container.Literal:=nil; - BESENFreeAndNil(Container); - end; - inherited Destroy; -end; - -procedure TBESENASTNodeFunctionLiteral.ExecuteCode(const Context:TObject;var AResult:TBESENValue); -begin - if assigned(Container) then begin - Container.GarbageCollectorLock; - try - Body.ExecuteCode(Context,AResult); - finally - Container.GarbageCollectorUnlock; - end; - end else begin - Body.ExecuteCode(Context,AResult); - end; -end; - -constructor TBESENASTNodeStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntSTATEMENT; -end; - -destructor TBESENASTNodeStatement.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeFunctionDeclaration.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntFUNCTIONDECLARATION; - Container:=nil; -end; - -destructor TBESENASTNodeFunctionDeclaration.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeFunctionExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntFUNCTIONEXPRESSION; - Container:=nil; -end; - -destructor TBESENASTNodeFunctionExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeExpressionStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntEXPRESSIONSTATEMENT; - Expression:=nil; -end; - -destructor TBESENASTNodeExpressionStatement.Destroy; -begin - Expression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeEmptyStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntEMPTYSTATEMENT; -end; - -destructor TBESENASTNodeEmptyStatement.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBlockStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBLOCKSTATEMENT; - Statements:=nil; -end; - -destructor TBESENASTNodeBlockStatement.Destroy; -var i:integer; -begin - for i:=0 to length(Statements)-1 do begin - BESENFreeAndNil(Statements[i]); - end; - SetLength(Statements,0); - inherited Destroy; -end; - -constructor TBESENASTNodeDebuggerStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntDEBUGGERSTATEMENT; -end; - -destructor TBESENASTNodeDebuggerStatement.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBreakStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBREAKSTATEMENT; - Identifier:=nil; -end; - -destructor TBESENASTNodeBreakStatement.Destroy; -begin - Identifier.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeContinueStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntCONTINUESTATEMENT; - Identifier:=nil; -end; - -destructor TBESENASTNodeContinueStatement.Destroy; -begin - Identifier.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeDoStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntDOSTATEMENT; - Statement:=nil; - Expression:=nil; -end; - -destructor TBESENASTNodeDoStatement.Destroy; -begin - Statement.Free; - Expression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeWhileStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntWHILESTATEMENT; - Expression:=nil; - Statement:=nil; -end; - -destructor TBESENASTNodeWhileStatement.Destroy; -begin - Expression.Free; - Statement.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeWithStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntWITHSTATEMENT; - Expression:=nil; - Statement:=nil; -end; - -destructor TBESENASTNodeWithStatement.Destroy; -begin - Expression.Free; - Statement.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeForStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntFORSTATEMENT; - Initial:=nil; - Condition:=nil; - Increment:=nil; - Statement:=nil; -end; - -destructor TBESENASTNodeForStatement.Destroy; -begin - Initial.Free; - Condition.Free; - Increment.Free; - Statement.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeForInStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntFORINSTATEMENT; - Variable:=nil; - Expression:=nil; - Statement:=nil; -end; - -destructor TBESENASTNodeForInStatement.Destroy; -begin - Variable.Free; - Expression.Free; - Statement.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeIfStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntIFSTATEMENT; - Expression:=nil; - TrueStatement:=nil; - FalseStatement:=nil; -end; - -destructor TBESENASTNodeIfStatement.Destroy; -begin - Expression.Free; - TrueStatement.Free; - FalseStatement.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeLabelledStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntLABELLEDSTATEMENT; - Identifiers:=nil; - Statement:=nil; -end; - -destructor TBESENASTNodeLabelledStatement.Destroy; -var i:integer; -begin - for i:=0 to length(Identifiers)-1 do begin - BESENFreeAndNil(Identifiers[i]); - end; - SetLength(Identifiers,0); - BESENFreeAndNil(Statement); - inherited Destroy; -end; - -constructor TBESENASTNodeCaseStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntCASESTATEMENT; - Expression:=nil; - Statements:=nil; -end; - -destructor TBESENASTNodeCaseStatement.Destroy; -var i:integer; -begin - BESENFreeAndNil(Expression); - for i:=0 to length(Statements)-1 do begin - BESENFreeAndNil(Statements[i]); - end; - SetLength(Statements,0); - inherited Destroy; -end; - -constructor TBESENASTNodeSwitchStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntSWITCHSTATEMENT; - Expression:=nil; - CaseStatements:=nil; -end; - -destructor TBESENASTNodeSwitchStatement.Destroy; -var i:integer; -begin - Expression.Free; - for i:=0 to length(CaseStatements)-1 do begin - BESENFreeAndNil(CaseStatements[i]); - end; - SetLength(CaseStatements,0); - inherited Destroy; -end; - -constructor TBESENASTNodeThrowStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntTHROWSTATEMENT; - Expression:=nil; -end; - -destructor TBESENASTNodeThrowStatement.Destroy; -begin - Expression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeTryStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntTRYSTATEMENT; - TryBlock:=nil; - CatchIdentifier:=nil; - CatchBlock:=nil; - FinallyBlock:=nil; -end; - -destructor TBESENASTNodeTryStatement.Destroy; -begin - TryBlock.Free; - CatchIdentifier.Free; - CatchBlock.Free; - FinallyBlock.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeArrayLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntARRAYLITERAL; - Elements:=nil; -end; - -destructor TBESENASTNodeArrayLiteral.Destroy; -var i:integer; -begin - for i:=0 to length(Elements)-1 do begin - BESENFreeAndNil(Elements[i]); - end; - SetLength(Elements,0); - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYEXPRESSION; - LeftExpression:=nil; - RightExpression:=nil; -end; - -destructor TBESENASTNodeBinaryExpression.Destroy; -begin - LeftExpression.Free; - RightExpression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentOperatorExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTOPERATOREXPRESSION; -end; - -destructor TBESENASTNodeAssignmentOperatorExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentMultiplyExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTMULTIPLYEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentMultiplyExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentDivideExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTDIVIDEEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentDivideExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentModuloExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTMODULOEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentModuloExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentPlusExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTPLUSEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentPlusExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentMinusExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTMINUSEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentMinusExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentShiftLeftExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTSHIFTLEFTEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentShiftLeftExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentShiftRightExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTSHIFTRIGHTEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentShiftRightExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentShiftRightUnsignedExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentShiftRightUnsignedExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentBitwiseAndExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTBITWISEANDEXPRESSION; -end; - -destructor TBESENASTNodeAssignmentBitwiseAndExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentBitwiseXorExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTBITWISEXOREXPRESSION; -end; - -destructor TBESENASTNodeAssignmentBitwiseXorExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeAssignmentBitwiseOrExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntASSIGNMENTBITWISEOREXPRESSION; -end; - -destructor TBESENASTNodeAssignmentBitwiseOrExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryOperatorExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYOPERATOREXPRESSION; -end; - -destructor TBESENASTNodeBinaryOperatorExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryCommaExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYCOMMAEXPRESSION; -end; - -destructor TBESENASTNodeBinaryCommaExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryDivideExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYDIVIDEEXPRESSION; -end; - -destructor TBESENASTNodeBinaryDivideExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryModuloExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYMODULOEXPRESSION; -end; - -destructor TBESENASTNodeBinaryModuloExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryMultiplyExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYMULTIPLYEXPRESSION; -end; - -destructor TBESENASTNodeBinaryMultiplyExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryPlusExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYPLUSEXPRESSION; -end; - -destructor TBESENASTNodeBinaryPlusExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryMinusExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYMINUSEXPRESSION; -end; - -destructor TBESENASTNodeBinaryMinusExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryShiftLeftExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYSHIFTLEFTEXPRESSION; -end; - -destructor TBESENASTNodeBinaryShiftLeftExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryShiftRightExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYSHIFTRIGHTEXPRESSION; -end; - -destructor TBESENASTNodeBinaryShiftRightExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryShiftRightUnsignedExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION; -end; - -destructor TBESENASTNodeBinaryShiftRightUnsignedExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryGreaterThanExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYGREATERTHANEXPRESSION; -end; - -destructor TBESENASTNodeBinaryGreaterThanExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryGreaterThanOrEqualExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYGREATERTHANOREQUALEXPRESSION; -end; - -destructor TBESENASTNodeBinaryGreaterThanOrEqualExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryLessThanExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYLESSTHANEXPRESSION; -end; - -destructor TBESENASTNodeBinaryLessThanExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryLessThanOrEqualExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYLESSTHANOREQUALEXPRESSION; -end; - -destructor TBESENASTNodeBinaryLessThanOrEqualExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryInstanceOfExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYINSTANCEOFEXPRESSION; -end; - -destructor TBESENASTNodeBinaryInstanceOfExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryInExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYINEXPRESSION; -end; - -destructor TBESENASTNodeBinaryInExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryEqualEqualExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYEQUALEQUALEXPRESSION; -end; - -destructor TBESENASTNodeBinaryEqualEqualExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryEqualEqualEqualExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYEQUALEQUALEQUALEXPRESSION; -end; - -destructor TBESENASTNodeBinaryEqualEqualEqualExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryNotEqualExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYNOTEQUALEXPRESSION; -end; - -destructor TBESENASTNodeBinaryNotEqualExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryNotEqualEqualExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYNOTEQUALEQUALEXPRESSION; -end; - -destructor TBESENASTNodeBinaryNotEqualEqualExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryBitwiseAndExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYBITWISEANDEXPRESSION; -end; - -destructor TBESENASTNodeBinaryBitwiseAndExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryBitwiseXorExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYBITWISEXOREXPRESSION; -end; - -destructor TBESENASTNodeBinaryBitwiseXorExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBinaryBitwiseOrExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBINARYBITWISEOREXPRESSION; -end; - -destructor TBESENASTNodeBinaryBitwiseOrExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeBooleanLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntBOOLEANLITERAL; - Value:=false; -end; - -destructor TBESENASTNodeBooleanLiteral.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeCallExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntCALLEXPRESSION; - TheFunction:=nil; - Arguments:=nil; -end; - -destructor TBESENASTNodeCallExpression.Destroy; -var i:integer; -begin - TheFunction.Free; - for i:=0 to length(Arguments)-1 do begin - BESENFreeAndNil(Arguments[i]); - end; - SetLength(Arguments,0); - inherited Destroy; -end; - -constructor TBESENASTNodeNewExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntNEWEXPRESSION; - TheFunction:=nil; - Arguments:=nil; -end; - -destructor TBESENASTNodeNewExpression.Destroy; -var i:integer; -begin - TheFunction.Free; - for i:=0 to length(Arguments)-1 do begin - BESENFreeAndNil(Arguments[i]); - end; - SetLength(Arguments,0); - inherited Destroy; -end; - -constructor TBESENASTNodeConditionalExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntCONDITIONALEXPRESSION; - Expression:=nil; - TrueExpression:=nil; - FalseExpression:=nil; -end; - -destructor TBESENASTNodeConditionalExpression.Destroy; -begin - BESENFreeAndNil(Expression); - BESENFreeAndNil(TrueExpression); - BESENFreeAndNil(FalseExpression); - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYEXPRESSION; - SubExpression:=nil; -end; - -destructor TBESENASTNodeUnaryExpression.Destroy; -begin - SubExpression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryOperatorExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYOPERATOREXPRESSION; -end; - -destructor TBESENASTNodeUnaryOperatorExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryPlusExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYPLUSEXPRESSION; -end; - -destructor TBESENASTNodeUnaryPlusExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryMinusExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYMINUSEXPRESSION; -end; - -destructor TBESENASTNodeUnaryMinusExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryBitwiseNotExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYBITWISENOTEXPRESSION; -end; - -destructor TBESENASTNodeUnaryBitwiseNotExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryLogicalNotExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYLOGICALNOTEXPRESSION; -end; - -destructor TBESENASTNodeUnaryLogicalNotExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryVoidExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYVOIDEXPRESSION; -end; - -destructor TBESENASTNodeUnaryVoidExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeUnaryTypeOfExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntUNARYTYPEOFEXPRESSION; -end; - -destructor TBESENASTNodeUnaryTypeOfExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodePropertyExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntPROPERTYEXPRESSION; - Dot:=false; -end; - -destructor TBESENASTNodePropertyExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeLogicalAndExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntLOGICALANDEXPRESSION; -end; - -destructor TBESENASTNodeLogicalAndExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeLogicalOrExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntLOGICALOREXPRESSION; -end; - -destructor TBESENASTNodeLogicalOrExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeDeleteExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntDELETEEXPRESSION; -end; - -destructor TBESENASTNodeDeleteExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodePostfixIncExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntPOSTFIXINCEXPRESSION; -end; - -destructor TBESENASTNodePostfixIncExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodePostfixDecExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntPOSTFIXDECEXPRESSION; -end; - -destructor TBESENASTNodePostfixDecExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodePrefixIncExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntPREFIXINCEXPRESSION; -end; - -destructor TBESENASTNodePrefixIncExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodePrefixDecExpression.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntPREFIXDECEXPRESSION; -end; - -destructor TBESENASTNodePrefixDecExpression.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeNullLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntNULLLITERAL; -end; - -destructor TBESENASTNodeNullLiteral.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeNumberLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntNUMBERLITERAL; - Value:=0; - Index:=0; -end; - -destructor TBESENASTNodeNumberLiteral.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeRegExpLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntREGEXPLITERAL; - Source:=''; - Flags:=''; -end; - -destructor TBESENASTNodeRegExpLiteral.Destroy; -begin - Source:=''; - Flags:=''; - inherited Destroy; -end; - -constructor TBESENASTNodeStringLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntSTRINGLITERAL; - Value:=''; -end; - -destructor TBESENASTNodeStringLiteral.Destroy; -begin - Value:=''; - inherited Destroy; -end; - -constructor TBESENASTNodeThisLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntTHISLITERAL; -end; - -destructor TBESENASTNodeThisLiteral.Destroy; -begin - inherited Destroy; -end; - -constructor TBESENASTNodeObjectLiteralProperty.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntOBJECTLITERALPROPERTY; - PropertyType:=banolptNONE; - PropertyAccessorType:=banolpatNONE; - Name:=''; - Value:=nil; - Container:=nil; -end; - -destructor TBESENASTNodeObjectLiteralProperty.Destroy; -begin - BESENFreeAndNil(Value); - Name:=''; - inherited Destroy; -end; - -constructor TBESENASTNodeObjectLiteral.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntOBJECTLITERAL; - Properties:=nil; -end; - -destructor TBESENASTNodeObjectLiteral.Destroy; -var i:integer; -begin - for i:=0 to length(Properties)-1 do begin - BESENFreeAndNil(Properties[i]); - end; - SetLength(Properties,0); - inherited Destroy; -end; - -constructor TBESENASTNodeReturnStatement.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntRETURNSTATEMENT; - Expression:=nil; -end; - -destructor TBESENASTNodeReturnStatement.Destroy; -begin - Expression.Free; - inherited Destroy; -end; - -constructor TBESENASTNodeProgram.Create(AInstance:TObject); -begin - inherited Create(AInstance); - NodeType:=bntPROGRAM; - Body:=TBESENASTNodeFunctionBody.Create(Instance); - Body.IsFunction:=false; -end; - -destructor TBESENASTNodeProgram.Destroy; -begin - if assigned(Instance) then begin - TBESEN(Instance).RemoveProgramNode(self); - end; - BESENFreeAndNil(Body); - inherited Destroy; -end; - -procedure TBESENASTNodeProgram.ExecuteCode(const Context:TObject;var AResult:TBESENValue); -begin - Body.ExecuteCode(Context,AResult); -end; - -end. diff --git a/3rd/besen/src/BESENArrayUtils.pas b/3rd/besen/src/BESENArrayUtils.pas deleted file mode 100644 index b43983dc0..000000000 --- a/3rd/besen/src/BESENArrayUtils.pas +++ /dev/null @@ -1,123 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENArrayUtils; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue; - -function BESENArrayToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; -function BESENArrayToIndexEx(AProp:TBESENString):int64; -function BESENArrayIndexToStr(v:TBESENUINT32):TBESENString; -procedure BESENArrayCheckTooLong(const a,b:TBESENUINT32); - -implementation - -uses BESEN,BESENUtils,BESENErrors; - -function BESENArrayToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; -var i:integer; -begin - if length(AProp)=0 then begin - result:=false; - end else if (length(AProp)>1) and (AProp[1]='0') then begin - result:=false; - end else begin - result:=true; - v:=0; - for i:=1 to length(AProp) do begin - if (word(widechar(AProp[i]))>=ord('0')) and (word(widechar(AProp[i]))<=ord('9')) then begin - v:=(v*10)+(word(widechar(AProp[i]))-ord('0')); - end else begin - result:=false; - break; - end; - end; - if result and ((IntToStr(v and $ffffffff)<>AProp) or (v>=$ffffffff)) then begin - result:=false; - end; - end; -end; - -function BESENArrayToIndexEx(AProp:TBESENString):int64; -var i:integer; -begin - if length(AProp)=0 then begin - result:=0; - end else if (length(AProp)>1) and (AProp[1]='0') then begin - result:=0; - end else begin - result:=0; - for i:=1 to length(AProp) do begin - if (word(widechar(AProp[i]))>=ord('0')) and (word(widechar(AProp[i]))<=ord('9')) then begin - result:=(result*10)+(word(widechar(AProp[i]))-ord('0')); - end else begin - result:=0; - break; - end; - end; - end; -end; - -function BESENArrayIndexToStr(v:TBESENUINT32):TBESENString; -var i:integer; - o:TBESENUINT32; -begin - if v=0 then begin - result:='0'; - end else begin - result:=''; - i:=0; - o:=v; - while o<>0 do begin - inc(i); - o:=o div 10; - end; - SetLength(result,i); - while (v<>0) and (i>0) do begin - result[i]:=widechar(word(v mod 10)+ord('0')); - dec(i); - v:=v div 10; - end; - end; -end; - -procedure BESENArrayCheckTooLong(const a,b:TBESENUINT32); -var c:TBESENUINT32; -begin - c:=TBESENUINT32(a+b) and $ffffffff; - if (c<a) or (c<b) then begin - BESENThrowRangeError('Array too long'); - end; -end; - -end. diff --git a/3rd/besen/src/BESENBaseObject.pas b/3rd/besen/src/BESENBaseObject.pas deleted file mode 100644 index bbc3cbdf6..000000000 --- a/3rd/besen/src/BESENBaseObject.pas +++ /dev/null @@ -1,59 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENBaseObject; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -type TBESENBaseObject=class(TObject) - public - Instance:TObject; - constructor Create(AInstance:TObject); overload; virtual; - destructor Destroy; override; - end; - -implementation - -constructor TBESENBaseObject.Create(AInstance:TObject); -begin - inherited Create; - Instance:=AInstance; -end; - -destructor TBESENBaseObject.Destroy; -begin - inherited Destroy; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENCharset.pas b/3rd/besen/src/BESENCharset.pas deleted file mode 100644 index 3ef487e46..000000000 --- a/3rd/besen/src/BESENCharset.pas +++ /dev/null @@ -1,421 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCharset; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -type TBESENCharBitmap=array[0..$f] of byte; - - TBESENCharset=(ISO_8859_1,ISO_8859_2,ISO_8859_3,ISO_8859_4,ISO_8859_5, - ISO_8859_6,ISO_8859_7,ISO_8859_8,ISO_8859_9,ISO_8859_10, - CP1250,CP1251,CP1252,CP1253,CP1254,CP1255,CP1256,CP1257,CP1258, - KOI8_R,UCS_2,UCS_4,UTF_32,UTF_16,UTF_8,UTF_7); - - TBESENCharsetSet=set of TBESENCharset; - - TBESENCharsetTable=array[128..255] of word; - - TBESENCharsetTableCasted=array[128..255] of widechar; - -const BESENAllCharsets:TBESENCharsetSet=[ISO_8859_1,ISO_8859_2,ISO_8859_3,ISO_8859_4, - ISO_8859_5,ISO_8859_6,ISO_8859_7,ISO_8859_8, - ISO_8859_9,ISO_8859_10,CP1250,CP1251,CP1252, - CP1253,CP1254,CP1255,CP1256,CP1257,CP1258, - KOI8_R,UCS_2,UCS_4,UTF_32,UTF_16,UTF_8,UTF_7]; - - BESENCharISO_8859_1:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, - $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, - $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, - $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, - $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, - $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, - $00D0,$00D1,$00D2,$00D3,$00D4,$00D5,$00D6,$00D7, - $00D8,$00D9,$00DA,$00DB,$00DC,$00DD,$00DE,$00DF, - $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, - $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, - $00F0,$00F1,$00F2,$00F3,$00F4,$00F5,$00F6,$00F7, - $00F8,$00F9,$00FA,$00FB,$00FC,$00FD,$00FE,$00FF); - - BESENCharISO_8859_2:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$0104,$02d8,$0141,$00a4,$013d,$015a,$00a7, - $00a8,$0160,$015e,$0164,$0179,$00ad,$017d,$017b, - $00b0,$0105,$02db,$0142,$00b4,$013e,$015b,$02c7, - $00b8,$0161,$015f,$0165,$017a,$02dd,$017e,$017c, - $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, - $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, - $0110,$0143,$0147,$00d3,$00d4,$0150,$00d6,$00d7, - $0158,$016e,$00da,$0170,$00dc,$00dd,$0162,$00df, - $0155,$00e1,$00e2,$0103,$00e4,$013a,$0107,$00e7, - $010d,$00e9,$0119,$00eb,$011b,$00ed,$00ee,$010f, - $0111,$0144,$0148,$00f3,$00f4,$0151,$00f6,$00f7, - $0159,$016f,$00fa,$0171,$00fc,$00fd,$0163,$02d9); - - BESENCharISO_8859_3:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$0126,$02d8,$00a3,$00a4,$fffd,$0124,$00a7, - $00a8,$0130,$015e,$011e,$0134,$00ad,$fffd,$017b, - $00b0,$0127,$00b2,$00b3,$00b4,$00b5,$0125,$00b7, - $00b8,$0131,$015f,$011f,$0135,$00bd,$fffd,$017c, - $00c0,$00c1,$00c2,$fffd,$00c4,$010a,$0108,$00c7, - $00c8,$00c9,$00ca,$00cb,$00cc,$00cd,$00ce,$00cf, - $fffd,$00d1,$00d2,$00d3,$00d4,$0120,$00d6,$00d7, - $011c,$00d9,$00da,$00db,$00dc,$016c,$015c,$00df, - $00e0,$00e1,$00e2,$fffd,$00e4,$010b,$0109,$00e7, - $00e8,$00e9,$00ea,$00eb,$00ec,$00ed,$00ee,$00ef, - $fffd,$00f1,$00f2,$00f3,$00f4,$0121,$00f6,$00f7, - $011d,$00f9,$00fa,$00fb,$00fc,$016d,$015d,$02d9); - - BESENCharISO_8859_4:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$0104,$0138,$0156,$00a4,$0128,$013b,$00a7, - $00a8,$0160,$0112,$0122,$0166,$00ad,$017d,$00af, - $00b0,$0105,$02db,$0157,$00b4,$0129,$013c,$02c7, - $00b8,$0161,$0113,$0123,$0167,$014a,$017e,$014b, - $0100,$00c1,$00c2,$00c3,$00c4,$00c5,$00c6,$012e, - $010c,$00c9,$0118,$00cb,$0116,$00cd,$00ce,$012a, - $0110,$0145,$014c,$0136,$00d4,$00d5,$00d6,$00d7, - $00d8,$0172,$00da,$00db,$00dc,$0168,$016a,$00df, - $0101,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$012f, - $010d,$00e9,$0119,$00eb,$0117,$00ed,$00ee,$012b, - $0111,$0146,$014d,$0137,$00f4,$00f5,$00f6,$00f7, - $00f8,$0173,$00fa,$00fb,$00fc,$0169,$016b,$02d9); - - BESENCharISO_8859_5:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$0401,$0402,$0403,$0404,$0405,$0406,$0407, - $0408,$0409,$040a,$040b,$040c,$00ad,$040e,$040f, - $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417, - $0418,$0419,$041a,$041b,$041c,$041d,$041e,$041f, - $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427, - $0428,$0429,$042a,$042b,$042c,$042d,$042e,$042f, - $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437, - $0438,$0439,$043a,$043b,$043c,$043d,$043e,$043f, - $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447, - $0448,$0449,$044a,$044b,$044c,$044d,$044e,$044f, - $2116,$0451,$0452,$0453,$0454,$0455,$0456,$0457, - $0458,$0459,$045a,$045b,$045c,$00a7,$045e,$045f); - - BESENCharISO_8859_6:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$fffd,$fffd,$fffd,$00a4,$fffd,$fffd,$fffd, - $fffd,$fffd,$fffd,$fffd,$060c,$00ad,$fffd,$fffd, - $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, - $fffd,$fffd,$fffd,$061b,$fffd,$fffd,$fffd,$061f, - $fffd,$0621,$0622,$0623,$0624,$0625,$0626,$0627, - $0628,$0629,$062a,$062b,$062c,$062d,$062e,$062f, - $0630,$0631,$0632,$0633,$0634,$0635,$0636,$0637, - $0638,$0639,$063a,$fffd,$fffd,$fffd,$fffd,$fffd, - $0640,$0641,$0642,$0643,$0644,$0645,$0646,$0647, - $0648,$0649,$064a,$064b,$064c,$064d,$064e,$064f, - $0650,$0651,$0652,$fffd,$fffd,$fffd,$fffd,$fffd, - $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd); - - BESENCharISO_8859_7:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$2018,$2019,$00a3,$fffd,$fffd,$00a6,$00a7, - $00a8,$00a9,$fffd,$00ab,$00ac,$00ad,$fffd,$2015, - $00b0,$00b1,$00b2,$00b3,$0384,$0385,$0386,$00b7, - $0388,$0389,$038a,$00bb,$038c,$00bd,$038e,$038f, - $0390,$0391,$0392,$0393,$0394,$0395,$0396,$0397, - $0398,$0399,$039a,$039b,$039c,$039d,$039e,$039f, - $03a0,$03a1,$fffd,$03a3,$03a4,$03a5,$03a6,$03a7, - $03a8,$03a9,$03aa,$03ab,$03ac,$03ad,$03ae,$03af, - $03b0,$03b1,$03b2,$03b3,$03b4,$03b5,$03b6,$03b7, - $03b8,$03b9,$03ba,$03bb,$03bc,$03bd,$03be,$03bf, - $03c0,$03c1,$03c2,$03c3,$03c4,$03c5,$03c6,$03c7, - $03c8,$03c9,$03ca,$03cb,$03cc,$03cd,$03ce,$fffd); - - BESENCharISO_8859_8:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$fffd,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, - $00a8,$00a9,$00d7,$00ab,$00ac,$00ad,$00ae,$00af, - $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, - $00b8,$00b9,$00f7,$00bb,$00bc,$00bd,$00be,$fffd, - $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, - $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, - $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, - $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$2017, - $05d0,$05d1,$05d2,$05d3,$05d4,$05d5,$05d6,$05d7, - $05d8,$05d9,$05da,$05db,$05dc,$05dd,$05de,$05df, - $05e0,$05e1,$05e2,$05e3,$05e4,$05e5,$05e6,$05e7, - $05e8,$05e9,$05ea,$fffd,$fffd,$200e,$200f,$fffd); - - BESENCharISO_8859_9:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$0104,$02d8,$0141,$00a4,$013d,$015a,$00a7, - $00a8,$0160,$015e,$0164,$0179,$00ad,$017d,$017b, - $00b0,$0105,$02db,$0142,$00b4,$013e,$015b,$02c7, - $00b8,$0161,$015f,$0165,$017a,$02dd,$017e,$017c, - $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, - $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, - $011e,$00d1,$00d2,$00d3,$00d4,$00d5,$00d6,$00d7, - $00d8,$00d9,$00da,$00db,$00dc,$0130,$015e,$00df, - $00e0,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$00e7, - $00e8,$00e9,$00ea,$00eb,$00ec,$00ed,$00ee,$00ef, - $011f,$00f1,$00f2,$00f3,$00f4,$00f5,$00f6,$00f7, - $00f8,$00f9,$00fa,$00fb,$00fc,$0131,$015f,$00ff); - - BESENCharISO_8859_10:TBESENCharsetTable= - ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, - $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, - $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, - $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, - $00a0,$0104,$0112,$0122,$012a,$0128,$0136,$00a7, - $013b,$0110,$0160,$0166,$017d,$00ad,$016a,$014a, - $00b0,$0105,$0113,$0123,$012b,$0129,$0137,$00b7, - $013c,$0111,$0161,$0167,$017e,$2015,$016b,$014b, - $0100,$00c1,$00c2,$00c3,$00c4,$00c5,$00c6,$012e, - $010c,$00c9,$0118,$00cb,$0116,$00cd,$00ce,$00cf, - $00d0,$0145,$014c,$00d3,$00d4,$00d5,$00d6,$0168, - $00d8,$0172,$00da,$00db,$00dc,$00dd,$00de,$00df, - $0101,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$012f, - $010d,$00e9,$0119,$00eb,$0117,$00ed,$00ee,$00ef, - $00f0,$0146,$014d,$00f3,$00f4,$00f5,$00f6,$0169, - $00f8,$0173,$00fa,$00fb,$00fc,$00fd,$00fe,$0138); - - BESENCharCP_1250:TBESENCharsetTable= - ($20ac,$fffd,$201a,$fffd,$201e,$2026,$2020,$2021, - $fffd,$2030,$0160,$2039,$015a,$0164,$017d,$0179, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $fffd,$2122,$0161,$203a,$015b,$0165,$017e,$017a, - $00a0,$02c7,$02d8,$0141,$00a4,$0104,$00a6,$00a7, - $00a8,$00a9,$015e,$00ab,$00ac,$00ad,$00ae,$017b, - $00b0,$00b1,$02db,$0142,$00b4,$00b5,$00b6,$00b7, - $00b8,$0105,$015f,$00bb,$013d,$02dd,$013e,$017c, - $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, - $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, - $0110,$0143,$0147,$00d3,$00d4,$0150,$00d6,$00d7, - $0158,$016e,$00da,$0170,$00dc,$00dd,$0162,$00df, - $0155,$00e1,$00e2,$0103,$00e4,$013a,$0107,$00e7, - $010d,$00e9,$0119,$00eb,$011b,$00ed,$00ee,$010f, - $0111,$0144,$0148,$00f3,$00f4,$0151,$00f6,$00f7, - $0159,$016f,$00fa,$0171,$00fc,$00fd,$0163,$02d9); - - BESENCharCP_1251:TBESENCharsetTable= - ($0402,$0403,$201a,$0453,$201e,$2026,$2020,$2021, - $20ac,$2030,$0409,$2039,$040a,$040c,$040b,$040f, - $0452,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $fffd,$2122,$0459,$203a,$045a,$045c,$045b,$045f, - $00a0,$040e,$045e,$0408,$00a4,$0490,$00a6,$00a7, - $0401,$00a9,$0404,$00ab,$00ac,$00ad,$00ae,$0407, - $00b0,$00b1,$0406,$0456,$0491,$00b5,$00b6,$00b7, - $0451,$2116,$0454,$00bb,$0458,$0405,$0455,$0457, - $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417, - $0418,$0419,$041a,$041b,$041c,$041d,$041e,$041f, - $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427, - $0428,$0429,$042a,$042b,$042c,$042d,$042e,$042f, - $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437, - $0438,$0439,$043a,$043b,$043c,$043d,$043e,$043f, - $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447, - $0448,$0449,$044a,$044b,$044c,$044d,$044e,$044f); - - BESENCharCP_1252:TBESENCharsetTable= - ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, - $02c6,$2030,$0160,$2039,$0152,$fffd,$017d,$fffd, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $02dc,$2122,$0161,$203a,$0153,$fffd,$017e,$0178, - $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, - $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, - $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, - $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, - $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, - $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, - $00D0,$00D1,$00D2,$00D3,$00D4,$00D5,$00D6,$00D7, - $00D8,$00D9,$00DA,$00DB,$00DC,$00DD,$00DE,$00DF, - $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, - $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, - $00F0,$00F1,$00F2,$00F3,$00F4,$00F5,$00F6,$00F7, - $00F8,$00F9,$00FA,$00FB,$00FC,$00FD,$00FE,$00FF); - - BESENCharCP_1253:TBESENCharsetTable= - ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, - $fffd,$2030,$fffd,$2039,$fffd,$fffd,$fffd,$fffd, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $fffd,$2122,$fffd,$203a,$fffd,$fffd,$fffd,$fffd, - $00a0,$0385,$0386,$00a3,$00a4,$00a5,$00a6,$00a7, - $00a8,$00a9,$fffd,$00ab,$00ac,$00ad,$00ae,$2015, - $00b0,$00b1,$00b2,$00b3,$0384,$00b5,$00b6,$00b7, - $0388,$0389,$038a,$00bb,$038c,$00bd,$038e,$038f, - $0390,$0391,$0392,$0393,$0394,$0395,$0396,$0397, - $0398,$0399,$039a,$039b,$039c,$039d,$039e,$039f, - $03a0,$03a1,$fffd,$03a3,$03a4,$03a5,$03a6,$03a7, - $03a8,$03a9,$03aa,$03ab,$03ac,$03ad,$03ae,$03af, - $03b0,$03b1,$03b2,$03b3,$03b4,$03b5,$03b6,$03b7, - $03b8,$03b9,$03ba,$03bb,$03bc,$03bd,$03be,$03bf, - $03c0,$03c1,$03c2,$03c3,$03c4,$03c5,$03c6,$03c7, - $03c8,$03c9,$03ca,$03cb,$03cc,$03cd,$03ce,$fffd); - - BESENCharCP_1254:TBESENCharsetTable= - ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, - $02c6,$2030,$0160,$2039,$0152,$fffd,$fffd,$fffd, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $02dc,$2122,$0161,$203a,$0153,$fffd,$fffd,$0178, - $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, - $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, - $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, - $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, - $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, - $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, - $011e,$00d1,$00d2,$00d3,$00d4,$00d5,$00d6,$00d7, - $00d8,$00d9,$00da,$00db,$00dc,$0130,$015e,$00df, - $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, - $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, - $011f,$00f1,$00f2,$00f3,$00f4,$00f5,$00f6,$00f7, - $00f8,$00f9,$00fa,$00fb,$00fc,$0131,$015f,$00ff); - - BESENCharCP_1255:TBESENCharsetTable= - ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, - $02c6,$2030,$fffd,$2039,$fffd,$fffd,$fffd,$fffd, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $02dc,$2122,$fffd,$203a,$fffd,$fffd,$fffd,$fffd, - $00a0,$00a1,$00a2,$00a3,$20aa,$00a5,$00a6,$00a7, - $00a8,$00a9,$00d7,$00ab,$00ac,$00ad,$00ae,$00af, - $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, - $00b8,$00b9,$00f7,$00bb,$00bc,$00bd,$00be,$00bf, - $05b0,$05b1,$05b2,$05b3,$05b4,$05b5,$05b6,$05b7, - $05b8,$05b9,$fffd,$05bb,$05bc,$05bd,$05be,$05bf, - $05c0,$05c1,$05c2,$05c3,$05f0,$05f1,$05f2,$05f3, - $05f4,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, - $05d0,$05d1,$05d2,$05d3,$05d4,$05d5,$05d6,$05d7, - $05d8,$05d9,$05da,$05db,$05dc,$05dd,$05de,$05df, - $05e0,$05e1,$05e2,$05e3,$05e4,$05e5,$05e6,$05e7, - $05e8,$05e9,$05ea,$fffd,$fffd,$200e,$200f,$fffd); - - BESENCharCP_1256:TBESENCharsetTable= - ($20ac,$067e,$201a,$0192,$201e,$2026,$2020,$2021, - $02c6,$2030,$0679,$2039,$0152,$0686,$0698,$0688, - $06af,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $06a9,$2122,$0691,$203a,$0153,$200c,$200d,$06ba, - $00a0,$060c,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, - $00a8,$00a9,$06be,$00ab,$00ac,$00ad,$00ae,$00af, - $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, - $00b8,$00b9,$061b,$00bb,$00bc,$00bd,$00be,$061f, - $06c1,$0621,$0622,$0623,$0624,$0625,$0626,$0627, - $0628,$0629,$062a,$062b,$062c,$062d,$062e,$062f, - $0630,$0631,$0632,$0633,$0634,$0635,$0636,$00d7, - $0637,$0638,$0639,$063a,$0640,$0641,$0642,$0643, - $00e0,$0644,$00e2,$0645,$0646,$0647,$0648,$00e7, - $00e8,$00e9,$00ea,$00eb,$0649,$064a,$00ee,$00ef, - $064b,$064c,$064d,$064e,$00f4,$064f,$0650,$00f7, - $0651,$00f9,$0652,$00fb,$00fc,$200e,$200f,$06d2); - - BESENCharCP_1257:TBESENCharsetTable= - ($20ac,$fffd,$201a,$fffd,$201e,$2026,$2020,$2021, - $fffd,$2030,$fffd,$2039,$fffd,$00a8,$02c7,$00b8, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $fffd,$2122,$fffd,$203a,$fffd,$00af,$02db,$fffd, - $00a0,$fffd,$00a2,$00a3,$00a4,$fffd,$00a6,$00a7, - $00d8,$00a9,$0156,$00ab,$00ac,$00ad,$00ae,$00c6, - $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, - $00f8,$00b9,$0157,$00bb,$00bc,$00bd,$00be,$00e6, - $0104,$012e,$0100,$0106,$00c4,$00c5,$0118,$0112, - $010c,$00c9,$0179,$0116,$0122,$0136,$012a,$013b, - $0160,$0143,$0145,$00d3,$014c,$00d5,$00d6,$00d7, - $0172,$0141,$015a,$016a,$00dc,$017b,$017d,$00df, - $0105,$012f,$0101,$0107,$00e4,$00e5,$0119,$0113, - $010d,$00e9,$017a,$0117,$0123,$0137,$012b,$013c, - $0161,$0144,$0146,$00f3,$014d,$00f5,$00f6,$00f7, - $0173,$0142,$015b,$016b,$00fc,$017c,$017e,$02d9); - - BESENCharCP_1258:TBESENCharsetTable= - ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, - $02c6,$2030,$fffd,$2039,$0152,$fffd,$fffd,$fffd, - $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, - $02dc,$2122,$fffd,$203a,$0153,$fffd,$fffd,$0178, - $00a0,$00a1,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, - $00a8,$00a9,$00aa,$00ab,$00ac,$00ad,$00ae,$00af, - $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, - $00b8,$00b9,$00ba,$00bb,$00bc,$00bd,$00be,$00bf, - $00c0,$00c1,$00c2,$0102,$00c4,$00c5,$00c6,$00c7, - $00c8,$00c9,$00ca,$00cb,$0300,$00cd,$00ce,$00cf, - $0110,$00d1,$0309,$00d3,$00d4,$01a0,$00d6,$00d7, - $00d8,$00d9,$00da,$00db,$00dc,$01af,$0303,$00df, - $00e0,$00e1,$00e2,$0103,$00e4,$00e5,$00e6,$00e7, - $00e8,$00e9,$00ea,$00eb,$0301,$00ed,$00ee,$00ef, - $0111,$00f1,$0323,$00f3,$00f4,$01a1,$00f6,$00f7, - $00f8,$00f9,$00fa,$00fb,$00fc,$01b0,$20ab,$00ff); - - BESENCharKOI8_R:TBESENCharsetTable= - ($2500,$2502,$250c,$2510,$2514,$2518,$251c,$2524, - $252c,$2534,$253c,$2580,$2584,$2588,$258c,$2590, - $2591,$2592,$2593,$2320,$25a0,$2219,$221a,$2248, - $2264,$2265,$00a0,$2321,$00b0,$00b2,$00b7,$00f7, - $2550,$2551,$2552,$0451,$2553,$2554,$2555,$2556, - $2557,$2558,$2559,$255a,$255b,$255c,$255d,$255e, - $255f,$2560,$2561,$0401,$2562,$2563,$2564,$2565, - $2566,$2567,$2568,$2569,$256a,$256b,$256c,$00a9, - $044e,$0430,$0431,$0446,$0434,$0435,$0444,$0433, - $0445,$0438,$0439,$043a,$043b,$043c,$043d,$043e, - $043f,$044f,$0440,$0441,$0442,$0443,$0436,$0432, - $044c,$044b,$0437,$0448,$044d,$0449,$0447,$044a, - $042e,$0410,$0411,$0426,$0414,$0415,$0424,$0413, - $0425,$0418,$0419,$041a,$041b,$041c,$041d,$041e, - $041f,$042f,$0420,$0421,$0422,$0423,$0416,$0412, - $042c,$042b,$0417,$0428,$042d,$0429,$0427,$042a); - -var BESENLocaleCharset:TBESENCharset; - -implementation - -end. diff --git a/3rd/besen/src/BESENCode.pas b/3rd/besen/src/BESENCode.pas deleted file mode 100644 index 68d921bce..000000000 --- a/3rd/besen/src/BESENCode.pas +++ /dev/null @@ -1,699 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCode; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENASTNodes,BESENStringList, - BESENHashMap; - -type TBESENCodeVariable=record - Name:TBESENString; - IsParameter:longbool; - ParameterIndex:integer; - end; - - TBESENCodeVariables=array of TBESENCodeVariable; - - PBESENCodePolymorphicInlineCacheItem=^TBESENCodePolymorphicInlineCacheItem; - TBESENCodePolymorphicInlineCacheItem=record - StructureID:TBESENINT32; - Index:TBESENINT32; - ID:TBESENINT32; - NestedLevel:TBESENINT32; - end; - - TBESENCodePolymorphicInlineCacheItems=array[0..BESENPolymorphicInlineCacheSize-1] of TBESENCodePolymorphicInlineCacheItem; - - PBESENCodePolymorphicInlineCacheInstruction=^TBESENCodePolymorphicInlineCacheInstruction; - TBESENCodePolymorphicInlineCacheInstruction=record - CacheItems:TBESENCodePolymorphicInlineCacheItems; - CacheItemPositions:TBESENUINT32; - end; - - TBESENCodePolymorphicInlineCacheInstructions=array of PBESENCodePolymorphicInlineCacheInstruction; - - TBESENCode=class(TBESENBaseObject) - public - CodePrevious,CodeNext:TBESENCode; - ByteCode:TBESENUINT32s; - ByteCodeLen:integer; - NativeCode:pointer; - NativeCodeSize:ptruint; - NativeCodePCOffsets:TBESENNativeCodePCOffsets; - Body:TBESENASTNodeFunctionBody; - FunctionLiteralContainers:TBESENFunctionLiteralContainers; - Literals:TBESENValues; - Locations:TBESENLocations; - Variables:TBESENCodeVariables; - PolymorphicInlineCacheInstructions:TBESENCodePolymorphicInlineCacheInstructions; - CountFunctionLiteralContainers:integer; - CountLiterals:integer; - CountLocations:integer; - CountVariables:integer; - CountPolymorphicInlineCacheInstructions:integer; - MaxRegisters:integer; - MaxBlock:integer; - MaxParamArgs:integer; - MaxLoop:integer; - HasLocalDelete:TBESENBoolean; - IsComplexFunction:TBESENBoolean; - HasMaybeDirectEval:TBESENBoolean; - HoldLocalVariablesInRegisters:TBESENBoolean; - LastCodePos:integer; - LastOpcode:integer; - LastLine:integer; - LookupNames:TBESENStringList; - FreeCodeContexts:TObject; - CountOfFreeCodeContexts:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Mark; - procedure Finish; - procedure ResetPolymorphicInlineCacheInstructions; - function Put(v:TBESENUINT32):integer; - function Patch(Offset:integer;v:TBESENUINT32):boolean; - function GenOp(Opcode:TBESENUINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9,Operand10:TBESENINT32):integer; overload; - function GenOp(Opcode:TBESENUINT32;Operands:array of TBESENINT32):integer; overload; - function GenLabel(Offset:TBESENUINT32):boolean; - function Here:integer; - procedure Restore(Pos:integer); - function GenLiteral(const v:TBESENValue;DestRegNr:integer):integer; - function GenFunction(const f:TBESENFunctionLiteralContainer;DestRegNr:integer):integer; - function GenLocation(const l:TBESENLocation):integer; - function GenVariable(const s:TBESENString;IsParameter:boolean;ParameterIndex:integer;const CodeGeneratorContext:TObject):integer; - function GenPolymorphicInlineCacheInstruction:integer; - function Disassemble:TBESENString; - procedure Execute(const Context:TObject;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENContext,BESENCodeContext,BESENUtils,BESENOpcodes,BESENCodeGeneratorContext; - -constructor TBESENCode.Create(AInstance:TObject); -begin - inherited Create(AInstance); - CodeNext:=nil; - if assigned(TBESEN(Instance).CodeLast) then begin - TBESEN(Instance).CodeLast.CodeNext:=self; - CodePrevious:=TBESEN(Instance).CodeLast; - TBESEN(Instance).CodeLast:=self; - end else begin - CodePrevious:=nil; - TBESEN(Instance).CodeFirst:=self; - TBESEN(Instance).CodeLast:=self; - end; - ByteCode:=nil; - ByteCodeLen:=0; - NativeCode:=nil; - NativeCodeSize:=0; - NativeCodePCOffsets:=nil; - Body:=nil; - FunctionLiteralContainers:=nil; - Literals:=nil; - Locations:=nil; - Variables:=nil; - PolymorphicInlineCacheInstructions:=nil; - CountFunctionLiteralContainers:=0; - CountLiterals:=0; - CountLocations:=0; - CountVariables:=0; - CountPolymorphicInlineCacheInstructions:=0; - MaxRegisters:=0; - MaxBlock:=0; - MaxLoop:=0; - MaxParamArgs:=0; - HasLocalDelete:=false; - IsComplexFunction:=false; - HasMaybeDirectEval:=false; - HoldLocalVariablesInRegisters:=false; - LastCodePos:=-1; - LastOpcode:=-1; - LastLine:=-1; - LookupNames:=TBESENStringList.Create; - FreeCodeContexts:=nil; - CountOfFreeCodeContexts:=0; -end; - -destructor TBESENCode.Destroy; -var i:integer; - NextCodeContext:TBESENCodeContext; -begin - while assigned(TBESENCodeContext(FreeCodeContexts)) do begin - NextCodeContext:=TBESENCodeContext(FreeCodeContexts).NextCodeContext; - TBESENCodeContext(FreeCodeContexts).NextCodeContext:=nil; - BESENFreeAndNil(FreeCodeContexts); - TBESENCodeContext(FreeCodeContexts):=NextCodeContext; - end; - BESENFreeAndNil(LookupNames); - for i:=0 to length(Literals)-1 do begin - Literals[i].Str:=''; - Literals[i].ReferenceBase.Str:=''; - Literals[i]:=BESENEmptyValue; - end; - for i:=0 to length(Variables)-1 do begin - Variables[i].Name:=''; - end; - SetLength(FunctionLiteralContainers,0); - SetLength(Literals,0); - SetLength(Locations,0); - SetLength(Variables,0); - for i:=0 to length(PolymorphicInlineCacheInstructions)-1 do begin - if assigned(PolymorphicInlineCacheInstructions[i]) then begin - Dispose(PolymorphicInlineCacheInstructions[i]); - PolymorphicInlineCacheInstructions[i]:=nil; - end; - end; - SetLength(PolymorphicInlineCacheInstructions,0); - SetLength(ByteCode,0); - SetLength(NativeCodePCOffsets,0); - if assigned(NativeCode) then begin - TBESEN(Instance).NativeCodeMemoryManager.FreeMemory(NativeCode); - NativeCode:=nil; - end; - if assigned(CodePrevious) then begin - CodePrevious.CodeNext:=CodeNext; - end else if TBESEN(Instance).CodeFirst=self then begin - TBESEN(Instance).CodeFirst:=CodeNext; - end; - if assigned(CodeNext) then begin - CodeNext.CodePrevious:=CodePrevious; - end else if TBESEN(Instance).CodeLast=self then begin - TBESEN(Instance).CodeLast:=CodePrevious; - end; - CodePrevious:=nil; - CodeNext:=nil; - inherited Destroy; -end; - -procedure TBESENCode.Mark; -var i:integer; -begin - for i:=0 to CountFunctionLiteralContainers-1 do begin - if assigned(FunctionLiteralContainers[i]) then begin - TBESEN(Instance).GarbageCollector.GrayIt(FunctionLiteralContainers[i]); - end; - end; - for i:=0 to CountLiterals-1 do begin - TBESEN(Instance).GarbageCollector.GrayValue(Literals[i]); - end; -end; - -procedure TBESENCode.Finish; -var i,j:integer; -begin - SetLength(ByteCode,ByteCodeLen); - SetLength(FunctionLiteralContainers,CountFunctionLiteralContainers); - SetLength(Literals,CountLiterals); - SetLength(Locations,CountLocations); - SetLength(Variables,CountVariables); - j:=length(PolymorphicInlineCacheInstructions); - SetLength(PolymorphicInlineCacheInstructions,CountPolymorphicInlineCacheInstructions); - for i:=j to length(PolymorphicInlineCacheInstructions)-1 do begin - PolymorphicInlineCacheInstructions[i]:=nil; - end; - for i:=0 to length(PolymorphicInlineCacheInstructions)-1 do begin - if not assigned(PolymorphicInlineCacheInstructions[i]) then begin - New(PolymorphicInlineCacheInstructions[i]); - end; - end; - ResetPolymorphicInlineCacheInstructions; -end; - -function TBESENCode.Put(v:TBESENUINT32):integer; -begin - result:=ByteCodeLen; - if ByteCodeLen>=length(ByteCode) then begin - SetLength(ByteCode,(ByteCodeLen+4096) and not 4095); - end; - ByteCode[result]:=v; - inc(ByteCodeLen); -end; - -function TBESENCode.Patch(Offset:integer;v:TBESENUINT32):boolean; -begin - result:=Offset<=ByteCodeLen; - if result then begin - ByteCode[Offset]:=v; - end; -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32):integer; -begin - if (Opcode in [bopGC,bopSTRICTCHECKREF,bopDEBUGGER,bopCHECKOBJECTCOERCIBLE,bopTRACE]) and (TBESENUINT32(LastOpcode)=Opcode) then begin - result:=LastCodePos; - end else begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put(Opcode and $ff); - end; -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (1 shl 8)); - Put(Operand); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (2 shl 8)); - Put(Operand1); - Put(Operand2); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (3 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (4 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (5 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); - Put(Operand5); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (6 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); - Put(Operand5); - Put(Operand6); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (7 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); - Put(Operand5); - Put(Operand6); - Put(Operand7); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (8 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); - Put(Operand5); - Put(Operand6); - Put(Operand7); - Put(Operand8); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (9 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); - Put(Operand5); - Put(Operand6); - Put(Operand7); - Put(Operand8); - Put(Operand9); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9,Operand10:TBESENINT32):integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (10 shl 8)); - Put(Operand1); - Put(Operand2); - Put(Operand3); - Put(Operand4); - Put(Operand5); - Put(Operand6); - Put(Operand7); - Put(Operand8); - Put(Operand9); - Put(Operand10); -end; - -function TBESENCode.GenOp(Opcode:TBESENUINT32;Operands:array of TBESENINT32):integer; -var i:integer; -begin - LastCodePos:=Here; - LastOpcode:=Opcode; - result:=Put((Opcode and $ff) or (longword(length(Operands)) shl 8)); - for i:=0 to length(Operands)-1 do begin - Put(Operands[i]); - end; -end; - -function TBESENCode.GenLabel(Offset:TBESENUINT32):boolean; -begin - result:=Patch(Offset,Here); -end; - -function TBESENCode.Here:integer; -begin - result:=ByteCodeLen; -end; - -procedure TBESENCode.Restore(Pos:integer); -begin - ByteCodeLen:=Pos; - LastCodePos:=-1; - LastOpcode:=-1; -end; - -function TBESENCode.GenLiteral(const v:TBESENValue;DestRegNr:integer):integer; -const BoolToInt:array[boolean] of longword=(0,$ffffffff); -var i:integer; - Okay:boolean; -begin - result:=-1; - for i:=0 to CountLiterals-1 do begin - if Literals[i].ValueType=v.ValueType then begin - case v.ValueType of - bvtUNDEFINED:begin - Okay:=true; - end; - bvtNULL:begin - Okay:=true; - end; - bvtBOOLEAN:begin - Okay:=Literals[i].Bool=v.Bool; - end; - bvtNUMBER:begin - Okay:=int64(pointer(@Literals[i].Num)^)=int64(pointer(@v.Num)^); - end; - bvtSTRING:begin - Okay:=Literals[i].Str=v.Str; - end; - bvtOBJECT:begin - Okay:=Literals[i].Obj=v.Obj; - end; - else begin - Okay:=false; - end; - end; - if Okay then begin - result:=i; - break; - end; - end; - end; - if result<0 then begin - result:=CountLiterals; - if CountLiterals>=length(Literals) then begin - SetLength(Literals,CountLiterals+256); - end; - Literals[result]:=v; - inc(CountLiterals); - end; - case v.ValueType of - bvtUNDEFINED:begin - GenOp(bopLITERALUNDEF,DestRegNr); - end; - bvtNULL:begin - GenOp(bopLITERALNULL,DestRegNr); - end; - bvtBOOLEAN:begin - if v.Bool then begin - GenOp(bopLITERALBOOL,DestRegNr,BoolToInt[true]); - end else begin - GenOp(bopLITERALBOOL,DestRegNr,BoolToInt[false]); - end; - end; - bvtNUMBER:begin - GenOp(bopLITERALNUM,DestRegNr,result); - end; - bvtSTRING:begin - GenOp(bopLITERALSTR,DestRegNr,result); - end; - bvtOBJECT:begin - GenOp(bopLITERALOBJ,DestRegNr,result); - end; - else begin - GenOp(bopLITERAL,DestRegNr,result); - end; - end; -end; - -function TBESENCode.GenFunction(const f:TBESENFunctionLiteralContainer;DestRegNr:integer):integer; -var i:integer; -begin - result:=-1; - for i:=0 to CountFunctionLiteralContainers-1 do begin - if FunctionLiteralContainers[i]=f then begin - result:=i; - break; - end; - end; - if result<0 then begin - result:=CountFunctionLiteralContainers; - if CountFunctionLiteralContainers>=length(FunctionLiteralContainers) then begin - SetLength(FunctionLiteralContainers,CountFunctionLiteralContainers+256); - end; - FunctionLiteralContainers[result]:=f; - inc(CountFunctionLiteralContainers); - end; - GenOp(bopFUNC,DestRegNr,result); -end; - -function TBESENCode.GenLocation(const l:TBESENLocation):integer; -var i:integer; - LastOpcodeWasLine:boolean; -begin - result:=-1; - if TBESEN(Instance).CodeLineInfo or TBESEN(Instance).CodeTracable then begin - for i:=0 to CountLocations-1 do begin - if Locations[i].LineNumber=l.LineNumber then begin - result:=i; - break; - end; - end; - if result<0 then begin - result:=CountLocations; - if CountLocations>=length(Locations) then begin - SetLength(Locations,CountLocations+256); - end; - Locations[result]:=l; - inc(CountLocations); - end; - LastOpcodeWasLine:=LastOpcode=bopLINE; - if LastLine<>result then begin - LastLine:=result; - if LastOpcodeWasLine then begin - ByteCode[LastCodePos+1]:=result; - end else begin - GenOp(bopLINE,result); - end; - end; - if TBESEN(Instance).CodeTracable and not LastOpcodeWasLine then begin - GenOp(bopTRACE); - end; - end; -end; - -function TBESENCode.GenVariable(const s:TBESENString;IsParameter:boolean;ParameterIndex:integer;const CodeGeneratorContext:TObject):integer; -var Item:PBESENHashMapItem; -begin - Item:=TBESENCodeGeneratorContext(CodeGeneratorContext).VariableNameHashMap.GetKey(s); - if assigned(Item) then begin - result:=Item^.Value; - end else begin - result:=-1; - end; - if result<0 then begin - result:=CountVariables; - if CountVariables>=length(Variables) then begin - SetLength(Variables,CountVariables+256); - end; - Variables[result].Name:=s; - Variables[result].IsParameter:=IsParameter; - Variables[result].ParameterIndex:=ParameterIndex; - Item:=TBESENCodeGeneratorContext(CodeGeneratorContext).VariableNameHashMap.NewKey(s,true); - Item^.Value:=result; - inc(CountVariables); - end; -end; - -function TBESENCode.GenPolymorphicInlineCacheInstruction:integer; -begin - result:=CountPolymorphicInlineCacheInstructions; - inc(CountPolymorphicInlineCacheInstructions); -end; - -procedure TBESENCode.ResetPolymorphicInlineCacheInstructions; -var PC,OPC,Instruction:TBESENUINT32; - i,j:integer; - PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; - CacheItem:PBESENCodePolymorphicInlineCacheItem; -begin - PC:=0; - while PC<TBESENUINT32(ByteCodeLen) do begin - Instruction:=ByteCode[PC]; - OPC:=PC+1; - inc(PC,1+(Instruction shr 8)); - case Instruction and $ff of - bopREF:begin - ByteCode[OPC+6]:=TBESENUINT32(TBESENINT32(-1)); - ByteCode[OPC+7]:=TBESENUINT32(TBESENINT32(-1)); - ByteCode[OPC+8]:=TBESENUINT32(TBESENINT32(-1)); - ByteCode[OPC+9]:=TBESENUINT32(TBESENINT32(-1)); - end; - bopVREF:begin - ByteCode[OPC+4]:=TBESENUINT32(TBESENINT32(-1)); - ByteCode[OPC+5]:=TBESENUINT32(TBESENINT32(-1)); - ByteCode[OPC+6]:=TBESENUINT32(TBESENINT32(-1)); - ByteCode[OPC+7]:=TBESENUINT32(TBESENINT32(-1)); - end; - end; - end; - for i:=0 to CountPolymorphicInlineCacheInstructions-1 do begin - PolymorphicInlineCacheInstruction:=PolymorphicInlineCacheInstructions[i]; - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENPolymorphicInlineCacheStartItemPositions; - for j:=0 to BESENPolymorphicInlineCacheSize-1 do begin - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[j]; - CacheItem^.StructureID:=-1; - CacheItem^.Index:=-1; - CacheItem^.ID:=-1; - CacheItem^.NestedLevel:=-1; - end; - end; -end; - -function TBESENCode.Disassemble:TBESENString; -var PC,OPC,Instruction,i:TBESENUINT32; - Output:TBESENString; - procedure Add(const s:TBESENString); - begin - Output:=Output+s; - end; -begin - Output:=''; - PC:=0; - while PC<TBESENUINT32(ByteCodeLen) do begin - Output:=Output+IntToHex(PC,8)+': '; - Instruction:=ByteCode[PC]; - OPC:=PC+1; - inc(PC,1+(Instruction shr 8)); - Add('0x'+IntToHex(Instruction and $ff,2)+' '); - if (Instruction and $ff)<longword(length(OpcodeNames)) then begin - Add(OpcodeNames[Instruction and $ff]); - end else begin - Add('UNKNOWN'); - end; - for i:=1 to Instruction shr 8 do begin - Add(' 0x'+IntToHex(ByteCode[OPC+(i-1)],8)); - end; - Output:=Output+#13#10; - end; - result:=Output; -end; - -procedure TBESENCode.Execute(const Context:TObject;var ResultValue:TBESENValue); -var CodeContext:TBESENCodeContext; -begin - if assigned(FreeCodeContexts) then begin - CodeContext:=TBESENCodeContext(FreeCodeContexts); - TBESENCodeContext(FreeCodeContexts):=TBESENCodeContext(FreeCodeContexts).NextCodeContext; - dec(CountOfFreeCodeContexts); - end else begin - CodeContext:=TBESENCodeContext.Create(Instance,self); - end; - TBESENCodeContext(TBESENContext(Context).CodeContext):=CodeContext; - try - TBESENCodeContext(TBESENContext(Context).CodeContext).Execute(TBESENContext(Context),ResultValue); - finally - TBESENContext(Context).CodeContext:=nil; - TBESENCodeContext(CodeContext).Context:=nil; - if CountOfFreeCodeContexts<TBESEN(Instance).MaxCountOfFreeCodeContexts then begin - CodeContext.NextCodeContext:=TBESENCodeContext(FreeCodeContexts); - TBESENCodeContext(FreeCodeContexts):=CodeContext; - inc(CountOfFreeCodeContexts); - end else begin - BESENFreeAndNil(CodeContext); - end; - end; -end; - -end. diff --git a/3rd/besen/src/BESENCodeContext.pas b/3rd/besen/src/BESENCodeContext.pas deleted file mode 100644 index a5657aa4c..000000000 --- a/3rd/besen/src/BESENCodeContext.pas +++ /dev/null @@ -1,4011 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCodeContext; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}SysUtils,Classes,Math,BESENConstants,BESENTypes,BESENValue, - BESENBaseObject,BESENCollectorObject,BESENObject,BESENLexicalEnvironment, - BESENStringList,BESENContext,BESENCode, - BESENObjectPropertyDescriptor; - -type TBESENCodeContextBlockType=(bccbtENUM,bccbtWITH,bccbtCATCH,bccbtCATCH2,bccbtFINALLY,bccbtFINALLY2); - - PBESENCodeContextBlock=^TBESENCodeContextBlock; - - TBESENCodeContextBlock=record - BlockType:TBESENCodeContextBlockType; - OldEnumBlock:PBESENCodeContextBlock; - PropertyEnumerator:TBESENObjectPropertyEnumerator; - OldPropertyEnumerator:TBESENObjectPropertyEnumerator; - LastTryBlock:longword; - Resume:longword; - Handler:longword; - Ident:TBESENString; - Obj:TBESENObject; - LexicalEnvironment:TBESENLexicalEnvironment; - Done:longbool; - Raised:longbool; - Value:TBESENValue; - end; - - TBESENCodeContextBlocks=array of TBESENCodeContextBlock; - - TBESENCodeContextOpcode=procedure(Operands:PBESENINT32Array) of object; {$ifdef UseRegister}register;{$endif} - - TBESENCodeContextOpcodePointers=array[byte] of pointer; - - TBESENCodeContextOpcodeArgs=array[byte] of longbool; - - TBESENCodeContextGetRefProc=procedure(const ARef:TBESENValue;var AResult:TBESENValue) of object; - - TBESENCodeContextGetRefProcs=array[byte] of TBESENCodeContextGetRefProc; - - TBESENCodeContextPutRefProc=procedure(const ARef,AValue:TBESENValue) of object; - - TBESENCodeContextPutRefProcs=array[byte] of TBESENCodeContextPutRefProc; - - TBESENCodeContextParameterIndices=array of integer; - - TBESENCodeContext=class(TBESENBaseObject) - private - LexicalEnvironment:TBESENLexicalEnvironment; - OldLexicalEnvironment:TBESENLexicalEnvironment; - GetRefProcs:TBESENCodeContextGetRefProcs; - PutRefProcs:TBESENCodeContextPutRefProcs; - LookupNames:PBESENStringArray; - procedure OpSTOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpEND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpVREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpAREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTHROW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTHIS(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpARRAY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpREGEXP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLOOKUP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpDELETE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTYPEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTOOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTONUMBER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTOBOOLEAN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTOSTRING(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTOPRIMITIVE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEG(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpINV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNOT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpMUL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpDIV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpMOD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpADD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpADDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSUB(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSHL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpUSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpINSTANCEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpIN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBAND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBXOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSWITH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSCATCH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpENDF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpJMP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpJZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpJNZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpJNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLOOPENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSTRYC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSTRYF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERALUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERALNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLITERALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpFUNC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLINE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSTRICT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSTRICTCHECKREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpDEBUGGER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCHECKOBJECTCOERCIBLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTOBJVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTOBJGET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTOBJSET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpINC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpDEC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPYBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPYNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPYSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPYOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPYREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpCOPYLOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGETVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpPUTVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLOOPINITCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLOOPADDCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTRACE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSHLBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSHRBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBANDBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBXORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSHLNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpUSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBANDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBXORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpBORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETCUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETCNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETCBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETCNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETCSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpSETCOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTRACENEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpTRACECALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpLENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpGENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpNEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpJZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - procedure OpJNZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} - protected - function ConstructError(ConstructorObject:TBESENObject;const Msg:TBESENString;const Name:TBESENString=''):TBESENValue; - function Trace(const TraceType:TBESENTraceType):boolean; - procedure GetIdentifierReference(Lex:TBESENLexicalEnvironment;const Name:TBESENString;const IsStrict:TBESENBoolean;var AResult:TBESENValue); - procedure GetPrimitive(const ARef:TBESENValue;var AResult:TBESENValue); - procedure GetObject(const ARef:TBESENValue;var AResult:TBESENValue); - procedure GetEnvRec(const ARef:TBESENValue;var AResult:TBESENValue); - procedure GetUndefined(const ARef:TBESENValue;var AResult:TBESENValue); - procedure GetValue(const AValue:TBESENValue;var AResult:TBESENValue); - procedure PutPrimitive(const ARef,AValue:TBESENValue); - procedure PutObject(const ARef,AValue:TBESENValue); - procedure PutEnvRec(const ARef,AValue:TBESENValue); - procedure PutUndefined(const ARef,AValue:TBESENValue); - procedure PutValue(const ARef,AValue:TBESENValue); - function AbstractRelational(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; - function AbstractRelationalNumber(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; - procedure Throw(const ThrowValue:TBESENValue); - function ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} - function ExecuteCode:TBESENBoolean; - procedure ExecuteTryBlockLevel; - public - NextCodeContext:TBESENCodeContext; - Code:TBESENCode; - Context:TBESENContext; - RegisterValues:TBESENValues; - PC:TBESENUINT32; - Blocks:TBESENCodeContextBlocks; - Block:PBESENCodeContextBlock; - LoopCounters:TBESENUINT32s; - ParamArgs:TBESENValuePointers; - PropertyEnumerator:TBESENObjectPropertyEnumerator; - EnumBlock:PBESENCodeContextBlock; - Temp,AnotherTemp:TBESENValue; - BlockLevel,NewBlockLevel:integer; - Obj:TBESENObject; - DontEnum,Running,BlockRunning:TBESENBoolean; - Str:TBESENString; - va,vb,vaa,vbb:TBESENValue; - Descriptor,Descriptor2:TBESENObjectPropertyDescriptor; - BaseValue:TBESENValue; - CallThisArg:TBESENValue; - ResultValue:TBESENValue; - constructor Create(AInstance:TObject;ACode:TBESENCode); overload; - destructor Destroy; override; - procedure Execute(const AContext:TBESENContext;var AResult:TBESENValue); - end; - -var BESENCodeContextOpcodes:TBESENCodeContextOpcodePointers; - -function BESENAdjustPolymorphicInlineCachePosition(Position,Index:TBESENUINT32):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} - -implementation - -uses BESEN,BESENEnvironmentRecord,BESENHashUtils,BESENUtils,BESENArrayUtils, - BESENObjectEnvironmentRecord,BESENDeclarativeEnvironmentRecord,BESENStringUtils, - BESENGarbageCollector,BESENASTNodes,BESENNumberUtils,BESENOpcodes,BESENErrors, - BESENObjectDeclaredFunction{$ifdef HasJIT}{$ifdef cpu386},BESENCodeJITx86{$endif}{$ifdef cpuamd64},BESENCodeJITx64{$endif}{$endif}; - -function sar(Value,Shift:integer):integer; -{$ifdef PurePascal}{$ifdef caninline}inline;{$endif} -begin -{$ifdef HasSAR} - result:=SARLongint(Value,Shift); -{$else} - Shift:=Shift and 31; - result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); -{$endif} -end; -{$else} -{$ifdef HasSAR} inline; -begin -result:=SARLongint(Value,Shift); -end; -{$else} -{$ifdef cpu386} -{$ifdef fpc} assembler; register; //inline; -asm - mov ecx,edx - sar eax,cl -end;// ['eax','edx','ecx']; -{$else} assembler; register; -asm - mov ecx,edx - sar eax,cl -end; -{$endif} -{$else} -{$ifdef cpuarm} assembler; //inline; -asm - mov r0,r0,asr R1 -end;// ['r0','R1']; -{$else}{$ifdef caninline}inline;{$endif} -begin -{$ifdef HasSAR} - result:=SARLongint(Value,Shift); -{$else} - Shift:=Shift and 31; - result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); -{$endif} -end; -{$endif} -{$endif} -{$endif} -{$endif} - -function BESENAdjustPolymorphicInlineCachePosition(Position,Index:TBESENUINT32):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -begin - result:=((Position shr (Index shl 2)) and $f) or ((Position and ((1 shl (Index shl 2))-1)) shl 4) or ((Position and not ((1 shl ((Index+1) shl 2))-1)) and TBESENUINT32(0-ord(Index<7))); -end; - -constructor TBESENCodeContext.Create(AInstance:TObject;ACode:TBESENCode); -var i:integer; -begin - inherited Create(AInstance); - Context:=nil; - Code:=ACode; - NextCodeContext:=nil; - Blocks:=nil; - Block:=nil; - PropertyEnumerator:=nil; - EnumBlock:=nil; - Temp:=BESENUndefinedValue; - AnotherTemp:=BESENUndefinedValue; - BlockLevel:=0; - NewBlockLevel:=0; - PC:=0; - Running:=true; - BlockRunning:=true; - RegisterValues:=nil; - LoopCounters:=nil; - ParamArgs:=nil; - - Str:=''; - vaa:=BESENUndefinedValue; - vbb:=BESENUndefinedValue; - Descriptor:=BESENUndefinedPropertyDescriptor; - Descriptor2:=BESENUndefinedPropertyDescriptor; - - CallThisArg:=BESENUndefinedValue; - - GetRefProcs[brbvtUNDEFINED]:=GetUndefined; - GetRefProcs[brbvtBOOLEAN]:=GetPrimitive; - GetRefProcs[brbvtNUMBER]:=GetPrimitive; - GetRefProcs[brbvtSTRING]:=GetPrimitive; - GetRefProcs[brbvtOBJECT]:=GetObject; - GetRefProcs[brbvtENVREC]:=GetEnvRec; - - PutRefProcs[brbvtUNDEFINED]:=PutUndefined; - PutRefProcs[brbvtBOOLEAN]:=PutPrimitive; - PutRefProcs[brbvtNUMBER]:=PutPrimitive; - PutRefProcs[brbvtSTRING]:=PutPrimitive; - PutRefProcs[brbvtOBJECT]:=PutObject; - PutRefProcs[brbvtENVREC]:=PutEnvRec; - - SetLength(RegisterValues,Code.MaxRegisters); - if length(RegisterValues)>0 then begin - FillChar(RegisterValues[0],length(RegisterValues)*sizeof(TBESENValue),#0); - end; - - Temp:=BESENEmptyValue; - SetLength(Blocks,Code.MaxBlock+1); - SetLength(LoopCounters,Code.MaxLoop+1); - SetLength(ParamArgs,Code.MaxParamArgs+1); - for i:=0 to length(ParamArgs)-1 do begin - ParamArgs[i]:=nil; - end; - if length(Blocks)>0 then begin - fillchar(Blocks[0],length(Blocks)*sizeof(TBESENCodeContextBlock),#0); - end; -end; - -destructor TBESENCodeContext.Destroy; -var i:integer; -begin - SetLength(LoopCounters,0); - SetLength(ParamArgs,0); - SetLength(RegisterValues,0); - for i:=0 to length(Blocks)-1 do begin - Blocks[i].Ident:=''; - Blocks[i].Value.Str:=''; - Blocks[i].Value.ReferenceBase.Str:=''; - end; - SetLength(Blocks,0); - Str:=''; - inherited Destroy; -end; - -function TBESENCodeContext.ConstructError(ConstructorObject:TBESENObject;const Msg:TBESENString;const Name:TBESENString=''):TBESENValue; -var v:TBESENValue; - vv:array[0..0] of PBESENValue; -begin - v.ValueType:=bvtSTRING; - v.Str:=Msg; - vv[0]:=@v; - ConstructorObject.Construct(BESENUndefinedValue,@vv,1,result); - TBESEN(Instance).GarbageCollector.Add(TBESENObject(result.Obj)); - if length(Name)>0 then begin - TBESENObject(result.Obj).PutEx('name',BESENStringValue(Name),true,Descriptor,Descriptor2,AnotherTemp); - end; -end; - -function TBESENCodeContext.Trace(const TraceType:TBESENTraceType):boolean; -begin - result:=true; - if assigned(TBESEN(Instance).TraceHook) then begin - if not TBESEN(Instance).TraceHook(TBESEN(Instance),Context,Code.Body,PC,TraceType) then begin - Running:=false; - BlockRunning:=false; - result:=false; - end; - end; -end; - -procedure TBESENCodeContext.GetIdentifierReference(Lex:TBESENLexicalEnvironment;const Name:TBESENString;const IsStrict:TBESENBoolean;var AResult:TBESENValue); -var EnvRec:TBESENEnvironmentRecord; -begin - AResult.ValueType:=bvtREFERENCE; - AResult.ReferenceBase.ValueType:=brbvtUNDEFINED; - AResult.Str:=Name; - AResult.ReferenceIsStrict:=IsStrict; - AResult.ReferenceHash:=BESENHashKey(Name); - AResult.ReferenceIndex:=-1; - AResult.ReferenceID:=-1; - while assigned(Lex) do begin - EnvRec:=Lex.EnvironmentRecord; - if assigned(EnvRec) and EnvRec.HasBindingEx(Name,Descriptor) then begin - AResult.ReferenceBase.ValueType:=brbvtENVREC; - AResult.ReferenceBase.EnvRec:=EnvRec; - break; - end; - Lex:=Lex.Outer; - end; -end; - -procedure TBESENCodeContext.GetPrimitive(const ARef:TBESENValue;var AResult:TBESENValue); -var O:TBESENObject; - Hash:TBESENHash; -begin - AResult.ValueType:=bvtUNDEFINED; - BESENReferenceBaseValueToValue(ARef.ReferenceBase,BaseValue); - if BaseValue.ValueType=bvtOBJECT then begin - O:=TBESENObject(BaseValue.Obj); - end else begin - O:=TBESEN(Instance).ToObj(BaseValue); - TBESEN(Instance).GarbageCollector.Add(O); - end; - if not assigned(O) then begin - BESENThrowNotDefined(ARef); - end; - O.GarbageCollectorLock; - try - if ARef.ReferenceID<0 then begin - if ARef.ReferenceIndex<0 then begin - Str:=ARef.Str; - Hash:=ARef.ReferenceHash; - end else begin - Str:=BESENArrayIndexToStr(TBESENUINT32(ARef.ReferenceIndex)); - Hash:=BESENHashKey(Str); - end; - end else begin - Str:=TBESEN(Instance).KeyIDManager.List[ARef.ReferenceID]; - Hash:=BESENHashKey(Str); - end; - if O.GetProperty(Str,Descriptor,Hash) then begin - if Descriptor.Presents<>[] then begin - if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin - if boppVALUE in Descriptor.Presents then begin - BESENCopyValue(AResult,Descriptor.Value); - end; - end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - if (boppGETTER in Descriptor.Presents) and assigned(Descriptor.Getter) then begin - TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Getter),BaseValue,nil,0,AResult); - end; - end; - end; - end; - finally - O.GarbageCollectorUnlock; - end; -end; - -procedure TBESENCodeContext.GetObject(const ARef:TBESENValue;var AResult:TBESENValue); -begin - if not assigned(ARef.ReferenceBase.Obj) then begin - BESENThrowNotDefined(ARef); - end; - if ARef.ReferenceID<0 then begin - if ARef.ReferenceIndex<0 then begin - TBESENObject(ARef.ReferenceBase.Obj).GetEx(ARef.Str,AResult,Descriptor,TBESENObject(ARef.ReferenceBase.Obj),ARef.ReferenceHash); - end else begin - TBESENObject(ARef.ReferenceBase.Obj).GetArrayIndex(TBESENUINT32(ARef.ReferenceIndex),AResult,TBESENObject(ARef.ReferenceBase.Obj)); - end; - end else begin - TBESENObject(ARef.ReferenceBase.Obj).GetIndex(ARef.ReferenceIndex,ARef.ReferenceID,AResult,TBESENObject(ARef.ReferenceBase.Obj)); - end; -end; - -procedure TBESENCodeContext.GetEnvRec(const ARef:TBESENValue;var AResult:TBESENValue); -begin - if ARef.ReferenceID<0 then begin - if ARef.ReferenceIndex<0 then begin - TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetBindingValueEx(ARef.Str,ARef.ReferenceIsStrict,AResult,Descriptor,ARef.ReferenceHash); - end else begin - TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetArrayIndexValue(TBESENUINT32(ARef.ReferenceIndex),ARef.ReferenceIsStrict,AResult); - end; - end else begin - TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetIndexValue(ARef.ReferenceIndex,ARef.ReferenceID,ARef.ReferenceIsStrict,AResult); - end; -end; - -procedure TBESENCodeContext.GetUndefined(const ARef:TBESENValue;var AResult:TBESENValue); -begin - BESENThrowNotDefined(ARef); -end; - -procedure TBESENCodeContext.GetValue(const AValue:TBESENValue;var AResult:TBESENValue); -begin - case AValue.ValueType of - bvtREFERENCE:begin - GetRefProcs[AValue.ReferenceBase.ValueType](AValue,AResult); - end; - bvtLOCAL:begin - Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(AValue.LocalIndex,-1,TBESEN(Instance).IsStrict,AResult); - end; - else begin - if @AResult<>@AValue then begin - BESENCopyValue(AResult,AValue); - end; - end; - end; -end; - -procedure TBESENCodeContext.PutPrimitive(const ARef,AValue:TBESENValue); -var O:TBESENObject; - ValuePointers:array[0..0] of PBESENValue; - Done:boolean; - Hash:TBESENHash; -begin - BESENReferenceBaseValueToValue(ARef.ReferenceBase,BaseValue); - if BaseValue.ValueType=bvtOBJECT then begin - O:=TBESENObject(BaseValue.Obj); - end else begin - O:=TBESEN(Instance).ToObj(BaseValue); - TBESEN(Instance).GarbageCollector.Add(O); - end; - if not assigned(O) then begin - BESENThrowNotAccessable(ARef); - end; - O.GarbageCollectorLock; - try - if ARef.ReferenceID<0 then begin - if ARef.ReferenceIndex<0 then begin - Str:=ARef.Str; - Hash:=ARef.ReferenceHash; - end else begin - Str:=BESENArrayIndexToStr(TBESENUINT32(ARef.ReferenceIndex)); - Hash:=BESENHashKey(Str); - end; - end else begin - Str:=TBESEN(Instance).KeyIDManager.List[ARef.ReferenceID]; - Hash:=BESENHashKey(Str); - end; - Done:=false; - if not O.CanPut(Str,Descriptor,Descriptor2,Hash) then begin - if ARef.ReferenceIsStrict then begin - BESENThrowNotAccessable(ARef); - end else begin - Done:=true; - end; - end; - if not Done then begin - if ([boppVALUE,boppWRITABLE]*Descriptor2.Presents)<>[] then begin - if ARef.ReferenceIsStrict then begin - BESENThrowNotAccessable(ARef); - end else begin - Done:=true; - end; - end; - if not Done then begin - if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin - ValuePointers[0]:=@AValue; - TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BaseValue,@ValuePointers,1,AnotherTemp); - end else begin - if ARef.ReferenceIsStrict then begin - BESENThrowNotAccessable(ARef); - end; - end; - end else begin - if ARef.ReferenceIsStrict then begin - BESENThrowNotAccessable(ARef); - end; - end; - end; - end; - finally - O.GarbageCollectorUnlock; - end; -end; - -procedure TBESENCodeContext.PutObject(const ARef,AValue:TBESENValue); -begin - if not assigned(ARef.ReferenceBase.Obj) then begin - BESENThrowNotAccessable(ARef); - end; - if ARef.ReferenceID<0 then begin - if ARef.ReferenceIndex<0 then begin - TBESENObject(ARef.ReferenceBase.Obj).PutEx(ARef.Str,AValue,ARef.ReferenceIsStrict,Descriptor,Descriptor2,AnotherTemp,ARef.ReferenceHash); - end else begin - TBESENObject(ARef.ReferenceBase.Obj).PutArrayIndex(TBESENUINT32(ARef.ReferenceIndex),AValue,ARef.ReferenceIsStrict); - end; - end else begin - TBESENObject(ARef.ReferenceBase.Obj).PutIndex(ARef.ReferenceIndex,ARef.ReferenceID,AValue,ARef.ReferenceIsStrict); - end; -end; - -procedure TBESENCodeContext.PutEnvRec(const ARef,AValue:TBESENValue); -begin - if ARef.ReferenceID<0 then begin - if ARef.ReferenceIndex<0 then begin - TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetMutableBindingEx(ARef.Str,AValue,ARef.ReferenceIsStrict,Descriptor,Descriptor2,AnotherTemp,ARef.ReferenceHash); - end else begin - TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetArrayIndexValue(TBESENUINT32(ARef.ReferenceIndex),AValue,ARef.ReferenceIsStrict); - end; - end else begin - TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetIndexValue(ARef.ReferenceIndex,ARef.ReferenceID,AValue,ARef.ReferenceIsStrict); - end; -end; - -procedure TBESENCodeContext.PutUndefined(const ARef,AValue:TBESENValue); -begin - if ARef.ReferenceIsStrict then begin - BESENThrowNotAccessable(ARef); - end else begin - TBESEN(Instance).ObjectGlobal.PutEx(ARef.Str,AValue,false,Descriptor,Descriptor2,AnotherTemp); - end; -end; - -procedure TBESENCodeContext.PutValue(const ARef,AValue:TBESENValue); -begin - if (AValue.ValueType=bvtOBJECT) and assigned(AValue.Obj) then begin - TBESENObject(AValue.Obj).GarbageCollectorWriteBarrier; - end; - case ARef.ValueType of - bvtREFERENCE:begin - PutRefProcs[ARef.ReferenceBase.ValueType](ARef,AValue); - end; - bvtLOCAL:begin - Context.VariableEnvironment.EnvironmentRecord.SetIndexValue(ARef.LocalIndex,-1,AValue,TBESEN(Instance).IsStrict); - end; - else begin - BESENThrowReference; - end; - end; -end; - -function TBESENCodeContext.AbstractRelational(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; -{$ifndef UseSafeOperations} -{$ifdef cpu386} -var a,b:TBESENNumber; - br:TBESENBoolean; -{$else} -var Item:PBESENNumberCodeAbstractRelationalLookupTableItem; -{$endif} -{$endif} -begin - result:=true; - if eva^.ValueType=bvtOBJECT then begin - TBESEN(Instance).ToPrimitiveValue(eva^,TBESEN(Instance).ObjectNumberConstructorValue,vaa); - eva:=@vaa; - end; - if evb^.ValueType=bvtOBJECT then begin - TBESEN(Instance).ToPrimitiveValue(evb^,TBESEN(Instance).ObjectNumberConstructorValue,vbb); - evb:=@vbb; - end; - if (eva^.ValueType=bvtSTRING) and (evb^.ValueType=bvtSTRING) then begin - BoolRes:=eva^.Str<evb^.Str; - end else begin - if eva^.ValueType<>bvtNUMBER then begin - TBESEN(Instance).ToNumberValue(eva^,va); - eva:=@va; - end; - if evb^.ValueType<>bvtNUMBER then begin - TBESEN(Instance).ToNumberValue(evb^,vb); - evb:=@vb; - end; -{$ifdef UseSafeOperations} - if BESENIsNaN(eva^.Num) or BESENIsNaN(evb^.Num) then begin - result:=false; - BoolRes:=false; - end else if BESENIsSameValue(eva^.Num,evb^.Num) then begin - BoolRes:=false; - end else if (BESENIsZero(eva^.Num) and BESENIsZero(evb^.Num)) and (BESENIsNegative(eva^.Num)<>BESENIsNegative(evb^.Num)) then begin - BoolRes:=false; - end else if BESENIsPosInfinite(eva^.Num) then begin - BoolRes:=false; - end else if BESENIsPosInfinite(evb^.Num) then begin - BoolRes:=true; - end else if BESENIsNegInfinite(evb^.Num) then begin - BoolRes:=false; - end else if BESENIsNegInfinite(eva^.Num) then begin - BoolRes:=true; - end else begin - BoolRes:=eva^.Num<evb^.Num; - end; -{$else} -{$ifdef cpu386} - a:=eva^.Num; - b:=evb^.Num; - asm - fld qword ptr [a] - fcomp qword ptr [b] - fstsw ax - sahf - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - mov dword ptr br,eax - neg cl - sbb ecx,ecx - mov dword ptr result,ecx - end {$ifdef fpc}['eax','ecx']{$endif}; - BoolRes:=br; -{$else} - Item:=@BESENNumberCodeAbstractRelationalLookupTable[((BESENNumberCodeFlags(eva^.Num) shl 4) or BESENNumberCodeFlags(evb^.Num)) and $ff]; - result:=Item^.IsNotUndefined; - BoolRes:=result and (Item^.ResultBooleanValue or (Item^.DoCompare and (eva^.Num<evb^.Num))); -{$endif} -{$endif} - end; -end; - -function TBESENCodeContext.AbstractRelationalNumber(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; -{$ifndef UseSafeOperations} -{$ifdef cpu386} -var a,b:TBESENNumber; - br:TBESENBoolean; -{$else} -var Item:PBESENNumberCodeAbstractRelationalLookupTableItem; -{$endif} -{$endif} -begin -{$ifdef UseSafeOperations} - result:=true; - if BESENIsNaN(eva^.Num) or BESENIsNaN(evb^.Num) then begin - result:=false; - BoolRes:=false; - end else if BESENIsSameValue(eva^.Num,evb^.Num) then begin - BoolRes:=false; - end else if (BESENIsZero(eva^.Num) and BESENIsZero(evb^.Num)) and (BESENIsNegative(eva^.Num)<>BESENIsNegative(evb^.Num)) then begin - BoolRes:=false; - end else if BESENIsPosInfinite(eva^.Num) then begin - BoolRes:=false; - end else if BESENIsPosInfinite(evb^.Num) then begin - BoolRes:=true; - end else if BESENIsNegInfinite(evb^.Num) then begin - BoolRes:=false; - end else if BESENIsNegInfinite(eva^.Num) then begin - BoolRes:=true; - end else begin - BoolRes:=eva^.Num<evb^.Num; - end; -{$else} -{$ifdef cpu386} - a:=eva^.Num; - b:=evb^.Num; - asm - fld qword ptr [a] - fcomp qword ptr [b] - fstsw ax - sahf - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - mov dword ptr br,eax - neg cl - sbb ecx,ecx - mov dword ptr result,ecx - end {$ifdef fpc}['eax','ecx']{$endif}; - BoolRes:=br; -{$else} - Item:=@BESENNumberCodeAbstractRelationalLookupTable[((BESENNumberCodeFlags(eva^.Num) shl 4) or BESENNumberCodeFlags(evb^.Num)) and $ff]; - result:=Item^.IsNotUndefined; - BoolRes:=result and (Item^.ResultBooleanValue or (Item^.DoCompare and (eva^.Num<evb^.Num))); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.Throw(const ThrowValue:TBESENValue); -begin - raise EBESENThrowException.Create('Throw',ThrowValue); -end; - -procedure TBESENCodeContext.OpSTOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Running:=false; - BlockRunning:=false; -end; - -procedure TBESENCodeContext.OpNEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var Counter,CountArguments:integer; - ConstructorValue:PBESENValue; - OldIsStrict:boolean; -begin - OldIsStrict:=TBESEN(Instance).IsStrict; - try - ConstructorValue:=@RegisterValues[Operands^[1]]; - CountArguments:=Operands^[2]; - for Counter:=0 to CountArguments-1 do begin - ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+3]]; - end; - if ConstructorValue^.ValueType<>bvtOBJECT then begin - BESENThrowTypeErrorNotAConstructorObject; - end else if not TBESENObject(ConstructorValue^.Obj).HasConstruct then begin - BESENThrowTypeErrorObjectHasNoConstruct; - end; - TBESEN(Instance).GarbageCollector.TriggerCollect; - TBESEN(Instance).ObjectConstruct(TBESENObject(ConstructorValue^.Obj),BESENUndefinedValue,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); - finally - TBESEN(Instance).IsStrict:=OldIsStrict; - end; -end; - -procedure TBESENCodeContext.OpCALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var Counter,CountArguments:integer; - Ref,Func:PBESENValue; - OldIsStrict,DirectCall:boolean; -begin - OldIsStrict:=TBESEN(Instance).IsStrict; - try - Ref:=@RegisterValues[Operands^[1]]; - Func:=@RegisterValues[Operands^[2]]; - CountArguments:=Operands^[3]; - for Counter:=0 to CountArguments-1 do begin - ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+4]]; - end; - if Func^.ValueType<>bvtOBJECT then begin - BESENThrowTypeErrorNotAFunction; - end else if not (assigned(Func^.Obj) and TBESENObject(Func^.Obj).HasCall) then begin - BESENThrowTypeErrorNotCallable; - end; - if Ref^.ValueType=bvtREFERENCE then begin - BESENRefBaseValueToCallThisArgValueProcs[Ref^.ReferenceBase.ValueType](CallThisArg,Ref^.ReferenceBase); - end else begin - CallThisArg.ValueType:=bvtUNDEFINED; - end; - if Func^.Obj=TBESEN(Instance).ObjectGlobalEval then begin - DirectCall:=((Ref^.ValueType=bvtREFERENCE) and (Ref^.ReferenceBase.ValueType=brbvtENVREC)) and TBESENEnvironmentRecord(Ref^.ReferenceBase.EnvRec).HasBindingEx('eval',Descriptor); - TBESEN(Instance).GlobalEval(Context,CallThisArg,@ParamArgs[0],CountArguments,DirectCall,RegisterValues[Operands^[0]]); - end else begin - TBESEN(Instance).ObjectCall(TBESENObject(Func^.Obj),CallThisArg,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); - end; - finally - TBESEN(Instance).IsStrict:=OldIsStrict; - end; -end; - -procedure TBESENCodeContext.OpEND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - NewBlockLevel:=Operands^[0]; - while Running and (BlockLevel>=NewBlockLevel) do begin - if BlockLevel=0 then begin - Running:=false; - BlockRunning:=false; - break; - end else begin - dec(BlockLevel); - Block:=@Blocks[BlockLevel]; - case Block^.BlockType of - bccbtENUM:begin - PropertyEnumerator:=Block^.OldPropertyEnumerator; - EnumBlock:=Block^.OldEnumBlock; - BESENFreeAndNil(Block^.PropertyEnumerator); - end; - bccbtWITH:begin - Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; - end; - bccbtCATCH:begin - Block^.Done:=true; - end; - bccbtCATCH2:begin - Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; - Block^.Ident:=''; - end; - bccbtFINALLY:begin - Block^.BlockType:=bccbtFINALLY2; - Block^.Done:=true; - Block^.Resume:=PC-2; - Block^.Raised:=false; - PC:=Block^.Handler; - inc(BlockLevel); - break; - end; - bccbtFINALLY2:begin - end; - end; - end; - end; -end; - -procedure TBESENCodeContext.OpVREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; - EnvRec:TBESENEnvironmentRecord; - CurrentObject:TBESENObject; - PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; - StructureID:integer; - CacheItem:PBESENCodePolymorphicInlineCacheItem; - CacheItemIndex:integer; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtREFERENCE; - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=Context.VariableEnvironment.EnvironmentRecord; - vp^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; - vp^.ReferenceHash:=TBESENHash(Operands^[2]); - - if TBESEN(Instance).InlineCacheEnabled then begin - EnvRec:=Context.VariableEnvironment.EnvironmentRecord; - if assigned(EnvRec) and (EnvRec is TBESENObjectEnvironmentRecord) then begin - CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; - if assigned(CurrentObject) then begin - PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[3]]; - - // Polymorphic lookup - if CurrentObject.StructureID<>0 then begin - for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; - if CurrentObject.StructureID=CacheItem^.StructureID then begin - if CacheItemIndex<>0 then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); - Operands^[4]:=CacheItem^.StructureID; - Operands^[5]:=BESENInt32BooleanValues[vp^.ReferenceIsStrict]; - Operands^[6]:=CacheItem^.Index; - Operands^[7]:=CacheItem^.ID; - end; - vp^.ReferenceIndex:=CacheItem^.Index; - vp^.ReferenceID:=CacheItem^.ID; - exit; - end; - end; - end; - - // Megamorphic lookup - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; - if CurrentObject.StructureID=0 then begin - if not CurrentObject.RebuildStructure then begin - CurrentObject:=nil; - end; - end; - if assigned(CurrentObject) then begin - StructureID:=CurrentObject.StructureID; - while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin - if CurrentObject.GetOwnProperty(Code.Variables[Operands^[1]].Name,Descriptor,vp^.ReferenceHash) then begin - if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); - vp^.ReferenceIndex:=CurrentObject.LastProp.Index; - vp^.ReferenceID:=CurrentObject.LastProp.ID; - CacheItem^.StructureID:=StructureID; - CacheItem^.Index:=vp^.ReferenceIndex; - CacheItem^.ID:=vp^.ReferenceID; - Operands^[4]:=CacheItem^.StructureID; - Operands^[5]:=BESENInt32BooleanValues[vp^.ReferenceIsStrict]; - Operands^[6]:=CacheItem^.Index; - Operands^[7]:=CacheItem^.ID; - exit; - end; - break; - end; - CurrentObject:=CurrentObject.Prototype; - end; - end; - - end; - end; - end; - - // Normal lookup - Operands^[4]:=-1; - vp^.ReferenceIndex:=-1; - vp^.ReferenceID:=-1; - vp^.Str:=Code.Variables[Operands^[1]].Name; -end; - -procedure TBESENCodeContext.OpLREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtLOCAL; - vp^.LocalIndex:=Operands^[1]; -end; - -procedure TBESENCodeContext.OpNOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin -end; - -procedure TBESENCodeContext.OpCOPY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); -end; - -procedure TBESENCodeContext.OpNEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r,a,b:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=not TBESEN(Instance).EqualityExpressionEquals(a^,b^); -end; - -procedure TBESENCodeContext.OpNSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r,a,b:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=not BESENEqualityExpressionStrictEquals(a^,b^); -end; - -procedure TBESENCodeContext.OpAREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; - DoubleIndex:PBESENNumber; -begin - r:=@RegisterValues[Operands^[0]]; - BESENValueToReferenceBaseValue(RegisterValues[Operands^[1]],r^.ReferenceBase); - r^.ValueType:=bvtREFERENCE; - r^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; - r^.ReferenceHash:=TBESENHash(Operands^[3]); - r^.ReferenceID:=-1; - DoubleIndex:=@RegisterValues[Operands^[2]].Num; - if (DoubleIndex^>=0) and (DoubleIndex^<2147483648.0) then begin // not 4294967296.0 due to ReferenceIndex<0 check ! - r^.ReferenceIndex:=TBESENINT32(TBESENUINT32(trunc(DoubleIndex^))); - end else begin - r^.ReferenceIndex:=-1; - r^.Str:=TBESEN(Instance).ToStr(RegisterValues[Operands^[2]]); - end; -end; - -procedure TBESENCodeContext.OpTHROW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - if Trace(bttTHROW) then begin - Throw(RegisterValues[Operands^[0]]); - end; -end; - -procedure TBESENCodeContext.OpSETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(ResultValue,RegisterValues[Operands^[0]]); -end; - -procedure TBESENCodeContext.OpGETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(RegisterValues[Operands^[0]],ResultValue); -end; - -procedure TBESENCodeContext.OpTHIS(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(RegisterValues[Operands^[0]],Context.ThisBinding); -end; - -procedure TBESENCodeContext.OpOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtOBJECT; - vp^.Obj:=TBESEN(Instance).ObjectConstructor; -end; - -procedure TBESENCodeContext.OpARRAY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtOBJECT; - vp^.Obj:=TBESEN(Instance).ObjectArrayConstructor; -end; - -procedure TBESENCodeContext.OpREGEXP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtOBJECT; - vp^.Obj:=TBESEN(Instance).ObjectRegExpConstructor; -end; - -procedure TBESENCodeContext.OpREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; - CurrentObject:TBESENObject; - PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; - CacheItemIndex:integer; - CacheItem:PBESENCodePolymorphicInlineCacheItem; - StructureID:integer; - StrReg:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - BESENValueToReferenceBaseValue(RegisterValues[Operands^[1]],r^.ReferenceBase); - r^.ValueType:=bvtREFERENCE; - r^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; - r^.ReferenceHash:=TBESENHash(Operands^[4]); - - if TBESEN(Instance).InlineCacheEnabled and (TBESENUINT32(Operands^[3])<>$fefefefe) and (r^.ReferenceBase.ValueType=brbvtOBJECT) then begin - CurrentObject:=TBESENObject(r^.ReferenceBase.Obj); - if assigned(CurrentObject) then begin - PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[5]]; - - // Polymorphic lookup - if CurrentObject.StructureID<>0 then begin - for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; - if CurrentObject.StructureID=CacheItem^.StructureID then begin - if CacheItemIndex<>0 then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); - Operands^[6]:=CacheItem^.StructureID; - Operands^[7]:=BESENInt32BooleanValues[r^.ReferenceIsStrict]; - Operands^[8]:=CacheItem^.Index; - Operands^[9]:=CacheItem^.ID; - end; - r^.ReferenceIndex:=CacheItem^.Index; - r^.ReferenceID:=CacheItem^.ID; - exit; - end; - end; - end; - - // Megamorphic lookup - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; - if CurrentObject.StructureID=0 then begin - if not CurrentObject.RebuildStructure then begin - CurrentObject:=nil; - end; - end; - if assigned(CurrentObject) then begin - StrReg:=@RegisterValues[Operands^[2]]; - StructureID:=CurrentObject.StructureID; - while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin - CurrentObject.LastProp:=nil; - if CurrentObject.GetOwnProperty(StrReg^.Str,Descriptor,r^.ReferenceHash) then begin - if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); - r^.ReferenceIndex:=CurrentObject.LastProp.Index; - r^.ReferenceID:=CurrentObject.LastProp.ID; - CacheItem^.StructureID:=StructureID; - CacheItem^.Index:=r^.ReferenceIndex; - CacheItem^.ID:=r^.ReferenceID; - Operands^[6]:=CacheItem^.StructureID; - Operands^[7]:=BESENInt32BooleanValues[r^.ReferenceIsStrict]; - Operands^[8]:=r^.ReferenceIndex; - Operands^[9]:=r^.ReferenceID; - exit; - end; - break; - end; - CurrentObject:=CurrentObject.Prototype; - end; - end; - - end; - end; - - // Normal lookup - Operands^[6]:=-1; - r^.ReferenceIndex:=-1; - r^.ReferenceID:=-1; - r^.Str:=RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpGETVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - case RegisterValues[Operands^[1]].ValueType of - bvtREFERENCE:begin - GetRefProcs[RegisterValues[Operands^[1]].ReferenceBase.ValueType](RegisterValues[Operands^[1]],RegisterValues[Operands^[0]]); - end; - bvtLOCAL:begin - Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(RegisterValues[Operands^[1]].LocalIndex,-1,TBESEN(Instance).IsStrict,RegisterValues[Operands^[0]]); - end; - else begin - BESENCopyValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); - end; - end; -end; - -procedure TBESENCodeContext.OpLOOKUP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; - PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; - Lex:TBESENLexicalEnvironment; - EnvRec:TBESENEnvironmentRecord; - CurrentObject:TBESENObject; - Item:PBESENDeclarativeEnvironmentRecordHashItem; - CacheItem:PBESENCodePolymorphicInlineCacheItem; - CacheItemIndex,NestedLevel,StructureID:integer; - FirstObjectEnvRec,DoIt:boolean; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtREFERENCE; - vp^.ReferenceBase.ValueType:=brbvtUNDEFINED; - vp^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; - vp^.ReferenceHash:=TBESENHash(Operands^[2]); - - if TBESEN(Instance).InlineCacheEnabled then begin - PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[3]]; - - // Polymorphic lookup - for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; - if CacheItem^.StructureID<>-1 then begin - NestedLevel:=CacheItem^.NestedLevel; - Lex:=Context.LexicalEnvironment; - while assigned(Lex) and (NestedLevel>0) do begin - dec(NestedLevel); - Lex:=Lex.Outer; - end; - if (NestedLevel=0) and assigned(Lex) then begin - EnvRec:=Lex.EnvironmentRecord; - if CacheItem^.StructureID>0 then begin - if EnvRec is TBESENObjectEnvironmentRecord then begin - CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; - if assigned(CurrentObject) and ((CurrentObject.StructureID<>0) and (CurrentObject.StructureID=CacheItem^.StructureID)) then begin - if CacheItemIndex<>0 then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); - end; - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=EnvRec; - vp^.ReferenceIndex:=CacheItem^.Index; - vp^.ReferenceID:=CacheItem^.ID; - exit; - end; - end; - end else begin - if EnvRec is TBESENDeclarativeEnvironmentRecord then begin - if (CacheItem^.Index<TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs.Count) and (TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs[CacheItem^.Index]=CacheItem^.ID) then begin - if CacheItemIndex<>0 then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); - end; - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=EnvRec; - vp^.ReferenceIndex:=CacheItem^.Index; - vp^.ReferenceID:=CacheItem^.ID; - exit; - end; - end; - end; - end; - end; - end; - - // Megamorphic lookup - vp^.ReferenceIndex:=-1; - vp^.ReferenceID:=-1; - vp^.Str:=LookupNames^[Operands^[1]]; - CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; - FirstObjectEnvRec:=true; - DoIt:=true; - NestedLevel:=0; - Lex:=Context.LexicalEnvironment; - while assigned(Lex) do begin - EnvRec:=Lex.EnvironmentRecord; - if DoIt and (EnvRec.HasMaybeDirectEval and not EnvRec.IsStrict) then begin - // If the direct eval is in an es5-strict-mode code body (top level or function), it can't create vars in - // that code lexical body's scope. But in an es5-non-strict code body (top level or function) we must disable - // here the caching, because a direct eval can create here vars in that code body's lexical scope. - DoIt:=false; - end; - if EnvRec is TBESENObjectEnvironmentRecord then begin - CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; - if assigned(CurrentObject) then begin - if CurrentObject.StructureID=0 then begin - if not CurrentObject.RebuildStructure then begin - CurrentObject:=nil; - end; - end; - if assigned(CurrentObject) then begin - StructureID:=CurrentObject.StructureID; - while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin - if CurrentObject.GetOwnProperty(vp^.Str,Descriptor,vp^.ReferenceHash) then begin - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=EnvRec; - if DoIt and FirstObjectEnvRec then begin - FirstObjectEnvRec:=false; - if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); - vp^.ReferenceIndex:=CurrentObject.LastProp.Index; - vp^.ReferenceID:=CurrentObject.LastProp.ID; - CacheItem^.StructureID:=StructureID; - CacheItem^.Index:=vp^.ReferenceIndex; - CacheItem^.ID:=vp^.ReferenceID; - CacheItem^.NestedLevel:=NestedLevel; - end; - end; - exit; - end; - CurrentObject:=CurrentObject.Prototype; - end; - end; - end; - end else begin - Item:=TBESENDeclarativeEnvironmentRecord(EnvRec).GetKey(vp^.Str); - if assigned(Item) then begin - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=EnvRec; - if DoIt and (Item^.Index>=0) then begin - PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); - vp^.ReferenceIndex:=Item^.Index; - vp^.ReferenceID:=TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs[vp^.ReferenceIndex]; - CacheItem^.StructureID:=-2; - CacheItem^.Index:=vp^.ReferenceIndex; - CacheItem^.ID:=vp^.ReferenceID; - CacheItem^.NestedLevel:=NestedLevel; - end; - exit; - end; - end; - inc(NestedLevel); - Lex:=Lex.Outer; - end; - end else begin - // Normal lookup - vp^.ReferenceIndex:=-1; - vp^.ReferenceID:=-1; - vp^.Str:=LookupNames^[Operands^[1]]; - Lex:=Context.LexicalEnvironment; - while assigned(Lex) do begin - EnvRec:=Lex.EnvironmentRecord; - if assigned(EnvRec) then begin - if EnvRec is TBESENObjectEnvironmentRecord then begin - CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; - while assigned(CurrentObject) do begin - if CurrentObject.GetOwnProperty(vp^.Str,Descriptor,vp^.ReferenceHash) then begin - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=EnvRec; - exit; - end; - CurrentObject:=CurrentObject.Prototype; - end; - end else if EnvRec is TBESENDeclarativeEnvironmentRecord then begin - Item:=TBESENDeclarativeEnvironmentRecord(EnvRec).GetKey(vp^.Str); - if assigned(Item) then begin - vp^.ReferenceBase.ValueType:=brbvtENVREC; - vp^.ReferenceBase.EnvRec:=EnvRec; - exit; - end; - end; - end; - Lex:=Lex.Outer; - end; - end; -end; - -procedure TBESENCodeContext.OpPUTVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - PutValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); -end; - -procedure TBESENCodeContext.OpDELETE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; - bv:TBESENBoolean; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - case up^.ValueType of - bvtREFERENCE:begin - case up^.ReferenceBase.ValueType of - brbvtBOOLEAN,brbvtNUMBER,brbvtSTRING:begin - BESENReferenceBaseValueToValue(up^.ReferenceBase,Temp); - if up^.ReferenceID<0 then begin - if up^.ReferenceIndex<0 then begin - bv:=TBESEN(Instance).ToObj(Temp).DeleteEx(up^.Str,up^.ReferenceIsStrict,Descriptor,up^.ReferenceHash); - end else begin - bv:=TBESEN(Instance).ToObj(Temp).DeleteArrayIndex(up^.ReferenceIndex,up^.ReferenceIsStrict); - end; - end else begin - bv:=TBESEN(Instance).ToObj(Temp).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID,up^.ReferenceIsStrict); - end; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=bv; - end; - brbvtOBJECT:begin - if up^.ReferenceID<0 then begin - if up^.ReferenceIndex<0 then begin - bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteEx(up^.Str,up^.ReferenceIsStrict,Descriptor,up^.ReferenceHash); - end else begin - bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteArrayIndex(up^.ReferenceIndex,up^.ReferenceIsStrict); - end; - end else begin - bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID,up^.ReferenceIsStrict); - end; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=bv; - end; - brbvtENVREC:begin - if up^.ReferenceIsStrict then begin - BESENThrowSyntaxError('"delete" not allowed here'); - end; - if up^.ReferenceID<0 then begin - if up^.ReferenceIndex<0 then begin - bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteBindingEx(up^.Str,Descriptor,up^.ReferenceHash); - end else begin - bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteArrayIndex(TBESENUINT32(up^.ReferenceIndex)); - end; - end else begin - bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID); - end; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=bv; - end; - else begin - if up^.ReferenceIsStrict then begin - BESENThrowSyntaxError('"delete" not allowed here'); - end else begin - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=true; - end; - end; - end; - end; - bvtLOCAL:begin - if TBESEN(Instance).IsStrict then begin - BESENThrowSyntaxError('"delete" not allowed here'); - end; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=Context.VariableEnvironment.EnvironmentRecord.DeleteIndex(up^.LocalIndex,-1); - end; - else begin - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=true; - end; - end; -end; - -procedure TBESENCodeContext.OpTYPEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - if up^.ValueType=bvtREFERENCE then begin - if not (up^.ReferenceBase.ValueType in [brbvtBOOLEAN,brbvtNUMBER,brbvtSTRING,brbvtOBJECT,brbvtENVREC]) then begin - Temp.ValueType:=bvtUNDEFINED; - end else begin - GetValue(up^,Temp); - end; - end else if up^.ValueType=bvtLOCAL then begin - Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(up^.LocalIndex,-1,TBESEN(Instance).IsStrict,Temp); - end else begin - BESENCopyValueProcs[up^.ValueType](Temp,up^); - end; - vp^.ValueType:=bvtSTRING; - case Temp.ValueType of - bvtUNDEFINED:begin - vp^.Str:='undefined'; - end; - bvtNULL:begin - vp^.Str:='object'; - end; - bvtBOOLEAN:begin - vp^.Str:='boolean'; - end; - bvtNUMBER:begin - vp^.Str:='number'; - end; - bvtSTRING:begin - vp^.Str:='string'; - end; - bvtOBJECT:begin - if assigned(Temp.Obj) and TBESENObject(Temp.Obj).HasCall then begin - vp^.Str:='function'; - end else begin - vp^.Str:='object'; - end; - end; - else begin - vp^.Str:='unknown'; - end; - end; -end; - -procedure TBESENCodeContext.OpTOOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - if up^.ValueType<>bvtOBJECT then begin - TBESEN(Instance).ToObjectValue(up^,vp^); - end else begin - BESENCopyValue(vp^,up^); - end; -end; - -procedure TBESENCodeContext.OpTONUMBER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - if up^.ValueType<>bvtNUMBER then begin - TBESEN(Instance).ToNumberValue(up^,vp^); - end else begin - BESENCopyValue(vp^,up^); - end; -end; - -procedure TBESENCodeContext.OpTOBOOLEAN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - if up^.ValueType<>bvtBOOLEAN then begin - TBESEN(Instance).ToBooleanValue(up^,vp^); - end else begin - BESENCopyValue(vp^,up^); - end; -end; - -procedure TBESENCodeContext.OpTOSTRING(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - if up^.ValueType<>bvtSTRING then begin - TBESEN(Instance).ToStringValue(up^,vp^); - end else begin - BESENCopyValue(vp^,up^); - end; -end; - -procedure TBESENCodeContext.OpTOPRIMITIVE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up,vp:PBESENValue; -begin - up:=@RegisterValues[Operands^[1]]; - vp:=@RegisterValues[Operands^[0]]; - if up^.ValueType=bvtOBJECT then begin - TBESEN(Instance).ToPrimitiveValue(up^,BESENEmptyValue,vp^); - end else begin - BESENCopyValue(vp^,up^); - end; -end; - -procedure TBESENCodeContext.OpNEG(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; -{$ifdef fpc} - PBESENQWORD(@r^.Num)^:=PBESENQWORD(@RegisterValues[Operands^[1]].Num)^ xor qword($8000000000000000); -{$else} - PBESENINT64(@r^.Num)^:=PBESENINT64(@RegisterValues[Operands^[1]].Num)^ xor int64($8000000000000000); -{$endif} -end; - -procedure TBESENCodeContext.OpINV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(not TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]])); -end; - -procedure TBESENCodeContext.OpNOT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=not RegisterValues[Operands^[1]].Bool; -end; - -procedure TBESENCodeContext.OpMUL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num*RegisterValues[Operands^[2]].Num; -end; - -procedure TBESENCodeContext.OpDIV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num/RegisterValues[Operands^[2]].Num; -end; - -procedure TBESENCodeContext.OpMOD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=BESENModulo(RegisterValues[Operands^[1]].Num,RegisterValues[Operands^[2]].Num); -end; - -procedure TBESENCodeContext.OpADD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r,a,b:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - if (a^.ValueType=bvtSTRING) or (b^.ValueType=bvtSTRING) then begin - if a^.ValueType<>bvtSTRING then begin - TBESEN(Instance).ToStringValue(a^,va); - a:=@va; - end; - if b^.ValueType<>bvtSTRING then begin - TBESEN(Instance).ToStringValue(b^,vb); - b:=@vb; - end; - r^.ValueType:=bvtSTRING; - r^.Str:=a^.Str+b^.Str; - end else begin - if a^.ValueType<>bvtNUMBER then begin - TBESEN(Instance).ToNumberValue(a^,va); - a:=@va; - end; - if b^.ValueType<>bvtNUMBER then begin - TBESEN(Instance).ToNumberValue(b^,vb); - b:=@vb; - end; - r^.ValueType:=bvtNUMBER; - r^.Num:=a^.Num+b^.Num; - end; -end; - -procedure TBESENCodeContext.OpADDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num+RegisterValues[Operands^[2]].Num; -end; - -procedure TBESENCodeContext.OpSUB(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num-RegisterValues[Operands^[2]].Num; -end; - -procedure TBESENCodeContext.OpSHL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) shl (TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); -end; - -procedure TBESENCodeContext.OpSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(sar(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]),TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); -end; - -procedure TBESENCodeContext.OpUSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENUINT32(TBESEN(Instance).ToUInt32(RegisterValues[Operands^[1]]) shr (TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); -end; - -procedure TBESENCodeContext.OpLT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - AbstractRelational(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool); -end; - -procedure TBESENCodeContext.OpGT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - AbstractRelational(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); -end; - -procedure TBESENCodeContext.OpLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - if AbstractRelational(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin - r^.Bool:=not r^.Bool; - end; -end; - -procedure TBESENCodeContext.OpGE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - if AbstractRelational(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool) then begin - r^.Bool:=not r^.Bool; - end; -end; - -procedure TBESENCodeContext.OpINSTANCEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r,a,b:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - r^.ValueType:=bvtBOOLEAN; - if b^.ValueType<>bvtOBJECT then begin - BESENThrowTypeError('Not a object'); - end else begin - r^.Bool:=TBESEN(Instance).ObjectInstanceOf(a^,TBESENObject(b^.Obj)); - end; -end; - -procedure TBESENCodeContext.OpIN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r,a,b:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - r^.ValueType:=bvtBOOLEAN; - if b^.ValueType<>bvtOBJECT then begin - BESENThrowTypeError('Not a object'); - end else begin - r^.Bool:=TBESENObject(b^.Obj).HasPropertyEx(TBESEN(Instance).ToStr(a^),Descriptor); - end; -end; - -procedure TBESENCodeContext.OpEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=TBESEN(Instance).EqualityExpressionEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); -end; - -procedure TBESENCodeContext.OpSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); -end; - -procedure TBESENCodeContext.OpBAND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) and TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); -end; - -procedure TBESENCodeContext.OpBXOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) xor TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); -end; - -procedure TBESENCodeContext.OpBOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) or TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); -end; - -procedure TBESENCodeContext.OpSENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; - Obj:TBESENObject; -begin - vp:=@RegisterValues[Operands^[0]]; - case vp^.ValueType of - bvtNULL,bvtUNDEFINED:begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin - Obj:=TBESEN(Instance).ObjectEmpty; - end else begin - Obj:=nil; - end; - end; - bvtOBJECT:begin - Obj:=TBESENObject(vp^.Obj); - end; - else begin - Obj:=nil; - end; - end; - if assigned(Obj) then begin - Block:=@Blocks[BlockLevel]; - Block^.BlockType:=bccbtENUM; - Block^.PropertyEnumerator:=Obj.Enumerator(false,false); - Block^.PropertyEnumerator.Reset; - Block^.OldPropertyEnumerator:=PropertyEnumerator; - PropertyEnumerator:=Block^.PropertyEnumerator; - Block^.OldEnumBlock:=EnumBlock; - EnumBlock:=Block; - inc(BlockLevel); - end else begin - BESENThrowTypeError('Not an object'); - end; -end; - -procedure TBESENCodeContext.OpSWITH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - Block:=@Blocks[BlockLevel]; - Block^.BlockType:=bccbtWITH; - Block^.LexicalEnvironment:=TBESEN(Instance).NewObjectEnvironment(TBESENObject(vp^.Obj),Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); - TBESEN(Instance).GarbageCollector.Add(Block^.LexicalEnvironment); - Context.LexicalEnvironment:=Block^.LexicalEnvironment; - TBESENObjectEnvironmentRecord(Block^.LexicalEnvironment.EnvironmentRecord).ProvideThis:=true; - Block^.LexicalEnvironment.EnvironmentRecord.UpdateImplicitThisValue; - inc(BlockLevel); -end; - -procedure TBESENCodeContext.OpSCATCH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Block:=@Blocks[BlockLevel-1]; - Block^.BlockType:=bccbtCATCH2; - Block^.LexicalEnvironment:=TBESEN(Instance).NewDeclarativeEnvironment(Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); - TBESEN(Instance).GarbageCollector.Add(Block^.LexicalEnvironment); - Context.LexicalEnvironment:=Block^.LexicalEnvironment; - Block^.LexicalEnvironment.EnvironmentRecord.CreateMutableBinding(Block^.Ident,false); - Block^.LexicalEnvironment.EnvironmentRecord.SetMutableBindingEx(Block^.Ident,Block^.Value,false,Descriptor,Descriptor2,AnotherTemp,BESENHashKey(Block^.Ident)); - Block^.Ident:=''; -end; - -procedure TBESENCodeContext.OpENDF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - dec(BlockLevel); - Block:=@Blocks[BlockLevel]; - if Block^.Raised or (Block^.Resume>=longword(Code.ByteCodeLen)) then begin - BlockRunning:=false; - end else begin - PC:=Block^.Resume; - end; -end; - -procedure TBESENCodeContext.OpJMP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - PC:=Operands^[0]; -end; - -procedure TBESENCodeContext.OpJZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - if RegisterValues[Operands^[1]].Bool then begin - PC:=Operands^[0]; - end; -end; - -procedure TBESENCodeContext.OpJNZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - if not RegisterValues[Operands^[1]].Bool then begin - PC:=Operands^[0]; - end; -end; - -procedure TBESENCodeContext.OpJNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[1]]; - if (vp^.ValueType in [bvtUNDEFINED,bvtNULL]) or ((vp^.ValueType=bvtOBJECT) and not assigned(vp^.Obj)) then begin - PC:=Operands^[0]; - end; -end; - -procedure TBESENCodeContext.OpLOOPENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - if PropertyEnumerator.GetNext(Str) then begin - vp:=@RegisterValues[Operands^[1]]; - vp^.ValueType:=bvtSTRING; - vp^.Str:=Str; - PC:=Operands^[0]; - end; -end; - -procedure TBESENCodeContext.OpSTRYC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Block:=@Blocks[BlockLevel]; - inc(BlockLevel); - Block^.BlockType:=bccbtCATCH; - Block^.Handler:=Operands^[0]; - Block^.Ident:=RegisterValues[Operands^[1]].Str; -end; - -procedure TBESENCodeContext.OpSTRYF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Block:=@Blocks[BlockLevel]; - inc(BlockLevel); - Block^.BlockType:=bccbtFINALLY; - Block^.Handler:=Operands^[0]; -end; - -procedure TBESENCodeContext.OpLITERAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(RegisterValues[Operands^[0]],Code.Literals[Operands^[1]]); -end; - -procedure TBESENCodeContext.OpLITERALUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - RegisterValues[Operands^[0]].ValueType:=bvtUNDEFINED; -end; - -procedure TBESENCodeContext.OpLITERALNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - RegisterValues[Operands^[0]].ValueType:=bvtNULL; -end; - -procedure TBESENCodeContext.OpLITERALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=Operands^[1]<>0; -end; - -procedure TBESENCodeContext.OpLITERALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtNUMBER; - vp^.Num:=Code.Literals[Operands^[1]].Num; -end; - -procedure TBESENCodeContext.OpLITERALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtSTRING; - vp^.Str:=Code.Literals[Operands^[1]].Str; -end; - -procedure TBESENCodeContext.OpLITERALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtOBJECT; - vp^.Obj:=Code.Literals[Operands^[1]].Obj; -end; - -procedure TBESENCodeContext.OpFUNC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; - Arg:TBESENINT32; -begin - vp:=@RegisterValues[Operands^[0]]; - Arg:=Operands^[1]; - if assigned(Code.FunctionLiteralContainers[Arg].Literal.Name) and (length(Code.FunctionLiteralContainers[Arg].Literal.Name.Name)>0) then begin - LexicalEnvironment:=TBESEN(Instance).NewDeclarativeEnvironment(Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); - OldLexicalEnvironment:=Context.LexicalEnvironment; - Context.LexicalEnvironment:=LexicalEnvironment; - TBESEN(Instance).GarbageCollector.Add(LexicalEnvironment); - try - vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,Code.FunctionLiteralContainers[Arg].Literal.Name.Name,Context.LexicalEnvironment)); - LexicalEnvironment.EnvironmentRecord.CreateImmutableBinding(TBESENObjectDeclaredFunction(vp^.Obj).ObjectName); - LexicalEnvironment.EnvironmentRecord.InitializeImmutableBinding(TBESENObjectDeclaredFunction(vp^.Obj).ObjectName,vp^); - finally - Context.LexicalEnvironment:=OldLexicalEnvironment; - end; - end else begin - if assigned(Code.FunctionLiteralContainers[Arg].Literal.Name) then begin - vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,Code.FunctionLiteralContainers[Arg].Literal.Name.Name,Context.LexicalEnvironment)); - end else begin - vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,'',Context.LexicalEnvironment)); - end; - end; -end; - -procedure TBESENCodeContext.OpLINE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - TBESEN(Instance).LineNumber:=Code.Locations[Operands^[0]].LineNumber; -end; - -procedure TBESENCodeContext.OpGC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - TBESEN(Instance).GarbageCollector.TriggerCollect; -end; - -procedure TBESENCodeContext.OpSTRICT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - TBESEN(Instance).IsStrict:=Operands^[0]<>0; -end; - -procedure TBESENCodeContext.OpSTRICTCHECKREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var up:PBESENValue; - der:TBESENDeclarativeEnvironmentRecord; - procedure ThrowIt(const s:TBESENSTRING); - begin - BESENThrowSyntaxError('"'+s+'" not allowed here'); - end; - procedure Check(const s:TBESENSTRING); - begin - if (s='eval') or (s='arguments') then begin - ThrowIt(s); - end; - end; -begin - up:=@RegisterValues[Operands^[0]]; - if up^.ReferenceIsStrict then begin - case up^.ValueType of - bvtREFERENCE:begin - case up^.ReferenceBase.ValueType of - brbvtENVREC:begin - if up^.ReferenceID<0 then begin - if up^.ReferenceIndex<0 then begin - Check(up^.Str); - end; - end else begin - if up^.ReferenceBase.EnvRec is TBESENDeclarativeEnvironmentRecord then begin - der:=TBESENDeclarativeEnvironmentRecord(up^.ReferenceBase.EnvRec); - if (up^.ReferenceIndex>=0) and (up^.ReferenceIndex<der.HashIndexNames.Count) then begin - Check(der.HashIndexNames.FList[up^.ReferenceIndex]); - end; - end else begin - if (up^.ReferenceIndex>=0) and (up^.ReferenceIndex<=TBESEN(Instance).KeyIDManager.List.Count) then begin - Check(TBESEN(Instance).KeyIDManager.List.FList[up^.ReferenceID]); - end; - end; - end; - end; - end; - end; - bvtLOCAL:begin - der:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord); - if (up^.LocalIndex>=0) and (up^.LocalIndex<der.HashIndexNames.Count) then begin - Check(der.HashIndexNames.FList[up^.LocalIndex]); - end; - end; - end; - end; -end; - -procedure TBESENCodeContext.OpDEBUGGER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Trace(bttDEBUGGER); -end; - -procedure TBESENCodeContext.OpCHECKOBJECTCOERCIBLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCheckObjectCoercible(RegisterValues[Operands^[0]]); -end; - -procedure TBESENCodeContext.OpPUTOBJVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var ObjReg,StrReg,ValReg:PBESENValue; -begin - ObjReg:=@RegisterValues[Operands^[0]]; - StrReg:=@RegisterValues[Operands^[1]]; - ValReg:=@RegisterValues[Operands^[2]]; - TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENDataPropertyDescriptor(ValReg^,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); -end; - -procedure TBESENCodeContext.OpPUTOBJGET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var ObjReg,StrReg,ValReg:PBESENValue; -begin - ObjReg:=@RegisterValues[Operands^[0]]; - StrReg:=@RegisterValues[Operands^[1]]; - ValReg:=@RegisterValues[Operands^[2]]; - TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENAccessorPropertyDescriptor(TBESENObject(ValReg^.Obj),nil,[bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); -end; - -procedure TBESENCodeContext.OpPUTOBJSET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var ObjReg,StrReg,ValReg:PBESENValue; -begin - ObjReg:=@RegisterValues[Operands^[0]]; - StrReg:=@RegisterValues[Operands^[1]]; - ValReg:=@RegisterValues[Operands^[2]]; - TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENAccessorPropertyDescriptor(nil,TBESENObject(ValReg^.Obj),[bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); -end; - -procedure TBESENCodeContext.OpINC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num+1; -end; - -procedure TBESENCodeContext.OpDEC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num-1; -end; - -procedure TBESENCodeContext.OpCOPYBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool; -end; - -procedure TBESENCodeContext.OpCOPYNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=RegisterValues[Operands^[1]].Num; -end; - -procedure TBESENCodeContext.OpCOPYSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtSTRING; - r^.Str:=RegisterValues[Operands^[1]].Str; -end; - -procedure TBESENCodeContext.OpCOPYOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtOBJECT; - r^.Obj:=RegisterValues[Operands^[1]].Obj; -end; - -procedure TBESENCodeContext.OpCOPYREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r,a:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - a:=@RegisterValues[Operands^[1]]; - r^.ValueType:=bvtREFERENCE; - BESENCopyReferenceBaseValue(r^.ReferenceBase,a^.ReferenceBase); - r^.Str:=a^.Str; - r^.ReferenceIsStrict:=a^.ReferenceIsStrict; - r^.ReferenceHash:=a^.ReferenceHash; - r^.ReferenceIndex:=a^.ReferenceIndex; - r^.ReferenceID:=a^.ReferenceID; -end; - -procedure TBESENCodeContext.OpCOPYLOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtLOCAL; - r^.LocalIndex:=RegisterValues[Operands^[1]].LocalIndex; -end; - -procedure TBESENCodeContext.OpGETVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - GetRefProcs[RegisterValues[Operands^[1]].ReferenceBase.ValueType](RegisterValues[Operands^[1]],RegisterValues[Operands^[0]]); -end; - -procedure TBESENCodeContext.OpPUTVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - PutRefProcs[RegisterValues[Operands^[0]].ReferenceBase.ValueType](RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); -end; - -procedure TBESENCodeContext.OpGETVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(RegisterValues[Operands^[1]].LocalIndex,-1,TBESEN(Instance).IsStrict,RegisterValues[Operands^[0]]); -end; - -procedure TBESENCodeContext.OpPUTVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Context.VariableEnvironment.EnvironmentRecord.SetIndexValue(RegisterValues[Operands^[0]].LocalIndex,-1,RegisterValues[Operands^[1]],TBESEN(Instance).IsStrict); -end; - -procedure TBESENCodeContext.OpGETVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(RegisterValues[Operands^[0]],TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex]^); -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]^,RegisterValues[Operands^[1]]); -end; - -procedure TBESENCodeContext.OpGETVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex]^.Bool; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; - hp^.ValueType:=bvtBOOLEAN; - hp^.Bool:=RegisterValues[Operands^[1]].Bool; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtNUMBER; - vp^.Num:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Num; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; - hp^.ValueType:=bvtNUMBER; - hp^.Num:=RegisterValues[Operands^[1]].Num; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtSTRING; - vp^.Str:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Str; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; - hp^.ValueType:=bvtSTRING; - hp^.Str:=RegisterValues[Operands^[1]].Str; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtOBJECT; - vp^.Obj:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Obj; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; - hp^.ValueType:=bvtOBJECT; - hp^.Obj:=RegisterValues[Operands^[1]].Obj; - if assigned(hp^.Obj) then begin - TBESENObject(hp^.Obj).GarbageCollectorWriteBarrier; - end; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(RegisterValues[Operands^[0]],TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]]^); -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]^,RegisterValues[Operands^[1]]); -end; - -procedure TBESENCodeContext.OpGETVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtBOOLEAN; - vp^.Bool:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]]^.Bool; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; - hp^.ValueType:=bvtBOOLEAN; - hp^.Bool:=RegisterValues[Operands^[1]].Bool; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtNUMBER; - vp^.Num:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Num; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; - hp^.ValueType:=bvtNUMBER; - hp^.Num:=RegisterValues[Operands^[1]].Num; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtSTRING; - vp^.Str:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Str; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; - hp^.ValueType:=bvtSTRING; - hp^.Str:=RegisterValues[Operands^[1]].Str; -end; - -procedure TBESENCodeContext.OpGETVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var vp:PBESENValue; -begin - vp:=@RegisterValues[Operands^[0]]; - vp^.ValueType:=bvtOBJECT; - vp^.Obj:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Obj; -end; - -procedure TBESENCodeContext.OpPUTVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var hp:PBESENValue; -begin - hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; - hp^.ValueType:=bvtOBJECT; - hp^.Obj:=RegisterValues[Operands^[1]].Obj; - if assigned(hp^.Obj) then begin - TBESENObject(hp^.Obj).GarbageCollectorWriteBarrier; - end; -end; - -procedure TBESENCodeContext.OpLOOPINITCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin -end; - -procedure TBESENCodeContext.OpLOOPADDCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin -end; - -procedure TBESENCodeContext.OpTRACE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - Trace(bttSTATEMENT); - if assigned(TBESEN(Instance).PeriodicHook) then begin - if not TBESEN(Instance).PeriodicHook(TBESEN(Instance)) then begin - Running:=false; - BlockRunning:=false; - end; - end; -end; - -procedure TBESENCodeContext.OpLTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool<RegisterValues[Operands^[2]].Bool; -end; - -procedure TBESENCodeContext.OpGTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool>RegisterValues[Operands^[2]].Bool; -end; - -procedure TBESENCodeContext.OpLEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool<=RegisterValues[Operands^[2]].Bool; -end; - -procedure TBESENCodeContext.OpGEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool>=RegisterValues[Operands^[2]].Bool; -end; - -procedure TBESENCodeContext.OpEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool=RegisterValues[Operands^[2]].Bool; -end; - -procedure TBESENCodeContext.OpNEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Bool<>RegisterValues[Operands^[2]].Bool; -end; - -procedure TBESENCodeContext.OpLTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - AbstractRelationalNumber(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool); -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<RegisterValues[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpGTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@RegisterValues[Operands^[2]]; - b:=@RegisterValues[Operands^[1]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setnbe al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - AbstractRelationalNumber(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); -{$else} -r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>RegisterValues[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpLENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@RegisterValues[Operands^[2]]; - b:=@RegisterValues[Operands^[1]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - not al - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setbe al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - if AbstractRelationalNumber(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin - r^.Bool:=not r^.Bool; - end; -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<=RegisterValues[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpGENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - not al - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setnb al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - if AbstractRelationalNumber(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool) then begin - r^.Bool:=not r^.Bool; - end; -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>=RegisterValues[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef UseSafeOperations} - r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); -{$else} -{$ifdef cpu386} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=RegisterValues[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpNEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef UseSafeOperations} - r^.Bool:=not BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); -{$else} -{$ifdef cpu386} - a:=@RegisterValues[Operands^[1]]; - b:=@RegisterValues[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - not eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$else} - r^.Bool:=not ((not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=RegisterValues[Operands^[2]].Num)); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpLTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Str<RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpGTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Str>RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpLESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Str<=RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpGESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Str>=RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Str=RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpNEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; - r^.Bool:=RegisterValues[Operands^[1]].Str<>RegisterValues[Operands^[2]].Str; -end; - -procedure TBESENCodeContext.OpSHLBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool] shl BESENNumberBooleanValues[RegisterValues[Operands^[2]].Bool]); -end; - -procedure TBESENCodeContext.OpSHRBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool] shr BESENNumberBooleanValues[RegisterValues[Operands^[2]].Bool]); -end; - -procedure TBESENCodeContext.OpBANDBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool and RegisterValues[Operands^[2]].Bool]; -end; - -procedure TBESENCodeContext.OpBXORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool xor RegisterValues[Operands^[2]].Bool]; -end; - -procedure TBESENCodeContext.OpBORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool or RegisterValues[Operands^[2]].Bool]; -end; - -procedure TBESENCodeContext.OpSHLNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) shl (BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31)); -end; - -procedure TBESENCodeContext.OpSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(sar(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num),(BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31))); -end; - -procedure TBESENCodeContext.OpUSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENUINT32(BESENToUInt32Fast(@RegisterValues[Operands^[1]].Num) shr (BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31)); -end; - -procedure TBESENCodeContext.OpBANDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) and BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); -end; - -procedure TBESENCodeContext.OpBXORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) xor BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); -end; - -procedure TBESENCodeContext.OpBORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtNUMBER; - r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) or BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); -end; - -procedure TBESENCodeContext.OpSETCUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - ResultValue.ValueType:=bvtUNDEFINED; -end; - -procedure TBESENCodeContext.OpSETCNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - ResultValue.ValueType:=bvtNULL; -end; - -procedure TBESENCodeContext.OpSETCBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=RegisterValues[Operands^[0]].Bool; -end; - -procedure TBESENCodeContext.OpSETCNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=RegisterValues[Operands^[0]].Num; -end; - -procedure TBESENCodeContext.OpSETCSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:=RegisterValues[Operands^[0]].Str; -end; - -procedure TBESENCodeContext.OpSETCOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - ResultValue.ValueType:=bvtOBJECT; - ResultValue.Obj:=RegisterValues[Operands^[0]].Obj; -end; - -procedure TBESENCodeContext.OpTRACENEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var Counter,CountArguments:integer; - OldIsStrict:boolean; - ConstructorValue:PBESENValue; -begin - OldIsStrict:=TBESEN(Instance).IsStrict; - try - ConstructorValue:=@RegisterValues[Operands^[1]]; - CountArguments:=Operands^[2]; - for Counter:=0 to CountArguments-1 do begin - ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+3]]; - end; - if ConstructorValue^.ValueType<>bvtOBJECT then begin - BESENThrowTypeErrorNotAConstructorObject; - end else if not TBESENObject(ConstructorValue^.Obj).HasConstruct then begin - BESENThrowTypeErrorObjectHasNoConstruct; - end; - if Trace(bttCALL) then begin - TBESEN(Instance).GarbageCollector.TriggerCollect; - TBESEN(Instance).ObjectConstruct(TBESENObject(ConstructorValue^.Obj),BESENUndefinedValue,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); - Trace(bttRETURN); - end else begin - RegisterValues[Operands^[0]].ValueType:=bvtUNDEFINED; - end; - finally - TBESEN(Instance).IsStrict:=OldIsStrict; - end; -end; - -procedure TBESENCodeContext.OpTRACECALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var Counter,CountArguments:integer; - Ref,Func:PBESENValue; - OldIsStrict,DirectCall:boolean; -begin - OldIsStrict:=TBESEN(Instance).IsStrict; - try - Ref:=@RegisterValues[Operands^[1]]; - Func:=@RegisterValues[Operands^[2]]; - CountArguments:=Operands^[3]; - for Counter:=0 to CountArguments-1 do begin - ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+4]]; - end; - if Func^.ValueType<>bvtOBJECT then begin - BESENThrowTypeErrorNotAFunction; - end else if not (assigned(Func^.Obj) and TBESENObject(Func^.Obj).HasCall) then begin - BESENThrowTypeErrorNotCallable; - end; - if Ref^.ValueType=bvtREFERENCE then begin - BESENRefBaseValueToCallThisArgValueProcs[Ref^.ReferenceBase.ValueType](CallThisArg,Ref^.ReferenceBase); - end else begin - CallThisArg.ValueType:=bvtUNDEFINED; - end; - if Trace(bttCALL) then begin - if Func^.Obj=TBESEN(Instance).ObjectGlobalEval then begin - DirectCall:=((Ref^.ValueType=bvtREFERENCE) and (Ref^.ReferenceBase.ValueType=brbvtENVREC)) and TBESENEnvironmentRecord(Ref^.ReferenceBase.EnvRec).HasBindingEx('eval',Descriptor); - TBESEN(Instance).GlobalEval(Context,CallThisArg,@ParamArgs[0],CountArguments,DirectCall,RegisterValues[Operands^[0]]); - end else begin - TBESEN(Instance).ObjectCall(TBESENObject(Func^.Obj),CallThisArg,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); - end; - Trace(bttRETURN); - end; - finally - TBESEN(Instance).IsStrict:=OldIsStrict; - end; -end; - -procedure TBESENCodeContext.OpLTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - AbstractRelationalNumber(@RegisterValues[Operands^[1]],@Code.Literals[Operands^[2]],r^.Bool); -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<Code.Literals[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpGTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@Code.Literals[Operands^[2]]; - b:=@RegisterValues[Operands^[1]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setnbe al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - AbstractRelationalNumber(@Code.Literals[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>Code.Literals[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpLENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@Code.Literals[Operands^[2]]; - b:=@RegisterValues[Operands^[1]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - not al - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setbe al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - if AbstractRelationalNumber(@Code.Literals[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin - r^.Bool:=not r^.Bool; - end; -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<=Code.Literals[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpGENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef cpu386} -{$ifdef UseSafeOperations} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - push edi - mov edi,dword ptr a - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - shl al,4 - mov edi,dword ptr b - mov ecx,dword ptr [edi+TBESENValue.Num+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [edi+TBESENValue.Num] - setnz dl - and edx,$7f - shr ecx,16 - or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] - and eax,$ff - lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] - mov edi,dword ptr a - fld qword ptr [edi+TBESENValue.Num] - mov edi,dword ptr b - fcomp qword ptr [edi+TBESENValue.Num] - fstsw ax - sahf - setb al - neg al - sbb eax,eax - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] - or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] - not al - and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] - cmp al,$01 - cmc - sbb eax,eax - mov edi,dword ptr r - mov dword ptr [edi+TBESENValue.Bool],eax - pop edi - end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; -{$else} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setnb al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$endif} -{$else} -{$ifdef UseSafeOperations} - if AbstractRelationalNumber(@RegisterValues[Operands^[1]],@Code.Literals[Operands^[2]],r^.Bool) then begin - r^.Bool:=not r^.Bool; - end; -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>=Code.Literals[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef UseSafeOperations} - r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],Code.Literals[Operands^[2]]); -{$else} -{$ifdef cpu386} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$else} - r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=Code.Literals[Operands^[2]].Num); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpNEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -var r{$ifdef cpu386},a,b{$endif}:PBESENValue; -begin - r:=@RegisterValues[Operands^[0]]; - r^.ValueType:=bvtBOOLEAN; -{$ifdef UseSafeOperations} - r^.Bool:=not BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],Code.Literals[Operands^[2]]); -{$else} -{$ifdef cpu386} - a:=@RegisterValues[Operands^[1]]; - b:=@Code.Literals[Operands^[2]]; - asm - mov edx,dword ptr a - fld qword ptr [edx+TBESENValue.Num] - mov edx,dword ptr b - fcomp qword ptr [edx+TBESENValue.Num] - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - not eax - mov edx,dword ptr r - mov dword ptr [edx+TBESENValue.Bool],eax - end {$ifdef fpc}['eax','ecx','edx']{$endif}; -{$else} - r^.Bool:=not ((not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=Code.Literals[Operands^[2]].Num)); -{$endif} -{$endif} -end; - -procedure TBESENCodeContext.OpJZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - if (not BESENIsNaN(RegisterValues[Operands^[1]].Num)) and (RegisterValues[Operands^[1]].Num=0) then begin - PC:=Operands^[0]; - end; -end; - -procedure TBESENCodeContext.OpJNZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} -begin - if not ((not BESENIsNaN(RegisterValues[Operands^[1]].Num)) and (RegisterValues[Operands^[1]].Num=0)) then begin - PC:=Operands^[0]; - end; -end; - -{$ifndef PurePascal} -{$define PurePascalExecuteByteCode} - -{$ifdef cpu386} -{$undef PurePascalExecuteByteCode} -function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; assembler; {$ifdef UseRegister}register;{$endif} -asm - push ebx - push esi - push edi - mov esi,self - mov dword ptr [esi+TBESENCodeContext.BlockRunning],$ffffffff - mov edi,dword ptr [esi+TBESENCodeContext.Code] - mov edi,dword ptr [edi+TBESENCode.ByteCode] - jmp @LoopStart - @LoopBegin: - mov ebx,dword ptr [esi+TBESENCodeContext.PC] - lea edx,dword ptr [edi+ebx*4+4] - mov ebx,dword ptr [edi+ebx*4] - mov ecx,ebx - and ecx,$ff - shr ebx,8 - inc ebx - add dword ptr [esi+TBESENCodeContext.PC],ebx - mov eax,esi - call dword ptr [ecx*4+offset BESENCodeContextOpcodes] - @LoopStart: - cmp dword ptr [esi+TBESENCodeContext.BlockRunning],0 - jnz @LoopBegin - mov eax,dword ptr [esi+TBESENCodeContext.BlockRunning] - pop edi - pop esi - pop ebx -end; -{$endif} - -{$ifdef cpuamd64} -{$ifdef windows} -{$undef PurePascalExecuteByteCode} -function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} -begin - BlockRunning:=true; - asm - mov rsi,self - mov rdi,qword ptr [rsi+TBESENCodeContext.Code] - mov rdi,qword ptr [rdi+TBESENCode.ByteCode] - jmp @LoopStart - @LoopBegin: - xor rbx,rbx - mov ebx,dword ptr [rsi+TBESENCodeContext.PC] - lea rdx,qword ptr [rdi+rbx*4+4] - mov ebx,dword ptr [rdi+rbx*4] - mov rax,rbx - and eax,$ff - shr ebx,8 - inc ebx - add dword ptr [rsi+TBESENCodeContext.PC],ebx - mov rcx,rsi - mov rbx,offset BESENCodeContextOpcodes - call qword ptr [rbx+rax*8] - @LoopStart: - cmp dword ptr [rsi+TBESENCodeContext.BlockRunning],0 - jnz @LoopBegin - end ['rax','rbx','rcx','rdx','rsi','rdi']; - result:=BlockRunning; -end; -{$else} -{$undef PurePascalExecuteByteCode} -function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} -begin - BlockRunning:=true; - asm - mov r12,self - mov r13,qword ptr [r12+TBESENCodeContext.Code] - mov r13,qword ptr [r13+TBESENCode.ByteCode] - jmp @LoopStart - @LoopBegin: - xor rbx,rbx - mov ebx,dword ptr [r12+TBESENCodeContext.PC] - lea rsi,qword ptr [r13+rbx*4+4] - mov ebx,dword ptr [r13+rbx*4] - mov rax,rbx - and eax,$ff - shr ebx,8 - inc ebx - add dword ptr [r12+TBESENCodeContext.PC],ebx - mov rdi,r12 - mov rbx,offset BESENCodeContextOpcodes - call qword ptr [rbx+rax*8] - @LoopStart: - cmp dword ptr [r12+TBESENCodeContext.BlockRunning],0 - jnz @LoopBegin - end ['rax','rbx','rcx','rdx','rsi','rdi','r8','r9','r10','r11','r12','r13']; - result:=BlockRunning; -end; -{$endif} -{$endif} -{$endif} - -{$ifdef PurePascalExecuteByteCode} -function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; -var Handler:TBESENCodeContextOpcode; - Instruction:longword; - ByteCode:PBESENUINT32Array; - Operands:PBESENINT32Array; -begin - BlockRunning:=true; - ByteCode:=@Code.ByteCode[0]; - while BlockRunning do begin - Instruction:=ByteCode^[PC]; - Operands:=@ByteCode^[PC+1]; - inc(PC,1+(Instruction shr 8)); - TMethod(Handler).Code:=BESENCodeContextOpcodes[Instruction and $ff]; - TMethod(Handler).Data:=self; - Handler(Operands); - end; - result:=BlockRunning; -end; -{$endif} - -function TBESENCodeContext.ExecuteCode:TBESENBoolean; -begin - if PC<TBESENUINT32(Code.ByteCodeLen) then begin -{$ifdef HasJIT} - if assigned(Code.NativeCode) then begin - result:=BESENExecuteNativeCode(self); - end else begin - result:=ExecuteByteCode; - end; -{$else} - result:=ExecuteByteCode; -{$endif} - if assigned(TBESEN(Instance).PeriodicHook) then begin - if not TBESEN(Instance).PeriodicHook(TBESEN(Instance)) then begin - Running:=false; - BlockRunning:=false; - result:=false; - end; - end; - end else begin - result:=false; - end; -end; - -procedure TBESENCodeContext.ExecuteTryBlockLevel; -var Reraise:boolean; - ExceptionValue:TBESENValue; - function ProcessException:boolean; - begin - result:=true; - while BlockLevel>0 do begin - case Blocks[BlockLevel-1].BlockType of - bccbtENUM:begin - dec(BlockLevel); - Block:=@Blocks[BlockLevel]; - PropertyEnumerator:=Block^.OldPropertyEnumerator; - EnumBlock:=Block^.OldEnumBlock; - BESENFreeAndNil(Block.PropertyEnumerator); - end; - bccbtWITH:begin - dec(BlockLevel); - Block:=@Blocks[BlockLevel]; - Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; - end; - bccbtCATCH:begin - Block:=@Blocks[BlockLevel-1]; - Block^.Value:=ExceptionValue; - PC:=Block^.Handler; - result:=false; - break; - end; - bccbtCATCH2:begin - dec(BlockLevel); - Block:=@Blocks[BlockLevel]; - Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; - Block^.Ident:=''; - end; - bccbtFINALLY:begin - Block:=@Blocks[BlockLevel-1]; - Block^.BlockType:=bccbtFINALLY2; - Block^.Resume:=$ffffffff; - Block^.Raised:=true; - PC:=Block^.Handler; - ExecuteTryBlockLevel; - end; - bccbtFINALLY2:begin - dec(BlockLevel); - end; - end; - end; - end; -begin - ExceptionValue:=BESENEmptyValue; - Reraise:=false; - while Running do begin - try - if not ExecuteCode then begin - break; - end; - except - on e:EBESENThrowException do begin - ExceptionValue:=E.Value; - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENEvalError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectEvalErrorConstructor,e.OriginalMessage); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENRangeError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectRangeErrorConstructor,e.OriginalMessage); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENReferenceError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectReferenceErrorConstructor,e.OriginalMessage); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENSyntaxError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectSyntaxErrorConstructor,e.OriginalMessage); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENTypeError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectTypeErrorConstructor,e.OriginalMessage); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENURIError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectURIErrorConstructor,e.OriginalMessage); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:EBESENError do begin - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,e.OriginalMessage,E.Name); - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - on e:Exception do begin -{$ifdef Delphi2009AndUp} - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,e.Message); -{$else} - ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,BESENUTF8ToUTF16(BESENConvertToUTF8(e.Message))); -{$endif} - Reraise:=ProcessException; - if Reraise then begin - raise; - end else begin - E.Message:=''; - end; - end; - else begin - ExceptionValue:=BESENEmptyValue; - Reraise:=ProcessException; - if Reraise then begin - raise; - end; - end; - end; - end; -end; - -procedure TBESENCodeContext.Execute(const AContext:TBESENContext;var AResult:TBESENValue); -var i:integer; - IsDeclarativeEnvironmentRecord:boolean; - EnvironmentRecord:TBESENEnvironmentRecord; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:TFPUExceptionMask; - OldFPURoundingMode:TFPURoundingMode; - OldFPUPrecisionMode:TFPUPrecisionMode; -{$endif} -begin - Context:=AContext; - ResultValue.ValueType:=bvtUNDEFINED; - PropertyEnumerator:=nil; - EnumBlock:=nil; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:=GetExceptionMask; - OldFPURoundingMode:=GetRoundMode; - OldFPUPrecisionMode:=GetPrecisionMode; -{$endif} - try -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(BESENFPUExceptionMask); - end; - if OldFPURoundingMode<>rmNearest then begin - SetRoundMode(rmNearest); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(BESENFPUPrecisionMode); - end; -{$endif} - for i:=0 to length(RegisterValues)-1 do begin - RegisterValues[i].ValueType:=bvtUNDEFINED; - end; - if Code.Body.EnableLocalsOptimization then begin - EnvironmentRecord:=Context.VariableEnvironment.EnvironmentRecord; - IsDeclarativeEnvironmentRecord:=EnvironmentRecord is TBESENDeclarativeEnvironmentRecord; - if (IsDeclarativeEnvironmentRecord and not TBESENDeclarativeEnvironmentRecord(EnvironmentRecord).IndexInitialized) or not IsDeclarativeEnvironmentRecord then begin - if IsDeclarativeEnvironmentRecord then begin - TBESENDeclarativeEnvironmentRecord(EnvironmentRecord).IndexInitialized:=true; - end; - for i:=0 to length(Code.Variables)-1 do begin - if not EnvironmentRecord.SetBindingValueIndex(Code.Variables[i].Name,i) then begin - BESENThrowInternalError('Internal error: 201003160136-0000'); - end; - end; - end; - end; - Running:=true; - Str:=''; - PC:=0; - BlockLevel:=0; - Block:=@Blocks[0]; -{$ifdef HasJIT} - if not assigned(Code.NativeCode) then begin - if not BESENGenerateNativeCode(self) then begin - if assigned(Code.NativeCode) then begin - TBESEN(Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); - Code.NativeCode:=nil; - Code.NativeCodeSize:=0; - end; - end; - end; -{$endif} - LookupNames:=Code.LookupNames.FList; - ExecuteTryBlockLevel; - finally -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(OldFPUExceptionMask); - end; - if OldFPURoundingMode<>rmNearest then begin - SetRoundMode(OldFPURoundingMode); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(OldFPUPrecisionMode); - end; -{$endif} - Context:=nil; - end; - BesenCopyValue(AResult,ResultValue); -end; - -procedure InitOpcodes; -var i:integer; -begin - fillchar(BESENCodeContextOpcodes,sizeof(TBESENCodeContextOpcodePointers),#0); - for i:=0 to 255 do begin - BESENCodeContextOpcodes[i]:=@TBESENCodeContext.OpNOP; - end; - BESENCodeContextOpcodes[bopSTOP]:=@TBESENCodeContext.OpSTOP; - BESENCodeContextOpcodes[bopNEW]:=@TBESENCodeContext.OpNEW; - BESENCodeContextOpcodes[bopCALL]:=@TBESENCodeContext.OpCALL; - BESENCodeContextOpcodes[bopEND]:=@TBESENCodeContext.OpEND; - BESENCodeContextOpcodes[bopVREF]:=@TBESENCodeContext.OpVREF; - BESENCodeContextOpcodes[bopLREF]:=@TBESENCodeContext.OpLREF; - BESENCodeContextOpcodes[bopNOP]:=@TBESENCodeContext.OpNOP; - BESENCodeContextOpcodes[bopCOPY]:=@TBESENCodeContext.OpCOPY; - BESENCodeContextOpcodes[bopNEQ]:=@TBESENCodeContext.OpNEQ; - BESENCodeContextOpcodes[bopNSEQ]:=@TBESENCodeContext.OpNSEQ; - BESENCodeContextOpcodes[bopAREF]:=@TBESENCodeContext.OpAREF; - BESENCodeContextOpcodes[bopTHROW]:=@TBESENCodeContext.OpTHROW; - BESENCodeContextOpcodes[bopSETC]:=@TBESENCodeContext.OpSETC; - BESENCodeContextOpcodes[bopGETC]:=@TBESENCodeContext.OpGETC; - BESENCodeContextOpcodes[bopTHIS]:=@TBESENCodeContext.OpTHIS; - BESENCodeContextOpcodes[bopOBJECT]:=@TBESENCodeContext.OpOBJECT; - BESENCodeContextOpcodes[bopARRAY]:=@TBESENCodeContext.OpARRAY; - BESENCodeContextOpcodes[bopREGEXP]:=@TBESENCodeContext.OpREGEXP; - BESENCodeContextOpcodes[bopREF]:=@TBESENCodeContext.OpREF; - BESENCodeContextOpcodes[bopGETVALUE]:=@TBESENCodeContext.OpGETVALUE; - BESENCodeContextOpcodes[bopLOOKUP]:=@TBESENCodeContext.OpLOOKUP; - BESENCodeContextOpcodes[bopPUTVALUE]:=@TBESENCodeContext.OpPUTVALUE; - BESENCodeContextOpcodes[bopDELETE]:=@TBESENCodeContext.OpDELETE; - BESENCodeContextOpcodes[bopTYPEOF]:=@TBESENCodeContext.OpTYPEOF; - BESENCodeContextOpcodes[bopTOOBJECT]:=@TBESENCodeContext.OpTOOBJECT; - BESENCodeContextOpcodes[bopTONUMBER]:=@TBESENCodeContext.OpTONUMBER; - BESENCodeContextOpcodes[bopTOBOOLEAN]:=@TBESENCodeContext.OpTOBOOLEAN; - BESENCodeContextOpcodes[bopTOSTRING]:=@TBESENCodeContext.OpTOSTRING; - BESENCodeContextOpcodes[bopTOPRIMITIVE]:=@TBESENCodeContext.OpTOPRIMITIVE; - BESENCodeContextOpcodes[bopNEG]:=@TBESENCodeContext.OpNEG; - BESENCodeContextOpcodes[bopINV]:=@TBESENCodeContext.OpINV; - BESENCodeContextOpcodes[bopNOT]:=@TBESENCodeContext.OpNOT; - BESENCodeContextOpcodes[bopMUL]:=@TBESENCodeContext.OpMUL; - BESENCodeContextOpcodes[bopDIV]:=@TBESENCodeContext.OpDIV; - BESENCodeContextOpcodes[bopMOD]:=@TBESENCodeContext.OpMOD; - BESENCodeContextOpcodes[bopADD]:=@TBESENCodeContext.OpADD; - BESENCodeContextOpcodes[bopADDNUM]:=@TBESENCodeContext.OpADDNUM; - BESENCodeContextOpcodes[bopSUB]:=@TBESENCodeContext.OpSUB; - BESENCodeContextOpcodes[bopSHL]:=@TBESENCodeContext.OpSHL; - BESENCodeContextOpcodes[bopSHR]:=@TBESENCodeContext.OpSHR; - BESENCodeContextOpcodes[bopUSHR]:=@TBESENCodeContext.OpUSHR; - BESENCodeContextOpcodes[bopLT]:=@TBESENCodeContext.OpLT; - BESENCodeContextOpcodes[bopGT]:=@TBESENCodeContext.OpGT; - BESENCodeContextOpcodes[bopLE]:=@TBESENCodeContext.OpLE; - BESENCodeContextOpcodes[bopGE]:=@TBESENCodeContext.OpGE; - BESENCodeContextOpcodes[bopINSTANCEOF]:=@TBESENCodeContext.OpINSTANCEOF; - BESENCodeContextOpcodes[bopIN]:=@TBESENCodeContext.OpIN; - BESENCodeContextOpcodes[bopEQ]:=@TBESENCodeContext.OpEQ; - BESENCodeContextOpcodes[bopSEQ]:=@TBESENCodeContext.OpSEQ; - BESENCodeContextOpcodes[bopBAND]:=@TBESENCodeContext.OpBAND; - BESENCodeContextOpcodes[bopBXOR]:=@TBESENCodeContext.OpBXOR; - BESENCodeContextOpcodes[bopBOR]:=@TBESENCodeContext.OpBOR; - BESENCodeContextOpcodes[bopSENUM]:=@TBESENCodeContext.OpSENUM; - BESENCodeContextOpcodes[bopSWITH]:=@TBESENCodeContext.OpSWITH; - BESENCodeContextOpcodes[bopSCATCH]:=@TBESENCodeContext.OpSCATCH; - BESENCodeContextOpcodes[bopENDF]:=@TBESENCodeContext.OpENDF; - BESENCodeContextOpcodes[bopJMP]:=@TBESENCodeContext.OpJMP; - BESENCodeContextOpcodes[bopJZ]:=@TBESENCodeContext.OpJZ; - BESENCodeContextOpcodes[bopJNZ]:=@TBESENCodeContext.OpJNZ; - BESENCodeContextOpcodes[bopJNULL]:=@TBESENCodeContext.OpJNULL; - BESENCodeContextOpcodes[bopLOOPENUM]:=@TBESENCodeContext.OpLOOPENUM; - BESENCodeContextOpcodes[bopSTRYC]:=@TBESENCodeContext.OpSTRYC; - BESENCodeContextOpcodes[bopSTRYF]:=@TBESENCodeContext.OpSTRYF; - BESENCodeContextOpcodes[bopLITERAL]:=@TBESENCodeContext.OpLITERAL; - BESENCodeContextOpcodes[bopLITERALUNDEF]:=@TBESENCodeContext.OpLITERALUNDEF; - BESENCodeContextOpcodes[bopLITERALNULL]:=@TBESENCodeContext.OpLITERALNULL; - BESENCodeContextOpcodes[bopLITERALBOOL]:=@TBESENCodeContext.OpLITERALBOOL; - BESENCodeContextOpcodes[bopLITERALNUM]:=@TBESENCodeContext.OpLITERALNUM; - BESENCodeContextOpcodes[bopLITERALSTR]:=@TBESENCodeContext.OpLITERALSTR; - BESENCodeContextOpcodes[bopLITERALOBJ]:=@TBESENCodeContext.OpLITERALOBJ; - BESENCodeContextOpcodes[bopFUNC]:=@TBESENCodeContext.OpFUNC; - BESENCodeContextOpcodes[bopLINE]:=@TBESENCodeContext.OpLINE; - BESENCodeContextOpcodes[bopGC]:=@TBESENCodeContext.OpGC; - BESENCodeContextOpcodes[bopSTRICT]:=@TBESENCodeContext.OpSTRICT; - BESENCodeContextOpcodes[bopSTRICTCHECKREF]:=@TBESENCodeContext.OpSTRICTCHECKREF; - BESENCodeContextOpcodes[bopDEBUGGER]:=@TBESENCodeContext.OpDEBUGGER; - BESENCodeContextOpcodes[bopCHECKOBJECTCOERCIBLE]:=@TBESENCodeContext.OpCHECKOBJECTCOERCIBLE; - BESENCodeContextOpcodes[bopPUTOBJVALUE]:=@TBESENCodeContext.OpPUTOBJVALUE; - BESENCodeContextOpcodes[bopPUTOBJGET]:=@TBESENCodeContext.OpPUTOBJGET; - BESENCodeContextOpcodes[bopPUTOBJSET]:=@TBESENCodeContext.OpPUTOBJSET; - BESENCodeContextOpcodes[bopINC]:=@TBESENCodeContext.OpINC; - BESENCodeContextOpcodes[bopDEC]:=@TBESENCodeContext.OpDEC; - BESENCodeContextOpcodes[bopCOPYBOOL]:=@TBESENCodeContext.OpCOPYBOOL; - BESENCodeContextOpcodes[bopCOPYNUM]:=@TBESENCodeContext.OpCOPYNUM; - BESENCodeContextOpcodes[bopCOPYSTR]:=@TBESENCodeContext.OpCOPYSTR; - BESENCodeContextOpcodes[bopCOPYOBJ]:=@TBESENCodeContext.OpCOPYOBJ; - BESENCodeContextOpcodes[bopCOPYREF]:=@TBESENCodeContext.OpCOPYREF; - BESENCodeContextOpcodes[bopCOPYLOCAL]:=@TBESENCodeContext.OpCOPYLOCAL; - BESENCodeContextOpcodes[bopGETVALUEREF]:=@TBESENCodeContext.OpGETVALUEREF; - BESENCodeContextOpcodes[bopPUTVALUEREF]:=@TBESENCodeContext.OpPUTVALUEREF; - BESENCodeContextOpcodes[bopGETVALUELOCAL]:=@TBESENCodeContext.OpGETVALUELOCAL; - BESENCodeContextOpcodes[bopPUTVALUELOCAL]:=@TBESENCodeContext.OpPUTVALUELOCAL; - BESENCodeContextOpcodes[bopGETVALUELOCALFAST]:=@TBESENCodeContext.OpGETVALUELOCALFAST; - BESENCodeContextOpcodes[bopPUTVALUELOCALFAST]:=@TBESENCodeContext.OpPUTVALUELOCALFAST; - BESENCodeContextOpcodes[bopGETVALUELOCALBOOL]:=@TBESENCodeContext.OpGETVALUELOCALBOOL; - BESENCodeContextOpcodes[bopPUTVALUELOCALBOOL]:=@TBESENCodeContext.OpPUTVALUELOCALBOOL; - BESENCodeContextOpcodes[bopGETVALUELOCALNUM]:=@TBESENCodeContext.OpGETVALUELOCALNUM; - BESENCodeContextOpcodes[bopPUTVALUELOCALNUM]:=@TBESENCodeContext.OpPUTVALUELOCALNUM; - BESENCodeContextOpcodes[bopGETVALUELOCALSTR]:=@TBESENCodeContext.OpGETVALUELOCALSTR; - BESENCodeContextOpcodes[bopPUTVALUELOCALSTR]:=@TBESENCodeContext.OpPUTVALUELOCALSTR; - BESENCodeContextOpcodes[bopGETVALUELOCALOBJ]:=@TBESENCodeContext.OpGETVALUELOCALOBJ; - BESENCodeContextOpcodes[bopPUTVALUELOCALOBJ]:=@TBESENCodeContext.OpPUTVALUELOCALOBJ; - BESENCodeContextOpcodes[bopGETVALUELOCALINDEX]:=@TBESENCodeContext.OpGETVALUELOCALINDEX; - BESENCodeContextOpcodes[bopPUTVALUELOCALINDEX]:=@TBESENCodeContext.OpPUTVALUELOCALINDEX; - BESENCodeContextOpcodes[bopGETVALUELOCALINDEXBOOL]:=@TBESENCodeContext.OpGETVALUELOCALINDEXBOOL; - BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXBOOL]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXBOOL; - BESENCodeContextOpcodes[bopGETVALUELOCALINDEXNUM]:=@TBESENCodeContext.OpGETVALUELOCALINDEXNUM; - BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXNUM]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXNUM; - BESENCodeContextOpcodes[bopGETVALUELOCALINDEXSTR]:=@TBESENCodeContext.OpGETVALUELOCALINDEXSTR; - BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXSTR]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXSTR; - BESENCodeContextOpcodes[bopGETVALUELOCALINDEXOBJ]:=@TBESENCodeContext.OpGETVALUELOCALINDEXOBJ; - BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXOBJ]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXOBJ; - BESENCodeContextOpcodes[bopLOOPINITCOUNT]:=@TBESENCodeContext.OpLOOPINITCOUNT; - BESENCodeContextOpcodes[bopLOOPADDCOUNT]:=@TBESENCodeContext.OpLOOPADDCOUNT; - BESENCodeContextOpcodes[bopTRACE]:=@TBESENCodeContext.OpTRACE; - BESENCodeContextOpcodes[bopLTBOOL]:=@TBESENCodeContext.OpLTBOOL; - BESENCodeContextOpcodes[bopGTBOOL]:=@TBESENCodeContext.OpGTBOOL; - BESENCodeContextOpcodes[bopLEBOOL]:=@TBESENCodeContext.OpLEBOOL; - BESENCodeContextOpcodes[bopGEBOOL]:=@TBESENCodeContext.OpGEBOOL; - BESENCodeContextOpcodes[bopEQBOOL]:=@TBESENCodeContext.OpEQBOOL; - BESENCodeContextOpcodes[bopNEQBOOL]:=@TBESENCodeContext.OpNEQBOOL; - BESENCodeContextOpcodes[bopLTNUM]:=@TBESENCodeContext.OpLTNUM; - BESENCodeContextOpcodes[bopGTNUM]:=@TBESENCodeContext.OpGTNUM; - BESENCodeContextOpcodes[bopLENUM]:=@TBESENCodeContext.OpLENUM; - BESENCodeContextOpcodes[bopGENUM]:=@TBESENCodeContext.OpGENUM; - BESENCodeContextOpcodes[bopEQNUM]:=@TBESENCodeContext.OpEQNUM; - BESENCodeContextOpcodes[bopNEQNUM]:=@TBESENCodeContext.OpNEQNUM; - BESENCodeContextOpcodes[bopLTSTR]:=@TBESENCodeContext.OpLTSTR; - BESENCodeContextOpcodes[bopGTSTR]:=@TBESENCodeContext.OpGTSTR; - BESENCodeContextOpcodes[bopLESTR]:=@TBESENCodeContext.OpLESTR; - BESENCodeContextOpcodes[bopGESTR]:=@TBESENCodeContext.OpGESTR; - BESENCodeContextOpcodes[bopEQSTR]:=@TBESENCodeContext.OpEQSTR; - BESENCodeContextOpcodes[bopNEQSTR]:=@TBESENCodeContext.OpNEQSTR; - BESENCodeContextOpcodes[bopSHLBOOL]:=@TBESENCodeContext.OpSHLBOOL; - BESENCodeContextOpcodes[bopSHRBOOL]:=@TBESENCodeContext.OpSHRBOOL; - BESENCodeContextOpcodes[bopBANDBOOL]:=@TBESENCodeContext.OpBANDBOOL; - BESENCodeContextOpcodes[bopBXORBOOL]:=@TBESENCodeContext.OpBXORBOOL; - BESENCodeContextOpcodes[bopBORBOOL]:=@TBESENCodeContext.OpBORBOOL; - BESENCodeContextOpcodes[bopSHLNUM]:=@TBESENCodeContext.OpSHLNUM; - BESENCodeContextOpcodes[bopSHRNUM]:=@TBESENCodeContext.OpSHRNUM; - BESENCodeContextOpcodes[bopUSHRNUM]:=@TBESENCodeContext.OpUSHRNUM; - BESENCodeContextOpcodes[bopBANDNUM]:=@TBESENCodeContext.OpBANDNUM; - BESENCodeContextOpcodes[bopBXORNUM]:=@TBESENCodeContext.OpBXORNUM; - BESENCodeContextOpcodes[bopBORNUM]:=@TBESENCodeContext.OpBORNUM; - BESENCodeContextOpcodes[bopSETCUNDEF]:=@TBESENCodeContext.OpSETCUNDEF; - BESENCodeContextOpcodes[bopSETCNULL]:=@TBESENCodeContext.OpSETCNULL; - BESENCodeContextOpcodes[bopSETCBOOL]:=@TBESENCodeContext.OpSETCBOOL; - BESENCodeContextOpcodes[bopSETCNUM]:=@TBESENCodeContext.OpSETCNUM; - BESENCodeContextOpcodes[bopSETCSTR]:=@TBESENCodeContext.OpSETCSTR; - BESENCodeContextOpcodes[bopSETCOBJ]:=@TBESENCodeContext.OpSETCOBJ; - BESENCodeContextOpcodes[bopTRACENEW]:=@TBESENCodeContext.OpTRACENEW; - BESENCodeContextOpcodes[bopTRACECALL]:=@TBESENCodeContext.OpTRACECALL; - BESENCodeContextOpcodes[bopLTNUMCONST]:=@TBESENCodeContext.OpLTNUMCONST; - BESENCodeContextOpcodes[bopGTNUMCONST]:=@TBESENCodeContext.OpGTNUMCONST; - BESENCodeContextOpcodes[bopLENUMCONST]:=@TBESENCodeContext.OpLENUMCONST; - BESENCodeContextOpcodes[bopGENUMCONST]:=@TBESENCodeContext.OpGENUMCONST; - BESENCodeContextOpcodes[bopEQNUMCONST]:=@TBESENCodeContext.OpEQNUMCONST; - BESENCodeContextOpcodes[bopNEQNUMCONST]:=@TBESENCodeContext.OpNEQNUMCONST; - BESENCodeContextOpcodes[bopJZERO]:=@TBESENCodeContext.OpJZERO; - BESENCodeContextOpcodes[bopJNZERO]:=@TBESENCodeContext.OpJNZERO; -end; - -procedure InitBESEN; -begin - InitOpcodes; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENCodeGeneratorContext.pas b/3rd/besen/src/BESENCodeGeneratorContext.pas deleted file mode 100644 index 7b0cc5ed2..000000000 --- a/3rd/besen/src/BESENCodeGeneratorContext.pas +++ /dev/null @@ -1,531 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCodeGeneratorContext; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENHashMap; - -type TBESENCodeGeneratorContextVariableScope=record - Ident:TBESENString; - ID:integer; - InScope:longbool; - ValueType:TBESENValueType; - Initialized:longbool; - MutableOrDeletable:longbool; - RegNr:integer; - end; - - TBESENCodeGeneratorContextVariableScopes=array of TBESENCodeGeneratorContextVariableScope; - - TBESENCodeGeneratorContextPatchables=class(TBESENBaseObject) - public - Continues:TBESENIntegers; - Breaks:TBESENIntegers; - CountContinues:integer; - CountBreaks:integer; - Previous:TBESENCodeGeneratorContextPatchables; - Continuable:longbool; - BlockDepth:integer; - Target:integer; - ContinueValueTypesItems:TBESENValueTypesItems; - BreakValueTypesItems:TBESENValueTypesItems; - CountContinueValueTypesItems:integer; - CountBreakValueTypesItems:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure AddContinue(Address:integer;const ValueTypes:TBESENValueTypes); - procedure AddBreak(Address:integer;const ValueTypes:TBESENValueTypes); - end; - - TBESENCodeGeneratorContextRegister=record - IsWhat:longword; - IsLocal:longbool; - LocalIndex:longint; - ReferenceValueType:TBESENValueType; - InUse:longbool; - Variable:longint; - end; - - TBESENCodeGeneratorContextRegisters=array of TBESENCodeGeneratorContextRegister; - - TBESENCodeGeneratorContextRegisterStates=record - Registers:TBESENCodeGeneratorContextRegisters; - MaxRegisters:integer; - end; - - TBESENCodeGeneratorContext=class(TBESENBaseObject) - public - Next:TBESENCodeGeneratorContext; - Code:TObject; - BlockDepth:integer; - MaxBlockDepth:integer; - LoopDepth:integer; - MaxLoopDepth:integer; - MaxParamArgs:integer; - Patchables:TBESENCodeGeneratorContextPatchables; - VariableScopes:TBESENCodeGeneratorContextVariableScopes; - CountVariableScopes:integer; - InVariableScope:longbool; - VariableScopeHashMap:TBESENHashMap; - VariableNameHashMap:TBESENHashMap; - Registers:TBESENCodeGeneratorContextRegisters; - MaxRegisters:integer; - LookupHashMap:TBESENHashMap; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure PushPatchables(Target:integer;Continuable:boolean); - procedure PopPatchables(ContinueAddr,BreakAddr:integer); - function FindPatchables(Target:integer;Continuable:boolean):TBESENCodeGeneratorContextPatchables; - procedure BlockEnter; - procedure BlockLeave; - function BlockCurrent:integer; - function AllocateRegister:integer; - procedure DeallocateRegister(var RegNr:integer); - procedure GetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); - procedure SetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); - function VariableIndex(const Ident:TBESENString):integer; - function VariableGetInitialized(const Ident:TBESENString):TBESENBoolean; - function VariableGetMutableOrDeletable(const Ident:TBESENString):TBESENBoolean; - procedure VariableSetFlags(const Ident:TBESENString;const Initialized,MutableOrDeletable:boolean); - function VariableGetRegister(const Ident:TBESENString):integer; - procedure VariableSetRegister(const Ident:TBESENString;const RegNr:integer); - function VariableGetType(const Ident:TBESENString):TBESENValueType; - procedure VariableSetType(const Ident:TBESENString;const ValueType:TBESENValueType); - procedure VariableAllSetType(const ValueType:TBESENValueType); - function VariableGetTypes:TBESENValueTypes; - procedure VariableSetTypes(const ValueTypes:TBESENValueTypes); - function VariableGetIdent(const Index:integer):TBESENString; - function VariableID(const Ident:TBESENString):integer; - function IsVariableInScope(const Ident:TBESENString):boolean; - procedure VariableSetScope(const Ident:TBESENString;IsInScope,IsParameter:boolean;ParameterIndex:integer); - function VariableSetAllScope(IsInScope:boolean):boolean; - end; - -implementation - -uses BESEN,BESENUtils,BESENCode; - -constructor TBESENCodeGeneratorContextPatchables.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Continues:=nil; - Breaks:=nil; - CountContinues:=0; - CountBreaks:=0; - Previous:=nil; - Continuable:=false; - BlockDepth:=0; - Target:=0; - ContinueValueTypesItems:=nil; - BreakValueTypesItems:=nil; - CountContinueValueTypesItems:=0; - CountBreakValueTypesItems:=0; -end; - -destructor TBESENCodeGeneratorContextPatchables.Destroy; -begin - SetLength(Continues,0); - SetLength(Breaks,0); - SetLength(ContinueValueTypesItems,0); - SetLength(BreakValueTypesItems,0); - inherited Destroy; -end; - -procedure TBESENCodeGeneratorContextPatchables.AddContinue(Address:integer;const ValueTypes:TBESENValueTypes); -begin - if CountContinues>=length(Continues) then begin - SetLength(Continues,CountContinues+256); - end; - Continues[CountContinues]:=Address; - inc(CountContinues); - if CountContinueValueTypesItems>=length(ContinueValueTypesItems) then begin - SetLength(ContinueValueTypesItems,CountContinueValueTypesItems+256); - end; - ContinueValueTypesItems[CountContinueValueTypesItems]:=copy(ValueTypes,0,length(ValueTypes)); - inc(CountContinueValueTypesItems); -end; - -procedure TBESENCodeGeneratorContextPatchables.AddBreak(Address:integer;const ValueTypes:TBESENValueTypes); -begin - if CountBreaks>=length(Breaks) then begin - SetLength(Breaks,CountBreaks+256); - end; - Breaks[CountBreaks]:=Address; - inc(CountBreaks); - if CountBreakValueTypesItems>=length(BreakValueTypesItems) then begin - SetLength(BreakValueTypesItems,CountBreakValueTypesItems+256); - end; - BreakValueTypesItems[CountBreakValueTypesItems]:=copy(ValueTypes,0,length(ValueTypes)); - inc(CountBreakValueTypesItems); -end; - -constructor TBESENCodeGeneratorContext.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Next:=nil; - Code:=nil; - BlockDepth:=0; - MaxBlockDepth:=0; - LoopDepth:=0; - MaxLoopDepth:=0; - MaxParamArgs:=0; - Patchables:=nil; - VariableScopes:=nil; - CountVariableScopes:=0; - InVariableScope:=true; - VariableScopeHashMap:=TBESENHashMap.Create; - VariableNameHashMap:=TBESENHashMap.Create; - Registers:=nil; - MaxRegisters:=0; - LookupHashMap:=TBESENHashMap.Create; -end; - -destructor TBESENCodeGeneratorContext.Destroy; -var NextPatchables:TBESENCodeGeneratorContextPatchables; -begin - BESENFreeAndNil(LookupHashMap); - while assigned(Patchables) do begin - NextPatchables:=Patchables.Previous; - Patchables.Free; - Patchables:=NextPatchables; - end; - SetLength(Registers,0); - SetLength(VariableScopes,0); - VariableScopeHashMap.Free; - VariableNameHashMap.Free; - inherited Destroy; -end; - -procedure TBESENCodeGeneratorContext.PushPatchables(Target:integer;Continuable:boolean); -var p:TBESENCodeGeneratorContextPatchables; -begin - p:=TBESENCodeGeneratorContextPatchables.Create(Instance); - p.Target:=Target; - p.Continuable:=Continuable; - p.Previous:=Patchables; - p.BlockDepth:=BlockDepth; - Patchables:=p; -end; - -procedure TBESENCodeGeneratorContext.PopPatchables(ContinueAddr,BreakAddr:integer); -var i:integer; - p:TBESENCodeGeneratorContextPatchables; -begin - p:=Patchables; - if ContinueAddr>=0 then begin - for i:=0 to p.CountContinues-1 do begin - TBESENCode(Code).Patch(p.Continues[i],ContinueAddr); - end; - end; - if BreakAddr>=0 then begin - for i:=0 to p.CountBreaks-1 do begin - TBESENCode(Code).Patch(p.Breaks[i],BreakAddr); - end; - end; - Patchables:=p.Previous; - BESENFreeAndNil(p); -end; - -function TBESENCodeGeneratorContext.FindPatchables(Target:integer;Continuable:boolean):TBESENCodeGeneratorContextPatchables; -var p:TBESENCodeGeneratorContextPatchables; -begin - result:=nil; - if (Target=bcttNOTARGET) and Continuable then begin - p:=Patchables; - while assigned(p) do begin - if p.Continuable then begin - result:=p; - break; - end; - p:=p.Previous; - end; - end else if Target=bcttNOTARGET then begin - result:=Patchables; - end else begin - p:=Patchables; - while assigned(p) do begin - if p.Target=Target then begin - result:=p; - break; - end; - p:=p.Previous; - end; - end; -{$ifdef UseAssert} - Assert(assigned(result),'Lost patchable'); -{$endif} -end; - -procedure TBESENCodeGeneratorContext.BlockEnter; -begin - inc(BlockDepth); - if MaxBlockDepth<BlockDepth then begin - MaxBlockDepth:=BlockDepth; - end; -end; - -procedure TBESENCodeGeneratorContext.BlockLeave; -begin - dec(BlockDepth); -end; - -function TBESENCodeGeneratorContext.BlockCurrent:integer; -begin - result:=BlockDepth; -end; - -function TBESENCodeGeneratorContext.AllocateRegister:integer; -var i:integer; -begin - result:=-1; - for i:=0 to MaxRegisters-1 do begin - if not Registers[i].InUse then begin - result:=i; - break; - end; - end; - if result<0 then begin - result:=MaxRegisters; - inc(MaxRegisters); - if result>=length(Registers) then begin - SetLength(Registers,result+256); - end; - end; - Registers[result].InUse:=true; - Registers[result].IsWhat:=0; - Registers[result].IsLocal:=false; - Registers[result].LocalIndex:=-1; - Registers[result].Variable:=-1; -end; - -procedure TBESENCodeGeneratorContext.DeallocateRegister(var RegNr:integer); -begin - if ((RegNr>=0) and (RegNr<MaxRegisters)) and not (Registers[RegNr].Variable>=0) then begin - Registers[RegNr].InUse:=false; - Registers[RegNr].IsWhat:=0; - Registers[RegNr].IsLocal:=false; - Registers[RegNr].LocalIndex:=-1; - end; - RegNr:=-1; -end; - -procedure TBESENCodeGeneratorContext.GetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); -begin - RegisterStates.Registers:=copy(Registers,0,length(Registers)); - RegisterStates.MaxRegisters:=MaxRegisters; -end; - -procedure TBESENCodeGeneratorContext.SetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); -begin - Registers:=copy(RegisterStates.Registers,0,length(RegisterStates.Registers)); - MaxRegisters:=RegisterStates.MaxRegisters; -end; - -function TBESENCodeGeneratorContext.VariableIndex(const Ident:TBESENString):integer; -var Item:PBESENHashMapItem; -begin - Item:=VariableScopeHashMap.GetKey(Ident); - if assigned(Item) then begin - result:=Item^.Value; - end else begin - result:=-1; - end; -end; - -function TBESENCodeGeneratorContext.VariableGetInitialized(const Ident:TBESENString):TBESENBoolean; -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - result:=VariableScopes[i].Initialized; - end else begin - result:=false; - end; -end; - -function TBESENCodeGeneratorContext.VariableGetMutableOrDeletable(const Ident:TBESENString):TBESENBoolean; -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - result:=VariableScopes[i].MutableOrDeletable; - end else begin - result:=false; - end; -end; - -procedure TBESENCodeGeneratorContext.VariableSetFlags(const Ident:TBESENString;const Initialized,MutableOrDeletable:boolean); -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - VariableScopes[i].Initialized:=Initialized; - VariableScopes[i].MutableOrDeletable:=MutableOrDeletable; - end; -end; - -function TBESENCodeGeneratorContext.VariableGetRegister(const Ident:TBESENString):integer; -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - result:=VariableScopes[i].RegNr; - end else begin - result:=-1; - end; -end; - -procedure TBESENCodeGeneratorContext.VariableSetRegister(const Ident:TBESENString;const RegNr:integer); -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - VariableScopes[i].RegNr:=RegNr; - end; -end; - -function TBESENCodeGeneratorContext.VariableGetType(const Ident:TBESENString):TBESENValueType; -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - result:=VariableScopes[i].ValueType; - end else begin - result:=bvtUNDEFINED; - end; -end; - -procedure TBESENCodeGeneratorContext.VariableSetType(const Ident:TBESENString;const ValueType:TBESENValueType); -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - VariableScopes[i].ValueType:=ValueType; - end; -end; - -procedure TBESENCodeGeneratorContext.VariableAllSetType(const ValueType:TBESENValueType); -var i:integer; -begin - for i:=0 to CountVariableScopes-1 do begin - VariableScopes[i].ValueType:=ValueType; - end; -end; - -function TBESENCodeGeneratorContext.VariableGetTypes:TBESENValueTypes; -var i:integer; -begin - SetLength(result,CountVariableScopes); - for i:=0 to CountVariableScopes-1 do begin - result[i]:=VariableScopes[i].ValueType; - end; -end; - -procedure TBESENCodeGeneratorContext.VariableSetTypes(const ValueTypes:TBESENValueTypes); -var i,j:integer; -begin - j:=CountVariableScopes; - if j>length(ValueTypes) then begin - j:=length(ValueTypes); - end; - for i:=0 to j-1 do begin - VariableScopes[i].ValueType:=ValueTypes[i]; - end; -end; - -function TBESENCodeGeneratorContext.VariableGetIdent(const Index:integer):TBESENString; -begin - if (Index>=0) and (Index<CountVariableScopes) then begin - result:=VariableScopes[Index].Ident; - end else begin - result:=''; - end; -end; - -function TBESENCodeGeneratorContext.VariableID(const Ident:TBESENString):integer; -var i:integer; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - result:=VariableScopes[i].ID; - end else begin - result:=-1; - end; -end; - -function TBESENCodeGeneratorContext.IsVariableInScope(const Ident:TBESENString):boolean; -var i:integer; -begin - result:=false; - if InVariableScope then begin - i:=VariableIndex(Ident); - if i>=0 then begin - result:=VariableScopes[i].InScope; - end; - end; -end; - -procedure TBESENCodeGeneratorContext.VariableSetScope(const Ident:TBESENString;IsInScope,IsParameter:boolean;ParameterIndex:integer); -var i:integer; - Item:PBESENHashMapItem; -begin - i:=VariableIndex(Ident); - if i>=0 then begin - VariableScopes[i].InScope:=IsInScope; - end else begin - if IsInScope then begin - if CountVariableScopes>=length(VariableScopes) then begin - SetLength(VariableScopes,CountVariableScopes+256); - end; - VariableScopes[CountVariableScopes].Ident:=Ident; - VariableScopes[CountVariableScopes].ID:=TBESENCode(Code).GenVariable(Ident,IsParameter,ParameterIndex,self); - VariableScopes[CountVariableScopes].InScope:=IsInScope; - VariableScopes[CountVariableScopes].Initialized:=false; - VariableScopes[CountVariableScopes].MutableOrDeletable:=false; - VariableScopes[CountVariableScopes].ValueType:=bvtUNDEFINED; - VariableScopes[CountVariableScopes].RegNr:=-1; - Item:=VariableScopeHashMap.NewKey(Ident,true); - Item^.Value:=CountVariableScopes; - inc(CountVariableScopes); - end; - end; -end; - -function TBESENCodeGeneratorContext.VariableSetAllScope(IsInScope:boolean):boolean; -begin - result:=InVariableScope; - InVariableScope:=IsInScope; -end; - -end. diff --git a/3rd/besen/src/BESENCodeJIT.pas b/3rd/besen/src/BESENCodeJIT.pas deleted file mode 100644 index cf1acf911..000000000 --- a/3rd/besen/src/BESENCodeJIT.pas +++ /dev/null @@ -1,89 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCodeJIT; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}BESENConstants,BESENTypes; - -function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; -function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} - -implementation - -{ - -Base JIT design concept: - - 1. It is mostly a damn simple method-based native-code-template-concatenation JIT mostly without any - fancy optimizations just as CSE, SSA, and so on. - - 2. The native code execution can be continued from any correspondent byte code instruction, so it - is possible to jump to any byte-code-instruction-mapped native-code-sub-block from any each - other in the same code context and in the same code instande. - - 3. The from the JIT generated native code can call the correspondent byte code instruction dispatcher - function from the byte code interpreter at every time, if it needed, for example, for complex byte - code instructions which are more trouble than it's worth to compile these to native code. - - 4. The virtual byte code interpreter VM registers are used instead the native platform target CPU - registers, for to keep the fallback-to-byte-code-instruction-dispatcher-function-stuff simple just - much as possible. - - 5. The from the JIT generated native code can be self-modifying, for example at the monomorphic and - polymorphic inline caching based byte code instructions, by modifying some index constant values - at some native code instruction opcode arguments. But this is optional, since the byte code itself - is also self-modifying in this monomorphic and polymorphic inline caching context. It's mostly a - trade-off, which way performs better on which target platform CPU architecture. - - 6. A byte-code-instruction-offset <-> native-code-instruction-offset map must be generated and used - for the jump-in-to-random-code-position-usage and for the effective use of the fallback-to-byte- - code-instruction-dispatcher-function-stuff. - -} - -uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, - BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, - BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager; - -function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; -begin - result:=false; -end; - -function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} -begin - result:=false; -end; - -end. diff --git a/3rd/besen/src/BESENCodeJITx64.pas b/3rd/besen/src/BESENCodeJITx64.pas deleted file mode 100644 index fb4d067c2..000000000 --- a/3rd/besen/src/BESENCodeJITx64.pas +++ /dev/null @@ -1,2229 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCodeJITx64; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}BESENConstants,BESENTypes; - -{$ifdef HasJIT} -{$ifdef cpuamd64} -function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; -function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} -{$endif} -{$endif} - -implementation - -{ - -Register layout: - - rbx = Offset to instance - r12 = Offset to code context - r13 = Offset to byte code <-> native code offset mapping map array - r14 = Offset to virtual VM registers - r15 = Offset to local hash table (only at function code, not at global code!) - others = for various temporary usage - -} - -{$ifdef HasJIT} -{$ifdef cpuamd64} -uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, - BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, - BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager; - -function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; -type TFixupKind=(fkPTR,fkRET,fkOFS); - TFixup=record - Kind:TFixupKind; - Ofs:integer; - Dest:pointer; - ToOfs:integer; - end; - TFixups=array of TFixup; -var Fixups:TFixups; - CountFixups,i:integer; - Offsets:array of longword; - Opcode:byte; - Instruction:TBESENUINT32; - CodeBuffer:TBESENBytes; - CodeBufferLen:integer; - CurrentPC,Temp,RetOfs,Literal:longword; - CodeBegin,CodeEnd:pointer; - ByteCode:PBESENUINT32Array; - Operands:PBESENINT32Array; - Code:TBESENCode; - CodeContext:TBESENCodeContext; - v:TBESENValue; - procedure Add(const s:TBESENANSISTRING); - begin - if length(s)>0 then begin - if (CodeBufferLen+length(s))>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+length(s)+4096) and not 4095); - end; - move(s[1],CodeBuffer[CodeBufferLen],length(s)); - inc(CodeBufferLen,length(s)); - end; - end; - procedure AddCode(CodeBegin,CodeEnd:pointer); - var CodeLen:ptrint; -{$ifdef windows} - OldProtect,OldProtectDummy:longword; - OK:boolean; -{$endif} - begin - CodeLen:=ptrint(ptruint(CodeEnd)-ptruint(CodeBegin)); - if CodeLen>0 then begin -{$ifdef windows} - OK:=VirtualProtect(CodeBegin,CodeLen,PAGE_EXECUTE_READWRITE,OldProtect); -{$endif} -{$ifdef unix} - fpmprotect(CodeBegin,CodeLen,PROT_READ or PROT_WRITE or PROT_EXEC); -{$endif} - if (CodeBufferLen+CodeLen)>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+CodeLen+4096) and not 4095); - end; - move(CodeBegin^,CodeBuffer[CodeBufferLen],CodeLen); - inc(CodeBufferLen,CodeLen); -{$ifdef windows} - if OK then begin - VirtualProtect(CodeBegin,CodeLen,OldProtect,OldProtectDummy); - end; -{$endif} - end; - end; - procedure AddDWord(const v:longword); - begin - if (CodeBufferLen+sizeof(longword))>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+sizeof(longword)+4096) and not 4095); - end; - move(v,CodeBuffer[CodeBufferLen],sizeof(longword)); - inc(CodeBufferLen,sizeof(longword)); - end; - procedure AddQWord(const v:qword); - begin - if (CodeBufferLen+sizeof(qword))>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+sizeof(qword)+4096) and not 4095); - end; - move(v,CodeBuffer[CodeBufferLen],sizeof(qword)); - inc(CodeBufferLen,sizeof(qword)); - end; - procedure AddPtr(const v:pointer); - begin - if (CodeBufferLen+sizeof(ptruint))>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+sizeof(ptruint)+4096) and not 4095); - end; - move(v,CodeBuffer[CodeBufferLen],sizeof(ptruint)); - inc(CodeBufferLen,sizeof(ptruint)); - end; - procedure AddDispatcher; - var Temp:qword; - CodeBegin,CodeEnd:pointer; - begin - case Opcode of - bopEND,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopTRACE,bopJZERO,bopJNZERO:begin - Add(#$41#$c7#$84#$24); // mov dword ptr [r12+TBESENCodeContext.PC],CurrentPC - asm - push rax - mov rax,offset TBESENCodeContext.PC - mov qword ptr Temp,rax - pop rax - end; - AddDWord(Temp); - AddDWord(CurrentPC); - end; - end; - -{$ifdef windows} - Add(#$4c#$89#$e1); // mov rcx,r12 -{$else} - Add(#$4c#$89#$e7); // mov rdi,r12 -{$endif} - -{$ifdef windows} - Add(#$48#$ba); // mov rdx,Operands -{$else} - Add(#$48#$be); // mov rsi,Operands -{$endif} - AddPtr(Operands); - - // mov rax,OpcodeDispatcher - Add(#$48#$b8); - AddPtr(BESENCodeContextOpcodes[Opcode]); - - // call rax - Add(#$ff#$d0); - - case Opcode of - bopEND,bopTRACE,bopENDF:begin - if (Opcode<>bopEND) or (Operands^[0]=0) then begin - asm - jmp @Skip - @CodeBegin: - cmp dword ptr [r12+TBESENCodeContext.BlockRunning],0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$0f#$84); // jz RET - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkRET; - Fixups[CountFixups].Ofs:=CodeBufferLen; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - end; - - case Opcode of - bopEND,bopENDF,bopJMP,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopJZERO,bopJNZERO:begin - asm - jmp @Skip - @CodeBegin: - xor rax,rax - mov eax,dword ptr [r12+TBESENCodeContext.PC] - jmp qword ptr [r13+rax*8] - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - end; - - end; -begin - result:=false; - try - CodeContext:=TBESENCodeContext(ACodeContext); - Code:=TBESENCode(CodeContext.Code); - if assigned(Code.NativeCode) then begin - TBESEN(CodeContext.Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); - Code.NativeCode:=nil; - Code.NativeCodeSize:=0; - end; - CodeBuffer:=nil; - CodeBufferLen:=0; - CurrentPC:=0; - Fixups:=nil; - CountFixups:=0; - Offsets:=nil; - ByteCode:=@Code.ByteCode[0]; - SetLength(Offsets,Code.ByteCodeLen); - while CurrentPC<TBESENUINT32(Code.ByteCodeLen) do begin - Offsets[CurrentPC]:=CodeBufferLen; - Instruction:=ByteCode^[CurrentPC]; - Operands:=@ByteCode^[CurrentPC+1]; - inc(CurrentPC,1+(Instruction shr 8)); - Opcode:=Instruction and $ff; - - case Opcode of - bopSTOP:begin - asm - jmp @Skip - @CodeBegin: - mov dword ptr [r12+TBESENCodeContext.BlockRunning],0 - mov dword ptr [r12+TBESENCodeContext.Running],0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$e9); // jmp to code end - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkRET; - Fixups[CountFixups].Ofs:=CodeBufferLen; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - bopNEW:begin - AddDispatcher; - end; - bopCALL:begin - AddDispatcher; - end; - bopEND:begin - if (Code.MaxBlock=0) and (Operands^[0]=0) then begin - asm - jmp @Skip - @CodeBegin: - mov dword ptr [r12+TBESENCodeContext.BlockRunning],0 - mov dword ptr [r12+TBESENCodeContext.Running],0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$e9); // jmp to code end - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkRET; - Fixups[CountFixups].Ofs:=CodeBufferLen; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end else begin - AddDispatcher; - end; - end; - bopVREF:begin - AddDispatcher; - end; - bopLREF:begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtLOCAL - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtLOCAL); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex],LocalIndex - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); - AddDWord(Operands^[1]); - end; - bopNOP:begin - end; - bopCOPY:begin - AddDispatcher; - end; - bopNEQ:begin - AddDispatcher; - end; - bopNSEQ:begin - AddDispatcher; - end; - bopAREF:begin - AddDispatcher; - end; - bopTHROW:begin - AddDispatcher; - end; - bopSETC:begin - AddDispatcher; - end; - bopGETC:begin - AddDispatcher; - end; - bopTHIS:begin - AddDispatcher; - end; - bopOBJECT:begin - asm - jmp @Skip - @CodeBegin: - mov rax,qword ptr [rbx+TBESEN.ObjectConstructor] - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - end; - bopARRAY:begin - asm - jmp @Skip - @CodeBegin: - mov rax,qword ptr [rbx+TBESEN.ObjectArrayConstructor] - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - end; - bopREGEXP:begin - asm - jmp @Skip - @CodeBegin: - mov rax,qword ptr [rbx+TBESEN.ObjectRegExpConstructor] - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - end; - bopREF:begin - AddDispatcher; - end; - bopGETVALUE:begin - AddDispatcher; - end; - bopLOOKUP:begin - AddDispatcher; - end; - bopPUTVALUE:begin - AddDispatcher; - end; - bopDELETE:begin - AddDispatcher; - end; - bopTYPEOF:begin - AddDispatcher; - end; - bopTOOBJECT:begin - AddDispatcher; - end; - bopTONUMBER:begin - AddDispatcher; - end; - bopTOBOOLEAN:begin - AddDispatcher; - end; - bopTOSTRING:begin - AddDispatcher; - end; - bopTOPRIMITIVE:begin - AddDispatcher; - end; - bopNEG:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$41#$81#$b6); // xor dword ptr [r14+RegisterOfs+TBESENValue.Num+4],$80000000 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+((ptruint(pointer(@v.Num))+4)-ptruint(pointer(@v)))); - AddDWord($80000000); - end; - bopINV:begin - AddDispatcher; - end; - bopNOT:begin - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp eax,$01 - sbb eax,eax - neg eax - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - end; - bopMUL:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$59#$86); // mulsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopDIV:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$5e#$86); // divsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopMOD:begin - AddDispatcher; - end; - bopADD:begin - AddDispatcher; - end; - bopADDNUM:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$58#$86); // addsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopSUB:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$5c#$86); // subsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopSHL:begin - AddDispatcher; - end; - bopSHR:begin - AddDispatcher; - end; - bopUSHR:begin - AddDispatcher; - end; - bopLT:begin - AddDispatcher; - end; - bopGT:begin - AddDispatcher; - end; - bopLE:begin - AddDispatcher; - end; - bopGE:begin - AddDispatcher; - end; - bopINSTANCEOF:begin - AddDispatcher; - end; - bopIN:begin - AddDispatcher; - end; - bopEQ:begin - AddDispatcher; - end; - bopSEQ:begin - AddDispatcher; - end; - bopBAND:begin - AddDispatcher; - end; - bopBXOR:begin - AddDispatcher; - end; - bopBOR:begin - AddDispatcher; - end; - bopSENUM:begin - AddDispatcher; - end; - bopSWITH:begin - AddDispatcher; - end; - bopSCATCH:begin - AddDispatcher; - end; - bopENDF:begin - AddDispatcher; - end; - bopJMP:begin - if longword(Operands^[0])<>CurrentPC then begin - Add(#$e9); // jmp Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - bopJZ:begin - if longword(Operands^[0])<>CurrentPC then begin - Add(#$41#$83#$be); // cmp dword ptr [r14+RegisterOfs+TBESENValue.Bool],0 - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - Add(#$00); - - Add(#$0f#$85); // jnz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - bopJNZ:begin - if longword(Operands^[0])<>CurrentPC then begin - Add(#$41#$83#$be); // cmp dword ptr [r14+RegisterOfs+TBESENValue.Bool],0 - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - Add(#$00); - - Add(#$0f#$84); // jnz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - bopJNULL:begin - AddDispatcher; - end; - bopLOOPENUM:begin - AddDispatcher; - end; - bopSTRYC:begin - AddDispatcher; - end; - bopSTRYF:begin - AddDispatcher; - end; - bopLITERALUNDEF:begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtUNDEFINED - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtUNDEFINED); - end; - bopLITERALNULL:begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNULL - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNULL); - end; - bopLITERALBOOL:begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],Bool - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - if Operands^[1]<>0 then begin - AddDWord(longword(pointer(@BESENLongBooleanValues[true])^)); - end else begin - AddDWord(longword(pointer(@BESENLongBooleanValues[false])^)); - end; - end; - bopLITERALNUM:begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[1]].Num); - - Add(#$f2#$0f#$10#$00); // movsd xmm0,qword ptr [rax] - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopLITERALSTR:begin - AddDispatcher; - end; - bopLITERALOBJ:begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$48#$b8); // mov rax,Obj - AddPtr(Code.Literals[Operands^[1]].Obj); - - Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - end; - bopFUNC:begin - AddDispatcher; - end; - bopLINE:begin - Add(#$b8); // mov eax,Arg - AddDWord(Code.Locations[Operands^[0]].LineNumber); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rbx+TBESEN.LineNumber],eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGC:begin - AddDispatcher; - end; - bopSTRICT:begin - Add(#$b8); // mov eax,Arg - AddDWord(longword(BESENLongBooleanValues[Operands^[0]<>0])); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rbx+TBESEN.IsStrict],eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSTRICTCHECKREF:begin - if not Code.Body.IsStrict then begin - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.ReferenceIsStrict] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v)))); - - Add(#$85#$c0); // test eax,rax - - Add(#$0f#$84); // jz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=CurrentPC; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - - AddDispatcher; - end; - bopDEBUGGER:begin - if TBESEN(CodeContext.Instance).CodeTracable then begin - AddDispatcher; - end; - end; - bopCHECKOBJECTCOERCIBLE:begin - AddDispatcher; - end; - bopPUTOBJVALUE:begin - AddDispatcher; - end; - bopPUTOBJGET:begin - AddDispatcher; - end; - bopPUTOBJSET:begin - AddDispatcher; - end; - bopINC:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$48#$b8); // mov rax,offset BESENDoubleOne - AddPtr(@BESENDoubleOne); - - Add(#$f2#$0f#$10#$00); // movsd xmm0,qword ptr [rax] - - Add(#$f2#$41#$0f#$58#$86); // addsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopDEC:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset BESENDoubleOne - AddPtr(@BESENDoubleOne); - - Add(#$f2#$0f#$5c#$00); // subsd xmm0,qword ptr [rax] - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopCOPYBOOL:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - end; - end; - bopCOPYNUM:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - end; - bopCOPYOBJ:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$49#$8b#$86); // mov rax,dword ptr [r14+RegisterOfs+TBESENValue.Obj] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - - Add(#$49#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Obj],rax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - end; - end; - bopCOPYREF:begin - if Operands^[0]<>Operands^[1] then begin - AddDispatcher; - end; - end; - bopCOPYLOCAL:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtLOCAL - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtLOCAL); - - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); - end; - end; - bopGETVALUEREF:begin - AddDispatcher; - end; - bopPUTVALUEREF:begin - AddDispatcher; - end; - bopGETVALUELOCAL:begin - AddDispatcher; - end; - bopPUTVALUELOCAL:begin - AddDispatcher; - end; - bopGETVALUELOCALFAST:begin - AddDispatcher; - end; - bopPUTVALUELOCALFAST:begin - AddDispatcher; - end; - bopGETVALUELOCALBOOL:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - xor rcx,rcx - mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] - mov rdx,qword ptr [r15+rcx*8] - mov dword ptr [rax+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [rdx+TBESENValue.Bool] - mov dword ptr [rax+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALBOOL:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - xor rcx,rcx - mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] - mov rdx,qword ptr [r15+rcx*8] - mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [rax+TBESENValue.Bool] - mov dword ptr [rdx+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALNUM:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - xor rcx,rcx - mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] - mov rdx,qword ptr [r15+rcx*8] - mov dword ptr [rax+TBESENValue.ValueType],bvtNUMBER - movsd xmm0,qword ptr [rdx+TBESENValue.Num] - movsd qword ptr [rax+TBESENValue.Num],xmm0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALNUM:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - xor rcx,rcx - mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] - mov rdx,qword ptr [r15+rcx*8] - mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER - movsd xmm0,qword ptr [rax+TBESENValue.Num] - movsd qword ptr [rdx+TBESENValue.Num],xmm0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALSTR:begin - AddDispatcher; - end; - bopPUTVALUELOCALSTR:begin - AddDispatcher; - end; - bopGETVALUELOCALOBJ:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - xor rcx,rcx - mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] - mov rdx,qword ptr [r15+rcx*8] - mov dword ptr [rax+TBESENValue.ValueType],bvtOBJECT - mov rcx,qword ptr [rdx+TBESENValue.Obj] - mov qword ptr [rax+TBESENValue.Obj],rcx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALOBJ:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - xor rcx,rcx - mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] - mov rdx,qword ptr [r15+rcx*8] - mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT - mov rcx,qword ptr [rax+TBESENValue.Obj] - mov qword ptr [rdx+TBESENValue.Obj],rcx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEX:begin - AddDispatcher; - end; - bopPUTVALUELOCALINDEX:begin - AddDispatcher; - end; - bopGETVALUELOCALINDEXBOOL:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] - AddDWord(ptruint(Operands^[1]*8)); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rax+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [rdx+TBESENValue.Bool] - mov dword ptr [rax+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEXBOOL:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] - AddDWord(ptruint(Operands^[0]*8)); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [rax+TBESENValue.Bool] - mov dword ptr [rdx+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEXNUM:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] - AddDWord(ptruint(Operands^[1]*8)); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rax+TBESENValue.ValueType],bvtNUMBER - movsd xmm0,qword ptr [rdx+TBESENValue.Num] - movsd qword ptr [rax+TBESENValue.Num],xmm0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEXNUM:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] - AddDWord(ptruint(Operands^[0]*8)); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER - movsd xmm0,qword ptr [rax+TBESENValue.Num] - movsd qword ptr [rdx+TBESENValue.Num],xmm0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEXSTR:begin - AddDispatcher; - end; - bopPUTVALUELOCALINDEXSTR:begin - AddDispatcher; - end; - bopGETVALUELOCALINDEXOBJ:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] - AddDWord(ptruint(Operands^[1]*8)); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rax+TBESENValue.ValueType],bvtOBJECT - mov rcx,qword ptr [rdx+TBESENValue.Obj] - mov qword ptr [rax+TBESENValue.Obj],rcx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEXOBJ:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] - AddDWord(ptruint(Operands^[0]*8)); - - asm - jmp @Skip - @CodeBegin: - mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT - mov rcx,qword ptr [rax+TBESENValue.Obj] - mov qword ptr [rdx+TBESENValue.Obj],rcx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopLOOPINITCOUNT:begin - end; - bopLOOPADDCOUNT:begin - end; - bopTRACE:begin - if TBESEN(CodeContext.Instance).CodeTracable then begin - AddDispatcher; - end; - end; - bopLTBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setb al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGTBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setnbe al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLEBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setbe al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGEBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setnb al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopEQBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp eax,edx - setz al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopNEQBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp eax,edx - setnz al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLTNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGTNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - setnbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLENUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - setbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGENUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - setnb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopEQNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopNEQNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - not eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLTSTR:begin - AddDispatcher; - end; - bopGTSTR:begin - AddDispatcher; - end; - bopLESTR:begin - AddDispatcher; - end; - bopGESTR:begin - AddDispatcher; - end; - bopEQSTR:begin - AddDispatcher; - end; - bopNEQSTR:begin - AddDispatcher; - end; - bopSHLBOOL:begin - AddDispatcher; - end; - bopSHRBOOL:begin - AddDispatcher; - end; - bopBANDBOOL:begin - AddDispatcher; - end; - bopBXORBOOL:begin - AddDispatcher; - end; - bopBORBOOL:begin - AddDispatcher; - end; - bopSHLNUM:begin - AddDispatcher; - end; - bopSHRNUM:begin - AddDispatcher; - end; - bopUSHRNUM:begin - AddDispatcher; - end; - bopBANDNUM:begin - AddDispatcher; - end; - bopBXORNUM:begin - AddDispatcher; - end; - bopBORNUM:begin - AddDispatcher; - end; - bopSETCUNDEF:begin - asm - jmp @Skip - @CodeBegin: - lea rax,qword ptr [r12+TBESENCodeContext.ResultValue] - mov dword ptr [rax+TBESENValue.ValueType],bvtUNDEFINED - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCNULL:begin - asm - jmp @Skip - @CodeBegin: - lea rax,qword ptr [r12+TBESENCodeContext.ResultValue] - mov dword ptr [rax+TBESENValue.ValueType],bvtNULL - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCBOOL:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] - mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [rax+TBESENValue.Bool] - mov dword ptr [rdx+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCNUM:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] - mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER - movsd xmm0,qword ptr [rax+TBESENValue.Num] - movsd qword ptr [rdx+TBESENValue.Num],xmm0 - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCSTR:begin - AddDispatcher; - end; - bopSETCOBJ:begin - Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] - mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT - mov rcx,qword ptr [rax+TBESENValue.Obj] - mov qword ptr [rdx+TBESENValue.Obj],rcx - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - AddCode(CodeBegin,CodeEnd); - end; - bopTRACENEW:begin - AddDispatcher; - end; - bopTRACECALL:begin - AddDispatcher; - end; - bopLTNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[2]].Num); - - Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] - - asm - jmp @Skip - @CodeBegin: - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGTNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[2]].Num); - - Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] - - asm - jmp @Skip - @CodeBegin: - setnbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLENUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[2]].Num); - - Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] - - asm - jmp @Skip - @CodeBegin: - setbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGENUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[2]].Num); - - Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] - - asm - jmp @Skip - @CodeBegin: - setnb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopEQNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[2]].Num); - - Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] - - asm - jmp @Skip - @CodeBegin: - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopNEQNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$48#$b8); // mov rax,offset Num - AddPtr(@Code.Literals[Operands^[2]].Num); - - Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] - - asm - jmp @Skip - @CodeBegin: - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - not eax - @CodeEnd: - @Skip: - push rax - mov rax,offset @CodeBegin - mov qword ptr CodeBegin,rax - mov rax,offset @CodeEnd - mov qword ptr CodeEnd,rax - pop rax - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - else begin - AddDispatcher; - end; - end; - - end; - RetOfs:=CodeBufferLen; - Add(#$c3); // ret - SetLength(CodeBuffer,CodeBufferLen); - Code.NativeCodeSize:=CodeBufferLen; - Code.NativeCode:=TBESEN(CodeContext.Instance).NativeCodeMemoryManager.GetMemory(Code.NativeCodeSize); - move(CodeBuffer[0],Code.NativeCode^,Code.NativeCodeSize); - SetLength(Code.NativeCodePCOffsets,Code.ByteCodeLen); - for i:=0 to Code.ByteCodeLen-1 do begin - Code.NativeCodePCOffsets[i]:=pointer(@PBESENByteArray(Code.NativeCode)[Offsets[i]]); - end; - for i:=0 to CountFixups-1 do begin - case FixUps[i].Kind of - fkPTR:begin - longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(FixUps[i].Dest)-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); - end; - fkRET:begin - longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[RetOfs]))-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); - end; - fkOFS:begin - longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(Code.NativeCodePCOffsets[FixUps[i].ToOfs])-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); - end; - end; - end; - result:=true; - finally - SetLength(Fixups,0); - SetLength(Offsets,0); - SetLength(CodeBuffer,0); - end; -end; - -function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} -var CodeContext:TBESENCodeContext; -begin - CodeContext:=TBESENCodeContext(ACodeContext); - CodeContext.BlockRunning:=true; - asm - push rax - push rbx - mov r12,qword ptr CodeContext - mov rbx,qword ptr [r12+TBESENCodeContext.Instance] - mov r13,qword ptr [r12+TBESENCodeContext.Code] - mov rax,qword ptr [r13+TBESENCode.Body] - mov r13,qword ptr [r13+TBESENCode.NativeCodePCOffsets] - mov r14,qword ptr [r12+TBESENCodeContext.RegisterValues] - xor r15,r15 - mov eax,dword ptr [rax+TBESENASTNodeFunctionBody.IsFunction] - test eax,eax - jz @IsNoFunction - mov r15,qword ptr [r12+TBESENCodeContext.Context] - mov r15,qword ptr [r15+TBESENContext.VariableEnvironment] - mov r15,qword ptr [r15+TBESENLexicalEnvironment.EnvironmentRecord] - mov r15,qword ptr [r15+TBESENDeclarativeEnvironmentRecord.HashValues] - @IsNoFunction: - xor rax,rax - mov eax,dword ptr [r12+TBESENCodeContext.PC] - call qword ptr [r13+rax*8] - pop rbx - pop rax - end ['rax','rbx','r12','r13','r14','r15']; - result:=CodeContext.BlockRunning; -end; -{$endif} -{$endif} - -end. diff --git a/3rd/besen/src/BESENCodeJITx86.pas b/3rd/besen/src/BESENCodeJITx86.pas deleted file mode 100644 index 1328ea679..000000000 --- a/3rd/besen/src/BESENCodeJITx86.pas +++ /dev/null @@ -1,2552 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCodeJITx86; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}BESENConstants,BESENTypes; - -{$ifdef HasJIT} -{$ifdef cpu386} -function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; -function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} -{$endif} -{$endif} - -implementation - -{ - -Register layout: - - esi = Offset to code context - edi = Offset to virtual VM registers - ebp = Offset to byte code <-> native code offset mapping map array - others = for various temporary usage - -} - -{$ifdef HasJIT} -{$ifdef cpu386} -uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, - BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, - BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager, - BESENObject,BESENObjectEnvironmentRecord; - -function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; -const sizeofTBESENValue=sizeof(TBESENValue); -type TFixupKind=(fkPTR,fkRET,fkOFS); - TFixup=record - Kind:TFixupKind; - Ofs:integer; - Dest:pointer; - ToOfs:integer; - end; - TFixups=array of TFixup; -var Fixups:TFixups; - CountFixups,i:integer; - Offsets:array of longword; - Opcode:byte; - Instruction:TBESENUINT32; - CodeBuffer:TBESENBytes; - CodeBufferLen,OldCodeBufferLen:integer; - CurrentPC,Temp,RetOfs,Literal:longword; - CodeBegin,CodeEnd:pointer; - CodeVars:array[0..8] of pointer; - ByteCode:PBESENUINT32Array; - Operands:PBESENINT32Array; - Code:TBESENCode; - CodeContext:TBESENCodeContext; - v:TBESENValue; - procedure Add(const s:TBESENANSISTRING); - begin - if length(s)>0 then begin - if (CodeBufferLen+length(s))>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+length(s)+4096) and not 4095); - end; - move(s[1],CodeBuffer[CodeBufferLen],length(s)); - inc(CodeBufferLen,length(s)); - end; - end; - procedure AddCode(CodeBegin,CodeEnd:pointer); - var CodeLen:ptrint; -{$ifdef windows} - OldProtect,OldProtectDummy:longword; - OK:boolean; -{$endif} - begin - CodeLen:=ptrint(ptruint(CodeEnd)-ptruint(CodeBegin)); - if CodeLen>0 then begin -{$ifdef windows} - OK:=VirtualProtect(CodeBegin,CodeLen,PAGE_EXECUTE_READWRITE,OldProtect); -{$endif} -{$ifdef unix} - fpmprotect(CodeBegin,CodeLen,PROT_READ or PROT_WRITE or PROT_EXEC); -{$endif} - if (CodeBufferLen+CodeLen)>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+CodeLen+4096) and not 4095); - end; - move(CodeBegin^,CodeBuffer[CodeBufferLen],CodeLen); - inc(CodeBufferLen,CodeLen); -{$ifdef windows} - if OK then begin - VirtualProtect(CodeBegin,CodeLen,OldProtect,OldProtectDummy); - end; -{$endif} - end; - end; - procedure AddDWord(const v:longword); - begin - if (CodeBufferLen+sizeof(longword))>=length(CodeBuffer) then begin - SetLength(CodeBuffer,(CodeBufferLen+sizeof(longword)+4096) and not 4095); - end; - move(v,CodeBuffer[CodeBufferLen],sizeof(longword)); - inc(CodeBufferLen,sizeof(longword)); - end; - procedure AddDispatcherPointer; - begin - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkPTR; - Fixups[CountFixups].Ofs:=CodeBufferLen-4; - Fixups[CountFixups].Dest:=BESENCodeContextOpcodes[Opcode]; - inc(CountFixups); - end; - procedure AddDispatcher; - var Temp:longword; - CodeBegin,CodeEnd:pointer; - begin - Add(#$89#$f0); // mov eax,esi - - case Opcode of - bopEND,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopTRACE,bopJZERO,bopJNZERO:begin - Add(#$c7#$80); // mov dword ptr [eax+TBESENCodeContext.PC],CurrentPC - asm - mov dword ptr Temp,offset TBESENCodeContext.PC - end; - AddDWord(Temp); - AddDWord(CurrentPC); - end; - end; - - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - Add(#$e8); // call OpcodeDispatcher - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkPTR; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].Dest:=BESENCodeContextOpcodes[Opcode]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - - case Opcode of - bopEND,bopTRACE,bopENDF:begin - if (Opcode<>bopEND) or (Operands^[0]=0) then begin - asm - jmp @Skip - @CodeBegin: - cmp dword ptr [esi+TBESENCodeContext.BlockRunning],0 - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$0f#$84); // jz RET - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkRET; - Fixups[CountFixups].Ofs:=CodeBufferLen; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - end; - - case Opcode of - bopEND,bopENDF,bopJMP,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopJZERO,bopJNZERO:begin - asm - jmp @Skip - @CodeBegin: -// mov ebp,dword ptr [esi+TBESENCodeContext.Code] -// mov ebp,dword ptr [ebp+TBESENCode.NativeCodePCOffsets] - mov edx,dword ptr [esi+TBESENCodeContext.PC] - jmp dword ptr [ebp+edx*4] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - end; - - end; -begin - result:=false; - try - CodeContext:=TBESENCodeContext(ACodeContext); - Code:=TBESENCode(CodeContext.Code); - if assigned(Code.NativeCode) then begin - TBESEN(CodeContext.Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); - Code.NativeCode:=nil; - Code.NativeCodeSize:=0; - end; - CodeBuffer:=nil; - CodeBufferLen:=0; - CurrentPC:=0; - Fixups:=nil; - CountFixups:=0; - Offsets:=nil; - ByteCode:=@Code.ByteCode[0]; - SetLength(Offsets,Code.ByteCodeLen); - while CurrentPC<TBESENUINT32(Code.ByteCodeLen) do begin - Offsets[CurrentPC]:=CodeBufferLen; - Instruction:=ByteCode^[CurrentPC]; - Operands:=@ByteCode^[CurrentPC+1]; - inc(CurrentPC,1+(Instruction shr 8)); - Opcode:=Instruction and $ff; - - case Opcode of - bopSTOP:begin - asm - jmp @Skip - @CodeBegin: - mov dword ptr [esi+TBESENCodeContext.BlockRunning],0 - mov dword ptr [esi+TBESENCodeContext.Running],0 - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$e9); // jmp to code end - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkRET; - Fixups[CountFixups].Ofs:=CodeBufferLen; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - bopNEW:begin - AddDispatcher; - end; - bopCALL:begin - AddDispatcher; - end; - bopEND:begin - if (Code.MaxBlock=0) and (Operands^[0]=0) then begin - asm - jmp @Skip - @CodeBegin: - mov dword ptr [esi+TBESENCodeContext.BlockRunning],0 - mov dword ptr [esi+TBESENCodeContext.Running],0 - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$e9); // jmp to code end - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkRET; - Fixups[CountFixups].Ofs:=CodeBufferLen; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end else begin - AddDispatcher; - end; - end; - bopVREF:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - // Monomorphic precheck before the polymorphic/megamorphic checks in the opcode handler itself - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+4*4] - test ecx,ecx - js @DoDispatcher - mov eax,dword ptr [esi+TBESENCodeContext.Context] - mov eax,dword ptr [eax+TBESENContext.VariableEnvironment] - mov ecx,dword ptr [eax+TBESENLexicalEnvironment.EnvironmentRecord] - cmp dword ptr [ecx+TBESENObjectEnvironmentRecord.RecordType],0 - jz @DoDispatcher - mov eax,dword ptr [ecx+TBESENObjectEnvironmentRecord.BindingObject] - mov eax,dword ptr [eax+TBESENObject.StructureID] - cmp eax,dword ptr [edx+4*4] - jnz @DoDispatcher - - @CodeVars6: - mov dword ptr [edi+$1337c0de],brbvtENVREC - - @CodeVars0: - mov dword ptr [edi+$1337c0de],ecx - - @CodeVars5: - mov dword ptr [edi+$1337c0de],bvtREFERENCE - - mov eax,dword ptr [edx+5*4] - @CodeVars2: - mov dword ptr [edi+$1337c0de],eax - - mov eax,dword ptr [edx+2*4] - @CodeVars1: - mov dword ptr [edi+$1337c0de],eax - - mov eax,dword ptr [edx+6*4] - @CodeVars3: - mov dword ptr [edi+$1337c0de],eax - - mov eax,dword ptr [edx+7*4] - @CodeVars4: - mov dword ptr [edi+$1337c0de],eax - - jmp @SkipDispatcher - @DoDispatcher: - mov eax,esi - db $e8; dd $00; // call OpcodeDispatcher - @SkipDispatcher: - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 - mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 - mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 - mov dword ptr [CodeVars+3*4],offset @CodeVars3+2 - mov dword ptr [CodeVars+4*4],offset @CodeVars4+2 - mov dword ptr [CodeVars+5*4],offset @CodeVars5+2 - mov dword ptr [CodeVars+6*4],offset @CodeVars6+2 - end; - OldCodeBufferLen:=CodeBufferLen; - AddCode(CodeBegin,CodeEnd); - AddDispatcherPointer; - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.EnvRec))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceHash))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[3])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIndex))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[4])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceID))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[5])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[6])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.ValueType))-ptruint(pointer(@v))); -{$endif} - end; - bopLREF:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtLOCAL - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtLOCAL); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex],LocalIndex - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); - AddDWord(Operands^[1]); - end; - bopNOP:begin - end; - bopCOPY:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopNEQ:begin - AddDispatcher; - end; - bopNSEQ:begin - AddDispatcher; - end; - bopAREF:begin - AddDispatcher; - end; - bopTHROW:begin - AddDispatcher; - end; - bopSETC:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETC:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea edx,dword ptr [esi+TBESENCodeContext.ResultValue] - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopTHIS:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov edx,dword ptr [esi+TBESENCodeContext.Context] - lea edx,dword ptr [edx+TBESENContext.ThisBinding] - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopOBJECT:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - asm - jmp @Skip - @CodeBegin: - mov eax,dword ptr [esi+TBESENCodeContext.Instance] - mov eax,dword ptr [eax+TBESEN.ObjectConstructor] - mov dword ptr [edx],eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopARRAY:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - asm - jmp @Skip - @CodeBegin: - mov eax,dword ptr [esi+TBESENCodeContext.Instance] - mov eax,dword ptr [eax+TBESEN.ObjectArrayConstructor] - mov dword ptr [edx],eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopREGEXP:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - asm - jmp @Skip - @CodeBegin: - mov eax,dword ptr [esi+TBESENCodeContext.Instance] - mov eax,dword ptr [eax+TBESEN.ObjectRegExpConstructor] - mov dword ptr [edx],eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopREF:begin - if TBESENUINT32(Operands^[3])<>$fefefefe then begin - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - // Monomorphic precheck before the polymorphic/megamorphic checks in the opcode handler itself - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+6*4] - test ecx,ecx - js @DoDispatcher - @CodeVars0: - cmp dword ptr [edi+$1337c0de],bvtOBJECT - jnz @DoDispatcher - @CodeVars2: - mov eax,dword ptr [edi+$1337c0de] - cmp dword ptr [eax+TBESENObject.StructureID],ecx - jnz @DoDispatcher - - @CodeVars1: - mov dword ptr [edi+$1337c0de],brbvtOBJECT - - @CodeVars3: - mov dword ptr [edi+$1337c0de],eax - - @CodeVars8: - mov dword ptr [edi+$1337c0de],bvtREFERENCE - - mov eax,dword ptr [edx+7*4] - @CodeVars5: - mov dword ptr [edi+$1337c0de],eax - - mov eax,dword ptr [edx+4*4] - @CodeVars4: - mov dword ptr [edi+$1337c0de],eax - - mov eax,dword ptr [edx+8*4] - @CodeVars6: - mov dword ptr [edi+$1337c0de],eax - - mov eax,dword ptr [edx+9*4] - @CodeVars7: - mov dword ptr [edi+$1337c0de],eax - - jmp @SkipDispatcher - @DoDispatcher: - mov eax,esi - db $e8; dd $00; // call OpcodeDispatcher - @SkipDispatcher: - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 - mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 - mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 - mov dword ptr [CodeVars+3*4],offset @CodeVars3+2 - mov dword ptr [CodeVars+4*4],offset @CodeVars4+2 - mov dword ptr [CodeVars+5*4],offset @CodeVars5+2 - mov dword ptr [CodeVars+6*4],offset @CodeVars6+2 - mov dword ptr [CodeVars+7*4],offset @CodeVars7+2 - mov dword ptr [CodeVars+8*4],offset @CodeVars8+2 - end; - OldCodeBufferLen:=CodeBufferLen; - AddCode(CodeBegin,CodeEnd); - AddDispatcherPointer; - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.ValueType))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[3])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.Obj))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[4])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceHash))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[5])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[6])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIndex))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[7])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceID))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[8])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); - end else begin - AddDispatcher; - end; - end; - bopGETVALUE:begin - AddDispatcher; - end; - bopLOOKUP:begin - AddDispatcher; - end; - bopPUTVALUE:begin - AddDispatcher; - end; - bopDELETE:begin - AddDispatcher; - end; - bopTYPEOF:begin - AddDispatcher; - end; - bopTOOBJECT:begin - AddDispatcher; - end; - bopTONUMBER:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - if Operands^[0]=Operands^[1] then begin - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - asm - jmp @Skip - @CodeBegin: - jz @SkipDispatcher - mov eax,esi - db $e8; dd $00; // call OpcodeDispatcher - @SkipDispatcher: - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddDispatcherPointer; - end else begin - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - asm - jmp @Skip - @CodeBegin: - jnz @DoDispatcher - @CodeVars0: - mov dword ptr [edi+$1337c0d3],bvtNUMBER - @CodeVars1: - fld qword ptr [edi+$1337c0d3] - @CodeVars2: - fstp qword ptr [edi+$1337c0d3] - jmp @SkipDispatcher - @DoDispatcher: - mov eax,esi - db $e8; dd $00; // call OpcodeDispatcher - @SkipDispatcher: - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 - mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 - mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 - end; - OldCodeBufferLen:=CodeBufferLen; - AddCode(CodeBegin,CodeEnd); - AddDispatcherPointer; - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v))); - end; -{$endif} - end; - bopTOBOOLEAN:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - if Operands^[0]=Operands^[1] then begin - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - asm - jmp @Skip - @CodeBegin: - jz @SkipDispatcher - mov eax,esi - db $e8; dd $00; // call OpcodeDispatcher - @SkipDispatcher: - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddDispatcherPointer; - end else begin - Add(#$ba); // mov edx,Operands - AddDWord(ptruint(Operands)); - - Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - asm - jmp @Skip - @CodeBegin: - jnz @DoDispatcher - @CodeVars0: - mov dword ptr [edi+$1337c0d3],bvtBOOLEAN - @CodeVars1: - mov eax,dword ptr [edi+$1337c0d3] - @CodeVars2: - mov dword ptr [edi+$1337c0d3],eax - jmp @SkipDispatcher - @DoDispatcher: - mov eax,esi - db $e8; dd $00; // call OpcodeDispatcher - @SkipDispatcher: - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 - mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 - mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 - end; - OldCodeBufferLen:=CodeBufferLen; - AddCode(CodeBegin,CodeEnd); - AddDispatcherPointer; - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v))); - PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v))); - end; -{$endif} - end; - bopTOSTRING:begin - AddDispatcher; - end; - bopTOPRIMITIVE:begin - AddDispatcher; - end; - bopNEG:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$81#$b7); // xor dword ptr [edi+RegisterOfs+TBESENValue.Num+4],$80000000 - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+((ptruint(pointer(@v.Num))+4)-ptruint(pointer(@v)))); - AddDWord($80000000); - end; - bopINV:begin - AddDispatcher; - end; - bopNOT:begin - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp eax,$01 - sbb eax,eax - neg eax - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - end; - bopMUL:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$8f); // fmul qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopDIV:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$b7); // fdiv qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopMOD:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - @Repeat: - fprem - fstsw ax - sahf - jp @Repeat - fstp st(1) - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopADD:begin - AddDispatcher; - end; - bopADDNUM:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$87); // fadd qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopSUB:begin - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$a7); // fsub qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopSHL:begin - AddDispatcher; - end; - bopSHR:begin - AddDispatcher; - end; - bopUSHR:begin - AddDispatcher; - end; - bopLT:begin - AddDispatcher; - end; - bopGT:begin - AddDispatcher; - end; - bopLE:begin - AddDispatcher; - end; - bopGE:begin - AddDispatcher; - end; - bopINSTANCEOF:begin - AddDispatcher; - end; - bopIN:begin - AddDispatcher; - end; - bopEQ:begin - AddDispatcher; - end; - bopSEQ:begin - AddDispatcher; - end; - bopBAND:begin - AddDispatcher; - end; - bopBXOR:begin - AddDispatcher; - end; - bopBOR:begin - AddDispatcher; - end; - bopSENUM:begin - AddDispatcher; - end; - bopSWITH:begin - AddDispatcher; - end; - bopSCATCH:begin - AddDispatcher; - end; - bopENDF:begin - AddDispatcher; - end; - bopJMP:begin - if longword(Operands^[0])<>CurrentPC then begin - Add(#$e9); // jmp Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - bopJZ:begin - if longword(Operands^[0])<>CurrentPC then begin - Add(#$83#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.Bool],0 - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - Add(#$00); - - Add(#$0f#$85); // jnz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - bopJNZ:begin - if longword(Operands^[0])<>CurrentPC then begin - Add(#$83#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.Bool],0 - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - Add(#$00); - - Add(#$0f#$84); // jz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - end; - bopJNULL:begin - AddDispatcher; - end; - bopLOOPENUM:begin - AddDispatcher; - end; - bopSTRYC:begin - AddDispatcher; - end; - bopSTRYF:begin - AddDispatcher; - end; - bopLITERALUNDEF:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtUNDEFINED - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtUNDEFINED); - end; - bopLITERALNULL:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNULL - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNULL); - end; - bopLITERALBOOL:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],Bool - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - if Operands^[1]<>0 then begin - AddDWord(longword(pointer(@BESENLongBooleanValues[true])^)); - end else begin - AddDWord(longword(pointer(@BESENLongBooleanValues[false])^)); - end; - end; - bopLITERALNUM:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - - Add(#$dd#$05); // fld qword ptr [Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[1]].Num))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopLITERALSTR:begin - AddDispatcher; - end; - bopLITERALOBJ:begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Obj],Obj - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - AddDWord(ptruint(pointer(Code.Literals[Operands^[1]].Obj))); - end; - bopFUNC:begin - AddDispatcher; - end; - bopLINE:begin - Add(#$b8); // mov eax,Arg - AddDWord(Code.Locations[Operands^[0]].LineNumber); - asm - jmp @Skip - @CodeBegin: - mov edx,dword ptr [esi+TBESENCodeContext.Instance] - mov dword ptr [edx+TBESEN.LineNumber],eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGC:begin - asm - jmp @Skip - @CodeBegin: - mov eax,dword ptr [esi+TBESENCodeContext.Instance] - mov eax,dword ptr [eax+TBESEN.GarbageCollector] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - - Add(#$e8); // call TBESENGarbageCollector.TriggerCollect - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkPTR; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].Dest:=@TBESENGarbageCollector.TriggerCollect; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - bopSTRICT:begin - Add(#$b8); // mov eax,Arg - AddDWord(longword(BESENLongBooleanValues[Operands^[0]<>0])); - asm - jmp @Skip - @CodeBegin: - mov edx,dword ptr [esi+TBESENCodeContext.Instance] - mov dword ptr [edx+TBESEN.IsStrict],eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSTRICTCHECKREF:begin - if not Code.Body.IsStrict then begin - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.ReferenceIsStrict] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v)))); - - Add(#$85#$c0); // test eax,rax - - Add(#$0f#$84); // jz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=CurrentPC; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; - - AddDispatcher; - end; - bopDEBUGGER:begin - if TBESEN(CodeContext.Instance).CodeTracable then begin - AddDispatcher; - end; - end; - bopCHECKOBJECTCOERCIBLE:begin - AddDispatcher; - end; - bopPUTOBJVALUE:begin - AddDispatcher; - end; - bopPUTOBJGET:begin - AddDispatcher; - end; - bopPUTOBJSET:begin - AddDispatcher; - end; - bopINC:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$d9#$e8); // fld1 - - Add(#$dc#$87); // fadd qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopDEC:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - end; - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$25); // fsub qword ptr [BESENNumOne] - AddDWord(ptruint(pointer(@BESENNumOne))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - bopCOPYBOOL:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - end; - end; - bopCOPYNUM:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtNUMBER); - - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - end; - end; - bopCOPYOBJ:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtOBJECT); - - Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.Obj] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - - Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.Obj] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); - end; - end; - bopCOPYREF:begin - if Operands^[0]<>Operands^[1] then begin - AddDispatcher; - end; - end; - bopCOPYLOCAL:begin - if Operands^[0]<>Operands^[1] then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtLOCAL - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtLOCAL); - - Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); - - Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); - end; - end; - bopGETVALUEREF:begin - AddDispatcher; - end; - bopPUTVALUEREF:begin - AddDispatcher; - end; - bopGETVALUELOCAL:begin - AddDispatcher; - end; - bopPUTVALUELOCAL:begin - AddDispatcher; - end; - bopGETVALUELOCALFAST:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALFAST:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - xchg eax,edx - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALBOOL:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [edx+TBESENValue.Bool] - mov dword ptr [eax+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALBOOL:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov dword ptr [edx+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [eax+TBESENValue.Bool] - mov dword ptr [edx+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALNUM:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER - fld qword ptr [edx+TBESENValue.Num] - fstp qword ptr [eax+TBESENValue.Num] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALNUM:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov dword ptr [edx+TBESENValue.ValueType],bvtNUMBER - fld qword ptr [eax+TBESENValue.Num] - fstp qword ptr [edx+TBESENValue.Num] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALSTR:begin - AddDispatcher; - end; - bopPUTVALUELOCALSTR:begin - AddDispatcher; - end; - bopGETVALUELOCALOBJ:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT - mov ecx,dword ptr [edx+TBESENValue.Obj] - mov dword ptr [eax+TBESENValue.Obj],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALOBJ:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.LocalIndex] - mov edx,dword ptr [ebx+ecx*4] - mov dword ptr [edx+TBESENValue.ValueType],bvtOBJECT - mov ecx,dword ptr [eax+TBESENValue.Obj] - mov dword ptr [edx+TBESENValue.Obj],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEX:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[1])*4); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEX:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[0])*4); - asm - jmp @Skip - @CodeBegin: - mov ecx,dword ptr [edx+TBESENValue.ValueType] - call dword ptr [ecx*4+offset BESENCopyValueProcs] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEXBOOL:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[1])*4); - asm - jmp @Skip - @CodeBegin: - mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [edx+TBESENValue.Bool] - mov dword ptr [eax+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEXBOOL:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[0])*4); - asm - jmp @Skip - @CodeBegin: - mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [edx+TBESENValue.Bool] - mov dword ptr [eax+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEXNUM:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[1])*4); - asm - jmp @Skip - @CodeBegin: - mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER - fld qword ptr [edx+TBESENValue.Num] - fstp qword ptr [eax+TBESENValue.Num] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEXNUM:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[0])*4); - asm - jmp @Skip - @CodeBegin: - mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER - fld qword ptr [edx+TBESENValue.Num] - fstp qword ptr [eax+TBESENValue.Num] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopGETVALUELOCALINDEXSTR:begin - AddDispatcher; - end; - bopPUTVALUELOCALINDEXSTR:begin - AddDispatcher; - end; - bopGETVALUELOCALINDEXOBJ:begin - Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - - Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[1])*4); - asm - jmp @Skip - @CodeBegin: - mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT - mov ecx,dword ptr [edx+TBESENValue.Obj] - mov dword ptr [eax+TBESENValue.Obj],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopPUTVALUELOCALINDEXOBJ:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); - - Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] - AddDWord(ptruint(Operands^[0])*4); - asm - jmp @Skip - @CodeBegin: - mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT - mov ecx,dword ptr [edx+TBESENValue.Obj] - mov dword ptr [eax+TBESENValue.Obj],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopLOOPINITCOUNT:begin - end; - bopLOOPADDCOUNT:begin - end; - bopTRACE:begin - if TBESEN(CodeContext.Instance).CodeTracable then begin - AddDispatcher; - end; - end; - bopLTBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setb al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGTBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setnbe al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLEBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setbe al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGEBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp al,$01 - sbb eax,eax - inc eax - cmp dl,$01 - sbb edx,edx - inc edx - cmp al,dl - setnb al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopEQBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp eax,edx - setz al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopNEQBOOL:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - cmp eax,edx - setnz al - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - end; - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLTNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGTNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setnbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLENUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGENUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setnb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopEQNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopNEQNUM:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - not eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLTSTR:begin - AddDispatcher; - end; - bopGTSTR:begin - AddDispatcher; - end; - bopLESTR:begin - AddDispatcher; - end; - bopGESTR:begin - AddDispatcher; - end; - bopEQSTR:begin - AddDispatcher; - end; - bopNEQSTR:begin - AddDispatcher; - end; - bopSHLBOOL:begin - AddDispatcher; - end; - bopSHRBOOL:begin - AddDispatcher; - end; - bopBANDBOOL:begin - AddDispatcher; - end; - bopBXORBOOL:begin - AddDispatcher; - end; - bopBORBOOL:begin - AddDispatcher; - end; - bopSHLNUM:begin - AddDispatcher; - end; - bopSHRNUM:begin - AddDispatcher; - end; - bopUSHRNUM:begin - AddDispatcher; - end; - bopBANDNUM:begin - AddDispatcher; - end; - bopBXORNUM:begin - AddDispatcher; - end; - bopBORNUM:begin - AddDispatcher; - end; - bopSETCUNDEF:begin - asm - jmp @Skip - @CodeBegin: - lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] - mov dword ptr [eax+TBESENValue.ValueType],bvtUNDEFINED - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCNULL:begin - asm - jmp @Skip - @CodeBegin: - lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] - mov dword ptr [eax+TBESENValue.ValueType],bvtNULL - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCBOOL:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] - mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN - mov ecx,dword ptr [edx+TBESENValue.Bool] - mov dword ptr [eax+TBESENValue.Bool],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCNUM:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] - mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER - fld qword ptr [edx+TBESENValue.Num] - fstp qword ptr [eax+TBESENValue.Num] - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopSETCSTR:begin - AddDispatcher; - end; - bopSETCOBJ:begin - Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); - asm - jmp @Skip - @CodeBegin: - lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] - mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT - mov ecx,dword ptr [edx+TBESENValue.Obj] - mov dword ptr [eax+TBESENValue.Obj],ecx - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - AddCode(CodeBegin,CodeEnd); - end; - bopTRACENEW:begin - AddDispatcher; - end; - bopTRACECALL:begin - AddDispatcher; - end; - bopLTNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGTNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setnbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopLENUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setbe al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopGENUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setnb al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopEQNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopNEQNUMCONST:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] - AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - not eax - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); - AddDWord(bvtBOOLEAN); - - Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax - AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); -{$endif} - end; - bopJZERO:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - if longword(Operands^[0])<>CurrentPC then begin - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [BESENDoubleZero] - AddDWord(ptruint(pointer(@BESENDoubleZero))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - cmp eax,0 - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$0f#$85); // jnz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; -{$endif} - end; - bopJNZERO:begin -{$ifdef UseSafeOperations} - AddDispatcher; -{$else} - if longword(Operands^[0])<>CurrentPC then begin - Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] - AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); - - Add(#$dc#$1d); // fcomp qword ptr [BESENDoubleZero] - AddDWord(ptruint(pointer(@BESENDoubleZero))); - - asm - jmp @Skip - @CodeBegin: - fstsw ax - sahf - setz al - setnp cl - and al,cl - neg al - sbb eax,eax - cmp eax,0 - @CodeEnd: - @Skip: - mov dword ptr CodeBegin,offset @CodeBegin - mov dword ptr CodeEnd,offset @CodeEnd - end; - - AddCode(CodeBegin,CodeEnd); - - Add(#$0f#$84); // jz Arg - if CountFixups>=length(Fixups) then begin - SetLength(Fixups,CountFixups+4096); - end; - Fixups[CountFixups].Kind:=fkOFS; - Fixups[CountFixups].Ofs:=CodeBufferLen; - Fixups[CountFixups].ToOfs:=Operands^[0]; - inc(CountFixups); - Add(#$00#$00#$00#$00); - end; -{$endif} - end; - else begin - AddDispatcher; - end; - end; - - end; - RetOfs:=CodeBufferLen; - Add(#$c3); // ret - SetLength(CodeBuffer,CodeBufferLen); - Code.NativeCodeSize:=CodeBufferLen; - Code.NativeCode:=TBESEN(CodeContext.Instance).NativeCodeMemoryManager.GetMemory(Code.NativeCodeSize); - move(CodeBuffer[0],Code.NativeCode^,Code.NativeCodeSize); - SetLength(Code.NativeCodePCOffsets,Code.ByteCodeLen); - for i:=0 to Code.ByteCodeLen-1 do begin - Code.NativeCodePCOffsets[i]:=pointer(@PBESENByteArray(Code.NativeCode)[Offsets[i]]); - end; - for i:=0 to CountFixups-1 do begin - case FixUps[i].Kind of - fkPTR:begin - ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(FixUps[i].Dest)-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); - end; - fkRET:begin - ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[RetOfs]))-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); - end; - fkOFS:begin - ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(Code.NativeCodePCOffsets[FixUps[i].ToOfs])-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); - end; - end; - end; - result:=true; - finally - SetLength(Fixups,0); - SetLength(Offsets,0); - SetLength(CodeBuffer,0); - end; -end; - -function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} -asm - push ebp - push ebx - push esi - push edi - mov esi,eax //ACodeContext - mov dword ptr [esi+TBESENCodeContext.BlockRunning],$ffffffff - mov edi,dword ptr [esi+TBESENCodeContext.RegisterValues] - mov edx,dword ptr [esi+TBESENCodeContext.Code] - mov ebx,dword ptr [edx+TBESENCode.Body] - mov ebx,dword ptr [ebx+TBESENASTNodeFunctionBody.IsFunction] - test ebx,ebx - jz @IsNoFunction - mov ebx,dword ptr [esi+TBESENCodeContext.Context] - mov ebx,dword ptr [ebx+TBESENContext.VariableEnvironment] - mov ebx,dword ptr [ebx+TBESENLexicalEnvironment.EnvironmentRecord] - mov ebx,dword ptr [ebx+TBESENDeclarativeEnvironmentRecord.HashValues] - @IsNoFunction: - mov ebp,dword ptr [edx+TBESENCode.NativeCodePCOffsets] - mov edx,dword ptr [esi+TBESENCodeContext.PC] - call dword ptr [ebp+edx*4] - mov eax,dword ptr [esi+TBESENCodeContext.BlockRunning] - pop edi - pop esi - pop ebx - pop ebp -end; -{$endif} -{$endif} - -end. diff --git a/3rd/besen/src/BESENCodeSnapshot.pas b/3rd/besen/src/BESENCodeSnapshot.pas deleted file mode 100644 index 02756543a..000000000 --- a/3rd/besen/src/BESENCodeSnapshot.pas +++ /dev/null @@ -1,1387 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCodeSnapshot; -{$i BESEN.inc} - -interface - -uses SysUtils,Classes,BESENConstants,BESENTypes,BESENBaseObject,BESENASTNodes; - -type TBESENCodeSnapshot=class(TBESENBaseObject) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function LoadFromStream(const Stream:TStream):TBESENASTNode; - procedure SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); - end; - -implementation - -uses BESEN,BESENValue,BESENInt64SelfBalancedTree,BESENPointerSelfBalancedTree, - BESENCode,BESENOpcodes,BESENUtils,BESENKeyIDManager, - BESENVersionConstants; - -constructor TBESENCodeSnapshot.Create(AInstance:TObject); -begin - inherited Create(AInstance); -end; - -destructor TBESENCodeSnapshot.Destroy; -begin - inherited Destroy; -end; - -function TBESENCodeSnapshot.LoadFromStream(const Stream:TStream):TBESENASTNode; -type TLoadedKeyManagerID=packed record - ID:integer; - Key:TBESENString; - end; - TLoadedKeyManagerIDs=array of TLoadedKeyManagerID; -var VisitedNodes:TBESENInt64SelfBalancedTree; - LoadedKeyManagerIDs:TLoadedKeyManagerIDs; - procedure BESENThrowStream(const s:string); - begin - raise EStreamError.Create(s); - end; - function ReadByte:byte; - begin - if Stream.Read(result,sizeof(byte))<>sizeof(byte) then begin - BESENThrowStream('Couldn''t read byte'); - end; - end; - function ReadBool:boolean; - begin - result:=ReadByte<>0; - end; - function ReadInt32:integer; - begin - if Stream.Read(result,sizeof(integer))<>sizeof(integer) then begin - BESENThrowStream('Couldn''t read integer'); - end; - end; - function ReadInt64:int64; - begin - if Stream.Read(result,sizeof(int64))<>sizeof(int64) then begin - BESENThrowStream('Couldn''t read int64'); - end; - end; - function ReadDouble:double; - begin - if Stream.Read(result,sizeof(double))<>sizeof(double) then begin - BESENThrowStream('Couldn''t double double'); - end; - end; - function ReadWideString:widestring; - var l:integer; - begin - l:=ReadInt32; - SetLength(result,l); - if length(result)>0 then begin - if Stream.Read(result[1],sizeof(widechar)*length(result))<>(sizeof(widechar)*length(result)) then begin - BESENThrowStream('Couldn''t read widestring'); - end; - end; - end; - function ReadNode:TBESENASTNode; - var Counter,Target,LineNumber,i,j,k:integer; - VisitNodeValue:TBESENInt64SelfBalancedTreeValue; - v:PBESENValue; - Ptr:int64; - NodeType:TBESENASTNodeType; - Code:TBESENCode; - FunctionLiteral:TBESENASTNodeFunctionLiteral; - function CreateNode(c:TBESENASTNodeClass):TBESENASTNode; - var Counter:integer; - begin - result:=c.Create(Instance); - VisitNodeValue.p:=result; - VisitedNodes.Insert(Ptr,VisitNodeValue); - TBESENASTNode(result).NodeType:=NodeType; - TBESENASTNode(result).Target:=Target; - TBESENASTNode(result).Location.LineNumber:=LineNumber; - TBESENASTNode(result).CountTrashNodes:=ReadInt32; - SetLength(TBESENASTNode(result).TrashNodes,TBESENASTNode(result).CountTrashNodes); - for Counter:=0 to TBESENASTNode(result).CountTrashNodes-1 do begin - TBESENASTNode(result).TrashNodes[Counter]:=TBESENASTNodeStatement(ReadNode); - end; - end; - begin - result:=nil; - try - Ptr:=ReadInt64; - if Ptr<>0 then begin - if VisitedNodes.Find(Ptr,VisitNodeValue) then begin - result:=VisitNodeValue.p; - end else begin - NodeType:=ReadByte; - Target:=ReadInt32; - LineNumber:=ReadInt32; - case NodeType of - bntNONE:begin - result:=CreateNode(TBESENASTNode); - end; - bntEXPRESSION:begin - result:=CreateNode(TBESENASTNodeExpression); - end; - bntLITERAL:begin - result:=CreateNode(TBESENASTNodeLiteral); - end; - bntIDENTIFIER:begin - result:=CreateNode(TBESENASTNodeIdentifier); - TBESENASTNodeIdentifier(result).Name:=ReadWideString; - TBESENASTNodeIdentifier(result).Index:=ReadInt32; - TBESENASTNodeIdentifier(result).ParameterIndex:=ReadInt32; - i:=ReadInt32; - if (i>=0) and (i<length(LoadedKeyManagerIDs)) then begin - TBESENASTNodeIdentifier(result).ID:=LoadedKeyManagerIDs[i].ID; - end else begin - TBESENASTNodeIdentifier(result).ID:=i; - end; - TBESENASTNodeIdentifier(result).IsParameter:=ReadBool; - TBESENASTNodeIdentifier(result).IsLocal:=ReadBool; - end; - bntVARIABLEDECLARATION:begin - result:=CreateNode(TBESENASTNodeVariableDeclaration); - TBESENASTNodeVariableDeclaration(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); - TBESENASTNodeVariableDeclaration(result).Expression:=TBESENASTNodeExpression(ReadNode); - end; - bntVARIABLEEXPRESSION:begin - result:=CreateNode(TBESENASTNodeVariableExpression); - SetLength(TBESENASTNodeVariableExpression(result).Declarations,ReadInt32); - for Counter:=0 to length(TBESENASTNodeVariableExpression(result).Declarations)-1 do begin - TBESENASTNodeVariableExpression(result).Declarations[Counter]:=TBESENASTNodeVariableDeclaration(ReadNode); - end; - end; - bntFUNCTIONBODY:begin - result:=CreateNode(TBESENASTNodeFunctionBody); - TBESENASTNodeFunctionBody(result).IsFunction:=ReadBool; - TBESENASTNodeFunctionBody(result).IsEmpty:=ReadBool; - TBESENASTNodeFunctionBody(result).EnableLocalsOptimization:=ReadBool; - TBESENASTNodeFunctionBody(result).DisableArgumentsObject:=ReadBool; - SetLength(TBESENASTNodeFunctionBody(result).Variables,ReadInt32); - for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Variables)-1 do begin - TBESENASTNodeFunctionBody(result).Variables[Counter]:=TBESENASTNodeIdentifier(ReadNode); - end; - SetLength(TBESENASTNodeFunctionBody(result).Parameters,ReadInt32); - for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Parameters)-1 do begin - TBESENASTNodeFunctionBody(result).Parameters[Counter]:=TBESENASTNodeIdentifier(ReadNode); - end; - SetLength(TBESENASTNodeFunctionBody(result).Functions,ReadInt32); - for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Functions)-1 do begin - TBESENASTNodeFunctionBody(result).Functions[Counter]:=TBESENASTNodeStatement(ReadNode); - end; - SetLength(TBESENASTNodeFunctionBody(result).Statements,ReadInt32); - for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Statements)-1 do begin - TBESENASTNodeFunctionBody(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); - end; - if ReadBool then begin - Code:=TBESENCode(TBESENASTNodeFunctionBody(result).Code); - Code.Body:=TBESENASTNodeFunctionBody(ReadNode); - Code.MaxRegisters:=ReadInt32; - Code.MaxBlock:=ReadInt32; - Code.MaxParamArgs:=ReadInt32; - Code.MaxLoop:=ReadInt32; - Code.HasLocalDelete:=ReadBool; - Code.IsComplexFunction:=ReadBool; - Code.HasMaybeDirectEval:=ReadBool; - Code.HoldLocalVariablesInRegisters:=ReadBool; - Code.CountFunctionLiteralContainers:=ReadInt32; - SetLength(Code.FunctionLiteralContainers,Code.CountFunctionLiteralContainers); - for Counter:=0 to Code.CountFunctionLiteralContainers-1 do begin - FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); - if assigned(FunctionLiteral) then begin - if not assigned(FunctionLiteral.Container) then begin - FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); - FunctionLiteral.Container.Literal:=FunctionLiteral; - end; - Code.FunctionLiteralContainers[Counter]:=FunctionLiteral.Container; - end else begin - Code.FunctionLiteralContainers[Counter]:=nil; - end; - end; - Code.CountLiterals:=ReadInt32; - SetLength(Code.Literals,Code.CountLiterals); - for Counter:=0 to Code.CountLiterals-1 do begin - v:=@Code.Literals[Counter]; - v^.ValueType:=ReadByte; - case v^.ValueType of - bvtNONE:begin - end; - bvtUNDEFINED:begin - end; - bvtNULL:begin - end; - bvtBOOLEAN:begin - v^.Bool:=ReadBool; - end; - bvtNUMBER:begin - v^.Num:=ReadDouble; - end; - bvtSTRING:begin - v^.Str:=ReadWideString; - end; - else begin - BESENThrowStream('Couldn''t read value'); - end; - end; - end; - Code.CountLocations:=ReadInt32; - SetLength(Code.Locations,Code.CountLocations); - for Counter:=0 to Code.CountLocations-1 do begin - Code.Locations[Counter].LineNumber:=ReadInt32; - end; - Code.CountVariables:=ReadInt32; - SetLength(Code.Variables,Code.CountVariables); - for Counter:=0 to Code.CountVariables-1 do begin - Code.Variables[Counter].Name:=ReadWideString; - Code.Variables[Counter].IsParameter:=ReadBool; - Code.Variables[Counter].ParameterIndex:=ReadInt32; - end; - Code.CountPolymorphicInlineCacheInstructions:=ReadInt32; - k:=ReadInt32; - Code.LookupNames.Clear; - for Counter:=0 to k-1 do begin - Code.LookupNames.Add(ReadWideString); - end; - Code.ByteCodeLen:=ReadInt32; - SetLength(Code.ByteCode,Code.ByteCodeLen); - if Code.ByteCodeLen>0 then begin - if Stream.Read(Code.ByteCode[0],Code.ByteCodeLen*sizeof(TBESENUINT32))<>(Code.ByteCodeLen*sizeof(TBESENUINT32)) then begin - BESENThrowStream('Couldn''t read byte code'); - end; - i:=0; - while i<Code.ByteCodeLen do begin - j:=i; - inc(i,1+((Code.ByteCode[i] shr 8) and $ffffff)); - case Code.ByteCode[j] and $ff of - bopREF:begin - k:=Code.ByteCode[j+4]; - if (k>=0) and (k<length(LoadedKeyManagerIDs)) then begin - k:=LoadedKeyManagerIDs[k].ID; - end; - Code.ByteCode[j+4]:=k; - end; - end; - end; - end; - Code.Finish; - end; - end; - bntFUNCTIONLITERAL:begin - result:=CreateNode(TBESENASTNodeFunctionLiteral); - TBESENASTNodeFunctionLiteral(result).Name:=TBESENASTNodeIdentifier(ReadNode); - FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); - if assigned(FunctionLiteral) then begin - if not assigned(FunctionLiteral.Container) then begin - FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); - FunctionLiteral.Container.Literal:=FunctionLiteral; - end; - TBESENASTNodeFunctionLiteral(result).Container:=FunctionLiteral.Container; - end else begin - TBESENASTNodeFunctionLiteral(result).Container:=nil; - end; - TBESENASTNodeFunctionLiteral(result).Index:=ReadInt32; - TBESENASTNodeFunctionLiteral(result).Body:=TBESENASTNodeFunctionBody(ReadNode); - end; - bntSTATEMENT:begin - result:=CreateNode(TBESENASTNodeStatement); - end; - bntVARIABLESTATEMENT:begin - result:=CreateNode(TBESENASTNodeVariableStatement); - SetLength(TBESENASTNodeVariableStatement(result).Declarations,ReadInt32); - for Counter:=0 to length(TBESENASTNodeVariableStatement(result).Declarations)-1 do begin - TBESENASTNodeVariableStatement(result).Declarations[Counter]:=TBESENASTNodeVariableDeclaration(ReadNode); - end; - end; - bntFUNCTIONDECLARATION:begin - result:=CreateNode(TBESENASTNodeFunctionDeclaration); - if ReadBool then begin - FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); - if assigned(FunctionLiteral) then begin - if not assigned(FunctionLiteral.Container) then begin - FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); - FunctionLiteral.Container.Literal:=FunctionLiteral; - end; - TBESENASTNodeFunctionDeclaration(result).Container:=FunctionLiteral.Container; - end else begin - TBESENASTNodeFunctionDeclaration(result).Container:=nil; - end; - end else begin - TBESENASTNodeFunctionDeclaration(result).Container:=nil; - end; - end; - bntEXPRESSIONSTATEMENT:begin - result:=CreateNode(TBESENASTNodeExpressionStatement); - TBESENASTNodeExpressionStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - end; - bntEMPTYSTATEMENT:begin - result:=CreateNode(TBESENASTNodeEmptyStatement); - end; - bntBLOCKSTATEMENT:begin - result:=CreateNode(TBESENASTNodeBlockStatement); - SetLength(TBESENASTNodeBlockStatement(result).Statements,ReadInt32); - for Counter:=0 to length(TBESENASTNodeBlockStatement(result).Statements)-1 do begin - TBESENASTNodeBlockStatement(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); - end; - end; - bntDEBUGGERSTATEMENT:begin - result:=CreateNode(TBESENASTNodeDebuggerStatement); - end; - bntBREAKSTATEMENT:begin - result:=CreateNode(TBESENASTNodeBreakStatement); - TBESENASTNodeBreakStatement(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); - end; - bntCONTINUESTATEMENT:begin - result:=CreateNode(TBESENASTNodeContinueStatement); - TBESENASTNodeContinueStatement(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); - end; - bntDOSTATEMENT:begin - result:=CreateNode(TBESENASTNodeDoStatement); - TBESENASTNodeDoStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); - TBESENASTNodeDoStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - end; - bntWHILESTATEMENT:begin - result:=CreateNode(TBESENASTNodeWhileStatement); - TBESENASTNodeWhileStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeWhileStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); - end; - bntWITHSTATEMENT:begin - result:=CreateNode(TBESENASTNodeWithStatement); - TBESENASTNodeWithStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeWithStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); - end; - bntFORSTATEMENT:begin - result:=CreateNode(TBESENASTNodeForStatement); - TBESENASTNodeForStatement(result).Initial:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeForStatement(result).Condition:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeForStatement(result).Increment:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeForStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); - end; - bntFORINSTATEMENT:begin - result:=CreateNode(TBESENASTNodeForInStatement); - TBESENASTNodeForInStatement(result).Variable:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeForInStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeForInStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); - end; - bntIFSTATEMENT:begin - result:=CreateNode(TBESENASTNodeIfStatement); - TBESENASTNodeIfStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeIfStatement(result).TrueStatement:=TBESENASTNodeStatement(ReadNode); - TBESENASTNodeIfStatement(result).FalseStatement:=TBESENASTNodeStatement(ReadNode); - end; - bntLABELLEDSTATEMENT:begin - result:=CreateNode(TBESENASTNodeLabelledStatement); - SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,ReadInt32); - for Counter:=0 to length(TBESENASTNodeLabelledStatement(result).Identifiers)-1 do begin - TBESENASTNodeLabelledStatement(result).Identifiers[Counter]:=TBESENASTNodeIdentifier(ReadNode); - end; - TBESENASTNodeLabelledStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); - end; - bntCASESTATEMENT:begin - result:=CreateNode(TBESENASTNodeCaseStatement); - TBESENASTNodeCaseStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - SetLength(TBESENASTNodeCaseStatement(result).Statements,ReadInt32); - for Counter:=0 to length(TBESENASTNodeCaseStatement(result).Statements)-1 do begin - TBESENASTNodeCaseStatement(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); - end; - end; - bntSWITCHSTATEMENT:begin - result:=CreateNode(TBESENASTNodeSwitchStatement); - TBESENASTNodeSwitchStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - SetLength(TBESENASTNodeSwitchStatement(result).CaseStatements,ReadInt32); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(result).CaseStatements)-1 do begin - TBESENASTNodeSwitchStatement(result).CaseStatements[Counter]:=TBESENASTNodeCaseStatement(ReadNode); - end; - end; - bntTHROWSTATEMENT:begin - result:=CreateNode(TBESENASTNodeThrowStatement); - TBESENASTNodeThrowStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - end; - bntTRYSTATEMENT:begin - result:=CreateNode(TBESENASTNodeTryStatement); - TBESENASTNodeTryStatement(result).TryBlock:=TBESENASTNodeBlockStatement(ReadNode); - TBESENASTNodeTryStatement(result).CatchIdentifier:=TBESENASTNodeIdentifier(ReadNode); - TBESENASTNodeTryStatement(result).CatchBlock:=TBESENASTNodeBlockStatement(ReadNode); - TBESENASTNodeTryStatement(result).FinallyBlock:=TBESENASTNodeBlockStatement(ReadNode); - end; - bntARRAYLITERAL:begin - result:=CreateNode(TBESENASTNodeArrayLiteral); - SetLength(TBESENASTNodeArrayLiteral(result).Elements,ReadInt32); - for Counter:=0 to length(TBESENASTNodeArrayLiteral(result).Elements)-1 do begin - TBESENASTNodeArrayLiteral(result).Elements[Counter]:=TBESENASTNodeExpression(ReadNode); - end; - end; - bntBINARYEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryExpression); - TBESENASTNodeBinaryExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentExpression); - TBESENASTNodeAssignmentExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentOperatorExpression); - TBESENASTNodeAssignmentOperatorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentOperatorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentMultiplyExpression); - TBESENASTNodeAssignmentMultiplyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentMultiplyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentDivideExpression); - TBESENASTNodeAssignmentDivideExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentDivideExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentModuloExpression); - TBESENASTNodeAssignmentModuloExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentModuloExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentPlusExpression); - TBESENASTNodeAssignmentPlusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentPlusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentMinusExpression); - TBESENASTNodeAssignmentMinusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentMinusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentShiftLeftExpression); - TBESENASTNodeAssignmentShiftLeftExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentShiftLeftExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentShiftRightExpression); - TBESENASTNodeAssignmentShiftRightExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentShiftRightExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentShiftRightUnsignedExpression); - TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentBitwiseAndExpression); - TBESENASTNodeAssignmentBitwiseAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentBitwiseAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentBitwiseXorExpression); - TBESENASTNodeAssignmentBitwiseXorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentBitwiseXorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeAssignmentBitwiseOrExpression); - TBESENASTNodeAssignmentBitwiseOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeAssignmentBitwiseOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYOPERATOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryOperatorExpression); - TBESENASTNodeBinaryOperatorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryOperatorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYCOMMAEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryCommaExpression); - TBESENASTNodeBinaryCommaExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryCommaExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYDIVIDEEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryDivideExpression); - TBESENASTNodeBinaryDivideExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryDivideExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYMODULOEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryModuloExpression); - TBESENASTNodeBinaryModuloExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryModuloExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYMULTIPLYEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryMultiplyExpression); - TBESENASTNodeBinaryMultiplyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryMultiplyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYPLUSEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryPlusExpression); - TBESENASTNodeBinaryPlusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryPlusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYMINUSEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryMinusExpression); - TBESENASTNodeBinaryMinusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryMinusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryShiftLeftExpression); - TBESENASTNodeBinaryShiftLeftExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryShiftLeftExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryShiftRightExpression); - TBESENASTNodeBinaryShiftRightExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryShiftRightExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryShiftRightUnsignedExpression); - TBESENASTNodeBinaryShiftRightUnsignedExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryShiftRightUnsignedExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYGREATERTHANEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryGreaterThanExpression); - TBESENASTNodeBinaryGreaterThanExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryGreaterThanExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryGreaterThanOrEqualExpression); - TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYLESSTHANEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryLessThanExpression); - TBESENASTNodeBinaryLessThanExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryLessThanExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryLessThanOrEqualExpression); - TBESENASTNodeBinaryLessThanOrEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryLessThanOrEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYINSTANCEOFEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryInstanceOfExpression); - TBESENASTNodeBinaryInstanceOfExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryInstanceOfExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYINEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryInExpression); - TBESENASTNodeBinaryInExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryInExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYEQUALEQUALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryEqualEqualExpression); - TBESENASTNodeBinaryEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryEqualEqualEqualExpression); - TBESENASTNodeBinaryEqualEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryEqualEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYNOTEQUALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryNotEqualExpression); - TBESENASTNodeBinaryNotEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryNotEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryNotEqualEqualExpression); - TBESENASTNodeBinaryNotEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryNotEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYBITWISEANDEXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryBitwiseAndExpression); - TBESENASTNodeBinaryBitwiseAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryBitwiseAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYBITWISEXOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryBitwiseXorExpression); - TBESENASTNodeBinaryBitwiseXorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryBitwiseXorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBINARYBITWISEOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeBinaryBitwiseOrExpression); - TBESENASTNodeBinaryBitwiseOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeBinaryBitwiseOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntBOOLEANLITERAL:begin - result:=CreateNode(TBESENASTNodeBooleanLiteral); - TBESENASTNodeBooleanLiteral(result).Value:=ReadBool; - end; - bntCALLEXPRESSION:begin - result:=CreateNode(TBESENASTNodeCallExpression); - TBESENASTNodeCallExpression(result).TheFunction:=TBESENASTNodeExpression(ReadNode); - SetLength(TBESENASTNodeCallExpression(result).Arguments,ReadInt32); - for Counter:=0 to length(TBESENASTNodeCallExpression(result).Arguments)-1 do begin - TBESENASTNodeCallExpression(result).Arguments[Counter]:=TBESENASTNodeExpression(ReadNode); - end; - end; - bntNEWEXPRESSION:begin - result:=CreateNode(TBESENASTNodeNewExpression); - TBESENASTNodeNewExpression(result).TheFunction:=TBESENASTNodeExpression(ReadNode); - SetLength(TBESENASTNodeNewExpression(result).Arguments,ReadInt32); - for Counter:=0 to length(TBESENASTNodeNewExpression(result).Arguments)-1 do begin - TBESENASTNodeNewExpression(result).Arguments[Counter]:=TBESENASTNodeExpression(ReadNode); - end; - end; - bntCONDITIONALEXPRESSION:begin - result:=CreateNode(TBESENASTNodeConditionalExpression); - TBESENASTNodeConditionalExpression(result).Expression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeConditionalExpression(result).TrueExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeConditionalExpression(result).FalseExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryExpression); - TBESENASTNodeUnaryExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYOPERATOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryOperatorExpression); - TBESENASTNodeUnaryOperatorExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYPLUSEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryPlusExpression); - TBESENASTNodeUnaryPlusExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYMINUSEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryMinusExpression); - TBESENASTNodeUnaryMinusExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYBITWISENOTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryBitwiseNotExpression); - TBESENASTNodeUnaryBitwiseNotExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYLOGICALNOTEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryLogicalNotExpression); - TBESENASTNodeUnaryLogicalNotExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYVOIDEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryVoidExpression); - TBESENASTNodeUnaryVoidExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntUNARYTYPEOFEXPRESSION:begin - result:=CreateNode(TBESENASTNodeUnaryTypeOfExpression); - TBESENASTNodeUnaryTypeOfExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntPROPERTYEXPRESSION:begin - result:=CreateNode(TBESENASTNodePropertyExpression); - TBESENASTNodePropertyExpression(result).Dot:=ReadBool; - TBESENASTNodePropertyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodePropertyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntLOGICALANDEXPRESSION:begin - result:=CreateNode(TBESENASTNodeLogicalAndExpression); - TBESENASTNodeLogicalAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeLogicalAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntLOGICALOREXPRESSION:begin - result:=CreateNode(TBESENASTNodeLogicalOrExpression); - TBESENASTNodeLogicalOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); - TBESENASTNodeLogicalOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntDELETEEXPRESSION:begin - result:=CreateNode(TBESENASTNodeDeleteExpression); - TBESENASTNodeDeleteExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntPOSTFIXINCEXPRESSION:begin - result:=CreateNode(TBESENASTNodePostfixIncExpression); - TBESENASTNodePostfixIncExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntPOSTFIXDECEXPRESSION:begin - result:=CreateNode(TBESENASTNodePostfixDecExpression); - TBESENASTNodePostfixDecExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntPREFIXINCEXPRESSION:begin - result:=CreateNode(TBESENASTNodePrefixIncExpression); - TBESENASTNodePrefixIncExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntPREFIXDECEXPRESSION:begin - result:=CreateNode(TBESENASTNodePrefixDecExpression); - TBESENASTNodePrefixDecExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); - end; - bntNULLLITERAL:begin - end; - bntNUMBERLITERAL:begin - result:=CreateNode(TBESENASTNodeNumberLiteral); - TBESENASTNodeNumberLiteral(result).Value:=ReadDouble; - end; - bntREGEXPLITERAL:begin - result:=CreateNode(TBESENASTNodeRegExpLiteral); - TBESENASTNodeRegExpLiteral(result).Source:=ReadWideString; - TBESENASTNodeRegExpLiteral(result).Flags:=ReadWideString; - end; - bntSTRINGLITERAL:begin - result:=CreateNode(TBESENASTNodeStringLiteral); - TBESENASTNodeStringLiteral(result).Value:=ReadWideString; - end; - bntTHISLITERAL:begin - result:=CreateNode(TBESENASTNodeThisLiteral); - end; - bntOBJECTLITERALPROPERTY:begin - result:=CreateNode(TBESENASTNodeObjectLiteralProperty); - TBESENASTNodeObjectLiteralProperty(result).Name:=ReadWideString; - TBESENASTNodeObjectLiteralProperty(result).PropertyType:=TBESENASTNodeObjectLiteralPropertyType(ReadInt32); - TBESENASTNodeObjectLiteralProperty(result).PropertyAccessorType:=TBESENASTNodeObjectLiteralPropertyAccessorType(ReadInt32); - TBESENASTNodeObjectLiteralProperty(result).Value:=TBESENASTNodeExpression(ReadNode); - if ReadBool then begin - FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); - if assigned(FunctionLiteral) then begin - if not assigned(FunctionLiteral.Container) then begin - FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); - FunctionLiteral.Container.Literal:=FunctionLiteral; - end; - TBESENASTNodeObjectLiteralProperty(result).Container:=FunctionLiteral.Container; - end else begin - TBESENASTNodeObjectLiteralProperty(result).Container:=nil; - end; - end else begin - TBESENASTNodeObjectLiteralProperty(result).Container:=nil; - end; - end; - bntOBJECTLITERAL:begin - result:=CreateNode(TBESENASTNodeObjectLiteral); - SetLength(TBESENASTNodeObjectLiteral(result).Properties,ReadInt32); - for Counter:=0 to length(TBESENASTNodeObjectLiteral(result).Properties)-1 do begin - TBESENASTNodeObjectLiteral(result).Properties[Counter]:=TBESENASTNodeObjectLiteralProperty(ReadNode); - end; - end; - bntRETURNSTATEMENT:begin - result:=CreateNode(TBESENASTNodeReturnStatement); - TBESENASTNodeReturnStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); - end; - bntPROGRAM:begin - result:=CreateNode(TBESENASTNodeProgram); - TBESENASTNodeProgram(result).Body:=TBESENASTNodeFunctionBody(ReadNode); - end; - bntFUNCTIONEXPRESSION:begin - result:=CreateNode(TBESENASTNodeFunctionExpression); - if ReadBool then begin - FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); - if assigned(FunctionLiteral) then begin - if not assigned(FunctionLiteral.Container) then begin - FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); - FunctionLiteral.Container.Literal:=FunctionLiteral; - end; - TBESENASTNodeFunctionExpression(result).Container:=FunctionLiteral.Container; - end else begin - TBESENASTNodeFunctionExpression(result).Container:=nil; - end; - end else begin - TBESENASTNodeFunctionExpression(result).Container:=nil; - end; - end; - end; - end; - end; - except - BESENFreeAndNil(result); - end; - end; -var Count,Counter:integer; - Key:TBESENString; -begin - VisitedNodes:=TBESENInt64SelfBalancedTree.Create; - LoadedKeyManagerIDs:=nil; - try - result:=nil; - try - if ReadInt64<>BESENCodeFormatRevisionNumber then begin - BESENThrowStream('Bad format'); - end; - Count:=ReadInt32; - SetLength(LoadedKeyManagerIDs,Count); - for Counter:=0 to Count-1 do begin - Key:=ReadWideString; - LoadedKeyManagerIDs[Counter].Key:=Key; - LoadedKeyManagerIDs[Counter].ID:=TBESEN(Instance).KeyIDManager.Get(Key); - end; - result:=ReadNode; - except - BESENFreeAndNil(result); - end; - finally - BESENFreeAndNil(VisitedNodes); - SetLength(LoadedKeyManagerIDs,0); - Key:=''; - end; -end; - -procedure TBESENCodeSnapshot.SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); -var VisitedNodes:TBESENPointerSelfBalancedTree; - procedure BESENThrowStream(const s:string); - begin - raise EStreamError.Create(s); - end; - procedure WriteByte(const b:byte); - begin - if Stream.Write(b,sizeof(byte))<>sizeof(byte) then begin - BESENThrowStream('Couldn''t write byte'); - end; - end; - procedure WriteBool(const b:boolean); - begin - if b then begin - WriteByte($ff); - end else begin - WriteByte(0); - end; - end; - procedure WriteInt32(const i:integer); - begin - if Stream.Write(i,sizeof(integer))<>sizeof(integer) then begin - BESENThrowStream('Couldn''t write integer'); - end; - end; - procedure WriteInt64(const i:int64); - begin - if Stream.Write(i,sizeof(int64))<>sizeof(int64) then begin - BESENThrowStream('Couldn''t write int64'); - end; - end; - procedure WriteDouble(const d:double); - begin - if Stream.Write(d,sizeof(double))<>sizeof(double) then begin - BESENThrowStream('Couldn''t write double'); - end; - end; - procedure WriteWideString(const ws:widestring); - begin - WriteInt32(length(ws)); - if length(ws)>0 then begin - if Stream.Write(ws[1],sizeof(widechar)*length(ws))<>(sizeof(widechar)*length(ws)) then begin - BESENThrowStream('Couldn''t write widestring'); - end; - end; - end; - procedure Visit(ToVisit:TBESENASTNode); - var Counter:integer; - VisitNodeValue:TBESENPointerSelfBalancedTreeValue; - v:PBESENValue; - Code:TBESENCode; - begin - WriteInt64(ptrint(ToVisit)); - if assigned(ToVisit) and not VisitedNodes.Find(ToVisit,VisitNodeValue) then begin - VisitNodeValue.p:=ToVisit; - VisitedNodes.Insert(ToVisit,VisitNodeValue); - WriteByte(ToVisit.NodeType); - WriteInt32(TBESENASTNode(ToVisit).Target); - WriteInt32(TBESENASTNode(ToVisit).Location.LineNumber); - WriteInt32(TBESENASTNode(ToVisit).CountTrashNodes); - for Counter:=0 to TBESENASTNode(ToVisit).CountTrashNodes-1 do begin - Visit(TBESENASTNode(ToVisit).TrashNodes[Counter]); - end; - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - end; - bntLITERAL:begin - end; - bntIDENTIFIER:begin - WriteWideString(TBESENASTNodeIdentifier(ToVisit).Name); - WriteInt32(TBESENASTNodeIdentifier(ToVisit).Index); - WriteInt32(TBESENASTNodeIdentifier(ToVisit).ParameterIndex); - WriteInt32(TBESENASTNodeIdentifier(ToVisit).ID); - WriteBool(TBESENASTNodeIdentifier(ToVisit).IsParameter); - WriteBool(TBESENASTNodeIdentifier(ToVisit).IsLocal); - end; - bntVARIABLEDECLARATION:begin - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); - end; - bntVARIABLEEXPRESSION:begin - WriteInt32(length(TBESENASTNodeVariableExpression(ToVisit).Declarations)); - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONBODY:begin - WriteBool(TBESENASTNodeFunctionBody(ToVisit).IsFunction); - WriteBool(TBESENASTNodeFunctionBody(ToVisit).IsEmpty); - WriteBool(TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization); - WriteBool(TBESENASTNodeFunctionBody(ToVisit).DisableArgumentsObject); - WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Variables)); - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]); - end; - WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Parameters)); - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]); - end; - WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Functions)); - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]); - end; - WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Statements)); - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); - end; - WriteBool(assigned(TBESENASTNodeFunctionBody(ToVisit).Code)); - if assigned(TBESENASTNodeFunctionBody(ToVisit).Code) then begin - Code:=TBESENCode(TBESENASTNodeFunctionBody(ToVisit).Code); - Visit(Code.Body); - WriteInt32(Code.MaxRegisters); - WriteInt32(Code.MaxBlock); - WriteInt32(Code.MaxParamArgs); - WriteInt32(Code.MaxLoop); - WriteBool(Code.HasLocalDelete); - WriteBool(Code.IsComplexFunction); - WriteBool(Code.HasMaybeDirectEval); - WriteBool(Code.HoldLocalVariablesInRegisters); - WriteInt32(Code.CountFunctionLiteralContainers); - for Counter:=0 to Code.CountFunctionLiteralContainers-1 do begin - Visit(Code.FunctionLiteralContainers[Counter].Literal); - end; - WriteInt32(Code.CountLiterals); - for Counter:=0 to Code.CountLiterals-1 do begin - v:=@Code.Literals[Counter]; - WriteByte(v^.ValueType); - case v^.ValueType of - bvtNONE:begin - end; - bvtUNDEFINED:begin - end; - bvtNULL:begin - end; - bvtBOOLEAN:begin - WriteBool(v^.Bool); - end; - bvtNUMBER:begin - WriteDouble(v^.Num); - end; - bvtSTRING:begin - WriteWideString(v^.Str); - end; - else begin - BESENThrowStream('Couldn''t write value'); - end; - end; - end; - WriteInt32(Code.CountLocations); - for Counter:=0 to Code.CountLocations-1 do begin - WriteInt32(Code.Locations[Counter].LineNumber); - end; - WriteInt32(Code.CountVariables); - for Counter:=0 to Code.CountVariables-1 do begin - WriteWideString(Code.Variables[Counter].Name); - WriteBool(Code.Variables[Counter].IsParameter); - WriteInt32(Code.Variables[Counter].ParameterIndex); - end; - WriteInt32(Code.CountPolymorphicInlineCacheInstructions); - WriteInt32(Code.LookupNames.Count); - for Counter:=0 to Code.LookupNames.Count-1 do begin - WriteWideString(Code.LookupNames[Counter]); - end; - WriteInt32(Code.ByteCodeLen); - if Code.ByteCodeLen>0 then begin - if Stream.Write(Code.ByteCode[0],Code.ByteCodeLen*sizeof(TBESENUINT32))<>(Code.ByteCodeLen*sizeof(TBESENUINT32)) then begin - BESENThrowStream('Couldn''t write byte code'); - end; - end; - end; - end; - bntFUNCTIONLITERAL:begin - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Name); - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Container.Literal); - WriteInt32(TBESENASTNodeFunctionLiteral(ToVisit).Index); - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); - end; - bntSTATEMENT:begin - end; - bntVARIABLESTATEMENT:begin - WriteInt32(length(TBESENASTNodeVariableStatement(ToVisit).Declarations)); - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONDECLARATION:begin - WriteBool(assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container)); - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); - end; - end; - bntEXPRESSIONSTATEMENT:begin - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); - end; - bntEMPTYSTATEMENT:begin - end; - bntBLOCKSTATEMENT:begin - WriteInt32(length(TBESENASTNodeBlockStatement(ToVisit).Statements)); - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); - end; - end; - bntDEBUGGERSTATEMENT:begin - end; - bntBREAKSTATEMENT:begin - Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); - end; - bntCONTINUESTATEMENT:begin - Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); - end; - bntDOSTATEMENT:begin - Visit(TBESENASTNodeDoStatement(ToVisit).Statement); - Visit(TBESENASTNodeDoStatement(ToVisit).Expression); - end; - bntWHILESTATEMENT:begin - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); - end; - bntWITHSTATEMENT:begin - Visit(TBESENASTNodeWithStatement(ToVisit).Expression); - Visit(TBESENASTNodeWithStatement(ToVisit).Statement); - end; - bntFORSTATEMENT:begin - Visit(TBESENASTNodeForStatement(ToVisit).Initial); - Visit(TBESENASTNodeForStatement(ToVisit).Condition); - Visit(TBESENASTNodeForStatement(ToVisit).Increment); - Visit(TBESENASTNodeForStatement(ToVisit).Statement); - end; - bntFORINSTATEMENT:begin - Visit(TBESENASTNodeForInStatement(ToVisit).Variable); - Visit(TBESENASTNodeForInStatement(ToVisit).Expression); - Visit(TBESENASTNodeForInStatement(ToVisit).Statement); - end; - bntIFSTATEMENT:begin - Visit(TBESENASTNodeIfStatement(ToVisit).Expression); - Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); - Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); - end; - bntLABELLEDSTATEMENT:begin - WriteInt32(length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)); - for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin - Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); - end; - Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); - end; - bntCASESTATEMENT:begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); - WriteInt32(length(TBESENASTNodeCaseStatement(ToVisit).Statements)); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); - end; - end; - bntSWITCHSTATEMENT:begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); - WriteInt32(length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); - end; - end; - bntTHROWSTATEMENT:begin - Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); - end; - bntTRYSTATEMENT:begin - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); - Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); - end; - bntARRAYLITERAL:begin - WriteInt32(length(TBESENASTNodeArrayLiteral(ToVisit).Elements)); - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); - end; - end; - bntBINARYEXPRESSION:begin - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); - end; - bntBINARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); - end; - bntBINARYCOMMAEXPRESSION:begin - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); - end; - bntBINARYDIVIDEEXPRESSION:begin - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); - end; - bntBINARYMODULOEXPRESSION:begin - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); - end; - bntBINARYMULTIPLYEXPRESSION:begin - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); - end; - bntBINARYPLUSEXPRESSION:begin - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); - end; - bntBINARYMINUSEXPRESSION:begin - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); - end; - bntBINARYGREATERTHANEXPRESSION:begin - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); - end; - bntBINARYLESSTHANEXPRESSION:begin - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); - end; - bntBINARYINSTANCEOFEXPRESSION:begin - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); - end; - bntBINARYINEXPRESSION:begin - Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); - end; - bntBINARYEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYNOTEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEANDEXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEXOREXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEOREXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); - end; - bntBOOLEANLITERAL:begin - WriteBool(TBESENASTNodeBooleanLiteral(ToVisit).Value); - end; - bntCALLEXPRESSION:begin - Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); - WriteInt32(length(TBESENASTNodeCallExpression(ToVisit).Arguments)); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); - end; - end; - bntNEWEXPRESSION:begin - Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); - WriteInt32(length(TBESENASTNodeNewExpression(ToVisit).Arguments)); - for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin - Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); - end; - end; - bntCONDITIONALEXPRESSION:begin - Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); - Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); - Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); - end; - bntUNARYEXPRESSION:begin - Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); - end; - bntUNARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); - end; - bntUNARYPLUSEXPRESSION:begin - Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); - end; - bntUNARYMINUSEXPRESSION:begin - Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); - end; - bntUNARYBITWISENOTEXPRESSION:begin - Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); - end; - bntUNARYLOGICALNOTEXPRESSION:begin - Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); - end; - bntUNARYVOIDEXPRESSION:begin - Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); - end; - bntUNARYTYPEOFEXPRESSION:begin - Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); - end; - bntPROPERTYEXPRESSION:begin - WriteBool(TBESENASTNodePropertyExpression(ToVisit).Dot); - Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); - end; - bntLOGICALANDEXPRESSION:begin - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); - end; - bntLOGICALOREXPRESSION:begin - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); - end; - bntDELETEEXPRESSION:begin - Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); - end; - bntPOSTFIXINCEXPRESSION:begin - Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); - end; - bntPOSTFIXDECEXPRESSION:begin - Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); - end; - bntPREFIXINCEXPRESSION:begin - Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); - end; - bntPREFIXDECEXPRESSION:begin - Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); - end; - bntNULLLITERAL:begin - end; - bntNUMBERLITERAL:begin - WriteDouble(TBESENASTNodeNumberLiteral(ToVisit).Value); - end; - bntREGEXPLITERAL:begin - WriteWideString(TBESENASTNodeRegExpLiteral(ToVisit).Source); - WriteWideString(TBESENASTNodeRegExpLiteral(ToVisit).Flags); - end; - bntSTRINGLITERAL:begin - WriteWideString(TBESENASTNodeStringLiteral(ToVisit).Value); - end; - bntTHISLITERAL:begin - end; - bntOBJECTLITERALPROPERTY:begin - WriteWideString(TBESENASTNodeObjectLiteralProperty(ToVisit).Name); - WriteInt32(integer(TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType)); - WriteInt32(integer(TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType)); - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); - WriteBool(assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container)); - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); - end; - end; - bntOBJECTLITERAL:begin - WriteInt32(length(TBESENASTNodeObjectLiteral(ToVisit).Properties)); - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); - end; - end; - bntRETURNSTATEMENT:begin - Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); - end; - bntPROGRAM:begin - Visit(TBESENASTNodeProgram(ToVisit).Body); - end; - bntFUNCTIONEXPRESSION:begin - WriteBool(assigned(TBESENASTNodeFunctionExpression(ToVisit).Container)); - if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); - end; - end; - end; - end; - end; -var Counter:integer; -begin - VisitedNodes:=TBESENPointerSelfBalancedTree.Create; - try - WriteInt64(BESENCodeFormatRevisionNumber); - WriteInt32(TBESEN(Instance).KeyIDManager.List.Count); - for Counter:=0 to TBESEN(Instance).KeyIDManager.List.Count-1 do begin - WriteWideString(TBESEN(Instance).KeyIDManager.List[Counter]); - end; - Visit(RootNode); - finally - BESENFreeAndNil(VisitedNodes); - end; -end; - -end. diff --git a/3rd/besen/src/BESENCollector.pas b/3rd/besen/src/BESENCollector.pas deleted file mode 100644 index 4f91d3e42..000000000 --- a/3rd/besen/src/BESENCollector.pas +++ /dev/null @@ -1,73 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCollector; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENBaseObject,BESENCollectorObject; - -type TBESENCollector=class(TBESENBaseObject) - public - First,Last:TBESENCollectorObject; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Clear; - end; - -implementation - -uses BESEN; - -constructor TBESENCollector.Create(AInstance:TObject); -begin - inherited Create(AInstance); - First:=nil; - Last:=nil; -end; - -destructor TBESENCollector.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENCollector.Clear; -begin - while assigned(First) do begin - First.Free; - end; - First:=nil; - Last:=nil; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENCollectorObject.pas b/3rd/besen/src/BESENCollectorObject.pas deleted file mode 100644 index 6523d33f7..000000000 --- a/3rd/besen/src/BESENCollectorObject.pas +++ /dev/null @@ -1,80 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCollectorObject; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENBaseObject; - -type TBESENCollectorObject=class(TBESENBaseObject) - public - CollectorPrevious,CollectorNext:TBESENCollectorObject; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - -implementation - -uses BESEN; - -constructor TBESENCollectorObject.Create(AInstance:TObject); -begin - inherited Create; - Instance:=AInstance; - CollectorPrevious:=TBESEN(Instance).Collector.Last; - CollectorNext:=nil; - if assigned(CollectorPrevious) then begin - CollectorPrevious.CollectorNext:=self; - end else begin - TBESEN(Instance).Collector.First:=self; - end; - TBESEN(Instance).Collector.Last:=self; -end; - -destructor TBESENCollectorObject.Destroy; -begin - if assigned(CollectorPrevious) then begin - CollectorPrevious.CollectorNext:=CollectorNext; - end else if TBESEN(Instance).Collector.First=self then begin - TBESEN(Instance).Collector.First:=CollectorNext; - end; - if assigned(CollectorNext) then begin - CollectorNext.CollectorPrevious:=CollectorPrevious; - end else if TBESEN(Instance).Collector.Last=self then begin - TBESEN(Instance).Collector.Last:=CollectorPrevious; - end; - CollectorNext:=nil; - CollectorPrevious:=nil; - inherited Destroy; -end; - -end. diff --git a/3rd/besen/src/BESENCompiler.pas b/3rd/besen/src/BESENCompiler.pas deleted file mode 100644 index 31fe5c132..000000000 --- a/3rd/besen/src/BESENCompiler.pas +++ /dev/null @@ -1,6597 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENCompiler; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, - BESENEvalCacheItem; - -type TBESENCompiler=class(TBESENBaseObject) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function Compile(InputSource:TBESENUTF8STRING;const Parameters:TBESENUTF8STRING='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; - end; - -implementation - -uses BESEN,BESENUtils,BESENPointerList,BESENHashMap,BESENErrors,BESENNumberUtils, - BESENCode,BESENCodeGeneratorContext,BESENOpcodes,BESENHashUtils,BESENGlobals, - BESENParser; - -const bcgtUNDEFINED=$01; - bcgtNULL=$02; - bcgtBOOLEAN=$04; - bcgtNUMBER=$08; - bcgtSTRING=$10; - bcgtOBJECT=$20; - bcgtREFERENCE=$40; - bcgtPRIMITIVE=bcgtUNDEFINED or bcgtNULL or bcgtBOOLEAN or bcgtNUMBER or bcgtSTRING; - bcgtVALUE=bcgtPRIMITIVE or bcgtOBJECT; - -function sar(Value,Shift:integer):integer; -{$ifdef PurePascal}{$ifdef caninline}inline;{$endif} -begin -{$ifdef HasSAR} - result:=SARLongint(Value,Shift); -{$else} - Shift:=Shift and 31; - result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); -{$endif} -end; -{$else} -{$ifdef HasSAR} inline; -begin -result:=SARLongint(Value,Shift); -end; -{$else} -{$ifdef cpu386} -{$ifdef fpc} assembler; register; //inline; -asm - mov ecx,edx - sar eax,cl -end;// ['eax','edx','ecx']; -{$else} assembler; register; -asm - mov ecx,edx - sar eax,cl -end; -{$endif} -{$else} -{$ifdef cpuarm} assembler; //inline; -asm - mov r0,r0,asr R1 -end;// ['r0','R1']; -{$else}{$ifdef caninline}inline;{$endif} -begin -{$ifdef HasSAR} - result:=SARLongint(Value,Shift); -{$else} - Shift:=Shift and 31; - result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); -{$endif} -end; -{$endif} -{$endif} -{$endif} -{$endif} - -constructor TBESENCompiler.Create(AInstance:TObject); -begin - inherited Create(AInstance); -end; - -destructor TBESENCompiler.Destroy; -begin - inherited Destroy; -end; - -function TBESENCompiler.Compile(InputSource:TBESENUTF8STRING;const Parameters:TBESENUTF8STRING='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; - function ConvertToValue(n:TBESENASTNode;var v:TBESENValue):boolean; - begin - case n.NodeType of - bntBOOLEANLITERAL:begin - v.ValueType:=bvtBOOLEAN; - v.Bool:=TBESENASTNodeBooleanLiteral(n).Value; - result:=true; - end; - bntNUMBERLITERAL:begin - v.ValueType:=bvtNUMBER; - v.Num:=TBESENASTNodeNumberLiteral(n).Value; - result:=true; - end; - bntSTRINGLITERAL:begin - v.ValueType:=bvtSTRING; - v.Str:=TBESENASTNodeStringLiteral(n).Value; - result:=true; - end; - else begin - v.ValueType:=bvtNONE; - result:=false; - end; - end; - end; - procedure TrimStuffAfterReturnBreakContinue(Node:TBESENASTNode;var Statements:TBESENASTNodeStatements); - var Counter,NewCount,TrimmedCounter:integer; - Statement:TBESENASTNodeStatement; - begin - NewCount:=length(Statements); - for Counter:=0 to length(Statements)-1 do begin - Statement:=Statements[Counter]; - if assigned(Statement) then begin - case Statement.NodeType of - bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT:begin - NewCount:=Counter+1; - break; - end; - end; - end; - end; - if NewCount<>length(Statements) then begin - TrimmedCounter:=Node.CountTrashNodes; - inc(Node.CountTrashNodes,length(Statements)-NewCount); - if Node.CountTrashNodes>=length(Node.TrashNodes) then begin - SetLength(Node.TrashNodes,Node.CountTrashNodes+256); - end; - for Counter:=NewCount to length(Statements)-1 do begin - Node.TrashNodes[TrimmedCounter]:=Statements[Counter]; - inc(TrimmedCounter); - end; - SetLength(Statements,NewCount); - end; - end; - procedure AddTrashNode(Node,TrashNode:TBESENASTNode); - var Index:integer; - begin - if assigned(Node) and assigned(TrashNode) then begin - Index:=Node.CountTrashNodes; - inc(Node.CountTrashNodes); - if Node.CountTrashNodes>=length(Node.TrashNodes) then begin - SetLength(Node.TrashNodes,Node.CountTrashNodes+256); - end; - Node.TrashNodes[Index]:=TrashNode; - TrashNode:=nil; - end; - end; - function IsLastNodeBreakContinueReturnNode(const Statements:TBESENASTNodeStatements):boolean; - var Counter:integer; - Statement:TBESENASTNodeStatement; - begin - result:=false; - for Counter:=length(Statements)-1 downto 0 do begin - Statement:=Statements[Counter]; - if assigned(Statement) then begin - result:=Statement.NodeType in [bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT]; - break; - end; - end; - end; - function IsBreakContinueReturnNode(Node:TBESENASTNode):boolean; - begin - result:=false; - if assigned(Node) then begin - case Node.NodeType of - bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT:begin - result:=true; - end; - bntBLOCKSTATEMENT:begin - result:=IsLastNodeBreakContinueReturnNode(TBESENASTNodeBlockStatement(Node).Statements); - end; - end; - end; - end; - function HasLabelBreakContinue(RootNode:TBESENASTNode):boolean; - var HasResult:boolean; - procedure Visit(ToVisit:TBESENASTNode); - var Counter:integer; - begin - if assigned(ToVisit) and not HasResult then begin - if ToVisit is TBESENASTNodeStatement then begin - if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin - TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; - end; - end; - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - end; - bntLITERAL:begin - end; - bntIDENTIFIER:begin - end; - bntVARIABLEDECLARATION:begin - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); - end; - bntVARIABLEEXPRESSION:begin - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONBODY:begin - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); - end; - end; - bntFUNCTIONLITERAL:begin - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); - end; - bntSTATEMENT:begin - end; - bntVARIABLESTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONDECLARATION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); - end; - end; - bntEXPRESSIONSTATEMENT:begin - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); - end; - bntEMPTYSTATEMENT:begin - end; - bntBLOCKSTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); - end; - end; - bntDEBUGGERSTATEMENT:begin - end; - bntBREAKSTATEMENT:begin - Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); - if assigned(TBESENASTNodeBreakStatement(ToVisit).Identifier) then begin - HasResult:=true; - end; - end; - bntCONTINUESTATEMENT:begin - Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); - if assigned(TBESENASTNodeContinueStatement(ToVisit).Identifier) then begin - HasResult:=true; - end; - end; - bntDOSTATEMENT:begin - Visit(TBESENASTNodeDoStatement(ToVisit).Statement); - Visit(TBESENASTNodeDoStatement(ToVisit).Expression); - end; - bntWHILESTATEMENT:begin - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); - end; - bntWITHSTATEMENT:begin - Visit(TBESENASTNodeWithStatement(ToVisit).Expression); - Visit(TBESENASTNodeWithStatement(ToVisit).Statement); - end; - bntFORSTATEMENT:begin - Visit(TBESENASTNodeForStatement(ToVisit).Initial); - Visit(TBESENASTNodeForStatement(ToVisit).Condition); - Visit(TBESENASTNodeForStatement(ToVisit).Increment); - Visit(TBESENASTNodeForStatement(ToVisit).Statement); - end; - bntFORINSTATEMENT:begin - Visit(TBESENASTNodeForInStatement(ToVisit).Variable); - Visit(TBESENASTNodeForInStatement(ToVisit).Expression); - Visit(TBESENASTNodeForInStatement(ToVisit).Statement); - end; - bntIFSTATEMENT:begin - Visit(TBESENASTNodeIfStatement(ToVisit).Expression); - Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); - Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); - end; - bntLABELLEDSTATEMENT:begin - HasResult:=true; - for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin - Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); - end; - Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); - end; - bntCASESTATEMENT:begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); - end; - end; - bntSWITCHSTATEMENT:begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); - end; - end; - bntTHROWSTATEMENT:begin - Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); - end; - bntTRYSTATEMENT:begin - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); - Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); - end; - bntARRAYLITERAL:begin - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin - Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); - end; - end; - end; - bntBINARYEXPRESSION:begin - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); - end; - bntBINARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); - end; - bntBINARYCOMMAEXPRESSION:begin - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); - end; - bntBINARYDIVIDEEXPRESSION:begin - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); - end; - bntBINARYMODULOEXPRESSION:begin - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); - end; - bntBINARYMULTIPLYEXPRESSION:begin - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); - end; - bntBINARYPLUSEXPRESSION:begin - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); - end; - bntBINARYMINUSEXPRESSION:begin - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); - end; - bntBINARYGREATERTHANEXPRESSION:begin - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); - end; - bntBINARYLESSTHANEXPRESSION:begin - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); - end; - bntBINARYINSTANCEOFEXPRESSION:begin - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); - end; - bntBINARYINEXPRESSION:begin - Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); - end; - bntBINARYEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYNOTEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEANDEXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEXOREXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEOREXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); - end; - bntBOOLEANLITERAL:begin - end; - bntCALLEXPRESSION:begin - Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); - end; - end; - bntNEWEXPRESSION:begin - Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); - for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin - Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); - end; - end; - bntCONDITIONALEXPRESSION:begin - Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); - Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); - Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); - end; - bntUNARYEXPRESSION:begin - Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); - end; - bntUNARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); - end; - bntUNARYPLUSEXPRESSION:begin - Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); - end; - bntUNARYMINUSEXPRESSION:begin - Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); - end; - bntUNARYBITWISENOTEXPRESSION:begin - Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); - end; - bntUNARYLOGICALNOTEXPRESSION:begin - Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); - end; - bntUNARYVOIDEXPRESSION:begin - Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); - end; - bntUNARYTYPEOFEXPRESSION:begin - Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); - end; - bntPROPERTYEXPRESSION:begin - Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); - end; - bntLOGICALANDEXPRESSION:begin - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); - end; - bntLOGICALOREXPRESSION:begin - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); - end; - bntDELETEEXPRESSION:begin - Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); - end; - bntPOSTFIXINCEXPRESSION:begin - Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); - end; - bntPOSTFIXDECEXPRESSION:begin - Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); - end; - bntPREFIXINCEXPRESSION:begin - Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); - end; - bntPREFIXDECEXPRESSION:begin - Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); - end; - bntNULLLITERAL:begin - end; - bntNUMBERLITERAL:begin - end; - bntREGEXPLITERAL:begin - end; - bntSTRINGLITERAL:begin - end; - bntTHISLITERAL:begin - end; - bntOBJECTLITERALPROPERTY:begin - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); - end; - end; - bntOBJECTLITERAL:begin - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); - end; - end; - bntRETURNSTATEMENT:begin - Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); - end; - bntPROGRAM:begin - Visit(TBESENASTNodeProgram(ToVisit).Body); - end; - bntFUNCTIONEXPRESSION:begin - if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); - end; - end; - end; - end; - end; - begin - HasResult:=false; - Visit(RootNode); - result:=HasResult; - end; - procedure CheckNodeForFeatures(RootNode:TBESENASTNode;var HasLocalDelete,IsComplexFunction,HasMaybeDirectEval,HasFunctions,HoldLocalVariablesInRegisters:boolean); - procedure Visit(ToVisit:TBESENASTNode); - var Counter:integer; - begin - if assigned(ToVisit) then begin - if ToVisit is TBESENASTNodeStatement then begin - if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin - TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; - end; - end; - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - end; - bntLITERAL:begin - end; - bntIDENTIFIER:begin - if (TBESENASTNodeIdentifier(ToVisit).Name='eval') or (TBESENASTNodeIdentifier(ToVisit).Name='arguments') then begin - if TBESENASTNodeIdentifier(ToVisit).Name='eval' then begin - HasMaybeDirectEval:=true; - end; - IsComplexFunction:=true; - HoldLocalVariablesInRegisters:=false; - end; - end; - bntVARIABLEDECLARATION:begin - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); - end; - bntVARIABLEEXPRESSION:begin - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONBODY:begin - IsComplexFunction:=true; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); - end; - end; - bntFUNCTIONLITERAL:begin - IsComplexFunction:=true; - HasFunctions:=true; - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); - end; - bntSTATEMENT:begin - end; - bntVARIABLESTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONDECLARATION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); - end; - end; - bntEXPRESSIONSTATEMENT:begin - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); - end; - bntEMPTYSTATEMENT:begin - end; - bntBLOCKSTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); - end; - end; - bntDEBUGGERSTATEMENT:begin - end; - bntBREAKSTATEMENT:begin - Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); - end; - bntCONTINUESTATEMENT:begin - Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); - end; - bntDOSTATEMENT:begin - Visit(TBESENASTNodeDoStatement(ToVisit).Statement); - Visit(TBESENASTNodeDoStatement(ToVisit).Expression); - end; - bntWHILESTATEMENT:begin - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); - end; - bntWITHSTATEMENT:begin - HoldLocalVariablesInRegisters:=false; - Visit(TBESENASTNodeWithStatement(ToVisit).Expression); - Visit(TBESENASTNodeWithStatement(ToVisit).Statement); - end; - bntFORSTATEMENT:begin - Visit(TBESENASTNodeForStatement(ToVisit).Initial); - Visit(TBESENASTNodeForStatement(ToVisit).Condition); - Visit(TBESENASTNodeForStatement(ToVisit).Increment); - Visit(TBESENASTNodeForStatement(ToVisit).Statement); - end; - bntFORINSTATEMENT:begin - Visit(TBESENASTNodeForInStatement(ToVisit).Variable); - Visit(TBESENASTNodeForInStatement(ToVisit).Expression); - Visit(TBESENASTNodeForInStatement(ToVisit).Statement); - end; - bntIFSTATEMENT:begin - Visit(TBESENASTNodeIfStatement(ToVisit).Expression); - Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); - Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); - end; - bntLABELLEDSTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin - Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); - end; - Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); - end; - bntCASESTATEMENT:begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); - end; - end; - bntSWITCHSTATEMENT:begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); - end; - end; - bntTHROWSTATEMENT:begin - Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); - end; - bntTRYSTATEMENT:begin - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); - Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); - HoldLocalVariablesInRegisters:=false; - end; - bntARRAYLITERAL:begin - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin - Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); - end; - end; - end; - bntBINARYEXPRESSION:begin - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); - end; - bntBINARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); - end; - bntBINARYCOMMAEXPRESSION:begin - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); - end; - bntBINARYDIVIDEEXPRESSION:begin - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); - end; - bntBINARYMODULOEXPRESSION:begin - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); - end; - bntBINARYMULTIPLYEXPRESSION:begin - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); - end; - bntBINARYPLUSEXPRESSION:begin - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); - end; - bntBINARYMINUSEXPRESSION:begin - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); - end; - bntBINARYGREATERTHANEXPRESSION:begin - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); - end; - bntBINARYLESSTHANEXPRESSION:begin - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); - end; - bntBINARYINSTANCEOFEXPRESSION:begin - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); - end; - bntBINARYINEXPRESSION:begin - Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); - end; - bntBINARYEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYNOTEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEANDEXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEXOREXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); - end; - bntBINARYBITWISEOREXPRESSION:begin - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); - end; - bntBOOLEANLITERAL:begin - end; - bntCALLEXPRESSION:begin - Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); - end; - end; - bntNEWEXPRESSION:begin - Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); - for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin - Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); - end; - end; - bntCONDITIONALEXPRESSION:begin - Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); - Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); - Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); - end; - bntUNARYEXPRESSION:begin - Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); - end; - bntUNARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); - end; - bntUNARYPLUSEXPRESSION:begin - Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); - end; - bntUNARYMINUSEXPRESSION:begin - Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); - end; - bntUNARYBITWISENOTEXPRESSION:begin - Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); - end; - bntUNARYLOGICALNOTEXPRESSION:begin - Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); - end; - bntUNARYVOIDEXPRESSION:begin - Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); - end; - bntUNARYTYPEOFEXPRESSION:begin - Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); - end; - bntPROPERTYEXPRESSION:begin - Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); - end; - bntLOGICALANDEXPRESSION:begin - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); - end; - bntLOGICALOREXPRESSION:begin - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); - end; - bntDELETEEXPRESSION:begin - IsComplexFunction:=true; - HoldLocalVariablesInRegisters:=false; - Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); - if assigned(TBESENASTNodeDeleteExpression(ToVisit).SubExpression) and (TBESENASTNodeDeleteExpression(ToVisit).SubExpression.NodeType=bntIDENTIFIER) then begin - HasLocalDelete:=true; - end; - end; - bntPOSTFIXINCEXPRESSION:begin - Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); - end; - bntPOSTFIXDECEXPRESSION:begin - Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); - end; - bntPREFIXINCEXPRESSION:begin - Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); - end; - bntPREFIXDECEXPRESSION:begin - Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); - end; - bntNULLLITERAL:begin - end; - bntNUMBERLITERAL:begin - end; - bntREGEXPLITERAL:begin - end; - bntSTRINGLITERAL:begin - end; - bntTHISLITERAL:begin - end; - bntOBJECTLITERALPROPERTY:begin - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); - end; - end; - bntOBJECTLITERAL:begin - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); - end; - end; - bntRETURNSTATEMENT:begin - Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); - end; - bntPROGRAM:begin - IsComplexFunction:=true; - HoldLocalVariablesInRegisters:=false; - Visit(TBESENASTNodeProgram(ToVisit).Body); - end; - bntFUNCTIONEXPRESSION:begin - IsComplexFunction:=true; - if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); - end; - end; - end; - end; - end; - begin - Visit(RootNode); - end; - procedure ScanCollectAndPreprocess(RootNode:TBESENASTNode); - var Functions:TBESENPointerList; - Variables:TBESENPointerList; - VariableHashMap:TBESENHashMap; - AreLocalsOptimizable,IsFunction,IsMaybeArgumentsObjectUsed:boolean; - FunctionLiteral:TBESENASTNodeFunctionLiteral; - procedure AddVariable(Identifier:TBESENASTNodeIdentifier;IsParameter:boolean;ParameterIndex:integer); - var Item:PBESENHashMapItem; - begin - if assigned(Variables) then begin - Item:=VariableHashMap.GetKey(Identifier.Name); - if not assigned(Item) then begin - Item:=VariableHashMap.NewKey(Identifier.Name,true); - Item^.Value:=Variables.Add(Identifier); - Identifier.Index:=Item^.Value; - Identifier.IsParameter:=IsParameter; - Identifier.ParameterIndex:=ParameterIndex; - end; - end; - end; - function Visit(ToVisit:TBESENASTNode):TBESENASTNode; - var Counter,NonEmptyStatementCount:integer; - OldFunctions:TBESENPointerList; - OldVariables:TBESENPointerList; - OldVariableHashMap:TBESENHashMap; - OldAreLocalsOptimizable,OldIsFunction,OldIsMaybeArgumentsObjectUsed,OldIsStrict:boolean; - OldFunctionLiteral:TBESENASTNodeFunctionLiteral; - begin - result:=ToVisit; - if assigned(ToVisit) then begin - if ToVisit is TBESENASTNodeStatement then begin - if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin - TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; - end; - end; - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - end; - bntLITERAL:begin - end; - bntIDENTIFIER:begin - TBESENASTNodeIdentifier(ToVisit).ID:=TBESEN(Instance).KeyIDManager.Get(TBESENASTNodeIdentifier(ToVisit).Name); - if (TBESENASTNodeIdentifier(ToVisit).Name='eval') or (TBESENASTNodeIdentifier(ToVisit).Name='arguments') then begin - IsMaybeArgumentsObjectUsed:=true; - end; - end; - bntVARIABLEDECLARATION:begin - TBESENASTNodeVariableDeclaration(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier)); - TBESENASTNodeVariableDeclaration(ToVisit).Expression:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression)); - AddVariable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,false,-1); - end; - bntVARIABLEEXPRESSION:begin - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter])); - end; - end; - bntFUNCTIONBODY:begin - OldFunctions:=Functions; - OldVariables:=Variables; - OldVariableHashMap:=VariableHashMap; - OldAreLocalsOptimizable:=AreLocalsOptimizable; - OldIsStrict:=TBESEN(Instance).IsStrict; - Functions:=TBESENPointerList.Create; - Variables:=TBESENPointerList.Create; - VariableHashMap:=TBESENHashMap.Create; - try - TBESEN(Instance).IsStrict:=TBESENASTNodeFunctionBody(ToVisit).IsStrict; - AreLocalsOptimizable:=true; - if IsFunction and assigned(FunctionLiteral) then begin - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter])); - AddVariable(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter],true,Counter); - end; - end; - NonEmptyStatementCount:=0; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter])); - if assigned(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]) and (TBESENASTNodeFunctionBody(ToVisit).Statements[Counter].NodeType<>bntEMPTYSTATEMENT) then begin - inc(NonEmptyStatementCount); - end; - end; - SetLength(TBESENASTNodeFunctionBody(ToVisit).Functions,Functions.Count); - for Counter:=0 to Functions.Count-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]:=Functions[Counter]; - end; - SetLength(TBESENASTNodeFunctionBody(ToVisit).Variables,Variables.Count); - for Counter:=0 to Variables.Count-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]:=Variables[Counter]; - end; - TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization:=IsFunction and AreLocalsOptimizable; - TBESENASTNodeFunctionBody(ToVisit).DisableArgumentsObject:=not (IsFunction and IsMaybeArgumentsObjectUsed); - TBESENASTNodeFunctionBody(ToVisit).IsEmpty:=NonEmptyStatementCount=0; - finally - BESENFreeAndNil(Functions); - BESENFreeAndNil(Variables); - BESENFreeAndNil(VariableHashMap); - Functions:=OldFunctions; - Variables:=OldVariables; - VariableHashMap:=OldVariableHashMap; - TBESEN(Instance).IsStrict:=OldIsStrict; - AreLocalsOptimizable:=OldAreLocalsOptimizable; - end; - end; - bntFUNCTIONLITERAL:begin - OldIsFunction:=IsFunction; - OldFunctionLiteral:=FunctionLiteral; - OldIsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; - IsMaybeArgumentsObjectUsed:=false; - IsFunction:=true; - FunctionLiteral:=TBESENASTNodeFunctionLiteral(ToVisit); - TBESENASTNodeFunctionLiteral(ToVisit).Body:=pointer(Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body)); - FunctionLiteral:=OldFunctionLiteral; - IsFunction:=OldIsFunction; - IsMaybeArgumentsObjectUsed:=OldIsMaybeArgumentsObjectUsed; - end; - bntSTATEMENT:begin - end; - bntVARIABLESTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter])); - end; - end; - bntFUNCTIONDECLARATION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal)); - end; - if assigned(Functions) then begin - Functions.Add(ToVisit); - result:=TBESENASTNodeEmptyStatement.Create(Instance); - TBESENASTNodeEmptyStatement(result).Location.LineNumber:=TBESENASTNodeFunctionDeclaration(ToVisit).Location.LineNumber; - end; - end; - bntEXPRESSIONSTATEMENT:begin - TBESENASTNodeExpressionStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression)); - end; - bntEMPTYSTATEMENT:begin - end; - bntBLOCKSTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter])); - end; - end; - bntDEBUGGERSTATEMENT:begin - end; - bntBREAKSTATEMENT:begin - TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); - end; - bntCONTINUESTATEMENT:begin - TBESENASTNodeContinueStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier)); - end; - bntDOSTATEMENT:begin - TBESENASTNodeDoStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Statement)); - TBESENASTNodeDoStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Expression)); - end; - bntWHILESTATEMENT:begin - TBESENASTNodeWhileStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Expression)); - TBESENASTNodeWhileStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Statement)); - end; - bntWITHSTATEMENT:begin - if TBESEN(Instance).IsStrict then begin - raise EBESENSyntaxError.Create('"with" not allowed here'); - end; - TBESENASTNodeWithStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Expression)); - TBESENASTNodeWithStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Statement)); - end; - bntFORSTATEMENT:begin - TBESENASTNodeForStatement(ToVisit).Initial:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Initial)); - TBESENASTNodeForStatement(ToVisit).Condition:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Condition)); - TBESENASTNodeForStatement(ToVisit).Increment:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Increment)); - TBESENASTNodeForStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Statement)); - end; - bntFORINSTATEMENT:begin - TBESENASTNodeForInStatement(ToVisit).Variable:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Variable)); - TBESENASTNodeForInStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Expression)); - TBESENASTNodeForInStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Statement)); - end; - bntIFSTATEMENT:begin - TBESENASTNodeIfStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).Expression)); - TBESENASTNodeIfStatement(ToVisit).TrueStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement)); - TBESENASTNodeIfStatement(ToVisit).FalseStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement)); - end; - bntLABELLEDSTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin - TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter])); - end; - TBESENASTNodeLabelledStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement)); - end; - bntCASESTATEMENT:begin - TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter])); - end; - end; - bntSWITCHSTATEMENT:begin - TBESENASTNodeSwitchStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression)); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter])); - end; - end; - bntTHROWSTATEMENT:begin - TBESENASTNodeThrowStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeThrowStatement(ToVisit).Expression)); - end; - bntTRYSTATEMENT:begin - TBESENASTNodeTryStatement(ToVisit).TryBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock)); - TBESENASTNodeTryStatement(ToVisit).CatchIdentifier:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier)); - TBESENASTNodeTryStatement(ToVisit).CatchBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock)); - TBESENASTNodeTryStatement(ToVisit).FinallyBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock)); - end; - bntARRAYLITERAL:begin - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin - TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]:=pointer(Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter])); - end; - end; - end; - bntBINARYEXPRESSION:begin - TBESENASTNodeBinaryExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTEXPRESSION:begin - TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression)); - end; - bntBINARYOPERATOREXPRESSION:begin - TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression)); - end; - bntBINARYCOMMAEXPRESSION:begin - TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression)); - end; - bntBINARYDIVIDEEXPRESSION:begin - TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression)); - end; - bntBINARYMODULOEXPRESSION:begin - TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression)); - end; - bntBINARYMULTIPLYEXPRESSION:begin - TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression)); - end; - bntBINARYPLUSEXPRESSION:begin - TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression)); - end; - bntBINARYMINUSEXPRESSION:begin - TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression)); - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression)); - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression)); - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression)); - end; - bntBINARYGREATERTHANEXPRESSION:begin - TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression)); - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression)); - end; - bntBINARYLESSTHANEXPRESSION:begin - TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression)); - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression)); - end; - bntBINARYINSTANCEOFEXPRESSION:begin - TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression)); - end; - bntBINARYINEXPRESSION:begin - TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryInExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression)); - end; - bntBINARYEQUALEQUALEXPRESSION:begin - TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression)); - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression)); - end; - bntBINARYNOTEQUALEXPRESSION:begin - TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression)); - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression)); - end; - bntBINARYBITWISEANDEXPRESSION:begin - TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression)); - end; - bntBINARYBITWISEXOREXPRESSION:begin - TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression)); - end; - bntBINARYBITWISEOREXPRESSION:begin - TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression)); - end; - bntBOOLEANLITERAL:begin - end; - bntCALLEXPRESSION:begin - TBESENASTNodeCallExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction)); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter])); - end; - end; - bntNEWEXPRESSION:begin - TBESENASTNodeNewExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction)); - for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin - TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter])); - end; - end; - bntCONDITIONALEXPRESSION:begin - TBESENASTNodeConditionalExpression(ToVisit).Expression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression)); - TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression)); - TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression)); - end; - bntUNARYEXPRESSION:begin - TBESENASTNodeUnaryExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression)); - end; - bntUNARYOPERATOREXPRESSION:begin - TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression)); - end; - bntUNARYPLUSEXPRESSION:begin - TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression)); - end; - bntUNARYMINUSEXPRESSION:begin - TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression)); - end; - bntUNARYBITWISENOTEXPRESSION:begin - TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression)); - end; - bntUNARYLOGICALNOTEXPRESSION:begin - TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression)); - end; - bntUNARYVOIDEXPRESSION:begin - TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression)); - end; - bntUNARYTYPEOFEXPRESSION:begin - TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression)); - end; - bntPROPERTYEXPRESSION:begin - TBESENASTNodePropertyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression)); - TBESENASTNodePropertyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression)); - end; - bntLOGICALANDEXPRESSION:begin - TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression)); - TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression)); - end; - bntLOGICALOREXPRESSION:begin - TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression)); - TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression)); - end; - bntDELETEEXPRESSION:begin - TBESENASTNodeDeleteExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression)); - end; - bntPOSTFIXINCEXPRESSION:begin - TBESENASTNodePostfixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression)); - end; - bntPOSTFIXDECEXPRESSION:begin - TBESENASTNodePostfixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression)); - end; - bntPREFIXINCEXPRESSION:begin - TBESENASTNodePrefixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression)); - end; - bntPREFIXDECEXPRESSION:begin - TBESENASTNodePrefixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression)); - end; - bntNULLLITERAL:begin - end; - bntNUMBERLITERAL:begin - end; - bntREGEXPLITERAL:begin - end; - bntSTRINGLITERAL:begin - end; - bntTHISLITERAL:begin - end; - bntOBJECTLITERALPROPERTY:begin - TBESENASTNodeObjectLiteralProperty(ToVisit).Value:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value)); - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal)); - end; - end; - bntOBJECTLITERAL:begin - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]:=pointer(Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter])); - end; - end; - bntRETURNSTATEMENT:begin - if not IsFunction then begin - raise EBESENSyntaxError.Create('Return outside a function'); - end; - TBESENASTNodeReturnStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeReturnStatement(ToVisit).Expression)); - end; - bntPROGRAM:begin - OldIsFunction:=IsFunction; - OldFunctionLiteral:=FunctionLiteral; - OldIsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; - IsFunction:=false; - IsMaybeArgumentsObjectUsed:=false; - FunctionLiteral:=nil; - TBESENASTNodeProgram(ToVisit).Body:=pointer(Visit(TBESENASTNodeProgram(ToVisit).Body)); - FunctionLiteral:=OldFunctionLiteral; - IsFunction:=OldIsFunction; - IsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; - end; - bntFUNCTIONEXPRESSION:begin - if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin - TBESENASTNodeFunctionExpression(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal)); - end; - end; - end; - end; - end; - begin - Functions:=nil; - Variables:=nil; - VariableHashMap:=nil; - AreLocalsOptimizable:=true; - IsFunction:=false; - IsMaybeArgumentsObjectUsed:=false; - FunctionLiteral:=nil; - Visit(RootNode); - end; - function Optimize(RootNode:TBESENASTNode):TBESENASTNode; - var vl,vr:TBESENValue; - function Visit(ToVisit:TBESENASTNode):TBESENASTNode; - var Counter,LastLineNumber:integer; - nr:TBESENNumber; - sr:TBESENString; - br,OldIsStrict:TBESENBoolean; - begin - result:=ToVisit; - if assigned(ToVisit) then begin - if ToVisit is TBESENASTNodeStatement then begin - if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin - TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; - end; - end; - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - end; - bntLITERAL:begin - end; - bntIDENTIFIER:begin - end; - bntVARIABLEDECLARATION:begin - TBESENASTNodeVariableDeclaration(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier)); - TBESENASTNodeVariableDeclaration(ToVisit).Expression:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression)); - end; - bntVARIABLEEXPRESSION:begin - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter])); - end; - end; - bntFUNCTIONBODY:begin - OldIsStrict:=TBESEN(Instance).IsStrict; - try - TBESEN(Instance).IsStrict:=TBESENASTNodeFunctionBody(ToVisit).IsStrict; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter])); - end; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter])); - end; - TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeFunctionBody(ToVisit).Statements); - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter])); - end; - finally - TBESEN(Instance).IsStrict:=OldIsStrict; - end; - end; - bntFUNCTIONLITERAL:begin - TBESENASTNodeFunctionLiteral(ToVisit).Body:=pointer(Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body)); - end; - bntSTATEMENT:begin - end; - bntVARIABLESTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter])); - end; - end; - bntFUNCTIONDECLARATION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal)); - end; - end; - bntEXPRESSIONSTATEMENT:begin - TBESENASTNodeExpressionStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression)); - end; - bntEMPTYSTATEMENT:begin - end; - bntBLOCKSTATEMENT:begin - TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeBlockStatement(ToVisit).Statements); - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter])); - end; - end; - bntDEBUGGERSTATEMENT:begin - end; - bntBREAKSTATEMENT:begin - TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); - end; - bntCONTINUESTATEMENT:begin - TBESENASTNodeContinueStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier)); - end; - bntDOSTATEMENT:begin - TBESENASTNodeDoStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Statement)); - TBESENASTNodeDoStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Expression)); - if ConvertToValue(TBESENASTNodeDoStatement(ToVisit).Expression,vl) then begin - if not TBESEN(Instance).ToBool(vl) then begin - if assigned(TBESENASTNodeDoStatement(ToVisit).Statement) then begin - result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); - AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Expression); - AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Statement); - TBESENASTNodeDoStatement(ToVisit).Statement:=nil; - TBESENASTNodeDoStatement(ToVisit).Expression:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeDoStatement(ToVisit).Statement; - AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Expression); - TBESENASTNodeDoStatement(ToVisit).Statement:=nil; - TBESENASTNodeDoStatement(ToVisit).Expression:=nil; - BESENFreeAndNil(ToVisit); - end; - end; - end; - if not assigned(result) then begin - result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); - end; - end; - bntWHILESTATEMENT:begin - TBESENASTNodeWhileStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Expression)); - TBESENASTNodeWhileStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Statement)); - if ConvertToValue(TBESENASTNodeWhileStatement(ToVisit).Expression,vl) then begin - if not TBESEN(Instance).ToBool(vl) then begin - result:=TBESENASTNodeEmptyStatement.Create(Instance); - TBESENASTNodeEmptyStatement(result).Location.LineNumber:=TBESENASTNodeFunctionDeclaration(ToVisit).Location.LineNumber; - AddTrashNode(result,TBESENASTNodeWhileStatement(ToVisit).Expression); - AddTrashNode(result,TBESENASTNodeWhileStatement(ToVisit).Statement); - TBESENASTNodeWhileStatement(ToVisit).Statement:=nil; - TBESENASTNodeWhileStatement(ToVisit).Expression:=nil; - BESENFreeAndNil(ToVisit); - end; - end; - if not assigned(result) then begin - result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); - end; - end; - bntWITHSTATEMENT:begin - TBESENASTNodeWithStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Expression)); - TBESENASTNodeWithStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Statement)); - end; - bntFORSTATEMENT:begin - TBESENASTNodeForStatement(ToVisit).Initial:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Initial)); - TBESENASTNodeForStatement(ToVisit).Condition:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Condition)); - TBESENASTNodeForStatement(ToVisit).Increment:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Increment)); - TBESENASTNodeForStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Statement)); - end; - bntFORINSTATEMENT:begin - TBESENASTNodeForInStatement(ToVisit).Variable:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Variable)); - TBESENASTNodeForInStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Expression)); - TBESENASTNodeForInStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Statement)); - end; - bntIFSTATEMENT:begin - LastLineNumber:=ToVisit.Location.LineNumber; - TBESENASTNodeIfStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).Expression)); - TBESENASTNodeIfStatement(ToVisit).TrueStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement)); - TBESENASTNodeIfStatement(ToVisit).FalseStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement)); - if ConvertToValue(TBESENASTNodeIfStatement(ToVisit).Expression,vl) then begin - if TBESEN(Instance).ToBool(vl) then begin - if assigned(TBESENASTNodeIfStatement(ToVisit).TrueStatement) then begin - result:=TBESENASTNodeIfStatement(ToVisit).TrueStatement; - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); - TBESENASTNodeIfStatement(ToVisit).Expression:=nil; - TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; - TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeEmptyStatement.Create(Instance); - result.Location.LineNumber:=LastLineNumber; - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); - TBESENASTNodeIfStatement(ToVisit).Expression:=nil; - TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; - TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; - BESENFreeAndNil(ToVisit); - end; - end else begin - if assigned(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin - result:=TBESENASTNodeIfStatement(ToVisit).FalseStatement; - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); - TBESENASTNodeIfStatement(ToVisit).Expression:=nil; - TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; - TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeEmptyStatement.Create(Instance); - result.Location.LineNumber:=LastLineNumber; - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); - AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); - TBESENASTNodeIfStatement(ToVisit).Expression:=nil; - TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; - TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; - BESENFreeAndNil(ToVisit); - end; - end; - end; - if not assigned(result) then begin - result:=TBESENASTNodeEmptyStatement.Create(Instance); - result.Location.LineNumber:=LastLineNumber; - end; - end; - bntLABELLEDSTATEMENT:begin - for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin - TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter])); - end; - TBESENASTNodeLabelledStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement)); - end; - bntCASESTATEMENT:begin - TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); - TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeCaseStatement(ToVisit).Statements); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter])); - end; - end; - bntSWITCHSTATEMENT:begin - TBESENASTNodeSwitchStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression)); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter])); - end; - end; - bntTHROWSTATEMENT:begin - TBESENASTNodeThrowStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeThrowStatement(ToVisit).Expression)); - end; - bntTRYSTATEMENT:begin - TBESENASTNodeTryStatement(ToVisit).TryBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock)); - TBESENASTNodeTryStatement(ToVisit).CatchIdentifier:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier)); - TBESENASTNodeTryStatement(ToVisit).CatchBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock)); - TBESENASTNodeTryStatement(ToVisit).FinallyBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock)); - end; - bntARRAYLITERAL:begin - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin - TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]:=pointer(Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter])); - end; - end; - end; - bntBINARYEXPRESSION:begin - end; - bntASSIGNMENTEXPRESSION:begin - TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression)); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression)); - TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression)); - end; - bntBINARYOPERATOREXPRESSION:begin - TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression)); - end; - bntBINARYCOMMAEXPRESSION:begin - TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression)); - end; - bntBINARYDIVIDEEXPRESSION:begin - TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESEN(Instance).ToNum(vl)/TBESEN(Instance).ToNum(vr); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYMODULOEXPRESSION:begin - TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression,vr) then begin - nr:=BESENModulo(TBESEN(Instance).ToNum(vl),TBESEN(Instance).ToNum(vr)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYMULTIPLYEXPRESSION:begin - TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESEN(Instance).ToNum(vl)*TBESEN(Instance).ToNum(vr); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYPLUSEXPRESSION:begin - TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression,vr) then begin - if (TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression is TBESENASTNodeStringLiteral) or (TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral) then begin - sr:=TBESEN(Instance).ToStr(vl)+TBESEN(Instance).ToStr(vr); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeStringLiteral.Create(Instance); - TBESENASTNodeStringLiteral(result).Value:=sr; - end else begin - nr:=TBESEN(Instance).ToNum(vl)+TBESEN(Instance).ToNum(vr); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - end; - bntBINARYMINUSEXPRESSION:begin - TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESEN(Instance).ToNum(vl)-TBESEN(Instance).ToNum(vr); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) shl (TBESEN(Instance).ToUInt32(vr) and 31)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression,vr) then begin - nr:=sar(TBESEN(Instance).ToInt32(vl),(TBESEN(Instance).ToUInt32(vr) and 31)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESENUINT32(TBESEN(Instance).ToUInt32(vl) shr (TBESEN(Instance).ToUInt32(vr) and 31)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYGREATERTHANEXPRESSION:begin - TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)>0; - end; - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)>=0; - end; - end; - bntBINARYLESSTHANEXPRESSION:begin - TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)<0; - end; - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)<=0; - end; - end; - bntBINARYINSTANCEOFEXPRESSION:begin - TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression)); - end; - bntBINARYINEXPRESSION:begin - TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryInExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression)); - end; - bntBINARYEQUALEQUALEXPRESSION:begin - TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionEquals(vl,vr); - end; - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=BESENEqualityExpressionStrictEquals(vl,vr); - end; - end; - bntBINARYNOTEQUALEXPRESSION:begin - TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=not TBESEN(Instance).EqualityExpressionEquals(vl,vr); - end; - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression,vr) then begin - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=not BESENEqualityExpressionStrictEquals(vl,vr); - end; - end; - bntBINARYBITWISEANDEXPRESSION:begin - TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) and TBESEN(Instance).ToInt32(vr)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYBITWISEXOREXPRESSION:begin - TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) xor TBESEN(Instance).ToInt32(vr)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBINARYBITWISEOREXPRESSION:begin - TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression)); - TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression,vr) then begin - nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) or TBESEN(Instance).ToInt32(vr)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntBOOLEANLITERAL:begin - end; - bntCALLEXPRESSION:begin - TBESENASTNodeCallExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction)); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter])); - end; - end; - bntNEWEXPRESSION:begin - TBESENASTNodeNewExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction)); - for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin - TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter])); - end; - end; - bntCONDITIONALEXPRESSION:begin - TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression)); - TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression)); - if ConvertToValue(TBESENASTNodeConditionalExpression(ToVisit).Expression,vl) then begin - if TBESEN(Instance).ToBool(vl) then begin - result:=TBESENASTNodeConditionalExpression(ToVisit).TrueExpression; - TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeConditionalExpression(ToVisit).FalseExpression; - TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=nil; - BESENFreeAndNil(ToVisit); - end; - end; - end; - bntUNARYEXPRESSION:begin - TBESENASTNodeUnaryExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression)); - end; - bntUNARYOPERATOREXPRESSION:begin - TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression)); - end; - bntUNARYPLUSEXPRESSION:begin - TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression)); - if ConvertToValue(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,vl) then begin - nr:=TBESEN(Instance).ToNum(vl); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntUNARYMINUSEXPRESSION:begin - TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression)); - if ConvertToValue(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression,vl) then begin - nr:=TBESEN(Instance).ToNum(vl); - PBESENDoubleHiLo(@nr)^.Hi:=PBESENDoubleHiLo(@nr)^.Hi xor $80000000; - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntUNARYBITWISENOTEXPRESSION:begin - TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression)); - if ConvertToValue(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression,vl) then begin - nr:=TBESENINT32(not TBESEN(Instance).ToInt32(vl)); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeNumberLiteral.Create(Instance); - TBESENASTNodeNumberLiteral(result).Value:=nr; - end; - end; - bntUNARYLOGICALNOTEXPRESSION:begin - TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression)); - if ConvertToValue(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression,vl) then begin - br:=not TBESEN(Instance).ToBool(vl); - BESENFreeAndNil(ToVisit); - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - TBESENASTNodeBooleanLiteral(result).Value:=br; - end; - end; - bntUNARYVOIDEXPRESSION:begin - TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression)); - end; - bntUNARYTYPEOFEXPRESSION:begin - TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression)); - end; - bntPROPERTYEXPRESSION:begin - TBESENASTNodePropertyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression)); - TBESENASTNodePropertyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression)); - end; - bntLOGICALANDEXPRESSION:begin - TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression)); - TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,vl) then begin - ConvertToValue(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,vr); - if vl.ValueType=vr.ValueType then begin - if TBESEN(Instance).ToBool(vr) then begin - result:=TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression; - AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); - TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression; - AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); - TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end; - end else begin - if TBESEN(Instance).ToBool(vl) then begin - result:=TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression; - AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); - TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression; - AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); - TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end; - end; - end; - end; - bntLOGICALOREXPRESSION:begin - TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression)); - TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression)); - if ConvertToValue(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression,vl) then begin - ConvertToValue(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression,vr); - if vl.ValueType=vr.ValueType then begin - if TBESEN(Instance).ToBool(vr) then begin - result:=TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression; - AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); - TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression; - AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); - TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end; - end else begin - if TBESEN(Instance).ToBool(vl) then begin - result:=TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression; - AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); - TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end else begin - result:=TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression; - AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); - TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; - TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; - BESENFreeAndNil(ToVisit); - end; - end; - end; - end; - bntDELETEEXPRESSION:begin - TBESENASTNodeDeleteExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression)); - end; - bntPOSTFIXINCEXPRESSION:begin - TBESENASTNodePostfixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression)); - end; - bntPOSTFIXDECEXPRESSION:begin - TBESENASTNodePostfixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression)); - end; - bntPREFIXINCEXPRESSION:begin - TBESENASTNodePrefixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression)); - end; - bntPREFIXDECEXPRESSION:begin - TBESENASTNodePrefixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression)); - end; - bntNULLLITERAL:begin - end; - bntNUMBERLITERAL:begin - end; - bntREGEXPLITERAL:begin - end; - bntSTRINGLITERAL:begin - end; - bntTHISLITERAL:begin - end; - bntOBJECTLITERALPROPERTY:begin - TBESENASTNodeObjectLiteralProperty(ToVisit).Value:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value)); - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal)); - end; - end; - bntOBJECTLITERAL:begin - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]:=pointer(Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter])); - end; - end; - bntRETURNSTATEMENT:begin - TBESENASTNodeReturnStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeReturnStatement(ToVisit).Expression)); - end; - bntPROGRAM:begin - TBESENASTNodeProgram(ToVisit).Body:=pointer(Visit(TBESENASTNodeProgram(ToVisit).Body)); - end; - bntFUNCTIONEXPRESSION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - TBESENASTNodeFunctionExpression(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal)); - end; - end; - end; - end; - end; - begin - result:=Visit(RootNode); - end; - procedure GenerateByteCode(RootNode:TBESENASTNode); - var Code:TBESENCode; - CodeGeneratorContext:TBESENCodeGeneratorContext; - OptimizeLocals,HasFunctions,DoHasLocalDelete,DoIsComplexFunction,DoHasMaybeDirectEval,DoHoldLocalVariablesInRegisters:boolean; - procedure Visit(ToVisit:TBESENASTNode;var DestRegNr:integer;CalleeNeedReturnedValue:boolean); - var Counter,L1,L2,L3,L3a,L3b,P1,P2,PR,PR2,r1,r2,r3,r4,r5,r6,v1:integer; - OldCode:TBESENCode; - OldCodeGeneratorContext:TBESENCodeGeneratorContext; - v:TBESENValue; - OldVarScope,OldDoHasLocalDelete,OldOptimizeLocals,OldHasFunctions,OldDoIsComplexFunction,OldDoHasMaybeDirectEval,OldDoHoldLocalVariablesInRegisters,DefaultCase,InScope:boolean; - Patchables:TBESENCodeGeneratorContextPatchables; - SwitchPatches:array of integer; - vta,vtb,vtc,vtd,vte,vtTemp,vtBegin,vtInner,vtEnd:TBESENValueTypes; - RegStates:array[0..3] of TBESENCodeGeneratorContextRegisterStates; - Operands:array of TBESENINT32; - hi:PBESENHashMapItem; - Hash:TBESENHash; - IsWhat1,IsWhat2:longword; - function IsValue(const r:integer):boolean; - begin - result:=(CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)=0; - end; - function IsPrimitive(const r:integer):boolean; - begin - result:=(CodeGeneratorContext.Registers[r].IsWhat and (bcgtREFERENCE or bcgtOBJECT))=0; - end; - function IsLocalVariableReference(const r:integer):boolean; - begin - result:=DoHoldLocalVariablesInRegisters and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)); - end; - function IsValueBoolean(const r:integer):boolean; - begin - result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtBOOLEAN) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtBOOLEAN)); - if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin - result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtBOOLEAN; - end; - end; - function IsValueNumber(const r:integer):boolean; - begin - result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtNUMBER) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtNUMBER)); - if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin - result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtNUMBER; - end; - end; - function IsValueString(const r:integer):boolean; - begin - result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtSTRING) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtSTRING)); - if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin - result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtSTRING; - end; - end; - function IsValueObject(const r:integer):boolean; - begin - result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtOBJECT) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtOBJECT)); - if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin - result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtOBJECT; - end; - end; - function IsValuePrimitive(const r:integer):boolean; - begin - result:=((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType in [bvtBOOLEAN,bvtNUMBER,bvtSTRING])) or ((CodeGeneratorContext.Registers[r].IsWhat and (bcgtREFERENCE or bcgtOBJECT))=0); - if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin - result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name) in [bvtBOOLEAN,bvtNUMBER,bvtSTRING]; - end; - end; - function IsNodeLocalVarReg(Node:TBESENASTNode;var r:integer):boolean; - begin - if DoHoldLocalVariablesInRegisters and (assigned(Node) and ((Node is TBESENASTNodeIdentifier) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(Node).Name))) then begin - r:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(Node).Name); - end else begin - r:=-1; - end; - result:=r>=0; - end; - function IsNodeLocalVarRegister(Node:TBESENASTNode):boolean; - begin - result:=(DoHoldLocalVariablesInRegisters and (assigned(Node) and ((Node is TBESENASTNodeIdentifier) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(Node).Name)))) and (CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(Node).Name)>0); - end; - procedure GenSetC(const r:integer); - begin - if IsValueBoolean(r) then begin - Code.GenOp(bopSETCBOOL,r); - end else if IsValueNumber(r) then begin - Code.GenOp(bopSETCNUM,r); - end else if IsValueString(r) then begin - Code.GenOp(bopSETCSTR,r); - end else if IsValueObject(r) then begin - Code.GenOp(bopSETCOBJ,r); - end else begin - if IsLocalVariableReference(r) then begin - Code.GenOp(bopSETC,r); - end else if (CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType in [bvtUNDEFINED,bvtNULL]) then begin - case CodeGeneratorContext.Registers[r].ReferenceValueType of - bvtNULL:begin - Code.GenOp(bopSETCNULL); - end; - else begin - Code.GenOp(bopSETC,r); - end; - end; - end else begin - Code.GenOp(bopSETC,r); - end; - end; - end; - procedure GenGetValueEx(const r,DestRegNr:integer); - begin - if CodeGeneratorContext.Registers[r].Variable>=0 then begin - case CodeGeneratorContext.Registers[r].ReferenceValueType of - bvtBOOLEAN:begin - Code.GenOp(bopCOPYBOOL,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; - end; - bvtNUMBER:begin - Code.GenOp(bopCOPYNUM,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; - end; - bvtSTRING:begin - Code.GenOp(bopCOPYSTR,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; - end; - bvtOBJECT:begin - Code.GenOp(bopCOPYOBJ,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; - end; - else begin - Code.GenOp(bopCOPY,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end; - end else begin - case CodeGeneratorContext.Registers[r].ReferenceValueType of - bvtBOOLEAN:begin - Code.GenOp(bopGETVALUELOCALINDEXBOOL,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; - end; - bvtNUMBER:begin - Code.GenOp(bopGETVALUELOCALINDEXNUM,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; - end; - bvtSTRING:begin - Code.GenOp(bopGETVALUELOCALINDEXSTR,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; - end; - bvtOBJECT:begin - Code.GenOp(bopGETVALUELOCALINDEXOBJ,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; - end; - else begin - Code.GenOp(bopGETVALUELOCALINDEX,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end; - end; - end; - procedure GenPutValueEx(const r,SrcRegNr:integer;ValueType:TBESENValueType=bvtUNDEFINED); - begin - if CodeGeneratorContext.Registers[r].Variable>=0 then begin - case ValueType of - bvtBOOLEAN:begin - Code.GenOp(bopCOPYBOOL,r,SrcRegNr); - end; - bvtNUMBER:begin - Code.GenOp(bopCOPYNUM,r,SrcRegNr); - end; - bvtSTRING:begin - Code.GenOp(bopCOPYSTR,r,SrcRegNr); - end; - bvtOBJECT:begin - Code.GenOp(bopCOPYOBJ,r,SrcRegNr); - end; - else begin - Code.GenOp(bopCOPY,r,SrcRegNr); - end; - end; - end else begin - case ValueType of - bvtBOOLEAN:begin - Code.GenOp(bopPUTVALUELOCALINDEXBOOL,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - bvtNUMBER:begin - Code.GenOp(bopPUTVALUELOCALINDEXNUM,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - bvtSTRING:begin - Code.GenOp(bopPUTVALUELOCALINDEXSTR,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - bvtOBJECT:begin - Code.GenOp(bopPUTVALUELOCALINDEXOBJ,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - else begin - Code.GenOp(bopPUTVALUELOCALINDEX,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - end; - end; - end; - procedure GenGetValue(const r,DestRegNr:integer); - begin - if (CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)<>0 then begin - if CodeGeneratorContext.Registers[r].IsLocal then begin - if CodeGeneratorContext.Registers[r].Variable>=0 then begin - if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin - Code.Restore(Code.LastCodePos); - end; - case CodeGeneratorContext.Registers[r].ReferenceValueType of - bvtBOOLEAN:begin - Code.GenOp(bopCOPYBOOL,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; - end; - bvtNUMBER:begin - Code.GenOp(bopCOPYNUM,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; - end; - bvtSTRING:begin - Code.GenOp(bopCOPYSTR,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; - end; - bvtOBJECT:begin - Code.GenOp(bopCOPYOBJ,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; - end; - else begin - Code.GenOp(bopCOPY,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end; - end else if (not DoHasLocalDelete) and CodeGeneratorContext.VariableGetInitialized(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex)) then begin - if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin - Code.Restore(Code.LastCodePos); - end; - case CodeGeneratorContext.Registers[r].ReferenceValueType of - bvtBOOLEAN:begin - Code.GenOp(bopGETVALUELOCALINDEXBOOL,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; - end; - bvtNUMBER:begin - Code.GenOp(bopGETVALUELOCALINDEXNUM,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; - end; - bvtSTRING:begin - Code.GenOp(bopGETVALUELOCALINDEXSTR,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; - end; - bvtOBJECT:begin - Code.GenOp(bopGETVALUELOCALINDEXOBJ,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; - end; - else begin - Code.GenOp(bopGETVALUELOCALINDEX,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end; - end else begin - Code.GenOp(bopGETVALUELOCAL,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end else begin - Code.GenOp(bopGETVALUEREF,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end else begin - Code.GenOp(bopGETVALUE,DestRegNr,r); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - end; - end; - procedure GenPutValue(const r,SrcRegNr:integer;ValueType:TBESENValueType=bvtUNDEFINED); - begin - if (CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)<>0 then begin - if CodeGeneratorContext.Registers[r].IsLocal then begin - if CodeGeneratorContext.Registers[r].Variable>=0 then begin - if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin - Code.Restore(Code.LastCodePos); - end; - case ValueType of - bvtBOOLEAN:begin - Code.GenOp(bopCOPYBOOL,r,SrcRegNr); - end; - bvtNUMBER:begin - Code.GenOp(bopCOPYNUM,r,SrcRegNr); - end; - bvtSTRING:begin - Code.GenOp(bopCOPYSTR,r,SrcRegNr); - end; - bvtOBJECT:begin - Code.GenOp(bopCOPYOBJ,r,SrcRegNr); - end; - else begin - Code.GenOp(bopCOPY,r,SrcRegNr); - end; - end; - end else if (not DoHasLocalDelete) and (CodeGeneratorContext.VariableGetInitialized(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex)) and - CodeGeneratorContext.VariableGetMutableOrDeletable(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex))) then begin - if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin - Code.Restore(Code.LastCodePos); - end; - case ValueType of - bvtBOOLEAN:begin - Code.GenOp(bopPUTVALUELOCALINDEXBOOL,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - bvtNUMBER:begin - Code.GenOp(bopPUTVALUELOCALINDEXNUM,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - bvtSTRING:begin - Code.GenOp(bopPUTVALUELOCALINDEXSTR,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - bvtOBJECT:begin - Code.GenOp(bopPUTVALUELOCALINDEXOBJ,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - else begin - Code.GenOp(bopPUTVALUELOCALINDEX,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); - end; - end; - end else begin - Code.GenOp(bopPUTVALUELOCAL,r,SrcRegNr); - end; - end else begin - Code.GenOp(bopPUTVALUEREF,r,SrcRegNr); - end; - end else begin - Code.GenOp(bopPUTVALUE,r,SrcRegNr); - end; - end; - procedure AssignSetType(const n:TBESENASTNode;const t:TBESENValueType); - begin - if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin - case n.NodeType of - bntIDENTIFIER:begin - if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(n).Name) then begin - CodeGeneratorContext.VariableSetType(TBESENASTNodeIdentifier(n).Name,t); - end; - end; - end; - end; - end; - procedure AssignSetWhatType(const n:TBESENASTNode;const wt:longword); - begin - if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin - case wt of - bcgtBOOLEAN:begin - AssignSetType(n,bvtBOOLEAN); - end; - bcgtNUMBER:begin - AssignSetType(n,bvtNUMBER); - end; - bcgtSTRING:begin - AssignSetType(n,bvtSTRING); - end; - bcgtOBJECT:begin - AssignSetType(n,bvtOBJECT); - end; - else begin - AssignSetType(n,bvtUNDEFINED); - end; - end; - end; - end; - function AssignGetType(const n:TBESENASTNode):TBESENValueType; - begin - result:=bvtUNDEFINED; - if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin - case n.NodeType of - bntIDENTIFIER:begin - if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(n).Name) then begin - result:=CodeGeneratorContext.VariableGetType(TBESENASTNodeIdentifier(n).Name); - end; - end; - end; - end; - end; - procedure AssignOpPre; - begin - if DestRegNr<0 then begin - if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin - DestRegNr:=r1; - end else begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - end; - r1:=-1; - r2:=-1; - r3:=-1; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - if IsValueNumber(r1) then begin - r3:=r1; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r3,r1); - end; - end else begin - if IsPrimitive(r1) then begin - raise EBESENReferenceError.Create('Left hand side must be a reference'); - end; - r3:=CodeGeneratorContext.AllocateRegister; - if IsValueNumber(r1) then begin - GenGetValue(r1,r3); - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r4); - Code.GenOp(bopTONUMBER,r3,r4); - CodeGeneratorContext.DeallocateRegister(r4); - end; - end; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r5:=r2; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r5); - end; - if IsValueNumber(r2) then begin - r4:=r5; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r4,r5); - if r2<>r5 then begin - CodeGeneratorContext.DeallocateRegister(r5); - end; - end; - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end; - procedure AssignOpAddPre; - begin - if DestRegNr<0 then begin - if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin - DestRegNr:=r1; - end else begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - end; - r1:=-1; - r2:=-1; - r3:=-1; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - if IsValuePrimitive(r1) then begin - r3:=r1; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOPRIMITIVE,r3,r1); - end; - end else begin - if IsPrimitive(r1) then begin - raise EBESENReferenceError.Create('Left hand side must be a reference'); - end; - r3:=CodeGeneratorContext.AllocateRegister; - if IsValuePrimitive(r1) then begin - GenGetValue(r1,r3); - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r4); - Code.GenOp(bopTOPRIMITIVE,r3,r4); - CodeGeneratorContext.DeallocateRegister(r4); - end; - end; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r5:=r2; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r5); - end; - if IsValuePrimitive(r2) then begin - r4:=r5; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOPRIMITIVE,r4,r5); - if r2<>r5 then begin - CodeGeneratorContext.DeallocateRegister(r5); - end; - end; - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end; - procedure AssignOpShiftPre; - begin - if DestRegNr<0 then begin - if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin - DestRegNr:=r1; - end else begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - end; - r1:=-1; - r2:=-1; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r3:=r1; - end else begin - if IsPrimitive(r1) then begin - raise EBESENReferenceError.Create('Left hand side must be a reference'); - end; - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r3); - end; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r4:=r2; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r4); - end; - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end; - procedure AssignOpPost(Number,Str,FromRight:boolean); - begin - if IsLocalVariableReference(r1) then begin - if DestRegNr=r1 then begin - if Number then begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtNUMBER); - end else if Str then begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtSTRING); - end else if FromRight then begin - if IsValueBoolean(r2) then begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtBOOLEAN); - end else if IsValueNumber(r2) then begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtNUMBER); - end else if IsValueString(r2) then begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtSTRING); - end else if IsValueObject(r2) then begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtOBJECT); - end else begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtUNDEFINED); - end; - end else begin - AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtUNDEFINED); - end; - end else begin - if Number then begin - Code.GenOp(bopCOPYNUM,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end else if Str then begin - Code.GenOp(bopCOPYSTR,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end else if FromRight then begin - if IsValueBoolean(r2) then begin - Code.GenOp(bopCOPYBOOL,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end else if IsValueNumber(r2) then begin - Code.GenOp(bopCOPYNUM,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end else if IsValueString(r2) then begin - Code.GenOp(bopCOPYSTR,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end else if IsValueObject(r2) then begin - Code.GenOp(bopCOPYOBJ,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - end else begin - Code.GenOp(bopCOPY,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - end; - end else begin - Code.GenOp(bopCOPY,r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - end; - AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - end; - end else begin - if Number then begin - GenPutValue(r1,DestRegNr,bvtNUMBER); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end else if Str then begin - GenPutValue(r1,DestRegNr,bvtSTRING); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end else if FromRight then begin - if IsValueBoolean(r2) then begin - GenPutValue(r1,DestRegNr,bvtBOOLEAN); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end else if IsValueNumber(r2) then begin - GenPutValue(r1,DestRegNr,bvtNUMBER); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end else if IsValueString(r2) then begin - GenPutValue(r1,DestRegNr,bvtSTRING); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end else if IsValueObject(r2) then begin - GenPutValue(r1,DestRegNr,bvtOBJECT); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - end else begin - GenPutValue(r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - end; - end else begin - GenPutValue(r1,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - end; - AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - end; - procedure BinaryPre; - begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - r2:=-1; - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r3:=r1; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r3); - end; - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r4:=r2; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r4); - end; - end; - procedure BinaryNumberPre; - begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - r2:=-1; - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r3:=r1; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r3); - end; - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r4:=r2; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r4); - end; - if IsValueNumber(r1) then begin - r5:=r3; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r5,r3); - if r1<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r3); - end; - r3:=r5; - r5:=-1; - end; - if not IsValueNumber(r2) then begin - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r5,r4); - if r2<>r4 then begin - CodeGeneratorContext.DeallocateRegister(r4); - end; - r4:=r5; - r5:=-1; - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - procedure BinaryPost; - begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - end; - function AreStrictValueTypesEqual(const vtBefore,vtAfter:TBESENValueTypes):boolean; - var i,j:integer; - begin - if length(vtBefore)<>length(vtAfter) then begin - result:=false; - end else begin - result:=true; - j:=min(length(vtBefore),length(vtAfter)); - for i:=0 to j-1 do begin - if vtBefore[i]<>vtAfter[i] then begin - result:=false; - break; - end; - end; - end; - end; - procedure ResetDifferentValueTypes(var vtBefore:TBESENValueTypes;vtAfter:TBESENValueTypes); - var i,MinLength,MaxLength,BeforeLength,AfterLength:integer; - begin - BeforeLength:=length(vtBefore); - AfterLength:=length(vtAfter); - MinLength:=min(BeforeLength,AfterLength); - MaxLength:=max(BeforeLength,AfterLength); - SetLength(vtBefore,MaxLength); - for i:=0 to MinLength-1 do begin - if vtBefore[i]<>vtAfter[i] then begin - vtBefore[i]:=bvtUNDEFINED; - end; - end; - for i:=MinLength to MaxLength-1 do begin - vtBefore[i]:=bvtUNDEFINED; - end; - end; - procedure ResetDifferentMultiValueTypes(var vtBefore:TBESENValueTypes;const vtAfter:TBESENValueTypesItems); - var i:integer; - begin - for i:=0 to length(vtAfter)-1 do begin - ResetDifferentValueTypes(vtBefore,vtAfter[i]); - end; - end; - begin - SwitchPatches:=nil; - vta:=nil; - vtb:=nil; - vtc:=nil; - vtd:=nil; - vte:=nil; - vtTemp:=nil; - vtBegin:=nil; - vtInner:=nil; - vtEnd:=nil; - for Counter:=low(RegStates) to high(RegStates) do begin - RegStates[Counter].Registers:=nil; - RegStates[Counter].MaxRegisters:=0; - end; - Operands:=nil; - v:=BESENEmptyValue; - if assigned(ToVisit) then begin - r1:=-1; - r2:=-1; - r3:=-1; - r4:=-1; - r5:=-1; - r6:=-1; - if ToVisit is TBESENASTNodeStatement then begin - if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin - TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; - end; - end; - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLiteral(BESENNullValue,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; - end; - bntLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLiteral(BESENNullValue,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; - end; - bntIDENTIFIER:begin - if DoHoldLocalVariablesInRegisters and OptimizeLocals and (DestRegNr<0) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(ToVisit).Name) then begin - p1:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(ToVisit).Name); - end else begin - p1:=-1; - end; - if p1>=0 then begin - DestRegNr:=p1; - CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name); - CodeGeneratorContext.Registers[DestRegNr].IsLocal:=true; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=AssignGetType(ToVisit); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; - end else begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=-1; - CodeGeneratorContext.Registers[DestRegNr].IsLocal:=false; - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; - Hash:=BESENHashKey(TBESENASTNodeIdentifier(ToVisit).Name); - if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(ToVisit).Name) then begin - if OptimizeLocals then begin - CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name); - CodeGeneratorContext.Registers[DestRegNr].IsLocal:=true; - Code.GenOp(bopLREF,DestRegNr,CodeGeneratorContext.Registers[DestRegNr].LocalIndex); - CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=AssignGetType(ToVisit); - end else begin - Code.GenOp(bopVREF,DestRegNr,CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - end; - end else begin - hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeIdentifier(ToVisit).Name); - if not assigned(hi) then begin - hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeIdentifier(ToVisit).Name,true); - hi^.Value:=Code.LookupNames.Add(TBESENASTNodeIdentifier(ToVisit).Name); - end; - Code.GenOp(bopLOOKUP,DestRegNr,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; - end; - end; - bntVARIABLEDECLARATION:begin - if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Identifier) then begin - TBESENASTNodeVariableDeclaration(ToVisit).Identifier.IsReached:=true; - end; - if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Identifier) and assigned(TBESENASTNodeVariableDeclaration(ToVisit).Expression) then begin - if DoHoldLocalVariablesInRegisters and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin - r1:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); - end else begin - r1:=-1; - end; - if r1>=0 then begin - r2:=-1; - PR:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - vta:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r2) then begin - GenGetValue(r2,r1); - AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); - end else if IsValue(r2) then begin - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r1,true); - AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r1].IsWhat); - end else begin - GenGetValue(r2,r1); - AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); - end; - CodeGeneratorContext.Registers[r1].IsWhat:=bcgtREFERENCE; - if CodeGeneratorContext.VariableGetMutableOrDeletable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin - CodeGeneratorContext.VariableSetFlags(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true,true); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end else begin - r1:=CodeGeneratorContext.AllocateRegister; - r2:=-1; - Hash:=BESENHashKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); - if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin - if OptimizeLocals then begin - Code.GenOp(bopLREF,r1,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name)); - end else begin - Code.GenOp(bopVREF,r1,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - end; - end else begin - hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); - if not assigned(hi) then begin - hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true); - hi^.Value:=Code.LookupNames.Add(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); - end; - Code.GenOp(bopLOOKUP,r1,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); - end; - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); - if IsValue(r2) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r3); - end; - if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin - if OptimizeLocals then begin - Code.GenOp(bopPUTVALUELOCAL,r1,r3); - end else begin - Code.GenOp(bopPUTVALUEREF,r1,r3); - end; - end else begin - Code.GenOp(bopPUTVALUE,r1,r3); - end; - if CodeGeneratorContext.VariableGetMutableOrDeletable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin - CodeGeneratorContext.VariableSetFlags(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true,true); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; -{ end else if CalleeNeedReturnedValue then begin - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,DestRegNr,true);} - end; - end; - bntVARIABLEEXPRESSION:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if DestRegNr<0 then begin - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - r1:=-1; - Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter],r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter],DestRegNr,true); - end; - end; - end; - bntFUNCTIONBODY:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - OldCode:=Code; - OldCodeGeneratorContext:=CodeGeneratorContext; - Code:=TBESENCode(TBESENASTNodeFunctionBody(ToVisit).Code); - CodeGeneratorContext:=TBESENCodeGeneratorContext.Create(Instance); - CodeGeneratorContext.Code:=Code; - OldDoHasLocalDelete:=DoHasLocalDelete; - OldDoIsComplexFunction:=DoIsComplexFunction; - OldDoHasMaybeDirectEval:=DoHasMaybeDirectEval; - OldOptimizeLocals:=OptimizeLocals; - OldHasFunctions:=HasFunctions; - OldDoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; - HasFunctions:=false; - OptimizeLocals:=TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization; - try - DoHasLocalDelete:=false; - DoIsComplexFunction:=not TBESENASTNodeFunctionBody(ToVisit).IsFunction; - DoHasMaybeDirectEval:=false; - HasFunctions:=length(TBESENASTNodeFunctionBody(ToVisit).Functions)>0; - DoHoldLocalVariablesInRegisters:=TBESENASTNodeFunctionBody(ToVisit).IsFunction; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - CheckNodeForFeatures(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter],DoHasLocalDelete,DoIsComplexFunction,DoHasMaybeDirectEval,HasFunctions,DoHoldLocalVariablesInRegisters); - end; - DoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters and (OptimizeLocals and not (DoHasLocalDelete or DoIsComplexFunction or DoHasMaybeDirectEval or HasFunctions)); - if TBESENASTNodeFunctionBody(ToVisit).IsStrict then begin - Code.GenOp(bopSTRICT,1); - end else begin - Code.GenOp(bopSTRICT,0); - end; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin - r1:=-1; - Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter],r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - if assigned(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]) and (TBESENASTNodeFunctionBody(ToVisit).Functions[Counter] is TBESENASTNodeFunctionDeclaration) then begin - if assigned(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal) and assigned(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name) then begin - CodeGeneratorContext.VariableSetScope(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,true,false,-1); - CodeGeneratorContext.VariableSetType(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,bvtUNDEFINED); - CodeGeneratorContext.VariableSetFlags(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,false,false); - end; - end; - end; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin - CodeGeneratorContext.VariableSetScope(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,true,TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter,TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].ParameterIndex); - CodeGeneratorContext.VariableSetType(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,bvtUNDEFINED); - CodeGeneratorContext.VariableSetFlags(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,false,not DoHasLocalDelete); - if DoHoldLocalVariablesInRegisters and not TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter then begin - r1:=CodeGeneratorContext.AllocateRegister; - CodeGeneratorContext.Registers[r1].Variable:=Counter; - CodeGeneratorContext.VariableSetRegister(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,r1); - end else begin - CodeGeneratorContext.VariableSetRegister(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,-1); - end; - end; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - r1:=-1; - Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter],r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - if DoHoldLocalVariablesInRegisters then begin - for Counter:=0 to length(CodeGeneratorContext.Registers)-1 do begin - if CodeGeneratorContext.Registers[Counter].Variable>=0 then begin - CodeGeneratorContext.Registers[Counter].Variable:=-1; - r1:=Counter; - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - end; - if TBESENASTNodeFunctionBody(ToVisit).IsFunction then begin - Code.GenOp(bopSETCUNDEF); - end; - Code.GenOp(bopEND,0); - Code.HasLocalDelete:=DoHasLocalDelete; - Code.IsComplexFunction:=DoIsComplexFunction; - Code.HasMaybeDirectEval:=DoHasMaybeDirectEval; - Code.HoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; - Code.MaxBlock:=CodeGeneratorContext.MaxBlockDepth; - Code.MaxLoop:=CodeGeneratorContext.MaxLoopDepth; - Code.MaxParamArgs:=CodeGeneratorContext.MaxParamArgs; - Code.MaxRegisters:=CodeGeneratorContext.MaxRegisters; - finally - BESENFreeAndNil(CodeGeneratorContext); - Code:=OldCode; - CodeGeneratorContext:=OldCodeGeneratorContext; - DoHasLocalDelete:=OldDoHasLocalDelete; - DoIsComplexFunction:=OldDoIsComplexFunction; - DoHasMaybeDirectEval:=OldDoHasMaybeDirectEval; - OptimizeLocals:=OldOptimizeLocals; - HasFunctions:=OldHasFunctions; - DoHoldLocalVariablesInRegisters:=OldDoHoldLocalVariablesInRegisters; - end; - end; - bntFUNCTIONLITERAL:begin - r1:=-1; - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - if TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).ByteCodeLen=0 then begin - TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).GenOp(bopEND,0); - end; - TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).Finish; - end; - bntSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - end; - bntVARIABLESTATEMENT:begin - Code.GenLocation(ToVisit.Location); - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if DestRegNr<0 then begin - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - r1:=-1; - Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter],r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter],DestRegNr,true); - end; - end; - end; - bntFUNCTIONDECLARATION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal,DestRegNr,true); - end; - end; - bntEXPRESSIONSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - if Code.Body.IsFunction then begin - PR:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - vta:=CodeGeneratorContext.VariableGetTypes; - r1:=-1; - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - CodeGeneratorContext.VariableSetTypes(vta); - Code.Restore(PR); - r1:=-1; - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - end; - end else begin - r1:=-1; - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if not Code.Body.IsFunction then begin - GenSetC(r2); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - bntEMPTYSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - end; - bntBLOCKSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if DestRegNr<0 then begin - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - r1:=-1; - Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter],r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter],DestRegNr,true); - end; - end; - end; - bntDEBUGGERSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - Code.GenOp(bopDEBUGGER); - end; - bntBREAKSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - Patchables:=CodeGeneratorContext.FindPatchables(TBESENASTNodeBreakStatement(ToVisit).Target,false); - if assigned(Patchables) then begin - if Patchables.BlockDepth<CodeGeneratorContext.BlockDepth then begin - Code.GenOp(bopEND,Patchables.BlockDepth+1); - end; - Patchables.AddBreak(Code.GenOp(bopJMP,0)+1,CodeGeneratorContext.VariableGetTypes); - end; - end; - bntCONTINUESTATEMENT:begin - Code.GenLocation(ToVisit.Location); - Patchables:=CodeGeneratorContext.FindPatchables(TBESENASTNodeContinueStatement(ToVisit).Target,true); - if assigned(Patchables) then begin - if Patchables.BlockDepth<CodeGeneratorContext.BlockDepth then begin - Code.GenOp(bopEND,Patchables.BlockDepth+1); - end; - Patchables.AddContinue(Code.GenOp(bopJMP,0)+1,CodeGeneratorContext.VariableGetTypes); - end; - end; - bntDOSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - inc(CodeGeneratorContext.LoopDepth); - if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin - CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; - end; - if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeDoStatement(ToVisit).Statement) then begin - - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - PR:=Code.Here; - - // Pass one - Collecting value type differences and generating final code if value types are static - // *** vta = Before do statement - // * vtb = After do statement and before do while expression - // * vtc = After do while expression - begin - CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); - - vta:=CodeGeneratorContext.VariableGetTypes; - L1:=Code.Here; - Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - - vtb:=CodeGeneratorContext.VariableGetTypes; - L2:=Code.Here; - Code.GenLocation(ToVisit.Location); - r1:=-1; - Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - L3:=Code.Here; - - vtc:=CodeGeneratorContext.VariableGetTypes; - - vtInner:=copy(vta,0,length(vta)); - ResetDifferentValueTypes(vtInner,vtb); - ResetDifferentValueTypes(vtInner,vtc); - - if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin - SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); - ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); - end; - - vtEnd:=copy(vtInner,0,length(vtInner)); - if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin - SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); - ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); - end; - - CodeGeneratorContext.PopPatchables(L2,L3); - - CodeGeneratorContext.VariableSetTypes(vtEnd); - end; - - // Pass two - Generating final loop code if value types are different - if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(PR); - - CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); - - CodeGeneratorContext.VariableSetTypes(vtInner); - L1:=Code.Here; - Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - - CodeGeneratorContext.VariableSetTypes(vtInner); - L2:=Code.Here; - Code.GenLocation(ToVisit.Location); - r1:=-1; - Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - L3:=Code.Here; - CodeGeneratorContext.PopPatchables(L2,L3); - - CodeGeneratorContext.VariableSetTypes(vtEnd); - end; - end else begin - // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop - CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); - L1:=Code.Here; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L2:=Code.Here; - Code.GenLocation(ToVisit.Location); - r1:=-1; - Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - L3:=Code.Here; - CodeGeneratorContext.PopPatchables(L2,L3); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - dec(CodeGeneratorContext.LoopDepth); - end; - bntWHILESTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - inc(CodeGeneratorContext.LoopDepth); - if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin - CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; - end; - if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeWhileStatement(ToVisit).Statement) then begin - - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - PR:=Code.Here; - - // Pass one - Collecting value type differences and generating final code if value types are static - // *** vta = Before first while expression execution and before while statement - // * vtb = Before while expression - // * vtc = After while expression - begin - Code.GenLocation(ToVisit.Location); - - CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); - - vta:=CodeGeneratorContext.VariableGetTypes; - P1:=Code.GenOp(bopJMP,0)+1; - - L1:=Code.Here; - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - - L2:=Code.Here; - Code.GenLocation(ToVisit.Location); - - vtb:=CodeGeneratorContext.VariableGetTypes; - Code.GenLabel(P1); - r1:=-1; - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - L3:=Code.Here; - - vtc:=CodeGeneratorContext.VariableGetTypes; - - vtInner:=copy(vta,0,length(vta)); - ResetDifferentValueTypes(vtInner,vtb); - ResetDifferentValueTypes(vtInner,vtc); - - if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin - SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); - ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); - end; - - vtEnd:=copy(vtInner,0,length(vtInner)); - if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin - SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); - ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); - end; - - CodeGeneratorContext.PopPatchables(L2,L3); - - CodeGeneratorContext.VariableSetTypes(vtEnd); - end; - - // Pass two - Generating final loop code if value types are different - if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(PR); - - CodeGeneratorContext.VariableSetTypes(vtInner); - - Code.GenLocation(ToVisit.Location); - - CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); - - P1:=Code.GenOp(bopJMP,0)+1; - - L1:=Code.Here; - CodeGeneratorContext.VariableSetTypes(vtInner); - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - - L2:=Code.Here; - Code.GenLocation(ToVisit.Location); - - Code.GenLabel(P1); - CodeGeneratorContext.VariableSetTypes(vtInner); - r1:=-1; - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - L3:=Code.Here; - - CodeGeneratorContext.VariableSetTypes(vtEnd); - - CodeGeneratorContext.PopPatchables(L2,L3); - end; - end else begin - // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop - Code.GenLocation(ToVisit.Location); - CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); - P1:=Code.GenOp(bopJMP,0)+1; - - L1:=Code.Here; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - - Code.GenLabel(P1); - L2:=Code.Here; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Code.GenLocation(ToVisit.Location); - - r1:=CodeGeneratorContext.AllocateRegister; - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - L3:=Code.Here; - CodeGeneratorContext.PopPatchables(L2,L3); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - dec(CodeGeneratorContext.LoopDepth); - end; - bntWITHSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeWithStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - r2:=r1; - end else if IsValue(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueObject(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOOBJECT,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - if r1<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r1); - end; - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - Code.GenOp(bopSWITH,r3); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.BlockEnter; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - OldVarScope:=CodeGeneratorContext.VariableSetAllScope(false); - OldOptimizeLocals:=OptimizeLocals; - OptimizeLocals:=false; - Visit(TBESENASTNodeWithStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - OptimizeLocals:=OldOptimizeLocals; - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); - CodeGeneratorContext.BlockLeave; - CodeGeneratorContext.VariableSetAllScope(OldVarScope); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - bntFORSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - inc(CodeGeneratorContext.LoopDepth); - if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin - CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; - end; - if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeForStatement(ToVisit).Statement) then begin - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - PR:=Code.Here; - - // Pass one - Collecting value type differences and generating final code if value types are static - // *** vta = Before initial expression - // * vtb = After conditional expression and before statement - // * vtc = After before statement and before increment expression - // * vtd = After increment expression and before conditional expression - // * vte = After conditional expression - begin - CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); - - vta:=CodeGeneratorContext.VariableGetTypes; - if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin - Code.GenLocation(ToVisit.Location); - PR2:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[1]); - vtTemp:=CodeGeneratorContext.VariableGetTypes; - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); - if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - Code.Restore(PR2); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - - P1:=Code.GenOp(bopJMP,0)+1; - - vtb:=CodeGeneratorContext.VariableGetTypes; - L1:=Code.Here; - if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin - Code.GenLocation(ToVisit.Location); - Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - end; - - vtc:=CodeGeneratorContext.VariableGetTypes; - L2:=Code.Here; - if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin - Code.GenLocation(ToVisit.Location); - PR2:=Code.Here; - vtTemp:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[1]); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); - if r1>=0 then begin - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - - vtd:=CodeGeneratorContext.VariableGetTypes; - Code.GenLabel(P1); - Code.GenLocation(ToVisit.Location); - if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); - if r1>=0 then begin - if (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end else begin - Code.GenOp(bopJMP,L1); - end; - end else begin - Code.GenOp(bopJMP,L1); - end; - L3:=Code.Here; - - vte:=CodeGeneratorContext.VariableGetTypes; - - vtBegin:=copy(vta,0,length(vta)); - - vtInner:=copy(vtb,0,length(vtb)); - ResetDifferentValueTypes(vtInner,vtc); - ResetDifferentValueTypes(vtInner,vtd); - ResetDifferentValueTypes(vtInner,vte); - - if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin - SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); - ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); - end; - - vtEnd:=copy(vtInner,0,length(vtInner)); - if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin - SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); - ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); - end; - - CodeGeneratorContext.PopPatchables(L2,L3); - - CodeGeneratorContext.VariableSetTypes(vtEnd); - end; - - // Pass two - Generating final loop code if value types are different - if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtd) and AreStrictValueTypesEqual(vta,vte) and AreStrictValueTypesEqual(vta,vtBegin) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(PR); - - CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); - - CodeGeneratorContext.VariableSetTypes(vtBegin); - if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin - Code.GenLocation(ToVisit.Location); - PR2:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[1]); - vtTemp:=CodeGeneratorContext.VariableGetTypes; - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); - if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - - P1:=Code.GenOp(bopJMP,0)+1; - - CodeGeneratorContext.VariableSetTypes(vtInner); - L1:=Code.Here; - if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin - Code.GenLocation(ToVisit.Location); - Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - end; - - CodeGeneratorContext.VariableSetTypes(vtInner); - L2:=Code.Here; - if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin - Code.GenLocation(ToVisit.Location); - PR2:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[1]); - vtTemp:=CodeGeneratorContext.VariableGetTypes; - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); - if r1>=0 then begin - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableSetTypes(vtTemp); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - - CodeGeneratorContext.VariableSetTypes(vtInner); - Code.GenLabel(P1); - Code.GenLocation(ToVisit.Location); - if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); - if r1>=0 then begin - if (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end else begin - Code.GenOp(bopJMP,L1); - end; - end else begin - Code.GenOp(bopJMP,L1); - end; - L3:=Code.Here; - - CodeGeneratorContext.VariableSetTypes(vtEnd); - - CodeGeneratorContext.PopPatchables(L2,L3); - end; - end else begin - // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop - CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); - - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - - if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin - Code.GenLocation(ToVisit.Location); - PR2:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[1]); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); - if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - P1:=Code.GenOp(bopJMP,0)+1; - - L1:=Code.Here; - if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin - Code.GenLocation(ToVisit.Location); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - end; - - L2:=Code.Here; - if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin - Code.GenLocation(ToVisit.Location); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - PR2:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[1]); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); - if r1>=0 then begin - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end else begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[1]); - Code.Restore(PR2); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - - Code.GenLabel(P1); - Code.GenLocation(ToVisit.Location); - if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - r1:=-1; - Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); - if r1>=0 then begin - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - Code.GenOp(bopJNZERO,L1,r3); - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - Code.GenOp(bopJZ,L1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end else begin - Code.GenOp(bopJMP,L1); - end; - end else begin - Code.GenOp(bopJMP,L1); - end; - L3:=Code.Here; - - CodeGeneratorContext.PopPatchables(L2,L3); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - dec(CodeGeneratorContext.LoopDepth); - end; - bntFORINSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - inc(CodeGeneratorContext.LoopDepth); - if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin - CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; - end; - Code.GenLocation(ToVisit.Location); - if TBESENASTNodeForInStatement(ToVisit).Variable.NodeType=bntVARIABLEDECLARATION then begin - r1:=-1; - r2:=-1; - if assigned(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier) then begin - Visit(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier,r1,true); - end else begin - Visit(TBESENASTNodeForInStatement(ToVisit).Variable,r1,true); - end; - Visit(TBESENASTNodeForInStatement(ToVisit).Expression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r3); - end; - P2:=Code.GenOp(bopJNULL,0,r3)+1; - if IsValueObject(r2) then begin - r4:=r3; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOOBJECT,r4,r3); - if r3<>r4 then begin - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - Code.GenOp(bopSENUM,r4); - r5:=CodeGeneratorContext.AllocateRegister; - CodeGeneratorContext.BlockEnter; - CodeGeneratorContext.PushPatchables(TBESENASTNodeForInStatement(ToVisit).Target,true); - P1:=Code.GenOp(bopJMP,0)+1; - L1:=Code.Here; - r3:=CodeGeneratorContext.AllocateRegister; - Hash:=BESENHashKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); - if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name) then begin - if IsLocalVariableReference(r1) then begin - Code.GenOp(bopCOPY,r1,r5); - end else if OptimizeLocals then begin - Code.GenOp(bopLREF,r3,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name)); - Code.GenOp(bopPUTVALUELOCAL,r3,r5); - end else begin - Code.GenOp(bopVREF,r3,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - Code.GenOp(bopPUTVALUEREF,r3,r5); - end; - end else begin - hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); - if not assigned(hi) then begin - hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name,true); - hi^.Value:=Code.LookupNames.Add(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); - end; - Code.GenOp(bopLOOKUP,r3,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); - Code.GenOp(bopPUTVALUEREF,r3,r5); - end; - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeForInStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L2:=Code.Here; - Code.GenLabel(P1); - Code.GenOp(bopLOOPENUM,L1,r5); - L3:=Code.Here; - Code.GenLabel(P2); - CodeGeneratorContext.PopPatchables(L2,L3); - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); - CodeGeneratorContext.BlockLeave; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - CodeGeneratorContext.DeallocateRegister(r6); - end else begin - r2:=-1; - Visit(TBESENASTNodeForInStatement(ToVisit).Expression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) or IsLocalVariableReference(r2) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r3); - end; - P2:=Code.GenOp(bopJNULL,0,r3)+1; - if IsValueObject(r2) then begin - r4:=r3; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOOBJECT,r4,r3); - if r3<>r4 then begin - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - Code.GenOp(bopSENUM,r4); - r5:=CodeGeneratorContext.AllocateRegister; - CodeGeneratorContext.BlockEnter; - CodeGeneratorContext.PushPatchables(TBESENASTNodeForInStatement(ToVisit).Target,true); - P1:=Code.GenOp(bopJMP,0)+1; - L1:=Code.Here; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - r1:=-1; - Visit(TBESENASTNodeForInStatement(ToVisit).Variable,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r1) then begin - Code.GenOp(bopCOPY,r1,r5); - end else begin - Code.GenOp(bopPUTVALUE,r1,r5); - end; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeForInStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L2:=Code.Here; - Code.GenLabel(P1); - Code.GenOp(bopLOOPENUM,L1,r5); - L3:=Code.Here; - Code.GenLabel(P2); - CodeGeneratorContext.PopPatchables(L2,L3); - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); - CodeGeneratorContext.BlockLeave; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - CodeGeneratorContext.DeallocateRegister(r6); - end; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - dec(CodeGeneratorContext.LoopDepth); - end; - bntIFSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if OptimizeLocals and not (HasLabelBreakContinue(TBESENASTNodeIfStatement(ToVisit).TrueStatement) or HasLabelBreakContinue(TBESENASTNodeIfStatement(ToVisit).FalseStatement)) then begin - PR:=Code.Here; - - vta:=CodeGeneratorContext.VariableGetTypes; - - Code.GenLocation(ToVisit.Location); - r1:=-1; - Visit(TBESENASTNodeIfStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - L1:=Code.GenOp(bopJNZERO,0,r3)+1; - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - L1:=Code.GenOp(bopJZ,0,r3)+1; - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - - vtb:=CodeGeneratorContext.VariableGetTypes; - - Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - if IsBreakContinueReturnNode(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin - vtc:=copy(vtb,0,length(vtb)); - end else begin - vtc:=CodeGeneratorContext.VariableGetTypes; - end; - L2:=Code.GenOp(bopJMP,0)+1; - - Code.GenLabel(L1); - CodeGeneratorContext.VariableSetTypes(vtb); - Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - if IsBreakContinueReturnNode(TBESENASTNodeIfStatement(ToVisit).TrueStatement) then begin - vtd:=copy(vtb,0,length(vtb)); - end else begin - vtd:=CodeGeneratorContext.VariableGetTypes; - end; - - Code.GenLabel(L2); - - vte:=copy(vtc,0,length(vtc)); - if not AreStrictValueTypesEqual(vte,vtd) then begin - ResetDifferentValueTypes(vte,vtd); - end; - - CodeGeneratorContext.VariableSetTypes(vte); - end else begin - // The if-statmente body contains break/continue or it's extremly type instable global code - Code.GenLocation(ToVisit.Location); - r1:=-1; - Visit(TBESENASTNodeIfStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - L1:=Code.GenOp(bopJNZERO,0,r3)+1; - end else begin - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - if r2<>r3 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - L1:=Code.GenOp(bopJZ,0,r3)+1; - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - vta:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L2:=Code.GenOp(bopJMP,0)+1; - Code.GenLabel(L1); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - Code.GenLabel(L2); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - end; - bntLABELLEDSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLocation(ToVisit.Location); - CodeGeneratorContext.PushPatchables(TBESENASTNodeLabelledStatement(ToVisit).Target,false); - Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L1:=Code.Here; - CodeGeneratorContext.PopPatchables(-1,L1); - end; - bntCASESTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Code.GenLocation(ToVisit.Location); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter],DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - end; - end; - bntSWITCHSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLocation(ToVisit.Location); - SetLength(SwitchPatches,length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)); - r1:=-1; - Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - if assigned(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression) then begin - r3:=-1; - Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression,r3,true); - if r3<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r3) then begin - r4:=r3; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r3,r4); - end; - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopSEQ,r5,r2,r4); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - SwitchPatches[Counter]:=Code.GenOp(bopJZ,0,r5)+1; - CodeGeneratorContext.DeallocateRegister(r5); - end; - end; - L1:=Code.GenOp(bopJMP,0)+1; - CodeGeneratorContext.PushPatchables(TBESENASTNodeSwitchStatement(ToVisit).Target,false); - DefaultCase:=false; - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - if assigned(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression) then begin - Code.GenLabel(SwitchPatches[Counter]); - end else begin - Code.GenLabel(L1); - DefaultCase:=true; - end; - Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter],DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - end; - if not DefaultCase then begin - Code.GenLabel(L1); - end; - SetLength(SwitchPatches,0); - CodeGeneratorContext.PopPatchables(-1,Code.Here); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - CodeGeneratorContext.DeallocateRegister(r6); - end; - bntTHROWSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - if assigned(TBESENASTNodeThrowStatement(ToVisit).Expression) then begin - r1:=-1; - Visit(TBESENASTNodeThrowStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - Code.GenOp(bopTHROW,r2); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - bntTRYSTATEMENT:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLocation(ToVisit.Location); - if assigned(TBESENASTNodeTryStatement(ToVisit).TryBlock) then begin - if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) and assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin - L1:=Code.GenOp(bopSTRYF,0)+1; - CodeGeneratorContext.BlockEnter; - r1:=CodeGeneratorContext.AllocateRegister; - Code.GenLiteral(BESENStringValue(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name),r1); - L2:=Code.GenOp(bopSTRYC,0,r1)+1; - CodeGeneratorContext.BlockEnter; - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L3a:=Code.GenOp(bopJMP,0)+1; - Code.GenLabel(L2); - InScope:=CodeGeneratorContext.IsVariableInScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name); - if InScope then begin - CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,false,false,-1); - end; - Code.GenOp(bopSCATCH); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - if InScope then begin - CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,true,false,-1); - CodeGeneratorContext.VariableSetType(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,bvtUNDEFINED); - end; - L3b:=Code.GenOp(bopJMP,0)+1; - CodeGeneratorContext.BlockLeave; - Code.GenLabel(L1); - if not Code.Body.IsFunction then begin - Code.GenOp(bopGETC,r1); - end; - if CodeGeneratorContext.MaxBlockDepth>CodeGeneratorContext.BlockCurrent then begin - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent+1); - end; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - if not Code.Body.IsFunction then begin - GenSetC(r1); - end; - Code.GenOp(bopENDF); - Code.GenLabel(L3a); - Code.GenLabel(L3b); - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); - CodeGeneratorContext.BlockLeave; - CodeGeneratorContext.DeallocateRegister(r1); - end else if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) then begin - r1:=CodeGeneratorContext.AllocateRegister; - Code.GenLiteral(BESENStringValue(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name),r1); - L1:=Code.GenOp(bopSTRYC,0,r1)+1; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.BlockEnter; - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L2:=Code.GenOp(bopJMP,0)+1; - Code.GenLabel(L1); - InScope:=CodeGeneratorContext.IsVariableInScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name); - if InScope then begin - CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,false,false,-1); - end; - Code.GenOp(bopSCATCH); - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - if InScope then begin - CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,true,false,-1); - CodeGeneratorContext.VariableSetType(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,bvtUNDEFINED); - end; - Code.GenLabel(L2); - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); - CodeGeneratorContext.BlockLeave; - end else if assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin - L1:=Code.GenOp(bopSTRYF,0)+1; - CodeGeneratorContext.BlockEnter; - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - L2:=Code.GenOp(bopJMP,0)+1; - Code.GenLabel(L1); - r1:=CodeGeneratorContext.AllocateRegister; - if not Code.Body.IsFunction then begin - Code.GenOp(bopGETC,r1); - end; - if CodeGeneratorContext.MaxBlockDepth>CodeGeneratorContext.BlockCurrent then begin - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent+1); - end; - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - if not Code.Body.IsFunction then begin - GenSetC(r1); - end; - Code.GenOp(bopENDF); - Code.GenLabel(L2); - Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); - CodeGeneratorContext.BlockLeave; - CodeGeneratorContext.DeallocateRegister(r1); - end; - end; - end; - bntARRAYLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=CodeGeneratorContext.AllocateRegister; - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopARRAY,r1); - Code.GenOp(bopNEW,DestRegNr,r1,0); - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenLiteral(BESENStringValue(inttostr(Counter)),r3); - r4:=-1; - Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter],r4,true); - if r4<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r4) or IsLocalVariableReference(r4) then begin - r5:=r4; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r4,r5); - end; - Code.GenOp(bopPUTOBJVALUE,DestRegNr,r3,r5); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - end; - end; - r3:=CodeGeneratorContext.AllocateRegister; - v:=BESENStringValue('length'); - Code.GenLiteral(v,r3); - r4:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopREF,r4,DestRegNr,r3,TBESEN(Instance).KeyIDManager.LengthID,BESENLengthHash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenLiteral(BESENNumberValue(length(TBESENASTNodeArrayLiteral(ToVisit).Elements)),r5); - Code.GenOp(bopPUTVALUEREF,r4,r5); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - CodeGeneratorContext.DeallocateRegister(r6); - end; - bntBINARYEXPRESSION:begin - end; - bntASSIGNMENTEXPRESSION:begin - if IsNodeLocalVarReg(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1) then begin - r1:=-1; - Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1,true); - r2:=-1; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - P1:=Code.Here; - vtb:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r2) then begin - GenGetValue(r2,r1); - AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r1].IsWhat); - end else if IsValue(r2) then begin - CodeGeneratorContext.DeallocateRegister(r2); - r2:=r1; - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(P1); - CodeGeneratorContext.VariableSetTypes(vtb); - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); - AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r2].IsWhat); - end else begin - GenGetValue(r2,r1); - AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r1].IsWhat); - end; - CodeGeneratorContext.Registers[r1].IsWhat:=bcgtREFERENCE; - if CalleeNeedReturnedValue or (DestRegNr>=0) then begin - if DestRegNr<0 then begin - DestRegNr:=r1; - end else begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,DestRegNr); - end; - end; - CodeGeneratorContext.DeallocateRegister(r2); - end else begin - r1:=-1; - end; - if r1<0 then begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - vta:=CodeGeneratorContext.VariableGetTypes; - PR:=Code.Here; - r1:=-1; - Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsPrimitive(r1) then begin - raise EBESENReferenceError.Create('Left hand side must be a reference'); - end; - r2:=-1; - P1:=Code.Here; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - vtb:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsLocalVariableReference(r2) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - GenGetValue(r2,DestRegNr); - if not IsValue(DestRegNr) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - end else if IsValue(r2) then begin - CodeGeneratorContext.DeallocateRegister(r2); - Code.Restore(P1); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - CodeGeneratorContext.VariableSetTypes(vtb); - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,DestRegNr,true); - r2:=DestRegNr; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r2].IsWhat; - end else begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - GenGetValue(r2,DestRegNr); - if not IsValue(DestRegNr) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - end; - AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - if (not DoHasLocalDelete) and (((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and - CodeGeneratorContext.Registers[r1].IsLocal) and - ((TBESENASTNodeAssignmentExpression(ToVisit).RightExpression.NodeType=bntIDENTIFIER) and - (((CodeGeneratorContext.Registers[r2].IsWhat and bcgtREFERENCE)<>0) and - CodeGeneratorContext.Registers[r2].IsLocal)) then begin - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - r2:=-1; - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - GenGetValueEx(r2,DestRegNr); - if IsValueBoolean(r2) then begin - GenPutValueEx(r1,DestRegNr,bvtBOOLEAN); - end else if IsValueNumber(r2) then begin - GenPutValueEx(r1,DestRegNr,bvtNUMBER); - end else if IsValueString(r2) then begin - GenPutValueEx(r1,DestRegNr,bvtSTRING); - end else if IsValueObject(r2) then begin - GenPutValueEx(r1,DestRegNr,bvtOBJECT); - end else begin - GenPutValueEx(r1,DestRegNr); - end; - end else begin - if ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)=0) or not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - if IsValueBoolean(r2) then begin - GenPutValue(r1,DestRegNr,bvtBOOLEAN); - end else if IsValueNumber(r2) then begin - GenPutValue(r1,DestRegNr,bvtNUMBER); - end else if IsValueString(r2) then begin - GenPutValue(r1,DestRegNr,bvtSTRING); - end else if IsValueObject(r2) then begin - GenPutValue(r1,DestRegNr,bvtOBJECT); - end else begin - GenPutValue(r1,DestRegNr); - end; - end; - if r1<>DestRegNr then begin - CodeGeneratorContext.DeallocateRegister(r1); - end; - if r2<>DestRegNr then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsPrimitive(r1) then begin - raise EBESENReferenceError.Create('Left hand side must be a reference'); - end; - r2:=-1; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) then begin - if IsValueBoolean(r2) then begin - Code.GenOp(bopCOPYBOOL,DestRegNr,r2); - end else if IsValueNumber(r2) then begin - Code.GenOp(bopCOPYNUM,DestRegNr,r2); - end else if IsValueString(r2) then begin - Code.GenOp(bopCOPYSTR,DestRegNr,r2); - end else if IsValueObject(r2) then begin - Code.GenOp(bopCOPYOBJ,DestRegNr,r2); - end else begin - Code.GenOp(bopCOPY,DestRegNr,r2); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r2].IsWhat; - end else begin - GenGetValue(r2,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - if ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)=0) or not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF); - end; - AssignOpPost(false,false,true); - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - AssignOpPre; - Code.GenOp(bopMUL,DestRegNr,r3,r4); - AssignOpPost(true,false,false); - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - AssignOpPre; - Code.GenOp(bopDIV,DestRegNr,r3,r4); - AssignOpPost(true,false,false); - end; - bntASSIGNMENTMODULOEXPRESSION:begin - AssignOpPre; - Code.GenOp(bopMOD,DestRegNr,r3,r4); - AssignOpPost(true,false,false); - end; - bntASSIGNMENTPLUSEXPRESSION:begin - AssignOpAddPre; - if IsValueNumber(r1) and IsValueNumber(r2) then begin - Code.GenOp(bopADDNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopADD,DestRegNr,r3,r4); - end; - if IsValueString(r1) or IsValueString(r2) then begin - AssignOpPost(false,true,false); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end else if IsValueNumber(r1) and IsValueNumber(r2) then begin - AssignOpPost(true,false,false); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end else begin - AssignOpPost(false,false,false); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING or bcgtNUMBER; - end; - AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - end; - bntASSIGNMENTMINUSEXPRESSION:begin - AssignOpPre; - Code.GenOp(bopSUB,DestRegNr,r3,r4); - AssignOpPost(true,false,false); - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - AssignOpShiftPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopSHLBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopSHLNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopSHL,DestRegNr,r3,r4); - end; - AssignOpPost(true,false,false); - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - AssignOpShiftPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopSHRNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopSHR,DestRegNr,r3,r4); - end; - AssignOpPost(true,false,false); - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - AssignOpShiftPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopUSHRNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopUSHR,DestRegNr,r3,r4); - end; - AssignOpPost(true,false,false); - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - AssignOpPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopBANDBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopBANDNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopBAND,DestRegNr,r3,r4); - end; - AssignOpPost(true,false,false); - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - AssignOpPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopBXORBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopBXORNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopBXOR,DestRegNr,r3,r4); - end; - AssignOpPost(true,false,false); - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - AssignOpPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopBORBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopBORNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopBOR,DestRegNr,r3,r4); - end; - AssignOpPost(true,false,false); - end; - bntBINARYOPERATOREXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if not IsValue(r1) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - end; - CodeGeneratorContext.DeallocateRegister(r1); - r1:=-1; - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) then begin - if IsValueBoolean(r1) then begin - Code.GenOp(bopCOPYBOOL,DestRegNr,r1); - end else if IsValueNumber(r1) then begin - Code.GenOp(bopCOPYNUM,DestRegNr,r1); - end else if IsValueString(r1) then begin - Code.GenOp(bopCOPYSTR,DestRegNr,r1); - end else if IsValueObject(r1) then begin - Code.GenOp(bopCOPYOBJ,DestRegNr,r1); - end else begin - Code.GenOp(bopCOPY,DestRegNr,r1); - end; - end else begin - GenGetValue(r1,DestRegNr); - end; - if IsValue(r1) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat; - end else begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - CodeGeneratorContext.DeallocateRegister(r1); - end; - bntBINARYCOMMAEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if not IsValue(r1) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - end; - CodeGeneratorContext.DeallocateRegister(r1); - PR:=Code.Here; - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - r1:=-1; - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,DestRegNr,true); - r1:=DestRegNr; - end else begin - GenGetValue(r1,DestRegNr); - CodeGeneratorContext.DeallocateRegister(r1); - end; - if IsValue(r1) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat; - end else begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - end; - bntBINARYDIVIDEEXPRESSION:begin - BinaryNumberPre; - Code.GenOp(bopDIV,DestRegNr,r3,r4); - BinaryPost; - end; - bntBINARYMODULOEXPRESSION:begin - BinaryNumberPre; - Code.GenOp(bopMOD,DestRegNr,r3,r4); - BinaryPost; - end; - bntBINARYMULTIPLYEXPRESSION:begin - BinaryNumberPre; - Code.GenOp(bopMUL,DestRegNr,r3,r4); - BinaryPost; - end; - bntBINARYPLUSEXPRESSION:begin - BinaryPre; - if IsValuePrimitive(r1) then begin - r5:=r3; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOPRIMITIVE,r5,r3); - end; - if IsValuePrimitive(r2) then begin - r6:=r4; - end else begin - r6:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOPRIMITIVE,r6,r4); - end; - if IsValueNumber(r1) and IsValueNumber(r2) then begin - Code.GenOp(bopADDNUM,DestRegNr,r5,r6); - end else begin - Code.GenOp(bopADD,DestRegNr,r5,r6); - end; - if IsValueString(r1) or IsValueString(r2) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end else if IsValueNumber(r1) and IsValueNumber(r2) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end else begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING or bcgtNUMBER; - end; - BinaryPost; - end; - bntBINARYMINUSEXPRESSION:begin - BinaryNumberPre; - Code.GenOp(bopSUB,DestRegNr,r3,r4); - BinaryPost; - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopSHLBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopSHLNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopSHL,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopSHRNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopSHR,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopUSHRNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopUSHR,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntBINARYGREATERTHANEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopGTBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopGTNUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopGTNUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopGTSTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopGT,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopGEBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopGENUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopGENUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopGESTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopGE,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYLESSTHANEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopLTBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopLTNUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopLTNUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopLTSTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopLT,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopLEBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopLENUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopLENUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopLESTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopLE,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYINSTANCEOFEXPRESSION:begin - BinaryPre; - Code.GenOp(bopINSTANCEOF,DestRegNr,r3,r4); - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYINEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - r2:=-1; - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) then begin - r3:=r1; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r3); - end; - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) then begin - r4:=r2; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r4); - end; - if IsValueString(r1) then begin - r5:=r3; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOSTRING,r5,r3); - end; - Code.GenOp(bopIN,DestRegNr,r5,r4); - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYEQUALEQUALEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopEQBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopEQNUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopEQNUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopEQSTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopEQ,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopEQBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopEQNUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopEQNUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopEQSTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopSEQ,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYNOTEQUALEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopNEQBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopNEQNUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopNEQNUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopNEQSTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopNEQ,DestRegNr,r3,r4); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) and IsValueBoolean(r4) then begin - Code.GenOp(bopNEQBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) and IsValueNumber(r4) then begin - if Code.LastOpcode=bopLITERALNUM then begin - v1:=Code.ByteCode[Code.LastCodePos+2]; - Code.Restore(Code.LastCodePos); - Code.GenOp(bopNEQNUMCONST,DestRegNr,r3,v1); - end else begin - Code.GenOp(bopNEQNUM,DestRegNr,r3,r4); - end; - end else if IsValueString(r3) and IsValueString(r4) then begin - Code.GenOp(bopNEQSTR,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopNSEQ,DestRegNr,r3,r4); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntBINARYBITWISEANDEXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopBANDBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopBANDNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopBAND,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntBINARYBITWISEXOREXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopBXORBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopBXORNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopBXOR,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntBINARYBITWISEOREXPRESSION:begin - BinaryPre; - if IsValueBoolean(r3) or IsValueBoolean(r4) then begin - Code.GenOp(bopBORBOOL,DestRegNr,r3,r4); - end else if IsValueNumber(r3) or IsValueNumber(r4) then begin - Code.GenOp(bopBORNUM,DestRegNr,r3,r4); - end else begin - Code.GenOp(bopBOR,DestRegNr,r3,r4); - end; - BinaryPost; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntBOOLEANLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - v.ValueType:=bvtBOOLEAN; - v.Bool:=TBESENASTNodeBooleanLiteral(ToVisit).Value; - Code.GenLiteral(v,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntCALLEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if CodeGeneratorContext.MaxParamArgs<length(TBESENASTNodeCallExpression(ToVisit).Arguments) then begin - CodeGeneratorContext.MaxParamArgs:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); - end; - SetLength(Operands,4+length(TBESENASTNodeCallExpression(ToVisit).Arguments)); - Operands[0]:=DestRegNr; - Operands[1]:=r1; - Operands[2]:=r1; - Operands[3]:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - Operands[4+Counter]:=CodeGeneratorContext.AllocateRegister; - end; - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - pr:=Code.Here; - r3:=-1; - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],r3,true); - if r3<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r3) or IsLocalVariableReference(r3) then begin - if IsLocalVariableReference(r3) then begin - Operands[4+Counter]:=-1; - end; - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(pr); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],Operands[4+Counter],true); - end else begin - GenGetValue(r3,Operands[4+Counter]); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - Operands[2]:=r2; - if TBESEN(Instance).CodeTracable then begin - Code.GenOp(bopTRACECALL,Operands); - end else begin - Code.GenOp(bopCALL,Operands); - end; - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - CodeGeneratorContext.DeallocateRegister(r1); - for Counter:=4 to length(Operands)-1 do begin - CodeGeneratorContext.DeallocateRegister(Operands[Counter]); - end; - SetLength(Operands,0); - if (OptimizeLocals and HasFunctions) or not OptimizeLocals then begin - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - bntNEWEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if CodeGeneratorContext.MaxParamArgs<length(TBESENASTNodeCallExpression(ToVisit).Arguments) then begin - CodeGeneratorContext.MaxParamArgs:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); - end; - SetLength(Operands,3+length(TBESENASTNodeCallExpression(ToVisit).Arguments)); - Operands[0]:=DestRegNr; - Operands[1]:=r1; - Operands[2]:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - Operands[3+Counter]:=CodeGeneratorContext.AllocateRegister; - end; - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - pr:=Code.Here; - r3:=-1; - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],r3,true); - if r3<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r3) or IsLocalVariableReference(r3) then begin - if IsLocalVariableReference(r3) then begin - Operands[3+Counter]:=-1; - end; - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(pr); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],Operands[3+Counter],true); - end else begin - GenGetValue(r3,Operands[3+Counter]); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - Operands[1]:=r2; - if TBESEN(Instance).CodeTracable then begin - Code.GenOp(bopTRACENEW,Operands); - end else begin - Code.GenOp(bopNEW,Operands); - end; - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - CodeGeneratorContext.DeallocateRegister(r1); - for Counter:=3 to length(Operands)-1 do begin - CodeGeneratorContext.DeallocateRegister(Operands[Counter]); - end; - SetLength(Operands,0); - if (OptimizeLocals and HasFunctions) or not OptimizeLocals then begin - CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - end; - bntCONDITIONALEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - end; - L1:=Code.GenOp(bopJZ,0,r3)+1; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - vta:=CodeGeneratorContext.VariableGetTypes; - - PR:=Code.Here; - r1:=-1; - Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) then begin - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression,DestRegNr,true); - end else begin - GenGetValue(r1,DestRegNr); - end; - vtb:=CodeGeneratorContext.VariableGetTypes; - - L2:=Code.GenOp(bopJMP,0)+1; - Code.GenLabel(L1); - - CodeGeneratorContext.VariableSetTypes(vta); - - PR:=Code.Here; - r2:=-1; - Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) then begin - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression,DestRegNr,true); - end else begin - GenGetValue(r2,DestRegNr); - end; - vtc:=CodeGeneratorContext.VariableGetTypes; - - vte:=copy(vtb,0,length(vtb)); - if not AreStrictValueTypesEqual(vte,vtc) then begin - ResetDifferentValueTypes(vte,vtc); - end; - CodeGeneratorContext.VariableSetTypes(vte); - - Code.GenLabel(L2); - if (not IsValue(r1)) or not IsValue(r2) then begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end else begin - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat or CodeGeneratorContext.Registers[r2].IsWhat; - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - end; - bntUNARYEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression,DestRegNr,true); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; - end; - bntUNARYOPERATOREXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression,DestRegNr,true); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; - end; - bntUNARYPLUSEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - PR:=Code.Here; - vta:=CodeGeneratorContext.VariableGetTypes; - r1:=-1; - Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValueNumber(r1) then begin - if IsValue(r1) or IsLocalVariableReference(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,DestRegNr,true); - end else begin - GenGetValue(r1,DestRegNr); - end; - end else begin - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - Code.GenOp(bopTONUMBER,DestRegNr,r2); - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntUNARYMINUSEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r3,r2); - end; - Code.GenOp(bopNEG,DestRegNr,r3); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntUNARYBITWISENOTEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueNumber(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r3,r2); - end; - Code.GenOp(bopINV,DestRegNr,r3); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntUNARYLOGICALNOTEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - if IsValueBoolean(r1) then begin - r3:=r2; - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r3,r2); - end; - Code.GenOp(bopNOT,DestRegNr,r3); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - end; - bntUNARYVOIDEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - CodeGeneratorContext.DeallocateRegister(r2); - end; - CodeGeneratorContext.DeallocateRegister(r1); - Code.GenLiteral(BESENUndefinedValue,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; - end; - bntUNARYTYPEOFEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - Code.GenOp(bopTYPEOF,DestRegNr,r1); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end; - bntPROPERTYEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if TBESENASTNodePropertyExpression(ToVisit).Dot then begin - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - r3:=CodeGeneratorContext.AllocateRegister; - if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral then begin - v:=BESENStringValue(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value); - Code.GenLiteral(v,r3); - end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeNumberLiteral then begin - v:=BESENNumberValue(TBESENASTNodeNumberLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value); - v:=BESENStringValue(TBESEN(Instance).ToStr(v)); - Code.GenLiteral(v,r3); - end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeBooleanLiteral then begin - v.ValueType:=bvtBOOLEAN; - v.Bool:=TBESENASTNodeBooleanLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value; - v:=BESENStringValue(TBESEN(Instance).ToStr(v)); - Code.GenLiteral(v,r3); - end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeNullLiteral then begin - v:=BESENNullValue; - v:=BESENStringValue(TBESEN(Instance).ToStr(v)); - Code.GenLiteral(v,r3); - end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeIdentifier then begin - v:=BESENStringValue(TBESENASTNodeIdentifier(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Name); - Code.GenLiteral(v,r3); - end; - if not IsValueObject(r1) then begin - Code.GenOp(bopCHECKOBJECTCOERCIBLE,r2); - end; - Hash:=BESENHashKey(v.Str); - Code.GenOp(bopREF,DestRegNr,r2,r3,TBESEN(Instance).KeyIDManager.Get(v.Str,Hash),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end else begin - if IsValue(r1) or IsLocalVariableReference(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - end; - r3:=-1; - Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression,r3,true); - if r3<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r3) then begin - r4:=r3; - end else begin - r4:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r3,r4); - end; - if not IsValueObject(r1) then begin - Code.GenOp(bopCHECKOBJECTCOERCIBLE,r2); - end; - if IsValueNumber(r3) then begin - r5:=r4; - if TBESENASTNodePropertyExpression(ToVisit).RightExpression.NodeType=bntNUMBERLITERAL then begin - Code.GenOp(bopAREF,DestRegNr,r2,r4,BESENHashKey(TBESEN(Instance).ToStr(BESENNumberValue(TBESENASTNodeNumberLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value)))); - end else begin - Code.GenOp(bopAREF,DestRegNr,r2,r4,0); - end; - end else begin - if IsValueString(r3) then begin - r5:=r4; - end else begin - r5:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOSTRING,r5,r4); - end; - if TBESENASTNodePropertyExpression(ToVisit).RightExpression.NodeType=bntSTRINGLITERAL then begin - Code.GenOp(bopREF,DestRegNr,r2,r5,TBESEN(Instance).KeyIDManager.Get(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value),BESENHashKey(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value),Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - end else begin - Code.GenOp(bopREF,DestRegNr,r2,r5,TBESENINT32($fefefefe),0,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); - end; - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - CodeGeneratorContext.DeallocateRegister(r4); - CodeGeneratorContext.DeallocateRegister(r5); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; - end; - bntLOGICALANDEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - pr:=Code.Here; - r1:=-1; - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) and not IsLocalVariableReference(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.VariableSetTypes(vta); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(pr); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,DestRegNr,true); - end else begin - GenGetValue(r1,DestRegNr); - end; - IsWhat1:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; - if IsValueBoolean(DestRegNr) then begin - r2:=DestRegNr; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTOBOOLEAN,r2,DestRegNr); - end; - L1:=Code.GenOp(bopJZ,0,r2)+1; - L2:=Code.GenOp(bopJMP,0)+1; - Code.GenLabel(L1); - CodeGeneratorContext.DeallocateRegister(r1); - if r2<>DestRegNr then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - r2:=-1; - - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - pr:=Code.Here; - r1:=-1; - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) and not IsLocalVariableReference(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.VariableSetTypes(vta); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(pr); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,DestRegNr,true); - end else begin - GenGetValue(r1,DestRegNr); - end; - IsWhat2:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; - Code.GenLabel(L2); - CodeGeneratorContext.DeallocateRegister(r1); - - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=IsWhat1 or IsWhat2; - - end; - bntLOGICALOREXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - pr:=Code.Here; - r1:=-1; - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) and not IsLocalVariableReference(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.VariableSetTypes(vta); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(pr); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,DestRegNr,true); - end else begin - GenGetValue(r1,DestRegNr); - end; - IsWhat1:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; - if IsValueBoolean(DestRegNr) then begin - r2:=DestRegNr; - end else begin - Code.GenOp(bopTOBOOLEAN,r2,DestRegNr); - end; - L1:=Code.GenOp(bopJZ,0,r2)+1; - CodeGeneratorContext.DeallocateRegister(r1); - if r2<>DestRegNr then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - r2:=-1; - - vta:=CodeGeneratorContext.VariableGetTypes; - CodeGeneratorContext.GetRegisterStates(RegStates[0]); - pr:=Code.Here; - r1:=-1; - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) and not IsLocalVariableReference(r1) then begin - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.VariableSetTypes(vta); - CodeGeneratorContext.SetRegisterStates(RegStates[0]); - Code.Restore(pr); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,DestRegNr,true); - end else begin - GenGetValue(r1,DestRegNr); - end; - IsWhat2:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; - CodeGeneratorContext.DeallocateRegister(r1); - Code.GenLabel(L1); - - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=IsWhat1 or IsWhat2; - end; - bntDELETEEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=-1; - Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if TBESENASTNodeDeleteExpression(ToVisit).SubExpression.NodeType=bntIDENTIFIER then begin - CodeGeneratorContext.VariableSetFlags(TBESENASTNodeIdentifier(TBESENASTNodeDeleteExpression(ToVisit).SubExpression).Name,false,false); - end; - Code.GenOp(bopDELETE,DestRegNr,r1); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; - AssignSetType(TBESENASTNodeDeleteExpression(ToVisit).SubExpression,bvtUNDEFINED); - end; - bntPOSTFIXINCEXPRESSION:begin - if IsNodeLocalVarReg(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1) then begin - r1:=-1; - Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1,true); - if IsValueNumber(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r2,r1); - end; - if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenOp(bopCOPYNUM,DestRegNr,r2); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - Code.GenOp(bopINC,r1,r2); - AssignSetType(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,bvtNUMBER); - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end else begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - PR:=Code.Here; - r1:=-1; - vta:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and - CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - if IsValueNumber(r1) then begin - GenGetValueEx(r1,DestRegNr); - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValueEx(r1,r2); - Code.GenOp(bopTONUMBER,DestRegNr,r2); - end; - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopINC,r3,DestRegNr); - GenPutValueEx(r1,r3,bvtNUMBER); - end else begin - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - if IsValueNumber(r1) then begin - GenGetValue(r1,DestRegNr); - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - Code.GenOp(bopTONUMBER,DestRegNr,r2); - end; - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopINC,r3,DestRegNr); - GenPutValue(r1,r3,bvtNUMBER); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - AssignSetWhatType(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - bntPOSTFIXDECEXPRESSION:begin - if IsNodeLocalVarReg(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1) then begin - r1:=-1; - Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1,true); - if IsValueNumber(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r2,r1); - end; - if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenOp(bopCOPYNUM,DestRegNr,r2); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - Code.GenOp(bopDEC,r1,r2); - AssignSetType(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,bvtNUMBER); - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end else begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - PR:=Code.Here; - r1:=-1; - vta:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and - CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - if IsValueNumber(r1) then begin - GenGetValueEx(r1,DestRegNr); - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValueEx(r1,r2); - Code.GenOp(bopTONUMBER,DestRegNr,r2); - end; - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopDEC,r3,DestRegNr); - GenPutValueEx(r1,r3,bvtNUMBER); - end else begin - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - if IsValueNumber(r1) then begin - GenGetValue(r1,DestRegNr); - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - Code.GenOp(bopTONUMBER,DestRegNr,r2); - end; - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopDEC,r3,DestRegNr); - GenPutValue(r1,r3,bvtNUMBER); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - AssignSetWhatType(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - bntPREFIXINCEXPRESSION:begin - if IsNodeLocalVarReg(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1) then begin - r1:=-1; - Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1,true); - if IsValueNumber(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r2,r1); - end; - Code.GenOp(bopINC,r1,r2); - if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin - if DestRegNr<0 then begin - DestRegNr:=r1; - end else begin - Code.GenOp(bopCOPYNUM,DestRegNr,r1); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - end; - AssignSetType(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,bvtNUMBER); - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end else begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - PR:=Code.Here; - r1:=-1; - vta:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and - CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - r2:=CodeGeneratorContext.AllocateRegister; - if IsValueNumber(r1) then begin - GenGetValueEx(r1,r2); - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValueEx(r1,r3); - Code.GenOp(bopTONUMBER,r2,r3); - CodeGeneratorContext.DeallocateRegister(r3); - end; - Code.GenOp(bopINC,DestRegNr,r2); - GenPutValueEx(r1,DestRegNr,bvtNUMBER); - end else begin - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - r2:=CodeGeneratorContext.AllocateRegister; - if IsValueNumber(r1) then begin - GenGetValue(r1,r2); - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r3); - Code.GenOp(bopTONUMBER,r2,r3); - CodeGeneratorContext.DeallocateRegister(r3); - end; - Code.GenOp(bopINC,DestRegNr,r2); - GenPutValue(r1,DestRegNr,bvtNUMBER); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - AssignSetWhatType(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - bntPREFIXDECEXPRESSION:begin - if IsNodeLocalVarReg(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1) then begin - r1:=-1; - Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1,true); - if IsValueNumber(r1) then begin - r2:=r1; - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopTONUMBER,r2,r1); - end; - Code.GenOp(bopDEC,r1,r2); - if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin - if DestRegNr<0 then begin - DestRegNr:=r1; - end else begin - Code.GenOp(bopCOPYNUM,DestRegNr,r1); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - end; - AssignSetType(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,bvtNUMBER); - if r1<>r2 then begin - CodeGeneratorContext.DeallocateRegister(r2); - end; - end else begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - PR:=Code.Here; - r1:=-1; - vta:=CodeGeneratorContext.VariableGetTypes; - Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and - CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.Restore(PR); - CodeGeneratorContext.VariableSetTypes(vta); - r2:=CodeGeneratorContext.AllocateRegister; - if IsValueNumber(r1) then begin - GenGetValueEx(r1,r2); - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValueEx(r1,r3); - Code.GenOp(bopTONUMBER,r2,r3); - CodeGeneratorContext.DeallocateRegister(r3); - end; - Code.GenOp(bopDEC,DestRegNr,r2); - GenPutValueEx(r1,DestRegNr,bvtNUMBER); - end else begin - if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin - if not CodeGeneratorContext.Registers[r1].IsLocal then begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - end else begin - Code.GenOp(bopSTRICTCHECKREF,r1); - end; - r2:=CodeGeneratorContext.AllocateRegister; - if IsValueNumber(r1) then begin - GenGetValue(r1,r2); - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r3); - Code.GenOp(bopTONUMBER,r2,r3); - CodeGeneratorContext.DeallocateRegister(r3); - end; - Code.GenOp(bopDEC,DestRegNr,r2); - GenPutValue(r1,DestRegNr,bvtNUMBER); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - AssignSetWhatType(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - bntNULLLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLiteral(BESENNullValue,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; - end; - bntNUMBERLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLiteral(BESENNumberValue(TBESENASTNodeNumberLiteral(ToVisit).Value),DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; - end; - bntREGEXPLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if CodeGeneratorContext.MaxParamArgs<2 then begin - CodeGeneratorContext.MaxParamArgs:=2; - end; - r1:=CodeGeneratorContext.AllocateRegister; - r2:=CodeGeneratorContext.AllocateRegister; - r3:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopREGEXP,r1); - Code.GenLiteral(BESENStringValue(TBESENASTNodeRegExpLiteral(ToVisit).Source),r2); - Code.GenLiteral(BESENStringValue(TBESENASTNodeRegExpLiteral(ToVisit).Flags),r3); - Code.GenOp(bopNEW,DestRegNr,r1,2,r2,r3); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; - bntSTRINGLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLiteral(BESENStringValue(TBESENASTNodeStringLiteral(ToVisit).Value),DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; - end; - bntTHISLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenOp(bopTHIS,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; - end; - bntOBJECTLITERALPROPERTY:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType of - banolptACCESSOR:begin - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - r1:=CodeGeneratorContext.AllocateRegister; - Code.GenLiteral(BESENStringValue(TBESENASTNodeObjectLiteralProperty(ToVisit).Name),r1); - r2:=-1; - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - CodeGeneratorContext.DeallocateRegister(r2); - r2:=CodeGeneratorContext.AllocateRegister; - Code.GenFunction(TBESENASTNodeObjectLiteralProperty(ToVisit).Container,r2); - case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType of - banolpatGET:begin - Code.GenOp(bopPUTOBJGET,DestRegNr,r1,r2); - end; - banolpatSET:begin - Code.GenOp(bopPUTOBJSET,DestRegNr,r1,r2); - end; - else begin - Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r2); - end; - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - end; - end; - banolptDATA:begin - r1:=CodeGeneratorContext.AllocateRegister; - Code.GenLiteral(BESENStringValue(TBESENASTNodeObjectLiteralProperty(ToVisit).Name),r1); - r2:=-1; - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value,r2,true); - if r2<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r2) then begin - Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r2); - end else begin - r3:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r2,r3); - Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r3); - end; - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - CodeGeneratorContext.DeallocateRegister(r3); - end; - end; - end; - bntOBJECTLITERAL:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - r1:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopOBJECT,r1); - Code.GenOp(bopNEW,DestRegNr,r1,0); - CodeGeneratorContext.DeallocateRegister(r1); - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter],DestRegNr,true); - end; - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - end; - bntRETURNSTATEMENT:begin - Code.GenLocation(ToVisit.Location); - if assigned(TBESENASTNodeReturnStatement(ToVisit).Expression) then begin - r1:=-1; - Visit(TBESENASTNodeReturnStatement(ToVisit).Expression,r1,true); - if r1<0 then begin - BESENThrowCodeGeneratorInvalidRegister; - end; - if IsValue(r1) or IsLocalVariableReference(r1) then begin - GenSetC(r1); - CodeGeneratorContext.DeallocateRegister(r1); - end else begin - r2:=CodeGeneratorContext.AllocateRegister; - GenGetValue(r1,r2); - GenSetC(r2); - CodeGeneratorContext.DeallocateRegister(r1); - CodeGeneratorContext.DeallocateRegister(r2); - end; - Code.GenOp(bopEND,0); - end else begin - Code.GenOp(bopSETCUNDEF); - Code.GenOp(bopEND,0); - end; - end; - bntPROGRAM:begin - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - Code.GenLocation(ToVisit.Location); - OldOptimizeLocals:=OptimizeLocals; - OldDoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; - OptimizeLocals:=false; - DoHoldLocalVariablesInRegisters:=false; - Visit(TBESENASTNodeProgram(ToVisit).Body,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); - OptimizeLocals:=OldOptimizeLocals; - DoHoldLocalVariablesInRegisters:=OldDoHoldLocalVariablesInRegisters; - if TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).ByteCodeLen=0 then begin - TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).GenOp(bopEND,0); - end; - TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).Finish; - end; - bntFUNCTIONEXPRESSION:begin - if DestRegNr<0 then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - end; - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - r1:=-1; - Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal,r1,false); - CodeGeneratorContext.DeallocateRegister(r1); - Code.GenFunction(TBESENASTNodeFunctionExpression(ToVisit).Container,DestRegNr); - CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; - end; - end; - end; - end; - if CalleeNeedReturnedValue and (DestRegNr<0) then begin - DestRegNr:=CodeGeneratorContext.AllocateRegister; - Code.GenOp(bopLITERALUNDEF,DestRegNr); - end; - for Counter:=low(RegStates) to high(RegStates) do begin - SetLength(RegStates[Counter].Registers,0); - end; - SetLength(vta,0); - SetLength(vtb,0); - SetLength(vtc,0); - SetLength(vtd,0); - SetLength(vte,0); - SetLength(vtTemp,0); - SetLength(vtBegin,0); - SetLength(vtInner,0); - SetLength(vtEnd,0); - SetLength(Operands,0); - end; - var tr:integer; - begin - Code:=TBESENCode.Create(Instance); - try - CodeGeneratorContext:=TBESENCodeGeneratorContext.Create(Instance); - try - CodeGeneratorContext.Code:=Code; - DoHasLocalDelete:=false; - DoIsComplexFunction:=false; - DoHasMaybeDirectEval:=false; - OptimizeLocals:=false; - HasFunctions:=false; - DoHoldLocalVariablesInRegisters:=false; - tr:=-1; - Visit(RootNode,tr,false); - finally - CodeGeneratorContext.Free; - end; - finally - Code.Free; - end; - end; -var Parser:TBESENParser; - RootNode:TBESENASTNode; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:TFPUExceptionMask; - OldFPURoundingMode:TFPURoundingMode; - OldFPUPrecisionMode:TFPUPrecisionMode; -{$endif} -begin - result:=nil; - Parser:=nil; - RootNode:=nil; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:=GetExceptionMask; - OldFPURoundingMode:=GetRoundMode; - OldFPUPrecisionMode:=GetPrecisionMode; -{$endif} - try -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(BESENFPUExceptionMask); - end; - if OldFPURoundingMode<>rmNearest then begin - SetRoundMode(rmNearest); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(BESENFPUPrecisionMode); - end; -{$endif} - try - // Parse the code - Parser:=TBESENParser.Create(Instance); - if IsFunction then begin - Parser.Lexer.Source:='function('+Parameters+'){'+InputSource+'}'; - end else begin - Parser.Lexer.Source:=InputSource; - end; - Parser.Init; - RootNode:=Parser.Parse(IsFunction,IsJSON); - BESENFreeAndNil(Parser); - - // Scan, collect variables/functions and preprocess the abstract syntax tree - ScanCollectAndPreprocess(RootNode); - - // Optimize the abstract syntax tree - RootNode:=Optimize(RootNode); - - // Generate the byte code - GenerateByteCode(RootNode); - - if assigned(RootNode) then begin - result:=RootNode; - end; - except - BESENFreeAndNil(RootNode); - BESENFreeAndNil(Parser); - raise; - end; - finally -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(OldFPUExceptionMask); - end; - if OldFPURoundingMode<>rmNearest then begin - SetRoundMode(OldFPURoundingMode); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(OldFPUPrecisionMode); - end; -{$endif} - end; -end; - - -end. diff --git a/3rd/besen/src/BESENConstants.pas b/3rd/besen/src/BESENConstants.pas deleted file mode 100644 index cdea9090e..000000000 --- a/3rd/besen/src/BESENConstants.pas +++ /dev/null @@ -1,103 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENConstants; -{$i BESEN.inc} - -interface - -uses Math; - -{$ifndef BESENNoFPU} -const BESENFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; - - BESENFPUPrecisionMode:TFPUPrecisionMode={$ifdef HAS_TYPE_EXTENDED}pmEXTENDED{$else}pmDOUBLE{$endif}; -{$endif} - -{$ifndef fpc} -const FPC_VERSION=2; - FPC_RELEASE=5; - FPC_PATCH=1; -{$endif} - -const COMPAT_UTF8_UNSAFE=1 shl 1; // accept 'valid but insecure' UTF8 - COMPAT_SGMLCOM=1 shl 2; // treat '<!--' as a '//' comment - COMPAT_BESEN=1 shl 3; // BESEN-specific extensions - COMPAT_JS=1 shl 4; // JavaScript-specific extensions - - BESEN_GC_MARKFACTOR:integer=25; - BESEN_GC_TRIGGERCOUNT_PER_COLLECT:integer=1; - - bimMAXIDENTS=1 shl 24; - - BESENHashItemsPerBucketsThreshold:longword=5; - BESENHashMaxSize:longword=1 shl 16; - - BESENMaxCountOfFreeCodeContexts:integer=16; - - BESENMaxCountOfFreeContexts:integer=16; - - BESEN_JIT_LOOPCOMPILETHRESHOLD:longword=1000; - - BESEN_CMWCRND_A=18782; - BESEN_CMWCRND_M=longword($fffffffe); - BESEN_CMWCRND_BITS=12; - BESEN_CMWCRND_SIZE=1 shl BESEN_CMWCRND_BITS; - BESEN_CMWCRND_MASK=BESEN_CMWCRND_SIZE-1; - - bncmmMINBLOCKCONTAINERSIZE=1048576; - - bcttNOTARGET=0; - - BESENEvalCacheSize:integer=256; - BESENEvalCacheMaxSourceLength:integer=256; - - bncfZERO=1 shl 0; - bncfNAN=1 shl 1; - bncfINFINITE=1 shl 2; - bncfNEGATIVE=1 shl 3; - - BESENObjectStructureIDManagerHashSize=65536; - BESENObjectStructureIDManagerHashSizeMask=BESENObjectStructureIDManagerHashSize-1; - - BESENPolymorphicInlineCacheSize=8; - BESENPolymorphicInlineCacheSizeMask=BESENPolymorphicInlineCacheSize-1; - - BESENPolymorphicInlineCacheStartItemPositions=longword((0 shl 0) or (1 shl 4) or (2 shl 8) or (3 shl 12) or (4 shl 16) or (5 shl 20) or (6 shl 24) or (7 shl 28)); - - BESENLongBooleanValues:array[boolean] of longbool=(false,true); - - BESENNumberBooleanValues:array[boolean] of integer=(0,1); - - BESENInt32BooleanValues:array[boolean] of integer=(0,longint(longword($ffffffff))); - -implementation - -end. diff --git a/3rd/besen/src/BESENContext.pas b/3rd/besen/src/BESENContext.pas deleted file mode 100644 index 9914497c1..000000000 --- a/3rd/besen/src/BESENContext.pas +++ /dev/null @@ -1,452 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENContext; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENObjectPropertyDescriptor, - BESENLexicalEnvironment,BESENASTNodes, - BESENEnvironmentRecord,BESENStringTree, - BESENObjectFunctionArguments; - -type TBESENContextCache=class; - - TBESENContext=class(TBESENCollectorObject) - private - Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; - Temp:TBESENValue; - public - Cache:TBESENContextCache; - CachePrevious,CacheNext:TBESENContext; - Previous,Next:TBESENContext; - CodeContext:TObject; - LexicalEnvironment:TBESENLexicalEnvironment; - VariableEnvironment:TBESENLexicalEnvironment; - ThisBinding:TBESENValue; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Reset; - function CreateArgumentsObject(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;Arguments:PPBESENValues;CountArguments:integer;const Env:TBESENEnvironmentRecord;const IsStrict:longbool):TBESENObjectFunctionArguments; - procedure InitializeDeclarationBindingInstantiation(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;const IsEval:boolean;Arguments:PPBESENValues;CountArguments:integer;const Reinitialize:boolean); - procedure Mark; - end; - - TBESENContextCacheItems=array of TBESENContext; - - TBESENContextCache=class(TBESENCollectorObject) - public - First,Last:TBESENContext; - Count:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Clear; - procedure Cleanup; - procedure Push(Context:TBESENContext); - function Pop:TBESENContext; - procedure Mark; - end; - -implementation - -uses BESEN,BESENUtils,BESENDeclarativeEnvironmentRecord,BESENObject, - BESENArrayUtils,BESENCodeContext,BESENErrors, - BESENObjectDeclaredFunction,BESENObjectArgGetterFunction, - BESENObjectArgSetterFunction; - -constructor TBESENContext.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Cache:=nil; - CachePrevious:=nil; - CacheNext:=nil; - Previous:=TBESEN(Instance).ContextLast; - Next:=nil; - if assigned(Previous) then begin - Previous.Next:=self; - end else begin - TBESEN(Instance).ContextFirst:=self; - end; - TBESEN(Instance).ContextLast:=self; - CodeContext:=nil; - LexicalEnvironment:=nil; - VariableEnvironment:=nil; - ThisBinding.ValueType:=bvtUNDEFINED; -end; - -destructor TBESENContext.Destroy; -begin - if assigned(Instance) and assigned(TBESEN(Instance).GarbageCollector) and (TBESEN(Instance).GarbageCollector.CurrentContext=self) then begin - TBESEN(Instance).GarbageCollector.CurrentContext:=Next; - end; - if assigned(Previous) then begin - Previous.Next:=Next; - end else if TBESEN(Instance).ContextFirst=self then begin - TBESEN(Instance).ContextFirst:=Next; - end; - if assigned(Next) then begin - Next.Previous:=Previous; - end else if TBESEN(Instance).ContextLast=self then begin - TBESEN(Instance).ContextLast:=Previous; - end; - Next:=nil; - Previous:=nil; - BESENFreeAndNil(CodeContext); - if assigned(Cache) then begin - dec(Cache.Count); - if assigned(CachePrevious) then begin - CachePrevious.CacheNext:=CacheNext; - end else if Cache.First=self then begin - Cache.First:=CacheNext; - end; - if assigned(CacheNext) then begin - CacheNext.CachePrevious:=CachePrevious; - end else if Cache.Last=self then begin - Cache.Last:=CachePrevious; - end; - Cache:=nil; - CacheNext:=nil; - CachePrevious:=nil; - end; - inherited Destroy; -end; - -procedure TBESENContext.Reset; -begin - CodeContext:=nil; - ThisBinding.ValueType:=bvtUNDEFINED; - while assigned(VariableEnvironment) and assigned(VariableEnvironment.EnvironmentRecord) do begin - if VariableEnvironment.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord then begin - break; - end; - VariableEnvironment:=VariableEnvironment.Outer; - end; - if not (assigned(VariableEnvironment) and assigned(VariableEnvironment.EnvironmentRecord) and (VariableEnvironment.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord)) then begin - VariableEnvironment:=nil; - end; - LexicalEnvironment:=nil; -end; - -function TBESENContext.CreateArgumentsObject(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;Arguments:PPBESENValues;CountArguments:integer;const Env:TBESENEnvironmentRecord;const IsStrict:longbool):TBESENObjectFunctionArguments; -var Len,Index,NamesCount:integer; - Map:TBESENObject; - Val:TBESENValue; - Name:TBESENString; - MappedNames:TBESENStringTree; - MappedNamesCount:integer; - StringTreeData:TBESENStringTreeData; - function MakeArgGetter(const Name:TBESENString;const Env:TBESENEnvironmentRecord):TBESENObjectArgGetterFunction; - begin - result:=TBESENObjectArgGetterFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,true); - TBESEN(Instance).GarbageCollector.Add(result); - result.Env:=Env; - result.ArgName:=Name; - end; - function MakeArgSetter(const Name:TBESENString;const Env:TBESENEnvironmentRecord):TBESENObjectArgSetterFunction; - begin - result:=TBESENObjectArgSetterFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,true); - TBESEN(Instance).GarbageCollector.Add(result); - result.Env:=Env; - result.ArgName:=Name; - end; -begin - Len:=CountArguments; - NamesCount:=length(TBESENObjectDeclaredFunction(FunctionObject).Parameters); - result:=TBESENObjectFunctionArguments.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - result.GarbageCollectorLock; - try - result.IsStrict:=IsStrict; - result.OverwriteData('length',BESENNumberValue(Len),[bopaWRITABLE,bopaCONFIGURABLE],false); - Map:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); - MappedNames:=TBESENStringTree.Create; - MappedNamesCount:=0; - try - for Index:=Len-1 downto 0 do begin - BESENCopyValue(Val,Arguments^[Index]^); - result.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENDataPropertyDescriptor(Val,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - if (not IsStrict) and (Index<NamesCount) then begin - Name:=TBESENObjectDeclaredFunction(FunctionObject).Parameters[Index]; - if not MappedNames.Find(Name,StringTreeData) then begin - StringTreeData.i:=Index; - MappedNames.Add(Name,StringTreeData,true); - inc(MappedNamesCount); - Map.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENAccessorPropertyDescriptor(MakeArgGetter(Name,Env),MakeArgSetter(Name,Env),[bopaCONFIGURABLE]),false); - end; - end; - end; - finally - MappedNames.Free; - end; - if MappedNamesCount>0 then begin - result.ParameterMap:=Map; - end; - if IsStrict then begin - result.OverwriteAccessor('caller',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); - result.OverwriteAccessor('callee',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); - end else begin - result.OverwriteData('callee',BESENObjectValueEx(TBESENObjectDeclaredFunction(FunctionObject)),[bopaWRITABLE,bopaCONFIGURABLE],false); - end; - finally - result.GarbageCollectorUnlock; - end; -end; - -procedure TBESENContext.InitializeDeclarationBindingInstantiation(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;const IsEval:boolean;Arguments:PPBESENValues;CountArguments:integer;const Reinitialize:boolean); - procedure SetParameters(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const IsStrict:boolean;const ParamCount:integer); - var i,j:integer; - ArgName:PBESENString; - v:PBESENValue; - begin - if (Env is TBESENDeclarativeEnvironmentRecord) and TBESENDeclarativeEnvironmentRecord(Env).IndexInitialized then begin - for i:=0 to ParamCount-1 do begin - j:=Body.Parameters[i].ParameterIndex; - if i<CountArguments then begin - BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Env).HashValues[j]^,Arguments^[i]^); - end else begin - TBESENDeclarativeEnvironmentRecord(Env).HashValues[j]^.ValueType:=bvtUNDEFINED; - end; - end; - end else begin - for i:=0 to ParamCount-1 do begin - ArgName:=@Body.Parameters[i].Name; - if i<CountArguments then begin - v:=Arguments^[i]; - end else begin - v:=@BESENUndefinedValue; - end; - if not Env.HasBindingEx(ArgName^,Descriptor) then begin - Env.CreateMutableBinding(ArgName^); - end; - Env.SetMutableBindingEx(ArgName^,v^,IsStrict,Descriptor,OwnDescriptor,Temp); - end; - end; - end; - procedure SetFunctions(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const ConfigurableBindings,IsStrict:boolean); - var i:integer; - fn:PBESENString; - fd:TBESENASTNodeFunctionDeclaration; - fo:TBESENObjectDeclaredFunction; - go:TBESENObject; - begin - for i:=0 to length(Body.Functions)-1 do begin - if assigned(Body.Functions[i]) and (Body.Functions[i] is TBESENASTNodeFunctionDeclaration) then begin - if assigned(TBESENASTNodeFunctionDeclaration(Body.Functions[i]).Container.Literal) and assigned(TBESENASTNodeFunctionDeclaration(Body.Functions[i]).Container.Literal.Name) then begin - fd:=TBESENASTNodeFunctionDeclaration(Body.Functions[i]); - fn:=@fd.Container.Literal.Name.Name; - fo:=TBESEN(Instance).MakeFunction(fd.Container.Literal,fd.Container.Literal.Name.Name,LexicalEnvironment); - if not Env.HasBindingEx(fn^,Descriptor) then begin - Env.CreateMutableBinding(fn^,ConfigurableBindings); - end else if Env=TBESEN(Instance).GlobalLexicalEnvironment.EnvironmentRecord then begin - // ES5-errata fix - go:=TBESEN(Instance).ObjectGlobal; - go.GetProperty(fn^,Descriptor); - if (boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes) then begin - if ConfigurableBindings then begin - go.DefineOwnPropertyEx(fn^,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true,Descriptor); - end else begin - go.DefineOwnPropertyEx(fn^,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE]),true,Descriptor); - end; - end else if (([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) or ((([boppWRITABLE,boppENUMERABLE]*Descriptor.Presents)<>[boppWRITABLE,boppENUMERABLE]) or (([bopaWRITABLE,bopaENUMERABLE]*Descriptor.Attributes)<>[bopaWRITABLE,bopaENUMERABLE])) then begin - BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(fn^); - end; - end; - Env.SetMutableBinding(fn^,BESENObjectValue(fo),IsStrict); - end; - end; - end; - end; - procedure SetArguments(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const IsStrict:boolean); - var ArgsObj:TBESENObjectFunctionArguments; - begin - ArgsObj:=CreateArgumentsObject(Body,TBESENObjectDeclaredFunction(FunctionObject),Arguments,CountArguments,Env,IsStrict); - if IsStrict then begin - Env.CreateImmutableBinding('arguments'); - Env.InitializeImmutableBinding('arguments',BESENObjectValue(ArgsObj)); - end else begin - Env.CreateMutableBinding('arguments'); - Env.SetMutableBindingEx('arguments',BESENObjectValue(ArgsObj),false,Descriptor,OwnDescriptor,Temp); - end; - end; - procedure SetVariables(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const ConfigurableBindings,IsStrict:boolean); - var i:integer; - d:TBESENASTNodeIdentifier; - dn:PBESENString; - begin - for i:=0 to length(Body.Variables)-1 do begin - d:=Body.Variables[i]; - if assigned(d) and (length(d.Name)>0) then begin - dn:=@d.Name; - if not Env.HasBindingEx(dn^,Descriptor) then begin - Env.CreateMutableBinding(dn^,ConfigurableBindings); - Env.SetMutableBindingEx(dn^,BESENUndefinedValue,IsStrict,Descriptor,OwnDescriptor,Temp); - end; - end; - end; - end; -var IsFunction:boolean; - ParamCount:integer; - Env:TBESENEnvironmentRecord; -begin - Env:=VariableEnvironment.EnvironmentRecord; - IsFunction:=assigned(TBESENObjectDeclaredFunction(FunctionObject)) and Body.IsFunction; - if IsFunction then begin - ParamCount:=length(Body.Parameters); - if ParamCount>0 then begin - SetParameters(Body,Env,Body.IsStrict,ParamCount); - end; - end; - if length(Body.Functions)>0 then begin - SetFunctions(Body,Env,IsEval,Body.IsStrict); - end; - if not Reinitialize then begin - if IsFunction and not (Body.DisableArgumentsObject or Env.HasBinding('arguments')) then begin - SetArguments(Body,Env,Body.IsStrict); - end; - SetVariables(Body,Env,IsEval,Body.IsStrict); - end; - if Env.RecordType=BESENEnvironmentRecordTypeDeclarative then begin - TBESENDeclarativeEnvironmentRecord(Env).Touched:=false; - end; -end; - -procedure TBESENContext.Mark; -var i:integer; -begin - if assigned(LexicalEnvironment) then begin - TBESEN(Instance).GarbageCollector.GrayIt(LexicalEnvironment); - end; - if assigned(VariableEnvironment) then begin - TBESEN(Instance).GarbageCollector.GrayIt(VariableEnvironment); - end; - TBESEN(Instance).GarbageCollector.GrayValue(ThisBinding); - if assigned(CodeContext) then begin - if assigned(TBESENCodeContext(CodeContext).Code) then begin - TBESENCodeContext(CodeContext).Code.Mark; - end; - for i:=0 to length(TBESENCodeContext(CodeContext).RegisterValues)-1 do begin - TBESEN(Instance).GarbageCollector.GrayValue(TBESENCodeContext(CodeContext).RegisterValues[i]); - end; - end; -end; - -constructor TBESENContextCache.Create(AInstance:TObject); -begin - inherited Create(AInstance); - First:=nil; - Last:=nil; - Count:=0; -end; - -destructor TBESENContextCache.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENContextCache.Clear; -var CurrentContext:TBESENContext; -begin - while true do begin - CurrentContext:=Pop; - if assigned(CurrentContext) then begin - BESENFreeAndNil(CurrentContext); - end else begin - break; - end; - end; -end; - -procedure TBESENContextCache.Cleanup; -var CurrentContext:TBESENContext; -begin - while Count>TBESEN(Instance).MaxCountOfFreeContexts do begin - CurrentContext:=Pop; - if assigned(CurrentContext) then begin - BESENFreeAndNil(CurrentContext); - end else begin - break; - end; - end; -end; - -procedure TBESENContextCache.Push(Context:TBESENContext); -begin - Context.Cache:=self; - if assigned(Last) then begin - Last.CacheNext:=Context; - Context.CachePrevious:=Last; - Context.CacheNext:=nil; - Last:=Context; - end else begin - First:=Context; - Last:=Context; - Context.CachePrevious:=nil; - Context.CacheNext:=nil; - end; - inc(Count); -end; - -function TBESENContextCache.Pop:TBESENContext; -begin - if assigned(Last) then begin - result:=Last; - if assigned(result.CachePrevious) then begin - result.CachePrevious.CacheNext:=result.CacheNext; - end else if First=result then begin - First:=result.CacheNext; - end; - if assigned(result.CacheNext) then begin - result.CacheNext.CachePrevious:=result.CachePrevious; - end else if Last=result then begin - Last:=result.CachePrevious; - end; - result.Cache:=nil; - result.CachePrevious:=nil; - result.CacheNext:=nil; - dec(Count); - end else begin - result:=nil; - Count:=0; - end; -end; - -procedure TBESENContextCache.Mark; -var CurrentContext:TBESENContext; -begin - CurrentContext:=First; - while assigned(CurrentContext) do begin - CurrentContext.Mark; - CurrentContext:=CurrentContext.CacheNext; - end; -end; - -end. diff --git a/3rd/besen/src/BESENDateUtils.pas b/3rd/besen/src/BESENDateUtils.pas deleted file mode 100644 index 694a984bd..000000000 --- a/3rd/besen/src/BESENDateUtils.pas +++ /dev/null @@ -1,1368 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENDateUtils; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}SysUtils,Classes,BESENConstants,BESENTypes; - -const BESENUnixDateDelta=25569.0; //1970/01/01 - - BESENmsPerDay=86400000.0; - - BESENmsPerY1=375*BESENmsPerDay; - BESENmsPerY4=(4*BESENmsPerY1)+BESENmsPerDay; - BESENmsPerY100=(25*BESENmsPerY4)-BESENmsPerDay; - BESENmsPerY400=(4*BESENmsPerY100)+BESENmsPerDay; - - BESENTime1970=(4*BESENmsPerY400)+(3*BESENmsPerY100)+(17*BESENmsPerY4)+(2*BESENmsPerY1); - - BESENmaxTime=BESENmsPerDay*100000000; - BESENminTime=-BESENmaxTime; - - BESENHoursPerDay=24.0; - BESENMinutesPerHour=60.0; - BESENSecondsPerMinute=60.0; - BESENmsPerSecond=1000.0; - BESENmsPerMinute=BESENmsPerSecond*BESENSecondsPerMinute; - BESENmsPerHour=BESENmsPerMinute*BESENMinutesPerHour; - -function BESENDay(t:TBESENNumber):TBESENNumber; - -function BESENTimeWithinDay(t:TBESENNumber):TBESENNumber; - -function BESENDaysInYear(y:TBESENNumber):TBESENNumber; -function BESENDayFromYear(y:TBESENNumber):TBESENNumber; -function BESENTimeFromYear(y:TBESENNumber):TBESENNumber; - -function BESENYearFromTime(t:TBESENNumber):TBESENNumber; - -function BESENDayWithinYear(t:TBESENNumber):TBESENNumber; - -function BESENWeekDay(t:TBESENNumber):TBESENNumber; - -function BESENIsLeapYear(t:TBESENNumber):boolean; - -function BESENMonthFromTime(t:TBESENNumber):TBESENNumber; -function BESENDayFromTime(t:TBESENNumber):TBESENNumber; -function BESENHourFromTime(t:TBESENNumber):TBESENNumber; -function BESENMinuteFromTime(t:TBESENNumber):TBESENNumber; -function BESENSecondFromTime(t:TBESENNumber):TBESENNumber; -function BESENMillisecondFromTime(t:TBESENNumber):TBESENNumber; -function BESENToIntegerForTime(Num:TBESENNumber):int64; -function BESENToIntForTime(Num:TBESENNumber):TBESENNumber; - -function BESENMakeTime(Hour,Minute,Second,Millisecond:TBESENNumber):TBESENNumber; -function BESENMakeDay(Year,Month,Date:TBESENNumber):TBESENNumber; - -function BESENMakeDate(Day,Time:TBESENNumber):TBESENNumber; - -function BESENTimeClip(const v:TBESENDate):TBESENDate; - -function BESENDateTimeToBESENDate(DateTime:TDateTime):TBESENDate; -function BESENDateToDateTime(BESENDate:TBESENDate):TDateTime; -function BESENSystemTimeToBESENDate(SystemTime:TSystemTime):TBESENDate; -function BESENDateToSystemTime(BESENDate:TBESENDate):TSystemTime; - -function BESENGetUTCDateTime:TDateTime; -function BESENGetUTCBESENDate:TBESENDate; -function BESENGetLocalDateTimeZone:TDateTime; -function BESENGetLocalTZA:TBESENDate; - -function BESENLocalTime(Date:TBESENDate):TBESENDate; -function BESENUTC(Date:TBESENDate):TBESENDate; - -function BESENLocalDateTimeToUTC(DateTime:TDateTime):TDateTime; -function BESENUTCToLocalDateTime(DateTime:TDateTime):TDateTime; - -function BESENGetDateTimeOffsetString(const Ofs:TDateTime):TBESENString; - -function BESENParseISOTime(s:TBESENString):TBESENDate; - -function BESENParseTime(s:TBESENString):TBESENDate; - -function BESENParseNetscapeTime(s:TBESENString):TBESENDate; - -function BESENFormatDateTime(const Format:TBESENSTRING;DateTime:TDateTime;const FormatSettings:TFormatSettings):TBESENSTRING; - -implementation - -uses {$ifdef BESENDelphiHasNoSystemTimeMore}System.DateUtils,{$endif}BESENNumberUtils,BESENStringUtils; - -const ParserMonthNames:array[0..11] of widestring=('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'); - ParserDayNames:array[0..6] of widestring=('sun','mon','tue','wed','thu','fri','sat'); - -function BESENDay(t:TBESENNumber):TBESENNumber; -begin - result:=BESENFloor(t/BESENmsPerDay); -end; - -function BESENTimeWithinDay(t:TBESENNumber):TBESENNumber; -begin - result:=BESENModuloPos(t,BESENmsPerDay); -end; - -function BESENDaysInYear(y:TBESENNumber):TBESENNumber; -var yi:integer; -begin - yi:=trunc(y); - if (yi mod 4)<>0 then begin - result:=365; - end else if (yi mod 100)<>0 then begin - result:=366; - end else if (yi mod 400)<>0 then begin - result:=365; - end else begin - result:=366; - end; -end; - -function BESENDayFromYear(y:TBESENNumber):TBESENNumber; -begin - result:=(365.0*(y-1970))+(BESENFloor((y-1969)/4)-BESENFloor((y-1901)/100))+BESENFloor((y-1601)/400); -end; - -function BESENTimeFromYear(y:TBESENNumber):TBESENNumber; -begin - result:=BESENDayFromYear(y)*BESENmsPerDay; -end; - -function BESENYearFromTime(t:TBESENNumber):TBESENNumber; -var y,t2:TBESENNumber; -begin - y:=BESENFloor(t/(BESENmsPerDay*365.2425))+1970; - t2:=BESENTimeFromYear(y); - if t2>t then begin - y:=y-1; - end else begin - if (t2+(BESENmsPerDay*BESENDaysInYear(y)))<=t then begin - y:=y+1; - end; - end; - result:=y; -end; - -function BESENDayWithinYear(t:TBESENNumber):TBESENNumber; -begin - result:=BESENDay(t)-BESENDayFromYear(BESENYearFromTime(t)); -end; - -function BESENWeekDay(t:TBESENNumber):TBESENNumber; -begin - result:=BESENModuloPos(BESENDay(t)+4,7.0); -end; - -function BESENIsLeapYear(t:TBESENNumber):boolean; -begin - if BESENModuloPos(t,4)<>0 then begin - result:=false; - end else if BESENModuloPos(t,100)<>0 then begin - result:=true; - end else if BESENModuloPos(t,400)<>0 then begin - result:=false; - end else begin - result:=true; - end; -end; - -function BESENMonthFromTime(t:TBESENNumber):TBESENNumber; -var dwy,ily:TBESENNumber; -begin - dwy:=BESENDayWithinYear(t); - if BESENIsLeapYear(BESENYearFromTime(t)) then begin - ily:=1; - end else begin - ily:=0; - end; - if dwy<31 then begin - result:=0; - end else if dwy<(59+ily) then begin - result:=1; - end else if dwy<(90+ily) then begin - result:=2; - end else if dwy<(120+ily) then begin - result:=3; - end else if dwy<(151+ily) then begin - result:=4; - end else if dwy<(181+ily) then begin - result:=5; - end else if dwy<(212+ily) then begin - result:=6; - end else if dwy<(243+ily) then begin - result:=7; - end else if dwy<(273+ily) then begin - result:=8; - end else if dwy<(304+ily) then begin - result:=9; - end else if dwy<(334+ily) then begin - result:=10; - end else if dwy<(365+ily) then begin - result:=11; - end else begin - result:=-1; - end; -end; - -function BESENDayFromTime(t:TBESENNumber):TBESENNumber; -var dwy,ily:TBESENNumber; -begin - dwy:=BESENDayWithinYear(t); - if BESENIsLeapYear(BESENYearFromTime(t)) then begin - ily:=1; - end else begin - ily:=0; - end; - case trunc(BESENMonthFromTime(t)) of - 0:begin - result:=dwy+1; - end; - 1:begin - result:=dwy-30; - end; - 2:begin - result:=dwy-(58+ily); - end; - 3:begin - result:=dwy-(89+ily); - end; - 4:begin - result:=dwy-(119+ily); - end; - 5:begin - result:=dwy-(150+ily); - end; - 6:begin - result:=dwy-(180+ily); - end; - 7:begin - result:=dwy-(211+ily); - end; - 8:begin - result:=dwy-(242+ily); - end; - 9:begin - result:=dwy-(272+ily); - end; - 10:begin - result:=dwy-(303+ily); - end; - 11:begin - result:=dwy-(333+ily); - end; - else begin - result:=-1; - end; - end; -end; - -function BESENHourFromTime(t:TBESENNumber):TBESENNumber; -begin - result:=BESENModuloPos(BESENFloor(t/BESENmsPerHour),BESENHoursPerDay); -end; - -function BESENMinuteFromTime(t:TBESENNumber):TBESENNumber; -begin - result:=BESENModuloPos(BESENFloor(t/BESENmsPerMinute),BESENMinutesPerHour); -end; - -function BESENSecondFromTime(t:TBESENNumber):TBESENNumber; -begin - result:=BESENModuloPos(BESENFloor(t/BESENmsPerSecond),BESENSecondsPerMinute); -end; - -function BESENMillisecondFromTime(t:TBESENNumber):TBESENNumber; -begin - result:=BESENFloor(BESENModuloPos(t,BESENmsPerSecond)); -end; - -function BESENToIntegerForTime(Num:TBESENNumber):int64; -begin - if BESENIsNaN(Num) then begin - result:=0; - end else if BESENIsFinite(Num) then begin - if BESENIsNegative(Num) then begin - result:=trunc(-BESENFloor(-Num)); - end else begin - result:=trunc(BESENFloor(Num)); - end; - end else begin - result:=trunc(Num); - end; -end; - -function BESENToIntForTime(Num:TBESENNumber):TBESENNumber; -begin - if BESENIsNaN(Num) then begin - result:=0; - end else if BESENIsFinite(Num) then begin - if BESENIsNegative(Num) then begin - result:=-BESENFloor(-Num); - end else begin - result:=BESENFloor(Num); - end; - end else begin - result:=Num; - end; -end; - -function BESENMakeTime(Hour,Minute,Second,Millisecond:TBESENNumber):TBESENNumber; -begin - if BESENIsFinite(Hour) and BESENIsFinite(Minute) and BESENIsFinite(Second) and BESENIsFinite(Millisecond) then begin - result:=(BESENToIntForTime(Hour)*BESENmsPerHour)+(BESENToIntForTime(Minute)*BESENmsPerMinute)+(BESENToIntForTime(Second)*BESENmsPerSecond)+BESENToIntForTime(Millisecond); - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENMakeDay(Year,Month,Date:TBESENNumber):TBESENNumber; -const Julian:array[boolean,0..11] of integer=((1,32,60,91,121,152,182,213,244,274,305,335),(1,32,61,92,122,153,183,214,245,275,306,336)); -var y,m:TBESENNumber; -begin - if not (BESENIsFinite(Year) and BESENIsFinite(Month) and BESENIsFinite(Date)) then begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - month:=BESENToIntForTime(month); - y:=BESENToIntForTime(year)+BESENFloor(month/12); - m:=BESENModuloPos(month,12.0); - if (BESENDayFromYear(y)<-100000000) or (BESENDayFromYear(y)>100000000) then begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - result:=BESENDay((BESENDayFromYear(y)+Julian[boolean(BESENIsLeapYear(BESENFloor(y)))][trunc(m)]-1)*BESENmsPerDay)+BESENToIntForTime(date)-1; - if (result<-100000000) or (result>100000000) then begin - result:=double(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENMakeDate(Day,Time:TBESENNumber):TBESENNumber; -begin - if BESENIsFinite(Day) and BESENIsFinite(Time) then begin - result:=(Day*BESENmsPerDay)+Time; - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENTimeClip(const v:TBESENDate):TBESENDate; -begin - if (not BESENIsFinite(v)) or ((v<-8.64e15) or (v>8.64e15)) then begin - result:=double(pointer(@BESENDoubleNaN)^); - end else begin - result:=BESENToIntForTime(v); - end; -end; - -function BESENDateTimeToBESENDate(DateTime:TDateTime):TBESENDate; -begin - result:=round((DateTime-BESENUnixDateDelta)*BESENmsPerDay); -end; - -function BESENDateToDateTime(BESENDate:TBESENDate):TDateTime; -begin - result:=(BESENDate/BESENmsPerDay)+BESENUnixDateDelta; -end; - -function BESENSystemTimeToBESENDate(SystemTime:TSystemTime):TBESENDate; -begin -{$ifdef BESENDelphiHasNoSystemTimeMore} - result:=EncodeDate(SystemTime.wYear,SystemTime.wMonth,SystemTime.wDay); - result:=result+(((ord(result<0) and 1)*(-1))*EncodeTime(SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond,SystemTime.wMilliSeconds)); -{$else} - result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); -{$endif} -end; - -function BESENDateToSystemTime(BESENDate:TBESENDate):TSystemTime; -{$ifdef BESENDelphiHasNoSystemTimeMore} -var DateTime:TDateTime; -{$endif} -begin -{$ifdef BESENDelphiHasNoSystemTimeMore} - DateTime:=BESENDateToDateTime(trunc(BESENDate)); - DecodeDateFully(DateTime,result.wYear,result.wMonth,result.wDay,result.wDayOfWeek); - dec(result.wDayOfWeek); - DecodeTime(DateTime,result.wHour,result.wMinute,result.wSecond,result.wMilliseconds); -{$else} - DateTimeToSystemTime(BESENDateToDateTime(trunc(BESENDate)),result); -{$endif} -end; - -function BESENGetLocalDateTime:TDateTime; -{$ifndef BESENDelphiHasNoSystemTimeMore} -var SystemTime:TSystemTime; -{$endif} -begin -{$ifdef BESENDelphiHasNoSystemTimeMore} - result:=Now; -{$else} - GetLocalTime(SystemTime); - result:=SystemTimeToDateTime(SystemTime); -{$endif} -end; - -function BESENGetUTCDateTime:TDateTime; -{$ifdef unix} -var TimeVal:TTimeVal; - ia,ib:int64; - fa,fb,fc:double; -begin - fpGetTimeOfDay(@TimeVal,nil); - ia:=TimeVal.tv_sec; - ib:=TimeVal.tv_usec; - fa:=ia*1000; - fb:=ib*0.001; - fc:=fa+fb; - result:=(fc/BESENmsPerDay)+BESENUnixDateDelta; -end; -{$else} -{$ifdef BESENEmbarcaderoNextGen} -begin - result:=TTimeZone.Local.ToUniversalTime(Now); -end; -{$else} -{$ifdef windows} -var SystemTime:TSystemTime; -begin - GetSystemTime(SystemTime); - result:=SystemTimeToDateTime(SystemTime); -end; -{$else} -var SystemTime:TSystemTime; -begin - GetSystemTime(SystemTime); - result:=SystemTimeToDateTime(SystemTime); -end; -{$endif} -{$endif} -{$endif} - -function BESENGetUTCBESENDate:TBESENDate; -{$ifdef unix} -var TimeVal:TTimeVal; - ia,ib:int64; - fa,fb:double; -begin - fpGetTimeOfDay(@TimeVal,nil); - ia:=TimeVal.tv_sec; - ib:=TimeVal.tv_usec; - fa:=ia*1000; - fb:=ib*0.001; - result:=fa+fb; -end; -{$else} -{$ifdef BESENDelphiHasNoSystemTimeMore} -begin - result:=BESENDateTimeToBESENDate(Now); -end; -{$else} -{$ifdef windows} -var SystemTime:TSystemTime; -begin - GetSystemTime(SystemTime); - result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); -end; -{$else} -var SystemTime:TSystemTime; -begin - GetSystemTime(SystemTime); - result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); -end; -{$endif} -{$endif} -{$endif} - -function BESENGetLocalDateTimeZone:TDateTime; -{$ifdef unix} -begin - result:=BESENGetLocalDateTime-BESENGetUTCDateTime; -end; -{$else} -{$ifdef windows} -var tz_info:TIME_ZONE_INFORMATION; -begin - case GetTimeZoneInformation(tz_info) of - TIME_ZONE_ID_STANDARD:result:=-(((tz_info.StandardBias+tz_info.Bias)*60000.0)/BESENmsPerDay); - TIME_ZONE_ID_DAYLIGHT:result:=-(((tz_info.DaylightBias+tz_info.Bias)*60000.0)/BESENmsPerDay); - else begin - result:=BESENGetLocalDateTime-BESENGetUTCDateTime; - end; - end; -end; -{$else} -begin - result:=BESENGetLocalDateTime-BESENGetUTCDateTime; -end; -{$endif} -{$endif} - -function BESENGetLocalTZA:TBESENDate; -{$ifdef unix} -var TimeVal:TTimeVal; - ia,ib:int64; - fa,fb,fc:double; -begin - fpGetTimeOfDay(@TimeVal,nil); - ia:=TimeVal.tv_sec; - ib:=TimeVal.tv_usec; - fa:=ia*1000; - fb:=ib*0.001; - fc:=fa+fb; - result:=BESENDateTimeToBESENDate(BESENGetLocalDateTime)-fc; -end; -{$else} -{$ifdef windows} -var tz_info:TIME_ZONE_INFORMATION; -begin - case GetTimeZoneInformation(tz_info) of - TIME_ZONE_ID_STANDARD:result:=-(tz_info.StandardBias+tz_info.Bias)*60000.0; - TIME_ZONE_ID_DAYLIGHT:result:=-(tz_info.DaylightBias+tz_info.Bias)*60000.0; - else begin - result:=(BESENGetLocalDateTime-BESENGetUTCDateTime)*BESENmsPerDay; - end; - end; -end; -{$else} -begin - result:=(BESENGetLocalDateTime-BESENGetUTCDateTime)*BESENmsPerDay; -end; -{$endif} -{$endif} - -function BESENLocalTime(Date:TBESENDate):TBESENDate; -begin - if BESENIsFinite(Date) then begin - result:=Date+BESENGetLocalTZA; - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENUTC(Date:TBESENDate):TBESENDate; -begin - if BESENIsFinite(Date) then begin - result:=Date-BESENGetLocalTZA; - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENLocalDateTimeToUTC(DateTime:TDateTime):TDateTime; -begin - result:=DateTime-BESENGetLocalDateTimeZone; -end; - -function BESENUTCToLocalDateTime(DateTime:TDateTime):TDateTime; -begin - result:=DateTime+BESENGetLocalDateTimeZone; -end; - -function BESENGetDateTimeOffsetString(const Ofs:TDateTime):TBESENString; -var i:int64; - a,b:TBESENString; -begin - i:=trunc(BESENFloor(Ofs*SecsPerDay)) div 60; - case i mod 60 of - 59:begin - inc(i); - end; - 1:begin - dec(i); - end; - end; - a:=IntToStr(i div 60); - b:=IntToStr(i mod 60); - if length(a)<2 then begin - a:='0'+a; - end; - if length(b)<2 then begin - b:='0'+b; - end; - if i<0 then begin - a:='-'+a; - end else begin - a:='+'+a; - end; - result:=a+b; -end; - -function BESENParseISOTime(s:TBESENString):TBESENDate; - function IsDigit(const w:widechar):boolean; - begin - result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); - end; - function ParseDay(const ss:TBESENString):TBESENDate; - var Offset:integer; - begin - if (length(ss)=10) and (IsDigit(ss[1]) and IsDigit(ss[2]) and IsDigit(ss[3]) and IsDigit(ss[4]) and (ss[5]='-') and IsDigit(ss[6]) and IsDigit(ss[7]) and (ss[8]='-') and IsDigit(ss[9]) and IsDigit(ss[10])) then begin - Offset:=1; - end else if (length(ss)=8) and (IsDigit(ss[1]) and IsDigit(ss[2]) and IsDigit(ss[3]) and IsDigit(ss[4]) and IsDigit(ss[5]) and IsDigit(ss[6]) and IsDigit(ss[7]) and IsDigit(ss[8])) then begin - Offset:=0; - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - result:=BESENMakeDay(StrToIntDef(copy(ss,1,4),0),StrToIntDef(copy(ss,5+(1*Offset),2),0),StrToIntDef(copy(ss,7+(2*Offset),2),0)); - end; - function ParseTime(const ss:TBESENString):TBESENDate; - var s,ms:TBESENString; - i,Offset,Hours,Minutes,Seconds,Milliseconds:integer; - WithSeconds:boolean; - begin - i:=BESENPosChar(',',ss); - if i=0 then begin - i:=BESENPosChar('.',ss); - end; - if i=0 then begin - s:=ss; - ms:=''; - end else begin - s:=copy(ss,1,i-1); - ms:=copy(ms,i+1,(length(ss)-i)+1); - end; - if (length(s)=8) and (IsDigit(s[1]) and IsDigit(s[2]) and (s[3]=':') and IsDigit(s[4]) and IsDigit(s[5]) and (s[6]=':') and IsDigit(s[7]) and IsDigit(s[8])) then begin - Offset:=1; - WithSeconds:=true; - end else if (length(s)=6) and (IsDigit(s[1]) and IsDigit(s[2]) and IsDigit(s[3]) and IsDigit(s[4]) and IsDigit(s[5]) and IsDigit(s[6])) then begin - Offset:=0; - WithSeconds:=true; - end else if (length(s)=5) and (IsDigit(s[1]) and IsDigit(s[2]) and (s[3]=':') and IsDigit(s[4]) and IsDigit(s[5])) then begin - Offset:=1; - WithSeconds:=false; - end else if (length(s)=4) and (IsDigit(s[1]) and IsDigit(s[2]) and IsDigit(s[3]) and IsDigit(s[4])) then begin - Offset:=0; - WithSeconds:=false; - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - Hours:=StrToIntDef(copy(s,1,2),100); - Minutes:=StrToIntDef(copy(s,3+(1*Offset),2),100); - if WithSeconds then begin - Seconds:=StrToIntDef(copy(s,5+(2*Offset),2),100); - end else begin - Seconds:=0; - if length(ms)>0 then begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - end; - case length(ms) of - 0:Milliseconds:=0; - 3:Milliseconds:=StrToIntDef(ms,10000); - else begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - end; - result:=BESENMakeTime(Hours,Minutes,Seconds,Milliseconds); - end; -var i,j,k:integer; - sz:TBESENString; - Delta:TBESENDate; -begin - i:=BESENPosChar('T',s); - if i=0 then begin - i:=BESENPosChar(' ',s); - end; - if i>0 then begin - j:=BESENPosChar('Z',s); - if j=0 then begin - j:=length(s)+1; - for k:=length(s) downto i+1 do begin - if (s[k]='-') or (s[k]='+') then begin - j:=k; - break; - end; - end; - end; - sz:=copy(s,j,(length(s)-j)+1); - s:=copy(s,1,j-1); - Delta:=0; - if (length(sz)=6) and ((sz[1]='-') or (sz[1]='+')) and IsDigit(sz[2]) and IsDigit(sz[3]) and (sz[4]=':') and IsDigit(sz[5]) and IsDigit(sz[6]) then begin - i:=StrToIntDef(copy(sz,2,2),-1); - j:=StrToIntDef(copy(sz,5,2),-1); - if ((i>=0) and (i<=24)) and ((j>=0) and (j<=60)) then begin - Delta:=(i*60)+j; - if sz[1]='-' then begin - Delta:=-Delta; - end; - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - end else if (length(sz)>0) and (sz<>'Z') then begin - result:=double(pointer(@BESENDoubleNaN)^); - exit; - end; - result:=BESENTimeClip(BESENMakeDate(ParseDay(copy(s,1,i-1)),ParseTime(copy(s,i+1,(length(s)-i)+1)))-(Delta*BESENmsPerMinute)); - end else begin - result:=double(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENParseTime(s:TBESENString):TBESENDate; -var p:integer; - function IsWhite(const w:widechar):boolean; - begin - result:=BESENUnicodeIsStringWhiteSpace(word(w)); - end; - function IsLetter(const w:widechar):boolean; - begin - result:=((word(w)>=ord('a')) and (word(w)<=ord('z'))) or ((word(w)>=ord('Z')) and (word(w)<=ord('Z'))); - end; - function IsDigit(const w:widechar):boolean; - begin - result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); - end; - function ToLower(const w:widechar):widechar; - begin - result:=widechar(word(BESENUnicodeToLower(word(w)))); - end; - procedure SkipWhite; - begin - while p<length(s) do begin - if IsWhite(s[p]) then begin - inc(p); - end else begin - break; - end; - end; - end; -var i,d,m,y,hr,min,sec,ms,wd:integer; - t:TBESENString; - yneg:boolean; -begin - result:=double(pointer(@BESENDoubleNaN)^); - - p:=1; - - SkipWhite; - - if ((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2])) then begin - t:=BESENLowercase(copy(s,p,3)); - for wd:=low(ParserDayNames) to high(ParserDayNames) do begin - if t=ParserDayNames[wd] then begin - inc(p,3); - if (p<=length(s)) and (s[p]=',') then begin - inc(p); - end; - SkipWhite; - break; - end; - end; - end; - - if (p<=length(s)) and IsDigit(s[p]) then begin - d:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - d:=(d*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - if not ((p<=length(s)) and IsWhite(s[p])) then begin - exit; - end; - SkipWhite; - if not (((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2]))) then begin - exit; - end; - t:=BESENLowercase(copy(s,p,3)); - inc(p,3); - m:=0; - for i:=low(ParserMonthNames) to high(ParserMonthNames) do begin - if t=ParserMonthNames[i] then begin - m:=i; - break; - end; - end; - end else begin - if not (((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2]))) then begin - exit; - end; - t:=BESENLowercase(copy(s,p,3)); - inc(p,3); - m:=0; - for i:=low(ParserMonthNames) to high(ParserMonthNames) do begin - if t=ParserMonthNames[i] then begin - m:=i; - break; - end; - end; - if not ((p<=length(s)) and IsWhite(s[p])) then begin - exit; - end; - SkipWhite; - d:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - d:=(d*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - end; - if (m<0) or ((d<1) or (d>31)) then begin - exit; - end; - - if not ((p<=length(s)) and IsWhite(s[p])) then begin - exit; - end; - SkipWhite; - - yneg:=(p<=length(s)) and (s[p]='-'); - if yneg then begin - inc(p); - end; - if not ((p<=length(s)) and IsDigit(s[p])) then begin - exit; - end; - y:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - y:=(y*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - if yneg then begin - y:=-y; - end; - - hr:=0; - min:=0; - sec:=0; - ms:=0; - if (p<=length(s)) and IsWhite(s[p]) then begin - SkipWhite; - if ((p+4)<=length(s)) and (IsDigit(s[p]) and IsDigit(s[p+1]) and (s[p+2]=':') and IsDigit(s[p+3]) and IsDigit(s[p+4])) then begin - hr:=((word(widechar(s[p]))-ord('0'))*10)+(word(widechar(s[p+1]))-ord('0')); - min:=((word(widechar(s[p+3]))-ord('0'))*10)+(word(widechar(s[p+4]))-ord('0')); - inc(p,5); - if ((p+2)<=length(s)) and ((s[p]=':') and IsDigit(s[p+1]) and IsDigit(s[p+2])) then begin - sec:=((word(widechar(s[p+1]))-ord('0'))*10)+(word(widechar(s[p+2]))-ord('0')); - inc(p,3); - end; - if ((p+3)<=length(s)) and (((s[p]=':') or (s[p]='.')) and IsDigit(s[p+1]) and IsDigit(s[p+2]) and IsDigit(s[p+3])) then begin - ms:=((word(widechar(s[p+1]))-ord('0'))*100)+((word(widechar(s[p+2]))-ord('0'))*10)+(word(widechar(s[p+3]))-ord('0')); - inc(p,4); - end; - end; - end; - if ((hr<0) or (hr>=24)) or ((min<0) or (min>=60)) or ((sec<0) or (sec>=60)) or ((ms<0) or (ms>=1000)) then begin - exit; - end; - - result:=BESENMakeDate(BESENMakeDay(y,m,d),BESENMakeTime(hr,min,sec,ms)); - - SkipWhite; - if ((p+2)<=length(s)) and (((s[p]='G') and (s[p+1]='M') and (s[p+2]='T')) or ((s[p]='U') and (s[p+1]='T') and (s[p+2]='C'))) then begin - inc(p,3); - if ((p+4)<=length(s)) and (((s[p]='-') or (s[p]='+')) and IsDigit(s[p+1]) and IsDigit(s[p+2]) and IsDigit(s[p+3]) and IsDigit(s[p+4])) then begin - i:=((((word(widechar(s[p+1]))-ord('0'))*10)+((word(widechar(s[p+2]))-ord('0'))))*60)+(((word(widechar(s[p+3]))-ord('0'))*10)+(word(widechar(s[p+4]))-ord('0'))); - if s[p]='-' then begin - i:=-i; - end; - result:=result-(BESENmsPerMinute*i); - end; - end else begin - result:=result-(BESENGetLocalDateTimeZone*BESENmsPerDay); - end; - - result:=BESENTimeClip(result); -end; - -function BESENParseNetscapeTime(s:TBESENString):TBESENDate; -var p:integer; - function IsWhite(const w:widechar):boolean; - begin - result:=BESENUnicodeIsStringWhiteSpace(word(w)); - end; - function IsLetter(const w:widechar):boolean; - begin - result:=((word(w)>=ord('a')) and (word(w)<=ord('z'))) or ((word(w)>=ord('Z')) and (word(w)<=ord('Z'))); - end; - function IsDigit(const w:widechar):boolean; - begin - result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); - end; - function ToLower(const w:widechar):widechar; - begin - result:=widechar(word(BESENUnicodeToLower(word(w)))); - end; - procedure SkipWhite; - begin - while p<length(s) do begin - if IsWhite(s[p]) then begin - inc(p); - end else begin - break; - end; - end; - end; -var i,j,d,m,y,hr,min,sec,ms:integer; - neg:boolean; - n:array[0..2] of integer; -begin - result:=double(pointer(@BESENDoubleNaN)^); - - p:=1; - - SkipWhite; - - for j:=0 to 2 do begin - if j<>0 then begin - SkipWhite; - if (p<=length(s)) and (s[p]='/') then begin - inc(p); - end else begin - exit; - end; - SkipWhite; - end; - n[j]:=0; - neg:=(p<=length(s)) and (s[p]='-'); - if neg then begin - inc(p); - end; - if (p<=length(s)) and IsDigit(s[p]) then begin - i:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - i:=(i*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - if neg then begin - i:=-i; - end; - n[j]:=i; - end else begin - exit; - end; - end; - if (n[0]>=70) and (n[1]>=70) then begin - exit; - end; - if n[0]>=70 then begin - y:=n[0]+1900; - m:=n[1]; - d:=n[2]; - end else begin - m:=n[0]; - d:=n[1]; - y:=n[2]; - if y<100 then begin - y:=n[0]+1900; - end; - end; - if (m<0) or ((d<1) or (d>31)) then begin - exit; - end; - - hr:=0; - min:=0; - sec:=0; - ms:=0; - - if not ((p<=length(s)) and IsWhite(s[p])) then begin - SkipWhite; - - if (p<=length(s)) and IsDigit(s[p]) then begin - i:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - i:=(i*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - hr:=i; - SkipWhite; - if (p<=length(s)) and (s[p]=':') then begin - inc(p); - SkipWhite; - - if (p<=length(s)) and IsDigit(s[p]) then begin - i:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - i:=(i*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - min:=i; - SkipWhite; - if (p<=length(s)) and (s[p]=':') then begin - inc(p); - SkipWhite; - - if (p<=length(s)) and IsDigit(s[p]) then begin - i:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - i:=(i*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - sec:=i; - SkipWhite; - if (p<=length(s)) and ((s[p]=':') or (s[p]='.')) then begin - inc(p); - SkipWhite; - if (p<=length(s)) and IsDigit(s[p]) then begin - i:=0; - while (p<=length(s)) and IsDigit(s[p]) do begin - i:=(i*10)+(word(widechar(s[p]))-ord('0')); - inc(p); - end; - ms:=i; - SkipWhite; - end; - end; - end else begin - exit; - end; - - end; - - if ((p+1)<=length(s)) and (ToLower(s[p+1])='m') then begin - if ToLower(s[p])='a' then begin - if (hr<1) or (hr>12) then begin - exit; - end; - hr:=(hr mod 12)+12; - end else if ToLower(s[p])='p' then begin - if (hr<1) or (hr>12) then begin - exit; - end; - hr:=hr mod 12; - end else begin - exit; - end; - inc(p,2); - SkipWhite; - end; - - end else begin - exit; - end; - - end; - end; - - end; - - if ((hr<0) or (hr>=24)) or ((min<0) or (min>=60)) or ((sec<0) or (sec>=60)) or ((ms<0) or (ms>=1000)) then begin - exit; - end; - - result:=BESENTimeClip(BESENMakeDate(BESENMakeDay(y,m,d),BESENMakeTime(hr,min,sec,ms))-(BESENGetLocalDateTimeZone*BESENmsPerDay)); -end; - -{$warnings off} -function BESENFormatDateTime(const Format:TBESENSTRING;DateTime:TDateTime;const FormatSettings:TFormatSettings):TBESENSTRING; -var Year,Month,Day,DayOfWeek,Hour,Minute,Second,MilliSecond:word; - ResultString:TBESENSTRING; - procedure Add(const s:TBESENSTRING); - begin - ResultString:=ResultString+s; - end; - procedure AddInt(Value,Digits:integer); - var s:TBESENSTRING; - begin - s:=inttostr(Value); - while length(s)<Digits do begin - s:='0'+s; - end; - Add(s); - end; - procedure Process(const Format:TBESENSTRING;Nesting:integer;TimeFlag:boolean); - var FormatPos,PosA,PosB,Count,t:integer; - FormatUp:TBESENSTRING; - CurrentChar,LastChar:TBESENWIDECHAR; - Clock12:boolean; - begin - if Nesting>1 then begin - exit; - end; - Clock12:=false; - FormatUp:=uppercase(Format); - FormatPos:=1; - while FormatPos<=length(Format) do begin - CurrentChar:=FormatUp[FormatPos]; - case CurrentChar of - '''','"':begin - inc(FormatPos); - while (FormatPos<=length(Format)) and (CurrentChar<>Format[FormatPos]) do begin - inc(FormatPos); - end; - inc(FormatPos); - end; - 'A':begin - if (copy(FormatUp,FormatPos,3)='A/P') or (copy(FormatUp,FormatPos,4)='AMPM') or (copy(FormatUp,FormatPos,5)='AM/PM') then begin - Clock12:=true; - break; - end; - inc(FormatPos); - end; - else begin - inc(FormatPos); - end; - end; - end; - LastChar:=#0; - FormatPos:=1; - while FormatPos<=length(Format) do begin - CurrentChar:=FormatUp[FormatPos]; - case CurrentChar of - '''','"':begin - inc(FormatPos); - PosA:=FormatPos; - while (FormatPos<=length(Format)) and (CurrentChar<>FormatUp[FormatPos]) do begin - inc(FormatPos); - end; - PosB:=FormatPos; - inc(FormatPos); - Add(copy(Format,PosA,PosB-PosA)); - LastChar:=CurrentChar; - end; - 'A':begin - if copy(FormatUp,FormatPos,3)='A/P' then begin - if Hour<12 then begin - Add(Format[FormatPos]); - end else begin - Add(Format[FormatPos+2]); - end; - inc(FormatPos,3); - end else if copy(FormatUp,FormatPos,4)='AMPM' then begin - inc(FormatPos,4); - if Hour<12 then begin - Add(FormatSettings.TimeAMString); - end else begin - Add(FormatSettings.TimePMString); - end; - end else if copy(FormatUp,FormatPos,5)='AM/PM' then begin - if Hour<12 then begin - Add(copy(Format,FormatPos,2)); - end else begin - Add(copy(Format,FormatPos+3,2)); - end; - inc(FormatPos,5); - end else begin - raise EConvertError.Create('Illegal character in format string'); - end; - end; - '/':begin - Add(FormatSettings.DateSeparator); - inc(FormatPos); - end; - ':':begin - Add(FormatSettings.TimeSeparator); - inc(FormatPos); - end; - ' ':begin - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]=' ') do begin - Add(' '); - inc(FormatPos); - end; - end; - 'Y':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='Y') do begin - inc(Count); - inc(FormatPos); - end; - if Count>2 then begin - AddInt(Year,4); - end else begin - AddInt(Year mod 100,2); - end; - LastChar:=CurrentChar; - end; - 'M':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='M') do begin - inc(Count); - inc(FormatPos); - end; - if (LastChar='H') or TimeFlag then begin - if Count=1 then begin - AddInt(Minute,0); - end else begin - AddInt(Minute,2); - end; - end else begin - case Count of - 1:begin - AddInt(Month,0); - end; - 2:begin - AddInt(Month,2); - end; - 3:begin - Add(FormatSettings.ShortMonthNames[Month]); - end; - else begin - Add(FormatSettings.LongMonthNames[Month]); - end; - end; - end; - LastChar:=CurrentChar; - end; - 'D':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='D') do begin - inc(Count); - inc(FormatPos); - end; - case Count of - 1:begin - AddInt(Day,0); - end; - 2:begin - AddInt(Day,2); - end; - 3:begin - Add(FormatSettings.ShortDayNames[DayOfWeek]); - end; - 4:begin - Add(FormatSettings.LongDayNames[DayOfWeek]); - end; - 5:begin - Process(FormatSettings.ShortDateFormat,Nesting+1,false); - end; - else begin - Process(FormatSettings.LongDateFormat,Nesting+1,false); - end; - end; - LastChar:=CurrentChar; - end; - 'H':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='H') do begin - inc(Count); - inc(FormatPos); - end; - t:=Hour; - if Clock12 then begin - if t=0 then begin - t:=12; - end else if t>12 then begin - dec(t,12); - end else if t>24 then begin - t:=t mod 12; - if t=0 then begin - t:=12; - end; - end; - end; - if Count=1 then begin - AddInt(t,0); - end else begin - AddInt(t,2); - end; - LastChar:=CurrentChar; - end; - 'N':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='N') do begin - inc(Count); - inc(FormatPos); - end; - if Count=1 then begin - AddInt(Minute,0); - end else begin - AddInt(Minute,2); - end; - LastChar:=CurrentChar; - end; - 'S':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='S') do begin - inc(Count); - inc(FormatPos); - end; - if Count=1 then begin - AddInt(Second,0); - end else begin - AddInt(Second,2); - end; - LastChar:=CurrentChar; - end; - 'Z':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='Z') do begin - inc(Count); - inc(FormatPos); - end; - if Count=1 then begin - AddInt(MilliSecond,0); - end else begin - AddInt(MilliSecond,3); - end; - LastChar:=CurrentChar; - end; - 'T':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='T') do begin - inc(Count); - inc(FormatPos); - end; - if Count=1 then begin - Process(FormatSettings.ShortTimeFormat,Nesting+1,true); - end else begin - Process(FormatSettings.LongTimeFormat,Nesting+1,true); - end; - LastChar:=CurrentChar; - end; - 'C':begin - Count:=0; - while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='C') do begin - inc(Count); - inc(FormatPos); - end; - Process(FormatSettings.ShortDateFormat,Nesting+1,false); - if (integer(Hour)+integer(Minute)+integer(Second))<>0 then begin - Add(' '); - Process(FormatSettings.LongTimeFormat,Nesting+1,true); - end; - LastChar:=CurrentChar; - end; - else begin - Add(Format[FormatPos]); - inc(FormatPos); - end; - end; - end; - end; -begin - DecodeDateFully(DateTime,Year,Month,Day,DayOfWeek); - DecodeTime(DateTime,Hour,Minute,Second,MilliSecond); - ResultString:=''; - if length(Format)>0 then begin - Process(Format,0,false); - end else begin - Process('C',0,false); - end; - result:=ResultString; -end; -{$warnings on} - -end. - diff --git a/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas b/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas deleted file mode 100644 index b4636da80..000000000 --- a/3rd/besen/src/BESENDeclarativeEnvironmentRecord.pas +++ /dev/null @@ -1,612 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENDeclarativeEnvironmentRecord; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENValue, - BESENPointerList,BESENStringList,BESENIntegerList, - BESENObjectPropertyDescriptor,BESENStringUtils; - -type PBESENDeclarativeEnvironmentRecordHashItem=^TBESENDeclarativeEnvironmentRecordHashItem; - TBESENDeclarativeEnvironmentRecordHashItem=record - Previous,Next,HashPrevious,HashNext:PBESENDeclarativeEnvironmentRecordHashItem; - Hash:TBESENHash; - Mutable:TBESENBoolean; - Initialized:TBESENBoolean; - Deletion:TBESENBoolean; - Key:TBESENString; - Value:TBESENValue; - Index:integer; - end; - - TBESENDeclarativeEnvironmentRecordHashBucket=record - HashFirst,HashLast:PBESENDeclarativeEnvironmentRecordHashItem; - end; - - TBESENDeclarativeEnvironmentRecordHashBuckets=array of TBESENDeclarativeEnvironmentRecordHashBucket; - - TBESENDeclarativeEnvironmentRecordValues=array of PBESENValue; - - TBESENDeclarativeEnvironmentRecord=class(TBESENEnvironmentRecord) - private - LastUsedItem:PBESENDeclarativeEnvironmentRecordHashItem; - procedure Clear; - procedure GrowAndRehashIfNeeded; - public - First,Last:PBESENDeclarativeEnvironmentRecordHashItem; - HashBuckets:TBESENDeclarativeEnvironmentRecordHashBuckets; - HashSize:longword; - HashSizeMask:longword; - HashedItems:longword; - HashBucketsUsed:longword; - HashIndexes:TBESENPointerList; - HashIndexNames:TBESENStringList; - HashIndexIDs:TBESENIntegerList; - HashValues:TBESENDeclarativeEnvironmentRecordValues; - Touched:TBESENBoolean; - IndexInitialized:TBESENBoolean; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Reset; - function GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; - function NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; - function DeleteKey(const Item:PBESENDeclarativeEnvironmentRecordHashItem):TBESENBoolean; - function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; override; - function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; - procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); override; - function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - procedure UpdateImplicitThisValue; override; - function CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; override; - function InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; - function SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; override; - function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; override; - procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); override; - function DeleteIndex(const I,ID:integer):TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENHashUtils,BESENErrors; - -constructor TBESENDeclarativeEnvironmentRecord.Create(AInstance:TObject); -var Hash:TBESENHash; -begin - inherited Create(AInstance); - FillChar(HashBuckets,sizeof(TBESENDeclarativeEnvironmentRecordHashBuckets),#0); - First:=nil; - Last:=nil; - HashSize:=256; - HashSizeMask:=HashSize-1; - HashedItems:=0; - HashBucketsUsed:=0; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - HashIndexes:=TBESENPointerList.Create; - HashIndexNames:=TBESENStringList.Create; - HashIndexIDs:=TBESENIntegerList.Create; - HashValues:=nil; - Touched:=false; - IndexInitialized:=false; - LastUsedItem:=nil; - RecordType:=BESENEnvironmentRecordTypeDeclarative; -end; - -destructor TBESENDeclarativeEnvironmentRecord.Destroy; -begin - Clear; - SetLength(HashValues,0); - SetLength(HashBuckets,0); - HashIndexes.Free; - HashIndexNames.Free; - HashIndexIDs.Free; - inherited Destroy; -end; - -procedure TBESENDeclarativeEnvironmentRecord.Clear; -var Hash:TBESENHash; - Item,NextItem:PBESENDeclarativeEnvironmentRecordHashItem; -begin - Item:=First; - while assigned(Item) do begin - NextItem:=Item^.Next; - Item^.Previous:=nil; - Item^.Next:=nil; - Item^.Key:=''; - Item^.Value.ValueType:=bvtUNDEFINED; - Dispose(Item); - Item:=NextItem; - end; - First:=nil; - Last:=nil; - LastUsedItem:=nil; - HashSize:=256; - HashSizeMask:=HashSize-1; - HashedItems:=0; - HashBucketsUsed:=0; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - HashIndexes.Clear; - HashIndexNames.Clear; - HashIndexIDs.Clear; - SetLength(HashValues,0); - Touched:=false; - IndexInitialized:=false; -end; - -procedure TBESENDeclarativeEnvironmentRecord.Reset; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - Item:=First; - while assigned(Item) do begin - Item^.Value.ValueType:=bvtUNDEFINED; - Item^.Initialized:=Item^.Mutable; - Item:=Item^.Next; - end; - Touched:=false; -end; - -procedure TBESENDeclarativeEnvironmentRecord.GrowAndRehashIfNeeded; -var Hash:TBESENHash; - Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin - LastUsedItem:=nil; - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - inc(HashSize,HashSize); - if HashSize>BESENHashMaxSize then begin - HashSize:=BESENHashMaxSize; - end; - HashSizeMask:=HashSize-1; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - HashedItems:=0; - Item:=First; - while assigned(Item) do begin - inc(HashedItems); - Item^.HashPrevious:=nil; - Item^.HashNext:=nil; - Item:=Item^.Next; - end; - HashBucketsUsed:=0; - Item:=First; - while assigned(Item) do begin - Hash:=BESENHashKey(Item^.Key) and HashSizeMask; - Item^.Hash:=Hash; - if assigned(HashBuckets[Hash].HashLast) then begin - HashBuckets[Hash].HashLast^.HashNext:=Item; - Item^.HashPrevious:=HashBuckets[Hash].HashLast; - HashBuckets[Hash].HashLast:=Item; - Item^.HashNext:=nil; - end else begin - inc(HashBucketsUsed); - HashBuckets[Hash].HashFirst:=Item; - HashBuckets[Hash].HashLast:=Item; - Item^.HashPrevious:=nil; - Item^.HashNext:=nil; - end; - Item:=Item^.Next; - end; - end; -end; - -function TBESENDeclarativeEnvironmentRecord.GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; -begin - if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin - result:=LastUsedItem; - Hash:=result^.Hash; - end else begin - if Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - result:=HashBuckets[Hash].HashFirst; - while assigned(result) and (result^.Key<>Key) do begin - result:=result^.HashNext; - end; - end; - if assigned(result) then begin - LastUsedItem:=result; - if HashBuckets[Hash].HashFirst<>result then begin - if assigned(result.HashPrevious) then begin - result.HashPrevious.HashNext:=result.HashNext; - end; - if assigned(result.HashNext) then begin - result.HashNext.HashPrevious:=result.HashPrevious; - end else if HashBuckets[Hash].HashLast=result then begin - HashBuckets[Hash].HashLast:=result.HashPrevious; - end; - HashBuckets[Hash].HashFirst.HashPrevious:=result; - result.HashNext:=HashBuckets[Hash].HashFirst; - result.HashPrevious:=nil; - HashBuckets[Hash].HashFirst:=result; - end; - end; -end; - -function TBESENDeclarativeEnvironmentRecord.NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; -begin - if Force then begin - result:=nil; - if Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - end else if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin - result:=LastUsedItem; - Hash:=result^.Hash; - end else begin - if Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - result:=HashBuckets[Hash].HashFirst; - if not assigned(result) then begin - inc(HashBucketsUsed); - end; - while assigned(result) and (result^.Key<>Key) do begin - result:=result^.HashNext; - end; - end; - if not assigned(result) then begin - inc(HashedItems); - New(result); - fillchar(result^,sizeof(TBESENDeclarativeEnvironmentRecordHashItem),#0); - result^.Hash:=Hash; - result^.Key:=Key; - result^.Index:=-1; - result^.Value.ValueType:=bvtUNDEFINED; - //result^.Value:=BESENUndefinedValue; - result^.Mutable:=false; - result^.Initialized:=false; - result^.Deletion:=false; - if assigned(HashBuckets[Hash].HashLast) then begin - HashBuckets[Hash].HashLast^.HashNext:=result; - result^.HashPrevious:=HashBuckets[Hash].HashLast; - result^.HashNext:=nil; - HashBuckets[Hash].HashLast:=result; - end else begin - HashBuckets[Hash].HashFirst:=result; - HashBuckets[Hash].HashLast:=result; - result^.HashPrevious:=nil; - result^.HashNext:=nil; - end; - if assigned(Last) then begin - Last^.Next:=result; - result^.Previous:=Last; - result^.Next:=nil; - Last:=result; - end else begin - First:=result; - Last:=result; - result^.Previous:=nil; - result^.Next:=nil; - end; - LastUsedItem:=result; - end; - GrowAndRehashIfNeeded; - Touched:=true; -end; - -function TBESENDeclarativeEnvironmentRecord.DeleteKey(const Item:PBESENDeclarativeEnvironmentRecordHashItem):TBESENBoolean; -begin - result:=assigned(Item); - if result then begin - Touched:=true; - if LastUsedItem=Item then begin - if assigned(Item^.Next) then begin - LastUsedItem:=Item^.Next; - end else begin - LastUsedItem:=Item^.Previous; - end; - end; - if assigned(Item^.Previous) then begin - Item^.Previous^.Next:=Item^.Next; - end else if First=Item then begin - First:=Item^.Next; - end; - if assigned(Item^.Next) then begin - Item^.Next^.Previous:=Item^.Previous; - end else if Last=Item then begin - Last:=Item^.Previous; - end; - Item^.Next:=nil; - Item^.Previous:=nil; - if assigned(Item^.HashPrevious) then begin - Item^.HashPrevious^.HashNext:=Item^.HashNext; - end else if HashBuckets[Item^.Hash].HashFirst=Item then begin - HashBuckets[Item^.Hash].HashFirst:=Item^.HashNext; - end; - if assigned(Item^.HashNext) then begin - Item^.HashNext^.HashPrevious:=Item^.HashPrevious; - end else if HashBuckets[Item^.Hash].HashLast=Item then begin - HashBuckets[Item^.Hash].HashLast:=Item^.HashPrevious; - end; - Item^.HashNext:=nil; - Item^.HashPrevious:=nil; - Item^.Key:=''; - Item^.Value:=BESENUndefinedValue; - if Item^.Index>=0 then begin - HashIndexes[Item^.Index]:=nil; - HashValues[Item^.Index]:=@BESENDummyValue; - end; - Dispose(Item); - end; -end; - -function TBESENDeclarativeEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - result:=assigned(GetKey(N,Hash)); -end; - -function TBESENDeclarativeEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - if assigned(GetKey(N,Hash)) then begin - BESENThrowTypeError('CreateMutableBinding for "'+N+'" failed'); - end; - Item:=NewKey(N,false,Hash); - Item^.Value.ValueType:=bvtUNDEFINED; - Item^.Mutable:=true; - Item^.Initialized:=false; - Item^.Deletion:=D; - result:=true; -end; - -function TBESENDeclarativeEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; - procedure ThrowIt; - begin - BESENThrowTypeError('SetMutableBinding for "'+N+'" failed'); - end; -begin - result:=false; - Item:=GetKey(N,Hash); - if not assigned(Item) then begin - ThrowIt; - end else if Item^.Mutable then begin - BESENCopyValue(Item^.Value,V); - Item^.Initialized:=true; - result:=true; - end else begin - if S then begin // will added/fixed in ES5 errata too - ThrowIt; - end; - end; -end; - -procedure TBESENDeclarativeEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); -var Item:PBESENDeclarativeEnvironmentRecordHashItem; - procedure ThrowUninitialized; - begin - BESENThrowReferenceError('Uninitialized immutable binding "'+N+'"'); - end; - procedure ThrowIt; - begin - BESENThrowTypeError('GetBindingValue for "'+N+'" failed'); - end; -begin - Item:=GetKey(N,Hash); - if assigned(Item) then begin - if Item^.Mutable or Item^.Initialized then begin - BESENCopyValue(R,Item^.Value); - end else begin - if S then begin - ThrowUninitialized; - end else begin - R.ValueType:=bvtUNDEFINED; - end; - end; - end else begin - ThrowIt; - end; -end; - -function TBESENDeclarativeEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - Item:=GetKey(N,Hash); - if assigned(Item) then begin - if Item^.Mutable and Item^.Deletion then begin - if Item^.Index>=0 then begin - HashIndexes[Item^.Index]:=nil; - HashValues[Item^.Index]:=@BESENDummyValue; - end; - DeleteKey(Item); - result:=true; - end else begin - result:=false; - end; - end else begin - result:=true; - end; -end; - -procedure TBESENDeclarativeEnvironmentRecord.UpdateImplicitThisValue; -begin - ImplicitThisValue.ValueType:=bvtUNDEFINED; - ImplicitThisValue.Obj:=nil; -end; - -function TBESENDeclarativeEnvironmentRecord.CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - if assigned(GetKey(N,Hash)) then begin - BESENThrowTypeError('CreateImmutableBinding for "'+N+'" failed'); - end; - Item:=NewKey(N,false,Hash); - Item^.Value.ValueType:=bvtUNDEFINED; - Item^.Mutable:=false; - Item^.Initialized:=false; - Item^.Deletion:=false; - result:=true; -end; - -function TBESENDeclarativeEnvironmentRecord.InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - Item:=GetKey(N,Hash); - if assigned(Item) and not (Item^.Mutable or Item^.Initialized) then begin - BESENCopyValue(Item^.Value,v); - Item^.Initialized:=true; - end else begin - BESENThrowTypeError('InitializeImmutableBinding for "'+N+'" failed'); - end; - result:=true; -end; - -function TBESENDeclarativeEnvironmentRecord.SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - Item:=GetKey(N,Hash); - if assigned(Item) then begin - Item^.Index:=I; - HashIndexes.Insert(I,Item); - HashIndexNames.Insert(I,N); - HashIndexIDs.Insert(I,TBESEN(Instance).KeyIDManager.Get(N,Hash)); - if i>=length(HashValues) then begin - SetLength(HashValues,i+256); - end; - HashValues[i]:=@Item^.Value; - result:=true; - end else begin - result:=false; - end; -end; - -function TBESENDeclarativeEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; - procedure ThrowIt; - begin - BESENThrowTypeError('SetIndexValue for "'+inttostr(I)+'" failed'); - end; -begin - if (I>=0) and (I<HashIndexes.Count) then begin - Item:=HashIndexes[I]; - end else begin - Item:=nil; - end; - if assigned(Item) and Item^.Mutable then begin - BESENCopyValue(Item^.Value,v); - Item^.Initialized:=true; - end else begin - ThrowIt; - end; - result:=true; -end; - -procedure TBESENDeclarativeEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); -var Item:PBESENDeclarativeEnvironmentRecordHashItem; - procedure ThrowUninitialized; - begin - BESENThrowReferenceError('Uninitialized immutable binding "'+Item^.Key+'"'); - end; - procedure ThrowIt; - begin - BESENThrowTypeError('GetIndexValue for "'+inttostr(I)+'" failed'); - end; -begin - if (I>=0) and (I<HashIndexes.Count) then begin - Item:=HashIndexes[I]; - end else begin - Item:=nil; - end; - if assigned(Item) then begin - if Item^.Mutable or Item^.Initialized then begin - BESENCopyValue(R,Item^.Value); - end else begin - if S then begin - ThrowUninitialized; - end else begin - R.ValueType:=bvtUNDEFINED; - end; - end; - end else begin - ThrowIt; - end; -end; - -function TBESENDeclarativeEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - if (I>=0) and (I<HashIndexes.Count) then begin - Item:=HashIndexes[I]; - end else begin - Item:=nil; - end; - if assigned(Item) then begin - if Item^.Mutable and Item^.Deletion then begin - HashIndexes[i]:=nil; - HashValues[i]:=@BESENDummyValue; - DeleteKey(Item); - result:=true; - end else begin - result:=false; - end; - end else begin - result:=true; - end; -end; - -procedure TBESENDeclarativeEnvironmentRecord.Finalize; -begin - Clear; - inherited Finalize; -end; - -procedure TBESENDeclarativeEnvironmentRecord.Mark; -var Item:PBESENDeclarativeEnvironmentRecordHashItem; -begin - Item:=First; - while assigned(Item) do begin - TBESEN(Instance).GarbageCollector.GrayValue(Item^.Value); - Item:=Item^.Next; - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENDecompiler.pas b/3rd/besen/src/BESENDecompiler.pas deleted file mode 100644 index 11d94d074..000000000 --- a/3rd/besen/src/BESENDecompiler.pas +++ /dev/null @@ -1,1017 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENDecompiler; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, - BESENEvalCacheItem; - -type TBESENDecompiler=class(TBESENBaseObject) - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; - end; - -implementation - -uses BESEN,BESENUtils,BESENPointerList,BESENHashMap,BESENErrors,BESENNumberUtils, - BESENCode,BESENCodeGeneratorContext,BESENOpcodes,BESENHashUtils,BESENGlobals, - BESENParser,BESENStringUtils; - -constructor TBESENDecompiler.Create(AInstance:TObject); -begin - inherited Create(AInstance); -end; - -destructor TBESENDecompiler.Destroy; -begin - inherited Destroy; -end; - -function TBESENDecompiler.Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; -var Code,s:TBESENUTF8STRING; - Indent:integer; - procedure Add(s:TBESENUTF8STRING); - begin - if (((length(Code)>0) and (Code[length(Code)] in [' ',#13,#10])) or (length(Code)=0)) and ((length(s)>0) and (s[1]=' ')) then begin - delete(s,1,1); - end; - Code:=Code+s; - end; - procedure AddCRLF(s:TBESENUTF8STRING); - begin - Add(s); - Add(#13#10); - end; - procedure AddIndent; - var i:integer; - begin - if (length(Code)>0) and not (Code[length(Code)] in [' ',#13,#10]) then begin - Code:=Code+#13#10; - end; - for i:=1 to Indent do begin - Code:=Code+#9; - end; - end; - procedure Visit(ToVisit:TBESENASTNode;NeedParens:boolean=true); - var Counter:integer; - First:boolean; - begin - if assigned(ToVisit) then begin - case ToVisit.NodeType of - bntNONE:begin - end; - bntEXPRESSION:begin - end; - bntLITERAL:begin - end; - bntIDENTIFIER:begin - Add(BESENUTF16ToUTF8(TBESENASTNodeIdentifier(ToVisit).Name)); - end; - bntVARIABLEDECLARATION:begin - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); - if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Expression) then begin - Add(' = '); - Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,false); - end; - end; - bntVARIABLEEXPRESSION:begin - First:=true; - Add('var '); - First:=true; - for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin - if First then begin - First:=false; - end else begin - Add(', '); - end; - Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); - end; - end; - bntFUNCTIONBODY:begin - if length(TBESENASTNodeFunctionBody(ToVisit).Variables)>0 then begin - First:=true; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin - if not (TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter or TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsReached) then begin - if First then begin - AddIndent; - Add('var '); - First:=false; - end else begin - Add(', '); - end; - Visit(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]); - end; - end; - if not First then begin - Add(';'); - end; - end; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]); - end; - for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); - end; - end; - bntFUNCTIONLITERAL:begin - if assigned(TBESENASTNodeFunctionLiteral(ToVisit).Name) then begin - AddIndent; - Add('function '); - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Name); - end else begin - Add('function'); - end; - Add('('); - for Counter:=0 to length(TBESENASTNodeFunctionLiteral(ToVisit).Body.Parameters)-1 do begin - if Counter>0 then begin - Add(', '); - end; - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body.Parameters[Counter]); - end; - AddCRLF(') {'); - inc(Indent); - Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); - dec(Indent); - AddIndent; - Add('}'); - end; - bntSTATEMENT:begin - Add(';'); - end; - bntVARIABLESTATEMENT:begin - AddIndent; - Add('var '); - for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin - if Counter>0 then begin - Add(', '); - end; - Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); - end; - Add(';'); - end; - bntFUNCTIONDECLARATION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - AddIndent; - Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); - Add(';'); - end; - end; - bntEXPRESSIONSTATEMENT:begin - AddIndent; - Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,false); - Add(';'); - end; - bntEMPTYSTATEMENT:begin - end; - bntBLOCKSTATEMENT:begin - AddIndent; - Add('{'); - inc(Indent); - for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); - end; - dec(Indent); - AddIndent; - Add('}'); - end; - bntDEBUGGERSTATEMENT:begin - AddIndent; - Add('debugger;'); - end; - bntBREAKSTATEMENT:begin - AddIndent; - if assigned(TBESENASTNodeBreakStatement(ToVisit).Identifier) then begin - Add('break '); - Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); - AddCRLF(';'); - end else begin - Add('break;'); - end; - end; - bntCONTINUESTATEMENT:begin - AddIndent; - if assigned(TBESENASTNodeContinueStatement(ToVisit).Identifier) then begin - Add('continue '); - Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); - AddCRLF(';'); - end else begin - Add('continue;'); - end; - end; - bntDOSTATEMENT:begin - AddIndent; - Add('do'); - Visit(TBESENASTNodeDoStatement(ToVisit).Statement); - Add('while('); - Visit(TBESENASTNodeDoStatement(ToVisit).Expression,false); - AddCRLF(');'); - end; - bntWHILESTATEMENT:begin - AddIndent; - Add('while('); - Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,false); - Add(')'); - Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); - end; - bntWITHSTATEMENT:begin - AddIndent; - Add('with('); - Visit(TBESENASTNodeWithStatement(ToVisit).Expression,false); - Add(')'); - Visit(TBESENASTNodeWithStatement(ToVisit).Statement); - end; - bntFORSTATEMENT:begin - AddIndent; - Add('for('); - Visit(TBESENASTNodeForStatement(ToVisit).Initial); - Add(';'); - Visit(TBESENASTNodeForStatement(ToVisit).Condition); - Add(';'); - Visit(TBESENASTNodeForStatement(ToVisit).Increment); - Add(')'); - Visit(TBESENASTNodeForStatement(ToVisit).Statement); - end; - bntFORINSTATEMENT:begin - AddIndent; - Add('for('); - if assigned(TBESENASTNodeForInStatement(ToVisit).Variable) and (TBESENASTNodeForInStatement(ToVisit).Variable.NodeType=bntVARIABLEDECLARATION) then begin - Add('var '); - end; - Visit(TBESENASTNodeForInStatement(ToVisit).Variable); - Add(' in '); - Visit(TBESENASTNodeForInStatement(ToVisit).Expression); - Add(')'); - Visit(TBESENASTNodeForInStatement(ToVisit).Statement); - end; - bntIFSTATEMENT:begin - AddIndent; - Add('if('); - Visit(TBESENASTNodeIfStatement(ToVisit).Expression,false); - AddCRLF(')'); - inc(Indent); - Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); - dec(Indent); - if assigned(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin - AddCRLF(''); - AddIndent; - Add('else'); - inc(Indent); - Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); - dec(Indent); - AddCRLF(''); - end; - end; - bntLABELLEDSTATEMENT:begin - AddIndent; - for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin - Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); - AddCRLF(': '); - end; - Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); - end; - bntCASESTATEMENT:begin - AddIndent; - if assigned(TBESENASTNodeCaseStatement(ToVisit).Expression) then begin - Add('case '); - Visit(TBESENASTNodeCaseStatement(ToVisit).Expression,false); - end else begin - Add('default'); - end; - AddCRLF(':'); - inc(Indent); - for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin - Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); - end; - dec(Indent); - end; - bntSWITCHSTATEMENT:begin - AddIndent; - Add('switch('); - Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression,false); - AddCRLF(') {'); - inc(Indent); - for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin - Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); - end; - dec(Indent); - AddIndent; - Add('}'); - end; - bntTHROWSTATEMENT:begin - AddIndent; - Add('throw '); - Visit(TBESENASTNodeThrowStatement(ToVisit).Expression,false); - AddCRLF(';'); - end; - bntTRYSTATEMENT:begin - AddIndent; - Add('try'); - Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); - if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) then begin - AddIndent; - Add('catch('); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier,false); - Add(')'); - Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); - end; - if assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin - AddIndent; - Add('finally'); - Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); - end; - end; - bntARRAYLITERAL:begin - Add('['); - for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin - if Counter>0 then begin - Add(', '); - end; - Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); - end; - Add(']'); - end; - bntBINARYEXPRESSION:begin - Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); - end; - bntASSIGNMENTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); - Add(' = '); - Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTOPERATOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTMULTIPLYEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); - Add(' *= '); - Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTDIVIDEEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); - Add(' /= '); - Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTMODULOEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); - Add(' %= '); - Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTPLUSEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); - Add(' += '); - Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTMINUSEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); - Add(' -= '); - Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTSHIFTLEFTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); - Add(' <<= '); - Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); - Add(' >>= '); - Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); - Add(' >>>= '); - Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTBITWISEANDEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); - Add(' &= '); - Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTBITWISEXOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); - Add(' ^= '); - Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntASSIGNMENTBITWISEOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); - Add(' |= '); - Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYOPERATOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); - Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYCOMMAEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); - Add(', '); - Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYDIVIDEEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); - Add(' / '); - Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYMODULOEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); - Add(' % '); - Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYMULTIPLYEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); - Add(' * '); - Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYPLUSEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); - Add(' + '); - Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYMINUSEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); - Add(' - '); - Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYSHIFTLEFTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); - Add(' << '); - Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYSHIFTRIGHTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); - Add(' >> '); - Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); - Add(' >>> '); - Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYGREATERTHANEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); - Add(' > '); - Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYGREATERTHANOREQUALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); - Add(' >= '); - Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYLESSTHANEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); - Add(' < '); - Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYLESSTHANOREQUALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); - Add(' <= '); - Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYINSTANCEOFEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); - Add(' instanceof '); - Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYINEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); - Add(' in '); - Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYEQUALEQUALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); - Add(' == '); - Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYEQUALEQUALEQUALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); - Add(' === '); - Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYNOTEQUALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); - Add(' != '); - Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYNOTEQUALEQUALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); - Add(' !== '); - Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYBITWISEANDEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); - Add(' & '); - Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYBITWISEXOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); - Add(' ^ '); - Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBINARYBITWISEOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); - Add(' | '); - Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntBOOLEANLITERAL:begin - if TBESENASTNodeBooleanLiteral(ToVisit).Value then begin - Add('true'); - end else begin - Add('false'); - end; - end; - bntCALLEXPRESSION:begin - Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); - Add('('); - for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin - if Counter>0 then begin - Add(', '); - end; - Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); - end; - Add(')'); - end; - bntNEWEXPRESSION:begin - Add('new '); - Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); - Add('('); - for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin - if Counter>0 then begin - Add(', '); - end; - Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); - end; - Add(')'); - end; - bntCONDITIONALEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); - Add(' ? '); - Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); - Add(' : '); - Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntUNARYEXPRESSION:begin - Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); - end; - bntUNARYOPERATOREXPRESSION:begin - Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); - end; - bntUNARYPLUSEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Add('+'); - Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntUNARYMINUSEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Add('-'); - Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntUNARYBITWISENOTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Add('~'); - Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntUNARYLOGICALNOTEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Add('!'); - Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntUNARYVOIDEXPRESSION:begin - Add('void '); - Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); - end; - bntUNARYTYPEOFEXPRESSION:begin - Add('typeof '); - Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); - end; - bntPROPERTYEXPRESSION:begin - Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); - if TBESENASTNodePropertyExpression(ToVisit).Dot and assigned(TBESENASTNodePropertyExpression(ToVisit).RightExpression) and (TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral) then begin - Add('.'); - Add(BESENUTF16ToUTF8(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value)); - end else begin - Add('['); - Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); - Add(']'); - end; - end; - bntLOGICALANDEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); - Add(' && '); - Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntLOGICALOREXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); - Add(' || '); - Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntDELETEEXPRESSION:begin - Add('delete '); - Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); - end; - bntPOSTFIXINCEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); - Add('++'); - if NeedParens then begin - Add(')'); - end; - end; - bntPOSTFIXDECEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); - Add('--'); - if NeedParens then begin - Add(')'); - end; - end; - bntPREFIXINCEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Add('++'); - Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntPREFIXDECEXPRESSION:begin - if NeedParens then begin - Add('('); - end; - Add('--'); - Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); - if NeedParens then begin - Add(')'); - end; - end; - bntNULLLITERAL:begin - Add('null'); - end; - bntNUMBERLITERAL:begin - if TBESENASTNodeNumberLiteral(ToVisit).Value=trunc(TBESENASTNodeNumberLiteral(ToVisit).Value) then begin - str(trunc(TBESENASTNodeNumberLiteral(ToVisit).Value),s); - end else begin - str(TBESENASTNodeNumberLiteral(ToVisit).Value,s); - end; - Add(s); - end; - bntREGEXPLITERAL:begin - Add('/'+BESENUTF16ToUTF8(TBESENASTNodeRegExpLiteral(ToVisit).Source)+'/'+BESENUTF16ToUTF8(TBESENASTNodeRegExpLiteral(ToVisit).Flags)); - end; - bntSTRINGLITERAL:begin - Add(BESENUTF16ToUTF8(BESENJSONStringQuote(TBESENASTNodeStringLiteral(ToVisit).Value))); - end; - bntTHISLITERAL:begin - Add('this'); - end; - bntOBJECTLITERALPROPERTY:begin - case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType of - banolptACCESSOR:begin - case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType of - banolpatGET:begin - Add('get '); - end; - banolpatSET:begin - Add('set '); - end; - end; - Add(BESENUTF16ToUTF8(TBESENASTNodeObjectLiteralProperty(ToVisit).Name)); - if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); - end; - end; - banolptDATA:begin - Add(BESENUTF16ToUTF8(TBESENASTNodeObjectLiteralProperty(ToVisit).Name)); - Add(': '); - Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); - end; - end; - end; - bntOBJECTLITERAL:begin - Add('{'); - inc(Indent); - for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin - if Counter>0 then begin - Add(', '); - end; - Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); - end; - dec(Indent); - Add('}'); - end; - bntRETURNSTATEMENT:begin - AddIndent; - Add('return '); - Visit(TBESENASTNodeReturnStatement(ToVisit).Expression,false); - AddCRLF(';'); - end; - bntPROGRAM:begin - Visit(TBESENASTNodeProgram(ToVisit).Body); - end; - bntFUNCTIONEXPRESSION:begin - if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin - AddIndent; - Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); - end; - end; - end; - end; - end; -begin - Code:=''; - Indent:=0; - Visit(RootNode); - result:=Code; -end; - -end. diff --git a/3rd/besen/src/BESENDoubleList.pas b/3rd/besen/src/BESENDoubleList.pas deleted file mode 100644 index 30bea5aaa..000000000 --- a/3rd/besen/src/BESENDoubleList.pas +++ /dev/null @@ -1,229 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENDoubleList; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -type PBESENDoubleArray=^TBESENDoubleArray; - TBESENDoubleArray=array[0..(2147483647 div sizeof(double))-1] of double; - - TBESENDoubleList=class - private - FList:PBESENDoubleArray; - FCount,FSize:integer; - function GetItem(index:integer):double; - procedure SetItem(index:integer;Value:double); - function GetItemPointer(index:integer):pointer; - public - constructor Create; - destructor Destroy; override; - procedure Clear; - function Add(Item:double):integer; - procedure Insert(index:integer;Item:double); - procedure Delete(index:integer); - function Remove(Item:double):integer; - function Find(Item:double):integer; - function IndexOf(Item:double):integer; - procedure Exchange(Index1,Index2:integer); - procedure SetCapacity(NewCapacity:integer); - procedure SetCount(NewCount:integer); - property Count:integer read FCount; - property Capacity:integer read FSize write SetCapacity; - property Item[index:integer]:double read GetItem write SetItem; default; - property Items[index:integer]:double read GetItem write SetItem; - property PItems[index:integer]:pointer read GetItemPointer; - end; - -implementation - -constructor TBESENDoubleList.Create; -begin - inherited Create; - FCount:=0; - FSize:=0; - FList:=nil; - Clear; -end; - -destructor TBESENDoubleList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENDoubleList.Clear; -begin - FCount:=0; - FSize:=0; - ReallocMem(FList,0); -end; - -procedure TBESENDoubleList.SetCapacity(NewCapacity:integer); -begin - if (NewCapacity>=0) and (NewCapacity<high(TBESENDoubleArray)) then begin - NewCapacity:=(NewCapacity+256) and not 255; - if FSize<>NewCapacity then begin - ReallocMem(FList,NewCapacity*sizeof(double)); - if FSize<NewCapacity then begin - FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(double),#0); - end; - FSize:=NewCapacity; - end; - end; -end; - -procedure TBESENDoubleList.SetCount(NewCount:integer); -begin - if (NewCount>=0) and (NewCount<high(TBESENDoubleArray)) then begin - if NewCount<FCount then begin - FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(double),#0); - end; - SetCapacity(NewCount); - FCount:=NewCount; - end; -end; - -function TBESENDoubleList.Add(Item:double):integer; -begin - result:=FCount; - SetCount(result+1); - FList^[result]:=Item; -end; - -procedure TBESENDoubleList.Insert(index:integer;Item:double); -var I:integer; -begin - if (index>=0) and (index<FCount) then begin - SetCount(FCount+1); - for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; - FList^[index]:=Item; - end else if index=FCount then begin - Add(Item); - end else if index>FCount then begin - SetCount(index); - Add(Item); - end; -end; - -procedure TBESENDoubleList.Delete(index:integer); -var I,J,K:integer; -begin - if (index>=0) and (index<FCount) then begin - K:=FCount-1; - J:=index; - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - end; -end; - -function TBESENDoubleList.Remove(Item:double):integer; -var I,J,K:integer; -begin - result:=-1; - K:=FCount; - J:=-1; - for I:=0 to K-1 do begin - if FList^[I]=Item then begin - J:=I; - break; - end; - end; - if J>=0 then begin - dec(K); - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - result:=J; - end; -end; - -function TBESENDoubleList.Find(Item:double):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -function TBESENDoubleList.IndexOf(Item:double):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -procedure TBESENDoubleList.Exchange(Index1,Index2:integer); -var TempDouble:double; -begin - if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin - TempDouble:=FList^[Index1]; - FList^[Index1]:=FList^[Index2]; - FList^[Index2]:=TempDouble; - end; -end; - -function TBESENDoubleList.GetItem(index:integer):double; -begin - if (index>=0) and (index<FCount) then begin - result:=FList^[index]; - end else begin - result:=0; - end; -end; - -procedure TBESENDoubleList.SetItem(index:integer;Value:double); -begin - if (index>=0) and (index<FCount) then begin - FList^[index]:=Value; - end; -end; - -function TBESENDoubleList.GetItemPointer(index:integer):pointer; -begin - if (index>=0) and (index<FCount) then begin - result:=@FList^[index]; - end else begin - result:=nil; - end; -end; - -end. diff --git a/3rd/besen/src/BESENEnvironmentRecord.pas b/3rd/besen/src/BESENEnvironmentRecord.pas deleted file mode 100644 index 415652e1a..000000000 --- a/3rd/besen/src/BESENEnvironmentRecord.pas +++ /dev/null @@ -1,201 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENEnvironmentRecord; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENObjectPropertyDescriptor, - BESENSelfBalancedTree,BESENHashMap, - BESENGarbageCollector; - -const BESENEnvironmentRecordTypeDeclarative=0; - BESENEnvironmentRecordTypeObject=longword($ffffffff); - -type TBESENEnvironmentRecord=class(TBESENGarbageCollectorObject) - public - IsStrict:TBESENBoolean; - HasMaybeDirectEval:TBESENBoolean; - ImplicitThisValue:TBESENValue; - RecordType:TBESENUINT32; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; - function HasBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; - function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; virtual; - function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; virtual; - procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); virtual; - function SetMutableBinding(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; virtual; - procedure GetBindingValue(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;Hash:TBESENHash=0); virtual; - function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; - function DeleteBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; - procedure UpdateImplicitThisValue; virtual; - function CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; - function InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; virtual; - function SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; virtual; - function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; virtual; - procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); virtual; - function DeleteIndex(const I,ID:integer):TBESENBoolean; virtual; - function SetArrayIndexValue(const I:TBESENUINT32;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; virtual; - procedure GetArrayIndexValue(const I:TBESENUINT32;const S:TBESENBoolean;var R:TBESENValue); virtual; - function DeleteArrayIndex(const I:TBESENUINT32):TBESENBoolean; virtual; - end; - -implementation - -uses BESEN,BESENArrayUtils,BESENHashUtils,BESENErrors; - -constructor TBESENEnvironmentRecord.Create(AInstance:TObject); -begin - inherited Create(AInstance); - IsStrict:=TBESEN(Instance).IsStrict; - HasMaybeDirectEval:=true; - ImplicitThisValue:=BESENUndefinedValue; -end; - -destructor TBESENEnvironmentRecord.Destroy; -begin - inherited Destroy; -end; - -{$warnings off} -function TBESENEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0000'); -end; - -function TBESENEnvironmentRecord.HasBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; -var Descriptor:TBESENObjectPropertyDescriptor; -begin - result:=HasBindingEx(N,Descriptor,Hash); -end; - -function TBESENEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0001'); -end; - -function TBESENEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0002'); -end; - -procedure TBESENEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); -begin - raise EBESENInternalError.Create('201003160116-0003'); -end; - -function TBESENEnvironmentRecord.SetMutableBinding(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; -var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; - Temp:TBESENValue; -begin - result:=SetMutableBindingEx(N,V,S,Descriptor,OwnDescriptor,Temp,Hash); -end; - -procedure TBESENEnvironmentRecord.GetBindingValue(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;Hash:TBESENHash=0); -var Descriptor:TBESENObjectPropertyDescriptor; -begin - GetBindingValueEx(N,S,R,Descriptor,Hash); -end; - -function TBESENEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0004'); -end; - -function TBESENEnvironmentRecord.DeleteBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; -var Descriptor:TBESENObjectPropertyDescriptor; -begin - result:=DeleteBindingEx(N,Descriptor,Hash); -end; - -procedure TBESENEnvironmentRecord.UpdateImplicitThisValue; -begin - raise EBESENInternalError.Create('201003160116-0005'); -end; - -function TBESENEnvironmentRecord.CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0006'); -end; - -function TBESENEnvironmentRecord.InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0007'); -end; - -function TBESENEnvironmentRecord.SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0008'); -end; - -function TBESENEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0009'); -end; - -procedure TBESENEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); -begin - raise EBESENInternalError.Create('201003160116-0010'); -end; - -function TBESENEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; -begin - raise EBESENInternalError.Create('201003160116-0011'); -end; - -function TBESENEnvironmentRecord.SetArrayIndexValue(const I:TBESENUINT32;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; -var N:TBESENString; -begin - N:=BESENArrayIndexToStr(I); - result:=SetMutableBinding(N,V,S,BESENHashKey(N)); - N:=''; -end; - -procedure TBESENEnvironmentRecord.GetArrayIndexValue(const I:TBESENUINT32;const S:TBESENBoolean;var R:TBESENValue); -var N:TBESENString; -begin - N:=BESENArrayIndexToStr(I); - GetBindingValue(N,S,R,BESENHashKey(N)); - N:=''; -end; - -function TBESENEnvironmentRecord.DeleteArrayIndex(const I:TBESENUINT32):TBESENBoolean; -var N:TBESENString; -begin - N:=BESENArrayIndexToStr(I); - result:=DeleteBinding(N,BESENHashKey(N)); - N:=''; -end; -{$warnings on} - -end. diff --git a/3rd/besen/src/BESENErrors.pas b/3rd/besen/src/BESENErrors.pas deleted file mode 100644 index efab7d836..000000000 --- a/3rd/besen/src/BESENErrors.pas +++ /dev/null @@ -1,630 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENErrors; -{$i BESEN.inc} - -interface - -uses SysUtils,Classes,BESENConstants,BESENTypes,BESENValue; - -type EBESENError=class(Exception) - public - OriginalMessage:TBESENString; - Name:TBESENString; - Value:TBESENValue; - constructor Create; overload; virtual; -// BEGIN - To avoid "Ambiguous overloaded call to" error - constructor Create(const Msg:string); overload; virtual; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; virtual; -// END - To avoid "Ambiguous overloaded call to" error - constructor Create(const AValue:TBESENValue); overload; virtual; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; virtual; - constructor Create(const AName,Msg:TBESENSTRING); overload; virtual; - constructor Create(const AName,Msg:TBESENSTRING;const AValue:TBESENValue); overload; virtual; - destructor Destroy; override; - end; - - EBESENUseStrict=class(EBESENError) - end; - - EBESENInternalError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENCompilerError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENEvalError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENRangeError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENReferenceError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENSyntaxError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENTypeError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENURIError=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - - EBESENThrowException=class(EBESENError) - public - constructor Create; overload; override; - constructor Create(const Msg:string); overload; override; - constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; - constructor Create(const AValue:TBESENValue); overload; override; - constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; - end; - -procedure BESENThrowReferenceError(const Msg:TBESENString); -procedure BESENThrowSyntaxError(const Msg:TBESENString); -procedure BESENThrowTypeError(const Msg:TBESENString); -procedure BESENThrowRangeError(const Msg:TBESENString); -procedure BESENThrowInternalError(const Msg:TBESENString); -procedure BESENThrowError(const Msg:TBESENString); -procedure BESENThrowCodeGeneratorInvalidRegister; -procedure BESENThrowRecursionLimitReached; -procedure BESENThrowNotDefined(const ARef:TBESENValue); -procedure BESENThrowReference; -procedure BESENThrowNotAccessable(const ARef:TBESENValue); -procedure BESENThrowNotReadable(const P:TBESENString); -procedure BESENThrowNotWritable(const P:TBESENString); -procedure BESENThrowNoSetter(const P:TBESENString); -procedure BESENThrowRcursivePrototypeChain; -procedure BESENThrowPut(const P:TBESENString); -procedure BESENThrowPutRecursivePrototypeChain; -procedure BESENThrowPutInvalidPrototype; -procedure BESENThrowDefineOwnProperty(const P:TBESENString); -procedure BESENThrowCaller; -procedure BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(const fn:TBESENString); -procedure BESENThrowTypeErrorNotAConstructorObject; -procedure BESENThrowTypeErrorObjectHasNoConstruct; -procedure BESENThrowTypeErrorNotAFunction; -procedure BESENThrowTypeErrorNotCallable; - -implementation - -uses BESEN,BESENStringUtils; - -constructor EBESENError.Create; -begin - inherited Create(''); - OriginalMessage:=''; - Name:='Error'; - Value:=BESENEmptyValue; -end; - -constructor EBESENError.Create(const Msg:string); -begin - inherited Create(Msg); - OriginalMessage:={$ifdef Delphi2009AndUp}Msg{$else}BESENConvertToUTF8(Msg){$endif}; - Name:='Error'; - Value:=BESENEmptyValue; -end; - -constructor EBESENError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); - OriginalMessage:=Msg; - Name:='Error'; - Value:=BESENEmptyValue; -end; - -constructor EBESENError.Create(const AValue:TBESENValue); -begin - inherited Create(''); - OriginalMessage:=''; - Name:='Error'; - Value:=AValue; -end; - -constructor EBESENError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); - OriginalMessage:=Msg; - Name:='Error'; - Value:=AValue; -end; - -constructor EBESENError.Create(const AName,Msg:TBESENSTRING); -begin - inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); - OriginalMessage:=Msg; - Name:=AName; - Value:=BESENEmptyValue; -end; - -constructor EBESENError.Create(const AName,Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); - OriginalMessage:=Msg; - Name:=AName; - Value:=AValue; -end; - -destructor EBESENError.Destroy; -begin - OriginalMessage:=''; - Value.Str:=''; - Value.ReferenceBase.Str:=''; - Value:=BESENEmptyValue; - Name:=''; - inherited Destroy; -end; - -constructor EBESENInternalError.Create; -begin - inherited Create; - Name:='InternalError'; -end; - -constructor EBESENInternalError.Create(const Msg:string); -begin - inherited Create(Msg); - Name:='InternalError'; -end; - -constructor EBESENInternalError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='InternalError'; -end; - -constructor EBESENInternalError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='InternalError'; -end; - -constructor EBESENInternalError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='InternalError'; -end; - -constructor EBESENCompilerError.Create; -begin - inherited Create; - Name:='CompilerError'; -end; - -constructor EBESENCompilerError.Create(const Msg:string); -begin - inherited Create(Msg); - Name:='CompilerError'; -end; - -constructor EBESENCompilerError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='CompilerError'; -end; - -constructor EBESENCompilerError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='CompilerError'; -end; - -constructor EBESENCompilerError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='CompilerError'; -end; - -constructor EBESENEvalError.Create; -begin - inherited Create; - Name:='EvalError'; -end; - -constructor EBESENEvalError.Create(const Msg:string); -begin - inherited Create(Msg); - Name:='EvalError'; -end; - -constructor EBESENEvalError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='EvalError'; -end; - -constructor EBESENEvalError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='EvalError'; -end; - -constructor EBESENEvalError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='EvalError'; -end; - -constructor EBESENRangeError.Create; -begin - inherited Create; - Name:='RangeError'; -end; - -constructor EBESENRangeError.Create(const Msg:string); -begin - inherited Create(Msg); - Name:='RangeError'; -end; - -constructor EBESENRangeError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='RangeError'; -end; - -constructor EBESENRangeError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='RangeError'; -end; - -constructor EBESENRangeError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='RangeError'; -end; - -constructor EBESENReferenceError.Create; -begin - inherited Create; - Name:='ReferenceError'; -end; - -constructor EBESENReferenceError.Create(const Msg:string); -begin - inherited Create(Msg); - Name:='ReferenceError'; -end; - -constructor EBESENReferenceError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='ReferenceError'; -end; - -constructor EBESENReferenceError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='ReferenceError'; -end; - -constructor EBESENReferenceError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='ReferenceError'; -end; - -constructor EBESENSyntaxError.Create; -begin - inherited Create; - Name:='SyntaxError'; -end; - -constructor EBESENSyntaxError.Create(const Msg:string); -begin - inherited CreateUTF16(Msg); - Name:='SyntaxError'; -end; - -constructor EBESENSyntaxError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='SyntaxError'; -end; - -constructor EBESENSyntaxError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='SyntaxError'; -end; - -constructor EBESENSyntaxError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='SyntaxError'; -end; - -constructor EBESENTypeError.Create; -begin - inherited Create; - Name:='TypeError'; -end; - -constructor EBESENTypeError.Create(const Msg:string); -begin - inherited CreateUTF16(Msg); - Name:='TypeError'; -end; - -constructor EBESENTypeError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='TypeError'; -end; - -constructor EBESENTypeError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='TypeError'; -end; - -constructor EBESENTypeError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='TypeError'; -end; - -constructor EBESENURIError.Create; -begin - inherited Create; - Name:='URIError'; -end; - -constructor EBESENURIError.Create(const Msg:string); -begin - inherited CreateUTF16(Msg); - Name:='URIError'; -end; - -constructor EBESENURIError.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='URIError'; -end; - -constructor EBESENURIError.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='URIError'; -end; - -constructor EBESENURIError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='URIError'; -end; - -constructor EBESENThrowException.Create; -begin - inherited Create; - Name:='ThrowException'; -end; - -constructor EBESENThrowException.Create(const Msg:string); -begin - inherited CreateUTF16(Msg); - Name:='ThrowException'; -end; - -constructor EBESENThrowException.CreateUTF16(const Msg:TBESENSTRING); -begin - inherited CreateUTF16(Msg); - Name:='ThrowException'; -end; - -constructor EBESENThrowException.Create(const AValue:TBESENValue); -begin - inherited Create(AValue); - Name:='ThrowException'; -end; - -constructor EBESENThrowException.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); -begin - inherited Create(Msg,AValue); - Name:='ThrowException'; -end; - -procedure BESENThrowReferenceError(const Msg:TBESENString); -begin - raise EBESENReferenceError.CreateUTF16(Msg); -end; - -procedure BESENThrowSyntaxError(const Msg:TBESENString); -begin - raise EBESENSyntaxError.CreateUTF16(Msg); -end; - -procedure BESENThrowTypeError(const Msg:TBESENString); -begin - raise EBESENTypeError.CreateUTF16(Msg); -end; - -procedure BESENThrowRangeError(const Msg:TBESENString); -begin - raise EBESENRangeError.CreateUTF16(Msg); -end; - -procedure BESENThrowInternalError(const Msg:TBESENString); -begin - raise EBESENInternalError.CreateUTF16(Msg); -end; - -procedure BESENThrowError(const Msg:TBESENString); -begin - raise EBESENError.CreateUTF16(Msg); -end; - -procedure BESENThrowCodeGeneratorInvalidRegister; -begin - BESENThrowError('Invalid register in code generation'); -end; - -procedure BESENThrowRecursionLimitReached; -begin - BESENThrowError('Recursion limit reached'); -end; - -procedure BESENThrowNotDefined(const ARef:TBESENValue); -begin - BESENThrowReferenceError('"'+ARef.Str+'" is not defined'); -end; - -procedure BESENThrowReference; -begin - BESENThrowReferenceError('Reference error'); -end; - -procedure BESENThrowNotAccessable(const ARef:TBESENValue); -begin - BESENThrowReferenceError('"'+ARef.Str+'" is not accessable'); -end; - -procedure BESENThrowNotReadable(const P:TBESENString); -begin - BESENThrowReferenceError('"'+P+'" is not readable'); -end; - -procedure BESENThrowNotWritable(const P:TBESENString); -begin - BESENThrowReferenceError('"'+P+'" is not writable'); -end; - -procedure BESENThrowNoSetter(const P:TBESENString); -begin - BESENThrowTypeError('"'+P+'" has no setter'); -end; - -procedure BESENThrowRcursivePrototypeChain; -begin - BESENThrowTypeError('Recursive prototype chain not allowed'); -end; - -procedure BESENThrowPut(const P:TBESENString); -begin - BESENThrowTypeError('Put for "'+P+'" failed'); -end; - -procedure BESENThrowPutRecursivePrototypeChain; -begin - BESENThrowTypeError('Put for "__proto__" failed, because the prototype chain would be recursive'); -end; - -procedure BESENThrowPutInvalidPrototype; -begin - BESENThrowTypeError('Put for "__proto__" failed, because the prototype would be invalid'); -end; - -procedure BESENThrowDefineOwnProperty(const P:TBESENString); -begin - BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); -end; - -procedure BESENThrowCaller; -begin - BESENThrowTypeError('"caller" not allowed here'); -end; - -procedure BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(const fn:TBESENString); -begin - BESENThrowTypeError('"'+fn+'" not writable or is a accessor descriptor'); -end; - -procedure BESENThrowTypeErrorNotAConstructorObject; -begin - BESENThrowTypeError('Not a constructor object'); -end; - -procedure BESENThrowTypeErrorObjectHasNoConstruct; -begin - BESENThrowTypeError('Object has no construct'); -end; - -procedure BESENThrowTypeErrorNotAFunction; -begin - BESENThrowTypeError('Not a function'); -end; - -procedure BESENThrowTypeErrorNotCallable; -begin - BESENThrowTypeError('Not callable'); -end; - -end. diff --git a/3rd/besen/src/BESENEvalCache.pas b/3rd/besen/src/BESENEvalCache.pas deleted file mode 100644 index a7d4ffc06..000000000 --- a/3rd/besen/src/BESENEvalCache.pas +++ /dev/null @@ -1,142 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENEvalCache; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, - BESENEvalCacheItem; - -type TBESENEvalCache=class(TBESENBaseObject) - private - procedure SetCacheSize(NewSize:longword); - public - HashSize:longword; - HashSizeMask:longword; - HashItems:TBESENEvalCacheItems; - MaxSourceLength:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function Hash(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENHash; - function Get(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENEvalCacheItem; - published - property CacheSize:longword read HashSize write SetCacheSize; - end; - -implementation - -uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; - -constructor TBESENEvalCache.Create(AInstance:TObject); -begin - inherited Create(AInstance); - HashItems:=nil; - SetCacheSize(BESENEvalCacheSize); - MaxSourceLength:=BESENEvalCacheMaxSourceLength; -end; - -destructor TBESENEvalCache.Destroy; -var i:integer; -begin - for i:=0 to length(HashItems)-1 do begin - if assigned(HashItems[i]) then begin - BESENFreeAndNil(HashItems[i]); - HashItems[i]:=nil; - end; - end; - SetLength(HashItems,0); - inherited Destroy; -end; - -procedure TBESENEvalCache.SetCacheSize(NewSize:longword); -var i:integer; -begin - for i:=0 to length(HashItems)-1 do begin - if assigned(HashItems[i]) then begin - HashItems[i].DecRef; - HashItems[i]:=nil; - end; - end; - HashSize:=BESENRoundUpToPowerOfTwo(NewSize); - HashSizeMask:=HashSize-1; - SetLength(HashItems,HashSize); - for i:=0 to length(HashItems)-1 do begin - HashItems[i]:=nil; - end; -end; - -function TBESENEvalCache.Hash(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENHash; -begin - result:=BESENHashKey(Source); - if CallerStrict then begin - result:=not (result+1); - end; -end; - -function TBESENEvalCache.Get(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENEvalCacheItem; -var HashValue:TBESENUINT32; - Node:TBESENASTNode; -begin - if HashSize>0 then begin - HashValue:=Hash(Source,CallerStrict) and HashSizeMask; - result:=HashItems[HashValue]; - if (assigned(result) and ((result.Source<>Source) or (result.CallerStrict<>CallerStrict))) or not assigned(result) then begin - result:=TBESENEvalCacheItem.Create(Instance); - try - result.Source:=Source; - result.CallerStrict:=CallerStrict; - Node:=TBESEN(Instance).Compile({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}Source{$ifndef BESENSingleStringType}){$endif}); - if (not assigned(Node)) or not (Node is TBESENASTNodeProgram) then begin - BESENThrowError('No program'); - end; - result.Node:=TBESENASTNodeProgram(Node); - try - if assigned(HashItems[HashValue]) then begin - HashItems[HashValue].DecRef; - end; - HashItems[HashValue]:=result; - result.IncRef; - except - HashItems[HashValue]:=nil; - raise; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - end else begin - result:=nil; - end; -end; - -end. diff --git a/3rd/besen/src/BESENEvalCacheItem.pas b/3rd/besen/src/BESENEvalCacheItem.pas deleted file mode 100644 index 49b50ee4d..000000000 --- a/3rd/besen/src/BESENEvalCacheItem.pas +++ /dev/null @@ -1,85 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENEvalCacheItem; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENRegExp,BESENASTNodes; - -type TBESENEvalCacheItem=class(TBESENBaseObject) - public - ReferenceCounter:integer; - Source:TBESENString; - CallerStrict:TBESENBoolean; - Node:TBESENASTNodeProgram; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure IncRef; - procedure DecRef; - end; - - TBESENEvalCacheItems=array of TBESENEvalCacheItem; - -implementation - -uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; - -constructor TBESENEvalCacheItem.Create(AInstance:TObject); -begin - inherited Create(Instance); - ReferenceCounter:=0; - Source:=''; - CallerStrict:=false; - Node:=nil; -end; - -destructor TBESENEvalCacheItem.Destroy; -begin - BESENFreeAndNil(Node); - Source:=''; - inherited Destroy; -end; - -procedure TBESENEvalCacheItem.IncRef; -begin - inc(ReferenceCounter); -end; - -procedure TBESENEvalCacheItem.DecRef; -begin - dec(ReferenceCounter); - if ReferenceCounter<=0 then begin - Destroy; - end; -end; - -end. diff --git a/3rd/besen/src/BESENGarbageCollector.pas b/3rd/besen/src/BESENGarbageCollector.pas deleted file mode 100644 index 2e523a97d..000000000 --- a/3rd/besen/src/BESENGarbageCollector.pas +++ /dev/null @@ -1,991 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENGarbageCollector; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENBaseObject,BESENCollectorObject, - BESENPointerSelfBalancedTree,BESENValue; - -type TBESENGarbageCollectorObjectList=class; - - TBESENGarbageCollectorObject=class(TBESENCollectorObject) - public - GarbageCollectorPrevious,GarbageCollectorNext, - GarbageCollectorRootObjectListPrevious,GarbageCollectorRootObjectListNext, - GarbageCollectorProtectedObjectListPrevious,GarbageCollectorProtectedObjectListNext, - GarbageCollectorObjectListPrevious,GarbageCollectorObjectListNext:TBESENGarbageCollectorObject; - GarbageCollectorObjectList:TBESENGarbageCollectorObjectList; - GarbageCollectorDependsChildren,GarbageCollectorDependsParents:TBESENPointerSelfBalancedTree; - GarbageCollectorLockReferenceCounter:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Finalize; virtual; - procedure Mark; virtual; - procedure DependsOn(Parent:TBESENGarbageCollectorObject); - procedure GarbageCollectorWriteBarrier; - procedure GarbageCollectorLock; - procedure GarbageCollectorUnlock; - end; - - TBESENGarbageCollectorRootObjectList=class(TBESENBaseObject) - public - First,Last:TBESENGarbageCollectorObject; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Clear; - procedure ClearWithFree; - procedure Add(AObject:TBESENGarbageCollectorObject); - procedure Remove(AObject:TBESENGarbageCollectorObject); - function Contains(AObject:TBESENGarbageCollectorObject):boolean; - procedure Push(AObject:TBESENGarbageCollectorObject); - function Pop:TBESENGarbageCollectorObject; - end; - - TBESENGarbageCollectorProtectedObjectList=class(TBESENBaseObject) - public - First,Last:TBESENGarbageCollectorObject; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Clear; - procedure ClearWithFree; - procedure Add(AObject:TBESENGarbageCollectorObject); - procedure Remove(AObject:TBESENGarbageCollectorObject); - function Contains(AObject:TBESENGarbageCollectorObject):boolean; - procedure Push(AObject:TBESENGarbageCollectorObject); - function Pop:TBESENGarbageCollectorObject; - end; - - TBESENGarbageCollectorObjectList=class(TBESENBaseObject) - public - First,Last:TBESENGarbageCollectorObject; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Clear; - procedure ClearWithFree; - procedure Add(AObject:TBESENGarbageCollectorObject); - procedure Remove(AObject:TBESENGarbageCollectorObject); - function Contains(AObject:TBESENGarbageCollectorObject):boolean; - procedure Push(AObject:TBESENGarbageCollectorObject); - function Pop:TBESENGarbageCollectorObject; - end; - - TBESENGarbageCollectorState=(bgcsINIT,bgcsMARKROOTS,bgcsMARKPROTECTED,bgcsMARKPROGRAMNODES,bgcsMARKCONTEXTS,bgcsMARKGRAYS,bgcsSWEEPWHITES,bgcsDONE); - - TBESENGarbageCollector=class(TBESENBaseObject) - public - First,Last:TBESENGarbageCollectorObject; - CurrentRootObject:TBESENGarbageCollectorObject; - CurrentProtectedObject:TBESENGarbageCollectorObject; - CurrentMarkObject:TBESENGarbageCollectorObject; - CurrentSweepObject:TBESENGarbageCollectorObject; - CurrentContext:TObject; - RootObjectList:TBESENGarbageCollectorRootObjectList; - ProtectedObjectList:TBESENGarbageCollectorProtectedObjectList; - WhiteObjectList:TBESENGarbageCollectorObjectList; - GrayObjectList:TBESENGarbageCollectorObjectList; - BlackObjectList:TBESENGarbageCollectorObjectList; - IsSweeping:longbool; - State:TBESENGarbageCollectorState; - TriggerCounter:integer; - MarkFactor:integer; - TriggerCountPerCollect:integer; - Count:int64; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Clear; - procedure Reset; - procedure WhiteIt(AObject:TBESENGarbageCollectorObject); - procedure ForceGrayIt(AObject:TBESENGarbageCollectorObject); - procedure GrayIt(AObject:TBESENGarbageCollectorObject); - procedure BlackIt(AObject:TBESENGarbageCollectorObject); - procedure Protect(AObject:TBESENGarbageCollectorObject); - procedure Unprotect(AObject:TBESENGarbageCollectorObject); - procedure FinalizeObjectForSweeping(AObject:TBESENGarbageCollectorObject); - procedure GrayValue(var Value:TBESENValue); - procedure FinalizeValue(var Value:TBESENValue); - procedure Mark(AObject:TBESENGarbageCollectorObject); - procedure Flip; - procedure TriggerCollect; - function Collect:boolean; - procedure CollectAll; - procedure Use(AObject:TBESENGarbageCollectorObject); - procedure Add(AObject:TBESENGarbageCollectorObject); - procedure AddRoot(AObject:TBESENGarbageCollectorObject); - procedure RemoveRoot(AObject:TBESENGarbageCollectorObject); - procedure AddProtected(AObject:TBESENGarbageCollectorObject); - procedure RemoveProtected(AObject:TBESENGarbageCollectorObject); - procedure LockObject(Obj:TBESENGarbageCollectorObject); - procedure UnlockObject(Obj:TBESENGarbageCollectorObject); - procedure LockValue(const Value:TBESENValue); - procedure UnlockValue(const Value:TBESENValue); - end; - -implementation - -uses BESEN,BESENUtils,BESENObject,BESENEnvironmentRecord, - BESENASTNodes,BESENCode,BESENContext, - BESENObjectDeclaredFunction; - -constructor TBESENGarbageCollectorObject.Create(AInstance:TObject); -begin - inherited Create(AInstance); - inc(TBESEN(Instance).GarbageCollector.Count); - GarbageCollectorPrevious:=TBESEN(Instance).GarbageCollector.Last; - GarbageCollectorNext:=nil; - if assigned(GarbageCollectorPrevious) then begin - GarbageCollectorPrevious.GarbageCollectorNext:=self; - end else begin - TBESEN(Instance).GarbageCollector.First:=self; - end; - TBESEN(Instance).GarbageCollector.Last:=self; - GarbageCollectorRootObjectListPrevious:=nil; - GarbageCollectorRootObjectListNext:=nil; - GarbageCollectorProtectedObjectListPrevious:=nil; - GarbageCollectorProtectedObjectListNext:=nil; - GarbageCollectorObjectListPrevious:=nil; - GarbageCollectorObjectListNext:=nil; - GarbageCollectorObjectList:=nil; - GarbageCollectorDependsChildren:=TBESENPointerSelfBalancedTree.Create; - GarbageCollectorDependsParents:=TBESENPointerSelfBalancedTree.Create; - GarbageCollectorLockReferenceCounter:=0; -end; - -destructor TBESENGarbageCollectorObject.Destroy; -var n:PBESENPointerSelfBalancedTreeNode; -begin - if assigned(GarbageCollectorPrevious) then begin - GarbageCollectorPrevious.GarbageCollectorNext:=GarbageCollectorNext; - end else if TBESEN(Instance).GarbageCollector.First=self then begin - TBESEN(Instance).GarbageCollector.First:=GarbageCollectorNext; - end; - if assigned(GarbageCollectorNext) then begin - GarbageCollectorNext.GarbageCollectorPrevious:=GarbageCollectorPrevious; - end else if TBESEN(Instance).GarbageCollector.Last=self then begin - TBESEN(Instance).GarbageCollector.Last:=GarbageCollectorPrevious; - end; - GarbageCollectorNext:=nil; - GarbageCollectorPrevious:=nil; - if assigned(GarbageCollectorObjectList) then begin - GarbageCollectorObjectList.Remove(self); - GarbageCollectorObjectList:=nil; - end; - if assigned(GarbageCollectorDependsParents) then begin - n:=GarbageCollectorDependsParents.FirstKey; - while assigned(n) do begin - if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren) then begin - TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren.Remove(self); - end; - n:=n^.NextKey; - end; - end; - if assigned(GarbageCollectorDependsChildren) then begin - n:=GarbageCollectorDependsChildren.FirstKey; - while assigned(n) do begin - if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents) then begin - TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents.Remove(self); - end; - n:=n^.NextKey; - end; - end; - BESENFreeAndNil(GarbageCollectorDependsChildren); - BESENFreeAndNil(GarbageCollectorDependsParents); - if assigned(Instance) and assigned(TBESEN(Instance).GarbageCollector) then begin - if assigned(TBESEN(Instance).GarbageCollector.RootObjectList) and TBESEN(Instance).GarbageCollector.RootObjectList.Contains(self) then begin - TBESEN(Instance).GarbageCollector.RootObjectList.Remove(self); - end; - if assigned(TBESEN(Instance).GarbageCollector.ProtectedObjectList) and TBESEN(Instance).GarbageCollector.ProtectedObjectList.Contains(self) then begin - TBESEN(Instance).GarbageCollector.ProtectedObjectList.Remove(self); - end; - end; - dec(TBESEN(Instance).GarbageCollector.Count); - inherited Destroy; -end; - -procedure TBESENGarbageCollectorObject.Finalize; -var n:PBESENPointerSelfBalancedTreeNode; -begin - if assigned(GarbageCollectorDependsParents) then begin - n:=GarbageCollectorDependsParents.FirstKey; - while assigned(n) do begin - if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren) then begin - TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren.Remove(self); - end; - n:=n^.NextKey; - end; - end; - if assigned(GarbageCollectorDependsChildren) then begin - n:=GarbageCollectorDependsChildren.FirstKey; - while assigned(n) do begin - if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents) then begin - TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents.Remove(self); - end; - n:=n^.NextKey; - end; - end; -end; - -procedure TBESENGarbageCollectorObject.Mark; -var n:PBESENPointerSelfBalancedTreeNode; -begin - if assigned(GarbageCollectorDependsChildren) then begin - n:=GarbageCollectorDependsChildren.FirstKey; - while assigned(n) do begin - if assigned(n^.Key) then begin - TBESEN(Instance).GarbageCollector.GrayIt(TBESENGarbageCollectorObject(n^.Key)); - end; - n:=n^.NextKey; - end; - end; -end; - -procedure TBESENGarbageCollectorObject.DependsOn(Parent:TBESENGarbageCollectorObject); -var v:TBESENPointerSelfBalancedTreeValue; -begin - if assigned(Parent) then begin - if assigned(GarbageCollectorDependsParents) then begin - v.p:=Parent; - GarbageCollectorDependsParents.Insert(Parent,v); - end; - if assigned(Parent.GarbageCollectorDependsChildren) then begin - v.p:=self; - Parent.GarbageCollectorDependsChildren.Insert(self,v); - end; - end; -end; - -procedure TBESENGarbageCollectorObject.GarbageCollectorWriteBarrier; -begin - TBESEN(Instance).GarbageCollector.GrayIt(self); -end; - -procedure TBESENGarbageCollectorObject.GarbageCollectorLock; -begin - inc(GarbageCollectorLockReferenceCounter); -end; - -procedure TBESENGarbageCollectorObject.GarbageCollectorUnlock; -begin - dec(GarbageCollectorLockReferenceCounter); -end; - -constructor TBESENGarbageCollectorRootObjectList.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Clear; -end; - -destructor TBESENGarbageCollectorRootObjectList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENGarbageCollectorRootObjectList.Clear; -var Item,NextItem:TBESENGarbageCollectorObject; -begin - Item:=First; - while assigned(Item) do begin - NextItem:=Item.GarbageCollectorRootObjectListNext; - Item.GarbageCollectorRootObjectListPrevious:=nil; - Item.GarbageCollectorRootObjectListNext:=nil; - Item:=NextItem; - end; - First:=nil; - Last:=nil; -end; - -procedure TBESENGarbageCollectorRootObjectList.ClearWithFree; -begin - while assigned(First) do begin - First.Free; - end; - Clear; -end; - -procedure TBESENGarbageCollectorRootObjectList.Add(AObject:TBESENGarbageCollectorObject); -begin - if assigned(Last) then begin - Last.GarbageCollectorRootObjectListNext:=AObject; - AObject.GarbageCollectorRootObjectListPrevious:=Last; - AObject.GarbageCollectorRootObjectListNext:=nil; - Last:=AObject; - end else begin - First:=AObject; - Last:=AObject; - end; -end; - -procedure TBESENGarbageCollectorRootObjectList.Remove(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject.GarbageCollectorRootObjectListPrevious) then begin - AObject.GarbageCollectorRootObjectListPrevious.GarbageCollectorRootObjectListNext:=AObject.GarbageCollectorRootObjectListNext; - end else if First=AObject then begin - First:=AObject.GarbageCollectorRootObjectListNext; - end; - if assigned(AObject.GarbageCollectorRootObjectListNext) then begin - AObject.GarbageCollectorRootObjectListNext.GarbageCollectorRootObjectListPrevious:=AObject.GarbageCollectorRootObjectListPrevious; - end else if Last=AObject then begin - Last:=AObject.GarbageCollectorRootObjectListPrevious; - end; - AObject.GarbageCollectorRootObjectListNext:=nil; - AObject.GarbageCollectorRootObjectListPrevious:=nil; -end; - -function TBESENGarbageCollectorRootObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; -begin - result:=((First=AObject) or (Last=AObject)) or (assigned(AObject.GarbageCollectorRootObjectListNext) or assigned(AObject.GarbageCollectorRootObjectListPrevious)); -end; - -procedure TBESENGarbageCollectorRootObjectList.Push(AObject:TBESENGarbageCollectorObject); -begin - Add(AObject); -end; - -function TBESENGarbageCollectorRootObjectList.Pop:TBESENGarbageCollectorObject; -begin - result:=Last; - if assigned(result) then begin - Remove(result); - end; -end; - -constructor TBESENGarbageCollectorProtectedObjectList.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Clear; -end; - -destructor TBESENGarbageCollectorProtectedObjectList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENGarbageCollectorProtectedObjectList.Clear; -var Item,NextItem:TBESENGarbageCollectorObject; -begin - Item:=First; - while assigned(Item) do begin - NextItem:=Item.GarbageCollectorProtectedObjectListNext; - Item.GarbageCollectorProtectedObjectListPrevious:=nil; - Item.GarbageCollectorProtectedObjectListNext:=nil; - Item:=NextItem; - end; - First:=nil; - Last:=nil; -end; - -procedure TBESENGarbageCollectorProtectedObjectList.ClearWithFree; -begin - while assigned(First) do begin - First.Free; - end; - Clear; -end; - -procedure TBESENGarbageCollectorProtectedObjectList.Add(AObject:TBESENGarbageCollectorObject); -begin - if assigned(Last) then begin - Last.GarbageCollectorProtectedObjectListNext:=AObject; - AObject.GarbageCollectorProtectedObjectListPrevious:=Last; - AObject.GarbageCollectorProtectedObjectListNext:=nil; - Last:=AObject; - end else begin - First:=AObject; - Last:=AObject; - end; -end; - -procedure TBESENGarbageCollectorProtectedObjectList.Remove(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject.GarbageCollectorProtectedObjectListPrevious) then begin - AObject.GarbageCollectorProtectedObjectListPrevious.GarbageCollectorProtectedObjectListNext:=AObject.GarbageCollectorProtectedObjectListNext; - end else if First=AObject then begin - First:=AObject.GarbageCollectorProtectedObjectListNext; - end; - if assigned(AObject.GarbageCollectorProtectedObjectListNext) then begin - AObject.GarbageCollectorProtectedObjectListNext.GarbageCollectorProtectedObjectListPrevious:=AObject.GarbageCollectorProtectedObjectListPrevious; - end else if Last=AObject then begin - Last:=AObject.GarbageCollectorProtectedObjectListPrevious; - end; - AObject.GarbageCollectorProtectedObjectListNext:=nil; - AObject.GarbageCollectorProtectedObjectListPrevious:=nil; -end; - -function TBESENGarbageCollectorProtectedObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; -begin - result:=((First=AObject) or (Last=AObject)) or (assigned(AObject.GarbageCollectorProtectedObjectListNext) or assigned(AObject.GarbageCollectorProtectedObjectListPrevious)); -end; - -procedure TBESENGarbageCollectorProtectedObjectList.Push(AObject:TBESENGarbageCollectorObject); -begin - Add(AObject); -end; - -function TBESENGarbageCollectorProtectedObjectList.Pop:TBESENGarbageCollectorObject; -begin - result:=Last; - if assigned(result) then begin - Remove(result); - end; -end; - -constructor TBESENGarbageCollectorObjectList.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Clear; -end; - -destructor TBESENGarbageCollectorObjectList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENGarbageCollectorObjectList.Clear; -var Item,NextItem:TBESENGarbageCollectorObject; -begin - Item:=First; - while assigned(Item) do begin - NextItem:=Item.GarbageCollectorObjectListNext; - Item.GarbageCollectorObjectListPrevious:=nil; - Item.GarbageCollectorObjectListNext:=nil; - Item.GarbageCollectorObjectList:=nil; - Item:=NextItem; - end; - First:=nil; - Last:=nil; -end; - -procedure TBESENGarbageCollectorObjectList.ClearWithFree; -begin - while assigned(First) do begin - First.Free; - end; - Clear; -end; - -procedure TBESENGarbageCollectorObjectList.Add(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject.GarbageCollectorObjectList) then begin - AObject.GarbageCollectorObjectList.Remove(AObject); - end; - AObject.GarbageCollectorObjectList:=self; - if assigned(Last) then begin - AObject.GarbageCollectorObjectListPrevious:=Last; - Last.GarbageCollectorObjectListNext:=AObject; - end else begin - First:=AObject; - AObject.GarbageCollectorObjectListPrevious:=nil; - end; - AObject.GarbageCollectorObjectListNext:=nil; - Last:=AObject; -end; - -procedure TBESENGarbageCollectorObjectList.Remove(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject.GarbageCollectorObjectListPrevious) then begin - AObject.GarbageCollectorObjectListPrevious.GarbageCollectorObjectListNext:=AObject.GarbageCollectorObjectListNext; - end else if First=AObject then begin - First:=AObject.GarbageCollectorObjectListNext; - end; - if assigned(AObject.GarbageCollectorObjectListNext) then begin - AObject.GarbageCollectorObjectListNext.GarbageCollectorObjectListPrevious:=AObject.GarbageCollectorObjectListPrevious; - end else if Last=AObject then begin - Last:=AObject.GarbageCollectorObjectListPrevious; - end; - AObject.GarbageCollectorObjectListNext:=nil; - AObject.GarbageCollectorObjectListPrevious:=nil; - AObject.GarbageCollectorObjectList:=nil; -end; - -function TBESENGarbageCollectorObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; -begin - result:=AObject.GarbageCollectorObjectList=self; -end; - -procedure TBESENGarbageCollectorObjectList.Push(AObject:TBESENGarbageCollectorObject); -begin - Add(AObject); -end; - -function TBESENGarbageCollectorObjectList.Pop:TBESENGarbageCollectorObject; -begin - result:=Last; - if assigned(result) then begin - Remove(result); - end; -end; - -constructor TBESENGarbageCollector.Create(AInstance:TObject); -begin - inherited Create(AInstance); - First:=nil; - Last:=nil; - RootObjectList:=TBESENGarbageCollectorRootObjectList.Create(Instance); - ProtectedObjectList:=TBESENGarbageCollectorProtectedObjectList.Create(Instance); - WhiteObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); - GrayObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); - BlackObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); - IsSweeping:=false; - State:=bgcsINIT; - TriggerCounter:=0; - MarkFactor:=BESEN_GC_MARKFACTOR; - TriggerCountPerCollect:=BESEN_GC_TRIGGERCOUNT_PER_COLLECT; - Count:=0; -end; - -destructor TBESENGarbageCollector.Destroy; -begin - Clear; - RootObjectList.Free; - ProtectedObjectList.Free; - WhiteObjectList.Free; - GrayObjectList.Free; - BlackObjectList.Free; - inherited Destroy; -end; - -procedure TBESENGarbageCollector.Clear; -var CurrentObject:TBESENGarbageCollectorObject; -begin - CurrentObject:=First; - while assigned(CurrentObject) do begin - FinalizeObjectForSweeping(CurrentObject); - CurrentObject:=CurrentObject.GarbageCollectorNext; - end; - while assigned(First) do begin - First.Free; - end; - First:=nil; - Last:=nil; - RootObjectList.Clear; - ProtectedObjectList.Clear; - WhiteObjectList.Clear; - GrayObjectList.Clear; - BlackObjectList.Clear; - CurrentRootObject:=nil; - CurrentProtectedObject:=nil; - CurrentMarkObject:=nil; - CurrentSweepObject:=nil; - TriggerCounter:=0; - Count:=0; - State:=bgcsINIT; - IsSweeping:=false; -end; - -procedure TBESENGarbageCollector.Reset; -begin - Flip; - CurrentRootObject:=nil; - CurrentProtectedObject:=nil; - CurrentSweepObject:=nil; - State:=bgcsINIT; -end; - -procedure TBESENGarbageCollector.WhiteIt(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject) and not WhiteObjectList.Contains(AObject) then begin - if assigned(AObject.GarbageCollectorObjectList) then begin - AObject.GarbageCollectorObjectList.Remove(AObject); - AObject.GarbageCollectorObjectList:=nil; - end; - WhiteObjectList.Push(AObject); - end; -end; - -procedure TBESENGarbageCollector.ForceGrayIt(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject) and not GrayObjectList.Contains(AObject) then begin - if assigned(AObject.GarbageCollectorObjectList) then begin - AObject.GarbageCollectorObjectList.Remove(AObject); - AObject.GarbageCollectorObjectList:=nil; - end; - GrayObjectList.Push(AObject); - end; -end; - -procedure TBESENGarbageCollector.GrayIt(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject) and not (GrayObjectList.Contains(AObject) or BlackObjectList.Contains(AObject)) then begin - if assigned(AObject.GarbageCollectorObjectList) then begin - AObject.GarbageCollectorObjectList.Remove(AObject); - AObject.GarbageCollectorObjectList:=nil; - end; - GrayObjectList.Push(AObject); - end; -end; - -procedure TBESENGarbageCollector.BlackIt(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject) and not BlackObjectList.Contains(AObject) then begin - if assigned(AObject.GarbageCollectorObjectList) then begin - AObject.GarbageCollectorObjectList.Remove(AObject); - AObject.GarbageCollectorObjectList:=nil; - end; - BlackObjectList.Push(AObject); - end; -end; - -procedure TBESENGarbageCollector.Protect(AObject:TBESENGarbageCollectorObject); -begin - AddProtected(AObject); -end; - -procedure TBESENGarbageCollector.Unprotect(AObject:TBESENGarbageCollectorObject); -begin - RemoveProtected(AObject); -end; - -procedure TBESENGarbageCollector.GrayValue(var Value:TBESENValue); -begin - case Value.ValueType of - bvtOBJECT:begin - if assigned(Value.Obj) then begin - GrayIt(TBESENObject(Value.Obj)); - end; - end; - bvtREFERENCE:begin - case Value.ReferenceBase.ValueType of - brbvtOBJECT:begin - if assigned(Value.ReferenceBase.Obj) then begin - GrayIt(TBESENObject(Value.ReferenceBase.Obj)); - end; - end; - brbvtENVREC:begin - if assigned(Value.ReferenceBase.EnvRec) then begin - GrayIt(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); - end; - end; - end; - end; - end; -end; - -procedure TBESENGarbageCollector.FinalizeValue(var Value:TBESENValue); -begin - Value:=BESENEmptyValue; -end; - -procedure TBESENGarbageCollector.Mark(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject) then begin - AObject.Mark; - end; -end; - -procedure TBESENGarbageCollector.FinalizeObjectForSweeping(AObject:TBESENGarbageCollectorObject); -begin - if assigned(AObject) then begin - AObject.Finalize; - end; -end; - -procedure TBESENGarbageCollector.Flip; -var TempObjectList:TBESENGarbageCollectorObjectList; -begin - TempObjectList:=WhiteObjectList; - WhiteObjectList:=BlackObjectList; - BlackObjectList:=TempObjectList; -end; - -procedure TBESENGarbageCollector.TriggerCollect; -begin - inc(TriggerCounter); - if TriggerCounter>=TriggerCountPerCollect then begin - TriggerCounter:=0; - Collect; - end; -end; - -function TBESENGarbageCollector.Collect:boolean; -var i:integer; - MarkCount:int64; - Current:PBESENPointerSelfBalancedTreeNode; - Node:TBESENASTNodeProgram; - NextObject:TBESENGarbageCollectorObject; -begin - result:=false; - while true do begin - case State of - bgcsINIT:begin - State:=bgcsMARKROOTS; - CurrentRootObject:=RootObjectList.First; - end; - bgcsMARKROOTS:begin - result:=false; - MarkCount:=(MarkFactor*Count) div 256; - if MarkCount<256 then begin - MarkCount:=256; - end else if MarkCount>$7fffffff then begin - MarkCount:=$7fffffff; - end; - for i:=1 to MarkCount do begin - if assigned(CurrentRootObject) then begin - BlackIt(CurrentRootObject); - Mark(CurrentRootObject); - CurrentRootObject:=CurrentRootObject.GarbageCollectorRootObjectListNext; - result:=assigned(CurrentRootObject); - end else begin - break; - end; - end; - if result then begin - break; - end else begin - CurrentProtectedObject:=ProtectedObjectList.First; - State:=bgcsMARKPROTECTED; - end; - end; - bgcsMARKPROTECTED:begin - result:=false; - MarkCount:=(MarkFactor*Count) div 256; - if MarkCount<256 then begin - MarkCount:=256; - end else if MarkCount>$7fffffff then begin - MarkCount:=$7fffffff; - end; - for i:=1 to MarkCount do begin - if assigned(CurrentProtectedObject) then begin - BlackIt(CurrentProtectedObject); - Mark(CurrentProtectedObject); - CurrentProtectedObject:=CurrentProtectedObject.GarbageCollectorProtectedObjectListNext; - result:=assigned(CurrentProtectedObject); - end else begin - break; - end; - end; - if result then begin - break; - end else begin - State:=bgcsMARKPROGRAMNODES; - end; - end; - bgcsMARKPROGRAMNODES:begin - Current:=TBESEN(Instance).ProgramNodes.FirstKey; - while assigned(Current) do begin - Node:=TBESENASTNodeProgram(Current^.Key); - if assigned(Node) and assigned(Node.Body) and assigned(Node.Body.Code) then begin - TBESENCode(Node.Body.Code).Mark; - end; - Current:=Current^.NextKey; - end; - CurrentContext:=TBESEN(Instance).ContextFirst; - State:=bgcsMARKCONTEXTS; - end; - bgcsMARKCONTEXTS:begin - result:=false; - while assigned(CurrentContext) do begin - TBESENContext(CurrentContext).Mark; - CurrentContext:=TBESENContext(CurrentContext).Next; - result:=assigned(CurrentContext); - end; - if result then begin - break; - end else begin - State:=bgcsMARKGRAYS; - end; - end; - bgcsMARKGRAYS:begin - result:=false; - MarkCount:=(MarkFactor*Count) div 256; - if MarkCount<256 then begin - MarkCount:=256; - end else if MarkCount>$7fffffff then begin - MarkCount:=$7fffffff; - end; - for i:=1 to MarkCount do begin - CurrentMarkObject:=GrayObjectList.Pop; - if assigned(CurrentMarkObject) then begin - Mark(CurrentMarkObject); - BlackIt(CurrentMarkObject); - result:=assigned(GrayObjectList.Last); - end else begin - break; - end; - end; - if result then begin - break; - end else begin - CurrentSweepObject:=WhiteObjectList.First; - State:=bgcsSWEEPWHITES; - end; - end; - bgcsSWEEPWHITES:begin - while assigned(CurrentSweepObject) do begin - NextObject:=CurrentSweepObject.GarbageCollectorObjectListNext; - if (CurrentSweepObject.GarbageCollectorLockReferenceCounter>0) or ProtectedObjectList.Contains(CurrentSweepObject) then begin - GrayIt(CurrentSweepObject); - end; - CurrentSweepObject:=NextObject; - end; - if assigned(GrayObjectList.First) then begin - State:=bgcsMARKGRAYS; - end else begin - CurrentSweepObject:=WhiteObjectList.First; - if assigned(CurrentSweepObject) then begin - while assigned(CurrentSweepObject) do begin - FinalizeObjectForSweeping(CurrentSweepObject); - CurrentSweepObject:=CurrentSweepObject.GarbageCollectorObjectListNext; - end; - while assigned(WhiteObjectList.First) do begin - IsSweeping:=true; - WhiteObjectList.First.Free; - IsSweeping:=false; - end; - end; - State:=bgcsDONE; - end; - end; - bgcsDONE:begin - Flip; - State:=bgcsINIT; - result:=false; - break; - end; - end; - end; -end; - -procedure TBESENGarbageCollector.CollectAll; -begin - while Collect do begin - end; -end; - -procedure TBESENGarbageCollector.Use(AObject:TBESENGarbageCollectorObject); -begin - ForceGrayIt(AObject); -end; - -procedure TBESENGarbageCollector.Add(AObject:TBESENGarbageCollectorObject); -begin - GrayIt(AObject); -end; - -procedure TBESENGarbageCollector.AddRoot(AObject:TBESENGarbageCollectorObject); -begin - RootObjectList.Add(AObject); - State:=bgcsINIT; -end; - -procedure TBESENGarbageCollector.RemoveRoot(AObject:TBESENGarbageCollectorObject); -begin - State:=bgcsINIT; - if RootObjectList.Contains(AObject) then begin - RootObjectList.Remove(AObject); - ForceGrayIt(AObject); - end; -end; - -procedure TBESENGarbageCollector.AddProtected(AObject:TBESENGarbageCollectorObject); -begin - GrayIt(AObject); - ProtectedObjectList.Add(AObject); - State:=bgcsINIT; -end; - -procedure TBESENGarbageCollector.RemoveProtected(AObject:TBESENGarbageCollectorObject); -begin - State:=bgcsINIT; - if ProtectedObjectList.Contains(AObject) then begin - ProtectedObjectList.Remove(AObject); - ForceGrayIt(AObject); - end; -end; - -procedure TBESENGarbageCollector.LockObject(Obj:TBESENGarbageCollectorObject); -begin - if assigned(Obj) then begin - Obj.GarbageCollectorLock; - end; -end; - -procedure TBESENGarbageCollector.UnlockObject(Obj:TBESENGarbageCollectorObject); -begin - if assigned(Obj) then begin - Obj.GarbageCollectorUnlock; - end; -end; - -procedure TBESENGarbageCollector.LockValue(const Value:TBESENValue); -begin - case Value.ValueType of - bvtOBJECT:begin - if assigned(Value.Obj) then begin - LockObject(TBESENObject(Value.Obj)); - end; - end; - bvtREFERENCE:begin - case Value.ReferenceBase.ValueType of - brbvtOBJECT:begin - if assigned(Value.ReferenceBase.Obj) then begin - LockObject(TBESENObject(Value.ReferenceBase.Obj)); - end; - end; - brbvtENVREC:begin - if assigned(Value.ReferenceBase.EnvRec) then begin - LockObject(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); - end; - end; - end; - end; - end; -end; - -procedure TBESENGarbageCollector.UnlockValue(const Value:TBESENValue); -begin - case Value.ValueType of - bvtOBJECT:begin - if assigned(Value.Obj) then begin - UnlockObject(TBESENObject(Value.Obj)); - end; - end; - bvtREFERENCE:begin - case Value.ReferenceBase.ValueType of - brbvtOBJECT:begin - if assigned(Value.ReferenceBase.Obj) then begin - UnlockObject(TBESENObject(Value.ReferenceBase.Obj)); - end; - end; - brbvtENVREC:begin - if assigned(Value.ReferenceBase.EnvRec) then begin - UnlockObject(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); - end; - end; - end; - end; - end; -end; - -end. diff --git a/3rd/besen/src/BESENGlobals.pas b/3rd/besen/src/BESENGlobals.pas deleted file mode 100644 index 6880c1f2b..000000000 --- a/3rd/besen/src/BESENGlobals.pas +++ /dev/null @@ -1,42 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENGlobals; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -var BESENLengthHash:TBESENHash; - -implementation - -end. diff --git a/3rd/besen/src/BESENHashMap.pas b/3rd/besen/src/BESENHashMap.pas deleted file mode 100644 index cb7e502a0..000000000 --- a/3rd/besen/src/BESENHashMap.pas +++ /dev/null @@ -1,308 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENHashMap; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils,BESENHashUtils; - -type PBESENHashMapItem=^TBESENHashMapItem; - TBESENHashMapItem=record - Previous,Next,HashPrevious,HashNext:PBESENHashMapItem; - Hash:TBESENHash; - Key:TBESENString; - Value:int64; - Ptr:pointer; - end; - - TBESENHashMapHashBucket=record - HashFirst,HashLast:PBESENHashMapItem; - end; - - TBESENHashMapHashBuckets=array of TBESENHashMapHashBucket; - - TBESENHashMap=class - private - LastUsedItem:PBESENHashMapItem; - procedure GrowAndRehashIfNeeded; - public - First,Last:PBESENHashMapItem; - HashBuckets:TBESENHashMapHashBuckets; - HashSize:longword; - HashSizeMask:longword; - HashedItems:longword; - HashBucketsUsed:longword; - constructor Create; - destructor Destroy; override; - procedure Clear; - function GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENHashMapItem; - function NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENHashMapItem; - function DeleteKey(const Item:PBESENHashMapItem):TBESENBoolean; - end; - -implementation - -constructor TBESENHashMap.Create; -var Hash:TBESENHash; -begin - inherited Create; - FillChar(HashBuckets,sizeof(TBESENHashMapHashBuckets),#0); - First:=nil; - Last:=nil; - HashSize:=256; - HashSizeMask:=HashSize-1; - HashedItems:=0; - HashBucketsUsed:=0; - HashBuckets:=nil; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - LastUsedItem:=nil; -end; - -destructor TBESENHashMap.Destroy; -begin - Clear; - SetLength(HashBuckets,0); - inherited Destroy; -end; - -procedure TBESENHashMap.Clear; -var Hash:TBESENHash; - Item,NextItem:PBESENHashMapItem; -begin - Item:=First; - while assigned(Item) do begin - NextItem:=Item^.Next; - Item^.Next:=nil; - Item^.Key:=''; - Dispose(Item); - Item:=NextItem; - end; - First:=nil; - Last:=nil; - LastUsedItem:=nil; - HashSize:=256; - HashSizeMask:=HashSize-1; - HashedItems:=0; - HashBucketsUsed:=0; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; -end; - -procedure TBESENHashMap.GrowAndRehashIfNeeded; -var Hash:TBESENHash; - Item:PBESENHashMapItem; -begin - if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin - LastUsedItem:=nil; - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - inc(HashSize,HashSize); - if HashSize>BESENHashMaxSize then begin - HashSize:=BESENHashMaxSize; - end; - HashSizeMask:=HashSize-1; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - HashedItems:=0; - Item:=First; - while assigned(Item) do begin - inc(HashedItems); - Item^.HashPrevious:=nil; - Item^.HashNext:=nil; - Item:=Item^.Next; - end; - HashBucketsUsed:=0; - Item:=First; - while assigned(Item) do begin - Hash:=BESENHashKey(Item^.Key) and HashSizeMask; - Item^.Hash:=Hash; - if assigned(HashBuckets[Hash].HashLast) then begin - HashBuckets[Hash].HashLast^.HashNext:=Item; - Item^.HashPrevious:=HashBuckets[Hash].HashLast; - HashBuckets[Hash].HashLast:=Item; - Item^.HashNext:=nil; - end else begin - inc(HashBucketsUsed); - HashBuckets[Hash].HashFirst:=Item; - HashBuckets[Hash].HashLast:=Item; - Item^.HashPrevious:=nil; - Item^.HashNext:=nil; - end; - Item:=Item^.Next; - end; - end; -end; - -function TBESENHashMap.GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENHashMapItem; -begin - if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin - result:=LastUsedItem; - Hash:=result^.Hash; - end else begin - if Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - result:=HashBuckets[Hash].HashFirst; - while assigned(result) and (result^.Key<>Key) do begin - result:=result^.HashNext; - end; - end; - if assigned(result) then begin - LastUsedItem:=result; - if HashBuckets[Hash].HashFirst<>result then begin - if assigned(result^.HashPrevious) then begin - result^.HashPrevious^.HashNext:=result^.HashNext; - end; - if assigned(result^.HashNext) then begin - result^.HashNext^.HashPrevious:=result^.HashPrevious; - end else if HashBuckets[Hash].HashLast=result then begin - HashBuckets[Hash].HashLast:=result^.HashPrevious; - end; - HashBuckets[Hash].HashFirst^.HashPrevious:=result; - result^.HashNext:=HashBuckets[Hash].HashFirst; - result^.HashPrevious:=nil; - HashBuckets[Hash].HashFirst:=result; - end; - end; -end; - -function TBESENHashMap.NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENHashMapItem; -begin - if Force then begin - result:=nil; - if Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - end else if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin - result:=LastUsedItem; - Hash:=result^.Hash; - end else begin - if Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - result:=HashBuckets[Hash].HashFirst; - if not assigned(result) then begin - inc(HashBucketsUsed); - end; - while assigned(result) and not (result^.Key<>Key) do begin - result:=result^.HashNext; - end; - end; - if not assigned(result) then begin - inc(HashedItems); - New(result); - fillchar(result^,sizeof(TBESENHashMapItem),#0); - result^.Hash:=Hash; - result^.Key:=Key; - if assigned(HashBuckets[Hash].HashLast) then begin - HashBuckets[Hash].HashLast^.HashNext:=result; - result^.HashPrevious:=HashBuckets[Hash].HashLast; - result^.HashNext:=nil; - HashBuckets[Hash].HashLast:=result; - end else begin - HashBuckets[Hash].HashFirst:=result; - HashBuckets[Hash].HashLast:=result; - result^.HashPrevious:=nil; - result^.HashNext:=nil; - end; - if assigned(Last) then begin - Last^.Next:=result; - result^.Previous:=Last; - result^.Next:=nil; - Last:=result; - end else begin - First:=result; - Last:=result; - result^.Previous:=nil; - result^.Next:=nil; - end; - LastUsedItem:=result; - end; - GrowAndRehashIfNeeded; -end; - -function TBESENHashMap.DeleteKey(const Item:PBESENHashMapItem):TBESENBoolean; -begin - result:=assigned(Item); - if result then begin - if LastUsedItem=Item then begin - if assigned(Item^.Next) then begin - LastUsedItem:=Item^.Next; - end else begin - LastUsedItem:=Item^.Previous; - end; - end; - if assigned(Item^.Previous) then begin - Item^.Previous^.Next:=Item^.Next; - end else if First=Item then begin - First:=Item^.Next; - end; - if assigned(Item^.Next) then begin - Item^.Next^.Previous:=Item^.Previous; - end else if Last=Item then begin - Last:=Item^.Previous; - end; - Item^.Next:=nil; - Item^.Previous:=nil; - if assigned(Item^.HashPrevious) then begin - Item^.HashPrevious^.HashNext:=Item^.HashNext; - end else if HashBuckets[Item^.Hash].HashFirst=Item then begin - HashBuckets[Item^.Hash].HashFirst:=Item^.HashNext; - end; - if assigned(Item^.HashNext) then begin - Item^.HashNext^.HashPrevious:=Item^.HashPrevious; - end else if HashBuckets[Item^.Hash].HashLast=Item then begin - HashBuckets[Item^.Hash].HashLast:=Item^.HashPrevious; - end; - Item^.HashNext:=nil; - Item^.HashPrevious:=nil; - Item^.Key:=''; - Dispose(Item); - end; -end; - -end. diff --git a/3rd/besen/src/BESENHashUtils.pas b/3rd/besen/src/BESENHashUtils.pas deleted file mode 100644 index 2655a42bb..000000000 --- a/3rd/besen/src/BESENHashUtils.pas +++ /dev/null @@ -1,159 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENHashUtils; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -function BESENHashKey(const Key:TBESENString):TBESENHash; -function BESENDoubleHash(Hash:TBESENHash):TBESENHash; - -implementation - -function BESENHashKey(const Key:TBESENString):TBESENHash; -{$ifdef PurePascal} -var i,h:longword; -begin - h:=2166136261; - for i:=1 to length(Key) do begin -{$ifdef UseOptimizedHashing} - h:=h xor ord(Key[i]); - inc(h,(h shl 1)+(h shl 4)+(h shl 7)+(h shl 8)+(h shl 24)); -{$else} - h:=(h xor ord(Key[i]))*16777619; -{$endif} - end; - if h=0 then begin - // result must be never zero ! ! ! - result:=$ffffffff; - end else begin - result:=h; - end; -end; -{$else} -{$ifdef cpu64} -var i:longword; - h:{$ifdef fpc}qword{$else}int64{$endif}; -begin - h:={$ifdef fpc}qword(14695981039346656037){$else}int64($14650FB0739D0383){$endif}; - for i:=1 to length(Key) do begin -{$ifdef UseOptimizedHashing} - h:=h xor word(widechar(Key[i])); - inc(h,(h shl 1)+(h shl 4)+(h shl 5)+(h shl 7)+(h shl 8)+(h shl 40)); -{$else} - h:=(h xor word(widechar(Key[i])))*1099511628211; -{$endif} - end; - result:=h; - dec(result,ord(result=0)); -end; -{$else} -{$ifdef cpu386} assembler; register; -asm - push ebx - push esi - push edi - test eax,eax - jz @Zero - mov ecx,dword ptr [eax-4] - jecxz @Zero - shr ecx,1 - mov esi,eax - mov eax,2166136261 - xor ebx,ebx -{$ifndef UseOptimizedHashing} - mov edi,16777619 -{$endif} - @Loop: - mov bx,word ptr [esi] - xor eax,ebx -{$ifdef UseOptimizedHashing} - mov ebx,eax - mov edi,ebx - add edi,edi - add eax,edi - mov edi,ebx - shl edi,4 - add eax,edi - mov edi,ebx - shl edi,7 - add eax,edi - mov edi,ebx - shl edi,8 - add eax,edi - shl ebx,24 - add eax,ebx -{$else} - mul edi -{$endif} - add esi,2 - dec ecx - jnz @Loop - or eax,eax - jnz @Done - @Zero: - xor eax,eax - not eax - @Done: - pop edi - pop esi - pop ebx -end; -{$else} -var i,h:longword; -begin - h:=2166136261; - for i:=1 to length(Key) do begin -{$ifdef UseOptimizedHashing} - h:=h xor word(widechar(Key[i])); - inc(h,(h shl 1)+(h shl 4)+(h shl 7)+(h shl 8)+(h shl 24)); -{$else} - h:=(h xor word(widechar(Key[i])))*16777619; -{$endif} - end; - result:=h-ord(h=0); -end; -{$endif} -{$endif} -{$endif} - -function BESENDoubleHash(Hash:TBESENHash):TBESENHash; -begin - result:=(not Hash)+(Hash shr 23); - result:=result xor (result shl 22); - result:=result xor (result shr 7); - result:=result xor (result shl 2); - result:=result xor (result shr 20); -end; - -end. diff --git a/3rd/besen/src/BESENInt64SelfBalancedTree.pas b/3rd/besen/src/BESENInt64SelfBalancedTree.pas deleted file mode 100644 index 391124762..000000000 --- a/3rd/besen/src/BESENInt64SelfBalancedTree.pas +++ /dev/null @@ -1,632 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENInt64SelfBalancedTree; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils; - -type PBESENInt64SelfBalancedTreeValue=^TBESENInt64SelfBalancedTreeValue; - TBESENInt64SelfBalancedTreeValue=record - case boolean of - false:(i:int64); - true:(p:pointer); - end; - - PBESENInt64SelfBalancedTreeNode=^TBESENInt64SelfBalancedTreeNode; - TBESENInt64SelfBalancedTreeNode=record - Parent,Left,Right,PreviousKey,NextKey:PBESENInt64SelfBalancedTreeNode; - Level:int64; - Key:int64; - Value:TBESENInt64SelfBalancedTreeValue; - end; - - TBESENInt64SelfBalancedTreeKeys=array of int64; - - TBESENInt64SelfBalancedTree=class - protected - procedure Skew(OldParent:PBESENInt64SelfBalancedTreeNode); - function Split(OldParent:PBESENInt64SelfBalancedTreeNode):boolean; - procedure RebalanceAfterLeafAdd(n:PBESENInt64SelfBalancedTreeNode); - procedure DeleteNode(n:PBESENInt64SelfBalancedTreeNode); - function First(StartNode:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; - function Next(n:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; - function FindNode(const Key:int64):PBESENInt64SelfBalancedTreeNode; - procedure ClearNode(var Node:PBESENInt64SelfBalancedTreeNode); - procedure OptimizeNode(var Node:PBESENInt64SelfBalancedTreeNode;MoreOptimize:boolean); - function GetValue(Key:int64):TBESENInt64SelfBalancedTreeValue; - procedure SetValue(Key:int64;Value:TBESENInt64SelfBalancedTreeValue); - public - RootNode:PBESENInt64SelfBalancedTreeNode; - FirstKey,LastKey:PBESENInt64SelfBalancedTreeNode; - constructor Create; - destructor Destroy; override; - function Find(const Key:int64;var Value:TBESENInt64SelfBalancedTreeValue):boolean; - function Insert(const Key:int64;Value:TBESENInt64SelfBalancedTreeValue):PBESENInt64SelfBalancedTreeNode; - procedure Remove(const Key:int64); - procedure Optimize; - function Keys:TBESENInt64SelfBalancedTreeKeys; - property Values[Key:int64]:TBESENInt64SelfBalancedTreeValue read GetValue write SetValue; default; - end; - -implementation - -constructor TBESENInt64SelfBalancedTree.Create; -begin - inherited Create; - New(RootNode); - FillChar(RootNode^,SizeOf(TBESENInt64SelfBalancedTreeNode),#0); - RootNode^.Level:=$7fffffffffffffff; - FirstKey:=nil; - LastKey:=nil; -end; - -destructor TBESENInt64SelfBalancedTree.Destroy; -begin - ClearNode(RootNode^.Left); - Dispose(RootNode); - inherited Destroy; -end; - -function TBESENInt64SelfBalancedTree.First(StartNode:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; -begin - try - if not assigned(StartNode^.Left) then begin - result:=nil; - exit; - end; - result:=StartNode; - while assigned(result^.Left) do begin - result:=result^.Left; - end; - except - result:=nil; - end; -end; - -function TBESENInt64SelfBalancedTree.Next(n:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; -begin - try - if assigned(n^.Right) then begin - result:=n^.Right; - while assigned(result^.Left) do begin - result:=result^.Left; - end; - end else begin - while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin - n:=n^.Parent; - end; - n:=n^.Parent; - if not assigned(n) then begin - result:=nil; - exit; - end; - result:=n; - end; - except - result:=nil; - end; -end; - -procedure TBESENInt64SelfBalancedTree.Skew(OldParent:PBESENInt64SelfBalancedTreeNode); -var NewParent:PBESENInt64SelfBalancedTreeNode; -begin -{$ifdef UseAssert} - Assert(assigned(OldParent)); -{$endif} - NewParent:=OldParent^.Left; -{$ifdef UseAssert} - Assert(assigned(NewParent)); -{$endif} - if OldParent^.Parent^.Left=OldParent then begin - OldParent^.Parent^.Left:=NewParent; - end else begin - OldParent^.Parent^.Right:=NewParent; - end; - NewParent^.Parent:=OldParent^.Parent; - OldParent^.Parent:=NewParent; - - OldParent^.Left:=NewParent^.Right; - if assigned(OldParent^.Left) then begin - OldParent^.Left^.Parent:=OldParent; - end; - NewParent^.Right:=OldParent; - - if assigned(OldParent^.Left) then begin - OldParent^.level:=OldParent^.Left^.level+1; - end else begin - OldParent^.level:=1; - end; -end; - -function TBESENInt64SelfBalancedTree.Split(OldParent:PBESENInt64SelfBalancedTreeNode):boolean; -var NewParent:PBESENInt64SelfBalancedTreeNode; -begin -{$ifdef UseAssert} - Assert(assigned(OldParent)); -{$endif} - NewParent:=OldParent^.Right; - if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin - if OldParent^.Parent^.Left=OldParent then begin - OldParent^.Parent^.Left:=NewParent; - end else begin - OldParent^.Parent^.Right:=NewParent; - end; - NewParent^.Parent:=OldParent^.Parent; - OldParent^.Parent:=NewParent; - - OldParent^.Right:=NewParent^.Left; - if assigned(OldParent^.Right) then begin - OldParent^.Right^.Parent:=OldParent; - end; - NewParent^.Left:=OldParent; - - NewParent^.level:=OldParent^.level+1; - - result:=true; - end else begin - result:=false; - end; -end; - -procedure TBESENInt64SelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENInt64SelfBalancedTreeNode); -begin - // n is a node that has just been inserted and is now a Leaf node. - n^.Level:=1; - n^.Left:=nil; - n^.Right:=nil; - n:=n^.Parent; - while n<>RootNode do begin - if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin - // this point the tree is correct, except (AA2) for n->Parent - Skew(n); - // We handle it (a Left add) by changing it into a Right add using Skew - // If the original add was to the Left side of a node that is on the - // Right side of a horizontal link, n now points to the rights side - // of the second horizontal link, which is correct. - // However if the original add was to the Left of node with a horizontal - // link, we must get to the Right side of the second link. - if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin - n:=n^.Parent; - end; - end; - if not Split(n^.Parent) then begin - break; - end; - n:=n^.Parent; - end; -end; - -function TBESENInt64SelfBalancedTree.FindNode(const Key:int64):PBESENInt64SelfBalancedTreeNode; -var n:PBESENInt64SelfBalancedTreeNode; -begin - try - result:=nil; - n:=RootNode^.Left; - while assigned(n) do begin - if Key=n^.Key then begin - result:=n; - break; - end else if Key<n^.Key then begin - n:=n^.Left; - end else begin - n:=n^.Right; - end; - end; - except - result:=nil; - end; -end; - -function TBESENInt64SelfBalancedTree.Insert(const Key:int64;Value:TBESENInt64SelfBalancedTreeValue):PBESENInt64SelfBalancedTreeNode; -var n,s:PBESENInt64SelfBalancedTreeNode; - LessThan:boolean; -begin - result:=nil; - try - n:=nil; - s:=RootNode^.Left; - while assigned(s) do begin - if Key=s^.Key then begin - n:=s; - break; - end else if Key<s^.Key then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - end; - if assigned(s) then begin - n^.Value:=Value; - end else begin - new(n); - fillchar(n^,sizeof(TBESENInt64SelfBalancedTreeNode),#0); - n^.Key:=Key; - n^.Value:=Value; - if assigned(LastKey) then begin - n^.PreviousKey:=LastKey; - LastKey^.NextKey:=n; - LastKey:=n; - end else begin - FirstKey:=n; - LastKey:=n; - end; - s:=RootNode; - LessThan:=true; - while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin - if LessThan then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - LessThan:=Key<s^.Key; - end; - if LessThan then begin - s^.Left:=n; - end else begin - s^.Right:=n; - end; - n^.Parent:=s; - RebalanceAfterLeafAdd(n); - result:=n; - end; - except - result:=nil; - end; -end; - -procedure TBESENInt64SelfBalancedTree.DeleteNode(n:PBESENInt64SelfBalancedTreeNode); -var Leaf,Temp:PBESENInt64SelfBalancedTreeNode; -begin - try - // If n is not a Leaf, we first swap it out with the Leaf node that just - // precedes it. - Leaf:=n; - if assigned(n^.Left) then begin - Leaf:=n^.Left; - while assigned(Leaf^.Right) do begin - Leaf:=Leaf^.Right; - end; - end else if assigned(n^.Right) then begin - Leaf:=n^.Right; - end; - - if Leaf^.Parent=n then begin - Temp:=Leaf; - end else begin - Temp:=Leaf^.Parent; - end; - if Leaf^.Parent^.Left=Leaf then begin - Leaf^.Parent^.Left:=nil; - end else begin - Leaf^.Parent^.Right:=nil; - end; - - if n<>Leaf then begin - if n^.Parent^.Left=n then begin - n^.Parent^.Left:=Leaf; - end else begin - n^.Parent^.Right:=Leaf; - end; - Leaf^.Parent:=n^.Parent; - if assigned(n^.Left) then begin - n^.Left^.Parent:=Leaf; - end; - Leaf^.Left:=n^.Left; - if assigned(n^.Right) then begin - n^.Right^.Parent:=Leaf; - end; - Leaf^.Right:=n^.Right; - Leaf^.level:=n^.level; - end; - if n<>RootNode then begin - n^.Key:=0; - if assigned(n^.PreviousKey) then begin - n^.PreviousKey^.NextKey:=n^.NextKey; - end else if FirstKey=n then begin - FirstKey:=n^.NextKey; - end; - if assigned(n^.NextKey) then begin - n^.NextKey^.PreviousKey:=n^.PreviousKey; - end else if LastKey=n then begin - LastKey:=n^.PreviousKey; - end; - dispose(n); - end; - - while Temp<>RootNode do begin - if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin - dec(Temp^.level); - if Split(Temp) then begin - if Split(Temp) then begin - Skew(Temp^.Parent^.Parent); - end; - break; - end; - Temp:=Temp^.Parent; - end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin - break; - end else begin - Skew(Temp); - { if assigned(Temp^.Right) then begin - if assigned(Temp^.Right^.Left) then begin - Temp^.Right^.level:=Temp^.Right^.level+1; - end else begin - Temp^.Right^.level:=1; - end; - end;} - if Temp^.level>Temp^.Parent^.level then begin - Skew(Temp); - Split(Temp^.Parent^.Parent); - break; - end; - Temp:=Temp^.Parent^.Parent; - end; - end; - except - end; -end; - -procedure TBESENInt64SelfBalancedTree.Remove(const Key:int64); -var n:PBESENInt64SelfBalancedTreeNode; -begin - try - n:=RootNode^.Left; - while assigned(n) do begin - if Key=n^.Key then begin - DeleteNode(n); - break; - end else if Key<n^.Key then begin - n:=n^.Left; - end else begin - n:=n^.Right; - end; - end; - except - end; -end; - -procedure TBESENInt64SelfBalancedTree.ClearNode(var Node:PBESENInt64SelfBalancedTreeNode); -begin - if not assigned(Node) then begin - exit; - end; - Node^.Key:=0; - if assigned(Node^.PreviousKey) then begin - Node^.PreviousKey^.NextKey:=Node^.NextKey; - end else if FirstKey=Node then begin - FirstKey:=Node^.NextKey; - end; - if assigned(Node^.NextKey) then begin - Node^.NextKey^.PreviousKey:=Node^.PreviousKey; - end else if LastKey=Node then begin - LastKey:=Node^.PreviousKey; - end; - ClearNode(Node^.Left); - ClearNode(Node^.Right); - dispose(Node); - Node:=nil; -end; - -procedure TBESENInt64SelfBalancedTree.OptimizeNode(var Node:PBESENInt64SelfBalancedTreeNode;MoreOptimize:boolean); -var Nodes:array of TBESENInt64SelfBalancedTreeNode; - NodeCount,NodeIndex:integer; - procedure CountNodes(Node:PBESENInt64SelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - CountNodes(Node^.Left); - CountNodes(Node^.Right); - inc(NodeCount); - end; - procedure CollectNodes(Node:PBESENInt64SelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - CollectNodes(Node^.Left); - if NodeIndex>=length(Nodes) then begin - NodeCount:=NodeIndex+1; - SetLength(Nodes,NodeCount); - end; - Nodes[NodeIndex]:=Node^; - inc(NodeIndex); - CollectNodes(Node^.Right); - end; - procedure FreeNodes(var Node:PBESENInt64SelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - Node^.Key:=0; - if assigned(Node^.PreviousKey) then begin - Node^.PreviousKey^.NextKey:=Node^.NextKey; - end; - if assigned(Node^.NextKey) then begin - Node^.NextKey^.PreviousKey:=Node^.PreviousKey; - end; - if FirstKey=Node then begin - FirstKey:=Node^.NextKey; - end; - if LastKey=Node then begin - LastKey:=Node^.PreviousKey; - end; - CountNodes(Node^.Left); - CountNodes(Node^.Right); - dispose(Node); - Node:=nil; - end; - procedure DoInsertNode(const Node:TBESENInt64SelfBalancedTreeNode); - var n,s:PBESENInt64SelfBalancedTreeNode; - LessThan:boolean; - begin - new(n); - n^:=Node; - n^.Parent:=nil; - n^.Left:=nil; - n^.Right:=nil; - n^.Level:=0; - s:=RootNode; - LessThan:=true; - while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin - if LessThan then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - LessThan:=n^.Key<s^.Key; - end; - if LessThan then begin - s^.Left:=n; - end else begin - s^.Right:=n; - end; - n^.Parent:=s; - if assigned(LastKey) then begin - n^.PreviousKey:=LastKey; - LastKey^.NextKey:=n; - LastKey:=n; - end else begin - FirstKey:=n; - LastKey:=n; - end; - if not MoreOptimize then begin - RebalanceAfterLeafAdd(n); - end; - end; - procedure RepairNodes(var Node:PBESENInt64SelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - RepairNodes(Node^.Left); - RepairNodes(Node^.Right); - if assigned(Node^.Left) and assigned(Node^.Right) then begin - Node^.Level:=Node^.Left^.Level+1; - end else begin - Node^.Level:=1; - end; - end; - procedure ReinsertNodesForRepair(LowNode,HighNode:integer); - var MiddleNode:integer; - begin - if HighNode<LowNode then begin - exit; - end; - MiddleNode:=LowNode+((HighNode-LowNode) div 2); - DoInsertNode(Nodes[MiddleNode]); - ReinsertNodesForRepair(LowNode,MiddleNode-1); - ReinsertNodesForRepair(MiddleNode+1,HighNode); - end; - procedure ReinsertNodes(LowNode,HighNode:integer); - var i:integer; - begin - for i:=LowNode to HighNode do begin - DoInsertNode(Nodes[i]); - end; - end; -begin - if not assigned(Node) then begin - exit; - end; - try - Nodes:=nil; - NodeCount:=0; - CountNodes(Node); - SetLength(Nodes,NodeCount); - NodeIndex:=0; - CollectNodes(Node); - FreeNodes(Node); - if MoreOptimize then begin - ReinsertNodesForRepair(0,length(Nodes)-1); - RepairNodes(RootNode^.Left); - end else begin - ReinsertNodes(0,length(Nodes)-1); - end; - SetLength(Nodes,0); - except - end; -end; - -function TBESENInt64SelfBalancedTree.Find(const Key:int64;var Value:TBESENInt64SelfBalancedTreeValue):boolean; -var n:PBESENInt64SelfBalancedTreeNode; -begin - n:=FindNode(Key); - if assigned(n) then begin - Value:=n^.Value; - result:=true; - end else begin - fillchar(Value,sizeof(TBESENInt64SelfBalancedTreeValue),#0); - result:=false; - end; -end; - -procedure TBESENInt64SelfBalancedTree.Optimize; -begin - OptimizeNode(RootNode^.Left,true); -end; - -function TBESENInt64SelfBalancedTree.Keys:TBESENInt64SelfBalancedTreeKeys; -var CurrentNode:PBESENInt64SelfBalancedTreeNode; - Count:integer; -begin - - result:=nil; - Count:=0; - CurrentNode:=FirstKey; - while assigned(CurrentNode) do begin - inc(Count); - CurrentNode:=CurrentNode^.NextKey; - end; - SetLength(result,Count); - Count:=0; - CurrentNode:=FirstKey; - while assigned(CurrentNode) do begin - result[Count]:=CurrentNode^.Key; - inc(Count); - CurrentNode:=CurrentNode^.NextKey; - end; -end; - -function TBESENInt64SelfBalancedTree.GetValue(Key:int64):TBESENInt64SelfBalancedTreeValue; -begin - Find(Key,result); -end; - -procedure TBESENInt64SelfBalancedTree.SetValue(Key:int64;Value:TBESENInt64SelfBalancedTreeValue); -begin - Insert(Key,Value); -end; - - -end. diff --git a/3rd/besen/src/BESENIntegerList.pas b/3rd/besen/src/BESENIntegerList.pas deleted file mode 100644 index 182ae56f6..000000000 --- a/3rd/besen/src/BESENIntegerList.pas +++ /dev/null @@ -1,230 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENIntegerList; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -type PBESENIntegerArray=^TBESENIntegerArray; - TBESENIntegerArray=array[0..(2147483647 div sizeof(integer))-1] of integer; - - TBESENIntegerList=class - private - FList:PBESENIntegerArray; - FCount,FSize:integer; - function GetItem(index:integer):integer; - procedure SetItem(index:integer;Value:integer); - function GetItemPointer(index:integer):pointer; - public - constructor Create; - destructor Destroy; override; - procedure Clear; - function Add(Item:integer):integer; - procedure Insert(index:integer;Item:integer); - procedure Delete(index:integer); - function Remove(Item:integer):integer; - function Find(Item:integer):integer; - function IndexOf(Item:integer):integer; - procedure Exchange(Index1,Index2:integer); - procedure SetCapacity(NewCapacity:integer); - procedure SetCount(NewCount:integer); - property Count:integer read FCount; - property Capacity:integer read FSize write SetCapacity; - property Item[index:integer]:integer read GetItem write SetItem; default; - property Items[index:integer]:integer read GetItem write SetItem; - property PItems[index:integer]:pointer read GetItemPointer; - end; - -implementation - -constructor TBESENIntegerList.Create; -begin - inherited Create; - FCount:=0; - FSize:=0; - FList:=nil; - Clear; -end; - -destructor TBESENIntegerList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENIntegerList.Clear; -begin - FCount:=0; - FSize:=0; - ReallocMem(FList,0); -end; - -procedure TBESENIntegerList.SetCapacity(NewCapacity:integer); -begin - if (NewCapacity>=0) and (NewCapacity<high(TBESENIntegerArray)) then begin - NewCapacity:=(NewCapacity+256) and not 255; - if FSize<>NewCapacity then begin - ReallocMem(FList,NewCapacity*sizeof(integer)); - if FSize<NewCapacity then begin - FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(integer),#0); - end; - FSize:=NewCapacity; - end; - end; -end; - -procedure TBESENIntegerList.SetCount(NewCount:integer); -begin - if (NewCount>=0) and (NewCount<high(TBESENIntegerArray)) then begin - if NewCount<FCount then begin - FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(integer),#0); - end; - SetCapacity(NewCount); - FCount:=NewCount; - end; -end; - -function TBESENIntegerList.Add(Item:integer):integer; -begin - result:=FCount; - SetCount(result+1); - FList^[result]:=Item; -end; - -procedure TBESENIntegerList.Insert(index:integer;Item:integer); -var I:integer; -begin - if (index>=0) and (index<FCount) then begin - SetCount(FCount+1); - for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; - FList^[index]:=Item; - end else if index=FCount then begin - Add(Item); - end else if index>FCount then begin - SetCount(index); - Add(Item); - end; -end; - -procedure TBESENIntegerList.Delete(index:integer); -var I,J,K:integer; -begin - if (index>=0) and (index<FCount) then begin - K:=FCount-1; - J:=index; - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - end; -end; - -function TBESENIntegerList.Remove(Item:integer):integer; -var I,J,K:integer; -begin - result:=-1; - K:=FCount; - J:=-1; - for I:=0 to K-1 do begin - if FList^[I]=Item then begin - J:=I; - break; - end; - end; - if J>=0 then begin - dec(K); - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - result:=J; - end; -end; - -function TBESENIntegerList.Find(Item:integer):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -function TBESENIntegerList.IndexOf(Item:integer):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -procedure TBESENIntegerList.Exchange(Index1,Index2:integer); -var TempInteger:integer; -begin - if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin - TempInteger:=FList^[Index1]; - FList^[Index1]:=FList^[Index2]; - FList^[Index2]:=TempInteger; - end; -end; - -function TBESENIntegerList.GetItem(index:integer):integer; -begin - if (index>=0) and (index<FCount) then begin - result:=FList^[index]; - end else begin - result:=0; - end; -end; - -procedure TBESENIntegerList.SetItem(index:integer;Value:integer); -begin - if (index>=0) and (index<FCount) then begin - FList^[index]:=Value; - end; -end; - -function TBESENIntegerList.GetItemPointer(index:integer):pointer; -begin - if (index>=0) and (index<FCount) then begin - result:=@FList^[index]; - end else begin - result:=nil; - end; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENKeyIDManager.pas b/3rd/besen/src/BESENKeyIDManager.pas deleted file mode 100644 index 59eba91bd..000000000 --- a/3rd/besen/src/BESENKeyIDManager.pas +++ /dev/null @@ -1,120 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENKeyIDManager; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENGarbageCollector,BESENHashMap,BESENStringList, - BESENBaseObject; - -type TBESENKeyIDManager=class(TBESENBaseObject) - public - HashMap:TBESENHashMap; - List:TBESENStringList; - Count:int64; - CallerID:TBESENINT32; - LengthID:TBESENINT32; - ProtoID:TBESENINT32; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; - function GetString(const Key:TBESENString;Hash:TBESENHash=0):TBESENString; - function Find(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; - end; - -implementation - -uses BESEN; - -constructor TBESENKeyIDManager.Create(AInstance:TObject); -begin - inherited Create(AInstance); - HashMap:=TBESENHashMap.Create; - List:=TBESENStringList.Create; - Count:=0; - CallerID:=Get('caller'); - LengthID:=Get('length'); - ProtoID:=Get('__proto__'); -end; - -destructor TBESENKeyIDManager.Destroy; -begin - HashMap.Free; - List.Free; - inherited Destroy; -end; - -function TBESENKeyIDManager.Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; -var Item:PBESENHashMapItem; -begin - Item:=HashMap.GetKey(Key,Hash); - if TBESEN(Instance).InlineCacheEnabled and not assigned(Item) then begin - inc(Count); - if Count<bimMAXIDENTS then begin - Item:=HashMap.NewKey(Key,true,Hash); - Item^.Value:=List.Add(Key); - end else begin - TBESEN(Instance).InlineCacheEnabled:=false; - List.Clear; - HashMap.Clear; - end; - end; - if assigned(Item) then begin - result:=Item^.Value; - end else begin - result:=-1; - end; -end; - -function TBESENKeyIDManager.GetString(const Key:TBESENString;Hash:TBESENHash=0):TBESENString; -var Item:PBESENHashMapItem; -begin - Item:=HashMap.GetKey(Key,Hash); - if TBESEN(Instance).InlineCacheEnabled and assigned(Item) then begin - result:=List[Item^.Value]; - end else begin - result:=Key; - end; -end; - -function TBESENKeyIDManager.Find(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; -var Item:PBESENHashMapItem; -begin - Item:=HashMap.GetKey(Key,Hash); - if TBESEN(Instance).InlineCacheEnabled and assigned(Item) then begin - result:=Item^.Value; - end else begin - result:=-1; - end; -end; - -end. diff --git a/3rd/besen/src/BESENLexer.pas b/3rd/besen/src/BESENLexer.pas deleted file mode 100644 index 17a26c576..000000000 --- a/3rd/besen/src/BESENLexer.pas +++ /dev/null @@ -1,1416 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENLexer; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils,BESENBaseObject; - -type TBESENLexerTokenType=(ltNONE,ltUNKNOWN,ltEOF, - - // Types - lttIDENTIFIER,lttSTRING,lttINTEGER,lttFLOAT, - - // Operators - ltoASSIGNMENT,ltoBITWISEAND,ltoBITWISEANDASSIGNMENT, - ltoBITWISENOT,ltoBITWISEOR,ltoBITWISEORASSIGNMENT, - ltoBITWISEXOR,ltoBITWISEXORASSIGNMENT,ltoCLOSEBRACE, - ltoCLOSEPAREN,ltoCLOSESQUARE,ltoCOLON,ltoCOMMA, - ltoCONDITIONAL,ltoDIVIDE,ltoDIVIDEASSIGNMENT,ltoDOT, - ltoEQUALEQUAL,ltoEQUALEQUALEQUAL,ltoGREATERTHAN, - ltoGREATERTHANOREQUAL,ltoLESSTHAN,ltoLESSTHANOREQUAL, - ltoLOGICALAND,ltoLOGICALNOT,ltoLOGICALOR,ltoMINUS, - ltoMINUSASSIGNMENT,ltoMINUSMINUS,ltoMODULO, - ltoMODULOASSIGNMENT,ltoMULTIPLY, - ltoMULTIPLYASSIGNMENT,ltoNOTEQUAL,ltoNOTEQUALEQUAL, - ltoOPENBRACE,ltoOPENPAREN,ltoOPENSQUARE,ltoPLUS, - ltoPLUSASSIGNMENT,ltoPLUSPLUS,ltoSEMICOLON, - ltoSHIFTLEFT,ltoSHIFTLEFTASSIGNMENT,ltoSHIFTRIGHT, - ltoSHIFTRIGHTASSIGNMENT,ltoSHIFTRIGHTUNSIGNED, - ltoSHIFTRIGHTUNSIGNEDASSIGNMENT, - - // Used keywords - ltkBREAK,ltkCASE,ltkCATCH,ltkCONTINUE,ltkDEBUGGER, - ltkDEFAULT,ltkDELETE,ltkDO,ltkELSE,ltkFALSE, - ltkFINALLY,ltkFOR,ltkFUNCTION,ltkIF,ltkIN, - ltkINSTANCEOF,ltkNEW,ltkNULL,ltkRETURN,ltkSWITCH, - ltkTHIS,ltkTHROW,ltkTRUE,ltkTRY,ltkTYPEOF,ltkVAR, - ltkVOID,ltkWHILE,ltkWITH, - - // Reserved keywords - ltkCLASS,ltkCONST,ltkENUM,ltkEXPORT,ltkEXTENDS, - ltkIMPORT,ltkSUPER, - - // Additional reserved keywords in strict mode - ltkIMPLEMENTS,ltkINTERFACE,ltkLET,ltkPACKAGE, - ltkPRIVATE,ltkPROTECTED,ltkPUBLIC,ltkSTATIC, - ltkYIELD - ); - - TBESENLexerTokenTypeSet=set of TBESENLexerTokenType; - - TBESENLexerToken=record - TokenType:TBESENLexerTokenType; - Name:TBESENString; - StringValue:TBESENString; - IntValue:int64; - FloatValue:double; - LineNumber:integer; - LineEnd:longbool; - WasLineEnd:longbool; - OldChar:TBESENUTF32CHAR; - OldLineNumber:integer; - OldPosition:integer; - OldCharEOF:longbool; - OldTokenEOF:longbool; - end; - - TBESENLexer=class(TBESENBaseObject) - public - Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; - Position:integer; - LineNumber:integer; - CurrentChar:TBESENUTF32CHAR; - WarningProc:TBESENWarningProc; - CharEOF:longbool; - TokenEOF:longbool; - LastWasLineEnd:longbool; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure NextChar; - procedure Restore(var Token:TBESENLexerToken); - function ParseRegExpLiteral(var Token:TBESENLexerToken;var ASource,AFlags:TBESENString):boolean; - function IsEOF:boolean; - procedure GetToken(var AResult:TBESENLexerToken); - end; - -const BESENLexerReservedTokens:TBESENLexerTokenTypeSet=[ltkCLASS,ltkCONST,ltkENUM,ltkEXPORT,ltkEXTENDS,ltkIMPORT,ltkSUPER]; - - BESENLexerStrictReservedTokens:TBESENLexerTokenTypeSet=[ltkIMPLEMENTS,ltkINTERFACE,ltkLET,ltkPACKAGE,ltkPRIVATE, - ltkPROTECTED,ltkPUBLIC,ltkSTATIC,ltkYIELD]; - - BESENLexerKeywordsTokens:TBESENLexerTokenTypeSet=[ltkBREAK..ltkYIELD]; - - BESENTokenStrings:array[TBESENLexerTokenType] of TBESENString=('','','EOF', - - // Types - 'IDENTIFIER','STRING','INTEGER','FLOAT', - - // Operators - '==','&','&=', - '~','|','|=', - '^','^=','}', - ')',']',':',',', - '?','/','/=','.', - '==','===','>', - '>=','<','<=', - '&&','!','||','-', - '-=','--','%', - '%=','*', - '*=','!=','!==', - '{','(','[','+', - '+=','++',';', - '<<','<<=','>>', - '>>=','>>>','>>>=', - - // Used keywords - 'break','case','catch','continue','debugger', - 'default','delete','do','else','false', - 'finally','for','function','if','in', - 'instanceof','new','null','return','switch', - 'this','throw','true','try','typeof','var', - 'void','while','with', - - // Reserved keywords - 'class','const','enum','export','extends', - 'import','super', - - // Additional reserved keywords in strict mode - 'implements','interface','let','package', - 'private','protected','public','static', - 'yield'); - -implementation - -uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESEN,BESENRegExp,BESENErrors,BESENNumberUtils; - -type TKeywordToken=ltkBREAK..ltkYIELD; - - TKeyword=TKeywordToken; - - TKeywords=array of TKeyword; - -const KeywordNames:array[TKeywordToken] of TBESENUTF16STRING= - (// Used keywords - 'break','case','catch','continue','debugger', - 'default','delete','do','else','false', - 'finally','for','function','if','in', - 'instanceof','new','null','return','switch', - 'this','throw','true','try','typeof','var', - 'void','while','with', - - // Reserved keywords - 'class','const','enum','export','extends', - 'import','super', - - // Additional reserved keywords in strict mode - 'implements','interface','let','package', - 'private','protected','public','static', - 'yield'); - - Keywords:TKeywords=nil; - -constructor TBESENLexer.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Source:=''; - Position:=1; - LineNumber:=1; - WarningProc:=nil; - CharEOF:=false; - TokenEOF:=false; - LastWasLineEnd:=false; -end; - -destructor TBESENLexer.Destroy; -begin - Source:=''; - inherited Destroy; -end; - -function TBESENLexer.IsEOF:boolean; -begin - result:=TokenEOF; -end; - -procedure TBESENLexer.NextChar; -{$ifdef BESENSingleStringType} -var Len:integer; -{$else} -var b:byte; -{$endif} -begin - if (Position>=1) and (Position<=length(Source)) then begin -{$ifdef BESENSingleStringType} -{$ifdef BESENEmbarcaderoNextGen} - CurrentChar:=Char.ConvertToUTF32(s,Position-1,Len); - inc(Position,Len); -{$else} - CurrentChar:=ord(Source[Position]); - inc(Position); - if (Position<=length(Source)) and ((SizeOf(Source[Position])=SizeOf(word)) and (((CurrentChar and $fc00)=$d800) and ((ord(Source[Position]) and $fc00)=$dc00))) then begin - // UTF16 - CurrentChar:=(((CurrentChar and $3ff) shl 10) or (ord(Source[Position]) and $3ff))+$10000; - inc(Position); - end; -{$endif} -{$else} - b:=byte(Source[Position]); - if (b and $80)=0 then begin - CurrentChar:=b; - inc(Position); - end else if ((Position+1)<=length(Source)) and ((b and $e0)=$c0) and ((byte(Source[Position+1]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $1f) shl 6) or (byte(Source[Position+1]) and $3f); - inc(Position,2); - end else if ((Position+2)<=length(Source)) and ((b and $f0)=$e0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $0f) shl 12) or ((byte(Source[Position+1]) and $3f) shl 6) or (byte(Source[Position+2]) and $3f); - inc(Position,3); - end else if ((Position+3)<=length(Source)) and ((b and $f8)=$f0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $07) shl 18) or ((byte(Source[Position+1]) and $3f) shl 12) or ((byte(Source[Position+2]) and $3f) shl 6) or (byte(Source[Position+3]) and $3f); - inc(Position,4); - end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+4)<=length(Source)) and ((b and $fc)=$f8) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $03) shl 24) or ((byte(Source[Position+1]) and $3f) shl 18) or ((byte(Source[Position+2]) and $3f) shl 12) or ((byte(Source[Position+3]) and $3f) shl 6) or (byte(Source[Position+4]) and $3f); - inc(Position,5); - end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+5)<=length(Source)) and ((b and $fe)=$fc) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) and ((byte(Source[Position+5]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $01) shl 30) or ((byte(Source[Position+1]) and $3f) shl 24) or ((byte(Source[Position+2]) and $3f) shl 18) or ((byte(Source[Position+3]) and $3f) shl 12) or ((byte(Source[Position+4]) and $3f) shl 6) or (byte(Source[Position+5]) and $3f); - inc(Position,6); - end else begin - CurrentChar:=$fffd; - inc(Position); - end; -{$endif} - end else begin - CurrentChar:=0; - CharEOF:=true; - end; -end; - -procedure TBESENLexer.Restore(var Token:TBESENLexerToken); -begin - Position:=Token.OldPosition; - LineNumber:=Token.OldLineNumber; - CurrentChar:=Token.OldChar; - CharEOF:=Token.OldCharEOF; - TokenEOF:=Token.OldTokenEOF; -end; - -function TBESENLexer.ParseRegExpLiteral(var Token:TBESENLexerToken;var ASource,AFlags:TBESENString):boolean; -var InCharClass,fg,fi,fm:boolean; - RegExpFlags:TBESENRegExpFlags; -begin - result:=false; - ASource:=''; - AFlags:=''; - InCharClass:=false; - while not CharEOF do begin - NextChar; - case CurrentChar of - $00,$0a,$0d,$2028,$2029:begin - exit; - end; - ord('\'):begin - ASource:=ASource+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - ord('['):begin - InCharClass:=true; - end; - ord(']'):begin - InCharClass:=false; - end; - ord('/'):begin - if not InCharClass then begin - break; - end; - end; - end; - ASource:=ASource+BESENUTF32CHARToUTF16(CurrentChar); - end; - if (not CharEOF) and (CurrentChar=ord('/')) then begin - NextChar; - end else begin - raise EBESENSyntaxError.Create('unterminated regex'); - end; - AFlags:=''; - fg:=false; - fi:=false; - fm:=false; - while not CharEOF do begin - case CurrentChar of - ord('g'):begin - if fg then begin - raise EBESENSyntaxError.Create('Too many global regular expression flags'); - end else begin - fg:=true; - AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - ord('i'):begin - if fi then begin - raise EBESENSyntaxError.Create('Too many ignorecase regular expression flags'); - end else begin - fi:=true; - AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - ord('m'):begin - if fm then begin - raise EBESENSyntaxError.Create('Too many multiline regular expression flags'); - end else begin - fm:=true; - AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - else begin - break; - end; - end; - end; - if BESENUnicodeIsLetter(CurrentChar) then begin - raise EBESENSyntaxError.Create('Unknown regular expression flag'); - end; - RegExpFlags:=[]; - if fg then begin - RegExpFlags:=RegExpFlags+[brefGLOBAL]; - end; - if fi then begin - RegExpFlags:=RegExpFlags+[brefIGNORECASE]; - end; - if fm then begin - RegExpFlags:=RegExpFlags+[brefMULTILINE]; - end; - try - TBESEN(Instance).RegExpCache.Get(ASource,RegExpFlags); - except - raise EBESENSyntaxError.Create('Invalid regular expression'); - end; - Token.StringValue:='/'+ASource+'/'+AFlags; - result:=true; -end; - -procedure TBESENLexer.GetToken(var AResult:TBESENLexerToken); -var c:TBESENUTF32CHAR; - v:longword; - procedure AddError(const Msg:TBESENSTRING); - begin - TBESEN(Instance).LineNumber:=LineNumber; - raise EBESENSyntaxError.CreateUTF16(Msg); - end; - procedure AddWarning(const Msg:TBESENSTRING); - begin - if assigned(WarningProc) then begin - WarningProc(LineNumber,Msg); - end; - end; - procedure ParseNumber(c:widechar;var Token:TBESENLexerToken); - var s:TBESENString; - HasDigits:boolean; - begin - Token.TokenType:=ltUNKNOWN; - - HasDigits:=false; - - s:=''; - - if c='.' then begin - if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin - s:=s+'.'; - - while (not CharEOF) and (CurrentChar=ord('0')) do begin - s:=s+widechar(CurrentChar); - NextChar; - end; - - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - s:=s+widechar(CurrentChar); - NextChar; - end; - - if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin - s:=s+widechar(CurrentChar); - NextChar; - if (not CharEOF) and ((CurrentChar=ord('+')) or (CurrentChar=ord('-'))) then begin - s:=s+widechar(CurrentChar); - NextChar; - end; - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - s:=s+widechar(CurrentChar); - NextChar; - end; - end; - - Token.TokenType:=lttFLOAT; - Token.FloatValue:=BESENStringToDouble('0'+s); - s:=''; - end; - exit; - end; - - if (not CharEOF) and (CurrentChar=ord('0')) then begin - NextChar; - case CurrentChar of - ord('x'),ord('X'):begin - NextChar; - s:='0x'; - while not CharEOF do begin - case CurrentChar of - ord('a')..ord('f'),ord('A')..ord('F'),ord('0')..ord('9'):begin - s:=s+widechar(word(CurrentChar)); - HasDigits:=true; - NextChar; - end; - else begin - break; - end; - end; - end; - if HasDigits then begin - Token.TokenType:=lttFLOAT; - Token.FloatValue:=BESENStringToDouble(s); - end; - s:=''; - exit; - end; - ord('0')..ord('7'):begin - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and not TBESEN(Instance).IsStrict then begin - s:='0'; - while not CharEOF do begin - case CurrentChar of - ord('0')..ord('7'):begin - s:=s+widechar(word(CurrentChar)); - HasDigits:=true; - NextChar; - end; - else begin - break; - end; - end; - end; - if HasDigits then begin - Token.TokenType:=lttFLOAT; - Token.FloatValue:=BESENStringToDouble(s); - end; - s:=''; - exit; - end else begin - AddError('Bad number literal'); - end; - end; - ord('8')..ord('9'):begin - AddError('Bad number literal'); - end; - else begin - HasDigits:=true; - s:=s+widechar('0'); - end; - end; - end; - - if TBESEN(Instance).IsStrict and HasDigits and ((not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9')))) then begin - AddError('Bad number literal'); - end else begin - - while (not CharEOF) and (CurrentChar=ord('0')) do begin - s:=s+widechar(CurrentChar); - HasDigits:=true; - NextChar; - end; - - if TBESEN(Instance).IsStrict and HasDigits and ((not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9')))) then begin - AddError('Bad number literal'); - end else begin - - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - s:=s+widechar(CurrentChar); - HasDigits:=true; - NextChar; - end; - - if (not CharEOF) and (CurrentChar=ord('.')) then begin - s:=s+widechar(CurrentChar); - NextChar; - - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - s:=s+widechar(CurrentChar); - NextChar; - HasDigits:=true; - end; - end; - - if HasDigits then begin - - if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin - HasDigits:=false; - s:=s+widechar(CurrentChar); - NextChar; - if (not CharEOF) and ((CurrentChar=ord('+')) or (CurrentChar=ord('-'))) then begin - s:=s+widechar(CurrentChar); - NextChar; - end; - if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin - HasDigits:=true; - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - s:=s+widechar(CurrentChar); - NextChar; - end; - end else begin - exit; - end; - end; - - if HasDigits then begin - Token.TokenType:=lttFLOAT; - Token.FloatValue:=BESENStringToDouble(s); - end; - end; - end; - end; - - s:=''; - end; - function FindKeyword(const Name:TBESENUTF16STRING):TBESENLexerTokenType; - var LowIndex,HighIndex,MiddleIndex:integer; - begin - result:=lttIDENTIFIER; - LowIndex:=0; - HighIndex:=length(Keywords)-1; - while LowIndex<=HighIndex do begin - case (HighIndex-LowIndex)+1 of - 1:begin - if KeywordNames[Keywords[LowIndex]]=Name then begin - result:=Keywords[LowIndex]; - end; - end; - 2:begin - if KeywordNames[Keywords[LowIndex]]=Name then begin - result:=Keywords[LowIndex]; - end else if KeywordNames[Keywords[HighIndex]]=Name then begin - result:=Keywords[HighIndex]; - end; - end; - else begin - MiddleIndex:=(LowIndex+HighIndex) div 2; - if KeywordNames[Keywords[MiddleIndex]]=Name then begin - result:=Keywords[MiddleIndex]; - end else if LowIndex<>HighIndex then begin - if KeywordNames[Keywords[MiddleIndex]]>Name then begin - HighIndex:=MiddleIndex-1; - end else begin - LowIndex:=MiddleIndex+1; - end; - continue; - end; - end; - end; - break; - end; - end; -begin - AResult.Name:=''; - AResult.StringValue:=''; - AResult.FloatValue:=0; - AResult.IntValue:=0; - AResult.LineNumber:=LineNumber; - AResult.LineEnd:=false; - AResult.WasLineEnd:=LastWasLineEnd; - AResult.OldChar:=CurrentChar; - AResult.OldLineNumber:=LineNumber; - AResult.OldPosition:=Position; - AResult.OldCharEOF:=CharEOF; - AResult.OldTokenEOF:=TokenEOF; - LastWasLineEnd:=false; - AResult.TokenType:=ltUNKNOWN; - while true do begin - if CharEOF then begin - TokenEOF:=true; - AResult.TokenType:=ltEOF; - break; - end else begin - while BESENUnicodeIsParserWhiteSpace(CurrentChar) do begin - case CurrentChar of - 0:begin - NextChar; - if not CharEOF then begin - CurrentChar:=1; - end; - end; - $000d:begin - NextChar; - if CurrentChar=$000a then begin - NextChar; - end; - inc(LineNumber); - AResult.WasLineEnd:=true; - end; - $000a,$2028,$2029:begin - NextChar; - inc(LineNumber); - AResult.WasLineEnd:=true; - end; - else begin - NextChar; - end; - end; - end; - if CharEOF then begin - AResult.TokenType:=ltEOF; - TokenEOF:=true; - break; - end else begin - AResult.LineNumber:=LineNumber; - AResult.OldChar:=CurrentChar; - AResult.OldLineNumber:=LineNumber; - AResult.OldPosition:=Position; - AResult.OldCharEOF:=CharEOF; - AResult.OldTokenEOF:=TokenEOF; - case CurrentChar of - 0:begin - end; - ord('='):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoEQUALEQUALEQUAL; - end; - else begin - AResult.TokenType:=ltoEQUALEQUAL; - end; - end; - end; - else begin - AResult.TokenType:=ltoASSIGNMENT; - end; - end; - end; - ord('&'):begin - NextChar; - case CurrentChar of - ord('&'):begin - NextChar; - AResult.TokenType:=ltoLOGICALAND; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoBITWISEANDASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoBITWISEAND; - end; - end; - end; - ord('|'):begin - NextChar; - case CurrentChar of - ord('|'):begin - NextChar; - AResult.TokenType:=ltoLOGICALOR; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoBITWISEORASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoBITWISEOR; - end; - end; - end; - ord('^'):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoBITWISEXORASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoBITWISEXOR; - end; - end; - end; - ord('/'):begin - NextChar; - case CurrentChar of - ord('/'):begin - while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin - NextChar; - end; - if BESENUnicodeIsLineTerminator(CurrentChar) then begin - inc(LineNumber); - AResult.WasLineEnd:=true; - if CurrentChar=$000d then begin - NextChar; - if CurrentChar=$000a then begin - NextChar; - end; - end else begin - NextChar; - end; - end; - continue; - end; - ord('*'):begin - NextChar; - c:=0; - while (not ((c=ord('*')) and (CurrentChar=ord('/')))) and not CharEOF do begin - if BESENUnicodeIsLineTerminator(CurrentChar) then begin - inc(LineNumber); - AResult.WasLineEnd:=true; - if CurrentChar=$000d then begin - c:=CurrentChar; - NextChar; - if CurrentChar=$000a then begin - c:=CurrentChar; - NextChar; - end; - end else begin - c:=CurrentChar; - NextChar; - end; - end else begin - c:=CurrentChar; - NextChar; - end; - end; - if CurrentChar=ord('/') then begin - NextChar; - end; - continue; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoDIVIDEASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoDIVIDE; - end; - end; - end; - ord('>'):begin - NextChar; - case CurrentChar of - ord('>'):begin - NextChar; - case CurrentChar of - ord('>'):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoSHIFTRIGHTUNSIGNEDASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoSHIFTRIGHTUNSIGNED; - end; - end; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoSHIFTRIGHTASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoSHIFTRIGHT; - end; - end; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoGREATERTHANOREQUAL; - end; - else begin - AResult.TokenType:=ltoGREATERTHAN; - end; - end; - end; - ord('<'):begin - NextChar; - case CurrentChar of - ord('<'):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoSHIFTLEFTASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoSHIFTLEFT; - end; - end; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoLESSTHANOREQUAL; - end; - ord('!'):begin - if (TBESEN(Instance).Compatibility and COMPAT_SGMLCOM)<>0 then begin - if ((Position+2)<=length(Source)) and (Source[Position]='-') and (Source[Position+1]='-') then begin - while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin - NextChar; - end; - if BESENUnicodeIsLineTerminator(CurrentChar) then begin - inc(LineNumber); - AResult.WasLineEnd:=true; - if CurrentChar=$000d then begin - NextChar; - if CurrentChar=$000a then begin - NextChar; - end; - end else begin - NextChar; - end; - continue; - end; - end else begin - AResult.TokenType:=ltoLESSTHAN; - end; - end else begin - AResult.TokenType:=ltoLESSTHAN; - end; - end; - else begin - AResult.TokenType:=ltoLESSTHAN; - end; - end; - end; - ord('-'):begin - NextChar; - case CurrentChar of - ord('-'):begin - NextChar; - if (TBESEN(Instance).Compatibility and COMPAT_SGMLCOM)<>0 then begin - if (Position=length(Source)) and (Source[Position]='>') then begin - while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin - NextChar; - end; - if BESENUnicodeIsLineTerminator(CurrentChar) then begin - inc(LineNumber); - AResult.WasLineEnd:=true; - if CurrentChar=$000d then begin - NextChar; - if CurrentChar=$000a then begin - NextChar; - end; - end else begin - NextChar; - end; - continue; - end; - end else begin - AResult.TokenType:=ltoMINUSMINUS; - end; - end else begin - AResult.TokenType:=ltoMINUSMINUS; - end; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoMINUSASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoMINUS; - end; - end; - end; - ord('+'):begin - NextChar; - case CurrentChar of - ord('+'):begin - NextChar; - AResult.TokenType:=ltoPLUSPLUS; - end; - ord('='):begin - NextChar; - AResult.TokenType:=ltoPLUSASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoPLUS; - end; - end; - end; - ord('%'):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoMODULOASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoMODULO; - end; - end; - end; - ord('*'):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoMULTIPLYASSIGNMENT; - end; - else begin - AResult.TokenType:=ltoMULTIPLY; - end; - end; - end; - ord('!'):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - case CurrentChar of - ord('='):begin - NextChar; - AResult.TokenType:=ltoNOTEQUALEQUAL; - end else begin - AResult.TokenType:=ltoNOTEQUAL; - end; - end; - end; - else begin - AResult.TokenType:=ltoLOGICALNOT; - end; - end; - end; - ord('~'):begin - NextChar; - AResult.TokenType:=ltoBITWISENOT; - end; - ord('}'):begin - NextChar; - AResult.TokenType:=ltoCLOSEBRACE; - end; - ord(')'):begin - NextChar; - AResult.TokenType:=ltoCLOSEPAREN; - end; - ord(']'):begin - NextChar; - AResult.TokenType:=ltoCLOSESQUARE; - end; - ord('{'):begin - NextChar; - AResult.TokenType:=ltoOPENBRACE; - end; - ord('('):begin - NextChar; - AResult.TokenType:=ltoOPENPAREN; - end; - ord('['):begin - NextChar; - AResult.TokenType:=ltoOPENSQUARE; - end; - ord(':'):begin - NextChar; - AResult.TokenType:=ltoCOLON; - end; - ord(';'):begin - NextChar; - AResult.TokenType:=ltoSEMICOLON; - end; - ord(','):begin - NextChar; - AResult.TokenType:=ltoCOMMA; - end; - ord('?'):begin - NextChar; - AResult.TokenType:=ltoCONDITIONAL; - end; - ord('.'):begin - NextChar; - case CurrentChar of - ord('0')..ord('9'):begin - ParseNumber('.',AResult); - end; - else begin - AResult.TokenType:=ltoDOT; - end; - end; - end; - ord('0')..ord('9'):begin - ParseNumber(#0,AResult); - end; - ord('"'),ord(''''):begin - AResult.TokenType:=lttSTRING; - c:=CurrentChar; - NextChar; - AResult.StringValue:=''; - while (CurrentChar<>c) and (Position<=length(Source)) do begin - case CurrentChar of - $000a,$000d,$2028,$2029:begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin - AddError('Unterminated string literal'); - break; - end else begin - NextChar; - end; - end; - $fffe,$feff:begin - AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); - NextChar; - end; - ord('\'):begin - NextChar; - case CurrentChar of - $000d:begin - AResult.StringValue:=AResult.StringValue+#$000d; - NextChar; - if CurrentChar=$000a then begin - AResult.StringValue:=AResult.StringValue+#$000a; - NextChar; - end; - inc(LineNumber); - AResult.WasLineEnd:=true; - end; - $000a,$2028,$2029:begin - AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); - inc(LineNumber); - AResult.WasLineEnd:=true; - break; - end; - ord('b'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$0008; - end; - ord('t'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$0009; - end; - ord('n'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$000a; - end; - ord('v'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$000b; - end; - ord('f'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$000c; - end; - ord('r'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$000d; - end; - ord('s'):begin - NextChar; - AResult.StringValue:=AResult.StringValue+#$fffe; - end; - ord('0')..ord('7'):begin - if TBESEN(Instance).IsStrict then begin - AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); - NextChar; - if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin - raise EBESENSyntaxError.Create('Octals aren''t allowed in strict mode'); - end; - end else begin - v:=CurrentChar-ord('0'); - NextChar; - if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin - v:=(v shl 3) or longword(CurrentChar-ord('0')); - NextChar; - if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin - v:=(v shl 3) or longword(CurrentChar-ord('0')); - NextChar; - end; - end; - AResult.StringValue:=AResult.StringValue+widechar(word(v)); - end; - end; - ord('x'):begin - if ((Position+1)<=length(Source)) and BESENIsHex(word(widechar(Source[Position]))) and BESENIsHex(word(widechar(Source[Position+1]))) then begin - NextChar; - v:=0; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - end; - end; - AResult.StringValue:=AResult.StringValue+widechar(word(v)); - end else begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin - AddError('Invalid escape char x'); - end else begin - NextChar; - AResult.StringValue:=AResult.StringValue+'x'; - end; - end; - end; - ord('u'):begin - if ((Position+3)<=length(Source)) and BESENIsHex(word(widechar(Source[Position]))) and BESENIsHex(word(widechar(Source[Position+1]))) and BESENIsHex(word(widechar(Source[Position+2]))) and BESENIsHex(word(widechar(Source[Position+3]))) then begin - NextChar; - v:=0; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - end; - end; - end; - end; - AResult.StringValue:=AResult.StringValue+widechar(word(v)); - end else begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin - AddError('Invalid escape char u'); - end else begin - NextChar; - AResult.StringValue:=AResult.StringValue+'u'; - end; - end; - end; - else begin - AResult.StringValue:=AResult.StringValue+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - end; - else begin - AResult.StringValue:=AResult.StringValue+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - end; - if CurrentChar=c then begin - NextChar; - end else begin - AddError('Unterminated string literal'); - end; - end; - else begin - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (CurrentChar=ord('#')) then begin - NextChar; - AResult.Name:='function'; - AResult.TokenType:=ltkFUNCTION; - end else if BESENUnicodeIsIDStart(CurrentChar) or (CurrentChar=ord('\')) then begin - AResult.Name:=''; - while BESENUnicodeIsIDPart(CurrentChar) or (CurrentChar=ord('\')) do begin - if CurrentChar=ord('\') then begin - NextChar; - case CurrentChar of - ord('x'),ord('X'):begin - NextChar; - v:=0; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - end; - end; - AResult.Name:=AResult.Name+widechar(word(v)); - end; - ord('u'),ord('U'):begin - NextChar; - v:=0; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin - case CurrentChar of - ord('0')..ord('9'):begin - v:=(v shl 4) or longword(CurrentChar-ord('0')); - end; - ord('a')..ord('f'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); - end; - ord('A')..ord('F'):begin - v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); - end; - end; - NextChar; - end; - end; - end; - end; - AResult.Name:=AResult.Name+widechar(word(v)); - end; - else begin - AResult.Name:=AResult.Name+'\'+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - end else begin - AResult.Name:=AResult.Name+BESENUTF32CHARToUTF16(CurrentChar); - NextChar; - end; - end; - if (length(AResult.Name)>0) and ((word(widechar(AResult.Name[1]))=$200c) or (word(widechar(AResult.Name[1]))=$200d)) then begin - raise EBESENSyntaxError.Create('Invalid identifier because <ZWJ> and <ZWNJ> are prohibited as first character'); - end; - AResult.TokenType:=FindKeyword(AResult.Name); - if AResult.TokenType in BESENLexerStrictReservedTokens then begin - if TBESEN(Instance).IsStrict then begin - raise EBESENSyntaxError.CreateUTF16('"'+AResult.Name+'" is a reserved keyword'); - end else begin - AResult.TokenType:=lttIDENTIFIER; - end; - end; - end; - end; - end; - end; - break; - end; - AResult.LineEnd:=BESENUnicodeIsLineTerminator(CurrentChar); - LastWasLineEnd:=AResult.LineEnd; - end; -end; - -procedure InitKeywords; -var kt:TKeywordToken; - i:integer; - k:TKeyword; -begin - SetLength(Keywords,(integer(high(TKeywordToken))-integer(low(TKeywordToken)))+1); - i:=0; - for kt:=low(TKeywordToken) to high(TKeywordToken) do begin - Keywords[i]:=kt; - inc(i); - end; - i:=0; - while (i+1)<length(Keywords) do begin - if KeywordNames[Keywords[i]]>KeywordNames[Keywords[i+1]] then begin - k:=Keywords[i]; - Keywords[i]:=Keywords[i+1]; - Keywords[i+1]:=k; - if i>0 then begin - dec(i); - end else begin - inc(i); - end; - end else begin - inc(i); - end; - end; -end; - -procedure DoneKeywords; -begin - SetLength(Keywords,0); -end; - -procedure InitBESEN; -begin - InitKeywords; -end; - -procedure DoneBESEN; -begin - DoneKeywords; -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENLexicalEnvironment.pas b/3rd/besen/src/BESENLexicalEnvironment.pas deleted file mode 100644 index 65a726cd7..000000000 --- a/3rd/besen/src/BESENLexicalEnvironment.pas +++ /dev/null @@ -1,80 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENLexicalEnvironment; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENGarbageCollector; - -type TBESENLexicalEnvironment=class(TBESENGarbageCollectorObject) - public - Outer:TBESENLexicalEnvironment; - EnvironmentRecord:TBESENEnvironmentRecord; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENLexicalEnvironment.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Outer:=nil; - EnvironmentRecord:=nil; -end; - -destructor TBESENLexicalEnvironment.Destroy; -begin - Outer:=nil; - EnvironmentRecord:=nil; - inherited Destroy; -end; - -procedure TBESENLexicalEnvironment.Finalize; -begin - Outer:=nil; - EnvironmentRecord:=nil; - inherited Finalize; -end; - -procedure TBESENLexicalEnvironment.Mark; -begin - TBESEN(Instance).GarbageCollector.GrayIt(Outer); - TBESEN(Instance).GarbageCollector.GrayIt(EnvironmentRecord); - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENLocale.pas b/3rd/besen/src/BESENLocale.pas deleted file mode 100644 index 9791fe191..000000000 --- a/3rd/besen/src/BESENLocale.pas +++ /dev/null @@ -1,225 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENLocale; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}SysUtils,Classes,BESENConstants,BESENTypes,BESENBaseObject; - -const BESENDefaultFormatSettings:TFormatSettings=( -{$ifdef DelphiXEAndUp} - CurrencyString:'$'; - CurrencyFormat:1; - CurrencyDecimals:2; - DateSeparator:'-'; - TimeSeparator:':'; - ListSeparator:','; - ShortDateFormat:'d/m/y'; - LongDateFormat:'dd" "mmmm" "yyyy'; - TimeAMString:'AM'; - TimePMString:'PM'; - ShortTimeFormat:'hh:nn'; - LongTimeFormat:'hh:nn:ss'; - ShortMonthNames:('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); - LongMonthNames:('January','February','March','April','May','June','July','August','September','October','November','December'); - ShortDayNames:('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); - LongDayNames:('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); - ThousandSeparator:','; - DecimalSeparator:'.'; - TwoDigitYearCenturyWindow:50; - NegCurrFormat:5; -{$else} - CurrencyFormat:1; - NegCurrFormat:5; - ThousandSeparator:','; - DecimalSeparator:'.'; - CurrencyDecimals:2; - DateSeparator:'-'; - TimeSeparator:':'; - ListSeparator:','; - CurrencyString:'$'; - ShortDateFormat:'d/m/y'; - LongDateFormat:'dd" "mmmm" "yyyy'; - TimeAMString:'AM'; - TimePMString:'PM'; - ShortTimeFormat:'hh:nn'; - LongTimeFormat:'hh:nn:ss'; - ShortMonthNames:('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); - LongMonthNames:('January','February','March','April','May','June','July','August','September','October','November','December'); - ShortDayNames:('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); - LongDayNames:('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); - TwoDigitYearCenturyWindow:50; -{$endif} - ); - -var BESENLocaleFormatSettings:TFormatSettings; - -implementation - -uses BESENCharSet,BESENStringUtils; - -{$warnings off} -procedure InitLocaleFormatSettings; -{$ifdef windows} -{$ifdef fpc} -var i:integer; -begin - BESENLocaleCharset:=ISO_8859_1;//BESENGetCodePage('ISO-8859-1'); - BESENLocaleFormatSettings:=BESENDefaultFormatSettings; - for i:= 1 to 12 do begin - BESENLocaleFormatSettings.ShortMonthNames[i]:=SysUtils.ShortMonthNames[i]; - BESENLocaleFormatSettings.LongMonthNames[i]:=SysUtils.LongMonthNames[i]; - end; - for i:=1 to 7 do begin - BESENLocaleFormatSettings.ShortDayNames[i]:=SysUtils.ShortDayNames[i]; - BESENLocaleFormatSettings.LongDayNames[i]:=SysUtils.LongDayNames[i]; - end; - BESENLocaleFormatSettings.DateSeparator:=SysUtils.DateSeparator; - BESENLocaleFormatSettings.ShortDateFormat:=SysUtils.ShortDateFormat; - BESENLocaleFormatSettings.LongDateFormat:=SysUtils.LongDateFormat; - BESENLocaleFormatSettings.TimeSeparator:=SysUtils.TimeSeparator; - BESENLocaleFormatSettings.TimeAMString:=SysUtils.TimeAMString; - BESENLocaleFormatSettings.TimePMString:=SysUtils.TimePMString; - BESENLocaleFormatSettings.ShortTimeFormat:=SysUtils.ShortTimeFormat; - BESENLocaleFormatSettings.LongTimeFormat:=SysUtils.LongTimeFormat; - BESENLocaleFormatSettings.CurrencyString:=SysUtils.CurrencyString; - BESENLocaleFormatSettings.CurrencyFormat:=SysUtils.CurrencyFormat; - BESENLocaleFormatSettings.NegCurrFormat:=SysUtils.NegCurrFormat; - BESENLocaleFormatSettings.ThousandSeparator:=SysUtils.ThousandSeparator; - BESENLocaleFormatSettings.DecimalSeparator:=SysUtils.DecimalSeparator; - BESENLocaleFormatSettings.CurrencyDecimals:=SysUtils.CurrencyDecimals; - BESENLocaleFormatSettings.ListSeparator:=SysUtils.ListSeparator; -end; -{$else} -var HourFormat,TimePrefix,TimePostfix:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; - LID:LCID; - i,LCP,Day:integer; -begin - BESENLocaleFormatSettings:=BESENDefaultFormatSettings; - LID:=GetThreadLocale; - if not TryStrToInt(GetLocaleStr(LID,LOCALE_IDEFAULTANSICODEPAGE,inttostr(GetACP)),LCP) then begin - LCP:=GetACP; - end; -{$ifndef BESENSingleStringType} - if LCP>0 then begin - BESENLocaleCharset:=BESENGetCodePage('WINDOWS-'+inttostr(LCP)); - end else{$endif} begin - BESENLocaleCharset:=ISO_8859_1; - end; - for i:=1 to 12 do begin - BESENLocaleFormatSettings.ShortMonthNames[i]:=GetLocaleStr(LID,LOCALE_SABBREVMONTHNAME1+i-1,BESENDefaultFormatSettings.ShortMonthNames[i]); - BESENLocaleFormatSettings.LongMonthNames[i]:=GetLocaleStr(LID,LOCALE_SMONTHNAME1+i-1,BESENDefaultFormatSettings.LongMonthNames[i]); - end; - for i:=1 to 7 do begin - Day:=(i+5) mod 7; - BESENLocaleFormatSettings.ShortDayNames[i]:=GetLocaleStr(LID,LOCALE_SABBREVDAYNAME1+Day,BESENDefaultFormatSettings.ShortDayNames[i]); - BESENLocaleFormatSettings.LongDayNames[i]:=GetLocaleStr(LID,LOCALE_SDAYNAME1+Day,BESENDefaultFormatSettings.LongDayNames[i]); - end; - BESENLocaleFormatSettings.DateSeparator:=GetLocaleChar(LID,LOCALE_SDATE,'/'); - BESENLocaleFormatSettings.ShortDateFormat:=GetLocaleStr(LID,LOCALE_SSHORTDATE,'m/d/yy'); - BESENLocaleFormatSettings.LongDateFormat:=GetLocaleStr(LID,LOCALE_SLONGDATE,'mmmm d, yyyy'); - BESENLocaleFormatSettings.TimeSeparator:=GetLocaleChar(LID,LOCALE_STIME,':'); - BESENLocaleFormatSettings.TimeAMString:=GetLocaleStr(LID,LOCALE_S1159,'AM'); - BESENLocaleFormatSettings.TimePMString:=GetLocaleStr(LID,LOCALE_S2359,'PM'); - if StrToIntDef(GetLocaleStr(LID,LOCALE_ITLZERO,'0'),0)=0 then begin - HourFormat:='h'; - end else begin - HourFormat:='hh'; - end; - TimePostfix:=''; - TimePrefix:=''; - if StrToIntDef(GetLocaleStr(LID,LOCALE_ITIME,'0'),0)=0 then begin - if StrToIntDef(GetLocaleStr(LID,LOCALE_ITIMEMARKPOSN,'0'),0)=0 then begin - TimePostfix:=' AMPM'; - end else begin - TimePrefix:='AMPM '; - end; - end; - BESENLocaleFormatSettings.ShortTimeFormat:=TimePrefix+HourFormat+':nn'+TimePrefix; - BESENLocaleFormatSettings.LongTimeFormat:=TimePrefix+HourFormat+':nn:ss'+TimePrefix; - BESENLocaleFormatSettings.CurrencyString:=GetLocaleStr(LID,LOCALE_SCURRENCY,''); - BESENLocaleFormatSettings.CurrencyFormat:=StrToIntDef(GetLocaleStr(LID,LOCALE_ICURRENCY,'0'),0); - BESENLocaleFormatSettings.NegCurrFormat:=StrToIntDef(GetLocaleStr(LID,LOCALE_INEGCURR,'0'),0); - BESENLocaleFormatSettings.ThousandSeparator:=GetLocaleChar(LID,LOCALE_STHOUSAND,','); - BESENLocaleFormatSettings.DecimalSeparator:=GetLocaleChar(LID,LOCALE_SDECIMAL,'.'); - BESENLocaleFormatSettings.CurrencyDecimals:=StrToIntDef(GetLocaleStr(LID,LOCALE_ICURRDIGITS,'0'),0); - BESENLocaleFormatSettings.ListSeparator:=GetLocaleChar(LID,LOCALE_SLIST,','); -end; -{$endif} -{$else} -var i:integer; -begin - BESENLocaleCharset:=ISO_8859_1;//BESENGetCodePage('ISO-8859-1'); - BESENLocaleFormatSettings:=BESENDefaultFormatSettings; - for i:= 1 to 12 do begin - BESENLocaleFormatSettings.ShortMonthNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.ShortMonthNames[i]{$endif}; - BESENLocaleFormatSettings.LongMonthNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.LongMonthNames[i]{$endif}; - end; - for i:=1 to 7 do begin - BESENLocaleFormatSettings.ShortDayNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.ShortDayNames[i]{$endif}; - BESENLocaleFormatSettings.LongDayNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.LongDayNames[i]{$endif}; - end; - BESENLocaleFormatSettings.DateSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.DateSeparator{$else}SysUtils.DateSeparator{$endif}; - BESENLocaleFormatSettings.ShortDateFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortDateFormat{$else}SysUtils.ShortDateFormat{$endif}; - BESENLocaleFormatSettings.LongDateFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongDateFormat{$else}SysUtils.LongDateFormat{$endif}; - BESENLocaleFormatSettings.TimeSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimeSeparator{$else}SysUtils.TimeSeparator{$endif}; - BESENLocaleFormatSettings.TimeAMString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimeAMString{$else}SysUtils.TimeAMString{$endif}; - BESENLocaleFormatSettings.TimePMString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimePMString{$else}SysUtils.TimePMString{$endif}; - BESENLocaleFormatSettings.ShortTimeFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortTimeFormat{$else}SysUtils.ShortTimeFormat{$endif}; - BESENLocaleFormatSettings.LongTimeFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongTimeFormat{$else}SysUtils.LongTimeFormat{$endif}; - BESENLocaleFormatSettings.CurrencyString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyString{$else}SysUtils.CurrencyString{$endif}; - BESENLocaleFormatSettings.CurrencyFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyFormat{$else}SysUtils.CurrencyFormat{$endif}; - BESENLocaleFormatSettings.NegCurrFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.NegCurrFormat{$else}SysUtils.NegCurrFormat{$endif}; - BESENLocaleFormatSettings.ThousandSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ThousandSeparator{$else}SysUtils.ThousandSeparator{$endif}; - BESENLocaleFormatSettings.DecimalSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.DecimalSeparator{$else}SysUtils.DecimalSeparator{$endif}; - BESENLocaleFormatSettings.CurrencyDecimals:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyDecimals{$else}SysUtils.CurrencyDecimals{$endif}; - BESENLocaleFormatSettings.ListSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ListSeparator{$else}SysUtils.ListSeparator{$endif}; -end; -{$endif} -{$warnings on} - -procedure InitBESEN; -begin - InitLocaleFormatSettings; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; - -end. diff --git a/3rd/besen/src/BESENNativeCodeMemoryManager.pas b/3rd/besen/src/BESENNativeCodeMemoryManager.pas deleted file mode 100644 index a21b0e392..000000000 --- a/3rd/besen/src/BESENNativeCodeMemoryManager.pas +++ /dev/null @@ -1,335 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENNativeCodeMemoryManager; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix,UnixType,{$endif} - SysUtils,Classes,BESENConstants,BESENTypes; - -type PBESENNativeCodeMemoryManagerBlock=^TBESENNativeCodeMemoryManagerBlock; - TBESENNativeCodeMemoryManagerBlock=packed record - Signature:ptruint; - Previous:PBESENNativeCodeMemoryManagerBlock; - Next:PBESENNativeCodeMemoryManagerBlock; - Size:ptruint; - end; - - PBESENNativeCodeMemoryManagerBlockContainer=^TBESENNativeCodeMemoryManagerBlockContainer; - TBESENNativeCodeMemoryManagerBlockContainer=record - Previous:PBESENNativeCodeMemoryManagerBlockContainer; - Next:PBESENNativeCodeMemoryManagerBlockContainer; - Base:pointer; - Size:ptruint; - Used:ptruint; - First:PBESENNativeCodeMemoryManagerBlock; - Last:PBESENNativeCodeMemoryManagerBlock; - end; - - TBESENNativeCodeMemoryManager=class - private - PageSize:ptruint; - Alignment:ptruint; - function AllocateBlockContainer(BlockContainerSize:ptruint):PBESENNativeCodeMemoryManagerBlockContainer; - procedure FreeBlockContainer(BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer); - public - First,Last:PBESENNativeCodeMemoryManagerBlockContainer; - constructor Create; - destructor Destroy; override; - function GetMemory(Size:ptruint):pointer; - procedure FreeMemory(p:pointer); - function ReallocMemory(p:pointer;Size:ptruint):pointer; - end; - -{$ifdef HasJIT} -{$ifdef unix} -var fpmprotect:function(__addr:pointer;__len:cardinal;__prot:longint):longint; cdecl;// external 'c' name 'mprotect'; -{$endif} -{$endif} - -implementation - -uses BESENUtils; - -const bncmmMemoryBlockSignature:ptruint={$ifdef cpu64}$1337bab3deadc0d3{$else}$deadc0d3{$endif}; - -constructor TBESENNativeCodeMemoryManager.Create; -{$ifdef windows} -var SystemInfo:TSystemInfo; -{$else} -{$ifdef unix} -{$endif} -{$endif} -begin - inherited Create; -{$ifdef windows} - GetSystemInfo(SystemInfo); - PageSize:=BESENRoundUpToPowerOfTwo(SystemInfo.dwPageSize); -{$else} -{$ifdef unix} - PageSize:=4096; -{$else} - PageSize:=4096; -{$endif} -{$endif} -{$ifdef cpu386} - Alignment:=16; -{$else} -{$ifdef cpuamd64} - Alignment:=16; -{$else} -{$ifdef cpuarm} - Alignment:=16; -{$else} - Alignment:=PageSize; -{$endif} -{$endif} -{$endif} - First:=nil; - Last:=nil; -end; - -destructor TBESENNativeCodeMemoryManager.Destroy; -begin - while assigned(First) do begin - FreeBlockContainer(First); - end; - inherited Destroy; -end; - -function TBESENNativeCodeMemoryManager.AllocateBlockContainer(BlockContainerSize:ptruint):PBESENNativeCodeMemoryManagerBlockContainer; -var Size:ptruint; - Block:PBESENNativeCodeMemoryManagerBlock; -begin - if BlockContainerSize>0 then begin - Size:=BESENRoundUpToMask(BlockContainerSize,PageSize); - New(result); -{$ifdef windows} - result^.Base:=VirtualAlloc(nil,Size,MEM_COMMIT,PAGE_EXECUTE_READWRITE); -{$else} -{$ifdef unix} - result^.Base:=fpmmap(nil,Size,PROT_READ or PROT_WRITE or PROT_EXEC,MAP_PRIVATE or MAP_ANONYMOUS,-1,0); -{$else} - GetMem(result^.Base,Size); -{$endif} -{$endif} - result^.Size:=Size; - result^.Used:=sizeof(TBESENNativeCodeMemoryManagerBlock)*2; - if assigned(Last) then begin - Last^.Next:=result; - result^.Previous:=Last; - Last:=result; - result^.Next:=nil; - end else begin - First:=result; - Last:=result; - result^.Previous:=nil; - result^.Next:=nil; - end; - FillChar(result^.Base^,result^.Size,#0); - result^.First:=result^.Base; - result^.Last:=pointer(@PBESENByteArray(result^.Base)[result^.Size-sizeof(TBESENNativeCodeMemoryManagerBlock)]); - Block:=result^.First; - Block^.Signature:=bncmmMemoryBlockSignature; - Block^.Previous:=nil; - Block^.Next:=result^.Last; - Block^.Size:=0; - Block:=result^.Last; - Block^.Signature:=bncmmMemoryBlockSignature; - Block^.Previous:=result^.First; - Block^.Next:=nil; - Block^.Size:=0; - end else begin - result:=nil; - end; -end; - -procedure TBESENNativeCodeMemoryManager.FreeBlockContainer(BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer); -begin - if assigned(BlockContainer^.Previous) then begin - BlockContainer^.Previous^.Next:=BlockContainer^.Next; - end else begin - First:=BlockContainer^.Next; - end; - if assigned(BlockContainer^.Next) then begin - BlockContainer^.Next^.Previous:=BlockContainer^.Previous; - end else begin - Last:=BlockContainer^.Previous; - end; -{$ifdef windows} - VirtualFree(BlockContainer^.Base,0,MEM_RELEASE); -{$else} -{$ifdef unix} - fpmunmap(BlockContainer^.Base,BlockContainer^.Size); -{$else} - FreeMem(BlockContainer^.Base); -{$endif} -{$endif} - Dispose(BlockContainer); -end; - -function TBESENNativeCodeMemoryManager.GetMemory(Size:ptruint):pointer; -var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; - CurrentBlock,NewBlock:PBESENNativeCodeMemoryManagerBlock; - DestSize,BlockContainerSize:ptruint; -begin - result:=nil; - if Size>0 then begin - DestSize:=Size+sizeof(TBESENNativeCodeMemoryManagerBlock); - BlockContainer:=First; - while true do begin - while assigned(BlockContainer) do begin - if (BlockContainer^.Used+DestSize)<=BlockContainer^.Size then begin - CurrentBlock:=BlockContainer^.First; - while assigned(CurrentBlock) and (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and assigned(CurrentBlock^.Next) do begin - NewBlock:=pointer(ptruint(BESENRoundUpToMask(ptruint(pointer(@PBESENByteArray(CurrentBlock)[(sizeof(TBESENNativeCodeMemoryManagerBlock)*2)+CurrentBlock^.Size])),Alignment)-sizeof(TBESENNativeCodeMemoryManagerBlock))); - if (ptruint(CurrentBlock^.Next)-ptruint(NewBlock))>=DestSize then begin - NewBlock^.Signature:=bncmmMemoryBlockSignature; - NewBlock^.Previous:=CurrentBlock; - NewBlock^.Next:=CurrentBlock^.Next; - NewBlock^.Size:=Size; - CurrentBlock^.Next^.Previous:=NewBlock; - CurrentBlock^.Next:=NewBlock; - result:=pointer(@PBESENByteArray(NewBlock)[sizeof(TBESENNativeCodeMemoryManagerBlock)]); - inc(BlockContainer^.Used,DestSize); - exit; - end else begin - CurrentBlock:=CurrentBlock^.Next; - end; - end; - end; - BlockContainer:=BlockContainer^.Next; - end; - if DestSize<=bncmmMINBLOCKCONTAINERSIZE then begin - BlockContainerSize:=bncmmMINBLOCKCONTAINERSIZE; - end else begin - BlockContainerSize:=BESENRoundUpToPowerOfTwo(DestSize); - end; - BlockContainer:=AllocateBlockContainer(BlockContainerSize); - if not assigned(BlockContainer) then begin - break; - end; - end; - end; -end; - -procedure TBESENNativeCodeMemoryManager.FreeMemory(p:pointer); -var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; - CurrentBlock:PBESENNativeCodeMemoryManagerBlock; -begin - BlockContainer:=First; - while assigned(BlockContainer) do begin - if ((ptruint(BlockContainer^.Base)+sizeof(TBESENNativeCodeMemoryManagerBlock))<=ptruint(p)) and ((ptruint(p)+sizeof(TBESENNativeCodeMemoryManagerBlock))<(ptruint(BlockContainer^.Base)+BlockContainer^.Size)) then begin - CurrentBlock:=pointer(ptruint(ptruint(p)-sizeof(TBESENNativeCodeMemoryManagerBlock))); - if (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and (CurrentBlock<>BlockContainer^.First) and (CurrentBlock<>BlockContainer^.Last) then begin - dec(BlockContainer^.Used,CurrentBlock^.Size+sizeof(TBESENNativeCodeMemoryManagerBlock)); - CurrentBlock^.Signature:=0; - CurrentBlock^.Previous^.Next:=CurrentBlock^.Next; - CurrentBlock^.Next^.Previous:=CurrentBlock^.Previous; - if (assigned(BlockContainer^.First) and (BlockContainer^.First^.Next=BlockContainer^.Last)) or not assigned(BlockContainer^.First) then begin - FreeBlockContainer(BlockContainer); - end; - exit; - end; - end; - BlockContainer:=BlockContainer^.Next; - end; -end; - -function TBESENNativeCodeMemoryManager.ReallocMemory(p:pointer;Size:ptruint):pointer; -var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; - CurrentBlock:PBESENNativeCodeMemoryManagerBlock; - DestSize:ptruint; -begin - result:=nil; - if assigned(p) then begin - if Size=0 then begin - FreeMemory(p); - end else begin - DestSize:=Size+sizeof(TBESENNativeCodeMemoryManagerBlock); - BlockContainer:=First; - while assigned(BlockContainer) do begin - if ((ptruint(BlockContainer^.Base)+sizeof(TBESENNativeCodeMemoryManagerBlock))<=ptruint(p)) and ((ptruint(p)+sizeof(TBESENNativeCodeMemoryManagerBlock))<(ptruint(BlockContainer^.Base)+BlockContainer^.Size)) then begin - CurrentBlock:=pointer(ptruint(ptruint(p)-sizeof(TBESENNativeCodeMemoryManagerBlock))); - if (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and (CurrentBlock<>BlockContainer^.First) and (CurrentBlock<>BlockContainer^.Last) then begin - if (ptruint(CurrentBlock^.Next)-ptruint(CurrentBlock))>=DestSize then begin - CurrentBlock^.Size:=Size; - result:=p; - exit; - end else begin - result:=GetMemory(Size); - if assigned(result) then begin - if CurrentBlock^.Size<Size then begin - Move(p^,result^,CurrentBlock^.Size); - end else begin - Move(p^,result^,Size); - end; - end; - FreeMemory(p); - exit; - end; - end; - end; - BlockContainer:=BlockContainer^.Next; - end; - end; - FreeMemory(p); - end else if Size<>0 then begin - result:=GetMemory(Size); - end; -end; - -procedure InitBESEN; -begin -{$ifdef HasJIT} -{$ifdef unix} -{$ifdef darwin} - fpmprotect:=dlsym(dlopen('libc.dylib',RTLD_NOW),'mprotect'); -{$else} - fpmprotect:=dlsym(dlopen('libc.so',RTLD_NOW),'mprotect'); -{$endif} - if not assigned(fpmprotect) then begin - raise Exception.Create('Importing of mprotect from libc.so failed!'); - end; -{$endif} -{$endif} -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENNativeObject.pas b/3rd/besen/src/BESENNativeObject.pas deleted file mode 100644 index 6c1e2f026..000000000 --- a/3rd/besen/src/BESENNativeObject.pas +++ /dev/null @@ -1,612 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENNativeObject; -{$i BESEN.inc} - -interface - -uses TypInfo,Variants,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, - BESENEnvironmentRecord; - -type TBESENNativeObject=class(TBESENObjectFunction) - private - PropList:PPropList; - PropListLen:integer; - function GetProp(const Prop:TBESENObjectProperty;var V:TBESENValue;Throw:boolean):boolean; - function PutProp(const Prop:TBESENObjectProperty;const V:TBESENValue;Throw:boolean):boolean; - protected - procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); virtual; - procedure InitializeObject; virtual; - procedure FinalizeObject; virtual; - public - Initialized:TBESENBoolean; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; - function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; - procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; - procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; - function HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - - TBESENNativeObjectClass=class of TBESENNativeObject; - -implementation - -uses {$ifdef BESENEmbarcaderoNextGen}System.SysUtils,{$endif}BESEN,BESENErrors,BESENHashUtils,BESENStringUtils,BESENGarbageCollector; - -{$ifdef BESENEmbarcaderoNextGen} -function PByteToString(Src:pbyte):string; -var SrcLen,ResultLen:longint; - TempStr:MarshaledAString; - TempBuffer:array[0..255] of char; -begin - result:=''; - if not assigned(Src) then begin - SrcLen:=Src^; - if ShortStringLength>0 then begin - inc(Src); - TempStr:=MarshaledAString(Src); - ResultLen:=UTF8ToUnicode(TempBuffer,length(TempBuffer),TempStr,SrcKen); - SetString(Result,TempBuffer,ResultLen-1); - end; - end; -end; -{$endif} - -constructor TBESENNativeObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - Initialized:=false; - PropList:=nil; - PropListLen:=0; - ObjectClassName:=ClassName+'$Constructor'; -end; - -destructor TBESENNativeObject.Destroy; -begin - if Initialized then begin - FinalizeObject; - end; - if assigned(PropList) then begin - FreeMem(PropList); - PropList:=nil; - PropListLen:=0; - end; - inherited Destroy; -end; - -procedure TBESENNativeObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); -begin -end; - -procedure TBESENNativeObject.InitializeObject; -{$ifdef fpc} -type PShortString=^ShortString; -{$endif} -type PMethodNameRec=^TMethodNameRec; - TMethodNameRec=packed record -{$ifdef fpc} - Name:PShortString; - Address:pointer; -{$else} - Size:word; - Address:pointer; - Name:{$ifdef BESENEmbarcaderoNextGen}TSymbolName{$else}ShortString{$endif}; -{$endif} - end; - TMethodNameRecs=packed array[word] of TMethodNameRec; - PMethodNameTable=^TMethodNameTable; - TMethodNameTable=packed record - Count:{$ifdef fpc}longword{$else}word{$endif}; - Methods:TMethodNameRecs; - end; -var i:integer; - Prop:TBESENObjectProperty; - Item:PPropInfo; - MethodTable:PMethodNameTable; - MethodNameRec:PMethodNameRec; - MethodName:TBESENSTRING; - MethodAddress:pointer; - NativeFunction:TBESENNativeFunction; -begin - if not Initialized then begin - Initialized:=true; - - ObjectClassName:=ClassName+'$Instance'; - - try - MethodTable:=pointer(pointer(ptrint(ptrint(pointer(self)^)+vmtMethodTable))^); - if assigned(MethodTable) then begin - MethodNameRec:=@MethodTable^.Methods[0]; - for i:=0 to MethodTable^.Count-1 do begin -{$ifdef fpc} - MethodName:=MethodNameRec^.Name^; -{$else} -{$ifdef BESENEmbarcaderoNextGen} - MethodName:=PByteToString(@(MethodNameRec^.Name)); -{$else} - MethodName:=TBESENSTRING(MethodNameRec^.Name); -{$endif} -{$endif} - MethodAddress:=MethodNameRec^.Address; - if (length(MethodName)>0) and assigned(MethodAddress) then begin - TMethod(NativeFunction).Code:=MethodAddress; - TMethod(NativeFunction).Data:=self; - RegisterNativeFunction(MethodName,NativeFunction,0,[],false); - end; -{$ifdef fpc} - inc(MethodNameRec); -{$else} - inc(ptruint(MethodNameRec),MethodNameRec^.Size); -{$endif} - end; - end; - except - raise; - end; - - PropListLen:=GetPropList(self,PropList); - try - for i:=0 to PropListLen-1 do begin - Item:=PropList^[i]; - if assigned(Item^.PropType) then begin - case Item^.PropType^.Kind of - tkLString,tkWString{$ifdef fpc},tkAString{$endif},tkVariant{$ifdef fpc},tkUString{$endif}, - tkInteger,tkChar,tkFloat,tkEnumeration,tkWChar,tkSet{$ifdef fpc},tkSString{$endif}, - tkInt64{$ifdef fpc},tkQWORD{$endif},tkClass:begin -{$ifdef BESENEmbarcaderoNextGen} - if not assigned(Item^.GetProc) then begin - BESENThrowNotReadable(PByteToString(@(Item^.Name))); - end; - Prop:=Properties.Get(PByteToString(@(Item^.Name))); - if not assigned(Prop) then begin - Prop:=Properties.Put(PByteToString(@(Item^.Name))); - end; -{$else} - if not assigned(Item^.GetProc) then begin - BESENThrowNotReadable(TBESENString(Item^.Name)); - end; - Prop:=Properties.Get(TBESENString(Item^.Name)); - if not assigned(Prop) then begin - Prop:=Properties.Put(TBESENString(Item^.Name)); - end; -{$endif} - Prop.PropIndex:=i; - Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; - Prop.Descriptor.Getter:=nil; - Prop.Descriptor.Setter:=nil; - if assigned(Item^.SetProc) then begin - Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE]; - end else begin - Prop.Descriptor.Attributes:=[bopaENUMERABLE]; - end; - Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - end; - end; - end; - end; - except - FreeMem(PropList); - PropList:=nil; - PropListLen:=0; - raise; - end; - - InvalidateStructure; - end; -end; - -procedure TBESENNativeObject.FinalizeObject; -begin - if Initialized then begin - Initialized:=false; - if assigned(PropList) then begin - FreeMem(PropList); - PropList:=nil; - PropListLen:=0; - end; - end; -end; - -function TBESENNativeObject.GetProp(const Prop:TBESENObjectProperty;var V:TBESENValue;Throw:boolean):boolean; -var Item:PPropInfo; - O:TObject; - Index:integer; -begin - result:=false; - if not Initialized then begin - exit; - end; - - Index:=Prop.PropIndex; - if (Index>=0) and (Index<PropListLen) then begin - Item:=PropList^[Index]; - end else begin - exit; - end; - - if not assigned(Item^.GetProc) then begin - if Throw then begin -{$ifdef BESENEmbarcaderoNextGen} - BESENThrowNotReadable(PByteToString(@(Item^.Name))); -{$else} - BESENThrowNotReadable(TBESENString(Item^.Name)); -{$endif} - end; - exit; - end; - - case Item^.PropType^.Kind of - tkLString{$ifdef fpc},tkAString,tkSString{$endif}:begin - V.ValueType:=bvtSTRING; -{$ifdef Delphi2009AndUp} - V.Str:=GetStrProp(self,Item); -{$else} - V.Str:=BESENConvertToUTF8(GetStrProp(self,Item)); -{$endif} - end; - tkWString{$ifdef fpc},tkUString{$endif}{$ifdef BESENEmbarcaderoNextGen},tkUString{$endif}:begin - V.ValueType:=bvtSTRING; - V.Str:={$ifdef BESENEmbarcaderoNextGen}GetStrProp{$else}GetWideStrProp{$endif}(self,Item); - end; - tkEnumeration:begin - V.ValueType:=bvtSTRING; - V.Str:=GetEnumProp(self,Item); - end; - tkSet:begin - V.ValueType:=bvtSTRING; - V.Str:=GetSetProp(self,Item,false); - end; - tkInteger:begin - V.ValueType:=bvtNUMBER; - V.Num:=GetOrdProp(self,Item); - end; - tkChar:begin - V.ValueType:=bvtSTRING; - V.Str:=WideChar({$ifndef BESENEmbarcaderoNextGen}TBESENCHAR({$endif}byte(GetOrdProp(self,Item)){$ifndef BESENEmbarcaderoNextGen}){$endif}); - end; - tkWChar:begin - V.ValueType:=bvtSTRING; - V.Str:=widechar(word(GetOrdProp(self,Item))); - end; - tkInt64{$ifdef fpc},tkQWORD{$endif}:begin - V.ValueType:=bvtNUMBER; - V.Num:=GetInt64Prop(self,Item); - end; - tkFloat:begin - V.ValueType:=bvtNUMBER; - V.Num:=GetFloatProp(self,Item); - end; - tkClass:begin - O:=GetObjectProp(self,Item); - if assigned(O) then begin - if O is TBESENObject then begin - V.ValueType:=bvtOBJECT; - TBESENObject(v.Obj):=TBESENObject(o); - end else begin - V.ValueType:=bvtUNDEFINED; - end; - end else begin - V.ValueType:=bvtNULL; - end; - end; - tkVariant:begin - BESENVariantToValue(GetVariantProp(self,Item),V); - end; - else begin - if Throw then begin - BESENThrowTypeError('Unknown native property data type'); - end; - exit; - end; - end; - - result:=true; -end; - -function TBESENNativeObject.PutProp(const Prop:TBESENObjectProperty;const V:TBESENValue;Throw:boolean):boolean; -var Item:PPropInfo; - Index:integer; -begin - result:=false; - if not Initialized then begin - exit; - end; - - Index:=Prop.PropIndex; - if (Index>=0) and (Index<PropListLen) then begin - Item:=PropList^[Index]; - end else begin - exit; - end; - - if not (assigned(Item^.SetProc) and ((boppWRITABLE in Prop.Descriptor.Presents) and (bopaWRITABLE in Prop.Descriptor.Attributes))) then begin - if Throw then begin -{$ifdef BESENEmbarcaderoNextGen} - BESENThrowNotWritable(PByteToString(@(Item^.Name))); -{$else} - BESENThrowNotWritable(TBESENString(Item^.Name)); -{$endif} - end; - exit; - end; - - case Item^.PropType^.Kind of - tkLString{$ifdef fpc},tkAString,tkSString{$endif}:begin -{$ifdef Delphi2009AndUp} - SetStrProp(self,Item,TBESEN(Instance).ToStr(V)); -{$else} - SetStrProp(self,Item,BESENUTF16ToUTF8(TBESEN(Instance).ToStr(V))); -{$endif} - end; - tkWString{$ifdef fpc},tkUString{$endif}{$ifdef BESENEmbarcaderoNextGen},tkUString{$endif}:begin - {$ifdef BESENEmbarcaderoNextGen}SetStrProp{$else}SetWideStrProp{$endif}(self,Item,TBESEN(Instance).ToStr(V)); - end; - tkEnumeration:begin - SetEnumProp(self,Item,TBESEN(Instance).ToStr(V)); - end; - tkSet:begin - SetSetProp(self,Item,TBESEN(Instance).ToStr(V)); - end; - tkInteger:begin - SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); - end; - tkChar:begin - if (V.ValueType=bvtSTRING) and (length(V.Str)>0) then begin - SetOrdProp(self,Item,byte(word(widechar(V.Str[1])))); - end else begin - SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); - end; - end; - tkWChar:begin - if (V.ValueType=bvtSTRING) and (length(V.Str)>0) then begin - SetOrdProp(self,Item,word(widechar(V.Str[1]))); - end else begin - SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); - end; - end; - tkInt64{$ifdef fpc},tkQWORD{$endif}:begin - SetInt64Prop(self,Item,TBESEN(Instance).ToInt(V)); - end; - tkFloat:begin - SetFloatProp(self,Item,TBESEN(Instance).ToNum(V)); - end; - tkClass:begin - SetObjectProp(self,Item,TBESEN(Instance).ToObj(V)); - end; - tkVariant:begin - SetVariantProp(self,Item,BESENValueToVariant(V)); - end; - else begin - if Throw then begin - BESENThrowTypeError('Wrong native property data type'); - end; - exit; - end; - end; - - result:=true; -end; - -function TBESENNativeObject.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; -begin - LastProp:=Properties.Get(P,Hash); - if assigned(LastProp) and (LastProp.PropIndex>=0) then begin - if GetProp(LastProp,Descriptor.Value,true) then begin - Descriptor.Getter:=LastProp.Descriptor.Getter; - Descriptor.Setter:=LastProp.Descriptor.Setter; - Descriptor.Attributes:=LastProp.Descriptor.Attributes; - Descriptor.Presents:=LastProp.Descriptor.Presents; - result:=true; - end else begin - result:=false; - end; - end else begin - result:=inherited GetOwnProperty(P,Descriptor); - end; -end; - -function TBESENNativeObject.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - LastProp:=Properties.Get(P,Hash); - if assigned(LastProp) and (LastProp.PropIndex>=0) then begin - result:=GetProp(LastProp,AResult,true); - end else begin - result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); - end; -end; - -function TBESENNativeObject.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - if (((Index>=0) and (Index<Properties.ItemCount)) and (Properties.Items[Index].ID=ID)) and (Properties.Items[Index].PropIndex>=0) then begin - result:=GetProp(Properties.Items[Index],AResult,true); - end else begin - result:=Get(TBESEN(Instance).KeyIDManager.List[ID],AResult,Base); - end; -end; - -procedure TBESENNativeObject.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); -begin - LastProp:=Properties.Get(P,Hash); - if assigned(LastProp) and (LastProp.PropIndex>=0) then begin - PutProp(LastProp,V,Throw); - end else begin - inherited PutEx(P,V,Throw,Descriptor,OwnDescriptor,TempValue,Hash); - end; -end; - -procedure TBESENNativeObject.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); -begin - if (((Index>=0) and (Index<Properties.ItemCount)) and (Properties.Items[Index].ID=ID)) and (Properties.Items[Index].PropIndex>=0) then begin - PutProp(Properties.Items[Index],V,Throw); - end else begin - Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); - end; -end; - -function TBESENNativeObject.HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - LastProp:=Properties.Get(P,Hash); - if assigned(LastProp) and (LastProp.PropIndex>=0) then begin - result:=true; - end else begin - result:=inherited HasPropertyEx(P,Descriptor,Hash); - end; -end; - -function TBESENNativeObject.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; - procedure BESENThrowIt; - begin - BESENThrowTypeError('Delete for "'+P+'" failed'); - end; -begin - LastProp:=Properties.Get(P,Hash); - if assigned(LastProp) and (LastProp.PropIndex>=0) then begin - result:=false; - if Throw then begin - BESENThrowIt; - end; - end else begin - result:=DeleteEx(P,Throw,Descriptor,Hash); - end; -end; - -function TBESENNativeObject.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - LastProp:=Properties.Get(P,Hash); - if assigned(LastProp) and (LastProp.PropIndex>=0) then begin - if (boppVALUE in Descriptor.Presents) and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)) then begin - PutProp(LastProp,Descriptor.Value,Throw); - result:=true; - end else begin - if Throw then begin - BESENThrowDefineOwnProperty(P); - end; - result:=false; - end; - end else begin - result:=inherited DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); - end; -end; - -procedure TBESENNativeObject.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=TBESENNativeObjectClass(ClassType).Create(Instance,self,false); - TBESEN(Instance).GarbageCollector.Add(TBESENObject(AResult.Obj)); - TBESENObject(AResult.Obj).GarbageCollectorLock; - try - TBESENNativeObject(AResult.Obj).ObjectClassName:=AResult.Obj.ClassName; - TBESENNativeObject(AResult.Obj).InitializeObject; - TBESENNativeObject(AResult.Obj).ConstructObject(ThisArgument,Arguments,CountArguments); - finally - TBESENObject(AResult.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENNativeObject.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - BESENThrowTypeError('Not a function'); -end; - -function TBESENNativeObject.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENNativeObject.HasCall:TBESENBoolean; -begin - result:=false; -end; - -procedure TBESENNativeObject.Finalize; -var i:integer; - o:TObject; - Item:PPropInfo; -begin - if assigned(PropList) then begin - for i:=0 to PropListLen-1 do begin - Item:=PropList^[i]; - if assigned(Item^.PropType) then begin - case Item^.PropType^.Kind of - tkCLASS:begin - if assigned(Item^.SetProc) then begin - o:=GetObjectProp(self,Item); - if o is TBESENGarbageCollectorObject then begin - SetObjectProp(self,Item,nil); - end; - end; - end; - end; - end; - end; - end; - inherited Finalize; -end; - -procedure TBESENNativeObject.Mark; -var i:integer; - o:TObject; -begin - if assigned(PropList) then begin - for i:=0 to PropListLen-1 do begin - if assigned(PropList^[i].PropType) then begin - case PropList^[i].PropType^.Kind of - tkCLASS:begin - o:=GetObjectProp(self,PropList^[i]); - if o is TBESENGarbageCollectorObject then begin - TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(o)); - end; - end; - end; - end; - end; - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENNumberUtils.pas b/3rd/besen/src/BESENNumberUtils.pas deleted file mode 100644 index 4865d286c..000000000 --- a/3rd/besen/src/BESENNumberUtils.pas +++ /dev/null @@ -1,4419 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENNumberUtils; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENStringUtils; - -type PBESENDoubleBytes=^TBESENDoubleBytes; - TBESENDoubleBytes=array[0..sizeof(double)-1] of byte; - - TBESENNumberCodeFlagLookupTable=array[word,boolean] of byte; - - PBESENNumberCodeAbstractRelationalLookupTableItem=^TBESENNumberCodeAbstractRelationalLookupTableItem; - TBESENNumberCodeAbstractRelationalLookupTableItem=packed record - IsNotUndefined:bytebool; - ResultBooleanValue:bytebool; - DoCompare:bytebool; - Spacer:bytebool; - end; - - TBESENNumberCodeAbstractRelationalLookupTable=array[byte] of TBESENNumberCodeAbstractRelationalLookupTableItem; - -const BESEN_ROUND_TO_NEAREST=0; - BESEN_ROUND_TOWARD_ZERO=1; - BESEN_ROUND_UPWARD=2; - BESEN_ROUND_DOWNWARD=3; - - BESEN_CHECKNUMBERSTRING_FAIL=-1; - BESEN_CHECKNUMBERSTRING_EMPTY=0; - BESEN_CHECKNUMBERSTRING_VALID=1; - BESEN_CHECKNUMBERSTRING_INFNEG=2; - BESEN_CHECKNUMBERSTRING_INFPOS=3; - BESEN_CHECKNUMBERSTRING_NAN=4; - - BESEN_DOUBLETOSTRINGMODE_STANDARD=0; - BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL=1; - BESEN_DOUBLETOSTRINGMODE_FIXED=2; - BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL=3; - BESEN_DOUBLETOSTRINGMODE_PRECISION=4; - BESEN_DOUBLETOSTRINGMODE_RADIX=5; - -{$ifdef BIG_ENDIAN} - BESENDoubleNaN:TBESENDoubleBytes=($7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff); - BESENDoubleInfPos:TBESENDoubleBytes=($7f,$f0,$00,$00,$00,$00,$00,$00); - BESENDoubleInfNeg:TBESENDoubleBytes=($ff,$f0,$00,$00,$00,$00,$00,$00); - BESENDoubleMax:TBESENDoubleBytes=($7f,$ef,$ff,$ff,$ff,$ff,$ff,$ff); - BESENDoubleMin:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$00,$01); -{$else} - BESENDoubleNaN:TBESENDoubleBytes=($ff,$ff,$ff,$ff,$ff,$ff,$ff,$7f); - BESENDoubleInfPos:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$f0,$7f); - BESENDoubleInfNeg:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$f0,$ff); - BESENDoubleMax:TBESENDoubleBytes=($ff,$ff,$ff,$ff,$ff,$ff,$ef,$7f); - BESENDoubleMin:TBESENDoubleBytes=($01,$00,$00,$00,$00,$00,$00,$00); -{$endif} - BESENDoubleZero:TBESENNumber=0.0; - BESENDoubleOne:TBESENNumber=1.0; - - BESENNumZero:TBESENNumber=0; - BESENNumOne:TBESENNumber=1; - -var BESENNumberCodeFlagLookupTable:TBESENNumberCodeFlagLookupTable; - BESENNumberCodeAbstractRelationalLookupTable:TBESENNumberCodeAbstractRelationalLookupTable; - -function BESENNumberCodeFlags(const AValue:TBESENNumber):byte; {$ifdef caninline}inline;{$endif} - -function BESENIntLog2(x:longword):longword; {$ifdef cpu386}assembler; register;{$endif} - -function BESENToInt(v:TBESENNumber):TBESENINT64; -function BESENToInt32(v:TBESENNumber):TBESENINT32; -function BESENToUInt32(v:TBESENNumber):TBESENUINT32; -function BESENToInt16(v:TBESENNumber):TBESENINT32; -function BESENToUInt16(v:TBESENNumber):TBESENUINT32; - -function BESENToIntFast(v:PBESENNumber):TBESENINT64; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -function BESENToInt32Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -function BESENToUInt32Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -function BESENToInt16Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -function BESENToUInt16Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} - -function BESENFloatToStr(const Value:TBESENNumber):TBESENString; -function BESENFloatToLocaleStr(const Value:TBESENNumber):TBESENString; - -function BESENSameValue(const A,B:TBESENNumber):boolean; -function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENNumberAbsolute(const AValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} -function BESENIsSameValue(const a,b:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -function BESENFloor(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} -function BESENCeil(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} - -function BESENStringToDoubleExact(const StringValue:TBESENString;RoundingMode:longint=BESEN_ROUND_TO_NEAREST;Base:longint=-1;OK:pointer=nil):double; -function BESENStringToDoubleFast(const StringValue:TBESENString;RoundingMode:integer=BESEN_ROUND_TO_NEAREST):double; -function BESENStringToDouble(const StringValue:TBESENString):double; - -function BESENStringToNumber(const StringValue:TBESENString;EmptyIsValid:TBESENBoolean=true;AcceptHex:TBESENBoolean=false;OnlyNumber:boolean=false;AcceptHexSign:boolean=true):TBESENNumber; - -function BESENStringToNumberBase(const StringValue:TBESENString;Base:longint):TBESENNumber; - -function BESENDoubleToString(const AValue:double;Mode,RequestedDigits:longint):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; - -function BESENNumberToString(const Value:TBESENNumber):TBESENString; - -function BESENNumberToRadixString(const Value:TBESENNumber;Radix:longint):TBESENString; - -function BESENCheckNumberString(const StringValue:TBESENString;var StartPosition,EndPosition:integer;IsParseFloat,AcceptHex,OnlyNumber,AcceptHexSign:boolean):integer; - -function BESENModulo(x,y:double):double;{$ifdef cpu386}stdcall; assembler;{$endif} -function BESENModuloPos(x,y:double):double; - -implementation - -uses BESENLocale; - -procedure InitBESENNumberTables; -var i:word; - j:boolean; - c,ca,cb:byte; - Item:PBESENNumberCodeAbstractRelationalLookupTableItem; -begin - for i:=low(TBESENNumberCodeFlagLookupTable) to high(TBESENNumberCodeFlagLookupTable) do begin - for j:=low(boolean) to high(boolean) do begin - c:=0; - if j then begin - if (i and $7ff0)=$7ff0 then begin - c:=c or bncfNAN; - end; - end else begin - if (i and $7ff0)=$7ff0 then begin - if (i and $000f)<>0 then begin - c:=c or bncfNAN; - end else begin - c:=c or bncfINFINITE; - end; - end else if (i and $7fff)=0 then begin - c:=c or bncfZERO; - end; - end; - if (i and $8000)<>0 then begin - c:=c or bncfNEGATIVE; - end; - BESENNumberCodeFlagLookupTable[i,j]:=c; - end; - end; - for c:=low(byte) to high(byte) do begin - Item:=@BESENNumberCodeAbstractRelationalLookupTable[c]; - ca:=c shr 4; - cb:=c and $f; - Item^.Spacer:=false; - if ((ca or cb) and bncfNAN)<>0 then begin - Item^.IsNotUndefined:=false; - Item^.ResultBooleanValue:=false; - Item^.DoCompare:=false; - end else if (((ca and cb) and bncfZERO)<>0) and (((ca xor cb) and bncfNEGATIVE)<>0) then begin - Item^.IsNotUndefined:=true; - Item^.ResultBooleanValue:=false; - Item^.DoCompare:=false; - end else if (ca and (bncfINFINITE or bncfNEGATIVE))=bncfINFINITE then begin - Item^.IsNotUndefined:=true; - Item^.ResultBooleanValue:=false; - Item^.DoCompare:=false; - end else if (cb and (bncfINFINITE or bncfNEGATIVE))=bncfINFINITE then begin - Item^.IsNotUndefined:=true; - Item^.ResultBooleanValue:=true; - Item^.DoCompare:=false; - end else if (cb and (bncfINFINITE or bncfNEGATIVE))=(bncfINFINITE or bncfNEGATIVE) then begin - Item^.IsNotUndefined:=true; - Item^.ResultBooleanValue:=false; - Item^.DoCompare:=false; - end else if (ca and (bncfINFINITE or bncfNEGATIVE))=(bncfINFINITE or bncfNEGATIVE) then begin - Item^.IsNotUndefined:=true; - Item^.ResultBooleanValue:=true; - Item^.DoCompare:=false; - end else begin - Item^.IsNotUndefined:=true; - Item^.ResultBooleanValue:=false; - Item^.DoCompare:=true; - end; - end; -end; - -function BESENNumberCodeFlags(const AValue:TBESENNumber):byte; {$ifdef caninline}inline;{$endif} -{$ifdef fpc} -var HighPart:longword; -begin - HighPart:=qword(pointer(@AValue)^) shr 32; - result:=BESENNumberCodeFlagLookupTable[HighPart shr 16,((HighPart and $ffff) or longword(qword(pointer(@AValue)^) and $ffffffff))<>0]; -end; -{$else} -{$ifdef cpu386} -asm - mov ecx,dword ptr [AValue+4] - mov edx,ecx - and edx,$0000ffff - or edx,dword ptr [AValue] - setnz dl - and edx,$7f - shr ecx,16 - mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] -end; -{$else} -var HighPart:longword; -begin - HighPart:=int64(pointer(@AValue)^) shr 32; - result:=BESENNumberCodeFlagLookupTable[HighPart shr 16,((HighPart and $ffff) or longword(int64(pointer(@AValue)^) and $ffffffff))<>0]; -end; -{$endif} -{$endif} - -function BESENStringToDoubleExact(const StringValue:TBESENString;RoundingMode:longint=BESEN_ROUND_TO_NEAREST;Base:longint=-1;OK:pointer=nil):double; -type PDoubleCasted=^TDoubleCasted; - TDoubleCasted=packed record - case byte of - 0:(Value:double); - 1:({$ifdef BIG_ENDIAN}Hi,Lo{$else}Lo,Hi{$endif}:longword); - 2:(Value64:int64); - end; -const MantissaWords=12; //6; // 12 - MantissaDigits=52; //28; // 52 - WordTopBit=$8000; - WordBits=16; - WordBitShift=4; - WordBitMask=WordBits-1; - WordMask=$ffff; - IEEEFormatBytes=8; - IEEEFormatBits=IEEEFormatBytes shl 3; - IEEEFormatExplicit=0; - IEEEFormatExponent=11; - IEEEFormatOneMask=WordTopBit shr ((IEEEFormatExponent+IEEEFormatExplicit) and WordBitMask); - IEEEFormatOnePos=(IEEEFormatExponent+IEEEFormatExplicit) shr WordBitShift; - IEEEFormatExpMax=1 shl (IEEEFormatExponent-1); - Bit53=int64(int64(1) shl 53); - MaximumMultiplier=longword(longword($ffffffff) div 36); -{$ifndef BESENNoFPU} - DtoAFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; - DtoAFPUPrecisionMode:TFPUPrecisionMode=pmDOUBLE; - DtoAFPURoundingMode:TFPURoundingMode=rmNEAREST; -{$endif} -type PWords=^TWords; - TWords=array[0..MantissaWords] of word; - PTemp=^TTemp; - TTemp=array[0..MantissaWords*2] of longword; - PDigits=^TDigits; - TDigits=array[0..MantissaDigits] of byte; -var MantissaPosition,Exponent,TenPower,TwoPower,ExtraTwos,Shift,i,p,q,r,Digit,Overflow,OverflowBits,DroppedBits,DroppedBitsMask,MiddleValue:longint; - Bit,Carry:word; - Negative,ExponentNegative,HasDigits,Started,ZeroTail,Done:boolean; - ResultCasted:PDoubleCasted; - Temp:PTemp; - Digits:PDigits; - MantissaMultiplicator,Mantissa:PWords; - Value:int64; - c:widechar; - Part,Multiplier,NextMultiplier:longword; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:TFPUExceptionMask; - OldFPUPrecisionMode:TFPUPrecisionMode; - OldFPURoundingMode:TFPURoundingMode; -{$endif} - function MantissaMultiply(vTo,vFrom:PWords):longint; - var i,j,k:longint; - v:longword; - t:PTemp; - begin - t:=Temp; - FillChar(t^,sizeof(TTemp),#0); - for i:=0 to MantissaWords-1 do begin - for j:=0 to MantissaWords-1 do begin - v:=longword(vTo^[i]+0)*longword(vFrom^[j]+0); - k:=i+j; - inc(t^[k],v shr WordBits); - inc(t^[k+1],v and WordMask); - end; - end; - for i:=high(TTemp) downto 1 do begin - inc(t^[i-1],t^[i] shr WordBits); - t^[i]:=t^[i] and WordMask; - end; - if (t^[0] and WordTopBit)<>0 then begin - for i:=0 to MantissaWords-1 do begin - vTo^[i]:=t^[i] and WordMask; - end; - result:=0; - end else begin - for i:=0 to MantissaWords-1 do begin - vTo^[i]:=(t^[i] shl 1)+word(ord((t^[i+1] and WordTopBit)<>0)); - end; - result:=-1; - end; - end; - procedure MantissaShiftRight(var Mantissa:TWords;Shift:longint); - var Bits,Words,InvBits,Position:longint; - Carry,Current:longword; - begin - Bits:=Shift and WordBitMask; - Words:=Shift shr WordBitShift; - InvBits:=WordBits-Bits; - Position:=high(TWords); - if Bits=0 then begin - if Words<>0 then begin - while Position>=Words do begin - Mantissa[Position]:=Mantissa[Position-Words]; - dec(Position); - end; - end; - end else begin - if (high(TWords)-Words)>=0 then begin - Carry:=Mantissa[high(TWords)-Words] shr Bits; - end else begin - Carry:=0; - end; - while Position>Words do begin - Current:=Mantissa[Position-(Words+1)]; - Mantissa[Position]:=(Current shl InvBits) or Carry; - Carry:=Current shr Bits; - dec(Position); - end; - Mantissa[Position]:=Carry; - dec(Position); - end; - while Position>=0 do begin - Mantissa[Position]:=0; - dec(Position); - end; - end; - procedure MantissaSetBit(var Mantissa:TWords;i:longint); - begin - Mantissa[i shr WordBitShift]:=Mantissa[i shr WordBitShift] or (WordTopBit shr (i and WordBitMask)); - end; - function MantissaTestBit(var Mantissa:TWords;i:longint):boolean; - begin - result:=(Mantissa[i shr WordBitShift] shr ((not i) and WordBitMask))<>0; - end; - function MantissaIsZero(var Mantissa:TWords):boolean; - var i:longint; - begin - result:=true; - for i:=low(TWords) to High(TWords) do begin - if Mantissa[i]<>0 then begin - result:=false; - break; - end; - end; - end; - function MantissaRound(Negative:boolean;var Mantissa:TWords;BitPos:longint):boolean; - var i,p:longint; - Bit:longword; - function RoundAbsDown:boolean; - var j:longint; - begin - Mantissa[i]:=Mantissa[i] and not (Bit-1); - for j:=i+1 to high(TWords) do begin - Mantissa[j]:=0; - end; - result:=false; - end; - function RoundAbsUp:boolean; - var j:longint; - begin - Mantissa[i]:=(Mantissa[i] and not (Bit-1))+Bit; - for j:=i+1 to high(TWords) do begin - Mantissa[j]:=0; - end; - while (i>0) and (Mantissa[i]=0) do begin - dec(i); - inc(Mantissa[i]); - end; - result:=Mantissa[0]=0; - end; - function RoundTowardsInfinity:boolean; - var j:longint; - m:longword; - begin - m:=Mantissa[i] and ((Bit shl 1)-1); - for j:=i+1 to high(TWords) do begin - m:=m or Mantissa[j]; - end; - if m<>0 then begin - result:=RoundAbsUp; - end else begin - result:=RoundAbsDown; - end; - end; - function RoundNear:boolean; - var j:longint; - m:longword; - begin - if (Mantissa[i] and Bit)<>0 then begin - Mantissa[i]:=Mantissa[i] and not Bit; - m:=Mantissa[i] and ((Bit shl 1)-1); - for j:=i+1 to high(TWords) do begin - m:=m or Mantissa[j]; - end; - Mantissa[i]:=Mantissa[i] or Bit; - if m<>0 then begin - result:=RoundAbsUp; - end else begin - if MantissaTestBit(Mantissa,BitPos-1) then begin - result:=RoundAbsUp; - end else begin - result:=RoundAbsDown; - end; - end; - end else begin - result:=RoundAbsDown; - end; - end; - begin - i:=BitPos shr WordBitShift; - p:=BitPos and WordBitMask; - Bit:=WordTopBit shr p; - case RoundingMode of - BESEN_ROUND_TO_NEAREST:begin - result:=RoundNear; - end; - BESEN_ROUND_TOWARD_ZERO:begin - result:=RoundAbsDown; - end; - BESEN_ROUND_UPWARD:begin - if Negative then begin - result:=RoundAbsDown; - end else begin - result:=RoundTowardsInfinity; - end; - end; - BESEN_ROUND_DOWNWARD:begin - if Negative then begin - result:=RoundTowardsInfinity; - end else begin - result:=RoundAbsDown; - end; - end; - else begin - result:=false; - end; - end; - end; - function CountLeadingZeros32(a:longword):longint; - const CountLeadingZerosHigh:array[byte] of byte=(8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); - begin - result:=0; - if a<$10000 then begin - inc(result,16); - a:=a shl 16; - end; - if a<$1000000 then begin - inc(result,8); - a:=a shl 8; - end; - inc(result,CountLeadingZerosHigh[a shr 24]); - end; - function CountLeadingZeros64(a:int64):longint; - begin - if a<int64($100000000) then begin - result:=32; - end else begin - result:=0; - a:=a shr 32; - end; - inc(result,CountLeadingZeros32(a)); - end; -begin - if assigned(OK) then begin - longbool(OK^):=false; - end; - ResultCasted:=pointer(@result); - ResultCasted^.Hi:=$7ff80000; - ResultCasted^.Lo:=$00000000; - i:=1; - p:=i; - while (i<=length(StringValue)) and BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i]))) do begin - inc(i); - end; - if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin - Negative:=StringValue[i]='-'; - inc(i); - end else begin - Negative:=false; - end; - HasDigits:=false; - if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin - if Negative then begin - ResultCasted^.Hi:=$fff00000; - ResultCasted^.Lo:=$00000000; - end else begin - ResultCasted^.Hi:=$7ff00000; - ResultCasted^.Lo:=$00000000; - end; - if assigned(OK) then begin - longbool(OK^):=true; - end; - end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin - ResultCasted^.Hi:=$7ff80000; - ResultCasted^.Lo:=$00000000; - if assigned(OK) then begin - longbool(OK^):=true; - end; - end else if (Base in [2,4,8,16,32]) or ((not (Base in [2..36])) and ((((i+1)<=length(StringValue)) and ((StringValue[i]='0') and ((StringValue[i+1]='b') or (StringValue[i+1]='o') or (StringValue[i+1]='x')))))) then begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - case Base of - 2:begin - Shift:=1; - end; - 4:begin - Shift:=2; - end; - 8:begin - Shift:=3; - end; - 16:begin - Shift:=4; - end; - 32:begin - Shift:=5; - end; - else begin - inc(i); - case StringValue[i] of - 'b':begin - Shift:=1; - end; - 'o':begin - Shift:=3; - end; - else {'x':}begin - Shift:=4; - end; - end; - inc(i); - end; - end; - TwoPower:=1 shl Shift; - Value:=0; - Exponent:=0; - while (i<=length(StringValue)) and (StringValue[i]='0') do begin - HasDigits:=true; - inc(i); - end; - if i<=length(StringValue) then begin - q:=0; - Digit:=0; - while i<=length(StringValue) do begin - c:=StringValue[i]; - if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+TwoPower)) then begin - Digit:=ord(c)-ord('0'); - end else if (TwoPower>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+TwoPower)-10))) then begin - Digit:=(ord(c)-ord('a'))+10; - end else if (TwoPower>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+TwoPower)-10))) then begin - Digit:=(ord(c)-ord('A'))+10; - end else begin - break; - end; - inc(i); - HasDigits:=true; - Value:=(Value shl Shift) or Digit; - Overflow:=longint(int64(Value shr 53)); - if Overflow<>0 then begin - OverflowBits:=1; - while Overflow>1 do begin - inc(OverflowBits); - Overflow:=Overflow shr 1; - end; - DroppedBitsMask:=(1 shl OverflowBits)-1; - DroppedBits:=Value and DroppedBitsMask; - Value:=Value shr OverflowBits; - Exponent:=OverflowBits; - ZeroTail:=true; - while i<=length(StringValue) do begin - c:=StringValue[i]; - if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+TwoPower)) then begin - Digit:=ord(c)-ord('0'); - end else if (TwoPower>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+TwoPower)-10))) then begin - Digit:=(ord(c)-ord('a'))+10; - end else if (TwoPower>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+TwoPower)-10))) then begin - Digit:=(ord(c)-ord('A'))+10; - end else begin - break; - end; - inc(i); - if Digit<>0 then begin - ZeroTail:=false; - end; - inc(Exponent,Shift); - end; - MiddleValue:=1 shl (OverflowBits-1); - if DroppedBits>MiddleValue then begin - inc(Value); - end else if DroppedBits=MiddleValue then begin - if ((Value and 1)<>0) or not ZeroTail then begin - inc(Value); - end; - end; - while (Value and Bit53)<>0 do begin - Value:=Value shr 1; - inc(Exponent); - end; - break; - end; - end; - if (Exponent<IEEEFormatExponent) and (Value<Bit53) then begin - Shift:=CountLeadingZeros64(Value)-11; - if Shift>=0 then begin - Value:=Value shl Shift; - end else begin - Value:=Value shr (-Shift); - end; - ResultCasted^.Value64:=((int64($432-(Shift-Exponent)) shl 52)+Value) and int64($7fffffffffffffff); - end else begin - New(Mantissa); - try - FillChar(Mantissa^,sizeof(TWords),#0); - Shift:=CountLeadingZeros64(Value); - Value:=Value shl Shift; - inc(Exponent,64-Shift); - Mantissa^[0]:=(Value shr 48) and $ffff; - Mantissa^[1]:=(Value shr 32) and $ffff; - Mantissa^[2]:=(Value shr 16) and $ffff; - Mantissa^[3]:=(Value shr 0) and $ffff; - if (Mantissa^[0] and WordTopBit)<>0 then begin - dec(Exponent); - if (Exponent>=(2-IEEEFormatExpMax)) and (Exponent<=IEEEFormatExpMax) then begin - inc(Exponent,IEEEFormatExpMax-1); - MantissaShiftRight(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit); - MantissaRound(Negative,Mantissa^,IEEEFormatBits); - if MantissaTestBit(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit-1) then begin - MantissaShiftRight(Mantissa^,1); - inc(Exponent); - end; - if Exponent>=(IEEEFormatExpMax shl 1)-1 then begin - ResultCasted^.Hi:=$7ff00000; - ResultCasted^.Lo:=$00000000; - end else begin - ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; - ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; - end; - end else if Exponent>0 then begin - ResultCasted^.Hi:=$7ff00000; - ResultCasted^.Lo:=$00000000; - end else begin - Shift:=IEEEFormatExplicit-(Exponent+(IEEEFormatExpMax-(2+IEEEFormatExponent))); - MantissaShiftRight(Mantissa^,Shift); - MantissaRound(Negative,Mantissa^,IEEEFormatBits); - if (Mantissa^[IEEEFormatOnePos] and IEEEFormatOneMask)<>0 then begin - Exponent:=1; - if IEEEFormatExplicit=0 then begin - Mantissa^[IEEEFormatOnePos]:=Mantissa^[IEEEFormatOnePos] and not IEEEFormatOneMask; - end; - Mantissa^[0]:=Mantissa^[0] or (Exponent shl (WordBitMask-IEEEFormatExponent)); - ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; - ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; - end else begin - if MantissaIsZero(Mantissa^) then begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end else begin - ResultCasted^.Hi:=(Mantissa^[0] shl 16) or Mantissa^[1]; - ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; - end; - end; - end; - end else begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end; - finally - Dispose(Mantissa); - end; - end; - end else begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end; - if Negative then begin - ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; - end; - if HasDigits then begin - if assigned(OK) then begin - longbool(OK^):=true; - end; - end; - end else if Base in [2..36] then begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - while (i<=length(StringValue)) and (StringValue[i]='0') do begin - HasDigits:=true; - inc(i); - end; - if i<=length(StringValue) then begin -{$ifndef BESENNoFPU} - OldFPUExceptionMask:=GetExceptionMask; - OldFPUPrecisionMode:=GetPrecisionMode; - OldFPURoundingMode:=GetRoundMode; -{$endif} - try -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin - SetExceptionMask(DtoAFPUExceptionMask); - end; - if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin - SetPrecisionMode(DtoAFPUPrecisionMode); - end; - if OldFPURoundingMode<>DtoAFPURoundingMode then begin - SetRoundMode(DtoAFPURoundingMode); - end; -{$endif} - Part:=0; - Multiplier:=1; - Digit:=0; - Done:=false; - while not Done do begin - while true do begin - c:=StringValue[i]; - if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+Base)) then begin - Digit:=ord(c)-ord('0'); - end else if (Base>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+Base)-10))) then begin - Digit:=(ord(c)-ord('a'))+10; - end else if (Base>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+Base)-10))) then begin - Digit:=(ord(c)-ord('A'))+10; - end else begin - Done:=true; - break; - end; - HasDigits:=true; - NextMultiplier:=Multiplier*longword(Base); - if NextMultiplier>MaximumMultiplier then begin - break; - end; - Part:=(Part*longword(Base))+longword(Digit); - Multiplier:=NextMultiplier; - Assert(Multiplier>Part); - inc(i); - if i>length(StringValue) then begin - Done:=true; - break; - end; - end; - ResultCasted^.Value:=(ResultCasted^.Value*Multiplier)+Part; - end; - finally -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin - SetExceptionMask(OldFPUExceptionMask); - end; - if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin - SetPrecisionMode(OldFPUPrecisionMode); - end; - if OldFPURoundingMode<>DtoAFPURoundingMode then begin - SetRoundMode(OldFPURoundingMode); - end; -{$endif} - end; - end else begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end; - if Negative then begin - ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; - end; - if HasDigits then begin - if assigned(OK) then begin - longbool(OK^):=true; - end; - end; - end else begin - HasDigits:=false; - Value:=0; - q:=i; - while i<=length(StringValue) do begin - c:=StringValue[i]; - if (c>='0') and (c<='9') then begin - HasDigits:=true; - Value:=(Value*10)+(ord(c)-ord('0')); - if (Value shr 53)<>0 then begin - HasDigits:=false; - break; - end; - end else begin - HasDigits:=false; - break; - end; - inc(i); - end; - if HasDigits then begin - if Value=0 then begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end else begin - Shift:=CountLeadingZeros64(Value)-11; - if Shift>=0 then begin - Value:=Value shl Shift; - end else begin - Value:=Value shr (-Shift); - end; - ResultCasted^.Value64:=((int64($432-Shift) shl 52)+Value) and int64($7fffffffffffffff); - end; - if Negative then begin - ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; - end; - if assigned(OK) then begin - longbool(OK^):=true; - end; - end else begin - i:=q; - New(MantissaMultiplicator); - New(Mantissa); - New(Temp); - New(Digits); - try - FillChar(Digits^,sizeof(TDigits),#0); - - p:=0; - TenPower:=0; - HasDigits:=false; - Started:=false; - ExponentNegative:=false; - Exponent:=0; - while i<=length(StringValue) do begin - case StringValue[i] of - '0':begin - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - while i<=length(StringValue) do begin - case StringValue[i] of - '0'..'9':begin - HasDigits:=true; - Started:=true; - if p<=high(TDigits) then begin - Digits^[p]:=ord(StringValue[i])-ord('0'); - inc(p); - end; - inc(TenPower); - inc(i); - end; - else begin - break; - end; - end; - end; - if (i<=length(StringValue)) and (StringValue[i]='.') then begin - inc(i); - if not Started then begin - while i<=length(StringValue) do begin - case StringValue[i] of - '0':begin - HasDigits:=true; - dec(TenPower); - inc(i); - end; - else begin - break; - end; - end; - end; - end; - while i<=length(StringValue) do begin - case StringValue[i] of - '0'..'9':begin - HasDigits:=true; - if p<=high(TDigits) then begin - Digits^[p]:=ord(StringValue[i])-ord('0'); - inc(p); - end; - inc(i); - end; - else begin - break; - end; - end; - end; - end; - if HasDigits then begin - if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin - inc(i); - if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin - ExponentNegative:=StringValue[i]='-'; - inc(i); - end; - HasDigits:=false; - while i<=length(StringValue) do begin - case StringValue[i] of - '0'..'9':begin - Exponent:=(Exponent*10)+longint(ord(StringValue[i])-ord('0')); - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - end; - if HasDigits then begin - if ExponentNegative then begin - dec(TenPower,Exponent); - end else begin - inc(TenPower,Exponent); - end; - - FillChar(Mantissa^,sizeof(TWords),#0); - - Bit:=WordTopBit; - q:=0; - Started:=false; - TwoPower:=0; - MantissaPosition:=0; - while MantissaPosition<MantissaWords do begin - Carry:=0; - while (p>q) and (Digits^[p-1]=0) do begin - dec(p); - end; - if p<=q then begin - break; - end; - r:=p; - while r>q do begin - dec(r); - i:=(2*Digits^[r])+Carry; - if i>=10 then begin - dec(i,10); - Carry:=1; - end else begin - Carry:=0; - end; - Digits^[r]:=i; - end; - if Carry<>0 then begin - Mantissa^[MantissaPosition]:=Mantissa^[MantissaPosition] or Bit; - Started:=true; - end; - if Started then begin - if Bit=1 then begin - Bit:=WordTopBit; - inc(MantissaPosition); - end else begin - Bit:=Bit shr 1; - end; - end else begin - dec(TwoPower); - end; - end; - inc(TwoPower,TenPower); - - if TenPower<0 then begin - for i:=0 to high(TWords)-1 do begin - MantissaMultiplicator^[i]:=$cccc; - end; - MantissaMultiplicator^[high(TWords)]:=$cccd; - ExtraTwos:=-2; - TenPower:=-TenPower; - end else if TenPower>0 then begin - MantissaMultiplicator^[0]:=$a000; - for i:=1 to high(TWords) do begin - MantissaMultiplicator^[i]:=$0000; - end; - ExtraTwos:=3; - end else begin - ExtraTwos:=0; - end; - while TenPower<>0 do begin - if (TenPower and 1)<>0 then begin - inc(TwoPower,ExtraTwos+MantissaMultiply(Mantissa,MantissaMultiplicator)); - end; - inc(ExtraTwos,ExtraTwos+MantissaMultiply(MantissaMultiplicator,MantissaMultiplicator)); - TenPower:=TenPower shr 1; - end; - - Exponent:=TwoPower; - if (Mantissa^[0] and WordTopBit)<>0 then begin - dec(Exponent); - - if (Exponent>=(2-IEEEFormatExpMax)) and (Exponent<=IEEEFormatExpMax) then begin - inc(Exponent,IEEEFormatExpMax-1); - MantissaShiftRight(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit); - MantissaRound(Negative,Mantissa^,IEEEFormatBits); - if MantissaTestBit(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit-1) then begin - MantissaShiftRight(Mantissa^,1); - inc(Exponent); - end; - if Exponent>=(IEEEFormatExpMax shl 1)-1 then begin - ResultCasted^.Hi:=$7ff00000; - ResultCasted^.Lo:=$00000000; - end else begin - ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; - ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; - end; - end else if Exponent>0 then begin - ResultCasted^.Hi:=$7ff00000; - ResultCasted^.Lo:=$00000000; - end else begin - Shift:=IEEEFormatExplicit-(Exponent+(IEEEFormatExpMax-(2+IEEEFormatExponent))); - MantissaShiftRight(Mantissa^,Shift); - MantissaRound(Negative,Mantissa^,IEEEFormatBits); - if (Mantissa^[IEEEFormatOnePos] and IEEEFormatOneMask)<>0 then begin - Exponent:=1; - if IEEEFormatExplicit=0 then begin - Mantissa^[IEEEFormatOnePos]:=Mantissa^[IEEEFormatOnePos] and not IEEEFormatOneMask; - end; - Mantissa^[0]:=Mantissa^[0] or (Exponent shl (WordBitMask-IEEEFormatExponent)); - ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; - ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; - end else begin - if MantissaIsZero(Mantissa^) then begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end else begin - ResultCasted^.Hi:=(Mantissa^[0] shl 16) or Mantissa^[1]; - ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; - end; - end; - end; - end else begin - ResultCasted^.Hi:=$00000000; - ResultCasted^.Lo:=$00000000; - end; - if Negative then begin - ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; - end; - if assigned(OK) then begin - longbool(OK^):=true; - end; - end; - end; - finally - Dispose(MantissaMultiplicator); - Dispose(Mantissa); - Dispose(Temp); - Dispose(Digits); - end; - end; - end; -end; - -function BESENConvertMantissaExponentToDouble(Mantissa:int64;MantissaSize,FractionalDigits,FractionalExponent,Exponent,ExponentSign:integer):double; {$ifdef caninline}inline;{$endif} -const MaxExponentOfTen=308; - MaxExponentOfTenMinusTwo=MaxExponentOfTen-2; - PowersOfTen:array[0..8] of TBESENParsingNumberType=(1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256); -var FloatValue,ExponentFactor:TBESENParsingNumberType; - MantissaExponent,PartExponent,Index:integer; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:TFPUExceptionMask; - OldFPURoundingMode:TFPURoundingMode; - OldFPUPrecisionMode:TFPUPrecisionMode; -{$endif} -begin -{$ifndef BESENNoFPU} - OldFPUExceptionMask:=GetExceptionMask; - OldFPURoundingMode:=GetRoundMode; - OldFPUPrecisionMode:=GetPrecisionMode; -{$endif} - try -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(BESENFPUExceptionMask); - end; - if OldFPURoundingMode<>rmNearest then begin - SetRoundMode(rmNearest); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(BESENFPUPrecisionMode); - end; -{$endif} - - FloatValue:=Mantissa; - - MantissaExponent:=FractionalDigits+FractionalExponent; - if MantissaSize>18 then begin - dec(MantissaExponent,MantissaSize-18); - end; - - if ExponentSign>0 then begin - dec(Exponent,MantissaExponent); - end else begin - inc(Exponent,MantissaExponent); - end; - if Exponent<0 then begin - ExponentSign:=-ExponentSign; - Exponent:=-Exponent; - end; - - while Exponent>0 do begin - PartExponent:=Exponent; - if PartExponent>MaxExponentOfTenMinusTwo then begin - PartExponent:=MaxExponentOfTenMinusTwo; - end; - dec(Exponent,PartExponent); - - Index:=0; - ExponentFactor:=1; - while (PartExponent<>0) and (Index<length(PowersOfTen)) do begin - if (PartExponent and 1)<>0 then begin - ExponentFactor:=ExponentFactor*PowersOfTen[Index]; - end; - inc(Index); - PartExponent:=PartExponent shr 1; - end; - - if ExponentSign>0 then begin - FloatValue:=FloatValue*ExponentFactor; - end else begin - FloatValue:=FloatValue/ExponentFactor; - end; - end; - result:=FloatValue; - finally -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(OldFPUExceptionMask); - end; - if OldFPURoundingMode<>rmNearest then begin - SetRoundMode(OldFPURoundingMode); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(OldFPUPrecisionMode); - end; -{$endif} - end; -end; - -function BESENStringToDoubleFast(const StringValue:TBESENString;RoundingMode:integer=BESEN_ROUND_TO_NEAREST):double; -type PDoubleCasted=^TDoubleCasted; - TDoubleCasted=packed record - case byte of - 0:(Value:double); - 1:({$ifdef BIG_ENDIAN}Hi,Lo{$else}Lo,Hi{$endif}:longword); - end; -const MaxExponentOfTen=308; - MaxExponentOfTenMinusTwo=MaxExponentOfTen-2; - PowersOfTen:array[0..8] of double=(1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256); -var i:integer; - Negative,HasDigits:boolean; - Mantissa:int64; - MantissaSize,FractionalDigits,FractionalExponent,ExponentSign,Exponent:integer; - ResultCasted:PDoubleCasted; - FloatValue,ExponentFactor:double; - MantissaExponent,PartExponent,Index:integer; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:TFPUExceptionMask; - OldFPURoundingMode,NewFPURoundingMode:TFPURoundingMode; - OldFPUPrecisionMode:TFPUPrecisionMode; -{$endif} -begin - ResultCasted:=pointer(@result); - ResultCasted^.Hi:=$7ff80000; - ResultCasted^.Lo:=$00000000; - i:=1; - while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin - inc(i); - end; - if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin - Negative:=StringValue[i]='-'; - inc(i); - end else begin - Negative:=false; - end; - if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin - if Negative then begin - ResultCasted^.Hi:=$fff00000; - ResultCasted^.Lo:=$00000000; - end else begin - ResultCasted^.Hi:=$7ff00000; - ResultCasted^.Lo:=$00000000; - end; - end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin - ResultCasted^.Hi:=$7ff80000; - ResultCasted^.Lo:=$00000000; - end else begin - FractionalDigits:=0; - FractionalExponent:=0; - MantissaSize:=0; - Mantissa:=0; - HasDigits:=false; - ExponentSign:=1; - Exponent:=0; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0'):begin - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'):begin - if MantissaSize<18 then begin - Mantissa:=(Mantissa*10)+(word(widechar(StringValue[i]))-ord('0')); - end; - inc(MantissaSize); - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - if (i<=length(StringValue)) and (StringValue[i]='.') then begin - inc(i); - if (MantissaSize=0) and (Mantissa=0) then begin - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0'):begin - inc(FractionalExponent); - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - end; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'):begin - if MantissaSize<18 then begin - Mantissa:=(Mantissa*10)+(word(widechar(StringValue[i]))-ord('0')); - inc(MantissaSize); - inc(FractionalDigits); - end; - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - end; - if HasDigits then begin - if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin - inc(i); - if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin - if StringValue[i]='-' then begin - ExponentSign:=-1; - end; - inc(i); - end; - HasDigits:=false; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'):begin - Exponent:=(Exponent*10)+integer(word(widechar(StringValue[i]))-ord('0')); - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - end; - if HasDigits then begin - -{$ifndef BESENNoFPU} - case RoundingMode of - BESEN_ROUND_TO_NEAREST:begin - NewFPURoundingMode:=rmNearest; - end; - BESEN_ROUND_TOWARD_ZERO:begin - NewFPURoundingMode:=rmTruncate; - end; - BESEN_ROUND_UPWARD:begin - NewFPURoundingMode:=rmUp; - end; - BESEN_ROUND_DOWNWARD:begin - NewFPURoundingMode:=rmDown; - end; - else begin - NewFPURoundingMode:=rmNearest; - end; - end; - - OldFPUExceptionMask:=GetExceptionMask; - OldFPURoundingMode:=GetRoundMode; - OldFPUPrecisionMode:=GetPrecisionMode; -{$endif} - try -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(BESENFPUExceptionMask); - end; - if OldFPURoundingMode<>NewFPURoundingMode then begin - SetRoundMode(NewFPURoundingMode); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(BESENFPUPrecisionMode); - end; -{$endif} - - FloatValue:=Mantissa; - - MantissaExponent:=FractionalDigits+FractionalExponent; - if MantissaSize>18 then begin - dec(MantissaExponent,MantissaSize-18); - end; - - if ExponentSign>0 then begin - dec(Exponent,MantissaExponent); - end else begin - inc(Exponent,MantissaExponent); - end; - if Exponent<0 then begin - ExponentSign:=-ExponentSign; - Exponent:=-Exponent; - end; - - while Exponent>0 do begin - PartExponent:=Exponent; - if PartExponent>MaxExponentOfTenMinusTwo then begin - PartExponent:=MaxExponentOfTenMinusTwo; - end; - dec(Exponent,PartExponent); - - Index:=0; - ExponentFactor:=1; - while (PartExponent<>0) and (Index<length(PowersOfTen)) do begin - if (PartExponent and 1)<>0 then begin - ExponentFactor:=ExponentFactor*PowersOfTen[Index]; - end; - inc(Index); - PartExponent:=PartExponent shr 1; - end; - - if ExponentSign>0 then begin - FloatValue:=FloatValue*ExponentFactor; - end else begin - FloatValue:=FloatValue/ExponentFactor; - end; - end; - - ResultCasted^.Value:=FloatValue; - if Negative then begin - ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; - end; - finally -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>BESENFPUExceptionMask then begin - SetExceptionMask(OldFPUExceptionMask); - end; - if OldFPURoundingMode<>NewFPURoundingMode then begin - SetRoundMode(OldFPURoundingMode); - end; - if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin - SetPrecisionMode(OldFPUPrecisionMode); - end; -{$endif} - end; - end; - end; - end; -end; - -function BESENStringToDouble(const StringValue:TBESENString):double; -var OK:longbool; -begin - OK:=false; - result:=BESENStringToDoubleExact(StringValue,BESEN_ROUND_TO_NEAREST,-1,@OK); - if not OK Then begin - result:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end; -end; - -function BESENCheckNumberString(const StringValue:TBESENString;var StartPosition,EndPosition:integer;IsParseFloat,AcceptHex,OnlyNumber,AcceptHexSign:boolean):integer; -var i,OldPosition:integer; - Negative,HasDigits,HasSign:boolean; -begin - result:=BESEN_CHECKNUMBERSTRING_FAIL; - i:=1; - while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin - inc(i); - end; - StartPosition:=i; - EndPosition:=i; - if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin - Negative:=StringValue[i]='-'; - HasSign:=true; - inc(i); - end else begin - Negative:=false; - HasSign:=false; - end; - if i>length(StringValue) then begin - result:=BESEN_CHECKNUMBERSTRING_EMPTY; - end else if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin - EndPosition:=i+7; - if Negative then begin - result:=BESEN_CHECKNUMBERSTRING_INFNEG; - end else begin - result:=BESEN_CHECKNUMBERSTRING_INFPOS; - end; - end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin - EndPosition:=i+2; - result:=BESEN_CHECKNUMBERSTRING_NAN; - end else begin - HasDigits:=false; - if (i<=length(StringValue)) and (StringValue[i]='0') then begin - inc(i); - HasDigits:=true; - if (i<=length(StringValue)) and ((StringValue[i]='x') or (StringValue[i]='X')) then begin - inc(i); - HasDigits:=false; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'),ord('a')..ord('f'),ord('A')..ord('F'):begin - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - if HasDigits then begin - EndPosition:=i-1; - if AcceptHex and (AcceptHexSign or not HasSign) then begin - result:=BESEN_CHECKNUMBERSTRING_VALID; - end else begin - result:=BESEN_CHECKNUMBERSTRING_FAIL; - end; - end; - exit; - end; - end; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'):begin - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - if (i<=length(StringValue)) and (StringValue[i]='.') then begin - inc(i); - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'):begin - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - end; - if HasDigits then begin - OldPosition:=i; - if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin - inc(i); - if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin - inc(i); - end; - HasDigits:=false; - while i<=length(StringValue) do begin - case word(widechar(StringValue[i])) of - ord('0')..ord('9'):begin - HasDigits:=true; - inc(i); - end; - else begin - break; - end; - end; - end; - if IsParseFloat and not HasDigits then begin - i:=OldPosition; - HasDigits:=true; - end; - end; - if HasDigits then begin - EndPosition:=i-1; - if OnlyNumber then begin - while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin - inc(i); - end; - if i>length(StringValue) then begin - result:=BESEN_CHECKNUMBERSTRING_VALID; - end else begin - result:=BESEN_CHECKNUMBERSTRING_FAIL; - end; - end else begin - result:=BESEN_CHECKNUMBERSTRING_VALID; - end; - end; - end; - end; -end; - -function BESENStringToNumber(const StringValue:TBESENString;EmptyIsValid:TBESENBoolean=true;AcceptHex:TBESENBoolean=false;OnlyNumber:boolean=false;AcceptHexSign:boolean=true):TBESENNumber; -var StartPosition,EndPosition:integer; -begin - case BESENCheckNumberString(StringValue,StartPosition,EndPosition,false,AcceptHex,OnlyNumber,AcceptHexSign) of - BESEN_CHECKNUMBERSTRING_EMPTY:begin - if EmptyIsValid then begin - result:=0; - end else begin - result:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end; - end; - BESEN_CHECKNUMBERSTRING_VALID:begin - result:=BESENStringToDouble(copy(StringValue,StartPosition,(EndPosition-StartPosition)+1)); - end; - BESEN_CHECKNUMBERSTRING_INFNEG:begin - result:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); - end; - BESEN_CHECKNUMBERSTRING_INFPOS:begin - result:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end; - else begin - // CHECKNUMBERSTRING_FAIL,CHECKNUMBERSTRING_NAN - result:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end; - end; -end; - -function BESENStringToNumberBase(const StringValue:TBESENString;Base:longint):TBESENNumber; -var OK:longbool; -begin - case Base of - 10:begin - result:=BESENStringToDouble(StringValue); - end; - else begin - OK:=false; - result:=BESENStringToDoubleExact(StringValue,BESEN_ROUND_TO_NEAREST,Base,@OK); - if not OK Then begin - result:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end; - end; - end; -end; - -function BESENSameValue(const A,B:TBESENNumber):boolean; - function min(a,b:TBESENNumber):TBESENNumber; - begin - if a<b then begin - result:=a; - end else begin - result:=b; - end; - end; - function max(a,b:TBESENNumber):TBESENNumber; - begin - if a>b then begin - result:=a; - end else begin - result:=b; - end; - end; -const FuzzFactor=1000; - DoubleResolution=1E-15*FuzzFactor; -var Epsilon:TBESENNumber; -begin - if int64(pointer(@A)^)=int64(pointer(@B)^) then begin - result:=true; - end else begin - Epsilon:=max(min(abs(A),abs(B))*DoubleResolution,DoubleResolution); - if A>B then begin - result:=(A-B)<=Epsilon; - end else begin - result:=(B-A)<=Epsilon; - end; - end; -end; - -function BESENSameNumber(const A,B:TBESENNumber):boolean; - function min(a,b:TBESENNumber):TBESENNumber; - begin - if a<b then begin - result:=a; - end else begin - result:=b; - end; - end; - function max(a,b:TBESENNumber):TBESENNumber; - begin - if a>b then begin - result:=a; - end else begin - result:=b; - end; - end; -const FuzzFactor=1000; - DoubleResolution=1E-15*FuzzFactor; -var Epsilon:TBESENNumber; -begin - if int64(pointer(@A)^)=int64(pointer(@B)^) then begin - result:=true; - end else if BESENIsNaN(A) and BESENIsNaN(B) then begin - result:=true; - end else if (abs(A)=0) and (abs(B)=0) then begin - result:=(int64(pointer(@A)^) shr 63)=(int64(pointer(@B)^) shr 63); - end else begin - Epsilon:=max(min(abs(A),abs(B))*DoubleResolution,DoubleResolution); - if A>B then begin - result:=(A-B)<=Epsilon; - end else begin - result:=(B-A)<=Epsilon; - end; - end; -end; - -function BESENFloor(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} -begin - result:=System.int(FloatValue); - if System.frac(FloatValue)<0 then begin - result:=result-1; - end; -end; - -function BESENCeil(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} -begin - result:=System.int(FloatValue); - if System.frac(FloatValue)>0 then begin - result:=result+1; - end; -end; - -function BESENToInt(v:TBESENNumber):TBESENINT64; -begin - result:=trunc(v); -end; - -function BESENToInt32(v:TBESENNumber):TBESENINT32; -var Sign:longword; -begin - if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin - v:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; - v:=BESENFloor(v); - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; - v:=BESENModulo(System.int(v),4294967296.0); - if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin - v:=v+4294967296.0; - end; - if v>=2147483648.0 then begin - v:=v-4294967296.0; - end; - end; - result:=trunc(v); -end; - -function BESENToUInt32(v:TBESENNumber):TBESENUINT32; -var Sign:longword; -begin - if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin - v:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; - v:=BESENFloor(v); - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; - v:=BESENModulo(System.int(v),4294967296.0); - if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin - v:=v+4294967296.0; - end; - end; - result:=trunc(v); -end; - -function BESENToInt16(v:TBESENNumber):TBESENINT32; -var Sign:longword; -begin - if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin - v:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; - v:=BESENFloor(v); - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; - v:=BESENModulo(System.int(v),65536.0); - if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin - v:=v+65536.0; - end; - if v>=32768.0 then begin - v:=v-65536.0; - end; - end; - result:=trunc(v); -end; - -function BESENToUInt16(v:TBESENNumber):TBESENUINT32; -var Sign:longword; -begin - if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin - v:=0.0; - end else begin - Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; - v:=BESENFloor(v); - PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; - v:=BESENModulo(System.int(v),65536.0); - if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin - v:=v+65536.0; - end; - end; - result:=trunc(v); -end; - -function BESENToIntFast(v:PBESENNumber):TBESENINT64; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -begin - result:=trunc(v^); -end; - -function BESENToInt32Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -begin - if not ((v^>=2147483648.0) and (v^<2147483648.0)) then begin - result:=BESENToInt32(v^); - end else begin - result:=trunc(v^); - end; -end; - -function BESENToUInt32Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -begin - if not ((v^>=0.0) and (v^<4294967296.0)) then begin - result:=BESENToUInt32(v^); - end else begin - result:=int64(trunc(v^)); - end; -end; - -function BESENToInt16Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -begin - if not ((v^>=-32768.0) and (v^<32768.0)) then begin - result:=BESENToInt16(v^); - end else begin - result:=trunc(v^); - end; -end; - -function BESENToUInt16Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} -begin - if not ((v^>=0.0) and (v^<65536.0)) then begin - result:=BESENToUInt16(v^); - end else begin - result:=trunc(v^); - end; -end; - -function BESENIntLog2(x:longword):longword; {$ifdef cpu386}assembler; register; -asm - test eax,eax - jz @Done - bsr eax,eax - @Done: -end; -{$else} -begin - x:=x or (x shr 1); - x:=x or (x shr 2); - x:=x or (x shr 4); - x:=x or (x shr 8); - x:=x or (x shr 16); - x:=x shr 1; - x:=x-((x shr 1) and $55555555); - x:=((x shr 2) and $33333333)+(x and $33333333); - x:=((x shr 4)+x) and $0f0f0f0f; - x:=x+(x shr 8); - x:=x+(x shr 16); - result:=x and $3f; -end; -{$endif} - -{$ifdef cpu64} -function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((PBESENINT64(@AValue)^ and $7ff0000000000000)=$7ff0000000000000) and ((PBESENINT64(@AValue)^ and $000fffffffffffff)<>$0000000000000000); -end; - -function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENINT64(@AValue)^ and $7fffffffffffffff)=$7ff0000000000000; -end; - -function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENINT64(@AValue)^ and $7ff0000000000000)<>$7ff0000000000000; -end; - -function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=PBESENINT64(@AValue)^=int64($7ff0000000000000); -end; - -function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin -{$ifdef fpc} - result:=qword(pointer(@AValue)^)=qword($fff0000000000000); -{$else} - result:=PBESENINT64(@AValue)^=int64($fff0000000000000); -{$endif} -end; - -function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=PBESENINT64(@AValue)^=int64($0000000000000000); -end; - -function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin -{$ifdef fpc} - result:=qword(pointer(@AValue)^)=qword($8000000000000000); -{$else} - result:=PBESENINT64(@AValue)^=int64($8000000000000000); -{$endif} -end; - -function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin -{$ifdef fpc} - result:=(qword(pointer(@AValue)^) and qword($7fffffffffffffff))=qword($0000000000000000); -{$else} - result:=(PBESENINT64(@AValue)^ and int64($7fffffffffffffff))=int64($0000000000000000); -{$endif} -end; - -function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin -{$ifdef fpc} - result:=(qword(pointer(@AValue)^) and qword($8000000000000000))<>0; -{$else} - result:=(PBESENINT64(@AValue)^ shr 63)<>0; -{$endif} -end; -{$else} -{$ifdef TrickyNumberChecks} -function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -var l:longword; -begin - l:=PBESENDoubleHiLo(@AValue)^.Lo; - result:=(longword($7ff00000-longword(longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or ((l or (-l)) shr 31))) shr 31)<>0; -end; - -function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=longword((longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo)=0; -end; - -function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(longword((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff)-$7ff00000) shr 31)<>0; -end; - -function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -var h:longword; -begin - h:=PBESENDoubleHiLo(@AValue)^.Hi; - result:=longword(((longword(h and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(h shr 31))=0; -end; - -function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -var h:longword; -begin - h:=PBESENDoubleHiLo(@AValue)^.Hi; - result:=longword(((longword(h and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(longword(not h) shr 31))=0; -end; - -function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -var h:longword; -begin - h:=PBESENDoubleHiLo(@AValue)^.Hi; - result:=longword(longword(longword(h and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(h shr 31))=0; -end; - -function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -var h:longword; -begin - h:=PBESENDoubleHiLo(@AValue)^.Hi; - result:=longword(longword(longword(h and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(longword(not h) shr 31))=0; -end; - -function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=longword(longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo)=0; -end; - -function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=longword(PBESENDoubleHiLo(@AValue)^.Hi and longword($80000000))<>0; -end; -{$else} -function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7ff00000)=$7ff00000) and (((PBESENDoubleHiLo(@AValue)^.Hi and $000fffff) or PBESENDoubleHiLo(@AValue)^.Lo)<>0); -end; - -function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff)=$7ff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); -end; - -function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENDoubleHiLo(@AValue)^.Hi and $7ff00000)<>$7ff00000; -end; - -function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENDoubleHiLo(@AValue)^.Hi=$7ff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); -end; - -function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENDoubleHiLo(@AValue)^.Hi=$fff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); -end; - -function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENDoubleHiLo(@AValue)^.Hi or PBESENDoubleHiLo(@AValue)^.Lo)=0; -end; - -function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENDoubleHiLo(@AValue)^.Hi=$80000000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); -end; - -function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo)=0; -end; - -function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(PBESENDoubleHiLo(@AValue)^.Hi and $80000000)<>0; -end; -{$endif} -{$endif} - -function BESENNumberAbsolute(const AValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} -begin -{$ifdef cpu64} - PBESENINT64(@result)^:=PBESENINT64(@AValue)^ and $7fffffffffffffff; -{$else} - PBESENDoubleHiLo(@result)^.Hi:=PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff; - PBESENDoubleHiLo(@result)^.Lo:=PBESENDoubleHiLo(@AValue)^.Lo; -{$endif} -end; - -function BESENIsSameValue(const a,b:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} -begin -{$ifdef fpc} - result:=qword(pointer(@a)^)=qword(pointer(@b)^); -{$else} - result:=PBESENINT64(@a)^=PBESENINT64(@b)^; -{$endif} -end; - -function BESENModulo(x,y:double):double;{$ifdef cpu386}stdcall; assembler; -asm - fld qword ptr y - fld qword ptr x - @Repeat: - fprem - fstsw ax - sahf - jp @Repeat - fstp st(1) -end; -{$else} -begin - result:=x-(BESENFloor(x/y)*y); -end; -{$endif} - -function BESENModuloPos(x,y:double):double; -begin - result:=BESENModulo(x,y); - if BESENIsNegative(result) then begin - result:=result+y; - end; -end; - -const BESENDoubleToStringPowerOfTenTable:array[0..86,0..2] of int64=((int64($fa8fd5a0081c0288),-1220,-348), - (int64($baaee17fa23ebf76),-1193,-340), - (int64($8b16fb203055ac76),-1166,-332), - (int64($cf42894a5dce35ea),-1140,-324), - (int64($9a6bb0aa55653b2d),-1113,-316), - (int64($e61acf033d1a45df),-1087,-308), - (int64($ab70fe17c79ac6ca),-1060,-300), - (int64($ff77b1fcbebcdc4f),-1034,-292), - (int64($be5691ef416bd60c),-1007,-284), - (int64($8dd01fad907ffc3c),-980,-276), - (int64($d3515c2831559a83),-954,-268), - (int64($9d71ac8fada6c9b5),-927,-260), - (int64($ea9c227723ee8bcb),-901,-252), - (int64($aecc49914078536d),-874,-244), - (int64($823c12795db6ce57),-847,-236), - (int64($c21094364dfb5637),-821,-228), - (int64($9096ea6f3848984f),-794,-220), - (int64($d77485cb25823ac7),-768,-212), - (int64($a086cfcd97bf97f4),-741,-204), - (int64($ef340a98172aace5),-715,-196), - (int64($b23867fb2a35b28e),-688,-188), - (int64($84c8d4dfd2c63f3b),-661,-180), - (int64($c5dd44271ad3cdba),-635,-172), - (int64($936b9fcebb25c996),-608,-164), - (int64($dbac6c247d62a584),-582,-156), - (int64($a3ab66580d5fdaf6),-555,-148), - (int64($f3e2f893dec3f126),-529,-140), - (int64($b5b5ada8aaff80b8),-502,-132), - (int64($87625f056c7c4a8b),-475,-124), - (int64($c9bcff6034c13053),-449,-116), - (int64($964e858c91ba2655),-422,-108), - (int64($dff9772470297ebd),-396,-100), - (int64($a6dfbd9fb8e5b88f),-369,-92), - (int64($f8a95fcf88747d94),-343,-84), - (int64($b94470938fa89bcf),-316,-76), - (int64($8a08f0f8bf0f156b),-289,-68), - (int64($cdb02555653131b6),-263,-60), - (int64($993fe2c6d07b7fac),-236,-52), - (int64($e45c10c42a2b3b06),-210,-44), - (int64($aa242499697392d3),-183,-36), - (int64($fd87b5f28300ca0e),-157,-28), - (int64($bce5086492111aeb),-130,-20), - (int64($8cbccc096f5088cc),-103,-12), - (int64($d1b71758e219652c),-77,-4), - (int64($9c40000000000000),-50,4), - (int64($e8d4a51000000000),-24,12), - (int64($ad78ebc5ac620000),3,20), - (int64($813f3978f8940984),30,28), - (int64($c097ce7bc90715b3),56,36), - (int64($8f7e32ce7bea5c70),83,44), - (int64($d5d238a4abe98068),109,52), - (int64($9f4f2726179a2245),136,60), - (int64($ed63a231d4c4fb27),162,68), - (int64($b0de65388cc8ada8),189,76), - (int64($83c7088e1aab65db),216,84), - (int64($c45d1df942711d9a),242,92), - (int64($924d692ca61be758),269,100), - (int64($da01ee641a708dea),295,108), - (int64($a26da3999aef774a),322,116), - (int64($f209787bb47d6b85),348,124), - (int64($b454e4a179dd1877),375,132), - (int64($865b86925b9bc5c2),402,140), - (int64($c83553c5c8965d3d),428,148), - (int64($952ab45cfa97a0b3),455,156), - (int64($de469fbd99a05fe3),481,164), - (int64($a59bc234db398c25),508,172), - (int64($f6c69a72a3989f5c),534,180), - (int64($b7dcbf5354e9bece),561,188), - (int64($88fcf317f22241e2),588,196), - (int64($cc20ce9bd35c78a5),614,204), - (int64($98165af37b2153df),641,212), - (int64($e2a0b5dc971f303a),667,220), - (int64($a8d9d1535ce3b396),694,228), - (int64($fb9b7cd9a4a7443c),720,236), - (int64($bb764c4ca7a44410),747,244), - (int64($8bab8eefb6409c1a),774,252), - (int64($d01fef10a657842c),800,260), - (int64($9b10a4e5e9913129),827,268), - (int64($e7109bfba19c0c9d),853,276), - (int64($ac2820d9623bf429),880,284), - (int64($80444b5e7aa7cf85),907,292), - (int64($bf21e44003acdd2d),933,300), - (int64($8e679c2f5e44ff8f),960,308), - (int64($d433179d9c8cb841),986,316), - (int64($9e19db92b4e31ba9),1013,324), - (int64($eb96bf6ebadf77d9),1039,332), - (int64($af87023b9bf0ee6b),1066,340)); - - BESENDoubleToStringPowerOfTenBinaryExponentTable:array[-1220..(1066+27)-1] of byte=(0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, - 11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15, - 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24, - 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25, - 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, - 25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26, - 26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26, - 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27, - 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28, - 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29, - 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, - 29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30, - 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,31, - 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, - 31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32, - 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, - 32,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33, - 33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,34, - 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, - 34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35, - 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, - 35,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37, - 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, - 37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38, - 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, - 38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,40,40, - 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, - 40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41, - 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, - 41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42, - 42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,43, - 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, - 43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44, - 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, - 44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45, - 45,45,45,45,45,45,45,45,45,45,45,45,45,46,46,46, - 46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, - 46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47, - 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, - 47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48, - 48,48,48,48,48,48,48,48,48,48,48,48,48,49,49,49, - 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, - 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50, - 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, - 50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51, - 51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52, - 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, - 52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53, - 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, - 53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54, - 54,54,54,54,54,54,54,54,54,54,54,54,54,55,55,55, - 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, - 55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56, - 56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, - 56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57, - 57,57,57,57,57,57,57,57,57,57,57,57,58,58,58,58, - 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58, - 58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59, - 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, - 59,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, - 60,60,60,60,60,60,60,60,60,60,60,60,61,61,61,61, - 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, - 61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62, - 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, - 62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, - 63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64, - 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, - 64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65, - 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, - 65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, - 66,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67, - 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, - 67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,68, - 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, - 68,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, - 69,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70, - 70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, - 70,70,70,70,70,70,71,71,71,71,71,71,71,71,71,71, - 71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, - 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, - 72,72,72,72,72,72,72,72,72,72,72,73,73,73,73,73, - 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, - 73,73,73,73,73,74,74,74,74,74,74,74,74,74,74,74, - 74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, - 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, - 75,75,75,75,75,75,75,75,75,75,75,76,76,76,76,76, - 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, - 76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77, - 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, - 78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, - 78,78,78,78,78,78,78,78,78,78,79,79,79,79,79,79, - 79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, - 79,79,79,79,79,80,80,80,80,80,80,80,80,80,80,80, - 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, - 81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, - 81,81,81,81,81,81,81,81,81,81,82,82,82,82,82,82, - 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, - 82,82,82,82,82,83,83,83,83,83,83,83,83,83,83,83, - 83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,84, - 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, - 84,84,84,84,84,84,84,84,84,84,85,85,85,85,85,85, - 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, - 85,85,85,85,86,86,86,86,86,86,86,86,86,86,86,86, - 86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, - 86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, - 86,86,86,86,86,86,86,86,86); - - BESENDoubleToStringPowerOfTenDecimalExponentTable:array[-348..(340+8)-1] of byte=(0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2, - 2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4, - 4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6, - 6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8, - 8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10, - 10,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12, - 12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14, - 14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16, - 16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18, - 18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20, - 20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22, - 22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24, - 24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26, - 26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28, - 28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30, - 30,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32, - 32,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34, - 34,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36, - 36,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38, - 38,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40, - 40,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42, - 42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44, - 44,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46, - 46,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48, - 48,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50, - 50,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52, - 52,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54, - 54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56, - 56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58, - 58,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60, - 60,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62, - 62,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64, - 64,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66, - 66,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68, - 68,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70, - 70,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72, - 72,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74, - 74,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76, - 76,77,77,77,77,77,77,77,77,78,78,78,78,78,78,78, - 78,79,79,79,79,79,79,79,79,80,80,80,80,80,80,80, - 80,81,81,81,81,81,81,81,81,82,82,82,82,82,82,82, - 82,83,83,83,83,83,83,83,83,84,84,84,84,84,84,84, - 84,85,85,85,85,85,85,85,85,86,86,86,86,86,86,86, - 86,86,86,86,86,86,86,86); - - BESENDoubleToStringEstimatePowerFactorTable:array[2..36] of int64=(4294967296, // round((ln(2)/ln(Radix))*4294967296.0); - 2709822658, - 2147483648, - 1849741732, - 1661520155, - 1529898219, - 1431655765, - 1354911329, - 1292913986, - 1241523975, - 1198050829, - 1160664035, - 1128071163, - 1099331346, - 1073741824, - 1050766077, - 1029986701, - 1011073584, - 993761859, - 977836272, - 963119891, - 949465783, - 936750801, - 924870866, - 913737342, - 903274219, - 893415894, - 884105413, - 875293062, - 866935226, - 858993459, - 851433729, - 844225782, - 837342623, - 830760078); - -function BESENDoubleToString(const AValue:double;Mode,RequestedDigits:longint):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; -{$ifndef fpc} -type qword=int64; -{$endif} -const SignificantMantissaSize=64; - MinimalTargetExponent=-60; - MaximalTargetExponent=-32; - mSHORTEST=0; - mFIXED=1; - mPRECISION=2; - BigNumMaxSignificantMantissaBits=3584; - BigitChunkSize=32; - BigitDoubleChunkSize=64; - BigitSize=28; - BigitMask=(1 shl BigitSize)-1; - BigNumCapacity=(BigNumMaxSignificantMantissaBits+(BigitSize-1)) div BigitSize; -{$ifdef BESENSingleStringType} - DigitChars:array[0..9] of char=('0','1','2','3','4','5','6','7','8','9'); -{$endif} -type TDoubleValue=record - SignificantMantissa:qword; - Exponent:longint; - end; - TBigNumChunk=longword; - TBigNumDoubleChunk=qword; - TBigNum=record - Bigits:array[0..BigNumCapacity] of TBigNumChunk; - UsedDigits:longint; - Exponent:longint; - end; - function QWordLessOrEqual(a,b:qword):boolean; - begin - result:=(a=b) or (((a shr 32)<(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)<(b and $ffffffff)))); - end; - function QWordGreaterOrEqual(a,b:qword):boolean; - begin - result:=(a=b) or (((a shr 32)>(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)>(b and $ffffffff)))); - end; - function QWordLess(a,b:qword):boolean; - begin - result:=((a shr 32)<(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)<(b and $ffffffff))); - end; - function QWordGreater(a,b:qword):boolean; - begin - result:=((a shr 32)>(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)>(b and $ffffffff))); - end; - function DoubleValue(SignificantMantissa:qword=0;Exponent:longint=0):TDoubleValue; - begin - result.SignificantMantissa:=SignificantMantissa; - result.Exponent:=Exponent; - end; - procedure SplitDouble(Value:double;var SignificantMantissa:qword;var Exponent:longint); - var Casted:qword absolute Value; - begin - SignificantMantissa:=Casted and qword($000fffffffffffff); - if (Casted and qword($7ff0000000000000))<>0 then begin - inc(SignificantMantissa,qword($0010000000000000)); - Exponent:=((Casted and qword($7ff0000000000000)) shr 52)-($3ff+52); - end else begin - Exponent:=(-($3ff+52))+1; - end; - end; - function DoubleValueGet(Value:double):TDoubleValue; - var SignificantMantissa:qword; - Exponent:longint; - begin - Assert(Value>0); - SplitDouble(Value,SignificantMantissa,Exponent); - while (SignificantMantissa and qword($0010000000000000))=0 do begin - SignificantMantissa:=SignificantMantissa shl 1; - dec(Exponent); - end; - SignificantMantissa:=SignificantMantissa shl (SignificantMantissaSize-53); - dec(Exponent,SignificantMantissaSize-53); - result.SignificantMantissa:=SignificantMantissa; - result.Exponent:=Exponent; - end; - procedure DoubleValueSubtract(var Left:TDoubleValue;const Right:TDoubleValue); - begin - Assert(Left.Exponent=Right.Exponent); - Assert(QWordGreaterOrEqual(Left.SignificantMantissa,Right.SignificantMantissa)); - dec(Left.SignificantMantissa,Right.SignificantMantissa); - end; - function DoubleValueMinus(const Left,Right:TDoubleValue):TDoubleValue; - begin - Assert(Left.Exponent=Right.Exponent); - Assert(QWordGreaterOrEqual(Left.SignificantMantissa,Right.SignificantMantissa)); - result.Exponent:=Left.Exponent; - result.SignificantMantissa:=Left.SignificantMantissa-Right.SignificantMantissa; - end; - procedure DoubleValueMuliply(var Left:TDoubleValue;const Right:TDoubleValue); - var a,b,c,d,ac,bc,ad,bd:qword; - begin - a:=Left.SignificantMantissa shr 32; - b:=Left.SignificantMantissa and $ffffffff; - c:=Right.SignificantMantissa shr 32; - d:=Right.SignificantMantissa and $ffffffff; - ac:=a*c; - bc:=b*c; - ad:=a*d; - bd:=b*d; - inc(Left.Exponent,Right.Exponent+64); - Left.SignificantMantissa:=ac+(ad shr 32)+(bc shr 32)+(qword(((bd shr 32)+((ad and $ffffffff)+(bc and $ffffffff)))+(qword(1) shl 31)) shr 32); - end; - function DoubleValueMul(const Left,Right:TDoubleValue):TDoubleValue; - var a,b,c,d,ac,bc,ad,bd:qword; - begin - a:=Left.SignificantMantissa shr 32; - b:=Left.SignificantMantissa and $ffffffff; - c:=Right.SignificantMantissa shr 32; - d:=Right.SignificantMantissa and $ffffffff; - ac:=a*c; - bc:=b*c; - ad:=a*d; - bd:=b*d; - result.Exponent:=Left.Exponent+(Right.Exponent+64); - a:=((bd shr 32)+((ad and $ffffffff)+(bc and $ffffffff)))+(qword(1) shl 31); - result.SignificantMantissa:=ac+(ad shr 32)+(bc shr 32)+(a shr 32); - end; - procedure DoubleValueNormalize(var Value:TDoubleValue); - var SignificantMantissa:qword; - Exponent:longint; - begin - Assert(Value.SignificantMantissa<>0); - SignificantMantissa:=Value.SignificantMantissa; - Exponent:=Value.Exponent; - while (SignificantMantissa and qword($ffc0000000000000))=0 do begin - SignificantMantissa:=SignificantMantissa shl 10; - dec(Exponent,10); - end; - while (SignificantMantissa and qword($8000000000000000))=0 do begin - SignificantMantissa:=SignificantMantissa shl 1; - dec(Exponent); - end; - Value.SignificantMantissa:=SignificantMantissa; - Value.Exponent:=Exponent; - end; - function DoubleValueNorm(const Value:TDoubleValue):TDoubleValue; - var SignificantMantissa:qword; - Exponent:longint; - begin - Assert(Value.SignificantMantissa<>0); - SignificantMantissa:=Value.SignificantMantissa; - Exponent:=Value.Exponent; - while (SignificantMantissa and qword($ffc0000000000000))=0 do begin - SignificantMantissa:=SignificantMantissa shl 10; - dec(Exponent,10); - end; - while (SignificantMantissa and qword($8000000000000000))=0 do begin - SignificantMantissa:=SignificantMantissa shl 1; - dec(Exponent); - end; - result.SignificantMantissa:=SignificantMantissa; - result.Exponent:=Exponent; - end; - function BigNumNew:TBigNum; - begin - FillChar(result,sizeof(TBigNum),#0); - end; - procedure BigNumZero(var BigNum:TBigNum); - begin - BigNum.UsedDigits:=0; - BigNum.Exponent:=0; - end; - procedure BigNumEnsureCapacity(var BigNum:TBigNum;Size:longint); - begin - end; - procedure BigNumClamp(var BigNum:TBigNum); - begin - while (BigNum.UsedDigits>0) and (BigNum.Bigits[BigNum.UsedDigits-1]=0) do begin - dec(BigNum.UsedDigits); - end; - if BigNum.UsedDigits=0 then begin - BigNum.Exponent:=0; - end; - end; - function BigNumIsClamped(const BigNum:TBigNum):boolean; - begin - result:=(BigNum.UsedDigits=0) or (BigNum.Bigits[BigNum.UsedDigits-1]<>0); - end; - procedure BigNumAlign(var BigNum:TBigNum;const Other:TBigNum); - var ZeroDigits,i:longint; - begin - if BigNum.Exponent>Other.Exponent then begin - ZeroDigits:=BigNum.Exponent-Other.Exponent; - BigNumEnsureCapacity(BigNum,Bignum.UsedDigits+ZeroDigits); - for i:=BigNum.UsedDigits-1 downto 0 do begin - BigNum.Bigits[i+ZeroDigits]:=BigNum.Bigits[i]; - end; - for i:=0 to ZeroDigits-1 do begin - BigNum.Bigits[i]:=0; - end; - inc(BigNum.UsedDigits,ZeroDigits); - dec(BigNum.Exponent,ZeroDigits); - Assert(BigNum.UsedDigits>=0); - Assert(BigNum.Exponent>=0); - end; - end; - procedure BigNumAssignUInt16(var BigNum:TBigNum;Value:word); - begin - Assert(BigitSize>=(sizeof(word)*8)); - BigNumZero(BigNum); - if Value<>0 then begin - BigNumEnsureCapacity(BigNum,1); - BigNum.Bigits[0]:=Value; - BigNum.UsedDigits:=1; - end; - end; - procedure BigNumAssignUInt64(var BigNum:TBigNum;Value:qword); - var i,j:longint; - begin - BigNumZero(BigNum); - if Value<>0 then begin - j:=(64 div BigitSize)+1; - BigNumEnsureCapacity(BigNum,j); - for i:=0 to j-1 do begin - BigNum.Bigits[i]:=Value and BigitMask; - Value:=Value shr BigitSize; - end; - BigNum.UsedDigits:=j; - BigNumClamp(BigNum); - end; - end; - procedure BigNumAssignBigNum(var BigNum:TBigNum;const Other:TBigNum); - begin - BigNum.Exponent:=Other.Exponent; - BigNum.Bigits:=Other.Bigits; - BigNum.UsedDigits:=Other.UsedDigits; - end; - procedure BigNumAddBigNum(var BigNum:TBigNum;const Other:TBigNum); - var Carry,Sum:TBigNumChunk; - BigitPos,i:longint; - begin - Assert(BigNumIsClamped(BigNum)); - Assert(BigNumIsClamped(Other)); - BigNumAlign(BigNum,Other); - BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+Other.UsedDigits); - BigitPos:=Other.Exponent-BigNum.Exponent; - Assert(BigitPos>=0); - Carry:=0; - for i:=0 to Other.UsedDigits-1 do begin - Sum:=BigNum.Bigits[BigitPos]+Other.Bigits[i]+Carry; - BigNum.Bigits[BigitPos]:=Sum and BigitMask; - Carry:=Sum shr BigitSize; - inc(BigitPos); - end; - while Carry<>0 do begin - Sum:=BigNum.Bigits[BigitPos]+Carry; - BigNum.Bigits[BigitPos]:=Sum and BigitMask; - Carry:=Sum shr BigitSize; - inc(BigitPos); - end; - if BigNum.UsedDigits<BigitPos then begin - BigNum.UsedDigits:=BigitPos; - end; - Assert(BigNumIsClamped(BigNum)); - end; - procedure BigNumAddUInt64(var BigNum:TBigNum;const Value:qword); - var Other:TBigNum; - begin - Other:=BigNumNew; - BigNumAssignUInt64(Other,Value); - BigNumAddBigNum(BigNum,Other); - end; - function BigNumBigitAt(const BigNum:TBigNum;Index:longint):TBigNumChunk; - begin - if (Index<BigNum.Exponent) or (Index>=(BigNum.UsedDigits+BigNum.Exponent)) then begin - result:=0; - end else begin - result:=BigNum.Bigits[Index-BigNum.Exponent]; - end; - end; - function BigNumCompare(const a,b:TBigNum):longint; - var la,lb,i,j:longint; - ba,bb:TBigNumChunk; - begin - Assert(BigNumIsClamped(a)); - Assert(BigNumIsClamped(b)); - la:=a.UsedDigits+a.Exponent; - lb:=b.UsedDigits+b.Exponent; - if la<lb then begin - result:=-1; - end else if la>lb then begin - result:=1; - end else begin - if a.Exponent<b.Exponent then begin - j:=a.Exponent; - end else begin - j:=b.Exponent; - end; - result:=0; - for i:=la-1 downto j do begin - ba:=BigNumBigItAt(a,i); - bb:=BigNumBigItAt(b,i); - if ba<bb then begin - result:=-1; - break; - end else if ba>bb then begin - result:=1; - break; - end; - end; - end; - end; - function BigNumPlusCompare(const a,b,c:TBigNum):longint; - var la,lb,lc,i,j:longint; - ba,bb,bc,br,Sum:TBigNumChunk; - begin - Assert(BigNumIsClamped(a)); - Assert(BigNumIsClamped(b)); - Assert(BigNumIsClamped(c)); - la:=a.UsedDigits+a.Exponent; - lb:=b.UsedDigits+b.Exponent; - lc:=c.UsedDigits+c.Exponent; - if la<lb then begin - result:=BigNumPlusCompare(b,a,c); - end else begin - if (la+1)<lc then begin - result:=-1; - end else if la>lc then begin - result:=1; - end else if (a.Exponent>=lb) and (la<lc) then begin - result:=-1; - end else begin - if a.Exponent<b.Exponent then begin - if a.Exponent<c.Exponent then begin - j:=a.Exponent; - end else begin - j:=c.Exponent; - end; - end else begin - if b.Exponent<c.Exponent then begin - j:=b.Exponent; - end else begin - j:=c.Exponent; - end; - end; - br:=0; - for i:=lc-1 downto j do begin - ba:=BigNumBigItAt(a,i); - bb:=BigNumBigItAt(b,i); - bc:=BigNumBigItAt(c,i); - Sum:=ba+bb; - if Sum>(bc+br) then begin - result:=1; - exit; - end else begin - br:=(bc+br)-Sum; - if br>1 then begin - result:=-1; - exit; - end; - br:=br shl BigitSize; - end; - end; - if br=0 then begin - result:=0; - end else begin - result:=-1; - end; - end; - end; - end; - procedure BigNumSubtractBigNum(var BigNum:TBigNum;const Other:TBigNum); - var Borrow,Difference:TBigNumChunk; - i,Offset:longint; - begin - Assert(BigNumIsClamped(BigNum)); - Assert(BigNumIsClamped(Other)); - Assert(BigNumCompare(Other,BigNum)<=0); - BigNumAlign(BigNum,Other); - Offset:=Other.Exponent-BigNum.Exponent; - Borrow:=0; - for i:=0 to Other.UsedDigits-1 do begin - Assert((Borrow=0) or (Borrow=1)); - Difference:=(BigNum.Bigits[i+Offset]-Other.Bigits[i])-Borrow; - BigNum.Bigits[i+Offset]:=Difference and BigitMask; - Borrow:=Difference shr (BigitChunkSize-1); - end; - i:=Other.UsedDigits; - while Borrow<>0 do begin - Difference:=BigNum.Bigits[i+Offset]-Borrow; - BigNum.Bigits[i+Offset]:=Difference and BigitMask; - Borrow:=Difference shr (BigitChunkSize-1); - inc(i); - end; - BigNumClamp(BigNum); - end; - procedure BigNumBigitsShiftLeft(var BigNum:TBigNum;Shift:longint); - var Carry,NextCarry:TBigNumChunk; - i:longint; - begin - Assert(Shift<BigitSize); - Assert(Shift>=0); - Carry:=0; - for i:=0 to BigNum.UsedDigits-1 do begin - NextCarry:=BigNum.Bigits[i] shr (BigitSize-Shift); - BigNum.Bigits[i]:=((BigNum.Bigits[i] shl Shift)+Carry) and BigitMask; - Carry:=NextCarry; - end; - if Carry<>0 then begin - BigNum.Bigits[BigNum.UsedDigits]:=Carry; - inc(BigNum.UsedDigits); - end; - end; - procedure BigNumBigitsShiftRight(var BigNum:TBigNum;Shift:longint); - var Carry,NextCarry:TBigNumChunk; - i:longint; - begin - Assert(Shift<BigitSize); - Assert(Shift>=0); - if BigNum.UsedDigits>0 then begin - Carry:=0; - for i:=BigNum.UsedDigits-1 downto 1 do begin - NextCarry:=BigNum.Bigits[i] shl (BigitSize-Shift); - BigNum.Bigits[i]:=((BigNum.Bigits[i] shr Shift)+Carry) and BigitMask; - Carry:=NextCarry; - end; - BigNum.Bigits[0]:=(BigNum.Bigits[0] shr Shift)+Carry; - end; - BigNumClamp(BigNum); - end; - procedure BignumSubtractTimes(var BigNum:TBigNum;const Other:TBigNum;Factor:longint); - var i,ExponentDiff:longint; - Borrow,Difference:TBigNumChunk; - Product,Remove:TBigNumDoubleChunk; - begin - Assert(BigNum.Exponent<=Other.Exponent); - if Factor<3 then begin - for i:=1 to Factor do begin - BigNumSubtractBignum(BigNum,Other); - end; - end else begin - Borrow:=0; - ExponentDiff:=Other.Exponent-BigNum.Exponent; - for i:=0 to Other.UsedDigits-1 do begin - Product:=TBigNumDoubleChunk(Factor)*Other.Bigits[i]; - Remove:=Borrow+Product; - Difference:=BigNum.Bigits[i+ExponentDiff]-TBigNumChunk(Remove and BigitMask); - BigNum.Bigits[i+ExponentDiff]:=Difference and BigitMask; - Borrow:=TBigNumChunk((Difference shr (BigitChunkSize-1))+(Remove shr BigitSize)); - end; - for i:=Other.UsedDigits+ExponentDiff to BigNum.UsedDigits-1 do begin - if Borrow=0 then begin - exit; - end; - Difference:=BigNum.Bigits[i]-Borrow; - BigNum.Bigits[i]:=Difference and BigitMask; - Borrow:=TBigNumChunk(Difference shr (BigitChunkSize-1)); - end; - BigNumClamp(BigNum); - end; - end; - procedure BigNumShiftLeft(var BigNum:TBigNum;Shift:longint); - begin - if BigNum.UsedDigits<>0 then begin - inc(BigNum.Exponent,Shift div BigitSize); - BignumEnsureCapacity(BigNum,BigNum.UsedDigits+1); - BigNumBigitsShiftLeft(BigNum,Shift mod BigitSize); - end; - end; - procedure BigNumShiftRight(var BigNum:TBigNum;Shift:longint); - begin - if BigNum.UsedDigits<>0 then begin - dec(BigNum.Exponent,Shift div BigitSize); - BignumEnsureCapacity(BigNum,BigNum.UsedDigits); - BigNumBigitsShiftRight(BigNum,Shift mod BigitSize); - end; - end; - procedure BigNumMultiplyByUInt32(var BigNum:TBigNum;Factor:word); - var Carry,Product:qword; - i:longint; - begin - if Factor=0 then begin - BigNumZero(BigNum); - end else if Factor<>1 then begin - Assert(BigitSize<32); - Carry:=0; - for i:=0 to BigNum.UsedDigits-1 do begin - Product:=(Factor*BigNum.Bigits[i])+Carry; - BigNum.Bigits[i]:=Product and BigitMask; - Carry:=Product shr BigitSize; - end; - while Carry<>0 do begin - BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+1); - BigNum.Bigits[BigNum.UsedDigits]:=Carry and BigitMask; - inc(BigNum.UsedDigits); - Carry:=Carry shr BigitSize; - end; - end; - end; - procedure BigNumMultiplyByUInt64(var BigNum:TBigNum;Factor:qword); - var Carry,Low,High,ProductLow,ProductHigh,Tmp:qword; - i:longint; - begin - if Factor=0 then begin - BigNumZero(BigNum); - end else if Factor<>1 then begin - Assert(BigitSize<32); - Carry:=0; - Low:=Factor and $ffffffff; - High:=Factor shr 32; - for i:=0 to BigNum.UsedDigits-1 do begin - ProductLow:=Low*BigNum.Bigits[i]; - ProductHigh:=High*BigNum.Bigits[i]; - Tmp:=(Carry and BigitMask)+ProductLow; - BigNum.Bigits[i]:=Tmp and BigitMask; - Carry:=(Carry shr BigitSize)+(Tmp shr BigitSize)+(ProductHigh shl (32-BigitSize)); - end; - while Carry<>0 do begin - BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+1); - BigNum.Bigits[BigNum.UsedDigits]:=Carry and BigitMask; - inc(BigNum.UsedDigits); - Carry:=Carry shr BigitSize; - end; - end; - end; - procedure BigNumSquare(var BigNum:TBigNum); - var ProductLength,CopyOffset,i,BigitIndex1,BigitIndex2:longint; - Accumulator:TBigNumDoubleChunk; - Chunk1,Chunk2:TBigNumChunk; - begin - Assert(BigNumIsClamped(BigNum)); - ProductLength:=2*BigNum.UsedDigits; - BigNumEnsureCapacity(BigNum,ProductLength); - Assert(not ((1 shl (2*(BigItChunkSize-BigitSize)))<=BigNum.UsedDigits)); - Accumulator:=0; - CopyOffset:=BigNum.UsedDigits; - for i:=0 to BigNum.UsedDigits-1 do begin - BigNum.Bigits[i+CopyOffset]:=BigNum.Bigits[i]; - end; - for i:=0 to BigNum.UsedDigits-1 do begin - BigitIndex1:=i; - BigitIndex2:=0; - while BigitIndex1>=0 do begin - Chunk1:=BigNum.Bigits[CopyOffset+BigitIndex1]; - Chunk2:=BigNum.Bigits[CopyOffset+BigitIndex2]; - inc(Accumulator,TBigNumDoubleChunk(Chunk1)*Chunk2); - dec(BigitIndex1); - inc(BigitIndex2); - end; - BigNum.Bigits[i]:=Accumulator and BigitMask; - Accumulator:=Accumulator shr BigitSize; - end; - for i:=BigNum.UsedDigits-1 to ProductLength-1 do begin - BigitIndex1:=BigNum.UsedDigits-1; - BigitIndex2:=i-BigitIndex1; - while BigitIndex2<BigNum.UsedDigits do begin - Chunk1:=BigNum.Bigits[CopyOffset+BigitIndex1]; - Chunk2:=BigNum.Bigits[CopyOffset+BigitIndex2]; - inc(Accumulator,TBigNumDoubleChunk(Chunk1)*Chunk2); - dec(BigitIndex1); - inc(BigitIndex2); - end; - BigNum.Bigits[i]:=Accumulator and BigitMask; - Accumulator:=Accumulator shr BigitSize; - end; - Assert(Accumulator=0); - BigNum.UsedDigits:=ProductLength; - inc(BigNum.Exponent,BigNum.Exponent); - BigNumClamp(BigNum); - end; - procedure BigNumAssignPowerUInt16(var BigNum:TBigNum;Base:word;PowerExponent:longint); - var Shifts,BitSize,TmpBase,FinalSize,Mask:longint; - ThisValue:qword; - DelayedMultipliciation:boolean; - begin - Assert(Base<>0); - Assert(PowerExponent>=0); - if PowerExponent=0 then begin - BigNumAssignUInt16(BigNum,1); - end else begin - BigNumZero(BigNum); - Shifts:=0; - while (Base and 1)=0 do begin - Base:=Base shr 1; - inc(Shifts); - end; - BitSize:=0; - TmpBase:=Base; - while TmpBase<>0 do begin - TmpBase:=TmpBase shr 1; - inc(BitSize); - end; - FinalSize:=BitSize*PowerExponent; - BigNumEnsureCapacity(BigNum,FinalSize); - Mask:=1; - while Mask<=PowerExponent do begin - inc(Mask,Mask); - end; - Mask:=Mask shr 2; - ThisValue:=Base; - DelayedMultipliciation:=false; - while (Mask<>0) and (ThisValue<=$ffffffff) do begin - ThisValue:=ThisValue*ThisValue; - if (PowerExponent and Mask)<>0 then begin - if (ThisValue and not ((qword(1) shl (64-BitSize))-1))=0 then begin - ThisValue:=ThisValue*Base; - end else begin - DelayedMultipliciation:=true; - end; - end; - Mask:=Mask shr 1; - end; - BigNumAssignUInt64(BigNum,ThisValue); - if DelayedMultipliciation then begin - BigNumMultiplyByUInt32(BigNum,Base); - end; - while Mask<>0 do begin - BigNumSquare(BigNum); - if (PowerExponent and Mask)<>0 then begin - BigNumMultiplyByUInt32(BigNum,Base); - end; - Mask:=Mask shr 1; - end; - BigNumShiftLeft(BigNum,Shifts*PowerExponent); - end; - end; - function BigNumDivideModuloIntBigNum(var BigNum:TBigNum;const Other:TBigNum):word; - var ThisBigit,OtherBigit:TBigNumChunk; - Quotient,DivisionEstimate:longword; - begin - Assert(BigNumIsClamped(BigNum)); - Assert(BigNumIsClamped(Other)); - Assert(Other.UsedDigits>0); - result:=0; - if (BigNum.UsedDigits+BigNum.Exponent)>=(Other.UsedDigits+Other.Exponent) then begin - BigNumAlign(BigNum,Other); - while (BigNum.UsedDigits+BigNum.Exponent)>(Other.UsedDigits+Other.Exponent) do begin - Assert(Other.Bigits[Other.UsedDigits-1]>=((1 shl BigitSize) div 16)); - inc(result,BigNum.Bigits[BigNum.UsedDigits-1]); - BigNumSubtractTimes(BigNum,Other,BigNum.Bigits[BigNum.UsedDigits-1]); - end; - Assert((BigNum.UsedDigits+BigNum.Exponent)=(Other.UsedDigits+Other.Exponent)); - ThisBigit:=BigNum.Bigits[BigNum.UsedDigits-1]; - OtherBigit:=Other.Bigits[Other.UsedDigits-1]; - if Other.UsedDigits=1 then begin - Quotient:=ThisBigit div OtherBigit; - BigNum.Bigits[BigNum.UsedDigits-1]:=ThisBigit-(OtherBigit*Quotient); - inc(result,Quotient); - BigNumClamp(BigNum); - end else begin - DivisionEstimate:=ThisBigit div (OtherBigit+1); - inc(result,DivisionEstimate); - BigNumSubtractTimes(BigNum,Other,DivisionEstimate); - if (OtherBigit*(DivisionEstimate+1))<=ThisBigit then begin - while BigNumCompare(Other,BigNum)<=0 do begin - BigNumSubtractBigNum(BigNum,Other); - inc(result); - end; - end; - end; - end; - end; - function BigNumDivideModuloInt(var BigNum:TBigNum;Divisor:word):word; - var q0,r0,q1,r1:qword; - i:integer; - begin - Assert(BigNumIsClamped(BigNum)); - q0:=0; - for i:=BigNum.UsedDigits-1 downto 1 do begin - q1:=(BigNum.Bigits[i] div Divisor)+q0; - r1:=((BigNum.Bigits[i] mod Divisor) shl 16)+(BigNum.Bigits[i-1] shr 16); - q0:=((r1 div Divisor) shl 16); - r0:=r1 mod Divisor; - BigNum.Bigits[i]:=q1; - BigNum.Bigits[i-1]:=(r0 shl 16)+(BigNum.Bigits[i-1] and $ffff); - end; - q1:=(BigNum.Bigits[0] div Divisor)+q0; - r1:=BigNum.Bigits[0] mod Divisor; - BigNum.Bigits[0]:=q1; - result:=r1; - BigNumClamp(BigNum); - end; - function NormalizedExponent(SignificantMantissa:qword;Exponent:longint):longint; - begin - Assert(SignificantMantissa<>0); - while (SignificantMantissa and qword($0010000000000000))=0 do begin - SignificantMantissa:=SignificantMantissa shl 1; - dec(Exponent); - end; - result:=Exponent; - end; - function GetEstimatePower(Exponent:longint):longint; - begin - result:=longint(int64(((Exponent+52)*int64(1292913986))-$1000) shr 32)+1; // result:=System.Trunc(Math.Ceil(((Exponent+52)*0.30102999566398114)-(1e-10))); - end; - function GetEstimatePowerOf(Exponent,Radix:longint):longint; - begin - result:=longint(int64(((Exponent+52)*BESENDoubleToStringEstimatePowerFactorTable[Radix])-$1000) shr 32)+1; // result:=System.Trunc(Math.Ceil(((Exponent+52)*(ln(2)/ln(Radix)))-(1e-10))); - end; - procedure GenerateShortestDigits(var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;IsEven:boolean;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - var Digit,Compare:longint; - InDeltaRoomMinus,InDeltaRoomPlus:boolean; - begin - Len:=0; - while true do begin - Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); - Assert((Digit>=0) and (Digit<=9)); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - if IsEven then begin - InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<=0; - end else begin - InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<0; - end; - if IsEven then begin - InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; - end else begin - InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; - end; - if (not InDeltaRoomMinus) and (not InDeltaRoomPlus) then begin - BigNumMultiplyByUInt32(Numerator,10); - BigNumMultiplyByUInt32(DeltaMinus,10); - BigNumMultiplyByUInt32(DeltaPlus,10); - end else if InDeltaRoomMinus and InDeltaRoomPlus then begin - Compare:=BigNumPlusCompare(Numerator,Numerator,Denominator); - if Compare<0 then begin - end else if Compare>0 then begin - Assert(Buffer[Len]<>'9'); - inc(Buffer[Len]); - end else begin - if ((ord(Buffer[Len])-ord('0')) and 1)<>0 then begin - Assert(Buffer[Len]<>'9'); - inc(Buffer[Len]); - end; - end; - exit; - end else if InDeltaRoomMinus then begin - exit; - end else begin - Assert(Buffer[Len]<>'9'); - inc(Buffer[Len]); - exit; - end; - end; - end; - procedure GenerateCountedDigits(Count:longint;var DecimalPoint:longint;var Numerator,Denominator:TBigNum;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - var i,Digit:longint; - begin - Assert(Count>=0); - for i:=1 to Count-1 do begin - Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); - Assert((Digit>=0) and (Digit<=9)); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - BigNumMultiplyByUInt32(Numerator,10); - end; - Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); - if BigNumPlusCompare(Numerator,Numerator,Denominator)>=0 then begin - inc(Digit); - end; - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - for i:=Len downto 2 do begin - if ord(Buffer[i])<>(ord('0')+10) then begin - break; - end; - Buffer[i]:='0'; - inc(Buffer[i-1]); - end; - if ord(Buffer[1])=(ord('0')+10) then begin - Buffer[1]:='1'; - inc(DecimalPoint); - end; - end; - procedure GenerateFixedDigits(RequestedDigits:longint;var DecimalPoint:longint;var Numerator,Denominator:TBigNum;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - begin - if (-DecimalPoint)>RequestedDigits then begin - DecimalPoint:=-RequestedDigits; - Len:=0; - end else if (-DecimalPoint)=RequestedDigits then begin - Assert(DecimalPoint=(-RequestedDigits)); - BigNumMultiplyByUInt32(Denominator,10); - if BigNumPlusCompare(Numerator,Numerator,Denominator)>=0 then begin - Buffer:='1'; - Len:=1; - end else begin - Len:=0; - end; - end else begin - GenerateCountedDigits(DecimalPoint+RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); - end; - end; - procedure FixupMultiplyBase(EstimatedPower:longint;IsEven:boolean;var DecimalPoint:longint;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); - var InRange:boolean; - begin - if IsEven then begin - InRange:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; - end else begin - InRange:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; - end; - if InRange then begin - DecimalPoint:=EstimatedPower+1; - end else begin - DecimalPoint:=EstimatedPower; - BigNumMultiplyByUInt32(Numerator,Base); - if BigNumCompare(DeltaMinus,DeltaPlus)=0 then begin - BigNumMultiplyByUInt32(DeltaMinus,Base); - BigNumAssignBigNum(DeltaPlus,DeltaMinus); - end else begin - BigNumMultiplyByUInt32(DeltaMinus,Base); - BigNumMultiplyByUInt32(DeltaPlus,Base); - end; - end; - end; - procedure InitialScaledStartValuesPositiveExponent(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); - begin - Assert(EstimatedPower>=0); - - BigNumAssignUInt64(Numerator,SignificantMantissa); - BigNumShiftLeft(Numerator,Exponent); - BigNumAssignPowerUInt16(Denominator,Base,EstimatedPower); - - if NeedBoundaryDeltas then begin - BigNumShiftLeft(Numerator,1); - BigNumShiftLeft(Denominator,1); - - BigNumAssignUInt16(DeltaPlus,1); - BigNumShiftLeft(DeltaPlus,Exponent); - - BigNumAssignUInt16(DeltaMinus,1); - BigNumShiftLeft(DeltaMinus,Exponent); - - if (Casted and qword($000fffffffffffff))=0 then begin - BigNumShiftLeft(Numerator,1); - BigNumShiftLeft(Denominator,1); - BigNumShiftLeft(DeltaPlus,1); - end; - end; - end; - procedure InitialScaledStartValuesNegativeExponentPositivePower(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); - begin - BigNumAssignUInt64(Numerator,SignificantMantissa); - BigNumAssignPowerUInt16(Denominator,Base,EstimatedPower); - BigNumShiftLeft(Denominator,-Exponent); - - if NeedBoundaryDeltas then begin - BigNumShiftLeft(Numerator,1); - BigNumShiftLeft(Denominator,1); - - BigNumAssignUInt16(DeltaPlus,1); - BigNumAssignUInt16(DeltaMinus,1); - - if (Casted and qword($000fffffffffffff))=0 then begin - BigNumShiftLeft(Numerator,1); - BigNumShiftLeft(Denominator,1); - BigNumShiftLeft(DeltaPlus,1); - end; - end; - end; - procedure InitialScaledStartValuesNegativeExponentNegativePower(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); - begin - BigNumAssignPowerUInt16(Numerator,Base,-EstimatedPower); - if NeedBoundaryDeltas then begin - BigNumAssignBigNum(DeltaPlus,Numerator); - BigNumAssignBigNum(DeltaMinus,Numerator); - end; - BigNumMultiplyByUInt64(Numerator,SignificantMantissa); - - BigNumAssignUInt16(Denominator,1); - BigNumShiftLeft(Denominator,-Exponent); - - if NeedBoundaryDeltas then begin - BigNumShiftLeft(Numerator,1); - BigNumShiftLeft(Denominator,1); - if ((Casted and qword($000fffffffffffff))=0) and ((Casted and qword($7ff0000000000000))<>qword($0010000000000000)) then begin - BigNumShiftLeft(Numerator,1); - BigNumShiftLeft(Denominator,1); - BigNumShiftLeft(DeltaPlus,1); - end; - end; - end; - procedure InitialScaledStartValues(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); - begin - if Exponent>=0 then begin - InitialScaledStartValuesPositiveExponent(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); - end else if EstimatedPower>=0 then begin - InitialScaledStartValuesNegativeExponentPositivePower(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); - end else begin - InitialScaledStartValuesNegativeExponentNegativePower(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); - end; - end; - procedure DoubleToDecimal(Value:double;Mode,RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); - var Casted:qword absolute Value; - SignificantMantissa:qword; - Exponent,EstimatedPower:longint; - Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum; - IsEven,NeedBoundaryDeltas:boolean; - begin - Assert(Value>0); - Assert(BESENIsFinite(Value)); - SplitDouble(Value,SignificantMantissa,Exponent); - IsEven:=(SignificantMantissa and 1)=0; - EstimatedPower:=GetEstimatePower(NormalizedExponent(SignificantMantissa,Exponent)); - if (Mode=mFIXED) and (((-EstimatedPower)-1)>RequestedDigits) then begin - Buffer:=''; - Len:=0; - DecimalPoint:=-RequestedDigits; - end else begin - Assert(BigNumMaxSignificantMantissaBits>=(324*4)); - NeedBoundaryDeltas:=Mode=mSHORTEST; - InitialScaledStartValues(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,10); - FixupMultiplyBase(EstimatedPower,IsEven,DecimalPoint,Numerator,Denominator,DeltaMinus,DeltaPlus,10); - case Mode of - mSHORTEST:begin - GenerateShortestDigits(Numerator,Denominator,DeltaMinus,DeltaPlus,IsEven,Buffer,Len); - end; - mFIXED:begin - GenerateFixedDigits(RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); - end; - else {mPRECISION:}begin - GenerateCountedDigits(RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); - end; - end; - end; - end; - procedure GenerateRadixDigits(var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;IsEven:boolean;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint;Radix:longint); - const Base36:array[0..36] of {$ifdef BESENSingleStringType}char{$else}ansichar{$endif}='0123456789abcdefghijklmnopqrstuvwxyz{'; - var Digit,Compare,MaxDigit:longint; - InDeltaRoomMinus,InDeltaRoomPlus:boolean; - function ValueOf(c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}):longint; - begin - case c of - '0'..'9':begin - result:=ord(c)-ord('0'); - end; - else begin - result:=(ord(c)-ord('a'))+$a; - end; - end; - end; - begin - Len:=0; - MaxDigit:=Radix-1; - while true do begin - Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); - Assert((Digit>=0) and (Digit<=MaxDigit)); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:=Base36[Digit]; - BigNumClamp(Numerator); - BigNumClamp(DeltaMinus); - BigNumClamp(DeltaPlus); - if IsEven then begin - InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<=0; - end else begin - InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<0; - end; - if IsEven then begin - InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; - end else begin - InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; - end; - if (not InDeltaRoomMinus) and (not InDeltaRoomPlus) then begin - BigNumMultiplyByUInt32(Numerator,Radix); - BigNumMultiplyByUInt32(DeltaMinus,Radix); - BigNumMultiplyByUInt32(DeltaPlus,Radix); - end else if InDeltaRoomMinus and InDeltaRoomPlus then begin - Compare:=BigNumPlusCompare(Numerator,Numerator,Denominator); - if Compare<0 then begin - end else if Compare>0 then begin - Assert(ValueOf(Buffer[Len])<>MaxDigit); - Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; - end else begin - if (ValueOf(Buffer[Len]) and 1)<>0 then begin - Assert(ValueOf(Buffer[Len])<>MaxDigit); - Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; - end; - end; - exit; - end else if InDeltaRoomMinus then begin - exit; - end else begin - Assert(ValueOf(Buffer[Len])<>MaxDigit); - Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; - exit; - end; - end; - end; - procedure DoubleToRadix(Value:double;Radix:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); - var Casted:qword absolute Value; - SignificantMantissa:qword; - Exponent,EstimatedPower:longint; - Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum; - IsEven,NeedBoundaryDeltas:boolean; - begin - Assert(Value>0); - Assert(BESENIsFinite(Value)); - SplitDouble(Value,SignificantMantissa,Exponent); - IsEven:=(SignificantMantissa and 1)=0; - EstimatedPower:=GetEstimatePowerOf(NormalizedExponent(SignificantMantissa,Exponent),Radix); - Assert(BigNumMaxSignificantMantissaBits>=(324*4)); - NeedBoundaryDeltas:=true; - InitialScaledStartValues(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Radix); - FixupMultiplyBase(EstimatedPower,IsEven,DecimalPoint,Numerator,Denominator,DeltaMinus,DeltaPlus,Radix); - GenerateRadixDigits(Numerator,Denominator,DeltaMinus,DeltaPlus,IsEven,Buffer,Len,Radix); - end; - procedure FastDoubleToRadix(v:double;Radix:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); - const Base36:array[0..35] of {$ifdef BESENSingleStringType}char{$else}ansichar{$endif}='0123456789abcdefghijklmnopqrstuvwxyz'; -{$ifndef BESENNoFPU} - DtoAFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; - DtoAFPUPrecisionMode:TFPUPrecisionMode=pmDOUBLE; - DtoAFPURoundingMode:TFPURoundingMode=rmNEAREST; -{$endif} - var IntPart,FracPart,Old,Epsilon:double; - Digit,i,j:longint; - TempBuffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; -{$ifndef BESENNoFPU} - OldFPUExceptionMask:TFPUExceptionMask; - OldFPUPrecisionMode:TFPUPrecisionMode; - OldFPURoundingMode:TFPURoundingMode; -{$endif} - IntPart64:int64; - begin - if (Radix<2) or (Radix>36) then begin - result:=''; - end else begin -{$ifndef BESENNoFPU} - OldFPUExceptionMask:=GetExceptionMask; - OldFPUPrecisionMode:=GetPrecisionMode; - OldFPURoundingMode:=GetRoundMode; -{$endif} - try -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin - SetExceptionMask(DtoAFPUExceptionMask); - end; - if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin - SetPrecisionMode(DtoAFPUPrecisionMode); - end; - if OldFPURoundingMode<>DtoAFPURoundingMode then begin - SetRoundMode(DtoAFPURoundingMode); - end; -{$endif} - try - TempBuffer:=''; - IntPart:=System.Int(v); - FracPart:=System.Frac(v); - if IntPart=0 then begin - result:='0'; - end else begin - if IntPart<4294967295.0 then begin - IntPart64:=trunc(IntPart); - while IntPart64>0 do begin - Digit:=IntPart64 mod Radix; - Assert((Digit>=0) and (Digit<Radix)); - IntPart64:=IntPart64 div Radix; - inc(Len); - if Len>=length(TempBuffer) then begin - SetLength(TempBuffer,Len*2); - end; - TempBuffer[Len]:=Base36[Digit]; - end; - end else begin - while IntPart>0 do begin - Old:=IntPart; - IntPart:=System.Int(IntPart/Radix); - Digit:=trunc(Old-(IntPart*Radix)); - Assert((Digit>=0) and (Digit<Radix)); - inc(Len); - if Len>=length(TempBuffer) then begin - SetLength(TempBuffer,Len*2); - end; - TempBuffer[Len]:=Base36[Digit]; - end; - end; - SetLength(Buffer,Len); - j:=1; - for i:=Len downto 1 do begin - Buffer[j]:=TempBuffer[i]; - inc(j); - end; - end; - if FracPart<>0 then begin - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:='.'; - Epsilon:=0.001/Radix; - while (FracPart>=Epsilon) and (Len<32) do begin - FracPart:=FracPart*Radix; - Digit:=trunc(FracPart); - FracPart:=System.Frac(FracPart); - Assert((Digit>=0) and (Digit<Radix)); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:=Base36[Digit]; - end; - end; - finally - TempBuffer:=''; - end; - finally -{$ifndef BESENNoFPU} - if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin - SetExceptionMask(OldFPUExceptionMask); - end; - if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin - SetPrecisionMode(OldFPUPrecisionMode); - end; - if OldFPURoundingMode<>DtoAFPURoundingMode then begin - SetRoundMode(OldFPURoundingMode); - end; -{$endif} - end; - end; - end; - function GetCachedPowerForBinaryExponentRange(MinExponent,MaxExponent:longint;var Power:TDoubleValue;var DecimalExponent:longint):boolean; - var Index:longint; - begin - result:=false; - if (low(BESENDoubleToStringPowerOfTenBinaryExponentTable)<=MinExponent) and (MinExponent<=high(BESENDoubleToStringPowerOfTenBinaryExponentTable)) then begin - Index:=BESENDoubleToStringPowerOfTenBinaryExponentTable[MinExponent]; - if ((Index>=0) and (Index<length(BESENDoubleToStringPowerOfTenTable))) and ((MinExponent<=BESENDoubleToStringPowerOfTenTable[Index,1]) and (BESENDoubleToStringPowerOfTenTable[Index,1]<=MaxExponent)) then begin - Power.SignificantMantissa:=BESENDoubleToStringPowerOfTenTable[Index,0]; - Power.Exponent:=BESENDoubleToStringPowerOfTenTable[Index,1]; - DecimalExponent:=BESENDoubleToStringPowerOfTenTable[Index,2]; - result:=true; - end; - end; - end; - function GetCachedPowerForDecimalExponent(RequestedExponent:longint;var Power:TDoubleValue;var FoundExponent:longint):boolean; - var Index:longint; - begin - result:=false; - if (low(BESENDoubleToStringPowerOfTenDecimalExponentTable)<=RequestedExponent) and (RequestedExponent<=high(BESENDoubleToStringPowerOfTenDecimalExponentTable)) then begin - Index:=BESENDoubleToStringPowerOfTenDecimalExponentTable[RequestedExponent]; - if (Index>=0) and (Index<length(BESENDoubleToStringPowerOfTenTable)) then begin - Power.SignificantMantissa:=BESENDoubleToStringPowerOfTenTable[Index,0]; - Power.Exponent:=BESENDoubleToStringPowerOfTenTable[Index,1]; - FoundExponent:=BESENDoubleToStringPowerOfTenTable[Index,2]; - result:=true; - end; - end; - end; - function RoundWeed(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};Len:longint;DistanceTooHighW,UnsafeInterval,Rest,TenCapacity,UnitValue:qword):boolean; - var SmallDistance,BigDistance:qword; - begin - SmallDistance:=DistanceTooHighW-UnitValue; - BigDistance:=DistanceTooHighW+UnitValue; - Assert(QWordLessOrEqual(Rest,UnsafeInterval)); - while (QWordLess(Rest,SmallDistance) and (QWordGreaterOrEqual(UnsafeInterval-Rest,TenCapacity))) and (QWordLess(Rest+TenCapacity,SmallDistance) or QWordGreaterOrEqual(SmallDistance-Rest,((Rest+TenCapacity)-SmallDistance))) do begin - dec(Buffer[Len]); - inc(Rest,TenCapacity); - end; - if ((QWordLess(Rest,BigDistance) and QWordGreaterOrEqual(UnsafeInterval-Rest,TenCapacity)) and (QWordLess(Rest+TenCapacity,BigDistance) or QWordGreater(BigDistance-Rest,((Rest+TenCapacity)-BigDistance)))) then begin - result:=false; - end else begin - result:=(QWordLessOrEqual(2*UnitValue,Rest) and QWordLessOrEqual(Rest,UnsafeInterval-(4*UnitValue))); - end; - end; - function RoundWeedCounted(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};Len:longint;Rest,TenCapacity,UnitValue:qword;var Capacity:longint):boolean; - var i:longint; - begin - Assert(QWordLess(Rest,TenCapacity)); - result:=false; - if QWordGreater(TenCapacity-UnitValue,UnitValue) then begin - result:=QWordGreater(TenCapacity-Rest,Rest) and QWordGreaterOrEqual(TenCapacity-(2*Rest),2*UnitValue); - if not result then begin - result:=QWordGreater(Rest,UnitValue) and QWordLessOrEqual(TenCapacity-(Rest-UnitValue),Rest-UnitValue); - if result then begin - inc(Buffer[Len]); - for i:=Len downto 2 do begin - if ord(Buffer[i])<>(ord('0')+10) then begin - break; - end; - Buffer[i]:='0'; - inc(Buffer[i-1]); - end; - end; - if ord(Buffer[1])=(ord('0')+10) then begin - Buffer[1]:='1'; - inc(Capacity); - end; - end; - end; - end; - function BiggestPowerTen(Number:longword;NumberBits:longint;var Power:longword;var Exponent:longint):boolean; - label c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11; - begin - result:=true; - case NumberBits of - 30,31,32:begin - c1: - if 1000000000<=Number then begin - Power:=1000000000; - Exponent:=9; - end else begin - goto c2; - end; - end; - 27,28,29:begin - c2: - if 100000000<=Number then begin - Power:=100000000; - Exponent:=8; - end else begin - goto c3; - end; - end; - 24,25,26:begin - c3: - if 10000000<=Number then begin - Power:=10000000; - Exponent:=7; - end else begin - goto c4; - end; - end; - 20,21,22,23:begin - c4: - if 1000000<=Number then begin - Power:=1000000; - Exponent:=6; - end else begin - goto c5; - end; - end; - 17,18,19:begin - c5: - if 100000<=Number then begin - Power:=100000; - Exponent:=5; - end else begin - goto c6; - end; - end; - 14,15,16:begin - c6: - if 10000<=Number then begin - Power:=10000; - Exponent:=4; - end else begin - goto c7; - end; - end; - 10,11,12,13:begin - c7: - if 1000<=Number then begin - Power:=1000; - Exponent:=3; - end else begin - goto c8; - end; - end; - 7,8,9:begin - c8: - if 100<=Number then begin - Power:=100; - Exponent:=2; - end else begin - goto c9; - end; - end; - 4,5,6:begin - c9: - if 10<=Number then begin - Power:=10; - Exponent:=1; - end else begin - goto c10; - end; - end; - 1,2,3:begin - c10: - if 1<=Number then begin - Power:=1; - Exponent:=0; - end else begin - goto c11; - end; - end; - 0:begin - c11: - Power:=0; - Exponent:=-1; - end; - else begin - Power:=0; - Exponent:=0; - result:=false; - end; - end; - end; - function DigitGen(Low,w,High:TDoubleValue;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,Capacity:longint):boolean; - var UnitValue,Fractionals,Rest:qword; - TooLow,TooHigh,UnsafeInterval,One:TDoubleValue; - Integrals,Divisor,Digit:longword; - DivisorExponent:longint; - begin - result:=false; - if ((Low.Exponent=w.Exponent) and (w.Exponent=High.Exponent)) and (QWordLessOrEqual(Low.SignificantMantissa+1,High.SignificantMantissa-1) and - ((MinimalTargetExponent<=w.Exponent) and (w.Exponent<=MaximalTargetExponent))) then begin - UnitValue:=1; - TooLow.SignificantMantissa:=Low.SignificantMantissa-UnitValue; - TooLow.Exponent:=Low.Exponent; - TooHigh.SignificantMantissa:=High.SignificantMantissa+UnitValue; - TooHigh.Exponent:=High.Exponent; - UnsafeInterval:=DoubleValueMinus(TooHigh,TooLow); - One.SignificantMantissa:=qword(1) shl (-w.Exponent); - One.Exponent:=w.Exponent; - Integrals:=TooHigh.SignificantMantissa shr (-One.Exponent); - Fractionals:=TooHigh.SignificantMantissa and (One.SignificantMantissa-1); - Divisor:=0; - DivisorExponent:=0; - if BiggestPowerTen(Integrals,SignificantMantissaSize-(-One.Exponent),Divisor,DivisorExponent) then begin - Capacity:=DivisorExponent+1; - Len:=0; - while Capacity>0 do begin - Digit:=Integrals div Divisor; - Integrals:=Integrals mod Divisor; - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - dec(Capacity); - Rest:=qword(qword(Integrals) shl (-One.Exponent))+Fractionals; - if QWordLess(Rest,UnsafeInterval.SignificantMantissa) then begin - result:=RoundWeed(Buffer,Len,DoubleValueMinus(TooHigh,w).SignificantMantissa,UnsafeInterval.SignificantMantissa,Rest,qword(Divisor) shl (-One.Exponent),UnitValue); - exit; - end; - Divisor:=Divisor div 10; - end; - if (One.Exponent>=-60) and (QWordLess(Fractionals,One.SignificantMantissa) and QWordGreaterOrEqual(qword($1999999999999999),One.SignificantMantissa)) then begin - while true do begin - Fractionals:=Fractionals*10; - UnitValue:=UnitValue*10; - UnsafeInterval.SignificantMantissa:=UnsafeInterval.SignificantMantissa*10; - Digit:=Fractionals shr (-One.Exponent); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - dec(Capacity); - Fractionals:=Fractionals and (One.SignificantMantissa-1); - if QWordLess(Fractionals,UnsafeInterval.SignificantMantissa) then begin - result:=RoundWeed(Buffer,Len,DoubleValueMinus(TooHigh,w).SignificantMantissa*UnitValue,UnsafeInterval.SignificantMantissa,Fractionals,One.SignificantMantissa,UnitValue); - exit; - end; - end; - end; - end; - end; - end; - function DigitGenCounted(w:TDoubleValue;RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,Capacity:longint):boolean; - var wError,Fractionals,Rest:qword; - One:TDoubleValue; - Integrals,Divisor,Digit:longword; - DivisorExponent:longint; - begin - result:=false; - if ((MinimalTargetExponent<=w.Exponent) and (w.Exponent<=MaximalTargetExponent)) and ((MinimalTargetExponent>=-60) and (MaximalTargetExponent<=-32)) then begin - wError:=1; - One.SignificantMantissa:=qword(1) shl (-w.Exponent); - One.Exponent:=w.Exponent; - Integrals:=w.SignificantMantissa shr (-One.Exponent); - Fractionals:=w.SignificantMantissa and (One.SignificantMantissa-1); - Divisor:=0; - DivisorExponent:=0; - if BiggestPowerTen(Integrals,SignificantMantissaSize-(-One.Exponent),Divisor,DivisorExponent) then begin - Capacity:=DivisorExponent+1; - Len:=0; - while Capacity>0 do begin - Digit:=Integrals div Divisor; - Integrals:=Integrals mod Divisor; - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - dec(RequestedDigits); - dec(Capacity); - if RequestedDigits=0 then begin - break; - end; - Divisor:=Divisor div 10; - end; - if RequestedDigits=0 then begin - Rest:=qword(qword(Integrals) shl (-One.Exponent))+Fractionals; - result:=RoundWeedCounted(Buffer,Len,Rest,qword(Divisor) shl (-One.Exponent),wError,Capacity); - exit; - end; - if ((One.Exponent>=-60) and QWordLess(Fractionals,One.SignificantMantissa)) and QWordGreaterOrEqual(qword($1999999999999999),One.SignificantMantissa) then begin - while (RequestedDigits>0) and (Fractionals>wError) do begin - Fractionals:=Fractionals*10; - Digit:=Fractionals shr (-One.Exponent); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - dec(RequestedDigits); - dec(Capacity); - Fractionals:=Fractionals and (One.SignificantMantissa-1); - end; - if RequestedDigits=0 then begin - result:=RoundWeedCounted(Buffer,Len,Fractionals,One.SignificantMantissa,wError,Capacity); - end else begin - result:=false; - end; - end; - end; - end; - end; - procedure NormalizedBoundaries(Value:double;var BoundaryMinus,BoundaryPlus:TDoubleValue); - var v:TDoubleValue; - SignificantMantissaIsZero:boolean; - begin - Assert(not BESENIsNegative(Value)); - Assert(BESENIsFinite(Value)); - SplitDouble(Value,v.SignificantMantissa,v.Exponent); - SignificantMantissaIsZero:=v.SignificantMantissa=qword($0010000000000000); - BoundaryPlus.SignificantMantissa:=(v.SignificantMantissa shl 1)+1; - BoundaryPlus.Exponent:=v.Exponent-1; - DoubleValueNormalize(BoundaryPlus); - if SignificantMantissaIsZero and (v.Exponent<>((-($3ff+52))+1)) then begin - BoundaryMinus.SignificantMantissa:=(v.SignificantMantissa shl 2)-1; - BoundaryMinus.Exponent:=v.Exponent-2; - end else begin - BoundaryMinus.SignificantMantissa:=(v.SignificantMantissa shl 1)-1; - BoundaryMinus.Exponent:=v.Exponent-1; - end; - BoundaryMinus.SignificantMantissa:=BoundaryMinus.SignificantMantissa shl (BoundaryMinus.Exponent-BoundaryPlus.Exponent); - BoundaryMinus.Exponent:=BoundaryPlus.Exponent; - end; - function DoFastShortest(Value:double;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalExponent:longint):boolean; - var w,BoundaryMinus,BoundaryPlus,TenMK,ScaledW,ScaledBoundaryMinus,ScaledBoundaryPlus:TDoubleValue; - mK,TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,Capacity:longint; - begin - result:=false; - w:=DoubleValueGet(Value); - NormalizedBoundaries(Value,BoundaryMinus,BoundaryPlus); - Assert(BoundaryPlus.Exponent=w.Exponent); - TenMKMinimalBinaryExponent:=MinimalTargetExponent-(w.Exponent+SignificantMantissaSize); - TenMKMaximalBinaryExponent:=MaximalTargetExponent-(w.Exponent+SignificantMantissaSize); - if GetCachedPowerForBinaryExponentRange(TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,TenMK,mK) then begin - if (MinimalTargetExponent<=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) and (MaximalTargetExponent>=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) then begin - ScaledW:=DoubleValueMul(w,TenMK); - if ScaledW.Exponent=(BoundaryPlus.Exponent+TenMK.Exponent+SignificantMantissaSize) then begin - ScaledBoundaryMinus:=DoubleValueMul(BoundaryMinus,TenMK); - ScaledBoundaryPlus:=DoubleValueMul(BoundaryPlus,TenMK); - Capacity:=0; - result:=DigitGen(ScaledBoundaryMinus,ScaledW,ScaledBoundaryPlus,Buffer,Len,Capacity); - DecimalExponent:=Capacity-mK; - end; - end; - end; - end; - function DoFastPrecision(Value:double;RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalExponent:longint):boolean; - var w,TenMK,ScaledW:TDoubleValue; - mK,TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,Capacity:longint; - begin - result:=false; - w:=DoubleValueGet(Value); - TenMKMinimalBinaryExponent:=MinimalTargetExponent-(w.Exponent+SignificantMantissaSize); - TenMKMaximalBinaryExponent:=MaximalTargetExponent-(w.Exponent+SignificantMantissaSize); - if GetCachedPowerForBinaryExponentRange(TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,TenMK,mK) then begin - if (MinimalTargetExponent<=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) and (MaximalTargetExponent>=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) then begin - ScaledW:=DoubleValueMul(w,TenMK); - Capacity:=0; - result:=DigitGenCounted(ScaledW,RequestedDigits,Buffer,Len,Capacity); - DecimalExponent:=Capacity-mK; - end; - end; - end; - function DoFastFixed(Value:double;FracitionalCount:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint):boolean; - const Five17=$b1a2bc2ec5; // 5^17 - type TInt128=record - High,Low:qword; - end; - procedure Int128Mul(var a:TInt128;const Multiplicand:longword); - var Accumulator:qword; - Part:longword; - begin - Accumulator:=(a.Low and $ffffffff)*Multiplicand; - Part:=Accumulator and $ffffffff; - Accumulator:=(Accumulator shr 32)+((a.Low shr 32)*Multiplicand); - a.Low:=(Accumulator shl 32)+Part; - Accumulator:=(Accumulator shr 32)+((a.High and $ffffffff)*Multiplicand); - Part:=Accumulator and $ffffffff; - Accumulator:=(Accumulator shr 32)+((a.High shr 32)*Multiplicand); - a.High:=(Accumulator shl 32)+Part; - Assert((Accumulator shr 32)=0); - end; - procedure Int128Shift(var a:TInt128;const Shift:longint); - begin - Assert(((-64)<=Shift) and (Shift<=64)); - if Shift<>0 then begin - if Shift=-64 then begin - a.High:=a.Low; - a.Low:=0; - end else if Shift=64 then begin - a.Low:=a.High; - a.High:=0; - end else if Shift<=0 then begin - a.High:=(a.High shl (-Shift))+(a.Low shr (64+Shift)); - a.Low:=a.Low shl (-Shift); - end else begin - a.Low:=(a.Low shr Shift)+(a.High shl (64-Shift)); - a.High:=a.High shr Shift; - end; - end; - end; - function Int128DivModPowerOfTwo(var a:TInt128;const Power:longint):longint; - begin - if Power>=64 then begin - result:=a.High shr (Power-64); - dec(a.High,result shl (Power-64)); - end else begin - result:=(a.Low shr Power)+(a.High shl (64-Power)); - a.High:=0; - dec(a.Low,(a.Low shr Power) shl Power); - end; - end; - function Int128IsZero(const a:TInt128):boolean; - begin - result:=(a.High=0) and (a.Low=0); - end; - function Int128BitAt(const a:TInt128;const Position:longint):boolean; - begin - if Position>=64 then begin - result:=((a.High shr (Position-64)) and 1)<>0; - end else begin - result:=((a.LOw shr Position) and 1)<>0; - end; - end; - procedure FillDigits32FixedLength(Number:longword;RequestedLength:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - var i,l:longint; - begin - l:=Len; - inc(Len,RequestedLength); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - for i:=RequestedLength downto 1 do begin - Buffer[l+i]:={$ifdef BESENSingleStringType}DigitChars[Number mod 10]{$else}AnsiChar(byte(byte(AnsiChar('0'))+(Number mod 10))){$endif}; - Number:=Number div 10; - end; - end; - procedure FillDigits32(Number:longword;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - var NumberLength,i,l:longint; - OldNumber:longword; - begin - OldNumber:=Number; - NumberLength:=0; - while Number<>0 do begin - Number:=Number div 10; - inc(NumberLength); - end; - if NumberLength<>0 then begin - l:=Len; - inc(Len,NumberLength); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Number:=OldNumber; - for i:=NumberLength downto 1 do begin - Buffer[l+i]:={$ifdef BESENSingleStringType}DigitChars[Number mod 10]{$else}AnsiChar(byte(byte(AnsiChar('0'))+(Number mod 10))){$endif}; - Number:=Number div 10; - end; - end; - end; - procedure FillDigits64FixedLength(Number:qword;RequestedLength:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - var p0,p1,p2:longword; - begin - p2:=Number mod 10000000; - Number:=Number div 10000000; - p1:=Number mod 10000000; - p0:=Number div 10000000; - FillDigits32FixedLength(p0,3,Buffer,Len); - FillDigits32FixedLength(p1,7,Buffer,Len); - FillDigits32FixedLength(p2,7,Buffer,Len); - end; - procedure FillDigits64(Number:qword;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); - var p0,p1,p2:longword; - begin - p2:=Number mod 10000000; - Number:=Number div 10000000; - p1:=Number mod 10000000; - p0:=Number div 10000000; - if p0<>0 then begin - FillDigits32(p0,Buffer,Len); - FillDigits32FixedLength(p1,7,Buffer,Len); - FillDigits32FixedLength(p2,7,Buffer,Len); - end else if p1<>0 then begin - FillDigits32(p1,Buffer,Len); - FillDigits32FixedLength(p2,7,Buffer,Len); - end else begin - FillDigits32(p2,Buffer,Len); - end; - end; - procedure RoundUp(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); - var i:longint; - begin - if Len=0 then begin - Buffer:='1'; - Len:=1; - DecimalPoint:=1; - end else begin - inc(Buffer[Len]); - for i:=Len downto 2 do begin - if ord(Buffer[i])<>(ord('0')+10) then begin - exit; - end; - Buffer[i]:='0'; - inc(Buffer[i-1]); - end; - if ord(Buffer[1])=(ord('0')+10) then begin - Buffer[1]:='1'; - inc(DecimalPoint); - end; - end; - end; - procedure FillFractionals(Fractionals:qword;Exponent:longint;FractionalCount:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); - var Point,i,Digit:longint; - Fractionals128:TInt128; - begin - Assert(((-128)<=Exponent) and (Exponent<=0)); - if (-Exponent)<=64 then begin - Assert((Fractionals shr 56)=0); - Point:=-Exponent; - for i:=1 to FracitionalCount do begin - Fractionals:=Fractionals*5; - dec(Point); - Digit:=Fractionals shr Point; - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - dec(Fractionals,qword(Digit) shl Point); - end; - if ((Fractionals shr (Point-1)) and 1)<>0 then begin - RoundUp(Buffer,Len,DecimalPoint); - end; - end else begin - Assert((64<(-Exponent)) and ((-Exponent)<=128)); - Fractionals128.High:=Fractionals; - Fractionals128.Low:=0; - Int128Shift(Fractionals128,(-Exponent)-64); - Point:=128; - for i:=1 to FracitionalCount do begin - if Int128IsZero(Fractionals128) then begin - break; - end; - Int128Mul(Fractionals128,5); - dec(Point); - Digit:=Int128DivModPowerOfTwo(Fractionals128,Point); - inc(Len); - if Len>=length(Buffer) then begin - SetLength(Buffer,Len*2); - end; - Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; - end; - if Int128BitAt(Fractionals128,Point-1) then begin - RoundUp(Buffer,Len,DecimalPoint); - end; - end; - end; - procedure TrimZeros(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); - var i:longint; - begin - while (Len>0) and (Buffer[Len]='0') do begin - dec(Len); - end; - i:=0; - while (i<Len) and (Buffer[i+1]='0') do begin - inc(i); - end; - if i<>0 then begin - Delete(Buffer,1,i); - dec(Len,i); - dec(DecimalPoint,i); - end; - end; - var SignificantMantissa,Divisor,Dividend,Remainder,Integrals,Fractionals:qword; - Exponent,DivisorPower:longint; - Quotient:longword; - begin - result:=false; - SplitDouble(Value,SignificantMantissa,Exponent); - if (Exponent<=20) and (FracitionalCount<=20) then begin - Len:=0; - if (Exponent+53)>74 then begin - Divisor:=Five17; - DivisorPower:=17; - Dividend:=SignificantMantissa; - if Exponent>DivisorPower then begin - Dividend:=Dividend shl (Exponent-DivisorPower); - Quotient:=Dividend div Divisor; - Remainder:=(Dividend mod Divisor) shl DivisorPower; - end else begin - Dividend:=Dividend shl (DivisorPower-Exponent); - Quotient:=Dividend div Divisor; - Remainder:=(Dividend mod Divisor) shl Exponent; - end; - FillDigits32(Quotient,Buffer,Len); - FillDigits64FixedLength(Remainder,DivisorPower,Buffer,Len); - DecimalPoint:=Len; - end else if Exponent>=0 then begin - SignificantMantissa:=SignificantMantissa shl Exponent; - FillDigits64(SignificantMantissa,Buffer,Len); - DecimalPoint:=Len; - end else if Exponent>-53 then begin - Integrals:=SignificantMantissa shr (-Exponent); - Fractionals:=SignificantMantissa-(Integrals shl (-Exponent)); - if Integrals>$ffffffff then begin - FillDigits64(Integrals,Buffer,Len); - end else begin - FillDigits32(Integrals,Buffer,Len); - end; - DecimalPoint:=Len; - FillFractionals(Fractionals,Exponent,FracitionalCount,Buffer,Len,DecimalPoint); - end else if Exponent<-128 then begin - Assert(FracitionalCount>=20); - Buffer:=''; - Len:=0; - DecimalPoint:=-FracitionalCount; - end else begin - DecimalPoint:=0; - FillFractionals(SignificantMantissa,Exponent,FracitionalCount,Buffer,Len,DecimalPoint); - end; - TrimZeros(Buffer,Len,DecimalPoint); - SetLength(Buffer,Len); - if Len=0 then begin - DecimalPoint:=-FracitionalCount; - end; - result:=true; - end; - end; -var OK,Fast:boolean; - Len,DecimalPoint,ZeroPrefixLength,ZeroPostfixLength,i:longint; -begin - if BESENIsNaN(AValue) then begin - result:='NaN'; - end else if BESENIsZero(AValue) then begin - result:='0'; - end else if BESENIsNegInfinite(AValue) then begin - result:='-Infinity'; - end else if BESENIsNegative(AValue) then begin - result:='-'+BESENDoubleToString(BESENNumberAbsolute(AValue),Mode,RequestedDigits); - end else if BESENIsInfinite(AValue) then begin - result:='Infinity'; - end else begin - result:='0'; - if AValue<>0 then begin - Len:=0; - DecimalPoint:=0; - OK:=false; - Fast:=false; - if ((Mode=BESEN_DOUBLETOSTRINGMODE_FIXED) and (AValue>=1e21)) or ((Mode=BESEN_DOUBLETOSTRINGMODE_RADIX) and (RequestedDigits=10)) then begin - Mode:=BESEN_DOUBLETOSTRINGMODE_STANDARD; - end; - case Mode of - BESEN_DOUBLETOSTRINGMODE_STANDARD,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin - OK:=DoFastShortest(AValue,result,Len,DecimalPoint); - inc(DecimalPoint,Len); - end; - BESEN_DOUBLETOSTRINGMODE_FIXED:begin - OK:=DoFastFixed(AValue,RequestedDigits,result,Len,DecimalPoint); - end; - BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,BESEN_DOUBLETOSTRINGMODE_PRECISION:begin - if RequestedDigits<=0 then begin - OK:=DoFastShortest(AValue,result,Len,DecimalPoint); - inc(DecimalPoint,Len); - RequestedDigits:=Len-1; - end else begin - OK:=DoFastPrecision(AValue,RequestedDigits,result,Len,DecimalPoint); - inc(DecimalPoint,Len); - end; - Assert((Len>0) and (Len<=(RequestedDigits+1))); - end; - BESEN_DOUBLETOSTRINGMODE_RADIX:begin - if ((RequestedDigits>=2) and (RequestedDigits<=36)) and (BESENIsFinite(AValue) and (AValue<4294967295.0) and (System.Int(AValue)=AValue)) then begin - FastDoubleToRadix(AValue,RequestedDigits,result,Len,DecimalPoint); - Fast:=true; - OK:=true; - end; - end; - end; - if not OK then begin - case Mode of - BESEN_DOUBLETOSTRINGMODE_STANDARD,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin - DoubleToDecimal(AValue,mSHORTEST,RequestedDigits,result,Len,DecimalPoint); - OK:=true; - end; - BESEN_DOUBLETOSTRINGMODE_FIXED:begin - DoubleToDecimal(AValue,mFIXED,RequestedDigits,result,Len,DecimalPoint); - OK:=true; - end; - BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,BESEN_DOUBLETOSTRINGMODE_PRECISION:begin - if RequestedDigits<=0 then begin - DoubleToDecimal(AValue,mSHORTEST,RequestedDigits,result,Len,DecimalPoint); - OK:=true; - RequestedDigits:=Len-1; - end else begin - DoubleToDecimal(AValue,mPRECISION,RequestedDigits,result,Len,DecimalPoint); - OK:=true; - end; - Assert((Len>0) and (Len<=(RequestedDigits+1))); - end; - BESEN_DOUBLETOSTRINGMODE_RADIX:begin - if (RequestedDigits>=2) and (RequestedDigits<=36) then begin - DoubleToRadix(AValue,RequestedDigits,result,Len,DecimalPoint); - OK:=true; - end; - end; - end; - end; - if OK then begin - SetLength(result,Len); - case Mode of - BESEN_DOUBLETOSTRINGMODE_STANDARD:begin - if (Len<=DecimalPoint) and (DecimalPoint<=21) then begin - SetLength(result,DecimalPoint); - FillChar(result[Len+1],DecimalPoint-Len,'0'); - end else if (0<DecimalPoint) and (DecimalPoint<=21) then begin - Insert('.',result,DecimalPoint+1); - end else if (DecimalPoint<=0) and (DecimalPoint>-6) then begin - for i:=1 to -DecimalPoint do begin - result:='0'+result; - end; - result:='0.'+result; - end else begin - if Len<>1 then begin - Insert('.',result,2); - end; - if DecimalPoint>=0 then begin - result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end else begin - result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end; - end; - end; - BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin - if Len<>1 then begin - Insert('.',result,2); - end; - if DecimalPoint>=0 then begin - result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end else begin - result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end; - end; - BESEN_DOUBLETOSTRINGMODE_FIXED:begin - ZeroPrefixLength:=0; - ZeroPostfixLength:=0; - if DecimalPoint<=0 then begin - ZeroPrefixLength:=(-DecimalPoint)+1; - DecimalPoint:=1; - end; - if (ZeroPrefixLength+Len)<(DecimalPoint+RequestedDigits) then begin - ZeroPostfixLength:=((DecimalPoint+RequestedDigits)-Len)-ZeroPrefixLength; - end; - for i:=1 to ZeroPrefixLength do begin - result:='0'+result; - end; - for i:=1 to ZeroPostfixLength do begin - result:=result+'0'; - end; - if (RequestedDigits>0) and (DecimalPoint>0) and (DecimalPoint<=length(result)) then begin - Insert('.',result,DecimalPoint+1); - end; - end; - BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL:begin - if RequestedDigits<1 then begin - RequestedDigits:=1; - end; - if RequestedDigits<>1 then begin - Insert('.',result,2); - for i:=Len+1 to RequestedDigits do begin - result:=result+'0'; - end; - end else begin - SetLength(result,1); - end; - if DecimalPoint>=0 then begin - result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end else begin - result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end; - end; - BESEN_DOUBLETOSTRINGMODE_PRECISION:begin - if RequestedDigits<1 then begin - RequestedDigits:=1; - end; - if (DecimalPoint<-6) or (DecimalPoint>=RequestedDigits) then begin - if RequestedDigits<>1 then begin - Insert('.',result,2); - for i:=Len+1 to RequestedDigits do begin - result:=result+'0'; - end; - end else begin - SetLength(result,1); - end; - if DecimalPoint>=0 then begin - result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end else begin - result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end; - end else begin - if DecimalPoint<=0 then begin - for i:=1 to -DecimalPoint do begin - result:='0'+result; - end; - result:='0.'+result; - for i:=Len+1 to RequestedDigits do begin - result:=result+'0'; - end; - end else begin - SetLength(result,RequestedDigits); - for i:=Len+1 to RequestedDigits do begin - result[i]:='0'; - end; - if DecimalPoint<RequestedDigits then begin - if Len<>1 then begin - Insert('.',result,DecimalPoint+1); - end; - end; - end; - end; - end; - BESEN_DOUBLETOSTRINGMODE_RADIX:begin - if not Fast then begin - if (Len<=DecimalPoint) and (DecimalPoint<=21) then begin - SetLength(result,DecimalPoint); - FillChar(result[Len+1],DecimalPoint-Len,'0'); - end else if (0<DecimalPoint) and (DecimalPoint<=21) then begin - Insert('.',result,DecimalPoint+1); - end else if (DecimalPoint<=0) and (DecimalPoint>-6) then begin - for i:=1 to -DecimalPoint do begin - result:='0'+result; - end; - result:='0.'+result; - end else begin - if Len<>1 then begin - Insert('.',result,2); - end; - if DecimalPoint>=0 then begin - result:=result+'p+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end else begin - result:=result+'p-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); - end; - end; - while (length(result)>1) and ((result[1]='0') and (result[2] in ['0'..'9','a'..'f'])) do begin - Delete(result,1,1); - end; - end; - end; - end; - end else begin - result:=''; - end; - end; - end; -end; - -function BESENNumberToString(const Value:TBESENNumber):TBESENString; -begin - if BESENIsNaN(Value) then begin - result:='NaN'; - end else if BESENIsZero(Value) then begin - result:='0'; - end else if BESENIsNegInfinite(Value) then begin - result:='-Infinity'; - end else if BESENIsNegative(Value) then begin - result:='-'+BESENFloatToStr(-Value); - end else if BESENIsInfinite(Value) then begin - result:='Infinity'; - end else begin - result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); - end; -end; - -function BESENNumberToRadixString(const Value:TBESENNumber;Radix:longint):TBESENString; -begin - if BESENIsNaN(Value) then begin - result:='NaN'; - end else if BESENIsZero(Value) then begin - result:='0'; - end else if BESENIsNegInfinite(Value) then begin - result:='-Infinity'; - end else if BESENIsNegative(Value) then begin - result:='-'+BESENFloatToStr(-Value); - end else if BESENIsInfinite(Value) then begin - result:='Infinity'; - end else begin - result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_RADIX,Radix)); - end; -end; - -function BESENFloatToStr(const Value:TBESENNumber):TBESENString; -begin - if BESENIsNaN(Value) then begin - result:='NaN'; - end else if BESENIsZero(Value) then begin - result:='0'; - end else if BESENIsNegInfinite(Value) then begin - result:='-Infinity'; - end else if BESENIsNegative(Value) then begin - result:='-'+BESENFloatToStr(-Value); - end else if BESENIsInfinite(Value) then begin - result:='Infinity'; - end else begin - result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); - end; -end; - -function BESENFloatToLocaleStr(const Value:TBESENNumber):TBESENString; -var i:integer; -begin - if BESENIsNaN(Value) then begin - result:='NaN'; - end else if BESENIsZero(Value) then begin - result:='0'; - end else if BESENIsNegInfinite(Value) then begin - result:='-Infinity'; - end else if BESENIsNegative(Value) then begin - result:='-'+BESENFloatToLocaleStr(-Value); - end else if BESENIsInfinite(Value) then begin - result:='Infinity'; - end else begin - result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); - for i:=1 to length(result) do begin - case word(result[i]) of - ord('.'):begin - result[i]:=widechar(word(ord(BESENLocaleFormatSettings.DecimalSeparator))); - end; - end; - end; - end; -end; - -procedure InitBESEN; -begin - InitBESENNumberTables; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENObject.pas b/3rd/besen/src/BESENObject.pas deleted file mode 100644 index f0a1cf769..000000000 --- a/3rd/besen/src/BESENObject.pas +++ /dev/null @@ -1,2513 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObject; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENObjectPropertyDescriptor, - BESENSelfBalancedTree,BESENHashMap, - BESENGarbageCollector, - BESENPointerSelfBalancedTree; - -type TBESENNativeFunction=procedure(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var ResultValue:TBESENValue) of object; - - TBESENObjectPropertyContainer=class; - - TBESENObjectProperty=class(TBESENCollectorObject) - public - PropertyContainer:TBESENObjectPropertyContainer; - HashPrevious,HashNext,Previous,Next:TBESENObjectProperty; - Hash:TBESENHash; - FullHash:TBESENHash; - Index:TBESENINT32; - ID:TBESENINT32; - ArrayIndex:TBESENINT32; - PropIndex:TBESENINT32; - Key:TBESENString; - Descriptor:TBESENObjectPropertyDescriptor; - IsInSelfBalancedTree:TBESENBoolean; - SelfBalancedTreeNode:PBESENSelfBalancedTreeNode; - constructor Create(AInstance:TObject;const APropertyMap:TBESENObjectPropertyContainer;const AHash,AFullHash:TBESENHash;const AKey:TBESENString); overload; - destructor Destroy; override; - end; - - TBESENObjectProperties=array of TBESENObjectProperty; - - TBESENObjectPropertyContainerHashBucket=record - HashFirst,HashLast:TBESENObjectProperty; - end; - - TBESENObjectPropertyContainerHashBuckets=array of TBESENObjectPropertyContainerHashBucket; - - TBESENObject=class; - - TBESENObjectPropertyEnumerator=class; - - TBESENObjectPropertiesBuckets=array of TBESENObjectProperties; - - TBESENObjectPropertyContainer=class(TBESENCollectorObject) - private - procedure GrowAndRehashIfNeeded; - protected - SelfBalancedTree:TBESENSelfBalancedTree; - HashBuckets:TBESENObjectPropertyContainerHashBuckets; - HashSize:longword; - HashSizeMask:longword; - HashedItems:longword; - HashBucketsUsed:longword; - EnumeratorFirst,EnumeratorLast:TBESENObjectPropertyEnumerator; - Sorted,IsArray:longbool; - LastUsedItem:TBESENObjectProperty; - Obj:TBESENObject; - public - First,Last:TBESENObjectProperty; - Items:TBESENObjectProperties; - ItemCount:longint; - ArrayBuckets:TBESENObjectPropertiesBuckets; - ArrayItemCount:longint; - constructor Create(AInstance:TObject;ASorted:boolean;AObj:TBESENObject); overload; - destructor Destroy; override; - procedure Clear; - procedure ArraySet(Index:longint;PropertyValue:TBESENObjectProperty); - function ArrayGet(Index:longint):TBESENObjectProperty; - procedure Sort(AIsArray:boolean); - function Put(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; - function Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; - procedure Remove(const Key:TBESENString;Hash:TBESENHash=0); - function GetFirst:TBESENObjectProperty; - function GetLast:TBESENObjectProperty; - function GetPrevious(const Item:TBESENObjectProperty):TBESENObjectProperty; - function GetNext(const Item:TBESENObjectProperty):TBESENObjectProperty; - end; - - TBESENObjectPropertyEnumerator=class(TBESENCollectorObject) - public - Obj:TBESENObject; - Previous,Next,Prototype:TBESENObjectPropertyEnumerator; - NextItem:TBESENObjectProperty; - GetOnlyOwnProperties:TBESENBoolean; - GetAllProperties:TBESENBoolean; - DuplicatesHashMap:TBESENHashMap; - constructor Create(AInstance:TObject;AObj:TBESENObject;AGetOnlyOwnProperties,AGetAllProperties:TBESENBoolean); overload; virtual; - destructor Destroy; override; - procedure Reset; - function GetNext(var Key:TBESENString):boolean; - end; - - PBESENObjectStructureProperty=^TBESENObjectStructureProperty; - TBESENObjectStructureProperty=record - Index:TBESENINT32; - ID:TBESENINT32; - Attributes:TBESENObjectPropertyDescriptorAttributes; - Presents:TBESENObjectPropertyDescriptorPresents; - end; - - TBESENObjectStructureProperties=array of TBESENObjectStructureProperty; - - TBESENObjectStructure=class(TBESENCollectorObject) - public - HashPrevious,HashNext,Previous,Next:TBESENObjectStructure; - TransitionFrom:TBESENObjectStructure; - ID:TBESENINT32; - Hash:TBESENHash; - PrototypeID:TBESENINT32; - Properties:TBESENObjectStructureProperties; - ReferenceCounter:longint; - constructor Create(AInstance:TObject); override; - destructor Destroy; override; - procedure IncRef; - procedure DecRef; - function IsPrefixTo(APrototypeID:TBESENINT32;const AProperties:TBESENObjectStructureProperties;var FirstNewPropIndex:longint):TBESENBoolean; - function IsEqualTo(APrototypeID:TBESENINT32;AHash:TBESENHash;const AProperties:TBESENObjectStructureProperties):TBESENBoolean; - function ContainsStructureID(StructureID:TBESENINT32):TBESENBoolean; - function GetStructureIDFromKeyID(KeyID:TBESENINT32):TBESENINT32; - end; - - TBESENObjectStructures=array of TBESENObjectStructure; - - PBESENObjectStructureIDManagerHashBucket=^TBESENObjectStructureIDManagerHashBucket; - TBESENObjectStructureIDManagerHashBucket=record - HashFirst,HashLast:TBESENObjectStructure; - end; - - TBESENObjectStructureIDManagerHashBuckets=array[0..BESENObjectStructureIDManagerHashSize-1] of TBESENObjectStructureIDManagerHashBucket; - - TBESENObjectStructureIDManager=class(TBESENBaseObject) - private - procedure Remove(Structure:TBESENObjectStructure); - public - First,Last:TBESENObjectStructure; - IDCounter:TBESENINT32; - HashBuckets:TBESENObjectStructureIDManagerHashBuckets; - constructor Create(AInstance:TObject); override; - destructor Destroy; override; - procedure Reset; - function ResetIfNeeded:longbool; - function Get(PrototypeID:TBESENINT32;const Properties:TBESENObjectStructureProperties;OldStructure:TBESENObjectStructure):TBESENObjectStructure; - end; - - TBESENObject=class(TBESENGarbageCollectorObject) - private - procedure SetPrototypeObject(NewPrototypeObject:TBESENObject); - procedure RebuildOwnStructure; - protected - procedure InvalidateStructure; - procedure PutNew(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); - procedure PutSetter(Base:TBESENObject;const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;const Descriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue); - procedure GetGetter(Base:TBESENObject;var AResult:TBESENValue;const Descriptor:TBESENObjectPropertyDescriptor); - public - ObjectClassName:TBESENString; - ObjectName:TBESENString; - Properties:TBESENObjectPropertyContainer; - Extensible:TBESENBoolean; - PrototypeObject:TBESENObject; - PrototypeChildren:TBESENPointerSelfBalancedTree; - Structure:TBESENObjectStructure; - StructureID:TBESENINT32; - StructureHash:TBESENHash; - LastProp:TBESENObjectProperty; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; virtual; - destructor Destroy; override; - function RebuildStructure:TBESENBoolean; - procedure RegisterNativeFunction(const AName:TBESENSTRING;const ANative:TBESENNativeFunction;const Len:longint=0;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];const AHasPrototypeProperty:longbool=false); - function HasRecursivePrototypeChain:TBESENBoolean; - procedure PutPrototype(const V:TBESENValue;Throw:TBESENBoolean); - function OverwriteAccessor(const P:TBESENString;const Getter:TBESENObject=nil;const Setter:TBESENObject=nil;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; - function OverwriteData(const P:TBESENString;const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; - function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; virtual; - function GetProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; virtual; - function GetFull(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; - function GetIndex(const Index,ID:longint;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; virtual; - function GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; virtual; - function Get(const P:TBESENString;var AResult:TBESENValue;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; - function CanPut(const P:TBESENString;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; - procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); virtual; - procedure PutFull(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var Temp:TBESENValue;Hash:TBESENHash=0); - procedure PutIndex(const Index,ID:longint;const V:TBESENValue;Throw:TBESENBoolean); virtual; - procedure PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); virtual; - procedure Put(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); - function HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; - function HasProperty(const P:TBESENString;Hash:TBESENHash=0):TBESENBoolean; - function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; - function Delete(const P:TBESENString;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; - function DeleteIndex(const Index,ID:longint;Throw:TBESENBoolean):TBESENBoolean; virtual; - function DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; virtual; - function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; - function DefineOwnProperty(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; - procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); virtual; - function Enumerator(GetOnlyOwnProperties,GetAllProperties:TBESENBoolean):TBESENObjectPropertyEnumerator; virtual; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); virtual; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); virtual; - function HasInstance(const AInstance:TBESENValue):TBESENBoolean; virtual; - function GetSecurityDomain:pointer; virtual; - function HasCall:TBESENBoolean; virtual; - function HasConstruct:TBESENBoolean; virtual; - function HasHasInstance:TBESENBoolean; virtual; - function HasEnumerator:TBESENBoolean; virtual; - function HasGetSecurityDomain:TBESENBoolean; virtual; - procedure Finalize; override; - procedure Mark; override; - property Prototype:TBESENObject read PrototypeObject write SetPrototypeObject; - end; - -procedure BESENCheckObjectCoercible(const v:TBESENValue); {$ifdef caninline}inline;{$endif} - -function BESENIsCallable(const v:TBESENValue):TBESENBoolean; {$ifdef caninline}inline;{$endif} - -implementation - -uses BESEN,BESENUtils,BESENArrayUtils,BESENHashUtils,BESENStringUtils,BESENCode,BESENErrors, - BESENObjectNativeFunction; - -function SortedKeyNormal(AProp:TBESENString):TBESENString; -begin - result:=AProp; -end; - -function SortedKeyNumberic(AProp:TBESENString):TBESENString; -var i:int64; -begin - if BESENArrayToIndex(AProp,i) then begin - result:=AProp; - while length(result)<16 do begin - result:='0'+result; - end; - result:=widechar(word($feff))+result; - end else begin - result:=widechar(word($fffe))+AProp; - end; -end; - -type TSortedKeyFunc=function(AProp:TBESENString):TBESENString; - -const SortedKeyFunc:array[boolean] of TSortedKeyFunc=(SortedKeyNormal,SortedKeyNumberic); - -constructor TBESENObjectProperty.Create(AInstance:TObject;const APropertyMap:TBESENObjectPropertyContainer;const AHash,AFullHash:TBESENHash;const AKey:TBESENString); -var InsertAtItem:TBESENObjectProperty; - SelfBalancedTreeValue:TBESENSelfBalancedTreeValue; - InsertAtNode:PBESENSelfBalancedTreeNode; - v:int64; - i,j:longint; - OK:boolean; -begin - inherited Create(AInstance); - Index:=-1; - v:=0; - if TBESEN(Instance).InlineCacheEnabled then begin - if BESENArrayToIndex(AKey,v) then begin - ID:=TBESEN(Instance).KeyIDManager.Find(AKey,AFullHash); - end else begin - v:=-1; - ID:=TBESEN(Instance).KeyIDManager.Get(AKey,AFullHash); - end; - end else begin - if not BESENArrayToIndex(AKey,v) then begin - v:=-1; - end; - ID:=-1; - end; - PropIndex:=-1; - ArrayIndex:=-1; - PropertyContainer:=APropertyMap; - Hash:=AHash; - FullHash:=AFullHash; - Key:=AKey; - Descriptor.Value.ValueType:=bvtUNDEFINED; - Descriptor.Getter:=nil; - Descriptor.Setter:=nil; - Descriptor.Attributes:=[]; - Descriptor.Presents:=[]; - IsInSelfBalancedTree:=false; - SelfBalancedTreeNode:=nil; - if ID>=0 then begin - Index:=PropertyContainer.ItemCount; - inc(PropertyContainer.ItemCount); - if Index>=length(PropertyContainer.Items) then begin - SetLength(PropertyContainer.Items,Index+256); - end; - PropertyContainer.Items[Index]:=self; - end; - if PropertyContainer.IsArray then begin - if (v>=0) and (v<=$7fffffff) then begin - ArrayIndex:=v; - PropertyContainer.ArraySet(ArrayIndex,self); - end; - end; - if assigned(PropertyContainer.HashBuckets[Hash].HashFirst) then begin - PropertyContainer.HashBuckets[Hash].HashFirst.HashPrevious:=self; - HashNext:=PropertyContainer.HashBuckets[Hash].HashFirst; - HashPrevious:=nil; - PropertyContainer.HashBuckets[Hash].HashFirst:=self; - end else begin - PropertyContainer.HashBuckets[Hash].HashFirst:=self; - PropertyContainer.HashBuckets[Hash].HashLast:=self; - HashPrevious:=nil; - HashNext:=nil; - end; -{if assigned(PropertyContainer.HashBuckets[Hash].HashLast) then begin - PropertyContainer.HashBuckets[Hash].HashLast.HashNext:=self; - HashPrevious:=PropertyContainer.HashBuckets[Hash].HashLast; - HashNext:=nil; - PropertyContainer.HashBuckets[Hash].HashLast:=self; - end else begin - PropertyContainer.HashBuckets[Hash].HashFirst:=self; - PropertyContainer.HashBuckets[Hash].HashLast:=self; - HashPrevious:=nil; - HashNext:=nil; - end;} - if PropertyContainer.Sorted then begin - if assigned(PropertyContainer.First) then begin - if SortedKeyFunc[boolean(PropertyContainer.IsArray)](PropertyContainer.First.Key)>=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key) then begin - PropertyContainer.First.Previous:=self; - Previous:=nil; - Next:=PropertyContainer.First; - PropertyContainer.First:=self; - end else if SortedKeyFunc[boolean(PropertyContainer.IsArray)](PropertyContainer.Last.Key)<=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key) then begin - PropertyContainer.Last.Next:=self; - Previous:=PropertyContainer.Last; - Next:=nil; - PropertyContainer.Last:=self; - end else begin - InsertAtNode:=PropertyContainer.SelfBalancedTree.FindNearest(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)); - if assigned(InsertAtNode) then begin - InsertAtItem:=InsertAtNode^.Value.p; - if SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)<SortedKeyFunc[boolean(PropertyContainer.IsArray)](InsertAtItem.Key) then begin - Previous:=InsertAtItem.Previous; - Next:=InsertAtItem; - InsertAtItem.Previous:=self; - if assigned(Previous) then begin - Previous.Next:=self; - end else begin - PropertyContainer.First:=self; - end; - end else begin - Previous:=InsertAtItem; - Next:=InsertAtItem.Next; - InsertAtItem.Next:=self; - if assigned(Next) then begin - Next.Previous:=self; - end else begin - PropertyContainer.Last:=self; - end; - end; - end else begin - InsertAtItem:=PropertyContainer.First; - while assigned(InsertAtItem) and (SortedKeyFunc[boolean(PropertyContainer.IsArray)](InsertAtItem.Key)<=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)) do begin - InsertAtItem:=InsertAtItem.Next; - end; - if assigned(InsertAtItem) then begin - Previous:=InsertAtItem.Previous; - Next:=InsertAtItem; - InsertAtItem.Previous:=self; - if assigned(Previous) then begin - Previous.Next:=self; - end else begin - PropertyContainer.First:=self; - end; - end else begin - PropertyContainer.Last.Next:=self; - Previous:=PropertyContainer.Last; - Next:=nil; - PropertyContainer.Last:=self; - end; - end; - end; - end else begin - PropertyContainer.First:=self; - PropertyContainer.Last:=self; - Previous:=nil; - Next:=nil; - end; - SelfBalancedTreeValue.p:=self; - SelfBalancedTreeNode:=PropertyContainer.SelfBalancedTree.Insert(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key),SelfBalancedTreeValue); - if assigned(SelfBalancedTreeNode) then begin - IsInSelfBalancedTree:=true; - end; - end else begin - if assigned(PropertyContainer.Last) then begin - PropertyContainer.Last.Next:=self; - Previous:=PropertyContainer.Last; - Next:=nil; - PropertyContainer.Last:=self; - end else begin - PropertyContainer.First:=self; - PropertyContainer.Last:=self; - Previous:=nil; - Next:=nil; - end; - end; - if ID>=0 then begin - PropertyContainer.Obj.InvalidateStructure; - end; -end; - -destructor TBESENObjectProperty.Destroy; -begin - if ID>=0 then begin - PropertyContainer.Obj.InvalidateStructure; - end; - if (Index>=0) and (Index<length(PropertyContainer.Items)) then begin - PropertyContainer.Items[Index]:=nil; - end; - Index:=-1; - if ArrayIndex>=0 then begin - PropertyContainer.ArraySet(ArrayIndex,nil); - end; - ArrayIndex:=-1; - if assigned(Previous) then begin - Previous.Next:=Next; - end else if PropertyContainer.First=self then begin - PropertyContainer.First:=Next; - end; - if assigned(Next) then begin - Next.Previous:=Previous; - end else if PropertyContainer.Last=self then begin - PropertyContainer.Last:=Previous; - end; - Next:=nil; - Previous:=nil; - if assigned(HashPrevious) then begin - HashPrevious.HashNext:=HashNext; - end else if PropertyContainer.HashBuckets[Hash].HashFirst=self then begin - PropertyContainer.HashBuckets[Hash].HashFirst:=HashNext; - end; - if assigned(HashNext) then begin - HashNext.HashPrevious:=HashPrevious; - end else if PropertyContainer.HashBuckets[Hash].HashLast=self then begin - PropertyContainer.HashBuckets[Hash].HashLast:=HashPrevious; - end; - HashNext:=nil; - HashPrevious:=nil; - if IsInSelfBalancedTree then begin - if assigned(SelfBalancedTreeNode) then begin - SelfBalancedTreeNode.Value.p:=nil; - end; - PropertyContainer.SelfBalancedTree.Remove(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)); - IsInSelfBalancedTree:=false; - end; - Key:=''; - inherited Destroy; -end; - -constructor TBESENObjectPropertyContainer.Create(AInstance:TObject;ASorted:boolean;AObj:TBESENObject); -var Hash:TBESENHash; -begin - inherited Create(AInstance); - SelfBalancedTree:=TBESENSelfBalancedTree.Create; - FillChar(HashBuckets,sizeof(TBESENObjectPropertyContainerHashBuckets),#0); - Sorted:=ASorted; - Obj:=AObj; - Items:=nil; - ItemCount:=0; - ArrayBuckets:=nil; - ArrayItemCount:=0; - First:=nil; - Last:=nil; - EnumeratorFirst:=nil; - EnumeratorLast:=nil; - HashSize:=256; - HashSizeMask:=HashSize-1; - HashedItems:=0; - HashBucketsUsed:=0; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - LastUsedItem:=nil; -end; - -destructor TBESENObjectPropertyContainer.Destroy; -var Enumerator,NextEnumerator:TBESENObjectPropertyEnumerator; -begin - Enumerator:=EnumeratorFirst; - while assigned(Enumerator) do begin - NextEnumerator:=Enumerator.Next; - Enumerator.Previous:=nil; - Enumerator.Next:=nil; - BESENFreeAndNil(Enumerator); - Enumerator:=NextEnumerator; - end; - Clear; - SetLength(HashBuckets,0); - SetLength(Items,0); - ItemCount:=0; - SetLength(ArrayBuckets,0); - ArrayItemCount:=0; - SelfBalancedTree.Free; - inherited Destroy; -end; - -procedure TBESENObjectPropertyContainer.Clear; -var Hash:TBESENHash; - Item,NextItem:TBESENObjectProperty; - i:longint; -begin - Item:=First; - while assigned(Item) do begin - NextItem:=Item.Next; - Item.Previous:=nil; - Item.Next:=nil; - BESENFreeAndNil(Item); - Item:=NextItem; - end; - First:=nil; - Last:=nil; - HashSize:=256; - HashSizeMask:=HashSize-1; - HashedItems:=0; - HashBucketsUsed:=0; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - for i:=0 to length(Items)-1 do begin - Items[i]:=nil; - end; - ItemCount:=0; - for i:=0 to length(ArrayBuckets)-1 do begin - SetLength(ArrayBuckets[i],0); - end; - SetLength(ArrayBuckets,0); - ArrayItemCount:=0; - LastUsedItem:=nil; -end; - -procedure TBESENObjectPropertyContainer.ArraySet(Index:longint;PropertyValue:TBESENObjectProperty); -var BucketIndex,InBucketIndex,OldLength,Counter,NewLength:longint; -begin - if Index>=0 then begin - BucketIndex:=Index shr 16; - InBucketIndex:=Index and $ffff; - if assigned(PropertyValue) then begin - OldLength:=length(ArrayBuckets); - if OldLength<=BucketIndex then begin - SetLength(ArrayBuckets,BESENRoundUpToPowerOfTwo(BucketIndex+1)); - for Counter:=OldLength to length(ArrayBuckets)-1 do begin - ArrayBuckets[Counter]:=nil; - end; - end; - OldLength:=length(ArrayBuckets[BucketIndex]); - if OldLength<=InBucketIndex then begin - SetLength(ArrayBuckets[BucketIndex],BESENRoundUpToPowerOfTwo(InBucketIndex+1)); - for Counter:=OldLength to length(ArrayBuckets[BucketIndex])-1 do begin - ArrayBuckets[BucketIndex,Counter]:=nil; - end; - end; - ArrayBuckets[BucketIndex,InBucketIndex]:=PropertyValue; - end else begin - if BucketIndex<length(ArrayBuckets) then begin - OldLength:=length(ArrayBuckets[BucketIndex]); - if InBucketIndex<OldLength then begin - ArrayBuckets[BucketIndex,InBucketIndex]:=nil; - NewLength:=0; - for Counter:=OldLength-1 downto 0 do begin - if assigned(ArrayBuckets[BucketIndex,Counter]) then begin - NewLength:=Counter+1; - break; - end; - end; - if NewLength=0 then begin - SetLength(ArrayBuckets[BucketIndex],0); - ArrayBuckets[BucketIndex]:=nil; - end else if NewLength<>OldLength then begin - NewLength:=BESENRoundUpToPowerOfTwo(NewLength+1); - if NewLength<>OldLength then begin - SetLength(ArrayBuckets[BucketIndex],NewLength); - end; - end; - end; - OldLength:=length(ArrayBuckets); - NewLength:=0; - for Counter:=OldLength-1 downto 0 do begin - if assigned(ArrayBuckets[Counter]) then begin - NewLength:=Counter+1; - break; - end; - end; - if NewLength=0 then begin - SetLength(ArrayBuckets,0); - ArrayBuckets:=nil; - end else if NewLength<>OldLength then begin - NewLength:=BESENRoundUpToPowerOfTwo(NewLength+1); - if NewLength<>OldLength then begin - SetLength(ArrayBuckets,NewLength); - end; - end; - end; - end; - BucketIndex:=length(ArrayBuckets)-1; - if BucketIndex>=0 then begin - ArrayItemCount:=(BucketIndex shl 16)+length(ArrayBuckets[BucketIndex]); - end else begin - ArrayItemCount:=0; - end; - end; -end; - -function TBESENObjectPropertyContainer.ArrayGet(Index:longint):TBESENObjectProperty; -var BucketIndex,InBucketIndex:longint; -begin - result:=nil; - if Index>=0 then begin - BucketIndex:=Index shr 16; - InBucketIndex:=Index and $ffff; - if (BucketIndex<length(ArrayBuckets)) and (InBucketIndex<length(ArrayBuckets[BucketIndex])) then begin - result:=ArrayBuckets[BucketIndex,InBucketIndex]; - end; - end; -end; - -procedure TBESENObjectPropertyContainer.Sort(AIsArray:boolean); -var PartA,PartB,Item:TBESENObjectProperty; - InSize,PartASize,PartBSize,Merges:longint; - SelfBalancedTreeValue:TBESENSelfBalancedTreeValue; - s:TBESENString; -begin - if not Sorted then begin - IsArray:=AIsArray; - end; - if assigned(First) then begin - InSize:=1; - while true do begin - PartA:=First; - First:=nil; - Last:=nil; - Merges:=0; - while assigned(PartA) do begin - inc(Merges); - PartB:=PartA; - PartASize:=0; - while PartASize<InSize do begin - inc(PartASize); - PartB:=PartB.Next; - if not assigned(PartB) then begin - break; - end; - end; - PartBSize:=InSize; - while (PartASize>0) or ((PartBSize>0) and assigned(PartB)) do begin - if PartASize=0 then begin - Item:=PartB; - PartB:=PartB.Next; - dec(PartBSize); - end else if (PartBSize=0) or not assigned(PartB) then begin - Item:=PartA; - PartA:=PartA.Next; - dec(PartASize); - end else if SortedKeyFunc[boolean(IsArray)](PartA.Key)<=SortedKeyFunc[boolean(IsArray)](PartB.Key) then begin - Item:=PartA; - PartA:=PartA.Next; - dec(PartASize); - end else begin - Item:=PartB; - PartB:=PartB.Next; - dec(PartBSize); - end; - if assigned(Last) then begin - Last.Next:=Item; - end else begin - First:=Item; - end; - Item.Previous:=Last; - Last:=Item; - end; - PartA:=PartB; - end; - Last.Next:=nil; - if Merges<=1 then begin - break; - end; - inc(InSize,InSize); - end; - if not Sorted then begin - Item:=First; - while assigned(Item) do begin - SelfBalancedTreeValue.p:=Item; - s:=SortedKeyFunc[boolean(IsArray)](Item.Key); - Item.SelfBalancedTreeNode:=SelfBalancedTree.Insert(s,SelfBalancedTreeValue); - s:=''; - Item.IsInSelfBalancedTree:=assigned(Item.SelfBalancedTreeNode); - Item:=Item.Next; - end; - end; - end; - Sorted:=true; -end; - -procedure TBESENObjectPropertyContainer.GrowAndRehashIfNeeded; -var Hash:TBESENHash; - Item:TBESENObjectProperty; -begin - if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - inc(HashSize,HashSize); - if HashSize>BESENHashMaxSize then begin - HashSize:=BESENHashMaxSize; - end; - HashSizeMask:=HashSize-1; - SetLength(HashBuckets,HashSize); - for Hash:=0 to HashSizeMask do begin - HashBuckets[Hash].HashFirst:=nil; - HashBuckets[Hash].HashLast:=nil; - end; - HashedItems:=0; - Item:=First; - while assigned(Item) do begin - inc(HashedItems); - Item.HashPrevious:=nil; - Item.HashNext:=nil; - Item:=Item.Next; - end; - HashBucketsUsed:=0; - Item:=First; - while assigned(Item) do begin - Hash:=Item.FullHash and HashSizeMask; - Item.Hash:=Hash; - if assigned(HashBuckets[Hash].HashLast) then begin - HashBuckets[Hash].HashLast.HashNext:=Item; - Item.HashPrevious:=HashBuckets[Hash].HashLast; - HashBuckets[Hash].HashLast:=Item; - Item.HashNext:=nil; - end else begin - inc(HashBucketsUsed); - HashBuckets[Hash].HashFirst:=Item; - HashBuckets[Hash].HashLast:=Item; - Item.HashPrevious:=nil; - Item.HashNext:=nil; - end; - Item:=Item.Next; - end; - end; -end; - -function TBESENObjectPropertyContainer.Put(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; -var Item:TBESENObjectProperty; - Enumerator:TBESENObjectPropertyEnumerator; - FullHash:TBESENHash; -begin - result:=nil; - if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin - Item:=LastUsedItem; - Hash:=Item.Hash; - FullHash:=Item.FullHash; - end else begin - IF Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - FullHash:=Hash; - Hash:=Hash and HashSizeMask; - Item:=HashBuckets[Hash].HashFirst; - if not assigned(Item) then begin - inc(HashBucketsUsed); - end; - while assigned(Item) and (Item.Key<>Key) do begin - Item:=Item.Next; - end; - end; - if assigned(Item) then begin - LastUsedItem:=Item; - result:=Item; - end else begin - inc(HashedItems); - Item:=TBESENObjectProperty.Create(Instance,self,Hash,FullHash,Key); - if assigned(Item) then begin - result:=Item; - LastUsedItem:=Item; - Enumerator:=EnumeratorFirst; - while assigned(Enumerator) do begin - if not assigned(Enumerator.NextItem) then begin - Enumerator.NextItem:=Item; - end; - Enumerator:=Enumerator.Next; - end; - end; - end; - GrowAndRehashIfNeeded; -end; - -function TBESENObjectPropertyContainer.Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; -begin - if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin - result:=LastUsedItem; - Hash:=result.Hash; - end else begin - IF Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - result:=HashBuckets[Hash].HashFirst; - while assigned(result) and (result.Key<>Key) do begin - result:=result.HashNext; - end; - end; - if assigned(result) then begin - LastUsedItem:=result; - if HashBuckets[Hash].HashFirst<>result then begin - if assigned(result.HashPrevious) then begin - result.HashPrevious.HashNext:=result.HashNext; - end; - if assigned(result.HashNext) then begin - result.HashNext.HashPrevious:=result.HashPrevious; - end else if HashBuckets[Hash].HashLast=result then begin - HashBuckets[Hash].HashLast:=result.HashPrevious; - end; - HashBuckets[Hash].HashFirst.HashPrevious:=result; - result.HashNext:=HashBuckets[Hash].HashFirst; - result.HashPrevious:=nil; - HashBuckets[Hash].HashFirst:=result; - end; - end; -end; - -procedure TBESENObjectPropertyContainer.Remove(const Key:TBESENString;Hash:TBESENHash=0); -var Item:TBESENObjectProperty; - Enumerator:TBESENObjectPropertyEnumerator; -begin - if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin - Item:=LastUsedItem; - end else begin - IF Hash=0 then begin - Hash:=BESENHashKey(Key); - end; - Hash:=Hash and HashSizeMask; - Item:=HashBuckets[Hash].HashFirst; - while assigned(Item) and (Item.Key<>Key) do begin - Item:=Item.HashNext; - end; - end; - if assigned(Item) then begin - if LastUsedItem=Item then begin - if assigned(Item.Next) then begin - LastUsedItem:=Item.Next; - end else begin - LastUsedItem:=Item.Previous; - end; - end; - Enumerator:=EnumeratorFirst; - while assigned(Enumerator) do begin - if Enumerator.NextItem=Item then begin - Enumerator.NextItem:=Item.Next; - end; - Enumerator:=Enumerator.Next; - end; - Item.Free; - if HashedItems>0 then begin - dec(HashedItems); - end; - end; -end; - -function TBESENObjectPropertyContainer.GetFirst:TBESENObjectProperty; -begin - result:=First; -end; - -function TBESENObjectPropertyContainer.GetLast:TBESENObjectProperty; -begin - result:=Last; -end; - -function TBESENObjectPropertyContainer.GetPrevious(const Item:TBESENObjectProperty):TBESENObjectProperty; -begin - if assigned(Item) then begin - result:=Item.Previous; - end else begin - result:=nil; - end; -end; - -function TBESENObjectPropertyContainer.GetNext(const Item:TBESENObjectProperty):TBESENObjectProperty; -begin - if assigned(Item) then begin - result:=Item.Next; - end else begin - result:=nil; - end; -end; - -constructor TBESENObjectPropertyEnumerator.Create(AInstance:TObject;AObj:TBESENObject;AGetOnlyOwnProperties,AGetAllProperties:TBESENBoolean); -begin - inherited Create(AInstance); - Obj:=AObj; - GetOnlyOwnProperties:=AGetOnlyOwnProperties; - GetAllProperties:=AGetAllProperties; - DuplicatesHashMap:=TBESENHashMap.Create; - if assigned(Obj.Properties.EnumeratorLast) then begin - Obj.Properties.EnumeratorLast.Next:=self; - Previous:=Obj.Properties.EnumeratorLast; - Next:=nil; - Obj.Properties.EnumeratorLast:=self; - end else begin - Obj.Properties.EnumeratorFirst:=self; - Obj.Properties.EnumeratorLast:=self; - Previous:=nil; - Next:=nil; - end; - Prototype:=nil; - NextItem:=nil; -end; - -destructor TBESENObjectPropertyEnumerator.Destroy; -begin - BESENFreeAndNil(Prototype); - BESENFreeAndNil(DuplicatesHashMap); - if assigned(Previous) then begin - Previous.Next:=Next; - end else if Obj.Properties.EnumeratorFirst=self then begin - Obj.Properties.EnumeratorFirst:=Next; - end; - if assigned(Next) then begin - Next.Previous:=Previous; - end else if Obj.Properties.EnumeratorLast=self then begin - Obj.Properties.EnumeratorLast:=Previous; - end; - Previous:=nil; - Next:=nil; - inherited Destroy; -end; - -procedure TBESENObjectPropertyEnumerator.Reset; -begin - if assigned(Prototype) then begin - BESENFreeAndNil(Prototype); - end; - if GetOnlyOwnProperties then begin - Prototype:=nil; - end else begin - if assigned(Obj.Prototype) then begin - Prototype:=Obj.Prototype.Enumerator(GetOnlyOwnProperties,GetAllProperties); - end else begin - Prototype:=nil; - end; - end; - NextItem:=TBESENObjectProperty(Obj.Properties.GetFirst); -end; - -function TBESENObjectPropertyEnumerator.GetNext(var Key:TBESENString):boolean; -var Prop:TBESENObjectProperty; - Hash:TBESENHash; -begin - while assigned(Prototype) do begin - if Prototype.GetNext(Key) then begin - Hash:=BESENHashKey(Key); - Prop:=Obj.Properties.Get(Key,Hash); - if assigned(Prop) then begin - if not assigned(DuplicatesHashMap.GetKey(Key,Hash)) then begin - DuplicatesHashMap.NewKey(Key,true,Hash); - if GetAllProperties or ((boppENUMERABLE in Prop.Descriptor.Presents) and (bopaENUMERABLE in Prop.Descriptor.Attributes)) then begin - result:=true; - exit; - end; - end; - end else begin - result:=true; - exit; - end; - end else begin - BESENFreeAndNil(Prototype); - Prototype:=nil; - break; - end; - end; - while assigned(NextItem) do begin - if not assigned(DuplicatesHashMap.GetKey(NextItem.Key,NextItem.FullHash)) then begin - if GetAllProperties or ((boppENUMERABLE in NextItem.Descriptor.Presents) and (bopaENUMERABLE in NextItem.Descriptor.Attributes)) then begin - Key:=NextItem.Key; - NextItem:=NextItem.Next; - result:=true; - exit; - end; - end; - NextItem:=NextItem.Next; - end; - Key:=''; - result:=false; -end; - -constructor TBESENObjectStructure.Create(AInstance:TObject); -begin - inherited Create(AInstance); - HashPrevious:=nil; - HashNext:=nil; - Previous:=nil; - Next:=nil; - TransitionFrom:=nil; - ID:=-1; - Hash:=0; - PrototypeID:=-1; - Properties:=nil; - ReferenceCounter:=0; -end; - -destructor TBESENObjectStructure.Destroy; -begin - if assigned(TransitionFrom) then begin - TransitionFrom.DecRef; - TransitionFrom:=nil; - end; - SetLength(Properties,0); - TBESEN(Instance).ObjectStructureIDManager.Remove(self); - inherited Destroy; -end; - -procedure TBESENObjectStructure.IncRef; -begin - inc(ReferenceCounter); -end; - -procedure TBESENObjectStructure.DecRef; -begin - dec(ReferenceCounter); - if ReferenceCounter<=0 then begin - Destroy; - end; -end; - -function TBESENObjectStructure.IsPrefixTo(APrototypeID:TBESENINT32;const AProperties:TBESENObjectStructureProperties;var FirstNewPropIndex:longint):TBESENBoolean; -var Transition:TBESENObjectStructure; - Transitions:TBESENObjectStructures; - TransitionCount,TransitionIndex,APropIndex,TransitionPropIndex:longint; - AProp,TransitionProp:PBESENObjectStructureProperty; -begin - result:=false; - - if PrototypeID<>APrototypeID then begin - exit; - end; - - TransitionCount:=0; - Transition:=self; - while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin - inc(TransitionCount); - Transition:=Transition.TransitionFrom; - end; - if assigned(Transition) and (Transition.PrototypeID<>PrototypeID) then begin - exit; - end; - - Transitions:=nil; - try - SetLength(Transitions,TransitionCount); - - TransitionIndex:=TransitionCount; - - Transition:=self; - while assigned(Transition) do begin - dec(TransitionIndex); - Transitions[TransitionIndex]:=Transition; - Transition:=Transition.TransitionFrom; - end; - - if TransitionIndex>0 then begin - SetLength(Transitions,0); - exit; - end; - - APropIndex:=0; - TransitionIndex:=0; - while (APropIndex<length(AProperties)) and (TransitionIndex<length(Transitions)) do begin - Transition:=Transitions[TransitionIndex]; - TransitionPropIndex:=0; - while (APropIndex<length(AProperties)) and (TransitionPropIndex<length(Transition.Properties)) do begin - AProp:=@AProperties[APropIndex]; - TransitionProp:=@Transition.Properties[TransitionPropIndex]; - if (AProp^.Index<>TransitionProp^.Index) or (AProp^.ID<>TransitionProp^.ID) or (AProp^.Attributes<>TransitionProp^.Attributes) or (AProp^.Presents<>TransitionProp^.Presents) then begin - SetLength(Transitions,0); - exit; - end; - inc(APropIndex); - inc(TransitionPropIndex); - end; - if TransitionPropIndex<length(Transition.Properties) then begin - SetLength(Transitions,0); - exit; - end; - inc(TransitionIndex); - end; - - if TransitionIndex<length(Transitions) then begin - SetLength(Transitions,0); - exit; - end; - - FirstNewPropIndex:=APropIndex; - - result:=true; - finally - SetLength(Transitions,0); - end; -end; - -function TBESENObjectStructure.IsEqualTo(APrototypeID:TBESENINT32;AHash:TBESENHash;const AProperties:TBESENObjectStructureProperties):TBESENBoolean; -var Transition:TBESENObjectStructure; - APropIndex,TransitionPropIndex:longint; - AProp,Prop:PBESENObjectStructureProperty; -begin - if (PrototypeID<>APrototypeID) or (Hash<>AHash) then begin - result:=false; - exit; - end; - if assigned(TransitionFrom) then begin - APropIndex:=length(AProperties)-1; - Transition:=self; - result:=true; - while assigned(Transition) and (Transition.PrototypeID=PrototypeID) and (APropIndex>=0) do begin - TransitionPropIndex:=length(Transition.Properties)-1; - while (APropIndex>=0) and (TransitionPropIndex>=0) do begin - AProp:=@AProperties[APropIndex]; - Prop:=@Transition.Properties[TransitionPropIndex]; - if (AProp^.Index<>Prop^.Index) or (AProp^.ID<>Prop^.ID) or (AProp^.Attributes<>Prop^.Attributes) or (AProp^.Presents<>Prop^.Presents) then begin - result:=false; - exit; - end; - dec(TransitionPropIndex); - dec(APropIndex); - end; - if TransitionPropIndex>=0 then begin - result:=false; - exit; - end; - Transition:=Transition.TransitionFrom; - end; - if APropIndex>=0 then begin - result:=false; - end; - end else if length(Properties)=length(AProperties) then begin - result:=true; - for APropIndex:=0 to length(AProperties)-1 do begin - AProp:=@AProperties[APropIndex]; - Prop:=@Properties[APropIndex]; - if (AProp^.Index<>Prop^.Index) or (AProp^.ID<>Prop^.ID) or (AProp^.Attributes<>Prop^.Attributes) or (AProp^.Presents<>Prop^.Presents) then begin - result:=false; - break; - end; - end; - end else begin - result:=false; - end; -end; - -function TBESENObjectStructure.ContainsStructureID(StructureID:TBESENINT32):TBESENBoolean; -var Transition:TBESENObjectStructure; -begin - result:=false; - Transition:=self; - while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin - if Transition.ID=StructureID then begin - result:=true; - exit; - end; - Transition:=Transition.TransitionFrom; - end; -end; - -function TBESENObjectStructure.GetStructureIDFromKeyID(KeyID:TBESENINT32):TBESENINT32; -var Transition:TBESENObjectStructure; - PropIndex:longint; -begin - result:=-1; - Transition:=self; - while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin - for PropIndex:=0 to length(Transition.Properties)-1 do begin - if Transition.Properties[PropIndex].ID=KeyID then begin - result:=Transition.ID; - exit; - end; - end; - Transition:=Transition.TransitionFrom; - end; -end; - -constructor TBESENObjectStructureIDManager.Create(AInstance:TObject); -begin - inherited Create(AInstance); - First:=nil; - Last:=nil; - IDCounter:=0; - FillChar(HashBuckets,sizeof(TBESENObjectStructureIDManagerHashBuckets),#0); -end; - -destructor TBESENObjectStructureIDManager.Destroy; -begin - while assigned(First) do begin - First.Free; - end; - inherited Destroy; -end; - -procedure TBESENObjectStructureIDManager.Reset; -var Code:TBESENCode; - GarbageCollectorObject:TBESENGarbageCollectorObject; - Obj:TBESENObject; -begin - try - Code:=TBESEN(Instance).CodeFirst; - while assigned(Code) do begin - Code.ResetPolymorphicInlineCacheInstructions; - Code:=Code.CodeNext; - end; - - GarbageCollectorObject:=TBESEN(Instance).GarbageCollector.First; - while assigned(GarbageCollectorObject) do begin - if GarbageCollectorObject is TBESENObject then begin - Obj:=TBESENObject(GarbageCollectorObject); - Obj.Structure:=nil; - Obj.StructureID:=0; - Obj.StructureHash:=0; - end; - GarbageCollectorObject:=GarbageCollectorObject.GarbageCollectorNext; - end; - - while assigned(First) do begin - First.Free; - end; - IDCounter:=0; - except - TBESEN(Instance).InlineCacheEnabled:=false; - end; -end; - -function TBESENObjectStructureIDManager.ResetIfNeeded:longbool; -begin - if IDCounter>=$40000000 then begin - Reset; - result:=true; - end else begin - result:=false; - end; -end; - -function TBESENObjectStructureIDManager.Get(PrototypeID:TBESENINT32;const Properties:TBESENObjectStructureProperties;OldStructure:TBESENObjectStructure):TBESENObjectStructure; -var Hash:TBESENHash; - HashBucket:PBESENObjectStructureIDManagerHashBucket; - PropIndex,FirstNewPropIndex:longint; - Prop:PBESENObjectStructureProperty; - Transitions:TBESENObjectStructures; -begin - Transitions:=nil; - try - Hash:=(2166136261 xor TBESENUINT32(PrototypeID))*1664525; - for PropIndex:=0 to length(Properties)-1 do begin - Prop:=@Properties[PropIndex]; - Hash:=((Hash+TBESENUINT32(Prop^.Index)) xor TBESENUINT32(Prop^.ID))*16777619; - Hash:=((Hash-TBESENUINT32(byte(Prop^.Attributes))) xor TBESENUINT32(byte(Prop^.Presents)))*1664525; - end; - HashBucket:=@HashBuckets[Hash and BESENObjectStructureIDManagerHashSizeMask]; - result:=HashBucket^.HashFirst; - while assigned(result) do begin - if result.IsEqualTo(PrototypeID,Hash,Properties) then begin - exit; - end; - result:=result.HashNext; - end; - result:=TBESENObjectStructure.Create(Instance); - result.PrototypeID:=PrototypeID; - result.Hash:=Hash; - inc(IDCounter); - result.ID:=IDCounter; - FirstNewPropIndex:=0; - if assigned(OldStructure) and OldStructure.IsPrefixTo(PrototypeID,Properties,FirstNewPropIndex) then begin - if FirstNewPropIndex<length(Properties) then begin - result.TransitionFrom:=OldStructure; - result.TransitionFrom.IncRef; - result.Properties:=copy(Properties,FirstNewPropIndex,length(Properties)-FirstNewPropIndex); - end else begin - result.Properties:=copy(Properties,0,length(Properties)); - end; - end else begin - result.Properties:=copy(Properties,0,length(Properties)); - end; - result.HashNext:=nil; - if assigned(HashBucket^.HashLast) then begin - HashBucket^.HashLast.HashNext:=result; - result.HashPrevious:=HashBucket^.HashLast; - HashBucket^.HashLast:=result; - end else begin - result.HashPrevious:=nil; - HashBucket^.HashFirst:=result; - HashBucket^.HashLast:=result; - end; - result.Next:=nil; - if assigned(Last) then begin - Last.Next:=result; - result.Previous:=Last; - Last:=result; - end else begin - result.Previous:=nil; - First:=result; - Last:=result; - end; - finally - SetLength(Transitions,0); - end; -end; - -procedure TBESENObjectStructureIDManager.Remove(Structure:TBESENObjectStructure); -var HashBucket:PBESENObjectStructureIDManagerHashBucket; -begin - if assigned(Structure) then begin - HashBucket:=@HashBuckets[Structure.Hash and BESENObjectStructureIDManagerHashSizeMask]; - if assigned(Structure.HashPrevious) then begin - Structure.HashPrevious.HashNext:=Structure.HashNext; - end else if HashBucket^.HashFirst=Structure then begin - HashBucket^.HashFirst:=Structure.HashNext; - end; - if assigned(Structure.HashNext) then begin - Structure.HashNext.HashPrevious:=Structure.HashPrevious; - end else if HashBucket^.HashLast=Structure then begin - HashBucket^.HashLast:=Structure.HashPrevious; - end; - Structure.HashNext:=nil; - Structure.HashPrevious:=nil; - if assigned(Structure.Previous) then begin - Structure.Previous.Next:=Structure.Next; - end else if First=Structure then begin - First:=Structure.Next; - end; - if assigned(Structure.Next) then begin - Structure.Next.Previous:=Structure.Previous; - end else if Last=Structure then begin - Last:=Structure.Previous; - end; - Structure.Next:=nil; - Structure.Previous:=nil; - end; -end; - -constructor TBESENObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance); - ObjectClassName:='Object'; - ObjectName:='object'; - - PrototypeChildren:=TBESENPointerSelfBalancedTree.Create; - - Structure:=nil; - StructureID:=0; - StructureHash:=0; - - Properties:=TBESENObjectPropertyContainer.Create(AInstance,false,self); - - PrototypeObject:=nil; - if assigned(APrototype) then begin - Prototype:=APrototype; - end; - - Extensible:=true; - - LastProp:=nil; - - if AHasPrototypeProperty and assigned(Prototype) then begin - OverwriteData('prototype',BESENObjectValueEx(Prototype),[]); - end; - - StructureID:=0; -end; - -destructor TBESENObject.Destroy; -var Node:PBESENPointerSelfBalancedTreeNode; - Obj:TBESENObject; -begin - TBESEN(Instance).GarbageCollector.FinalizeObjectForSweeping(self); - - BESENFreeAndNil(Properties); - - Prototype:=nil; - - if assigned(PrototypeChildren) then begin - Node:=PrototypeChildren.FirstKey; - while assigned(Node) do begin - Obj:=TBESENObject(Node^.Key); - if assigned(Obj) and (Obj.PrototypeObject=self) then begin - Obj.PrototypeObject:=nil; - Obj.InvalidateStructure; - end; - Node:=Node^.NextKey; - end; - end; - - BESENFreeAndNil(PrototypeChildren); - - if assigned(Structure) then begin - Structure.DecRef; - Structure:=nil; - end; - - ObjectName:=''; - ObjectClassName:=''; - inherited Destroy; -end; - -procedure TBESENObject.SetPrototypeObject(NewPrototypeObject:TBESENObject); -var Obj:TBESENObject; - Value:TBESENPointerSelfBalancedTreeValue; -begin - if assigned(NewPrototypeObject) then begin - Obj:=NewPrototypeObject; - while assigned(Obj) do begin - if Obj=self then begin - BESENThrowRcursivePrototypeChain; - end; - Obj:=Obj.Prototype; - end; - end; - if assigned(PrototypeObject) then begin - PrototypeObject.PrototypeChildren.Remove(self); - end; - PrototypeObject:=NewPrototypeObject; - if assigned(PrototypeObject) then begin - Value.p:=self; - PrototypeObject.PrototypeChildren.Insert(self,Value); - end; - InvalidateStructure; -end; - -procedure TBESENObject.InvalidateStructure; -var Node:PBESENPointerSelfBalancedTreeNode; - Obj:TBESENObject; -begin - if StructureID<>0 then begin - if assigned(PrototypeChildren) then begin - Node:=PrototypeChildren.FirstKey; - while assigned(Node) do begin - Obj:=TBESENObject(Node^.Key); - if assigned(Obj) and (Obj.PrototypeObject=self) then begin - Obj.InvalidateStructure; - end; - Node:=Node^.NextKey; - end; - end; - StructureID:=0; - end; -end; - -procedure TBESENObject.RebuildOwnStructure; -var PrototypeID:TBESENINT64; - Count,Index:longint; - Prop:TBESENObjectProperty; - StructureProperties:TBESENObjectStructureProperties; - OldStructure:TBESENObjectStructure; -begin - StructureProperties:=nil; - try - OldStructure:=Structure; - Structure:=nil; - - StructureID:=0; - StructureHash:=0; - - if TBESEN(Instance).InlineCacheEnabled then begin - - if assigned(Prototype) then begin - PrototypeID:=Prototype.StructureID; - end else begin - PrototypeID:=-1; - end; - - Count:=0; - Prop:=Properties.First; - while assigned(Prop) do begin - if Prop.ID>=0 then begin - inc(Count); - end; - Prop:=Prop.Next; - end; - SetLength(StructureProperties,Count); - Index:=0; - Prop:=Properties.First; - while assigned(Prop) do begin - if Prop.ID>=0 then begin - StructureProperties[Index].Index:=Prop.Index; - StructureProperties[Index].ID:=Prop.ID; - StructureProperties[Index].Attributes:=Prop.Descriptor.Attributes; - StructureProperties[Index].Presents:=Prop.Descriptor.Presents; - inc(Index); - end; - Prop:=Prop.Next; - end; - - Structure:=TBESEN(Instance).ObjectStructureIDManager.Get(PrototypeID,StructureProperties,OldStructure); - if assigned(Structure) then begin - Structure.IncRef; - StructureID:=Structure.ID; - StructureHash:=Structure.Hash; - end; - end; - - if assigned(OldStructure) then begin - OldStructure.DecRef; - OldStructure:=nil; - end; - finally - SetLength(StructureProperties,0); - end; -end; - -function TBESENObject.RebuildStructure:TBESENBoolean; - procedure RebuildObjectStructure(Obj:TBESENObject); - begin - if Obj.StructureID=0 then begin - if assigned(Obj.Prototype) then begin - RebuildObjectStructure(Obj.Prototype); - end; - Obj.RebuildOwnStructure; - end; - end; -begin - RebuildObjectStructure(self); - result:=not TBESEN(Instance).ObjectStructureIDManager.ResetIfNeeded; -end; - -procedure TBESENObject.RegisterNativeFunction(const AName:TBESENSTRING;const ANative:TBESENNativeFunction;const Len:longint=0;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];const AHasPrototypeProperty:longbool=false); -var o:TBESENObjectNativeFunction; -begin - o:=TBESENObjectNativeFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,AHasPrototypeProperty); - o.Native:=ANative; - o.ObjectName:=AName; - TBESEN(Instance).GarbageCollector.Add(o); - o.GarbageCollectorLock; - try - OverwriteData(AName,BESENObjectValueEx(o),Attributes,true); - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - o.OverwriteData('name',BESENStringValue(AName),[]); - end; - o.OverwriteData('length',BESENNumberValue(Len),[]); - finally - o.GarbageCollectorUnlock; - end; -end; - -function TBESENObject.HasRecursivePrototypeChain:TBESENBoolean; -var Obj:TBESENObject; -begin - result:=false; - Obj:=Prototype; - while assigned(Obj) do begin - if Obj=self then begin - result:=true; - break; - end; - Obj:=Obj.Prototype; - end; -end; - -procedure TBESENObject.PutPrototype(const V:TBESENValue;Throw:TBESENBoolean); -var Obj:TBESENObject; -begin - case V.ValueType of - bvtUNDEFINED,bvtNULL:begin - Prototype:=nil; - end; - bvtOBJECT:begin - Obj:=TBESENObject(V.Obj); - while assigned(Obj) do begin - if Obj=self then begin - if Throw then begin - BESENThrowPutRecursivePrototypeChain; - end; - exit; - end; - Obj:=Obj.Prototype; - end; - Prototype:=TBESENObject(V.Obj); - end; - else begin - if Throw then begin - BESENThrowPutInvalidPrototype; - end; - end; - end; -end; - -function TBESENObject.OverwriteAccessor(const P:TBESENString;const Getter:TBESENObject=nil;const Setter:TBESENObject=nil;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; -var Prop:TBESENObjectProperty; -begin - Prop:=Properties.Get(P); - if assigned(Prop) then begin - if Prop.ID>=0 then begin - if (Prop.Descriptor.Attributes<>(Attributes*[bopaENUMERABLE,bopaCONFIGURABLE])) or (([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[]) then begin - InvalidateStructure; - end; - if assigned(Prop.Descriptor.Getter) then begin - if not (boppGETTER in Prop.Descriptor.Presents) then begin - InvalidateStructure; - end; - end; - if assigned(Prop.Descriptor.Setter) then begin - if not (boppSETTER in Prop.Descriptor.Presents) then begin - InvalidateStructure; - end; - end; - end; - end else begin - Prop:=Properties.Put(P); - end; - Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; - Prop.Descriptor.Getter:=Getter; - Prop.Descriptor.Setter:=Setter; - Prop.Descriptor.Attributes:=Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; - Prop.Descriptor.Presents:=[boppENUMERABLE,boppCONFIGURABLE]; - if assigned(Prop.Descriptor.Getter) then begin - Prop.Descriptor.Presents:=Prop.Descriptor.Presents+[boppGETTER]; - end; - if assigned(Prop.Descriptor.Setter) then begin - Prop.Descriptor.Presents:=Prop.Descriptor.Presents+[boppSETTER]; - end; - result:=true; -end; - -function TBESENObject.OverwriteData(const P:TBESENString;const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; -var Prop:TBESENObjectProperty; -begin - Prop:=Properties.Get(P); - if assigned(Prop) then begin - if Prop.ID>=0 then begin - if (Prop.Descriptor.Attributes<>Attributes) or (Prop.Descriptor.Presents<>[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]) then begin - InvalidateStructure; - end; - end; - end else begin - Prop:=Properties.Put(P); - end; - BESENCopyValue(Prop.Descriptor.Value,Value); - Prop.Descriptor.Getter:=nil; - Prop.Descriptor.Setter:=nil; - Prop.Descriptor.Attributes:=Attributes; - Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - result:=true; -end; - -function TBESENObject.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; -var Prop:TBESENObjectProperty; -begin - Prop:=Properties.Get(P,Hash); - LastProp:=Prop; - if assigned(Prop) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - BESENCopyValue(Descriptor.Value,Prop.Descriptor.Value); - Descriptor.Getter:=nil; - Descriptor.Setter:=nil; - Descriptor.Attributes:=Prop.Descriptor.Attributes; - Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - result:=true; - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - Descriptor.Value.ValueType:=bvtUNDEFINED; - Descriptor.Getter:=Prop.Descriptor.Getter; - Descriptor.Setter:=Prop.Descriptor.Setter; - Descriptor.Attributes:=Prop.Descriptor.Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; - Descriptor.Presents:=[boppGETTER,boppSETTER,boppENUMERABLE,boppCONFIGURABLE]; - result:=true; - end else begin - result:=false; - end; - end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin - if assigned(Prototype) then begin - Descriptor.Value.ValueType:=bvtOBJECT; - Descriptor.Value.Obj:=Prototype; - end else begin - Descriptor.Value.ValueType:=bvtNULL; - end; - Descriptor.Getter:=nil; - Descriptor.Setter:=nil; - Descriptor.Attributes:=[bopaWRITABLE]; - Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE,boppPROTO]; - result:=true; - end else begin - Descriptor.Presents:=[]; - result:=false; - end; -end; - -function TBESENObject.GetProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; -var Base:TBESENObject; -begin - if Hash=0 then begin - Hash:=BESENHashKey(P); - end; - Base:=self; - while assigned(Base) do begin - if Base.GetOwnProperty(P,Descriptor,Hash) then begin - result:=true; - exit; - end; - Base:=Base.Prototype; - end; - Descriptor.Presents:=[]; - result:=false; -end; - -procedure TBESENObject.GetGetter(Base:TBESENObject;var AResult:TBESENValue;const Descriptor:TBESENObjectPropertyDescriptor); -begin - if (boppGETTER in Descriptor.Presents) and assigned(Descriptor.Getter) then begin - TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Getter),BESENObjectValue(Base),nil,0,AResult); - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; -end; - -function TBESENObject.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -var Prop:TBESENObjectProperty; -begin - if not assigned(Base) then begin - Base:=self; - end; - Prop:=Properties.Get(P,Hash); - if assigned(Prop) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - BESENCopyValue(AResult,Prop.Descriptor.Value); - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - GetGetter(Base,AResult,Prop.Descriptor); - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; - result:=true; - end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin - if assigned(Prototype) then begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=Prototype; - end else begin - AResult.ValueType:=bvtNULL; - end; - result:=true; - end else begin - if assigned(Prototype) then begin - result:=Prototype.GetEx(P,AResult,Descriptor,Base,Hash); - end else begin - AResult.ValueType:=bvtUNDEFINED; - result:=false; - end; - end; -end; - -function TBESENObject.GetFull(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - result:=false; - AResult.ValueType:=bvtUNDEFINED; - if GetProperty(P,Descriptor,Hash) then begin - if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin - if boppVALUE in Descriptor.Presents then begin - BESENCopyValue(AResult,Descriptor.Value); - end; - end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - if assigned(Base) then begin - GetGetter(Base,AResult,Descriptor); - end else begin - GetGetter(self,AResult,Descriptor); - end; - end; - result:=true; - end; -end; - -function TBESENObject.GetIndex(const Index,ID:longint;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -var Prop:TBESENObjectProperty; -begin - result:=false; - if not assigned(Base) then begin - Base:=self; - end; - if (Index>=0) and (Index<Properties.ItemCount) then begin - Prop:=Properties.Items[Index]; - if assigned(Prop) and (Prop.ID=ID) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - BESENCopyValue(AResult,Prop.Descriptor.Value); - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - GetGetter(Base,AResult,Prop.Descriptor); - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; - result:=true; - exit; - end; - end; - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (TBESEN(Instance).KeyIDManager.ProtoID=ID) then begin - if assigned(Prototype) then begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=Prototype; - end else begin - AResult.ValueType:=bvtNULL; - end; - result:=true; - exit; - end else if assigned(Prototype) then begin - result:=Prototype.GetIndex(Index,ID,AResult,Base); - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; -end; - -function TBESENObject.GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -begin - result:=Get(BESENArrayIndexToStr(Index),AResult,Base); -end; - -function TBESENObject.Get(const P:TBESENString;var AResult:TBESENValue;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -var Descriptor:TBESENObjectPropertyDescriptor; -begin - if not assigned(Base) then begin - Base:=self; - end; - if Hash=0 then begin - Hash:=BESENHashKey(P); - end; - result:=GetEx(P,AResult,Descriptor,Base,Hash); -end; - -function TBESENObject.CanPut(const P:TBESENString;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - Descriptor.Presents:=[]; - if GetOwnProperty(P,OwnDescriptor) then begin - if ([boppGETTER,boppSETTER]*OwnDescriptor.Presents)<>[] then begin - result:=(boppSETTER in OwnDescriptor.Presents) and assigned(OwnDescriptor.Setter); - end else begin - result:=(boppWRITABLE in OwnDescriptor.Presents) and (bopaWRITABLE in OwnDescriptor.Attributes); - end; - end else begin - if assigned(Prototype) then begin - if Prototype.GetProperty(P,Descriptor) then begin - if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - result:=(boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter); - end else begin - result:=Extensible and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)); - end; - end else begin - result:=Extensible; - end; - end else begin - result:=Extensible; - end; - end; -end; - -procedure TBESENObject.PutNew(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); -var Prop:TBESENObjectProperty; -begin - Prop:=Properties.Put(P,Hash); - BESENCopyValue(Prop.Descriptor.Value,V); - Prop.Descriptor.Getter:=nil; - Prop.Descriptor.Setter:=nil; - Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; - Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - if Prop.ID>=0 then begin - InvalidateStructure; - end; -end; - -procedure TBESENObject.PutSetter(Base:TBESENObject;const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;const Descriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue); -var ValuePointers:array[0..0] of PBESENValue; -begin - if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin - ValuePointers[0]:=@v; - TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BESENObjectValue(Base),@ValuePointers,1,TempValue); - end else begin - if Throw then begin - BESENThrowNoSetter(P); - end; - end; -end; - -procedure TBESENObject.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); -var Prop:TBESENObjectProperty; -begin - // Optimized and combined GetOwnProperty + CanPut + DefineOwnProperty - Prop:=Properties.Get(P,Hash); - if assigned(Prop) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - if bopaWRITABLE in Prop.Descriptor.Attributes then begin - BESENCopyValue(Prop.Descriptor.Value,V); - end else begin - if Throw then begin - BESENThrowPut(P); - end; - end; - exit; - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - PutSetter(self,P,V,Throw,Prop.Descriptor,TempValue); - exit; - end; - end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin - PutPrototype(V,Throw); - exit; - end; - - if assigned(Prototype) then begin - if Prototype.GetProperty(P,Descriptor) then begin - if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - PutSetter(self,P,V,Throw,Descriptor,TempValue); - exit; - end else begin - if not (Extensible and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes))) then begin - if Throw then begin - BESENThrowPut(P); - end; - exit; - end; - end; - end; - end; - - if Extensible then begin - PutNew(P,V,Throw,Hash); - exit; - end; - - if Throw then begin - BESENThrowPut(P); - end; -end; - -procedure TBESENObject.PutFull(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var Temp:TBESENValue;Hash:TBESENHash=0); -var ValuePointers:array[0..0] of PBESENValue; -begin - if CanPut(P,Descriptor,OwnDescriptor,Hash) then begin - if boppPROTO in OwnDescriptor.Presents then begin - PutPrototype(V,Throw); - end else if ([boppVALUE,boppWRITABLE]*OwnDescriptor.Presents)<>[] then begin - BESENCopyValue(OwnDescriptor.Value,V); - OwnDescriptor.Getter:=nil; - OwnDescriptor.Setter:=nil; - OwnDescriptor.Attributes:=[]; - OwnDescriptor.Presents:=[boppVALUE]; - DefineOwnPropertyEx(P,OwnDescriptor,Throw,Descriptor,Hash); - end else begin - if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin - ValuePointers[0]:=@V; - TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BESENObjectValue(self),@ValuePointers,1,Temp); - end else begin - if Throw then begin - BESENThrowNoSetter(P); - end; - end; - end else begin - BESENCopyValue(OwnDescriptor.Value,v); - OwnDescriptor.Getter:=nil; - OwnDescriptor.Setter:=nil; - OwnDescriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; - OwnDescriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - DefineOwnPropertyEx(P,OwnDescriptor,Throw,Descriptor,Hash); - end; - end; - end else begin - if Throw then begin - BESENThrowPut(P); - end; - end; -end; - -procedure TBESENObject.PutIndex(const Index,ID:longint;const V:TBESENValue;Throw:TBESENBoolean); - procedure ThrowIt; - begin - BESENThrowTypeError('Put failed'); - end; - procedure PutSetter(Obj:TBESENObject;Prop:TBESENObjectProperty); - var TempValue:TBESENValue; - ValuePointers:array[0..0] of PBESENValue; - begin - if (boppSETTER in Prop.Descriptor.Presents) and assigned(Prop.Descriptor.Setter) then begin - ValuePointers[0]:=@V; - TBESEN(Instance).ObjectCall(TBESENObject(Prop.Descriptor.Setter),BESENObjectValue(Obj),@ValuePointers,1,TempValue); - exit; - end; - if Throw then begin - BESENThrowNoSetter(Prop.Key); - end; - end; -var Obj:TBESENObject; - Prop:TBESENObjectProperty; -begin - if (Index>=0) and (Index<Properties.ItemCount) then begin - Prop:=Properties.Items[Index]; - if assigned(Prop) and (Prop.ID=ID) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - if bopaWRITABLE in Prop.Descriptor.Attributes then begin - BESENCopyValue(Prop.Descriptor.Value,V); - end else begin - if Throw then begin - BESENThrowPut(Prop.Key); - end; - end; - exit; - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - PutSetter(self,Prop); - exit; - end; - end; - end; - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (ID=TBESEN(Instance).KeyIDManager.ProtoID) then begin - PutPrototype(V,Throw); - exit; - end; - Prop:=nil; - Obj:=Prototype; - while assigned(Obj) do begin - if (Index>=0) and (Index<Obj.Properties.ItemCount) then begin - Prop:=Obj.Properties.Items[Index]; - if assigned(Prop) and (Prop.ID=ID) and (([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[]) then begin - break; - end; - end; - Obj:=Obj.Prototype; - end; - if assigned(Obj) and assigned(Prop) then begin - if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - PutSetter(self,Prop); - exit; - end else begin - if not (Extensible and ((boppWRITABLE in Prop.Descriptor.Presents) and (bopaWRITABLE in Prop.Descriptor.Attributes))) then begin - if Throw then begin - BESENThrowPut(Prop.Key); - end; - exit; - end; - end; - end else begin - Obj:=self; - end; - if Extensible then begin - PutNew(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); - end; - if Throw then begin - ThrowIt; - end; -end; - -procedure TBESENObject.PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); -begin - Put(BESENArrayIndexToStr(Index),V,Throw); -end; - -procedure TBESENObject.Put(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); -var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; - Temp:TBESENValue; -begin - if Hash=0 then begin - Hash:=BESENHashKey(P); - end; - PutEx(P,V,Throw,Descriptor,OwnDescriptor,Temp,Hash); -end; - -function TBESENObject.HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - result:=GetProperty(P,Descriptor,Hash); -end; - -function TBESENObject.HasProperty(const P:TBESENString;Hash:TBESENHash=0):TBESENBoolean; -var Descriptor:TBESENObjectPropertyDescriptor; -begin - if Hash=0 then begin - Hash:=BESENHashKey(P); - end; - result:=HasPropertyEx(P,Descriptor,Hash); -end; - -function TBESENObject.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; - procedure ThrowIt; - begin - BESENThrowTypeError('Delete for "'+P+'" failed'); - end; -begin - if GetOwnProperty(P,Descriptor,Hash) then begin - if boppPROTO in Descriptor.Presents then begin - Prototype:=nil; - result:=true; - end else if (boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes) then begin - Properties.Remove(P,Hash); - result:=true; - end else begin - if Throw then begin - ThrowIt; - end; - result:=false; - end; - end else begin - result:=true; - end; -end; - -function TBESENObject.Delete(const P:TBESENString;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; -var Descriptor:TBESENObjectPropertyDescriptor; -begin - if Hash=0 then begin - Hash:=BESENHashKey(P); - end; - result:=DeleteEx(P,Throw,Descriptor,Hash); -end; - -function TBESENObject.DeleteIndex(const Index,ID:longint;Throw:TBESENBoolean):TBESENBoolean; -var Descriptor:TBESENObjectPropertyDescriptor; - Prop:TBESENObjectProperty; -begin - if (Index>=0) and (Index<Properties.ItemCount) then begin - Prop:=Properties.Items[Index]; - if assigned(Prop) and (Prop.ID=ID) then begin - result:=DeleteEx(Prop.Key,Throw,Descriptor); - exit; - end; - end; - result:=DeleteEx(TBESEN(Instance).KeyIDManager.List[ID],Throw,Descriptor); -end; - -function TBESENObject.DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; -begin - result:=Delete(BESENArrayIndexToStr(Index),Throw); -end; - -function TBESENObject.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -var Prop:TBESENObjectProperty; - CurrentResult:boolean; - procedure ThrowIt; - begin - BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); - end; -begin - result:=false; - CurrentResult:=GetOwnProperty(P,Current,Hash); - if not CurrentResult then begin - if Extensible then begin - if (([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Descriptor.Presents)=[]) or (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin - Prop:=Properties.Get(P,Hash); - if not assigned(Prop) then begin - Prop:=Properties.Put(P,Hash); - end; - BESENCopyValue(Prop.Descriptor.Value,Descriptor.Value); - Prop.Descriptor.Getter:=nil; - Prop.Descriptor.Setter:=nil; - Prop.Descriptor.Attributes:=Descriptor.Attributes; - Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - if Prop.ID>=0 then begin - InvalidateStructure; - end; - result:=true; - exit; - end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - Prop:=Properties.Get(P,Hash); - if not assigned(Prop) then begin - Prop:=Properties.Put(P,Hash); - end; - Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; - Prop.Descriptor.Getter:=Descriptor.Getter; - Prop.Descriptor.Setter:=Descriptor.Setter; - Prop.Descriptor.Attributes:=Descriptor.Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; - Prop.Descriptor.Presents:=[boppGETTER,boppSETTER,boppENUMERABLE,boppCONFIGURABLE]; - if Prop.ID>=0 then begin - InvalidateStructure; - end; - result:=true; - exit; - end; - end else begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end; - if Descriptor.Presents=[] then begin - result:=true; - exit; - end; - if boppPROTO in Current.Presents then begin - if ((([boppGETTER,boppSETTER]*Descriptor.Presents)=[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[])) and (boppVALUE in Descriptor.Presents) then begin - PutPrototype(Descriptor.Value,Throw); - result:=true; - end else begin - if Throw then begin - ThrowIt; - end; - end; - result:=true; - exit; - end; - if ((Descriptor.Presents*Current.Presents)=Descriptor.Presents) and - (((boppVALUE in Descriptor.Presents) and TBESEN(Instance).SameValue(Descriptor.Value,Current.Value)) or not (boppVALUE in Descriptor.Presents)) and - (((boppGETTER in Descriptor.Presents) and TBESEN(Instance).SameObject(TBESENObject(Descriptor.Getter),TBESENObject(Current.Getter))) or not (boppGETTER in Descriptor.Presents)) and - (((boppSETTER in Descriptor.Presents) and TBESEN(Instance).SameObject(TBESENObject(Descriptor.Setter),TBESENObject(Current.Setter))) or not (boppSETTER in Descriptor.Presents)) and - (((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppWRITABLE in Descriptor.Presents)) and - (((boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppENUMERABLE in Descriptor.Presents)) and - (((boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppCONFIGURABLE in Descriptor.Presents)) then begin - result:=true; - exit; - end; - if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin - if (((boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes))) or - ((((boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in Descriptor.Attributes)))<>(((boppENUMERABLE in Current.Presents) and (bopaENUMERABLE in Current.Attributes)))) then begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end; - if ([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Descriptor.Presents)=[] then begin - end else if (([boppVALUE,boppWRITABLE]*Current.Presents)<>[])<>(([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin - if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin - if Throw then begin - ThrowIt; - end; - exit; - end; - if ([boppVALUE,boppWRITABLE]*Current.Presents)<>[] then begin - Current.Value.ValueType:=bvtUNDEFINED; - Current.Getter:=nil; - Current.Setter:=nil; - Current.Attributes:=Current.Attributes*[bopaCONFIGURABLE,bopaENUMERABLE]; - Current.Presents:=Current.Presents*[boppCONFIGURABLE,boppENUMERABLE]; - end else begin - Current.Value.ValueType:=bvtUNDEFINED; - Current.Getter:=nil; - Current.Setter:=nil; - Current.Attributes:=Current.Attributes*[bopaCONFIGURABLE,bopaENUMERABLE]; - Current.Presents:=(Current.Presents*[boppCONFIGURABLE,boppENUMERABLE])+[boppVALUE]; - end; - end else if (([boppVALUE,boppWRITABLE]*Current.Presents)<>[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin - if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin - if (((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)) or - ((boppVALUE in Descriptor.Presents) and not (((boppVALUE in Current.Presents) and TBESEN(Instance).SameValue(Descriptor.Value,Current.Value)) or - (TBESEN(Instance).SameValue(Descriptor.Value,BESENUndefinedValue) and not (boppVALUE in Current.Presents))))) and not - ((boppWRITABLE in Current.Presents) and (bopaWRITABLE in Current.Attributes)) then begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end; - end else if (([boppGETTER,boppSETTER]*Current.Presents)<>[]) and (([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) then begin - if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin - if boppSETTER in Descriptor.Presents then begin - if boppSETTER in Current.Presents then begin - if not TBESEN(Instance).SameObject(TBESENObject(Descriptor.Setter),TBESENObject(Current.Setter)) then begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end else begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end; - if boppGETTER in Descriptor.Presents then begin - if boppGETTER in Current.Presents then begin - if not TBESEN(Instance).SameObject(TBESENObject(Descriptor.Getter),TBESENObject(Current.Getter)) then begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end else begin - if Throw then begin - ThrowIt; - end; - exit; - end; - end; - end; - end; - if boppVALUE in Descriptor.Presents then begin - Current.Presents:=Current.Presents+[boppVALUE]; - BESENCopyValue(Current.Value,Descriptor.Value); - end; - if boppGETTER in Descriptor.Presents then begin - Current.Presents:=Current.Presents+[boppGETTER]; - Current.Getter:=Descriptor.Getter; - end; - if boppSETTER in Descriptor.Presents then begin - Current.Presents:=Current.Presents+[boppSETTER]; - Current.Setter:=Descriptor.Setter; - end; - if boppWRITABLE in Descriptor.Presents then begin - Current.Presents:=Current.Presents+[boppWRITABLE]; - Current.Attributes:=(Current.Attributes-[bopaWRITABLE])+(Descriptor.Attributes*[bopaWRITABLE]); - end; - if boppENUMERABLE in Descriptor.Presents then begin - Current.Presents:=Current.Presents+[boppENUMERABLE]; - Current.Attributes:=(Current.Attributes-[bopaENUMERABLE])+(Descriptor.Attributes*[bopaENUMERABLE]); - end; - if boppCONFIGURABLE in Descriptor.Presents then begin - Current.Presents:=Current.Presents+[boppCONFIGURABLE]; - Current.Attributes:=(Current.Attributes-[bopaCONFIGURABLE])+(Descriptor.Attributes*[bopaCONFIGURABLE]); - end; - Prop:=Properties.Get(P,Hash); - if assigned(Prop) then begin - if (Prop.ID>=0) and ((Prop.Descriptor.Attributes<>Current.Attributes) or (Prop.Descriptor.Presents<>Current.Presents)) then begin - InvalidateStructure; - end; - end else begin - Prop:=Properties.Put(P,Hash); - end; - BESENCopyValue(Prop.Descriptor.Value,Current.Value); - Prop.Descriptor.Getter:=Current.Getter; - Prop.Descriptor.Setter:=Current.Setter; - Prop.Descriptor.Attributes:=Current.Attributes; - Prop.Descriptor.Presents:=Current.Presents; - result:=true; -end; - -function TBESENObject.DefineOwnProperty(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; -var Current:TBESENObjectPropertyDescriptor; -begin - result:=DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); -end; - -procedure TBESENObject.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); -var EffectiveHint:TBESENObject; - v:TBESENValue; - procedure ThrowIt; - begin - raise EBESENTypeError.Create('Bad default value'); - end; -begin - case AHint.ValueType of - bvtNUMBER:begin - EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; - end; - bvtSTRING:begin - EffectiveHint:=TBESEN(Instance).ObjectStringConstructor; - end; - bvtOBJECT:begin - if (AHint.Obj=TBESEN(Instance).ObjectNumberConstructor) or (AHint.Obj=TBESEN(Instance).ObjectStringConstructor) then begin - EffectiveHint:=TBESENObject(AHint.Obj); - end else if AHint.Obj=TBESEN(Instance).ObjectDateConstructor then begin - EffectiveHint:=TBESEN(Instance).ObjectStringConstructor; - end else begin - EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; - end; - end else begin - EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; - end; - end; - if EffectiveHint=TBESEN(Instance).ObjectStringConstructor then begin - Get('toString',v); - if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); - if AResult.ValueType<>bvtOBJECT then begin - exit; - end; - end; - Get('valueOf',v); - if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); - if AResult.ValueType<>bvtOBJECT then begin - exit; - end; - end; - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - AResult:=BESENStringValue('[object '+inttostr(ptruint(self))+']'); - end else begin - ThrowIt; - end; - end else if EffectiveHint=TBESEN(Instance).ObjectNumberConstructor then begin - Get('valueOf',v); - if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); - if AResult.ValueType<>bvtOBJECT then begin - exit; - end; - end; - Get('toString',v); - if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); - if AResult.ValueType<>bvtOBJECT then begin - exit; - end; - end; - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - AResult:=BESENStringValue('[object '+inttostr(ptruint(self))+']'); - end else begin - ThrowIt; - end; - end else begin - ThrowIt; - end; -end; - -function TBESENObject.Enumerator(GetOnlyOwnProperties,GetAllProperties:TBESENBoolean):TBESENObjectPropertyEnumerator; -begin - result:=TBESENObjectPropertyEnumerator.Create(Instance,self,GetOnlyOwnProperties,GetAllProperties); -end; - -procedure TBESENObject.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); -begin - AResult:=BESENUndefinedValue; -end; - -procedure TBESENObject.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); -begin - AResult:=BESENUndefinedValue; -end; - -function TBESENObject.HasInstance(const AInstance:TBESENValue):TBESENBoolean; -begin - result:=false; -end; - -function TBESENObject.GetSecurityDomain:pointer; -begin - result:=nil; -end; - -function TBESENObject.HasCall:TBESENBoolean; -begin - result:=false; -end; - -function TBESENObject.HasConstruct:TBESENBoolean; -begin - result:=false; -end; - -function TBESENObject.HasHasInstance:TBESENBoolean; -begin - result:=false; -end; - -function TBESENObject.HasEnumerator:TBESENBoolean; -begin - result:=false; -end; - -function TBESENObject.HasGetSecurityDomain:TBESENBoolean; -begin - result:=false; -end; - -procedure TBESENObject.Finalize; -var CurrentItem:TBESENObjectProperty; -begin - Prototype:=nil; - CurrentItem:=Properties.GetFirst; - while assigned(CurrentItem) do begin - TBESEN(Instance).GarbageCollector.FinalizeValue(CurrentItem.Descriptor.Value); - CurrentItem:=CurrentItem.Next; - end; - Properties.Clear; - inherited Finalize; -end; - -procedure TBESENObject.Mark; -var CurrentItem:TBESENObjectProperty; -begin - TBESEN(Instance).GarbageCollector.GrayIt(Prototype); - CurrentItem:=Properties.First; - while assigned(CurrentItem) do begin - TBESEN(Instance).GarbageCollector.GrayValue(CurrentItem.Descriptor.Value); - TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(CurrentItem.Descriptor.Getter)); - TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(CurrentItem.Descriptor.Setter)); - CurrentItem:=CurrentItem.Next; - end; - inherited Mark; -end; - -procedure BESENCheckObjectCoercible(const v:TBESENValue); {$ifdef caninline}inline;{$endif} -begin - case v.ValueType of - bvtUNDEFINED,bvtNULL,bvtREFERENCE,bvtLOCAL:begin - BESENThrowTypeError('CheckObjectCoercible failed'); - end; - end; -end; - -function BESENIsCallable(const v:TBESENValue):TBESENBoolean; {$ifdef caninline}inline;{$endif} -begin - result:=(v.ValueType=bvtOBJECT) and (assigned(v.Obj) and TBESENObject(v.Obj).HasCall); -end; - -end. diff --git a/3rd/besen/src/BESENObjectArgGetterFunction.pas b/3rd/besen/src/BESENObjectArgGetterFunction.pas deleted file mode 100644 index cb0ee4ce3..000000000 --- a/3rd/besen/src/BESENObjectArgGetterFunction.pas +++ /dev/null @@ -1,94 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectArgGetterFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; - -type TBESENObjectArgGetterFunction=class(TBESENObjectFunction) - public - Env:TBESENEnvironmentRecord; - ArgName:TBESENString; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasCall:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENErrors,BESENHashUtils; - -constructor TBESENObjectArgGetterFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='ArgGetter'; - Env:=nil; - ArgName:=''; -end; - -destructor TBESENObjectArgGetterFunction.Destroy; -begin - Env:=nil; - ArgName:=''; - inherited Destroy; -end; - -procedure TBESENObjectArgGetterFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - Env.GetBindingValue(ArgName,true,AResult,BESENHashKey(ArgName)); -end; - -function TBESENObjectArgGetterFunction.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectArgGetterFunction.Finalize; -begin - Env:=nil; - inherited Finalize; -end; - -procedure TBESENObjectArgGetterFunction.Mark; -begin - if assigned(Env) then begin - TBESEN(Instance).GarbageCollector.GrayIt(Env); - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectArgSetterFunction.pas b/3rd/besen/src/BESENObjectArgSetterFunction.pas deleted file mode 100644 index 60bac0587..000000000 --- a/3rd/besen/src/BESENObjectArgSetterFunction.pas +++ /dev/null @@ -1,99 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectArgSetterFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; - -type TBESENObjectArgSetterFunction=class(TBESENObjectFunction) - public - Env:TBESENEnvironmentRecord; - ArgName:TBESENString; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasCall:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENErrors,BESENHashUtils; - -constructor TBESENObjectArgSetterFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='ArgSetter'; - Env:=nil; - ArgName:=''; -end; - -destructor TBESENObjectArgSetterFunction.Destroy; -begin - Env:=nil; - ArgName:=''; - inherited Destroy; -end; - -procedure TBESENObjectArgSetterFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if CountArguments<1 then begin - Env.SetMutableBinding(ArgName,BESENUndefinedValue,true,BESENHashKey(ArgName)); - end else begin - Env.SetMutableBinding(ArgName,Arguments^[0]^,true,BESENHashKey(ArgName)); - end; - AResult.ValueType:=bvtUNDEFINED; -end; - -function TBESENObjectArgSetterFunction.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectArgSetterFunction.Finalize; -begin - Env:=nil; - inherited Finalize; -end; - -procedure TBESENObjectArgSetterFunction.Mark; -begin - if assigned(Env) then begin - TBESEN(Instance).GarbageCollector.GrayIt(Env); - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectArray.pas b/3rd/besen/src/BESENObjectArray.pas deleted file mode 100644 index 4db3bac2b..000000000 --- a/3rd/besen/src/BESENObjectArray.pas +++ /dev/null @@ -1,362 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectArray; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectArray=class(TBESENObject) - private - ArrayLength:TBESENUINT32; - function ToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; - function GetLen:TBESENUINT32; - procedure SetLen(NewLen:TBESENUINT32); - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; - procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; - function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - function GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; - procedure PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); override; - function DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - procedure Push(const AValue:TBESENValue); - property Len:TBESENUINT32 read GetLen write SetLen; - end; - -implementation - -uses BESEN,BESENUtils,BESENArrayUtils,BESENHashUtils,BESENGlobals, - BESENNumberUtils,BESENErrors; - -constructor TBESENObjectArray.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Array'; - ObjectName:='array'; - Len:=0; - ArrayLength:=0; - - Properties.Sort(true); - - inherited OverwriteData('length',BESENNumberValue(0),[bopaWRITABLE]); -end; - -destructor TBESENObjectArray.Destroy; -begin - inherited Destroy; -end; - -function TBESENObjectArray.ToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; -begin - result:=BESENArrayToIndex(AProp,v); -end; - -{procedure TBESENObjectArray.SetLen(const AValue:TBESENValue); -var NewLen,i:TBESENUInt32; -begin - NewLen:=TBESEN(Instance).ToUInt32(AValue); - if Len>NewLen then begin - for i:=Len+1 to NewLen do begin - inherited Delete(IndexToStr(i-1),true); - end; - end; - Len:=NewLen; -end;} - -function TBESENObjectArray.GetLen:TBESENUINT32; -var LenDesc:TBESENObjectPropertyDescriptor; -begin - GetOwnProperty('length',LenDesc,BESENLengthHash); - result:=TBESEN(Instance).ToUINT32(LenDesc.Value); - ArrayLength:=result; -end; - -procedure TBESENObjectArray.SetLen(NewLen:TBESENUINT32); -begin - ArrayLength:=NewLen; - inherited OverwriteData('length',BESENNumberValue(NewLen),[bopaWRITABLE]); -end; - -procedure TBESENObjectArray.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); -var Index:int64; - Prop:TBESENObjectProperty; -begin - // Trying faster pre-catching implementation first - if ToIndex(P,Index) then begin - if (Index>=0) and (Index<ArrayLength) then begin - Prop:=Properties.Get(P,Hash); - if assigned(Prop) then begin - if (([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[]) and (bopaWRITABLE in Prop.Descriptor.Attributes) then begin - BESENCopyValue(Prop.Descriptor.Value,v); - exit; - end; - end else if Extensible then begin - Prop:=Properties.Put(P,Hash); - if assigned(Prop) then begin - BESENCopyValue(Prop.Descriptor.Value,v); - Prop.Descriptor.Getter:=nil; - Prop.Descriptor.Setter:=nil; - Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; - if Prop.ID>=0 then begin - InvalidateStructure; - end; - exit; - end; - end; - end; - end; - - // Fallback to specification-conformant implementation - PutFull(P,V,Throw,Descriptor,OwnDescriptor,TempValue,Hash); -end; - -procedure TBESENObjectArray.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); -begin - if ID=TBESEN(Instance).KeyIDManager.LengthID then begin - Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); - end else if ((Index>=0) and (Index<Properties.ItemCount)) and assigned(Properties.Items[Index]) and (Properties.Items[Index].ID=ID) then begin - inherited PutIndex(Index,ID,V,Throw); - end else begin - Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); - end; -end; - -function TBESENObjectArray.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -var OldLenDesc,NewLenDesc:TBESENObjectPropertyDescriptor; - NewLen,OldLen:TBESENUInt32; - NewWritable:boolean; - Index:int64; - Num:double; -begin - GetOwnProperty('length',OldLenDesc,BESENLengthHash); - OldLen:=TBESEN(Instance).ToUINT32(OldLenDesc.Value); - if P='length' then begin - if not (boppVALUE in Descriptor.Presents) then begin - result:=inherited DefineOwnPropertyEx('length',Descriptor,Throw,Current,BESENLengthHash); - exit; - end; - NewLenDesc:=Descriptor; - NewLen:=TBESEN(Instance).ToUInt32(Descriptor.Value); - Num:=TBESEN(Instance).ToNum(Descriptor.Value); - if (NewLen<>Num) or not BESENIsFinite(Num) then begin - raise EBESENRangeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); - end; - if NewLen>=OldLen then begin - ArrayLength:=NewLen; - result:=inherited DefineOwnPropertyEx('length',Descriptor,Throw,Current,BESENLengthHash); - exit; - end; - if not ((boppWRITABLE in OldLenDesc.Presents) and (bopaWRITABLE in OldLenDesc.Attributes)) then begin - if Throw then begin - raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); - end else begin - result:=false; - exit; - end; - end; - if ((boppWRITABLE in NewLenDesc.Presents) and (bopaWRITABLE in NewLenDesc.Attributes)) or not (bopaWRITABLE in NewLenDesc.Attributes) then begin - NewWritable:=true; - end else begin - NewWritable:=false; - NewLenDesc.Presents:=NewLenDesc.Presents+[boppWRITABLE]; - NewLenDesc.Attributes:=NewLenDesc.Attributes+[bopaWRITABLE]; - end; - result:=inherited DefineOwnPropertyEx('length',NewLenDesc,Throw,Current,BESENLengthHash); - if not result then begin - exit; - end; - ArrayLength:=NewLen; - while NewLen<OldLen do begin - dec(OldLen); - if not Delete(BESENArrayIndexToStr(OldLen),false) then begin - NewLenDesc.Value:=BESENNumberValue(OldLen+1); - if not NewWritable then begin - NewLenDesc.Attributes:=NewLenDesc.Attributes-[bopaWRITABLE]; - end; - inherited DefineOwnPropertyEx('length',NewLenDesc,false,Current,BESENLengthHash); - if Throw then begin - raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); - end else begin - result:=false; - exit; - end; - end; - end; - if not NewWritable then begin - NewLenDesc:=BESENUndefinedPropertyDescriptor; - NewLenDesc.Presents:=NewLenDesc.Presents+[boppWRITABLE]; - NewLenDesc.Attributes:=NewLenDesc.Attributes-[bopaWRITABLE]; - inherited DefineOwnPropertyEx('length',NewLenDesc,false,Current,BESENLengthHash); - end; - result:=true; - end else if ToIndex(P,Index) then begin - if (Index>=OldLen) and not ((boppWRITABLE in OldLenDesc.Presents) and (bopaWRITABLE in OldLenDesc.Attributes)) then begin - if Throw then begin - raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); - end else begin - result:=false; - exit; - end; - end; - result:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); - if not result then begin - if Throw then begin - raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); - end else begin - result:=false; - exit; - end; - end; - if Index>=OldLen then begin - ArrayLength:=Index+1; - OldLenDesc.Value:=BESENNumberValue(Index+1); - inherited DefineOwnPropertyEx('length',OldLenDesc,false,Current,BESENLengthHash); - end; - result:=true; - end else begin - result:=inherited DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); - end; -end; - -function TBESENObjectArray.GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; - function Fallback:boolean; - begin - result:=Get(BESENArrayIndexToStr(Index),AResult,Base); - end; -var Prop:TBESENObjectProperty; -begin - result:=false; - if not assigned(Base) then begin - Base:=self; - end; - if Index<TBESENUINT32(Properties.ArrayItemCount) then begin - Prop:=Properties.ArrayGet(Index); - if assigned(Prop) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - BESENCopyValue(AResult,Prop.Descriptor.Value); - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - GetGetter(Base,AResult,Prop.Descriptor); - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; - result:=true; - exit; - end; - end; - result:=Fallback; -end; - -procedure TBESENObjectArray.PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); - procedure Fallback; - begin - Put(BESENArrayIndexToStr(Index),V,Throw); - end; - procedure PutSetter(Obj:TBESENObject;Prop:TBESENObjectProperty); - var TempValue:TBESENValue; - ValuePointers:array[0..0] of PBESENValue; - begin - if (boppSETTER in Prop.Descriptor.Presents) and assigned(Prop.Descriptor.Setter) then begin - ValuePointers[0]:=@V; - TBESEN(Instance).ObjectCall(TBESENObject(Prop.Descriptor.Setter),BESENObjectValue(Obj),@ValuePointers,1,TempValue); - exit; - end; - if Throw then begin - BESENThrowNoSetter(Prop.Key); - end; - end; -var Prop:TBESENObjectProperty; -begin - if Index<TBESENUINT32(Properties.ArrayItemCount) then begin - Prop:=Properties.ArrayGet(Index); - if assigned(Prop) then begin - if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin - if bopaWRITABLE in Prop.Descriptor.Attributes then begin - BESENCopyValue(Prop.Descriptor.Value,V); - end else begin - if Throw then begin - BESENThrowPut(Prop.Key); - end; - end; - exit; - end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin - PutSetter(self,Prop); - exit; - end; - end; - end; - Fallback; -end; - -function TBESENObjectArray.DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; - function Fallback:boolean; - begin - result:=Delete(BESENArrayIndexToStr(Index),Throw); - end; -var Prop:TBESENObjectProperty; -begin - if Index<TBESENUINT32(Properties.ArrayItemCount) then begin - Prop:=Properties.ArrayGet(Index); - if assigned(Prop) then begin - result:=Delete(Prop.Key,Throw); - exit; - end; - end; - result:=Fallback; -end; - -procedure TBESENObjectArray.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectArray.Mark; -begin - inherited Mark; -end; - -procedure TBESENObjectArray.Push(const AValue:TBESENValue); -var v,tv:TBESENValue; - ValuePointers:array[0..0] of PBESENValue; -begin - Get('push',v); - if (v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall then begin - ValuePointers[0]:=@AValue; - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),@ValuePointers,1,tv); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectArrayConstructor.pas b/3rd/besen/src/BESENObjectArrayConstructor.pas deleted file mode 100644 index 2590278e7..000000000 --- a/3rd/besen/src/BESENObjectArrayConstructor.pas +++ /dev/null @@ -1,123 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectArrayConstructor; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectArrayConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - procedure NativeIsArray(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENGlobals,BESENObjectArray,BESENNumberUtils,BESENErrors; - -constructor TBESENObjectArrayConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - - ObjectClassName:='Function'; - ObjectName:='Array'; - - RegisterNativeFunction('isArray',NativeIsArray,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectArrayConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectArrayConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectArray; - r3:TBESENValue; - l:int64; - i:integer; -begin - r3:=BESENEmptyValue; - r1:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(r1); - if CountArguments>0 then begin - r1.GarbageCollectorLock; - try - if (CountArguments=1) and (Arguments^[0]^.ValueType=bvtNUMBER) then begin - r3:=Arguments^[0]^; - l:=TBESEN(Instance).ToUInt32(r3); - if (l<>r3.Num) or not BESENIsFinite(r3.Num) then begin - raise EBESENRangeError.Create('Bad array length'); - end; - r1.Put('length',r3,true,BESENLengthHash); - end else begin - for i:=0 to CountArguments-1 do begin - r1.DefineOwnProperty(inttostr(i),BESENDataPropertyDescriptor(Arguments^[i]^,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); - end; - r3:=BESENNumberValue(CountArguments); - r1.Put('length',r3,true,BESENLengthHash); - end; - finally - r1.GarbageCollectorUnlock; - end; - end; - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=r1; -end; - -procedure TBESENObjectArrayConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - Construct(ThisArgument,Arguments,CountArguments,AResult); -end; - -function TBESENObjectArrayConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectArrayConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectArrayConstructor.NativeIsArray(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=(CountArguments>0) and (((Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) and (TBESENObject(Arguments^[0]^.Obj).ObjectClassName='Array')); -end; - -end. diff --git a/3rd/besen/src/BESENObjectArrayPrototype.pas b/3rd/besen/src/BESENObjectArrayPrototype.pas deleted file mode 100644 index 60bf971ec..000000000 --- a/3rd/besen/src/BESENObjectArrayPrototype.pas +++ /dev/null @@ -1,1330 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectArrayPrototype; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectArray,BESENValue,BESENObjectPropertyDescriptor, - BESENObjectBoolean; - -type TBESENObjectArrayPrototype=class(TBESENObjectArray) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeJoin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReverse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeShift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSort(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSplice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeUnshift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeEvery(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSome(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeForEach(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeMap(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeFilter(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReduce(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReduceRight(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors,BESENGlobals,BESENArrayUtils,BESENHashUtils,BESENNumberUtils,BESENStringUtils,BESENLocale; - -constructor TBESENObjectArrayPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Array'; - ObjectName:='Array'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('concat',NativeConcat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('join',NativeJoin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('pop',NativePop,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('push',NativePush,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('reverse',NativeReverse,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('shift',NativeShift,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('slice',NativeSlice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('sort',NativeSort,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('splice',NativeSplice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('unshift',NativeUnshift,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('indexOf',NativeIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('lastIndexOf',NativeLastIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('every',NativeEvery,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('some',NativeSome,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('forEach',NativeForEach,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('map',NativeMap,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('filter',NativeFilter,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('reduce',NativeReduce,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('reduceRight',NativeReduceRight,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectArrayPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectArrayPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v,ov:TBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('join',v); - if BESENIsCallable(v) then begin - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),ThisArgument,nil,0,ResultValue); - end else begin - TBESEN(Instance).ObjectPrototype.NativeToString(ThisArgument,Arguments,CountArguments,ResultValue); - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,v,vo,vs:TBESENValue; - i,l:int64; - Separator,s:TBESENString; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - Separator:=BESENLocaleFormatSettings.ListSeparator; - s:=''; - if l>0 then begin - i:=0; - while i<l do begin - if i>0 then begin - s:=s+Separator; - end; - TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(i),v); - TBESEN(Instance).ToObjectValue(v,vo); - if (vo.ValueType<>bvtOBJECT) or not assigned(TBESENObject(vo.Obj)) then begin - raise EBESENTypeError.Create('No valid object'); - end; - TBESENObject(vo.Obj).Get('toLocaleString',v); - if (v.ValueType<>bvtOBJECT) or not (assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall) then begin - raise EBESENTypeError.Create('No callable'); - end; - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),vo,nil,0,vs); - if v.ValueType<>bvtSTRING then begin - raise EBESENTypeError.Create('No string'); - end; - s:=s+TBESEN(Instance).ToStr(vs); - inc(i); - end; - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENStringValue(s); -end; - -procedure TBESENObjectArrayPrototype.NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var a,eA:TBESENObjectArray; - ov,e,v:TBESENValue; - l:int64; - pk:TBESENString; - k,n:int64; - i:integer; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - e:=BESENEmptyValue; - e:=BESENObjectValue(TBESENObject(ov.Obj)); - n:=0; - i:=0; - while true do begin - if (e.ValueType=bvtOBJECT) and assigned(e.Obj) and (e.Obj is TBESENObjectArray) then begin - eA:=TBESENObjectArray(e.Obj); - eA.Get('length',v,eA,BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - k:=0; - while k<l do begin - BESENArrayCheckTooLong(n,1); - pk:=BESENArrayIndexToStr(k); - if eA.Get(pk,v) then begin - a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - inc(n); - inc(k); - end; - end else begin - BESENArrayCheckTooLong(n,1); - A.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(e,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - inc(n); - end; - if i<CountArguments then begin - e:=Arguments^[i]^; - inc(i); - end else begin - break; - end; - end; - a.Len:=n; - finally - a.GarbageCollectorUnlock; - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(a); -end; - -procedure TBESENObjectArrayPrototype.NativeJoin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,v:TBESENValue; - i,l:int64; - UseComma:boolean; - Separator,s:TBESENString; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - v:=BESENEmptyValue; - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - UseComma:=(CountArguments=0) or (Arguments^[0]^.ValueType=bvtUNDEFINED); - if UseComma then begin - Separator:=','; - end else begin - Separator:=TBESEN(Instance).ToStr(Arguments^[0]^); - end; - s:=''; - if l>0 then begin - i:=0; - while i<l do begin - if i>0 then begin - s:=s+Separator; - end; - TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(i),v); - if not (v.ValueType in [bvtUNDEFINED,bvtNULL]) then begin - s:=s+TBESEN(Instance).ToStr(v); - end; - inc(i); - end; - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENStringValue(s); -end; - -procedure TBESENObjectArrayPrototype.NativePop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,v:TBESENValue; - l:int64; - si:TBESENString; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENUndefinedValue; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - if l=0 then begin - TBESENObject(ov.Obj).Put('length',BESENNumberValue(0),true,BESENLengthHash); - ResultValue:=BESENUndefinedValue; - end else begin - si:=BESENArrayIndexToStr(l-1); - TBESENObject(ov.Obj).Get(si,ResultValue); - TBESENObject(ov.Obj).Delete(si,true); - TBESENObject(ov.Obj).Put('length',BESENNumberValue(l-1),true,BESENLengthHash); - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativePush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,v:TBESENValue; - l:int64; - p:integer; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - for p:=0 to CountArguments-1 do begin - BESENArrayCheckTooLong(l,1); - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(l),Arguments^[p]^,true); - inc(l); - end; - TBESENObject(ov.Obj).Put('length',BESENNumberValue(l),true,BESENLengthHash); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENNumberValue(l); -end; - -procedure TBESENObjectArrayPrototype.NativeReverse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,uv,lv:TBESENValue; - l:int64; - up,lp:TBESENString; - middle,lower,upper:longword; - ue,le:TBESENBoolean; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - uv:=BESENEmptyValue; - lv:=BESENEmptyValue; - TBESENObject(ov.Obj).Get('length',lv,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(lv); - middle:=l shr 1; - lower:=0; - while lower<>middle do begin - upper:=l-(lower+1); - up:=BESENArrayIndexToStr(upper); - lp:=BESENArrayIndexToStr(lower); - le:=TBESENObject(ov.Obj).Get(lp,lv); - ue:=TBESENObject(ov.Obj).Get(up,uv); - if le and ue then begin - TBESENObject(ov.Obj).Put(lp,uv,true); - TBESENObject(ov.Obj).Put(up,lv,true); - end else if ue and not le then begin - TBESENObject(ov.Obj).Put(lp,uv,true); - TBESENObject(ov.Obj).Delete(up,true); - end else if le and not ue then begin - TBESENObject(ov.Obj).Put(up,lv,true); - TBESENObject(ov.Obj).Delete(lp,true); - end; - inc(lower); - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(TBESENObject(ov.Obj)); -end; - -procedure TBESENObjectArrayPrototype.NativeShift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,v:TBESENValue; - l,k:int64; - fp,tp:TBESENString; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - if l=0 then begin - TBESENObject(ov.Obj).Put('length',BESENNumberValue(0),true,BESENLengthHash); - ResultValue:=BESENUndefinedValue; - end else begin - TBESENObject(ov.Obj).Get('0',ResultValue); - k:=1; - while k<l do begin - fp:=BESENArrayIndexToStr(k); - tp:=BESENArrayIndexToStr(k-1); - if TBESENObject(ov.Obj).Get(fp,v) then begin - TBESENObject(ov.Obj).Put(tp,v,true); - end else begin - TBESENObject(ov.Obj).Delete(tp,true); - end; - inc(k); - end; - TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(l-1),true); - TBESENObject(ov.Obj).Put('length',BESENNumberValue(l-1),true,BESENLengthHash); - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var a:TBESENObjectArray; - ov,v:TBESENValue; - l:int64; - Pk:TBESENString; - rs,re,k,f,n:int64; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - rs:=TBESEN(Instance).ToInt32(Arguments^[0]^); - end else begin - rs:=0; - end; - if rs<0 then begin - k:=l+rs; - if k<0 then begin - k:=0; - end; - end else begin - k:=rs; - if l<k then begin - k:=l; - end; - end; - if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin - re:=TBESEN(Instance).ToInt32(Arguments^[1]^); - end else begin - re:=l; - end; - if re<0 then begin - f:=l+re; - if f<0 then begin - f:=0; - end; - end else begin - f:=re; - if l<f then begin - f:=l; - end; - end; - n:=0; - while k<f do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - inc(k); - inc(n); - end; - a.Put('length',BESENNumberValue(n),true,BESENLengthHash); - finally - a.GarbageCollectorUnlock; - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(a); -end; - -procedure TBESENObjectArrayPrototype.NativeSort(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var CompareFunction:TBESENObject; - ov,sva,svb:TBESENValue; - procedure IntroSort(Left,Right,Depth:int64); - function SortCompare(const x,y:TBESENValue):integer; - var vn:TBESENValue; - sx,sy:TBESENString; - ValuePointers:array[0..1] of PBESENValue; - begin - if (x.ValueType=bvtNONE) and (y.ValueType=bvtNONE) then begin - result:=0; - end else if x.ValueType=bvtNONE then begin - result:=1; - end else if y.ValueType=bvtNONE then begin - result:=-1; - end else if (x.ValueType=bvtUNDEFINED) and (y.ValueType=bvtUNDEFINED) then begin - result:=0; - end else if x.ValueType=bvtUNDEFINED then begin - result:=1; - end else if y.ValueType=bvtUNDEFINED then begin - result:=-1; - end else begin - if assigned(CompareFunction) then begin - ValuePointers[0]:=@x; - ValuePointers[1]:=@y; - TBESEN(Instance).ObjectCall(CompareFunction,ThisArgument,@ValuePointers,2,vn); - if (vn.ValueType<>bvtNUMBER) or BESENIsNaN(vn.Num) then begin - raise EBESENTypeError.Create('Array sort error'); - end; - if BESENIsNegative(vn.Num) then begin - result:=-1; - end else if not BESENIsZero(0) then begin - result:=1; - end else begin - result:=0; - end; - end else begin - sx:=TBESEN(Instance).ToStr(x); - sy:=TBESEN(Instance).ToStr(y); - if sx<sy then begin - result:=-1; - end else if sx>sy then begin - result:=1; - end else begin - result:=0; - end; - sx:=''; - sy:=''; - end; - end; - end; - procedure GetIndex(i:int64;var r:TBESENValue); - var s:TBESENString; - begin - s:=BESENArrayIndexToStr(i); - if not TBESENObject(ov.Obj).Get(s,r) then begin - r.ValueType:=bvtNONE; - end; - end; - procedure PutIndex(i:int64;const a:TBESENValue); - begin - if a.ValueType=bvtNONE then begin - TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(i),true); - end else begin - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(i),a,true); - end; - end; - function CompareIndex(const a,b:int64):integer; - begin - GetIndex(a,sva); - GetIndex(b,svb); - result:=SortCompare(sva,svb); - end; - procedure Swap(a,b:int64); - begin - GetIndex(a,sva); - GetIndex(b,svb); - PutIndex(b,sva); - PutIndex(a,svb); - end; - procedure SiftDown(Current,MaxIndex:int64); - var SiftLeft,SiftRight,Largest:int64; - sl,sr,l:TBESENValue; - begin - SiftLeft:=Left+(2*(Current-Left))+1; - SiftRight:=Left+(2*(Current-Left))+2; - Largest:=Current; - sl:=BESENEmptyValue; - sr:=BESENEmptyValue; - l:=BESENEmptyValue; - GetIndex(SiftLeft,sl); - GetIndex(Largest,l); - if (SiftLeft<=MaxIndex) and (SortCompare(sl,l)>0) then begin - Largest:=SiftLeft; - GetIndex(Largest,l); - end; - GetIndex(SiftRight,sr); - if (SiftRight<=MaxIndex) and (SortCompare(sr,l)>0) then begin - Largest:=SiftRight; - end; - if Largest<>Current then begin - Swap(Current,Largest); - SiftDown(Largest,MaxIndex); - end; - end; - procedure InsertionSort; - var i,j:int64; - t,x,v:TBESENValue; - begin - t:=BESENEmptyValue; - x:=BESENEmptyValue; - v:=BESENEmptyValue; - i:=Left+1; - while i<=Right do begin - GetIndex(i,t); - j:=i-1; - while j>=Left do begin - GetIndex(j,v); - if SortCompare(t,v)<0 then begin - GetIndex(j,x); - PutIndex(j+1,x); - dec(j); - end else begin - break; - end; - end; - PutIndex(j+1,t); - inc(i); - end; - end; - procedure HeapSort; - var i:int64; - begin - i:=((Left+Right+1) div 2)-1; - while i>=Left do begin - SiftDown(i,Right); - dec(i); - end; - i:=Right; - while i>=Left+1 do begin - Swap(i,Left); - SiftDown(Left,i-1); - dec(i); - end; - end; - procedure QuickSortWidthMedianOfThreeOptimization; - var Middle,i,j:integer; - Pivot,v:TBESENValue; - begin - Middle:=(Left+Right) div 2; - if (Right-Left)>3 then begin - if CompareIndex(Left,Middle)>0 then begin - Swap(Left,Middle); - end; - if CompareIndex(Left,Right)>0 then begin - Swap(Left,Right); - end; - if CompareIndex(Middle,Right)>0 then begin - Swap(Middle,Right); - end; - end; - Pivot:=BESENEmptyValue; - v:=BESENEmptyValue; - GetIndex(Middle,Pivot); - i:=Left; - j:=Right; - while true do begin - while i<j do begin - GetIndex(i,v); - if SortCompare(v,Pivot)<0 then begin - inc(i); - end else begin - break; - end; - end; - while j>i do begin - GetIndex(j,v); - if SortCompare(v,Pivot)>0 then begin - dec(j); - end else begin - break; - end; - end; - if i>j then begin - break; - end; - Swap(i,j); - inc(i); - dec(j); - end; - IntroSort(Left,j,Depth-1); - IntroSort(i,Right,Depth-1); - end; - begin - if Left<Right then begin - if (Right-Left)<16 then begin - InsertionSort; - end else if Depth=0 then begin - HeapSort; - end else begin - QuickSortWidthMedianOfThreeOptimization; - end; - end; - end; -var l:int64; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',sva,TBESENObject(ov.Obj),BESENLengthHash); - l:=TBESEN(Instance).ToUINT32(sva); - if CountArguments>0 then begin - if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and TBESENObject(Arguments^[0]^.Obj).HasCall then begin - CompareFunction:=TBESENObject(Arguments^[0]^.Obj); - end else begin - raise EBESENTypeError.Create('Bad argument'); - end; - end else begin - CompareFunction:=nil; - end; - IntroSort(0,l-1,BESENIntLog2(l)*2); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(TBESENObject(ov.Obj)); -end; - -procedure TBESENObjectArrayPrototype.NativeSplice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,v:TBESENValue; - A:TBESENObject; - r3,r5,r6,r17,k:TBESENUINT32; - s9,s11,s22,s33,s39:TBESENString; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - r3:=TBESEN(Instance).ToUINT32(v); - - if CountArguments<1 then begin - v:=BESENNumberValue(0); - end else begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - end; - if (-v.Num)>r3 then begin - r5:=0; - end else if BESENIsNegative(v.Num) then begin - r5:=trunc(r3+v.Num); - end else if v.Num<r3 then begin - r5:=trunc(v.Num); - end else begin - r5:=r3; - end; - - if CountArguments<2 then begin - v:=BESENNumberValue(0); - end else begin - TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); - end; - if BESENIsNegative(v.Num) then begin - r6:=0; - end else begin - r6:=trunc(v.Num); - end; - if (r3-r5)<r6 then begin - r6:=r3-r5; - end; - k:=0; - while k<r6 do begin - s9:=BESENArrayIndexToStr(r5+k); - if TBESENObject(ov.Obj).Get(s9,v) then begin - s11:=BESENArrayIndexToStr(k); - A.DefineOwnProperty(s11,BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - inc(k); - end; - - A.Put('length',BESENNumberValue(r6),true,BESENLengthHash); - if CountArguments<2 then begin - r17:=0; - end else begin - r17:=CountArguments-2; - end; - if r17<>r6 then begin - if r17<=r6 then begin - k:=r5; - while k<(r3-r6) do begin - s22:=BESENArrayIndexToStr(k+r6); - if TBESENObject(ov.Obj).Get(s22,v) then begin - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k+r17),v,true); - end else begin - TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(k+r17),true); - end; - inc(k); - end; - k:=r3; - while k>((r3+r17)-r6) do begin - s33:=BESENArrayIndexToStr(k-1); - TBESENObject(ov.Obj).Delete(s33,true); - dec(k); - end; - end else begin - k:=r3-r6; - while k>r5 do begin - s39:=BESENArrayIndexToStr(k+r6-1); - if TBESENObject(ov.Obj).Get(s39,v) then begin - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k+r17-1),v,true); - end else begin - TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(k+r17-1),true); - end; - dec(k); - end; - end; - end; - - k:=2; - while k<longword(CountArguments) do begin - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr((k+r5)-2),Arguments^[k]^,true); - inc(k); - end; - - TBESENObject(ov.Obj).Put('length',BESENNumberValue((r3+r17)-r6),true,BESENLengthHash); - finally - a.GarbageCollectorUnlock; - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(a); -end; - -procedure TBESENObjectArrayPrototype.NativeUnshift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var r2,r3,k:TBESENUINT32; - ov,v:TBESENValue; - p:TBESENString; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - r2:=TBESEN(Instance).ToUINT32(v); - r3:=CountArguments; - BESENArrayCheckTooLong(r2,r3); - k:=r2; - while k>0 do begin - p:=BESENArrayIndexToStr(k-1); - if TBESENObject(ov.Obj).Get(p,v) then begin - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr((k+r3)-1),v,true); - end else begin - TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr((k+r3)-1),true); - end; - dec(k); - end; - k:=0; - while k<r3 do begin - TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k),Arguments^[k]^,true); - inc(k); - end; - TBESENObject(ov.Obj).Put('length',BESENNumberValue(r2+r3),true,BESENLengthHash); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - ResultValue:=BESENUndefinedValue; -end; - -procedure TBESENObjectArrayPrototype.NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,sv,v:TBESENValue; - Len,n,k:int64; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=-1; - if Len>0 then begin - if CountArguments>0 then begin - sv:=Arguments^[0]^; - end else begin - sv:=BESENUndefinedValue; - end; - if CountArguments>1 then begin - n:=TBESEN(Instance).ToInt(Arguments^[1]^); - end else begin - n:=0; - end; - if n<Len then begin - if n<0 then begin - k:=Len-abs(n); - if k<0 then begin - k:=0; - end; - end else begin - k:=n; - end; - while k<Len do begin - if TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(k),v) then begin - if BESENEqualityExpressionStrictEquals(sv,v) then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=k; - break; - end; - end; - inc(k); - end; - end; - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,sv,v:TBESENValue; - Len,n,k:int64; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=-1; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if Len>0 then begin - if CountArguments>0 then begin - sv:=Arguments^[0]^; - end else begin - sv:=BESENUndefinedValue; - end; - if CountArguments>1 then begin - n:=TBESEN(Instance).ToInt(Arguments^[1]^); - end else begin - n:=Len-1; - end; - if n<0 then begin - k:=Len-abs(n); - end else begin - k:=min(n,Len-1); - end; - while k>=0 do begin - if TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(k),v) then begin - if BESENEqualityExpressionStrictEquals(sv,v) then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=k; - break; - end; - end; - dec(k); - end; - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeEvery(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,tv,v,vr,vi:TBESENValue; - Len,k:int64; - Pk:TBESENString; - ValuePointers:array[0..2] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - if CountArguments>1 then begin - tv:=Arguments^[1]^; - end else begin - tv:=BESENUndefinedValue; - end; - ValuePointers[0]:=@v; - ValuePointers[1]:=@vi; - ValuePointers[2]:=@ov; - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=true; - k:=0; - while k<Len do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); - if not TBESEN(Instance).ToBool(vr) then begin - ResultValue.Bool:=false; - break; - end; - end; - inc(k); - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeSome(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,tv,v,vr,vi:TBESENValue; - Len,k:int64; - Pk:TBESENString; - ValuePointers:array[0..2] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - if CountArguments>1 then begin - tv:=Arguments^[1]^; - end else begin - tv:=BESENUndefinedValue; - end; - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=false; - ValuePointers[0]:=@v; - ValuePointers[1]:=@vi; - ValuePointers[2]:=@ov; - k:=0; - while k<Len do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); - if TBESEN(Instance).ToBool(vr) then begin - ResultValue.Bool:=true; - break; - end; - end; - inc(k); - end; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeForEach(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,tv,v,vr,vi:TBESENValue; - Len,k:int64; - Pk:TBESENString; - ValuePointers:array[0..2] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - if CountArguments>1 then begin - tv:=Arguments^[1]^; - end else begin - tv:=BESENUndefinedValue; - end; - ValuePointers[0]:=@v; - ValuePointers[1]:=@vi; - ValuePointers[2]:=@ov; - k:=0; - while k<Len do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); - end; - inc(k); - end; - ResultValue.ValueType:=bvtUNDEFINED; - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeMap(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,tv,v,vr,vi:TBESENValue; - Len,k:int64; - Pk:TBESENString; - a:TBESENObjectArray; - ValuePointers:array[0..2] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - if CountArguments>1 then begin - tv:=Arguments^[1]^; - end else begin - tv:=BESENUndefinedValue; - end; - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - try - a.Len:=Len; - ValuePointers[0]:=@v; - ValuePointers[1]:=@vi; - ValuePointers[2]:=@ov; - k:=0; - while k<Len do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); - a.DefineOwnProperty(Pk,BESENDataPropertyDescriptor(vr,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - inc(k); - end; - finally - a.GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(a); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeFilter(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,tv,kv,vr,vi:TBESENValue; - Len,k,n:int64; - Pk:TBESENString; - a:TBESENObjectArray; - ValuePointers:array[0..2] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',kv,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(kv); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - if CountArguments>1 then begin - tv:=Arguments^[1]^; - end else begin - tv:=BESENUndefinedValue; - end; - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - try - ValuePointers[0]:=@kv; - ValuePointers[1]:=@vi; - ValuePointers[2]:=@ov; - k:=0; - n:=0; - while k<Len do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,kv) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); - if TBESEN(Instance).ToBool(vr) then begin - a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(kv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - inc(n); - end; - end; - inc(k); - end; - finally - a.GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(a); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeReduce(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,av,v,vi,nav:TBESENValue; - Len,k:int64; - Pk:TBESENString; - kPresent:boolean; - ValuePointers:array[0..3] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - k:=0; - if CountArguments>1 then begin - av:=Arguments^[1]^; - end else if Len=0 then begin - raise EBESENTypeError.Create('Reduce failed'); - end else begin - kPresent:=false; - while (k<Len) and not kPresent do begin - Pk:=BESENArrayIndexToStr(k); - kPresent:=TBESENObject(ov.Obj).HasProperty(Pk); - if kPresent then begin - TBESENObject(ov.Obj).Get(Pk,av); - end; - inc(k); - end; - if not kPresent then begin - raise EBESENTypeError.Create('Reduce failed'); - end; - end; - nav:=BesenUndefinedValue; - ValuePointers[0]:=@av; - ValuePointers[1]:=@v; - ValuePointers[2]:=@vi; - ValuePointers[3]:=@ov; - while k<Len do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),BESENUndefinedValue,@ValuePointers,4,nav); - BesenCopyValue(av,nav); - end; - inc(k); - end; - BESENCopyValue(ResultValue,av); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectArrayPrototype.NativeReduceRight(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,cv,av,v,vi,nav:TBESENValue; - Len,k:int64; - Pk:TBESENString; - kPresent:boolean; - ValuePointers:array[0..3] of PBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToUINT32(v); - if CountArguments>0 then begin - cv:=Arguments^[0]^; - end else begin - cv:=BESENUndefinedValue; - end; - if not BESENIsCallable(cv) then begin - raise EBESENTypeError.Create('Callback not callable'); - end; - k:=Len-1; - if CountArguments>1 then begin - av:=Arguments^[1]^; - end else if Len=0 then begin - raise EBESENTypeError.Create('Reduce failed'); - end else begin - kPresent:=false; - while (k>=0) and not kPresent do begin - Pk:=BESENArrayIndexToStr(k); - kPresent:=TBESENObject(ov.Obj).HasProperty(Pk); - if kPresent then begin - TBESENObject(ov.Obj).Get(Pk,av); - end; - dec(k); - end; - if not kPresent then begin - raise EBESENTypeError.Create('Reduce failed'); - end; - end; - nav:=BesenUndefinedValue; - ValuePointers[0]:=@av; - ValuePointers[1]:=@v; - ValuePointers[2]:=@vi; - ValuePointers[3]:=@ov; - while k>=0 do begin - Pk:=BESENArrayIndexToStr(k); - if TBESENObject(ov.Obj).Get(Pk,v) then begin - vi.ValueType:=bvtNUMBER; - vi.Num:=k; - TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),BESENUndefinedValue,@ValuePointers,4,nav); // ES5 errata fix - BesenCopyValue(av,nav); - end; - dec(k); - end; - BESENCopyValue(ResultValue,av); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectBindingFunction.pas b/3rd/besen/src/BESENObjectBindingFunction.pas deleted file mode 100644 index da3c0cbd3..000000000 --- a/3rd/besen/src/BESENObjectBindingFunction.pas +++ /dev/null @@ -1,191 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectBindingFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; - -type TBESENObjectBindingFunction=class(TBESENObjectFunction) - public - TargetFunction:TBESENObject; - BoundThis:TBESENValue; - BoundArguments:TBESENValues; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; - function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - function HasHasInstance:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENErrors,BESENHashUtils; - -constructor TBESENObjectBindingFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='Binding'; - TargetFunction:=nil; - BoundThis:=BESENUndefinedValue; - BoundArguments:=nil; -end; - -destructor TBESENObjectBindingFunction.Destroy; -begin - TargetFunction:=nil; - BoundThis:=BESENUndefinedValue; - SetLength(BoundArguments,0); - inherited Destroy; -end; - -function TBESENObjectBindingFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - result:=inherited GetEx(p,AResult,Descriptor,Base,Hash); -end; - -function TBESENObjectBindingFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - result:=inherited GetIndex(Index,ID,AResult,Base); -end; - -procedure TBESENObjectBindingFunction.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var CallArgs:TBESENValuePointers; - i,j:integer; -begin - CallArgs:=nil; - if assigned(TargetFunction) and TargetFunction.HasConstruct then begin - SetLength(CallArgs,length(BoundArguments)+CountArguments); - try - j:=0; - for i:=0 to length(BoundArguments)-1 do begin - CallArgs[j]:=@BoundArguments[i]; - inc(j); - end; - for i:=0 to CountArguments-1 do begin - CallArgs[j]:=Arguments^[i]; - inc(j); - end; - TargetFunction.Construct(BoundThis,@CallArgs[0],length(CallArgs),AResult); - finally - SetLength(CallArgs,0); - end; - end else begin - raise EBESENTypeError.Create('No hasConstruct'); - end; -end; - -procedure TBESENObjectBindingFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var CallArgs:TBESENValuePointers; - i,j:integer; -begin - CallArgs:=nil; - if assigned(TargetFunction) and TargetFunction.HasCall then begin - SetLength(CallArgs,length(BoundArguments)+CountArguments); - try - j:=0; - for i:=0 to length(BoundArguments)-1 do begin - CallArgs[j]:=@BoundArguments[i]; - inc(j); - end; - for i:=0 to CountArguments-1 do begin - CallArgs[j]:=Arguments^[i]; - inc(j); - end; - TBESEN(Instance).ObjectCall(TargetFunction,BoundThis,@CallArgs[0],length(CallArgs),AResult); - finally - SetLength(CallArgs,0); - end; - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; -end; - -function TBESENObjectBindingFunction.HasInstance(const AInstance:TBESENValue):TBESENBoolean; -begin - if not TargetFunction.HasHasInstance then begin - raise EBESENTypeError.Create('No hasInstance'); - end; - result:=assigned(TargetFunction) and TargetFunction.HasInstance(AInstance); -end; - -function TBESENObjectBindingFunction.HasConstruct:TBESENBoolean; -begin - result:=assigned(TargetFunction) and TargetFunction.HasConstruct; -end; - -function TBESENObjectBindingFunction.HasCall:TBESENBoolean; -begin - result:=assigned(TargetFunction) and TargetFunction.HasCall; -end; - -function TBESENObjectBindingFunction.HasHasInstance:TBESENBoolean; -begin - result:=assigned(TargetFunction) and TargetFunction.HasHasInstance; -end; - -procedure TBESENObjectBindingFunction.Finalize; -begin - TargetFunction:=nil; - BoundThis:=BESENUndefinedValue; - SetLength(BoundArguments,0); - inherited Finalize; -end; - -procedure TBESENObjectBindingFunction.Mark; -var i:integer; -begin - if assigned(TargetFunction) then begin - TBESEN(Instance).GarbageCollector.GrayIt(TargetFunction); - end; - TBESEN(Instance).GarbageCollector.GrayValue(BoundThis); - for i:=0 to length(BoundArguments)-1 do begin - TBESEN(Instance).GarbageCollector.GrayValue(BoundArguments[i]); - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectBoolean.pas b/3rd/besen/src/BESENObjectBoolean.pas deleted file mode 100644 index 118264e62..000000000 --- a/3rd/besen/src/BESENObjectBoolean.pas +++ /dev/null @@ -1,74 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectBoolean; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectBoolean=class(TBESENObject) - public - Value:TBESENBoolean; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENObjectBoolean.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Boolean'; - ObjectName:=''; - Value:=false; -end; - -destructor TBESENObjectBoolean.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectBoolean.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectBoolean.Mark; -begin - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectBooleanConstructor.pas b/3rd/besen/src/BESENObjectBooleanConstructor.pas deleted file mode 100644 index 8ad3c33fb..000000000 --- a/3rd/besen/src/BESENObjectBooleanConstructor.pas +++ /dev/null @@ -1,103 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectBooleanConstructor; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectBooleanConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENObjectBoolean; - -constructor TBESENObjectBooleanConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='Boolean'; -end; - -destructor TBESENObjectBooleanConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectBooleanConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectBoolean; -begin - r1:=TBESENObjectBoolean.Create(Instance,TBESEN(Instance).ObjectBooleanPrototype,false); - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - if CountArguments>0 then begin - r1.Value:=TBESEN(Instance).ToBool(Arguments^[0]^); - end else begin - r1.Value:=false; - end; - finally - r1.GarbageCollectorUnlock; - end; - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=r1; -end; - -procedure TBESENObjectBooleanConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if CountArguments<1 then begin - AResult.ValueType:=bvtBOOLEAN; - AResult.Bool:=false; - end else begin - TBESEN(Instance).ToBooleanValue(Arguments^[0]^,AResult); - end; -end; - -function TBESENObjectBooleanConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectBooleanConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -end. diff --git a/3rd/besen/src/BESENObjectBooleanPrototype.pas b/3rd/besen/src/BESENObjectBooleanPrototype.pas deleted file mode 100644 index 466a7536b..000000000 --- a/3rd/besen/src/BESENObjectBooleanPrototype.pas +++ /dev/null @@ -1,101 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectBooleanPrototype; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor, - BESENObjectBoolean; - -type TBESENObjectBooleanPrototype=class(TBESENObjectBoolean) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectBooleanPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype); - ObjectClassName:='Boolean'; - ObjectName:='Boolean'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectBooleanPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectBooleanPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if ThisArgument.ValueType=bvtBOOLEAN then begin - if ThisArgument.Bool then begin - ResultValue:=BESENStringValue('true'); - end else begin - ResultValue:=BESENStringValue('false'); - end; - end else if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) then begin - if TBESENObjectBoolean(TBESENObject(ThisArgument.Obj)).Value then begin - ResultValue:=BESENStringValue('true'); - end else begin - ResultValue:=BESENStringValue('false'); - end; - end else begin - raise EBESENTypeError.Create('Not a boolean object'); - end; -end; - -procedure TBESENObjectBooleanPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if ThisArgument.ValueType=bvtBOOLEAN then begin - BESENCopyValue(ResultValue,ThisArgument); - end else if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) then begin - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=TBESENObjectBoolean(TBESENObject(ThisArgument.Obj)).Value; - end else begin - raise EBESENTypeError.Create('Not a boolean object'); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectConsole.pas b/3rd/besen/src/BESENObjectConsole.pas deleted file mode 100644 index 531b0e9fc..000000000 --- a/3rd/besen/src/BESENObjectConsole.pas +++ /dev/null @@ -1,155 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectConsole; -{$i BESEN.inc} - -interface - -const BESENObjectConsoleSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}widestring{$endif}= -'/**'+#13#10+ -' * Console object for BESEN'+#13#10+ -' * @author Dmitry A. Soshnikov <dmitry.soshnikov@gmail.com>'+#13#10+ -' */'+#13#10+ -'(function initConsole(global) {'+#13#10+ -''+#13#10+ -' // helpers'+#13#10+ -''+#13#10+ -' var getClass = Object.prototype.toString;'+#13#10+ -' var timeMap = {};'+#13#10+ -''+#13#10+ -' function repeatSring(string, times) {'+#13#10+ -' return Array(times + 1).join(string);'+#13#10+ -' }'+#13#10+ -''+#13#10+ -' function dir(object, deep, level) {'+#13#10+ -' level || (level = 1);'+#13#10+ -' typeof deep == "undefined" && (deep = true);'+#13#10+ -' var openBracket, closeBracket;'+#13#10+ -' if (Array.isArray(object)) {'+#13#10+ -' openBracket = "["; closeBracket = "]"'+#13#10+ -' } else {'+#13#10+ -' openBracket = "{"; closeBracket = "}"'+#13#10+ -' }'+#13#10+ -' var props = [];'+#13#10+ -' var indent = repeatSring(console.dir.indention, level);'+#13#10+ -' if (console.dir.showInternals) {'+#13#10+ -' props.push(indent + "[[Class]]: \"" + getClass.call(object).slice(8, -1) + "\"");'+#13#10+ -' }'+#13#10+ -' var data, current, currentClass;'+#13#10+ -' var goDeeper = (typeof deep == "number" ? deep > level : deep);'+#13#10+ -' Object.getOwnPropertyNames(object).forEach(function (property) {'+#13#10+ -' current = object[property];'+#13#10+ -' currentClass = getClass.call(current);'+#13#10+ -' if (goDeeper && (currentClass == "[object Object]" || Array.isArray(current))) {'+#13#10+ -' data = dir(current, deep, level + 1);'+#13#10+ -' } else {'+#13#10+ -' data = ('+#13#10+ -' typeof current == "function" ? "function" : ('+#13#10+ -' Array.isArray(current) ? "[" + current + "]" :'+#13#10+ -' (currentClass == "[object String]" ? "\"" + current + "\"" : current)'+#13#10+ -' )'+#13#10+ -' );'+#13#10+ -' }'+#13#10+ -' props.push(indent + property + ": " + data);'+#13#10+ -' });'+#13#10+ -' return "".concat('+#13#10+ -' openBracket, "\n", props.join(",\n"), "\n",'+#13#10+ -' (level > 1 ? repeatSring(console.dir.indention, level - 1) : ""),'+#13#10+ -' closeBracket'+#13#10+ -' );'+#13#10+ -' }'+#13#10+ -''+#13#10+ -' /**'+#13#10+ -' * console object;'+#13#10+ -' * implements: log, dir, time, timeEnd'+#13#10+ -' */'+#13#10+ -' global.console = {'+#13#10+ -''+#13#10+ -' /**'+#13#10+ -' * simple log using toString'+#13#10+ -' */'+#13#10+ -' log: function(){'+#13#10+ -' var s = "", a = arguments, j = +a.length;'+#13#10+ -' for(var i=0;i<j;i++) s += a[i] + " ";'+#13#10+ -' println(s);'+#13#10+ -' },'+#13#10+ -''+#13#10+ -' /**'+#13#10+ -' * dir an object'+#13#10+ -' * @param {Object} object'+#13#10+ -' * @param {Variant} deep - level of depth, default is {Boolean} true'+#13#10+ -' * can be set also to {Number} value specifying needed level of depth'+#13#10+ -' * Examples:'+#13#10+ -' * - console.dir(obj) // console.dir(obj, true)'+#13#10+ -' * - console.dir(obj, false); // only first level is shown'+#13#10+ -' * - console.dir(obj, 3); // properties of three levels are shown'+#13#10+ -' */'+#13#10+ -' dir: function (object, deep) {'+#13#10+ -' // if called for a primitive'+#13#10+ -' if (Object(object) !== object) {'+#13#10+ -' return console.log(object);'+#13#10+ -' }'+#13#10+ -' // else for an object'+#13#10+ -' return println(dir(object, deep));'+#13#10+ -' },'+#13#10+ -''+#13#10+ -' // time functions borrowed from Firebug'+#13#10+ -''+#13#10+ -' /**'+#13#10+ -' * time start'+#13#10+ -' */'+#13#10+ -' time: function(name) {'+#13#10+ -' timeMap[name] = Date.now();'+#13#10+ -' },'+#13#10+ -''+#13#10+ -' /**'+#13#10+ -' * time end'+#13#10+ -' */'+#13#10+ -' timeEnd: function(name) {'+#13#10+ -' if (name in timeMap) {'+#13#10+ -' var delta = Date.now() - timeMap[name];'+#13#10+ -' println(name + ": ", delta + "ms");'+#13#10+ -' delete timeMap[name];'+#13#10+ -' }'+#13#10+ -' }'+#13#10+ -' };'+#13#10+ -''+#13#10+ -' // indention for dir, default is 4 spaces'+#13#10+ -' console.dir.indention = " ";'+#13#10+ -''+#13#10+ -' // whether to show internal properties such as [[Class]]'+#13#10+ -' console.dir.showInternals = true;'+#13#10+ -''+#13#10+ -'})(this);'+#13#10; - -implementation - -end. diff --git a/3rd/besen/src/BESENObjectConstructor.pas b/3rd/besen/src/BESENObjectConstructor.pas deleted file mode 100644 index afd5ed97e..000000000 --- a/3rd/besen/src/BESENObjectConstructor.pas +++ /dev/null @@ -1,457 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectConstructor; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - procedure NativeGetPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetOwnPropertyDescriptor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetOwnPropertyNames(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCreate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeDefineProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeDefineProperties(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSeal(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeFreeze(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePreventExtensions(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIsSealed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIsFrozen(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIsExtensible(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeKeys(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENUtils,BESENArrayUtils,BESENErrors,BESENObjectString,BESENObjectArray; - -constructor TBESENObjectConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - - RegisterNativeFunction('getPrototypeOf',NativeGetPrototypeOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getOwnPropertyDescriptor',NativeGetOwnPropertyDescriptor,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getOwnPropertyNames',NativeGetOwnPropertyNames,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('create',NativeCreate,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('defineProperty',NativeDefineProperty,3,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('defineProperties',NativeDefineProperties,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('seal',NativeSeal,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('freeze',NativeFreeze,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('preventExtensions',NativePreventExtensions,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('isSealed',NativeIsSealed,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('isFrozen',NativeIsFrozen,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('isExtensible',NativeIsExtensible,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('keys',NativeKeys,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if CountArguments>0 then begin - case Arguments^[0]^.ValueType of - bvtNULL,bvtUNDEFINED:begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); - end; - else begin - TBESEN(Instance).ToObjectValue(Arguments^[0]^,AResult); - end; - end; - end else begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); - end; - if (AResult.ValueType=bvtOBJECT) and assigned(AResult.Obj) then begin - TBESEN(Instance).GarbageCollector.Add(TBESENObject(AResult.Obj)); - end; -end; - -procedure TBESENObjectConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - Construct(ThisArgument,Arguments,CountArguments,AResult); -end; - -function TBESENObjectConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectConstructor.NativeGetPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin - raise EBESENTypeError.Create('No object'); - end; - ResultValue:=BESENObjectValueEx(TBESENObject(Arguments^[0]^.Obj).Prototype); -end; - -procedure TBESENObjectConstructor.NativeGetOwnPropertyDescriptor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var n:TBESENString; - Descriptor:TBESENObjectPropertyDescriptor; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin - raise EBESENTypeError.Create('No object'); - end; - if CountArguments>1 then begin - n:=TBESEN(Instance).ToStr(Arguments^[1]^); - end else begin - n:=''; - end; - TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(n,Descriptor); - TBESEN(Instance).FromPropertyDescriptor(Descriptor,ResultValue); - if (ResultValue.ValueType=bvtOBJECT) and assigned(ResultValue.Obj) then begin - TBESEN(Instance).GarbageCollector.Add(TBESENObject(ResultValue.Obj)); - end; -end; - -procedure TBESENObjectConstructor.NativeGetOwnPropertyNames(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ArrayObject:TBESENObjectArray; - o:TBESENObject; - PropItem:TBESENObjectProperty; - n:longword; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin - raise EBESENTypeError.Create('No object'); - end; - ArrayObject:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ArrayObject); - ArrayObject.GarbageCollectorLock; - try - o:=TBESENObject(Arguments^[0]^.Obj); - if o is TBESENObjectString then begin - for n:=1 to length(TBESENObjectString(o).Value) do begin - ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(n-1),BESENDataPropertyDescriptor(BESENStringValue(BESENArrayIndexToStr(n-1)),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - n:=length(TBESENObjectString(o).Value); - end else begin - n:=0; - end; - PropItem:=o.Properties.First; - while assigned(PropItem) do begin - ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(BESENStringValue(PropItem.Key),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - inc(n); - PropItem:=PropItem.Next; - end; - ArrayObject.Len:=n; - finally - ArrayObject.GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(ArrayObject); -end; - -procedure TBESENObjectConstructor.NativeCreate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var o:TBESENObject; - vo:TBESENValue; - ValuePointers:array[0..1] of PBESENValue; -begin - if not ((CountArguments>0) and ((Arguments^[0]^.ValueType=bvtNULL) or ((Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)))) then begin - raise EBESENTypeError.Create('No object and not null'); - end; - if Arguments^[0]^.ValueType=bvtNULL then begin - o:=TBESENObject.Create(Instance,nil); - end else begin - o:=TBESENObject.Create(Instance,TBESENObject(Arguments^[0]^.Obj)); - end; - if CountArguments>1 then begin - vo.ValueType:=bvtOBJECT; - TBESENObject(vo.Obj):=o; - ValuePointers[0]:=@vo; - ValuePointers[1]:=Arguments^[1]; - NativeDefineProperties(ThisArgument,@ValuePointers,CountArguments,ResultValue); - end; - ResultValue.ValueType:=bvtOBJECT; - ResultValue.Obj:=o; -end; - -procedure TBESENObjectConstructor.NativeDefineProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var n:TBESENString; - Descriptor:TBESENObjectPropertyDescriptor; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin - raise EBESENTypeError.Create('No object'); - end; - if CountArguments>1 then begin - n:=TBESEN(Instance).ToStr(Arguments^[1]^); - end else begin - n:=''; - end; - if CountArguments>2 then begin - TBESEN(Instance).ToPropertyDescriptor(Arguments^[2]^,Descriptor); - end else begin - Descriptor:=BESENUndefinedPropertyDescriptor; - end; - TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(n,Descriptor,true); - BESENCopyValue(ResultValue,Arguments^[0]^); -end; - -procedure TBESENObjectConstructor.NativeDefineProperties(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Props:TBESENObject; - Names:TBESENStrings; - Descriptors:TBESENObjectPropertyDescriptors; - Enumerator:TBESENObjectPropertyEnumerator; - i,Count:integer; - v:TBESENValue; - Key:TBESENString; -begin - Names:=nil; - Descriptors:=nil; - Enumerator:=nil; - Key:=''; - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin - raise EBESENTypeError.Create('No object'); - end; - try - if CountArguments>1 then begin - Props:=TBESEN(Instance).ToObj(Arguments^[1]^); - end else begin - Props:=TBESEN(Instance).ToObj(BESENUndefinedValue); - end; - TBESEN(Instance).GarbageCollector.Add(Props); - Props.GarbageCollectorLock; - try - Count:=0; - Enumerator:=Props.Enumerator(true,false); - Enumerator.Reset; - while Enumerator.GetNext(Key) do begin - if Count>=length(Names) then begin - SetLength(Names,Count+256); - end; - if Count>=length(Descriptors) then begin - SetLength(Descriptors,Count+256); - end; - Names[Count]:=Key; - Props.Get(Key,v); - TBESEN(Instance).ToPropertyDescriptor(v,Descriptors[Count]); - inc(Count); - end; - for i:=0 to Count-1 do begin - TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Names[i],Descriptors[i],true); - end; - finally - Props.GarbageCollectorUnlock; - end; - finally - BESENFreeAndNil(Enumerator); - SetLength(Names,0); - SetLength(Descriptors,0); - end; - ResultValue:=Arguments^[0]^; -end; - - -procedure TBESENObjectConstructor.NativeSeal(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Descriptor:TBESENObjectPropertyDescriptor; - Enumerator:TBESENObjectPropertyEnumerator; - Key:TBESENString; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin - raise EBESENTypeError.Create('No object'); - end; - Enumerator:=nil; - Key:=''; - try - Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); - Enumerator.Reset; - while Enumerator.GetNext(Key) do begin - TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); - Descriptor.Attributes:=Descriptor.Attributes-[bopaCONFIGURABLE]; - TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Key,Descriptor,true); - end; - finally - BESENFreeAndNil(Enumerator); - end; - TBESENObject(Arguments^[0]^.Obj).Extensible:=false; - BESENCopyValue(ResultValue,Arguments^[0]^); -end; - -procedure TBESENObjectConstructor.NativeFreeze(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Descriptor:TBESENObjectPropertyDescriptor; - Enumerator:TBESENObjectPropertyEnumerator; - Key:TBESENString; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin - raise EBESENTypeError.Create('No object'); - end; - Enumerator:=nil; - Key:=''; - try - Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); - Enumerator.Reset; - while Enumerator.GetNext(Key) do begin - TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); - if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin - Descriptor.Attributes:=Descriptor.Attributes-[bopaWRITABLE]; - end; - Descriptor.Attributes:=Descriptor.Attributes-[bopaCONFIGURABLE]; - TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Key,Descriptor,true); - end; - finally - BESENFreeAndNil(Enumerator); - end; - TBESENObject(Arguments^[0]^.Obj).Extensible:=false; - BESENCopyValue(ResultValue,Arguments^[0]^); -end; - -procedure TBESENObjectConstructor.NativePreventExtensions(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin - raise EBESENTypeError.Create('No object'); - end; - TBESENObject(Arguments^[0]^.Obj).Extensible:=false; - BESENCopyValue(ResultValue,Arguments^[0]^); -end; - -procedure TBESENObjectConstructor.NativeIsSealed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Descriptor:TBESENObjectPropertyDescriptor; - Enumerator:TBESENObjectPropertyEnumerator; - Key:TBESENString; - IsSealed:boolean; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin - raise EBESENTypeError.Create('No object'); - end; - IsSealed:=true; - Enumerator:=nil; - Key:=''; - try - Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); - Enumerator.Reset; - while Enumerator.GetNext(Key) do begin - TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); - if (boppCONFIGURABLE In Descriptor.Presents) and (bopaCONFIGURABLE In Descriptor.Attributes) then begin - IsSealed:=false; - break; - end; - end; - finally - BESENFreeAndNil(Enumerator); - end; - if TBESENObject(Arguments^[0]^.Obj).Extensible then begin - IsSealed:=false; - end; - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=IsSealed; -end; - -procedure TBESENObjectConstructor.NativeIsFrozen(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Descriptor:TBESENObjectPropertyDescriptor; - Enumerator:TBESENObjectPropertyEnumerator; - Key:TBESENString; - IsFrozen:boolean; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin - raise EBESENTypeError.Create('No object'); - end; - IsFrozen:=true; - Enumerator:=nil; - Key:=''; - try - Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); - Enumerator.Reset; - while Enumerator.GetNext(Key) do begin - TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); - if ((([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) and ((boppWRITABLE In Descriptor.Presents) and (bopaWRITABLE In Descriptor.Attributes))) or - ((boppCONFIGURABLE In Descriptor.Presents) and (bopaCONFIGURABLE In Descriptor.Attributes)) then begin - IsFrozen:=false; - break; - end; - end; - finally - BESENFreeAndNil(Enumerator); - end; - if TBESENObject(Arguments^[0]^.Obj).Extensible then begin - IsFrozen:=false; - end; - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=IsFrozen; -end; - -procedure TBESENObjectConstructor.NativeIsExtensible(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin - raise EBESENTypeError.Create('No object'); - end; - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=TBESENObject(Arguments^[0]^.Obj).Extensible; -end; - -procedure TBESENObjectConstructor.NativeKeys(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ArrayObject:TBESENObjectArray; - Enumerator:TBESENObjectPropertyEnumerator; - Key:TBESENString; - Index:longword; -begin - if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin - raise EBESENTypeError.Create('No object'); - end; - ArrayObject:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ArrayObject); - ArrayObject.GarbageCollectorLock; - try - Index:=0; - Enumerator:=nil; - Key:=''; - try - Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,false); - Enumerator.Reset; - while Enumerator.GetNext(Key) do begin - ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENDataPropertyDescriptor(BESENStringValue(Key),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - inc(Index); - end; - finally - BESENFreeAndNil(Enumerator); - end; - ArrayObject.Len:=Index; - finally - ArrayObject.GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(ArrayObject); -end; - -end. diff --git a/3rd/besen/src/BESENObjectDate.pas b/3rd/besen/src/BESENObjectDate.pas deleted file mode 100644 index d6572d073..000000000 --- a/3rd/besen/src/BESENObjectDate.pas +++ /dev/null @@ -1,95 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectDate; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectDate=class(TBESENObject) - public - Value:TBESENDate; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENObjectDate.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Date'; - ObjectName:=''; - - Value:=Now; -end; - -destructor TBESENObjectDate.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectDate.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); -begin - case AHint.ValueType of - bvtNUMBER,bvtSTRING:begin - inherited DefaultValue(AHint,AResult); - end; - bvtOBJECT:begin - if AHint.Obj<>TBESEN(Instance).ObjectNumberConstructor then begin - inherited DefaultValue(TBESEN(Instance).ObjectStringConstructorValue,AResult); - end else begin - inherited DefaultValue(AHint,AResult); - end; - end; - else begin - inherited DefaultValue(TBESEN(Instance).ObjectStringConstructorValue,AResult); - end; - end; -end; - -procedure TBESENObjectDate.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectDate.Mark; -begin - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectDateConstructor.pas b/3rd/besen/src/BESENObjectDateConstructor.pas deleted file mode 100644 index 7da26baed..000000000 --- a/3rd/besen/src/BESENObjectDateConstructor.pas +++ /dev/null @@ -1,231 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectDateConstructor; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectDateConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - procedure NativeNow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeUTC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors,BESENASTNodes,BESENStringUtils,BESENUtils,BESENObjectDate,BESENDateUtils,BESENNumberUtils,BESENLocale; - -constructor TBESENObjectDateConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='Date'; - - RegisterNativeFunction('now',NativeNow,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('parse',NativeParse,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('UTC',NativeUTC,7,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectDateConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectDateConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectDate; - r3:TBESENValue; - s:TBESENString; - year,month,date,hours,minutes,seconds,ms:TBESENNumber; -begin - r3:=BESENEmptyValue; - r1:=TBESENObjectDate.Create(Instance,TBESEN(Instance).ObjectDatePrototype,false); - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - if CountArguments=0 then begin - r1.Value:=BESENTimeClip(BESENDateTimeToBESENDate(BESENGetUTCDateTime)); - end else if CountArguments=1 then begin - TBESEN(Instance).ToPrimitiveValue(Arguments^[0]^,TBESEN(Instance).ObjectNumberConstructorValue,r3); - if r3.ValueType<>bvtSTRING then begin - r1.Value:=BESENTimeClip(TBESEN(Instance).ToNum(r3)); - end else begin - s:=TBESEN(Instance).ToStr(r3); - r1.Value:=BESENParseTime(s); - if BESENIsNaN(r1.Value) then begin - r1.Value:=BESENParseISOTime(s); - if BESENIsNaN(r1.Value) then begin - r1.Value:=BESENParseNetscapeTime(s); - if BESENIsNaN(r1.Value) then begin - try - r1.Value:=BESENTimeClip(BESENDateTimeToBESENDate(BESENLocalDateTimeToUTC(StrToDateTime(s{$if ((FPC_VERSION>=3) or ((FPC_VERSION>=2) and ((FPC_RELEASE>=5) or ((FPC_RELEASE>=4) and (FPC_PATCH>=1)))))},BESENLocaleFormatSettings{$ifend})))); - except - r1.Value:=double(pointer(@BESENDoubleNaN)^); - end; - end; - end; - end; - end; - end else if CountArguments>1 then begin - year:=TBESEN(Instance).ToNum(Arguments^[0]^); - month:=TBESEN(Instance).ToNum(Arguments^[1]^); - date:=1; - hours:=0; - minutes:=0; - seconds:=0; - ms:=0; - if CountArguments>2 then begin - date:=TBESEN(Instance).ToNum(Arguments^[2]^); - if CountArguments>3 then begin - hours:=TBESEN(Instance).ToNum(Arguments^[3]^); - if CountArguments>4 then begin - minutes:=TBESEN(Instance).ToNum(Arguments^[4]^); - if CountArguments>5 then begin - seconds:=TBESEN(Instance).ToNum(Arguments^[5]^); - if CountArguments>6 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[6]^); - end; - end; - end; - end; - end; - r1.Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENMakeTime(Hours,Minutes,Seconds,ms))); - end; - finally - r1.GarbageCollectorUnlock; - end; - AResult:=BESENObjectValue(r1); -end; - -procedure TBESENObjectDateConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var Value:TBESENDate; -begin - Value:=BESENTimeClip(BESENGetUTCBESENDate); - if BESENIsNaN(Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - AResult:=BESENStringValue('Invalid Date'); - end else begin - AResult:=BESENStringValue('NaN'); - end; - end else begin - AResult:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyyy hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(Value)),BESENDefaultFormatSettings)+' GMT'+BESENGetDateTimeOffsetString(BESENGetLocalDateTimeZone)); - end; -end; - -procedure TBESENObjectDateConstructor.NativeNow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue:=BESENNumberValue(BESENGetUTCBESENDate); -end; - -procedure TBESENObjectDateConstructor.NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENNumber; - s:TBESENString; -begin - try - if CountArguments>0 then begin - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - v:=BESENParseTime(s); - if BESENIsNaN(v) then begin - v:=BESENParseISOTime(s); - if BESENIsNaN(v) then begin - v:=BESENParseNetscapeTime(s); - if BESENIsNaN(v) then begin - try - v:=BESENTimeClip(BESENDateTimeToBESENDate(BESENLocalDateTimeToUTC(StrToDateTime(s{$if ((FPC_VERSION>=3) or ((FPC_VERSION>=2) and ((FPC_RELEASE>=5) or ((FPC_RELEASE>=4) and (FPC_PATCH>=1)))))},BESENLocaleFormatSettings{$ifend})))); - except - v:=double(pointer(@BESENDoubleNaN)^); - end; - end; - end; - end; - ResultValue:=BESENNumberValue(v); - end else begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end; - finally - end; -end; - -procedure TBESENObjectDateConstructor.NativeUTC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var year,month,date,hours,minutes,seconds,ms:TBESENNumber; -begin - try - if CountArguments>1 then begin - year:=TBESEN(Instance).ToNum(Arguments^[0]^); - month:=TBESEN(Instance).ToNum(Arguments^[1]^); - date:=1; - hours:=0; - minutes:=0; - seconds:=0; - ms:=0; - if CountArguments>2 then begin - date:=TBESEN(Instance).ToNum(Arguments^[2]^); - if CountArguments>3 then begin - hours:=TBESEN(Instance).ToNum(Arguments^[3]^); - if CountArguments>4 then begin - minutes:=TBESEN(Instance).ToNum(Arguments^[4]^); - if CountArguments>5 then begin - seconds:=TBESEN(Instance).ToNum(Arguments^[5]^); - if CountArguments>6 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[6]^); - end; - end; - end; - end; - end; - ResultValue:=BESENNumberValue(BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENMakeTime(Hours,Minutes,Seconds,ms)))); - end else begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end; - finally - end; -end; - -function TBESENObjectDateConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectDateConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectDatePrototype.pas b/3rd/besen/src/BESENObjectDatePrototype.pas deleted file mode 100644 index bd095da39..000000000 --- a/3rd/besen/src/BESENObjectDatePrototype.pas +++ /dev/null @@ -1,1082 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectDatePrototype; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectDate,BESENValue,BESENObjectPropertyDescriptor, - BESENRegExp; - -type TBESENObjectDatePrototype=class(TBESENObjectDate) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToUTCString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetTimezoneOffset(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToGMTString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToISOString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToJSON(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors,BESENNumberUtils,BESENArrayUtils,BESENDateUtils,BESENLocale; - -constructor TBESENObjectDatePrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Date'; - ObjectName:='Date'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toDateString',NativeToDateString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toTimeString',NativeToTimeString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleDateString',NativeToLocaleDateString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleTimeString',NativeToLocaleTimeString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toUTCString',NativeToUTCString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getTime',NativeGetTime,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getFullYear',NativeGetFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCFullYear',NativeGetUTCFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getMonth',NativeGetMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCMonth',NativeGetUTCMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getDate',NativeGetDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCDate',NativeGetUTCDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getDay',NativeGetDay,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCDay',NativeGetUTCDay,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getHours',NativeGetHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCHours',NativeGetUTCHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getMinutes',NativeGetMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCMinutes',NativeGetUTCMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getSeconds',NativeGetSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCSeconds',NativeGetUTCSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getMilliseconds',NativeGetMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getUTCMilliseconds',NativeGetUTCMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getTimezoneOffset',NativeGetTimezoneOffset,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setTime',NativeSetTime,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setMilliseconds',NativeSetMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCMilliseconds',NativeSetUTCMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setSeconds',NativeSetSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCSeconds',NativeSetUTCSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setMinutes',NativeSetMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCMinutes',NativeSetUTCMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setHours',NativeSetHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCHours',NativeSetUTCHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setDate',NativeSetDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCDate',NativeSetUTCDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setMonth',NativeSetMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCMonth',NativeSetUTCMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setFullYear',NativeSetFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setUTCFullYear',NativeSetUTCFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toGMTString',NativeToGMTString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toISOString',NativeToISOString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toJSON',NativeToJSON,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('getYear',NativeGetYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('setYear',NativeSetYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectDatePrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectDatePrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyyy hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)+' GMT'+BESENGetDateTimeOffsetString(BESENGetLocalDateTimeZone)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyy',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('dddddd tt',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToLocaleDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('dddddd',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToLocaleTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('tt',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToUTCString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('ddd, dd mmm yyyy hh:nn:ss',BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value),BESENDefaultFormatSettings)+' GMT'); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; - -end; - -procedure TBESENObjectDatePrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENYearFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENYearFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENMonthFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENMonthFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENDayFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENDayFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENWeekDay(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENWeekDay(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENHourFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENHourFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENMinuteFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENMinuteFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENSecondFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENSecondFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENMillisecondFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENMillisecondFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetTimezoneOffset(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue((TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value-BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))/BESENmsPerMinute); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(TBESEN(Instance).ToNum(Arguments^[0]^)); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - ms:=TBESEN(Instance).ToNum(Arguments^[0]^); - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),BESENSecondFromTime(t),ms)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - ms:=TBESEN(Instance).ToNum(Arguments^[0]^); - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),BESENSecondFromTime(t),ms))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Seconds,ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Seconds:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - ms:=BESENMillisecondFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),Seconds,ms)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Seconds,ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - Seconds:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - ms:=BESENMillisecondFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),Seconds,ms))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Minutes,Seconds,ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Minutes:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Seconds:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Seconds:=BESENSecondFromTime(t); - end; - if CountArguments>2 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[2]^); - end else begin - ms:=BESENMillisecondFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),Minutes,Seconds,ms)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Minutes,Seconds,ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - Minutes:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Seconds:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Seconds:=BESENSecondFromTime(t); - end; - if CountArguments>2 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[2]^); - end else begin - ms:=BESENMillisecondFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),Minutes,Seconds,ms))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Hours,Minutes,Seconds,ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Hours:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Minutes:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Minutes:=BESENMinuteFromTime(t); - end; - if CountArguments>2 then begin - Seconds:=TBESEN(Instance).ToNum(Arguments^[2]^); - end else begin - Seconds:=BESENSecondFromTime(t); - end; - if CountArguments>3 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[3]^); - end else begin - ms:=BESENMillisecondFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(Hours,Minutes,Seconds,ms)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Hours,Minutes,Seconds,ms:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - Hours:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Minutes:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Minutes:=BESENMinuteFromTime(t); - end; - if CountArguments>2 then begin - Seconds:=TBESEN(Instance).ToNum(Arguments^[2]^); - end else begin - Seconds:=BESENSecondFromTime(t); - end; - if CountArguments>3 then begin - ms:=TBESEN(Instance).ToNum(Arguments^[3]^); - end else begin - ms:=BESENMillisecondFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(Hours,Minutes,Seconds,ms))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Date:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Date:=TBESEN(Instance).ToNum(Arguments^[0]^); - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),BESENMonthFromTime(t),Date),BESENTimeWithinDay(t)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Date:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - Date:=TBESEN(Instance).ToNum(Arguments^[0]^); - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),BESENMonthFromTime(t),Date),BESENTimeWithinDay(t))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Month,Date:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Month:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Date:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Date:=BESENDayFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),Month,Date),BESENTimeWithinDay(t)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Month,Date:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - Month:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Date:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Date:=BESENDayFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),Month,Date),BESENTimeWithinDay(t))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Year,Month,Date:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Year:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Month:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Month:=BESENMonthFromTime(t); - end; - if CountArguments>2 then begin - Date:=TBESEN(Instance).ToNum(Arguments^[2]^); - end else begin - Date:=BESENDayFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENTimeWithinDay(t)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Year,Month,Date:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; - Year:=TBESEN(Instance).ToNum(Arguments^[0]^); - if CountArguments>1 then begin - Month:=TBESEN(Instance).ToNum(Arguments^[1]^); - end else begin - Month:=BESENMonthFromTime(t); - end; - if CountArguments>2 then begin - Date:=TBESEN(Instance).ToNum(Arguments^[2]^); - end else begin - Date:=BESENDayFromTime(t); - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENTimeWithinDay(t))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToGMTString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - NativeToUTCString(ThisArgument,Arguments,CountArguments,ResultValue); -end; - -procedure TBESENObjectDatePrototype.NativeToISOString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - ResultValue:=BESENStringValue('Invalid Date'); - end else begin - ResultValue:=BESENStringValue('NaN'); - end; - end else begin - ResultValue:=BESENStringValue(BESENFormatDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz"Z"',BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value),BESENDefaultFormatSettings)); - end; - end else begin - raise EBESENTypeError.Create('Not date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeToJSON(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ov,tv:TBESENValue; -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ov); - TBESEN(Instance).ToPrimitiveValue(ov,TBESEN(Instance).ObjectNumberConstructorValue,tv); - if (tv.ValueType=bvtNUMBER) and not BESENIsFinite(tv.Num) then begin - ResultValue:=BESENNullValue; - end else begin - TBESENObject(ov.Obj).GarbageCollectorLock; - try - TBESENObject(ov.Obj).Get('toISOString',tv); - if not BESENIsCallable(tv) then begin - raise EBESENTypeError.Create('no "toISOString" callable object'); - end; - TBESEN(Instance).ObjectCall(TBESENObject(tv.Obj),ov,nil,0,ResultValue); - finally - TBESENObject(ov.Obj).GarbageCollectorUnlock; - end; - end; -end; - -procedure TBESENObjectDatePrototype.NativeGetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin - ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - end else begin - ResultValue:=BESENNumberValue(BESENYearFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))-1900); - end; - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -procedure TBESENObjectDatePrototype.NativeSetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var t:TBESENDate; - Year:TBESENNumber; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin - if CountArguments=0 then begin - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); - end else begin - t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - Year:=TBESEN(Instance).ToNum(Arguments^[0]^); - if (0<=Year) and (Year<=99) then begin - Year:=Year+1900; - end; - TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(Year,BESENMonthFromTime(t),BESENDayFromTime(t)),BESENTimeWithinDay(t)))); - end; - ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a date object'); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectDeclaredFunction.pas b/3rd/besen/src/BESENObjectDeclaredFunction.pas deleted file mode 100644 index 9d0506dfb..000000000 --- a/3rd/besen/src/BESENObjectDeclaredFunction.pas +++ /dev/null @@ -1,235 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectDeclaredFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, - BESENLexicalEnvironment,BESENContext,BESENASTNodes; - -type TBESENObjectDeclaredFunctionParameters=array of TBESENString; - - TBESENObjectDeclaredFunction=class(TBESENObjectFunction) - public - LexicalEnvironment:TBESENLexicalEnvironment; - Node:TBESENASTNodeFunctionLiteral; - Parameters:TBESENObjectDeclaredFunctionParameters; - Container:TBESENFunctionLiteralContainer; - ContextCache:TBESENContextCache; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; - function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure CallEx(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue;IsConstruct:boolean); virtual; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENErrors,BESENUtils,BESENCode,BESENDeclarativeEnvironmentRecord; - -constructor TBESENObjectDeclaredFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='declared'; - LexicalEnvironment:=nil; - Node:=nil; - Parameters:=nil; - Container:=nil; - ContextCache:=TBESENContextCache.Create(Instance); -end; - -destructor TBESENObjectDeclaredFunction.Destroy; -begin - SetLength(Parameters,0); - BESENFreeAndNil(ContextCache); - inherited Destroy; -end; - -function TBESENObjectDeclaredFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); - if Node.Body.IsStrict and (P='caller') then begin - raise EBESENTypeError.Create('"caller" not allowed here'); - end; -end; - -function TBESENObjectDeclaredFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - result:=inherited GetIndex(Index,ID,AResult,Base); - if TBESEN(Instance).IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin - raise EBESENTypeError.Create('"caller" not allowed here'); - end; -end; - -procedure TBESENObjectDeclaredFunction.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObject; - r3:TBESENValue; -begin - Get('prototype',r3); - if (r3.ValueType=bvtOBJECT) and assigned(TBESENObject(r3.Obj)) then begin - r1:=TBESENObject.Create(Instance,TBESENObject(r3.Obj),false); - end else begin - r1:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - end; - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - r1.Extensible:=true; - CallEx(BESENObjectValue(r1),Arguments,CountArguments,AResult,true); - finally - r1.GarbageCollectorUnlock; - end; - if AResult.ValueType<>bvtOBJECT then begin - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=r1; - end; -end; - -procedure TBESENObjectDeclaredFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - CallEx(ThisArgument,Arguments,CountArguments,AResult,false); -end; - -procedure TBESENObjectDeclaredFunction.CallEx(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue;IsConstruct:boolean); -var NewContext:TBESENContext; - LocalEnv:TBESENLexicalEnvironment; - procedure SetThisBinding; - begin - if Node.Body.IsStrict then begin - BESENCopyValue(NewContext.ThisBinding,ThisArgument); - end else if ThisArgument.ValueType in [bvtUNDEFINED,bvtNULL] then begin - NewContext.ThisBinding.ValueType:=bvtOBJECT; - NewContext.ThisBinding.Obj:=TBESEN(Instance).ObjectGlobal; - end else if ThisArgument.ValueType<>bvtOBJECT then begin - TBESEN(Instance).ToObjectValue(ThisArgument,NewContext.ThisBinding); - end else begin - BESENCopyValue(NewContext.ThisBinding,ThisArgument); - end; - end; -begin - if assigned(Node) and (assigned(Node.Body) and not (Node.Body.IsEmpty and (CountArguments=0))) then begin - GarbageCollectorLock; - try - NewContext:=ContextCache.Pop; - if assigned(NewContext) then begin - LocalEnv:=NewContext.VariableEnvironment; - end else begin - NewContext:=TBESENContext.Create(Instance); - LocalEnv:=nil; - end; - if assigned(LocalEnv) then begin - LocalEnv.Outer:=LexicalEnvironment; - NewContext.LexicalEnvironment:=LocalEnv; - SetThisBinding; - NewContext.InitializeDeclarationBindingInstantiation(Node.Body,self,false,Arguments,CountArguments,true); - end else begin - LocalEnv:=TBESEN(Instance).NewDeclarativeEnvironment(LexicalEnvironment,Node.Body.IsStrict,TBESENCode(Node.Body.Code).HasMaybeDirectEval); - TBESEN(Instance).GarbageCollector.Add(LocalEnv); - NewContext.LexicalEnvironment:=LocalEnv; - NewContext.VariableEnvironment:=LocalEnv; - SetThisBinding; - NewContext.InitializeDeclarationBindingInstantiation(Node.Body,self,false,Arguments,CountArguments,false); - if not IsConstruct then begin - TBESEN(Instance).GarbageCollector.TriggerCollect; - end; - end; - try - if Node.Body.IsEmpty then begin - AResult.ValueType:=bvtUNDEFINED; - end else begin - Node.ExecuteCode(NewContext,AResult); - end; - if (ContextCache.Count<TBESEN(Instance).MaxCountOfFreeContexts) and (Node.Body.DisableArgumentsObject and ((length(Node.Body.Functions)=0) and (assigned(Node.Body.Code) and ((TBESENCode(Node.Body.Code).CountFunctionLiteralContainers=0) and not (TBESENCode(Node.Body.Code).IsComplexFunction or TBESENCode(Node.Body.Code).HasLocalDelete))))) then begin - NewContext.Reset; - if (((assigned(LocalEnv) and (NewContext.VariableEnvironment=LocalEnv){ and (LocalEnv.Outer=Instance.GlobalLexicalEnvironment)}) and assigned(LocalEnv.EnvironmentRecord)) and (LocalEnv.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord)) and not TBESENDeclarativeEnvironmentRecord(LocalEnv.EnvironmentRecord).Touched then begin - LocalEnv.Outer:=nil; - TBESENDeclarativeEnvironmentRecord(LocalEnv.EnvironmentRecord).Reset; - ContextCache.Push(NewContext); - NewContext:=nil; - end; - end; - finally - NewContext.Free; - end; - finally - GarbageCollectorUnlock; - end; - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; -end; - -function TBESENObjectDeclaredFunction.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectDeclaredFunction.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectDeclaredFunction.Finalize; -begin - Container:=nil; - LexicalEnvironment:=nil; - inherited Finalize; -end; - -procedure TBESENObjectDeclaredFunction.Mark; -begin - if assigned(Container) then begin - TBESEN(Instance).GarbageCollector.GrayIt(Container); - end; - if assigned(LexicalEnvironment) then begin - TBESEN(Instance).GarbageCollector.GrayIt(LexicalEnvironment); - end; - if assigned(ContextCache) then begin - ContextCache.Mark; - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectEnvironmentRecord.pas b/3rd/besen/src/BESENObjectEnvironmentRecord.pas deleted file mode 100644 index af811c7f9..000000000 --- a/3rd/besen/src/BESENObjectEnvironmentRecord.pas +++ /dev/null @@ -1,168 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectEnvironmentRecord; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENObject, - BESENObjectPropertyDescriptor,BESENValue; - -type TBESENObjectEnvironmentRecord=class(TBESENEnvironmentRecord) - public - BindingObject:TBESENObject; - ProvideThis:TBESENBoolean; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; override; - function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; - procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); override; - function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - procedure UpdateImplicitThisValue; override; - function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; override; - procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); override; - function DeleteIndex(const I,ID:integer):TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENStringUtils,BESENErrors; - -constructor TBESENObjectEnvironmentRecord.Create(AInstance:TObject); -begin - inherited Create(AInstance); - BindingObject:=nil; - ProvideThis:=false; - RecordType:=BESENEnvironmentRecordTypeObject; -end; - -destructor TBESENObjectEnvironmentRecord.Destroy; -begin - BindingObject:=nil; - inherited Destroy; -end; - -function TBESENObjectEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - result:=BindingObject.HasPropertyEx(N,Descriptor,Hash); -end; - -function TBESENObjectEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; -begin - if BindingObject.HasProperty(N,Hash) then begin - BESENThrowTypeError('CreateMutableBinding for "'+N+'" failed'); - end; - if D then begin - result:=BindingObject.DefineOwnProperty(N,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true,Hash); // ES5 errata false to true - end else begin - result:=BindingObject.DefineOwnProperty(N,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE]),true,Hash); // ES5 errata false to true - end; -end; - -function TBESENObjectEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; -begin - BindingObject.PutEx(N,V,S,Descriptor,OwnDescriptor,TempValue,Hash); - result:=true; -end; - -procedure TBESENObjectEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); - procedure ThrowIt; - begin - BESENThrowTypeError('GetBindingValue for "'+N+'" failed'); - end; -begin - if not BindingObject.GetEx(N,R,Descriptor,BindingObject,Hash) then begin - if S then begin - ThrowIt; - end else begin - R.ValueType:=bvtUNDEFINED; - end; - end; -end; - -function TBESENObjectEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -begin - result:=BindingObject.DeleteEx(N,false,Descriptor,Hash); -end; - -procedure TBESENObjectEnvironmentRecord.UpdateImplicitThisValue; -begin - if ProvideThis then begin - ImplicitThisValue.ValueType:=bvtOBJECT; - ImplicitThisValue.Obj:=BindingObject; - end else begin - ImplicitThisValue.ValueType:=bvtUNDEFINED; - ImplicitThisValue.Obj:=nil; - end; -end; - -function TBESENObjectEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; -begin - BindingObject.PutIndex(I,ID,V,S); - result:=true; -end; - -procedure TBESENObjectEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); - procedure ThrowIt; - begin - BESENThrowTypeError('GetIndexValue failed'); - end; -begin - if not BindingObject.GetIndex(I,ID,R,BindingObject) then begin - if S then begin - ThrowIt; - end else begin - R.ValueType:=bvtUNDEFINED; - end; - end; -end; - -function TBESENObjectEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; -begin - result:=BindingObject.DeleteIndex(I,iD,false); -end; - -procedure TBESENObjectEnvironmentRecord.Finalize; -begin - BindingObject:=nil; - inherited Finalize; -end; - -procedure TBESENObjectEnvironmentRecord.Mark; -begin - TBESEN(Instance).GarbageCollector.GrayIt(BindingObject); - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectError.pas b/3rd/besen/src/BESENObjectError.pas deleted file mode 100644 index 3e86d3f1d..000000000 --- a/3rd/besen/src/BESENObjectError.pas +++ /dev/null @@ -1,74 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectError; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectError=class(TBESENObject) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENObjectError.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Error'; - ObjectName:=''; - - OverwriteData('length',BESENNumberValue(1),[]); -end; - -destructor TBESENObjectError.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectError.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectError.Mark; -begin - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectErrorConstructor.pas b/3rd/besen/src/BESENObjectErrorConstructor.pas deleted file mode 100644 index 9e00fc4c3..000000000 --- a/3rd/besen/src/BESENObjectErrorConstructor.pas +++ /dev/null @@ -1,108 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectErrorConstructor; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectErrorConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENObjectError; - -constructor TBESENObjectErrorConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='Error'; -end; - -destructor TBESENObjectErrorConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectErrorConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectError; - r2:TBESENObject; - r3:TBESENValue; -begin - // ES5 errata fix - Get('prototype',r3); - if r3.ValueType=bvtOBJECT then begin - r2:=TBESENObject(r3.Obj); - end else begin - r2:=nil; - end; - r1:=TBESENObjectError.Create(Instance,r2,false); - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - r1.OverwriteData('message',BESENStringValue(TBESEN(Instance).ToStr(Arguments^[0]^)),[bopaWRITABLE,bopaCONFIGURABLE]); - end else begin - r1.OverwriteData('message',BESENStringValue(''),[bopaWRITABLE,bopaCONFIGURABLE]); - end; - finally - r1.GarbageCollectorUnlock; - end; - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=r1; -end; - -procedure TBESENObjectErrorConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - // ES5 Errate fix - Construct(ThisArgument,Arguments,CountArguments,AResult); -end; - -function TBESENObjectErrorConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectErrorConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -end. diff --git a/3rd/besen/src/BESENObjectErrorPrototype.pas b/3rd/besen/src/BESENObjectErrorPrototype.pas deleted file mode 100644 index dd3c10158..000000000 --- a/3rd/besen/src/BESENObjectErrorPrototype.pas +++ /dev/null @@ -1,99 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectErrorPrototype; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectError,BESENValue,BESENObjectPropertyDescriptor, - BESENObjectBoolean; - -type TBESENObjectErrorPrototype=class(TBESENObjectError) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectErrorPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Error'; - ObjectName:='Error'; - - OverwriteData('name',BESENStringValue('Error'),[bopaWRITABLE,bopaCONFIGURABLE]); - OverwriteData('message',BESENStringValue(''),[bopaWRITABLE,bopaCONFIGURABLE]); - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - -end; - -destructor TBESENObjectErrorPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectErrorPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var nv,mv:TBESENValue; - n,m:TBESENString; -begin - // ES5 errata fix - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - TBESENObjectError(TBESENObject(ThisArgument.Obj)).Get('name',nv); - TBESENObjectError(TBESENObject(ThisArgument.Obj)).Get('message',mv); - if nv.ValueType=bvtUNDEFINED then begin - n:='Error'; - end else begin - n:=TBESEN(Instance).ToStr(nv); - end; - if mv.ValueType=bvtUNDEFINED then begin - m:=''; - end else begin - m:=TBESEN(Instance).ToStr(mv); - end; - if (length(n)=0) and (length(m)=0) then begin - ResultValue:=BESENStringValue('Error'); - end else if length(n)=0 then begin - ResultValue:=BESENStringValue(m); - end else if length(m)=0 then begin - ResultValue:=BESENStringValue(n); - end else begin - ResultValue:=BESENStringValue(n+': '+m); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectFunction.pas b/3rd/besen/src/BESENObjectFunction.pas deleted file mode 100644 index bccd29aa2..000000000 --- a/3rd/besen/src/BESENObjectFunction.pas +++ /dev/null @@ -1,122 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectFunction=class(TBESENObject) - public - SecurityDomain:pointer; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetSecurityDomain:pointer; override; - function HasGetSecurityDomain:TBESENBoolean; override; - function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; - function HasHasInstance:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='function'; - - SecurityDomain:=nil; - - OverwriteData('length',BESENNumberValue(1),[]); -end; - -destructor TBESENObjectFunction.Destroy; -begin - inherited Destroy; -end; - -function TBESENObjectFunction.GetSecurityDomain:pointer; -begin - result:=SecurityDomain; -end; - -function TBESENObjectFunction.HasGetSecurityDomain:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectFunction.HasInstance(const AInstance:TBESENValue):TBESENBoolean; -var v,o:TBESENObject; - ov:TBESENValue; -begin - result:=false; - if AInstance.ValueType<>bvtOBJECT then begin - exit; - end; - v:=TBESENObject(AInstance.Obj); - Get('prototype',ov); - if ov.ValueType<>bvtOBJECT then begin - raise EBESENTypeError.Create('Prototype not object'); - end; - o:=TBESENObject(ov.Obj); - while true do begin - v:=v.Prototype; - if not assigned(v) then begin - break; - end else if TBESEN(Instance).SameObject(v,o) then begin - result:=true; - break; - end; - end; -end; - -function TBESENObjectFunction.HasHasInstance:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectFunction.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectFunction.Mark; -begin - inherited Mark; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectFunctionArguments.pas b/3rd/besen/src/BESENObjectFunctionArguments.pas deleted file mode 100644 index d52ba4275..000000000 --- a/3rd/besen/src/BESENObjectFunctionArguments.pas +++ /dev/null @@ -1,230 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectFunctionArguments; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectFunctionArguments=class(TBESENObject) - public - ParameterMap:TBESENObject; - IsStrict:longbool; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; - function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; - function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; - procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; - function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; - procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN,BESENGlobals,BESENStringUtils,BESENErrors; - -constructor TBESENObjectFunctionArguments.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Arguments'; - ObjectName:='Arguments'; - ParameterMap:=nil; -end; - -destructor TBESENObjectFunctionArguments.Destroy; -begin - inherited Destroy; -end; - -function TBESENObjectFunctionArguments.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; -var MappedDescriptor:TBESENObjectPropertyDescriptor; -begin - if IsStrict or not assigned(ParameterMap) then begin - result:=inherited GetOwnProperty(P,Descriptor,Hash); - end else begin - result:=inherited GetOwnProperty(P,Descriptor,Hash); - if result then begin - MappedDescriptor:=Descriptor; - if not ParameterMap.GetOwnProperty(P,MappedDescriptor,Hash) then begin - ParameterMap.Get(P,Descriptor.Value); - result:=Descriptor.Presents<>[]; - end; - end; - end; -end; - -function TBESENObjectFunctionArguments.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - if IsStrict or not assigned(ParameterMap) then begin - result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); - end else begin - if ParameterMap.GetOwnProperty(P,Descriptor,Hash) then begin - result:=ParameterMap.GetEx(P,AResult,Descriptor,Base,Hash); - end else begin - result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); - if IsStrict and (P='caller') then begin - BESENThrowCaller; - end; - end; - end; -end; - -function TBESENObjectFunctionArguments.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -var Descriptor:TBESENObjectPropertyDescriptor; -begin - if not assigned(Base) then begin - Base:=self; - end; - if IsStrict or not assigned(ParameterMap) then begin - result:=inherited GetIndex(Index,ID,AResult,Base); - end else begin - if ParameterMap.GetOwnProperty(TBESEN(Instance).KeyIDManager.List[ID],Descriptor) then begin - result:=ParameterMap.GetEx(TBESEN(Instance).KeyIDManager.List[ID],AResult,Descriptor,Base); - end else begin - result:=inherited GetIndex(Index,ID,AResult,Base); - if IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin - BESENThrowCaller; - end; - end; - end; -end; - -function TBESENObjectFunctionArguments.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -var IsMapped:boolean; -begin - if IsStrict or not assigned(ParameterMap) then begin - result:=inherited DeleteEx(P,Throw,Descriptor,Hash); - end else begin - IsMapped:=ParameterMap.GetOwnProperty(P,Descriptor,Hash); - result:=inherited DeleteEx(P,Throw,Descriptor,Hash); - if result and IsMapped then begin - ParameterMap.DeleteEx(P,false,Descriptor,Hash); - end; - end; -end; - -procedure TBESENObjectFunctionArguments.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); -begin - PutFull(P,V,false,Descriptor,OwnDescriptor,TempValue,Hash); -end; - -procedure TBESENObjectFunctionArguments.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); -begin - Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); -end; - -function TBESENObjectFunctionArguments.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; -var IsMapped,Allowed:boolean; - procedure ThrowIt; - begin - BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); - end; -begin - if IsStrict or not assigned(ParameterMap) then begin - result:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); - end else begin - IsMapped:=ParameterMap.GetOwnProperty(P,Current,Hash); - Allowed:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); - if not Allowed then begin - if Throw then begin - ThrowIt; - end; - result:=false; - exit; - end; - if IsMapped then begin - if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - ParameterMap.DeleteEx(p,false,Current,Hash); - end else begin - if boppVALUE in Descriptor.Presents then begin - ParameterMap.Put(p,Descriptor.Value,Throw,Hash); - end; - if (boppWRITABLE in Descriptor.Presents) and not (bopaWRITABLE in Descriptor.Attributes) then begin - ParameterMap.DeleteEx(p,false,Current,Hash); - end; - end; - end; - result:=true; - end; -end; - -procedure TBESENObjectFunctionArguments.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); -var i,j:integer; - s:TBESENString; - v:TBESENValue; - procedure ThrowIt; - begin - BESENThrowTypeError('Bad default value'); - end; -begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - s:='['; - Get('length',v,self,BESENLengthHash); - j:=TBESEN(Instance).ToInt32(v); - for i:=0 to j-1 do begin - if i>0 then begin - s:=s+', '; - end; - Get(IntToStr(i),v); - s:=s+inttostr(i)+'='+TBESEN(Instance).ToStr(v); - end; - s:=s+']'; - AResult:=BESENStringValue(s); - end else begin - inherited DefaultValue(AHint,AResult); - end; -end; - -procedure TBESENObjectFunctionArguments.Finalize; -begin - ParameterMap:=nil; - inherited Finalize; -end; - -procedure TBESENObjectFunctionArguments.Mark; -begin - if assigned(ParameterMap) then begin - TBESEN(Instance).GarbageCollector.GrayIt(ParameterMap); - end; - inherited Mark; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectFunctionConstructor.pas b/3rd/besen/src/BESENObjectFunctionConstructor.pas deleted file mode 100644 index d69c8e03d..000000000 --- a/3rd/besen/src/BESENObjectFunctionConstructor.pas +++ /dev/null @@ -1,124 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectFunctionConstructor; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectFunctionConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENErrors,BESENASTNodes,BESENStringUtils,BESENUtils,BESENObjectDeclaredFunction; - -constructor TBESENObjectFunctionConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); -end; - -destructor TBESENObjectFunctionConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectFunctionConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var Body,Parameters:TBESENString; - i:integer; - Node:TBESENASTNode; - f:TBESENObjectDeclaredFunction; - OldIsStrict:boolean; -begin - Body:=''; - Parameters:=''; - OldIsStrict:=TBESEN(Instance).IsStrict; - try - if CountArguments>0 then begin - for i:=0 to CountArguments-2 do begin - if i>0 then begin - Parameters:=Parameters+','; - end; - Parameters:=Parameters+TBESEN(Instance).ToStr(Arguments^[i]^); - end; - Body:=TBESEN(Instance).ToStr(Arguments[CountArguments-1]^); - end; - TBESEN(Instance).IsStrict:=false; - Node:=TBESEN(Instance).Compile({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}Body{$ifndef BESENSingleStringType}),BESENUTF16ToUTF8({$endif}Parameters{$ifndef BESENSingleStringType}){$endif},true); - if assigned(Node) and (Node is TBESENASTNodeFunctionExpression) then begin - if assigned(TBESENASTNodeFunctionExpression(Node).Container.Literal.Name) then begin - if TBESEN(Instance).IsStrict then begin - if TBESENASTNodeFunctionExpression(Node).Container.Literal.Name.Name='eval' then begin - raise EBESENSyntaxError.Create('"eval" not allowed here'); - end; - end; - f:=TBESEN(Instance).MakeFunction(TBESENASTNodeFunctionExpression(Node).Container.Literal,TBESENASTNodeFunctionExpression(Node).Container.Literal.Name.Name,TBESEN(Instance).GlobalLexicalEnvironment); - end else begin - f:=TBESEN(Instance).MakeFunction(TBESENASTNodeFunctionExpression(Node).Container.Literal,'',TBESEN(Instance).GlobalLexicalEnvironment); - end; - TBESEN(Instance).GarbageCollector.Add(f); - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=f; - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; - BESENFreeAndNil(Node); - finally - TBESEN(Instance).IsStrict:=OldIsStrict; - end; -end; - -procedure TBESENObjectFunctionConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - Construct(ThisArgument,Arguments,CountArguments,AResult); -end; - -function TBESENObjectFunctionConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectFunctionConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectFunctionPrototype.pas b/3rd/besen/src/BESENObjectFunctionPrototype.pas deleted file mode 100644 index 71dddaab1..000000000 --- a/3rd/besen/src/BESENObjectFunctionPrototype.pas +++ /dev/null @@ -1,237 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectFunctionPrototype; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, - BESENObjectNativeFunction; - -type TBESENObjectFunctionPrototype=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasCall:TBESENBoolean; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeApply(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeBind(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENGlobals,BESENStringUtils,BESENErrors,BESENObjectDeclaredFunction, - BESENObjectThrowTypeErrorFunction,BESENObjectArgGetterFunction, - BESENObjectArgSetterFunction,BESENObjectBindingFunction; - -constructor TBESENObjectFunctionPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='prototype'; - - OverwriteData('length',BESENNumberValue(0),[]); - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; -end; - -destructor TBESENObjectFunctionPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectFunctionPrototype.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - AResult:=BESENUndefinedValue; -end; - -function TBESENObjectFunctionPrototype.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectFunctionPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ThisArgumentObj:TObject; -begin - ThisArgumentObj:=ThisArgument.Obj; - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgumentObj)) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectDeclaredFunction) then begin - if assigned(TBESENObjectDeclaredFunction(ThisArgumentObj).Node) then begin - ResultValue:=BESENStringValue(BESENUTF8ToUTF16(TBESEN(Instance).Decompile(TBESENObjectDeclaredFunction(ThisArgumentObj).Node))); - end else begin - ResultValue:=BESENStringValue('function () {'#10'}'#10); - end; - end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectNativeFunction) then begin - ResultValue:=BESENStringValue('function () {'#10#9'[native code]'#10'}'#10); - end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectThrowTypeErrorFunction) then begin - ResultValue:=BESENStringValue('function () {'#10#9'[native code, ThrowTypeError]'#10'}'#10); - end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectArgGetterFunction) then begin - ResultValue:=BESENStringValue('function () {'#10#9'[native code, ArgGetter]'#10'}'#10); - end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectArgSetterFunction) then begin - ResultValue:=BESENStringValue('function () {'#10#9'[native code, ArgSetter]'#10'}'#10); - end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectBindingFunction) then begin - ResultValue:=BESENStringValue('function () {'#10#9'[native code, Binding]'#10'}'#10); - end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectFunction) then begin - ResultValue:=BESENStringValue('function () {'#10'}'#10); - end else begin - raise EBESENTypeError.Create('Not a function object'); - end; -end; - -procedure TBESENObjectFunctionPrototype.NativeApply(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var CallThisArg:TBESENValue; - v2,v3:TBESENValue; - vArgs:TBESENValues; - pArgs:TBESENValuePointers; - i,j:integer; -begin - // ES5 errata fix - vArgs:=nil; - pArgs:=nil; - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if not TBESENObject(ThisArgument.Obj).HasCall then begin - raise EBESENTypeError.Create('No callable'); - end; - v2:=BESENEmptyValue; - v3:=BESENEmptyValue; - try - if CountArguments<1 then begin - CallThisArg:=BESENUndefinedValue; - end else begin - BESENCopyValue(CallThisArg,Arguments^[0]^); - if (CountArguments>1) and not (Arguments^[1]^.ValueType in [bvtUNDEFINED,bvtNULL]) then begin - TBESEN(Instance).ToObjectValue(Arguments^[1]^,v2); - if (v2.ValueType=bvtOBJECT) and assigned(v2.Obj) then begin - TBESENObject(v2.Obj).GarbageCollectorLock; - end; - TBESENObject(v2.Obj).Get('length',v3,TBESENObject(v2.Obj),BESENLengthHash); - j:=TBESEN(Instance).ToUInt32(v3); - SetLength(vArgs,j); - SetLength(pArgs,j); - for i:=0 to j-1 do begin - TBESENObject(v2.Obj).Get(inttostr(i),vArgs[i]); - pArgs[i]:=@vArgs[i]; - end; - end; - end; - TBESEN(Instance).ObjectCall(TBESENObject(ThisArgument.Obj),CallThisArg,@pArgs[0],length(pArgs),ResultValue); - finally - if (v2.ValueType=bvtOBJECT) and assigned(v2.Obj) then begin - TBESENObject(v2.Obj).GarbageCollectorUnlock; - end; - SetLength(vArgs,0); - SetLength(pArgs,0); - end; -end; - -procedure TBESENObjectFunctionPrototype.NativeCall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var CallThisArg:TBESENValue; - pArgs:TBESENValuePointers; - i:integer; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if not TBESENObject(ThisArgument.Obj).HasCall then begin - raise EBESENTypeError.Create('No callable'); - end; - pArgs:=nil; - try - if CountArguments<1 then begin - CallThisArg:=BESENUndefinedValue; - end else begin - BESENCopyValue(CallThisArg,Arguments^[0]^); - if CountArguments>1 then begin - SetLength(pArgs,CountArguments-1); - for i:=0 to length(pArgs)-1 do begin - pArgs[i]:=Arguments[i+1]; - end; - end; - end; - TBESEN(Instance).ObjectCall(TBESENObject(ThisArgument.Obj),CallThisArg,@pArgs[0],length(pArgs),ResultValue); - finally - SetLength(pArgs,0); - end; -end; - -procedure TBESENObjectFunctionPrototype.NativeBind(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var o:TBESENObjectBindingFunction; - i:integer; - v:TBESENValue; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if not TBESENObject(ThisArgument.Obj).HasCall then begin - raise EBESENTypeError.Create('Bad arg'); - end; - o:=TBESENObjectBindingFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,false); - TBESEN(Instance).GarbageCollector.Add(o); - o.GarbageCollectorLock; - try - o.TargetFunction:=TBESENObject(ThisArgument.Obj); - if CountArguments>0 then begin - BESENCopyValue(o.BoundThis,Arguments^[0]^); - end else begin - o.BoundThis.ValueType:=bvtUNDEFINED; - end; - if CountArguments>1 then begin - SetLength(o.BoundArguments,CountArguments-1); - for i:=1 to CountArguments-1 do begin - BESENCopyValue(o.BoundArguments[i-1],Arguments^[i]^); - end; - end else begin - SetLength(o.BoundArguments,0); - end; - if o.TargetFunction is TBESENObjectFunction then begin - TBESENObjectFunction(o.TargetFunction).Get('length',v,o.TargetFunction,BESENLengthHash); - o.OverwriteData('length',BESENNumberValue(max(0,TBESEN(Instance).ToInt(v)-length(o.BoundArguments))),[]); - end else begin - o.OverwriteData('length',BESENNumberValue(0),[]); - end; - o.Extensible:=true; - o.OverwriteAccessor('caller',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); - o.OverwriteAccessor('arguments',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); - finally - o.GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(o); -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectGlobal.pas b/3rd/besen/src/BESENObjectGlobal.pas deleted file mode 100644 index 2b1a5d7bf..000000000 --- a/3rd/besen/src/BESENObjectGlobal.pas +++ /dev/null @@ -1,516 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectGlobal; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor,BESENCharSet; - -type TBESENObjectGlobal=class(TBESENObject) - private - function Encode(const s:TBESENString;const NotToEscapeChars:TBESENCharBitmap):TBESENString; - function Decode(const s:TBESENString;const ReservedChars:TBESENCharBitmap):TBESENString; - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeEval(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeParseInt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeParseFloat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIsNaN(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIsFinite(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeDecodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeDecodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeEncodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeEncodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeEscape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeUnescape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCompatability(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENNumberUtils,BESENStringUtils,BESENErrors; - -const BESENCompatibilityModes:TBESENCompatibilityModes=( - (Name:'utf8_unsafe';Flag:COMPAT_UTF8_UNSAFE), - (Name:'sgmlcom';Flag:COMPAT_SGMLCOM), - (Name:'besen';Flag:COMPAT_BESEN), - (Name:'js';Flag:COMPAT_JS)); - -constructor TBESENObjectGlobal.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -var v:TBESENValue; -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - - v:=BESENEmptyValue; - - v:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); - OverwriteData('NaN',v,[]); - - v:=BESENNumberValue(double(pointer(@BESENDoubleInfPos)^)); - OverwriteData('Infinity',v,[]); - - v:=BESENUndefinedValue; - OverwriteData('undefined',v,[]); - - RegisterNativeFunction('eval',NativeEval,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('parseInt',NativeParseInt,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('parseFloat',NativeParseFloat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('isNaN',NativeIsNaN,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('isFinite',NativeIsFinite,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('decodeURI',NativeDecodeURI,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('decodeURIComponent',NativeDecodeURIComponent,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('encodeURI',NativeEncodeURI,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('encodeURIComponent',NativeEncodeURIComponent,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - - RegisterNativeFunction('escape',NativeEscape,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('unescape',NativeUnescape,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - - if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin - RegisterNativeFunction('compat',NativeCompatability,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('compatability',NativeCompatability,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - end; -end; - -destructor TBESENObjectGlobal.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectGlobal.NativeEval(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue:=BESENUndefinedValue; -end; - -procedure TBESENObjectGlobal.NativeParseInt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:TBESENString; - i,StartPos,UntilPos,r,c:integer; - Negative:boolean; -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - if CountArguments>0 then begin - if CountArguments>1 then begin - r:=TBESEN(Instance).ToInt(Arguments^[1]^); - end else begin - r:=0; - end; - if (r<>0) and ((r<2) or (r>36)) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - exit; - end; - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - i:=1; - while (i<=length(s)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(s[i])))) do begin - inc(i); - end; - if (i<=length(s)) and ((s[i]='-') or (s[i]='+')) then begin - Negative:=s[i]='-'; - inc(i); - end else begin - Negative:=false; - end; - if (r in [0,16]) and ((i+1)<=length(s)) and (s[i]='0') and ((s[i+1]='x') or (s[i+1]='X')) then begin - r:=16; - inc(i,2); - end else if (((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and not TBESEN(Instance).IsStrict) and ((r=0) and ((i<=length(s)) and (s[i]='0'))) then begin - r:=8; - inc(i); - end; - if r=0 then begin - r:=10; - end; - StartPos:=i; - UntilPos:=i; - while UntilPos<=length(s) do begin - c:=word(widechar(s[UntilPos])); - case c of - ord('0')..ord('9'):begin - c:=c-ord('0'); - end; - ord('a')..ord('z'):begin - c:=(c+10)-ord('a'); - end; - ord('A')..ord('Z'):begin - c:=(c+10)-ord('A'); - end; - else begin - break; - end; - end; - if c>=r then begin - break; - end; - inc(UntilPos); - end; - if StartPos>=UntilPos then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - exit; - end; - i:=UntilPos-StartPos; - if r=10 then begin - ResultValue.Num:=BESENStringToNumber(copy(s,StartPos,UntilPos-StartPos),false,false); - end else begin - ResultValue.Num:=BESENStringToNumberBase(copy(s,StartPos,UntilPos-StartPos),r); - end; - if Negative and not BESENIsNaN(ResultValue.Num) then begin - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end; - end; -end; - -procedure TBESENObjectGlobal.NativeParseFloat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - ResultValue.Num:=BESENStringToNumber(TBESEN(Instance).ToStr(Arguments^[0]^),false,false); - end; -end; - -procedure TBESENObjectGlobal.NativeIsNaN(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtBOOLEAN; - if CountArguments=0 then begin - ResultValue.Bool:=true; - end else begin - ResultValue.Bool:=BESENIsNaN(TBESEN(Instance).ToNum(Arguments^[0]^)); - end; -end; - -procedure TBESENObjectGlobal.NativeIsFinite(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtBOOLEAN; - if CountArguments=0 then begin - ResultValue.Bool:=false; - end else begin - ResultValue.Bool:=BESENIsFinite(TBESEN(Instance).ToNum(Arguments^[0]^)); - end; -end; - -function TBESENObjectGlobal.Encode(const s:TBESENString;const NotToEscapeChars:TBESENCharBitmap):TBESENString; -var i:integer; - c:TBESENUTF32CHAR; - r:TBESENString; - procedure DoEscape(v:longword); - begin - r:=r+'%'+BESENHexChars[false,(v shr 4) and $f]+BESENHexChars[false,v and $f]; - end; -begin - r:=''; - i:=1; - while i<=length(s) do begin - c:=word(widechar(s[i])); - if (c and $fc00)=$dc00 then begin - raise EBESENURIError.Create('Bad UTF16 string'); - end else if (c and $fc00)=$d800 then begin - if ((i+1)<=length(s)) and ((word(widechar(s[i+1])) and $fc00)=$dc00) then begin - c:=(((c and $3ff) shl 10) or (word(widechar(s[i+1])) and $3ff))+$10000; - inc(i,2); - end else begin - raise EBESENURIError.Create('Bad UTF16 string'); - end; - end else begin - inc(i); - end; - if c<=$7f then begin - if (NotToEscapeChars[(c and $7f) shr 3] and (1 shl (c and 7)))<>0 then begin - r:=r+widechar(word(c)); - end else begin - DoEscape(c); - end; - end else if c<=$7ff then begin - DoEscape($c0 or (c shr 6)); - DoEscape($80 or (c and $3f)); - end else if c<=$ffff then begin - DoEscape($e0 or (c shr 12)); - DoEscape($80 or ((c shr 6) and $3f)); - DoEscape($80 or (c and $3f)); - end else if c<=$1fffff then begin - DoEscape($f0 or (c shr 18)); - DoEscape($80 or ((c shr 12) and $3f)); - DoEscape($80 or ((c shr 6) and $3f)); - DoEscape($80 or (c and $3f)); - end else begin - raise EBESENURIError.Create('Bad UTF16 string'); - end; - end; - result:=r; -end; - -function TBESENObjectGlobal.Decode(const s:TBESENString;const ReservedChars:TBESENCharBitmap):TBESENString; -const UTF8Mask:array[0..5] of byte=($c0,$e0,$f0,$f8,$fc,$fe); -var i,j,k,h:integer; - c,ac:TBESENUTF32CHAR; -begin - result:=''; - i:=1; - while i<=length(s) do begin - j:=i; - c:=word(widechar(s[i])); - if (c and $fc00)=$dc00 then begin - raise EBESENURIError.Create('Bad UTF16 string'); - end else if (c and $fc00)=$d800 then begin - if ((i+1)<=length(s)) and ((word(widechar(s[i+1])) and $fc00)=$dc00) then begin - c:=(((c and $3ff) shl 10) or (word(widechar(s[i+1])) and $3ff))+$10000; - inc(i,2); - end else begin - raise EBESENURIError.Create('Bad UTF16 string'); - end; - end else begin - inc(i); - end; - if c=ord('%') then begin - if ((i+1)<=length(s)) and (BESENIsHex(word(widechar(s[i]))) and BESENIsHex(word(widechar(s[i+1])))) then begin - c:=(BESENHexValues[word(widechar(s[i]))] shl 4) or BESENHexValues[word(widechar(s[i+1]))]; - end else begin - raise EBESENURIError.Create('Bad URI hex'); - end; - inc(i,2); - if (c and $80)<>0 then begin - k:=1; - while k<6 do begin - if (c and UTF8Mask[k])=UTF8Mask[k-1] then begin - break; - end; - inc(k); - end; - if k>=6 then begin - raise EBESENURIError.Create('Bad UTF8'); - end; - c:=c and not UTF8Mask[k]; - for h:=1 to k do begin - if ((i+2)<=length(s)) and ((s[i]='%') and (BESENIsHex(word(widechar(s[i+1]))) and BESENIsHex(word(widechar(s[i+2]))))) then begin - ac:=(BESENHexValues[word(widechar(s[i+1]))] shl 4) or BESENHexValues[word(widechar(s[i+2]))]; - end else begin - raise EBESENURIError.Create('Bad URI hex'); - end; - inc(i,3); - if (ac and not $3f)<>$80 then begin - raise EBESENURIError.Create('Bad UTF8'); - end; - c:=(C shl 6) or (ac and $3f); - end; - end; - end; - if c<=$ffff then begin - if (c<=$7f) and ((ReservedChars[(c and $7f) shr 3] and (1 shl (c and 7)))<>0) then begin - result:=result+copy(s,j,(i-j)+1); - end else begin - result:=result+widechar(word(c)); - end; - end else if c<=$10ffff then begin - dec(c,$100000); - result:=result+widechar(word($d800 or ((c shr 10) and $3ff)))+widechar(word($dc00 or (c and $3ff))); - end else begin - raise EBESENURIError.Create('Bad unicode'); - end; - end; -end; - -procedure TBESENObjectGlobal.NativeDecodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$58,$98,$00,$ac,$01,$00,$00,$00,$00,$00,$00,$00); // [;/?:@&=+$,#] -begin - if CountArguments=0 then begin - ResultValue:=BESENStringValue('undefined'); - end else begin - ResultValue:=BESENStringValue(Decode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); - end; -end; - -procedure TBESENObjectGlobal.NativeDecodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00); // [] -begin - if CountArguments=0 then begin - ResultValue:=BESENStringValue('undefined'); - end else begin - ResultValue:=BESENStringValue(Decode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); - end; -end; - -procedure TBESENObjectGlobal.NativeEncodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$da,$ff,$ff,$af,$ff,$ff,$ff,$87,$fe,$ff,$ff,$47); // [-_.!~*'();/?:@&=+$,#a-zA-Z0-9] -begin - if CountArguments=0 then begin - ResultValue:=BESENStringValue('undefined'); - end else begin - ResultValue:=BESENStringValue(Encode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); - end; -end; - -procedure TBESENObjectGlobal.NativeEncodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$82,$67,$ff,$03,$fe,$ff,$ff,$87,$fe,$ff,$ff,$47); // [-_.!~*'()a-zA-Z0-9] -begin - if CountArguments=0 then begin - ResultValue:=BESENStringValue('undefined'); - end else begin - ResultValue:=BESENStringValue(Encode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); - end; -end; - -procedure TBESENObjectGlobal.NativeEscape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const NotToEscapeChars:TBESENCharBitmap=($00,$00,$00,$00,$00,$ec,$ff,$03,$ff,$ff,$ff,$87,$fe,$ff,$ff,$07); // [A-Za-z0-9@*_+\-./] -var s,ss:TBESENString; - i:integer; - c:word; - HexUppercase:boolean; -begin - if CountArguments=0 then begin - ResultValue:=BESENStringValue('undefined'); - end else begin - HexUppercase:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - ss:=''; - for i:=1 to length(s) do begin - c:=word(widechar(s[i])); - if (c<$80) and ((NotToEscapeChars[c shr 3] and (1 shl (c and 7)))<>0) then begin - ss:=ss+widechar(c); - end else if c<$100 then begin - ss:=ss+'%'+BESENHexChars[HexUppercase,(c shr 4) and $f]+BESENHexChars[HexUppercase,c and $f]; - end else begin - ss:=ss+'%u'+BESENHexChars[HexUppercase,(c shr 12) and $f]+BESENHexChars[HexUppercase,(c shr 8) and $f]+BESENHexChars[HexUppercase,(c shr 4) and $f]+BESENHexChars[HexUppercase,c and $f]; - end; - end; - ResultValue:=BESENStringValue(ss); - end; -end; - -procedure TBESENObjectGlobal.NativeUnescape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s,ss:TBESENString; - i:integer; - c:word; -begin - if CountArguments=0 then begin - ResultValue:=BESENStringValue('undefined'); - end else begin - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - ss:=''; - i:=1; - while i<=length(s) do begin - c:=word(widechar(s[i])); - if c=ord('%') then begin - inc(i); - if ((i+4)<=length(s)) and (s[i]='u') then begin - ss:=ss+widechar(word((BESENHexValues[word(widechar(s[i+1]))] shl 12) or (BESENHexValues[word(widechar(s[i+2]))] shl 8) or (BESENHexValues[word(widechar(s[i+3]))] shl 4) or BESENHexValues[word(widechar(s[i+4]))])); - inc(i,5); - end else if (i+1)<=length(s) then begin - ss:=ss+widechar(word((BESENHexValues[word(widechar(s[i]))] shl 4) or BESENHexValues[word(widechar(s[i+1]))])); - inc(i,2); - end else begin - ss:=ss+widechar(c); - inc(i); - end; - end else begin - ss:=ss+widechar(c); - inc(i); - end; - end; - ResultValue:=BESENStringValue(ss); - end; -end; - -procedure TBESENObjectGlobal.NativeCompatability(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure ParseCompatibility(s:TBESENString); - var No:boolean; - i:integer; - begin - s:=BESENLowercase(s); - if copy(s,1,3)='no_' then begin - System.delete(s,1,3); - No:=true; - end else if copy(s,1,4)='not_' then begin - System.delete(s,1,4); - No:=true; - end else if copy(s,1,1)='-' then begin - System.delete(s,1,1); - No:=true; - end else if copy(s,1,1)='!' then begin - System.delete(s,1,1); - No:=true; - end else if copy(s,1,1)='~' then begin - System.delete(s,1,1); - No:=true; - end else begin - No:=false; - end; - for i:=low(TBESENCompatibilityModes) to high(TBESENCompatibilityModes) do begin - if s=BESENCompatibilityModes[i].Name then begin - if No then begin - TBESEN(Instance).Compatibility:=TBESEN(Instance).Compatibility and not BESENCompatibilityModes[i].Flag; - end else begin - TBESEN(Instance).Compatibility:=TBESEN(Instance).Compatibility or BESENCompatibilityModes[i].Flag; - end; - break; - end; - end; - end; -var i:integer; - s,ps:TBESENString; -begin - s:=''; - for i:=0 to CountArguments-1 do begin - if length(s)>0 then begin - s:=s+' '; - end; - s:=TBESEN(Instance).ToStr(Arguments^[i]^); - end; - ps:=''; - for i:=1 to length(s) do begin - if BESENUnicodeIsStringWhiteSpace(word(widechar(s[i]))) then begin - if length(ps)>0 then begin - ParseCompatibility(ps); - ps:=''; - end; - end else begin - ps:=ps+s[i]; - end; - end; - if length(ps)>0 then begin - ParseCompatibility(ps); - ps:=''; - end; - s:=''; - for i:=low(TBESENCompatibilityModes) to high(TBESENCompatibilityModes) do begin - if (TBESEN(Instance).Compatibility and BESENCompatibilityModes[i].Flag)<>0 then begin - if length(s)>0 then begin - s:=s+' '; - end; - s:=s+BESENCompatibilityModes[i].Name; - end; - end; - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:=s; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectJSON.pas b/3rd/besen/src/BESENObjectJSON.pas deleted file mode 100644 index 5773631b7..000000000 --- a/3rd/besen/src/BESENObjectJSON.pas +++ /dev/null @@ -1,439 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectJSON; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectJSON=class(TBESENObject) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeStringify(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENGlobals,BESENUtils,BESENArrayUtils,BESENStringUtils,BESENPointerList, - BESENStringTree,BESENNumberUtils,BESENErrors,BESENObjectBoolean,BESENObjectNumber, - BESENObjectString,BESENObjectArray; - -constructor TBESENObjectJSON.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='JSON'; - - RegisterNativeFunction('parse',NativeParse,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('stringify',NativeStringify,3,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectJSON.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectJSON.NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Root,Recviver:TBESENObject; - procedure Walk(const Holder:TBESENObject;const Name:TBESENString;var rv:TBESENValue); - var Val,NewElement,Temp:TBESENValue; - i,Len:int64; - Enumerator:TBESENObjectPropertyEnumerator; - PropKey:TBESENString; - Keys:TBESENStrings; - p:TBESENString; - ValuePointers:array[0..1] of PBESENValue; - o:TBESENObject; - begin - Keys:=nil; - Holder.Get(Name,Val); - if (Val.ValueType=bvtOBJECT) and assigned(Val.Obj) then begin - o:=TBESENObject(Val.Obj); - o.GarbageCollectorLock; - try - if Val.Obj is TBESENObjectArray then begin - i:=0; - TBESENObject(Val.Obj).Get('length',Temp,TBESENObject(Val.Obj),BESENLengthHash); - Len:=TBESEN(Instance).ToInt(Temp); - while i<Len do begin - Walk(TBESENObject(Val.Obj),BESENArrayIndexToStr(i),NewElement); - if NewElement.ValueType=bvtUNDEFINED then begin - TBESENObject(Val.Obj).Delete(BESENArrayIndexToStr(i),false); - end else begin - TBESENObject(Val.Obj).DefineOwnProperty(BESENArrayIndexToStr(i),BESENDataPropertyDescriptor(NewElement,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - inc(i); - end; - end else begin - try - i:=0; - Enumerator:=nil; - PropKey:=''; - try - Enumerator:=TBESENObject(Val.Obj).Enumerator(true,false); - Enumerator.Reset; - while Enumerator.GetNext(PropKey) do begin - if i>=length(Keys) then begin - SetLength(Keys,i+256); - end; - Keys[i]:=PropKey; - inc(i); - end; - finally - BESENFreeAndNil(Enumerator); - end; - i:=0; - while i<length(Keys) do begin - p:=Keys[i]; - Walk(TBESENObject(Val.Obj),p,NewElement); - if NewElement.ValueType=bvtUNDEFINED then begin - TBESENObject(Val.Obj).Delete(p,false); - end else begin - TBESENObject(Val.Obj).DefineOwnProperty(p,BESENDataPropertyDescriptor(NewElement,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - end; - inc(i); - end; - finally - SetLength(Keys,0); - end; - end; - finally - o.GarbageCollectorUnlock; - end; - end; - Temp.ValueType:=bvtSTRING; - Temp.Str:=Name; - ValuePointers[0]:=@Temp; - ValuePointers[1]:=@Val; - TBESEN(Instance).ObjectCall(Recviver,BESENObjectValue(Holder),@ValuePointers,2,rv); - end; -begin - if CountArguments>0 then begin - ResultValue:=TBESEN(Instance).JSONEval({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}TBESEN(Instance).ToStr(Arguments^[0]^){$ifndef BESENSingleStringType}){$endif}); - end else begin - ResultValue:=BESENUndefinedValue; - end; - if (CountArguments>1) and BESENIsCallable(Arguments^[1]^) then begin - Recviver:=TBESENObject(Arguments^[1]^.Obj); - Root:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); - TBESEN(Instance).GarbageCollector.Add(Root); - Root.GarbageCollectorLock; - try - Root.DefineOwnProperty('',BESENDataPropertyDescriptor(ResultValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - Walk(Root,'',ResultValue); - finally - Root.GarbageCollectorUnlock; - end; - end; -end; - -procedure TBESENObjectJSON.NativeStringify(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Value,Replacer,Space,v:TBESENValue; - i,j,k:int64; - Gap,Ident,vs:TBESENString; - ReplacerFunction,Wrapper:TBESENObject; - Stack:TBESENPointerList; - PropertyList:TBESENStrings; - HasPropertyList:boolean; - PropertyListStringTree:TBESENStringTree; - PropertyListStringTreeData:TBESENStringTreeData; - procedure Str(const Key:TBESENSTRING;const Holder:TBESENObject;var rv:TBESENValue); - var Value,toJSON,v,Temp:TBESENValue; - Output,StepBack:TBESENString; - i,j:int64; - oi:integer; - Enumerator:TBESENObjectPropertyEnumerator; - PropKey:TBESENString; - Keys:TBESENStrings; - ValuePointers:array[0..1] of PBESENValue; - begin - Keys:=nil; - Holder.Get(Key,Value); - if Value.ValueType=bvtOBJECT then begin - TBESENObject(Value.Obj).Get('toJSON',toJSON); - iF BESENIsCallable(toJSON) then begin - v.ValueType:=bvtSTRING; - v.Str:=Key; - ValuePointers[0]:=@v; - TBESEN(Instance).ObjectCall(TBESENObject(toJSON.Obj),Value,@ValuePointers,1,Temp); - BESENCopyValue(Value,Temp); - end; - end; - if assigned(ReplacerFunction) then begin - v.ValueType:=bvtSTRING; - v.Str:=Key; - ValuePointers[0]:=@v; - ValuePointers[1]:=@Value; - TBESEN(Instance).ObjectCall(ReplacerFunction,BESENObjectValue(Holder),@ValuePointers,2,Temp); - BESENCopyValue(Value,Temp); - end; - if (Value.ValueType=bvtOBJECT) and not assigned(Value.Obj) then begin - Value.ValueType:=bvtNULL; - end; - if Value.ValueType=bvtOBJECT then begin - if Value.Obj is TBESENObjectNumber then begin - TBESEN(Instance).ToNumberValue(Value,Temp); - BESENCopyValue(Value,Temp); - end else if Value.Obj is TBESENObjectString then begin - TBESEN(Instance).ToStringValue(Value,Temp); - BESENCopyValue(Value,Temp); - end else if Value.Obj is TBESENObjectBoolean then begin - TBESEN(Instance).ToPrimitiveValue(Value,Temp); - BESENCopyValue(Value,Temp); - end; - end; - case Value.ValueType of - bvtNULL:begin - rv:=BESENStringValue('null'); - end; - bvtBOOLEAN:begin - if Value.Bool then begin - rv:=BESENStringValue('true'); - end else begin - rv:=BESENStringValue('false'); - end; - end; - bvtSTRING:begin - rv:=BESENStringValue(BESENJSONStringQuote(TBESEN(Instance).ToStr(Value))); - end; - bvtNUMBER:begin - if BESENIsFinite(Value.Num) then begin - TBESEN(Instance).ToStringValue(Value,rv); - end else begin - rv:=BESENStringValue('null'); - end; - end; - bvtOBJECT:begin - if Stack.Find(Value.Obj)>=0 then begin - raise EBESENTypeError.Create('Cyclical situation found'); - end; - oi:=Stack.Add(Value.Obj); - StepBack:=Ident; - Ident:=Ident+Gap; - if BESENIsCallable(Value) then begin - rv:=BESENUndefinedValue; - end else if Value.Obj is TBESENObjectArray then begin - TBESENObject(Value.Obj).Get('length',Temp,TBESENObject(Value.Obj),BESENLengthHash); - j:=TBESEN(Instance).ToUInt32(Temp); - if j=0 then begin - Output:='[]'; - end else begin - if length(Ident)>0 then begin - Output:='['#10+Ident; - end else begin - Output:='['; - end; - i:=0; - while i<j do begin - Str(BESENArrayIndexToStr(i),TBESENObject(Value.Obj),v); - if v.ValueType=bvtUNDEFINED then begin - Output:=Output+'null'; - end else begin - Output:=Output+TBESEN(Instance).ToStr(v); - end; - inc(i); - if i<j then begin - Output:=Output+','; - if length(Ident)>0 then begin - Output:=Output+#10+Ident; - end; - end; - end; - if length(Ident)>0 then begin - Output:=Output+#10+StepBack+']'; - end else begin - Output:=Output+']'; - end; - end; - rv:=BESENStringValue(Output); - end else begin - try - if HasPropertyList and (length(PropertyList)>0) then begin - Keys:=copy(PropertyList,0,length(PropertyList)); - j:=length(Keys); - end else begin - j:=0; - Enumerator:=nil; - PropKey:=''; - try - Enumerator:=TBESENObject(Value.Obj).Enumerator(true,false); - Enumerator.Reset; - while Enumerator.GetNext(PropKey) do begin - if j>=length(Keys) then begin - SetLength(Keys,j+256); - end; - Keys[j]:=PropKey; - inc(j); - end; - finally - BESENFreeAndNil(Enumerator); - end; - end; - if j=0 then begin - Output:='{}'; - end else begin - if length(Ident)>0 then begin - Output:='{'#10+Ident; - end else begin - Output:='{'; - end; - i:=0; - while i<j do begin - Str(Keys[i],TBESENObject(Value.Obj),v); - Output:=Output+BESENJSONStringQuote(Keys[i]); - if length(Ident)>0 then begin - Output:=Output+': '; - end else begin - Output:=Output+':'; - end; - if v.ValueType=bvtUNDEFINED then begin - Output:=Output+'null'; - end else begin - Output:=Output+TBESEN(Instance).ToStr(v); - end; - inc(i); - if i<j then begin - Output:=Output+','; - if length(Ident)>0 then begin - Output:=Output+#10+Ident; - end; - end; - end; - if length(Ident)>0 then begin - Output:=Output+#10+StepBack+'}'; - end else begin - Output:=Output+'}'; - end; - end; - rv:=BESENStringValue(Output); - finally - SetLength(Keys,0); - end; - end; - Stack.Delete(oi); - Ident:=StepBack; - end; - else begin - rv:=BESENUndefinedValue; - end; - end; - end; -var PropItem:TBESENObjectProperty; -begin - Gap:=''; - Ident:=''; - ReplacerFunction:=nil; - PropertyList:=nil; - Stack:=TBESENPointerList.Create; - try - if CountArguments>0 then begin - Value:=Arguments^[0]^; - end else begin - Value:=BESENUndefinedValue; - end; - if CountArguments>1 then begin - Replacer:=Arguments^[1]^; - end else begin - Replacer:=BESENUndefinedValue; - end; - HasPropertyList:=false; - if (Replacer.ValueType=bvtOBJECT) and assigned(Replacer.Obj) then begin - if BESENIsCallable(Replacer) then begin - ReplacerFunction:=TBESENObject(Replacer.Obj); - end else if Replacer.Obj is TBESENObjectArray then begin - PropertyListStringTree:=TBESENStringTree.Create; - try - HasPropertyList:=true; - PropItem:=TBESENObject(Replacer.Obj).Properties.First; - k:=0; - while assigned(PropItem) do begin - if (boppENUMERABLE in PropItem.Descriptor.Presents) and (bopaENUMERABLE in PropItem.Descriptor.Attributes) and BESENArrayToIndex(PropItem.Key,i) then begin - TBESENObject(Replacer.Obj).Get(PropItem.Key,v); - if (v.ValueType in [bvtSTRING,bvtNUMBER]) or ((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and ((TBESENObject(v.Obj) is TBESENObjectString) or (TBESENObject(v.Obj) is TBESENObjectNumber))) then begin - vs:=TBESEN(Instance).ToStr(v); - if not PropertyListStringTree.Find(vs,PropertyListStringTreeData) then begin - PropertyListStringTreeData.i:=k; - PropertyListStringTree.Add(vs,PropertyListStringTreeData); - if k>=length(PropertyList) then begin - SetLength(PropertyList,k+256); - end; - PropertyList[k]:=vs; - inc(k); - end; - end; - end; - PropItem:=PropItem.Next; - end; - SetLength(PropertyList,k); - finally - BESENFreeAndNil(PropertyListStringTree); - end; - end; - end; - if CountArguments>2 then begin - if (Arguments^[2]^.ValueType=bvtOBJECT) and assigned(Arguments^[2]^.Obj) then begin - if Arguments^[2]^.Obj is TBESENObjectNumber then begin - TBESEN(Instance).ToNumberValue(Arguments^[2]^,Space); - end else if Arguments^[2]^.Obj is TBESENObjectString then begin - TBESEN(Instance).ToStringValue(Arguments^[2]^,Space); - end; - end else begin - Space:=Arguments^[2]^; - end; - if Space.ValueType=bvtNumber then begin - j:=min(10,TBESEN(Instance).ToInt(Space)); - i:=0; - while i<j do begin - Gap:=Gap+' '; - inc(i); - end; - end else if Space.ValueType=bvtSTRING then begin - Gap:=copy(TBESEN(Instance).ToStr(Space),1,10); - end; - end; - Wrapper:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); - TBESEN(Instance).GarbageCollector.Add(Wrapper); - Wrapper.GarbageCollectorLock; - try - Wrapper.DefineOwnProperty('',BESENDataPropertyDescriptor(Value,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); - Str('',Wrapper,ResultValue); - finally - Wrapper.GarbageCollectorUnlock; - end; - finally - BESENFreeAndNil(Stack); - SetLength(PropertyList,0); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectMath.pas b/3rd/besen/src/BESENObjectMath.pas deleted file mode 100644 index 35944d657..000000000 --- a/3rd/besen/src/BESENObjectMath.pas +++ /dev/null @@ -1,524 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectMath; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectMath=class(TBESENObject) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeAbs(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeACos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeASin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeATan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeATan2(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCeil(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeExp(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeFloor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLog(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeMax(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeMin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeRandom(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeRound(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSqrt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeTan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENNumberUtils; - -constructor TBESENObjectMath.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -var v:TBESENValue; -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Math'; - - v:=BESENEmptyValue; - v:=BESENNumberValue(2.7182818284590452354); - OverwriteData('E',v,[]); - - v:=BESENNumberValue(2.7182818284590452354); - OverwriteData('E',v,[]); - - v:=BESENNumberValue(2.302585092994046); - OverwriteData('LN10',v,[]); - - v:=BESENNumberValue(0.6931471805599453); - OverwriteData('LN2',v,[]); - - v:=BESENNumberValue(1.4426950408889634); - OverwriteData('LOG2E',v,[]); - - v:=BESENNumberValue(0.4342944819032518); - OverwriteData('LOG10E',v,[]); - - v:=BESENNumberValue(3.1415926535897932); - OverwriteData('PI',v,[]); - - v:=BESENNumberValue(0.7071067811865476); - OverwriteData('SQRT1_2',v,[]); - - v:=BESENNumberValue(1.4142135623730951); - OverwriteData('SQRT2',v,[]); - - RegisterNativeFunction('abs',NativeAbs,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('acos',NativeACos,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('asin',NativeASin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('atan',NativeATan,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('atan2',NativeATan2,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('ceil',NativeCeil,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('cos',NativeCos,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('exp',NativeExp,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('floor',NativeFloor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('log',NativeLog,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('max',NativeMax,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('min',NativeMin,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('pow',NativePow,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('random',NativeRandom,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('round',NativeRound,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('sin',NativeSin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('sqrt',NativeSqrt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('tan',NativeTan,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectMath.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectMath.NativeAbs(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if CountArguments=0 then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if not BESENIsNaN(ResultValue.Num) then begin - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi and $7fffffff; - end; - end; -end; - -procedure TBESENObjectMath.NativeACos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if CountArguments=0 then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if not BESENIsNaN(ResultValue.Num) then begin - if (ResultValue.Num<-1) or (ResultValue.Num>1) then begin - int64(pointer(@ResultValue.Num)^):=int64(pointer(@BESENDoubleNaN)^); - end else if ResultValue.Num=1 then begin - ResultValue.Num:=0; - end else begin - ResultValue.Num:=arccos(ResultValue.Num); - end; - end; - end; -end; - -procedure TBESENObjectMath.NativeASin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if CountArguments=0 then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if not BESENIsNaN(ResultValue.Num) then begin - if (ResultValue.Num<-1) or (ResultValue.Num>1) then begin - int64(pointer(@ResultValue.Num)^):=int64(pointer(@BESENDoubleNaN)^); - end else if not BESENIsZero(ResultValue.Num) then begin - ResultValue.Num:=arcsin(ResultValue.Num); - end; - end; - end; -end; - -procedure TBESENObjectMath.NativeATan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if CountArguments=0 then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if not (BESENIsNaN(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin - if BESENIsPosInfinite(ResultValue.Num) then begin - ResultValue.Num:=PI*0.5; - end else if BESENIsNegInfinite(ResultValue.Num) then begin - ResultValue.Num:=-(PI*0.5); - end else begin - ResultValue.Num:=arctan(ResultValue.Num); - end; - end; - end; -end; - -procedure TBESENObjectMath.NativeATan2(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var x,y:TBESENNumber; -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments<2 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - y:=TBESEN(Instance).ToNum(Arguments^[0]^); - x:=TBESEN(Instance).ToNum(Arguments^[1]^); - if BESENIsNaN(y) or BESENIsNaN(x) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if (y>0) and BESENIsZero(x) then begin - ResultValue.Num:=PI*0.5; - end else if BESENIsPosZero(y) and ((x>0) or BESENIsPosZero(x)) then begin - ResultValue.Num:=0; - end else if BESENIsPosZero(y) and (BESENIsNegZero(x) or (x<0)) then begin - ResultValue.Num:=PI; - end else if BESENIsNegZero(y) and ((BESENIsFinite(x) and not BESENIsNegative(x)) or BESENIsPosZero(x)) then begin - ResultValue.Num:=0; - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end else if BESENIsNegZero(y) and (BESENIsNegZero(x) or (x<0)) then begin - ResultValue.Num:=-PI; - end else if (y<0) and BESENIsZero(x) then begin - ResultValue.Num:=-PI*0.5; - end else if ((y>0) and BESENIsFinite(y)) and BESENIsPosInfinite(x) then begin - ResultValue.Num:=0; - end else if ((y>0) and BESENIsFinite(y)) and BESENIsNegInfinite(x) then begin - ResultValue.Num:=PI; - end else if ((y<0) and BESENIsFinite(y)) and BESENIsPosInfinite(x) then begin - ResultValue.Num:=0; - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end else if ((y<0) and BESENIsFinite(y)) and BESENIsNegInfinite(x) then begin - ResultValue.Num:=-PI; - end else if BESENIsPosInfinite(y) and BESENIsFinite(x) then begin - ResultValue.Num:=PI*0.5; - end else if BESENIsNegInfinite(y) and BESENIsFinite(x) then begin - ResultValue.Num:=-(PI*0.5); - end else if BESENIsPosInfinite(y) and BESENIsPosInfinite(x) then begin - ResultValue.Num:=PI*0.25; - end else if BESENIsPosInfinite(y) and BESENIsNegInfinite(x) then begin - ResultValue.Num:=(3*PI)*0.25; - end else if BESENIsNegInfinite(y) and BESENIsPosInfinite(x) then begin - ResultValue.Num:=-(PI*0.25); - end else if BESENIsNegInfinite(y) and BESENIsNegInfinite(x) then begin - ResultValue.Num:=-((3*PI)*0.25); - end else begin - ResultValue.Num:=arctan2(y,x); - end; - end; -end; - -procedure TBESENObjectMath.NativeCeil(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if not (BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin - if (ResultValue.Num<0) and (ResultValue.Num>(-1)) then begin - ResultValue.Num:=0; - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end else begin - ResultValue.Num:=BESENCeil(ResultValue.Num); - end; - end; - end; -end; - -procedure TBESENObjectMath.NativeCos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if BESENIsZero(ResultValue.Num) then begin - ResultValue.Num:=1; - end else begin - ResultValue.Num:=cos(ResultValue.Num); - end; - end; -end; - -procedure TBESENObjectMath.NativeExp(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if BESENIsZero(ResultValue.Num) then begin - ResultValue.Num:=1; - end else if BESENIsPosInfinite(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else if BESENIsNegInfinite(ResultValue.Num) then begin - ResultValue.Num:=0; - end else begin - ResultValue.Num:=exp(ResultValue.Num); - end; - end; -end; - -procedure TBESENObjectMath.NativeFloor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if not (BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin - if (ResultValue.Num>0) and (ResultValue.Num<1) then begin - ResultValue.Num:=0; - end else begin - ResultValue.Num:=BESENFloor(ResultValue.Num); - end; - end; - end; -end; - -procedure TBESENObjectMath.NativeLog(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) or (ResultValue.Num<0) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if BESENIsZero(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); - end else if ResultValue.Num=1 then begin - ResultValue.Num:=0; - end else if BESENIsPosInfinite(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else begin - ResultValue.Num:=ln(ResultValue.Num); - end; - end; -end; - -procedure TBESENObjectMath.NativeMax(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var x,n:TBESENNumber; - i:integer; -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); - end else begin - n:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); - for i:=0 to CountArguments-1 do begin - x:=TBESEN(Instance).ToNum(Arguments^[i]^); - if BESENIsNaN(x) then begin - n:=TBESENNumber(pointer(@BESENDoubleNaN)^); - break; - end; - if (i=0) or ((x>n) or (BESENIsPosInfinite(x) or (BESENIsPosZero(x) and BESENIsNegZero(n)))) then begin - n:=x; - end; - end; - ResultValue.Num:=n; - end; -end; - -procedure TBESENObjectMath.NativeMin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var x,n:TBESENNumber; - i:integer; -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else begin - n:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - for i:=0 to CountArguments-1 do begin - x:=TBESEN(Instance).ToNum(Arguments^[i]^); - if BESENIsNaN(x) then begin - n:=TBESENNumber(pointer(@BESENDoubleNaN)^); - break; - end; - if (i=0) or ((x<n) or (BESENIsNegInfinite(x) or (BESENIsNegZero(x) and BESENIsPosZero(n)))) then begin - n:=x; - end; - end; - ResultValue.Num:=n; - end; -end; - -procedure TBESENObjectMath.NativePow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var x,y:TBESENNumber; -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments<2 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - x:=TBESEN(Instance).ToNum(Arguments^[0]^); - y:=TBESEN(Instance).ToNum(Arguments^[1]^); - if BESENIsNaN(y) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if BESENIsZero(y) then begin - ResultValue.Num:=1; - end else if BESENIsNaN(x) and not BESENIsZero(y) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if (abs(x)>1) and BESENIsPosInfinite(y) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else if (abs(x)>1) and BESENIsNegInfinite(y) then begin - ResultValue.Num:=0; - end else if (abs(x)=1) and BESENIsInfinite(y) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if (abs(x)<1) and BESENIsPosInfinite(y) then begin - ResultValue.Num:=0; - end else if (abs(x)<1) and BESENIsNegInfinite(y) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else if BESENIsPosInfinite(x) and (y>0) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else if BESENIsPosInfinite(x) and (y<0) then begin - ResultValue.Num:=0; - end else if BESENIsNegInfinite(x) and (y>0) then begin - y:=abs(BESENModulo(y,2.0)); - if y=1 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); - end else begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end; - end else if BESENIsNegInfinite(x) and (y<0) then begin - y:=abs(BESENModulo(-y,2.0)); - ResultValue.Num:=0; - if y=1 then begin - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end; - end else if BESENIsPosZero(x) and (y>0) then begin - ResultValue.Num:=0; - end else if BESENIsPosZero(x) and (y<0) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end else if BESENIsNegZero(x) and (y>0) then begin - y:=abs(BESENModulo(-y,2.0)); - ResultValue.Num:=0; - if y=1 then begin - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end; - end else if BESENIsNegZero(x) and (y<0) then begin - y:=abs(BESENModulo(y,2.0)); - if y=1 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); - end else begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); - end; - end else if ((x<0) and BESENIsFinite(x)) and (BESENIsFinite(y) and not BESENIsZero(frac(y))) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - ResultValue.Num:=power(x,y); - end; - end; -end; - -procedure TBESENObjectMath.NativeRandom(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=TBESEN(Instance).RandomGenerator.GetNumber; -end; - -procedure TBESENObjectMath.NativeRound(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if not (BESENIsZero(ResultValue.Num) or BESENIsInfinite(ResultValue.Num)) then begin - if (ResultValue.Num>=-0.5) and (ResultValue.Num<0) then begin - ResultValue.Num:=0; - PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; - end else if (ResultValue.Num>0) and (ResultValue.Num<0.5) then begin - ResultValue.Num:=0; - end else begin - ResultValue.Num:=BESENFloor(ResultValue.Num+0.5); - end; - end; - end; -end; - -procedure TBESENObjectMath.NativeSin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if not BESENIsZero(ResultValue.Num) then begin - ResultValue.Num:=sin(ResultValue.Num); - end; - end; -end; - -procedure TBESENObjectMath.NativeSqrt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) or BESENIsNegative(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if not (BESENIsZero(ResultValue.Num) or BESENIsPosInfinite(ResultValue.Num)) then begin - ResultValue.Num:=sqrt(ResultValue.Num); - end; - end; -end; - -procedure TBESENObjectMath.NativeTan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - if CountArguments=0 then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); - if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin - ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); - end else if not BESENIsZero(ResultValue.Num) then begin - ResultValue.Num:=tan(ResultValue.Num); - end; - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectNativeFunction.pas b/3rd/besen/src/BESENObjectNativeFunction.pas deleted file mode 100644 index 99e4ee82c..000000000 --- a/3rd/besen/src/BESENObjectNativeFunction.pas +++ /dev/null @@ -1,102 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectNativeFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectNativeFunction=class(TBESENObjectFunction) - public - Native:TBESENNativeFunction; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; - function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasCall:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectNativeFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='native'; - Native:=nil; -end; - -destructor TBESENObjectNativeFunction.Destroy; -begin - inherited Destroy; -end; - -function TBESENObjectNativeFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); - if TBESEN(Instance).IsStrict and (P='caller') then begin - raise EBESENTypeError.Create('"caller" not allowed here'); - end; -end; - -function TBESENObjectNativeFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; -begin - if not assigned(Base) then begin - Base:=self; - end; - result:=inherited GetIndex(Index,ID,AResult,Base); - if TBESEN(Instance).IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin - raise EBESENTypeError.Create('"caller" not allowed here'); - end; -end; - -procedure TBESENObjectNativeFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if assigned(Native) then begin - Native(ThisArgument,Arguments,CountArguments,AResult); - end else begin - AResult.ValueType:=bvtUNDEFINED; - end; -end; - -function TBESENObjectNativeFunction.HasCall:TBESENBoolean; -begin - result:=true; -end; - -end. diff --git a/3rd/besen/src/BESENObjectNumber.pas b/3rd/besen/src/BESENObjectNumber.pas deleted file mode 100644 index c981651d3..000000000 --- a/3rd/besen/src/BESENObjectNumber.pas +++ /dev/null @@ -1,75 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectNumber; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectNumber=class(TBESENObject) - public - Value:TBESENNumber; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENObjectNumber.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Number'; - ObjectName:=''; - - Value:=0; -end; - -destructor TBESENObjectNumber.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectNumber.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectNumber.Mark; -begin - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENObjectNumberConstructor.pas b/3rd/besen/src/BESENObjectNumberConstructor.pas deleted file mode 100644 index a0261fc5a..000000000 --- a/3rd/besen/src/BESENObjectNumberConstructor.pas +++ /dev/null @@ -1,130 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectNumberConstructor; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectNumberConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENObjectNumber,BESENNumberUtils,BESENGlobals,BESENObjectArray; - -constructor TBESENObjectNumberConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -var v:TBESENValue; -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='Number'; - - v:=BESENEmptyValue; - - v:=BESENNumberValue(0); - move(BESENDoubleMax,v.Num,sizeof(TBESENNumber)); - OverwriteData('MAX_VALUE',v,[]); - - v:=BESENNumberValue(0); - move(BESENDoubleMin,v.Num,sizeof(TBESENNumber)); - OverwriteData('MIN_VALUE',v,[]); - - v:=BESENNumberValue(0); - move(BESENDoubleNaN,v.Num,sizeof(TBESENNumber)); - OverwriteData('NaN',v,[]); - - v:=BESENNumberValue(0); - move(BESENDoubleInfNeg,v.Num,sizeof(TBESENNumber)); - OverwriteData('NEGATIVE_INFINITY',v,[]); - - v:=BESENNumberValue(0); - move(BESENDoubleInfPos,v.Num,sizeof(TBESENNumber)); - OverwriteData('POSITIVE_INFINITY',v,[]); -end; - -destructor TBESENObjectNumberConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectNumberConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectNumber; -begin - r1:=TBESENObjectNumber.Create(Instance,TBESEN(Instance).ObjectNumberPrototype,false); - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - if CountArguments>0 then begin - r1.Value:=TBESEN(Instance).ToNum(Arguments^[0]^); - end else begin - r1.Value:=0.0; - end; - finally - r1.GarbageCollectorUnlock; - end; - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=r1; -end; - -procedure TBESENObjectNumberConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var v:TBESENValue; -begin - if CountArguments<1 then begin - AResult.ValueType:=bvtNUMBER; - AResult.Num:=0; - end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectArray) then begin - TBESENObjectArray(Arguments^[0]^.Obj).Get('length',v,TBESENObject(Arguments^[0]^.Obj),BESENLengthHash); - TBESEN(Instance).ToNumberValue(v,AResult); - end else begin - TBESEN(Instance).ToNumberValue(Arguments^[0]^,AResult); - end; -end; - -function TBESENObjectNumberConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectNumberConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -end. diff --git a/3rd/besen/src/BESENObjectNumberPrototype.pas b/3rd/besen/src/BESENObjectNumberPrototype.pas deleted file mode 100644 index 4ce2dfb24..000000000 --- a/3rd/besen/src/BESENObjectNumberPrototype.pas +++ /dev/null @@ -1,281 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectNumberPrototype; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectNumber,BESENValue,BESENObjectPropertyDescriptor, - BESENObjectBoolean; - -type TBESENObjectNumberPrototype=class(TBESENObjectNumber) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToExponential(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToPrecision(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors,BESENNumberUtils; - -constructor TBESENObjectNumberPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Number'; - ObjectName:='Number'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - RegisterNativeFunction('toString',NativeToString,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toFixed',NativeToFixed,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toExponential',NativeToExponential,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toPrecision',NativeToPrecision,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectNumberPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectNumberPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Radix:integer; - nv:TBESENValue; -begin - if ThisArgument.ValueType=bvtNUMBER then begin - nv:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; - if CountArguments=0 then begin - Radix:=10; - end else begin - Radix:=TBESEN(Instance).ToInt32(Arguments^[0]^); - end; - if Radix=10 then begin - TBESEN(Instance).ToStringValue(nv,ResultValue); - end else if Radix in [2..36] then begin - ResultValue.ValueType:=bvtSTRING; - if BESENIsNaN(nv.Num) then begin - ResultValue.Str:='NaN'; - end else if BESENIsZero(nv.Num) then begin - ResultValue.Str:='0'; - end else if BESENIsInfinite(nv.Num) then begin - if BESENIsNegative(nv.Num) then begin - ResultValue.Str:='-Infinity'; - end else begin - ResultValue.Str:='Infinity'; - end; - end else begin - ResultValue.Str:=BESENNumberToRadixString(nv.Num,Radix); - end; - end else begin - raise EBESENRangeError.Create('Bad radix'); - end; -end; - -procedure TBESENObjectNumberPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var nv:TBESENValue; -begin - if ThisArgument.ValueType=bvtNUMBER then begin - nv:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; - ResultValue:=BESENStringValue(BESENFloatToLocaleStr(nv.Num)); -end; - -procedure TBESENObjectNumberPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if ThisArgument.ValueType=bvtNUMBER then begin - ResultValue:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - ResultValue:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; -end; - -procedure TBESENObjectNumberPrototype.NativeToFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -{$ifdef UseDTOA} -var f:int64; - v,nv:TBESENValue; - x:TBESENNumber; -begin - if ThisArgument.ValueType=bvtNUMBER then begin - nv:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; - f:=0; - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin - if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>1076)) then begin - raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); - end; - end else begin - if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin - raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); - end; - end; - f:=trunc(v.Num); - end; - x:=nv.Num; - ResultValue.ValueType:=bvtSTRING; - if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin - ResultValue.Str:=BESENFloatToStr(x); - end else begin - ResultValue.Str:=dtostr(x,DTOSTR_FIXED,f); - end; -end; -{$else} -var f:int64; - v,nv:TBESENValue; - x:TBESENNumber; - s:TBESENString; - ss:shortstring; -begin - if ThisArgument.ValueType=bvtNUMBER then begin - nv:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; - f:=0; - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin - raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); - end; - f:=trunc(v.Num); - end; - x:=nv.Num; - ResultValue.ValueType:=bvtSTRING; - if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin - ResultValue.Str:=BESENFloatToStr(x); - end else begin - str(x:1:f,ss); - s:=TBESENString(ss); - ResultValue.Str:=s; - end; -end; -{$endif} - -procedure TBESENObjectNumberPrototype.NativeToExponential(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v,nv:TBESENValue; - x:TBESENNumber; - f:integer; -begin - if ThisArgument.ValueType=bvtNUMBER then begin - nv:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; - f:=0; - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin - if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>1076)) then begin - raise EBESENRangeError.CreateUTF16('Exponent width '+BESENFloatToStr(v.Num)+' out of range'); - end; - end else begin - if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin - raise EBESENRangeError.CreateUTF16('Exponent width '+BESENFloatToStr(v.Num)+' out of range'); - end; - end; - f:=trunc(v.Num); - end; - x:=nv.Num; - if not BESENIsFinite(x) then begin - ResultValue:=BESENStringValue(BESENFloatToStr(x)); - end else begin - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,f+1))); - end else begin - ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL,0))); - end; - end; -end; - -procedure TBESENObjectNumberPrototype.NativeToPrecision(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var f:int64; - v,nv:TBESENValue; - x:TBESENNumber; -begin - if ThisArgument.ValueType=bvtNUMBER then begin - nv:=ThisArgument; - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin - nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a Number object'); - end; - f:=0; - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin - if BESENIsNaN(v.Num) or ((v.Num<1) or (v.Num>1076)) then begin - raise EBESENRangeError.CreateUTF16('Precision '+BESENFloatToStr(v.Num)+' out of range'); - end; - end else begin - if BESENIsNaN(v.Num) or ((v.Num<1) or (v.Num>21)) then begin - raise EBESENRangeError.CreateUTF16('Precision '+BESENFloatToStr(v.Num)+' out of range'); - end; - end; - f:=trunc(v.Num); - end; - x:=nv.Num; - if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin - ResultValue:=BESENStringValue(BESENFloatToStr(x)); - end else begin - ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_PRECISION,f))); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectPropertyDescriptor.pas b/3rd/besen/src/BESENObjectPropertyDescriptor.pas deleted file mode 100644 index 425667358..000000000 --- a/3rd/besen/src/BESENObjectPropertyDescriptor.pas +++ /dev/null @@ -1,146 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectPropertyDescriptor; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENValue; - -type TBESENObjectPropertyDescriptorAttribute=(bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE); - - TBESENObjectPropertyDescriptorAttributes=set of TBESENObjectPropertyDescriptorAttribute; - - TBESENObjectPropertyDescriptorPresent=(boppVALUE,boppGETTER,boppSETTER,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE,boppPROTO); - - TBESENObjectPropertyDescriptorPresents=set of TBESENObjectPropertyDescriptorPresent; - - PBESENObjectPropertyDescriptor=^TBESENObjectPropertyDescriptor; - TBESENObjectPropertyDescriptor=record - Value:TBESENValue; - Getter:TObject; - Setter:TObject; - Attributes:TBESENObjectPropertyDescriptorAttributes; - Presents:TBESENObjectPropertyDescriptorPresents; - end; - - TBESENObjectPropertyDescriptors=array of TBESENObjectPropertyDescriptor; - -var BESENUndefinedPropertyDescriptor:TBESENObjectPropertyDescriptor; - -function BESENAccessorPropertyDescriptor(const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} -function BESENDataPropertyDescriptor(const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} -function BESENPropertyDescriptor(const Value:TBESENValue;const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} - -function BESENIsUndefinedDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsAccessorDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsDataDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsGenericDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -function BESENIsInconsistentDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} - -implementation - -uses BESEN; - -function BESENAccessorPropertyDescriptor(const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} -begin - result.Value.ValueType:=bvtUNDEFINED; - result.Getter:=Getter; - result.Setter:=Setter; - result.Attributes:=Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; - result.Presents:=[boppENUMERABLE,boppCONFIGURABLE]; - if assigned(result.Getter) then begin - result.Presents:=result.Presents+[boppGETTER]; - end; - if assigned(result.Setter) then begin - result.Presents:=result.Presents+[boppSETTER]; - end; -end; - -function BESENDataPropertyDescriptor(const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} -begin - BESENCopyValue(result.Value,Value); - result.Getter:=nil; - result.Setter:=nil; - result.Attributes:=Attributes; - result.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; -end; - -function BESENPropertyDescriptor(const Value:TBESENValue;const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} -begin - BESENCopyValue(result.Value,Value); - result.Getter:=Getter; - result.Setter:=Setter; - result.Attributes:=Attributes; - result.Presents:=[boppVALUE,boppGETTER,boppSETTER,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; -end; - -function BESENIsUndefinedDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=Descriptor.Presents=[]; -end; - -function BESENIsAccessorDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]; -end; - -function BESENIsDataDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]; -end; - -function BESENIsGenericDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=not (BESENIsAccessorDescriptor(Descriptor) or BESENIsDataDescriptor(Descriptor)); -end; - -function BESENIsInconsistentDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]); -end; - -procedure InitBESEN; -begin - fillchar(BESENUndefinedPropertyDescriptor,sizeof(TBESENObjectPropertyDescriptor),#0); - BESENUndefinedPropertyDescriptor.Presents:=[]; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. - diff --git a/3rd/besen/src/BESENObjectPrototype.pas b/3rd/besen/src/BESENObjectPrototype.pas deleted file mode 100644 index 713a8c147..000000000 --- a/3rd/besen/src/BESENObjectPrototype.pas +++ /dev/null @@ -1,223 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectPrototype; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectPrototype=class(TBESENObject) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToSource(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeHasOwnProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIsPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePropertyIsEnumerable(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectName:='prototype'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toSource',NativeToSource,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('hasOwnProperty',NativeHasOwnProperty,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('isPrototypeOf',NativeIsPrototypeOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('propertyIsEnumerable',NativePropertyIsEnumerable,0,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var o:TBesenObject; -begin - // ES5 errata fix - case ThisArgument.ValueType of - bvtUNDEFINED:begin - ResultValue:=BESENStringValue('[object Undefined]'); - end; - bvtNULL:begin - ResultValue:=BESENStringValue('[object Null]'); - end; - else begin - o:=TBESEN(Instance).ToObj(ThisArgument); - o.GarbageCollectorLock; - try - if assigned(o) then begin - if length(o.ObjectClassName)>0 then begin - ResultValue:=BESENStringValue('[object '+o.ObjectClassName+']'); - end else begin - ResultValue:=BESENStringValue('[object Object]'); - end; - end else begin - BESENThrowTypeError('Null this object'); - end; - finally - o.GarbageCollectorUnlock; - end; - end; - end; -end; - -procedure TBESENObjectPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENValue; - o:TBesenObject; -begin - o:=TBESEN(Instance).ToObj(ThisArgument); - if assigned(o) then begin - o.GarbageCollectorLock; - try - o.Get('toString',v); - if (v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall then begin - TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),ThisArgument,Arguments,CountArguments,ResultValue); - end else begin - BESENThrowTypeError('Null this object'); - end; - finally - o.GarbageCollectorUnlock; - end; - end else begin - BESENThrowTypeError('Null this object'); - end; -end; - -procedure TBESENObjectPrototype.NativeToSource(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue:=BESENStringValue('/* Unimplemented */'); -end; - -procedure TBESENObjectPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - TBESEN(Instance).ToObjectValue(ThisArgument,ResultValue); -end; - -procedure TBESENObjectPrototype.NativeHasOwnProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Descriptor:TBESENObjectPropertyDescriptor; - o:TBesenObject; -begin - o:=TBESEN(Instance).ToObj(ThisArgument); - if not assigned(o) then begin - raise EBESENTypeError.Create('Null this object'); - end; - o.GarbageCollectorLock; - try - ResultValue.ValueType:=bvtBOOLEAN; - if CountArguments>0 then begin - ResultValue.Bool:=o.GetOwnProperty(TBESEN(Instance).ToStr(Arguments^[0]^),Descriptor); - end else begin - ResultValue.Bool:=false; - end; - finally - o.GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectPrototype.NativeIsPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v,o:TBESENObject; -begin - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=false; - if (CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) then begin - o:=TBESEN(Instance).ToObj(ThisArgument); - if not assigned(o) then begin - raise EBESENTypeError.Create('Null this object'); - end; - o.GarbageCollectorLock; - try - v:=TBESENObject(Arguments^[0]^.Obj); - while assigned(v) do begin - v:=v.Prototype; - if assigned(v) then begin - if o=v then begin - ResultValue.Bool:=true; - break; - end; - end else begin - ResultValue.Bool:=false; - break; - end; - end; - finally - o.GarbageCollectorUnlock; - end; - end else begin - ResultValue.Bool:=false; - end; -end; - -procedure TBESENObjectPrototype.NativePropertyIsEnumerable(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var Descriptor:TBESENObjectPropertyDescriptor; - o:TBESENObject; - s:TBESENString; -begin - ResultValue.ValueType:=bvtBOOLEAN; - if CountArguments>0 then begin - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - o:=TBESEN(Instance).ToObj(ThisArgument); - if not assigned(o) then begin - raise EBESENTypeError.Create('Null this object'); - end; - o.GarbageCollectorLock; - try - if o.GetOwnProperty(s,Descriptor) then begin - ResultValue.Bool:=(boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in Descriptor.Attributes); - end else begin - ResultValue.Bool:=false; - end; - finally - o.GarbageCollectorUnlock; - end; - end else begin - ResultValue.Bool:=false; - end; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENObjectRegExp.pas b/3rd/besen/src/BESENObjectRegExp.pas deleted file mode 100644 index c812bbc73..000000000 --- a/3rd/besen/src/BESENObjectRegExp.pas +++ /dev/null @@ -1,199 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectRegExp; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor, - BESENRegExp; - -type TBESENObjectRegExp=class(TBESENObject) - public - Engine:TBESENRegExp; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasCall:TBESENBoolean; override; - procedure Finalize; override; - procedure Mark; override; - procedure SetStatic(const Input:TBESENString;const Captures:TBESENRegExpCaptures); - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectRegExp.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -var bv:TBESENValue; -begin - inherited Create(AInstance,APrototype); - ObjectClassName:='RegExp'; - ObjectName:=''; - - Engine:=TBESEN(Instance).DefaultRegExp; - - OverwriteData('source',BESENStringValue(''),[]); - - bv.ValueType:=bvtBOOLEAN; - bv.Bool:=brefGLOBAL in Engine.Flags; - OverwriteData('global',bv,[]); - - bv.Bool:=brefIGNORECASE in Engine.Flags; - OverwriteData('ignoreCase',bv,[]); - - bv.Bool:=brefMULTILINE in Engine.Flags; - OverwriteData('multiline',bv,[]); - - OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); -end; - -destructor TBESENObjectRegExp.Destroy; -begin - if assigned(Engine) then begin - if Engine<>TBESEN(Instance).DefaultRegExp then begin - Engine.DecRef; - end; - Engine:=nil; - end; - inherited Destroy; -end; - -procedure TBESENObjectRegExp.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - TBESEN(Instance).ObjectRegExpPrototype.NativeExec(ThisArgument,Arguments,CountArguments,AResult); - end else begin - raise EBESENTypeError.Create('Not callable'); - end; -end; - -function TBESENObjectRegExp.HasCall:TBESENBoolean; -begin - result:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; -end; - -procedure TBESENObjectRegExp.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectRegExp.Mark; -begin - inherited Mark; -end; - -procedure TBESENObjectRegExp.SetStatic(const Input:TBESENString;const Captures:TBESENRegExpCaptures); -var i:integer; - v:TBESENValue; - pn,lastParen:TBESENString; -begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin - exit; - end; - v:=BESENEmptyValue; - lastParen:=''; - for i:=0 to 9 do begin - case i of - 0:pn:='$&'; - 1:pn:='$1'; - 2:pn:='$2'; - 3:pn:='$3'; - 4:pn:='$4'; - 5:pn:='$5'; - 6:pn:='$6'; - 7:pn:='$7'; - 8:pn:='$8'; - 9:pn:='$9'; - else pn:='$0'; - end; - if (i<length(Captures)) and (Captures[i].e<>brecUNDEFINED) then begin - v:=BESENStringValue(copy(Input,Captures[i].s+1,Captures[i].e-Captures[i].s)); - end else begin - v:=BESENStringValue(''); - end; - if (i>0) and (i<length(Captures)) then begin - lastParen:=v.Str; - end; - OverwriteData(pn,v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]); - if i=0 then begin - OverwriteData('lastMatch',v,[bopaWRITABLE,bopaCONFIGURABLE]); - end; - end; - - v.ValueType:=bvtBOOLEAN; - v.Bool:=brefMULTILINE in Engine.Flags; - OverwriteData('$*',v,[bopaWRITABLE,bopaCONFIGURABLE]); - OverwriteData('multiline',v,[]); - - v:=BESENStringValue(Input); - OverwriteData('$_',v,[bopaWRITABLE,bopaCONFIGURABLE]); - OverwriteData('input',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v:=BESENStringValue(lastParen); - OverwriteData('$+',v,[bopaWRITABLE,bopaCONFIGURABLE]); - OverwriteData('leftParen',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin - v:=BESENStringValue(copy(Input,1,Captures[0].s)); - end else begin - v:=BESENStringValue(''); - end; - OverwriteData('$`',v,[bopaWRITABLE,bopaCONFIGURABLE]); - OverwriteData('leftContext',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin - v:=BESENStringValue(copy(Input,Captures[0].e,(length(Input)-longint(Captures[0].e))+1)); - end else begin - v:=BESENStringValue(''); - end; - OverwriteData('$''',v,[bopaWRITABLE,bopaCONFIGURABLE]); - OverwriteData('rightContext',v,[bopaWRITABLE,bopaCONFIGURABLE]); - - v.ValueType:=bvtBOOLEAN; - v.Bool:=brefGLOBAL in Engine.Flags; - OverwriteData('global',v,[]); - - v.ValueType:=bvtBOOLEAN; - v.Bool:=brefIGNORECASE in Engine.Flags; - OverwriteData('ignoreCase',v,[]); - - if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin - v:=BESENNumberValue(Captures[0].e); - end else begin - v:=BESENNumberValue(0); - end; - OverwriteData('lastIndex',v,[bopaWRITABLE]); - - OverwriteData('source',BESENStringValue(Engine.Source),[]); -end; - -end. diff --git a/3rd/besen/src/BESENObjectRegExpConstructor.pas b/3rd/besen/src/BESENObjectRegExpConstructor.pas deleted file mode 100644 index 793d58410..000000000 --- a/3rd/besen/src/BESENObjectRegExpConstructor.pas +++ /dev/null @@ -1,188 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectRegExpConstructor; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectRegExpConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; - function HasHasInstance:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENObjectRegExp,BESENRegExp,BESENErrors; - -constructor TBESENObjectRegExpConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='RegExp'; -end; - -destructor TBESENObjectRegExpConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectRegExpConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectRegExp; - s,f:TBESENString; - Flags:TBESENRegExpFlags; - v:TBESENValue; - i:integer; -begin - r1:=TBESENObjectRegExp.Create(Instance,TBESEN(Instance).ObjectRegExpPrototype,false); - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - if (CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin - r1.Engine:=TBESENObjectRegExp(Arguments^[0]^.Obj).Engine; - end else begin - if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin - s:=''; - end else begin - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - end; - if CountArguments>1 then begin - f:=TBESEN(Instance).ToStr(Arguments^[1]^); - end else begin - f:=''; - end; - Flags:=[]; - for i:=1 to length(f) do begin - case f[i] of - 'g':begin - if brefGLOBAL in Flags then begin - raise EBESENSyntaxError.Create('Too many global regular expression flags'); - end else begin - Flags:=Flags+[brefGLOBAL]; - end; - end; - 'i':begin - if brefIGNORECASE in Flags then begin - raise EBESENSyntaxError.Create('Too many ignorecase regular expression flags'); - end else begin - Flags:=Flags+[brefIGNORECASE]; - end; - end; - 'm':begin - if brefMULTILINE in Flags then begin - raise EBESENSyntaxError.Create('Too many multiline regular expression flags'); - end else begin - Flags:=Flags+[brefMULTILINE]; - end; - end; - else begin - raise EBESENSyntaxError.Create('Unknown regular expression flag'); - end; - end; - end; - try - r1.Engine:=TBESEN(Instance).RegExpCache.Get(s,Flags); - except - raise EBESENSyntaxError.Create('Invalid regular expression'); - end; - end; - - if assigned(r1.Engine) then begin - r1.Engine.IncRef; - end else begin - raise EBESENError.Create('Fatal error'); - end; - - r1.Engine.DebugDump; - - v.ValueType:=bvtSTRING; - v.Str:=r1.Engine.Source; - r1.OverwriteData('source',v,[]); - - v.ValueType:=bvtBOOLEAN; - v.Bool:=brefGLOBAL in r1.Engine.Flags; - r1.OverwriteData('global',v,[]); - - v.ValueType:=bvtBOOLEAN; - v.Bool:=brefIGNORECASE in r1.Engine.Flags; - r1.OverwriteData('ignoreCase',v,[]); - - v.ValueType:=bvtBOOLEAN; - v.Bool:=brefMULTILINE in r1.Engine.Flags; - r1.OverwriteData('multiline',v,[]); - - v.ValueType:=bvtNUMBER; - v.Num:=0; - r1.OverwriteData('lastIndex',v,[bopaWRITABLE]); - finally - r1.GarbageCollectorUnlock; - end; - AResult:=BESENObjectValue(r1); -end; - -procedure TBESENObjectRegExpConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - Construct(ThisArgument,Arguments,CountArguments,AResult); -end; - -function TBESENObjectRegExpConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectRegExpConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectRegExpConstructor.HasInstance(const AInstance:TBESENValue):TBESENBoolean; -begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - result:=(AInstance.ValueType=bvtOBJECT) and assigned(AInstance.Obj) and (AInstance.Obj is TBESENObjectRegExp); - end else begin - raise EBESENTypeError.Create('Has no instance'); - end; -end; - -function TBESENObjectRegExpConstructor.HasHasInstance:TBESENBoolean; -begin - result:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; -end; - -end. diff --git a/3rd/besen/src/BESENObjectRegExpPrototype.pas b/3rd/besen/src/BESENObjectRegExpPrototype.pas deleted file mode 100644 index 4d191ebd6..000000000 --- a/3rd/besen/src/BESENObjectRegExpPrototype.pas +++ /dev/null @@ -1,228 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectRegExpPrototype; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectRegExp,BESENValue,BESENObjectPropertyDescriptor, - BESENRegExp; - -type TBESENObjectRegExpPrototype=class(TBESENObjectRegExp) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeTest(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeExec(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors,BESENNumberUtils,BESENArrayUtils,BESENObjectArray; - -constructor TBESENObjectRegExpPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='RegExp'; - ObjectName:='RegExp'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('test',NativeTest,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('exec',NativeExec,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectRegExpPrototype.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectRegExpPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:TBESENString; - i:integer; - c:widechar; -begin - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)))and (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExpPrototype)) then begin - ResultValue:=BESENStringValue('RegExp.prototype'); - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExp) then begin - s:='/'; - i:=1; - while i<=length(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source) do begin - c:=TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source[i]; - case c of - '/':begin - s:=s+'\/'; - inc(i); - end; - '\':begin - s:=s+'\\'; - inc(i); - if i<=length(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source) then begin - c:=TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source[i]; - s:=s+c; - inc(i); - end; - end; - else begin - s:=s+c; - inc(i); - end; - end; - end; - s:=s+'/'; - if brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin - s:=s+'g'; - end; - if brefIGNORECASE in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin - s:=s+'i'; - end; - if brefMULTILINE in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin - s:=s+'m'; - end; - ResultValue:=BESENStringValue(s); - end else begin - raise EBESENTypeError.Create('Not a RegExp object'); - end; -end; - -procedure TBESENObjectRegExpPrototype.NativeTest(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v,vo,vs:TBESENValue; - ValuePointers:array[0..0] of PBESENValue; -begin - Get('exec',v); - TBESEN(Instance).ToObjectValue(v,vo); - if (vo.ValueType<>bvtOBJECT) or not (assigned(TBESENObject(vo.Obj)) and TBESENObject(vo.Obj).HasCall) then begin - raise EBESENTypeError.Create('No callable'); - end; - TBESENObject(vo.Obj).GarbageCollectorLock; - try - if CountArguments<1 then begin - ValuePointers[0]:=@BESENUndefinedValue; - end else begin - ValuePointers[0]:=Arguments^[0]; - end; - TBESEN(Instance).ObjectCall(TBESENObject(vo.Obj),ThisArgument,@ValuePointers,1,vs); - finally - TBESENObject(vo.Obj).GarbageCollectorUnlock; - end; - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=TBESEN(Instance).EqualityExpressionCompare(vs,BESENNullValue)<>0; -end; - -procedure TBESENObjectRegExpPrototype.NativeExec(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v,vi:TBESENValue; - i:integer; - s:TBESENString; - Captures:TBESENRegExpCaptures; - o:TBESENObjectArray; -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - if not (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExp) then begin - raise EBESENTypeError.Create('Not a RegExp object'); - end; - if CountArguments<1 then begin - raise EBESENRangeError.Create('Bad argument count'); - end; - - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - - i:=0; - - try - TBESENObject(ThisArgument.Obj).Get('lastIndex',v); - TBESEN(Instance).ToNumberValue(v,vi); - if not (brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags) then begin - v:=BESENNumberValue(0); - end; - if (not BESENIsFinite(v.Num)) or (v.Num<0) or (v.Num>length(s)) then begin - TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(0),true); - ResultValue:=BESENNullValue; - exit; - end; - i:=trunc(vi.Num); - except - end; - -{$ifdef UseAssert} - Assert(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.CountOfCaptures>0); -{$endif} - Captures:=nil; - try - SetLength(Captures,TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.CountOfCaptures); - while not TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Match(s,i,Captures) do begin - inc(i); - if i>length(s) then begin - TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(0),true); - ResultValue:=BESENNullValue; - for i:=0 to length(Captures)-1 do begin - Captures[i].e:=brecUNDEFINED; - end; - TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).SetStatic(s,Captures); - SetLength(Captures,0); - exit; - end; - end; - TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).SetStatic(s,Captures); - if brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin - TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(Captures[0].e),true); - end; - v:=BESENEmptyValue; - o:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(o); - o.GarbageCollectorLock; - try - for i:=0 to length(Captures)-1 do begin - if Captures[i].e=brecUNDEFINED then begin - v:=BESENUndefinedValue; - end else begin - v:=BESENStringValue(copy(s,Captures[i].s+1,Captures[i].e-Captures[i].s)); - end; - o.DefineOwnProperty(BESENArrayIndexToStr(i),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); - end; - o.Len:=length(Captures); - o.DefineOwnProperty('index',BESENDataPropertyDescriptor(BESENNumberValue(Captures[0].s),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); - o.DefineOwnProperty('input',BESENDataPropertyDescriptor(BESENStringValue(s),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); - finally - o.GarbageCollectorUnlock; - end; - ResultValue:=BESENObjectValue(o); - finally - SetLength(Captures,0); - end; -end; - -end. diff --git a/3rd/besen/src/BESENObjectString.pas b/3rd/besen/src/BESENObjectString.pas deleted file mode 100644 index 0969d292a..000000000 --- a/3rd/besen/src/BESENObjectString.pas +++ /dev/null @@ -1,133 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectString; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectString=class(TBESENObject) - public - Value:TBESENString; - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; - function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; - procedure Finalize; override; - procedure Mark; override; - procedure UpdateLength; - end; - -implementation - -uses BESEN,BESENStringUtils,BESENNumberUtils; - -constructor TBESENObjectString.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='String'; - ObjectName:=''; - - Value:=''; - OverwriteData('length',BESENNumberValue(0),[]); -end; - -destructor TBESENObjectString.Destroy; -begin - Value:=''; - inherited Destroy; -end; - -function TBESENObjectString.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; -begin - result:=false; - AResult.ValueType:=bvtUNDEFINED; - if GetProperty(P,Descriptor,Hash) then begin - if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin - if boppVALUE in Descriptor.Presents then begin - BESENCopyValue(AResult,Descriptor.Value); - end; - end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin - if assigned(Base) then begin - GetGetter(Base,AResult,Descriptor); - end else begin - GetGetter(self,AResult,Descriptor); - end; - end; - result:=true; - end; -end; - -function TBESENObjectString.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; -var Index:int64; - v:TBESENValue; -begin - // ES5 errata fix - Descriptor.Value.ValueType:=BESENUndefinedPropertyDescriptor.Value.ValueType; - Descriptor.Getter:=BESENUndefinedPropertyDescriptor.Getter; - Descriptor.Setter:=BESENUndefinedPropertyDescriptor.Setter; - Descriptor.Attributes:=BESENUndefinedPropertyDescriptor.Attributes; - Descriptor.Presents:=BESENUndefinedPropertyDescriptor.Presents; - result:=inherited GetOwnProperty(P,Descriptor,Hash); - if not result then begin - TBESEN(Instance).ToIntegerValue(BESENStringValue(p),v); - if BESENIsFinite(v.Num) then begin - Index:=BESENToInt(v.Num); - if (IntToStr(abs(Index))=P) and ((Index>=0) and (Index<length(Value))) then begin - Descriptor.Value.ValueType:=bvtSTRING; - Descriptor.Value.Str:=copy(Value,Index+1,1); - Descriptor.Getter:=nil; - Descriptor.Setter:=nil; - Descriptor.Attributes:=[bopaENUMERABLE]; - Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; - result:=true; - end; - end; - end; -end; - -procedure TBESENObjectString.Finalize; -begin - inherited Finalize; -end; - -procedure TBESENObjectString.Mark; -begin - inherited Mark; -end; - -procedure TBESENObjectString.UpdateLength; -begin - OverwriteData('length',BESENNumberValue(length(Value)),[]); -end; - -end. diff --git a/3rd/besen/src/BESENObjectStringConstructor.pas b/3rd/besen/src/BESENObjectStringConstructor.pas deleted file mode 100644 index 263aa140a..000000000 --- a/3rd/besen/src/BESENObjectStringConstructor.pas +++ /dev/null @@ -1,119 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectStringConstructor; -{$i BESEN.inc} - -interface - -uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectStringConstructor=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasConstruct:TBESENBoolean; override; - function HasCall:TBESENBoolean; override; - procedure NativeFromCharCode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENObjectString; - -constructor TBESENObjectStringConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='String'; - - OverwriteData('length',BESENNumberValue(1),[]); - - RegisterNativeFunction('fromCharCode',NativeFromCharCode,1,[bopaWRITABLE,bopaCONFIGURABLE],false); -end; - -destructor TBESENObjectStringConstructor.Destroy; -begin - inherited Destroy; -end; - -procedure TBESENObjectStringConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -var r1:TBESENObjectString; -begin - r1:=TBESENObjectString.Create(Instance,TBESEN(Instance).ObjectStringPrototype,false); - TBESEN(Instance).GarbageCollector.Add(r1); - r1.GarbageCollectorLock; - try - if CountArguments>0 then begin - r1.Value:=TBESEN(Instance).ToStr(Arguments^[0]^); - end else begin - r1.Value:=''; - end; - r1.UpdateLength; - finally - r1.GarbageCollectorUnlock; - end; - AResult.ValueType:=bvtOBJECT; - AResult.Obj:=r1; -end; - -procedure TBESENObjectStringConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - if CountArguments<1 then begin - AResult:=BESENStringValue(''); - end else begin - TBESEN(Instance).ToStringValue(Arguments^[0]^,AResult); - end; -end; - -function TBESENObjectStringConstructor.HasConstruct:TBESENBoolean; -begin - result:=true; -end; - -function TBESENObjectStringConstructor.HasCall:TBESENBoolean; -begin - result:=true; -end; - -procedure TBESENObjectStringConstructor.NativeFromCharCode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:TBESENString; - i:integer; -begin - s:=''; - for i:=0 to CountArguments-1 do begin - s:=s+widechar(word(TBESEN(Instance).ToUInt16(Arguments^[i]^))); - end; - ResultValue:=BESENStringValue(s); -end; - -end. diff --git a/3rd/besen/src/BESENObjectStringPrototype.pas b/3rd/besen/src/BESENObjectStringPrototype.pas deleted file mode 100644 index d22643c04..000000000 --- a/3rd/besen/src/BESENObjectStringPrototype.pas +++ /dev/null @@ -1,1108 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectStringPrototype; -{$i BESEN.inc} - -interface - -uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectString,BESENValue,BESENObjectPropertyDescriptor, - BESENObjectBoolean; - -type TBESENObjectStringPrototype=class(TBESENObjectString) - private - function RegExpArg(Arguments:PPBESENValues;CountArguments:integer):TBESENObject; - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCharAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeCharCodeAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLocaleCompare(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeMatch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReplace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSearch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSplit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSubstring(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeToLocaleUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeTrim(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSubstr(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeAnchor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeBig(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeBlink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeBold(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeFontColor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeFontSize(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeItalics(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSmall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeStrike(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSub(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSup(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - -implementation - -uses BESEN,BESENErrors,BESENObjectRegExp,BESENNumberUtils,BESENRegExp,BESENStringUtils, - BESENObjectArray; - -constructor TBESENObjectStringPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='String'; - ObjectName:='Number'; - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - OverwriteData('name',BESENStringValue(ObjectName),[]); - end; - - OverwriteData('length',BESENNumberValue(0),[]); - - RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - - RegisterNativeFunction('charAt',NativeCharAt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('charCodeAt',NativeCharCodeAt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('concat',NativeConcat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('indexOf',NativeIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('lastIndexOf',NativeLastIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('localeCompare',NativeLocaleCompare,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('match',NativeMatch,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('replace',NativeReplace,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('search',NativeSearch,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('slice',NativeSlice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('split',NativeSplit,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('substring',NativeSubString,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLowerCase',NativeToLowerCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleLowerCase',NativeToLocaleLowerCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toUpperCase',NativeToUpperCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('toLocaleUpperCase',NativeToLocaleUpperCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('trim',NativeTrim,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - - RegisterNativeFunction('substr',NativeSubStr,2,[bopaWRITABLE,bopaCONFIGURABLE],false); - - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - RegisterNativeFunction('anchor',NativeAnchor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('big',NativeBig,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('blink',NativeBlink,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('bold',NativeBold,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('fixed',NativeFixed,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('fontcolor',NativeFontColor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('fontsize',NativeFontSize,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('italics',NativeItalics,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('link',NativeLink,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('small',NativeSmall,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('strike',NativeStrike,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('sub',NativeSub,0,[bopaWRITABLE,bopaCONFIGURABLE],false); - RegisterNativeFunction('sup',NativeSup,1,[bopaWRITABLE,bopaCONFIGURABLE],false); - end; -end; - -destructor TBESENObjectStringPrototype.Destroy; -begin - inherited Destroy; -end; - -function TBESENObjectStringPrototype.RegExpArg(Arguments:PPBESENValues;CountArguments:integer):TBESENObject; -var v:TBESENValue; -begin - v:=BESENEmptyValue; - if CountArguments<0 then begin - TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),nil,0,v); - if v.ValueType=bvtOBJECT then begin - result:=TBESENObject(v.Obj); - end else begin - result:=nil; - end; - end else if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin - result:=TBESENObject(Arguments^[0]^.Obj); - end else begin - TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),Arguments,1,v); - if v.ValueType=bvtOBJECT then begin - result:=TBESENObject(v.Obj); - end else begin - result:=nil; - end; - end; -{$ifdef UseAssert} - Assert(assigned(result)); -{$endif} -end; - -procedure TBESENObjectStringPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if ThisArgument.ValueType=bvtSTRING then begin - BESENCopyValue(ResultValue,ThisArgument); - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectString) then begin - ResultValue:=BESENStringValue(TBESENObjectString(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a string object'); - end; -end; - -procedure TBESENObjectStringPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if ThisArgument.ValueType=bvtSTRING then begin - BESENCopyValue(ResultValue,ThisArgument); - end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectString) then begin - ResultValue:=BESENStringValue(TBESENObjectString(TBESENObject(ThisArgument.Obj)).Value); - end else begin - raise EBESENTypeError.Create('Not a string object'); - end; -end; - -procedure TBESENObjectStringPrototype.NativeCharAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENValue; - i:integer; - s:TBESENString; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - v:=BESENEmptyValue; - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - i:=-1; - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if BESENIsFinite(v.Num) then begin - i:=trunc(v.Num); - end; - end else begin - i:=0; - end; - if (i>=0) and (i<length(s)) then begin - ResultValue:=BESENStringValue(copy(s,i+1,1)); - end else begin - ResultValue:=BESENStringValue(''); - end; -end; - -procedure TBESENObjectStringPrototype.NativeCharCodeAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENValue; - i:integer; - s:TBESENString; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin - i:=-1; - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if BESENIsFinite(v.Num) then begin - i:=trunc(v.Num); - end; - end else begin - i:=0; - end; - if (i>=0) and (i<length(s)) then begin - ResultValue:=BESENNumberValue(word(widechar(s[i+1]))); - end else begin - ResultValue:=BESENNumberValue(0); - move(BESENDoubleNaN,ResultValue.Num,sizeof(TBESENNumber)); - end; -end; - -procedure TBESENObjectStringPrototype.NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:TBESENString; - i:integer; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - for i:=0 to CountArguments-1 do begin - s:=s+TBESEN(Instance).ToStr(Arguments^[i]^); - end; - ResultValue:=BESENStringValue(s); -end; - -procedure TBESENObjectStringPrototype.NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENValue; - i,j,k,l,ls,p,fp,fl:integer; - s,ss:TBESENString; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - if CountArguments<1 then begin - ss:=''; - end else begin - ss:=TBESEN(Instance).ToStr(Arguments^[0]^); - end; - p:=0; - if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin - TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); - p:=trunc(v.Num); - end; - if p<0 then begin - p:=0; - end else if p>=length(s) then begin - p:=length(s)-1; - end; - inc(p); - ls:=length(ss); - l:=(length(s)-ls)+1; - fp:=0; - for i:=p to l do begin - fl:=0; - for j:=1 to ls do begin - k:=i+j-1; - if ((k<1) or (k>length(s))) or (s[k]<>ss[j]) then begin - break; - end else begin - inc(fl); - end; - end; - if fl=ls then begin - fp:=i; - break; - end; - end; - ResultValue:=BESENNumberValue(fp-1); -end; - -procedure TBESENObjectStringPrototype.NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v,vi:TBESENValue; - i,j,k,l,ls,p,fp,fl:integer; - s,ss:TBESENString; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - if CountArguments<1 then begin - ss:=''; - end else begin - ss:=TBESEN(Instance).ToStr(Arguments^[0]^); - end; - vi:=BESENEmptyValue; - if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin - TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); - end else begin - v:=BESENNumberValue(0); - move(BESENDoubleNaN,v.Num,sizeof(TBESENNumber)); - end; - if BESENIsNaN(v.Num) then begin - vi:=BESENNumberValue(0); - move(BESENDoubleInfPos,vi.Num,sizeof(TBESENNumber)); - end else begin - TBESEN(Instance).ToIntegerValue(v,vi); - end; - l:=trunc(min(max(vi.Num,0),length(s))); - ls:=length(ss); - if l<ls then begin - ResultValue:=BESENNumberValue(-1); - exit; - end; - p:=length(s)-ls; - if p<l then begin - l:=p; - end; - fp:=-1; - for i:=l downto 0 do begin - fl:=0; - for j:=1 to ls do begin - k:=i+j; - if ((k<1) or (k>length(s))) or (s[k]<>ss[j]) then begin - break; - end else begin - inc(fl); - end; - end; - if fl=ls then begin - fp:=i; - break; - end; - end; - ResultValue:=BESENNumberValue(fp); -end; - -procedure TBESENObjectStringPrototype.NativeLocaleCompare(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s,ss:TBESENString; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - if CountArguments<1 then begin - ss:='undefined'; - end else begin - ss:=TBESEN(Instance).ToStr(Arguments^[0]^); - end; - if s<ss then begin - ResultValue:=BESENNumberValue(-1); - end else if s>ss then begin - ResultValue:=BESENNumberValue(1); - end else begin - ResultValue:=BESENNumberValue(0); - end; -end; - -procedure TBESENObjectStringPrototype.NativeMatch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var RegExp:TBESENObjectRegExp; - v,vr,vs:TBESENValue; - Exec:TBESENObject; - Global:boolean; - s:TBESENString; - a:TBESENObjectArray; - n,Matches:integer; - ValuePointers:array[0..0] of PBESENValue; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - - v:=BESENEmptyValue; - - RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); - RegExp.Get('exec',v); -{$ifdef UseAssert} - Assert((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall); -{$endif} - Exec:=TBESENObject(v.Obj); - - RegExp.Get('global',v); -{$ifdef UseAssert} - Assert(v.ValueType=bvtBOOLEAN); -{$endif} - Global:=v.Bool; - if Global then begin - v:=BESENEmptyValue; - vr:=BESENEmptyValue; - - Matches:=0; - - RegExp.OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); - - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - try - n:=0; - while true do begin - vs.ValueType:=bvtSTRING; - vs.Str:=s; - ValuePointers[0]:=@vs; - TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,vr); - if vr.ValueType=bvtNULL then begin - break; - end; - - {$ifdef UseAssert} - Assert((vr.ValueType=bvtOBJECT) and assigned(vr.Obj) and (vr.Obj is TBESENObjectArray)); - {$endif} - TBESENObject(vr.Obj).Get('0',v); - {$ifdef UseAssert} - Assert(v.ValueType=bvtSTRING); - {$endif} - - a.OverwriteData(inttostr(n),v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]); - inc(Matches); - - if length(v.Str)=0 then begin - RegExp.Get('lastIndex',v); - {$ifdef UseAssert} - Assert(v.ValueType=bvtNUMBER); - {$endif} - v.Num:=v.Num+1; - RegExp.OverwriteData('lastIndex',v,[bopaWRITABLE]); - end; - inc(n); - end; - finally - a.GarbageCollectorUnlock; - end; - if Matches=0 then begin - ResultValue:=BESENNullValue; - end else begin - ResultValue:=BESENObjectValue(a); - end; - end else begin - vs.ValueType:=bvtSTRING; - vs.Str:=s; - ValuePointers[0]:=@vs; - TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,ResultValue); - end; -end; - -procedure TBESENObjectStringPrototype.NativeReplace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure Helper(var PrevIndexP:longword;a:TBESENObject;var OutStr:TBESENString;const Source:TBESENString;var ReplaceValue:TBESENValue;CountCaptures:integer); - var v,vr:TBESENValue; - n:integer; - Index,i,j,k:longword; - ms,Replace:TBESENString; - Values:TBESENValues; - pValues:TBESENValuePointers; - begin - v:=BESENEmptyValue; - - a.Get('index',v); - Index:=TBESEN(Instance).ToUInt32(v); - - a.Get('0',v); -{$ifdef UseAssert} - Assert(v.ValueType=bvtSTRING); -{$endif} - ms:=TBESEN(Instance).ToStr(v); - - i:=PrevIndexP; - if i<Index then begin - OutStr:=OutStr+copy(Source,i+1,Index-i); - end; - PrevIndexP:=Index+longword(length(ms)); - - if ReplaceValue.ValueType=bvtOBJECT then begin - Values:=nil; - pValues:=nil; - try - SetLength(Values,CountCaptures+2); - SetLength(pValues,CountCaptures+2); - for n:=0 to length(Values)-1 do begin - Values[n]:=BESENEmptyValue; - end; - for n:=0 to CountCaptures-1 do begin - a.Get(inttostr(n),Values[n]); - end; - Values[CountCaptures]:=BESENNumberValue(Index); - Values[CountCaptures+1]:=BESENStringValue(Source); - for n:=0 to length(Values)-1 do begin - pValues[n]:=@Values[n]; - end; - TBESEN(Instance).ObjectCall(TBESENObject(ReplaceValue.Obj),BESENObjectValueEx(TBESENObject(ReplaceValue.Obj)),@pValues[0],length(pValues),vr); - OutStr:=OutStr+TBESEN(Instance).ToStr(vr); - finally - SetLength(Values,0); - SetLength(pValues,0); - end; - exit; - end; - - Replace:=TBESEN(Instance).ToStr(ReplaceValue); - - i:=0; - while i<longword(length(Replace)) do begin - if (Replace[i+1]='$') and ((i+1)<longword(length(Replace))) then begin - inc(i); - case Replace[i+1] of - '$':begin - OutStr:=OutStr+'$'; - inc(i); - continue; - end; - '`':begin - k:=0; - while k<Index do begin - OutStr:=OutStr+Source[k+1]; - inc(k); - end; - inc(i); - continue; - end; - '''':begin - k:=PrevIndexP; - while k<longword(length(Source)) do begin - OutStr:=OutStr+Source[k+1]; - inc(k); - end; - inc(i); - continue; - end; - '&':begin - OutStr:=OutStr+ms; - inc(i); - continue; - end; - end; - j:=i; - n:=0; - while (j<longword(length(Replace))) and ((word(widechar(Replace[j+1]))>=ord('0')) and (word(widechar(Replace[j+1]))<=ord('9'))) do begin - n:=(n*10)+(word(widechar(Replace[j+1]))-ord('0')); - inc(j); - end; - if i=j then begin - OutStr:=OutStr+'$'; - continue; - end; - a.Get(inttostr(n),v); - if v.ValueType<>bvtUNDEFINED then begin -{$ifdef UseAssert} - Assert(v.ValueType=bvtSTRING); -{$endif} - OutStr:=OutStr+v.Str; - end; - i:=j; - end else begin - OutStr:=OutStr+Replace[i+1]; - inc(i); - end; - end; - end; -var RegExp:TBESENObjectRegExp; - CountCaptures:integer; - ReplaceValue,v,v2,vr,vs:TBESENValue; - Exec:TBESENObject; - Global:boolean; - s,OutStr:TBESENString; - PrevIndex:longword; - ValuePointers:array[0..0] of PBESENValue; - HasOutputString:boolean; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - - RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); - CountCaptures:=RegExp.Engine.CountOfCaptures; - ReplaceValue:=BESENEmptyValue; - v:=BESENEmptyValue; - v2:=BESENEmptyValue; - vr:=BESENEmptyValue; - OutStr:=''; - - PrevIndex:=0; - - if CountArguments<2 then begin - ReplaceValue.ValueType:=bvtSTRING; - ReplaceValue.Str:=''; - end else if (Arguments^[1]^.ValueType=bvtOBJECT) and assigned(Arguments^[1]^.Obj) and TBESENObject(Arguments^[1]^.Obj).HasCall then begin - BESENCopyValue(ReplaceValue,Arguments^[1]^); - end else begin - TBESEN(Instance).ToStringValue(Arguments^[1]^,ReplaceValue); - end; - - RegExp.Get('exec',v); -{$ifdef UseAssert} - Assert((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall); -{$endif} - Exec:=TBESENObject(v.Obj); - - RegExp.Get('global',v); -{$ifdef UseAssert} - Assert(v.ValueType=bvtBOOLEAN); -{$endif} - Global:=v.Bool; - - HasOutputString:=false; - - if Global then begin - RegExp.OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); - while true do begin - vs.ValueType:=bvtSTRING; - vs.Str:=s; - ValuePointers[0]:=@vs; - TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,vr); - if vr.ValueType=bvtNULL then begin - break; - end; -{$ifdef UseAssert} - Assert((vr.ValueType=bvtOBJECT) and assigned(TBESENObject(vr.Obj)) and (TBESENObject(vr.Obj) is TBESENObjectArray)); -{$endif} - TBESENObject(vr.Obj).Get('0',v); -{$ifdef UseAssert} - Assert(v.ValueType=bvtSTRING); -{$endif} - if length(v.Str)<>0 then begin - Helper(PrevIndex,TBESENObject(vr.Obj),OutStr,s,ReplaceValue,CountCaptures); - HasOutputString:=true; - end else begin - RegExp.Get('lastIndex',v); -{$ifdef UseAssert} - Assert(v.ValueType=bvtNUMBER); -{$endif} - v.Num:=v.Num+1; - RegExp.OverwriteData('lastIndex',v,[bopaWRITABLE]); - end; - end; - end else begin - v.ValueType:=bvtSTRING; - v.Str:=s; - ValuePointers[0]:=@v; - TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,v2); - if v2.ValueType<>bvtNULL then begin -{$ifdef UseAssert} - Assert((v2.ValueType=bvtOBJECT) and assigned(v2.Obj) and (v2.Obj is TBESENObjectArray)); -{$endif} - Helper(PrevIndex,TBESENObject(v2.Obj),OutStr,s,ReplaceValue,CountCaptures); - HasOutputString:=true; - end; - end; - - if HasOutputString then begin - ResultValue:=BESENStringValue(OutStr+copy(s,PrevIndex+1,(longword(length(s))-PrevIndex)+1)); - end else begin - ResultValue:=BESENStringValue(s); - end; -end; - -procedure TBESENObjectStringPrototype.NativeSearch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var RegExp:TBESENObjectRegExp; - s:TBESENSTRING; - i:integer; - Captures:TBESENRegExpCaptures; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); - Captures:=nil; - try - ResultValue:=BESENNumberValue(-1); - for i:=0 to length(s)-1 do begin - if RegExp.Engine.Match(s,i,Captures) then begin - ResultValue:=BESENNumberValue(Captures[0].s); - break; - end; - end; - finally - SetLength(Captures,0); - end; -end; - -procedure TBESENObjectStringPrototype.NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:TBESENString; - len,intStart,intEnd,sFrom,sTo,span:integer; -begin - BESENCheckObjectCoercible(ThisArgument); - - s:=TBESEN(Instance).ToStr(ThisArgument); - - len:=length(s); - - if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin - intStart:=0; - end else begin - intStart:=TBESEN(Instance).ToInt(Arguments^[0]^); - end; - - if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin - intEnd:=len; - end else begin - intEnd:=TBESEN(Instance).ToInt(Arguments^[1]^); - end; - - if intStart<0 then begin - sFrom:=max(len+intStart,0); - end else begin - sFrom:=min(intStart,len); - end; - - if intEnd<0 then begin - sTo:=max(len+intEnd,0); - end else begin - STo:=min(intEnd,len); - end; - - span:=max(sTo-sFrom,0); - - if span=0 then begin - ResultValue:=BESENStringValue(''); - end else begin - ResultValue:=BESENStringValue(copy(s,sFrom+1,span)); - end; -end; - -procedure TBESENObjectStringPrototype.NativeSplit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - function SplitMatch(var r:TBESENValue;var s:TBESENString;q:integer;var Captures:TBESENRegExpCaptures):boolean; - var rl,sl,i:integer; - begin - if r.ValueType<>bvtOBJECT then begin - rl:=length(r.Str); - sl:=length(s); - if (q+rl)>sl then begin - result:=false; - end else begin - for i:=0 to rl-1 do begin - if s[q+i+1]<>r.Str[i+1] then begin - result:=false; - exit; - end; - end; - Captures[0].s:=q; - Captures[0].e:=q+rl; - result:=true; - end; - end else begin - result:=TBESENObjectRegExp(R.Obj).Engine.Match(s,q,Captures); - end; - end; -var v,av,r:TBESENValue; - s,rs:TBESENString; - a:TBESENObjectArray; - lim:TBESENUINT32; - p,sl,CountCaptures,e,q,i:integer; - Captures:TBESENRegExpCaptures; - n,Done:boolean; - ValuePointers:array[0..0] of PBESENValue; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - - v:=BESENEmptyValue; - - a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); - TBESEN(Instance).GarbageCollector.Add(a); - a.GarbageCollectorLock; - try - ResultValue:=BESENObjectValue(a); - - if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin - lim:=$ffffffff; - end else begin - lim:=TBESEN(Instance).ToUInt32(Arguments^[1]^); - end; - - Done:=false; - sl:=length(s); - if (sl=0) and ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) then begin - Done:=true; - end; - - if not Done then begin - v:=BESENEmptyValue; - av:=BESENEmptyValue; - r:=BESENEmptyValue; - Captures:=nil; - try - p:=0; - if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin - r:=BESENStringValue('undefined'); - CountCaptures:=1; - end else if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin - BESENCopyValue(r,Arguments^[0]^); - CountCaptures:=TBESENObjectRegExp(Arguments^[0]^.Obj).Engine.CountOfCaptures; - end else begin - rs:=TBESEN(Instance).ToStr(Arguments^[0]^); - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (rs=' ') then begin - av:=BESENStringValue('\s+'); - ValuePointers[0]:=@av; - TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),@ValuePointers,1,r); - while (p<sl) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[p+1]))) do begin - inc(p); - end; - end else begin - r:=BESENStringValue(rs); - end; - CountCaptures:=1; - end; - if CountCaptures<>0 then begin - SetLength(Captures,CountCaptures); - end; - if lim>0 then begin - if (CountArguments<1) or ((Arguments^[0]^.ValueType=bvtUNDEFINED) and ((TBESEN(Instance).Compatibility and COMPAT_JS)=0)) then begin - v:=BESENStringValue(s); - a.Push(v); - end else if length(s)=0 then begin - if not SplitMatch(r,s,0,Captures) then begin - v:=BESENStringValue(s); - a.Push(v); - end; - end else begin - q:=p; - while true do begin - if q=sl then begin - v:=BESENStringValue(copy(s,p+1,sl-p)); - a.Push(v); - break; - end else begin - if not SplitMatch(r,s,q,Captures) then begin - inc(q); - continue; - end else begin - e:=Captures[0].e; - if e=p then begin - inc(q); - continue; - end else begin - v:=BESENStringValue(copy(s,p+1,q-p)); - a.Push(v); - if A.Len=lim then begin - break; - end else begin - p:=e; - i:=0; - n:=false; - while true do begin - if i=(CountCaptures-1) then begin - q:=p; - n:=false; - break; - end else begin - inc(i); - if Captures[i].e=brecUNDEFINED then begin - v:=BESENUndefinedValue; - end else begin - v:=BESENStringValue(copy(s,Captures[i].s+1,Captures[i].e-Captures[i].s)); - end; - a.Push(v); - if A.Len=lim then begin - n:=true; - break; - end; - end; - end; - if n then begin - break; - end else begin - continue; - end; - end; - end; - end; - end; - end; - end; - end; - finally - SetLength(Captures,0); - end; - end; - finally - a.GarbageCollectorUnlock; - end; -end; - -procedure TBESENObjectStringPrototype.NativeSubstring(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENValue; - s:TBESENString; - a,b,ss,se,sl:integer; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - - if CountArguments<1 then begin - a:=0; - end else begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - if BESENIsNaN(v.Num) then begin - a:=0; - end else begin - a:=trunc(min(max(v.Num,0),length(s))); - end; - end; - - if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin - b:=length(s); - end else begin - TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); - if BESENIsNaN(v.Num) then begin - b:=0; - end else begin - b:=trunc(min(max(v.Num,0),length(s))); - end; - end; - - ss:=min(a,b); - se:=max(a,b); - sl:=max(se-ss,0); - - if sl=0 then begin - ResultValue:=BESENStringValue(''); - end else begin - ResultValue:=BESENStringValue(copy(s,ss+1,sl)); - end; -end; - -procedure TBESENObjectStringPrototype.NativeToLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - BESENCheckObjectCoercible(ThisArgument); - ResultValue:=BESENStringValue(BESENLowercase(TBESEN(Instance).ToStr(ThisArgument))); -end; - -procedure TBESENObjectStringPrototype.NativeToLocaleLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - BESENCheckObjectCoercible(ThisArgument); - ResultValue:=BESENStringValue(BESENLowercase(TBESEN(Instance).ToStr(ThisArgument))); -end; - -procedure TBESENObjectStringPrototype.NativeToUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - BESENCheckObjectCoercible(ThisArgument); - ResultValue:=BESENStringValue(BESENUppercase(TBESEN(Instance).ToStr(ThisArgument))); -end; - -procedure TBESENObjectStringPrototype.NativeToLocaleUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - BESENCheckObjectCoercible(ThisArgument); - ResultValue:=BESENStringValue(BESENUppercase(TBESEN(Instance).ToStr(ThisArgument))); -end; - -procedure TBESENObjectStringPrototype.NativeTrim(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:TBESENString; - StartPosition,LengthCount:integer; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - LengthCount:=length(s); - if LengthCount>0 then begin - while (LengthCount>0) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[LengthCount]))) do begin - dec(LengthCount); - end; - StartPosition:=1; - while (StartPosition<=LengthCount) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[StartPosition]))) do begin - inc(StartPosition); - end; - s:=copy(s,StartPosition,LengthCount-StartPosition+1); - end; - ResultValue:=BESENStringValue(s); -end; - -procedure TBESENObjectStringPrototype.NativeSubstr(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var v:TBESENValue; - s:TBESENString; - ss,sl:integer; -begin - BESENCheckObjectCoercible(ThisArgument); - s:=TBESEN(Instance).ToStr(ThisArgument); - - if CountArguments<1 then begin - v:=BESENNumberValue(0); - end else begin - TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); - end; - if BESENIsNegative(v.Num) then begin - ss:=trunc(max(v.Num+length(s),0)); - end else begin - ss:=trunc(min(v.Num,length(s))); - end; - - if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin - sl:=length(s)-ss; - end else begin - sl:=min(TBESEN(Instance).ToInt(Arguments^[1]^),length(s)-ss); - end; - - if sl=0 then begin - ResultValue:=BESENStringValue(''); - end else begin - ResultValue:=BESENStringValue(copy(s,ss+1,sl)); - end; -end; - -procedure TBESENObjectStringPrototype.NativeAnchor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeBig(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeBlink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeBold(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeFontColor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeFontSize(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeItalics(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeLink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeSmall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeStrike(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeSub(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -procedure TBESENObjectStringPrototype.NativeSup(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin - raise EBESENTypeError.Create('Null this object'); - end; - ResultValue:=BESENStringValue(''); -end; - -end. diff --git a/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas b/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas deleted file mode 100644 index da3648759..000000000 --- a/3rd/besen/src/BESENObjectThrowTypeErrorFunction.pas +++ /dev/null @@ -1,74 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENObjectThrowTypeErrorFunction; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; - -type TBESENObjectThrowTypeErrorFunction=class(TBESENObjectFunction) - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; - destructor Destroy; override; - procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; - function HasCall:TBESENBoolean; override; - end; - -implementation - -uses BESEN,BESENErrors; - -constructor TBESENObjectThrowTypeErrorFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - ObjectClassName:='Function'; - ObjectName:='ThrowTypeError'; -end; - -destructor TBESENObjectThrowTypeErrorFunction.Destroy; -begin - inherited Destroy; -end; - -{$warnings off} -procedure TBESENObjectThrowTypeErrorFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); -begin - raise EBESENTypeError.Create('ThrowTypeError'); -end; -{$warnings on} - -function TBESENObjectThrowTypeErrorFunction.HasCall:TBESENBoolean; -begin - result:=true; -end; - -end. diff --git a/3rd/besen/src/BESENOpcodes.pas b/3rd/besen/src/BESENOpcodes.pas deleted file mode 100644 index e3e2a4e16..000000000 --- a/3rd/besen/src/BESENOpcodes.pas +++ /dev/null @@ -1,365 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENOpcodes; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -const bopSTOP=0; - bopNEW=1; - bopCALL=2; - bopEND=3; - bopVREF=4; - bopLREF=5; - bopNOP=6; - bopCOPY=7; - bopNEQ=8; - bopNSEQ=9; - bopAREF=10; - bopTHROW=11; - bopSETC=12; - bopGETC=13; - bopTHIS=14; - bopOBJECT=15; - bopARRAY=16; - bopREGEXP=17; - bopREF=18; - bopGETVALUE=19; - bopLOOKUP=20; - bopPUTVALUE=21; - bopDELETE=22; - bopTYPEOF=23; - bopTOOBJECT=24; - bopTONUMBER=25; - bopTOBOOLEAN=26; - bopTOSTRING=27; - bopTOPRIMITIVE=28; - bopNEG=29; - bopINV=30; - bopNOT=31; - bopMUL=32; - bopDIV=33; - bopMOD=34; - bopADD=35; - bopADDNUM=36; - bopSUB=37; - bopSHL=38; - bopSHR=39; - bopUSHR=40; - bopLT=41; - bopGT=42; - bopLE=43; - bopGE=44; - bopINSTANCEOF=45; - bopIN=46; - bopEQ=47; - bopSEQ=48; - bopBAND=49; - bopBXOR=50; - bopBOR=51; - bopSENUM=52; - bopSWITH=53; - bopSCATCH=54; - bopENDF=55; - bopJMP=56; - bopJZ=57; - bopJNZ=58; - bopJNULL=59; - bopLOOPENUM=60; - bopSTRYC=61; - bopSTRYF=62; - bopLITERAL=63; - bopLITERALUNDEF=64; - bopLITERALNULL=65; - bopLITERALBOOL=66; - bopLITERALNUM=67; - bopLITERALSTR=68; - bopLITERALOBJ=69; - bopFUNC=70; - bopLINE=71; - bopGC=72; - bopSTRICT=73; - bopSTRICTCHECKREF=74; - bopDEBUGGER=75; - bopCHECKOBJECTCOERCIBLE=76; - bopPUTOBJVALUE=77; - bopPUTOBJGET=78; - bopPUTOBJSET=79; - bopINC=80; - bopDEC=81; - bopCOPYBOOL=82; - bopCOPYNUM=83; - bopCOPYSTR=84; - bopCOPYOBJ=85; - bopCOPYREF=86; - bopCOPYLOCAL=87; - bopGETVALUEREF=88; - bopPUTVALUEREF=89; - bopGETVALUELOCAL=90; - bopPUTVALUELOCAL=91; - bopGETVALUELOCALFAST=92; - bopPUTVALUELOCALFAST=93; - bopGETVALUELOCALBOOL=94; - bopPUTVALUELOCALBOOL=95; - bopGETVALUELOCALNUM=96; - bopPUTVALUELOCALNUM=97; - bopGETVALUELOCALSTR=98; - bopPUTVALUELOCALSTR=99; - bopGETVALUELOCALOBJ=100; - bopPUTVALUELOCALOBJ=101; - bopGETVALUELOCALINDEX=102; - bopPUTVALUELOCALINDEX=103; - bopGETVALUELOCALINDEXBOOL=104; - bopPUTVALUELOCALINDEXBOOL=105; - bopGETVALUELOCALINDEXNUM=106; - bopPUTVALUELOCALINDEXNUM=107; - bopGETVALUELOCALINDEXSTR=108; - bopPUTVALUELOCALINDEXSTR=109; - bopGETVALUELOCALINDEXOBJ=110; - bopPUTVALUELOCALINDEXOBJ=111; - bopLOOPINITCOUNT=112; - bopLOOPADDCOUNT=113; - bopTRACE=114; - bopLTBOOL=115; - bopGTBOOL=116; - bopLEBOOL=117; - bopGEBOOL=118; - bopEQBOOL=119; - bopNEQBOOL=120; - bopLTNUM=121; - bopGTNUM=122; - bopLENUM=123; - bopGENUM=124; - bopEQNUM=125; - bopNEQNUM=126; - bopLTSTR=127; - bopGTSTR=128; - bopLESTR=129; - bopGESTR=130; - bopEQSTR=131; - bopNEQSTR=132; - bopSHLBOOl=133; - bopSHRBOOL=134; - bopBANDBOOL=135; - bopBXORBOOL=136; - bopBORBOOL=137; - bopSHLNUM=138; - bopSHRNUM=139; - bopUSHRNUM=140; - bopBANDNUM=141; - bopBXORNUM=142; - bopBORNUM=143; - bopSETCUNDEF=144; - bopSETCNULL=145; - bopSETCBOOL=146; - bopSETCNUM=147; - bopSETCSTR=148; - bopSETCOBJ=149; - bopTRACENEW=150; - bopTRACECALL=151; - bopLTNUMCONST=152; - bopGTNUMCONST=153; - bopLENUMCONST=154; - bopGENUMCONST=155; - bopEQNUMCONST=156; - bopNEQNUMCONST=157; - bopJZERO=158; - bopJNZERO=159; - - bopFIRST=0; - bopLAST=159; - - OpcodeNames:array[bopFIRST..bopLAST] of TBESENString=('STOP', - 'NEW', - 'CALL', - 'END', - 'VREF', - 'LREF', - 'NOP', - 'COPY', - 'NEQ', - 'NSEQ', - 'AREF', - 'THROW', - 'SETC', - 'GETC', - 'THIS', - 'OBJECT', - 'ARRAY', - 'REGEXP', - 'REF', - 'GETVALUE', - 'LOOKUP', - 'PUTVALUE', - 'DELETE', - 'TYPEOF', - 'TOOBJECT', - 'TONUMBER', - 'TOBOOLEAN', - 'TOSTRING', - 'TOPRIMITIVE', - 'NEG', - 'INV', - 'NOT', - 'MUL', - 'DIV', - 'MOD', - 'ADD', - 'ADDNUM', - 'SUB', - 'SHL', - 'SHR', - 'USHR', - 'LT', - 'GT', - 'LE', - 'GE', - 'INSTANCEOF', - 'IN', - 'EQ', - 'SEQ', - 'BAND', - 'BXOR', - 'BOR', - 'SENUM', - 'SWITH', - 'SCATCH', - 'ENDF', - 'JMP', - 'JZ', - 'JNZ', - 'JNULL', - 'LOOPENUM', - 'STRYC', - 'STRYF', - 'LITERAL', - 'LITERALUNDEF', - 'LITERALNULL', - 'LITERALBOOL', - 'LITERALNUM', - 'LITERALSTR', - 'LITERALOBJ', - 'FUNC', - 'LINE', - 'GC', - 'STRICT', - 'STRICTCHECKREF', - 'DEBUGGER', - 'CHECKOBJECTCOERCIBLE', - 'PUTOBJVALUE', - 'PUTOBJGET', - 'PUTOBJSET', - 'INC', - 'DEC', - 'COPYBOOL', - 'COPYNUM', - 'COPYSTR', - 'COPYOBJ', - 'COPYREF', - 'COPYLOCAL', - 'GETVALUEREF', - 'PUTVALUEREF', - 'GETVALUELOCAL', - 'PUTVALUELOCAL', - 'GETVALUELOCALFAST', - 'PUTVALUELOCALFAST', - 'GETVALUELOCALBOOL', - 'PUTVALUELOCALBOOL', - 'GETVALUELOCALNUM', - 'PUTVALUELOCALNUM', - 'GETVALUELOCALSTR', - 'PUTVALUELOCALSTR', - 'GETVALUELOCALOBJ', - 'PUTVALUELOCALOBJ', - 'GETVALUELOCALINDEX', - 'PUTVALUELOCALINDEX', - 'GETVALUELOCALINDEXBOOL', - 'PUTVALUELOCALINDEXBOOL', - 'GETVALUELOCALINDEXNUM', - 'PUTVALUELOCALINDEXNUM', - 'GETVALUELOCALINDEXSTR', - 'PUTVALUELOCALINDEXSTR', - 'GETVALUELOCALINDEXOBJ', - 'PUTVALUELOCALINDEXOBJ', - 'LOOPINITCOUNT', - 'LOOPADDCOUNT', - 'TRACE', - 'LTBOOL', - 'GTBOOL', - 'LEBOOL', - 'GEBOOL', - 'EQBOOL', - 'NEQBOOL', - 'LTNUM', - 'GTNUM', - 'LENUM', - 'GENUM', - 'EQNUM', - 'NEQNUM', - 'LTSTR', - 'GTSTR', - 'LESTR', - 'GESTR', - 'EQSTR', - 'NEQSTR', - 'SHLBOOl', - 'SHRBOOL', - 'BANDBOOL', - 'BXORBOOL', - 'BORBOOL', - 'SHLNUM', - 'SHRNUM', - 'USHRNUM', - 'BANDNUM', - 'BXORNUM', - 'BORNUM', - 'SETCUNDEF', - 'SETCNULL', - 'SETCBOOL', - 'SETCNUM', - 'SETCSTR', - 'SETCOBJ', - 'TRACENEW', - 'TRACECALL', - 'LTNUMCONST', - 'GTNUMCONST', - 'LENUMCONST', - 'GENUMCONST', - 'EQNUMCONST', - 'NEQNUMCONST', - 'JZERO', - 'JNZERO'); - -implementation - -end. diff --git a/3rd/besen/src/BESENParser.pas b/3rd/besen/src/BESENParser.pas deleted file mode 100644 index 81fb24a5e..000000000 --- a/3rd/besen/src/BESENParser.pas +++ /dev/null @@ -1,2698 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENParser; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, - BESENCollectorObject,BESENObjectPropertyDescriptor, - BESENLexicalEnvironment,BESENASTNodes, - BESENEnvironmentRecord,BESENStringTree, - BESENPointerList, - BESENLexer; - -type TBESENParserLabelSet=class(TBESENCollectorObject) - public - Next:TBESENParserLabelSet; - Target:TBESENTarget; - Continuable:longbool; - Index:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENParserLabel=class(TBESENCollectorObject) - public - Next:TBESENParserLabel; - Name:TBESENString; - LabelSet:TBESENParserLabelSet; - Node:TBESENASTNode; - LineNumber:integer; - Index:integer; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - end; - - TBESENParser=class(TBESENBaseObject) - public - Lexer:TBESENLexer; - WarningProc:TBESENWarningProc; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Init; - function Parse(IsFunction,IsJSON:boolean):TBESENASTNode; - end; - -implementation - -uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESEN,BESENUtils,BESENStringUtils,BESENErrors; - -constructor TBESENParserLabelSet.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Next:=nil; - Target:=-1; - Continuable:=false; - Index:=-1; -end; - -destructor TBESENParserLabelSet.Destroy; -begin - Next:=nil; - inherited Destroy; -end; - -constructor TBESENParserLabel.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Next:=nil; - Name:=''; - LabelSet:=nil; - Node:=nil; - LineNumber:=0; - Index:=-1; -end; - -destructor TBESENParserLabel.Destroy; -begin - Next:=nil; - Node:=nil; - LabelSet:=nil; - Name:=''; - inherited Destroy; -end; - -constructor TBESENParser.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Lexer:=TBESENLexer.Create(Instance); - ErrorProc:=nil; - WarningProc:=nil; -end; - -destructor TBESENParser.Destroy; -begin - Lexer.Free; - inherited Destroy; -end; - -procedure TBESENParser.Init; -begin - Lexer.NextChar; -end; - -function TBESENParser.Parse(IsFunction,IsJSON:boolean):TBESENASTNode; -var CurrentToken:TBESENLexerToken; - InForHeader:boolean; - Labels:TBESENParserLabel; - LabelSets,CurrentLabelSet:TBESENParserLabelSet; - LabelSetList,LabelList:TBESENPointerList; - IsInFunction,UseStrictAlreadyParsed:boolean; - procedure AddError(const Msg:TBESENSTRING); - begin - TBESEN(Instance).LineNumber:=Lexer.LineNumber; - raise EBESENSyntaxError.CreateUTF16(Msg); - end; - procedure AddWarning(const Msg:TBESENSTRING); - begin - if assigned(WarningProc) then begin - WarningProc(Lexer.LineNumber,Msg); - end; - end; - procedure NextToken; - begin - Lexer.GetToken(CurrentToken); - end; - procedure SkipToken(TokenType:TBESENLexerTokenType); - begin - if CurrentToken.TokenType<>TokenType then begin - AddError('"'+BESENTokenStrings[TokenType]+'" expected'); - end; - NextToken; - end; - procedure CleanUpLabels; - var i:integer; - begin - for i:=0 to LabelSetList.Count-1 do begin - TBESENParserLabelSet(LabelSetList[i]).Free; - LabelSetList[i]:=nil; - end; - LabelSetList.Clear; - for i:=0 to LabelList.Count-1 do begin - TBESENParserLabelSet(LabelList[i]).Free; - LabelList[i]:=nil; - end; - LabelList.Clear; - end; - function LabelSetCurrent:TBESENParserLabelSet; - begin - if not assigned(CurrentLabelSet) then begin - CurrentLabelSet:=TBESENParserLabelSet.Create(Instance); - CurrentLabelSet.Index:=LabelSetList.Add(CurrentLabelSet); - if assigned(LabelSets) then begin - CurrentLabelSet.Target:=LabelSets.Target+1; - end else begin - CurrentLabelSet.Target:=1; - end; - CurrentLabelSet.Next:=LabelSets; - LabelSets:=CurrentLabelSet; - end; - result:=CurrentLabelSet; - end; - function LabelEnter(const Name:TBESENString='';const Node:TBESENASTNode=nil):TBESENParserLabel; - var l:TBESENParserLabel; - begin - result:=nil; - try - if length(Name)<>0 then begin - l:=Labels; - while assigned(l) do begin - if l.Name=Name then begin - TBESEN(Instance).LineNumber:=Lexer.LineNumber; - raise EBESENSyntaxError.CreateUTF16('Duplicate label "'+Name+'"'); - end; - l:=l.Next; - end; - end; - result:=TBESENParserLabel.Create(Instance); - result.Name:=Name; - result.LabelSet:=LabelSetCurrent; - result.Node:=Node; - result.LineNumber:=Lexer.LineNumber; - result.Next:=Labels; - result.Index:=LabelList.Add(result); - Labels:=result; - except - BESENFreeAndNil(result); - raise; - end; - end; - procedure LabelLeave; - var OldLabels:TBESENParserLabel; - begin -{$ifdef UseAssert} - Assert(assigned(Labels)); -{$endif} - if assigned(Labels) then begin - OldLabels:=Labels; - Labels:=OldLabels.Next; - LabelList[OldLabels.Index]:=niL; - BESENFreeAndNil(OldLabels); - end; - end; - function LabelTargetLookup(const Name:TBESENString='';const Continuable:boolean=false):TBESENTarget; - var l:TBESENParserLabel; - begin - try - l:=Labels; - while assigned(l) do begin - if l.Name=Name then begin - if Continuable and not l.LabelSet.Continuable then begin - if length(Name)=0 then begin - continue; - end; - TBESEN(Instance).LineNumber:=Lexer.LineNumber; - raise EBESENSyntaxError.CreateUTF16('Label name "'+Name+'" not suitable for continue'); - end; - result:=l.LabelSet.Target; - exit; - end; - l:=l.Next; - end; - if length(Name)<>0 then begin - TBESEN(Instance).LineNumber:=Lexer.LineNumber; - raise EBESENSyntaxError.CreateUTF16('Label name "'+Name+'" not defined, or not reachable'); - end else if Continuable then begin - TBESEN(Instance).LineNumber:=Lexer.LineNumber; - raise EBESENSyntaxError.Create('Continue statement not within a loop'); - end else begin - TBESEN(Instance).LineNumber:=Lexer.LineNumber; - raise EBESENSyntaxError.Create('Break statement not within a loop or switch'); - end; - except - raise; - end; - end; - function ParseSourceElement:TBESENASTNodeStatement; forward; - function ParseStatement(ResetCurrentLabelSet:boolean):TBESENASTNodeStatement; forward; - function ParseAssignmentExpression(InFlag:boolean):TBESENASTNodeExpression; forward; - function ParseExpression(InFlag:boolean):TBESENASTNodeExpression; forward; - function NextIsSemicolon:boolean; - begin - result:=(CurrentToken.TokenType in [ltEOF,ltoCLOSEBRACE,ltoSEMICOLON]) or (CurrentToken.WasLineEnd and not InForHeader); - end; - procedure ParseOptionalSemicolon; - begin - case CurrentToken.TokenType of - ltEOF:begin - end; - ltoCLOSEBRACE:begin - end; - ltoSEMICOLON:begin - SkipToken(ltoSEMICOLON); - end; - else begin - if not (CurrentToken.WasLineEnd and not InForHeader) then begin - SkipToken(ltoSEMICOLON); - end; - end; - end; - end; - procedure ParseDirective(var IsDirectivePrologue,FirstDirective:boolean;Body:TBESENASTNodeFunctionBody); - var OldToken:TBESENLexerToken; - begin - if IsDirectivePrologue then begin - if CurrentToken.TokenType=lttSTRING then begin - OldToken:=CurrentToken; - NextToken; - if NextIsSemicolon then begin - if (length(OldToken.StringValue)=10) and (copy(Lexer.Source,OldToken.OldPosition,10)='use strict') then begin - if UseStrictAlreadyParsed then begin - AddWarning('"use strict"/''use strict'' already seen!'); - end else begin - UseStrictAlreadyParsed:=true; - if not TBESEN(Instance).IsStrict then begin - TBESEN(Instance).IsStrict:=true; - Body.IsStrict:=true; - if not FirstDirective then begin - raise EBESENUseStrict.Create('Wrong "use strict"/''use strict'' position!'); - end; - end else begin - TBESEN(Instance).IsStrict:=true; - end; - end; - end; - FirstDirective:=false; - end else begin - IsDirectivePrologue:=false; - end; - Lexer.Restore(OldToken); - NextToken; - end else begin - IsDirectivePrologue:=false; - end; - end; - end; - function ParseIdentifier(AllowEvalArguments:boolean):TBESENASTNodeIdentifier; - begin - result:=nil; - try - result:=TBESENASTNodeIdentifier.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - if CurrentToken.TokenType=lttIDENTIFIER then begin - result.Name:=CurrentToken.Name; - end else begin - AddError('identifier literal expected'); - end; - if (TBESEN(Instance).IsStrict and not AllowEvalArguments) and ((result.Name='eval') or (result.Name='arguments')) then begin - AddError('"'+result.Name+'" not allowed here'); - end; - NextToken; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseIdentifierName(AllowEvalArguments:boolean):TBESENASTNodeIdentifier; - begin - result:=nil; - try - result:=TBESENASTNodeIdentifier.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - if CurrentToken.TokenType in BESENLexerKeywordsTokens then begin - result.Name:=BESENTokenStrings[CurrentToken.TokenType]; - end else if CurrentToken.TokenType=lttIDENTIFIER then begin - result.Name:=CurrentToken.Name; - end else begin - AddError('identifier literal expected'); - end; - if (TBESEN(Instance).IsStrict and not AllowEvalArguments) and ((result.Name='eval') or (result.Name='arguments')) then begin - AddError('"'+result.Name+'" not allowed here'); - end; - NextToken; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseFunctionLiteral(WithFunction,WithName:boolean):TBESENASTNodeFunctionLiteral; - var i,j:integer; - OldIsInFunction,OldIsStrict,OldUseStrictAlreadyParsed:boolean; - OldToken:TBesenLexerToken; - procedure ParseFunctionStatements; - var IsDirectivePrologue,FirstDirective:boolean; - Statements,i:integer; - begin - Statements:=0; - try - IsDirectivePrologue:=true; - FirstDirective:=true; - UseStrictAlreadyParsed:=false; - while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin - if IsDirectivePrologue then begin - ParseDirective(IsDirectivePrologue,FirstDirective,result.Body); - end; - if Statements>=length(result.Body.Statements) then begin - SetLength(result.Body.Statements,Statements+256); - end; - result.Body.Statements[Statements]:=ParseSourceElement; - inc(Statements); - end; - SetLength(result.Body.Statements,Statements); - SkipToken(ltoCLOSEBRACE); - except - for i:=0 to Statements-1 do begin - BesenFreeAndNil(result.Body.Statements[i]); - end; - SetLength(result.Body.Statements,0); - Statements:=0; - raise; - end; - end; - function ParseFakeReturnStatement:TBESENASTNodeReturnStatement; - begin - result:=nil; - try - result:=TBESENASTNodeReturnStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - if not NextIsSemicolon then begin - result.Expression:=ParseExpression(true); - end; - if NextIsSemicolon then begin - ParseOptionalSemicolon; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - var FakeReturnStatement:TBESENASTNodeReturnStatement; - begin - result:=nil; - try - OldUseStrictAlreadyParsed:=UseStrictAlreadyParsed; - OldIsInFunction:=IsInFunction; - OldIsStrict:=TBESEN(Instance).IsStrict; - IsInFunction:=true; - try - result:=TBESENASTNodeFunctionLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - - if WithFunction then begin - SkipToken(ltkFUNCTION); - end; - - if WithName or (CurrentToken.TokenType<>ltoOPENPAREN) then begin - result.Name:=ParseIdentifier(not TBESEN(Instance).IsStrict); - end; - - SkipToken(ltoOPENPAREN); - i:=0; - if (CurrentToken.TokenType<>ltoCLOSEPAREN) and not Lexer.IsEOF then begin - while true do begin - if i>=length(result.Body.Parameters) then begin - SetLength(result.Body.Parameters,i+256); - end; - result.Body.Parameters[i]:=ParseIdentifier(not TBESEN(Instance).IsStrict); - if TBESEN(Instance).IsStrict and (result.Body.Parameters[i] is TBESENASTNodeIdentifier) then begin - for j:=0 to i-1 do begin - if TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name=TBESENASTNodeIdentifier(result.Body.Parameters[j]).Name then begin - AddError('Duplicate parameter "'+TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name+'"'); - end; - end; - end; - inc(i); - if Lexer.IsEOF or (CurrentToken.TokenType=ltoCLOSEPAREN) then begin - break; - end else if CurrentToken.TokenType=ltoCOMMA then begin - SkipToken(ltoCOMMA); - end; - end; - end; - SetLength(result.Body.Parameters,i); - SkipToken(ltoCLOSEPAREN); - - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (CurrentToken.TokenType<>ltoOPENBRACE) then begin - UseStrictAlreadyParsed:=false; - result.Body.IsStrict:=TBESEN(Instance).IsStrict; - if CurrentToken.WasLineEnd then begin - CurrentToken.WasLineEnd:=false; - end; - FakeReturnStatement:=ParseFakeReturnStatement; - SetLength(result.Body.Statements,1); - result.Body.Statements[0]:=FakeReturnStatement; - end else begin - SkipToken(ltoOPENBRACE); - if IsFunction then begin - IsFunction:=false; - Lexer.LineNumber:=1; - end; - OldToken:=CurrentToken; - result.Body.IsStrict:=TBESEN(Instance).IsStrict; - try - ParseFunctionStatements; - except - on e:EBESENUseStrict do begin - result.Body.IsStrict:=TBESEN(Instance).IsStrict; - Lexer.Restore(OldToken); - NextToken; - ParseFunctionStatements; - end; - end; - end; - finally - IsInFunction:=OldIsInFunction; - TBESEN(Instance).IsStrict:=OldIsStrict; - UseStrictAlreadyParsed:=OldUseStrictAlreadyParsed; - end; - if result.Body.IsStrict then begin - if assigned(result.Name) and ((result.Name.Name='eval') or (result.Name.Name='arguments')) then begin - AddError('"'+result.Name.Name+'" not allowed here as function parameter name'); - end; - for i:=0 to length(result.Body.Parameters)-1 do begin - if (result.Body.Parameters[i].Name='eval') or (result.Body.Parameters[i].Name='arguments') then begin - AddError('"'+result.Body.Parameters[i].Name+'" not allowed here as function parameter name'); - end; - for j:=0 to i-1 do begin - if result.Body.Parameters[i].Name=result.Body.Parameters[j].Name then begin - AddError('Duplicate parameter "'+TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name+'"'); - end; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseFunctionDeclaration:TBESENASTNodeFunctionDeclaration; - var Literal:TBESENASTNodeFunctionLiteral; - begin - result:=nil; - try - result:=TBESENASTNodeFunctionDeclaration.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - Literal:=ParseFunctionLiteral(true,true); - result.Container:=Literal.Container; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseFunctionExpression(WithFunction,WithName:boolean):TBESENASTNodeFunctionExpression; - var Literal:TBESENASTNodeFunctionLiteral; - begin - result:=nil; - try - result:=TBESENASTNodeFunctionExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - Literal:=ParseFunctionLiteral(WithFunction,WithName); - result.Container:=Literal.Container; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseStatementList(InSwitch:boolean):TBESENASTNodeStatements; - var Count:integer; - begin - result:=nil; - try - Count:=0; - while (not ((CurrentToken.TokenType=ltoCLOSEBRACE) or (InSwitch and (CurrentToken.TokenType=ltkCASE) or (CurrentToken.TokenType=ltkDEFAULT)))) and not Lexer.IsEOF do begin - if Count>=length(result) then begin - SetLength(result,Count+256); - end; - result[Count]:=ParseStatement(true); - inc(Count); - if CurrentToken.TokenType=ltkFUNCTION then begin - if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin - break; - end; - end; - end; - SetLength(result,Count); - except - for Count:=0 to length(result)-1 do begin - BESENFreeAndNil(result[Count]); - end; - SetLength(result,0); - raise; - end; - end; - function ParseBlockStatement:TBESENASTNodeBlockStatement; - begin - result:=nil; - try - SkipToken(ltoOPENBRACE); - result:=TBESENASTNodeBlockStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - result.Statements:=ParseStatementList(false); - SkipToken(ltoCLOSEBRACE); - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseDebuggerStatement:TBESENASTNodeDebuggerStatement; - begin - result:=nil; - try - SkipToken(ltkDEBUGGER); - result:=TBESENASTNodeDebuggerStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - ParseOptionalSemicolon; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseBreakStatement:TBESENASTNodeBreakStatement; - begin - result:=nil; - try - SkipToken(ltkBREAK); - result:=TBESENASTNodeBreakStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - if NextIsSemicolon then begin - result.Target:=LabelTargetLookup('',false); - end else begin - if CurrentToken.TokenType=lttIDENTIFIER then begin - if CurrentToken.WasLineEnd then begin - AddError('Illegal line terminator after break'); - end; - result.Identifier:=ParseIdentifier(true); - if assigned(result.Identifier) then begin - result.Target:=LabelTargetLookup(result.Identifier.Name,false); - end else begin - result.Target:=LabelTargetLookup('',false); - end; - end; - ParseOptionalSemicolon; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseContinueStatement:TBESENASTNodeContinueStatement; - begin - result:=nil; - try - SkipToken(ltkCONTINUE); - result:=TBESENASTNodeContinueStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - if NextIsSemicolon then begin - result.Target:=LabelTargetLookup('',true); - end else begin - if CurrentToken.TokenType=lttIDENTIFIER then begin - if CurrentToken.WasLineEnd then begin - AddError('Illegal line terminator after continue'); - end; - result.Identifier:=ParseIdentifier(true); - if assigned(result.Identifier) then begin - result.Target:=LabelTargetLookup(result.Identifier.Name,true); - end else begin - result.Target:=LabelTargetLookup('',true); - end; - end; - ParseOptionalSemicolon; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseAssignmentExpression(InFlag); - while not Lexer.IsEOF do begin - case CurrentToken.TokenType of - ltoCOMMA:begin - SkipToken(ltoCOMMA); - Left:=result; - result:=TBESENASTNodeBinaryCommaExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryCommaExpression(result).LeftExpression:=Left; - TBESENASTNodeBinaryCommaExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - else begin - break; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseDoStatement:TBESENASTNodeDoStatement; - var LabelSet:TBESENParserLabelSet; - begin - result:=nil; - try - result:=TBESENASTNodeDoStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - LabelSet:=LabelSetCurrent; - LabelSet.Continuable:=true; - LabelEnter('',result); - result.Target:=LabelSet.Target; - SkipToken(ltkDO); - result.Statement:=ParseStatement(true); - SkipToken(ltkWHILE); - result.Expression:=ParseExpression(true); - ParseOptionalSemicolon; - LabelLeave; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseRegExpLiteral:TBESENASTNodeRegExpLiteral; - begin - result:=nil; - try - result:=TBESENASTNodeRegExpLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - if CurrentToken.TokenType in [ltoDIVIDE,ltoDIVIDEASSIGNMENT] then begin - Lexer.Restore(CurrentToken); - if not Lexer.ParseRegExpLiteral(CurrentToken,result.Source,result.Flags) then begin - AddError('regex literal expected'); - end; - end else begin - AddError('regex literal expected'); - end; - NextToken; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseStringLiteral:TBESENASTNodeStringLiteral; - begin - result:=nil; - try - result:=TBESENASTNodeStringLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - if CurrentToken.TokenType=lttSTRING then begin - result.Value:=CurrentToken.StringValue; - end else begin - AddError('string literal expected'); - end; - NextToken; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseNumbericLiteral:TBESENASTNodeNumberLiteral; - begin - result:=nil; - try - result:=TBESENASTNodeNumberLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - case CurrentToken.TokenType of - lttINTEGER:begin - result.Value:=CurrentToken.IntValue; - end; - lttFLOAT:begin - result.Value:=CurrentToken.FloatValue; - end; - else begin - AddError('numberic literal expected'); - end; - end; - NextToken; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseObjectLiteralProperty(const Parent:TBESENASTNodeObjectLiteral;const Count:integer):TBESENASTNodeObjectLiteralProperty; - var PropertyType:TBESENASTNodeObjectLiteralPropertyType; - PropertyAccessorType:TBESENASTNodeObjectLiteralPropertyAccessorType; - OldToken:TBESENLexerToken; - i:integer; - Key:TBESENString; - function ParseObjectLiteralPropertyName:TBESENString; - begin - case CurrentToken.TokenType of - lttIDENTIFIER:begin - result:=CurrentToken.Name; - NextToken; - end; - lttSTRING:begin - result:=CurrentToken.StringValue; - NextToken; - end; - lttINTEGER:begin - result:=TBESEN(Instance).ToStr(BESENNumberValue(CurrentToken.IntValue)); - NextToken; - end; - lttFLOAT:begin - result:=TBESEN(Instance).ToStr(BESENNumberValue(CurrentToken.FloatValue)); - NextToken; - end; - else begin - if CurrentToken.TokenType in BESENLexerKeywordsTokens then begin - result:=BESENTokenStrings[CurrentToken.TokenType]; - NextToken; - end else begin - AddError('identifier or numeric literal expected'); - end; - end; - end; - end; - var Literal:TBESENASTNodeFunctionLiteral; - begin - result:=nil; - try - PropertyType:=banolptDATA; - PropertyAccessorType:=banolpatNONE; - if (CurrentToken.TokenType=lttIDENTIFIER) and ((CurrentToken.Name='get') or (CurrentToken.Name='set')) then begin - OldToken:=CurrentToken; - if CurrentToken.Name='get' then begin - PropertyType:=banolptACCESSOR; - PropertyAccessorType:=banolpatGET; - end else if CurrentToken.Name='set' then begin - PropertyType:=banolptACCESSOR; - PropertyAccessorType:=banolpatSET; - end; - if PropertyType=banolptACCESSOR then begin - NextToken; - if not (CurrentToken.TokenType in [lttIDENTIFIER,lttSTRING,lttINTEGER,lttFLOAT]) then begin - PropertyType:=banolptDATA; - Lexer.Restore(OldToken); - NextToken; - end; - end; - end; - Key:=ParseObjectLiteralPropertyName; - case PropertyType of - banolptACCESSOR:begin - for i:=0 to Count-1 do begin - if Key=Parent.Properties[i].Name then begin - case Parent.Properties[i].PropertyType of - banolptACCESSOR:begin - if Parent.Properties[i].PropertyAccessorType=PropertyAccessorType then begin - case PropertyAccessorType of - banolpatGET:begin - AddError('Duplicate accessor property getter "'+Key+'"'); - end; - banolpatSET:begin - AddError('Duplicate accessor property setter "'+Key+'"'); - end; - else begin - AddError('Invalid property "'+Key+'"'); - end; - end; - end; - end; - banolptDATA:begin - AddError('Invalid property "'+Key+'"'); - end; - end; - end; - end; - result:=TBESENASTNodeObjectLiteralProperty.Create(Instance); - result.PropertyType:=PropertyType; - result.PropertyAccessorType:=PropertyAccessorType; - result.Name:=Key; - Literal:=ParseFunctionLiteral(false,false); - result.Container:=Literal.Container; - if not ((PropertyAccessorType in [banolpatGET,banolpatSET]) and (assigned(Literal) and assigned(Literal.Body))) then begin - AddError('Invalid property "'+Key+'"'); - end else begin - case PropertyAccessorType of - banolpatGET:begin - if length(Literal.Body.Parameters)>0 then begin - AddError('Getter must have no parameters'); - end; - end; - banolpatSET:begin - if length(Literal.Body.Parameters)<>1 then begin - AddError('Setter must have only one parameter'); - end; - end; - else begin - AddError('Invalid property "'+Key+'"'); - end; - end; - end; - end; - banolptDATA:begin - for i:=0 to Count-1 do begin - if Key=Parent.Properties[i].Name then begin - case Parent.Properties[i].PropertyType of - banolptACCESSOR:begin - AddError('Invalid property "'+Key+'"'); - end; - banolptDATA:begin - if TBESEN(Instance).IsStrict then begin - AddError('Duplicate data property "'+Key+'"'); - end; - end; - end; - end; - end; - result:=TBESENASTNodeObjectLiteralProperty.Create(Instance); - result.PropertyType:=banolptDATA; - result.Location.LineNumber:=CurrentToken.LineNumber; - result.Name:=Key; - SkipToken(ltoCOLON); - result.Value:=ParseAssignmentExpression(true); - end; - else begin - AddError('Invalid property "'+Key+'"'); - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseObjectLiteral:TBESENASTNodeObjectLiteral; - var Count:integer; - begin - result:=nil; - try - result:=TBESENASTNodeObjectLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - result.Properties:=nil; - Count:=0; - SkipToken(ltoOPENBRACE); - while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin - if Count>=length(result.Properties) then begin - SetLength(result.Properties,Count+256); - end; - result.Properties[Count]:=ParseObjectLiteralProperty(result,Count); - inc(Count); - if CurrentToken.TokenType<>ltoCLOSEBRACE then begin - if CurrentToken.TokenType=ltoCOMMA then begin - SkipToken(ltoCOMMA); - end else begin - AddError(''','' or ''}'' expected'); - break; - end; - end; - end; - SetLength(result.Properties,Count); - SkipToken(ltoCLOSEBRACE); - except - for Count:=0 to length(result.Properties)-1 do begin - BESENFreeAndNil(result.Properties[Count]); - end; - SetLength(result.Properties,0); - BESENFreeAndNil(result); - raise; - end; - end; - function ParseArrayLiteral:TBESENASTNodeArrayLiteral; - var Count:integer; - begin - result:=nil; - try - result:=TBESENASTNodeArrayLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoOPENSQUARE); - result.Elements:=nil; - Count:=0; - while (CurrentToken.TokenType<>ltoCLOSESQUARE) and not Lexer.IsEOF do begin - if Count>=length(result.Elements) then begin - SetLength(result.Elements,Count+256); - end; - if CurrentToken.TokenType=ltoCOMMA then begin - result.Elements[Count]:=nil; - end else begin - result.Elements[Count]:=ParseAssignmentExpression(true); - end; - inc(Count); - if CurrentToken.TokenType<>ltoCLOSESQUARE then begin - if CurrentToken.TokenType=ltoCOMMA then begin - SkipToken(ltoCOMMA); - end else begin - AddError(''','' or '']'' expected'); - break; - end; - end; - end; - SetLength(result.Elements,Count); - SkipToken(ltoCLOSESQUARE); - except - for Count:=0 to length(result.Elements)-1 do begin - BESENFreeAndNil(result.Elements[Count]); - end; - SetLength(result.Elements,0); - BESENFreeAndNil(result); - raise; - end; - end; - function ParsePrimaryExpression:TBESENASTNodeExpression; - begin - result:=nil; - try - case CurrentToken.TokenType of - ltkTHIS:begin - result:=TBESENASTNodeThisLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltkTHIS); - end; - ltkNULL:begin - result:=TBESENASTNodeNullLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltkNULL); - end; - ltkTRUE:begin - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBooleanLiteral(result).Value:=true; - SkipToken(ltkTRUE); - end; - ltkFALSE:begin - result:=TBESENASTNodeBooleanLiteral.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBooleanLiteral(result).Value:=false; - SkipToken(ltkFALSE); - end; - ltoOPENPAREN:begin - SkipToken(ltoOPENPAREN); - result:=ParseExpression(true); - SkipToken(ltoCLOSEPAREN); - end; - ltoOPENBRACE:begin - result:=ParseObjectLiteral; - end; - ltoOPENSQUARE:begin - result:=ParseArrayLiteral; - end; - lttIDENTIFIER:begin - result:=ParseIdentifier(true); - end; - ltoDIVIDE,ltoDIVIDEASSIGNMENT:begin - result:=ParseRegExpLiteral; - end; - lttSTRING:begin - result:=ParseStringLiteral; - end; - lttINTEGER,lttFLOAT:begin - result:=ParseNumbericLiteral; - end; - else begin - AddError('identifier or literal expected'); - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseArgumentList:TBESENASTNodeExpressions; - var Count:integer; - begin - result:=nil; - try - Count:=0; - SkipToken(ltoOPENPAREN); - if (CurrentToken.TokenType<>ltoCLOSEPAREN) and not Lexer.IsEOF then begin - while true do begin - if Count>=length(result) then begin - SetLength(result,Count+256); - end; - result[Count]:=ParseAssignmentExpression(true); - inc(Count); - if Lexer.IsEOF or (CurrentToken.TokenType=ltoCLOSEPAREN) then begin - break; - end else if CurrentToken.TokenType=ltoCOMMA then begin - SkipToken(ltoCOMMA); - end else begin - break; - end; - end; - end; - SkipToken(ltoCLOSEPAREN); - SetLength(result,Count); - except - for Count:=0 to length(result)-1 do begin - BESENFreeAndNil(result[Count]); - end; - SetLength(result,0); - raise; - end; - end; - function ParseLeftHandSideAndMemberExpression(IsLeftHandSideExpression:boolean=true):TBESENASTNodeExpression; - var Expression:TBESENASTNodeExpression; - Identifier:TBESENASTNodeIdentifier; - begin - result:=nil; - try - case CurrentToken.TokenType of - ltkNEW:begin - SkipToken(ltkNEW); - result:=TBESENASTNodeNewExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeNewExpression(result).TheFunction:=ParseLeftHandSideAndMemberExpression(false); - if CurrentToken.TokenType=ltoOPENPAREN then begin - TBESENASTNodeNewExpression(result).Arguments:=ParseArgumentList; - end else begin - TBESENASTNodeNewExpression(result).Arguments:=nil; - end; - end; - ltkFUNCTION:begin - result:=ParseFunctionExpression(true,false); - end; - else begin - result:=ParsePrimaryExpression; - end; - end; - while not Lexer.IsEOF do begin - if IsLeftHandSideExpression and (CurrentToken.TokenType=ltoOPENPAREN) then begin - Expression:=result; - result:=TBESENASTNodeCallExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeCallExpression(result).TheFunction:=Expression; - TBESENASTNodeCallExpression(result).Arguments:=ParseArgumentList; - end else if CurrentToken.TokenType=ltoOPENSQUARE then begin - Expression:=result; - result:=TBESENASTNodePropertyExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodePropertyExpression(result).Dot:=false; - TBESENASTNodePropertyExpression(result).LeftExpression:=Expression; - SkipToken(ltoOPENSQUARE); - TBESENASTNodePropertyExpression(result).RightExpression:=ParseExpression(true); - if TBESEN(Instance).IsStrict then begin - if assigned(TBESENASTNodePropertyExpression(result).RightExpression) then begin - if TBESENASTNodePropertyExpression(result).RightExpression is TBESENASTNodeStringLiteral then begin - if ((TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value='eval') or (TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value='arguments')) then begin - AddError('"'+TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value+'" not allowed here'); - end; - end; - end; - end; - SkipToken(ltoCLOSESQUARE); - end else if CurrentToken.TokenType=ltoDOT then begin - Expression:=result; - result:=TBESENASTNodePropertyExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodePropertyExpression(result).Dot:=true; - TBESENASTNodePropertyExpression(result).LeftExpression:=Expression; - SkipToken(ltoDOT); - TBESENASTNodePropertyExpression(result).RightExpression:=TBESENASTNodeStringLiteral.Create(Instance); - Identifier:=ParseIdentifierName(true); - TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value:=Identifier.Name; - Identifier.Free; - end else begin - break; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParsePostfixExpression:TBESENASTNodeExpression; - var Expression:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseLeftHandSideAndMemberExpression; - case CurrentToken.TokenType of - ltoPLUSPLUS:begin - if CurrentToken.WasLineEnd then begin - AddError('Illegal line terminator before postfix increment'); - end; - Expression:=result; - result:=TBESENASTNodePostfixIncExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoPLUSPLUS); - TBESENASTNodePostfixIncExpression(result).SubExpression:=Expression; - end; - ltoMINUSMINUS:begin - if CurrentToken.WasLineEnd then begin - AddError('Illegal line terminator before postfix decrement'); - end; - Expression:=result; - result:=TBESENASTNodePostfixDecExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoMINUSMINUS); - TBESENASTNodePostfixDecExpression(result).SubExpression:=Expression; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseUnaryExpression:TBESENASTNodeExpression; - begin - result:=nil; - try - case CurrentToken.TokenType of - ltoPLUSPLUS:begin - result:=TBESENASTNodePrefixIncExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoPLUSPLUS); - TBESENASTNodePrefixIncExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltoMINUSMINUS:begin - result:=TBESENASTNodePrefixDecExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoMINUSMINUS); - TBESENASTNodePrefixdecExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltoPLUS:begin - result:=TBESENASTNodeUnaryPlusExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoPLUS); - TBESENASTNodeUnaryPlusExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltoMINUS:begin - result:=TBESENASTNodeUnaryMinusExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoMINUS); - TBESENASTNodeUnaryMinusExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltoBITWISENOT:begin - result:=TBESENASTNodeUnaryBitwiseNotExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoBITWISENOT); - TBESENASTNodeUnaryBitwiseNotExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltoLOGICALNOT:begin - result:=TBESENASTNodeUnaryLogicalNotExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltoLOGICALNOT); - TBESENASTNodeUnaryLogicalNotExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltkVOID:begin - result:=TBESENASTNodeUnaryVoidExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltkVOID); - TBESENASTNodeUnaryVoidExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltkTYPEOF:begin - result:=TBESENASTNodeUnaryTypeOfExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltkTYPEOF); - TBESENASTNodeUnaryTypeOfExpression(result).SubExpression:=ParseUnaryExpression; - end; - ltkDELETE:begin - result:=TBESENASTNodeDeleteExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - SkipToken(ltkDELETE); - TBESENASTNodeDeleteExpression(result).SubExpression:=ParseUnaryExpression; - end; - else begin - result:=ParsePostfixExpression; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseMultiplyExpression:TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseUnaryExpression; - while not Lexer.IsEOF do begin - case CurrentToken.TokenType of - ltoDIVIDE:begin - Left:=result; - result:=TBESENASTNodeBinaryDivideExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryDivideExpression(result).LeftExpression:=Left; - SkipToken(ltoDIVIDE); - TBESENASTNodeBinaryDivideExpression(result).RightExpression:=ParseUnaryExpression; - end; - ltoMODULO:begin - Left:=result; - result:=TBESENASTNodeBinaryModuloExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryModuloExpression(result).LeftExpression:=Left; - SkipToken(ltoMODULO); - TBESENASTNodeBinaryModuloExpression(result).RightExpression:=ParseUnaryExpression; - end; - ltoMULTIPLY:begin - Left:=result; - result:=TBESENASTNodeBinaryMultiplyExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryMultiplyExpression(result).LeftExpression:=Left; - SkipToken(ltoMULTIPLY); - TBESENASTNodeBinaryMultiplyExpression(result).RightExpression:=ParseUnaryExpression; - end; - else begin - break; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseAdditionExpression:TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseMultiplyExpression; - while not Lexer.IsEOF do begin - case CurrentToken.TokenType of - ltoPLUS:begin - Left:=result; - result:=TBESENASTNodeBinaryPlusExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryPlusExpression(result).LeftExpression:=Left; - SkipToken(ltoPLUS); - TBESENASTNodeBinaryPlusExpression(result).RightExpression:=ParseMultiplyExpression; - end; - ltoMINUS:begin - Left:=result; - result:=TBESENASTNodeBinaryMinusExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryMinusExpression(result).LeftExpression:=Left; - SkipToken(ltoMINUS); - TBESENASTNodeBinaryMinusExpression(result).RightExpression:=ParseMultiplyExpression; - end; - else begin - break; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseShiftExpression:TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseAdditionExpression; - while not Lexer.IsEOF do begin - case CurrentToken.TokenType of - ltoSHIFTLEFT:begin - Left:=result; - result:=TBESENASTNodeBinaryShiftLeftExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryShiftLeftExpression(result).LeftExpression:=Left; - SkipToken(ltoSHIFTLEFT); - TBESENASTNodeBinaryShiftLeftExpression(result).RightExpression:=ParseAdditionExpression; - end; - ltoSHIFTRIGHT:begin - Left:=result; - result:=TBESENASTNodeBinaryShiftRightExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryShiftRightExpression(result).LeftExpression:=Left; - SkipToken(ltoSHIFTRIGHT); - TBESENASTNodeBinaryShiftRightExpression(result).RightExpression:=ParseAdditionExpression; - end; - ltoSHIFTRIGHTUNSIGNED:begin - Left:=result; - result:=TBESENASTNodeBinaryShiftRightUnsignedExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryShiftRightUnsignedExpression(result).LeftExpression:=Left; - SkipToken(ltoSHIFTRIGHTUNSIGNED); - TBESENASTNodeBinaryShiftRightUnsignedExpression(result).RightExpression:=ParseAdditionExpression; - end; - else begin - break; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseRelationalExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseShiftExpression; - while not Lexer.IsEOF do begin - case CurrentToken.TokenType of - ltoGREATERTHAN:begin - Left:=result; - result:=TBESENASTNodeBinaryGreaterThanExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryGreaterThanExpression(result).LeftExpression:=Left; - SkipToken(ltoGREATERTHAN); - TBESENASTNodeBinaryGreaterThanExpression(result).RightExpression:=ParseShiftExpression; - end; - ltoGREATERTHANOREQUAL:begin - Left:=result; - result:=TBESENASTNodeBinaryGreaterThanOrEqualExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).LeftExpression:=Left; - SkipToken(ltoGREATERTHANOREQUAL); - TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).RightExpression:=ParseShiftExpression; - end; - ltoLESSTHAN:begin - Left:=result; - result:=TBESENASTNodeBinaryLessThanExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryLessThanExpression(result).LeftExpression:=Left; - SkipToken(ltoLESSTHAN); - TBESENASTNodeBinaryLessThanExpression(result).RightExpression:=ParseShiftExpression; - end; - ltoLESSTHANOREQUAL:begin - Left:=result; - result:=TBESENASTNodeBinaryLessThanOrEqualExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryLessThanOrEqualExpression(result).LeftExpression:=Left; - SkipToken(ltoLESSTHANOREQUAL); - TBESENASTNodeBinaryLessThanOrEqualExpression(result).RightExpression:=ParseShiftExpression; - end; - ltkINSTANCEOF:begin - Left:=result; - result:=TBESENASTNodeBinaryInstanceOfExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryInstanceOfExpression(result).LeftExpression:=Left; - SkipToken(ltkINSTANCEOF); - TBESENASTNodeBinaryInstanceOfExpression(result).RightExpression:=ParseShiftExpression; - end; - ltkIN:begin - if InFlag then begin - Left:=result; - result:=TBESENASTNodeBinaryInExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryInExpression(result).LeftExpression:=Left; - SkipToken(ltkIN); - TBESENASTNodeBinaryInExpression(result).RightExpression:=ParseShiftExpression; - end else begin - break; - end; - end; - else begin - break; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseEqualityExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseRelationalExpression(InFlag); - while not Lexer.IsEOF do begin - case CurrentToken.TokenType of - ltoEQUALEQUAL:begin - Left:=result; - result:=TBESENASTNodeBinaryEqualEqualExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryEqualEqualExpression(result).LeftExpression:=Left; - SkipToken(ltoEQUALEQUAL); - TBESENASTNodeBinaryEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); - end; - ltoEQUALEQUALEQUAL:begin - Left:=result; - result:=TBESENASTNodeBinaryEqualEqualEqualExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryEqualEqualEqualExpression(result).LeftExpression:=Left; - SkipToken(ltoEQUALEQUALEQUAL); - TBESENASTNodeBinaryEqualEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); - end; - ltoNOTEQUAL:begin - Left:=result; - result:=TBESENASTNodeBinaryNotEqualExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryNotEqualExpression(result).LeftExpression:=Left; - SkipToken(ltoNOTEQUAL); - TBESENASTNodeBinaryNotEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); - end; - ltoNOTEQUALEQUAL:begin - Left:=result; - result:=TBESENASTNodeBinaryNotEqualEqualExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryNotEqualEqualExpression(result).LeftExpression:=Left; - SkipToken(ltoNOTEQUALEQUAL); - TBESENASTNodeBinaryNotEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); - end; - else begin - break; - end; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseBitwiseAndExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseEqualityExpression(InFlag); - while not Lexer.IsEOF do begin - if CurrentToken.TokenType=ltoBITWISEAND then begin - Left:=result; - result:=TBESENASTNodeBinaryBitwiseAndExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryBitwiseAndExpression(result).LeftExpression:=Left; - SkipToken(ltoBITWISEAND); - TBESENASTNodeBinaryBitwiseAndExpression(result).RightExpression:=ParseEqualityExpression(InFlag); - end else begin - break; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseBitwiseXorExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseBitwiseAndExpression(InFlag); - while not Lexer.IsEOF do begin - if CurrentToken.TokenType=ltoBITWISEXOR then begin - Left:=result; - result:=TBESENASTNodeBinaryBitwiseXorExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryBitwiseXorExpression(result).LeftExpression:=Left; - SkipToken(ltoBITWISEXOR); - TBESENASTNodeBinaryBitwiseXorExpression(result).RightExpression:=ParseBitwiseAndExpression(InFlag); - end else begin - break; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseBitwiseOrExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseBitwiseXorExpression(InFlag); - while not Lexer.IsEOF do begin - if CurrentToken.TokenType=ltoBITWISEOR then begin - Left:=result; - result:=TBESENASTNodeBinaryBitwiseOrExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeBinaryBitwiseOrExpression(result).LeftExpression:=Left; - SkipToken(ltoBITWISEOR); - TBESENASTNodeBinaryBitwiseOrExpression(result).RightExpression:=ParseBitwiseXorExpression(InFlag); - end else begin - break; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseLogicalAndExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseBitwiseOrExpression(InFlag); - while not Lexer.IsEOF do begin - if CurrentToken.TokenType=ltoLOGICALAND then begin - Left:=result; - result:=TBESENASTNodeLogicalAndExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeLogicalAndExpression(result).LeftExpression:=Left; - SkipToken(ltoLOGICALAND); - TBESENASTNodeLogicalAndExpression(result).RightExpression:=ParseBitwiseOrExpression(InFlag); - end else begin - break; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseLogicalOrExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseLogicalAndExpression(InFlag); - while not Lexer.IsEOF do begin - if CurrentToken.TokenType=ltoLOGICALOR then begin - Left:=result; - result:=TBESENASTNodeLogicalOrExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeLogicalOrExpression(result).LeftExpression:=Left; - SkipToken(ltoLOGICALOR); - TBESENASTNodeLogicalOrExpression(result).RightExpression:=ParseLogicalAndExpression(InFlag); - end else begin - break; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseConditionalExpression(InFlag:boolean):TBESENASTNodeExpression; - var Expression:TBESENASTNodeExpression; - begin - result:=nil; - try - result:=ParseLogicalOrExpression(InFlag); - if CurrentToken.TokenType=ltoCONDITIONAL then begin - Expression:=result; - result:=TBESENASTNodeConditionalExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeConditionalExpression(result).Expression:=Expression; - SkipToken(ltoCONDITIONAL); - TBESENASTNodeConditionalExpression(result).TrueExpression:=ParseAssignmentExpression(InFlag); - SkipToken(ltoCOLON); - TBESENASTNodeConditionalExpression(result).FalseExpression:=ParseAssignmentExpression(InFlag); - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseAssignmentExpression(InFlag:boolean):TBESENASTNodeExpression; - var Left:TBESENASTNodeExpression; - begin - result:=nil; - Left:=nil; - try - result:=ParseConditionalExpression(InFlag); - case CurrentToken.TokenType of - ltoASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentExpression(result).LeftExpression:=Left; - SkipToken(ltoASSIGNMENT); - TBESENASTNodeAssignmentExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoMULTIPLYASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentMultiplyExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentMultiplyExpression(result).LeftExpression:=Left; - SkipToken(ltoMULTIPLYASSIGNMENT); - TBESENASTNodeAssignmentMultiplyExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoDIVIDEASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentDivideExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentDivideExpression(result).LeftExpression:=Left; - SkipToken(ltoDIVIDEASSIGNMENT); - TBESENASTNodeAssignmentDivideExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoMODULOASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentModuloExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentModuloExpression(result).LeftExpression:=Left; - SkipToken(ltoMODULOASSIGNMENT); - TBESENASTNodeAssignmentModuloExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoPLUSASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentPlusExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentPlusExpression(result).LeftExpression:=Left; - SkipToken(ltoPLUSASSIGNMENT); - TBESENASTNodeAssignmentPlusExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoMINUSASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentMinusExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentMinusExpression(result).LeftExpression:=Left; - SkipToken(ltoMINUSASSIGNMENT); - TBESENASTNodeAssignmentMinusExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoSHIFTLEFTASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentShiftLeftExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentShiftLeftExpression(result).LeftExpression:=Left; - SkipToken(ltoSHIFTLEFTASSIGNMENT); - TBESENASTNodeAssignmentShiftLeftExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoSHIFTRIGHTASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentShiftRightExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentShiftRightExpression(result).LeftExpression:=Left; - SkipToken(ltoSHIFTRIGHTASSIGNMENT); - TBESENASTNodeAssignmentShiftRightExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoSHIFTRIGHTUNSIGNEDASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentShiftRightUnsignedExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).LeftExpression:=Left; - SkipToken(ltoSHIFTRIGHTUNSIGNEDASSIGNMENT); - TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoBITWISEANDASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentBitwiseAndExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentBitwiseAndExpression(result).LeftExpression:=Left; - SkipToken(ltoBITWISEANDASSIGNMENT); - TBESENASTNodeAssignmentBitwiseAndExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoBITWISEXORASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentBitwiseXorExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentBitwiseXorExpression(result).LeftExpression:=Left; - SkipToken(ltoBITWISEXORASSIGNMENT); - TBESENASTNodeAssignmentBitwiseXorExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - ltoBITWISEORASSIGNMENT:begin - Left:=result; - result:=TBESENASTNodeAssignmentBitwiseOrExpression.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - TBESENASTNodeAssignmentBitwiseOrExpression(result).LeftExpression:=Left; - SkipToken(ltoBITWISEORASSIGNMENT); - TBESENASTNodeAssignmentBitwiseOrExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseVariableDeclaration(InFlag:boolean):TBESENASTNodeVariableDeclaration; - begin - result:=nil; - try - result:=TBESENASTNodeVariableDeclaration.Create(Instance); - result.Location.LineNumber:=CurrentToken.LineNumber; - result.Identifier:=ParseIdentifier(not TBESEN(Instance).IsStrict); - if CurrentToken.TokenType=ltoASSIGNMENT then begin - SkipToken(ltoASSIGNMENT); - result.Expression:=ParseAssignmentExpression(InFlag); - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseForStatement:TBESENASTNodeStatement; - var OldInForHeader:boolean; - State,i,ln:integer; - Declaration:TBESENASTNodeVariableDeclaration; - Initial,Expression,Variable:TBESENASTNodeExpression; - VariableExpression:TBESENASTNodeVariableExpression; - LabelSet:TBESENParserLabelSet; - ALabel:TBESENParserLabel; - begin - ln:=Lexer.LineNumber; - result:=nil; - Initial:=nil; - Declaration:=nil; - Variable:=nil; - Expression:=nil; - try - LabelSet:=LabelSetCurrent; - LabelSet.Continuable:=true; - ALabel:=LabelEnter('',nil); - - SkipToken(ltkFOR); - - SkipToken(ltoOPENPAREN); - OldInForHeader:=InForHeader; - InForHeader:=true; - State:=0; - while not Lexer.IsEOF do begin - case State of - 0:begin - if CurrentToken.TokenType=ltkVAR then begin - State:=1; - end else if CurrentToken.TokenType<>ltoSEMICOLON then begin - State:=2; - end else begin - State:=5; - end; - end; - 1:begin - SkipToken(ltkVAR); - Declaration:=ParseVariableDeclaration(false); - if (CurrentToken.TokenType=ltkIN) and (assigned(Declaration) and not assigned(Declaration.Expression)) then begin - Variable:=Declaration; - Declaration:=nil; - State:=3; - end else begin - State:=4; - end; - end; - 2:begin - Initial:=ParseExpression(false); - if CurrentToken.TokenType=ltkIN then begin - Variable:=Initial; - Initial:=nil; - State:=3; - end else begin - State:=5; - end; - end; - 3:begin - SkipToken(ltkIN); - Expression:=ParseExpression(true); - SkipToken(ltoCLOSEPAREN); - InForHeader:=OldInForHeader; - result:=TBESENASTNodeForInStatement.Create(Instance); - TBESENASTNodeForInStatement(result).Target:=LabelSet.Target; - TBESENASTNodeForInStatement(result).Variable:=Variable; - TBESENASTNodeForInStatement(result).Expression:=Expression; - ALabel.Node:=result; - Variable:=nil; - Expression:=nil; - break; - end; - 4:begin - VariableExpression:=TBESENASTNodeVariableExpression.Create(Instance); - Initial:=VariableExpression; - SetLength(VariableExpression.Declarations,1); - VariableExpression.Declarations[0]:=Declaration; - Declaration:=nil; - i:=1; - while (CurrentToken.TokenType=ltoCOMMA) and not Lexer.IsEOF do begin - SkipToken(ltoCOMMA); - if i>=length(VariableExpression.Declarations) then begin - SetLength(VariableExpression.Declarations,i+256); - end; - VariableExpression.Declarations[i]:=ParseVariableDeclaration(false); - inc(i); - end; - SetLength(VariableExpression.Declarations,i); - State:=5; - end; - 5:begin - result:=TBESENASTNodeForStatement.Create(Instance); - TBESENASTNodeForStatement(result).Initial:=Initial; - TBESENASTNodeForStatement(result).Target:=LabelSet.Target; - ALabel.Node:=result; - Initial:=nil; - SkipToken(ltoSEMICOLON); - if CurrentToken.TokenType<>ltoSEMICOLON then begin - TBESENASTNodeForStatement(result).Condition:=ParseExpression(true); - end; - SkipToken(ltoSEMICOLON); - if CurrentToken.TokenType<>ltoCLOSEPAREN then begin - TBESENASTNodeForStatement(result).Increment:=ParseExpression(true); - end; - SkipToken(ltoCLOSEPAREN); - break; - end; - end; - end; - InForHeader:=OldInForHeader; - if assigned(result) then begin - if result is TBESENASTNodeForStatement then begin - TBESENASTNodeForStatement(result).Statement:=ParseStatement(true); - end else if result is TBESENASTNodeForInStatement then begin - TBESENASTNodeForInStatement(result).Statement:=ParseStatement(true); - end; - end else begin - result:=TBESENASTNodeEmptyStatement.Create(Instance); - end; - result.Location.LineNumber:=ln; - LabelLeave; - except - BESENFreeAndNil(Initial); - BESENFreeAndNil(Declaration); - BESENFreeAndNil(Variable); - BESENFreeAndNil(Expression); - BESENFreeAndNil(result); - raise; - end; - end; - function ParseIfStatement:TBESENASTNodeIfStatement; - begin - result:=nil; - try - result:=TBESENASTNodeIfStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkIF); - SkipToken(ltoOPENPAREN); - result.Expression:=ParseExpression(true); - SkipToken(ltoCLOSEPAREN); - result.TrueStatement:=ParseStatement(true); - if CurrentToken.TokenType=ltkELSE then begin - SkipToken(ltkELSE); - result.FalseStatement:=ParseStatement(true); - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseReturnStatement:TBESENASTNodeReturnStatement; - begin - result:=nil; - try - if not IsInFunction then begin - raise EBESENSyntaxError.Create('Return outside a function'); - end; - result:=TBESENASTNodeReturnStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkRETURN); - if not NextIsSemicolon then begin - if CurrentToken.WasLineEnd then begin - AddError('Illegal line terminator after return'); - end; - result.Expression:=ParseExpression(true); - end; - ParseOptionalSemicolon; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseThrowStatement:TBESENASTNodeThrowStatement; - begin - result:=nil; - try - result:=TBESENASTNodeThrowStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkTHROW); - if CurrentToken.WasLineEnd then begin - AddError('Illegal line terminator after throw'); - end; - result.Expression:=ParseExpression(true); - ParseOptionalSemicolon; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseTryStatement:TBESENASTNodeTryStatement; - begin - result:=nil; - try - result:=TBESENASTNodeTryStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkTRY); - - result.CatchBlock:=nil; - result.FinallyBlock:=nil; - result.CatchIdentifier:=nil; - - result.TryBlock:=ParseBlockStatement; - - if (CurrentToken.TokenType<>ltkCATCH) and (CurrentToken.TokenType<>ltkFINALLY) then begin - AddError('catch or finally expected after try'); - end; - - if CurrentToken.TokenType=ltkCATCH then begin - SkipToken(ltkCATCH); - SkipToken(ltoOPENPAREN); - result.CatchIdentifier:=ParseIdentifier(not TBESEN(Instance).IsStrict); - SkipToken(ltoCLOSEPAREN); - result.CatchBlock:=ParseBlockStatement; - end; - - if CurrentToken.TokenType=ltkFINALLY then begin - SkipToken(ltkFINALLY); - result.FinallyBlock:=ParseBlockStatement; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseSwitchStatement:TBESENASTNodeSwitchStatement; - var CaseStatements:integer; - CaseStatement:TBESENASTNodeCaseStatement; - DefaultSeen:boolean; - LabelSet:TBESENParserLabelSet; - begin - result:=nil; - try - result:=TBESENASTNodeSwitchStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkSWITCH); - - LabelSet:=LabelSetCurrent; - LabelSet.Continuable:=true; - LabelEnter('',result); - - result.Target:=LabelSet.Target; - - DefaultSeen:=false; - - SkipToken(ltoOPENPAREN); - result.Expression:=ParseExpression(true); - SkipToken(ltoCLOSEPAREN); - - CaseStatements:=0; - SkipToken(ltoOPENBRACE); - while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin - if CaseStatements>=length(result.CaseStatements) then begin - SetLength(result.CaseStatements,CaseStatements+256); - end; - result.CaseStatements[CaseStatements]:=TBESENASTNodeCaseStatement.Create(Instance); - result.CaseStatements[CaseStatements].Location.LineNumber:=Lexer.LineNumber; - CaseStatement:=result.CaseStatements[CaseStatements]; - inc(CaseStatements); - - CaseStatement.Expression:=nil; - - if CurrentToken.TokenType=ltkCASE then begin - SkipToken(ltkCASE); - CaseStatement.Expression:=ParseExpression(true); - SkipToken(ltoCOLON); - end else begin - if DefaultSeen then begin - AddError('duplication default clause in switch statement'); - end else begin - DefaultSeen:=true; - SkipToken(ltkDEFAULT); - SkipToken(ltoCOLON); - end; - end; - - CaseStatement.Statements:=ParseStatementList(true); - end; - SetLength(result.CaseStatements,CaseStatements); - - SkipToken(ltoCLOSEBRACE); - LabelLeave; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseVariableStatement:TBESENASTNodeVariableStatement; - var Count:integer; - begin - result:=nil; - try - result:=TBESENASTNodeVariableStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkVAR); - - result.Declarations:=niL; - Count:=1; - SetLength(result.Declarations,Count); - result.Declarations[0]:=ParseVariableDeclaration(true); - while (CurrentToken.TokenType=ltoCOMMA) and not Lexer.IsEOF do begin - SkipToken(ltoCOMMA); - if Count>=length(result.Declarations) then begin - SetLength(result.Declarations,Count+256); - end; - result.Declarations[Count]:=ParseVariableDeclaration(true); - inc(Count); - end; - SetLength(result.Declarations,Count); - - ParseOptionalSemicolon; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseWhileStatement:TBESENASTNodeWhileStatement; - var LabelSet:TBESENParserLabelSet; - begin - result:=nil; - try - result:=TBESENASTNodeWhileStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - LabelSet:=LabelSetCurrent; - LabelSet.Continuable:=true; - LabelEnter('',result); - result.Target:=LabelSet.Target; - SkipToken(ltkWHILE); - - SkipToken(ltoOPENPAREN); - result.Expression:=ParseExpression(true); - SkipToken(ltoCLOSEPAREN); - - result.Statement:=ParseStatement(true); - LabelLeave; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseWithStatement:TBESENASTNodeWithStatement; - begin - result:=nil; - try - if TBESEN(Instance).IsStrict then begin - AddError('WITH isn''t allowed in strict mode'); - end; - result:=TBESENASTNodeWithStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - SkipToken(ltkWITH); - - SkipToken(ltoOPENPAREN); - result.Expression:=ParseExpression(true); - SkipToken(ltoCLOSEPAREN); - - result.Statement:=ParseStatement(true); - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseExpressionStatement:TBESENASTNodeStatement; - var Expression:TBESENASTNodeExpression; - LabelSet,OldLabelSet:TBESENParserLabelSet; - ln,LabelCount:integer; - OldToken:TBESENLexerToken; - begin - ln:=Lexer.LineNumber; - result:=nil; - Expression:=nil; - try - Expression:=ParseExpression(true); - if (Expression is TBESENASTNodeIdentifier) and (CurrentToken.TokenType=ltoCOLON) then begin - SkipToken(ltoCOLON); - - result:=TBESENASTNodeLabelledStatement.Create(Instance); - result.Location.LineNumber:=ln; - - SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,1); - TBESENASTNodeLabelledStatement(result).Identifiers[0]:=TBESENASTNodeIdentifier(Expression); - - Expression:=nil; - - OldLabelSet:=CurrentLabelSet; - CurrentLabelSet:=nil; - - LabelSet:=LabelSetCurrent; - LabelSet.Continuable:=true; - - LabelCount:=1; - LabelEnter(TBESENASTNodeLabelledStatement(result).Identifiers[0].Name,result); - while true do begin - OldToken:=CurrentToken; - if CurrentToken.TokenType=lttIDENTIFIER then begin - Expression:=ParseIdentifier(true); - if assigned(Expression) and (Expression is TBESENASTNodeIdentifier) and (CurrentToken.TokenType=ltoCOLON) then begin - SkipToken(ltoCOLON); - if LabelCount>=length(TBESENASTNodeLabelledStatement(result).Identifiers) then begin - SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,LabelCount+256); - end; - TBESENASTNodeLabelledStatement(result).Identifiers[LabelCount]:=TBESENASTNodeIdentifier(Expression); - LabelEnter(TBESENASTNodeLabelledStatement(result).Identifiers[LabelCount].Name,result); - inc(LabelCount); - end else begin - if assigned(Expression) then begin - BESENFreeAndNil(Expression); - end; - Lexer.Restore(OldToken); - NextToken; - break; - end; - end else begin - break; - end; - end; - SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,LabelCount); - - TBESENASTNodeLabelledStatement(result).Target:=LabelSet.Target; - TBESENASTNodeLabelledStatement(result).Statement:=ParseStatement(not (CurrentToken.TokenType in [ltkFOR,ltkWHILE,ltkDO])); - - while LabelCount>0 do begin - dec(LabelCount); - LabelLeave; - end; - - if assigned(CurrentLabelSet) then begin - LabelSetList[CurrentLabelSet.Index]:=nil; - BESENFreeAndNil(CurrentLabelSet); - end; - CurrentLabelSet:=OldLabelSet; - - end else begin - ParseOptionalSemicolon; - result:=TBESENASTNodeExpressionStatement.Create(Instance); - result.Location.LineNumber:=ln; - TBESENASTNodeExpressionStatement(result).Expression:=Expression; - Expression:=nil; - end; - except - BESENFreeAndNil(result); - BESENFreeAndNil(Expression); - raise; - end; - end; - function ParseFunctionStatement:TBESENASTNodeStatement; - var Expression:TBESENASTNodeAssignmentExpression; - begin - result:=nil; - try - result:=TBESENASTNodeExpressionStatement.Create(Instance); - result.Location.LineNumber:=Lexer.LineNumber; - TBESENASTNodeExpressionStatement(result).Expression:=TBESENASTNodeAssignmentExpression.Create(Instance); - Expression:=TBESENASTNodeAssignmentExpression(TBESENASTNodeExpressionStatement(result).Expression); - Expression.LeftExpression:=ParseIdentifier(not TBESEN(Instance).IsStrict); - Expression.RightExpression:=ParseFunctionExpression(false,false); - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseStatement(ResetCurrentLabelSet:boolean):TBESENASTNodeStatement; - var LineNumber:integer; - OldToken:TBESENLexerToken; - begin - result:=nil; - try - if ResetCurrentLabelSet then begin - CurrentLabelSet:=nil; - end; - LineNumber:=CurrentToken.LineNumber; - case CurrentToken.TokenType of - ltoSEMICOLON:begin - SkipToken(ltoSEMICOLON); - result:=TBESENASTNodeEmptyStatement.Create(Instance); - end; - ltoOPENBRACE:begin - result:=ParseBlockStatement; - end; - ltkDEBUGGER:begin - result:=ParseDebuggerStatement; - end; - ltkBREAK:begin - result:=ParseBreakStatement; - end; - ltkCONTINUE:begin - result:=ParseContinueStatement; - end; - ltkDO:begin - result:=ParseDoStatement; - end; - ltkFOR:begin - result:=ParseForStatement; - end; - ltkIF:begin - result:=ParseIfStatement; - end; - ltkRETURN:begin - result:=ParseReturnStatement; - end; - ltkTHROW:begin - result:=ParseThrowStatement; - end; - ltkTRY:begin - result:=ParseTryStatement; - end; - ltkSWITCH:begin - result:=ParseSwitchStatement; - end; - ltkVAR:begin - result:=ParseVariableStatement; - end; - ltkWHILE:begin - result:=ParseWhileStatement; - end; - ltkWITH:begin - result:=ParseWithStatement; - end; - else begin - if CurrentToken.TokenType=ltkFUNCTION then begin - OldToken:=CurrentToken; - SkipToken(ltkFUNCTION); - if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - if CurrentToken.TokenType<>ltoOPENPAREN then begin - result:=ParseFunctionStatement; - end else begin - Lexer.Restore(OldToken); - NextToken; - result:=ParseExpressionStatement; - end; - end else begin - AddError('function keyword not allowed here'); - result:=nil; - end; - end else begin - result:=ParseExpressionStatement; - end; - end; - end; - if assigned(result) then begin - result.Location.LineNumber:=LineNumber; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseSourceElement:TBESENASTNodeStatement; - begin - result:=nil; - try - if CurrentToken.TokenType=ltkFUNCTION then begin - result:=ParseFunctionDeclaration; - end else begin - result:=ParseStatement(true); - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - procedure CheckJSON(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); - var Position:integer; - CurrentChar:TBESENUTF32CHAR; - CharEOF:boolean; - procedure NextChar; -{$ifdef BESENSingleStringType} - var Len:integer; -{$else} - var b:byte; -{$endif} - begin - if (Position>=1) and (Position<=length(Source)) then begin -{$ifdef BESENSingleStringType} -{$ifdef BESENEmbarcaderoNextGen} - CurrentChar:=Char.ConvertToUTF32(s,Position-1,Len); - inc(Position,Len); -{$else} - CurrentChar:=ord(Source[Position]); - inc(Position); - if (Position<=length(Source)) and ((SizeOf(Source[Position])=SizeOf(word)) and (((CurrentChar and $fc00)=$d800) and ((ord(Source[Position]) and $fc00)=$dc00))) then begin - // UTF16 - CurrentChar:=(((CurrentChar and $3ff) shl 10) or (ord(Source[Position]) and $3ff))+$10000; - inc(Position); - end; -{$endif} -{$else} - b:=byte(Source[Position]); - if (b and $80)=0 then begin - CurrentChar:=b; - inc(Position); - end else if ((Position+1)<=length(Source)) and ((b and $e0)=$c0) and ((byte(Source[Position+1]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $1f) shl 6) or (byte(Source[Position+1]) and $3f); - inc(Position,2); - end else if ((Position+2)<=length(Source)) and ((b and $f0)=$e0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $0f) shl 12) or ((byte(Source[Position+1]) and $3f) shl 6) or (byte(Source[Position+2]) and $3f); - inc(Position,3); - end else if ((Position+3)<=length(Source)) and ((b and $f8)=$f0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $07) shl 18) or ((byte(Source[Position+1]) and $3f) shl 12) or ((byte(Source[Position+2]) and $3f) shl 6) or (byte(Source[Position+3]) and $3f); - inc(Position,4); - end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+4)<=length(Source)) and ((b and $fc)=$f8) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $03) shl 24) or ((byte(Source[Position+1]) and $3f) shl 18) or ((byte(Source[Position+2]) and $3f) shl 12) or ((byte(Source[Position+3]) and $3f) shl 6) or (byte(Source[Position+4]) and $3f); - inc(Position,5); - end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+5)<=length(Source)) and ((b and $fe)=$fc) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) and ((byte(Source[Position+5]) and $c0)=$80) then begin - CurrentChar:=((byte(Source[Position]) and $01) shl 30) or ((byte(Source[Position+1]) and $3f) shl 24) or ((byte(Source[Position+2]) and $3f) shl 18) or ((byte(Source[Position+3]) and $3f) shl 12) or ((byte(Source[Position+4]) and $3f) shl 6) or (byte(Source[Position+5]) and $3f); - inc(Position,6); - end else begin - CurrentChar:=$fffd; - inc(Position); - end; -{$endif} - end else begin - CurrentChar:=0; - CharEOF:=true; - end; - end; - procedure JSONError; - begin - raise EBESENSyntaxError.Create('JSON.parse'); - end; - procedure SkipWhite; - begin - while (not CharEOF) and ((CurrentChar=$0009) or (CurrentChar=$000a) or (CurrentChar=$000d) or (CurrentChar=$0020)) do begin - NextChar; - end; - end; - function IsChar(c:widechar):boolean; - begin - result:=(not CharEOF) and (CurrentChar=word(c)); - end; - procedure ExpectChar(c:widechar); - begin - if IsChar(c) then begin - NextChar; - end else begin - JSONError; - end; - end; - procedure CheckValue; - procedure CheckString; - begin - if IsChar('"') then begin - NextChar; - while not (CharEOF or IsChar('"')) do begin - case CurrentChar of - $0000..$001f:begin - JSONError; - end; - ord('\'):begin - NextChar; - case CurrentChar of - ord('"'),ord('\'),ord('/'),ord('b'),ord('f'),ord('n'),ord('r'),ord('t'):begin - NextChar; - end; - ord('u'):begin - NextChar; - if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin - NextChar; - if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin - NextChar; - if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin - NextChar; - if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin - NextChar; - end else begin - JSONError; - end; - end else begin - JSONError; - end; - end else begin - JSONError; - end; - end else begin - JSONError; - end; - end; - else begin - JSONError; - end; - end; - end; - else begin - NextChar; - end; - end; - end; - ExpectChar('"'); - end else begin - JSONError; - end; - SkipWhite; - end; - procedure CheckNumber; - begin - if CharEOF then begin - JSONError; - end; - case CurrentChar of - ord('-'),ord('0')..ord('9'):begin - if IsChar('-') then begin - NextChar; - if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin - JSONError; - end; - end; - if (not CharEOF) and (CurrentChar=ord('0')) then begin - NextChar; - if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin - JSONError; - end; - end else begin - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - NextChar; - end; - end; - if IsChar('.') then begin - NextChar; - if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin - JSONError; - end; - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - NextChar; - end; - end; - if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin - NextChar; - if (not CharEOF) and ((CurrentChar=ord('-')) or (CurrentChar=ord('+'))) then begin - NextChar; - end; - if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin - JSONError; - end; - while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin - NextChar; - end; - end; - end else begin - JSONError; - end; - end; - end; - procedure CheckObjectProperty; - begin - CheckString; - SkipWhite; - ExpectChar(':'); - SkipWhite; - CheckValue; - end; - procedure CheckObject; - begin - ExpectChar('{'); - SkipWhite; - while not (CharEOF or IsChar('}')) do begin - CheckObjectProperty; - SkipWhite; - if IsChar(',') then begin - NextChar; - SkipWhite; - if (not CharEOF) and IsChar('}') then begin - JSONError; - end; - end; - end; - ExpectChar('}'); - end; - procedure CheckArray; - begin - ExpectChar('['); - SkipWhite; - while not (CharEOF or IsChar(']')) do begin - CheckValue; - SkipWhite; - if IsChar(',') then begin - NextChar; - SkipWhite; - if (not CharEOF) and IsChar(']') then begin - JSONError; - end; - end; - end; - ExpectChar(']'); - end; - procedure CheckKeyword(const Keyword:TBESENString); - var i:integer; - begin - for i:=1 to length(Keyword) do begin - ExpectChar(Keyword[i]); - end; - end; - begin - SkipWhite; - if CharEOF then begin - JSONError; - end; - case CurrentChar of - ord('{'):begin - CheckObject; - end; - ord('['):begin - CheckArray; - end; - ord('"'):begin - CheckString; - end; - ord('-'),ord('0')..ord('9'):begin - CheckNumber; - end; - ord('t'):begin - CheckKeyword('true'); - end; - ord('f'):begin - CheckKeyword('false'); - end; - ord('n'):begin - CheckKeyword('null'); - end; - else begin - JSONError; - end; - end; - end; - begin - CharEOF:=false; - Position:=1; - NextChar; - CheckValue; - SkipWhite; - if not CharEOF then begin - JSONError; - end; - end; -var Statement:TBESENASTNodeStatement; - OldIsStrict:boolean; - OldToken:TBesenLexerToken; - procedure ParseJSONStatements; - var i:integer; - begin - try - SetLength(TBESENASTNodeProgram(result).Body.Statements,0); - if not Lexer.IsEOF then begin - Statement:=ParseExpressionStatement; - if assigned(Statement) then begin - SetLength(TBESENASTNodeProgram(result).Body.Statements,1); - TBESENASTNodeProgram(result).Body.Statements[0]:=Statement; - end else begin - AddError('Fatal error'); - end; - end; - except - for i:=0 to length(TBESENASTNodeProgram(result).Body.Statements)-1 do begin - BesenFreeAndNil(TBESENASTNodeProgram(result).Body.Statements[i]); - end; - SetLength(TBESENASTNodeProgram(result).Body.Statements,0); - raise; - end; - end; - procedure ParseProgramStatements; - var IsDirectivePrologue,FirstDirective:boolean; - Statements,i:integer; - begin - Statements:=0; - try - IsDirectivePrologue:=true; - FirstDirective:=true; - UseStrictAlreadyParsed:=false; - while not Lexer.IsEOF do begin - if IsDirectivePrologue then begin - ParseDirective(IsDirectivePrologue,FirstDirective,TBESENASTNodeProgram(result).Body); - end; - Statement:=ParseSourceElement; - if assigned(Statement) then begin - if Statements>=length(TBESENASTNodeProgram(result).Body.Statements) then begin - SetLength(TBESENASTNodeProgram(result).Body.Statements,Statements+256); - end; - TBESENASTNodeProgram(result).Body.Statements[Statements]:=Statement; - inc(Statements); - end else begin - AddError('Fatal error'); - break; - end; - end; - SetLength(TBESENASTNodeProgram(result).Body.Statements,Statements); - except - for i:=0 to Statements-1 do begin - BesenFreeAndNil(TBESENASTNodeProgram(result).Body.Statements[i]); - end; - SetLength(TBESENASTNodeProgram(result).Body.Statements,0); - Statements:=0; - raise; - end; - end; -begin - Labels:=nil; - LabelSets:=nil; - CurrentLabelSet:=nil; - LabelSetList:=TBESENPointerList.Create; - LabelList:=TBESENPointerList.Create; - OldIsStrict:=TBESEN(Instance).IsStrict; - try - NextToken; - InForHeader:=false; - if IsFunction then begin - IsInFunction:=true; - try - result:=ParseFunctionExpression(true,false); - except - result:=nil; - raise; - end; - end else if IsJSON then begin - IsInFunction:=false; - result:=TBESENASTNodeProgram.Create(Instance); - try - CheckJSON(Lexer.Source); - TBESEN(Instance).IsStrict:=false; - TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; - ParseJSONStatements; - except - SetLength(TBESENASTNodeProgram(result).Body.Statements,0); - raise; - end; - end else begin - IsInFunction:=false; - result:=TBESENASTNodeProgram.Create(Instance); - try - OldToken:=CurrentToken; - TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; - try - ParseProgramStatements; - except - on e:EBESENUseStrict do begin - TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; - Lexer.Restore(OldToken); - NextToken; - ParseProgramStatements; - end; - end; - TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; - except - SetLength(TBESENASTNodeProgram(result).Body.Statements,0); - raise; - end; - end; - finally - CurrentToken.Name:=''; - CurrentToken.StringValue:=''; - CleanUpLabels; - TBESEN(Instance).IsStrict:=OldIsStrict; - BESENFreeAndNil(LabelSetList); - BESENFreeAndNil(LabelList); - end; -end; - -end. diff --git a/3rd/besen/src/BESENPointerList.pas b/3rd/besen/src/BESENPointerList.pas deleted file mode 100644 index e49fbb8e0..000000000 --- a/3rd/besen/src/BESENPointerList.pas +++ /dev/null @@ -1,230 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENPointerList; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -type PBESENPointerArray=^TBESENPointerArray; - TBESENPointerArray=array[0..(2147483647 div sizeof(pointer))-1] of pointer; - - TBESENPointerList=class - private - FList:PBESENPointerArray; - FCount,FSize:integer; - function GetItem(index:integer):pointer; - procedure SetItem(index:integer;Value:pointer); - function GetItemPointer(index:integer):pointer; - public - constructor Create; - destructor Destroy; override; - procedure Clear; - function Add(Item:pointer):integer; - procedure Insert(index:integer;Item:pointer); - procedure Delete(index:integer); - function Remove(Item:pointer):integer; - function Find(Item:pointer):integer; - function IndexOf(Item:pointer):integer; - procedure Exchange(Index1,Index2:integer); - procedure SetCapacity(NewCapacity:integer); - procedure SetCount(NewCount:integer); - property Count:integer read FCount; - property Capacity:integer read FSize write SetCapacity; - property Item[index:integer]:pointer read GetItem write SetItem; default; - property Items[index:integer]:pointer read GetItem write SetItem; - property PItems[index:integer]:pointer read GetItemPointer; - end; - -implementation - -constructor TBESENPointerList.Create; -begin - inherited Create; - FCount:=0; - FSize:=0; - FList:=nil; - Clear; -end; - -destructor TBESENPointerList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENPointerList.Clear; -begin - FCount:=0; - FSize:=0; - ReallocMem(FList,0); -end; - -procedure TBESENPointerList.SetCapacity(NewCapacity:integer); -begin - if (NewCapacity>=0) and (NewCapacity<high(TBESENPointerArray)) then begin - NewCapacity:=(NewCapacity+256) and not 255; - if FSize<>NewCapacity then begin - ReallocMem(FList,NewCapacity*sizeof(pointer)); - if FSize<NewCapacity then begin - FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(pointer),#0); - end; - FSize:=NewCapacity; - end; - end; -end; - -procedure TBESENPointerList.SetCount(NewCount:integer); -begin - if (NewCount>=0) and (NewCount<high(TBESENPointerArray)) then begin - if NewCount<FCount then begin - FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(pointer),#0); - end; - SetCapacity(NewCount); - FCount:=NewCount; - end; -end; - -function TBESENPointerList.Add(Item:pointer):integer; -begin - result:=FCount; - SetCount(result+1); - FList^[result]:=Item; -end; - -procedure TBESENPointerList.Insert(index:integer;Item:pointer); -var I:integer; -begin - if (index>=0) and (index<FCount) then begin - SetCount(FCount+1); - for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; - FList^[index]:=Item; - end else if index=FCount then begin - Add(Item); - end else if index>FCount then begin - SetCount(index); - Add(Item); - end; -end; - -procedure TBESENPointerList.Delete(index:integer); -var I,J,K:integer; -begin - if (index>=0) and (index<FCount) then begin - K:=FCount-1; - J:=index; - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - end; -end; - -function TBESENPointerList.Remove(Item:pointer):integer; -var I,J,K:integer; -begin - result:=-1; - K:=FCount; - J:=-1; - for I:=0 to K-1 do begin - if FList^[I]=Item then begin - J:=I; - break; - end; - end; - if J>=0 then begin - dec(K); - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - result:=J; - end; -end; - -function TBESENPointerList.Find(Item:pointer):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -function TBESENPointerList.IndexOf(Item:pointer):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -procedure TBESENPointerList.Exchange(Index1,Index2:integer); -var TempPointer:pointer; -begin - if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin - TempPointer:=FList^[Index1]; - FList^[Index1]:=FList^[Index2]; - FList^[Index2]:=TempPointer; - end; -end; - -function TBESENPointerList.GetItem(index:integer):pointer; -begin - if (index>=0) and (index<FCount) then begin - result:=FList^[index]; - end else begin - result:=nil; - end; -end; - -procedure TBESENPointerList.SetItem(index:integer;Value:pointer); -begin - if (index>=0) and (index<FCount) then begin - FList^[index]:=Value; - end; -end; - -function TBESENPointerList.GetItemPointer(index:integer):pointer; -begin - if (index>=0) and (index<FCount) then begin - result:=@FList^[index]; - end else begin - result:=nil; - end; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENPointerSelfBalancedTree.pas b/3rd/besen/src/BESENPointerSelfBalancedTree.pas deleted file mode 100644 index 48f1ffa4e..000000000 --- a/3rd/besen/src/BESENPointerSelfBalancedTree.pas +++ /dev/null @@ -1,630 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENPointerSelfBalancedTree; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils; - -type PBESENPointerSelfBalancedTreeValue=^TBESENPointerSelfBalancedTreeValue; - TBESENPointerSelfBalancedTreeValue=record - case boolean of - false:(i:int64); - true:(p:pointer); - end; - - PBESENPointerSelfBalancedTreeNode=^TBESENPointerSelfBalancedTreeNode; - TBESENPointerSelfBalancedTreeNode=record - Parent,Left,Right,PreviousKey,NextKey:PBESENPointerSelfBalancedTreeNode; - Level:int64; - Key:pointer; - Value:TBESENPointerSelfBalancedTreeValue; - end; - - TBESENPointerSelfBalancedTreeKeys=array of pointer; - - TBESENPointerSelfBalancedTree=class - protected - procedure Skew(OldParent:PBESENPointerSelfBalancedTreeNode); - function Split(OldParent:PBESENPointerSelfBalancedTreeNode):boolean; - procedure RebalanceAfterLeafAdd(n:PBESENPointerSelfBalancedTreeNode); - procedure DeleteNode(n:PBESENPointerSelfBalancedTreeNode); - function First(StartNode:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; - function Next(n:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; - function FindNode(const Key:pointer):PBESENPointerSelfBalancedTreeNode; - procedure ClearNode(var Node:PBESENPointerSelfBalancedTreeNode); - procedure OptimizeNode(var Node:PBESENPointerSelfBalancedTreeNode;MoreOptimize:boolean); - function GetValue(Key:pointer):TBESENPointerSelfBalancedTreeValue; - procedure SetValue(Key:pointer;Value:TBESENPointerSelfBalancedTreeValue); - public - RootNode:PBESENPointerSelfBalancedTreeNode; - FirstKey,LastKey:PBESENPointerSelfBalancedTreeNode; - constructor Create; - destructor Destroy; override; - function Find(const Key:pointer;var Value:TBESENPointerSelfBalancedTreeValue):boolean; - function Insert(const Key:pointer;Value:TBESENPointerSelfBalancedTreeValue):PBESENPointerSelfBalancedTreeNode; - procedure Remove(const Key:pointer); - procedure Optimize; - function Keys:TBESENPointerSelfBalancedTreeKeys; - property Values[Key:pointer]:TBESENPointerSelfBalancedTreeValue read GetValue write SetValue; default; - end; - -implementation - -constructor TBESENPointerSelfBalancedTree.Create; -begin - inherited Create; - new(RootNode); - fillchar(RootNode^,sizeof(TBESENPointerSelfBalancedTreeNode),#0); - RootNode^.Level:=$7fffffffffffffff; - FirstKey:=nil; - LastKey:=nil; -end; - -destructor TBESENPointerSelfBalancedTree.Destroy; -begin - ClearNode(RootNode^.Left); - dispose(RootNode); - inherited Destroy; -end; - -function TBESENPointerSelfBalancedTree.First(StartNode:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; -begin - try - if not assigned(StartNode^.Left) then begin - result:=nil; - exit; - end; - result:=StartNode; - while assigned(result^.Left) do begin - result:=result^.Left; - end; - except - result:=nil; - end; -end; - -function TBESENPointerSelfBalancedTree.Next(n:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; -begin - try - if assigned(n^.Right) then begin - result:=n^.Right; - while assigned(result^.Left) do begin - result:=result^.Left; - end; - end else begin - while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin - n:=n^.Parent; - end; - n:=n^.Parent; - if not assigned(n) then begin - result:=nil; - exit; - end; - result:=n; - end; - except - result:=nil; - end; -end; - -procedure TBESENPointerSelfBalancedTree.Skew(OldParent:PBESENPointerSelfBalancedTreeNode); -var NewParent:PBESENPointerSelfBalancedTreeNode; -begin -{$ifdef UseAssert} - Assert(assigned(OldParent)); -{$endif} - NewParent:=OldParent^.Left; -{$ifdef UseAssert} - Assert(assigned(NewParent)); -{$endif} - if OldParent^.Parent^.Left=OldParent then begin - OldParent^.Parent^.Left:=NewParent; - end else begin - OldParent^.Parent^.Right:=NewParent; - end; - NewParent^.Parent:=OldParent^.Parent; - OldParent^.Parent:=NewParent; - - OldParent^.Left:=NewParent^.Right; - if assigned(OldParent^.Left) then begin - OldParent^.Left^.Parent:=OldParent; - end; - NewParent^.Right:=OldParent; - - if assigned(OldParent^.Left) then begin - OldParent^.level:=OldParent^.Left^.level+1; - end else begin - OldParent^.level:=1; - end; -end; - -function TBESENPointerSelfBalancedTree.Split(OldParent:PBESENPointerSelfBalancedTreeNode):boolean; -var NewParent:PBESENPointerSelfBalancedTreeNode; -begin -{$ifdef UseAssert} - Assert(assigned(OldParent)); -{$endif} - NewParent:=OldParent^.Right; - if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin - if OldParent^.Parent^.Left=OldParent then begin - OldParent^.Parent^.Left:=NewParent; - end else begin - OldParent^.Parent^.Right:=NewParent; - end; - NewParent^.Parent:=OldParent^.Parent; - OldParent^.Parent:=NewParent; - - OldParent^.Right:=NewParent^.Left; - if assigned(OldParent^.Right) then begin - OldParent^.Right^.Parent:=OldParent; - end; - NewParent^.Left:=OldParent; - - NewParent^.level:=OldParent^.level+1; - - result:=true; - end else begin - result:=false; - end; -end; - -procedure TBESENPointerSelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENPointerSelfBalancedTreeNode); -begin - // n is a node that has just been inserted and is now a Leaf node. - n^.Level:=1; - n^.Left:=nil; - n^.Right:=nil; - n:=n^.Parent; - while n<>RootNode do begin - if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin - // this point the tree is correct, except (AA2) for n->Parent - Skew(n); - // We handle it (a Left add) by changing it into a Right add using Skew - // If the original add was to the Left side of a node that is on the - // Right side of a horizontal link, n now points to the rights side - // of the second horizontal link, which is correct. - // However if the original add was to the Left of node with a horizontal - // link, we must get to the Right side of the second link. - if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin - n:=n^.Parent; - end; - end; - if not Split(n^.Parent) then begin - break; - end; - n:=n^.Parent; - end; -end; - -function TBESENPointerSelfBalancedTree.FindNode(const Key:pointer):PBESENPointerSelfBalancedTreeNode; -var n:PBESENPointerSelfBalancedTreeNode; -begin - try - result:=nil; - n:=RootNode^.Left; - while assigned(n) do begin - if Key=n^.Key then begin - result:=n; - break; - end else if ptruint(Key)<ptruint(n^.Key) then begin - n:=n^.Left; - end else begin - n:=n^.Right; - end; - end; - except - result:=nil; - end; -end; - -function TBESENPointerSelfBalancedTree.Insert(const Key:pointer;Value:TBESENPointerSelfBalancedTreeValue):PBESENPointerSelfBalancedTreeNode; -var n,s:PBESENPointerSelfBalancedTreeNode; - LessThan:boolean; -begin - result:=nil; - try - n:=nil; - s:=RootNode^.Left; - while assigned(s) do begin - if Key=s^.Key then begin - n:=s; - break; - end else if ptruint(Key)<ptruint(s^.Key) then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - end; - if assigned(s) then begin - n^.Value:=Value; - end else begin - new(n); - fillchar(n^,sizeof(TBESENPointerSelfBalancedTreeNode),#0); - n^.Key:=Key; - n^.Value:=Value; - if assigned(LastKey) then begin - n^.PreviousKey:=LastKey; - LastKey^.NextKey:=n; - LastKey:=n; - end else begin - FirstKey:=n; - LastKey:=n; - end; - s:=RootNode; - LessThan:=true; - while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin - if LessThan then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - LessThan:=ptruint(Key)<ptruint(s^.Key); - end; - if LessThan then begin - s^.Left:=n; - end else begin - s^.Right:=n; - end; - n^.Parent:=s; - RebalanceAfterLeafAdd(n); - result:=n; - end; - except - result:=nil; - end; -end; - -procedure TBESENPointerSelfBalancedTree.DeleteNode(n:PBESENPointerSelfBalancedTreeNode); -var Leaf,Temp:PBESENPointerSelfBalancedTreeNode; -begin - try - // If n is not a Leaf, we first swap it out with the Leaf node that just - // precedes it. - Leaf:=n; - if assigned(n^.Left) then begin - Leaf:=n^.Left; - while assigned(Leaf^.Right) do begin - Leaf:=Leaf^.Right; - end; - end else if assigned(n^.Right) then begin - Leaf:=n^.Right; - end; - - if Leaf^.Parent=n then begin - Temp:=Leaf; - end else begin - Temp:=Leaf^.Parent; - end; - if Leaf^.Parent^.Left=Leaf then begin - Leaf^.Parent^.Left:=nil; - end else begin - Leaf^.Parent^.Right:=nil; - end; - - if n<>Leaf then begin - if n^.Parent^.Left=n then begin - n^.Parent^.Left:=Leaf; - end else begin - n^.Parent^.Right:=Leaf; - end; - Leaf^.Parent:=n^.Parent; - if assigned(n^.Left) then begin - n^.Left^.Parent:=Leaf; - end; - Leaf^.Left:=n^.Left; - if assigned(n^.Right) then begin - n^.Right^.Parent:=Leaf; - end; - Leaf^.Right:=n^.Right; - Leaf^.level:=n^.level; - end; - if n<>RootNode then begin - n^.Key:=nil; - if assigned(n^.PreviousKey) then begin - n^.PreviousKey^.NextKey:=n^.NextKey; - end else if FirstKey=n then begin - FirstKey:=n^.NextKey; - end; - if assigned(n^.NextKey) then begin - n^.NextKey^.PreviousKey:=n^.PreviousKey; - end else if LastKey=n then begin - LastKey:=n^.PreviousKey; - end; - dispose(n); - end; - - while Temp<>RootNode do begin - if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin - dec(Temp^.level); - if Split(Temp) then begin - if Split(Temp) then begin - Skew(Temp^.Parent^.Parent); - end; - break; - end; - Temp:=Temp^.Parent; - end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin - break; - end else begin - Skew(Temp); - { if assigned(Temp^.Right) then begin - if assigned(Temp^.Right^.Left) then begin - Temp^.Right^.level:=Temp^.Right^.level+1; - end else begin - Temp^.Right^.level:=1; - end; - end;} - if Temp^.level>Temp^.Parent^.level then begin - Skew(Temp); - Split(Temp^.Parent^.Parent); - break; - end; - Temp:=Temp^.Parent^.Parent; - end; - end; - except - end; -end; - -procedure TBESENPointerSelfBalancedTree.Remove(const Key:pointer); -var n:PBESENPointerSelfBalancedTreeNode; -begin - try - n:=RootNode^.Left; - while assigned(n) do begin - if Key=n^.Key then begin - DeleteNode(n); - break; - end else if ptruint(Key)<ptruint(n^.Key) then begin - n:=n^.Left; - end else begin - n:=n^.Right; - end; - end; - except - end; -end; - -procedure TBESENPointerSelfBalancedTree.ClearNode(var Node:PBESENPointerSelfBalancedTreeNode); -begin - if not assigned(Node) then begin - exit; - end; - Node^.Key:=nil; - if assigned(Node^.PreviousKey) then begin - Node^.PreviousKey^.NextKey:=Node^.NextKey; - end else if FirstKey=Node then begin - FirstKey:=Node^.NextKey; - end; - if assigned(Node^.NextKey) then begin - Node^.NextKey^.PreviousKey:=Node^.PreviousKey; - end else if LastKey=Node then begin - LastKey:=Node^.PreviousKey; - end; - ClearNode(Node^.Left); - ClearNode(Node^.Right); - dispose(Node); - Node:=nil; -end; - -procedure TBESENPointerSelfBalancedTree.OptimizeNode(var Node:PBESENPointerSelfBalancedTreeNode;MoreOptimize:boolean); -var Nodes:array of TBESENPointerSelfBalancedTreeNode; - NodeCount,NodeIndex:integer; - procedure CountNodes(Node:PBESENPointerSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - CountNodes(Node^.Left); - CountNodes(Node^.Right); - inc(NodeCount); - end; - procedure CollectNodes(Node:PBESENPointerSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - CollectNodes(Node^.Left); - if NodeIndex>=length(Nodes) then begin - NodeCount:=NodeIndex+1; - SetLength(Nodes,NodeCount); - end; - Nodes[NodeIndex]:=Node^; - inc(NodeIndex); - CollectNodes(Node^.Right); - end; - procedure FreeNodes(var Node:PBESENPointerSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - Node^.Key:=nil; - if assigned(Node^.PreviousKey) then begin - Node^.PreviousKey^.NextKey:=Node^.NextKey; - end; - if assigned(Node^.NextKey) then begin - Node^.NextKey^.PreviousKey:=Node^.PreviousKey; - end; - if FirstKey=Node then begin - FirstKey:=Node^.NextKey; - end; - if LastKey=Node then begin - LastKey:=Node^.PreviousKey; - end; - CountNodes(Node^.Left); - CountNodes(Node^.Right); - dispose(Node); - Node:=nil; - end; - procedure DoInsertNode(const Node:TBESENPointerSelfBalancedTreeNode); - var n,s:PBESENPointerSelfBalancedTreeNode; - LessThan:boolean; - begin - new(n); - n^:=Node; - n^.Parent:=nil; - n^.Left:=nil; - n^.Right:=nil; - n^.Level:=0; - s:=RootNode; - LessThan:=true; - while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin - if LessThan then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - LessThan:=ptruint(n^.Key)<ptruint(s^.Key); - end; - if LessThan then begin - s^.Left:=n; - end else begin - s^.Right:=n; - end; - n^.Parent:=s; - if assigned(LastKey) then begin - n^.PreviousKey:=LastKey; - LastKey^.NextKey:=n; - LastKey:=n; - end else begin - FirstKey:=n; - LastKey:=n; - end; - if not MoreOptimize then begin - RebalanceAfterLeafAdd(n); - end; - end; - procedure RepairNodes(var Node:PBESENPointerSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - RepairNodes(Node^.Left); - RepairNodes(Node^.Right); - if assigned(Node^.Left) and assigned(Node^.Right) then begin - Node^.Level:=Node^.Left^.Level+1; - end else begin - Node^.Level:=1; - end; - end; - procedure ReinsertNodesForRepair(LowNode,HighNode:integer); - var MiddleNode:integer; - begin - if HighNode<LowNode then begin - exit; - end; - MiddleNode:=LowNode+((HighNode-LowNode) div 2); - DoInsertNode(Nodes[MiddleNode]); - ReinsertNodesForRepair(LowNode,MiddleNode-1); - ReinsertNodesForRepair(MiddleNode+1,HighNode); - end; - procedure ReinsertNodes(LowNode,HighNode:integer); - var i:integer; - begin - for i:=LowNode to HighNode do begin - DoInsertNode(Nodes[i]); - end; - end; -begin - if not assigned(Node) then begin - exit; - end; - try - Nodes:=nil; - NodeCount:=0; - CountNodes(Node); - SetLength(Nodes,NodeCount); - NodeIndex:=0; - CollectNodes(Node); - FreeNodes(Node); - if MoreOptimize then begin - ReinsertNodesForRepair(0,length(Nodes)-1); - RepairNodes(RootNode^.Left); - end else begin - ReinsertNodes(0,length(Nodes)-1); - end; - SetLength(Nodes,0); - except - end; -end; - -function TBESENPointerSelfBalancedTree.Find(const Key:pointer;var Value:TBESENPointerSelfBalancedTreeValue):boolean; -var n:PBESENPointerSelfBalancedTreeNode; -begin - n:=FindNode(Key); - if assigned(n) then begin - Value:=n^.Value; - result:=true; - end else begin - fillchar(Value,sizeof(TBESENPointerSelfBalancedTreeValue),#0); - result:=false; - end; -end; - -procedure TBESENPointerSelfBalancedTree.Optimize; -begin - OptimizeNode(RootNode^.Left,true); -end; - -function TBESENPointerSelfBalancedTree.Keys:TBESENPointerSelfBalancedTreeKeys; -var CurrentNode:PBESENPointerSelfBalancedTreeNode; - Count:integer; -begin - result:=nil; - Count:=0; - CurrentNode:=FirstKey; - while assigned(CurrentNode) do begin - inc(Count); - CurrentNode:=CurrentNode^.NextKey; - end; - SetLength(result,Count); - Count:=0; - CurrentNode:=FirstKey; - while assigned(CurrentNode) do begin - result[Count]:=CurrentNode^.Key; - inc(Count); - CurrentNode:=CurrentNode^.NextKey; - end; -end; - -function TBESENPointerSelfBalancedTree.GetValue(Key:pointer):TBESENPointerSelfBalancedTreeValue; -begin - Find(Key,result); -end; - -procedure TBESENPointerSelfBalancedTree.SetValue(Key:pointer;Value:TBESENPointerSelfBalancedTreeValue); -begin - Insert(Key,Value); -end; - -end. diff --git a/3rd/besen/src/BESENRandomGenerator.pas b/3rd/besen/src/BESENRandomGenerator.pas deleted file mode 100644 index 23d455539..000000000 --- a/3rd/besen/src/BESENRandomGenerator.pas +++ /dev/null @@ -1,274 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENRandomGenerator; -{$i BESEN.inc} - -interface - -uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, - UnixType,{$endif}SysUtils,Classes,Math,BESENConstants,BESENTypes, - BESENObject,BESENValue,BESENCollectorObject; - -type TBESENRandomGeneratorTable=array[0..BESEN_CMWCRND_SIZE-1] of longword; - - TBESENRandomGenerator=class(TBESENCollectorObject) - public - Table:TBESENRandomGeneratorTable; - Position:longword; - Carry:longword; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Reinitialize; - function Get:longword; - function GetNumber:TBESENNumber; - end; - -implementation - -uses BESEN; - -constructor TBESENRandomGenerator.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Reinitialize; -end; - -destructor TBESENRandomGenerator.Destroy; -begin - inherited Destroy; -end; - -{$ifdef win32} -type HCRYPTPROV=DWORD; - -const PROV_RSA_FULL=1; - CRYPT_VERIFYCONTEXT=$F0000000; - -function CryptAcquireContext(var phProv:HCRYPTPROV;pszContainer:PAnsiChar;pszProvider:PAnsiChar;dwProvType:DWORD; dwFlags:DWORD):BOOL; stdcall; external advapi32 name 'CryptAcquireContextA'; -function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL; stdcall; external advapi32 name 'CryptReleaseContext'; -function CryptGenRandom(hProv: HCRYPTPROV; dwLen: DWORD; pbBuffer: Pointer): BOOL; stdcall; external advapi32 name 'CryptGenRandom'; - -function CoCreateGuid(var guid: TGUID): HResult; stdcall; external 'ole32.dll'; -{$endif} - -procedure TBESENRandomGenerator.Reinitialize; -const N=25; - m=7; - s=7; - t=15; - a=longword($8ebfd028); - b=longword($2b5b2500); - c=longword($db8b0000); -var LRG,LFSR,k,y,Seed1,Seed2:longword; - i,j:integer; - x:array[0..N-1] of longword; - UnixTimeInMilliSeconds:int64; -{$ifdef unix} - f:file of longword; - ura,urb:longword; -{$else} -{$ifdef win32} - lpc,lpf:int64; - pp,p:pwidechar; - st:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; -{$endif} -{$endif} -{$ifdef win32} - function GenerateRandomBytes(var Buffer;Bytes:Cardinal):boolean; - var CryptProv:HCRYPTPROV; - begin - try - if not CryptAcquireContext(CryptProv,nil,nil,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT) then begin - result:=false; - exit; - end; - FillChar(Buffer,Bytes,#0); - result:=CryptGenRandom(CryptProv,Bytes,@Buffer); - CryptReleaseContext(CryptProv,0); - except - result:=false; - end; - end; - function GetRandomGUIDGarbage:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; - var g:TGUID; - begin - CoCreateGUID(g); - SetLength(result,sizeof(TGUID)); - move(g,result[1],sizeof(TGUID)); - end; -{$endif} -begin - UnixTimeInMilliSeconds:=round((SysUtils.Now-25569.0)*86400000.0); - Seed1:=longword(UnixTimeInMilliSeconds and $ffffffff)+longword(UnixTimeInMilliSeconds shr 32); - Seed2:=longword(UnixTimeInMilliSeconds shr 32) xor not longword(UnixTimeInMilliSeconds and $ffffffff); -{$ifdef unix} - ura:=0; - urb:=0; - AssignFile(f,'/dev/urandom'); - {$i-}System.reset(f,1);{$i+} - if ioresult=0 then begin - System.read(f,ura); - System.read(f,urb); - CloseFile(f); - end else begin - AssignFile(f,'/dev/random'); - {$i-}System.reset(f,1);{$i+} - if ioresult=0 then begin - System.read(f,ura); - System.read(f,urb); - CloseFile(f); - end; - end; - Seed1:=Seed1 xor ura; - Seed2:=Seed2 xor urb; -{$else} -{$ifdef win32} - QueryPerformanceCounter(lpc); - QueryPerformanceFrequency(lpf); - inc(Seed1,timeGetTime+GetCurrentProcessId); - dec(Seed2,GetTickCount-GetCurrentThreadId); - inc(Seed1,paramcount); - Seed1:=Seed1 xor (lpc shr 32); - Seed2:=Seed2 xor lpc; - Seed1:=(Seed1*lpc)+(Seed2*(lpf-Seed1)); - Seed2:=(Seed2*lpc)+(Seed1*(lpf-Seed2)); - pp:=GetEnvironmentStringsW; - if assigned(pp) then begin - p:=pp; - while assigned(p) and (p^<>#0) do begin - while assigned(p) and (p^<>#0) do begin - inc(Seed1,(Seed2*word(p^))); - Seed1:=(Seed1*1664525)+1013904223; - Seed2:=Seed2 xor (Seed1*word(p^)); - Seed2:=Seed2 xor (Seed2 shl 13); - Seed2:=Seed2 xor (Seed2 shr 17); - Seed2:=Seed2 xor (Seed2 shl 5); - inc(p); - end; - inc(p); - end; - FreeEnvironmentStringsW(pointer(pp)); - end; - pp:=pointer(GetCommandLineW); - if assigned(pp) then begin - p:=pp; - while assigned(p) and (p^<>#0) do begin - inc(Seed1,(Seed2*word(p^))); - Seed1:=(Seed1*1664525)+1013904223; - Seed2:=Seed2 xor (Seed1*word(p^)); - Seed2:=Seed2 xor (Seed2 shl 13); - Seed2:=Seed2 xor (Seed2 shr 17); - Seed2:=Seed2 xor (Seed2 shl 5); - inc(p); - end; - end; - SetLength(st,4096); - if GenerateRandomBytes(st[1],length(st)) then begin - for i:=1 to length(st) do begin - inc(Seed1,(Seed2*byte(st[i]))); - Seed1:=(Seed1*1664525)+1013904223; - Seed2:=Seed2 xor (Seed1*byte(st[i])); - Seed2:=Seed2 xor (Seed2 shl 13); - Seed2:=Seed2 xor (Seed2 shr 17); - Seed2:=Seed2 xor (Seed2 shl 5); - end; - end; - st:=GetRandomGUIDGarbage; - for i:=1 to length(st) do begin - inc(Seed1,(Seed2*byte(st[i]))); - Seed1:=(Seed1*1664525)+1013904223; - Seed2:=Seed2 xor (Seed1*byte(st[i])); - Seed2:=Seed2 xor (Seed2 shl 13); - Seed2:=Seed2 xor (Seed2 shr 17); - Seed2:=Seed2 xor (Seed2 shl 5); - end; - SetLength(st,0); -{$endif} -{$endif} - LRG:=not Seed1; - LFSR:=Seed2; - for i:=0 to N-1 do begin - LRG:=(LRG*1664525)+1013904223; - LFSR:=LFSR xor (LFSR shl 13); - LFSR:=LFSR xor (LFSR shr 17); - LFSR:=LFSR xor (LFSR shl 5); - x[i]:=LRG xor not LFSR; - end; - k:=N-1; - LRG:=Seed1; - LFSR:=not Seed2; - for i:=0 to BESEN_CMWCRND_MASK do begin - LRG:=(LRG*1664525)+1013904223; - LFSR:=LFSR xor (LFSR shl 13); - LFSR:=LFSR xor (LFSR shr 17); - LFSR:=LFSR xor (LFSR shl 5); - inc(k); - if k>=N then begin - for j:=0 to (N-m)-1 do begin - x[j]:=x[j+m] xor (x[j] shr 1) xor ((x[j] and 1)*a); - end; - for j:=(N-m) to N-1 do begin - x[j]:=x[j+m-N] xor (x[j] shr 1) xor ((x[j] and 1)*a); - end; - k:=0; - end; - y:=x[k] xor ((x[k] shl s) and b); - y:=y xor ((y shl t) and c); - Table[i]:=(LRG+LFSR) xor y; - end; - Position:=(x[LFSR and $f] xor Table[LRG and BESEN_CMWCRND_MASK]) and BESEN_CMWCRND_MASK; -end; - -function TBESENRandomGenerator.Get:longword; -var t:{$ifdef fpc}qword{$else}int64{$endif}; - x:longword; -begin - Position:=(Position+1) and BESEN_CMWCRND_MASK; - t:=(BESEN_CMWCRND_A*Table[Position])+Carry; - Carry:=t shr 32; - x:=t+Carry; - if x<Carry then begin - inc(x); - inc(Carry); - end; - result:=BESEN_CMWCRND_M-x; - Table[Position]:=result; -end; - -function TBESENRandomGenerator.GetNumber:TBESENNumber; -const f:TBESENNumber=1.0/int64($100000000); -var i:int64; -begin - i:=Get; - result:=i*f; -end; - -end. diff --git a/3rd/besen/src/BESENRegExp.pas b/3rd/besen/src/BESENRegExp.pas deleted file mode 100644 index 175394068..000000000 --- a/3rd/besen/src/BESENRegExp.pas +++ /dev/null @@ -1,2550 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENRegExp; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENCollectorObject; - -const breoFAIL=0; // match failed - breoSUCCEED=1; // match succeeded - breoCHAR=2; // match a char class instance - breoZERO=3; // reset counter - breoREACH=4; // test counter over - breoNREACH=5; // test counter under - breoSTART=6; // enter a group - breoEND=7; // exit a group - breoUNDEF=8; // reset a group - breoMARK=9; // record a position - breoFDIST=10; // position test - breoRDIST=11; // position and counter test - breoMNEXT=12; // max-loop - breoRNEXT=13; // reach-loop - breoGOTO=14; // Branch - breoGS=15; // greeedy success - breoNS=16; // non-greeedy success - breoGF=17; // greedy fail - breoNF=18; // non-greeedy fail - breoAS=19; // assert success - breoAF=20; // assert fail - breoBOL=21; // test begin of a line - breoEOL=22; // test end of a line - breoBRK=23; // test work-break - breoNBRK=24; // test non-work-break - breoBACKREF=25; // backreference match - - brecUNDEFINED=longword($ffffffff); - brecINFINITY=-1; - - bresADDR=2; - bresINT=2; - - breMAXSTATESHOLDINMEMORY:longint=16; - - BESENRegExpCacheSize:longint=256; - -type TBESENRegExpOpcode=byte; - - TBESENRegExpFlag=(brefGLOBAL,brefIGNORECASE,brefMULTILINE); - - TBESENRegExpFlags=set of TBESENRegExpFlag; - - TBESENRegExpCharClass=class; - - TBESENRegExpCharClassRange=class - public - CharClass:TBESENRegExpCharClass; - Previous,Next:TBESENRegExpCharClassRange; - Lo,Hi:TBESENUTF32CHAR; - constructor Create(ACharClass:TBESENRegExpCharClass;ALo,AHi:TBESENUTF32CHAR); - constructor CreateBefore(ACharClass:TBESENRegExpCharClass;ABefore:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); - constructor CreateAfter(ACharClass:TBESENRegExpCharClass;AAfter:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); - destructor Destroy; override; - end; - - TBESENRegExp=class; - - TBESENRegExpCharClass=class - public - RegExp:TBESENRegExp; - Previous,Next:TBESENRegExpCharClass; - First,Last:TBESENRegExpCharClassRange; - Inverted:longbool; - Canonicalized:longbool; - constructor Create(ARegExp:TBESENRegExp); - destructor Destroy; override; - procedure Clear; - procedure Dump; - procedure DebugDump; - procedure Optimize; - procedure AddRange(Lo,Hi:TBESENUTF32CHAR;IgnoreCase:boolean=false); - procedure AddChar(c:TBESENUTF32CHAR;IgnoreCase:boolean=false); - procedure TakeoverCombine(From:TBESENRegExpCharClass); - procedure Assign(From:TBESENRegExpCharClass); - procedure Append(From:TBESENRegExpCharClass); - procedure Invert; - procedure Canonicalize; - function Count:longword; - function Contains(c:TBESENUTF32CHAR):boolean; - function IsSingle:boolean; - end; - - TBESENRegExpCharClasses=array of TBESENRegExpCharClass; - - TBESENRegExpCapture=record - s,e:longword; - end; - - TBESENRegExpCaptures=array of TBESENRegExpCapture; - - TBESENRegExpValue=longint; - - TBESENRegExpValues=array of TBESENRegExpValue; - - TBESENRegExpState=class - public - RegExp:TBESENRegExp; - Previous,Next:TBESENRegExpState; - Captures:TBESENRegExpCaptures; - Counters:TBESENRegExpValues; - Marks:TBESENRegExpValues; - constructor Create(ARegExp:TBESENRegExp); - destructor Destroy; override; - end; - - TBESENRegExp=class(TBESENCollectorObject) - private - FirstCharClass,LastCharClass:TBESENRegExpCharClass; - FirstState,LastState,CurrentState:TBESENRegExpState; - CountStates:longint; - function InternCharClass(c:TBESENRegExpCharClass):longint; - function CodePos:longint; - procedure CodePosSet(p:longint); - procedure CodeAdd(c:longint); - procedure CodePatch(p,c:longint); - procedure CodeInsert(p,n:longint); - procedure CodeAddI(c:longint); - procedure CodeAddA(c:longint); - procedure CodePatchI(p,c:longint); - procedure CodePatchA(p,c:longint); - function AllocateState:TBESENRegExpState; - procedure CleanupStates; - procedure CopyState(const a,b:TBESENRegExpState); - function DisassembleOpcode(PC:longint):TBESENString; - procedure DebugDisassemble; - function Execute(PC:longint;const Input:TBESENString;var State:TBESENRegExpState;var RemainTimeOutSteps:int64):boolean; - public - Source:TBESENString; - ByteCode:TBESENBytes; - ByteCodeLen:longint; - Flags:TBESENRegExpFlags; - CountOfCaptures:longint; - CountOfCounters:longint; - CountOfMarks:longint; - MaxRef:longint; - CharClasses:TBESENRegExpCharClasses; - CharClassesCount:longint; - ReferenceCounter:longint; - constructor Create(AInstance:TObject); override; - destructor Destroy; override; - procedure IncRef; - procedure DecRef; - procedure Compile(const ASource:TBESENString;const AFlags:TBESENRegExpFlags=[]); - function Match(const Input:TBESENString;Index:longint;var Captures:TBESENRegExpCaptures):boolean; - function Disassemble:TBESENString; - procedure DebugDump; - end; - -implementation - -uses BESEN,BESENUtils,BESENStringUtils,BESENErrors; - -type TBESENUTF8ORSINGLESTRING={$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; - -constructor TBESENRegExpCharClassRange.Create(ACharClass:TBESENRegExpCharClass;ALo,AHi:TBESENUTF32CHAR); -begin - inherited Create; - CharClass:=ACharClass; - Lo:=ALo; - Hi:=AHi; - if assigned(CharClass.Last) then begin - Previous:=CharClass.Last; - CharClass.Last:=self; - Previous.Next:=self; - Next:=nil; - end else begin - CharClass.First:=self; - CharClass.Last:=self; - Previous:=nil; - Next:=nil; - end; -end; - -constructor TBESENRegExpCharClassRange.CreateBefore(ACharClass:TBESENRegExpCharClass;ABefore:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); -begin - inherited Create; - CharClass:=ACharClass; - Lo:=ALo; - Hi:=AHi; - Previous:=ABefore.Previous; - Next:=ABefore; - ABefore.Previous:=self; - if assigned(Previous) then begin - Previous.Next:=self; - end else begin - CharClass.First:=self; - end; -end; - -constructor TBESENRegExpCharClassRange.CreateAfter(ACharClass:TBESENRegExpCharClass;AAfter:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); -begin - inherited Create; - CharClass:=ACharClass; - Lo:=ALo; - Hi:=AHi; - Previous:=AAfter; - Next:=AAfter.Next; - AAfter.Next:=self; - if assigned(Next) then begin - Next.Previous:=self; - end else begin - CharClass.Last:=self; - end; -end; - -destructor TBESENRegExpCharClassRange.Destroy; -begin - if assigned(Previous) then begin - Previous.Next:=Next; - end else if CharClass.First=self then begin - CharClass.First:=Next; - end; - if assigned(Next) then begin - Next.Previous:=Previous; - end else if CharClass.Last=self then begin - CharClass.Last:=Previous; - end; - Previous:=nil; - Next:=nil; - inherited Destroy; -end; - -constructor TBESENRegExpCharClass.Create(ARegExp:TBESENRegExp); -begin - inherited Create; - RegExp:=ARegExp; - if assigned(RegExp.LastCharClass) then begin - Previous:=RegExp.LastCharClass; - RegExp.LastCharClass:=self; - Previous.Next:=self; - Next:=nil; - end else begin - RegExp.FirstCharClass:=self; - RegExp.LastCharClass:=self; - Previous:=nil; - Next:=nil; - end; - First:=nil; - Last:=nil; - Inverted:=false; - Canonicalized:=false; -end; - -destructor TBESENRegExpCharClass.Destroy; -begin - while assigned(First) do begin - First.Free; - end; - if assigned(Previous) then begin - Previous.Next:=Next; - end else if RegExp.FirstCharClass=self then begin - RegExp.FirstCharClass:=Next; - end; - if assigned(Next) then begin - Next.Previous:=Previous; - end else if RegExp.LastCharClass=self then begin - RegExp.LastCharClass:=Previous; - end; - Previous:=nil; - Next:=nil; - inherited Destroy; -end; - -procedure TBESENRegExpCharClass.Clear; -begin - while assigned(First) do begin - First.Free; - end; - Inverted:=false; - Canonicalized:=false; -end; - -procedure TBESENRegExpCharClass.Dump; -var Range:TBESENRegExpCharClassRange; -begin - Range:=First; - while assigned(Range) do begin - writeln(Range.Lo:8,' ',Range.Hi:8); - Range:=Range.Next; - end; -end; - -procedure TBESENRegExpCharClass.DebugDump; -var Range:TBESENRegExpCharClassRange; -begin - Range:=First; - while assigned(Range) do begin - if assigned(TBESEN(RegExp.Instance).RegExpDebugOutputHook) then begin - TBESEN(RegExp.Instance).RegExpDebugOutputHook(TBESEN(RegExp.Instance),'[0x'+TBESENUTF8ORSINGLESTRING(IntToHex(Range.Lo,8))+',0x'+TBESENUTF8ORSINGLESTRING(IntToHex(Range.Hi,8))+']',true); - end; - Range:=Range.Next; - end; -end; - -procedure TBESENRegExpCharClass.Optimize; -var Range:TBESENRegExpCharClassRange; -begin - Range:=First; - while assigned(Range) do begin - if assigned(Range.Previous) and (((Range.Previous.Hi>=Range.Lo) or ((Range.Previous.Hi+1)=Range.Lo))) then begin - if Range.Lo>Range.Previous.Lo then begin - Range.Lo:=Range.Previous.Lo; - end; - if Range.Hi<Range.Previous.Hi then begin - Range.Hi:=Range.Previous.Hi; - end; - Range.Previous.Free; - if assigned(Range.Previous) then begin - Range:=Range.Previous; - end; - end else if assigned(Range.Next) and (((Range.Hi>=Range.Next.Lo) or ((Range.Hi+1)=Range.Next.Lo))) then begin - if Range.Lo>Range.Next.Lo then begin - Range.Lo:=Range.Next.Lo; - end; - if Range.Hi<Range.Next.Hi then begin - Range.Hi:=Range.Next.Hi; - end; - Range.Next.Free; - if assigned(Range.Previous) then begin - Range:=Range.Previous; - end; - end else begin - Range:=Range.Next; - end; - end; -end; - -procedure TBESENRegExpCharClass.AddRange(Lo,Hi:TBESENUTF32CHAR;IgnoreCase:boolean=false); -var Range:TBESENRegExpCharClassRange; - c,cl,cu:TBESENUTF32CHAR; - NeedToCanonicalize:boolean; -begin - if IgnoreCase then begin - NeedToCanonicalize:=false; - for c:=Lo to Hi do begin - cl:=BESENUnicodeToLower(c); - cu:=BESENUnicodeToUpper(c); - if (cl<>cu) or (cl<>c) or (cu<>c) then begin - NeedToCanonicalize:=true; - break; - end; - end; - if NeedToCanonicalize then begin - for c:=Lo to Hi do begin - cl:=BESENUnicodeToLower(c); - cu:=BESENUnicodeToUpper(c); - if (cl=cu) and (cl=c) then begin - AddRange(c,c,false); - end else begin - AddRange(cl,cl,false); - AddRange(cu,cu,false); - if (cl<>c) and (cu<>c) then begin - AddRange(c,c,false); - end; - end; - end; - end else begin - AddRange(Lo,Hi,false); - end; - end else begin - Range:=First; - while assigned(Range) do begin - if (Lo>=Range.Lo) and (Hi<=Range.Hi) then begin - exit; - end else if (Lo<=Range.Lo) or ((Lo=Range.Lo) and (Hi<=Range.Hi)) then begin - break; - end; - Range:=Range.Next; - end; - if assigned(Range) then begin - TBESENRegExpCharClassRange.CreateBefore(self,Range,Lo,Hi); - end else begin - TBESENRegExpCharClassRange.Create(self,Lo,Hi); - end; - Optimize; - end; -end; - -procedure TBESENRegExpCharClass.AddChar(c:TBESENUTF32CHAR;IgnoreCase:boolean=false); -begin - AddRange(c,c,IgnoreCase); -end; - -procedure TBESENRegExpCharClass.TakeoverCombine(From:TBESENRegExpCharClass); -var Range:TBESENRegExpCharClassRange; -begin - if assigned(From) then begin - if assigned(First) then begin - Canonicalized:=Canonicalized and From.Canonicalized; - end else begin - Canonicalized:=From.Canonicalized; - end; - Range:=From.First; - while assigned(Range) do begin - Range.CharClass:=self; - Range:=Range.Next; - end; - if assigned(Last) then begin - Last.Next:=From.First; - From.First.Previous:=Last; - Last:=From.Last; - end else begin - First:=From.First; - Last:=From.Last; - end; - From.First:=nil; - From.Last:=nil; - end; -end; - -procedure TBESENRegExpCharClass.Assign(From:TBESENRegExpCharClass); -var Range:TBESENRegExpCharClassRange; -begin - if assigned(From) then begin - while assigned(First) do begin - First.Free; - end; - Inverted:=From.Inverted; - Canonicalized:=From.Canonicalized; - Range:=From.First; - while assigned(Range) do begin - Range.CharClass:=self; - Range:=Range.Next; - end; - First:=From.First; - Last:=From.Last; - From.First:=nil; - From.Last:=nil; - end; -end; - -procedure TBESENRegExpCharClass.Append(From:TBESENRegExpCharClass); -var Range:TBESENRegExpCharClassRange; -begin - if assigned(From) then begin - Range:=From.First; - while assigned(Range) do begin - TBESENRegExpCharClassRange.Create(self,Range.Lo,Range.Hi); - Range:=Range.Next; - end; - end; -end; - -procedure TBESENRegExpCharClass.Invert; -var NewList:TBESENRegExpCharClass; - Range:TBESENRegExpCharClassRange; - Lo,Hi:TBESENUTF32CHAR; -begin - Optimize; - Inverted:=not Inverted; - if assigned(First) and (First=Last) and (First.Lo=0) and (First.Hi=$ffffffff) then begin - First.Free; - end else if not assigned(First) then begin - TBESENRegExpCharClassRange.Create(self,0,$ffffffff); - end else begin - NewList:=TBESENRegExpCharClass.Create(RegExp); - try - Range:=First; - if Range.Lo>0 then begin - TBESENRegExpCharClassRange.Create(NewList,0,Range.Lo-1); - end; - Lo:=Range.Hi; - Range:=Range.Next; - while assigned(Range) do begin - if (Lo+1)<Range.Lo then begin - Hi:=Range.Lo; - TBESENRegExpCharClassRange.Create(NewList,Lo+1,Hi-1); - end; - Lo:=Range.Hi; - Range:=Range.Next; - end; - if Lo<>$ffffffff then begin - TBESENRegExpCharClassRange.Create(NewList,Lo+1,$ffffffff); - end; - while assigned(First) do begin - First.Free; - end; - Range:=NewList.First; - while assigned(Range) do begin - Range.CharClass:=self; - Range:=Range.Next; - end; - First:=NewList.First; - Last:=NewList.Last; - NewList.First:=nil; - NewList.Last:=nil; - Range:=First; - while assigned(Range) do begin - Range.CharClass:=self; - Range:=Range.Next; - end; - finally - NewList.Free; - end; - end; -end; - -procedure TBESENRegExpCharClass.Canonicalize; -var NewList:TBESENRegExpCharClass; - Range:TBESENRegExpCharClassRange; - OldInverted:boolean; -begin - if not Canonicalized then begin - NewList:=TBESENRegExpCharClass.Create(RegExp); - try - OldInverted:=Inverted; - if Inverted then begin - Invert; - end; - Range:=First; - while assigned(Range) do begin - NewList.AddRange(Range.Lo,Range.Hi,true); - Range:=Range.Next; - end; - while assigned(First) do begin - First.Free; - end; - First:=NewList.First; - Last:=NewList.Last; - NewList.First:=nil; - NewList.Last:=nil; - Range:=First; - while assigned(Range) do begin - Range.CharClass:=self; - Range:=Range.Next; - end; - if OldInverted then begin - Invert; - end; - Inverted:=OldInverted; - finally - NewList.Free; - end; - Canonicalized:=true; - end; -end; - -function TBESENRegExpCharClass.Count:longword; -var Range:TBESENRegExpCharClassRange; -begin - result:=0; - Range:=First; - while assigned(Range) do begin - inc(result,(Range.Hi-Range.Lo)+1); - Range:=Range.Next; - end; -end; - -function TBESENRegExpCharClass.Contains(c:TBESENUTF32CHAR):boolean; -var Range:TBESENRegExpCharClassRange; -begin - result:=false; - Range:=First; - while assigned(Range) do begin - if (c>=Range.Lo) and (c<=Range.Hi) then begin - result:=true; - break; - end; - Range:=Range.Next; - end; -end; - -function TBESENRegExpCharClass.IsSingle:boolean; -begin - result:=(First=Last) and ((assigned(First) and (First.Lo=First.Hi)) or not assigned(First)); -end; - -function CompareCharClasses(c1,c2:TBESENRegExpCharClass):longint; -var r1,r2:TBESENRegExpCharClassRange; -begin - r1:=c1.First; - r2:=c2.First; - while assigned(r1) and assigned(r2) do begin - if r1.Lo<>r2.Lo then begin - result:=longint(r1.Lo)-longint(r2.Lo); - exit; - end; - if r1.Hi<>r2.Hi then begin - result:=longint(r1.Hi)-longint(r2.Hi); - exit; - end; - r1:=r1.Next; - r2:=r2.Next; - end; - if assigned(r1) then begin - result:=1; - end else if assigned(r2) then begin - result:=-1; - end else begin - result:=0; - end; -end; - -constructor TBESENRegExpState.Create(ARegExp:TBESENRegExp); -begin - inherited Create; - RegExp:=ARegExp; - if assigned(RegExp.LastState) then begin - Previous:=RegExp.LastState; - RegExp.LastState:=self; - Previous.Next:=self; - Next:=nil; - end else begin - RegExp.FirstState:=self; - RegExp.LastState:=self; - Previous:=nil; - Next:=nil; - end; - Captures:=nil; - Counters:=nil; - Marks:=nil; - SetLength(Captures,RegExp.CountOfCaptures); - SetLength(Counters,RegExp.CountOfCounters); - SetLength(Marks,RegExp.CountOfMarks); -end; - -destructor TBESENRegExpState.Destroy; -begin - SetLength(Captures,0); - SetLength(Counters,0); - SetLength(Marks,0); - if assigned(Previous) then begin - Previous.Next:=Next; - end else if RegExp.FirstState=self then begin - RegExp.FirstState:=Next; - end; - if assigned(Next) then begin - Next.Previous:=Previous; - end else if RegExp.LastState=self then begin - RegExp.LastState:=Previous; - end; - Previous:=nil; - Next:=nil; - inherited Destroy; -end; - -constructor TBESENRegExp.Create(AInstance:TObject); -begin - inherited Create(AInstance); - FirstCharClass:=nil; - LastCharClass:=nil; - FirstState:=nil; - LastState:=nil; - CurrentState:=nil; - CountStates:=0; - Source:=''; - ByteCode:=nil; - ByteCodeLen:=0; - Flags:=[]; - CountOfCaptures:=0; - CountOfCounters:=0; - CountOfMarks:=0; - MaxRef:=0; - CharClasses:=nil; - CharClassesCount:=0; - ReferenceCounter:=0; -end; - -destructor TBESENRegExp.Destroy; -begin - SetLength(CharClasses,0); - while assigned(FirstCharClass) do begin - FirstCharClass.Free; - end; - while assigned(FirstState) do begin - FirstState.Free; - end; - Source:=''; - SetLength(ByteCode,0); - inherited Destroy; -end; - -procedure TBESENRegExp.IncRef; -begin - inc(ReferenceCounter); -end; - -procedure TBESENRegExp.DecRef; -begin - if ReferenceCounter>1 then begin - dec(ReferenceCounter); - end else begin - ReferenceCounter:=0; - Destroy; - end; -end; - -function TBESENRegExp.InternCharClass(c:TBESENRegExpCharClass):longint; -var i:longint; -begin - for i:=0 to CharClassesCount-1 do begin - if CompareCharClasses(c,CharClasses[i])=0 then begin - result:=i; - exit; - end; - end; - result:=CharClassesCount; - inc(CharClassesCount); - if CharClassesCount>=length(CharClasses) then begin - SetLength(CharClasses,(CharClassesCount+256) and not 255); - end; - CharClasses[result]:=c; -end; - -function TBESENRegExp.CodePos:longint; -begin - result:=ByteCodeLen; -end; - -procedure TBESENRegExp.CodePosSet(p:longint); -begin - ByteCodeLen:=p; - if ByteCodeLen>=length(ByteCode) then begin - SetLength(ByteCode,(ByteCodeLen+4097) and 4095); - end; -end; - -procedure TBESENRegExp.CodeAdd(c:longint); -var i:longint; -begin - i:=ByteCodeLen; - inc(ByteCodeLen); - if ByteCodeLen>=length(ByteCode) then begin - SetLength(ByteCode,(ByteCodeLen+4097) and 4095); - end; - ByteCode[i]:=c; -end; - -procedure TBESENRegExp.CodePatch(p,c:longint); -var i:longint; -begin - i:=p; - if ByteCodeLen>=length(ByteCode) then begin - SetLength(ByteCode,(ByteCodeLen+4097) and 4095); - end; - ByteCode[i]:=c; -end; - -procedure TBESENRegExp.CodeInsert(p,n:longint); -var i,j:longint; -begin - for i:=1 to n do begin - CodeAdd(0); - end; - for i:=ByteCodeLen-n downto p+1 do begin - j:=i-1; - ByteCode[j+n]:=ByteCode[j]; - end; -end; - -procedure TBESENRegExp.CodeAddI(c:longint); -begin - CodeAdd((c shr 8) and $ff); - CodeAdd(c and $ff); -end; - -procedure TBESENRegExp.CodeAddA(c:longint); -begin - CodeAddI(c-CodePos); -end; - -procedure TBESENRegExp.CodePatchI(p,c:longint); -begin - CodePatch(p,(c shr 8) and $ff); - CodePatch(p+1,c and $ff); -end; - -procedure TBESENRegExp.CodePatchA(p,c:longint); -begin - CodePatchI(p,c-p); -end; - -function TBESENRegExp.AllocateState:TBESENRegExpState; -begin - if assigned(CurrentState) then begin - if assigned(CurrentState.Next) then begin - CurrentState:=CurrentState.Next; - end else begin - CurrentState:=TBESENRegExpState.Create(self); - inc(CountStates); - end; - end else begin - if assigned(FirstState) then begin - CurrentState:=FirstState; - end else begin - CurrentState:=TBESENRegExpState.Create(self); - inc(CountStates); - end; - end; - result:=CurrentState; -end; - -procedure TBESENRegExp.CleanupStates; -begin - while assigned(LastState) and (CountStates>TBESEN(Instance).RegExpMaxStatesHoldInMemory) do begin - LastState.Free; - dec(CountStates); - end; - CurrentState:=nil; -end; - -procedure TBESENRegExp.CopyState(const a,b:TBESENRegExpState); -begin - if CountOfCaptures>0 then begin - move(b.Captures[0],a.Captures[0],CountOfCaptures*sizeof(TBESENRegExpCapture)); - end; - if CountOfCounters>0 then begin - move(b.Counters[0],a.Counters[0],CountOfCounters*sizeof(TBESENRegExpValue)); - end; - if CountOfMarks>0 then begin - move(b.Marks[0],a.Marks[0],CountOfMarks*sizeof(TBESENRegExpValue)); - end; -end; - -procedure TBESENRegExp.Compile(const ASource:TBESENString;const AFlags:TBESENRegExpFlags=[]); -var AtEOF:boolean; - CurrentChar:TBESENUTF32CHAR; - UTF32Source:TBESENUTF32STRING; - SourcePos:longint; - function NextChar:TBESENUTF32CHAR; - begin - if (SourcePos+1)<length(UTF32Source) then begin - inc(SourcePos); - CurrentChar:=UTF32Source[SourcePos]; - end else begin - CurrentChar:=0; - AtEOF:=true; - end; - result:=CurrentChar; - end; - procedure SyntaxError; - begin - raise EBESENSyntaxError.Create('regex syntax error'); - end; - procedure Expect(c:TBESENUTF32CHAR); - begin - if AtEOF or (CurrentChar<>c) then begin - SyntaxError; - end; - NextChar; - end; - function ParseInteger:longint; - var OK:boolean; - begin - result:=0; - OK:=false; - while (not AtEOF) and (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) do begin - result:=(result*10)+longint(CurrentChar-ord('0')); - OK:=true; - NextChar; - end; - if not OK then begin - SyntaxError; - end; - end; - function ParseHex:longword; - begin - result:=0; - if AtEOF then begin - SyntaxError; - end else if (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) then begin - result:=CurrentChar-ord('0'); - NextChar; - end else if (CurrentChar>=ord('a')) and (CurrentChar<=ord('f')) then begin - result:=CurrentChar-ord('a')+$a; - NextChar; - end else if (CurrentChar>=ord('A')) and (CurrentChar<=ord('F')) then begin - result:=CurrentChar-ord('A')+$a; - NextChar; - end else begin - SyntaxError; - end; - end; - procedure ParseDisjunction; forward; - function ParseClassEscape(CanBeAlreadyCanonicalized:boolean):TBESENRegExpCharClass; - var i:longint; - ch:TBESENUTF32CHAR; - IgnoreCase:boolean; - begin - result:=nil; - try - IgnoreCase:=CanBeAlreadyCanonicalized and (brefIGNORECASE in Flags); - result:=TBESENRegExpCharClass.Create(self); - if (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) then begin - if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and - (CurrentChar=ord('0')) and ((SourcePos+2)<length(UTF32Source)) and ((UTF32Source[SourcePos+1]>=ord('0')) and (UTF32Source[SourcePos+1]<=ord('7'))) and - ((UTF32Source[SourcePos+2]>=ord('0')) and (UTF32Source[SourcePos+2]<=ord('7'))) then begin - result.AddChar(((UTF32Source[SourcePos+1]-ord('0'))*8)+(UTF32Source[SourcePos+2]-ord('0')),IgnoreCase); - result.Canonicalized:=IgnoreCase; - NextChar; - NextChar; - NextChar; - exit; - end; - i:=0; - while (not AtEOF) and (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) do begin - i:=(i*10)+longint(CurrentChar-ord('0')); - NextChar; - end; - if i<>0 then begin - SyntaxError; - end; - result.AddChar(i,IgnoreCase); - result.Canonicalized:=IgnoreCase; - exit; - end; - ch:=CurrentChar; - NextChar; - case ch of - ord('b'):begin - result.AddChar($0008); - result.Canonicalized:=true; - end; - ord('t'):begin - result.AddChar($0009); - result.Canonicalized:=true; - end; - ord('n'):begin - result.AddChar($000a); - result.Canonicalized:=true; - end; - ord('v'):begin - result.AddChar($000b); - result.Canonicalized:=true; - end; - ord('f'):begin - result.AddChar($000c); - result.Canonicalized:=true; - end; - ord('r'):begin - result.AddChar($000d); - result.Canonicalized:=true; - end; - ord('d'):begin - result.AddRange(ord('0'),ord('9')); - result.Canonicalized:=true; - end; - ord('D'):begin - result.AddRange(ord('0'),ord('9')); - result.Invert; - result.Inverted:=false; - result.Canonicalized:=true; - end; - ord('w'):begin - result.AddRange(ord('a'),ord('z')); - result.AddRange(ord('A'),ord('Z')); - result.AddRange(ord('0'),ord('9')); - result.AddChar(ord('_')); - result.Canonicalized:=true; - end; - ord('W'):begin - result.AddRange(ord('a'),ord('z')); - result.AddRange(ord('A'),ord('Z')); - result.AddRange(ord('0'),ord('9')); - result.AddChar(ord('_')); - result.Invert; - result.Inverted:=false; - result.Canonicalized:=true; - end; - ord('s'):begin - result.AddRange($0009,$000d); - result.AddChar($0020); - result.AddChar($00a0); - result.AddChar($1680); - result.AddChar($180e); - result.AddRange($2000,$200b); - result.AddRange($2028,$2029); - result.AddChar($202f); - result.AddChar($205f); - result.AddChar($3000); - result.AddChar($fffe); - result.AddChar($feff); - result.Canonicalized:=true; - end; - ord('S'):begin - result.AddRange($0009,$000d); - result.AddChar($0020); - result.AddChar($00a0); - result.AddChar($1680); - result.AddChar($180e); - result.AddRange($2000,$200b); - result.AddRange($2028,$2029); - result.AddChar($202f); - result.AddChar($205f); - result.AddChar($3000); - result.AddChar($fffe); - result.AddChar($feff); - result.Invert; - result.Inverted:=false; - result.Canonicalized:=true; - end; - ord('c'):begin - if AtEOF then begin - SyntaxError; - end; - ch:=CurrentChar; - NextChar; - if ((ch>=ord('a')) and (ch<=ord('z'))) or ((ch>=ord('A')) and (ch<=ord('Z'))) then begin - result.AddChar(ch mod 32,IgnoreCase); - result.Canonicalized:=IgnoreCase; - end else begin - SyntaxError; - end; - end; - ord('x'):begin - ch:=ParseHex; - ch:=(ch shl 4) or ParseHex; - result.AddChar(ch,IgnoreCase); - result.Canonicalized:=IgnoreCase; - end; - ord('u'):begin - ch:=ParseHex; - ch:=(ch shl 4) or ParseHex; - ch:=(ch shl 4) or ParseHex; - ch:=(ch shl 4) or ParseHex; - result.AddChar(ch,IgnoreCase); - result.Canonicalized:=IgnoreCase; - end; - else begin - result.AddChar(ch,IgnoreCase); - result.Canonicalized:=IgnoreCase; - end; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseClassAtom:TBESENRegExpCharClass; - begin - if AtEOF then begin - SyntaxError; - end; - result:=nil; - try - if CurrentChar=ord('\') then begin - NextChar; - result:=ParseClassEscape(false); - end else begin - result:=TBESENRegExpCharClass.Create(self); - result.AddChar(CurrentChar); - NextChar; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - function ParseCharacterClass:TBESENRegExpCharClass; - var InvertFlag:boolean; - a,b:TBESENRegExpCharClass; - begin - result:=nil; - try - a:=nil; - b:=nil; - try - result:=TBESENRegExpCharClass.Create(self); - Expect(ord('[')); - InvertFlag:=(not AtEOF) and (CurrentChar=ord('^')); - if InvertFlag then begin - NextChar; - end; - while (not AtEOF) and (CurrentChar<>ord(']')) do begin - a:=ParseClassAtom; - if (not AtEOF) and (CurrentChar=ord('-')) then begin - NextChar; - if (not AtEOF) and (CurrentChar=ord(']')) then begin - a.AddChar(ord('-')); - end else begin - if not a.IsSingle then begin - BESENFreeAndNil(a); - SyntaxError; - end; - b:=ParseClassAtom; - if (not b.IsSingle) or ((assigned(a.Last) and assigned(b.Last)) and not (a.Last.Lo<=b.Last.Hi)) then begin - BESENFreeAndNil(a); - BESENFreeAndNil(b); - SyntaxError; - end; - if assigned(a.Last) and assigned(b.Last) then begin - a.Last.Hi:=b.Last.Hi; - end else begin - a.TakeoverCombine(b); - end; - BESENFreeAndNil(b); - end; - end; - result.TakeoverCombine(a); - BESENFreeAndNil(a); - end; - Expect(ord(']')); - if (brefIGNORECASE in Flags) and not result.Canonicalized then begin - result.Canonicalize; - end; - if InvertFlag then begin - result.Invert; - end; - finally - BESENFreeAndNil(a); - BESENFreeAndNil(b); - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - procedure ParseAtom; - var neg:boolean; - i,p1,px:longint; - c:TBESENRegExpCharClass; - begin - c:=nil; - try - if CurrentChar=ord('(') then begin - NextChar; - if (not AtEOF) and (CurrentChar=ord('?')) then begin - NextChar; - if (not AtEOF) and (CurrentChar=ord(':')) then begin - NextChar; - ParseDisjunction; - end else if (not AtEOF) and ((CurrentChar=ord('=')) or (CurrentChar=ord('!'))) then begin - neg:=CurrentChar=ord('!'); - NextChar; - if neg then begin - CodeAdd(breoAF); - end else begin - CodeAdd(breoAS); - end; - p1:=CodePos; - CodeAddA(0); - ParseDisjunction; - CodeAdd(breoSUCCEED); - px:=CodePos; - CodePatchA(p1,px); - end else begin - SyntaxError; - end; - end else begin - i:=CountOfCaptures; - inc(CountOfCaptures); - CodeAdd(breoSTART); - CodeAddI(i); - ParseDisjunction; - CodeAdd(breoEND); - CodeAddI(i); - end; - Expect(ord(')')); - end else begin - case CurrentChar of - ord('\'):begin - NextChar; - if AtEOF then begin - SyntaxError; - end; - if (CurrentChar>=ord('1')) and (CurrentChar<=ord('9')) then begin - i:=ParseInteger; - CodeAdd(breoBACKREF); - CodeAddI(i); - if i>MaxRef then begin - MaxRef:=i; - end; - exit; - end; - c:=ParseClassEscape(true); - end; - ord('['):begin - c:=ParseCharacterClass; - end; - ord('.'):begin - NextChar; - c:=TBESENRegExpCharClass.Create(self); - c.AddChar($000a); - c.AddChar($000d); - c.AddRange($2028,$2029); - c.Invert; - c.Inverted:=false; - c.Canonicalized:=true; - end; - else begin - c:=TBESENRegExpCharClass.Create(self); - c.AddChar(CurrentChar,brefIGNORECASE in Flags); - c.Canonicalized:=brefIGNORECASE in Flags; - NextChar; - end; - end; - i:=InternCharClass(c); - CodeAdd(breoCHAR); - CodeAddI(i); - end; - except - BESENFreeAndNil(c); - raise; - end; - end; - procedure ParseTerm; - function QuantifierIsNext:boolean; - var Lookahead:PBESENUTF32CHARS; - Len,p:longint; - begin - if CurrentChar<>ord('{') then begin - result:=false; - end else if not (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin - result:=true; - end else begin - Lookahead:=@UTF32Source[SourcePos]; - Len:=length(UTF32Source)-SourcePos; - p:=1; - if Len=0 then begin - result:=false; - end else begin - while (p<Len) and (Lookahead^[p]>=ord('0')) and (Lookahead^[p]<=ord('9')) do begin - inc(p); - end; - if (p<Len) and (Lookahead^[p]=ord(',')) then begin - inc(p); - while (p<Len) and (Lookahead^[p]>=ord('0')) and (Lookahead^[p]<=ord('9')) do begin - inc(p); - end; - if (p<Len) and (Lookahead^[p]>=ord('}')) then begin - result:=true; - end else begin - result:=false; - end; - end else if (p<Len) and (Lookahead^[p]>=ord('}')) then begin - result:=p>1; - end else begin - result:=false; - end; - end; - end; - end; - var Lookahead:PBESENUTF32CHARS; - Len,Position,oparen,cparen,min,max,m,px,py,i,c,p,p1,k:longint; - Greedy:boolean; - begin - Lookahead:=@UTF32Source[SourcePos]; - Len:=length(UTF32Source)-SourcePos; - case CurrentChar of - ord('\'):begin - if (Len>1) and (Lookahead^[1]=ord('b')) then begin - NextChar; - NextChar; - CodeAdd(breoBRK); - exit; - end; - if (Len>1) and (Lookahead^[1]=ord('B')) then begin - NextChar; - NextChar; - CodeAdd(breoNBRK); - exit; - end; - end; - ord('^'):begin - NextChar; - CodeAdd(breoBOL); - exit; - end; - ord('$'):begin - NextChar; - CodeAdd(breoEOL); - exit; - end; - ord('*'),ord('+'),ord('?'),ord(')'),ord(']'),ord('{'),ord('}'),ord('|'):begin - SyntaxError; - end; - end; - - Position:=CodePos; - oparen:=CountOfCaptures; - ParseAtom; - cparen:=CountOfCaptures; - - if AtEOF then begin - min:=1; - max:=1; - end else if CurrentChar=ord('*') then begin - NextChar; - min:=0; - max:=brecINFINITY; - end else if CurrentChar=ord('+') then begin - NextChar; - min:=1; - max:=brecINFINITY; - end else if CurrentChar=ord('?') then begin - NextChar; - min:=0; - max:=1; - end else if QuantifierIsNext then begin - NextChar; - min:=ParseInteger; - if (not AtEOF) and (CurrentChar=ord(',')) then begin - Expect(ord(',')); - if (not AtEOF) and (CurrentChar=ord('}')) then begin - max:=brecINFINITY; - end else begin - max:=ParseInteger; - end; - end else begin - max:=min; - end; - Expect(ord('}')); - end else begin - min:=1; - max:=1; - end; - - if (not AtEOF) and (CurrentChar=ord('?')) then begin - NextChar; - Greedy:=false; - end else begin - Greedy:=true; - end; - - if (min=max) and not Greedy then begin - Greedy:=true; - end; - - if (Max<>brecINFINITY) and (min>max) then begin - SyntaxError; - end; - - if (min=1) and (max=1) then begin - exit; - end; - - if max=0 then begin - CodePosSet(Position); - exit; - end; - - if oparen<>cparen then begin - CodeInsert(Position,1+(2*bresINT)); - CodePatch(Position,breoUNDEF); - CodePatchI(Position+1,oparen); - CodePatchI(Position+1+bresINT,cparen); - end; - - if min=max then begin - p:=Position; - i:=1+bresINT; - c:=CountOfCounters; - inc(CountOfCounters); - CodeInsert(Position,i); - CodePatch(p,breoZERO); - inc(p); - CodePatchI(p,c); - inc(p,bresINT); - px:=p; -{$ifdef UseAssert} - Assert(p=(Position+i)); -{$endif} - CodeAdd(breoRNEXT); - CodeAddI(c); - CodeAddI(max); - CodeAddA(px); - end else if (min=0) and (max=1) then begin - p:=Position; - i:=1+bresADDR; - CodeInsert(Position,i); - if Greedy then begin - CodePatch(p,breoGF); - end else begin - CodePatch(p,breoNF); - end; - inc(p); - p1:=p; - inc(p,bresADDR); -{$ifdef UseAssert} - Assert(p=(Position+i)); -{$endif} - px:=CodePos; - CodePatchA(p1,px); - end else if (min=0) and (max=brecINFINITY) then begin - p:=Position; - i:=2+bresADDR+bresINT; - m:=CountOfMarks; - inc(CountOfMarks); - CodeInsert(Position,i); - px:=p; - if Greedy then begin - CodePatch(p,breoGF); - end else begin - CodePatch(p,breoNF); - end; - inc(p); - p1:=p; - inc(p,bresADDR); - CodePatch(p,breoMARK); - inc(p); - CodePatchI(p,m); - inc(p,bresINT); -{$ifdef UseAssert} - Assert(p=(Position+i)); -{$endif} - CodeAdd(breoFDIST); - CodeAddI(m); - CodeAdd(breoGOTO); - CodeAddA(px); - py:=CodePos; - CodePatchA(p1,py); - end else begin - p:=Position; - i:=3+(bresINT*2)+bresADDR; - c:=CountOfCounters; - k:=CountOfMarks; - inc(CountOfCounters); - inc(CountOfMarks); - CodeInsert(Position,i); - CodePatch(p,breoZERO); - inc(p); - CodePatchI(p,c); - inc(p,bresINT); - px:=p; - if Greedy then begin - CodePatch(p,breoGF); - end else begin - CodePatch(p,breoNF); - end; - inc(p); - p1:=p; - inc(p,bresADDR); - CodePatch(p,breoMARK); - inc(p); - CodePatchI(p,k); - inc(p,bresINT); -{$ifdef UseAssert} - Assert(p=(Position+i)); -{$endif} - if min<>0 then begin - CodeAdd(breoRDIST); - CodeAddI(k); - CodeAddI(c); - CodeAddI(min); - end else begin - CodeAdd(breoFDIST); - CodeAddI(k); - end; - if max<>brecINFINITY then begin - CodeAdd(breoRNEXT); - CodeAddI(c); - CodeAddI(max); - CodeAddA(px); - end else begin - CodeAdd(breoMNEXT); - CodeAddI(c); - CodeAddI(min); - CodeAddA(px); - end; - py:=CodePos; - if min<>0 then begin - CodeAdd(breoREACH); - CodeAddI(c); - CodeAddI(min); - end; - CodePatchA(p1,py); - end; - end; - procedure ParseAlternative; - begin - while not (AtEOF or (CurrentChar=ord(')')) or (CurrentChar=ord('|'))) do begin - ParseTerm; - end; - end; - procedure ParseDisjunction; - var Position,p,p1,p2,x1,x2,i:longint; - begin - Position:=CodePos; - ParseAlternative; - if (not AtEOF) and (CurrentChar=ord('|')) then begin - NextChar; - - p:=Position; - i:=1+bresADDR; - - CodeInsert(Position,i); - - CodePatch(p,breoGF); - inc(p); - p1:=p; - inc(p,bresADDR); -{$ifdef UseAssert} - Assert(p=(Position+i)); -{$endif} - - CodeAdd(breoGOTO); - p2:=CodePos; - - CodeAddA(0); - x1:=CodePos; - - ParseDisjunction; - - x2:=CodePos; - CodePatchA(p1,x1); - CodePatchA(p2,x2); - end; - end; - procedure Optimize; - begin - end; -begin - Flags:=AFlags; - CountOfCaptures:=1; - Source:=ASource; - AtEOF:=false; - UTF32Source:=nil; - try - UTF32Source:=BESENUTF16ToUTF32(Source); - SourcePos:=-1; - NextChar; - ParseDisjunction; - CodeAdd(breoSUCCEED); - SetLength(ByteCode,ByteCodeLen); - Optimize; - SetLength(CharClasses,CharClassesCount); - finally - SetLength(UTF32Source,0); - end; -end; - -function TBESENRegExp.Disassemble:TBESENString; - function CodeMakeI(a:longint):longint; - begin - if (a+2)<=length(ByteCode) then begin - result:=(ByteCode[a] shl 8) or ByteCode[a+1]; - end else begin - raise EBESENInternalError.Create('Internal error: 201002250421-0000'); - end; - end; - function CodeMakeA(a:longint):longint; - begin - result:=(CodeMakeI(a)+a) and $ffff; - end; -var PC,i,i2,i3,a:longint; - Opcode:byte; - procedure GetParams1; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams3; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - i3:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2A; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; - procedure GetParamsA; {$ifdef caninline}inline;{$endif} - begin - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; -begin - result:=''; - PC:=0; - i:=0; - i2:=0; - i3:=0; - a:=0; - while (PC>=0) and (PC<ByteCodeLen) do begin - result:=result+'0x'+IntToHex(PC,8)+': '; - Opcode:=ByteCode[PC]; - inc(PC); - case Opcode of - breoFAIL:begin - result:=result+'FAIL'; - end; - breoSUCCEED:begin - result:=result+'SUCCEED'; - end; - breoCHAR:begin - GetParams1; - result:=result+'CHAR '+IntToStr(i); - end; - breoZERO:begin - GetParams1; - result:=result+'ZERO '+IntToStr(i); - end; - breoREACH:begin - GetParams2; - result:=result+'REACH '+IntToStr(i)+', '+IntToStr(i2); - end; - breoNREACH:begin - GetParams2; - result:=result+'NREACH '+IntToStr(i)+', '+IntToStr(i2); - end; - breoSTART:begin - GetParams1; - result:=result+'START '+IntToStr(i); - end; - breoEND:begin - GetParams1; - result:=result+'END '+IntToStr(i); - end; - breoUNDEF:begin - GetParams2; - result:=result+'UNDEF '+IntToStr(i)+', '+IntToStr(i2); - end; - breoMARK:begin - GetParams1; - result:=result+'MARK '+IntToStr(i); - end; - breoFDIST:begin - GetParams1; - result:=result+'FDIST '+IntToStr(i); - end; - breoRDIST:begin - GetParams3; - result:=result+'RDIST '+IntToStr(i)+', '+IntToStr(i2)+', '+IntToStr(i3); - end; - breoMNEXT:begin - GetParams2A; - result:=result+'MNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); - end; - breoRNEXT:begin - GetParams2A; - result:=result+'RNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); - end; - breoGOTO:begin - GetParamsA; - result:=result+'GOTO 0x'+IntToHex(a,8); - end; - breoGS:begin - GetParamsA; - result:=result+'GS 0x'+IntToHex(a,8); - end; - breoNS:begin - GetParamsA; - result:=result+'NS 0x'+IntToHex(a,8); - end; - breoGF:begin - GetParamsA; - result:=result+'GF 0x'+IntToHex(a,8); - end; - breoNF:begin - GetParamsA; - result:=result+'NF 0x'+IntToHex(a,8); - end; - breoAS:begin - GetParamsA; - result:=result+'AS 0x'+IntToHex(a,8); - end; - breoAF:begin - GetParamsA; - result:=result+'AF 0x'+IntToHex(a,8); - end; - breoBOL:begin - result:=result+'BOL'; - end; - breoEOL:begin - result:=result+'EOL'; - end; - breoBRK:begin - result:=result+'BRK'; - end; - breoNBRK:begin - result:=result+'NBRK'; - end; - breoBACKREF:begin - GetParams1; - result:=result+'BACKREF '+IntToStr(i); - end; - else begin - raise EBESENInternalError.Create('Internal error: 201002250323-0000'); - end; - end; - result:=result+#10; - end; -end; - -procedure TBESENRegExp.DebugDisassemble; - function CodeMakeI(a:longint):longint; - begin - if (a+2)<=length(ByteCode) then begin - result:=(ByteCode[a] shl 8) or ByteCode[a+1]; - end else begin - raise EBESENInternalError.Create('Internal error: 201002250421-0000'); - end; - end; - function CodeMakeA(a:longint):longint; - begin - result:=(CodeMakeI(a)+a) and $ffff; - end; -var PC,i,i2,i3,a:longint; - Opcode:byte; - Line:TBESENUTF8ORSINGLESTRING; - procedure GetParams1; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams3; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - i3:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2A; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; - procedure GetParamsA; {$ifdef caninline}inline;{$endif} - begin - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; -begin - PC:=0; - i:=0; - i2:=0; - i3:=0; - a:=0; - while (PC>=0) and (PC<ByteCodeLen) do begin - Line:='0x'+TBESENUTF8ORSINGLESTRING(IntToHex(PC,8))+': '; - Opcode:=ByteCode[PC]; - inc(PC); - case Opcode of - breoFAIL:begin - Line:=Line+'FAIL'; - end; - breoSUCCEED:begin - Line:=Line+'SUCCEED'; - end; - breoCHAR:begin - GetParams1; - Line:=Line+'CHAR '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - breoZERO:begin - GetParams1; - Line:=Line+'ZERO '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - breoREACH:begin - GetParams2; - Line:=Line+'REACH '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); - end; - breoNREACH:begin - GetParams2; - Line:=Line+'NREACH '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); - end; - breoSTART:begin - GetParams1; - Line:=Line+'START '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - breoEND:begin - GetParams1; - Line:=Line+'END '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - breoUNDEF:begin - GetParams2; - Line:=Line+'UNDEF '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); - end; - breoMARK:begin - GetParams1; - Line:=Line+'MARK '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - breoFDIST:begin - GetParams1; - Line:=Line+'FDIST '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - breoRDIST:begin - GetParams3; - Line:=Line+'RDIST '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i3)); - end; - breoMNEXT:begin - GetParams2A; - Line:=Line+'MNEXT '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoRNEXT:begin - GetParams2A; - Line:=Line+'RNEXT '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoGOTO:begin - GetParamsA; - Line:=Line+'GOTO 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoGS:begin - GetParamsA; - Line:=Line+'GS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoNS:begin - GetParamsA; - Line:=Line+'NS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoGF:begin - GetParamsA; - Line:=Line+'GF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoNF:begin - GetParamsA; - Line:=Line+'NF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoAS:begin - GetParamsA; - Line:=Line+'AS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoAF:begin - GetParamsA; - Line:=Line+'AF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); - end; - breoBOL:begin - Line:=Line+'BOL'; - end; - breoEOL:begin - Line:=Line+'EOL'; - end; - breoBRK:begin - Line:=Line+'BRK'; - end; - breoNBRK:begin - Line:=Line+'NBRK'; - end; - breoBACKREF:begin - GetParams1; - Line:=Line+'BACKREF '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); - end; - else begin - raise EBESENInternalError.Create('Internal error: 201002250323-0000'); - end; - end; - if assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),Line,true); - end; - end; -end; - -function TBESENRegExp.DisassembleOpcode(PC:longint):TBESENString; - function CodeMakeI(a:longint):longint; - begin - if (a+2)<=length(ByteCode) then begin - result:=(ByteCode[a] shl 8) or ByteCode[a+1]; - end else begin - raise EBESENInternalError.Create('Internal error: 201002250421-0000'); - end; - end; - function CodeMakeA(a:longint):longint; - begin - result:=(CodeMakeI(a)+a) and $ffff; - end; -var i,i2,i3,a:longint; - Opcode:byte; - procedure GetParams1; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams3; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - i3:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2A; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; - procedure GetParamsA; {$ifdef caninline}inline;{$endif} - begin - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; -begin - result:=''; - i:=0; - i2:=0; - i3:=0; - a:=0; - if (PC>=0) and (PC<ByteCodeLen) then begin - result:=result+'0x'+IntToHex(PC,8)+': '; - Opcode:=ByteCode[PC]; - inc(PC); - case Opcode of - breoFAIL:begin - result:=result+'FAIL'; - end; - breoSUCCEED:begin - result:=result+'SUCCEED'; - end; - breoCHAR:begin - GetParams1; - result:=result+'CHAR '+IntToStr(i); - end; - breoZERO:begin - GetParams1; - result:=result+'ZERO '+IntToStr(i); - end; - breoREACH:begin - GetParams2; - result:=result+'REACH '+IntToStr(i)+', '+IntToStr(i2); - end; - breoNREACH:begin - GetParams2; - result:=result+'NREACH '+IntToStr(i)+', '+IntToStr(i2); - end; - breoSTART:begin - GetParams1; - result:=result+'START '+IntToStr(i); - end; - breoEND:begin - GetParams1; - result:=result+'END '+IntToStr(i); - end; - breoUNDEF:begin - GetParams2; - result:=result+'UNDEF '+IntToStr(i)+', '+IntToStr(i2); - end; - breoMARK:begin - GetParams1; - result:=result+'MARK '+IntToStr(i); - end; - breoFDIST:begin - GetParams1; - result:=result+'FDIST '+IntToStr(i); - end; - breoRDIST:begin - GetParams3; - result:=result+'RDIST '+IntToStr(i)+', '+IntToStr(i2)+', '+IntToStr(i3); - end; - breoMNEXT:begin - GetParams2A; - result:=result+'MNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); - end; - breoRNEXT:begin - GetParams2A; - result:=result+'RNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); - end; - breoGOTO:begin - GetParamsA; - result:=result+'GOTO 0x'+IntToHex(a,8); - end; - breoGS:begin - GetParamsA; - result:=result+'GS 0x'+IntToHex(a,8); - end; - breoNS:begin - GetParamsA; - result:=result+'NS 0x'+IntToHex(a,8); - end; - breoGF:begin - GetParamsA; - result:=result+'GF 0x'+IntToHex(a,8); - end; - breoNF:begin - GetParamsA; - result:=result+'NF 0x'+IntToHex(a,8); - end; - breoAS:begin - GetParamsA; - result:=result+'AS 0x'+IntToHex(a,8); - end; - breoAF:begin - GetParamsA; - result:=result+'AF 0x'+IntToHex(a,8); - end; - breoBOL:begin - result:=result+'BOL'; - end; - breoEOL:begin - result:=result+'EOL'; - end; - breoBRK:begin - result:=result+'BRK'; - end; - breoNBRK:begin - result:=result+'NBRK'; - end; - breoBACKREF:begin - GetParams1; - result:=result+'BACKREF '+IntToStr(i); - end; - else begin - raise EBESENInternalError.Create('Internal error: 201002250323-0000'); - end; - end; - end; -end; - -function TBESENRegExp.Execute(PC:longint;const Input:TBESENString;var State:TBESENRegExpState;var RemainTimeOutSteps:int64):boolean; - procedure Print(Data:TBESENUTF8ORSINGLESTRING); - begin - if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),TBESENUTF8ORSINGLESTRING(Data),false); - end; - end; - procedure PrintLn(Data:TBESENUTF8ORSINGLESTRING); - begin - if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),TBESENUTF8ORSINGLESTRING(Data),true); - end; - end; - function CodeMakeI(a:longint):longint; {$ifdef caninline}inline;{$endif} - begin - if (a+2)<=length(ByteCode) then begin - result:=(ByteCode[a] shl 8) or ByteCode[a+1]; - end else begin - BESENThrowInternalError('Internal error: 201002250421-0000'); - result:=0; - end; - end; - function CodeMakeA(a:longint):longint; {$ifdef caninline}inline;{$endif} - begin - result:=(CodeMakeI(a)+a) and $ffff; - end; - function GetChar(i:longint):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} - begin - if (i>=0) and (i<length(Input)) then begin - result:=word(widechar(Input[i+1])); - end else begin - BESENThrowInternalError('Internal error: 201002250421-0001'); - result:=0; - end; - end; - function IsWordChar(i:longint):boolean; {$ifdef caninline}inline;{$endif} - begin - if (i>=0) and (i<length(Input)) then begin - case word(widechar(Input[i+1])) of - ord('a')..ord('z'),ord('A')..ord('Z'),ord('0')..ord('9'),ord('_'):begin - result:=true; - end; - else begin - result:=false; - end; - end; - end else begin - result:=false; - end; - end; -var Opcode:byte; - i,i2,i3,a,x,br,len,opc:longint; - ch:TBESENUTF32CHAR; - OldCurrentState,NewState:TBESENRegExpState; - DoBreak:boolean; - procedure GetParams1; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams3; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - i3:=CodeMakeI(PC); - inc(PC,bresINT); - end; - procedure GetParams2A; {$ifdef caninline}inline;{$endif} - begin - i:=CodeMakeI(PC); - inc(PC,bresINT); - i2:=CodeMakeI(PC); - inc(PC,bresINT); - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; - procedure GetParamsA; {$ifdef caninline}inline;{$endif} - begin - a:=CodeMakeA(PC); - inc(PC,bresADDR); - end; - procedure DebugOut; - var c:longint; - e:longword; - begin - opc:=PC; - Print('index='+AnsiString(IntToStr(State.Captures[0].e))+' captures=['); - for c:=0 to CountOfCaptures-1 do begin - if c<>0 then begin - Print(','); - end; - if State.Captures[c].s=brecUNDEFINED then begin - Print('undef'); - end else if int64(State.Captures[c].s+State.Captures[c].e)>length(Input) then begin - Print('bad<'+AnsiString(IntToHex(State.Captures[c].s,8))+','+AnsiString(IntToHex(State.Captures[c].e,8))+'>'); - end else begin - e:=State.Captures[c].e; - if e=brecUNDEFINED then begin - e:=State.Captures[0].e; - end; - Print('"'+BESENUTF16ToUTF8(copy(Input,State.Captures[c].s+1,e-State.Captures[c].s))+'"'); - if State.Captures[c].e=brecUNDEFINED then begin - Print('+'); - end; - end; - end; - Print(']'); - if Opcode in [breoZERO,breoREACH,breoNREACH,breoMNEXT,breoRNEXT] then begin - Print(' counters=['); - for c:=0 to CountOfCounters-1 do begin - if c<>0 then begin - Print(','); - end; - Print(AnsiString(IntToStr(State.Counters[c]))); - end; - Print(']'); - end; - if Opcode in [breoMARK,breoFDIST,breoRDIST] then begin - Print(' marks=['); - for c:=0 to CountOfMarks-1 do begin - if c<>0 then begin - Print(','); - end; - Print(AnsiString(IntToStr(State.Marks[c]))); - end; - Print(']'); - end; - if Opcode<>breoCHAR then begin - PrintLn(''); - PrintLn(AnsiString(DisassembleOpcode(opc))); - end; - end; -begin - result:=false; - OldCurrentState:=CurrentState; - try - NewState:=AllocateState; - i:=0; - i2:=0; - i3:=0; - a:=0; - opc:=0; - while (PC>=0) and (PC<ByteCodeLen) and (RemainTimeOutSteps<>0) do begin - if RemainTimeOutSteps>0 then begin - dec(RemainTimeOutSteps); - end; - Opcode:=ByteCode[PC]; - if TBESEN(Instance).RegExpDebug<>0 then begin - DebugOut; - end; - inc(PC); - case Opcode of - breoFAIL:begin - result:=false; - break; - end; - breoSUCCEED:begin - result:=true; - break; - end; - breoCHAR:begin - GetParams1; - if State.Captures[0].e<longword(length(Input)) then begin - ch:=GetChar(State.Captures[0].e); - inc(State.Captures[0].e); - if ((ch and $fc00)=$d800) and (State.Captures[0].e<longword(length(Input))) and ((GetChar(State.Captures[0].e) and $fc00)=$dc00) then begin - ch:=(((ch and $3ff) shl 10) or (GetChar(State.Captures[0].e) and $3ff))+$10000; - end; - if TBESEN(Instance).RegExpDebug<>0 then begin - Print(' ch="'+BESENUTF32CHARToUTF8(ch)+'" result='); - if CharClasses[i].Contains(ch) then begin - PrintLn('true'); - end else begin - PrintLn('false'); - end; - PrintLn(AnsiString(DisassembleOpcode(opc))); - end; - if not CharClasses[i].Contains(ch) then begin - result:=false; - break; - end; - end else begin - if TBESEN(Instance).RegExpDebug<>0 then begin - PrintLn(''); - PrintLn(AnsiString(DisassembleOpcode(opc))); - end; - result:=false; - break; - end; - end; - breoZERO:begin - GetParams1; - State.Counters[i]:=0; - end; - breoREACH:begin - GetParams2; - if State.Counters[i]<i2 then begin - result:=false; - break; - end; - end; - breoNREACH:begin - GetParams2; - if State.Counters[i]>=i2 then begin - result:=false; - break; - end; - end; - breoSTART:begin - GetParams1; - State.Captures[i].s:=State.Captures[0].e; - State.Captures[i].e:=brecUNDEFINED; - end; - breoEND:begin - GetParams1; - State.Captures[i].e:=State.Captures[0].e; - end; - breoUNDEF:begin - GetParams2; - while i<i2 do begin - State.Captures[i].s:=brecUNDEFINED; - State.Captures[i].e:=brecUNDEFINED; - inc(i); - end; - end; - breoMARK:begin - GetParams1; - State.Marks[i]:=State.Captures[0].e; - end; - breoFDIST:begin - GetParams1; - if State.Marks[i]=longint(State.Captures[0].e) then begin - result:=false; - break; - end; - end; - breoRDIST:begin - GetParams3; - if (State.Marks[i]=longint(State.Captures[0].e)) and (State.Counters[i2]>=i3) then begin - result:=false; - break; - end; - end; - breoMNEXT:begin - GetParams2A; - if State.Counters[i]<i2 then begin - inc(State.Counters[i]); - end; - PC:=a; - end; - breoRNEXT:begin - GetParams2A; - inc(State.Counters[i]); - if State.Counters[i]<i2 then begin - PC:=a; - end; - end; - breoGOTO:begin - GetParamsA; - PC:=a; - end; - breoGS:begin - GetParamsA; - CopyState(NewState,State); - result:=Execute(PC,Input,NewState,RemainTimeOutSteps); - if result then begin - PC:=a; - end else begin - result:=false; - break; - end; - end; - breoNS:begin - GetParamsA; - CopyState(NewState,State); - result:=Execute(a,Input,NewState,RemainTimeOutSteps); - if not result then begin - result:=false; - break; - end; - end; - breoGF:begin - GetParamsA; - CopyState(NewState,State); - result:=Execute(PC,Input,NewState,RemainTimeOutSteps); - if result then begin - CopyState(State,NewState); - result:=true; - break; - end else begin - PC:=a; - end; - end; - breoNF:begin - GetParamsA; - CopyState(NewState,State); - result:=Execute(a,Input,NewState,RemainTimeOutSteps); - if result then begin - CopyState(State,NewState); - result:=true; - break; - end; - end; - breoAS:begin - GetParamsA; - CopyState(NewState,State); - result:=Execute(PC,Input,NewState,RemainTimeOutSteps); - if result then begin - i:=State.Captures[0].e; - CopyState(State,NewState); - State.Captures[0].e:=i; - PC:=a; - end else begin - result:=false; - break; - end; - end; - breoAF:begin - GetParamsA; - CopyState(NewState,State); - result:=Execute(PC,Input,NewState,RemainTimeOutSteps); - if result then begin - result:=false; - break; - end else begin - PC:=a; - end; - end; - breoBOL:begin - if State.Captures[0].e=0 then begin - end else if not (brefMULTILINE in Flags) then begin - result:=false; - break; - end else if (word(widechar(Input[State.Captures[0].e]))=$000a) or - (word(widechar(Input[State.Captures[0].e]))=$000d) or - (word(widechar(Input[State.Captures[0].e]))=$2028) or - (word(widechar(Input[State.Captures[0].e]))=$2029) then begin - end else begin - result:=false; - break; - end; - end; - breoEOL:begin - if State.Captures[0].e=longword(length(Input)) then begin - end else if not (brefMULTILINE in Flags) then begin - result:=false; - break; - end else if (word(widechar(Input[State.Captures[0].e]))=$000a) or - (word(widechar(Input[State.Captures[0].e]))=$000d) or - (word(widechar(Input[State.Captures[0].e]))=$2028) or - (word(widechar(Input[State.Captures[0].e]))=$2029) then begin - end else begin - result:=false; - break; - end; - end; - breoBRK:begin - if IsWordChar(State.Captures[0].e-1)=IsWordChar(State.Captures[0].e) then begin - result:=false; - break; - end; - end; - breoNBRK:begin - if IsWordChar(State.Captures[0].e-1)<>IsWordChar(State.Captures[0].e) then begin - result:=false; - break; - end; - end; - breoBACKREF:begin - GetParams1; - if ((i>=0) and (i<length(State.Captures))) and (State.Captures[i].e<>brecUNDEFINED) then begin - br:=State.Captures[i].s; - len:=longword(longword(State.Captures[i].e)-longword(br)); - if int64(len+int64(State.Captures[0].e))>length(Input) then begin - result:=false; - break; - end; - DoBreak:=false; - if brefIGNORECASE in Flags then begin - for x:=0 to len-1 do begin - if BESENUnicodeToUpper(GetChar(br+x))<>BESENUnicodeToUpper(GetChar(longint(State.Captures[0].e)+x)) then begin - result:=false; - DoBreak:=true; - break; - end; - end; - end else begin - for x:=0 to len-1 do begin - if GetChar(br+x)<>GetChar(longint(State.Captures[0].e)+x) then begin - result:=false; - DoBreak:=true; - break; - end; - end; - end; - if DoBreak then begin - break; - end; - inc(State.Captures[0].e,len); - end; - end; - else begin - BESENThrowInternalError('Internal error: 201002250323-0000'); - end; - end; - end; - finally - CurrentState:=OldCurrentState; - end; -end; - -function TBESENRegExp.Match(const Input:TBESENString;Index:longint;var Captures:TBESENRegExpCaptures):boolean; -var State:TBESENRegExpState; - i:longint; - RemainTimeOutSteps:int64; -begin - CurrentState:=nil; - State:=AllocateState; - try - Captures:=nil; - State.Captures[0].s:=Index; - State.Captures[0].e:=Index; - for i:=1 to CountOfCaptures-1 do begin - State.Captures[i].s:=brecUNDEFINED; - State.Captures[i].e:=brecUNDEFINED; - end; - if TBESEN(Instance).RegExpTimeOutSteps>0 then begin - RemainTimeOutSteps:=TBESEN(Instance).RegExpTimeOutSteps; - end else begin - RemainTimeOutSteps:=-1; - end; - result:=Execute(0,Input,State,RemainTimeOutSteps); - if RemainTimeOutSteps=0 then begin - if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'TIMEOUT',true); - end; - end; - if result then begin - if length(Captures)<>length(State.Captures) then begin - SetLength(Captures,length(State.Captures)); - end; - if length(State.Captures)>0 then begin - move(State.Captures[0],Captures[0],length(State.Captures)*sizeof(TBESENRegExpCapture)); - end; - end else begin - SetLength(Captures,0); - end; - finally - CleanupStates; - end; -end; - -procedure TBESENRegExp.DebugDump; -var i:longint; -begin - if assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin - if (TBESEN(Instance).RegExpDebug>2) and (CharClassesCount>0) then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASSES-DUMP-BEGIN---',true); - for i:=0 to CharClassesCount-1 do begin - if assigned(CharClasses[i]) then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASS-NUMBER-0x'+AnsiString(IntToHex(i,8))+'-DUMP-BEGIN---',true); - CharClasses[i].DebugDump; - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASS-NUMBER-0x'+AnsiString(IntToHex(i,8))+'-DUMP-END---',true); - end; - end; - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASSES-DUMP-END---',true); - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'',true); - end; - if TBESEN(Instance).RegExpDebug>1 then begin - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---REGEXP-BYTECODE-DISASSEMBLY-BEGIN---',true); - DebugDisassemble; - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---REGEXP-BYTECODE-DISASSEMBLY-END---',true); - TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'',true); - end; - end; -end; - -end. diff --git a/3rd/besen/src/BESENRegExpCache.pas b/3rd/besen/src/BESENRegExpCache.pas deleted file mode 100644 index 930b64f0a..000000000 --- a/3rd/besen/src/BESENRegExpCache.pas +++ /dev/null @@ -1,152 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENRegExpCache; -{$i BESEN.inc} - -interface - -uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENRegExp; - -type TBESENRegExpCacheItems=array of TBESENRegExp; - - TBESENRegExpCache=class(TBESENBaseObject) - private - HashSize:longword; - HashSizeMask:longword; - HashItems:TBESENRegExpCacheItems; - procedure SetCacheSize(NewSize:longword); - public - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - function Hash(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENHash; - function Get(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENRegExp; - function IsCached(RegExp:TBESENRegExp):boolean; - published - property CacheSize:longword read HashSize write SetCacheSize; - end; - -implementation - -uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; - -constructor TBESENRegExpCache.Create(AInstance:TObject); -begin - inherited Create(AInstance); - HashItems:=nil; - SetCacheSize(BESENRegExpCacheSize); -end; - -destructor TBESENRegExpCache.Destroy; -var i:integer; -begin - for i:=0 to length(HashItems)-1 do begin - if assigned(HashItems[i]) then begin - BesenFreeAndNil(HashItems[i]); - HashItems[i]:=nil; - end; - end; - SetLength(HashItems,0); - inherited Destroy; -end; - -procedure TBESENRegExpCache.SetCacheSize(NewSize:longword); -var i:integer; -begin - for i:=0 to length(HashItems)-1 do begin - if assigned(HashItems[i]) then begin - HashItems[i].DecRef; - HashItems[i]:=nil; - end; - end; - HashSize:=BESENRoundUpToPowerOfTwo(NewSize); - HashSizeMask:=HashSize-1; - SetLength(HashItems,HashSize); - for i:=0 to length(HashItems)-1 do begin - HashItems[i]:=nil; - end; -end; - -function TBESENRegExpCache.Hash(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENHash; -begin - result:=BESENHashKey(Source); - if brefGLOBAL in Flags then begin - result:=result+4; - end; - if brefIGNORECASE in Flags then begin - result:=result+2; - end; - if brefMULTILINE in Flags then begin - result:=result+1; - end; -end; - -function TBESENRegExpCache.Get(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENRegExp; -var HashValue:TBESENUINT32; -begin - if HashSize>0 then begin - HashValue:=Hash(Source,Flags) and HashSizeMask; - result:=HashItems[HashValue]; - if (assigned(result) and ((result.Source<>Source) or (result.Flags<>Flags))) or not assigned(result) then begin - result:=TBESENRegExp.Create(Instance); - try - result.Compile(Source,Flags); - try - if assigned(HashItems[HashValue]) then begin - HashItems[HashValue].DecRef; - end; - HashItems[HashValue]:=result; - result.IncRef; - except - HashItems[HashValue]:=nil; - raise; - end; - except - BESENFreeAndNil(result); - raise; - end; - end; - end else begin - result:=TBESENRegExp.Create(Instance); - try - result.Compile(Source,Flags); - except - BESENFreeAndNil(result); - raise; - end; - end; -end; - -function TBESENRegExpCache.IsCached(RegExp:TBESENRegExp):boolean; -begin - result:=(HashSize>0) and (assigned(RegExp) and (RegExp=HashItems[Hash(RegExp.Source,RegExp.Flags) and HashSizeMask])); -end; - -end. diff --git a/3rd/besen/src/BESENScope.pas b/3rd/besen/src/BESENScope.pas deleted file mode 100644 index 9c4d3f98a..000000000 --- a/3rd/besen/src/BESENScope.pas +++ /dev/null @@ -1,83 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENScope; -{$i BESEN.inc} - -interface - -uses BESENObject,BESENGarbageCollector; - -type TBESENScope=class(TBESENGarbageCollectorObject) - public - Next:TBESENScope; - Obj:TBESENObject; - constructor Create(AInstance:TObject;AObj:TBESENObject); overload; virtual; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENScope.Create(AInstance:TObject;AObj:TBESENObject); -begin - inherited Create(AInstance); - Next:=nil; - Obj:=AObj; -end; - -destructor TBESENScope.Destroy; -begin - Obj:=nil; - inherited Destroy; -end; - -procedure TBESENScope.Finalize; -begin - Obj:=nil; - Next:=nil; - inherited Finalize; -end; - -procedure TBESENScope.Mark; -begin - if assigned(Obj) then begin - TBESEN(Instance).GarbageCollector.GrayIt(Obj); - end; - if assigned(Next) then begin - TBESEN(Instance).GarbageCollector.GrayIt(Next); - end; - inherited Mark; -end; - -end. diff --git a/3rd/besen/src/BESENSelfBalancedTree.pas b/3rd/besen/src/BESENSelfBalancedTree.pas deleted file mode 100644 index 8cf5b441a..000000000 --- a/3rd/besen/src/BESENSelfBalancedTree.pas +++ /dev/null @@ -1,678 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENSelfBalancedTree; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils; - -type PBESENSelfBalancedTreeValue=^TBESENSelfBalancedTreeValue; - TBESENSelfBalancedTreeValue=record - case boolean of - false:(i:int64); - true:(p:pointer); - end; - - PBESENSelfBalancedTreeNode=^TBESENSelfBalancedTreeNode; - TBESENSelfBalancedTreeNode=record - Parent,Left,Right,PreviousKey,NextKey:PBESENSelfBalancedTreeNode; - Level:int64; - Key:TBESENString; - Value:TBESENSelfBalancedTreeValue; - end; - - TBESENSelfBalancedTreeKeys=array of widestring; - - TBESENSelfBalancedTree=class - protected - procedure Skew(OldParent:PBESENSelfBalancedTreeNode); - function Split(OldParent:PBESENSelfBalancedTreeNode):boolean; - procedure RebalanceAfterLeafAdd(n:PBESENSelfBalancedTreeNode); - procedure DeleteNode(n:PBESENSelfBalancedTreeNode); - function First(StartNode:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; - function Next(n:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; - function FindNode(const Key:TBESENString):PBESENSelfBalancedTreeNode; - procedure ClearNode(var Node:PBESENSelfBalancedTreeNode); - procedure OptimizeNode(var Node:PBESENSelfBalancedTreeNode;MoreOptimize:boolean); - function GetValue(Key:TBESENString):TBESENSelfBalancedTreeValue; - procedure SetValue(Key:TBESENString;Value:TBESENSelfBalancedTreeValue); - public - RootNode:PBESENSelfBalancedTreeNode; - FirstKey,LastKey:PBESENSelfBalancedTreeNode; - constructor Create; - destructor Destroy; override; - function Find(const Key:TBESENString;var Value:TBESENSelfBalancedTreeValue):boolean; - function FindNearest(const Key:TBESENString):PBESENSelfBalancedTreeNode; - function Insert(const Key:TBESENString;Value:TBESENSelfBalancedTreeValue):PBESENSelfBalancedTreeNode; - procedure Remove(const Key:TBESENString); - procedure Optimize; - function Keys:TBESENSelfBalancedTreeKeys; - property Values[Key:TBESENString]:TBESENSelfBalancedTreeValue read GetValue write SetValue; default; - end; - -implementation - -constructor TBESENSelfBalancedTree.Create; -begin - inherited Create; - new(RootNode); - fillchar(RootNode^,sizeof(TBESENSelfBalancedTreeNode),#0); - RootNode^.Level:=$7fffffffffffffff; - FirstKey:=nil; - LastKey:=nil; -end; - -destructor TBESENSelfBalancedTree.Destroy; -begin - ClearNode(RootNode^.Left); - dispose(RootNode); - inherited Destroy; -end; - -function TBESENSelfBalancedTree.First(StartNode:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; -begin - try - if not assigned(StartNode^.Left) then begin - result:=nil; - exit; - end; - result:=StartNode; - while assigned(result^.Left) do begin - result:=result^.Left; - end; - except - result:=nil; - end; -end; - -function TBESENSelfBalancedTree.Next(n:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; -begin - try - if assigned(n^.Right) then begin - result:=n^.Right; - while assigned(result^.Left) do begin - result:=result^.Left; - end; - end else begin - while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin - n:=n^.Parent; - end; - n:=n^.Parent; - if not assigned(n) then begin - result:=nil; - exit; - end; - result:=n; - end; - except - result:=nil; - end; -end; - -procedure TBESENSelfBalancedTree.Skew(OldParent:PBESENSelfBalancedTreeNode); -var NewParent:PBESENSelfBalancedTreeNode; -begin -{$ifdef UseAssert} - Assert(assigned(OldParent)); -{$endif} - NewParent:=OldParent^.Left; -{$ifdef UseAssert} - Assert(assigned(NewParent)); -{$endif} - if OldParent^.Parent^.Left=OldParent then begin - OldParent^.Parent^.Left:=NewParent; - end else begin - OldParent^.Parent^.Right:=NewParent; - end; - NewParent^.Parent:=OldParent^.Parent; - OldParent^.Parent:=NewParent; - - OldParent^.Left:=NewParent^.Right; - if assigned(OldParent^.Left) then begin - OldParent^.Left^.Parent:=OldParent; - end; - NewParent^.Right:=OldParent; - - if assigned(OldParent^.Left) then begin - OldParent^.level:=OldParent^.Left^.level+1; - end else begin - OldParent^.level:=1; - end; -end; - -function TBESENSelfBalancedTree.Split(OldParent:PBESENSelfBalancedTreeNode):boolean; -var NewParent:PBESENSelfBalancedTreeNode; -begin -{$ifdef UseAssert} - Assert(assigned(OldParent)); -{$endif} - NewParent:=OldParent^.Right; - if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin - if OldParent^.Parent^.Left=OldParent then begin - OldParent^.Parent^.Left:=NewParent; - end else begin - OldParent^.Parent^.Right:=NewParent; - end; - NewParent^.Parent:=OldParent^.Parent; - OldParent^.Parent:=NewParent; - - OldParent^.Right:=NewParent^.Left; - if assigned(OldParent^.Right) then begin - OldParent^.Right^.Parent:=OldParent; - end; - NewParent^.Left:=OldParent; - - NewParent^.level:=OldParent^.level+1; - - result:=true; - end else begin - result:=false; - end; -end; - -procedure TBESENSelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENSelfBalancedTreeNode); -begin - // n is a node that has just been inserted and is now a Leaf node. - n^.Level:=1; - n^.Left:=nil; - n^.Right:=nil; - n:=n^.Parent; - while n<>RootNode do begin - if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin - // this point the tree is correct, except (AA2) for n->Parent - Skew(n); - // We handle it (a Left add) by changing it into a Right add using Skew - // If the original add was to the Left side of a node that is on the - // Right side of a horizontal link, n now points to the rights side - // of the second horizontal link, which is correct. - // However if the original add was to the Left of node with a horizontal - // link, we must get to the Right side of the second link. - if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin - n:=n^.Parent; - end; - end; - if not Split(n^.Parent) then begin - break; - end; - n:=n^.Parent; - end; -end; - -function TBESENSelfBalancedTree.FindNode(const Key:TBESENString):PBESENSelfBalancedTreeNode; -var n:PBESENSelfBalancedTreeNode; -begin - try - result:=nil; - n:=RootNode^.Left; - while assigned(n) do begin - case BESENStringCompare(Key,n^.Key) of - -1:begin - n:=n^.Left; - end; - 1:begin - n:=n^.Right; - end; - else begin - result:=n; - break; - end; - end; - end; - except - result:=nil; - end; -end; - -function TBESENSelfBalancedTree.FindNearest(const Key:TBESENString):PBESENSelfBalancedTreeNode; -var n:PBESENSelfBalancedTreeNode; -begin - try - result:=nil; - n:=RootNode^.Left; - while assigned(n) do begin - result:=n; - case BESENStringCompare(Key,n^.Key) of - -1:begin - n:=n^.Left; - end; - 1:begin - n:=n^.Right; - end; - else begin - break; - end; - end; - end; - except - result:=nil; - end; -end; - -function TBESENSelfBalancedTree.Insert(const Key:TBESENString;Value:TBESENSelfBalancedTreeValue):PBESENSelfBalancedTreeNode; -var n,s:PBESENSelfBalancedTreeNode; - LessThan:boolean; -begin - result:=nil; - try - n:=nil; - s:=RootNode^.Left; - while assigned(s) do begin - case BESENStringCompare(Key,s^.Key) of - -1:begin - s:=s^.Left; - end; - 1:begin - s:=s^.Right; - end; - else begin - n:=s; - break; - end; - end; - end; - if assigned(s) then begin - n^.Value:=Value; - end else begin - new(n); - fillchar(n^,sizeof(TBESENSelfBalancedTreeNode),#0); - n^.Key:=Key; - n^.Value:=Value; - if assigned(LastKey) then begin - n^.PreviousKey:=LastKey; - LastKey^.NextKey:=n; - LastKey:=n; - end else begin - FirstKey:=n; - LastKey:=n; - end; - s:=RootNode; - LessThan:=true; - while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin - if LessThan then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - LessThan:=Key<s^.Key; - end; - if LessThan then begin - s^.Left:=n; - end else begin - s^.Right:=n; - end; - n^.Parent:=s; - RebalanceAfterLeafAdd(n); - result:=n; - end; - except - result:=nil; - end; -end; - -procedure TBESENSelfBalancedTree.DeleteNode(n:PBESENSelfBalancedTreeNode); -var Leaf,Temp:PBESENSelfBalancedTreeNode; -begin - try - // If n is not a Leaf, we first swap it out with the Leaf node that just - // precedes it. - Leaf:=n; - if assigned(n^.Left) then begin - Leaf:=n^.Left; - while assigned(Leaf^.Right) do begin - Leaf:=Leaf^.Right; - end; - end else if assigned(n^.Right) then begin - Leaf:=n^.Right; - end; - - if Leaf^.Parent=n then begin - Temp:=Leaf; - end else begin - Temp:=Leaf^.Parent; - end; - if Leaf^.Parent^.Left=Leaf then begin - Leaf^.Parent^.Left:=nil; - end else begin - Leaf^.Parent^.Right:=nil; - end; - - if n<>Leaf then begin - if n^.Parent^.Left=n then begin - n^.Parent^.Left:=Leaf; - end else begin - n^.Parent^.Right:=Leaf; - end; - Leaf^.Parent:=n^.Parent; - if assigned(n^.Left) then begin - n^.Left^.Parent:=Leaf; - end; - Leaf^.Left:=n^.Left; - if assigned(n^.Right) then begin - n^.Right^.Parent:=Leaf; - end; - Leaf^.Right:=n^.Right; - Leaf^.level:=n^.level; - end; - if n<>RootNode then begin - n^.Key:=''; - if assigned(n^.PreviousKey) then begin - n^.PreviousKey^.NextKey:=n^.NextKey; - end else if FirstKey=n then begin - FirstKey:=n^.NextKey; - end; - if assigned(n^.NextKey) then begin - n^.NextKey^.PreviousKey:=n^.PreviousKey; - end else if LastKey=n then begin - LastKey:=n^.PreviousKey; - end; - dispose(n); - end; - - while Temp<>RootNode do begin - if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin - dec(Temp^.level); - if Split(Temp) then begin - if Split(Temp) then begin - Skew(Temp^.Parent^.Parent); - end; - break; - end; - Temp:=Temp^.Parent; - end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin - break; - end else begin - Skew(Temp); - { if assigned(Temp^.Right) then begin - if assigned(Temp^.Right^.Left) then begin - Temp^.Right^.level:=Temp^.Right^.level+1; - end else begin - Temp^.Right^.level:=1; - end; - end;} - if Temp^.level>Temp^.Parent^.level then begin - Skew(Temp); - Split(Temp^.Parent^.Parent); - break; - end; - Temp:=Temp^.Parent^.Parent; - end; - end; - except - end; -end; - -procedure TBESENSelfBalancedTree.Remove(const Key:TBESENString); -var n:PBESENSelfBalancedTreeNode; -begin - try - n:=RootNode^.Left; - while assigned(n) do begin - case BESENStringCompare(Key,n^.Key) of - -1:begin - n:=n^.Left; - end; - 1:begin - n:=n^.Right; - end; - else begin - DeleteNode(n); - break; - end; - end; - end; - except - end; -end; - -procedure TBESENSelfBalancedTree.ClearNode(var Node:PBESENSelfBalancedTreeNode); -begin - if not assigned(Node) then begin - exit; - end; - Node^.Key:=''; - if assigned(Node^.PreviousKey) then begin - Node^.PreviousKey^.NextKey:=Node^.NextKey; - end else if FirstKey=Node then begin - FirstKey:=Node^.NextKey; - end; - if assigned(Node^.NextKey) then begin - Node^.NextKey^.PreviousKey:=Node^.PreviousKey; - end else if LastKey=Node then begin - LastKey:=Node^.PreviousKey; - end; - ClearNode(Node^.Left); - ClearNode(Node^.Right); - dispose(Node); - Node:=nil; -end; - -procedure TBESENSelfBalancedTree.OptimizeNode(var Node:PBESENSelfBalancedTreeNode;MoreOptimize:boolean); -var Nodes:array of TBESENSelfBalancedTreeNode; - - NodeCount,NodeIndex:integer; - procedure CountNodes(Node:PBESENSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - CountNodes(Node^.Left); - CountNodes(Node^.Right); - inc(NodeCount); - end; - procedure CollectNodes(Node:PBESENSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - CollectNodes(Node^.Left); - if NodeIndex>=length(Nodes) then begin - NodeCount:=NodeIndex+1; - SetLength(Nodes,NodeCount); - end; - Nodes[NodeIndex].Key:=Node^.Key; - Nodes[NodeIndex].Value:=Node^.Value; - Node^.Key:=''; - inc(NodeIndex); - CollectNodes(Node^.Right); - end; - procedure FreeNodes(var Node:PBESENSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - Node^.Key:=''; - if assigned(Node^.PreviousKey) then begin - Node^.PreviousKey^.NextKey:=Node^.NextKey; - end; - if assigned(Node^.NextKey) then begin - Node^.NextKey^.PreviousKey:=Node^.PreviousKey; - end; - if FirstKey=Node then begin - FirstKey:=Node^.NextKey; - end; - if LastKey=Node then begin - LastKey:=Node^.PreviousKey; - end; - CountNodes(Node^.Left); - CountNodes(Node^.Right); - dispose(Node); - Node:=nil; - end; - procedure DoInsertNode(const Node:TBESENSelfBalancedTreeNode); - var n,s:PBESENSelfBalancedTreeNode; - LessThan:boolean; - begin - new(n); - n^.Key:=Node.Key; - n^.Value:=Node.Value; - n^.Parent:=nil; - n^.Left:=nil; - n^.Right:=nil; - n^.Level:=0; - s:=RootNode; - LessThan:=true; - while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin - if LessThan then begin - s:=s^.Left; - end else begin - s:=s^.Right; - end; - LessThan:=n^.Key<s^.Key; - end; - if LessThan then begin - s^.Left:=n; - end else begin - s^.Right:=n; - end; - n^.Parent:=s; - if assigned(LastKey) then begin - n^.PreviousKey:=LastKey; - LastKey^.NextKey:=n; - LastKey:=n; - end else begin - FirstKey:=n; - LastKey:=n; - end; - if not MoreOptimize then begin - RebalanceAfterLeafAdd(n); - end; - end; - procedure RepairNodes(var Node:PBESENSelfBalancedTreeNode); - begin - if not assigned(Node) then begin - exit; - end; - RepairNodes(Node^.Left); - RepairNodes(Node^.Right); - if assigned(Node^.Left) and assigned(Node^.Right) then begin - Node^.Level:=Node^.Left^.Level+1; - end else begin - Node^.Level:=1; - end; - end; - procedure ReinsertNodesForRepair(LowNode,HighNode:integer); - var MiddleNode:integer; - begin - if HighNode<LowNode then begin - exit; - end; - MiddleNode:=LowNode+((HighNode-LowNode) div 2); - DoInsertNode(Nodes[MiddleNode]); - Nodes[MiddleNode].Key:=''; - ReinsertNodesForRepair(LowNode,MiddleNode-1); - ReinsertNodesForRepair(MiddleNode+1,HighNode); - end; - procedure ReinsertNodes(LowNode,HighNode:integer); - var i:integer; - begin - for i:=LowNode to HighNode do begin - DoInsertNode(Nodes[i]); - Nodes[i].Key:=''; - end; - end; -var i:integer; -begin - if not assigned(Node) then begin - exit; - end; - try - Nodes:=nil; - NodeCount:=0; - CountNodes(Node); - SetLength(Nodes,NodeCount); - NodeIndex:=0; - CollectNodes(Node); - FreeNodes(Node); - if MoreOptimize then begin - ReinsertNodesForRepair(0,length(Nodes)-1); - RepairNodes(RootNode^.Left); - end else begin - ReinsertNodes(0,length(Nodes)-1); - end; - for i:=0 to length(Nodes)-1 do begin - Nodes[i].Key:=''; - end; - SetLength(Nodes,0); - except - end; -end; - -function TBESENSelfBalancedTree.Find(const Key:TBESENString;var Value:TBESENSelfBalancedTreeValue):boolean; -var n:PBESENSelfBalancedTreeNode; -begin - n:=FindNode(Key); - if assigned(n) then begin - Value:=n^.Value; - result:=true; - end else begin - fillchar(Value,sizeof(TBESENSelfBalancedTreeValue),#0); - result:=false; - end; -end; - -procedure TBESENSelfBalancedTree.Optimize; -begin - OptimizeNode(RootNode^.Left,true); -end; - -function TBESENSelfBalancedTree.Keys:TBESENSelfBalancedTreeKeys; -var CurrentNode:PBESENSelfBalancedTreeNode; - Count:integer; -begin - result:=nil; - Count:=0; - CurrentNode:=FirstKey; - while assigned(CurrentNode) do begin - inc(Count); - CurrentNode:=CurrentNode^.NextKey; - end; - SetLength(result,Count); - Count:=0; - CurrentNode:=FirstKey; - while assigned(CurrentNode) do begin - result[Count]:=CurrentNode^.Key; - inc(Count); - CurrentNode:=CurrentNode^.NextKey; - end; -end; - -function TBESENSelfBalancedTree.GetValue(Key:TBESENString):TBESENSelfBalancedTreeValue; -begin - Find(Key,result); -end; - -procedure TBESENSelfBalancedTree.SetValue(Key:TBESENString;Value:TBESENSelfBalancedTreeValue); -begin - Insert(Key,Value); -end; - -end. diff --git a/3rd/besen/src/BESENShell.cfg b/3rd/besen/src/BESENShell.cfg deleted file mode 100644 index e9c1cc14e..000000000 --- a/3rd/besen/src/BESENShell.cfg +++ /dev/null @@ -1,38 +0,0 @@ --$A8 --$B- --$C+ --$D+ --$E- --$F- --$G+ --$H+ --$I+ --$J- --$K- --$L+ --$M- --$N+ --$O+ --$P+ --$Q- --$R- --$S- --$T- --$U- --$V+ --$W- --$X+ --$YD --$Z1 --cg --AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; --H+ --W+ --M --$M16384,1048576 --K$00400000 --LE"c:\program files (x86)\borland\delphi7\Projects\Bpl" --LN"c:\program files (x86)\borland\delphi7\Projects\Bpl" --w-UNSAFE_TYPE --w-UNSAFE_CODE --w-UNSAFE_CAST diff --git a/3rd/besen/src/BESENShell.dof b/3rd/besen/src/BESENShell.dof deleted file mode 100644 index b1bb99770..000000000 --- a/3rd/besen/src/BESENShell.dof +++ /dev/null @@ -1,136 +0,0 @@ -[FileVersion] -Version=7.0 -[Compiler] -A=8 -B=0 -C=1 -D=1 -E=0 -F=0 -G=1 -H=1 -I=1 -J=0 -K=0 -L=1 -M=0 -N=1 -O=1 -P=1 -Q=0 -R=0 -S=0 -T=0 -U=0 -V=1 -W=0 -X=1 -Y=1 -Z=1 -ShowHints=1 -ShowWarnings=1 -UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -NamespacePrefix= -SymbolDeprecated=1 -SymbolLibrary=1 -SymbolPlatform=1 -UnitLibrary=1 -UnitPlatform=1 -UnitDeprecated=1 -HResultCompat=1 -HidingMember=1 -HiddenVirtual=1 -Garbage=1 -BoundsError=1 -ZeroNilCompat=1 -StringConstTruncated=1 -ForLoopVarVarPar=1 -TypedConstVarPar=1 -AsgToTypedConst=1 -CaseLabelRange=1 -ForVariable=1 -ConstructingAbstract=1 -ComparisonFalse=1 -ComparisonTrue=1 -ComparingSignedUnsigned=1 -CombiningSignedUnsigned=1 -UnsupportedConstruct=1 -FileOpen=1 -FileOpenUnitSrc=1 -BadGlobalSymbol=1 -DuplicateConstructorDestructor=1 -InvalidDirective=1 -PackageNoLink=1 -PackageThreadVar=1 -ImplicitImport=1 -HPPEMITIgnored=1 -NoRetVal=1 -UseBeforeDef=1 -ForLoopVarUndef=1 -UnitNameMismatch=1 -NoCFGFileFound=1 -MessageDirective=1 -ImplicitVariants=1 -UnicodeToLocale=1 -LocaleToUnicode=1 -ImagebaseMultiple=1 -SuspiciousTypecast=1 -PrivatePropAccessor=1 -UnsafeType=0 -UnsafeCode=0 -UnsafeCast=0 -[Linker] -MapFile=0 -OutputObjs=0 -ConsoleApp=1 -DebugInfo=0 -RemoteSymbols=0 -MinStackSize=16384 -MaxStackSize=1048576 -ImageBase=4194304 -ExeDescription= -[Directories] -OutputDir= -UnitOutputDir= -PackageDLLOutputDir= -PackageDCPOutputDir= -SearchPath= -Packages= -Conditionals= -DebugSourceDirs= -UsePackages=0 -[Parameters] -RunParams= -HostApplication= -Launcher= -UseLauncher=0 -DebugCWD= -[Language] -ActiveLang= -ProjectLang= -RootDir= -[Version Info] -IncludeVerInfo=0 -AutoIncBuild=0 -MajorVer=1 -MinorVer=0 -Release=0 -Build=0 -Debug=0 -PreRelease=0 -Special=0 -Private=0 -DLL=0 -Locale=1031 -CodePage=1252 -[Version Info Keys] -CompanyName= -FileDescription= -FileVersion=1.0.0.0 -InternalName= -LegalCopyright= -LegalTrademarks= -OriginalFilename= -ProductName= -ProductVersion=1.0.0.0 -Comments= diff --git a/3rd/besen/src/BESENShell.dpr b/3rd/besen/src/BESENShell.dpr deleted file mode 100644 index f0e0ddc0a..000000000 --- a/3rd/besen/src/BESENShell.dpr +++ /dev/null @@ -1,942 +0,0 @@ -program BESENShell; -{$i BESEN.inc} -{$ifdef win32} - {$apptype console} -{$endif} - -uses -{$ifdef fpc} -{$ifdef win32} - Windows, -{$endif} -{$else} -{$ifdef win32} -// FastMM4, - Windows, -{$endif} -{$endif} - SysUtils, - Classes, - BESEN in 'BESEN.pas', - BESENCodeSnapshot in 'BESENCodeSnapshot.pas', - BESENVersionConstants in 'BESENVersionConstants.pas', - BESENConstants in 'BESENConstants.pas', - BESENValueContainer in 'BESENValueContainer.pas', - BESENUnicodeTables in 'BESENUnicodeTables.pas', - BESENStringUtils in 'BESENStringUtils.pas', - BESENStringTree in 'BESENStringTree.pas', - BESENStringList in 'BESENStringList.pas', - BESENSelfBalancedTree in 'BESENSelfBalancedTree.pas', - BESENScope in 'BESENScope.pas', - BESENRegExpCache in 'BESENRegExpCache.pas', - BESENRandomGenerator in 'BESENRandomGenerator.pas', - BESENPointerSelfBalancedTree in 'BESENPointerSelfBalancedTree.pas', - BESENPointerList in 'BESENPointerList.pas', - BESENParser in 'BESENParser.pas', - BESENOpcodes in 'BESENOpcodes.pas', - BESENObjectThrowTypeErrorFunction in 'BESENObjectThrowTypeErrorFunction.pas', - BESENObjectStringPrototype in 'BESENObjectStringPrototype.pas', - BESENObjectStringConstructor in 'BESENObjectStringConstructor.pas', - BESENObjectString in 'BESENObjectString.pas', - BESENObjectRegExpPrototype in 'BESENObjectRegExpPrototype.pas', - BESENObjectRegExpConstructor in 'BESENObjectRegExpConstructor.pas', - BESENObjectRegExp in 'BESENObjectRegExp.pas', - BESENObjectPrototype in 'BESENObjectPrototype.pas', - BESENObjectPropertyDescriptor in 'BESENObjectPropertyDescriptor.pas', - BESENObjectNumberPrototype in 'BESENObjectNumberPrototype.pas', - BESENObjectNumberConstructor in 'BESENObjectNumberConstructor.pas', - BESENObjectNumber in 'BESENObjectNumber.pas', - BESENObjectNativeFunction in 'BESENObjectNativeFunction.pas', - BESENObjectMath in 'BESENObjectMath.pas', - BESENObjectJSON in 'BESENObjectJSON.pas', - BESENObjectGlobal in 'BESENObjectGlobal.pas', - BESENObjectFunctionPrototype in 'BESENObjectFunctionPrototype.pas', - BESENObjectFunctionConstructor in 'BESENObjectFunctionConstructor.pas', - BESENObjectFunctionArguments in 'BESENObjectFunctionArguments.pas', - BESENObjectFunction in 'BESENObjectFunction.pas', - BESENObjectErrorPrototype in 'BESENObjectErrorPrototype.pas', - BESENObjectErrorConstructor in 'BESENObjectErrorConstructor.pas', - BESENObjectError in 'BESENObjectError.pas', - BESENObjectEnvironmentRecord in 'BESENObjectEnvironmentRecord.pas', - BESENObjectDeclaredFunction in 'BESENObjectDeclaredFunction.pas', - BESENObjectDatePrototype in 'BESENObjectDatePrototype.pas', - BESENObjectDateConstructor in 'BESENObjectDateConstructor.pas', - BESENObjectDate in 'BESENObjectDate.pas', - BESENObjectConstructor in 'BESENObjectConstructor.pas', - BESENObjectBooleanPrototype in 'BESENObjectBooleanPrototype.pas', - BESENObjectBooleanConstructor in 'BESENObjectBooleanConstructor.pas', - BESENObjectBoolean in 'BESENObjectBoolean.pas', - BESENObjectBindingFunction in 'BESENObjectBindingFunction.pas', - BESENObjectArrayPrototype in 'BESENObjectArrayPrototype.pas', - BESENObjectArrayConstructor in 'BESENObjectArrayConstructor.pas', - BESENObjectArray in 'BESENObjectArray.pas', - BESENObjectArgSetterFunction in 'BESENObjectArgSetterFunction.pas', - BESENObjectArgGetterFunction in 'BESENObjectArgGetterFunction.pas', - BESENObject in 'BESENObject.pas', - BESENNumberUtils in 'BESENNumberUtils.pas', - BESENNativeObject in 'BESENNativeObject.pas', - BESENNativeCodeMemoryManager in 'BESENNativeCodeMemoryManager.pas', - BESENLocale in 'BESENLocale.pas', - BESENLexicalEnvironment in 'BESENLexicalEnvironment.pas', - BESENLexer in 'BESENLexer.pas', - BESENKeyIDManager in 'BESENKeyIDManager.pas', - BESENIntegerList in 'BESENIntegerList.pas', - BESENInt64SelfBalancedTree in 'BESENInt64SelfBalancedTree.pas', - BESENHashUtils in 'BESENHashUtils.pas', - BESENHashMap in 'BESENHashMap.pas', - BESENGlobals in 'BESENGlobals.pas', - BESENGarbageCollector in 'BESENGarbageCollector.pas', - BESENEvalCacheItem in 'BESENEvalCacheItem.pas', - BESENEvalCache in 'BESENEvalCache.pas', - BESENErrors in 'BESENErrors.pas', - BESENEnvironmentRecord in 'BESENEnvironmentRecord.pas', - BESENDoubleList in 'BESENDoubleList.pas', - BESENDecompiler in 'BESENDecompiler.pas', - BESENDeclarativeEnvironmentRecord in 'BESENDeclarativeEnvironmentRecord.pas', - BESENDateUtils in 'BESENDateUtils.pas', - BESENCompiler in 'BESENCompiler.pas', - BESENCollectorObject in 'BESENCollectorObject.pas', - BESENCollector in 'BESENCollector.pas', - BESENCharset in 'BESENCharset.pas', - BESENBaseObject in 'BESENBaseObject.pas', - BESENArrayUtils in 'BESENArrayUtils.pas', - BESENTypes in 'BESENTypes.pas', - BESENUtils in 'BESENUtils.pas', - BESENValue in 'BESENValue.pas', - BESENRegExp in 'BESENRegExp.pas', - BESENCode in 'BESENCode.pas', - BESENASTNodes in 'BESENASTNodes.pas', - BESENCodeContext in 'BESENCodeContext.pas', - BESENCodeGeneratorContext in 'BESENCodeGeneratorContext.pas', - BESENContext in 'BESENContext.pas', - BESENObjectConsole in 'BESENObjectConsole.pas'; - -type TShellFunctions=class - procedure RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); - procedure NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - - TFileObject=class(TBESENNativeObject) - private - fFileName:TBESENString; - fFileStream:TFileStream; - protected - procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); override; - procedure InitializeObject; override; - procedure FinalizeObject; override; - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); override; - destructor Destroy; override; - published - procedure close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - property fileName:TBESENString read fFileName write fFileName; - end; - -var Instance:TBESEN; - ShellFunctions:TShellFunctions; - DoExit:boolean; - -constructor TFileObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - fFileStream:=nil; -end; - -destructor TFileObject.Destroy; -begin - BesenFreeAndNil(fFileStream); - inherited Destroy; -end; - -procedure TFileObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); -var s:string; - Mode:longword; -begin - inherited ConstructObject(ThisArgument,Arguments,CountArguments); - if CountArguments=0 then begin - raise EBESENError.Create('FileError','Too few arguments'); - end else begin - fFileName:=TBESEN(Instance).ToStr(Arguments^[0]^); - if FileExists(fFileName) then begin - Mode:=fmOpenReadWrite or fmShareExclusive; - end else begin - Mode:=fmCreate or fmShareDenyRead; - end; - if CountArguments>1 then begin - s:=TBESEN(Instance).ToStr(Arguments^[1]^); - if s='c' then begin - Mode:=fmCreate or fmShareDenyRead; - end else if s='r' then begin - Mode:=fmOpenRead or fmShareDenyWrite; - end else if s='rw' then begin - Mode:=fmOpenReadWrite or fmShareExclusive; - end else if s='w' then begin - if FileExists(fFileName) then begin - Mode:=fmOpenWrite or fmShareDenyRead; - end else begin - Mode:=fmCreate or fmShareDenyRead; - end; - end; - end; -{$ifdef BESENSingleStringType} - fFileStream:=TFileStream.Create(fFileName,Mode); -{$else} - fFileStream:=TFileStream.Create(String(BESENEncodeString(BESENUTF16ToUTF8(fFileName),UTF_8,BESENLocaleCharset)),Mode); -{$endif} - end; - s:=''; -end; - -procedure TFileObject.InitializeObject; -begin - inherited InitializeObject; - fFileName:=''; - fFileStream:=nil; -end; - -procedure TFileObject.FinalizeObject; -begin - BesenFreeAndNil(fFileStream); - inherited FinalizeObject; -end; - -procedure TFileObject.close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - BesenFreeAndNil(fFileStream); -end; - -procedure TFileObject.read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var l,ms:int64; - s:string; -begin - s:=''; - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ms:=fFileStream.Size-fFileStream.Position; - if CountArguments=0 then begin - l:=ms; - end else begin - if Arguments^[0]^.ValueType=bvtUNDEFINED then begin - l:=ms; - end else begin - l:=TBESEN(Instance).ToInt(Arguments^[0]^); - if l>ms then begin - l:=ms; - end; - end; - end; - SetLength(s,l); - if l>0 then begin - fFileStream.Read(s[1],l); - end; - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:=s; - SetLength(s,0); - end; -end; - -procedure TFileObject.write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var l:int64; - s:string; -begin - s:=''; - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - if CountArguments>0 then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=0; - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - l:=length(s); - if l>0 then begin - ResultValue.Num:=fFileStream.Write(s[1],l); - end; - SetLength(s,0); - end; - end; -end; - -procedure TFileObject.seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var l,ms:int64; -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ms:=fFileStream.Size; - if CountArguments=0 then begin - l:=fFileStream.Position; - end else begin - if Arguments^[0]^.ValueType=bvtUNDEFINED then begin - l:=fFileStream.Position; - end else begin - l:=TBESEN(Instance).ToInt(Arguments^[0]^); - if l>ms then begin - l:=ms; - end; - end; - end; - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=fFileStream.Seek(l,soFromBeginning); - end; -end; - -procedure TFileObject.position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=fFileStream.Position; - end; -end; - -procedure TFileObject.eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=fFileStream.Position<fFileStream.Size; - end; -end; - -procedure TFileObject.flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin -{$ifdef win32} - Windows.FlushFileBuffers(fFileStream.Handle); -{$endif} - end; -end; - -procedure TShellFunctions.RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); -begin - if NewLine then begin - writeln(Data); - end else begin - write(Data); - end; -end; - -procedure TShellFunctions.NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if CountArguments>0 then begin - Instance.RegExpDebug:=Instance.ToUINT32(Arguments^[0]^); - end; -end; - -procedure TShellFunctions.NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=Instance.RegExpDebug; -end; - -procedure TShellFunctions.NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if CountArguments>0 then begin - Instance.RegExpTimeOutSteps:=Instance.ToINT(Arguments^[0]^); - end; -end; - -procedure TShellFunctions.NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=Instance.RegExpTimeOutSteps; -end; - -procedure TShellFunctions.NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var i:integer; - v:PBESENValue; - fOutput:widestring; - procedure writeit(s:widestring); - begin - fOutput:=fOutput+s; - end; -begin - fOutput:=''; - ResultValue.ValueType:=bvtUNDEFINED; - for i:=0 to CountArguments-1 do begin - v:=Arguments^[i]; - case v^.ValueType of - bvtUNDEFINED:begin - writeit('undefined'); - end; - bvtNULL:begin - writeit('null'); - end; - bvtBOOLEAN:begin - if v^.Bool then begin - writeit('true'); - end else begin - writeit('false'); - end; - end; - bvtNUMBER:begin - writeit(BESENFloatToStr(v^.Num)); - end; - bvtSTRING:begin - writeit(v^.Str); - end; - bvtOBJECT:begin - writeit(TBESEN(Instance).ToStr(v^)); - end; - bvtREFERENCE:begin - writeit('reference'); - end; - end; - end; -{$ifdef Delphi2009AndUp} - writeln(fOutput); -{$else} - writeln(BESENEncodeString(BESENUTF16ToUTF8(fOutput),UTF_8,BESENLocaleCharset)); -{$endif} -end; - -procedure TShellFunctions.NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - NativePrint(ThisArgument,Arguments,CountArguments,ResultValue); - writeln; -end; - -procedure TShellFunctions.NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:string; -begin - readln(s); -{$ifdef Delphi2009AndUp} - ResultValue:=BESENStringValue(s); -{$else} - ResultValue:=BESENStringLocaleCharsetValue(s); -{$endif} -end; - -procedure TShellFunctions.NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - NativePrintLn(ThisArgument,Arguments,CountArguments,ResultValue); -end; - -procedure TShellFunctions.NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var i:integer; - v:PBESENValue; - ss:widestring; - procedure writeit(s:widestring); - begin - ss:=ss+s; - end; -begin - ss:=''; - ResultValue.ValueType:=bvtUNDEFINED; - for i:=0 to CountArguments-1 do begin - v:=Arguments^[i]; - case v^.ValueType of - bvtUNDEFINED:begin - writeit('undefined'); - end; - bvtNULL:begin - writeit('null'); - end; - bvtBOOLEAN:begin - if v^.Bool then begin - writeit('true'); - end else begin - writeit('false'); - end; - end; - bvtNUMBER:begin - writeit(BESENFloatToStr(v^.Num)); - end; - bvtSTRING:begin - writeit(v^.Str); - end; - bvtOBJECT:begin - writeit(TBESEN(Instance).ToStr(v^)); - end; - bvtREFERENCE:begin - writeit('reference'); - end; - end; - end; -{$ifdef Delphi2009AndUp} - writeln(ss); -{$else} - writeln(BESENEncodeString(BESENUTF16ToUTF8(ss),UTF_8,BESENLocaleCharset)); -{$endif} -end; - -procedure TShellFunctions.NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ss:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - s:string; -begin - ss:=''; - try - if CountArguments>0 then begin -{$ifdef BESENSingleStringType} - ss:=TBESEN(Instance).ToStr(Arguments^[0]^); -{$else} - ss:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - end else begin - ss:=''; - end; -(* if CountArguments>1 then begin -{$ifdef BESENSingleStringType} - s:=TBESEN(Instance).ToStr(Arguments^[1]^); -{$else} - s:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)),UTF_8,BESENLocaleCharset); -{$endif} - end else begin - s:=''; - end;*) - write(ss); - readln(s); -{$ifdef Delphi2009AndUp} - ResultValue:=BESENStringValue(s); -{$else} - ResultValue:=BESENStringLocaleCharsetValue(s); -{$endif} - finally - end; -end; - -procedure TShellFunctions.NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - DoExit:=true; -end; - -procedure TShellFunctions.NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - fm:byte; - f:file; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>0 then begin -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - Content:=''; - fm:=filemode; - filemode:=0; - assignfile(f,String(FileName)); - {$i-}reset(f,1);{$i+}; - if ioresult=0 then begin - SetLength(Content,filesize(f)); - if length(Content)>0 then begin - {$i-}blockread(f,Content[1],length(Content));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); - exit; - end; - end; - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:={$ifndef BESENSingleStringType}BESENUTF8ToUTF16(BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType})){$endif}; - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - end else begin - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); - end; - end else begin - raise EBESENError.Create('FileError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - fm:byte; - f:file; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>1 then begin -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); - Content:=TBESEN(Instance).ToStr(Arguments^[1]^); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); - Content:=#$ef#$bb#$bf+BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)); -{$endif} - fm:=filemode; - filemode:=2; - assignfile(f,String(FileName)); - {$i-}rewrite(f,1);{$i+}; - if ioresult=0 then begin - if length(Content)>0 then begin - {$i-}blockwrite(f,Content[1],length(Content));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); - exit; - end; - end; - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - end else begin - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); - end; - end else begin - raise EBESENError.Create('FileError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const BoolStr:array[boolean] of {$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}=('false','true'); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - SearchRec:TSearchRec; - Count:integer; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>0 then begin - Content:='['; -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - if FindFirst(String(FileName),faAnyFile or faDirectory,SearchRec)=0 then begin - Count:=0; - repeat - if Count>0 then begin - Content:=Content+','; - end; - Content:=Content+'{'; - Content:=Content+'"name":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENJSONStringQuote(BESENUTF8ToUTF16(BESENEncodeString(AnsiString(SearchRec.Name),BESENLocaleCharset,UTF_8))))+','; - Content:=Content+'"size":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(IntToStr(SearchRec.Size))+','; - Content:=Content+'"time":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENFloatToStr(BESENDateTimeToBESENDate(FileDateToDateTime(SearchRec.Time))))+','; - Content:=Content+'"flags":{'; - Content:=Content+'"hidden":'+BoolStr[(SearchRec.Attr and faHidden)<>0]+','; - Content:=Content+'"systemFile":'+BoolStr[(SearchRec.Attr and faSysFile)<>0]+','; - Content:=Content+'"volumeID":'+BoolStr[(SearchRec.Attr and faVolumeID)<>0]+','; - Content:=Content+'"directory":'+BoolStr[(SearchRec.Attr and faDirectory)<>0]+','; - Content:=Content+'"archive":'+BoolStr[(SearchRec.Attr and faArchive)<>0]+''; - Content:=Content+'}}'; - inc(Count); - until FindNext(SearchRec)<>0; - FindClose(SearchRec); - end; - Content:=Content+']'; - ResultValue:=TBESEN(Instance).JSONEval(Content); - end else begin - raise EBESENError.Create('DirectoryError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - fm:byte; - f:file; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>0 then begin -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - Content:=''; - fm:=filemode; - filemode:=0; - assignfile(f,string(FileName)); - {$i-}reset(f,1);{$i+}; - if ioresult=0 then begin - SetLength(Content,filesize(f)); - if length(Content)>0 then begin - {$i-}blockread(f,Content[1],length(Content));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); - exit; - end; - end; - ResultValue:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType}){$endif}); - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - end else begin - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); - end; - end else begin - raise EBESENError.Create('FileError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - TBESEN(Instance).GarbageCollector.CollectAll; -end; - -procedure TShellFunctions.NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:='BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'; -end; - -procedure Print(const v:TBESENValue); -var fOutput:widestring; - procedure writeit(s:widestring); - begin - fOutput:=fOutput+s; - end; -begin - fOutput:=''; - case v.ValueType of - bvtUNDEFINED:begin - writeit('undefined'); - end; - bvtNULL:begin - writeit('null'); - end; - bvtBOOLEAN:begin - if v.Bool then begin - writeit('true'); - end else begin - writeit('false'); - end; - end; - bvtNUMBER:begin - writeit(BESENFloatToStr(v.Num)); - end; - bvtSTRING:begin - writeit(v.Str); - end; - bvtOBJECT:begin -{$ifdef BESENSingleStringType} - writeit(TBESEN(Instance).ToStr(v)); -{$else} - writeit(WideString(BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(v)),UTF_8,BESENLocaleCharset))); -{$endif} - end; - bvtREFERENCE:begin - writeit('reference'); - end; - end; -{$ifdef Delphi2009AndUp} - writeln(fOutput); -{$else} - writeln(BESENUTF16ToUTF8(fOutput)); -{$endif} -end; - -var FileName,s:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - ss:widestring; - v:TBESENValue; - i:integer; - c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}; - Compatibility:longword; - ObjDocument,ObjNavigator,ObjShell,ObjWindow:TBESENObject; -begin -{$ifdef cpu386} - Set8087CW($133f); -{$endif} -{$ifdef cpuamd64} - Set8087CW($133f); -{$endif} - DoExit:=false; - FileName:=''; - Compatibility:=COMPAT_BESEN; - if paramcount>0 then begin - for i:=1 to paramcount do begin - s:={$ifndef BESENSingleStringType}AnsiString({$endif}paramstr(i){$ifndef BESENSingleStringType}){$endif}; - if length(s)>0 then begin - case s[1] of - '-','+','/':begin - c:=s[1]; - if c='-' then begin - end; - delete(s,1,1); - if (s='?') or (s='h') or (s='help') then begin - writeln('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'); - writeln('Usage: ',ExtractFileName(paramstr(0)),' [filename] [options]'); - writeln('Options: +help = This help text'); - writeln(' +javascript = Enable facile javascript compatibility mode'); - writeln(' +sgmlcom = Treat ''<!--'' as a ''//'' comment'); - writeln(' +unsafeutf8 = Accept ''valid but insecure'' UTF8'); - DoExit:=true; - end else if s='javascript' then begin - Compatibility:=Compatibility or COMPAT_JS; - end else if s='sgmlcom' then begin - Compatibility:=Compatibility or COMPAT_SGMLCOM; - end else if s='unsafeutf8' then begin - Compatibility:=Compatibility or COMPAT_UTF8_UNSAFE; - end; - end; - else begin - FileName:=s; - end; - end; - end; - end; - end; - ShellFunctions:=TShellFunctions.Create; - Instance:=TBESEN.Create(Compatibility); - TBESEN(Instance).RegExpDebugOutputHook:=ShellFunctions.RegExpDebugOutputHook; - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); - TBESEN(Instance).RegisterNativeObject('File',TFileObject); - - ObjDocument:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ObjDocument); - TBESEN(Instance).ObjectGlobal.OverwriteData('document',BESENObjectValue(ObjDocument),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjDocument.RegisterNativeFunction('write',ShellFunctions.NativePrint,1,[]); - ObjDocument.RegisterNativeFunction('writeln',ShellFunctions.NativePrintLn,1,[]); - - ObjNavigator:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ObjNavigator); - TBESEN(Instance).ObjectGlobal.OverwriteData('navigator',BESENObjectValue(ObjNavigator),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjNavigator.OverwriteData('userAgent',BESENStringValue('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux'),[bopaWRITABLE,bopaCONFIGURABLE]); - - ObjShell:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ObjShell); - TBESEN(Instance).ObjectGlobal.OverwriteData('Shell',BESENObjectValue(ObjShell),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjShell.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); - ObjShell.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); - ObjShell.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); - ObjShell.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); - ObjShell.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); - ObjShell.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); - ObjShell.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); - ObjShell.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); - ObjShell.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); - ObjShell.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); - ObjShell.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); - ObjShell.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); - ObjShell.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); - ObjShell.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); - ObjShell.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); - ObjShell.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); - ObjShell.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); - - ObjWindow:=TBESEN(Instance).ObjectGlobal; - TBESEN(Instance).ObjectGlobal.OverwriteData('window',BESENObjectValue(ObjWindow),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjDocument.OverwriteData('window',BESENObjectValue(TBESEN(Instance).ObjectGlobal),[bopaWRITABLE,bopaCONFIGURABLE]); - - try - try - if not DoExit then begin - TBESEN(Instance).InjectObject('console',{$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}BESENObjectConsoleSource{$ifndef BESENSingleStringType}){$endif}); - end; - except - on e:EBESENError do begin - writeln(e.Name,': ',e.Message); - end; - on e:exception do begin - writeln('Exception: ',e.Message); - end; - end; - if length(FileName)>0 then begin - try - if not DoExit then begin - v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}BESENGetFileContent(FileName){$ifndef BESENSingleStringType}){$endif}); - Print(v); - end; - except - on e:EBESENError do begin - writeln(e.Name,': ',e.Message); - end; - on e:exception do begin - writeln('Exception: ',e.Message); - end; - end; - end else begin - v.ValueType:=bvtUNDEFINED; - v.Obj:=nil; - while not DoExit do begin - write('>'); - readln(ss); - try - v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}ss{$ifndef BESENSingleStringType}){$endif}); - if not DoExit then begin - Print(v); - v.ValueType:=bvtUNDEFINED; - v.Obj:=nil; - TBESEN(Instance).GarbageCollector.CollectAll; - end; - except - on e:EBESENError do begin - writeln(e.Name,'(',TBESEN(Instance).LineNumber,'): ',e.Message); - end; - on e:exception do begin - writeln('Exception(',TBESEN(Instance).LineNumber,'): ',e.Message); - end; - end; - end; - end; - except - on e:exception do begin - writeln(e.Message); - end; - end; - FileName:=''; - s:=''; - ShellFunctions.Destroy; - TBESEN(Instance).Destroy; -end. diff --git a/3rd/besen/src/BESENShell.dproj b/3rd/besen/src/BESENShell.dproj deleted file mode 100644 index 0c8081b54..000000000 --- a/3rd/besen/src/BESENShell.dproj +++ /dev/null @@ -1,214 +0,0 @@ -<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{64B522E5-F0C1-47B8-BF9A-FB051D6D623B}</ProjectGuid> - <MainSource>BESENShell.dpr</MainSource> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Release</Config> - <TargetedPlatforms>1</TargetedPlatforms> - <AppType>Console</AppType> - <FrameworkType>None</FrameworkType> - <ProjectVersion>14.3</ProjectVersion> - <Platform Condition="'$(Platform)'==''">Win32</Platform> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_ImageBase>00400000</DCC_ImageBase> - <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)</DCC_Namespace> - <DCC_SymbolReferenceInfo>1</DCC_SymbolReferenceInfo> - <DCC_F>false</DCC_F> - <DCC_K>false</DCC_K> - <VerInfo_Locale>1031</VerInfo_Locale> - <DCC_N>true</DCC_N> - <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <DCC_E>false</DCC_E> - <DCC_S>false</DCC_S> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <DCC_Namespace>System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> - <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <VerInfo_Locale>1033</VerInfo_Locale> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - <DCC_DebugInformation>false</DCC_DebugInformation> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_Optimize>false</DCC_Optimize> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <DCCReference Include="BESEN.pas"/> - <DCCReference Include="BESENCodeSnapshot.pas"/> - <DCCReference Include="BESENVersionConstants.pas"/> - <DCCReference Include="BESENConstants.pas"/> - <DCCReference Include="BESENValueContainer.pas"/> - <DCCReference Include="BESENUnicodeTables.pas"/> - <DCCReference Include="BESENStringUtils.pas"/> - <DCCReference Include="BESENStringTree.pas"/> - <DCCReference Include="BESENStringList.pas"/> - <DCCReference Include="BESENSelfBalancedTree.pas"/> - <DCCReference Include="BESENScope.pas"/> - <DCCReference Include="BESENRegExpCache.pas"/> - <DCCReference Include="BESENRandomGenerator.pas"/> - <DCCReference Include="BESENPointerSelfBalancedTree.pas"/> - <DCCReference Include="BESENPointerList.pas"/> - <DCCReference Include="BESENParser.pas"/> - <DCCReference Include="BESENOpcodes.pas"/> - <DCCReference Include="BESENObjectThrowTypeErrorFunction.pas"/> - <DCCReference Include="BESENObjectStringPrototype.pas"/> - <DCCReference Include="BESENObjectStringConstructor.pas"/> - <DCCReference Include="BESENObjectString.pas"/> - <DCCReference Include="BESENObjectRegExpPrototype.pas"/> - <DCCReference Include="BESENObjectRegExpConstructor.pas"/> - <DCCReference Include="BESENObjectRegExp.pas"/> - <DCCReference Include="BESENObjectPrototype.pas"/> - <DCCReference Include="BESENObjectPropertyDescriptor.pas"/> - <DCCReference Include="BESENObjectNumberPrototype.pas"/> - <DCCReference Include="BESENObjectNumberConstructor.pas"/> - <DCCReference Include="BESENObjectNumber.pas"/> - <DCCReference Include="BESENObjectNativeFunction.pas"/> - <DCCReference Include="BESENObjectMath.pas"/> - <DCCReference Include="BESENObjectJSON.pas"/> - <DCCReference Include="BESENObjectGlobal.pas"/> - <DCCReference Include="BESENObjectFunctionPrototype.pas"/> - <DCCReference Include="BESENObjectFunctionConstructor.pas"/> - <DCCReference Include="BESENObjectFunctionArguments.pas"/> - <DCCReference Include="BESENObjectFunction.pas"/> - <DCCReference Include="BESENObjectErrorPrototype.pas"/> - <DCCReference Include="BESENObjectErrorConstructor.pas"/> - <DCCReference Include="BESENObjectError.pas"/> - <DCCReference Include="BESENObjectEnvironmentRecord.pas"/> - <DCCReference Include="BESENObjectDeclaredFunction.pas"/> - <DCCReference Include="BESENObjectDatePrototype.pas"/> - <DCCReference Include="BESENObjectDateConstructor.pas"/> - <DCCReference Include="BESENObjectDate.pas"/> - <DCCReference Include="BESENObjectConstructor.pas"/> - <DCCReference Include="BESENObjectBooleanPrototype.pas"/> - <DCCReference Include="BESENObjectBooleanConstructor.pas"/> - <DCCReference Include="BESENObjectBoolean.pas"/> - <DCCReference Include="BESENObjectBindingFunction.pas"/> - <DCCReference Include="BESENObjectArrayPrototype.pas"/> - <DCCReference Include="BESENObjectArrayConstructor.pas"/> - <DCCReference Include="BESENObjectArray.pas"/> - <DCCReference Include="BESENObjectArgSetterFunction.pas"/> - <DCCReference Include="BESENObjectArgGetterFunction.pas"/> - <DCCReference Include="BESENObject.pas"/> - <DCCReference Include="BESENNumberUtils.pas"/> - <DCCReference Include="BESENNativeObject.pas"/> - <DCCReference Include="BESENNativeCodeMemoryManager.pas"/> - <DCCReference Include="BESENLocale.pas"/> - <DCCReference Include="BESENLexicalEnvironment.pas"/> - <DCCReference Include="BESENLexer.pas"/> - <DCCReference Include="BESENKeyIDManager.pas"/> - <DCCReference Include="BESENIntegerList.pas"/> - <DCCReference Include="BESENInt64SelfBalancedTree.pas"/> - <DCCReference Include="BESENHashUtils.pas"/> - <DCCReference Include="BESENHashMap.pas"/> - <DCCReference Include="BESENGlobals.pas"/> - <DCCReference Include="BESENGarbageCollector.pas"/> - <DCCReference Include="BESENEvalCacheItem.pas"/> - <DCCReference Include="BESENEvalCache.pas"/> - <DCCReference Include="BESENErrors.pas"/> - <DCCReference Include="BESENEnvironmentRecord.pas"/> - <DCCReference Include="BESENDoubleList.pas"/> - <DCCReference Include="BESENDecompiler.pas"/> - <DCCReference Include="BESENDeclarativeEnvironmentRecord.pas"/> - <DCCReference Include="BESENDateUtils.pas"/> - <DCCReference Include="BESENCompiler.pas"/> - <DCCReference Include="BESENCollectorObject.pas"/> - <DCCReference Include="BESENCollector.pas"/> - <DCCReference Include="BESENCharset.pas"/> - <DCCReference Include="BESENBaseObject.pas"/> - <DCCReference Include="BESENArrayUtils.pas"/> - <DCCReference Include="BESENTypes.pas"/> - <DCCReference Include="BESENUtils.pas"/> - <DCCReference Include="BESENValue.pas"/> - <DCCReference Include="BESENRegExp.pas"/> - <DCCReference Include="BESENCode.pas"/> - <DCCReference Include="BESENASTNodes.pas"/> - <DCCReference Include="BESENCodeContext.pas"/> - <DCCReference Include="BESENCodeGeneratorContext.pas"/> - <DCCReference Include="BESENContext.pas"/> - <DCCReference Include="BESENObjectConsole.pas"/> - <BuildConfiguration Include="Debug"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Release"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType>VCLApplication</Borland.ProjectType> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">BESENShell.dpr</Source> - </Source> - <VersionInfo> - <VersionInfo Name="IncludeVerInfo">False</VersionInfo> - <VersionInfo Name="AutoIncBuild">False</VersionInfo> - <VersionInfo Name="MajorVer">1</VersionInfo> - <VersionInfo Name="MinorVer">0</VersionInfo> - <VersionInfo Name="Release">0</VersionInfo> - <VersionInfo Name="Build">0</VersionInfo> - <VersionInfo Name="Debug">False</VersionInfo> - <VersionInfo Name="PreRelease">False</VersionInfo> - <VersionInfo Name="Special">False</VersionInfo> - <VersionInfo Name="Private">False</VersionInfo> - <VersionInfo Name="DLL">False</VersionInfo> - <VersionInfo Name="Locale">1031</VersionInfo> - <VersionInfo Name="CodePage">1252</VersionInfo> - </VersionInfo> - <VersionInfoKeys> - <VersionInfoKeys Name="CompanyName"/> - <VersionInfoKeys Name="FileDescription"/> - <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> - <VersionInfoKeys Name="InternalName"/> - <VersionInfoKeys Name="LegalCopyright"/> - <VersionInfoKeys Name="LegalTrademarks"/> - <VersionInfoKeys Name="OriginalFilename"/> - <VersionInfoKeys Name="ProductName"/> - <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> - <VersionInfoKeys Name="Comments"/> - </VersionInfoKeys> - </Delphi.Personality> - <Platforms> - <Platform value="OSX32">False</Platform> - <Platform value="Win32">True</Platform> - <Platform value="Win64">False</Platform> - </Platforms> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> -</Project> diff --git a/3rd/besen/src/BESENShell.lpi b/3rd/besen/src/BESENShell.lpi deleted file mode 100644 index 35cf14b20..000000000 --- a/3rd/besen/src/BESENShell.lpi +++ /dev/null @@ -1,113 +0,0 @@ -<?xml version="1.0"?> -<CONFIG> - <ProjectOptions> - <PathDelim Value="\"/> - <Version Value="7"/> - <General> - <Flags> - <MainUnitHasCreateFormStatements Value="False"/> - <MainUnitHasTitleStatement Value="False"/> - <UseDefaultCompilerOptions Value="True"/> - </Flags> - <MainUnit Value="0"/> - <TargetFileExt Value=".exe"/> - <ResourceType Value="res"/> - <UseXPManifest Value="True"/> - <ActiveWindowIndexAtStart Value="0"/> - </General> - <VersionInfo> - <Language Value=""/> - <CharSet Value=""/> - <StringTable Comments="" CompanyName="" FileDescription="" FileVersion="" InternalName="" LegalCopyright="" LegalTrademarks="" OriginalFilename="" ProductName="" ProductVersion=""/> - </VersionInfo> - <PublishOptions> - <Version Value="2"/> - <IgnoreBinaries Value="False"/> - <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/> - <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/> - </PublishOptions> - <RunParams> - <local> - <FormatVersion Value="1"/> - <CommandLineParams Value="bl3.js"/> - <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/> - </local> - </RunParams> - <Units Count="2"> - <Unit0> - <Filename Value="BESENShell.lpr"/> - <IsPartOfProject Value="True"/> - <UnitName Value="BESENShell"/> - <IsVisibleTab Value="True"/> - <EditorIndex Value="0"/> - <WindowIndex Value="0"/> - <TopLine Value="135"/> - <CursorPos X="1" Y="163"/> - <UsageCount Value="20"/> - <Loaded Value="True"/> - <DefaultSyntaxHighlighter Value="Delphi"/> - </Unit0> - <Unit1> - <Filename Value="BESEN.pas"/> - <IsPartOfProject Value="True"/> - <UnitName Value="BESEN"/> - <WindowIndex Value="0"/> - <TopLine Value="1779"/> - <CursorPos X="62" Y="1827"/> - <UsageCount Value="20"/> - <DefaultSyntaxHighlighter Value="Delphi"/> - </Unit1> - </Units> - <JumpHistory Count="0" HistoryIndex="-1"/> - </ProjectOptions> - <CompilerOptions> - <Version Value="8"/> - <PathDelim Value="\"/> - <Target> - <Filename Value="BESENShell"/> - </Target> - <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)\"/> - <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Parsing> - <SyntaxOptions> - <SyntaxMode Value="Delphi"/> - <UseAnsiStrings Value="True"/> - </SyntaxOptions> - </Parsing> - <Linking> - <Debugging> - <GenerateDebugInfo Value="True"/> - </Debugging> - </Linking> - <Other> - <CompilerPath Value="$(CompPath)"/> - </Other> - </CompilerOptions> - <Debugging> - <Exceptions Count="7"> - <Item1> - <Name Value="EAbort"/> - </Item1> - <Item2> - <Name Value="ECodetoolError"/> - </Item2> - <Item3> - <Name Value="EFOpenError"/> - </Item3> - <Item4> - <Name Value="EBesenTypeError"/> - </Item4> - <Item5> - <Name Value="EBesenReferenceError"/> - </Item5> - <Item6> - <Name Value="EBesenSyntaxError"/> - </Item6> - <Item7> - <Name Value="EBesenThrowException"/> - </Item7> - </Exceptions> - </Debugging> -</CONFIG> diff --git a/3rd/besen/src/BESENShell.lpr b/3rd/besen/src/BESENShell.lpr deleted file mode 100644 index f0e0ddc0a..000000000 --- a/3rd/besen/src/BESENShell.lpr +++ /dev/null @@ -1,942 +0,0 @@ -program BESENShell; -{$i BESEN.inc} -{$ifdef win32} - {$apptype console} -{$endif} - -uses -{$ifdef fpc} -{$ifdef win32} - Windows, -{$endif} -{$else} -{$ifdef win32} -// FastMM4, - Windows, -{$endif} -{$endif} - SysUtils, - Classes, - BESEN in 'BESEN.pas', - BESENCodeSnapshot in 'BESENCodeSnapshot.pas', - BESENVersionConstants in 'BESENVersionConstants.pas', - BESENConstants in 'BESENConstants.pas', - BESENValueContainer in 'BESENValueContainer.pas', - BESENUnicodeTables in 'BESENUnicodeTables.pas', - BESENStringUtils in 'BESENStringUtils.pas', - BESENStringTree in 'BESENStringTree.pas', - BESENStringList in 'BESENStringList.pas', - BESENSelfBalancedTree in 'BESENSelfBalancedTree.pas', - BESENScope in 'BESENScope.pas', - BESENRegExpCache in 'BESENRegExpCache.pas', - BESENRandomGenerator in 'BESENRandomGenerator.pas', - BESENPointerSelfBalancedTree in 'BESENPointerSelfBalancedTree.pas', - BESENPointerList in 'BESENPointerList.pas', - BESENParser in 'BESENParser.pas', - BESENOpcodes in 'BESENOpcodes.pas', - BESENObjectThrowTypeErrorFunction in 'BESENObjectThrowTypeErrorFunction.pas', - BESENObjectStringPrototype in 'BESENObjectStringPrototype.pas', - BESENObjectStringConstructor in 'BESENObjectStringConstructor.pas', - BESENObjectString in 'BESENObjectString.pas', - BESENObjectRegExpPrototype in 'BESENObjectRegExpPrototype.pas', - BESENObjectRegExpConstructor in 'BESENObjectRegExpConstructor.pas', - BESENObjectRegExp in 'BESENObjectRegExp.pas', - BESENObjectPrototype in 'BESENObjectPrototype.pas', - BESENObjectPropertyDescriptor in 'BESENObjectPropertyDescriptor.pas', - BESENObjectNumberPrototype in 'BESENObjectNumberPrototype.pas', - BESENObjectNumberConstructor in 'BESENObjectNumberConstructor.pas', - BESENObjectNumber in 'BESENObjectNumber.pas', - BESENObjectNativeFunction in 'BESENObjectNativeFunction.pas', - BESENObjectMath in 'BESENObjectMath.pas', - BESENObjectJSON in 'BESENObjectJSON.pas', - BESENObjectGlobal in 'BESENObjectGlobal.pas', - BESENObjectFunctionPrototype in 'BESENObjectFunctionPrototype.pas', - BESENObjectFunctionConstructor in 'BESENObjectFunctionConstructor.pas', - BESENObjectFunctionArguments in 'BESENObjectFunctionArguments.pas', - BESENObjectFunction in 'BESENObjectFunction.pas', - BESENObjectErrorPrototype in 'BESENObjectErrorPrototype.pas', - BESENObjectErrorConstructor in 'BESENObjectErrorConstructor.pas', - BESENObjectError in 'BESENObjectError.pas', - BESENObjectEnvironmentRecord in 'BESENObjectEnvironmentRecord.pas', - BESENObjectDeclaredFunction in 'BESENObjectDeclaredFunction.pas', - BESENObjectDatePrototype in 'BESENObjectDatePrototype.pas', - BESENObjectDateConstructor in 'BESENObjectDateConstructor.pas', - BESENObjectDate in 'BESENObjectDate.pas', - BESENObjectConstructor in 'BESENObjectConstructor.pas', - BESENObjectBooleanPrototype in 'BESENObjectBooleanPrototype.pas', - BESENObjectBooleanConstructor in 'BESENObjectBooleanConstructor.pas', - BESENObjectBoolean in 'BESENObjectBoolean.pas', - BESENObjectBindingFunction in 'BESENObjectBindingFunction.pas', - BESENObjectArrayPrototype in 'BESENObjectArrayPrototype.pas', - BESENObjectArrayConstructor in 'BESENObjectArrayConstructor.pas', - BESENObjectArray in 'BESENObjectArray.pas', - BESENObjectArgSetterFunction in 'BESENObjectArgSetterFunction.pas', - BESENObjectArgGetterFunction in 'BESENObjectArgGetterFunction.pas', - BESENObject in 'BESENObject.pas', - BESENNumberUtils in 'BESENNumberUtils.pas', - BESENNativeObject in 'BESENNativeObject.pas', - BESENNativeCodeMemoryManager in 'BESENNativeCodeMemoryManager.pas', - BESENLocale in 'BESENLocale.pas', - BESENLexicalEnvironment in 'BESENLexicalEnvironment.pas', - BESENLexer in 'BESENLexer.pas', - BESENKeyIDManager in 'BESENKeyIDManager.pas', - BESENIntegerList in 'BESENIntegerList.pas', - BESENInt64SelfBalancedTree in 'BESENInt64SelfBalancedTree.pas', - BESENHashUtils in 'BESENHashUtils.pas', - BESENHashMap in 'BESENHashMap.pas', - BESENGlobals in 'BESENGlobals.pas', - BESENGarbageCollector in 'BESENGarbageCollector.pas', - BESENEvalCacheItem in 'BESENEvalCacheItem.pas', - BESENEvalCache in 'BESENEvalCache.pas', - BESENErrors in 'BESENErrors.pas', - BESENEnvironmentRecord in 'BESENEnvironmentRecord.pas', - BESENDoubleList in 'BESENDoubleList.pas', - BESENDecompiler in 'BESENDecompiler.pas', - BESENDeclarativeEnvironmentRecord in 'BESENDeclarativeEnvironmentRecord.pas', - BESENDateUtils in 'BESENDateUtils.pas', - BESENCompiler in 'BESENCompiler.pas', - BESENCollectorObject in 'BESENCollectorObject.pas', - BESENCollector in 'BESENCollector.pas', - BESENCharset in 'BESENCharset.pas', - BESENBaseObject in 'BESENBaseObject.pas', - BESENArrayUtils in 'BESENArrayUtils.pas', - BESENTypes in 'BESENTypes.pas', - BESENUtils in 'BESENUtils.pas', - BESENValue in 'BESENValue.pas', - BESENRegExp in 'BESENRegExp.pas', - BESENCode in 'BESENCode.pas', - BESENASTNodes in 'BESENASTNodes.pas', - BESENCodeContext in 'BESENCodeContext.pas', - BESENCodeGeneratorContext in 'BESENCodeGeneratorContext.pas', - BESENContext in 'BESENContext.pas', - BESENObjectConsole in 'BESENObjectConsole.pas'; - -type TShellFunctions=class - procedure RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); - procedure NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - end; - - TFileObject=class(TBESENNativeObject) - private - fFileName:TBESENString; - fFileStream:TFileStream; - protected - procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); override; - procedure InitializeObject; override; - procedure FinalizeObject; override; - public - constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); override; - destructor Destroy; override; - published - procedure close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - procedure flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); - property fileName:TBESENString read fFileName write fFileName; - end; - -var Instance:TBESEN; - ShellFunctions:TShellFunctions; - DoExit:boolean; - -constructor TFileObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); -begin - inherited Create(AInstance,APrototype,AHasPrototypeProperty); - fFileStream:=nil; -end; - -destructor TFileObject.Destroy; -begin - BesenFreeAndNil(fFileStream); - inherited Destroy; -end; - -procedure TFileObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); -var s:string; - Mode:longword; -begin - inherited ConstructObject(ThisArgument,Arguments,CountArguments); - if CountArguments=0 then begin - raise EBESENError.Create('FileError','Too few arguments'); - end else begin - fFileName:=TBESEN(Instance).ToStr(Arguments^[0]^); - if FileExists(fFileName) then begin - Mode:=fmOpenReadWrite or fmShareExclusive; - end else begin - Mode:=fmCreate or fmShareDenyRead; - end; - if CountArguments>1 then begin - s:=TBESEN(Instance).ToStr(Arguments^[1]^); - if s='c' then begin - Mode:=fmCreate or fmShareDenyRead; - end else if s='r' then begin - Mode:=fmOpenRead or fmShareDenyWrite; - end else if s='rw' then begin - Mode:=fmOpenReadWrite or fmShareExclusive; - end else if s='w' then begin - if FileExists(fFileName) then begin - Mode:=fmOpenWrite or fmShareDenyRead; - end else begin - Mode:=fmCreate or fmShareDenyRead; - end; - end; - end; -{$ifdef BESENSingleStringType} - fFileStream:=TFileStream.Create(fFileName,Mode); -{$else} - fFileStream:=TFileStream.Create(String(BESENEncodeString(BESENUTF16ToUTF8(fFileName),UTF_8,BESENLocaleCharset)),Mode); -{$endif} - end; - s:=''; -end; - -procedure TFileObject.InitializeObject; -begin - inherited InitializeObject; - fFileName:=''; - fFileStream:=nil; -end; - -procedure TFileObject.FinalizeObject; -begin - BesenFreeAndNil(fFileStream); - inherited FinalizeObject; -end; - -procedure TFileObject.close(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - BesenFreeAndNil(fFileStream); -end; - -procedure TFileObject.read(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var l,ms:int64; - s:string; -begin - s:=''; - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ms:=fFileStream.Size-fFileStream.Position; - if CountArguments=0 then begin - l:=ms; - end else begin - if Arguments^[0]^.ValueType=bvtUNDEFINED then begin - l:=ms; - end else begin - l:=TBESEN(Instance).ToInt(Arguments^[0]^); - if l>ms then begin - l:=ms; - end; - end; - end; - SetLength(s,l); - if l>0 then begin - fFileStream.Read(s[1],l); - end; - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:=s; - SetLength(s,0); - end; -end; - -procedure TFileObject.write(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var l:int64; - s:string; -begin - s:=''; - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - if CountArguments>0 then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=0; - s:=TBESEN(Instance).ToStr(Arguments^[0]^); - l:=length(s); - if l>0 then begin - ResultValue.Num:=fFileStream.Write(s[1],l); - end; - SetLength(s,0); - end; - end; -end; - -procedure TFileObject.seek(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var l,ms:int64; -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ms:=fFileStream.Size; - if CountArguments=0 then begin - l:=fFileStream.Position; - end else begin - if Arguments^[0]^.ValueType=bvtUNDEFINED then begin - l:=fFileStream.Position; - end else begin - l:=TBESEN(Instance).ToInt(Arguments^[0]^); - if l>ms then begin - l:=ms; - end; - end; - end; - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=fFileStream.Seek(l,soFromBeginning); - end; -end; - -procedure TFileObject.position(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=fFileStream.Position; - end; -end; - -procedure TFileObject.eof(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin - ResultValue.ValueType:=bvtBOOLEAN; - ResultValue.Bool:=fFileStream.Position<fFileStream.Size; - end; -end; - -procedure TFileObject.flush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if assigned(fFileStream) then begin -{$ifdef win32} - Windows.FlushFileBuffers(fFileStream.Handle); -{$endif} - end; -end; - -procedure TShellFunctions.RegExpDebugOutputHook(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN); -begin - if NewLine then begin - writeln(Data); - end else begin - write(Data); - end; -end; - -procedure TShellFunctions.NativeSetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if CountArguments>0 then begin - Instance.RegExpDebug:=Instance.ToUINT32(Arguments^[0]^); - end; -end; - -procedure TShellFunctions.NativeGetRegExpDebugMode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=Instance.RegExpDebug; -end; - -procedure TShellFunctions.NativeSetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - if CountArguments>0 then begin - Instance.RegExpTimeOutSteps:=Instance.ToINT(Arguments^[0]^); - end; -end; - -procedure TShellFunctions.NativeGetRegExpTimeOutSteps(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtNUMBER; - ResultValue.Num:=Instance.RegExpTimeOutSteps; -end; - -procedure TShellFunctions.NativePrint(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var i:integer; - v:PBESENValue; - fOutput:widestring; - procedure writeit(s:widestring); - begin - fOutput:=fOutput+s; - end; -begin - fOutput:=''; - ResultValue.ValueType:=bvtUNDEFINED; - for i:=0 to CountArguments-1 do begin - v:=Arguments^[i]; - case v^.ValueType of - bvtUNDEFINED:begin - writeit('undefined'); - end; - bvtNULL:begin - writeit('null'); - end; - bvtBOOLEAN:begin - if v^.Bool then begin - writeit('true'); - end else begin - writeit('false'); - end; - end; - bvtNUMBER:begin - writeit(BESENFloatToStr(v^.Num)); - end; - bvtSTRING:begin - writeit(v^.Str); - end; - bvtOBJECT:begin - writeit(TBESEN(Instance).ToStr(v^)); - end; - bvtREFERENCE:begin - writeit('reference'); - end; - end; - end; -{$ifdef Delphi2009AndUp} - writeln(fOutput); -{$else} - writeln(BESENEncodeString(BESENUTF16ToUTF8(fOutput),UTF_8,BESENLocaleCharset)); -{$endif} -end; - -procedure TShellFunctions.NativePrintLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - NativePrint(ThisArgument,Arguments,CountArguments,ResultValue); - writeln; -end; - -procedure TShellFunctions.NativeReadLn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var s:string; -begin - readln(s); -{$ifdef Delphi2009AndUp} - ResultValue:=BESENStringValue(s); -{$else} - ResultValue:=BESENStringLocaleCharsetValue(s); -{$endif} -end; - -procedure TShellFunctions.NativeTrace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - NativePrintLn(ThisArgument,Arguments,CountArguments,ResultValue); -end; - -procedure TShellFunctions.NativeAlert(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var i:integer; - v:PBESENValue; - ss:widestring; - procedure writeit(s:widestring); - begin - ss:=ss+s; - end; -begin - ss:=''; - ResultValue.ValueType:=bvtUNDEFINED; - for i:=0 to CountArguments-1 do begin - v:=Arguments^[i]; - case v^.ValueType of - bvtUNDEFINED:begin - writeit('undefined'); - end; - bvtNULL:begin - writeit('null'); - end; - bvtBOOLEAN:begin - if v^.Bool then begin - writeit('true'); - end else begin - writeit('false'); - end; - end; - bvtNUMBER:begin - writeit(BESENFloatToStr(v^.Num)); - end; - bvtSTRING:begin - writeit(v^.Str); - end; - bvtOBJECT:begin - writeit(TBESEN(Instance).ToStr(v^)); - end; - bvtREFERENCE:begin - writeit('reference'); - end; - end; - end; -{$ifdef Delphi2009AndUp} - writeln(ss); -{$else} - writeln(BESENEncodeString(BESENUTF16ToUTF8(ss),UTF_8,BESENLocaleCharset)); -{$endif} -end; - -procedure TShellFunctions.NativePrompt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var ss:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - s:string; -begin - ss:=''; - try - if CountArguments>0 then begin -{$ifdef BESENSingleStringType} - ss:=TBESEN(Instance).ToStr(Arguments^[0]^); -{$else} - ss:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - end else begin - ss:=''; - end; -(* if CountArguments>1 then begin -{$ifdef BESENSingleStringType} - s:=TBESEN(Instance).ToStr(Arguments^[1]^); -{$else} - s:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)),UTF_8,BESENLocaleCharset); -{$endif} - end else begin - s:=''; - end;*) - write(ss); - readln(s); -{$ifdef Delphi2009AndUp} - ResultValue:=BESENStringValue(s); -{$else} - ResultValue:=BESENStringLocaleCharsetValue(s); -{$endif} - finally - end; -end; - -procedure TShellFunctions.NativeExit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - DoExit:=true; -end; - -procedure TShellFunctions.NativeReadFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - fm:byte; - f:file; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>0 then begin -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - Content:=''; - fm:=filemode; - filemode:=0; - assignfile(f,String(FileName)); - {$i-}reset(f,1);{$i+}; - if ioresult=0 then begin - SetLength(Content,filesize(f)); - if length(Content)>0 then begin - {$i-}blockread(f,Content[1],length(Content));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); - exit; - end; - end; - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:={$ifndef BESENSingleStringType}BESENUTF8ToUTF16(BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType})){$endif}; - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - end else begin - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t read file "'+String(FileName)+'"'); - end; - end else begin - raise EBESENError.Create('FileError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeWriteFile(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - fm:byte; - f:file; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>1 then begin -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); - Content:=TBESEN(Instance).ToStr(Arguments^[1]^); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); - Content:=#$ef#$bb#$bf+BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[1]^)); -{$endif} - fm:=filemode; - filemode:=2; - assignfile(f,String(FileName)); - {$i-}rewrite(f,1);{$i+}; - if ioresult=0 then begin - if length(Content)>0 then begin - {$i-}blockwrite(f,Content[1],length(Content));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); - exit; - end; - end; - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - end else begin - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t write file "'+String(FileName)+'"'); - end; - end else begin - raise EBESENError.Create('FileError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeReadDirectory(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -const BoolStr:array[boolean] of {$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}=('false','true'); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - SearchRec:TSearchRec; - Count:integer; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>0 then begin - Content:='['; -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - if FindFirst(String(FileName),faAnyFile or faDirectory,SearchRec)=0 then begin - Count:=0; - repeat - if Count>0 then begin - Content:=Content+','; - end; - Content:=Content+'{'; - Content:=Content+'"name":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENJSONStringQuote(BESENUTF8ToUTF16(BESENEncodeString(AnsiString(SearchRec.Name),BESENLocaleCharset,UTF_8))))+','; - Content:=Content+'"size":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(IntToStr(SearchRec.Size))+','; - Content:=Content+'"time":'+{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}(BESENFloatToStr(BESENDateTimeToBESENDate(FileDateToDateTime(SearchRec.Time))))+','; - Content:=Content+'"flags":{'; - Content:=Content+'"hidden":'+BoolStr[(SearchRec.Attr and faHidden)<>0]+','; - Content:=Content+'"systemFile":'+BoolStr[(SearchRec.Attr and faSysFile)<>0]+','; - Content:=Content+'"volumeID":'+BoolStr[(SearchRec.Attr and faVolumeID)<>0]+','; - Content:=Content+'"directory":'+BoolStr[(SearchRec.Attr and faDirectory)<>0]+','; - Content:=Content+'"archive":'+BoolStr[(SearchRec.Attr and faArchive)<>0]+''; - Content:=Content+'}}'; - inc(Count); - until FindNext(SearchRec)<>0; - FindClose(SearchRec); - end; - Content:=Content+']'; - ResultValue:=TBESEN(Instance).JSONEval(Content); - end else begin - raise EBESENError.Create('DirectoryError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeLoad(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -var FileName,Content:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - fm:byte; - f:file; -begin - ResultValue.ValueType:=bvtUNDEFINED; - try - if CountArguments>0 then begin -{$ifdef BESENSingleStringType} - FileName:=TBESEN(Instance).ToStr(Arguments^[0]^)); -{$else} - FileName:=BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(Arguments^[0]^)),UTF_8,BESENLocaleCharset); -{$endif} - Content:=''; - fm:=filemode; - filemode:=0; - assignfile(f,string(FileName)); - {$i-}reset(f,1);{$i+}; - if ioresult=0 then begin - SetLength(Content,filesize(f)); - if length(Content)>0 then begin - {$i-}blockread(f,Content[1],length(Content));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); - exit; - end; - end; - ResultValue:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}Content{$ifndef BESENSingleStringType}){$endif}); - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - end else begin - {$i-}closefile(f);{$i+} - if ioresult=0 then begin - end; - filemode:=fm; - raise EBESENError.Create('FileError','Couldn''t load file "'+String(FileName)+'"'); - end; - end else begin - raise EBESENError.Create('FileError','Too few arguments'); - end; - finally - end; -end; - -procedure TShellFunctions.NativeGC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtUNDEFINED; - TBESEN(Instance).GarbageCollector.CollectAll; -end; - -procedure TShellFunctions.NativeVersion(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); -begin - ResultValue.ValueType:=bvtSTRING; - ResultValue.Str:='BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'; -end; - -procedure Print(const v:TBESENValue); -var fOutput:widestring; - procedure writeit(s:widestring); - begin - fOutput:=fOutput+s; - end; -begin - fOutput:=''; - case v.ValueType of - bvtUNDEFINED:begin - writeit('undefined'); - end; - bvtNULL:begin - writeit('null'); - end; - bvtBOOLEAN:begin - if v.Bool then begin - writeit('true'); - end else begin - writeit('false'); - end; - end; - bvtNUMBER:begin - writeit(BESENFloatToStr(v.Num)); - end; - bvtSTRING:begin - writeit(v.Str); - end; - bvtOBJECT:begin -{$ifdef BESENSingleStringType} - writeit(TBESEN(Instance).ToStr(v)); -{$else} - writeit(WideString(BESENEncodeString(BESENUTF16ToUTF8(TBESEN(Instance).ToStr(v)),UTF_8,BESENLocaleCharset))); -{$endif} - end; - bvtREFERENCE:begin - writeit('reference'); - end; - end; -{$ifdef Delphi2009AndUp} - writeln(fOutput); -{$else} - writeln(BESENUTF16ToUTF8(fOutput)); -{$endif} -end; - -var FileName,s:{$ifdef BESENSingleStringType}TBESENString{$else}ansistring{$endif}; - ss:widestring; - v:TBESENValue; - i:integer; - c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}; - Compatibility:longword; - ObjDocument,ObjNavigator,ObjShell,ObjWindow:TBESENObject; -begin -{$ifdef cpu386} - Set8087CW($133f); -{$endif} -{$ifdef cpuamd64} - Set8087CW($133f); -{$endif} - DoExit:=false; - FileName:=''; - Compatibility:=COMPAT_BESEN; - if paramcount>0 then begin - for i:=1 to paramcount do begin - s:={$ifndef BESENSingleStringType}AnsiString({$endif}paramstr(i){$ifndef BESENSingleStringType}){$endif}; - if length(s)>0 then begin - case s[1] of - '-','+','/':begin - c:=s[1]; - if c='-' then begin - end; - delete(s,1,1); - if (s='?') or (s='h') or (s='help') then begin - writeln('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010-2015, Benjamin ''BeRo'' Rosseaux'); - writeln('Usage: ',ExtractFileName(paramstr(0)),' [filename] [options]'); - writeln('Options: +help = This help text'); - writeln(' +javascript = Enable facile javascript compatibility mode'); - writeln(' +sgmlcom = Treat ''<!--'' as a ''//'' comment'); - writeln(' +unsafeutf8 = Accept ''valid but insecure'' UTF8'); - DoExit:=true; - end else if s='javascript' then begin - Compatibility:=Compatibility or COMPAT_JS; - end else if s='sgmlcom' then begin - Compatibility:=Compatibility or COMPAT_SGMLCOM; - end else if s='unsafeutf8' then begin - Compatibility:=Compatibility or COMPAT_UTF8_UNSAFE; - end; - end; - else begin - FileName:=s; - end; - end; - end; - end; - end; - ShellFunctions:=TShellFunctions.Create; - Instance:=TBESEN.Create(Compatibility); - TBESEN(Instance).RegExpDebugOutputHook:=ShellFunctions.RegExpDebugOutputHook; - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); - TBESEN(Instance).ObjectGlobal.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); - TBESEN(Instance).RegisterNativeObject('File',TFileObject); - - ObjDocument:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ObjDocument); - TBESEN(Instance).ObjectGlobal.OverwriteData('document',BESENObjectValue(ObjDocument),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjDocument.RegisterNativeFunction('write',ShellFunctions.NativePrint,1,[]); - ObjDocument.RegisterNativeFunction('writeln',ShellFunctions.NativePrintLn,1,[]); - - ObjNavigator:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ObjNavigator); - TBESEN(Instance).ObjectGlobal.OverwriteData('navigator',BESENObjectValue(ObjNavigator),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjNavigator.OverwriteData('userAgent',BESENStringValue('BESEN Shell v'+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux'),[bopaWRITABLE,bopaCONFIGURABLE]); - - ObjShell:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); - TBESEN(Instance).GarbageCollector.Add(ObjShell); - TBESEN(Instance).ObjectGlobal.OverwriteData('Shell',BESENObjectValue(ObjShell),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjShell.RegisterNativeFunction('setRegExpDebugMode',ShellFunctions.NativeSetRegExpDebugMode,1,[]); - ObjShell.RegisterNativeFunction('getRegExpDebugMode',ShellFunctions.NativeGetRegExpDebugMode,0,[]); - ObjShell.RegisterNativeFunction('setRegExpTimeOutSteps',ShellFunctions.NativeSetRegExpTimeOutSteps,1,[]); - ObjShell.RegisterNativeFunction('getRegExpTimeOutSteps',ShellFunctions.NativeGetRegExpTimeOutSteps,0,[]); - ObjShell.RegisterNativeFunction('print',ShellFunctions.NativePrint,1,[]); - ObjShell.RegisterNativeFunction('println',ShellFunctions.NativePrintLn,1,[]); - ObjShell.RegisterNativeFunction('readln',ShellFunctions.NativeReadLn,1,[]); - ObjShell.RegisterNativeFunction('trace',ShellFunctions.NativeTrace,1,[]); - ObjShell.RegisterNativeFunction('alert',ShellFunctions.NativeAlert,1,[]); - ObjShell.RegisterNativeFunction('prompt',ShellFunctions.NativePrompt,1,[]); - ObjShell.RegisterNativeFunction('exit',ShellFunctions.NativeExit,1,[]); - ObjShell.RegisterNativeFunction('readFile',ShellFunctions.NativeReadFile,1,[]); - ObjShell.RegisterNativeFunction('writeFile',ShellFunctions.NativeWriteFile,2,[]); - ObjShell.RegisterNativeFunction('readDirectory',ShellFunctions.NativeReadDirectory,1,[]); - ObjShell.RegisterNativeFunction('load',ShellFunctions.NativeLoad,1,[]); - ObjShell.RegisterNativeFunction('gc',ShellFunctions.NativeGC,0,[]); - ObjShell.RegisterNativeFunction('version',ShellFunctions.NativeVersion,0,[]); - - ObjWindow:=TBESEN(Instance).ObjectGlobal; - TBESEN(Instance).ObjectGlobal.OverwriteData('window',BESENObjectValue(ObjWindow),[bopaWRITABLE,bopaCONFIGURABLE]); - ObjDocument.OverwriteData('window',BESENObjectValue(TBESEN(Instance).ObjectGlobal),[bopaWRITABLE,bopaCONFIGURABLE]); - - try - try - if not DoExit then begin - TBESEN(Instance).InjectObject('console',{$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}BESENObjectConsoleSource{$ifndef BESENSingleStringType}){$endif}); - end; - except - on e:EBESENError do begin - writeln(e.Name,': ',e.Message); - end; - on e:exception do begin - writeln('Exception: ',e.Message); - end; - end; - if length(FileName)>0 then begin - try - if not DoExit then begin - v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENConvertToUTF8({$endif}BESENGetFileContent(FileName){$ifndef BESENSingleStringType}){$endif}); - Print(v); - end; - except - on e:EBESENError do begin - writeln(e.Name,': ',e.Message); - end; - on e:exception do begin - writeln('Exception: ',e.Message); - end; - end; - end else begin - v.ValueType:=bvtUNDEFINED; - v.Obj:=nil; - while not DoExit do begin - write('>'); - readln(ss); - try - v:=TBESEN(Instance).Execute({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}ss{$ifndef BESENSingleStringType}){$endif}); - if not DoExit then begin - Print(v); - v.ValueType:=bvtUNDEFINED; - v.Obj:=nil; - TBESEN(Instance).GarbageCollector.CollectAll; - end; - except - on e:EBESENError do begin - writeln(e.Name,'(',TBESEN(Instance).LineNumber,'): ',e.Message); - end; - on e:exception do begin - writeln('Exception(',TBESEN(Instance).LineNumber,'): ',e.Message); - end; - end; - end; - end; - except - on e:exception do begin - writeln(e.Message); - end; - end; - FileName:=''; - s:=''; - ShellFunctions.Destroy; - TBESEN(Instance).Destroy; -end. diff --git a/3rd/besen/src/BESENStringList.pas b/3rd/besen/src/BESENStringList.pas deleted file mode 100644 index 3abb6ef48..000000000 --- a/3rd/besen/src/BESENStringList.pas +++ /dev/null @@ -1,231 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENStringList; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -type PBESENStringArray=^TBESENStringArray; - TBESENStringArray=array[0..(2147483647 div sizeof(TBESENString))-1] of TBESENString; - - TBESENStringList=class - private - FCount,FSize:integer; - function GetItem(index:integer):TBESENString; - procedure SetItem(index:integer;Value:TBESENString); - public - FList:PBESENStringArray; - constructor Create; - destructor Destroy; override; - procedure Clear; - function Add(Item:TBESENString):integer; - procedure Insert(index:integer;Item:TBESENString); - procedure Delete(index:integer); - function Remove(Item:TBESENString):integer; - function Find(Item:TBESENString):integer; - function IndexOf(Item:TBESENString):integer; - procedure Exchange(Index1,Index2:integer); - procedure SetCapacity(NewCapacity:integer); - procedure SetCount(NewCount:integer); - property Count:integer read FCount; - property Capacity:integer read FSize write SetCapacity; - property Item[index:integer]:TBESENString read GetItem write SetItem; default; - property Items[index:integer]:TBESENString read GetItem write SetItem; - end; - -implementation - -constructor TBESENStringList.Create; -begin - inherited Create; - FCount:=0; - FSize:=0; - FList:=nil; - Clear; -end; - -destructor TBESENStringList.Destroy; -begin - Clear; - inherited Destroy; -end; - -procedure TBESENStringList.Clear; -var i:integer; -begin - for i:=0 to FSize-1 do begin - FList^[i]:=''; - end; - FCount:=0; - FSize:=0; - ReallocMem(FList,0); -end; - -procedure TBESENStringList.SetCapacity(NewCapacity:integer); -var i:integer; -begin - if (NewCapacity>=0) and (NewCapacity<high(TBESENStringArray)) then begin - NewCapacity:=(NewCapacity+256) and not 255; - if FSize<>NewCapacity then begin - if NewCapacity<FSize then begin - for i:=NewCapacity to FSize-1 do begin - FList^[i]:=''; - end; - end; - ReallocMem(FList,NewCapacity*sizeof(TBESENString)); - if FSize<NewCapacity then begin - FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(TBESENString),#0); - end; - FSize:=NewCapacity; - end; - end; -end; - -procedure TBESENStringList.SetCount(NewCount:integer); -var i:integer; -begin - if (NewCount>=0) and (NewCount<high(TBESENStringArray)) then begin - if NewCount<FCount then begin - for i:=NewCount to FCount-1 do begin - FList^[i]:=''; - end; - end; - SetCapacity(NewCount); - FCount:=NewCount; - end; -end; - -function TBESENStringList.Add(Item:TBESENString):integer; -begin - result:=FCount; - SetCount(FCount+1); - FList^[result]:=Item; -end; - -procedure TBESENStringList.Insert(index:integer;Item:TBESENString); -var I:integer; -begin - if (index>=0) and (index<FCount) then begin - SetCount(FCount+1); - for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; - FList^[index]:=Item; - end else if index=FCount then begin - Add(Item); - end else if index>FCount then begin - SetCount(index); - Add(Item); - end; -end; - -procedure TBESENStringList.Delete(index:integer); -var I,J,K:integer; -begin - if (index>=0) and (index<FCount) then begin - K:=FCount-1; - J:=index; - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - end; -end; - -function TBESENStringList.Remove(Item:TBESENString):integer; -var I,J,K:integer; -begin - result:=-1; - K:=FCount; - J:=-1; - for I:=0 to K-1 do begin - if FList^[I]=Item then begin - J:=I; - break; - end; - end; - if J>=0 then begin - dec(K); - for I:=J to K-1 do FList^[I]:=FList^[I+1]; - SetCount(K); - result:=J; - end; -end; - -function TBESENStringList.Find(Item:TBESENString):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -function TBESENStringList.IndexOf(Item:TBESENString):integer; -var I:integer; -begin - result:=-1; - for I:=0 to FCount-1 do begin - if FList^[I]=Item then begin - result:=I; - exit; - end; - end; -end; - -procedure TBESENStringList.Exchange(Index1,Index2:integer); -var TempString:TBESENString; -begin - if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin - TempString:=FList^[Index1]; - FList^[Index1]:=FList^[Index2]; - FList^[Index2]:=TempString; - end; -end; - -function TBESENStringList.GetItem(index:integer):TBESENString; -begin - if (index>=0) and (index<FCount) then begin - result:=FList^[index]; - end else begin - result:=''; - end; -end; - -procedure TBESENStringList.SetItem(index:integer;Value:TBESENString); -begin - if (index>=0) and (index<FCount) then begin - FList^[index]:=Value; - end; -end; - -end. diff --git a/3rd/besen/src/BESENStringTree.pas b/3rd/besen/src/BESENStringTree.pas deleted file mode 100644 index a3b2dcffd..000000000 --- a/3rd/besen/src/BESENStringTree.pas +++ /dev/null @@ -1,356 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENStringTree; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils; - -type TBESENStringTreeData=record - case boolean of - false:(i:int64); - true:(p:pointer); - end; - - PBESENStringTreeNode=^TBESENStringTreeNode; - TBESENStringTreeNode=record - TheChar:widechar; - Data:TBESENStringTreeData; - DataExist:longbool; - Previous,Next,Up,Down:PBESENStringTreeNode; - end; - - TBESENStringTree=class - public - Root:PBESENStringTreeNode; - function CreateBESENStringTreeNode(AChar:widechar):PBESENStringTreeNode; - procedure DestroyBESENStringTreeNode(Node:PBESENStringTreeNode); - public - constructor Create; - destructor Destroy; override; - procedure Clear; - procedure DumpTree; - procedure DumpList; - procedure AppendTo(DestBESENStringTree:TBESENStringTree); - procedure Optimize(DestBESENStringTree:TBESENStringTree); - function Add(Content:TBESENString;const Data:TBESENStringTreeData;Replace:boolean=false):boolean; - function Delete(Content:TBESENString):boolean; - function Find(Content:TBESENString;var Data:TBESENStringTreeData):boolean; - end; - -implementation - -constructor TBESENStringTree.Create; -begin - inherited Create; - Root:=nil; - Clear; -end; - -destructor TBESENStringTree.Destroy; -begin - Clear; - inherited Destroy; -end; - -function TBESENStringTree.CreateBESENStringTreeNode(AChar:widechar):PBESENStringTreeNode; -begin - getmem(result,sizeof(TBESENStringTreeNode)); - fillchar(result^.Data,sizeof(TBESENStringTreeData),#0); - result^.TheChar:=AChar; - result^.DataExist:=false; - result^.Previous:=nil; - result^.Next:=nil; - result^.Up:=nil; - result^.Down:=nil; -end; - -procedure TBESENStringTree.DestroyBESENStringTreeNode(Node:PBESENStringTreeNode); -begin - if not assigned(Node) then exit; - DestroyBESENStringTreeNode(Node^.Next); - DestroyBESENStringTreeNode(Node^.Down); - freemem(Node); -end; - -procedure TBESENStringTree.Clear; -begin - DestroyBESENStringTreeNode(Root); - Root:=nil; -end; - -procedure TBESENStringTree.DumpTree; -var Ident:integer; - procedure DumpNode(Node:PBESENStringTreeNode); - var SubNode:PBESENStringTreeNode; - IdentCounter,IdentOld:integer; - begin - for IdentCounter:=1 to Ident do write(' '); - write(Node^.TheChar); - IdentOld:=Ident; - SubNode:=Node^.Next; - while assigned(SubNode) do begin - write(SubNode^.TheChar); - if not assigned(SubNode^.Next) then break; - inc(Ident); - SubNode:=SubNode^.Next; - end; - writeln; - inc(Ident); - while assigned(SubNode) and (SubNode<>Node) do begin - if assigned(SubNode^.Down) then DumpNode(SubNode^.Down); - SubNode:=SubNode^.Previous; - dec(Ident); - end; - Ident:=IdentOld; - if assigned(Node^.Down) then DumpNode(Node^.Down); - end; -begin - Ident:=0; - DumpNode(Root); -end; - -procedure TBESENStringTree.DumpList; - procedure DumpNode(Node:PBESENStringTreeNode;const ParentStr:TBESENString); - var s:TBESENString; - begin - if not assigned(Node) then exit; - if Node^.DataExist then begin - s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; - writeln({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}s{$ifndef BESENSingleStringType}){$endif}); - end; - if assigned(Node^.Next) then begin - s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; - DumpNode(Node^.Next,s); - end; - if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); - end; -begin - if not assigned(Root) then exit; - DumpNode(Root,''); -end; - -procedure TBESENStringTree.AppendTo(DestBESENStringTree:TBESENStringTree); - procedure DumpNode(Node:PBESENStringTreeNode;const ParentStr:TBESENString); - var s:TBESENString; - begin - if not assigned(Node) then exit; - if Node^.DataExist then begin - s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; - DestBESENStringTree.Add(s,Node^.Data); - end; - if assigned(Node^.Next) then begin - s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; - DumpNode(Node^.Next,s); - end; - if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); - end; -begin - if not assigned(DestBESENStringTree) then exit; - if not assigned(Root) then exit; - DumpNode(Root,''); -end; - -procedure TBESENStringTree.Optimize(DestBESENStringTree:TBESENStringTree); - procedure DumpNode(Node:PBESENStringTreeNode;ParentStr:TBESENString); - var s:TBESENString; - begin - if not assigned(Node) then exit; - ParentStr:=ParentStr; - if Node^.DataExist then begin - s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; - DestBESENStringTree.Add(s,Node^.Data); - end; - if assigned(Node^.Next) then begin - s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; - DumpNode(Node^.Next,s); - end; - if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); - end; -begin - if not assigned(DestBESENStringTree) then exit; - DestBESENStringTree.Clear; - if not assigned(Root) then exit; - DumpNode(Root,''); -end; - -function TBESENStringTree.Add(Content:TBESENString;const Data:TBESENStringTreeData;Replace:boolean=false):boolean; -var StringLength,Position,PositionCounter:integer; - NewNode,LastNode,Node:PBESENStringTreeNode; - StringChar,NodeChar:widechar; -begin - result:=false; - StringLength:=length(Content); - if StringLength>0 then begin - LastNode:=nil; - Node:=Root; - for Position:=1 to StringLength do begin - StringChar:=Content[Position]; - if assigned(Node) then begin - NodeChar:=Node^.TheChar; - if NodeChar=StringChar then begin - LastNode:=Node; - Node:=Node^.Next; - end else begin - while (NodeChar<StringChar) and assigned(Node^.Down) do begin - Node:=Node^.Down; - NodeChar:=Node^.TheChar; - end; - if NodeChar=StringChar then begin - LastNode:=Node; - Node:=Node^.Next; - end else begin - NewNode:=CreateBESENStringTreeNode(StringChar); - if NodeChar<StringChar then begin - NewNode^.Down:=Node^.Down; - NewNode^.Up:=Node; - if assigned(NewNode^.Down) then begin - NewNode^.Down^.Up:=NewNode; - end; - NewNode^.Previous:=Node^.Previous; - Node^.Down:=NewNode; - end else if NodeChar>StringChar then begin - NewNode^.Down:=Node; - NewNode^.Up:=Node^.Up; - if assigned(NewNode^.Up) then begin - NewNode^.Up^.Down:=NewNode; - end; - NewNode^.Previous:=Node^.Previous; - if not assigned(NewNode^.Up) then begin - if assigned(NewNode^.Previous) then begin - NewNode^.Previous^.Next:=NewNode; - end else begin - Root:=NewNode; - end; - end; - Node^.Up:=NewNode; - end; - LastNode:=NewNode; - Node:=LastNode^.Next; - end; - end; - end else begin - for PositionCounter:=Position to StringLength do begin - NewNode:=CreateBESENStringTreeNode(Content[PositionCounter]); - if assigned(LastNode) then begin - NewNode^.Previous:=LastNode; - LastNode^.Next:=NewNode; - LastNode:=LastNode^.Next; - end else begin - if not assigned(Root) then begin - Root:=NewNode; - LastNode:=Root; - end; - end; - end; - break; - end; - end; - if assigned(LastNode) then begin - if Replace or not LastNode^.DataExist then begin - LastNode^.Data:=Data; - LastNode^.DataExist:=true; - result:=true; - end; - end; - end; -end; - -function TBESENStringTree.Delete(Content:TBESENString):boolean; -var StringLength,Position:integer; - Node:PBESENStringTreeNode; - StringChar,NodeChar:widechar; -begin - result:=false; - StringLength:=length(Content); - if StringLength>0 then begin - Node:=Root; - for Position:=1 to StringLength do begin - StringChar:=Content[Position]; - if assigned(Node) then begin - NodeChar:=Node^.TheChar; - while (NodeChar<>StringChar) and assigned(Node^.Down) do begin - Node:=Node^.Down; - NodeChar:=Node^.TheChar; - end; - if NodeChar=StringChar then begin - if (Position=StringLength) and Node^.DataExist then begin - Node^.DataExist:=false; - result:=true; - exit; - end; - Node:=Node^.Next; - end else begin - break; - end; - end else begin - break; - end; - end; - end; -end; - -function TBESENStringTree.Find(Content:TBESENString;var Data:TBESENStringTreeData):boolean; -var StringLength,Position:integer; - Node:PBESENStringTreeNode; - StringChar,NodeChar:TBESENString; -begin - result:=false; - StringLength:=length(Content); - if StringLength>0 then begin - Node:=Root; - for Position:=1 to StringLength do begin - StringChar:=Content[Position]; - if assigned(Node) then begin - NodeChar:=Node^.TheChar; - while (NodeChar<>StringChar) and assigned(Node^.Down) do begin - Node:=Node^.Down; - NodeChar:=Node^.TheChar; - end; - if NodeChar=StringChar then begin - if (Position=StringLength) and Node^.DataExist then begin - Data:=Node^.Data; - result:=true; - exit; - end; - Node:=Node^.Next; - end else begin - break; - end; - end else begin - break; - end; - end; - end; -end; - -end. diff --git a/3rd/besen/src/BESENStringUtils.pas b/3rd/besen/src/BESENStringUtils.pas deleted file mode 100644 index f3f773f1c..000000000 --- a/3rd/besen/src/BESENStringUtils.pas +++ /dev/null @@ -1,2618 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENStringUtils; -{$i BESEN.inc} - -interface - -uses SysUtils,Classes,BESENConstants,BESENTypes,BESENCharset; - -type TBESENHexValues=array[word] of byte; - -const BESENBase64Chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -const BESENHexChars:array[boolean,0..15] of widechar=(('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'), - ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')); - -var BESENHexValues:TBESENHexValues; - -function BESENPosChar(ToFindChar:TBESENWIDECHAR;const InString:TBESENSTRING):longint; -function BESENPos(const ToFindString,InString:TBESENSTRING):longint; - -{$ifndef BESENSingleStringType} -function BESENANSIPosChar(ToFindChar:TBESENCHAR;const InString:TBESENANSISTRING):longint; -function BESENANSIPos(const ToFindString,InString:TBESENANSISTRING):longint; - -function BESENANSITrim(const InputString:TBESENANSISTRING):TBESENANSISTRING; - -function BESENANSIUpperCase(const InputString:TBESENANSISTRING):TBESENANSISTRING; -{$endif} - -function BESENStringCompare(const s1,s2:TBESENString):longint; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} - -{$ifdef BESENSingleStringType} -function BESENGetFileContent(fn:TBESENSTRING):TBESENSTRING; -{$else} -function BESENGetFileContent(fn:TBESENANSISTRING):TBESENANSISTRING; -function BESENConvertToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; - -function BESENDecodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; -function BESENEncodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; -function BESENDequote(s:TBESENANSISTRING):TBESENANSISTRING; - -function BESENIsUTF8(const s:TBESENANSISTRING):boolean; -function BESENEncodeString(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharset):TBESENANSISTRING; -function BESENGetCodePage(Value:TBESENANSISTRING):TBESENCharset; -function BESENGetCodePageID(Value:TBESENCharset):TBESENANSISTRING; -function BESENDoNeedEncoding(Value:TBESENANSISTRING):boolean; -function BESENFindIdealCoding(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharsetSet):TBESENCharset; -function BESENISOToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; - -function BESENUTF32Pos(const ToFindString,InString:TBESENUTF32STRING):longint; -procedure BESENUTF32Delete(var s:TBESENUTF32STRING;Index,Len:longint); -function BESENUTF32Compare(const a,b:TBESENUTF32STRING):boolean; overload; -function BESENUTF32Compare(const a:TBESENUTF32STRING;const b:TBESENANSISTRING):boolean; overload; -procedure BESENUTF32Clear(var a:TBESENUTF32STRING); -procedure BESENBESENUTF32AddString(var a:TBESENUTF32STRING;const b:TBESENANSISTRING); -procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENUTF32CHAR); overload; -procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENCHAR); overload; -procedure BESENUTF32Add(var a:TBESENUTF32STRING;const b:TBESENUTF32STRING); -function BESENUTF32ToUTF8(const s:TBESENUTF32STRING):TBESENUTF8STRING; -function BESENUTF8ToUTF32(const s:TBESENUTF8STRING):TBESENUTF32STRING; -function BESENUTF8ToUTF16(const s:TBESENUTF8STRING):TBESENUTF16STRING; -function BESENUTF16ToUTF8(const s:TBESENUTF16STRING):TBESENUTF8STRING; -{$endif} -function BESENUTF32ToUTF16(const s:TBESENUTF32STRING):TBESENUTF16STRING; -function BESENUTF32CHARToUTF16(w:TBESENUTF32CHAR):TBESENUTF16STRING; -function BESENUTF16ToUTF32(const s:TBESENUTF16STRING):TBESENUTF32STRING; -{$ifndef BESENSingleStringType} -function BESENUTF32ToWIDESTRING(const s:TBESENUTF32STRING):widestring; -function BESENWIDESTRINGToUTF32(const s:widestring):TBESENUTF32STRING; -function BESENUTF32ToSTRING(const s:TBESENUTF32STRING):TBESENANSISTRING; -function BESENSTRINGToUTF32(const s:TBESENANSISTRING):TBESENUTF32STRING; -function BESENUTF32CharToUTF8(u4c:TBESENUTF32CHAR):TBESENUTF8STRING; -procedure BESENUTF8Inc(var s:TBESENUTF8STRING;var i:longint); -procedure BESENUTF8Dec(var s:TBESENUTF8STRING;var i:longint); -procedure BESENUTF8Delete(var s:TBESENUTF8STRING;i:longint); -function BESENUTF8Length(const s:TBESENUTF8STRING):longint; -function BESENUTF8GetRawPos(const s:TBESENUTF8STRING;Index:longint):longint; -function BESENUTF8GetChar(var s:TBESENUTF8STRING;Index:longint):TBESENUTF32CHAR; -function BESENUTF8GetRawChar(var s:TBESENUTF8STRING;i:longint):TBESENUTF32CHAR; -function BESENUTF8GetRawCharAndInc(var s:TBESENUTF8STRING;var i:longint):TBESENUTF32CHAR; -function BESENUTF8Pos(ToFindString,InString:TBESENUTF8STRING):longint; -{$endif} - -function BESENUnicodeGetLUT(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} -function BESENUnicodeGetType(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsAlpha(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsAlphaNumber(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsLetter(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsIDPartEx(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsIDStart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsIDPart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsDigit(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsStringWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsParserWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsLineTerminator(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsPrint(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsUpper(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeIsLower(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -function BESENUnicodeToUpper(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} -function BESENUnicodeToLower(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} - -function BESENLowercase(const s:TBESENString):TBESENString; -function BESENUppercase(const s:TBESENString):TBESENString; - -function BESENJSONStringQuote(const s:TBESENString):TBESENString; - -function BESENIsHex(const v:word):boolean; - -implementation - -uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESENUnicodeTables; - -const JSCT_UNASSIGNED=0; - JSCT_UPPERCASE_LETTER=1; - JSCT_LOWERCASE_LETTER=2; - JSCT_TITLECASE_LETTER=3; - JSCT_MODIFIER_LETTER=4; - JSCT_OTHER_LETTER=5; - JSCT_NON_SPACING_MARK=6; - JSCT_ENCLOSING_MARK=7; - JSCT_COMBINING_SPACING_MARK=8; - JSCT_DECIMAL_DIGIT_NUMBER=9; - JSCT_LETTER_NUMBER=10; - JSCT_OTHER_NUMBER=11; - JSCT_SPACE_SEPARATOR=12; - JSCT_LINE_SEPARATOR=13; - JSCT_PARAGRAPH_SEPARATOR=14; - JSCT_CONTROL=15; - JSCT_FORMAT=16; - JSCT_PRIVATE_USE=18; - JSCT_SURROGATE=19; - JSCT_DASH_PUNCTUATION=20; - JSCT_START_PUNCTUATION=21; - JSCT_END_PUNCTUATION=22; - JSCT_CONNECTOR_PUNCTUATION=23; - JSCT_OTHER_PUNCTUATION=24; - JSCT_MATH_SYMBOL=25; - JSCT_CURRENCY_SYMBOL=26; - JSCT_MODIFIER_SYMBOL=27; - JSCT_OTHER_SYMBOL=28; - -function BESENUnicodeGetLUT(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} -begin - result:=UnicodeALut[UnicodeYLut[(UnicodeXLut[(c and $ffff) shr 6] shl 6) or (c and $3f)]]; -end; - -function BESENUnicodeGetType(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} -begin - result:=BESENUnicodeGetLUT(c) and $1f; -end; - -function BESENUnicodeIsAlpha(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((((1 shl JSCT_UPPERCASE_LETTER) or - (1 shl JSCT_LOWERCASE_LETTER) or - (1 shl JSCT_TITLECASE_LETTER) or - (1 shl JSCT_MODIFIER_LETTER) or - (1 shl JSCT_OTHER_LETTER)) shr BESENUnicodeGetType(c)) and 1)<>0; -end; - -function BESENUnicodeIsAlphaNumber(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((((1 shl JSCT_UPPERCASE_LETTER) or - (1 shl JSCT_LOWERCASE_LETTER) or - (1 shl JSCT_TITLECASE_LETTER) or - (1 shl JSCT_MODIFIER_LETTER) or - (1 shl JSCT_OTHER_LETTER) or - (1 shl JSCT_DECIMAL_DIGIT_NUMBER)) shr BESENUnicodeGetType(c)) and 1)<>0; -end; - -function BESENUnicodeIsLetter(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((((1 shl JSCT_UPPERCASE_LETTER) or - (1 shl JSCT_LOWERCASE_LETTER) or - (1 shl JSCT_TITLECASE_LETTER) or - (1 shl JSCT_MODIFIER_LETTER) or - (1 shl JSCT_OTHER_LETTER) or - (1 shl JSCT_LETTER_NUMBER)) shr BESENUnicodeGetType(c)) and 1)<>0; -end; - -function BESENUnicodeIsIDPartEx(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((((1 shl JSCT_UPPERCASE_LETTER) or - (1 shl JSCT_LOWERCASE_LETTER) or - (1 shl JSCT_TITLECASE_LETTER) or - (1 shl JSCT_MODIFIER_LETTER) or - (1 shl JSCT_OTHER_LETTER) or - (1 shl JSCT_LETTER_NUMBER) or - (1 shl JSCT_NON_SPACING_MARK) or - (1 shl JSCT_COMBINING_SPACING_MARK) or - (1 shl JSCT_DECIMAL_DIGIT_NUMBER) or - (1 shl JSCT_CONNECTOR_PUNCTUATION)) shr BESENUnicodeGetType(c)) and 1)<>0; -end; - -function BESENUnicodeIsIDStart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=BESENUnicodeIsLetter(c) or ((c=ord('_')) or (c=ord('$'))); -end; - -function BESENUnicodeIsIDPart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=BESENUnicodeIsIDPartEx(c) or ((c=ord('_')) or (c=ord('$')) or ((c=$200c) or (c=$200d))); -end; - -function BESENUnicodeIsDigit(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=BESENUnicodeGetType(c)=JSCT_DECIMAL_DIGIT_NUMBER; -end; - -function BESENUnicodeIsSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(BESENUnicodeGetLUT(c) and $00070000)=$0040000; -end; - -function BESENUnicodeIsStringWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((c>=$0009) and (c<=$000d)) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$2028) or (c=$2029) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); -end; - -function BESENUnicodeIsParserWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=((c>=$0009) and (c<=$000d)) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$2028) or (c=$2029) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); -end; - -function BESENUnicodeIsWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(c=$0009) or (c=$000b) or (c=$000c) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); -end; - -function BESENUnicodeIsLineTerminator(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=(c=$000a) or (c=$000d) or (c=$2028) or (c=$2029); -end; - -function BESENUnicodeIsPrint(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=c<128; -end; - -function BESENUnicodeIsUpper(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=BESENUnicodeGetType(c)=JSCT_UPPERCASE_LETTER; -end; - -function BESENUnicodeIsLower(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} -begin - result:=BESENUnicodeGetType(c)=JSCT_LOWERCASE_LETTER; -end; - -function BESENUnicodeToUpper(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} -begin - if (BESENUnicodeGetLUT(c) and $00100000)<>0 then begin - result:=c-TBESENUTF32CHAR(BESENUnicodeGetLUT(c) shr 22); - end else begin - result:=c; - end; -end; - -function BESENUnicodeToLower(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} -begin - if (BESENUnicodeGetLUT(c) and $00200000)<>0 then begin - result:=c+TBESENUTF32CHAR(BESENUnicodeGetLUT(c) shr 22); - end else begin - result:=c; - end; -end; - -function BESENPosChar(ToFindChar:TBESENWIDECHAR;const InString:TBESENSTRING):longint; -var i:longint; -begin - result:=0; - for i:=1 to length(InString) do begin - if InString[i]=ToFindChar then begin - result:=i; - break; - end; - end; -end; - -function BESENPos(const ToFindString,InString:TBESENSTRING):longint; -var i,j,l:longint; - OK:boolean; -begin - result:=0; - i:=1; - while i<=length(InString) do begin - l:=i+length(ToFindString)-1; - if l>length(InString) then begin - exit; - end; - OK:=true; - for j:=1 to length(ToFindString) do begin - if InString[i+j-1]<>ToFindString[j] then begin - OK:=false; - break; - end; - end; - if OK then begin - result:=i; - exit; - end; - inc(i); - end; -end; - -{$ifndef BESENSingleStringType} -function BESENANSIPosChar(ToFindChar:TBESENCHAR;const InString:TBESENANSISTRING):longint; -var i:longint; -begin - result:=0; - for i:=1 to length(InString) do begin - if InString[i]=ToFindChar then begin - result:=i; - break; - end; - end; -end; - -function BESENANSIPos(const ToFindString,InString:TBESENANSISTRING):longint; -var i,j,l:longint; - OK:boolean; -begin - result:=0; - i:=1; - while i<=length(InString) do begin - l:=i+length(ToFindString)-1; - if l>length(InString) then begin - exit; - end; - OK:=true; - for j:=1 to length(ToFindString) do begin - if InString[i+j-1]<>ToFindString[j] then begin - OK:=false; - break; - end; - end; - if OK then begin - result:=i; - exit; - end; - inc(i); - end; -end; - -function BESENANSITrim(const InputString:TBESENANSISTRING):TBESENANSISTRING; -var Counter,FromHere,ToHere:longint; -begin - FromHere:=1; - ToHere:=length(InputString); - for Counter:=1 to length(InputString) do begin - if not (InputString[Counter] in [#0..#32]) then begin - FromHere:=Counter; - break; - end; - end; - for Counter:=length(InputString) downto FromHere do begin - if not (InputString[Counter] in [#0..#32]) then begin - ToHere:=Counter; - break; - end; - end; - result:=copy(InputString,FromHere,(ToHere-FromHere)+1); -end; - -function BESENANSIUpperCase(const InputString:TBESENANSISTRING):TBESENANSISTRING; -var i:longint; -begin - result:=InputString; - for i:=1 to length(result) do begin - if result[i] in ['a'..'z'] then begin - inc(byte(AnsiChar(result[i])),byte(AnsiChar('A'))-byte(AnsiChar('a'))); - end; - end; -end; -{$endif} - -function BESENStringCompare(const s1,s2:TBESENString):longint; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} -const BoolToSign:array[boolean] of longint=(1,-1); -var i,j:longint; -begin - if pointer(s1)=pointer(s2) then begin - result:=0; - exit; - end; - j:=length(s1); - if length(s2)<j then begin - j:=length(s2); - end; - for i:=1 to j do begin - result:=longint(word(s1[i]))-longint(word(s2[i])); - if result<>0 then begin - result:=BoolToSign[result<0]; - exit; - end; - end; - result:=length(s1)-length(s2); - if result<>0 then begin - result:=BoolToSign[result<0]; - end; -end; - -{$ifdef cpu64} -function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} -begin - result:=s1=s2; -end; -{$else} -{$ifdef cpu386} -procedure BESENStringEqualsAlignFiller; assembler; register; -asm - nop; -end; - -function BESENStringEquals(const s1,s2:TBESENString):boolean; assembler; register; -asm - push ebx - cmp eax,edx - je @Match - test eax,eax - jz @CheckNullEAX - test edx,edx - jz @CheckNullEDX - mov ecx,dword ptr [eax-4] - cmp ecx,dword ptr [edx-4] - jne @Mismatch - sub ecx,8 - jl @Small - mov ebx,dword ptr [eax] - cmp ebx,dword ptr [edx] - jne @Mismatch - lea ebx,dword ptr [eax+ecx] - add edx,ecx - mov eax,dword ptr [ebx] - cmp eax,dword ptr [edx] - jne @Mismatch - mov eax,dword ptr [ebx+4] - cmp eax,dword ptr [edx+4] - jne @Mismatch - sub ecx,4 - jle @Match - neg ecx - add ecx,ebx - and ecx,-4 - sub ecx,ebx -@LargeLoop: - mov eax,dword ptr [ebx+ecx] - cmp eax,dword ptr [edx+ecx] - jne @Mismatch - mov eax,dword ptr [ebx+ecx+4] - cmp eax,dword ptr [edx+ecx+4] - jne @Mismatch - add ecx,8 - jl @LargeLoop -@Match: - mov eax,1 - jmp @Done -@Small: - add ecx,8 - jle @Match -@SmallLoop: - mov bx,word ptr [eax] - cmp bx,word ptr [edx] - jne @Mismatch - add eax,2 - add edx,2 - sub ecx,2 - jnz @SmallLoop - jmp @Match -@CheckNullEAX: - cmp dword ptr [edx-4],eax - je @Match - jmp @Mismatch -@CheckNullEDX: - cmp dword ptr [eax-4],edx - je @Match -@Mismatch: - xor eax,eax -@Done: - pop ebx -end; -(* is a plain asm implementation of: -function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef UseRegister}register;{$endif} -var l:TBESENINT32; - x,y:PWideChar; -begin - result:=false; - x:=PWideChar(s1); - y:=PWideChar(s2); - if x=y then begin - result:=true; - exit; - end; - if (ptruint(x) and ptruint(y))=0 then begin - result:=(assigned(x) and (PBESENUINT32(pointer(ptruint(ptruint(x)-sizeof(longword))))^=0)) or - (assigned(y) and (PBESENUINT32(pointer(ptruint(ptruint(y)-sizeof(longword))))^=0)); - exit; - end; - l:=PBESENINT32(pointer(ptruint(ptruint(x)-sizeof(longword))))^; - if l<>PBESENINT32(pointer(ptruint(ptruint(y)-sizeof(longword))))^ then begin - exit; - end; - if l<8 then begin - while l>0 do begin - if x^<>y^ then begin - exit; - end; - inc(x); - inc(y); - dec(l,2); - end; - end else begin - if (PBESENUINT32(x)^<>PBESENUINT32(y)^) then begin - exit; - end; - dec(l,8); - inc(ptrint(x),l); - inc(ptrint(y),l); - if PBESENUINT32Array(x)^[0]<>PBESENUINT32Array(y)^[0] then begin - exit; - end; - if PBESENUINT32Array(x)^[1]<>PBESENUINT32Array(y)^[1] then begin - exit; - end; - dec(l,4); - if l>0 then begin - l:=(((-l)+ptrint(x)) and (-4))-ptrint(x); - inc(ptrint(x),l); - inc(ptrint(y),l); - repeat - if PBESENUINT32Array(x)^[0]<>PBESENUINT32Array(y)^[0] then begin - exit; - end; - if PBESENUINT32Array(x)^[1]<>PBESENUINT32Array(y)^[1] then begin - exit; - end; - inc(PBESENUINT32(x),2); - inc(PBESENUINT32(y)); - inc(l,8); - until l>=0; - end; - end; - result:=true; -end; -*) -{$else} -function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} -begin - result:=s1=s2; -end; -{$endif} -{$endif} - -{$ifdef BESENSingleStringType} -function BESENGetFileContent(fn:TBESENSTRING):TBESENSTRING; -var sl:TStringList; -begin - result:=''; - sl:=TStringList.Create; - try - sl.LoadFromFile(fn); - result:=sl.Text; - finally - sl.Free; - end; -end; -{$else} -function BESENGetFileContent(fn:TBESENANSISTRING):TBESENANSISTRING; -var fm:byte; - f:file; -begin - result:=''; - fm:=filemode; - filemode:=0; - assignfile(f,String(fn)); - {$i-}reset(f,1);{$i+}; - if ioresult=0 then begin - SetLength(result,filesize(f)); - if length(result)>0 then begin - {$i-}blockread(f,result[1],length(result));{$i+} - if ioresult<>0 then begin - {$i-}closefile(f);{$i+} - filemode:=fm; - exit; - end; - end; - {$i-}closefile(f);{$i+} - end; - filemode:=fm; -end; - -function BESENConvertToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; -var s2:TBESENANSISTRING; - i,j,k:longint; -begin - if (length(s)>=3) and (s[1]=#$ef) and (s[2]=#$bb) and (s[3]=#$bf) then begin - // UTF8 - result:=copy(s,4,length(s)-3); - end else if (length(s)>=4) and (s[1]=#$00) and (s[2]=#$00) and (s[3]=#$fe) and (s[4]=#$ff) then begin - // UTF32 big endian - s:=copy(s,5,length(s)-4); - s2:=s; - SetLength(s2,(length(s)+3) and not 3); - for i:=1 to length(s) do begin - j:=i shr 2; - k:=i and 3; - s2[(j shl 2)+(4-k)]:=s[i]; - end; - result:=BESENEncodeString(s,UTF_32,UTF_8); - end else if (length(s)>=4) and (s[1]=#$ff) and (s[2]=#$fe) and (s[3]=#$00) and (s[4]=#$00) then begin - // UTF32 little endian - result:=BESENEncodeString(copy(s,5,length(s)-4),UTF_32,UTF_8); - end else if (length(s)>=2) and (s[1]=#$fe) and (s[2]=#$ff) then begin - // UTF16 big endian - s:=copy(s,3,length(s)-2); - s2:=s; - SetLength(s2,(length(s)+1) and not 1); - for i:=1 to length(s) do begin - j:=i shr 1; - k:=i and 1; - s2[(j shl 1)+(2-k)]:=s[i]; - end; - result:=BESENEncodeString(s,UTF_16,UTF_8); - end else if (length(s)>=2) and (s[1]=#$ff) and (s[2]=#$fe) then begin - // UTF16 little endian - result:=BESENEncodeString(copy(s,3,length(s)-2),UTF_16,UTF_8); - end else if BESENIsUTF8(s) then begin - // UTF8 without byte order mark or plain US-ASCII - result:=s; - end else begin - // Without any unicode byte order mark - result:=BESENEncodeString(s,BESENLocaleCharset,UTF_8); - end; -end; - -const Base64Table:array[0..63] of TBESENCHAR='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - -var Base64DecoderTable:array[TBESENCHAR] of byte; - -procedure InitBase64; -var i:longint; -begin - for i:=0 to 63 do begin - Base64DecoderTable[Base64Table[i]]:=i; - end; -end; - -function BESENDecodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; -var i,j,l:longint; - c:longword; -begin - SetLength(result,((length(s)*3) shr 2)+3); -{while (length(s) and 3)<>0 do begin - s:=s+'='; - end;} - l:=0; - i:=1; - while i<=length(s) do begin - c:=0; - for j:=1 to 4 do begin - if i<=length(s) then begin - case s[i] of - 'A'..'Z','a'..'z','0'..'9','+','/':begin - c:=c or (Base64DecoderTable[s[i]] shl (24-((j shl 2)+(j shl 1)))); - end; - '=':begin - c:=(c and $00ffffff) or (((c shr 24)+1) shl 24); - end; - else begin - c:=c or $f0000000; - break; - end; - end; - end else begin - c:=(c and $00ffffff) or (((c shr 24)+1) shl 24); - end; - inc(i); - end; - if (c shr 24)<3 then begin - inc(l); - result[l]:=ansichar(byte((c shr 16) and $ff)); - if (c shr 24)<2 then begin - inc(l); - result[l]:=ansichar(byte((c shr 8) and $ff)); - if (c shr 24)<1 then begin - inc(l); - result[l]:=ansichar(byte(c and $ff)); - end; - end; - end else begin - break; - end; - end; - SetLength(result,l); -end; - -function BESENEncodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; -var i,l:longint; - c:longword; -begin - if length(s)=0 then begin - result:=''; - end else begin - SetLength(result,((length(s)*4) div 3)+4); - l:=1; - i:=1; - while (i+2)<=length(s) do begin - c:=(byte(s[i]) shl 16) or (byte(s[i+1]) shl 8) or byte(s[i+2]); - result[l]:=Base64Table[(c shr 18) and $3f]; - result[l+1]:=Base64Table[(c shr 12) and $3f]; - result[l+2]:=Base64Table[(c shr 6) and $3f]; - result[l+3]:=Base64Table[c and $3f]; - inc(i,3); - inc(l,4); - end; - if (i+1)<=length(s) then begin - c:=(byte(s[i]) shl 16) or (byte(s[i+1]) shl 8); - result[l]:=Base64Table[(c shr 18) and $3f]; - result[l+1]:=Base64Table[(c shr 12) and $3f]; - result[l+2]:=Base64Table[(c shr 6) and $3f]; - result[l+3]:='='; - inc(l,4); - end else if i<=length(s) then begin - c:=byte(s[i]) shl 16; - result[l]:=Base64Table[(c shr 18) and $3f]; - result[l+1]:=Base64Table[(c shr 12) and $3f]; - result[l+2]:='='; - result[l+3]:='='; - inc(l,4); - end; - if l>1 then begin - SetLength(result,l-1); - end else begin - result:=BESENAnsiTrim(result); - end; - end; -end; - -function BESENDequote(s:TBESENANSISTRING):TBESENANSISTRING; -const hexa:array[1..$F] of TBESENCHAR='123456789ABCDEF'; -var p:longint; - encode:TBESENANSISTRING; -begin - if s='' then begin - result:=#13#10; - end else begin - result:=''; - if s[length(s)]='=' then begin - SetLength(s,Length(s)-1) - end else begin - if (length(s)>=3) and (s[length(s)-2]<>'=') then begin - s:=s+#13#10; - end; - end; - p:=BESENANSIPosChar('=',s); - while p>0 do begin - encode:=ansichar(byte((pos(s[p+1],hexa) shl 4) or pos(s[p+2],hexa))); - if encode=#0 then begin - encode:=#13#10; - end; - result:=result+copy(s,1,p-1)+encode; - delete(s,1,p+2); - p:=BESENANSIPosChar('=',s); - end; - result:=result+s; - p:=BESENANSIPosChar('_',result); - while p>0 do begin - result[p]:=' '; - p:=BESENANSIPosChar('_',result); - end; - end; -end; - -const UnknownChar=#254; - -function GetCharsetTable(CharSet:TBESENCharset):TBESENCharsetTable; -begin - case CharSet of - ISO_8859_1:result:=BESENCharISO_8859_1; - ISO_8859_2:result:=BESENCharISO_8859_2; - ISO_8859_3:result:=BESENCharISO_8859_3; - ISO_8859_4:result:=BESENCharISO_8859_4; - ISO_8859_5:result:=BESENCharISO_8859_5; - ISO_8859_6:result:=BESENCharISO_8859_6; - ISO_8859_7:result:=BESENCharISO_8859_7; - ISO_8859_8:result:=BESENCharISO_8859_8; - ISO_8859_9:result:=BESENCharISO_8859_9; - ISO_8859_10:result:=BESENCharISO_8859_10; - CP1250:result:=BESENCharCP_1250; - CP1251:result:=BESENCharCP_1251; - CP1252:result:=BESENCharCP_1252; - CP1253:result:=BESENCharCP_1253; - CP1254:result:=BESENCharCP_1254; - CP1255:result:=BESENCharCP_1255; - CP1256:result:=BESENCharCP_1256; - CP1257:result:=BESENCharCP_1257; - CP1258:result:=BESENCharCP_1258; - KOI8_R:result:=BESENCharKOI8_R; - end; -end; - -function BESENIsUTF8(const s:TBESENANSISTRING):boolean; -var i,j:longint; - b:byte; -begin - j:=0; - i:=1; - while i<=length(s) do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - inc(i); - inc(j); - end else if ((i+1)<length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - inc(i,2); - inc(j); - end else if ((i+2)<length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - inc(i,3); - inc(j); - end else if ((i+3)<length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - inc(i,4); - inc(j); -{$ifndef strictutf8} - end else if ((i+4)<length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - inc(i,5); - inc(j); - end else if ((i+5)<length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - inc(i,6); - inc(j); -{$endif} - end else begin - i:=0; - j:=0; - break; - end; - end; - result:=(i>0) and (j>0); -end; - -function BESENEncodeString(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharset):TBESENANSISTRING; - function UTF16ToUTF32(const Value:TBESENANSISTRING):TBESENANSISTRING; - var i,j:longint; - s:widestring; - Buffer:array of longword; - v:longword; - w:word; - begin - SetLength(s,(length(Value)+1) and not 1); - i:=1; - j:=0; - while (i+1)<=length(Value) do begin - inc(j); - s[j]:=widechar(word((word(byte(Value[i])) shl 8) or byte(Value[i+1]))); - inc(i,2); - end; - SetLength(s,j); - SetLength(Buffer,length(s)); - j:=0; - i:=1; - while i<=length(s) do begin - w:=word(s[i]); - if (w<=$d7ff) or (w>=$e000) then begin - Buffer[j]:=w; - inc(j); - inc(i); - end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin - Buffer[j]:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; - inc(j); - inc(i,2); - end else begin - Buffer[j]:=$fffd; - inc(j); - inc(i); - end; - end; - SetLength(Buffer,j); - SetLength(result,length(Buffer)*4); - j:=1; - for i:=0 to length(Buffer)-1 do begin - v:=Buffer[i]; - result[j]:=ansichar(byte((v shr 24) and $ff)); - inc(j); - result[j]:=ansichar(byte((v shr 16) and $ff)); - inc(j); - result[j]:=ansichar(byte((v shr 8) and $ff)); - inc(j); - result[j]:=ansichar(byte(v and $ff)); - inc(j); - end; - SetLength(Buffer,0); - end; - function UTF32ToUTF16(const Value:TBESENANSISTRING):TBESENANSISTRING; - var i,j:longint; - w,u4c:TBESENUTF32CHAR; - Buffer:widestring; - s:array of longword; - begin - SetLength(s,(length(Value)+3) shr 2); - for i:=0 to length(s)-1 do begin - j:=(i shl 2)+1; - u4c:=0; - if j<=length(Value) then begin - u4c:=u4c or (byte(Value[j]) shl 24); - inc(j); - if j<=length(Value) then begin - u4c:=u4c or (byte(Value[j]) shl 16); - inc(j); - if j<=length(Value) then begin - u4c:=u4c or (byte(Value[j]) shl 8); - inc(j); - if j<=length(Value) then begin - u4c:=u4c or byte(Value[j]); - end; - end; - end; - end; - s[i]:=u4c; - end; - SetLength(Buffer,length(s)*2); - j:=0; - for i:=0 to length(s)-1 do begin - w:=s[i]; - if w<=$d7ff then begin - inc(j); - Buffer[j]:=widechar(word(w)); - end else if w<=$dfff then begin - inc(j); - Buffer[j]:=#$fffd; - end else if w<=$fffd then begin - inc(j); - Buffer[j]:=widechar(word(w)); - end else if w<=$ffff then begin - inc(j); - Buffer[j]:=#$fffd; - end else if w<=$10ffff then begin - dec(w,$10000); - inc(j); - Buffer[j]:=widechar(word((w shr 10) or $d800)); - inc(j); - Buffer[j]:=widechar(word((w and $3ff) or $dc00)); - end else begin - inc(j); - Buffer[j]:=#$fffd; - end; - end; - SetLength(Buffer,j); - SetLength(result,length(Buffer)*2); - j:=1; - for i:=1 to length(Buffer) do begin - w:=word(Buffer[i]); - result[j]:=ansichar(byte((w shr 8) and $ff)); - inc(j); - result[j]:=ansichar(byte(w and $ff)); - inc(j); - end; - SetLength(Buffer,0); - end; - function UTF8ToUTF32(Value:TBESENANSISTRING):TBESENANSISTRING; - var i,j:longint; - b:byte; - Buffer:array of longword; - v:longword; - begin - j:=0; - i:=1; - while i<=length(Value) do begin - b:=byte(Value[i]); - if (b and $80)=0 then begin - inc(i); - inc(j); - end else if ((i+1)<=length(Value)) and ((b and $e0)=$c0) and ((byte(Value[i+1]) and $c0)=$80) then begin - inc(i,2); - inc(j); - end else if ((i+2)<=length(Value)) and ((b and $f0)=$e0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) then begin - inc(i,3); - inc(j); - end else if ((i+3)<=length(Value)) and ((b and $f8)=$f0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) then begin - inc(i,4); - inc(j); -{$ifndef strictutf8} - end else if ((i+4)<=length(Value)) and ((b and $fc)=$f8) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) then begin - inc(i,5); - inc(j); - end else if ((i+5)<=length(Value)) and ((b and $fe)=$fc) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) and ((byte(Value[i+5]) and $c0)=$80) then begin - inc(i,6); - inc(j); -{$endif} - end else begin - inc(i); - inc(j); - end; - end; - SetLength(Buffer,j); - if j=0 then begin - exit; - end; - j:=0; - i:=1; - while i<=length(Value) do begin - b:=byte(Value[i]); - if (b and $80)=0 then begin - Buffer[j]:=b; - inc(i); - inc(j); - end else if ((i+1)<=length(Value)) and ((b and $e0)=$c0) and ((byte(Value[i+1]) and $c0)=$80) then begin - Buffer[j]:=((byte(Value[i]) and $1f) shl 6) or (byte(Value[i+1]) and $3f); - inc(i,2); - inc(j); - end else if ((i+2)<=length(Value)) and ((b and $f0)=$e0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) then begin - Buffer[j]:=((byte(Value[i]) and $0f) shl 12) or ((byte(Value[i+1]) and $3f) shl 6) or (byte(Value[i+2]) and $3f); - inc(i,3); - inc(j); - end else if ((i+3)<=length(Value)) and ((b and $f8)=$f0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) then begin - Buffer[j]:=((byte(Value[i]) and $07) shl 18) or ((byte(Value[i+1]) and $3f) shl 12) or ((byte(Value[i+2]) and $3f) shl 6) or (byte(Value[i+3]) and $3f); - inc(i,4); - inc(j); -{$ifndef strictutf8} - end else if ((i+4)<=length(Value)) and ((b and $fc)=$f8) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) then begin - Buffer[j]:=((byte(Value[i]) and $03) shl 24) or ((byte(Value[i+1]) and $3f) shl 18) or ((byte(Value[i+2]) and $3f) shl 12) or ((byte(Value[i+3]) and $3f) shl 6) or (byte(Value[i+4]) and $3f); - inc(i,5); - inc(j); - end else if ((i+5)<=length(Value)) and ((b and $fe)=$fc) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) and ((byte(Value[i+5]) and $c0)=$80) then begin - Buffer[j]:=((byte(Value[i]) and $01) shl 30) or ((byte(Value[i+1]) and $3f) shl 24) or ((byte(Value[i+2]) and $3f) shl 18) or ((byte(Value[i+3]) and $3f) shl 12) or ((byte(Value[i+4]) and $3f) shl 6) or (byte(Value[i+5]) and $3f); - inc(i,6); - inc(j); -{$endif} - end else begin - Buffer[j]:=$fffd; - inc(i); - inc(j); - end; - end; - SetLength(result,length(Buffer)*4); - j:=1; - for i:=0 to length(Buffer)-1 do begin - v:=Buffer[i]; - result[j]:=ansichar(byte((v shr 24) and $ff)); - inc(j); - result[j]:=ansichar(byte((v shr 16) and $ff)); - inc(j); - result[j]:=ansichar(byte((v shr 8) and $ff)); - inc(j); - result[j]:=ansichar(byte(v and $ff)); - inc(j); - end; - SetLength(Buffer,0); - end; - function UTF32toUTF8(Value:TBESENANSISTRING):TBESENANSISTRING; - var i,j:longint; - u4c:longword; - s:array of longword; - begin - SetLength(s,(length(Value)+3) shr 2); - for i:=0 to length(s)-1 do begin - j:=(i shl 2)+1; - u4c:=0; - if j<=length(Value) then begin - u4c:=u4c or (byte(Value[j]) shl 24); - inc(j); - if j<=length(Value) then begin - u4c:=u4c or (byte(Value[j]) shl 16); - inc(j); - if j<=length(Value) then begin - u4c:=u4c or (byte(Value[j]) shl 8); - inc(j); - if j<=length(Value) then begin - u4c:=u4c or byte(Value[j]); - end; - end; - end; - end; - s[i]:=u4c; - end; - result:=''; - j:=0; - for i:=0 to length(s)-1 do begin - u4c:=s[i]; - if u4c<=$7f then begin - inc(j); - end else if u4c<=$7ff then begin - inc(j,2); - end else if u4c<=$ffff then begin - inc(j,3); - end else if u4c<=$1fffff then begin - inc(j,4); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - inc(j,5); - end else if u4c<=$7fffffff then begin - inc(j,6); -{$endif} - end else begin - inc(j,3); - end; - end; - SetLength(result,j); - j:=1; - for i:=0 to length(s)-1 do begin - u4c:=s[i]; - if u4c<=$7f then begin - result[j]:=ansichar(byte(u4c)); - inc(j); - end else if u4c<=$7ff then begin - result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); - result[j+1]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,2); - end else if u4c<=$ffff then begin - result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+2]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,3); - end else if u4c<=$1fffff then begin - result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+3]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,4); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+4]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,5); - end else if u4c<=$7fffffff then begin - result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); - result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+5]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,6); -{$endif} - end else begin - u4c:=$fffd; - result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+2]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,3); - end; - end; - SetLength(s,0); - end; - function UTF7toUCS2(Value:TBESENANSISTRING):TBESENANSISTRING; - var i:longint; - c:TBESENCHAR; - s:TBESENANSISTRING; - begin - result:=''; - i:=1; - while i<=length(Value) do begin - c:=Value[i]; - inc(i); - if c<>'+' then begin - result:=result+#0+c; - end else begin - s:=''; - while i<=length(Value) do begin - c:=Value[i]; - inc(i); - if c='-' then begin - break; - end else if (c='=') or (BESENANSIPosChar(c,BESENBase64Chars)<1) then begin - dec(i); - break; - end; - s:=s+c; - end; - if s='' then begin - s:='+'; - end else begin - s:=BESENDecodeBase64(s); - end; - result:=result+s; - end; - end; - end; - function UCS2toUTF7(Value:TBESENANSISTRING):TBESENANSISTRING; - var s:TBESENANSISTRING; - c1,c2:TBESENCHAR; - i,j:longint; - begin - result:=''; - i:=1; - while i<=length(Value) do begin - c2:=Value[i]; - if (i+1)<=length(Value) then begin - c1:=Value[i+1]; - end else begin - c1:=#0; - end; - inc(i,2); - if (c2=#0) and (c1<#128) then begin - if c1='+' then begin - result:=result+'+-'; - end else begin - result:=result+TBESENCHAR(c1); - end; - end else begin - s:=c2+c1; - while i<=length(Value) do begin - c2:=Value[i]; - if (i+1)<=length(Value) then begin - c1:=Value[i+1]; - end else begin - c1:=#0; - end; - if c2=#0 then begin - break; - end else begin - inc(i,2); - s:=s+c2+c1; - end; - end; - s:=BESENEncodeBase64(s); - j:=BESENANSIPosChar('=',s); - if j>0 then begin - s:=copy(s,1,j-1); - end; - result:=result+'+'+s+'-'; - end; - end; - end; -var Unicode:word; - i,j:longint; - b:byte; - c1,c2,c3,c4:TBESENCHAR; - SourceTable,TargetTable:TBESENCharsetTable; - FromByteCount,ToByteCount:byte; -begin - if CharFrom=CharTo then begin - result:=Value; - end else begin - SourceTable:=GetCharsetTable(CharFrom); - TargetTable:=GetCharsetTable(CharTo); - if CharFrom in [UCS_2,UTF_7] then begin - FromByteCount:=2; - end else if CharFrom in [UCS_4,UTF_32,UTF_16,UTF_8] then begin - FromByteCount:=4; - end else begin - FromByteCount:=1; - end; - if CharTo in [UCS_2,UTF_7] then begin - ToByteCount:=2; - end else if CharTo in [UCS_4,UTF_32,UTF_16,UTF_8] then begin - ToByteCount:=4; - end else begin - ToByteCount:=1; - end; - case CharFrom of - UTF_7:begin - Value:=UTF7toUCS2(Value); - end; - UTF_8:begin - Value:=UTF8ToUTF32(Value); - end; - UTF_16:begin - Value:=UTF16ToUTF32(Value); - end; - end; - c1:=#0; - c2:=#0; - c3:=#0; - c4:=#0; - result:=''; - i:=1; - while i<=length(Value) do begin - case FromByteCount of - 1:begin - c1:=Value[i]; - if c1>#127 then begin - Unicode:=SourceTable[byte(c1)]; - c1:=ansichar(byte(Unicode and $ff)); - c2:=ansichar(byte(Unicode shr 8)); - end; - inc(i); - end; - 2:begin - c2:=Value[i]; - if (i+1)<=length(Value) then begin - c1:=Value[i+1]; - end else begin - c1:=#0; - end; - inc(i,2); - end; - 3:begin - c3:=Value[i]; - if (i+1)<=length(Value) then begin - c2:=Value[i+1]; - end else begin - c2:=#0; - end; - if (i+2)<=length(Value) then begin - c1:=Value[i+2]; - end else begin - c1:=#0; - end; - inc(i,3); - end; - 4:begin - c4:=Value[i]; - if (i+1)<=length(Value) then begin - c3:=Value[i+1]; - end else begin - c3:=#0; - end; - if (i+2)<=length(Value) then begin - c2:=Value[i+2]; - end else begin - c2:=#0; - end; - if (i+3)<=length(Value) then begin - c1:=Value[i+3]; - end else begin - c1:=#0; - end; - inc(i,4); - end; - end; - Unicode:=(byte(c2) shl 8) or byte(c1); - if ToByteCount=1 then begin - if (c3<>#0) or (c4<>#0) then begin - c1:=UnknownChar; - c2:=#0; - c3:=#0; - c4:=#0; - end else begin - if Unicode>127 then begin - b:=ord(UnknownChar); - for j:=128 to 255 do begin - if TargetTable[j]=Unicode then begin - b:=j; - break; - end; - end; - c1:=ansichar(byte(b)); - c2:=#0; - end else begin - c1:=ansichar(byte(Unicode and $ff)); - end; - end; - end; - case ToByteCount of - 1:begin - result:=result+c1; - end; - 2:begin - result:=result+c2+c1; - end; - 3:begin - result:=result+c3+c2+c1; - end; - 4:begin - result:=result+c4+c3+c2+c1; - end; - end; - end; - case CharTo of - UTF_7:begin - result:=UCS2toUTF7(result); - end; - UTF_8:begin - result:=UTF32toUTF8(result); - end; - UTF_16:begin - result:=UTF32ToUTF16(result); - end; - end; - end; -end; - -function BESENGetCodePage(Value:TBESENANSISTRING):TBESENCharset; -begin - Value:=BESENANSIUpperCase(Value); - if BESENANSIPos('ISO-8859-10',Value)>0 then begin - result:=ISO_8859_10; - end else if BESENANSIPos('ISO-8859-1',Value)>0 then begin - result:=ISO_8859_1; - end else if BESENANSIPos('ISO-8859-2',Value)>0 then begin - result:=ISO_8859_2; - end else if BESENANSIPos('ISO-8859-3',Value)>0 then begin - result:=ISO_8859_3; - end else if BESENANSIPos('ISO-8859-4',Value)>0 then begin - result:=ISO_8859_4; - end else if BESENANSIPos('ISO-8859-5',Value)>0 then begin - result:=ISO_8859_5; - end else if BESENANSIPos('ISO-8859-6',Value)>0 then begin - result:=ISO_8859_6; - end else if BESENANSIPos('ISO-8859-7',Value)>0 then begin - result:=ISO_8859_7; - end else if BESENANSIPos('ISO-8859-8',Value)>0 then begin - result:=ISO_8859_8; - end else if BESENANSIPos('ISO-8859-9',Value)>0 then begin - result:=ISO_8859_9; - end else if (BESENANSIPos('WINDOWS-1250',Value)>0) or (BESENANSIPos('X-CP1250',Value)>0) then begin - result:=CP1250; - end else if (BESENANSIPos('WINDOWS-1251',Value)>0) or (BESENANSIPos('X-CP1251',Value)>0) then begin - result:=CP1251; - end else if (BESENANSIPos('WINDOWS-1252',Value)>0) or (BESENANSIPos('X-CP1252',Value)>0) then begin - result:=CP1252; - end else if (BESENANSIPos('WINDOWS-1253',Value)>0) or (BESENANSIPos('X-CP1253',Value)>0) then begin - result:=CP1253; - end else if (BESENANSIPos('WINDOWS-1254',Value)>0) or (BESENANSIPos('X-CP1254',Value)>0) then begin - result:=CP1254; - end else if (BESENANSIPos('WINDOWS-1255',Value)>0) or (BESENANSIPos('X-CP1255',Value)>0) then begin - result:=CP1255; - end else if (BESENANSIPos('WINDOWS-1256',Value)>0) or (BESENANSIPos('X-CP1256',Value)>0) then begin - result:=CP1256; - end else if (BESENANSIPos('WINDOWS-1257',Value)>0) or (BESENANSIPos('X-CP1257',Value)>0) then begin - result:=CP1257; - end else if (BESENANSIPos('WINDOWS-1258',Value)>0) or (BESENANSIPos('X-CP1258',Value)>0) then begin - result:=CP1258; - end else if BESENANSIPos('KOI8-R',Value)>0 then begin - result:=KOI8_R; - end else if BESENANSIPos('UTF-7',Value)>0 then begin - result:=UTF_7; - end else if BESENANSIPos('UTF-8',Value)>0 then begin - result:=UTF_8; - end else if BESENANSIPos('UTF-16',Value)>0 then begin - result:=UTF_16; - end else if BESENANSIPos('UTF-32',Value)>0 then begin - result:=UTF_32; - end else if BESENANSIPos('UCS-4',Value)>0 then begin - result:=UCS_4; - end else if BESENANSIPos('UCS-2',Value)>0 then begin - result:=UCS_2; - end else if BESENANSIPos('UNICODE',Value)>0 then begin - result:=UCS_2; - end else begin - result:=ISO_8859_1; - end; -end; - -function BESENGetCodePageID(Value:TBESENCharset):TBESENANSISTRING; -begin - case Value of - ISO_8859_2:result:='ISO-8859-2'; - ISO_8859_3:result:='ISO-8859-3'; - ISO_8859_4:result:='ISO-8859-4'; - ISO_8859_5:result:='ISO-8859-5'; - ISO_8859_6:result:='ISO-8859-6'; - ISO_8859_7:result:='ISO-8859-7'; - ISO_8859_8:result:='ISO-8859-8'; - ISO_8859_9:result:='ISO-8859-9'; - ISO_8859_10:result:='ISO-8859-10'; - CP1250:result:='WINDOWS-1250'; - CP1251:result:='WINDOWS-1251'; - CP1252:result:='WINDOWS-1252'; - CP1253:result:='WINDOWS-1253'; - CP1254:result:='WINDOWS-1254'; - CP1255:result:='WINDOWS-1255'; - CP1256:result:='WINDOWS-1256'; - CP1257:result:='WINDOWS-1257'; - CP1258:result:='WINDOWS-1258'; - KOI8_R:result:='KOI8-R'; - UCS_2:result:='Unicode-1-1-UCS-2'; - UCS_4:result:='Unicode-1-1-UCS-4'; - UTF_32:result:='UTF-32'; - UTF_16:result:='UTF-16'; - UTF_8:result:='UTF-8'; - UTF_7:result:='UTF-7'; - else result:='ISO-8859-1'; - end; -end; - -function BESENDoNeedEncoding(Value:TBESENANSISTRING):boolean; -var i:longint; -begin - result:=false; - for i:=1 to length(Value) do begin - if ord(Value[i])>127 then begin - result:=true; - break; - end; - end; -end; - -function BESENFindIdealCoding(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharsetSet):TBESENCharset; -var cs:TBESENCharset; - i,j,k:longint; - s,t:TBESENANSISTRING; -begin - result:=ISO_8859_1; - s:=''; - for i:=1 to length(Value) do begin - if ord(Value[i])>127 then begin - s:=s+Value[i]; - end; - end; - j:=128; - for cs:=low(TBESENCharset) to high(TBESENCharset) do begin - if cs in CharTo then begin - t:=BESENEncodeString(s,CharFrom,cs); - k:=0; - for i:=1 to length(t) do begin - if t[i]=UnknownChar then begin - inc(k); - end; - end; - if k<j then begin - j:=k; - result:=cs; - if k=0 then begin - break; - end; - end; - end; - end; -end; - -function BESENISOToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; -var q,us,e:TBESENANSISTRING; - encode:TBESENCHAR; - p1,p2,p3:longint; - cs:TBESENCharset; -begin - result:=''; - us:=BESENANSIUpperCase(s); - p1:=BESENANSIPos('=?ISO',us); - while p1>0 do begin - q:=copy(s,p1+2,length(s)); - p2:=BESENANSIPosChar('?',q); - if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin - break; - end; - e:=copy(q,1,p2-1); - cs:=BESENGetCodePage(e); - encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); - q:=copy(q,p2+3,length(q)); - p3:=BESENANSIPos('?=',q); - if p3=0 then begin - break; - end; - SetLength(q,p3-1); - if encode='B' then begin - q:=BESENDecodeBase64(q); - end else if encode='Q' then begin - q:=BESENDequote(q+'='); - end else begin - break; - end; - q:=BESENEncodeString(q,cs,UTF_8); - result:=result+copy(s,1,p1-1)+q; - inc(p1,2+p2+2+p3); - delete(s,1,p1); - delete(us,1,p1); - p1:=BESENANSIPos('=?ISO',us); - end; - p1:=BESENANSIPos('=?UTF-7',us); - while p1>0 do begin - q:=copy(s,p1+2,length(s)); - p2:=BESENANSIPosChar('?',q); - if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin - break; - end; - encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); - q:=copy(q,p2+3,length(q)); - p3:=BESENANSIPos('?=',q); - if p3=0 then begin - break; - end; - SetLength(q,p3-1); - if encode='B' then begin - q:=BESENDecodeBase64(q); - end else if encode='Q' then begin - q:=BESENDequote(q+'='); - end else begin - break; - end; - q:=BESENEncodeString(s,UTF_7,UTF_8); - result:=result+copy(s,1,p1-1)+q; - inc(p1,2+p2+2+p3); - delete(s,1,p1); - delete(us,1,p1); - p1:=BESENANSIPos('=?UTF-7',us); - end; - p1:=BESENANSIPos('=?UTF-8',us); - while p1>0 do begin - q:=copy(s,p1+2,length(s)); - p2:=BESENANSIPosChar('?',q); - if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin - break; - end; - encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); - q:=copy(q,p2+3,length(q)); - p3:=BESENANSIPos('?=',q); - if p3=0 then begin - break; - end; - SetLength(q,p3-1); - if encode='B' then begin - q:=BESENDecodeBase64(q); - end else if encode='Q' then begin - q:=BESENDequote(q+'='); - end else begin - break; - end; - result:=result+copy(s,1,p1-1)+q; - inc(p1,2+p2+2+p3); - delete(s,1,p1); - delete(us,1,p1); - p1:=BESENANSIPos('=?UTF-8',us); - end; - p1:=BESENANSIPos('=?',us); - while p1>0 do begin - q:=copy(s,p1+2,length(s)); - p2:=BESENANSIPosChar('?',q); - if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin - break; - end; - e:=copy(q,1,p2-1); - cs:=BESENGetCodePage(e); - if cs=ISO_8859_1 then begin - result:=result+'=?'; - delete(s,1,p1); - delete(us,1,p1); - p1:=BESENANSIPos('=?',us); - continue; - end; - encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); - q:=copy(q,p2+3,length(q)); - p3:=BESENANSIPos('?=',q); - if p3=0 then begin - break; - end; - SetLength(q,p3-1); - if encode='B' then begin - q:=BESENDecodeBase64(q); - end else if encode='Q' then begin - q:=BESENDequote(q+'='); - end else begin - break; - end; - q:=BESENEncodeString(q,cs,UTF_8); - result:=result+copy(s,1,p1-1)+q; - inc(p1,2+p2+2+p3); - delete(s,1,p1); - delete(us,1,p1); - p1:=BESENANSIPos('=?',us); - end; - result:=result+BESENEncodeString(s,ISO_8859_1,UTF_8); -end; - -function BESENUTF32Pos(const ToFindString,InString:TBESENUTF32STRING):longint; -var i,j:longint; -begin - result:=-1; - for i:=0 to length(InString)-length(ToFindString) do begin - for j:=0 to length(ToFindString)-1 do begin - if ToFindString[j]<>InString[i+j] then begin - break; - end; - result:=i; - exit; - end; - end; -end; - -procedure BESENUTF32Delete(var s:TBESENUTF32STRING;Index,Len:longint); -var i,a,b:longint; -begin - if Index>=length(s) then begin - exit; - end; - if Len>length(s) then begin - Len:=length(s); - end; - if (Index+Len)>=length(s) then begin - Len:=length(s)-Index; - end; - a:=Index+Len; - b:=Index; - i:=length(s)-a; - move(s[a],s[b],i*sizeof(TBESENUTF32CHAR)); - SetLength(s,length(s)-Len); -end; - -function BESENUTF32Compare(const a,b:TBESENUTF32STRING):boolean; overload; -var i:longint; -begin - if a=b then begin - result:=true; - exit; - end; - if length(a)<>length(b) then begin - result:=false; - exit; - end; - for i:=0 to length(a)-1 do begin - if a[i]<>b[i] then begin - result:=false; - exit; - end; - end; - result:=true; -end; - -function BESENUTF32Compare(const a:TBESENUTF32STRING;const b:TBESENANSISTRING):boolean; overload; -var i:longint; -begin - if length(a)<>length(b) then begin - result:=false; - exit; - end; - for i:=0 to length(a)-1 do begin - if a[i]<>byte(b[i+1]) then begin - result:=false; - exit; - end; - end; - result:=true; -end; - -procedure BESENUTF32Clear(var a:TBESENUTF32STRING); -begin - SetLength(a,0); -end; - -procedure BESENBESENUTF32AddString(var a:TBESENUTF32STRING;const b:TBESENANSISTRING); -var i,j:longint; -begin - j:=length(a); - SetLength(a,j+length(b)); - for i:=1 to length(b) do begin - a[j+i-1]:=byte(b[i]); - end; -end; - -procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENUTF32CHAR); overload; -var j:longint; -begin - j:=length(a); - SetLength(a,j+1); - a[j]:=b; -end; - -procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENCHAR); overload; -var j:longint; -begin - j:=length(a); - SetLength(a,j+1); - a[j]:=byte(b); -end; - -procedure BESENUTF32Add(var a:TBESENUTF32STRING;const b:TBESENUTF32STRING); -var i,j:longint; -begin - j:=length(a); - SetLength(a,j+length(b)); - for i:=0 to length(b)-1 do begin - a[j+i]:=byte(b[i]); - end; -end; - -function BESENUTF32ToUTF8(const s:TBESENUTF32STRING):TBESENUTF8STRING; -var i,j:longint; - u4c:TBESENUTF32CHAR; -begin - result:=''; - j:=0; - for i:=0 to length(s)-1 do begin - u4c:=s[i]; - if u4c<=$7f then begin - inc(j); - end else if u4c<=$7ff then begin - inc(j,2); - end else if u4c<=$ffff then begin - inc(j,3); - end else if u4c<=$1fffff then begin - inc(j,4); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - inc(j,5); - end else if u4c<=$7fffffff then begin - inc(j,6); -{$endif} - end else begin - inc(j,3); - end; - end; - SetLength(result,j); - j:=1; - for i:=0 to length(s)-1 do begin - u4c:=s[i]; - if u4c<=$7f then begin - result[j]:=ansichar(byte(u4c)); - inc(j); - end else if u4c<=$7ff then begin - result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); - result[j+1]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,2); - end else if u4c<=$ffff then begin - result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+2]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,3); - end else if u4c<=$1fffff then begin - result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+3]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,4); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+4]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,5); - end else if u4c<=$7fffffff then begin - result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); - result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+5]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,6); -{$endif} - end else begin - u4c:=$fffd; - result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+2]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,3); - end; - end; -end; - -function BESENUTF8ToUTF32(const s:TBESENUTF8STRING):TBESENUTF32STRING; -var i,j:longint; - b:byte; -begin - j:=0; - i:=1; - while i<=length(s) do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - inc(i); - inc(j); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - inc(i,2); - inc(j); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - inc(i,3); - inc(j); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - inc(i,4); - inc(j); -{$ifndef strictutf8} - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - inc(i,5); - inc(j); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - inc(i,6); - inc(j); -{$endif} - end else begin - inc(i); - inc(j); - end; - end; - SetLength(result,j); - if j=0 then begin - exit; - end; - j:=0; - i:=1; - while i<=length(s) do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - result[j]:=b; - inc(i); - inc(j); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - result[j]:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); - inc(i,2); - inc(j); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - result[j]:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); - inc(i,3); - inc(j); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - result[j]:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); - inc(i,4); - inc(j); -{$ifndef strictutf8} - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - result[j]:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); - inc(i,5); - inc(j); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - result[j]:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); - inc(i,6); - inc(j); -{$endif} - end else begin - result[j]:=$fffd; - inc(i); - inc(j); - end; - end; -end; - -function BESENUTF8ToUTF16(const s:TBESENUTF8STRING):TBESENUTF16STRING; -var i,j:longint; - w:TBESENUTF32CHAR; - b:byte; -begin - result:=''; - i:=1; - j:=0; - while i<=length(s) do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - w:=b; - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - w:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - w:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - w:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); - inc(i,4); -{$ifndef strictutf8} - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - w:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - w:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); - inc(i,6); -{$endif} - end else begin - w:=$fffd; - inc(i); - end; - if w<=$d7ff then begin - inc(j); - end else if w<=$dfff then begin - inc(j); - end else if w<=$fffd then begin - inc(j); - end else if w<=$ffff then begin - inc(j); - end else if w<=$10ffff then begin - inc(j,2); - end else begin - inc(j); - end; - end; - SetLength(result,j); - i:=1; - j:=0; - while i<=length(s) do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - w:=b; - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - w:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - w:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - w:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); - inc(i,4); -{$ifndef strictutf8} - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - w:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - w:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); - inc(i,6); -{$endif} - end else begin - w:=$fffd; - inc(i); - end; - if w<=$d7ff then begin - inc(j); - result[j]:=widechar(word(w)); - end else if w<=$dfff then begin - inc(j); - result[j]:=#$fffd; - end else if w<=$fffd then begin - inc(j); - result[j]:=widechar(word(w)); - end else if w<=$ffff then begin - inc(j); - result[j]:=#$fffd; - end else if w<=$10ffff then begin - dec(w,$10000); - inc(j); - result[j]:=widechar(word((w shr 10) or $d800)); - inc(j); - result[j]:=widechar(word((w and $3ff) or $dc00)); - end else begin - inc(j); - result[j]:=#$fffd; - end; - end; -end; - -function BESENUTF16ToUTF8(const s:TBESENUTF16STRING):TBESENUTF8STRING; -var i,j:longint; - w:word; - u4c:TBESENUTF32CHAR; -begin - result:=''; - j:=0; - i:=1; - while i<=length(s) do begin - w:=word(s[i]); - if (w<=$d7ff) or (w>=$e000) then begin - u4c:=w; - inc(i); - end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin - u4c:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; - inc(i,2); - end else begin - u4c:=$fffd; - inc(i); - end; - if u4c<=$7f then begin - inc(j); - end else if u4c<=$7ff then begin - inc(j,2); - end else if u4c<=$ffff then begin - inc(j,3); - end else if u4c<=$1fffff then begin - inc(j,4); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - inc(j,5); - end else if u4c<=$7fffffff then begin - inc(j,6); -{$endif} - end else begin - inc(j,3); - end; - end; - SetLength(result,j); - j:=1; - i:=1; - while i<=length(s) do begin - w:=word(s[i]); - if (w<=$d7ff) or (w>=$e000) then begin - u4c:=w; - inc(i); - end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin - u4c:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; - inc(i,2); - end else begin - u4c:=$fffd; - inc(i); - end; - if u4c<=$7f then begin - result[j]:=ansichar(byte(u4c)); - inc(j); - end else if u4c<=$7ff then begin - result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); - result[j+1]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,2); - end else if u4c<=$ffff then begin - result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+2]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,3); - end else if u4c<=$1fffff then begin - result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+3]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,4); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+4]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,5); - end else if u4c<=$7fffffff then begin - result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); - result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); - result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); - result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+5]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,6); -{$endif} - end else begin - u4c:=$fffd; - result[j]:=ansichar(byte($e0 or (u4c shr 12))); - result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); - result[j+2]:=ansichar(byte($80 or (u4c and $3f))); - inc(j,3); - end; - end; -end; -{$endif} - -function BESENUTF32ToUTF16(const s:TBESENUTF32STRING):TBESENUTF16STRING; -var i,j:longint; - w:TBESENUTF32CHAR; -begin - SetLength(result,length(s)*2); - j:=0; - for i:=0 to length(s)-1 do begin - w:=s[i]; - if w<=$d7ff then begin - inc(j); - result[j]:=widechar(word(w)); - end else if w<=$dfff then begin - inc(j); - result[j]:=#$fffd; - end else if w<=$fffd then begin - inc(j); - result[j]:=widechar(word(w)); - end else if w<=$ffff then begin - inc(j); - result[j]:=#$fffd; - end else if w<=$10ffff then begin - dec(w,$10000); - inc(j); - result[j]:=widechar(word((w shr 10) or $d800)); - inc(j); - result[j]:=widechar(word((w and $3ff) or $dc00)); - end else begin - inc(j); - result[j]:=#$fffd; - end; - end; - SetLength(result,j); -end; - -function BESENUTF32CHARToUTF16(w:TBESENUTF32CHAR):TBESENUTF16STRING; -begin - if w<=$d7ff then begin - result:=widechar(word(w)); - end else if w<=$dfff then begin - result:=#$fffd; - end else if w<=$fffd then begin - result:=widechar(word(w)); - end else if w<=$ffff then begin - result:=#$fffd; - end else if w<=$10ffff then begin - dec(w,$10000); - result:=widechar(word((w shr 10) or $d800)); - result:=result+widechar(word((w and $3ff) or $dc00)); - end else begin - result:=#$fffd; - end; -end; - -function BESENUTF16ToUTF32(const s:TBESENUTF16STRING):TBESENUTF32STRING; -var i,j:longint; - w:word; -begin - SetLength(result,length(s)); - j:=0; - i:=1; - while i<=length(s) do begin - w:=word(s[i]); - if (w<=$d7ff) or (w>=$e000) then begin - result[j]:=w; - inc(j); - inc(i); - end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin - result[j]:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; - inc(j); - inc(i,2); - end else begin - result[j]:=$fffd; - inc(j); - inc(i); - end; - end; - SetLength(result,j); -end; - -{$ifndef BESENSingleStringType} -function BESENUTF32ToWIDESTRING(const s:TBESENUTF32STRING):widestring; -var i:longint; -begin - SetLength(result,length(s)); - for i:=0 to length(s)-1 do begin - result[i+1]:=widechar(word(s[i])); - end; -end; - -function BESENWIDESTRINGToUTF32(const s:widestring):TBESENUTF32STRING; -var i:longint; -begin - SetLength(result,length(s)); - for i:=1 to length(s) do begin - result[i-1]:=word(widechar(s[i])); - end; -end; - -function BESENUTF32ToSTRING(const s:TBESENUTF32STRING):TBESENANSISTRING; -var i:longint; -begin - SetLength(result,length(s)); - for i:=0 to length(s)-1 do begin - result[i+1]:=TBESENCHAR(byte(s[i])); - end; -end; - -function BESENSTRINGToUTF32(const s:TBESENANSISTRING):TBESENUTF32STRING; -var i:longint; -begin - SetLength(result,length(s)); - for i:=1 to length(s) do begin - result[i-1]:=byte(TBESENCHAR(s[i])); - end; -end; - -function BESENUTF32CharToUTF8(u4c:TBESENUTF32CHAR):TBESENUTF8STRING; -begin - if u4c<=$7f then begin - result:=ansichar(byte(u4c)); - end else if u4c<=$7ff then begin - result:=ansichar(byte($c0 or ((u4c shr 6) and $1f)))+ansichar(byte($80 or (u4c and $3f))); - end else if u4c<=$ffff then begin - result:=ansichar(byte($e0 or ((u4c shr 12) and $0f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); - end else if u4c<=$1fffff then begin - result:=ansichar(byte($f0 or ((u4c shr 18) and $07)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); -{$ifndef strictutf8} - end else if u4c<=$3ffffff then begin - result:=ansichar(byte($f8 or ((u4c shr 24) and $03)))+ansichar(byte($80 or ((u4c shr 18) and $3f)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); - end else if u4c<=$7fffffff then begin - result:=ansichar(byte($fc or ((u4c shr 30) and $01)))+ansichar(byte($80 or ((u4c shr 24) and $3f)))+ansichar(byte($80 or ((u4c shr 18) and $3f)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); -{$endif} - end else begin - u4c:=$fffd; - result:=ansichar(byte($e0 or ((u4c shr 12) and $0f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); - end; -end; - -procedure BESENUTF8Inc(var s:TBESENUTF8STRING;var i:longint); -var b:byte; -begin - if (i>=1) and (i<=length(s)) then begin - b:=byte(s[i]); - if (b and $80)=0 then begin - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - inc(i,4); - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - inc(i,6); - end else begin - inc(i); - end; - end; -end; - -procedure BESENUTF8Dec(var s:TBESENUTF8STRING;var i:longint); -begin - if (i>=1) and (i<=(length(s)+1)) then begin - dec(i); - while i>0 do begin - if byte(s[i]) in [$80..$bf] then begin - dec(i); - end else begin - break; - end; - end; - end; -end; - -procedure BESENUTF8Delete(var s:TBESENUTF8STRING;i:longint); -begin - if (i>=1) and (i<=length(s)) then begin - delete(s,i,1); - while (i>=1) and (i<=length(s)+1) do begin - if byte(s[i]) in [$80..$bf] then begin - delete(s,i,1); - end else begin - break; - end; - end; - end; -end; - -function BESENUTF8Length(const s:TBESENUTF8STRING):longint; -var b:byte; - i,j:longint; -begin - result:=0; - i:=1; - j:=length(s); - while i<=j do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - inc(i,4); - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - inc(i,6); - end else begin - inc(i); - end; - inc(result); - end; -end; - -function BESENUTF8GetRawPos(const s:TBESENUTF8STRING;Index:longint):longint; -var b:byte; - i,j,k:longint; -begin - result:=0; - k:=1; - i:=1; - j:=length(s); - while i<=j do begin - if k=Index then begin - result:=i; - exit; - end; - b:=byte(s[i]); - if (b and $80)=0 then begin - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - inc(i,4); - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - inc(i,6); - end else begin - inc(i); - end; - inc(k); - end; -end; - -function BESENUTF8GetChar(var s:TBESENUTF8STRING;Index:longint):TBESENUTF32CHAR; -var b,i,j:longint; -begin - i:=1; - j:=0; - while i<=Index do begin - b:=byte(s[i]); - if (b and $80)=0 then begin - result:=b; - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); - inc(i,4); - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); - inc(i,6); - end else begin - result:=$fffd; - inc(i); - end; - inc(j); - if j=Index then begin - exit; - end; - end; - result:=0; -end; - -function BESENUTF8GetRawChar(var s:TBESENUTF8STRING;i:longint):TBESENUTF32CHAR; -var b:byte; -begin - if (i<1) or (i>length(s)) then begin - result:=0; - inc(i); - exit; - end; - b:=byte(s[i]); - if (b and $80)=0 then begin - result:=b; - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); - end else begin - result:=$fffd; - end; -end; - -function BESENUTF8GetRawCharAndInc(var s:TBESENUTF8STRING;var i:longint):TBESENUTF32CHAR; -var b:byte; -begin - if (i<1) or (i>length(s)) then begin - result:=0; - inc(i); - exit; - end; - b:=byte(s[i]); - if (b and $80)=0 then begin - result:=b; - inc(i); - end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin - result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); - inc(i,2); - end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin - result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); - inc(i,3); - end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin - result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); - inc(i,4); -{$ifndef strictutf8} - end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin - result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); - inc(i,5); - end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin - result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); - inc(i,6); -{$endif} - end else begin - result:=$fffd; - inc(i); - end; -end; -{$endif} - -function BESENUTF8Pos(ToFindString,InString:TBESENUTF8STRING):longint; -var i,j,l:longint; - OK:boolean; -begin - result:=0; - i:=1; - while i<=length(InString) do begin - l:=i+length(ToFindString)-1; - if l>length(InString) then begin - exit; - end; - OK:=true; - for j:=1 to length(ToFindString) do begin - if InString[i+j-1]<>ToFindString[j] then begin - OK:=false; - break; - end; - end; - if OK then begin - result:=i; - exit; - end; - BESENUTF8Inc(InString,i); - end; -end; - -function BESENLowercase(const s:TBESENString):TBESENString; -var t:TBESENUTF32STRING; - i:longint; -begin - t:=BESENUTF16ToUTF32(s); - for i:=0 to length(t)-1 do begin - t[i]:=BESENUnicodeToLower(t[i]); - end; - result:=BESENUTF32ToUTF16(t); - SetLength(t,0); -end; - -function BESENUppercase(const s:TBESENString):TBESENString; -var t:TBESENUTF32STRING; - i:longint; -begin - t:=BESENUTF16ToUTF32(s); - for i:=0 to length(t)-1 do begin - t[i]:=BESENUnicodeToUpper(t[i]); - end; - result:=BESENUTF32ToUTF16(t); - SetLength(t,0); -end; - -function BESENJSONStringQuote(const s:TBESENString):TBESENString; -var i:longint; - c:word; -begin - result:='"'; - i:=1; - while i<=length(s) do begin - case s[i] of - '"','\':begin - result:=result+'\'+s[i]; - inc(i); - end; - #$0008:begin - result:=result+'\b'; - inc(i); - end; - #$0009:begin - result:=result+'\t'; - inc(i); - end; - #$000a:begin - result:=result+'\n'; - inc(i); - end; - #$000b:begin - result:=result+'\v'; - inc(i); - end; - #$000c:begin - result:=result+'\f'; - inc(i); - end; - #$000d:begin - result:=result+'\r'; - inc(i); - end; - #$0000..#$0007,#$000e..#$001f,#$007d..#$009f,#$00ad,#$0600..#$0604,#$070f,#$17b4,#$17b5,#$200c..#$200f,#$2028..#$202f,#$2060..#$206f,#$feff,#$fff0..#$ffff:begin - c:=word(widechar(s[i])); - result:=result+'\u'+BESENHexChars[false,(c shr 12) and $f]+BESENHexChars[false,(c shr 8) and $f]+BESENHexChars[false,(c shr 4) and $f]+BESENHexChars[false,c and $f]; - inc(i); - end; - else begin - result:=result+s[i]; - inc(i); - end; - end; - end; - result:=result+'"'; -end; - -function BESENIsHex(const v:word):boolean; -const IsCharHex:TBESENCharBitmap=($00,$00,$00,$00,$00,$00,$ff,$03,$7e,$00,$00,$00,$7e,$00,$00,$00); // [0-9a-fA-F] -begin - result:=(v<$80) and ((IsCharHex[(v shr 3) and $7f] and (1 shl (v and 7)))<>0); -end; - -procedure InitHexValues; -var i:longint; -begin - fillchar(BESENHexValues,sizeof(TBESENHexValues),#0); - for i:=0 to 15 do begin - BESENHexValues[word(widechar(BESENHexChars[false,i]))]:=i; - BESENHexValues[word(widechar(BESENHexChars[true,i]))]:=i; - end; -end; - -procedure InitBESEN; -begin -{$ifndef BESENSingleStringType} - InitBase64; -{$endif} - InitHexValues; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENTypes.pas b/3rd/besen/src/BESENTypes.pas deleted file mode 100644 index 583f54934..000000000 --- a/3rd/besen/src/BESENTypes.pas +++ /dev/null @@ -1,200 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENTypes; -{$i BESEN.inc} - -interface - -uses BESENConstants; - -type{$ifdef BESENSingleStringType} - TBESENCHAR=widechar; - - PBESENCHAR=pwidechar; -{$else} - TBESENCHAR=ansichar; - - PBESENCHAR=pansichar; -{$endif} - - TBESENWIDECHAR=widechar; - - PBESENWIDECHAR=pwidechar; - - PBESENByte=^byte; - -{$ifdef BESENSingleStringType} -{$ifdef BESENEmbarcaderoNextGen} - WideString=UnicodeString; -{$endif} -{$else} - TBESENANSISTRING=ansistring; - - TBESENUTF8STRING=TBESENANSISTRING; -{$endif} - - TBESENUTF16STRING=widestring; - - TBESENUTF32CHAR=longword; - - PBESENUTF32CHARS=^TBESENUTF32CHARS; - TBESENUTF32CHARS=array[0..($7fffffff div sizeof(TBESENUTF32CHAR))-1] of TBESENUTF32CHAR; - - TBESENUTF32STRING=array of TBESENUTF32CHAR; - -{$ifdef fpc} - {$undef OldDelphi} -{$else} - {$ifdef conditionalexpressions} - {$if CompilerVersion>=23.0} - {$undef OldDelphi} - qword=uint64; - ptruint=NativeUInt; - ptrint=NativeInt; - {$else} - {$define OldDelphi} - {$ifend} - {$else} - {$define OldDelphi} - {$endif} -{$endif} -{$ifdef OldDelphi} - qword=int64; -{$ifdef cpu64} - ptruint=qword; - ptrint=int64; -{$else} - ptruint=longword; - ptrint=longint; -{$endif} -{$endif} - - TBESENParsingNumberType={$ifdef HAS_TYPE_EXTENDED}extended{$else}double{$endif}; - - PBESENNumber=^TBESENNumber; - TBESENNumber=double; - - TBESENBoolean=longbool; - - TBESENDate=TBEsenNumber; - - PBESENString=^TBESENString; - TBESENString=TBESENUTF16STRING; - - TBESENINT16=smallint; - TBESENUINT16=word; - - PBESENINT32=^TBESENINT32; - TBESENINT32=longint; - - PBESENUINT32=^TBESENUINT32; - TBESENUINT32=longword; - - PBESENINT64=^TBESENINT64; - TBESENINT64=int64; - -{$ifdef fpc} - PBESENQWORD=^TBESENQWORD; - TBESENQWORD=qword; -{$endif} - - TBESENHash=TBESENUINT32; - - TBESENTarget=TBESENINT32; - - PBESENByteArray=^TBESENByteArray; - TBESENByteArray=array[0..$7fffffff-2] of byte; - - PBESENUINT32Array=^TBESENUINT32Array; - TBESENUINT32Array=array[0..($7fffffff div sizeof(TBESENUINT32))-1] of TBESENUINT32; - - PBESENINT32Array=^TBESENINT32Array; - TBESENINT32Array=array[0..($7fffffff div sizeof(TBESENUINT32))-1] of TBESENINT32; - - PBESENINT64Array=^TBESENINT64Array; - TBESENINT64Array=array[0..($7fffffff div sizeof(TBESENINT64))-1] of TBESENINT64; - - TBESENBytes=array of byte; - - TBESENIntegers=array of integer; - - TBESENUINT32s=array of TBESENUINT32; - - TBESENINT32s=array of TBESENINT32; - - TBESENNativeCodePCOffsets=array of pointer; - - TBESENRadixChars=array[0..35] of TBESENCHAR; - - TBESENLocation=record - LineNumber:integer; - end; - - PBESENDoubleHiLo=^TBESENDoubleHiLo; - TBESENDoubleHiLo=packed record -{$ifdef BIG_ENDIAN} - Hi,Lo:longword; -{$else} - Lo,Hi:longword; -{$endif} - end; - - TBESENLocations=array of TBESENLocation; - - TBESENStrings=array of TBESENString; - - TBESENWarningProc=procedure(LineNumber:integer;const Msg:TBESENSTRING) of object; - - TBESENTraceType=(bttNONE,bttSTATEMENT,bttCALL,bttRETURN,bttTHROW,bttDEBUGGER); - - TBESENCompatibilityMode=record - Name:TBESENString; - Flag:longword; - end; - - TBESENCompatibilityModes=array[0..3] of TBESENCompatibilityMode; - -{$ifdef BESENDelphiHasNoSystemTimeMore} - TSystemTime=record - wYear:word; - wMonth:word; - wDayOfWeek:word; - wDay:word; - wHour:word; - wMinute:word; - wSecond:word; - wMilliseconds:word; - end; -{$endif} - -implementation - -end. diff --git a/3rd/besen/src/BESENUnicodeTables.pas b/3rd/besen/src/BESENUnicodeTables.pas deleted file mode 100644 index c13093a02..000000000 --- a/3rd/besen/src/BESENUnicodeTables.pas +++ /dev/null @@ -1,1274 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENUnicodeTables; -{$i BESEN.inc} - -interface - -const UnicodeXLut:array[0..1023] of byte=( - 0, 1, 2, 3, 4, 5, 6, 7, (* $0000 *) - 8, 9, 10, 11, 12, 13, 14, 15, (* $0200 *) - 16, 17, 18, 19, 20, 21, 22, 23, (* $0400 *) - 24, 25, 26, 27, 28, 28, 28, 28, (* $0600 *) - 28, 28, 28, 28, 29, 30, 31, 32, (* $0800 *) - 33, 34, 35, 36, 37, 38, 39, 40, (* $0A00 *) - 41, 42, 43, 44, 45, 46, 28, 28, (* $0C00 *) - 47, 48, 49, 50, 51, 52, 53, 28, (* $0E00 *) - 28, 28, 54, 55, 56, 57, 58, 59, (* $1000 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $1200 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $1400 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $1600 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $1800 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $1A00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $1C00 *) - 60, 60, 61, 62, 63, 64, 65, 66, (* $1E00 *) - 67, 68, 69, 70, 71, 72, 73, 74, (* $2000 *) - 75, 75, 75, 76, 77, 78, 28, 28, (* $2200 *) - 79, 80, 81, 82, 83, 83, 84, 85, (* $2400 *) - 86, 85, 28, 28, 87, 88, 89, 28, (* $2600 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $2800 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $2A00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $2C00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $2E00 *) - 90, 91, 92, 93, 94, 56, 95, 28, (* $3000 *) - 96, 97, 98, 99, 83, 100, 83, 101, (* $3200 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $3400 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $3600 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $3800 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $3A00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $3C00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $3E00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4000 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4200 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4400 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4600 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4800 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4A00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $4C00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $4E00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5A00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5C00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $5E00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6A00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6C00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $6E00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7A00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7C00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $7E00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8A00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8C00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $8E00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9A00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $9C00 *) - 56, 56, 56, 56, 56, 56, 102, 28, (* $9E00 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $A000 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $A200 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $A400 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $A600 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $A800 *) - 28, 28, 28, 28, 28, 28, 28, 28, (* $AA00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $AC00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $AE00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $B000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $B200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $B400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $B600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $B800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $BA00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $BC00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $BE00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $C000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $C200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $C400 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $C600 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $C800 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $CA00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $CC00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $CE00 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $D000 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $D200 *) - 56, 56, 56, 56, 56, 56, 56, 56, (* $D400 *) - 56, 56, 56, 56, 56, 56, 103, 28, (* $D600 *) -104, 104, 104, 104, 104, 104, 104, 104, (* $D800 *) -104, 104, 104, 104, 104, 104, 104, 104, (* $DA00 *) -104, 104, 104, 104, 104, 104, 104, 104, (* $DC00 *) -104, 104, 104, 104, 104, 104, 104, 104, (* $DE00 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $E000 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $E200 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $E400 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $E600 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $E800 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $EA00 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $EC00 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $EE00 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $F000 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $F200 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $F400 *) -105, 105, 105, 105, 105, 105, 105, 105, (* $F600 *) -105, 105, 105, 105, 56, 56, 56, 56, (* $F800 *) -106, 28, 28, 28, 107, 108, 109, 110, (* $FA00 *) - 56, 56, 56, 56, 111, 112, 113, 114, (* $FC00 *) -115, 116, 56, 117, 118, 119, 120, 121); (* $FE00 *) - -UnicodeYLut:array[0..7807] of byte=( - 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) - 0, 1, 1, 1, 1, 1, 0, 0, (* 0 *) - 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) - 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) - 2, 3, 3, 3, 4, 3, 3, 3, (* 0 *) - 5, 6, 3, 7, 3, 8, 3, 3, (* 0 *) - 9, 9, 9, 9, 9, 9, 9, 9, (* 0 *) - 9, 9, 3, 3, 7, 7, 7, 3, (* 0 *) - 3, 10, 10, 10, 10, 10, 10, 10, (* 1 *) - 10, 10, 10, 10, 10, 10, 10, 10, (* 1 *) - 10, 10, 10, 10, 10, 10, 10, 10, (* 1 *) - 10, 10, 10, 5, 3, 6, 11, 12, (* 1 *) - 11, 13, 13, 13, 13, 13, 13, 13, (* 1 *) - 13, 13, 13, 13, 13, 13, 13, 13, (* 1 *) - 13, 13, 13, 13, 13, 13, 13, 13, (* 1 *) - 13, 13, 13, 5, 7, 6, 7, 0, (* 1 *) - 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) - 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) - 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) - 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) - 2, 3, 4, 4, 4, 4, 15, 15, (* 2 *) - 11, 15, 16, 5, 7, 8, 15, 11, (* 2 *) - 15, 7, 17, 17, 11, 16, 15, 3, (* 2 *) - 11, 18, 16, 6, 19, 19, 19, 3, (* 2 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 3 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 3 *) - 20, 20, 20, 20, 20, 20, 20, 7, (* 3 *) - 20, 20, 20, 20, 20, 20, 20, 16, (* 3 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 3 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 3 *) - 21, 21, 21, 21, 21, 21, 21, 7, (* 3 *) - 21, 21, 21, 21, 21, 21, 21, 22, (* 3 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) - 25, 26, 23, 24, 23, 24, 23, 24, (* 4 *) - 16, 23, 24, 23, 24, 23, 24, 23, (* 4 *) - 24, 23, 24, 23, 24, 23, 24, 23, (* 5 *) - 24, 16, 23, 24, 23, 24, 23, 24, (* 5 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) - 27, 23, 24, 23, 24, 23, 24, 28, (* 5 *) - 16, 29, 23, 24, 23, 24, 30, 23, (* 6 *) - 24, 31, 31, 23, 24, 16, 32, 32, (* 6 *) - 33, 23, 24, 31, 34, 16, 35, 36, (* 6 *) - 23, 24, 16, 16, 35, 37, 16, 38, (* 6 *) - 23, 24, 23, 24, 23, 24, 38, 23, (* 6 *) - 24, 39, 40, 16, 23, 24, 39, 23, (* 6 *) - 24, 41, 41, 23, 24, 23, 24, 42, (* 6 *) - 23, 24, 16, 40, 23, 24, 40, 40, (* 6 *) - 40, 40, 40, 40, 43, 44, 45, 43, (* 7 *) - 44, 45, 43, 44, 45, 23, 24, 23, (* 7 *) - 24, 23, 24, 23, 24, 23, 24, 23, (* 7 *) - 24, 23, 24, 23, 24, 16, 23, 24, (* 7 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 7 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 7 *) - 16, 43, 44, 45, 23, 24, 46, 46, (* 7 *) - 46, 46, 23, 24, 23, 24, 23, 24, (* 7 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 9 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 9 *) - 16, 16, 16, 47, 48, 16, 49, 49, (* 9 *) - 50, 50, 16, 51, 16, 16, 16, 16, (* 9 *) - 49, 16, 16, 52, 16, 16, 16, 16, (* 9 *) - 53, 54, 16, 16, 16, 16, 16, 54, (* 9 *) - 16, 16, 55, 16, 16, 16, 16, 16, (* 9 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 9 *) - 16, 16, 16, 56, 16, 16, 16, 16, (* 10 *) - 56, 16, 57, 57, 16, 16, 16, 16, (* 10 *) - 16, 16, 58, 16, 16, 16, 16, 16, (* 10 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 10 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 10 *) - 16, 46, 46, 46, 46, 46, 46, 46, (* 10 *) - 59, 59, 59, 59, 59, 59, 59, 59, (* 10 *) - 59, 11, 11, 59, 59, 59, 59, 59, (* 10 *) - 59, 59, 11, 11, 11, 11, 11, 11, (* 11 *) - 11, 11, 11, 11, 11, 11, 11, 11, (* 11 *) - 59, 59, 11, 11, 11, 11, 11, 11, (* 11 *) - 11, 11, 11, 11, 11, 11, 11, 46, (* 11 *) - 59, 59, 59, 59, 59, 11, 11, 11, (* 11 *) - 11, 11, 46, 46, 46, 46, 46, 46, (* 11 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 11 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 11 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) - 60, 60, 60, 60, 60, 60, 46, 46, (* 13 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) - 60, 60, 46, 46, 46, 46, 46, 46, (* 13 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) - 46, 46, 46, 46, 3, 3, 46, 46, (* 13 *) - 46, 46, 59, 46, 46, 46, 3, 46, (* 13 *) - 46, 46, 46, 46, 11, 11, 61, 3, (* 14 *) - 62, 62, 62, 46, 63, 46, 64, 64, (* 14 *) - 16, 20, 20, 20, 20, 20, 20, 20, (* 14 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 14 *) - 20, 20, 46, 20, 20, 20, 20, 20, (* 14 *) - 20, 20, 20, 20, 65, 66, 66, 66, (* 14 *) - 16, 21, 21, 21, 21, 21, 21, 21, (* 14 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 14 *) - 21, 21, 16, 21, 21, 21, 21, 21, (* 15 *) - 21, 21, 21, 21, 67, 68, 68, 46, (* 15 *) - 69, 70, 38, 38, 38, 71, 72, 46, (* 15 *) - 46, 46, 38, 46, 38, 46, 38, 46, (* 15 *) - 38, 46, 23, 24, 23, 24, 23, 24, (* 15 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 15 *) - 73, 74, 16, 40, 46, 46, 46, 46, (* 15 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 15 *) - 46, 75, 75, 75, 75, 75, 75, 75, (* 16 *) - 75, 75, 75, 75, 75, 46, 75, 75, (* 16 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) - 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 16 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 16 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 17 *) - 21, 21, 21, 21, 21, 21, 21, 21, (* 17 *) - 46, 74, 74, 74, 74, 74, 74, 74, (* 17 *) - 74, 74, 74, 74, 74, 46, 74, 74, (* 17 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) - 23, 24, 15, 60, 60, 60, 60, 46, (* 18 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 18 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) - 40, 23, 24, 23, 24, 46, 46, 23, (* 19 *) - 24, 46, 46, 23, 24, 46, 46, 46, (* 19 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) - 23, 24, 23, 24, 46, 46, 23, 24, (* 19 *) - 23, 24, 23, 24, 23, 24, 46, 46, (* 19 *) - 23, 24, 46, 46, 46, 46, 46, 46, (* 19 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) - 46, 76, 76, 76, 76, 76, 76, 76, (* 20 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 20 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 21 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 21 *) - 76, 76, 76, 76, 76, 76, 76, 46, (* 21 *) - 46, 59, 3, 3, 3, 3, 3, 3, (* 21 *) - 46, 77, 77, 77, 77, 77, 77, 77, (* 21 *) - 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) - 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) - 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) - 77, 77, 77, 77, 77, 77, 77, 16, (* 22 *) - 46, 3, 46, 46, 46, 46, 46, 46, (* 22 *) - 46, 60, 60, 60, 60, 60, 60, 60, (* 22 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) - 60, 60, 46, 60, 60, 60, 60, 60, (* 22 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) - 60, 60, 46, 60, 60, 60, 3, 60, (* 22 *) - 3, 60, 60, 3, 60, 46, 46, 46, (* 23 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 23 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) - 40, 40, 40, 46, 46, 46, 46, 46, (* 23 *) - 40, 40, 40, 3, 3, 46, 46, 46, (* 23 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 23 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 24 *) - 46, 46, 46, 46, 3, 46, 46, 46, (* 24 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 24 *) - 46, 46, 46, 3, 46, 46, 46, 3, (* 24 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 24 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 24 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 24 *) - 40, 40, 40, 46, 46, 46, 46, 46, (* 24 *) - 59, 40, 40, 40, 40, 40, 40, 40, (* 25 *) - 40, 40, 40, 60, 60, 60, 60, 60, (* 25 *) - 60, 60, 60, 46, 46, 46, 46, 46, (* 25 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 25 *) - 78, 78, 78, 78, 78, 78, 78, 78, (* 25 *) - 78, 78, 3, 3, 3, 3, 46, 46, (* 25 *) - 60, 40, 40, 40, 40, 40, 40, 40, (* 25 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 25 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) - 46, 46, 40, 40, 40, 40, 40, 46, (* 26 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 27 *) - 40, 40, 40, 40, 40, 40, 40, 46, (* 27 *) - 40, 40, 40, 40, 3, 40, 60, 60, (* 27 *) - 60, 60, 60, 60, 60, 79, 79, 60, (* 27 *) - 60, 60, 60, 60, 60, 59, 59, 60, (* 27 *) - 60, 15, 60, 60, 60, 60, 46, 46, (* 27 *) - 9, 9, 9, 9, 9, 9, 9, 9, (* 27 *) - 9, 9, 46, 46, 46, 46, 46, 46, (* 27 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) - 46, 60, 60, 80, 46, 40, 40, 40, (* 29 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) - 40, 40, 46, 46, 60, 40, 80, 80, (* 29 *) - 80, 60, 60, 60, 60, 60, 60, 60, (* 30 *) - 60, 80, 80, 80, 80, 60, 46, 46, (* 30 *) - 15, 60, 60, 60, 60, 46, 46, 46, (* 30 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 30 *) - 40, 40, 60, 60, 3, 3, 81, 81, (* 30 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 30 *) - 3, 46, 46, 46, 46, 46, 46, 46, (* 30 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 30 *) - 46, 60, 80, 80, 46, 40, 40, 40, (* 31 *) - 40, 40, 40, 40, 40, 46, 46, 40, (* 31 *) - 40, 46, 46, 40, 40, 40, 40, 40, (* 31 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 31 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 31 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 31 *) - 40, 46, 40, 46, 46, 46, 40, 40, (* 31 *) - 40, 40, 46, 46, 60, 46, 80, 80, (* 31 *) - 80, 60, 60, 60, 60, 46, 46, 80, (* 32 *) - 80, 46, 46, 80, 80, 60, 46, 46, (* 32 *) - 46, 46, 46, 46, 46, 46, 46, 80, (* 32 *) - 46, 46, 46, 46, 40, 40, 46, 40, (* 32 *) - 40, 40, 60, 60, 46, 46, 81, 81, (* 32 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 32 *) - 40, 40, 4, 4, 82, 82, 82, 82, (* 32 *) - 19, 83, 15, 46, 46, 46, 46, 46, (* 32 *) - 46, 46, 60, 46, 46, 40, 40, 40, (* 33 *) - 40, 40, 40, 46, 46, 46, 46, 40, (* 33 *) - 40, 46, 46, 40, 40, 40, 40, 40, (* 33 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 33 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 33 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 33 *) - 40, 46, 40, 40, 46, 40, 40, 46, (* 33 *) - 40, 40, 46, 46, 60, 46, 80, 80, (* 33 *) - 80, 60, 60, 46, 46, 46, 46, 60, (* 34 *) - 60, 46, 46, 60, 60, 60, 46, 46, (* 34 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 34 *) - 46, 40, 40, 40, 40, 46, 40, 46, (* 34 *) - 46, 46, 46, 46, 46, 46, 81, 81, (* 34 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 34 *) - 60, 60, 40, 40, 40, 46, 46, 46, (* 34 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 34 *) - 46, 60, 60, 80, 46, 40, 40, 40, (* 35 *) - 40, 40, 40, 40, 46, 40, 46, 40, (* 35 *) - 40, 40, 46, 40, 40, 40, 40, 40, (* 35 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 35 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 35 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 35 *) - 40, 46, 40, 40, 46, 40, 40, 40, (* 35 *) - 40, 40, 46, 46, 60, 40, 80, 80, (* 35 *) - 80, 60, 60, 60, 60, 60, 46, 60, (* 36 *) - 60, 80, 46, 80, 80, 60, 46, 46, (* 36 *) - 15, 46, 46, 46, 46, 46, 46, 46, (* 36 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) - 40, 46, 46, 46, 46, 46, 81, 81, (* 36 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 36 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) - 46, 60, 80, 80, 46, 40, 40, 40, (* 37 *) - 40, 40, 40, 40, 40, 46, 46, 40, (* 37 *) - 40, 46, 46, 40, 40, 40, 40, 40, (* 37 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 37 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 37 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 37 *) - 40, 46, 40, 40, 46, 46, 40, 40, (* 37 *) - 40, 40, 46, 46, 60, 40, 80, 60, (* 37 *) - 80, 60, 60, 60, 46, 46, 46, 80, (* 38 *) - 80, 46, 46, 80, 80, 60, 46, 46, (* 38 *) - 46, 46, 46, 46, 46, 46, 60, 80, (* 38 *) - 46, 46, 46, 46, 40, 40, 46, 40, (* 38 *) - 40, 40, 46, 46, 46, 46, 81, 81, (* 38 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 38 *) - 15, 46, 46, 46, 46, 46, 46, 46, (* 38 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 38 *) - 46, 46, 60, 80, 46, 40, 40, 40, (* 39 *) - 40, 40, 40, 46, 46, 46, 40, 40, (* 39 *) - 40, 46, 40, 40, 40, 40, 46, 46, (* 39 *) - 46, 40, 40, 46, 40, 46, 40, 40, (* 39 *) - 46, 46, 46, 40, 40, 46, 46, 46, (* 39 *) - 40, 40, 40, 46, 46, 46, 40, 40, (* 39 *) - 40, 40, 40, 40, 40, 40, 46, 40, (* 39 *) - 40, 40, 46, 46, 46, 46, 80, 80, (* 39 *) - 60, 80, 80, 46, 46, 46, 80, 80, (* 40 *) - 80, 46, 80, 80, 80, 60, 46, 46, (* 40 *) - 46, 46, 46, 46, 46, 46, 46, 80, (* 40 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 40 *) - 46, 46, 46, 46, 46, 46, 46, 81, (* 40 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 40 *) - 84, 19, 19, 46, 46, 46, 46, 46, (* 40 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 40 *) - 46, 80, 80, 80, 46, 40, 40, 40, (* 41 *) - 40, 40, 40, 40, 40, 46, 40, 40, (* 41 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 41 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 41 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 41 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 41 *) - 40, 40, 40, 40, 46, 40, 40, 40, (* 41 *) - 40, 40, 46, 46, 46, 46, 60, 60, (* 41 *) - 60, 80, 80, 80, 80, 46, 60, 60, (* 42 *) - 60, 46, 60, 60, 60, 60, 46, 46, (* 42 *) - 46, 46, 46, 46, 46, 60, 60, 46, (* 42 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) - 40, 40, 46, 46, 46, 46, 81, 81, (* 42 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 42 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) - 46, 46, 80, 80, 46, 40, 40, 40, (* 43 *) - 40, 40, 40, 40, 40, 46, 40, 40, (* 43 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 43 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 43 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 43 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 43 *) - 40, 40, 40, 40, 46, 40, 40, 40, (* 43 *) - 40, 40, 46, 46, 46, 46, 80, 60, (* 43 *) - 80, 80, 80, 80, 80, 46, 60, 80, (* 44 *) - 80, 46, 80, 80, 60, 60, 46, 46, (* 44 *) - 46, 46, 46, 46, 46, 80, 80, 46, (* 44 *) - 46, 46, 46, 46, 46, 46, 40, 46, (* 44 *) - 40, 40, 46, 46, 46, 46, 81, 81, (* 44 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 44 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 44 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 44 *) - 46, 46, 80, 80, 46, 40, 40, 40, (* 45 *) - 40, 40, 40, 40, 40, 46, 40, 40, (* 45 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 45 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) - 40, 46, 40, 40, 40, 40, 40, 40, (* 45 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) - 40, 40, 46, 46, 46, 46, 80, 80, (* 45 *) - 80, 60, 60, 60, 46, 46, 80, 80, (* 46 *) - 80, 46, 80, 80, 80, 60, 46, 46, (* 46 *) - 46, 46, 46, 46, 46, 46, 46, 80, (* 46 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) - 40, 40, 46, 46, 46, 46, 81, 81, (* 46 *) - 81, 81, 81, 81, 81, 81, 81, 81, (* 46 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 47 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) - 40, 40, 40, 40, 40, 40, 40, 3, (* 47 *) - 40, 60, 40, 40, 60, 60, 60, 60, (* 47 *) - 60, 60, 60, 46, 46, 46, 46, 4, (* 47 *) - 40, 40, 40, 40, 40, 40, 59, 60, (* 48 *) - 60, 60, 60, 60, 60, 60, 60, 15, (* 48 *) - 9, 9, 9, 9, 9, 9, 9, 9, (* 48 *) - 9, 9, 3, 3, 46, 46, 46, 46, (* 48 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) - 46, 40, 40, 46, 40, 46, 46, 40, (* 49 *) - 40, 46, 40, 46, 46, 40, 46, 46, (* 49 *) - 46, 46, 46, 46, 40, 40, 40, 40, (* 49 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 49 *) - 46, 40, 40, 40, 46, 40, 46, 40, (* 49 *) - 46, 46, 40, 40, 46, 40, 40, 3, (* 49 *) - 40, 60, 40, 40, 60, 60, 60, 60, (* 49 *) - 60, 60, 46, 60, 60, 40, 46, 46, (* 49 *) - 40, 40, 40, 40, 40, 46, 59, 46, (* 50 *) - 60, 60, 60, 60, 60, 60, 46, 46, (* 50 *) - 9, 9, 9, 9, 9, 9, 9, 9, (* 50 *) - 9, 9, 46, 46, 40, 40, 46, 46, (* 50 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) - 15, 15, 15, 15, 3, 3, 3, 3, (* 51 *) - 3, 3, 3, 3, 3, 3, 3, 3, (* 51 *) - 3, 3, 3, 15, 15, 15, 15, 15, (* 51 *) - 60, 60, 15, 15, 15, 15, 15, 15, (* 51 *) - 78, 78, 78, 78, 78, 78, 78, 78, (* 51 *) - 78, 78, 85, 85, 85, 85, 85, 85, (* 51 *) - 85, 85, 85, 85, 15, 60, 15, 60, (* 51 *) - 15, 60, 5, 6, 5, 6, 80, 80, (* 51 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 52 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) - 40, 40, 46, 46, 46, 46, 46, 46, (* 52 *) - 46, 60, 60, 60, 60, 60, 60, 60, (* 52 *) - 60, 60, 60, 60, 60, 60, 60, 80, (* 52 *) - 60, 60, 60, 60, 60, 3, 60, 60, (* 53 *) - 60, 60, 60, 60, 46, 46, 46, 46, (* 53 *) - 60, 60, 60, 60, 60, 60, 46, 60, (* 53 *) - 46, 60, 60, 60, 60, 60, 60, 60, (* 53 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 53 *) - 60, 60, 60, 60, 60, 60, 46, 46, (* 53 *) - 46, 60, 60, 60, 60, 60, 60, 60, (* 53 *) - 46, 60, 46, 46, 46, 46, 46, 46, (* 53 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) - 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) - 76, 76, 76, 76, 76, 76, 46, 46, (* 55 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 55 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) - 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) - 16, 16, 16, 16, 16, 16, 16, 46, (* 55 *) - 46, 46, 46, 3, 46, 46, 46, 46, (* 55 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 46, 46, 46, 46, 46, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 46, 46, 46, 46, 46, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) - 40, 40, 46, 46, 46, 46, 46, 46, (* 59 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) - 23, 24, 23, 24, 23, 24, 16, 16, (* 61 *) - 16, 16, 16, 16, 46, 46, 46, 46, (* 61 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) - 23, 24, 46, 46, 46, 46, 46, 46, (* 62 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) - 86, 86, 86, 86, 86, 86, 46, 46, (* 63 *) - 87, 87, 87, 87, 87, 87, 46, 46, (* 63 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) - 86, 86, 86, 86, 86, 86, 46, 46, (* 64 *) - 87, 87, 87, 87, 87, 87, 46, 46, (* 64 *) - 16, 86, 16, 86, 16, 86, 16, 86, (* 64 *) - 46, 87, 46, 87, 46, 87, 46, 87, (* 64 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 64 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 64 *) - 88, 88, 89, 89, 89, 89, 90, 90, (* 64 *) - 91, 91, 92, 92, 93, 93, 46, 46, (* 64 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) - 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) - 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) - 86, 86, 16, 94, 16, 46, 16, 16, (* 65 *) - 87, 87, 95, 95, 96, 11, 38, 11, (* 65 *) - 11, 11, 16, 94, 16, 46, 16, 16, (* 66 *) - 97, 97, 97, 97, 96, 11, 11, 11, (* 66 *) - 86, 86, 16, 16, 46, 46, 16, 16, (* 66 *) - 87, 87, 98, 98, 46, 11, 11, 11, (* 66 *) - 86, 86, 16, 16, 16, 99, 16, 16, (* 66 *) - 87, 87, 100, 100, 101, 11, 11, 11, (* 66 *) - 46, 46, 16, 94, 16, 46, 16, 16, (* 66 *) -102, 102, 103, 103, 96, 11, 11, 46, (* 66 *) - 2, 2, 2, 2, 2, 2, 2, 2, (* 67 *) - 2, 2, 2, 2, 104, 104, 104, 104, (* 67 *) - 8, 8, 8, 8, 8, 8, 3, 3, (* 67 *) - 5, 6, 5, 5, 5, 6, 5, 5, (* 67 *) - 3, 3, 3, 3, 3, 3, 3, 3, (* 67 *) -105, 106, 104, 104, 104, 104, 104, 46, (* 67 *) - 3, 3, 3, 3, 3, 3, 3, 3, (* 67 *) - 3, 5, 6, 3, 3, 3, 3, 12, (* 67 *) - 12, 3, 3, 3, 7, 5, 6, 46, (* 68 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) - 46, 46, 104, 104, 104, 104, 104, 104, (* 68 *) - 17, 46, 46, 46, 17, 17, 17, 17, (* 68 *) - 17, 17, 7, 7, 7, 5, 6, 16, (* 68 *) -107, 107, 107, 107, 107, 107, 107, 107, (* 69 *) -107, 107, 7, 7, 7, 5, 6, 46, (* 69 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) - 4, 4, 4, 4, 4, 4, 4, 4, (* 69 *) - 4, 4, 4, 4, 46, 46, 46, 46, (* 69 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) - 60, 60, 60, 60, 60, 60, 60, 60, (* 70 *) - 60, 60, 60, 60, 60, 79, 79, 79, (* 70 *) - 79, 60, 46, 46, 46, 46, 46, 46, (* 70 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) - 15, 15, 38, 15, 15, 15, 15, 38, (* 71 *) - 15, 15, 16, 38, 38, 38, 16, 16, (* 71 *) - 38, 38, 38, 16, 15, 38, 15, 15, (* 71 *) - 38, 38, 38, 38, 38, 38, 15, 15, (* 71 *) - 15, 15, 15, 15, 38, 15, 38, 15, (* 71 *) - 38, 15, 38, 38, 38, 38, 16, 16, (* 71 *) - 38, 38, 15, 38, 16, 40, 40, 40, (* 71 *) - 40, 46, 46, 46, 46, 46, 46, 46, (* 71 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 72 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 72 *) - 46, 46, 46, 19, 19, 19, 19, 19, (* 72 *) - 19, 19, 19, 19, 19, 19, 19, 108, (* 72 *) -109, 109, 109, 109, 109, 109, 109, 109, (* 72 *) -109, 109, 109, 109, 110, 110, 110, 110, (* 72 *) -111, 111, 111, 111, 111, 111, 111, 111, (* 72 *) -111, 111, 111, 111, 112, 112, 112, 112, (* 72 *) -113, 113, 113, 46, 46, 46, 46, 46, (* 73 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 73 *) - - 7, 7, 7, 7, 7, 15, 15, 15, (* 73 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) - 15, 15, 7, 15, 7, 15, 15, 15, (* 74 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) - 15, 15, 15, 46, 46, 46, 46, 46, (* 74 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 74 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 74 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) - 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) - 7, 7, 46, 46, 46, 46, 46, 46, (* 76 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 76 *) - 15, 46, 15, 15, 15, 15, 15, 15, (* 77 *) - 7, 7, 7, 7, 15, 15, 15, 15, (* 77 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) - 7, 7, 15, 15, 15, 15, 15, 15, (* 77 *) - 15, 5, 6, 15, 15, 15, 15, 15, (* 77 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) - 15, 15, 15, 46, 46, 46, 46, 46, (* 78 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) - 15, 15, 15, 15, 15, 46, 46, 46, (* 79 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 80 *) - 15, 15, 15, 46, 46, 46, 46, 46, (* 80 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 80 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 80 *) -114, 114, 114, 114, 114, 114, 114, 114, (* 80 *) -114, 114, 114, 114, 114, 114, 114, 114, (* 80 *) -114, 114, 114, 114, 82, 82, 82, 82, (* 80 *) - 82, 82, 82, 82, 82, 82, 82, 82, (* 80 *) - 82, 82, 82, 82, 82, 82, 82, 82, (* 81 *) -115, 115, 115, 115, 115, 115, 115, 115, (* 81 *) -115, 115, 115, 115, 115, 115, 115, 115, (* 81 *) -115, 115, 115, 115, 15, 15, 15, 15, (* 81 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 81 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 81 *) - 15, 15, 15, 15, 15, 15, 116, 116, (* 81 *) -116, 116, 116, 116, 116, 116, 116, 116, (* 81 *) -116, 116, 116, 116, 116, 116, 116, 116, (* 82 *) -116, 116, 116, 116, 116, 116, 116, 116, (* 82 *) -117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) -117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) -117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) -117, 117, 118, 46, 46, 46, 46, 46, (* 82 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 82 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 82 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) - 15, 15, 15, 15, 15, 15, 46, 46, (* 84 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 84 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 85 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 85 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) - 15, 15, 15, 15, 46, 46, 46, 46, (* 86 *) - 46, 46, 15, 15, 15, 15, 15, 15, (* 86 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) - 46, 15, 15, 15, 15, 46, 15, 15, (* 87 *) - 15, 15, 46, 46, 15, 15, 15, 15, (* 87 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) - 46, 15, 15, 15, 15, 15, 15, 15, (* 87 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 88 *) - 15, 15, 15, 15, 46, 15, 46, 15, (* 88 *) - 15, 15, 15, 46, 46, 46, 15, 46, (* 88 *) - 15, 15, 15, 15, 15, 15, 15, 46, (* 88 *) - 46, 15, 15, 15, 15, 15, 15, 15, (* 88 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 88 *) - 46, 46, 46, 46, 46, 46, 119, 119, (* 88 *) -119, 119, 119, 119, 119, 119, 119, 119, (* 88 *) -114, 114, 114, 114, 114, 114, 114, 114, (* 89 *) -114, 114, 83, 83, 83, 83, 83, 83, (* 89 *) - 83, 83, 83, 83, 15, 46, 46, 46, (* 89 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) - 46, 15, 15, 15, 15, 15, 15, 15, (* 89 *) - 15, 15, 15, 15, 15, 15, 15, 46, (* 89 *) - 2, 3, 3, 3, 15, 59, 3, 120, (* 90 *) - 5, 6, 5, 6, 5, 6, 5, 6, (* 90 *) - 5, 6, 15, 15, 5, 6, 5, 6, (* 90 *) - 5, 6, 5, 6, 8, 5, 6, 5, (* 90 *) - 15, 121, 121, 121, 121, 121, 121, 121, (* 90 *) -121, 121, 60, 60, 60, 60, 60, 60, (* 90 *) - 8, 59, 59, 59, 59, 59, 15, 15, (* 90 *) - 46, 46, 46, 46, 46, 46, 46, 15, (* 90 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) - 40, 40, 40, 40, 40, 46, 46, 46, (* 92 *) - 46, 60, 60, 59, 59, 59, 59, 46, (* 92 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 92 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) - 40, 40, 40, 3, 59, 59, 59, 46, (* 93 *) - 46, 46, 46, 46, 46, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 46, 46, 46, (* 94 *) - 46, 40, 40, 40, 40, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 95 *) - 40, 40, 40, 40, 40, 40, 40, 46, (* 95 *) - 15, 15, 85, 85, 85, 85, 15, 15, (* 95 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 95 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) - 15, 15, 15, 15, 15, 46, 46, 46, (* 96 *) - 85, 85, 85, 85, 85, 85, 85, 85, (* 96 *) - 85, 85, 15, 15, 15, 15, 15, 15, (* 96 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) - 15, 15, 15, 15, 46, 46, 46, 46, (* 97 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) - 15, 15, 15, 15, 46, 46, 46, 15, (* 97 *) -114, 114, 114, 114, 114, 114, 114, 114, (* 98 *) -114, 114, 15, 15, 15, 15, 15, 15, (* 98 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) - 15, 46, 46, 46, 46, 46, 46, 46, (* 98 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 98 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) - 15, 15, 15, 15, 46, 46, 46, 46, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 46, (* 99 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 46, (* 100 *) - 46, 46, 46, 15, 15, 15, 15, 15, (* 100 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) - 15, 15, 15, 15, 15, 15, 46, 46, (* 101 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) - 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) - 15, 15, 15, 15, 15, 15, 15, 46, (* 101 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) - 40, 40, 40, 40, 40, 40, 46, 46, (* 102 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) - 40, 40, 40, 40, 46, 46, 46, 46, (* 103 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) -123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) - 40, 40, 40, 40, 40, 40, 46, 46, (* 106 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 106 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 106 *) - 16, 16, 16, 16, 16, 16, 16, 46, (* 107 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 107 *) - 46, 46, 46, 16, 16, 16, 16, 16, (* 107 *) - 46, 46, 46, 46, 46, 46, 60, 40, (* 107 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 107 *) - 40, 7, 40, 40, 40, 40, 40, 40, (* 107 *) - 40, 40, 40, 40, 40, 40, 40, 46, (* 107 *) - 40, 40, 40, 40, 40, 46, 40, 46, (* 107 *) - 40, 40, 46, 40, 40, 46, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) - 40, 40, 46, 46, 46, 46, 46, 46, (* 109 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 109 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 110 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 110 *) - 46, 46, 46, 40, 40, 40, 40, 40, (* 110 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) - 40, 40, 40, 40, 40, 40, 5, 6, (* 111 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 112 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 46, 46, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 114 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 114 *) - 40, 40, 40, 40, 46, 46, 46, 46, (* 114 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) - 60, 60, 60, 60, 46, 46, 46, 46, (* 115 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) - 3, 8, 8, 12, 12, 5, 6, 5, (* 115 *) - 6, 5, 6, 5, 6, 5, 6, 5, (* 115 *) - 6, 5, 6, 5, 6, 46, 46, 46, (* 116 *) - 46, 3, 3, 3, 3, 12, 12, 12, (* 116 *) - 3, 3, 3, 46, 3, 3, 3, 3, (* 116 *) - 8, 5, 6, 5, 6, 5, 6, 3, (* 116 *) - 3, 3, 7, 8, 7, 7, 7, 46, (* 116 *) - 3, 4, 3, 3, 46, 46, 46, 46, (* 116 *) - 40, 40, 40, 46, 40, 46, 40, 40, (* 116 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 116 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) - 40, 40, 40, 40, 40, 46, 46, 104, (* 117 *) - 46, 3, 3, 3, 4, 3, 3, 3, (* 118 *) - 5, 6, 3, 7, 3, 8, 3, 3, (* 118 *) - 9, 9, 9, 9, 9, 9, 9, 9, (* 118 *) - 9, 9, 3, 3, 7, 7, 7, 3, (* 118 *) - 3, 10, 10, 10, 10, 10, 10, 10, (* 118 *) - 10, 10, 10, 10, 10, 10, 10, 10, (* 118 *) - 10, 10, 10, 10, 10, 10, 10, 10, (* 118 *) - 10, 10, 10, 5, 3, 6, 11, 12, (* 118 *) - 11, 13, 13, 13, 13, 13, 13, 13, (* 119 *) - 13, 13, 13, 13, 13, 13, 13, 13, (* 119 *) - 13, 13, 13, 13, 13, 13, 13, 13, (* 119 *) - 13, 13, 13, 5, 7, 6, 7, 46, (* 119 *) - 46, 3, 5, 6, 3, 3, 40, 40, (* 119 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 119 *) - 59, 40, 40, 40, 40, 40, 40, 40, (* 119 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 119 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) - 40, 40, 40, 40, 40, 40, 59, 59, (* 120 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) - 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) - 40, 40, 40, 40, 40, 40, 40, 46, (* 120 *) - 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) - 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) - 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) - 46, 46, 40, 40, 40, 46, 46, 46, (* 121 *) - 4, 4, 7, 11, 15, 4, 4, 46, (* 121 *) - 7, 7, 7, 7, 7, 15, 15, 46, (* 121 *) - 46, 46, 46, 46, 46, 46, 46, 46, (* 121 *) - 46, 46, 46, 46, 46, 15, 46, 46); (* 121 *) - -UnicodeALut:array[0..123] of longword=( - $0001000F, (* 0 Cc, ignorable *) - $0004000F, (* 1 Cc, whitespace *) - $0004000C, (* 2 Zs, whitespace *) - $00000018, (* 3 Po *) - $0006001A, (* 4 Sc, currency *) - $00000015, (* 5 Ps *) - $00000016, (* 6 Pe *) - $00000019, (* 7 Sm *) - $00000014, (* 8 Pd *) - $00036089, (* 9 Nd, identifier part, decimal 16 *) - $0827FF81, (* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 *) - $0000001B, (* 11 Sk *) - $00050017, (* 12 Pc, underscore *) - $0817FF82, (* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 *) - $0000000C, (* 14 Zs *) - $0000001C, (* 15 So *) - $00070182, (* 16 Ll, identifier start *) - $0000600B, (* 17 No, decimal 16 *) - $0000500B, (* 18 No, decimal 8 *) - $0000800B, (* 19 No, strange *) - $08270181, (* 20 Lu, hasLower (add 32), identifier start *) - $08170182, (* 21 Ll, hasUpper (subtract 32), identifier start *) - $E1D70182, (* 22 Ll, hasUpper (subtract -121), identifier start *) - $00670181, (* 23 Lu, hasLower (add 1), identifier start *) - $00570182, (* 24 Ll, hasUpper (subtract 1), identifier start *) - $CE670181, (* 25 Lu, hasLower (add -199), identifier start *) - $3A170182, (* 26 Ll, hasUpper (subtract 232), identifier start *) - $E1E70181, (* 27 Lu, hasLower (add -121), identifier start *) - $4B170182, (* 28 Ll, hasUpper (subtract 300), identifier start *) - $34A70181, (* 29 Lu, hasLower (add 210), identifier start *) - $33A70181, (* 30 Lu, hasLower (add 206), identifier start *) - $33670181, (* 31 Lu, hasLower (add 205), identifier start *) - $32A70181, (* 32 Lu, hasLower (add 202), identifier start *) - $32E70181, (* 33 Lu, hasLower (add 203), identifier start *) - $33E70181, (* 34 Lu, hasLower (add 207), identifier start *) - $34E70181, (* 35 Lu, hasLower (add 211), identifier start *) - $34670181, (* 36 Lu, hasLower (add 209), identifier start *) - $35670181, (* 37 Lu, hasLower (add 213), identifier start *) - $00070181, (* 38 Lu, identifier start *) - $36A70181, (* 39 Lu, hasLower (add 218), identifier start *) - $00070185, (* 40 Lo, identifier start *) - $36670181, (* 41 Lu, hasLower (add 217), identifier start *) - $36E70181, (* 42 Lu, hasLower (add 219), identifier start *) - $00AF0181, (* 43 Lu, hasLower (add 2), hasTitle, identifier start *) - $007F0183, (* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start *) - $009F0182, (* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start *) - $00000000, (* 46 unassigned *) - $34970182, (* 47 Ll, hasUpper (subtract 210), identifier start *) - $33970182, (* 48 Ll, hasUpper (subtract 206), identifier start *) - $33570182, (* 49 Ll, hasUpper (subtract 205), identifier start *) - $32970182, (* 50 Ll, hasUpper (subtract 202), identifier start *) - $32D70182, (* 51 Ll, hasUpper (subtract 203), identifier start *) - $33D70182, (* 52 Ll, hasUpper (subtract 207), identifier start *) - $34570182, (* 53 Ll, hasUpper (subtract 209), identifier start *) - $34D70182, (* 54 Ll, hasUpper (subtract 211), identifier start *) - $35570182, (* 55 Ll, hasUpper (subtract 213), identifier start *) - $36970182, (* 56 Ll, hasUpper (subtract 218), identifier start *) - $36570182, (* 57 Ll, hasUpper (subtract 217), identifier start *) - $36D70182, (* 58 Ll, hasUpper (subtract 219), identifier start *) - $00070084, (* 59 Lm, identifier start *) - $00030086, (* 60 Mn, identifier part *) - $09A70181, (* 61 Lu, hasLower (add 38), identifier start *) - $09670181, (* 62 Lu, hasLower (add 37), identifier start *) - $10270181, (* 63 Lu, hasLower (add 64), identifier start *) - $0FE70181, (* 64 Lu, hasLower (add 63), identifier start *) - $09970182, (* 65 Ll, hasUpper (subtract 38), identifier start *) - $09570182, (* 66 Ll, hasUpper (subtract 37), identifier start *) - $10170182, (* 67 Ll, hasUpper (subtract 64), identifier start *) - $0FD70182, (* 68 Ll, hasUpper (subtract 63), identifier start *) - $0F970182, (* 69 Ll, hasUpper (subtract 62), identifier start *) - $0E570182, (* 70 Ll, hasUpper (subtract 57), identifier start *) - $0BD70182, (* 71 Ll, hasUpper (subtract 47), identifier start *) - $0D970182, (* 72 Ll, hasUpper (subtract 54), identifier start *) - $15970182, (* 73 Ll, hasUpper (subtract 86), identifier start *) - $14170182, (* 74 Ll, hasUpper (subtract 80), identifier start *) - $14270181, (* 75 Lu, hasLower (add 80), identifier start *) - $0C270181, (* 76 Lu, hasLower (add 48), identifier start *) - $0C170182, (* 77 Ll, hasUpper (subtract 48), identifier start *) - $00034089, (* 78 Nd, identifier part, decimal 0 *) - $00000087, (* 79 Me *) - $00030088, (* 80 Mc, identifier part *) - $00037489, (* 81 Nd, identifier part, decimal 26 *) - $00005A0B, (* 82 No, decimal 13 *) - $00006E0B, (* 83 No, decimal 23 *) - $0000740B, (* 84 No, decimal 26 *) - $0000000B, (* 85 No *) - $FE170182, (* 86 Ll, hasUpper (subtract -8), identifier start *) - $FE270181, (* 87 Lu, hasLower (add -8), identifier start *) - $ED970182, (* 88 Ll, hasUpper (subtract -74), identifier start *) - $EA970182, (* 89 Ll, hasUpper (subtract -86), identifier start *) - $E7170182, (* 90 Ll, hasUpper (subtract -100), identifier start *) - $E0170182, (* 91 Ll, hasUpper (subtract -128), identifier start *) - $E4170182, (* 92 Ll, hasUpper (subtract -112), identifier start *) - $E0970182, (* 93 Ll, hasUpper (subtract -126), identifier start *) - $FDD70182, (* 94 Ll, hasUpper (subtract -9), identifier start *) - $EDA70181, (* 95 Lu, hasLower (add -74), identifier start *) - $FDE70181, (* 96 Lu, hasLower (add -9), identifier start *) - $EAA70181, (* 97 Lu, hasLower (add -86), identifier start *) - $E7270181, (* 98 Lu, hasLower (add -100), identifier start *) - $FE570182, (* 99 Ll, hasUpper (subtract -7), identifier start *) - $E4270181, (* 100 Lu, hasLower (add -112), identifier start *) - $FE670181, (* 101 Lu, hasLower (add -7), identifier start *) - $E0270181, (* 102 Lu, hasLower (add -128), identifier start *) - $E0A70181, (* 103 Lu, hasLower (add -126), identifier start *) - $00010010, (* 104 Cf, ignorable *) - $0004000D, (* 105 Zl, whitespace *) - $0004000E, (* 106 Zp, whitespace *) - $0000400B, (* 107 No, decimal 0 *) - $0000440B, (* 108 No, decimal 2 *) - $0427438A, (* 109 Nl, hasLower (add 16), identifier start, decimal 1 *) - $0427818A, (* 110 Nl, hasLower (add 16), identifier start, strange *) - $0417638A, (* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 *) - $0417818A, (* 112 Nl, hasUpper (subtract 16), identifier start, strange *) - $0007818A, (* 113 Nl, identifier start, strange *) - $0000420B, (* 114 No, decimal 1 *) - $0000720B, (* 115 No, decimal 25 *) - $06A0001C, (* 116 So, hasLower (add 26) *) - $0690001C, (* 117 So, hasUpper (subtract 26) *) - $00006C0B, (* 118 No, decimal 22 *) - $0000560B, (* 119 No, decimal 11 *) - $0007738A, (* 120 Nl, identifier start, decimal 25 *) - $0007418A, (* 121 Nl, identifier start, decimal 0 *) - $00000013, (* 122 Cs *) - $00000012); (* 123 Co *) - - -implementation - -end. diff --git a/3rd/besen/src/BESENUtils.pas b/3rd/besen/src/BESENUtils.pas deleted file mode 100644 index 23f7339df..000000000 --- a/3rd/besen/src/BESENUtils.pas +++ /dev/null @@ -1,76 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENUtils; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes; - -function BESENRoundUpToMask(x,m:ptruint):ptruint; -function BESENRoundUpToPowerOfTwo(x:ptruint):ptruint; - -procedure BESENFreeAndNil(var Obj); - -implementation - -function BESENRoundUpToMask(x,m:ptruint):ptruint; -begin - if (x and (m-1))<>0 then begin - result:=(x+m) and not (m-1); - end else begin - result:=x; - end; -end; - -function BESENRoundUpToPowerOfTwo(x:ptruint):ptruint; -begin - dec(x); - x:=x or (x shr 1); - x:=x or (x shr 2); - x:=x or (x shr 4); - x:=x or (x shr 8); - x:=x or (x shr 16); -{$ifdef cpu64} - x:=x or (x shr 32); -{$endif} - result:=x+1; -end; - -procedure BESENFreeAndNil(var Obj); -begin - if assigned(TObject(Obj)) then begin - TObject(Obj).Free; - TObject(Obj):=nil; - end; -end; - -end. diff --git a/3rd/besen/src/BESENValue.pas b/3rd/besen/src/BESENValue.pas deleted file mode 100644 index 040937e5b..000000000 --- a/3rd/besen/src/BESENValue.pas +++ /dev/null @@ -1,705 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENValue; -{$i BESEN.inc} - -interface - -uses BESENConstants,BESENTypes,BESENStringUtils,BESENCharSet,Variants; - -const brbvtUNDEFINED=0; - brbvtBOOLEAN=1; - brbvtNUMBER=2; - brbvtSTRING=3; - brbvtOBJECT=4; - brbvtENVREC=5; - - brbvtFIRST=brbvtUNDEFINED; - brbvtLAST=brbvtENVREC; - - bvtUNDEFINED=0; - bvtNULL=1; - bvtBOOLEAN=2; - bvtNUMBER=3; - bvtSTRING=4; - bvtOBJECT=5; - bvtREFERENCE=6; - bvtLOCAL=7; - bvtENVREC=8; - bvtNONE=9; - - bvtFIRST=bvtUNDEFINED; - bvtLAST=bvtNONE; - -type TBESENReferenceBaseValueType=ptruint; - - PBESENReferenceBaseValue=^TBESENReferenceBaseValue; - TBESENReferenceBaseValue=record - Str:TBESENString; -{$ifdef BESENEmbarcaderoNextGen} - Obj:TObject; - EnvRec:TObject; -{$endif} - case ValueType:TBESENReferenceBaseValueType of - brbvtUNDEFINED:( - ); - brbvtBOOLEAN:( - Bool:TBESENBoolean; - ); - brbvtNUMBER:( - Num:TBESENNumber; - ); - brbvtSTRING:( - ); - brbvtOBJECT:( -{$ifndef BESENEmbarcaderoNextGen} - Obj:TObject; -{$endif} - ); - brbvtENVREC:( -{$ifndef BESENEmbarcaderoNextGen} - EnvRec:TObject; -{$endif} - ); - end; - - TBESENValueType=ptruint; - - PBESENValue=^TBESENValue; - TBESENValue=record - Str:TBESENString; - ReferenceBase:TBESENReferenceBaseValue; -{$ifdef BESENEmbarcaderoNextGen} - Obj:TObject; - EnvRec:TObject; -{$endif} - case ValueType:TBESENValueType of - bvtUNDEFINED:( - ); - bvtNULL:( - ); - bvtBOOLEAN:( - Bool:TBESENBoolean; - ); - bvtNUMBER:( - Num:TBESENNumber; - ); - bvtSTRING:( - ); - bvtOBJECT:( -{$ifndef BESENEmbarcaderoNextGen} - Obj:TObject; -{$endif} - ); - bvtREFERENCE:( - ReferenceIsStrict:longbool; - ReferenceHash:TBESENHash; - ReferenceIndex:TBESENINT32; - ReferenceID:TBESENINT32; - ); - bvtLOCAL:( - LocalIndex:TBESENINT32; - ); - bvtENVREC:( -{$ifndef BESENEmbarcaderoNextGen} - EnvRec:TObject; -{$endif} - ); - bvtNONE:( - ); - end; - - TBESENValueTypes=array of TBESENValueType; - - TBESENValueTypesItems=array of TBESENValueTypes; - - TBESENValues=array of TBESENValue; - - TBESENValuePointers=array of PBESENValue; - - PPBESENValues=^TPBESENValues; - TPBESENValues=array[0..($7fffffff div sizeof(PBESENValue))-1] of PBESENValue; - - TBESENPointerToValues=array of PBESENValue; - - TBESENCopyReferenceBaseValueProc=procedure(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - - TBESENCopyReferenceBaseValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENCopyReferenceBaseValueProc; - - TBESENCopyValueProc=procedure(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} - - TBESENCopyValueProcs=array[bvtFIRST..bvtLAST] of TBESENCopyValueProc; - - TBESENValueToRefBaseValueProc=procedure(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} - - TBESENValueToRefBaseValueProcs=array[bvtFIRST..bvtLAST] of TBESENValueToRefBaseValueProc; - - TBESENRefBaseValueToValueProc=procedure(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - - TBESENRefBaseValueToValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENRefBaseValueToValueProc; - - TBESENRefBaseValueToCallThisArgValueProc=procedure(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); - - TBESENRefBaseValueToCallThisArgValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENRefBaseValueToCallThisArgValueProc; - -procedure BESENCopyReferenceBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyReferenceBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyReferenceBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyReferenceBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyReferenceBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyReferenceBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyReferenceBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENCopyReferenceBaseValue(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENCopyValueUndefined(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueNull(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueBoolean(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueNumber(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueString(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueObject(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueReference(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueLocal(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueEnvRec(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENCopyValueNone(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENCopyValue(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENValueToRefBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueNull(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueReference(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueLocal(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -procedure BESENValueToRefBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENValueToReferenceBaseValue(const Value:TBESENValue;var AResult:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENRefBaseValueToValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENReferenceBaseValueToValue(const Value:TBESENReferenceBaseValue;var AResult:TBESENValue); {$ifdef UseRegister}register;{$endif} - -procedure BESENRefBaseValueToCallThisArgValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToCallThisArgValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToCallThisArgValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToCallThisArgValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToCallThisArgValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -procedure BESENRefBaseValueToCallThisArgValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} - -const BESENCopyReferenceBaseValueProcs:TBESENCopyReferenceBaseValueProcs=(BESENCopyReferenceBaseValueUndefined, - BESENCopyReferenceBaseValueBoolean, - BESENCopyReferenceBaseValueNumber, - BESENCopyReferenceBaseValueString, - BESENCopyReferenceBaseValueObject, - BESENCopyReferenceBaseValueEnvRec); - - BESENCopyValueProcs:TBESENCopyValueProcs=(BESENCopyValueUndefined, - BESENCopyValueNull, - BESENCopyValueBoolean, - BESENCopyValueNumber, - BESENCopyValueString, - BESENCopyValueObject, - BESENCopyValueReference, - BESENCopyValueLocal, - BESENCopyValueEnvRec, - BESENCopyValueNone); - - BESENValueToRefBaseValueProcs:TBESENValueToRefBaseValueProcs=(BESENValueToRefBaseValueUndefined, - BESENValueToRefBaseValueNull, - BESENValueToRefBaseValueBoolean, - BESENValueToRefBaseValueNumber, - BESENValueToRefBaseValueString, - BESENValueToRefBaseValueObject, - BESENValueToRefBaseValueReference, - BESENValueToRefBaseValueLocal, - BESENValueToRefBaseValueEnvRec, - BESENValueToRefBaseValueNone); - - BESENRefBaseValueToValueProcs:TBESENRefBaseValueToValueProcs=(BESENRefBaseValueToValueUndefined, - BESENRefBaseValueToValueBoolean, - BESENRefBaseValueToValueNumber, - BESENRefBaseValueToValueString, - BESENRefBaseValueToValueObject, - BESENRefBaseValueToValueEnvRec); - - BESENRefBaseValueToCallThisArgValueProcs:TBESENRefBaseValueToCallThisArgValueProcs=(BESENRefBaseValueToCallThisArgValueUndefined, - BESENRefBaseValueToCallThisArgValueBoolean, - BESENRefBaseValueToCallThisArgValueNumber, - BESENRefBaseValueToCallThisArgValueString, - BESENRefBaseValueToCallThisArgValueObject, - BESENRefBaseValueToCallThisArgValueEnvRec); - -function BESENValueToVariant(const v:TBESENValue):Variant; -procedure BESENVariantToValue(const vt:Variant;var v:TBESENValue); - -function BESENBooleanValue(const Bool:TBESENBoolean):TBESENValue; -function BESENNumberValue(const Num:TBESENNumber):TBESENValue; -function BESENStringValue(const Str:TBESENString):TBESENValue; -{$ifndef BESENSingleStringType} -function BESENStringLocaleCharsetValue(const Str:TBESENAnsiString):TBESENValue; -{$endif} -function BESENObjectValue(const Obj:TObject):TBESENValue; -function BESENObjectValueEx(const Obj:TObject):TBESENValue; - -function BESENEqualityExpressionStrictEquals(const a,b:TBESENValue):longbool; - -var BESENEmptyValue:TBESENValue; - BESENNullValue:TBESENValue; - BESENUndefinedValue:TBESENValue; - BESENDummyValue:TBESENValue; - -implementation - -uses BESEN,BESENNumberUtils,BESENEnvironmentRecord; - -procedure BESENCopyReferenceBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtUNDEFINED; -end; - -procedure BESENCopyReferenceBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtBOOLEAN; - Dest.Bool:=Src.Bool; -end; - -procedure BESENCopyReferenceBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtNUMBER; - Dest.Num:=Src.Num; -end; - -procedure BESENCopyReferenceBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtSTRING; - Dest.Str:=Src.Str; -end; - -procedure BESENCopyReferenceBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtOBJECT; - Dest.Obj:=Src.Obj; -end; - -procedure BESENCopyReferenceBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtENVREC; - Dest.EnvRec:=Src.EnvRec; -end; - -procedure BESENCopyReferenceBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtNONE; -end; - -procedure BESENCopyReferenceBaseValue(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyReferenceBaseValueProcs[Src.ValueType](Dest,Src); -end; - -procedure BESENCopyValueUndefined(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtUNDEFINED; -end; - -procedure BESENCopyValueNull(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtNULL; -end; - -procedure BESENCopyValueBoolean(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtBOOLEAN; - Dest.Bool:=Src.Bool; -end; - -procedure BESENCopyValueNumber(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtNUMBER; - Dest.Num:=Src.Num; -end; - -procedure BESENCopyValueString(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtSTRING; - Dest.Str:=Src.Str; -end; - -procedure BESENCopyValueObject(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtOBJECT; - Dest.Obj:=Src.Obj; -end; - -procedure BESENCopyValueReference(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtREFERENCE; - BESENCopyReferenceBaseValue(Dest.ReferenceBase,Src.ReferenceBase); - Dest.Str:=Src.Str; - Dest.ReferenceIsStrict:=Src.ReferenceIsStrict; - Dest.ReferenceHash:=Src.ReferenceHash; - Dest.ReferenceIndex:=Src.ReferenceIndex; - Dest.ReferenceID:=Src.ReferenceID; -end; - -procedure BESENCopyValueLocal(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtLOCAL; - Dest.LocalIndex:=Src.LocalIndex; -end; - -procedure BESENCopyValueEnvRec(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtENVREC; - Dest.EnvRec:=Src.EnvRec; -end; - -procedure BESENCopyValueNone(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtNONE; -end; - -procedure BESENCopyValue(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - BESENCopyValueProcs[Src.ValueType](Dest,Src); -end; - -procedure BESENValueToRefBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtUNDEFINED; -end; - -procedure BESENValueToRefBaseValueNull(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtUNDEFINED; -end; - -procedure BESENValueToRefBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtBOOLEAN; - Dest.Bool:=Src.Bool; -end; - -procedure BESENValueToRefBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtNUMBER; - Dest.Num:=Src.Num; -end; - -procedure BESENValueToRefBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtSTRING; - Dest.Str:=Src.Str; -end; - -procedure BESENValueToRefBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtOBJECT; - Dest.Obj:=Src.Obj; -end; - -procedure BESENValueToRefBaseValueReference(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtUNDEFINED; -end; - -procedure BESENValueToRefBaseValueLocal(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtUNDEFINED; -end; - -procedure BESENValueToRefBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtENVREC; - Dest.EnvRec:=Src.EnvRec; -end; - -procedure BESENValueToRefBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=brbvtUNDEFINED; -end; - -procedure BESENValueToReferenceBaseValue(const Value:TBESENValue;var AResult:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - BESENValueToRefBaseValueProcs[Value.ValueType](AResult,Value); -end; - -procedure BESENRefBaseValueToValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtUNDEFINED; -end; - -procedure BESENRefBaseValueToValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtBOOLEAN; - Dest.Bool:=Src.Bool; -end; - -procedure BESENRefBaseValueToValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtNUMBER; - Dest.Num:=Src.Num; -end; - -procedure BESENRefBaseValueToValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtSTRING; - Dest.Str:=Src.Str; -end; - -procedure BESENRefBaseValueToValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtOBJECT; - Dest.Obj:=Src.Obj; -end; - -procedure BESENRefBaseValueToValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtENVREC; - Dest.EnvRec:=Src.EnvRec; -end; - -procedure BESENReferenceBaseValueToValue(const Value:TBESENReferenceBaseValue;var AResult:TBESENValue); {$ifdef UseRegister}register;{$endif} -begin - BESENRefBaseValueToValueProcs[Value.ValueType](AResult,Value); -end; - -procedure BESENRefBaseValueToCallThisArgValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtUNDEFINED; -end; - -procedure BESENRefBaseValueToCallThisArgValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtBOOLEAN; - Dest.Bool:=Src.Bool; -end; - -procedure BESENRefBaseValueToCallThisArgValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtNUMBER; - Dest.Num:=Src.Num; -end; - -procedure BESENRefBaseValueToCallThisArgValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtSTRING; - Dest.Str:=Src.Str; -end; - -procedure BESENRefBaseValueToCallThisArgValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -begin - Dest.ValueType:=bvtOBJECT; - Dest.Obj:=Src.Obj; -end; - -procedure BESENRefBaseValueToCallThisArgValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} -var ImplicitThisValue:PBESENValue; -begin - ImplicitThisValue:=@TBESENEnvironmentRecord(Src.EnvRec).ImplicitThisValue; - Dest.ValueType:=ImplicitThisValue.ValueType; - Dest.Obj:=ImplicitThisValue.Obj; -end; - -function BESENValueToVariant(const v:TBESENValue):Variant; -begin - case v.ValueType of - bvtNULL:begin - result:=Variants.Null; - end; - bvtBOOLEAN:begin - result:=V.Bool; - end; - bvtSTRING:begin - result:=V.Str; - end; - bvtNUMBER:begin - result:=V.Num; - end; - else begin - result:=Variants.Unassigned; - end; - end; -end; - -procedure BESENVariantToValue(const vt:Variant;var v:TBESENValue); -begin - try - case VarType(vt) of - varNull:begin - V.ValueType:=bvtNULL; - end; - varSmallInt,varInteger,varShortInt,varByte,varWord,varLongWord,varInt64{$ifdef fpc},varQWord{$endif}:begin - V.ValueType:=bvtNUMBER; - V.Num:=vt; - end; - varSingle,varDouble,varDATE,varCurrency:begin - V.ValueType:=bvtNUMBER; - V.Num:=vt; - end; - varBoolean:begin - V.ValueType:=bvtBOOLEAN; - V.Bool:=vt; - end; - varString,varOleStr:begin - V.ValueType:=bvtSTRING; - V.Str:=vt; - end; - else begin - V.ValueType:=bvtUNDEFINED; - end; - end; - except - V.ValueType:=bvtUNDEFINED; - end; -end; - -function BESENBooleanValue(const Bool:TBESENBoolean):TBESENValue; -begin - result.ValueType:=bvtBOOLEAN; - result.Bool:=Bool; -end; - -function BESENNumberValue(const Num:TBESENNumber):TBESENValue; -begin - result.ValueType:=bvtNUMBER; - result.Num:=Num; -end; - -function BESENStringValue(const Str:TBESENString):TBESENValue; -begin - result.ValueType:=bvtSTRING; - result.Str:=Str; -end; - -{$ifndef BESENSingleStringType} -function BESENStringLocaleCharsetValue(const Str:TBESENAnsiString):TBESENValue; -begin - result.ValueType:=bvtSTRING; - result.Str:=BESENUTF8ToUTF16(BESENEncodeString(Str,BESENLocaleCharset,UTF_8)); -end; -{$endif} - -function BESENObjectValue(const Obj:TObject):TBESENValue; -begin - result.ValueType:=bvtOBJECT; - result.Obj:=Obj; -end; - -function BESENObjectValueEx(const Obj:TObject):TBESENValue; -begin - if assigned(Obj) then begin - result.ValueType:=bvtOBJECT; - result.Obj:=Obj; - end else begin - result:=BESENNullValue; - end; -end; - -function BESENObjectValueEx2(const Obj:TObject):TBESENValue; -begin - if assigned(Obj) then begin - result.ValueType:=bvtOBJECT; - result.Obj:=Obj; - end else begin - result:=BESENUndefinedValue; - end; -end; - -function BESENEqualityExpressionStrictEquals(const a,b:TBESENValue):longbool; -begin - if a.ValueType<>b.ValueType then begin - result:=false; - end else begin - case a.ValueType of - bvtUNDEFINED:begin - result:=true; - end; - bvtNULL:begin - result:=true; - end; - bvtNUMBER:begin -{$ifdef UseSafeOperations} - if BESENIsNaN(a.Num) then begin - result:=false; - end else if BESENIsNaN(b.Num) then begin - result:=false; - end else begin - result:=(a.Num=b.Num) or (BESENIsZero(a.Num) and BESENIsZero(b.Num)); - end; -{$else} - result:=(not (BESENIsNaN(a.Num) or BESENIsNaN(b.Num))) and (a.Num=b.Num); -{$endif} - end; - bvtSTRING:begin - result:=a.Str=b.Str; - end; - bvtBOOLEAN:begin - result:=a.Bool=b.Bool; - end; - bvtOBJECT:begin - result:=a.Obj=b.Obj; - end; - else begin - result:=false; - end; - end; - end; -end; - -procedure InitBESEN; -begin - fillchar(BESENEmptyValue,sizeof(TBESENValue),#0); - fillchar(BESENNullValue,sizeof(TBESENValue),#0); - fillchar(BESENUndefinedValue,sizeof(TBESENValue),#0); - BESENEmptyValue.ValueType:=bvtUNDEFINED; - BESENNullValue.ValueType:=bvtNULL; - BESENUndefinedValue.ValueType:=bvtUNDEFINED; - BESENDummyValue:=BESENEmptyValue; -end; - -procedure DoneBESEN; -begin -end; - -initialization - InitBESEN; -finalization - DoneBESEN; -end. diff --git a/3rd/besen/src/BESENValueContainer.pas b/3rd/besen/src/BESENValueContainer.pas deleted file mode 100644 index 633232ca7..000000000 --- a/3rd/besen/src/BESENValueContainer.pas +++ /dev/null @@ -1,77 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENValueContainer; -{$i BESEN.inc} - -interface - -uses BESENValue,BESENGarbageCollector; - -type TBESENValueContainer=class(TBESENGarbageCollectorObject) - public - Value:TBESENValue; - constructor Create(AInstance:TObject); overload; override; - destructor Destroy; override; - procedure Finalize; override; - procedure Mark; override; - end; - -implementation - -uses BESEN; - -constructor TBESENValueContainer.Create(AInstance:TObject); -begin - inherited Create(AInstance); - Value:=BESENEmptyValue; -end; - -destructor TBESENValueContainer.Destroy; -begin - Value.Str:=''; - Value.ReferenceBase.Str:=''; - inherited Destroy; -end; - -procedure TBESENValueContainer.Finalize; -begin - TBESEN(Instance).GarbageCollector.FinalizeValue(Value); - inherited Finalize; -end; - -procedure TBESENValueContainer.Mark; -begin - TBESEN(Instance).GarbageCollector.GrayValue(Value); - inherited Mark; -end; - -end. - \ No newline at end of file diff --git a/3rd/besen/src/BESENVersionConstants.pas b/3rd/besen/src/BESENVersionConstants.pas deleted file mode 100644 index 45c0da006..000000000 --- a/3rd/besen/src/BESENVersionConstants.pas +++ /dev/null @@ -1,42 +0,0 @@ -(******************************************************************************* - L I C E N S E -******************************************************************************** - -BESEN - A ECMAScript Fifth Edition Object Pascal Implementation -Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux - -The source code of the BESEN ecmascript engine library and helper tools are -distributed under the Library GNU Lesser General Public License Version 2.1 -(see the file copying.txt) with the following modification: - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent modules, -and to copy and distribute the resulting executable under terms of your choice, -provided that you also meet, for each linked independent module, the terms -and conditions of the license of that module. An independent module is a module -which is not derived from or based on this library. If you modify this -library, you may extend this exception to your version of the library, but you -are not obligated to do so. If you do not wish to do so, delete this exception -statement from your version. - -If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> -or contact: - Free Software Foundation - 675 Mass Ave - Cambridge, MA 02139 - USA - -*******************************************************************************) -unit BESENVersionConstants; -{$i BESEN.inc} - -interface - -const BESENVersion='20150630-2027-0000'; - - BESENCodeFormatRevisionNumber:int64=19; - -implementation - -end. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1cbfdbdd7..97c303c37 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -34,7 +34,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -78,7 +78,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -125,7 +125,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -169,7 +169,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -319,7 +319,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\besen\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 00f4c2ce56c8a016dd33200688693a60969f5fb0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 00:00:26 +0800 Subject: [PATCH 0888/2794] cleanup project --- baseunits/uData.pas | 2 +- baseunits/uDownloadsManager.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 4f30305e0..886210b8d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -121,7 +121,7 @@ TMangaInformation = class(TObject) implementation uses - Dialogs, fpJSON, JSONParser, IniFiles, jsHTMLUtil, FastHTMLParser, HTMLUtil, + Dialogs, fpJSON, JSONParser, IniFiles, FastHTMLParser, HTMLUtil, SynaCode, uMisc, frmMain, WebsiteModules; // ----- TDataProcess ----- diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 7e2029022..ae1d5ff7d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -15,7 +15,7 @@ interface uses - lazutf8classes, LazFileUtils, jsHTMLUtil, FastHTMLParser, HTMLUtil, SynaCode, + lazutf8classes, LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, SimpleLogger, dateutils; From bfdeb76ca3c7245373f11c6bb00f0618040a0de9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 00:04:39 +0800 Subject: [PATCH 0889/2794] added besen module --- .gitmodules | 3 +++ 3rd/BESEN | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 3rd/BESEN diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..f172a31e5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "3rd/BESEN"] + path = 3rd/BESEN + url = https://github.com/BeRo1985/besen.git diff --git a/3rd/BESEN b/3rd/BESEN new file mode 160000 index 000000000..9af50070a --- /dev/null +++ b/3rd/BESEN @@ -0,0 +1 @@ +Subproject commit 9af50070a2625306ae5084c0af7328ee374a6856 From 88a1409693601b0a38bb5aa73ed3fa0dc56098d9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 01:14:37 +0800 Subject: [PATCH 0890/2794] cleanup and fix all includes files --- .../AnimExtremist/chapter_page_number.inc | 64 +-- .../includes/AnimExtremist/image_url.inc | 66 +-- .../AnimExtremist/manga_information.inc | 206 ++++----- .../AnimExtremist/names_and_links.inc | 68 +-- .../includes/AnimeA/chapter_page_number.inc | 74 ++-- .../includes/AnimeA/directory_page_number.inc | 72 +-- baseunits/includes/AnimeA/image_url.inc | 62 +-- .../includes/AnimeA/manga_information.inc | 220 +++++----- baseunits/includes/AnimeA/names_and_links.inc | 44 +- .../AnimeStory/chapter_page_number.inc | 68 +-- baseunits/includes/AnimeStory/image_url.inc | 62 +-- .../includes/AnimeStory/manga_information.inc | 260 +++++------ .../includes/AnimeStory/names_and_links.inc | 74 ++-- .../BlogTruyen/directory_page_number.inc | 70 +-- baseunits/includes/BlogTruyen/image_url.inc | 68 +-- .../includes/BlogTruyen/manga_information.inc | 257 ++++++----- .../includes/BlogTruyen/names_and_links.inc | 76 ++-- .../CentralDeMangas/directory_page_number.inc | 68 +-- .../includes/CentralDeMangas/image_url.inc | 80 ++-- .../CentralDeMangas/manga_information.inc | 210 +++++---- .../CentralDeMangas/names_and_links.inc | 76 ++-- .../CentrumMangi_PL/chapter_page_number.inc | 4 +- .../includes/CentrumMangi_PL/image_url.inc | 4 +- .../includes/DM5/directory_page_number.inc | 4 +- .../includes/EGScans/chapter_page_number.inc | 68 +-- baseunits/includes/EGScans/image_url.inc | 62 +-- .../includes/EGScans/manga_information.inc | 137 +++--- .../includes/EGScans/names_and_links.inc | 82 ++-- .../includes/EatManga/chapter_page_number.inc | 86 ++-- baseunits/includes/EatManga/image_url.inc | 72 +-- .../includes/EatManga/manga_information.inc | 221 +++++----- .../includes/EatManga/names_and_links.inc | 74 ++-- .../EsMangaHere/chapter_page_number.inc | 62 +-- baseunits/includes/EsMangaHere/image_url.inc | 74 ++-- .../EsMangaHere/manga_information.inc | 238 +++++----- .../includes/EsMangaHere/names_and_links.inc | 68 +-- .../includes/Fakku/directory_page_number.inc | 72 +-- baseunits/includes/Fakku/image_url.inc | 10 +- .../includes/Fakku/manga_information.inc | 202 ++++----- baseunits/includes/Fakku/names_and_links.inc | 94 ++-- .../Hentai2Read/chapter_page_number.inc | 74 ++-- .../Hentai2Read/directory_page_number.inc | 72 +-- baseunits/includes/Hentai2Read/image_url.inc | 62 +-- .../Hentai2Read/manga_information.inc | 329 +++++++------- .../includes/Hentai2Read/names_and_links.inc | 91 ++-- .../HugeManga/chapter_page_number.inc | 68 +-- baseunits/includes/HugeManga/image_url.inc | 64 +-- .../includes/HugeManga/manga_information.inc | 149 ++++--- .../includes/HugeManga/names_and_links.inc | 74 ++-- .../includes/Imanhua/names_and_links.inc | 8 +- .../JapanShin/chapter_page_number.inc | 4 +- baseunits/includes/JapanShin/image_url.inc | 8 +- .../includes/JapanShin/manga_information.inc | 32 +- .../includes/JapanShin/names_and_links.inc | 10 +- .../includes/Japscan/manga_information.inc | 2 +- .../includes/Japscan/names_and_links.inc | 2 +- .../includes/Kivmanga/chapter_page_number.inc | 66 +-- baseunits/includes/Kivmanga/image_url.inc | 64 +-- .../includes/Kivmanga/manga_information.inc | 14 +- .../includes/Kivmanga/names_and_links.inc | 72 +-- .../includes/Komikid/chapter_page_number.inc | 66 +-- baseunits/includes/Komikid/image_url.inc | 90 ++-- .../includes/Komikid/manga_information.inc | 146 +++---- .../includes/Komikid/names_and_links.inc | 80 ++-- .../LectureEnLigne/directory_page_number.inc | 84 ++-- .../LectureEnLigne/manga_information.inc | 222 +++++----- .../LectureEnLigne/names_and_links.inc | 84 ++-- baseunits/includes/Mabuns/image_url.inc | 86 ++-- .../includes/Mabuns/manga_information.inc | 183 ++++---- baseunits/includes/Mabuns/names_and_links.inc | 73 ++-- .../Manga24h/directory_page_number.inc | 70 +-- baseunits/includes/Manga24h/image_url.inc | 63 ++- .../includes/Manga24h/manga_information.inc | 274 ++++++------ .../includes/Manga24h/names_and_links.inc | 75 ++-- .../includes/MangaAe/chapter_page_number.inc | 78 ++-- .../MangaAe/directory_page_number.inc | 74 ++-- baseunits/includes/MangaAe/image_url.inc | 70 +-- .../includes/MangaAe/manga_information.inc | 234 +++++----- .../includes/MangaAe/names_and_links.inc | 100 ++--- .../includes/MangaAr/chapter_page_number.inc | 68 +-- baseunits/includes/MangaAr/image_url.inc | 96 ++-- .../includes/MangaAr/manga_information.inc | 259 ++++++----- .../includes/MangaAr/names_and_links.inc | 88 ++-- .../MangaEden/directory_page_number.inc | 70 +-- baseunits/includes/MangaEden/image_url.inc | 72 +-- .../includes/MangaEden/manga_information.inc | 269 ++++++------ .../includes/MangaEden/names_and_links.inc | 75 ++-- baseunits/includes/MangaEsta/image_url.inc | 86 ++-- .../includes/MangaEsta/manga_information.inc | 231 +++++----- .../includes/MangaEsta/names_and_links.inc | 77 ++-- .../MangaFrame/chapter_page_number.inc | 76 ++-- baseunits/includes/MangaFrame/image_url.inc | 76 ++-- .../includes/MangaFrame/manga_information.inc | 164 +++---- .../includes/MangaFrame/names_and_links.inc | 64 +-- .../includes/MangaGo/chapter_page_number.inc | 66 +-- .../MangaGo/directory_page_number.inc | 71 ++- baseunits/includes/MangaGo/image_url.inc | 96 ++-- .../includes/MangaGo/manga_information.inc | 206 ++++----- .../includes/MangaGo/names_and_links.inc | 74 ++-- baseunits/includes/MangaHost/image_url.inc | 2 +- .../includes/MangaInn/chapter_page_number.inc | 62 +-- baseunits/includes/MangaInn/image_url.inc | 62 +-- .../includes/MangaInn/manga_information.inc | 244 +++++------ .../includes/MangaInn/names_and_links.inc | 80 ++-- baseunits/includes/MangaLib_PL/image_url.inc | 2 +- .../MangaPark/chapter_page_number.inc | 58 +-- .../MangaPark/directory_page_number.inc | 84 ++-- baseunits/includes/MangaPark/image_url.inc | 63 ++- .../includes/MangaPark/manga_information.inc | 285 ++++++------ .../includes/MangaPark/names_and_links.inc | 68 +-- .../includes/MangaREADER_POR/image_url.inc | 90 ++-- .../MangaREADER_POR/manga_information.inc | 382 ++++++++-------- .../MangaREADER_POR/names_and_links.inc | 102 ++--- .../includes/MangaTown/manga_information.inc | 4 +- .../MangaTraders/chapter_page_number.inc | 72 +-- baseunits/includes/MangaTraders/image_url.inc | 66 +-- .../MangaTraders/manga_information.inc | 224 +++++----- .../includes/MangaTraders/names_and_links.inc | 92 ++-- .../MangaVadisi/chapter_page_number.inc | 66 +-- baseunits/includes/MangaVadisi/image_url.inc | 66 +-- .../MangaVadisi/manga_information.inc | 122 +++--- .../includes/MangaVadisi/names_and_links.inc | 72 +-- .../includes/Mangacow/chapter_page_number.inc | 68 +-- baseunits/includes/Mangacow/image_url.inc | 62 +-- .../includes/Mangacow/manga_information.inc | 412 +++++++++--------- .../includes/Mangacow/names_and_links.inc | 104 ++--- .../includes/MangasPROJECT/image_url.inc | 92 ++-- .../MangasPROJECT/manga_information.inc | 357 ++++++++------- .../MangasPROJECT/names_and_links.inc | 84 ++-- .../MeinManga/chapter_page_number.inc | 74 ++-- baseunits/includes/MeinManga/image_url.inc | 12 +- .../includes/MeinManga/manga_information.inc | 339 +++++++------- .../includes/MeinManga/names_and_links.inc | 76 ++-- .../NineManga/chapter_page_number.inc | 10 +- baseunits/includes/NineManga/image_url.inc | 8 +- .../includes/NineManga/manga_information.inc | 42 +- .../includes/NineManga/names_and_links.inc | 6 +- .../includes/OneManga/chapter_page_number.inc | 4 +- baseunits/includes/PornComix/image_url.inc | 4 +- .../RedHawkScans/chapter_page_number.inc | 66 +-- .../RedHawkScans/directory_page_number.inc | 72 +-- baseunits/includes/RedHawkScans/image_url.inc | 64 +-- .../RedHawkScans/manga_information.inc | 233 +++++----- .../includes/RedHawkScans/names_and_links.inc | 76 ++-- baseunits/includes/ScanManga/image_url.inc | 90 ++-- .../includes/ScanManga/manga_information.inc | 258 +++++------ .../includes/ScanManga/names_and_links.inc | 92 ++-- .../includes/SenManga/chapter_page_number.inc | 86 ++-- baseunits/includes/SenManga/image_url.inc | 76 ++-- .../includes/SenManga/manga_information.inc | 264 +++++------ .../includes/SenManga/names_and_links.inc | 70 +-- .../includes/Starkana/chapter_page_number.inc | 64 +-- baseunits/includes/Starkana/image_url.inc | 58 +-- .../includes/Starkana/manga_information.inc | 186 ++++---- .../includes/Starkana/names_and_links.inc | 68 +-- .../includes/SubManga/chapter_page_number.inc | 108 ++--- baseunits/includes/SubManga/image_url.inc | 60 +-- .../includes/SubManga/manga_information.inc | 266 +++++------ .../includes/SubManga/names_and_links.inc | 72 +-- .../includes/TruyenTranhTuan/image_url.inc | 78 ++-- .../TruyenTranhTuan/manga_information.inc | 241 +++++----- .../TruyenTranhTuan/names_and_links.inc | 74 ++-- .../Turkcraft/chapter_page_number.inc | 66 +-- baseunits/includes/Turkcraft/image_url.inc | 64 +-- .../includes/Turkcraft/manga_information.inc | 146 +++---- .../includes/Turkcraft/names_and_links.inc | 72 +-- .../VnSharing/directory_page_number.inc | 72 +-- baseunits/includes/VnSharing/image_url.inc | 74 ++-- .../includes/VnSharing/manga_information.inc | 259 ++++++----- .../includes/VnSharing/names_and_links.inc | 94 ++-- baseunits/uData.pas | 2 +- 171 files changed, 8623 insertions(+), 8650 deletions(-) diff --git a/baseunits/includes/AnimExtremist/chapter_page_number.inc b/baseunits/includes/AnimExtremist/chapter_page_number.inc index a81d34667..7e1c9c640 100644 --- a/baseunits/includes/AnimExtremist/chapter_page_number.inc +++ b/baseunits/includes/AnimExtremist/chapter_page_number.inc @@ -1,32 +1,32 @@ - function GetAnimeExtremistPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), - '.html', '', []) + '-1.html', - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if Pos('</select>', parse.Strings[i]) > 0 then - begin - manager.container.PageNumber := - StrToInt(GetString(TrimLeft(TrimRight(parse.Strings[i - 3] + '~!@')), 'Pagina ', '~!@')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetAnimeExtremistPageNumber: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + Result := GetPage(TObject(l), + StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), + '.html', '', []) + '-1.html', + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if Pos('</select>', parse[i]) > 0 then + begin + manager.container.PageNumber := + StrToInt(GetString(TrimLeft(TrimRight(parse[i - 3] + '~!@')), 'Pagina ', '~!@')); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/AnimExtremist/image_url.inc b/baseunits/includes/AnimExtremist/image_url.inc index a456808e7..d754211d9 100644 --- a/baseunits/includes/AnimExtremist/image_url.inc +++ b/baseunits/includes/AnimExtremist/image_url.inc @@ -1,33 +1,33 @@ - function GetAnimeExtremistImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), - '.html', '', []) + '-' + IntToStr(workCounter + 1) + '.html'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('id="photo"', parse.Strings[i]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - manager.container.pageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetAnimeExtremistImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), + '.html', '', []) + '-' + IntToStr(workCounter + 1) + '.html'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('id="photo"', parse[i]) > 0) then + begin + s := GetVal(parse[i], 'src'); + manager.container.pageLinks[workCounter] := + GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/AnimExtremist/manga_information.inc b/baseunits/includes/AnimExtremist/manga_information.inc index 671199845..70715521f 100644 --- a/baseunits/includes/AnimExtremist/manga_information.inc +++ b/baseunits/includes/AnimExtremist/manga_information.inc @@ -1,103 +1,103 @@ - function GetAnimeExtremistInfoFromURL: Byte; - var - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(ANIMEEXTREMIST_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[ANIMEEXTREMIST_ID, 0]; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos(' Manga - Animextremist', parse.Strings[i]) > 0) then - mangaInfo.title := GetString('~!@' + parse.Strings[i], '~!@', - ' Manga - Animextremist'); - - // get cover link - if (mangaInfo.coverLink = '') and - (GetTagName(parse.Strings[i]) = 'img') then - if Pos('src="../', parse.Strings[i]) > 0 then - mangaInfo.coverLink := WebsiteRoots[ANIMEEXTREMIST_ID, 1] + - GetString(parse.Strings[i], 'src="..', '"'); - - // get summary - if (Pos('align="justify" class="style33"', parse.Strings[i])) <> 0 then - begin - j := i + 1; - mangaInfo.summary := ''; - while (Pos('<td height', parse.Strings[j]) = 0) and (j < parse.Count - 1) do - begin - s := parse.Strings[j]; - if (s <> '') and (s[1] <> '<') then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j] + '\n\r'; - end; - Inc(j); - end; - end; - - // get chapter name and links - if (Pos('/mangas-online/', parse.Strings[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [rfReplaceAll])); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #10, '', [rfReplaceAll]); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #13, '', [rfReplaceAll]); - parse.Strings[i + 1] := TrimLeft(parse.Strings[i + 1]); - parse.Strings[i + 1] := TrimRight(parse.Strings[i + 1]); - mangaInfo.chapterName.Add(HTMLEntitiesFilter( - StringFilter(TrimRight(RemoveSymbols(parse.Strings[i + 1]))))); - end; - - { // get authors - if (Pos('Autor(s):', parse.Strings[i])<>0) then - mangaInfo.authors:= parse.Strings[i+3]; - - // get artists - if (Pos('Artist(s):', parse.Strings[i])<>0) then - mangaInfo.artists:= parse.Strings[i+3]; } - - // get genres - if (Pos('ord=genero&id', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := mangaInfo.genres + - (HTMLEntitiesFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))) + ', '); - end; - - // get status - if (Pos('class="manga_estado"', parse.Strings[i]) <> 0) then - begin - if Pos('Completo', parse.Strings[i + 3]) <> 0 then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - Result := NO_ERROR; - end; + function GetAnimeExtremistInfoFromURL: Byte; + var + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(ANIMEEXTREMIST_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[ANIMEEXTREMIST_ID, 0]; + mangaInfo.genres := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos(' Manga - Animextremist', parse[i]) > 0) then + mangaInfo.title := GetString('~!@' + parse[i], '~!@', + ' Manga - Animextremist'); + + // get cover link + if (mangaInfo.coverLink = '') and + (GetTagName(parse[i]) = 'img') then + if Pos('src="../', parse[i]) > 0 then + mangaInfo.coverLink := WebsiteRoots[ANIMEEXTREMIST_ID, 1] + + GetString(parse[i], 'src="..', '"'); + + // get summary + if (Pos('align="justify" class="style33"', parse[i])) <> 0 then + begin + j := i + 1; + mangaInfo.summary := ''; + while (Pos('<td height', parse[j]) = 0) and (j < parse.Count - 1) do + begin + s := parse[j]; + if (s <> '') and (s[1] <> '<') then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j] + '\n\r'; + end; + Inc(j); + end; + end; + + // get chapter name and links + if (Pos('/mangas-online/', parse[i]) <> 0) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add( + StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [rfReplaceAll])); + parse[i + 1] := StringReplace(parse[i + 1], #10, '', [rfReplaceAll]); + parse[i + 1] := StringReplace(parse[i + 1], #13, '', [rfReplaceAll]); + parse[i + 1] := TrimLeft(parse[i + 1]); + parse[i + 1] := TrimRight(parse[i + 1]); + mangaInfo.chapterName.Add(HTMLEntitiesFilter( + StringFilter(TrimRight(RemoveSymbols(parse[i + 1]))))); + end; + + { // get authors + if (Pos('Autor(s):', parse[i])<>0) then + mangaInfo.authors:= parse[i+3]; + + // get artists + if (Pos('Artist(s):', parse[i])<>0) then + mangaInfo.artists:= parse[i+3]; } + + // get genres + if (Pos('ord=genero&id', parse[i]) <> 0) then + begin + mangaInfo.genres := mangaInfo.genres + + (HTMLEntitiesFilter(TrimLeft(TrimRight(parse[i + 1]))) + ', '); + end; + + // get status + if (Pos('class="manga_estado"', parse[i]) <> 0) then + begin + if Pos('Completo', parse[i + 3]) <> 0 then + mangaInfo.status := '0' // completed + else + mangaInfo.status := '1'; // ongoing + end; + end; + + Result := NO_ERROR; + end; diff --git a/baseunits/includes/AnimExtremist/names_and_links.inc b/baseunits/includes/AnimExtremist/names_and_links.inc index af696c532..8970f4e24 100644 --- a/baseunits/includes/AnimExtremist/names_and_links.inc +++ b/baseunits/includes/AnimExtremist/names_and_links.inc @@ -1,35 +1,35 @@ - function AnimeExtremistGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMEEXTREMIST_ID, 1] + - ANIMEEXTREMIST_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('id="manga" style="margin', parse.Strings[i]) <> 0 then - begin - Result := NO_ERROR; - names.Add(TrimLeft(TrimRight(parse.Strings[i + 4]))); - links.Add(StringReplace(GetString(parse.Strings[i + 3], 'href="', '">'), - WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [])); - end; - end; - Source.Free; + function AnimeExtremistGetNamesAndLinks: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[ANIMEEXTREMIST_ID, 1] + + ANIMEEXTREMIST_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if Pos('id="manga" style="margin', parse[i]) <> 0 then + begin + Result := NO_ERROR; + names.Add(TrimLeft(TrimRight(parse[i + 4]))); + links.Add(StringReplace(GetString(parse[i + 3], 'href="', '">'), + WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [])); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/AnimeA/chapter_page_number.inc b/baseunits/includes/AnimeA/chapter_page_number.inc index b63973389..6056791f0 100644 --- a/baseunits/includes/AnimeA/chapter_page_number.inc +++ b/baseunits/includes/AnimeA/chapter_page_number.inc @@ -1,37 +1,37 @@ - function GetAnimeAPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - isPage: Boolean = False; - begin - manager.container.PageNumber := 0; - l := TStringList.Create; - Result := GetPage(TObject(l), FillMangaSiteHost(ANIMEA_ID, - StringReplace(URL, '.html', '', [])) + - '.html', manager.container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and - (Pos('class="mangaselecter pageselect"', parse[i]) > 0) then - isPage := True; - if isPage and (Pos('</select', parse[i]) > 0) then - begin - isPage := False; - Break; - end; - if isPage and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); - end; - end; - parse.Free; - end; + function GetAnimeAPageNumber: Boolean; + var + i: Cardinal; + l: TStringList; + isPage: Boolean = False; + begin + manager.container.PageNumber := 0; + l := TStringList.Create; + Result := GetPage(TObject(l), FillMangaSiteHost(ANIMEA_ID, + StringReplace(URL, '.html', '', [])) + + '.html', manager.container.Manager.retryConnect); + + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + l.Free; + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (Pos('<select', parse[i]) > 0) and + (Pos('class="mangaselecter pageselect"', parse[i]) > 0) then + isPage := True; + if isPage and (Pos('</select', parse[i]) > 0) then + begin + isPage := False; + Break; + end; + if isPage and (Pos('<option', parse[i]) > 0) then + Inc(manager.container.PageNumber); + end; + end; + parse.Free; + end; diff --git a/baseunits/includes/AnimeA/directory_page_number.inc b/baseunits/includes/AnimeA/directory_page_number.inc index a87ea93b4..f421c8afc 100644 --- a/baseunits/includes/AnimeA/directory_page_number.inc +++ b/baseunits/includes/AnimeA/directory_page_number.inc @@ -1,37 +1,37 @@ - function GetAnimeADirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + ANIMEA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'a') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')) = - 'http://manga.animea.net/browse.html?page=1') and - (Pos('Next', parse.Strings[i + 1]) > 0) then - begin - Page := StrToInt(TrimRight(TrimLeft(parse.Strings[i - 4]))); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetAnimeADirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + ANIMEA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'a') and + (GetVal(parse[i], 'href') = + 'http://manga.animea.net/browse.html?page=1') and + (Pos('Next', parse[i + 1]) > 0) then + begin + Page := StrToInt(TrimRight(TrimLeft(parse[i - 4]))); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/AnimeA/image_url.inc b/baseunits/includes/AnimeA/image_url.inc index f862d4930..afc2a933d 100644 --- a/baseunits/includes/AnimeA/image_url.inc +++ b/baseunits/includes/AnimeA/image_url.inc @@ -1,31 +1,31 @@ - function GetAnimeAImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(ANIMEA_ID, - StringReplace(URL, '.html', '', []) + - '-page-' + IntToStr(workCounter + 1) + '.html'), - manager.container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', parse[i]) > 0) and - (Pos('class="scanmr"', parse[i]) > 0) and - (Pos('id="scanmr"', parse[i])> 0) then - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - end; - end; - parse.Free; - end; + function GetAnimeAImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(ANIMEA_ID, + StringReplace(URL, '.html', '', []) + + '-page-' + IntToStr(workCounter + 1) + '.html'), + manager.container.Manager.retryConnect); + + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + l.Free; + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (Pos('<img', parse[i]) > 0) and + (Pos('class="scanmr"', parse[i]) > 0) and + (Pos('id="scanmr"', parse[i])> 0) then + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + end; + end; + parse.Free; + end; diff --git a/baseunits/includes/AnimeA/manga_information.inc b/baseunits/includes/AnimeA/manga_information.inc index dab00aaa0..5e05c0cb8 100644 --- a/baseunits/includes/AnimeA/manga_information.inc +++ b/baseunits/includes/AnimeA/manga_information.inc @@ -1,110 +1,110 @@ - function GetAnimeAInfoFromURL: Byte; - var - i, j: Cardinal; - isExtractGenres: Boolean = False; - s: String; - begin - mangaInfo.website := WebsiteRoots[ANIMEA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ANIMEA_ID, URL + ANIMEA_SKIP); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i + 1], 'Manga - Read ', ' Manga Scans'); - - // get cover link - if Pos('class="cover_mp"', parse[i]) > 0 then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // get authors - if (Pos('Author(s):', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimRight(TrimLeft(parse.Strings[i + 3])); - - // get artists - if (Pos('Artist(s):', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimRight(TrimLeft(parse.Strings[i + 2])); - - // get genres - if (Pos('Genre(s):', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := ''; - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if GetTagName(parse.Strings[i]) <> 'a' then - for j := 0 to 37 do - if Pos(LowerCase(defaultGenres[j]), LowerCase(parse.Strings[i])) <> 0 then - mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); - if Pos('</li>', parse.Strings[i]) > 0 then - isExtractGenres := False; - end; - - // get summary - if Pos('Upload a chapter', parse.Strings[i]) > 0 then - begin - j := i + 8; - mangaInfo.summary := ''; - while (j < parse.Count - 4) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - mangaInfo.summary := StringFilter(mangaInfo.summary + parse.Strings[j]); - Inc(j); - end; - mangaInfo.summary := StringFilter(mangaInfo.summary); - end; - - // get status - if (Pos('Status:', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - // get chapter name and links - if (Pos('<a', parse[i]) > 0) and (Pos('id="ch_', parse[i]) > 0) and - (i + 3 < parse.Count - 1) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - s := ''; - if (parse[i + 3] <> '') and (Pos('<', parse[i + 3]) = 0) then - begin - s := Trim(TrimLeftChar(parse[i + 3], [':'])); - end; - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]) + ' ' + s))); - mangaInfo.chapterName.Add(s); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; + function GetAnimeAInfoFromURL: Byte; + var + i, j: Cardinal; + isExtractGenres: Boolean = False; + s: String; + begin + mangaInfo.website := WebsiteRoots[ANIMEA_ID, 0]; + mangaInfo.url := FillMangaSiteHost(ANIMEA_ID, URL + ANIMEA_SKIP); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos('<title>', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i + 1], 'Manga - Read ', ' Manga Scans'); + + // get cover link + if Pos('class="cover_mp"', parse[i]) > 0 then + mangaInfo.coverLink := GetVal(parse[i], 'src'); + + // get authors + if (Pos('Author(s):', parse[i]) <> 0) then + mangaInfo.authors := TrimRight(TrimLeft(parse[i + 3])); + + // get artists + if (Pos('Artist(s):', parse[i]) <> 0) then + mangaInfo.artists := TrimRight(TrimLeft(parse[i + 2])); + + // get genres + if (Pos('Genre(s):', parse[i]) <> 0) then + begin + mangaInfo.genres := ''; + isExtractGenres := True; + end; + + if isExtractGenres then + begin + if GetTagName(parse[i]) <> 'a' then + for j := 0 to 37 do + if Pos(LowerCase(defaultGenres[j]), LowerCase(parse[i])) <> 0 then + mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); + if Pos('</li>', parse[i]) > 0 then + isExtractGenres := False; + end; + + // get summary + if Pos('Upload a chapter', parse[i]) > 0 then + begin + j := i + 8; + mangaInfo.summary := ''; + while (j < parse.Count - 4) and (Pos('</p>', parse[j]) = 0) do + begin + mangaInfo.summary := StringFilter(mangaInfo.summary + parse[j]); + Inc(j); + end; + mangaInfo.summary := StringFilter(mangaInfo.summary); + end; + + // get status + if (Pos('Status:', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 2]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + + // get chapter name and links + if (Pos('<a', parse[i]) > 0) and (Pos('id="ch_', parse[i]) > 0) and + (i + 3 < parse.Count - 1) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); + s := ''; + if (parse[i + 3] <> '') and (Pos('<', parse[i + 3]) = 0) then + begin + s := Trim(TrimLeftChar(parse[i + 3], [':'])); + end; + s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]) + ' ' + s))); + mangaInfo.chapterName.Add(s); + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterName.Count > 1 then + begin + InvertStrings(mangaInfo.chapterName); + InvertStrings(mangaInfo.chapterLinks); + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/AnimeA/names_and_links.inc b/baseunits/includes/AnimeA/names_and_links.inc index 0180f5abc..6e9efa3e1 100644 --- a/baseunits/includes/AnimeA/names_and_links.inc +++ b/baseunits/includes/AnimeA/names_and_links.inc @@ -1,23 +1,23 @@ - function AnimeAGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + - ANIMEA_BROWSER + URL, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - for i := 0 to Source.Count - 1 do - begin - if Pos('manga_img', Source.Strings[i]) <> 0 then - begin - Result := NO_ERROR; - links.Add(GetString(Source.Strings[i], '"', '"')); - names.Add(GetString(Source.Strings[i], 'title="', ' Manga"')); - end; - end; - Source.Free; + function AnimeAGetNamesAndLinks: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + + ANIMEA_BROWSER + URL, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + for i := 0 to Source.Count - 1 do + begin + if Pos('manga_img', Source[i]) <> 0 then + begin + Result := NO_ERROR; + links.Add(GetString(Source[i], '"', '"')); + names.Add(GetString(Source[i], 'title="', ' Manga"')); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/AnimeStory/chapter_page_number.inc b/baseunits/includes/AnimeStory/chapter_page_number.inc index ba000e827..ae0639dd5 100644 --- a/baseunits/includes/AnimeStory/chapter_page_number.inc +++ b/baseunits/includes/AnimeStory/chapter_page_number.inc @@ -1,34 +1,34 @@ - function GetAnimeStoryPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + '1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('data-page=', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i]; - manager.container.pageNumber := - StrToInt(GetAttributeValue(GetTagAttribute(s, 'data-page='))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetAnimeStoryPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + '1'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := parse.Count - 1 downto 5 do + begin + if (Pos('data-page=', parse[i]) > 0) then + begin + s := parse[i]; + manager.container.pageNumber := + StrToInt(GetVal(s, 'data-page')); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/AnimeStory/image_url.inc b/baseunits/includes/AnimeStory/image_url.inc index 01426dfb3..e46728a98 100644 --- a/baseunits/includes/AnimeStory/image_url.inc +++ b/baseunits/includes/AnimeStory/image_url.inc @@ -1,31 +1,31 @@ - function GetAnimeStoryImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('id="chpimg"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - DecodeURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetAnimeStoryImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('id="chpimg"', parse[i]) > 0) then + begin + manager.container.PageLinks[workCounter] := + DecodeURL(GetVal(parse[i], 'src')); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/AnimeStory/manga_information.inc b/baseunits/includes/AnimeStory/manga_information.inc index b1d0c1e87..1605fe4e0 100644 --- a/baseunits/includes/AnimeStory/manga_information.inc +++ b/baseunits/includes/AnimeStory/manga_information.inc @@ -1,130 +1,130 @@ - function GetAnimeStoryInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[ANIMESTORY_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ANIMESTORY_ID, '/' + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - { if (mangaInfo.coverLink = '') AND - (Pos('imageanchor="1"', parse.Strings[i])>0) then - mangaInfo.coverLink:= CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href='))); - } - // get title - if (Pos('<title>', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - TrimRight(HTMLEntitiesFilter(GetString('~!@' + parse.Strings[i + 1], - '~!@', ' | Anime-Story')))); - - if (not isExtractChapter) and (Pos('Liste des Chapitres', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('href=', parse.Strings[i]) > 0) and - (Pos('Lecture', parse.Strings[i + 1]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[ANIMESTORY_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft( - TrimRight(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'title='))))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class=''comments''', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get summary - if (Pos('Synopsis', parse.Strings[i]) <> 0) and - (Pos('<h2>', parse.Strings[i - 1]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 5 < parse.Count) and (Pos('Auteur :', parse.Strings[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 5]))); - - // get artists - if (i + 5 < parse.Count) and (Pos('Illustrateur :', parse.Strings[i]) <> 0) then - mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 5]))); - - // get genres - if (Pos('Sous-genre(s) :', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('search?subgenre', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</td>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 5 < parse.Count) and (Pos('Statut :', parse.Strings[i]) <> 0) then - begin - if (Pos('terminé', parse.Strings[i + 5]) <> 0) or - (Pos('one shot', parse.Strings[i + 5]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetAnimeStoryInfoFromURL: Byte; + var + s: String; + isExtractGenres: Boolean = False; + isExtractChapter: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.website := WebsiteRoots[ANIMESTORY_ID, 0]; + mangaInfo.url := FillMangaSiteHost(ANIMESTORY_ID, '/' + URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + { if (mangaInfo.coverLink = '') AND + (Pos('imageanchor="1"', parse[i])>0) then + mangaInfo.coverLink:= CorrectURL(GetVal(parse[i], 'href')); + } + // get title + if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft( + TrimRight(HTMLEntitiesFilter(GetString('~!@' + parse[i + 1], + '~!@', ' | Anime-Story')))); + + if (not isExtractChapter) and (Pos('Liste des Chapitres', parse[i]) > 0) then + isExtractChapter := True; + + // get chapter name and links + if (isExtractChapter) and + (Pos('href=', parse[i]) > 0) and + (Pos('Lecture', parse[i + 1]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[ANIMESTORY_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft( + TrimRight(GetVal(parse[i], 'title')))); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + + if (isExtractChapter) and + (Pos('class=''comments''', parse[i]) > 0) then + isExtractChapter := False; + + // get summary + if (Pos('Synopsis', parse[i]) <> 0) and + (Pos('<h2>', parse[i - 1]) <> 0) then + begin + j := i + 4; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + end; + + // get authors + if (i + 5 < parse.Count) and (Pos('Auteur :', parse[i]) <> 0) then + mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 5]))); + + // get artists + if (i + 5 < parse.Count) and (Pos('Illustrateur :', parse[i]) <> 0) then + mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse[i + 5]))); + + // get genres + if (Pos('Sous-genre(s) :', parse[i]) <> 0) then + begin + isExtractGenres := True; + end; + + if isExtractGenres then + begin + if Pos('search?subgenre', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + TrimLeft(TrimRight(parse[i + 1])) + ', '; + if Pos('</td>', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 5 < parse.Count) and (Pos('Statut :', parse[i]) <> 0) then + begin + if (Pos('terminé', parse[i + 5]) <> 0) or + (Pos('one shot', parse[i + 5]) <> 0) then + mangaInfo.status := '0' // completed + else + mangaInfo.status := '1'; // ongoing + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/AnimeStory/names_and_links.inc b/baseunits/includes/AnimeStory/names_and_links.inc index 0db9238cf..a820aa5b2 100644 --- a/baseunits/includes/AnimeStory/names_and_links.inc +++ b/baseunits/includes/AnimeStory/names_and_links.inc @@ -1,38 +1,38 @@ - function AnimeStoryGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMESTORY_ID, 1] + - ANIMESTORY_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="left"', parse.Strings[i]) > 0) and - (Pos('href=', parse.Strings[i + 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 2]); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')); - links.Add(s); - end; - end; - Source.Free; + function AnimeStoryGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[ANIMESTORY_ID, 1] + + ANIMESTORY_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="left"', parse[i]) > 0) and + (Pos('href=', parse[i + 1]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(parse[i + 2]); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i + 1], 'href'); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/BlogTruyen/directory_page_number.inc b/baseunits/includes/BlogTruyen/directory_page_number.inc index 902f67da4..7ec9ddbdf 100644 --- a/baseunits/includes/BlogTruyen/directory_page_number.inc +++ b/baseunits/includes/BlogTruyen/directory_page_number.inc @@ -1,36 +1,36 @@ - function GetBlogTruyenDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[BLOGTRUYEN_ID, 1] + - BLOGTRUYEN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('[cuối]', parse.Strings[i]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse.Strings[i - 1], 'LoadPage(', ')'))); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetBlogTruyenDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[BLOGTRUYEN_ID, 1] + + BLOGTRUYEN_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('[cuối]', parse[i]) > 0) then + begin + s := TrimRight(TrimLeft(GetString(parse[i - 1], 'LoadPage(', ')'))); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/BlogTruyen/image_url.inc b/baseunits/includes/BlogTruyen/image_url.inc index 3cfac417c..175f0b6c8 100644 --- a/baseunits/includes/BlogTruyen/image_url.inc +++ b/baseunits/includes/BlogTruyen/image_url.inc @@ -1,34 +1,34 @@ - function GetBlogTruyenImageURL: Boolean; - var - isExtrackLink: Boolean = False; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(BLOGTRUYEN_ID, URL), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if not (isExtrackLink) and (Pos('id="content"', parse.Strings[i]) > 0) then - isExtrackLink := True; - if (isExtrackLink) and (GetTagName(parse.Strings[i]) = 'img') then - manager.container.PageLinks.Add( - EncodeUrl(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')))) - else - if (isExtrackLink) and (Pos('</article>', parse.Strings[i]) > 0) then - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetBlogTruyenImageURL: Boolean; + var + isExtrackLink: Boolean = False; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(BLOGTRUYEN_ID, URL), + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if not (isExtrackLink) and (Pos('id="content"', parse[i]) > 0) then + isExtrackLink := True; + if (isExtrackLink) and (GetTagName(parse[i]) = 'img') then + manager.container.PageLinks.Add( + EncodeUrl(GetVal(parse[i], 'src'))) + else + if (isExtrackLink) and (Pos('</article>', parse[i]) > 0) then + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/BlogTruyen/manga_information.inc b/baseunits/includes/BlogTruyen/manga_information.inc index a3303f813..dadbb7363 100644 --- a/baseunits/includes/BlogTruyen/manga_information.inc +++ b/baseunits/includes/BlogTruyen/manga_information.inc @@ -1,129 +1,128 @@ - function GetBlogTruyenInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = True; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[BLOGTRUYEN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(BLOGTRUYEN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('div class="thumbnail"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i + 2], 'src='))); - - // get summary - if (Pos('class="content"', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 1; - while (j < parse.Count) and (Pos('</div>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - Break; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if (Pos('class="entry-title"', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse.Strings[i + 3]))); - - // get chapter name and links - if (isExtractChapter) and - (Pos('class="publishedDate"', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i - 5], 'href=')); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse.Strings[i - 4])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class="al-c social-button"', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get authors - if (i + 2 < parse.Count) and (Pos('Tác giả:', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(TrimRight(parse.Strings[i + 2])); - - // get artists - //if (i+1<parse.Count) AND (Pos('/search/artist/', parse.Strings[i])<>0) then - // mangaInfo.artists:= TrimLeft(parse.Strings[i+1]); - - // get genres - if (not isExtractGenres) and (Pos('class="category"', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - s := TrimLeft(TrimRight(parse.Strings[i])); - if Pos('Đăng bởi:', s) <> 0 then - isExtractGenres := False - else - if (s <> '') and (s[1] <> '<') and - (Pos('class="category"', parse.Strings[i - 2]) <> 0) then - mangaInfo.genres := mangaInfo.genres + s + ', '; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Trạng thái:', parse.Strings[i]) <> 0) then - begin - if (Pos('Đang tiến hành', parse.Strings[i + 2]) <> 0) or - (Pos('Tạm ngưng', parse.Strings[i + 2]) <> 0) then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetBlogTruyenInfoFromURL: Byte; + var + s: String; + isExtractSummary: Boolean = True; + isExtractGenres: Boolean = False; + isExtractChapter: Boolean = True; + i, j: Cardinal; + begin + mangaInfo.website := WebsiteRoots[BLOGTRUYEN_ID, 0]; + mangaInfo.url := FillMangaSiteHost(BLOGTRUYEN_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('div class="thumbnail"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); + + // get summary + if (Pos('class="content"', parse[i]) <> 0) and + (isExtractSummary) then + begin + j := i + 1; + while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + Break; + end; + Inc(j); + end; + isExtractSummary := False; + end; + + // get title + if (Pos('class="entry-title"', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); + + // get chapter name and links + if (isExtractChapter) and + (Pos('class="publishedDate"', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := GetVal(parse[i - 5], 'href'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(Trim(parse[i - 4])); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + + if (isExtractChapter) and + (Pos('class="al-c social-button"', parse[i]) > 0) then + isExtractChapter := False; + + // get authors + if (i + 2 < parse.Count) and (Pos('Tác giả:', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(TrimRight(parse[i + 2])); + + // get artists + //if (i+1<parse.Count) AND (Pos('/search/artist/', parse[i])<>0) then + // mangaInfo.artists:= TrimLeft(parse[i+1]); + + // get genres + if (not isExtractGenres) and (Pos('class="category"', parse[i]) <> 0) then + begin + isExtractGenres := True; + mangaInfo.genres := ''; + end; + + if isExtractGenres then + begin + s := TrimLeft(TrimRight(parse[i])); + if Pos('Đăng bởi:', s) <> 0 then + isExtractGenres := False + else + if (s <> '') and (s[1] <> '<') and + (Pos('class="category"', parse[i - 2]) <> 0) then + mangaInfo.genres := mangaInfo.genres + s + ', '; + end; + + // get status + if (i + 2 < parse.Count) and (Pos('Trạng thái:', parse[i]) <> 0) then + begin + if (Pos('Đang tiến hành', parse[i + 2]) <> 0) or + (Pos('Tạm ngưng', parse[i + 2]) <> 0) then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/BlogTruyen/names_and_links.inc b/baseunits/includes/BlogTruyen/names_and_links.inc index 3bd449e40..0ee2a1064 100644 --- a/baseunits/includes/BlogTruyen/names_and_links.inc +++ b/baseunits/includes/BlogTruyen/names_and_links.inc @@ -1,39 +1,39 @@ - function BlogTruyenGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - stream: TStringStream; - begin - Result := INFORMATION_NOT_FOUND; - stream := TStringStream.Create(''); - s := WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER; - s := BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(URL) + 1); - while not HttpPostURL(WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER, - BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(URL) + 1), stream) do - Sleep(32); - Source.Text := stream.DataString; - stream.Free; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="tiptip', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft( - TrimRight(GetString(parse.Strings[i + 2], 'title="truyện tranh ', '">')))); - names.Add(HTMLEntitiesFilter(s)); - links.Add(GetAttributeValue(GetTagAttribute(parse.Strings[i + 2], 'href="'))); - end; - end; - Source.Free; + function BlogTruyenGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + stream: TStringStream; + begin + Result := INFORMATION_NOT_FOUND; + stream := TStringStream.Create(''); + s := WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER; + s := BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(URL) + 1); + while not HttpPostURL(WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER, + BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(URL) + 1), stream) do + Sleep(32); + Source.Text := stream.DataString; + stream.Free; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="tiptip', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft( + TrimRight(GetString(parse[i + 2], 'title="truyện tranh ', '">')))); + names.Add(HTMLEntitiesFilter(s)); + links.Add(GetVal(parse[i + 2], 'href="')); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/CentralDeMangas/directory_page_number.inc b/baseunits/includes/CentralDeMangas/directory_page_number.inc index 7ec245d59..af364441a 100644 --- a/baseunits/includes/CentralDeMangas/directory_page_number.inc +++ b/baseunits/includes/CentralDeMangas/directory_page_number.inc @@ -1,35 +1,35 @@ - function GetCentralDeMangasDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + - CENTRALDEMANGAS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('/mangas/list/*/', parse.Strings[i]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse.Strings[i], '/mangas/list/*/', '">'))); - page := StrToInt(s); - Result := NO_ERROR; - Exit; - end; - end; - Source.Free; + function GetCentralDeMangasDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + + CENTRALDEMANGAS_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 2 do + begin + if (Pos('/mangas/list/*/', parse[i]) > 0) then + begin + s := TrimRight(TrimLeft(GetString(parse[i], '/mangas/list/*/', '">'))); + page := StrToInt(s); + Result := NO_ERROR; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/CentralDeMangas/image_url.inc b/baseunits/includes/CentralDeMangas/image_url.inc index 636c7c9be..afcbe1a12 100644 --- a/baseunits/includes/CentralDeMangas/image_url.inc +++ b/baseunits/includes/CentralDeMangas/image_url.inc @@ -1,40 +1,40 @@ - function GetCentralDeMangasImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := EncodeUrl(FillMangaSiteHost(CENTRALDEMANGAS_ID, URL)); - // + IntToStr(workCounter+1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('var pages = ', parse.Strings[i]) > 0 then - begin - s := StringReplace(parse.Strings[i], '\/', '/', [rfReplaceAll]); - repeat - j := Pos('http://', s); - manager.container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); - s := StringReplace(s, '"', '', []); - s := StringReplace(s, '"', '', []); - Delete(s, j, 10); - j := Pos('http://', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetCentralDeMangasImageURL: Boolean; + var + s: String; + j, i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := EncodeUrl(FillMangaSiteHost(CENTRALDEMANGAS_ID, URL)); + // + IntToStr(workCounter+1)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('var pages = ', parse[i]) > 0 then + begin + s := StringReplace(parse[i], '\/', '/', [rfReplaceAll]); + repeat + j := Pos('http://', s); + manager.container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); + s := StringReplace(s, '"', '', []); + s := StringReplace(s, '"', '', []); + Delete(s, j, 10); + j := Pos('http://', s); + until j = 0; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/CentralDeMangas/manga_information.inc b/baseunits/includes/CentralDeMangas/manga_information.inc index e687948dc..100a32d85 100644 --- a/baseunits/includes/CentralDeMangas/manga_information.inc +++ b/baseunits/includes/CentralDeMangas/manga_information.inc @@ -1,106 +1,104 @@ - function GetCentralDeMangasInfoFromURL: Byte; - var - isExtractGenres: Boolean = False; - i: Cardinal; - begin - mangaInfo.website := WebsiteRoots[CENTRALDEMANGAS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(CENTRALDEMANGAS_ID, URL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // convert charset - // source.Text:= ISO_8859_1ToUTF8(source.Text); - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class="img-thumbnail"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('class="img-thumbnail"', parse.Strings[i]) > 0) then - mangaInfo.summary := parse.Strings[i + 6]; - - // get title - if (mangaInfo.title = '') and - (Pos('<title>', parse.Strings[i]) <> 0) then - mangaInfo.title := TrimLeft(HTMLEntitiesFilter( - StringFilter(GetString('~!@' + parse.Strings[i + 1], '~!@', ' || Central de Mangás')))); - - // get chapter name and links - if Pos('class="col-xs-1 col-sm-1 col-md-1 col-lg-1"', parse.Strings[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'href'))); - mangaInfo.chapterName.Add(RemoveSymbols(Trim(parse.Strings[i + 1]))); - end; - - // get authors - if (i + 12 < parse.Count) and - (Pos('Autor', parse.Strings[i]) <> 0) and - (Pos('<h4>', parse.Strings[i - 1]) <> 0) then - mangaInfo.authors := TrimLeft(TrimRight(parse.Strings[i + 12])); - - // get artists - if (i + 12 < parse.Count) and - (Pos('Arte', parse.Strings[i]) <> 0) and - (Pos('<h4>', parse.Strings[i - 1]) <> 0) then - mangaInfo.artists := TrimLeft(TrimRight(parse.Strings[i + 12])); - - // get genres - if (i + 1 < parse.Count) and - (Pos('Gênero', parse.Strings[i]) <> 0) and - (Pos('</h4>', parse.Strings[i + 1]) <> 0) and - (Pos('<h4>', parse.Strings[i - 1]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if (Pos('<h4>', parse.Strings[i]) > 0) and - (Pos('Scantrad', parse.Strings[i + 1]) > 0) and - (Pos('</h4>', parse.Strings[i + 2]) > 0) then - isExtractGenres := False; - - if Pos('class="btn btn-xs btn-primary"', parse.Strings[i]) > 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := parse.Strings[i + 1] - else - mangaInfo.genres := mangaInfo.genres + ', ' + parse.Strings[i + 1]; - end; - - // get status - if (i + 12 < parse.Count) and - (Pos('Status', parse.Strings[i]) <> 0) and - (Pos('<h4>', parse.Strings[i - 1]) <> 0) then - begin - if (Pos('Completo', parse.Strings[i + 12]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - Result := NO_ERROR; - end; + function GetCentralDeMangasInfoFromURL: Byte; + var + isExtractGenres: Boolean = False; + i: Cardinal; + begin + mangaInfo.website := WebsiteRoots[CENTRALDEMANGAS_ID, 0]; + mangaInfo.url := FillMangaSiteHost(CENTRALDEMANGAS_ID, URL); + if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // convert charset + // source.Text:= ISO_8859_1ToUTF8(source.Text); + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('class="img-thumbnail"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); + + // get summary + if (Pos('class="img-thumbnail"', parse[i]) > 0) then + mangaInfo.summary := parse[i + 6]; + + // get title + if (mangaInfo.title = '') and + (Pos('<title>', parse[i]) <> 0) then + mangaInfo.title := TrimLeft(HTMLEntitiesFilter( + StringFilter(GetString('~!@' + parse[i + 1], '~!@', ' || Central de Mangás')))); + + // get chapter name and links + if Pos('class="col-xs-1 col-sm-1 col-md-1 col-lg-1"', parse[i]) > 0 then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); + mangaInfo.chapterName.Add(RemoveSymbols(Trim(parse[i + 1]))); + end; + + // get authors + if (i + 12 < parse.Count) and + (Pos('Autor', parse[i]) <> 0) and + (Pos('<h4>', parse[i - 1]) <> 0) then + mangaInfo.authors := TrimLeft(TrimRight(parse[i + 12])); + + // get artists + if (i + 12 < parse.Count) and + (Pos('Arte', parse[i]) <> 0) and + (Pos('<h4>', parse[i - 1]) <> 0) then + mangaInfo.artists := TrimLeft(TrimRight(parse[i + 12])); + + // get genres + if (i + 1 < parse.Count) and + (Pos('Gênero', parse[i]) <> 0) and + (Pos('</h4>', parse[i + 1]) <> 0) and + (Pos('<h4>', parse[i - 1]) <> 0) then + begin + isExtractGenres := True; + mangaInfo.genres := ''; + end; + + if isExtractGenres then + begin + if (Pos('<h4>', parse[i]) > 0) and + (Pos('Scantrad', parse[i + 1]) > 0) and + (Pos('</h4>', parse[i + 2]) > 0) then + isExtractGenres := False; + + if Pos('class="btn btn-xs btn-primary"', parse[i]) > 0 then + if mangaInfo.genres = '' then + mangaInfo.genres := parse[i + 1] + else + mangaInfo.genres := mangaInfo.genres + ', ' + parse[i + 1]; + end; + + // get status + if (i + 12 < parse.Count) and + (Pos('Status', parse[i]) <> 0) and + (Pos('<h4>', parse[i - 1]) <> 0) then + begin + if (Pos('Completo', parse[i + 12]) <> 0) then + mangaInfo.status := '0' // completed + else + mangaInfo.status := '1'; // ongoing + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/CentralDeMangas/names_and_links.inc b/baseunits/includes/CentralDeMangas/names_and_links.inc index b607df104..f3bb5a7e9 100644 --- a/baseunits/includes/CentralDeMangas/names_and_links.inc +++ b/baseunits/includes/CentralDeMangas/names_and_links.inc @@ -1,39 +1,39 @@ - function CentralDeMangasGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + - CENTRALDEMANGAS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/mangas/info/', parse.Strings[i]) > 0) and - (Pos('<td>', parse.Strings[i - 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 1]); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetString(parse.Strings[i], 'href="', '"'), - WebsiteRoots[CENTRALDEMANGAS_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; + function CentralDeMangasGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + + CENTRALDEMANGAS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('/mangas/info/', parse[i]) > 0) and + (Pos('<td>', parse[i - 1]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(parse[i + 1]); + names.Add(HTMLEntitiesFilter(s)); + s := StringReplace(GetString(parse[i], 'href="', '"'), + WebsiteRoots[CENTRALDEMANGAS_ID, 1], '', []); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc index 56f0c721c..564e21f16 100644 --- a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc +++ b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc @@ -21,10 +21,10 @@ manager.container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin - if (Pos('</select>', parse.Strings[i]) > 0) then + if (Pos('</select>', parse[i]) > 0) then if Count > 0 then begin - s := parse.Strings[i - 2]; + s := parse[i - 2]; manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); Break; end diff --git a/baseunits/includes/CentrumMangi_PL/image_url.inc b/baseunits/includes/CentrumMangi_PL/image_url.inc index 52c5728b1..cc77f7ac6 100644 --- a/baseunits/includes/CentrumMangi_PL/image_url.inc +++ b/baseunits/includes/CentrumMangi_PL/image_url.inc @@ -20,9 +20,9 @@ begin manager.container.PageLinks.Clear; for i := 0 to parse.Count - 1 do - if (Pos('<img alt=', parse.Strings[i]) > 0) then + if (Pos('<img alt=', parse[i]) > 0) then begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); + s := GetVal(parse[i], 'src'); s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); s := StringReplace(s, 'mangas/', WebsiteRoots[CENTRUMMANGI_PL_ID, 1] + '/mangas/', [rfReplaceAll]); diff --git a/baseunits/includes/DM5/directory_page_number.inc b/baseunits/includes/DM5/directory_page_number.inc index 9902dfb41..24440ff8e 100644 --- a/baseunits/includes/DM5/directory_page_number.inc +++ b/baseunits/includes/DM5/directory_page_number.inc @@ -22,9 +22,9 @@ end; for i := parse.Count - 1 downto 2 do begin - if (Pos('/mangas/list/*/', parse.Strings[i]) > 0) then + if (Pos('/mangas/list/*/', parse[i]) > 0) then begin - s := TrimRight(TrimLeft(GetString(parse.Strings[i], '/mangas/list/*/', '">'))); + s := TrimRight(TrimLeft(GetString(parse[i], '/mangas/list/*/', '">'))); page := StrToInt(s); Result := NO_ERROR; Exit; diff --git a/baseunits/includes/EGScans/chapter_page_number.inc b/baseunits/includes/EGScans/chapter_page_number.inc index e12a990a9..672d43ac5 100644 --- a/baseunits/includes/EGScans/chapter_page_number.inc +++ b/baseunits/includes/EGScans/chapter_page_number.inc @@ -1,34 +1,34 @@ - function GetEGScansPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('</span>', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 4]; - manager.container.PageNumber := - StrToInt(TrimLeft(TrimRight(GetString(s + ' ', 'of ', ' ')))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetEGScansPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := parse.Count - 1 downto 2 do + begin + if (Pos('</span>', parse[i]) > 0) then + begin + s := parse[i - 4]; + manager.container.PageNumber := + StrToInt(TrimLeft(TrimRight(GetString(s + ' ', 'of ', ' ')))); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/EGScans/image_url.inc b/baseunits/includes/EGScans/image_url.inc index 71ef5bd13..7816b484c 100644 --- a/baseunits/includes/EGScans/image_url.inc +++ b/baseunits/includes/EGScans/image_url.inc @@ -1,31 +1,31 @@ - function GetEGScansImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - if (Pos('<img ondragstart', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Add(WebsiteRoots[EGSCANS_ID, 1] + - '/' + EncodeURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')))); - end; - end; - parse.Free; - l.Free; - end; + function GetEGScansImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + if (Pos('<img ondragstart', parse[i]) > 0) then + begin + manager.container.PageLinks.Add(WebsiteRoots[EGSCANS_ID, 1] + + '/' + EncodeURL(GetVal(parse[i], 'src'))); + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/EGScans/manga_information.inc b/baseunits/includes/EGScans/manga_information.inc index 1626c4868..e63e10616 100644 --- a/baseunits/includes/EGScans/manga_information.inc +++ b/baseunits/includes/EGScans/manga_information.inc @@ -1,69 +1,68 @@ - function GetEGScansInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i: Cardinal; - begin - mangaInfo.website := WebsiteRoots[EGSCANS_ID, 0]; - mangaInfo.url :=FillMangaSiteHost(EGSCANS_ID, '/' + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (not isExtractChapter) and - (Pos('<span>', parse.Strings[i]) > 0) and - (Pos('Chapter', parse.Strings[i + 1]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('</span>', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get manga name - if (mangaInfo.title = '') and (Pos('content="Read ', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i], '~!@content="Read ', - ' Manga Online"'); - - { if (isExtractChapter) AND (Pos('</select>', parse.Strings[i])>0) then - break; } - - if (isExtractChapter) and - (Pos('<option value="', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := '/' + URL + '/' + StringReplace(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'value=')), WebsiteRoots[EGSCANS_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - Result := NO_ERROR; - end; + function GetEGScansInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i: Cardinal; + begin + mangaInfo.website := WebsiteRoots[EGSCANS_ID, 0]; + mangaInfo.url :=FillMangaSiteHost(EGSCANS_ID, '/' + URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + mangaInfo.status := '1'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get chapter name and links + if (not isExtractChapter) and + (Pos('<span>', parse[i]) > 0) and + (Pos('Chapter', parse[i + 1]) > 0) then + isExtractChapter := True; + + if (isExtractChapter) and + (Pos('</span>', parse[i]) > 0) then + isExtractChapter := False; + + // get manga name + if (mangaInfo.title = '') and (Pos('content="Read ', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i], '~!@content="Read ', + ' Manga Online"'); + + { if (isExtractChapter) AND (Pos('</select>', parse[i])>0) then + break; } + + if (isExtractChapter) and + (Pos('<option value="', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := '/' + URL + '/' + StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[EGSCANS_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + end; + + Result := NO_ERROR; + end; diff --git a/baseunits/includes/EGScans/names_and_links.inc b/baseunits/includes/EGScans/names_and_links.inc index f2c4542bc..7df0bf512 100644 --- a/baseunits/includes/EGScans/names_and_links.inc +++ b/baseunits/includes/EGScans/names_and_links.inc @@ -1,42 +1,42 @@ - function EGScansGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[EGSCANS_ID, 1] + - EGSCANS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('<option value="', parse.Strings[i]) > 0) and - (Pos('="0"', parse.Strings[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], - 'value="')), - WebsiteRoots[S2SCAN_ID, 1], '', []); - links.Add(s); - end; - if Pos('<select name="manga"', parse.Strings[i]) > 0 then - Break; - end; - Source.Free; + function EGScansGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[EGSCANS_ID, 1] + + EGSCANS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 2 do + begin + if (Pos('<option value="', parse[i]) > 0) and + (Pos('="0"', parse[i]) = 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(HTMLEntitiesFilter(s)); + s := StringReplace(GetVal(parse[i], + 'value="'), + WebsiteRoots[S2SCAN_ID, 1], '', []); + links.Add(s); + end; + if Pos('<select name="manga"', parse[i]) > 0 then + Break; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/EatManga/chapter_page_number.inc b/baseunits/includes/EatManga/chapter_page_number.inc index 7be00bb0f..df1cca393 100644 --- a/baseunits/includes/EatManga/chapter_page_number.inc +++ b/baseunits/includes/EatManga/chapter_page_number.inc @@ -1,43 +1,43 @@ - function GetEatMangaPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - try - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL)), - manager.container.manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'id') = 'pages') then - isGetPageNumber := True; - if isGetPageNumber then - begin - if GetTagName(parse[i]) = '/select' then - Break - else if GetTagName(parse[i]) = 'option' then - Inc(manager.container.PageNumber); - end; - end; - end; - finally - parse.Free; - l.Free; - end; - end; + function GetEatMangaPageNumber: Boolean; + var + i: Integer; + l: TStringList; + isGetPageNumber: Boolean = False; + begin + l := TStringList.Create; + parse := TStringList.Create; + try + Result := GetPage(TObject(l), + DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL)), + manager.container.manager.retryConnect); + + Parser := THTMLParser.Create(PChar(l.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'id') = 'pages') then + isGetPageNumber := True; + if isGetPageNumber then + begin + if GetTagName(parse[i]) = '/select' then + Break + else if GetTagName(parse[i]) = 'option' then + Inc(manager.container.PageNumber); + end; + end; + end; + finally + parse.Free; + l.Free; + end; + end; diff --git a/baseunits/includes/EatManga/image_url.inc b/baseunits/includes/EatManga/image_url.inc index 9c81d7f62..8923d05e1 100644 --- a/baseunits/includes/EatManga/image_url.inc +++ b/baseunits/includes/EatManga/image_url.inc @@ -1,36 +1,36 @@ - function GetEatMangaImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(workCounter + 1)), - manager.container.Manager.retryConnect); - - parse := TStringList.Create; - try - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = 'eatmanga_image') then - begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - finally - parse.Free; - l.Free; - end; - end; + function GetEatMangaImageURL: Boolean; + var + i: Integer; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(workCounter + 1)), + manager.container.Manager.retryConnect); + + parse := TStringList.Create; + try + Parser := THTMLParser.Create(PChar(l.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (GetTagName(parse[i]) = 'img') and + (GetVal(parse[i], 'id') = 'eatmanga_image') then + begin + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + end; + finally + parse.Free; + l.Free; + end; + end; diff --git a/baseunits/includes/EatManga/manga_information.inc b/baseunits/includes/EatManga/manga_information.inc index 1a12f427a..d53ce8cf5 100644 --- a/baseunits/includes/EatManga/manga_information.inc +++ b/baseunits/includes/EatManga/manga_information.inc @@ -1,111 +1,110 @@ - function GetEatMangaInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[EATMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(EATMANGA_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse.Strings[i]) = 'img') and - (Pos('border="0" align="center"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos(' manga about ?', parse.Strings[i]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get title - if (Pos(', Read ', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft(StringFilter(GetString(parse.Strings[i], - ', Read ', ' English Scan Online'))); - - // get chapter name and links - if (Pos('<th class="title">', parse.Strings[i]) > 0) and - (Pos('/upcoming/', parse.Strings[i + 1]) = 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse.Strings[i + 1], 'href="', '"'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 2]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Author:', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist:', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 4]); - - // get genres - if (Pos('Genre:', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := ''; - s := parse.Strings[i + 4]; - if s[1] <> '<' then - mangaInfo.genres := s; - end; - - // get status - if (i + 4 < parse.Count) and (Pos('Chapters:', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetEatMangaInfoFromURL: Byte; + var + s: String; + i, j: Cardinal; + begin + mangaInfo.website := WebsiteRoots[EATMANGA_ID, 0]; + mangaInfo.url := FillMangaSiteHost(EATMANGA_ID, URL);// + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (GetTagName(parse[i]) = 'img') and + (Pos('border="0" align="center"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); + + // get summary + if (Pos(' manga about ?', parse[i]) <> 0) then + begin + j := i + 4; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + end; + + // get title + if (Pos(', Read ', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft(StringFilter(GetString(parse[i], + ', Read ', ' English Scan Online'))); + + // get chapter name and links + if (Pos('<th class="title">', parse[i]) > 0) and + (Pos('/upcoming/', parse[i + 1]) = 0) then + begin + Inc(mangaInfo.numChapter); + s := GetString(parse[i + 1], 'href="', '"'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 2]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + + // get authors + if (i + 4 < parse.Count) and (Pos('Author:', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(parse[i + 4]); + + // get artists + if (i + 4 < parse.Count) and (Pos('Artist:', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(parse[i + 4]); + + // get genres + if (Pos('Genre:', parse[i]) <> 0) then + begin + mangaInfo.genres := ''; + s := parse[i + 4]; + if s[1] <> '<' then + mangaInfo.genres := s; + end; + + // get status + if (i + 4 < parse.Count) and (Pos('Chapters:', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 4]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/EatManga/names_and_links.inc b/baseunits/includes/EatManga/names_and_links.inc index c2c8902b0..1b6ce45f6 100644 --- a/baseunits/includes/EatManga/names_and_links.inc +++ b/baseunits/includes/EatManga/names_and_links.inc @@ -1,38 +1,38 @@ - function EatMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[EATMANGA_ID, 1] + - EATMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos(' Online">', parse.Strings[i]) > 0) and - (Pos('<th>', parse.Strings[i - 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href="')); - links.Add(s); - end; - end; - Source.Free; + function EatMangaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[EATMANGA_ID, 1] + + EATMANGA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 5 do + begin + if (Pos(' Online">', parse[i]) > 0) and + (Pos('<th>', parse[i - 1]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i], 'href="'); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/EsMangaHere/chapter_page_number.inc b/baseunits/includes/EsMangaHere/chapter_page_number.inc index e72aae7fc..7b81a708a 100644 --- a/baseunits/includes/EsMangaHere/chapter_page_number.inc +++ b/baseunits/includes/EsMangaHere/chapter_page_number.inc @@ -1,31 +1,31 @@ - function GetEsMangaHerePageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(ESMANGAHERE_ID, URL), - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := parse.Count - 1 downto 4 do - begin - if Pos('</select>', parse.Strings[i]) > 0 then - begin - manager.container.PageNumber := - StrToInt(TrimLeft(TrimRight(parse.Strings[i - 3]))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetEsMangaHerePageNumber: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(ESMANGAHERE_ID, URL), + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := parse.Count - 1 downto 4 do + begin + if Pos('</select>', parse[i]) > 0 then + begin + manager.container.PageNumber := + StrToInt(TrimLeft(TrimRight(parse[i - 3]))); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/EsMangaHere/image_url.inc b/baseunits/includes/EsMangaHere/image_url.inc index 49eb62c79..db9ee2ba1 100644 --- a/baseunits/includes/EsMangaHere/image_url.inc +++ b/baseunits/includes/EsMangaHere/image_url.inc @@ -1,37 +1,37 @@ - function GetEsMangaHereImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - if workCounter > 0 then - Result := GetPage(TObject(l), - FillMangaSiteHost(ESMANGAHERE_ID, URL) + - IntToStr(workCounter + 1) + '.html', - manager.container.manager.retryConnect) - else - Result := GetPage(TObject(l), - WebsiteRoots[ESMANGAHERE_ID, 1] + URL, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="read_img"', parse.Strings[i]) <> 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i + 6], 'src=')); - parse.Free; - l.Free; - Exit; - end; - end; - parse.Free; - l.Free; - end; + function GetEsMangaHereImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + if workCounter > 0 then + Result := GetPage(TObject(l), + FillMangaSiteHost(ESMANGAHERE_ID, URL) + + IntToStr(workCounter + 1) + '.html', + manager.container.manager.retryConnect) + else + Result := GetPage(TObject(l), + WebsiteRoots[ESMANGAHERE_ID, 1] + URL, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="read_img"', parse[i]) <> 0) then + begin + manager.container.PageLinks[workCounter] := + GetVal(parse[i + 6], 'src'); + parse.Free; + l.Free; + Exit; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/EsMangaHere/manga_information.inc b/baseunits/includes/EsMangaHere/manga_information.inc index 788dcb580..69b647f00 100644 --- a/baseunits/includes/EsMangaHere/manga_information.inc +++ b/baseunits/includes/EsMangaHere/manga_information.inc @@ -1,119 +1,119 @@ - function GetEsMangaHereInfoFromURL: Byte; - var - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[ESMANGAHERE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ESMANGAHERE_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i + 1], 'Manga - Leer ', - ' manga en Español'); - - // get cover link - if GetTagName(parse.Strings[i]) = 'img' then - if (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'img') then - mangaInfo.coverLink := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src')); - - // get summary - if (Pos('id="show"', parse.Strings[i])) <> 0 then - begin - parse.Strings[i + 1] := StringFilter(parse.Strings[i + 1]); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #10, '\n', [rfReplaceAll]); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse.Strings[i + 1]; - end; - - // get chapter name and links - if (GetTagName(parse.Strings[i]) = 'a') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'color_0077') and - (Pos('/manga/', GetAttributeValue(GetTagAttribute(parse.Strings[i], - 'href='))) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[ESMANGAHERE_ID, 1], '', [rfReplaceAll])); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #10, '', [rfReplaceAll]); - parse.Strings[i + 1] := StringReplace(parse.Strings[i + 1], #13, '', [rfReplaceAll]); - parse.Strings[i + 1] := TrimLeft(parse.Strings[i + 1]); - parse.Strings[i + 1] := TrimRight(parse.Strings[i + 1]); - mangaInfo.chapterName.Add( - StringFilter(TrimRight(RemoveSymbols(parse.Strings[i + 1])))); - end; - - // get authors - if (Pos('Autor(s):', parse.Strings[i]) <> 0) then - mangaInfo.authors := parse.Strings[i + 3]; - - // get artists - if (Pos('Artist(s):', parse.Strings[i]) <> 0) then - mangaInfo.artists := parse.Strings[i + 3]; - - // get genres - if (Pos('Género(s):', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := ''; - for j := 0 to 37 do - if Pos(LowerCase(defaultGenres[j]), LowerCase(parse.Strings[i + 2])) <> 0 then - mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); - end; - - { // get status - if (Pos('Status:', parse.Strings[i])<>0) then - begin - if Pos('Ongoing', parse.Strings[i+2])<>0 then - mangaInfo.status:= '1' // ongoing - else - mangaInfo.status:= '0'; // completed - end; } - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - - // Delete 'latest' chapter because it isnt exist - { if (mangaInfo.status = '1') AND (mangainfo.ChapterName.Count > 0) then - begin - Dec(mangaInfo.numChapter); - mangainfo.ChapterName.Delete(mangainfo.ChapterName.Count-1); - mangainfo.chapterLinks.Delete(mangainfo.chapterLinks.Count-1); - end; } - Result := NO_ERROR; - end; + function GetEsMangaHereInfoFromURL: Byte; + var + i, j: Cardinal; + begin + mangaInfo.website := WebsiteRoots[ESMANGAHERE_ID, 0]; + mangaInfo.url := FillMangaSiteHost(ESMANGAHERE_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + mangaInfo.status := '1'; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos('<title>', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i + 1], 'Manga - Leer ', + ' manga en Español'); + + // get cover link + if GetTagName(parse[i]) = 'img' then + if (GetVal(parse[i], 'class') = 'img') then + mangaInfo.coverLink := + GetVal(parse[i], 'src'); + + // get summary + if (Pos('id="show"', parse[i])) <> 0 then + begin + parse[i + 1] := StringFilter(parse[i + 1]); + parse[i + 1] := StringReplace(parse[i + 1], #10, '\n', [rfReplaceAll]); + parse[i + 1] := StringReplace(parse[i + 1], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := parse[i + 1]; + end; + + // get chapter name and links + if (GetTagName(parse[i]) = 'a') and + (GetVal(parse[i], 'class') = 'color_0077') and + (Pos('/manga/', GetVal(parse[i], + 'href')) <> 0) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add( + StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[ESMANGAHERE_ID, 1], '', [rfReplaceAll])); + parse[i + 1] := StringReplace(parse[i + 1], #10, '', [rfReplaceAll]); + parse[i + 1] := StringReplace(parse[i + 1], #13, '', [rfReplaceAll]); + parse[i + 1] := TrimLeft(parse[i + 1]); + parse[i + 1] := TrimRight(parse[i + 1]); + mangaInfo.chapterName.Add( + StringFilter(TrimRight(RemoveSymbols(parse[i + 1])))); + end; + + // get authors + if (Pos('Autor(s):', parse[i]) <> 0) then + mangaInfo.authors := parse[i + 3]; + + // get artists + if (Pos('Artist(s):', parse[i]) <> 0) then + mangaInfo.artists := parse[i + 3]; + + // get genres + if (Pos('Género(s):', parse[i]) <> 0) then + begin + mangaInfo.genres := ''; + for j := 0 to 37 do + if Pos(LowerCase(defaultGenres[j]), LowerCase(parse[i + 2])) <> 0 then + mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); + end; + + { // get status + if (Pos('Status:', parse[i])<>0) then + begin + if Pos('Ongoing', parse[i+2])<>0 then + mangaInfo.status:= '1' // ongoing + else + mangaInfo.status:= '0'; // completed + end; } + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterName.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterName.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + + // Delete 'latest' chapter because it isnt exist + { if (mangaInfo.status = '1') AND (mangainfo.ChapterName.Count > 0) then + begin + Dec(mangaInfo.numChapter); + mangainfo.ChapterName.Delete(mangainfo.ChapterName.Count-1); + mangainfo.chapterLinks.Delete(mangainfo.chapterLinks.Count-1); + end; } + Result := NO_ERROR; + end; diff --git a/baseunits/includes/EsMangaHere/names_and_links.inc b/baseunits/includes/EsMangaHere/names_and_links.inc index e4df10267..d9c94ae0d 100644 --- a/baseunits/includes/EsMangaHere/names_and_links.inc +++ b/baseunits/includes/EsMangaHere/names_and_links.inc @@ -1,35 +1,35 @@ - function EsMangaHereGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ESMANGAHERE_ID, 1] + - ESMANGAHERE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('manga_info', parse.Strings[i]) <> 0 then - begin - Result := NO_ERROR; - names.Add(StringFilter(GetString(parse.Strings[i], 'rel="', '" href'))); - links.Add(StringReplace(GetString(parse.Strings[i], 'href="', '">'), - WebsiteRoots[ESMANGAHERE_ID, 1], '', [])); - end; - end; - Source.Free; + function EsMangaHereGetNamesAndLinks: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[ESMANGAHERE_ID, 1] + + ESMANGAHERE_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if Pos('manga_info', parse[i]) <> 0 then + begin + Result := NO_ERROR; + names.Add(StringFilter(GetString(parse[i], 'rel="', '" href'))); + links.Add(StringReplace(GetString(parse[i], 'href="', '">'), + WebsiteRoots[ESMANGAHERE_ID, 1], '', [])); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Fakku/directory_page_number.inc b/baseunits/includes/Fakku/directory_page_number.inc index 147e4c660..caa8361ac 100644 --- a/baseunits/includes/Fakku/directory_page_number.inc +++ b/baseunits/includes/Fakku/directory_page_number.inc @@ -1,37 +1,37 @@ - function GetFakkuDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'a') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'title=')) = - 'Last Page') then - begin - s := TrimRight(TrimLeft(GetString(parse.Strings[i], '/page/', '"'))); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetFakkuDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'a') and + (GetVal(parse[i], 'title') = + 'Last Page') then + begin + s := TrimRight(TrimLeft(GetString(parse[i], '/page/', '"'))); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Fakku/image_url.inc b/baseunits/includes/Fakku/image_url.inc index 29287e549..6c1582686 100644 --- a/baseunits/includes/Fakku/image_url.inc +++ b/baseunits/includes/Fakku/image_url.inc @@ -16,9 +16,9 @@ //Get total pages for i := 0 to l.Count - 1 do begin - if (Pos('window.params.thumbs = ', l.strings[i]) > 0) then + if (Pos('window.params.thumbs = ', l[i]) > 0) then begin - s := GetString(l.Strings[i], '= [', '];'); + s := GetString(l[i], '= [', '];'); with TStringList.Create do try DelimitedText := s; @@ -36,10 +36,10 @@ //Get imgurl for i := 0 to l.Count - 1 do begin - if (Pos('return ''', l.Strings[i]) > 0) then + if (Pos('return ''', l[i]) > 0) then begin - imgURL := GetString(l.Strings[i], 'return ''', ''' +'); - imgExt := GetString(l.Strings[i], 'x + ''', ''';'); + imgURL := GetString(l[i], 'return ''', ''' +'); + imgExt := GetString(l[i], 'x + ''', ''';'); Break; end; end; diff --git a/baseunits/includes/Fakku/manga_information.inc b/baseunits/includes/Fakku/manga_information.inc index fdd9c231c..a5d29243b 100644 --- a/baseunits/includes/Fakku/manga_information.inc +++ b/baseunits/includes/Fakku/manga_information.inc @@ -1,101 +1,101 @@ - function GetFakkuInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = False; - i: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(FAKKU_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[FAKKU_ID, 0]; - if parse.Count = 0 then - Exit; - - mangaInfo.status := '0'; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - for i := 0 to parse.Count - 1 do - begin - // get manga title - if GetVal(parse[i], 'property') = 'og:title' then - mangaInfo.title := CommonStringFilter(GetVal(parse[i], 'content')); - - // get cover - if (Pos('<img ', parse[i]) > 0) and (Pos('class="cover"', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'src'); - if ExecRegExpr('^//', s) then - mangaInfo.coverLink := 'https:' + s - else - mangaInfo.coverLink := s - end; - - // get read/chapter - if GetVal(parse[i], 'class') = 'button green' then - begin - Inc(mangaInfo.numChapter); - if mangaInfo.title = '' then - mangaInfo.title := 'Unknown'; - mangaInfo.chapterName.Add(mangaInfo.title); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - end; - - // get series/authors - if (Pos('div class="left"', parse.Strings[i]) > 0) and - (Pos('Series', parse.Strings[i + 1]) > 0) then - begin - mangaInfo.authors := parse.Strings[i + 6]; - mangaInfo.genres := mangaInfo.authors; - end; - - // get artists - if (Pos('div class="left"', parse.Strings[i]) > 0) and - (Pos('Artist', parse.Strings[i + 1]) > 0) then - begin - mangaInfo.artists := parse.Strings[i + 6]; - mangaInfo.genres := mangaInfo.genres + ', ' + mangaInfo.artists; - end; - - // get language - if (Pos('div class="left"', parse.Strings[i]) > 0) and - (Pos('Language', parse.Strings[i + 1]) > 0) then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse.Strings[i + 7]); - - // get descriptions - if (Pos('div class="left"', parse.Strings[i]) > 0) and - (Pos('Description', parse.Strings[i + 1]) > 0) then - isExtractSummary := True; - - if isExtractSummary then - begin - if (Pos('</div>', parse.Strings[i + 5]) > 0) then - isExtractSummary := False - else if (not (Pos('<', parse.Strings[i + 5]) > 0)) then - mangaInfo.summary := Trim(mangaInfo.summary) + ' ' + Trim(parse.Strings[i + 5]); - end; - - // get genres - if (Pos('"/tags/', parse.Strings[i]) > 0) then - begin - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse.Strings[i + 1]); - end; - end; - - //last correction - mangaInfo.summary := BreaksString(StringFilter(mangaInfo.summary)); - Result := NO_ERROR; - end; + function GetFakkuInfoFromURL: Byte; + var + s: String; + isExtractSummary: Boolean = False; + i: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(FAKKU_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[FAKKU_ID, 0]; + if parse.Count = 0 then + Exit; + + mangaInfo.status := '0'; + mangaInfo.genres := ''; + // using parser (cover link, summary, chapter name and link) + for i := 0 to parse.Count - 1 do + begin + // get manga title + if GetVal(parse[i], 'property') = 'og:title' then + mangaInfo.title := CommonStringFilter(GetVal(parse[i], 'content')); + + // get cover + if (Pos('<img ', parse[i]) > 0) and (Pos('class="cover"', parse[i]) > 0) then + begin + s := GetVal(parse[i], 'src'); + if ExecRegExpr('^//', s) then + mangaInfo.coverLink := 'https:' + s + else + mangaInfo.coverLink := s + end; + + // get read/chapter + if GetVal(parse[i], 'class') = 'button green' then + begin + Inc(mangaInfo.numChapter); + if mangaInfo.title = '' then + mangaInfo.title := 'Unknown'; + mangaInfo.chapterName.Add(mangaInfo.title); + mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); + end; + + // get series/authors + if (Pos('div class="left"', parse[i]) > 0) and + (Pos('Series', parse[i + 1]) > 0) then + begin + mangaInfo.authors := parse[i + 6]; + mangaInfo.genres := mangaInfo.authors; + end; + + // get artists + if (Pos('div class="left"', parse[i]) > 0) and + (Pos('Artist', parse[i + 1]) > 0) then + begin + mangaInfo.artists := parse[i + 6]; + mangaInfo.genres := mangaInfo.genres + ', ' + mangaInfo.artists; + end; + + // get language + if (Pos('div class="left"', parse[i]) > 0) and + (Pos('Language', parse[i + 1]) > 0) then + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 7]); + + // get descriptions + if (Pos('div class="left"', parse[i]) > 0) and + (Pos('Description', parse[i + 1]) > 0) then + isExtractSummary := True; + + if isExtractSummary then + begin + if (Pos('</div>', parse[i + 5]) > 0) then + isExtractSummary := False + else if (not (Pos('<', parse[i + 5]) > 0)) then + mangaInfo.summary := Trim(mangaInfo.summary) + ' ' + Trim(parse[i + 5]); + end; + + // get genres + if (Pos('"/tags/', parse[i]) > 0) then + begin + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); + end; + end; + + //last correction + mangaInfo.summary := BreaksString(StringFilter(mangaInfo.summary)); + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Fakku/names_and_links.inc b/baseunits/includes/Fakku/names_and_links.inc index 2b979d06d..be64020cc 100644 --- a/baseunits/includes/Fakku/names_and_links.inc +++ b/baseunits/includes/Fakku/names_and_links.inc @@ -1,48 +1,48 @@ - function FakkuGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - i := StrToInt(URL); - if i = 0 then - begin - if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - end - else - begin - if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + - FAKKU_BROWSER + '/page/' + IntToStr(i + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="content-title"', parse[i]) > 0 then - begin - Result := NO_ERROR; - names.Add(Trim(GetAttributeValue(GetTagAttribute(parse[i], 'title=')))); - links.Add(StringReplace(GetAttributeValue(GetTagAttribute(parse[i], 'href=')), - WebsiteRoots[FAKKU_ID, 1], '', [])); - end; - end; - Source.Free; + function FakkuGetNamesAndLinks: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + i := StrToInt(URL); + if i = 0 then + begin + if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + end + else + begin + if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + + FAKKU_BROWSER + '/page/' + IntToStr(i + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if Pos('class="content-title"', parse[i]) > 0 then + begin + Result := NO_ERROR; + names.Add(Trim(GetVal(parse[i], 'title'))); + links.Add(StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[FAKKU_ID, 1], '', [])); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Hentai2Read/chapter_page_number.inc b/baseunits/includes/Hentai2Read/chapter_page_number.inc index 735da9b19..7caa10210 100644 --- a/baseunits/includes/Hentai2Read/chapter_page_number.inc +++ b/baseunits/includes/Hentai2Read/chapter_page_number.inc @@ -1,37 +1,37 @@ - function GetHentai2ReadPageNumber: Boolean; - var - i, j: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(HENTAI2READ_ID, URL), - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'select') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = - 'cbo_wpm_pag') then - begin - j := i + 1; - while GetTagName(parse.Strings[j]) = 'option' do - begin - Inc(manager.container.PageNumber); - Inc(j, 3); - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetHentai2ReadPageNumber: Boolean; + var + i, j: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(HENTAI2READ_ID, URL), + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'select') and + (GetVal(parse[i], 'class') = + 'cbo_wpm_pag') then + begin + j := i + 1; + while GetTagName(parse[j]) = 'option' do + begin + Inc(manager.container.PageNumber); + Inc(j, 3); + end; + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Hentai2Read/directory_page_number.inc b/baseunits/includes/Hentai2Read/directory_page_number.inc index 77ee7dcba..f4febbca6 100644 --- a/baseunits/includes/Hentai2Read/directory_page_number.inc +++ b/baseunits/includes/Hentai2Read/directory_page_number.inc @@ -1,37 +1,37 @@ - function GetHentai2ReadDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), HENTAI2READ_ROOT + HENTAI2READ_BROWSER + - '?text-ver', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'img') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'alt=')) = 'Next Page') then - begin - s := TrimRight(TrimLeft(parse.Strings[i - 5])); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetHentai2ReadDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), HENTAI2READ_ROOT + HENTAI2READ_BROWSER + + '?text-ver', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'img') and + (GetVal(parse[i], 'alt') = 'Next Page') then + begin + s := TrimRight(TrimLeft(parse[i - 5])); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Hentai2Read/image_url.inc b/baseunits/includes/Hentai2Read/image_url.inc index 536490d18..af38c9f7a 100644 --- a/baseunits/includes/Hentai2Read/image_url.inc +++ b/baseunits/includes/Hentai2Read/image_url.inc @@ -1,31 +1,31 @@ - function GetHentai2ReadImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(HENTAI2READ_ID, URL) + IntToStr(workCounter + 1) + '/', - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse.Strings[i]) = 'img') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'id=')) = - 'img_mng_enl') then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetHentai2ReadImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(HENTAI2READ_ID, URL) + IntToStr(workCounter + 1) + '/', + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (GetTagName(parse[i]) = 'img') and + (GetVal(parse[i], 'id') = + 'img_mng_enl') then + begin + manager.container.PageLinks[workCounter] := + GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Hentai2Read/manga_information.inc b/baseunits/includes/Hentai2Read/manga_information.inc index 718b711d1..1adfe35ca 100644 --- a/baseunits/includes/Hentai2Read/manga_information.inc +++ b/baseunits/includes/Hentai2Read/manga_information.inc @@ -1,165 +1,164 @@ - function GetHentai2ReadInfoFromURL: Byte; - var - s: String; - isExtractChapters: Boolean = False; - isExtractGenres: Boolean = False; - isExtractSummary: Boolean = True; - i, j: Cardinal; - regx: TRegExpr; - begin - mangaInfo.url := FillMangaSiteHost(HENTAI2READ_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[HENTAI2READ_ID, 0]; - - regx := TRegExpr.Create; - regx.ModifierI := True; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get title - if (Pos('class="head_det_title"', parse[i]) > 0) then - begin - s := Trim(StringFilter(parse[i + 1])); - regx.Expression := '^.+\sdj\s[-_]\s(.+)$'; - mangaInfo.title := regx.Replace(s, '$1', True); - end; - //if (mangaInfo.title = '') AND - //(Pos('meta name="description" content="', parse.Strings[i])>0) then - //mangaInfo.title:= GetString(parse.Strings[i], 'meta name="description" content="', ' hentai chapters'); - - // get cover link - if (GetTagName(parse.Strings[i]) = 'div') and - (i < parse.Count - 3) then - if (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'cover') then - begin - mangaInfo.coverLink := - GetAttributeValue(GetTagAttribute(parse.Strings[i + 2], 'src=')); - if mangaInfo.coverLink = - 'http://hentai2read.com/wp-content/hentai/cover/tbn/001_1535_233x0.jpg' then - mangaInfo.coverLink := ''; - end; - - // get chapter name and links - if isExtractChapters then - begin - if (GetTagName(parse.Strings[i]) = 'a') and (i < parse.Count - 2) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'href=')), - HENTAI2READ_ROOT, '', [rfReplaceAll]); - s := StringReplace(s, HENTAI2READ_MROOT, '', [rfReplaceAll]); - mangaInfo.chapterLinks.Add(s); - //s:= StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), HENTAI2READ_ROOT, '', [rfReplaceAll]); - //parse.Strings[i+1]:= StringReplace(parse.Strings[i+1], #10, '', [rfReplaceAll]); - //parse.Strings[i+1]:= StringReplace(parse.Strings[i+1], #13, '', [rfReplaceAll]); - //parse.Strings[i+1]:= TrimLeft(parse.Strings[i+1]); - //parse.Strings[i+1]:= TrimRight(parse.Strings[i+1]); - //s:= RemoveSymbols(parse.Strings[i+1]); - regx.Expression := '^\d+\s[-_]\s'; - s := regx.Replace(Trim(parse[i + 1]), '', False); - mangaInfo.chapterName.Add(Trim(StringFilter(RemoveSymbols(s)))); - //mangaInfo.chapterName.Add(StringFilter(TrimRight(RemoveSymbols(parse.Strings[i+1])))); - end - else - if (GetTagName(parse.Strings[i]) = 'div') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'right') then - isExtractChapters := False; - end; - - // get summary - if (Pos('Hentai Summary', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 5; - mangaInfo.summary := ''; - while (j < parse.Count) and (Pos('<div class="box">', parse.Strings[j]) = 0) and - (j < parse.Count - 1) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - s := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - s := Trim(BreaksString(s)); - mangaInfo.summary := Trim(mangaInfo.summary + s); - end; - Inc(j); - end; - isExtractSummary := False; - end; - - if Pos('Hentai Chapters', parse.Strings[i]) > 0 then - isExtractChapters := True; - - // get authors - if (Pos('Author(s):', parse.Strings[i]) <> 0) and (i < parse.Count - 6) then - mangaInfo.authors := parse.Strings[i + 5]; - - // get artists - if (Pos('Artist(s):', parse.Strings[i]) <> 0) and (i < parse.Count - 6) then - mangaInfo.artists := parse.Strings[i + 5]; - - // get genres - if (Pos('Genre(s):', parse.Strings[i]) <> 0) and (i < parse.Count - 6) then - begin - mangaInfo.genres := ''; - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if GetTagName(parse.Strings[i]) = 'a' then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - end - else - if (GetTagName(parse.Strings[i]) = 'div') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'box') then - isExtractGenres := False; - end; - - // get status - if (Pos('Status:', parse.Strings[i]) <> 0) and (i <= parse.Count - 5) then - begin - if Pos('Ongoing', parse.Strings[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - regx.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetHentai2ReadInfoFromURL: Byte; + var + s: String; + isExtractChapters: Boolean = False; + isExtractGenres: Boolean = False; + isExtractSummary: Boolean = True; + i, j: Cardinal; + regx: TRegExpr; + begin + mangaInfo.url := FillMangaSiteHost(HENTAI2READ_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[HENTAI2READ_ID, 0]; + + regx := TRegExpr.Create; + regx.ModifierI := True; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get title + if (Pos('class="head_det_title"', parse[i]) > 0) then + begin + s := Trim(StringFilter(parse[i + 1])); + regx.Expression := '^.+\sdj\s[-_]\s(.+)$'; + mangaInfo.title := regx.Replace(s, '$1', True); + end; + //if (mangaInfo.title = '') AND + //(Pos('meta name="description" content="', parse[i])>0) then + //mangaInfo.title:= GetString(parse[i], 'meta name="description" content="', ' hentai chapters'); + + // get cover link + if (GetTagName(parse[i]) = 'div') and + (i < parse.Count - 3) then + if (GetVal(parse[i], 'class') = 'cover') then + begin + mangaInfo.coverLink := + GetVal(parse[i + 2], 'src'); + if mangaInfo.coverLink = + 'http://hentai2read.com/wp-content/hentai/cover/tbn/001_1535_233x0.jpg' then + mangaInfo.coverLink := ''; + end; + + // get chapter name and links + if isExtractChapters then + begin + if (GetTagName(parse[i]) = 'a') and (i < parse.Count - 2) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + HENTAI2READ_ROOT, '', [rfReplaceAll]); + s := StringReplace(s, HENTAI2READ_MROOT, '', [rfReplaceAll]); + mangaInfo.chapterLinks.Add(s); + //s:= StringReplace(GetVal(parse[i], 'href'), HENTAI2READ_ROOT, '', [rfReplaceAll]); + //parse[i+1]:= StringReplace(parse[i+1], #10, '', [rfReplaceAll]); + //parse[i+1]:= StringReplace(parse[i+1], #13, '', [rfReplaceAll]); + //parse[i+1]:= TrimLeft(parse[i+1]); + //parse[i+1]:= TrimRight(parse[i+1]); + //s:= RemoveSymbols(parse[i+1]); + regx.Expression := '^\d+\s[-_]\s'; + s := regx.Replace(Trim(parse[i + 1]), '', False); + mangaInfo.chapterName.Add(Trim(StringFilter(RemoveSymbols(s)))); + //mangaInfo.chapterName.Add(StringFilter(TrimRight(RemoveSymbols(parse[i+1])))); + end + else + if (GetTagName(parse[i]) = 'div') and + (GetVal(parse[i], 'class') = 'right') then + isExtractChapters := False; + end; + + // get summary + if (Pos('Hentai Summary', parse[i]) <> 0) and + (isExtractSummary) then + begin + j := i + 5; + mangaInfo.summary := ''; + while (j < parse.Count) and (Pos('<div class="box">', parse[j]) = 0) and + (j < parse.Count - 1) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + s := HTMLEntitiesFilter(StringFilter(parse[j])); + s := Trim(BreaksString(s)); + mangaInfo.summary := Trim(mangaInfo.summary + s); + end; + Inc(j); + end; + isExtractSummary := False; + end; + + if Pos('Hentai Chapters', parse[i]) > 0 then + isExtractChapters := True; + + // get authors + if (Pos('Author(s):', parse[i]) <> 0) and (i < parse.Count - 6) then + mangaInfo.authors := parse[i + 5]; + + // get artists + if (Pos('Artist(s):', parse[i]) <> 0) and (i < parse.Count - 6) then + mangaInfo.artists := parse[i + 5]; + + // get genres + if (Pos('Genre(s):', parse[i]) <> 0) and (i < parse.Count - 6) then + begin + mangaInfo.genres := ''; + isExtractGenres := True; + end; + + if isExtractGenres then + begin + if GetTagName(parse[i]) = 'a' then + begin + if mangaInfo.genres = '' then + mangaInfo.genres := Trim(parse[i + 1]) + else + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); + end + else + if (GetTagName(parse[i]) = 'div') and + (GetVal(parse[i], 'class') = 'box') then + isExtractGenres := False; + end; + + // get status + if (Pos('Status:', parse[i]) <> 0) and (i <= parse.Count - 5) then + begin + if Pos('Ongoing', parse[i + 4]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + regx.Free; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterName.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterName.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Hentai2Read/names_and_links.inc b/baseunits/includes/Hentai2Read/names_and_links.inc index 9695a1777..6e2d6e32a 100644 --- a/baseunits/includes/Hentai2Read/names_and_links.inc +++ b/baseunits/includes/Hentai2Read/names_and_links.inc @@ -1,47 +1,46 @@ - function Hentai2ReadGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), HENTAI2READ_ROOT + HENTAI2READ_BROWSER + - IntToStr(StrToInt(URL) + 1) + '/?text-ver', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - regx := TRegExpr.Create; - regx.ModifierI := True; - regx.Expression := '^.+\sdj\s[-_]\s(.+)$'; - for i := 0 to parse.Count - 1 do - begin - //if Pos('class="lst-anm-ifo"', parse.Strings[i])>0 then - if Pos('class="mng_det_pop"', parse[i]) > 0 then - begin - begin - Result := NO_ERROR; - s := Trim(StringFilter(GetAttributeValue( - GetTagAttribute(parse[i], 'title=')))); - s := regx.Replace(s, '$1', True); - names.Add(s); - links.Add(StringReplace(GetAttributeValue(GetTagAttribute(parse[i], 'href=')), - HENTAI2READ_ROOT, '', [])); - end; - end; - end; - regx.Free; - Source.Free; + function Hentai2ReadGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + regx: TRegExpr; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), HENTAI2READ_ROOT + HENTAI2READ_BROWSER + + IntToStr(StrToInt(URL) + 1) + '/?text-ver', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + regx := TRegExpr.Create; + regx.ModifierI := True; + regx.Expression := '^.+\sdj\s[-_]\s(.+)$'; + for i := 0 to parse.Count - 1 do + begin + //if Pos('class="lst-anm-ifo"', parse[i])>0 then + if Pos('class="mng_det_pop"', parse[i]) > 0 then + begin + begin + Result := NO_ERROR; + s := Trim(StringFilter(GetVal(parse[i], 'title'))); + s := regx.Replace(s, '$1', True); + names.Add(s); + links.Add(StringReplace(GetVal(parse[i], 'href'), + HENTAI2READ_ROOT, '', [])); + end; + end; + end; + regx.Free; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/HugeManga/chapter_page_number.inc b/baseunits/includes/HugeManga/chapter_page_number.inc index 57908d955..19f260753 100644 --- a/baseunits/includes/HugeManga/chapter_page_number.inc +++ b/baseunits/includes/HugeManga/chapter_page_number.inc @@ -1,34 +1,34 @@ - function GetHugeMangaPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('</option>', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 2]; - manager.container.pageNumber := - StrToInt(GetAttributeValue(GetTagAttribute(s, 'value='))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetHugeMangaPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.pageNumber := 0; + for i := parse.Count - 1 downto 5 do + begin + if (Pos('</option>', parse[i]) > 0) then + begin + s := parse[i - 2]; + manager.container.pageNumber := + StrToInt(GetVal(s, 'value')); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/HugeManga/image_url.inc b/baseunits/includes/HugeManga/image_url.inc index b546ff14b..079f6fb45 100644 --- a/baseunits/includes/HugeManga/image_url.inc +++ b/baseunits/includes/HugeManga/image_url.inc @@ -1,32 +1,32 @@ - function GetHugeMangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - EncodeURL(WebsiteRoots[HUGEMANGA_ID, 1] + HUGEMANGA_BROWSER + - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetHugeMangaImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="picture"', parse[i]) > 0) then + begin + manager.container.PageLinks[workCounter] := + EncodeURL(WebsiteRoots[HUGEMANGA_ID, 1] + HUGEMANGA_BROWSER + + GetVal(parse[i], 'src')); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/HugeManga/manga_information.inc b/baseunits/includes/HugeManga/manga_information.inc index 08e951a5d..2a439531a 100644 --- a/baseunits/includes/HugeManga/manga_information.inc +++ b/baseunits/includes/HugeManga/manga_information.inc @@ -1,75 +1,74 @@ - function GetHugeMangaInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[HUGEMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(HUGEMANGA_ID, HUGEMANGA_BROWSER + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('<title>', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i + 1], 'indonesia online - ', - ' - Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse.Strings[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := '/' + URL + '/' + GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'value=')); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetHugeMangaInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.website := WebsiteRoots[HUGEMANGA_ID, 0]; + mangaInfo.url := FillMangaSiteHost(HUGEMANGA_ID, HUGEMANGA_BROWSER + URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + mangaInfo.status := '1'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get chapter name and links + if (Pos('select name="chapter"', parse[i]) > 0) then + isExtractChapter := True; + + // get manga name + if (mangaInfo.title = '') and (Pos('<title>', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i + 1], 'indonesia online - ', + ' - Chapter'); + + if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then + Break; + + if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := '/' + URL + '/' + GetVal(parse[i], 'value'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/HugeManga/names_and_links.inc b/baseunits/includes/HugeManga/names_and_links.inc index 4e3e592c8..29c4db3b4 100644 --- a/baseunits/includes/HugeManga/names_and_links.inc +++ b/baseunits/includes/HugeManga/names_and_links.inc @@ -1,38 +1,38 @@ - function HugeMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[HUGEMANGA_ID, 1] + - HUGEMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('option value="', parse.Strings[i]) > 0) and - (Pos('value="0"', parse.Strings[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 1]); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - links.Add(s); - end; - end; - Source.Free; + function HugeMangaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[HUGEMANGA_ID, 1] + + HUGEMANGA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('option value="', parse[i]) > 0) and + (Pos('value="0"', parse[i]) = 0) then + begin + Result := NO_ERROR; + s := StringFilter(parse[i + 1]); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i], 'value'); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Imanhua/names_and_links.inc b/baseunits/includes/Imanhua/names_and_links.inc index 69f461538..949efedb1 100644 --- a/baseunits/includes/Imanhua/names_and_links.inc +++ b/baseunits/includes/Imanhua/names_and_links.inc @@ -23,13 +23,13 @@ end; for i := 0 to parse.Count - 1 do begin - if (Pos('href="/comic/', parse.Strings[i]) > 0) and - (Pos('/list_', parse.Strings[i]) = 0) then + if (Pos('href="/comic/', parse[i]) > 0) and + (Pos('/list_', parse[i]) = 0) then begin Result := NO_ERROR; - s := StringFilter(parse.Strings[i + 1]); + s := StringFilter(parse[i + 1]); names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); + s := GetVal(parse[i], 'href'); links.Add(s); end; end; diff --git a/baseunits/includes/JapanShin/chapter_page_number.inc b/baseunits/includes/JapanShin/chapter_page_number.inc index 29763e83d..e7ef3eaa5 100644 --- a/baseunits/includes/JapanShin/chapter_page_number.inc +++ b/baseunits/includes/JapanShin/chapter_page_number.inc @@ -18,8 +18,8 @@ manager.container.PageNumber := 0; //class="tbtitle dropdown_parent dropdown_right for i := 0 to parse.Count - 1 do - if (Pos('onClick="changePage', parse.Strings[i]) > 0) and - (Pos('return false', parse.Strings[i]) > 0) then + if (Pos('onClick="changePage', parse[i]) > 0) and + (Pos('return false', parse[i]) > 0) then Inc(manager.container.PageNumber); end; parse.Free; diff --git a/baseunits/includes/JapanShin/image_url.inc b/baseunits/includes/JapanShin/image_url.inc index 08d5a94b8..54c98147a 100644 --- a/baseunits/includes/JapanShin/image_url.inc +++ b/baseunits/includes/JapanShin/image_url.inc @@ -24,11 +24,11 @@ if parse.Count > 0 then begin for i := 0 to parse.Count - 1 do - if (Pos('<img', parse.Strings[i]) > 0) and - (Pos('class="open"', parse.Strings[i]) > 0) then + if (Pos('<img', parse[i]) > 0) and + (Pos('class="open"', parse[i]) > 0) then begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); + manager.container.PageLinks[workCounter] := + GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/JapanShin/manga_information.inc b/baseunits/includes/JapanShin/manga_information.inc index e5bf9c04f..b5d0c3d4b 100644 --- a/baseunits/includes/JapanShin/manga_information.inc +++ b/baseunits/includes/JapanShin/manga_information.inc @@ -27,40 +27,40 @@ for i := 0 to parse.Count - 1 do begin //get title - if (Pos('h1 class="title"', parse.Strings[i]) > 0) then - mangaInfo.title := Trim(parse.Strings[i + 1]); + if (Pos('h1 class="title"', parse[i]) > 0) then + mangaInfo.title := Trim(parse[i + 1]); //get coverlink - if (Pos('class="thumbnail"', parse.Strings[i]) > 0) then + if (Pos('class="thumbnail"', parse[i]) > 0) then begin j := i + 1; - while (Pos('<img', parse.Strings[j]) = 0) do + while (Pos('<img', parse[j]) = 0) do Inc(j); - mangaInfo.coverLink := GetAttributeValue(GetTagAttribute(parse.Strings[j], 'src=')); + mangaInfo.coverLink := GetVal(parse[j], 'src'); end; //get authors - if (Pos('Auteur :', parse.Strings[i]) > 0) then - mangaInfo.authors := parse.Strings[i + 2]; + if (Pos('Auteur :', parse[i]) > 0) then + mangaInfo.authors := parse[i + 2]; //get genre - if (Pos('Genre :', parse.Strings[i]) > 0) then - mangaInfo.genres := parse.Strings[i + 2]; + if (Pos('Genre :', parse[i]) > 0) then + mangaInfo.genres := parse[i + 2]; //get summary - if (Pos('Synopsis :', parse.Strings[i]) > 0) then - mangaInfo.summary := parse.Strings[i + 2]; + if (Pos('Synopsis :', parse[i]) > 0) then + mangaInfo.summary := parse[i + 2]; //get chapter name and links - if (Pos('href="', parse.Strings[i]) > 0) and - (Pos('title="', parse.Strings[i]) > 0) and - (Pos('/reader/read/', parse.Strings[i]) > 0) then + if (Pos('href="', parse[i]) > 0) and + (Pos('title="', parse[i]) > 0) and + (Pos('/reader/read/', parse[i]) > 0) then begin Inc(mangaInfo.numChapter); mangaInfo.chapterLinks.Add( - StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), + StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[JAPANSHIN_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(Trim(parse.Strings[i + 1])); + mangaInfo.chapterName.Add(Trim(parse[i + 1])); end; end; diff --git a/baseunits/includes/JapanShin/names_and_links.inc b/baseunits/includes/JapanShin/names_and_links.inc index 0ffdd6f80..cbf9d5319 100644 --- a/baseunits/includes/JapanShin/names_and_links.inc +++ b/baseunits/includes/JapanShin/names_and_links.inc @@ -26,14 +26,14 @@ end; for i := 0 to parse.Count - 1 do begin - if (Pos('<a', parse.Strings[i]) > 0) and - (Pos('/reader/series/', parse.Strings[i]) > 0) and - (Pos('title="', parse.Strings[i]) > 0) then + if (Pos('<a', parse[i]) > 0) and + (Pos('/reader/series/', parse[i]) > 0) and + (Pos('title="', parse[i]) > 0) then begin Result := NO_ERROR; - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); + s := GetVal(parse[i], 'href'); links.Add(StringReplace(s, WebsiteRoots[JAPANSHIN_ID, 1], '', [rfIgnoreCase])); - s := Trim(HTMLEntitiesFilter(StringFilter(parse.Strings[i + 1]))); + s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); names.Add(s); end; end; diff --git a/baseunits/includes/Japscan/manga_information.inc b/baseunits/includes/Japscan/manga_information.inc index e97e8328b..f95a3f667 100644 --- a/baseunits/includes/Japscan/manga_information.inc +++ b/baseunits/includes/Japscan/manga_information.inc @@ -85,7 +85,7 @@ if Pos('.htm', s) > 0 then s := ReplaceRegExpr('/\d+\.html?$', s, '', False); mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse.Strings[i + 1])); + s := RemoveSymbols(Trim(parse[i + 1])); mangaInfo.chapterName.Add(CommonStringFilter(s)); end; end; diff --git a/baseunits/includes/Japscan/names_and_links.inc b/baseunits/includes/Japscan/names_and_links.inc index 5f351194e..4cd6d280e 100644 --- a/baseunits/includes/Japscan/names_and_links.inc +++ b/baseunits/includes/Japscan/names_and_links.inc @@ -28,7 +28,7 @@ if (Pos(' href="/mangas/', parse[i + 1]) > 0) then begin Result := NO_ERROR; - links.Add(GetAttributeValue(GetTagAttribute(parse[i + 1], 'href='))); + links.Add(GetVal(parse[i + 1], 'href')); names.Add(Trim(parse[i + 2])); end; end; diff --git a/baseunits/includes/Kivmanga/chapter_page_number.inc b/baseunits/includes/Kivmanga/chapter_page_number.inc index 3b8ac8e7f..88945b811 100644 --- a/baseunits/includes/Kivmanga/chapter_page_number.inc +++ b/baseunits/includes/Kivmanga/chapter_page_number.inc @@ -1,33 +1,33 @@ - function GetKivmangaPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Next Page"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 6]; - manager.container.PageNumber := StrToInt(GetString(s, '"', '"')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetKivmangaPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.pageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (Pos('title="Next Page"', parse[i]) > 0) then + begin + s := parse[i - 6]; + manager.container.PageNumber := StrToInt(GetString(s, '"', '"')); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Kivmanga/image_url.inc b/baseunits/includes/Kivmanga/image_url.inc index e89d51717..3675e2982 100644 --- a/baseunits/includes/Kivmanga/image_url.inc +++ b/baseunits/includes/Kivmanga/image_url.inc @@ -1,32 +1,32 @@ - function GetKivmangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse.Strings[i]) > 0) then - begin - s := WebsiteRoots[KIVMANGA_ID, 1] + KIVMANGA_BROWSER + - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - manager.container.PageLinks.Strings[workCounter] := EncodeURL(s); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetKivmangaImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="picture"', parse[i]) > 0) then + begin + s := WebsiteRoots[KIVMANGA_ID, 1] + KIVMANGA_BROWSER + + GetVal(parse[i], 'src'); + manager.container.PageLinks[workCounter] := EncodeURL(s); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Kivmanga/manga_information.inc b/baseunits/includes/Kivmanga/manga_information.inc index d99947a32..6dba60146 100644 --- a/baseunits/includes/Kivmanga/manga_information.inc +++ b/baseunits/includes/Kivmanga/manga_information.inc @@ -36,25 +36,25 @@ for i := 0 to parse.Count - 1 do begin // get chapter name and links - if (Pos('select name="chapter"', parse.Strings[i]) > 0) then + if (Pos('select name="chapter"', parse[i]) > 0) then isExtractChapter := True; // get manga name - if (mangaInfo.title = '') and (Pos('<title>', parse.Strings[i]) > 0) then - mangaInfo.title := TrimLeft(TrimRight(GetString(parse.Strings[i + 1], + if (mangaInfo.title = '') and (Pos('<title>', parse[i]) > 0) then + mangaInfo.title := TrimLeft(TrimRight(GetString(parse[i + 1], 'Read Free Manga Online - ', '-'))); - if (isExtractChapter) and (Pos('option value=', parse.Strings[i]) > 0) then + if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then begin Inc(mangaInfo.numChapter); - s := URL + '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); + s := URL + '/' + GetVal(parse[i], 'value'); mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); end; if (isExtractChapter) and - (Pos('</select>', parse.Strings[i]) > 0) then + (Pos('</select>', parse[i]) > 0) then begin isExtractChapter := False; Break; diff --git a/baseunits/includes/Kivmanga/names_and_links.inc b/baseunits/includes/Kivmanga/names_and_links.inc index 6b9a9045f..bd4346d5c 100644 --- a/baseunits/includes/Kivmanga/names_and_links.inc +++ b/baseunits/includes/Kivmanga/names_and_links.inc @@ -1,37 +1,37 @@ - function KivmangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[KIVMANGA_ID, 1], 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('option value="', parse.Strings[i]) > 0) and - (Pos('value="0"', parse.Strings[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - links.Add(s); - end; - end; - Source.Free; + function KivmangaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[KIVMANGA_ID, 1], 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 5 do + begin + if (Pos('option value="', parse[i]) > 0) and + (Pos('value="0"', parse[i]) = 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(HTMLEntitiesFilter(s)); + s := '/' + GetVal(parse[i], 'value'); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Komikid/chapter_page_number.inc b/baseunits/includes/Komikid/chapter_page_number.inc index bcbff46d4..115857794 100644 --- a/baseunits/includes/Komikid/chapter_page_number.inc +++ b/baseunits/includes/Komikid/chapter_page_number.inc @@ -1,33 +1,33 @@ - function GetKomikidPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KOMIKID_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Next Page"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 6]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetKomikidPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(KOMIKID_ID, URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.pageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (Pos('title="Next Page"', parse[i]) > 0) then + begin + s := parse[i - 6]; + manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Komikid/image_url.inc b/baseunits/includes/Komikid/image_url.inc index a4ce8aea1..7d27184a4 100644 --- a/baseunits/includes/Komikid/image_url.inc +++ b/baseunits/includes/Komikid/image_url.inc @@ -1,45 +1,45 @@ - function GetKomikidImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - s := EncodeURL(FillMangaSiteHost(KOMIKID_ID, URL) + '/' + - IntToStr(workCounter + 1) + '/'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', LowerCase(parse.Strings[i])) > 0) and - (Pos('class="picture"', LowerCase(parse.Strings[i])) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - regx := TRegExpr.Create; - try - regx.Expression := 'https?://'; - if not regx.Exec(s) then - s := WebsiteRoots[KOMIKID_ID, 1] + '/' + s; - s := EncodeURL(s); - manager.container.PageLinks.Strings[workCounter] := s; - finally - regx.Free; - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetKomikidImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + regx: TRegExpr; + begin + l := TStringList.Create; + s := EncodeURL(FillMangaSiteHost(KOMIKID_ID, URL) + '/' + + IntToStr(workCounter + 1) + '/'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (Pos('<img', LowerCase(parse[i])) > 0) and + (Pos('class="picture"', LowerCase(parse[i])) > 0) then + begin + s := GetVal(parse[i], 'src'); + regx := TRegExpr.Create; + try + regx.Expression := 'https?://'; + if not regx.Exec(s) then + s := WebsiteRoots[KOMIKID_ID, 1] + '/' + s; + s := EncodeURL(s); + manager.container.PageLinks[workCounter] := s; + finally + regx.Free; + end; + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Komikid/manga_information.inc b/baseunits/includes/Komikid/manga_information.inc index 1e12adf47..33390d731 100644 --- a/baseunits/includes/Komikid/manga_information.inc +++ b/baseunits/includes/Komikid/manga_information.inc @@ -1,73 +1,73 @@ - function GetKomikidInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[KOMIKID_ID, 0]; - mangaInfo.url := FillMangaSiteHost(KOMIKID_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('<title>', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i - 2], 'content="', ' Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse.Strings[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := URL + '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetKomikidInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.website := WebsiteRoots[KOMIKID_ID, 0]; + mangaInfo.url := FillMangaSiteHost(KOMIKID_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + mangaInfo.status := '1'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get chapter name and links + if (Pos('select name="chapter"', parse[i]) > 0) then + isExtractChapter := True; + + // get manga name + if (mangaInfo.title = '') and (Pos('<title>', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i - 2], 'content="', ' Chapter'); + + if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then + Break; + + if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := URL + '/' + GetVal(parse[i], 'value'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Komikid/names_and_links.inc b/baseunits/includes/Komikid/names_and_links.inc index 13c270dfe..114101927 100644 --- a/baseunits/includes/Komikid/names_and_links.inc +++ b/baseunits/includes/Komikid/names_and_links.inc @@ -1,41 +1,41 @@ - function KomikidGetNamesAndLinks: Byte; - var - i: Cardinal; - isFound: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[KOMIKID_ID, 1] + KOMIKID_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="series_col"', LowerCase(parse.Strings[i])) > 0 then - isFound := True; - if isFound and (Pos('</html>', LowerCase(parse.Strings[i])) > 0) then - isFound := False; - if isFound and (Pos('<a ', parse.Strings[i]) > 0) then - if (Pos('<li>', parse.Strings[i - 1]) > 0) then - begin - Result := NO_ERROR; - links.Add('/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href="'))); - names.Add(Trim(RemoveStringBreaks(HTMLEntitiesFilter( - StringFilter(parse.Strings[i + 1]))))); - end; - end; - parse.Clear; - Source.Free; + function KomikidGetNamesAndLinks: Byte; + var + i: Cardinal; + isFound: Boolean = False; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[KOMIKID_ID, 1] + KOMIKID_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if Pos('class="series_col"', LowerCase(parse[i])) > 0 then + isFound := True; + if isFound and (Pos('</html>', LowerCase(parse[i])) > 0) then + isFound := False; + if isFound and (Pos('<a ', parse[i]) > 0) then + if (Pos('<li>', parse[i - 1]) > 0) then + begin + Result := NO_ERROR; + links.Add('/' + GetVal(parse[i], 'href="')); + names.Add(Trim(RemoveStringBreaks(HTMLEntitiesFilter( + StringFilter(parse[i + 1]))))); + end; + end; + parse.Clear; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/LectureEnLigne/directory_page_number.inc b/baseunits/includes/LectureEnLigne/directory_page_number.inc index 4dc9deaf8..20aa3be4c 100644 --- a/baseunits/includes/LectureEnLigne/directory_page_number.inc +++ b/baseunits/includes/LectureEnLigne/directory_page_number.inc @@ -1,43 +1,43 @@ - function GetLectureEnLigneDirectoryPageNumber: Byte; - var - i, p: Cardinal; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + - LECTUREENLIGNE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - Page := 0; - regx := TRegExpr.Create; - regx.Expression := '^.*\?page=liste.*ordre=.*p=(\d+)\".*$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('href="', parse.Strings[i]) > 0) and - (Pos('?page=liste', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - p := StrToIntDef(regx.Replace(parse.Strings[i], '$1', True), 0); - if p > Page then - Page := p; - end; - end; - regx.Free; - Source.Free; + function GetLectureEnLigneDirectoryPageNumber: Byte; + var + i, p: Cardinal; + regx: TRegExpr; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + + LECTUREENLIGNE_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + + Page := 0; + regx := TRegExpr.Create; + regx.Expression := '^.*\?page=liste.*ordre=.*p=(\d+)\".*$'; + for i := 0 to parse.Count - 1 do + begin + if (Pos('href="', parse[i]) > 0) and + (Pos('?page=liste', parse[i]) > 0) then + begin + Result := NO_ERROR; + p := StrToIntDef(regx.Replace(parse[i], '$1', True), 0); + if p > Page then + Page := p; + end; + end; + regx.Free; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/LectureEnLigne/manga_information.inc b/baseunits/includes/LectureEnLigne/manga_information.inc index 68f14a9b8..1e832ce87 100644 --- a/baseunits/includes/LectureEnLigne/manga_information.inc +++ b/baseunits/includes/LectureEnLigne/manga_information.inc @@ -1,111 +1,111 @@ - function GetLectureEnLigneInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Integer; - begin - mangaInfo.url := FillMangaSiteHost(LECTUREENLIGNE_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[LECTUREENLIGNE_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class="imagemanga"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(WebsiteRoots[LECTUREENLIGNE_ID, 1] + - '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - - // get title - if (Pos('<title>', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - TrimRight(HTMLEntitiesFilter(GetString('~!@' + parse.Strings[i + 1], - '~!@', ' - Lecture-en-ligne.com')))); - - // get chapter name and links - if (Pos('class="table"', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - '../..', '', []); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - mangaInfo.chapterLinks.Add(s); - j := i - 1; - while (Pos('<', parse.Strings[j]) > 0) or (Trim(parse.Strings[j]) = '') do - Dec(j); - s := RemoveSymbols(Trim(parse.Strings[j])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class=''comments''', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get summary - if (Pos('Résumé :', parse.Strings[i]) <> 0) and - (Pos('<p', parse.Strings[i - 1]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 3 < parse.Count) and (Pos('Auteur :', parse.Strings[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 3]))); - - // get artists - if (i + 3 < parse.Count) and (Pos('Dessinateur :', parse.Strings[i]) <> 0) then - mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 3]))); - - // get genres - if (i + 3 < parse.Count) and (Pos('Genres :', parse.Strings[i]) <> 0) then - mangaInfo.genres := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 3]))); - - - // get status - if (i + 5 < parse.Count) and (Pos('Statut :', parse.Strings[i]) <> 0) then - begin - if (Pos('Terminé', parse.Strings[i + 3]) <> 0) or - (Pos('one shot', parse.Strings[i + 3]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; + function GetLectureEnLigneInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j: Integer; + begin + mangaInfo.url := FillMangaSiteHost(LECTUREENLIGNE_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[LECTUREENLIGNE_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('class="imagemanga"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(WebsiteRoots[LECTUREENLIGNE_ID, 1] + + '/' + GetVal(parse[i], 'src')); + + // get title + if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft( + TrimRight(HTMLEntitiesFilter(GetString('~!@' + parse[i + 1], + '~!@', ' - Lecture-en-ligne.com')))); + + // get chapter name and links + if (Pos('class="table"', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + '../..', '', []); + if Pos('.htm', s) > 0 then + s := ReplaceRegExpr('/\d+\.html?$', s, '', False); + mangaInfo.chapterLinks.Add(s); + j := i - 1; + while (Pos('<', parse[j]) > 0) or (Trim(parse[j]) = '') do + Dec(j); + s := RemoveSymbols(Trim(parse[j])); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + + if (isExtractChapter) and + (Pos('class=''comments''', parse[i]) > 0) then + isExtractChapter := False; + + // get summary + if (Pos('Résumé :', parse[i]) <> 0) and + (Pos('<p', parse[i - 1]) <> 0) then + begin + j := i + 4; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + end; + + // get authors + if (i + 3 < parse.Count) and (Pos('Auteur :', parse[i]) <> 0) then + mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); + + // get artists + if (i + 3 < parse.Count) and (Pos('Dessinateur :', parse[i]) <> 0) then + mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); + + // get genres + if (i + 3 < parse.Count) and (Pos('Genres :', parse[i]) <> 0) then + mangaInfo.genres := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); + + + // get status + if (i + 5 < parse.Count) and (Pos('Statut :', parse[i]) <> 0) then + begin + if (Pos('Terminé', parse[i + 3]) <> 0) or + (Pos('one shot', parse[i + 3]) <> 0) then + mangaInfo.status := '0' // completed + else + mangaInfo.status := '1'; // ongoing + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + InvertStrings(mangaInfo.chapterName); + InvertStrings(mangaInfo.chapterLinks); + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/LectureEnLigne/names_and_links.inc b/baseunits/includes/LectureEnLigne/names_and_links.inc index 0284d80c9..39107b2a9 100644 --- a/baseunits/includes/LectureEnLigne/names_and_links.inc +++ b/baseunits/includes/LectureEnLigne/names_and_links.inc @@ -1,43 +1,43 @@ - function LectureEnLigneGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + - LECTUREENLIGNE_BROWSER + '&p=' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - { - if (Pos('option value=', parse[i]) > 0) then - begin - Result:= NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i+1])))); - links.Add(StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')), WebsiteRoots[LECTUREENLIGNE_ID,1], '', [])); - end; - } - if (Pos('class="infoImages"', parse.Strings[i]) > 0) and - (Pos('href="', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse.Strings[i + 1])))); - links.Add('/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href='))); - end; - end; - Source.Free; + function LectureEnLigneGetNamesAndLinks: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + + LECTUREENLIGNE_BROWSER + '&p=' + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + { + if (Pos('option value=', parse[i]) > 0) then + begin + Result:= NO_ERROR; + names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i+1])))); + links.Add(StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[LECTUREENLIGNE_ID,1], '', [])); + end; + } + if (Pos('class="infoImages"', parse[i]) > 0) and + (Pos('href="', parse[i]) > 0) then + begin + Result := NO_ERROR; + names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); + links.Add('/' + GetVal(parse[i], 'href')); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Mabuns/image_url.inc b/baseunits/includes/Mabuns/image_url.inc index f470354d6..ed59702f4 100644 --- a/baseunits/includes/Mabuns/image_url.inc +++ b/baseunits/includes/Mabuns/image_url.inc @@ -1,43 +1,43 @@ - function GetMabunsImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MABUNS_ID, URL); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('addpage(''', parse.Strings[i]) > 0 then - begin - s := parse.Strings[i]; - s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); - repeat - j := Pos('addpage(''', s); - if Pos('googleusercontent', s) > 0 then - manager.container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ''','))) - else - manager.container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ');'))); - Delete(s, Pos('addpage(''', s), 16); - j := Pos('addpage(''', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMabunsImageURL: Boolean; + var + s: String; + j, i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := FillMangaSiteHost(MABUNS_ID, URL); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('addpage(''', parse[i]) > 0 then + begin + s := parse[i]; + s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); + repeat + j := Pos('addpage(''', s); + if Pos('googleusercontent', s) > 0 then + manager.container.PageLinks.Add( + EncodeUrl(GetString(s, 'addpage(''', ''','))) + else + manager.container.PageLinks.Add( + EncodeUrl(GetString(s, 'addpage(''', ');'))); + Delete(s, Pos('addpage(''', s), 16); + j := Pos('addpage(''', s); + until j = 0; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Mabuns/manga_information.inc b/baseunits/includes/Mabuns/manga_information.inc index 1e17240e6..13edbd1ba 100644 --- a/baseunits/includes/Mabuns/manga_information.inc +++ b/baseunits/includes/Mabuns/manga_information.inc @@ -1,92 +1,91 @@ - function GetMabunsInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MABUNS_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MABUNS_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('rel="image_src"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'href='))); - - // get title - if (Pos('Judul :', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - TrimRight(HTMLEntitiesFilter(StringFilter(GetString(parse.Strings[i] + '~!@', - 'Judul :', '~!@'))))); - - if (not isExtractChapter) and (Pos('Baca Online:', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('<a href', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[MABUNS_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('</table>', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get authors - if (i + 8 < parse.Count) and (Pos('Author :', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft( - TrimRight(GetString(parse.Strings[i] + '~!@', 'Author :', '~!@'))); - - // get artists - if (i + 1 < parse.Count) and (Pos('Artist :', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft( - TrimRight(GetString(parse.Strings[i] + '~!@', 'Artist :', '~!@'))); - - // get genres - if (Pos('Genre :', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := TrimLeft( - TrimRight(GetString(parse.Strings[i] + '~!@', 'Genre :', '~!@'))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetMabunsInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(MABUNS_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[MABUNS_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('rel="image_src"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'href')); + + // get title + if (Pos('Judul :', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft( + TrimRight(HTMLEntitiesFilter(StringFilter(GetString(parse[i] + '~!@', + 'Judul :', '~!@'))))); + + if (not isExtractChapter) and (Pos('Baca Online:', parse[i]) > 0) then + isExtractChapter := True; + + // get chapter name and links + if (isExtractChapter) and + (Pos('<a href', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[MABUNS_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + + if (isExtractChapter) and + (Pos('</table>', parse[i]) > 0) then + isExtractChapter := False; + + // get authors + if (i + 8 < parse.Count) and (Pos('Author :', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft( + TrimRight(GetString(parse[i] + '~!@', 'Author :', '~!@'))); + + // get artists + if (i + 1 < parse.Count) and (Pos('Artist :', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft( + TrimRight(GetString(parse[i] + '~!@', 'Artist :', '~!@'))); + + // get genres + if (Pos('Genre :', parse[i]) <> 0) then + begin + mangaInfo.genres := TrimLeft( + TrimRight(GetString(parse[i] + '~!@', 'Genre :', '~!@'))); + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Mabuns/names_and_links.inc b/baseunits/includes/Mabuns/names_and_links.inc index 8ed618b12..afe0ab886 100644 --- a/baseunits/includes/Mabuns/names_and_links.inc +++ b/baseunits/includes/Mabuns/names_and_links.inc @@ -1,38 +1,37 @@ - function MabunsGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MABUNS_ID, 1] + MABUNS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="manga"', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 3]))); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetAttributeValue(GetTagAttribute( - parse.Strings[i + 6], 'href=')), - WebsiteRoots[MABUNS_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; + function MabunsGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MABUNS_ID, 1] + MABUNS_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="manga"', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); + names.Add(HTMLEntitiesFilter(s)); + s := StringReplace(GetVal(parse[i + 6], 'href'), + WebsiteRoots[MABUNS_ID, 1], '', []); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Manga24h/directory_page_number.inc b/baseunits/includes/Manga24h/directory_page_number.inc index 7372f7306..74fdc1a03 100644 --- a/baseunits/includes/Manga24h/directory_page_number.inc +++ b/baseunits/includes/Manga24h/directory_page_number.inc @@ -1,36 +1,36 @@ - function GetManga24hDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + - MANGA24H_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('Pages (', parse.Strings[i]) > 0) then - begin - s := GetString(parse.Strings[i], 'Pages (', ')'); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetManga24hDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + + MANGA24H_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('Pages (', parse[i]) > 0) then + begin + s := GetString(parse[i], 'Pages (', ')'); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Manga24h/image_url.inc b/baseunits/includes/Manga24h/image_url.inc index 32b6c4387..8b1038cf9 100644 --- a/baseunits/includes/Manga24h/image_url.inc +++ b/baseunits/includes/Manga24h/image_url.inc @@ -1,32 +1,31 @@ - function GetManga24hImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGA24H_ID, URL), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'img') and - (Pos('style="border:3px', parse.Strings[i]) <> 0) then - // (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'm_picture') then - begin - manager.container.PageLinks.Add(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - end; - end; - end; - parse.Free; - l.Free; - end; + function GetManga24hImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(MANGA24H_ID, URL), + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'img') and + (Pos('style="border:3px', parse[i]) <> 0) then + // (GetVal(parse[i], 'class') = 'm_picture') then + begin + manager.container.PageLinks.Add(GetVal(parse[i], 'src')); + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Manga24h/manga_information.inc b/baseunits/includes/Manga24h/manga_information.inc index 67b26b44a..569a811b4 100644 --- a/baseunits/includes/Manga24h/manga_information.inc +++ b/baseunits/includes/Manga24h/manga_information.inc @@ -1,138 +1,136 @@ - function GetManga24hInfoFromURL: Byte; - var - // patchURL, - s: String; - i, j: Cardinal; - isExtractChapters: Boolean = False; - isExtractSummary: Boolean = False; - begin - // patchURL:= UTF8ToANSI(URL); - // Insert('comics/', patchURL, 10); - mangaInfo.url := FillMangaSiteHost(MANGA24H_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGA24H_ID, 0]; - mangaInfo.summary := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover link - if (Pos('class="img-rounded', parse.Strings[i]) > 0) then - begin - mangaInfo.coverLink := EncodeURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - s := mangaInfo.coverLink; - end; - - // get summary - if (Pos('"clearfix"', parse.Strings[i]) > 0) and - (Pos('<p>', parse.Strings[i + 3]) > 0) then - begin - j := i + 5; - mangaInfo.summary := ''; - while (Pos('$(document).ready(function()', parse.Strings[j]) = 0) and - (j < parse.Count - 1) do - begin - s := parse.Strings[j]; - if (Length(s) > 0) and (s[1] <> '<') then - begin - parse.Strings[j] := StringFilter(HTMLEntitiesFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + - StringFilter(TrimRight(TrimLeft(parse.Strings[j]))); - end; - Inc(j); - end; - end; - - if (Pos('<tbody>', parse.Strings[i]) <> 0) and (not isExtractSummary) then - isExtractChapters := True; - - if (Pos('</tbody>', parse.Strings[i]) <> 0) and (isExtractSummary) then - isExtractChapters := False; - - - // get chapter name and links - if (isExtractChapters) and - (Pos('<td>', parse.Strings[i]) <> 0) and - (GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')) <> '') and - (Pos('</a>', parse.Strings[i + 3]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - CorrectURL('/' + StringReplace(GetAttributeValue( - GetTagAttribute(parse.Strings[i + 1], 'href=')), WebsiteRoots[MANGA24H_ID, 1], - '', [rfReplaceAll]))); - parse.Strings[i + 2] := HTMLEntitiesFilter(parse.Strings[i + 2]); - parse.Strings[i + 2] := StringReplace(parse.Strings[i + 2], #10, '', [rfReplaceAll]); - parse.Strings[i + 2] := StringReplace(parse.Strings[i + 2], #13, '', [rfReplaceAll]); - parse.Strings[i + 2] := TrimLeft(parse.Strings[i + 2]); - mangaInfo.chapterName.Add( - StringFilter(TrimRight(RemoveSymbols(parse.Strings[i + 2])))); - end; - - // get title - if (Pos('<title>', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - StringFilter(GetString('~!@' + parse.Strings[i + 1], '~!@', ' - Truyen Tranh Online'))); - - // get authors - if (Pos('Tác giả :', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(StringFilter(parse.Strings[i + 3])); - - // get artists - if (Pos('Họa sỹ :', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(StringFilter(parse.Strings[i + 3])); - - // get genres - if (Pos('Thể loại :', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := ''; - for j := 0 to 37 do - if Pos(LowerCase(defaultGenres[j]), LowerCase(parse.Strings[i + 4])) <> 0 then - mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); - end; - - // get status - if (Pos('Tình Trạng:', parse.Strings[i]) <> 0) then - begin - if Pos('Hoàn Thành', parse.Strings[i + 4]) <> 0 then - mangaInfo.status := '0' // ongoing - else - mangaInfo.status := '1'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetManga24hInfoFromURL: Byte; + var + // patchURL, + s: String; + i, j: Cardinal; + isExtractChapters: Boolean = False; + isExtractSummary: Boolean = False; + begin + // patchURL:= UTF8ToANSI(URL); + // Insert('comics/', patchURL, 10); + mangaInfo.url := FillMangaSiteHost(MANGA24H_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[MANGA24H_ID, 0]; + mangaInfo.summary := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover link + if (Pos('class="img-rounded', parse[i]) > 0) then + begin + mangaInfo.coverLink := EncodeURL(GetVal(parse[i], 'src')); + s := mangaInfo.coverLink; + end; + + // get summary + if (Pos('"clearfix"', parse[i]) > 0) and + (Pos('<p>', parse[i + 3]) > 0) then + begin + j := i + 5; + mangaInfo.summary := ''; + while (Pos('$(document).ready(function()', parse[j]) = 0) and + (j < parse.Count - 1) do + begin + s := parse[j]; + if (Length(s) > 0) and (s[1] <> '<') then + begin + parse[j] := StringFilter(HTMLEntitiesFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + + StringFilter(TrimRight(TrimLeft(parse[j]))); + end; + Inc(j); + end; + end; + + if (Pos('<tbody>', parse[i]) <> 0) and (not isExtractSummary) then + isExtractChapters := True; + + if (Pos('</tbody>', parse[i]) <> 0) and (isExtractSummary) then + isExtractChapters := False; + + + // get chapter name and links + if (isExtractChapters) and + (Pos('<td>', parse[i]) <> 0) and + (GetVal(parse[i + 1], 'href') <> '') and + (Pos('</a>', parse[i + 3]) <> 0) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add( + CorrectURL('/' + StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGA24H_ID, 1], + '', [rfReplaceAll]))); + parse[i + 2] := HTMLEntitiesFilter(parse[i + 2]); + parse[i + 2] := StringReplace(parse[i + 2], #10, '', [rfReplaceAll]); + parse[i + 2] := StringReplace(parse[i + 2], #13, '', [rfReplaceAll]); + parse[i + 2] := TrimLeft(parse[i + 2]); + mangaInfo.chapterName.Add( + StringFilter(TrimRight(RemoveSymbols(parse[i + 2])))); + end; + + // get title + if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft( + StringFilter(GetString('~!@' + parse[i + 1], '~!@', ' - Truyen Tranh Online'))); + + // get authors + if (Pos('Tác giả :', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(StringFilter(parse[i + 3])); + + // get artists + if (Pos('Họa sỹ :', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(StringFilter(parse[i + 3])); + + // get genres + if (Pos('Thể loại :', parse[i]) <> 0) then + begin + mangaInfo.genres := ''; + for j := 0 to 37 do + if Pos(LowerCase(defaultGenres[j]), LowerCase(parse[i + 4])) <> 0 then + mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); + end; + + // get status + if (Pos('Tình Trạng:', parse[i]) <> 0) then + begin + if Pos('Hoàn Thành', parse[i + 4]) <> 0 then + mangaInfo.status := '0' // ongoing + else + mangaInfo.status := '1'; // completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterName.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterName.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Manga24h/names_and_links.inc b/baseunits/includes/Manga24h/names_and_links.inc index c750fe4bd..536dcc856 100644 --- a/baseunits/includes/Manga24h/names_and_links.inc +++ b/baseunits/includes/Manga24h/names_and_links.inc @@ -1,39 +1,38 @@ - function Manga24hGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + - MANGA24H_BROWSER + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 3 do - begin - if (Pos('<b>', parse.Strings[i]) <> 0) and - (Pos('</b>', parse.Strings[i + 2]) <> 0) and - (GetAttributeValue(GetTagAttribute(parse.Strings[i - 1], 'href=')) <> '') then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(s); - links.Add('/' + StringReplace(GetAttributeValue( - GetTagAttribute(parse.Strings[i - 1], 'href=')), WebsiteRoots[MANGA24H_ID, 1], '', [])); - end; - end; - Source.Free; + function Manga24hGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + + MANGA24H_BROWSER + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 3 do + begin + if (Pos('<b>', parse[i]) <> 0) and + (Pos('</b>', parse[i + 2]) <> 0) and + (GetVal(parse[i - 1], 'href') <> '') then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(s); + links.Add('/' + StringReplace(GetVal(parse[i - 1], 'href'), WebsiteRoots[MANGA24H_ID, 1], '', [])); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaAe/chapter_page_number.inc b/baseunits/includes/MangaAe/chapter_page_number.inc index d89eef3fe..5e1a5db1f 100644 --- a/baseunits/includes/MangaAe/chapter_page_number.inc +++ b/baseunits/includes/MangaAe/chapter_page_number.inc @@ -1,39 +1,39 @@ - function GetMangaAePageNumber: Boolean; - var - s: String; - i, p: LongInt; - l: TStringList; - isExtractPage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) <> 0) and (Pos('class="active"', parse[i]) <> 0) then - isExtractPage := True; - if isExtractPage and (Pos('</div', parse[i]) <> 0) then - Break; - if isExtractPage and - (Pos('<a', parse[i]) <> 0) and (Pos(URL, parse[i]) <> 0) then - begin - p := StrToIntDef(Trim(parse[i + 1]), 0); - if p > manager.container.PageNumber then - manager.container.PageNumber := p; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaAePageNumber: Boolean; + var + s: String; + i, p: LongInt; + l: TStringList; + isExtractPage: Boolean = False; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (Pos('<a', parse[i]) <> 0) and (Pos('class="active"', parse[i]) <> 0) then + isExtractPage := True; + if isExtractPage and (Pos('</div', parse[i]) <> 0) then + Break; + if isExtractPage and + (Pos('<a', parse[i]) <> 0) and (Pos(URL, parse[i]) <> 0) then + begin + p := StrToIntDef(Trim(parse[i + 1]), 0); + if p > manager.container.PageNumber then + manager.container.PageNumber := p; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaAe/directory_page_number.inc b/baseunits/includes/MangaAe/directory_page_number.inc index b660d8dd7..f4d105735 100644 --- a/baseunits/includes/MangaAe/directory_page_number.inc +++ b/baseunits/includes/MangaAe/directory_page_number.inc @@ -1,37 +1,37 @@ - function GetMangaAeDirectoryPageNumber: Byte; - var - i, p: LongInt; - isExtractPage: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + MANGAAE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Page := 1; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (Pos('<div', parse[i]) <> 0 ) and (Pos('class="pagination', parse[i]) <> 0) then - isExtractPage := True; - if isExtractPage and (Pos('</div', parse[i]) <> 0) then - Break; - if isExtractPage and (Pos('<a', parse[i]) <> 0) then - begin - s := ReplaceRegExpr('^.*/page\:(\d+)$', GetVal(parse[i], 'href'), '$1', True); - p := StrToIntDef(s, 0); - if p > Page then - Page := p; - end; - end; - Result := NO_ERROR; - Source.Free; - end; + function GetMangaAeDirectoryPageNumber: Byte; + var + i, p: LongInt; + isExtractPage: Boolean = False; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + MANGAAE_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Page := 1; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + begin + if (Pos('<div', parse[i]) <> 0 ) and (Pos('class="pagination', parse[i]) <> 0) then + isExtractPage := True; + if isExtractPage and (Pos('</div', parse[i]) <> 0) then + Break; + if isExtractPage and (Pos('<a', parse[i]) <> 0) then + begin + s := ReplaceRegExpr('^.*/page\:(\d+)$', GetVal(parse[i], 'href'), '$1', True); + p := StrToIntDef(s, 0); + if p > Page then + Page := p; + end; + end; + Result := NO_ERROR; + Source.Free; + end; diff --git a/baseunits/includes/MangaAe/image_url.inc b/baseunits/includes/MangaAe/image_url.inc index 56cb354e8..a41ccdea2 100644 --- a/baseunits/includes/MangaAe/image_url.inc +++ b/baseunits/includes/MangaAe/image_url.inc @@ -1,35 +1,35 @@ - function GetMangaAeImageURL: Boolean; - var - s: String; - i: LongInt; - l: TStringList; - isImageURL: Boolean = False; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('id="showchaptercontainer', parse[i]) <> 0) then - isImageURL := True; - if isImageURL and (Pos('<img', parse[i]) <> 0) then - begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaAeImageURL: Boolean; + var + s: String; + i: LongInt; + l: TStringList; + isImageURL: Boolean = False; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (Pos('id="showchaptercontainer', parse[i]) <> 0) then + isImageURL := True; + if isImageURL and (Pos('<img', parse[i]) <> 0) then + begin + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaAe/manga_information.inc b/baseunits/includes/MangaAe/manga_information.inc index 54ebc1068..1142484b1 100644 --- a/baseunits/includes/MangaAe/manga_information.inc +++ b/baseunits/includes/MangaAe/manga_information.inc @@ -1,117 +1,117 @@ - function GetMangaAeInfoFromURL: Byte; - var - i: LongInt; - regx: TRegExpr; - isExtractChapter: Boolean = False; - isExtractGenres : Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAAE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAAE_ID, URL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.genres := ''; - - regx := TRegExpr.Create; - try - regx.Expression := '/1/?$'; - for i := 0 to parse.Count - 1 do - begin - // cover - if (Pos('<img', parse[i]) <> 0) and (Pos('class="manga-cover', parse[i]) <> 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // title - if (mangaInfo.title = '') and (Pos('class="EnglishName', parse[i]) <> 0) then - begin - parse[i] := Trim(parse[i + 1]); - if Length(parse[i]) > 2 then - begin - if (parse[i][1] = '(') and (parse[i][Length(parse[i])] = ')') then - parse[i] := Copy(parse[i], 2, Length(parse[i]) - 2); - end; - mangaInfo.title := Trim(parse[i]); - end; - - // author - if (Pos('class="manga-details-author', parse[i]) <> 0) then - if (Pos('<', parse[i + 21]) = 0) then - mangaInfo.authors := Trim(parse[i + 21]); - - // status - if (i + 4 < parse.Count) and - (Pos('الحالة :', parse.Strings[i]) <> 0) and - (Pos('</h3', parse.Strings[i + 1]) <> 0) then - begin - if (Pos('مستمرة', parse.Strings[i + 4]) <> 0) then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - // genres - if Pos('التصنيف:', parse[i]) <> 0 then - isExtractGenres := True; - if isExtractChapter and (Pos('</ul', parse[i]) <> 0) then - isExtractGenres := False; - if isExtractGenres and - (Pos('<a', parse[i]) <> 0) and (Pos('/manga/cats', parse[i]) <> 0) then - begin - if mangaInfo.genres <> '' then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]) - else - mangaInfo.genres := Trim(parse[i + 1]); - end; - - // summary - if (Pos('نبذة عن المانجا', parse[i]) <> 0) and (Pos('</h3', parse[i + 1]) <> 0) then - if Pos('<', parse[i + 4]) = 0 then - mangaInfo.summary := CommonStringFilter(parse[i + 4]); - - //chapters - if (Pos('<ul', parse[i]) <> 0) and (Pos('class="new-manga-chapters', parse[i]) <> 0) then - isExtractChapter := True; - if isExtractChapter and (Pos('</ul', parse[i]) <> 0) then - isExtractChapter := False; - if isExtractChapter and - (Pos('<a', parse[i]) <> 0) and (Pos('class="chapter', parse[i]) <> 0) then - begin - parse[i] := GetVal(parse[i], 'href'); - if regx.Exec(parse[i]) then - parse[i] := regx.Replace(parse[i], '', False); - mangaInfo.chapterLinks.Add(parse[i]); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - finally - regx.Free; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - - Result := NO_ERROR; - end; + function GetMangaAeInfoFromURL: Byte; + var + i: LongInt; + regx: TRegExpr; + isExtractChapter: Boolean = False; + isExtractGenres : Boolean = False; + begin + mangaInfo.website := WebsiteRoots[MANGAAE_ID, 0]; + mangaInfo.url := FillMangaSiteHost(MANGAAE_ID, URL); + if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + Source.Free; + + if parse.Count = 0 then + Exit; + + mangaInfo.genres := ''; + + regx := TRegExpr.Create; + try + regx.Expression := '/1/?$'; + for i := 0 to parse.Count - 1 do + begin + // cover + if (Pos('<img', parse[i]) <> 0) and (Pos('class="manga-cover', parse[i]) <> 0) then + mangaInfo.coverLink := GetVal(parse[i], 'src'); + + // title + if (mangaInfo.title = '') and (Pos('class="EnglishName', parse[i]) <> 0) then + begin + parse[i] := Trim(parse[i + 1]); + if Length(parse[i]) > 2 then + begin + if (parse[i][1] = '(') and (parse[i][Length(parse[i])] = ')') then + parse[i] := Copy(parse[i], 2, Length(parse[i]) - 2); + end; + mangaInfo.title := Trim(parse[i]); + end; + + // author + if (Pos('class="manga-details-author', parse[i]) <> 0) then + if (Pos('<', parse[i + 21]) = 0) then + mangaInfo.authors := Trim(parse[i + 21]); + + // status + if (i + 4 < parse.Count) and + (Pos('الحالة :', parse[i]) <> 0) and + (Pos('</h3', parse[i + 1]) <> 0) then + begin + if (Pos('مستمرة', parse[i + 4]) <> 0) then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + + // genres + if Pos('التصنيف:', parse[i]) <> 0 then + isExtractGenres := True; + if isExtractChapter and (Pos('</ul', parse[i]) <> 0) then + isExtractGenres := False; + if isExtractGenres and + (Pos('<a', parse[i]) <> 0) and (Pos('/manga/cats', parse[i]) <> 0) then + begin + if mangaInfo.genres <> '' then + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]) + else + mangaInfo.genres := Trim(parse[i + 1]); + end; + + // summary + if (Pos('نبذة عن المانجا', parse[i]) <> 0) and (Pos('</h3', parse[i + 1]) <> 0) then + if Pos('<', parse[i + 4]) = 0 then + mangaInfo.summary := CommonStringFilter(parse[i + 4]); + + //chapters + if (Pos('<ul', parse[i]) <> 0) and (Pos('class="new-manga-chapters', parse[i]) <> 0) then + isExtractChapter := True; + if isExtractChapter and (Pos('</ul', parse[i]) <> 0) then + isExtractChapter := False; + if isExtractChapter and + (Pos('<a', parse[i]) <> 0) and (Pos('class="chapter', parse[i]) <> 0) then + begin + parse[i] := GetVal(parse[i], 'href'); + if regx.Exec(parse[i]) then + parse[i] := regx.Replace(parse[i], '', False); + mangaInfo.chapterLinks.Add(parse[i]); + mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); + end; + end; + finally + regx.Free; + end; + + //invert chapters + if mangaInfo.chapterLinks.Count > 1 then + begin + InvertStrings(mangaInfo.chapterName); + InvertStrings(mangaInfo.chapterLinks); + end; + + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaAe/names_and_links.inc b/baseunits/includes/MangaAe/names_and_links.inc index b8d74874c..37ff3f4ec 100644 --- a/baseunits/includes/MangaAe/names_and_links.inc +++ b/baseunits/includes/MangaAe/names_and_links.inc @@ -1,50 +1,50 @@ - function MangaAeGetNamesAndLinks: Byte; - var - i: LongInt; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + - MANGAAE_BROWSER + 'page:' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '[^/]*\w+\.\w+(\:\d+)?/.+'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) <> 0) and (Pos('class="manga"', parse[i]) <> 0) then - begin - s := GetVal(parse[i], 'href'); - if regx.Exec(s) then - begin - links.Add(s); - names.Add(CommonStringFilter(parse[i + 1])); - end; - end; - end; - finally - regx.Free; - end; - end; - Result := NO_ERROR; - Source.Free; - end; + function MangaAeGetNamesAndLinks: Byte; + var + i: LongInt; + s: String; + regx: TRegExpr; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + + MANGAAE_BROWSER + 'page:' + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + if parse.Count > 0 then + begin + regx := TRegExpr.Create; + try + regx.Expression := '[^/]*\w+\.\w+(\:\d+)?/.+'; + for i := 0 to parse.Count - 1 do + begin + if (Pos('<a', parse[i]) <> 0) and (Pos('class="manga"', parse[i]) <> 0) then + begin + s := GetVal(parse[i], 'href'); + if regx.Exec(s) then + begin + links.Add(s); + names.Add(CommonStringFilter(parse[i + 1])); + end; + end; + end; + finally + regx.Free; + end; + end; + Result := NO_ERROR; + Source.Free; + end; diff --git a/baseunits/includes/MangaAr/chapter_page_number.inc b/baseunits/includes/MangaAr/chapter_page_number.inc index 32ba05c07..9e9082bc1 100644 --- a/baseunits/includes/MangaAr/chapter_page_number.inc +++ b/baseunits/includes/MangaAr/chapter_page_number.inc @@ -1,34 +1,34 @@ - function GetMangaArPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - - if l.Count > 0 then - try - for i := 0 to l.Count - 1 do - if Pos('var pages = [', l[i]) > 0 then - begin - s := l[i]; - s := StringReplace(s, 'var pages =', '', [rfIgnoreCase]); - s := Trim(TrimChar(s, [';', ' '])); - Break; - end; - if s <> '' then - begin - manager.container.PageLinks.Clear; - ParseJSONArray(s, 'url', manager.container.PageLinks); - manager.container.PageNumber := manager.container.PageLinks.Count; - end; - finally - parse.Free; - l.Free; - end; - end; + function GetMangaArPageNumber: Boolean; + var + s: String; + i: Integer; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + + if l.Count > 0 then + try + for i := 0 to l.Count - 1 do + if Pos('var pages = [', l[i]) > 0 then + begin + s := l[i]; + s := StringReplace(s, 'var pages =', '', [rfIgnoreCase]); + s := Trim(TrimChar(s, [';', ' '])); + Break; + end; + if s <> '' then + begin + manager.container.PageLinks.Clear; + ParseJSONArray(s, 'url', manager.container.PageLinks); + manager.container.PageNumber := manager.container.PageLinks.Count; + end; + finally + parse.Free; + l.Free; + end; + end; diff --git a/baseunits/includes/MangaAr/image_url.inc b/baseunits/includes/MangaAr/image_url.inc index 31d3dc71c..93cec135d 100644 --- a/baseunits/includes/MangaAr/image_url.inc +++ b/baseunits/includes/MangaAr/image_url.inc @@ -1,48 +1,48 @@ - function GetMangaArImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l, ts: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - manager.container.PageLinks.Clear; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('var pages =', parse.Strings[i]) > 0) then - begin - ts := TStringList.Create; - s := GetString(parse.Strings[i], '[{', '}];'); - s := StringReplace(s, '":', '",', [rfReplaceAll]); - s := StringReplace(s, '\', '', [rfReplaceAll]); - ts.DelimitedText := s; - for j := 0 to ts.Count - 1 do - begin - if (Pos('url', ts.Strings[j]) > 0) then - begin - s := ts.Strings[j + 1]; - s := 'http' + GetString(s, 'http', '?w='); //original resolution - manager.container.PageLinks.Add(s); - end; - end; - ts.Free; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaArImageURL: Boolean; + var + s: String; + j, i: Cardinal; + l, ts: TStringList; + begin + l := TStringList.Create; + s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + manager.container.PageLinks.Clear; + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (Pos('var pages =', parse[i]) > 0) then + begin + ts := TStringList.Create; + s := GetString(parse[i], '[{', '}];'); + s := StringReplace(s, '":', '",', [rfReplaceAll]); + s := StringReplace(s, '\', '', [rfReplaceAll]); + ts.DelimitedText := s; + for j := 0 to ts.Count - 1 do + begin + if (Pos('url', ts[j]) > 0) then + begin + s := ts[j + 1]; + s := 'http' + GetString(s, 'http', '?w='); //original resolution + manager.container.PageLinks.Add(s); + end; + end; + ts.Free; + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaAr/manga_information.inc b/baseunits/includes/MangaAr/manga_information.inc index 6c3585232..91bca2bbd 100644 --- a/baseunits/includes/MangaAr/manga_information.inc +++ b/baseunits/includes/MangaAr/manga_information.inc @@ -1,130 +1,129 @@ - function GetMangaArInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAAR_ID, URL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAAR_ID, 0]; - - mangaInfo.numChapter := 0; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class=" thumbnail"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := - CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i + 2], 'src='))); - - // get summary - if (i + 4 < parse.Count) and (Pos('القصة', parse.Strings[i]) > 0) then - if (Pos('</span>', parse.Strings[i - 1]) > 0) and - (Pos('</dt>', parse.Strings[i + 1]) > 0) then - begin - mangaInfo.summary := ''; - j := i + 4; - while (j < parse.Count) and (not (Pos('</dd>', parse.Strings[j]) > 0)) do - begin - s := Trim(parse.Strings[j]); - s := HTMLEntitiesFilter(StringFilter(s)); - mangaInfo.summary := mangaInfo.summary + s; - Inc(j); - end; - mangaInfo.summary := StringReplace(mangaInfo.summary, '<p>', - '\r\n', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '</p>', '', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', - '\r\n', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', - '\r\n', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', - '\r\n', [rfReplaceAll]); - end; - - // get title - if (mangaInfo.title = '') and - (Pos('http-equiv="description" content="', parse.Strings[i]) <> 0) then - mangaInfo.title := Trim(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'content='))); - - // get chapter name and links - if (Pos('class="tit ajaxify {title:', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse.Strings[i + 1])); - s := StringFilter(HTMLEntitiesFilter(s)); - mangaInfo.chapterName.Add(s); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('اسم المؤلف', parse.Strings[i]) > 0) then - if (Pos('</span>', parse.Strings[i - 1]) > 0) and - (Pos('</dt>', parse.Strings[i + 1]) > 0) then - mangaInfo.authors := Trim(parse.Strings[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('اسم الرسام', parse.Strings[i]) > 0) then - if (Pos('</span>', parse.Strings[i - 1]) > 0) and - (Pos('</dt>', parse.Strings[i + 1]) > 0) then - mangaInfo.artists := Trim(parse.Strings[i + 4]); - - // get genres - if (i + 4 < parse.Count) and (Pos('التصنيف', parse.Strings[i]) > 0) then - if (Pos('</span>', parse.Strings[i - 1]) > 0) and - (Pos('</dt>', parse.Strings[i + 1]) > 0) then - begin - mangaInfo.genres := Trim(parse.Strings[i + 4]); - mangaInfo.genres := StringReplace(mangaInfo.genres, sLineBreak, - '', [rfReplaceAll]); - mangaInfo.genres := StringReplace(mangaInfo.genres, ' ', '', [rfReplaceAll]); - mangaInfo.genres := StringReplace(mangaInfo.genres, ',', ', ', [rfReplaceAll]); - end; - - // get status - if (i + 4 < parse.Count) and (Pos('حالة الترجمة', parse.Strings[i]) > 0) then - if (Pos('</span>', parse.Strings[i - 1]) > 0) and - (Pos('</dt>', parse.Strings[i + 1]) > 0) then - begin - if Trim(parse.Strings[i + 4]) = 'مكتملة' then - mangaInfo.status := '1' // Ongoing - else - mangaInfo.status := '0'; // Completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetMangaArInfoFromURL: Byte; + var + s: String; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(MANGAAR_ID, URL); + if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[MANGAAR_ID, 0]; + + mangaInfo.numChapter := 0; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('class=" thumbnail"', parse[i]) > 0) then + mangaInfo.coverLink := + CorrectURL(GetVal(parse[i + 2], 'src')); + + // get summary + if (i + 4 < parse.Count) and (Pos('القصة', parse[i]) > 0) then + if (Pos('</span>', parse[i - 1]) > 0) and + (Pos('</dt>', parse[i + 1]) > 0) then + begin + mangaInfo.summary := ''; + j := i + 4; + while (j < parse.Count) and (not (Pos('</dd>', parse[j]) > 0)) do + begin + s := Trim(parse[j]); + s := HTMLEntitiesFilter(StringFilter(s)); + mangaInfo.summary := mangaInfo.summary + s; + Inc(j); + end; + mangaInfo.summary := StringReplace(mangaInfo.summary, '<p>', + '\r\n', [rfReplaceAll]); + mangaInfo.summary := StringReplace(mangaInfo.summary, '</p>', '', [rfReplaceAll]); + mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', + '\r\n', [rfReplaceAll]); + mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', + '\r\n', [rfReplaceAll]); + mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', + '\r\n', [rfReplaceAll]); + end; + + // get title + if (mangaInfo.title = '') and + (Pos('http-equiv="description" content="', parse[i]) <> 0) then + mangaInfo.title := Trim(GetVal(parse[i], 'content')); + + // get chapter name and links + if (Pos('class="tit ajaxify {title:', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := GetVal(parse[i], 'href'); + s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(Trim(parse[i + 1])); + s := StringFilter(HTMLEntitiesFilter(s)); + mangaInfo.chapterName.Add(s); + end; + + // get authors + if (i + 4 < parse.Count) and (Pos('اسم المؤلف', parse[i]) > 0) then + if (Pos('</span>', parse[i - 1]) > 0) and + (Pos('</dt>', parse[i + 1]) > 0) then + mangaInfo.authors := Trim(parse[i + 4]); + + // get artists + if (i + 4 < parse.Count) and (Pos('اسم الرسام', parse[i]) > 0) then + if (Pos('</span>', parse[i - 1]) > 0) and + (Pos('</dt>', parse[i + 1]) > 0) then + mangaInfo.artists := Trim(parse[i + 4]); + + // get genres + if (i + 4 < parse.Count) and (Pos('التصنيف', parse[i]) > 0) then + if (Pos('</span>', parse[i - 1]) > 0) and + (Pos('</dt>', parse[i + 1]) > 0) then + begin + mangaInfo.genres := Trim(parse[i + 4]); + mangaInfo.genres := StringReplace(mangaInfo.genres, sLineBreak, + '', [rfReplaceAll]); + mangaInfo.genres := StringReplace(mangaInfo.genres, ' ', '', [rfReplaceAll]); + mangaInfo.genres := StringReplace(mangaInfo.genres, ',', ', ', [rfReplaceAll]); + end; + + // get status + if (i + 4 < parse.Count) and (Pos('حالة الترجمة', parse[i]) > 0) then + if (Pos('</span>', parse[i - 1]) > 0) and + (Pos('</dt>', parse[i + 1]) > 0) then + begin + if Trim(parse[i + 4]) = 'مكتملة' then + mangaInfo.status := '1' // Ongoing + else + mangaInfo.status := '0'; // Completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaAr/names_and_links.inc b/baseunits/includes/MangaAr/names_and_links.inc index 03e7eba30..ff451e7b0 100644 --- a/baseunits/includes/MangaAr/names_and_links.inc +++ b/baseunits/includes/MangaAr/names_and_links.inc @@ -1,45 +1,45 @@ - function MangaArGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - isExtractMangaList: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAR_ID, 1] + MANGAAR_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<tbody>', parse.Strings[i]) > 0) then - isExtractMangaList := True; - if (Pos('</tbody>', parse.Strings[i]) > 0) then - begin - isExtractMangaList := False; - Break; - end; - - if isExtractMangaList and (Pos('href=', parse.Strings[i]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); - links.Add(s); - s := Trim(StringFilter(parse.Strings[i + 1])); - s := HTMLEntitiesFilter(s); - names.Add(s); - end; - end; - end; - Source.Free; + function MangaArGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + isExtractMangaList: Boolean = False; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAAR_ID, 1] + MANGAAR_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (Pos('<tbody>', parse[i]) > 0) then + isExtractMangaList := True; + if (Pos('</tbody>', parse[i]) > 0) then + begin + isExtractMangaList := False; + Break; + end; + + if isExtractMangaList and (Pos('href=', parse[i]) > 0) then + begin + s := GetVal(parse[i], 'href'); + s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); + links.Add(s); + s := Trim(StringFilter(parse[i + 1])); + s := HTMLEntitiesFilter(s); + names.Add(s); + end; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaEden/directory_page_number.inc b/baseunits/includes/MangaEden/directory_page_number.inc index 3814c9043..371881b37 100644 --- a/baseunits/includes/MangaEden/directory_page_number.inc +++ b/baseunits/includes/MangaEden/directory_page_number.inc @@ -1,36 +1,36 @@ - function GetMangaEdenDirectoryPageNumber(const root: String): Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), root + MANGAEDEN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse.Strings[i]) = 'span') and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'class=')) = 'next') then - begin - s := TrimRight(TrimLeft(parse.Strings[i - 4])); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetMangaEdenDirectoryPageNumber(const root: String): Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), root + MANGAEDEN_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'span') and + (GetVal(parse[i], 'class') = 'next') then + begin + s := TrimRight(TrimLeft(parse[i - 4])); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaEden/image_url.inc b/baseunits/includes/MangaEden/image_url.inc index 205aacece..7f09aa4e7 100644 --- a/baseunits/includes/MangaEden/image_url.inc +++ b/baseunits/includes/MangaEden/image_url.inc @@ -1,36 +1,36 @@ - function GetMangaEdenImageURL: Boolean; - var - s, imgURL: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - if manager.container.MangaSiteID = MANGAEDEN_ID then - s := FillMangaSiteHost(MANGAEDEN_ID, URL) + IntToStr(workCounter + 1) + '/' - else - s := FillMangaSiteHost(PERVEDEN_ID, URL) + IntToStr(workCounter + 1) + '/'; - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := parse.Count - 1 downto 0 do - if (Pos('"mainImg"', parse.Strings[i]) > 0) then - begin - imgURL := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - if Copy(imgURL, 1, 2) = '//' then - imgURL := 'http:' + imgURL; - manager.container.PageLinks.Strings[workCounter] := imgURL; - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaEdenImageURL: Boolean; + var + s, imgURL: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + if manager.container.MangaSiteID = MANGAEDEN_ID then + s := FillMangaSiteHost(MANGAEDEN_ID, URL) + IntToStr(workCounter + 1) + '/' + else + s := FillMangaSiteHost(PERVEDEN_ID, URL) + IntToStr(workCounter + 1) + '/'; + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := parse.Count - 1 downto 0 do + if (Pos('"mainImg"', parse[i]) > 0) then + begin + imgURL := GetVal(parse[i], 'src'); + if Copy(imgURL, 1, 2) = '//' then + imgURL := 'http:' + imgURL; + manager.container.PageLinks[workCounter] := imgURL; + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaEden/manga_information.inc b/baseunits/includes/MangaEden/manga_information.inc index ed050e745..87078618b 100644 --- a/baseunits/includes/MangaEden/manga_information.inc +++ b/baseunits/includes/MangaEden/manga_information.inc @@ -1,135 +1,134 @@ - function GetMangaEdenInfoFromURL(const root: String): Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - if Pos('http', LowerCase(URL)) = 0 then - mangaInfo.url := root + URL;// + '&confirm=yes'; - if Pos('/en-manga/', URL) > 0 then - mangaInfo.genres := 'English, ' - else - mangaInfo.genres := 'Italian, '; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - if root = WebsiteRoots[MANGAEDEN_ID, 1] then - mangaInfo.website := WebsiteRoots[MANGAEDEN_ID, 0] - else - mangaInfo.website := WebsiteRoots[PERVEDEN_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse.Strings[i]) = 'div') and - (Pos('class="mangaImage2"', parse.Strings[i]) > 0) then - begin - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i + 1], 'src='))); - if Copy(mangaInfo.coverLink, 1, 2) = '//' then - mangaInfo.coverLink := 'http:' + mangaInfo.coverLink; - end; - - // get summary - if (Pos('hr style="margin-top:0;', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 2; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if ((Pos('enIcon', parse.Strings[i]) <> 0) or (Pos('itIcon', parse.Strings[i]) <> 0)) and - (mangaInfo.title = '') then - begin - mangaInfo.title := StringFilter(TrimRight(TrimLeft(parse.Strings[i + 1]))); - mangaInfo.title := GetString('~!@' + mangaInfo.title, '~!@', ' Manga'); - end; - - // get chapter name and links - if (i + 7 < parse.Count) and (Pos('class="chapterLink"', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse.Strings[i], 'href="', '1/"'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 3]))) + - ' ' + RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 7]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 1 < parse.Count) and (Pos('/?author', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 1]); - - // get artists - if (i + 1 < parse.Count) and (Pos('/?artist', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 1]); - - // get genres - if (Pos('Genres', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('/?categories', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('<br />', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if parse.Strings[i] = 'Status' then - begin - if Pos('Ongoing', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetMangaEdenInfoFromURL(const root: String): Byte; + var + s: String; + isExtractSummary: Boolean = True; + isExtractGenres: Boolean = False; + i, j: Cardinal; + begin + if Pos('http', LowerCase(URL)) = 0 then + mangaInfo.url := root + URL;// + '&confirm=yes'; + if Pos('/en-manga/', URL) > 0 then + mangaInfo.genres := 'English, ' + else + mangaInfo.genres := 'Italian, '; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + if root = WebsiteRoots[MANGAEDEN_ID, 1] then + mangaInfo.website := WebsiteRoots[MANGAEDEN_ID, 0] + else + mangaInfo.website := WebsiteRoots[PERVEDEN_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (GetTagName(parse[i]) = 'div') and + (Pos('class="mangaImage2"', parse[i]) > 0) then + begin + mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 1], 'src')); + if Copy(mangaInfo.coverLink, 1, 2) = '//' then + mangaInfo.coverLink := 'http:' + mangaInfo.coverLink; + end; + + // get summary + if (Pos('hr style="margin-top:0;', parse[i]) <> 0) and + (isExtractSummary) then + begin + j := i + 2; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + isExtractSummary := False; + end; + + // get title + if ((Pos('enIcon', parse[i]) <> 0) or (Pos('itIcon', parse[i]) <> 0)) and + (mangaInfo.title = '') then + begin + mangaInfo.title := StringFilter(TrimRight(TrimLeft(parse[i + 1]))); + mangaInfo.title := GetString('~!@' + mangaInfo.title, '~!@', ' Manga'); + end; + + // get chapter name and links + if (i + 7 < parse.Count) and (Pos('class="chapterLink"', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := GetString(parse[i], 'href="', '1/"'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 3]))) + + ' ' + RemoveSymbols(TrimLeft(TrimRight(parse[i + 7]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + + // get authors + if (i + 1 < parse.Count) and (Pos('/?author', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(parse[i + 1]); + + // get artists + if (i + 1 < parse.Count) and (Pos('/?artist', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(parse[i + 1]); + + // get genres + if (Pos('Genres', parse[i]) <> 0) then + begin + isExtractGenres := True; + end; + + if isExtractGenres then + begin + if Pos('/?categories', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + TrimLeft(TrimRight(parse[i + 1])) + ', '; + if Pos('<br />', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if parse[i] = 'Status' then + begin + if Pos('Ongoing', parse[i + 2]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaEden/names_and_links.inc b/baseunits/includes/MangaEden/names_and_links.inc index 648ca9307..5cc8f82f0 100644 --- a/baseunits/includes/MangaEden/names_and_links.inc +++ b/baseunits/includes/MangaEden/names_and_links.inc @@ -1,39 +1,38 @@ - function MangaEdenGetNamesAndLinks(const root: String): Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), root + MANGAEDEN_BROWSER + '?page=' + - IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if ((Pos('class="openManga"', parse.Strings[i]) > 0) or - (Pos('class="closedManga"', parse.Strings[i]) > 0)) then - begin - Result := NO_ERROR; - s := TrimLeft(TrimRight(StringFilter(parse.Strings[i + 1]))); - names.Add(s); - links.Add(StringReplace(GetAttributeValue(GetTagAttribute( - parse.Strings[i], 'href=')), root, '', [])); - end; - end; - Source.Free; + function MangaEdenGetNamesAndLinks(const root: String): Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), root + MANGAEDEN_BROWSER + '?page=' + + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if ((Pos('class="openManga"', parse[i]) > 0) or + (Pos('class="closedManga"', parse[i]) > 0)) then + begin + Result := NO_ERROR; + s := TrimLeft(TrimRight(StringFilter(parse[i + 1]))); + names.Add(s); + links.Add(StringReplace(GetVal(parse[i], 'href'), root, '', [])); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaEsta/image_url.inc b/baseunits/includes/MangaEsta/image_url.inc index 44e57b0c0..1f8b2224b 100644 --- a/baseunits/includes/MangaEsta/image_url.inc +++ b/baseunits/includes/MangaEsta/image_url.inc @@ -1,43 +1,43 @@ - function GetMangaEstaImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAESTA_ID, URL); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('addpage(''', parse.Strings[i]) > 0 then - begin - s := parse.Strings[i]; - s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); - repeat - j := Pos('addpage(''', s); - if Pos('googleusercontent', s) > 0 then - manager.container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ''','))) - else - manager.container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ');'))); - Delete(s, Pos('addpage(''', s), 16); - j := Pos('addpage(''', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaEstaImageURL: Boolean; + var + s: String; + j, i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := FillMangaSiteHost(MANGAESTA_ID, URL); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('addpage(''', parse[i]) > 0 then + begin + s := parse[i]; + s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); + repeat + j := Pos('addpage(''', s); + if Pos('googleusercontent', s) > 0 then + manager.container.PageLinks.Add( + EncodeUrl(GetString(s, 'addpage(''', ''','))) + else + manager.container.PageLinks.Add( + EncodeUrl(GetString(s, 'addpage(''', ');'))); + Delete(s, Pos('addpage(''', s), 16); + j := Pos('addpage(''', s); + until j = 0; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaEsta/manga_information.inc b/baseunits/includes/MangaEsta/manga_information.inc index d18b973d1..fea20e879 100644 --- a/baseunits/includes/MangaEsta/manga_information.inc +++ b/baseunits/includes/MangaEsta/manga_information.inc @@ -1,116 +1,115 @@ - function GetMangaEstaInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAESTA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAESTA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('imageanchor="1"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'href='))); - - // get title - if (Pos('Nama :', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft(TrimRight(HTMLEntitiesFilter(parse.Strings[i + 2]))); - - if (not isExtractChapter) and (Pos('ONLINE INDONESIAN', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('href="http://www.mangaesta.net/', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[MANGAESTA_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class=''comments''', parse.Strings[i]) > 0) then - isExtractChapter := False; - - // get summary - if (Pos('Sinopsis :', parse.Strings[i]) <> 0) then - begin - j := i + 6; - while (j < parse.Count) and (Pos('</div>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 8 < parse.Count) and (Pos('Author :', parse.Strings[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - - // get artists - if (i + 1 < parse.Count) and (Pos('Artist :', parse.Strings[i]) <> 0) then - mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - - // get genres - if (Pos('Genre :', parse.Strings[i]) <> 0) then - begin - mangaInfo.genres := StringReplace( - StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))), ' |', ',', [rfReplaceAll]); - mangaInfo.genres := StringReplace(mangaInfo.genres, '|', ',', [rfReplaceAll]); - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status :', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetMangaEstaInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(MANGAESTA_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[MANGAESTA_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('imageanchor="1"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'href')); + + // get title + if (Pos('Nama :', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft(TrimRight(HTMLEntitiesFilter(parse[i + 2]))); + + if (not isExtractChapter) and (Pos('ONLINE INDONESIAN', parse[i]) > 0) then + isExtractChapter := True; + + // get chapter name and links + if (isExtractChapter) and + (Pos('href="http://www.mangaesta.net/', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[MANGAESTA_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + + if (isExtractChapter) and + (Pos('class=''comments''', parse[i]) > 0) then + isExtractChapter := False; + + // get summary + if (Pos('Sinopsis :', parse[i]) <> 0) then + begin + j := i + 6; + while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + end; + + // get authors + if (i + 8 < parse.Count) and (Pos('Author :', parse[i]) <> 0) then + mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); + + // get artists + if (i + 1 < parse.Count) and (Pos('Artist :', parse[i]) <> 0) then + mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); + + // get genres + if (Pos('Genre :', parse[i]) <> 0) then + begin + mangaInfo.genres := StringReplace( + StringFilter(TrimLeft(TrimRight(parse[i + 2]))), ' |', ',', [rfReplaceAll]); + mangaInfo.genres := StringReplace(mangaInfo.genres, '|', ',', [rfReplaceAll]); + end; + + // get status + if (i + 2 < parse.Count) and (Pos('Status :', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 2]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaEsta/names_and_links.inc b/baseunits/includes/MangaEsta/names_and_links.inc index cbdbdc0c1..b42a8e304 100644 --- a/baseunits/includes/MangaEsta/names_and_links.inc +++ b/baseunits/includes/MangaEsta/names_and_links.inc @@ -1,40 +1,39 @@ - function MangaEstaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAESTA_ID, 1] + - MANGAESTA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="gallery-icon"', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft( - TrimRight(GetAttributeValue(GetTagAttribute(parse.Strings[i + 3], 'title='))))); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetAttributeValue(GetTagAttribute( - parse.Strings[i + 2], 'href=')), - WebsiteRoots[MANGAESTA_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; + function MangaEstaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAESTA_ID, 1] + + MANGAESTA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="gallery-icon"', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft( + TrimRight(GetVal(parse[i + 3], 'title')))); + names.Add(HTMLEntitiesFilter(s)); + s := StringReplace(GetVal(parse[i + 2], 'href'), + WebsiteRoots[MANGAESTA_ID, 1], '', []); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaFrame/chapter_page_number.inc b/baseunits/includes/MangaFrame/chapter_page_number.inc index 129ec0307..068eba0c2 100644 --- a/baseunits/includes/MangaFrame/chapter_page_number.inc +++ b/baseunits/includes/MangaFrame/chapter_page_number.inc @@ -1,38 +1,38 @@ - function GetMangaFramePageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - isExtractPageNumber: Boolean = False; - begin - manager.container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAFRAME_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - l.Text := FixHTMLTagQuote(l.Text); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="tbtitle dropdown_parent dropdown_right"', parse[i]) > 0 then - isExtractPageNumber := True; - if isExtractPageNumber and (Pos('</ul', parse[i]) > 0) then - begin - isExtractPageNumber := False; - Break; - end; - if isExtractPageNumber and (Pos('<a', parse[i]) > 0) then - Inc(manager.container.PageNumber); - end; - end; - parse.Free; - end; + function GetMangaFramePageNumber: Boolean; + var + i: Integer; + l: TStringList; + s: String; + isExtractPageNumber: Boolean = False; + begin + manager.container.PageNumber := 0; + l := TStringList.Create; + parse := TStringList.Create; + s := FillMangaSiteHost(MANGAFRAME_ID, URL); + Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + + l.Text := FixHTMLTagQuote(l.Text); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + l.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if Pos('class="tbtitle dropdown_parent dropdown_right"', parse[i]) > 0 then + isExtractPageNumber := True; + if isExtractPageNumber and (Pos('</ul', parse[i]) > 0) then + begin + isExtractPageNumber := False; + Break; + end; + if isExtractPageNumber and (Pos('<a', parse[i]) > 0) then + Inc(manager.container.PageNumber); + end; + end; + parse.Free; + end; diff --git a/baseunits/includes/MangaFrame/image_url.inc b/baseunits/includes/MangaFrame/image_url.inc index b48f170bd..7567b04c9 100644 --- a/baseunits/includes/MangaFrame/image_url.inc +++ b/baseunits/includes/MangaFrame/image_url.inc @@ -1,38 +1,38 @@ - function GetMangaFrameImageURL: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAFRAME_ID, URL); - if not ExecRegExpr('/$', s) then - s := s + '/'; - s := s + 'page/' + IntToStr(QWord(workCounter) + 1); - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - l.Text := FixHTMLTagQuote(l.Text); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - //if i + 2 < parse.Count - 1 then - if (Pos('class="open"', parse[i]) > 0) and (Pos('<img', parse[i]) > 0) then - begin - manager.container.PageLinks[workCounter] := Trim(GetVal(parse[i], 'src')); - Break; - end; - parse.Free; - end; + function GetMangaFrameImageURL: Boolean; + var + i: Integer; + l: TStringList; + s: String; + begin + l := TStringList.Create; + s := FillMangaSiteHost(MANGAFRAME_ID, URL); + if not ExecRegExpr('/$', s) then + s := s + '/'; + s := s + 'page/' + IntToStr(QWord(workCounter) + 1); + Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); + + if Self.Terminated then + begin + l.Free; + parse.Free; + Exit; + end; + + l.Text := FixHTMLTagQuote(l.Text); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + l.Free; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + //if i + 2 < parse.Count - 1 then + if (Pos('class="open"', parse[i]) > 0) and (Pos('<img', parse[i]) > 0) then + begin + manager.container.PageLinks[workCounter] := Trim(GetVal(parse[i], 'src')); + Break; + end; + parse.Free; + end; diff --git a/baseunits/includes/MangaFrame/manga_information.inc b/baseunits/includes/MangaFrame/manga_information.inc index 5563f098a..d10d85bab 100644 --- a/baseunits/includes/MangaFrame/manga_information.inc +++ b/baseunits/includes/MangaFrame/manga_information.inc @@ -1,82 +1,82 @@ - function GetMangaFrameInfoFromURL: Byte; - var - i: Integer; - begin - mangaInfo.website := WebsiteRoots[MANGAFRAME_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAFRAME_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit(INFORMATION_NOT_FOUND); - - mangaInfo.coverLink := ''; - mangaInfo.title := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.status := '1'; - - for i := 0 to parse.Count - 1 do - begin - //cover - if (i + 2 < parse.Count - 1) then - if (Pos('class="thumbnail"', parse[i]) > 0) and (Pos('<img', parse[i + 2]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - //title - if (i + 1 < parse.Count - 1) then - if (Pos('class="title"', parse[i]) > 0) and (Pos('<h1', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - - //author - if (i + 3 < parse.Count - 1) then - if (Pos('Author', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) - and (Pos('<', parse[i + 2]) = 0) then - mangaInfo.authors := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); - - //artist - if (i + 3 < parse.Count - 1) then - if (Pos('Artist', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) - and (Pos('<', parse[i + 2]) = 0) then - mangaInfo.artists := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); - - //synopsis - if (i + 3 < parse.Count - 1) then - if (Pos('Synopsis', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) - and (Pos('<', parse[i + 2]) = 0) then - mangaInfo.summary := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); - - //chapters - if (i + 2 < parse.Count - 1) then - if (Pos('class="title"', parse[i]) > 0) and (Pos('<a', parse[i + 1]) > 0) - and (Pos('/okuyucu/read', parse[i + 1]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(Trim(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGAFRAME_ID, 1], '', [rfIgnoreCase]))); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); - end; - end; - - // invert chapters - if mangaInfo.chapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - - Result := NO_ERROR; - end; + function GetMangaFrameInfoFromURL: Byte; + var + i: Integer; + begin + mangaInfo.website := WebsiteRoots[MANGAFRAME_ID, 0]; + mangaInfo.url := FillMangaSiteHost(MANGAFRAME_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Source.Free; + + if parse.Count = 0 then + Exit(INFORMATION_NOT_FOUND); + + mangaInfo.coverLink := ''; + mangaInfo.title := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + mangaInfo.status := '1'; + + for i := 0 to parse.Count - 1 do + begin + //cover + if (i + 2 < parse.Count - 1) then + if (Pos('class="thumbnail"', parse[i]) > 0) and (Pos('<img', parse[i + 2]) > 0) then + mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); + + //title + if (i + 1 < parse.Count - 1) then + if (Pos('class="title"', parse[i]) > 0) and (Pos('<h1', parse[i]) > 0) then + mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); + + //author + if (i + 3 < parse.Count - 1) then + if (Pos('Author', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) + and (Pos('<', parse[i + 2]) = 0) then + mangaInfo.authors := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); + + //artist + if (i + 3 < parse.Count - 1) then + if (Pos('Artist', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) + and (Pos('<', parse[i + 2]) = 0) then + mangaInfo.artists := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); + + //synopsis + if (i + 3 < parse.Count - 1) then + if (Pos('Synopsis', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) + and (Pos('<', parse[i + 2]) = 0) then + mangaInfo.summary := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); + + //chapters + if (i + 2 < parse.Count - 1) then + if (Pos('class="title"', parse[i]) > 0) and (Pos('<a', parse[i + 1]) > 0) + and (Pos('/okuyucu/read', parse[i + 1]) > 0) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add(Trim(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGAFRAME_ID, 1], '', [rfIgnoreCase]))); + mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); + end; + end; + + // invert chapters + if mangaInfo.chapterName.Count > 1 then + begin + InvertStrings(mangaInfo.chapterName); + InvertStrings(mangaInfo.chapterLinks); + end; + + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaFrame/names_and_links.inc b/baseunits/includes/MangaFrame/names_and_links.inc index 6e186a6b3..d08dfec28 100644 --- a/baseunits/includes/MangaFrame/names_and_links.inc +++ b/baseunits/includes/MangaFrame/names_and_links.inc @@ -1,32 +1,32 @@ - function MangaFrameNamesAndLinks: Byte; - var - i: Integer; - s: String; - //isExtractNames: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[MANGAFRAME_ID, 1] + MANGAFRAME_BROWSER + IntToStr(StrToInt(URL) + 1) + '/'; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if i + 2 < parse.Count - 1 then - if (Pos('class="title"', parse[i]) > 0) and (Pos('<a', parse[i + 1]) > 0) and - (Pos('/okuyucu/series/', parse[i + 1]) > 0) then - begin - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); - links.Add(Trim(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGAFRAME_ID, 1], '', [rfIgnoreCase]))); - end; - Result := NO_ERROR; - end; + function MangaFrameNamesAndLinks: Byte; + var + i: Integer; + s: String; + //isExtractNames: Boolean = False; + begin + Result := INFORMATION_NOT_FOUND; + s := WebsiteRoots[MANGAFRAME_ID, 1] + MANGAFRAME_BROWSER + IntToStr(StrToInt(URL) + 1) + '/'; + if not GetPage(TObject(Source), s, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Source.Free; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + if i + 2 < parse.Count - 1 then + if (Pos('class="title"', parse[i]) > 0) and (Pos('<a', parse[i + 1]) > 0) and + (Pos('/okuyucu/series/', parse[i + 1]) > 0) then + begin + names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); + links.Add(Trim(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGAFRAME_ID, 1], '', [rfIgnoreCase]))); + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaGo/chapter_page_number.inc b/baseunits/includes/MangaGo/chapter_page_number.inc index 615915dfe..b20b382c8 100644 --- a/baseunits/includes/MangaGo/chapter_page_number.inc +++ b/baseunits/includes/MangaGo/chapter_page_number.inc @@ -1,33 +1,33 @@ - function GetMangaGoPageNumber: Boolean; - var - i: Cardinal; - s: String; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAGO_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - if Pos('total_pages=', parse.Strings[i]) > 0 then - begin - regx := TRegExpr.Create; - regx.Expression := '^.*total_pages=(\d+)\b.*$'; - manager.container.PageNumber := - StrToIntDef(regx.Replace(parse.Strings[i], '$1', True), 0); - regx.Free; - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaGoPageNumber: Boolean; + var + i: Cardinal; + s: String; + l: TStringList; + regx: TRegExpr; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := FillMangaSiteHost(MANGAGO_ID, URL); + Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + if Pos('total_pages=', parse[i]) > 0 then + begin + regx := TRegExpr.Create; + regx.Expression := '^.*total_pages=(\d+)\b.*$'; + manager.container.PageNumber := + StrToIntDef(regx.Replace(parse[i], '$1', True), 0); + regx.Free; + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaGo/directory_page_number.inc b/baseunits/includes/MangaGo/directory_page_number.inc index a6a2f75bc..8e976ce7b 100644 --- a/baseunits/includes/MangaGo/directory_page_number.inc +++ b/baseunits/includes/MangaGo/directory_page_number.inc @@ -1,37 +1,36 @@ - function GetMangaGoDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + - MANGAGO_BROWSER + '1/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="pagination"', parse.Strings[i]) <> 0) then - begin - s := TrimLeft(TrimRight(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'total=')))); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetMangaGoDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + + MANGAGO_BROWSER + '1/', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="pagination"', parse[i]) <> 0) then + begin + s := TrimLeft(TrimRight(GetVal(parse[i], 'total'))); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaGo/image_url.inc b/baseunits/includes/MangaGo/image_url.inc index 81cff3c4e..5da91c04d 100644 --- a/baseunits/includes/MangaGo/image_url.inc +++ b/baseunits/includes/MangaGo/image_url.inc @@ -1,48 +1,48 @@ - function GetMangaGoImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - regx: TRegExpr; - s: String; - begin - l := TStringList.Create; - regx := TRegExpr.Create; - regx.Expression := '^(.*/pg-)\d+/$'; - s := regx.Replace(URL, '$1', True); - //regx.Expression := '\.html?$'; - regx.Expression := '\-$'; - if (not regx.Exec(s)) and (s[Length(s)] <> '/') then - s := s + '/'; - s := FillMangaSiteHost(MANGAGO_ID, s); - Result := GetPage(TObject(l), s + IntToStr(workCounter + 1) + '/', - manager.container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - regx.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('imgReady(''', parse[i]) > 0) then - begin - regx.Expression := '^.*imgReady\(''([^'']*)''.*$'; - manager.container.PageLinks[workCounter] := regx.Replace(parse[i], '$1', True); - Break; - end; - end; - regx.Free; - parse.Free; - l.Free; - end; + function GetMangaGoImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + regx: TRegExpr; + s: String; + begin + l := TStringList.Create; + regx := TRegExpr.Create; + regx.Expression := '^(.*/pg-)\d+/$'; + s := regx.Replace(URL, '$1', True); + //regx.Expression := '\.html?$'; + regx.Expression := '\-$'; + if (not regx.Exec(s)) and (s[Length(s)] <> '/') then + s := s + '/'; + s := FillMangaSiteHost(MANGAGO_ID, s); + Result := GetPage(TObject(l), s + IntToStr(workCounter + 1) + '/', + manager.container.Manager.retryConnect); + + if Self.Terminated then + begin + l.Free; + parse.Free; + regx.Free; + Exit; + end; + + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('imgReady(''', parse[i]) > 0) then + begin + regx.Expression := '^.*imgReady\(''([^'']*)''.*$'; + manager.container.PageLinks[workCounter] := regx.Replace(parse[i], '$1', True); + Break; + end; + end; + regx.Free; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaGo/manga_information.inc b/baseunits/includes/MangaGo/manga_information.inc index 0ce409b32..480a76f1c 100644 --- a/baseunits/includes/MangaGo/manga_information.inc +++ b/baseunits/includes/MangaGo/manga_information.inc @@ -1,103 +1,103 @@ - function GetMangaGoInfoFromURL: Byte; - var - i: Integer; - isExtractGenres: Boolean = False; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAGO_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAGO_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get title - if (i + 3 < parse.Count - 1) then - if (Pos('name="description"', parse.Strings[i]) > 0) and (mangaInfo.title = '') then - mangaInfo.title := StringReplace(TrimLeft(StringFilter(parse.Strings[i + 3])), - ' manga - Mangago', '', []); - - // get status - if (i + 5 < parse.Count - 1) then - if (Pos('<label>', parse.Strings[i]) > 0) and - (Pos('Status:', parse.Strings[i + 1]) > 0) and - (Pos('Completed', parse.Strings[i + 5]) > 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - - // get cover - if (Pos('<meta', parse.Strings[i]) > 0) and - (Pos('property="og:image"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'content='))); - - // get authors - if (i + 1 < parse.Count - 1) then - if (Pos('<label>', parse.Strings[i]) > 0) and - (Pos('Author:', parse.Strings[i + 1]) > 0) then - mangaInfo.authors := Trim(HTMLEntitiesFilter(StringFilter(parse.Strings[i + 5]))); - - // get genres - if (i + 1 < parse.Count - 1) then - if (Pos('<label>', parse.Strings[i]) > 0) and - (Pos('Genre(s)', parse.Strings[i + 1]) > 0) then - isExtractGenres := True; - - if (i + 1 < parse.Count - 1) then - if isExtractGenres then - begin - if Pos('</td>', parse.Strings[i]) > 0 then - isExtractGenres := False; - if Pos('/genre/', parse.Strings[i]) > 0 then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse.Strings[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse.Strings[i + 1]); - end; - end; - - // get summary - if (i + 1 < parse.Count - 1) then - if Pos('class="manga_summary"', parse.Strings[i]) > 0 then - mangaInfo.summary := Trim(HTMLEntitiesFilter(StringFilter(parse.Strings[i + 1]))); - - //get chapter links and names - if (GetTagName(parse[i]) = 'table') and - ((GetVal(parse[i], 'id') = 'chapter_table') or (GetVal(parse[i], 'id') = 'raws_table')) then - isExtractChapters := True; - if isExtractChapters then - begin - if GetTagName(parse[i]) = '/table' then - isExtractChapters := False; - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'chico') then - begin - Inc(mangaInfo.numChapter); - mangaInfo.ChapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.ChapterName.Add(CommonStringFilter(Trim(parse[i + 1]) + ' ' + - Trim(parse[i + 3]) + ' ' + Trim(parse[i + 5]))); - end; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - InvertStrings([mangaInfo.ChapterName, mangaInfo.ChapterLinks]); - Result := NO_ERROR; - end; + function GetMangaGoInfoFromURL: Byte; + var + i: Integer; + isExtractGenres: Boolean = False; + isExtractChapters: Boolean = False; + begin + mangaInfo.website := WebsiteRoots[MANGAGO_ID, 0]; + mangaInfo.url := FillMangaSiteHost(MANGAGO_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Source.Free; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get title + if (i + 3 < parse.Count - 1) then + if (Pos('name="description"', parse[i]) > 0) and (mangaInfo.title = '') then + mangaInfo.title := StringReplace(TrimLeft(StringFilter(parse[i + 3])), + ' manga - Mangago', '', []); + + // get status + if (i + 5 < parse.Count - 1) then + if (Pos('<label>', parse[i]) > 0) and + (Pos('Status:', parse[i + 1]) > 0) and + (Pos('Completed', parse[i + 5]) > 0) then + mangaInfo.status := '0' // completed + else + mangaInfo.status := '1'; // ongoing + + // get cover + if (Pos('<meta', parse[i]) > 0) and + (Pos('property="og:image"', parse[i]) > 0) then + mangaInfo.coverLink := + (GetVal(parse[i], 'content')); + + // get authors + if (i + 1 < parse.Count - 1) then + if (Pos('<label>', parse[i]) > 0) and + (Pos('Author:', parse[i + 1]) > 0) then + mangaInfo.authors := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 5]))); + + // get genres + if (i + 1 < parse.Count - 1) then + if (Pos('<label>', parse[i]) > 0) and + (Pos('Genre(s)', parse[i + 1]) > 0) then + isExtractGenres := True; + + if (i + 1 < parse.Count - 1) then + if isExtractGenres then + begin + if Pos('</td>', parse[i]) > 0 then + isExtractGenres := False; + if Pos('/genre/', parse[i]) > 0 then + begin + if mangaInfo.genres = '' then + mangaInfo.genres := Trim(parse[i + 1]) + else + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); + end; + end; + + // get summary + if (i + 1 < parse.Count - 1) then + if Pos('class="manga_summary"', parse[i]) > 0 then + mangaInfo.summary := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); + + //get chapter links and names + if (GetTagName(parse[i]) = 'table') and + ((GetVal(parse[i], 'id') = 'chapter_table') or (GetVal(parse[i], 'id') = 'raws_table')) then + isExtractChapters := True; + if isExtractChapters then + begin + if GetTagName(parse[i]) = '/table' then + isExtractChapters := False; + if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'chico') then + begin + Inc(mangaInfo.numChapter); + mangaInfo.ChapterLinks.Add(GetVal(parse[i], 'href')); + mangaInfo.ChapterName.Add(CommonStringFilter(Trim(parse[i + 1]) + ' ' + + Trim(parse[i + 3]) + ' ' + Trim(parse[i + 5]))); + end; + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + InvertStrings([mangaInfo.ChapterName, mangaInfo.ChapterLinks]); + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaGo/names_and_links.inc b/baseunits/includes/MangaGo/names_and_links.inc index 5fae35393..c2a9545df 100644 --- a/baseunits/includes/MangaGo/names_and_links.inc +++ b/baseunits/includes/MangaGo/names_and_links.inc @@ -1,38 +1,38 @@ - function MangaGoGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + - MANGAGO_BROWSER + IntToStr(StrToInt(URL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('h3 class="title"', parse.Strings[i]) > 0 then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')); - s := StringReplace(s, WebsiteRoots[MANGAGO_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; + function MangaGoGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + + MANGAGO_BROWSER + IntToStr(StrToInt(URL) + 1) + '/', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if Pos('h3 class="title"', parse[i]) > 0 then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i + 1], 'href'); + s := StringReplace(s, WebsiteRoots[MANGAGO_ID, 1], '', []); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaHost/image_url.inc b/baseunits/includes/MangaHost/image_url.inc index 8efdacda8..11db27645 100644 --- a/baseunits/includes/MangaHost/image_url.inc +++ b/baseunits/includes/MangaHost/image_url.inc @@ -19,7 +19,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) > 0) and (Pos('class="open', parse[i]) > 0) then begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaInn/chapter_page_number.inc b/baseunits/includes/MangaInn/chapter_page_number.inc index 38450cc74..cbf9cc470 100644 --- a/baseunits/includes/MangaInn/chapter_page_number.inc +++ b/baseunits/includes/MangaInn/chapter_page_number.inc @@ -1,31 +1,31 @@ - function GetMangaInnPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAINN_ID, URL), - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - for i := parse.Count - 1 downto 5 do - begin - if Pos('</select>', parse.Strings[i]) <> 0 then - begin - try - manager.container.PageNumber := StrToInt(Trim(parse.Strings[i - 3])); - except - manager.container.PageNumber := 0; - end; - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaInnPageNumber: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(MANGAINN_ID, URL), + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + for i := parse.Count - 1 downto 5 do + begin + if Pos('</select>', parse[i]) <> 0 then + begin + try + manager.container.PageNumber := StrToInt(Trim(parse[i - 3])); + except + manager.container.PageNumber := 0; + end; + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaInn/image_url.inc b/baseunits/includes/MangaInn/image_url.inc index 968463a0d..57e358b74 100644 --- a/baseunits/includes/MangaInn/image_url.inc +++ b/baseunits/includes/MangaInn/image_url.inc @@ -1,31 +1,31 @@ - function GetMangaInnImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAINN_ID, URL) + - '/page_' + IntToStr(workCounter + 1), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if GetTagName(parse.Strings[i]) = 'img' then - if GetAttributeValue(GetTagAttribute(parse.Strings[i], 'id=')) = 'imgPage' then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaInnImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(MANGAINN_ID, URL) + + '/page_' + IntToStr(workCounter + 1), + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if GetTagName(parse[i]) = 'img' then + if GetVal(parse[i], 'id') = 'imgPage' then + begin + manager.container.PageLinks[workCounter] := + GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaInn/manga_information.inc b/baseunits/includes/MangaInn/manga_information.inc index ff281779a..21ad4e035 100644 --- a/baseunits/includes/MangaInn/manga_information.inc +++ b/baseunits/includes/MangaInn/manga_information.inc @@ -1,122 +1,122 @@ - function GetMangaInnInfoFromURL: Byte; - var - i, j: Cardinal; - s: String; - isExtractChapters: Boolean = False; - begin - mangaInfo.url := FillMangaSiteHost(MANGAINN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAINN_ID, 0]; - - if parse.Count = 0 then - Exit; - - // using parser - mangaInfo.genres := ''; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i + 1], ' - Read ', ' Online For Free'); - - // get cover link - if GetTagName(parse.Strings[i]) = 'img' then - if Pos('/mangas/logos/', parse.Strings[i]) <> 0 then - mangaInfo.coverLink := - CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('Summary', parse.Strings[i])) <> 0 then - begin - j := i; - while Pos('</td>', parse.Strings[j]) = 0 do - begin - Inc(j); - if (GetTagName(parse.Strings[j]) = 'span') and - (GetTagAttribute(parse.Strings[j], 'class=') <> '') then - begin - parse.Strings[j + 1] := StringFilter(parse.Strings[j + 1]); - parse.Strings[j + 1] := - StringReplace(parse.Strings[j + 1], #10, '\n', [rfReplaceAll]); - parse.Strings[j + 1] := - StringReplace(parse.Strings[j + 1], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := Trim(parse.Strings[j + 1]); - end; - end; - end; - - // get authors - if (Pos('Author(s)', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(TrimRight(parse.Strings[i + 4])); - - // get artists - if (Pos('Artist(s)', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(TrimRight(parse.Strings[i + 4])); - - // get genres - if (Pos('class="RedHeadLabel"', parse[i]) > 0) then - if (Pos('Genre(s)', parse[i + 1]) > 0) then - if mangaInfo.genres <> '' then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 5]) - else - mangaInfo.genres := Trim(parse[i + 5]); - - // get type(genres) - if (Pos('class="RedHeadLabel"', parse[i]) > 0) then - if (Pos('Type', parse[i + 1]) > 0) then - if mangaInfo.genres <> '' then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 6]) - else - mangaInfo.genres := Trim(parse[i + 6]); - - // get status - if (Pos('Status', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - if Pos('Completed', parse.Strings[i + 3]) <> 0 then - mangaInfo.status := '0'; // completed - end; - - if Pos('class="m"', parse[i]) > 0 then - if Pos('Chapter Name', parse[i + 1]) > 0 then - isExtractChapters := True; - //if isExtractChapters and - //(Pos('</table', parse[i]) > 0) then - //isExtractChapters := False; - // get chapter name and links - if isExtractChapters and - (Pos('/manga/chapter/', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - CorrectURL(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGAINN_ID, 1], - '', [rfReplaceAll]))); - s := Trim(parse[i + 2]); - if Length(s) > 0 then - if s[Length(s)] = ':' then - Delete(s, Length(s), 1); - s := Trim(s); - if Trim(parse[i + 4]) <> '' then - s := s + ' ' + Trim(parse[i + 4]); - mangaInfo.chapterName.Add(Trim(StringFilter(RemoveSymbols(s)))); - end; - end; - Result := NO_ERROR; - end; + function GetMangaInnInfoFromURL: Byte; + var + i, j: Cardinal; + s: String; + isExtractChapters: Boolean = False; + begin + mangaInfo.url := FillMangaSiteHost(MANGAINN_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[MANGAINN_ID, 0]; + + if parse.Count = 0 then + Exit; + + // using parser + mangaInfo.genres := ''; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos('<title>', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i + 1], ' - Read ', ' Online For Free'); + + // get cover link + if GetTagName(parse[i]) = 'img' then + if Pos('/mangas/logos/', parse[i]) <> 0 then + mangaInfo.coverLink := + CorrectURL(GetVal(parse[i], 'src')); + + // get summary + if (Pos('Summary', parse[i])) <> 0 then + begin + j := i; + while Pos('</td>', parse[j]) = 0 do + begin + Inc(j); + if (GetTagName(parse[j]) = 'span') and + (GetVal(parse[j], 'class') <> '') then + begin + parse[j + 1] := StringFilter(parse[j + 1]); + parse[j + 1] := + StringReplace(parse[j + 1], #10, '\n', [rfReplaceAll]); + parse[j + 1] := + StringReplace(parse[j + 1], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := Trim(parse[j + 1]); + end; + end; + end; + + // get authors + if (Pos('Author(s)', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(TrimRight(parse[i + 4])); + + // get artists + if (Pos('Artist(s)', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(TrimRight(parse[i + 4])); + + // get genres + if (Pos('class="RedHeadLabel"', parse[i]) > 0) then + if (Pos('Genre(s)', parse[i + 1]) > 0) then + if mangaInfo.genres <> '' then + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 5]) + else + mangaInfo.genres := Trim(parse[i + 5]); + + // get type(genres) + if (Pos('class="RedHeadLabel"', parse[i]) > 0) then + if (Pos('Type', parse[i + 1]) > 0) then + if mangaInfo.genres <> '' then + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 6]) + else + mangaInfo.genres := Trim(parse[i + 6]); + + // get status + if (Pos('Status', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 3]) <> 0 then + mangaInfo.status := '1' // ongoing + else + if Pos('Completed', parse[i + 3]) <> 0 then + mangaInfo.status := '0'; // completed + end; + + if Pos('class="m"', parse[i]) > 0 then + if Pos('Chapter Name', parse[i + 1]) > 0 then + isExtractChapters := True; + //if isExtractChapters and + //(Pos('</table', parse[i]) > 0) then + //isExtractChapters := False; + // get chapter name and links + if isExtractChapters and + (Pos('/manga/chapter/', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add( + CorrectURL(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGAINN_ID, 1], + '', [rfReplaceAll]))); + s := Trim(parse[i + 2]); + if Length(s) > 0 then + if s[Length(s)] = ':' then + Delete(s, Length(s), 1); + s := Trim(s); + if Trim(parse[i + 4]) <> '' then + s := s + ' ' + Trim(parse[i + 4]); + mangaInfo.chapterName.Add(Trim(StringFilter(RemoveSymbols(s)))); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaInn/names_and_links.inc b/baseunits/includes/MangaInn/names_and_links.inc index 677ce62b2..37db1e3f5 100644 --- a/baseunits/includes/MangaInn/names_and_links.inc +++ b/baseunits/includes/MangaInn/names_and_links.inc @@ -1,41 +1,41 @@ - function MangaInnGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAINN_ID, 1] + - MANGAINN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<li ', parse[i]) > 0) and - (Pos('class="mangalistItems"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := GetVal(parse[i + 1], 'href'); - s := StringReplace(s, WebsiteRoots[MANGAINN_ID, 1], '', - [rfIgnoreCase, rfReplaceAll]); - s := StringReplace(s, 'http://www.mangainn.com', '', - [rfIgnoreCase, rfReplaceAll]); - links.Add(s); - names.Add(Trim(StringFilter(parse[i + 2]))); - end; - end; - Source.Free; + function MangaInnGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAINN_ID, 1] + + MANGAINN_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('<li ', parse[i]) > 0) and + (Pos('class="mangalistItems"', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := GetVal(parse[i + 1], 'href'); + s := StringReplace(s, WebsiteRoots[MANGAINN_ID, 1], '', + [rfIgnoreCase, rfReplaceAll]); + s := StringReplace(s, 'http://www.mangainn.com', '', + [rfIgnoreCase, rfReplaceAll]); + links.Add(s); + names.Add(Trim(StringFilter(parse[i + 2]))); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangaLib_PL/image_url.inc b/baseunits/includes/MangaLib_PL/image_url.inc index 2964b5437..8ccfb8ebe 100644 --- a/baseunits/includes/MangaLib_PL/image_url.inc +++ b/baseunits/includes/MangaLib_PL/image_url.inc @@ -51,7 +51,7 @@ begin for i := 0 to parse.Count - 1 do if (Pos('<img ', parse[i]) > 0) and - (Pos('id="img_curr"', parse.Strings[i]) > 0) then + (Pos('id="img_curr"', parse[i]) > 0) then begin manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; diff --git a/baseunits/includes/MangaPark/chapter_page_number.inc b/baseunits/includes/MangaPark/chapter_page_number.inc index 4abd2a417..4d478ecfc 100644 --- a/baseunits/includes/MangaPark/chapter_page_number.inc +++ b/baseunits/includes/MangaPark/chapter_page_number.inc @@ -1,29 +1,29 @@ - function GetMangaParkPageNumber: Boolean; - var - i: LongInt; - s: String; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := URL; - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAPARK_ID, s), - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) <> 0) and (Pos('id="img-', parse[i]) <> 0) then - begin - Inc(manager.container.PageNumber); - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); - end; - parse.Free; - l.Free; - end; + function GetMangaParkPageNumber: Boolean; + var + i: LongInt; + s: String; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := URL; + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 2); + Result := GetPage(TObject(l), + FillMangaSiteHost(MANGAPARK_ID, s), + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + if (Pos('<img', parse[i]) <> 0) and (Pos('id="img-', parse[i]) <> 0) then + begin + Inc(manager.container.PageNumber); + manager.container.PageLinks.Add(GetVal(parse[i], 'src')); + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaPark/directory_page_number.inc b/baseunits/includes/MangaPark/directory_page_number.inc index 9cedf1253..bf32cc338 100644 --- a/baseunits/includes/MangaPark/directory_page_number.inc +++ b/baseunits/includes/MangaPark/directory_page_number.inc @@ -1,42 +1,42 @@ - function GetMangaParkDirectoryPageNumber: Byte; - var - i: LongInt; - isExtractPage: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAPARK_ID, 1] + - '/search?orderby=add', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'onchange') = - 'javascript:window.location.href=this.options[this.selectedIndex].value;') then - isExtractPage := True; - if isExtractPage then - begin - if GetTagName(parse[i]) = '/select' then - Break - else if GetTagName(parse[i]) = 'option' then - Inc(Page); - end; - end; - end; - Source.Free; - end; + function GetMangaParkDirectoryPageNumber: Byte; + var + i: LongInt; + isExtractPage: Boolean = False; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAPARK_ID, 1] + + '/search?orderby=add', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + Parser := THTMLParser.Create(PChar(Source.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'onchange') = + 'javascript:window.location.href=this.options[this.selectedIndex].value;') then + isExtractPage := True; + if isExtractPage then + begin + if GetTagName(parse[i]) = '/select' then + Break + else if GetTagName(parse[i]) = 'option' then + Inc(Page); + end; + end; + end; + Source.Free; + end; diff --git a/baseunits/includes/MangaPark/image_url.inc b/baseunits/includes/MangaPark/image_url.inc index 899039e1d..12a83d8e2 100644 --- a/baseunits/includes/MangaPark/image_url.inc +++ b/baseunits/includes/MangaPark/image_url.inc @@ -1,32 +1,31 @@ - function GetMangaParkImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAPARK_ID, URL) + - 'all',//IntToStr(workCounter+1), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - // if GetTagName(parse.Strings[i]) = 'img' then - if (Pos('a target="_blank"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Add(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'href='))); - // break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaParkImageURL: Boolean; + var + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(MANGAPARK_ID, URL) + + 'all',//IntToStr(workCounter+1), + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + // if GetTagName(parse[i]) = 'img' then + if (Pos('a target="_blank"', parse[i]) > 0) then + begin + manager.container.PageLinks.Add(GetVal(parse[i], 'href')); + // break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaPark/manga_information.inc b/baseunits/includes/MangaPark/manga_information.inc index 77a06ee5a..990e043d7 100644 --- a/baseunits/includes/MangaPark/manga_information.inc +++ b/baseunits/includes/MangaPark/manga_information.inc @@ -1,143 +1,142 @@ - function GetMangaParkInfoFromURL: Byte; - var - s, sver: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - tnames, tlinks: TStringList; - begin - mangaInfo.website := WebsiteRoots[MANGAPARK_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAPARK_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count > 0 then - begin - tnames:= TStringList.Create; - tlinks:= TStringList.Create; - try - sver := ''; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('property="og:title"', parse[i]) <> 0) then - begin - mangaInfo.title := CommonStringFilter(GetVal(parse[i], 'content')); - mangaInfo.title := ReplaceRegExpr('\sManga$', mangaInfo.title, '', False); - end; - - // get cover - if (GetTagName(parse.Strings[i]) = 'meta') and - (Pos('property="og:image"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'content='))); - - // get summary - if (Pos('<h2>', parse.Strings[i]) <> 0) and - (Pos('Summary', parse.Strings[i + 1]) <> 0) and - (isExtractSummary) then - begin - j := i + 3; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get chapter name and links - if (Pos('<a', parse[i]) <> 0) and (Pos('class="st st', parse[i]) <> 0) then - begin - if tlinks.Count > 0 then - begin - InvertStrings([tnames, tlinks]); - mangaInfo.chapterName.AddStrings(tnames); - mangaInfo.chapterLinks.AddStrings(tlinks); - tnames.Clear; - tlinks.Clear; - end; - sver := Trim(parse[i + 1]); - end; - if (Pos('<a', parse[i]) <> 0) and (Pos('class="ch sts sts', parse[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - tlinks.Add(s); - tnames.Add(CommonStringFilter( - Format('%s %s %s', [sver, Trim(parse[i + 1]), Trim(parse[i + 3])]))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Author(s)', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 6]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist(s)', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 6]); - - // get genres - if (Pos('Genre(s)', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if Pos('/genre/', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</td>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - finally - if tlinks.Count > 0 then - begin - InvertStrings([tnames, tlinks]); - mangaInfo.chapterName.AddStrings(tnames); - mangaInfo.chapterLinks.AddStrings(tlinks); - end; - tnames.Free; - tlinks.Free; - end; - end; - Result := NO_ERROR; - end; + function GetMangaParkInfoFromURL: Byte; + var + s, sver: String; + isExtractSummary: Boolean = True; + isExtractGenres: Boolean = False; + i, j: Cardinal; + tnames, tlinks: TStringList; + begin + mangaInfo.website := WebsiteRoots[MANGAPARK_ID, 0]; + mangaInfo.url := FillMangaSiteHost(MANGAPARK_ID, URL);// + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + Parser := THTMLParser.Create(PChar(Source.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count > 0 then + begin + tnames:= TStringList.Create; + tlinks:= TStringList.Create; + try + sver := ''; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos('property="og:title"', parse[i]) <> 0) then + begin + mangaInfo.title := CommonStringFilter(GetVal(parse[i], 'content')); + mangaInfo.title := ReplaceRegExpr('\sManga$', mangaInfo.title, '', False); + end; + + // get cover + if (GetTagName(parse[i]) = 'meta') and + (Pos('property="og:image"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'content')); + + // get summary + if (Pos('<h2>', parse[i]) <> 0) and + (Pos('Summary', parse[i + 1]) <> 0) and + (isExtractSummary) then + begin + j := i + 3; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := parse[j]; + end; + Inc(j); + end; + isExtractSummary := False; + end; + + // get chapter name and links + if (Pos('<a', parse[i]) <> 0) and (Pos('class="st st', parse[i]) <> 0) then + begin + if tlinks.Count > 0 then + begin + InvertStrings([tnames, tlinks]); + mangaInfo.chapterName.AddStrings(tnames); + mangaInfo.chapterLinks.AddStrings(tlinks); + tnames.Clear; + tlinks.Clear; + end; + sver := Trim(parse[i + 1]); + end; + if (Pos('<a', parse[i]) <> 0) and (Pos('class="ch sts sts', parse[i]) <> 0) then + begin + Inc(mangaInfo.numChapter); + s := GetVal(parse[i], 'href'); + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 2); + tlinks.Add(s); + tnames.Add(CommonStringFilter( + Format('%s %s %s', [sver, Trim(parse[i + 1]), Trim(parse[i + 3])]))); + end; + + // get authors + if (i + 4 < parse.Count) and (Pos('Author(s)', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(parse[i + 6]); + + // get artists + if (i + 4 < parse.Count) and (Pos('Artist(s)', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(parse[i + 6]); + + // get genres + if (Pos('Genre(s)', parse[i]) <> 0) then + begin + isExtractGenres := True; + mangaInfo.genres := ''; + end; + + if isExtractGenres then + begin + if Pos('/genre/', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + TrimLeft(TrimRight(parse[i + 1])) + ', '; + if Pos('</td>', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 4]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + finally + if tlinks.Count > 0 then + begin + InvertStrings([tnames, tlinks]); + mangaInfo.chapterName.AddStrings(tnames); + mangaInfo.chapterLinks.AddStrings(tlinks); + end; + tnames.Free; + tlinks.Free; + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaPark/names_and_links.inc b/baseunits/includes/MangaPark/names_and_links.inc index 20422d78f..1bc62ecae 100644 --- a/baseunits/includes/MangaPark/names_and_links.inc +++ b/baseunits/includes/MangaPark/names_and_links.inc @@ -1,34 +1,34 @@ - function MangaParkGetNamesAndLinks: Byte; - var - i: LongInt; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAPARK_ID, 1] + - '/search?orderby=add&page=' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'em') and (GetVal(parse[i], 'class') = 'icon') then - begin - links.Add(GetVal(parse[i + 3], 'href')); - names.Add(CommonStringFilter(GetVal(parse[i + 3], 'title'))); - end; - end; - Source.Free; - end; + function MangaParkGetNamesAndLinks: Byte; + var + i: LongInt; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAPARK_ID, 1] + + '/search?orderby=add&page=' + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + Parser := THTMLParser.Create(PChar(Source.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (GetTagName(parse[i]) = 'em') and (GetVal(parse[i], 'class') = 'icon') then + begin + links.Add(GetVal(parse[i + 3], 'href')); + names.Add(CommonStringFilter(GetVal(parse[i + 3], 'title'))); + end; + end; + Source.Free; + end; diff --git a/baseunits/includes/MangaREADER_POR/image_url.inc b/baseunits/includes/MangaREADER_POR/image_url.inc index 5573a0124..3fe4a3490 100644 --- a/baseunits/includes/MangaREADER_POR/image_url.inc +++ b/baseunits/includes/MangaREADER_POR/image_url.inc @@ -1,45 +1,45 @@ - function GetMangaREADER_PORImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAREADER_POR_ID, URL) + '/#1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - manager.container.pageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('function Proxima()', parse.Strings[i]) > 0 then - begin - //s:= GetString(parse.Strings[i], 'new Array("",', 'function Proxima'); - s := GetString(parse.Strings[i], 'new Array("",', ');'); - s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); - manager.container.PageLinks.DelimitedText := s; - Break; - //repeat - // j:= Pos('http://', s); - // manager.container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); - // s:= StringReplace(s, '"', '', []); - // s:= StringReplace(s, '"', '', []); - // Delete(s, j, 7); - // j:= Pos('http://', s); - //until j = 0; - end; - end; - end; - - parse.Free; - l.Free; - end; + function GetMangaREADER_PORImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGAREADER_POR_ID, URL) + '/#1'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + manager.container.pageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('function Proxima()', parse[i]) > 0 then + begin + //s:= GetString(parse[i], 'new Array("",', 'function Proxima'); + s := GetString(parse[i], 'new Array("",', ');'); + s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); + manager.container.PageLinks.DelimitedText := s; + Break; + //repeat + // j:= Pos('http://', s); + // manager.container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); + // s:= StringReplace(s, '"', '', []); + // s:= StringReplace(s, '"', '', []); + // Delete(s, j, 7); + // j:= Pos('http://', s); + //until j = 0; + end; + end; + end; + + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaREADER_POR/manga_information.inc b/baseunits/includes/MangaREADER_POR/manga_information.inc index d2c004db0..2c6c92c09 100644 --- a/baseunits/includes/MangaREADER_POR/manga_information.inc +++ b/baseunits/includes/MangaREADER_POR/manga_information.inc @@ -1,191 +1,191 @@ - function GetMangaREADER_PORInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j, n: Cardinal; - numberOfPage: Cardinal = 1; - - procedure ExtractChapter; - begin - if (not isExtractChapter) and (Pos('id="listagemCaps', parse.Strings[i]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('paginacao', parse.Strings[i]) > 0) then - isExtractChapter := False; //bermasalah - - // get chapter name and links - if (isExtractChapter) and - (Pos('</em>', parse.Strings[i]) > 0) and - (i + 6 < parse.Count - 1) then - begin - Inc(mangaInfo.numChapter); - //s:= StringReplace(GetString(parse.Strings[i+6], 'href="', '"'), WebsiteRoots[MANGAREADER_POR_ID,1], '', []); - //mangaInfo.chapterLinks.Add(s); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 6], 'href')); - s := StringReplace(s, WebsiteRoots[MANGAREADER_POR_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - end; - - begin - mangaInfo.url := FillMangaSiteHost(MANGAREADER_POR_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //weird stuff - if Source.Count > 1 then - Source.Text := StringReplace(Source.Text, '<3', '❤', [rfReplaceAll, rfIgnoreCase]); - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[MANGAREADER_POR_ID, 0]; - mangaInfo.status := '0'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - - isExtractChapter := False; - for i := 0 to parse.Count - 1 do - begin - // Get number of page. - if Pos('Última Página', parse.Strings[i]) > 0 then - numberOfPage := StrToInt(GetString(parse.Strings[i - 1], '/page/', '">')); - - // get cover - //if (mangaInfo.coverLink='') AND - // (Pos('img src="', parse.Strings[i])>0) AND - // (Pos('class="imgClass"', parse.Strings[i])>0) then - // mangaInfo.coverLink:=GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src')); - - {if (mangaInfo.coverLink = '') AND - (Pos('class="cvr', parse.Strings[i])>0) then - mangaInfo.coverLink:= CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')));} - - // get title - if (Pos('Título:', parse.Strings[i]) > 0) then - mangaInfo.title := parse.Strings[i + 2]; - - ExtractChapter; - - //Not available - // get summary - //if (Pos('class="text', parse.Strings[i]) <> 0) then - //begin - // j:= i+9; - // while (j<parse.Count) AND (Pos('</div>', parse.Strings[j])=0) do - // begin - // s:= parse.Strings[j]; - // if s[1] <> '<' then - // begin - // parse.Strings[j]:= HTMLEntitiesFilter(StringFilter(TrimLeft(parse.Strings[j]))); - // parse.Strings[j]:= StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - // parse.Strings[j]:= StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - // mangaInfo.summary:= mangaInfo.summary + parse.Strings[j]; - // break; - // end; - // Inc(j); - // end; - // isExtractSummary:= FALSE; - //end; - - // get authors - if (Pos('Autor:', parse.Strings[i]) > 0) then - mangaInfo.authors := Trim(StringFilter(parse.Strings[i + 2])); - - // get artists - if (Pos('Artista:', parse.Strings[i]) > 0) then - mangaInfo.artists := Trim(StringFilter(parse.Strings[i + 2])); - - // get genres - if Pos('Categoria:', parse.Strings[i]) > 0 then - mangaInfo.genres := parse.Strings[i + 4]; - //if (Pos('class="cat', parse.Strings[i])<>0) then - //begin - // isExtractGenres:= TRUE; - //end; - - //if isExtractGenres then - //begin - // if Pos('', parse.Strings[i]) <> 0 then - // mangaInfo.genres:= mangaInfo.genres + TrimLeft(TrimRight(parse.Strings[i+1])) + ', '; - // if Pos('</br>', parse.Strings[i]) <> 0 then - // isExtractGenres:= FALSE; - //end; - - // not available - // get status - //if (i+2<parse.Count) AND (Pos('Status', parse.Strings[i])<>0) then - //begin - // if Pos('Ongoing', parse.Strings[i+3])<>0 then - // mangaInfo.status:= '1' // ongoing - // else - // mangaInfo.status:= '0'; // completed - //end; - end; - - // If there're more than 1 page, we need to continue to scrape for chapters ... - if numberOfPage > 1 then - begin - for n := 2 to numberOfPage do - begin - Source.Clear; - s := mangaInfo.url + '/' + IntToStr(n); - if not GetPage(TObject(Source), mangaInfo.url + '/page/' + - IntToStr(n), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - //weird stuff - if Source.Count > 1 then - Source.Text := StringReplace(Source.Text, '<3', '❤', [rfReplaceAll, rfIgnoreCase]); - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - isExtractChapter := False; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - ExtractChapter; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetMangaREADER_PORInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j, n: Cardinal; + numberOfPage: Cardinal = 1; + + procedure ExtractChapter; + begin + if (not isExtractChapter) and (Pos('id="listagemCaps', parse[i]) > 0) then + isExtractChapter := True; + + if (isExtractChapter) and + (Pos('paginacao', parse[i]) > 0) then + isExtractChapter := False; //bermasalah + + // get chapter name and links + if (isExtractChapter) and + (Pos('</em>', parse[i]) > 0) and + (i + 6 < parse.Count - 1) then + begin + Inc(mangaInfo.numChapter); + //s:= StringReplace(GetString(parse[i+6], 'href="', '"'), WebsiteRoots[MANGAREADER_POR_ID,1], '', []); + //mangaInfo.chapterLinks.Add(s); + s := GetVal(parse[i + 6], 'href'); + s := StringReplace(s, WebsiteRoots[MANGAREADER_POR_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + end; + + begin + mangaInfo.url := FillMangaSiteHost(MANGAREADER_POR_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + //weird stuff + if Source.Count > 1 then + Source.Text := StringReplace(Source.Text, '<3', '❤', [rfReplaceAll, rfIgnoreCase]); + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + mangaInfo.website := WebsiteRoots[MANGAREADER_POR_ID, 0]; + mangaInfo.status := '0'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + + isExtractChapter := False; + for i := 0 to parse.Count - 1 do + begin + // Get number of page. + if Pos('Última Página', parse[i]) > 0 then + numberOfPage := StrToInt(GetString(parse[i - 1], '/page/', '">')); + + // get cover + //if (mangaInfo.coverLink='') AND + // (Pos('img src="', parse[i])>0) AND + // (Pos('class="imgClass"', parse[i])>0) then + // mangaInfo.coverLink:=GetVal(parse[i], 'src'); + + {if (mangaInfo.coverLink = '') AND + (Pos('class="cvr', parse[i])>0) then + mangaInfo.coverLink:= CorrectURL(GetVal(parse[i], 'src'));} + + // get title + if (Pos('Título:', parse[i]) > 0) then + mangaInfo.title := parse[i + 2]; + + ExtractChapter; + + //Not available + // get summary + //if (Pos('class="text', parse[i]) <> 0) then + //begin + // j:= i+9; + // while (j<parse.Count) AND (Pos('</div>', parse[j])=0) do + // begin + // s:= parse[j]; + // if s[1] <> '<' then + // begin + // parse[j]:= HTMLEntitiesFilter(StringFilter(TrimLeft(parse[j]))); + // parse[j]:= StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + // parse[j]:= StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + // mangaInfo.summary:= mangaInfo.summary + parse[j]; + // break; + // end; + // Inc(j); + // end; + // isExtractSummary:= FALSE; + //end; + + // get authors + if (Pos('Autor:', parse[i]) > 0) then + mangaInfo.authors := Trim(StringFilter(parse[i + 2])); + + // get artists + if (Pos('Artista:', parse[i]) > 0) then + mangaInfo.artists := Trim(StringFilter(parse[i + 2])); + + // get genres + if Pos('Categoria:', parse[i]) > 0 then + mangaInfo.genres := parse[i + 4]; + //if (Pos('class="cat', parse[i])<>0) then + //begin + // isExtractGenres:= TRUE; + //end; + + //if isExtractGenres then + //begin + // if Pos('', parse[i]) <> 0 then + // mangaInfo.genres:= mangaInfo.genres + TrimLeft(TrimRight(parse[i+1])) + ', '; + // if Pos('</br>', parse[i]) <> 0 then + // isExtractGenres:= FALSE; + //end; + + // not available + // get status + //if (i+2<parse.Count) AND (Pos('Status', parse[i])<>0) then + //begin + // if Pos('Ongoing', parse[i+3])<>0 then + // mangaInfo.status:= '1' // ongoing + // else + // mangaInfo.status:= '0'; // completed + //end; + end; + + // If there're more than 1 page, we need to continue to scrape for chapters ... + if numberOfPage > 1 then + begin + for n := 2 to numberOfPage do + begin + Source.Clear; + s := mangaInfo.url + '/' + IntToStr(n); + if not GetPage(TObject(Source), mangaInfo.url + '/page/' + + IntToStr(n), Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + //weird stuff + if Source.Count > 1 then + Source.Text := StringReplace(Source.Text, '<3', '❤', [rfReplaceAll, rfIgnoreCase]); + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + isExtractChapter := False; + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + ExtractChapter; + end; + end; + Source.Free; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaREADER_POR/names_and_links.inc b/baseunits/includes/MangaREADER_POR/names_and_links.inc index 9774236ed..373cfa4d9 100644 --- a/baseunits/includes/MangaREADER_POR/names_and_links.inc +++ b/baseunits/includes/MangaREADER_POR/names_and_links.inc @@ -1,51 +1,51 @@ - function MangaREADER_PORGetNamesAndLinks: Byte; - var - i: LongInt; - s: String; - parser: TJSONParser; - Data: TJSONData; - jobject: TJSONObject; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(source), - WebsiteRoots[MANGAREADER_POR_ID, 1] + '/AJAX/listaMangas/all', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //UTF8BOM:string=#$EF#$BB#$BF - //Remove BOM header, jsonparser can't deal with BOM - s := Source.Text; - if Length(s) > 3 then - begin - if Copy(s, 1, 3) = UTF8BOM then - Delete(s, 1, 3); - end; - parser := TJSONParser.Create(s); - try - Data := parser.Parse; - try - if Assigned(Data) then - begin - if Data.JSONType = jtArray then - begin - for i := 0 to Data.Count - 1 do - begin - jobject := TJSONObject(Data.Items[i]); - names.Add(jobject.Strings['title']); - links.Add(StringReplace(jobject.Strings['serie_url'], - WebsiteRoots[MANGAREADER_POR_ID, 1], '', [])); - end; - end; - end; - finally - Data.Free; - end; - finally - parser.Free; - end; - Result := NO_ERROR; - Source.Free; - end; + function MangaREADER_PORGetNamesAndLinks: Byte; + var + i: LongInt; + s: String; + parser: TJSONParser; + Data: TJSONData; + jobject: TJSONObject; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(source), + WebsiteRoots[MANGAREADER_POR_ID, 1] + '/AJAX/listaMangas/all', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + //UTF8BOM:string=#$EF#$BB#$BF + //Remove BOM header, jsonparser can't deal with BOM + s := Source.Text; + if Length(s) > 3 then + begin + if Copy(s, 1, 3) = UTF8BOM then + Delete(s, 1, 3); + end; + parser := TJSONParser.Create(s, [joUTF8]); + try + Data := parser.Parse; + try + if Assigned(Data) then + begin + if Data.JSONType = jtArray then + begin + for i := 0 to Data.Count - 1 do + begin + jobject := TJSONObject(Data.Items[i]); + names.Add(jobject.Strings['title']); + links.Add(StringReplace(jobject.Strings['serie_url'], + WebsiteRoots[MANGAREADER_POR_ID, 1], '', [])); + end; + end; + end; + finally + Data.Free; + end; + finally + parser.Free; + end; + Result := NO_ERROR; + Source.Free; + end; diff --git a/baseunits/includes/MangaTown/manga_information.inc b/baseunits/includes/MangaTown/manga_information.inc index f88fa57a9..5e89d647b 100644 --- a/baseunits/includes/MangaTown/manga_information.inc +++ b/baseunits/includes/MangaTown/manga_information.inc @@ -36,7 +36,7 @@ // get title if (i + 1 < parse.Count - 1) then - if (Pos('class="title-top"', parse.Strings[i]) > 0) and (mangaInfo.title = '') then + if (Pos('class="title-top"', parse[i]) > 0) and (mangaInfo.title = '') then mangaInfo.title := Trim(StringFilter(parse[i + 1])); // get genres @@ -75,7 +75,7 @@ // get summary if (i + 1 < parse.Count - 1) then - if (Pos('<span', parse.Strings[i]) > 0) and (Pos('id="show"', parse[i]) > 0) then + if (Pos('<span', parse[i]) > 0) and (Pos('id="show"', parse[i]) > 0) then mangaInfo.summary := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); //get chapter links and names diff --git a/baseunits/includes/MangaTraders/chapter_page_number.inc b/baseunits/includes/MangaTraders/chapter_page_number.inc index d72c58f55..703fbe28a 100644 --- a/baseunits/includes/MangaTraders/chapter_page_number.inc +++ b/baseunits/includes/MangaTraders/chapter_page_number.inc @@ -1,36 +1,36 @@ - function GetMangaTradersPageNumber: Boolean; - var - isGetPageNumber: Boolean = False; - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGATRADERS_ID, URL); - s := s + '/page-1'; - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if Pos('<select', parse[i]) > 0 then - isGetPageNumber := True; - if isGetPageNumber and (Pos('</select', parse[i]) > 0) then - begin - isGetPageNumber := False; - Break; - end; - if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; + function GetMangaTradersPageNumber: Boolean; + var + isGetPageNumber: Boolean = False; + i: Integer; + l: TStringList; + s: String; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := FillMangaSiteHost(MANGATRADERS_ID, URL); + s := s + '/page-1'; + Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if Pos('<select', parse[i]) > 0 then + isGetPageNumber := True; + if isGetPageNumber and (Pos('</select', parse[i]) > 0) then + begin + isGetPageNumber := False; + Break; + end; + if isGetPageNumber and (Pos('<option', parse[i]) > 0) then + Inc(manager.container.PageNumber); + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaTraders/image_url.inc b/baseunits/includes/MangaTraders/image_url.inc index fd18e51de..43fecf3ac 100644 --- a/baseunits/includes/MangaTraders/image_url.inc +++ b/baseunits/includes/MangaTraders/image_url.inc @@ -1,33 +1,33 @@ - function GetMangaTradersImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGATRADERS_ID, URL); - s := s + '/page-' + IntToStr(workCounter + 1); - Result := GetPage(TObject(l), s, manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then - begin - //fix line - parse[i] := RemoveBreaks(parse[i]); - if Pos(#9, parse[i]) > 0 then - parse[i] := StringReplace(parse[i], #9, ' ', [rfReplaceAll, rfIgnoreCase]); - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaTradersImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := FillMangaSiteHost(MANGATRADERS_ID, URL); + s := s + '/page-' + IntToStr(workCounter + 1); + Result := GetPage(TObject(l), s, manager.container.manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then + begin + //fix line + parse[i] := RemoveBreaks(parse[i]); + if Pos(#9, parse[i]) > 0 then + parse[i] := StringReplace(parse[i], #9, ' ', [rfReplaceAll, rfIgnoreCase]); + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaTraders/manga_information.inc b/baseunits/includes/MangaTraders/manga_information.inc index 6e6dfde63..0aef311d3 100644 --- a/baseunits/includes/MangaTraders/manga_information.inc +++ b/baseunits/includes/MangaTraders/manga_information.inc @@ -1,112 +1,112 @@ - function GetMangaTradersInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - i: Integer; - regx: TRegExpr; - begin - mangaInfo.website := WebsiteRoots[MANGATRADERS_ID, 0]; - // fixing url - mangaInfo.url := FillMangaSiteHost(MANGATRADERS_ID, URL); - regx := TRegExpr.Create; - try - regx.Expression := '\/manga\/\?series\=(.*)$'; - if regx.Exec(mangaInfo.url) then - mangaInfo.url := regx.Replace(mangaInfo.url, '/read-online/$1', True); - finally - regx.Free; - end; - - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - begin - Parser.Free; - Source.Free; - Exit; - end; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.summary := ''; - - regx := TRegExpr.Create; - regx.Expression := '\/page\-\d+$'; - for i := 0 to parse.Count - 1 do - begin - //title - if Pos('<h1', parse[i]) > 0 then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //cover - if Pos('property="og:image:url"', parse[i]) > 0 then - mangaInfo.coverLink := GetVal(parse[i], 'content'); - - //author - if Pos('<b', parse[i]) > 0 then - if Pos('Author:', parse[i + 1]) > 0 then - mangaInfo.authors := CommonStringFilter(parse[i + 4]); - - //status - if Pos('<b', parse[i]) > 0 then - if Pos('Publishing Status:', parse[i + 1]) > 0 then - begin - if LowerCase(Trim(parse[i + 3])) = 'ongoing' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - - //genres - if Pos('Genre:', parse[i]) > 0 then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - if isExtractGenres and (Pos('</div', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('Genre:', parse[i]) = 0) and - (Pos('<', parse[i]) = 0) then - mangaInfo.genres := mangaInfo.genres + parse[i]; - - //description - if Pos('Description:', parse[i]) > 0 then - mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 4])); - - //chapters - if (Pos('<a', parse[i]) > 0) and (Pos('/chapter-', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - if regx.Exec(s) then - s := regx.Replace(s, '', False); - mangaInfo.chapterLinks.Add(s); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - regx.Free; - - //remove duplicate links - RemoveDuplicateStrings([mangaInfo.chapterLinks, mangaInfo.chapterName]); - //inverts - InvertStrings(mangaInfo.chapterLinks); - InvertStrings(mangaInfo.chapterName); - - Parser.Free; - Source.Free; - Result := NO_ERROR; - end; + function GetMangaTradersInfoFromURL: Byte; + var + s: String; + isExtractGenres: Boolean = False; + i: Integer; + regx: TRegExpr; + begin + mangaInfo.website := WebsiteRoots[MANGATRADERS_ID, 0]; + // fixing url + mangaInfo.url := FillMangaSiteHost(MANGATRADERS_ID, URL); + regx := TRegExpr.Create; + try + regx.Expression := '\/manga\/\?series\=(.*)$'; + if regx.Exec(mangaInfo.url) then + mangaInfo.url := regx.Replace(mangaInfo.url, '/read-online/$1', True); + finally + regx.Free; + end; + + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + begin + Parser.Free; + Source.Free; + Exit; + end; + + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.summary := ''; + + regx := TRegExpr.Create; + regx.Expression := '\/page\-\d+$'; + for i := 0 to parse.Count - 1 do + begin + //title + if Pos('<h1', parse[i]) > 0 then + mangaInfo.title := CommonStringFilter(parse[i + 1]); + + //cover + if Pos('property="og:image:url"', parse[i]) > 0 then + mangaInfo.coverLink := GetVal(parse[i], 'content'); + + //author + if Pos('<b', parse[i]) > 0 then + if Pos('Author:', parse[i + 1]) > 0 then + mangaInfo.authors := CommonStringFilter(parse[i + 4]); + + //status + if Pos('<b', parse[i]) > 0 then + if Pos('Publishing Status:', parse[i + 1]) > 0 then + begin + if LowerCase(Trim(parse[i + 3])) = 'ongoing' then + mangaInfo.status := '1' + else + mangaInfo.status := '0'; + end; + + //genres + if Pos('Genre:', parse[i]) > 0 then + begin + isExtractGenres := True; + mangaInfo.genres := ''; + end; + if isExtractGenres and (Pos('</div', parse[i]) > 0) then + isExtractGenres := False; + if isExtractGenres and (Pos('Genre:', parse[i]) = 0) and + (Pos('<', parse[i]) = 0) then + mangaInfo.genres := mangaInfo.genres + parse[i]; + + //description + if Pos('Description:', parse[i]) > 0 then + mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 4])); + + //chapters + if (Pos('<a', parse[i]) > 0) and (Pos('/chapter-', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := GetVal(parse[i], 'href'); + if regx.Exec(s) then + s := regx.Replace(s, '', False); + mangaInfo.chapterLinks.Add(s); + mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); + end; + end; + regx.Free; + + //remove duplicate links + RemoveDuplicateStrings([mangaInfo.chapterLinks, mangaInfo.chapterName]); + //inverts + InvertStrings(mangaInfo.chapterLinks); + InvertStrings(mangaInfo.chapterName); + + Parser.Free; + Source.Free; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaTraders/names_and_links.inc b/baseunits/includes/MangaTraders/names_and_links.inc index c30c3809a..54e9b8d96 100644 --- a/baseunits/includes/MangaTraders/names_and_links.inc +++ b/baseunits/includes/MangaTraders/names_and_links.inc @@ -1,46 +1,46 @@ - function MangaTradersGetNamesAndLinks: Byte; - var - i: Integer; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGATRADERS_ID, 1] + - MANGATRADERS_BROWSER , 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - regx := TRegExpr.Create; - try - regx.Expression := '\/manga\/\?series\=(.*)$'; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="seriesList', parse[i]) > 0 then - begin - Result := NO_ERROR; - names.Add(CommonStringFilter(parse[i + 3])); - s := TrimLeftChar(GetVal(parse[i + 2], 'href'), ['.']); - if regx.Exec(s) then - s := regx.Replace(s, '/read-online/$1', True); - links.Add(s); - end; - end; - finally - regx.Free; - end; - Source.Free; - end; + function MangaTradersGetNamesAndLinks: Byte; + var + i: Integer; + s: String; + regx: TRegExpr; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGATRADERS_ID, 1] + + MANGATRADERS_BROWSER , 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + + regx := TRegExpr.Create; + try + regx.Expression := '\/manga\/\?series\=(.*)$'; + for i := 0 to parse.Count - 1 do + begin + if Pos('class="seriesList', parse[i]) > 0 then + begin + Result := NO_ERROR; + names.Add(CommonStringFilter(parse[i + 3])); + s := TrimLeftChar(GetVal(parse[i + 2], 'href'), ['.']); + if regx.Exec(s) then + s := regx.Replace(s, '/read-online/$1', True); + links.Add(s); + end; + end; + finally + regx.Free; + end; + Source.Free; + end; diff --git a/baseunits/includes/MangaVadisi/chapter_page_number.inc b/baseunits/includes/MangaVadisi/chapter_page_number.inc index fbe621132..d3cffa5db 100644 --- a/baseunits/includes/MangaVadisi/chapter_page_number.inc +++ b/baseunits/includes/MangaVadisi/chapter_page_number.inc @@ -1,33 +1,33 @@ - function GetMangaVadisiPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Sonraki Sayfa"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 6]; - manager.container.PageNumber := StrToInt(GetString(s, '"', '"')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaVadisiPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (Pos('title="Sonraki Sayfa"', parse[i]) > 0) then + begin + s := parse[i - 6]; + manager.container.PageNumber := StrToInt(GetString(s, '"', '"')); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaVadisi/image_url.inc b/baseunits/includes/MangaVadisi/image_url.inc index 06745a518..81579b593 100644 --- a/baseunits/includes/MangaVadisi/image_url.inc +++ b/baseunits/includes/MangaVadisi/image_url.inc @@ -1,33 +1,33 @@ - function GetMangaVadisiImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL) - + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse.Strings[i]) > 0) then - begin - manager.container.pageLinks.Strings[workCounter] := - EncodeURL(WebsiteRoots[MANGAVADISI_ID, 1] + MANGAVADISI_BROWSER + - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaVadisiImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL) + + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="picture"', parse[i]) > 0) then + begin + manager.container.pageLinks[workCounter] := + EncodeURL(WebsiteRoots[MANGAVADISI_ID, 1] + MANGAVADISI_BROWSER + + GetVal(parse[i], 'src')); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangaVadisi/manga_information.inc b/baseunits/includes/MangaVadisi/manga_information.inc index cef04d8dd..218fc5e9b 100644 --- a/baseunits/includes/MangaVadisi/manga_information.inc +++ b/baseunits/includes/MangaVadisi/manga_information.inc @@ -1,61 +1,61 @@ - function GetMangaVadisiInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.website := WebsiteRoots[MANGAVADISI_ID, 0]; - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('Manga Vadisi - ', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i], 'Manga Vadisi - ', ' - Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse.Strings[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := URL + '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - Result := NO_ERROR; - end; + function GetMangaVadisiInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + mangaInfo.website := WebsiteRoots[MANGAVADISI_ID, 0]; + mangaInfo.status := '1'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get chapter name and links + if (Pos('select name="chapter"', parse[i]) > 0) then + isExtractChapter := True; + + // get manga name + if (mangaInfo.title = '') and (Pos('Manga Vadisi - ', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i], 'Manga Vadisi - ', ' - Chapter'); + + if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then + Break; + + if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := URL + '/' + GetVal(parse[i], 'value'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + end; + + // Since chapter name and link are inverted, we need to invert them + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangaVadisi/names_and_links.inc b/baseunits/includes/MangaVadisi/names_and_links.inc index df305379c..a747d26d8 100644 --- a/baseunits/includes/MangaVadisi/names_and_links.inc +++ b/baseunits/includes/MangaVadisi/names_and_links.inc @@ -1,37 +1,37 @@ - function MangaVadisiGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAVADISI_ID, 1] + - MANGAVADISI_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('<option value="', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - links.Add(s); - end; - end; - Source.Free; + function MangaVadisiGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MANGAVADISI_ID, 1] + + MANGAVADISI_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 5 do + begin + if (Pos('<option value="', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i], 'value'); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Mangacow/chapter_page_number.inc b/baseunits/includes/Mangacow/chapter_page_number.inc index 0f982e66f..e1c8b2baf 100644 --- a/baseunits/includes/Mangacow/chapter_page_number.inc +++ b/baseunits/includes/Mangacow/chapter_page_number.inc @@ -1,34 +1,34 @@ - function GetMangaCowPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + '1/'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '^.*\.push\("([^"]+)"\);.*$'; - regx.ModifierI := True; - for i := 0 to parse.Count - 1 do - if Pos('arr_img.push(', parse[i]) > 0 then - manager.container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); - finally - regx.Free - end; - end; - parse.Free; - l.Free; - end; + function GetMangaCowPageNumber: Boolean; + var + s: String; + i: Integer; + l: TStringList; + regx: TRegExpr; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + '1/'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + regx := TRegExpr.Create; + try + regx.Expression := '^.*\.push\("([^"]+)"\);.*$'; + regx.ModifierI := True; + for i := 0 to parse.Count - 1 do + if Pos('arr_img.push(', parse[i]) > 0 then + manager.container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); + finally + regx.Free + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Mangacow/image_url.inc b/baseunits/includes/Mangacow/image_url.inc index e5f6e5796..55a689e24 100644 --- a/baseunits/includes/Mangacow/image_url.inc +++ b/baseunits/includes/Mangacow/image_url.inc @@ -1,31 +1,31 @@ - function GetMangaCowImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(workCounter + 1) + '/'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'style') = 'width:0px; height:0px') then - begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetMangaCowImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(workCounter + 1) + '/'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (GetTagName(parse[i]) = 'img') and + (GetVal(parse[i], 'style') = 'width:0px; height:0px') then + begin + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Mangacow/manga_information.inc b/baseunits/includes/Mangacow/manga_information.inc index 9a35ad999..50d8e99a1 100644 --- a/baseunits/includes/Mangacow/manga_information.inc +++ b/baseunits/includes/Mangacow/manga_information.inc @@ -1,206 +1,206 @@ - function GetMangaCowInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - isExtractInfo: Boolean = False; - isExtractGenres: Boolean = False; - chapterPage: Cardinal; - begin - mangaInfo.website := WebsiteRoots[MANGACOW_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGACOW_ID, URL); - - if mangaInfo.url[Length(mangaInfo.url)] <> '/' then - mangaInfo.url := mangaInfo.url + '/'; - - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - chapterPage := 0; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'class') = 'cvr') then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // get title - if (Pos('<h1 ', parse[i]) > 0) and - (Pos('class="ttl"', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - - // get chapter name and links - if Pos('class="lst"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGACOW_ID, 1], - '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); - mangaInfo.chapterName.Add(s); - end; - - if (Pos('<a ', parse[i]) > 0) and (Pos('/chapter-list/', parse[i]) > 0) then - if Trim(parse[i + 1]) = 'Last' then - chapterPage := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', - GetVal(parse[i], 'href'), '$1', True), 0); - - if (Pos('class="mng_ifo"', parse[i]) > 0) then - isExtractInfo := True; - if isExtractInfo and - (Pos('class="lst mng_chp"', parse[i]) > 0) then - isExtractInfo := False; - - if isExtractInfo then - begin - // get summary - if (Pos('Subscribe', parse[i]) > 0) then - if (Pos('</b>', parse[i + 1]) > 0) then - mangaInfo.summary := - Trim(BreaksString(HTMLEntitiesFilter(StringFilter(parse[i + 12])))); - - // get authors - if (mangaInfo.authors = '') and - (Trim(parse[i]) = 'Author') then - begin - j := i + 1; - while j < parse.Count - 1 do - begin - if Pos('</p', parse[j]) > 0 then - Break; - if Pos('<', parse[j]) = 0 then - begin - if Trim(parse[j]) = ',' then - mangaInfo.authors := mangaInfo.authors + ', ' - else - mangaInfo.authors := mangainfo.authors + Trim(parse[j]); - end; - Inc(j); - end; - mangaInfo.authors := Trim(RemoveStringBreaks(StringFilter(mangaInfo.authors))); - mangaInfo.authors := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.authors), '', False)); - mangaInfo.authors := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.authors), '', False)); - end; - - // get artists - if (mangaInfo.artists = '') and - (Trim(parse[i]) = 'Artist') then - begin - j := i + 1; - while j < parse.Count - 1 do - begin - if Pos('</p', parse[j]) > 0 then - Break; - if Pos('<', parse[j]) = 0 then - begin - if Trim(parse[j]) = ',' then - mangaInfo.artists := mangaInfo.artists + ', ' - else - mangaInfo.artists := mangainfo.artists + Trim(parse[j]); - end; - Inc(j); - end; - mangaInfo.artists := Trim(RemoveStringBreaks(StringFilter(mangaInfo.artists))); - mangaInfo.artists := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.artists), '', False)); - mangaInfo.artists := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.artists), '', False)); - end; - - // get genres - if (Pos('Category', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('manga-list/category/', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</p>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - end; - - // get the rest of chapter list - if chapterPage > 1 then - begin - for j := 2 to chapterPage do - begin - if GetPage(TObject(Source), mangaInfo.url + 'chapter-list/' + - IntToStr(j) + '/', Reconnect) then - begin - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if Pos('class="lst"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MANGACOW_ID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); - mangaInfo.chapterName.Add(s); - end; - end; - end; - end; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - Source.Free; - end; + function GetMangaCowInfoFromURL: Byte; + var + s: String; + i, j: Cardinal; + isExtractInfo: Boolean = False; + isExtractGenres: Boolean = False; + chapterPage: Cardinal; + begin + mangaInfo.website := WebsiteRoots[MANGACOW_ID, 0]; + mangaInfo.url := FillMangaSiteHost(MANGACOW_ID, URL); + + if mangaInfo.url[Length(mangaInfo.url)] <> '/' then + mangaInfo.url := mangaInfo.url + '/'; + + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + mangaInfo.summary := ''; + chapterPage := 0; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'class') = 'cvr') then + mangaInfo.coverLink := GetVal(parse[i], 'src'); + + // get title + if (Pos('<h1 ', parse[i]) > 0) and + (Pos('class="ttl"', parse[i]) > 0) then + mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); + + // get chapter name and links + if Pos('class="lst"', parse[i]) > 0 then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGACOW_ID, 1], + '', [rfIgnoreCase]); + mangaInfo.chapterLinks.Add(s); + s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); + mangaInfo.chapterName.Add(s); + end; + + if (Pos('<a ', parse[i]) > 0) and (Pos('/chapter-list/', parse[i]) > 0) then + if Trim(parse[i + 1]) = 'Last' then + chapterPage := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', + GetVal(parse[i], 'href'), '$1', True), 0); + + if (Pos('class="mng_ifo"', parse[i]) > 0) then + isExtractInfo := True; + if isExtractInfo and + (Pos('class="lst mng_chp"', parse[i]) > 0) then + isExtractInfo := False; + + if isExtractInfo then + begin + // get summary + if (Pos('Subscribe', parse[i]) > 0) then + if (Pos('</b>', parse[i + 1]) > 0) then + mangaInfo.summary := + Trim(BreaksString(HTMLEntitiesFilter(StringFilter(parse[i + 12])))); + + // get authors + if (mangaInfo.authors = '') and + (Trim(parse[i]) = 'Author') then + begin + j := i + 1; + while j < parse.Count - 1 do + begin + if Pos('</p', parse[j]) > 0 then + Break; + if Pos('<', parse[j]) = 0 then + begin + if Trim(parse[j]) = ',' then + mangaInfo.authors := mangaInfo.authors + ', ' + else + mangaInfo.authors := mangainfo.authors + Trim(parse[j]); + end; + Inc(j); + end; + mangaInfo.authors := Trim(RemoveStringBreaks(StringFilter(mangaInfo.authors))); + mangaInfo.authors := Trim(ReplaceRegExpr('^[\:|\-]', + Trim(mangaInfo.authors), '', False)); + mangaInfo.authors := Trim(ReplaceRegExpr('^[\:|\-]', + Trim(mangaInfo.authors), '', False)); + end; + + // get artists + if (mangaInfo.artists = '') and + (Trim(parse[i]) = 'Artist') then + begin + j := i + 1; + while j < parse.Count - 1 do + begin + if Pos('</p', parse[j]) > 0 then + Break; + if Pos('<', parse[j]) = 0 then + begin + if Trim(parse[j]) = ',' then + mangaInfo.artists := mangaInfo.artists + ', ' + else + mangaInfo.artists := mangainfo.artists + Trim(parse[j]); + end; + Inc(j); + end; + mangaInfo.artists := Trim(RemoveStringBreaks(StringFilter(mangaInfo.artists))); + mangaInfo.artists := Trim(ReplaceRegExpr('^[\:|\-]', + Trim(mangaInfo.artists), '', False)); + mangaInfo.artists := Trim(ReplaceRegExpr('^[\:|\-]', + Trim(mangaInfo.artists), '', False)); + end; + + // get genres + if (Pos('Category', parse[i]) <> 0) then + begin + isExtractGenres := True; + end; + + if isExtractGenres then + begin + if Pos('manga-list/category/', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + TrimLeft(TrimRight(parse[i + 1])) + ', '; + if Pos('</p>', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 3]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + end; + + // get the rest of chapter list + if chapterPage > 1 then + begin + for j := 2 to chapterPage do + begin + if GetPage(TObject(Source), mangaInfo.url + 'chapter-list/' + + IntToStr(j) + '/', Reconnect) then + begin + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + if Pos('class="lst"', parse[i]) > 0 then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[MANGACOW_ID, 1], '', [rfIgnoreCase]); + mangaInfo.chapterLinks.Add(s); + s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); + mangaInfo.chapterName.Add(s); + end; + end; + end; + end; + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + Source.Free; + end; diff --git a/baseunits/includes/Mangacow/names_and_links.inc b/baseunits/includes/Mangacow/names_and_links.inc index 8a5e51369..448dcf02f 100644 --- a/baseunits/includes/Mangacow/names_and_links.inc +++ b/baseunits/includes/Mangacow/names_and_links.inc @@ -1,53 +1,53 @@ - function MangaCowGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - //if Trim(URL) = '0' then - //s := '' - //else - s := IntToStr(StrToInt(URL) + 1) + '/'; - if not GetPage(TObject(Source), WebsiteRoots[MANGACOW_ID, 1] + - MANGACOW_BROWSER + s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a ', parse[i]) > 0) and (Pos('class="mng_det_pop"', parse[i]) > 0) then - if Pos('<br', parse[i + 3]) > 0 then - begin - Result := NO_ERROR; - s := Trim(HTMLEntitiesFilter(StringFilter(GetVal(parse[i], 'title')))); - names.Add(S); - s := StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGACOW_ID, 1], - '', [rfIgnoreCase]); - links.Add(S); - end; - //if (Pos('class="img_wrp', parse.Strings[i]) > 0) then - //begin - // Result:= NO_ERROR; - // s:= StringFilter(GetAttributeValue(GetTagAttribute(parse.Strings[i+1], 'title='))); - // names.Add(HTMLEntitiesFilter(s)); - // s:= StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i+1], 'href=')), WebsiteRoots[MANGACOW_ID,1], '', []); - // links.Add(s); - //end; - end; - Source.Free; + function MangaCowGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + //if Trim(URL) = '0' then + //s := '' + //else + s := IntToStr(StrToInt(URL) + 1) + '/'; + if not GetPage(TObject(Source), WebsiteRoots[MANGACOW_ID, 1] + + MANGACOW_BROWSER + s, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + + for i := 0 to parse.Count - 1 do + begin + if (Pos('<a ', parse[i]) > 0) and (Pos('class="mng_det_pop"', parse[i]) > 0) then + if Pos('<br', parse[i + 3]) > 0 then + begin + Result := NO_ERROR; + s := Trim(HTMLEntitiesFilter(StringFilter(GetVal(parse[i], 'title')))); + names.Add(S); + s := StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGACOW_ID, 1], + '', [rfIgnoreCase]); + links.Add(S); + end; + //if (Pos('class="img_wrp', parse[i]) > 0) then + //begin + // Result:= NO_ERROR; + // s:= StringFilter(GetVal(parse[i+1], 'title')); + // names.Add(HTMLEntitiesFilter(s)); + // s:= StringReplace(GetVal(parse[i+1], 'href'), WebsiteRoots[MANGACOW_ID,1], '', []); + // links.Add(s); + //end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/MangasPROJECT/image_url.inc b/baseunits/includes/MangasPROJECT/image_url.inc index d81be40f4..6b5b21135 100644 --- a/baseunits/includes/MangasPROJECT/image_url.inc +++ b/baseunits/includes/MangasPROJECT/image_url.inc @@ -1,46 +1,46 @@ - function GetMangasPROJECTImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l, ts: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGASPROJECT_ID, URL) + '/#1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('{ path: ', parse.Strings[i]) > 0 then - begin - s := GetString(parse.Strings[i], 'new Array({ path: ', '});'); - s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); - ts := TStringList.Create; - try - ts.DelimitedText := s; - for j := 0 to ts.Count - 1 do - begin - if Pos('http', ts.Strings[j]) > 0 then - manager.container.PageLinks.Add(ts.Strings[j]); - end; - finally - ts.Free; - end; - Break; - end; - end; - end; - - parse.Free; - l.Free; - end; + function GetMangasPROJECTImageURL: Boolean; + var + s: String; + j, i: Cardinal; + l, ts: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MANGASPROJECT_ID, URL) + '/#1'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('{ path: ', parse[i]) > 0 then + begin + s := GetString(parse[i], 'new Array({ path: ', '});'); + s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); + ts := TStringList.Create; + try + ts.DelimitedText := s; + for j := 0 to ts.Count - 1 do + begin + if Pos('http', ts[j]) > 0 then + manager.container.PageLinks.Add(ts[j]); + end; + finally + ts.Free; + end; + Break; + end; + end; + end; + + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MangasPROJECT/manga_information.inc b/baseunits/includes/MangasPROJECT/manga_information.inc index 61b64598e..2d6e2356b 100644 --- a/baseunits/includes/MangasPROJECT/manga_information.inc +++ b/baseunits/includes/MangasPROJECT/manga_information.inc @@ -1,179 +1,178 @@ - function GetMangasPROJECTInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - i, j, n: Cardinal; - numberOfPage: Cardinal = 1; - - procedure ExtractChapter; - begin - if (not isExtractChapter) and (Pos('class="chapter_cont', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('class="nome', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse.Strings[i + 22], 'href="', '"'), - WebsiteRoots[MANGASPROJECT_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - s := StringFilter(HTMLEntitiesFilter(s)); - if Length(s) >= 3 then - begin - s := Copy(s, 1, Length(s) - 2); - s := StringReplace(s, '- ' + #39, '- ', []); - end; - mangaInfo.chapterName.Add(s); - end; - - if (isExtractChapter) and - (Pos('paginacao', parse.Strings[i]) > 0) then - isExtractChapter := False; //bermasalah - end; - - begin - mangaInfo.url := FillMangaSiteHost(MANGASPROJECT_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[MANGASPROJECT_ID, 0]; - mangaInfo.status := '0'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - //Get number of pages - //Don't know why unicode pos not work here - if (Pos('tima', parse.Strings[i]) > 0) and - (Pos('gina', parse.Strings[i]) > 0) then - numberOfPage := StrToInt(GetString(parse.Strings[i - 1], '/page/', '">')); - - // get cover - if Pos('class="side"', parse.Strings[i]) > 0 then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i + 2], 'src='))); - - // get title - if (Pos('class="text', parse.Strings[i]) > 0) then - mangaInfo.title := parse.Strings[i + 3]; - - // get summary - if (Pos('class="text', parse.Strings[i]) <> 0) then - begin - j := i + 9; - while (j < parse.Count) and (Pos('</div>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter( - StringFilter(TrimLeft(parse.Strings[j]))); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - Break; - end; - Inc(j); - end; - end; - - ExtractChapter; - - // get authors - if (Pos('class="text', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(StringFilter(parse.Strings[i + 7])); - - // get artists - if (Pos('class="text', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(StringFilter(parse.Strings[i + 7])); - - // get genres - if (Pos('class="cat', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</br>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse.Strings[i]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - //Extract chapter - if numberOfPage > 1 then - begin - for n := 2 to numberOfPage do - begin - Source.Clear; - s := mangaInfo.url + '/' + IntToStr(n); - if not GetPage(TObject(Source), mangaInfo.url + '/page/' + - IntToStr(n), Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - isExtractChapter := False; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - ExtractChapter; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetMangasPROJECTInfoFromURL: Byte; + var + s: String; + isExtractGenres: Boolean = False; + isExtractChapter: Boolean = False; + i, j, n: Cardinal; + numberOfPage: Cardinal = 1; + + procedure ExtractChapter; + begin + if (not isExtractChapter) and (Pos('class="chapter_cont', parse[i]) > 0) then + isExtractChapter := True; + + // get chapter name and links + if (isExtractChapter) and + (Pos('class="nome', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetString(parse[i + 22], 'href="', '"'), + WebsiteRoots[MANGASPROJECT_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + s := StringFilter(HTMLEntitiesFilter(s)); + if Length(s) >= 3 then + begin + s := Copy(s, 1, Length(s) - 2); + s := StringReplace(s, '- ' + #39, '- ', []); + end; + mangaInfo.chapterName.Add(s); + end; + + if (isExtractChapter) and + (Pos('paginacao', parse[i]) > 0) then + isExtractChapter := False; //bermasalah + end; + + begin + mangaInfo.url := FillMangaSiteHost(MANGASPROJECT_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + mangaInfo.website := WebsiteRoots[MANGASPROJECT_ID, 0]; + mangaInfo.status := '0'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + //Get number of pages + //Don't know why unicode pos not work here + if (Pos('tima', parse[i]) > 0) and + (Pos('gina', parse[i]) > 0) then + numberOfPage := StrToInt(GetString(parse[i - 1], '/page/', '">')); + + // get cover + if Pos('class="side"', parse[i]) > 0 then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); + + // get title + if (Pos('class="text', parse[i]) > 0) then + mangaInfo.title := parse[i + 3]; + + // get summary + if (Pos('class="text', parse[i]) <> 0) then + begin + j := i + 9; + while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter( + StringFilter(TrimLeft(parse[j]))); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + Break; + end; + Inc(j); + end; + end; + + ExtractChapter; + + // get authors + if (Pos('class="text', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(StringFilter(parse[i + 7])); + + // get artists + if (Pos('class="text', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(StringFilter(parse[i + 7])); + + // get genres + if (Pos('class="cat', parse[i]) <> 0) then + begin + isExtractGenres := True; + end; + + if isExtractGenres then + begin + if Pos('', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + TrimLeft(TrimRight(parse[i + 1])) + ', '; + if Pos('</br>', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) then + begin + if Pos('Ongoing', parse[i + 3]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + //Extract chapter + if numberOfPage > 1 then + begin + for n := 2 to numberOfPage do + begin + Source.Clear; + s := mangaInfo.url + '/' + IntToStr(n); + if not GetPage(TObject(Source), mangaInfo.url + '/page/' + + IntToStr(n), Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + isExtractChapter := False; + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + ExtractChapter; + end; + end; + Source.Free; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MangasPROJECT/names_and_links.inc b/baseunits/includes/MangasPROJECT/names_and_links.inc index 8e44d525a..12d3d8ae9 100644 --- a/baseunits/includes/MangasPROJECT/names_and_links.inc +++ b/baseunits/includes/MangasPROJECT/names_and_links.inc @@ -1,42 +1,42 @@ - function MangasPROJECTGetNamesAndLinks: Byte; - var - i: Cardinal; - url: String; - sstream: TStringStream; - parser: TJSONParser; - Data: TJSONData; - begin - Result := INFORMATION_NOT_FOUND; - url := 'http://www.mangasproject.net/AJAX/listaMangas/all'; - if not GetPage(TObject(Source), url, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - sstream := TStringStream.Create(Source.Text); - parser := TJSONParser.Create(sstream); - try - Data := Parser.Parse; - if Data <> nil then - begin - if Data.Count > 0 then - begin - Result := NO_ERROR; - for i := 0 to Data.Count - 1 do - begin - names.Add(Data.Items[i].Items[0].AsString); - links.Add(StringReplace(Data.Items[i].Items[2].AsString, - WebsiteRoots[MangasPROJECT_ID, 1], '', [])); - end; - end; - Data.Free; - end; - except - on E: Exception do - MessageDlg('Exception occured: ', E.Message, mtConfirmation, [mbYes], 0); - end; - sstream.Free; - parser.Free; - Source.Free; - end; \ No newline at end of file + function MangasPROJECTGetNamesAndLinks: Byte; + var + i: Cardinal; + url: String; + sstream: TStringStream; + parser: TJSONParser; + Data: TJSONData; + begin + Result := INFORMATION_NOT_FOUND; + url := 'http://www.mangasproject.net/AJAX/listaMangas/all'; + if not GetPage(TObject(Source), url, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + sstream := TStringStream.Create(Source.Text); + parser := TJSONParser.Create(sstream, [joUTF8]); + try + Data := Parser.Parse; + if Data <> nil then + begin + if Data.Count > 0 then + begin + Result := NO_ERROR; + for i := 0 to Data.Count - 1 do + begin + names.Add(Data.Items[i].Items[0].AsString); + links.Add(StringReplace(Data.Items[i].Items[2].AsString, + WebsiteRoots[MangasPROJECT_ID, 1], '', [])); + end; + end; + Data.Free; + end; + except + on E: Exception do + MessageDlg('Exception occured: ', E.Message, mtConfirmation, [mbYes], 0); + end; + sstream.Free; + parser.Free; + Source.Free; + end; diff --git a/baseunits/includes/MeinManga/chapter_page_number.inc b/baseunits/includes/MeinManga/chapter_page_number.inc index 26ab4b57e..7d977b0c8 100644 --- a/baseunits/includes/MeinManga/chapter_page_number.inc +++ b/baseunits/includes/MeinManga/chapter_page_number.inc @@ -1,37 +1,37 @@ - function GetMeinMangaPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MEINMANGA_ID, URL)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - manager.container.PageLinks.Clear; - for i := parse.Count - 1 downto 0 do - begin - if (Pos('</select>', parse.Strings[i]) > 0) then - begin - manager.container.PageNumber := - StrToInt(TrimLeft(TrimRight(parse.Strings[i - 3]))); - Break; - end; - end; - if manager.container.PageNumber > 0 then - for i := 0 to manager.container.PageNumber - 1 do - manager.container.pageLinks.Add(s + IntToStr(i + 1) + '.html'); - end; - parse.Free; - l.Free; - end; + function GetMeinMangaPageNumber: Boolean; + var + s: String; + i: Integer; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(MEINMANGA_ID, URL)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + manager.container.PageLinks.Clear; + for i := parse.Count - 1 downto 0 do + begin + if (Pos('</select>', parse[i]) > 0) then + begin + manager.container.PageNumber := + StrToInt(TrimLeft(TrimRight(parse[i - 3]))); + Break; + end; + end; + if manager.container.PageNumber > 0 then + for i := 0 to manager.container.PageNumber - 1 do + manager.container.pageLinks.Add(s + IntToStr(i + 1) + '.html'); + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index e75290e21..f6c70564a 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -7,7 +7,7 @@ Parser: THTMLParser; begin s := manager.container.DownloadInfo.SaveTo + - '/' + manager.container.ChapterName.Strings[ + '/' + manager.container.ChapterName[ manager.container.CurrentDownloadChapterPtr] + '/' + Format('%.3d', [workCounter + 1]); // Check to see if a file with similar name was already exist. If so then we @@ -27,7 +27,7 @@ FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; Result := GetPage(TObject(l), - manager.container.PageLinks.Strings[workCounter], + manager.container.PageLinks[workCounter], manager.container.Manager.retryConnect); if Self.Terminated then @@ -50,15 +50,15 @@ if parse.Count > 0 then begin for i := 0 to parse.Count - 1 do - if (Pos('class="pic_fragment"', parse.Strings[i]) > 0) then + if (Pos('class="pic_fragment"', parse[i]) > 0) then begin FHTTP.Clear; SaveImage( manager.container.MangaSiteID, - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')), + GetVal(parse[i], 'src'), CorrectPathSys(manager.container.DownloadInfo.SaveTo + - manager.container.ChapterName.Strings[ + manager.container.ChapterName[ manager.container.CurrentDownloadChapterPtr]), Format('%.3d', [workCounter + 1]) + '_' + IntToStr(prefix), @@ -81,7 +81,7 @@ imageName := Format('%.3d', [workCounter + 1]); Merge2Images( CorrectPathSys(manager.container.DownloadInfo.SaveTo + '/' + - manager.container.ChapterName.Strings[manager.container.CurrentDownloadChapterPtr]), + manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr]), imageName + '_' + IntToStr(prefix - 2) + '.jpg', imageName + '_' + IntToStr(prefix - 1) + '.jpg', imageName + '.jpg'); diff --git a/baseunits/includes/MeinManga/manga_information.inc b/baseunits/includes/MeinManga/manga_information.inc index c2c5cc494..1916af253 100644 --- a/baseunits/includes/MeinManga/manga_information.inc +++ b/baseunits/includes/MeinManga/manga_information.inc @@ -1,170 +1,169 @@ - function GetMeinMangaInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - i, j: Cardinal; - URLs: TStringList; - - procedure GetChapterTitleAndChapterURL; - begin - if (Pos('/default/images/book.jpg', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse.Strings[i + 2], 'href="', '">'), - WebsiteRoots[MEINMANGA_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse.Strings[i + 3])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - end; - - begin - mangaInfo.url := FillMangaSiteHost(MEINMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MEINMANGA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - URLs := TStringList.Create; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse.Strings[i]) = 'img') and - (Pos('/pic/logo/', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('Kurzbeschreibung', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 6; - while (j < parse.Count) and (Pos('</div>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if (s[1] <> '<') then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if (mangaInfo.title = '') and (Pos('class="chrname"', parse.Strings[i]) <> 0) then - mangaInfo.title := Trim(StringFilter(parse.Strings[i + 1])); - - // Get chapter title and url - GetChapterTitleAndChapterURL; - - // get authors - if (i + 4 < parse.Count) and - (Pos('Autor', parse.Strings[i]) <> 0) and - (Pos('valign="top"', parse.Strings[i - 1]) <> 0) then - mangaInfo.authors := Trim(parse.Strings[i + 4]); - - // get artists - if (i + 4 < parse.Count) and - (Pos('Zeichner', parse.Strings[i]) <> 0) and - (Pos('valign="top"', parse.Strings[i - 1]) <> 0) then - mangaInfo.artists := Trim(parse.Strings[i + 4]); - - // get genres - if (i + 4 < parse.Count) and - (Pos('Genre', parse.Strings[i]) <> 0) and - (Pos('valign="top"', parse.Strings[i - 1]) <> 0) then - mangaInfo.genres := Trim(parse.Strings[i + 4]); - - // get status - if (i + 4 < parse.Count) and - (Pos('Status', parse.Strings[i]) <> 0) and - (Pos('valign="top"', parse.Strings[i - 1]) <> 0) then - begin - if Pos('ongoing', parse.Strings[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - // Get number of page - if (URLs.Count = 0) and - (Pos('class="gotopage"', parse.Strings[i]) <> 0) and - (Pos('class="hover"', parse.Strings[i + 2]) <> 0) then - begin - j := i + 3; - while (j < parse.Count) and - ((Pos('class="next"', parse.Strings[j]) = 0) and - (Pos('</div>', parse.Strings[j]) = 0)) do - begin - if (Pos('<a', parse.Strings[j]) <> 0) then - begin - URLs.Add(GetString(parse.Strings[j], 'href="', '">')); - end; - Inc(j); - end; - end; - end; - - // Repeat until we get all chapter information - if URLs.Count > 0 then - begin - for j := 0 to URLs.Count - 1 do - begin - Source := TStringList.Create; - if not GetPage(TObject(Source), URLs.Strings[j], Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - GetChapterTitleAndChapterURL; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - URLs.Free; - Result := NO_ERROR; - end; + function GetMeinMangaInfoFromURL: Byte; + var + s: String; + isExtractSummary: Boolean = True; + i, j: Cardinal; + URLs: TStringList; + + procedure GetChapterTitleAndChapterURL; + begin + if (Pos('/default/images/book.jpg', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetString(parse[i + 2], 'href="', '">'), + WebsiteRoots[MEINMANGA_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(Trim(parse[i + 3])); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + end; + + begin + mangaInfo.url := FillMangaSiteHost(MEINMANGA_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[MEINMANGA_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + URLs := TStringList.Create; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (GetTagName(parse[i]) = 'img') and + (Pos('/pic/logo/', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); + + // get summary + if (Pos('Kurzbeschreibung', parse[i]) <> 0) and + (isExtractSummary) then + begin + j := i + 6; + while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do + begin + s := parse[j]; + if (s[1] <> '<') then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + isExtractSummary := False; + end; + + // get title + if (mangaInfo.title = '') and (Pos('class="chrname"', parse[i]) <> 0) then + mangaInfo.title := Trim(StringFilter(parse[i + 1])); + + // Get chapter title and url + GetChapterTitleAndChapterURL; + + // get authors + if (i + 4 < parse.Count) and + (Pos('Autor', parse[i]) <> 0) and + (Pos('valign="top"', parse[i - 1]) <> 0) then + mangaInfo.authors := Trim(parse[i + 4]); + + // get artists + if (i + 4 < parse.Count) and + (Pos('Zeichner', parse[i]) <> 0) and + (Pos('valign="top"', parse[i - 1]) <> 0) then + mangaInfo.artists := Trim(parse[i + 4]); + + // get genres + if (i + 4 < parse.Count) and + (Pos('Genre', parse[i]) <> 0) and + (Pos('valign="top"', parse[i - 1]) <> 0) then + mangaInfo.genres := Trim(parse[i + 4]); + + // get status + if (i + 4 < parse.Count) and + (Pos('Status', parse[i]) <> 0) and + (Pos('valign="top"', parse[i - 1]) <> 0) then + begin + if Pos('ongoing', parse[i + 4]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + + // Get number of page + if (URLs.Count = 0) and + (Pos('class="gotopage"', parse[i]) <> 0) and + (Pos('class="hover"', parse[i + 2]) <> 0) then + begin + j := i + 3; + while (j < parse.Count) and + ((Pos('class="next"', parse[j]) = 0) and + (Pos('</div>', parse[j]) = 0)) do + begin + if (Pos('<a', parse[j]) <> 0) then + begin + URLs.Add(GetString(parse[j], 'href="', '">')); + end; + Inc(j); + end; + end; + end; + + // Repeat until we get all chapter information + if URLs.Count > 0 then + begin + for j := 0 to URLs.Count - 1 do + begin + Source := TStringList.Create; + if not GetPage(TObject(Source), URLs[j], Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + GetChapterTitleAndChapterURL; + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + URLs.Free; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/MeinManga/names_and_links.inc b/baseunits/includes/MeinManga/names_and_links.inc index 214731d93..b8033c6b5 100644 --- a/baseunits/includes/MeinManga/names_and_links.inc +++ b/baseunits/includes/MeinManga/names_and_links.inc @@ -1,39 +1,39 @@ - function MeinMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MEINMANGA_ID, 1] + - MEINMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/manga/', parse.Strings[i]) > 0) and - (Pos('<img', parse.Strings[i - 2]) > 0) then - begin - Result := NO_ERROR; - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - links.Add(s); - s := StringFilter(Trim(parse.Strings[i + 1])); - s := StringReplace(s, WebsiteRoots[MEINMANGA_ID, 1], '', []); - names.Add(HTMLEntitiesFilter(s)); - end; - end; - Source.Free; + function MeinMangaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[MEINMANGA_ID, 1] + + MEINMANGA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('/manga/', parse[i]) > 0) and + (Pos('<img', parse[i - 2]) > 0) then + begin + Result := NO_ERROR; + s := GetVal(parse[i], 'href'); + links.Add(s); + s := StringFilter(Trim(parse[i + 1])); + s := StringReplace(s, WebsiteRoots[MEINMANGA_ID, 1], '', []); + names.Add(HTMLEntitiesFilter(s)); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/NineManga/chapter_page_number.inc b/baseunits/includes/NineManga/chapter_page_number.inc index a2381d3e9..98c980f23 100644 --- a/baseunits/includes/NineManga/chapter_page_number.inc +++ b/baseunits/includes/NineManga/chapter_page_number.inc @@ -21,16 +21,16 @@ manager.container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin - if (Pos('<select', parse.Strings[i]) > 0) and - (Pos('name="page"', parse.Strings[i]) > 0) and - (Pos('id="page"', parse.Strings[i]) > 0) then + if (Pos('<select', parse[i]) > 0) and + (Pos('name="page"', parse[i]) > 0) and + (Pos('id="page"', parse[i]) > 0) then isExtractPageNumber := True; - if isExtractPageNumber and (Pos('</select', parse.Strings[i]) > 0) then + if isExtractPageNumber and (Pos('</select', parse[i]) > 0) then begin isExtractPageNumber := False; Break; end; - if isExtractPageNumber and (Pos('<option', parse.Strings[i]) > 0) then + if isExtractPageNumber and (Pos('<option', parse[i]) > 0) then Inc(manager.container.PageNumber); end; end; diff --git a/baseunits/includes/NineManga/image_url.inc b/baseunits/includes/NineManga/image_url.inc index fde89a654..814c5b3aa 100644 --- a/baseunits/includes/NineManga/image_url.inc +++ b/baseunits/includes/NineManga/image_url.inc @@ -29,11 +29,11 @@ if parse.Count > 0 then begin for i := 0 to parse.Count - 1 do - if (Pos('<img', parse.Strings[i]) > 0) and - (Pos('class="manga_pic', parse.Strings[i]) > 0) then + if (Pos('<img', parse[i]) > 0) and + (Pos('class="manga_pic', parse[i]) > 0) then begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); + manager.container.PageLinks[workCounter] := + GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/NineManga/manga_information.inc b/baseunits/includes/NineManga/manga_information.inc index 17b8a1ddf..510f104a8 100644 --- a/baseunits/includes/NineManga/manga_information.inc +++ b/baseunits/includes/NineManga/manga_information.inc @@ -40,53 +40,53 @@ begin //manga title if {(mangaInfo.title = '') and} - (Pos('itemprop="name"', parse.Strings[i]) > 0) then + (Pos('itemprop="name"', parse[i]) > 0) then begin - mangaInfo.title := HTMLEntitiesFilter(StringFilter(Trim(parse.Strings[i + 1]))); + mangaInfo.title := HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))); mangaInfo.title := ReplaceRegExpr('\sManga$', mangaInfo.title, '', False); end; //coverlink - if Pos('itemprop="image"', parse.Strings[i]) > 0 then - mangaInfo.coverLink := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); + if Pos('itemprop="image"', parse[i]) > 0 then + mangaInfo.coverLink := GetVal(parse[i], 'src'); //genres - if Pos('itemprop="genre"', parse.Strings[i]) > 0 then + if Pos('itemprop="genre"', parse[i]) > 0 then isExtractGenres := True; - if isExtractGenres and (Pos('</li>', parse.Strings[i]) > 0) then + if isExtractGenres and (Pos('</li>', parse[i]) > 0) then isExtractGenres := False; - if isExtractGenres and (Pos('href="', parse.Strings[i]) > 0) then + if isExtractGenres and (Pos('href="', parse[i]) > 0) then if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse.Strings[i + 1]) + mangaInfo.genres := Trim(parse[i + 1]) else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse.Strings[i + 1]); + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); //author - if Pos('itemprop="author"', parse.Strings[i]) > 0 then - mangaInfo.authors := Trim(parse.Strings[i + 1]); + if Pos('itemprop="author"', parse[i]) > 0 then + mangaInfo.authors := Trim(parse[i + 1]); //status - if Pos('class="red" href="/category/', parse.Strings[i]) > 0 then - if Pos('/category/updated', parse.Strings[i]) > 0 then + if Pos('class="red" href="/category/', parse[i]) > 0 then + if Pos('/category/updated', parse[i]) > 0 then mangaInfo.status := '1' //ongoing else - if Pos('/category/completed', parse.Strings[i]) > 0 then + if Pos('/category/completed', parse[i]) > 0 then mangaInfo.status := '0'; //completed //summary - if Pos('itemprop="description"', parse.Strings[i]) > 0 then - //mangaInfo.summary:= mangaInfo.summary+#13#10+Trim(parse.Strings[i+5]); - mangaInfo.summary := HTMLEntitiesFilter(StringFilter(Trim(parse.Strings[i + 5]))); + if Pos('itemprop="description"', parse[i]) > 0 then + //mangaInfo.summary:= mangaInfo.summary+#13#10+Trim(parse[i+5]); + mangaInfo.summary := HTMLEntitiesFilter(StringFilter(Trim(parse[i + 5]))); ////chapter name and links - //if Pos('class="chapter_list_', parse.Strings[i]) > 0 then + //if Pos('class="chapter_list_', parse[i]) > 0 then //begin // Inc(mangaInfo.numChapter); // mangaInfo.chapterLinks.Add( - // StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), + // StringReplace(GetVal(parse[i], 'href'), // WebsiteRoots[SiteID, 1], '', [rfIgnoreCase])); // mangaInfo.chapterName.Add(HTMLEntitiesFilter( - // StringFilter(Trim(parse.Strings[i + 1])))); + // StringFilter(Trim(parse[i + 1])))); //end; end; @@ -96,7 +96,7 @@ for i := 0 to Source.Count - 1 do begin if (Pos('<a ', Source[i]) > 0) and - (Pos('class="chapter_list_', Source.Strings[i]) > 0) then + (Pos('class="chapter_list_', Source[i]) > 0) then begin Inc(mangaInfo.numChapter); s := StringReplace(GetVal(Source[i], 'href'), WebsiteRoots[SiteID, 1], '', [rfIgnoreCase]); diff --git a/baseunits/includes/NineManga/names_and_links.inc b/baseunits/includes/NineManga/names_and_links.inc index e9e72de8d..1ac1b8aaa 100644 --- a/baseunits/includes/NineManga/names_and_links.inc +++ b/baseunits/includes/NineManga/names_and_links.inc @@ -25,13 +25,13 @@ end; for i := 0 to parse.Count - 1 do begin - if (Pos('class="bookname"', parse.Strings[i]) > 0) then + if (Pos('class="bookname"', parse[i]) > 0) then begin Result := NO_ERROR; links.Add( - StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), + StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[SiteID, 1], '', [rfReplaceAll])); - names.Add(HTMLEntitiesFilter(StringFilter(Trim(parse.Strings[i + 1])))); + names.Add(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); end; end; Source.Free; diff --git a/baseunits/includes/OneManga/chapter_page_number.inc b/baseunits/includes/OneManga/chapter_page_number.inc index 4ab49d02e..ef03ca138 100644 --- a/baseunits/includes/OneManga/chapter_page_number.inc +++ b/baseunits/includes/OneManga/chapter_page_number.inc @@ -21,8 +21,8 @@ for i := 1 to parse.Count - 1 do begin - if (Pos('<select ', parse.Strings[i]) > 0) and - (Pos('class="cbo_wpm_pag"', parse.Strings[i]) > 0) then + if (Pos('<select ', parse[i]) > 0) and + (Pos('class="cbo_wpm_pag"', parse[i]) > 0) then isGetPage := True; if isGetPage and (Pos('</select', parse[i]) > 0) then begin diff --git a/baseunits/includes/PornComix/image_url.inc b/baseunits/includes/PornComix/image_url.inc index a73fabf39..88a7007a6 100644 --- a/baseunits/includes/PornComix/image_url.inc +++ b/baseunits/includes/PornComix/image_url.inc @@ -43,7 +43,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('class="pic', parse[i]) <> 0) then begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end @@ -54,7 +54,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('id="show_image', parse[i]) <> 0) then begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/RedHawkScans/chapter_page_number.inc b/baseunits/includes/RedHawkScans/chapter_page_number.inc index 5bcff0140..1c8ffe43a 100644 --- a/baseunits/includes/RedHawkScans/chapter_page_number.inc +++ b/baseunits/includes/RedHawkScans/chapter_page_number.inc @@ -1,33 +1,33 @@ - function GetRedHawkScansPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(REDHAWKSCANS_ID, URL) + 'page/1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 1 to parse.Count - 1 do - begin - if (Pos('class="topbar_right"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i + 4]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetRedHawkScansPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(REDHAWKSCANS_ID, URL) + 'page/1'); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 1 to parse.Count - 1 do + begin + if (Pos('class="topbar_right"', parse[i]) > 0) then + begin + s := parse[i + 4]; + manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/RedHawkScans/directory_page_number.inc b/baseunits/includes/RedHawkScans/directory_page_number.inc index 881393194..bfcaec06b 100644 --- a/baseunits/includes/RedHawkScans/directory_page_number.inc +++ b/baseunits/includes/RedHawkScans/directory_page_number.inc @@ -1,37 +1,37 @@ - function GetRedHawkScansDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[REDHAWKSCANS_ID, 1] + - REDHAWKSCANS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('Last ', parse.Strings[i]) > 0) and - (Pos('class="gbutton', parse.Strings[i - 1]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse.Strings[i - 1], '/list/', '/"'))); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetRedHawkScansDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[REDHAWKSCANS_ID, 1] + + REDHAWKSCANS_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('Last ', parse[i]) > 0) and + (Pos('class="gbutton', parse[i - 1]) > 0) then + begin + s := TrimRight(TrimLeft(GetString(parse[i - 1], '/list/', '/"'))); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/RedHawkScans/image_url.inc b/baseunits/includes/RedHawkScans/image_url.inc index 4cc09c97c..49df161f5 100644 --- a/baseunits/includes/RedHawkScans/image_url.inc +++ b/baseunits/includes/RedHawkScans/image_url.inc @@ -1,32 +1,32 @@ - function GetRedHawkScansImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(REDHAWKSCANS_ID, URL) + 'page/' + - IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="open"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src=')); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetRedHawkScansImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(REDHAWKSCANS_ID, URL) + 'page/' + + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="open"', parse[i]) > 0) then + begin + manager.container.PageLinks[workCounter] := + GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/RedHawkScans/manga_information.inc b/baseunits/includes/RedHawkScans/manga_information.inc index 4f648bafd..2a9c2e5c8 100644 --- a/baseunits/includes/RedHawkScans/manga_information.inc +++ b/baseunits/includes/RedHawkScans/manga_information.inc @@ -1,117 +1,116 @@ - function GetRedHawkScansInfoFromURL: Byte; - var - isExtractChapter: Boolean = False; - s: String; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(REDHAWKSCANS_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[REDHAWKSCANS_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (GetTagName(parse.Strings[i]) = 'img') and - (Pos('class="thumbnail"', parse.Strings[i - 2]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('Description', parse.Strings[i]) <> 0) and - (Pos('<b', parse.Strings[i - 1]) <> 0) then - begin - j := i + 2; - while (j < parse.Count) and (Pos('</li>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get title - if (Pos('Title', parse.Strings[i]) <> 0) and - (Pos('<b', parse.Strings[i - 1]) <> 0) and - (mangaInfo.title = '') then - mangaInfo.title := StringReplace(TrimLeft(StringFilter(parse.Strings[i + 2])), - ': ', '', []); - - if (not isExtractChapter) and - (Pos('All chapters available for', parse.Strings[i]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('class="element"', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse.Strings[i + 3], 'href="', '"'), - WebsiteRoots[REDHAWKSCANS_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 4]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 2 < parse.Count) and (Pos('Author', parse.Strings[i]) <> 0) and - (Pos('<b', parse.Strings[i - 1]) <> 0) then - mangaInfo.authors := StringReplace(TrimLeft(parse.Strings[i + 2]), ': ', '', []); - - // get artists - if (i + 2 < parse.Count) and (Pos('Artist', parse.Strings[i]) <> 0) and - (Pos('<b', parse.Strings[i - 1]) <> 0) then - mangaInfo.artists := StringReplace(TrimLeft(parse.Strings[i + 2]), ': ', '', []); - - // get genres - if (Pos('Genre', parse.Strings[i]) <> 0) and - (Pos('<b', parse.Strings[i - 1]) <> 0) then - mangaInfo.genres := StringReplace(TrimLeft(parse.Strings[i + 2]), ': ', '', []); - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse.Strings[i]) <> 0) and - (Pos('<b', parse.Strings[i - 1]) <> 0) then - begin - if Pos('Ongoing', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetRedHawkScansInfoFromURL: Byte; + var + isExtractChapter: Boolean = False; + s: String; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(REDHAWKSCANS_ID, URL);// + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[REDHAWKSCANS_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (GetTagName(parse[i]) = 'img') and + (Pos('class="thumbnail"', parse[i - 2]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); + + // get summary + if (Pos('Description', parse[i]) <> 0) and + (Pos('<b', parse[i - 1]) <> 0) then + begin + j := i + 2; + while (j < parse.Count) and (Pos('</li>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + end; + + // get title + if (Pos('Title', parse[i]) <> 0) and + (Pos('<b', parse[i - 1]) <> 0) and + (mangaInfo.title = '') then + mangaInfo.title := StringReplace(TrimLeft(StringFilter(parse[i + 2])), + ': ', '', []); + + if (not isExtractChapter) and + (Pos('All chapters available for', parse[i]) > 0) then + isExtractChapter := True; + + if (isExtractChapter) and + (Pos('class="element"', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetString(parse[i + 3], 'href="', '"'), + WebsiteRoots[REDHAWKSCANS_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 4]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + + // get authors + if (i + 2 < parse.Count) and (Pos('Author', parse[i]) <> 0) and + (Pos('<b', parse[i - 1]) <> 0) then + mangaInfo.authors := StringReplace(TrimLeft(parse[i + 2]), ': ', '', []); + + // get artists + if (i + 2 < parse.Count) and (Pos('Artist', parse[i]) <> 0) and + (Pos('<b', parse[i - 1]) <> 0) then + mangaInfo.artists := StringReplace(TrimLeft(parse[i + 2]), ': ', '', []); + + // get genres + if (Pos('Genre', parse[i]) <> 0) and + (Pos('<b', parse[i - 1]) <> 0) then + mangaInfo.genres := StringReplace(TrimLeft(parse[i + 2]), ': ', '', []); + + // get status + if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) and + (Pos('<b', parse[i - 1]) <> 0) then + begin + if Pos('Ongoing', parse[i + 2]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/RedHawkScans/names_and_links.inc b/baseunits/includes/RedHawkScans/names_and_links.inc index 1c8e9301a..cc5394a2f 100644 --- a/baseunits/includes/RedHawkScans/names_and_links.inc +++ b/baseunits/includes/RedHawkScans/names_and_links.inc @@ -1,39 +1,39 @@ - function RedHawkScansGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[REDHAWKSCANS_ID, 1] + - REDHAWKSCANS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="title"', parse.Strings[i]) > 0) and - (Pos('<a', parse.Strings[i + 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], - 'href="')), WebsiteRoots[REDHAWKSCANS_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; + function RedHawkScansGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[REDHAWKSCANS_ID, 1] + + REDHAWKSCANS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="title"', parse[i]) > 0) and + (Pos('<a', parse[i + 1]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); + names.Add(HTMLEntitiesFilter(s)); + s := StringReplace(GetVal(parse[i + 1], + 'href="'), WebsiteRoots[REDHAWKSCANS_ID, 1], '', []); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/ScanManga/image_url.inc b/baseunits/includes/ScanManga/image_url.inc index 2f861226a..b5550cc6b 100644 --- a/baseunits/includes/ScanManga/image_url.inc +++ b/baseunits/includes/ScanManga/image_url.inc @@ -1,45 +1,45 @@ - function GetScanMangaImageURL: Boolean; - var - s, h: String; - i, j: Cardinal; - l, t: TStringList; - - begin - l := TStringList.Create; - t := TStringList.Create; - - s := DecodeUrl(FillMangaSiteHost(SCANMANGA_ID, URL)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - - for i := 0 to l.Count - 1 do - begin - if (Pos('$(''#image_lel'')', l.strings[i]) > 0) and - (Pos('[id_page]', l.Strings[i]) > 0) then - begin - s := Trim(l.Strings[i]); - s := GetString(s, '''src'',''', '''+'); - h := s; - Break; - end; - end; - manager.container.PageLinks.Clear; - for i := 0 to l.Count - 1 do - begin - if (Pos('var c = new Array;', l.strings[i]) > 0) and - (Pos(';check = false;', l.Strings[i]) > 0) then - begin - s := Trim(l.Strings[i]); - s := GetString(s, 'var c = new Array;', ';check = false;'); - t.Delimiter := ';'; - t.DelimitedText := s; - for j := 0 to t.Count - 1 do - if Pos(']="', t.Strings[j]) > 0 then - manager.container.PageLinks.Add(h + GetString(t.Strings[j], '="', '"')); - Break; - end; - end; - t.Free; - l.Free; - end; + function GetScanMangaImageURL: Boolean; + var + s, h: String; + i, j: Cardinal; + l, t: TStringList; + + begin + l := TStringList.Create; + t := TStringList.Create; + + s := DecodeUrl(FillMangaSiteHost(SCANMANGA_ID, URL)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + + for i := 0 to l.Count - 1 do + begin + if (Pos('$(''#image_lel'')', l[i]) > 0) and + (Pos('[id_page]', l[i]) > 0) then + begin + s := Trim(l[i]); + s := GetString(s, '''src'',''', '''+'); + h := s; + Break; + end; + end; + manager.container.PageLinks.Clear; + for i := 0 to l.Count - 1 do + begin + if (Pos('var c = new Array;', l[i]) > 0) and + (Pos(';check = false;', l[i]) > 0) then + begin + s := Trim(l[i]); + s := GetString(s, 'var c = new Array;', ';check = false;'); + t.Delimiter := ';'; + t.DelimitedText := s; + for j := 0 to t.Count - 1 do + if Pos(']="', t[j]) > 0 then + manager.container.PageLinks.Add(h + GetString(t[j], '="', '"')); + Break; + end; + end; + t.Free; + l.Free; + end; diff --git a/baseunits/includes/ScanManga/manga_information.inc b/baseunits/includes/ScanManga/manga_information.inc index a41ef9c99..0cc9a207c 100644 --- a/baseunits/includes/ScanManga/manga_information.inc +++ b/baseunits/includes/ScanManga/manga_information.inc @@ -1,129 +1,129 @@ - function GetScanMangaInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(SCANMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[SCANMANGA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('<img itemprop="image"', parse.Strings[i]) > 0) then - begin - mangaInfo.coverLink := - CorrectURL(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - //mangaInfo.coverLink:= StringReplace(mangaInfo.coverLink, ':8080/', '/', []); - end; - - // get title - if (Pos('id=''ambubble''', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft(TrimRight(HTMLEntitiesFilter(parse.Strings[i]))); - - // get chapter name and links - if (Pos('class=''chapitre_nom''', parse.Strings[i]) > 0) and - (Pos('<strong>', parse.Strings[i + 1]) > 0) then - begin - s := Trim(RemoveSymbols(parse.Strings[i + 2])); - if (Pos('<', parse.Strings[i + 6]) = 0) and (Pos('>', parse.Strings[i + 6]) = 0) then - s := s + ' ' + Trim(RemoveSymbols(parse.Strings[i + 6])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - if (Pos('/lecture-en-ligne/', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')), - WebsiteRoots[SCANMANGA_ID, 1], '', []); - s := StringReplace(TrimLeft(TrimRight(s)), '"', '', [rfReplaceAll]); - mangaInfo.chapterLinks.Add(s); - end; - - // get summary - if (Pos('itemprop="description">', parse.Strings[i]) <> 0) then - begin - j := i + 1; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 2 < parse.Count) and - (Pos('itemprop="author"', parse.Strings[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - - // get artists - //if (i+5<parse.Count) AND (Pos('Illustrateur :', parse.Strings[i])<>0) then - // mangaInfo.artists:= StringFilter(TrimLeft(TrimRight(parse.Strings[i+5]))); - - // get genres - if (Pos('itemprop="genre"', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := mangaInfo.genres + HTMLEntitiesFilter( - TrimLeft(TrimRight(parse.Strings[i + 1]))) + ', '; - end; - - if isExtractGenres then - begin - if Pos('class=''tTip''>', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - HTMLEntitiesFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))) + ', '; - if Pos('itemprop="editor"', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 11 < parse.Count) and (Pos('itemprop="editor"', parse.Strings[i]) <> 0) then - begin - if (Pos('Termin', parse.Strings[i + 5]) <> 0) or - (Pos('One Shot', parse.Strings[i + 5]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetScanMangaInfoFromURL: Byte; + var + s: String; + isExtractGenres: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(SCANMANGA_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[SCANMANGA_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (mangaInfo.coverLink = '') and + (Pos('<img itemprop="image"', parse[i]) > 0) then + begin + mangaInfo.coverLink := + CorrectURL(GetVal(parse[i], 'src')); + //mangaInfo.coverLink:= StringReplace(mangaInfo.coverLink, ':8080/', '/', []); + end; + + // get title + if (Pos('id=''ambubble''', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := TrimLeft(TrimRight(HTMLEntitiesFilter(parse[i]))); + + // get chapter name and links + if (Pos('class=''chapitre_nom''', parse[i]) > 0) and + (Pos('<strong>', parse[i + 1]) > 0) then + begin + s := Trim(RemoveSymbols(parse[i + 2])); + if (Pos('<', parse[i + 6]) = 0) and (Pos('>', parse[i + 6]) = 0) then + s := s + ' ' + Trim(RemoveSymbols(parse[i + 6])); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); + end; + if (Pos('/lecture-en-ligne/', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[SCANMANGA_ID, 1], '', []); + s := StringReplace(TrimLeft(TrimRight(s)), '"', '', [rfReplaceAll]); + mangaInfo.chapterLinks.Add(s); + end; + + // get summary + if (Pos('itemprop="description">', parse[i]) <> 0) then + begin + j := i + 1; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + end; + + // get authors + if (i + 2 < parse.Count) and + (Pos('itemprop="author"', parse[i]) <> 0) then + mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); + + // get artists + //if (i+5<parse.Count) AND (Pos('Illustrateur :', parse[i])<>0) then + // mangaInfo.artists:= StringFilter(TrimLeft(TrimRight(parse[i+5]))); + + // get genres + if (Pos('itemprop="genre"', parse[i]) <> 0) then + begin + isExtractGenres := True; + mangaInfo.genres := mangaInfo.genres + HTMLEntitiesFilter( + TrimLeft(TrimRight(parse[i + 1]))) + ', '; + end; + + if isExtractGenres then + begin + if Pos('class=''tTip''>', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + HTMLEntitiesFilter(TrimLeft(TrimRight(parse[i + 1]))) + ', '; + if Pos('itemprop="editor"', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 11 < parse.Count) and (Pos('itemprop="editor"', parse[i]) <> 0) then + begin + if (Pos('Termin', parse[i + 5]) <> 0) or + (Pos('One Shot', parse[i + 5]) <> 0) then + mangaInfo.status := '0' // completed + else + mangaInfo.status := '1'; // ongoing + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/ScanManga/names_and_links.inc b/baseunits/includes/ScanManga/names_and_links.inc index 93c8f6a58..80ddfb7ec 100644 --- a/baseunits/includes/ScanManga/names_and_links.inc +++ b/baseunits/includes/ScanManga/names_and_links.inc @@ -1,47 +1,47 @@ - function ScanMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SCANMANGA_ID, 1] + - SCANMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (i + 4 < parse.Count - 1) and - (Pos('<li>', parse.Strings[i]) > 0) and - (Pos('</a>', parse.Strings[i + 3]) > 0) and - (Pos('</li>', parse.Strings[i + 4]) > 0) then - begin - Result := NO_ERROR; - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')); - if (Length(s) > 1) and - (Pos('/scanlation/Shonen.html', s) = 0) and - (Pos('/scanlation/Shojo.html', s) = 0) and - (Pos('/scanlation/Josei.html', s) = 0) and - (Pos('/scanlation/Seinen.html', s) = 0) then - begin - links.Add(StringReplace(s, WebsiteRoots[SCANMANGA_ID, 1], '', [])); - s := StringFilter(parse.Strings[i + 2]); - names.Add(HTMLEntitiesFilter(s)); - end; - end; - end; - Source.Free; + function ScanMangaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[SCANMANGA_ID, 1] + + SCANMANGA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (i + 4 < parse.Count - 1) and + (Pos('<li>', parse[i]) > 0) and + (Pos('</a>', parse[i + 3]) > 0) and + (Pos('</li>', parse[i + 4]) > 0) then + begin + Result := NO_ERROR; + s := GetVal(parse[i + 1], 'href'); + if (Length(s) > 1) and + (Pos('/scanlation/Shonen.html', s) = 0) and + (Pos('/scanlation/Shojo.html', s) = 0) and + (Pos('/scanlation/Josei.html', s) = 0) and + (Pos('/scanlation/Seinen.html', s) = 0) then + begin + links.Add(StringReplace(s, WebsiteRoots[SCANMANGA_ID, 1], '', [])); + s := StringFilter(parse[i + 2]); + names.Add(HTMLEntitiesFilter(s)); + end; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/SenManga/chapter_page_number.inc b/baseunits/includes/SenManga/chapter_page_number.inc index 982262947..08fba26a7 100644 --- a/baseunits/includes/SenManga/chapter_page_number.inc +++ b/baseunits/includes/SenManga/chapter_page_number.inc @@ -1,43 +1,43 @@ - function GetSenMangaPageNumber: Boolean; - var - s: String; - i: LongInt; - l: TStringList; - isStartGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(URL); - s := FillMangaSiteHost(SENMANGA_ID, s); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - if Result then - begin - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - manager.container.PageNumber := 0; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (Pos('cbo_wpm_pag', parse[i]) > 0) then - isStartGetPageNumber := True; - if isStartGetPageNumber then - begin - if GetTagName(parse[i]) = '/select' then - Break - else - if GetTagName(parse[i]) = 'option' then - Inc(manager.container.PageNumber); - end; - end; - end; - parse.Free; - l.Free; - end; + function GetSenMangaPageNumber: Boolean; + var + s: String; + i: LongInt; + l: TStringList; + isStartGetPageNumber: Boolean = False; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(URL); + s := FillMangaSiteHost(SENMANGA_ID, s); + Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + if Result then + begin + Parser := THTMLParser.Create(l.Text); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + + manager.container.PageNumber := 0; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + begin + if (GetTagName(parse[i]) = 'select') and (Pos('cbo_wpm_pag', parse[i]) > 0) then + isStartGetPageNumber := True; + if isStartGetPageNumber then + begin + if GetTagName(parse[i]) = '/select' then + Break + else + if GetTagName(parse[i]) = 'option' then + Inc(manager.container.PageNumber); + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/SenManga/image_url.inc b/baseunits/includes/SenManga/image_url.inc index 112afb0aa..0a2f3e557 100644 --- a/baseunits/includes/SenManga/image_url.inc +++ b/baseunits/includes/SenManga/image_url.inc @@ -1,38 +1,38 @@ - function GetSenMangaImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - try - Result := GetPage(TObject(l), - FillMangaSiteHost(SENMANGA_ID, URL + '/' + IntToStr(workCounter + 1) + '/'), - manager.container.Manager.retryConnect); - if Result then - begin - parse := TStringList.Create; - try - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = 'img_mng_enl') then - begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - finally - parse.Free; - end; - end; - finally - l.Free; - end; - end; + function GetSenMangaImageURL: Boolean; + var + i: Integer; + l: TStringList; + begin + l := TStringList.Create; + try + Result := GetPage(TObject(l), + FillMangaSiteHost(SENMANGA_ID, URL + '/' + IntToStr(workCounter + 1) + '/'), + manager.container.Manager.retryConnect); + if Result then + begin + parse := TStringList.Create; + try + Parser := THTMLParser.Create(l.Text); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + if (GetTagName(parse[i]) = 'img') and + (GetVal(parse[i], 'id') = 'img_mng_enl') then + begin + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + finally + parse.Free; + end; + end; + finally + l.Free; + end; + end; diff --git a/baseunits/includes/SenManga/manga_information.inc b/baseunits/includes/SenManga/manga_information.inc index 6b1491bfa..07b07c926 100644 --- a/baseunits/includes/SenManga/manga_information.inc +++ b/baseunits/includes/SenManga/manga_information.inc @@ -1,132 +1,132 @@ - function GetSenMangaInfoFromURL: Byte; - var - i, j, p: Integer; - - procedure GetChapters(const ln: Integer); - begin - if (GetTagName(parse[ln]) = 'a') and (GetVal(parse[ln], 'class') = 'lst') then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[ln], 'href')); - mangaInfo.chapterName.Add(parse[ln + 3]); - end; - end; - - begin - mangaInfo.website := WebsiteRoots[SENMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(SENMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.status := ''; - p := 0; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if (GetTagName(parse[i]) = 'h1') and (GetVal(parse[i], 'class') = 'ttl') then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - //cover - if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'class') = 'cvr') then - mangaInfo.coverLink := FixURL(GetVal(parse[i], 'src')); - //summary - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'det') then - mangaInfo.summary := parse[i + 3]; - - if (GetTagName(parse[i]) = 'b') then - begin - //author - if Trim(parse[i + 1]) = 'Author' then - mangaInfo.authors := parse[i + 5]; - //artist - if Trim(parse[i + 1]) = 'Artist' then - mangaInfo.artists := parse[i + 5]; - //status - if mangaInfo.status = '' then - if Trim(parse[i + 1]) = 'Status' then - begin - mangaInfo.status := Trim(parse[i + 5]); - if mangaInfo.status = 'Completed' then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end; - //genres - if Trim(parse[i + 1]) = 'Category' then - for j := i + 3 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if GetTagName(parse[j]) = 'a' then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[j + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[j + 1]); - end; - end; - end; - - //chapters - GetChapters(i); - - //chapterpage - if (GetTagName(parse[i]) = 'a') and (Pos('/chapter-list/', parse[i]) > 0) then - if Trim(parse[i + 1]) = 'Last' then - begin - j := StrToIntDef(ReplaceRegExpr( - '^.*/chapter-list/(\d+)/?$', GetVal(parse[i], 'href'), '$1', True), 0); - if j > p then p := j; - end; - end; - - //get the rest of chapters from another page - if p > 1 then - begin - for i := 2 to p do - begin - s := mangaInfo.url; - if s[Length(s)] <> '/' then s := s + '/'; - s := s + 'chapter-list/' + IntToStr(i) + '/'; - if GetPage(TObject(Source), s, Reconnect) then - begin - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - if parse.Count > 0 then - for j := 0 to parse.Count - 1 do - GetChapters(j); - end; - end; - end; - Source.Free; - - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end - else - Result := INFORMATION_NOT_FOUND; - end; + function GetSenMangaInfoFromURL: Byte; + var + i, j, p: Integer; + + procedure GetChapters(const ln: Integer); + begin + if (GetTagName(parse[ln]) = 'a') and (GetVal(parse[ln], 'class') = 'lst') then + begin + mangaInfo.chapterLinks.Add(GetVal(parse[ln], 'href')); + mangaInfo.chapterName.Add(parse[ln + 3]); + end; + end; + + begin + mangaInfo.website := WebsiteRoots[SENMANGA_ID, 0]; + mangaInfo.url := FillMangaSiteHost(SENMANGA_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + Parser := THTMLParser.Create(Source.Text); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + mangaInfo.genres := ''; + mangaInfo.status := ''; + p := 0; + for i := 0 to parse.Count - 1 do + begin + //title + if mangaInfo.title = '' then + if (GetTagName(parse[i]) = 'h1') and (GetVal(parse[i], 'class') = 'ttl') then + mangaInfo.title := CommonStringFilter(parse[i + 1]); + //cover + if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'class') = 'cvr') then + mangaInfo.coverLink := FixURL(GetVal(parse[i], 'src')); + //summary + if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'det') then + mangaInfo.summary := parse[i + 3]; + + if (GetTagName(parse[i]) = 'b') then + begin + //author + if Trim(parse[i + 1]) = 'Author' then + mangaInfo.authors := parse[i + 5]; + //artist + if Trim(parse[i + 1]) = 'Artist' then + mangaInfo.artists := parse[i + 5]; + //status + if mangaInfo.status = '' then + if Trim(parse[i + 1]) = 'Status' then + begin + mangaInfo.status := Trim(parse[i + 5]); + if mangaInfo.status = 'Completed' then + mangaInfo.status := '0' + else + mangaInfo.status := '1'; + end; + //genres + if Trim(parse[i + 1]) = 'Category' then + for j := i + 3 to parse.Count - 1 do + begin + if GetTagName(parse[j]) = '/p' then + Break + else + if GetTagName(parse[j]) = 'a' then + begin + if mangaInfo.genres = '' then + mangaInfo.genres := Trim(parse[j + 1]) + else + mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[j + 1]); + end; + end; + end; + + //chapters + GetChapters(i); + + //chapterpage + if (GetTagName(parse[i]) = 'a') and (Pos('/chapter-list/', parse[i]) > 0) then + if Trim(parse[i + 1]) = 'Last' then + begin + j := StrToIntDef(ReplaceRegExpr( + '^.*/chapter-list/(\d+)/?$', GetVal(parse[i], 'href'), '$1', True), 0); + if j > p then p := j; + end; + end; + + //get the rest of chapters from another page + if p > 1 then + begin + for i := 2 to p do + begin + s := mangaInfo.url; + if s[Length(s)] <> '/' then s := s + '/'; + s := s + 'chapter-list/' + IntToStr(i) + '/'; + if GetPage(TObject(Source), s, Reconnect) then + begin + Parser := THTMLParser.Create(Source.Text); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + if parse.Count > 0 then + for j := 0 to parse.Count - 1 do + GetChapters(j); + end; + end; + end; + Source.Free; + + InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); + Result := NO_ERROR; + end + else + Result := INFORMATION_NOT_FOUND; + end; diff --git a/baseunits/includes/SenManga/names_and_links.inc b/baseunits/includes/SenManga/names_and_links.inc index f388627b1..e9c8c7ba4 100644 --- a/baseunits/includes/SenManga/names_and_links.inc +++ b/baseunits/includes/SenManga/names_and_links.inc @@ -1,35 +1,35 @@ - function SenMangaGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SENMANGA_ID, 1] + - '/directory/all/any/last-added/' + IntToStr(StrToInt(URL) + 1) + '/', 3) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'lst mng_det_pop') then - begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter(GetVal(parse[i], 'title'))); - end; - Result := NO_ERROR; - end; - end; + function SenMangaGetNamesAndLinks: Byte; + var + i: Integer; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[SENMANGA_ID, 1] + + '/directory/all/any/last-added/' + IntToStr(StrToInt(URL) + 1) + '/', 3) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + Parser := THTMLParser.Create(Source.Text); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + parse.Clear; + Parser.Exec; + finally + Parser.Free; + end; + Source.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'lst mng_det_pop') then + begin + links.Add(GetVal(parse[i], 'href')); + names.Add(CommonStringFilter(GetVal(parse[i], 'title'))); + end; + Result := NO_ERROR; + end; + end; diff --git a/baseunits/includes/Starkana/chapter_page_number.inc b/baseunits/includes/Starkana/chapter_page_number.inc index 63b3ded51..554ef1ea1 100644 --- a/baseunits/includes/Starkana/chapter_page_number.inc +++ b/baseunits/includes/Starkana/chapter_page_number.inc @@ -1,32 +1,32 @@ - function GetStarkanaPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL)), - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('id="page_switch', parse[i]) > 0) then - isGetPageNumber := True; - if isGetPageNumber and (Pos('</select', parse[i]) > 0) then - Break; - if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; + function GetStarkanaPageNumber: Boolean; + var + i: Integer; + l: TStringList; + isGetPageNumber: Boolean = False; + begin + l := TStringList.Create; + parse := TStringList.Create; + Result := GetPage(TObject(l), + DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL)), + manager.container.Manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (Pos('<select', parse[i]) > 0) and (Pos('id="page_switch', parse[i]) > 0) then + isGetPageNumber := True; + if isGetPageNumber and (Pos('</select', parse[i]) > 0) then + Break; + if isGetPageNumber and (Pos('<option', parse[i]) > 0) then + Inc(manager.container.PageNumber); + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Starkana/image_url.inc b/baseunits/includes/Starkana/image_url.inc index 0f7c072b7..77ac25600 100644 --- a/baseunits/includes/Starkana/image_url.inc +++ b/baseunits/includes/Starkana/image_url.inc @@ -1,29 +1,29 @@ - function GetStarkanaImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(workCounter + 1)), - manager.container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and (Pos('class="dyn', parse[i]) > 0) and - (Pos('style="cursor: pointer', parse[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetStarkanaImageURL: Boolean; + var + i: Integer; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(workCounter + 1)), + manager.container.manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('<img', parse[i]) > 0) and (Pos('class="dyn', parse[i]) > 0) and + (Pos('style="cursor: pointer', parse[i]) > 0) then + begin + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Starkana/manga_information.inc b/baseunits/includes/Starkana/manga_information.inc index 0870821d3..e0a4c55f4 100644 --- a/baseunits/includes/Starkana/manga_information.inc +++ b/baseunits/includes/Starkana/manga_information.inc @@ -1,93 +1,93 @@ - function GetStarkanaInfoFromURL: Byte; - var - i: Integer; - isExtractGenres: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[STARKANA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(STARKANA_ID, URL) + '?mature_confirm=1'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - - mangaInfo.genres := ''; - - for i := 0 to parse.Count - 1 do - begin - //cover - if (Pos('<a', parse[i]) > 0) and (Pos('class="olol', parse[i]) > 0) then - if (Pos('<img', parse[i + 1]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 1], 'src'); - - //title - if Pos('Title(s):', parse[i]) > 0 then - mangaInfo.title := CommonStringFilter(parse[i + 5]); - - //author(s) - if Pos('Author(s):', parse[i]) > 0 then - mangaInfo.authors := CommonStringFilter(parse[i + 7]); - - //artist(s) - if Pos('Artist(s):', parse[i]) > 0 then - mangaInfo.artists := CommonStringFilter(parse[i + 7]); - - //status - if Pos('Status:', parse[i]) > 0 then - if (Trim(LowerCase(parse[i + 7])) = 'ongoing') then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - - //summary - if Pos('Summary:', parse[i]) > 0 then - if Pos('valign="top"', parse[i - 2]) > 0 then - mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 7])); - - //genres - if Pos('Genres:', parse[i]) > 0 then - isExtractGenres := True; - if isExtractGenres and (Pos('</tr', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('<', parse[i]) = 0) and - (Pos('Genres:', parse[i]) = 0) then - begin - parse[i] := Trim(parse[i]); - if parse[i] = ',' then - parse[i] := ', '; - mangaInfo.genres := mangaInfo.genres + parse[i]; - end; - - //chapter(s) - if Pos('class="download-link', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); // 1, 3, 7 - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[STARKANA_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(CommonStringFilter( - Trim(parse[i + 1]) + ' ' + Trim(parse[i + 3]) + ' ' + Trim(parse[i + 7]))); - end; - end; - - //invert chapter(s) - if mangaInfo.chapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterLinks); - InvertStrings(mangaInfo.chapterName); - end; - Result := NO_ERROR; - end; + function GetStarkanaInfoFromURL: Byte; + var + i: Integer; + isExtractGenres: Boolean = False; + begin + mangaInfo.website := WebsiteRoots[STARKANA_ID, 0]; + mangaInfo.url := FillMangaSiteHost(STARKANA_ID, URL) + '?mature_confirm=1'; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + Source.Free; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + + mangaInfo.genres := ''; + + for i := 0 to parse.Count - 1 do + begin + //cover + if (Pos('<a', parse[i]) > 0) and (Pos('class="olol', parse[i]) > 0) then + if (Pos('<img', parse[i + 1]) > 0) then + mangaInfo.coverLink := GetVal(parse[i + 1], 'src'); + + //title + if Pos('Title(s):', parse[i]) > 0 then + mangaInfo.title := CommonStringFilter(parse[i + 5]); + + //author(s) + if Pos('Author(s):', parse[i]) > 0 then + mangaInfo.authors := CommonStringFilter(parse[i + 7]); + + //artist(s) + if Pos('Artist(s):', parse[i]) > 0 then + mangaInfo.artists := CommonStringFilter(parse[i + 7]); + + //status + if Pos('Status:', parse[i]) > 0 then + if (Trim(LowerCase(parse[i + 7])) = 'ongoing') then + mangaInfo.status := '1' + else + mangaInfo.status := '0'; + + //summary + if Pos('Summary:', parse[i]) > 0 then + if Pos('valign="top"', parse[i - 2]) > 0 then + mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 7])); + + //genres + if Pos('Genres:', parse[i]) > 0 then + isExtractGenres := True; + if isExtractGenres and (Pos('</tr', parse[i]) > 0) then + isExtractGenres := False; + if isExtractGenres and (Pos('<', parse[i]) = 0) and + (Pos('Genres:', parse[i]) = 0) then + begin + parse[i] := Trim(parse[i]); + if parse[i] = ',' then + parse[i] := ', '; + mangaInfo.genres := mangaInfo.genres + parse[i]; + end; + + //chapter(s) + if Pos('class="download-link', parse[i]) > 0 then + begin + Inc(mangaInfo.numChapter); // 1, 3, 7 + mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), + WebsiteRoots[STARKANA_ID, 1], '', [rfIgnoreCase])); + mangaInfo.chapterName.Add(CommonStringFilter( + Trim(parse[i + 1]) + ' ' + Trim(parse[i + 3]) + ' ' + Trim(parse[i + 7]))); + end; + end; + + //invert chapter(s) + if mangaInfo.chapterLinks.Count > 1 then + begin + InvertStrings(mangaInfo.chapterLinks); + InvertStrings(mangaInfo.chapterName); + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Starkana/names_and_links.inc b/baseunits/includes/Starkana/names_and_links.inc index 70cfb6cc3..789336074 100644 --- a/baseunits/includes/Starkana/names_and_links.inc +++ b/baseunits/includes/Starkana/names_and_links.inc @@ -1,34 +1,34 @@ - function StarkanaGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[STARKANA_ID, 1] + - STARKANA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('style="float:right;', parse[i]) > 0) then - begin - links.Add(GetVal(parse[i + 2], 'href')); - names.Add(CommonStringFilter(parse[i + 3])); - end; - end; - Result := NO_ERROR; - Source.Free; - end; + function StarkanaGetNamesAndLinks: Byte; + var + i: Integer; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[STARKANA_ID, 1] + + STARKANA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('style="float:right;', parse[i]) > 0) then + begin + links.Add(GetVal(parse[i + 2], 'href')); + names.Add(CommonStringFilter(parse[i + 3])); + end; + end; + Result := NO_ERROR; + Source.Free; + end; diff --git a/baseunits/includes/SubManga/chapter_page_number.inc b/baseunits/includes/SubManga/chapter_page_number.inc index be8bb2bb8..087d81066 100644 --- a/baseunits/includes/SubManga/chapter_page_number.inc +++ b/baseunits/includes/SubManga/chapter_page_number.inc @@ -1,54 +1,54 @@ - function GetSubMangaPageNumber: Boolean; - var - surl: String; - i: Integer; - l: TStringList; - nextPage: Boolean = True; - pageNum: Cardinal; - begin - pageNum := 1; - surl := FillMangaSiteHost(SUBMANGA_ID, URL); - l := TStringList.Create; - parse := TStringList.Create; - try - manager.container.PageLinks.Clear; - while nextPage do - begin - nextPage := False; - l.Clear; - parse.Clear; - Result := GetPage(TObject(l), surl, manager.container.manager.retryConnect); - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (not nextPage) and - ((GetTagName(parse[i]) = 'a') and - (GetTagName(parse[i + 1]) = 'span') and - (GetVal(parse[i + 1], 'class') = 'glyphicon glyphicon-chevron-right')) then - if Pos('/c/', GetVal(parse[i], 'href')) <> 0 then - begin - nextPage := True; - Inc(pageNum); - surl := FillMangaSiteHost(SUBMANGA_ID, URL) + '/' + IntToStr(pageNum); - end; - if GetTagName(parse[i]) = 'img' then - begin - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); - Break; - end; - end; - end; - finally - parse.Free; - l.Free; - end; - manager.container.PageNumber := manager.container.PageLinks.Count; - end; + function GetSubMangaPageNumber: Boolean; + var + surl: String; + i: Integer; + l: TStringList; + nextPage: Boolean = True; + pageNum: Cardinal; + begin + pageNum := 1; + surl := FillMangaSiteHost(SUBMANGA_ID, URL); + l := TStringList.Create; + parse := TStringList.Create; + try + manager.container.PageLinks.Clear; + while nextPage do + begin + nextPage := False; + l.Clear; + parse.Clear; + Result := GetPage(TObject(l), surl, manager.container.manager.retryConnect); + Parser := THTMLParser.Create(l.Text); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + if parse.Count > 0 then + for i := 0 to parse.Count - 1 do + begin + if (not nextPage) and + ((GetTagName(parse[i]) = 'a') and + (GetTagName(parse[i + 1]) = 'span') and + (GetVal(parse[i + 1], 'class') = 'glyphicon glyphicon-chevron-right')) then + if Pos('/c/', GetVal(parse[i], 'href')) <> 0 then + begin + nextPage := True; + Inc(pageNum); + surl := FillMangaSiteHost(SUBMANGA_ID, URL) + '/' + IntToStr(pageNum); + end; + if GetTagName(parse[i]) = 'img' then + begin + manager.container.PageLinks.Add(GetVal(parse[i], 'src')); + Break; + end; + end; + end; + finally + parse.Free; + l.Free; + end; + manager.container.PageNumber := manager.container.PageLinks.Count; + end; diff --git a/baseunits/includes/SubManga/image_url.inc b/baseunits/includes/SubManga/image_url.inc index 831bf50d9..db8e56c9a 100644 --- a/baseunits/includes/SubManga/image_url.inc +++ b/baseunits/includes/SubManga/image_url.inc @@ -1,30 +1,30 @@ - function GetSubMangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(SUBMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if GetTagName(parse[i]) = 'img' then - begin - manager.container.PageLinks.Strings[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetSubMangaImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(SUBMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if GetTagName(parse[i]) = 'img' then + begin + manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/SubManga/manga_information.inc b/baseunits/includes/SubManga/manga_information.inc index 9872d12e5..2a676bd4e 100644 --- a/baseunits/includes/SubManga/manga_information.inc +++ b/baseunits/includes/SubManga/manga_information.inc @@ -1,133 +1,133 @@ - function GetSubMangaInfoFromURL: Byte; - var - s: String; - i, j: Integer; - isGetChapters: Boolean = False; - begin - mangaInfo.url := FillMangaSiteHost(SUBMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[SUBMANGA_ID, 0]; - - mangaInfo.genres := ''; - mangaInfo.status := '1'; - - // using 1st parser (cover link, summary) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('content="Leer ', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i], 'content="Leer ', ' manga online'); - - if Pos('class="suscripcion', parse.Strings[i]) > 0 then - begin - // get cover link - if Pos('<img', parse.Strings[i + 5]) > 0 then - mangaInfo.coverLink := - GetAttributeValue(GetTagAttribute(parse.Strings[i + 5], 'src')); - // get summary - j := i + 8; - while (j < parse.Count - 1) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - Inc(j); - s := parse.Strings[j]; - if (s <> '') and - (s[1] <> '<') then - begin - parse.Strings[j] := StringFilter(parse.Strings[j]); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - end; - end; - - // get authors/artists - if (Pos('Creado por', parse.Strings[i]) <> 0) then - begin - if Pos('/autor/', parse.Strings[i + 1]) > 0 then - mangaInfo.authors := parse.Strings[i + 2]; - if Pos('/mangaka/', parse.Strings[i + 5]) > 0 then - mangaInfo.authors := parse.Strings[i + 6]; - end; - - // get genres - if (Pos('submanga.com/genero/', parse.Strings[i]) <> 0) then - mangaInfo.genres := mangaInfo.genres + parse.Strings[i + 1] + ', '; - end; - - // get chapters - Source.Clear; - if not GetPage(TObject(Source), mangaInfo.url + '/completa', Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - // get chapters - if (GetTagName(parse[i]) = 'table') and - (GetVal(parse[i], 'class') = 'table table-striped table-hover') then - isGetChapters := True; - if isGetChapters and (GetTagName(parse[i]) = '/table') then - Break; - if isGetChapters and - ((GetTagName(parse[i]) = 'a') and (GetTagName(parse[i - 1]) = 'td') and - (GetTagName(parse[i - 2]) = 'tr')) then - if Length(GetVal(parse[i], 'href')) > 3 then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterName.Add(CommonStringFilter( - Trim(parse[i + 1]) + ' ' + Trim(parse[i + 3]))); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - end; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - // replace urls - with TRegExpr.Create do - try - Expression := '^.*(/\d+)$'; - for i := 0 to mangaInfo.chapterLinks.Count - 1 do - mangaInfo.chapterLinks[i] := Replace(mangaInfo.chapterLinks[i], '/c/$1', True); - finally - Free; - end; - Result := NO_ERROR; - end; - end; + function GetSubMangaInfoFromURL: Byte; + var + s: String; + i, j: Integer; + isGetChapters: Boolean = False; + begin + mangaInfo.url := FillMangaSiteHost(SUBMANGA_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + mangaInfo.website := WebsiteRoots[SUBMANGA_ID, 0]; + + mangaInfo.genres := ''; + mangaInfo.status := '1'; + + // using 1st parser (cover link, summary) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos('content="Leer ', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i], 'content="Leer ', ' manga online'); + + if Pos('class="suscripcion', parse[i]) > 0 then + begin + // get cover link + if Pos('<img', parse[i + 5]) > 0 then + mangaInfo.coverLink := + GetVal(parse[i + 5], 'src'); + // get summary + j := i + 8; + while (j < parse.Count - 1) and (Pos('</p>', parse[j]) = 0) do + begin + Inc(j); + s := parse[j]; + if (s <> '') and + (s[1] <> '<') then + begin + parse[j] := StringFilter(parse[j]); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + end; + end; + + // get authors/artists + if (Pos('Creado por', parse[i]) <> 0) then + begin + if Pos('/autor/', parse[i + 1]) > 0 then + mangaInfo.authors := parse[i + 2]; + if Pos('/mangaka/', parse[i + 5]) > 0 then + mangaInfo.authors := parse[i + 6]; + end; + + // get genres + if (Pos('submanga.com/genero/', parse[i]) <> 0) then + mangaInfo.genres := mangaInfo.genres + parse[i + 1] + ', '; + end; + + // get chapters + Source.Clear; + if not GetPage(TObject(Source), mangaInfo.url + '/completa', Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + try + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + finally + Parser.Free; + end; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + begin + // get chapters + if (GetTagName(parse[i]) = 'table') and + (GetVal(parse[i], 'class') = 'table table-striped table-hover') then + isGetChapters := True; + if isGetChapters and (GetTagName(parse[i]) = '/table') then + Break; + if isGetChapters and + ((GetTagName(parse[i]) = 'a') and (GetTagName(parse[i - 1]) = 'td') and + (GetTagName(parse[i - 2]) = 'tr')) then + if Length(GetVal(parse[i], 'href')) > 3 then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterName.Add(CommonStringFilter( + Trim(parse[i + 1]) + ' ' + Trim(parse[i + 3]))); + mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); + end; + end; + end; + Source.Free; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); + // replace urls + with TRegExpr.Create do + try + Expression := '^.*(/\d+)$'; + for i := 0 to mangaInfo.chapterLinks.Count - 1 do + mangaInfo.chapterLinks[i] := Replace(mangaInfo.chapterLinks[i], '/c/$1', True); + finally + Free; + end; + Result := NO_ERROR; + end; + end; diff --git a/baseunits/includes/SubManga/names_and_links.inc b/baseunits/includes/SubManga/names_and_links.inc index 048ed1ae4..2054011c4 100644 --- a/baseunits/includes/SubManga/names_and_links.inc +++ b/baseunits/includes/SubManga/names_and_links.inc @@ -1,37 +1,37 @@ - function SubMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SUBMANGA_ID, 1] + - SUBMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="xs"', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 3]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i - 1], 'href=')); - links.Add(StringReplace(s, WebsiteRoots[SUBMANGA_ID, 1], '', [])); - end; - end; - Source.Free; + function SubMangaGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[SUBMANGA_ID, 1] + + SUBMANGA_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('class="xs"', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i - 1], 'href'); + links.Add(StringReplace(s, WebsiteRoots[SUBMANGA_ID, 1], '', [])); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/TruyenTranhTuan/image_url.inc b/baseunits/includes/TruyenTranhTuan/image_url.inc index 0140064fb..f58f06b3b 100644 --- a/baseunits/includes/TruyenTranhTuan/image_url.inc +++ b/baseunits/includes/TruyenTranhTuan/image_url.inc @@ -1,39 +1,39 @@ - function GetTruyenTranhTuanImageURL: Boolean; - var - s, s2: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('var slides_page = ["', parse.Strings[i]) > 0 then - begin - s := parse.Strings[i]; - repeat - j := Pos('"/manga/', s); - s2 := EncodeUrl(WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + '/manga/' + - GetString(s, '"/manga/', '"')); - manager.container.PageLinks.Add(s2); - Delete(s, Pos('"/manga/', s), 10); - j := Pos('"/manga/', s); - until j = 0; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetTruyenTranhTuanImageURL: Boolean; + var + s, s2: String; + j, i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL), + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('var slides_page = ["', parse[i]) > 0 then + begin + s := parse[i]; + repeat + j := Pos('"/manga/', s); + s2 := EncodeUrl(WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + '/manga/' + + GetString(s, '"/manga/', '"')); + manager.container.PageLinks.Add(s2); + Delete(s, Pos('"/manga/', s), 10); + j := Pos('"/manga/', s); + until j = 0; + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/TruyenTranhTuan/manga_information.inc b/baseunits/includes/TruyenTranhTuan/manga_information.inc index ff81ec909..76b13b6ef 100644 --- a/baseunits/includes/TruyenTranhTuan/manga_information.inc +++ b/baseunits/includes/TruyenTranhTuan/manga_information.inc @@ -1,121 +1,120 @@ - function GetTruyenTranhTuanInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[TRUYENTRANHTUAN_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse.Strings[i]) = 'meta') and - (Pos('property="og:image"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'content='))); - - // get summary - if (Pos('id="manga-summary"', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if (Pos('<title>', parse.Strings[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := Trim(StringFilter(GetString('~!@' + parse.Strings[i + 1], - '~!@', ' - Truyện tranh online - truyentranhtuan.com'))); - - // get chapter name and links - if (Pos('class="chapter-name"', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse.Strings[i + 2], 'href="', '"'); - s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse.Strings[i + 3])); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 1 < parse.Count) and (Pos('Tác giả:', parse.Strings[i]) <> 0) then - mangaInfo.authors := Trim(parse.Strings[i + 2]); - - // get artists - //if (i+1<parse.Count) AND (Pos('/search/artist/', parse.Strings[i])<>0) then - // mangaInfo.artists:= TrimLeft(parse.Strings[i+1]); - - // get genres - if (Pos('Thể loại:', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if Pos('<a href=', parse.Strings[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '; - if Pos('</span>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 5 < parse.Count) and (Pos('Chương mới nhất', parse.Strings[i]) <> 0) then - begin - if Pos('dang-tien-hanh', parse.Strings[i + 1]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetTruyenTranhTuanInfoFromURL: Byte; + var + s: String; + isExtractSummary: Boolean = True; + isExtractGenres: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL);// + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[TRUYENTRANHTUAN_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get cover + if (GetTagName(parse[i]) = 'meta') and + (Pos('property="og:image"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'content')); + + // get summary + if (Pos('id="manga-summary"', parse[i]) <> 0) and + (isExtractSummary) then + begin + j := i + 4; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := mangaInfo.summary + parse[j]; + end; + Inc(j); + end; + isExtractSummary := False; + end; + + // get title + if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then + mangaInfo.title := Trim(StringFilter(GetString('~!@' + parse[i + 1], + '~!@', ' - Truyện tranh online - truyentranhtuan.com'))); + + // get chapter name and links + if (Pos('class="chapter-name"', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := GetString(parse[i + 2], 'href="', '"'); + s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(Trim(parse[i + 3])); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + + // get authors + if (i + 1 < parse.Count) and (Pos('Tác giả:', parse[i]) <> 0) then + mangaInfo.authors := Trim(parse[i + 2]); + + // get artists + //if (i+1<parse.Count) AND (Pos('/search/artist/', parse[i])<>0) then + // mangaInfo.artists:= TrimLeft(parse[i+1]); + + // get genres + if (Pos('Thể loại:', parse[i]) <> 0) then + begin + isExtractGenres := True; + mangaInfo.genres := ''; + end; + + if isExtractGenres then + begin + if Pos('<a href=', parse[i]) <> 0 then + mangaInfo.genres := mangaInfo.genres + + TrimLeft(TrimRight(parse[i + 1])) + ', '; + if Pos('</span>', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 5 < parse.Count) and (Pos('Chương mới nhất', parse[i]) <> 0) then + begin + if Pos('dang-tien-hanh', parse[i + 1]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/TruyenTranhTuan/names_and_links.inc b/baseunits/includes/TruyenTranhTuan/names_and_links.inc index 56a215e72..02a3a5f76 100644 --- a/baseunits/includes/TruyenTranhTuan/names_and_links.inc +++ b/baseunits/includes/TruyenTranhTuan/names_and_links.inc @@ -1,38 +1,38 @@ - function TruyenTranhTuanGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + - TRUYENTRANHTUAN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('class="manga"', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetAttributeValue(GetTagAttribute(parse.Strings[i + 1], 'href=')); - s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; + function TruyenTranhTuanGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + + TRUYENTRANHTUAN_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 5 do + begin + if (Pos('class="manga"', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); + names.Add(HTMLEntitiesFilter(s)); + s := GetVal(parse[i + 1], 'href'); + s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/Turkcraft/chapter_page_number.inc b/baseunits/includes/Turkcraft/chapter_page_number.inc index acdeb6a4f..81c290c02 100644 --- a/baseunits/includes/Turkcraft/chapter_page_number.inc +++ b/baseunits/includes/Turkcraft/chapter_page_number.inc @@ -1,33 +1,33 @@ - function GetTurkcraftPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Next Page"', parse.Strings[i]) > 0) then - begin - s := parse.Strings[i - 5]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetTurkcraftPageNumber: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + parse := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/1'); + Result := GetPage(TObject(l), + s, + manager.container.manager.retryConnect); + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.pageNumber := 0; + for i := 0 to parse.Count - 1 do + begin + if (Pos('title="Next Page"', parse[i]) > 0) then + begin + s := parse[i - 5]; + manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); + Break; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Turkcraft/image_url.inc b/baseunits/includes/Turkcraft/image_url.inc index 000925d8c..6d21c5fb7 100644 --- a/baseunits/includes/Turkcraft/image_url.inc +++ b/baseunits/includes/Turkcraft/image_url.inc @@ -1,32 +1,32 @@ - function GetTurkcraftImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse.Strings[i]) > 0) then - begin - manager.container.PageLinks.Strings[workCounter] := - EncodeURL(WebsiteRoots[TURKCRAFT_ID, 1] + TURKCRAFT_BROWSER + - GetAttributeValue(GetTagAttribute(parse.Strings[i], 'src='))); - Break; - end; - end; - parse.Free; - l.Free; - end; + function GetTurkcraftImageURL: Boolean; + var + s: String; + i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(workCounter + 1)); + Result := GetPage(TObject(l), + s, + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + + if parse.Count > 0 then + begin + for i := 0 to parse.Count - 1 do + if (Pos('class="picture"', parse[i]) > 0) then + begin + manager.container.PageLinks[workCounter] := + EncodeURL(WebsiteRoots[TURKCRAFT_ID, 1] + TURKCRAFT_BROWSER + + GetVal(parse[i], 'src')); + Break; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/Turkcraft/manga_information.inc b/baseunits/includes/Turkcraft/manga_information.inc index d58537fca..418258754 100644 --- a/baseunits/includes/Turkcraft/manga_information.inc +++ b/baseunits/includes/Turkcraft/manga_information.inc @@ -1,73 +1,73 @@ - function GetTurkcraftInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(TURKCRAFT_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.website := WebsiteRoots[TURKCRAFT_ID, 0]; - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse.Strings[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('Mangaturk - ', parse.Strings[i]) > 0) then - mangaInfo.title := GetString(parse.Strings[i], 'Mangaturk - ', ' - Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse.Strings[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := URL + '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetTurkcraftInfoFromURL: Byte; + var + s: String; + isExtractChapter: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(TURKCRAFT_ID, URL); + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + + mangaInfo.website := WebsiteRoots[TURKCRAFT_ID, 0]; + mangaInfo.status := '1'; + mangaInfo.coverLink := ''; + mangaInfo.summary := ''; + mangaInfo.authors := ''; + mangaInfo.artists := ''; + mangaInfo.genres := ''; + + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get chapter name and links + if (Pos('select name="chapter"', parse[i]) > 0) then + isExtractChapter := True; + + // get manga name + if (mangaInfo.title = '') and (Pos('Mangaturk - ', parse[i]) > 0) then + mangaInfo.title := GetString(parse[i], 'Mangaturk - ', ' - Chapter'); + + if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then + Break; + + if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + s := URL + '/' + GetVal(parse[i], 'value'); + mangaInfo.chapterLinks.Add(s); + s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); + end; + end; + + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/Turkcraft/names_and_links.inc b/baseunits/includes/Turkcraft/names_and_links.inc index ee4662003..776fd5255 100644 --- a/baseunits/includes/Turkcraft/names_and_links.inc +++ b/baseunits/includes/Turkcraft/names_and_links.inc @@ -1,37 +1,37 @@ - function TurkcraftGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[TURKCRAFT_ID, 1] + - TURKCRAFT_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('<option value="', parse.Strings[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := '/' + GetAttributeValue(GetTagAttribute(parse.Strings[i], 'value=')); - links.Add(s); - end; - end; - Source.Free; + function TurkcraftGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[TURKCRAFT_ID, 1] + + TURKCRAFT_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := parse.Count - 1 downto 5 do + begin + if (Pos('<option value="', parse[i]) > 0) then + begin + Result := NO_ERROR; + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(HTMLEntitiesFilter(s)); + s := '/' + GetVal(parse[i], 'value'); + links.Add(s); + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/VnSharing/directory_page_number.inc b/baseunits/includes/VnSharing/directory_page_number.inc index a04a26e3a..d5470f3ee 100644 --- a/baseunits/includes/VnSharing/directory_page_number.inc +++ b/baseunits/includes/VnSharing/directory_page_number.inc @@ -1,37 +1,37 @@ - function GetVnSharingDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + - VNSHARING_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('»', parse.Strings[i]) > 0) then - begin - s := GetAttributeValue(GetTagAttribute(parse.Strings[i - 1], 'page=')); - SetLength(s, Length(s) - 1); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; + function GetVnSharingDirectoryPageNumber: Byte; + var + i: Cardinal; + begin + Result := INFORMATION_NOT_FOUND; + if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + + VNSHARING_BROWSER, 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('»', parse[i]) > 0) then + begin + s := GetVal(parse[i - 1], 'page'); + SetLength(s, Length(s) - 1); + Page := StrToInt(s); + Result := NO_ERROR; + Source.Free; + Exit; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/includes/VnSharing/image_url.inc b/baseunits/includes/VnSharing/image_url.inc index 51588fc7a..969fda71a 100644 --- a/baseunits/includes/VnSharing/image_url.inc +++ b/baseunits/includes/VnSharing/image_url.inc @@ -1,37 +1,37 @@ - function GetVnSharingImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(VNSHARING_ID, URL), - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('lstImages.push("', parse.Strings[i]) > 0 then - begin - s := parse.Strings[i]; - repeat - j := Pos('lstImages.push("', s); - manager.container.PageLinks.Add( - EncodeUrl(GetString(s, 'lstImages.push("', '");'))); - Delete(s, Pos('lstImages.push("', s), 16); - j := Pos('lstImages.push("', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; + function GetVnSharingImageURL: Boolean; + var + s: String; + j, i: Cardinal; + l: TStringList; + begin + l := TStringList.Create; + Result := GetPage(TObject(l), + FillMangaSiteHost(VNSHARING_ID, URL), + manager.container.Manager.retryConnect); + parse := TStringList.Create; + Parser := THTMLParser.Create(PChar(l.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count > 0 then + begin + manager.container.PageLinks.Clear; + for i := 0 to parse.Count - 1 do + begin + if Pos('lstImages.push("', parse[i]) > 0 then + begin + s := parse[i]; + repeat + j := Pos('lstImages.push("', s); + manager.container.PageLinks.Add( + EncodeUrl(GetString(s, 'lstImages.push("', '");'))); + Delete(s, Pos('lstImages.push("', s), 16); + j := Pos('lstImages.push("', s); + until j = 0; + end; + end; + end; + parse.Free; + l.Free; + end; diff --git a/baseunits/includes/VnSharing/manga_information.inc b/baseunits/includes/VnSharing/manga_information.inc index 67cd59a0b..23f159f78 100644 --- a/baseunits/includes/VnSharing/manga_information.inc +++ b/baseunits/includes/VnSharing/manga_information.inc @@ -1,130 +1,129 @@ - function GetVnSharingInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(VNSHARING_ID, URL) + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[VNSHARING_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('name="title"', parse.Strings[i]) > 0) then - mangaInfo.title := TrimLeft(TrimRight(GetString(parse.Strings[i], - '"Truyện ', ' | Đọc online'))); - - // get cover - if (GetTagName(parse.Strings[i]) = 'img') and - (Pos('img width="190px" height="250px"', parse.Strings[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetAttributeValue( - GetTagAttribute(parse.Strings[i], 'src='))); - - // get summary - if (Pos('Sơ lược:', parse.Strings[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse.Strings[j]) = 0) do - begin - s := parse.Strings[j]; - if s[1] <> '<' then - begin - parse.Strings[j] := HTMLEntitiesFilter(StringFilter(parse.Strings[j])); - parse.Strings[j] := StringReplace(parse.Strings[j], #10, '\n', [rfReplaceAll]); - parse.Strings[j] := StringReplace(parse.Strings[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse.Strings[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get chapter name and links - if (i + 1 < parse.Count) and - (GetTagName(parse.Strings[i]) = 'a') and - (Pos('/Truyen/', parse.Strings[i]) > 0) and - (Pos('title="Đọc', parse.Strings[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - EncodeUrl(GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')))); - parse.Strings[i + 1] := RemoveSymbols(TrimLeft(TrimRight(parse.Strings[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(parse.Strings[i + 1]))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Tác giả:', parse.Strings[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse.Strings[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Họa sỹ:', parse.Strings[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse.Strings[i + 4]); - - // get genres - if (Pos('Thể loại:', parse.Strings[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if (i + 1 < parse.Count) and (Pos('"/TheLoai/', parse.Strings[i]) > 0) then - mangaInfo.genres := mangaInfo.genres + - (TrimLeft(TrimRight(parse.Strings[i + 1])) + ', '); - if Pos('</p>', parse.Strings[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Tình trạng:', parse.Strings[i]) <> 0) then - begin - if Pos('Đang tiến hành', parse.Strings[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - if (mangaInfo.status = '1') and (mangainfo.ChapterName.Count > 0) then - begin - Dec(mangaInfo.numChapter); - mangainfo.ChapterName.Delete(mangainfo.ChapterName.Count - 1); - mangainfo.ChapterLinks.Delete(mangainfo.ChapterLinks.Count - 1); - end; - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; + function GetVnSharingInfoFromURL: Byte; + var + s: String; + isExtractSummary: Boolean = True; + isExtractGenres: Boolean = False; + i, j: Cardinal; + begin + mangaInfo.url := FillMangaSiteHost(VNSHARING_ID, URL) + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + + // parsing the HTML source + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + + Parser.Free; + Source.Free; + mangaInfo.website := WebsiteRoots[VNSHARING_ID, 0]; + // using parser (cover link, summary, chapter name and link) + if parse.Count = 0 then + Exit; + for i := 0 to parse.Count - 1 do + begin + // get manga title + if (mangaInfo.title = '') and + (Pos('name="title"', parse[i]) > 0) then + mangaInfo.title := TrimLeft(TrimRight(GetString(parse[i], + '"Truyện ', ' | Đọc online'))); + + // get cover + if (GetTagName(parse[i]) = 'img') and + (Pos('img width="190px" height="250px"', parse[i]) > 0) then + mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); + + // get summary + if (Pos('Sơ lược:', parse[i]) <> 0) and + (isExtractSummary) then + begin + j := i + 4; + while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do + begin + s := parse[j]; + if s[1] <> '<' then + begin + parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); + parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); + parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); + mangaInfo.summary := parse[j]; + end; + Inc(j); + end; + isExtractSummary := False; + end; + + // get chapter name and links + if (i + 1 < parse.Count) and + (GetTagName(parse[i]) = 'a') and + (Pos('/Truyen/', parse[i]) > 0) and + (Pos('title="Đọc', parse[i]) > 0) then + begin + Inc(mangaInfo.numChapter); + mangaInfo.chapterLinks.Add( + EncodeUrl(GetVal(parse[i], 'href'))); + parse[i + 1] := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); + mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(parse[i + 1]))); + end; + + // get authors + if (i + 4 < parse.Count) and (Pos('Tác giả:', parse[i]) <> 0) then + mangaInfo.authors := TrimLeft(parse[i + 4]); + + // get artists + if (i + 4 < parse.Count) and (Pos('Họa sỹ:', parse[i]) <> 0) then + mangaInfo.artists := TrimLeft(parse[i + 4]); + + // get genres + if (Pos('Thể loại:', parse[i]) <> 0) then + begin + isExtractGenres := True; + mangaInfo.genres := ''; + end; + + if isExtractGenres then + begin + if (i + 1 < parse.Count) and (Pos('"/TheLoai/', parse[i]) > 0) then + mangaInfo.genres := mangaInfo.genres + + (TrimLeft(TrimRight(parse[i + 1])) + ', '); + if Pos('</p>', parse[i]) <> 0 then + isExtractGenres := False; + end; + + // get status + if (i + 2 < parse.Count) and (Pos('Tình trạng:', parse[i]) <> 0) then + begin + if Pos('Đang tiến hành', parse[i + 2]) <> 0 then + mangaInfo.status := '1' // ongoing + else + mangaInfo.status := '0'; // completed + end; + end; + + if (mangaInfo.status = '1') and (mangainfo.ChapterName.Count > 0) then + begin + Dec(mangaInfo.numChapter); + mangainfo.ChapterName.Delete(mangainfo.ChapterName.Count - 1); + mangainfo.ChapterLinks.Delete(mangainfo.ChapterLinks.Count - 1); + end; + // Since chapter name and link are inverted, we need to invert them + if mangainfo.ChapterLinks.Count > 1 then + begin + i := 0; + j := mangainfo.ChapterLinks.Count - 1; + while (i < j) do + begin + mangainfo.ChapterName.Exchange(i, j); + mangainfo.chapterLinks.Exchange(i, j); + Inc(i); + Dec(j); + end; + end; + Result := NO_ERROR; + end; diff --git a/baseunits/includes/VnSharing/names_and_links.inc b/baseunits/includes/VnSharing/names_and_links.inc index 8c337856f..9382fea28 100644 --- a/baseunits/includes/VnSharing/names_and_links.inc +++ b/baseunits/includes/VnSharing/names_and_links.inc @@ -1,48 +1,48 @@ - function VnSharingGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - - begin - Result := INFORMATION_NOT_FOUND; - // bad code - if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + - VNSHARING_BROWSER + '?page=' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/Truyen/', parse.Strings[i]) > 0) and - (GetAttributeValue(GetTagAttribute(parse.Strings[i], 'width=')) <> '') then - begin - { if NOT isGetNamesAndLinks then - isGetNamesAndLinks:= TRUE - else - begin } - Result := NO_ERROR; - s := GetAttributeValue(GetTagAttribute(parse.Strings[i], 'href=')); - // if s <> '/Truyen/Tenki-Yohou-no-Koibito?id=506' then - if s <> '/Truyen/Bakuman-Fantasy-Weirdos?id=6238' then - begin - links.Add(s); - s := StringFilter(TrimLeft(TrimRight(parse.Strings[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - end; - end; - end; - Source.Free; + function VnSharingGetNamesAndLinks: Byte; + var + i: Cardinal; + s: String; + + begin + Result := INFORMATION_NOT_FOUND; + // bad code + if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + + VNSHARING_BROWSER + '?page=' + IntToStr(StrToInt(URL) + 1), 0) then + begin + Result := NET_PROBLEM; + Source.Free; + Exit; + end; + parse.Clear; + Parser := THTMLParser.Create(PChar(Source.Text)); + Parser.OnFoundTag := OnTag; + Parser.OnFoundText := OnText; + Parser.Exec; + Parser.Free; + if parse.Count = 0 then + begin + Source.Free; + Exit; + end; + for i := 0 to parse.Count - 1 do + begin + if (Pos('/Truyen/', parse[i]) > 0) and + (GetVal(parse[i], 'width') <> '') then + begin + { if NOT isGetNamesAndLinks then + isGetNamesAndLinks:= TRUE + else + begin } + Result := NO_ERROR; + s := GetVal(parse[i], 'href'); + // if s <> '/Truyen/Tenki-Yohou-no-Koibito?id=506' then + if s <> '/Truyen/Bakuman-Fantasy-Weirdos?id=6238' then + begin + links.Add(s); + s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); + names.Add(HTMLEntitiesFilter(s)); + end; + end; + end; + Source.Free; end; \ No newline at end of file diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 886210b8d..561040e26 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -121,7 +121,7 @@ TMangaInformation = class(TObject) implementation uses - Dialogs, fpJSON, JSONParser, IniFiles, FastHTMLParser, HTMLUtil, + Dialogs, fpJSON, JSONParser, jsonscanner, IniFiles, FastHTMLParser, HTMLUtil, SynaCode, uMisc, frmMain, WebsiteModules; // ----- TDataProcess ----- From 46c18af5ff5ab59b55d18180d98d7b1497d941e8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 02:14:26 +0800 Subject: [PATCH 0891/2794] updater, add synapse --- updater/languages/updater.en.po | 5 +---- updater/languages/updater.id_ID.po | 5 +---- updater/languages/updater.po | 4 ---- updater/updater.lpi | 7 +++++-- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index 8d4d5ba17..3ac32a9fb 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -11,10 +11,6 @@ msgstr "" "Language: en\n" "X-Generator: Poedit 1.8.2\n" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Updater" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "File size" @@ -128,3 +124,4 @@ msgstr "Unpacking file [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Waiting main app to close..." + diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 3b4f6c71e..b20963fde 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -11,10 +11,6 @@ msgstr "" "Language: id_ID\n" "X-Generator: Poedit 1.8.2\n" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Pembaruan" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Ukuran" @@ -119,3 +115,4 @@ msgstr "Membuka berkas [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Menunggu aplikasi utama untuk berhenti..." + diff --git a/updater/languages/updater.po b/updater/languages/updater.po index 8f14f02c9..a6e4f13e2 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -1,10 +1,6 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "" diff --git a/updater/updater.lpi b/updater/updater.lpi index 0efaaf586..6cf5e7f3e 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -74,10 +74,13 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="1"> + <RequiredPackages Count="2"> <Item1> - <PackageName Value="LCL"/> + <PackageName Value="laz_synapse"/> </Item1> + <Item2> + <PackageName Value="LCL"/> + </Item2> </RequiredPackages> <Units Count="4"> <Unit0> From 93f662f3e22042a930ae3a7988d6871fae877644 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 02:42:20 +0800 Subject: [PATCH 0892/2794] httpsendthread, change default useragent --- baseunits/httpsendthread.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 101dd3da8..25e29d426 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -36,6 +36,9 @@ THTTPSendThread = class(THTTPSend) property FollowRedirection: Boolean read ffollowredirection write ffollowredirection; end; +var + DefaultUserAgent: String = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; + implementation { THTTPSendThread } @@ -58,7 +61,8 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); begin inherited Create; KeepAlive := True; - UserAgent := 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36'; + if Trim(DefaultUserAgent) <> '' then + UserAgent := DefaultUserAgent; Protocol := '1.1'; Headers.NameValueSeparator := ':'; Cookies.NameValueSeparator := '='; From 84e313bee70f81b8f43435c50a1f9b5adcbb39c5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 03:02:01 +0800 Subject: [PATCH 0893/2794] httpsendthread, add head method --- baseunits/httpsendthread.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 25e29d426..ef8fbde5c 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -23,8 +23,9 @@ THTTPSendThread = class(THTTPSend) public constructor Create(AOwner: TFMDThread = nil); function HTTPRequest(const Method, URL: String; Response: TObject = nil): Boolean; + function HEAD(const URL: String; Response: TObject = nil): Boolean; function GET(const URL: String; Response: TObject = nil): Boolean; - function POST(const URL: String; URLData: String = ''; Response: TObject = nil): Boolean; + function POST(const URL: String; POSTData: String = ''; Response: TObject = nil): Boolean; function GetCookies: String; procedure RemoveCookie(const CookieName: string); procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); @@ -172,17 +173,22 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; end; end; +function THTTPSendThread.HEAD(const URL: String; Response: TObject): Boolean; +begin + Result := HTTPRequest('HEAD', URL, Response); +end; + function THTTPSendThread.GET(const URL: String; Response: TObject): Boolean; begin Result := HTTPRequest('GET', URL, Response); end; -function THTTPSendThread.POST(const URL: String; URLData: String; +function THTTPSendThread.POST(const URL: String; POSTData: String; Response: TObject): Boolean; begin - if URLData <> '' then begin + if POSTData <> '' then begin Document.Clear; - WriteStrToStream(Document, URLData); + WriteStrToStream(Document, POSTData); end; MimeType := 'application/x-www-form-urlencoded'; Result := HTTPRequest('POST', URL, Response); From ce850d5622f3d9a266b262e4a581d40310f4f476 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 03:06:15 +0800 Subject: [PATCH 0894/2794] updater, don't need to encode url from response header --- updater/uMain.pas | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 595ac80c0..d519b0b4a 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -174,9 +174,7 @@ constructor TDownloadThread.Create; FHTTP.Timeout := 10000; FHTTP.SetProxy(ProxyType,ProxyHost,ProxyPort,ProxyUser,ProxyPass); if isSFURL then - FHTTP.UserAgent := UA_CURL - else - FHTTP.UserAgent := DEFAULT_UA; + FHTTP.UserAgent := UA_CURL; FTotalSize := 0; FCurrentSize := 0; URL := ''; @@ -291,7 +289,8 @@ procedure TDownloadThread.Execute; HTTPHeaders := TStringList.Create; regx := TRegExpr.Create; try - HTTPHeaders.NameValueSeparator:=':'; + HTTPHeaders.Assign(FHTTP.Headers); + regx.ModifierI := True; if isSFURL then begin @@ -327,7 +326,7 @@ procedure TDownloadThread.Execute; FileName := 'new_version.7z'; end; - FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Headers.Assign(HTTPHeaders); //**loading page UpdateStatus(RS_LoadingPage); ctry := 0; @@ -390,8 +389,7 @@ procedure TDownloadThread.Execute; UpdateStatus(Format(RS_Downloading, [FileName])); ctry := 0; FHTTP.Clear; - HTTPHeaders.Values['Accept'] := ' */*'; - FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Headers.Assign(HTTPHeaders); FHTTP.Cookies.Clear; while (not FHTTP.HTTPMethod('GET', Trim(rurl))) or (FHTTP.ResultCode >= 300) do @@ -439,10 +437,9 @@ procedure TDownloadThread.Execute; begin HTTPHeaders.Values['Referer'] := ' ' + rurl; rurl := Trim(FHTTP.Headers.Values['location']); - rurl := EncodeURL(DecodeURL(Trim(rurl))); end; FHTTP.Clear; - FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Headers.Assign(HTTPHeaders); end; end; From 4abd16bc7686ce70bde893767257d38724362269 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 03:06:54 +0800 Subject: [PATCH 0895/2794] updater, don't need to encode url from response header --- updater/uMain.pas | 15 ++++++--------- updater/updater.lpi | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 595ac80c0..d519b0b4a 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -174,9 +174,7 @@ constructor TDownloadThread.Create; FHTTP.Timeout := 10000; FHTTP.SetProxy(ProxyType,ProxyHost,ProxyPort,ProxyUser,ProxyPass); if isSFURL then - FHTTP.UserAgent := UA_CURL - else - FHTTP.UserAgent := DEFAULT_UA; + FHTTP.UserAgent := UA_CURL; FTotalSize := 0; FCurrentSize := 0; URL := ''; @@ -291,7 +289,8 @@ procedure TDownloadThread.Execute; HTTPHeaders := TStringList.Create; regx := TRegExpr.Create; try - HTTPHeaders.NameValueSeparator:=':'; + HTTPHeaders.Assign(FHTTP.Headers); + regx.ModifierI := True; if isSFURL then begin @@ -327,7 +326,7 @@ procedure TDownloadThread.Execute; FileName := 'new_version.7z'; end; - FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Headers.Assign(HTTPHeaders); //**loading page UpdateStatus(RS_LoadingPage); ctry := 0; @@ -390,8 +389,7 @@ procedure TDownloadThread.Execute; UpdateStatus(Format(RS_Downloading, [FileName])); ctry := 0; FHTTP.Clear; - HTTPHeaders.Values['Accept'] := ' */*'; - FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Headers.Assign(HTTPHeaders); FHTTP.Cookies.Clear; while (not FHTTP.HTTPMethod('GET', Trim(rurl))) or (FHTTP.ResultCode >= 300) do @@ -439,10 +437,9 @@ procedure TDownloadThread.Execute; begin HTTPHeaders.Values['Referer'] := ' ' + rurl; rurl := Trim(FHTTP.Headers.Values['location']); - rurl := EncodeURL(DecodeURL(Trim(rurl))); end; FHTTP.Clear; - FHTTP.Headers.Text := HTTPHeaders.Text; + FHTTP.Headers.Assign(HTTPHeaders); end; end; diff --git a/updater/updater.lpi b/updater/updater.lpi index 6cf5e7f3e..1d401c763 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MajorVersionNr Value="2"/> <MinorVersionNr Value="3"/> - <RevisionNr Value="1"/> + <RevisionNr Value="2"/> <Attributes pvaPrivateBuild="True"/> <StringTable FileDescription="Updater for Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="updater.exe" ProductName="Updater" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> From f989c25580f08322747ccca4325e25d68c9b5011 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 03:57:08 +0800 Subject: [PATCH 0896/2794] frmmain, fix layout --- mangadownloader/forms/frmMain.lfm | 19 +++++++++++-------- mangadownloader/forms/frmMain.pas | 13 ++++++++++++- mangadownloader/languages/fmd.en.po | 14 +++++--------- mangadownloader/languages/fmd.id_ID.po | 14 +++++--------- mangadownloader/languages/fmd.po | 14 +++++--------- 5 files changed, 38 insertions(+), 36 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index c06ed6cdb..e0f9cf255 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2362,6 +2362,7 @@ object MainForm: TMainForm 'CBZ' 'PDF' ) + OnSelectionChanged = rgOptionCompressSelectionChanged ParentFont = False TabOrder = 0 end @@ -2514,11 +2515,12 @@ object MainForm: TMainForm end end object seOptionPDFQuality: TSpinEdit - Left = 44 + Left = 20 Height = 23 Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 132 + Top = 133 Width = 50 + Enabled = False MinValue = 5 ParentFont = False ParentShowHint = False @@ -2527,24 +2529,25 @@ object MainForm: TMainForm Value = 100 end object lbOptionPDFQuality: TLabel - Left = 103 + Left = 79 Height = 15 Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 135 + Top = 136 Width = 119 Caption = 'PDF compression level' + Enabled = False ParentColor = False ParentFont = False ParentShowHint = False ShowHint = True end - object lbOptionCustomRenameHint1: TLabel - Left = 260 + object lbOptionPDFQualityHint: TLabel + Left = 224 Height = 15 - Hint = '100: FlateEncode (lossless), lower: DCTEncode (lossy)' - Top = 135 + Top = 136 Width = 13 Caption = '[?]' + Enabled = False Font.Color = clBlue ParentColor = False ParentFont = False diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 208811f2c..5c1e086b4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -108,7 +108,7 @@ TMainForm = class(TForm) lbFilterHint: TLabel; lbOptionExternal: TLabel; lbOptionChapterCustomRenameHint: TLabel; - lbOptionCustomRenameHint1: TLabel; + lbOptionPDFQualityHint: TLabel; lbOptionExternalParamsHint: TLabel; TransferRateGraphList: TListChartSource; medURLCut: TMenuItem; @@ -447,6 +447,7 @@ TMainForm = class(TForm) procedure pmFavoritesPopup(Sender: TObject); procedure pmMangaListPopup(Sender: TObject); procedure pmSbMainPopup(Sender: TObject); + procedure rgOptionCompressSelectionChanged(Sender: TObject); procedure sbUpdateListDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); procedure seOptionAutoCheckFavIntervalMinutesChange(Sender: TObject); @@ -3292,6 +3293,13 @@ procedure TMainForm.pmSbMainPopup(Sender: TObject); Abort; end; +procedure TMainForm.rgOptionCompressSelectionChanged(Sender: TObject); +begin + seOptionPDFQuality.Enabled:=rgOptionCompress.ItemIndex=3; + lbOptionPDFQuality.Enabled:=seOptionPDFQuality.Enabled; + lbOptionPDFQualityHint.Enabled:=seOptionPDFQuality.Enabled; +end; + procedure TMainForm.sbUpdateListDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); var @@ -4911,10 +4919,13 @@ procedure TMainForm.ApplyLanguage; idxOptionLetFMDDo := cbOptionLetFMDDo.ItemIndex; idxOptionProxyType := cbOptionProxyType.ItemIndex; idxDropTargetMode := rgDropTargetMode.ItemIndex; + ShowMessage('widthBefore: '+IntToStr(lbOptionPDFQuality.Width)); if SimpleTranslator.SetLangByIndex(cbLanguages.ItemIndex) then begin + // assign new value lbOptionExternalParamsHint.Hint := Format(RS_LblOptionExternalParamsHint, [EXPARAM_PATH, EXPARAM_CHAPTER, EXPARAM_PATH, EXPARAM_CHAPTER]); + lbOptionPDFQualityHint.Hint:=lbOptionPDFQuality.Hint; cbFilterStatus.Items.Text := RS_FilterStatusItems; cbOptionLetFMDDo.Items.Text := RS_OptionFMDDoItems; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 94aff1c8b..e5f8d1414 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1133,15 +1133,6 @@ msgstr "Connection timeout (seconds)" msgid "Chapter folder name:" msgstr "Chapter folder name:" -#: tmainform.lboptioncustomrenamehint1.caption -msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT1.CAPTION" -msgid "[?]" -msgstr "[?]" - -#: tmainform.lboptioncustomrenamehint1.hint -msgid "100: FlateEncode (lossless), lower: DCTEncode (lossy)" -msgstr "100: FlateEncode (lossless), lower: DCTEncode (lossy)" - #: tmainform.lboptiondialogs.caption msgid "Show dialog confirmation for:" msgstr "Show dialog confirmation for:" @@ -1230,6 +1221,11 @@ msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" msgstr "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + #: tmainform.lboptionport.caption msgid "Port" msgstr "Port" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 14d3f5beb..970675ce6 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1117,15 +1117,6 @@ msgstr "Batas waktu koneksi (detik)" msgid "Chapter folder name:" msgstr "Nama folder bab:" -#: tmainform.lboptioncustomrenamehint1.caption -msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT1.CAPTION" -msgid "[?]" -msgstr "[?]" - -#: tmainform.lboptioncustomrenamehint1.hint -msgid "100: FlateEncode (lossless), lower: DCTEncode (lossy)" -msgstr "100 = FlateEncode (lossless), lebih rendah = DCTEncode (lossy)" - #: tmainform.lboptiondialogs.caption msgid "Show dialog confirmation for:" msgstr "Tampilkan dialog konfirmasi untuk:" @@ -1213,6 +1204,11 @@ msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" msgstr "100 = FlateEncode (lossless), lebih rendah = DCTEncode (lossy)" +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + #: tmainform.lboptionport.caption msgid "Port" msgstr "Port" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 338773b74..08c99ca1e 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1069,15 +1069,6 @@ msgstr "" msgid "Chapter folder name:" msgstr "" -#: tmainform.lboptioncustomrenamehint1.caption -msgctxt "TMAINFORM.LBOPTIONCUSTOMRENAMEHINT1.CAPTION" -msgid "[?]" -msgstr "" - -#: tmainform.lboptioncustomrenamehint1.hint -msgid "100: FlateEncode (lossless), lower: DCTEncode (lossy)" -msgstr "" - #: tmainform.lboptiondialogs.caption msgid "Show dialog confirmation for:" msgstr "" @@ -1158,6 +1149,11 @@ msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" msgstr "" +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "TMAINFORM.LBOPTIONPDFQUALITYHINT.CAPTION" +msgid "[?]" +msgstr "" + #: tmainform.lboptionport.caption msgid "Port" msgstr "" From 0d722b59820b87fb6e7b9d58e7b25e92f914cefd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 03:59:24 +0800 Subject: [PATCH 0897/2794] cleanup --- mangadownloader/forms/frmMain.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5c1e086b4..e37bbac54 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4919,7 +4919,6 @@ procedure TMainForm.ApplyLanguage; idxOptionLetFMDDo := cbOptionLetFMDDo.ItemIndex; idxOptionProxyType := cbOptionProxyType.ItemIndex; idxDropTargetMode := rgDropTargetMode.ItemIndex; - ShowMessage('widthBefore: '+IntToStr(lbOptionPDFQuality.Width)); if SimpleTranslator.SetLangByIndex(cbLanguages.ItemIndex) then begin // assign new value From dc7e5ee846791875167d375bb86df69513a78fbf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 28 Jan 2016 04:07:54 +0800 Subject: [PATCH 0898/2794] Bump version 0.9.31.3 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index b36e2776a..5ab52f289 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,11 @@ https://bintray.com/riderkick/FMD/data/db/view#files Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.31.3 (28-01-2016) +[*] Fix save as pdf issue with indexed images +[*] Updater, fix download manga list always failed (403 Forbidden) +[*] Various changes and bug fixes + 0.9.31.2 (24-01-2016) [*] Fix remove mangafox watermark (file IO error when using multiple threads) [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 97c303c37..54226b31b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="31"/> - <BuildNr Value="2"/> + <BuildNr Value="3"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5997ce089..9fff8d4a7 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.31.2 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.2/fmd_0.9.31.2.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.2/fmd_0.9.31.2_Win64.7z +VERSION=0.9.31.3 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.3/fmd_0.9.31.3.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.3/fmd_0.9.31.3_Win64.7z From 2df79a9ec76fb6a23083e37fee09dd6cfc0642df Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 29 Jan 2016 13:08:37 +0800 Subject: [PATCH 0899/2794] only replace different version number in readme.rtf and validate before savetofile fix #175 --- mangadownloader/forms/frmMain.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e37bbac54..f376bafc8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1717,14 +1717,17 @@ procedure TMainForm.LoadAbout; st := TStringList.Create; try regx.ModifierI := True; - regx.Expression := '(version.*)(\d+\.){3}\d+'; + regx.Expression := '(version.*)((\d+\.){3}\d+)'; st.LoadFromFile(s); if st.Count > 0 then for i := 0 to st.Count - 1 do if regx.Exec(st[i]) then begin - st[i] := regx.Replace(st[i], '$1\' + FMD_VERSION_NUMBER, True); - st.SaveToFile(s); + if regx.Match[2] <> FMD_VERSION_NUMBER then begin + st[i] := regx.Replace(st[i], '$1\' + FMD_VERSION_NUMBER, True); + if DeleteFileUTF8(s) then + st.SaveToFile(s); + end; Break; end; finally From 590b06eab664a4624c14ed4d7b4681c3ed023633 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 31 Jan 2016 22:41:03 +0800 Subject: [PATCH 0900/2794] updater, fix download sf url --- updater/uMain.pas | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index d519b0b4a..7332b097c 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -43,6 +43,7 @@ TfrmMain = class(TForm) TDownloadThread = class(TFMDThread) private FTotalSize, FCurrentSize :integer; + FIsSFURL :boolean; FHTTP :THTTPSendThread; FStatus :string; FProgress :string; @@ -62,7 +63,6 @@ TDownloadThread = class(TFMDThread) procedure OnThreadTerminate(Sender: TObject); public URL :string; - isSFURL :boolean; FileName :string; DirPath :string; MaxRetry :cardinal; @@ -173,8 +173,6 @@ constructor TDownloadThread.Create; FHTTP.Sock.OnStatus := @SockOnStatus; FHTTP.Timeout := 10000; FHTTP.SetProxy(ProxyType,ProxyHost,ProxyPort,ProxyUser,ProxyPass); - if isSFURL then - FHTTP.UserAgent := UA_CURL; FTotalSize := 0; FCurrentSize := 0; URL := ''; @@ -281,7 +279,7 @@ procedure TDownloadThread.Execute; fname, sproject, sdir, - sfile : String; + s, sfile : String; st, HTTPHeaders: TStringList; filestream : TFileStreamUTF8; begin @@ -290,9 +288,13 @@ procedure TDownloadThread.Execute; regx := TRegExpr.Create; try HTTPHeaders.Assign(FHTTP.Headers); + s := LowerCase(URL); + FIsSFURL := (Pos('sourceforge.net/', s) <> 0) or (Pos('sf.net/', s) <> 0); + if FIsSFURL then + FHTTP.UserAgent := UA_CURL; regx.ModifierI := True; - if isSFURL then + if FIsSFURL then begin regx.Expression := '/download$'; URL := Trim(regx.Replace(URL, '', False)); @@ -311,7 +313,6 @@ procedure TDownloadThread.Execute; FileName := sfile; rurl := 'http://sourceforge.net/projects/' + sproject + '/files/' + sdir + '/' + sfile + '/download'; - rurl := EncodeURL(DecodeURL(Trim(rurl))); end else begin @@ -365,12 +366,12 @@ procedure TDownloadThread.Execute; FHTTP.Clear; end; - if (FHTTP.ResultCode >= 300) or isSFURL then + if ((FHTTP.ResultCode >= 300) or FIsSFURL) and (FHTTP.Headers.Values['Location'] <> '') then begin HTTPHeaders.Values['Referer'] := ' ' + rurl; UpdateStatus(RS_Redirected); rurl := Trim(FHTTP.Headers.Values['Location']); - if isSFURL then + if FIsSFURL then begin if (Pos('use_mirror=', rurl) > 0) then begin @@ -646,8 +647,6 @@ procedure TfrmMain.FormShow(Sender :TObject); begin dl := TDownloadThread.Create; dl.URL := _URL; - dl.isSFURL := (Pos('sourceforge.net/', LowerCase(dl.URL)) <> 0) or - (Pos('sf.net/', dl.URL) <> 0); dl.MaxRetry := _MaxRetry; if _UpdApp then dl.DirPath := GetCurrentDirUTF8 From 9433ecc2a363be78296659335ab843cb389d73bd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 31 Jan 2016 23:08:35 +0800 Subject: [PATCH 0901/2794] updater, clean up and fix --- updater/uMain.pas | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 7332b097c..2e98ac639 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -43,7 +43,6 @@ TfrmMain = class(TForm) TDownloadThread = class(TFMDThread) private FTotalSize, FCurrentSize :integer; - FIsSFURL :boolean; FHTTP :THTTPSendThread; FStatus :string; FProgress :string; @@ -288,17 +287,20 @@ procedure TDownloadThread.Execute; regx := TRegExpr.Create; try HTTPHeaders.Assign(FHTTP.Headers); - s := LowerCase(URL); - FIsSFURL := (Pos('sourceforge.net/', s) <> 0) or (Pos('sf.net/', s) <> 0); - if FIsSFURL then - FHTTP.UserAgent := UA_CURL; - regx.ModifierI := True; - if FIsSFURL then + s := LowerCase(URL); + if (Pos('sourceforge.net/', s) <> 0) or (Pos('sf.net/', s) <> 0) then begin + FHTTP.UserAgent := UA_CURL; regx.Expression := '/download$'; URL := Trim(regx.Replace(URL, '', False)); - //**parsing SF url + //**parsing and fixing SF url + if Pos('sf.net/', s) > 0 then begin + URL := StringReplace(URL, 'sf.net/', 'sourceforge.net/', [rfIgnoreCase]); + s := LowerCase(URL); + end; + if Pos('sourceforge.net/p/', s) > 0 then + URL := StringReplace(URL, 'sourceforge.net/p/', 'sourceforge.net/projects/', [rfIgnoreCase]); regx.Expression := '^.*sourceforge.net/projects/(.+)/files/(.+)/([^/]+)$'; if not regx.Exec(URL) then begin @@ -366,22 +368,11 @@ procedure TDownloadThread.Execute; FHTTP.Clear; end; - if ((FHTTP.ResultCode >= 300) or FIsSFURL) and (FHTTP.Headers.Values['Location'] <> '') then + if (FHTTP.ResultCode >= 300) and (FHTTP.Headers.Values['Location'] <> '') then begin HTTPHeaders.Values['Referer'] := ' ' + rurl; UpdateStatus(RS_Redirected); rurl := Trim(FHTTP.Headers.Values['Location']); - if FIsSFURL then - begin - if (Pos('use_mirror=', rurl) > 0) then - begin - regx.Expression := '.*use_mirror=(.+)$'; - rurl := regx.Replace(rurl, '$1', True); - rurl := 'http://' + rurl + '.dl.sourceforge.net/project/' + - sproject + '/' + sdir + '/' + sfile; - end; - end; - rurl := EncodeURL(DecodeURL(Trim(rurl))); end; //**download file From 71c4a8127ec8b2647b1b3961a8a8a27404f3cf0e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 31 Jan 2016 23:09:51 +0800 Subject: [PATCH 0902/2794] updater, change version number --- updater/updater.lpi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/updater.lpi b/updater/updater.lpi index 1d401c763..8f1438e26 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MajorVersionNr Value="2"/> <MinorVersionNr Value="3"/> - <RevisionNr Value="2"/> + <RevisionNr Value="3"/> <Attributes pvaPrivateBuild="True"/> <StringTable FileDescription="Updater for Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="updater.exe" ProductName="Updater" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> From 8534e6321fd9cd93aa24a31b2be581a8a118192a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 01:26:16 +0800 Subject: [PATCH 0903/2794] baseunit, change getmangadatabaseurl with custom url --- baseunits/uBaseUnit.pas | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9efb7035a..e6f853273 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -580,6 +580,8 @@ interface PERVEDEN_BROWSER: string = '/en-directory/'; MANGALIB_PL_COOKIES: String; + + DBDownloadURL: string; //------------------------------------------ Genre: array [0..37] of String; @@ -806,7 +808,7 @@ function GetMangaSiteID(const Name: String): Integer; function GetMangaSiteName(const ID: Cardinal): String; function GetMangaSiteRoot(const Website: String): String; overload; function GetMangaSiteRoot(const MangaID: Cardinal): String; overload; -function GetMangaDatabaseURL(const Name: String): String; +function GetMangaDatabaseURL(const AWebsite: String): String; function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; function SitesWithSortedList(const website:String): Boolean; @@ -1237,10 +1239,15 @@ function GetMangaSiteRoot(const MangaID : Cardinal) : String; Result := WebsiteRoots[MangaID, 1]; end; -// bad coding.. but this is how FMD works -function GetMangaDatabaseURL(const Name: String): String; +function GetMangaDatabaseURL(const AWebsite: String): String; begin - Result := 'https://bintray.com/artifact/download/riderkick/FMD/db/' + Name + '.7z'; + if DBDownloadURL='' then + DBDownloadURL:='https://bintray.com/artifact/download/riderkick/FMD/db/<website>.7z'; + Result:=DBDownloadURL; + if Pos('<website>',LowerCase(Result))>0 then + Result:=StringReplace(Result,'<website>',AWebsite,[rfIgnoreCase,rfReplaceAll]) + else + Result:=Result+AWebsite; end; function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; From ee4eac8709e7c3a682f7128c819100160b5b5bb2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 01:26:56 +0800 Subject: [PATCH 0904/2794] frmmain, assign dbdownloadurl with value from mangalist.ini --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f376bafc8..566c0a626 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4621,6 +4621,7 @@ procedure TMainForm.LoadMangaOptions; data: PSingleItem; wName, wLang: TStringList; begin + DBDownloadURL:=mangalistIni.ReadString('general','DBDownloadURL',''); wName := TStringList.Create; wLang := TStringList.Create; lang := TStringList.Create; From 97af01d9b9f3a64da52a99aa71ddfb9419885d70 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 03:26:32 +0800 Subject: [PATCH 0905/2794] remove redhawkscan, website offline close #176 --- .../RedHawkScans/chapter_page_number.inc | 33 ----- .../RedHawkScans/directory_page_number.inc | 37 ----- baseunits/includes/RedHawkScans/image_url.inc | 32 ----- .../RedHawkScans/manga_information.inc | 116 ---------------- .../includes/RedHawkScans/names_and_links.inc | 39 ------ baseunits/uBaseUnit.pas | 130 +++++++++--------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- config/mangalist.ini | 2 +- 9 files changed, 64 insertions(+), 350 deletions(-) delete mode 100644 baseunits/includes/RedHawkScans/chapter_page_number.inc delete mode 100644 baseunits/includes/RedHawkScans/directory_page_number.inc delete mode 100644 baseunits/includes/RedHawkScans/image_url.inc delete mode 100644 baseunits/includes/RedHawkScans/manga_information.inc delete mode 100644 baseunits/includes/RedHawkScans/names_and_links.inc diff --git a/baseunits/includes/RedHawkScans/chapter_page_number.inc b/baseunits/includes/RedHawkScans/chapter_page_number.inc deleted file mode 100644 index 1c8ffe43a..000000000 --- a/baseunits/includes/RedHawkScans/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetRedHawkScansPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(REDHAWKSCANS_ID, URL) + 'page/1'); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 1 to parse.Count - 1 do - begin - if (Pos('class="topbar_right"', parse[i]) > 0) then - begin - s := parse[i + 4]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/RedHawkScans/directory_page_number.inc b/baseunits/includes/RedHawkScans/directory_page_number.inc deleted file mode 100644 index bfcaec06b..000000000 --- a/baseunits/includes/RedHawkScans/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetRedHawkScansDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[REDHAWKSCANS_ID, 1] + - REDHAWKSCANS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('Last ', parse[i]) > 0) and - (Pos('class="gbutton', parse[i - 1]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse[i - 1], '/list/', '/"'))); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/RedHawkScans/image_url.inc b/baseunits/includes/RedHawkScans/image_url.inc deleted file mode 100644 index 49df161f5..000000000 --- a/baseunits/includes/RedHawkScans/image_url.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetRedHawkScansImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(REDHAWKSCANS_ID, URL) + 'page/' + - IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="open"', parse[i]) > 0) then - begin - manager.container.PageLinks[workCounter] := - GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/RedHawkScans/manga_information.inc b/baseunits/includes/RedHawkScans/manga_information.inc deleted file mode 100644 index 2a9c2e5c8..000000000 --- a/baseunits/includes/RedHawkScans/manga_information.inc +++ /dev/null @@ -1,116 +0,0 @@ - function GetRedHawkScansInfoFromURL: Byte; - var - isExtractChapter: Boolean = False; - s: String; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(REDHAWKSCANS_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[REDHAWKSCANS_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (GetTagName(parse[i]) = 'img') and - (Pos('class="thumbnail"', parse[i - 2]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); - - // get summary - if (Pos('Description', parse[i]) <> 0) and - (Pos('<b', parse[i - 1]) <> 0) then - begin - j := i + 2; - while (j < parse.Count) and (Pos('</li>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - end; - - // get title - if (Pos('Title', parse[i]) <> 0) and - (Pos('<b', parse[i - 1]) <> 0) and - (mangaInfo.title = '') then - mangaInfo.title := StringReplace(TrimLeft(StringFilter(parse[i + 2])), - ': ', '', []); - - if (not isExtractChapter) and - (Pos('All chapters available for', parse[i]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('class="element"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse[i + 3], 'href="', '"'), - WebsiteRoots[REDHAWKSCANS_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 4]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 2 < parse.Count) and (Pos('Author', parse[i]) <> 0) and - (Pos('<b', parse[i - 1]) <> 0) then - mangaInfo.authors := StringReplace(TrimLeft(parse[i + 2]), ': ', '', []); - - // get artists - if (i + 2 < parse.Count) and (Pos('Artist', parse[i]) <> 0) and - (Pos('<b', parse[i - 1]) <> 0) then - mangaInfo.artists := StringReplace(TrimLeft(parse[i + 2]), ': ', '', []); - - // get genres - if (Pos('Genre', parse[i]) <> 0) and - (Pos('<b', parse[i - 1]) <> 0) then - mangaInfo.genres := StringReplace(TrimLeft(parse[i + 2]), ': ', '', []); - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) and - (Pos('<b', parse[i - 1]) <> 0) then - begin - if Pos('Ongoing', parse[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/RedHawkScans/names_and_links.inc b/baseunits/includes/RedHawkScans/names_and_links.inc deleted file mode 100644 index cc5394a2f..000000000 --- a/baseunits/includes/RedHawkScans/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function RedHawkScansGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[REDHAWKSCANS_ID, 1] + - REDHAWKSCANS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="title"', parse[i]) > 0) and - (Pos('<a', parse[i + 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetVal(parse[i + 1], - 'href="'), WebsiteRoots[REDHAWKSCANS_ID, 1], '', []); - links.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e6f853273..087b22252 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -283,70 +283,69 @@ interface MANGAFRAME_ID = 15; EATMANGA_ID = 16; STARKANA_ID = 17; - REDHAWKSCANS_ID = 18; - BLOGTRUYEN_ID = 19; - KOMIKID_ID = 20; - SUBMANGA_ID = 21; - ESMANGAHERE_ID = 22; - ANIMEEXTREMIST_ID = 23; - HUGEMANGA_ID = 24; - S2SCAN_ID = 25; - SENMANGA_ID = 26; - IMANHUA_ID = 27; - MABUNS_ID = 28; - MANGAESTA_ID = 29; - CENTRALDEMANGAS_ID = 30; - EGSCANS_ID = 31; - MANGAAR_ID = 32; - MANGAAE_ID = 33; - ANIMESTORY_ID = 34; - LECTUREENLIGNE_ID = 35; - SCANMANGA_ID = 36; - MANGAGO_ID = 37; - DM5_ID = 38; - MANGACOW_ID = 39; - KIVMANGA_ID = 40; - MEINMANGA_ID = 41; - MANGASPROJECT_ID = 42; - MANGAREADER_POR_ID = 43; - NINEMANGA_ID = 44; - NINEMANGA_ES_ID = 45; - NINEMANGA_CN_ID = 46; - NINEMANGA_RU_ID = 47; - NINEMANGA_DE_ID = 48; - NINEMANGA_IT_ID = 49; - NINEMANGA_BR_ID = 50; - JAPANSHIN_ID = 51; - JAPSCAN_ID = 52; - CENTRUMMANGI_PL_ID = 53; - MANGALIB_PL_ID = 54; - ONEMANGA_ID = 55; - MANGATOWN_ID = 56; - MANGAOKU_ID = 57; - MYREADINGMANGAINFO_ID = 58; - IKOMIK_ID = 59; - NHENTAI_ID = 60; - MANGAMINT_ID = 61; - UNIXMANGA_ID = 62; - HAKIHOME_ID = 63; - EXTREMEMANGAS_ID = 64; - MANGAHOST_ID = 65; - PORNCOMIX_ID = 66; - PORNCOMIXRE_ID = 67; - PORNCOMIXIC_ID = 68; - XXCOMICS_ID = 69; - XXCOMICSMT_ID = 70; - XXCOMICS3D_ID = 71; - PORNXXXCOMICS_ID = 72; - MANGASEE_ID = 73; - MANGAKU_ID = 74; - ACADEMYVN_ID = 75; - MANGAAT_ID = 76; - READMANGATODAY_ID = 77; - LONEMANGA_ID = 78; - DYNASTYSCANS_ID = 79; - - WebsiteRoots: array [0..79] of array [0..1] of string = ( + BLOGTRUYEN_ID = 18; + KOMIKID_ID = 19; + SUBMANGA_ID = 20; + ESMANGAHERE_ID = 21; + ANIMEEXTREMIST_ID = 22; + HUGEMANGA_ID = 23; + S2SCAN_ID = 24; + SENMANGA_ID = 25; + IMANHUA_ID = 26; + MABUNS_ID = 27; + MANGAESTA_ID = 28; + CENTRALDEMANGAS_ID = 29; + EGSCANS_ID = 30; + MANGAAR_ID = 31; + MANGAAE_ID = 32; + ANIMESTORY_ID = 33; + LECTUREENLIGNE_ID = 34; + SCANMANGA_ID = 35; + MANGAGO_ID = 36; + DM5_ID = 37; + MANGACOW_ID = 38; + KIVMANGA_ID = 39; + MEINMANGA_ID = 40; + MANGASPROJECT_ID = 41; + MANGAREADER_POR_ID = 42; + NINEMANGA_ID = 43; + NINEMANGA_ES_ID = 44; + NINEMANGA_CN_ID = 45; + NINEMANGA_RU_ID = 46; + NINEMANGA_DE_ID = 47; + NINEMANGA_IT_ID = 48; + NINEMANGA_BR_ID = 49; + JAPANSHIN_ID = 50; + JAPSCAN_ID = 51; + CENTRUMMANGI_PL_ID = 52; + MANGALIB_PL_ID = 53; + ONEMANGA_ID = 54; + MANGATOWN_ID = 55; + MANGAOKU_ID = 56; + MYREADINGMANGAINFO_ID = 57; + IKOMIK_ID = 58; + NHENTAI_ID = 59; + MANGAMINT_ID = 60; + UNIXMANGA_ID = 61; + HAKIHOME_ID = 62; + EXTREMEMANGAS_ID = 63; + MANGAHOST_ID = 64; + PORNCOMIX_ID = 65; + PORNCOMIXRE_ID = 66; + PORNCOMIXIC_ID = 67; + XXCOMICS_ID = 68; + XXCOMICSMT_ID = 69; + XXCOMICS3D_ID = 70; + PORNXXXCOMICS_ID = 71; + MANGASEE_ID = 72; + MANGAKU_ID = 73; + ACADEMYVN_ID = 74; + MANGAAT_ID = 75; + READMANGATODAY_ID = 76; + LONEMANGA_ID = 77; + DYNASTYSCANS_ID = 78; + + WebsiteRoots: array [0..78] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -365,7 +364,6 @@ interface ('MangaFrame', 'http://www.mangaframe.com'), ('EatManga', 'http://eatmanga.com'), ('Starkana', 'http://starkana.jp'), - ('RedHawkScans', 'http://manga.redhawkscans.com'), ('BlogTruyen', 'http://blogtruyen.com'), ('Komikid', 'http://www.komikid.com'), ('SubManga', 'http://submanga.com'), @@ -473,8 +471,6 @@ interface STARKANA_BROWSER = '/manga/list'; - REDHAWKSCANS_BROWSER = '/reader/list/'; - BLOGTRUYEN_BROWSER = '/danhsach/tatca'; BLOGTRUYEN_JS_BROWSER = '/ListStory/GetListStory/'; BLOGTRUYEN_POST_FORM = 'Url=tatca&OrderBy=1&PageIndex='; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 561040e26..7d23676d5 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -808,8 +808,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/BlogTruyen/directory_page_number.inc} - {$I includes/RedHawkScans/directory_page_number.inc} - {$I includes/S2Scans/directory_page_number.inc} {$I includes/LectureEnLigne/directory_page_number.inc} @@ -914,9 +912,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenDirectoryPageNumber else - if WebsiteID = REDHAWKSCANS_ID then - Result := GetRedHawkScansDirectoryPageNumber - else if WebsiteID = S2SCAN_ID then Result := GetS2ScanDirectoryPageNumber else @@ -1082,8 +1077,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaGo/names_and_links.inc} - {$I includes/RedHawkScans/names_and_links.inc} - {$I includes/S2Scans/names_and_links.inc} {$I includes/EGScans/names_and_links.inc} @@ -1193,9 +1186,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGAGO_ID then Result := MangaGoGetNamesAndLinks else - if WebsiteID = REDHAWKSCANS_ID then - Result := RedHawkScansGetNamesAndLinks - else if WebsiteID = S2SCAN_ID then Result := S2ScanGetNamesAndLinks else @@ -1419,8 +1409,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/EatManga/manga_information.inc} - {$I includes/RedHawkScans/manga_information.inc} - {$I includes/S2Scans/manga_information.inc} {$I includes/EGScans/manga_information.inc} @@ -1577,9 +1565,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGAGO_ID then Result := GetMangaGoInfoFromURL else - if WebsiteID = REDHAWKSCANS_ID then - Result := GetRedHawkScansInfoFromURL - else if WebsiteID = S2SCAN_ID then Result := GetS2scanInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ae1d5ff7d..38ab1687b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -408,8 +408,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MeinManga/chapter_page_number.inc} - {$I includes/RedHawkScans/chapter_page_number.inc} - {$I includes/S2Scans/chapter_page_number.inc} {$I includes/SenManga/chapter_page_number.inc} @@ -501,9 +499,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoPageNumber else - if manager.container.MangaSiteID = REDHAWKSCANS_ID then - Result := GetRedHawkScansPageNumber - else if manager.container.MangaSiteID = S2SCAN_ID then Result := GetS2scanPageNumber else @@ -705,8 +700,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaVadisi/image_url.inc} - {$I includes/RedHawkScans/image_url.inc} - {$I includes/ScanManga/image_url.inc} {$I includes/SenManga/image_url.inc} @@ -800,9 +793,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoImageURL else - if manager.container.MangaSiteID = REDHAWKSCANS_ID then - Result := GetRedHawkScansImageURL - else if manager.container.MangaSiteID = EGSCANS_ID then Result := GetEGScansImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index ce76dfa0e..111dc2dcd 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,7 +5,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader Arabic=MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,RedHawkScans,S2Scans,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From fe5e4154ffba6a0a92bc74243b50e241adc95648 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 05:25:36 +0800 Subject: [PATCH 0906/2794] updater, remove mf dialog --- updater/languages/updater.en.po | 30 ++++----------------------- updater/languages/updater.id_ID.po | 21 ++++--------------- updater/languages/updater.po | 15 ++++---------- updater/uMain.pas | 33 ++++++------------------------ 4 files changed, 18 insertions(+), 81 deletions(-) diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index 3ac32a9fb..bb6f9bd14 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -11,6 +11,10 @@ msgstr "" "Language: en\n" "X-Generator: Poedit 1.8.2\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "File size" @@ -51,32 +55,6 @@ msgstr "Failed loading page!" msgid "File not found!" msgstr "File not found!" -#: umain.rs_filenotfound_mfdatalink -#| msgid "" -#| "File not found!\n" -#| "This site probably have been added to unofficial build.\n" -#| "\n" -#| "Remedy:\n" -#| "Build you manga list from scratch or download manually from this link:\n" -#| "%s\n" -#| "Link copied to clipboard!\n" -msgid "" -"File not found!\n" -"This site probably have been added to unofficial build.\n" -"\n" -"Remedy:\n" -"Build you manga list from scratch or download manually from this link:\n" -"%s\n" -"Link copied to clipboard!\n" -msgstr "" -"File not found!\n" -"This site probably have been added to unofficial build.\n" -"\n" -"Remedy:\n" -"Build you manga list from scratch or download manually from this link:\n" -"%s\n" -"Link copied to clipboard!\n" - #: umain.rs_finished msgid "Finished." msgstr "Finished." diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index b20963fde..85672136c 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -11,6 +11,10 @@ msgstr "" "Language: id_ID\n" "X-Generator: Poedit 1.8.2\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Ukuran" @@ -51,23 +55,6 @@ msgstr "Gagal memuat halaman!" msgid "File not found!" msgstr "Berkas tidak ditemukan!" -#: umain.rs_filenotfound_mfdatalink -msgid "" -"File not found!\n" -"This site probably have been added to unofficial build.\n" -"\n" -"Remedy:\n" -"Build you manga list from scratch or download manually from this link:\n" -"%s\n" -"Link copied to clipboard!\n" -msgstr "" -"Berkas tidak ditemukan\n" -"Kemungkinan situs ini telah ditambahkan ke versi tidak resmi.\n" -"\n" -"Buat sendiri list kamu dari awal atau coba download dari link ini:\n" -"%s\n" -"Link sudah disalin ke clipboard!\n" - #: umain.rs_finished msgid "Finished." msgstr "Selesai." diff --git a/updater/languages/updater.po b/updater/languages/updater.po index a6e4f13e2..b7474ab66 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -1,6 +1,10 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "" @@ -41,17 +45,6 @@ msgstr "" msgid "File not found!" msgstr "" -#: umain.rs_filenotfound_mfdatalink -msgid "" -"File not found!\n" -"This site probably have been added to unofficial build.\n" -"\n" -"Remedy:\n" -"Build you manga list from scratch or download manually from this link:\n" -"%s\n" -"Link copied to clipboard!\n" -msgstr "" - #: umain.rs_finished msgid "Finished." msgstr "" diff --git a/updater/uMain.pas b/updater/uMain.pas index 2e98ac639..821b5b11d 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -116,15 +116,6 @@ procedure IncReadCount(const ACount: Int64); RS_UnpackFile = 'Unpacking file [%s]...'; RS_Finished = 'Finished.'; RS_ErrorCheckAntiVirus = 'Error saving file, check your AntiVirus!'; - RS_FileNotFound_mfdatalink = - 'File not found!' + LineEnding + - 'This site probably have been added to unofficial build.' + LineEnding + - LineEnding + - 'Remedy:' + LineEnding + - 'Build you manga list from scratch or download manually from this link:' + - LineEnding + - '%s' + LineEnding + - 'Link copied to clipboard!'; RS_7zNotFound = 'Can''t extract file because 7za.exe not found!'; RS_Unknown = '(unknown)'; @@ -354,15 +345,9 @@ procedure TDownloadThread.Execute; if (FHTTP.ResultCode >= 400) and (FHTTP.ResultCode < 500) then begin UpdateStatus(RS_FileNotFound); - if _UpdApp then - ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + - RS_Response + ':' + LineEnding + - IntToStr(FHTTP.ResultCode) + ' ' + FHTTP.ResultString) - else - begin - Clipboard.AsText := mf_data_link; - ShowErrorMessage(Format(RS_FileNotFound_mfdatalink, [mf_data_link])); - end; + ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + + RS_Response + ':' + LineEnding + + IntToStr(FHTTP.ResultCode) + ' ' + FHTTP.ResultString); Break; end; FHTTP.Clear; @@ -406,15 +391,9 @@ procedure TDownloadThread.Execute; if ctry>=MaxRetry then begin UpdateStatus(RS_FileNotFound); - if _UpdApp then - ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + - RS_Response + ':' + LineEnding + - IntToStr(FHTTP.ResultCode) + ' ' + FHTTP.ResultString) - else - begin - Clipboard.AsText := mf_data_link; - ShowErrorMessage(Format(RS_FileNotFound_mfdatalink, [mf_data_link])); - end; + ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + + RS_Response + ':' + LineEnding + + IntToStr(FHTTP.ResultCode) + ' ' + FHTTP.ResultString); Break; end; //try to load previous url, in case it was temporary url From 5bffa619626c7e7b04bccb317d6936cf4f1c80d9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 05:29:00 +0800 Subject: [PATCH 0907/2794] fmd, added option to show dialog download db --- mangadownloader/forms/frmMain.lfm | 56 +++++++++++++++----------- mangadownloader/forms/frmMain.pas | 5 ++- mangadownloader/languages/fmd.en.po | 12 ++++-- mangadownloader/languages/fmd.id_ID.po | 12 ++++-- mangadownloader/languages/fmd.po | 12 ++++-- 5 files changed, 61 insertions(+), 36 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e0f9cf255..cfdbfa865 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,7 +1,7 @@ object MainForm: TMainForm Left = 273 Height = 616 - Top = 96 + Top = 76 Width = 819 ActiveControl = pcMain Caption = 'Free Manga Downloader' @@ -2621,7 +2621,7 @@ object MainForm: TMainForm end object tsUpdate: TTabSheet Caption = 'Updates' - ClientHeight = 375 + ClientHeight = 416 ClientWidth = 579 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 16 @@ -2721,43 +2721,53 @@ object MainForm: TMainForm end object tsDialogs: TTabSheet Caption = 'Dialogs' - ClientHeight = 375 + ChildSizing.LeftRightSpacing = 10 + ChildSizing.TopBottomSpacing = 10 + ClientHeight = 416 ClientWidth = 579 object gbDialogs: TGroupBox Left = 10 - Height = 346 - Top = 14 - Width = 556 - Anchors = [akTop, akLeft, akRight, akBottom] - ClientHeight = 326 - ClientWidth = 552 + Height = 101 + Top = 10 + Width = 559 + Align = alTop + AutoSize = True + Caption = 'Show dialog confirmation for' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 81 + ClientWidth = 555 TabOrder = 0 object cbOptionShowQuitDialog: TCheckBox - Left = 24 + Left = 6 Height = 19 - Top = 32 - Width = 66 + Top = 6 + Width = 179 Caption = 'Exit FMD' ParentFont = False TabOrder = 0 end - object lbOptionDialogs: TLabel - Left = 16 - Height = 15 - Top = 8 - Width = 158 - Caption = 'Show dialog confirmation for:' - ParentColor = False - end object cbOptionShowDeleteTaskDialog: TCheckBox - Left = 24 + Left = 6 Height = 19 - Top = 56 - Width = 122 + Top = 31 + Width = 179 Caption = 'Delete task/favorite' ParentFont = False TabOrder = 1 end + object cbOptionShowDownloadMangalistDialog: TCheckBox + Left = 6 + Height = 19 + Top = 56 + Width = 179 + Caption = 'Download manga list if empty' + ParentFont = False + TabOrder = 2 + end end end object tsWebsites: TTabSheet diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 566c0a626..317f24e9e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -57,6 +57,7 @@ TMainForm = class(TForm) cbOptionMangaFoxRemoveWatermark: TCheckBox; cbOptionMangaFoxRemoveWatermarkSaveAsPNG: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; + cbOptionShowDownloadMangalistDialog: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; cbOptionDigitVolume: TCheckBox; @@ -219,7 +220,6 @@ TMainForm = class(TForm) lbOptionLetFMDDo: TLabel; lbOptionNewMangaTime: TLabel; lbOptionLanguage: TLabel; - lbOptionDialogs: TLabel; lbFilterCustomGenres: TLabel; lbFilterSummary: TLabel; lbFilterStatus: TLabel; @@ -2270,6 +2270,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); end else + if cbOptionShowDownloadMangalistDialog.Checked then RunGetList; end; end; @@ -4334,6 +4335,7 @@ procedure TMainForm.LoadOptions; // dialogs cbOptionShowQuitDialog.Checked := ReadBool('dialogs', 'ShowQuitDialog', True); cbOptionShowDeleteTaskDialog.Checked := ReadBool('dialogs', 'ShowDeleteDldTaskDialog', True); + cbOptionShowDownloadMangalistDialog.Checked := ReadBool('dialogs', 'ShowDownloadMangalistDialog', True); // misc cbOptionBatotoShowScanGroup.Checked := ReadBool('misc', 'BatotoShowScanGroup', True); @@ -4454,6 +4456,7 @@ procedure TMainForm.SaveOptions; // dialogs WriteBool('dialogs', 'ShowQuitDialog', cbOptionShowQuitDialog.Checked); WriteBool('dialogs', 'ShowDeleteDldTaskDialog', cbOptionShowDeleteTaskDialog.Checked); + WriteBool('dialogs', 'ShowDownloadMangalistDialog', cbOptionShowDownloadMangalistDialog.Checked); // misc WriteBool('misc', 'BatotoShowScanGroup', cbOptionBatotoShowScanGroup.Checked); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index e5f8d1414..b8110640e 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -565,6 +565,10 @@ msgstr "Remove manga name from chapter" msgid "Delete task/favorite" msgstr "Delete task/favorite" +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Download manga list if empty" + #: tmainform.cboptionshowdownloadtoolbar.caption msgid "Show downloads toolbar" msgstr "Show downloads toolbar" @@ -1003,6 +1007,10 @@ msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." msgstr "Search website..." +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Show dialog confirmation for" + #: tmainform.gbdroptarget.caption msgid "Drop Box" msgstr "Drop Box" @@ -1133,10 +1141,6 @@ msgstr "Connection timeout (seconds)" msgid "Chapter folder name:" msgstr "Chapter folder name:" -#: tmainform.lboptiondialogs.caption -msgid "Show dialog confirmation for:" -msgstr "Show dialog confirmation for:" - #: tmainform.lboptionexternal.caption msgid "Open manga by using external program:" msgstr "Open manga by using external program:" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 970675ce6..19cbe1209 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -554,6 +554,10 @@ msgstr "Hapus nama komik dari bab" msgid "Delete task/favorite" msgstr "Hapus unduhan/kesukaan" +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Unduh daftar komik jika kosong" + #: tmainform.cboptionshowdownloadtoolbar.caption msgid "Show downloads toolbar" msgstr "Tampilkan toolbar unduhan" @@ -988,6 +992,10 @@ msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." msgstr "Cari situs web..." +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Tampilkan dialog konfirmasi untuk" + #: tmainform.gbdroptarget.caption msgid "Drop Box" msgstr "Kotak unduh" @@ -1117,10 +1125,6 @@ msgstr "Batas waktu koneksi (detik)" msgid "Chapter folder name:" msgstr "Nama folder bab:" -#: tmainform.lboptiondialogs.caption -msgid "Show dialog confirmation for:" -msgstr "Tampilkan dialog konfirmasi untuk:" - #: tmainform.lboptionexternal.caption msgid "Open manga by using external program:" msgstr "Buka komik dengan program eksternal:" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 08c99ca1e..524089e29 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -526,6 +526,10 @@ msgstr "" msgid "Delete task/favorite" msgstr "" +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "" + #: tmainform.cboptionshowdownloadtoolbar.caption msgid "Show downloads toolbar" msgstr "" @@ -958,6 +962,10 @@ msgctxt "TMAINFORM.EDWEBSITESSEARCH.TEXTHINT" msgid "Search website..." msgstr "" +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "" + #: tmainform.gbdroptarget.caption msgid "Drop Box" msgstr "" @@ -1069,10 +1077,6 @@ msgstr "" msgid "Chapter folder name:" msgstr "" -#: tmainform.lboptiondialogs.caption -msgid "Show dialog confirmation for:" -msgstr "" - #: tmainform.lboptionexternal.caption msgid "Open manga by using external program:" msgstr "" From f447b0d6751a5a1d2305c15f78957526ba86d5c6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 06:17:56 +0800 Subject: [PATCH 0908/2794] cleanup and fix --- mangadownloader/md.lpi | 19 ++++++++++--------- mangadownloader/md.lpr | 15 ++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 54226b31b..2d94bc720 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -33,8 +33,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -77,8 +77,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -124,8 +124,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -168,8 +168,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\fasthtmlparser;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -187,6 +187,7 @@ </CodeGeneration> <Linking> <Debugging> + <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> @@ -318,7 +319,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\RedHawkScans;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index cc61cb7ac..48e60b3a1 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -6,16 +6,13 @@ uses {$IFDEF DEBUGLEAKS} - heaptrc, SysUtils, + SysUtils, {$ENDIF} - {$DEFINE UseCThreads} - {$IFDEF UNIX} - {$IFDEF UseCThreads} - cthreads, - {$ENDIF} - {$ENDIF} - Forms, LazFileUtils, Interfaces, simpleipc, IniFiles, - sqlite3dyn, uBaseUnit, frmMain; + {$IFDEF UNIX}{$IFDEF UseCThreads} + cthreads, + {$ENDIF}{$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, uBaseUnit, frmMain; var CheckInstance: Boolean = True; From 8030fa07938070b2dfbfe54130ba0e4296ab0284 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 07:41:49 +0800 Subject: [PATCH 0909/2794] change db url to new sf --- config/mangalist.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/mangalist.ini b/config/mangalist.ini index 111dc2dcd..7075a7db4 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -1,5 +1,6 @@ [general] DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader +DBDownloadURL=http://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] Arabic=MangaAe,MangaAr,MangaAt From 7852bdfc7aa8f199c930eb2de4f94b9fe7eaa18c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 08:23:59 +0800 Subject: [PATCH 0910/2794] Bump version 0.9.32.0 --- changelog.txt | 10 +++++++--- mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5ab52f289..9ef29aa60 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,12 +1,16 @@ Free Manga Downloader Project page: https://github.com/riderkick/FMD -For manga list data check: -https://bintray.com/riderkick/FMD/data/db/view#files - Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.32.0 (01-02-2016) +[*] Updater: various fix +[+] Added option to show/hide dialog download manga list from server when local database empty +[*] RedHawkScan: Removed, website offline +[*] Change manga list download url to new location +[*] Various changes and bug fixes + 0.9.31.3 (28-01-2016) [*] Fix save as pdf issue with indexed images [*] Updater, fix download manga list always failed (403 Forbidden) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2d94bc720..f6e969173 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="31"/> - <BuildNr Value="3"/> + <RevisionNr Value="32"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 9fff8d4a7..e7ac0ba08 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.31.3 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.31.3/fmd_0.9.31.3.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.31.3/fmd_0.9.31.3_Win64.7z +VERSION=0.9.32.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.0/fmd_0.9.32.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.0/fmd_0.9.32.0_Win64.7z From 59a3b9bc76772b01167093841de17568fd2062be Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Feb 2016 20:09:17 +0800 Subject: [PATCH 0911/2794] move shoujosense to en-sc --- config/mangalist.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 7075a7db4..57aebaa2f 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,9 +4,9 @@ DBDownloadURL=http://sourceforge.net/projects/newfmd/files/data/<website>.7z/dow [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,Shoujosense,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From bef9b5882ec7e218baa60aa2b16985a7ed887b39 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 00:49:03 +0800 Subject: [PATCH 0912/2794] udata, various method to clean mangainfo after get --- baseunits/uData.pas | 168 ++++++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 7d23676d5..c248ca166 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1740,93 +1740,107 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; end; end; - s := mangaInfo.artists; - if (s <> '') and (s[1] = '<') then - mangaInfo.artists := ''; - s := mangaInfo.authors; - if (s <> '') and (s[1] = '<') then - mangaInfo.authors := ''; - - // check everything once more - mangaInfo.title := Trim(RemoveStringBreaks(CommonStringFilter(mangaInfo.title))); - mangaInfo.authors := Trim(RemoveStringBreaks(Trim(mangaInfo.authors))); - mangaInfo.artists := Trim(RemoveStringBreaks(Trim(mangaInfo.artists))); - mangaInfo.genres := Trim(RemoveStringBreaks(Trim(mangaInfo.genres))); - - mangaInfo.authors := TrimRightChar(Trim(mangaInfo.authors), [',']); - mangaInfo.artists := TrimRightChar(Trim(mangaInfo.artists), [',']); - mangaInfo.genres := TrimRightChar(Trim(mangaInfo.genres), [',']); - - mangaInfo.summary := Trim(mangaInfo.summary); - - //// strip - //mangaInfo.summary := StringBreaks(mangaInfo.summary); - //mangaInfo.summary := Trim(TrimChar(mangaInfo.summary, [#13, #10])); - //mangaInfo.summary := BreaksString(mangaInfo.summary); - //// strip double CR - //mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\n\r\n\r', '\n\r', [rfReplaceAll])); - //mangaInfo.summary := Trim(StringReplace(mangaInfo.summary, '\r\n\r\n', '\r\n', [rfReplaceAll])); - - // fix info - if (mangaInfo.authors = '-') or (mangaInfo.authors = ':') then - mangaInfo.authors := ''; - if (mangaInfo.artists = '-') or (mangaInfo.artists = ':') then - mangaInfo.artists := ''; - if (mangaInfo.summary = '-') or (mangaInfo.summary = ':') then - mangaInfo.summary := ''; - - // remove duplicate chapter - if mangaInfo.chapterLinks.Count > 0 then - begin - j := 0; - while j < (mangaInfo.chapterLinks.Count - 1) do + with mangaInfo do begin + s := artists; + if (s <> '') and (s[1] = '<') then + artists := ''; + s := authors; + if (s <> '') and (s[1] = '<') then + authors := ''; + + // check everything once more + title := Trim(RemoveStringBreaks(CommonStringFilter(title))); + authors := Trim(RemoveStringBreaks(Trim(authors))); + artists := Trim(RemoveStringBreaks(Trim(artists))); + genres := Trim(RemoveStringBreaks(Trim(genres))); + + authors := TrimRightChar(Trim(authors), [',']); + artists := TrimRightChar(Trim(artists), [',']); + genres := TrimRightChar(Trim(genres), [',']); + + summary := Trim(summary); + + //// strip + //summary := StringBreaks(summary); + //summary := Trim(TrimChar(summary, [#13, #10])); + //summary := BreaksString(summary); + //// strip double CR + //summary := Trim(StringReplace(summary, '\n\r\n\r', '\n\r', [rfReplaceAll])); + //summary := Trim(StringReplace(summary, '\r\n\r\n', '\r\n', [rfReplaceAll])); + + // fix info + if (authors = '-') or (authors = ':') then + authors := ''; + if (artists = '-') or (artists = ':') then + artists := ''; + if (summary = '-') or (summary = ':') then + summary := ''; + + // cleanup chapters + if chapterLinks.Count>0 then begin + while chapterName.Count<chapterLinks.Count do + chapterName.Add(''); + while chapterLinks.Count<chapterName.Count do + chapterName.Delete(chapterName.Count-1); + for j:=0 to chapterLinks.Count-1 do begin + chapterLinks[j]:=Trim(chapterLinks[j]); + chapterName[j]:=Trim(chapterName[j]); + end; + end; + + // remove duplicate chapter + if chapterLinks.Count > 0 then begin - del := False; - if (j + 1) < mangaInfo.chapterLinks.Count then - for k := j + 1 to mangaInfo.chapterLinks.Count - 1 do - begin - if SameText(mangaInfo.chapterLinks[j], mangaInfo.chapterLinks[k]) then + j := 0; + while j < (chapterLinks.Count - 1) do + begin + del := False; + if (j + 1) < chapterLinks.Count then + for k := j + 1 to chapterLinks.Count - 1 do begin - mangaInfo.chapterLinks.Delete(j); - mangaInfo.chapterName.Delete(j); - del := True; - Break; + if SameText(chapterLinks[j], chapterLinks[k]) then + begin + chapterLinks.Delete(j); + chapterName.Delete(j); + del := True; + Break; + end; end; - end; - if not del then - Inc(j); + if not del then + Inc(j); + end; end; - end; - if mangaInfo.chapterLinks.Count > 0 then - begin - // remove host from chapter links - RemoveHostFromURLsPair(mangaInfo.chapterLinks, mangaInfo.chapterName); - // fixing chapter name - for j := 0 to mangaInfo.chapterName.Count - 1 do + if chapterLinks.Count > 0 then begin - mangaInfo.chapterName.Strings[j] := Trim(RemoveStringBreaks( - CommonStringFilter(mangaInfo.chapterName[j]))); - end; + // remove host from chapter links + RemoveHostFromURLsPair(chapterLinks, chapterName); + // fixing chapter name + for j := 0 to chapterName.Count - 1 do + begin + chapterName.Strings[j] := Trim(RemoveStringBreaks( + CommonStringFilter(chapterName[j]))); + end; - //remove manga name from chapter - if OptionRemoveMangaNameFromChapter and (mangaInfo.title <> '') then - begin - s := LowerCase(mangaInfo.title); - j := Length(s); - for k := 0 to mangaInfo.chapterName.Count - 1 do begin - s2 := LowerCase(mangaInfo.chapterName[k]); - if Length(s2) > j then - if Pos(s, s2) = 1 then begin - s2 := mangaInfo.chapterName[k]; - Delete(s2, 1, j); - mangaInfo.chapterName[k] := Trim(s2); - end; + //remove manga name from chapter + if OptionRemoveMangaNameFromChapter and (title <> '') then + begin + s := LowerCase(title); + j := Length(s); + for k := 0 to chapterName.Count - 1 do begin + s2 := LowerCase(chapterName[k]); + if Length(s2) > j then + if Pos(s, s2) = 1 then begin + s2 := chapterName[k]; + Delete(s2, 1, j); + chapterName[k] := Trim(s2); + end; + end; end; end; - end; - mangaInfo.numChapter := mangaInfo.chapterLinks.Count; + numChapter := chapterLinks.Count; + end; end; procedure TMangaInformation.SyncMinorInfoToData(const DataProcess: TDataProcess; From 6513a6bb8700507f64666c4a88f014d76cff417c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 00:50:17 +0800 Subject: [PATCH 0913/2794] baseunit, trim urls before remove host from urls --- baseunits/uBaseUnit.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 087b22252..b64af37dc 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1470,6 +1470,7 @@ procedure RemoveHostFromURLs(const URLs : TStringList); Expression := REGEX_HOST; for i := 0 to URLs.Count - 1 do begin + URLs[i]:=Trim(URLs[i]); s := Replace(URLs[i], '$4', True); if s = '' then s := URLs[i]; @@ -1496,6 +1497,7 @@ procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); i := 0; while i < URLs.Count do begin + URLs[i]:=Trim(URLs[i]); s := Replace(URLs[i], '$4', True); if s = '' then s := URLs[i]; From d8d8c3f2bdd1985120ce10b93377bf2e012c6922 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 00:55:07 +0800 Subject: [PATCH 0914/2794] remove hakihome old script #178 --- .../includes/HakiHome/chapter_page_number.inc | 37 ------ .../HakiHome/directory_page_number.inc | 34 ------ baseunits/includes/HakiHome/image_url.inc | 39 ------- .../includes/HakiHome/manga_information.inc | 105 ------------------ .../includes/HakiHome/names_and_links.inc | 49 -------- baseunits/uBaseUnit.pas | 41 ++++--- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 10 -- 8 files changed, 19 insertions(+), 311 deletions(-) delete mode 100644 baseunits/includes/HakiHome/chapter_page_number.inc delete mode 100644 baseunits/includes/HakiHome/directory_page_number.inc delete mode 100644 baseunits/includes/HakiHome/image_url.inc delete mode 100644 baseunits/includes/HakiHome/manga_information.inc delete mode 100644 baseunits/includes/HakiHome/names_and_links.inc diff --git a/baseunits/includes/HakiHome/chapter_page_number.inc b/baseunits/includes/HakiHome/chapter_page_number.inc deleted file mode 100644 index fbea7abb1..000000000 --- a/baseunits/includes/HakiHome/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetHakiHomePageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - isExtractPageNumber: Boolean = False; - begin - manager.container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(HAKIHOME_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - l.Text := FixHTMLTagQuote(l.Text); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('onchange="javascript:if', parse[i]) > 0) then - isExtractPageNumber := True; - if isExtractPageNumber and (Pos('</select', parse[i]) > 0) then - begin - isExtractPageNumber := False; - Break; - end; - if isExtractPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/HakiHome/directory_page_number.inc b/baseunits/includes/HakiHome/directory_page_number.inc deleted file mode 100644 index 354d61cfb..000000000 --- a/baseunits/includes/HakiHome/directory_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetHakiHomeDirectoryPageNumber: Byte; - var - i: Integer; - begin - Page := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[HAKIHOME_ID, 1] + HAKIHOME_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - Source.Text := FixHTMLTagQuote(Source.Text); - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - if i + 1 < parse.Count - 1 then - if (Pos('class="inbut"', parse[i]) > 0) and (Pos('<a', parse[i]) > 0) and - (Pos('Last', parse[i + 1]) > 0) then - begin - Result := NO_ERROR; - Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', Trim(GetVal(parse[i], 'href')), '$1', True), 1); - Break; - end; - end; - end; diff --git a/baseunits/includes/HakiHome/image_url.inc b/baseunits/includes/HakiHome/image_url.inc deleted file mode 100644 index 525f3d15d..000000000 --- a/baseunits/includes/HakiHome/image_url.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetHakiHomeImageURL: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(HAKIHOME_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - s := s + IntToStr(QWord(workCounter) + 1) + '.html'; - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - l.Text := FixHTMLTagQuote(l.Text); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if i + 2 < parse.Count - 1 then - if (Pos('id="con"', parse[i]) > 0) and (Pos('<img', parse[i + 2]) > 0) then - begin - manager.container.PageLinks[workCounter] := Trim(GetVal(parse[i + 2], 'src')); - Break; - end; - parse.Free; - end; diff --git a/baseunits/includes/HakiHome/manga_information.inc b/baseunits/includes/HakiHome/manga_information.inc deleted file mode 100644 index c8791cdc0..000000000 --- a/baseunits/includes/HakiHome/manga_information.inc +++ /dev/null @@ -1,105 +0,0 @@ - function GetHakiHomeInfoFromURL: Byte; - var - i: Integer; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[HAKIHOME_ID, 0]; - mangaInfo.url := FillMangaSiteHost(HAKIHOME_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //replace ' with " - Source.Text := FixHTMLTagQuote(Source.Text); - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.coverLink := ''; - mangaInfo.title := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.status := '0'; - - for i := 0 to parse.Count - 1 do - begin - //cover - if (Pos('<img', parse[i]) > 0) and (Pos('style="display', parse[i]) > 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //title - if (i + 2 < parse.Count - 1) then - if (Pos('class="tuade"', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2])))); - - //artist - if (i + 1 < parse.Count - 1) then - if (Pos('<a ', parse[i]) > 0) and (Pos('/art/', parse[i]) > 0) then - if Pos('<', parse[i + 1]) = 0 then - if mangaInfo.artists = '' then - mangaInfo.artists := Trim(parse[i + 1]) - else - mangaInfo.artists := mangaInfo.artists + ', ' + Trim(parse[i + 1]); - - //genres/tag - if (i + 1 < parse.Count - 1) then - if (Pos('/tag/', parse[i]) > 0) and - (Pos('<a ', parse[i]) > 0) and (Pos('title=', parse[i]) > 0) then - if Pos('<', parse[i + 1]) = 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - //genres/series/language - if (i + 2 < parse.Count - 1) then - if ((Pos('Series:', parse[i]) > 0) or ((Pos('Language:', parse[i]) > 0))) and - (Pos('<a ', parse[i + 1]) > 0) then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 2]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 2]); - - //chapters - if (Pos('<table', parse[i]) > 0) and (Pos('class="listing"', parse[i]) > 0) then - isExtractChapters := True; - if isExtractChapters and (Pos('</table', parse[i]) > 0) then - isExtractChapters := False; - if (i + 1 < parse.Count - 1) then - if isExtractChapters and (Pos('class="readchap"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[HAKIHOME_ID, 1], '', [rfIgnoreCase]))); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - end; - - // invert chapters - if mangaInfo.chapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - - if mangaInfo.chapterName.Count = 1 then - mangaInfo.chapterName[0] := mangaInfo.title - else - if mangaInfo.chapterName.Count > 1 then - for i := 0 to mangaInfo.chapterName.Count - 1 do - if Pos(LowerCase(mangaInfo.title), LowerCase(mangaInfo.chapterName[i])) = 0 then - mangaInfo.chapterName[i] := mangaInfo.title + ' ' + mangaInfo.chapterName[i]; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/HakiHome/names_and_links.inc b/baseunits/includes/HakiHome/names_and_links.inc deleted file mode 100644 index 9d484b910..000000000 --- a/baseunits/includes/HakiHome/names_and_links.inc +++ /dev/null @@ -1,49 +0,0 @@ - function HakiHomeNamesAndLinks: Byte; - var - i: Integer; - s: String; - isExtractNames: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[HAKIHOME_ID, 1] + HAKIHOME_BROWSER + '/pagel/'+ - IntToStr(StrToInt(URL) + 1) + '/'; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Source.Text := FixHTMLTagQuote(Source.Text); - //correcting some broken tag - Source.Text := StringReplace(Source.Text, '>" href=', '><a href=', [rfReplaceAll, rfIgnoreCase]); - Source.Text := StringReplace(Source.Text, '="<', '=""><', [rfReplaceAll, rfIgnoreCase]); - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<table', parse[i]) > 0) and (Pos('class="listing"', parse[i]) > 0) then - isExtractNames := True; - if isExtractNames and (Pos('</table', parse[i]) > 0) then - begin - isExtractNames := False; - Break; - end; - if i + 1 < parse.Count - 1 then - if isExtractNames and (Pos('<a', parse[i]) > 0) and - (Pos('class="tuade"', parse[i]) > 0) then - begin - Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - links.Add(Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[HAKIHOME_ID, 1], '', [rfIgnoreCase]))); - end; - end; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b64af37dc..076ae8fb4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -327,25 +327,25 @@ interface NHENTAI_ID = 59; MANGAMINT_ID = 60; UNIXMANGA_ID = 61; - HAKIHOME_ID = 62; - EXTREMEMANGAS_ID = 63; - MANGAHOST_ID = 64; - PORNCOMIX_ID = 65; - PORNCOMIXRE_ID = 66; - PORNCOMIXIC_ID = 67; - XXCOMICS_ID = 68; - XXCOMICSMT_ID = 69; - XXCOMICS3D_ID = 70; - PORNXXXCOMICS_ID = 71; - MANGASEE_ID = 72; - MANGAKU_ID = 73; - ACADEMYVN_ID = 74; - MANGAAT_ID = 75; - READMANGATODAY_ID = 76; - LONEMANGA_ID = 77; - DYNASTYSCANS_ID = 78; - - WebsiteRoots: array [0..78] of array [0..1] of string = ( + + EXTREMEMANGAS_ID = 62; + MANGAHOST_ID = 63; + PORNCOMIX_ID = 64; + PORNCOMIXRE_ID = 65; + PORNCOMIXIC_ID = 66; + XXCOMICS_ID = 67; + XXCOMICSMT_ID = 68; + XXCOMICS3D_ID = 69; + PORNXXXCOMICS_ID = 70; + MANGASEE_ID = 71; + MANGAKU_ID = 72; + ACADEMYVN_ID = 73; + MANGAAT_ID = 74; + READMANGATODAY_ID = 75; + LONEMANGA_ID = 76; + DYNASTYSCANS_ID = 77; + + WebsiteRoots: array [0..77] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -408,7 +408,6 @@ interface ('NHentai', 'http://nhentai.net'), ('MangaMint', 'http://www.mangamint.com'), ('UnixManga', 'http://unixmanga.co'), - ('HakiHome', 'http://hakihome.com'), ('ExtremeMangas', 'http://www.extrememangas.com'), ('MangaHost', 'http://br.mangahost.com'), ('PornComix', 'http://porncomix.wf'), @@ -542,8 +541,6 @@ interface UNIXMANGA_BROWSER = '/onlinereading/manga-lists.html'; - HAKIHOME_BROWSER = '/ListMangaHentai.html'; - EXTREMEMANGAS_BROWSER = '/2013/04/lista-de-mangas.html'; MANGAHOST_BROWSER = '/mangas'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c248ca166..1aa91bfb7 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -836,8 +836,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/MangaMint/directory_page_number.inc} - {$I includes/HakiHome/directory_page_number.inc} - {$I includes/MangaFrame/directory_page_number.inc} {$I includes/MangaHost/directory_page_number.inc} @@ -963,9 +961,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = MANGAMINT_ID then Result := GetMangaMintDirectoryPageNumber else - if WebsiteID = HAKIHOME_ID then - Result := GetHakiHomeDirectoryPageNumber - else if WebsiteID = MANGAFRAME_ID then Result := GetMangaFrameDirectoryPageNumber else @@ -1119,8 +1114,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/UnixManga/names_and_links.inc} - {$I includes/HakiHome/names_and_links.inc} - {$I includes/ExtremeMangas/names_and_links.inc} {$I includes/MangaHost/names_and_links.inc} @@ -1318,9 +1311,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = UNIXMANGA_ID then Result := UnixMangaNamesAndLinks else - if WebsiteID = HAKIHOME_ID then - Result := HakiHomeNamesAndLinks - else if WebsiteID = EXTREMEMANGAS_ID then Result := ExtremeMangasNamesAndLinks else @@ -1483,8 +1473,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/UnixManga/manga_information.inc} - {$I includes/HakiHome/manga_information.inc} - {$I includes/ExtremeMangas/manga_information.inc} {$I includes/MangaHost/manga_information.inc} @@ -1694,9 +1682,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = UNIXMANGA_ID then Result := GetUnixMangaInfoFromURL else - if WebsiteID = HAKIHOME_ID then - Result := GetHakiHomeInfoFromURL - else if WebsiteID = EXTREMEMANGAS_ID then Result := GetExtremeMangasInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 38ab1687b..c712dc2d5 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -448,8 +448,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/UnixManga/chapter_page_number.inc} - {$I includes/HakiHome/chapter_page_number.inc} - {$I includes/ExtremeMangas/chapter_page_number.inc} {$I includes/MangaHost/chapter_page_number.inc} @@ -599,9 +597,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaPageNumber else - if manager.container.MangaSiteID = HAKIHOME_ID then - Result := GetHakiHomePageNumber - else if manager.container.MangaSiteID = EXTREMEMANGAS_ID then Result := GetExtremeMangasPageNumber else @@ -742,8 +737,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/UnixManga/image_url.inc} - {$I includes/HakiHome/image_url.inc} - {$I includes/MangaHost/image_url.inc} {$I includes/PornComix/image_url.inc} @@ -911,9 +904,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaImageURL else - if manager.container.MangaSiteID = HAKIHOME_ID then - Result := GetHakiHomeImageURL - else if manager.container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostImageURL else From eaf6381bea15ecdbf917d9700c0654aa05ce3c71 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 00:55:35 +0800 Subject: [PATCH 0915/2794] added hakihome module fix #178 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/HakiHome.pas | 172 +++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/HakiHome.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 0402df2d2..964c1b918 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -22,4 +22,5 @@ uses UnionMangas, MangaStreamTo, MangaKoi, - GameofScanlation; + GameofScanlation, + Hakihome; diff --git a/baseunits/modules/HakiHome.pas b/baseunits/modules/HakiHome.pas new file mode 100644 index 000000000..490eb47da --- /dev/null +++ b/baseunits/modules/HakiHome.pas @@ -0,0 +1,172 @@ +unit Hakihome; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; + +implementation + +const + dirurl='/listmangahentai.html'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=query.XPathString('//*[@class="nav"]/li[last()-1]/a/@href'); + if s<>'' then Page:=StrToIntDef(GetBetween('/pagel/','/',s),1); + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='/pagel/'+IncStr(AURL)+'/'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@class="listing"]/tbody/tr/td/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//*[@class="noidung"]//img/@src'); + if title=''then title:=query.XPathString('//*[@class="tuade"]'); + artists:=SeparateRight(query.XPathString('//*[@class="art lefts"]'),':'); + genres:=SeparateRight(query.XPathString('//*[@class="category lefts"]'),':'); + AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="tag"]'),':')); + AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="lan rights"]'),':')); + for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + if (chapterName.Count=1) and (title<>'') then + chapterName[0]:=title; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + Cookies.Values['ReadType']:='2'; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('(//*[@id="topn"]/span/select)[last()]/option').Count; + s:=query.XPathString('//*[@id="contentchap"]//script[contains(.,"var jsondata")]'); + if s<>'' then begin + s:=Trim(GetBetween('=',';',s)); + query.ParseHTML(s); + for v in query.XPath('json(*)()') do + PageLinks.Add(v.toString); + end; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=AppendURLDelim(AURL)+IncStr(DownloadThread.workCounter)+'/'; + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageLinks[DownloadThread.workCounter]:=query.XPathString('//*[@id="con"]//img/@src'); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='Hakihome'; + RootURL:='http://hakihome.com'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 37b53595babbf42a726bc9fec8d216c95b3d5b75 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 01:02:46 +0800 Subject: [PATCH 0916/2794] match hakihome name with its module --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 57aebaa2f..0ed05f985 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -19,4 +19,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,HakiHome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D From 2c9f38d7d8eebd38138bfc50ed17652da208e51a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 01:54:39 +0800 Subject: [PATCH 0917/2794] cleanup project file strongly recommended to use fpc 3.0.0 up --- mangadownloader/md.lpi | 18 +++++------------- updater/updater.lpi | 9 --------- 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f6e969173..5a4b172fc 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -63,8 +63,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dRELEASEWIN64 --FcUTF8"/> +-dRELEASEWIN64"/> </Other> </CompilerOptions> </Item2> @@ -110,8 +109,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dDEBUGWIN32 --FcUTF8"/> +-dDEBUGWIN32"/> </Other> </CompilerOptions> </Item3> @@ -154,8 +152,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dDEBUGWIN64 --FcUTF8"/> +-dDEBUGWIN64"/> </Other> </CompilerOptions> </Item4> @@ -201,17 +198,13 @@ -dSELFUPDATE -dLOGACTIVE -dDEBUGWIN32 --dDEBUGLEAKS --FcUTF8"/> +-dDEBUGLEAKS"/> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> </Other> </CompilerOptions> </Item5> - <SharedMatrixOptions Count="1"> - <Item1 ID="178609478703" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dEnableUTF8RTL"/> - </SharedMatrixOptions> </BuildModes> <PublishOptions> <Version Value="2"/> @@ -352,8 +345,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dRELEASEWIN32 --FcUTF8"/> +-dRELEASEWIN32"/> </Other> </CompilerOptions> <Debugging> diff --git a/updater/updater.lpi b/updater/updater.lpi index 8f1438e26..7908f1f81 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -57,14 +57,8 @@ </Win32> </Options> </Linking> - <Other> - <CustomOptions Value="-FcUTF8"/> - </Other> </CompilerOptions> </Item2> - <SharedMatrixOptions Count="1"> - <Item1 ID="765037756923" Modes="Win32,Win64" Value="-dEnableUTF8RTL"/> - </SharedMatrixOptions> </BuildModes> <PublishOptions> <Version Value="2"/> @@ -138,9 +132,6 @@ </Win32> </Options> </Linking> - <Other> - <CustomOptions Value="-FcUTF8"/> - </Other> </CompilerOptions> <Debugging> <Exceptions Count="3"> From 879350ac7023ab20dc54fb2ec95a598542d6ddfc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 02:59:43 +0800 Subject: [PATCH 0918/2794] hakihome, fix update list --- baseunits/modules/HakiHome.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/HakiHome.pas b/baseunits/modules/HakiHome.pas index 490eb47da..4d6e4e10a 100644 --- a/baseunits/modules/HakiHome.pas +++ b/baseunits/modules/HakiHome.pas @@ -51,7 +51,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; query:=TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@class="listing"]/tbody/tr/td/a') do begin + for v in query.XPath('//table[@class="listing"]/tbody/tr/td[2]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end; From 15ee9fa22a5db36d09befde70e1eb6c3a31b52a3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 03:00:29 +0800 Subject: [PATCH 0919/2794] hakihome, fix update list --- baseunits/modules/Hakihome.pas | 172 +++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 baseunits/modules/Hakihome.pas diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas new file mode 100644 index 000000000..4d6e4e10a --- /dev/null +++ b/baseunits/modules/Hakihome.pas @@ -0,0 +1,172 @@ +unit Hakihome; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; + +implementation + +const + dirurl='/listmangahentai.html'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=query.XPathString('//*[@class="nav"]/li[last()-1]/a/@href'); + if s<>'' then Page:=StrToIntDef(GetBetween('/pagel/','/',s),1); + finally + query.Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='/pagel/'+IncStr(AURL)+'/'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + for v in query.XPath('//table[@class="listing"]/tbody/tr/td[2]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + query.Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + coverLink:=query.XPathString('//*[@class="noidung"]//img/@src'); + if title=''then title:=query.XPathString('//*[@class="tuade"]'); + artists:=SeparateRight(query.XPathString('//*[@class="art lefts"]'),':'); + genres:=SeparateRight(query.XPathString('//*[@class="category lefts"]'),':'); + AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="tag"]'),':')); + AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="lan rights"]'),':')); + for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + if (chapterName.Count=1) and (title<>'') then + chapterName[0]:=title; + InvertStrings([chapterLinks,chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + Cookies.Values['ReadType']:='2'; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageNumber:=query.XPath('(//*[@id="topn"]/span/select)[last()]/option').Count; + s:=query.XPathString('//*[@id="contentchap"]//script[contains(.,"var jsondata")]'); + if s<>'' then begin + s:=Trim(GetBetween('=',';',s)); + query.ParseHTML(s); + for v in query.XPath('json(*)()') do + PageLinks.Add(v.toString); + end; + finally + query.Free; + end; + end; + end; +end; + +function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + query: TXQueryEngineHTML; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=AppendURLDelim(AURL)+IncStr(DownloadThread.workCounter)+'/'; + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + query:=TXQueryEngineHTML.Create; + try + query.ParseHTML(StreamToString(Document)); + PageLinks[DownloadThread.workCounter]:=query.XPathString('//*[@id="con"]//img/@src'); + finally + query.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='Hakihome'; + RootURL:='http://hakihome.com'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From f48ee446da90d64b3db35d36d45697e6f307fa2d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 14:05:38 +0800 Subject: [PATCH 0920/2794] Bump version 0.9.32.1 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9ef29aa60..0840fe597 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.32.1 (02-02-2016) +[*] Hakihome: rewrite all script +[*] Various changes and bug fixes + 0.9.32.0 (01-02-2016) [*] Updater: various fix [+] Added option to show/hide dialog download manga list from server when local database empty diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5a4b172fc..470377a46 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="32"/> + <BuildNr Value="1"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index e7ac0ba08..91004336f 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.32.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.0/fmd_0.9.32.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.0/fmd_0.9.32.0_Win64.7z +VERSION=0.9.32.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.1/fmd_0.9.32.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.1/fmd_0.9.32.1_Win64.7z From fcab2fd04a10518a7e8fdcc925e83e579a26218e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 23:16:25 +0800 Subject: [PATCH 0921/2794] fix scroll issue on focus changed --- mangadownloader/forms/frmAccountManager.lfm | 1 + mangadownloader/forms/frmAccountManager.pas | 8 ++++++++ mangadownloader/forms/frmMain.lfm | 22 ++++++++++++--------- mangadownloader/forms/frmMain.pas | 8 ++++++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 20e6e3f40..26e319187 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -264,6 +264,7 @@ object AccountManagerForm: TAccountManagerForm OnBeforeCellPaint = vtAccountListBeforeCellPaint OnChange = vtAccountListChange OnChecked = vtAccountListChecked + OnFocusChanged = vtAccountListFocusChanged OnGetText = vtAccountListGetText OnPaintText = vtAccountListPaintText OnInitNode = vtAccountListInitNode diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index bd536a684..9d7313f67 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -34,6 +34,8 @@ TAccountManagerForm = class(TForm) procedure vtAccountListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtAccountListChecked(Sender: TBaseVirtualTree; Node: PVirtualNode ); + procedure vtAccountListFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); procedure vtAccountListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); @@ -440,5 +442,11 @@ procedure TAccountManagerForm.vtAccountListChecked(Sender: TBaseVirtualTree; Account.ValueBool[Node^.Index, 0] := Node^.CheckState = csCheckedNormal; end; +procedure TAccountManagerForm.vtAccountListFocusChanged( + Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); +begin + Sender.ScrollIntoView(Node, False, False); +end; + end. diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index cfdbfa865..6f8abd1c5 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -100,7 +100,6 @@ object MainForm: TMainForm Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] HintMode = hmHintAndDefault Images = IconDL - IncrementalSearch = isVisibleOnly Margin = 2 ParentFont = False ParentShowHint = False @@ -118,6 +117,7 @@ object MainForm: TMainForm OnDragOver = vtDownloadDragOver OnDragDrop = vtDownloadDragDrop OnDrawText = vtDownloadDrawText + OnFocusChanged = vtDownloadFocusChanged OnGetText = vtDownloadGetText OnGetImageIndex = vtDownloadGetImageIndex OnGetHint = vtDownloadGetHint @@ -487,13 +487,12 @@ object MainForm: TMainForm Header.Columns = <> Header.DefaultHeight = 17 Header.MainColumn = -1 - IncrementalSearch = isVisibleOnly Margin = 2 ParentFont = False PopupMenu = pmChapterList TabOrder = 0 TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] @@ -1708,7 +1707,6 @@ object MainForm: TMainForm Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] HintMode = hmHintAndDefault Images = IconList - IncrementalSearch = isVisibleOnly Margin = 0 ParentFont = False ParentShowHint = False @@ -1716,13 +1714,14 @@ object MainForm: TMainForm ShowHint = True TabOrder = 0 TextMargin = 2 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = vtFavoritesBeforeCellPaint OnColumnDblClick = vtFavoritesColumnDblClick OnDragOver = vtFavoritesDragOver OnDragDrop = vtFavoritesDragDrop + OnFocusChanged = vtDownloadFocusChanged OnGetText = vtFavoritesGetText OnGetImageIndex = vtFavoritesGetImageIndex OnGetHint = vtFavoritesGetHint @@ -2789,12 +2788,11 @@ object MainForm: TMainForm Header.Columns = <> Header.DefaultHeight = 17 Header.MainColumn = -1 - IncrementalSearch = isVisibleOnly Margin = 0 ParentFont = False TabOrder = 0 TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] OnChange = vtOptionMangaSiteSelectionChange @@ -3280,14 +3278,13 @@ object MainForm: TMainForm Header.DefaultHeight = 17 Header.MainColumn = -1 HintMode = hmHint - IncrementalSearch = isAll Margin = 0 ParentShowHint = False PopupMenu = pmMangaList ShowHint = True TabOrder = 0 TextMargin = 3 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toDisableAutoscrollOnFocus] + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] OnBeforeCellPaint = vtMangaListBeforeCellPaint @@ -3562,6 +3559,7 @@ object MainForm: TMainForm end object pmDownload: TPopupMenu Images = IconList + OwnerDraw = False OnPopup = pmDownloadPopup left = 616 top = 360 @@ -3881,6 +3879,7 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu + OwnerDraw = False left = 616 top = 392 object miChapterListCheckSelected: TMenuItem @@ -3912,6 +3911,7 @@ object MainForm: TMainForm end object pmFavorites: TPopupMenu Images = IconList + OwnerDraw = False OnPopup = pmFavoritesPopup left = 616 top = 432 @@ -4223,6 +4223,7 @@ object MainForm: TMainForm end object pmMangaList: TPopupMenu Images = IconList + OwnerDraw = False OnPopup = pmMangaListPopup left = 128 top = 272 @@ -4371,6 +4372,7 @@ object MainForm: TMainForm end object pmUpdate: TPopupMenu ParentBidiMode = False + OwnerDraw = False left = 128 top = 144 object mnUpdateList: TMenuItem @@ -5796,6 +5798,7 @@ object MainForm: TMainForm } end object pmEditURL: TPopupMenu + OwnerDraw = False OnPopup = pmEditURLPopup left = 592 top = 136 @@ -5871,6 +5874,7 @@ object MainForm: TMainForm top = 72 end object pmSbMain: TPopupMenu + OwnerDraw = False OnPopup = pmSbMainPopup left = 152 top = 376 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 317f24e9e..9cf3121fc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -478,6 +478,8 @@ TMainForm = class(TForm) procedure vtDownloadDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const CellText: String; const CellRect: TRect; var DefaultDraw: Boolean); + procedure vtDownloadFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); procedure vtDownloadGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); @@ -3628,6 +3630,12 @@ procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; end; end; +procedure TMainForm.vtDownloadFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +begin + Sender.ScrollIntoView(Node, False, False); +end; + // Download table procedure TMainForm.vtDownloadGetHint(Sender: TBaseVirtualTree; From 9170dd9a231c52f3ab130256f67778934f0fd9fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 23:22:49 +0800 Subject: [PATCH 0922/2794] hakihome, append title on every chapter title --- baseunits/modules/Hakihome.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 4d6e4e10a..f54d488ee 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -83,7 +83,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="lan rights"]'),':')); for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + chapterName.Add(Trim(title+' '+v.toString)); end; if (chapterName.Count=1) and (title<>'') then chapterName[0]:=title; From bfaf4b0cb8dd63e83dd095d52a16a7248257821c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 23:22:56 +0800 Subject: [PATCH 0923/2794] rename --- baseunits/modules/HakiHome.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/HakiHome.pas b/baseunits/modules/HakiHome.pas index 4d6e4e10a..f54d488ee 100644 --- a/baseunits/modules/HakiHome.pas +++ b/baseunits/modules/HakiHome.pas @@ -83,7 +83,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="lan rights"]'),':')); for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + chapterName.Add(Trim(title+' '+v.toString)); end; if (chapterName.Count=1) and (title<>'') then chapterName[0]:=title; From d9a4a39d4f96798da9ec89a7392856bec3665093 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 23:25:59 +0800 Subject: [PATCH 0924/2794] rename file --- baseunits/modules/HakiHome.pas | 172 --------------------------------- 1 file changed, 172 deletions(-) delete mode 100644 baseunits/modules/HakiHome.pas diff --git a/baseunits/modules/HakiHome.pas b/baseunits/modules/HakiHome.pas deleted file mode 100644 index f54d488ee..000000000 --- a/baseunits/modules/HakiHome.pas +++ /dev/null @@ -1,172 +0,0 @@ -unit Hakihome; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; - -implementation - -const - dirurl='/listmangahentai.html'; - -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=query.XPathString('//*[@class="nav"]/li[last()-1]/a/@href'); - if s<>'' then Page:=StrToIntDef(GetBetween('/pagel/','/',s),1); - finally - query.Free; - end; - end; -end; - -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; - s: String; -begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='/pagel/'+IncStr(AURL)+'/'; - if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@class="listing"]/tbody/tr/td[2]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - query.Free; - end; - end; -end; - -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//*[@class="noidung"]//img/@src'); - if title=''then title:=query.XPathString('//*[@class="tuade"]'); - artists:=SeparateRight(query.XPathString('//*[@class="art lefts"]'),':'); - genres:=SeparateRight(query.XPathString('//*[@class="category lefts"]'),':'); - AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="tag"]'),':')); - AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="lan rights"]'),':')); - for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(Trim(title+' '+v.toString)); - end; - if (chapterName.Count=1) and (title<>'') then - chapterName[0]:=title; - InvertStrings([chapterLinks,chapterName]); - finally - query.Free; - end; - end; - end; -end; - -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - s: String; - v: IXQValue; -begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin - PageLinks.Clear; - PageContainerLinks.Clear; - PageNumber := 0; - Cookies.Values['ReadType']:='2'; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('(//*[@id="topn"]/span/select)[last()]/option').Count; - s:=query.XPathString('//*[@id="contentchap"]//script[contains(.,"var jsondata")]'); - if s<>'' then begin - s:=Trim(GetBetween('=',';',s)); - query.ParseHTML(s); - for v in query.XPath('json(*)()') do - PageLinks.Add(v.toString); - end; - finally - query.Free; - end; - end; - end; -end; - -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - s: String; -begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=AppendURLDelim(AURL)+IncStr(DownloadThread.workCounter)+'/'; - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter]:=query.XPathString('//*[@id="con"]//img/@src'); - finally - query.Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website:='Hakihome'; - RootURL:='http://hakihome.com'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. From ed312ab17978fd17575142d04c17dee39981a5b1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Feb 2016 23:51:21 +0800 Subject: [PATCH 0925/2794] ehentai, fix get sub page count fix #179 --- baseunits/modules/EHentai.pas | 52 +++++++++++++---------------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 3cc5a2e75..841cd1c73 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -215,11 +215,14 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; var query: TXQueryEngineHTML; rurl: String; + getOK: Boolean; + i, p: Integer; procedure GetImageLink; var x: IXQValue; begin + query.ParseHTML(DownloadThread.FHTTP.Document); with DownloadThread.manager.container do begin for x in query.XPath('//div[@id="gdt"]//a/@href') do PageContainerLinks.Add(x.toString); @@ -228,37 +231,6 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; - procedure ScanParse; - var - getOK: Boolean; - i, p: Integer; - v: IXQValue; - begin - getOK := True; - //check content warning - if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then - begin - getOK := GETWithLogin(DownloadThread.FHTTP, rurl + '?nw=session', Module.Website); - if getOK then - query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); - end; - if getOK then - begin - GetImageLink; - //get page count - p:=0; - v:=query.XPath('//table[@class="ptt"]//td'); - if v.Count>2 then p:=StrToIntDef(v.get(v.Count-2).toString,0); - if p > 0 then - for i := 1 to p do - if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then - begin - query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); - GetImageLink; - end; - end; - end; - begin Result := False; if DownloadThread = nil then Exit; @@ -272,8 +244,22 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; Result := True; query := TXQueryEngineHTML.Create; try - query.ParseHTML(StreamToString(Document)); - ScanParse; + getOK := True; + //check content warning + if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then + getOK := GETWithLogin(DownloadThread.FHTTP, rurl + '?nw=session', Module.Website); + if getOK then begin + GetImageLink; + //get page count + p:=0; + p:=StrToIntDef(query.XPathString('//table[@class="ptt"]//td[last()-1]'),0); + if p>1 then begin + Dec(p); + for i:=1 to p do + if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then + GetImageLink; + end; + end; finally query.Free; end; From da0a47611077d2ec92c360fa3566205806c4065c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 3 Feb 2016 00:07:30 +0800 Subject: [PATCH 0926/2794] frmmain, fix auto scroll on vtdownload --- mangadownloader/forms/frmMain.pas | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9cf3121fc..40c36e50e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3500,22 +3500,19 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); cNode:=vtDownload.GetFirst; while cNode^.Index<nIndex do cNode:=vtDownload.GetNext(cNode); - vtDownload.FocusedNode:=cNode; if Mode in [dmBelow,dmNowhere] then - fNode:=cNode; + vtDownload.FocusedNode:=cNode; + for i:=0 to ConTemp.Count-1 do begin vtDownload.Selected[cNode]:=True; if i<ConTemp.Count-1 then cNode:=vtDownload.GetPrevious(cNode); end; - if Mode=dmAbove then - fNode:=cNode; - fRect:=vtDownload.GetDisplayRect(fNode,0,False); - if (fRect.Top-vtDownload.Header.Height<0) or (fRect.Bottom>vtDownload.ClientHeight) then - vtDownload.ScrollIntoView(fNode,False,False); + if Mode=dmAbove then + vtDownload.FocusedNode:=cNode; finally DLManager.CS_DownloadManager_Task.Release; end; From f4edfc443e9bf9cb39121cdb76a54b895b417073 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 3 Feb 2016 00:11:57 +0800 Subject: [PATCH 0927/2794] Bump version 0.9.32.2 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0840fe597..e4fff1774 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.32.2 (03-02-2016) +[*] E-Hentai/ExHentai: fix incorrect page number +[*] Various changes and bug fixes + 0.9.32.1 (02-02-2016) [*] Hakihome: rewrite all script [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 470377a46..5d0d48df8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="32"/> - <BuildNr Value="1"/> + <BuildNr Value="2"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 91004336f..d9e152715 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.32.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.1/fmd_0.9.32.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.1/fmd_0.9.32.1_Win64.7z +VERSION=0.9.32.2 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.2/fmd_0.9.32.2.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.2/fmd_0.9.32.2_Win64.7z From d9482ca41856c73f923fb15cb240d192ad259ce7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Feb 2016 23:45:29 +0800 Subject: [PATCH 0928/2794] dbdataprocess, change link data type to text fix #181 --- baseunits/DBDataProcess.pas | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 8282760da..4cc9019b7 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -119,7 +119,7 @@ TDBDataProcess = class(TObject) DBTempFieldWebsiteIndex = Length(DBDataProcessParams); DBDataProccesCreateParam = '('#13#10 + '"title" TEXT,'#13#10 + - '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + + '"link" TEXT NOT NULL PRIMARY KEY,'#13#10 + '"authors" TEXT,'#13#10 + '"artists" TEXT,'#13#10 + '"genres" TEXT,'#13#10 + @@ -317,15 +317,9 @@ procedure TDBDataProcess.CreateTable; procedure TDBDataProcess.ConvertNewTable; begin - //'"title" TEXT,'#13#10 + - // '"link" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + - // '"authors" TEXT,'#13#10 + - // '"artists" TEXT,'#13#10 + - // '"genres" TEXT,'#13#10 + - // '"status" TEXT,'#13#10 + - // '"summary" TEXT,'#13#10 + if FQuery.Active = False then Exit; if (FieldTypeNames[FQuery.FieldByName('title').DataType] <> Fieldtypenames[ftMemo]) or + (FieldTypeNames[FQuery.FieldByName('link').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[FQuery.FieldByName('authors').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[FQuery.FieldByName('artists').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[FQuery.FieldByName('genres').DataType] <> Fieldtypenames[ftMemo]) or From a25232f39980901c5a538790cf408a572360f07e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Feb 2016 23:47:01 +0800 Subject: [PATCH 0929/2794] dbdataprocess, vacuum database after convert data type --- baseunits/DBDataProcess.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 4cc9019b7..6bae19595 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -335,6 +335,7 @@ procedure TDBDataProcess.ConvertNewTable; ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+FTableName)+' RENAME TO '+QuotedStrd(FTableName)); end; FTrans.Commit; + VacuumTable; FQuery.Open; except FTrans.Rollback; From fa927cd036fc9990c443d34b9517b41bb74f7714 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Feb 2016 23:48:31 +0800 Subject: [PATCH 0930/2794] dbdataprocess, remove locatebylink, only available with varchar --- baseunits/DBDataProcess.pas | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 6bae19595..94ee22f48 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -74,7 +74,6 @@ TDBDataProcess = class(TObject) const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; - function LocateByLink(ALink: String): Boolean; function WebsiteLoaded(const AWebsite: String): Boolean; function LinkExist(ALink: String): Boolean; @@ -1058,18 +1057,6 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList end; end; -function TDBDataProcess.LocateByLink(ALink: String): Boolean; -begin - Result := False; - if (FQuery.Active) and (FRecordCount > 0) and (ALink <> '') then - try - Result := FQuery.Locate('link', ALink, [loCaseInsensitive]); - except - on E: Exception do - WriteLog_E('TDBDataProcess.LocateByLink.Error!', E, Self); - end; -end; - procedure TDBDataProcess.CreateDatabase(AWebsite: String); var filepath: String; From 379d195fb9e14a73795016d37491d53181eca294 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Feb 2016 09:41:14 +0800 Subject: [PATCH 0931/2794] downloadsmanager, put all updates in critical section #182 --- baseunits/uDownloadsManager.pas | 59 +++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c712dc2d5..543bf00f7 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -110,7 +110,7 @@ TTaskThread = class(TFMDThread) TTaskContainer = class private FReadCount: Integer; - CS_FReadCount: TCriticalSection; + CS_FContainer: TCriticalSection; FWebsite: String; procedure SetWebsite(AValue: String); public @@ -136,9 +136,11 @@ TTaskContainer = class FailedChapterLinks, PageContainerLinks, PageLinks: TStringList; - procedure IncReadCount(const ACount: Integer); constructor Create; destructor Destroy; override; + procedure IncReadCount(const ACount: Integer); + procedure Lock; inline; + procedure Unlock; inline; property Website: String read FWebsite write SetWebsite; end; @@ -333,9 +335,14 @@ procedure TDownloadThread.Execute; if not Terminated and Reslt then begin - manager.container.DownCounter := InterLockedIncrement(manager.container.DownCounter); - manager.container.DownloadInfo.Progress := - Format('%d/%d', [manager.container.DownCounter, manager.container.PageNumber]); + manager.container.Lock; + try + manager.container.DownCounter := InterLockedIncrement(manager.container.DownCounter); + manager.container.DownloadInfo.Progress := + Format('%d/%d', [manager.container.DownCounter, manager.container.PageNumber]); + finally + manager.container.Unlock; + end; end; except on E: Exception do @@ -1544,21 +1551,11 @@ procedure TTaskContainer.SetWebsite(AValue: String); ModuleId := Modules.LocateModule(AValue); end; -procedure TTaskContainer.IncReadCount(const ACount: Integer); -begin - CS_FReadCount.Acquire; - try - Inc(FReadCount, ACount); - finally - CS_FReadCount.Release; - end; -end; - constructor TTaskContainer.Create; begin inherited Create; ThreadState := False; - CS_FReadCount := TCriticalSection.Create; + CS_FContainer := TCriticalSection.Create; ChapterLinks := TStringList.Create; ChapterName := TStringList.Create; FailedChapterName := TStringList.Create; @@ -1579,10 +1576,30 @@ destructor TTaskContainer.Destroy; ChapterLinks.Free; FailedChapterName.Free; FailedChapterLinks.Free; - CS_FReadCount.Free; + CS_FContainer.Free; inherited Destroy; end; +procedure TTaskContainer.IncReadCount(const ACount: Integer); +begin + Lock; + try + Inc(FReadCount, ACount); + finally + Unlock; + end; +end; + +procedure TTaskContainer.Lock; +begin + CS_FContainer.Acquire; +end; + +procedure TTaskContainer.Unlock; +begin + CS_FContainer.Release; +end; + { TDownloadManager } function TDownloadManager.GetItems(Index: Integer): TTaskContainer; @@ -1610,7 +1627,7 @@ function TDownloadManager.GetTransferRate: Integer; with TTaskContainer(Containers[i]) do if ThreadState then begin - CS_FReadCount.Acquire; + Lock; try if Status = STATUS_COMPRESS then DownloadInfo.TransferRate := '' @@ -1621,7 +1638,7 @@ function TDownloadManager.GetTransferRate: Integer; end; FReadCount := 0; finally - CS_FReadCount.Release; + Unlock; end; end; Result := FTotalReadCount; @@ -1834,12 +1851,12 @@ procedure TDownloadManager.ClearTransferRate; for i := 0 to Containers.Count - 1 do with TTaskContainer(Containers[i]) do begin - CS_FReadCount.Acquire; + Lock; try FReadCount := 0; DownloadInfo.TransferRate := ''; finally - CS_FReadCount.Release; + Unlock; end; end; finally From 8661f564511067503353e6fb0543c7890bfe7df8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Feb 2016 10:29:51 +0800 Subject: [PATCH 0932/2794] Bump version 0.9.32.3 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index e4fff1774..ada9fcdea 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,9 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.32.3 (05-02-2016) +[*] Various changes and bug fixes + 0.9.32.2 (03-02-2016) [*] E-Hentai/ExHentai: fix incorrect page number [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5d0d48df8..57652c356 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="32"/> - <BuildNr Value="2"/> + <BuildNr Value="3"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index d9e152715..07949e978 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.32.2 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.2/fmd_0.9.32.2.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.2/fmd_0.9.32.2_Win64.7z +VERSION=0.9.32.3 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.3/fmd_0.9.32.3.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.3/fmd_0.9.32.3_Win64.7z From 6efda8a8140db9dd59f8c6853609486d3e659a9a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 6 Feb 2016 18:15:19 +0800 Subject: [PATCH 0933/2794] removed mangacap, website offline close #183 --- baseunits/modules/WPManga.pas | 1 - config/mangalist.ini | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index a023e0340..81e36f646 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -288,7 +288,6 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaCap', 'http://www.mangacap.com'); AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com'); AddWebsiteModule('Authrone', 'http://www.authrone.com'); AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index 0ed05f985..c83ec9c7b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=http://sourceforge.net/projects/newfmd/files/data/<website>.7z/dow [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaCap,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From cbba4622cf6ce84d8d2846f0aadee112920f680c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 02:22:58 +0800 Subject: [PATCH 0934/2794] ehentai, added option to download original image, and various changes on misc options --- baseunits/modules/EHentai.pas | 86 +++++++++--------- baseunits/modules/MangaFox.pas | 2 +- baseunits/uBaseUnit.pas | 5 +- mangadownloader/forms/frmMain.lfm | 118 +++++++++++++++++-------- mangadownloader/forms/frmMain.pas | 46 +++++----- mangadownloader/languages/fmd.en.po | 53 ++++++----- mangadownloader/languages/fmd.id_ID.po | 52 +++++++---- mangadownloader/languages/fmd.po | 52 +++++++---- 8 files changed, 250 insertions(+), 164 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 841cd1c73..db58f0f9d 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -15,6 +15,7 @@ implementation const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; exhentaiurllogin = 'https://forums.e-hentai.org/index.php?act=Login&CODE=01'; + accname='ExHentai'; var onlogin: Boolean = False; @@ -23,53 +24,51 @@ implementation function ExHentaiLogin(var AHTTP: THTTPSendThread): Boolean; var s: String; -const - acc = 'ExHentai'; begin Result := False; if AHTTP = nil then Exit; - if Account.Enabled[acc] = False then Exit; - if Account.Username[acc] = '' then Exit; + if Account.Enabled[accname] = False then Exit; if TryEnterCriticalsection(locklogin) > 0 then with AHTTP do begin onlogin := True; - Account.Status[acc] := asChecking; + Account.Status[accname] := asChecking; Reset; Cookies.Clear; s := 'returntype=8&CookieDate=1&b=d&bt=pone'+ - '&UserName=' + EncodeURLElement(Account.Username[acc]) + - '&PassWord=' + EncodeURLElement(Account.Password[acc]) + + '&UserName=' + EncodeURLElement(Account.Username[accname]) + + '&PassWord=' + EncodeURLElement(Account.Password[accname]) + '&ipb_login_submit=Login%21'; if POST(exhentaiurllogin, s) then begin if ResultCode = 200 then begin Result := Cookies.Values['ipb_pass_hash'] <> ''; if Result then begin - Account.Cookies[acc] := GetCookies; - Account.Status[acc] := asValid; + Account.Cookies[accname] := GetCookies; + Account.Status[accname] := asValid; end - else Account.Status[acc] := asInvalid; + else Account.Status[accname] := asInvalid; Account.Save; end; end; onlogin := False; - if Account.Status[acc] = asChecking then - Account.Status[acc] := asUnknown; + if Account.Status[accname] = asChecking then + Account.Status[accname] := asUnknown; LeaveCriticalsection(locklogin); end else begin while onlogin do Sleep(1000); - if Result then AHTTP.Cookies.Text := Account.Cookies[acc]; + if Result then AHTTP.Cookies.Text := Account.Cookies[accname]; end; end; function GETWithLogin(var AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; begin Result := False; - if AWebsite = 'ExHentai' then begin + //if AWebsite = accname then begin + if Account.Enabled[accname] then begin AHTTP.FollowRedirection := False; - AHTTP.Cookies.Text := Account.Cookies[AWebsite]; + AHTTP.Cookies.Text := Account.Cookies[accname]; Result := AHTTP.GET(AURL); if Result and (AHTTP.ResultCode > 300) then begin Result := ExHentaiLogin(AHTTP); @@ -287,7 +286,10 @@ function DownloadImage(var DownloadThread: TDownloadThread; while (not Result) and (not DownloadThread.IsTerminated) do begin source.LoadFromStream(DownloadThread.FHTTP.Document); query.ParseHTML(source.Text); - iurl := query.XPathString('//*[@id="img"]/@src'); + if OptionEHentaiDownloadOriginalImage and (Account.Status[accname]=asValid) then + iurl:=query.XPathString('//a/@href[contains(.,"/fullimg.php")]') + else + iurl := query.XPathString('//*[@id="img"]/@src'); if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then @@ -349,38 +351,30 @@ function DownloadImage(var DownloadThread: TDownloadThread; end; procedure RegisterModule; -begin - with AddModule do + + function AddWebsiteModule(AWebsite,ARootURL:String):TModuleContainer; begin - Website := 'E-Hentai'; - RootURL := 'http://g.e-hentai.org'; - MaxTaskLimit := 1; - MaxConnectionLimit := 4; - SortedList := True; - InformationAvailable := True; - DynamicPageLink := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnDownloadImage := @DownloadImage; + Result:=AddModule; + with Result do begin + Website:=AWebsite; + RootURL:=ARootURL; + MaxTaskLimit := 1; + MaxConnectionLimit:=4; + SortedList:=True; + DynamicPageLink:=True; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnDownloadImage:=@DownloadImage; + end; end; - with AddModule do - begin - Website := 'ExHentai'; - RootURL := 'http://exhentai.org'; - MaxTaskLimit := 1; - MaxConnectionLimit := 4; - SortedList := True; - InformationAvailable := True; - DynamicPageLink := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnDownloadImage := @DownloadImage; - AccountSupport := True; - OnLogin := @ExHentaiLogin; + +begin + AddWebsiteModule('E-Hentai','http://g.e-hentai.org'); + with AddWebsiteModule('ExHentai','http://exhentai.org') do begin + AccountSupport:=True; + OnLogin:=@ExHentaiLogin; end; end; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index b6a5c57ae..ad17e126c 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -299,7 +299,7 @@ function AfterImageSaved(const AFilename: String; Module: TModuleContainer): Boo begin Result := True; if OptionMangaFoxRemoveWatermark then - Result := mangafoxwatermarkremover.RemoveWatermark(AFilename, OptionMangaFoxRemoveWatermarkSaveAsPNG); + Result := mangafoxwatermarkremover.RemoveWatermark(AFilename, OptionMangaFoxSaveAsPNG); end; procedure RegisterModule; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 076ae8fb4..17370999e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -621,8 +621,9 @@ interface OptionBatotoShowScanGroup: Boolean = True; OptionBatotoShowAllLang: Boolean = True; OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; - OptionMangaFoxRemoveWatermark: Boolean = False; - OptionMangaFoxRemoveWatermarkSaveAsPNG: Boolean = False; + OptionMangaFoxRemoveWatermark: Boolean = True; + OptionMangaFoxSaveAsPNG: Boolean = False; + OptionEHentaiDownloadOriginalImage: Boolean=False; OptionHTTPUseGzip: Boolean = True; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 6f8abd1c5..d9e83cb47 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2920,54 +2920,105 @@ object MainForm: TMainForm end object tsMisc: TTabSheet Caption = 'Misc' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.VerticalSpacing = 6 ClientHeight = 416 ClientWidth = 579 - object gbMisc: TGroupBox - Left = 12 - Height = 390 - Top = 12 - Width = 556 - Anchors = [akTop, akLeft, akRight, akBottom] - ClientHeight = 370 - ClientWidth = 552 + object gbBatoto: TGroupBox + Left = 6 + Height = 70 + Top = 6 + Width = 567 + Align = alTop + AutoSize = True + Caption = 'Batoto' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 50 + ClientWidth = 563 TabOrder = 0 - object cbOptionBatotoShowAllLang: TCheckBox - Left = 16 + object cbBatotoShowAllLang: TCheckBox + Left = 6 Height = 19 - Top = 40 - Width = 167 - Caption = '[Batoto] Show All Language' + Top = 6 + Width = 144 + Caption = 'Show all language' ParentFont = False TabOrder = 1 end - object cbOptionBatotoShowScanGroup: TCheckBox - Left = 16 + object cbBatotoShowScanGroup: TCheckBox + Left = 6 Height = 19 - Top = 16 - Width = 190 - Caption = '[Batoto] Show scan group name' + Top = 25 + Width = 144 + Caption = 'Show scan group name' ParentFont = False TabOrder = 0 end - object cbOptionMangaFoxRemoveWatermark: TCheckBox - Left = 16 + end + object gbMangafox: TGroupBox + Left = 6 + Height = 70 + Top = 82 + Width = 567 + Align = alTop + AutoSize = True + Caption = 'Mangafox' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 50 + ClientWidth = 563 + TabOrder = 1 + object cbMangaFoxRemoveWatermark: TCheckBox + Left = 6 Height = 19 - Top = 88 - Width = 186 - Caption = '[Mangafox] Remove watermark' - OnChange = cbOptionMangaFoxRemoveWatermarkChange + Top = 6 + Width = 122 + Caption = 'Remove watermark' + OnChange = cbMangaFoxRemoveWatermarkChange ParentFont = False - TabOrder = 2 + TabOrder = 0 end - object cbOptionMangaFoxRemoveWatermarkSaveAsPNG: TCheckBox - Left = 34 + object cbMangaFoxSaveAsPNG: TCheckBox + Left = 6 Height = 19 - Top = 112 - Width = 85 + Top = 25 + Width = 122 Caption = 'Save as PNG' Enabled = False ParentFont = False - TabOrder = 3 + TabOrder = 1 + end + end + object gbEHentai: TGroupBox + Left = 6 + Height = 51 + Top = 158 + Width = 567 + Align = alTop + AutoSize = True + Caption = 'E-Hentai/ExHentai' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 31 + ClientWidth = 563 + TabOrder = 2 + object cbEHentaiDownloadOriginalImage: TCheckBox + Left = 6 + Height = 19 + Top = 6 + Width = 153 + Caption = 'Download original image (require ExHentai account)' + OnChange = cbMangaFoxRemoveWatermarkChange + ParentFont = False + TabOrder = 0 end end end @@ -3559,7 +3610,6 @@ object MainForm: TMainForm end object pmDownload: TPopupMenu Images = IconList - OwnerDraw = False OnPopup = pmDownloadPopup left = 616 top = 360 @@ -3879,7 +3929,6 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - OwnerDraw = False left = 616 top = 392 object miChapterListCheckSelected: TMenuItem @@ -3911,7 +3960,6 @@ object MainForm: TMainForm end object pmFavorites: TPopupMenu Images = IconList - OwnerDraw = False OnPopup = pmFavoritesPopup left = 616 top = 432 @@ -4223,7 +4271,6 @@ object MainForm: TMainForm end object pmMangaList: TPopupMenu Images = IconList - OwnerDraw = False OnPopup = pmMangaListPopup left = 128 top = 272 @@ -4372,7 +4419,6 @@ object MainForm: TMainForm end object pmUpdate: TPopupMenu ParentBidiMode = False - OwnerDraw = False left = 128 top = 144 object mnUpdateList: TMenuItem @@ -5798,7 +5844,6 @@ object MainForm: TMainForm } end object pmEditURL: TPopupMenu - OwnerDraw = False OnPopup = pmEditURLPopup left = 592 top = 136 @@ -5874,7 +5919,6 @@ object MainForm: TMainForm top = 72 end object pmSbMain: TPopupMenu - OwnerDraw = False OnPopup = pmSbMainPopup left = 152 top = 376 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 40c36e50e..41836cf2c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -49,13 +49,14 @@ TMainForm = class(TForm) btWebsitesSearchClear: TSpeedButton; btUpdateList: TSpeedButton; btURL: TSpeedButton; + cbEHentaiDownloadOriginalImage: TCheckBox; cbOptionAutoCheckFavStartup: TCheckBox; cbOptionAutoCheckFavInterval: TCheckBox; cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; - cbOptionMangaFoxRemoveWatermark: TCheckBox; - cbOptionMangaFoxRemoveWatermarkSaveAsPNG: TCheckBox; + cbMangaFoxRemoveWatermark: TCheckBox; + cbMangaFoxSaveAsPNG: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadMangalistDialog: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; @@ -68,6 +69,8 @@ TMainForm = class(TForm) cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; edOptionMangaCustomRename: TEdit; + gbMangafox: TGroupBox; + gbEHentai: TGroupBox; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; miAbortSilentThread: TMenuItem; @@ -140,8 +143,8 @@ TMainForm = class(TForm) btRemoveFilterLarge: TBitBtn; cbOptionAutoCheckLatestVersion: TCheckBox; cbOptionShowDeleteTaskDialog: TCheckBox; - cbOptionBatotoShowScanGroup: TCheckBox; - cbOptionBatotoShowAllLang: TCheckBox; + cbBatotoShowScanGroup: TCheckBox; + cbBatotoShowAllLang: TCheckBox; cbOptionUseProxy: TCheckBox; cbSelectManga: TComboBox; ckFilterAction: TCheckBox; @@ -207,7 +210,7 @@ TMainForm = class(TForm) gbOptionProxy: TGroupBox; gbOptionRenaming: TGroupBox; gbOptionFavorites: TGroupBox; - gbMisc: TGroupBox; + gbBatoto: TGroupBox; IconList: TImageList; itSaveDownloadedList: TIdleTimer; itRefreshDLInfo: TIdleTimer; @@ -359,7 +362,7 @@ TMainForm = class(TForm) procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderNameChange(Sender: TObject); - procedure cbOptionMangaFoxRemoveWatermarkChange(Sender: TObject); + procedure cbMangaFoxRemoveWatermarkChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; @@ -2203,9 +2206,9 @@ procedure TMainForm.cbOptionGenerateMangaFolderNameChange(Sender: TObject); lbOptionMangaCustomRenameHint.Enabled := cbOptionGenerateMangaFolderName.Checked; end; -procedure TMainForm.cbOptionMangaFoxRemoveWatermarkChange(Sender: TObject); +procedure TMainForm.cbMangaFoxRemoveWatermarkChange(Sender: TObject); begin - cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Enabled:=cbOptionMangaFoxRemoveWatermark.Checked; + cbMangaFoxSaveAsPNG.Enabled:=cbMangaFoxRemoveWatermark.Checked; end; procedure TMainForm.btReadOnlineClick(Sender: TObject); @@ -4343,10 +4346,11 @@ procedure TMainForm.LoadOptions; cbOptionShowDownloadMangalistDialog.Checked := ReadBool('dialogs', 'ShowDownloadMangalistDialog', True); // misc - cbOptionBatotoShowScanGroup.Checked := ReadBool('misc', 'BatotoShowScanGroup', True); - cbOptionBatotoShowAllLang.Checked := ReadBool('misc', 'BatotoShowAllLang', False); - cbOptionMangaFoxRemoveWatermark.Checked := ReadBool('misc', 'MangafoxRemoveWatermark', False); - cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Checked := ReadBool('misc', 'MangafoxRemoveWatermarkSaveAsPNG', False); + cbBatotoShowScanGroup.Checked := ReadBool('Batoto', 'ShowScanGroup', True); + cbBatotoShowAllLang.Checked := ReadBool('Batoto', 'ShowAllLang', True); + cbMangaFoxRemoveWatermark.Checked := ReadBool('MangaFox', 'RemoveWatermark', True); + cbMangaFoxSaveAsPNG.Checked := ReadBool('MangaFox', 'SaveAsPNG', False); + cbEHentaiDownloadOriginalImage.Checked:=ReadBool('EHentai','DownloadOriginalImage',False); // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4464,10 +4468,11 @@ procedure TMainForm.SaveOptions; WriteBool('dialogs', 'ShowDownloadMangalistDialog', cbOptionShowDownloadMangalistDialog.Checked); // misc - WriteBool('misc', 'BatotoShowScanGroup', cbOptionBatotoShowScanGroup.Checked); - WriteBool('misc', 'BatotoShowAllLang', cbOptionBatotoShowAllLang.Checked); - WriteBool('misc', 'MangafoxRemoveWatermark', cbOptionMangaFoxRemoveWatermark.Checked); - WriteBool('misc', 'MangafoxRemoveWatermarkSaveAsPNG', cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Checked); + WriteBool('Batoto', 'ShowScanGroup', cbBatotoShowScanGroup.Checked); + WriteBool('Batoto', 'ShowAllLang', cbBatotoShowAllLang.Checked); + WriteBool('MangaFox', 'RemoveWatermark', cbMangaFoxRemoveWatermark.Checked); + WriteBool('MangaFox', 'SaveAsPNG', cbMangaFoxSaveAsPNG.Checked); + WriteBool('EHentai','DownloadOriginalImage',cbEHentaiDownloadOriginalImage.Checked); finally UpdateFile; end; @@ -4600,14 +4605,15 @@ procedure TMainForm.ApplyOptions; itCheckFav.Enabled := OptionAutoCheckFavInterval; //misc - OptionBatotoShowScanGroup := cbOptionBatotoShowScanGroup.Checked; - OptionBatotoShowAllLang := cbOptionBatotoShowAllLang.Checked; - OptionMangaFoxRemoveWatermark := cbOptionMangaFoxRemoveWatermark.Checked; - OptionMangaFoxRemoveWatermarkSaveAsPNG := cbOptionMangaFoxRemoveWatermarkSaveAsPNG.Checked; + OptionBatotoShowScanGroup := cbBatotoShowScanGroup.Checked; + OptionBatotoShowAllLang := cbBatotoShowAllLang.Checked; + OptionMangaFoxRemoveWatermark := cbMangaFoxRemoveWatermark.Checked; + OptionMangaFoxSaveAsPNG := cbMangaFoxSaveAsPNG.Checked; if OptionMangaFoxRemoveWatermark then mangafoxwatermarkremover.LoadTemplate(CleanAndExpandDirectory(GetCurrentDirUTF8) + OptionMangaFoxTemplateFolder) else mangafoxwatermarkremover.ClearTemplate; + OptionEHentaiDownloadOriginalImage:=cbEHentaiDownloadOriginalImage.Checked; //languages ApplyLanguage; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index b8110640e..a2573247c 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -467,10 +467,31 @@ msgstr "Free Manga Downloader" msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" +#: tmainform.cbbatotoshowalllang.caption +msgid "Show all language" +msgstr "Show all language" + +#: tmainform.cbbatotoshowscangroup.caption +msgid "Show scan group name" +msgstr "Show scan group name" + +#: tmainform.cbehentaidownloadoriginalimage.caption +msgid "Download original image (require ExHentai account)" +msgstr "Download original image (require ExHentai account)" + #: tmainform.cbfilterstatus.text msgid "<none>" msgstr "<none>" +#: tmainform.cbmangafoxremovewatermark.caption +msgid "Remove watermark" +msgstr "Remove watermark" + +#: tmainform.cbmangafoxsaveaspng.caption +msgctxt "tmainform.cbmangafoxsaveaspng.caption" +msgid "Save as PNG" +msgstr "Save as PNG" + #: tmainform.cbonlynew.caption msgid "Search only new manga" msgstr "Search only new manga" @@ -500,16 +521,6 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Auto check for latest version " -#: tmainform.cboptionbatotoshowalllang.caption -msgctxt "tmainform.cboptionbatotoshowalllang.caption" -msgid "[Batoto] Show All Language" -msgstr "[Batoto] Show All Language" - -#: tmainform.cboptionbatotoshowscangroup.caption -msgctxt "tmainform.cboptionbatotoshowscangroup.caption" -msgid "[Batoto] Show scan group name" -msgstr "[Batoto] Show scan group name" - #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "tmainform.cboptionchangeunicodecharacter.caption" msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" @@ -535,16 +546,6 @@ msgstr "Auto generate folder based on manga's name" msgid "Enable live search (slow on long list)" msgstr "Enable live search (slow on long list)" -#: tmainform.cboptionmangafoxremovewatermark.caption -#| msgid "[Mangafox] Remove watermark (Beware! Experimental!)" -msgctxt "tmainform.cboptionmangafoxremovewatermark.caption" -msgid "[Mangafox] Remove watermark" -msgstr "[Mangafox] Remove watermark" - -#: tmainform.cboptionmangafoxremovewatermarksaveaspng.caption -msgid "Save as PNG" -msgstr "Save as PNG" - #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Minimize to tray" @@ -1007,6 +1008,10 @@ msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." msgstr "Search website..." +#: tmainform.gbbatoto.caption +msgid "Batoto" +msgstr "Batoto" + #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" msgstr "Show dialog confirmation for" @@ -1015,6 +1020,14 @@ msgstr "Show dialog confirmation for" msgid "Drop Box" msgstr "Drop Box" +#: tmainform.gbehentai.caption +msgid "E-Hentai/ExHentai" +msgstr "E-Hentai/ExHentai" + +#: tmainform.gbmangafox.caption +msgid "Mangafox" +msgstr "Mangafox" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "External program" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 19cbe1209..205589dee 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -459,10 +459,31 @@ msgstr "Free Manga Downloader" msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" +#: tmainform.cbbatotoshowalllang.caption +msgid "Show all language" +msgstr "Tampilkan semua bahasa" + +#: tmainform.cbbatotoshowscangroup.caption +msgid "Show scan group name" +msgstr "Tampilkan nama grup scan" + +#: tmainform.cbehentaidownloadoriginalimage.caption +msgid "Download original image (require ExHentai account)" +msgstr "Unduh gambar asli (membutuhkan akun ExHentai)" + #: tmainform.cbfilterstatus.text msgid "<none>" msgstr "<none>" +#: tmainform.cbmangafoxremovewatermark.caption +msgid "Remove watermark" +msgstr "Hapus watermark" + +#: tmainform.cbmangafoxsaveaspng.caption +msgctxt "tmainform.cbmangafoxsaveaspng.caption" +msgid "Save as PNG" +msgstr "Simpan sebagai PNG" + #: tmainform.cbonlynew.caption msgid "Search only new manga" msgstr "Cari hanya komik baru" @@ -490,16 +511,6 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Otomatis periksa versi terbaru" -#: tmainform.cboptionbatotoshowalllang.caption -msgctxt "tmainform.cboptionbatotoshowalllang.caption" -msgid "[Batoto] Show All Language" -msgstr "[Batoto] Tampilkan semua bahasa" - -#: tmainform.cboptionbatotoshowscangroup.caption -msgctxt "tmainform.cboptionbatotoshowscangroup.caption" -msgid "[Batoto] Show scan group name" -msgstr "[Batoto] Tampilkan nama grup scan" - #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "tmainform.cboptionchangeunicodecharacter.caption" msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" @@ -525,15 +536,6 @@ msgstr "Buat otomatis folder berdasarkan nama komik" msgid "Enable live search (slow on long list)" msgstr "Aktifkan pencarian langsung (lambat dengan daftar yang panjang)" -#: tmainform.cboptionmangafoxremovewatermark.caption -msgctxt "tmainform.cboptionmangafoxremovewatermark.caption" -msgid "[Mangafox] Remove watermark" -msgstr "[Mangafox] Hapus watermark" - -#: tmainform.cboptionmangafoxremovewatermarksaveaspng.caption -msgid "Save as PNG" -msgstr "Simpan sebagai PNG" - #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Perkecil ke penampan" @@ -992,6 +994,10 @@ msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." msgstr "Cari situs web..." +#: tmainform.gbbatoto.caption +msgid "Batoto" +msgstr "Batoto" + #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" msgstr "Tampilkan dialog konfirmasi untuk" @@ -1000,6 +1006,14 @@ msgstr "Tampilkan dialog konfirmasi untuk" msgid "Drop Box" msgstr "Kotak unduh" +#: tmainform.gbehentai.caption +msgid "E-Hentai/ExHentai" +msgstr "E-Hentai/ExHentai" + +#: tmainform.gbmangafox.caption +msgid "Mangafox" +msgstr "Mangafox" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Program eksternal" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 524089e29..349652e30 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -431,10 +431,31 @@ msgstr "" msgid "Add to download list as stopped task" msgstr "" +#: tmainform.cbbatotoshowalllang.caption +msgid "Show all language" +msgstr "" + +#: tmainform.cbbatotoshowscangroup.caption +msgid "Show scan group name" +msgstr "" + +#: tmainform.cbehentaidownloadoriginalimage.caption +msgid "Download original image (require ExHentai account)" +msgstr "" + #: tmainform.cbfilterstatus.text msgid "<none>" msgstr "" +#: tmainform.cbmangafoxremovewatermark.caption +msgid "Remove watermark" +msgstr "" + +#: tmainform.cbmangafoxsaveaspng.caption +msgctxt "TMAINFORM.CBMANGAFOXSAVEASPNG.CAPTION" +msgid "Save as PNG" +msgstr "" + #: tmainform.cbonlynew.caption msgid "Search only new manga" msgstr "" @@ -462,16 +483,6 @@ msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" msgid "Auto check for latest version " msgstr "" -#: tmainform.cboptionbatotoshowalllang.caption -msgctxt "TMAINFORM.CBOPTIONBATOTOSHOWALLLANG.CAPTION" -msgid "[Batoto] Show All Language" -msgstr "" - -#: tmainform.cboptionbatotoshowscangroup.caption -msgctxt "TMAINFORM.CBOPTIONBATOTOSHOWSCANGROUP.CAPTION" -msgid "[Batoto] Show scan group name" -msgstr "" - #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" @@ -497,15 +508,6 @@ msgstr "" msgid "Enable live search (slow on long list)" msgstr "" -#: tmainform.cboptionmangafoxremovewatermark.caption -msgctxt "TMAINFORM.CBOPTIONMANGAFOXREMOVEWATERMARK.CAPTION" -msgid "[Mangafox] Remove watermark" -msgstr "" - -#: tmainform.cboptionmangafoxremovewatermarksaveaspng.caption -msgid "Save as PNG" -msgstr "" - #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "" @@ -962,6 +964,10 @@ msgctxt "TMAINFORM.EDWEBSITESSEARCH.TEXTHINT" msgid "Search website..." msgstr "" +#: tmainform.gbbatoto.caption +msgid "Batoto" +msgstr "" + #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" msgstr "" @@ -970,6 +976,14 @@ msgstr "" msgid "Drop Box" msgstr "" +#: tmainform.gbehentai.caption +msgid "E-Hentai/ExHentai" +msgstr "" + +#: tmainform.gbmangafox.caption +msgid "Mangafox" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "" From 721bfa364dcad78c2b181cfa8bf38ac0bc67741c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 11:07:59 +0800 Subject: [PATCH 0935/2794] ehentai fix get image url --- baseunits/modules/EHentai.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index db58f0f9d..41977c09e 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -286,9 +286,10 @@ function DownloadImage(var DownloadThread: TDownloadThread; while (not Result) and (not DownloadThread.IsTerminated) do begin source.LoadFromStream(DownloadThread.FHTTP.Document); query.ParseHTML(source.Text); + iurl:=''; if OptionEHentaiDownloadOriginalImage and (Account.Status[accname]=asValid) then - iurl:=query.XPathString('//a/@href[contains(.,"/fullimg.php")]') - else + iurl:=query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); + if iurl='' then iurl := query.XPathString('//*[@id="img"]/@src'); if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); From 324205dcabfd6662c9d3e582e8b990eacbb8bc0f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 11:22:02 +0800 Subject: [PATCH 0936/2794] ehentia, cleanup --- baseunits/modules/EHentai.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 41977c09e..4106527c6 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -65,7 +65,6 @@ function ExHentaiLogin(var AHTTP: THTTPSendThread): Boolean; function GETWithLogin(var AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; begin Result := False; - //if AWebsite = accname then begin if Account.Enabled[accname] then begin AHTTP.FollowRedirection := False; AHTTP.Cookies.Text := Account.Cookies[accname]; @@ -285,7 +284,7 @@ function DownloadImage(var DownloadThread: TDownloadThread; try while (not Result) and (not DownloadThread.IsTerminated) do begin source.LoadFromStream(DownloadThread.FHTTP.Document); - query.ParseHTML(source.Text); + query.ParseHTML(DownloadThread.FHTTP.Document); iurl:=''; if OptionEHentaiDownloadOriginalImage and (Account.Status[accname]=asValid) then iurl:=query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); From 4088a0504910cce0cb62d8dd09437a6922eec541 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 13:44:13 +0800 Subject: [PATCH 0937/2794] baseunit, txqueryenginehtml overload create --- baseunits/uBaseUnit.pas | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 17370999e..7d38e8c4c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -756,7 +756,8 @@ TXQueryEngineHTML = class FTreeParser: TTreeParser; function Eval(Expression: String; isCSS: Boolean = False; Tree: TTreeNode = nil): IXQValue; public - constructor Create(HTML: String = ''); + constructor Create(HTML: String = ''); overload; + constructor Create(HTMLStream: TStream); overload; destructor Destroy; override; procedure ParseHTML(HTML: String); overload; procedure ParseHTML(HTMLStream: TStream); overload; @@ -3734,6 +3735,14 @@ constructor TXQueryEngineHTML.Create(HTML: String); end; end; +constructor TXQueryEngineHTML.Create(HTMLStream: TStream); +begin + if Assigned(HTMLStream) then + Create(StreamToString(HTMLStream)) + else + Create; +end; + destructor TXQueryEngineHTML.Destroy; begin FEngine.Free; From e1f40f77629ff6c7e268d18b8813a3ba8aea1693 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 14:08:35 +0800 Subject: [PATCH 0938/2794] added mangachanru close #187 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaChanRU.pas | 158 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaChanRU.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 964c1b918..78002634c 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -23,4 +23,5 @@ uses MangaStreamTo, MangaKoi, GameofScanlation, - Hakihome; + Hakihome, + MangaChanRU; diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas new file mode 100644 index 000000000..043d87c88 --- /dev/null +++ b/baseunits/modules/MangaChanRU.pas @@ -0,0 +1,158 @@ +unit MangaChanRU; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil, RegExpr; + +implementation + +const + dirurl='/manga/new'; + perpage=20; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s:=XPathString('//*[@id="pagination"]/a[last()]/@href'); + if s<>'' then Page:=StrToIntDef(SeparateRight(s,'offset='),1); + if Page>1 then + Page:=ceil(Page/perpage); + finally + Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='?offset='+IntToStr(StrToInt(AURL)*perpage); + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@class="content_row"]//a[@class="title_link"]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink:=XPathString('//*[@id="manga_images"]//img[@id="cover"]/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=XPathString('//*[@class="name_row"]/h1'); + authors:=XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Автор")]/td[2]'); + genres:=XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тип")]/td[2]'); + AddCommaString(genres,XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тэги")]/td[2]')); + s:=XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Загружено")]/td[2]'); + if s<>'' then begin + if Pos('продолжается',s)>0 then status:='1' + else status:='0'; + end; + summary:=XPathString('//*[@id="description"]/text()'); + for v in XPath('//table[@class="table_cha"]//tr/td/*[@class="manga"]/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + i, j: Integer; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + Source:=TStringList.Create; + try + Source.LoadFromStream(Document); + if Source.Count>0 then + for i:=0 to Source.Count-1 do + if Pos('"fullimg":',Source[i])>0 then begin + s:=SeparateRight(Source[i],':'); + s:=TrimChar(s,['[',']',',']); + PageLinks.CommaText:=s; + if PageLinks.Count>0 then + with TRegExpr.Create('(?i)//im(\d*\.)') do + try + for j:=0 to PageLinks.Count-1 do + PageLinks[j]:=Replace(PageLinks[j],'//img$1',True); + finally + Free; + end; + Break; + end; + finally + Source.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='MangaChanRU'; + RootURL:='http://mangachan.ru'; + SortedList:=True; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index c83ec9c7b..203c6f056 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,7 +14,7 @@ Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga -Russian=NineManga_RU +Russian=MangaChanRU,NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi From c8d8f0a4d3f3e04a0036e7d2acb05ccd50be92fb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 15:31:11 +0800 Subject: [PATCH 0939/2794] baseunit, fix cleanstring --- baseunits/uBaseUnit.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7d38e8c4c..a973a2913 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2415,10 +2415,12 @@ function SetParams(const input: array of String): String; function CleanString(const S: String): String; begin Result := Trim(S); - Result := StringReplace(Result, #13, '', [rfReplaceAll]); - Result := StringReplace(Result, #10, '', [rfReplaceAll]); + if Result = '' then Exit; + Result := StringReplace(Result, #13, ' ', [rfReplaceAll]); + Result := StringReplace(Result, #10, ' ', [rfReplaceAll]); while Pos(' ', Result) > 0 do Result := StringReplace(Result, ' ', ' ', [rfReplaceAll]); + Result := Trim(Result); end; function CleanAndExpandURL(const URL: String): String; From 5edca40f81b0c3ec52185ce341f5b434ebc87914 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 15:35:19 +0800 Subject: [PATCH 0940/2794] baseunit, fix addcommastring --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a973a2913..d743e6d5b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2723,8 +2723,8 @@ function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): procedure AddCommaString(var Dest: string; S: string); begin - if Trim(S) = '' then Exit; - if Trim(S) = ',' then Exit; + S := Trim(TrimChar(Trim(S), [',', ' '])); + if (S = '') or (S = ',') then Exit; if Dest = '' then Dest := S else From d499f21a5f0f99850c7493e6b7ec9f1d45d02140 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 16:41:43 +0800 Subject: [PATCH 0941/2794] mangacanru, fix getdirectorypagenumber --- baseunits/modules/MangaChanRU.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 043d87c88..4d8459646 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -29,7 +29,7 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; s:=XPathString('//*[@id="pagination"]/a[last()]/@href'); if s<>'' then Page:=StrToIntDef(SeparateRight(s,'offset='),1); if Page>1 then - Page:=ceil(Page/perpage); + Page:=ceil(Page/perpage)+1; finally Free; end; From 8b831257738cc8f34f2621417368bcd56ab2cfc1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 16:57:38 +0800 Subject: [PATCH 0942/2794] added mintmanga close #186 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MintManga.pas | 172 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MintManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 78002634c..118d08d2d 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -24,4 +24,5 @@ uses MangaKoi, GameofScanlation, Hakihome, - MangaChanRU; + MangaChanRU, + MintManga; diff --git a/baseunits/modules/MintManga.pas b/baseunits/modules/MintManga.pas new file mode 100644 index 000000000..082d63d64 --- /dev/null +++ b/baseunits/modules/MintManga.pas @@ -0,0 +1,172 @@ +unit MintManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; + +implementation + +const + dirurl='/list?sortType=created'; + perpage=70; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s:=XPathString('//*[@class="pagination"]/a[@class="step"][last()]/@href'); + if s<>'' then Page:=StrToIntDef(GetBetween('offset=','&',s),1); + if Page>1 then + Page:=ceil(Page/perpage)+1; + finally + Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='&offset='+IntToStr(StrToInt(AURL)*perpage)+'&max='+IntToStr(perpage); + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@class="tiles row"]/div/div[@class="desc"]/h3/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + v: IXQValue; + rname, s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink:=XPathString('//*[@class="picture-fotorama"]/img/@src'); + rname:=XPathString('//h1[@class="names"]/span[@class="name"]'); + if title=''then title:=XPathString('//h1[@class="names"]/span[@class="eng-name"]'); + if title=''then title:=rname; + authors:=Trim(SeparateRight(XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Автор")]'),':')); + genres:=Trim(SeparateRight(XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Категория")]'),':')); + for v in XPath('//p[@class="elementList"]/span[starts-with(@class,"elem_genre")]') do + AddCommaString(genres,v.toString); + s:=XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Перевод")]'); + if s<>'' then begin + if Pos('продолжается',s)>0 then status:='1' + else status:='0'; + end; + summary:=XPathString('//*[@class="manga-description"]'); + for v in XPath('//table[@class="table table-hover"]/tbody/tr/td/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + s:=CleanString(v.toString); + if OptionRemoveMangaNameFromChapter and (rname<>'') then + if Pos(rname,LowerCase(s))=1 then s:=Trim(StringReplace(s,rname,'',[rfIgnoreCase])); + chapterName.Add(s); + end; + InvertStrings([chapterLinks,chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + Source: TStringList; + i, j, x: Integer; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + s:=AURL; + if Pos('mature=1',LowerCase(s))=0 then s+='?mature=1'; + if GET(FillHost(Module.RootURL,s)) then begin + Result:=True; + Source:=TStringList.Create; + try + Source.LoadFromStream(Document); + if Source.Count>0 then begin + s:=''; + for i:=0 to Source.Count-1 do + if Pos('rm_h.init(',Source[i])>0 then begin + s:=Trim(Source[i]); + Break; + end; + if s<>'' then begin + s:=GetBetween('[[',']]',Source[i]); + s:=StringReplace(s,'[','',[rfReplaceAll]); + s:=StringReplace(s,']','',[rfReplaceAll]); + s:=StringReplace(s,'"','',[rfReplaceAll]); + s:=StringReplace(s,'''','',[rfReplaceAll]); + Source.CommaText:=s; + if (Source.Count>0) and (frac(Source.Count/5)=0) then begin + j:=Source.Count div 5; + for i:=0 to j-1 do begin + x:=i*5; + PageLinks.Add(Source[x+1]+Source[x]+Source[x+2]); + end; + end; + end; + end; + finally + Source.Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='MintManga'; + RootURL:='http://mintmanga.com'; + SortedList:=True; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 203c6f056..555038cea 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,7 +14,7 @@ Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga -Russian=MangaChanRU,NineManga_RU +Russian=MangaChanRU,MintManga,NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi From 5529c9277bf87897085aa7c36e2a4e4cdd188329 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 17:07:04 +0800 Subject: [PATCH 0943/2794] renamed mintmanga to mintmangaru --- baseunits/ModuleList.inc | 2 +- baseunits/modules/{MintManga.pas => MintMangaRU.pas} | 4 ++-- config/mangalist.ini | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename baseunits/modules/{MintManga.pas => MintMangaRU.pas} (99%) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 118d08d2d..e9531e0ec 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -25,4 +25,4 @@ uses GameofScanlation, Hakihome, MangaChanRU, - MintManga; + MintMangaRU; diff --git a/baseunits/modules/MintManga.pas b/baseunits/modules/MintMangaRU.pas similarity index 99% rename from baseunits/modules/MintManga.pas rename to baseunits/modules/MintMangaRU.pas index 082d63d64..f1aac5c7f 100644 --- a/baseunits/modules/MintManga.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -1,4 +1,4 @@ -unit MintManga; +unit MintMangaRU; {$mode objfpc}{$H+} @@ -156,7 +156,7 @@ procedure RegisterModule; begin with AddModule do begin - Website:='MintManga'; + Website:='MintMangaRU'; RootURL:='http://mintmanga.com'; SortedList:=True; OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index 555038cea..470770fcd 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,7 +14,7 @@ Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga -Russian=MangaChanRU,MintManga,NineManga_RU +Russian=MangaChanRU,MintMangaRU,NineManga_RU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi From 8a56ec5f28ee472c512a860378f9da860ba4d347 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 17:10:53 +0800 Subject: [PATCH 0944/2794] added readmangaru close #185 --- baseunits/modules/MintMangaRU.pas | 25 ++++++++++++++++--------- config/mangalist.ini | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index f1aac5c7f..246141e12 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -153,17 +153,24 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; procedure RegisterModule; -begin - with AddModule do + + function AddWebsiteModule(AWebsite,ARootURL:String):TModuleContainer; begin - Website:='MintMangaRU'; - RootURL:='http://mintmanga.com'; - SortedList:=True; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Result:=AddModule; + with Result do begin + Website:=AWebsite; + RootURL:=ARootURL; + SortedList:=True; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; end; + +begin + AddWebsiteModule('MintMangaRU','http://mintmanga.com'); + AddWebsiteModule('ReadMangaRU','http://readmanga.me'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 470770fcd..bdb2ae1b1 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,7 +14,7 @@ Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga -Russian=MangaChanRU,MintMangaRU,NineManga_RU +Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi From f43a69ff932869202386a6fd8c184098472ae859 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 11 Feb 2016 17:29:03 +0800 Subject: [PATCH 0945/2794] Bump version 0.9.33.0 --- changelog.txt | 8 ++++++++ mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index ada9fcdea..1a9f77103 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.33.0 (11-02-2016) +[-] MangaCap: removed, website offline +[+] E-Hentai/ExHentai: added option to download original image if available +[+] Added MangaChanRU[RU] +[+] Added MintMangaRU[RU] +[+] Added ReadMangaRU[RU] +[*] Various changes and bug fixes + 0.9.32.3 (05-02-2016) [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 57652c356..384fbb885 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="32"/> - <BuildNr Value="3"/> + <RevisionNr Value="33"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 07949e978..1e6c7fc47 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.32.3 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.32.3/fmd_0.9.32.3.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.32.3/fmd_0.9.32.3_Win64.7z +VERSION=0.9.33.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.33.0/fmd_0.9.33.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.33.0/fmd_0.9.33.0_Win64.7z From 5eecad165f9748fbaed2a1ff2aaad4784941bacd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 13:15:26 +0800 Subject: [PATCH 0946/2794] change default batotoshowalllang to false fix #190 --- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d743e6d5b..dee1aab7f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -619,7 +619,7 @@ interface OptionAutoCheckFavRemoveCompletedManga: Boolean = False; OptionBatotoShowScanGroup: Boolean = True; - OptionBatotoShowAllLang: Boolean = True; + OptionBatotoShowAllLang: Boolean = False; OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; OptionMangaFoxRemoveWatermark: Boolean = True; OptionMangaFoxSaveAsPNG: Boolean = False; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 41836cf2c..3a24f6c9d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4347,7 +4347,7 @@ procedure TMainForm.LoadOptions; // misc cbBatotoShowScanGroup.Checked := ReadBool('Batoto', 'ShowScanGroup', True); - cbBatotoShowAllLang.Checked := ReadBool('Batoto', 'ShowAllLang', True); + cbBatotoShowAllLang.Checked := ReadBool('Batoto', 'ShowAllLang', False); cbMangaFoxRemoveWatermark.Checked := ReadBool('MangaFox', 'RemoveWatermark', True); cbMangaFoxSaveAsPNG.Checked := ReadBool('MangaFox', 'SaveAsPNG', False); cbEHentaiDownloadOriginalImage.Checked:=ReadBool('EHentai','DownloadOriginalImage',False); From a326455c0f355efba8051ab499556a7e4dc4b87e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 13:19:30 +0800 Subject: [PATCH 0947/2794] change default connection's retry count and timeout --- baseunits/uBaseUnit.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dee1aab7f..d385e042f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -601,8 +601,8 @@ interface OptionChapterCustomRename: String; OptionPDFQuality: Cardinal = 95; - OptionConnectionMaxRetry: Integer = 0; - OptionConnectionTimeout: Integer = 15000; + OptionConnectionMaxRetry: Integer = 5; + OptionConnectionTimeout: Integer = 30000; OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3a24f6c9d..161ee2fd1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4296,8 +4296,8 @@ procedure TMainForm.LoadOptions; // connection seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', 1); seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', 3);; - seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', 15); + seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', OptionConnectionMaxRetry);; + seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', OptionConnectionTimeout); cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); cbOptionProxyType.Text := ReadString('connections', 'ProxyType', 'HTTP'); edOptionHost.Text := ReadString('connections', 'Host', ''); From b6fb10cfb798d457a195e23704763c41a76d6c43 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 13:20:34 +0800 Subject: [PATCH 0948/2794] batoto, change max connection limit to 1 #190 --- baseunits/modules/Batoto.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 22a1cff07..1518f5b00 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -309,7 +309,7 @@ procedure RegisterModule; Website := modulename; RootURL := urlroot; MaxTaskLimit := 1; - MaxConnectionLimit := 2; + MaxConnectionLimit := 1; AccountSupport := True; SortedList := True; InformationAvailable := True; From 0f943c9dd1c583ec5a3d43e2cee0aae2897e5a1d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 13:39:24 +0800 Subject: [PATCH 0949/2794] remove academyvn includes files --- .../AcademyVN/chapter_page_number.inc | 34 ------ .../AcademyVN/directory_page_number.inc | 47 -------- .../includes/AcademyVN/manga_information.inc | 105 ------------------ .../includes/AcademyVN/names_and_links.inc | 35 ------ baseunits/uBaseUnit.pas | 12 +- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 5 - 7 files changed, 5 insertions(+), 248 deletions(-) delete mode 100644 baseunits/includes/AcademyVN/chapter_page_number.inc delete mode 100644 baseunits/includes/AcademyVN/directory_page_number.inc delete mode 100644 baseunits/includes/AcademyVN/manga_information.inc delete mode 100644 baseunits/includes/AcademyVN/names_and_links.inc diff --git a/baseunits/includes/AcademyVN/chapter_page_number.inc b/baseunits/includes/AcademyVN/chapter_page_number.inc deleted file mode 100644 index 82ceef1d6..000000000 --- a/baseunits/includes/AcademyVN/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetAcademyVNPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ACADEMYVN_ID, URL)); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (Pos('img-responsive', GetVal(parse[i], 'class')) > 0) then - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); - manager.container.PageNumber := manager.container.PageLinks.Count; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/AcademyVN/directory_page_number.inc b/baseunits/includes/AcademyVN/directory_page_number.inc deleted file mode 100644 index 201088aa1..000000000 --- a/baseunits/includes/AcademyVN/directory_page_number.inc +++ /dev/null @@ -1,47 +0,0 @@ - function GetAcademyVNDirectoryPageNumber: Byte; - var - i, p: Integer; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ACADEMYVN_ID, 1] + - '/manga/all', 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - Page := 0; - regx := TRegExpr.Create; - try - regx.Expression := '^.*/manga/all\?page=(\d+)$'; - regx.ModifierI := True; - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'a') and (Pos('/manga/all?page=', parse[i]) > 0 ) then - begin - s := GetVal(parse[i], 'href'); - s := regx.Replace(s, '$1', True); - p := StrToIntDef(s, 0); - if p > Page then - Page := p; - end; - finally - regx.Free; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/AcademyVN/manga_information.inc b/baseunits/includes/AcademyVN/manga_information.inc deleted file mode 100644 index 80bb2cfe6..000000000 --- a/baseunits/includes/AcademyVN/manga_information.inc +++ /dev/null @@ -1,105 +0,0 @@ - function GetAcademyVNInfoFromURL: Byte; - var - s: String; - i, j: Integer; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[ACADEMYVN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ACADEMYVN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if GetVal(parse[i], 'class') = '__name' then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //cover - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = '__image') then - if GetTagName(parse[i + 2]) = 'img' then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - if GetTagName(parse[i]) = 'strong' then - begin - //genre - if Pos('Thể loại:', parse[i + 1]) > 0 then - begin - for j := i + 2 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break; - if Pos('<', parse[j]) = 0 then - mangaInfo.genres := mangaInfo.genres + parse[j]; - end; - mangaInfo.genres := Trim(mangaInfo.genres); - end; - - //author - if Pos('Tác giả:', parse[i + 1]) > 0 then - mangaInfo.authors := CommonStringFilter(TrimLeftChar(parse[i + 5], [':'])); - - //status - if Pos('Tình trạng:', parse[i + 1]) > 0 then - begin - s := Trim(TrimLeftChar(parse[i + 3], [':'])); - if (s = 'Đang tiến hành') or (s = 'Ngưng') then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - end; - //summary - if GetVal(parse[i], 'class') = '__description' then - for j := i + 3 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/div' then - Break; - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := mangaInfo.summary + CommonStringFilter(parse[j]); - end; - - //chapters - if GetVal(parse[i], 'class') = 'table-scroll' then - isExtractChapters := True; - if isExtractChapters then - begin - if GetTagName(parse[i]) = '/table' then - isExtractChapters := False - else - if GetTagName(parse[i]) = 'a' then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.chapterName.Add(Trim(parse[i + 2])); - end; - end; - end; - Result := NO_ERROR; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 1 then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - end; diff --git a/baseunits/includes/AcademyVN/names_and_links.inc b/baseunits/includes/AcademyVN/names_and_links.inc deleted file mode 100644 index 5107b706d..000000000 --- a/baseunits/includes/AcademyVN/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function AcademyVNGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ACADEMYVN_ID, 1] + - '/manga/all?page=' + IntToStr(StrToInt(URL) + 1), 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(FixHTMLTagQuote(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'a') and - (GetVal(parse[i], 'class') = 'ajax-title text-ellipsis') then - begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter(GetVal(parse[i], 'title'))); - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d385e042f..63c77ca97 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -339,13 +339,12 @@ interface PORNXXXCOMICS_ID = 70; MANGASEE_ID = 71; MANGAKU_ID = 72; - ACADEMYVN_ID = 73; - MANGAAT_ID = 74; - READMANGATODAY_ID = 75; - LONEMANGA_ID = 76; - DYNASTYSCANS_ID = 77; + MANGAAT_ID = 73; + READMANGATODAY_ID = 74; + LONEMANGA_ID = 75; + DYNASTYSCANS_ID = 76; - WebsiteRoots: array [0..77] of array [0..1] of string = ( + WebsiteRoots: array [0..76] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -419,7 +418,6 @@ interface ('PornXXXComics', 'http://pornxxxcomics.com'), ('MangaSee', 'http://mangasee.co'), ('MangaKu', 'http://mangaku.web.id'), - ('AcademyVN', 'http://truyen.academyvn.com'), ('MangaAt', 'http://www.mangaat.com'), ('ReadMangaToday', 'http://www.readmanga.today'), ('LoneManga', 'http://lonemanga.com'), diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1aa91bfb7..0f46c72c8 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -844,8 +844,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/MangaSee/directory_page_number.inc} - {$I includes/AcademyVN/directory_page_number.inc} - {$I includes/MangaAt/directory_page_number.inc} {$I includes/ReadMangaToday/directory_page_number.inc} @@ -979,9 +977,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = MANGASEE_ID then Result := GetMangaSeeDirectoryPageNumber else - if WebsiteID = ACADEMYVN_ID then - Result := GetAcademyVNDirectoryPageNumber - else if WebsiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber else @@ -1124,8 +1119,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/MangaKu/names_and_links.inc} - {$I includes/AcademyVN/names_and_links.inc} - {$I includes/MangaAt/names_and_links.inc} {$I includes/ReadMangaToday/names_and_links.inc} @@ -1332,9 +1325,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks else - if WebsiteID = ACADEMYVN_ID then - Result := AcademyVNGetNamesAndLinks - else if WebsiteID = MANGAAT_ID then Result := MangaAtGetNamesAndLinks else @@ -1483,8 +1473,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/MangaKu/manga_information.inc} - {$I includes/AcademyVN/manga_information.inc} - {$I includes/MangaAt/manga_information.inc} {$I includes/ReadMangaToday/manga_information.inc} @@ -1703,9 +1691,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL else - if WebsiteID = ACADEMYVN_ID then - Result := GetAcademyVNInfoFromURL - else if WebsiteID = MANGAAT_ID then Result := GetMangaAtInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 543bf00f7..2e5c8ffee 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -465,8 +465,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaKu/chapter_page_number.inc} - {$I includes/AcademyVN/chapter_page_number.inc} - {$I includes/MangaAt/chapter_page_number.inc} {$I includes/ReadMangaToday/chapter_page_number.inc} @@ -625,9 +623,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGAKU_ID then Result := GetMangaKuPageNumber else - if manager.container.MangaSiteID = ACADEMYVN_ID then - Result := GetAcademyVNPageNumber - else if manager.container.MangaSiteID = MANGAAT_ID then Result := GetMangaAtPageNumber else From b0f8ce1aad26ec05a6c6d636e4b1d7412c32ea66 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 14:10:49 +0800 Subject: [PATCH 0950/2794] added academyvn module fix #188 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/AcademyVN.pas | 133 ++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/AcademyVN.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e9531e0ec..077101bcd 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -25,4 +25,5 @@ uses GameofScanlation, Hakihome, MangaChanRU, - MintMangaRU; + MintMangaRU, + AcademyVN; diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas new file mode 100644 index 000000000..685faaf33 --- /dev/null +++ b/baseunits/modules/AcademyVN.pas @@ -0,0 +1,133 @@ +unit AcademyVN; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil, RegExpr; + +implementation + +const + dirurl='/manga/all'; + +function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + var Page: Integer; Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + page:=StrToIntDef(XPathString('(//*[starts-with(@class,"pagination")]//a)[last()-1]'),1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(var MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL+dirurl; + if AURL<>'0' then s+='?page='+IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//table[1]/tbody/tr/td[1]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; + const Reconnect: Integer; Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink:=XPathString('//*[@class="__image"]/img/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=XPathString('//*[@class="__info"]/h3'); + authors:=SeparateRight(XPathString('//*[@class="__info"]/p[starts-with(.,"Tác giả:")]'),':'); + genres:=SeparateRight(XPathString('//*[@class="__info"]/p[starts-with(.,"Thể loại:")]'),':'); + s:=XPathString('//*[@class="__info"]/p[starts-with(.,"Tình trạng:")]'); + if s<>'' then begin + if (Pos('Đang tiến hành',s)>0) or (Pos('Ngưng',s)>0) then status:='1' + else status:='0'; + end; + summary:=XPathString('//*[@class="__info"]/*[@class="__description"]'); + for v in XPath('//*[@class="table-scroll"]/table/tbody/tr/td[1]/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; + Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//*[@class="manga-container"]/img/@src') do + PageLinks.Add(v.toString); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='AcademyVN'; + RootURL:='http://truyen.academyvn.com'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From 6e22559b66d631ee6f8e99adfa054d8ed98dc571 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 14:18:46 +0800 Subject: [PATCH 0951/2794] academyvn, clean up --- baseunits/modules/AcademyVN.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 685faaf33..6fe8063e3 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -5,8 +5,8 @@ interface uses - Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil, RegExpr; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; implementation From 311b8d598fa3654200ca36430605bd0a72a73daa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 14:45:01 +0800 Subject: [PATCH 0952/2794] baseunit, added cleanmultilinedstring --- baseunits/uBaseUnit.pas | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 63c77ca97..603811577 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -873,6 +873,7 @@ function RemoveSymbols(const input: String): String; function CorrectPathSys(const Path: String): String; function CleanString(const S: String): String; +function CleanMultilinedString(const S: String; MaxLineEnding: Integer = 1): String; function CleanAndExpandURL(const URL: String): String; function CleanURL(const URL: String): String; function AppendURLDelim(const URL: String): String; @@ -897,6 +898,7 @@ function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): String; procedure AddCommaString(var Dest: string; S: string); +function StringOfString(c: String; l: Integer): String; function IncStr(const S: String; N: Integer = 1): String; overload; function IncStr(const I: Integer; N: Integer = 1): String; overload; inline; @@ -2071,6 +2073,17 @@ function CorrectPathSys(const Path: String): String; end; end; +function StringOfString(c: String; l: Integer): String; +var + i: Integer; +begin + Result:=''; + if c='' then Exit; + if l<1 then Exit; + for i:=1 to l do + Result+=c; +end; + function IncStr(const S: String; N: Integer): String; var i: Integer; @@ -2421,6 +2434,25 @@ function CleanString(const S: String): String; Result := Trim(Result); end; +function CleanMultilinedString(const S: String; MaxLineEnding: Integer): String; +var + rn, rnp, n, np: String; +begin + Result:=Trim(s); + if Result='' then Exit; + if MaxLineEnding<1 then MaxLineEnding:=1; + + rn:=StringOfString(#13#10,MaxLineEnding); + rnp:=rn+#13#10; + while Pos(rnp,Result)>0 do + Result:=StringReplace(Result,rnp,rn,[rfReplaceAll]); + + n:=StringOfChar(#10,MaxLineEnding); + np:=n+#10; + while Pos(np,Result)>0 do + Result:=StringReplace(Result,np,n,[rfReplaceAll]); +end; + function CleanAndExpandURL(const URL: String): String; begin Result := AppendURLDelim(CleanURL(URL)); From ad4bd7cfc25fb608e6ad74600cc1f4340121cd37 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 14:45:16 +0800 Subject: [PATCH 0953/2794] udata, clean summary after getinfo --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0f46c72c8..c85c771a1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1728,7 +1728,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; artists := TrimRightChar(Trim(artists), [',']); genres := TrimRightChar(Trim(genres), [',']); - summary := Trim(summary); + summary := CleanMultilinedString(summary); //// strip //summary := StringBreaks(summary); From 9beb043a8ab47b692f3240591f617e7aea025669 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 14:47:23 +0800 Subject: [PATCH 0954/2794] udata, clean up --- baseunits/uData.pas | 8 -------- 1 file changed, 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c85c771a1..709c8f90f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1730,14 +1730,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; summary := CleanMultilinedString(summary); - //// strip - //summary := StringBreaks(summary); - //summary := Trim(TrimChar(summary, [#13, #10])); - //summary := BreaksString(summary); - //// strip double CR - //summary := Trim(StringReplace(summary, '\n\r\n\r', '\n\r', [rfReplaceAll])); - //summary := Trim(StringReplace(summary, '\r\n\r\n', '\r\n', [rfReplaceAll])); - // fix info if (authors = '-') or (authors = ':') then authors := ''; From e8156d96435a78b31be8373745245ca332e754cd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 14:50:23 +0800 Subject: [PATCH 0955/2794] Bump version 0.9.34.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1a9f77103..462af37b1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.34.0 (15-02-2016) +[*] AcademyVN: rewrite all script +[*] Various changes and bug fixes + 0.9.33.0 (11-02-2016) [-] MangaCap: removed, website offline [+] E-Hentai/ExHentai: added option to download original image if available diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 384fbb885..03d0cbf84 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="33"/> + <RevisionNr Value="34"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 1e6c7fc47..8c6aeab36 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.33.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.33.0/fmd_0.9.33.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.33.0/fmd_0.9.33.0_Win64.7z +VERSION=0.9.34.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.34.0/fmd_0.9.34.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.34.0/fmd_0.9.34.0_Win64.7z From 661b321afc1c4e6dc0415d393ef7c54f8e117d17 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Feb 2016 15:58:17 +0800 Subject: [PATCH 0956/2794] change default value of misc option --- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.pas | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 603811577..9657012e9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -616,7 +616,7 @@ interface OptionAutoCheckFavDownload: Boolean = False; OptionAutoCheckFavRemoveCompletedManga: Boolean = False; - OptionBatotoShowScanGroup: Boolean = True; + OptionBatotoShowScanGroup: Boolean = False; OptionBatotoShowAllLang: Boolean = False; OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; OptionMangaFoxRemoveWatermark: Boolean = True; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 161ee2fd1..55158e6cf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4346,11 +4346,11 @@ procedure TMainForm.LoadOptions; cbOptionShowDownloadMangalistDialog.Checked := ReadBool('dialogs', 'ShowDownloadMangalistDialog', True); // misc - cbBatotoShowScanGroup.Checked := ReadBool('Batoto', 'ShowScanGroup', True); - cbBatotoShowAllLang.Checked := ReadBool('Batoto', 'ShowAllLang', False); - cbMangaFoxRemoveWatermark.Checked := ReadBool('MangaFox', 'RemoveWatermark', True); - cbMangaFoxSaveAsPNG.Checked := ReadBool('MangaFox', 'SaveAsPNG', False); - cbEHentaiDownloadOriginalImage.Checked:=ReadBool('EHentai','DownloadOriginalImage',False); + cbBatotoShowScanGroup.Checked := ReadBool('Batoto', 'ShowScanGroup', OptionBatotoShowScanGroup); + cbBatotoShowAllLang.Checked := ReadBool('Batoto', 'ShowAllLang', OptionBatotoShowAllLang); + cbMangaFoxRemoveWatermark.Checked := ReadBool('MangaFox', 'RemoveWatermark', OptionMangaFoxRemoveWatermark); + cbMangaFoxSaveAsPNG.Checked := ReadBool('MangaFox', 'SaveAsPNG', OptionMangaFoxSaveAsPNG); + cbEHentaiDownloadOriginalImage.Checked:=ReadBool('EHentai','DownloadOriginalImage',OptionEHentaiDownloadOriginalImage); // websites if Length(optionMangaSiteSelectionNodes) > 0 then From 72bb0c8abd62785e833050ee164f81a1cfae44e1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Feb 2016 16:59:06 +0800 Subject: [PATCH 0957/2794] downloadmanager, change resourcestring --- baseunits/uDownloadsManager.pas | 4 ++-- mangadownloader/languages/fmd.en.po | 7 ++++--- mangadownloader/languages/fmd.id_ID.po | 7 ++++--- mangadownloader/languages/fmd.po | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2e5c8ffee..d2ea549b8 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -229,7 +229,7 @@ TDownloadManager = class end; resourcestring - RS_FailedToCreateDirTooLong = 'Failed to create dir! Too long?'; + RS_FailedToCreateDir = 'Failed to create directory!'; RS_FailedTryResumeTask = 'Failed, try resuming this task!'; RS_Preparing = 'Preparing'; RS_Downloading = 'Downloading'; @@ -1302,7 +1302,7 @@ procedure TTaskThread.Execute; if not ForceDirectoriesUTF8(S) then begin container.Status := STATUS_FAILED; - container.DownloadInfo.Status := RS_FailedToCreateDirTooLong; + container.DownloadInfo.Status := RS_FailedToCreateDir; Exit; end; end; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index a2573247c..79f97bbe4 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1679,9 +1679,9 @@ msgstr "Downloading" msgid "Failed" msgstr "Failed" -#: udownloadsmanager.rs_failedtocreatedirtoolong -msgid "Failed to create dir! Too long?" -msgstr "Failed to create dir! Too long?" +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Failed to create directory!" #: udownloadsmanager.rs_failedtryresumetask msgid "Failed, try resuming this task!" @@ -1829,3 +1829,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 205589dee..336127bdd 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1663,9 +1663,9 @@ msgstr "Mengunduh" msgid "Failed" msgstr "Gagal" -#: udownloadsmanager.rs_failedtocreatedirtoolong -msgid "Failed to create dir! Too long?" -msgstr "Gagal membuat folder! Terlalu panjang?" +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Gagal membuat direktori!" #: udownloadsmanager.rs_failedtryresumetask msgid "Failed, try resuming this task!" @@ -1813,3 +1813,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 349652e30..851cd6d2c 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1606,8 +1606,8 @@ msgstr "" msgid "Failed" msgstr "" -#: udownloadsmanager.rs_failedtocreatedirtoolong -msgid "Failed to create dir! Too long?" +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create direktory!" msgstr "" #: udownloadsmanager.rs_failedtryresumetask From 0c6363e20d2d2c5d7b2aaada8bed2e370c2ebeb6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 16:42:40 +0800 Subject: [PATCH 0958/2794] typo --- mangadownloader/languages/fmd.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 851cd6d2c..9282750fa 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1607,7 +1607,7 @@ msgid "Failed" msgstr "" #: udownloadsmanager.rs_failedtocreatedir -msgid "Failed to create direktory!" +msgid "Failed to create directory!" msgstr "" #: udownloadsmanager.rs_failedtryresumetask From 8c976e18fe4dd0e9afb9a1775e44ad2d083db89e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 16:42:51 +0800 Subject: [PATCH 0959/2794] cleanup --- mangadownloader/forms/frmMain.pas | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 55158e6cf..75c5a1dd1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1034,12 +1034,11 @@ procedure TMainForm.FormCreate(Sender: TObject); // Load config.ini options := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_FILE); - options.CacheUpdates := True; + options.CacheUpdates := False; + options.Options := options.Options-[ifoStripQuotes]; // Load revision.ini revisionIni := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + REVISION_FILE); - options.CacheUpdates := False; - options.StripQuotes := False; // Load updates.ini updates := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + UPDATE_FILE); @@ -3466,9 +3465,8 @@ procedure TMainForm.vtDownloadDragAllowed(Sender : TBaseVirtualTree; procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); var i, nIndex: Cardinal; - cNode, fNode: PVirtualNode; + cNode: PVirtualNode; ConTemp: TFPList; - fRect: TRect; begin if vtDownload.SelectedCount=0 then Exit; nIndex:=NextIndex; From 4c38dcbf34b7ffde9ca2417498d7ff8d74b9a0d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 18:22:00 +0800 Subject: [PATCH 0960/2794] cleanup websitemodules --- baseunits/WebsiteModules.pas | 200 ++++++++++++------------- baseunits/modules/AcademyVN.pas | 17 ++- baseunits/modules/Batoto.pas | 25 ++-- baseunits/modules/Doujinmoeus.pas | 31 ++-- baseunits/modules/EHentai.pas | 25 ++-- baseunits/modules/EightMuses.pas | 18 +-- baseunits/modules/FoOlSlide.pas | 21 +-- baseunits/modules/GameofScanlation.pas | 17 ++- baseunits/modules/Hakihome.pas | 21 +-- baseunits/modules/HentaiCafe.pas | 17 ++- baseunits/modules/HitomiLa.pas | 17 ++- baseunits/modules/KissManga.pas | 17 ++- baseunits/modules/Luscious.pas | 29 ++-- baseunits/modules/Madokami.pas | 27 ++-- baseunits/modules/MangaChanRU.pas | 17 ++- baseunits/modules/MangaFox.pas | 35 ++--- baseunits/modules/MangaHere.pas | 29 ++-- baseunits/modules/MangaKoi.pas | 21 +-- baseunits/modules/MangaLife.pas | 23 +-- baseunits/modules/MangaReader.pas | 33 ++-- baseunits/modules/MangaStream.pas | 33 ++-- baseunits/modules/MangaStreamTo.pas | 17 ++- baseunits/modules/MangaTr.pas | 17 ++- baseunits/modules/Mangacan.pas | 28 ++-- baseunits/modules/MintMangaRU.pas | 17 ++- baseunits/modules/PecintaKomik.pas | 17 ++- baseunits/modules/RawSenManga.pas | 21 +-- baseunits/modules/Seemh.pas | 17 ++- baseunits/modules/UnionMangas.pas | 17 ++- baseunits/modules/WPManga.pas | 21 +-- baseunits/uData.pas | 2 +- baseunits/uDownloadsManager.pas | 5 +- 32 files changed, 438 insertions(+), 414 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 81781afa7..3d326e898 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -25,29 +25,29 @@ interface TModuleContainer = class; - TOnGetDirectoryPageNumber = function(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; - TOnGetNameAndLink = function(var MangaInfo: TMangaInformation; + TOnGetDirectoryPageNumber = function(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; + TOnGetNameAndLink = function(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; - Module: TModuleContainer): Integer; - TOnGetInfo = function(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; + const Module: TModuleContainer): Integer; + TOnGetInfo = function(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; - TOnTaskStart = function(var Task: TTaskContainer; Module: TModuleContainer): Boolean; - TOnGetPageNumber = function(var DownloadThread: TDownloadThread; - const AURL: String; Module: TModuleContainer): Boolean; - TOnGetImageURL = function(var DownloadThread: TDownloadThread; - const AURL: String; Module: TModuleContainer): Boolean; + TOnTaskStart = function(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; + TOnGetPageNumber = function(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; + TOnGetImageURL = function(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; - TOnBeforeDownloadImage = function(var DownloadThread: TDownloadThread; - AURL: String; Module: TModuleContainer): Boolean; + TOnBeforeDownloadImage = function(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; - TOnDownloadImage = function(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; + TOnDownloadImage = function(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; - TOnAfterImageSaved = function(const AFilename: String; Module: TModuleContainer): Boolean; + TOnAfterImageSaved = function(const AFilename: String; const Module: TModuleContainer): Boolean; - TOnLogin = function(var AHTTP: THTTPSendThread): Boolean; + TOnLogin = function(const AHTTP: THTTPSendThread): Boolean; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, @@ -110,66 +110,63 @@ TWebsiteModules = class function LocateModule(const AWebsite: String): Integer; function LocateModuleByHost(const AHost: String): Integer; function ModuleAvailable(const ModuleId: Integer; - ModuleMethod: TModuleMethod): Boolean; - overload; + const ModuleMethod: TModuleMethod): Boolean; overload; function ModuleAvailable(const AWebsite: String; - ModuleMethod: TModuleMethod): Boolean; - overload; - function ModuleAvailable(const AWebsite: String; ModuleMethod: TModuleMethod; + const ModuleMethod: TModuleMethod): Boolean; overload; + function ModuleAvailable(const AWebsite: String; + const ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; overload; function ModuleAvailable(const AWebsite: String): Boolean; overload; - function ModuleAvailable(const AWebsite: String; var OutIndex: Integer): Boolean; - overload; + function ModuleAvailable(const AWebsite: String; + var OutIndex: Integer): Boolean; overload; - function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer): Integer; overload; - function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const AWebsite: String): Integer; overload; - function GetNameAndLink(var MangaInfo: TMangaInformation; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; - const ModuleId: Integer): Integer; - overload; - function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL, AWebsite: String): Integer; overload; - - function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; const ModuleId: Integer): Integer; overload; - function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; const AWebsite: String): Integer; overload; - - function TaskStart(var Task: TTaskContainer; const ModuleId: Integer): Boolean; - overload; - function TaskStart(var Task: TTaskContainer; const AWebsite: String): Boolean; - overload; - - function GetPageNumber(var DownloadThread: TDownloadThread; + const ModuleId: Integer): Integer; overload; + function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; + const AURL, AWebsite: String): Integer; overload; + + function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const ModuleId: Integer): Integer; overload; + function GetInfo(const MangaInfo: TMangaInformation; + const AURL, AWebsite: String): Integer; overload; + + function TaskStart(const Task: TTaskContainer; + const ModuleId: Integer): Boolean; overload; + function TaskStart(const Task: TTaskContainer; + const AWebsite: String): Boolean; overload; + + function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; overload; - function GetPageNumber(var DownloadThread: TDownloadThread; - const AURL, AWebsite: String): Boolean; - overload; + function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL, AWebsite: String): Boolean; overload; - function GetImageURL(var DownloadThread: TDownloadThread; + function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; overload; - function GetImageURL(var DownloadThread: TDownloadThread; - const AURL, AWebsite: String): Boolean; - overload; + function GetImageURL(const DownloadThread: TDownloadThread; + const AURL, AWebsite: String): Boolean; overload; - function BeforeDownloadImage(var DownloadThread: TDownloadThread; - AURL: String; const ModuleId: Integer): Boolean; overload; - function BeforeDownloadImage(var DownloadThread: TDownloadThread; - AURL: String; const AWebsite: String): Boolean; overload; + function BeforeDownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const ModuleId: Integer): Boolean; overload; + function BeforeDownloadImage(const DownloadThread: TDownloadThread; + const AURL, AWebsite: String): Boolean; overload; - function DownloadImage(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix: String; ModuleId: Integer): Boolean; overload; - function DownloadImage(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix, AWebsite: String): Boolean; overload; + function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const ModuleId: Integer): Boolean; overload; + function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName, AWebsite: String): Boolean; overload; - function AfterImageSaved(const AFilename: String; ModuleId: Integer): Boolean; overload; - function AfterImageSaved(const AFilename: String; AWebsite: String): Boolean; overload; + function AfterImageSaved(const AFilename: String; const ModuleId: Integer): Boolean; overload; + function AfterImageSaved(const AFilename, AWebsite: String): Boolean; overload; - function Login(var AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; overload; - function Login(var AHTTP: THTTPSendThread; const AWebsite: String): Boolean; overload; + function Login(const AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; overload; + function Login(const AHTTP: THTTPSendThread; const AWebsite: String): Boolean; overload; procedure LockModules; procedure UnlockModules; @@ -324,7 +321,7 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; end; function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; - ModuleMethod: TModuleMethod): Boolean; + const ModuleMethod: TModuleMethod): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; @@ -345,13 +342,13 @@ function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; end; function TWebsiteModules.ModuleAvailable(const AWebsite: String; - ModuleMethod: TModuleMethod): Boolean; + const ModuleMethod: TModuleMethod): Boolean; begin Result := ModuleAvailable(LocateModule(AWebsite), ModuleMethod); end; function TWebsiteModules.ModuleAvailable(const AWebsite: String; - ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; + const ModuleMethod: TModuleMethod; var OutIndex: Integer): Boolean; begin Result := False; OutIndex := LocateModule(AWebsite); @@ -370,8 +367,9 @@ function TWebsiteModules.ModuleAvailable(const AWebsite: String; Result := OutIndex > -1; end; -function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; const ModuleId: Integer): Integer; +function TWebsiteModules.GetDirectoryPageNumber( + const MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer + ): Integer; begin Page := 1; Result := MODULE_NOT_FOUND; @@ -381,14 +379,16 @@ function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation MangaInfo, Page, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; const AWebsite: String): Integer; +function TWebsiteModules.GetDirectoryPageNumber( + const MangaInfo: TMangaInformation; var Page: Integer; const AWebsite: String + ): Integer; begin Result := GetDirectoryPageNumber(MangaInfo, Page, LocateModule(AWebsite)); end; -function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; const ModuleId: Integer): Integer; +function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; const ModuleId: Integer + ): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; @@ -397,29 +397,29 @@ function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; MangaInfo, ANames, ALinks, AURL, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.GetNameAndLink(var MangaInfo: TMangaInformation; +function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL, AWebsite: String): Integer; begin Result := GetNameAndLink(MangaInfo, ANames, ALinks, AURL, LocateModule(AWebsite)); end; -function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const AURL: String; const Reconnect: Integer; const ModuleId: Integer): Integer; +function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetInfo) then Result := TModuleContainer(FModuleList[ModuleId]).OnGetInfo( - MangaInfo, AURL, Reconnect, TModuleContainer(FModuleList[ModuleId])); + MangaInfo, AURL, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.GetInfo(var MangaInfo: TMangaInformation; - const AURL: String; const Reconnect: Integer; const AWebsite: String): Integer; +function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; + const AURL, AWebsite: String): Integer; begin - Result := GetInfo(MangaInfo, AURL, Reconnect, LocateModule(AWebsite)); + Result := GetInfo(MangaInfo, AURL, LocateModule(AWebsite)); end; -function TWebsiteModules.TaskStart(var Task: TTaskContainer; +function TWebsiteModules.TaskStart(const Task: TTaskContainer; const ModuleId: Integer): Boolean; begin Result := False; @@ -429,13 +429,13 @@ function TWebsiteModules.TaskStart(var Task: TTaskContainer; Task, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.TaskStart(var Task: TTaskContainer; +function TWebsiteModules.TaskStart(const Task: TTaskContainer; const AWebsite: String): Boolean; begin Result := TaskStart(Task, LocateModule(AWebsite)); end; -function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; +function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; @@ -445,13 +445,13 @@ function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.GetPageNumber(var DownloadThread: TDownloadThread; +function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; const AURL, AWebsite: String): Boolean; begin Result := GetPageNumber(DownloadThread, AURL, LocateModule(AWebsite)); end; -function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; +function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; @@ -461,15 +461,15 @@ function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.GetImageURL(var DownloadThread: TDownloadThread; +function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; const AURL, AWebsite: String): Boolean; begin Result := GetImageURL(DownloadThread, AURL, LocateModule(AWebsite)); end; function TWebsiteModules.BeforeDownloadImage( - var DownloadThread: TDownloadThread; AURL: String; const ModuleId: Integer - ): Boolean; + const DownloadThread: TDownloadThread; const AURL: String; + const ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; @@ -479,31 +479,29 @@ function TWebsiteModules.BeforeDownloadImage( end; function TWebsiteModules.BeforeDownloadImage( - var DownloadThread: TDownloadThread; AURL: String; const AWebsite: String - ): Boolean; + const DownloadThread: TDownloadThread; const AURL, AWebsite: String): Boolean; begin Result := BeforeDownloadImage(DownloadThread, AURL, LocateModule(AWebsite)); end; -function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix: String; ModuleId: Integer): Boolean; +function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnDownloadImage) then Result := TModuleContainer(FModuleList[ModuleId]).OnDownloadImage( - DownloadThread, AURL, APath, AName, APrefix, TModuleContainer(FModuleList[ModuleId])); + DownloadThread, AURL, APath, AName, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.DownloadImage(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix, AWebsite: String): Boolean; +function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName, AWebsite: String): Boolean; begin - Result := DownloadImage(DownloadThread, AURL, APath, AName, APrefix, - LocateModule(AWebsite)); + Result := DownloadImage(DownloadThread, AURL, APath, AName, LocateModule(AWebsite)); end; function TWebsiteModules.AfterImageSaved(const AFilename: String; - ModuleId: Integer): Boolean; + const ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; @@ -511,13 +509,13 @@ function TWebsiteModules.AfterImageSaved(const AFilename: String; Result := TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved(AFilename, TModuleContainer(FModuleList[ModuleId])); end; -function TWebsiteModules.AfterImageSaved(const AFilename: String; - AWebsite: String): Boolean; +function TWebsiteModules.AfterImageSaved(const AFilename, AWebsite: String + ): Boolean; begin Result := AfterImageSaved(AFilename, LocateModule(AWebsite)); end; -function TWebsiteModules.Login(var AHTTP: THTTPSendThread; +function TWebsiteModules.Login(const AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; begin Result := False; @@ -526,8 +524,8 @@ function TWebsiteModules.Login(var AHTTP: THTTPSendThread; Result := TModuleContainer(FModuleList[ModuleId]).OnLogin(AHTTP); end; -function TWebsiteModules.Login(var AHTTP: THTTPSendThread; const AWebsite: String - ): Boolean; +function TWebsiteModules.Login(const AHTTP: THTTPSendThread; + const AWebsite: String): Boolean; begin Result := Login(AHTTP, LocateModule(AWebsite)); end; diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 6fe8063e3..4ef382967 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -13,8 +13,8 @@ implementation const dirurl='/manga/all'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; @@ -30,8 +30,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var v: IXQValue; s: String; @@ -54,8 +55,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; s: String; @@ -90,8 +91,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var v: IXQValue; begin diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 1518f5b00..6efe1792e 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -24,7 +24,7 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; locklogin: TRTLCriticalSection; onlogin: Boolean = False; -function Login(var AHTTP: THTTPSendThread): Boolean; +function Login(const AHTTP: THTTPSendThread): Boolean; var query: TXQueryEngineHTML; loginform: THTMLForm; @@ -95,7 +95,7 @@ function Login(var AHTTP: THTTPSendThread): Boolean; end; end; -function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; +function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String): Boolean; var s: String; begin @@ -125,8 +125,8 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; end; end; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -148,8 +148,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -174,8 +175,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v, w: IXQValue; @@ -239,8 +240,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; @@ -277,8 +278,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; rurl: String; diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index 0ae591074..aed68241e 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -12,15 +12,16 @@ implementation uses simplehtmltreeparser, xquery; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Page := 100; Result := NO_ERROR; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Source: TStringList; Parser: TTreeParser; @@ -31,7 +32,7 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if MangaInfo = nil then Exit; Source := TStringList.Create; try - s := 'get=' + IncStr(URL); + s := 'get=' + IncStr(AURL); with MangaInfo.FHTTP.Document do begin Clear; Write(PChar(s)^, Length(s)); @@ -45,9 +46,9 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if SelectXPathString('json(*)("success")', Parser) = 'true' then begin for v in SelectXPathIX('json(*)("newest")()("token")', Parser) do - Links.Add(v.toString); + ALinks.Add(v.toString); for v in SelectXPathIX('json(*)("newest")()("name")', Parser) do - Names.Add(v.toString); + ANames.Add(v.toString); end; finally Parser.Free; @@ -58,8 +59,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var info: TMangaInfo; Source: TStringList; @@ -69,10 +70,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); + info.url := FillHost(Module.RootURL, AURL); Source := TStringList.Create; try - if MangaInfo.GetPage(TObject(Source), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -109,7 +110,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function TaskStart(var Task: TTaskContainer; Module: TModuleContainer): Boolean; +function TaskStart(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; begin Result := True; if Task = nil then Exit; @@ -117,8 +118,8 @@ function TaskStart(var Task: TTaskContainer; Module: TModuleContainer): Boolean; Task.PageNumber := 0; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Container: TTaskContainer; Source: TStringList; @@ -133,7 +134,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Container.PageNumber := 0; Source := TStringList.Create; try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, URL), + if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, AURL), Container.Manager.retryConnect) then if Source.Count > 0 then begin diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 4106527c6..a18be8c10 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -21,7 +21,7 @@ implementation onlogin: Boolean = False; locklogin: TRTLCriticalSection; -function ExHentaiLogin(var AHTTP: THTTPSendThread): Boolean; +function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; var s: String; begin @@ -62,7 +62,7 @@ function ExHentaiLogin(var AHTTP: THTTPSendThread): Boolean; end; end; -function GETWithLogin(var AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; +function GETWithLogin(const AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; begin Result := False; if Account.Enabled[accname] then begin @@ -79,8 +79,8 @@ function GETWithLogin(var AHTTP: THTTPSendThread; const AURL, AWebsite: String): Result := AHTTP.GET(AURL); end; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin @@ -99,8 +99,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; rurl: String; @@ -126,8 +127,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -208,8 +209,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; rurl: String; @@ -265,8 +266,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function DownloadImage(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; iurl: String; diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index b5124dfe2..27b760497 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -9,8 +9,8 @@ interface implementation -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -22,10 +22,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := RemoveURLDelim(FillHost(Module.RootURL, URL)); + info.url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -61,8 +61,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Query: TXQueryEngineHTML; @@ -76,7 +76,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), - RemoveURLDelim(FillHost(Module.RootURL, URL)), Manager.retryConnect) then + RemoveURLDelim(FillHost(Module.RootURL, AURL)), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; @@ -96,8 +96,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Query: TXQueryEngineHTML; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index a82a0d31e..c5217ca0e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -14,8 +14,8 @@ implementation dirurl='/directory/'; yomangadirurl='/reader/directory/'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -41,8 +41,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -69,8 +70,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -103,8 +104,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; @@ -139,8 +140,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 97e2c3396..d7473dd9c 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -13,8 +13,9 @@ implementation const dirurl='/forums/projects-releases.9/'; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -36,8 +37,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -79,8 +80,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; @@ -109,8 +110,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index f54d488ee..a62625da9 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -13,8 +13,8 @@ implementation const dirurl='/listmangahentai.html'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -35,8 +35,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -61,8 +62,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -95,8 +96,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; @@ -129,8 +130,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index c95ac1bad..841c1dd95 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -11,8 +11,8 @@ implementation uses synautil; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin @@ -31,8 +31,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -55,8 +56,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -91,8 +92,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var source: TStringList; i: Integer; diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 84b0d2a16..3f01f7140 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -9,8 +9,8 @@ interface implementation -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var source: TStringList; i: Integer; @@ -36,8 +36,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -60,8 +61,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -92,8 +93,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index a37462f0c..89b23fab2 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -37,8 +37,8 @@ function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; end; end; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -62,8 +62,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -89,8 +90,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -135,8 +136,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var source: TStringList; i: Integer; diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 530d75d55..75d22d65d 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -15,15 +15,16 @@ implementation const dirURL = '/c/-/albums/t/manga/sorted/new/page/'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Page := 100; Result := NO_ERROR; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -34,15 +35,15 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Source := TStringList.Create; try if GetPage(MangaInfo.FHTTP, TObject(Source), - Module.RootURL + dirURL + IncStr(URL) + '/', 3) then + Module.RootURL + dirURL + IncStr(AURL) + '/', 3) then if Source.Count > 0 then begin Result := NO_ERROR; Query := TXQueryEngineHTML.Create(Source.Text); try for v in Query.XPath('//*[@id="albums_wrapper"]//*[@class="caption"]//a') do begin - Links.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); - Names.Add(v.toString); + ALinks.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); + ANames.Add(v.toString); end; finally Query.Free; @@ -55,8 +56,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -69,7 +70,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + info.url := AppendURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; regx := TRegExpr.Create; try @@ -80,7 +81,7 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if RightStr(info.url, 5) <> 'view/' then info.url += 'view/'; if Pos('/pictures/album/', info.url) > 0 then info.url := StringReplace(info.url, '/pictures/album/', '/albums/', []); - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -122,8 +123,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Query: TXQueryEngineHTML; @@ -142,7 +143,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; - rurl := AppendURLDelim(FillHost(Module.RootURL, URL)); + rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; regx:=TRegExpr.Create; try diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 61077e0c1..ea0574b80 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -33,7 +33,7 @@ implementation locklogin: TRTLCriticalSection; onlogin: Boolean = False; -function Login(var AHTTP: THTTPSendThread): Boolean; +function Login(const AHTTP: THTTPSendThread): Boolean; begin Result := False; if Account.Enabled[modulename] = False then Exit; @@ -71,7 +71,7 @@ function Login(var AHTTP: THTTPSendThread): Boolean; end; end; -function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; +function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; begin Result := False; AHTTP.Cookies.Text := Account.Cookies[modulename]; @@ -84,15 +84,16 @@ function GETWithLogin(var AHTTP: THTTPSendThread; AURL: String): Boolean; end; end; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := Length(madokamidirlist); end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -123,8 +124,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -167,8 +168,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; datapath, datafiles: String; @@ -203,13 +204,13 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function DownloadImage(var DownloadThread: TDownloadThread; - const AURL, APath, AName, APrefix: String; Module: TModuleContainer): Boolean; +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; if GETWithLogin(DownloadThread.FHTTP, AURL) then begin - SaveImageStreamToFile(DownloadThread.FHTTP.Document, APath, AName + APrefix); + SaveImageStreamToFile(DownloadThread.FHTTP.Document, APath, AName); end; end; diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 4d8459646..867fe22f5 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -14,8 +14,8 @@ implementation dirurl='/manga/new'; perpage=20; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var s: String; begin @@ -36,8 +36,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var v: IXQValue; s: String; @@ -60,8 +61,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; s: String; @@ -97,8 +98,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; i, j: Integer; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index ad17e126c..3705fcbad 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -10,15 +10,16 @@ interface implementation -function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; - var Page: Integer; {%H-}Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := 1; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const {%H-}URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Parse: TStringList; @@ -30,8 +31,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; if (GetTagName(Parse[i]) = 'a') and (Pos('series_preview manga_', Parse[i]) > 0) then begin - Links.Add(GetVal(Parse[i], 'href')); - Names.Add(CommonStringFilter(Parse[i + 1])); + ALinks.Add(GetVal(Parse[i], 'href')); + ANames.Add(CommonStringFilter(Parse[i + 1])); end; end; @@ -55,8 +56,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; @@ -183,10 +184,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); + info.url := FillHost(Module.RootURL, AURL); Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Parse)) then begin Result := INFORMATION_NOT_FOUND; ParseHTML(Parse.Text, Parse); @@ -201,8 +202,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Parse: TStringList; Container: TTaskContainer; @@ -238,7 +239,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Parse := TStringList.Create; try if DownloadThread.GetPage(TObject(Parse), - AppendURLDelim(FillHost(Module.RootURL, URL)) + '1.html', + AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1.html', Container.Manager.retryConnect) then begin ParseHTML(Parse.Text, Parse); @@ -253,8 +254,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Parse: TStringList; Container: TTaskContainer; @@ -279,7 +280,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Parse := TStringList.Create; try if DownloadThread.GetPage(TObject(Parse), - AppendURLDelim(FillHost(Module.RootURL, URL)) + + AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '.html', Container.Manager.retryConnect) then begin @@ -295,7 +296,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; end; end; -function AfterImageSaved(const AFilename: String; Module: TModuleContainer): Boolean; +function AfterImageSaved(const AFilename: String; const Module: TModuleContainer): Boolean; begin Result := True; if OptionMangaFoxRemoveWatermark then diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 4c8d87741..95ad5d022 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -12,8 +12,9 @@ implementation const dirURL = '/mangalist/'; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -30,8 +31,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Query := TXQueryEngineHTML.Create(Source.Text); try for v in Query.XPath('//a[@class="manga_info"]') do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; finally Query.Free; @@ -44,8 +45,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -57,10 +58,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + info.url := AppendURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -98,8 +99,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Query: TXQueryEngineHTML; @@ -112,7 +113,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, URL)), Manager.retryConnect) then + AppendURLDelim(FillHost(Module.RootURL, AURL)), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; @@ -130,8 +131,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Query: TXQueryEngineHTML; @@ -142,7 +143,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; with DownloadThread.manager.container do begin Source := TStringList.Create; try - rurl := AppendURLDelim(FillHost(Module.RootURL, URL)); + rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); if DownloadThread.workCounter > 0 then rurl += IncStr(DownloadThread.workCounter) + '.html'; if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 1a41f1355..8a2da6523 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -13,8 +13,8 @@ implementation const dirurl='/directory'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin @@ -33,8 +33,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -59,8 +60,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; a, v, t: IXQValue; @@ -105,8 +106,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; begin @@ -129,8 +130,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index cb80007c1..95a0106c1 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -15,8 +15,9 @@ implementation const dirURL = '/directory/'; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -33,8 +34,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; Query := TXQueryEngineHTML.Create(Source.Text); try for v in Query.XPath('//*[@id="content"]/p/a') do begin - Links.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); - Names.Add(v.toString); + ALinks.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); + ANames.Add(v.toString); end; finally Query.Free; @@ -47,8 +48,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Source: TStringList; Query: TXQueryEngineHTML; @@ -60,10 +61,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, URL)); + info.url := AppendURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -105,8 +106,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Query: TXQueryEngineHTML; @@ -123,7 +124,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, URL)), Manager.retryConnect) then + AppendURLDelim(FillHost(Module.RootURL, AURL)), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 8cc82946d..9b9e54048 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -15,15 +15,16 @@ implementation const dirurl = '/alphabetical'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := 1; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Source: TStringList; Parser: TTreeParser; @@ -44,8 +45,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; ParseHTMLTree(Parser, Source.Text); for v in SelectXPathIX('//ul[@class="series_alpha"]/li/a', Parser) do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; finally Parser.Free; @@ -57,8 +58,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Source: TStringList; Parser: TTreeParser; @@ -104,10 +105,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; if MangaInfo = nil then Exit; MangaInfo.mangaInfo.website := Module.Website; - MangaInfo.mangaInfo.url := FillHost(Module.RootURL, URL); + MangaInfo.mangaInfo.url := FillHost(Module.RootURL, AURL); Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), MangaInfo.mangaInfo.url, Reconnect) then + if MangaInfo.FHTTP.GET(MangaInfo.mangaInfo.url, TObject(Source)) then begin Result := INFORMATION_NOT_FOUND; if Source.Count > 0 then @@ -127,8 +128,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Parser: TTreeParser; @@ -141,7 +142,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; PageNumber := 0; Source := TStringList.Create; try - if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(Module.RootURL, URL), + if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(Module.RootURL, AURL), Manager.retryConnect) then if Source.Count > 0 then begin @@ -161,8 +162,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Parser: TTreeParser; @@ -173,7 +174,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, URL)) + + AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter), Manager.retryConnect) then if Source.Count > 0 then begin diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 75ec24f0e..874aaf43f 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -15,15 +15,16 @@ implementation const readURL = 'http://readms.com'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Page := 1; Result := NO_ERROR; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const URL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Source: TStringList; Parser: TTreeParser; @@ -40,8 +41,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; try ParseHTMLTree(Parser, Source.Text); for v in SelectXPathIX('//table//tr/td[1]//a', Parser) do begin - Links.Add(v.toNode.getAttribute('href')); - Names.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end finally Parser.Free; @@ -54,8 +55,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var info: TMangaInfo; Source: TStringList; @@ -67,10 +68,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; Result := NET_PROBLEM; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); + info.url := FillHost(Module.RootURL, AURL); Source := TStringList.Create; try - if GetPage(MangaInfo.FHTTP, TObject(Source), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then if Source.Count > 0 then begin Result := NO_ERROR; @@ -103,8 +104,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Container: TTaskContainer; Source: TStringList; @@ -119,7 +120,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Container.PageNumber := 0; Source := TStringList.Create; try - if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(readURL, URL + '/1'), + if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(readURL, AURL + '/1'), Container.Manager.retryConnect) then if Source.Count > 0 then begin @@ -143,8 +144,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; Parser: TTreeParser; @@ -155,7 +156,7 @@ function GetImageURL(var DownloadThread: TDownloadThread; const URL: String; Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(readURL, URL)) + + AppendURLDelim(FillHost(readURL, AURL)) + IncStr(DownloadThread.workCounter), Manager.retryConnect) then if Source.Count > 0 then begin diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index a8a02f8c4..506393add 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -13,8 +13,9 @@ implementation const dirurl='/series.html'; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -36,8 +37,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -62,8 +63,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; begin @@ -86,8 +87,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index eacfddaac..79181a91d 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -12,8 +12,9 @@ implementation var mangatrcookie: String = ''; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -36,8 +37,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -99,8 +100,8 @@ function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; @@ -127,8 +128,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; begin diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index eb7fbd6d4..e4386deb3 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -13,16 +13,16 @@ implementation const dirURL = '/daftar-komik-manga-bahasa-indonesia.html'; -function GetDirectoryPageNumber(var {%H-}MangaInfo: TMangaInformation; - var Page: Integer; {%H-}Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := 1; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const Names, Links: TStringList; const {%H-}URL: String; - Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var Parse: TStringList; @@ -33,8 +33,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; for i := 0 to Parse.Count - 1 do if (GetTagName(Parse[i]) = 'a') and (Pos('baca-komik-', Parse[i]) <> 0) then begin - Links.Add(GetVal(Parse[i], 'href')); - Names.Add(CommonStringFilter(Parse[i + 1])); + ALinks.Add(GetVal(Parse[i], 'href')); + ANames.Add(CommonStringFilter(Parse[i + 1])); end; end; @@ -58,8 +58,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const URL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var Parse: TStringList; info: TMangaInfo; @@ -115,10 +115,10 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; if MangaInfo = nil then Exit; info := MangaInfo.mangaInfo; info.website := Module.Website; - info.url := FillHost(Module.RootURL, URL); + info.url := FillHost(Module.RootURL, AURL); Parse := TStringList.Create; try - if MangaInfo.GetPage(TObject(Parse), info.url, Reconnect) then + if MangaInfo.FHTTP.GET(info.url, TObject(Parse)) then begin Result := INFORMATION_NOT_FOUND; ParseHTML(Parse.Text, Parse); @@ -133,8 +133,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const URL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Parse: TStringList; Container: TTaskContainer; @@ -159,7 +159,7 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const URL: String; Parse := TStringList.Create; try if DownloadThread.GetPage(TObject(Parse), - FillHost(Module.RootURL, URL), + FillHost(Module.RootURL, AURL), Container.Manager.retryConnect) then begin ParseHTML(Parse.Text, Parse); diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index 246141e12..b9c546df4 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -14,8 +14,8 @@ implementation dirurl='/list?sortType=created'; perpage=70; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var s: String; begin @@ -36,8 +36,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var v: IXQValue; s: String; @@ -60,8 +61,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; rname, s: String; @@ -102,8 +103,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var Source: TStringList; i, j, x: Integer; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 5eec6c2aa..13f0accfe 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -13,8 +13,9 @@ implementation const dirurl='/directory/'; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -36,8 +37,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -73,8 +74,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; begin @@ -97,8 +98,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s, b: String; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index c42af8758..461a37e3e 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -10,8 +10,9 @@ interface implementation -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -33,8 +34,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -107,8 +108,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; @@ -153,8 +154,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; @@ -177,8 +178,8 @@ function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function BeforeDownloadImage(var DownloadThread: TDownloadThread; - AURL: String; Module: TModuleContainer): Boolean; +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; begin Result:=False; if DownloadThread = nil then Exit; diff --git a/baseunits/modules/Seemh.pas b/baseunits/modules/Seemh.pas index 830fbeecf..d786f6ee0 100644 --- a/baseunits/modules/Seemh.pas +++ b/baseunits/modules/Seemh.pas @@ -13,8 +13,8 @@ implementation const dirurl='/list/'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin @@ -33,8 +33,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -59,8 +60,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -91,8 +92,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index c23007877..ed4c0db32 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -13,8 +13,8 @@ implementation const dirurl='/mangas'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -38,8 +38,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -64,8 +65,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -103,8 +104,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; v: IXQValue; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 81e36f646..ea33a4d53 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -18,8 +18,8 @@ implementation dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; dirURLmangahen = '/manga_list/all/any/last-added/'; -function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; - var Page: Integer; Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -47,8 +47,9 @@ function GetDirectoryPageNumber(var MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(var MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -96,8 +97,8 @@ function GetNameAndLink(var MangaInfo: TMangaInformation; end; end; -function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; - const Reconnect: Integer; Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -219,8 +220,8 @@ function GetInfo(var MangaInfo: TMangaInformation; const AURL: String; end; end; -function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; begin @@ -243,8 +244,8 @@ function GetPageNumber(var DownloadThread: TDownloadThread; const AURL: String; end; end; -function GetImageURL(var DownloadThread: TDownloadThread; const AURL: String; - Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 709c8f90f..8495ae6d3 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1499,7 +1499,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; ModuleId := Modules.LocateModule(website); if Modules.ModuleAvailable(ModuleId, MMGetInfo) then begin mangaInfo.url := FillHost(Modules.Module[ModuleId].RootURL, URL); - Result := Modules.GetInfo(Self, URL, Reconnect, ModuleId) + Result := Modules.GetInfo(Self, URL, ModuleId) end else begin diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d2ea549b8..a07063ecf 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -50,7 +50,7 @@ TDownloadThread = class(TFMDThread) // Get number of download link from URL function GetPageNumberFromURL(const URL: String): Boolean; // Download image - function DownloadImage(const prefix: String = ''): Boolean; + function DownloadImage: Boolean; procedure OnTag({%H-}NoCaseTag, ActualTag: string); procedure OnText(Text: String); @@ -1084,7 +1084,7 @@ procedure TTaskThread.SyncShowBaloon; MainForm.TrayIcon.ShowBalloonHint; end; -function TDownloadThread.DownloadImage(const prefix: String): Boolean; +function TDownloadThread.DownloadImage: Boolean; var s, TURL, lpath, sfilename: String; @@ -1128,7 +1128,6 @@ function TDownloadThread.DownloadImage(const prefix: String): Boolean; s, lpath, Format('%.3d', [workCounter + 1]), - prefix, ModuleId); end else From a2b55aa47530f6d6073370f7796b9e198fc2baf1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 18:36:35 +0800 Subject: [PATCH 0961/2794] changed listview header height --- mangadownloader/forms/frmAccountManager.lfm | 3 ++- mangadownloader/forms/frmMain.lfm | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 26e319187..90f3ec1cd 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -15,6 +15,7 @@ object AccountManagerForm: TAccountManagerForm OnDestroy = FormDestroy OnShow = FormShow LCLVersion = '1.7' + Visible = False object pnBtContainer: TPanel Left = 295 Height = 304 @@ -253,7 +254,7 @@ object AccountManagerForm: TAccountManagerForm Text = 'Status' end> Header.DefaultHeight = 17 - Header.Height = 25 + Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] NodeDataSize = 1 TabOrder = 0 diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index d9e83cb47..dcaab7b1d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -12,7 +12,7 @@ object MainForm: TMainForm OnDestroy = FormDestroy OnShow = FormShow OnWindowStateChange = FormWindowStateChange - LCLVersion = '1.7' + Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -96,7 +96,7 @@ object MainForm: TMainForm Width = 80 end> Header.DefaultHeight = 17 - Header.Height = 25 + Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] HintMode = hmHintAndDefault Images = IconDL @@ -486,6 +486,7 @@ object MainForm: TMainForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 23 Header.MainColumn = -1 Margin = 2 ParentFont = False @@ -1703,7 +1704,7 @@ object MainForm: TMainForm Width = 200 end> Header.DefaultHeight = 24 - Header.Height = 24 + Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] HintMode = hmHintAndDefault Images = IconList @@ -2787,6 +2788,7 @@ object MainForm: TMainForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 23 Header.MainColumn = -1 Margin = 0 ParentFont = False @@ -3327,6 +3329,7 @@ object MainForm: TMainForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 23 Header.MainColumn = -1 HintMode = hmHint Margin = 0 From 231e37b668d55f66cba475d59f05f996288e9492 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 20:09:39 +0800 Subject: [PATCH 0962/2794] udata, fix empty mangainfo.link --- baseunits/uData.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8495ae6d3..34e4a7091 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1489,7 +1489,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; AdvanceLoadHTTPConfig(FHTTP, website); mangaInfo.website := website; - if mangaInfo.link = '' then mangaInfo.link := URL; mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; mangaInfo.chapterName.Clear; @@ -1711,6 +1710,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; end; with mangaInfo do begin + if mangaInfo.link = '' then mangaInfo.link := mangaInfo.url; + s := artists; if (s <> '') and (s[1] = '<') then artists := ''; From feb8a685b6cebbe70e7f4712a8ec48ba037a3b1f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 20:16:04 +0800 Subject: [PATCH 0963/2794] udata, fix cleanup mangainfo --- baseunits/uData.pas | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 34e4a7091..fc25cd2a0 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1712,14 +1712,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; with mangaInfo do begin if mangaInfo.link = '' then mangaInfo.link := mangaInfo.url; - s := artists; - if (s <> '') and (s[1] = '<') then - artists := ''; - s := authors; - if (s <> '') and (s[1] = '<') then - authors := ''; - - // check everything once more + // cleanup info title := Trim(RemoveStringBreaks(CommonStringFilter(title))); authors := Trim(RemoveStringBreaks(Trim(authors))); artists := Trim(RemoveStringBreaks(Trim(artists))); @@ -1732,9 +1725,9 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; summary := CleanMultilinedString(summary); // fix info - if (authors = '-') or (authors = ':') then + if (LeftStr(authors, 1) = '<') or (authors = '-') or (authors = ':') then authors := ''; - if (artists = '-') or (artists = ':') then + if (LeftStr(artists, 1) = '<') or (artists = '-') or (artists = ':') then artists := ''; if (summary = '-') or (summary = ':') then summary := ''; From 9f284b267056223f7251889fd66255fc3367f689 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 20:42:57 +0800 Subject: [PATCH 0964/2794] fix getinfo with empy selected website --- baseunits/uGetMangaInfosThread.pas | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 40f993250..6b64a2783 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -69,7 +69,7 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.mangaInfo.website := Website; FInfo.mangaInfo.link := Link; FInfo.ModuleId := Modules.LocateModule(Website); - if (FMangaListPos >= 0) and + if (FMangaListPos >= 0) and (MainForm.cbSelectManga.ItemIndex<>-1) and (website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex]) then begin filterPos := FMangaListPos; @@ -138,8 +138,6 @@ procedure TGetMangaInfosThread.DoGetInfos; end; begin - if MainForm.cbSelectManga.ItemIndex < 0 then - Exit; try INIAdvanced.Reload; if not GetMangaInfo then From 5d730d0c533d4f5752ad3d1b231e7da5c4c313dd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 20:53:02 +0800 Subject: [PATCH 0965/2794] getinfo, fix get thumbnails --- baseunits/uGetMangaInfosThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 6b64a2783..4924c0eca 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -153,7 +153,7 @@ procedure TGetMangaInfosThread.DoGetInfos; if OptionEnableLoadCover and (Trim(FInfo.mangaInfo.coverLink) <> '') then begin FInfo.FHTTP.Document.Clear; - FIsHasMangaCover := GetPage(FInfo.FHTTP, TObject(FCover), FInfo.mangaInfo.coverLink, 0) + FIsHasMangaCover := FInfo.FHTTP.GET(FInfo.mangaInfo.coverLink, FCover); end else FIsHasMangaCover := False; From 089a324d6d75743c294d9177e55ad90a70e0c101 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 20:57:39 +0800 Subject: [PATCH 0966/2794] udata, fix link --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fc25cd2a0..eb8b9e63f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1710,7 +1710,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; end; with mangaInfo do begin - if mangaInfo.link = '' then mangaInfo.link := mangaInfo.url; + if mangaInfo.link = '' then mangaInfo.link := RemoveHostFromURL(mangaInfo.url); // cleanup info title := Trim(RemoveStringBreaks(CommonStringFilter(title))); From 43ba34fc0751c586dea4c24e5a2280d341d91d8a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 21:25:15 +0800 Subject: [PATCH 0967/2794] added webtoons close #193 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Webtoons.pas | 151 +++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/Webtoons.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 077101bcd..ae018255b 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -26,4 +26,5 @@ uses Hakihome, MangaChanRU, MintMangaRU, - AcademyVN; + AcademyVN, + Webtoons; diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas new file mode 100644 index 000000000..48431092b --- /dev/null +++ b/baseunits/modules/Webtoons.pas @@ -0,0 +1,151 @@ +unit Webtoons; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; + +implementation + +const + dirurl='/en/genre'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="card_lst"]/li/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('div/p[@class="subj"]',v.toNode)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + p, i: Integer; + + procedure getchapters; + var + v: IXQValue; + begin + for v in query.XPath('//ul[@id="_listUl"]/li/a') do begin + MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); + MangaInfo.mangaInfo.chapterName.Add(query.XPathString('span[@class="subj"]/span',v.toNode)); + end; + end; + + procedure getp; + begin + p:=StrToIntDef(SeparateRight( + query.XPathString('//div[@class="detail_lst"]/div[@class="paginate"]/a[last()]/@href'),'&page='),1); + end; + +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + url:=FillHost(Module.RootURL,AURL); + if GET(url) then begin + Result:=NO_ERROR; + query:=TXQueryEngineHTML.Create(Document); + with query do + try + coverLink:=XPathString('//div[@class="detail_header type_white"]/span[@class="thmb"]/img/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=XPathString('//div[@class="info"]/h1/text()'); + authors:=XPathString('//div[@class="info"]/a/text()'); + genres:=XPathString('//div[@class="info"]/h2'); + summary:=XPathString('//p[@class="summary"]'); + getchapters; + getp; + if p>1 then begin + i:=2; + while i<=p do begin + if GET(url+'&page='+IntToStr(i)) then begin + ParseHTML(Document); + getchapters; + getp; + end; + Inc(i); + end; + end; + InvertStrings([chapterLinks,chapterName]); + Reset; + Headers.Values['Referer']:=' '+url; + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@id="_imageList"]/img[@class="_images"]/@data-url') do + PageLinks.Add(v.toString); + finally + Free; + end; + end; + end; +end; + +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result:=False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container do + if CurrentDownloadChapterPtr<ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer']:=' '+FillHost(Module.RootURL,ChapterLinks[CurrentDownloadChapterPtr]); + Result:=True; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='Webtoons'; + RootURL:='http://www.webtoons.com'; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnBeforeDownloadImage:=@BeforeDownloadImage; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index bdb2ae1b1..49fc058bf 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=http://sourceforge.net/projects/newfmd/files/data/<website>.7z/dow [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From fccba02fbc74b6e8a4f7fae6b504b9ca12b0ade1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 21:28:33 +0800 Subject: [PATCH 0968/2794] Bump version 0.9.35.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 462af37b1..c5e71d9fa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.35.0 (21-02-2016) +[*] Added Webtoons[EN] +[*] Various changes and bug fixes + 0.9.34.0 (15-02-2016) [*] AcademyVN: rewrite all script [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 03d0cbf84..cd728c65f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="34"/> + <RevisionNr Value="35"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 8c6aeab36..f0db14ead 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.34.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.34.0/fmd_0.9.34.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.34.0/fmd_0.9.34.0_Win64.7z +VERSION=0.9.35.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.35.0/fmd_0.9.35.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.35.0/fmd_0.9.35.0_Win64.7z From e288c9eb68ccfb8f0587d8a798f69bac00fbb5d5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 23:15:38 +0800 Subject: [PATCH 0969/2794] updater, fix download with sf url --- updater/uMain.pas | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 821b5b11d..bdc225a3e 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -262,6 +262,7 @@ procedure TDownloadThread.UZipOnStartFile(Sender :TObject; const AFileName :stri procedure TDownloadThread.Execute; var + sf : Boolean = False; regx : TRegExpr; i, ctry : Cardinal; Sza, @@ -282,6 +283,7 @@ procedure TDownloadThread.Execute; s := LowerCase(URL); if (Pos('sourceforge.net/', s) <> 0) or (Pos('sf.net/', s) <> 0) then begin + sf := True; FHTTP.UserAgent := UA_CURL; regx.Expression := '/download$'; URL := Trim(regx.Replace(URL, '', False)); @@ -304,7 +306,11 @@ procedure TDownloadThread.Execute; sfile := regx.Replace(URL, '$3', True); if FileName = '' then FileName := sfile; - rurl := 'http://sourceforge.net/projects/' + sproject + '/files/' + + if Pos('https://',LowerCase(URL)) = 1 then + rurl := 'https://' + else + rurl:='http://'; + rurl := rurl + 'sourceforge.net/projects/' + sproject + '/files/' + sdir + '/' + sfile + '/download'; end else @@ -355,7 +361,8 @@ procedure TDownloadThread.Execute; if (FHTTP.ResultCode >= 300) and (FHTTP.Headers.Values['Location'] <> '') then begin - HTTPHeaders.Values['Referer'] := ' ' + rurl; + if not sf then + HTTPHeaders.Values['Referer'] := ' ' + rurl; UpdateStatus(RS_Redirected); rurl := Trim(FHTTP.Headers.Values['Location']); end; From 70b9aca243c3702cb9fe039d0326308ac3bce564 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 23:19:11 +0800 Subject: [PATCH 0970/2794] updater, increase version number --- updater/updater.lpi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/updater/updater.lpi b/updater/updater.lpi index 7908f1f81..601587523 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="2"/> - <MinorVersionNr Value="3"/> - <RevisionNr Value="3"/> + <MinorVersionNr Value="4"/> <Attributes pvaPrivateBuild="True"/> <StringTable FileDescription="Updater for Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="updater.exe" ProductName="Updater" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> From 052d874244bee46940eece8544da55bed2340040 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 23:19:34 +0800 Subject: [PATCH 0971/2794] changed mangalist url --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 49fc058bf..ab342cc8e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -1,6 +1,6 @@ [general] DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader -DBDownloadURL=http://sourceforge.net/projects/newfmd/files/data/<website>.7z/download +DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] Arabic=MangaAe,MangaAr,MangaAt From 09b2e779b7d6a30d4da8e133499143d1f0839275 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Feb 2016 23:22:53 +0800 Subject: [PATCH 0972/2794] Bump version 0.9.35.1 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 1 + update | 6 +++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index c5e71d9fa..9daf8d4dc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,9 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.35.1 (21-02-2016) +[*] Updater: fix download manga list from server + 0.9.35.0 (21-02-2016) [*] Added Webtoons[EN] [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index cd728c65f..9c0bc2850 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,6 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="35"/> + <BuildNr Value="1"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index f0db14ead..81bb3f51f 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.35.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.35.0/fmd_0.9.35.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.35.0/fmd_0.9.35.0_Win64.7z +VERSION=0.9.35.1 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.35.1/fmd_0.9.35.1.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.35.1/fmd_0.9.35.1_Win64.7z From 0ce0b2e030581bbfae7950e0aff650c0b49f5dfa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Feb 2016 19:43:45 +0800 Subject: [PATCH 0973/2794] gos, cleanup --- baseunits/modules/GameofScanlation.pas | 28 ++++++++++---------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index d7473dd9c..231ed6dd5 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -17,22 +17,20 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - query.ParseHTML(MangaInfo.FHTTP.Document); - for v in query.XPath('//h4/a[@class="menuRow"]') do begin + for v in XPath('//h4/a[@class="menuRow"]') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end; finally - query.Free; + Free; end; end; end; @@ -83,9 +81,8 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; v: IXQValue; - s: RegExprString; + s: String; begin Result:=False; if DownloadThread=nil then Exit; @@ -97,14 +94,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; s:=AppendURLDelim(FillHost(Module.RootURL,s))+'?chapter_view=fullstrip'; if GET(s) then begin Result:=True; - query:=TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(Document) do try - query.ParseHTML(Document); - for v in query.XPath('//div[@id="comicMainImage"]/a/img/@src') do + for v in XPath('//div[@id="comicMainImage"]/a/img/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL,v.toString)); - PageNumber:=query.XPath('//select[@id="ctrl_chapter_page"]/option').Count; + PageNumber:=XPath('//select[@id="ctrl_chapter_page"]/option').Count; finally - query.Free; + Free; end; end; end; @@ -113,7 +109,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; s: String; begin Result:=False; @@ -123,16 +118,15 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread.workCounter>0 then s+='?comic_page='+IncStr(DownloadThread.workCounter); if GET(FillHost(Module.RootURL,s)) then begin Result:=True; - query:=TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(Document) do try - query.ParseHTML(Document); - s:=query.XPathString('//img[@id="comicMainImage"]/@src'); + s:=XPathString('//img[@id="comicMainImage"]/@src'); if s<>'' then begin s:=MaybeFillHost(Module.RootURL,s); PageLinks[DownloadThread.workCounter]:=s; end; finally - query.Free; + Free; end; end; end; From 4a5e9d580e7d21900e74bb67e02caa872b479d8a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Feb 2016 20:56:47 +0800 Subject: [PATCH 0974/2794] cloudflare, added getcf with various overload and cleanup --- baseunits/modules/Cloudflare.pas | 104 ++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 5ee0d6c74..7dafb6598 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -7,16 +7,24 @@ interface uses Classes, SysUtils, uBaseUnit, BESEN, BESENValue, RegExpr; -function AntiBotActive(const AHTTP:THTTPSendThread):Boolean; -function GETCF(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String):Boolean; +function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; + var CS: TRTLCriticalSection): Boolean; overload; +function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String): Boolean; overload; +function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; overload; implementation -function GetAnsweredURL(const Source,URL:String;var OMethod,OURL:String;var OSleepTime:Integer):Boolean; +function AntiBotActive(const AHTTP:THTTPSendThread): Boolean; +begin + Result:=False; + if AHTTP=nil then Exit; + Result:=Pos('URL=/cdn-cgi/',AHTTP.Headers.Values['Refresh'])>0; +end; + +function JSGetAnsweredURL(const Source,URL: String; var OMethod, OURL: String; + var OSleepTime: Integer): Boolean; var s, meth, surl, jschl_vc, pass, jschl_answer: String; - query: TXQueryEngineHTML; - js: TBESEN; v: TBESENValue; begin Result:=False; @@ -28,15 +36,14 @@ function GetAnsweredURL(const Source,URL:String;var OMethod,OURL:String;var OSle pass:=''; jschl_answer:=''; - query:=TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(Source) do try - query.ParseHTML(Source); - meth:=UpperCase(query.XPathString('//form[@id="challenge-form"]/@method')); - surl:=query.XPathString('//form[@id="challenge-form"]/@action'); - jschl_vc:=query.XPathString('//input[@name="jschl_vc"]/@value'); - pass:=query.XPathString('//input[@name="pass"]/@value'); + meth:=UpperCase(XPathString('//form[@id="challenge-form"]/@method')); + surl:=XPathString('//form[@id="challenge-form"]/@action'); + jschl_vc:=XPathString('//input[@name="jschl_vc"]/@value'); + pass:=XPathString('//input[@name="pass"]/@value'); finally - query.Free; + Free; end; if (meth='') or (surl='') or (jschl_vc='') or (pass='') then Exit; @@ -61,15 +68,16 @@ function GetAnsweredURL(const Source,URL:String;var OMethod,OURL:String;var OSle Free; end; - js:=TBESEN.Create; - try - v:=js.Execute(s); - if v.ValueType=bvtNUMBER then - jschl_answer:=FloatToStr(v.Num); - except - jschl_answer:=''; + with TBESEN.Create do begin + try + v:=Execute(s); + if v.ValueType=bvtNUMBER then + jschl_answer:=FloatToStr(v.Num); + except + jschl_answer:=''; + end; + Free; end; - js.Free; if jschl_answer='' then Exit; OMethod:=meth; @@ -77,14 +85,7 @@ function GetAnsweredURL(const Source,URL:String;var OMethod,OURL:String;var OSle Result:=True; end; -function AntiBotActive(const AHTTP:THTTPSendThread):Boolean; -begin - Result:=False; - if AHTTP=nil then Exit; - Result:=Pos('URL=/cdn-cgi/',AHTTP.Headers.Values['Refresh'])>0; -end; - -function GETCF(const AHTTP:THTTPSendThread;AURL:String;var Cookie:String):Boolean; +function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): Boolean; var m, u, h: String; st, counter: Integer; @@ -100,7 +101,7 @@ function GETCF(const AHTTP:THTTPSendThread;AURL:String;var Cookie:String):Boolea u:=''; h:=AppendURLDelim(GetHostURL(AURL)); st:=5000; - if GetAnsweredURL(StreamToString(AHTTP.Document),h,m,u,st) then + if JSGetAnsweredURL(StreamToString(AHTTP.Document),h,m,u,st) then if (m<>'') and (u<>'') then begin AHTTP.Reset; AHTTP.Headers.Values['Referer']:=' '+AURL; @@ -122,4 +123,49 @@ function GETCF(const AHTTP:THTTPSendThread;AURL:String;var Cookie:String):Boolea end; end; +function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; + var CS: TRTLCriticalSection): Boolean; +begin + Result:=False; + if AHTTP=nil then Exit; + AHTTP.Cookies.Text:=Cookie; + Result:=AHTTP.GET(AURL); + if (AHTTP.ResultCode>500) and AntiBotActive(AHTTP) then begin + if TryEnterCriticalsection(CS)>0 then + try + Result:=CFJS(AHTTP,AURL,Cookie); + finally + LeaveCriticalsection(CS); + end + else + try + EnterCriticalsection(CS); + AHTTP.Cookies.Text:=Cookie; + finally + LeaveCriticalsection(CS); + end; + Result:=AHTTP.GET(AURL); + end; +end; + +function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String): Boolean; +begin + Result:=False; + if AHTTP=nil then Exit; + AHTTP.Cookies.Text:=Cookie; + Result:=AHTTP.GET(AURL); + if (AHTTP.ResultCode>500) and AntiBotActive(AHTTP) then begin + Result:=CFJS(AHTTP,AURL,Cookie); + Result:=AHTTP.GET(AURL); + end; +end; + +function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +var + Cookie: String; +begin + Cookie:=''; + Result:=GETCF(AHTTP,AURL,Cookie); +end; + end. From c3663f00a41a8b0763df8564e85491e3a115a04d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Feb 2016 21:12:03 +0800 Subject: [PATCH 0975/2794] kissmanga, cleanup --- baseunits/modules/KissManga.pas | 99 +++++++++++++-------------------- 1 file changed, 38 insertions(+), 61 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 89b23fab2..9637963f7 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -15,32 +15,16 @@ implementation var kissmangacookies: String=''; - lockget: TRTLCriticalSection; - onlockget: Boolean=False; + kissmangalockget: TRTLCriticalSection; -function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; begin - AHTTP.Cookies.Text:=kissmangacookies; - Result:=AHTTP.GET(AURL); - if (AHTTP.ResultCode>500) and Cloudflare.AntiBotActive(AHTTP) then begin - if TryEnterCriticalsection(lockget)>0 then begin - onlockget:=True; - Result:=Cloudflare.GETCF(AHTTP,AURL,kissmangacookies); - onlockget:=False; - LeaveCriticalsection(lockget); - end - else begin - while onlockget do Sleep(1000); - AHTTP.Cookies.Text:=kissmangacookies; - end; - Result:=AHTTP.GET(AURL); - end; + Result:=Cloudflare.GETCF(AHTTP,AURL,kissmangacookies,kissmangalockget); end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; s: String; begin Result := NET_PROBLEM; @@ -48,16 +32,15 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+dirurl) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=query.XPathString('//ul[@class="pager"]/li[last()]/a/@href'); + s:=XPathString('//ul[@class="pager"]/li[last()]/a/@href'); if s<>'' then begin s:=ReplaceRegExpr('^.*=(\d+)$',s,'$1',True); Page:=StrToIntDef(s,1); end; finally - query.Free; + Free; end; end; end; @@ -66,7 +49,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; s: String; begin @@ -77,15 +59,14 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; s:=s+'?page='+IncStr(AURL); if GETWithCookie(MangaInfo.FHTTP,s) then begin Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@class="listing"]/tbody/tr/td[1]/a') do begin + for v in XPath('//table[@class="listing"]/tbody/tr/td[1]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end; finally - query.Free; + Free; end; end; end; @@ -93,45 +74,41 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; i: Integer; s: String; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GETWithCookie(MangaInfo.FHTTP,FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//div[@id="rightside"]//img/@src'); - if title=''then title:=query.XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); - v:=query.XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); - if v.Count > 0 then begin - i:=0; - while i<v.Count-2 do begin - s:=v.get(i).toString; - if Pos('Genres:',s)=1 then genres:=SeparateRight(s,':') else - if Pos('Author:',s)=1 then authors:=SeparateRight(s,':') else - if Pos('Artist:',s)=1 then artists:=SeparateRight(s,':') else - if Pos('Status:',s)=1 then begin - if Pos('ongoing',LowerCase(v.get(i).toString))>0 then status:='1' - else status:='0'; - end else - if Pos('Summary:',s)=1 then summary:=v.get(i+1).toString; - Inc(i); - end; - end; - for v in query.XPath('//table[@class="listing"]/tbody/tr/td/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + if GETWithCookie(MangaInfo.FHTTP,FillHost(Module.RootURL,AURL)) then begin + Result:=NO_ERROR; + with MangaInfo.mangaInfo,TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + coverLink:=XPathString('//div[@id="rightside"]//img/@src'); + if title=''then title:=XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); + v:=XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); + if v.Count > 0 then begin + i:=0; + while i<v.Count-2 do begin + s:=v.get(i).toString; + if Pos('Genres:',s)=1 then genres:=SeparateRight(s,':') else + if Pos('Author:',s)=1 then authors:=SeparateRight(s,':') else + if Pos('Artist:',s)=1 then artists:=SeparateRight(s,':') else + if Pos('Status:',s)=1 then begin + if Pos('ongoing',LowerCase(v.get(i).toString))>0 then status:='1' + else status:='0'; + end else + if Pos('Summary:',s)=1 then summary:=v.get(i+1).toString; + Inc(i); end; - InvertStrings([chapterLinks,chapterName]); - finally - query.Free; end; + for v in XPath('//table[@class="listing"]/tbody/tr/td/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + Free; end; end; end; @@ -180,10 +157,10 @@ procedure RegisterModule; end; initialization - InitCriticalSection(lockget); + InitCriticalSection(kissmangalockget); RegisterModule; finalization - DoneCriticalsection(lockget); + DoneCriticalsection(kissmangalockget); end. From c67af3ddb79fce745dc17e757b0419cf4321c291 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Feb 2016 23:27:16 +0800 Subject: [PATCH 0976/2794] gos, rewrite all fix #194 --- baseunits/modules/GameofScanlation.pas | 81 ++++++++++++++------------ 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 231ed6dd5..75d71198a 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -6,12 +6,20 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil; + RegExpr, synautil, Cloudflare; implementation const - dirurl='/forums/projects-releases.9/'; + dirurl='/projects/'; +var + goscookies: string=''; + goslockget: TRTLCriticalSection; + +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +begin + Result:=Cloudflare.GETCF(AHTTP,AURL,goscookies,goslockget); +end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; @@ -21,11 +29,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+dirurl) then begin Result:=NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//h4/a[@class="menuRow"]') do begin + for v in XPath('//div[@class="info"]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end; @@ -41,11 +49,11 @@ function GetInfo(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; i, p: Integer; - rurl: String; + s: String; procedure GetChapters; begin - for v in query.XPath('//*[@class="discussionListItems"]//div[@class="listBlock main"]/div/h3/a') do begin + for v in query.XPath('//div[@class="list_press_text"]/p[@class="text_work"]/a') do begin MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); MangaInfo.mangaInfo.chapterName.Add(v.toString); end; @@ -55,18 +63,26 @@ function GetInfo(const MangaInfo: TMangaInformation; Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - rurl:=AppendURLDelim(FillHost(Module.RootURL,AURL)); - if GET(rurl) then begin + url:=AppendURLDelim(FillHost(Module.RootURL,AURL)); + if GETWithCookie(MangaInfo.FHTTP,url) then begin Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + query:=TXQueryEngineHTML.Create(Document); try - query.ParseHTML(Document); - if title=''then title:=query.XPathString('//div[@class="titleBarContent"]/h1'); + if title=''then title:=query.XPathString('//div[@class="con"]/h2'); + summary:=query.XPathString('//dd[@class="dsc"]'); + s:=query.XPathString('//div[@class="con"]/dl/span[@class="aln"]'); + if s<>'' then begin + s:=LowerCase(s); + if Pos('ongoing',s)>0 then + status:='1' + else if Pos('completed',s)>0 then + status:='0'; + end; GetChapters; - p:=StrToIntDef(query.XPathString('(//div[@class="PageNav"])[1]/@data-last'),1); + p:=StrToIntDef(query.XPathString('//nav/a[last()-1]'),1); if p>1 then for i:=2 to p do - if GET(rurl+'page-'+IntToStr(i)) then begin + if GET(AppendURLDelim(url)+'page-'+IntToStr(i)) then begin query.ParseHTML(Document); GetChapters; end; @@ -92,13 +108,12 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; s:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); s:=AppendURLDelim(FillHost(Module.RootURL,s))+'?chapter_view=fullstrip'; - if GET(s) then begin + if GETWithCookie(DownloadThread.FHTTP,s) then begin Result:=True; with TXQueryEngineHTML.Create(Document) do try for v in XPath('//div[@id="comicMainImage"]/a/img/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL,v.toString)); - PageNumber:=XPath('//select[@id="ctrl_chapter_page"]/option').Count; finally Free; end; @@ -106,30 +121,20 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; -function GetImageURL(const DownloadThread: TDownloadThread; +function BeforeDownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; begin Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=AppendURLDelim(AURL); - if DownloadThread.workCounter>0 then s+='?comic_page='+IncStr(DownloadThread.workCounter); - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - with TXQueryEngineHTML.Create(Document) do - try - s:=XPathString('//img[@id="comicMainImage"]/@src'); - if s<>'' then begin - s:=MaybeFillHost(Module.RootURL,s); - PageLinks[DownloadThread.workCounter]:=s; - end; - finally - Free; - end; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do + if CurrentDownloadChapterPtr<ChapterLinks.Count then begin + Headers.Values['Referer']:=' '+FillHost(Module.RootURL,ChapterLinks[CurrentDownloadChapterPtr]); + Cookies.Text:=goscookies; + if (goscookies='') or (HEAD(AURL) and (ResultCode=503)) then + Result:=GETWithCookie(DownloadThread.FHTTP,Module.RootURL) + else + Result:=True; end; - end; end; procedure RegisterModule; @@ -141,11 +146,15 @@ procedure RegisterModule; OnGetNameAndLink:=@GetNameAndLink; OnGetInfo:=@GetInfo; OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; + OnBeforeDownloadImage:=@BeforeDownloadImage; end; end; initialization + InitCriticalSection(goslockget); RegisterModule; +finalization + DoneCriticalsection(goslockget); + end. From f2167ef9d1961562bc707646db353bad4b020f73 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Feb 2016 23:33:45 +0800 Subject: [PATCH 0977/2794] removed lonemanga, redirected to gos --- .../LoneManga/chapter_page_number.inc | 33 ------- .../includes/LoneManga/manga_information.inc | 88 ------------------- .../includes/LoneManga/names_and_links.inc | 26 ------ baseunits/uBaseUnit.pas | 6 +- baseunits/uData.pas | 10 --- baseunits/uDownloadsManager.pas | 5 -- config/mangalist.ini | 2 +- 7 files changed, 3 insertions(+), 167 deletions(-) delete mode 100644 baseunits/includes/LoneManga/chapter_page_number.inc delete mode 100644 baseunits/includes/LoneManga/manga_information.inc delete mode 100644 baseunits/includes/LoneManga/names_and_links.inc diff --git a/baseunits/includes/LoneManga/chapter_page_number.inc b/baseunits/includes/LoneManga/chapter_page_number.inc deleted file mode 100644 index d06d82cb8..000000000 --- a/baseunits/includes/LoneManga/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetLoneMangaPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - - s := 'showAll=true&design=Show+in+Long+Strip+Mode'; - FHTTP.Sock.Tag := 100; //POST - FHTTP.Document.Clear; - FHTTP.Document.Write(PChar(s)^, Length(s)); - - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(LONEMANGA_ID, URL)), - manager.container.manager.retryConnect); - - ParseHTML(l.Text, parse); - if parse.Count > 0 then - begin - manager.container.PageLinks.Clear; - for i := 0 to parse.Count-1 do - begin - if GetVal(parse[i], 'class') = 'imageWrapper' then - if GetTagName(parse[i+2]) = 'img' then - manager.container.PageLinks.Add(GetVal(parse[i+2], 'src')); - end; - manager.container.PageNumber := manager.container.PageLinks.Count; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/LoneManga/manga_information.inc b/baseunits/includes/LoneManga/manga_information.inc deleted file mode 100644 index 57e16e377..000000000 --- a/baseunits/includes/LoneManga/manga_information.inc +++ /dev/null @@ -1,88 +0,0 @@ - function GetLoneMangaInfoFromURL: Byte; - var - s: String; - i, j: Integer; - begin - mangaInfo.website := WebsiteRoots[LONEMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(LONEMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count-1 do - begin - //title - if mangaInfo.title = '' then - if GetVal(parse[i], 'class') = 'kommiku-bread' then - mangaInfo.title := CommonStringFilter(parse[i+2]); - - //cover - if mangaInfo.coverLink = '' then - if (GetTagName(parse[i]) = 'img') and - (Pos('float:', parse[i]) <> 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - if (GetTagName(parse[i]) = 'td') and - (GetVal(parse[i], 'class') = 'infoTabOne') then - begin - //genre - if Pos('Type:', parse[i+2]) > 0 then - mangaInfo.genres := Trim(parse[i+6]); - - //status - if Pos('Status:', parse[i+2]) > 0 then - begin - s := LowerCase(Trim(parse[i+6])); - if s = 'ongoing' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - - //summary - if Pos('Summary:', parse[i+2]) <> 0 then - begin - mangaInfo.summary := ''; - for j := i + 5 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/td' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := mangaInfo.summary + LineEnding + CommonStringFilter(parse[j]); - end; - mangaInfo.summary := Trim(mangaInfo.summary); - end; - end; - - //chapters - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'column') then - begin - for j := i+2 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/table' then - Break - else - if GetTagName(parse[j]) = 'a' then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[j], 'href')); - mangaInfo.chapterName.Add(CommonStringFilter(parse[j+1])); - end; - end; - end; - end; - Result := NO_ERROR; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 1 then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - end; diff --git a/baseunits/includes/LoneManga/names_and_links.inc b/baseunits/includes/LoneManga/names_and_links.inc deleted file mode 100644 index d28229fcc..000000000 --- a/baseunits/includes/LoneManga/names_and_links.inc +++ /dev/null @@ -1,26 +0,0 @@ - function LoneMangaGetNamesAndLinks: Byte; - var - i: Integer; - s: string; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[LONEMANGA_ID, 1] + '/mangas/'; - if not GetPage(TObject(Source), s, 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetVal(parse[i], 'class') = 'grid-entry-title entry-title') then - begin - links.Add(GetVal(parse[i+1], 'href')); - names.Add(CommonStringFilter(parse[i+2])); - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9657012e9..d76342166 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -341,10 +341,9 @@ interface MANGAKU_ID = 72; MANGAAT_ID = 73; READMANGATODAY_ID = 74; - LONEMANGA_ID = 75; - DYNASTYSCANS_ID = 76; + DYNASTYSCANS_ID = 75; - WebsiteRoots: array [0..76] of array [0..1] of string = ( + WebsiteRoots: array [0..75] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -420,7 +419,6 @@ interface ('MangaKu', 'http://mangaku.web.id'), ('MangaAt', 'http://www.mangaat.com'), ('ReadMangaToday', 'http://www.readmanga.today'), - ('LoneManga', 'http://lonemanga.com'), ('Dynasty-Scans', 'http://dynasty-scans.com') ); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index eb8b9e63f..7454f6906 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1123,8 +1123,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/ReadMangaToday/names_and_links.inc} - {$I includes/LoneManga/names_and_links.inc} - {$I includes/Dynasty-Scans/names_and_links.inc} begin @@ -1331,9 +1329,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = READMANGATODAY_ID then Result := ReadMangaTodayGetNamesAndLinks else - if WebsiteID = LONEMANGA_ID then - Result := LoneMangaGetNamesAndLinks - else if WebsiteID = DYNASTYSCANS_ID then Result := DynastyScansGetNamesAndLinks else @@ -1477,8 +1472,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/ReadMangaToday/manga_information.inc} - {$I includes/LoneManga/manga_information.inc} - {$I includes/Dynasty-Scans/manga_information.inc} begin @@ -1696,9 +1689,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = READMANGATODAY_ID then Result := GetReadMangaTodayInfoFromURL else - if WebsiteID = LONEMANGA_ID then - Result := GetLoneMangaInfoFromURL - else if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a07063ecf..2e66efaf7 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -469,8 +469,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/ReadMangaToday/chapter_page_number.inc} - {$I includes/LoneManga/chapter_page_number.inc} - {$I includes/Dynasty-Scans/chapter_page_number.inc} begin @@ -629,9 +627,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = READMANGATODAY_ID then Result := GetReadMangaTodayPageNumber else - if manager.container.MangaSiteID = LONEMANGA_ID then - Result := GetLoneMangaPageNumber - else if manager.container.MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansPageNumber; end; diff --git a/config/mangalist.ini b/config/mangalist.ini index ab342cc8e..48e0908fb 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,LoneManga,Madokami,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,Madokami,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 22973fa1d35dc0cbc6f67b99d3c032c3e39cadbc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Feb 2016 23:47:59 +0800 Subject: [PATCH 0978/2794] Bump version 0.9.35.2 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9daf8d4dc..9d2010fe7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.35.2 (25-02-2016) +[*] GameofScanlation: rewrite all script +[-] LoneManga: removed, website redirected to GameofScanlation +[*] Various changes and bug fixes + 0.9.35.1 (21-02-2016) [*] Updater: fix download manga list from server diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9c0bc2850..7ddd2dccc 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -19,7 +19,7 @@ <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> <RevisionNr Value="35"/> - <BuildNr Value="1"/> + <BuildNr Value="2"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 81bb3f51f..a3c57fb41 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.35.1 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.35.1/fmd_0.9.35.1.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.35.1/fmd_0.9.35.1_Win64.7z +VERSION=0.9.35.2 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.35.2/fmd_0.9.35.2.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.35.2/fmd_0.9.35.2_Win64.7z From 873bac41f34f7112532e960eaff0be8eeca39081 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 27 Feb 2016 01:12:30 +0800 Subject: [PATCH 0979/2794] added tsumino #196, require cookie --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Tsumino.pas | 141 ++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/Tsumino.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ae018255b..a6fcae545 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -27,4 +27,5 @@ uses MangaChanRU, MintMangaRU, AcademyVN, - Webtoons; + Webtoons, + Tsumino; diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas new file mode 100644 index 000000000..a4bfc1c6a --- /dev/null +++ b/baseunits/modules/Tsumino.pas @@ -0,0 +1,141 @@ +unit Tsumino; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + synautil; + +implementation + +const + dirurl='/Browse/Index/1/'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result:=NET_PROBLEM; + Page:=1; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl+'10000000') then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + page:=StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'),1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL; + if AURL<>'0' then s:=s+dirurl+IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="row row-no-padding"]//div[@class="overlay"]') do begin + ALinks.Add(XPathString('a/@href',v.toNode)); + ANames.Add(XPathString('div/div[@class="overlay-title"]',v.toNode)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + i: Integer; + s: String; + v: IXQValue; +const + g: array[0..2] of String = ('Parody','Characters','Tags'); +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + url:=FillHost(Module.RootURL,AURL); + if GET(url) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink:=XPathString('//img[@class="book-page-image img-responsive"]/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=XPathString('//div[@class="book-line"][starts-with(.,"Title")]/div[@class="book-data"]'); + artists:=XPathString('//div[@class="book-line"][starts-with(.,"Artist")]/div[@class="book-data"]'); + genres:=''; + for i:=Low(g) to High(g) do + for v in XPath('//div[@class="book-line"][starts-with(.,"'+g[i]+'")]/div[@class="book-data"]/*') do + AddCommaString(genres,v.toString); + if title<>'' then begin + chapterLinks.Add(url); + chapterName.Add(title); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@class="no-border book-grid-item"]/a/img/@data-original') do begin + s:=Trim(v.toString); + if s<>'' then begin + s:=StringReplace(s,'/Thumb/','/Image/',[rfIgnoreCase]); + PageLinks.Add(MaybeFillHost(Module.RootURL,s)); + end; + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='Tsumino'; + RootURL:='http://www.tsumino.com'; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + SortedList:=True; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 48e0908fb..c99020463 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -19,4 +19,4 @@ Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D From ae386b93b9f3c2c539cfa89c2ddf17798d0c44d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 27 Feb 2016 01:40:50 +0800 Subject: [PATCH 0980/2794] Bump version 0.9.36.0 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 3 +-- update | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9d2010fe7..92586b929 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,9 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.36.0 (27-02-2016) +[+] Added Tsumino[H], require cookie in advanced.ini + 0.9.35.2 (25-02-2016) [*] GameofScanlation: rewrite all script [-] LoneManga: removed, website redirected to GameofScanlation diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 7ddd2dccc..00b006455 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,8 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="35"/> - <BuildNr Value="2"/> + <RevisionNr Value="36"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index a3c57fb41..b8d0ebac3 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.35.2 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.35.2/fmd_0.9.35.2.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.35.2/fmd_0.9.35.2_Win64.7z +VERSION=0.9.36.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.36.0/fmd_0.9.36.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.36.0/fmd_0.9.36.0_Win64.7z From 2467bced4c32f51bb49c970092826d9514329a6c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 08:39:24 +0800 Subject: [PATCH 0981/2794] madokami, cleanup --- baseunits/modules/Madokami.pas | 69 +++++++++++++++------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index ea0574b80..5b8f512cc 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -31,7 +31,6 @@ implementation var locklogin: TRTLCriticalSection; - onlogin: Boolean = False; function Login(const AHTTP: THTTPSendThread): Boolean; begin @@ -40,7 +39,6 @@ function Login(const AHTTP: THTTPSendThread): Boolean; if Account.Username[modulename] = '' then Exit; if TryEnterCriticalsection(locklogin) > 0 then try - onlogin := True; Account.Status[modulename] := asChecking; AHTTP.Reset; AHTTP.Cookies.Clear; @@ -60,15 +58,18 @@ function Login(const AHTTP: THTTPSendThread): Boolean; Account.Save; end; finally - onlogin := False; LeaveCriticalsection(locklogin); end - else - while onlogin do Sleep(1000); - AHTTP.Reset; - if Result then begin - AHTTP.Cookies.Text := Account.Cookies[modulename]; + else begin + EnterCriticalsection(locklogin); + try + if Result then + AHTTP.Cookies.Text:=Account.Cookies[modulename]; + finally + LeaveCriticalsection(locklogin); + end; end; + AHTTP.Reset; end; function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; @@ -95,7 +96,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; currentdir: Integer; s: String; @@ -106,28 +106,26 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if currentdir>Length(madokamidirlist) then Exit; if MangaInfo.FHTTP.GET(Module.RootURL+madokamidirlist[currentdir]) then begin Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - s:=v.toString; - if Length(s)>1 then - if s[Length(s)]='/' then - SetLength(s,Length(s)-1); - ANames.Add(s); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + s:=v.toString; + if Length(s)>1 then + if s[Length(s)]='/' then + SetLength(s,Length(s)-1); + ANames.Add(s); + end; + finally + Free; end; - finally - query.Free; - end; end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; i: Integer; begin @@ -135,10 +133,8 @@ function GetInfo(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - with MangaInfo.mangaInfo, query do begin + with MangaInfo.mangaInfo,TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try coverLink := XPathString('//img[@itemprop="image"]/@src'); if title = '' then title := XPathString('//*[@class="title"]'); authors := XPathString('//*[@itemprop="author"]'); @@ -161,34 +157,31 @@ function GetInfo(const MangaInfo: TMangaInformation; finally Free; end; + finally + Free; end; - finally - query.Free; - end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; datapath, datafiles: String; i: Integer; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.manager.container do begin PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin Result := True; - query := TXQueryEngineHTML.Create; + with TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document) do try - query.ParseHTML(StreamToString(Document)); - datapath := query.XPathString('//div[@id="reader"]/@data-path'); + datapath := XPathString('//div[@id="reader"]/@data-path'); datapath := EncodeURLElement(datapath); - datafiles := query.XPathString('//div[@id="reader"]/@data-files'); + datafiles := XPathString('//div[@id="reader"]/@data-files'); datafiles := Trim(TrimChar(datafiles, ['[', ']'])); datafiles := JSONStringToString(datafiles); PageLinks.Delimiter := ','; @@ -198,7 +191,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageLinks[i] := Module.RootURL + '/reader/image?path=' + datapath + '&file=' + EncodeURLElement(PageLinks[i]); finally - query.Free; + Free; end; end; end; From a521e38a84097a4a78d9aa2a0a0fb1158205d9b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 08:57:05 +0800 Subject: [PATCH 0982/2794] batoto, cleanup --- baseunits/modules/Batoto.pas | 141 ++++++++++++++++------------------- 1 file changed, 65 insertions(+), 76 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 6efe1792e..6a257700b 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -22,7 +22,6 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; var locklogin: TRTLCriticalSection; - onlogin: Boolean = False; function Login(const AHTTP: THTTPSendThread): Boolean; var @@ -37,16 +36,14 @@ function Login(const AHTTP: THTTPSendThread): Boolean; if TryEnterCriticalsection(locklogin) > 0 then with AHTTP do begin - onlogin := True; Account.Status[modulename] := asChecking; Reset; Cookies.Clear; Writelog_V('Batoto, login: get login form'); if GET(urlroot) then begin loginform := THTMLForm.Create; - query := TXQueryEngineHTML.Create; + query := TXQueryEngineHTML.Create(Document); try - query.ParseHTML(StreamToString(Document)); key := query.XPathString('//input[@name="auth_key"]/@value'); if key <> '' then begin with loginform do begin @@ -83,15 +80,19 @@ function Login(const AHTTP: THTTPSendThread): Boolean; loginform.Free end; end; - onlogin := False; if Account.Status[modulename] = asChecking then Account.Status[modulename] := asUnknown; LeaveCriticalsection(locklogin); end else begin - while onlogin do Sleep(1000); - if Result then AHTTP.Cookies.Text := Account.Cookies[modulename]; + EnterCriticalsection(locklogin); + try + if Result then + AHTTP.Cookies.Text:=Account.Cookies[modulename]; + finally + LeaveCriticalsection(locklogin); + end; end; end; @@ -128,7 +129,6 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String): Boolean function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; s: String; begin Result:=NET_PROBLEM; @@ -136,15 +136,15 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if MangaInfo =nil then Exit(UNKNOWN_ERROR); if MangaInfo.FHTTP.GET(Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=Trim(query.XPathString('//ul[@class="ipsList_inline left pages"]/li/a')); - if s<>'' then - Page:=StrToIntDef(Trim(SeparateRight(LowerCase(s),'page 1 of ')),1); - finally - query.Free; - end; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); + s:=Trim(XPathString('//ul[@class="ipsList_inline left pages"]/li/a')); + if s<>'' then + Page:=StrToIntDef(Trim(SeparateRight(LowerCase(s),'page 1 of ')),1); + finally + Free; + end; end; end; @@ -152,7 +152,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; s: String; begin @@ -162,43 +161,38 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if AURL<>'0' then s+='&st='+IntToStr(StrToInt(AURL)*perpage); if MangaInfo.FHTTP.GET(s) then begin Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@class="ipb_table topic_list hover_rows"]/tbody/tr/td/h4/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//table[@class="ipb_table topic_list hover_rows"]/tbody/tr/td/h4/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - query.Free; - end; end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v, w: IXQValue; s, t, l: String; i: Integer; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - with MangaInfo do begin - mangaInfo.website := modulename; - mangaInfo.url := FillHost(urlroot, AURL); - while onlogin do Sleep(1000); - if GETWithLogin(FHTTP, mangaInfo.url) then begin + with MangaInfo.mangaInfo do begin + website := modulename; + url := FillHost(urlroot, AURL); + if GETWithLogin(MangaInfo.FHTTP,url) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(FHTTP.Document)); - with mangaInfo do begin - coverLink := Query.XPathString('//div[@class="ipsBox"]//img/@src'); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + coverLink := XPathString('//div[@class="ipsBox"]//img/@src'); if title = '' then - title := Query.XPathString('//h1[@class="ipsType_pagetitle"]'); - for v in query.XPath('//table[@class="ipb_table"]//tr') do begin + title := XPathString('//h1[@class="ipsType_pagetitle"]'); + for v in XPath('//table[@class="ipb_table"]//tr') do begin s := v.toString; if Pos('Author:', s) > 0 then authors:= GetRightValue('Author:', s) else if Pos('Artist:', s) > 0 then artists:= GetRightValue('Artist:', s) @@ -208,7 +202,7 @@ function GetInfo(const MangaInfo: TMangaInformation; else status := '0'; end; end; - v := query.XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); + v := XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); if v.Count > 0 then begin genres := ''; for i := 1 to v.Count do AddCommaString(genres, v.get(i).toString); @@ -217,25 +211,24 @@ function GetInfo(const MangaInfo: TMangaInformation; if OptionBatotoShowAllLang then s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]' else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]'; - for v in query.XPath(s) do begin - w := query.XPath('td[1]/a', v.toNode); + for v in XPath(s) do begin + w := XPath('td[1]/a', v.toNode); chapterLinks.Add(w.toNode.getAttribute('href')); t := w.toString; if OptionBatotoShowAllLang then begin - l := query.XPath('td[2]/div', v.toNode).toNode.getAttribute('title'); + l := XPath('td[2]/div', v.toNode).toNode.getAttribute('title'); if l <> '' then t += ' ['+ l +']'; end; if OptionBatotoShowScanGroup then begin - l := query.XPath('td[3]', v.toNode).toString; + l := XPath('td[3]', v.toNode).toString; if l <> '' then t += ' ['+ l +']'; end; chapterName.Add(t); end; - InvertStrings([chapterLinks, chapterName]) + InvertStrings([chapterLinks, chapterName]); + finally + Free; end; - finally - query.Free; - end; end else Result := INFORMATION_NOT_FOUND; end; end; @@ -243,7 +236,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; v: IXQValue; cid, s: String; begin @@ -254,26 +246,25 @@ function GetPageNumber(const DownloadThread: TDownloadThread; cid := SeparateRight(AURL, '/reader#'); if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageContainerLinks.Text := cid; - if query.XPathString('//select[@id="page_select"]') <> '' then begin - PageNumber := Query.XPath('(//select[@id="page_select"])[1]/option/@value').Count; - if PageNumber>0 then begin - s:=query.XPathString('//div[@id="full_image"]//img/@src'); - if s<>'' then PageLinks.Add(s) + with TXQueryEngineHTML.Create(Document) do + try + PageContainerLinks.Text := cid; + if XPathString('//select[@id="page_select"]') <> '' then begin + PageNumber := XPath('(//select[@id="page_select"])[1]/option/@value').Count; + if PageNumber>0 then begin + s:=XPathString('//div[@id="full_image"]//img/@src'); + if s<>'' then PageLinks.Add(s) + end; + end + else begin + // long-strip view + PageLinks.Clear; + for v in XPath('//div/img/@src') do + PageLinks.Add(v.toString); end; - end - else begin - // long-strip view - PageLinks.Clear; - for v in query.XPath('//div/img/@src') do - PageLinks.Add(v.toString); + finally + Free; end; - finally - query.Free; - end; end; end; end; @@ -281,7 +272,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; rurl: String; begin Result := False; @@ -292,13 +282,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; if GET(rurl) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@id="full_image"]//img/@src'); - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := XPathString('//div[@id="full_image"]//img/@src'); + finally + Free; + end; end; end; end; From 6003e20873eb232b8fef9357654a16ccf1de0d5c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 09:08:49 +0800 Subject: [PATCH 0983/2794] madokami, fix empty title --- baseunits/modules/Madokami.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 5b8f512cc..29640de09 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -137,6 +137,7 @@ function GetInfo(const MangaInfo: TMangaInformation; try coverLink := XPathString('//img[@itemprop="image"]/@src'); if title = '' then title := XPathString('//*[@class="title"]'); + if title = '' then title := XPathString('(//h1//span[@itemprop="title"])[last()]'); authors := XPathString('//*[@itemprop="author"]'); v := XPath('//div[@class="genres"]/a'); if v.Count > 0 then begin From 4299417db7dbecdc41282ef1e62a38f78285b219 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 09:29:45 +0800 Subject: [PATCH 0984/2794] udata, remove leading - after remove chapter name --- baseunits/uData.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 7454f6906..024f7b80d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1779,7 +1779,10 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if Pos(s, s2) = 1 then begin s2 := chapterName[k]; Delete(s2, 1, j); - chapterName[k] := Trim(s2); + s2:=Trim(s2); + if LeftStr(s2,2)='- ' then + Delete(s2,1,2); + chapterName[k] := s2; end; end; end; From b107efe09a697f47ac9ca260a9c64e99cc657852 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 09:42:40 +0800 Subject: [PATCH 0985/2794] madokami, fix login #198 --- baseunits/modules/Madokami.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 29640de09..d2096725e 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -46,7 +46,8 @@ function Login(const AHTTP: THTTPSendThread): Boolean; ' Basic ' + Base64Encode(Account.Username[modulename] + ':' + Account.Password[modulename]); if AHTTP.GET(urlroot + '/login') then begin - Result := AHTTP.Cookies.Values['laravel_session'] <> ''; + //Result := AHTTP.Cookies.Values['laravel_session'] <> ''; + Result:=(AHTTP.ResultCode<400) and (AHTTP.Headers.Values['WWW-Authenticate']=''); if Result then begin Account.Cookies[modulename] := AHTTP.GetCookies; Account.Status[modulename] := asValid; From f48632ab20f7530c2a30d3291ca1b5eb9975f296 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 09:58:03 +0800 Subject: [PATCH 0986/2794] added show password on add account only --- mangadownloader/forms/frmAccountManager.pas | 1 + mangadownloader/forms/frmAccountSet.lfm | 17 +++++++++++++---- mangadownloader/forms/frmAccountSet.pas | 10 ++++++++++ mangadownloader/languages/fmd.en.po | 11 +++++------ mangadownloader/languages/fmd.id_ID.po | 11 +++++------ mangadownloader/languages/fmd.po | 8 ++++---- 6 files changed, 38 insertions(+), 20 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 9d7313f67..e5296ef61 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -421,6 +421,7 @@ procedure TAccountManagerForm.btAddClick(Sender: TObject); cbWebsiteName.Items.Assign(WebsitesAvailable); if cbWebsiteName.Items.Count > 0 then cbWebsiteName.ItemIndex := 0; + ckShowPassword.Visible:=True; if ShowModal = mrOK then if Account.AddAccount(cbWebsiteName.Text, edUsername.Text, edPassword.Text) then begin diff --git a/mangadownloader/forms/frmAccountSet.lfm b/mangadownloader/forms/frmAccountSet.lfm index 6ebf27740..5f282ea17 100644 --- a/mangadownloader/forms/frmAccountSet.lfm +++ b/mangadownloader/forms/frmAccountSet.lfm @@ -1,16 +1,15 @@ object AccountSetForm: TAccountSetForm Left = 0 - Height = 224 + Height = 234 Top = 0 Width = 269 ActiveControl = cbWebsiteName Caption = 'Account' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 - ClientHeight = 224 + ClientHeight = 234 ClientWidth = 269 Position = poMainFormCenter - LCLVersion = '1.7' Visible = False object cbWebsiteName: TComboBox Left = 8 @@ -77,7 +76,7 @@ object AccountSetForm: TAccountSetForm object pnButtons: TPanel Left = 8 Height = 26 - Top = 190 + Top = 200 Width = 253 Align = alBottom AutoSize = True @@ -183,4 +182,14 @@ object AccountSetForm: TAccountSetForm TabOrder = 1 end end + object ckShowPassword: TCheckBox + Left = 8 + Height = 19 + Top = 176 + Width = 102 + Caption = 'Show password' + OnChange = ckShowPasswordChange + TabOrder = 4 + Visible = False + end end diff --git a/mangadownloader/forms/frmAccountSet.pas b/mangadownloader/forms/frmAccountSet.pas index 3119bddad..81838463c 100644 --- a/mangadownloader/forms/frmAccountSet.pas +++ b/mangadownloader/forms/frmAccountSet.pas @@ -16,6 +16,7 @@ TAccountSetForm = class(TForm) btOk: TBitBtn; btCancel: TBitBtn; cbWebsiteName: TComboBox; + ckShowPassword: TCheckBox; edUsername: TEdit; edPassword: TEdit; Label1: TLabel; @@ -23,6 +24,7 @@ TAccountSetForm = class(TForm) Label3: TLabel; pnButtons: TPanel; procedure btOkClick(Sender: TObject); + procedure ckShowPasswordChange(Sender: TObject); private { private declarations } public @@ -52,5 +54,13 @@ procedure TAccountSetForm.btOkClick(Sender: TObject); ModalResult := mrOK; end; +procedure TAccountSetForm.ckShowPasswordChange(Sender: TObject); +begin + if ckShowPassword.Checked then + edPassword.PasswordChar:=#0 + else + edPassword.PasswordChar:='*'; +end; + end. diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 79f97bbe4..6083ee8ef 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_US\n" -"X-Generator: Poedit 1.8.2\n" +"X-Generator: Poedit 1.8.7\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: frmaccountmanager.rs_accountdeleteconfirmation @@ -293,10 +293,6 @@ msgstr "Edit" msgid "Refresh" msgstr "Refresh" -#: taccountmanagerform.caption -msgid "AccountManagerForm" -msgstr "AccountManagerForm" - #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -324,6 +320,10 @@ msgstr "Cancel" msgid "Ok" msgstr "Ok" +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Show password" + #: taccountsetform.edpassword.texthint msgctxt "taccountsetform.edpassword.texthint" msgid "Password" @@ -1829,4 +1829,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 336127bdd..efc36306a 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.8.2\n" +"X-Generator: Poedit 1.8.7\n" "Plural-Forms: nplurals=1; plural=0;\n" #: frmaccountmanager.rs_accountdeleteconfirmation @@ -292,10 +292,6 @@ msgstr "Ubah" msgid "Refresh" msgstr "Segarkan" -#: taccountmanagerform.caption -msgid "AccountManagerForm" -msgstr "AccountManagerForm" - #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" @@ -320,6 +316,10 @@ msgstr "Batal" msgid "Ok" msgstr "Ok" +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Tampilkan kata kunci" + #: taccountsetform.edpassword.texthint msgctxt "taccountsetform.edpassword.texthint" msgid "Password" @@ -1813,4 +1813,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 9282750fa..dfa351f08 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -264,10 +264,6 @@ msgstr "" msgid "Refresh" msgstr "" -#: taccountmanagerform.caption -msgid "AccountManagerForm" -msgstr "" - #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" @@ -292,6 +288,10 @@ msgstr "" msgid "Ok" msgstr "" +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "" + #: taccountsetform.edpassword.texthint msgctxt "TACCOUNTSETFORM.EDPASSWORD.TEXTHINT" msgid "Password" From 3c7b7697192436691b581b4beb11dcc5694af76c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 14:27:38 +0800 Subject: [PATCH 0987/2794] frmmain, changed open folder and open file icon --- mangadownloader/forms/frmMain.lfm | 168 +++++++++++++++---------- mangadownloader/languages/fmd.en.po | 6 +- mangadownloader/languages/fmd.id_ID.po | 6 +- mangadownloader/languages/fmd.po | 5 - 4 files changed, 104 insertions(+), 81 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index dcaab7b1d..5d719efff 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -555,39 +555,39 @@ object MainForm: TMainForm Anchors = [akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 } OnClick = btBrowseClick end @@ -1970,6 +1970,42 @@ object MainForm: TMainForm FilterIndex = 0 HideDirectories = False ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C005884950000001F0000 + 001A0000001A0000001A0000001A0000001A0000001A00000011000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0075477E225250A932B2B + 0C8A2D2D0D872D2D0D872D2D0D872D2D0D872D2D0D8723230B6A000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF4186A8FFE5E5E5FFE5E5 + E4FFFEFEFDFFFEFEFCFFFDFDFAFFFCFCF9FFFEFEF9FF3B3B1B88000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF4489ACFFE4E4E4FFE3E3 + E2FFFCFCFBFFFBFBF8FFFAFAF6FFF8F8F4FFFBFBF5FF4F4F2C7D000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF468BAFFFE3E3E2FFE2E2 + E1FFFBFBF8FFFAFAF6FFF8F8F4FFF7F7F1FFFAFAF4FF58583276005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF488FB2FFE2E2E1FFE1E1 + DFFFFAFAF6FFF8F8F4FFF7F7F1FFF5F5EFFFFAFAF2FF5D5D37740076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF4C92B6FFE1E1DFFFE1E1 + DDFFF8F8F4FFF7F7F1FFF5F5EFFFF4F4ECFFF8F8EEFF62623C720078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF4F96B8FFE1E1DDFFDFDF + DBFFF7F7F1FFF5F5EFFFF4F4ECFFF0F0E6FFF6F6E8FF67674070007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF5299BCFFDFDFDBFFDEDE + D9FFF5F5EFFFF4F4ECFFF0F0E6FFEBEBDDFFF3F3E3FF6C6C446E007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF569CBFFFDEDED9FFDCDC + D7FFF4F4ECFFF0F0E6FFEBEBDDFFE7E7D6FFF2F2E1FF7171486C007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF589FC2FFDCDCD7FFDBDB + D4FFF0F0E6FFEBEBDDFFA4A493FFA4A493FFA4A493FF4949257C0082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF62A8C9FFDBDBD4FFD8D8 + CFFFEBEBDDFFE7E7D6FFB6B6A5FFFFFFFFFF79795069797950250084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF6DAFCDFFEDEDE4FFF4F4 + E7FFF4F4E3FFF2F2E1FFC2C2B1FF467F85B87C7C5225797950000085C8000085 + C8000085C885ADF1FFFFABEFFEFF94E2F8FF6EC8EDFF4397B9FF8EB7BAFF8EB7 + BAFF8EB7BAFF8EB7BAFF93BCBBFF1B84B0963E818E003D7F8C000087CA000087 + CA000087CA8388DBF4FF60C1E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } NumGlyphs = 1 Anchors = [akTop, akLeft, akRight] MaxLength = 0 @@ -2562,39 +2598,39 @@ object MainForm: TMainForm Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 } OnClick = btOptionBrowseClick end diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6083ee8ef..d71fb0a7d 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -458,11 +458,6 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" @@ -1829,3 +1824,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index efc36306a..d17f7269d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -450,11 +450,6 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" @@ -1813,3 +1808,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index dfa351f08..a3532ff1f 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -422,11 +422,6 @@ msgstr "" msgid "Visit my blog" msgstr "" -#: tmainform.caption -msgctxt "TMAINFORM.CAPTION" -msgid "Free Manga Downloader" -msgstr "" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From 2c7995f3596ca622127a14e0c8eb53f94abebb33 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 16:01:18 +0800 Subject: [PATCH 0988/2794] removed submanga's old code #199 --- .../includes/SubManga/chapter_page_number.inc | 54 ------- baseunits/includes/SubManga/image_url.inc | 30 ---- .../includes/SubManga/manga_information.inc | 133 ------------------ .../includes/SubManga/names_and_links.inc | 37 ----- baseunits/uBaseUnit.pas | 119 ++++++++-------- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 13 -- 7 files changed, 57 insertions(+), 339 deletions(-) delete mode 100644 baseunits/includes/SubManga/chapter_page_number.inc delete mode 100644 baseunits/includes/SubManga/image_url.inc delete mode 100644 baseunits/includes/SubManga/manga_information.inc delete mode 100644 baseunits/includes/SubManga/names_and_links.inc diff --git a/baseunits/includes/SubManga/chapter_page_number.inc b/baseunits/includes/SubManga/chapter_page_number.inc deleted file mode 100644 index 087d81066..000000000 --- a/baseunits/includes/SubManga/chapter_page_number.inc +++ /dev/null @@ -1,54 +0,0 @@ - function GetSubMangaPageNumber: Boolean; - var - surl: String; - i: Integer; - l: TStringList; - nextPage: Boolean = True; - pageNum: Cardinal; - begin - pageNum := 1; - surl := FillMangaSiteHost(SUBMANGA_ID, URL); - l := TStringList.Create; - parse := TStringList.Create; - try - manager.container.PageLinks.Clear; - while nextPage do - begin - nextPage := False; - l.Clear; - parse.Clear; - Result := GetPage(TObject(l), surl, manager.container.manager.retryConnect); - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (not nextPage) and - ((GetTagName(parse[i]) = 'a') and - (GetTagName(parse[i + 1]) = 'span') and - (GetVal(parse[i + 1], 'class') = 'glyphicon glyphicon-chevron-right')) then - if Pos('/c/', GetVal(parse[i], 'href')) <> 0 then - begin - nextPage := True; - Inc(pageNum); - surl := FillMangaSiteHost(SUBMANGA_ID, URL) + '/' + IntToStr(pageNum); - end; - if GetTagName(parse[i]) = 'img' then - begin - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); - Break; - end; - end; - end; - finally - parse.Free; - l.Free; - end; - manager.container.PageNumber := manager.container.PageLinks.Count; - end; diff --git a/baseunits/includes/SubManga/image_url.inc b/baseunits/includes/SubManga/image_url.inc deleted file mode 100644 index db8e56c9a..000000000 --- a/baseunits/includes/SubManga/image_url.inc +++ /dev/null @@ -1,30 +0,0 @@ - function GetSubMangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(SUBMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if GetTagName(parse[i]) = 'img' then - begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/SubManga/manga_information.inc b/baseunits/includes/SubManga/manga_information.inc deleted file mode 100644 index 2a676bd4e..000000000 --- a/baseunits/includes/SubManga/manga_information.inc +++ /dev/null @@ -1,133 +0,0 @@ - function GetSubMangaInfoFromURL: Byte; - var - s: String; - i, j: Integer; - isGetChapters: Boolean = False; - begin - mangaInfo.url := FillMangaSiteHost(SUBMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[SUBMANGA_ID, 0]; - - mangaInfo.genres := ''; - mangaInfo.status := '1'; - - // using 1st parser (cover link, summary) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('content="Leer ', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i], 'content="Leer ', ' manga online'); - - if Pos('class="suscripcion', parse[i]) > 0 then - begin - // get cover link - if Pos('<img', parse[i + 5]) > 0 then - mangaInfo.coverLink := - GetVal(parse[i + 5], 'src'); - // get summary - j := i + 8; - while (j < parse.Count - 1) and (Pos('</p>', parse[j]) = 0) do - begin - Inc(j); - s := parse[j]; - if (s <> '') and - (s[1] <> '<') then - begin - parse[j] := StringFilter(parse[j]); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - end; - end; - - // get authors/artists - if (Pos('Creado por', parse[i]) <> 0) then - begin - if Pos('/autor/', parse[i + 1]) > 0 then - mangaInfo.authors := parse[i + 2]; - if Pos('/mangaka/', parse[i + 5]) > 0 then - mangaInfo.authors := parse[i + 6]; - end; - - // get genres - if (Pos('submanga.com/genero/', parse[i]) <> 0) then - mangaInfo.genres := mangaInfo.genres + parse[i + 1] + ', '; - end; - - // get chapters - Source.Clear; - if not GetPage(TObject(Source), mangaInfo.url + '/completa', Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - // get chapters - if (GetTagName(parse[i]) = 'table') and - (GetVal(parse[i], 'class') = 'table table-striped table-hover') then - isGetChapters := True; - if isGetChapters and (GetTagName(parse[i]) = '/table') then - Break; - if isGetChapters and - ((GetTagName(parse[i]) = 'a') and (GetTagName(parse[i - 1]) = 'td') and - (GetTagName(parse[i - 2]) = 'tr')) then - if Length(GetVal(parse[i], 'href')) > 3 then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterName.Add(CommonStringFilter( - Trim(parse[i + 1]) + ' ' + Trim(parse[i + 3]))); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - end; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - // replace urls - with TRegExpr.Create do - try - Expression := '^.*(/\d+)$'; - for i := 0 to mangaInfo.chapterLinks.Count - 1 do - mangaInfo.chapterLinks[i] := Replace(mangaInfo.chapterLinks[i], '/c/$1', True); - finally - Free; - end; - Result := NO_ERROR; - end; - end; diff --git a/baseunits/includes/SubManga/names_and_links.inc b/baseunits/includes/SubManga/names_and_links.inc deleted file mode 100644 index 2054011c4..000000000 --- a/baseunits/includes/SubManga/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function SubMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SUBMANGA_ID, 1] + - SUBMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="xs"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i - 1], 'href'); - links.Add(StringReplace(s, WebsiteRoots[SUBMANGA_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d76342166..fdf1927bb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -285,65 +285,63 @@ interface STARKANA_ID = 17; BLOGTRUYEN_ID = 18; KOMIKID_ID = 19; - SUBMANGA_ID = 20; - ESMANGAHERE_ID = 21; - ANIMEEXTREMIST_ID = 22; - HUGEMANGA_ID = 23; - S2SCAN_ID = 24; - SENMANGA_ID = 25; - IMANHUA_ID = 26; - MABUNS_ID = 27; - MANGAESTA_ID = 28; - CENTRALDEMANGAS_ID = 29; - EGSCANS_ID = 30; - MANGAAR_ID = 31; - MANGAAE_ID = 32; - ANIMESTORY_ID = 33; - LECTUREENLIGNE_ID = 34; - SCANMANGA_ID = 35; - MANGAGO_ID = 36; - DM5_ID = 37; - MANGACOW_ID = 38; - KIVMANGA_ID = 39; - MEINMANGA_ID = 40; - MANGASPROJECT_ID = 41; - MANGAREADER_POR_ID = 42; - NINEMANGA_ID = 43; - NINEMANGA_ES_ID = 44; - NINEMANGA_CN_ID = 45; - NINEMANGA_RU_ID = 46; - NINEMANGA_DE_ID = 47; - NINEMANGA_IT_ID = 48; - NINEMANGA_BR_ID = 49; - JAPANSHIN_ID = 50; - JAPSCAN_ID = 51; - CENTRUMMANGI_PL_ID = 52; - MANGALIB_PL_ID = 53; - ONEMANGA_ID = 54; - MANGATOWN_ID = 55; - MANGAOKU_ID = 56; - MYREADINGMANGAINFO_ID = 57; - IKOMIK_ID = 58; - NHENTAI_ID = 59; - MANGAMINT_ID = 60; - UNIXMANGA_ID = 61; - - EXTREMEMANGAS_ID = 62; - MANGAHOST_ID = 63; - PORNCOMIX_ID = 64; - PORNCOMIXRE_ID = 65; - PORNCOMIXIC_ID = 66; - XXCOMICS_ID = 67; - XXCOMICSMT_ID = 68; - XXCOMICS3D_ID = 69; - PORNXXXCOMICS_ID = 70; - MANGASEE_ID = 71; - MANGAKU_ID = 72; - MANGAAT_ID = 73; - READMANGATODAY_ID = 74; - DYNASTYSCANS_ID = 75; - - WebsiteRoots: array [0..75] of array [0..1] of string = ( + ESMANGAHERE_ID = 20; + ANIMEEXTREMIST_ID = 21; + HUGEMANGA_ID = 22; + S2SCAN_ID = 23; + SENMANGA_ID = 24; + IMANHUA_ID = 25; + MABUNS_ID = 26; + MANGAESTA_ID = 27; + CENTRALDEMANGAS_ID = 28; + EGSCANS_ID = 29; + MANGAAR_ID = 30; + MANGAAE_ID = 31; + ANIMESTORY_ID = 32; + LECTUREENLIGNE_ID = 33; + SCANMANGA_ID = 34; + MANGAGO_ID = 35; + DM5_ID = 36; + MANGACOW_ID = 37; + KIVMANGA_ID = 38; + MEINMANGA_ID = 39; + MANGASPROJECT_ID = 40; + MANGAREADER_POR_ID = 41; + NINEMANGA_ID = 42; + NINEMANGA_ES_ID = 43; + NINEMANGA_CN_ID = 44; + NINEMANGA_RU_ID = 45; + NINEMANGA_DE_ID = 46; + NINEMANGA_IT_ID = 47; + NINEMANGA_BR_ID = 48; + JAPANSHIN_ID = 49; + JAPSCAN_ID = 50; + CENTRUMMANGI_PL_ID = 51; + MANGALIB_PL_ID = 52; + ONEMANGA_ID = 53; + MANGATOWN_ID = 54; + MANGAOKU_ID = 55; + MYREADINGMANGAINFO_ID = 56; + IKOMIK_ID = 57; + NHENTAI_ID = 58; + MANGAMINT_ID = 59; + UNIXMANGA_ID = 60; + EXTREMEMANGAS_ID = 61; + MANGAHOST_ID = 62; + PORNCOMIX_ID = 63; + PORNCOMIXRE_ID = 64; + PORNCOMIXIC_ID = 65; + XXCOMICS_ID = 66; + XXCOMICSMT_ID = 67; + XXCOMICS3D_ID = 68; + PORNXXXCOMICS_ID = 69; + MANGASEE_ID = 70; + MANGAKU_ID = 71; + MANGAAT_ID = 72; + READMANGATODAY_ID = 73; + DYNASTYSCANS_ID = 74; + + WebsiteRoots: array [0..74] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -364,7 +362,6 @@ interface ('Starkana', 'http://starkana.jp'), ('BlogTruyen', 'http://blogtruyen.com'), ('Komikid', 'http://www.komikid.com'), - ('SubManga', 'http://submanga.com'), ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), ('HugeManga', 'http://hugemanga.com'), @@ -472,8 +469,6 @@ interface KOMIKID_BROWSER = '/daftar.php'; - SUBMANGA_BROWSER = '/series/n'; - ESMANGAHERE_BROWSER = '/mangalist/'; ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 024f7b80d..03040290c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1027,8 +1027,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/TruyenTranhTuan/names_and_links.inc} - {$I includes/SubManga/names_and_links.inc} - {$I includes/Komikid/names_and_links.inc} {$I includes/Mabuns/names_and_links.inc} @@ -1191,9 +1189,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = TRUYENTRANHTUAN_ID then Result := TruyenTranhTuanGetNamesAndLinks else - if WebsiteID = SUBMANGA_ID then - Result := SubMangaGetNamesAndLinks - else if WebsiteID = ESMANGAHERE_ID then Result := EsMangaHereGetNamesAndLinks else @@ -1358,8 +1353,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; // due to its weird designs, this will take a lot of work (and time) for it to // work property - {$I includes/SubManga/manga_information.inc} - {$I includes/EsMangaHere/manga_information.inc} {$I includes/AnimExtremist/manga_information.inc} @@ -1551,9 +1544,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MEINMANGA_ID then Result := GetMeinMangaInfoFromURL else - if WebsiteID = SUBMANGA_ID then - Result := GetSubMangaInfoFromURL - else if WebsiteID = ESMANGAHERE_ID then Result := GetEsMangaHereInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2e66efaf7..50c5f2ddc 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -421,8 +421,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Starkana/chapter_page_number.inc} - {$I includes/SubManga/chapter_page_number.inc} - {$I includes/Turkcraft/chapter_page_number.inc} {$I includes/AnimeA/chapter_page_number.inc} @@ -509,9 +507,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = ESMANGAHERE_ID then Result := GetEsMangaHerePageNumber else - if manager.container.MangaSiteID = SUBMANGA_ID then - Result := GetSubMangaPageNumber - else if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistPageNumber else @@ -698,8 +693,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Starkana/image_url.inc} - {$I includes/SubManga/image_url.inc} - {$I includes/TruyenTranhTuan/image_url.inc} {$I includes/Turkcraft/image_url.inc} @@ -789,9 +782,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = ESMANGAHERE_ID then Result := GetEsMangaHereImageURL else - if manager.container.MangaSiteID = SUBMANGA_ID then - Result := GetSubMangaImageURL - else if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else @@ -1301,9 +1291,6 @@ procedure TTaskThread.Execute; end; end; - //if no total page number found, we reset pagelinks here - if container.MangaSiteID = SUBMANGA_ID then - container.PageLinks.Clear; if ModuleId > -1 then Modules.TaskStart(container, ModuleId); From efef021a7b5e94ebfb3bb6d726402360c3ce5073 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 16:02:32 +0800 Subject: [PATCH 0989/2794] added submanga module fix #199 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Submanga.pas | 161 +++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Submanga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a6fcae545..43fa1bd57 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -28,4 +28,5 @@ uses MintMangaRU, AcademyVN, Webtoons, - Tsumino; + Tsumino, + SubManga; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas new file mode 100644 index 000000000..7f73afd86 --- /dev/null +++ b/baseunits/modules/Submanga.pas @@ -0,0 +1,161 @@ +unit SubManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr; + +implementation + +const + dirurl='/series'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result:=NET_PROBLEM; + Page:=1; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl+'10000000') then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + page:=StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'),1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//table[@class="caps"]/tbody/tr/td[1]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('text()',v.toNode)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + url:=FillHost(Module.RootURL,AURL); + if GET(url) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink:=XPathString('//p[@class="cb"]/img/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=XPathString('//div[@id="b"]//h1/a'); + summary:=XPathString('//div[@id="b"]/div[2]/p[3]'); + genres:=XPathString('//div[@id="b"]/div[2]/p[4]'); + authors:=XPathString('//div[@id="b"]/div[2]/p[5]/a'); + if XPath('//table[@class="caps"]/tbody/tr').Count>0 then + if GET(AppendURLDelim(url)+'completa') then begin + ParseHTML(Document); + with TRegExpr.Create do + try + Expression:='^.*/(\d+)/?$'; + for v in XPath('//table[@class="caps"]/tbody/tr/td[@class="s"]/a') do begin + s:=v.toNode.getAttribute('href'); + if s<>'' then begin + s:=Replace(s,'/c/$1',True); + chapterLinks.Add(s); + chapterName.Add(v.toString); + end; + end; + finally + Free; + end; + InvertStrings([chapterLinks,chapterName]); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber:=XPath('//table[1]/tbody//select/option').Count; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.manager.container,DownloadThread.FHTTP do begin + s:=FillHost(Module.RootURL,AURL); + if DownloadThread.workCounter>0 then + s:=s+'/'+IncStr(DownloadThread.workCounter); + if GET(s) then begin + Result:=True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter]:=XPathString('//div[@id="ab"]/a/img/@src'); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='SubManga'; + RootURL:='http://submanga.com'; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + OnGetImageURL:=@GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 8c1986fd2236e340cc970e4f2911086d176ae384 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 16:08:21 +0800 Subject: [PATCH 0990/2794] changed default save to options --- baseunits/uBaseUnit.pas | 2 +- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fdf1927bb..f8c9237fc 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -229,7 +229,7 @@ interface DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; - DEFAULT_CHAPTER_CUSTOMRENAME = '%NUMBERING% - %CHAPTER%'; + DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; FMDFormatSettings :TFormatSettings = ( CurrencyFormat :1; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 5d719efff..93458676f 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -12,6 +12,7 @@ object MainForm: TMainForm OnDestroy = FormDestroy OnShow = FormShow OnWindowStateChange = FormWindowStateChange + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 75c5a1dd1..aff9299ec 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4310,7 +4310,7 @@ procedure TMainForm.LoadOptions; seOptionPDFQuality.Value := ReadInteger('saveto', 'PDFQuality', 100); rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); cbOptionChangeUnicodeCharacter.Checked := ReadBool('saveto', 'ChangeUnicodeCharacter', False); - cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', True); + cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', False); cbOptionGenerateMangaFolderName.Checked := ReadBool('saveto', 'GenerateMangaName', True); edOptionMangaCustomRename.Text := ReadString('saveto', 'MangaCustomRename', DEFAULT_MANGA_CUSTOMRENAME); if Trim(edOptionMangaCustomRename.Text) = '' then From fe3502047f2c6992ca882901e00f3d87de4d1571 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Feb 2016 16:17:17 +0800 Subject: [PATCH 0991/2794] Bump version 0.9.37.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 92586b929..1aa00da38 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.37.0 (28-02-2016) +[*] Madokami: fix login +[*] SubManga: rewrite all script +[+] Added show password checkbox in add account dialog +[*] Various changes and bug fixes + 0.9.36.0 (27-02-2016) [+] Added Tsumino[H], require cookie in advanced.ini diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 00b006455..826023255 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="36"/> + <RevisionNr Value="37"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index b8d0ebac3..8b1c94402 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.36.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.36.0/fmd_0.9.36.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.36.0/fmd_0.9.36.0_Win64.7z +VERSION=0.9.37.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.37.0/fmd_0.9.37.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.37.0/fmd_0.9.37.0_Win64.7z From a74c68681636eed9d37ae8094512a18b0a6df8d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 3 Mar 2016 23:19:22 +0800 Subject: [PATCH 0992/2794] umisc, added naturalcustomsort --- baseunits/uMisc.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index bd7be1400..c7d3887d4 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -54,6 +54,7 @@ function FormatByteSize(const bytes :longint; persecond: boolean = False) :strin //sorting function NaturalCompareStr(Str1, Str2: string): integer; inline; +function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; inline; //run external process function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean = True; @@ -383,6 +384,11 @@ function NaturalCompareStr(Str1, Str2: string): integer; Result := NaturalSortUnit.UTF8LogicalCompareText(Str1, Str2); end; +function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; +begin + Result := NaturalCompareStr(List[Index1], List[Index2]); +end; + procedure QuickSortNaturalPart(var Alist: TStringList; Separator: String; PartIndex: Integer); From 4ecbba6297e531c52205d5465c00cfd469d0bec6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 4 Mar 2016 01:08:35 +0800 Subject: [PATCH 0993/2794] upacker, cleanup and fix --- baseunits/uDownloadsManager.pas | 6 +- baseunits/uPacker.pas | 172 ++++++++++++++------------------ 2 files changed, 76 insertions(+), 102 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 50c5f2ddc..8e57cc5a4 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1035,9 +1035,9 @@ procedure TTaskThread.Compress; uPacker := TPacker.Create; try case container.Manager.compress of - 1: uPacker.ext := '.zip'; - 2: uPacker.ext := '.cbz'; - 3: uPacker.ext := '.pdf'; + 1: uPacker.Format := pfZIP; + 2: uPacker.Format := pfCBZ; + 3: uPacker.Format := pfPDF; end; uPacker.CompressionQuality := OptionPDFQuality; uPacker.Path := CorrectPathSys(container.DownloadInfo.SaveTo) + diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 73bd305b4..44c3ab0dd 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -11,87 +11,61 @@ interface uses - Classes, Zipper, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, - SimpleException, SimpleLogger; + Classes, Zipper, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, lazutf8classes, + LazFileUtils, SimpleException, uMisc; type + TPackerFormat = (pfZIP, pfCBZ, pfPDF); + TPacker = class protected - list: TStringList; - procedure OnFileFound(FileIterator: TFileIterator); - public - ext, Path: String; - CompressionQuality: Cardinal; + FSavedFilename, FExt: String; + FFileList: TStringList; + procedure FileFound(FileIterator: TFileIterator); procedure DoZipCbz; procedure DoPdf; + public + Path: String; + Format: TPackerFormat; + CompressionQuality: Cardinal; procedure Execute; end; implementation -uses - lazutf8classes, LazFileUtils; - -procedure TPacker.OnFileFound(FileIterator: TFileIterator); +procedure TPacker.FileFound(FileIterator: TFileIterator); begin - list.Add(FileIterator.Filename); + FFileList.Add(FileIterator.Filename); end; procedure TPacker.DoZipCbz; var - s, fPath: String; - searcher: TFileSearcher; Zip: TZipper; i: Cardinal; fstream: TFileStreamUTF8; begin try - fPath := Trim(Path); - RenameFileUTF8(Path, fPath); - list := TStringList.Create; - searcher := TFileSearcher.Create; - searcher.OnFileFound := OnFileFound; - searcher.Search(fPath, '*.jpg;*.jpeg;*.png;*.gif;*.db', False, False); - - if list.Count > 0 then - begin - Zip := TZipper.Create; - try - Zip.FileName := fPath + ext; - for i := 0 to list.Count - 1 do - begin - s := list[i]; - {$IFDEF WINDOWS} - s := StringReplace(s, '/', '\', [rfReplaceAll]); - {$ENDIF} - Zip.Entries.AddFileEntry(TFileStreamUTF8.Create(s, fmOpenRead), - ExtractFileName(s)); - end; - fstream := TFileStreamUTF8.Create(fPath + ext, fmCreate); + Zip := TZipper.Create; + try + for i := 0 to FFileList.Count - 1 do + begin + Zip.Entries.AddFileEntry(TFileStreamUTF8.Create(FFileList[i], fmOpenRead), + ExtractFileName(FFileList[i])); + end; + if Zip.Entries.Count>0 then begin + fstream := TFileStreamUTF8.Create(FSavedFilename, fmCreate); try Zip.SaveToStream(fstream); finally fstream.Free; end; - - for i := 0 to list.Count - 1 do - begin + for i:=0 to Zip.Entries.Count-1 do Zip.Entries[i].Stream.Free; - end; - finally - Zip.Free; + zip.Clear; end; - - //for i := 0 to list.Count - 1 do - //begin - // DeleteFileUTF8(list[i]); - //end; - if DeleteDirectory(fPath, False) then - RemoveDirUTF8(fPath); - RenameFileUTF8(fPath + ext, Path + ext); + finally + Zip.Free; end; - searcher.Free; - list.Free; except on E: Exception do begin @@ -103,58 +77,31 @@ procedure TPacker.DoZipCbz; procedure TPacker.DoPdf; var - s, fPath: String; - searcher: TFileSearcher; pdf: TImg2Pdf; i: Cardinal; fstream: TFileStreamUTF8; begin try - fPath := Trim(Path); - RenameFileUTF8(Path, fPath); - list := TStringList.Create; - searcher := TFileSearcher.Create; + pdf := TImg2Pdf.Create; try - searcher.OnFileFound := OnFileFound; - searcher.Search(fPath, '*.jpg;*.jpeg;*.png;*.gif', False, False); - - if list.Count <> 0 then + pdf.CompressionQuality := CompressionQuality; + pdf.Title := GetLastDir(Path); + for i := 0 to FFileList.Count - 1 do begin - pdf := TImg2Pdf.Create; try - pdf.CompressionQuality := CompressionQuality; - pdf.Title := GetLastDir(Path); - // pdf.FileName:= fPath+ext; - for i := 0 to list.Count - 1 do - begin - s := list[i]; - {$IFDEF WINDOWS} - s := StringReplace(s, '/', '\', [rfReplaceAll]); - {$ENDIF} - // add image to PDF - try - pdf.AddImage(s); - except - end; - end; - - fstream := TFileStreamUTF8.Create(fPath + ext, fmCreate); - try - pdf.SaveToStream(fstream); - finally - fstream.Free; - end; - - finally - pdf.Free; + pdf.AddImage(FFileList[i]); + except end; - if DeleteDirectory(fPath, False) then - RemoveDirUTF8(fPath); - RenameFileUTF8(fPath + ext, Path + ext); + end; + + fstream := TFileStreamUTF8.Create(FSavedFilename, fmCreate); + try + pdf.SaveToStream(fstream); + finally + fstream.Free; end; finally - searcher.Free; - list.Free; + pdf.Free; end; except on E: Exception do @@ -167,12 +114,39 @@ procedure TPacker.DoPdf; procedure TPacker.Execute; begin - if (ext = '.zip') or (ext = '.cbz') then - begin - DoZipCbz; - end - else - DoPdf; + Path:=CleanAndExpandDirectory(Path); + if DirectoryExistsUTF8(Path)=False then Exit; + FFileList:=TStringList.Create; + try + with TFileSearcher.Create do + try + OnFileFound:=FileFound; + Search(Self.Path,'*.jpg;*.jpeg;*.png;*.gif',False,False); + finally + Free; + end; + if FFileList.Count>0 then begin + FFileList.CustomSort(NaturalCustomSort); + case Format of + pfZIP: FExt:='.zip'; + pfCBZ: FExt:='.cbz'; + pfPDF: FExt:='.pdf'; + end; + FSavedFilename:=TrimAndExpandFilename(Path)+FExt; + if FileExistsUTF8(FSavedFilename) then + if DeleteFileUTF8(FSavedFilename)=False then + Exit; + case Format of + pfZIP,pfCBZ: DoZipCbz; + pfPDF: DoPdf; + end; + if FileExistsUTF8(FSavedFilename) then + if DeleteDirectory(Path,False) then + RemoveDirUTF8(Path); + end; + finally + FFileList.Free; + end; end; end. From e5ab77de420affeba1f0ede3ac68c180833feb53 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 4 Mar 2016 22:11:26 +0800 Subject: [PATCH 0994/2794] added mangabackup close #202 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaBackup.pas | 145 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaBackup.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 43fa1bd57..684cc0592 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -29,4 +29,5 @@ uses AcademyVN, Webtoons, Tsumino, - SubManga; + SubManga, + MangaBackup; diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas new file mode 100644 index 000000000..5b9f70486 --- /dev/null +++ b/baseunits/modules/MangaBackup.pas @@ -0,0 +1,145 @@ +unit MangaBackup; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + RegExpr,SimpleLogger; + +implementation + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result:=NET_PROBLEM; + Page:=1; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL+'/genre/?add') then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page:=XPath('(//select)[1]/option').Count; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + s:=Module.RootURL; + if AURL='0' then + s:=s+'/genre/?add' + else + s:=s+'/genre/'+IncStr(AURL)+'?add'; + if MangaInfo.FHTTP.GET(s) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="ls1"]/div//h3/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('text()',v.toNode)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result:=NET_PROBLEM; + if MangaInfo=nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin + url:=FillHost(Module.RootURL,AURL); + if GET(url) then begin + Result:=NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink:=XPathString('//div[@class="cover"]/img/@src'); + if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); + if title=''then title:=XPathString('//h1/a'); + authors:=XPathString('//table[@class="attr"]/tbody/tr[5]/td'); + artists:=XPathString('//table[@class="attr"]/tbody/tr[6]/td'); + genres:=''; + for v in XPath('//table[@class="attr"]/tbody/tr[7]/td/a') do + AddCommaString(genres,v.toString); + summary:=XPathString('//p[@class="summary"]'); + s:=XPathString('//table[@class="attr"]/tbody/tr[9]/td'); + if s<>'' then begin + s:=LowerCase(s); + if Pos('ongoing',s)>0 then + status:='1' + else if Pos('completed',s)>0 then + status:='0'; + end; + for v in XPath('//ul[@class="chapter"]/li/span/a') do begin + s:=v.toNode.getAttribute('href'); + if RightStr(s,2)='/1' then + SetLength(s,Length(s)-2); + chapterLinks.Add(s); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks,chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result:=False; + if DownloadThread=nil then Exit; + with DownloadThread.FHTTP,DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL,AURL)) then begin + Result:=True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//section[@id="viewer"]/div[@class="canvas"]/a[@class="img-link"]/img') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website:='MangaBackup'; + RootURL:='http://mangabackup.com'; + SortedList:=True; + OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; + OnGetNameAndLink:=@GetNameAndLink; + OnGetInfo:=@GetInfo; + OnGetPageNumber:=@GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index c99020463..715cd64b3 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,Madokami,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From df9c56fbf1db7353bc564294e668aee8f0be785d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 4 Mar 2016 22:14:59 +0800 Subject: [PATCH 0995/2794] cleanup --- baseunits/modules/MangaBackup.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index 5b9f70486..233e66013 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr,SimpleLogger; + RegExpr; implementation From 4f2106e4da0c1fd67021704d2c7d4b0c3db5acdf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 4 Mar 2016 22:20:47 +0800 Subject: [PATCH 0996/2794] gos, fix get image url fix #203 --- baseunits/modules/GameofScanlation.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 75d71198a..940a2ea29 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -112,7 +112,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result:=True; with TXQueryEngineHTML.Create(Document) do try - for v in XPath('//div[@id="comicMainImage"]/a/img/@src') do + for v in XPath('//div[@id="comicMainImage"]//img/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL,v.toString)); finally Free; From 77bbcefbfae19b1aa9c311bfd691f1458231b686 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 4 Mar 2016 22:24:06 +0800 Subject: [PATCH 0997/2794] Bump version 0.9.38.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1aa00da38..73dfb9d57 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.38.0 (04-03-2016) +[+] Added MangaBackup[EN] +[*] GameofScanlation: fix get image url +[*] Various changes and bug fixes + 0.9.37.0 (28-02-2016) [*] Madokami: fix login [*] SubManga: rewrite all script diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 826023255..2454b9bf1 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="37"/> + <RevisionNr Value="38"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 8b1c94402..a97ec760b 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.37.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.37.0/fmd_0.9.37.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.37.0/fmd_0.9.37.0_Win64.7z +VERSION=0.9.38.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.38.0/fmd_0.9.38.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.38.0/fmd_0.9.38.0_Win64.7z From c00b64a0dfeba9e9a3a03e10c0f3a1420c208973 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 15:31:11 +0800 Subject: [PATCH 0998/2794] separated xqueryenginehtml to its own unit --- baseunits/XQueryEngineHTML.pas | 127 +++++++++++++++++++++++++ baseunits/modules/AcademyVN.pas | 2 +- baseunits/modules/Batoto.pas | 2 +- baseunits/modules/Cloudflare.pas | 2 +- baseunits/modules/EHentai.pas | 2 +- baseunits/modules/EightMuses.pas | 3 +- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/modules/GameofScanlation.pas | 2 +- baseunits/modules/Hakihome.pas | 2 +- baseunits/modules/HentaiCafe.pas | 3 +- baseunits/modules/HitomiLa.pas | 3 +- baseunits/modules/KissManga.pas | 2 +- baseunits/modules/Luscious.pas | 3 +- baseunits/modules/Madokami.pas | 2 +- baseunits/modules/MangaBackup.pas | 2 +- baseunits/modules/MangaChanRU.pas | 2 +- baseunits/modules/MangaHere.pas | 3 +- baseunits/modules/MangaKoi.pas | 2 +- baseunits/modules/MangaLife.pas | 3 +- baseunits/modules/MangaStreamTo.pas | 2 +- baseunits/modules/MangaTr.pas | 3 +- baseunits/modules/MintMangaRU.pas | 2 +- baseunits/modules/PecintaKomik.pas | 2 +- baseunits/modules/RawSenManga.pas | 2 +- baseunits/modules/Submanga.pas | 2 +- baseunits/modules/Tsumino.pas | 3 +- baseunits/modules/UnionMangas.pas | 2 +- baseunits/modules/WPManga.pas | 3 +- baseunits/modules/Webtoons.pas | 2 +- baseunits/uBaseUnit.pas | 102 -------------------- 30 files changed, 163 insertions(+), 131 deletions(-) create mode 100644 baseunits/XQueryEngineHTML.pas diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas new file mode 100644 index 000000000..d9b9b2e76 --- /dev/null +++ b/baseunits/XQueryEngineHTML.pas @@ -0,0 +1,127 @@ +unit XQueryEngineHTML; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, xquery, xquery_json, simplehtmltreeparser; + +type + + { TXQueryEngineHTML } + + TXQueryEngineHTML = class + private + FEngine: TXQueryEngine; + FTreeParser: TTreeParser; + function Eval(Expression: String; isCSS: Boolean = False; Tree: TTreeNode = nil): IXQValue; + public + constructor Create(HTML: String = ''); overload; + constructor Create(HTMLStream: TStream); overload; + destructor Destroy; override; + procedure ParseHTML(HTML: String); overload; + procedure ParseHTML(HTMLStream: TStream); overload; + function XPath(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; + function XPathString(Expression: String; Tree: TTreeNode = nil): String; inline; + function CSS(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; + function CSSString(Expression: String; Tree: TTreeNode = nil): String; inline; + property Engine: TXQueryEngine read FEngine; + end; + + IXQValue = xquery.IXQValue; + +implementation + +function StreamToString(const Stream: TStream): string; +var + x: Integer; +begin + Stream.Position := 0; + Setlength(Result, Stream.Size); + x := Stream.Read(PChar(Result)^, Stream.Size); + SetLength(Result, x); +end; + +{ TXQueryEngineHTML } + +function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean; Tree: TTreeNode): IXQValue; +var + t: TTreeNode; +begin + Result := xqvalue(); + t := Tree; + if t = nil then t := FTreeParser.getLastTree; + if Expression = '' then Exit; + try + if isCSS then Result := FEngine.evaluateCSS3(Expression, t) + else Result := FEngine.evaluateXPath3(Expression, t); + except + end; +end; + +constructor TXQueryEngineHTML.Create(HTML: String); +begin + FEngine := TXQueryEngine.create; + FTreeParser := TTreeParser.Create; + with FTreeParser do begin + parsingModel := pmHTML; + repairMissingStartTags := True; + repairMissingEndTags := True; + trimText := False; + readComments := False; + readProcessingInstructions := False; + autoDetectHTMLEncoding := False; + if HTML <> '' then parseTree(HTML); + end; +end; + +constructor TXQueryEngineHTML.Create(HTMLStream: TStream); +begin + if Assigned(HTMLStream) then + Create(StreamToString(HTMLStream)) + else + Create; +end; + +destructor TXQueryEngineHTML.Destroy; +begin + FEngine.Free; + FTreeParser.Free; + inherited Destroy; +end; + +procedure TXQueryEngineHTML.ParseHTML(HTML: String); +begin + if HTML <> '' then FTreeParser.parseTree(HTML); +end; + +procedure TXQueryEngineHTML.ParseHTML(HTMLStream: TStream); +begin + ParseHTML(StreamToString(HTMLStream)); +end; + +function TXQueryEngineHTML.XPath(Expression: String; Tree: TTreeNode): IXQValue; +begin + Result := Eval(Expression, False, Tree); +end; + +function TXQueryEngineHTML.XPathString(Expression: String; Tree: TTreeNode + ): String; +begin + Result := Eval(Expression, False, Tree).toString; +end; + +function TXQueryEngineHTML.CSS(Expression: String; Tree: TTreeNode): IXQValue; +begin + Result := Eval(Expression, True, Tree); +end; + +function TXQueryEngineHTML.CSSString(Expression: String; Tree: TTreeNode + ): String; +begin + Result := Eval(Expression, True, Tree).toString; +end; + +end. + diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 4ef382967..617252625 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 6a257700b..259368028 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, dateutils, SimpleLogger, synautil; + accountmanagerdb, XQueryEngineHTML, dateutils, SimpleLogger, synautil; implementation diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 7dafb6598..0e0d14110 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, uBaseUnit, BESEN, BESENValue, RegExpr; + Classes, SysUtils, uBaseUnit, XQueryEngineHTML, BESEN, BESENValue, RegExpr; function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; var CS: TRTLCriticalSection): Boolean; overload; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index a18be8c10..c06fc337c 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb; + accountmanagerdb, XQueryEngineHTML; implementation diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index 27b760497..d9abc3a93 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index c5217ca0e..7b311e0e0 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil; + XQueryEngineHTML, RegExpr, synautil; implementation diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 940a2ea29..d6143568b 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil, Cloudflare; + XQueryEngineHTML, RegExpr, synautil, Cloudflare; implementation diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index a62625da9..72b4ad26c 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index 841c1dd95..5e3756052 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 3f01f7140..e3c10074d 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 9637963f7..4acaa6a81 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - Cloudflare, RegExpr, synautil; + XQueryEngineHTML, Cloudflare, RegExpr, synautil; implementation diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 75d22d65d..5c0816cc0 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index d2096725e..0e4450a8e 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, synacode, RegExpr, fpjson; + accountmanagerdb, XQueryEngineHTML, synacode, RegExpr, fpjson; implementation diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index 233e66013..c43709e82 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr; + XQueryEngineHTML, RegExpr; implementation diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 867fe22f5..1cd05fec7 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil, RegExpr; + XQueryEngineHTML, synautil, RegExpr; implementation diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 95ad5d022..51d28a467 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, synautil; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 8a2da6523..e715bdc3b 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 95a0106c1..2454d048d 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index 506393add..67f6d9810 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil; + XQueryEngineHTML, RegExpr, synautil; implementation diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index 79181a91d..eebf20fe5 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index b9c546df4..5c83690da 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 13f0accfe..241dc1ec1 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 461a37e3e..26fbdab63 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil; + XQueryEngineHTML, RegExpr, synautil; implementation diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 7f73afd86..7a772e2eb 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr; + XQueryEngineHTML, RegExpr; implementation diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index a4bfc1c6a..e52ce76ad 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation @@ -59,7 +59,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var i: Integer; - s: String; v: IXQValue; const g: array[0..2] of String = ('Parody','Characters','Tags'); diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index ed4c0db32..37d68ed7c 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil; + XQueryEngineHTML, RegExpr, synautil; implementation diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index ea33a4d53..40622cdad 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; implementation diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index 48431092b..eb818fc78 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - synautil; + XQueryEngineHTML, synautil; implementation diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f8c9237fc..d1d03d355 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -739,28 +739,6 @@ THTTPSendThread = class(httpsendthread.THTTPSendThread) constructor Create(AOwner: TFMDThread = nil); end; - { TXQueryEngineHTML } - - TXQueryEngineHTML = class - private - FEngine: TXQueryEngine; - FTreeParser: TTreeParser; - function Eval(Expression: String; isCSS: Boolean = False; Tree: TTreeNode = nil): IXQValue; - public - constructor Create(HTML: String = ''); overload; - constructor Create(HTMLStream: TStream); overload; - destructor Destroy; override; - procedure ParseHTML(HTML: String); overload; - procedure ParseHTML(HTMLStream: TStream); overload; - function XPath(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; - function XPathString(Expression: String; Tree: TTreeNode = nil): String; inline; - function CSS(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; - function CSSString(Expression: String; Tree: TTreeNode = nil): String; inline; - property Engine: TXQueryEngine read FEngine; - end; - - IXQValue = xquery.IXQValue; - { THTMLForm } THTMLForm = class @@ -3727,86 +3705,6 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); SetProxy(OptionProxyType, OptionProxyHost, OptionProxyPort, OptionProxyUser, OptionProxyPass); end; -{ TXQueryEngineHTML } - -function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean; Tree: TTreeNode): IXQValue; -var - t: TTreeNode; -begin - Result := xqvalue(); - t := Tree; - if t = nil then t := FTreeParser.getLastTree; - if Expression = '' then Exit; - try - if isCSS then Result := FEngine.evaluateCSS3(Expression, t) - else Result := FEngine.evaluateXPath3(Expression, t); - except - end; -end; - -constructor TXQueryEngineHTML.Create(HTML: String); -begin - FEngine := TXQueryEngine.create; - FTreeParser := TTreeParser.Create; - with FTreeParser do begin - parsingModel := pmHTML; - repairMissingStartTags := True; - repairMissingEndTags := True; - trimText := False; - readComments := False; - readProcessingInstructions := False; - autoDetectHTMLEncoding := False; - if HTML <> '' then parseTree(HTML); - end; -end; - -constructor TXQueryEngineHTML.Create(HTMLStream: TStream); -begin - if Assigned(HTMLStream) then - Create(StreamToString(HTMLStream)) - else - Create; -end; - -destructor TXQueryEngineHTML.Destroy; -begin - FEngine.Free; - FTreeParser.Free; - inherited Destroy; -end; - -procedure TXQueryEngineHTML.ParseHTML(HTML: String); -begin - if HTML <> '' then FTreeParser.parseTree(HTML); -end; - -procedure TXQueryEngineHTML.ParseHTML(HTMLStream: TStream); -begin - ParseHTML(StreamToString(HTMLStream)); -end; - -function TXQueryEngineHTML.XPath(Expression: String; Tree: TTreeNode): IXQValue; -begin - Result := Eval(Expression, False, Tree); -end; - -function TXQueryEngineHTML.XPathString(Expression: String; Tree: TTreeNode - ): String; -begin - Result := Eval(Expression, False, Tree).toString; -end; - -function TXQueryEngineHTML.CSS(Expression: String; Tree: TTreeNode): IXQValue; -begin - Result := Eval(Expression, True, Tree); -end; - -function TXQueryEngineHTML.CSSString(Expression: String; Tree: TTreeNode - ): String; -begin - Result := Eval(Expression, True, Tree).toString; -end; - { TParseHTML } procedure TParseHTML.FoundTag(NoCaseTag, ActualTag: string); From 32680092cc5abacdc1207b88de04b7a8afd069ef Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 15:47:12 +0800 Subject: [PATCH 0999/2794] fixed xqueryenginehtml --- baseunits/XQueryEngineHTML.pas | 68 ++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index d9b9b2e76..16fe55216 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -15,17 +15,18 @@ TXQueryEngineHTML = class private FEngine: TXQueryEngine; FTreeParser: TTreeParser; - function Eval(Expression: String; isCSS: Boolean = False; Tree: TTreeNode = nil): IXQValue; + function Eval(const Expression: String; const isCSS: Boolean = False; + const Tree: TTreeNode = nil): IXQValue; public - constructor Create(HTML: String = ''); overload; - constructor Create(HTMLStream: TStream); overload; + constructor Create(const HTML: String = ''); overload; + constructor Create(const HTMLStream: TStream); overload; destructor Destroy; override; - procedure ParseHTML(HTML: String); overload; - procedure ParseHTML(HTMLStream: TStream); overload; - function XPath(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; - function XPathString(Expression: String; Tree: TTreeNode = nil): String; inline; - function CSS(Expression: String; Tree: TTreeNode = nil): IXQValue; inline; - function CSSString(Expression: String; Tree: TTreeNode = nil): String; inline; + procedure ParseHTML(const HTML: String); overload; + procedure ParseHTML(const HTMLStream: TStream); overload; + function XPath(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; + function XPathString(const Expression: String; const Tree: TTreeNode = nil): String; inline; + function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; + function CSSString(const Expression: String; const Tree: TTreeNode = nil): String; inline; property Engine: TXQueryEngine read FEngine; end; @@ -33,7 +34,7 @@ TXQueryEngineHTML = class implementation -function StreamToString(const Stream: TStream): string; +function StreamToString(const Stream: TStream): String; var x: Integer; begin @@ -45,26 +46,32 @@ function StreamToString(const Stream: TStream): string; { TXQueryEngineHTML } -function TXQueryEngineHTML.Eval(Expression: String; isCSS: Boolean; Tree: TTreeNode): IXQValue; +function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; + const Tree: TTreeNode): IXQValue; var t: TTreeNode; begin Result := xqvalue(); t := Tree; - if t = nil then t := FTreeParser.getLastTree; - if Expression = '' then Exit; + if t = nil then + t := FTreeParser.getLastTree; + if Expression = '' then + Exit; try - if isCSS then Result := FEngine.evaluateCSS3(Expression, t) - else Result := FEngine.evaluateXPath3(Expression, t); + if isCSS then + Result := FEngine.evaluateCSS3(Expression, t) + else + Result := FEngine.evaluateXPath3(Expression, t); except end; end; -constructor TXQueryEngineHTML.Create(HTML: String); +constructor TXQueryEngineHTML.Create(const HTML: String); begin - FEngine := TXQueryEngine.create; + FEngine := TXQueryEngine.Create; FTreeParser := TTreeParser.Create; - with FTreeParser do begin + with FTreeParser do + begin parsingModel := pmHTML; repairMissingStartTags := True; repairMissingEndTags := True; @@ -72,16 +79,17 @@ constructor TXQueryEngineHTML.Create(HTML: String); readComments := False; readProcessingInstructions := False; autoDetectHTMLEncoding := False; - if HTML <> '' then parseTree(HTML); + if HTML <> '' then + parseTree(HTML); end; end; -constructor TXQueryEngineHTML.Create(HTMLStream: TStream); +constructor TXQueryEngineHTML.Create(const HTMLStream: TStream); begin if Assigned(HTMLStream) then Create(StreamToString(HTMLStream)) else - Create; + Create(''); end; destructor TXQueryEngineHTML.Destroy; @@ -91,37 +99,35 @@ destructor TXQueryEngineHTML.Destroy; inherited Destroy; end; -procedure TXQueryEngineHTML.ParseHTML(HTML: String); +procedure TXQueryEngineHTML.ParseHTML(const HTML: String); begin - if HTML <> '' then FTreeParser.parseTree(HTML); + if HTML <> '' then + FTreeParser.parseTree(HTML); end; -procedure TXQueryEngineHTML.ParseHTML(HTMLStream: TStream); +procedure TXQueryEngineHTML.ParseHTML(const HTMLStream: TStream); begin ParseHTML(StreamToString(HTMLStream)); end; -function TXQueryEngineHTML.XPath(Expression: String; Tree: TTreeNode): IXQValue; +function TXQueryEngineHTML.XPath(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, False, Tree); end; -function TXQueryEngineHTML.XPathString(Expression: String; Tree: TTreeNode - ): String; +function TXQueryEngineHTML.XPathString(const Expression: String; const Tree: TTreeNode): String; begin Result := Eval(Expression, False, Tree).toString; end; -function TXQueryEngineHTML.CSS(Expression: String; Tree: TTreeNode): IXQValue; +function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, True, Tree); end; -function TXQueryEngineHTML.CSSString(Expression: String; Tree: TTreeNode - ): String; +function TXQueryEngineHTML.CSSString(const Expression: String; const Tree: TTreeNode): String; begin Result := Eval(Expression, True, Tree).toString; end; end. - From c3b056d9f3179611ecd388d4f2898cf30b3e70e6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 16:13:20 +0800 Subject: [PATCH 1000/2794] xqueryenginehtml, added xpathstringall and cssstringall --- baseunits/XQueryEngineHTML.pas | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 16fe55216..268d729d5 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -25,8 +25,12 @@ TXQueryEngineHTML = class procedure ParseHTML(const HTMLStream: TStream); overload; function XPath(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function XPathString(const Expression: String; const Tree: TTreeNode = nil): String; inline; + function XPathStringAll(const Expression: String; const Tree: TTreeNode = nil; + const Separator: String = ', '): String; function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function CSSString(const Expression: String; const Tree: TTreeNode = nil): String; inline; + function CSSStringAll(const Expression: String; const Tree: TTreeNode = nil; + const Separator: String = ', '): String; property Engine: TXQueryEngine read FEngine; end; @@ -44,6 +48,17 @@ function StreamToString(const Stream: TStream): String; SetLength(Result, x); end; +procedure AddSeparatorString(var Dest: String; const S: String; const Separator: String = ', '); +begin + if Trim(S) <> '' then + begin + if Trim(Dest) = '' then + Dest := Trim(S) + else + Dest := Trim(Dest) + Separator + Trim(S); + end; +end; + { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; @@ -120,6 +135,16 @@ function TXQueryEngineHTML.XPathString(const Expression: String; const Tree: TTr Result := Eval(Expression, False, Tree).toString; end; +function TXQueryEngineHTML.XPathStringAll(const Expression: String; + const Tree: TTreeNode; const Separator: String): String; +var + v: IXQValue; +begin + Result := ''; + for v in Eval(Expression, False, Tree) do + AddSeparatorString(Result, v.toString, Separator); +end; + function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, True, Tree); @@ -130,4 +155,14 @@ function TXQueryEngineHTML.CSSString(const Expression: String; const Tree: TTree Result := Eval(Expression, True, Tree).toString; end; +function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Tree: TTreeNode; + const Separator: String): String; +var + v: IXQValue; +begin + Result := ''; + for v in Eval(Expression, True, Tree) do + AddSeparatorString(Result, v.toString, Separator); +end; + end. From 78a9bea6f1fbd7e6b6504f85fe4813c998fa0035 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 18:21:01 +0800 Subject: [PATCH 1001/2794] xqueryenginehtml, added overload of xpathstringall and cssstringall --- baseunits/XQueryEngineHTML.pas | 56 ++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 268d729d5..b0861c577 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -25,12 +25,16 @@ TXQueryEngineHTML = class procedure ParseHTML(const HTMLStream: TStream); overload; function XPath(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function XPathString(const Expression: String; const Tree: TTreeNode = nil): String; inline; - function XPathStringAll(const Expression: String; const Tree: TTreeNode = nil; - const Separator: String = ', '): String; + function XPathStringAll(const Expression: String; const Separator: String = ', '; + const Tree: TTreeNode = nil): String; overload; + function XPathStringAll(const Expression: String; const Exc: array of String; + const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function CSSString(const Expression: String; const Tree: TTreeNode = nil): String; inline; - function CSSStringAll(const Expression: String; const Tree: TTreeNode = nil; - const Separator: String = ', '): String; + function CSSStringAll(const Expression: String; const Separator: String = ', '; + const Tree: TTreeNode = nil): String; overload; + function CSSStringAll(const Expression: String; const Exc: array of String; + const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; property Engine: TXQueryEngine read FEngine; end; @@ -59,6 +63,18 @@ procedure AddSeparatorString(var Dest: String; const S: String; const Separator: end; end; +function StringInArray(const S: String; const SS: array of String): Boolean; +var + i: Integer; +begin + Result := True; + if Length(SS) > 0 then + for i := Low(SS) to High(SS) do + if SameText(S, SS[i]) then + Exit; + Result := False; +end; + { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; @@ -135,8 +151,8 @@ function TXQueryEngineHTML.XPathString(const Expression: String; const Tree: TTr Result := Eval(Expression, False, Tree).toString; end; -function TXQueryEngineHTML.XPathStringAll(const Expression: String; - const Tree: TTreeNode; const Separator: String): String; +function TXQueryEngineHTML.XPathStringAll(const Expression: String; const Separator: String; + const Tree: TTreeNode): String; var v: IXQValue; begin @@ -145,6 +161,17 @@ function TXQueryEngineHTML.XPathStringAll(const Expression: String; AddSeparatorString(Result, v.toString, Separator); end; +function TXQueryEngineHTML.XPathStringAll(const Expression: String; const Exc: array of String; + const Separator: String; const Tree: TTreeNode): String; +var + v: IXQValue; +begin + Result := ''; + for v in Eval(Expression, False, Tree) do + if StringInArray(Trim(v.toString), Exc) = False then + AddSeparatorString(Result, v.toString, Separator); +end; + function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, True, Tree); @@ -155,14 +182,25 @@ function TXQueryEngineHTML.CSSString(const Expression: String; const Tree: TTree Result := Eval(Expression, True, Tree).toString; end; -function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Tree: TTreeNode; - const Separator: String): String; +function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Separator: String; + const Tree: TTreeNode): String; var v: IXQValue; begin Result := ''; - for v in Eval(Expression, True, Tree) do + for v in Eval(Expression, False, Tree) do AddSeparatorString(Result, v.toString, Separator); end; +function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Exc: array of String; + const Separator: String; const Tree: TTreeNode): String; +var + v: IXQValue; +begin + Result := ''; + for v in Eval(Expression, False, Tree) do + if StringInArray(Trim(v.toString), Exc) = False then + AddSeparatorString(Result, v.toString, Separator); +end; + end. From a597ce7adab6327cee7c9523f8c809c541da9124 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 18:21:18 +0800 Subject: [PATCH 1002/2794] fixed maybefillhost --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d1d03d355..a13c6c7ea 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1407,7 +1407,7 @@ function MaybeFillHost(const Host, URL: String): String; with TRegExpr.Create do try Expression := REGEX_HOST; - if Replace(URL, '$1', True) = '' then + if Replace(URL, '$2', True) = '' then begin tu := Replace(URL, '$4', True); if tu = '' then From 632742519fa8e4c9f53ec550c19d4fbd2487e20a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 19:10:26 +0800 Subject: [PATCH 1003/2794] removed hentai2read old code #205 --- .../Hentai2Read/chapter_page_number.inc | 37 ---- .../Hentai2Read/directory_page_number.inc | 37 ---- baseunits/includes/Hentai2Read/image_url.inc | 31 ---- .../Hentai2Read/manga_information.inc | 164 ------------------ .../includes/Hentai2Read/names_and_links.inc | 46 ----- baseunits/uBaseUnit.pas | 152 ++++++++-------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- 8 files changed, 72 insertions(+), 420 deletions(-) delete mode 100644 baseunits/includes/Hentai2Read/chapter_page_number.inc delete mode 100644 baseunits/includes/Hentai2Read/directory_page_number.inc delete mode 100644 baseunits/includes/Hentai2Read/image_url.inc delete mode 100644 baseunits/includes/Hentai2Read/manga_information.inc delete mode 100644 baseunits/includes/Hentai2Read/names_and_links.inc diff --git a/baseunits/includes/Hentai2Read/chapter_page_number.inc b/baseunits/includes/Hentai2Read/chapter_page_number.inc deleted file mode 100644 index 7caa10210..000000000 --- a/baseunits/includes/Hentai2Read/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetHentai2ReadPageNumber: Boolean; - var - i, j: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(HENTAI2READ_ID, URL), - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and - (GetVal(parse[i], 'class') = - 'cbo_wpm_pag') then - begin - j := i + 1; - while GetTagName(parse[j]) = 'option' do - begin - Inc(manager.container.PageNumber); - Inc(j, 3); - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Hentai2Read/directory_page_number.inc b/baseunits/includes/Hentai2Read/directory_page_number.inc deleted file mode 100644 index f4febbca6..000000000 --- a/baseunits/includes/Hentai2Read/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetHentai2ReadDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), HENTAI2READ_ROOT + HENTAI2READ_BROWSER + - '?text-ver', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'alt') = 'Next Page') then - begin - s := TrimRight(TrimLeft(parse[i - 5])); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Hentai2Read/image_url.inc b/baseunits/includes/Hentai2Read/image_url.inc deleted file mode 100644 index af38c9f7a..000000000 --- a/baseunits/includes/Hentai2Read/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetHentai2ReadImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(HENTAI2READ_ID, URL) + IntToStr(workCounter + 1) + '/', - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = - 'img_mng_enl') then - begin - manager.container.PageLinks[workCounter] := - GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Hentai2Read/manga_information.inc b/baseunits/includes/Hentai2Read/manga_information.inc deleted file mode 100644 index 1adfe35ca..000000000 --- a/baseunits/includes/Hentai2Read/manga_information.inc +++ /dev/null @@ -1,164 +0,0 @@ - function GetHentai2ReadInfoFromURL: Byte; - var - s: String; - isExtractChapters: Boolean = False; - isExtractGenres: Boolean = False; - isExtractSummary: Boolean = True; - i, j: Cardinal; - regx: TRegExpr; - begin - mangaInfo.url := FillMangaSiteHost(HENTAI2READ_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[HENTAI2READ_ID, 0]; - - regx := TRegExpr.Create; - regx.ModifierI := True; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get title - if (Pos('class="head_det_title"', parse[i]) > 0) then - begin - s := Trim(StringFilter(parse[i + 1])); - regx.Expression := '^.+\sdj\s[-_]\s(.+)$'; - mangaInfo.title := regx.Replace(s, '$1', True); - end; - //if (mangaInfo.title = '') AND - //(Pos('meta name="description" content="', parse[i])>0) then - //mangaInfo.title:= GetString(parse[i], 'meta name="description" content="', ' hentai chapters'); - - // get cover link - if (GetTagName(parse[i]) = 'div') and - (i < parse.Count - 3) then - if (GetVal(parse[i], 'class') = 'cover') then - begin - mangaInfo.coverLink := - GetVal(parse[i + 2], 'src'); - if mangaInfo.coverLink = - 'http://hentai2read.com/wp-content/hentai/cover/tbn/001_1535_233x0.jpg' then - mangaInfo.coverLink := ''; - end; - - // get chapter name and links - if isExtractChapters then - begin - if (GetTagName(parse[i]) = 'a') and (i < parse.Count - 2) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - HENTAI2READ_ROOT, '', [rfReplaceAll]); - s := StringReplace(s, HENTAI2READ_MROOT, '', [rfReplaceAll]); - mangaInfo.chapterLinks.Add(s); - //s:= StringReplace(GetVal(parse[i], 'href'), HENTAI2READ_ROOT, '', [rfReplaceAll]); - //parse[i+1]:= StringReplace(parse[i+1], #10, '', [rfReplaceAll]); - //parse[i+1]:= StringReplace(parse[i+1], #13, '', [rfReplaceAll]); - //parse[i+1]:= TrimLeft(parse[i+1]); - //parse[i+1]:= TrimRight(parse[i+1]); - //s:= RemoveSymbols(parse[i+1]); - regx.Expression := '^\d+\s[-_]\s'; - s := regx.Replace(Trim(parse[i + 1]), '', False); - mangaInfo.chapterName.Add(Trim(StringFilter(RemoveSymbols(s)))); - //mangaInfo.chapterName.Add(StringFilter(TrimRight(RemoveSymbols(parse[i+1])))); - end - else - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'right') then - isExtractChapters := False; - end; - - // get summary - if (Pos('Hentai Summary', parse[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 5; - mangaInfo.summary := ''; - while (j < parse.Count) and (Pos('<div class="box">', parse[j]) = 0) and - (j < parse.Count - 1) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - s := HTMLEntitiesFilter(StringFilter(parse[j])); - s := Trim(BreaksString(s)); - mangaInfo.summary := Trim(mangaInfo.summary + s); - end; - Inc(j); - end; - isExtractSummary := False; - end; - - if Pos('Hentai Chapters', parse[i]) > 0 then - isExtractChapters := True; - - // get authors - if (Pos('Author(s):', parse[i]) <> 0) and (i < parse.Count - 6) then - mangaInfo.authors := parse[i + 5]; - - // get artists - if (Pos('Artist(s):', parse[i]) <> 0) and (i < parse.Count - 6) then - mangaInfo.artists := parse[i + 5]; - - // get genres - if (Pos('Genre(s):', parse[i]) <> 0) and (i < parse.Count - 6) then - begin - mangaInfo.genres := ''; - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if GetTagName(parse[i]) = 'a' then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - end - else - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'box') then - isExtractGenres := False; - end; - - // get status - if (Pos('Status:', parse[i]) <> 0) and (i <= parse.Count - 5) then - begin - if Pos('Ongoing', parse[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - regx.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Hentai2Read/names_and_links.inc b/baseunits/includes/Hentai2Read/names_and_links.inc deleted file mode 100644 index 6e2d6e32a..000000000 --- a/baseunits/includes/Hentai2Read/names_and_links.inc +++ /dev/null @@ -1,46 +0,0 @@ - function Hentai2ReadGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), HENTAI2READ_ROOT + HENTAI2READ_BROWSER + - IntToStr(StrToInt(URL) + 1) + '/?text-ver', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - regx := TRegExpr.Create; - regx.ModifierI := True; - regx.Expression := '^.+\sdj\s[-_]\s(.+)$'; - for i := 0 to parse.Count - 1 do - begin - //if Pos('class="lst-anm-ifo"', parse[i])>0 then - if Pos('class="mng_det_pop"', parse[i]) > 0 then - begin - begin - Result := NO_ERROR; - s := Trim(StringFilter(GetVal(parse[i], 'title'))); - s := regx.Replace(s, '$1', True); - names.Add(s); - links.Add(StringReplace(GetVal(parse[i], 'href'), - HENTAI2READ_ROOT, '', [])); - end; - end; - end; - regx.Free; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a13c6c7ea..383a726b6 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -270,84 +270,83 @@ interface OURMANGA_ID = 2; MANGA24H_ID = 3; VNSHARING_ID = 4; - HENTAI2READ_ID = 5; - FAKKU_ID = 6; - TRUYEN18_ID = 7; - MANGAPARK_ID = 8; - MANGATRADERS_ID = 9; - MANGAEDEN_ID = 10; - PERVEDEN_ID = 11; - TRUYENTRANHTUAN_ID = 12; - TURKCRAFT_ID = 13; - MANGAVADISI_ID = 14; - MANGAFRAME_ID = 15; - EATMANGA_ID = 16; - STARKANA_ID = 17; - BLOGTRUYEN_ID = 18; - KOMIKID_ID = 19; - ESMANGAHERE_ID = 20; - ANIMEEXTREMIST_ID = 21; - HUGEMANGA_ID = 22; - S2SCAN_ID = 23; - SENMANGA_ID = 24; - IMANHUA_ID = 25; - MABUNS_ID = 26; - MANGAESTA_ID = 27; - CENTRALDEMANGAS_ID = 28; - EGSCANS_ID = 29; - MANGAAR_ID = 30; - MANGAAE_ID = 31; - ANIMESTORY_ID = 32; - LECTUREENLIGNE_ID = 33; - SCANMANGA_ID = 34; - MANGAGO_ID = 35; - DM5_ID = 36; - MANGACOW_ID = 37; - KIVMANGA_ID = 38; - MEINMANGA_ID = 39; - MANGASPROJECT_ID = 40; - MANGAREADER_POR_ID = 41; - NINEMANGA_ID = 42; - NINEMANGA_ES_ID = 43; - NINEMANGA_CN_ID = 44; - NINEMANGA_RU_ID = 45; - NINEMANGA_DE_ID = 46; - NINEMANGA_IT_ID = 47; - NINEMANGA_BR_ID = 48; - JAPANSHIN_ID = 49; - JAPSCAN_ID = 50; - CENTRUMMANGI_PL_ID = 51; - MANGALIB_PL_ID = 52; - ONEMANGA_ID = 53; - MANGATOWN_ID = 54; - MANGAOKU_ID = 55; - MYREADINGMANGAINFO_ID = 56; - IKOMIK_ID = 57; - NHENTAI_ID = 58; - MANGAMINT_ID = 59; - UNIXMANGA_ID = 60; - EXTREMEMANGAS_ID = 61; - MANGAHOST_ID = 62; - PORNCOMIX_ID = 63; - PORNCOMIXRE_ID = 64; - PORNCOMIXIC_ID = 65; - XXCOMICS_ID = 66; - XXCOMICSMT_ID = 67; - XXCOMICS3D_ID = 68; - PORNXXXCOMICS_ID = 69; - MANGASEE_ID = 70; - MANGAKU_ID = 71; - MANGAAT_ID = 72; - READMANGATODAY_ID = 73; - DYNASTYSCANS_ID = 74; - - WebsiteRoots: array [0..74] of array [0..1] of string = ( + + FAKKU_ID = 5; + TRUYEN18_ID = 6; + MANGAPARK_ID = 7; + MANGATRADERS_ID = 8; + MANGAEDEN_ID = 9; + PERVEDEN_ID = 10; + TRUYENTRANHTUAN_ID = 11; + TURKCRAFT_ID = 12; + MANGAVADISI_ID = 13; + MANGAFRAME_ID = 14; + EATMANGA_ID = 15; + STARKANA_ID = 16; + BLOGTRUYEN_ID = 17; + KOMIKID_ID = 18; + ESMANGAHERE_ID = 19; + ANIMEEXTREMIST_ID = 20; + HUGEMANGA_ID = 21; + S2SCAN_ID = 22; + SENMANGA_ID = 23; + IMANHUA_ID = 24; + MABUNS_ID = 25; + MANGAESTA_ID = 26; + CENTRALDEMANGAS_ID = 27; + EGSCANS_ID = 28; + MANGAAR_ID = 29; + MANGAAE_ID = 30; + ANIMESTORY_ID = 31; + LECTUREENLIGNE_ID = 32; + SCANMANGA_ID = 33; + MANGAGO_ID = 34; + DM5_ID = 35; + MANGACOW_ID = 36; + KIVMANGA_ID = 37; + MEINMANGA_ID = 38; + MANGASPROJECT_ID = 39; + MANGAREADER_POR_ID = 40; + NINEMANGA_ID = 41; + NINEMANGA_ES_ID = 42; + NINEMANGA_CN_ID = 43; + NINEMANGA_RU_ID = 44; + NINEMANGA_DE_ID = 45; + NINEMANGA_IT_ID = 46; + NINEMANGA_BR_ID = 47; + JAPANSHIN_ID = 48; + JAPSCAN_ID = 49; + CENTRUMMANGI_PL_ID = 50; + MANGALIB_PL_ID = 51; + ONEMANGA_ID = 52; + MANGATOWN_ID = 53; + MANGAOKU_ID = 54; + MYREADINGMANGAINFO_ID = 55; + IKOMIK_ID = 56; + NHENTAI_ID = 57; + MANGAMINT_ID = 58; + UNIXMANGA_ID = 59; + EXTREMEMANGAS_ID = 60; + MANGAHOST_ID = 61; + PORNCOMIX_ID = 62; + PORNCOMIXRE_ID = 63; + PORNCOMIXIC_ID = 64; + XXCOMICS_ID = 65; + XXCOMICSMT_ID = 66; + XXCOMICS3D_ID = 67; + PORNXXXCOMICS_ID = 68; + MANGASEE_ID = 69; + MANGAKU_ID = 70; + MANGAAT_ID = 71; + READMANGATODAY_ID = 72; + DYNASTYSCANS_ID = 73; + + WebsiteRoots: array [0..73] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), - ('Hentai2Read', 'http://hentai2read.com'), ('Fakku', 'https://www.fakku.net'), ('Truyen18', 'http://www.truyen18.org'), ('MangaPark', 'http://mangapark.me'), @@ -432,10 +431,6 @@ interface VNSHARING_BROWSER = '/DanhSach'; - HENTAI2READ_ROOT = 'http://hentai2read.com'; - HENTAI2READ_MROOT = 'http://m.hentai2read.com'; - HENTAI2READ_BROWSER = '/hentai-list/all/any/name-az/'; - FAKKU_BROWSER_1 = '/manga/newest'; FAKKU_BROWSER_2 = '/doujinshi/newest'; @@ -3135,9 +3130,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; end; end; - if Pos(HENTAI2READ_ROOT, URL) <> 0 then - HTTP.Headers.Insert(0, 'Referer:' + HENTAI2READ_ROOT + '/'); - HTTP.Clear; HTTP.Headers.Text := HTTPHeader.Text; counter := 0; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 03040290c..cad132b68 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -792,8 +792,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; {$I includes/VnSharing/directory_page_number.inc} - {$I includes/Hentai2Read/directory_page_number.inc} - {$I includes/Fakku/directory_page_number.inc} {$I includes/MangaPark/directory_page_number.inc} @@ -884,9 +882,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if WebsiteID = HENTAI2READ_ID then - Result := GetHentai2ReadDirectoryPageNumber - else if WebsiteID = FAKKU_ID then Result := GetFakkuDirectoryPageNumber else @@ -1017,8 +1012,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/VnSharing/names_and_links.inc} - {$I includes/Hentai2Read/names_and_links.inc} - {$I includes/Fakku/names_and_links.inc} {$I includes/MangaPark/names_and_links.inc} @@ -1147,9 +1140,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else - if WebsiteID = HENTAI2READ_ID then - Result := Hentai2ReadGetNamesAndLinks - else if WebsiteID = FAKKU_ID then Result := FakkuGetNamesAndLinks else @@ -1363,8 +1353,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/VnSharing/manga_information.inc} - {$I includes/Hentai2Read/manga_information.inc} - {$I includes/Fakku/manga_information.inc} {$I includes/MangaPark/manga_information.inc} @@ -1505,9 +1493,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else - if WebsiteID = HENTAI2READ_ID then - Result := GetHentai2ReadInfoFromURL - else if WebsiteID = FAKKU_ID then Result := GetFakkuInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8e57cc5a4..9edebe451 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -385,8 +385,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/EsMangaHere/chapter_page_number.inc} - {$I includes/Hentai2Read/chapter_page_number.inc} - {$I includes/HugeManga/chapter_page_number.inc} {$I includes/Kivmanga/chapter_page_number.inc} @@ -544,9 +542,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else - if manager.container.MangaSiteID = HENTAI2READ_ID then - Result := GetHentai2ReadPageNumber - else if (manager.container.MangaSiteID = NINEMANGA_ID) or (manager.container.MangaSiteID = NINEMANGA_ES_ID) or (manager.container.MangaSiteID = NINEMANGA_CN_ID) or @@ -649,8 +644,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Fakku/image_url.inc} - {$I includes/Hentai2Read/image_url.inc} - {$I includes/HugeManga/image_url.inc} {$I includes/Kivmanga/image_url.inc} @@ -758,9 +751,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else - if manager.container.MangaSiteID = HENTAI2READ_ID then - Result := GetHentai2ReadImageURL - else if manager.container.MangaSiteID = FAKKU_ID then Result := GetFakkuImageURL else From d30ac2fc5412b16dde057ef5813363e276a393ed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 19:10:52 +0800 Subject: [PATCH 1004/2794] added hentai2read module fix #205 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Hentai2Read.pas | 224 ++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Hentai2Read.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 684cc0592..ec515abe2 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -30,4 +30,5 @@ uses Webtoons, Tsumino, SubManga, - MangaBackup; + MangaBackup, + Hentai2Read; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas new file mode 100644 index 000000000..3f87febf5 --- /dev/null +++ b/baseunits/modules/Hentai2Read.pas @@ -0,0 +1,224 @@ +unit Hentai2Read; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, synautil; + +const + dirurl = '/hentai-list/all/any/last-added/'; + cdnurl = 'http://hentaicdn.com'; + +implementation + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then + Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString( + '//ul[starts-with(@class,"pagination")]/li[last()-1]/a'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then + Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then + s := s + IncStr(AURL) + '/'; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//a[@class="mangaPopover"]') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then + Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@class="img-responsive border-black-op"]/@src'); + if coverLink <> '' then + coverLink := TrimLeftChar(coverLink, ['/']); + if coverlink <> '' then + coverLink := MaybeFillHost(cdnurl, coverLink); + if title = '' then + title := XPathString('//h3/a/text()'); + authors := XPathStringAll( + '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Author")]/*[position()>1]', + ['-']); + artists := XPathStringAll( + '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Artist")]/*[position()>1]', + ['-']); + genres := XPathStringAll( + '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Parody") or starts-with(.,"Category") or starts-with(.,"Content") or starts-with(.,"Language")]/*[position()>1]', ['-']); + s := XPathString('//ul[@class="list list-simple-mini"]/li[starts-with(.,"Status")]'); + if s <> '' then + begin + s := LowerCase(s); + if Pos('ongoing', s) > 0 then + status := '1' + else if Pos('completed', s) > 0 then + status := '0'; + end; + summary := XPathStringAll( + '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Storyline")]/*[position()>1]'); + for v in XPath('//ul[starts-with(@class,"nav-chapters")]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('text()', v.toNode)); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + v: IXQValue; + Source: TStringList; + i: Integer; + s: String; +begin + Result := False; + if DownloadThread = nil then + Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do + begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then + begin + Result := True; + Source := TStringList.Create; + try + Source.LoadFromStream(Document); + if Source.Count > 0 then + for i := 0 to Source.Count - 1 do + if Pos('var rff_imageList', Source[i]) > 0 then + begin + s := SeparateRight(Source[i], '='); + if s <> '' then + begin + s := Trim(TrimRightChar(s, [';'])); + with TXQueryEngineHTML.Create(s) do + try + for v in XPath('json(*)()') do + PageLinks.Add(cdnurl + '/hentai' + v.toString); + finally + Free; + end; + end; + Break; + end; + finally + Source.Free; + end; + if PageLinks.Count = 0 then + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath( + '(//ul[@class="dropdown-menu text-center list-inline"])[1]/li').Count; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then + Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do + begin + s := FillHost(Module.RootURL, AURL); + if DownloadThread.workCounter > 0 then + s := AppendURLDelim(s) + IncStr(DownloadThread.workCounter) + '/'; + if GET(s) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//img[@id="arf-reader"]/@src'); + if s<>'' then + begin + s:=TrimLeftChar(s,['/']); + PageLinks[DownloadThread.workCounter] := MaybeFillHost(cdnurl, s); + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Hentai2Read'; + RootURL := 'http://hentai2read.com'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From a95dc9ab6ad25344f8bd24a6b881d50fb08fe0eb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 10 Mar 2016 19:17:11 +0800 Subject: [PATCH 1005/2794] Bump version 0.9.39.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 73dfb9d57..ea4d4e019 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.39.0 (10-03-2016) +[*] Hentai2Read: rewrite all script +[*] Various changes and bug fixes + 0.9.38.0 (04-03-2016) [+] Added MangaBackup[EN] [*] GameofScanlation: fix get image url diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2454b9bf1..19f97fb3b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="38"/> + <RevisionNr Value="39"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index a97ec760b..d3c7e2f27 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.38.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.38.0/fmd_0.9.38.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.38.0/fmd_0.9.38.0_Win64.7z +VERSION=0.9.39.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.39.0/fmd_0.9.39.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.39.0/fmd_0.9.39.0_Win64.7z From aeaec468a04bae05888466731002181efc3f4ad8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 08:21:21 +0800 Subject: [PATCH 1006/2794] httpsendthread, only change mime on post if necessary --- baseunits/httpsendthread.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index ef8fbde5c..22e5e78c8 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -190,7 +190,8 @@ function THTTPSendThread.POST(const URL: String; POSTData: String; Document.Clear; WriteStrToStream(Document, POSTData); end; - MimeType := 'application/x-www-form-urlencoded'; + if (MimeType = 'text/html') or (MimeType = '') then + MimeType := 'application/x-www-form-urlencoded'; Result := HTTPRequest('POST', URL, Response); end; From d522a9f8ebfca3cd6644d22cd1601317843ff2b3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 08:30:45 +0800 Subject: [PATCH 1007/2794] httpsendthread, fix parameter and code format --- baseunits/httpsendthread.pas | 39 +++++++++++++++++------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 22e5e78c8..0d24f81a0 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -18,33 +18,34 @@ THTTPSendThread = class(THTTPSend) fretrycount: Integer; fgzip: Boolean; ffollowredirection: Boolean; - procedure SetTimeout(AValue: integer); + procedure SetTimeout(AValue: Integer); procedure OnOwnerTerminate(Sender: TObject); public constructor Create(AOwner: TFMDThread = nil); - function HTTPRequest(const Method, URL: String; Response: TObject = nil): Boolean; - function HEAD(const URL: String; Response: TObject = nil): Boolean; - function GET(const URL: String; Response: TObject = nil): Boolean; - function POST(const URL: String; POSTData: String = ''; Response: TObject = nil): Boolean; + function HTTPRequest(const Method, URL: String; const Response: TObject = nil): Boolean; + function HEAD(const URL: String; const Response: TObject = nil): Boolean; + function GET(const URL: String; const Response: TObject = nil): Boolean; + function POST(const URL: String; const POSTData: String = ''; const Response: TObject = nil): Boolean; function GetCookies: String; - procedure RemoveCookie(const CookieName: string); + procedure RemoveCookie(const CookieName: String); procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); procedure SetNoProxy; procedure Reset; - property Timeout: integer read FTimeout write SetTimeout; + property Timeout: Integer read FTimeout write SetTimeout; property RetryCount: Integer read fretrycount write fretrycount; property GZip: Boolean read fgzip write fgzip; property FollowRedirection: Boolean read ffollowredirection write ffollowredirection; end; var - DefaultUserAgent: String = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; + DefaultUserAgent: String = + 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; implementation { THTTPSendThread } -procedure THTTPSendThread.SetTimeout(AValue: integer); +procedure THTTPSendThread.SetTimeout(AValue: Integer); begin if FTimeout = AValue then Exit; FTimeout := AValue; @@ -79,8 +80,7 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); end; end; -function THTTPSendThread.HTTPRequest(const Method, URL: String; - Response: TObject): Boolean; +function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: TObject): Boolean; function CheckTerminate: Boolean; begin @@ -97,7 +97,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; Result := False; rurl := EncodeURL(DecodeURL(URL)); if Pos('HTTP/', Headers.Text) = 1 then Reset; - HTTPHeader:= TStringList.Create; + HTTPHeader := TStringList.Create; HTTPHeader.Assign(Headers); try // first request @@ -173,18 +173,17 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; end; end; -function THTTPSendThread.HEAD(const URL: String; Response: TObject): Boolean; +function THTTPSendThread.HEAD(const URL: String; const Response: TObject): Boolean; begin Result := HTTPRequest('HEAD', URL, Response); end; -function THTTPSendThread.GET(const URL: String; Response: TObject): Boolean; +function THTTPSendThread.GET(const URL: String; const Response: TObject): Boolean; begin Result := HTTPRequest('GET', URL, Response); end; -function THTTPSendThread.POST(const URL: String; POSTData: String; - Response: TObject): Boolean; +function THTTPSendThread.POST(const URL: String; const POSTData: String; const Response: TObject): Boolean; begin if POSTData <> '' then begin Document.Clear; @@ -207,7 +206,7 @@ function THTTPSendThread.GetCookies: String; end; end; -procedure THTTPSendThread.RemoveCookie(const CookieName: string); +procedure THTTPSendThread.RemoveCookie(const CookieName: String); var i: Integer; begin @@ -218,8 +217,7 @@ procedure THTTPSendThread.RemoveCookie(const CookieName: string); end; end; -procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, - Pass: String); +procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, Pass: String); var pt: String; begin @@ -262,7 +260,7 @@ procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, procedure THTTPSendThread.SetNoProxy; begin - SetProxy('', '', '', '' ,''); + SetProxy('', '', '', '', ''); end; procedure THTTPSendThread.Reset; @@ -276,4 +274,3 @@ procedure THTTPSendThread.Reset; end; end. - From 29c554c32d15e0552fd5451c872262ceee8ee09e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 10:50:53 +0800 Subject: [PATCH 1008/2794] tmangainformation, added removehostfromchapterlinks flag --- baseunits/uData.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index cad132b68..d9df083cd 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -83,6 +83,7 @@ TMangaInformation = class(TObject) parse: TStringList; isGenerateFolderChapterName: Boolean; isRemoveUnicode: Boolean; + RemoveHostFromChapterLinks: Boolean; FHTTP: THTTPSendThread; ModuleId: Integer; @@ -739,6 +740,7 @@ constructor TMangaInformation.Create(AOwnerThread: TFMDThread; mangaInfo := TMangaInfo.Create; isGetByUpdater := False; ModuleId := -1; + RemoveHostFromChapterLinks := True; end; destructor TMangaInformation.Destroy; @@ -1735,7 +1737,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if chapterLinks.Count > 0 then begin // remove host from chapter links - RemoveHostFromURLsPair(chapterLinks, chapterName); + if RemoveHostFromChapterLinks then + RemoveHostFromURLsPair(chapterLinks, chapterName); // fixing chapter name for j := 0 to chapterName.Count - 1 do begin From f8bd1f751c5b0632f34abf428655aba8b83b72a0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 11:44:15 +0800 Subject: [PATCH 1009/2794] httpsendtherad, added querystring method --- baseunits/httpsendthread.pas | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 0d24f81a0..b9d408eab 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -37,12 +37,37 @@ THTTPSendThread = class(THTTPSend) property FollowRedirection: Boolean read ffollowredirection write ffollowredirection; end; + TKeyValuePair = array[0..1] of String; + +function KeyVal(const AKey, AValue: String): TKeyValuePair; +function QueryString(KeyValuePairs: array of TKeyValuePair): String; + var DefaultUserAgent: String = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; implementation +function KeyVal(const AKey, AValue: String): TKeyValuePair; +begin + Result[0] := AKey; + Result[1] := AValue; +end; + +function QueryString(KeyValuePairs: array of TKeyValuePair): String; +var + i: Integer; +begin + Result := ''; + if Length(KeyValuePairs) > 0 then + for i := Low(KeyValuePairs) to High(KeyValuePairs) do + begin + if Result <> '' then + Result := Result + '&'; + Result := Result + EncodeURL(KeyValuePairs[i, 0]) + '=' + EncodeURL(KeyValuePairs[i, 1]); + end; +end; + { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); From cc02dfad6f32108e1bac28653837e05324593d4c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 14:51:39 +0800 Subject: [PATCH 1010/2794] streamtostring, restore position --- baseunits/XQueryEngineHTML.pas | 4 +++- baseunits/uBaseUnit.pas | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index b0861c577..9caed8862 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -44,12 +44,14 @@ implementation function StreamToString(const Stream: TStream): String; var - x: Integer; + p, x: Int64; begin + p := Stream.Position; Stream.Position := 0; Setlength(Result, Stream.Size); x := Stream.Read(PChar(Result)^, Stream.Size); SetLength(Result, x); + Stream.Position := p; end; procedure AddSeparatorString(var Dest: String; const S: String; const Separator: String = ', '); diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 383a726b6..5b34caa2d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1633,13 +1633,15 @@ procedure ConvertCharsetToUTF8(S: TStrings); function StreamToString(const Stream: TStream): string; var - x: Integer; + p, x: Int64; begin //SetString(Result, PChar(Stream.Memory), Stream.Size div SizeOf(Char)); + p:=Stream.Position; Stream.Position:=0; Setlength(Result,Stream.Size); x:=Stream.Read(PChar(Result)^,Stream.Size); SetLength(Result,x); + Stream.Position:=p; end; function GetRightValue(const name, s: string): string; From eaa2bd0814a5887f8dbb88cfb810ba933cc3b64e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 15:31:50 +0800 Subject: [PATCH 1011/2794] added tumangaonline close #206 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/Tumangaonline.pas | 232 ++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/Tumangaonline.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ec515abe2..4c68ff0b1 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -31,4 +31,5 @@ uses Tsumino, SubManga, MangaBackup, - Hentai2Read; + Hentai2Read, + Tumangaonline; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas new file mode 100644 index 000000000..8b6525c03 --- /dev/null +++ b/baseunits/modules/Tumangaonline.pas @@ -0,0 +1,232 @@ +unit Tumangaonline; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, synacode, RegExpr; + +implementation + +const + dirurls: array[0..5] of String = ( + '/listado-mangas/mangas?tipo=4&filter=Webtoon', + '/listado-mangas/mangas?tipo=4&filter=Manga', + '/listado-mangas/mangas?tipo=4&filter=OneShot', + '/listado-mangas/mangas?tipo=4&filter=Manhwa', + '/listado-mangas/mangas?tipo=4&filter=Manhua', + '/listado-mangas/mangas?tipo=4&filter=Novela' + ); + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('//ul[@class="pagination"]/li[starts-with(.,"Página 1 de")]'); + if s <> '' then begin + s := SeparateRight(s, 'de '); + Page := StrToIntDef(s, 1); + end; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex]; + if AURL <> '0' then + s := s + '&pag=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="row text-center"]/div/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@itemprop="image"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1[@class="panel-title"]'); + authors := XPathString('//table[@class="tbl table-hover"]/tbody/tr/td[@property="name"]/a[1]'); + artists := XPathString('//table[@class="tbl table-hover"]/tbody/tr/td[@property="name"]/a[2]'); + genres := XPathString('//table[@class="tbl table-hover"]/tbody/tr/td[@colspan="2"]'); + summary := XPathString('//div[@id="descripcion"]'); + MangaInfo.RemoveHostFromChapterLinks := False; + for v in XPath('//table[@class="tbl table-hover table-striped"]/tbody/tr/td/h5/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('onClick')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + s, idManga, idCapitulo: String; + source: TStringList; + i: Integer; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + s := ''; + + if Pos('listacapitulos', LowerCase(AURL)) > 0 then + begin + with TRegExpr.Create do + try + Expression := '(?i)listaCapitulos\((\d+),(\d+)[^d]*.*$'; + idManga := Replace(AURL, '$1', True); + idCapitulo := Replace(AURL, '$2', True); + finally + Free; + end; + + Headers.Values['Referer'] := ' ' + MaybeFillHost(Module.RootURL, DownloadInfo.Link); + if POST(Module.RootURL + '/index.php?option=com_controlmanga&view=capitulos&format=raw', + QueryString([KeyVal('idManga', idManga), KeyVal('idCapitulo', idCapitulo)])) then + begin + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//a[@class="toViewer"]/@data-enlace'); + if s <> '' then + ChapterLinks[CurrentDownloadChapterPtr] := s; + finally + Free; + end; + end; + end + else if Pos('/visor/', AURL) > 0 then + s := AURL + else + Exit; + if s = '' then Exit; + + Headers.Values['Referer'] := ' ' + MaybeFillHost(Module.RootURL, DownloadInfo.Link); + if GET(MaybeFillHost(Module.RootURL, s)) then begin + Result := True; + with PageContainerLinks do begin + NameValueSeparator := '='; + Delimiter := '&'; + source := TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do begin + if Pos('var tipo ', source[i]) > 0 then + Values['tipo'] := TrimChar(SeparateRight(source[i], '='), [';', ' ']) + else if Pos('var tam ', source[i]) > 0 then + Values['tam'] := TrimChar(SeparateRight(source[i], '='), [';', ' ']) + else if Pos('var sep ', source[i]) > 0 then + Values['sep'] := TrimChar(SeparateRight(source[i], '='), [';', ' ']) + else if Pos('function toggleFullScreen()', source[i]) > 0 then + Break; + end; + finally + source.Free; + end; + with TXQueryEngineHTML.Create(Document) do + try + Values['ruta'] := EncodeURL(XPathString('//input[@hidden=true]/@value')); + PageNumber := XPath('//select[@id="pageNumber"]/option').Count; + finally + Free; + end; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + if PageContainerLinks.Count = 0 then Exit; + with PageContainerLinks do begin + if NameValueSeparator <> '=' then + NameValueSeparator := '='; + if Delimiter <> '&' then + Delimiter := '&'; + Values['pagina'] := IncStr(DownloadThread.workCounter); + end; + Headers.Values['Referer'] := + ' ' + MaybeFillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + if POST(Module.RootURL + '/visor/x.php', PageContainerLinks.DelimitedText) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := + XPathString('//img[@class="img-responsive center-block"]/@src'); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do begin + Website := 'Tumangaonline'; + RootURL := 'http://www.tumangaonline.com'; + TotalDirectory := Length(dirurls); + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 715cd64b3..212077481 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -15,7 +15,7 @@ Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU -Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga +Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga,Tumangaonline Thai=MangaBoom Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing From f97ea3363cdf3ce14ccbb5d93377d63bb38e02fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 12 Mar 2016 16:03:44 +0800 Subject: [PATCH 1012/2794] Bump version 0.9.40.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index ea4d4e019..c1603918b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.40.0 (12-03-2016) +[+] Added Tsumangaonline[ES] +[*] Various changes and bug fixes + 0.9.39.0 (10-03-2016) [*] Hentai2Read: rewrite all script [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 19f97fb3b..6eb524e58 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="39"/> + <RevisionNr Value="40"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index d3c7e2f27..3545ce122 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.39.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.39.0/fmd_0.9.39.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.39.0/fmd_0.9.39.0_Win64.7z +VERSION=0.9.40.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.40.0/fmd_0.9.40.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.40.0/fmd_0.9.40.0_Win64.7z From 6bceca4efa1d4fdac97e1f09c84047f2074ed9fb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Mar 2016 13:45:35 +0800 Subject: [PATCH 1013/2794] tumangaonline, added taskstart --- baseunits/modules/Tumangaonline.pas | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 8b6525c03..d6a0493c3 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -102,6 +102,17 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; end; end; +function TaskStart(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; +begin + Result := True; + if Task = nil then Exit; + with Task.PageContainerLinks do + begin + NameValueSeparator := '='; + Delimiter := '&'; + end; +end; + function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var @@ -152,8 +163,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String if GET(MaybeFillHost(Module.RootURL, s)) then begin Result := True; with PageContainerLinks do begin - NameValueSeparator := '='; - Delimiter := '&'; source := TStringList.Create; try source.LoadFromStream(Document); @@ -190,13 +199,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if DownloadThread = nil then Exit; with DownloadThread.manager.container, DownloadThread.FHTTP do begin if PageContainerLinks.Count = 0 then Exit; - with PageContainerLinks do begin - if NameValueSeparator <> '=' then - NameValueSeparator := '='; - if Delimiter <> '&' then - Delimiter := '&'; - Values['pagina'] := IncStr(DownloadThread.workCounter); - end; + PageContainerLinks.Values['pagina'] := IncStr(DownloadThread.workCounter); Headers.Values['Referer'] := ' ' + MaybeFillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); if POST(Module.RootURL + '/visor/x.php', PageContainerLinks.DelimitedText) then begin @@ -218,6 +221,7 @@ procedure RegisterModule; Website := 'Tumangaonline'; RootURL := 'http://www.tumangaonline.com'; TotalDirectory := Length(dirurls); + OnTaskStart := @TaskStart; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 85974170db6d9925a979df4a104632798987cb92 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Mar 2016 14:22:40 +0800 Subject: [PATCH 1014/2794] added mangafox watermark template #208 --- extras/mangafoxtemplate/728x48.png | Bin 0 -> 10056 bytes extras/mangafoxtemplate/728x67.png | Bin 0 -> 12355 bytes extras/mangafoxtemplate/728x86.png | Bin 0 -> 16545 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 extras/mangafoxtemplate/728x48.png create mode 100644 extras/mangafoxtemplate/728x67.png create mode 100644 extras/mangafoxtemplate/728x86.png diff --git a/extras/mangafoxtemplate/728x48.png b/extras/mangafoxtemplate/728x48.png new file mode 100644 index 0000000000000000000000000000000000000000..3fa925fe879b94303c1ffcf764a40395b15381c0 GIT binary patch literal 10056 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 literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728x67.png b/extras/mangafoxtemplate/728x67.png new file mode 100644 index 0000000000000000000000000000000000000000..d81b5418e4e79469ffd04c5bc11dd3acd070e0e2 GIT binary patch literal 12355 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 literal 0 HcmV?d00001 diff --git a/extras/mangafoxtemplate/728x86.png b/extras/mangafoxtemplate/728x86.png new file mode 100644 index 0000000000000000000000000000000000000000..d823a0895b412acdff8ef27970d710420267c74d GIT binary patch literal 16545 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 Tu#w!S00000NkvXXu0mjf5PFRH literal 0 HcmV?d00001 From 87c32ad323d32ac78476d06fc5d55295f67dcd6c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Mar 2016 14:23:40 +0800 Subject: [PATCH 1015/2794] compressed mangafox watermark template --- extras/mangafoxtemplate/728-01.png | Bin 50465 -> 17790 bytes extras/mangafoxtemplate/728-02.png | Bin 18576 -> 13403 bytes extras/mangafoxtemplate/728-03.png | Bin 12787 -> 9330 bytes extras/mangafoxtemplate/728-04.png | Bin 16618 -> 11804 bytes extras/mangafoxtemplate/728-05.png | Bin 23361 -> 16506 bytes extras/mangafoxtemplate/728-06.png | Bin 9991 -> 7384 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/extras/mangafoxtemplate/728-01.png b/extras/mangafoxtemplate/728-01.png index 5d24c8f4fdac1020b59e7e64d7b9a18f748e6222..a3aa6c90cb1f20464e38fc34afc9521b7f5ef9bc 100644 GIT binary patch literal 17790 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%0D!d`Yf`w-{ug4+|6;#Ai6MqL>`b) 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 V?T459?NI;#002ovPDHLkV1gK9^~nGL literal 50465 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�TJz_cch6cuPhC#%33BMijr-o2)tIRZ8MmcQxq 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 diff --git a/extras/mangafoxtemplate/728-02.png b/extras/mangafoxtemplate/728-02.png index 56326c39a497eb41bd717b71023cbe20933f2671..20c3d84e60891d6130881c10c69b39e36487055c 100644 GIT binary patch literal 13403 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 Blr;bV literal 18576 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 bzZ?G-jJBY=aY=i-00000NkvXXu0mjfWxaQF diff --git a/extras/mangafoxtemplate/728-03.png b/extras/mangafoxtemplate/728-03.png index 4b9d3f2b695bccb9af2d61ae675167d04ba75d0e..bf1aea5d291762423b1597fef340aed1e53bd2c8 100644 GIT binary patch literal 9330 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 X*ir9gFz}zhdjRs%DpK_lW?}yW?p>NK literal 12787 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 FV1oCHL6-mk diff --git a/extras/mangafoxtemplate/728-04.png b/extras/mangafoxtemplate/728-04.png index ca39841a62df9296a6fdd1fd4bbcc88345840587..8a9e169b6af4bba957d073ae4c685e621a2196df 100644 GIT binary patch literal 11804 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 NNQ*0o)ruGe{Rc)LgHHee literal 16618 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 diff --git a/extras/mangafoxtemplate/728-05.png b/extras/mangafoxtemplate/728-05.png index f2b4a54550da9845cd69d0244b62e21ba95550f0..28f869be3b251ecf4015f12bcb906d765517665e 100644 GIT binary patch literal 16506 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 L6vS&q4TJv=M&4sK literal 23361 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 diff --git a/extras/mangafoxtemplate/728-06.png b/extras/mangafoxtemplate/728-06.png index 0899d7243da90e5e565561896bd71d22043c1a58..faedb6144c30c700e9146d7dd372b568b09cfcde 100644 GIT binary patch literal 7384 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 KMNUMnLSTZ~=qMNf literal 9991 zcmV+iC-~TjP)<h;3K|Lk000e1NJLTq00P(m001Ni00000mUj}800009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-ss783y>ndE#W001BWNkl<Zc-rlpd6->QmG;-Yb!#3{ zDKb_n^FR_H36KOrNCbj1i_oYb4hZ7V3bx`0Dqw3jsBJsZG))WIwup_`wvC7&GD#x> zAt7_k^BwBW_ssJ-zweJ*RnVmS3!nWwv=6ZUsXF)Wz3;o<{hoE!-fP_(LqtTPuvVN{ zy?AwILsToGHq`kwH6kM7G>C{_D-tBctx1ST5Y^O36qi5}BE&?*4(jTis3Gpxiim{O zj{lVfK||y<yz0d;tf`T(MjRT&t#_qfB#Il&F%c23uG+?_tr0(}m#`*^#YFsgjf7#H zh}|e*jRcaY0*T_2h_IW?W(g8Ti-@RgvA}JXz-_1z5kz7lP9i}NO1w@)BnYEMt+6(g zmyt)2)Wjy|0`cl=er;UDi{gp6h-hu)4sq*6#H*>1FcudHsP#l*v6|RnGk5F7ul2%4 zr$NLE>JlQ8;6uM*^8Jv6m`&BL#6%>BYGWc|)-;G$CtjV{jX_OJqPU2N(IR$TjZ-Bv z^cr9BS;S<L3lTR~C*s8u)i;p%<n&@O5rHTnVU0lCXb}nG@hCpEDDl`UxQNF^h$JRR zbsa>AVsVkMMv#~YF(;Am!p2uFsfa{EJSHL$H9<ncur7$lC6ah`p(2TiTQ|vhMD?HQ zxKUg}V)2*+iNiD$tEmdI+HLZ0{8g=D$m?Z6Ld0m%+N9FhAbRWc%UVYiM{WOadQIVr zi9{i_F;UuyRc2~!|G8CE<JQK-*E@umDDBGhaFv-(Ls*lab3}L(^F6P{ZWIwBsrlol zS#F6ZinHv-SK;{ouvC}b=s4{`qTC@)A|c}24RtTSZPnKtzS@VG-56>!y*jIDink+K zSYtH>c9S;KsI8Yw=iv<^Bo-I38^vfTw?{!kSW{iaD5N$PN{!j<*AkOI4XgR`>-0h6 z%?TwY4N|8@Z3)wRS=Wh%*hr$L=}7$xhF_nkiFtl)!ZT~@!rK3Qf5siD6{$(o_~o!( z5;fDxtf>jYTB$j*65@4!T|5@IJxRplzFGgrPP8$M67fV$@G2ay)xx+m$K&y!MZ83# zh)^R=eSM8O^_cUWrXY-YHAfOqt;8F}Pt@ioc{>siTW``E<6(WHh~7k7^y=|JVzF3E zq}EXC>KbD~y%&q?wU#<Ler+t4Z!;SHRCN71dThNhXo%veF16WL8ycp=k?J#rFmYs$ zEqc@zi{c_y(|@Ks789`(wc^!@(IUjeX?WSExpA*Kta%L{PK*|D6Ez}Ygst&EcA8cb zZq(%0%Byj_M)NhhONz!4F&blWaqD8P-yCyHIclnbIzx<>*WeiKMhQK)T_$-uVtZl` z_v-9;eOTkx`?ZG!01}JEL`1YU(ft`-qcgpRQ|mJMSpJi+*A0i|v?j!B=#qv+qH!t! z6p>mf2CdDpBjU)lHc6`lPOaNOov1G>k7^v(C}B+vu~5W~$MlBsbnFqYt(Dj2N8-eS z`mq^p@fN{q`XlEVmsm}Mc(sS&c#T$jl$fzuvx0=w1aXOCeqFuD%YH!IHW5TSvQphf zahsxP-dc{--fRiA4ku`cq(<rw3t1(KS9P6jZ4;3W@f)>7Jg5swQ{y8_(9rs)qHBr2 zULO>jEq<XvN>Z5cL&Ki_+zFXAuQ>{j*ne(Qxge4V>W#Ykgd|?pwZtR_BBD!;C5<Ji zb!%qJw4R(=5s7<89KTM2rkL3%i`#8QB&Pqd^K8&0E)vPBalB^hC)OmAphXg%G)fec z(zp{9r-dI2q*WS^e5*E!G)l8Q#oH0vdnDSWttp;JB_kR5FCKC6n20d1St>8o%TSxl zNkk$qj~|Q8Y;6_iO(*O|$%nH|<*13S`L#98jfGbLn2>l79jSjsI%cb$v`d4?L1}(P zs1mP<5x55h5nt+>q^314FTDH+75{*|2A5sqxgvG(v1HiXSkPteA3afDf<B4Kt8u*c zT~DkjFJeV9Ad!gF=ar)tH3YM!`LaXVCv`_22N9=7^l9FXWF0YyJuM>rT?_NF@^GQV zV<Hj;lDB7`RF_>YkBKDeq<Lz5-xtY?*l#*v&tCPe8E3VA_}Mj)=u+Bq-Lxl`r~dIk z?#MW<ds1XZ=!;R~4S!Zwtydmx#qiy4ORFt$kwD5)>A$}8@(oqKOSIbXH7H7gTK5}Q z{0sH7V!<Cj(V1A^mDpi8UaJ+C%Tvqk?hn-z@03~*@0{x%C`;jGy^MXjIDWlhXh+nw zBNT3@eu}pvSrnMwfiJ6r?_4#wYTm9h{|jM@2w|}5lealC_-^UB$t)Ufs7#Gt>vuo* zFMDO?pNg=B*Uft7D6qdB)50V_^=cUg{$IVKN%O(dz%(HFO3*%luN7+?Dwz0Cgn`Ca zH0YnpDBh9rMN}9O18kGm(*D0T8#UdC$zeENtEm~k0d!uNs}bti`OiWgCZ^slGzMvT zE$CF}U7#?<+mV`wz@8a6rdsKACuu#rk*&`vftRhNrx6b*zjFK@(D)Ov*H74vCZWy? zEtj9U_-;lPkh^2a>6`b0KheUleC5oR&tH4O+{cpsGncMdaF@Gl{fTF{F<d;S^YrhI zK_$7sFW+(Oy3IWn4Ai{){FX=YhA&vW`RXz^uQ_@3;Bj&RJ?E}m^^ZDz=d^uzsp%IO zd1=eh%fHWBxeT3Ax%s5ke|_cF*}t%OX?5q4J2}*K>9Hr=tBh<s;j|`{AAX=^!yW3; zvR+Ake977mS$}^<W%T4bF)3ActU2*9ywguu`CfL<xay2mpZU@;3x7f65#ooZ{@(s! zi{_vHw5^>MJMAW1GV9x}F7DmhdfY9f=Gpre{+gZ-bS}J~P$xCxGbe2O8a#LIh7}*Q zJv4T{yY-Yu`(qa_+pnB-%G$fJUR-hdg)uKViw$z|gvL@iH{W;JhV}0cbUA1KD6E)$ zmXf&Yj71Mx!SI<g&-_b=0z7s4#u*1j8ZK!s44koP(LH|Ug$+AuA7qYPw`Z{#^qqV9 zn)i?Ouli8e@%K=sgnHs>3qF=l%h@OF2J-8dpK}Xd_pz%#wcwDkXl%QjJ-AfK)qHMI z*Y`Pe;@R(PB0^I#pXl6pVRXD~C(R<cV)wkumTdZkacF8?TzGM{v1ghelRYcv9Dl#l zz5et|6S(<HmY;a5PvH$HY|=*&FeEQzzW0IhzN3mril5&=m`$~KeTknI_cRV=9-j|e zAL8fRSoTxCS*vr=Z%NP25;ELo<eJF-;#)4}OEX`{Juk5N@2ueRYy3qjzq@H@7U}mq zZgT9fDUXFW2;>76?Bc$;m5~h<9X%s|Nd4fLUk3YE>-lqD<k@*B@*5sopl`dCzim!) z>GS;SY_vIL*506V{W)y;#QQ!Es5Cyp@7A#4Fa7YAOZsacbbc}aUjMht9LR&o=f1$1 zi*w^E$gas!Jn11URMEUkUgY;{f+0yA^BcI}pCP^%I4F-y{NvVg<@|eXZn`pO!m;0? zyJK+XUc=blJK}e|z|!vVn>W!rBQ?H=5+i->u>Ly7_=}sL5!E5>ALvw7x!wKAZ0OvN zdg4By`}Bu1?yNo;M&I_RQ(p8Nb{w#u=^UF_-dhsb^nD}yrEm7hliargFe>NWH59%7 zbK08SCGupBOOrh130D7m{_~AIRm*S#!|fQdj|a~l-uT;rn^q6w!h-L*+;GKnEp`U% zb~3V)?`~JhQ|n>}Vc(KybnX;CaPdCwNwDLt<h92s`mukgu-5OvdBX`i@SksUEqzGf zX+e#{$?bpj6~L&>BimV_UsU!<2oGQXP8nK3_UVP#vSY!zj{AXKf^}xy*X{u5X>!7z zb=i?NT>fKW?riz$?Rq2za^kl2P2cZX6S~=UC;|7}a8)~Y%?N0{9Xf{u_AW-_p0944 zk?n1VJqyhk&htw`OL^ea7dKlEuW;N>;Ah8^TDQ?+pXV1=`emX*8>st_O3es)@u-O1 zU4Rq$&^^Dr`nqrb%?Bokb)C6#&Al1u?IfJI>u=8$#<$2t7-MqY(q)_fDNSl*CFGal z)E}h$<JFKKuBV7s6bNPQM;33mdvCqMlQKpVz0EJ7m7LkB-HRZ2zOCG-7!=Vv$CCo1 zZN}Kb;}@-1cyC|CXuZP_-7QXpyyLx{>wadY@4fNbnL)0JLo2+b;5bjrJs<%?broCn z5MXG|Gj$mP`e|Er!u&<|?qA@e*X9c=>94QsZQ_XzpS@CAX0d-hI-V+oM*qpf%P=^k z*SaH(9^D<K;pue=qfCu{NT&EH75L@*z9_1|6Egzlt=Y1A(bZ6S1A6R(EkI^fX3!P7 zyV8u0e)+UN8;72lJy-+(aVqS4yEc5r#k+sEIxR3J<OQf?{4~W`y{P-XzWjXGAl(lA zEs@$hqBB~L-T#A&KK{$&+~-boisW1bez|6J0-inbOTYi^`mqOB;SbWk06$gF`0&DE zR=oGY5y6v+sx_trM#N&#M;?1_9i#2+m$c858_2iK8v>|^WAI>6AV0QdZ`{HVys>#i zFaV)<=ELv$-Gx^^%+6X0<SkUMyBTH07ys$S1cTDE^7|;Qc^LFzbZDkx6vWOhv0>*L zjo{!>8H{H}8er%+jRW0`BwQXnm6w{?GZzRlvq-gMEWbxsW);ER*-Gz>bb9Yx2E~T} zY>ErV!S1VrCyv>N`vTb=pMCJ3+j5y1UQw!Rd|<Y+kb&$1FceqZDD0j;&;cnJj?+&n zYc~~mTF|<NePPe4QhKx3A9W!X`-BN7Bpj^Am-i%kfZ;ie9T$zN^Eo)RE_hVx@mr?( zVd*t{|9<OGvtB7I@b(Gis1&^+W9(=!LBIh4gi+zp+O+ocN?>0*qs>qd$O{uoEam&c zsXtBMew67hzcbt~2Y}~dq-2<9mZGq;-m}YszwH|oFZ#r;^_lcf)~5uH{sR3=p7NIe z2mjE3M@VDR`i!KQmvLa9IDT3T285izwaYSx7C^bh+kQ89ET+3Ni2gjmi>)e`{Fuy# zKb1P^=eNC6Cu#eq{eg!z7T0~-Ge7m7(Jrz(XE65E4AWHxAyW86`%j233gGyAd35dz zhj6s!&}$3%yP3S$#c!8etos^c>qaNaWCY5cjGg$e#^9Boib`<&lk8bF6jMC9?li2E ze#0>jY2Rw%r8QA95%gjA2$h9*5PtT?mjs}wHl~BdaSAm#PQSHK?0g`C<lAoJkSMV% zEdBSCa`K~<_5tn`28F?+@VDKo4PAX*)mMa01Q-5Gl8diW>q=n2;(Hiau`68nkpB<! zc~U6P3$#{Gk$_=g`-Azrj<NAd`i@)ShL2`uVvdJ7p<7A}3Hztk#fAP_vsb40p(Hr} zP{W2_akF@Ax{aQ?UZwKJ6SiUGPI654wZP-CFxedP>80z|{cAbJ6DO8mSU;W*<{3eu z9yV{=^q1=n9eDfc+ZQSfoly6YTVXVlTnzs-zist%cy#Z`B*(kP89e*6bFN4I(g`P= zem|#PtUmefbK~EGeXD0*JgcO^!JCdb>yDXDdgjFyJ2$%7(30o$knG^#&u4A?=B$za zrMoCdkX%0VytW?xV*ZYsm-JQYQvC8ACvU!jZ=4+Jr+oAGmoqYO+|soVqg=Rb`_**U zj}j~!BV0)EuPf0?@VKNn=iTU~Jtr++ayNi8^Q`n$GcWv*42J?cuFdRUxMk%H9vXjG zl;P>Nk#N^FGcWo;4!6YPXD)ircXw|NA#=te`LUfJS+VsUZS>cZKjR`-^GB9sIds{I zwHNDqj-fJ0&~wVEf7pPrcMd_{1zWnVheI~q+qazf+gum@JbcosO<&86-E_*PuO4-v zxc;377WYQ`w=La%<M^(1Xanb`0sn!mTh{*7OQW099u)Q6n`bZoXLx$Yri)J4%MyNk z_Ib}NQ~OrJ&ZYj&wHIw|%K)TKU$*7~yV7L>%)6v}#}Mf?N`87>pl?U^*$vbDl>dCz zraOg~PCos-6$KvIesaeT=sj=v4H$~>MD>q?2GImC;-dn4pdUyAV|W^L!~0*f?%zt5 zFdShxz=xqcfE(Db3xF(vSIVJU^g>am4|Jly%Y%)E6GEUU6>_BLhh98)9G5Ue%@And zL*ND<@8;L%5jqMCsnzqtB0)AHPvkIc0}cn(3Xz(|1uyEyV+`y2%c=NS?AKJtfr3TF zgi4C;sdGppXQGW^CBX+3(C`Ss$UzBQl4K#HQNpUylLsg=f}I8rR09Wa86ga?@ySsx zSEJQ#DB|KV3b~+qMmahLjN?HF6DZY_zj3@ix`QzE`~ujaUM5OI83=I5T9703U=#|5 z3uN#pSf4ZZJ@P>Ypn~T+0f(|SS{}wQ-7Eu4uZtVPUMNlRQ_O>%W8#{ZqJQ5Co)x^} z%<_#SY%Kzp(JIXoE|d%t`XLF1hfWA(C}ZKFbJNN#+xmPAU=))yDolU}L5NLMQ9wfl z6`U$%K9L>}K@oBeIC=n}Ly?MEA;JdFha{9B0D}tQ=g(<Bc|1pms}hA20LKm}0T>WQ zs6`;eA}rzHdzcZBIn<kmGQ*JepnzBMDu4^aFk*s276Ju-h!QwB9uzRq$pWg0Qo;0b z4TyB?2q$j>geIgZf(kiQ$WTx{JlzGbAR@#j1L)S|6mwy9yQ~LbkAq>OYV@Le*yv@b zh8++96+AR-bUaj?Jf-Tvy+s)VH3Oz&g%J}5*Umomy$^!|BLJh-%!3hu2Sq4MuZ!&h z6HN0%DGMdOy!n*#`wAwGgAI!PM)cVKT_V8+1vI>B1ZG&cDvk+^Qo#Wt8;YoricjPg z!6yaan2-uFK((PT=@U%GsCXe0Faenirh^}VRR$B10c8wIe#8Jlh(g5y9UQR8L&2Sf zl=BHSLKi6G5Ky4xM2uqMW1>?sz$ihH(06t4Ts()sC!mOh0}+%X^a@zu7c6WY_Z4^w zxcvdeC<k~7Iv!<>iNkU0l!*WZ>@oxnfCB`1JRpJyw2(YDo=s#$Km{_@X1NfOu7Z;+ zf|(^%_4*<BW&n_aEcg>(6bUGUHA3}%>0_GT0^pRPXjSu3Xi)M&2e2&&@dL_lo&?Q* zW4@1WSz)PqCK&mJ5P%FQJ=KS@Vwx((03$G7T~~5N3rhMVvy|QOU~;$-hP7&Upt2VS z7|#N#XAqKMcU3>AU;&lDfB-WE*#ce#0tHaY_-a3Zw~Gv6*~ShDG9GHx^A#++s!j?6 zkOjq6@T-0vh(`6va4EDE6VQlM7sUdn>a?ctkgAHyfxKGH+*w$8UX9xU-2k)X5qMhF z^^T;#9s(CsV{$7)<N?0z0=Q}k(<%bK0@i>EQ7{U*>eHwj1AOZs4(JxPQw5EMQ$$0v z3>13;2Brvw5wD6<F;KK3CI#0ckB#Zj!}E~JyHlcna|_$7W^;oHEC<a44T=UtV}P0i z(5rmA6(~oL%tC~rf$jmp@W50`cr*`SPf(;n!3e<jDdRvlkh650>Ybta8qgDA6F5X^ zV5sWzES>8869HIJ5};&GA|;mv4n#OW8lQZL0n%kEE);Wlz$}230*W5{#|a$((?p9P z3aUOfmsMVYhrXnvLE5SY*dvoc_N#H{Lkk-wgYi-s$7eDw*GPdj0TUW&6MO?ui>eN| z2Dlk7ivl5J9iQX@iXqRaFs@G4GgK=a3==9jIK&tVDliNf$qB|^<~L&lS%?&HdmRk2 zA(ga_3oZtPg~^EL%`I$jU|$kOaa1NlwJI@19bd=rz|LDa7-tO21Uw%zsD_(ErE0AR zRI(7FXTXetPyvz}1$0a$8-ZR81x(Ymrf(C-5tV#^G@e?h7CNM{@X3Nj1n#JU3rZHo zJ-{gfOfUch_@IuWL|}meK@Qsl+ttcgJ{1BS9YV`cs`FBF6amaBJi%}pkAmh#I4SbF zJ^2`VHEsaLR49U<tq_8#7Zl6^><UaJs|(dl3`3p=UfFYCH1Gl6@*_8zbQ5K~B0NtB zP#SUY(DWo>^=V|V9~~IN(QH?Th~zZCJ~%0IDmkn)1S(Sxp+jhBjQaSmV;<&DS=c$! zmz+;OduK2qXwau)<i|n78Np^8vXoUx1;;XaBE>vPNHO%l3cw>xPj&AT_(cm?1Q7bF zisJ;wvvVE5gdX`6(`76$LfB0n%3jquk_ka^V0fhJnYCVUb{@k3X%|d=Jqk8yRBwzT z<jl#cDa|JenaB8P5ZY)XDTW*fLGAvaS@swUF(C+nd=XP~${QI*FT)fbV030uh4jf5 zX&|qoDr|f;ZZ{ao+E64i0~m*42N$#~`_3hIas}V<eaFXgn7{(cqbi`Q5Kv0lHc=W% zqYCK+W2Z;vx#Rv?tWgSBq^c1zzGI{Kz-dQ6)(_i5Z5HlGg(oixrum)NVv`~w@F7xE z=%YY@o<jxOL3ct(za?x7_}1|=$FU1-IkyhiHXzWz(HXVKP$8=lp)BAK>|2y21DP?v zjv!T@+}%Va6I}yH&r%7qP|~qExL7?TgdTV(^n!tot6CueCI;wf`U1$3g(5iM1!IFy zOie}Vp+@h5u)13<RNZMM!Y1t-i~<8JD5vlsO$uDFO>7kygAuT?ijXfkJ~;4<-~;9~ z9?fM!z#Rh)q5zpNN1^>N+;}LiO6a0MuL~%IWjNF$jFqeBi#`ybQkX2av&wi1IWX`D zz;bcj<d#f;-aW$!JP$B4cz9&TCl@0FyZf6xJtEaQt_nryC-A2DO#%lf)6X#Q5&@K% zz#*h)fbEwsC#GVgH}&Qb^izL$`L}}NkSLWnq~Mp^mM?$!g{7yht{Cf<F8LWezIMs^ z%^EWc%i1praUVGT<PX=WJbdoar`(X`(QRjUehe<zarE&o239mz&WB?+t-msa;ud+o z(eZ(m=iLTByK2kouWJT251hAX?N=D;SbOffeoEb+o%QKom%FxZIk@Ybu4At&?%j0$ z+u#4JUiaDd`&${^xo%GUaeKXNpy$&1cYG0g7@oD}tam-Yug;r){7)E9y!Yria@pWw zxbKRs>%O5VS6;g8jGbsq2+zg7arBbMwHvR3FW<zYSFdXQSf5sF-~4g-@Lx^g*|n|f z1B);KAwA=3tK<KMPImrbxDSNvyL8dn-`Cofz2n9IxPD&OZE*h?T`RusZ=HRby0TQ- zf78N+H|;MiKWoz^e*@zV&s@HC)|Cv_p19@t5cSZ7ttZ_MKR&JF&*qlKw-#2$Kcckp zn}zSW^pyKJu(9i-iwYAK^ly9nvdcN9Wg{hhVbkUP%g<f7{73vMG0iUs>9$)}ZMyNM z4aeULKi#oy(XV*uj8osaobn^@I{MgaVeo%Y_WQ;OMe@8T+%wx`tc6j5JiX`M&4K0l znqASMGxk%SJC<3P*8g&`HBw7Tn7}ywc0M!{WydX~|NKV%l+hH+cBkeY;<kq;pg1?8 z^Da`K`*aRQ=a}R25Z^g2Ft$EdvR3^L$bRWx_|-Cfp!FwQcg0A<eIvJi;HB1Gbbs`# zq(1V=F}cgU<<gx;J;boU`7iN@M(5yi?6>{ivzI*_QR-{^2{(M&K6@WOJY}pe{uFy^ znGnM`dw*6t_Nkzu%r|}x!T#lTMIQ1WSRVf1UF?7RbHzWqf#P4>xOYB3y&%i-7pL$X z`zt=10L9ohpXX-(kcU^;yudSy4#$1)f;-%SV-LzG`3s&VxBhX?zmGebc(I8QVdC<S z!N)G2i1m-&cU%S7d*v6fK7VPluD47cwm!t~wmuWB{{>$WGQ!wQ`+#sr2A_SQGurZx ze65<XKl9#5`Q(TC78)Zs6=6^w<@UvX*x^p`Ywhpkxmo|j!}7c2uaCk1;2+98wZR$p zTYpoparSR0o%y5cS@)Y>*tT)$H58WK#lbk;38;X8$#V;_2V<Mou2_0oQ17sJCS$_B z`M6P0DD7$sA|V|fYC~49o4@jI?Sj@TexC;=-xQXbFqHH>AI95?LoJZ31KD)Sf|KsE zf%1>PdRa4r9S6wGo#@aQtnI6XLW~rHbNXu?o}E7|xO-<rnD>47iWc^@F)rIyUeIzo zkXbe0q?b7PhpvB5r&Wld=Y^3NmaN)-Oy~XTyXwF4J=6k&9fe#xVs{(PlF|dG5r~WP z^rFnvbtvn$uh{&vL9z1L1$kglND2(pgUx|Cug2}7#VQbt9!0()Z(DM5=WQf^eeF3d z3^x0Nt<&QtV5Hq*dOio|k)=#7_O?}<mVDi>OL3r<{#FXYi!F4EPo>Qeg2A{Oq7T*E zWCu6y6I6nn@LZ=&vW@XLQ~XZh>|I!5bmlnL5AS}v_{}aa389>E!h&PI!{nj%n_Ji# zbS`MzTDO^rR`xW7CKMVy*uTFc15H+$UXmRpdgiL>R^zc%xRmRmf1x{CZ^6^+pPB&- zK#6Nkyow^vcTj3~;J1q+*BWXey`+y9I>XX-9Q#RpE1Fn&%U!=%VD1ulqFI+bkE~^p zk*+K+!Xw9}rA%e+$ZQ-Er0V|q56`!aA6!V#Uceaulf43my4>}jyyw>)rOF(G5n-%_ zf#sB(Ll()sf4A*IAU&6nI97i>&PQ+l_!sDD1|_}msj2IccMy7yP+Dy8Y=Xe4JikHN zv)afif}uE-!*G+)7g0#}?w@Od?1d70R^N7SZiPCygg~appHDh{R9Ld7=2I5HBH!dO z3_~+ehUZn%^X;M43@+gJYbZT4$8RjKdkxtDv(tr#n);Uj=0q*IL{uJ$YieSe-zl6u zGtA1K<xCv&=f8S%TS?%VRr|;1AAlZ=mv}2d1KF<}qZjO+#1jYRTRrmw7k_N?zYlkJ zjET?S*6;9A>!^Cd3&|Vi`GcJdG%Juhap%|<1armhVfLd})BGj&&3S(3%3M0r*iB#` z`!pxtI+Fa-2XTVpSNX1<000J>Nkl<Z(!B$7@N+X<d&Z59b?$dj>28Hz3lno5PyhYR zPc3_<`|c~B5#X4wyT+~C`j$S{`;qI$I!P)G<hzWCZ?saJqeNSN96Y=5pYbyToxj_2 z?PrJETz(?f3#}@}g=6D&hS&9fa5sK?{LBION2lu(#i0%cI&f5hfwd>~z}Bnbg3I-( z>(tyY2Kx5zvHCmSH=EF*SVyK>;0RFnYTP==gXGt$!v4y;zs|1C=a4j4h|T<8={2t$ ze>4Wu^T`UR5%%%7klgsU&c=uMRy)rw*2d;OizvfOAy<FseNSqint@N4UUPSe&wLWm z(XH&9Lw*}>slDJgFvaf_&hZB5t%vq3-xBkjM}k`x!N%JdZ+zZhtQ5W_?6FI41^C3J z2iNTmX1aOc-`;o1!h5wjic8P-O*3!T{X-|5_es&UR*TjPGY-49wtZ=)LjQYbAN>W` zb#2GId*G|B%hv5hx0S{3<FTvHKJ$v5z@E;tb0_zZ5$O5YrrCEzU~;3({lc<h&~*IS zZy(RgB}ZSmtM?Qpc=AJ=7Ji1bTy)t+k^<dbd-z+q{DZT1sf#Wh{_zJ_ZNC%1l9S$j zc9D-BxA+qai(^N#$Ck@79WZ>xxm{nzyk^@en|}n1$BS0`2v4mZt3>a(+%%oaWm`^o zFC$aej9;~>{oAnrf^(K^!1B%XY;|}>pzk_Pv;AV`#8=~vVDA-eT|any4jMZ*9(VNp z<UaYK+25X@DQ@`Ki(5yh#_zDhUCVV!)AQLxXh(!U|HAx^pF)1&S?`v7ayE3m>&10U z$e5-GX}R=^YYHJIFTHK?NuS8>6@cV%*Zf=iAp2*MlWBgZaPHrbWzX_{KDlPccNTHy zhBcczVb_jXowrBjbN~0xkpC3UvCA-AA!M&lKPHUB0bmgJ10@eADQ+1`R<#mm@cQSt z<zgkG2XcjKQd&!zfa>TTP_#H?KqUjP7wjCsJ`5m40X&8>f<e%G6sZh6U){x*((ag$ z%z)_?EO;LL3<O5CgvDYvdiATsKDd~Efnf@eW0X`6X^0raB3ZI+$cBtz0E&%9C2;lX z5o7h5=TJd&yFoD{2&*X``X{&4ufpxQUNBTWJxBLZ)hHxPhIkkg8ly~&ZxfQ7qPCQF zqXXEu*z~#-bXOzv!PanH=miT(OuUEG4evJys^{|+8wyEaAXP0C)PX5}r*Tf!v%#J+ znJ=6C>@2H9F9g~M7Rp=a*cmL0>V9Ja@-8;mq{*OzuQ4=Pz8OK@g$hpgN6Wh2xyMqm zOB$X5gMdXLH;w~EJFvmFJ)&yi4=H>MC939P2t7CSeT%+@Is|<(l~K-Cmnm2rMAcOb z`zIkj@3IFDLcfpC{#Aiju|jf?gC0sSF!inO5h{RUOdcou4h0l*g21)Gi!9t|>e_;k z2}&^G2PT?o69$;Jj^pW3iNkPLun9;_IO)l+f_o8JMnNTr(5A=FX;8GSsrmR&#tp;D zXtfi+$E#F{&;bX-G`;U`Klz#;fsa2z{{;2`K*>d`ki+pXf@yxIaC(#!P)#a8_IoYy zOCMK(Og}zk-`YGvfEH=^N*XfYf~ggO5g0HkL<3+t8e_?7J;+23A50Aov*<yR!YCQg zf+A%G!yp6|e*~2BWWqj=g<?4>4kbuKFJ>AABKnB(<SinSp-YH^Z|#PBlq6*U-hryd zA;{pX)n9*bf~vAi$c{~Vt)SA28M3FElP-a4L?%RFhuCP4p&xY0Q`dU6@>JW40WLla zKo64@eD-0uLlvJQ8ZLUZipg^UF9~76M4cL62?=yyYCZ<84lZC0RvohMVY&EeD5Oyp z@Srf11gluhK{-@R7hCtM{eXyYir*=m)dKSZ#z-|Qg%2D|gC2G>I@R$_T?7>c6^6l8 ztFFoR0XL{-`39knNaG+OW7Slk>ym~dwhe<J87N{XpgQCssGc<WE<W^vf`>x^(EMug zTGB=dDOE*k+7zl!Rv)VjK^Q=p6b@w2J-jSnYj^|}S_V%A+rT5FOcvJ+A%_A4lr2W9 zrGuJJ2o_8bRtud{prTQH`P%ma1$>v11|=$BMOYqaCPlQvaHC*VZ}==3Oza4gF{qHK z9<No$$EaX|F*P3)a3~TGf{o%RV1OD`YgsL9#S83eVIUM?xSHk+E0DzYF{<?-Q~XZj zG;kd#RSO4mKqj;y#DszBz4gCpujB7yzh!UP8}KL2-m<ssEn&Z9Z`uFQ{x5rMZys~f RuYv#o002ovPDHLkV1hsJVblNs From 233909cc8619c4292c47a8153dbe9ba9130cc264 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Mar 2016 15:44:58 +0800 Subject: [PATCH 1016/2794] rewrite all mangafox code --- baseunits/modules/MangaFox.pas | 346 +++++++++------------------------ 1 file changed, 88 insertions(+), 258 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 3705fcbad..75d67d907 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -6,293 +6,126 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - mangafoxwatermarkremover, HTMLUtil, RegExpr; + XQueryEngineHTML, mangafoxwatermarkremover; implementation -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - Page := 1; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'a') and - (Pos('series_preview manga_', Parse[i]) > 0) then - begin - ALinks.Add(GetVal(Parse[i], 'href')); - ANames.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - + v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + '/manga/', 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga/') then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="manga_list"]/ul/li/a[starts-with(@class,"series_preview manga")]') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - end; - finally - Parse.Free; end; end; -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - s: String = ''; - begin - for i := StartIndex to Parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'tips') then - begin - Inc(info.numChapter); - s := Trim(parse[i + 1]) + ' ' + Trim(parse[i + 5]); - info.chapterName.Add(CommonStringFilter(s)); - s := GetVal(parse[i], 'href'); - if RightStr(s, 6) = '1.html' then - SetLength(s, Length(s) - 6); - info.chapterLinks.Add(s); - end; - end; - - //invert chapters - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; - - procedure ScanParse; - var - i, j: Integer; - begin - info.authors := ''; - info.artists := ''; - info.genres := ''; - info.summary := ''; - info.status := ''; - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if GetVal(parse[i], 'id') = 'title' then - info.title := CommonStringFilter(Parse[i + 3]); - - //cover - if info.coverLink = '' then - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'cover') then - info.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); - - //author - if info.authors = '' then - if Pos('/search/author/', parse[i]) > 0 then - info.authors := Trim(parse[i + 1]); - - //artist - if info.artists = '' then - if Pos('/search/artist/', parse[i]) > 0 then - info.artists := Trim(parse[i + 1]); - - //genres - if info.genres = '' then - if (GetTagName(parse[i]) = 'td') and (GetVal(parse[i], 'valign') = 'top') then - if Pos('/genres/', parse[i + 2]) > 0 then - begin - - for j := i + 1 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/td' then - Break - else - if Pos('<', parse[j]) = 0 then - info.genres := info.genres + parse[j]; - end; - end; - - //summary - if info.summary = '' then - if (GetTagName(parse[i]) = 'p') and (GetVal(parse[i], 'class') = 'summary') then - begin - for j := i + 1 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if Pos('<', parse[j]) = 0 then - info.summary := info.summary + #13#10 + CommonStringFilter(parse[j]); + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="cover"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="cover"]/img/@alt'); + if title = '' then begin + title := XPathString('//meta[@property="og:title"]/@content'); + if RightStr(title, 6) = ' Manga' then + SetLength(title, Length(title) - 6); end; - end; - - //status - if info.status = '' then - if GetTagName(parse[i]) = 'h5' then - if UpperCase(Trim(parse[i + 1])) = 'STATUS:' then + authors := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[2]'); + artists := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[3]'); + genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); + summary := XPathString('//p[@class="summary"]'); + for v in XPath('//ul[@class="chlist"]/li//h3') do begin - if Pos('ONGOING', UpperCase(parse[i + 5])) > 0 then - info.status := '1' // ongoing - else - info.status := '0'; // completed + s := XPathString('a/@href', v.toNode); + if RightStr(s, 6) = '1.html' then + SetLength(s, Length(s) - 6); + chapterLinks.Add(s); + s := XPathString('a', v.toNode); + s := s + ' ' + XPathString('span[@class="title nowrap"]', v.toNode); + chapterName.Add(s); end; - - //check if it's licensed - if GetVal(parse[i], 'class') = 'warning' then - if Pos('it is not available in', parse[i + 1]) > 0 then - begin - info.numChapter := 0; - info.chapterName.Clear; - info.chapterLinks.Clear; - info.summary := Trim(Parse[i + 1]); - Break; + InvertStrings([chapterLinks, chapterName]); + finally + Free; end; - - //chapters - if GetVal(Parse[i], 'id') = 'chapters' then - begin - ScanChapters(i); - Break; - end; end; end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, AURL); - Parse := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Parse)) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; - end; - finally - Parse.Free; - end; end; -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i, j: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'select') and - (GetVal(Parse[i], 'onchange') = 'change_page(this)') then - begin - for j := i + 1 to Parse.Count - 1 do - begin - if GetTagName(Parse[j]) = '/select' then - Break - else - if (GetTagName(Parse[j]) = 'option') and - (GetVal(Parse[j], 'value') <> '0') then - Inc(Container.PageNumber); - end; - Break; - end; - end; - + v: IXQValue; + i: Integer; + s: String; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1.html', - Container.Manager.retryConnect) then - begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1.html') then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + v := XPath('//select[@onchange="change_page(this)"]/option'); + for i := v.Count downto 1 do begin + s := v.get(i).toNode.getAttribute('value'); + if s <> '0' then begin + PageNumber := StrToIntDef(s, 0); + Break; + end; + end; + finally + Free; + end; end; - finally - Parse.Free; end; end; -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'img') and (GetVal(Parse[i], 'id') = 'image') then - begin - if DownloadThread.workCounter < Container.PageLinks.Count then - Container.PageLinks[DownloadThread.workCounter] := GetVal(Parse[i], 'src'); - Break; - end; - end; - +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(DownloadThread.workCounter) + '.html', - Container.Manager.retryConnect) then + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + + IncStr(DownloadThread.workCounter) + '.html') then begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; - end; + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := + XPathString('//div[@class="read_img"]//img[@id="image"]/@src'); + finally + Free; + end; end; - finally - Parse.Free; end; end; @@ -309,9 +142,6 @@ procedure RegisterModule; begin Website := 'MangaFox'; RootURL := 'http://mangafox.me'; - SortedList := False; - InformationAvailable := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From 733bf3bb1b0de44aa2b0596cd0da1cbf705dd327 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Mar 2016 20:15:08 +0800 Subject: [PATCH 1017/2794] frmmain, fixed layout - set autosize for all component with text for translations - cleanup all unused components and change some class of component to match the layout --- mangadownloader/forms/frmMain.lfm | 2889 +++++++++++++----------- mangadownloader/forms/frmMain.pas | 212 +- mangadownloader/languages/fmd.en.po | 6 + mangadownloader/languages/fmd.id_ID.po | 6 + mangadownloader/languages/fmd.po | 5 + 5 files changed, 1733 insertions(+), 1385 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 93458676f..813e93939 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,24 +1,24 @@ object MainForm: TMainForm - Left = 273 - Height = 616 - Top = 76 - Width = 819 + Left = 379 + Height = 557 + Top = 148 + Width = 771 ActiveControl = pcMain Caption = 'Free Manga Downloader' - ClientHeight = 616 - ClientWidth = 819 + ClientHeight = 557 + ClientWidth = 771 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow OnWindowStateChange = FormWindowStateChange + Position = poScreenCenter LCLVersion = '1.7' - Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 - Top = 586 - Width = 819 + Top = 527 + Width = 771 AutoSize = False Panels = < item @@ -33,9 +33,9 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 549 + Height = 490 Top = 11 - Width = 614 + Width = 566 ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 @@ -47,17 +47,17 @@ object MainForm: TMainForm OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' - ClientHeight = 521 - ClientWidth = 606 + ClientHeight = 462 + ClientWidth = 558 object vtDownload: TVirtualStringTree - Left = 2 - Height = 486 + Left = 4 + Height = 426 Top = 32 - Width = 600 + Width = 550 Align = alClient - BorderSpacing.Left = 2 + BorderSpacing.Left = 4 BorderSpacing.Right = 4 - BorderSpacing.Bottom = 3 + BorderSpacing.Bottom = 4 DefaultText = 'Node' DragOperations = [doMove] Header.AutoSizeIndex = 0 @@ -128,23 +128,21 @@ object MainForm: TMainForm OnKeyUp = vtDownloadKeyUp end object pnDownloadToolbar: TPanel - Left = 2 - Height = 28 + Left = 4 + Height = 24 Top = 4 - Width = 600 + Width = 550 Align = alTop - BorderSpacing.Left = 2 - BorderSpacing.Top = 4 - BorderSpacing.Right = 4 + BorderSpacing.Around = 4 BevelOuter = bvNone - ClientHeight = 28 - ClientWidth = 600 + ClientHeight = 24 + ClientWidth = 550 TabOrder = 1 object TransferRateGraph: TChart - Left = 323 - Height = 26 + Left = 321 + Height = 24 Top = 0 - Width = 277 + Width = 229 AllowZoom = False AxisList = < item @@ -189,7 +187,6 @@ object MainForm: TMainForm ) Toolset = TransferRateToolset Align = alClient - BorderSpacing.Bottom = 2 Visible = False object TransferRateGraphArea: TAreaSeries Transparency = 125 @@ -201,22 +198,22 @@ object MainForm: TMainForm end object pnDownloadToolbarLeft: TPanel Left = 0 - Height = 28 + Height = 24 Top = 0 - Width = 323 + Width = 321 Align = alLeft AutoSize = True BevelOuter = bvNone - ClientHeight = 28 - ClientWidth = 323 + ClientHeight = 24 + ClientWidth = 321 TabOrder = 1 object ToolBarDownload: TToolBar Left = 0 - Height = 25 + Height = 24 Top = 0 Width = 321 + Align = alClient AutoSize = True - BorderSpacing.Right = 2 ButtonHeight = 25 EdgeBorders = [] Images = IconList @@ -263,59 +260,60 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 521 - ClientWidth = 606 + ClientHeight = 462 + ClientWidth = 558 object sbInformation: TScrollBox Left = 0 - Height = 521 + Height = 462 Top = 0 - Width = 606 - HorzScrollBar.Page = 218 - VertScrollBar.Page = 317 + Width = 558 + HorzScrollBar.Page = 327 + VertScrollBar.Page = 452 Align = alClient BorderStyle = bsNone - ClientHeight = 521 - ClientWidth = 606 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 462 + ClientWidth = 558 TabOrder = 0 object pnInfomation: TPanel - Left = 0 + Left = 4 Height = 262 - Top = 0 - Width = 606 + Top = 8 + Width = 550 Align = alTop BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ClientHeight = 262 - ClientWidth = 606 + ClientWidth = 550 ParentFont = False TabOrder = 0 object rmInformation: TRichMemo - Left = 165 - Height = 222 - Top = 38 - Width = 436 + AnchorSideLeft.Control = pnThumbContainer + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edURL + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = edURL + AnchorSideRight.Side = asrBottom + Left = 158 + Height = 233 + Top = 27 + Width = 392 Anchors = [akTop, akLeft, akRight, akBottom] Color = clWhite HideSelection = False ParentFont = False ReadOnly = True ScrollBars = ssVertical - TabOrder = 1 - ZoomFactor = 1 - end - object edURL: TEdit - Left = 4 - Height = 23 - Top = 6 - Width = 554 - Anchors = [akTop, akLeft, akRight] - OnKeyPress = edURLKeyPress - PopupMenu = pmEditURL TabOrder = 0 - TextHint = 'Input URL here' + ZoomFactor = 1 end object btDonate: TImage Cursor = crHandPoint - Left = 2 + Left = -54 Height = 21 Top = 14 Width = 75 @@ -324,12 +322,47 @@ object MainForm: TMainForm Stretch = True Visible = False end - object btURL: TSpeedButton - Left = 561 + object pnThumbContainer: TPanel + AnchorSideLeft.Control = edURL + AnchorSideTop.Control = edURL + AnchorSideTop.Side = asrBottom + Left = 0 + Height = 216 + Top = 27 + Width = 154 + BevelOuter = bvNone + BorderStyle = bsSingle + ClientHeight = 212 + ClientWidth = 150 + Color = clWhite + ParentColor = False + TabOrder = 1 + object imCover: TImage + Left = 0 + Height = 212 + Top = 0 + Width = 150 + AntialiasingMode = amOn + Align = alClient + Center = True + Proportional = True + Stretch = True + end + object pbWait: TPaintBox + Left = 0 + Height = 212 + Top = 0 + Width = 150 + Align = alClient + end + end + object edURL: TEditButton + Left = 0 Height = 23 - Top = 6 - Width = 40 - Anchors = [akTop, akRight] + Top = 0 + Width = 550 + Align = alTop + ButtonWidth = 30 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF @@ -366,65 +399,75 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btURLClick - end - object pnThumbContainer: TPanel - Left = 4 - Height = 216 - Top = 38 - Width = 154 - BevelOuter = bvNone - BorderStyle = bsSingle - ClientHeight = 212 - ClientWidth = 150 - Color = clWhite - ParentColor = False + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edURLButtonClick + OnKeyPress = edURLKeyPress + PasswordChar = #0 + PopupMenu = pmEditURL TabOrder = 2 - object imCover: TImage - Left = 0 - Height = 212 - Top = 0 - Width = 150 - AntialiasingMode = amOn - Align = alClient - Center = True - Proportional = True - Stretch = True - end - object pbWait: TPaintBox - Left = 0 - Height = 212 - Top = 0 - Width = 150 - Align = alClient - end + TextHint = 'Input URL here' end end object spInfos: TSplitter Cursor = crVSplit - Left = 0 + Left = 4 Height = 5 - Top = 262 - Width = 606 + Top = 274 + Width = 550 Align = alTop ResizeAnchor = akTop end object pnChapterList: TPanel - Left = 0 - Height = 254 - Top = 267 - Width = 606 + Left = 4 + Height = 171 + Top = 283 + Width = 550 Align = alClient BevelOuter = bvNone - ClientHeight = 254 - ClientWidth = 606 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 171 + ClientWidth = 550 TabOrder = 2 + object clbChapterList: TVirtualStringTree + AnchorSideBottom.Control = lbSaveTo + Left = 0 + Height = 92 + Top = 0 + Width = 516 + Anchors = [akTop, akLeft, akRight, akBottom] + Colors.UnfocusedSelectionColor = clHighlight + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.Height = 23 + Header.MainColumn = -1 + Margin = 2 + ParentFont = False + PopupMenu = pmChapterList + TabOrder = 0 + TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnBeforeCellPaint = clbChapterListBeforeCellPaint + OnGetText = clbChapterListGetText + OnInitNode = clbChapterListInitNode + end object btDownload: TBitBtn - Left = 387 - Height = 30 - Top = 186 - Width = 101 - Anchors = [akRight, akBottom] + AnchorSideTop.Control = btReadOnline + AnchorSideRight.Control = btReadOnline + AnchorSideBottom.Control = btReadOnline + AnchorSideBottom.Side = asrBottom + Left = 338 + Height = 26 + Top = 115 + Width = 100 + Anchors = [akTop, akRight, akBottom] + AutoSize = True Caption = 'Download' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -466,48 +509,31 @@ object MainForm: TMainForm TabOrder = 1 end object cbAddAsStopped: TCheckBox - Left = 4 + AnchorSideLeft.Control = edSaveTo + AnchorSideTop.Control = edSaveTo + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = edSaveTo + AnchorSideRight.Side = asrBottom + Left = 0 Height = 19 - Top = 223 - Width = 214 - Anchors = [akLeft, akBottom] + Top = 142 + Width = 334 + Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' OnChange = cbAddAsStoppedChange ParentFont = False TabOrder = 3 end - object clbChapterList: TVirtualStringTree - Left = 4 - Height = 166 - Top = 0 - Width = 563 - Anchors = [akTop, akLeft, akRight, akBottom] - Colors.UnfocusedSelectionColor = clHighlight - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = <> - Header.DefaultHeight = 17 - Header.Height = 23 - Header.MainColumn = -1 - Margin = 2 - ParentFont = False - PopupMenu = pmChapterList - TabOrder = 0 - TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnBeforeCellPaint = clbChapterListBeforeCellPaint - OnGetText = clbChapterListGetText - OnInitNode = clbChapterListInitNode - end object btReadOnline: TBitBtn - Left = 493 - Height = 30 - Top = 186 + AnchorSideTop.Control = edSaveTo + AnchorSideRight.Control = btChecks + AnchorSideRight.Side = asrBottom + Left = 442 + Height = 26 + Top = 115 Width = 108 Anchors = [akRight, akBottom] + AutoSize = True Caption = 'Read online' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -548,56 +574,14 @@ object MainForm: TMainForm OnClick = btReadOnlineClick TabOrder = 2 end - object btBrowse: TSpeedButton - Left = 360 - Height = 23 - Top = 189 - Width = 23 - Anchors = [akRight, akBottom] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 - 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 - 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 - 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 - 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 - 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 - 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC - DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 - 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 - D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 - AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA - D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 - B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC - DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 - B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD - DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B - B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE - DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D - BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 - DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F - BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 - E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 - C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 - E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 - C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA - FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 - C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC - FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 - CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 - FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 - CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 - CC810088CC810088CC810088CC810088CC610087CB000087CB00 - } - OnClick = btBrowseClick - end object btChecks: TSpeedButton - Left = 571 + AnchorSideLeft.Control = clbChapterList + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = clbChapterList + Left = 520 Height = 30 Top = 0 Width = 30 - Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000090000 @@ -637,11 +621,17 @@ object MainForm: TMainForm OnClick = btChecksClick end object btAddToFavorites: TBitBtn - Left = 387 - Height = 30 - Top = 220 - Width = 214 - Anchors = [akRight, akBottom] + AnchorSideLeft.Control = btDownload + AnchorSideTop.Control = btReadOnline + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btReadOnline + AnchorSideRight.Side = asrBottom + Left = 338 + Height = 26 + Top = 145 + Width = 212 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoSize = True Caption = 'Add to favorites' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -682,68 +672,371 @@ object MainForm: TMainForm OnClick = btAddToFavoritesClick TabOrder = 4 end - object edSaveTo: TEdit - Left = 4 - Height = 23 - Top = 189 - Width = 353 - Anchors = [akLeft, akRight, akBottom] - ParentFont = False - TabOrder = 5 - TextHint = 'Save to' - end object lbSaveTo: TLabel - Left = 4 + AnchorSideLeft.Control = clbChapterList + AnchorSideTop.Control = clbChapterList + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = edSaveTo + Left = 0 Height = 15 - Top = 171 + Top = 96 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' ParentColor = False ParentFont = False end + object edSaveTo: TDirectoryEdit + AnchorSideLeft.Control = lbSaveTo + AnchorSideTop.Control = btReadOnline + AnchorSideRight.Control = btDownload + Left = 0 + Height = 23 + Top = 115 + Width = 334 + ShowHidden = False + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + NumGlyphs = 1 + Anchors = [akTop, akLeft, akRight] + MaxLength = 0 + ParentFont = False + TabOrder = 5 + TextHint = 'Save to' + end end end end object tsFilter: TTabSheet Caption = 'Filter' - ClientHeight = 521 - ClientWidth = 606 + ClientHeight = 462 + ClientWidth = 558 object sbFilter: TScrollBox Left = 0 - Height = 521 + Height = 462 Top = 0 - Width = 606 - HorzScrollBar.Page = 568 - VertScrollBar.Page = 424 + Width = 558 + HorzScrollBar.Page = 488 + VertScrollBar.Page = 416 Align = alClient BorderStyle = bsNone - ClientHeight = 521 - ClientWidth = 606 + ClientHeight = 462 + ClientWidth = 558 TabOrder = 0 - object pnGenres: TPanel - Left = 24 - Height = 180 - Top = 10 - Width = 582 + object pnCustomGenre: TPanel + Left = 8 + Height = 23 + Top = 196 + Width = 542 Align = alTop AutoSize = True - BorderSpacing.Left = 24 - BorderSpacing.Top = 10 + BorderSpacing.Around = 8 BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 10 + ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ChildSizing.Layout = cclTopToBottomThenLeftToRight + ChildSizing.ControlsPerLine = 3 + ClientHeight = 23 + ClientWidth = 542 + TabOrder = 2 + object lbFilterCustomGenres: TLabel + Left = 0 + Height = 23 + Top = 0 + Width = 93 + Align = alLeft + Caption = 'Custom Genres' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edCustomGenres: TEdit + Left = 97 + Height = 23 + Top = 0 + Width = 428 + Align = alClient + BorderSpacing.Left = 4 + ParentFont = False + TabOrder = 0 + TextHint = 'Input custom genres, separated by comma' + end + object lbFilterHint: TLabel + AnchorSideLeft.Control = edCustomGenres + AnchorSideLeft.Side = asrBottom + Left = 529 + Height = 23 + Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' + Top = 0 + Width = 13 + Align = alRight + BorderSpacing.Left = 4 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + end + object pnFilter: TPanel + Left = 8 + Height = 136 + Top = 237 + Width = 542 + Align = alTop + BorderSpacing.Top = 10 + BorderSpacing.Around = 8 + BevelOuter = bvNone + ClientHeight = 136 + ClientWidth = 542 + ParentFont = False + TabOrder = 1 + object Panel1: TPanel + Left = 0 + Height = 136 + Top = 0 + Width = 299 + Align = alLeft + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.EnlargeHorizontal = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 2 + ClientHeight = 136 + ClientWidth = 299 + TabOrder = 0 + object lbFilterTitle: TLabel + Left = 0 + Height = 23 + Top = 0 + Width = 110 + Caption = 'Title' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterTitle: TEdit + Left = 114 + Height = 23 + Top = 0 + Width = 185 + TabOrder = 0 + TextHint = 'Title' + end + object lbFilterAuthors: TLabel + Left = 0 + Height = 23 + Top = 27 + Width = 110 + Caption = 'Author' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterAuthors: TEdit + Left = 114 + Height = 23 + Top = 27 + Width = 185 + TabOrder = 2 + TextHint = 'Author' + end + object lbFilterArtists: TLabel + Left = 0 + Height = 23 + Top = 54 + Width = 110 + Caption = 'Artist' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterArtists: TEdit + Left = 114 + Height = 23 + Top = 54 + Width = 185 + TabOrder = 1 + TextHint = 'Artist' + end + object lbFilterStatus: TLabel + Left = 0 + Height = 23 + Top = 81 + Width = 110 + Caption = 'Status' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object cbFilterStatus: TComboBox + Left = 114 + Height = 23 + Top = 81 + Width = 185 + ItemHeight = 15 + ItemIndex = 2 + Items.Strings = ( + 'Completed' + 'Ongoing' + '<none>' + ) + Style = csDropDownList + TabOrder = 3 + Text = '<none>' + end + object lbFilterSummary: TLabel + Left = 0 + Height = 23 + Top = 108 + Width = 110 + Caption = 'Summary' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterSummary: TEdit + Left = 114 + Height = 23 + Top = 108 + Width = 185 + TabOrder = 4 + TextHint = 'Part of summary' + end + end + object Panel2: TPanel + Left = 303 + Height = 136 + Top = 0 + Width = 239 + Align = alClient + AutoSize = True + BorderSpacing.Left = 4 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ClientHeight = 136 + ClientWidth = 239 + TabOrder = 1 + object rbOne: TRadioButton + Left = 0 + Height = 19 + Top = 0 + Width = 169 + Caption = 'Have one of genres checked' + ParentFont = False + TabOrder = 0 + end + object rbAll: TRadioButton + Left = 0 + Height = 19 + Top = 23 + Width = 169 + Caption = 'Have all genre checked' + Checked = True + ParentFont = False + TabOrder = 1 + TabStop = True + end + object cbOnlyNew: TCheckBox + Left = 0 + Height = 19 + Top = 46 + Width = 169 + Caption = 'Search only new manga' + ParentFont = False + TabOrder = 2 + end + object cbSearchFromAllSites: TCheckBox + Left = 0 + Height = 19 + Top = 69 + Width = 169 + Caption = 'Search in all manga sites' + TabOrder = 3 + end + object cbUseRegExpr: TCheckBox + Left = 0 + Height = 19 + Top = 92 + Width = 169 + Caption = 'Regular Expression' + TabOrder = 4 + end + end + end + object pnGenres: TPanel + Left = 8 + Height = 180 + Top = 8 + Width = 542 + Align = alTop + AutoSize = True + BorderSpacing.Around = 8 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.Layout = cclTopToBottomThenLeftToRight ChildSizing.ControlsPerLine = 8 ClientHeight = 180 - ClientWidth = 582 + ClientWidth = 542 TabOrder = 0 object ckFilterAction: TCheckBox Left = 0 Height = 19 Hint = 'A work typically depicting fighting, violence, chaos, and fast paced motion.' Top = 0 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Action' ParentFont = False @@ -756,7 +1049,7 @@ object MainForm: TMainForm Height = 19 Hint = 'Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity.' Top = 23 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Adult' ParentFont = False @@ -769,7 +1062,7 @@ object MainForm: TMainForm Height = 19 Hint = 'If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it''s up to your personal prejudice on this case.' Top = 46 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Adventure' ParentFont = False @@ -782,7 +1075,7 @@ object MainForm: TMainForm Height = 19 Hint = 'A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict.' Top = 69 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Comedy' ParentFont = False @@ -795,7 +1088,7 @@ object MainForm: TMainForm Height = 19 Hint = 'Fan based work inpspired by official manga/anime.' Top = 92 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Doujinshi' ParentFont = False @@ -808,7 +1101,7 @@ object MainForm: TMainForm Height = 19 Hint = 'A work meant to bring on an emotional response, such as instilling sadness or tension.' Top = 115 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Drama' ParentFont = False @@ -821,7 +1114,7 @@ object MainForm: TMainForm Height = 19 Hint = 'Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans.' Top = 138 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Ecchi' ParentFont = False @@ -834,7 +1127,7 @@ object MainForm: TMainForm Height = 19 Hint = 'Anything that involves, but not limited to, magic, dream world, and fairy tales.' Top = 161 - Width = 75 + Width = 94 AllowGrayed = True Caption = 'Fantasy' ParentFont = False @@ -843,11 +1136,11 @@ object MainForm: TMainForm TabOrder = 7 end object ckFilterGenderBender: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'Girls dressing up as guys, guys dressing up as girls.'#13#10'Guys turning into girls, girls turning into guys.' Top = 0 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Gender Bender' ParentFont = False @@ -856,11 +1149,11 @@ object MainForm: TMainForm TabOrder = 8 end object ckFilterHarem: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed.' Top = 23 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Harem' ParentFont = False @@ -869,11 +1162,11 @@ object MainForm: TMainForm TabOrder = 9 end object ckFilterHentai: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'Hentai' Top = 46 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Hentai' ParentFont = False @@ -882,11 +1175,11 @@ object MainForm: TMainForm TabOrder = 10 end object ckFilterHistorical: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'Having to do with old or ancient times.' Top = 69 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Historical' ParentFont = False @@ -895,11 +1188,11 @@ object MainForm: TMainForm TabOrder = 11 end object ckFilterHorror: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking.' Top = 92 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Horror' ParentFont = False @@ -908,11 +1201,11 @@ object MainForm: TMainForm TabOrder = 12 end object ckFilterJosei: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'Literally "Woman". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature.' Top = 115 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Josei' ParentFont = False @@ -921,11 +1214,11 @@ object MainForm: TMainForm TabOrder = 13 end object ckFilterLolicon: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'Representing a sexual attraction to young or under-age girls.' Top = 138 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Lolicon' ParentFont = False @@ -934,11 +1227,11 @@ object MainForm: TMainForm TabOrder = 14 end object ckFilterMartialArts: TCheckBox - Left = 85 + Left = 98 Height = 19 Hint = 'As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth.' Top = 161 - Width = 98 + Width = 117 AllowGrayed = True Caption = 'Martial Arts' ParentFont = False @@ -947,11 +1240,11 @@ object MainForm: TMainForm TabOrder = 15 end object ckFilterMature: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language.' Top = 0 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Mature' ParentFont = False @@ -960,11 +1253,11 @@ object MainForm: TMainForm TabOrder = 16 end object ckFilterMecha: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'A work involving and usually concentrating on all types of large robotic machines.' Top = 23 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Mecha' ParentFont = False @@ -973,11 +1266,11 @@ object MainForm: TMainForm TabOrder = 17 end object ckFilterMusical: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Musical' Top = 46 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Musical' ParentFont = False @@ -986,11 +1279,11 @@ object MainForm: TMainForm TabOrder = 18 end object ckFilterMystery: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it.' Top = 69 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Mystery' ParentFont = False @@ -999,11 +1292,11 @@ object MainForm: TMainForm TabOrder = 19 end object ckFilterPsychological: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology.' Top = 92 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Psychological' ParentFont = False @@ -1012,11 +1305,11 @@ object MainForm: TMainForm TabOrder = 20 end object ckFilterRomance: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is.' Top = 115 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Romance' ParentFont = False @@ -1025,11 +1318,11 @@ object MainForm: TMainForm TabOrder = 21 end object ckFilterSchoolLife: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Having a major setting of the story deal with some type of school.' Top = 138 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'School Life' ParentFont = False @@ -1038,11 +1331,11 @@ object MainForm: TMainForm TabOrder = 22 end object ckFilterSciFi: TCheckBox - Left = 193 + Left = 219 Height = 19 Hint = 'Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world.' Top = 161 - Width = 93 + Width = 112 AllowGrayed = True Caption = 'Sci-Fi' ParentFont = False @@ -1051,11 +1344,11 @@ object MainForm: TMainForm TabOrder = 23 end object ckFilterSeinen: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'From Google: Seinen means ''young Man''. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood.' Top = 0 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Seinen' ParentFont = False @@ -1064,11 +1357,11 @@ object MainForm: TMainForm TabOrder = 24 end object ckFilterShotacon: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'Representing a sexual attraction to young or under-age boys.' Top = 23 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Shotacon' ParentFont = False @@ -1077,11 +1370,11 @@ object MainForm: TMainForm TabOrder = 25 end object ckFilterShoujo: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'A work intended and primarily written for females. Usually involves a lot of romance and strong character development.' Top = 46 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Shoujo' ParentFont = False @@ -1090,11 +1383,11 @@ object MainForm: TMainForm TabOrder = 26 end object ckFilterShoujoAi: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'Often synonymous with yuri, this can be thought of as somewhat less extreme. "Girl''''s Love", so to speak.' Top = 69 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Shoujo Ai' ParentFont = False @@ -1103,11 +1396,11 @@ object MainForm: TMainForm TabOrder = 27 end object ckFilterShounen: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'A work intended and primarily written for males. These works usually involve fighting and/or violence.' Top = 92 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Shounen' ParentFont = False @@ -1116,11 +1409,11 @@ object MainForm: TMainForm TabOrder = 28 end object ckFilterShounenAi: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'Often synonymous with yaoi, this can be thought of as somewhat less extreme. "Boy''''s Love", so to speak' Top = 115 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Shounen Ai' ParentFont = False @@ -1129,11 +1422,11 @@ object MainForm: TMainForm TabOrder = 29 end object ckFilterSliceofLife: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own.' Top = 138 - Width = 81 + Width = 100 AllowGrayed = True Caption = 'Slice of Life' ParentFont = False @@ -1142,11 +1435,11 @@ object MainForm: TMainForm TabOrder = 30 end object ckFilterSmut: TCheckBox - Left = 296 + Left = 335 Height = 19 Hint = 'Deals with series that are considered profane or offensive, particularly with regards to sexual content.' Top = 161 - Width = 81 + Width = 100 HelpType = htKeyword AllowGrayed = True Caption = 'Smut' @@ -1156,11 +1449,11 @@ object MainForm: TMainForm TabOrder = 31 end object ckFilterSports: TCheckBox - Left = 387 + Left = 439 Height = 19 Hint = 'As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few.' Top = 0 - Width = 87 + Width = 103 AllowGrayed = True Caption = 'Sports' ParentFont = False @@ -1169,11 +1462,11 @@ object MainForm: TMainForm TabOrder = 32 end object ckFilterSupernatural: TCheckBox - Left = 387 + Left = 439 Height = 19 Hint = 'Usually entails amazing and unexplained powers or events which defy the laws of physics.' Top = 23 - Width = 87 + Width = 103 AllowGrayed = True Caption = 'Supernatural' ParentFont = False @@ -1182,11 +1475,11 @@ object MainForm: TMainForm TabOrder = 33 end object ckFilterTragedy: TCheckBox - Left = 387 + Left = 439 Height = 19 Hint = 'Contains events resulting in great loss and misfortune.' Top = 46 - Width = 87 + Width = 103 AllowGrayed = True Caption = 'Tragedy' ParentFont = False @@ -1195,11 +1488,11 @@ object MainForm: TMainForm TabOrder = 34 end object ckFilterYaoi: TCheckBox - Left = 387 + Left = 439 Height = 19 Hint = 'This work usually involves intimate relationships between men.' Top = 69 - Width = 87 + Width = 103 AllowGrayed = True Caption = 'Yaoi' ParentFont = False @@ -1208,11 +1501,11 @@ object MainForm: TMainForm TabOrder = 35 end object ckFilterYuri: TCheckBox - Left = 387 + Left = 439 Height = 19 Hint = 'This work usually involves intimate relationships between women.' Top = 92 - Width = 87 + Width = 103 AllowGrayed = True Caption = 'Yuri' ParentFont = False @@ -1221,11 +1514,11 @@ object MainForm: TMainForm TabOrder = 36 end object ckFilterWeebtons: TCheckBox - Left = 387 + Left = 439 Height = 19 Hint = 'Weebtoons' Top = 115 - Width = 87 + Width = 103 AllowGrayed = True Caption = 'Weebtoons' ParentFont = False @@ -1234,198 +1527,54 @@ object MainForm: TMainForm TabOrder = 37 end end - object pnFilter: TPanel + object Panel3: TPanel Left = 0 - Height = 192 - Top = 232 - Width = 606 + Height = 35 + Top = 381 + Width = 558 Align = alTop + AutoSize = True BevelOuter = bvNone - ClientHeight = 192 - ClientWidth = 606 - ParentFont = False - TabOrder = 1 - object rbOne: TRadioButton - Left = 323 - Height = 19 - Top = 32 - Width = 169 - Caption = 'Have one of genres checked' - ParentFont = False - TabOrder = 1 - end - object rbAll: TRadioButton - Left = 323 - Height = 19 - Top = 8 - Width = 142 - Caption = 'Have all genre checked' - Checked = True - ParentFont = False - TabOrder = 0 - TabStop = True - end - object cbOnlyNew: TCheckBox - Left = 323 - Height = 19 - Top = 56 - Width = 146 - Caption = 'Search only new manga' - ParentFont = False - TabOrder = 2 - end - object edFilterTitle: TEdit - Left = 135 - Height = 23 - Top = 8 - Width = 175 - TabOrder = 3 - TextHint = 'Title' - end - object edFilterArtists: TEdit - Left = 135 - Height = 23 - Top = 56 - Width = 175 - TabOrder = 4 - TextHint = 'Artist' - end - object edFilterAuthors: TEdit - Left = 135 - Height = 23 - Top = 32 - Width = 175 - TabOrder = 5 - TextHint = 'Author' - end - object lbFilterTitle: TLabel - Left = 23 - Height = 17 - Top = 8 - Width = 28 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Title' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object lbFilterAuthors: TLabel - Left = 23 - Height = 17 - Top = 32 - Width = 43 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Author' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object lbFilterArtists: TLabel - Left = 23 - Height = 17 - Top = 56 - Width = 34 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Artist' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object cbFilterStatus: TComboBox - Left = 135 - Height = 23 - Top = 80 - Width = 175 - ItemHeight = 15 - ItemIndex = 2 - Items.Strings = ( - 'Completed' - 'Ongoing' - '<none>' - ) - Style = csDropDownList - TabOrder = 6 - Text = '<none>' - end - object lbFilterStatus: TLabel - Left = 23 - Height = 17 - Top = 80 - Width = 38 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Status' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object lbFilterSummary: TLabel - Left = 23 - Height = 17 - Top = 104 - Width = 59 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Summary' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edFilterSummary: TEdit - Left = 135 - Height = 23 - Top = 104 - Width = 175 - TabOrder = 7 - TextHint = 'Part of summary' - end - object btRemoveFilterLarge: TBitBtn - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 191 - Height = 37 - Hint = 'Remove filter' - Top = 139 - Width = 136 - Caption = 'Remove filter' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 3 + ClientHeight = 35 + ClientWidth = 558 + TabOrder = 3 + object btFilter: TBitBtn + Left = 4 + Height = 27 + Top = 4 + Width = 78 + Caption = 'Filter' Font.Height = -13 Font.Style = [fsBold] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000080000000000005A000000770000008000000000000000 + 003300000022000000089C5106999C51065CA75C0D00B56A1800000000000000 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A000000110000000400005A00000077000000770000008000000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578040426000000 - 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 - 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 - A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 - A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C - 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C + 001A0000001100000004A75C0DCCA75C0DCCA95E0E5CB56A1800000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578B76C1999B56A + 18CCB56A18CCB56A18CCB56A18CCFFC538FFB56A18CCB76C195C000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097EC37923CCFFE3 + 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87D0852D99D287 + 2ECCD2872ECCD2872ECCD2872ECCFFE597FFD2872ECCD0852D5C000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B89714C1F00D58A + 3100D58A3100D98E3400DF9438CCDF9438CCDE93375CD2872E001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B8912121200A870 + 2D00D58A3100E69B3D00E79C3E99E79C3E5CDF943800D2872E00363636002C2C 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 250027275200101090000000AA000000AA000000AA000000A700363636002C2C + 25005C4A3300E69B3D00E89D3F00E89D3F00DF943800D2872E00363636002C2C 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535004343430035355F00121291000000AA000000A700363636002C2C + 252D353535006B594100E89D3F00E89D3F00DF943800D2872E00363636002C2C 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A43434300464646004646460035355F0023237700363636002C2C + 257E3535352A434343006F5D450097724300936D3F008C673A00363636002C2C 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA @@ -1439,51 +1588,44 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btRemoveFilterClick + OnClick = btFilterClick ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 8 - end - object cbSearchFromAllSites: TCheckBox - Left = 323 - Height = 19 - Top = 80 - Width = 149 - Caption = 'Search in all manga sites' - TabOrder = 9 + TabOrder = 1 end - object btFilter: TBitBtn - Left = 39 - Height = 37 - Top = 139 - Width = 130 - Caption = 'Filter' + object btRemoveFilterLarge: TBitBtn + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 86 + Height = 27 + Hint = 'Remove filter' + Top = 4 + Width = 129 + Caption = 'Remove filter' Font.Height = -13 Font.Style = [fsBold] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000089C5106999C51065CA75C0D00B56A1800000000000000 + 003300000022000000080000000000005A000000770000008000000000000000 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A0000001100000004A75C0DCCA75C0DCCA95E0E5CB56A1800000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578B76C1999B56A - 18CCB56A18CCB56A18CCB56A18CCFFC538FFB56A18CCB76C195C000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097EC37923CCFFE3 - 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87D0852D99D287 - 2ECCD2872ECCD2872ECCD2872ECCFFE597FFD2872ECCD0852D5C000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B89714C1F00D58A - 3100D58A3100D98E3400DF9438CCDF9438CCDE93375CD2872E001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B8912121200A870 - 2D00D58A3100E69B3D00E79C3E99E79C3E5CDF943800D2872E00363636002C2C + 001A000000110000000400005A00000077000000770000008000000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578040426000000 + 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 + 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 + A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 + A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C + 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 25005C4A3300E69B3D00E89D3F00E89D3F00DF943800D2872E00363636002C2C + 250027275200101090000000AA000000AA000000AA000000A700363636002C2C 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535006B594100E89D3F00E89D3F00DF943800D2872E00363636002C2C + 252D353535004343430035355F00121291000000AA000000A700363636002C2C 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A434343006F5D450097724300936D3F008C673A00363636002C2C + 257E3535352A43434300464646004646460035355F0023237700363636002C2C 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA @@ -1497,15 +1639,17 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btFilterClick + OnClick = btRemoveFilterClick ParentFont = False - TabOrder = 10 + ParentShowHint = False + ShowHint = True + TabOrder = 0 end object btFilterReset: TBitBtn - Left = 345 - Height = 37 - Top = 139 - Width = 128 + Left = 219 + Height = 27 + Top = 4 + Width = 116 Caption = 'Reset value' Font.Height = -13 Font.Style = [fsBold] @@ -1547,83 +1691,20 @@ object MainForm: TMainForm } OnClick = btFilterResetClick ParentFont = False - TabOrder = 11 - end - object cbUseRegExpr: TCheckBox - Left = 323 - Height = 19 - Top = 104 - Width = 118 - Caption = 'Regular Expression' - TabOrder = 12 - end - end - object pnCustomGenre: TPanel - Left = 0 - Height = 42 - Top = 190 - Width = 606 - Align = alTop - BevelOuter = bvNone - ClientHeight = 42 - ClientWidth = 606 - TabOrder = 2 - object lbFilterCustomGenres: TLabel - Left = 23 - Height = 17 - Top = 10 - Width = 93 - Alignment = taRightJustify - BidiMode = bdRightToLeft - Caption = 'Custom Genres' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edCustomGenres: TEdit - Left = 135 - Height = 23 - Top = 10 - Width = 416 - ParentFont = False - TabOrder = 0 - TextHint = 'Input custom genres, separated by comma' - end - object lbFilterHint: TLabel - Left = 555 - Height = 15 - Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' - Top = 13 - Width = 13 - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object Bevel1: TBevel - Left = 0 - Height = 5 - Top = 37 - Width = 606 - Align = alBottom - Shape = bsBottomLine + TabOrder = 2 end end end end object tsFavorites: TTabSheet Caption = 'Favorites' - ClientHeight = 521 - ClientWidth = 606 + ClientHeight = 511 + ClientWidth = 525 object btFavoritesCheckNewChapter: TBitBtn Left = 33 Height = 40 - Top = 441 - Width = 545 + Top = 431 + Width = 458 Anchors = [akLeft, akRight, akBottom] Caption = 'Check for new chapter' Glyph.Data = { @@ -1666,15 +1747,13 @@ object MainForm: TMainForm TabOrder = 1 end object vtFavorites: TVirtualStringTree - Left = 2 - Height = 430 + Left = 4 + Height = 420 Top = 4 - Width = 600 + Width = 517 Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Left = 2 - BorderSpacing.Top = 4 - BorderSpacing.Right = 4 + BorderSpacing.Around = 4 DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < @@ -1732,8 +1811,8 @@ object MainForm: TMainForm object btFavoritesImport: TBitBtn Left = 33 Height = 24 - Top = 487 - Width = 545 + Top = 477 + Width = 458 Anchors = [akLeft, akRight, akBottom] Caption = 'Import list' Glyph.Data = { @@ -1777,10 +1856,10 @@ object MainForm: TMainForm TabOrder = 2 end object btCancelFavoritesCheck: TSpeedButton - Left = 538 + Left = 457 Height = 40 - Top = 441 - Width = 40 + Top = 431 + Width = 34 Anchors = [akRight, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -1824,13 +1903,13 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 521 - ClientWidth = 606 + ClientHeight = 462 + ClientWidth = 558 object pnOptions: TPageControl Left = 8 - Height = 444 + Height = 385 Top = 8 - Width = 587 + Width = 539 ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False @@ -1838,136 +1917,82 @@ object MainForm: TMainForm TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' - ClientHeight = 416 - ClientWidth = 579 - object cbLanguages: TComboBox - Left = 20 - Height = 23 - Top = 34 - Width = 212 - ItemHeight = 15 - Items.Strings = ( - 'English' - ) - ParentFont = False - Style = csDropDownList - TabOrder = 0 - end - object lbOptionLanguage: TLabel - Left = 20 - Height = 15 - Top = 18 - Width = 55 - Caption = 'Language:' - ParentColor = False - end - object seOptionNewMangaTime: TSpinEdit - Left = 20 - Height = 23 - Top = 112 - Width = 58 - MaxValue = 365 - MinValue = 1 - ParentFont = False - TabOrder = 1 - Value = 1 - end - object lbOptionNewMangaTime: TLabel - Left = 86 - Height = 15 - Top = 115 - Width = 238 - Caption = 'New manga based on it''s update time (days)' - ParentColor = False - ParentFont = False - end + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 357 + ClientWidth = 531 object cbOptionMinimizeToTray: TCheckBox - Left = 20 + AnchorSideLeft.Control = seOptionNewMangaTime + AnchorSideTop.Control = seOptionNewMangaTime + AnchorSideTop.Side = asrBottom + Left = 4 Height = 19 - Top = 200 + Top = 159 Width = 106 + BorderSpacing.Top = 20 Caption = 'Minimize to tray' ParentFont = False + TabOrder = 0 + end + object cbOptionOneInstanceOnly: TCheckBox + AnchorSideLeft.Control = cbOptionMinimizeToTray + AnchorSideTop.Control = cbOptionMinimizeToTray + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 19 + Top = 182 + Width = 177 + Caption = 'Permit only one FMD running' + ParentFont = False TabOrder = 2 end - object cbOptionLetFMDDo: TComboBox - Left = 20 - Height = 23 - Top = 80 - Width = 212 - ItemHeight = 15 - Items.Strings = ( - 'Do nothing' - 'Exit FMD' - 'Shutdown' - 'Hibernate' - ) + object cbOptionLiveSearch: TCheckBox + AnchorSideLeft.Control = cbOptionOneInstanceOnly + AnchorSideTop.Control = cbOptionOneInstanceOnly + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 19 + Top = 205 + Width = 210 + Caption = 'Enable live search (slow on long list)' ParentFont = False - Style = csDropDownList TabOrder = 3 end - object lbOptionLetFMDDo: TLabel - Left = 20 - Height = 15 - Top = 64 - Width = 117 - Caption = 'After download finish:' - ParentColor = False - end object gbOptionExternal: TGroupBox - Left = 20 - Height = 132 - Top = 228 + AnchorSideLeft.Control = cbOptionLiveSearch + AnchorSideTop.Control = cbOptionLiveSearch + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 118 + Top = 244 Width = 520 Anchors = [akTop, akLeft, akRight] + BorderSpacing.Top = 20 Caption = 'External program' - ClientHeight = 112 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 98 ClientWidth = 516 ParentFont = False - TabOrder = 4 - object edOptionExternalParams: TEdit - Left = 13 - Height = 23 - Top = 74 - Width = 467 - Anchors = [akTop, akLeft, akRight] - TabOrder = 0 - TextHint = 'External program parameters' - end + TabOrder = 1 object lbOptionExternal: TLabel - Left = 13 + Left = 4 Height = 15 - Top = 6 - Width = 213 + Top = 4 + Width = 508 + Align = alTop Caption = 'Open manga by using external program:' ParentColor = False end - object lbOptionExternalParamsHint: TLabel - Left = 485 - Height = 15 - Top = 77 - Width = 13 - Anchors = [akTop, akRight] - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object lbOptionExternalParams: TLabel - Left = 13 - Height = 15 - Top = 56 - Width = 62 - Caption = 'Parameters:' - ParentColor = False - end object edOptionExternalPath: TFileNameEdit - Left = 13 + Left = 4 Height = 23 - Top = 24 - Width = 491 + Top = 23 + Width = 508 FilterIndex = 0 HideDirectories = False ButtonWidth = 23 @@ -2008,66 +2033,183 @@ object MainForm: TMainForm CC810088CC810088CC810088CC810088CC610087CB000087CB00 } NumGlyphs = 1 - Anchors = [akTop, akLeft, akRight] + Align = alTop MaxLength = 0 TabOrder = 1 TextHint = 'External program path' end + object lbOptionExternalParams: TLabel + Left = 4 + Height = 15 + Top = 50 + Width = 508 + Align = alTop + Caption = 'Parameters:' + ParentColor = False + end + object edOptionExternalParams: TEdit + AnchorSideLeft.Control = lbOptionExternalParams + AnchorSideTop.Control = lbOptionExternalParams + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 69 + Width = 481 + Anchors = [akTop, akLeft, akRight] + TabOrder = 0 + TextHint = 'External program parameters' + end + object lbOptionExternalParamsHint: TLabel + AnchorSideLeft.Control = edOptionExternalParams + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edOptionExternalParams + AnchorSideTop.Side = asrCenter + Left = 489 + Height = 15 + Top = 73 + Width = 13 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end end - object cbOptionOneInstanceOnly: TCheckBox - Left = 20 - Height = 19 - Top = 176 - Width = 177 - Caption = 'Permit only one FMD running' + object lbOptionLanguage: TLabel + Left = 4 + Height = 15 + Top = 8 + Width = 523 + Align = alTop + Caption = 'Language:' + ParentColor = False + end + object cbLanguages: TComboBox + AnchorSideLeft.Control = lbOptionLanguage + AnchorSideTop.Control = lbOptionLanguage + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 27 + Width = 224 + ItemHeight = 15 + Items.Strings = ( + 'English' + ) + ParentFont = False + Style = csDropDownList + TabOrder = 4 + end + object lbOptionLetFMDDo: TLabel + AnchorSideLeft.Control = cbLanguages + AnchorSideTop.Control = cbLanguages + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 15 + Top = 54 + Width = 117 + Caption = 'After download finish:' + ParentColor = False + end + object cbOptionLetFMDDo: TComboBox + AnchorSideLeft.Control = lbOptionLetFMDDo + AnchorSideTop.Control = lbOptionLetFMDDo + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 73 + Width = 224 + ItemHeight = 15 + Items.Strings = ( + 'Do nothing' + 'Exit FMD' + 'Shutdown' + 'Hibernate' + ) + ParentFont = False + Style = csDropDownList + TabOrder = 5 + end + object seOptionNewMangaTime: TSpinEdit + AnchorSideLeft.Control = cbOptionLetFMDDo + AnchorSideTop.Control = cbOptionLetFMDDo + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 116 + Width = 50 + BorderSpacing.Top = 20 + MaxValue = 365 + MinValue = 1 ParentFont = False - TabOrder = 5 + TabOrder = 6 + Value = 1 end - object cbOptionLiveSearch: TCheckBox - Left = 20 - Height = 19 - Top = 152 - Width = 210 - Caption = 'Enable live search (slow on long list)' + object lbOptionNewMangaTime: TLabel + AnchorSideLeft.Control = seOptionNewMangaTime + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionNewMangaTime + AnchorSideTop.Side = asrCenter + Left = 58 + Height = 15 + Top = 120 + Width = 238 + Caption = 'New manga based on it''s update time (days)' + ParentColor = False ParentFont = False - TabOrder = 6 end end object tsView: TTabSheet Caption = 'View' - ClientHeight = 416 - ClientWidth = 579 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 357 + ClientWidth = 531 object cbOptionShowDownloadToolbar: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 232 - Width = 151 + Top = 177 + Width = 523 + Align = alTop Caption = 'Show downloads toolbar' ParentFont = False TabOrder = 0 end object gbDropTarget: TGroupBox - Left = 16 - Height = 200 - Top = 16 - Width = 312 + Left = 4 + Height = 165 + Top = 8 + Width = 523 + Align = alTop + AutoSize = True Caption = 'Drop Box' - ClientHeight = 180 - ClientWidth = 308 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 145 + ClientWidth = 519 TabOrder = 1 object ckDropTarget: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 9 - Width = 100 + Top = 4 + Width = 511 + Align = alTop Caption = 'Show Drop Box' ParentFont = False TabOrder = 0 end object tbDropTargetOpacity: TTrackBar - Left = 16 + AnchorSideLeft.Control = lbDropTargetOpacity + AnchorSideTop.Control = lbDropTargetOpacity + AnchorSideTop.Side = asrBottom + Left = 4 Height = 33 - Top = 128 + Top = 108 Width = 280 Frequency = 15 Max = 255 @@ -2077,18 +2219,24 @@ object MainForm: TMainForm TabOrder = 1 end object lbDropTargetOpacity: TLabel - Left = 16 + AnchorSideLeft.Control = rgDropTargetMode + AnchorSideTop.Control = rgDropTargetMode + AnchorSideTop.Side = asrBottom + Left = 4 Height = 15 - Top = 112 + Top = 89 Width = 41 Caption = 'Opacity' ParentColor = False ParentFont = False end object rgDropTargetMode: TRadioGroup - Left = 16 + AnchorSideLeft.Control = ckDropTarget + AnchorSideTop.Control = ckDropTarget + AnchorSideTop.Side = asrBottom + Left = 4 Height = 58 - Top = 40 + Top = 27 Width = 120 AutoFill = True AutoSize = True @@ -2112,10 +2260,11 @@ object MainForm: TMainForm end end object cbOptionEnableLoadCover: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 256 - Width = 153 + Top = 200 + Width = 523 + Align = alTop Caption = 'Enable load manga cover' ParentFont = False TabOrder = 2 @@ -2123,64 +2272,74 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 416 - ClientWidth = 579 + ClientHeight = 406 + ClientWidth = 498 object sbDownloadConnections: TScrollBox Left = 0 - Height = 416 + Height = 406 Top = 0 - Width = 579 - HorzScrollBar.Page = 457 - VertScrollBar.Page = 304 + Width = 498 + HorzScrollBar.Page = 455 + VertScrollBar.Page = 268 Align = alClient BorderStyle = bsNone - ClientHeight = 416 - ClientWidth = 579 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 406 + ClientWidth = 498 TabOrder = 0 object cbOptionUseProxy: TCheckBox - Left = 12 + AnchorSideLeft.Control = seOptionConnectionTimeout + AnchorSideTop.Control = seOptionConnectionTimeout + AnchorSideTop.Side = asrBottom + Left = 4 Height = 19 - Top = 160 + Top = 132 Width = 71 + BorderSpacing.Top = 20 Caption = 'Use proxy' OnChange = cbOptionUseProxyChange ParentFont = False TabOrder = 0 end object gbOptionProxy: TGroupBox - Left = 12 - Height = 120 - Top = 184 - Width = 561 - Anchors = [akTop, akLeft, akRight] + AnchorSideLeft.Control = cbOptionUseProxy + AnchorSideTop.Control = cbOptionUseProxy + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 105 + Top = 155 + Width = 403 + AutoSize = True Caption = 'Proxy config' - ClientHeight = 100 - ClientWidth = 557 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 4 + ClientHeight = 85 + ClientWidth = 399 Enabled = False ParentFont = False TabOrder = 1 object lbOptionHost: TLabel - Left = 16 - Height = 15 - Top = 40 - Width = 25 + Left = 4 + Height = 23 + Top = 4 + Width = 26 Caption = 'Host' ParentColor = False ParentFont = False end - object lbOptionPort: TLabel - Left = 16 - Height = 15 - Top = 72 - Width = 22 - Caption = 'Port' - ParentColor = False - end object edOptionHost: TEdit - Left = 57 + Left = 34 Height = 23 - Top = 38 - Width = 154 + Top = 4 + Width = 150 + Constraints.MinWidth = 150 Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Default' @@ -2188,45 +2347,24 @@ object MainForm: TMainForm TabOrder = 0 TextHint = 'Proxy host/IP' end - object edOptionPort: TEdit - Left = 57 - Height = 23 - Top = 70 - Width = 154 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Default' - ParentFont = False - TabOrder = 1 - TextHint = 'Proxy Port' - end object lbOptionUser: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 232 - Height = 15 - Top = 40 + Left = 188 + Height = 23 + Top = 4 Width = 53 Caption = 'Username' ParentColor = False end - object lbOptionPass: TLabel - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 233 - Height = 15 - Top = 72 - Width = 50 - Caption = 'Password' - ParentColor = False - end object edOptionUser: TEdit AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 297 + Left = 245 Height = 23 - Top = 38 - Width = 154 + Top = 4 + Width = 150 + Constraints.MinWidth = 150 Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Default' @@ -2234,13 +2372,43 @@ object MainForm: TMainForm TabOrder = 2 TextHint = 'Proxy username' end + object lbOptionPort: TLabel + Left = 4 + Height = 23 + Top = 31 + Width = 26 + Caption = 'Port' + ParentColor = False + end + object edOptionPort: TEdit + Left = 34 + Height = 23 + Top = 31 + Width = 150 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Default' + ParentFont = False + TabOrder = 1 + TextHint = 'Proxy Port' + end + object lbOptionPass: TLabel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 188 + Height = 23 + Top = 31 + Width = 53 + Caption = 'Password' + ParentColor = False + end object edOptionPass: TEdit AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 297 + Left = 245 Height = 23 - Top = 70 - Width = 154 + Top = 31 + Width = 150 Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Default' @@ -2248,11 +2416,19 @@ object MainForm: TMainForm TabOrder = 3 TextHint = 'Proxy password' end + object lbOptionProxyType: TLabel + Left = 4 + Height = 23 + Top = 58 + Width = 26 + Caption = 'Type' + ParentColor = False + end object cbOptionProxyType: TComboBox - Left = 57 + Left = 34 Height = 23 - Top = 6 - Width = 154 + Top = 58 + Width = 150 ItemHeight = 15 ItemIndex = 0 Items.Strings = ( @@ -2264,20 +2440,12 @@ object MainForm: TMainForm TabOrder = 4 Text = 'HTTP' end - object lbOptionProxyType: TLabel - Left = 15 - Height = 15 - Top = 8 - Width = 26 - Caption = 'Type' - ParentColor = False - end end object seOptionMaxParallel: TSpinEdit - Left = 12 + Left = 4 Height = 23 - Top = 26 - Width = 48 + Top = 8 + Width = 52 MaxValue = 8 MinValue = 1 ParentFont = False @@ -2286,28 +2454,29 @@ object MainForm: TMainForm Value = 1 end object lbOptionMaxParallel: TLabel - Left = 66 + AnchorSideLeft.Control = seOptionMaxParallel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionMaxParallel + AnchorSideTop.Side = asrCenter + Left = 60 Height = 15 - Top = 29 + Top = 12 Width = 292 Caption = 'Number of downloaded tasks at the same time (Max: 8)' ParentColor = False ParentFont = False end - object lbOptionMaxThread: TLabel - Left = 66 - Height = 15 - Top = 61 - Width = 337 - Caption = 'Number of downloaded files per task at the same time (Max: 32)' - ParentColor = False - ParentFont = False - end object seOptionMaxThread: TSpinEdit - Left = 12 + AnchorSideLeft.Control = seOptionMaxParallel + AnchorSideTop.Control = seOptionMaxParallel + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = seOptionMaxParallel + AnchorSideRight.Side = asrBottom + Left = 4 Height = 23 - Top = 58 - Width = 48 + Top = 35 + Width = 52 + Anchors = [akTop, akLeft, akRight] MaxValue = 32 MinValue = 1 ParentFont = False @@ -2315,30 +2484,59 @@ object MainForm: TMainForm TabOrder = 3 Value = 1 end + object lbOptionMaxThread: TLabel + AnchorSideLeft.Control = seOptionMaxThread + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionMaxThread + AnchorSideTop.Side = asrCenter + Left = 60 + Height = 15 + Top = 39 + Width = 337 + Caption = 'Number of downloaded files per task at the same time (Max: 32)' + ParentColor = False + ParentFont = False + end object seOptionMaxRetry: TSpinEdit - Left = 12 + AnchorSideLeft.Control = seOptionMaxParallel + AnchorSideTop.Control = seOptionMaxThread + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = seOptionMaxParallel + AnchorSideRight.Side = asrBottom + Left = 4 Height = 23 - Top = 90 - Width = 48 + Top = 62 + Width = 52 + Anchors = [akTop, akLeft, akRight] MinValue = -1 ParentFont = False ParentShowHint = False TabOrder = 4 end object lbOptionMaxRetry: TLabel - Left = 66 + AnchorSideLeft.Control = seOptionMaxRetry + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionMaxRetry + AnchorSideTop.Side = asrCenter + Left = 60 Height = 15 - Top = 93 + Top = 66 Width = 391 Caption = 'Number of retry times if tasks have download problems (-1 = always retry)' ParentColor = False ParentFont = False end object seOptionConnectionTimeout: TSpinEdit - Left = 12 + AnchorSideLeft.Control = seOptionMaxRetry + AnchorSideTop.Control = seOptionMaxRetry + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = seOptionMaxRetry + AnchorSideRight.Side = asrBottom + Left = 4 Height = 23 - Top = 120 - Width = 48 + Top = 89 + Width = 52 + Anchors = [akTop, akLeft, akRight] MaxValue = 300 MinValue = 1 ParentFont = False @@ -2347,9 +2545,13 @@ object MainForm: TMainForm Value = 30 end object lbOptionConnectionTimeout: TLabel - Left = 66 + AnchorSideLeft.Control = seOptionConnectionTimeout + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionConnectionTimeout + AnchorSideTop.Side = asrCenter + Left = 60 Height = 15 - Top = 123 + Top = 93 Width = 161 Caption = 'Connection timeout (seconds)' ParentColor = False @@ -2359,27 +2561,37 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 416 - ClientWidth = 579 + ClientHeight = 357 + ClientWidth = 531 object sbSaveTo: TScrollBox Left = 0 - Height = 416 + Height = 357 Top = 0 - Width = 579 - HorzScrollBar.Page = 537 - VertScrollBar.Page = 416 + Width = 531 + HorzScrollBar.Page = 198 + VertScrollBar.Page = 357 Align = alClient BorderStyle = bsNone - ClientHeight = 416 - ClientWidth = 562 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 357 + ClientWidth = 514 TabOrder = 0 object rgOptionCompress: TRadioGroup - Left = 20 + AnchorSideLeft.Control = lbDefaultDownloadPath + AnchorSideTop.Control = edOptionDefaultPath + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = lbDefaultDownloadPath + AnchorSideRight.Side = asrBottom + Left = 4 Height = 60 - Top = 66 - Width = 503 + Top = 54 + Width = 506 Anchors = [akTop, akLeft, akRight] AutoFill = True + BorderSpacing.Top = 4 Caption = 'Save downloaded chapters as' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 @@ -2390,7 +2602,7 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 40 - ClientWidth = 499 + ClientWidth = 502 Columns = 4 ItemIndex = 0 Items.Strings = ( @@ -2401,71 +2613,116 @@ object MainForm: TMainForm ) OnSelectionChanged = rgOptionCompressSelectionChanged ParentFont = False - TabOrder = 0 + TabOrder = 2 end object gbOptionRenaming: TGroupBox - Left = 20 - Height = 254 - Top = 170 - Width = 503 + AnchorSideLeft.Control = lbDefaultDownloadPath + AnchorSideTop.Control = seOptionPDFQuality + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = lbDefaultDownloadPath + AnchorSideRight.Side = asrBottom + Left = 4 + Height = 237 + Top = 145 + Width = 506 Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Top = 4 Caption = 'Renaming' - ClientHeight = 234 - ClientWidth = 499 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 217 + ClientWidth = 502 ParentFont = False - TabOrder = 1 + TabOrder = 4 object cbOptionRemoveMangaNameFromChapter: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 104 - Width = 208 + Top = 50 + Width = 494 + Align = alTop Caption = 'Remove manga name from chapter' ParentFont = False - TabOrder = 7 + TabOrder = 3 end object cbOptionGenerateMangaFolderName: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 30 - Width = 261 + Top = 27 + Width = 494 + Align = alTop Caption = 'Auto generate folder based on manga''s name' OnChange = cbOptionGenerateMangaFolderNameChange ParentFont = False TabOrder = 0 end + object lbOptionMangaCustomRename: TLabel + Left = 4 + Height = 15 + Top = 79 + Width = 494 + Align = alTop + BorderSpacing.Top = 10 + Caption = 'Manga folder name:' + ParentColor = False + end + object edOptionMangaCustomRename: TEdit + AnchorSideLeft.Control = lbOptionMangaCustomRename + AnchorSideTop.Control = lbOptionMangaCustomRename + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = lbOptionMangaCustomRename + AnchorSideRight.Side = asrBottom + Left = 4 + Height = 23 + Top = 98 + Width = 308 + TabOrder = 4 + TextHint = 'Custom rename' + end object cbOptionChangeUnicodeCharacter: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 8 - Width = 517 + Top = 4 + Width = 494 + Align = alTop Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' ParentFont = False TabOrder = 1 end object edOptionChapterCustomRename: TEdit - Left = 16 + AnchorSideLeft.Control = lbOptionCustomRename + AnchorSideTop.Control = lbOptionCustomRename + AnchorSideTop.Side = asrBottom + Left = 4 Height = 23 - Top = 200 - Width = 417 - Anchors = [akTop, akLeft, akRight] + Top = 144 + Width = 308 TabOrder = 2 TextHint = 'Custom rename' end object lbOptionCustomRename: TLabel - Left = 16 + AnchorSideLeft.Control = edOptionMangaCustomRename + AnchorSideTop.Control = edOptionMangaCustomRename + AnchorSideTop.Side = asrBottom + Left = 4 Height = 15 - Top = 184 + Top = 125 Width = 112 Caption = 'Chapter folder name:' ParentColor = False end object lbOptionChapterCustomRenameHint: TLabel - Left = 436 + AnchorSideLeft.Control = edOptionChapterCustomRename + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edOptionChapterCustomRename + AnchorSideTop.Side = asrCenter + Left = 316 Height = 15 Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' - Top = 203 + Top = 148 Width = 13 - Anchors = [akTop, akRight] Caption = '[?]' Font.Color = clBlue ParentColor = False @@ -2474,129 +2731,104 @@ object MainForm: TMainForm ShowHint = True end object lbOptionRenameDigits: TLabel - Left = 16 + AnchorSideLeft.Control = edOptionChapterCustomRename + AnchorSideTop.Control = edOptionChapterCustomRename + AnchorSideTop.Side = asrBottom + Left = 4 Height = 15 - Top = 128 + Top = 171 Width = 78 Caption = 'Rename digits' ParentColor = False end + object lbOptionMangaCustomRenameHint: TLabel + AnchorSideLeft.Control = edOptionMangaCustomRename + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edOptionMangaCustomRename + AnchorSideTop.Side = asrCenter + Left = 316 + Height = 15 + Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10#13#10'Note:'#13#10'Manga folder name must have at least %MANGA%.' + Top = 102 + Width = 13 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end object seOptionDigitVolume: TSpinEdit - Left = 88 + AnchorSideLeft.Control = cbOptionDigitVolume + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cbOptionDigitVolume + Left = 69 Height = 23 - Top = 150 + Top = 190 Width = 50 + BorderSpacing.Left = 4 MaxValue = 10 MinValue = 1 - TabOrder = 3 + TabOrder = 5 Value = 1 end object seOptionDigitChapter: TSpinEdit - Left = 224 + AnchorSideLeft.Control = cbOptionDigitChapter + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cbOptionDigitChapter + Left = 205 Height = 23 - Top = 150 + Top = 190 Width = 50 + BorderSpacing.Left = 4 MaxValue = 10 MinValue = 1 - TabOrder = 4 + TabOrder = 6 Value = 1 end object cbOptionDigitVolume: TCheckBox - Left = 19 + AnchorSideLeft.Control = lbOptionRenameDigits + AnchorSideTop.Control = lbOptionRenameDigits + AnchorSideTop.Side = asrBottom + Left = 4 Height = 19 - Top = 152 + Top = 190 Width = 61 Caption = 'Volume' OnChange = cbOptionDigitVolumeChange - TabOrder = 5 + TabOrder = 7 end object cbOptionDigitChapter: TCheckBox - Left = 152 + AnchorSideLeft.Control = seOptionDigitVolume + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionDigitVolume + Left = 139 Height = 19 - Top = 152 + Top = 190 Width = 62 + BorderSpacing.Left = 20 Caption = 'Chapter' OnChange = cbOptionDigitChapterChange - TabOrder = 6 - end - object edOptionMangaCustomRename: TEdit - Left = 16 - Height = 23 - Top = 72 - Width = 417 - Anchors = [akTop, akLeft, akRight] TabOrder = 8 - TextHint = 'Custom rename' - end - object lbOptionMangaCustomRename: TLabel - Left = 16 - Height = 15 - Top = 56 - Width = 107 - Caption = 'Manga folder name:' - ParentColor = False - end - object lbOptionMangaCustomRenameHint: TLabel - Left = 436 - Height = 15 - Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10#13#10'Note:'#13#10'Manga folder name must have at least %MANGA%.' - Top = 75 - Width = 13 - Anchors = [akTop, akRight] - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True end end - object seOptionPDFQuality: TSpinEdit - Left = 20 - Height = 23 - Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 133 - Width = 50 - Enabled = False - MinValue = 5 - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 2 - Value = 100 - end - object lbOptionPDFQuality: TLabel - Left = 79 - Height = 15 - Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' - Top = 136 - Width = 119 - Caption = 'PDF compression level' - Enabled = False - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - object lbOptionPDFQualityHint: TLabel - Left = 224 + object lbDefaultDownloadPath: TLabel + Left = 4 Height = 15 - Top = 136 - Width = 13 - Caption = '[?]' - Enabled = False - Font.Color = clBlue + Top = 8 + Width = 506 + Align = alTop + Caption = 'Choose the default download path:' ParentColor = False ParentFont = False - ParentShowHint = False - ShowHint = True end - object btOptionBrowse: TSpeedButton - Left = 495 + object edOptionDefaultPath: TDirectoryEdit + Left = 4 Height = 23 - Top = 34 - Width = 23 - Anchors = [akTop, akRight] + Top = 27 + Width = 506 + ShowHidden = False + ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000000000 @@ -2633,66 +2865,129 @@ object MainForm: TMainForm CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 CC810088CC810088CC810088CC810088CC610087CB000087CB00 } - OnClick = btOptionBrowseClick + NumGlyphs = 1 + Align = alTop + MaxLength = 0 + ParentFont = False + TabOrder = 0 + TextHint = 'Default download path' + end + object Panel8: TPanel + Left = 4 + Height = 0 + Top = 54 + Width = 506 + Align = alTop + AutoSize = True + BevelOuter = bvNone + TabOrder = 1 + end + object lbOptionPDFQualityHint: TLabel + AnchorSideLeft.Control = lbOptionPDFQuality + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbOptionPDFQuality + Left = 181 + Height = 15 + Top = 122 + Width = 13 + BorderSpacing.Left = 4 + Caption = '[?]' + Enabled = False + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True end - object edOptionDefaultPath: TEdit - Left = 20 + object seOptionPDFQuality: TSpinEdit + AnchorSideLeft.Control = lbDefaultDownloadPath + AnchorSideTop.Control = rgOptionCompress + AnchorSideTop.Side = asrBottom + Left = 4 Height = 23 - Top = 34 - Width = 473 - Anchors = [akTop, akLeft, akRight] + Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' + Top = 118 + Width = 50 + BorderSpacing.Top = 4 + Enabled = False + MinValue = 5 ParentFont = False + ParentShowHint = False + ShowHint = True TabOrder = 3 - TextHint = 'Default download path' + Value = 100 end - object lbDefaultDownloadPath: TLabel - Left = 20 + object lbOptionPDFQuality: TLabel + AnchorSideLeft.Control = seOptionPDFQuality + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionPDFQuality + AnchorSideTop.Side = asrCenter + Left = 58 Height = 15 - Top = 15 - Width = 186 - Caption = 'Choose the default download path:' + Hint = '100 = FlateEncode (lossless), lower = DCTEncode (lossy)' + Top = 122 + Width = 119 + BorderSpacing.Left = 4 + Caption = 'PDF compression level' + Enabled = False ParentColor = False ParentFont = False + ParentShowHint = False + ShowHint = True end end end object tsUpdate: TTabSheet Caption = 'Updates' - ClientHeight = 416 - ClientWidth = 579 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 406 + ClientWidth = 498 object cbOptionAutoCheckLatestVersion: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 16 - Width = 173 + Top = 8 + Width = 490 + Align = alTop Caption = 'Auto check for latest version ' ParentFont = False TabOrder = 0 end object gbOptionFavorites: TGroupBox - Left = 17 - Height = 178 - Top = 48 - Width = 520 - Anchors = [akTop, akLeft, akRight] + Left = 4 + Height = 143 + Top = 31 + Width = 490 + Align = alTop + AutoSize = True Caption = 'Favorites' - ClientHeight = 158 - ClientWidth = 516 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 123 + ClientWidth = 486 ParentFont = False TabOrder = 1 object cbOptionAutoCheckFavStartup: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 8 - Width = 219 + Top = 27 + Width = 478 + Align = alTop Caption = 'Auto check for new chapter at startup' ParentFont = False TabOrder = 3 end object seOptionAutoCheckFavIntervalMinutes: TSpinEdit - Left = 16 + AnchorSideLeft.Control = cbOptionAutoCheckFavStartup + AnchorSideTop.Control = cbOptionAutoCheckFavStartup + AnchorSideTop.Side = asrBottom + Left = 4 Height = 23 - Top = 56 + Top = 50 Width = 58 MaxValue = 1440 MinValue = 1 @@ -2701,35 +2996,46 @@ object MainForm: TMainForm Value = 1 end object lbOptionAutoCheckFavIntervalMinutes: TLabel - Left = 82 + AnchorSideLeft.Control = seOptionAutoCheckFavIntervalMinutes + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionAutoCheckFavIntervalMinutes + AnchorSideTop.Side = asrCenter + Left = 66 Height = 15 - Top = 60 + Top = 54 Width = 243 Caption = 'Auto check for new chapter every %d minutes' ParentColor = False end object cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox - Left = 16 + AnchorSideLeft.Control = cbOptionAutoCheckFavDownload + AnchorSideTop.Control = cbOptionAutoCheckFavDownload + AnchorSideTop.Side = asrBottom + Left = 4 Height = 19 - Top = 120 + Top = 100 Width = 298 Caption = 'Automatic remove completed manga from Favorites' TabOrder = 1 end object cbOptionAutoCheckFavDownload: TCheckBox - Left = 16 + AnchorSideLeft.Control = seOptionAutoCheckFavIntervalMinutes + AnchorSideTop.Control = seOptionAutoCheckFavIntervalMinutes + AnchorSideTop.Side = asrBottom + Left = 4 Height = 19 - Top = 96 + Top = 77 Width = 242 Caption = 'Automatic download after finish checking' ParentFont = False TabOrder = 2 end object cbOptionAutoCheckFavInterval: TCheckBox - Left = 16 + Left = 4 Height = 19 - Top = 32 - Width = 237 + Top = 4 + Width = 478 + Align = alTop Caption = 'Auto check for new chapter in an interval' OnChange = cbOptionAutoCheckFavIntervalChange ParentFont = False @@ -2737,19 +3043,21 @@ object MainForm: TMainForm end end object cbOptionUpdateListNoMangaInfo: TCheckBox - Left = 17 + Left = 4 Height = 19 - Top = 242 - Width = 407 + Top = 178 + Width = 490 + Align = alTop Caption = 'Don''t load manga information when updating list (filter will be not work!)' ParentFont = False TabOrder = 2 end object cbOptionUpdateListRemoveDuplicateLocalData: TCheckBox - Left = 17 + Left = 4 Height = 19 - Top = 266 - Width = 310 + Top = 201 + Width = 490 + Align = alTop Caption = 'Remove duplicate local data when updating manga list' ParentFont = False TabOrder = 3 @@ -2758,49 +3066,53 @@ object MainForm: TMainForm end object tsDialogs: TTabSheet Caption = 'Dialogs' - ChildSizing.LeftRightSpacing = 10 - ChildSizing.TopBottomSpacing = 10 - ClientHeight = 416 - ClientWidth = 579 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 406 + ClientWidth = 498 object gbDialogs: TGroupBox - Left = 10 - Height = 101 - Top = 10 - Width = 559 + Left = 4 + Height = 93 + Top = 8 + Width = 490 Align = alTop AutoSize = True Caption = 'Show dialog confirmation for' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.VerticalSpacing = 6 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 81 - ClientWidth = 555 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 73 + ClientWidth = 486 TabOrder = 0 object cbOptionShowQuitDialog: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 6 - Width = 179 + Top = 4 + Width = 478 + Align = alTop Caption = 'Exit FMD' ParentFont = False TabOrder = 0 end object cbOptionShowDeleteTaskDialog: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 31 - Width = 179 + Top = 27 + Width = 478 + Align = alTop Caption = 'Delete task/favorite' ParentFont = False TabOrder = 1 end object cbOptionShowDownloadMangalistDialog: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 56 - Width = 179 + Top = 50 + Width = 478 + Align = alTop Caption = 'Download manga list if empty' ParentFont = False TabOrder = 2 @@ -2809,18 +3121,18 @@ object MainForm: TMainForm end object tsWebsites: TTabSheet Caption = 'Websites' - ClientHeight = 416 - ClientWidth = 579 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 406 + ClientWidth = 498 object vtOptionMangaSiteSelection: TVirtualStringTree - Left = 2 - Height = 377 - Top = 35 - Width = 573 + Left = 4 + Height = 361 + Top = 37 + Width = 490 Align = alClient - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Bottom = 2 - BorderSpacing.Around = 2 DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = <> @@ -2842,18 +3154,20 @@ object MainForm: TMainForm OnInitNode = vtOptionMangaSiteSelectionInitNode end object pnlWebsitesTool: TPanel - Left = 2 + Left = 4 Height = 23 - Top = 6 - Width = 573 + Top = 8 + Width = 490 Align = alTop BorderSpacing.Top = 4 BorderSpacing.Right = 2 BorderSpacing.Bottom = 4 BorderSpacing.Around = 2 BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ClientHeight = 23 - ClientWidth = 573 + ClientWidth = 490 TabOrder = 1 object edWebsitesSearch: TEdit Left = 0 @@ -2867,7 +3181,7 @@ object MainForm: TMainForm TextHint = 'Search website...' end object btWebsitesSearchClear: TSpeedButton - Left = 186 + Left = 188 Height = 23 Top = 0 Width = 22 @@ -2911,7 +3225,7 @@ object MainForm: TMainForm OnClick = btWebsitesSearchClearClick end object pnlWebsitesToolRight: TPanel - Left = 403 + Left = 320 Height = 23 Top = 0 Width = 170 @@ -2956,78 +3270,85 @@ object MainForm: TMainForm end object tsAccounts: TTabSheet Caption = 'Accounts' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 end object tsMisc: TTabSheet Caption = 'Misc' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.VerticalSpacing = 6 - ClientHeight = 416 - ClientWidth = 579 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 406 + ClientWidth = 498 object gbBatoto: TGroupBox - Left = 6 + Left = 4 Height = 70 - Top = 6 - Width = 567 + Top = 8 + Width = 490 Align = alTop AutoSize = True Caption = 'Batoto' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ClientHeight = 50 - ClientWidth = 563 + ClientWidth = 486 TabOrder = 0 object cbBatotoShowAllLang: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 6 - Width = 144 + Top = 4 + Width = 478 + Align = alTop Caption = 'Show all language' ParentFont = False TabOrder = 1 end object cbBatotoShowScanGroup: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 25 - Width = 144 + Top = 27 + Width = 478 + Align = alTop Caption = 'Show scan group name' ParentFont = False TabOrder = 0 end end object gbMangafox: TGroupBox - Left = 6 + Left = 4 Height = 70 Top = 82 - Width = 567 + Width = 490 Align = alTop AutoSize = True Caption = 'Mangafox' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ClientHeight = 50 - ClientWidth = 563 + ClientWidth = 486 TabOrder = 1 object cbMangaFoxRemoveWatermark: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 6 - Width = 122 + Top = 27 + Width = 478 + Align = alTop Caption = 'Remove watermark' OnChange = cbMangaFoxRemoveWatermarkChange ParentFont = False TabOrder = 0 end object cbMangaFoxSaveAsPNG: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 25 - Width = 122 + Top = 4 + Width = 478 + Align = alTop Caption = 'Save as PNG' Enabled = False ParentFont = False @@ -3035,25 +3356,26 @@ object MainForm: TMainForm end end object gbEHentai: TGroupBox - Left = 6 - Height = 51 - Top = 158 - Width = 567 + Left = 4 + Height = 47 + Top = 156 + Width = 490 Align = alTop AutoSize = True Caption = 'E-Hentai/ExHentai' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 31 - ClientWidth = 563 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 27 + ClientWidth = 486 TabOrder = 2 object cbEHentaiDownloadOriginalImage: TCheckBox - Left = 6 + Left = 4 Height = 19 - Top = 6 - Width = 153 + Top = 4 + Width = 478 + Align = alTop Caption = 'Download original image (require ExHentai account)' OnChange = cbMangaFoxRemoveWatermarkChange ParentFont = False @@ -3064,11 +3386,14 @@ object MainForm: TMainForm end object btOptionApply: TBitBtn Left = 8 - Height = 41 - Top = 466 - Width = 128 + Height = 45 + Top = 404 + Width = 125 Anchors = [akLeft, akBottom] + AutoSize = True Caption = 'Apply' + Constraints.MinHeight = 45 + Constraints.MinWidth = 125 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 @@ -3111,14 +3436,14 @@ object MainForm: TMainForm end object tsAbout: TTabSheet Caption = 'About' - ChildSizing.LeftRightSpacing = 2 - ChildSizing.TopBottomSpacing = 2 - ClientHeight = 521 - ClientWidth = 606 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 8 + ClientHeight = 511 + ClientWidth = 525 object btCheckLatestVersion: TBitBtn Left = 25 Height = 40 - Top = 470 + Top = 460 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Check for latest version' @@ -3164,7 +3489,7 @@ object MainForm: TMainForm object btAbortCheckLatestVersion: TSpeedButton Left = 193 Height = 40 - Top = 470 + Top = 460 Width = 40 Anchors = [akLeft, akBottom] Glyph.Data = { @@ -3209,7 +3534,7 @@ object MainForm: TMainForm object btVisitMyBlog: TBitBtn Left = 249 Height = 40 - Top = 470 + Top = 460 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Visit my blog' @@ -3253,10 +3578,10 @@ object MainForm: TMainForm TabOrder = 1 end object pcAbout: TPageControl - Left = 2 - Height = 457 - Top = 2 - Width = 602 + Left = 4 + Height = 441 + Top = 8 + Width = 517 ActivePage = tsAboutText Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] @@ -3264,13 +3589,13 @@ object MainForm: TMainForm TabOrder = 2 object tsAboutText: TTabSheet Caption = 'About FMD' - ClientHeight = 429 - ClientWidth = 594 + ClientHeight = 413 + ClientWidth = 509 object rmAbout: TRichMemo Left = 2 - Height = 423 + Height = 407 Top = 4 - Width = 588 + Width = 503 Align = alClient BorderSpacing.Top = 2 BorderSpacing.Right = 2 @@ -3317,14 +3642,14 @@ object MainForm: TMainForm Left = 0 Height = 8 Top = 0 - Width = 819 + Width = 771 Align = alTop TabOrder = 1 Visible = False end object pcLeft: TPageControl Left = 4 - Height = 547 + Height = 488 Top = 12 Width = 195 ActivePage = tsMangaList @@ -3337,30 +3662,24 @@ object MainForm: TMainForm TabOrder = 4 object tsMangaList: TTabSheet Caption = 'Manga List' - ChildSizing.LeftRightSpacing = 2 - ChildSizing.TopBottomSpacing = 3 - ClientHeight = 519 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 460 ClientWidth = 187 - object lbMode: TLabel - Left = 3 - Height = 15 - Top = 68 - Width = 157 - Anchors = [akTop, akLeft, akRight] - Caption = 'Mode: Show all (0)' - Font.Style = [fsBold] - ParentColor = False - ParentFont = False - end object vtMangaList: TVirtualStringTree - Left = 2 - Height = 424 - Top = 92 - Width = 181 - Align = alBottom + AnchorSideLeft.Control = lbMode + AnchorSideTop.Control = lbMode + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btRemoveFilter + AnchorSideRight.Side = asrBottom + Left = 4 + Height = 371 + Top = 85 + Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Right = 2 - BorderSpacing.Around = 2 + BorderSpacing.Top = 8 DefaultText = 'Node' DragOperations = [] Header.AutoSizeIndex = 0 @@ -3385,23 +3704,60 @@ object MainForm: TMainForm OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint end - object edSearch: TEdit - Left = 3 - Height = 23 - Top = 36 - Width = 157 - Anchors = [akTop, akLeft, akRight] - OnChange = edSearchChange - OnKeyDown = edSearchKeyDown - TabOrder = 1 - TextHint = 'Search title...' + object btAbortUpdateList: TSpeedButton + Left = 104 + Height = 22 + Hint = 'Abort update list' + Top = 104 + Width = 23 + Flat = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 + 0004000000170000002B00001A430000448000005AAB00005DC400005DC40000 + 5AAB0000448000001A430000002D0000001800000004FFFFFF00FFFFFF000000 + 000000001F000000534D020274BF08089DE30E0EC4F51111D4FD1111D4FD0E0E + C4F508089DE3020274BF0000534D00001F0000000000FFFFFF00FFFFFF000000 + 830000007F4D040488CD1212C4F61212B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF0F0FC2F6030388CD00007F4D00008300FFFFFF00FFFFFF000000 + 851A03038ABF1818C1F61212B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF0F0FBCF6020289BF0000851AFFFFFF00FFFFFF000000 + 896C1616AAE21616C1FFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF0909A1E30000896CFFFFFF00FFFFFF000000 + 8DA72E2EC0F51212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1212AFF500008DA7FFFFFF00FFFFFF000000 + 92C44444CDFD2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818AFFD000092C4FFFFFF00FFFFFF000000 + 96C44949D1FD3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFD000096C4FFFFFF00FFFFFF000000 + 9AA74747D3F53737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2727B4F500009AA7FFFFFF00FFFFFF000000 + 9E6C3232C6E34949D1FFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4747CFFF2A2ABDE300009E6CFFFFFF00FFFFFF000000 + A11A0808A8BF5656E2F65151D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF5050D8FF4F4FDCF60707A7BF0000A11AFFFFFF00FFFFFF000000 + A2000000A54D1010B1CD5B5BE8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5F5FE7FF5858E4F60F0FB0CD0000A54D0000A200FFFFFF00FFFFFF000000 + A2000000A5000000A84D0909AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5B + E9F53636CFE30909AEBF0000A84D0000A5000000A200FFFFFF00FFFFFF000000 + A2000000A5000000A8000000A91A0000AA6C0000AAA60000AAC40000AAC40000 + AAA60000AA6C0000A91A0000A8000000A5000000A200FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btAbortUpdateListClick + ShowCaption = False + ShowHint = True + ParentShowHint = False end object cbSelectManga: TComboBox - Left = 3 + Left = 4 Height = 23 Hint = 'For more manga sites, please go to Options->Manga sites' - Top = 8 - Width = 157 + Top = 4 + Width = 150 Anchors = [akTop, akLeft, akRight] ItemHeight = 15 ItemIndex = 0 @@ -3413,17 +3769,18 @@ object MainForm: TMainForm ShowHint = True Sorted = True Style = csDropDownList - TabOrder = 2 + TabOrder = 1 end object btUpdateList: TSpeedButton + AnchorSideLeft.Control = cbSelectManga AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 162 + AnchorSideTop.Control = cbSelectManga + AnchorSideTop.Side = asrCenter + Left = 158 Height = 23 Hint = 'Update manga list' - Top = 8 - Width = 22 - Anchors = [akTop, akRight] + Top = 4 + Width = 25 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 20000000000000040000640000006400000000000000000000000000001F0000 @@ -3461,59 +3818,33 @@ object MainForm: TMainForm 0099AA550099AA550099AA550099AA550099AA550073AA550000 } OnClick = btUpdateListClick + ShowCaption = False end - object btRemoveFilter: TSpeedButton - Left = 162 + object edSearch: TEdit + AnchorSideLeft.Control = cbSelectManga + AnchorSideTop.Control = cbSelectManga + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = cbSelectManga + AnchorSideRight.Side = asrBottom + Left = 4 Height = 23 - Top = 63 - Width = 22 - Anchors = [akTop, akRight] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000080000000000005A000000770000008000000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A000000110000000400005A00000077000000770000008000000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578040426000000 - 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 - 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 - A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 - A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C - 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 250027275200101090000000AA000000AA000000AA000000A700363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535004343430035355F00121291000000AA000000A700363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A43434300464646004646460035355F0023237700363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btRemoveFilterClick + Top = 31 + Width = 150 + Anchors = [akTop, akLeft, akRight] + OnChange = edSearchChange + OnKeyDown = edSearchKeyDown + TabOrder = 2 + TextHint = 'Search title...' end object btSearchClear: TSpeedButton + AnchorSideLeft.Control = edSearch AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 162 + AnchorSideTop.Control = edSearch + AnchorSideTop.Side = asrCenter + Left = 158 Height = 23 - Top = 36 - Width = 22 - Anchors = [akTop, akRight] + Top = 31 + Width = 25 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000090000 @@ -3551,66 +3882,86 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btSearchClearClick + ShowCaption = False end - object btAbortUpdateList: TSpeedButton - Left = 136 - Height = 22 - Hint = 'Abort update list' - Top = 64 - Width = 23 - Flat = True + object lbMode: TLabel + AnchorSideLeft.Control = edSearch + AnchorSideTop.Control = edSearch + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = edSearch + AnchorSideRight.Side = asrBottom + Left = 4 + Height = 15 + Top = 62 + Width = 150 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Top = 8 + Caption = 'Mode: Show all (0)' + Font.Style = [fsBold] + ParentColor = False + ParentFont = False + end + object btRemoveFilter: TSpeedButton + AnchorSideLeft.Control = lbMode + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbMode + AnchorSideTop.Side = asrCenter + Left = 158 + Height = 23 + Top = 58 + Width = 25 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 - 0004000000170000002B00001A430000448000005AAB00005DC400005DC40000 - 5AAB0000448000001A430000002D0000001800000004FFFFFF00FFFFFF000000 - 000000001F000000534D020274BF08089DE30E0EC4F51111D4FD1111D4FD0E0E - C4F508089DE3020274BF0000534D00001F0000000000FFFFFF00FFFFFF000000 - 830000007F4D040488CD1212C4F61212B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF0F0FC2F6030388CD00007F4D00008300FFFFFF00FFFFFF000000 - 851A03038ABF1818C1F61212B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF0F0FBCF6020289BF0000851AFFFFFF00FFFFFF000000 - 896C1616AAE21616C1FFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF0909A1E30000896CFFFFFF00FFFFFF000000 - 8DA72E2EC0F51212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1212AFF500008DA7FFFFFF00FFFFFF000000 - 92C44444CDFD2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818AFFD000092C4FFFFFF00FFFFFF000000 - 96C44949D1FD3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFD000096C4FFFFFF00FFFFFF000000 - 9AA74747D3F53737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2727B4F500009AA7FFFFFF00FFFFFF000000 - 9E6C3232C6E34949D1FFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4747CFFF2A2ABDE300009E6CFFFFFF00FFFFFF000000 - A11A0808A8BF5656E2F65151D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF5050D8FF4F4FDCF60707A7BF0000A11AFFFFFF00FFFFFF000000 - A2000000A54D1010B1CD5B5BE8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5F5FE7FF5858E4F60F0FB0CD0000A54D0000A200FFFFFF00FFFFFF000000 - A2000000A5000000A84D0909AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5B - E9F53636CFE30909AEBF0000A84D0000A5000000A200FFFFFF00FFFFFF000000 - A2000000A5000000A8000000A91A0000AA6C0000AAA60000AAC40000AAC40000 - AAA60000AA6C0000A91A0000A8000000A5000000A200FFFFFF00FFFFFF00FFFF + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000080000000000005A000000770000008000000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A000000110000000400005A00000077000000770000008000000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578040426000000 + 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 + 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 + A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 + A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C + 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 250027275200101090000000AA000000AA000000AA000000A700363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535004343430035355F00121291000000AA000000A700363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A43434300464646004646460035355F0023237700363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btAbortUpdateListClick + OnClick = btRemoveFilterClick ShowCaption = False - ShowHint = True - ParentShowHint = False end end object tsDownloadFilter: TTabSheet Caption = '>>' - ClientHeight = 478 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 509 ClientWidth = 187 ImageIndex = 4 object tvDownloadFilter: TTreeView - Left = 0 - Height = 478 - Top = 0 - Width = 187 + Left = 4 + Height = 501 + Top = 4 + Width = 179 Align = alClient AutoExpand = True DefaultItemHeight = 18 @@ -3625,8 +3976,8 @@ object MainForm: TMainForm object sbMain: TStatusBar Left = 0 Height = 23 - Top = 563 - Width = 819 + Top = 504 + Width = 771 Panels = < item Width = 195 @@ -3639,7 +3990,7 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 555 + Height = 496 Top = 8 Width = 2 OnMoved = spMainSplitterMoved @@ -3651,8 +4002,8 @@ object MainForm: TMainForm object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - left = 616 - top = 360 + left = 584 + top = 180 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -3969,8 +4320,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - left = 616 - top = 392 + left = 584 + top = 212 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -4001,8 +4352,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - left = 616 - top = 432 + left = 520 + top = 228 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -4492,8 +4843,8 @@ object MainForm: TMainForm Enabled = False Interval = 600000 OnTimer = itCheckFavTimer - left = 760 - top = 200 + left = 696 + top = 228 end object itRefreshDLInfo: TIdleTimer Enabled = False @@ -5932,8 +6283,8 @@ object MainForm: TMainForm Enabled = False Interval = 500 OnTimer = itStartupTimer - left = 696 - top = 72 + left = 648 + top = 120 end object tmBackup: TIdleTimer Interval = 60000 @@ -5944,19 +6295,19 @@ object MainForm: TMainForm object itMonitor: TTimer Enabled = False OnTimer = itMonitorTimer - left = 760 - top = 240 + left = 648 + top = 224 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - left = 648 - top = 72 + left = 504 + top = 120 end object TransferRateToolset: TChartToolset - left = 608 - top = 72 + left = 464 + top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index aff9299ec..365c83e4a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -31,12 +31,9 @@ interface TMainForm = class(TForm) appPropertiesMain: TApplicationProperties; - Bevel1: TBevel; btAddToFavorites: TBitBtn; - btBrowse: TSpeedButton; btCancelFavoritesCheck: TSpeedButton; btAbortCheckLatestVersion: TSpeedButton; - btOptionBrowse: TSpeedButton; btChecks: TSpeedButton; btDonate: TImage; btFavoritesImport: TBitBtn; @@ -48,7 +45,6 @@ TMainForm = class(TForm) btSearchClear: TSpeedButton; btWebsitesSearchClear: TSpeedButton; btUpdateList: TSpeedButton; - btURL: TSpeedButton; cbEHentaiDownloadOriginalImage: TCheckBox; cbOptionAutoCheckFavStartup: TCheckBox; cbOptionAutoCheckFavInterval: TCheckBox; @@ -68,13 +64,20 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + edOptionDefaultPath: TDirectoryEdit; edOptionMangaCustomRename: TEdit; + edSaveTo: TDirectoryEdit; + edURL: TEditButton; gbMangafox: TGroupBox; gbEHentai: TGroupBox; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; + Panel1: TPanel; + Panel2: TPanel; + Panel3: TPanel; + Panel8: TPanel; pcAbout: TPageControl; pmSbMain: TPopupMenu; sbSaveTo: TScrollBox; @@ -89,12 +92,9 @@ TMainForm = class(TForm) TransferRateGraphArea: TAreaSeries; TransferRateGraph: TChart; ckDropTarget: TCheckBox; - edOptionDefaultPath: TEdit; edOptionExternalParams: TEdit; edOptionExternalPath: TFileNameEdit; - edSaveTo: TEdit; edWebsitesSearch: TEdit; - edURL: TEdit; gbDropTarget: TGroupBox; gbOptionExternal: TGroupBox; IconDL: TImageList; @@ -355,7 +355,6 @@ TMainForm = class(TForm) procedure btReadOnlineClick(Sender: TObject); procedure btSearchClearClick(Sender: TObject); procedure btUpdateListClick(Sender: TObject); - procedure btURLClick(Sender: TObject); procedure btVisitMyBlogClick(Sender: TObject); procedure btWebsitesSearchClearClick(Sender: TObject); procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); @@ -375,13 +374,12 @@ TMainForm = class(TForm) procedure edSearchChange(Sender: TObject); procedure edSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState ); + procedure edURLButtonClick(Sender: TObject); procedure edURLKeyPress(Sender: TObject; var Key: Char); procedure edWebsitesSearchChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); - procedure btBrowseClick(Sender: TObject); - procedure btOptionBrowseClick(Sender: TObject); procedure btDownloadClick(Sender: TObject); procedure btFavoritesCheckNewChapterClick(Sender: TObject); procedure btOptionApplyClick(Sender: TObject); @@ -1450,7 +1448,7 @@ procedure TMainForm.medURLPasteClick(Sender: TObject); procedure TMainForm.medURLPasteandgoClick(Sender: TObject); begin edURL.Text := Clipboard.AsText; - btURLClick(edURL); + edURLButtonClick(edURL); end; procedure TMainForm.medtURLDeleteClick(Sender: TObject); @@ -1487,7 +1485,7 @@ procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); edURL.Text := FillHost(Modules.Module[i].RootURL, DownloadInfo.Link) else edURL.Text := FillMangaSiteHost(DownloadInfo.Website, DownloadInfo.Link); - btURLClick(btURL); + edURLButtonClick(edURL); pcMain.ActivePage := tsInformation; end; end; @@ -2007,24 +2005,6 @@ procedure TMainForm.btFavoritesCheckNewChapterClick(Sender: TObject); // ----- -procedure TMainForm.btBrowseClick(Sender: TObject); -begin - //dlgSaveTo.InitialDir := CorrectFilePath(edSaveTo.Text); - dlgSaveTo.InitialDir := edSaveTo.Text; - if dlgSaveTo.Execute then - edSaveTo.Text := dlgSaveTo.FileName; - //edSaveTo.Text := CorrectFilePath(dlgSaveTo.FileName); -end; - -procedure TMainForm.btOptionBrowseClick(Sender: TObject); -begin - //dlgSaveTo.InitialDir := CorrectFilePath(edOptionDefaultPath.Text); - dlgSaveTo.InitialDir := edOptionDefaultPath.Text; - if dlgSaveTo.Execute then - edOptionDefaultPath.Text := CorrectPathSys(dlgSaveTo.FileName); - //edOptionDefaultPath.Text := CorrectFilePath(dlgSaveTo.FileName); -end; - // ----- procedure TMainForm.btUpdateListClick(Sender: TObject); @@ -2087,91 +2067,6 @@ procedure TMainForm.ClearChapterListState; ChapterList[i].Downloaded := False; end; -procedure TMainForm.btURLClick(Sender: TObject); -var - i: Integer; - webid: Cardinal; - website, - host, - link: String; - regx: TRegExpr; -begin - website := ''; - host := ''; - link := ''; - edURL.Text := FixURL(edURL.Text); - regx := TRegExpr.Create; - try - regx.Expression := '^https?\://'; - if not (regx.Exec(edURL.Text)) then - edURL.Text := 'http://' + edURL.Text; - - regx.Expression := REGEX_HOST; - if regx.Exec(edURL.Text) then - begin - host := regx.Replace(edURL.Text, '$2', True); - link := regx.Replace(edURL.Text, '$4', True); - end; - - if (host <> '') and (link <> '') then - begin - host := LowerCase(host); - i := Modules.LocateModuleByHost(host); - if i > -1 then - begin - website := Modules.Module[i].Website; - edURL.Text := FillHost(Modules.Module[i].RootURL, link); - end - else - begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(host, WebsiteRoots[i, 1]) > 0 then - begin - webid := i; - website := WebsiteRoots[i, 0]; - Break; - end; - if website <> '' then - edURL.Text := FillMangaSiteHost(webid, link); - end; - end; - finally - regx.Free; - end; - - DisableAddToFavorites(website); - if (website = '') or (link = '') then - begin - MessageDlg('', RS_DlgURLNotSupport, mtInformation, [mbYes], 0); - Exit; - end; - - if isGetMangaInfos then - begin - GetInfosThread.IsFlushed := True; - GetInfosThread.Terminate; - //GetInfosThread.WaitFor; - end; - GetInfosThread := TGetMangaInfosThread.Create; - GetInfosThread.MangaListPos := -1; - GetInfosThread.Title := ''; - GetInfosThread.Website := website; - GetInfosThread.Link := link; - GetInfosThread.Start; - - pcMain.ActivePage := tsInformation; - imCover.Picture.Assign(nil); - clbChapterList.Clear; - if Assigned(gifWaiting) then - begin - itAnimate.Enabled := True; - pbWait.Visible := True; - end; - btAddToFavorites.Enabled := not SitesWithoutFavorites(website); - rmInformation.Clear; - rmInformation.Lines.Add(RS_Loading); -end; - procedure TMainForm.btVisitMyBlogClick(Sender: TObject); begin OpenURL('http://akarink.wordpress.com/'); @@ -2311,7 +2206,7 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; procedure TMainForm.edURLKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then - btURLClick(btURL); + edURLButtonClick(edURL); end; procedure TMainForm.edWebsitesSearchChange(Sender: TObject); @@ -4784,6 +4679,91 @@ procedure TMainForm.edSearchKeyDown(Sender: TObject; var Key: Word; edSearch.Tag := 0; end; +procedure TMainForm.edURLButtonClick(Sender: TObject); +var + i: Integer; + webid: Cardinal; + website, + host, + link: String; + regx: TRegExpr; +begin + website := ''; + host := ''; + link := ''; + edURL.Text := FixURL(edURL.Text); + regx := TRegExpr.Create; + try + regx.Expression := '^https?\://'; + if not (regx.Exec(edURL.Text)) then + edURL.Text := 'http://' + edURL.Text; + + regx.Expression := REGEX_HOST; + if regx.Exec(edURL.Text) then + begin + host := regx.Replace(edURL.Text, '$2', True); + link := regx.Replace(edURL.Text, '$4', True); + end; + + if (host <> '') and (link <> '') then + begin + host := LowerCase(host); + i := Modules.LocateModuleByHost(host); + if i > -1 then + begin + website := Modules.Module[i].Website; + edURL.Text := FillHost(Modules.Module[i].RootURL, link); + end + else + begin + for i := Low(WebsiteRoots) to High(WebsiteRoots) do + if Pos(host, WebsiteRoots[i, 1]) > 0 then + begin + webid := i; + website := WebsiteRoots[i, 0]; + Break; + end; + if website <> '' then + edURL.Text := FillMangaSiteHost(webid, link); + end; + end; + finally + regx.Free; + end; + + DisableAddToFavorites(website); + if (website = '') or (link = '') then + begin + MessageDlg('', RS_DlgURLNotSupport, mtInformation, [mbYes], 0); + Exit; + end; + + if isGetMangaInfos then + begin + GetInfosThread.IsFlushed := True; + GetInfosThread.Terminate; + //GetInfosThread.WaitFor; + end; + GetInfosThread := TGetMangaInfosThread.Create; + GetInfosThread.MangaListPos := -1; + GetInfosThread.Title := ''; + GetInfosThread.Website := website; + GetInfosThread.Link := link; + GetInfosThread.Start; + + pcMain.ActivePage := tsInformation; + imCover.Picture.Assign(nil); + clbChapterList.Clear; + if Assigned(gifWaiting) then + begin + itAnimate.Enabled := True; + pbWait.Visible := True; + end; + btAddToFavorites.Enabled := not SitesWithoutFavorites(website); + rmInformation.Clear; + rmInformation.Lines.Add(RS_Loading); +end; + procedure TMainForm.UpdateVtChapter; begin clbChapterList.Clear; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d71fb0a7d..8fdf19667 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -458,6 +458,12 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" +#: tmainform.caption +#, fuzzy +msgctxt "tmainform.caption" +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index d17f7269d..ae32f8e56 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -450,6 +450,12 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" +#: tmainform.caption +#, fuzzy +msgctxt "tmainform.caption" +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index a3532ff1f..dfa351f08 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -422,6 +422,11 @@ msgstr "" msgid "Visit my blog" msgstr "" +#: tmainform.caption +msgctxt "TMAINFORM.CAPTION" +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From 6f94ff7a91087860529318671efd52520d986ee2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Mar 2016 20:19:43 +0800 Subject: [PATCH 1018/2794] fixed speed graph doesn't show on startup when there is automatic download task started (from previous session) --- baseunits/uDownloadsManager.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9edebe451..cd0d78aae 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -2049,7 +2049,9 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; end; //force to check task if all task loaded is STATUS_WAIT if tcount = 0 then - CheckAndActiveTask; + CheckAndActiveTask + else if MainForm.itRefreshDLInfo.Enabled = False then + MainForm.itRefreshDLInfo.Enabled := True; MainForm.vtDownloadFilters; end; From 075bb3457d48335b44467228e69d61ca0307a145 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 18 Mar 2016 22:20:09 +0800 Subject: [PATCH 1019/2794] fixed tsumino genres and image url fixed #209 --- baseunits/modules/Tsumino.pas | 46 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index e52ce76ad..266e03eb3 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, synautil, RegExpr; implementation @@ -57,11 +57,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - i: Integer; - v: IXQValue; -const - g: array[0..2] of String = ('Parody','Characters','Tags'); begin Result:=NET_PROBLEM; if MangaInfo=nil then Exit(UNKNOWN_ERROR); @@ -75,10 +70,7 @@ function GetInfo(const MangaInfo: TMangaInformation; if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); if title=''then title:=XPathString('//div[@class="book-line"][starts-with(.,"Title")]/div[@class="book-data"]'); artists:=XPathString('//div[@class="book-line"][starts-with(.,"Artist")]/div[@class="book-data"]'); - genres:=''; - for i:=Low(g) to High(g) do - for v in XPath('//div[@class="book-line"][starts-with(.,"'+g[i]+'")]/div[@class="book-data"]/*') do - AddCommaString(genres,v.toString); + genres:=XPathStringAll('//div[@class="book-line"][starts-with(.,"Parody") or starts-with(.,"Characters") or starts-with(.,"Tags")]/div[@class="book-data"]/*'); if title<>'' then begin chapterLinks.Add(url); chapterName.Add(title); @@ -93,8 +85,9 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - v: IXQValue; - s: String; + source: TStringList; + i, pgLast: Integer; + thumbUrl: String; begin Result:=False; if DownloadThread=nil then Exit; @@ -104,18 +97,29 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//div[@class="no-border book-grid-item"]/a/img/@data-original') do begin - s:=Trim(v.toString); - if s<>'' then begin - s:=StringReplace(s,'/Thumb/','/Image/',[rfIgnoreCase]); - PageLinks.Add(MaybeFillHost(Module.RootURL,s)); + source:=TStringList.Create; + try + source.LoadFromStream(Document); + pgLast:=0; + thumbUrl:=''; + if source.Count>0 then + for i:=0 to source.Count-1 do begin + if Pos('var pgLast',source[i])>0 then + pgLast:=StrToIntDef(GetValuesFromString(source[i],'='),0) + else if Pos('var thumbUrl',source[i])>0 then begin + thumbUrl:=GetValuesFromString(source[i],'='); + Break; end; end; - finally - Free; + if (pgLast>0) and (thumbUrl<>'') then begin + thumbUrl:=ReplaceRegExpr('(?i)/Thumb(/\d+/)[9]+',thumbUrl,'/Image$1',True); + thumbUrl:=AppendURLDelim(FillHost(Module.RootURL,thumbUrl)); + for i:=1 to pgLast do + PageLinks.Add(thumbUrl+IntToStr(i)); end; + finally + source.Free; + end; end; end; end; From 581c0ac7f21a2cba7cc5410a6f575ff2b22a2b0e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 18 Mar 2016 22:43:14 +0800 Subject: [PATCH 1020/2794] Bump version 0.9.41.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index c1603918b..5d7763433 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.41.0 (18-03-2016) +[*] MangaFox: fixed remove watermark and rewrite all code +[*] Tsumino: fixed get image url +[*] Fixed mainform's components layout +[*] Various changes and bug fixes + 0.9.40.0 (12-03-2016) [+] Added Tsumangaonline[ES] [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6eb524e58..298024e82 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="40"/> + <RevisionNr Value="41"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 3545ce122..5dde8ebe0 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.40.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.40.0/fmd_0.9.40.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.40.0/fmd_0.9.40.0_Win64.7z +VERSION=0.9.41.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.41.0/fmd_0.9.41.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.41.0/fmd_0.9.41.0_Win64.7z From 619f442d9f18a25c412af04ed5c79530d4d99d70 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 00:06:02 +0800 Subject: [PATCH 1021/2794] mainform, swap position of remove mangafox watermark options --- mangadownloader/forms/frmMain.lfm | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 813e93939..8c0c3e9de 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3279,13 +3279,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 406 - ClientWidth = 498 + ClientHeight = 357 + ClientWidth = 531 object gbBatoto: TGroupBox Left = 4 Height = 70 Top = 8 - Width = 490 + Width = 523 Align = alTop AutoSize = True Caption = 'Batoto' @@ -3294,13 +3294,13 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 50 - ClientWidth = 486 + ClientWidth = 519 TabOrder = 0 object cbBatotoShowAllLang: TCheckBox Left = 4 Height = 19 Top = 4 - Width = 478 + Width = 511 Align = alTop Caption = 'Show all language' ParentFont = False @@ -3310,7 +3310,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 27 - Width = 478 + Width = 511 Align = alTop Caption = 'Show scan group name' ParentFont = False @@ -3321,7 +3321,7 @@ object MainForm: TMainForm Left = 4 Height = 70 Top = 82 - Width = 490 + Width = 523 Align = alTop AutoSize = True Caption = 'Mangafox' @@ -3330,13 +3330,13 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 50 - ClientWidth = 486 + ClientWidth = 519 TabOrder = 1 object cbMangaFoxRemoveWatermark: TCheckBox Left = 4 Height = 19 - Top = 27 - Width = 478 + Top = 4 + Width = 511 Align = alTop Caption = 'Remove watermark' OnChange = cbMangaFoxRemoveWatermarkChange @@ -3346,8 +3346,8 @@ object MainForm: TMainForm object cbMangaFoxSaveAsPNG: TCheckBox Left = 4 Height = 19 - Top = 4 - Width = 478 + Top = 27 + Width = 511 Align = alTop Caption = 'Save as PNG' Enabled = False @@ -3359,7 +3359,7 @@ object MainForm: TMainForm Left = 4 Height = 47 Top = 156 - Width = 490 + Width = 523 Align = alTop AutoSize = True Caption = 'E-Hentai/ExHentai' @@ -3368,13 +3368,13 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 27 - ClientWidth = 486 + ClientWidth = 519 TabOrder = 2 object cbEHentaiDownloadOriginalImage: TCheckBox Left = 4 Height = 19 Top = 4 - Width = 478 + Width = 511 Align = alTop Caption = 'Download original image (require ExHentai account)' OnChange = cbMangaFoxRemoveWatermarkChange From 8e753af9fd82d4b165132215830810765f5859f5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 00:13:05 +0800 Subject: [PATCH 1022/2794] mainform, fixed layout --- mangadownloader/forms/frmMain.lfm | 66 +++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 8c0c3e9de..f7289290b 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2272,13 +2272,13 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 406 - ClientWidth = 498 + ClientHeight = 357 + ClientWidth = 531 object sbDownloadConnections: TScrollBox Left = 0 - Height = 406 + Height = 357 Top = 0 - Width = 498 + Width = 531 HorzScrollBar.Page = 455 VertScrollBar.Page = 268 Align = alClient @@ -2287,8 +2287,8 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 406 - ClientWidth = 498 + ClientHeight = 357 + ClientWidth = 531 TabOrder = 0 object cbOptionUseProxy: TCheckBox AnchorSideLeft.Control = seOptionConnectionTimeout @@ -2943,13 +2943,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 406 - ClientWidth = 498 + ClientHeight = 357 + ClientWidth = 531 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 4 Height = 19 Top = 8 - Width = 490 + Width = 523 Align = alTop Caption = 'Auto check for latest version ' ParentFont = False @@ -2959,7 +2959,7 @@ object MainForm: TMainForm Left = 4 Height = 143 Top = 31 - Width = 490 + Width = 523 Align = alTop AutoSize = True Caption = 'Favorites' @@ -2968,22 +2968,22 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 123 - ClientWidth = 486 + ClientWidth = 519 ParentFont = False TabOrder = 1 object cbOptionAutoCheckFavStartup: TCheckBox Left = 4 Height = 19 - Top = 27 - Width = 478 + Top = 4 + Width = 511 Align = alTop Caption = 'Auto check for new chapter at startup' ParentFont = False TabOrder = 3 end object seOptionAutoCheckFavIntervalMinutes: TSpinEdit - AnchorSideLeft.Control = cbOptionAutoCheckFavStartup - AnchorSideTop.Control = cbOptionAutoCheckFavStartup + AnchorSideLeft.Control = cbOptionAutoCheckFavInterval + AnchorSideTop.Control = cbOptionAutoCheckFavInterval AnchorSideTop.Side = asrBottom Left = 4 Height = 23 @@ -3033,8 +3033,8 @@ object MainForm: TMainForm object cbOptionAutoCheckFavInterval: TCheckBox Left = 4 Height = 19 - Top = 4 - Width = 478 + Top = 27 + Width = 511 Align = alTop Caption = 'Auto check for new chapter in an interval' OnChange = cbOptionAutoCheckFavIntervalChange @@ -3046,7 +3046,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 178 - Width = 490 + Width = 523 Align = alTop Caption = 'Don''t load manga information when updating list (filter will be not work!)' ParentFont = False @@ -3056,7 +3056,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 201 - Width = 490 + Width = 523 Align = alTop Caption = 'Remove duplicate local data when updating manga list' ParentFont = False @@ -3070,13 +3070,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 406 - ClientWidth = 498 + ClientHeight = 357 + ClientWidth = 531 object gbDialogs: TGroupBox Left = 4 Height = 93 Top = 8 - Width = 490 + Width = 523 Align = alTop AutoSize = True Caption = 'Show dialog confirmation for' @@ -3085,13 +3085,13 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 73 - ClientWidth = 486 + ClientWidth = 519 TabOrder = 0 object cbOptionShowQuitDialog: TCheckBox Left = 4 Height = 19 Top = 4 - Width = 478 + Width = 511 Align = alTop Caption = 'Exit FMD' ParentFont = False @@ -3101,7 +3101,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 27 - Width = 478 + Width = 511 Align = alTop Caption = 'Delete task/favorite' ParentFont = False @@ -3111,7 +3111,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 50 - Width = 478 + Width = 511 Align = alTop Caption = 'Download manga list if empty' ParentFont = False @@ -3125,13 +3125,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 406 - ClientWidth = 498 + ClientHeight = 357 + ClientWidth = 531 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 4 - Height = 361 + Height = 312 Top = 37 - Width = 490 + Width = 523 Align = alClient DefaultText = 'Node' Header.AutoSizeIndex = 0 @@ -3157,7 +3157,7 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 8 - Width = 490 + Width = 523 Align = alTop BorderSpacing.Top = 4 BorderSpacing.Right = 2 @@ -3167,7 +3167,7 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 23 - ClientWidth = 490 + ClientWidth = 523 TabOrder = 1 object edWebsitesSearch: TEdit Left = 0 @@ -3225,7 +3225,7 @@ object MainForm: TMainForm OnClick = btWebsitesSearchClearClick end object pnlWebsitesToolRight: TPanel - Left = 320 + Left = 353 Height = 23 Top = 0 Width = 170 From 56cde95b26a8ae25dc3986a1bbd913e9090ff2ca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 00:22:24 +0800 Subject: [PATCH 1023/2794] fixed account manager form layout --- mangadownloader/forms/frmAccountManager.lfm | 48 ++-- mangadownloader/forms/frmAccountSet.lfm | 237 ++++++++++---------- mangadownloader/forms/frmAccountSet.pas | 1 - mangadownloader/forms/frmMain.pas | 2 + mangadownloader/languages/fmd.en.po | 8 + mangadownloader/languages/fmd.id_ID.po | 8 + mangadownloader/languages/fmd.po | 8 + 7 files changed, 161 insertions(+), 151 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 90f3ec1cd..e712425fc 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -6,8 +6,8 @@ object AccountManagerForm: TAccountManagerForm ActiveControl = vtAccountList BorderStyle = bsNone Caption = 'AccountManagerForm' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 + ChildSizing.LeftRightSpacing = 8 + ChildSizing.TopBottomSpacing = 8 ClientHeight = 316 ClientWidth = 392 OnClose = FormClose @@ -15,29 +15,28 @@ object AccountManagerForm: TAccountManagerForm OnDestroy = FormDestroy OnShow = FormShow LCLVersion = '1.7' - Visible = False object pnBtContainer: TPanel - Left = 295 - Height = 304 - Top = 6 - Width = 91 + Left = 299 + Height = 300 + Top = 8 + Width = 85 Align = alRight AutoSize = True + BorderSpacing.Left = 4 BevelOuter = bvNone - ChildSizing.VerticalSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 1 - ClientHeight = 304 - ClientWidth = 91 + ClientHeight = 300 + ClientWidth = 85 TabOrder = 1 object btDelete: TBitBtn - Left = 6 + Left = 0 Height = 26 - Top = 64 + Top = 60 Width = 85 Align = alTop AutoSize = True - BorderSpacing.Left = 6 Caption = 'Delete' Enabled = False Glyph.Data = { @@ -80,13 +79,12 @@ object AccountManagerForm: TAccountManagerForm TabOrder = 0 end object btEdit: TBitBtn - Left = 6 + Left = 0 Height = 26 - Top = 32 + Top = 30 Width = 85 Align = alTop AutoSize = True - BorderSpacing.Left = 6 Caption = 'Edit' Enabled = False Glyph.Data = { @@ -129,13 +127,12 @@ object AccountManagerForm: TAccountManagerForm TabOrder = 1 end object btAdd: TBitBtn - Left = 6 + Left = 0 Height = 26 Top = 0 Width = 85 Align = alTop AutoSize = True - BorderSpacing.Left = 6 Caption = 'Add' Default = True Glyph.Data = { @@ -178,13 +175,12 @@ object AccountManagerForm: TAccountManagerForm TabOrder = 2 end object btRefresh: TBitBtn - Left = 6 + Left = 0 Height = 26 - Top = 96 + Top = 90 Width = 85 Align = alTop AutoSize = True - BorderSpacing.Left = 6 Caption = 'Refresh' Enabled = False Glyph.Data = { @@ -228,10 +224,10 @@ object AccountManagerForm: TAccountManagerForm end end object vtAccountList: TVirtualStringTree - Left = 6 - Height = 304 - Top = 6 - Width = 289 + Left = 8 + Height = 300 + Top = 8 + Width = 287 Align = alClient Header.AutoSizeIndex = 0 Header.Columns = < diff --git a/mangadownloader/forms/frmAccountSet.lfm b/mangadownloader/forms/frmAccountSet.lfm index 5f282ea17..28df60f66 100644 --- a/mangadownloader/forms/frmAccountSet.lfm +++ b/mangadownloader/forms/frmAccountSet.lfm @@ -1,23 +1,24 @@ object AccountSetForm: TAccountSetForm - Left = 0 + Left = 490 Height = 234 - Top = 0 + Top = 229 Width = 269 ActiveControl = cbWebsiteName Caption = 'Account' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 ClientHeight = 234 ClientWidth = 269 Position = poMainFormCenter - Visible = False + LCLVersion = '1.7' object cbWebsiteName: TComboBox Left = 8 Height = 23 Top = 29 Width = 253 Align = alTop - BorderSpacing.Bottom = 20 ItemHeight = 15 Style = csDropDownList TabOrder = 0 @@ -28,44 +29,40 @@ object AccountSetForm: TAccountSetForm Top = 8 Width = 253 Align = alTop - BorderSpacing.Bottom = 6 Caption = 'Website' ParentColor = False end object Label2: TLabel Left = 8 Height = 15 - Top = 72 + Top = 58 Width = 253 Align = alTop - BorderSpacing.Bottom = 6 Caption = 'Username' ParentColor = False end object Label3: TLabel Left = 8 Height = 15 - Top = 126 + Top = 108 Width = 253 Align = alTop - BorderSpacing.Bottom = 6 Caption = 'Password' ParentColor = False end object edUsername: TEdit Left = 8 Height = 23 - Top = 93 + Top = 79 Width = 253 Align = alTop - BorderSpacing.Bottom = 10 TabOrder = 1 TextHint = 'Username' end object edPassword: TEdit Left = 8 Height = 23 - Top = 147 + Top = 129 Width = 253 Align = alTop EchoMode = emPassword @@ -73,123 +70,115 @@ object AccountSetForm: TAccountSetForm TabOrder = 2 TextHint = 'Password' end - object pnButtons: TPanel - Left = 8 - Height = 26 - Top = 200 - Width = 253 - Align = alBottom - AutoSize = True - BevelOuter = bvNone - ClientHeight = 26 - ClientWidth = 253 - TabOrder = 3 - object btOk: TBitBtn - Left = 104 - Height = 26 - Top = 0 - Width = 61 - Align = alRight - AutoSize = True - BorderSpacing.Left = 6 - Caption = 'Ok' - Default = True - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 00010000000800000010000000170000001A0000001900000017000000150000 - 00110000000D0000000A000000060000000300000001FFFFFF00FFFFFF000000 - 00020000000F0000001F0000002D02330066025F00CC012B0055000000290000 - 00220000001A000000130000000C0000000600000001FFFFFF00FFFFFF000000 - 0000000000000320000006570048077200CC16A60AE8087601C406570029021E - 00000000000000000000000000000000000000000000FFFFFF00FFFFFF000747 - 00000A6500000B8300480B8200CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85 - 001B0745000000000000000000000000000000000000FFFFFF00FFFFFF000E8D - 00000D8800480D8700CC43CA33F629C318FF39CC28FF28C217FF1EAA0FEA0D87 - 00AE0D8A00100F8F0000084A00000000000000000000FFFFFF00FFFFFF000E8E - 00480E8D00CC5FD94FF933BC22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA2 - 0FE40E8D009E0F8F00081094000010950000084B0000FFFFFF00FFFFFF000F92 - 00CC6DE55CFA59D048FF69E158FC0F9200CC0F92006D139504CB34B423F832B2 - 21FF1F9F0FDF0F92008C109400021095000010950000FFFFFF00FFFFFF001196 - 0048119700CC73EA62FD119700CC119600480F9300001196004C189D08D33DB6 - 2CFB37AF26FE1FA00EDA1197007B11980000129B0000FFFFFF00FFFFFF001197 - 0000129B0048129B00CC129B0048119700000F93000011970000129B006924AA - 13D857CF46FE55CD44FD21A710D6129C006313A00000FFFFFF00FFFFFF001197 - 0000129B0000129C0000129B00001197000011990000129F0000129F000113A0 - 008533B820DE61D850FF5CD54BFA1EA80CD213A1004CFFFFFF00FFFFFF001197 - 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 - 000614A3009E43C631E56BE25AFF70E95FFB14A300CCFFFFFF00FFFFFF001197 - 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 - 000014A5001014A700B077EE66FF14A700CC14A70048FFFFFF00FFFFFF001197 - 0000129B0000129C0000129B00001197000013A2000014A5000014A5000014A6 - 000015A8000015A9001F15AA00CC15AA004814A70000FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btOkClick - TabOrder = 0 - end - object btCancel: TBitBtn - Left = 171 - Height = 26 - Top = 0 - Width = 82 - Align = alRight - AutoSize = True - BorderSpacing.Left = 6 - Caption = 'Cancel' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000013000000190000001900000016000000120000000F0000000E0000 - 0011000000150000001900000019000000140000000EFFFFFF00FFFFFF000000 - 001C000000260000346400005FCC00003561000000240000001D0000001B0000 - 00210000366000005FCC00003464000000270000001CFFFFFF00FFFFFF000000 - 1E0000005748000072CC1111D8FF000072CC0000574800002000000020000000 - 5748000072CC1111D8FF000072CC0000574800001E00FFFFFF00FFFFFF000000 - 8200000082CC1111D0FF1111D0FF1111D0FF000082CC00008348000083480000 - 82CC1111D0FF1111D0FF1111D0FF000082CC00008200FFFFFF00FFFFFF000000 - 860000008748000087CC1111C4FF1111C4FF1111C4FF000087CC000087CC1111 - C4FF1111C4FF1111C4FF000087CC0000874800008600FFFFFF00FFFFFF000000 - 86000000870000008C4800008DCC1111B8FF1111B8FF1111B8FF1111B8FF1111 - B8FF1111B8FF00008DCC00008C480000870000008600FFFFFF00FFFFFF000000 - 86000000870000008D0000009148000092CC1515AFFF1111ACFF1111ACFF1111 - ACFF000092CC0000914800008D000000870000008600FFFFFF00FFFFFF000000 - A1000000A00000009B0000009848000097CC2525B4FF1111A2FF1111A2FF1414 - A5FF000097CC0000984800009B000000A0000000A100FFFFFF00FFFFFF000000 - A1000000A00000009C4800009BCC5353DBFF2E2EB7FF3D3DC6FF3131BAFF1515 - 9FFF1E1EA8FF00009BCC00009C480000A0000000A100FFFFFF00FFFFFF000000 - A1000000A1480000A0CC6767EFFF3636BEFF5E5EE6FF0000A0CC0000A0CC4F4F - D7FF3636BEFF4545CDFF0000A0CC0000A1480000A100FFFFFF00FFFFFF000000 - A3000000A3CC7676FEFF4C4CD4FF7272FAFF0000A3CC0000A3480000A3480000 - A3CC6262EAFF4C4CD4FF5C5CE4FF0000A3CC0000A300FFFFFF00FFFFFF000000 - A6000000A7480000A7CC7777FFFF0000A7CC0000A7480000A3000000A3000000 - A7480000A7CC7070F8FF0000A7CC0000A7480000A600FFFFFF00FFFFFF000000 - A6000000A7000000AA480000AACC0000AA480000A7000000A3000000A3000000 - A7000000AA480000AACC0000AA480000A7000000A600FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - ModalResult = 2 - TabOrder = 1 - end - end object ckShowPassword: TCheckBox Left = 8 Height = 19 - Top = 176 - Width = 102 + Top = 158 + Width = 253 + Align = alTop Caption = 'Show password' OnChange = ckShowPasswordChange - TabOrder = 4 + TabOrder = 3 Visible = False end + object btOk: TBitBtn + AnchorSideRight.Control = btCancel + AnchorSideBottom.Control = btCancel + AnchorSideBottom.Side = asrBottom + Left = 112 + Height = 26 + Top = 200 + Width = 61 + Anchors = [akRight, akBottom] + AutoSize = True + Caption = 'Ok' + Default = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 00010000000800000010000000170000001A0000001900000017000000150000 + 00110000000D0000000A000000060000000300000001FFFFFF00FFFFFF000000 + 00020000000F0000001F0000002D02330066025F00CC012B0055000000290000 + 00220000001A000000130000000C0000000600000001FFFFFF00FFFFFF000000 + 0000000000000320000006570048077200CC16A60AE8087601C406570029021E + 00000000000000000000000000000000000000000000FFFFFF00FFFFFF000747 + 00000A6500000B8300480B8200CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85 + 001B0745000000000000000000000000000000000000FFFFFF00FFFFFF000E8D + 00000D8800480D8700CC43CA33F629C318FF39CC28FF28C217FF1EAA0FEA0D87 + 00AE0D8A00100F8F0000084A00000000000000000000FFFFFF00FFFFFF000E8E + 00480E8D00CC5FD94FF933BC22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA2 + 0FE40E8D009E0F8F00081094000010950000084B0000FFFFFF00FFFFFF000F92 + 00CC6DE55CFA59D048FF69E158FC0F9200CC0F92006D139504CB34B423F832B2 + 21FF1F9F0FDF0F92008C109400021095000010950000FFFFFF00FFFFFF001196 + 0048119700CC73EA62FD119700CC119600480F9300001196004C189D08D33DB6 + 2CFB37AF26FE1FA00EDA1197007B11980000129B0000FFFFFF00FFFFFF001197 + 0000129B0048129B00CC129B0048119700000F93000011970000129B006924AA + 13D857CF46FE55CD44FD21A710D6129C006313A00000FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000113A0 + 008533B820DE61D850FF5CD54BFA1EA80CD213A1004CFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000614A3009E43C631E56BE25AFF70E95FFB14A300CCFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000014A5001014A700B077EE66FF14A700CC14A70048FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000013A2000014A5000014A5000014A6 + 000015A8000015A9001F15AA00CC15AA004814A70000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOkClick + TabOrder = 4 + end + object btCancel: TBitBtn + AnchorSideRight.Control = Label1 + AnchorSideRight.Side = asrBottom + Left = 179 + Height = 26 + Top = 200 + Width = 82 + Anchors = [akRight, akBottom] + AutoSize = True + Caption = 'Cancel' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000013000000190000001900000016000000120000000F0000000E0000 + 0011000000150000001900000019000000140000000EFFFFFF00FFFFFF000000 + 001C000000260000346400005FCC00003561000000240000001D0000001B0000 + 00210000366000005FCC00003464000000270000001CFFFFFF00FFFFFF000000 + 1E0000005748000072CC1111D8FF000072CC0000574800002000000020000000 + 5748000072CC1111D8FF000072CC0000574800001E00FFFFFF00FFFFFF000000 + 8200000082CC1111D0FF1111D0FF1111D0FF000082CC00008348000083480000 + 82CC1111D0FF1111D0FF1111D0FF000082CC00008200FFFFFF00FFFFFF000000 + 860000008748000087CC1111C4FF1111C4FF1111C4FF000087CC000087CC1111 + C4FF1111C4FF1111C4FF000087CC0000874800008600FFFFFF00FFFFFF000000 + 86000000870000008C4800008DCC1111B8FF1111B8FF1111B8FF1111B8FF1111 + B8FF1111B8FF00008DCC00008C480000870000008600FFFFFF00FFFFFF000000 + 86000000870000008D0000009148000092CC1515AFFF1111ACFF1111ACFF1111 + ACFF000092CC0000914800008D000000870000008600FFFFFF00FFFFFF000000 + A1000000A00000009B0000009848000097CC2525B4FF1111A2FF1111A2FF1414 + A5FF000097CC0000984800009B000000A0000000A100FFFFFF00FFFFFF000000 + A1000000A00000009C4800009BCC5353DBFF2E2EB7FF3D3DC6FF3131BAFF1515 + 9FFF1E1EA8FF00009BCC00009C480000A0000000A100FFFFFF00FFFFFF000000 + A1000000A1480000A0CC6767EFFF3636BEFF5E5EE6FF0000A0CC0000A0CC4F4F + D7FF3636BEFF4545CDFF0000A0CC0000A1480000A100FFFFFF00FFFFFF000000 + A3000000A3CC7676FEFF4C4CD4FF7272FAFF0000A3CC0000A3480000A3480000 + A3CC6262EAFF4C4CD4FF5C5CE4FF0000A3CC0000A300FFFFFF00FFFFFF000000 + A6000000A7480000A7CC7777FFFF0000A7CC0000A7480000A3000000A3000000 + A7480000A7CC7070F8FF0000A7CC0000A7480000A600FFFFFF00FFFFFF000000 + A6000000A7000000AA480000AACC0000AA480000A7000000A3000000A3000000 + A7000000AA480000AACC0000AA480000A7000000A600FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ModalResult = 2 + TabOrder = 5 + end end diff --git a/mangadownloader/forms/frmAccountSet.pas b/mangadownloader/forms/frmAccountSet.pas index 81838463c..6630a5940 100644 --- a/mangadownloader/forms/frmAccountSet.pas +++ b/mangadownloader/forms/frmAccountSet.pas @@ -22,7 +22,6 @@ TAccountSetForm = class(TForm) Label1: TLabel; Label2: TLabel; Label3: TLabel; - pnButtons: TPanel; procedure btOkClick(Sender: TObject); procedure ckShowPasswordChange(Sender: TObject); private diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 365c83e4a..8ecb7ed8a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1134,6 +1134,8 @@ procedure TMainForm.FormCreate(Sender: TObject); with AccountManagerForm do begin Parent := tsAccounts; Align := alClient; + ChildSizing.LeftRightSpacing := 0; + ChildSizing.TopBottomSpacing := 0; Show; end; end; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8fdf19667..f12e1a187 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -293,6 +293,10 @@ msgstr "Edit" msgid "Refresh" msgstr "Refresh" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -320,6 +324,10 @@ msgstr "Cancel" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Show password" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index ae32f8e56..433f3101a 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -292,6 +292,10 @@ msgstr "Ubah" msgid "Refresh" msgstr "Segarkan" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" @@ -316,6 +320,10 @@ msgstr "Batal" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Tampilkan kata kunci" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index dfa351f08..ba08728ce 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -264,6 +264,10 @@ msgstr "" msgid "Refresh" msgstr "" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" @@ -288,6 +292,10 @@ msgstr "" msgid "Ok" msgstr "" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "" From 44b18e8e5d4877fa374533405356d0b1a050f74a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 00:28:12 +0800 Subject: [PATCH 1024/2794] fixed update dialog form layout --- mangadownloader/forms/frmUpdateDialog.lfm | 39 ++++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/mangadownloader/forms/frmUpdateDialog.lfm b/mangadownloader/forms/frmUpdateDialog.lfm index 5598b9d45..96194b458 100644 --- a/mangadownloader/forms/frmUpdateDialog.lfm +++ b/mangadownloader/forms/frmUpdateDialog.lfm @@ -5,19 +5,20 @@ object UpdateDialogForm: TUpdateDialogForm Width = 488 BorderIcons = [biSystemMenu] Caption = 'New Version Found' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 + ChildSizing.LeftRightSpacing = 8 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 ClientHeight = 420 ClientWidth = 488 Position = poOwnerFormCenter - LCLVersion = '1.5' + LCLVersion = '1.7' object mmLog: TMemo - Left = 6 + Left = 8 Height = 336 - Top = 46 - Width = 476 + Top = 44 + Width = 472 Align = alClient - BorderSpacing.Bottom = 6 Font.CharSet = ANSI_CHARSET Font.Height = -13 Font.Name = 'Courier New' @@ -33,33 +34,34 @@ object UpdateDialogForm: TUpdateDialogForm WordWrap = False end object lbMessage: TLabel - Left = 6 + Left = 8 Height = 30 - Top = 6 - Width = 476 + Top = 8 + Width = 472 Align = alTop - BorderSpacing.Bottom = 10 Caption = 'New version found! Do you want to update now?'#13#10'FMD will be closed to finish the update.' ParentColor = False end object pnBottom: TPanel - Left = 6 + Left = 8 Height = 26 - Top = 388 - Width = 476 + Top = 386 + Width = 472 Align = alBottom AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 2 ClientHeight = 26 - ClientWidth = 476 + ClientWidth = 472 TabOrder = 1 object btnUpdate: TBitBtn - Left = 78 + Left = 0 Height = 26 Top = 0 Width = 84 - Align = alLeft AutoSize = True Caption = '&Update' Default = True @@ -103,11 +105,10 @@ object UpdateDialogForm: TUpdateDialogForm TabOrder = 0 end object btnLater: TBitBtn - Left = 0 + Left = 90 Height = 26 Top = 0 Width = 72 - Align = alLeft AutoSize = True Caption = '&Later' Glyph.Data = { From 2f164799b173721477d78e4532a5e88126a09ef4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 00:32:26 +0800 Subject: [PATCH 1025/2794] fixed new chapter form layout --- mangadownloader/forms/frmNewChapter.lfm | 49 +++++++++++++------------ 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/mangadownloader/forms/frmNewChapter.lfm b/mangadownloader/forms/frmNewChapter.lfm index d6df897ce..766ad58cf 100644 --- a/mangadownloader/forms/frmNewChapter.lfm +++ b/mangadownloader/forms/frmNewChapter.lfm @@ -6,46 +6,49 @@ object NewChapter: TNewChapter BorderIcons = [] BorderStyle = bsSizeToolWin Caption = 'New Chapter Notification' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 + ChildSizing.LeftRightSpacing = 8 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 ClientHeight = 290 ClientWidth = 394 OnCreate = FormCreate Position = poDesktopCenter - LCLVersion = '1.5' - object mmMemo: TMemo - Left = 6 - Height = 235 - Top = 17 - Width = 382 - Align = alClient - BorderSpacing.Bottom = 6 - ReadOnly = True - ScrollBars = ssAutoBoth - TabOrder = 0 - end + LCLVersion = '1.7' object lbNotification: TLabel - Left = 6 + Left = 8 Height = 1 - Top = 6 - Width = 382 + Top = 8 + Width = 378 Align = alTop - BorderSpacing.Bottom = 10 Font.Style = [fsBold] ParentColor = False ParentFont = False end + object mmMemo: TMemo + Left = 8 + Height = 235 + Top = 15 + Width = 378 + Align = alClient + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 0 + end object pnBottom: TPanel - Left = 6 + Left = 8 Height = 26 - Top = 258 - Width = 382 + Top = 256 + Width = 378 Align = alBottom AutoSize = True BevelOuter = bvNone ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 4 ClientHeight = 26 - ClientWidth = 382 + ClientWidth = 378 TabOrder = 1 object btDownload: TBitBtn Left = 0 @@ -145,7 +148,7 @@ object NewChapter: TNewChapter TabOrder = 2 end object btCancel: TBitBtn - Left = 300 + Left = 296 Height = 26 Top = 0 Width = 82 From 45920917736ae6768d68c7d7a60aee5e5679cbe9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 01:33:09 +0800 Subject: [PATCH 1026/2794] fixed import favorites form layout --- mangadownloader/forms/frmImportFavorites.lfm | 167 ++++++++++--------- mangadownloader/forms/frmImportFavorites.pas | 32 +--- mangadownloader/forms/frmMain.lfm | 20 +-- mangadownloader/languages/fmd.en.po | 10 +- mangadownloader/languages/fmd.id_ID.po | 10 +- mangadownloader/languages/fmd.po | 4 +- 6 files changed, 112 insertions(+), 131 deletions(-) diff --git a/mangadownloader/forms/frmImportFavorites.lfm b/mangadownloader/forms/frmImportFavorites.lfm index 177f67f5c..8b73f01a5 100644 --- a/mangadownloader/forms/frmImportFavorites.lfm +++ b/mangadownloader/forms/frmImportFavorites.lfm @@ -1,21 +1,33 @@ object ImportFavorites: TImportFavorites Left = 480 - Height = 171 + Height = 127 Top = 298 - Width = 406 + Width = 426 BorderIcons = [biSystemMenu] - BorderStyle = bsDialog Caption = 'Import list ...' - ClientHeight = 171 - ClientWidth = 406 - OnCreate = FormCreate + ChildSizing.LeftRightSpacing = 8 + ChildSizing.TopBottomSpacing = 8 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 6 + ClientHeight = 127 + ClientWidth = 426 Position = poDesktopCenter - LCLVersion = '1.5' + LCLVersion = '1.7' + object lbSelectSoftware: TLabel + Left = 8 + Height = 15 + Top = 8 + Width = 410 + Align = alTop + Caption = 'Software:' + ParentColor = False + end object cbSoftware: TComboBox - Left = 16 + Left = 8 Height = 23 - Top = 32 - Width = 371 + Top = 29 + Width = 410 + Align = alTop ItemHeight = 15 ItemIndex = 0 Items.Strings = ( @@ -26,19 +38,63 @@ object ImportFavorites: TImportFavorites TabOrder = 0 Text = 'Domdomsoft Manga Downloader' end - object edPath: TEdit - Left = 16 + object edPath: TDirectoryEdit + Left = 8 Height = 23 - Top = 72 - Width = 344 - TabOrder = 1 - Text = 'Path to the software (e.g. C:\MangaDownloader)' + Top = 58 + Width = 410 + ShowHidden = False + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0046699C005C8BBF005C8BBF005C8BBF005C8BBF005C8BBF005C8BBF005C + 8BBF005C8BBF005C8BBF005C8BBF0046699C0000002C000000120000000A0000 + 0016006395B486CFF0FF81CBEDFF81CBEDFF81CBEDFF81CBEDFF81CBEDFF81CB + EDFF86CFF0FF4B8FB1FF86CFF0FF006395B4004060510000000A000000000052 + 7B00006CA3A884CEEEFF7CC7E8FF7CC7E8FF7CC7E8FF7CC7E8FF7CC7E8FF7CC7 + E8FF84CEEEFF579BBDFF84CEEEFFF4B62EFF006CA3A800527B00005681000072 + AB000072ABA087D0EFFF7FCAE9FF7FCAE9FF7FCAE9FF7FCAE9FF7FCAE9FF7FCA + E9FF87D0EFFF5FA3C5FF87D0EFFFFEC941FF0072ABA00072AB000074AE000074 + AE000074AE9D8AD3F0FF82CDEBFF82CDEBFF82CDEBFF82CDEBFF82CDEBFF82CD + EBFF8AD3F0FF62A6C8FF8AD3F0FFE9E9DBFF0074AE9D0074AE000076B1000076 + B1000076B19A8ED6F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF8ED6F2FF66AACCFF8ED6F2FFF0F0E6FF0076B19A0076B1000079B5000079 + B5000079B59792DAF4FF8BD4F0FF8BD4F0FF8BD4F0FF8BD4F0FF8BD4F0FF8BD4 + F0FF92DAF4FF69ADCFFF92DAF4FFF8F8F3FF0079B5970079B500007BB800007B + B800007BB89497DEF6FF90D8F2FF90D8F2FF90D8F2FF90D8F2FF90D8F2FF90D8 + F2FF97DEF6FF79BDDCFF78BDDCFFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB919BE1F7FF94DBF4FF94DBF4FF94DBF4FF94DBF4FF94DBF4FF94DB + F4FF94DBF4FF9EE4F9FF7CC0DEFF007DBB91007DBB33007CBA00007FBE00007F + BE00007FBE8E9EE5F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FFA1E8FAFF007FBE8E007EBE00007EBD000081C1000081 + C1000081C18BA3E8FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3 + F9FF9DE3F9FF9DE3F9FFA3E8FBFF0081C18B0081C1000081C1000083C4000083 + C4000083C489A6EBFCFFA1E6FBFFA1E6FBFFA1E6FBFFA1E6FBFFA1E6FBFFA1E6 + FBFFA1E6FBFFA1E6FBFFA6EBFCFF0083C4890083C4000083C4000084C6000084 + C6000084C686A9EEFDFFA4E9FCFFA4E9FCFFA4E9FCFFA4E9FCFFA4E9FCFFA4E9 + FCFFA4E9FCFFA4E9FCFFA9EEFDFF0084C6860084C6000084C6000086C9000086 + C9000086C984ACF1FFFFA7ECFEFFA7ECFEFFA7ECFEFFA7ECFEFFA7ECFEFFA7EC + FEFFA7ECFEFFA7ECFEFFACF1FFFF0086C9840086C9000086C9000087CA000087 + CA000087CA82B1F5FFFFAEF2FFFFAEF2FFFFAEF2FFFFAEF2FFFFAEF2FFFFAEF2 + FFFFAEF2FFFFAEF2FFFFB1F5FFFF0087CA820087CA000087CA000088CB000088 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610088CB000088CB00 + } + NumGlyphs = 1 + Align = alTop + MaxLength = 0 + TabOrder = 3 + TextHint = 'Path to the software (e.g. C:\MangaDownloader)' end object btImport: TBitBtn - Left = 152 - Height = 24 - Top = 128 - Width = 104 + AnchorSideLeft.Control = lbSelectSoftware + Left = 8 + Height = 26 + Top = 92 + Width = 62 + Anchors = [akLeft, akBottom] + AutoSize = True Caption = '&OK' Default = True Glyph.Data = { @@ -79,13 +135,17 @@ object ImportFavorites: TImportFavorites } ModalResult = 1 OnClick = btImportClick - TabOrder = 2 + TabOrder = 1 end object btCancel: TBitBtn - Left = 272 - Height = 24 - Top = 128 - Width = 104 + AnchorSideLeft.Control = btImport + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btImport + Left = 74 + Height = 26 + Top = 92 + Width = 82 + AutoSize = True Caption = 'Cancel' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -124,61 +184,6 @@ object ImportFavorites: TImportFavorites FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } ModalResult = 2 - TabOrder = 3 - end - object lbSelectSoftware: TLabel - Left = 16 - Height = 15 - Top = 16 - Width = 49 - Caption = 'Software:' - ParentColor = False - end - object btBrowse: TSpeedButton - Left = 364 - Height = 23 - Top = 72 - Width = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btBrowseClick - end - object dlgPath: TSelectDirectoryDialog - left = 224 - top = 8 + TabOrder = 2 end end diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index 04324f585..b97cfcc91 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, Forms, Dialogs, StdCtrls, Buttons, DefaultTranslator, + Classes, SysUtils, Forms, Dialogs, StdCtrls, Buttons, DefaultTranslator, EditBtn, lazutf8classes, LazFileUtils, uBaseUnit, WebsiteModules, RegExpr, frmNewChapter; @@ -20,16 +20,12 @@ interface { TImportFavorites } TImportFavorites = class(TForm) - btBrowse: TSpeedButton; btImport: TBitBtn; btCancel: TBitBtn; cbSoftware: TComboBox; - edPath: TEdit; - dlgPath: TSelectDirectoryDialog; + edPath: TDirectoryEdit; lbSelectSoftware: TLabel; - procedure btBrowseClick(Sender: TObject); procedure btImportClick(Sender: TObject); - procedure FormCreate(Sender: TObject); private { private declarations } procedure DMDHandle; @@ -68,14 +64,14 @@ procedure TImportFavorites.DMDHandle; i, j, m: Integer; regx: TRegExpr; begin - if NOT FileExistsUTF8(CorrectFilePath(edPath.Text) + 'Config/Bookmarks') then + if NOT FileExistsUTF8(CleanAndExpandDirectory(edPath.Text) + 'Config/Bookmarks') then exit; list:= TStringList.Create; urlList:= TStringList.Create; mangaList:= TStringList.Create; unimportedMangas:= TStringList.Create; - fstream:= TFileStreamUTF8.Create(CorrectFilePath(edPath.Text) + 'Config/Bookmarks', fmOpenRead); + fstream:= TFileStreamUTF8.Create(CleanAndExpandDirectory(edPath.Text) + 'Config/Bookmarks', fmOpenRead); list.LoadFromStream(fstream); if list.Count > 0 then @@ -91,7 +87,7 @@ procedure TImportFavorites.DMDHandle; if urlList.Count > 0 then begin - path:= CorrectFilePath(MainForm.options.ReadString('saveto', 'SaveTo', '')); + path:= CleanAndExpandDirectory(MainForm.options.ReadString('saveto', 'SaveTo', '')); regx := TRegExpr.Create; try regx.Expression := REGEX_HOST; @@ -155,7 +151,7 @@ procedure TImportFavorites.DMDHandle; procedure TImportFavorites.FMDHandle; begin - MainForm.FavoriteManager.MergeWith(CorrectFilePath(edPath.Text) + 'works/favorites.ini'); + MainForm.FavoriteManager.MergeWith(CleanAndExpandDirectory(edPath.Text) + 'works/favorites.ini'); MessageDlg('', RS_ImportCompleted, mtConfirmation, [mbYes], 0) @@ -171,22 +167,6 @@ procedure TImportFavorites.Run; { ----- public methods ----- } -procedure TImportFavorites.FormCreate(Sender: TObject); -begin - Caption:= MainForm.btFavoritesImport.Caption; - btImport.Caption:= RS_Import; - edPath.Text:= RS_SoftwarePath; - btCancel.Caption:= RS_Cancel; - lbSelectSoftware.Caption:= RS_Software; -end; - -procedure TImportFavorites.btBrowseClick(Sender: TObject); -begin - dlgPath.InitialDir:= CorrectFilePath(edPath.Text); - if dlgPath.Execute then - edPath.Text:= CorrectFilePath(dlgPath.FileName); -end; - procedure TImportFavorites.btImportClick(Sender: TObject); begin Run; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f7289290b..cadceeb00 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1698,13 +1698,13 @@ object MainForm: TMainForm end object tsFavorites: TTabSheet Caption = 'Favorites' - ClientHeight = 511 - ClientWidth = 525 + ClientHeight = 462 + ClientWidth = 558 object btFavoritesCheckNewChapter: TBitBtn Left = 33 Height = 40 - Top = 431 - Width = 458 + Top = 382 + Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Check for new chapter' Glyph.Data = { @@ -1748,9 +1748,9 @@ object MainForm: TMainForm end object vtFavorites: TVirtualStringTree Left = 4 - Height = 420 + Height = 371 Top = 4 - Width = 517 + Width = 550 Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Around = 4 @@ -1811,8 +1811,8 @@ object MainForm: TMainForm object btFavoritesImport: TBitBtn Left = 33 Height = 24 - Top = 477 - Width = 458 + Top = 428 + Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Import list' Glyph.Data = { @@ -1856,9 +1856,9 @@ object MainForm: TMainForm TabOrder = 2 end object btCancelFavoritesCheck: TSpeedButton - Left = 457 + Left = 490 Height = 40 - Top = 431 + Top = 382 Width = 34 Anchors = [akRight, akBottom] Glyph.Data = { diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index f12e1a187..ba696d63d 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -295,7 +295,7 @@ msgstr "Refresh" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "AccountManagerForm" #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" @@ -326,7 +326,7 @@ msgstr "Ok" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Account" #: taccountsetform.ckshowpassword.caption msgid "Show password" @@ -392,8 +392,8 @@ msgstr "Import list ..." msgid "Domdomsoft Manga Downloader" msgstr "Domdomsoft Manga Downloader" -#: timportfavorites.edpath.text -msgctxt "TIMPORTFAVORITES.EDPATH.TEXT" +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" msgid "Path to the software (e.g. C:\\MangaDownloader)" msgstr "Path to the software (e.g. C:\\MangaDownloader)" @@ -467,7 +467,6 @@ msgid "Visit my blog" msgstr "Visit my blog" #: tmainform.caption -#, fuzzy msgctxt "tmainform.caption" msgid "Free Manga Downloader" msgstr "Free Manga Downloader" @@ -1838,4 +1837,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 433f3101a..b4735c75c 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -294,7 +294,7 @@ msgstr "Segarkan" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "AccountManagerForm" #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -322,7 +322,7 @@ msgstr "Ok" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Akun" #: taccountsetform.ckshowpassword.caption msgid "Show password" @@ -385,8 +385,8 @@ msgstr "Impor daftar ..." msgid "Domdomsoft Manga Downloader" msgstr "Domdomsoft Manga Downloader" -#: timportfavorites.edpath.text -msgctxt "timportfavorites.edpath.text" +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" msgid "Path to the software (e.g. C:\\MangaDownloader)" msgstr "Path ke perangkat lunak (misalnya C:\\MangaDownloader)" @@ -459,7 +459,6 @@ msgid "Visit my blog" msgstr "Kunjungi blog" #: tmainform.caption -#, fuzzy msgctxt "tmainform.caption" msgid "Free Manga Downloader" msgstr "Free Manga Downloader" @@ -1822,4 +1821,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index ba08728ce..47ccc7c31 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -357,8 +357,8 @@ msgstr "" msgid "Domdomsoft Manga Downloader" msgstr "" -#: timportfavorites.edpath.text -msgctxt "TIMPORTFAVORITES.EDPATH.TEXT" +#: timportfavorites.edpath.texthint +msgctxt "TIMPORTFAVORITES.EDPATH.TEXTHINT" msgid "Path to the software (e.g. C:\\MangaDownloader)" msgstr "" From 283901e8745dada6664f28eaa87f0f767075845a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 14:53:20 +0800 Subject: [PATCH 1027/2794] added option to hide downloaded chapters from list chapterlist>right click menu>hide downloaded chapters --- mangadownloader/forms/frmMain.lfm | 70 ++++++++++++++------------ mangadownloader/forms/frmMain.pas | 34 ++++++++++--- mangadownloader/languages/fmd.en.po | 5 ++ mangadownloader/languages/fmd.id_ID.po | 5 ++ mangadownloader/languages/fmd.po | 4 ++ 5 files changed, 79 insertions(+), 39 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index cadceeb00..285ecd515 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,11 +1,11 @@ object MainForm: TMainForm Left = 379 - Height = 557 - Top = 148 + Height = 592 + Top = 113 Width = 771 ActiveControl = pcMain Caption = 'Free Manga Downloader' - ClientHeight = 557 + ClientHeight = 592 ClientWidth = 771 OnClose = FormClose OnCreate = FormCreate @@ -17,7 +17,7 @@ object MainForm: TMainForm object sbUpdateList: TStatusBar Left = 0 Height = 30 - Top = 527 + Top = 562 Width = 771 AutoSize = False Panels = < @@ -33,7 +33,7 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 490 + Height = 525 Top = 11 Width = 566 ActivePage = tsDownload @@ -47,11 +47,11 @@ object MainForm: TMainForm OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' - ClientHeight = 462 + ClientHeight = 497 ClientWidth = 558 object vtDownload: TVirtualStringTree Left = 4 - Height = 426 + Height = 461 Top = 32 Width = 550 Align = alClient @@ -260,22 +260,22 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 462 + ClientHeight = 497 ClientWidth = 558 object sbInformation: TScrollBox Left = 0 - Height = 462 + Height = 497 Top = 0 Width = 558 HorzScrollBar.Page = 327 - VertScrollBar.Page = 452 + VertScrollBar.Page = 487 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 462 + ClientHeight = 497 ClientWidth = 558 TabOrder = 0 object pnInfomation: TPanel @@ -420,20 +420,21 @@ object MainForm: TMainForm end object pnChapterList: TPanel Left = 4 - Height = 171 + Height = 206 Top = 283 Width = 550 Align = alClient BevelOuter = bvNone ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 171 + ClientHeight = 206 ClientWidth = 550 TabOrder = 2 object clbChapterList: TVirtualStringTree + AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = lbSaveTo Left = 0 - Height = 92 + Height = 127 Top = 0 Width = 516 Anchors = [akTop, akLeft, akRight, akBottom] @@ -464,7 +465,7 @@ object MainForm: TMainForm AnchorSideBottom.Side = asrBottom Left = 338 Height = 26 - Top = 115 + Top = 150 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True @@ -516,11 +517,10 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 0 Height = 19 - Top = 142 + Top = 177 Width = 334 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' - OnChange = cbAddAsStoppedChange ParentFont = False TabOrder = 3 end @@ -530,7 +530,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 442 Height = 26 - Top = 115 + Top = 150 Width = 108 Anchors = [akRight, akBottom] AutoSize = True @@ -628,7 +628,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 338 Height = 26 - Top = 145 + Top = 180 Width = 212 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True @@ -679,7 +679,7 @@ object MainForm: TMainForm AnchorSideBottom.Control = edSaveTo Left = 0 Height = 15 - Top = 96 + Top = 131 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' @@ -692,7 +692,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btDownload Left = 0 Height = 23 - Top = 115 + Top = 150 Width = 334 ShowHidden = False ButtonWidth = 23 @@ -1903,11 +1903,11 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 462 + ClientHeight = 497 ClientWidth = 558 object pnOptions: TPageControl Left = 8 - Height = 385 + Height = 420 Top = 8 Width = 539 ActivePage = tsGeneral @@ -1921,7 +1921,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 + ClientHeight = 392 ClientWidth = 531 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime @@ -3125,11 +3125,11 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 + ClientHeight = 392 ClientWidth = 531 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 4 - Height = 312 + Height = 347 Top = 37 Width = 523 Align = alClient @@ -3387,7 +3387,7 @@ object MainForm: TMainForm object btOptionApply: TBitBtn Left = 8 Height = 45 - Top = 404 + Top = 439 Width = 125 Anchors = [akLeft, akBottom] AutoSize = True @@ -3649,7 +3649,7 @@ object MainForm: TMainForm end object pcLeft: TPageControl Left = 4 - Height = 488 + Height = 523 Top = 12 Width = 195 ActivePage = tsMangaList @@ -3666,7 +3666,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 460 + ClientHeight = 495 ClientWidth = 187 object vtMangaList: TVirtualStringTree AnchorSideLeft.Control = lbMode @@ -3675,7 +3675,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btRemoveFilter AnchorSideRight.Side = asrBottom Left = 4 - Height = 371 + Height = 406 Top = 85 Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] @@ -3976,7 +3976,7 @@ object MainForm: TMainForm object sbMain: TStatusBar Left = 0 Height = 23 - Top = 504 + Top = 539 Width = 771 Panels = < item @@ -3990,7 +3990,7 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 496 + Height = 531 Top = 8 Width = 2 OnMoved = spMainSplitterMoved @@ -4348,12 +4348,16 @@ object MainForm: TMainForm Caption = 'Highlight download chapters' OnClick = miChapterListHighlightClick end + object miChapterListHideDownloaded: TMenuItem + Caption = 'Hide downloaded chapters' + OnClick = miChapterListHideDownloadedClick + end end object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup left = 520 - top = 228 + top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8ecb7ed8a..49c6d4a2b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -72,6 +72,7 @@ TMainForm = class(TForm) gbEHentai: TGroupBox; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; + miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; Panel1: TPanel; @@ -388,7 +389,6 @@ TMainForm = class(TForm) procedure btFilterResetClick(Sender: TObject); procedure btRemoveFilterClick(Sender: TObject); - procedure cbAddAsStoppedChange(Sender: TObject); procedure cbOptionUseProxyChange(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); @@ -409,6 +409,7 @@ TMainForm = class(TForm) procedure medURLSelectAllClick(Sender: TObject); procedure medURLUndoClick(Sender: TObject); procedure miAbortSilentThreadClick(Sender: TObject); + procedure miChapterListHideDownloadedClick(Sender: TObject); procedure miDownloadViewMangaInfoClick(Sender: TObject); procedure miChapterListHighlightClick(Sender: TObject); procedure miDownloadDeleteTaskClick(Sender: TObject); @@ -1475,6 +1476,29 @@ procedure TMainForm.miAbortSilentThreadClick(Sender: TObject); SilentThreadManager.StopAll(False); end; +procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); +var + xnode: PVirtualNode; +begin + if Sender = miChapterListHideDownloaded then + miChapterListHideDownloaded.Checked := not miChapterListHideDownloaded.Checked; + if (Length(ChapterList) = 0) or (Length(ChapterList) <> clbChapterList.RootNodeCount) then Exit; + clbChapterList.BeginUpdate; + try + xnode := clbChapterList.GetFirst; + while Assigned (xnode) do + begin + if miChapterListHideDownloaded.Checked and ChapterList[xnode^.Index].Downloaded then + Exclude(xnode^.States, vsVisible) + else + Include(xnode^.States, vsVisible); + xnode := clbChapterList.GetNext(xnode); + end; + finally + clbChapterList.EndUpdate; + end; +end; + procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); var i: Integer; @@ -3799,11 +3823,6 @@ procedure TMainForm.btOptionApplyClick(Sender: TObject); if not Self.Focused then Self.SetFocus; end; -procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); -begin - options.WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); -end; - // vtMangaList procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; @@ -4135,6 +4154,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); else ClearChapterListState; UpdateVtChapter; + miChapterListHideDownloadedClick(nil); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); btReadOnline.Enabled := (mangaInfo.link <> ''); @@ -4173,6 +4193,7 @@ procedure TMainForm.LoadOptions; cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); edOptionExternalPath.FileName := ReadString('general', 'ExternalProgramPath', ''); edOptionExternalParams.Text := ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); + miChapterListHideDownloaded.Checked := ReadBool('general', 'ChapterListHideDownloaded', False); cbAddAsStopped.Checked := ReadBool('general', 'AddAsStopped', False); miHighLightNewManga.Checked := ReadBool('general', 'HighlightNewManga', True); miChapterListHighlight.Checked := ReadBool('general', 'HighlightDownloadedChapters', True); @@ -4304,6 +4325,7 @@ procedure TMainForm.SaveOptions; WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); WriteString('general', 'ExternalProgramPath', edOptionExternalPath.FileName); WriteString('general', 'ExternalProgramParams', edOptionExternalParams.Text); + WriteBool('general', 'ChapterListHideDownloaded', miChapterListHideDownloaded.Checked); WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); WriteBool('general', 'HighlightNewManga', miHighlightNewManga.Checked); WriteBool('general', 'HighlightDownloadedChapters', miChapterListHighlight.Checked); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index ba696d63d..01bdcc381 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1313,6 +1313,10 @@ msgstr "Check all" msgid "Check selected" msgstr "Check selected" +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "" + #: tmainform.michapterlisthighlight.caption msgid "Highlight download chapters" msgstr "Highlight download chapters" @@ -1837,3 +1841,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index b4735c75c..5fe0bc375 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1297,6 +1297,10 @@ msgstr "Centang semua" msgid "Check selected" msgstr "Centang yang dipilih" +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "" + #: tmainform.michapterlisthighlight.caption msgid "Highlight download chapters" msgstr "Sorot bab terunduh" @@ -1821,3 +1825,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 47ccc7c31..9e0840e3a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1242,6 +1242,10 @@ msgstr "" msgid "Check selected" msgstr "" +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "" + #: tmainform.michapterlisthighlight.caption msgid "Highlight download chapters" msgstr "" From 433b7882521d3015f3218e18720a447ffc6e310a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 14:55:32 +0800 Subject: [PATCH 1028/2794] fixed typo --- mangadownloader/forms/frmMain.lfm | 2 +- mangadownloader/languages/fmd.en.po | 8 ++++---- mangadownloader/languages/fmd.id_ID.po | 3 +-- mangadownloader/languages/fmd.po | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 285ecd515..b54381099 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4345,7 +4345,7 @@ object MainForm: TMainForm Caption = '-' end object miChapterListHighlight: TMenuItem - Caption = 'Highlight download chapters' + Caption = 'Highlight downloaded chapters' OnClick = miChapterListHighlightClick end object miChapterListHideDownloaded: TMenuItem diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 01bdcc381..61c11b714 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1315,11 +1315,12 @@ msgstr "Check selected" #: tmainform.michapterlisthidedownloaded.caption msgid "Hide downloaded chapters" -msgstr "" +msgstr "Hide downloaded chapters" #: tmainform.michapterlisthighlight.caption -msgid "Highlight download chapters" -msgstr "Highlight download chapters" +#| msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" +msgstr "Highlight downloaded chapters" #: tmainform.michapterlistuncheckall.caption msgid "Uncheck all" @@ -1841,4 +1842,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 5fe0bc375..c95ffa9ad 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1302,7 +1302,7 @@ msgid "Hide downloaded chapters" msgstr "" #: tmainform.michapterlisthighlight.caption -msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" msgstr "Sorot bab terunduh" #: tmainform.michapterlistuncheckall.caption @@ -1825,4 +1825,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 9e0840e3a..4f6c14334 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1247,7 +1247,7 @@ msgid "Hide downloaded chapters" msgstr "" #: tmainform.michapterlisthighlight.caption -msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" msgstr "" #: tmainform.michapterlistuncheckall.caption From 5b66baa896e51daf06e6990deb4458380ff84a53 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 14:56:15 +0800 Subject: [PATCH 1029/2794] updated indonesian translations --- mangadownloader/languages/fmd.id_ID.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index c95ffa9ad..edf52f2e1 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1299,7 +1299,7 @@ msgstr "Centang yang dipilih" #: tmainform.michapterlisthidedownloaded.caption msgid "Hide downloaded chapters" -msgstr "" +msgstr "Sembunyikan bab terunduh" #: tmainform.michapterlisthighlight.caption msgid "Highlight downloaded chapters" From 1ff4ed1cee02ae59ac9a881bbc0cfa505211dace Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 15:00:39 +0800 Subject: [PATCH 1030/2794] fixed and cleanup menu highlight downloaded chapters --- mangadownloader/forms/frmMain.pas | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 49c6d4a2b..cfa6dfe5b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1518,18 +1518,15 @@ procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); procedure TMainForm.miChapterListHighlightClick(Sender: TObject); begin - miChapterListHighlight.Checked := not miChapterListHighlight.Checked; - options.WriteBool('general', 'HighlightDownloadedChapters', - miChapterListHighlight.Checked); - if Length(ChapterList) > 0 then - begin - if miChapterListHighlight.Checked then - DLManager.GetDownloadedChaptersState(mangaInfo.website + mangaInfo.link, - ChapterList) - else - ClearChapterListState; - clbChapterList.Repaint; - end; + if Sender = miChapterListHighlight then + miChapterListHighlight.Checked := not miChapterListHighlight.Checked; + if Length(ChapterList) = 0 then Exit; + if miChapterListHighlight.Checked then + DLManager.GetDownloadedChaptersState(mangaInfo.website + mangaInfo.link, + ChapterList) + else + ClearChapterListState; + clbChapterList.Repaint; end; procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); @@ -4148,11 +4145,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); ChapterList[i].Link := mangaInfo.chapterLinks[i]; ChapterList[i].Downloaded := False; end; - if miChapterListHighlight.Checked then - DLManager.GetDownloadedChaptersState(mangaInfo.website + mangaInfo.link, - ChapterList) - else - ClearChapterListState; + miChapterListHighlightClick(nil); UpdateVtChapter; miChapterListHideDownloadedClick(nil); From c06accde04794431478eb3b29c02a7de2e0f71ba Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 15:05:53 +0800 Subject: [PATCH 1031/2794] fixed don't include selected chapters with invisible state --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index cfa6dfe5b..7d2458668 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1884,7 +1884,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); xNode := clbChapterList.GetFirstChecked; for i := 0 to clbChapterList.CheckedCount - 1 do begin - if xNode^.CheckState = csCheckedNormal then + if (xNode^.CheckState = csCheckedNormal) and (vsVisible in xNode^.States) then begin if not isCreate then begin From fef47fcecde22afd1423cb843bef566391882045 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Mar 2016 15:18:52 +0800 Subject: [PATCH 1032/2794] fixed save menu checkbox state when changed --- mangadownloader/forms/frmMain.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7d2458668..d20dc4169 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1481,7 +1481,10 @@ procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); xnode: PVirtualNode; begin if Sender = miChapterListHideDownloaded then + begin miChapterListHideDownloaded.Checked := not miChapterListHideDownloaded.Checked; + options.WriteBool('general', 'ChapterListHideDownloaded', miChapterListHideDownloaded.Checked); + end; if (Length(ChapterList) = 0) or (Length(ChapterList) <> clbChapterList.RootNodeCount) then Exit; clbChapterList.BeginUpdate; try @@ -1519,7 +1522,10 @@ procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); procedure TMainForm.miChapterListHighlightClick(Sender: TObject); begin if Sender = miChapterListHighlight then + begin miChapterListHighlight.Checked := not miChapterListHighlight.Checked; + options.WriteBool('general', 'HighlightDownloadedChapters', miChapterListHighlight.Checked); + end; if Length(ChapterList) = 0 then Exit; if miChapterListHighlight.Checked then DLManager.GetDownloadedChaptersState(mangaInfo.website + mangaInfo.link, From e9ccbe01eb6ddf904322dde2759c2327885ffbf3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 20 Mar 2016 20:45:45 +0800 Subject: [PATCH 1033/2794] fixed hentai2read chapter list order fixed #210 --- baseunits/modules/Hentai2Read.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 3f87febf5..2d4205e4f 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -110,6 +110,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(XPathString('text()', v.toNode)); end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; From e336fd7713535430daf5f285537d576eea88acf7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Mar 2016 18:09:07 +0800 Subject: [PATCH 1034/2794] mangafox, fixed getting all chapter fixed #211 --- baseunits/modules/MangaFox.pas | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 75d67d907..d37b16cd1 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -36,7 +36,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -58,15 +57,11 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; artists := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[3]'); genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); summary := XPathString('//p[@class="summary"]'); - for v in XPath('//ul[@class="chlist"]/li//h3') do + for v in XPath('//ul[@class="chlist"]/li') do begin - s := XPathString('a/@href', v.toNode); - if RightStr(s, 6) = '1.html' then - SetLength(s, Length(s) - 6); - chapterLinks.Add(s); - s := XPathString('a', v.toNode); - s := s + ' ' + XPathString('span[@class="title nowrap"]', v.toNode); - chapterName.Add(s); + chapterLinks.Add(XPathString('div/*/a[@class="tips"]/@href', v.toNode)); + chapterName.Add(Trim(XPathString('div/*/a[@class="tips"]', v.toNode) + ' ' + + XPathString('div/*/span[@class="title nowrap"]', v.toNode))); end; InvertStrings([chapterLinks, chapterName]); finally @@ -89,7 +84,12 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1.html') then begin + s := ChapterLinks[CurrentDownloadChapterPtr]; + if RightStr(s, 6) = '1.html' then begin + SetLength(s, Length(s) - 6); + ChapterLinks[CurrentDownloadChapterPtr] := s; + end; + if GET(AppendURLDelim(FillHost(Module.RootURL, s)) + '1.html') then begin Result := True; with TXQueryEngineHTML.Create(Document) do try From 20528b7d68e6ed26a80025c1cb8a78c86f7d2967 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Mar 2016 21:08:33 +0800 Subject: [PATCH 1035/2794] Bump version 0.9.42.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5d7763433..74dbda97b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.42.0 (22-03-2016) +[+] Added option to hide downloaded chapter. chapter list > right click > hide downloaded chapter +[*] Fixed various form layout +[*] Hentai2Read: fixed chapter list order +[*] MangaFox: fixed only show last 10 chapter +[*] Various changes and bug fixes + 0.9.41.0 (18-03-2016) [*] MangaFox: fixed remove watermark and rewrite all code [*] Tsumino: fixed get image url diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 298024e82..1518a110e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="41"/> + <RevisionNr Value="42"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5dde8ebe0..6f79e3f55 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.41.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.41.0/fmd_0.9.41.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.41.0/fmd_0.9.41.0_Win64.7z +VERSION=0.9.42.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.42.0/fmd_0.9.42.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.42.0/fmd_0.9.42.0_Win64.7z From 113bc015bcb03891c89bd8c539f7cd4c4da3b1fb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 18:53:23 +0800 Subject: [PATCH 1036/2794] baseunit, added overload of saveimage --- baseunits/uBaseUnit.pas | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5b34caa2d..f6307fd90 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -915,6 +915,8 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: Stri const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; +function SaveImage(const AHTTP: THTTPSend; URL: String; + const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; @@ -3441,6 +3443,14 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; Result := SaveImage(AHTTP, mangaSiteID, URL, Path, Name, f, Reconnect); end; +function SaveImage(const AHTTP: THTTPSend; URL: String; const Path, Name: String; const Reconnect: Integer + ): Boolean; +var + f: String; +begin + Result := SaveImage(AHTTP, -1, URL, Path, Name, f, Reconnect); +end; + function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; begin From cf0f9aa2602eb9967fa5e6e95e1b6706a6a00aaa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 19:11:29 +0800 Subject: [PATCH 1037/2794] downloadmanager, failed status use available resourcestring --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index cd0d78aae..c9b150ee0 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1074,7 +1074,7 @@ function TDownloadThread.DownloadImage: Boolean; if not ForceDirectoriesUTF8(lpath) then begin manager.container.Status := STATUS_FAILED; - manager.container.DownloadInfo.Status := 'Failed to create dir! Too long?'; + manager.container.DownloadInfo.Status := RS_FailedToCreateDir; Result := False; Exit; end; From 34dfa74c015ce7153037de1cc340b7607f6c1c37 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 19:51:39 +0800 Subject: [PATCH 1038/2794] cleanup unused code --- baseunits/modules/AcademyVN.pas | 1 - baseunits/modules/FoOlSlide.pas | 1 - baseunits/modules/GameofScanlation.pas | 1 - baseunits/modules/Hakihome.pas | 1 - baseunits/modules/Hentai2Read.pas | 1 - baseunits/modules/HentaiCafe.pas | 1 - baseunits/modules/HitomiLa.pas | 1 - baseunits/modules/KissManga.pas | 1 - baseunits/modules/Luscious.pas | 1 - baseunits/modules/Madokami.pas | 1 - baseunits/modules/MangaBackup.pas | 1 - baseunits/modules/MangaChanRU.pas | 1 - baseunits/modules/MangaFox.pas | 1 - baseunits/modules/MangaKoi.pas | 1 - baseunits/modules/MangaLife.pas | 1 - baseunits/modules/MangaReader.pas | 1 - baseunits/modules/MangaStreamTo.pas | 1 - baseunits/modules/MintMangaRU.pas | 1 - baseunits/modules/PecintaKomik.pas | 1 - baseunits/modules/RawSenManga.pas | 1 - baseunits/modules/Seemh.pas | 1 - baseunits/modules/Submanga.pas | 1 - baseunits/modules/Tsumino.pas | 1 - baseunits/modules/Tumangaonline.pas | 1 - baseunits/modules/UnionMangas.pas | 1 - baseunits/modules/WPManga.pas | 1 - baseunits/modules/Webtoons.pas | 1 - 27 files changed, 27 deletions(-) diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 617252625..6a5af6137 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -100,7 +100,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 7b311e0e0..23e0ae5a7 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -115,7 +115,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index d6143568b..b8506c999 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -104,7 +104,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; s:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); s:=AppendURLDelim(FillHost(Module.RootURL,s))+'?chapter_view=fullstrip'; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 72b4ad26c..4599a5050 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -107,7 +107,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; Cookies.Values['ReadType']:='2'; if GET(FillHost(Module.RootURL,AURL)) then begin diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 2d4205e4f..4b83a6a4f 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -132,7 +132,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index 5e3756052..2ab206533 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -104,7 +104,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index e3c10074d..6969a05bb 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -104,7 +104,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 4acaa6a81..562172fe0 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -123,7 +123,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GETWithCookie(DownloadThread.FHTTP,FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 5c0816cc0..9a833c43a 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -142,7 +142,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Container := DownloadThread.manager.container; with Container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 0e4450a8e..a872d9288 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -175,7 +175,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin Result := True; diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index c43709e82..758afce3f 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -110,7 +110,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 1cd05fec7..7c74bb43c 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -109,7 +109,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index d37b16cd1..c664d5e68 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -82,7 +82,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; s := ChapterLinks[CurrentDownloadChapterPtr]; if RightStr(s, 6) = '1.html' then begin diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index e715bdc3b..4fc9f62c7 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -115,7 +115,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 2454d048d..3bcf425a0 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -120,7 +120,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Container := DownloadThread.manager.container; with Container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; Source := TStringList.Create; try diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 9b9e54048..a1c3fde51 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -138,7 +138,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; Source := TStringList.Create; try diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index 67f6d9810..3a366722b 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -72,7 +72,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index 5c83690da..32d043fb9 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -114,7 +114,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; s:=AURL; if Pos('mature=1',LowerCase(s))=0 then s+='?mature=1'; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 241dc1ec1..88bcc5ac8 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -83,7 +83,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 26fbdab63..3d773d6ee 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -130,7 +130,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Free; end; PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,s+'/1')) then begin Result:=True; diff --git a/baseunits/modules/Seemh.pas b/baseunits/modules/Seemh.pas index d786f6ee0..547863def 100644 --- a/baseunits/modules/Seemh.pas +++ b/baseunits/modules/Seemh.pas @@ -102,7 +102,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 7a772e2eb..3784555be 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -105,7 +105,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index 266e03eb3..ace648b91 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -93,7 +93,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index d6a0493c3..fdd279c75 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -124,7 +124,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; s := ''; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 37d68ed7c..277cbf19d 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -114,7 +114,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 40622cdad..f1fa78df3 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -230,7 +230,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1') then begin Result := True; diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index eb818fc78..b675a9059 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -105,7 +105,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if DownloadThread=nil then Exit; with DownloadThread.FHTTP,DownloadThread.manager.container do begin PageLinks.Clear; - PageContainerLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin Result:=True; From 1978e951c378117685fe8ec0ec06bef134a29de1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 20:35:17 +0800 Subject: [PATCH 1039/2794] 8muses, get image url from thumbnails, cleanup --- baseunits/modules/EightMuses.pas | 147 ++++++++++++++----------------- 1 file changed, 64 insertions(+), 83 deletions(-) diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index d9abc3a93..d239d3126 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -10,121 +10,102 @@ interface implementation -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; - info: TMangaInfo; v: IXQValue; s: String; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - Source := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try - with info do begin - coverLink := Query.XPathString('//div[@class="holder"]/a/img/@src'); - if Pos('//', coverLink) = 1 then coverLink := 'https:' + coverLink; - if title = '' then - title := Query.XPathString('//ul[@class="breadcrumbs"]/li[last()]'); - //multi - if Query.XPathString('//div[@class="holder"]/a') <> '' then begin - for v in Query.XPath('//div[@class="holder"]/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - s := v.toString; - if (title <> '') and (Pos('Issue', s) = 1) then s := title + ' ' + s; - chapterName.Add(s); - end; - end - else begin - chapterLinks.Add(info.url); - chapterName.Add(title); + coverLink := XPathString('//div[@class="holder"]/a/img/@src'); + if Pos('//', coverLink) = 1 then coverLink := 'https:' + coverLink; + if title = '' then + title := XPathString('//ul[@class="breadcrumbs"]/li[last()]'); + //multi + if XPathString('//div[@class="holder"]/a') <> '' then begin + for v in XPath('//div[@class="holder"]/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + s := v.toString; + if (title <> '') and (Pos('Issue', s) = 1) then s := title + ' ' + s; + chapterName.Add(s); end; + end + else begin + chapterLinks.Add(url); + chapterName.Add(title); end; finally - Query.Free; + Free; end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + end; end; end; -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; v: IXQValue; + s: String; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; - with Container do begin - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), - RemoveURLDelim(FillHost(Module.RootURL, AURL)), Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - for v in Query.XPath('//div[@class="holder"]/a/@href') do begin + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageContainerLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@class="holder"]/a/img/@src') do + begin + s := v.toString; + if LeftStr(s, 2) = '//' then + s := 'https:' + s; + s := StringReplace(s, '/th/', '/fu/', [rfIgnoreCase]); + PageLinks.Add(s); + end; + if PageLinks.Count = 0 then + begin + for v in XPath('//div[@class="holder"]/a/@href') do PageContainerLinks.Add(v.toString); - Inc(PageNumber); - end; - finally - Query.Free; + PageNumber := PageContainerLinks.Count; end; + finally + Free; end; - finally - Source.Free; end; end; end; -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; rurl: String; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin - Source := TStringList.Create; - try - rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkCounter])); - if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - rurl := Query.XPathString('//img[@id="image"]/@src'); - if Pos('//', rurl) = 1 then rurl := 'https:' + rurl; - PageLinks[DownloadThread.workCounter] := rurl; - finally - Query.Free; - end; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkCounter])); + if GET(rurl) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + rurl := XPathString('//img[@id="image"]/@src'); + if Pos('//', rurl) = 1 then + rurl := 'https:' + rurl; + PageLinks[DownloadThread.workCounter] := rurl; + finally + Free; end; - finally - Source.Free; end; end; end; From e2c3a46a48417bc0eef2b963247e3a95462fcbc1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 20:48:50 +0800 Subject: [PATCH 1040/2794] downloadmanager, downloadimage, added lname --- baseunits/uDownloadsManager.pas | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c9b150ee0..f31fa8f21 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1061,7 +1061,7 @@ procedure TTaskThread.SyncShowBaloon; function TDownloadThread.DownloadImage: Boolean; var - s, TURL, lpath, sfilename: String; + s, TURL, lpath, lname, sfilename: String; {$I includes/MeinManga/image_url.inc} @@ -1090,6 +1090,8 @@ function TDownloadThread.DownloadImage: Boolean; if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); + lname := Format('%.3d', [workCounter + 1]); + if Result then begin if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin s := ''; @@ -1102,7 +1104,7 @@ function TDownloadThread.DownloadImage: Boolean; Self, s, lpath, - Format('%.3d', [workCounter + 1]), + lname, ModuleId); end else @@ -1114,7 +1116,7 @@ function TDownloadThread.DownloadImage: Boolean; manager.container.MangaSiteID, TURL, lpath, - Format('%.3d', [workCounter + 1]), + lname, sfilename, manager.container.Manager.retryConnect); end; From 78be9061b7b3614b2c9cbc2ebdde92ffb7c3c07a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 21:13:21 +0800 Subject: [PATCH 1041/2794] ehentai, use available filename closed #212 --- baseunits/modules/EHentai.pas | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index c06fc337c..792e07e85 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML; + accountmanagerdb, XQueryEngineHTML, synautil, LazFileUtils; implementation @@ -250,7 +250,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if getOK then begin GetImageLink; //get page count - p:=0; p:=StrToIntDef(query.XPathString('//table[@class="ptt"]//td[last()-1]'),0); if p>1 then begin Dec(p); @@ -276,13 +275,20 @@ function DownloadImage(const DownloadThread: TDownloadThread; function DoDownloadImage: Boolean; var i, rcount: Integer; - base_url, startkey, gid, startpage, nl: String; + iname, base_url, startkey, gid, startpage, nl: String; source: TStringList; begin rcount := 0; Result := False; source := TStringList.Create; try + iname := query.XPathString('//div[@id="i2"]/div[2]'); + if iname <> '' then begin + iname := Trim(SeparateLeft(iname, '::')); + iname := ExtractFileNameOnly(iname); + end; + if iname = '' then + iname := AName; while (not Result) and (not DownloadThread.IsTerminated) do begin source.LoadFromStream(DownloadThread.FHTTP.Document); query.ParseHTML(DownloadThread.FHTTP.Document); @@ -294,7 +300,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, -1, iurl, APath, AName); + Result := SaveImage(DownloadThread.FHTTP, iurl, APath, iname); if DownloadThread.IsTerminated then Break; if rcount >= reconnect then Break; if not Result then begin @@ -341,9 +347,8 @@ function DownloadImage(const DownloadThread: TDownloadThread; reconnect := DownloadThread.FHTTP.RetryCount; iurl := FillHost(Module.RootURL, AURL); if GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then begin - query := TXQueryEngineHTML.Create; + query := TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document); try - query.ParseHTML(StreamToString(DownloadThread.FHTTP.Document)); Result := DoDownloadImage; finally query.Free; From cd06cd06a65b843a468827365fe01aa9ab190cc0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 22:22:03 +0800 Subject: [PATCH 1042/2794] downloadmanager, fixed auto start download often failed when max connection limit = 1 --- baseunits/uDownloadsManager.pas | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index f31fa8f21..65725e0a6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1170,15 +1170,15 @@ procedure TTaskThread.CheckOut; container.CurrentPageNumber := InterLockedIncrement(container.CurrentPageNumber); Exit; end; - - if Modules.MaxConnectionLimit[ModuleId] > 0 then - while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do - Sleep(SOCKHEARTBEATRATE) - else - while (not Terminated) and (threads.Count >= currentMaxThread) do - Sleep(SOCKHEARTBEATRATE); end; + if Modules.MaxConnectionLimit[ModuleId] > 0 then + while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do + Sleep(SOCKHEARTBEATRATE) + else + while (not Terminated) and (threads.Count >= currentMaxThread) do + Sleep(SOCKHEARTBEATRATE); + if (not Terminated) and (threads.Count < currentMaxThread) then begin LockCreateConnection; @@ -1238,8 +1238,15 @@ procedure TTaskThread.Execute; if Trim(container.PageLinks[i]) <> 'D' then Inc(c); end; - if c > 0 then + if c > 0 then begin + WriteLog_W(Format('%s, checkforfinish failed=%d/%d "%s" > "%s"', + [Self.ClassName, + c, + container.PageLinks.Count, + container.DownloadInfo.Title, + container.ChapterName[container.CurrentDownloadChapterPtr]])); Result := False; + end; end; procedure WaitForThreads; @@ -1412,8 +1419,14 @@ procedure TTaskThread.Execute; else container.Status := STATUS_FAILED; end - else + else begin + WriteLog_W(Format('%s, failed download image PageLinks=%d "%s" > "%s"', + [Self.ClassName, + container.PageLinks.Count, + container.DownloadInfo.Title, + container.ChapterName[container.CurrentDownloadChapterPtr]])); container.Status := STATUS_FAILED; + end; if (container.Status = STATUS_FAILED) and (not FindStrLinear(container.FailedChapterLinks, From e3390e786b97e85b51703ee9a54f8f927795f629 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 22:30:47 +0800 Subject: [PATCH 1043/2794] downloadmanager, fixed feed pagecontainerlinks when pagecontainerlinks=pagenumber only --- baseunits/uDownloadsManager.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 65725e0a6..a945f4350 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1095,10 +1095,12 @@ function TDownloadThread.DownloadImage: Boolean; if Result then begin if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin s := ''; - if workCounter < manager.container.PageContainerLinks.Count then + if (manager.container.PageNumber = manager.container.PageContainerLinks.Count) + and (workCounter < manager.container.PageContainerLinks.Count) then s := manager.container.PageContainerLinks[workCounter] else if workCounter < manager.container.PageLinks.Count then s := manager.container.PageLinks[workCounter]; + if s <> '' then Result := Modules.DownloadImage( Self, From a204a1a685e3f655857e774f905fa5b22f386f65 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 22:56:59 +0800 Subject: [PATCH 1044/2794] downloadmanager, added container.filenames to store filename --- baseunits/uDownloadsManager.pas | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a945f4350..320fb8f38 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -136,6 +136,7 @@ TTaskContainer = class FailedChapterLinks, PageContainerLinks, PageLinks: TStringList; + Filenames: TStringList; constructor Create; destructor Destroy; override; procedure IncReadCount(const ACount: Integer); @@ -1090,7 +1091,11 @@ function TDownloadThread.DownloadImage: Boolean; if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); - lname := Format('%.3d', [workCounter + 1]); + lname := ''; + if workCounter < manager.container.Filenames.Count then + lname := manager.container.Filenames[workCounter]; + if lname = '' then + lname := Format('%.3d', [workCounter + 1]); if Result then begin if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin @@ -1545,6 +1550,7 @@ constructor TTaskContainer.Create; FailedChapterLinks := TStringList.Create; PageLinks := TStringList.Create; PageContainerLinks := TStringList.Create; + Filenames := TStringList.Create; FReadCount := 0; WorkCounter := 0; CurrentPageNumber := 0; @@ -1553,6 +1559,7 @@ constructor TTaskContainer.Create; destructor TTaskContainer.Destroy; begin + Filenames.Free; PageContainerLinks.Free; PageLinks.Free; ChapterName.Free; @@ -1725,7 +1732,9 @@ procedure TDownloadManager.Restore; s := ReadString(tid, 'PageLinks', ''); if s <> '' then GetParams(PageLinks, s); s := ReadString(tid, 'PageContainerLinks', ''); - if s <> '' then GetParams(PageContainerLinks, s); //deprecated, for old config + if s <> '' then GetParams(PageContainerLinks, s); + s := ReadString(tid, 'Filenames', ''); + if s <> '' then GetParams(Filenames, s); j := ReadInteger(tid, 'TaskStatus', -1); if j >= 0 then Status := TDownloadStatusType(j) @@ -1808,6 +1817,8 @@ procedure TDownloadManager.Backup; WriteString(tid, 'PageLinks', SetParams(PageLinks)); if PageContainerLinks.Count > 0 then WriteString(tid, 'PageContainerLinks', SetParams(PageContainerLinks)); + if Filenames.Count > 0 then + WriteString(tid, 'Filenames', SetParams(Filenames)); WriteString(tid, 'TaskStatus', GetEnumName(TypeInfo(TDownloadStatusType), integer(Status))); WriteInteger(tid, 'ChapterPtr', CurrentDownloadChapterPtr); WriteInteger(tid, 'NumberOfPages', PageNumber); From fb7d5b6a2374eea526a38d59003386afeeb8a1e8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 22:57:16 +0800 Subject: [PATCH 1045/2794] ehentai, store filename to container.filenames --- baseunits/modules/EHentai.pas | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 792e07e85..4db6feeed 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -220,11 +220,17 @@ function GetPageNumber(const DownloadThread: TDownloadThread; procedure GetImageLink; var x: IXQValue; + s: String; begin - query.ParseHTML(DownloadThread.FHTTP.Document); - with DownloadThread.manager.container do begin - for x in query.XPath('//div[@id="gdt"]//a/@href') do - PageContainerLinks.Add(x.toString); + with DownloadThread.manager.container, query do begin + ParseHTML(DownloadThread.FHTTP.Document); + for x in XPath('//div[@id="gdt"]//a') do + begin + PageContainerLinks.Add(x.toNode.getAttribute('href')); + s := Trim(SeparateRight(XPathString('img/@title', x.toNode), ':')); + if s <> '' then + Filenames.Add(ExtractFileNameOnly(s)); + end; while PageLinks.Count<PageContainerLinks.Count do PageLinks.Add('G'); end; @@ -236,6 +242,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageContainerLinks.Clear; + Filenames.Clear; PageNumber := 0; rurl:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); rurl:=AppendURLDelim(FillHost(Module.RootURL,rurl)); @@ -275,20 +282,13 @@ function DownloadImage(const DownloadThread: TDownloadThread; function DoDownloadImage: Boolean; var i, rcount: Integer; - iname, base_url, startkey, gid, startpage, nl: String; + base_url, startkey, gid, startpage, nl: String; source: TStringList; begin rcount := 0; Result := False; source := TStringList.Create; try - iname := query.XPathString('//div[@id="i2"]/div[2]'); - if iname <> '' then begin - iname := Trim(SeparateLeft(iname, '::')); - iname := ExtractFileNameOnly(iname); - end; - if iname = '' then - iname := AName; while (not Result) and (not DownloadThread.IsTerminated) do begin source.LoadFromStream(DownloadThread.FHTTP.Document); query.ParseHTML(DownloadThread.FHTTP.Document); @@ -300,7 +300,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, iurl, APath, iname); + Result := SaveImage(DownloadThread.FHTTP, iurl, APath, AName); if DownloadThread.IsTerminated then Break; if rcount >= reconnect then Break; if not Result then begin From f57a5a749b55cd01e7465d97ce93dd657bb71765 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 23:01:06 +0800 Subject: [PATCH 1046/2794] ehentai, store filename even if its empty --- baseunits/modules/EHentai.pas | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 4db6feeed..decbd5bba 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -220,16 +220,14 @@ function GetPageNumber(const DownloadThread: TDownloadThread; procedure GetImageLink; var x: IXQValue; - s: String; begin with DownloadThread.manager.container, query do begin ParseHTML(DownloadThread.FHTTP.Document); for x in XPath('//div[@id="gdt"]//a') do begin PageContainerLinks.Add(x.toNode.getAttribute('href')); - s := Trim(SeparateRight(XPathString('img/@title', x.toNode), ':')); - if s <> '' then - Filenames.Add(ExtractFileNameOnly(s)); + Filenames.Add(ExtractFileNameOnly(Trim(SeparateRight( + XPathString('img/@title', x.toNode), ':')))); end; while PageLinks.Count<PageContainerLinks.Count do PageLinks.Add('G'); From 83150b38b5333df8617684f54afda7c7be35c031 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Mar 2016 23:28:34 +0800 Subject: [PATCH 1047/2794] Bump version 0.9.43.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 74dbda97b..d722208a3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.43.0 (23-03-2016) +[*] Fixed download sometimes failed when max connection limit = 1 +[*] 8Muses: faster get image url +[*] E-Hentai/ExHentai: use original filename if available +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.42.0...0.9.43.0 + 0.9.42.0 (22-03-2016) [+] Added option to hide downloaded chapter. chapter list > right click > hide downloaded chapter [*] Fixed various form layout diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1518a110e..a17728d2b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="42"/> + <RevisionNr Value="43"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 6f79e3f55..9d78c4f8f 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.42.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.42.0/fmd_0.9.42.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.42.0/fmd_0.9.42.0_Win64.7z +VERSION=0.9.43.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.43.0/fmd_0.9.43.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.43.0/fmd_0.9.43.0_Win64.7z From 72d1afe3fd92a93a3067b1f5a5faf13f7222b88d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 13:54:42 +0800 Subject: [PATCH 1048/2794] mangafox, trim last 1.html on chapterlinks fixed #216 --- baseunits/modules/MangaFox.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index c664d5e68..5138473ce 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -36,6 +36,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -59,7 +60,10 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; summary := XPathString('//p[@class="summary"]'); for v in XPath('//ul[@class="chlist"]/li') do begin - chapterLinks.Add(XPathString('div/*/a[@class="tips"]/@href', v.toNode)); + s := XPathString('div/*/a[@class="tips"]/@href', v.toNode); + if RightStr(s, 6) = '1.html' then + SetLength(s, Length(s) - 6); + chapterLinks.Add(s); chapterName.Add(Trim(XPathString('div/*/a[@class="tips"]', v.toNode) + ' ' + XPathString('div/*/span[@class="title nowrap"]', v.toNode))); end; From 014e48ef46096b103b953405b5d9c78da67fbcca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 14:06:00 +0800 Subject: [PATCH 1049/2794] update indonesian translations --- mangadownloader/languages/fmd.id_ID.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index edf52f2e1..6a70b1fd6 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -437,7 +437,7 @@ msgstr "Terapkan" #: tmainform.btreadonline.caption msgid "Read online" -msgstr "Baca online" +msgstr "Baca daring" #: tmainform.btremovefilterlarge.caption msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" From 2a7454fb94ad4db350400f631ac2e2e6b94b620e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 14:27:47 +0800 Subject: [PATCH 1050/2794] baseunit, move maybefillhost lines after fillhost --- baseunits/uBaseUnit.pas | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f6307fd90..a5ef88287 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -785,10 +785,10 @@ function FillURLProtocol(const AProtocol, AURL: String): String; function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; function FillMangaSiteHost(const Website, URL: String): String; overload; function FillHost(const Host, URL: String): String; +function MaybeFillHost(const Host, URL: String): String; // modify url function GetHostURL(URL: String): String; -function MaybeFillHost(const Host, URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(Const URLs: TStringList); procedure RemoveHostFromURLsPair(Const URLs, Names : TStringList); @@ -1387,13 +1387,6 @@ function FillHost(const Host, URL: String): String; end; end; -function GetHostURL(URL: String): String; -begin - Result:=URL; - if URL='' then Exit; - Result:=ReplaceRegExpr(REGEX_HOST,Result,'$1$2',True); -end; - function MaybeFillHost(const Host, URL: String): String; var tu: string; @@ -1416,6 +1409,13 @@ function MaybeFillHost(const Host, URL: String): String; end; end; +function GetHostURL(URL: String): String; +begin + Result:=URL; + if URL='' then Exit; + Result:=ReplaceRegExpr(REGEX_HOST,Result,'$1$2',True); +end; + function RemoveHostFromURL(URL : String) : String; begin Result := ReplaceRegExpr(REGEX_HOST, URL, '$4', True); From ca95a61b3c9aad758b34c6cbf34397c1d0dc769e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 14:53:17 +0800 Subject: [PATCH 1051/2794] baseunit, fixed cleanurl --- baseunits/uBaseUnit.pas | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a5ef88287..fdc45ebc2 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2430,23 +2430,28 @@ function CleanAndExpandURL(const URL: String): String; function CleanURL(const URL: String): String; var - host, link: String; + x: Integer; + p: String; begin Result := URL; - with TRegExpr.Create do - try - Expression := REGEX_HOST; - host := Replace(URL, '$1$2$3', True); - link := Replace(URL, '$4', True); - if link <> '' then - begin - while Pos('//', link) <> 0 do - link := StringReplace(link, '//', '/', [rfReplaceAll]); - Result := host + URL; - end; - finally - Free; + if Result = '' then Exit; + if Pos(':', Result) = 1 then + Delete(Result, 1, 1); + if Pos('//', Result) = 1 then + Delete(Result, 1, 2); + p := ''; + x := Pos('://', Result); + if x > 0 then + begin + x := x + 2; + p := Copy(Result, 1, x); + Delete(Result, 1, x); + while Pos('/', Result) = 1 do + Delete(Result, 1, 1); end; + while Pos('//', Result) > 0 do + Result := StringReplace(Result, '//', '/', [rfReplaceAll]); + Result := p + Result; end; function AppendURLDelim(const URL: String): String; From 5f3fb62e6335693efa5e476848d514432c2cf395 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 14:57:40 +0800 Subject: [PATCH 1052/2794] baseunit, fixed fillhost, cleanurl first --- baseunits/uBaseUnit.pas | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fdc45ebc2..20c1bfa1b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1373,15 +1373,14 @@ function FillHost(const Host, URL: String): String; var tu: string; begin - Result := URL; + Result := CleanURL(URL); if Host = '' then Exit; with TRegExpr.Create do try Expression := REGEX_HOST; - tu := Replace(URL, '$4', True); - if tu = '' then - tu := URL; - Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); + tu := Replace(Result, '$4', True); + if tu <> '' then + Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); finally Free; end; From e0995799d657fb7e563a3eec0e47b981b6ae3f72 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 15:00:42 +0800 Subject: [PATCH 1053/2794] baseunit, fixed maybefillhost, cleanurl first --- baseunits/uBaseUnit.pas | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 20c1bfa1b..3824e2071 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1390,18 +1390,17 @@ function MaybeFillHost(const Host, URL: String): String; var tu: string; begin - Result := URL; + Result := CleanURL(URL); if Host = '' then Exit; if URL = '' then Exit; with TRegExpr.Create do try Expression := REGEX_HOST; - if Replace(URL, '$2', True) = '' then + if Replace(Result, '$2', True) = '' then begin - tu := Replace(URL, '$4', True); - if tu = '' then - tu := URL; - Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); + tu := Replace(Result, '$4', True); + if tu <> '' then + Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); end; finally Free; From 18079738bc7fa3ae483767855e98751e9c27571b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 15:06:57 +0800 Subject: [PATCH 1054/2794] getinfo, coverlink always cleanurl --- baseunits/uData.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d9df083cd..734e684f7 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1680,6 +1680,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if mangaInfo.link = '' then mangaInfo.link := RemoveHostFromURL(mangaInfo.url); // cleanup info + coverLink := CleanURL(coverLink); title := Trim(RemoveStringBreaks(CommonStringFilter(title))); authors := Trim(RemoveStringBreaks(Trim(authors))); artists := Trim(RemoveStringBreaks(Trim(artists))); From 938b9e8e102cc8a3581e175d8f66b43ca9e8de58 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 15:07:46 +0800 Subject: [PATCH 1055/2794] baseunit, cleanurl do trim --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3824e2071..f4f48f06c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2431,7 +2431,7 @@ function CleanURL(const URL: String): String; x: Integer; p: String; begin - Result := URL; + Result := Trim(URL); if Result = '' then Exit; if Pos(':', Result) = 1 then Delete(Result, 1, 1); From 097a1473d97d9c6a3810ce3d07fb1159be9d8a79 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 15:23:59 +0800 Subject: [PATCH 1056/2794] wpmanga, fix manga info --- baseunits/modules/WPManga.pas | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index f1fa78df3..b5a06ddd7 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -19,8 +19,8 @@ implementation dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; dirURLmangahen = '/manga_list/all/any/last-added/'; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; @@ -48,9 +48,8 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; end; end; -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -98,8 +97,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; end; end; -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; v: IXQValue; @@ -134,9 +133,11 @@ function GetInfo(const MangaInfo: TMangaInformation; function getwpmangavalue(aname: String): String; begin - Result := query.XPathString('(//*[@class="mng_ifo"]//p)[contains(.,"' + + Result := query.XPathString('(//*[@class="mng_ifo"]//p)[starts-with(.,"' + aname + '")]'); - if Result <> '' then Result := TrimChar(SeparateRight(Result, aname), [':', ' ']); + if Result <> '' then Result := Trim(TrimChar(SeparateRight(Result, aname), [':', ' '])); + if Result = '-' then + Result := ''; end; procedure scaninfo; @@ -192,6 +193,7 @@ function GetInfo(const MangaInfo: TMangaInformation; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); coverLink := query.XPathString('//img[starts-with(@class,"cvr")]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); title := query.XPathString('//*[@itemprop="itemreviewed"]'); if Module.Website = 'MangaIndo' then scaninfomangaindo else scaninfo; @@ -221,8 +223,8 @@ function GetInfo(const MangaInfo: TMangaInformation; end; end; -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; begin @@ -244,8 +246,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; s: String; @@ -253,7 +255,8 @@ function GetImageURL(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then begin + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then + begin Result := True; query := TXQueryEngineHTML.Create; try From fc1e994331ddc38e298da54803af92663eb688a9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 16:08:40 +0800 Subject: [PATCH 1057/2794] wpmanga, fixed getpagenumber, getimageurl, faster get image url --- baseunits/modules/WPManga.pas | 61 ++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index b5a06ddd7..57e853f8a 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -226,22 +226,45 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; + s: String; + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; + Cookies.Values['viewer'] := '1'; if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1') then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber := query.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; - finally - query.Free; + //multi page + s := StreamToString(Document); + if Pos('var imglist = ', s) > 0 then + begin + s := GetBetween('var imglist = ', '];', s); + if s <> '' then + begin + s := s + ']'; + s := RemoveBreaks(s); + with TXQueryEngineHTML.Create(s) do + try + for v in XPath('json(*)()("url")') do + PageLinks.Add(v.toString); + finally + Free; + end; + end; end; + //single page + if PageLinks.Count = 0 then + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; + if PageNumber = 0 then + PageNumber := XPath('(//select[@name="page"])[1]/option').Count; + finally + Free; + end; end; end; end; @@ -249,7 +272,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; s: String; begin Result := False; @@ -258,17 +280,18 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - if Module.Website = 'ReadHentaiManga' then - s := HTMLDecode(query.XPathString('//img[@id="main_img"]/@src')) - else - s := query.XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); - PageLinks[DownloadThread.WorkCounter] := s; - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + if Module.Website = 'ReadHentaiManga' then + s := HTMLDecode(XPathString('//img[@id="main_img"]/@src')) + else + s := XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); + if s = '' then + s := XPathString('//*[@id="reader"]//img[@id="picture"]/@src'); + PageLinks[DownloadThread.WorkCounter] := s; + finally + Free; + end; end; end; end; From c8738422896e471a6cf940b1d64081b140f32429 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 16:39:16 +0800 Subject: [PATCH 1058/2794] remove senmanga old code --- .../includes/SenManga/chapter_page_number.inc | 43 ------ .../SenManga/directory_page_number.inc | 35 ----- baseunits/includes/SenManga/image_url.inc | 38 ----- .../includes/SenManga/manga_information.inc | 132 ------------------ .../includes/SenManga/names_and_links.inc | 35 ----- baseunits/uBaseUnit.pas | 127 +++++++---------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- 8 files changed, 54 insertions(+), 381 deletions(-) delete mode 100644 baseunits/includes/SenManga/chapter_page_number.inc delete mode 100644 baseunits/includes/SenManga/directory_page_number.inc delete mode 100644 baseunits/includes/SenManga/image_url.inc delete mode 100644 baseunits/includes/SenManga/manga_information.inc delete mode 100644 baseunits/includes/SenManga/names_and_links.inc diff --git a/baseunits/includes/SenManga/chapter_page_number.inc b/baseunits/includes/SenManga/chapter_page_number.inc deleted file mode 100644 index 08fba26a7..000000000 --- a/baseunits/includes/SenManga/chapter_page_number.inc +++ /dev/null @@ -1,43 +0,0 @@ - function GetSenMangaPageNumber: Boolean; - var - s: String; - i: LongInt; - l: TStringList; - isStartGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(URL); - s := FillMangaSiteHost(SENMANGA_ID, s); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - if Result then - begin - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - manager.container.PageNumber := 0; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (Pos('cbo_wpm_pag', parse[i]) > 0) then - isStartGetPageNumber := True; - if isStartGetPageNumber then - begin - if GetTagName(parse[i]) = '/select' then - Break - else - if GetTagName(parse[i]) = 'option' then - Inc(manager.container.PageNumber); - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/SenManga/directory_page_number.inc b/baseunits/includes/SenManga/directory_page_number.inc deleted file mode 100644 index 85ccd6a25..000000000 --- a/baseunits/includes/SenManga/directory_page_number.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetSenMangaDirectoryPageNumber: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SENMANGA_ID, 1] + - '/directory/all/any/last-added/', 3) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - for i := parse.Count - 1 downto 0 do - if (GetTagName(parse[i]) = 'a') and - (Pos('/directory/all/any/last-added/', parse[i]) > 0) then - begin - Page := StrToIntDef(ReplaceRegExpr('^.*/last-added/(\d+)/?$', - GetVal(parse[i], 'href'), '$1', True), 1); - Result := NO_ERROR; - Break; - end; - end; diff --git a/baseunits/includes/SenManga/image_url.inc b/baseunits/includes/SenManga/image_url.inc deleted file mode 100644 index 0a2f3e557..000000000 --- a/baseunits/includes/SenManga/image_url.inc +++ /dev/null @@ -1,38 +0,0 @@ - function GetSenMangaImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - try - Result := GetPage(TObject(l), - FillMangaSiteHost(SENMANGA_ID, URL + '/' + IntToStr(workCounter + 1) + '/'), - manager.container.Manager.retryConnect); - if Result then - begin - parse := TStringList.Create; - try - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = 'img_mng_enl') then - begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); - Break; - end; - finally - parse.Free; - end; - end; - finally - l.Free; - end; - end; diff --git a/baseunits/includes/SenManga/manga_information.inc b/baseunits/includes/SenManga/manga_information.inc deleted file mode 100644 index 07b07c926..000000000 --- a/baseunits/includes/SenManga/manga_information.inc +++ /dev/null @@ -1,132 +0,0 @@ - function GetSenMangaInfoFromURL: Byte; - var - i, j, p: Integer; - - procedure GetChapters(const ln: Integer); - begin - if (GetTagName(parse[ln]) = 'a') and (GetVal(parse[ln], 'class') = 'lst') then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[ln], 'href')); - mangaInfo.chapterName.Add(parse[ln + 3]); - end; - end; - - begin - mangaInfo.website := WebsiteRoots[SENMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(SENMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.status := ''; - p := 0; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if (GetTagName(parse[i]) = 'h1') and (GetVal(parse[i], 'class') = 'ttl') then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - //cover - if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'class') = 'cvr') then - mangaInfo.coverLink := FixURL(GetVal(parse[i], 'src')); - //summary - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'det') then - mangaInfo.summary := parse[i + 3]; - - if (GetTagName(parse[i]) = 'b') then - begin - //author - if Trim(parse[i + 1]) = 'Author' then - mangaInfo.authors := parse[i + 5]; - //artist - if Trim(parse[i + 1]) = 'Artist' then - mangaInfo.artists := parse[i + 5]; - //status - if mangaInfo.status = '' then - if Trim(parse[i + 1]) = 'Status' then - begin - mangaInfo.status := Trim(parse[i + 5]); - if mangaInfo.status = 'Completed' then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end; - //genres - if Trim(parse[i + 1]) = 'Category' then - for j := i + 3 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/p' then - Break - else - if GetTagName(parse[j]) = 'a' then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[j + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[j + 1]); - end; - end; - end; - - //chapters - GetChapters(i); - - //chapterpage - if (GetTagName(parse[i]) = 'a') and (Pos('/chapter-list/', parse[i]) > 0) then - if Trim(parse[i + 1]) = 'Last' then - begin - j := StrToIntDef(ReplaceRegExpr( - '^.*/chapter-list/(\d+)/?$', GetVal(parse[i], 'href'), '$1', True), 0); - if j > p then p := j; - end; - end; - - //get the rest of chapters from another page - if p > 1 then - begin - for i := 2 to p do - begin - s := mangaInfo.url; - if s[Length(s)] <> '/' then s := s + '/'; - s := s + 'chapter-list/' + IntToStr(i) + '/'; - if GetPage(TObject(Source), s, Reconnect) then - begin - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - if parse.Count > 0 then - for j := 0 to parse.Count - 1 do - GetChapters(j); - end; - end; - end; - Source.Free; - - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end - else - Result := INFORMATION_NOT_FOUND; - end; diff --git a/baseunits/includes/SenManga/names_and_links.inc b/baseunits/includes/SenManga/names_and_links.inc deleted file mode 100644 index e9c8c7ba4..000000000 --- a/baseunits/includes/SenManga/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function SenMangaGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SENMANGA_ID, 1] + - '/directory/all/any/last-added/' + IntToStr(StrToInt(URL) + 1) + '/', 3) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'lst mng_det_pop') then - begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter(GetVal(parse[i], 'title'))); - end; - Result := NO_ERROR; - end; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f4f48f06c..8bb735efb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -289,59 +289,58 @@ interface ANIMEEXTREMIST_ID = 20; HUGEMANGA_ID = 21; S2SCAN_ID = 22; - SENMANGA_ID = 23; - IMANHUA_ID = 24; - MABUNS_ID = 25; - MANGAESTA_ID = 26; - CENTRALDEMANGAS_ID = 27; - EGSCANS_ID = 28; - MANGAAR_ID = 29; - MANGAAE_ID = 30; - ANIMESTORY_ID = 31; - LECTUREENLIGNE_ID = 32; - SCANMANGA_ID = 33; - MANGAGO_ID = 34; - DM5_ID = 35; - MANGACOW_ID = 36; - KIVMANGA_ID = 37; - MEINMANGA_ID = 38; - MANGASPROJECT_ID = 39; - MANGAREADER_POR_ID = 40; - NINEMANGA_ID = 41; - NINEMANGA_ES_ID = 42; - NINEMANGA_CN_ID = 43; - NINEMANGA_RU_ID = 44; - NINEMANGA_DE_ID = 45; - NINEMANGA_IT_ID = 46; - NINEMANGA_BR_ID = 47; - JAPANSHIN_ID = 48; - JAPSCAN_ID = 49; - CENTRUMMANGI_PL_ID = 50; - MANGALIB_PL_ID = 51; - ONEMANGA_ID = 52; - MANGATOWN_ID = 53; - MANGAOKU_ID = 54; - MYREADINGMANGAINFO_ID = 55; - IKOMIK_ID = 56; - NHENTAI_ID = 57; - MANGAMINT_ID = 58; - UNIXMANGA_ID = 59; - EXTREMEMANGAS_ID = 60; - MANGAHOST_ID = 61; - PORNCOMIX_ID = 62; - PORNCOMIXRE_ID = 63; - PORNCOMIXIC_ID = 64; - XXCOMICS_ID = 65; - XXCOMICSMT_ID = 66; - XXCOMICS3D_ID = 67; - PORNXXXCOMICS_ID = 68; - MANGASEE_ID = 69; - MANGAKU_ID = 70; - MANGAAT_ID = 71; - READMANGATODAY_ID = 72; - DYNASTYSCANS_ID = 73; - - WebsiteRoots: array [0..73] of array [0..1] of string = ( + IMANHUA_ID = 23; + MABUNS_ID = 24; + MANGAESTA_ID = 25; + CENTRALDEMANGAS_ID = 26; + EGSCANS_ID = 27; + MANGAAR_ID = 28; + MANGAAE_ID = 29; + ANIMESTORY_ID = 30; + LECTUREENLIGNE_ID = 31; + SCANMANGA_ID = 32; + MANGAGO_ID = 33; + DM5_ID = 34; + MANGACOW_ID = 35; + KIVMANGA_ID = 36; + MEINMANGA_ID = 37; + MANGASPROJECT_ID = 38; + MANGAREADER_POR_ID = 39; + NINEMANGA_ID = 40; + NINEMANGA_ES_ID = 41; + NINEMANGA_CN_ID = 42; + NINEMANGA_RU_ID = 43; + NINEMANGA_DE_ID = 44; + NINEMANGA_IT_ID = 45; + NINEMANGA_BR_ID = 46; + JAPANSHIN_ID = 47; + JAPSCAN_ID = 48; + CENTRUMMANGI_PL_ID = 49; + MANGALIB_PL_ID = 50; + ONEMANGA_ID = 51; + MANGATOWN_ID = 52; + MANGAOKU_ID = 53; + MYREADINGMANGAINFO_ID = 54; + IKOMIK_ID = 55; + NHENTAI_ID = 56; + MANGAMINT_ID = 57; + UNIXMANGA_ID = 58; + EXTREMEMANGAS_ID = 59; + MANGAHOST_ID = 60; + PORNCOMIX_ID = 61; + PORNCOMIXRE_ID = 62; + PORNCOMIXIC_ID = 63; + XXCOMICS_ID = 64; + XXCOMICSMT_ID = 65; + XXCOMICS3D_ID = 66; + PORNXXXCOMICS_ID = 67; + MANGASEE_ID = 68; + MANGAKU_ID = 69; + MANGAAT_ID = 70; + READMANGATODAY_ID = 71; + DYNASTYSCANS_ID = 72; + + WebsiteRoots: array [0..72] of array [0..1] of string = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -365,7 +364,6 @@ interface ('AnimExtremist', 'http://www.animextremist.com'), ('HugeManga', 'http://hugemanga.com'), ('S2Scans', 'http://reader.s2smanga.com'), - ('SenManga', 'http://www.senmanga.com'), ('imanhua', 'http://www.imanhua.com'), ('Mabuns', 'http://www.mabuns.web.id'), ('MangaEsta', 'http://www.mangaesta.net'), @@ -470,8 +468,6 @@ interface HUGEMANGA_BROWSER = '/'; - SENMANGA_BROWSER = '/Manga/'; - IMANHUA_BROWSER = '/all.html'; MABUNS_BROWSER = '/p/mabuns-manga-list.html'; @@ -775,7 +771,6 @@ function SitesWithoutFavorites(const website:String): Boolean; // Return true if the website doesn't contain manga information function SitesWithoutInformation(const website: String): Boolean; function SitesWithoutReferer(const website: String): Boolean; -function SitesRefererisURL(const website: String): Boolean; function SitesWithSingleChapter(const website: String): Boolean; // url @@ -1256,8 +1251,7 @@ function SitesWithSortedList(const website : String) : Boolean; PORNCOMIXRE_ID, PORNCOMIXIC_ID, PORNXXXCOMICS_ID, - MANGAPARK_ID, - SENMANGA_ID + MANGAPARK_ID ]); end; @@ -1322,14 +1316,6 @@ function SitesWithoutReferer(const website : String) : Boolean; ]); end; -function SitesRefererisURL(const website : String) : Boolean; -begin - Result := False; - Result := SitesMemberOf(website, [ - SENMANGA_ID - ]); -end; - function SitesWithSingleChapter(const website : String) : Boolean; begin Result := False; @@ -3365,12 +3351,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; begin if HTTPHeader.Values['Referer'] = '' then if not (SitesWithoutReferer(WebsiteRoots[mangaSiteID, 0])) then - begin - if SitesRefererisURL(WebsiteRoots[mangaSiteID, 0]) then - HTTPHeader.Values['Referer'] := ' ' + URL - else - HTTPHeader.Values['Referer'] := ' ' + WebsiteRoots[mangaSiteID, 1]; - end; + HTTPHeader.Values['Referer'] := ' ' + WebsiteRoots[mangaSiteID, 1]; end; HTTP.Document.Clear; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 734e684f7..b3dbe5f66 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -800,8 +800,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; //{$I includes/MangaTraders/directory_page_number.inc} - {$I includes/SenManga/directory_page_number.inc} - {$I includes/MangaGo/directory_page_number.inc} {$I includes/MangaEden/directory_page_number.inc} @@ -908,9 +906,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; if WebsiteID = S2SCAN_ID then Result := GetS2ScanDirectoryPageNumber else - if WebsiteID = SENMANGA_ID then - Result := GetSenMangaDirectoryPageNumber - else if WebsiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLigneDirectoryPageNumber else @@ -1052,8 +1047,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Mangacow/names_and_links.inc} - {$I includes/SenManga/names_and_links.inc} - {$I includes/Starkana/names_and_links.inc} {$I includes/EatManga/names_and_links.inc} @@ -1232,9 +1225,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = MANGACOW_ID then Result := MangaCowGetNamesAndLinks else - if WebsiteID = SENMANGA_ID then - Result := SenMangaGetNamesAndLinks - else if WebsiteID = KIVMANGA_ID then Result := KivmangaGetNamesAndLinks else @@ -1403,8 +1393,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; {$I includes/Mangacow/manga_information.inc} - {$I includes/SenManga/manga_information.inc} - {$I includes/BlogTruyen/manga_information.inc} {$I includes/MeinManga/manga_information.inc} @@ -1579,9 +1567,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if WebsiteID = MANGACOW_ID then Result := GetMangaCowInfoFromURL else - if WebsiteID = SENMANGA_ID then - Result := GetSenMangaInfoFromURL - else if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 320fb8f38..641d1a97c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -416,8 +416,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/S2Scans/chapter_page_number.inc} - {$I includes/SenManga/chapter_page_number.inc} - {$I includes/Starkana/chapter_page_number.inc} {$I includes/Turkcraft/chapter_page_number.inc} @@ -533,9 +531,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGACOW_ID then Result := GetMangaCowPageNumber else - if manager.container.MangaSiteID = SENMANGA_ID then - Result := GetSenMangaPageNumber - else if (manager.container.MangaSiteID = MANGAEDEN_ID) or (manager.container.MangaSiteID = PERVEDEN_ID) then Result := GetMangaEdenPageNumber @@ -683,8 +678,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/ScanManga/image_url.inc} - {$I includes/SenManga/image_url.inc} - {$I includes/Starkana/image_url.inc} {$I includes/TruyenTranhTuan/image_url.inc} @@ -815,9 +808,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGACOW_ID then Result := GetMangaCowImageURL else - if manager.container.MangaSiteID = SENMANGA_ID then - Result := GetSenMangaImageURL - else if manager.container.MangaSiteID = TRUYENTRANHTUAN_ID then Result := GetTruyenTranhTuanImageURL else From 1f687baeade5662b22301a3fcac16ee895109680 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 16:54:22 +0800 Subject: [PATCH 1059/2794] wpmanga, added senmanga fixed #215 --- baseunits/modules/WPManga.pas | 97 +++++++++++++++++------------------ 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 57e853f8a..55cab7965 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -6,23 +6,20 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, synautil, RegExpr; implementation -uses - RegExpr, synautil; - const dirURL = '/manga-list/all/any/last-added/'; dirURLmangaindo = '/daftar-manga/all/any/last-added/'; dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; dirURLmangahen = '/manga_list/all/any/last-added/'; + dirURLsenmanga = '/directory/all/any/last-added/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; s: String; begin Page := 1; @@ -32,18 +29,18 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else if Module.Website = 'MangaHen' then s := dirURLmangahen + else if Module.Website = 'SenManga' then s := dirURLsenmanga else s := dirURL; if GET(Module.RootURL + s) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - s := Query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); - s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); - Page := StrToIntDef(s, 1); - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//*[@class="pgg"]/li[last()]/a/@href'); + s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); + Page := StrToIntDef(s, 1); + finally + Free; + end; end; end; end; @@ -51,7 +48,6 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; s: String; begin @@ -61,38 +57,42 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else if Module.Website = 'MangaHen' then s := dirURLmangahen + else if Module.Website = 'SenManga' then s := dirURLsenmanga else s := dirURL; if GET(Module.RootURL + s + IncStr(AURL) + '/') then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - if Module.Website = 'MangaIndo' then begin - for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do - ALinks.Add(v.toString); - for v in Query.XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do - ANames.Add(v.toString); - end - else if Module.Website = 'ReadHentaiManga' then begin - for v in Query.XPath('//*[@id="content"]//*[@id="center"]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toNode.getAttribute('title')); - end; - end - else begin - if (Module.Website = 'EyeOnManga') or + with TXQueryEngineHTML.Create(Document) do + try + if Module.Website = 'MangaIndo' then begin + for v in XPath('//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do + ALinks.Add(v.toString); + for v in XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do + ANames.Add(v.toString); + end + else if Module.Website = 'ReadHentaiManga' then + for v in XPath('//*[@id="content"]//*[@id="center"]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toNode.getAttribute('title')); + end + else if Module.Website = 'SenManga' then + for v in XPath('//table[@id="wpm_mng_lst"]/tbody/tr/td/a[1]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toNode.getAttribute('title')); + end + else if (Module.Website = 'EyeOnManga') or (Module.Website = 'MangaBoom') then - s := '//*[@id="sct_content"]//h2/a[1]' + for v in XPath('//*[@id="sct_content"]//h2/a[1]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end else - s := '//*[@id="sct_content"]//div[@class="det"]/a[1]'; - for v in Query.XPath(s) do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; + for v in XPath('//*[@id="sct_content"]//div[@class="det"]/a[1]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - query.Free; - end; end; end; end; @@ -107,28 +107,23 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; procedure scanchapters; begin - with MangaInfo.mangaInfo, query do begin - if Module.Website = 'MangaBoom' then begin + with MangaInfo.mangaInfo, query do if Module.Website = 'MangaBoom' then for v in XPath('//ul[@class="lst"]//a[1]') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toNode.Next.toString()); - end; - end + end else if (Module.Website = 'EyeOnManga') or (Module.Website = 'MangaIndo') then - begin for v in XPath('//ul[@class="chp_lst"]//a[1]') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); - end; - end + end else begin for v in XPath('//ul[@class="lst"]//a[1]/@href') do chapterLinks.Add(v.toString); for v in XPath('//ul[@class="lst"]//a[1]/b[1]') do chapterName.Add(v.toString); end; - end; end; function getwpmangavalue(aname: String): String; @@ -276,7 +271,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.manager.container do if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then begin Result := True; @@ -293,7 +288,6 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Free; end; end; - end; end; procedure RegisterModule; @@ -322,6 +316,7 @@ procedure RegisterModule; AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); AddWebsiteModule('MangaBug', 'http://www.mangabug.com'); + AddWebsiteModule('SenManga', 'http://www.senmanga.com'); end; initialization From 8be29ab04ae51e662f74aca8d61ec81dd8f14c10 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 17:32:34 +0800 Subject: [PATCH 1060/2794] formatting --- baseunits/XQueryEngineHTML.pas | 2 - baseunits/modules/AcademyVN.pas | 70 +-- baseunits/modules/Batoto.pas | 82 +-- baseunits/modules/Cloudflare.pas | 162 +++--- baseunits/modules/EHentai.pas | 69 +-- baseunits/modules/FoOlSlide.pas | 128 ++--- baseunits/modules/GameofScanlation.pas | 124 ++--- baseunits/modules/Hakihome.pas | 106 ++-- baseunits/modules/Hentai2Read.pas | 4 +- baseunits/modules/HentaiCafe.pas | 5 +- baseunits/modules/HitomiLa.pas | 2 +- baseunits/modules/KissManga.pas | 146 ++--- baseunits/modules/Luscious.pas | 2 +- baseunits/modules/Madokami.pas | 60 +- baseunits/modules/MangaBackup.pas | 100 ++-- baseunits/modules/MangaChanRU.pas | 105 ++-- baseunits/modules/MangaKoi.pas | 110 ++-- baseunits/modules/MangaStreamTo.pas | 75 +-- baseunits/modules/MangaTr.pas | 6 +- baseunits/modules/MintMangaRU.pas | 142 ++--- baseunits/modules/PecintaKomik.pas | 94 ++-- baseunits/modules/RawSenManga.pas | 158 +++--- baseunits/modules/Submanga.pas | 100 ++-- baseunits/modules/Tsumino.pas | 104 ++-- baseunits/modules/UnionMangas.pas | 83 +-- baseunits/modules/Webtoons.pas | 85 +-- baseunits/uBaseUnit.pas | 737 +++++++++++++------------ baseunits/uData.pas | 95 ++-- baseunits/uDownloadsManager.pas | 62 ++- baseunits/uMisc.pas | 123 +++-- mangadownloader/md.lpr | 10 +- 31 files changed, 1573 insertions(+), 1578 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 9caed8862..73ffcea1b 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -57,12 +57,10 @@ function StreamToString(const Stream: TStream): String; procedure AddSeparatorString(var Dest: String; const S: String; const Separator: String = ', '); begin if Trim(S) <> '' then - begin if Trim(Dest) = '' then Dest := Trim(S) else Dest := Trim(Dest) + Separator + Trim(S); - end; end; function StringInArray(const S: String; const SS: array of String): Boolean; diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 6a5af6137..a220f0f6e 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/manga/all'; + dirurl = '/manga/all'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -19,11 +19,11 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - page:=StrToIntDef(XPathString('(//*[starts-with(@class,"pagination")]//a)[last()-1]'),1); + page := StrToIntDef(XPathString('(//*[starts-with(@class,"pagination")]//a)[last()-1]'), 1); finally Free; end; @@ -37,12 +37,12 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='?page='+IncStr(AURL); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then s += '?page=' + IncStr(AURL); if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//table[1]/tbody/tr/td[1]/a') do begin @@ -61,29 +61,29 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink:=XPathString('//*[@class="__image"]/img/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=XPathString('//*[@class="__info"]/h3'); - authors:=SeparateRight(XPathString('//*[@class="__info"]/p[starts-with(.,"Tác giả:")]'),':'); - genres:=SeparateRight(XPathString('//*[@class="__info"]/p[starts-with(.,"Thể loại:")]'),':'); - s:=XPathString('//*[@class="__info"]/p[starts-with(.,"Tình trạng:")]'); - if s<>'' then begin - if (Pos('Đang tiến hành',s)>0) or (Pos('Ngưng',s)>0) then status:='1' - else status:='0'; + coverLink := XPathString('//*[@class="__image"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//*[@class="__info"]/h3'); + authors := SeparateRight(XPathString('//*[@class="__info"]/p[starts-with(.,"Tác giả:")]'), ':'); + genres := SeparateRight(XPathString('//*[@class="__info"]/p[starts-with(.,"Thể loại:")]'), ':'); + s := XPathString('//*[@class="__info"]/p[starts-with(.,"Tình trạng:")]'); + if s <> '' then begin + if (Pos('Đang tiến hành', s) > 0) or (Pos('Ngưng', s) > 0) then status := '1' + else status := '0'; end; - summary:=XPathString('//*[@class="__info"]/*[@class="__description"]'); + summary := XPathString('//*[@class="__info"]/*[@class="__description"]'); for v in XPath('//*[@class="table-scroll"]/table/tbody/tr/td[1]/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -96,13 +96,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var v: IXQValue; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; with TXQueryEngineHTML.Create(Document) do try for v in XPath('//*[@class="manga-container"]/img/@src') do @@ -118,12 +118,12 @@ procedure RegisterModule; begin with AddModule do begin - Website:='AcademyVN'; - RootURL:='http://truyen.academyvn.com'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Website := 'AcademyVN'; + RootURL := 'http://truyen.academyvn.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; end; end; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 259368028..2566cf25c 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -27,7 +27,7 @@ function Login(const AHTTP: THTTPSendThread): Boolean; var query: TXQueryEngineHTML; loginform: THTMLForm; - key: string; + key: String; begin Result := False; if AHTTP = nil then Exit; @@ -70,7 +70,8 @@ function Login(const AHTTP: THTTPSendThread): Boolean; Account.Save; end else - Writelog_V(['Batoto, login: failed, unexpected server reply: ',ResultCode,' ',ResultString]); + Writelog_V(['Batoto, login: failed, unexpected server reply: ', + ResultCode, ' ', ResultString]); end else Writelog_V('Batoto, login: connection failed'); @@ -89,7 +90,7 @@ function Login(const AHTTP: THTTPSendThread): Boolean; EnterCriticalsection(locklogin); try if Result then - AHTTP.Cookies.Text:=Account.Cookies[modulename]; + AHTTP.Cookies.Text := Account.Cookies[modulename]; finally LeaveCriticalsection(locklogin); end; @@ -100,25 +101,25 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String): Boolean var s: String; begin - Result:=False; - AHTTP.Cookies.Text:=Account.Cookies['Batoto']; - AHTTP.KeepAlive:=False; - Result:=AHTTP.GET(AURL); - if (AHTTP.ResultCode>400) and (AHTTP.ResultCode<500) then Exit; + Result := False; + AHTTP.Cookies.Text := Account.Cookies['Batoto']; + AHTTP.KeepAlive := False; + Result := AHTTP.GET(AURL); + if (AHTTP.ResultCode > 400) and (AHTTP.ResultCode < 500) then Exit; if Result then begin - Result:=True; - if Account.Enabled[modulename]=False then Exit; - if Account.Username[modulename]='' then Exit; - if Account.Status[modulename]=asInvalid then Exit; - s:=StreamToString(AHTTP.Document); + Result := True; + if Account.Enabled[modulename] = False then Exit; + if Account.Username[modulename] = '' then Exit; + if Account.Status[modulename] = asInvalid then Exit; + s := StreamToString(AHTTP.Document); Result := (Pos('class=''logged_in''', s) > 0) or (Pos('class="logged_in"', s) > 0); if not Result then begin - Result:=Login(AHTTP); + Result := Login(AHTTP); if Result then - Result:=AHTTP.GET(AURL) + Result := AHTTP.GET(AURL) else begin - Result:=True; + Result := True; AHTTP.Document.Clear; WriteStrToStream(AHTTP.Document, s); end; @@ -131,17 +132,19 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var s: String; begin - Result:=NET_PROBLEM; - Page:=1; - if MangaInfo =nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage)) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + + dirparam + IntToStr(perpage)) + then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=Trim(XPathString('//ul[@class="ipsList_inline left pages"]/li/a')); - if s<>'' then - Page:=StrToIntDef(Trim(SeparateRight(LowerCase(s),'page 1 of ')),1); + s := Trim(XPathString('//ul[@class="ipsList_inline left pages"]/li/a')); + if s <> '' then + Page := StrToIntDef(Trim(SeparateRight(LowerCase(s), 'page 1 of ')), 1); finally Free; end; @@ -155,12 +158,12 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurls[Module.CurrentDirectoryIndex]+dirparam+IntToStr(perpage); - if AURL<>'0' then s+='&st='+IntToStr(StrToInt(AURL)*perpage); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + dirparam + IntToStr(perpage); + if AURL <> '0' then s += '&st=' + IntToStr(StrToInt(AURL) * perpage); if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//table[@class="ipb_table topic_list hover_rows"]/tbody/tr/td/h4/a') do begin @@ -185,7 +188,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo do begin website := modulename; url := FillHost(urlroot, AURL); - if GETWithLogin(MangaInfo.FHTTP,url) then begin + if GETWithLogin(MangaInfo.FHTTP, url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -194,9 +197,9 @@ function GetInfo(const MangaInfo: TMangaInformation; title := XPathString('//h1[@class="ipsType_pagetitle"]'); for v in XPath('//table[@class="ipb_table"]//tr') do begin s := v.toString; - if Pos('Author:', s) > 0 then authors:= GetRightValue('Author:', s) - else if Pos('Artist:', s) > 0 then artists:= GetRightValue('Artist:', s) - else if Pos('Description:', s) > 0 then summary:= GetRightValue('Description:', s) + if Pos('Author:', s) > 0 then authors := GetRightValue('Author:', s) + else if Pos('Artist:', s) > 0 then artists := GetRightValue('Artist:', s) + else if Pos('Description:', s) > 0 then summary := GetRightValue('Description:', s) else if Pos('Status:', s) > 0 then begin if Pos('Ongoing', s) > 0 then status := '1' else status := '0'; @@ -217,11 +220,11 @@ function GetInfo(const MangaInfo: TMangaInformation; t := w.toString; if OptionBatotoShowAllLang then begin l := XPath('td[2]/div', v.toNode).toNode.getAttribute('title'); - if l <> '' then t += ' ['+ l +']'; + if l <> '' then t += ' [' + l + ']'; end; if OptionBatotoShowScanGroup then begin l := XPath('td[3]', v.toNode).toString; - if l <> '' then t += ' ['+ l +']'; + if l <> '' then t += ' [' + l + ']'; end; chapterName.Add(t); end; @@ -251,9 +254,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageContainerLinks.Text := cid; if XPathString('//select[@id="page_select"]') <> '' then begin PageNumber := XPath('(//select[@id="page_select"])[1]/option/@value').Count; - if PageNumber>0 then begin - s:=XPathString('//div[@id="full_image"]//img/@src'); - if s<>'' then PageLinks.Add(s) + if PageNumber > 0 then begin + s := XPathString('//div[@id="full_image"]//img/@src'); + if s <> '' then PageLinks.Add(s); end; end else begin @@ -278,7 +281,8 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.manager.container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; - rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + IntToStr(DownloadThread.WorkCounter + 1); + rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + + IntToStr(DownloadThread.WorkCounter + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; if GET(rurl) then begin Result := True; diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 0e0d14110..d3a318f28 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -14,75 +14,75 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; overl implementation -function AntiBotActive(const AHTTP:THTTPSendThread): Boolean; +function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; begin - Result:=False; - if AHTTP=nil then Exit; - Result:=Pos('URL=/cdn-cgi/',AHTTP.Headers.Values['Refresh'])>0; + Result := False; + if AHTTP = nil then Exit; + Result := Pos('URL=/cdn-cgi/', AHTTP.Headers.Values['Refresh']) > 0; end; -function JSGetAnsweredURL(const Source,URL: String; var OMethod, OURL: String; +function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; var OSleepTime: Integer): Boolean; var s, meth, surl, jschl_vc, pass, jschl_answer: String; v: TBESENValue; begin - Result:=False; - if (Source='') or (URL='') then Exit; + Result := False; + if (Source = '') or (URL = '') then Exit; - meth:=''; - surl:=''; - jschl_vc:=''; - pass:=''; - jschl_answer:=''; + meth := ''; + surl := ''; + jschl_vc := ''; + pass := ''; + jschl_answer := ''; with TXQueryEngineHTML.Create(Source) do - try - meth:=UpperCase(XPathString('//form[@id="challenge-form"]/@method')); - surl:=XPathString('//form[@id="challenge-form"]/@action'); - jschl_vc:=XPathString('//input[@name="jschl_vc"]/@value'); - pass:=XPathString('//input[@name="pass"]/@value'); - finally - Free; - end; + try + meth := UpperCase(XPathString('//form[@id="challenge-form"]/@method')); + surl := XPathString('//form[@id="challenge-form"]/@action'); + jschl_vc := XPathString('//input[@name="jschl_vc"]/@value'); + pass := XPathString('//input[@name="pass"]/@value'); + finally + Free; + end; - if (meth='') or (surl='') or (jschl_vc='') or (pass='') then Exit; + if (meth = '') or (surl = '') or (jschl_vc = '') or (pass = '') then Exit; - s:=Source; + s := Source; with TRegExpr.Create do try - ModifierG:=False; - ModifierI:=True; - Expression:='^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; - Expression:='^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; - s:=Replace(s,'$1',True); - Expression:='\s{3,}[a-z](\s*=\s*document\.|\.).+;\r?\n'; - s:=Replace(s,'',False); - Expression:='t\s=\s*t\.firstChild.href;'; - s:=Replace(s,' t = "'+URL+'";',False); - Expression:='a\.value\s*='; - s:=Replace(s,'a =',False); - Expression:='^.*\.submit\(.*\},\s*(\d{4,})\).*$'; - OSleepTime:=StrToIntDef(Replace(Source,'$1',True),5000); + ModifierG := False; + ModifierI := True; + Expression := '^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; + Expression := '^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; + s := Replace(s, '$1', True); + Expression := '\s{3,}[a-z](\s*=\s*document\.|\.).+;\r?\n'; + s := Replace(s, '', False); + Expression := 't\s=\s*t\.firstChild.href;'; + s := Replace(s, ' t = "' + URL + '";', False); + Expression := 'a\.value\s*='; + s := Replace(s, 'a =', False); + Expression := '^.*\.submit\(.*\},\s*(\d{4,})\).*$'; + OSleepTime := StrToIntDef(Replace(Source, '$1', True), 5000); finally Free; end; with TBESEN.Create do begin try - v:=Execute(s); - if v.ValueType=bvtNUMBER then - jschl_answer:=FloatToStr(v.Num); + v := Execute(s); + if v.ValueType = bvtNUMBER then + jschl_answer := FloatToStr(v.Num); except - jschl_answer:=''; + jschl_answer := ''; end; Free; end; - if jschl_answer='' then Exit; - OMethod:=meth; - OURL:=surl+'?jschl_vc='+jschl_vc+'&pass='+pass+'&jschl_answer='+jschl_answer; - Result:=True; + if jschl_answer = '' then Exit; + OMethod := meth; + OURL := surl + '?jschl_vc=' + jschl_vc + '&pass=' + pass + '&jschl_answer=' + jschl_answer; + Result := True; end; function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): Boolean; @@ -90,35 +90,35 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B m, u, h: String; st, counter: Integer; begin - Result:=False; - if AHTTP=nil then Exit; - if Cookie<>'' then AHTTP.Cookies.Text:=Cookie; - counter:=0; - while counter<3 do begin + Result := False; + if AHTTP = nil then Exit; + if Cookie <> '' then AHTTP.Cookies.Text := Cookie; + counter := 0; + while counter < 3 do begin Inc(counter); if AntiBotActive(AHTTP) then begin - m:='GET'; - u:=''; - h:=AppendURLDelim(GetHostURL(AURL)); - st:=5000; - if JSGetAnsweredURL(StreamToString(AHTTP.Document),h,m,u,st) then - if (m<>'') and (u<>'') then begin + m := 'GET'; + u := ''; + h := AppendURLDelim(GetHostURL(AURL)); + st := 5000; + if JSGetAnsweredURL(StreamToString(AHTTP.Document), h, m, u, st) then + if (m <> '') and (u <> '') then begin AHTTP.Reset; - AHTTP.Headers.Values['Referer']:=' '+AURL; + AHTTP.Headers.Values['Referer'] := ' ' + AURL; //minimum wait time is 5000 - if st<5000 then st:=5000; + if st < 5000 then st := 5000; Sleep(st); - AHTTP.FollowRedirection:=False; - if AHTTP.HTTPRequest(m,FillHost(h,u)) then - Result:=AHTTP.Cookies.Values['cf_clearance']<>''; - AHTTP.FollowRedirection:=True; - if Result then Cookie:=AHTTP.GetCookies; + AHTTP.FollowRedirection := False; + if AHTTP.HTTPRequest(m, FillHost(h, u)) then + Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; + AHTTP.FollowRedirection := True; + if Result then Cookie := AHTTP.GetCookies; end; end; if Result then Exit - else if counter<3 then begin + else if counter < 3 then begin AHTTP.Reset; - Result:=AHTTP.GET(AURL); + Result := AHTTP.GET(AURL); end; end; end; @@ -126,37 +126,37 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; var CS: TRTLCriticalSection): Boolean; begin - Result:=False; - if AHTTP=nil then Exit; - AHTTP.Cookies.Text:=Cookie; - Result:=AHTTP.GET(AURL); - if (AHTTP.ResultCode>500) and AntiBotActive(AHTTP) then begin - if TryEnterCriticalsection(CS)>0 then + Result := False; + if AHTTP = nil then Exit; + AHTTP.Cookies.Text := Cookie; + Result := AHTTP.GET(AURL); + if (AHTTP.ResultCode > 500) and AntiBotActive(AHTTP) then begin + if TryEnterCriticalsection(CS) > 0 then try - Result:=CFJS(AHTTP,AURL,Cookie); + Result := CFJS(AHTTP, AURL, Cookie); finally LeaveCriticalsection(CS); end else try EnterCriticalsection(CS); - AHTTP.Cookies.Text:=Cookie; + AHTTP.Cookies.Text := Cookie; finally LeaveCriticalsection(CS); end; - Result:=AHTTP.GET(AURL); + Result := AHTTP.GET(AURL); end; end; function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String): Boolean; begin - Result:=False; - if AHTTP=nil then Exit; - AHTTP.Cookies.Text:=Cookie; - Result:=AHTTP.GET(AURL); - if (AHTTP.ResultCode>500) and AntiBotActive(AHTTP) then begin - Result:=CFJS(AHTTP,AURL,Cookie); - Result:=AHTTP.GET(AURL); + Result := False; + if AHTTP = nil then Exit; + AHTTP.Cookies.Text := Cookie; + Result := AHTTP.GET(AURL); + if (AHTTP.ResultCode > 500) and AntiBotActive(AHTTP) then begin + Result := CFJS(AHTTP, AURL, Cookie); + Result := AHTTP.GET(AURL); end; end; @@ -164,8 +164,8 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; var Cookie: String; begin - Cookie:=''; - Result:=GETCF(AHTTP,AURL,Cookie); + Cookie := ''; + Result := GETCF(AHTTP, AURL, Cookie); end; end. diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index decbd5bba..b6e556301 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -10,12 +10,13 @@ interface implementation -uses RegExpr, synacode; +uses + RegExpr, synacode; const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; exhentaiurllogin = 'https://forums.e-hentai.org/index.php?act=Login&CODE=01'; - accname='ExHentai'; + accname = 'ExHentai'; var onlogin: Boolean = False; @@ -35,10 +36,10 @@ function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; Account.Status[accname] := asChecking; Reset; Cookies.Clear; - s := 'returntype=8&CookieDate=1&b=d&bt=pone'+ - '&UserName=' + EncodeURLElement(Account.Username[accname]) + - '&PassWord=' + EncodeURLElement(Account.Password[accname]) + - '&ipb_login_submit=Login%21'; + s := 'returntype=8&CookieDate=1&b=d&bt=pone' + + '&UserName=' + EncodeURLElement(Account.Username[accname]) + + '&PassWord=' + EncodeURLElement(Account.Password[accname]) + + '&ipb_login_submit=Login%21'; if POST(exhentaiurllogin, s) then begin if ResultCode = 200 then begin Result := Cookies.Values['ipb_pass_hash'] <> ''; @@ -190,8 +191,8 @@ function GetInfo(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit; with MangaInfo.mangaInfo do begin website := Module.Website; - url:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); - url:=AppendURLDelim(FillHost(Module.RootURL,url)); + url := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); + url := AppendURLDelim(FillHost(Module.RootURL, url)); if GETWithLogin(MangaInfo.FHTTP, url, Module.Website) then begin Result := NO_ERROR; // if there is only 1 line, it's banned message! @@ -229,7 +230,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Filenames.Add(ExtractFileNameOnly(Trim(SeparateRight( XPathString('img/@title', x.toNode), ':')))); end; - while PageLinks.Count<PageContainerLinks.Count do + while PageLinks.Count < PageContainerLinks.Count do PageLinks.Add('G'); end; end; @@ -242,8 +243,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageContainerLinks.Clear; Filenames.Clear; PageNumber := 0; - rurl:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); - rurl:=AppendURLDelim(FillHost(Module.RootURL,rurl)); + rurl := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); + rurl := AppendURLDelim(FillHost(Module.RootURL, rurl)); if GETWithLogin(DownloadThread.FHTTP, rurl, Module.Website) then begin Result := True; query := TXQueryEngineHTML.Create; @@ -255,10 +256,10 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if getOK then begin GetImageLink; //get page count - p:=StrToIntDef(query.XPathString('//table[@class="ptt"]//td[last()-1]'),0); - if p>1 then begin + p := StrToIntDef(query.XPathString('//table[@class="ptt"]//td[last()-1]'), 0); + if p > 1 then begin Dec(p); - for i:=1 to p do + for i := 1 to p do if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then GetImageLink; end; @@ -290,10 +291,10 @@ function DownloadImage(const DownloadThread: TDownloadThread; while (not Result) and (not DownloadThread.IsTerminated) do begin source.LoadFromStream(DownloadThread.FHTTP.Document); query.ParseHTML(DownloadThread.FHTTP.Document); - iurl:=''; - if OptionEHentaiDownloadOriginalImage and (Account.Status[accname]=asValid) then - iurl:=query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); - if iurl='' then + iurl := ''; + if OptionEHentaiDownloadOriginalImage and (Account.Status[accname] = asValid) then + iurl := query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); + if iurl = '' then iurl := query.XPathString('//*[@id="img"]/@src'); if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); @@ -356,29 +357,29 @@ function DownloadImage(const DownloadThread: TDownloadThread; procedure RegisterModule; - function AddWebsiteModule(AWebsite,ARootURL:String):TModuleContainer; + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - Result:=AddModule; + Result := AddModule; with Result do begin - Website:=AWebsite; - RootURL:=ARootURL; + Website := AWebsite; + RootURL := ARootURL; MaxTaskLimit := 1; - MaxConnectionLimit:=4; - SortedList:=True; - DynamicPageLink:=True; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnDownloadImage:=@DownloadImage; + MaxConnectionLimit := 4; + SortedList := True; + DynamicPageLink := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; end; end; begin - AddWebsiteModule('E-Hentai','http://g.e-hentai.org'); - with AddWebsiteModule('ExHentai','http://exhentai.org') do begin - AccountSupport:=True; - OnLogin:=@ExHentaiLogin; + AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org'); + with AddWebsiteModule('ExHentai', 'http://exhentai.org') do begin + AccountSupport := True; + OnLogin := @ExHentaiLogin; end; end; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 23e0ae5a7..60481c34b 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -11,8 +11,8 @@ interface implementation const - dirurl='/directory/'; - yomangadirurl='/reader/directory/'; + dirurl = '/directory/'; + yomangadirurl = '/reader/directory/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -23,17 +23,17 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if Module.Website='YoManga' then s:=yomangadirurl - else s:=dirurl; - if MangaInfo.FHTTP.GET(Module.RootURL+s) then begin + if Module.Website = 'YoManga' then s := yomangadirurl + else s := dirurl; + if MangaInfo.FHTTP.GET(Module.RootURL + s) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=query.XPathString('//div[@class="next"]/a[contains(text(),"Last")]/@href'); - if s<>'' then begin - s:=ReplaceRegExpr('.*/(\d+)/$',s,'$1',True); - Page:=StrToIntDef(s,1); + s := query.XPathString('//div[@class="next"]/a[contains(text(),"Last")]/@href'); + if s <> '' then begin + s := ReplaceRegExpr('.*/(\d+)/$', s, '$1', True); + Page := StrToIntDef(s, 1); end; finally query.Free; @@ -49,15 +49,15 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if Module.Website='YoManga' then s:=yomangadirurl - else s:=dirurl; - s:=Module.RootURL+s; - if AURL<>'0' then s+=IncStr(AURL)+'/'; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if Module.Website = 'YoManga' then s := yomangadirurl + else s := dirurl; + s := Module.RootURL + s; + if AURL <> '0' then s += IncStr(AURL) + '/'; if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//div[@class="list series"]/div/div[@class="title"]/a') do begin @@ -76,19 +76,22 @@ function GetInfo(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//div[@class="thumbnail"]/img/@src'); - if title=''then title:=query.XPathString('//h1[@class="title"]'); - authors:=TrimLeftChar(query.XPathString('//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'),[':',' ']); - artists:=TrimLeftChar(query.XPathString('//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'),[':',' ']); - summary:=TrimLeftChar(query.XPathString('//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'),[':',' ']); + coverLink := query.XPathString('//div[@class="thumbnail"]/img/@src'); + if title = '' then title := query.XPathString('//h1[@class="title"]'); + authors := TrimLeftChar(query.XPathString( + '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), [':', ' ']); + artists := TrimLeftChar(query.XPathString( + '//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), [':', ' ']); + summary := TrimLeftChar(query.XPathString( + '//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), [':', ' ']); for v in query.XPath('//div[@class="list"]//div[@class="title"]/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); @@ -96,7 +99,7 @@ function GetInfo(const MangaInfo: TMangaInformation; chapterName.Add(v.toNode.getAttribute('title')) else chapterName.Add(v.toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally query.Free; end; @@ -111,20 +114,20 @@ function GetPageNumber(const DownloadThread: TDownloadThread; v: IXQValue; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').Count; - s:=query.XPathString('//script[contains(.,"var pages")]'); - if s<>'' then begin - s:=GetBetween('var pages = ',';',s); + PageNumber := query.XPath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').Count; + s := query.XPathString('//script[contains(.,"var pages")]'); + if s <> '' then begin + s := GetBetween('var pages = ', ';', s); try query.ParseHTML(s); for v in query.XPath('json(*)()("url")') do @@ -145,17 +148,18 @@ function GetImageURL(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=AURL; - if DownloadThread.workCounter>0 then s:=AppendURLDelim(s)+'page/'+IncStr(DownloadThread.workCounter); - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := AURL; + if DownloadThread.workCounter > 0 then + s := AppendURLDelim(s) + 'page/' + IncStr(DownloadThread.workCounter); + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter]:=query.XPathString('//div[@id="page"]//img/@src'); + PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@id="page"]//img/@src'); finally query.Free; end; @@ -165,24 +169,24 @@ function GetImageURL(const DownloadThread: TDownloadThread; procedure RegisterModule; - procedure AddWebsiteModule(AWebsite,ARootURL: String); + procedure AddWebsiteModule(AWebsite, ARootURL: String); + begin + with AddModule do begin - with AddModule do - begin - Website:=AWebsite; - RootURL:=ARootURL; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; - end; + Website := AWebsite; + RootURL := ARootURL; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; + end; begin - AddWebsiteModule('Shoujosense','http://reader.shoujosense.com'); - AddWebsiteModule('YoManga','http://yomanga.co'); - AddWebsiteModule('RawYoManga','http://raws.yomanga.co'); + AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); + AddWebsiteModule('YoManga', 'http://yomanga.co'); + AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); end; initialization diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index b8506c999..eb6645cfa 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -11,14 +11,14 @@ interface implementation const - dirurl='/projects/'; + dirurl = '/projects/'; var - goscookies: string=''; + goscookies: String = ''; goslockget: TRTLCriticalSection; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; begin - Result:=Cloudflare.GETCF(AHTTP,AURL,goscookies,goslockget); + Result := Cloudflare.GETCF(AHTTP, AURL, goscookies, goslockget); end; function GetNameAndLink(const MangaInfo: TMangaInformation; @@ -27,19 +27,19 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; var v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+dirurl) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="info"]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + try + for v in XPath('//div[@class="info"]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - Free; - end; end; end; @@ -60,33 +60,33 @@ function GetInfo(const MangaInfo: TMangaInformation; end; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - url:=AppendURLDelim(FillHost(Module.RootURL,AURL)); - if GETWithCookie(MangaInfo.FHTTP,url) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create(Document); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + url := AppendURLDelim(FillHost(Module.RootURL, AURL)); + if GETWithCookie(MangaInfo.FHTTP, url) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(Document); try - if title=''then title:=query.XPathString('//div[@class="con"]/h2'); - summary:=query.XPathString('//dd[@class="dsc"]'); - s:=query.XPathString('//div[@class="con"]/dl/span[@class="aln"]'); - if s<>'' then begin - s:=LowerCase(s); - if Pos('ongoing',s)>0 then - status:='1' - else if Pos('completed',s)>0 then - status:='0'; + if title = '' then title := query.XPathString('//div[@class="con"]/h2'); + summary := query.XPathString('//dd[@class="dsc"]'); + s := query.XPathString('//div[@class="con"]/dl/span[@class="aln"]'); + if s <> '' then begin + s := LowerCase(s); + if Pos('ongoing', s) > 0 then + status := '1' + else if Pos('completed', s) > 0 then + status := '0'; end; GetChapters; - p:=StrToIntDef(query.XPathString('//nav/a[last()-1]'),1); - if p>1 then - for i:=2 to p do - if GET(AppendURLDelim(url)+'page-'+IntToStr(i)) then begin + p := StrToIntDef(query.XPathString('//nav/a[last()-1]'), 1); + if p > 1 then + for i := 2 to p do + if GET(AppendURLDelim(url) + 'page-' + IntToStr(i)) then begin query.ParseHTML(Document); GetChapters; end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally query.Free; end; @@ -100,22 +100,22 @@ function GetPageNumber(const DownloadThread: TDownloadThread; v: IXQValue; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - s:=ReplaceRegExpr('/\?\w+.*$',AURL,'/',False); - s:=AppendURLDelim(FillHost(Module.RootURL,s))+'?chapter_view=fullstrip'; - if GETWithCookie(DownloadThread.FHTTP,s) then begin - Result:=True; + s := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); + s := AppendURLDelim(FillHost(Module.RootURL, s)) + '?chapter_view=fullstrip'; + if GETWithCookie(DownloadThread.FHTTP, s) then begin + Result := True; with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//div[@id="comicMainImage"]//img/@src') do - PageLinks.Add(MaybeFillHost(Module.RootURL,v.toString)); - finally - Free; - end; + try + for v in XPath('//div[@id="comicMainImage"]//img/@src') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)); + finally + Free; + end; end; end; end; @@ -123,16 +123,16 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function BeforeDownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - Result:=False; + Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do - if CurrentDownloadChapterPtr<ChapterLinks.Count then begin - Headers.Values['Referer']:=' '+FillHost(Module.RootURL,ChapterLinks[CurrentDownloadChapterPtr]); - Cookies.Text:=goscookies; - if (goscookies='') or (HEAD(AURL) and (ResultCode=503)) then - Result:=GETWithCookie(DownloadThread.FHTTP,Module.RootURL) + with DownloadThread.manager.container, DownloadThread.FHTTP do + if CurrentDownloadChapterPtr < ChapterLinks.Count then begin + Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + Cookies.Text := goscookies; + if (goscookies = '') or (HEAD(AURL) and (ResultCode = 503)) then + Result := GETWithCookie(DownloadThread.FHTTP, Module.RootURL) else - Result:=True; + Result := True; end; end; @@ -140,12 +140,12 @@ procedure RegisterModule; begin with AddModule do begin - Website:='GameofScanlation'; - RootURL:='https://gameofscanlation.moe'; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnBeforeDownloadImage:=@BeforeDownloadImage; + Website := 'GameofScanlation'; + RootURL := 'https://gameofscanlation.moe'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; end; end; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 4599a5050..814c2fa67 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/listmangahentai.html'; + dirurl = '/listmangahentai.html'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -22,13 +22,13 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=query.XPathString('//*[@class="nav"]/li[last()-1]/a/@href'); - if s<>'' then Page:=StrToIntDef(GetBetween('/pagel/','/',s),1); + s := query.XPathString('//*[@class="nav"]/li[last()-1]/a/@href'); + if s <> '' then Page := StrToIntDef(GetBetween('/pagel/', '/', s), 1); finally query.Free; end; @@ -43,13 +43,13 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='/pagel/'+IncStr(AURL)+'/'; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then s += '/pagel/' + IncStr(AURL) + '/'; if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//table[@class="listing"]/tbody/tr/td[2]/a') do begin @@ -68,27 +68,27 @@ function GetInfo(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//*[@class="noidung"]//img/@src'); - if title=''then title:=query.XPathString('//*[@class="tuade"]'); - artists:=SeparateRight(query.XPathString('//*[@class="art lefts"]'),':'); - genres:=SeparateRight(query.XPathString('//*[@class="category lefts"]'),':'); - AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="tag"]'),':')); - AddCommaString(genres,SeparateRight(query.XPathString('//*[@class="lan rights"]'),':')); + coverLink := query.XPathString('//*[@class="noidung"]//img/@src'); + if title = '' then title := query.XPathString('//*[@class="tuade"]'); + artists := SeparateRight(query.XPathString('//*[@class="art lefts"]'), ':'); + genres := SeparateRight(query.XPathString('//*[@class="category lefts"]'), ':'); + AddCommaString(genres, SeparateRight(query.XPathString('//*[@class="tag"]'), ':')); + AddCommaString(genres, SeparateRight(query.XPathString('//*[@class="lan rights"]'), ':')); for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(Trim(title+' '+v.toString)); + chapterName.Add(Trim(title + ' ' + v.toString)); end; - if (chapterName.Count=1) and (title<>'') then - chapterName[0]:=title; - InvertStrings([chapterLinks,chapterName]); + if (chapterName.Count = 1) and (title <> '') then + chapterName[0] := title; + InvertStrings([chapterLinks, chapterName]); finally query.Free; end; @@ -103,24 +103,24 @@ function GetPageNumber(const DownloadThread: TDownloadThread; s: String; v: IXQValue; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - Cookies.Values['ReadType']:='2'; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Cookies.Values['ReadType'] := '2'; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('(//*[@id="topn"]/span/select)[last()]/option').Count; - s:=query.XPathString('//*[@id="contentchap"]//script[contains(.,"var jsondata")]'); - if s<>'' then begin - s:=Trim(GetBetween('=',';',s)); + PageNumber := query.XPath('(//*[@id="topn"]/span/select)[last()]/option').Count; + s := query.XPathString('//*[@id="contentchap"]//script[contains(.,"var jsondata")]'); + if s <> '' then begin + s := Trim(GetBetween('=', ';', s)); query.ParseHTML(s); for v in query.XPath('json(*)()') do - PageLinks.Add(v.toString); + PageLinks.Add(v.toString); end; finally query.Free; @@ -135,16 +135,16 @@ function GetImageURL(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=AppendURLDelim(AURL)+IncStr(DownloadThread.workCounter)+'/'; - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := AppendURLDelim(AURL) + IncStr(DownloadThread.workCounter) + '/'; + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter]:=query.XPathString('//*[@id="con"]//img/@src'); + PageLinks[DownloadThread.workCounter] := query.XPathString('//*[@id="con"]//img/@src'); finally query.Free; end; @@ -156,13 +156,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='Hakihome'; - RootURL:='http://hakihome.com'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; + Website := 'Hakihome'; + RootURL := 'http://hakihome.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; end; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 4b83a6a4f..2f71d64a1 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -191,9 +191,9 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; with TXQueryEngineHTML.Create(Document) do try s := XPathString('//img[@id="arf-reader"]/@src'); - if s<>'' then + if s <> '' then begin - s:=TrimLeftChar(s,['/']); + s := TrimLeftChar(s, ['/']); PageLinks[DownloadThread.workCounter] := MaybeFillHost(cdnurl, s); end; finally diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index 2ab206533..158f82cba 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -10,7 +10,8 @@ interface implementation -uses synautil; +uses + synautil; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -41,7 +42,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/page/'+ AURL +'/') then begin + if MangaInfo.FHTTP.GET(Module.RootURL + '/page/' + AURL + '/') then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 6969a05bb..3a582a916 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -46,7 +46,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/index-all-'+ AURL +'.html') then begin + if MangaInfo.FHTTP.GET(Module.RootURL + '/index-all-' + AURL + '.html') then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 562172fe0..e45c5dfb8 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -11,15 +11,15 @@ interface implementation const - dirurl='/MangaList/Newest'; + dirurl = '/MangaList/Newest'; var - kissmangacookies: String=''; + kissmangacookies: String = ''; kissmangalockget: TRTLCriticalSection; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; begin - Result:=Cloudflare.GETCF(AHTTP,AURL,kissmangacookies,kissmangalockget); + Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacookies, kissmangalockget); end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; @@ -30,18 +30,18 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP,Module.RootURL+dirurl) then begin + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - s:=XPathString('//ul[@class="pager"]/li[last()]/a/@href'); - if s<>'' then begin - s:=ReplaceRegExpr('^.*=(\d+)$',s,'$1',True); - Page:=StrToIntDef(s,1); + try + s := XPathString('//ul[@class="pager"]/li[last()]/a/@href'); + if s <> '' then begin + s := ReplaceRegExpr('^.*=(\d+)$', s, '$1', True); + Page := StrToIntDef(s, 1); + end; + finally + Free; end; - finally - Free; - end; end; end; @@ -52,22 +52,22 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then - s:=s+'?page='+IncStr(AURL); - if GETWithCookie(MangaInfo.FHTTP,s) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then + s := s + '?page=' + IncStr(AURL); + if GETWithCookie(MangaInfo.FHTTP, s) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//table[@class="listing"]/tbody/tr/td[1]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + try + for v in XPath('//table[@class="listing"]/tbody/tr/td[1]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - Free; - end; end; end; @@ -78,38 +78,38 @@ function GetInfo(const MangaInfo: TMangaInformation; i: Integer; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP,FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - with MangaInfo.mangaInfo,TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - coverLink:=XPathString('//div[@id="rightside"]//img/@src'); - if title=''then title:=XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); - v:=XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); - if v.Count > 0 then begin - i:=0; - while i<v.Count-2 do begin - s:=v.get(i).toString; - if Pos('Genres:',s)=1 then genres:=SeparateRight(s,':') else - if Pos('Author:',s)=1 then authors:=SeparateRight(s,':') else - if Pos('Artist:',s)=1 then artists:=SeparateRight(s,':') else - if Pos('Status:',s)=1 then begin - if Pos('ongoing',LowerCase(v.get(i).toString))>0 then status:='1' - else status:='0'; - end else - if Pos('Summary:',s)=1 then summary:=v.get(i+1).toString; - Inc(i); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + coverLink := XPathString('//div[@id="rightside"]//img/@src'); + if title = '' then title := XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); + v := XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); + if v.Count > 0 then begin + i := 0; + while i < v.Count - 2 do begin + s := v.get(i).toString; + if Pos('Genres:', s) = 1 then genres := SeparateRight(s, ':') else + if Pos('Author:', s) = 1 then authors := SeparateRight(s, ':') else + if Pos('Artist:', s) = 1 then artists := SeparateRight(s, ':') else + if Pos('Status:', s) = 1 then begin + if Pos('ongoing', LowerCase(v.get(i).toString)) > 0 then status := '1' + else status := '0'; + end else + if Pos('Summary:', s) = 1 then summary := v.get(i + 1).toString; + Inc(i); + end; end; + for v in XPath('//table[@class="listing"]/tbody/tr/td/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; end; - for v in XPath('//table[@class="listing"]/tbody/tr/td/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks,chapterName]); - finally - Free; - end; end; end; @@ -119,20 +119,20 @@ function GetPageNumber(const DownloadThread: TDownloadThread; source: TStringList; i: Integer; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP,FillHost(Module.RootURL,AURL)) then begin - Result:=True; - source:=TStringList.Create; + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin + Result := True; + source := TStringList.Create; try source.LoadFromStream(Document); - if source.Count>0 then - for i:=0 to source.Count-1 do begin - if Pos('lstImages.push',source[i])>0 then - PageLinks.Add(GetBetween('.push("','");',source[i])); + if source.Count > 0 then + for i := 0 to source.Count - 1 do begin + if Pos('lstImages.push', source[i]) > 0 then + PageLinks.Add(GetBetween('.push("', '");', source[i])); end; finally source.Free; @@ -145,13 +145,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='KissManga'; - RootURL:='http://kissmanga.com'; - SortedList:=True; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Website := 'KissManga'; + RootURL := 'http://kissmanga.com'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; end; end; diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 9a833c43a..1935c42e2 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -145,7 +145,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); Source := TStringList.Create; - regx:=TRegExpr.Create; + regx := TRegExpr.Create; try regx.ModifierI := True; regx.Expression := '/page/\d+/?$'; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index a872d9288..f9bb3a6e6 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -13,7 +13,7 @@ implementation const modulename = 'Madokami'; urlroot = 'https://manga.madokami.com'; - madokamidirlist: array [0..12] of string = ( + madokamidirlist: array [0..12] of String = ( '/Manga/%23%20-%20F', '/Manga/G%20-%20M', '/Manga/N%20-%20Z', @@ -47,7 +47,7 @@ function Login(const AHTTP: THTTPSendThread): Boolean; ':' + Account.Password[modulename]); if AHTTP.GET(urlroot + '/login') then begin //Result := AHTTP.Cookies.Values['laravel_session'] <> ''; - Result:=(AHTTP.ResultCode<400) and (AHTTP.Headers.Values['WWW-Authenticate']=''); + Result := (AHTTP.ResultCode < 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ''); if Result then begin Account.Cookies[modulename] := AHTTP.GetCookies; Account.Status[modulename] := asValid; @@ -65,7 +65,7 @@ function Login(const AHTTP: THTTPSendThread): Boolean; EnterCriticalsection(locklogin); try if Result then - AHTTP.Cookies.Text:=Account.Cookies[modulename]; + AHTTP.Cookies.Text := Account.Cookies[modulename]; finally LeaveCriticalsection(locklogin); end; @@ -101,21 +101,21 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; currentdir: Integer; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - currentdir:=StrToIntDef(AURL,0); - if currentdir>Length(madokamidirlist) then Exit; - if MangaInfo.FHTTP.GET(Module.RootURL+madokamidirlist[currentdir]) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + currentdir := StrToIntDef(AURL, 0); + if currentdir > Length(madokamidirlist) then Exit; + if MangaInfo.FHTTP.GET(Module.RootURL + madokamidirlist[currentdir]) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - s:=v.toString; - if Length(s)>1 then - if s[Length(s)]='/' then - SetLength(s,Length(s)-1); + s := v.toString; + if Length(s) > 1 then + if s[Length(s)] = '/' then + SetLength(s, Length(s) - 1); ANames.Add(s); end; finally @@ -134,7 +134,7 @@ function GetInfo(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; - with MangaInfo.mangaInfo,TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try coverLink := XPathString('//img[@itemprop="image"]/@src'); if title = '' then title := XPathString('//*[@class="title"]'); @@ -179,27 +179,27 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin Result := True; with TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document) do - try - datapath := XPathString('//div[@id="reader"]/@data-path'); - datapath := EncodeURLElement(datapath); - datafiles := XPathString('//div[@id="reader"]/@data-files'); - datafiles := Trim(TrimChar(datafiles, ['[', ']'])); - datafiles := JSONStringToString(datafiles); - PageLinks.Delimiter := ','; - PageLinks.DelimitedText := datafiles; - if PageLinks.Count > 0 then - for i := 0 to PageLinks.Count - 1 do - PageLinks[i] := Module.RootURL + '/reader/image?path=' + - datapath + '&file=' + EncodeURLElement(PageLinks[i]); - finally - Free; - end; + try + datapath := XPathString('//div[@id="reader"]/@data-path'); + datapath := EncodeURLElement(datapath); + datafiles := XPathString('//div[@id="reader"]/@data-files'); + datafiles := Trim(TrimChar(datafiles, ['[', ']'])); + datafiles := JSONStringToString(datafiles); + PageLinks.Delimiter := ','; + PageLinks.DelimitedText := datafiles; + if PageLinks.Count > 0 then + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := Module.RootURL + '/reader/image?path=' + + datapath + '&file=' + EncodeURLElement(PageLinks[i]); + finally + Free; + end; end; end; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index 758afce3f..bd41f6172 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -13,14 +13,14 @@ implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin - Result:=NET_PROBLEM; - Page:=1; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+'/genre/?add') then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/genre/?add') then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - Page:=XPath('(//select)[1]/option').Count; + Page := XPath('(//select)[1]/option').Count; finally Free; end; @@ -34,20 +34,20 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL; - if AURL='0' then - s:=s+'/genre/?add' + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL; + if AURL = '0' then + s := s + '/genre/?add' else - s:=s+'/genre/'+IncStr(AURL)+'?add'; + s := s + '/genre/' + IncStr(AURL) + '?add'; if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//div[@class="ls1"]/div//h3/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('text()',v.toNode)); + ANames.Add(XPathString('text()', v.toNode)); end; finally Free; @@ -61,39 +61,39 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - url:=FillHost(Module.RootURL,AURL); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + url := FillHost(Module.RootURL, AURL); if GET(url) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink:=XPathString('//div[@class="cover"]/img/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=XPathString('//h1/a'); - authors:=XPathString('//table[@class="attr"]/tbody/tr[5]/td'); - artists:=XPathString('//table[@class="attr"]/tbody/tr[6]/td'); - genres:=''; + coverLink := XPathString('//div[@class="cover"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1/a'); + authors := XPathString('//table[@class="attr"]/tbody/tr[5]/td'); + artists := XPathString('//table[@class="attr"]/tbody/tr[6]/td'); + genres := ''; for v in XPath('//table[@class="attr"]/tbody/tr[7]/td/a') do - AddCommaString(genres,v.toString); - summary:=XPathString('//p[@class="summary"]'); - s:=XPathString('//table[@class="attr"]/tbody/tr[9]/td'); - if s<>'' then begin - s:=LowerCase(s); - if Pos('ongoing',s)>0 then - status:='1' - else if Pos('completed',s)>0 then - status:='0'; + AddCommaString(genres, v.toString); + summary := XPathString('//p[@class="summary"]'); + s := XPathString('//table[@class="attr"]/tbody/tr[9]/td'); + if s <> '' then begin + s := LowerCase(s); + if Pos('ongoing', s) > 0 then + status := '1' + else if Pos('completed', s) > 0 then + status := '0'; end; for v in XPath('//ul[@class="chapter"]/li/span/a') do begin - s:=v.toNode.getAttribute('href'); - if RightStr(s,2)='/1' then - SetLength(s,Length(s)-2); + s := v.toNode.getAttribute('href'); + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 2); chapterLinks.Add(s); chapterName.Add(v.toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -106,13 +106,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var v: IXQValue; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; with TXQueryEngineHTML.Create(Document) do try for v in XPath('//section[@id="viewer"]/div[@class="canvas"]/a[@class="img-link"]/img') do @@ -128,13 +128,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='MangaBackup'; - RootURL:='http://mangabackup.com'; - SortedList:=True; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Website := 'MangaBackup'; + RootURL := 'http://mangabackup.com'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; end; end; diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 7c74bb43c..e9a2ae84a 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -5,14 +5,14 @@ interface uses - Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, XQueryEngineHTML, synautil, RegExpr; implementation const - dirurl='/manga/new'; - perpage=20; + dirurl = '/manga/new'; + perpage = 20; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -22,14 +22,14 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - s:=XPathString('//*[@id="pagination"]/a[last()]/@href'); - if s<>'' then Page:=StrToIntDef(SeparateRight(s,'offset='),1); - if Page>1 then - Page:=ceil(Page/perpage)+1; + s := XPathString('//*[@id="pagination"]/a[last()]/@href'); + if s <> '' then Page := StrToIntDef(SeparateRight(s, 'offset='), 1); + if Page > 1 then + Page := ceil(Page / perpage) + 1; finally Free; end; @@ -43,12 +43,12 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='?offset='+IntToStr(StrToInt(AURL)*perpage); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then s += '?offset=' + IntToStr(StrToInt(AURL) * perpage); if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//*[@class="content_row"]//a[@class="title_link"]') do begin @@ -67,30 +67,31 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink:=XPathString('//*[@id="manga_images"]//img[@id="cover"]/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=XPathString('//*[@class="name_row"]/h1'); - authors:=XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Автор")]/td[2]'); - genres:=XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тип")]/td[2]'); - AddCommaString(genres,XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тэги")]/td[2]')); - s:=XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Загружено")]/td[2]'); - if s<>'' then begin - if Pos('продолжается',s)>0 then status:='1' - else status:='0'; + coverLink := XPathString('//*[@id="manga_images"]//img[@id="cover"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//*[@class="name_row"]/h1'); + authors := XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Автор")]/td[2]'); + genres := XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тип")]/td[2]'); + AddCommaString(genres, XPathString( + '//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тэги")]/td[2]')); + s := XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Загружено")]/td[2]'); + if s <> '' then begin + if Pos('продолжается', s) > 0 then status := '1' + else status := '0'; end; - summary:=XPathString('//*[@id="description"]/text()'); + summary := XPathString('//*[@id="description"]/text()'); for v in XPath('//table[@class="table_cha"]//tr/td/*[@class="manga"]/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -105,27 +106,27 @@ function GetPageNumber(const DownloadThread: TDownloadThread; i, j: Integer; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - Source:=TStringList.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + Source := TStringList.Create; try Source.LoadFromStream(Document); - if Source.Count>0 then - for i:=0 to Source.Count-1 do - if Pos('"fullimg":',Source[i])>0 then begin - s:=SeparateRight(Source[i],':'); - s:=TrimChar(s,['[',']',',']); - PageLinks.CommaText:=s; - if PageLinks.Count>0 then + if Source.Count > 0 then + for i := 0 to Source.Count - 1 do + if Pos('"fullimg":', Source[i]) > 0 then begin + s := SeparateRight(Source[i], ':'); + s := TrimChar(s, ['[', ']', ',']); + PageLinks.CommaText := s; + if PageLinks.Count > 0 then with TRegExpr.Create('(?i)//im(\d*\.)') do try - for j:=0 to PageLinks.Count-1 do - PageLinks[j]:=Replace(PageLinks[j],'//img$1',True); + for j := 0 to PageLinks.Count - 1 do + PageLinks[j] := Replace(PageLinks[j], '//img$1', True); finally Free; end; @@ -142,13 +143,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='MangaChanRU'; - RootURL:='http://mangachan.ru'; - SortedList:=True; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Website := 'MangaChanRU'; + RootURL := 'http://mangachan.ru'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; end; end; diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 4fc9f62c7..85ca5665e 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/directory'; + dirurl = '/directory'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -21,12 +21,12 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - Page:=query.XPath('//select/option').Count; + Page := query.XPath('//select/option').Count; finally query.Free; end; @@ -41,13 +41,13 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='/'+IncStr(AURL)+'.html'; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then s += '/' + IncStr(AURL) + '.html'; if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//div[@class="cover-info"]/p[@class="title"]/a') do begin @@ -68,37 +68,37 @@ function GetInfo(const MangaInfo: TMangaInformation; s: String; i: Integer; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//img[@class="detail-cover"]/@src'); - if title=''then title:=query.XPathString('//div[@class="manga-detail"]/h1'); + coverLink := query.XPathString('//img[@class="detail-cover"]/@src'); + if title = '' then title := query.XPathString('//div[@class="manga-detail"]/h1'); for v in query.XPath('//div[@class="manga-detail"]//p') do begin - s:=v.toString; - if Pos('Author(s):',s)>0 then authors:=SeparateRight(s,':') else - if Pos('Artist(s):',s)>0 then artists:=SeparateRight(s,':') else - if Pos('Genre(s):',s)>0 then genres:=SeparateRight(s,':') else - if Pos('Status:',s)>0 then begin - s:=LowerCase(s); - if Pos('ongoing',s)>0 then status:='1' else status:='0'; + s := v.toString; + if Pos('Author(s):', s) > 0 then authors := SeparateRight(s, ':') else + if Pos('Artist(s):', s) > 0 then artists := SeparateRight(s, ':') else + if Pos('Genre(s):', s) > 0 then genres := SeparateRight(s, ':') else + if Pos('Status:', s) > 0 then begin + s := LowerCase(s); + if Pos('ongoing', s) > 0 then status := '1' else status := '0'; end; end; - summary:=query.XPathString('//p[@id="show"]/text()'); + summary := query.XPathString('//p[@id="show"]/text()'); - a:=query.XPath('//ul[@class="detail-chlist"]/li/a/@href'); - v:=query.XPath('//ul[@class="detail-chlist"]/li/a/span[1]'); - t:=query.XPath('//ul[@class="detail-chlist"]/li/span[@class="vol"]'); - if (a.Count>0) and (a.Count=v.Count) and (a.Count=t.Count) then - for i:=1 to a.Count do begin + a := query.XPath('//ul[@class="detail-chlist"]/li/a/@href'); + v := query.XPath('//ul[@class="detail-chlist"]/li/a/span[1]'); + t := query.XPath('//ul[@class="detail-chlist"]/li/span[@class="vol"]'); + if (a.Count > 0) and (a.Count = v.Count) and (a.Count = t.Count) then + for i := 1 to a.Count do begin chapterLinks.Add(a.get(i).toString); - chapterName.Add(v.get(i).toString+' '+t.get(i).toString); + chapterName.Add(v.get(i).toString + ' ' + t.get(i).toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally query.Free; end; @@ -111,17 +111,17 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var query: TXQueryEngineHTML; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('//div[@class="mangaread-pagenav"]/select/option').Count; + PageNumber := query.XPath('//div[@class="mangaread-pagenav"]/select/option').Count; finally query.Free; end; @@ -135,17 +135,17 @@ function GetImageURL(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=RemoveURLDelim(AURL); - if DownloadThread.workCounter>0 then s+='/'+IncStr(DownloadThread.workCounter)+'.html'; - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := RemoveURLDelim(AURL); + if DownloadThread.workCounter > 0 then s += '/' + IncStr(DownloadThread.workCounter) + '.html'; + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter]:=query.XPathString('//section[@id="viewer"]//img/@src'); + PageLinks[DownloadThread.workCounter] := query.XPathString('//section[@id="viewer"]//img/@src'); finally query.Free; end; @@ -157,13 +157,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='MangaKoi'; - RootURL:='http://www.mangakoi.com'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; + Website := 'MangaKoi'; + RootURL := 'http://www.mangakoi.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; end; diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index 3a366722b..1ae123ce0 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/series.html'; + dirurl = '/series.html'; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; @@ -20,11 +20,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//table[@id="page-list"]//tr/td/p/a') do begin @@ -43,15 +43,15 @@ function GetInfo(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - if title=''then title:=query.XPathString('//div[@id="content-main"]/h1'); + if title = '' then title := query.XPathString('//div[@id="content-main"]/h1'); for v in query.XPath('//table[@class="ch-table"]/tbody/tr/td/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); @@ -68,17 +68,17 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var query: TXQueryEngineHTML; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('//select[@id="id_page"]/option').Count; + PageNumber := query.XPath('//select[@id="id_page"]/option').Count; finally query.Free; end; @@ -92,18 +92,19 @@ function GetImageURL(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=AURL; - s:=ReplaceRegExpr('\.html?$',s,'',False); - s+='-page-'+IncStr(DownloadThread.workCounter)+'.html'; - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := AURL; + s := ReplaceRegExpr('\.html?$', s, '', False); + s += '-page-' + IncStr(DownloadThread.workCounter) + '.html'; + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter]:=query.XPathString('//img[@class="manga-page center-block"]/@src'); + PageLinks[DownloadThread.workCounter] := + query.XPathString('//img[@class="manga-page center-block"]/@src'); finally query.Free; end; @@ -115,13 +116,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='MangaStreamTo'; - RootURL:='http://www.mangastream.to'; - InformationAvailable:=False; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; + Website := 'MangaStreamTo'; + RootURL := 'http://www.mangastream.to'; + InformationAvailable := False; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; end; diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index eebf20fe5..c8c610939 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -139,12 +139,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.manager.container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + AURL; if DownloadThread.workCounter > PageContainerLinks.Count then Exit; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, PageContainerLinks[DownloadThread.workCounter])) then begin + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, + PageContainerLinks[DownloadThread.workCounter])) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@class="chapter-content"]//img/@src'); + PageLinks[DownloadThread.workCounter] := + query.XPathString('//div[@class="chapter-content"]//img/@src'); finally query.Free; end; diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index 32d043fb9..fdf8c5eaa 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -5,14 +5,14 @@ interface uses - Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, XQueryEngineHTML, synautil; implementation const - dirurl='/list?sortType=created'; - perpage=70; + dirurl = '/list?sortType=created'; + perpage = 70; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -22,14 +22,14 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - s:=XPathString('//*[@class="pagination"]/a[@class="step"][last()]/@href'); - if s<>'' then Page:=StrToIntDef(GetBetween('offset=','&',s),1); - if Page>1 then - Page:=ceil(Page/perpage)+1; + s := XPathString('//*[@class="pagination"]/a[@class="step"][last()]/@href'); + if s <> '' then Page := StrToIntDef(GetBetween('offset=', '&', s), 1); + if Page > 1 then + Page := ceil(Page / perpage) + 1; finally Free; end; @@ -43,12 +43,12 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='&offset='+IntToStr(StrToInt(AURL)*perpage)+'&max='+IntToStr(perpage); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then s += '&offset=' + IntToStr(StrToInt(AURL) * perpage) + '&max=' + IntToStr(perpage); if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//*[@class="tiles row"]/div/div[@class="desc"]/h3/a') do begin @@ -67,35 +67,37 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; rname, s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink:=XPathString('//*[@class="picture-fotorama"]/img/@src'); - rname:=XPathString('//h1[@class="names"]/span[@class="name"]'); - if title=''then title:=XPathString('//h1[@class="names"]/span[@class="eng-name"]'); - if title=''then title:=rname; - authors:=Trim(SeparateRight(XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Автор")]'),':')); - genres:=Trim(SeparateRight(XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Категория")]'),':')); + coverLink := XPathString('//*[@class="picture-fotorama"]/img/@src'); + rname := XPathString('//h1[@class="names"]/span[@class="name"]'); + if title = '' then title := XPathString('//h1[@class="names"]/span[@class="eng-name"]'); + if title = '' then title := rname; + authors := Trim(SeparateRight( + XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Автор")]'), ':')); + genres := Trim(SeparateRight( + XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Категория")]'), ':')); for v in XPath('//p[@class="elementList"]/span[starts-with(@class,"elem_genre")]') do - AddCommaString(genres,v.toString); - s:=XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Перевод")]'); - if s<>'' then begin - if Pos('продолжается',s)>0 then status:='1' - else status:='0'; + AddCommaString(genres, v.toString); + s := XPathString('//*[starts-with(@class,"subject-meta")]/*[starts-with(.,"Перевод")]'); + if s <> '' then begin + if Pos('продолжается', s) > 0 then status := '1' + else status := '0'; end; - summary:=XPathString('//*[@class="manga-description"]'); + summary := XPathString('//*[@class="manga-description"]'); for v in XPath('//table[@class="table table-hover"]/tbody/tr/td/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - s:=CleanString(v.toString); - if OptionRemoveMangaNameFromChapter and (rname<>'') then - if Pos(rname,LowerCase(s))=1 then s:=Trim(StringReplace(s,rname,'',[rfIgnoreCase])); + s := CleanString(v.toString); + if OptionRemoveMangaNameFromChapter and (rname <> '') then + if Pos(rname, LowerCase(s)) = 1 then s := Trim(StringReplace(s, rname, '', [rfIgnoreCase])); chapterName.Add(s); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -110,37 +112,37 @@ function GetPageNumber(const DownloadThread: TDownloadThread; i, j, x: Integer; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - s:=AURL; - if Pos('mature=1',LowerCase(s))=0 then s+='?mature=1'; - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - Source:=TStringList.Create; + s := AURL; + if Pos('mature=1', LowerCase(s)) = 0 then s += '?mature=1'; + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + Source := TStringList.Create; try Source.LoadFromStream(Document); - if Source.Count>0 then begin - s:=''; - for i:=0 to Source.Count-1 do - if Pos('rm_h.init(',Source[i])>0 then begin - s:=Trim(Source[i]); + if Source.Count > 0 then begin + s := ''; + for i := 0 to Source.Count - 1 do + if Pos('rm_h.init(', Source[i]) > 0 then begin + s := Trim(Source[i]); Break; end; - if s<>'' then begin - s:=GetBetween('[[',']]',Source[i]); - s:=StringReplace(s,'[','',[rfReplaceAll]); - s:=StringReplace(s,']','',[rfReplaceAll]); - s:=StringReplace(s,'"','',[rfReplaceAll]); - s:=StringReplace(s,'''','',[rfReplaceAll]); - Source.CommaText:=s; - if (Source.Count>0) and (frac(Source.Count/5)=0) then begin - j:=Source.Count div 5; - for i:=0 to j-1 do begin - x:=i*5; - PageLinks.Add(Source[x+1]+Source[x]+Source[x+2]); + if s <> '' then begin + s := GetBetween('[[', ']]', Source[i]); + s := StringReplace(s, '[', '', [rfReplaceAll]); + s := StringReplace(s, ']', '', [rfReplaceAll]); + s := StringReplace(s, '"', '', [rfReplaceAll]); + s := StringReplace(s, '''', '', [rfReplaceAll]); + Source.CommaText := s; + if (Source.Count > 0) and (frac(Source.Count / 5) = 0) then begin + j := Source.Count div 5; + for i := 0 to j - 1 do begin + x := i * 5; + PageLinks.Add(Source[x + 1] + Source[x] + Source[x + 2]); end; end; end; @@ -154,23 +156,23 @@ function GetPageNumber(const DownloadThread: TDownloadThread; procedure RegisterModule; - function AddWebsiteModule(AWebsite,ARootURL:String):TModuleContainer; + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - Result:=AddModule; + Result := AddModule; with Result do begin - Website:=AWebsite; - RootURL:=ARootURL; - SortedList:=True; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; end; end; begin - AddWebsiteModule('MintMangaRU','http://mintmanga.com'); - AddWebsiteModule('ReadMangaRU','http://readmanga.me'); + AddWebsiteModule('MintMangaRU', 'http://mintmanga.com'); + AddWebsiteModule('ReadMangaRU', 'http://readmanga.me'); end; initialization diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 88bcc5ac8..1f1590132 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/directory/'; + dirurl = '/directory/'; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; @@ -20,11 +20,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//section[@class="cols"]//div[@class="col-cnt"]/ul/li/a') do begin @@ -44,29 +44,29 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//section[@class="post"]/img/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=query.XPathString('//div[@class="post-cnt"]/h2'); + coverLink := query.XPathString('//section[@class="post"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := query.XPathString('//div[@class="post-cnt"]/h2'); for v in query.XPath('(//div[@class="post-cnt"])[1]/ul/li') do begin - s:=v.toString; - if Pos('Author(s):',s)=1 then authors:=SeparateRight(s,':') else - if Pos('Artist(s):',s)=1 then artists:=SeparateRight(s,':') else - if Pos('Genre:',s)=1 then genres:=SeparateRight(s,':') else - if Pos('Sinopsis:',s)=1 then summary:=SeparateRight(s,':'); + s := v.toString; + if Pos('Author(s):', s) = 1 then authors := SeparateRight(s, ':') else + if Pos('Artist(s):', s) = 1 then artists := SeparateRight(s, ':') else + if Pos('Genre:', s) = 1 then genres := SeparateRight(s, ':') else + if Pos('Sinopsis:', s) = 1 then summary := SeparateRight(s, ':'); end; for v in query.XPath('(//div[@class="post-cnt"])[2]/ul/li/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(query.XPathString('text()',v.toNode)); + chapterName.Add(query.XPathString('text()', v.toNode)); end; - InvertStrings([chapterLinks,chapterName]) + InvertStrings([chapterLinks, chapterName]) finally query.Free; end; @@ -79,17 +79,17 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var query: TXQueryEngineHTML; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('//select[@name="page"]/option').Count; + PageNumber := query.XPath('//select[@name="page"]/option').Count; finally query.Free; end; @@ -103,20 +103,20 @@ function GetImageURL(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s, b: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=RemoveURLDelim(AURL); - if DownloadThread.workCounter>0 then s+='/'+IncStr(DownloadThread.workCounter); - if GET(FillHost(Module.RootURL,s)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := RemoveURLDelim(AURL); + if DownloadThread.workCounter > 0 then s += '/' + IncStr(DownloadThread.workCounter); + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - b:=query.XPathString('//base/@href'); - if b='' then b:=Module.RootURL; - s:=query.XPathString('//img[@class="picture"]/@src'); - if s<>'' then PageLinks[DownloadThread.workCounter]:=MaybeFillHost(b,s); + b := query.XPathString('//base/@href'); + if b = '' then b := Module.RootURL; + s := query.XPathString('//img[@class="picture"]/@src'); + if s <> '' then PageLinks[DownloadThread.workCounter] := MaybeFillHost(b, s); finally query.Free; end; @@ -128,12 +128,12 @@ procedure RegisterModule; begin with AddModule do begin - Website:='PecintaKomik'; - RootURL:='http://www.pecintakomik.com'; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; + Website := 'PecintaKomik'; + RootURL := 'http://www.pecintakomik.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; end; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 3d773d6ee..073f03b5c 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -17,11 +17,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+'/Manga/?order=text-version') then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/Manga/?order=text-version') then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//table//tr/td[2]/a') do begin @@ -40,52 +40,53 @@ function GetInfo(const MangaInfo: TMangaInformation; query: TXQueryEngineHTML; v: IXQValue; i: Integer; - s,cl,m: String; + s, cl, m: String; cu: Boolean; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - m:=RemoveHostFromURL(AURL); - m:=RemoveURLDelim(m); - cl:=''; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + m := RemoveHostFromURL(AURL); + m := RemoveURLDelim(m); + cl := ''; with TRegExpr.Create do try - Expression:='(.+)/.+/\d+?$'; - cu:=Exec(m); + Expression := '(.+)/.+/\d+?$'; + cu := Exec(m); if cu then begin - cl:=m; - m:=Replace(m,'$1',True); + cl := m; + m := Replace(m, '$1', True); end; finally Free; end; - m:=AppendURLDelim(m); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if cl<>'' then url:=FillHost(Module.RootURL,cl) - else url:=FillHost(Module.RootURL,m); - if GET(FillHost(Module.RootURL,m)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + m := AppendURLDelim(m); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if cl <> '' then url := FillHost(Module.RootURL, cl) + else url := FillHost(Module.RootURL, m); + if GET(FillHost(Module.RootURL, m)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//img[@class="series-cover"]/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=query.XPathString('//h1[@itemprop="name"]'); - v:=query.XPath('//div[@class="series_desc"]/*'); + coverLink := query.XPathString('//img[@class="series-cover"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := query.XPathString('//h1[@itemprop="name"]'); + v := query.XPath('//div[@class="series_desc"]/*'); if v.Count > 0 then begin - i:=0; - while i<v.Count-2 do begin - s:=v.get(i).toString; - if Pos('Categorize in:',s)=1 then genres:=v.get(i+1).toString else - if Pos('Author:',s)=1 then authors:=v.get(i+1).toString else - if Pos('Artist:',s)=1 then artists:=Trim(SeparateRight(v.get(i).toString,':')) else - if Pos('Status:',s)=1 then if Pos('ongoing',LowerCase(v.get(i).toString))>0 then status:='1' else status:='0'; + i := 0; + while i < v.Count - 2 do begin + s := v.get(i).toString; + if Pos('Categorize in:', s) = 1 then genres := v.get(i + 1).toString else + if Pos('Author:', s) = 1 then authors := v.get(i + 1).toString else + if Pos('Artist:', s) = 1 then artists := Trim(SeparateRight(v.get(i).toString, ':')) else + if Pos('Status:', s) = 1 then if Pos('ongoing', LowerCase(v.get(i).toString)) > 0 then + status := '1' else status := '0'; Inc(i); end; end; - summary:=query.XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); - if cu and (cl<>'') then - if GET(FillHost(Module.RootURL,cl)) then + summary := query.XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); + if cu and (cl <> '') then + if GET(FillHost(Module.RootURL, cl)) then begin query.ParseHTML(StreamToString(Document)); //selected chapter @@ -96,10 +97,10 @@ function GetInfo(const MangaInfo: TMangaInformation; //end; //all chapter for v in query.XPath('//select[@name="chapter"]/option') do begin - chapterLinks.Add(m+v.toNode.getAttribute('value')); + chapterLinks.Add(m + v.toNode.getAttribute('value')); chapterName.Add(v.toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); end; finally query.Free; @@ -114,35 +115,35 @@ function GetPageNumber(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin - s:=RemoveURLDelim(ChapterLinks[CurrentDownloadChapterPtr]); + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + s := RemoveURLDelim(ChapterLinks[CurrentDownloadChapterPtr]); with TRegExpr.Create do try - Expression:='(.+)/.+/\d+?$'; + Expression := '(.+)/.+/\d+?$'; if Exec(s) then begin - Expression:='/\d+$'; - s:=Replace(s,'',False); + Expression := '/\d+$'; + s := Replace(s, '', False); end; - ChapterLinks[CurrentDownloadChapterPtr]:=s; + ChapterLinks[CurrentDownloadChapterPtr] := s; finally Free; end; PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,s+'/1')) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + if GET(FillHost(Module.RootURL, s + '/1')) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageNumber:=query.XPath('//select[@name="page"]/option').Count; - if PageNumber>0 then begin - s:=MaybeFillHost(Module.RootURL,query.XPathString('//img[@id="picture"]/@src')); - if Pos('/raw-viewer.php?',LowerCase(s))>0 then begin - if LowerCase(RightStr(s,7))='&page=1' then begin - SetLength(s,Length(s)-1); - while PageLinks.Count<PageNumber do PageLinks.Add(s+IncStr(PageLinks.Count)); + PageNumber := query.XPath('//select[@name="page"]/option').Count; + if PageNumber > 0 then begin + s := MaybeFillHost(Module.RootURL, query.XPathString('//img[@id="picture"]/@src')); + if Pos('/raw-viewer.php?', LowerCase(s)) > 0 then begin + if LowerCase(RightStr(s, 7)) = '&page=1' then begin + SetLength(s, Length(s) - 1); + while PageLinks.Count < PageNumber do PageLinks.Add(s + IncStr(PageLinks.Count)); end; end; end; @@ -159,17 +160,17 @@ function GetImageURL(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - if GET(FillHost(Module.RootURL,AURL)+'/'+IncStr(DownloadThread.WorkCounter)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(DownloadThread.WorkCounter)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - s:=MaybeFillHost(Module.RootURL,query.XPathString('//img[@id="picture"]/@src')); - if s<>'' then - PageLinks[DownloadThread.workCounter]:=s; + s := MaybeFillHost(Module.RootURL, query.XPathString('//img[@id="picture"]/@src')); + if s <> '' then + PageLinks[DownloadThread.workCounter] := s; finally query.Free; end; @@ -180,12 +181,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; function BeforeDownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - Result:=False; + Result := False; if DownloadThread = nil then Exit; with DownloadThread.manager.container do - if CurrentDownloadChapterPtr<ChapterLinks.Count then begin - DownloadThread.FHTTP.Headers.Values['Referer']:=' '+FillHost(Module.RootURL,ChapterLinks[CurrentDownloadChapterPtr]); - Result:=True; + if CurrentDownloadChapterPtr < ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer'] := + ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + Result := True; end; end; @@ -193,15 +195,15 @@ procedure RegisterModule; begin with AddModule do begin - Website:='RawSenManga'; - RootURL:='http://raw.senmanga.com'; - MaxTaskLimit:=1; - MaxConnectionLimit:=4; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; - OnBeforeDownloadImage:=@BeforeDownloadImage; + Website := 'RawSenManga'; + RootURL := 'http://raw.senmanga.com'; + MaxTaskLimit := 1; + MaxConnectionLimit := 4; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + OnBeforeDownloadImage := @BeforeDownloadImage; end; end; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 3784555be..680490379 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -11,19 +11,19 @@ interface implementation const - dirurl='/series'; + dirurl = '/series'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin - Result:=NET_PROBLEM; - Page:=1; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl+'10000000') then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '10000000') then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - page:=StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'),1); + page := StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'), 1); finally Free; end; @@ -36,15 +36,15 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; var v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//table[@class="caps"]/tbody/tr/td[1]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('text()',v.toNode)); + ANames.Add(XPathString('text()', v.toNode)); end; finally Free; @@ -58,30 +58,30 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - url:=FillHost(Module.RootURL,AURL); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + url := FillHost(Module.RootURL, AURL); if GET(url) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink:=XPathString('//p[@class="cb"]/img/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=XPathString('//div[@id="b"]//h1/a'); - summary:=XPathString('//div[@id="b"]/div[2]/p[3]'); - genres:=XPathString('//div[@id="b"]/div[2]/p[4]'); - authors:=XPathString('//div[@id="b"]/div[2]/p[5]/a'); - if XPath('//table[@class="caps"]/tbody/tr').Count>0 then - if GET(AppendURLDelim(url)+'completa') then begin + coverLink := XPathString('//p[@class="cb"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@id="b"]//h1/a'); + summary := XPathString('//div[@id="b"]/div[2]/p[3]'); + genres := XPathString('//div[@id="b"]/div[2]/p[4]'); + authors := XPathString('//div[@id="b"]/div[2]/p[5]/a'); + if XPath('//table[@class="caps"]/tbody/tr').Count > 0 then + if GET(AppendURLDelim(url) + 'completa') then begin ParseHTML(Document); with TRegExpr.Create do try - Expression:='^.*/(\d+)/?$'; + Expression := '^.*/(\d+)/?$'; for v in XPath('//table[@class="caps"]/tbody/tr/td[@class="s"]/a') do begin - s:=v.toNode.getAttribute('href'); - if s<>'' then begin - s:=Replace(s,'/c/$1',True); + s := v.toNode.getAttribute('href'); + if s <> '' then begin + s := Replace(s, '/c/$1', True); chapterLinks.Add(s); chapterName.Add(v.toString); end; @@ -89,7 +89,7 @@ function GetInfo(const MangaInfo: TMangaInformation; finally Free; end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); end; finally Free; @@ -101,16 +101,16 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; with TXQueryEngineHTML.Create(Document) do try - PageNumber:=XPath('//table[1]/tbody//select/option').Count; + PageNumber := XPath('//table[1]/tbody//select/option').Count; finally Free; end; @@ -123,17 +123,17 @@ function GetImageURL(const DownloadThread: TDownloadThread; var s: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.manager.container,DownloadThread.FHTTP do begin - s:=FillHost(Module.RootURL,AURL); - if DownloadThread.workCounter>0 then - s:=s+'/'+IncStr(DownloadThread.workCounter); + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := FillHost(Module.RootURL, AURL); + if DownloadThread.workCounter > 0 then + s := s + '/' + IncStr(DownloadThread.workCounter); if GET(s) then begin - Result:=True; + Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter]:=XPathString('//div[@id="ab"]/a/img/@src'); + PageLinks[DownloadThread.workCounter] := XPathString('//div[@id="ab"]/a/img/@src'); finally Free; end; @@ -145,12 +145,12 @@ procedure RegisterModule; begin with AddModule do begin - Website:='SubManga'; - RootURL:='http://submanga.com'; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnGetImageURL:=@GetImageURL; + Website := 'SubManga'; + RootURL := 'http://submanga.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; end; end; diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index ace648b91..9f5e290db 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -11,19 +11,19 @@ interface implementation const - dirurl='/Browse/Index/1/'; + dirurl = '/Browse/Index/1/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin - Result:=NET_PROBLEM; - Page:=1; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl+'10000000') then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '10000000') then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - page:=StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'),1); + page := StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'), 1); finally Free; end; @@ -37,17 +37,17 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL; - if AURL<>'0' then s:=s+dirurl+IncStr(AURL); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL; + if AURL <> '0' then s := s + dirurl + IncStr(AURL); if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//div[@class="row row-no-padding"]//div[@class="overlay"]') do begin - ALinks.Add(XPathString('a/@href',v.toNode)); - ANames.Add(XPathString('div/div[@class="overlay-title"]',v.toNode)); + ALinks.Add(XPathString('a/@href', v.toNode)); + ANames.Add(XPathString('div/div[@class="overlay-title"]', v.toNode)); end; finally Free; @@ -58,20 +58,22 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - url:=FillHost(Module.RootURL,AURL); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + url := FillHost(Module.RootURL, AURL); if GET(url) then begin - Result:=NO_ERROR; + Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink:=XPathString('//img[@class="book-page-image img-responsive"]/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=XPathString('//div[@class="book-line"][starts-with(.,"Title")]/div[@class="book-data"]'); - artists:=XPathString('//div[@class="book-line"][starts-with(.,"Artist")]/div[@class="book-data"]'); - genres:=XPathStringAll('//div[@class="book-line"][starts-with(.,"Parody") or starts-with(.,"Characters") or starts-with(.,"Tags")]/div[@class="book-data"]/*'); - if title<>'' then begin + coverLink := XPathString('//img[@class="book-page-image img-responsive"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString( + '//div[@class="book-line"][starts-with(.,"Title")]/div[@class="book-data"]'); + artists := XPathString('//div[@class="book-line"][starts-with(.,"Artist")]/div[@class="book-data"]'); + genres := XPathStringAll( + '//div[@class="book-line"][starts-with(.,"Parody") or starts-with(.,"Characters") or starts-with(.,"Tags")]/div[@class="book-data"]/*'); + if title <> '' then begin chapterLinks.Add(url); chapterName.Add(title); end; @@ -89,32 +91,32 @@ function GetPageNumber(const DownloadThread: TDownloadThread; i, pgLast: Integer; thumbUrl: String; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - source:=TStringList.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + source := TStringList.Create; try source.LoadFromStream(Document); - pgLast:=0; - thumbUrl:=''; - if source.Count>0 then - for i:=0 to source.Count-1 do begin - if Pos('var pgLast',source[i])>0 then - pgLast:=StrToIntDef(GetValuesFromString(source[i],'='),0) - else if Pos('var thumbUrl',source[i])>0 then begin - thumbUrl:=GetValuesFromString(source[i],'='); + pgLast := 0; + thumbUrl := ''; + if source.Count > 0 then + for i := 0 to source.Count - 1 do begin + if Pos('var pgLast', source[i]) > 0 then + pgLast := StrToIntDef(GetValuesFromString(source[i], '='), 0) + else if Pos('var thumbUrl', source[i]) > 0 then begin + thumbUrl := GetValuesFromString(source[i], '='); Break; end; end; - if (pgLast>0) and (thumbUrl<>'') then begin - thumbUrl:=ReplaceRegExpr('(?i)/Thumb(/\d+/)[9]+',thumbUrl,'/Image$1',True); - thumbUrl:=AppendURLDelim(FillHost(Module.RootURL,thumbUrl)); - for i:=1 to pgLast do - PageLinks.Add(thumbUrl+IntToStr(i)); + if (pgLast > 0) and (thumbUrl <> '') then begin + thumbUrl := ReplaceRegExpr('(?i)/Thumb(/\d+/)[9]+', thumbUrl, '/Image$1', True); + thumbUrl := AppendURLDelim(FillHost(Module.RootURL, thumbUrl)); + for i := 1 to pgLast do + PageLinks.Add(thumbUrl + IntToStr(i)); end; finally source.Free; @@ -127,13 +129,13 @@ procedure RegisterModule; begin with AddModule do begin - Website:='Tsumino'; - RootURL:='http://www.tsumino.com'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - SortedList:=True; + Website := 'Tsumino'; + RootURL := 'http://www.tsumino.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + SortedList := True; end; end; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 277cbf19d..4a4dca034 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/mangas'; + dirurl = '/mangas'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -22,15 +22,15 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s:=query.XPathString('//*[@class="pagination"]/li[last()]/a/@href'); - if s<>'' then begin - s:=ReplaceRegExpr('^.*/(\d+)/?\*?$',s,'$1',True); - Page:=StrToIntDef(s,1); + s := query.XPathString('//*[@class="pagination"]/li[last()]/a/@href'); + if s <> '' then begin + s := ReplaceRegExpr('^.*/(\d+)/?\*?$', s, '$1', True); + Page := StrToIntDef(s, 1); end; finally query.Free; @@ -46,13 +46,13 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='/a-z/'+IncStr(AURL)+'/*'; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then s += '/a-z/' + IncStr(AURL) + '/*'; if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); for v in query.XPath('//div[@class="row"]/div/a[2]') do begin @@ -72,31 +72,31 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; s: String; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//img[@class="img-thumbnail"]/@src'); - if title=''then title:=query.XPathString('//div/h2'); + coverLink := query.XPathString('//img[@class="img-thumbnail"]/@src'); + if title = '' then title := query.XPathString('//div/h2'); for v in query.XPath('//h4') do begin - s:=v.toString; - if Pos('Gênero(s):',s)=1 then genres:=SeparateRight(s,':') else - if Pos('Autor:',s)=1 then authors:=SeparateRight(s,':') else - if Pos('Artista:',s)=1 then artists:=SeparateRight(s,':') else - if Pos('Status:',s)=1 then begin - if Pos('Ativo',s)>0 then status:='1' else status:='0'; + s := v.toString; + if Pos('Gênero(s):', s) = 1 then genres := SeparateRight(s, ':') else + if Pos('Autor:', s) = 1 then authors := SeparateRight(s, ':') else + if Pos('Artista:', s) = 1 then artists := SeparateRight(s, ':') else + if Pos('Status:', s) = 1 then begin + if Pos('Ativo', s) > 0 then status := '1' else status := '0'; end; end; - summary:=query.XPathString('//div/div[@class="panel-body"]'); + summary := query.XPathString('//div/div[@class="panel-body"]'); for v in query.XPath('//div[@class="row lancamento-linha"]/div[1]/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); finally query.Free; end; @@ -110,17 +110,18 @@ function GetPageNumber(const DownloadThread: TDownloadThread; query: TXQueryEngineHTML; v: IXQValue; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - for v in query.XPath('//div[@id="image"]/div/img[@class="real img-responsive"][@id!="imagem-forum"]/@data-lazy') do + for v in query.XPath( + '//div[@id="image"]/div/img[@class="real img-responsive"][@id!="imagem-forum"]/@data-lazy') do PageLinks.Add(v.toString); finally query.Free; @@ -133,12 +134,12 @@ procedure RegisterModule; begin with AddModule do begin - Website:='UnionMangas'; - RootURL:='http://unionmangas.com.br'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; + Website := 'UnionMangas'; + RootURL := 'http://unionmangas.com.br'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; end; end; diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index b675a9059..a343a52e1 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl='/en/genre'; + dirurl = '/en/genre'; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; @@ -19,15 +19,15 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; var v: IXQValue; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin - Result:=NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin + Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try for v in XPath('//ul[@class="card_lst"]/li/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('div/p[@class="subj"]',v.toNode)); + ANames.Add(XPathString('div/p[@class="subj"]', v.toNode)); end; finally Free; @@ -47,38 +47,38 @@ function GetInfo(const MangaInfo: TMangaInformation; begin for v in query.XPath('//ul[@id="_listUl"]/li/a') do begin MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); - MangaInfo.mangaInfo.chapterName.Add(query.XPathString('span[@class="subj"]/span',v.toNode)); + MangaInfo.mangaInfo.chapterName.Add(query.XPathString('span[@class="subj"]/span', v.toNode)); end; end; procedure getp; begin - p:=StrToIntDef(SeparateRight( - query.XPathString('//div[@class="detail_lst"]/div[@class="paginate"]/a[last()]/@href'),'&page='),1); + p := StrToIntDef(SeparateRight( + query.XPathString('//div[@class="detail_lst"]/div[@class="paginate"]/a[last()]/@href'), '&page='), 1); end; begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - url:=FillHost(Module.RootURL,AURL); + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin + url := FillHost(Module.RootURL, AURL); if GET(url) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create(Document); + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(Document); with query do try - coverLink:=XPathString('//div[@class="detail_header type_white"]/span[@class="thmb"]/img/@src'); - if coverLink<>'' then coverLink:=MaybeFillHost(Module.RootURL,coverLink); - if title=''then title:=XPathString('//div[@class="info"]/h1/text()'); - authors:=XPathString('//div[@class="info"]/a/text()'); - genres:=XPathString('//div[@class="info"]/h2'); - summary:=XPathString('//p[@class="summary"]'); + coverLink := XPathString('//div[@class="detail_header type_white"]/span[@class="thmb"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="info"]/h1/text()'); + authors := XPathString('//div[@class="info"]/a/text()'); + genres := XPathString('//div[@class="info"]/h2'); + summary := XPathString('//p[@class="summary"]'); getchapters; getp; - if p>1 then begin - i:=2; - while i<=p do begin - if GET(url+'&page='+IntToStr(i)) then begin + if p > 1 then begin + i := 2; + while i <= p do begin + if GET(url + '&page=' + IntToStr(i)) then begin ParseHTML(Document); getchapters; getp; @@ -86,9 +86,9 @@ function GetInfo(const MangaInfo: TMangaInformation; Inc(i); end; end; - InvertStrings([chapterLinks,chapterName]); + InvertStrings([chapterLinks, chapterName]); Reset; - Headers.Values['Referer']:=' '+url; + Headers.Values['Referer'] := ' ' + url; finally query.Free; end; @@ -101,13 +101,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var v: IXQValue; begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; with TXQueryEngineHTML.Create(Document) do try for v in XPath('//div[@id="_imageList"]/img[@class="_images"]/@data-url') do @@ -122,12 +122,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function BeforeDownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - Result:=False; + Result := False; if DownloadThread = nil then Exit; with DownloadThread.manager.container do - if CurrentDownloadChapterPtr<ChapterLinks.Count then begin - DownloadThread.FHTTP.Headers.Values['Referer']:=' '+FillHost(Module.RootURL,ChapterLinks[CurrentDownloadChapterPtr]); - Result:=True; + if CurrentDownloadChapterPtr < ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer'] := + ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + Result := True; end; end; @@ -135,12 +136,12 @@ procedure RegisterModule; begin with AddModule do begin - Website:='Webtoons'; - RootURL:='http://www.webtoons.com'; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - OnBeforeDownloadImage:=@BeforeDownloadImage; + Website := 'Webtoons'; + RootURL := 'http://www.webtoons.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; end; end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8bb735efb..e4a65ed54 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -14,7 +14,7 @@ interface uses {$ifdef windows} - windows, + Windows, {$else} UTF8Process, {$endif} @@ -24,14 +24,14 @@ interface synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, xquery, xquery_json, Imaging, ImagingExtras, SimpleException, SimpleLogger; -Type +type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); const FMD_REVISION = '$WCREV$'; FMD_INSTANCE = '_FreeMangaDownloaderInstance_'; - FMD_TARGETOS = {$i %FPCTARGETOS%}; + FMD_TARGETOS = {$i %FPCTARGETOS%}; FMD_TARGETCPU = {$i %FPCTARGETCPU%}; JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -72,7 +72,7 @@ interface Symbols: array [0..10] of Char = ('\', '/', ':', '*', '?', '"', '<', '>', '|', #9, ';'); - StringFilterChar: array [0..35] of array [0..1] of string = ( + StringFilterChar: array [0..35] of array [0..1] of String = ( (#10, '\n'), (#13, '\r'), (''', ''''), @@ -111,7 +111,7 @@ interface ('²', '²') ); - HTMLEntitiesChar: array [0..82] of array [0..1] of string = ( + HTMLEntitiesChar: array [0..82] of array [0..1] of String = ( ('«', '«'), ('°', '°'), ('À', 'À'), @@ -270,7 +270,6 @@ interface OURMANGA_ID = 2; MANGA24H_ID = 3; VNSHARING_ID = 4; - FAKKU_ID = 5; TRUYEN18_ID = 6; MANGAPARK_ID = 7; @@ -340,7 +339,7 @@ interface READMANGATODAY_ID = 71; DYNASTYSCANS_ID = 72; - WebsiteRoots: array [0..72] of array [0..1] of string = ( + WebsiteRoots: array [0..72] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -504,7 +503,7 @@ interface MANGAREADER_POR_BROWSER = '/AJAX/listaMangas/all'; NINEMANGA_BROWSER = - '/search/?name_sel=contain&wd=&author_sel=contain&author=&artist_sel=contain&artist=&category_id=&out_category_id=&completed_series=either'; + '/search/?name_sel=contain&wd=&author_sel=contain&author=&artist_sel=contain&artist=&category_id=&out_category_id=&completed_series=either'; JAPANSHIN_BROWSER = '/lectureenligne/reader/list/'; JAPSCAN_BROWSER = '/mangas/'; @@ -527,7 +526,7 @@ interface MANGAHOST_BROWSER = '/mangas'; - DYNASTYSCANS_BROWSER: array [0..3] of string = ( + DYNASTYSCANS_BROWSER: array [0..3] of String = ( '/anthologies', '/doujins', '/issues', @@ -540,23 +539,23 @@ interface DATA_FOLDER: String = 'data' + PathDelim; {$IFDEF WINDOWS} - DEFAULT_PATH : string = '\downloads'; + DEFAULT_PATH: String = '\downloads'; {$ELSE} - DEFAULT_PATH: string = '/downloads'; + DEFAULT_PATH: String = '/downloads'; {$ENDIF} // Sites var BROWSER_INVERT: Boolean = False; - FAKKU_BROWSER: string = '/manga/newest'; + FAKKU_BROWSER: String = '/manga/newest'; - MANGAEDEN_BROWSER: string = '/en-directory/'; + MANGAEDEN_BROWSER: String = '/en-directory/'; - PERVEDEN_BROWSER: string = '/en-directory/'; + PERVEDEN_BROWSER: String = '/en-directory/'; MANGALIB_PL_COOKIES: String; - DBDownloadURL: string; + DBDownloadURL: String; //------------------------------------------ Genre: array [0..37] of String; @@ -605,20 +604,20 @@ interface OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; OptionMangaFoxRemoveWatermark: Boolean = True; OptionMangaFoxSaveAsPNG: Boolean = False; - OptionEHentaiDownloadOriginalImage: Boolean=False; + OptionEHentaiDownloadOriginalImage: Boolean = False; OptionHTTPUseGzip: Boolean = True; OptionRemoveMangaNameFromChapter: Boolean = False; type - TArrayOfString = array of string; + TArrayOfString = array of String; TCheckStyleType = (CS_DIRECTORY_COUNT, CS_DIRECTORY_PAGE, - CS_DIRECTORY_PAGE_2, CS_INFO); - TFlagType = (CS_GETPAGENUMBER, CS_GETPAGELINK, CS_DOWNLOAD); - TDownloadStatusType = (STATUS_STOP, STATUS_WAIT, STATUS_PREPARE, - STATUS_DOWNLOAD, STATUS_FINISH, STATUS_COMPRESS, - STATUS_PROBLEM, STATUS_FAILED); + CS_DIRECTORY_PAGE_2, CS_INFO); + TFlagType = (CS_GETPAGENUMBER, CS_GETPAGELINK, CS_DOWNLOAD); + TDownloadStatusType = (STATUS_STOP, STATUS_WAIT, STATUS_PREPARE, + STATUS_DOWNLOAD, STATUS_FINISH, STATUS_COMPRESS, + STATUS_PROBLEM, STATUS_FAILED); TDownloadStatusTypes = set of TDownloadStatusType; TFavoriteStatusType = (STATUS_IDLE, STATUS_CHECK, STATUS_CHECKING, STATUS_CHECKED); @@ -630,7 +629,7 @@ interface TMangaListItem = record Text: String; - JDN: LongInt; + JDN: Longint; end; PSingleItem = ^TSingleItem; @@ -643,7 +642,7 @@ TSingleItem = record TChapterStateItem = record Title, - Link : String; + Link: String; Downloaded: Boolean; end; @@ -713,14 +712,14 @@ TDownloadPageThread = class(TThread) TParseHTML = class private - FRaw: string; - procedure FoundTag(NoCaseTag, ActualTag: string); - procedure FoundText(Text: string); + FRaw: String; + procedure FoundTag(NoCaseTag, ActualTag: String); + procedure FoundText(Text: String); public Output: TStrings; - constructor Create(const Raw: string = ''); - function Exec(const Raw: string = ''): string; - property Raw: string read FRaw write FRaw; + constructor Create(const Raw: String = ''); + function Exec(const Raw: String = ''): String; + property Raw: String read FRaw write FRaw; end; { THTTPSendThread } @@ -766,8 +765,8 @@ function GetMangaSiteRoot(const MangaID: Cardinal): String; overload; function GetMangaDatabaseURL(const AWebsite: String): String; function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; -function SitesWithSortedList(const website:String): Boolean; -function SitesWithoutFavorites(const website:String): Boolean; +function SitesWithSortedList(const website: String): Boolean; +function SitesWithoutFavorites(const website: String): Boolean; // Return true if the website doesn't contain manga information function SitesWithoutInformation(const website: String): Boolean; function SitesWithoutReferer(const website: String): Boolean; @@ -785,14 +784,14 @@ function MaybeFillHost(const Host, URL: String): String; // modify url function GetHostURL(URL: String): String; function RemoveHostFromURL(URL: String): String; -procedure RemoveHostFromURLs(Const URLs: TStringList); -procedure RemoveHostFromURLsPair(Const URLs, Names : TStringList); +procedure RemoveHostFromURLs(const URLs: TStringList); +procedure RemoveHostFromURLsPair(const URLs, Names: TStringList); //JSON procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); //HTML -procedure ParseHTML(const aRaw: string; aOutput: TStrings); +procedure ParseHTML(const aRaw: String; aOutput: TStrings); // XPath / CSS Selector procedure ParseHTMLTree(var tp: TTreeParser; const S: String); @@ -806,27 +805,27 @@ function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; // encode/decode -function Base64Encode(const s: string): string; -function Base64Decode(const s: string): string; +function Base64Encode(const s: String): String; +function Base64Decode(const s: String): String; // StringUtils -function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; -function StreamToString(const Stream: TStream): string; inline; -function GetRightValue(const name, s: string): string; -function QuotedStrd(const S: string): string; overload; inline; -function QuotedStrd(const S: Integer): string; overload; inline; -function BracketStr(const S: string): string; inline; +function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; +function StreamToString(const Stream: TStream): String; inline; +function GetRightValue(const Name, s: String): String; +function QuotedStrd(const S: String): String; overload; inline; +function QuotedStrd(const S: Integer): String; overload; inline; +function BracketStr(const S: String): String; inline; function RandomString(SLength: Integer; ONumber: Boolean = False; - OSymbol: Boolean = False; OSpace: Boolean = False): string; + OSymbol: Boolean = False; OSpace: Boolean = False): String; function GetValuesFromString(Str: String; Sepr: Char): String; -procedure InvertStrings(Const St: TStringList); overload; +procedure InvertStrings(const St: TStringList); overload; procedure InvertStrings(const Sts: array of TStringList); overload; procedure TrimStrings(TheStrings: TStrings); -procedure RemoveDuplicateStrings(Strs: Array of TStringList; RemIndex: Cardinal = 0); -procedure CleanHTMLComments(Const Str: TStringList); +procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Cardinal = 0); +procedure CleanHTMLComments(const Str: TStringList); function FixHTMLTagQuote(const s: String): String; -function FixCommonBrokenHTML(const s:String): string; +function FixCommonBrokenHTML(const s: String): String; function URLDecode(const s: String): String; function HTMLDecode(const AStr: String): String; @@ -857,7 +856,7 @@ function TrimLeftChar(const Source: String; const Chars: TSysCharSet): String; function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): String; -procedure AddCommaString(var Dest: string; S: string); +procedure AddCommaString(var Dest: String; S: String); function StringOfString(c: String; l: Integer): String; function IncStr(const S: String; N: Integer = 1): String; overload; @@ -913,7 +912,8 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: Stri function SaveImage(const AHTTP: THTTPSend; URL: String; const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; + const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; + overload; inline; procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); @@ -921,10 +921,10 @@ procedure QuickSortData(var merge: TStringList); procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteList); -function GetCurrentJDN: longint; -function DateToJDN(const year, month, day: word): longint; overload; -function DateToJDN(const date: TDate): longint; overload; -function JDNToDate(const JDN: longint): TDate; +function GetCurrentJDN: Longint; +function DateToJDN(const year, month, day: Word): Longint; overload; +function DateToJDN(const date: TDate): Longint; overload; +function JDNToDate(const JDN: Longint): TDate; {function ConvertInt32ToStr(const aValue: Cardinal) : String; function ConvertStrToInt32(const aStr : String): Cardinal;} @@ -945,34 +945,34 @@ implementation {$IFDEF WINDOWS} // thanks Leledumbo for the code const - SE_CREATE_TOKEN_NAME = 'SeCreateTokenPrivilege'; - SE_ASSIGNPRIMARYTOKEN_NAME = 'SeAssignPrimaryTokenPrivilege'; - SE_LOCK_MEMORY_NAME = 'SeLockMemoryPrivilege'; - SE_INCREASE_QUOTA_NAME = 'SeIncreaseQuotaPrivilege'; - SE_UNSOLICITED_INPUT_NAME = 'SeUnsolicitedInputPrivilege'; - SE_MACHINE_ACCOUNT_NAME = 'SeMachineAccountPrivilege'; - SE_TCB_NAME = 'SeTcbPrivilege'; - SE_SECURITY_NAME = 'SeSecurityPrivilege'; - SE_TAKE_OWNERSHIP_NAME = 'SeTakeOwnershipPrivilege'; - SE_LOAD_DRIVER_NAME = 'SeLoadDriverPrivilege'; - SE_SYSTEM_PROFILE_NAME = 'SeSystemProfilePrivilege'; - SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege'; + SE_CREATE_TOKEN_NAME = 'SeCreateTokenPrivilege'; + SE_ASSIGNPRIMARYTOKEN_NAME = 'SeAssignPrimaryTokenPrivilege'; + SE_LOCK_MEMORY_NAME = 'SeLockMemoryPrivilege'; + SE_INCREASE_QUOTA_NAME = 'SeIncreaseQuotaPrivilege'; + SE_UNSOLICITED_INPUT_NAME = 'SeUnsolicitedInputPrivilege'; + SE_MACHINE_ACCOUNT_NAME = 'SeMachineAccountPrivilege'; + SE_TCB_NAME = 'SeTcbPrivilege'; + SE_SECURITY_NAME = 'SeSecurityPrivilege'; + SE_TAKE_OWNERSHIP_NAME = 'SeTakeOwnershipPrivilege'; + SE_LOAD_DRIVER_NAME = 'SeLoadDriverPrivilege'; + SE_SYSTEM_PROFILE_NAME = 'SeSystemProfilePrivilege'; + SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege'; SE_PROF_SINGLE_PROCESS_NAME = 'SeProfileSingleProcessPrivilege'; - SE_INC_BASE_PRIORITY_NAME = 'SeIncreaseBasePriorityPrivilege'; - SE_CREATE_PAGEFILE_NAME = 'SeCreatePagefilePrivilege'; - SE_CREATE_PERMANENT_NAME = 'SeCreatePermanentPrivilege'; - SE_BACKUP_NAME = 'SeBackupPrivilege'; - SE_RESTORE_NAME = 'SeRestorePrivilege'; - SE_SHUTDOWN_NAME = 'SeShutdownPrivilege'; - SE_DEBUG_NAME = 'SeDebugPrivilege'; - SE_AUDIT_NAME = 'SeAuditPrivilege'; - SE_SYSTEM_ENVIRONMENT_NAME = 'SeSystemEnvironmentPrivilege'; - SE_CHANGE_NOTIFY_NAME = 'SeChangeNotifyPrivilege'; - SE_REMOTE_SHUTDOWN_NAME = 'SeRemoteShutdownPrivilege'; - SE_UNDOCK_NAME = 'SeUndockPrivilege'; - SE_SYNC_AGENT_NAME = 'SeSyncAgentPrivilege'; - SE_ENABLE_DELEGATION_NAME = 'SeEnableDelegationPrivilege'; - SE_MANAGE_VOLUME_NAME = 'SeManageVolumePrivilege'; + SE_INC_BASE_PRIORITY_NAME = 'SeIncreaseBasePriorityPrivilege'; + SE_CREATE_PAGEFILE_NAME = 'SeCreatePagefilePrivilege'; + SE_CREATE_PERMANENT_NAME = 'SeCreatePermanentPrivilege'; + SE_BACKUP_NAME = 'SeBackupPrivilege'; + SE_RESTORE_NAME = 'SeRestorePrivilege'; + SE_SHUTDOWN_NAME = 'SeShutdownPrivilege'; + SE_DEBUG_NAME = 'SeDebugPrivilege'; + SE_AUDIT_NAME = 'SeAuditPrivilege'; + SE_SYSTEM_ENVIRONMENT_NAME = 'SeSystemEnvironmentPrivilege'; + SE_CHANGE_NOTIFY_NAME = 'SeChangeNotifyPrivilege'; + SE_REMOTE_SHUTDOWN_NAME = 'SeRemoteShutdownPrivilege'; + SE_UNDOCK_NAME = 'SeUndockPrivilege'; + SE_SYNC_AGENT_NAME = 'SeSyncAgentPrivilege'; + SE_ENABLE_DELEGATION_NAME = 'SeEnableDelegationPrivilege'; + SE_MANAGE_VOLUME_NAME = 'SeManageVolumePrivilege'; function SetSuspendState(hibernate, forcecritical, disablewakeevent: Boolean): Boolean; stdcall; external 'powrprof.dll' Name 'SetSuspendState'; @@ -1077,7 +1077,7 @@ function UnicodeRemove(const S: String): String; Result := S; for i := 1 to Length(Result) do begin - if (byte(Result[i]) < 31) or (byte(Result[i]) > 127) then + if (Byte(Result[i]) < 31) or (Byte(Result[i]) > 127) then begin Delete(Result, i, 1); Insert('_', Result, i); @@ -1126,7 +1126,7 @@ function CorrectFilePath(const APath: String): String; procedure CheckPath(const S: String); var wS, lcS, lcS2: String; - i, j: word; + i, j: Word; begin wS := s; lcS2 := ''; @@ -1182,7 +1182,7 @@ function GetMangaSiteName(const ID: Cardinal): String; Result := WebsiteRoots[ID, 0]; end; -function GetMangaSiteRoot(const Website : String) : String; +function GetMangaSiteRoot(const Website: String): String; var i: Integer; begin @@ -1192,20 +1192,20 @@ function GetMangaSiteRoot(const Website : String) : String; Exit(WebsiteRoots[i, 1]); end; -function GetMangaSiteRoot(const MangaID : Cardinal) : String; +function GetMangaSiteRoot(const MangaID: Cardinal): String; begin Result := WebsiteRoots[MangaID, 1]; end; function GetMangaDatabaseURL(const AWebsite: String): String; begin - if DBDownloadURL='' then - DBDownloadURL:='https://bintray.com/artifact/download/riderkick/FMD/db/<website>.7z'; - Result:=DBDownloadURL; - if Pos('<website>',LowerCase(Result))>0 then - Result:=StringReplace(Result,'<website>',AWebsite,[rfIgnoreCase,rfReplaceAll]) + if DBDownloadURL = '' then + DBDownloadURL := 'https://bintray.com/artifact/download/riderkick/FMD/db/<website>.7z'; + Result := DBDownloadURL; + if Pos('<website>', LowerCase(Result)) > 0 then + Result := StringReplace(Result, '<website>', AWebsite, [rfIgnoreCase, rfReplaceAll]) else - Result:=Result+AWebsite; + Result := Result + AWebsite; end; function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; @@ -1221,7 +1221,7 @@ function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): end; end; -function SitesWithSortedList(const website : String) : Boolean; +function SitesWithSortedList(const website: String): Boolean; var i: Integer = -1; begin @@ -1255,7 +1255,7 @@ function SitesWithSortedList(const website : String) : Boolean; ]); end; -function SitesWithoutFavorites(const website : String) : Boolean; +function SitesWithoutFavorites(const website: String): Boolean; var i: Integer = -1; begin @@ -1300,10 +1300,10 @@ function SitesWithoutInformation(const website: String): Boolean; ]); end; -function SitesWithoutReferer(const website : String) : Boolean; +function SitesWithoutReferer(const website: String): Boolean; begin Result := False; - Result:= SitesMemberOf(website, [ + Result := SitesMemberOf(website, [ MEINMANGA_ID, IKOMIK_ID, PORNCOMIX_ID, @@ -1316,7 +1316,7 @@ function SitesWithoutReferer(const website : String) : Boolean; ]); end; -function SitesWithSingleChapter(const website : String) : Boolean; +function SitesWithSingleChapter(const website: String): Boolean; begin Result := False; Result := SitesMemberOf(website, [ @@ -1341,7 +1341,7 @@ function FillURLProtocol(const AProtocol, AURL: String): String; end; end; -function FillMangaSiteHost(const MangaID : Cardinal; URL : String) : String; +function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; begin Result := URL; if MangaID <= High(WebsiteRoots) then @@ -1357,7 +1357,7 @@ function FillMangaSiteHost(const Website, URL: String): String; function FillHost(const Host, URL: String): String; var - tu: string; + tu: String; begin Result := CleanURL(URL); if Host = '' then Exit; @@ -1374,7 +1374,7 @@ function FillHost(const Host, URL: String): String; function MaybeFillHost(const Host, URL: String): String; var - tu: string; + tu: String; begin Result := CleanURL(URL); if Host = '' then Exit; @@ -1395,12 +1395,12 @@ function MaybeFillHost(const Host, URL: String): String; function GetHostURL(URL: String): String; begin - Result:=URL; - if URL='' then Exit; - Result:=ReplaceRegExpr(REGEX_HOST,Result,'$1$2',True); + Result := URL; + if URL = '' then Exit; + Result := ReplaceRegExpr(REGEX_HOST, Result, '$1$2', True); end; -function RemoveHostFromURL(URL : String) : String; +function RemoveHostFromURL(URL: String): String; begin Result := ReplaceRegExpr(REGEX_HOST, URL, '$4', True); if Result = '' then @@ -1409,63 +1409,63 @@ function RemoveHostFromURL(URL : String) : String; Result := '/' + Result; end; -procedure RemoveHostFromURLs(const URLs : TStringList); +procedure RemoveHostFromURLs(const URLs: TStringList); var - i: Integer; - s: String; + i: Integer; + s: String; begin if URLs = nil then Exit; if URLs.Count > 0 then with TRegExpr.Create do - try - Expression := REGEX_HOST; - for i := 0 to URLs.Count - 1 do - begin - URLs[i]:=Trim(URLs[i]); - s := Replace(URLs[i], '$4', True); - if s = '' then - s := URLs[i]; - if (s <> '') and (s[1] <> '/') then - s := '/' + s; - URLs[i] := s; + try + Expression := REGEX_HOST; + for i := 0 to URLs.Count - 1 do + begin + URLs[i] := Trim(URLs[i]); + s := Replace(URLs[i], '$4', True); + if s = '' then + s := URLs[i]; + if (s <> '') and (s[1] <> '/') then + s := '/' + s; + URLs[i] := s; + end; + finally + Free; end; - finally - Free; - end; end; -procedure RemoveHostFromURLsPair(const URLs, Names : TStringList); +procedure RemoveHostFromURLsPair(const URLs, Names: TStringList); var - i: Integer; - s: String; + i: Integer; + s: String; begin if (URLs = nil) or (Names = nil) then Exit; if (URLs.Count <> Names.Count) then Exit; if URLs.Count > 0 then with TRegExpr.Create do - try - Expression := REGEX_HOST; - i := 0; - while i < URLs.Count do - begin - URLs[i]:=Trim(URLs[i]); - s := Replace(URLs[i], '$4', True); - if s = '' then - s := URLs[i]; - if (s <> '') and (s[1] <> '/') then - s := '/' + s; - URLs[i] := s; - if (URLs[i] = '') or (URLs[i] = '/') then + try + Expression := REGEX_HOST; + i := 0; + while i < URLs.Count do begin - URLs.Delete(i); - Names.Delete(i); - end - else - Inc(i); + URLs[i] := Trim(URLs[i]); + s := Replace(URLs[i], '$4', True); + if s = '' then + s := URLs[i]; + if (s <> '') and (s[1] <> '/') then + s := '/' + s; + URLs[i] := s; + if (URLs[i] = '') or (URLs[i] = '/') then + begin + URLs.Delete(i); + Names.Delete(i); + end + else + Inc(i); + end; + finally + Free; end; - finally - Free; - end; end; procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); @@ -1480,7 +1480,7 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); try D := P.Parse; try - If Assigned(D) then + if Assigned(D) then if (D.JSONType = jtArray) and (D.Count > 0) then for i := 0 to D.Count - 1 do begin @@ -1496,15 +1496,15 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); OutArray.EndUpdate; end; -procedure ParseHTML(const aRaw: string; aOutput: TStrings); +procedure ParseHTML(const aRaw: String; aOutput: TStrings); begin if not Assigned(aOutput) then Exit; with TParseHTML.Create(aRaw) do try - Output := aOutput; - Exec; - finally - Free; - end; + Output := aOutput; + Exec; + finally + Free; + end; end; procedure ParseHTMLTree(var tp: TTreeParser; const S: String); @@ -1617,49 +1617,49 @@ procedure ConvertCharsetToUTF8(S: TStrings); if cs <> '' then S.Text := ConvertEncoding(S.Text, cs, 'utf8'); end; -function StreamToString(const Stream: TStream): string; +function StreamToString(const Stream: TStream): String; var p, x: Int64; begin //SetString(Result, PChar(Stream.Memory), Stream.Size div SizeOf(Char)); - p:=Stream.Position; - Stream.Position:=0; - Setlength(Result,Stream.Size); - x:=Stream.Read(PChar(Result)^,Stream.Size); - SetLength(Result,x); - Stream.Position:=p; + p := Stream.Position; + Stream.Position := 0; + Setlength(Result, Stream.Size); + x := Stream.Read(PChar(Result)^, Stream.Size); + SetLength(Result, x); + Stream.Position := p; end; -function GetRightValue(const name, s: string): string; +function GetRightValue(const Name, s: String): String; var i: Integer; begin if s = '' then Exit(''); - if name = '' then Exit(s); - i := Pos(name, s); + if Name = '' then Exit(s); + i := Pos(Name, s); if i > 0 then - Result := Trim(Copy(s, i + Length(name), Length(s))); + Result := Trim(Copy(s, i + Length(Name), Length(s))); end; -function QuotedStrd(const S: string): string; +function QuotedStrd(const S: String): String; begin Result := AnsiQuotedStr(S, '"'); end; -function QuotedStrd(const S: Integer): string; +function QuotedStrd(const S: Integer): String; begin Result := QuotedStrd(IntToStr(S)); end; -function BracketStr(const S: string): string; +function BracketStr(const S: String): String; begin Result := '(' + S + ')'; end; -procedure ParseCommandLine(const cmd: string; var Output: TStrings; +procedure ParseCommandLine(const cmd: String; var Output: TStrings; AStripQuotes: Boolean = False); var - s, cl: string; + s, cl: String; cq: Integer; acl, lq: Boolean; @@ -1725,7 +1725,7 @@ procedure ParseCommandLine(const cmd: string; var Output: TStrings; end; function RandomString(SLength: Integer; ONumber: Boolean; OSymbol: Boolean; - OSpace: Boolean): string; + OSpace: Boolean): String; var sgen: String; const @@ -1745,7 +1745,7 @@ function RandomString(SLength: Integer; ONumber: Boolean; OSymbol: Boolean; sgen := sgen + #32; repeat Result := Result + sgen[Random(Length(sgen)) + 1]; - until (Length(Result) = SLength) + until (Length(Result) = SLength); end; function GetValuesFromString(Str: String; Sepr: Char): String; @@ -1765,7 +1765,7 @@ function GetValuesFromString(Str: String; Sepr: Char): String; end; end; -procedure InvertStrings(const St : TStringList); +procedure InvertStrings(const St: TStringList); var i: Integer; begin @@ -1774,7 +1774,7 @@ procedure InvertStrings(const St : TStringList); St.Exchange(i, St.Count - 1 - i); end; -function FixHTMLTagQuote(const s : String) : String; +function FixHTMLTagQuote(const s: String): String; begin Result := s; if Length(Result) > 2 then @@ -1786,7 +1786,7 @@ function FixHTMLTagQuote(const s : String) : String; end; end; -function FixCommonBrokenHTML(const s: String): string; +function FixCommonBrokenHTML(const s: String): String; begin Result := s; Result := StringReplace(Result, '="width="', '="width:', [rfReplaceAll]); @@ -1796,48 +1796,48 @@ function FixCommonBrokenHTML(const s: String): string; function URLDecode(const s: String): String; var - sAnsi: String; - sUtf8: String; - sWide: WideString; - - i, len: Cardinal; - ESC: string[2]; - CharCode: integer; - c: char; -begin - sAnsi := PChar(s); - SetLength(sUtf8, Length(sAnsi)); - i := 1; - len := 1; - while (i <= Cardinal(Length(sAnsi))) do begin - if (sAnsi[i] <> '%') then begin - if (sAnsi[i] = '+') then begin - c := ' '; - end else begin - c := sAnsi[i]; - end; - sUtf8[len] := c; - Inc(len); + sAnsi: String; + sUtf8: String; + sWide: WideString; + + i, len: Cardinal; + ESC: String[2]; + CharCode: Integer; + c: Char; +begin + sAnsi := PChar(s); + SetLength(sUtf8, Length(sAnsi)); + i := 1; + len := 1; + while (i <= Cardinal(Length(sAnsi))) do begin + if (sAnsi[i] <> '%') then begin + if (sAnsi[i] = '+') then begin + c := ' '; end else begin - Inc(i); - ESC := Copy(sAnsi, i, 2); - Inc(i, 1); - try - CharCode := StrToInt('$' + ESC); - c := Char(CharCode); - sUtf8[len] := c; - Inc(len); - except end; + c := sAnsi[i]; end; + sUtf8[len] := c; + Inc(len); + end else begin Inc(i); - end; - Dec(len); - SetLength(sUtf8, len); + ESC := Copy(sAnsi, i, 2); + Inc(i, 1); + try + CharCode := StrToInt('$' + ESC); + c := Char(CharCode); + sUtf8[len] := c; + Inc(len); + except end; + end; + Inc(i); + end; + Dec(len); + SetLength(sUtf8, len); - sWide := UTF8Decode(sUtf8); - len := Length(sWide); + sWide := UTF8Decode(sUtf8); + len := Length(sWide); - Result := {%H-}sWide; + Result := {%H-}sWide; end; function HTMLDecode(const AStr: String): String; @@ -1855,51 +1855,52 @@ function HTMLDecode(const AStr: String): String; begin case Sp^ of '&': begin - Cp := Sp; - Inc(Sp); - case Sp^ of - 'a': if AnsiStrPos(Sp, 'amp;') = Sp then { do not localize } - begin - Inc(Sp, 3); - Rp^ := '&'; - end; - 'l', - 'g': if (AnsiStrPos(Sp, 'lt;') = Sp) or (AnsiStrPos(Sp, 'gt;') = Sp) then { do not localize } - begin - Cp := Sp; - Inc(Sp, 2); - while (Sp^ <> ';') and (Sp^ <> #0) do - Inc(Sp); - if Cp^ = 'l' then - Rp^ := '<' - else - Rp^ := '>'; - end; - 'n': if AnsiStrPos(Sp, 'nbsp;') = Sp then { do not localize } - begin - Inc(Sp, 4); - Rp^ := ' '; - end; - 'q': if AnsiStrPos(Sp, 'quot;') = Sp then { do not localize } - begin - Inc(Sp,4); - Rp^ := '"'; - end; - '#': begin - Tp := Sp; - Inc(Tp); - while (Sp^ <> ';') and (Sp^ <> #0) do - Inc(Sp); - SetString(S, Tp, Sp - Tp); - Val(S, I, Code); - Rp^ := Chr((I)); - end; - else - Exit; - end; - end - else - Rp^ := Sp^; + Cp := Sp; + Inc(Sp); + case Sp^ of + 'a': if AnsiStrPos(Sp, 'amp;') = Sp then { do not localize } + begin + Inc(Sp, 3); + Rp^ := '&'; + end; + 'l', + 'g': if (AnsiStrPos(Sp, 'lt;') = Sp) or (AnsiStrPos(Sp, 'gt;') = Sp) then + { do not localize } + begin + Cp := Sp; + Inc(Sp, 2); + while (Sp^ <> ';') and (Sp^ <> #0) do + Inc(Sp); + if Cp^ = 'l' then + Rp^ := '<' + else + Rp^ := '>'; + end; + 'n': if AnsiStrPos(Sp, 'nbsp;') = Sp then { do not localize } + begin + Inc(Sp, 4); + Rp^ := ' '; + end; + 'q': if AnsiStrPos(Sp, 'quot;') = Sp then { do not localize } + begin + Inc(Sp, 4); + Rp^ := '"'; + end; + '#': begin + Tp := Sp; + Inc(Tp); + while (Sp^ <> ';') and (Sp^ <> #0) do + Inc(Sp); + SetString(S, Tp, Sp - Tp); + Val(S, I, Code); + Rp^ := Chr((I)); + end; + else + Exit; + end; + end + else + Rp^ := Sp^; end; Inc(Rp); Inc(Sp); @@ -1951,8 +1952,8 @@ procedure TrimStrings(TheStrings: TStrings); end; end; -procedure RemoveDuplicateStrings(Strs : array of TStringList; - RemIndex : Cardinal); +procedure RemoveDuplicateStrings(Strs: array of TStringList; + RemIndex: Cardinal); var i, j, k: Integer; begin @@ -1969,7 +1970,7 @@ procedure RemoveDuplicateStrings(Strs : array of TStringList; if Strs[RemIndex].Strings[i] = Strs[RemIndex].Strings[j] then begin for k := 0 to High(Strs) do - Strs[k].Delete(j); + Strs[k].Delete(j); end else Inc(j); @@ -1978,7 +1979,7 @@ procedure RemoveDuplicateStrings(Strs : array of TStringList; end; end; -procedure CleanHTMLComments(const Str : TStringList); +procedure CleanHTMLComments(const Str: TStringList); var i: Integer; begin @@ -2031,11 +2032,11 @@ function StringOfString(c: String; l: Integer): String; var i: Integer; begin - Result:=''; - if c='' then Exit; - if l<1 then Exit; - for i:=1 to l do - Result+=c; + Result := ''; + if c = '' then Exit; + if l < 1 then Exit; + for i := 1 to l do + Result += c; end; function IncStr(const S: String; N: Integer): String; @@ -2076,19 +2077,19 @@ function GetHeaderValue(const AHeaders: TStrings; HName: String): String; end; end; -function Base64Encode(const s: string): string; +function Base64Encode(const s: String): String; begin if s = '' then Exit(s); Result := EncodeStringBase64(s); end; -function Base64Decode(const s: string): string; +function Base64Decode(const s: String): String; begin if s = '' then Exit(s); Result := DecodeStringBase64(s); end; -function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string; +function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; var b1, b2: Char; p, r: String; @@ -2115,7 +2116,7 @@ function StringReplaceBrackets(const S, OldPattern, NewPattern: string; Flags: T end; function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, - AChapter, ANumbering : String; const AIsUnicodeRemove : Boolean) : String; + AChapter, ANumbering: String; const AIsUnicodeRemove: Boolean): String; var chap: String; begin @@ -2133,7 +2134,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, if Pos('%NUMBERING% - ', Result) > 0 then Result := StringReplaceBrackets(Result, '%NUMBERING% - ', '', [rfReplaceAll]) else - Result := StringReplaceBrackets(Result, '%NUMBERING%', '', [rfReplaceAll]) + Result := StringReplaceBrackets(Result, '%NUMBERING%', '', [rfReplaceAll]); end else Result := StringReplaceBrackets(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); @@ -2240,7 +2241,7 @@ function FindStrQuick(const s: String; var AStrings: TStringList): Boolean; procedure GetParams(const output: TStrings; input: String); var - l: word; + l: Word; begin repeat l := Pos(SEPERATOR, input); @@ -2254,7 +2255,7 @@ procedure GetParams(const output: TStrings; input: String); procedure GetParams(var output: TCardinalList; input: String); var - l: word; + l: Word; begin repeat l := Pos(SEPERATOR, input); @@ -2268,7 +2269,7 @@ procedure GetParams(var output: TCardinalList; input: String); procedure GetParams(var output: TList; input: String); var - l: word; + l: Word; begin repeat l := Pos(SEPERATOR, input); @@ -2280,8 +2281,8 @@ procedure GetParams(var output: TList; input: String); until l = 0; end; -function ExtractParam(const output : TStrings; input, sep : String; - WhiteSp : Boolean) : Integer; +function ExtractParam(const output: TStrings; input, sep: String; + WhiteSp: Boolean): Integer; var l, lse: QWord; s: String; @@ -2332,7 +2333,7 @@ function RemoveDuplicateNumbersInString(const AString: String): String; end; Result := ''; for i := 0 to list.Count - 1 do - Result := Result + IntToStr(integer(list.Items[i])) + SEPERATOR; + Result := Result + IntToStr(Integer(list.Items[i])) + SEPERATOR; list.Free; end; @@ -2392,19 +2393,19 @@ function CleanMultilinedString(const S: String; MaxLineEnding: Integer): String; var rn, rnp, n, np: String; begin - Result:=Trim(s); - if Result='' then Exit; - if MaxLineEnding<1 then MaxLineEnding:=1; + Result := Trim(s); + if Result = '' then Exit; + if MaxLineEnding < 1 then MaxLineEnding := 1; - rn:=StringOfString(#13#10,MaxLineEnding); - rnp:=rn+#13#10; - while Pos(rnp,Result)>0 do - Result:=StringReplace(Result,rnp,rn,[rfReplaceAll]); + rn := StringOfString(#13#10, MaxLineEnding); + rnp := rn + #13#10; + while Pos(rnp, Result) > 0 do + Result := StringReplace(Result, rnp, rn, [rfReplaceAll]); - n:=StringOfChar(#10,MaxLineEnding); - np:=n+#10; - while Pos(np,Result)>0 do - Result:=StringReplace(Result,np,n,[rfReplaceAll]); + n := StringOfChar(#10, MaxLineEnding); + np := n + #10; + while Pos(np, Result) > 0 do + Result := StringReplace(Result, np, n, [rfReplaceAll]); end; function CleanAndExpandURL(const URL: String): String; @@ -2462,7 +2463,7 @@ function RemoveURLDelimLeft(const URL: String): String; Result := TrimLeftChar(URL, ['/']); end; -function FixURL(const URL : String) : String; +function FixURL(const URL: String): String; begin Result := URL; if Pos(':', Result) or Pos('/', Result) > 0 then @@ -2478,7 +2479,7 @@ function FixPath(const path: String): String; Exit; for i := 1 to Length(path) do begin - if byte(path[i]) >= 128 then + if Byte(path[i]) >= 128 then Result := Result + '_' else Result := Result + path[i]; @@ -2517,7 +2518,7 @@ function StringFilter(const Source: String): String; begin if Pos(StringFilterChar[i, 0], LowerCase(Result)) > 0 then Result := StringReplace(Result, StringFilterChar[i, 0], StringFilterChar[i, 1], - [rfIgnoreCase, rfReplaceAll]); + [rfIgnoreCase, rfReplaceAll]); end; // broken entities @@ -2571,7 +2572,7 @@ function HTMLEntitiesFilter(const Source: String): String; procedure CustomGenres(var output: TStringList; input: String); var s: String = ''; - i: word; + i: Word; begin if Length(input) = 0 then Exit; @@ -2594,7 +2595,7 @@ procedure CustomGenres(var output: TStringList; input: String); output.Add(s); end; -function CommonStringFilter(const Source : String) : String; +function CommonStringFilter(const Source: String): String; begin Result := Source; if Source = '' then Exit; @@ -2639,7 +2640,7 @@ function RemoveStringBreaks(const Source: String): String; Result := StringReplace(Result, '\r', '', [rfReplaceAll]); end; -function RemoveDoubleSpace(const Source : String) : String; +function RemoveDoubleSpace(const Source: String): String; begin Result := Source; while Pos(' ', Result) > 0 do @@ -2659,7 +2660,7 @@ function TrimChar(const Source: String; const Chars: TSysCharSet): String; function TrimLeftChar(const Source: String; const Chars: TSysCharSet): String; var - i, j: LongInt; + i, j: Longint; begin Result := Source; i := Length(Result); @@ -2675,7 +2676,7 @@ function TrimLeftChar(const Source: String; const Chars: TSysCharSet): String; function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; var - i, j: LongInt; + i, j: Longint; begin Result := Source; i := Length(Result); @@ -2710,7 +2711,7 @@ function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): Result := TrimLeft(TrimRight(Result)); end; -procedure AddCommaString(var Dest: string; S: string); +procedure AddCommaString(var Dest: String; S: String); begin S := Trim(TrimChar(Trim(S), [',', ' '])); if (S = '') or (S = ',') then Exit; @@ -2982,37 +2983,37 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; globReturn: - if OptionProxyType = 'HTTP' then - begin - HTTP.ProxyHost := OptionProxyHost; - HTTP.ProxyPort := OptionProxyPort; - HTTP.ProxyUser := OptionProxyUser; - HTTP.ProxyPass := OptionProxyPass; - end - else - if (OptionProxyType = 'SOCKS4') or (OptionProxyType = 'SOCKS5') then - begin - if OptionProxyType = 'SOCKS4' then - HTTP.Sock.SocksType := ST_Socks4 + if OptionProxyType = 'HTTP' then + begin + HTTP.ProxyHost := OptionProxyHost; + HTTP.ProxyPort := OptionProxyPort; + HTTP.ProxyUser := OptionProxyUser; + HTTP.ProxyPass := OptionProxyPass; + end else - if OptionProxyType = 'SOCKS5' then - HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := OptionProxyHost; - HTTP.Sock.SocksPort := OptionProxyPort; - HTTP.Sock.SocksUsername := OptionProxyUser; - http.Sock.SocksPassword := OptionProxyPass; - end - else - begin - HTTP.Sock.SocksIP := OptionProxyHost; - HTTP.Sock.SocksPort := OptionProxyPort; - HTTP.Sock.SocksUsername := OptionProxyUser; - http.Sock.SocksPassword := OptionProxyPass; - HTTP.ProxyHost := OptionProxyHost; - HTTP.ProxyPort := OptionProxyPort; - HTTP.ProxyUser := OptionProxyUser; - HTTP.ProxyPass := OptionProxyPass; - end; + if (OptionProxyType = 'SOCKS4') or (OptionProxyType = 'SOCKS5') then + begin + if OptionProxyType = 'SOCKS4' then + HTTP.Sock.SocksType := ST_Socks4 + else + if OptionProxyType = 'SOCKS5' then + HTTP.Sock.SocksType := ST_Socks5; + HTTP.Sock.SocksIP := OptionProxyHost; + HTTP.Sock.SocksPort := OptionProxyPort; + HTTP.Sock.SocksUsername := OptionProxyUser; + http.Sock.SocksPassword := OptionProxyPass; + end + else + begin + HTTP.Sock.SocksIP := OptionProxyHost; + HTTP.Sock.SocksPort := OptionProxyPort; + HTTP.Sock.SocksUsername := OptionProxyUser; + http.Sock.SocksPassword := OptionProxyPass; + HTTP.ProxyHost := OptionProxyHost; + HTTP.ProxyPort := OptionProxyPort; + HTTP.ProxyUser := OptionProxyUser; + HTTP.ProxyPass := OptionProxyPass; + end; HTTPHeader.Values['DNT'] := ' 1'; HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; @@ -3108,19 +3109,19 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; if s <> '' then begin with TRegExpr.Create do - try - Expression := REGEX_HOST; - if Replace(s, '$1', True) = '' then - begin - if s[1] <> '/' then - s := '/' + s; - URL := Replace(URL, '$1$2$3', True) + s; - end - else - URL := s; - finally - Free; - end; + try + Expression := REGEX_HOST; + if Replace(s, '$1', True) = '' then + begin + if s[1] <> '/' then + s := '/' + s; + URL := Replace(URL, '$1$2$3', True) + s; + end + else + URL := s; + finally + Free; + end; end; HTTP.Clear; @@ -3227,7 +3228,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String on E: Exception do WriteLog_E('SaveImageStreamToFile.Failed!', E); end; - if FileExistsUTF8(f) then Result := f + if FileExistsUTF8(f) then Result := f; end; end; @@ -3382,19 +3383,19 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; if s <> '' then begin with TRegExpr.Create do - try - Expression := REGEX_HOST; - if Replace(s, '$1', True) = '' then - begin - if s[1] <> '/' then - s := '/' + s; - URL := Replace(URL, '$1$2$3', True) + s; - end - else - URL := s; - finally - Free; - end; + try + Expression := REGEX_HOST; + if Replace(s, '$1', True) = '' then + begin + if s[1] <> '/' then + s := '/' + s; + URL := Replace(URL, '$1$2$3', True) + s; + end + else + URL := s; + finally + Free; + end; end; HTTP.Clear; @@ -3580,9 +3581,9 @@ procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteL names.Free; end; -function DateToJDN(const year, month, day: word): longint; +function DateToJDN(const year, month, day: Word): Longint; var - a, y, m: longint; + a, y, m: Longint; begin a := (14 - month) div 12; y := year + 4800 - a; @@ -3591,17 +3592,17 @@ function DateToJDN(const year, month, day: word): longint; (y div 400) - 32045) - 0.5); end; -function DateToJDN(const date: TDate): longint; +function DateToJDN(const date: TDate): Longint; var - day, month, year: word; + day, month, year: Word; begin DecodeDate(date, year, month, day); Result := DateToJDN(year, month, day); end; -function JDNToDate(const JDN: longint): TDate; +function JDNToDate(const JDN: Longint): TDate; var - a, b, c, d, e, m: longint; + a, b, c, d, e, m: Longint; day, month, year: Word; begin a := trunc(JDN + 32044.5); @@ -3616,9 +3617,9 @@ function JDNToDate(const JDN: longint): TDate; Result := EncodeDate(year, month, day); end; -function GetCurrentJDN: longint; +function GetCurrentJDN: Longint; var - day, month, year: word; + day, month, year: Word; begin DecodeDate(Now, year, month, day); Result := DateToJDN(year, month, day); @@ -3695,17 +3696,17 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); { TParseHTML } -procedure TParseHTML.FoundTag(NoCaseTag, ActualTag: string); +procedure TParseHTML.FoundTag(NoCaseTag, ActualTag: String); begin Output.Add(ActualTag); end; -procedure TParseHTML.FoundText(Text: string); +procedure TParseHTML.FoundText(Text: String); begin Output.Add(Text); end; -constructor TParseHTML.Create(const Raw: string); +constructor TParseHTML.Create(const Raw: String); begin inherited Create; if Raw <> '' then @@ -3714,7 +3715,7 @@ constructor TParseHTML.Create(const Raw: string); FRaw := ''; end; -function TParseHTML.Exec(const Raw: string): string; +function TParseHTML.Exec(const Raw: String): String; var parser: THTMLParser; begin @@ -3799,11 +3800,11 @@ procedure fmdPowerOff; {$IFDEF UNIX} // This process require admin rights in order to execute with TProcessUTF8.Create(nil) do try - CommandLine := 'poweroff'; - Execute; - finally - Free; - end; + CommandLine := 'poweroff'; + Execute; + finally + Free; + end; {$ENDIF} end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b3dbe5f66..01f184bca 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -93,27 +93,21 @@ TMangaInformation = class(TObject) destructor Destroy; override; procedure ClearInfo; function GetDirectoryPage(var Page: Integer; const website: String): Byte; - function GetNameAndLink(const names, links: TStringList; - const website, URL: String): Byte; + function GetNameAndLink(const names, links: TStringList; const website, URL: String): Byte; function GetInfoFromURL(const website, URL: String; const Reconnect: Integer = 0): Byte; - procedure SyncInfoToData(const DataProcess: TDataProcess; - const index: Cardinal); overload; + procedure SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); overload; procedure SyncInfoToData(const DataProcess: TDBDataProcess); overload; - procedure SyncMinorInfoToData(const DataProcess: TDataProcess; - const index: Cardinal); + procedure SyncMinorInfoToData(const DataProcess: TDataProcess; const index: Cardinal); // Only use this function for getting manga infos for the first time - procedure AddInfoToDataWithoutBreak(const Name, link: String; - const DataProcess: TDataProcess); + procedure AddInfoToDataWithoutBreak(const Name, link: String; const DataProcess: TDataProcess); // Only use this function for update manga list procedure AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); overload; // to add data to TDBDataProcess - procedure AddInfoToData(const Title, Link: String; - const DataProcess: TDBDataProcess); overload; + procedure AddInfoToData(const Title, Link: String; const DataProcess: TDBDataProcess); overload; //wrapper - function GetPage(var output: TObject; URL: String; - const Reconnect: Integer = 0): Boolean; inline; + function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; inline; end; var @@ -346,9 +340,7 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; if l.Count <> 0 then begin for j := 0 to l.Count - 1 do - begin site.Add(id); - end; Data.Text := Data.Text + l.Text; end; end; @@ -404,8 +396,8 @@ procedure TDataProcess.SaveToFile; // check if we need to filter or not function TDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; + const haveAllChecked, searchNewManga: Boolean): Boolean; begin if (filterPos.Count = 0) or (Data.Count = 0) or @@ -423,9 +415,8 @@ function TDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringLis end; function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; - useRegExpr: Boolean = False): Boolean; + const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; + const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; var currentJDN, i, j, k, fpos, Count: Integer; s: String; @@ -457,7 +448,7 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; for i := 0 to filterPos.Count - 1 do begin fpos := filterPos.Items[i]; - if (currentJDN - {%H-}integer(jdn.Items[fpos]) >= minusDay) and + if (currentJDN - {%H-}Integer(jdn.Items[fpos]) >= minusDay) and (filterMark.Items[fpos] = FILTER_SHOW) then filterMark.Items[fpos] := FILTER_HIDE; end; @@ -616,10 +607,8 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; end; end else - begin - if filterMark.Items[fpos] = FILTER_SHOW then - filterMark.Items[fpos] := FILTER_HIDE; - end; + if filterMark.Items[fpos] = FILTER_SHOW then + filterMark.Items[fpos] := FILTER_HIDE; end; end; gen.Free; @@ -646,14 +635,12 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; filterMark.Items[fpos] := FILTER_HIDE; end else - begin for j := 0 to uncheckedGenres.Count - 1 do if Pos((uncheckedGenres.Strings[j] + ','), s) <> 0 then begin filterMark.Items[fpos] := FILTER_HIDE; Break; end; - end; end; end; end; @@ -685,13 +672,11 @@ function TDataProcess.Search(AMangaName: String): Boolean; Exit; AMangaName := Upcase(AMangaName); for i := 0 to filterPos.Count - 1 do - begin if Pos(AMangaName, upcase(Title.Strings[filterPos.Items[i]])) > 0 then begin searchPos.Add(filterPos.Items[i]); Result := True; end; - end; end; // get data position @@ -711,13 +696,11 @@ procedure TDataProcess.RemoveFilter; filterMark.Clear; filterPos.Clear; if Data.Count > 0 then - begin for i := 0 to Data.Count - 1 do begin filterMark.Add(FILTER_SHOW); filterPos.Add(i); end; - end; isFiltered := False; end; @@ -729,8 +712,7 @@ procedure TDataProcess.Sort; { TMangaInformation } -constructor TMangaInformation.Create(AOwnerThread: TFMDThread; - CreateInfo: Boolean); +constructor TMangaInformation.Create(AOwnerThread: TFMDThread; CreateInfo: Boolean); begin inherited Create; FHTTP := THTTPSendThread.Create(AOwnerThread); @@ -779,8 +761,7 @@ procedure TMangaInformation.OnText(Text: String); parse.Add(Text); end; -function TMangaInformation.GetDirectoryPage(var Page: Integer; - const website: String): Byte; +function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: String): Byte; var s: String; p: Integer; @@ -1320,8 +1301,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; RemoveHostFromURLsPair(links, names); end; -function TMangaInformation.GetInfoFromURL(const website, URL: String; - const Reconnect: Integer): Byte; +function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reconnect: Integer): Byte; var s, s2: String; j, k: Integer; @@ -1462,7 +1442,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; ModuleId := Modules.LocateModule(website); if Modules.ModuleAvailable(ModuleId, MMGetInfo) then begin mangaInfo.url := FillHost(Modules.Module[ModuleId].RootURL, URL); - Result := Modules.GetInfo(Self, URL, ModuleId) + Result := Modules.GetInfo(Self, URL, ModuleId); end else begin @@ -1686,14 +1666,14 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; summary := ''; // cleanup chapters - if chapterLinks.Count>0 then begin - while chapterName.Count<chapterLinks.Count do + if chapterLinks.Count > 0 then begin + while chapterName.Count < chapterLinks.Count do chapterName.Add(''); - while chapterLinks.Count<chapterName.Count do - chapterName.Delete(chapterName.Count-1); - for j:=0 to chapterLinks.Count-1 do begin - chapterLinks[j]:=Trim(chapterLinks[j]); - chapterName[j]:=Trim(chapterName[j]); + while chapterLinks.Count < chapterName.Count do + chapterName.Delete(chapterName.Count - 1); + for j := 0 to chapterLinks.Count - 1 do begin + chapterLinks[j] := Trim(chapterLinks[j]); + chapterName[j] := Trim(chapterName[j]); end; end; @@ -1706,7 +1686,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; del := False; if (j + 1) < chapterLinks.Count then for k := j + 1 to chapterLinks.Count - 1 do - begin if SameText(chapterLinks[j], chapterLinks[k]) then begin chapterLinks.Delete(j); @@ -1714,7 +1693,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; del := True; Break; end; - end; if not del then Inc(j); end; @@ -1727,10 +1705,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; RemoveHostFromURLsPair(chapterLinks, chapterName); // fixing chapter name for j := 0 to chapterName.Count - 1 do - begin chapterName.Strings[j] := Trim(RemoveStringBreaks( CommonStringFilter(chapterName[j]))); - end; //remove manga name from chapter if OptionRemoveMangaNameFromChapter and (title <> '') then @@ -1743,9 +1719,9 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; if Pos(s, s2) = 1 then begin s2 := chapterName[k]; Delete(s2, 1, j); - s2:=Trim(s2); - if LeftStr(s2,2)='- ' then - Delete(s2,1,2); + s2 := Trim(s2); + if LeftStr(s2, 2) = '- ' then + Delete(s2, 1, 2); chapterName[k] := s2; end; end; @@ -1756,14 +1732,12 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; end; end; -procedure TMangaInformation.SyncMinorInfoToData(const DataProcess: TDataProcess; - const index: Cardinal); +procedure TMangaInformation.SyncMinorInfoToData(const DataProcess: TDataProcess; const index: Cardinal); begin // sync info to data {$IFDEF DOWNLOADER} if not dataProcess.isFilterAllSites then {$ENDIF} - begin DataProcess.Data.Strings[index] := SetParams( [DataProcess.Param[index, DATA_PARAM_TITLE], DataProcess.Param[index, DATA_PARAM_LINK], @@ -1779,13 +1753,11 @@ procedure TMangaInformation.SyncMinorInfoToData(const DataProcess: TDataProcess; '0', {$ENDIF} '0']); - end; // then break it into parts dataProcess.BreakDataToParts(index); end; -procedure TMangaInformation.SyncInfoToData(const DataProcess: TDataProcess; - const index: Cardinal); +procedure TMangaInformation.SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); begin // sync info to data {$IFDEF DOWNLOADER} @@ -1852,8 +1824,7 @@ procedure TMangaInformation.AddInfoToDataWithoutBreak(const Name, link: String; ]))); end; -procedure TMangaInformation.AddInfoToData(const Name, link: String; - const DataProcess: TDataProcess); +procedure TMangaInformation.AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); var l: TStringList; begin @@ -1887,8 +1858,7 @@ procedure TMangaInformation.AddInfoToData(const Name, link: String; l.Free; end; -procedure TMangaInformation.AddInfoToData(const Title, Link: String; - const DataProcess: TDBDataProcess); +procedure TMangaInformation.AddInfoToData(const Title, Link: String; const DataProcess: TDBDataProcess); begin if Assigned(DataProcess) then begin @@ -1900,8 +1870,7 @@ procedure TMangaInformation.AddInfoToData(const Title, Link: String; end; end; -function TMangaInformation.GetPage(var output: TObject; URL: String; - const Reconnect: Integer): Boolean; +function TMangaInformation.GetPage(var output: TObject; URL: String; const Reconnect: Integer): Boolean; begin Result := uBaseUnit.GetPage(FHTTP, output, URL, Reconnect); end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 641d1a97c..ea4b68c81 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -52,7 +52,7 @@ TDownloadThread = class(TFMDThread) // Download image function DownloadImage: Boolean; - procedure OnTag({%H-}NoCaseTag, ActualTag: string); + procedure OnTag({%H-}NoCaseTag, ActualTag: String); procedure OnText(Text: String); procedure SockOnStatus(Sender: TObject; Reason: THookSocketReason; @@ -196,16 +196,16 @@ TDownloadManager = class var Chapters: array of TChapterStateItem); // Add new task to the list. - function AddTask:Integer; + function AddTask: Integer; // Check and active previous work-in-progress tasks. procedure CheckAndActiveTaskAtStartup; // Check and active waiting tasks. procedure CheckAndActiveTask(const isCheckForFMDDo: Boolean = False); // Active a stopped task. procedure SetTaskActive(const taskID: Integer); - procedure ActiveTask(const taskID : Integer); + procedure ActiveTask(const taskID: Integer); // Stop a download/wait task. - procedure StopTask(const taskID : Integer; const isCheckForActive : Boolean = + procedure StopTask(const taskID: Integer; const isCheckForActive: Boolean = True; isWaitFor: Boolean = False); // Start all task procedure StartAllTasks; @@ -214,7 +214,7 @@ TDownloadManager = class // Stop all download task inside a task before terminate the program. procedure StopAllDownloadTasksForExit; // Remove a task from list. - procedure RemoveTask(const taskID : Integer); + procedure RemoveTask(const taskID: Integer); // Remove all finished tasks. procedure RemoveAllFinishedTasks; // check status of task @@ -245,14 +245,14 @@ implementation uses frmMain, WebsiteModules; -function IntToStr(Value: Cardinal): string; +function IntToStr(Value: Cardinal): String; begin Result := SysUtils.IntToStr(QWord(Value)); end; { TDownloadThread } -procedure TDownloadThread.OnTag(NoCaseTag, ActualTag : string); +procedure TDownloadThread.OnTag(NoCaseTag, ActualTag: String); begin parse.Add(ActualTag); end; @@ -318,7 +318,7 @@ procedure TDownloadThread.Execute; manager.container.PageLinks.Add('W'); end else - Reslt := False + Reslt := False; end; // Get image urls. CS_GETPAGELINK: @@ -349,12 +349,14 @@ procedure TDownloadThread.Execute; on E: Exception do begin E.Message := E.Message + LineEnding + - ' In TDownloadThread.Execute : ' + GetEnumName(TypeInfo(TFlagType), integer(checkStyle)) + LineEnding + + ' In TDownloadThread.Execute : ' + GetEnumName(TypeInfo(TFlagType), Integer(checkStyle)) + + LineEnding + ' Website : ' + manager.container.DownloadInfo.Website + LineEnding + ' URL : ' + FillMangaSiteHost(manager.container.MangaSiteID, - manager.container.ChapterLinks[manager.container.CurrentDownloadChapterPtr]) + LineEnding + + manager.container.ChapterLinks[manager.container.CurrentDownloadChapterPtr]) + LineEnding + ' Title : ' + manager.container.DownloadInfo.title + LineEnding + - ' Chapter : ' + manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr] + LineEnding; + ' Chapter : ' + manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr] + + LineEnding; MainForm.ExceptionHandler(Self, E); end; end; @@ -723,7 +725,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; begin Result := False; if (manager.container.PageLinks.Count > 0) and - (manager.container.PageLinks.Strings[workCounter] <> 'W') then + (manager.container.PageLinks.Strings[workCounter] <> 'W') then Exit; if Modules.ModuleAvailable(ModuleId, MMGetImageURL) then @@ -1079,7 +1081,7 @@ function TDownloadThread.DownloadImage: Boolean; FHTTP.Clear; if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then - Result := Modules.BeforeDownloadImage(Self,TURL,ModuleId); + Result := Modules.BeforeDownloadImage(Self, TURL, ModuleId); lname := ''; if workCounter < manager.container.Filenames.Count then @@ -1418,16 +1420,16 @@ procedure TTaskThread.Execute; end else begin WriteLog_W(Format('%s, failed download image PageLinks=%d "%s" > "%s"', - [Self.ClassName, - container.PageLinks.Count, - container.DownloadInfo.Title, - container.ChapterName[container.CurrentDownloadChapterPtr]])); + [Self.ClassName, + container.PageLinks.Count, + container.DownloadInfo.Title, + container.ChapterName[container.CurrentDownloadChapterPtr]])); container.Status := STATUS_FAILED; end; if (container.Status = STATUS_FAILED) and - (not FindStrLinear(container.FailedChapterLinks, - container.ChapterName[container.CurrentDownloadChapterPtr])) then + (not FindStrLinear(container.FailedChapterLinks, + container.ChapterName[container.CurrentDownloadChapterPtr])) then begin container.FailedChapterName.Add(container.ChapterName[container.CurrentDownloadChapterPtr]); container.FailedChapterLinks.Add(container.ChapterLinks[container.CurrentDownloadChapterPtr]); @@ -1584,8 +1586,8 @@ procedure TTaskContainer.Unlock; function TDownloadManager.GetItems(Index: Integer): TTaskContainer; begin - if (Index<0) or (Containers.Count=0) then Exit(nil); - Result:=TTaskContainer(Containers[Index]); + if (Index < 0) or (Containers.Count = 0) then Exit(nil); + Result := TTaskContainer(Containers[Index]); end; function TDownloadManager.GetTaskCount: Integer; @@ -1809,7 +1811,7 @@ procedure TDownloadManager.Backup; WriteString(tid, 'PageContainerLinks', SetParams(PageContainerLinks)); if Filenames.Count > 0 then WriteString(tid, 'Filenames', SetParams(Filenames)); - WriteString(tid, 'TaskStatus', GetEnumName(TypeInfo(TDownloadStatusType), integer(Status))); + WriteString(tid, 'TaskStatus', GetEnumName(TypeInfo(TDownloadStatusType), Integer(Status))); WriteInteger(tid, 'ChapterPtr', CurrentDownloadChapterPtr); WriteInteger(tid, 'NumberOfPages', PageNumber); WriteInteger(tid, 'CurrentPage', CurrentPageNumber); @@ -1871,7 +1873,7 @@ procedure TDownloadManager.AddToDownloadedChaptersList(const Alink: String; i, p, q: Integer; Ch, dlCh: TStringList; begin - if (Alink <> '') and (AValue.Count > 0) then + if (Alink <> '') and (AValue.Count > 0) then begin CS_DownloadedChapterList.Acquire; Ch := TStringList.Create; @@ -1929,7 +1931,7 @@ procedure TDownloadManager.AddToDownloadedChaptersList(const Alink: String; procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; var Chapters: array of TChapterStateItem); var - dlCh : TStringList; + dlCh: TStringList; i, p, q: Integer; begin if (Alink <> '') and (Length(Chapters) > 0) and @@ -1975,7 +1977,7 @@ procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; end; end; -function TDownloadManager.AddTask : Integer; +function TDownloadManager.AddTask: Integer; begin Result := -1; CS_DownloadManager_Task.Acquire; @@ -2005,10 +2007,10 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); if (tcount < maxDLTasks) and (Status = STATUS_WAIT) and Modules.CanCreateTask(ModuleId) then - begin - ActiveTask(i); - Inc(tcount); - end; + begin + ActiveTask(i); + Inc(tcount); + end; finally CS_DownloadManager_Task.Release; end; @@ -2023,7 +2025,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); begin MainForm.itRefreshDLInfo.Enabled := False; MainForm.UpdateVtDownload; - if isCheckForFMDDo and (OptionLetFMDDo<>DO_NOTHING) then begin + if isCheckForFMDDo and (OptionLetFMDDo <> DO_NOTHING) then begin frmMain.DoAfterFMD := OptionLetFMDDo; MainForm.DoExitWaitCounter; end; diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index c7d3887d4..bada685f3 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -1,4 +1,4 @@ -unit uMisc; +unit uMisc; {$mode objfpc}{$H+} @@ -6,7 +6,7 @@ interface uses {$ifdef windows} - ShellApi, windows, + ShellApi, Windows, {$else} UTF8Process, {$endif} @@ -19,7 +19,7 @@ interface TIniFileR = class(TMemIniFile) private FCSReload: TCriticalSection; - FFileAge: longint; + FFileAge: Longint; public constructor Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); override; @@ -50,39 +50,41 @@ function FindStrLinear(aList: TStrings; aValue: String): Boolean; function FindStrLinearPos(aList: TStrings; aValue: String): Integer; //formatting -function FormatByteSize(const bytes :longint; persecond: boolean = False) :string; +function FormatByteSize(const bytes: Longint; persecond: Boolean = False): String; //sorting -function NaturalCompareStr(Str1, Str2: string): integer; inline; +function NaturalCompareStr(Str1, Str2: String): Integer; inline; function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; inline; //run external process function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean = True; isPersistent: Boolean = True): Boolean; -function RunExternalProcess(Exe: String; Params: array of string; ShowWind: Boolean = True; +function RunExternalProcess(Exe: String; Params: array of String; ShowWind: Boolean = True; isPersistent: Boolean = True): Boolean; overload; -function RunExternalProcess(Exe, Params: String; ShowWind: Boolean = True; +function RunExternalProcess(Exe, Params: String; ShowWind: Boolean = True; isPersistent: Boolean = True): Boolean; overload; -function RunExternalProcess(CommandLine: String; ShowWind: Boolean = True; +function RunExternalProcess(CommandLine: String; ShowWind: Boolean = True; isPersistent: Boolean = True): Boolean; overload; //stringutils -procedure ParseCommandLine(const cmd: string; var Output: TStrings; +procedure ParseCommandLine(const cmd: String; var Output: TStrings; AStripQuotes: Boolean = False); function ParsedCommandLine(const cmd: String): TArrayOfString; function StringsToArray(const S: TStrings): TArrayOfString; -function StringsToCommandLine(const S: TStrings): string; overload; -function StringsToCommandLine(const S: array of string): string; overload; -procedure DeleteArrayOfString(Var TheStrings: TArrayOfString; Index: Integer); +function StringsToCommandLine(const S: TStrings): String; overload; +function StringsToCommandLine(const S: array of String): String; overload; +procedure DeleteArrayOfString(var TheStrings: TArrayOfString; Index: Integer); const - UA_SYNAPSE = 'Mozilla/4.0 (compatible; Synapse)'; - UA_CURL = 'curl/7.42.1'; + UA_SYNAPSE = 'Mozilla/4.0 (compatible; Synapse)'; + UA_CURL = 'curl/7.42.1'; UA_GOOGLEBOT = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; - UA_MSIE = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; - UA_FIREFOX = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0'; - UA_CHROME = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36'; - UA_OPERA = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36 OPR/30.0.1835.125'; + UA_MSIE = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; + UA_FIREFOX = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0'; + UA_CHROME = + 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36'; + UA_OPERA = + 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36 OPR/30.0.1835.125'; RANDOM_SLEEP = 3000; @@ -111,21 +113,21 @@ procedure TIniFileR.Reload; slLines: TStringList; begin if FCSReload.TryEnter then try - if FileExistsUTF8(FileName) then - if FileAgeUTF8(FileName) <> FFileAge then - begin - slLines := TStringList.Create; - try - FFileAge := FileAge(FileName); - slLines.LoadFromFile(FileName); - SetStrings(slLines); - finally - slLines.Free; + if FileExistsUTF8(FileName) then + if FileAgeUTF8(FileName) <> FFileAge then + begin + slLines := TStringList.Create; + try + FFileAge := FileAge(FileName); + slLines.LoadFromFile(FileName); + SetStrings(slLines); + finally + slLines.Free; + end; end; - end; - finally - FCSReload.Release; - end; + finally + FCSReload.Release; + end; end; { uMisc } @@ -150,21 +152,21 @@ function BrackSquareText(const S: Integer): String; Result := BrackText(IntToStr(S)); end; -function BrackTextQuoted(const S : String) : String; +function BrackTextQuoted(const S: String): String; begin Result := BrackText(QuotedStr(S)); end; -function BrackTextQuoted(const S : Integer) : String; +function BrackTextQuoted(const S: Integer): String; begin Result := BrackText(QuotedStr(IntToStr(S))); end; -function StringToASCII(S : String) : String; +function StringToASCII(S: String): String; var i: Integer; begin - Result:='#0'; + Result := '#0'; if Length(S) > 0 then begin Result := ''; @@ -173,11 +175,11 @@ function StringToASCII(S : String) : String; end; end; -function StringToHex(S : String) : String; +function StringToHex(S: String): String; var i: Integer; begin - Result:='#0'; + Result := '#0'; if Length(S) > 0 then begin Result := ''; @@ -192,7 +194,7 @@ procedure padZero(var S: String; VolLength, ChapLength: Integer); var j: Integer; begin - for j := i to Length(t) do + for j := i to Length(t) do begin if (cstart = -1) and (t[j] in ['0'..'9']) then cstart := j @@ -242,7 +244,7 @@ procedure padZero(var S: String; VolLength, ChapLength: Integer); vlength := 1; if vol then begin - for i := Pos('VOL', upcase(t)) to Length(t) do + for i := Pos('VOL', upcase(t)) to Length(t) do begin if (vstart = -1) and (t[i] in ['0'..'9']) then vstart := i @@ -379,7 +381,7 @@ function getStringPart(const txt, sep: String; partIndex: Cardinal): String; Result := Copy(txt, lpos, rpos - lpos - Length(sep)); end; -function NaturalCompareStr(Str1, Str2: string): integer; +function NaturalCompareStr(Str1, Str2: String): Integer; begin Result := NaturalSortUnit.UTF8LogicalCompareText(Str1, Str2); end; @@ -395,7 +397,7 @@ procedure QuickSortNaturalPart(var Alist: TStringList; Separator: String; function CompareFn(Index1, Index2: Integer): Integer; begin Result := NaturalCompareStr(getStringPart(Alist[Index1], Separator, PartIndex), - getStringPart(Alist[Index2], Separator, PartIndex)); + getStringPart(Alist[Index2], Separator, PartIndex)); end; procedure QSort(L, R: Integer); @@ -469,9 +471,9 @@ function FindStrLinear(aList: TStrings; aValue: String): Boolean; Result := False; end; -function FormatByteSize(const bytes :longint; persecond: boolean = False) :string; +function FormatByteSize(const bytes: Longint; persecond: Boolean = False): String; const - B = 1; + B = 1; KB = 1024 * B; MB = 1024 * KB; GB = 1024 * MB; @@ -553,7 +555,7 @@ function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean; end; {$ifdef windows} -function WinRunProcessA(Exe, Params: string; ShowWind: Boolean; isPersistent: Boolean): Boolean; +function WinRunProcessA(Exe, Params: String; ShowWind: Boolean; isPersistent: Boolean): Boolean; var SEInfo: TSHELLEXECUTEINFOA; begin @@ -577,7 +579,7 @@ function WinRunProcessA(Exe, Params: string; ShowWind: Boolean; isPersistent: Bo WaitForSingleObject(SEInfo.hProcess, INFINITE); end; -function WinRunProcessW(Exe, Params: string; ShowWind: Boolean; isPersistent: Boolean): Boolean; +function WinRunProcessW(Exe, Params: String; ShowWind: Boolean; isPersistent: Boolean): Boolean; var SEInfo: TSHELLEXECUTEINFOW; begin @@ -600,9 +602,10 @@ function WinRunProcessW(Exe, Params: string; ShowWind: Boolean; isPersistent: Bo if isPersistent then WaitForSingleObject(SEInfo.hProcess, INFINITE); end; + {$endif} -function RunExternalProcess(Exe: String; Params: array of string; +function RunExternalProcess(Exe: String; Params: array of String; ShowWind: Boolean; isPersistent: Boolean): Boolean; {$ifndef windows} var @@ -638,10 +641,10 @@ function RunExternalProcess(Exe: String; Params: array of string; except on E: Exception do begin - WriteLog_E('RunExternalProcess.Error '#13#10+ - 'Executable: '+Exe+#13#10+ - 'Parameters: '+StringsToCommandLine(Params)+#13#10+ - 'Message : '+E.Message+#13#10+ + WriteLog_E('RunExternalProcess.Error '#13#10 + + 'Executable: ' + Exe + #13#10 + + 'Parameters: ' + StringsToCommandLine(Params) + #13#10 + + 'Message : ' + E.Message + #13#10 + GetStackTraceInfo); end; end; @@ -666,8 +669,8 @@ function RunExternalProcess(Exe, Params: String; ShowWind: Boolean; function RunExternalProcess(CommandLine: String; ShowWind: Boolean; isPersistent: Boolean): Boolean; var - s: string; - sa: TArrayOfString; + s: String; + sa: TArrayOfString; begin if Trim(CommandLine) = '' then Exit(False); try @@ -687,10 +690,10 @@ function RunExternalProcess(CommandLine: String; ShowWind: Boolean; end; end; -procedure ParseCommandLine(const cmd: string; var Output: TStrings; +procedure ParseCommandLine(const cmd: String; var Output: TStrings; AStripQuotes: Boolean = False); var - s, cl: string; + s, cl: String; cq: Integer; acl, lq: Boolean; @@ -781,14 +784,14 @@ function StringsToArray(const S: TStrings): TArrayOfString; Result[i] := S[i]; end; -function StringsToCommandLine(const S: TStrings): string; +function StringsToCommandLine(const S: TStrings): String; var i: Integer; begin Result := ''; - if S.Count>0 then + if S.Count > 0 then begin - for i := 0 to S.Count-1 do + for i := 0 to S.Count - 1 do begin if Pos(' ', S[i]) <> 0 then Result := Result + '"' + S[i] + '" ' @@ -799,12 +802,12 @@ function StringsToCommandLine(const S: TStrings): string; end; end; -function StringsToCommandLine(const S: array of string): string; +function StringsToCommandLine(const S: array of String): String; var i: Integer; begin Result := ''; - if Length(S)>0 then + if Length(S) > 0 then begin for i := Low(S) to High(S) do begin diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 48e60b3a1..36cfef2cd 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -5,12 +5,12 @@ {$DEFINE MANGADOWNLOADER} uses - {$IFDEF DEBUGLEAKS} + {$IFDEF DEBUGLEAKS} SysUtils, - {$ENDIF} - {$IFDEF UNIX}{$IFDEF UseCThreads} + {$ENDIF} + {$IFDEF UNIX} {$IFDEF UseCThreads} cthreads, - {$ENDIF}{$ENDIF} + {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, uBaseUnit, frmMain; @@ -22,7 +22,7 @@ begin with TIniFile.Create(CleanAndExpandDirectory(GetCurrentDirUTF8) + - CONFIG_FOLDER + CONFIG_FILE) do + CONFIG_FOLDER + CONFIG_FILE) do try CheckInstance := ReadBool('general', 'OneInstanceOnly', True); finally From bb0e6b5189501c7bf66cd738ea9d43a7643236b7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Mar 2016 21:21:06 +0800 Subject: [PATCH 1061/2794] Bump version 0.9.44.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index d722208a3..4b1c62d8e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.44.0 (24-03-2016) +[*] MangaFox: fixed downloaded chapters incorrectly recognized as new chapter +[*] WPManga: fixed mangainfo and get image url +[*] SenManga: fixed get image url +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.43.0...0.9.44.0 + 0.9.43.0 (23-03-2016) [*] Fixed download sometimes failed when max connection limit = 1 [*] 8Muses: faster get image url diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index a17728d2b..6e6b45ea3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="43"/> + <RevisionNr Value="44"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 9d78c4f8f..18ffad669 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.43.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.43.0/fmd_0.9.43.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.43.0/fmd_0.9.43.0_Win64.7z +VERSION=0.9.44.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.44.0/fmd_0.9.44.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.44.0/fmd_0.9.44.0_Win64.7z From 6d2e22725e73b5498a85f79b3dc924ccf0edf0a5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Mar 2016 14:29:21 +0800 Subject: [PATCH 1062/2794] rename padzero to volumechapterpadzero --- baseunits/uBaseUnit.pas | 6 +++--- baseunits/uMisc.pas | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e4a65ed54..3e25f5a85 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2143,13 +2143,13 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, with MainForm.options do begin if ReadBool('saveto', 'ConvertDigitVolume', False) then begin if ReadBool('saveto', 'ConvertDigitChapter', False) then - padZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), + VolumeChapterPadZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), ReadInteger('saveto', 'DigitChapterLength', 3)) else - padZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), 0); + VolumeChapterPadZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), 0); end else if ReadBool('saveto', 'ConvertDigitChapter', False) then - padZero(chap, 0, ReadInteger('saveto', 'DigitChapterLength', 3)); + VolumeChapterPadZero(chap, 0, ReadInteger('saveto', 'DigitChapterLength', 3)); end; Result := StringReplaceBrackets(Result, '%CHAPTER%', chap, [rfReplaceAll]); diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index bada685f3..f170b30a5 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -28,7 +28,7 @@ TIniFileR = class(TMemIniFile) end; //String utils -procedure padZero(var S: String; VolLength, ChapLength: Integer); +procedure VolumeChapterPadZero(var S: String; VolLength, ChapLength: Integer); function padZeros(const S: String; VolLength, ChapLength: Integer): String; inline; function BrackText(const S: String): String; overload; inline; function BrackText(const S: Integer): String; overload; inline; @@ -188,7 +188,7 @@ function StringToHex(S: String): String; end; end; -procedure padZero(var S: String; VolLength, ChapLength: Integer); +procedure VolumeChapterPadZero(var S: String; VolLength, ChapLength: Integer); procedure searchChap(var i, cstart, clength: Integer; var t: String); var @@ -332,7 +332,7 @@ procedure padZero(var S: String; VolLength, ChapLength: Integer); function padZeros(const S: String; VolLength, ChapLength: Integer): String; begin Result := S; - padZero(Result, VolLength, ChapLength); + VolumeChapterPadZero(Result, VolLength, ChapLength); end; //loading directly from stream accepted as raw (file become bigger) From 0242b8966adf590e2a28440c2d10e62d3c165668 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Mar 2016 14:47:27 +0800 Subject: [PATCH 1063/2794] baseunit, added padzero and padzeros --- baseunits/uBaseUnit.pas | 70 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3e25f5a85..ad84ed7ff 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -809,6 +809,11 @@ function Base64Encode(const s: String): String; function Base64Decode(const s: String): String; // StringUtils +function PadZero(const S: String; ATotalWidth: Integer = 3; + PadAll: Boolean = False; StripZero: Boolean = False): String; +procedure PadZeros(S: TStrings; ATotalWidth: Integer = 3; + PadAll: Boolean = False; StripZeros: Boolean = False); + function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; function StreamToString(const Stream: TStream): String; inline; function GetRightValue(const Name, s: String): String; @@ -822,8 +827,8 @@ procedure InvertStrings(const St: TStringList); overload; procedure InvertStrings(const Sts: array of TStringList); overload; procedure TrimStrings(TheStrings: TStrings); procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Cardinal = 0); -procedure CleanHTMLComments(const Str: TStringList); +procedure CleanHTMLComments(const Str: TStringList); function FixHTMLTagQuote(const s: String): String; function FixCommonBrokenHTML(const s: String): String; function URLDecode(const s: String): String; @@ -2089,6 +2094,69 @@ function Base64Decode(const s: String): String; Result := DecodeStringBase64(s); end; +function PadZero(const S: String; ATotalWidth: Integer; PadAll: Boolean; StripZero: Boolean): String; +var + isnumber: Boolean; + n: String; + i: Integer; + + procedure padn(var R: String); + begin + if isnumber then + begin + if StripZero then + while (Length(n) > 0) and (n[1] = '0') do + Delete(n, 1, 1); + R := R + StringOfChar('0', ATotalWidth - Length(n)) + n; + n := ''; + isnumber := False; + end; + end; + +begin + if S = '' then Exit(S); + Result := ''; + isnumber := False; + n := ''; + for i := 1 to Length(S) do + begin + if S[i] in ['0'..'9'] then + begin + n := n + S[i]; + isnumber := True; + end + else + begin + if isnumber then + begin + padn(Result); + if not PadAll then + begin + Result := Result + S[i]; + Break; + end; + end; + Result := Result + S[i]; + end; + end; + padn(Result); + Inc(i); + if i < Length(S) then + Result := Result + Copy(S, i, Length(S) - i + 1); +end; + +procedure PadZeros(S: TStrings; ATotalWidth: Integer; PadAll: Boolean; StripZeros: Boolean); +var + i: Integer; +begin + if S = nil then Exit; + if S.Count = 0 then Exit; + for i := 0 to S.Count - 1 do + begin + S[i] := PadZero(S[i], ATotalWidth, PadAll, StripZeros); + end; +end; + function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; var b1, b2: Char; From 9ad8f6fa4ca68078f13c9456dbcd34a896040e2a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Mar 2016 14:48:50 +0800 Subject: [PATCH 1064/2794] added serializeandmaintainnames workaround for #217 --- baseunits/uBaseUnit.pas | 77 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ad84ed7ff..91a512f34 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -814,6 +814,9 @@ function PadZero(const S: String; ATotalWidth: Integer = 3; procedure PadZeros(S: TStrings; ATotalWidth: Integer = 3; PadAll: Boolean = False; StripZeros: Boolean = False); +// maintain the order of strings by adding serialized number if necessary +procedure SerializeAndMaintainNames(F: TStrings); + function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; function StreamToString(const Stream: TStream): String; inline; function GetRightValue(const Name, s: String): String; @@ -2157,6 +2160,80 @@ procedure PadZeros(S: TStrings; ATotalWidth: Integer; PadAll: Boolean; StripZero end; end; +procedure SerializeAndMaintainNames(F: TStrings); +var + s, so: TStringList; + sameorder: Boolean; + i, ls: Integer; + fs: String; + + function identicalstrings(s1, s2: TStrings): Boolean; + var + j: Integer; + begin + Result := False; + if s1.Count <> s2.Count then Exit; + for j := 0 to s1.Count - 1 do + if s1[j] <> s2[j] then + Exit; + Result := True; + end; + + procedure checksorder; + begin + so.Clear; + so.AddStrings(s); + so.Sort; + sameorder := identicalstrings(s, so); + end; + +begin + if F = nil then Exit; + if F.Count = 0 then Exit; + s := TStringList.Create; + try + //try sorting it + s.AddStrings(F); + s.Sort; + sameorder := identicalstrings(s, F); + + //try padzero + if not sameorder then + begin + so := TStringList.Create; + try + ls := Length(IntToStr(F.Count)); + if ls < 3 then + ls := 3; + s.Clear; + s.AddStrings(F); + PadZeros(s, ls, False, False); + checksorder; + + // add serializing number + if not sameorder then + begin + s.Clear; + s.AddStrings(F); + fs := '%.' + IntToStr(ls) + 'd_%s'; + for i := 0 to s.Count - 1 do + s[i] := Format(fs, [i + 1, s[i]]); + checksorder; + end; + finally + so.Free; + end; + end; + if sameorder then + begin + F.Clear; + F.AddStrings(s); + end; + finally + s.Free; + end; +end; + function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; var b1, b2: Char; From d3badc1bd43dba1111bc0ce7126097ca7581e84e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Mar 2016 15:20:59 +0800 Subject: [PATCH 1065/2794] ehentai, serializeandmaintainnames fixed #217 --- baseunits/modules/EHentai.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index b6e556301..57021ff28 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -232,6 +232,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; while PageLinks.Count < PageContainerLinks.Count do PageLinks.Add('G'); + SerializeAndMaintainNames(Filenames); end; end; From fba99c231386d423a232910a87bfcf24e9586799 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Mar 2016 16:34:28 +0800 Subject: [PATCH 1066/2794] ehentai, fixed getting url parameter on retry fixed #213 --- baseunits/modules/EHentai.pas | 122 ++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 57021ff28..cce812a7d 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,13 +6,10 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, synautil, LazFileUtils; + accountmanagerdb, XQueryEngineHTML, synautil, synacode, RegExpr, LazFileUtils; implementation -uses - RegExpr, synacode; - const dirURL = 'f_doujinshi=on&f_manga=on&f_western=on&f_apply=Apply+Filter'; exhentaiurllogin = 'https://forums.e-hentai.org/index.php?act=Login&CODE=01'; @@ -281,63 +278,76 @@ function DownloadImage(const DownloadThread: TDownloadThread; function DoDownloadImage: Boolean; var - i, rcount: Integer; - base_url, startkey, gid, startpage, nl: String; - source: TStringList; + rcount: Integer; + base_url, startkey, gid, startpage, nl, s, nls: String; begin rcount := 0; Result := False; - source := TStringList.Create; - try - while (not Result) and (not DownloadThread.IsTerminated) do begin - source.LoadFromStream(DownloadThread.FHTTP.Document); - query.ParseHTML(DownloadThread.FHTTP.Document); - iurl := ''; - if OptionEHentaiDownloadOriginalImage and (Account.Status[accname] = asValid) then - iurl := query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); - if iurl = '' then - iurl := query.XPathString('//*[@id="img"]/@src'); - if iurl = '' then - iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); - if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, iurl, APath, AName); - if DownloadThread.IsTerminated then Break; - if rcount >= reconnect then Break; - if not Result then begin - base_url := ''; - startkey := ''; - gid := ''; - startpage := ''; - nl := ''; - //get AURL param - if source.Count > 0 then - for i := 0 to source.Count - 1 do begin - if Pos('var base_url=', source[i]) > 0 then - base_url := RemoveURLDelim(GetValuesFromString(source[i], '=')) - else if Pos('var startkey=', source[i]) > 0 then - startkey := GetValuesFromString(source[i], '=') - else if Pos('var gid=', source[i]) > 0 then - gid := GetValuesFromString(source[i], '=') - else if Pos('var startpage=', source[i]) > 0 then - startpage := GetValuesFromString(source[i], '=') - else if Pos('return nl(', source[i]) > 0 then - nl := ReplaceRegExpr('(?i)^.*nl\([''"](.*)[''"]\).*$', - source[i], '$1', True); - end; - if (base_url <> '') and (startkey <> '') and (gid <> '') and - (startpage <> '') then - iurl := base_url + '/s/' + startkey + '/' + gid + '-' + startpage - else iurl := FillHost(Module.RootURL, AURL); - if nl <> '' then begin - iurl := iurl + '?nl=' + nl; - if not GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then Break; - end else Break; - if rcount >= reconnect then Break - else Inc(rcount); + nls := ''; + while (not Result) and (not DownloadThread.IsTerminated) do begin + s := StreamToString(DownloadThread.FHTTP.Document); + query.ParseHTML(DownloadThread.FHTTP.Document); + iurl := ''; + if OptionEHentaiDownloadOriginalImage and (Account.Status[accname] = asValid) then + iurl := query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); + if iurl = '' then + iurl := query.XPathString('//*[@id="img"]/@src'); + if iurl = '' then + iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); + if iurl <> '' then + Result := SaveImage(DownloadThread.FHTTP, iurl, APath, AName); + if DownloadThread.IsTerminated then Break; + if rcount >= reconnect then Break; + if not Result then begin + base_url := ''; + startkey := ''; + gid := ''; + startpage := ''; + nl := ''; + //get AURL param + if Pos('var base_url', s) > 0 then + begin + base_url := GetBetween('var base_url=', ';', s); + base_url := TrimChar(base_url, ['''', '"']); + end; + if Pos('var startkey', s) > 0 then + begin + startkey := GetBetween('var startkey=', ';', s); + startkey := TrimChar(startkey, ['''', '"']); + end; + if Pos('var gid', s) > 0 then + begin + gid := GetBetween('var gid=', ';', s); + gid := TrimChar(gid, ['''', '"']); end; + if Pos('var startpage', s) > 0 then + begin + startpage := GetBetween('var startpage=', ';', s); + startpage := TrimChar(startpage, ['''', '"']); + end; + if Pos('return nl(', s) > 0 then + begin + nl := GetBetween('return nl(', ')', s); + nl := TrimChar(nl, ['''', '"']); + end; + s := ''; + + if (base_url <> '') and (startkey <> '') and (gid <> '') and + (startpage <> '') then + iurl := RemoveURLDelim(base_url) + '/s/' + startkey + '/' + gid + '-' + startpage + else + iurl := FillHost(Module.RootURL, AURL); + if nl <> '' then + begin + if nls = '' then + nls := '?nl=' + nl + else + nls := nls + '&nl=' + nl; + iurl := iurl + nls; + end; + if not GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then Break; + Inc(rcount); end; - finally - source.Free; end; end; From b42a5a39f767bbde459f32d03df7b99341519d77 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 25 Mar 2016 16:44:08 +0800 Subject: [PATCH 1067/2794] Bump version 0.9.45.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4b1c62d8e..81c42278c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.45.0 (25-03-2016) +[*] E-Hentai/ExHentai: fixed file naming problem (#217) +[*] E-Hentai/ExHentai: fixed get another image url when failed (#213) +Full changes: https://github.com/riderkick/FMD/compare/0.9.44.0...0.9.45.0 + 0.9.44.0 (24-03-2016) [*] MangaFox: fixed downloaded chapters incorrectly recognized as new chapter [*] WPManga: fixed mangainfo and get image url diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6e6b45ea3..51ea60c5f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="44"/> + <RevisionNr Value="45"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 18ffad669..4b5819cbd 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.44.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.44.0/fmd_0.9.44.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.44.0/fmd_0.9.44.0_Win64.7z +VERSION=0.9.45.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.45.0/fmd_0.9.45.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.45.0/fmd_0.9.45.0_Win64.7z From 52785afba77d6dc23a406560cbde4dda6e291179 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 13:58:38 +0800 Subject: [PATCH 1068/2794] simplelogger, trap lazlogger debugln --- baseunits/SimpleException/SimpleLogger.pas | 175 +++++++++++++-------- 1 file changed, 108 insertions(+), 67 deletions(-) diff --git a/baseunits/SimpleException/SimpleLogger.pas b/baseunits/SimpleException/SimpleLogger.pas index de9482433..ee736bae9 100644 --- a/baseunits/SimpleException/SimpleLogger.pas +++ b/baseunits/SimpleException/SimpleLogger.pas @@ -25,12 +25,28 @@ interface uses - Classes, SysUtils, DbgInfoReader, LazFileUtils, LazUTF8; + Classes, SysUtils, DbgInfoReader, LazFileUtils, LazUTF8 + {$ifdef traplazlogger or sendtolazlogger} + , LazLogger + {$endif}; type TLogType = (ERROR, WARNING, INFO, DEBUG, VERBOSE); + {$ifdef traplazlogger} + { TLazloggerHelper } + + TLazloggerHelper = class + public + procedure DbgLn(Sender: TObject; S: String; var Handled: Boolean); + end; + + {$endif} + var + {$ifdef traplazlogger} + lazloggerhelper: TLazloggerHelper; + {$endif} _CS_LOG: TRTLCriticalSection; _LOG_ACTIVE: Boolean = False; _LOG_LEVEL: Integer = 2; @@ -40,26 +56,26 @@ interface const _LOG_SYMBOL = 'EWIDV'; - function ArrayToString(Args: array of const): String; - procedure SetLogFile(const LogFileName: String); - procedure WriteLog_E(const msg: String); overload; inline; - procedure WriteLog_E(msg: array of const); overload; inline; - procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject = nil); overload; - procedure WriteLog_E(msg: array of const; Exc: Exception; Sender: TObject = nil); overload; inline; - procedure Writelog_W(const msg: String); inline; - procedure WriteLog_W(msg: array of const); overload; inline; - procedure Writelog_I(const msg: String); inline; - procedure WriteLog_I(msg: array of const); overload; inline; - procedure Writelog_D(const msg: String); inline; - procedure WriteLog_D(msg: array of const); overload; inline; - procedure Writelog_V(const msg: String); inline; - procedure WriteLog_V(msg: array of const); overload; inline; - function SimpleBackTraceStr(const Addr: Pointer): String; - function GetStackTraceInfo(const MaxStackCount: Integer = 20): string; +function ArrayToString(Args: array of const): String; +procedure SetLogFile(const LogFileName: String); +procedure WriteLog_E(const msg: String); overload; inline; +procedure WriteLog_E(msg: array of const); overload; inline; +procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject = nil); overload; +procedure WriteLog_E(msg: array of const; Exc: Exception; Sender: TObject = nil); overload; inline; +procedure Writelog_W(const msg: String); inline; +procedure WriteLog_W(msg: array of const); overload; inline; +procedure Writelog_I(const msg: String); inline; +procedure WriteLog_I(msg: array of const); overload; inline; +procedure Writelog_D(const msg: String); inline; +procedure WriteLog_D(msg: array of const); overload; inline; +procedure Writelog_V(const msg: String); inline; +procedure WriteLog_V(msg: array of const); overload; inline; +function SimpleBackTraceStr(const Addr: Pointer): String; +function GetStackTraceInfo(const MaxStackCount: Integer = 20): String; implementation -procedure ForceLogFile(const logfilename: string); +procedure ForceLogFile(const logfilename: String); var f: String; begin @@ -75,9 +91,27 @@ procedure ForceLogFile(const logfilename: string); _FLOGFILE := f; end; +procedure SetLogFile(const LogFileName: String); +begin + if Trim(LogFileName) <> '' then + begin + EnterCriticalsection(_CS_LOG); + try + ForceLogFile(LogFileName); + finally + LeaveCriticalsection(_CS_LOG); + end; + end; +end; + +function FormatLogMessage(const msg: String; LogType: TLogType = DEBUG): String; +begin + Result := FormatDateTime('dd/mm/yyyy|hh:nn:ss.zzz ', Now) + + '[' + _LOG_SYMBOL[Integer(logType) + 1] + '] ' + msg; +end; + procedure WriteLog(const msg: String; LogType: TLogType = DEBUG); var - s: String; f: TextFile; begin if not _LOG_ACTIVE then Exit; @@ -85,8 +119,6 @@ procedure WriteLog(const msg: String; LogType: TLogType = DEBUG); if Integer(logType) > _LOG_LEVEL then Exit; EnterCriticalsection(_CS_LOG); try - s := FormatDateTime('dd/mm/yyyy|hh:nn:ss.zzz ', Now); - s := s + '[' + _LOG_SYMBOL[Integer(logType)+1] + ']'; AssignFile(f, _FLOGFILE); try if FileExistsUTF8(_FLOGFILE) then @@ -96,7 +128,7 @@ procedure WriteLog(const msg: String; LogType: TLogType = DEBUG); ForceLogFile(_FLOGFILE); Rewrite(f); end; - WriteLn(f, s + ' ' + msg); + WriteLn(f, FormatLogMessage(msg, LogType)); finally CloseFile(f); end; @@ -105,40 +137,27 @@ procedure WriteLog(const msg: String; LogType: TLogType = DEBUG); end; end; -procedure SetLogFile(const LogFileName: String); -begin - if Trim(LogFileName) <> '' then - begin - EnterCriticalsection(_CS_LOG); - try - ForceLogFile(LogFileName); - finally - LeaveCriticalsection(_CS_LOG); - end; - end; -end; - function VarRecToString(AVarRec: TVarRec): String; begin case AVarRec.VType of - vtInteger : Result := IntToStr(AVarRec.VInteger); - vtBoolean : Result := BoolToStr(AVarRec.VBoolean, True); - vtChar : Result := AVarRec.VChar; - vtWideChar : Result := WideString(AVarRec.VWideChar); - vtExtended : Result := FloatToStr(AVarRec.VExtended^); - vtString : Result := AVarRec.VString^; - vtPointer : Result := hexStr(AVarRec.VPointer); - vtPChar : Result := AVarRec.VPChar; - vtObject : Result := AVarRec.VObject.ClassName; - vtClass : Result := AVarRec.VClass.ClassName; - vtPWideChar : Result := AVarRec.VPWideChar; - vtAnsiString : Result := AnsiString(AVarRec.VAnsiString); - vtCurrency : Result := CurrToStr(AVarRec.VCurrency^); - vtVariant : Result := String(AVarRec.VVariant); - vtWideString : Result := WideString(AVarRec.VWideString); - vtInt64 : Result := IntToStr(AVarRec.VInt64^); - vtUnicodeString : Result := UnicodeString(AVarRec.VUnicodeString); - vtQWord : Result := IntToStr(AVarRec.VQWord^); + vtInteger: Result := IntToStr(AVarRec.VInteger); + vtBoolean: Result := BoolToStr(AVarRec.VBoolean, True); + vtChar: Result := AVarRec.VChar; + vtWideChar: Result := WideString(AVarRec.VWideChar); + vtExtended: Result := FloatToStr(AVarRec.VExtended^); + vtString: Result := AVarRec.VString^; + vtPointer: Result := hexStr(AVarRec.VPointer); + vtPChar: Result := AVarRec.VPChar; + vtObject: Result := AVarRec.VObject.ClassName; + vtClass: Result := AVarRec.VClass.ClassName; + vtPWideChar: Result := AVarRec.VPWideChar; + vtAnsiString: Result := Ansistring(AVarRec.VAnsiString); + vtCurrency: Result := CurrToStr(AVarRec.VCurrency^); + vtVariant: Result := String(AVarRec.VVariant); + vtWideString: Result := WideString(AVarRec.VWideString); + vtInt64: Result := IntToStr(AVarRec.VInt64^); + vtUnicodeString: Result := UnicodeString(AVarRec.VUnicodeString); + vtQWord: Result := IntToStr(AVarRec.VQWord^); else Result := ''; end; @@ -161,22 +180,22 @@ procedure WriteLog_E(const msg: String); procedure WriteLog_E(msg: array of const); begin - WriteLog(ArrayToString(msg), ERROR); + WriteLog_E(ArrayToString(msg)); end; procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); var - s: string; + s: String; begin s := ''; if Assigned(Sender) then s += LineEnding + - 'Sender Class : ' + Sender.ClassName; + 'Sender Class : ' + Sender.ClassName; if Assigned(Exc) then begin s += LineEnding + - 'Exception Class : ' + Exc.ClassName + LineEnding + - 'Exception Message : ' + Exc.Message; + 'Exception Class : ' + Exc.ClassName + LineEnding + + 'Exception Message : ' + Exc.Message; end; s += LineEnding + GetStackTraceInfo; WriteLog_E(msg + s); @@ -194,7 +213,7 @@ procedure Writelog_W(const msg: String); procedure WriteLog_W(msg: array of const); begin - WriteLog(ArrayToString(msg), WARNING); + WriteLog_W(ArrayToString(msg)); end; procedure Writelog_I(const msg: String); @@ -204,17 +223,21 @@ procedure Writelog_I(const msg: String); procedure WriteLog_I(msg: array of const); begin - WriteLog(ArrayToString(msg), INFO); + WriteLog_I(ArrayToString(msg)); end; procedure Writelog_D(const msg: String); begin + {$ifdef sendtolazlogger} + DebugLn(msg); + {$else} WriteLog(msg, DEBUG); + {$endif} end; procedure WriteLog_D(msg: array of const); begin - WriteLog(ArrayToString(msg), DEBUG); + WriteLog_D(ArrayToString(msg)); end; procedure Writelog_V(const msg: String); @@ -224,14 +247,14 @@ procedure Writelog_V(const msg: String); procedure WriteLog_V(msg: array of const); begin - WriteLog(ArrayToString(msg), VERBOSE); + WriteLog_V(ArrayToString(msg)); end; function SimpleBackTraceStr(const Addr: Pointer): String; var func, Source: ShortString; hs: String[32]; - line: longint; + line: LongInt; begin Result := '$' + hexStr(Addr); if _HAS_DEBUG_LINE then @@ -257,7 +280,7 @@ function SimpleBackTraceStr(const Addr: Pointer): String; end; end; -function GetStackTraceInfo(const MaxStackCount: Integer): string; +function GetStackTraceInfo(const MaxStackCount: Integer): String; var i, maxStack: Integer; cf, pcf, cAddress, cFrame: Pointer; @@ -318,6 +341,10 @@ procedure doInitialization; _LOG_ACTIVE := True; _LOG_LEVEL := SizeOf(TLogType); {$ENDIF} + {$ifdef traplazlogger} + lazloggerhelper := TLazloggerHelper.Create; + LazLogger.DebugLogger.OnDebugLn := @lazloggerhelper.DbgLn; + {$endif} _FLOGFILE := ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '_LOG.txt'); for i := 1 to Paramcount do begin @@ -326,8 +353,8 @@ procedure doInitialization; _LOG_ACTIVE := True; if i < Paramcount then begin - if StrToIntDef(ParamStr(i+1), -1) > -1 then - _LOG_LEVEL := StrToInt(ParamStr(i+1)); + if StrToIntDef(ParamStr(i + 1), -1) > -1 then + _LOG_LEVEL := StrToInt(ParamStr(i + 1)); end; if _LOG_LEVEL > SizeOf(TLogType) then _LOG_LEVEL := SizeOf(TLogType); @@ -337,10 +364,25 @@ procedure doInitialization; procedure doFinalization; begin + {$ifdef traplazlogger} + DebugLogger.OnDebugLn := nil; + lazloggerhelper.Free; + {$endif} CloseSymbolFile; DoneCriticalsection(_CS_LOG); end; +{$ifdef traplazlogger} +{ TLazloggerHelper } + +procedure TLazloggerHelper.DbgLn(Sender: TObject; S: String; var Handled: Boolean); +begin + Handled := False; + WriteLog(S, DEBUG); +end; + +{$endif} + initialization doInitialization; @@ -348,4 +390,3 @@ finalization doFinalization; end. - From d39ffc3e89fb37e2565d8e4c2b893705d9f3ec38 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 13:59:00 +0800 Subject: [PATCH 1069/2794] added sqlitedata, for base sqlite database --- baseunits/SQLiteData.pas | 331 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 baseunits/SQLiteData.pas diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas new file mode 100644 index 000000000..cd61834ad --- /dev/null +++ b/baseunits/SQLiteData.pas @@ -0,0 +1,331 @@ +unit SQLiteData; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, LazFileUtils, strutils, sqlite3conn, sqldb, DB; + +type + + { TSQLite3ConnectionH } + + TSQLite3ConnectionH = class(TSQLite3Connection) + public + property Handle read GetHandle; + end; + + TExceptionEvent = procedure(Sender: TObject; E: Exception) of object; + + { TSQliteData } + + TSQliteData = class + private + FConn: TSQLite3ConnectionH; + FOnError: TExceptionEvent; + FTrans: TSQLTransaction; + FQuery: TSQLQuery; + FFilename: String; + FTableName: String; + FCreateParams: String; + FRecordCount: Integer; + procedure DoOnError(E: Exception); + function GetAutoApplyUpdates: Boolean; + procedure SetAutoApplyUpdates(AValue: Boolean); + procedure SetCreateParams(AValue: String); + procedure SetOnError(AValue: TExceptionEvent); + protected + function CreateDB: Boolean; virtual; + function CreateDBTable: Boolean; virtual; + function InternalOpenDB: Boolean; virtual; + function OpenDBTable: Boolean; virtual; + function ConvertNewTableIF: Boolean; virtual; + procedure DoConvertNewTable; + procedure GetRecordCount; virtual; + procedure SetRecordCount(const AValue: Integer); virtual; + procedure IncRecordCount(const N: Integer = 1); + procedure Vacuum; virtual; + public + constructor Create; + destructor Destroy; override; + function Open: Boolean; + procedure Close; + procedure Refresh(RecheckDataCount: Boolean = False); + procedure Save; + function Connected: Boolean; + property Connection: TSQLite3ConnectionH read FConn; + property Table: TSQLQuery read FQuery; + property Filename: String read FFilename write FFilename; + property TableName: String read FTableName write FTableName; + property CreateParams: String read FCreateParams write SetCreateParams; + property RecordCount: Integer read FRecordCount; + property AutoApplyUpdates: Boolean read GetAutoApplyUpdates write SetAutoApplyUpdates; + property OnError: TExceptionEvent read FOnError write SetOnError; + end; + +implementation + +function QuotedStrd(const S: String): String; +begin + Result := AnsiQuotedStr(S, '"'); +end; + +{ TSQliteData } + +procedure TSQliteData.DoOnError(E: Exception); +begin + if Assigned(OnError) then + OnError(Self, E); +end; + +function TSQliteData.GetAutoApplyUpdates: Boolean; +begin + Result := sqoAutoApplyUpdates in FQuery.Options; +end; + +procedure TSQliteData.SetAutoApplyUpdates(AValue: Boolean); +begin + if AValue then + FQuery.Options := FQuery.Options + [sqoAutoApplyUpdates] + else + FQuery.Options := FQuery.Options - [sqoAutoApplyUpdates]; +end; + +procedure TSQliteData.SetCreateParams(AValue: String); +begin + if FCreateParams = AValue then Exit; + FCreateParams := Trim(AValue); + FCreateParams := TrimSet(FCreateParams, ['(', ')', ';']); +end; + +procedure TSQliteData.SetOnError(AValue: TExceptionEvent); +begin + if FOnError = AValue then Exit; + FOnError := AValue; +end; + +function TSQliteData.CreateDB: Boolean; +begin + Result := False; + if FFilename = '' then Exit; + if FileExistsUTF8(ffilename) then DeleteFileUTF8(FFilename); + CreateDBTable; +end; + +function TSQliteData.CreateDBTable: Boolean; +begin + Result := False; + if FTableName = '' then Exit; + if FCreateParams = '' then Exit; + if InternalOpenDB = False then Exit; + try + FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + + '(' + FCreateParams + ')'); + FTrans.Commit; + Result := OpenDBTable; + except + on E: Exception do + DoOnError(E); + end; +end; + +function TSQliteData.InternalOpenDB: Boolean; +begin + Result := False; + if FFilename = '' then Exit; + try + FConn.DatabaseName := FFilename; + FConn.Connected := True; + FTrans.Active := True; + Result := FConn.Connected; + finally + Result := FConn.Connected; + end; +end; + +function TSQliteData.OpenDBTable: Boolean; +begin + Result := False; + if InternalOpenDB = False then Exit; + try + if FQuery.Active then FQuery.Close; + FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrd(FTableName); + FQuery.Open; + GetRecordCount; + except + on E: Exception do + DoOnError(E); + end; + Result := FQuery.Active; + if Result then DoConvertNewTable; +end; + +function TSQliteData.ConvertNewTableIF: Boolean; +begin + Result := False; +end; + +procedure TSQliteData.DoConvertNewTable; +var + qactive: Boolean; +begin + if not ConvertNewTableIF then Exit; + if not FConn.Connected then Exit; + try + qactive := FQuery.Active; + if FQuery.Active then FQuery.Close; + with FConn do + begin + ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd('temp' + FTableName)); + ExecuteDirect('CREATE TABLE ' + QuotedStrd('temp' + FTableName) + #13#10 + FCreateParams); + ExecuteDirect('INSERT INTO ' + QuotedStrd('temp' + FTableName) + ' SELECT * FROM ' + + QuotedStrd(FTableName)); + ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrd('temp' + FTableName) + ' RENAME TO ' + + QuotedStrd(FTableName)); + end; + FTrans.Commit; + if qactive <> FQuery.Active then + FQuery.Active := qactive; + except + FTrans.Rollback; + end; +end; + +procedure TSQliteData.GetRecordCount; +begin + if FQuery.Active then begin + FQuery.Last; + FRecordCount := FQuery.RecordCount; + FQuery.Refresh; + end + else FRecordCount := 0; +end; + +procedure TSQliteData.SetRecordCount(const AValue: Integer); +begin + if FRecordCount = AValue then Exit; + FRecordCount := AValue; +end; + +procedure TSQliteData.IncRecordCount(const N: Integer); +begin + Inc(FRecordCount, N); +end; + +procedure TSQliteData.Vacuum; +var + qactive: Boolean; +begin + if FConn.Connected = False then Exit; + try + qactive := FQuery.Active; + if FQuery.Active then FQuery.Close; + FConn.ExecuteDirect('END TRANSACTION'); + try + FConn.ExecuteDirect('VACUUM'); + finally + FConn.ExecuteDirect('BEGIN TRANSACTION'); + if FQuery.Active <> qactive then + FQuery.Active := qactive; + end; + except + on E: Exception do + DoOnError(E); + end; +end; + +constructor TSQliteData.Create; +begin + FConn := TSQLite3ConnectionH.Create(nil); + FTrans := TSQLTransaction.Create(nil); + FQuery := TSQLQuery.Create(nil); + FConn.CharSet := 'UTF8'; + FConn.Transaction := FTrans; + FQuery.DataBase := FTrans.DataBase; + FQuery.Transaction := FTrans; + AutoApplyUpdates := True; + FRecordCount := 0; + FFilename := ''; + FTableName := 'maintable'; + FCreateParams := ''; +end; + +destructor TSQliteData.Destroy; +begin + Self.Close; + FConn.Free; + FQuery.Free; + FTrans.Free; + inherited Destroy; +end; + +function TSQliteData.Open: Boolean; +begin + Result := False; + if FFilename = '' then Exit; + if FCreateParams = '' then Exit; + if not FileExistsUTF8(FFilename) then + Result := CreateDBTable + else + Result := OpenDBTable; +end; + +procedure TSQliteData.Close; +begin + if not FConn.Connected then Exit; + try + Save; + Vacuum; + FQuery.Close; + FTrans.Active := False; + FConn.Close; + FRecordCount := 0; + except + on E: Exception do + DoOnError(E); + end; +end; + +procedure TSQliteData.Refresh(RecheckDataCount: Boolean); +begin + if not FConn.Connected then Exit; + if FQuery.Active then + FQuery.Refresh + else + FQuery.Open; + if RecheckDataCount then + GetRecordCount; +end; + +procedure TSQliteData.Save; +var + qactive: Boolean; +begin + if FConn.Connected = False then Exit; + try + qactive := FQuery.Active; + if FQuery.Active then + begin + FQuery.ApplyUpdates; + FQuery.Close; + end; + FTrans.Commit; + if qactive <> qactive then + FQuery.Active := FQuery.Active; + if FQuery.Active then + GetRecordCount; + except + on E: Exception do + DoOnError(E); + end; +end; + +function TSQliteData.Connected: Boolean; +begin + Result := FConn.Connected and FQuery.Active; +end; + +end. From 163b491a0064346c58297502ec0d818a0ba4a5ad Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 14:00:50 +0800 Subject: [PATCH 1070/2794] project, debug build mode with lazlogger --- mangadownloader/md.lpi | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 51ea60c5f..67e3fac4d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -186,17 +186,14 @@ <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> - <Options> - <Win32> - <GraphicApplication Value="True"/> - </Win32> - </Options> </Linking> <Other> <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dLOGACTIVE +-dTRAPLAZLOGGER +-dSENDTOLAZLOGGER -dDEBUGWIN32 -dDEBUGLEAKS"/> <ExecuteAfter> From aec913549d35ed69cf8ed52108d0c52fecdf3787 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 14:01:36 +0800 Subject: [PATCH 1071/2794] added downloadedchaptersdb unit to work with dowloaded chapter list --- baseunits/DownloadedChaptersDB.pas | 169 +++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 baseunits/DownloadedChaptersDB.pas diff --git a/baseunits/DownloadedChaptersDB.pas b/baseunits/DownloadedChaptersDB.pas new file mode 100644 index 000000000..a517d744b --- /dev/null +++ b/baseunits/DownloadedChaptersDB.pas @@ -0,0 +1,169 @@ +unit DownloadedChaptersDB; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, SQLiteData, LazFileUtils; + +type + + { TDownloadedChaptersDB } + + TDownloadedChaptersDB = class(TSQliteData) + private + locklocate: TRTLCriticalSection; + function GetChapters(const AWebsiteLink: String): String; + procedure SetChapters(const AWebsiteLink: String; AValue: String); + public + constructor Create; + destructor Destroy; override; + procedure Delete(const AWebsiteLink: String); + property Chapters[const AWebsiteLink: String]: String read GetChapters write SetChapters; + function ImportFromIni(const AFilename: String): Boolean; + end; + +implementation + +function CleanStr(const S: String): String; +begin + Result := LowerCase(Trim(S)); + if Pos(' ', Result) > 0 then + Result := StringReplace(Result, ' ', '', [rfReplaceAll]); + while Pos(LineEnding + LineEnding, Result) > 0 do + Result := StringReplace(Result, LineEnding + LineEnding, LineEnding, [rfReplaceAll]); +end; + +{ TDownloadedChaptersDB } + +function TDownloadedChaptersDB.GetChapters(const AWebsiteLink: String): String; +begin + Result := ''; + if AWebsiteLink = '' then Exit; + if not Connected then Exit; + EnterCriticalsection(locklocate); + with Table do + try + if Locate('websitelink', LowerCase(AWebsiteLink), []) then + Result := Fields[1].AsString; + finally + LeaveCriticalsection(locklocate); + end; +end; + +procedure TDownloadedChaptersDB.SetChapters(const AWebsiteLink: String; AValue: String); +var + dc, ds: TStringList; + c, s: String; + i: Integer; +begin + if AWebsiteLink = '' then Exit; + if AValue = '' then Exit; + if not Connected then Exit; + EnterCriticalsection(locklocate); + with Table do + try + if Locate('websitelink', LowerCase(AWebsiteLink), []) then + begin + c := CleanStr(AValue); + s := Fields[1].AsString; + if c = s then Exit; + dc := TStringList.Create; + ds := TStringList.Create; + try + dc.AddText(c); + ds.Sorted := True; + ds.Duplicates := dupIgnore; + ds.AddText(s); + for i := 0 to dc.Count - 1 do + begin + dc[i] := Trim(dc[i]); + if dc[i] <> '' then + ds.Add(dc[i]); + end; + Edit; + try + Fields[1].AsString := ds.Text; + Post; + except + CancelUpdates; + end; + finally + dc.Free; + ds.Free; + end; + end + else + begin + Append; + try + Fields[0].AsString := LowerCase(AWebsiteLink); + Fields[1].AsString := CleanStr(AValue); + Post; + IncRecordCount; + except + CancelUpdates; + end; + end; + finally + LeaveCriticalsection(locklocate); + end; +end; + +constructor TDownloadedChaptersDB.Create; +begin + inherited Create; + InitCriticalSection(locklocate); + AutoApplyUpdates := True; + TableName := 'downloadedchapters'; + CreateParams := + 'websitelink VARCHAR(3000) NOT NULL PRIMARY KEY,' + + 'chapters TEXT'; +end; + +destructor TDownloadedChaptersDB.Destroy; +begin + inherited Destroy; + DoneCriticalsection(locklocate); +end; + +procedure TDownloadedChaptersDB.Delete(const AWebsiteLink: String); +begin + if not Connected then Exit; + EnterCriticalsection(locklocate); + with Table do + try + if Locate('websitelink', LowerCase(AWebsiteLink), []) then + Delete; + finally + LeaveCriticalsection(locklocate); + end; +end; + +function TDownloadedChaptersDB.ImportFromIni(const AFilename: String): Boolean; +var + dc: TStringList; + i: Integer; +begin + Result := False; + if not Connected then Exit; + if not FileExistsUTF8(AFilename) then Exit; + dc := TStringList.Create; + try + dc.LoadFromFile(AFilename); + if dc.Count > 0 then + i := 0; + while i < dc.Count - 2 do + begin + Chapters[dc[i]] := StringReplace(dc[i + 1], '!%~', LineEnding, [rfReplaceAll]); + Inc(i, 2); + end; + Result := True; + finally + dc.Free; + end; +end; + +end. + From 8135e62c771c414613899dae585ab6faffacf55b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 14:02:18 +0800 Subject: [PATCH 1072/2794] integrate downloadedchaptersdb --- baseunits/uBaseUnit.pas | 35 ++++--- baseunits/uDownloadsManager.pas | 167 +++++------------------------- baseunits/uFavoritesManager.pas | 4 +- baseunits/uSilentThread.pas | 4 +- mangadownloader/forms/frmMain.lfm | 6 -- mangadownloader/forms/frmMain.pas | 13 +-- 6 files changed, 48 insertions(+), 181 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 91a512f34..41ff7f37d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -197,23 +197,24 @@ interface ('γ', 'γ') ); - README_FILE = 'readme.rtf'; - WORK_FOLDER = 'works' + PathDelim; - WORK_FILE = 'works.ini'; - DOWNLOADEDCHAPTERS_FILE = 'downloadedchapters.ini'; - FAVORITES_FILE = 'favorites.ini'; - IMAGE_FOLDER = 'images' + PathDelim; - DATA_EXT = '.dat'; - DBDATA_EXT = '.db'; - CONFIG_FOLDER = 'config' + PathDelim; - CONFIG_FILE = 'config.ini'; - CONFIG_ADVANCED = 'advanced.ini'; - REVISION_FILE = 'revision.ini'; - UPDATE_FILE = 'updates.ini'; - MANGALIST_FILE = 'mangalist.ini'; - LANGUAGE_FILE = 'languages.ini'; - CHANGELOG_FILE = 'changelog.txt'; - ACCOUNTS_FILE = 'accounts.db'; + README_FILE = 'readme.rtf'; + WORK_FOLDER = 'works' + PathDelim; + WORK_FILE = 'works.ini'; + DOWNLOADEDCHAPTERS_FILE = 'downloadedchapters.ini'; + DOWNLOADEDCHAPTERSDB_FILE = 'downloadedchapters.db'; + FAVORITES_FILE = 'favorites.ini'; + IMAGE_FOLDER = 'images' + PathDelim; + DATA_EXT = '.dat'; + DBDATA_EXT = '.db'; + CONFIG_FOLDER = 'config' + PathDelim; + CONFIG_FILE = 'config.ini'; + CONFIG_ADVANCED = 'advanced.ini'; + REVISION_FILE = 'revision.ini'; + UPDATE_FILE = 'updates.ini'; + MANGALIST_FILE = 'mangalist.ini'; + LANGUAGE_FILE = 'languages.ini'; + CHANGELOG_FILE = 'changelog.txt'; + ACCOUNTS_FILE = 'accounts.db'; UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/'; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ea4b68c81..cb46a5e6b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface lazutf8classes, LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, - uFMDThread, uMisc, SimpleLogger, dateutils; + uFMDThread, uMisc, DownloadedChaptersDB, SimpleLogger, dateutils; type TDownloadManager = class; @@ -169,9 +169,9 @@ TDownloadManager = class maxDLTasks, // max. download threads per task maxDLThreadsPerTask: Integer; - // current chapterLinks which thread is processing - DownloadedChaptersListFile: TStringList; + //downloaded chapter list database + DownloadedChapters: TDownloadedChaptersDB; //exit counter ExitWaitOK: Boolean; @@ -181,8 +181,6 @@ TDownloadManager = class property Count: Integer read GetTaskCount; - procedure BackupDownloadedChaptersList; - procedure Restore; procedure Backup; @@ -190,8 +188,6 @@ TDownloadManager = class procedure ClearTransferRate; // These methods relate to highlight downloaded chapters. - procedure AddToDownloadedChaptersList(const ALink, AValue: String); overload; - procedure AddToDownloadedChaptersList(const Alink: String; AValue: TStrings); overload; procedure GetDownloadedChaptersState(const Alink: String; var Chapters: array of TChapterStateItem); @@ -1639,10 +1635,13 @@ constructor TDownloadManager.Create; DownloadManagerFile := TIniFile.Create(WORK_FOLDER + WORK_FILE); DownloadManagerFile.CacheUpdates := True; - DownloadedChaptersListFile := TStringList.Create; - + DownloadedChapters := TDownloadedChaptersDB.Create; + DownloadedChapters.Filename := WORK_FOLDER + DOWNLOADEDCHAPTERSDB_FILE; + DownloadedChapters.OnError := MainForm.ExceptionHandler; + DownloadedChapters.Open; if FileExistsUTF8(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE) then - DownloadedChaptersListFile.LoadFromFile(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE); + if DownloadedChapters.ImportFromIni(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE) then + DeleteFileUTF8(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE); Containers := TFPList.Create; isFinishTaskAccessed := False; @@ -1664,26 +1663,13 @@ destructor TDownloadManager.Destroy; CS_DownloadManager_Task.Release; end; FreeAndNil(Containers); - FreeAndNil(DownloadedChaptersListFile); FreeAndNil(DownloadManagerFile); + DownloadedChapters.Free; CS_DownloadedChapterList.Free; CS_DownloadManager_Task.Free; inherited Destroy; end; -procedure TDownloadManager.BackupDownloadedChaptersList; -begin - if CS_DownloadedChapterList.TryEnter then - begin - CS_DownloadedChapterList.Acquire; - try - DownloadedChaptersListFile.SaveToFile(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE); - finally - CS_DownloadedChapterList.Release; - end; - end; -end; - procedure TDownloadManager.Restore; var tid, s: String; @@ -1851,129 +1837,24 @@ procedure TDownloadManager.ClearTransferRate; end; end; -procedure TDownloadManager.AddToDownloadedChaptersList(const ALink, AValue: String); -var - st: TStringList; -begin - if (ALink <> '') and (AValue <> '') then - begin - st := TStringList.Create; - try - GetParams(st, AValue); - AddToDownloadedChaptersList(ALink, st); - finally - St.Free; - end; - end; -end; - -procedure TDownloadManager.AddToDownloadedChaptersList(const Alink: String; - AValue: TStrings); -var - i, p, q: Integer; - Ch, dlCh: TStringList; -begin - if (Alink <> '') and (AValue.Count > 0) then - begin - CS_DownloadedChapterList.Acquire; - Ch := TStringList.Create; - dlCh := TStringList.Create; - try - p := -1; - //locate the link - if DownloadedChaptersListFile.Count > 1 then - for i := 0 to DownloadedChaptersListFile.Count - 1 do - if SameText(Alink, DownloadedChaptersListFile[i]) then - begin - p := i; - if i + 1 < DownloadedChaptersListFile.Count then - GetParams(dlCh, DownloadedChaptersListFile[i + 1]); - Break; - end; - - //remove if links found on downloadedchapterlist - Ch.Assign(AValue); - if dlCh.Count > 0 then - begin - dlCh.Sorted := True; - i := 0; - while i < Ch.Count do - begin - if dlCh.Find(Ch[i], q) then - Ch.Delete(i) - else - Inc(i); - end; - end; - - //merge the links - if p > -1 then - begin - if p + 1 < DownloadedChaptersListFile.Count then - DownloadedChaptersListFile[p + 1] := DownloadedChaptersListFile[p + 1] + SetParams(Ch) - else - DownloadedChaptersListFile.Add(SetParams(Ch)); - end - else - begin - //if it's new data - DownloadedChaptersListFile.Add(Alink); - DownloadedChaptersListFile.Add(SetParams(Ch)); - end; - finally - dlCh.Free; - Ch.Free; - CS_DownloadedChapterList.Release; - end; - end; -end; - procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; var Chapters: array of TChapterStateItem); var - dlCh: TStringList; - i, p, q: Integer; + s: TStringList; + i, p: Integer; begin - if (Alink <> '') and (Length(Chapters) > 0) and - (DownloadedChaptersListFile.Count > 0) then - begin - CS_DownloadedChapterList.Acquire; - try - p := -1; - //locate the link - for i := 0 to DownloadedChaptersListFile.Count - 1 do - if SameText(Alink, DownloadedChaptersListFile[i]) then - begin - if i + 1 < DownloadedChaptersListFile.Count then - if DownloadedChaptersListFile[i + 1] <> '' then - p := i + 1; - Break; - end; - - //compare the content - if p > -1 then - begin - dlCh := TStringList.Create; - try - GetParams(dlCh, DownloadedChaptersListFile[p]); - if dlCh.Count > 0 then - begin - dlCh.Sorted := True; - for i := Low(Chapters) to High(Chapters) do - Chapters[i].Downloaded := dlCh.Find(Chapters[i].Link, q); - end; - finally - dlCh.Free; - end; - end - else - begin - for i := Low(Chapters) to High(Chapters) do - Chapters[i].Downloaded := False; - end; - finally - CS_DownloadedChapterList.Release; - end; + s := TStringList.Create; + try + s.Sorted := True; + s.AddText(DownloadedChapters.Chapters[Alink]); + if s.Count > 0 then + for i := Low(Chapters) to High(Chapters) do + Chapters[i].Downloaded := s.Find(LowerCase(Chapters[i].Link), p) + else + for i := Low(Chapters) to High(Chapters) do + Chapters[i].Downloaded := False; + finally + s.Free; end; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 8205eb9b0..11d2f84d0 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -713,8 +713,8 @@ procedure TFavoriteManager.ShowResult; FavoriteInfo.downloadedChapterList + SetParams(NewMangaInfo.chapterLinks); //save to downloaded chapter list from dlmanager. - DLManager.AddToDownloadedChaptersList( - FavoriteInfo.Website + FavoriteInfo.Link, NewMangaInfo.chapterLinks); + DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := + NewMangaInfo.chapterLinks.Text; end; Inc(counter); end; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 26fb3e4c0..c583a94a5 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -385,8 +385,8 @@ procedure TSilentThread.MainThreadAfterChecking; // save downloaded chapters if Info.mangaInfo.chapterLinks.Count > 0 then begin - DLManager.AddToDownloadedChaptersList(Info.mangaInfo.website + - URL, Info.mangaInfo.chapterLinks); + DLManager.DownloadedChapters.Chapters[Info.mangaInfo.website + URL]:= + Info.mangaInfo.chapterLinks.Text; FavoriteManager.AddToDownloadedChaptersList(Info.mangaInfo.website, URL, Info.mangaInfo.chapterLinks); end; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b54381099..69db5e38d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -5569,12 +5569,6 @@ object MainForm: TMainForm 82F2107B87EA008398D00066779A } end - object itSaveDownloadedList: TIdleTimer - Interval = 300000 - OnTimer = itSaveDownloadedListTimer - left = 752 - top = 120 - end object IconDL: TImageList left = 24 top = 184 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d20dc4169..7b186b60e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -213,7 +213,6 @@ TMainForm = class(TForm) gbOptionFavorites: TGroupBox; gbBatoto: TGroupBox; IconList: TImageList; - itSaveDownloadedList: TIdleTimer; itRefreshDLInfo: TIdleTimer; itCheckFav: TIdleTimer; itAnimate: TIdleTimer; @@ -399,7 +398,6 @@ TMainForm = class(TForm) procedure itRefreshDLInfoStartTimer(Sender: TObject); procedure itRefreshDLInfoStopTimer(Sender: TObject); procedure itRefreshDLInfoTimer(Sender: TObject); - procedure itSaveDownloadedListTimer(Sender: TObject); procedure itStartupTimer(Sender: TObject); procedure medURLCutClick(Sender: TObject); procedure medURLCopyClick(Sender: TObject); @@ -1203,7 +1201,6 @@ procedure TMainForm.CloseNow; Writelog_D(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; - itSaveDownloadedList.Enabled := False; itRefreshDLInfo.Enabled := False; itCheckFav.Enabled := False; itAnimate.Enabled := False; @@ -1213,7 +1210,6 @@ procedure TMainForm.CloseNow; Writelog_D(Self.ClassName+'.CloseNow, backup all data to file'); //Backup data DLManager.Backup; - DLManager.BackupDownloadedChaptersList; isExiting := True; FavoriteManager.Backup; SaveOptions; @@ -1409,11 +1405,6 @@ procedure TMainForm.itRefreshDLInfoTimer(Sender: TObject); vtDownload.Repaint; end; -procedure TMainForm.itSaveDownloadedListTimer(Sender: TObject); -begin - DLManager.BackupDownloadedChaptersList; -end; - procedure TMainForm.itStartupTimer(Sender: TObject); begin itStartup.Enabled := False; @@ -1950,8 +1941,8 @@ procedure TMainForm.btDownloadClick(Sender: TObject); UpdateVtDownload; DLManager.CheckAndActiveTask; - DLManager.AddToDownloadedChaptersList( - mangaInfo.website + mangaInfo.link, DLManager.Items[pos].ChapterLinks); + DLManager.DownloadedChapters.Chapters[mangaInfo.website + mangaInfo.link]:= + DLManager.Items[pos].ChapterLinks.Text; FavoriteManager.AddToDownloadedChaptersList( mangaInfo.website, mangaInfo.link, DLManager.Items[pos].ChapterLinks); clbChapterList.Repaint; From 175630b30947adf1e70a825cb35808f941243967 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 14:30:53 +0800 Subject: [PATCH 1073/2794] append work_folder, config_folder --- .../NineManga/directory_page_number.inc | 5 +---- baseunits/uBaseUnit.pas | 20 +++++++++---------- baseunits/uDownloadsManager.pas | 10 +++++----- baseunits/uFavoritesManager.pas | 2 +- mangadownloader/forms/frmMain.pas | 13 ++++++------ mangadownloader/md.lpr | 4 ++-- 6 files changed, 25 insertions(+), 29 deletions(-) diff --git a/baseunits/includes/NineManga/directory_page_number.inc b/baseunits/includes/NineManga/directory_page_number.inc index e67808db8..01701e22b 100644 --- a/baseunits/includes/NineManga/directory_page_number.inc +++ b/baseunits/includes/NineManga/directory_page_number.inc @@ -1,7 +1,6 @@ function GetNineMangaDirectoryPageNumber: Byte; var SiteID: Cardinal; - iniadv: TIniFile; p: Integer; begin Source.Free; @@ -9,9 +8,7 @@ BROWSER_INVERT := True; //I can't get manga directory total pages. Its not available on any page //The only option to get total pages is just checking manually with browser :( - iniadv := TIniFile.Create(CONFIG_FOLDER + CONFIG_ADVANCED); - p := iniadv.ReadInteger('UpdateListDirectoryPageNumber', website, -1); - iniadv.Free; + p := INIAdvanced.ReadInteger('UpdateListDirectoryPageNumber', website, -1); if p > 0 then Page := p else diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 41ff7f37d..aa03ee36d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -199,22 +199,22 @@ interface README_FILE = 'readme.rtf'; WORK_FOLDER = 'works' + PathDelim; - WORK_FILE = 'works.ini'; - DOWNLOADEDCHAPTERS_FILE = 'downloadedchapters.ini'; - DOWNLOADEDCHAPTERSDB_FILE = 'downloadedchapters.db'; - FAVORITES_FILE = 'favorites.ini'; + WORK_FILE = WORK_FOLDER + 'works.ini'; + DOWNLOADEDCHAPTERS_FILE = WORK_FOLDER + 'downloadedchapters.ini'; + DOWNLOADEDCHAPTERSDB_FILE = WORK_FOLDER + 'downloadedchapters.db'; + FAVORITES_FILE = WORK_FOLDER + 'favorites.ini'; IMAGE_FOLDER = 'images' + PathDelim; DATA_EXT = '.dat'; DBDATA_EXT = '.db'; CONFIG_FOLDER = 'config' + PathDelim; - CONFIG_FILE = 'config.ini'; - CONFIG_ADVANCED = 'advanced.ini'; - REVISION_FILE = 'revision.ini'; - UPDATE_FILE = 'updates.ini'; - MANGALIST_FILE = 'mangalist.ini'; + CONFIG_FILE = CONFIG_FOLDER + 'config.ini'; + CONFIG_ADVANCED = CONFIG_FOLDER + 'advanced.ini'; + REVISION_FILE = CONFIG_FOLDER + 'revision.ini'; + UPDATE_FILE = CONFIG_FOLDER + 'updates.ini'; + MANGALIST_FILE = CONFIG_FOLDER + 'mangalist.ini'; + ACCOUNTS_FILE = CONFIG_FOLDER + 'accounts.db'; LANGUAGE_FILE = 'languages.ini'; CHANGELOG_FILE = 'changelog.txt'; - ACCOUNTS_FILE = 'accounts.db'; UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/'; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index cb46a5e6b..d308f0d1c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1632,16 +1632,16 @@ constructor TDownloadManager.Create; CS_DownloadManager_Task := TCriticalSection.Create; CS_DownloadedChapterList := TCriticalSection.Create; - DownloadManagerFile := TIniFile.Create(WORK_FOLDER + WORK_FILE); + DownloadManagerFile := TIniFile.Create(WORK_FILE); DownloadManagerFile.CacheUpdates := True; DownloadedChapters := TDownloadedChaptersDB.Create; - DownloadedChapters.Filename := WORK_FOLDER + DOWNLOADEDCHAPTERSDB_FILE; + DownloadedChapters.Filename := DOWNLOADEDCHAPTERSDB_FILE; DownloadedChapters.OnError := MainForm.ExceptionHandler; DownloadedChapters.Open; - if FileExistsUTF8(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE) then - if DownloadedChapters.ImportFromIni(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE) then - DeleteFileUTF8(WORK_FOLDER + DOWNLOADEDCHAPTERS_FILE); + if FileExistsUTF8(DOWNLOADEDCHAPTERS_FILE) then + if DownloadedChapters.ImportFromIni(DOWNLOADEDCHAPTERS_FILE) then + DeleteFileUTF8(DOWNLOADEDCHAPTERS_FILE); Containers := TFPList.Create; isFinishTaskAccessed := False; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 11d2f84d0..ffc407e3c 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -427,7 +427,7 @@ constructor TFavoriteManager.Create; inherited Create; CS_Favorites := TCriticalSection.Create; isRunning := False; - favoritesFile := TIniFile.Create(WORK_FOLDER + FAVORITES_FILE); + favoritesFile := TIniFile.Create(FAVORITES_FILE); favoritesFile.CacheUpdates := True; FFavorites := TFPList.Create; Restore; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7b186b60e..333fec4ec 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -975,7 +975,6 @@ destructor TOpenDBThread.Destroy; procedure TMainForm.FormCreate(Sender: TObject); begin Randomize; - fmdDirectory := CleanAndExpandDirectory(GetCurrentDirUTF8); SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), FormatDateTime('dd-mm-yyyy', Now)])); Writelog_I(['Starting ',QuotedStrd(Application.Title),' [PID:',GetProcessID,'] [HANDLE:',IntToStr(GetCurrentProcess),']']); @@ -1005,10 +1004,10 @@ procedure TMainForm.FormCreate(Sender: TObject); PrevWindowState := wsNormal; // account - accountmanagerdb.InitAccountManager(fmdDirectory + CONFIG_FOLDER + ACCOUNTS_FILE); + accountmanagerdb.InitAccountManager(fmdDirectory + ACCOUNTS_FILE); // advanced settings - INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_ADVANCED); + INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_ADVANCED); // main dataprocess dataProcess := TDBDataProcess.Create; @@ -1030,19 +1029,19 @@ procedure TMainForm.FormCreate(Sender: TObject); mangaInfo := TMangaInfo.Create; // Load config.ini - options := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + CONFIG_FILE); + options := TIniFile.Create(fmdDirectory + CONFIG_FILE); options.CacheUpdates := False; options.Options := options.Options-[ifoStripQuotes]; // Load revision.ini - revisionIni := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + REVISION_FILE); + revisionIni := TIniFile.Create(fmdDirectory + REVISION_FILE); // Load updates.ini - updates := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + UPDATE_FILE); + updates := TIniFile.Create(fmdDirectory + UPDATE_FILE); updates.CacheUpdates := False; // Load mangalist.ini - mangalistIni := TIniFile.Create(fmdDirectory + CONFIG_FOLDER + MANGALIST_FILE); + mangalistIni := TIniFile.Create(fmdDirectory + MANGALIST_FILE); mangalistIni.CacheUpdates := True; // generate tvDownloadFilter nodes diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 36cfef2cd..92379b20a 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -21,8 +21,8 @@ {$R *.res} begin - with TIniFile.Create(CleanAndExpandDirectory(GetCurrentDirUTF8) + - CONFIG_FOLDER + CONFIG_FILE) do + fmdDirectory := CleanAndExpandDirectory(GetCurrentDirUTF8); + with TIniFile.Create(fmdDirectory + CONFIG_FILE) do try CheckInstance := ReadBool('general', 'OneInstanceOnly', True); finally From 2e26744893a979b1853a99f2011eacb8eda9f42b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 15:12:34 +0800 Subject: [PATCH 1074/2794] make all required path to be variable, and set at runtime possible for different config path at runtime (appdata/portable) --- baseunits/DBDataProcess.pas | 32 ++++++------ baseunits/uBaseUnit.pas | 81 +++++++++++++++++++++---------- baseunits/uData.pas | 2 +- baseunits/uUpdateDBThread.pas | 10 ++-- baseunits/uUpdateThread.pas | 6 +-- mangadownloader/forms/frmMain.pas | 39 +++++++-------- mangadownloader/md.lpr | 3 +- 7 files changed, 99 insertions(+), 74 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 94ee22f48..9d907a546 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -189,7 +189,7 @@ function QuotedLike(const S: String): String; function DBDataFilePath(const AWebsite: String): String; begin - Result := fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT; + Result := DATA_FOLDER + AWebsite + DBDATA_EXT; end; procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); @@ -200,7 +200,7 @@ procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); rcount: Integer; i: Integer; begin - filepath := fmdDirectory + DATA_FOLDER + AWebsite; + filepath := DATA_FOLDER + AWebsite; if FileExistsUTF8(filepath + DATA_EXT) then begin rawdata := TDataProcess.Create; @@ -243,8 +243,8 @@ function DataFileExist(const AWebsite: String): Boolean; begin if AWebsite = '' then Exit(False); - Result := FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DATA_EXT) or - FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + Result := FileExistsUTF8(DATA_FOLDER + AWebsite + DATA_EXT) or + FileExistsUTF8(DATA_FOLDER + AWebsite + DBDATA_EXT); end; procedure CopyDBDataProcess(const AWebsite, NWebsite: String); @@ -254,8 +254,8 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: String); if DataFileExist(AWebsite) then begin try - CopyFile(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, + CopyFile(DATA_FOLDER + AWebsite + DBDATA_EXT, + DATA_FOLDER + NWebsite + DBDATA_EXT, [cffPreserveTime, cffOverwriteFile], True); except on E: Exception do @@ -268,28 +268,28 @@ function DeleteDBDataProcess(const AWebsite: String): Boolean; var tryc: Integer; begin - Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + Result := not FileExistsUTF8(DATA_FOLDER + AWebsite + DBDATA_EXT); if Result = False then begin tryc := 0; - while not DeleteFileUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT) do + while not DeleteFileUTF8(DATA_FOLDER + AWebsite + DBDATA_EXT) do begin if tryc > 3 then Break; Inc(tryc); Sleep(250); end; - Result := not FileExistsUTF8(fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + Result := not FileExistsUTF8(DATA_FOLDER + AWebsite + DBDATA_EXT); end; end; procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); begin - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT) then + if FileExistsUTF8(DATA_FOLDER + NWebsite + DBDATA_EXT) then begin if DeleteDBDataProcess(AWebsite) then - RenameFileUTF8(fmdDirectory + DATA_FOLDER + NWebsite + DBDATA_EXT, - fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + RenameFileUTF8(DATA_FOLDER + NWebsite + DBDATA_EXT, + DATA_FOLDER + AWebsite + DBDATA_EXT); end; end; @@ -618,7 +618,7 @@ function TDBDataProcess.Connect(AWebsite: String): Boolean; FWebsite := AWebsite; if FWebsite = '' then Exit; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + filepath := DATA_FOLDER + FWebsite + DBDATA_EXT; if not FileExistsUTF8(filepath) then Exit; Result := InternalOpen(filepath); @@ -634,7 +634,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; FWebsite := AWebsite; if FWebsite = '' then Exit; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + filepath := DATA_FOLDER + FWebsite + DBDATA_EXT; if not FileExistsUTF8(filepath) then ConvertDataProccessToDB(AWebsite, True); if not FileExistsUTF8(filepath) then @@ -741,7 +741,7 @@ procedure TDBDataProcess.Backup(AWebsite: String); begin with TSQLite3Backup.Create do try - Backup(FConn, fmdDirectory + DATA_FOLDER + AWebsite + DBDATA_EXT); + Backup(FConn, DATA_FOLDER + AWebsite + DBDATA_EXT); finally Free; end; @@ -1064,7 +1064,7 @@ procedure TDBDataProcess.CreateDatabase(AWebsite: String); if AWebsite <> '' then FWebsite := AWebsite; if FWebsite = '' then Exit; Close; - filepath := fmdDirectory + DATA_FOLDER + FWebsite + DBDATA_EXT; + filepath := DATA_FOLDER + FWebsite + DBDATA_EXT; if FileExistsUTF8(filepath) then DeleteFileUTF8(filepath); InternalOpen(filepath); diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index aa03ee36d..d799b1a81 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -197,25 +197,6 @@ interface ('γ', 'γ') ); - README_FILE = 'readme.rtf'; - WORK_FOLDER = 'works' + PathDelim; - WORK_FILE = WORK_FOLDER + 'works.ini'; - DOWNLOADEDCHAPTERS_FILE = WORK_FOLDER + 'downloadedchapters.ini'; - DOWNLOADEDCHAPTERSDB_FILE = WORK_FOLDER + 'downloadedchapters.db'; - FAVORITES_FILE = WORK_FOLDER + 'favorites.ini'; - IMAGE_FOLDER = 'images' + PathDelim; - DATA_EXT = '.dat'; - DBDATA_EXT = '.db'; - CONFIG_FOLDER = 'config' + PathDelim; - CONFIG_FILE = CONFIG_FOLDER + 'config.ini'; - CONFIG_ADVANCED = CONFIG_FOLDER + 'advanced.ini'; - REVISION_FILE = CONFIG_FOLDER + 'revision.ini'; - UPDATE_FILE = CONFIG_FOLDER + 'updates.ini'; - MANGALIST_FILE = CONFIG_FOLDER + 'mangalist.ini'; - ACCOUNTS_FILE = CONFIG_FOLDER + 'accounts.db'; - LANGUAGE_FILE = 'languages.ini'; - CHANGELOG_FILE = 'changelog.txt'; - UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/'; OPTION_MANGALIST = 0; @@ -534,10 +515,31 @@ interface '/series' ); -var - FMD_VERSION_NUMBER: String = ''; - - DATA_FOLDER: String = 'data' + PathDelim; + DATA_EXT = '.dat'; + DBDATA_EXT = '.db'; + UPDATER_EXE = 'updater.exe'; + ZIP_EXE = '7za.exe'; + +var + FMD_VERSION_NUMBER, + FMD_DIRECTORY, + WORK_FOLDER, + WORK_FILE, + DOWNLOADEDCHAPTERS_FILE, + DOWNLOADEDCHAPTERSDB_FILE, + FAVORITES_FILE, + CONFIG_FOLDER, + CONFIG_FILE, + CONFIG_ADVANCED, + REVISION_FILE, + UPDATE_FILE, + MANGALIST_FILE, + ACCOUNTS_FILE, + DATA_FOLDER, + IMAGE_FOLDER, + LANGUAGE_FILE, + CHANGELOG_FILE, + README_FILE: String; {$IFDEF WINDOWS} DEFAULT_PATH: String = '\downloads'; @@ -573,8 +575,6 @@ interface OptionProxyUser: String = ''; OptionProxyPass: String = ''; - fmdDirectory: String; - OptionLetFMDDo: TFMDDo = DO_NOTHING; OptionChangeUnicodeCharacter: Boolean = False; @@ -748,6 +748,8 @@ THTMLForm = class property Data: TStringList read fdata; end; +// Set base directory +procedure SetFMDdirectory(const ADir: String); // Get current binary version function GetCurrentBinVersion: String; // Remove Unicode @@ -1042,6 +1044,32 @@ function NTSetPrivilege(sPrivilege: String; bEnabled: Boolean): Boolean; {$ENDIF} +procedure SetFMDdirectory(const ADir: String); +begin + FMD_DIRECTORY := CleanAndExpandDirectory(ADir); + + WORK_FOLDER := FMD_DIRECTORY + 'works' + PathDelim; + WORK_FILE := WORK_FOLDER + 'works.ini'; + DOWNLOADEDCHAPTERS_FILE := WORK_FOLDER + 'downloadedchapters.ini'; + DOWNLOADEDCHAPTERSDB_FILE := WORK_FOLDER + 'downloadedchapters.db'; + FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; + + CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; + CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; + CONFIG_ADVANCED := CONFIG_FOLDER + 'advanced.ini'; + REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; + UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; + MANGALIST_FILE := CONFIG_FOLDER + 'mangalist.ini'; + ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; + + DATA_FOLDER := FMD_DIRECTORY + 'data' + PathDelim; + + IMAGE_FOLDER := FMD_DIRECTORY + 'images' + PathDelim; + LANGUAGE_FILE := FMD_DIRECTORY + 'languages.ini'; + CHANGELOG_FILE := FMD_DIRECTORY + 'changelog.txt'; + README_FILE := FMD_DIRECTORY + 'readme.rtf'; +end; + function GetCurrentBinVersion: String; var AppVerInfo: TStringList; @@ -1142,7 +1170,7 @@ procedure CheckPath(const S: String); if wS[2] <> ':' then begin {$IFDEF WINDOWS} - lcS2 := CorrectFilePath(fmdDirectory); + lcS2 := CorrectFilePath(FMD_DIRECTORY); {$ELSE} lcS2 := ''; {$ENDIF} @@ -3988,6 +4016,7 @@ function HeaderByName(const AHeaders: TStrings; const AHeaderName: String): Stri end; initialization + SetFMDdirectory(GetCurrentDirUTF8); FMD_VERSION_NUMBER := GetCurrentBinVersion; {$IFDEF WINDOWS} DEFAULT_PATH := GetCurrentDir + DirectorySeparator + 'downloads'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 01f184bca..e3b7ee14e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -246,7 +246,7 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; l: TStringList; Filename: String; begin - Filename := fmdDirectory + DATA_FOLDER + website; + Filename := DATA_FOLDER + website; Data.Clear; searchPos.Clear; diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 6cef62fca..c4cd07479 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -67,10 +67,10 @@ procedure TUpdateDBThread.ExtractFile; var Sza, datapath, filepath: String; begin - Sza := fmdDirectory + '7za.exe'; + Sza := FMD_DIRECTORY + ZIP_EXE; if not FileExistsUTF8(Sza) then Exit; - datapath := fmdDirectory + DATA_FOLDER; + datapath := DATA_FOLDER; filepath := datapath + websiteName; if FileExistsUTF8(filepath + '.7z') then filepath += '.7z' @@ -133,10 +133,10 @@ procedure TUpdateDBThread.Execute; begin try Synchronize(MainThreadShowGetting); - RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', + RunExternalProcess(FMD_DIRECTORY + UPDATER_EXE, ['-r' , '3', '-d', GetMangaDatabaseURL(websiteName), '--lang', SimpleTranslator.LastSelected]); - if FileExistsUTF8(fmdDirectory + DATA_FOLDER + websiteName + '.7z') or - FileExistsUTF8(fmdDirectory + DATA_FOLDER + websiteName + '.zip') then + if FileExistsUTF8(DATA_FOLDER + websiteName + '.7z') or + FileExistsUTF8(DATA_FOLDER + websiteName + '.zip') then Synchronize(MainThreadRefreshList) else Synchronize(MainThreadShowEndGetting); diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 76d7996ba..cb6e40399 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -315,10 +315,10 @@ procedure TUpdateListManagerThread.ExtractFile; var Sza, datapath, filepath: String; begin - Sza := fmdDirectory + '7za.exe'; + Sza := FMD_DIRECTORY + ZIP_EXE; if not FileExistsUTF8(Sza) then Exit; - datapath := fmdDirectory + DATA_FOLDER; + datapath := DATA_FOLDER; filepath := datapath + website; if FileExistsUTF8(filepath + '.7z') then filepath += '.7z' @@ -574,7 +574,7 @@ procedure TUpdateListManagerThread.Execute; Inc(websitePtr); FStatus := RS_GettingListFor + ' ' + website + ' ...'; Synchronize(MainThreadShowGetting); - RunExternalProcess(fmdDirectory + 'updater.exe', ['-r' , '3', '-d', + RunExternalProcess(FMD_DIRECTORY + UPDATER_EXE, ['-r' , '3', '-d', GetMangaDatabaseURL(website), '--lang', SimpleTranslator.LastSelected]); Synchronize(RefreshList); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 333fec4ec..5192d64a5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -996,18 +996,18 @@ procedure TMainForm.FormCreate(Sender: TObject); LoadAbout; // remove old updater - if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then - DeleteFileUTF8(fmdDirectory + 'old_updater.exe'); + if FileExistsUTF8(FMD_DIRECTORY + 'old_updater.exe') then + DeleteFileUTF8(FMD_DIRECTORY + 'old_updater.exe'); // TrayIcon TrayIcon.Icon.Assign(Application.Icon); PrevWindowState := wsNormal; // account - accountmanagerdb.InitAccountManager(fmdDirectory + ACCOUNTS_FILE); + accountmanagerdb.InitAccountManager(ACCOUNTS_FILE); // advanced settings - INIAdvanced := TIniFileR.Create(fmdDirectory + CONFIG_ADVANCED); + INIAdvanced := TIniFileR.Create(CONFIG_ADVANCED); // main dataprocess dataProcess := TDBDataProcess.Create; @@ -1029,19 +1029,19 @@ procedure TMainForm.FormCreate(Sender: TObject); mangaInfo := TMangaInfo.Create; // Load config.ini - options := TIniFile.Create(fmdDirectory + CONFIG_FILE); + options := TIniFile.Create(CONFIG_FILE); options.CacheUpdates := False; options.Options := options.Options-[ifoStripQuotes]; // Load revision.ini - revisionIni := TIniFile.Create(fmdDirectory + REVISION_FILE); + revisionIni := TIniFile.Create(REVISION_FILE); // Load updates.ini - updates := TIniFile.Create(fmdDirectory + UPDATE_FILE); + updates := TIniFile.Create(UPDATE_FILE); updates.CacheUpdates := False; // Load mangalist.ini - mangalistIni := TIniFile.Create(fmdDirectory + MANGALIST_FILE); + mangalistIni := TIniFile.Create(MANGALIST_FILE); mangalistIni.CacheUpdates := True; // generate tvDownloadFilter nodes @@ -1363,12 +1363,12 @@ procedure TMainForm.itMonitorTimer(Sender: TObject); else if DoAfterFMD = DO_UPDATE then begin - if FileExistsUTF8(fmdDirectory + 'updater.exe') then - CopyFile(fmdDirectory + 'updater.exe', fmdDirectory + 'old_updater.exe'); - if FileExistsUTF8(fmdDirectory + 'old_updater.exe') then + if FileExistsUTF8(FMD_DIRECTORY + UPDATER_EXE) then + CopyFile(FMD_DIRECTORY + UPDATER_EXE, FMD_DIRECTORY + 'old_' + UPDATER_EXE); + if FileExistsUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) then begin Self.CloseNow; - RunExternalProcess(fmdDirectory + 'old_updater.exe', + RunExternalProcess(FMD_DIRECTORY + 'old_' + UPDATER_EXE, ['-x', '-r', '3', '-a', FUpdateURL, '-l', Application.ExeName, '--lang', SimpleTranslator.LastSelected], True, False); Self.Close; @@ -1726,28 +1726,26 @@ procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); procedure TMainForm.LoadAbout; var i: Integer; - s: string; fs: TFileStreamUTF8; st: TStringList; regx: TRegExpr; begin // load readme.rtf - s := fmdDirectory + README_FILE; - if FileExistsUTF8(s) then begin + if FileExistsUTF8(README_FILE) then begin regx := TRegExpr.Create; st := TStringList.Create; try regx.ModifierI := True; regx.Expression := '(version.*)((\d+\.){3}\d+)'; - st.LoadFromFile(s); + st.LoadFromFile(README_FILE); if st.Count > 0 then for i := 0 to st.Count - 1 do if regx.Exec(st[i]) then begin if regx.Match[2] <> FMD_VERSION_NUMBER then begin st[i] := regx.Replace(st[i], '$1\' + FMD_VERSION_NUMBER, True); - if DeleteFileUTF8(s) then - st.SaveToFile(s); + if DeleteFileUTF8(README_FILE) then + st.SaveToFile(README_FILE); end; Break; end; @@ -1755,7 +1753,7 @@ procedure TMainForm.LoadAbout; st.Free; regx.Free; end; - fs := TFileStreamUTF8.Create(s, fmOpenRead or fmShareDenyNone); + fs := TFileStreamUTF8.Create(README_FILE, fmOpenRead or fmShareDenyNone); try rmAbout.LoadRichText(fs); finally @@ -1763,8 +1761,7 @@ procedure TMainForm.LoadAbout; end; end; // load changelog.txt - s := CleanAndExpandDirectory(fmdDirectory) + CHANGELOG_FILE; - if FileExistsUTF8(s) then mmChangelog.Lines.LoadFromFile(s); + if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); end; procedure TMainForm.tvDownloadFilterRepaint; diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 92379b20a..82466226f 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -21,8 +21,7 @@ {$R *.res} begin - fmdDirectory := CleanAndExpandDirectory(GetCurrentDirUTF8); - with TIniFile.Create(fmdDirectory + CONFIG_FILE) do + with TIniFile.Create(CONFIG_FILE) do try CheckInstance := ReadBool('general', 'OneInstanceOnly', True); finally From befe3ec348f7d96ce4f4d702587cadd3188b9ea6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 15:52:08 +0800 Subject: [PATCH 1075/2794] config, works and favorites using temporary file fixed #218 overwrite the original files on update and delete temporary files on exit. --- baseunits/uBaseUnit.pas | 6 ++++++ baseunits/uDownloadsManager.pas | 25 ++++++++++++++++--------- baseunits/uFavoritesManager.pas | 11 ++++++++--- mangadownloader/forms/frmMain.pas | 10 ++++++++-- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d799b1a81..4929bcd07 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -525,11 +525,14 @@ interface FMD_DIRECTORY, WORK_FOLDER, WORK_FILE, + WORK_FILE_RUN, DOWNLOADEDCHAPTERS_FILE, DOWNLOADEDCHAPTERSDB_FILE, FAVORITES_FILE, + FAVORITES_FILE_RUN, CONFIG_FOLDER, CONFIG_FILE, + CONFIG_FILE_RUN, CONFIG_ADVANCED, REVISION_FILE, UPDATE_FILE, @@ -1050,12 +1053,15 @@ procedure SetFMDdirectory(const ADir: String); WORK_FOLDER := FMD_DIRECTORY + 'works' + PathDelim; WORK_FILE := WORK_FOLDER + 'works.ini'; + WORK_FILE_RUN := WORK_FILE + '.run'; DOWNLOADEDCHAPTERS_FILE := WORK_FOLDER + 'downloadedchapters.ini'; DOWNLOADEDCHAPTERSDB_FILE := WORK_FOLDER + 'downloadedchapters.db'; FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; + FAVORITES_FILE_RUN := FAVORITES_FILE + '.run'; CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; + CONFIG_FILE_RUN := CONFIG_FILE + '.run'; CONFIG_ADVANCED := CONFIG_FOLDER + 'advanced.ini'; REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d308f0d1c..608c13b60 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -15,7 +15,7 @@ interface uses - lazutf8classes, LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, + lazutf8classes, LazFileUtils, FileUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, DownloadedChaptersDB, SimpleLogger, dateutils; @@ -1632,7 +1632,12 @@ constructor TDownloadManager.Create; CS_DownloadManager_Task := TCriticalSection.Create; CS_DownloadedChapterList := TCriticalSection.Create; - DownloadManagerFile := TIniFile.Create(WORK_FILE); + if FileExistsUTF8(WORK_FILE_RUN) then + DeleteFileUTF8(WORK_FILE_RUN); + if FileExistsUTF8(WORK_FILE) then + CopyFile(WORK_FILE, WORK_FILE_RUN, [cffOverwriteFile, cffPreserveTime]); + + DownloadManagerFile := TIniFile.Create(WORK_FILE_RUN); DownloadManagerFile.CacheUpdates := True; DownloadedChapters := TDownloadedChaptersDB.Create; @@ -1664,6 +1669,7 @@ destructor TDownloadManager.Destroy; end; FreeAndNil(Containers); FreeAndNil(DownloadManagerFile); + DeleteFileUTF8(WORK_FILE_RUN); DownloadedChapters.Free; CS_DownloadedChapterList.Free; CS_DownloadManager_Task.Free; @@ -1763,21 +1769,21 @@ procedure TDownloadManager.Backup; isRunningBackup := True; CS_DownloadManager_Task.Acquire; + with DownloadManagerFile do try - DownloadManagerFile.CacheUpdates := True; // Erase all sections - for i := 0 to DownloadManagerFile.ReadInteger('general', 'NumberOfTasks', 0) do - DownloadManagerFile.EraseSection('task' + IntToStr(i)); - DownloadManagerFile.EraseSection('general'); + for i := 0 to ReadInteger('general', 'NumberOfTasks', 0) do + EraseSection('task' + IntToStr(i)); + EraseSection('general'); // backup if Containers.Count > 0 then begin - DownloadManagerFile.WriteInteger('general', 'NumberOfTasks', Containers.Count); + WriteInteger('general', 'NumberOfTasks', Containers.Count); for i := 0 to Containers.Count - 1 do begin tid := 'task' + IntToStr(i); - with DownloadManagerFile, TTaskContainer(Containers[i]) do begin + with TTaskContainer(Containers[i]) do begin WriteString(tid, 'Website', DownloadInfo.Website); WriteString(tid, 'Link', DownloadInfo.Link); WriteString(tid, 'Title', DownloadInfo.Title); @@ -1804,7 +1810,8 @@ procedure TDownloadManager.Backup; end; end; end; - DownloadManagerFile.UpdateFile; + UpdateFile; + CopyFile(WORK_FILE_RUN, WORK_FILE, [cffOverwriteFile, cffPreserveTime]); finally CS_DownloadManager_Task.Release; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index ffc407e3c..f861d3ece 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, + Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, FileUtil, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, SimpleException; @@ -427,7 +427,11 @@ constructor TFavoriteManager.Create; inherited Create; CS_Favorites := TCriticalSection.Create; isRunning := False; - favoritesFile := TIniFile.Create(FAVORITES_FILE); + if FileExistsUTF8(FAVORITES_FILE_RUN) then + DeleteFileUTF8(FAVORITES_FILE_RUN); + if FileExistsUTF8(FAVORITES_FILE) then + CopyFile(FAVORITES_FILE, FAVORITES_FILE_RUN, [cffOverwriteFile, cffPreserveTime]); + favoritesFile := TIniFile.Create(FAVORITES_FILE_RUN); favoritesFile.CacheUpdates := True; FFavorites := TFPList.Create; Restore; @@ -436,8 +440,8 @@ constructor TFavoriteManager.Create; destructor TFavoriteManager.Destroy; begin Backup; - favoritesFile.UpdateFile; favoritesFile.Free; + DeleteFileUTF8(FAVORITES_FILE_RUN); if FFavorites.Count > 0 then begin StopChekForNewChapter; while FFavorites.Count > 0 do begin @@ -938,6 +942,7 @@ procedure TFavoriteManager.Backup; WriteString(IntToStr(i), 'Link', Link); end; UpdateFile; + CopyFile(FAVORITES_FILE_RUN, FAVORITES_FILE, [cffOverwriteFile, cffPreserveTime]); end; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5192d64a5..477d3cf67 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1029,8 +1029,12 @@ procedure TMainForm.FormCreate(Sender: TObject); mangaInfo := TMangaInfo.Create; // Load config.ini - options := TIniFile.Create(CONFIG_FILE); - options.CacheUpdates := False; + if FileExistsUTF8(CONFIG_FILE_RUN) then + DeleteFileUTF8(CONFIG_FILE_RUN); + if FileExistsUTF8(CONFIG_FILE) then + CopyFile(CONFIG_FILE, CONFIG_FILE_RUN, [cffOverwriteFile, cffPreserveTime]); + options := TIniFile.Create(CONFIG_FILE_RUN); + options.CacheUpdates := True; options.Options := options.Options-[ifoStripQuotes]; // Load revision.ini @@ -1249,6 +1253,7 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(mangalistIni); FreeAndNil(updates); FreeAndNil(options); + DeleteFileUTF8(CONFIG_FILE_RUN); FreeAndNil(INIAdvanced); if isNormalExit then Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']') @@ -4378,6 +4383,7 @@ procedure TMainForm.SaveOptions; WriteBool('EHentai','DownloadOriginalImage',cbEHentaiDownloadOriginalImage.Checked); finally UpdateFile; + CopyFile(CONFIG_FILE_RUN, CONFIG_FILE, [cffOverwriteFile, cffPreserveTime]); end; end; From ceeacfd342577684f128bd8c83cd258e9b6b1446 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 16:01:07 +0800 Subject: [PATCH 1076/2794] mainform, fixed store cbaddasstoped --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 69db5e38d..663f567f1 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -521,6 +521,7 @@ object MainForm: TMainForm Width = 334 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' + OnChange = cbAddAsStoppedChange ParentFont = False TabOrder = 3 end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 477d3cf67..365dac3f0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -357,6 +357,7 @@ TMainForm = class(TForm) procedure btUpdateListClick(Sender: TObject); procedure btVisitMyBlogClick(Sender: TObject); procedure btWebsitesSearchClearClick(Sender: TObject); + procedure cbAddAsStoppedChange(Sender: TObject); procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); @@ -2098,6 +2099,11 @@ procedure TMainForm.btWebsitesSearchClearClick(Sender: TObject); edWebsitesSearch.Clear; end; +procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); +begin + options.WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); +end; + procedure TMainForm.cbOptionAutoCheckFavIntervalChange(Sender: TObject); begin seOptionAutoCheckFavIntervalMinutes.Enabled := cbOptionAutoCheckFavInterval.Checked; From 985d745babeaba84e81d3cd4a560bab66d3cd2ed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Mar 2016 16:28:19 +0800 Subject: [PATCH 1077/2794] Bump version 0.9.46.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 81c42278c..ddc55cf52 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.46.0 (27-03-2016) +[*] Downloaded Chapters now using SQLite3 database +[*] Config, Downloads and Favorites using temporary file at runtime (#218) +Full changes: https://github.com/riderkick/FMD/compare/0.9.45.0...0.9.46.0 + 0.9.45.0 (25-03-2016) [*] E-Hentai/ExHentai: fixed file naming problem (#217) [*] E-Hentai/ExHentai: fixed get another image url when failed (#213) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 67e3fac4d..ac104fa47 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="45"/> + <RevisionNr Value="46"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 4b5819cbd..ee2b5207d 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.45.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.45.0/fmd_0.9.45.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.45.0/fmd_0.9.45.0_Win64.7z +VERSION=0.9.46.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.46.0/fmd_0.9.46.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.46.0/fmd_0.9.46.0_Win64.7z From 2eddb20388292df4e2ce3e0d3ec2d1f112897eee Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 30 Mar 2016 11:09:02 +0800 Subject: [PATCH 1078/2794] force to create required directories fixed #222 --- baseunits/uDownloadsManager.pas | 2 ++ baseunits/uFavoritesManager.pas | 1 + mangadownloader/forms/frmMain.pas | 2 ++ 3 files changed, 5 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 608c13b60..20a81e4e1 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1629,6 +1629,8 @@ function TDownloadManager.GetTransferRate: Integer; constructor TDownloadManager.Create; begin inherited Create; + ForceDirectoriesUTF8(WORK_FOLDER); + CS_DownloadManager_Task := TCriticalSection.Create; CS_DownloadedChapterList := TCriticalSection.Create; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index f861d3ece..8462f3744 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -425,6 +425,7 @@ function TFavoriteManager.GetFavoritesCount: Integer; constructor TFavoriteManager.Create; begin inherited Create; + ForceDirectoriesUTF8(WORK_FOLDER); CS_Favorites := TCriticalSection.Create; isRunning := False; if FileExistsUTF8(FAVORITES_FILE_RUN) then diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 365dac3f0..6b70df160 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -993,6 +993,8 @@ procedure TMainForm.FormCreate(Sender: TObject); Application.HintHidePause := 10000; sbUpdateList.DoubleBuffered := True; + ForceDirectoriesUTF8(CONFIG_FOLDER); + // load about LoadAbout; From 9590d336fc1eb76225f4d2aea9091027fffcfa51 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 30 Mar 2016 12:31:55 +0800 Subject: [PATCH 1079/2794] windows only, attempt to move form to visible area or center #219 --- mangadownloader/forms/frmMain.pas | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6b70df160..551f746f7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -809,6 +809,25 @@ implementation // ... UpdateStatusTextStyle: TTextStyle; +{$ifdef windows} + PrevWndProc: WNDPROC; + +function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall; +begin + if uMsg = WM_DISPLAYCHANGE then + begin + Screen.UpdateMonitors; + Screen.UpdateScreen; + if Screen.MonitorCount < MainForm.Monitor.MonitorNum then + MainForm.DefaultMonitor := dmMainForm; + if (MainForm.Left > Screen.Width) or (MainForm.Top > Screen.Height) then + MainForm.MoveToDefaultPosition; + end + else + Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam); +end; +{$endif} + procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); var i: Integer; @@ -976,6 +995,9 @@ destructor TOpenDBThread.Destroy; procedure TMainForm.FormCreate(Sender: TObject); begin Randomize; + {$ifdef windows} + PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback))); + {$endif} SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), FormatDateTime('dd-mm-yyyy', Now)])); Writelog_I(['Starting ',QuotedStrd(Application.Title),' [PID:',GetProcessID,'] [HANDLE:',IntToStr(GetCurrentProcess),']']); From 22489c4bdc4ccd5edd5c2ddfae7e9fc538bf03de Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 30 Mar 2016 12:36:57 +0800 Subject: [PATCH 1080/2794] Bump version 0.9.47.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index ddc55cf52..9a56b2ab3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.47.0 (30-03-2016) +[*] Fixed crash with clean install without works folder (#222) +Full changes: https://github.com/riderkick/FMD/compare/0.9.46.0...0.9.47.0 + 0.9.46.0 (27-03-2016) [*] Downloaded Chapters now using SQLite3 database [*] Config, Downloads and Favorites using temporary file at runtime (#218) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ac104fa47..f87e40e80 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="46"/> + <RevisionNr Value="47"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index ee2b5207d..ae4343625 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.46.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.46.0/fmd_0.9.46.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.46.0/fmd_0.9.46.0_Win64.7z +VERSION=0.9.47.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.47.0/fmd_0.9.47.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.47.0/fmd_0.9.47.0_Win64.7z From 4f221e3c44c95cc2c15c8efed81d6cfe9a3547bb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 03:12:32 +0800 Subject: [PATCH 1081/2794] module specific options handled by websitemodules, ui added at runtime --- baseunits/WebsiteModules.pas | 110 +++++- baseunits/modules/Batoto.pas | 14 +- baseunits/modules/EHentai.pas | 9 +- baseunits/modules/MangaFox.pas | 14 +- baseunits/uBaseUnit.pas | 18 +- mangadownloader/forms/frmCustomOption.lfm | 10 + mangadownloader/forms/frmCustomOption.pas | 383 +++++++++++++++++++++ mangadownloader/forms/frmMain.lfm | 392 +++++++++------------- mangadownloader/forms/frmMain.pas | 72 ++-- mangadownloader/languages/fmd.en.po | 65 ++-- mangadownloader/languages/fmd.id_ID.po | 65 ++-- mangadownloader/languages/fmd.po | 65 ++-- 12 files changed, 826 insertions(+), 391 deletions(-) create mode 100644 mangadownloader/forms/frmCustomOption.lfm create mode 100644 mangadownloader/forms/frmCustomOption.pas diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 3d326e898..4de2df9dd 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager, uBaseUnit, RegExpr; + Classes, SysUtils, uData, uDownloadsManager, uBaseUnit, RegExpr, IniFiles; const MODULE_NOT_FOUND = -1; @@ -53,6 +53,15 @@ TModuleContainer = class; MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, MMDownloadImage, MMAfterImageSaved, MMLogin); + TWebsiteOptionType = (woCheckBox, woEdit, woSpinEdit); + + TWebsiteOptionItem = record + OptionType: TWebsiteOptionType; + Name: String; + Caption: PString; + BindValue: Pointer; + end; + { TModuleContainer } TModuleContainer = class @@ -73,6 +82,7 @@ TModuleContainer = class DynamicPageLink: Boolean; TotalDirectoryPage: array of Integer; CurrentDirectoryIndex: Integer; + OptionList: array of TWebsiteOptionItem; OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; OnGetNameAndLink: TOnGetNameAndLink; OnGetInfo: TOnGetInfo; @@ -87,6 +97,8 @@ TModuleContainer = class destructor Destroy; override; public property TotalDirectory: Integer read FTotalDirectory write SetTotalDirectory; + procedure AddOption(const AOptionType: TWebsiteOptionType; + const ABindValue: Pointer; const AName: String; const ACaption: PString); end; { TWebsiteModules } @@ -95,6 +107,7 @@ TWebsiteModules = class private FCSModules: TRTLCriticalSection; FModuleList: TFPList; + FWebsiteOptionFile: TIniFile; function GetModule(const ModuleId: Integer): TModuleContainer; function GetCount: Integer; function GetMaxTaskLimit(const ModuleId: Integer): Integer; @@ -176,17 +189,18 @@ TWebsiteModules = class property Website[const ModuleId: Integer]: String read GetWebsite; property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; - property MaxConnectionLimit[const ModuleId: Integer]: Integer - read GetMaxConnectionLimit; + property MaxConnectionLimit[const ModuleId: Integer]: Integer read GetMaxConnectionLimit; property ActiveTaskCount[const ModuleId: Integer]: Integer read GetActiveTaskCount; - property ActiveConnectionCount[const ModuleId: Integer]: Integer - read GetActiveConnectionLimit; + property ActiveConnectionCount[const ModuleId: Integer]: Integer read GetActiveConnectionLimit; procedure IncActiveTaskCount(ModuleId: Integer); procedure DecActiveTaskCount(ModuleId: Integer); function CanCreateTask(ModuleId: Integer): Boolean; procedure IncActiveConnectionCount(ModuleId: Integer); procedure DecActiveConnectionCount(ModuleId: Integer); function CanCreateConnection(ModuleId: Integer): Boolean; + + procedure LoadWebsiteOption; + procedure SaveWebsiteOption; end; var @@ -198,6 +212,9 @@ function AddModule: TModuleContainer; procedure LockCreateConnection; procedure UnlockCreateConnection; +function CleanOptionName(const S: String): String; + + implementation {$I ModuleList.inc} @@ -210,6 +227,26 @@ implementation { TModuleContainer } +function CleanOptionName(const S: String): String; +const + Alpha = ['A'..'Z', 'a'..'z', '_']; + Num = ['0'..'9']; + AlphaNum = Alpha + Num; +var + i: Integer; +begin + Result := Trim(S); + if Result = '' then Exit; + while (Length(Result) > 0) and (Result[1] in Num) do + Delete(Result, 1, 1); + i := 1; + while i <= Length(Result) do + if not (Result[i] in AlphaNum) then + Delete(Result, i, 1) + else + Inc(i); +end; + procedure TModuleContainer.SetTotalDirectory(AValue: Integer); var i: Integer; @@ -240,21 +277,41 @@ constructor TModuleContainer.Create; destructor TModuleContainer.Destroy; begin SetLength(TotalDirectoryPage, 0); + SetLength(OptionList,0); inherited Destroy; end; +procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; + const AName: String; const ACaption: PString); +begin + if ABindValue = nil then Exit; + if AName = '' then Exit; + SetLength(OptionList, Length(OptionList) + 1); + with OptionList[High(OptionList)] do + begin + OptionType := AOptionType; + BindValue := ABindValue; + Name := CleanOptionName(AName); + Caption := ACaption; + end; +end; + { TWebsiteModules } constructor TWebsiteModules.Create; begin InitCriticalSection(FCSModules); FModuleList := TFPList.Create; + FWebsiteOptionFile := TIniFile.Create(WEBSITE_CONFIG_FILE); + FWebsiteOptionFile.CacheUpdates := True; end; destructor TWebsiteModules.Destroy; var i: Integer; begin + if Assigned(FWebsiteOptionFile) then + FWebsiteOptionFile.Free; if FModuleList.Count > 0 then for i := 0 to FModuleList.Count - 1 do TModuleContainer(FModuleList[i]).Free; @@ -506,7 +563,9 @@ function TWebsiteModules.AfterImageSaved(const AFilename: String; Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved) then - Result := TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved(AFilename, TModuleContainer(FModuleList[ModuleId])); + Result := TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved(AFilename, + TModuleContainer(FModuleList[ModuleId])); + end; function TWebsiteModules.AfterImageSaved(const AFilename, AWebsite: String @@ -590,6 +649,45 @@ function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; Result := ActiveConnectionCount < MaxConnectionLimit; end; +procedure TWebsiteModules.LoadWebsiteOption; +var + i, j: Integer; +begin + if FModuleList.Count = 0 then Exit; + for i := 0 to FModuleList.Count - 1 do + with TModuleContainer(FModuleList[i]) do + if Length(OptionList) > 0 then + for j := Low(OptionList) to High(OptionList) do + with OptionList[j], FWebsiteOptionFile do + begin + case OptionType of + woCheckBox: PBoolean(BindValue)^ := ReadBool(Website, Name, PBoolean(BindValue)^); + woEdit: PString(BindValue)^ := ReadString(Website, Name, PString(BindValue)^); + woSpinEdit: PInteger(BindValue)^ := ReadInteger(Website, Name, PInteger(BindValue)^); + end; + end; +end; + +procedure TWebsiteModules.SaveWebsiteOption; +var + i, j: Integer; +begin + if FModuleList.Count = 0 then Exit; + for i := 0 to FModuleList.Count - 1 do + with TModuleContainer(FModuleList[i]) do + if Length(OptionList) > 0 then + for j := Low(OptionList) to High(OptionList) do + with OptionList[j], FWebsiteOptionFile do + begin + case OptionType of + woCheckBox: WriteBool(Website, Name, PBoolean(BindValue)^); + woEdit: WriteString(Website, Name, PString(BindValue)^); + woSpinEdit: WriteInteger(Website, Name, PInteger(BindValue)^); + end; + end; + FWebsiteOptionFile.UpdateFile; +end; + function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(nil); diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 2566cf25c..2d67a7763 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -22,6 +22,12 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; var locklogin: TRTLCriticalSection; + showalllang: Boolean = False; + showscangroup: Boolean = False; + +resourcestring + RS_ShowAllLang = 'Show all language'; + RS_ShowScanGroup = 'Show scanlation group'; function Login(const AHTTP: THTTPSendThread): Boolean; var @@ -211,18 +217,18 @@ function GetInfo(const MangaInfo: TMangaInformation; for i := 1 to v.Count do AddCommaString(genres, v.get(i).toString); end; - if OptionBatotoShowAllLang then + if showalllang then s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]' else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]'; for v in XPath(s) do begin w := XPath('td[1]/a', v.toNode); chapterLinks.Add(w.toNode.getAttribute('href')); t := w.toString; - if OptionBatotoShowAllLang then begin + if showalllang then begin l := XPath('td[2]/div', v.toNode).toNode.getAttribute('title'); if l <> '' then t += ' [' + l + ']'; end; - if OptionBatotoShowScanGroup then begin + if showscangroup then begin l := XPath('td[3]', v.toNode).toString; if l <> '' then t += ' [' + l + ']'; end; @@ -314,6 +320,8 @@ procedure RegisterModule; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; OnLogin := @Login; + AddOption(woCheckBox, @showalllang,'ShowAllLang', @RS_ShowAllLang); + AddOption(woCheckBox, @showscangroup,'ShowScanGroup', @RS_ShowScanGroup); end; end; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index cce812a7d..c7f1679e2 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -18,6 +18,10 @@ implementation var onlogin: Boolean = False; locklogin: TRTLCriticalSection; + downloadoriginalimage: Boolean = False; + +resourcestring + RS_DownloadOriginalImage = 'Download original image(require ExHentai account)'; function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; var @@ -288,7 +292,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; s := StreamToString(DownloadThread.FHTTP.Document); query.ParseHTML(DownloadThread.FHTTP.Document); iurl := ''; - if OptionEHentaiDownloadOriginalImage and (Account.Status[accname] = asValid) then + if downloadoriginalimage and (Account.Status[accname] = asValid) then iurl := query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); if iurl = '' then iurl := query.XPathString('//*[@id="img"]/@src'); @@ -387,7 +391,8 @@ procedure RegisterModule; end; begin - AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org'); + with AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org') do + AddOption(woCheckBox, @downloadoriginalimage, 'DownloadOriginal', @RS_DownloadOriginalImage); with AddWebsiteModule('ExHentai', 'http://exhentai.org') do begin AccountSupport := True; OnLogin := @ExHentaiLogin; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 5138473ce..ac825efa3 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -10,6 +10,14 @@ interface implementation +var + removewatermark: Boolean = True; + saveaspng: Boolean = False; + +resourcestring + RS_RemoveWatermark = 'Remove watermark'; + RS_SaveAsPNG = 'Save as PNG'; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var @@ -135,8 +143,8 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; function AfterImageSaved(const AFilename: String; const Module: TModuleContainer): Boolean; begin Result := True; - if OptionMangaFoxRemoveWatermark then - Result := mangafoxwatermarkremover.RemoveWatermark(AFilename, OptionMangaFoxSaveAsPNG); + if removewatermark then + Result := mangafoxwatermarkremover.RemoveWatermark(AFilename, saveaspng); end; procedure RegisterModule; @@ -150,6 +158,8 @@ procedure RegisterModule; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; OnAfterImageSaved := @AfterImageSaved; + AddOption(woCheckBox, @removewatermark, 'RemoveWatermak', @RS_RemoveWatermark); + AddOption(woCheckBox, @saveaspng, 'SaveAsPNG', @RS_SaveAsPNG); end; end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4929bcd07..edfc8e887 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -538,11 +538,14 @@ interface UPDATE_FILE, MANGALIST_FILE, ACCOUNTS_FILE, + WEBSITE_CONFIG_FILE, DATA_FOLDER, IMAGE_FOLDER, LANGUAGE_FILE, CHANGELOG_FILE, - README_FILE: String; + README_FILE, + EXTRAS_FOLDER, + MANGAFOXTEMPLATE_FOLDER: String; {$IFDEF WINDOWS} DEFAULT_PATH: String = '\downloads'; @@ -603,13 +606,6 @@ interface OptionAutoCheckFavDownload: Boolean = False; OptionAutoCheckFavRemoveCompletedManga: Boolean = False; - OptionBatotoShowScanGroup: Boolean = False; - OptionBatotoShowAllLang: Boolean = False; - OptionMangaFoxTemplateFolder: String = 'extras' + PathDelim + 'mangafoxtemplate'; - OptionMangaFoxRemoveWatermark: Boolean = True; - OptionMangaFoxSaveAsPNG: Boolean = False; - OptionEHentaiDownloadOriginalImage: Boolean = False; - OptionHTTPUseGzip: Boolean = True; OptionRemoveMangaNameFromChapter: Boolean = False; @@ -1048,7 +1044,7 @@ function NTSetPrivilege(sPrivilege: String; bEnabled: Boolean): Boolean; {$ENDIF} procedure SetFMDdirectory(const ADir: String); -begin +begin WriteLog_D('setfmddirectory: '+adir); FMD_DIRECTORY := CleanAndExpandDirectory(ADir); WORK_FOLDER := FMD_DIRECTORY + 'works' + PathDelim; @@ -1067,6 +1063,7 @@ procedure SetFMDdirectory(const ADir: String); UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; MANGALIST_FILE := CONFIG_FOLDER + 'mangalist.ini'; ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; + WEBSITE_CONFIG_FILE := CONFIG_FOLDER + 'websiteconfig.ini'; DATA_FOLDER := FMD_DIRECTORY + 'data' + PathDelim; @@ -1074,6 +1071,9 @@ procedure SetFMDdirectory(const ADir: String); LANGUAGE_FILE := FMD_DIRECTORY + 'languages.ini'; CHANGELOG_FILE := FMD_DIRECTORY + 'changelog.txt'; README_FILE := FMD_DIRECTORY + 'readme.rtf'; + + EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; + MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; end; function GetCurrentBinVersion: String; diff --git a/mangadownloader/forms/frmCustomOption.lfm b/mangadownloader/forms/frmCustomOption.lfm new file mode 100644 index 000000000..62b5b8d4b --- /dev/null +++ b/mangadownloader/forms/frmCustomOption.lfm @@ -0,0 +1,10 @@ +object CustomOptionForm: TCustomOptionForm + Left = 281 + Height = 240 + Top = 68 + Width = 320 + Caption = 'CustomOptionForm' + OnCreate = FormCreate + OnDestroy = FormDestroy + LCLVersion = '1.7' +end diff --git a/mangadownloader/forms/frmCustomOption.pas b/mangadownloader/forms/frmCustomOption.pas new file mode 100644 index 000000000..43f42eaa8 --- /dev/null +++ b/mangadownloader/forms/frmCustomOption.pas @@ -0,0 +1,383 @@ +unit frmCustomOption; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, StdCtrls, Spin, WebsiteModules; + +type + + { TCheckBoxBindValue } + + TCheckBoxBindValue = class(TCheckBox) + private + FBindValue: PBoolean; + procedure SetBindValue(AValue: PBoolean); + protected + procedure ValueChange(Sender: TObject); + public + constructor Create(TheOwner: TComponent); override; + property BindValue: PBoolean read FBindValue write SetBindValue; + end; + + { TEditBindValue } + + TEditBindValue = class(TEdit) + private + FBindValue: PString; + procedure SetBindValue(AValue: PString); + protected + procedure ValueChange(Sender: TObject); + public + constructor Create(TheOwner: TComponent); override; + property BindValue: PString read FBindValue write SetBindValue; + end; + + { TSpinEditBindValue } + + TSpinEditBindValue = class(TSpinEdit) + private + FBindValue: PInteger; + procedure SetBindValue(AValue: PInteger); + protected + procedure ValueChange(Sender: TObject); + public + constructor Create(TheOwner: TComponent); override; + property BindValue: PInteger read FBindValue write SetBindValue; + end; + + { TCustomOptionForm } + + TCustomOptionForm = class(TForm) + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + private + { private declarations } + function AddOptionItem(const AOptionItemType: TWebsiteOptionType; + const AName, ACaption, AGroup, AGroupCaption: String): TWinControl; + public + { public declarations } + function AddCheckbox(const ABindValue: PBoolean; + const AName, ACaption, AGroup, AGroupCaption: String): TWinControl; + function AddEdit(const ABindValue: PString; + const AName, ACaption, AGroup, AGroupCaption: String): TWinControl; + function AddSpinEdit(const ABindValue: PInteger; + AName, ACaption, AGroup, AGroupCaption: String): TWinControl; + procedure CreateWebsiteOption; + end; + +var + CustomOptionForm: TCustomOptionForm; + dparent: TWinControl; + tbspace: Cardinal = 6; + lrspace: Cardinal = 6; + hspace: Cardinal = 4; + vspace: Cardinal = 4; + +const + TWebsiteOptionItemTypeStr: array[TWebsiteOptionType] of String = + ('ack', 'ae', 'ase'); + +implementation + +{$R *.lfm} + +{ TCheckBoxBindValue } + +procedure TCheckBoxBindValue.SetBindValue(AValue: PBoolean); +begin + if FBindValue = AValue then Exit; + FBindValue := AValue; + if Assigned(FBindValue) then + Checked := FBindValue^; +end; + +procedure TCheckBoxBindValue.ValueChange(Sender: TObject); +begin + if Assigned(FBindValue) then + FBindValue^ := Checked; +end; + +constructor TCheckBoxBindValue.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + OnChange := @ValueChange; +end; + +{ TEditBindValue } + +procedure TEditBindValue.SetBindValue(AValue: PString); +begin + if FBindValue = AValue then Exit; + FBindValue := AValue; + if Assigned(FBindValue) then + Text := FBindValue^; +end; + +procedure TEditBindValue.ValueChange(Sender: TObject); +begin + if Assigned(FBindValue) then + FBindValue^ := Text; +end; + +constructor TEditBindValue.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + OnChange := @ValueChange; +end; + +{ TSpinEditBindValue } + +procedure TSpinEditBindValue.SetBindValue(AValue: PInteger); +begin + if FBindValue = AValue then Exit; + FBindValue := AValue; + if Assigned(FBindValue) then + Value := FBindValue^; +end; + +procedure TSpinEditBindValue.ValueChange(Sender: TObject); +begin + if Assigned(FBindValue) then + FBindValue^ := Value; +end; + +constructor TSpinEditBindValue.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + MinValue := 0; + MaxValue := 10000; + OnChange := @ValueChange; +end; + +{ TCustomOptionForm } + +procedure TCustomOptionForm.FormCreate(Sender: TObject); +begin + dparent := Self; + with dparent.ChildSizing do + begin + TopBottomSpacing := tbspace; + LeftRightSpacing := lrspace; + HorizontalSpacing := hspace; + VerticalSpacing := vspace; + end; + Modules.LoadWebsiteOption; + CreateWebsiteOption; +end; + +procedure TCustomOptionForm.FormDestroy(Sender: TObject); +begin + Modules.SaveWebsiteOption; +end; + +function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionType; const AName, ACaption, + AGroup, AGroupCaption: String): TWinControl; +var + i, j: Integer; + compparent: TWinControl; + compparentsibling, compsibling: TControl; + lcomp, lcompcaption, lgroup, lgroupcaption: String; + lb: TLabel; + + procedure SetControlProp(const AControl, ASibling: TControl; + const AParent: TWinControl; const AName, ACaption: String); + begin + with AControl do + begin + if AParent <> nil then + Parent := AParent; + Name := AName; + Caption := ACaption; + AutoSize := True; + Top := AParent.ChildSizing.TopBottomSpacing; + AnchorParallel(akLeft, 0, AParent); + if ASibling <> nil then + begin + Top := ASibling.Top + ASibling.Height; + AnchorToNeighbour(akTop, 0, ASibling); + end; + end; + end; + +begin + Result := nil; + lcomp := CleanOptionName(AName); + if lcomp = '' then Exit; + lcompcaption := Trim(ACaption); + lgroup := CleanOptionName(AGroup); + lgroupcaption := Trim(AGroupCaption); + compparent := nil; + compparentsibling := nil; + compsibling := nil; + + if (lcompcaption = '') and (lcomp <> '') then + lcompcaption := Trim(AName); + if (lgroupcaption = '') and (lgroup <> '') then + lgroupcaption := Trim(AGroup); + + if lcomp <> '' then + begin + if lgroup <> '' then + lcomp := lgroup + lcomp; + lcomp := TWebsiteOptionItemTypeStr[AOptionItemType] + lcomp; + if lgroup <> '' then + lgroup := 'agb' + lgroup; + end; + + with dparent do + if ComponentCount > 0 then + for i := ComponentCount - 1 downto 0 do + begin + if SameText(Components[i].Name, lcomp) then + Exit + else + if (Components[i] is TGroupBox) and SameText(Components[i].Name, lgroup) then + begin + compparent := TGroupBox(Components[i]); + with compparent do + if ComponentCount > 0 then + begin + compsibling := TControl(Components[ComponentCount - 1]); + for j := ComponentCount - 1 downto 0 do + if SameText(Components[j].Name, lcomp) then + Exit; + end; + end; + end; + + with dparent do + if ComponentCount > 0 then + begin + i := ComponentCount - 1; + if TWinControl(Components[i]).Parent is TGroupBox then + compparentsibling := TWinControl(Components[i]).Parent + else + compparentsibling := TWinControl(Components[i]); + end; + + Self.BeginFormUpdate; + try + if compparent = nil then + if lgroup <> '' then + begin + compparent := TGroupBox.Create(dparent); + SetControlProp(compparent, compparentsibling, dparent, lgroup, lgroupcaption); + with compparent.ChildSizing do + begin + TopBottomSpacing := dparent.ChildSizing.TopBottomSpacing; + LeftRightSpacing := dparent.ChildSizing.LeftRightSpacing; + HorizontalSpacing := dparent.ChildSizing.HorizontalSpacing; + VerticalSpacing := dparent.ChildSizing.VerticalSpacing; + end; + compparent.Align := alTop; + end + else + begin + compparent := dparent; + if (compsibling = nil) and (compparentsibling <> nil) then + compsibling := compparentsibling; + end; + + case AOptionItemType of + woCheckBox: + begin + Result := TCheckBoxBindValue.Create(compparent); + SetControlProp(Result, compsibling, compparent, lcomp, lcompcaption); + end; + + woEdit: + begin + lb := TLabel.Create(compparent); + SetControlProp(lb, compsibling, compparent, lcomp + 'Lbl', lcompcaption); + compsibling := lb; + Result := TEditBindValue.Create(compparent); + SetControlProp(Result, compsibling, compparent, lcomp, ''); + with Result do + begin + Width := compparent.Width - compparent.ChildSizing.LeftRightSpacing; + Anchors := Anchors + [akRight]; + Text := ''; + end; + end; + + woSpinEdit: + begin + lb := TLabel.Create(compparent); + Result := TSpinEditBindValue.Create(compparent); + SetControlProp(Result, compsibling, compparent, lcomp, lcompcaption); + Result.Width := Result.Width + (Result.Width div 4); + SetControlProp(lb, Result, compparent, lcomp + 'Lbl', lcompcaption); + with lb do + begin + AnchorToNeighbour(akLeft, 0, Result); + AnchorVerticalCenterTo(Result); + end; + end; + end; + finally + Self.EndFormUpdate; + end; +end; + +function TCustomOptionForm.AddCheckbox(const ABindValue: PBoolean; + const AName, ACaption, AGroup, AGroupCaption: String + ): TWinControl; +begin + Result := AddOptionItem(woCheckBox, AName, ACaption, AGroup, AGroupCaption); + TCheckBoxBindValue(Result).BindValue := ABindValue; +end; + +function TCustomOptionForm.AddEdit(const ABindValue: PString; + const AName, ACaption, AGroup, AGroupCaption: String + ): TWinControl; +begin + Result := AddOptionItem(woEdit, AName, ACaption, AGroup, AGroupCaption); + TEditBindValue(Result).BindValue := ABindValue; +end; + +function TCustomOptionForm.AddSpinEdit(const ABindValue: PInteger; + AName, ACaption, AGroup, AGroupCaption: String + ): TWinControl; +begin + Result := AddOptionItem(woSpinEdit, AName, ACaption, AGroup, AGroupCaption); + TSpinEditBindValue(Result).BindValue := ABindValue; +end; + +procedure TCustomOptionForm.CreateWebsiteOption; +var + i, j: Integer; + c: TComponent; + cap: String; +begin + while dparent.ComponentCount > 0 do + for i := 0 to dparent.ComponentCount - 1 do + begin + c := dparent.Components[dparent.ComponentCount - 1]; + dparent.RemoveComponent(c); + c.Free; + end; + + if Modules = nil then Exit; + if Modules.Count > 0 then + for i := 0 to Modules.Count - 1 do + with Modules.Module[i] do + if Length(OptionList) > 0 then + for j := Low(OptionList) to High(OptionList) do + with OptionList[j] do + begin + if Assigned(Caption) then + cap := Caption^ + else + cap := ''; + case OptionType of + woCheckBox: AddCheckbox(BindValue, Name, cap, Website, Website); + woEdit: AddEdit(BindValue, Name, cap, Website, Website); + woSpinEdit: AddSpinEdit(BindValue, Name, cap, Website, Website); + end; + end; +end; + +end. diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 663f567f1..8bce94b91 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2944,7 +2944,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 + ClientHeight = 392 ClientWidth = 531 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 4 @@ -3128,145 +3128,182 @@ object MainForm: TMainForm ChildSizing.VerticalSpacing = 4 ClientHeight = 392 ClientWidth = 531 - object vtOptionMangaSiteSelection: TVirtualStringTree + object pcWebsiteOptions: TPageControl Left = 4 - Height = 347 - Top = 37 + Height = 376 + Top = 8 Width = 523 + ActivePage = tsWebsiteSelection Align = alClient - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = <> - Header.DefaultHeight = 17 - Header.Height = 23 - Header.MainColumn = -1 - Margin = 0 - ParentFont = False + TabIndex = 0 TabOrder = 0 - TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] - OnChange = vtOptionMangaSiteSelectionChange - OnFocusChanged = vtOptionMangaSiteSelectionFocusChanged - OnFreeNode = vtOptionMangaSiteSelectionFreeNode - OnGetText = vtOptionMangaSiteSelectionGetText - OnGetNodeDataSize = vtOptionMangaSiteSelectionGetNodeDataSize - OnInitNode = vtOptionMangaSiteSelectionInitNode - end - object pnlWebsitesTool: TPanel - Left = 4 - Height = 23 - Top = 8 - Width = 523 - Align = alTop - BorderSpacing.Top = 4 - BorderSpacing.Right = 2 - BorderSpacing.Bottom = 4 - BorderSpacing.Around = 2 - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 23 - ClientWidth = 523 - TabOrder = 1 - object edWebsitesSearch: TEdit - Left = 0 - Height = 23 - Top = 0 - Width = 184 - Align = alLeft - BorderSpacing.Right = 2 - OnChange = edWebsitesSearchChange - TabOrder = 0 - TextHint = 'Search website...' - end - object btWebsitesSearchClear: TSpeedButton - Left = 188 - Height = 23 - Top = 0 - Width = 22 - Align = alLeft - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btWebsitesSearchClearClick - end - object pnlWebsitesToolRight: TPanel - Left = 353 - Height = 23 - Top = 0 - Width = 170 - Align = alRight - AutoSize = True - BevelOuter = bvNone - ClientHeight = 23 - ClientWidth = 170 - TabOrder = 1 - object ToolBarWebsites: TToolBar + object tsWebsiteSelection: TTabSheet + Caption = 'Websites' + ClientHeight = 348 + ClientWidth = 515 + object vtOptionMangaSiteSelection: TVirtualStringTree Left = 0 - Height = 22 - Top = 0 - Width = 170 - AutoSize = True - EdgeBorders = [] - Images = IconList - List = True + Height = 313 + Top = 35 + Width = 515 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.Height = 23 + Header.MainColumn = -1 + Margin = 0 ParentFont = False - ShowCaptions = True TabOrder = 0 - Transparent = True - object tbWebsitesExpandAll: TToolButton - Left = 1 + TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] + OnChange = vtOptionMangaSiteSelectionChange + OnFocusChanged = vtOptionMangaSiteSelectionFocusChanged + OnFreeNode = vtOptionMangaSiteSelectionFreeNode + OnGetText = vtOptionMangaSiteSelectionGetText + OnGetNodeDataSize = vtOptionMangaSiteSelectionGetNodeDataSize + OnInitNode = vtOptionMangaSiteSelectionInitNode + end + object pnlWebsitesTool: TPanel + Left = 2 + Height = 23 + Top = 6 + Width = 509 + Align = alTop + BorderSpacing.Top = 4 + BorderSpacing.Right = 2 + BorderSpacing.Bottom = 4 + BorderSpacing.Around = 2 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 23 + ClientWidth = 509 + TabOrder = 1 + object edWebsitesSearch: TEdit + Left = 0 + Height = 23 Top = 0 - AutoSize = True - Caption = 'Expand All' - ImageIndex = 17 - OnClick = tbWebsitesExpandAllClick + Width = 184 + Align = alLeft + BorderSpacing.Right = 2 + OnChange = edWebsitesSearchChange + TabOrder = 0 + TextHint = 'Search website...' + end + object btWebsitesSearchClear: TSpeedButton + Left = 188 + Height = 23 + Top = 0 + Width = 22 + Align = alLeft + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btWebsitesSearchClearClick end - object tbWebsitesCollapseAll: TToolButton - Left = 82 + object pnlWebsitesToolRight: TPanel + Left = 339 + Height = 23 Top = 0 + Width = 170 + Align = alRight AutoSize = True - Caption = 'Collapse All' - ImageIndex = 18 - OnClick = tbWebsitesCollapseAllClick + BevelOuter = bvNone + ClientHeight = 23 + ClientWidth = 170 + TabOrder = 1 + object ToolBarWebsites: TToolBar + Left = 0 + Height = 22 + Top = 0 + Width = 170 + AutoSize = True + EdgeBorders = [] + Images = IconList + List = True + ParentFont = False + ShowCaptions = True + TabOrder = 0 + Transparent = True + object tbWebsitesExpandAll: TToolButton + Left = 1 + Top = 0 + AutoSize = True + Caption = 'Expand All' + ImageIndex = 17 + OnClick = tbWebsitesExpandAllClick + end + object tbWebsitesCollapseAll: TToolButton + Left = 82 + Top = 0 + AutoSize = True + Caption = 'Collapse All' + ImageIndex = 18 + OnClick = tbWebsitesCollapseAllClick + end + end end end end + object tsWebsiteOptions: TTabSheet + Caption = 'Options' + ClientHeight = 348 + ClientWidth = 515 + object sbWebsiteOptions: TScrollBox + Left = 0 + Height = 348 + Top = 0 + Width = 515 + HorzScrollBar.Increment = 1 + HorzScrollBar.Page = 1 + HorzScrollBar.Smooth = True + HorzScrollBar.Tracking = True + VertScrollBar.Increment = 1 + VertScrollBar.Page = 1 + VertScrollBar.Smooth = True + VertScrollBar.Tracking = True + Align = alClient + BorderStyle = bsNone + TabOrder = 0 + end + end end end object tsAccounts: TTabSheet @@ -3280,109 +3317,6 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 - ClientWidth = 531 - object gbBatoto: TGroupBox - Left = 4 - Height = 70 - Top = 8 - Width = 523 - Align = alTop - AutoSize = True - Caption = 'Batoto' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 50 - ClientWidth = 519 - TabOrder = 0 - object cbBatotoShowAllLang: TCheckBox - Left = 4 - Height = 19 - Top = 4 - Width = 511 - Align = alTop - Caption = 'Show all language' - ParentFont = False - TabOrder = 1 - end - object cbBatotoShowScanGroup: TCheckBox - Left = 4 - Height = 19 - Top = 27 - Width = 511 - Align = alTop - Caption = 'Show scan group name' - ParentFont = False - TabOrder = 0 - end - end - object gbMangafox: TGroupBox - Left = 4 - Height = 70 - Top = 82 - Width = 523 - Align = alTop - AutoSize = True - Caption = 'Mangafox' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 50 - ClientWidth = 519 - TabOrder = 1 - object cbMangaFoxRemoveWatermark: TCheckBox - Left = 4 - Height = 19 - Top = 4 - Width = 511 - Align = alTop - Caption = 'Remove watermark' - OnChange = cbMangaFoxRemoveWatermarkChange - ParentFont = False - TabOrder = 0 - end - object cbMangaFoxSaveAsPNG: TCheckBox - Left = 4 - Height = 19 - Top = 27 - Width = 511 - Align = alTop - Caption = 'Save as PNG' - Enabled = False - ParentFont = False - TabOrder = 1 - end - end - object gbEHentai: TGroupBox - Left = 4 - Height = 47 - Top = 156 - Width = 523 - Align = alTop - AutoSize = True - Caption = 'E-Hentai/ExHentai' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 27 - ClientWidth = 519 - TabOrder = 2 - object cbEHentaiDownloadOriginalImage: TCheckBox - Left = 4 - Height = 19 - Top = 4 - Width = 511 - Align = alTop - Caption = 'Download original image (require ExHentai account)' - OnChange = cbMangaFoxRemoveWatermarkChange - ParentFont = False - TabOrder = 0 - end - end end end object btOptionApply: TBitBtn diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 551f746f7..66f6a8568 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,7 +22,7 @@ interface FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, - frmAccountManager, CheckUpdate, accountmanagerdb, DBDataProcess, + frmAccountManager, frmCustomOption, CheckUpdate, accountmanagerdb, DBDataProcess, mangafoxwatermarkremover, SimpleTranslator, SimpleException, SimpleLogger; type @@ -45,14 +45,11 @@ TMainForm = class(TForm) btSearchClear: TSpeedButton; btWebsitesSearchClear: TSpeedButton; btUpdateList: TSpeedButton; - cbEHentaiDownloadOriginalImage: TCheckBox; cbOptionAutoCheckFavStartup: TCheckBox; cbOptionAutoCheckFavInterval: TCheckBox; cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; - cbMangaFoxRemoveWatermark: TCheckBox; - cbMangaFoxSaveAsPNG: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadMangalistDialog: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; @@ -68,13 +65,12 @@ TMainForm = class(TForm) edOptionMangaCustomRename: TEdit; edSaveTo: TDirectoryEdit; edURL: TEditButton; - gbMangafox: TGroupBox; - gbEHentai: TGroupBox; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; + pcWebsiteOptions: TPageControl; Panel1: TPanel; Panel2: TPanel; Panel3: TPanel; @@ -82,6 +78,9 @@ TMainForm = class(TForm) pcAbout: TPageControl; pmSbMain: TPopupMenu; sbSaveTo: TScrollBox; + sbWebsiteOptions: TScrollBox; + tsWebsiteSelection: TTabSheet; + tsWebsiteOptions: TTabSheet; tsAccounts: TTabSheet; tsAboutText: TTabSheet; tsChangelogText: TTabSheet; @@ -144,8 +143,6 @@ TMainForm = class(TForm) btRemoveFilterLarge: TBitBtn; cbOptionAutoCheckLatestVersion: TCheckBox; cbOptionShowDeleteTaskDialog: TCheckBox; - cbBatotoShowScanGroup: TCheckBox; - cbBatotoShowAllLang: TCheckBox; cbOptionUseProxy: TCheckBox; cbSelectManga: TComboBox; ckFilterAction: TCheckBox; @@ -211,7 +208,6 @@ TMainForm = class(TForm) gbOptionProxy: TGroupBox; gbOptionRenaming: TGroupBox; gbOptionFavorites: TGroupBox; - gbBatoto: TGroupBox; IconList: TImageList; itRefreshDLInfo: TIdleTimer; itCheckFav: TIdleTimer; @@ -362,7 +358,6 @@ TMainForm = class(TForm) procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderNameChange(Sender: TObject); - procedure cbMangaFoxRemoveWatermarkChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; @@ -1080,13 +1075,6 @@ procedure TMainForm.FormCreate(Sender: TObject); seOptionMaxParallel.MaxValue := MAX_TASKLIMIT; seOptionMaxThread.MaxValue := MAX_CONNECTIONPERHOSTLIMIT; - isStartup := False; - CollectLanguagesFromFiles; - LoadFormInformation; - LoadMangaOptions; - LoadOptions; - ApplyOptions; - if cbFilterStatus.Items.Count > 2 then cbFilterStatus.ItemIndex := 2; @@ -1165,6 +1153,26 @@ procedure TMainForm.FormCreate(Sender: TObject); ChildSizing.TopBottomSpacing := 0; Show; end; + + CustomOptionForm := TCustomOptionForm.Create(Self); + with CustomOptionForm do + begin + Parent := sbWebsiteOptions; + BorderStyle := bsNone; + Align := alClient; + Show; + end; + + // load mangafox template + mangafoxwatermarkremover.LoadTemplate(MANGAFOXTEMPLATE_FOLDER); + + // load options + isStartup := False; + CollectLanguagesFromFiles; + LoadFormInformation; + LoadMangaOptions; + LoadOptions; + ApplyOptions; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -2151,11 +2159,6 @@ procedure TMainForm.cbOptionGenerateMangaFolderNameChange(Sender: TObject); lbOptionMangaCustomRenameHint.Enabled := cbOptionGenerateMangaFolderName.Checked; end; -procedure TMainForm.cbMangaFoxRemoveWatermarkChange(Sender: TObject); -begin - cbMangaFoxSaveAsPNG.Enabled:=cbMangaFoxRemoveWatermark.Checked; -end; - procedure TMainForm.btReadOnlineClick(Sender: TObject); begin OpenURL(mangaInfo.url); @@ -4283,11 +4286,7 @@ procedure TMainForm.LoadOptions; cbOptionShowDownloadMangalistDialog.Checked := ReadBool('dialogs', 'ShowDownloadMangalistDialog', True); // misc - cbBatotoShowScanGroup.Checked := ReadBool('Batoto', 'ShowScanGroup', OptionBatotoShowScanGroup); - cbBatotoShowAllLang.Checked := ReadBool('Batoto', 'ShowAllLang', OptionBatotoShowAllLang); - cbMangaFoxRemoveWatermark.Checked := ReadBool('MangaFox', 'RemoveWatermark', OptionMangaFoxRemoveWatermark); - cbMangaFoxSaveAsPNG.Checked := ReadBool('MangaFox', 'SaveAsPNG', OptionMangaFoxSaveAsPNG); - cbEHentaiDownloadOriginalImage.Checked:=ReadBool('EHentai','DownloadOriginalImage',OptionEHentaiDownloadOriginalImage); + // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4406,15 +4405,12 @@ procedure TMainForm.SaveOptions; WriteBool('dialogs', 'ShowDownloadMangalistDialog', cbOptionShowDownloadMangalistDialog.Checked); // misc - WriteBool('Batoto', 'ShowScanGroup', cbBatotoShowScanGroup.Checked); - WriteBool('Batoto', 'ShowAllLang', cbBatotoShowAllLang.Checked); - WriteBool('MangaFox', 'RemoveWatermark', cbMangaFoxRemoveWatermark.Checked); - WriteBool('MangaFox', 'SaveAsPNG', cbMangaFoxSaveAsPNG.Checked); - WriteBool('EHentai','DownloadOriginalImage',cbEHentaiDownloadOriginalImage.Checked); + finally UpdateFile; CopyFile(CONFIG_FILE_RUN, CONFIG_FILE, [cffOverwriteFile, cffPreserveTime]); end; + Modules.SaveWebsiteOption; end; procedure TMainForm.ApplyOptions; @@ -4544,15 +4540,6 @@ procedure TMainForm.ApplyOptions; itCheckFav.Enabled := OptionAutoCheckFavInterval; //misc - OptionBatotoShowScanGroup := cbBatotoShowScanGroup.Checked; - OptionBatotoShowAllLang := cbBatotoShowAllLang.Checked; - OptionMangaFoxRemoveWatermark := cbMangaFoxRemoveWatermark.Checked; - OptionMangaFoxSaveAsPNG := cbMangaFoxSaveAsPNG.Checked; - if OptionMangaFoxRemoveWatermark then - mangafoxwatermarkremover.LoadTemplate(CleanAndExpandDirectory(GetCurrentDirUTF8) + OptionMangaFoxTemplateFolder) - else - mangafoxwatermarkremover.ClearTemplate; - OptionEHentaiDownloadOriginalImage:=cbEHentaiDownloadOriginalImage.Checked; //languages ApplyLanguage; @@ -4982,6 +4969,9 @@ procedure TMainForm.ApplyLanguage; Self.Repaint; vtMangaList.Repaint; tvDownloadFilterRepaint; + + // refresh custom option + CustomOptionForm.CreateWebsiteOption; end; end; end; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 61c11b714..bd235fbb3 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -12,6 +12,18 @@ msgstr "" "X-Generator: Poedit 1.8.7\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Show all language" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Show scanlation group" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Download original image(require ExHentai account)" + #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" msgstr "Are you sure you want to delete this account?" @@ -276,6 +288,14 @@ msgstr "System will hibernate in %d second." msgid "System will shutdown in %d second." msgstr "System will shutdown in %d second." +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Remove watermark" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Save as PNG" + #: taccountmanagerform.btadd.caption msgid "Add" msgstr "Add" @@ -475,31 +495,10 @@ msgstr "Free Manga Downloader" msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" -#: tmainform.cbbatotoshowalllang.caption -msgid "Show all language" -msgstr "Show all language" - -#: tmainform.cbbatotoshowscangroup.caption -msgid "Show scan group name" -msgstr "Show scan group name" - -#: tmainform.cbehentaidownloadoriginalimage.caption -msgid "Download original image (require ExHentai account)" -msgstr "Download original image (require ExHentai account)" - #: tmainform.cbfilterstatus.text msgid "<none>" msgstr "<none>" -#: tmainform.cbmangafoxremovewatermark.caption -msgid "Remove watermark" -msgstr "Remove watermark" - -#: tmainform.cbmangafoxsaveaspng.caption -msgctxt "tmainform.cbmangafoxsaveaspng.caption" -msgid "Save as PNG" -msgstr "Save as PNG" - #: tmainform.cbonlynew.caption msgid "Search only new manga" msgstr "Search only new manga" @@ -1016,10 +1015,6 @@ msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." msgstr "Search website..." -#: tmainform.gbbatoto.caption -msgid "Batoto" -msgstr "Batoto" - #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" msgstr "Show dialog confirmation for" @@ -1028,14 +1023,6 @@ msgstr "Show dialog confirmation for" msgid "Drop Box" msgstr "Drop Box" -#: tmainform.gbehentai.caption -msgid "E-Hentai/ExHentai" -msgstr "E-Hentai/ExHentai" - -#: tmainform.gbmangafox.caption -msgid "Mangafox" -msgstr "Mangafox" - #: tmainform.gboptionexternal.caption msgid "External program" msgstr "External program" @@ -1552,6 +1539,7 @@ msgid "Misc" msgstr "Misc" #: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" msgid "Options" msgstr "Options" @@ -1568,7 +1556,18 @@ msgstr "Updates" msgid "View" msgstr "View" +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Options" + #: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Websites" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" msgid "Websites" msgstr "Websites" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 6a70b1fd6..7320b2707 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -12,6 +12,18 @@ msgstr "" "X-Generator: Poedit 1.8.7\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Tampilkan semua bahasa" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Tampilkan nama grup scan" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Unduh gambar asli(membutuhkan akun ExHentai)" + #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" msgstr "Apakah anda yakin ingin menghapus akun ini?" @@ -275,6 +287,14 @@ msgstr "Komputer akan dihibernasi dalam %d detik" msgid "System will shutdown in %d second." msgstr "Komputer akan dimatikan dalam %d detik" +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Hapus watermark" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Simpan sebagai PNG" + #: taccountmanagerform.btadd.caption msgid "Add" msgstr "Tambah" @@ -467,31 +487,10 @@ msgstr "Free Manga Downloader" msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" -#: tmainform.cbbatotoshowalllang.caption -msgid "Show all language" -msgstr "Tampilkan semua bahasa" - -#: tmainform.cbbatotoshowscangroup.caption -msgid "Show scan group name" -msgstr "Tampilkan nama grup scan" - -#: tmainform.cbehentaidownloadoriginalimage.caption -msgid "Download original image (require ExHentai account)" -msgstr "Unduh gambar asli (membutuhkan akun ExHentai)" - #: tmainform.cbfilterstatus.text msgid "<none>" msgstr "<none>" -#: tmainform.cbmangafoxremovewatermark.caption -msgid "Remove watermark" -msgstr "Hapus watermark" - -#: tmainform.cbmangafoxsaveaspng.caption -msgctxt "tmainform.cbmangafoxsaveaspng.caption" -msgid "Save as PNG" -msgstr "Simpan sebagai PNG" - #: tmainform.cbonlynew.caption msgid "Search only new manga" msgstr "Cari hanya komik baru" @@ -1002,10 +1001,6 @@ msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." msgstr "Cari situs web..." -#: tmainform.gbbatoto.caption -msgid "Batoto" -msgstr "Batoto" - #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" msgstr "Tampilkan dialog konfirmasi untuk" @@ -1014,14 +1009,6 @@ msgstr "Tampilkan dialog konfirmasi untuk" msgid "Drop Box" msgstr "Kotak unduh" -#: tmainform.gbehentai.caption -msgid "E-Hentai/ExHentai" -msgstr "E-Hentai/ExHentai" - -#: tmainform.gbmangafox.caption -msgid "Mangafox" -msgstr "Mangafox" - #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Program eksternal" @@ -1535,6 +1522,7 @@ msgid "Misc" msgstr "Lain-lain" #: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" msgid "Options" msgstr "Pengaturan" @@ -1551,7 +1539,18 @@ msgstr "Pembaruan" msgid "View" msgstr "Tampilan" +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Pengaturan" + #: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Situs web" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" msgid "Websites" msgstr "Situs web" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 4f6c14334..045edd275 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1,6 +1,18 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "" + #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" msgstr "" @@ -247,6 +259,14 @@ msgstr "" msgid "System will shutdown in %d second." msgstr "" +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "" + #: taccountmanagerform.btadd.caption msgid "Add" msgstr "" @@ -439,31 +459,10 @@ msgstr "" msgid "Add to download list as stopped task" msgstr "" -#: tmainform.cbbatotoshowalllang.caption -msgid "Show all language" -msgstr "" - -#: tmainform.cbbatotoshowscangroup.caption -msgid "Show scan group name" -msgstr "" - -#: tmainform.cbehentaidownloadoriginalimage.caption -msgid "Download original image (require ExHentai account)" -msgstr "" - #: tmainform.cbfilterstatus.text msgid "<none>" msgstr "" -#: tmainform.cbmangafoxremovewatermark.caption -msgid "Remove watermark" -msgstr "" - -#: tmainform.cbmangafoxsaveaspng.caption -msgctxt "TMAINFORM.CBMANGAFOXSAVEASPNG.CAPTION" -msgid "Save as PNG" -msgstr "" - #: tmainform.cbonlynew.caption msgid "Search only new manga" msgstr "" @@ -972,10 +971,6 @@ msgctxt "TMAINFORM.EDWEBSITESSEARCH.TEXTHINT" msgid "Search website..." msgstr "" -#: tmainform.gbbatoto.caption -msgid "Batoto" -msgstr "" - #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" msgstr "" @@ -984,14 +979,6 @@ msgstr "" msgid "Drop Box" msgstr "" -#: tmainform.gbehentai.caption -msgid "E-Hentai/ExHentai" -msgstr "" - -#: tmainform.gbmangafox.caption -msgid "Mangafox" -msgstr "" - #: tmainform.gboptionexternal.caption msgid "External program" msgstr "" @@ -1480,6 +1467,7 @@ msgid "Misc" msgstr "" #: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" msgid "Options" msgstr "" @@ -1496,7 +1484,18 @@ msgstr "" msgid "View" msgstr "" +#: tmainform.tswebsiteoptions.caption +msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" +msgid "Options" +msgstr "" + #: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "" + +#: tmainform.tswebsiteselection.caption +msgctxt "TMAINFORM.TSWEBSITESELECTION.CAPTION" msgid "Websites" msgstr "" From c5647663856dbc6553f147529cd89bc403404925 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 05:07:24 +0800 Subject: [PATCH 1082/2794] rename options --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index c7f1679e2..ff95fbc2b 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -392,7 +392,7 @@ procedure RegisterModule; begin with AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org') do - AddOption(woCheckBox, @downloadoriginalimage, 'DownloadOriginal', @RS_DownloadOriginalImage); + AddOption(woCheckBox, @downloadoriginalimage, 'DownloadOriginalImage', @RS_DownloadOriginalImage); with AddWebsiteModule('ExHentai', 'http://exhentai.org') do begin AccountSupport := True; OnLogin := @ExHentaiLogin; From cb43989f1829463bd68128ce431c6ae9c6c53732 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 05:08:20 +0800 Subject: [PATCH 1083/2794] added fmdoptions unit, for all options related --- baseunits/CheckUpdate.pas | 2 +- baseunits/DBDataProcess.pas | 2 +- baseunits/FMDOptions.pas | 259 ++++++++++++++++++ baseunits/WebsiteModules.pas | 13 +- .../NineManga/directory_page_number.inc | 2 +- baseunits/uBaseUnit.pas | 142 +--------- baseunits/uData.pas | 10 +- baseunits/uDownloadsManager.pas | 19 +- baseunits/uFavoritesManager.pas | 12 +- baseunits/uGetMangaInfosThread.pas | 4 +- baseunits/uSilentThread.pas | 8 +- baseunits/uUpdateDBThread.pas | 2 +- baseunits/uUpdateThread.pas | 12 +- mangadownloader/forms/frmAccountManager.pas | 8 +- mangadownloader/forms/frmImportFavorites.pas | 4 +- mangadownloader/forms/frmMain.pas | 87 ++---- mangadownloader/md.lpi | 6 +- mangadownloader/md.lpr | 2 +- 18 files changed, 334 insertions(+), 260 deletions(-) create mode 100644 baseunits/FMDOptions.pas diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 6c04f8aac..aa64e1826 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, Forms, Controls, uFMDThread, uBaseUnit; + Classes, SysUtils, Forms, Controls, uFMDThread, uBaseUnit, FMDOptions; type diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 9d907a546..a959d49bd 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, FileUtil, LazFileUtils, sqlite3conn, sqlite3backup, + Classes, SysUtils, FileUtil, LazFileUtils, FMDOptions, sqlite3conn, sqlite3backup, sqlite3dyn, sqldb, DB, dateutils, RegExpr; type diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas new file mode 100644 index 000000000..132708233 --- /dev/null +++ b/baseunits/FMDOptions.pas @@ -0,0 +1,259 @@ +unit FMDOptions; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, IniFiles, fileinfo, LazFileUtils, LazUTF8, FileUtil, Forms, LCLProc; + +type + + { TIniFileRun } + + TIniFileRun = class(IniFiles.TMemIniFile) + private + FCSLock: TRTLCriticalSection; + FFileAge: Longint; + FRealFileName: String; + public + constructor Create(const AFileName: string; AEscapeLineFeeds: Boolean = False); overload; override; + destructor Destroy; override; + procedure UpdateFile; override; + procedure Reload; + end; + +const + FMD_REVISION = '$WCREV$'; + FMD_INSTANCE = '_FreeMangaDownloaderInstance_'; + FMD_TARGETOS = {$i %FPCTARGETOS%}; + FMD_TARGETCPU = {$i %FPCTARGETCPU%}; + + EXPARAM_PATH = '%PATH%'; + EXPARAM_CHAPTER = '%CHAPTER%'; + DEFAULT_EXPARAM = '"' + EXPARAM_PATH + EXPARAM_CHAPTER + '"'; + + SOCKHEARTBEATRATE = 400; + + DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; + DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; + DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; + + DATA_EXT = '.dat'; + DBDATA_EXT = '.db'; + UPDATER_EXE = 'updater.exe'; + ZIP_EXE = '7za.exe'; + RUN_EXE = '.run'; + +var + FMD_VERSION_NUMBER, + FMD_DIRECTORY, + APPDATA_DIRECTORY, + DEFAULT_PATH, + WORK_FOLDER, + WORK_FILE, + DOWNLOADEDCHAPTERS_FILE, + DOWNLOADEDCHAPTERSDB_FILE, + FAVORITES_FILE, + CONFIG_FOLDER, + CONFIG_FILE, + CONFIG_ADVANCED, + REVISION_FILE, + UPDATE_FILE, + MANGALIST_FILE, + ACCOUNTS_FILE, + WEBSITE_CONFIG_FILE, + DATA_FOLDER, + IMAGE_FOLDER, + LANGUAGE_FILE, + CHANGELOG_FILE, + README_FILE, + EXTRAS_FOLDER, + MANGAFOXTEMPLATE_FOLDER: String; + + // ini files + revisionfile, + updatesfile, + mangalistfile: TIniFile; + configfile, + advancedfile: TIniFileRun; + +// set base directory +procedure SetFMDdirectory(const ADir: String); +procedure SetAppDataDirectory(const ADir: String); + +implementation + +{ TIniFileRun } + +constructor TIniFileRun.Create(const AFileName: string; AEscapeLineFeeds: Boolean); +begin + FRealFileName := AFileName; + if FileExistsUTF8(AFileName + RUN_EXE) then + DeleteFileUTF8(RUN_EXE); + if FileExistsUTF8(AFileName) then + CopyFile(AFileName, AFileName + RUN_EXE); + InitCriticalSection(FCSLock); + if FileExistsUTF8(AFileName) then + FFileAge := FileAgeUTF8(AFileName) + else + FFileAge := 0; + inherited Create(AFileName + RUN_EXE, AEscapeLineFeeds); +end; + +destructor TIniFileRun.Destroy; +begin + inherited Destroy; + DoneCriticalsection(FCSLock); + if FileExistsUTF8(FileName) then + DeleteFileUTF8(FileName); +end; + +procedure TIniFileRun.UpdateFile; +begin + inherited UpdateFile; + CopyFile(FileName, FRealFileName, [cffOverwriteFile, cffPreserveTime, cffCreateDestDirectory]); +end; + +procedure TIniFileRun.Reload; +var + s: TStringList; +begin + if TryEnterCriticalsection(FCSLock) > 0 then + try + if FileExistsUTF8(FileName) then + if FileAgeUTF8(FileName) <> FFileAge then + begin + s := TStringList.Create; + try + FFileAge := FileAge(FileName); + s.LoadFromFile(FileName); + SetStrings(s); + finally + s.Free; + end; + end; + finally + LeaveCriticalsection(FCSLock); + end; +end; + +procedure FreeNil(var Obj); +begin + if Pointer(Obj) <> nil then + TObject(Obj).Free; + Pointer(Obj) := nil; +end; + +procedure FreeIniFiles; +begin + FreeNil(mangalistfile); + FreeNil(configfile); + FreeNil(advancedfile); +end; + +procedure SetIniFiles; +begin + FreeIniFiles; + mangalistfile := TIniFile.Create(MANGALIST_FILE); + configfile := TIniFileRun.Create(CONFIG_FILE); + configfile.Options := configfile.Options - [ifoStripQuotes]; + advancedfile := TIniFileRun.Create(CONFIG_ADVANCED); +end; + +procedure SetFMDdirectory(const ADir: String); +begin + FMD_DIRECTORY := CleanAndExpandDirectory(ADir); + + CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; + REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; + UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; + MANGALIST_FILE := CONFIG_FOLDER + 'mangalist.ini'; + + IMAGE_FOLDER := FMD_DIRECTORY + 'images' + PathDelim; + LANGUAGE_FILE := FMD_DIRECTORY + 'languages.ini'; + CHANGELOG_FILE := FMD_DIRECTORY + 'changelog.txt'; + README_FILE := FMD_DIRECTORY + 'readme.rtf'; + EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; + MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; +end; + +procedure SetAppDataDirectory(const ADir: String); +begin + APPDATA_DIRECTORY := CleanAndExpandDirectory(ADir); + + DEFAULT_PATH := APPDATA_DIRECTORY + 'downloads' + PathDelim; + + CONFIG_FOLDER := APPDATA_DIRECTORY + 'config' + PathDelim; + CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; + CONFIG_ADVANCED := CONFIG_FOLDER + 'advanced.ini'; + ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; + WEBSITE_CONFIG_FILE := CONFIG_FOLDER + 'websiteconfig.ini'; + + DATA_FOLDER := APPDATA_DIRECTORY + 'data' + PathDelim; + + WORK_FOLDER := APPDATA_DIRECTORY + 'works' + PathDelim; + WORK_FILE := WORK_FOLDER + 'works.ini'; + DOWNLOADEDCHAPTERS_FILE := WORK_FOLDER + 'downloadedchapters.ini'; + DOWNLOADEDCHAPTERSDB_FILE := WORK_FOLDER + 'downloadedchapters.db'; + FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; + + SetIniFiles; +end; + +function GetCurrentBinVersion: String; +var + AppVerInfo: TStringList; + i: Integer; +begin + Result := ''; + AppVerInfo := TStringList.Create; + with TFileVersionInfo.Create(nil) do + try + try + FileName := ParamStrUTF8(0); + if FileName = '' then + FileName := Application.ExeName; + {$IF FPC_FULLVERSION >= 20701} + ReadFileInfo; + {$ENDIF} + if VersionStrings.Count > 0 then + begin + {$IF FPC_FULLVERSION >= 20701} + AppVerInfo.Assign(VersionStrings); + {$ELSE} + for i := 0 to VersionStrings.Count - 1 do + AppVerInfo.Add(VersionCategories.Strings[i] + '=' + + VersionStrings.Strings[i]); + {$ENDIF} + for i := 0 to AppVerInfo.Count - 1 do + AppVerInfo.Strings[i] := LowerCase(AppVerInfo.Names[i]) + '=' + AppVerInfo.ValueFromIndex[i]; + Result := AppVerInfo.Values['fileversion']; + end; + except + end; + finally + Free; + AppVerInfo.Free; + end; +end; + +procedure doInitialization; +begin + FMD_VERSION_NUMBER := GetCurrentBinVersion; + SetFMDdirectory(GetCurrentDirUTF8); + SetAppDataDirectory(GetCurrentDirUTF8); +end; + +procedure doFinalization; +begin + FreeIniFiles; +end; + +initialization + doInitialization; + +finalization + doFinalization; + +end. diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 4de2df9dd..456d6c15a 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager, uBaseUnit, RegExpr, IniFiles; + Classes, SysUtils, uData, uDownloadsManager, uBaseUnit, FMDOptions, RegExpr, IniFiles; const MODULE_NOT_FOUND = -1; @@ -107,7 +107,6 @@ TWebsiteModules = class private FCSModules: TRTLCriticalSection; FModuleList: TFPList; - FWebsiteOptionFile: TIniFile; function GetModule(const ModuleId: Integer): TModuleContainer; function GetCount: Integer; function GetMaxTaskLimit(const ModuleId: Integer): Integer; @@ -302,16 +301,12 @@ constructor TWebsiteModules.Create; begin InitCriticalSection(FCSModules); FModuleList := TFPList.Create; - FWebsiteOptionFile := TIniFile.Create(WEBSITE_CONFIG_FILE); - FWebsiteOptionFile.CacheUpdates := True; end; destructor TWebsiteModules.Destroy; var i: Integer; begin - if Assigned(FWebsiteOptionFile) then - FWebsiteOptionFile.Free; if FModuleList.Count > 0 then for i := 0 to FModuleList.Count - 1 do TModuleContainer(FModuleList[i]).Free; @@ -658,7 +653,7 @@ procedure TWebsiteModules.LoadWebsiteOption; with TModuleContainer(FModuleList[i]) do if Length(OptionList) > 0 then for j := Low(OptionList) to High(OptionList) do - with OptionList[j], FWebsiteOptionFile do + with OptionList[j], configfile do begin case OptionType of woCheckBox: PBoolean(BindValue)^ := ReadBool(Website, Name, PBoolean(BindValue)^); @@ -677,7 +672,7 @@ procedure TWebsiteModules.SaveWebsiteOption; with TModuleContainer(FModuleList[i]) do if Length(OptionList) > 0 then for j := Low(OptionList) to High(OptionList) do - with OptionList[j], FWebsiteOptionFile do + with OptionList[j], configfile do begin case OptionType of woCheckBox: WriteBool(Website, Name, PBoolean(BindValue)^); @@ -685,7 +680,7 @@ procedure TWebsiteModules.SaveWebsiteOption; woSpinEdit: WriteInteger(Website, Name, PInteger(BindValue)^); end; end; - FWebsiteOptionFile.UpdateFile; + configfile.UpdateFile; end; function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; diff --git a/baseunits/includes/NineManga/directory_page_number.inc b/baseunits/includes/NineManga/directory_page_number.inc index 01701e22b..46f7ea073 100644 --- a/baseunits/includes/NineManga/directory_page_number.inc +++ b/baseunits/includes/NineManga/directory_page_number.inc @@ -8,7 +8,7 @@ BROWSER_INVERT := True; //I can't get manga directory total pages. Its not available on any page //The only option to get total pages is just checking manually with browser :( - p := INIAdvanced.ReadInteger('UpdateListDirectoryPageNumber', website, -1); + p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', website, -1); if p > 0 then Page := p else diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index edfc8e887..bdaa662bc 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -21,29 +21,19 @@ interface SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, - synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, simplehtmltreeparser, + synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, Imaging, ImagingExtras, SimpleException, SimpleLogger; type TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); const - FMD_REVISION = '$WCREV$'; - FMD_INSTANCE = '_FreeMangaDownloaderInstance_'; - - FMD_TARGETOS = {$i %FPCTARGETOS%}; - FMD_TARGETCPU = {$i %FPCTARGETCPU%}; - JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); GIF_HEADER: array[0..2] of Byte = ($47, $49, $46); PNG_HEADER: array[0..2] of Byte = ($89, $50, $4E); UTF8BOM = #$EF#$BB#$BF; - EXPARAM_PATH = '%PATH%'; - EXPARAM_CHAPTER = '%CHAPTER%'; - DEFAULT_EXPARAM = '"' + EXPARAM_PATH + EXPARAM_CHAPTER + '"'; - DATA_PARAM_TITLE = 0; DATA_PARAM_LINK = 1; DATA_PARAM_AUTHORS = 2; @@ -207,12 +197,6 @@ interface NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; - SOCKHEARTBEATRATE = 400; - - DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; - DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; - DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; - FMDFormatSettings :TFormatSettings = ( CurrencyFormat :1; NegCurrFormat :5; @@ -515,44 +499,7 @@ interface '/series' ); - DATA_EXT = '.dat'; - DBDATA_EXT = '.db'; - UPDATER_EXE = 'updater.exe'; - ZIP_EXE = '7za.exe'; - -var - FMD_VERSION_NUMBER, - FMD_DIRECTORY, - WORK_FOLDER, - WORK_FILE, - WORK_FILE_RUN, - DOWNLOADEDCHAPTERS_FILE, - DOWNLOADEDCHAPTERSDB_FILE, - FAVORITES_FILE, - FAVORITES_FILE_RUN, - CONFIG_FOLDER, - CONFIG_FILE, - CONFIG_FILE_RUN, - CONFIG_ADVANCED, - REVISION_FILE, - UPDATE_FILE, - MANGALIST_FILE, - ACCOUNTS_FILE, - WEBSITE_CONFIG_FILE, - DATA_FOLDER, - IMAGE_FOLDER, - LANGUAGE_FILE, - CHANGELOG_FILE, - README_FILE, - EXTRAS_FOLDER, - MANGAFOXTEMPLATE_FOLDER: String; - - {$IFDEF WINDOWS} - DEFAULT_PATH: String = '\downloads'; - {$ELSE} - DEFAULT_PATH: String = '/downloads'; - {$ENDIF} - +var // Sites var BROWSER_INVERT: Boolean = False; @@ -747,10 +694,6 @@ THTMLForm = class property Data: TStringList read fdata; end; -// Set base directory -procedure SetFMDdirectory(const ADir: String); -// Get current binary version -function GetCurrentBinVersion: String; // Remove Unicode function UnicodeRemove(const S: String): String; // Check a directory to see if it's empty (return TRUE) or not @@ -1043,76 +986,6 @@ function NTSetPrivilege(sPrivilege: String; bEnabled: Boolean): Boolean; {$ENDIF} -procedure SetFMDdirectory(const ADir: String); -begin WriteLog_D('setfmddirectory: '+adir); - FMD_DIRECTORY := CleanAndExpandDirectory(ADir); - - WORK_FOLDER := FMD_DIRECTORY + 'works' + PathDelim; - WORK_FILE := WORK_FOLDER + 'works.ini'; - WORK_FILE_RUN := WORK_FILE + '.run'; - DOWNLOADEDCHAPTERS_FILE := WORK_FOLDER + 'downloadedchapters.ini'; - DOWNLOADEDCHAPTERSDB_FILE := WORK_FOLDER + 'downloadedchapters.db'; - FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; - FAVORITES_FILE_RUN := FAVORITES_FILE + '.run'; - - CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; - CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; - CONFIG_FILE_RUN := CONFIG_FILE + '.run'; - CONFIG_ADVANCED := CONFIG_FOLDER + 'advanced.ini'; - REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; - UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; - MANGALIST_FILE := CONFIG_FOLDER + 'mangalist.ini'; - ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; - WEBSITE_CONFIG_FILE := CONFIG_FOLDER + 'websiteconfig.ini'; - - DATA_FOLDER := FMD_DIRECTORY + 'data' + PathDelim; - - IMAGE_FOLDER := FMD_DIRECTORY + 'images' + PathDelim; - LANGUAGE_FILE := FMD_DIRECTORY + 'languages.ini'; - CHANGELOG_FILE := FMD_DIRECTORY + 'changelog.txt'; - README_FILE := FMD_DIRECTORY + 'readme.rtf'; - - EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; - MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; -end; - -function GetCurrentBinVersion: String; -var - AppVerInfo: TStringList; - i: Integer; -begin - Result := ''; - AppVerInfo := TStringList.Create; - with TFileVersionInfo.Create(nil) do - try - try - FileName := ParamStrUTF8(0); - if FileName = '' then - FileName := Application.ExeName; - {$IF FPC_FULLVERSION >= 20701} - ReadFileInfo; - {$ENDIF} - if VersionStrings.Count > 0 then - begin - {$IF FPC_FULLVERSION >= 20701} - AppVerInfo.Assign(VersionStrings); - {$ELSE} - for i := 0 to VersionStrings.Count - 1 do - AppVerInfo.Add(VersionCategories.Strings[i] + '=' + - VersionStrings.Strings[i]); - {$ENDIF} - for i := 0 to AppVerInfo.Count - 1 do - AppVerInfo.Strings[i] := LowerCase(AppVerInfo.Names[i]) + '=' + AppVerInfo.ValueFromIndex[i]; - Result := AppVerInfo.Values['fileversion']; - end; - except - end; - finally - Free; - AppVerInfo.Free; - end; -end; - function UnicodeRemove(const S: String): String; var i: Cardinal; @@ -2320,7 +2193,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, Result := StringReplaceBrackets(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); // pad number chap := Trim(AChapter); - with MainForm.options do begin + with configfile do begin if ReadBool('saveto', 'ConvertDigitVolume', False) then begin if ReadBool('saveto', 'ConvertDigitChapter', False) then VolumeChapterPadZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), @@ -4021,13 +3894,4 @@ function HeaderByName(const AHeaders: TStrings; const AHeaderName: String): Stri end; end; -initialization - SetFMDdirectory(GetCurrentDirUTF8); - FMD_VERSION_NUMBER := GetCurrentBinVersion; - {$IFDEF WINDOWS} - DEFAULT_PATH := GetCurrentDir + DirectorySeparator + 'downloads'; - {$ELSE} - DEFAULT_PATH := '/downloads'; - {$ENDIF} - end. diff --git a/baseunits/uData.pas b/baseunits/uData.pas index e3b7ee14e..56e37052a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,7 +14,7 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FileUtil, + Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FMDOptions, FileUtil, LazFileUtils, SimpleLogger, strutils, dateutils, RegExpr, httpsend; type @@ -832,11 +832,11 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St begin Page := 0; - //load User-Agent from INIAdvanced + //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, website); //load pagenumber_config if available - p := INIAdvanced.ReadInteger('UpdateListDirectoryPageNumber', website, -1); + p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', website, -1); if p > 0 then begin @@ -1093,7 +1093,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Dynasty-Scans/names_and_links.inc} begin - //load User-Agent from INIAdvanced + //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, website); if ModuleId < 0 then @@ -1429,7 +1429,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if Trim(URL) = '' then Exit(INFORMATION_NOT_FOUND); - //load User-Agent from INIAdvanced + //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, website); mangaInfo.website := website; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 20a81e4e1..b5eb7f1ec 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface lazutf8classes, LazFileUtils, FileUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, - uFMDThread, uMisc, DownloadedChaptersDB, SimpleLogger, dateutils; + uFMDThread, uMisc, DownloadedChaptersDB, FMDOptions, SimpleLogger, dateutils; type TDownloadManager = class; @@ -152,7 +152,7 @@ TDownloadManager = class FTotalReadCount: Integer; FSortDirection: Boolean; FSortColumn: Integer; - DownloadManagerFile: TIniFile; + DownloadManagerFile: TIniFileRun; function GetItems(Index: Integer): TTaskContainer; protected function GetTaskCount: Integer; @@ -1133,7 +1133,7 @@ procedure TTaskThread.CheckOut; if Terminated then Exit; //load advanced config if any - mt := INIAdvanced.ReadInteger('DownloadMaxThreadsPerTask', + mt := advancedfile.ReadInteger('DownloadMaxThreadsPerTask', container.DownloadInfo.Website, -1); if (mt > 0) then begin @@ -1186,7 +1186,7 @@ procedure TTaskThread.CheckOut; ModuleId := Self.ModuleId; workCounter := container.WorkCounter; checkStyle := Flag; - //load User-Agent from INIAdvanced + //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, container.DownloadInfo.Website); Start; container.WorkCounter := InterLockedIncrement(container.WorkCounter); @@ -1255,7 +1255,7 @@ procedure TTaskThread.Execute; S, P: String; DynamicPageLink: Boolean; begin - INIAdvanced.Reload; + advancedfile.Reload; ModuleId := container.ModuleId; container.ThreadState := True; container.DownloadInfo.TransferRate := ''; @@ -1634,12 +1634,7 @@ constructor TDownloadManager.Create; CS_DownloadManager_Task := TCriticalSection.Create; CS_DownloadedChapterList := TCriticalSection.Create; - if FileExistsUTF8(WORK_FILE_RUN) then - DeleteFileUTF8(WORK_FILE_RUN); - if FileExistsUTF8(WORK_FILE) then - CopyFile(WORK_FILE, WORK_FILE_RUN, [cffOverwriteFile, cffPreserveTime]); - - DownloadManagerFile := TIniFile.Create(WORK_FILE_RUN); + DownloadManagerFile := TIniFileRun.Create(WORK_FILE); DownloadManagerFile.CacheUpdates := True; DownloadedChapters := TDownloadedChaptersDB.Create; @@ -1671,7 +1666,6 @@ destructor TDownloadManager.Destroy; end; FreeAndNil(Containers); FreeAndNil(DownloadManagerFile); - DeleteFileUTF8(WORK_FILE_RUN); DownloadedChapters.Free; CS_DownloadedChapterList.Free; CS_DownloadManager_Task.Free; @@ -1813,7 +1807,6 @@ procedure TDownloadManager.Backup; end; end; UpdateFile; - CopyFile(WORK_FILE_RUN, WORK_FILE, [cffOverwriteFile, cffPreserveTime]); finally CS_DownloadManager_Task.Release; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 8462f3744..4afe8cff6 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, FileUtil, - uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, + uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, FMDOptions, SimpleException; type @@ -90,7 +90,7 @@ TFavoriteManager = class protected function GetFavoritesCount: Integer; public - favoritesFile: TIniFile; + favoritesFile: TIniFileRun; taskthread: TFavoriteTask; DLManager: TDownloadManager; OnUpdateFavorite: procedure of object; @@ -428,11 +428,7 @@ constructor TFavoriteManager.Create; ForceDirectoriesUTF8(WORK_FOLDER); CS_Favorites := TCriticalSection.Create; isRunning := False; - if FileExistsUTF8(FAVORITES_FILE_RUN) then - DeleteFileUTF8(FAVORITES_FILE_RUN); - if FileExistsUTF8(FAVORITES_FILE) then - CopyFile(FAVORITES_FILE, FAVORITES_FILE_RUN, [cffOverwriteFile, cffPreserveTime]); - favoritesFile := TIniFile.Create(FAVORITES_FILE_RUN); + favoritesFile := TIniFileRun.Create(FAVORITES_FILE); favoritesFile.CacheUpdates := True; FFavorites := TFPList.Create; Restore; @@ -442,7 +438,6 @@ destructor TFavoriteManager.Destroy; begin Backup; favoritesFile.Free; - DeleteFileUTF8(FAVORITES_FILE_RUN); if FFavorites.Count > 0 then begin StopChekForNewChapter; while FFavorites.Count > 0 do begin @@ -943,7 +938,6 @@ procedure TFavoriteManager.Backup; WriteString(IntToStr(i), 'Link', Link); end; UpdateFile; - CopyFile(FAVORITES_FILE_RUN, FAVORITES_FILE, [cffOverwriteFile, cffPreserveTime]); end; end; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 4924c0eca..de2699e0f 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -16,7 +16,7 @@ interface uses - SysUtils, Graphics, Dialogs, uBaseUnit, uData, uFMDThread; + SysUtils, Graphics, Dialogs, uBaseUnit, uData, uFMDThread, FMDOptions; type @@ -139,7 +139,7 @@ procedure TGetMangaInfosThread.DoGetInfos; begin try - INIAdvanced.Reload; + advancedfile.Reload; if not GetMangaInfo then begin if not Self.Terminated then diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index c583a94a5..374ad3bdf 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -16,7 +16,7 @@ interface uses Classes, SysUtils, uBaseUnit, uData, uFMDThread, uDownloadsManager, - WebsiteModules, LazFileUtils; + WebsiteModules, FMDOptions, LazFileUtils; type @@ -191,7 +191,7 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; procedure TSilentThreadManager.Checkout(Index: Integer); begin if (Index < 0) or (Index >= MetaData.Count) then Exit; - INIAdvanced.Reload; + advancedfile.Reload; Modules.IncActiveConnectionCount(TSilentThreadMetaData(MetaData[Index]).ModuleId); case TSilentThreadMetaData(MetaData[Index]).MetaDataType of MD_DownloadAll: Threads.Add(TSilentThread.Create); @@ -359,7 +359,7 @@ procedure TSilentThread.MainThreadAfterChecking; if FSavePath = '' then begin if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := options.ReadString('saveto', 'SaveTo', DEFAULT_PATH); + edSaveTo.Text := configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH); if Trim(edSaveTo.Text) = '' then edSaveTo.Text := DEFAULT_PATH; edSaveTo.Text := CleanAndExpandDirectory(CorrectPathSys(edSaveTo.Text)); @@ -455,7 +455,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; if FSavePath = '' then begin if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := options.ReadString('saveto', 'SaveTo', DEFAULT_PATH); + edSaveTo.Text := configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH); if Trim(edSaveTo.Text) = '' then edSaveTo.Text := DEFAULT_PATH; edSaveTo.Text := CorrectPathSys(edSaveTo.Text); diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index c4cd07479..2e608988f 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, uBaseUnit, uMisc, SimpleTranslator, + Classes, SysUtils, uBaseUnit, uMisc, SimpleTranslator, FMDOptions, LazFileUtils; type diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index cb6e40399..790a44f7d 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, - uBaseUnit, uFMDThread, uMisc, WebsiteModules, DBDataProcess, SimpleTranslator; + uBaseUnit, uFMDThread, uMisc, WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions; type TUpdateListManagerThread = class; @@ -443,9 +443,9 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; begin MainForm.ulTotalPtr := limit; try - INIAdvanced.Reload; + advancedfile.Reload; while (not Terminated) and (workPtr < limit) do begin - mt := INIAdvanced.ReadInteger('UpdateListNumberOfThreads', website, -1); + mt := advancedfile.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then begin if mt > MAX_CONNECTIONPERHOSTLIMIT then //32 is max | be carefull, there's still memory leak problems @@ -524,7 +524,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; FStatus := s; MainForm.ulWorkPtr := workPtr + 1; Synchronize(MainThreadShowGetting); - INIAdvanced.Reload; + advancedfile.Reload; finally UnlockCreateConnection; end; @@ -618,7 +618,7 @@ procedure TUpdateListManagerThread.Execute; Writelog_D(cloghead+'get number of directory page'); // get directory page count - INIAdvanced.Reload; + advancedfile.Reload; directoryCount := 0; directoryCount2 := 0; workPtr := 0; @@ -631,7 +631,7 @@ procedure TUpdateListManagerThread.Execute; Writelog_D(cloghead+'get names and links'); // get names and links - INIAdvanced.Reload; + advancedfile.Reload; workPtr := 0; isFinishSearchingForNewManga := False; if ModuleId <> -1 then diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index e5296ef61..a18fac4c2 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -5,9 +5,9 @@ interface uses - Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Buttons, + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, uFMDThread, - uBaseUnit, frmAccountSet, SimpleLogger, SimpleException; + uBaseUnit, FMDOptions, frmAccountSet, SimpleException; type @@ -230,7 +230,7 @@ procedure TAccountManagerForm.SaveForm; var i: Integer; begin - with MainForm.options, vtAccountList.Header.Columns do begin + with configfile, vtAccountList.Header.Columns do begin if Count > 0 then for i := 0 to Count - 1 do WriteInteger('form', 'vtAccountList' + IntToStr(i) + 'Width', Items[i].Width); @@ -241,7 +241,7 @@ procedure TAccountManagerForm.LoadForm; var i: Integer; begin - with MainForm.options, vtAccountList.Header.Columns do begin + with configfile, vtAccountList.Header.Columns do begin if Count > 0 then for i := 0 to Count - 1 do Items[i].Width := ReadInteger('form', 'vtAccountList' + IntToStr(i) + 'Width', 50); diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index b97cfcc91..585e19475 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, Forms, Dialogs, StdCtrls, Buttons, DefaultTranslator, EditBtn, - lazutf8classes, LazFileUtils, uBaseUnit, WebsiteModules, RegExpr, + lazutf8classes, LazFileUtils, uBaseUnit, WebsiteModules, FMDOptions, RegExpr, frmNewChapter; type @@ -87,7 +87,7 @@ procedure TImportFavorites.DMDHandle; if urlList.Count > 0 then begin - path:= CleanAndExpandDirectory(MainForm.options.ReadString('saveto', 'SaveTo', '')); + path:= CleanAndExpandDirectory(configfile.ReadString('saveto', 'SaveTo', '')); regx := TRegExpr.Create; try regx.Expression := REGEX_HOST; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 66f6a8568..076748662 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmCustomOption, CheckUpdate, accountmanagerdb, DBDataProcess, - mangafoxwatermarkremover, SimpleTranslator, SimpleException, SimpleLogger; + mangafoxwatermarkremover, SimpleTranslator, FMDOptions, SimpleException, SimpleLogger; type @@ -552,7 +552,6 @@ TMainForm = class(TForm) LastSearchStr, LastSearchWeb: String; isStartup, isExiting, isRunDownloadFilter, isUpdating, isPendingExitCounter, isNormalExit: Boolean; - revisionIni, updates, mangalistIni, options: TIniFile; FavoriteManager: TFavoriteManager; dataProcess: TDBDataProcess; mangaInfo: TMangaInfo; @@ -694,7 +693,6 @@ TSearchDBThread = class(TThread) FMDInstance: TSimpleIPCServer; MainForm: TMainForm; - INIAdvanced: TIniFileR; // update fmd through main thread DoAfterFMD: TFMDDo; @@ -840,9 +838,9 @@ procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); begin if HTTP = nil then Exit; if Website = '' then Exit; - s:=Trim(INIAdvanced.ReadString('UserAgent',Website,'')); + s:=Trim(advancedfile.ReadString('UserAgent',Website,'')); if s<>'' then HTTP.UserAgent:=s; - s:=Trim(INIAdvanced.ReadString('Cookies',Website,'')); + s:=Trim(advancedfile.ReadString('Cookies',Website,'')); if s<>'' then HTTP.Cookies.Text:=s; end; @@ -1026,9 +1024,6 @@ procedure TMainForm.FormCreate(Sender: TObject); // account accountmanagerdb.InitAccountManager(ACCOUNTS_FILE); - // advanced settings - INIAdvanced := TIniFileR.Create(CONFIG_ADVANCED); - // main dataprocess dataProcess := TDBDataProcess.Create; @@ -1048,26 +1043,6 @@ procedure TMainForm.FormCreate(Sender: TObject); // ShowInformation mangaInfo := TMangaInfo.Create; - // Load config.ini - if FileExistsUTF8(CONFIG_FILE_RUN) then - DeleteFileUTF8(CONFIG_FILE_RUN); - if FileExistsUTF8(CONFIG_FILE) then - CopyFile(CONFIG_FILE, CONFIG_FILE_RUN, [cffOverwriteFile, cffPreserveTime]); - options := TIniFile.Create(CONFIG_FILE_RUN); - options.CacheUpdates := True; - options.Options := options.Options-[ifoStripQuotes]; - - // Load revision.ini - revisionIni := TIniFile.Create(REVISION_FILE); - - // Load updates.ini - updates := TIniFile.Create(UPDATE_FILE); - updates.CacheUpdates := False; - - // Load mangalist.ini - mangalistIni := TIniFile.Create(MANGALIST_FILE); - mangalistIni.CacheUpdates := True; - // generate tvDownloadFilter nodes GeneratetvDownloadFilterNodes; @@ -1090,10 +1065,6 @@ procedure TMainForm.FormCreate(Sender: TObject); TrayIcon.Show; - // load some necessary options at startup - Revision := revisionIni.ReadInteger('general', 'Revision', 0); - revisionIni.Free; - currentJDN := GetCurrentJDN; // read online @@ -1166,7 +1137,7 @@ procedure TMainForm.FormCreate(Sender: TObject); // load mangafox template mangafoxwatermarkremover.LoadTemplate(MANGAFOXTEMPLATE_FOLDER); - // load options + // load configfile isStartup := False; CollectLanguagesFromFiles; LoadFormInformation; @@ -1283,11 +1254,6 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(gifWaiting); FreeAndNil(mangaCover); - FreeAndNil(mangalistIni); - FreeAndNil(updates); - FreeAndNil(options); - DeleteFileUTF8(CONFIG_FILE_RUN); - FreeAndNil(INIAdvanced); if isNormalExit then Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']') else @@ -1511,7 +1477,7 @@ procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); if Sender = miChapterListHideDownloaded then begin miChapterListHideDownloaded.Checked := not miChapterListHideDownloaded.Checked; - options.WriteBool('general', 'ChapterListHideDownloaded', miChapterListHideDownloaded.Checked); + configfile.WriteBool('general', 'ChapterListHideDownloaded', miChapterListHideDownloaded.Checked); end; if (Length(ChapterList) = 0) or (Length(ChapterList) <> clbChapterList.RootNodeCount) then Exit; clbChapterList.BeginUpdate; @@ -1552,7 +1518,7 @@ procedure TMainForm.miChapterListHighlightClick(Sender: TObject); if Sender = miChapterListHighlight then begin miChapterListHighlight.Checked := not miChapterListHighlight.Checked; - options.WriteBool('general', 'HighlightDownloadedChapters', miChapterListHighlight.Checked); + configfile.WriteBool('general', 'HighlightDownloadedChapters', miChapterListHighlight.Checked); end; if Length(ChapterList) = 0 then Exit; if miChapterListHighlight.Checked then @@ -1757,7 +1723,7 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); begin miHighlightNewManga.Checked := not miHighlightNewManga.Checked; - options.WriteBool('general', 'HighLightNewManga', miHighlightNewManga.Checked); + configfile.WriteBool('general', 'HighLightNewManga', miHighlightNewManga.Checked); vtMangaList.Repaint; end; @@ -1898,7 +1864,7 @@ procedure TMainForm.GeneratetvDownloadFilterNodes; Items[9].SelectedIndex := 8; Items[9].StateIndex := 8; - Items[Self.options.ReadInteger('general', 'DownloadFilterSelect',0)].Selected := True; + Items[configfile.ReadInteger('general', 'DownloadFilterSelect',0)].Selected := True; end; end; @@ -2133,7 +2099,7 @@ procedure TMainForm.btWebsitesSearchClearClick(Sender: TObject); procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); begin - options.WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); + configfile.WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); end; procedure TMainForm.cbOptionAutoCheckFavIntervalChange(Sender: TObject); @@ -2207,7 +2173,7 @@ procedure TMainForm.cbSelectMangaChange(Sender: TObject); begin if cbSelectManga.ItemIndex < 0 then Exit; - options.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); + configfile.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then begin currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; @@ -3375,7 +3341,7 @@ procedure TMainForm.tvDownloadFilterSelectionChanged(Sender: TObject); begin vtDownloadFilters; pcMain.ActivePage := tsDownload; - options.WriteInteger('general', 'DownloadFilterSelect', + configfile.WriteInteger('general', 'DownloadFilterSelect', tvDownloadFilter.Selected.AbsoluteIndex); end; @@ -4140,7 +4106,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); begin pcMain.ActivePage := tsInformation; if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := options.ReadString('saveto', 'SaveTo', DEFAULT_PATH); + edSaveTo.Text := configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH); if Trim(edSaveTo.Text) = '' then edSaveTo.Text := DEFAULT_PATH; edSaveTo.Text := CorrectPathSys(edSaveTo.Text); @@ -4209,7 +4175,7 @@ procedure TMainForm.LoadOptions; s: String; data: PSingleItem; begin - with options do begin + with configfile do begin // general cbOptionOneInstanceOnly.Checked := ReadBool('general', 'OneInstanceOnly', True); cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); @@ -4295,7 +4261,7 @@ procedure TMainForm.LoadOptions; l := TStringList.Create; try s := ReadString('general', 'MangaListSelect', - mangalistIni.ReadString('general', 'DefaultSelect', DEFAULT_LIST)); + mangalistfile.ReadString('general', 'DefaultSelect', DEFAULT_LIST)); if Pos(SEPERATOR, s) > 0 then GetParams(l, s) //for old config else @@ -4333,7 +4299,7 @@ procedure TMainForm.SaveOptions; end; end; - with options do + with configfile do try // general WriteString('general', 'MangaListSelect', s); @@ -4408,7 +4374,6 @@ procedure TMainForm.SaveOptions; finally UpdateFile; - CopyFile(CONFIG_FILE_RUN, CONFIG_FILE, [cffOverwriteFile, cffPreserveTime]); end; Modules.SaveWebsiteOption; end; @@ -4561,17 +4526,17 @@ procedure TMainForm.LoadMangaOptions; data: PSingleItem; wName, wLang: TStringList; begin - DBDownloadURL:=mangalistIni.ReadString('general','DBDownloadURL',''); + DBDownloadURL:=mangalistfile.ReadString('general','DBDownloadURL',''); wName := TStringList.Create; wLang := TStringList.Create; lang := TStringList.Create; try - mangalistIni.ReadSection('available', lang); + mangalistfile.ReadSection('available', lang); TrimStrings(lang); if lang.Count > 0 then for i := 0 to lang.Count - 1 do begin - s := Trim(mangalistIni.ReadString('available', lang[i], '')); + s := Trim(mangalistfile.ReadString('available', lang[i], '')); if s <> '' then ExtractStrings([','], [], PChar(s), wName); TrimStrings(wName); @@ -4606,7 +4571,7 @@ procedure TMainForm.LoadMangaOptions; // load selected manga list lang.Clear; - s := options.ReadString('general', 'MangaListSelect', DEFAULT_LIST); + s := configfile.ReadString('general', 'MangaListSelect', DEFAULT_LIST); if Pos(SEPERATOR, s) <> 0 then ExtractParam(lang, s, SEPERATOR, False) else @@ -4638,7 +4603,7 @@ procedure TMainForm.LoadMangaOptions; // load last selected manga if cbSelectManga.Items.Count > 0 then begin - sel := options.ReadInteger('form', 'SelectManga', 0); + sel := configfile.ReadInteger('form', 'SelectManga', 0); if sel < 0 then sel := 0; if sel > cbSelectManga.Items.Count - 1 then @@ -4823,7 +4788,7 @@ procedure TMainForm.LoadFormInformation; var i: Integer; begin - with options do + with configfile do begin pcLeft.Width := ReadInteger('form', 'MainSplitter', 195); sbMain.Panels[0].Width := pcLeft.Width + 4; @@ -4865,7 +4830,7 @@ procedure TMainForm.SaveFormInformation; var i: Integer; begin - with options do + with configfile do begin WriteInteger('form', 'MainSplitter', pcLeft.Width); WriteInteger('form', 'pcMainPageIndex', pcMain.PageIndex); @@ -4898,7 +4863,7 @@ procedure TMainForm.SaveFormInformation; procedure TMainForm.SaveDropTargetFormInformation; begin - with options do + with configfile do begin WriteBool('droptarget', 'Show', ckDropTarget.Checked); WriteInteger('droptarget', 'Mode', rgDropTargetMode.ItemIndex); @@ -4923,7 +4888,7 @@ procedure TMainForm.CollectLanguagesFromFiles; for i := 0 to AvailableLanguages.Count - 1 do cbLanguages.Items.Add(SimpleTranslator.AvailableLanguages.ValueFromIndex[i]); cbLanguages.ItemIndex := SimpleTranslator.AvailableLanguages.IndexOfName( - options.ReadString('languages', 'Selected', 'en')); + configfile.ReadString('languages', 'Selected', 'en')); end; end; @@ -4981,8 +4946,8 @@ procedure TMainForm.OpenWithExternalProgram(const dirPath, Filename: String); Exe, Params, p, f: String; begin - Exe := Trim(options.ReadString('general', 'ExternalProgramPath', '')); - Params := Trim(options.ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM)); + Exe := Trim(configfile.ReadString('general', 'ExternalProgramPath', '')); + Params := Trim(configfile.ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM)); p := Trim(TrimRightChar(Trim(dirPath), [PathDelim])); f := Trim(TrimChar(Trim(Filename), [PathDelim])); diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f87e40e80..7fb04b3ab 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -238,7 +238,7 @@ <PackageName Value="LCL"/> </Item7> </RequiredPackages> - <Units Count="9"> + <Units Count="10"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -299,6 +299,10 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit8> + <Unit9> + <Filename Value="..\baseunits\FMDOptions.pas"/> + <IsPartOfProject Value="True"/> + </Unit9> </Units> </ProjectOptions> <CompilerOptions> diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 82466226f..5486086fd 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -12,7 +12,7 @@ cthreads, {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, uBaseUnit, frmMain; + Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, frmMain; var CheckInstance: Boolean = True; From 4813c1e6c05eee0341762463618b8d41638a0a6a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 05:19:43 +0800 Subject: [PATCH 1084/2794] move more options to fmdoptions --- baseunits/FMDOptions.pas | 42 +++++++++++++++++++++++++++++++ baseunits/modules/MintMangaRU.pas | 2 +- baseunits/uBaseUnit.pas | 41 ------------------------------ 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 132708233..0adc2c36c 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -23,6 +23,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) procedure Reload; end; + TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); + const FMD_REVISION = '$WCREV$'; FMD_INSTANCE = '_FreeMangaDownloaderInstance_'; @@ -78,6 +80,46 @@ TIniFileRun = class(IniFiles.TMemIniFile) configfile, advancedfile: TIniFileRun; + // db data download url + DBDownloadURL: String; + + currentWebsite: String; + + OptionProxyType: String = ''; + OptionProxyHost: String = ''; + OptionProxyPort: String = ''; + OptionProxyUser: String = ''; + OptionProxyPass: String = ''; + + OptionLetFMDDo: TFMDDo = DO_NOTHING; + + OptionChangeUnicodeCharacter: Boolean = False; + OptionGenerateMangaFolderName: Boolean = False; + OptionMangaCustomRename: String; + OptionChapterCustomRename: String; + + OptionPDFQuality: Cardinal = 95; + OptionConnectionMaxRetry: Integer = 5; + OptionConnectionTimeout: Integer = 30000; + OptionUpdateListNoMangaInfo: Boolean = False; + OptionUpdateListRemoveDuplicateLocalData: Boolean = False; + + OptionMaxThreads: Integer = 1; + + OptionEnableLoadCover: Boolean = False; + + OptionAutoCheckLatestVersion: Boolean = True; + OptionAutoCheckFavStartup: Boolean = True; + OptionAutoCheckFavInterval: Boolean = True; + OptionAutoCheckFavIntervalMinutes: Cardinal = 60; + OptionNewMangaTime: Cardinal = 1; + OptionAutoCheckFavDownload: Boolean = False; + OptionAutoCheckFavRemoveCompletedManga: Boolean = False; + + OptionHTTPUseGzip: Boolean = True; + + OptionRemoveMangaNameFromChapter: Boolean = False; + // set base directory procedure SetFMDdirectory(const ADir: String); procedure SetAppDataDirectory(const ADir: String); diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index fdf8c5eaa..13e7851cf 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, FMDOptions, synautil; implementation diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bdaa662bc..808a91c0f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -24,9 +24,6 @@ interface synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, Imaging, ImagingExtras, SimpleException, SimpleLogger; -type - TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); - const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); GIF_HEADER: array[0..2] of Byte = ($47, $49, $46); @@ -511,7 +508,6 @@ interface MANGALIB_PL_COOKIES: String; - DBDownloadURL: String; //------------------------------------------ Genre: array [0..37] of String; @@ -519,43 +515,6 @@ interface Revision: Cardinal; currentJDN: Integer; isChangeDirectory: Boolean = False; - - currentWebsite: String; - - OptionProxyType: String = ''; - OptionProxyHost: String = ''; - OptionProxyPort: String = ''; - OptionProxyUser: String = ''; - OptionProxyPass: String = ''; - - OptionLetFMDDo: TFMDDo = DO_NOTHING; - - OptionChangeUnicodeCharacter: Boolean = False; - OptionGenerateMangaFolderName: Boolean = False; - OptionMangaCustomRename: String; - OptionChapterCustomRename: String; - - OptionPDFQuality: Cardinal = 95; - OptionConnectionMaxRetry: Integer = 5; - OptionConnectionTimeout: Integer = 30000; - OptionUpdateListNoMangaInfo: Boolean = False; - OptionUpdateListRemoveDuplicateLocalData: Boolean = False; - - OptionMaxThreads: Integer = 1; - - OptionEnableLoadCover: Boolean = False; - - OptionAutoCheckLatestVersion: Boolean = True; - OptionAutoCheckFavStartup: Boolean = True; - OptionAutoCheckFavInterval: Boolean = True; - OptionAutoCheckFavIntervalMinutes: Cardinal = 60; - OptionNewMangaTime: Cardinal = 1; - OptionAutoCheckFavDownload: Boolean = False; - OptionAutoCheckFavRemoveCompletedManga: Boolean = False; - - OptionHTTPUseGzip: Boolean = True; - - OptionRemoveMangaNameFromChapter: Boolean = False; type TArrayOfString = array of String; From b29b4eac1a62724f2680b4925bcb8fae1619b79e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 05:58:28 +0800 Subject: [PATCH 1085/2794] remove thttpsendthread from baseunit, set default thttpsendthread on mainform --- baseunits/CheckUpdate.pas | 2 +- baseunits/FMDOptions.pas | 6 -- baseunits/WebsiteModules.pas | 3 +- baseunits/httpsendthread.pas | 22 ++++- baseunits/modules/AcademyVN.pas | 2 +- baseunits/modules/Batoto.pas | 3 +- baseunits/modules/Cloudflare.pas | 3 +- baseunits/modules/Doujinmoeus.pas | 2 +- baseunits/modules/EHentai.pas | 3 +- baseunits/modules/EightMuses.pas | 2 +- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/modules/GameofScanlation.pas | 2 +- baseunits/modules/Hakihome.pas | 2 +- baseunits/modules/Hentai2Read.pas | 2 +- baseunits/modules/HentaiCafe.pas | 2 +- baseunits/modules/HitomiLa.pas | 2 +- baseunits/modules/KissManga.pas | 2 +- baseunits/modules/Luscious.pas | 2 +- baseunits/modules/Madokami.pas | 2 +- baseunits/modules/MangaBackup.pas | 2 +- baseunits/modules/MangaChanRU.pas | 2 +- baseunits/modules/MangaFox.pas | 2 +- baseunits/modules/MangaHere.pas | 2 +- baseunits/modules/MangaKoi.pas | 2 +- baseunits/modules/MangaLife.pas | 2 +- baseunits/modules/MangaReader.pas | 3 +- baseunits/modules/MangaStream.pas | 2 +- baseunits/modules/MangaStreamTo.pas | 2 +- baseunits/modules/MangaTr.pas | 2 +- baseunits/modules/Mangacan.pas | 2 +- baseunits/modules/MintMangaRU.pas | 2 +- baseunits/modules/PecintaKomik.pas | 2 +- baseunits/modules/RawSenManga.pas | 2 +- baseunits/modules/Submanga.pas | 2 +- baseunits/modules/Tsumino.pas | 2 +- baseunits/modules/UnionMangas.pas | 2 +- baseunits/modules/WPManga.pas | 2 +- baseunits/modules/Webtoons.pas | 2 +- baseunits/uBaseUnit.pas | 97 +++++++++------------ baseunits/uData.pas | 4 +- baseunits/uDownloadsManager.pas | 8 +- mangadownloader/forms/frmAccountManager.pas | 2 +- mangadownloader/forms/frmMain.pas | 32 +++---- 43 files changed, 125 insertions(+), 123 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index aa64e1826..13533cb56 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, Forms, Controls, uFMDThread, uBaseUnit, FMDOptions; + Classes, SysUtils, Forms, Controls, uFMDThread, uBaseUnit, FMDOptions, httpsendthread; type diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 0adc2c36c..a2e5e6529 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -85,12 +85,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) currentWebsite: String; - OptionProxyType: String = ''; - OptionProxyHost: String = ''; - OptionProxyPort: String = ''; - OptionProxyUser: String = ''; - OptionProxyPass: String = ''; - OptionLetFMDDo: TFMDDo = DO_NOTHING; OptionChangeUnicodeCharacter: Boolean = False; diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 456d6c15a..a13da7bbf 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -10,7 +10,8 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager, uBaseUnit, FMDOptions, RegExpr, IniFiles; + Classes, SysUtils, uData, uDownloadsManager, FMDOptions, httpsendthread, + RegExpr, IniFiles; const MODULE_NOT_FOUND = -1; diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index b9d408eab..0517d5997 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -41,10 +41,18 @@ THTTPSendThread = class(THTTPSend) function KeyVal(const AKey, AValue: String): TKeyValuePair; function QueryString(KeyValuePairs: array of TKeyValuePair): String; +procedure SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String); var DefaultUserAgent: String = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; + DefaultRetryCount: Integer = 1; + DefaultTimeout: Integer = 15000; + DefaultProxyType: String = ''; + DefaultProxyHost: String = ''; + DefaultProxyPort: String = ''; + DefaultProxyUser: String = ''; + DefaultProxyPass: String = ''; implementation @@ -68,6 +76,15 @@ function QueryString(KeyValuePairs: array of TKeyValuePair): String; end; end; +procedure SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String); +begin + DefaultProxyType := ProxyType; + DefaultProxyHost := Host; + DefaultProxyPort := Port; + DefaultProxyUser := User; + DefaultProxyPass := Pass; +end; + { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); @@ -94,9 +111,10 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); Headers.NameValueSeparator := ':'; Cookies.NameValueSeparator := '='; fgzip := True; - fretrycount := 0; ffollowredirection := True; - SetTimeout(15000); + fretrycount := DefaultRetryCount; + SetTimeout(DefaultTimeout); + SetProxy(DefaultProxyType, DefaultProxyHost, DefaultProxyPort, DefaultProxyUser, DefaultProxyPass); Reset; if Assigned(AOwner) then begin diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index a220f0f6e..93066adbc 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; implementation diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 2d67a7763..99a663515 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,7 +6,8 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, dateutils, SimpleLogger, synautil; + accountmanagerdb, XQueryEngineHTML, httpsendthread, dateutils, SimpleLogger, + synautil; implementation diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index d3a318f28..4b13df9ec 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, uBaseUnit, XQueryEngineHTML, BESEN, BESENValue, RegExpr; + Classes, SysUtils, uBaseUnit, XQueryEngineHTML, httpsendthread, BESEN, BESENValue, + RegExpr; function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; var CS: TRTLCriticalSection): Boolean; overload; diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index aed68241e..26c2a7bd8 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -5,7 +5,7 @@ interface uses - Classes, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, WebsiteModules, uData, uBaseUnit, uDownloadsManager, httpsendthread; implementation diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index ff95fbc2b..9273169a1 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,7 +6,8 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, synautil, synacode, RegExpr, LazFileUtils; + accountmanagerdb, XQueryEngineHTML, httpsendthread, synautil, synacode, + RegExpr, LazFileUtils; implementation diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index d239d3126..cd225df94 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, httpsendthread; implementation diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 60481c34b..b4f5642db 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, RegExpr, synautil; implementation diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index eb6645cfa..4446c7d0f 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr, synautil, Cloudflare; + XQueryEngineHTML, httpsendthread, RegExpr, synautil, Cloudflare; implementation diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 814c2fa67..a19e8089b 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; implementation diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 2f71d64a1..37318b9ab 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; const dirurl = '/hentai-list/all/any/last-added/'; diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index 158f82cba..f76ab864c 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, httpsendthread; implementation diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 3a582a916..7c7654d2d 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, httpsendthread; implementation diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index e45c5dfb8..3e632ec69 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, Cloudflare, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, Cloudflare, RegExpr, synautil; implementation diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 1935c42e2..5c9e51aff 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, httpsendthread; implementation diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index f9bb3a6e6..461c78b73 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, synacode, RegExpr, fpjson; + accountmanagerdb, XQueryEngineHTML, httpsendthread, synacode, RegExpr, fpjson; implementation diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index bd41f6172..bd7d99f6c 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr; + XQueryEngineHTML, httpsendthread, RegExpr; implementation diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index e9a2ae84a..9a395dda6 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index ac825efa3..0ba928295 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, mangafoxwatermarkremover; + XQueryEngineHTML, httpsendthread, mangafoxwatermarkremover; implementation diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 51d28a467..1f436b764 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; implementation diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 85ca5665e..009f7ffa2 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; implementation diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 3bcf425a0..8f57f2d48 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, httpsendthread; implementation diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index a1c3fde51..7102fed7a 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -5,7 +5,8 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + httpsendthread; implementation diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 874aaf43f..85c8b3f04 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager; + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, httpsendthread; implementation diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index 1ae123ce0..e829390be 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, RegExpr, synautil; implementation diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index c8c610939..d98ecf756 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, httpsendthread; implementation diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index e4386deb3..b7bb99aa1 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - HTMLUtil, synautil; + httpsendthread, HTMLUtil, synautil; implementation diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index 13e7851cf..df9fbc5d1 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, FMDOptions, synautil; + XQueryEngineHTML, FMDOptions, httpsendthread, synautil; implementation diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 1f1590132..25b8f6727 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; implementation diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 073f03b5c..99292d946 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, RegExpr, synautil; implementation diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 680490379..05da78d28 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr; + XQueryEngineHTML, httpsendthread, RegExpr; implementation diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index 9f5e290db..3ad808208 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 4a4dca034..7f1b70fda 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, RegExpr, synautil; implementation diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 55cab7965..d1ae741b8 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index a343a52e1..b746cfc99 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, httpsendthread, synautil; implementation diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 808a91c0f..16da59408 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -628,13 +628,6 @@ TParseHTML = class property Raw: String read FRaw write FRaw; end; - { THTTPSendThread } - - THTTPSendThread = class(httpsendthread.THTTPSendThread) - public - constructor Create(AOwner: TFMDThread = nil); - end; - { THTMLForm } THTMLForm = class @@ -2995,36 +2988,36 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; globReturn: - if OptionProxyType = 'HTTP' then + if DefaultProxyType = 'HTTP' then begin - HTTP.ProxyHost := OptionProxyHost; - HTTP.ProxyPort := OptionProxyPort; - HTTP.ProxyUser := OptionProxyUser; - HTTP.ProxyPass := OptionProxyPass; + HTTP.ProxyHost := DefaultProxyHost; + HTTP.ProxyPort := DefaultProxyPort; + HTTP.ProxyUser := DefaultProxyUser; + HTTP.ProxyPass := DefaultProxyPass; end else - if (OptionProxyType = 'SOCKS4') or (OptionProxyType = 'SOCKS5') then + if (DefaultProxyType = 'SOCKS4') or (DefaultProxyType = 'SOCKS5') then begin - if OptionProxyType = 'SOCKS4' then + if DefaultProxyType = 'SOCKS4' then HTTP.Sock.SocksType := ST_Socks4 else - if OptionProxyType = 'SOCKS5' then + if DefaultProxyType = 'SOCKS5' then HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := OptionProxyHost; - HTTP.Sock.SocksPort := OptionProxyPort; - HTTP.Sock.SocksUsername := OptionProxyUser; - http.Sock.SocksPassword := OptionProxyPass; + HTTP.Sock.SocksIP := DefaultProxyHost; + HTTP.Sock.SocksPort := DefaultProxyPort; + HTTP.Sock.SocksUsername := DefaultProxyUser; + http.Sock.SocksPassword := DefaultProxyPass; end else begin - HTTP.Sock.SocksIP := OptionProxyHost; - HTTP.Sock.SocksPort := OptionProxyPort; - HTTP.Sock.SocksUsername := OptionProxyUser; - http.Sock.SocksPassword := OptionProxyPass; - HTTP.ProxyHost := OptionProxyHost; - HTTP.ProxyPort := OptionProxyPort; - HTTP.ProxyUser := OptionProxyUser; - HTTP.ProxyPass := OptionProxyPass; + HTTP.Sock.SocksIP := DefaultProxyHost; + HTTP.Sock.SocksPort := DefaultProxyPort; + HTTP.Sock.SocksUsername := DefaultProxyUser; + http.Sock.SocksPassword := DefaultProxyPass; + HTTP.ProxyHost := DefaultProxyHost; + HTTP.ProxyPort := DefaultProxyPort; + HTTP.ProxyUser := DefaultProxyUser; + HTTP.ProxyPass := DefaultProxyPass; end; HTTPHeader.Values['DNT'] := ' 1'; @@ -3304,36 +3297,36 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; HTTP.Headers.NameValueSeparator := ':'; - if OptionProxyType = 'HTTP' then + if DefaultProxyType = 'HTTP' then begin - HTTP.ProxyHost := OptionProxyHost; - HTTP.ProxyPort := OptionProxyPort; - HTTP.ProxyUser := OptionProxyUser; - HTTP.ProxyPass := OptionProxyPass; + HTTP.ProxyHost := DefaultProxyHost; + HTTP.ProxyPort := DefaultProxyPort; + HTTP.ProxyUser := DefaultProxyUser; + HTTP.ProxyPass := DefaultProxyPass; end else - if (OptionProxyType = 'SOCKS4') or (OptionProxyType = 'SOCKS5') then + if (DefaultProxyType = 'SOCKS4') or (DefaultProxyType = 'SOCKS5') then begin - if OptionProxyType = 'SOCKS4' then + if DefaultProxyType = 'SOCKS4' then HTTP.Sock.SocksType := ST_Socks4 else - if OptionProxyType = 'SOCKS5' then + if DefaultProxyType = 'SOCKS5' then HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := OptionProxyHost; - HTTP.Sock.SocksPort := OptionProxyPort; - HTTP.Sock.SocksUsername := OptionProxyUser; - http.Sock.SocksPassword := OptionProxyPass; + HTTP.Sock.SocksIP := DefaultProxyHost; + HTTP.Sock.SocksPort := DefaultProxyPort; + HTTP.Sock.SocksUsername := DefaultProxyUser; + http.Sock.SocksPassword := DefaultProxyPass; end else begin - HTTP.Sock.SocksIP := OptionProxyHost; - HTTP.Sock.SocksPort := OptionProxyPort; - HTTP.Sock.SocksUsername := OptionProxyUser; - http.Sock.SocksPassword := OptionProxyPass; - HTTP.ProxyHost := OptionProxyHost; - HTTP.ProxyPort := OptionProxyPort; - HTTP.ProxyUser := OptionProxyUser; - HTTP.ProxyPass := OptionProxyPass; + HTTP.Sock.SocksIP := DefaultProxyHost; + HTTP.Sock.SocksPort := DefaultProxyPort; + HTTP.Sock.SocksUsername := DefaultProxyUser; + http.Sock.SocksPassword := DefaultProxyPass; + HTTP.ProxyHost := DefaultProxyHost; + HTTP.ProxyPort := DefaultProxyPort; + HTTP.ProxyUser := DefaultProxyUser; + HTTP.ProxyPass := DefaultProxyPass; end; HTTPHeader.Values['DNT'] := ' 1'; @@ -3696,16 +3689,6 @@ function THTMLForm.GetData: String; end; end; -{ THTTPSendThread } - -constructor THTTPSendThread.Create(AOwner: TFMDThread); -begin - inherited Create(AOwner); - RetryCount := OptionConnectionMaxRetry; - Timeout := OptionConnectionTimeout; - SetProxy(OptionProxyType, OptionProxyHost, OptionProxyPort, OptionProxyUser, OptionProxyPass); -end; - { TParseHTML } procedure TParseHTML.FoundTag(NoCaseTag, ActualTag: String); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 56e37052a..c20e90752 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,8 +14,8 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FMDOptions, FileUtil, - LazFileUtils, SimpleLogger, strutils, dateutils, RegExpr, httpsend; + Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FMDOptions, httpsendthread, + FileUtil, LazFileUtils, SimpleLogger, strutils, dateutils, RegExpr, httpsend; type diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b5eb7f1ec..596aad457 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -15,10 +15,10 @@ interface uses - lazutf8classes, LazFileUtils, FileUtil, FastHTMLParser, HTMLUtil, SynaCode, - RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, - ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, - uFMDThread, uMisc, DownloadedChaptersDB, FMDOptions, SimpleLogger, dateutils; + lazutf8classes, LazFileUtils, FileUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, + Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, + typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, + DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils; type TDownloadManager = class; diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index a18fac4c2..d25b47c20 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, uFMDThread, - uBaseUnit, FMDOptions, frmAccountSet, SimpleException; + uBaseUnit, FMDOptions, httpsendthread, frmAccountSet, SimpleException; type diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 076748662..1bf489998 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmCustomOption, CheckUpdate, accountmanagerdb, DBDataProcess, - mangafoxwatermarkremover, SimpleTranslator, FMDOptions, SimpleException, SimpleLogger; + mangafoxwatermarkremover, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, SimpleLogger; type @@ -4459,27 +4459,29 @@ procedure TMainForm.ApplyOptions; end; //connection - OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; - OptionConnectionMaxRetry := seOptionMaxRetry.Value; - OptionMaxThreads := seOptionMaxThread.Value; DLManager.maxDLTasks := seOptionMaxParallel.Value; DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; - DLManager.retryConnect := OptionConnectionMaxRetry; + DLManager.retryConnect := seOptionMaxRetry.Value; + OptionMaxThreads := seOptionMaxThread.Value; + OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; + OptionConnectionMaxRetry := seOptionMaxRetry.Value; + DefaultTimeout := OptionConnectionTimeout; + DefaultRetryCount := OptionConnectionMaxRetry; if cbOptionUseProxy.Checked then begin - OptionProxyType := cbOptionProxyType.Text; - OptionProxyHost := edOptionHost.Text; - OptionProxyPass := edOptionPass.Text; - OptionProxyPort := edOptionPort.Text; - OptionProxyUser := edOptionUser.Text; + DefaultProxyType := cbOptionProxyType.Text; + DefaultProxyHost := edOptionHost.Text; + DefaultProxyPass := edOptionPass.Text; + DefaultProxyPort := edOptionPort.Text; + DefaultProxyUser := edOptionUser.Text; end else begin - OptionProxyType := ''; - OptionProxyHost := ''; - OptionProxyPass := ''; - OptionProxyPort := ''; - OptionProxyUser := ''; + DefaultProxyType := ''; + DefaultProxyHost := ''; + DefaultProxyPass := ''; + DefaultProxyPort := ''; + DefaultProxyUser := ''; end; //saveto From 860031c61299669c1c66f652c5889ec034b3da2a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 13:14:58 +0800 Subject: [PATCH 1086/2794] ehentai, fixed filename incorrectly serialized several times fixed #224 --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 9273169a1..afbf2f225 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -234,7 +234,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; while PageLinks.Count < PageContainerLinks.Count do PageLinks.Add('G'); - SerializeAndMaintainNames(Filenames); end; end; @@ -266,6 +265,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then GetImageLink; end; + SerializeAndMaintainNames(Filenames); end; finally query.Free; From 48683dffa98a9ae60497e4281ab79ef6308710e4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 13:36:23 +0800 Subject: [PATCH 1087/2794] added readcomiconline closed #225 --- baseunits/modules/KissManga.pas | 59 +++++++++++++++++++++++---------- config/mangalist.ini | 2 +- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 3e632ec69..3f46be098 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -11,15 +11,22 @@ interface implementation const - dirurl = '/MangaList/Newest'; + kissmangadirurl = '/MangaList/Newest'; + readcomiconlinedirurl = '/ComicList/Newest'; var kissmangacookies: String = ''; kissmangalockget: TRTLCriticalSection; + readcomiconlinecookies: String = ''; + readcomiconlinelockget: TRTLCriticalSection; -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; + const Module: TModuleContainer): Boolean; begin - Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacookies, kissmangalockget); + if Module.Website = 'KissManga' then + Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacookies, kissmangalockget) + else if Module.Website = 'ReadComicOnline' then + Result := Cloudflare.GETCF(AHTTP, AURL, readcomiconlinecookies, readcomiconlinelockget); end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; @@ -30,7 +37,12 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl) then begin + s := Module.RootURL; + if Module.Website = 'KissManga' then + s := s + kissmangadirurl + else if Module.Website = 'ReadComicOnline' then + s := s + readcomiconlinedirurl; + if GETWithCookie(MangaInfo.FHTTP, s, Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -54,10 +66,14 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; + s := Module.RootURL; + if Module.Website = 'KissManga' then + s := s + kissmangadirurl + else if Module.Website = 'ReadComicOnline' then + s := s + readcomiconlinedirurl; if AURL <> '0' then s := s + '?page=' + IncStr(AURL); - if GETWithCookie(MangaInfo.FHTTP, s) then begin + if GETWithCookie(MangaInfo.FHTTP, s, Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -80,7 +96,7 @@ function GetInfo(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL)) then begin + if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL), Module) then begin Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -124,7 +140,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with DownloadThread.FHTTP, DownloadThread.manager.container do begin PageLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then begin Result := True; source := TStringList.Create; try @@ -142,24 +158,33 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; procedure RegisterModule; -begin - with AddModule do + + procedure AddWebsiteModule(AWebsite, ARootURL: String); begin - Website := 'KissManga'; - RootURL := 'http://kissmanga.com'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; + with AddModule do + begin + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; end; + +begin + AddWebsiteModule('KissManga', 'http://kissmanga.com'); + AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.com'); end; initialization InitCriticalSection(kissmangalockget); + InitCriticalSection(readcomiconlinelockget); RegisterModule; finalization DoneCriticalsection(kissmangalockget); + DoneCriticalsection(readcomiconlinelockget); end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 212077481..1f27a02fa 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 3ce3f325dd39c5cd7d8d053d33da174b17269552 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 14:59:04 +0800 Subject: [PATCH 1088/2794] rename frmcustomoption to frmwebsiteoptioncustom --- mangadownloader/forms/frmMain.pas | 11 ++++++----- ...frmCustomOption.lfm => frmWebsiteOptionCustom.lfm} | 0 ...frmCustomOption.pas => frmWebsiteOptionCustom.pas} | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) rename mangadownloader/forms/{frmCustomOption.lfm => frmWebsiteOptionCustom.lfm} (100%) rename mangadownloader/forms/{frmCustomOption.pas => frmWebsiteOptionCustom.pas} (99%) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1bf489998..802253935 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,8 +22,9 @@ interface FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, - frmAccountManager, frmCustomOption, CheckUpdate, accountmanagerdb, DBDataProcess, - mangafoxwatermarkremover, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, SimpleLogger; + frmAccountManager, frmWebsiteOptionCustom, CheckUpdate, accountmanagerdb, + DBDataProcess, mangafoxwatermarkremover, SimpleTranslator, FMDOptions, + httpsendthread, SimpleException, SimpleLogger; type @@ -1125,8 +1126,8 @@ procedure TMainForm.FormCreate(Sender: TObject); Show; end; - CustomOptionForm := TCustomOptionForm.Create(Self); - with CustomOptionForm do + WebsiteOptionCustomForm := TCustomOptionForm.Create(Self); + with WebsiteOptionCustomForm do begin Parent := sbWebsiteOptions; BorderStyle := bsNone; @@ -4938,7 +4939,7 @@ procedure TMainForm.ApplyLanguage; tvDownloadFilterRepaint; // refresh custom option - CustomOptionForm.CreateWebsiteOption; + WebsiteOptionCustomForm.CreateWebsiteOption; end; end; end; diff --git a/mangadownloader/forms/frmCustomOption.lfm b/mangadownloader/forms/frmWebsiteOptionCustom.lfm similarity index 100% rename from mangadownloader/forms/frmCustomOption.lfm rename to mangadownloader/forms/frmWebsiteOptionCustom.lfm diff --git a/mangadownloader/forms/frmCustomOption.pas b/mangadownloader/forms/frmWebsiteOptionCustom.pas similarity index 99% rename from mangadownloader/forms/frmCustomOption.pas rename to mangadownloader/forms/frmWebsiteOptionCustom.pas index 43f42eaa8..6e201a0c5 100644 --- a/mangadownloader/forms/frmCustomOption.pas +++ b/mangadownloader/forms/frmWebsiteOptionCustom.pas @@ -1,4 +1,4 @@ -unit frmCustomOption; +unit frmWebsiteOptionCustom; {$mode objfpc}{$H+} @@ -69,7 +69,7 @@ TCustomOptionForm = class(TForm) end; var - CustomOptionForm: TCustomOptionForm; + WebsiteOptionCustomForm: TCustomOptionForm; dparent: TWinControl; tbspace: Cardinal = 6; lrspace: Cardinal = 6; From 0be666e65fc7ccc10fb61af002e037dd1e3cbe22 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Apr 2016 18:49:53 +0800 Subject: [PATCH 1089/2794] added advanced website options, cookies and useragent, saved to advanced file --- mangadownloader/forms/frmMain.lfm | 15 ++- mangadownloader/forms/frmMain.pas | 28 +++-- .../forms/frmWebsiteOptionAdvanced.lfm | 95 +++++++++++++++ .../forms/frmWebsiteOptionAdvanced.pas | 113 ++++++++++++++++++ mangadownloader/languages/fmd.en.po | 14 +++ mangadownloader/languages/fmd.id_ID.po | 14 +++ mangadownloader/languages/fmd.po | 14 +++ mangadownloader/md.lpi | 9 +- 8 files changed, 286 insertions(+), 16 deletions(-) create mode 100644 mangadownloader/forms/frmWebsiteOptionAdvanced.lfm create mode 100644 mangadownloader/forms/frmWebsiteOptionAdvanced.pas diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 8bce94b91..cca6898f4 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -36,13 +36,13 @@ object MainForm: TMainForm Height = 525 Top = 11 Width = 566 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 4 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1911,10 +1911,10 @@ object MainForm: TMainForm Height = 420 Top = 8 Width = 539 - ActivePage = tsGeneral + ActivePage = tsWebsites Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 6 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -3133,9 +3133,9 @@ object MainForm: TMainForm Height = 376 Top = 8 Width = 523 - ActivePage = tsWebsiteSelection + ActivePage = tsWebsiteAdvanced Align = alClient - TabIndex = 0 + TabIndex = 2 TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' @@ -3304,6 +3304,9 @@ object MainForm: TMainForm TabOrder = 0 end end + object tsWebsiteAdvanced: TTabSheet + Caption = 'Advanced' + end end end object tsAccounts: TTabSheet diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 802253935..2a43f6dad 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -16,15 +16,15 @@ interface {$else} FakeActiveX, {$endif} - Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, - ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, - simpleipc, lclproc, types, strutils, LCLIntf, DefaultTranslator, EditBtn, - FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, - uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, - uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, - frmAccountManager, frmWebsiteOptionCustom, CheckUpdate, accountmanagerdb, - DBDataProcess, mangafoxwatermarkremover, SimpleTranslator, FMDOptions, - httpsendthread, SimpleException, SimpleLogger; + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, + ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, + types, strutils, LCLIntf, DefaultTranslator, EditBtn, FileUtil, LazUTF8Classes, TAGraph, + TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, + uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, + uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, + frmWebsiteOptionAdvanced, CheckUpdate, accountmanagerdb, DBDataProcess, + mangafoxwatermarkremover, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, + SimpleLogger; type @@ -80,6 +80,7 @@ TMainForm = class(TForm) pmSbMain: TPopupMenu; sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; + tsWebsiteAdvanced: TTabSheet; tsWebsiteSelection: TTabSheet; tsWebsiteOptions: TTabSheet; tsAccounts: TTabSheet; @@ -1135,6 +1136,15 @@ procedure TMainForm.FormCreate(Sender: TObject); Show; end; + WebsiteOptionAdvancedForm := TWebsiteOptionAdvancedForm.Create(Self); + with WebsiteOptionAdvancedForm do + begin + Parent := tsWebsiteAdvanced; + BorderStyle := bsNone; + Align := alClient; + Show; + end; + // load mangafox template mangafoxwatermarkremover.LoadTemplate(MANGAFOXTEMPLATE_FOLDER); diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm new file mode 100644 index 000000000..3da72cecf --- /dev/null +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -0,0 +1,95 @@ +object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm + Left = 281 + Height = 456 + Top = 68 + Width = 545 + ClientHeight = 456 + ClientWidth = 545 + OnCreate = FormCreate + OnDestroy = FormDestroy + LCLVersion = '1.7' + object pcAdvanced: TPageControl + Left = 0 + Height = 456 + Top = 0 + Width = 545 + ActivePage = tsCookies + Align = alClient + TabIndex = 0 + TabOrder = 0 + object tsCookies: TTabSheet + Caption = 'Cookies' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 428 + ClientWidth = 537 + object sgCookies: TStringGrid + Left = 6 + Height = 416 + Top = 6 + Width = 525 + Align = alClient + AutoAdvance = aaNone + AutoEdit = False + ColCount = 2 + Columns = < + item + Title.Caption = 'Website' + end + item + Title.Caption = 'Cookies' + Width = 400 + end> + DefaultDrawing = False + FixedCols = 0 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goColSizing, goEditing, goSmoothScroll, goHeaderPushedLook, goCellHints, goTruncCellHints, goCellEllipsis] + RowCount = 2 + TabAdvance = aaNone + TabOrder = 0 + TitleStyle = tsNative + OnDblClick = sgUserAgentDblClick + OnKeyDown = sgUserAgentKeyDown + OnSetEditText = sgUserAgentSetEditText + end + end + object tsUserAgent: TTabSheet + Caption = 'User Agent' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 428 + ClientWidth = 537 + object sgUserAgent: TStringGrid + Left = 6 + Height = 416 + Top = 6 + Width = 525 + Align = alClient + AutoAdvance = aaNone + AutoEdit = False + ColCount = 2 + Columns = < + item + Title.Caption = 'Website' + end + item + Title.Caption = 'User Agent' + Width = 400 + end> + DefaultDrawing = False + FixedCols = 0 + Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goColSizing, goEditing, goSmoothScroll, goHeaderPushedLook, goCellHints, goTruncCellHints, goCellEllipsis] + RowCount = 2 + TabAdvance = aaNone + TabOrder = 0 + TitleStyle = tsNative + OnDblClick = sgUserAgentDblClick + OnKeyDown = sgUserAgentKeyDown + OnSetEditText = sgUserAgentSetEditText + end + end + end +end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas new file mode 100644 index 000000000..338065807 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -0,0 +1,113 @@ +unit frmWebsiteOptionAdvanced; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, Windows, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, + LCLProc, Grids, VirtualTrees, FMDOptions; + +type + + { TWebsiteOptionAdvancedForm } + + TWebsiteOptionAdvancedForm = class(TForm) + pcAdvanced: TPageControl; + sgUserAgent: TStringGrid; + sgCookies: TStringGrid; + tsCookies: TTabSheet; + tsUserAgent: TTabSheet; + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure sgUserAgentDblClick(Sender: TObject); + procedure sgUserAgentKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure sgUserAgentSetEditText(Sender: TObject; ACol, ARow: Integer; + const Value: String); + private + { private declarations } + public + { public declarations } + procedure LoadFromFileToGrid(const AGrid: TStringGrid; const ASection: String); + end; + +var + WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm; + +implementation + +{$R *.lfm} + +{ TWebsiteOptionAdvancedForm } + +procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); +begin + LoadFromFileToGrid(sgUserAgent, 'UserAgent'); + LoadFromFileToGrid(sgCookies, 'Cookies'); +end; + +procedure TWebsiteOptionAdvancedForm.FormDestroy(Sender: TObject); +begin + advancedfile.UpdateFile; +end; + +procedure TWebsiteOptionAdvancedForm.sgUserAgentDblClick(Sender: TObject); +begin + if not (Sender is TStringGrid) then Exit; + if TStringGrid(Sender).SelectedColumn.Index > 0 then + TStringGrid(Sender).EditorMode := True; +end; + +procedure TWebsiteOptionAdvancedForm.sgUserAgentKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + if not (Sender is TStringGrid) then Exit; + if (Key = VK_RETURN) and (TStringGrid(Sender).SelectedColumn.Index = 0) then + Key := 0; +end; + +procedure TWebsiteOptionAdvancedForm.sgUserAgentSetEditText(Sender: TObject; ACol, + ARow: Integer; const Value: String); +var + s: String; +begin + if ACol = 0 then Exit; + if not (Sender is TStringGrid) then Exit; + if TStringGrid(Sender).Cells[ACol, ARow] = Value then Exit; + if Sender = sgUserAgent then + s := 'UserAgent' + else if Sender = sgCookies then + s := 'Cookies'; + advancedfile.WriteString(s, sgUserAgent.Cells[0, ARow], Value); +end; + +procedure TWebsiteOptionAdvancedForm.LoadFromFileToGrid(const AGrid: TStringGrid; + const ASection: String); +var + s: TStringList; + i: Integer; +begin + if AGrid = nil then Exit; + if ASection = '' then Exit; + AGrid.Clear; + s := TStringList.Create; + try + advancedfile.ReadSectionRaw(ASection, s); + if s.Count > 0 then + begin + AGrid.RowCount := s.Count + 1; + for i := 0 to s.Count - 1 do + begin + AGrid.Cells[0, i + 1] := s.Names[i]; + AGrid.Cells[1, i + 1] := s.ValueFromIndex[i]; + end; + AGrid.AutoSizeColumn(0); + AGrid.SortColRow(True, 0); + end; + finally + s.Free; + end; +end; + +end. + diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index bd235fbb3..8028a24eb 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1556,6 +1556,10 @@ msgstr "Updates" msgid "View" msgstr "View" +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Advanced" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" @@ -1679,6 +1683,16 @@ msgstr "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 7320b2707..1d2ca51b8 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1539,6 +1539,10 @@ msgstr "Pembaruan" msgid "View" msgstr "Tampilan" +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Lanjutan" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" @@ -1662,6 +1666,16 @@ msgstr "" "Versi baru ditemukan! Apakah Anda ingin memperbarui sekarang? \n" "FMD akan ditutup untuk menyelesaikan update.\n" +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Mengompresi..." diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 045edd275..b85057731 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1484,6 +1484,10 @@ msgstr "" msgid "View" msgstr "" +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" msgid "Options" @@ -1605,6 +1609,16 @@ msgid "" "FMD will be closed to finish the update.\n" msgstr "" +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 7fb04b3ab..ce8bd568d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -238,7 +238,7 @@ <PackageName Value="LCL"/> </Item7> </RequiredPackages> - <Units Count="10"> + <Units Count="11"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -303,6 +303,13 @@ <Filename Value="..\baseunits\FMDOptions.pas"/> <IsPartOfProject Value="True"/> </Unit9> + <Unit10> + <Filename Value="forms\frmWebsiteOptionAdvanced.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="WebsiteOptionAdvancedForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit10> </Units> </ProjectOptions> <CompilerOptions> From 82e3dd427ac09dbaab2a56f69df816897d99b552 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 01:43:32 +0800 Subject: [PATCH 1090/2794] added advanced website option, cookies and user agent, stored to advanced.ini --- mangadownloader/forms/frmMain.lfm | 14 +- .../forms/frmWebsiteOptionAdvanced.lfm | 79 +++++---- .../forms/frmWebsiteOptionAdvanced.pas | 165 +++++++++++++----- mangadownloader/languages/fmd.en.po | 20 +++ mangadownloader/languages/fmd.id_ID.po | 20 +++ mangadownloader/languages/fmd.po | 20 +++ 6 files changed, 238 insertions(+), 80 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index cca6898f4..4923b9c18 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -36,13 +36,13 @@ object MainForm: TMainForm Height = 525 Top = 11 Width = 566 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1911,10 +1911,10 @@ object MainForm: TMainForm Height = 420 Top = 8 Width = 539 - ActivePage = tsWebsites + ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 6 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -3133,9 +3133,9 @@ object MainForm: TMainForm Height = 376 Top = 8 Width = 523 - ActivePage = tsWebsiteAdvanced + ActivePage = tsWebsiteSelection Align = alClient - TabIndex = 2 + TabIndex = 0 TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' @@ -3306,6 +3306,8 @@ object MainForm: TMainForm end object tsWebsiteAdvanced: TTabSheet Caption = 'Advanced' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 end end end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index 3da72cecf..29cc1147e 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -6,7 +6,6 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ClientHeight = 456 ClientWidth = 545 OnCreate = FormCreate - OnDestroy = FormDestroy LCLVersion = '1.7' object pcAdvanced: TPageControl Left = 0 @@ -25,33 +24,40 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ChildSizing.VerticalSpacing = 4 ClientHeight = 428 ClientWidth = 537 - object sgCookies: TStringGrid + object vtCookies: TVirtualStringTree Left = 6 Height = 416 Top = 6 Width = 525 Align = alClient - AutoAdvance = aaNone - AutoEdit = False - ColCount = 2 - Columns = < + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < item - Title.Caption = 'Website' + Position = 0 + Text = 'Website' end item - Title.Caption = 'Cookies' + Position = 1 + Text = 'Cookies' Width = 400 end> - DefaultDrawing = False - FixedCols = 0 - Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goColSizing, goEditing, goSmoothScroll, goHeaderPushedLook, goCellHints, goTruncCellHints, goCellEllipsis] - RowCount = 2 - TabAdvance = aaNone + Header.DefaultHeight = 23 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] TabOrder = 0 - TitleStyle = tsNative - OnDblClick = sgUserAgentDblClick - OnKeyDown = sgUserAgentKeyDown - OnSetEditText = sgUserAgentSetEditText + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toExtendedFocus] + OnColumnDblClick = vtCookiesColumnDblClick + OnCompareNodes = vtCookiesCompareNodes + OnEditing = vtCookiesEditing + OnFreeNode = vtCookiesFreeNode + OnGetText = vtCookiesGetText + OnGetNodeDataSize = vtCookiesGetNodeDataSize + OnHeaderClick = vtCookiesHeaderClick + OnKeyDown = vtCookiesKeyDown + OnNewText = vtCookiesNewText end end object tsUserAgent: TTabSheet @@ -62,33 +68,40 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ChildSizing.VerticalSpacing = 4 ClientHeight = 428 ClientWidth = 537 - object sgUserAgent: TStringGrid + object vtUserAgent: TVirtualStringTree Left = 6 Height = 416 Top = 6 Width = 525 Align = alClient - AutoAdvance = aaNone - AutoEdit = False - ColCount = 2 - Columns = < + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < item - Title.Caption = 'Website' + Position = 0 + Text = 'Website' end item - Title.Caption = 'User Agent' + Position = 1 + Text = 'User Agent' Width = 400 end> - DefaultDrawing = False - FixedCols = 0 - Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goColSizing, goEditing, goSmoothScroll, goHeaderPushedLook, goCellHints, goTruncCellHints, goCellEllipsis] - RowCount = 2 - TabAdvance = aaNone + Header.DefaultHeight = 23 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] TabOrder = 0 - TitleStyle = tsNative - OnDblClick = sgUserAgentDblClick - OnKeyDown = sgUserAgentKeyDown - OnSetEditText = sgUserAgentSetEditText + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toExtendedFocus] + OnColumnDblClick = vtCookiesColumnDblClick + OnCompareNodes = vtCookiesCompareNodes + OnEditing = vtCookiesEditing + OnFreeNode = vtCookiesFreeNode + OnGetText = vtCookiesGetText + OnGetNodeDataSize = vtCookiesGetNodeDataSize + OnHeaderClick = vtCookiesHeaderClick + OnKeyDown = vtCookiesKeyDown + OnNewText = vtCookiesNewText end end end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 338065807..54c8faa64 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -10,25 +10,42 @@ interface type + TNameValue = record + Name, + Value: String; + end; + PNameValue = ^TNameValue; + { TWebsiteOptionAdvancedForm } TWebsiteOptionAdvancedForm = class(TForm) pcAdvanced: TPageControl; - sgUserAgent: TStringGrid; - sgCookies: TStringGrid; tsCookies: TTabSheet; tsUserAgent: TTabSheet; + vtCookies: TVirtualStringTree; + vtUserAgent: TVirtualStringTree; procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure sgUserAgentDblClick(Sender: TObject); - procedure sgUserAgentKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure sgUserAgentSetEditText(Sender: TObject; ACol, ARow: Integer; - const Value: String); + procedure vtCookiesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; + Shift: TShiftState); + procedure vtCookiesCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure vtCookiesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; var Allowed: Boolean); + procedure vtCookiesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vtCookiesGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); + procedure vtCookiesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure vtCookiesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure vtCookiesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure vtCookiesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; const NewText: String); private { private declarations } public { public declarations } - procedure LoadFromFileToGrid(const AGrid: TStringGrid; const ASection: String); + procedure LoadFromFileToVT(const AVT: TVirtualStringTree; const ASection: String); end; var @@ -42,67 +59,133 @@ implementation procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); begin - LoadFromFileToGrid(sgUserAgent, 'UserAgent'); - LoadFromFileToGrid(sgCookies, 'Cookies'); + LoadFromFileToVT(vtCookies, 'Cookies'); + LoadFromFileToVT(vtUserAgent, 'UserAgent'); +end; + +procedure TWebsiteOptionAdvancedForm.vtCookiesColumnDblClick(Sender: TBaseVirtualTree; + Column: TColumnIndex; Shift: TShiftState); +begin + if Column <> 0 then + Sender.EditNode(Sender.FocusedNode, Column); +end; + +procedure TWebsiteOptionAdvancedForm.vtCookiesCompareNodes(Sender: TBaseVirtualTree; + Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +var + Data1, Data2: PNameValue; +begin + Data1 := Sender.GetNodeData(Node1); + Data2 := Sender.GetNodeData(Node2); + if Assigned(Data1) and Assigned(Data2) then + case Column of + 0: Result := CompareStr(Data1^.Name, Data2^.Name); + 1: Result := CompareStr(Data1^.Value, Data2^.Value); + end; end; -procedure TWebsiteOptionAdvancedForm.FormDestroy(Sender: TObject); +procedure TWebsiteOptionAdvancedForm.vtCookiesEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); begin - advancedfile.UpdateFile; + Allowed := Column <> 0; end; -procedure TWebsiteOptionAdvancedForm.sgUserAgentDblClick(Sender: TObject); +procedure TWebsiteOptionAdvancedForm.vtCookiesFreeNode(Sender: TBaseVirtualTree; + Node: PVirtualNode); +var + Data: PNameValue; begin - if not (Sender is TStringGrid) then Exit; - if TStringGrid(Sender).SelectedColumn.Index > 0 then - TStringGrid(Sender).EditorMode := True; + Data := Sender.GetNodeData(Node); + if Assigned(Data) then + Finalize(Data^); end; -procedure TWebsiteOptionAdvancedForm.sgUserAgentKeyDown(Sender: TObject; var Key: Word; +procedure TWebsiteOptionAdvancedForm.vtCookiesGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TNameValue); +end; + +procedure TWebsiteOptionAdvancedForm.vtCookiesGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + Data: PNameValue; +begin + Data := Sender.GetNodeData(Node); + if Assigned(Data) then + case Column of + 0: CellText := Data^.Name; + 1: CellText := Data^.Value; + end; +end; + +procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; + Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + Sender.SortColumn := Column; + if Sender.SortDirection = sdAscending then + Sender.SortDirection := sdDescending + else + Sender.SortDirection := sdAscending; + Sender.Treeview.SortTree(Sender.SortColumn, Sender.SortDirection); +end; + +procedure TWebsiteOptionAdvancedForm.vtCookiesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin - if not (Sender is TStringGrid) then Exit; - if (Key = VK_RETURN) and (TStringGrid(Sender).SelectedColumn.Index = 0) then - Key := 0; + if not (Sender is TBaseVirtualTree) then Exit; + with TBaseVirtualTree(Sender) do + if (Key = VK_RETURN) and (FocusedColumn <> 0) then + EditNode(FocusedNode, FocusedColumn); end; -procedure TWebsiteOptionAdvancedForm.sgUserAgentSetEditText(Sender: TObject; ACol, - ARow: Integer; const Value: String); +procedure TWebsiteOptionAdvancedForm.vtCookiesNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; const NewText: String); var - s: String; + Data: PNameValue; begin - if ACol = 0 then Exit; - if not (Sender is TStringGrid) then Exit; - if TStringGrid(Sender).Cells[ACol, ARow] = Value then Exit; - if Sender = sgUserAgent then - s := 'UserAgent' - else if Sender = sgCookies then - s := 'Cookies'; - advancedfile.WriteString(s, sgUserAgent.Cells[0, ARow], Value); + if Column = 0 then Exit; + Data := Sender.GetNodeData(Node); + if Data^.Value <> NewText then + begin + Data^.Value := NewText; + advancedfile.WriteString(TVirtualStringTree(Sender).DefaultText, Data^.Name, NewText); + end; end; -procedure TWebsiteOptionAdvancedForm.LoadFromFileToGrid(const AGrid: TStringGrid; +procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: TVirtualStringTree; const ASection: String); var s: TStringList; i: Integer; + Node: PVirtualNode; + Data: PNameValue; begin - if AGrid = nil then Exit; + if AVT = nil then Exit; if ASection = '' then Exit; - AGrid.Clear; + AVT.Clear; + AVT.DefaultText := ASection; s := TStringList.Create; try advancedfile.ReadSectionRaw(ASection, s); if s.Count > 0 then begin - AGrid.RowCount := s.Count + 1; - for i := 0 to s.Count - 1 do - begin - AGrid.Cells[0, i + 1] := s.Names[i]; - AGrid.Cells[1, i + 1] := s.ValueFromIndex[i]; + AVT.BeginUpdate; + try + for i := 0 to s.Count - 1 do + begin + Node := AVT.AddChild(nil); + Data := AVT.GetNodeData(Node); + Data^.Name := s.Names[i]; + Data^.Value := s.ValueFromIndex[i]; + end; + AVT.Header.AutoFitColumns(False, smaUseColumnOption, 0, 0); + AVT.Header.SortColumn := 0; + AVT.Header.SortDirection := sdAscending; + AVT.SortTree(AVT.Header.SortColumn, AVT.Header.SortDirection); + finally + AVT.EndUpdate; end; - AGrid.AutoSizeColumn(0); - AGrid.SortColRow(True, 0); end; finally s.Free; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8028a24eb..a013e3a45 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1693,6 +1693,26 @@ msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" msgid "User Agent" msgstr "User Agent" +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "User Agent" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1d2ca51b8..ae1a68608 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1676,6 +1676,26 @@ msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" msgid "User Agent" msgstr "User Agent" +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Situs web" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Situs web" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "User Agent" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Mengompresi..." diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index b85057731..9024b5f96 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1619,6 +1619,26 @@ msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" msgid "User Agent" msgstr "" +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[1].TEXT" +msgid "Cookies" +msgstr "" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[1].TEXT" +msgid "User Agent" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "" From b5b90af11fd9ccf9df22c49997e673fd7b803496 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 01:45:29 +0800 Subject: [PATCH 1091/2794] save advanced.ini with apply button --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2a43f6dad..6ec44a6c0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4386,6 +4386,7 @@ procedure TMainForm.SaveOptions; finally UpdateFile; end; + advancedfile.UpdateFile; Modules.SaveWebsiteOption; end; From 88ba955e8d020e68187bb250068fe4766a92592e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 01:47:40 +0800 Subject: [PATCH 1092/2794] cleanup --- baseunits/uDownloadsManager.pas | 1 - baseunits/uFavoritesManager.pas | 1 - 2 files changed, 2 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 596aad457..4f652009d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1635,7 +1635,6 @@ constructor TDownloadManager.Create; CS_DownloadedChapterList := TCriticalSection.Create; DownloadManagerFile := TIniFileRun.Create(WORK_FILE); - DownloadManagerFile.CacheUpdates := True; DownloadedChapters := TDownloadedChaptersDB.Create; DownloadedChapters.Filename := DOWNLOADEDCHAPTERSDB_FILE; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 4afe8cff6..d28c02cca 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -429,7 +429,6 @@ constructor TFavoriteManager.Create; CS_Favorites := TCriticalSection.Create; isRunning := False; favoritesFile := TIniFileRun.Create(FAVORITES_FILE); - favoritesFile.CacheUpdates := True; FFavorites := TFPList.Create; Restore; end; From d2e7df878977786e8880399ed9e6383d80c4bfd0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 02:02:03 +0800 Subject: [PATCH 1093/2794] tinifilerun, update file only when dirty --- baseunits/FMDOptions.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index a2e5e6529..2b0b2c58d 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, IniFiles, fileinfo, LazFileUtils, LazUTF8, FileUtil, Forms, LCLProc; + Classes, SysUtils, IniFiles, fileinfo, LazFileUtils, LazUTF8, FileUtil, Forms; type @@ -14,10 +14,10 @@ interface TIniFileRun = class(IniFiles.TMemIniFile) private FCSLock: TRTLCriticalSection; - FFileAge: Longint; + FFileAge: LongInt; FRealFileName: String; public - constructor Create(const AFileName: string; AEscapeLineFeeds: Boolean = False); overload; override; + constructor Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); overload; override; destructor Destroy; override; procedure UpdateFile; override; procedure Reload; @@ -122,7 +122,7 @@ implementation { TIniFileRun } -constructor TIniFileRun.Create(const AFileName: string; AEscapeLineFeeds: Boolean); +constructor TIniFileRun.Create(const AFileName: String; AEscapeLineFeeds: Boolean); begin FRealFileName := AFileName; if FileExistsUTF8(AFileName + RUN_EXE) then From 61e8cbb610670875bb158a80a9844c30a6a458a5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 03:19:45 +0800 Subject: [PATCH 1094/2794] fmdoptions, added availablewebsite --- baseunits/FMDOptions.pas | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 2b0b2c58d..8816a2b36 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -85,6 +85,9 @@ TIniFileRun = class(IniFiles.TMemIniFile) currentWebsite: String; + // available website + AvailableWebsite: TStringList; + OptionLetFMDDo: TFMDDo = DO_NOTHING; OptionChangeUnicodeCharacter: Boolean = False; @@ -147,6 +150,7 @@ destructor TIniFileRun.Destroy; procedure TIniFileRun.UpdateFile; begin + if CacheUpdates and (Dirty = False) then Exit; inherited UpdateFile; CopyFile(FileName, FRealFileName, [cffOverwriteFile, cffPreserveTime, cffCreateDestDirectory]); end; @@ -188,10 +192,46 @@ procedure FreeIniFiles; FreeNil(advancedfile); end; +procedure GetAvailableWebsite; +var + l, w: TStringList; + i, j: Integer; +begin + AvailableWebsite.Clear; + AvailableWebsite.BeginUpdate; + try + l := TStringList.Create; + try + mangalistfile.ReadSection('available', l); + if l.Count > 0 then + begin + w := TStringList.Create; + try + for i := 0 to l.Count - 1 do + begin + w.Clear; + w.CommaText := mangalistfile.ReadString('available', l[i], ''); + if w.Count > 0 then + for j := 0 to w.Count - 1 do + AvailableWebsite.Values[w[j]] := l[i]; + end; + finally + w.Free; + end; + end; + finally + l.Free; + end; + finally + AvailableWebsite.EndUpdate; + end; +end; + procedure SetIniFiles; begin FreeIniFiles; mangalistfile := TIniFile.Create(MANGALIST_FILE); + GetAvailableWebsite; configfile := TIniFileRun.Create(CONFIG_FILE); configfile.Options := configfile.Options - [ifoStripQuotes]; advancedfile := TIniFileRun.Create(CONFIG_ADVANCED); @@ -277,6 +317,8 @@ function GetCurrentBinVersion: String; procedure doInitialization; begin FMD_VERSION_NUMBER := GetCurrentBinVersion; + AvailableWebsite := TStringList.Create; + AvailableWebsite.Sorted := True; SetFMDdirectory(GetCurrentDirUTF8); SetAppDataDirectory(GetCurrentDirUTF8); end; @@ -284,6 +326,7 @@ procedure doInitialization; procedure doFinalization; begin FreeIniFiles; + AvailableWebsite.Free; end; initialization From aee0dce277f7cd2ef3f6c127c0fe70d8a2cdfb5b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 03:55:27 +0800 Subject: [PATCH 1095/2794] added advanced website option cookies and useragent edit via popup menu --- .../forms/frmWebsiteOptionAdvanced.lfm | 157 ++++++++++++++++-- .../forms/frmWebsiteOptionAdvanced.pas | 113 +++++++++++-- mangadownloader/forms/frmWebsiteSelection.lfm | 47 ++++++ mangadownloader/forms/frmWebsiteSelection.pas | 31 ++++ mangadownloader/languages/fmd.en.po | 22 +++ mangadownloader/languages/fmd.id_ID.po | 22 +++ mangadownloader/languages/fmd.po | 22 +++ mangadownloader/md.lpi | 10 +- 8 files changed, 392 insertions(+), 32 deletions(-) create mode 100644 mangadownloader/forms/frmWebsiteSelection.lfm create mode 100644 mangadownloader/forms/frmWebsiteSelection.pas diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index 29cc1147e..89ee91ba3 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -1,17 +1,17 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm - Left = 281 - Height = 456 - Top = 68 - Width = 545 - ClientHeight = 456 - ClientWidth = 545 + Left = 279 + Height = 236 + Top = 275 + Width = 484 + ClientHeight = 236 + ClientWidth = 484 OnCreate = FormCreate LCLVersion = '1.7' object pcAdvanced: TPageControl Left = 0 - Height = 456 + Height = 236 Top = 0 - Width = 545 + Width = 484 ActivePage = tsCookies Align = alClient TabIndex = 0 @@ -22,13 +22,13 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 428 - ClientWidth = 537 + ClientHeight = 208 + ClientWidth = 476 object vtCookies: TVirtualStringTree Left = 6 - Height = 416 + Height = 196 Top = 6 - Width = 525 + Width = 464 Align = alClient DefaultText = 'Node' Header.AutoSizeIndex = 0 @@ -45,10 +45,11 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Header.DefaultHeight = 23 Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + PopupMenu = pmCookies TabOrder = 0 TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] OnColumnDblClick = vtCookiesColumnDblClick OnCompareNodes = vtCookiesCompareNodes OnEditing = vtCookiesEditing @@ -89,10 +90,11 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Header.DefaultHeight = 23 Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + PopupMenu = pmCookies TabOrder = 0 TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] OnColumnDblClick = vtCookiesColumnDblClick OnCompareNodes = vtCookiesCompareNodes OnEditing = vtCookiesEditing @@ -105,4 +107,131 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm end end end + object pmCookies: TPopupMenu + Images = imglstpmCokies + left = 221 + top = 89 + object MenuItem1: TMenuItem + Caption = 'Add' + ImageIndex = 0 + OnClick = MenuItem1Click + end + object MenuItem2: TMenuItem + Caption = 'Edit' + ImageIndex = 1 + OnClick = MenuItem2Click + end + object MenuItem3: TMenuItem + Caption = '-' + end + object MenuItem4: TMenuItem + Caption = 'Delete' + ImageIndex = 2 + OnClick = MenuItem4Click + end + end + object imglstpmCokies: TImageList + AllocBy = 2 + left = 320 + top = 89 + Bitmap = { + 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003B7F320015A9000015A9000015A9 + 000015A9000015AA009915AA00CC15AA00CC15AA009915A9000015A9000015A9 + 000015A90000094D0000FFFFFF00FFFFFF00119A0000129F000014A8000014A8 + 000014A8000014A800CC72E961FF71E860FF14A800CC14A8000014A8000014A8 + 0000129F0000119A0000FFFFFF00FFFFFF00119A0000119B0000129E000014A5 + 000014A5000014A500CC69E058FF69E058FF14A500CC14A5000014A50000129E + 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000129D + 000013A2000013A200CC62D951FF61D850FF13A200CC13A20000129D0000119B + 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000119B + 0000129C0000129E00CC5AD149FF59D048FF129E00CC129C0000119B0000119B + 0000119B0000119A0000FFFFFF00FFFFFF00119A0099119A00CC119A00CC119A + 00CC119A00CC119A00CC54CB43FF52C941FF119A00CC119A00CC119A00CC119A + 00CC119A00CC119A0099FFFFFF00FFFFFF00109600CC5ED54DFF55CC44FF54CB + 43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC63EFF4EC53DFF4DC43CFF4CC3 + 3BFF4EC53DFF109600CCFFFFFF00FFFFFF000F9200CC59D048FF50C73FFF50C7 + 3FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A920FF2CA51BFF2BA31AFF2DA5 + 1CFF33AB22FF0F9200CCFFFFFF00FFFFFF000E8E00990E8D00CC0E8D00CC0E8D + 00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D00CC0E8D00CC0E8D00CC0E8D + 00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8C + 00000E8B00000D8900CC29B618FF27B416FF0D8900CC0E8B00000E8C00000E8C + 00000E8C00000E8D0000FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8A + 00000C8400000C8400CC25C014FF24C013FF0C8400CC0C8400000E8A00000E8C + 00000E8C00000E8D0000FFFFFF00FFFFFF000747000000000000000000000320 + 00000A7D00000A7D00CC23CD12FF22CC11FF0A7D00CC0A7D0000032000000000 + 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 + 0000021D0000066D00CC22D811FF22D811FF066D00CC021D0000000000000000 + 00000000000000000000FFFFFF00FFFFFF0000000000000000040000001B0000 + 003000000033024700A6025D00CC025D00CC024700A600000033000000310000 + 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000 + 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000 + 00100000000300000000FFFFFF00000000000000000000000000000000000000 + 000000000000000000000000000001272D000175860055555500555555000101 + E42B0101E09D0101D23F0101B600000000000000000000000000000000000000 + 00000000000001272D0001758600019BB200019BB200555555005555551F1515 + BC9D8888FFFF0101C5B90101B443000000000000000000000000000000000127 + 2D0001758600019BB200019BB200019BB200019BB2005555552450505069F6F6 + F6FF6868F8FF5C5CF2FF0000A8B1000000000000000001272D0001758600019B + B200019BB200019BB200019BB200019BB200019AB240158395A3F6F6F6FFCCCC + CCFFDDDDDDFF060683B50000A032001F2A00005E7D00019BB200019BB200019B + B200019BB200019BB200019BB200019AB2400195ADB788EEFFFF33AABBFFDDDD + DDFF171717830909312905055500007CA500007DA600019BB200019BB200019B + B200019BB200019BB200019AB2400195ADB788EEFFFF83EBFCFF56CDDEFF087A + 8CB00C0C0C2F0A0A0A000A0A0A00007CA500007DA600019BB200019BB200019B + B200019BB200019AB2400195ADB788EEFFFF7EE7F8FF5ACFE0FF0395ACC0039A + B0430A0A0A000A0A0A000A0A0A00007CA500007DA600019BB200019BB200019B + B200019AB2400195ADB788EEFFFF78E3F4FF5DD2E3FF028DA4C20292A9440399 + AF000A0A0A000A0A0A000A0A0A00007CA500007DA600019BB200019BB200019A + B2400195ADB788EEFFFF71DEEFFF60D3E4FF02859BC3028AA1450291A8000399 + AF000A0A0A000A0A0A000A0A0A00007CA500007DA600019BB200019AB2400195 + ADB788EEFFFF69DAEBFF60D3E4FF027C92C5028298450289A0000291A8000399 + AF000A0A0A000505050000000000007CA500007DA600019AB2400195ADB788EE + FFFF63D5E6FF5FD3E4FF017389C701798F45028197000289A0000291A800024D + 5800000000000000000000000000007CA500007CA527018DA8A688EEFFFF5DD1 + E2FF5BD0E1FF016B80C80170864601788E000281970001455000000000000000 + 000000000000000000000000000000759B060072976CC0E4F1EF44BBCCFF58CE + DFFF016379CA01687D47016F8500013C47000000000000000000000000000000 + 0000000000000000000000000000016B8E3962A5BBC0C2E6F2FFA0CEDDF50159 + 6FC30060764701343E0000000000000000000000000000000000000000000000 + 0000000000000000000000000000015E7B85C2E6F2FF5591A5D1014C649A0131 + 41500000001500000013000000110000000F0000000D0000000A000000080000 + 000600000004000000030000000100000000014B649A012E3C63010A0D350000 + 002D0000002A00000026000000210000001D0000001900000014000000100000 + 000B000000080000000500000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A8000000A9480000A9CC0000 + A9CC0000A9930000A7000000A20000009A0000009E000000A4000000A82B0000 + A97E0000A9B00000A966FFFFFF00FFFFFF000000A4000000A4CC7474FCFF6B6B + F4FE3636CDE50000A4CC0000A10000009A0000009E000000A3890606A8CF0000 + A4BD0000A54A0000A501FFFFFF00FFFFFF0000009F0000009F6600009ECC3737 + C9E56262EAFF5858E3FA1616AFD600009A330E0EA99F2828BEDD00009EB40000 + 9F1F0000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098330000 + 968A000096CC4141CDEE5151D9FD2727B7E32F2FBEE3000096B100009A180000 + 9F000000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098000000 + 900000008D3300008ECC3131BCF33333BCFA090997D400008E0000008F000000 + 8E0000008E000000A500FFFFFF00FFFFFF000000800000008000000080000000 + 8215000086B01A1AA8E72222B4F907078ED214149FE105058DD2000082000000 + 7C000000780000007800FFFFFF00FFFFFF00000078000000780000007B000000 + 7E911515A6E51D1DBEFD07078AD400007F6300007EAE0A0A94DC00007EB60000 + 7A000000780000007800FFFFFF00FFFFFF000000700000007000000075670D0D + 96DC1717CCFF0F0FA2E50000777500007E0000007A000000769104048AD50000 + 76860000730000007200FFFFFF00FFFFFF0000006C0000006D1F00006ECC1515 + D1FB1111C3F400006EB40000701100007000000078000000720000006E820000 + 6EB800006D4100006C00FFFFFF00FFFFFF00000066000000668C0A0A9FE51212 + DDFF030378D3000067330000510000000000000000000000380000006A000000 + 66840000668900006404FFFFFF00FFFFFF000000180000005FCC1111DBFE0C0C + AFEC00005F8B0000190000000000000000000000000000000000000000000000 + 320000005F7300004832FFFFFF00FFFFFF000000001C0000325E000059CC0000 + 57BC0000164200000020000000160000000F0000000D00000010000000150000 + 001B00001D3800002D4CFFFFFF00FFFFFF000000000E00000014000000190000 + 001900000016000000100000000B0000000800000007000000080000000B0000 + 000E0000001100000013FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 + } + end end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 54c8faa64..f36b997c7 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -6,7 +6,7 @@ interface uses Classes, Windows, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, - LCLProc, Grids, VirtualTrees, FMDOptions; + LCLProc, Grids, Menus, VirtualTrees, FMDOptions, frmWebsiteSelection; type @@ -19,12 +19,21 @@ TNameValue = record { TWebsiteOptionAdvancedForm } TWebsiteOptionAdvancedForm = class(TForm) + imglstpmCokies: TImageList; + MenuItem1: TMenuItem; + MenuItem2: TMenuItem; + MenuItem3: TMenuItem; + MenuItem4: TMenuItem; pcAdvanced: TPageControl; + pmCookies: TPopupMenu; tsCookies: TTabSheet; tsUserAgent: TTabSheet; vtCookies: TVirtualStringTree; vtUserAgent: TVirtualStringTree; procedure FormCreate(Sender: TObject); + procedure MenuItem1Click(Sender: TObject); + procedure MenuItem2Click(Sender: TObject); + procedure MenuItem4Click(Sender: TObject); procedure vtCookiesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); procedure vtCookiesCompareNodes(Sender: TBaseVirtualTree; Node1, @@ -43,9 +52,10 @@ TWebsiteOptionAdvancedForm = class(TForm) Column: TColumnIndex; const NewText: String); private { private declarations } + procedure LoadFromFileToVT(const AVT: TVirtualStringTree; const ASection: String); + procedure GetWebsite(const AVT: TVirtualStringTree; const S: TStrings); public { public declarations } - procedure LoadFromFileToVT(const AVT: TVirtualStringTree; const ASection: String); end; var @@ -63,6 +73,49 @@ procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); LoadFromFileToVT(vtUserAgent, 'UserAgent'); end; +procedure TWebsiteOptionAdvancedForm.MenuItem1Click(Sender: TObject); +var + Data: PNameValue; + Node: PVirtualNode; +begin + if Screen.ActiveControl is TVirtualStringTree then + with TWebsiteSelectionForm.Create(Self) do + try + GetWebsite(TVirtualStringTree(Screen.ActiveControl), cbWebsites.Items); + if (ShowModal = mrOk) and (cbWebsites.Text <> '') then + with TVirtualStringTree(Screen.ActiveControl) do + begin + Node := AddChild(nil); + Data := GetNodeData(Node); + Data^.Name := cbWebsites.Text; + advancedfile.WriteString(DefaultText, cbWebsites.Text, ''); + EditNode(Node, 1); + end; + finally + Free; + end; +end; + +procedure TWebsiteOptionAdvancedForm.MenuItem2Click(Sender: TObject); +begin + if Screen.ActiveControl is TVirtualStringTree then + with TVirtualStringTree(Screen.ActiveControl) do + EditNode(FocusedNode, 1); +end; + +procedure TWebsiteOptionAdvancedForm.MenuItem4Click(Sender: TObject); +var + Data: PNameValue; +begin + if Screen.ActiveControl is TVirtualStringTree then + with TVirtualStringTree(Screen.ActiveControl) do + begin + Data := GetNodeData(FocusedNode); + advancedfile.DeleteKey(DefaultText, Data^.Name); + DeleteNode(FocusedNode); + end; +end; + procedure TWebsiteOptionAdvancedForm.vtCookiesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin @@ -77,11 +130,10 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesCompareNodes(Sender: TBaseVirtualT begin Data1 := Sender.GetNodeData(Node1); Data2 := Sender.GetNodeData(Node2); - if Assigned(Data1) and Assigned(Data2) then - case Column of - 0: Result := CompareStr(Data1^.Name, Data2^.Name); - 1: Result := CompareStr(Data1^.Value, Data2^.Value); - end; + case Column of + 0: Result := CompareStr(Data1^.Name, Data2^.Name); + 1: Result := CompareStr(Data1^.Value, Data2^.Value); + end; end; procedure TWebsiteOptionAdvancedForm.vtCookiesEditing(Sender: TBaseVirtualTree; @@ -112,11 +164,10 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesGetText(Sender: TBaseVirtualTree; Data: PNameValue; begin Data := Sender.GetNodeData(Node); - if Assigned(Data) then - case Column of - 0: CellText := Data^.Name; - 1: CellText := Data^.Value; - end; + case Column of + 0: CellText := Data^.Name; + 1: CellText := Data^.Value; + end; end; procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; @@ -133,8 +184,8 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; procedure TWebsiteOptionAdvancedForm.vtCookiesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin - if not (Sender is TBaseVirtualTree) then Exit; - with TBaseVirtualTree(Sender) do + if not (Sender is TVirtualStringTree) then Exit; + with TVirtualStringTree(Sender) do if (Key = VK_RETURN) and (FocusedColumn <> 0) then EditNode(FocusedNode, FocusedColumn); end; @@ -192,5 +243,39 @@ procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: TVirtualStringT end; end; +procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: TVirtualStringTree; + const S: TStrings); +var + Data: PNameValue; + Node: PVirtualNode; + i, p: Integer; +begin + if AVT = nil then Exit; + if S = nil then Exit; + S.Clear; + if AvailableWebsite.Count > 0 then + begin + S.BeginUpdate; + try + for i := 0 to AvailableWebsite.Count - 1 do + S.Add(AvailableWebsite.Names[i]); + if AVT.RootNodeCount > 0 then + begin + Node := AVT.GetFirst(); + while Assigned(Node) do + begin + Data := AVT.GetNodeData(Node); + p := S.IndexOf(Data^.Name); + if p > -1 then + S.Delete(p); + Node := AVT.GetNext(Node); + end; + end; + finally + S.EndUpdate; + end; + end; +end; + end. diff --git a/mangadownloader/forms/frmWebsiteSelection.lfm b/mangadownloader/forms/frmWebsiteSelection.lfm new file mode 100644 index 000000000..c5b82a54a --- /dev/null +++ b/mangadownloader/forms/frmWebsiteSelection.lfm @@ -0,0 +1,47 @@ +object WebsiteSelectionForm: TWebsiteSelectionForm + Left = 202 + Height = 75 + Top = 182 + Width = 310 + BorderStyle = bsSizeToolWin + Caption = 'Select a website' + ChildSizing.LeftRightSpacing = 10 + ChildSizing.TopBottomSpacing = 10 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ClientHeight = 75 + ClientWidth = 310 + Position = poMainFormCenter + LCLVersion = '1.7' + object cbWebsites: TComboBox + Left = 10 + Height = 23 + Top = 10 + Width = 290 + Align = alTop + AutoComplete = True + AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchAscending] + ItemHeight = 15 + TabOrder = 0 + end + object btOk: TBitBtn + AnchorSideLeft.Control = cbWebsites + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = cbWebsites + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = cbWebsites + AnchorSideRight.Side = asrCenter + AnchorSideBottom.Side = asrBottom + Left = 124 + Height = 26 + Top = 41 + Width = 62 + Anchors = [akLeft, akBottom] + AutoSize = True + Default = True + DefaultCaption = True + Kind = bkOK + ModalResult = 1 + TabOrder = 1 + end +end diff --git a/mangadownloader/forms/frmWebsiteSelection.pas b/mangadownloader/forms/frmWebsiteSelection.pas new file mode 100644 index 000000000..de9cc7686 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteSelection.pas @@ -0,0 +1,31 @@ +unit frmWebsiteSelection; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons; + +type + + { TWebsiteSelectionForm } + + TWebsiteSelectionForm = class(TForm) + btOk: TBitBtn; + cbWebsites: TComboBox; + private + { private declarations } + public + { public declarations } + end; + +var + WebsiteSelectionForm: TWebsiteSelectionForm; + +implementation + +{$R *.lfm} + +end. + diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index a013e3a45..40c9ddde6 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -193,6 +193,7 @@ msgid "Title:" msgstr "Title:" #: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" msgid "Website:" msgstr "Website:" @@ -297,6 +298,7 @@ msgid "Save as PNG" msgstr "Save as PNG" #: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" msgid "Add" msgstr "Add" @@ -306,6 +308,7 @@ msgid "Delete" msgstr "Delete" #: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" msgstr "Edit" @@ -1683,6 +1686,21 @@ msgstr "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Add" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Edit" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Delete" + #: twebsiteoptionadvancedform.tscookies.caption msgctxt "twebsiteoptionadvancedform.tscookies.caption" msgid "Cookies" @@ -1713,6 +1731,10 @@ msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" msgid "User Agent" msgstr "User Agent" +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Select a website" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index ae1a68608..010a11552 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -193,6 +193,7 @@ msgid "Title:" msgstr "Judul:" #: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" msgid "Website:" msgstr "Situs web:" @@ -296,6 +297,7 @@ msgid "Save as PNG" msgstr "Simpan sebagai PNG" #: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" msgid "Add" msgstr "Tambah" @@ -305,6 +307,7 @@ msgid "Delete" msgstr "Hapus" #: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" msgstr "Ubah" @@ -1666,6 +1669,21 @@ msgstr "" "Versi baru ditemukan! Apakah Anda ingin memperbarui sekarang? \n" "FMD akan ditutup untuk menyelesaikan update.\n" +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Tambah" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Ubah" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Hapus" + #: twebsiteoptionadvancedform.tscookies.caption msgctxt "twebsiteoptionadvancedform.tscookies.caption" msgid "Cookies" @@ -1696,6 +1714,10 @@ msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" msgid "User Agent" msgstr "User Agent" +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Pilih situs web" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Mengompresi..." diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 9024b5f96..7e9508f47 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -173,6 +173,7 @@ msgid "Title:" msgstr "" #: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" msgid "Website:" msgstr "" @@ -268,6 +269,7 @@ msgid "Save as PNG" msgstr "" #: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" msgid "Add" msgstr "" @@ -277,6 +279,7 @@ msgid "Delete" msgstr "" #: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" msgstr "" @@ -1609,6 +1612,21 @@ msgid "" "FMD will be closed to finish the update.\n" msgstr "" +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM1.CAPTION" +msgid "Add" +msgstr "" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM2.CAPTION" +msgid "Edit" +msgstr "" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM4.CAPTION" +msgid "Delete" +msgstr "" + #: twebsiteoptionadvancedform.tscookies.caption msgctxt "twebsiteoptionadvancedform.tscookies.caption" msgid "Cookies" @@ -1639,6 +1657,10 @@ msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[1].TEXT" msgid "User Agent" msgstr "" +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ce8bd568d..55876f995 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -300,15 +300,17 @@ <ResourceBaseClass Value="Form"/> </Unit8> <Unit9> - <Filename Value="..\baseunits\FMDOptions.pas"/> - <IsPartOfProject Value="True"/> - </Unit9> - <Unit10> <Filename Value="forms\frmWebsiteOptionAdvanced.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="WebsiteOptionAdvancedForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> + </Unit9> + <Unit10> + <Filename Value="forms\frmWebsiteSelection.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="WebsiteSelectionForm"/> + <ResourceBaseClass Value="Form"/> </Unit10> </Units> </ProjectOptions> From 783e05e884e64c9090d09316f4eac6bb50fe8f20 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 04:26:27 +0800 Subject: [PATCH 1096/2794] readcomiconline, fixed getinfo --- baseunits/modules/KissManga.pas | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 3f46be098..26a75c482 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -103,20 +103,20 @@ function GetInfo(const MangaInfo: TMangaInformation; coverLink := XPathString('//div[@id="rightside"]//img/@src'); if title = '' then title := XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); v := XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); - if v.Count > 0 then begin - i := 0; - while i < v.Count - 2 do begin - s := v.get(i).toString; - if Pos('Genres:', s) = 1 then genres := SeparateRight(s, ':') else - if Pos('Author:', s) = 1 then authors := SeparateRight(s, ':') else - if Pos('Artist:', s) = 1 then artists := SeparateRight(s, ':') else - if Pos('Status:', s) = 1 then begin - if Pos('ongoing', LowerCase(v.get(i).toString)) > 0 then status := '1' - else status := '0'; - end else - if Pos('Summary:', s) = 1 then summary := v.get(i + 1).toString; - Inc(i); - end; + for i := 1 to v.Count do + begin + s := v.get(i).toString; + WriteLn(s); + if Pos('Genres', s) = 1 then genres := SeparateRight(s, ':') else + if (Pos('Author', s) = 1) or (Pos('Writer', s) = 1) then authors := SeparateRight(s, ':') else + if Pos('Artist', s) = 1 then artists := SeparateRight(s, ':') else + if Pos('Status', s) = 1 then begin + if Pos('ONGOING', UpperCase(s)) > 0 then + status := '1' + else if Pos('COMPLETED', UpperCase(s)) > 0 then + status := '0'; + end else + if Pos('Summary:', s) = 1 then summary := v.get(i + 1).toString; end; for v in XPath('//table[@class="listing"]/tbody/tr/td/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); From 117be2da2482e11464fdd13361830bb245a3aee1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 04:47:15 +0800 Subject: [PATCH 1097/2794] baseunit, added fixwhitespace --- baseunits/uBaseUnit.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 16da59408..98fea3a36 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -737,6 +737,7 @@ function HTMLDecode(const AStr: String): String; function RemoveSymbols(const input: String): String; function CorrectPathSys(const Path: String): String; +function FixWhiteSpace(const S: String): String; function CleanString(const S: String): String; function CleanMultilinedString(const S: String; MaxLineEnding: Integer = 1): String; function CleanAndExpandURL(const URL: String): String; @@ -2383,6 +2384,14 @@ function SetParams(const input: array of String): String; Result := Result + input[i] + SEPERATOR; end; +function FixWhiteSpace(const S: String): String; +begin + Result := S; + if Result = '' then Exit; + while Pos(#$C2#$A0, Result) > 0 do + Result := StringReplace(Result, #$C2#$A0, ' ', [rfReplaceAll]); +end; + function CleanString(const S: String): String; begin Result := Trim(S); From 6cfcf2d051e2bf5c838435faa81f2a1d40b1fa53 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 04:47:45 +0800 Subject: [PATCH 1098/2794] udata, fixed cleanup info --- baseunits/uData.pas | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c20e90752..d292d174f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1646,16 +1646,16 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco // cleanup info coverLink := CleanURL(coverLink); - title := Trim(RemoveStringBreaks(CommonStringFilter(title))); - authors := Trim(RemoveStringBreaks(Trim(authors))); - artists := Trim(RemoveStringBreaks(Trim(artists))); - genres := Trim(RemoveStringBreaks(Trim(genres))); + title := Trim(FixWhiteSpace(RemoveStringBreaks(CommonStringFilter(title)))); + authors := Trim(FixWhiteSpace(RemoveStringBreaks(Trim(authors)))); + artists := Trim(FixWhiteSpace(RemoveStringBreaks(Trim(artists)))); + genres := Trim(FixWhiteSpace(RemoveStringBreaks(Trim(genres)))); - authors := TrimRightChar(Trim(authors), [',']); - artists := TrimRightChar(Trim(artists), [',']); - genres := TrimRightChar(Trim(genres), [',']); + authors := TrimRightChar(Trim(FixWhiteSpace(authors)), [',']); + artists := TrimRightChar(Trim(FixWhiteSpace(artists)), [',']); + genres := TrimRightChar(Trim(FixWhiteSpace(genres)), [',']); - summary := CleanMultilinedString(summary); + summary := CleanMultilinedString(FixWhiteSpace(summary)); // fix info if (LeftStr(authors, 1) = '<') or (authors = '-') or (authors = ':') then From dbca2c38d86e7e37ebd12b037264f23d54dd6186 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 05:44:15 +0800 Subject: [PATCH 1099/2794] kissmanga, cleanup --- baseunits/modules/KissManga.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 26a75c482..fb2c998f9 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -106,7 +106,6 @@ function GetInfo(const MangaInfo: TMangaInformation; for i := 1 to v.Count do begin s := v.get(i).toString; - WriteLn(s); if Pos('Genres', s) = 1 then genres := SeparateRight(s, ':') else if (Pos('Author', s) = 1) or (Pos('Writer', s) = 1) then authors := SeparateRight(s, ':') else if Pos('Artist', s) = 1 then artists := SeparateRight(s, ':') else From 33ffbaec4650f6385722a60188f048d17ea43421 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 05:46:13 +0800 Subject: [PATCH 1100/2794] changed download list and favorites list double click to open with instead of open folder --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6ec44a6c0..56945a42f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3379,7 +3379,7 @@ procedure TMainForm.vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; procedure TMainForm.vtDownloadColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin - miDownloadOpenFolderClick(Sender); + miDownloadOpenWithClick(Sender); end; procedure TMainForm.vtDownloadDragAllowed(Sender : TBaseVirtualTree; @@ -3713,7 +3713,7 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; procedure TMainForm.vtFavoritesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin - miFavoritesOpenFolderClick(Sender); + miFavoritesOpenWithClick(Sender); end; procedure TMainForm.vtFavoritesDragDrop(Sender: TBaseVirtualTree; From 1dc225c221caf194042a77f9be46eb8902466b78 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Apr 2016 06:00:10 +0800 Subject: [PATCH 1101/2794] Bump version 0.9.48.0 --- changelog.txt | 9 +++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9a56b2ab3..4af049bde 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.48.0 (02-04-2016) +[*] E-Hentai/ExHentai: Fixed filename serialized several times +[+] Added ReadComicOnline[EN] +[*] Website specific option moved to Options > Websites > Options +[+] Added website specific cookies and user agent, Options > Websites > Advanced +[*] Changed double click behaviour on download list and favorite list to "Open ..." +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.47.0...0.9.48.0 + 0.9.47.0 (30-03-2016) [*] Fixed crash with clean install without works folder (#222) Full changes: https://github.com/riderkick/FMD/compare/0.9.46.0...0.9.47.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 55876f995..f23135b9d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="47"/> + <RevisionNr Value="48"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index ae4343625..90349545b 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.47.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.47.0/fmd_0.9.47.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.47.0/fmd_0.9.47.0_Win64.7z +VERSION=0.9.48.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.48.0/fmd_0.9.48.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.48.0/fmd_0.9.48.0_Win64.7z From b0294a696bbe458d71391508dcabac22a87620c5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 3 Apr 2016 14:49:21 +0800 Subject: [PATCH 1102/2794] baseunit.saveimage preserve file last modified date from server --- baseunits/uBaseUnit.pas | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 98fea3a36..5895904b0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -19,7 +19,7 @@ interface UTF8Process, {$endif} SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, - LConvEncoding, strutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, + LConvEncoding, strutils, dateutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, Imaging, ImagingExtras, SimpleException, SimpleLogger; @@ -221,6 +221,8 @@ interface TwoDigitYearCenturyWindow :50; ); + HTTPDateTimeFormatStr = 'ddd, dd mmm yyyy hh:nn:ss'; + // EN: Param seperator SEPERATOR = '!%~'; SEPERATOR2 = '~%!'; @@ -808,7 +810,7 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0) function GetURLFromBitly(const URL: String): String; // try to save tmemorystream to file, return the saved filename if success, otherwise return empty string -function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String): String; +function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; // Download an image from url and save it to a specific location. function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; @@ -3215,7 +3217,7 @@ function GetURLFromBitly(const URL: String): String; httpSource.Free; end; -function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String +function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt ): String; var p, f: String; @@ -3240,9 +3242,19 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String end; except on E: Exception do - WriteLog_E('SaveImageStreamToFile.Failed!', E); + WriteLog_E('SaveImageStreamToFile.WriteToFile Failed! ' + f, E); + end; + if FileExistsUTF8(f) then + begin + Result := f; + if Age > 0 then + try + FileSetDateUTF8(f, Age); + except + on E: Exception do + WriteLog_E('SaveImageStreamToFile.FileSetDate Error! ' + f, E); + end; end; - if FileExistsUTF8(f) then Result := f; end; end; @@ -3252,7 +3264,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; var HTTPHeader: TStringList; HTTP: THTTPSend; - counter: Integer; + counter, lastmodified: LongInt; s: String; procedure preTerminate; @@ -3429,7 +3441,14 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; end; if checkTerminate then Exit; - SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name); + s := Trim(HTTP.Headers.Values['last-modified']); + lastmodified := 0; + if s <> '' then + try + lastmodified := DateTimeToFileDate(ScanDateTime(HTTPDateTimeFormatStr, s, FMDFormatSettings)); + except + end; + SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name, lastmodified); preTerminate; Result := SavedFilename <> ''; end; From e504286736224380d001e9eb3ac72de0c1797d07 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 12:34:07 +0800 Subject: [PATCH 1103/2794] hitomila, fix update list incorrect first page --- baseunits/modules/HitomiLa.pas | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 7c7654d2d..f3c3a80ce 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -41,24 +41,26 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; + s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/index-all-' + AURL + '.html') then begin + s := Module.RootURL; + if AURL <> '0' then + s := s + '/index-all-' + AURL + '.html'; + if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//div[@class="gallery-content"]/div/h1/a') do - begin - ANames.Add(v.toString); - ALinks.Add(v.toNode.getAttribute('href')); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="gallery-content"]/div/h1/a') do + begin + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + end; + finally + Free; end; - finally - query.Free; - end; end; end; From 28bf5730895bdc93016e46f1ad9c33faa71babab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 12:41:21 +0800 Subject: [PATCH 1104/2794] hitomila, cleanup --- baseunits/modules/HitomiLa.pas | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index f3c3a80ce..44bce1b55 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -67,7 +67,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; s: String; begin @@ -76,10 +75,8 @@ function GetInfo(const MangaInfo: TMangaInformation; MangaInfo.mangaInfo.website := Module.Website; if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - with MangaInfo.mangaInfo, query do begin + with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src')); title := XPathString('//div/h1'); for v in XPath('//div[@class="gallery-info"]/table//tr/td[2]//a') do @@ -89,17 +86,15 @@ function GetInfo(const MangaInfo: TMangaInformation; chapterLinks.Add(s); chapterName.Add(title); end; + finally + Free; end; - finally - query.Free; - end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; v: IXQValue; begin Result := False; @@ -109,15 +104,14 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - for v in query.XPath('//div[@class="img-url"]') do - PageLinks.Add(FillURLProtocol('https://', v.toString)); - PageNumber := PageLinks.Count - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@class="img-url"]') do + PageLinks.Add(FillURLProtocol('https://', v.toString)); + PageNumber := PageLinks.Count + finally + Free; + end; end; end; end; From 6a48a0c3d20deecd6d42037ad4197c5722363818 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 13:12:17 +0800 Subject: [PATCH 1105/2794] xqueryenginehtml, added ttreenode --- baseunits/XQueryEngineHTML.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 73ffcea1b..9986f5486 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -39,6 +39,7 @@ TXQueryEngineHTML = class end; IXQValue = xquery.IXQValue; + TTreeNode = simplehtmltreeparser.TTreeNode; implementation From 0b69867eb7dadc1742726ddb76c011318c1a88bc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 13:12:47 +0800 Subject: [PATCH 1106/2794] hitomila, fix info --- baseunits/modules/HitomiLa.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 44bce1b55..e5cca7293 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -68,6 +68,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + t: TTreeNode; s: String; begin Result := NET_PROBLEM; @@ -77,11 +78,16 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src')); - title := XPathString('//div/h1'); - for v in XPath('//div[@class="gallery-info"]/table//tr/td[2]//a') do + t := XPath('//div[contains(@class,"dj-gallery")]').toNode; + coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src', t)); + title := XPathString('//div/h1', t); + artists := XPathString('//h2//a[contains(@href,"/artist/")]', t); + if (title = '') and (artists <> '') then + title := artists; + genres := ''; + for v in XPath('//div[@class="gallery-info"]/table//tr/td[2]//a', t) do AddCommaString(genres, v.toString); - s := XPathString('//div[@class="cover-column"]/a/@href'); + s := XPathString('//div[@class="cover-column"]/a/@href', t); if (s <> '') and (title <> '') then begin chapterLinks.Add(s); chapterName.Add(title); From 8eee5ef73ae420bb289d11b582f1eeaf1ed4d4db Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 13:26:01 +0800 Subject: [PATCH 1107/2794] tinifilerun, remove reload, unsafe --- baseunits/FMDOptions.pas | 24 ------------------------ baseunits/uDownloadsManager.pas | 1 - baseunits/uGetMangaInfosThread.pas | 1 - baseunits/uSilentThread.pas | 1 - baseunits/uUpdateThread.pas | 4 ---- 5 files changed, 31 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 8816a2b36..c2843c247 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -20,7 +20,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) constructor Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); overload; override; destructor Destroy; override; procedure UpdateFile; override; - procedure Reload; end; TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); @@ -155,29 +154,6 @@ procedure TIniFileRun.UpdateFile; CopyFile(FileName, FRealFileName, [cffOverwriteFile, cffPreserveTime, cffCreateDestDirectory]); end; -procedure TIniFileRun.Reload; -var - s: TStringList; -begin - if TryEnterCriticalsection(FCSLock) > 0 then - try - if FileExistsUTF8(FileName) then - if FileAgeUTF8(FileName) <> FFileAge then - begin - s := TStringList.Create; - try - FFileAge := FileAge(FileName); - s.LoadFromFile(FileName); - SetStrings(s); - finally - s.Free; - end; - end; - finally - LeaveCriticalsection(FCSLock); - end; -end; - procedure FreeNil(var Obj); begin if Pointer(Obj) <> nil then diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4f652009d..af22e05cf 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1255,7 +1255,6 @@ procedure TTaskThread.Execute; S, P: String; DynamicPageLink: Boolean; begin - advancedfile.Reload; ModuleId := container.ModuleId; container.ThreadState := True; container.DownloadInfo.TransferRate := ''; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index de2699e0f..34f38e02c 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -139,7 +139,6 @@ procedure TGetMangaInfosThread.DoGetInfos; begin try - advancedfile.Reload; if not GetMangaInfo then begin if not Self.Terminated then diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 374ad3bdf..bd0831f1a 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -191,7 +191,6 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; procedure TSilentThreadManager.Checkout(Index: Integer); begin if (Index < 0) or (Index >= MetaData.Count) then Exit; - advancedfile.Reload; Modules.IncActiveConnectionCount(TSilentThreadMetaData(MetaData[Index]).ModuleId); case TSilentThreadMetaData(MetaData[Index]).MetaDataType of MD_DownloadAll: Threads.Add(TSilentThread.Create); diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 790a44f7d..1331a9f01 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -443,7 +443,6 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; begin MainForm.ulTotalPtr := limit; try - advancedfile.Reload; while (not Terminated) and (workPtr < limit) do begin mt := advancedfile.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then @@ -524,7 +523,6 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; FStatus := s; MainForm.ulWorkPtr := workPtr + 1; Synchronize(MainThreadShowGetting); - advancedfile.Reload; finally UnlockCreateConnection; end; @@ -618,7 +616,6 @@ procedure TUpdateListManagerThread.Execute; Writelog_D(cloghead+'get number of directory page'); // get directory page count - advancedfile.Reload; directoryCount := 0; directoryCount2 := 0; workPtr := 0; @@ -631,7 +628,6 @@ procedure TUpdateListManagerThread.Execute; Writelog_D(cloghead+'get names and links'); // get names and links - advancedfile.Reload; workPtr := 0; isFinishSearchingForNewManga := False; if ModuleId <> -1 then From bd697ad4f7eea689f92a6203993fd7418e9ad7c2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 14:11:05 +0800 Subject: [PATCH 1108/2794] added more advanced website options ui --- .../forms/frmWebsiteOptionAdvanced.lfm | 313 +++++++++++++++++- .../forms/frmWebsiteOptionAdvanced.pas | 13 + mangadownloader/languages/fmd.en.po | 52 +++ mangadownloader/languages/fmd.id_ID.po | 52 +++ mangadownloader/languages/fmd.po | 52 +++ 5 files changed, 466 insertions(+), 16 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index 89ee91ba3..d40638d44 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -1,17 +1,17 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm - Left = 279 - Height = 236 - Top = 275 - Width = 484 - ClientHeight = 236 - ClientWidth = 484 + Left = 235 + Height = 307 + Top = 142 + Width = 510 + ClientHeight = 307 + ClientWidth = 510 OnCreate = FormCreate LCLVersion = '1.7' object pcAdvanced: TPageControl Left = 0 - Height = 236 + Height = 307 Top = 0 - Width = 484 + Width = 510 ActivePage = tsCookies Align = alClient TabIndex = 0 @@ -22,13 +22,13 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 208 - ClientWidth = 476 + ClientHeight = 279 + ClientWidth = 502 object vtCookies: TVirtualStringTree Left = 6 - Height = 196 + Height = 267 Top = 6 - Width = 464 + Width = 490 Align = alClient DefaultText = 'Node' Header.AutoSizeIndex = 0 @@ -67,13 +67,13 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 428 - ClientWidth = 537 + ClientHeight = 279 + ClientWidth = 502 object vtUserAgent: TVirtualStringTree Left = 6 - Height = 416 + Height = 267 Top = 6 - Width = 525 + Width = 490 Align = alClient DefaultText = 'Node' Header.AutoSizeIndex = 0 @@ -106,6 +106,179 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm OnNewText = vtCookiesNewText end end + object tsDownloads: TTabSheet + Caption = 'Downloads' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 279 + ClientWidth = 502 + object pcDownloads: TPageControl + Left = 6 + Height = 267 + Top = 6 + Width = 490 + ActivePage = tsMaxThreadsPerTask + Align = alClient + TabIndex = 0 + TabOrder = 0 + object tsMaxThreadsPerTask: TTabSheet + Caption = 'Max threads per task' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 239 + ClientWidth = 482 + object vtDownloadMaxThreadsPerTask: TVirtualStringTree + Left = 6 + Height = 227 + Top = 6 + Width = 470 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Website' + end + item + Position = 1 + Text = 'Value' + Width = 400 + end> + Header.DefaultHeight = 23 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + PopupMenu = pmCookies + TabOrder = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] + OnColumnDblClick = vtCookiesColumnDblClick + OnCompareNodes = vtCookiesCompareNodes + OnEditing = vtCookiesEditing + OnFreeNode = vtCookiesFreeNode + OnGetText = vtCookiesGetText + OnGetNodeDataSize = vtCookiesGetNodeDataSize + OnHeaderClick = vtCookiesHeaderClick + OnKeyDown = vtCookiesKeyDown + OnNewText = vtCookiesNewText + end + end + end + end + object tsUpdateList: TTabSheet + Caption = 'Update List' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 279 + ClientWidth = 502 + object pcUpdateList: TPageControl + Left = 6 + Height = 267 + Top = 6 + Width = 490 + ActivePage = tsDirectoryPageNumber + Align = alClient + TabIndex = 0 + TabOrder = 0 + object tsDirectoryPageNumber: TTabSheet + Caption = 'Directory page number' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 239 + ClientWidth = 482 + object vtUpdateListDirectoryPageNumber: TVirtualStringTree + Left = 6 + Height = 227 + Top = 6 + Width = 470 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Website' + end + item + Position = 1 + Text = 'Value' + Width = 400 + end> + Header.DefaultHeight = 23 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + PopupMenu = pmCookies + TabOrder = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] + OnColumnDblClick = vtCookiesColumnDblClick + OnCompareNodes = vtCookiesCompareNodes + OnEditing = vtCookiesEditing + OnFreeNode = vtCookiesFreeNode + OnGetText = vtCookiesGetText + OnGetNodeDataSize = vtCookiesGetNodeDataSize + OnHeaderClick = vtCookiesHeaderClick + OnKeyDown = vtCookiesKeyDown + OnNewText = vtCookiesNewText + end + end + object tsNumberofThreads: TTabSheet + Caption = 'Number of threads' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 239 + ClientWidth = 482 + object vtUpdateListNumberOfThreads: TVirtualStringTree + Left = 6 + Height = 227 + Top = 6 + Width = 470 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Website' + end + item + Position = 1 + Text = 'Value' + Width = 400 + end> + Header.DefaultHeight = 23 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + PopupMenu = pmCookies + TabOrder = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] + OnColumnDblClick = vtCookiesColumnDblClick + OnCompareNodes = vtCookiesCompareNodes + OnEditing = vtCookiesEditing + OnFreeNode = vtCookiesFreeNode + OnGetText = vtCookiesGetText + OnGetNodeDataSize = vtCookiesGetNodeDataSize + OnHeaderClick = vtCookiesHeaderClick + OnKeyDown = vtCookiesKeyDown + OnNewText = vtCookiesNewText + end + end + end + end end object pmCookies: TPopupMenu Images = imglstpmCokies @@ -113,11 +286,83 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm top = 89 object MenuItem1: TMenuItem Caption = 'Add' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 + 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 + 0000000000040000001B0000003000000033024700A6025D00CC025D00CC0247 + 00A600000033000000310000001F0000000600000000FFFFFF00FFFFFF000000 + 0000000000000000000000000000021D0000066D00CC22D811FF22D811FF066D + 00CC021D000000000000000000000000000000000000FFFFFF00FFFFFF000747 + 00000000000000000000032000000A7D00000A7D00CC23CD12FF22CC11FF0A7D + 00CC0A7D000003200000000000000000000000000000FFFFFF00FFFFFF000E8D + 00000E8C00000E8C00000E8A00000C8400000C8400CC25C014FF24C013FF0C84 + 00CC0C8400000E8A00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8D + 00000E8C00000E8C00000E8C00000E8B00000D8900CC29B618FF27B416FF0D89 + 00CC0E8B00000E8C00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8E + 00990E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D + 00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000F92 + 00CC59D048FF50C73FFF50C73FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A9 + 20FF2CA51BFF2BA31AFF2DA51CFF33AB22FF0F9200CCFFFFFF00FFFFFF001096 + 00CC5ED54DFF55CC44FF54CB43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC6 + 3EFF4EC53DFF4DC43CFF4CC33BFF4EC53DFF109600CCFFFFFF00FFFFFF00119A + 0099119A00CC119A00CC119A00CC119A00CC119A00CC54CB43FF52C941FF119A + 00CC119A00CC119A00CC119A00CC119A00CC119A0099FFFFFF00FFFFFF00119A + 0000119B0000119B0000119B0000129C0000129E00CC5AD149FF59D048FF129E + 00CC129C0000119B0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A + 0000119B0000119B0000129D000013A2000013A200CC62D951FF61D850FF13A2 + 00CC13A20000129D0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A + 0000119B0000129E000014A5000014A5000014A500CC69E058FF69E058FF14A5 + 00CC14A5000014A50000129E0000119B0000119A0000FFFFFF00FFFFFF00119A + 0000129F000014A8000014A8000014A8000014A800CC72E961FF71E860FF14A8 + 00CC14A8000014A8000014A80000129F0000119A0000FFFFFF00FFFFFF003B7F + 320015A9000015A9000015A9000015A9000015AA009915AA00CC15AA00CC15AA + 009915A9000015A9000015A9000015A90000094D0000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 0 OnClick = MenuItem1Click end object MenuItem2: TMenuItem Caption = 'Edit' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 200000000000000400006400000064000000000000000000000000000000014B + 649A012E3C63010A0D350000002D0000002A00000026000000210000001D0000 + 001900000014000000100000000B000000080000000500000002015E7B85C2E6 + F2FF5591A5D1014C649A013141500000001500000013000000110000000F0000 + 000D0000000A0000000800000006000000040000000300000001016B8E3962A5 + BBC0C2E6F2FFA0CEDDF501596FC30060764701343E0000000000000000000000 + 000000000000000000000000000000000000000000000000000000759B060072 + 976CC0E4F1EF44BBCCFF58CEDFFF016379CA01687D47016F8500013C47000000 + 0000000000000000000000000000000000000000000000000000007CA500007C + A527018DA8A688EEFFFF5DD1E2FF5BD0E1FF016B80C80170864601788E000281 + 9700014550000000000000000000000000000000000000000000007CA500007D + A600019AB2400195ADB788EEFFFF63D5E6FF5FD3E4FF017389C701798F450281 + 97000289A0000291A800024D5800000000000000000000000000007CA500007D + A600019BB200019AB2400195ADB788EEFFFF69DAEBFF60D3E4FF027C92C50282 + 98450289A0000291A8000399AF000A0A0A000505050000000000007CA500007D + A600019BB200019BB200019AB2400195ADB788EEFFFF71DEEFFF60D3E4FF0285 + 9BC3028AA1450291A8000399AF000A0A0A000A0A0A000A0A0A00007CA500007D + A600019BB200019BB200019BB200019AB2400195ADB788EEFFFF78E3F4FF5DD2 + E3FF028DA4C20292A9440399AF000A0A0A000A0A0A000A0A0A00007CA500007D + A600019BB200019BB200019BB200019BB200019AB2400195ADB788EEFFFF7EE7 + F8FF5ACFE0FF0395ACC0039AB0430A0A0A000A0A0A000A0A0A00007CA500007D + A600019BB200019BB200019BB200019BB200019BB200019AB2400195ADB788EE + FFFF83EBFCFF56CDDEFF087A8CB00C0C0C2F0A0A0A000A0A0A00001F2A00005E + 7D00019BB200019BB200019BB200019BB200019BB200019BB200019AB2400195 + ADB788EEFFFF33AABBFFDDDDDDFF171717830909312905055500000000000000 + 000001272D0001758600019BB200019BB200019BB200019BB200019BB200019A + B240158395A3F6F6F6FFCCCCCCFFDDDDDDFF060683B50000A032000000000000 + 0000000000000000000001272D0001758600019BB200019BB200019BB200019B + B2005555552450505069F6F6F6FF6868F8FF5C5CF2FF0000A8B1000000000000 + 00000000000000000000000000000000000001272D0001758600019BB200019B + B200555555005555551F1515BC9D8888FFFF0101C5B90101B443000000000000 + 000000000000000000000000000000000000000000000000000001272D000175 + 860055555500555555000101E42B0101E09D0101D23F0101B600 + } ImageIndex = 1 OnClick = MenuItem2Click end @@ -126,6 +371,42 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm end object MenuItem4: TMenuItem Caption = 'Delete' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 2 OnClick = MenuItem4Click end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index f36b997c7..9eee0976c 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -24,11 +24,21 @@ TWebsiteOptionAdvancedForm = class(TForm) MenuItem2: TMenuItem; MenuItem3: TMenuItem; MenuItem4: TMenuItem; + pcUpdateList: TPageControl; + pcDownloads: TPageControl; pcAdvanced: TPageControl; pmCookies: TPopupMenu; + tsMaxThreadsPerTask: TTabSheet; + tsDirectoryPageNumber: TTabSheet; + tsNumberofThreads: TTabSheet; + tsUpdateList: TTabSheet; + tsDownloads: TTabSheet; tsCookies: TTabSheet; tsUserAgent: TTabSheet; vtCookies: TVirtualStringTree; + vtDownloadMaxThreadsPerTask: TVirtualStringTree; + vtUpdateListDirectoryPageNumber: TVirtualStringTree; + vtUpdateListNumberOfThreads: TVirtualStringTree; vtUserAgent: TVirtualStringTree; procedure FormCreate(Sender: TObject); procedure MenuItem1Click(Sender: TObject); @@ -71,6 +81,9 @@ procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); begin LoadFromFileToVT(vtCookies, 'Cookies'); LoadFromFileToVT(vtUserAgent, 'UserAgent'); + LoadFromFileToVT(vtDownloadMaxThreadsPerTask, 'DownloadMaxThreadsPerTask'); + LoadFromFileToVT(vtUpdateListDirectoryPageNumber, 'UpdateListDirectoryPageNumber'); + LoadFromFileToVT(vtUpdateListNumberOfThreads, 'UpdateListNumberOfThreads'); end; procedure TWebsiteOptionAdvancedForm.MenuItem1Click(Sender: TObject); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 40c9ddde6..fcbe39472 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1508,6 +1508,7 @@ msgid "Dialogs" msgstr "Dialogs" #: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Downloads" @@ -1706,6 +1707,27 @@ msgctxt "twebsiteoptionadvancedform.tscookies.caption" msgid "Cookies" msgstr "Cookies" +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Directory page number" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Downloads" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Max threads per task" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Number of threads" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Update List" + #: twebsiteoptionadvancedform.tsuseragent.caption msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" msgid "User Agent" @@ -1721,6 +1743,36 @@ msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" msgid "Cookies" msgstr "Cookies" +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Value" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Value" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Value" + #: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" msgid "Website" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 010a11552..801c0485b 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1491,6 +1491,7 @@ msgid "Dialogs" msgstr "Dialog" #: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Unduhan" @@ -1689,6 +1690,27 @@ msgctxt "twebsiteoptionadvancedform.tscookies.caption" msgid "Cookies" msgstr "Cookies" +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Jumlah halaman directory" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Unduhan" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Max jumlah threafs per unduhan" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Jumlah threads" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Pembaruan daftar" + #: twebsiteoptionadvancedform.tsuseragent.caption msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" msgid "User Agent" @@ -1704,6 +1726,36 @@ msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" msgid "Cookies" msgstr "Cookies" +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Situs web" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Nilai" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Situs web" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Nilai" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Situs web" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Nilai" + #: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" msgid "Website" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 7e9508f47..a498858b1 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1436,6 +1436,7 @@ msgid "Dialogs" msgstr "" #: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "" @@ -1632,6 +1633,27 @@ msgctxt "twebsiteoptionadvancedform.tscookies.caption" msgid "Cookies" msgstr "" +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.TSDOWNLOADS.CAPTION" +msgid "Downloads" +msgstr "" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "" + #: twebsiteoptionadvancedform.tsuseragent.caption msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" msgid "User Agent" @@ -1647,6 +1669,36 @@ msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[1].TEXT" msgid "Cookies" msgstr "" +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTDOWNLOADMAXTHREADSPERTASK.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[1].TEXT" +msgid "Value" +msgstr "" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[1].TEXT" +msgid "Value" +msgstr "" + #: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[0].TEXT" msgid "Website" From ea60df60045cb88aab7e4d6469d4db563f73074e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Apr 2016 15:14:11 +0800 Subject: [PATCH 1109/2794] downloadmanager, improve count transfer rate, fix and cleanup --- baseunits/uDownloadsManager.pas | 231 ++++++++++++------------------ baseunits/uFavoritesManager.pas | 4 +- mangadownloader/forms/frmMain.pas | 22 ++- 3 files changed, 104 insertions(+), 153 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index af22e05cf..277d83640 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -81,6 +81,7 @@ TDownloadThread = class(TFMDThread) TTaskThread = class(TFMDThread) private ModuleId: Integer; + FCheckAndActiveTaskFlag: Boolean; protected FMessage, FAnotherURL: String; procedure CheckOut; @@ -89,9 +90,9 @@ TTaskThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; procedure Compress; + procedure SyncStop; // show notification when download completed procedure SyncShowBaloon; - procedure SyncStop; public //additional parameter httpCookies: String; @@ -109,11 +110,13 @@ TTaskThread = class(TFMDThread) TTaskContainer = class private - FReadCount: Integer; - CS_FContainer: TCriticalSection; FWebsite: String; procedure SetWebsite(AValue: String); public + // critical section + CS_Container: TCriticalSection; + // read count for transfer rate + ReadCount: Integer; // task thread of this container Thread: TTaskThread; // download manager @@ -140,8 +143,6 @@ TTaskContainer = class constructor Create; destructor Destroy; override; procedure IncReadCount(const ACount: Integer); - procedure Lock; inline; - procedure Unlock; inline; property Website: String read FWebsite write SetWebsite; end; @@ -149,7 +150,6 @@ TTaskContainer = class TDownloadManager = class private - FTotalReadCount: Integer; FSortDirection: Boolean; FSortColumn: Integer; DownloadManagerFile: TIniFileRun; @@ -158,9 +158,9 @@ TDownloadManager = class function GetTaskCount: Integer; function GetTransferRate: Integer; public - CS_DownloadManager_Task: TCriticalSection; - CS_DownloadedChapterList: TCriticalSection; + CS_Task: TCriticalSection; Containers: TFPList; + ContainersActiveTask: TFPList; isRunningBackup, isFinishTaskAccessed, isRunningBackupDownloadedChaptersList, isReadyForExit: Boolean; @@ -184,9 +184,6 @@ TDownloadManager = class procedure Restore; procedure Backup; - // TransferRate - procedure ClearTransferRate; - // These methods relate to highlight downloaded chapters. procedure GetDownloadedChaptersState(const Alink: String; var Chapters: array of TChapterStateItem); @@ -332,13 +329,13 @@ procedure TDownloadThread.Execute; if not Terminated and Reslt then begin - manager.container.Lock; + manager.container.CS_Container.Acquire; try manager.container.DownCounter := InterLockedIncrement(manager.container.DownCounter); manager.container.DownloadInfo.Progress := Format('%d/%d', [manager.container.DownCounter, manager.container.PageNumber]); finally - manager.container.Unlock; + manager.container.CS_Container.Release; end; end; except @@ -981,6 +978,7 @@ constructor TTaskThread.Create; inherited Create(True); threads := TFPList.Create; ModuleId := -1; + FCheckAndActiveTaskFlag := True; anotherURL := ''; httpCookies := ''; end; @@ -1030,6 +1028,11 @@ procedure TTaskThread.Compress; end; end; +procedure TTaskThread.SyncStop; +begin + container.Manager.CheckAndActiveTask(FCheckAndActiveTaskFlag); +end; + procedure TTaskThread.SyncShowBaloon; begin if container.Status = STATUS_FAILED then @@ -1257,7 +1260,7 @@ procedure TTaskThread.Execute; begin ModuleId := container.ModuleId; container.ThreadState := True; - container.DownloadInfo.TransferRate := ''; + container.DownloadInfo.TransferRate := FormatByteSize(container.ReadCount, true); try if container.ModuleId > -1 then DynamicPageLink := Modules.Module[ModuleId].DynamicPageLink @@ -1478,41 +1481,40 @@ procedure TTaskThread.DoTerminate; while threads.Count > 0 do Sleep(100); end; - container.DownloadInfo.TransferRate := ''; - container.ThreadState := False; - container.Thread := nil; Modules.DecActiveTaskCount(ModuleId); - Synchronize(SyncStop); - inherited DoTerminate; -end; - -procedure TTaskThread.SyncStop; -begin - if container.Status = STATUS_STOP then - Exit; - if not container.Manager.isReadyForExit then - begin - if (container.WorkCounter >= container.PageLinks.Count) and - (container.CurrentDownloadChapterPtr >= container.ChapterLinks.Count) - and (container.FailedChapterLinks.Count = 0) then - begin - container.Status := STATUS_FINISH; - container.DownloadInfo.Status := RS_Finish; - container.DownloadInfo.Progress := ''; - container.Manager.CheckAndActiveTask(True); - end - else - if (container.Status in [STATUS_PROBLEM, STATUS_FAILED]) then - container.Manager.CheckAndActiveTask(True) - else + with container do begin + container.ReadCount := 0; + DownloadInfo.TransferRate := ''; + ThreadState := False; + Thread := nil; + Manager.CS_Task.Acquire; + try + Manager.ContainersActiveTask.Remove(container); + finally + Manager.CS_Task.Release; + end; + if (Status <> STATUS_STOP) and (not Manager.isReadyForExit) then begin - container.Status := STATUS_STOP; - container.DownloadInfo.Status := - Format('%s (%d/%d)', [RS_Stopped, container.CurrentDownloadChapterPtr + - 1, container.ChapterLinks.Count]); - container.Manager.CheckAndActiveTask(False); + if (WorkCounter >= PageLinks.Count) and + (CurrentDownloadChapterPtr >= ChapterLinks.Count) + and (FailedChapterLinks.Count = 0) then + begin + Status := STATUS_FINISH; + DownloadInfo.Status := RS_Finish; + DownloadInfo.Progress := ''; + end + else + begin + Status := STATUS_STOP; + DownloadInfo.Status := + Format('%s (%d/%d)', [RS_Stopped, CurrentDownloadChapterPtr + + 1, ChapterLinks.Count]); + FCheckAndActiveTaskFlag := False; + end; + Synchronize(SyncStop); end; end; + inherited DoTerminate; end; { TTaskContainer } @@ -1530,7 +1532,7 @@ constructor TTaskContainer.Create; begin inherited Create; ThreadState := False; - CS_FContainer := TCriticalSection.Create; + CS_Container := TCriticalSection.Create; ChapterLinks := TStringList.Create; ChapterName := TStringList.Create; FailedChapterName := TStringList.Create; @@ -1538,7 +1540,7 @@ constructor TTaskContainer.Create; PageLinks := TStringList.Create; PageContainerLinks := TStringList.Create; Filenames := TStringList.Create; - FReadCount := 0; + ReadCount := 0; WorkCounter := 0; CurrentPageNumber := 0; CurrentDownloadChapterPtr := 0; @@ -1553,30 +1555,20 @@ destructor TTaskContainer.Destroy; ChapterLinks.Free; FailedChapterName.Free; FailedChapterLinks.Free; - CS_FContainer.Free; + CS_Container.Free; inherited Destroy; end; procedure TTaskContainer.IncReadCount(const ACount: Integer); begin - Lock; + CS_Container.Acquire; try - Inc(FReadCount, ACount); + Inc(ReadCount, ACount); finally - Unlock; + CS_Container.Release; end; end; -procedure TTaskContainer.Lock; -begin - CS_FContainer.Acquire; -end; - -procedure TTaskContainer.Unlock; -begin - CS_FContainer.Release; -end; - { TDownloadManager } function TDownloadManager.GetItems(Index: Integer): TTaskContainer; @@ -1595,33 +1587,23 @@ function TDownloadManager.GetTransferRate: Integer; i: Integer; begin Result := 0; - if Containers.Count > 0 then - begin - CS_DownloadManager_Task.Acquire; - try - FTotalReadCount := 0; - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do - if ThreadState then - begin - Lock; - try - if Status = STATUS_COMPRESS then - DownloadInfo.TransferRate := '' - else - begin - DownloadInfo.TransferRate := FormatByteSize(FReadCount, True); - Inc(FTotalReadCount, FReadCount); - end; - FReadCount := 0; - finally - Unlock; - end; - end; - Result := FTotalReadCount; - finally - CS_DownloadManager_Task.Release; - end; + if ContainersActiveTask.Count = 0 then Exit; + CS_Task.Acquire; + try + for i := 0 to ContainersActiveTask.Count - 1 do + with TTaskContainer(ContainersActiveTask[i]) do + begin + CS_Container.Acquire; + try + DownloadInfo.TransferRate := FormatByteSize(ReadCount, True); + Inc(Result, ReadCount); + ReadCount := 0; + finally + CS_Container.Release; + end; + end; + finally + CS_Task.Release; end; end; @@ -1630,11 +1612,8 @@ constructor TDownloadManager.Create; inherited Create; ForceDirectoriesUTF8(WORK_FOLDER); - CS_DownloadManager_Task := TCriticalSection.Create; - CS_DownloadedChapterList := TCriticalSection.Create; - + CS_Task := TCriticalSection.Create; DownloadManagerFile := TIniFileRun.Create(WORK_FILE); - DownloadedChapters := TDownloadedChaptersDB.Create; DownloadedChapters.Filename := DOWNLOADEDCHAPTERSDB_FILE; DownloadedChapters.OnError := MainForm.ExceptionHandler; @@ -1644,6 +1623,7 @@ constructor TDownloadManager.Create; DeleteFileUTF8(DOWNLOADEDCHAPTERS_FILE); Containers := TFPList.Create; + ContainersActiveTask := TFPList.Create; isFinishTaskAccessed := False; isRunningBackup := False; isRunningBackupDownloadedChaptersList := False; @@ -1652,7 +1632,7 @@ constructor TDownloadManager.Create; destructor TDownloadManager.Destroy; begin - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try while Containers.Count > 0 do begin @@ -1660,13 +1640,13 @@ destructor TDownloadManager.Destroy; Containers.Remove(Containers.Last); end; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; - FreeAndNil(Containers); - FreeAndNil(DownloadManagerFile); + Containers.Free; + DownloadManagerFile.Free; + ContainersActiveTask.Free; DownloadedChapters.Free; - CS_DownloadedChapterList.Free; - CS_DownloadManager_Task.Free; + CS_Task.Free; inherited Destroy; end; @@ -1675,7 +1655,7 @@ procedure TDownloadManager.Restore; tid, s: String; tmp, i, j: Integer; begin - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try while Containers.Count > 0 do begin @@ -1749,7 +1729,7 @@ procedure TDownloadManager.Restore; end; end; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; end; @@ -1762,7 +1742,7 @@ procedure TDownloadManager.Backup; Exit; isRunningBackup := True; - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; with DownloadManagerFile do try // Erase all sections @@ -1806,37 +1786,11 @@ procedure TDownloadManager.Backup; end; UpdateFile; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; isRunningBackup := False; end; -procedure TDownloadManager.ClearTransferRate; -var - i: Integer; -begin - if Containers.Count > 0 then - begin - CS_DownloadManager_Task.Acquire; - try - FTotalReadCount := 0; - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do - begin - Lock; - try - FReadCount := 0; - DownloadInfo.TransferRate := ''; - finally - Unlock; - end; - end; - finally - CS_DownloadManager_Task.Release; - end; - end; -end; - procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; var Chapters: array of TChapterStateItem); var @@ -1861,12 +1815,12 @@ procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; function TDownloadManager.AddTask: Integer; begin Result := -1; - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try Result := Containers.Add(TTaskContainer.Create); TTaskContainer(Containers.Last).Manager := Self; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; end; @@ -1875,7 +1829,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); i, tcount: Integer; begin if Containers.Count = 0 then Exit; - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try tcount := 0; for i := 0 to Containers.Count - 1 do @@ -1893,7 +1847,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); Inc(tcount); end; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; try @@ -1969,6 +1923,7 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); Modules.IncActiveTaskCount(ModuleId); Thread := TTaskThread.Create; Thread.container := TTaskContainer(Containers[taskID]); + ContainersActiveTask.Add(Thread.container); Thread.Start; end; end; @@ -2046,7 +2001,7 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; procedure TDownloadManager.RemoveTask(const taskID: Integer); begin if (taskID < 0) or (taskID >= Containers.Count) then Exit; - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try with TTaskContainer(Containers[taskID]) do if ThreadState then begin @@ -2056,7 +2011,7 @@ procedure TDownloadManager.RemoveTask(const taskID: Integer); TTaskContainer(Containers[taskID]).Free; Containers.Delete(taskID); finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; CheckAndActiveTask; end; @@ -2081,7 +2036,7 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea Result := False; if Containers.Count > 0 then begin - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try for i := 0 to Containers.Count - 1 do if TTaskContainer(Containers[i]).Status in Stats then begin @@ -2089,7 +2044,7 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea Break; end; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; end; end; @@ -2134,12 +2089,12 @@ function CompareTaskContainer(Item1, Item2: Pointer): Integer; procedure TDownloadManager.Sort(const AColumn: Integer); begin if Containers.Count < 2 then Exit; - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try SortColumn := AColumn; Containers.Sort(CompareTaskContainer); finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index d28c02cca..5bb441cc6 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -667,7 +667,7 @@ procedure TFavoriteManager.ShowResult; with Items[counter] do if Assigned(NewMangaInfo) then if NewMangaInfo.chapterLinks.Count > 0 then begin - DLManager.CS_DownloadManager_Task.Acquire; + DLManager.CS_Task.Acquire; try DLManager.containers.Add(TTaskContainer.Create); with TTaskContainer(DLManager.Containers.Last) do begin @@ -705,7 +705,7 @@ procedure TFavoriteManager.ShowResult; FavoriteInfo.currentChapter := IntToStr(MangaInfo.chapterLinks.Count); finally - DLManager.CS_DownloadManager_Task.Release; + DLManager.CS_Task.Release; end; //mark downloaded FavoriteInfo.downloadedChapterList := diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 56945a42f..0c5788780 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1404,11 +1404,7 @@ procedure TMainForm.itRefreshDLInfoStartTimer(Sender: TObject); procedure TMainForm.itRefreshDLInfoStopTimer(Sender: TObject); begin - if Assigned(DLManager) then - begin - DLManager.ClearTransferRate; - TransferRateGraph.Visible := False; - end; + TransferRateGraph.Visible := False; vtDownload.Repaint; end; @@ -1552,7 +1548,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if MessageDlg('', RS_DlgRemoveTask, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then Exit; - DLManager.CS_DownloadManager_Task.Acquire; + DLManager.CS_Task.Acquire; try xNode := vtDownload.GetLast(); while Assigned(xNode) do begin @@ -1580,7 +1576,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); xNode := vtDownload.GetPreviousSelected(xNode); end; finally - DLManager.CS_DownloadManager_Task.Release; + DLManager.CS_Task.Release; end; DLManager.CheckAndActiveTask; UpdateVtDownload; @@ -3024,7 +3020,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); begin Result := False; with DLManager do begin - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try for i := 0 to Count - 1 do if Items[i].Status = STATUS_FINISH then @@ -3033,7 +3029,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); Break; end; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; end; end; @@ -3047,7 +3043,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); begin with DLManager do begin - CS_DownloadManager_Task.Acquire; + CS_Task.Acquire; try xNode := vtDownload.GetFirstSelected; repeat @@ -3059,7 +3055,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); xNode := vtDownload.GetNextSelected(xNode); until xNode = nil; finally - CS_DownloadManager_Task.Release; + CS_Task.Release; end; end; end; @@ -3398,7 +3394,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); nIndex:=NextIndex; vtDownload.BeginUpdate; ConTemp:=TFPList.Create; - DLManager.CS_DownloadManager_Task.Acquire; + DLManager.CS_Task.Acquire; try i:=0; cNode:=vtDownload.GetFirstSelected(); @@ -3441,7 +3437,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); if Mode=dmAbove then vtDownload.FocusedNode:=cNode; finally - DLManager.CS_DownloadManager_Task.Release; + DLManager.CS_Task.Release; end; ConTemp.Free; vtDownload.EndUpdate; From fb46e2b4f1c07289ca3640678cf5f2e1211f15f1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Apr 2016 13:23:39 +0800 Subject: [PATCH 1110/2794] udata, fill n/a for empty title --- baseunits/uData.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d292d174f..b37c8ee61 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1658,6 +1658,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco summary := CleanMultilinedString(FixWhiteSpace(summary)); // fix info + if title = '' then + title := 'N/A'; if (LeftStr(authors, 1) = '<') or (authors = '-') or (authors = ':') then authors := ''; if (LeftStr(artists, 1) = '<') or (artists = '-') or (artists = ':') then From e24637756448dfac8ef2e94b93b78163d329543b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Apr 2016 21:27:06 +0800 Subject: [PATCH 1111/2794] baseunit, added function titlecase --- baseunits/uBaseUnit.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5895904b0..cf775df8d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -716,6 +716,7 @@ procedure PadZeros(S: TStrings; ATotalWidth: Integer = 3; // maintain the order of strings by adding serialized number if necessary procedure SerializeAndMaintainNames(F: TStrings); +function TitleCase(const S: string): string; function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; function StreamToString(const Stream: TStream): String; inline; function GetRightValue(const Name, s: String): String; @@ -2097,6 +2098,14 @@ procedure SerializeAndMaintainNames(F: TStrings); end; end; +function TitleCase(const S: string): string; +begin + Result := AnsiProperCase(S, + [#9, #10, #13, + ' ', '.', ',', '-', '+', '_', '=', + '/', '\', '[', ']', '(', ')', '{', '}', '<', '>']); +end; + function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; var b1, b2: Char; From 08aa3f9197116f55e10a73bf47d84acb453009aa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Apr 2016 22:14:56 +0800 Subject: [PATCH 1112/2794] hitomila, fix info --- baseunits/modules/HitomiLa.pas | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index e5cca7293..8064f2a06 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation @@ -68,8 +68,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - t: TTreeNode; s: String; + i: SizeInt; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -78,16 +78,15 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - t := XPath('//div[contains(@class,"dj-gallery")]').toNode; - coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src', t)); - title := XPathString('//div/h1', t); - artists := XPathString('//h2//a[contains(@href,"/artist/")]', t); - if (title = '') and (artists <> '') then - title := artists; + coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src')); + title := ReplaceRegExpr('( by.*)? - Read Online.*$', XPathString('//title'), '', False); + if title = '' then + title := GetBetween('/galleries/', '.html', AnsiLowerCase(AURL)); + artists := TitleCase(XPathString('//div[starts-with(@class,"gallery")]/h2/ul/li/a')); genres := ''; - for v in XPath('//div[@class="gallery-info"]/table//tr/td[2]//a', t) do - AddCommaString(genres, v.toString); - s := XPathString('//div[@class="cover-column"]/a/@href', t); + for v in XPath('//div[@class="gallery-info"]/table//tr/td//a') do + AddCommaString(genres, TitleCase(v.toString)); + s := XPathString('//div[@class="cover-column"]/a/@href'); if (s <> '') and (title <> '') then begin chapterLinks.Add(s); chapterName.Add(title); From 808e466c1e351e97824d6d0024ee76fd36bad4a8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Apr 2016 22:35:07 +0800 Subject: [PATCH 1113/2794] hitomila, fix title --- baseunits/modules/HitomiLa.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 8064f2a06..1d8ed78f6 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -79,7 +79,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src')); - title := ReplaceRegExpr('( by.*)? - Read Online.*$', XPathString('//title'), '', False); + title := Trim(ReplaceRegExpr('( by.*)?- Read Online.*$', XPathString('//title'), '', False)); if title = '' then title := GetBetween('/galleries/', '.html', AnsiLowerCase(AURL)); artists := TitleCase(XPathString('//div[starts-with(@class,"gallery")]/h2/ul/li/a')); From c3efb3d8ee19a90dc55465c01f3fc32432709539 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Apr 2016 00:25:20 +0800 Subject: [PATCH 1114/2794] Bump version 0.9.49.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4af049bde..e2929d8aa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.49.0 (08-04-2016) +[*] Preserve file last modified date from server +[*] Added more website advanced option +[*] HitomiLa: fix info +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.48.0...0.9.49.0 + 0.9.48.0 (02-04-2016) [*] E-Hentai/ExHentai: Fixed filename serialized several times [+] Added ReadComicOnline[EN] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f23135b9d..0a0230efd 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="48"/> + <RevisionNr Value="49"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 90349545b..582bca74d 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.48.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.48.0/fmd_0.9.48.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.48.0/fmd_0.9.48.0_Win64.7z +VERSION=0.9.49.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.49.0/fmd_0.9.49.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.49.0/fmd_0.9.49.0_Win64.7z From 415e97c8bb83c54ec21b17956f10c6a5d721618a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Apr 2016 19:43:33 +0800 Subject: [PATCH 1115/2794] cleanup --- baseunits/modules/HitomiLa.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 1d8ed78f6..39c75238b 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -69,7 +69,6 @@ function GetInfo(const MangaInfo: TMangaInformation; var v: IXQValue; s: String; - i: SizeInt; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); From 40a54d2d4f3921d2b99c5dd7732e74562ecdd4cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Apr 2016 19:44:27 +0800 Subject: [PATCH 1116/2794] httpsendthread, added possibility to apply retrycount,, timeout and proxy to all existing httpsendthread - store all httpsendthread object to fplist - added setdefaulttimeoutandapply, setdefaultretrycountandapply, setdefaultproxyandapply --- baseunits/httpsendthread.pas | 92 ++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 0517d5997..2c02d8d34 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -22,6 +22,7 @@ THTTPSendThread = class(THTTPSend) procedure OnOwnerTerminate(Sender: TObject); public constructor Create(AOwner: TFMDThread = nil); + destructor Destroy; override; function HTTPRequest(const Method, URL: String; const Response: TObject = nil): Boolean; function HEAD(const URL: String; const Response: TObject = nil): Boolean; function GET(const URL: String; const Response: TObject = nil): Boolean; @@ -41,7 +42,10 @@ THTTPSendThread = class(THTTPSend) function KeyVal(const AKey, AValue: String): TKeyValuePair; function QueryString(KeyValuePairs: array of TKeyValuePair): String; -procedure SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String); +function SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String): Boolean; +procedure SetDefaultProxyAndApply(const ProxyType, Host, Port, User, Pass: String); +procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); +procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); var DefaultUserAgent: String = @@ -56,6 +60,10 @@ procedure SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String); implementation +var + ALLHTTPSendThread: TFPList; + CS_ALLHTTPSendThread: TRTLCriticalSection; + function KeyVal(const AKey, AValue: String): TKeyValuePair; begin Result[0] := AKey; @@ -76,8 +84,14 @@ function QueryString(KeyValuePairs: array of TKeyValuePair): String; end; end; -procedure SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String); +function SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String): Boolean; begin + Result := (ProxyType <> DefaultProxyType) or + (Host <> DefaultProxyHost) or + (Port <> DefaultProxyPort) or + (User <> DefaultProxyUser) or + (Pass <> DefaultProxyPass); + if not Result then Exit; DefaultProxyType := ProxyType; DefaultProxyHost := Host; DefaultProxyPort := Port; @@ -85,6 +99,53 @@ procedure SetDefaultProxy(const ProxyType, Host, Port, User, Pass: String); DefaultProxyPass := Pass; end; +procedure SetDefaultProxyAndApply(const ProxyType, Host, Port, User, Pass: String); +var + i: SizeInt; +begin + if not SetDefaultProxy(ProxyType, Host, Port, User, Pass) then Exit; + EnterCriticalsection(CS_ALLHTTPSendThread); + try + if ALLHTTPSendThread.Count > 0 then + for i := 0 to ALLHTTPSendThread.Count - 1 do + THTTPSendThread(ALLHTTPSendThread[i]).SetProxy(ProxyType, Host, Port, User, Pass); + finally + LeaveCriticalsection(CS_ALLHTTPSendThread); + end; +end; + +procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); +var + i: SizeInt; +begin + if ATimeout = DefaultTimeout then Exit; + DefaultTimeout := ATimeout; + EnterCriticalsection(CS_ALLHTTPSendThread); + try + if ALLHTTPSendThread.Count > 0 then + for i := 0 to ALLHTTPSendThread.Count - 1 do + THTTPSendThread(ALLHTTPSendThread[i]).Timeout := ATimeout; + finally + LeaveCriticalsection(CS_ALLHTTPSendThread); + end; +end; + +procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); +var + i: SizeInt; +begin + if ARetryCount = DefaultRetryCount then Exit; + DefaultRetryCount := ARetryCount; + EnterCriticalsection(CS_ALLHTTPSendThread); + try + if ALLHTTPSendThread.Count > 0 then + for i := 0 to ALLHTTPSendThread.Count - 1 do + THTTPSendThread(ALLHTTPSendThread[i]).RetryCount := ARetryCount; + finally + LeaveCriticalsection(CS_ALLHTTPSendThread); + end; +end; + { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); @@ -121,6 +182,23 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); fowner := AOwner; fowner.OnCustomTerminate := @OnOwnerTerminate; end; + EnterCriticalsection(CS_ALLHTTPSendThread); + try + ALLHTTPSendThread.Add(Self); + finally + LeaveCriticalsection(CS_ALLHTTPSendThread); + end; +end; + +destructor THTTPSendThread.Destroy; +begin + EnterCriticalsection(CS_ALLHTTPSendThread); + try + ALLHTTPSendThread.Remove(Self); + finally + LeaveCriticalsection(CS_ALLHTTPSendThread); + end; + inherited Destroy; end; function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: TObject): Boolean; @@ -264,7 +342,7 @@ procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, Pass: Stri var pt: String; begin - pt := upcase(ProxyType); + pt := AnsiUpperCase(ProxyType); with Sock do begin if pt = 'HTTP' then begin @@ -316,4 +394,12 @@ procedure THTTPSendThread.Reset; if fgzip then Headers.Values['Accept-Encoding'] := ' gzip, deflate'; end; +initialization + InitCriticalSection(CS_ALLHTTPSendThread); + ALLHTTPSendThread := TFPList.Create; + +finalization + ALLHTTPSendThread.Free; + DoneCriticalsection(CS_ALLHTTPSendThread); + end. From f4471fea3e632fe84be6237a899cbd0c8febc931 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Apr 2016 19:44:37 +0800 Subject: [PATCH 1117/2794] apply connection option to all existing thttpsendthread and cleanup --- baseunits/FMDOptions.pas | 2 -- baseunits/uBaseUnit.pas | 12 ++++++------ baseunits/uFavoritesManager.pas | 4 ++-- baseunits/uSilentThread.pas | 4 ++-- baseunits/uUpdateThread.pas | 6 +++--- mangadownloader/forms/frmMain.pas | 27 +++++++-------------------- 6 files changed, 20 insertions(+), 35 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index c2843c247..0f61f25e2 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -95,8 +95,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionChapterCustomRename: String; OptionPDFQuality: Cardinal = 95; - OptionConnectionMaxRetry: Integer = 5; - OptionConnectionTimeout: Integer = 30000; OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cf775df8d..a3090c96f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3000,9 +3000,9 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; else begin HTTP := THTTPSend.Create; - HTTP.Timeout := OptionConnectionTimeout; - HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; - HTTP.Sock.SetTimeout(OptionConnectionTimeout); + HTTP.Timeout := DefaultTimeout; + HTTP.Sock.ConnectionTimeout := DefaultTimeout; + HTTP.Sock.SetTimeout(DefaultTimeout); end; HTTP.Headers.NameValueSeparator := ':'; @@ -3321,9 +3321,9 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; else begin HTTP := THTTPSend.Create; - HTTP.Timeout := OptionConnectionTimeout; - HTTP.Sock.ConnectionTimeout := OptionConnectionTimeout; - HTTP.Sock.SetTimeout(OptionConnectionTimeout); + HTTP.Timeout := DefaultTimeout; + HTTP.Sock.ConnectionTimeout := DefaultTimeout; + HTTP.Sock.SetTimeout(DefaultTimeout); end; HTTP.Headers.NameValueSeparator := ':'; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 5bb441cc6..02af2f68d 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -13,7 +13,7 @@ interface uses Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, FileUtil, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, FMDOptions, - SimpleException; + httpsendthread, SimpleException; type TFavoriteManager = class; @@ -205,7 +205,7 @@ procedure TFavoriteThread.Execute; Synchronize(SyncStatus); getInfo.mangaInfo.title := container.FavoriteInfo.Title; getInfo.GetInfoFromURL(container.FavoriteInfo.Website, - container.FavoriteInfo.Link, OptionConnectionMaxRetry); + container.FavoriteInfo.Link, DefaultRetryCount); if container.MangaInfo = nil then container.MangaInfo := TMangaInfo.Create; TransferMangaInfo(container.MangaInfo, getInfo.mangaInfo); diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index bd0831f1a..3a9ad3194 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -16,7 +16,7 @@ interface uses Classes, SysUtils, uBaseUnit, uData, uFMDThread, uDownloadsManager, - WebsiteModules, FMDOptions, LazFileUtils; + WebsiteModules, FMDOptions, httpsendthread, LazFileUtils; type @@ -415,7 +415,7 @@ procedure TSilentThread.Execute; try Info.ModuleId := Self.ModuleId; Info.mangaInfo.title := title; - if Info.GetInfoFromURL(website, URL, OptionConnectionMaxRetry) = NO_ERROR then + if Info.GetInfoFromURL(website, URL, DefaultRetryCount) = NO_ERROR then if not Terminated then Synchronize(MainThreadAfterChecking); except diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 1331a9f01..a464ea111 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -11,8 +11,8 @@ interface uses - Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, - uBaseUnit, uFMDThread, uMisc, WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions; + Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, uBaseUnit, uFMDThread, uMisc, + WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread; type TUpdateListManagerThread = class; @@ -227,7 +227,7 @@ procedure TUpdateListThread.Execute; begin Info.mangaInfo.title:=title; if link<>'' then begin - Info.GetInfoFromURL(manager.website,link,OptionConnectionMaxRetry); + Info.GetInfoFromURL(manager.website,link,DefaultRetryCount); if not Terminated then begin manager.CS_AddInfoToData.Acquire; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0c5788780..c4a643fdc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4209,8 +4209,8 @@ procedure TMainForm.LoadOptions; // connection seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', 1); seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', OptionConnectionMaxRetry);; - seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', OptionConnectionTimeout); + seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', DefaultRetryCount);; + seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', DefaultTimeout); cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); cbOptionProxyType.Text := ReadString('connections', 'ProxyType', 'HTTP'); edOptionHost.Text := ReadString('connections', 'Host', ''); @@ -4471,26 +4471,13 @@ procedure TMainForm.ApplyOptions; DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; DLManager.retryConnect := seOptionMaxRetry.Value; OptionMaxThreads := seOptionMaxThread.Value; - OptionConnectionTimeout := seOptionConnectionTimeout.Value * 1000; - OptionConnectionMaxRetry := seOptionMaxRetry.Value; - DefaultTimeout := OptionConnectionTimeout; - DefaultRetryCount := OptionConnectionMaxRetry; + SetDefaultTimeoutAndApply(seOptionConnectionTimeout.Value * 1000); + SetDefaultRetryCountAndApply(seOptionMaxRetry.Value); if cbOptionUseProxy.Checked then - begin - DefaultProxyType := cbOptionProxyType.Text; - DefaultProxyHost := edOptionHost.Text; - DefaultProxyPass := edOptionPass.Text; - DefaultProxyPort := edOptionPort.Text; - DefaultProxyUser := edOptionUser.Text; - end + SetDefaultProxyAndApply(cbOptionProxyType.Text, edOptionHost.Text, + edOptionPort.Text, edOptionUser.Text, edOptionPass.Text) else - begin - DefaultProxyType := ''; - DefaultProxyHost := ''; - DefaultProxyPass := ''; - DefaultProxyPort := ''; - DefaultProxyUser := ''; - end; + SetDefaultProxyAndApply('', '', '' ,'', ''); //saveto OptionPDFQuality := seOptionPDFQuality.Value; From 58b5bbb64cd9d13d091f0285e9f895910ddd52a5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Apr 2016 19:59:22 +0800 Subject: [PATCH 1118/2794] changed default connection timeout and retrycount --- baseunits/httpsendthread.pas | 2 +- mangadownloader/forms/frmMain.pas | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 2c02d8d34..91459e8ee 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -50,7 +50,7 @@ procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); var DefaultUserAgent: String = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; - DefaultRetryCount: Integer = 1; + DefaultRetryCount: Integer = 0; DefaultTimeout: Integer = 15000; DefaultProxyType: String = ''; DefaultProxyHost: String = ''; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c4a643fdc..ca5e66f14 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4209,8 +4209,8 @@ procedure TMainForm.LoadOptions; // connection seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', 1); seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', DefaultRetryCount);; - seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', DefaultTimeout); + seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', 5);; + seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', 30000); cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); cbOptionProxyType.Text := ReadString('connections', 'ProxyType', 'HTTP'); edOptionHost.Text := ReadString('connections', 'Host', ''); From c6ddc1e3746df502494b820643d56eb88d960962 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 9 Apr 2016 20:06:55 +0800 Subject: [PATCH 1119/2794] httpsendthread, fix change proxy --- baseunits/httpsendthread.pas | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 91459e8ee..98355f260 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -344,6 +344,15 @@ procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, Pass: Stri begin pt := AnsiUpperCase(ProxyType); with Sock do begin + ProxyHost := ''; + ProxyPort := ''; + ProxyUser := ''; + ProxyPass := ''; + SocksIP := ''; + SocksPort := '1080'; + SocksType := ST_Socks5; + SocksUsername := ''; + SocksPassword := ''; if pt = 'HTTP' then begin ProxyHost := Host; @@ -363,18 +372,6 @@ procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, Pass: Stri SocksPort := Port; SocksUsername := User; SocksPassword := Pass; - end - else - begin - SocksIP := ''; - SocksPort := '1080'; - SocksType := ST_Socks5; - SocksUsername := ''; - SocksPassword := ''; - ProxyHost := ''; - ProxyPort := ''; - ProxyUser := ''; - ProxyPass := ''; end; end; end; From 46d43bf30d5d1ad5d42ffe4f8dc8ee6bf7c93b36 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Apr 2016 15:04:20 +0800 Subject: [PATCH 1120/2794] rsm, fixed empty chapters fixed #228 --- baseunits/modules/RawSenManga.pas | 73 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 99292d946..b65acf3bf 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -37,7 +37,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; i: Integer; s, cl, m: String; @@ -65,46 +64,44 @@ function GetInfo(const MangaInfo: TMangaInformation; else url := FillHost(Module.RootURL, m); if GET(FillHost(Module.RootURL, m)) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink := query.XPathString('//img[@class="series-cover"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := query.XPathString('//h1[@itemprop="name"]'); - v := query.XPath('//div[@class="series_desc"]/*'); - if v.Count > 0 then begin - i := 0; - while i < v.Count - 2 do begin - s := v.get(i).toString; - if Pos('Categorize in:', s) = 1 then genres := v.get(i + 1).toString else - if Pos('Author:', s) = 1 then authors := v.get(i + 1).toString else - if Pos('Artist:', s) = 1 then artists := Trim(SeparateRight(v.get(i).toString, ':')) else - if Pos('Status:', s) = 1 then if Pos('ongoing', LowerCase(v.get(i).toString)) > 0 then - status := '1' else status := '0'; - Inc(i); + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@class="series-cover"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1[@itemprop="name"]'); + v := XPath('//div[@class="series_desc"]/*'); + if v.Count > 0 then begin + i := 0; + while i < v.Count - 2 do begin + s := v.get(i).toString; + if Pos('Categorize in:', s) = 1 then genres := v.get(i + 1).toString else + if Pos('Author:', s) = 1 then authors := v.get(i + 1).toString else + if Pos('Artist:', s) = 1 then artists := Trim(SeparateRight(v.get(i).toString, ':')) else + if Pos('Status:', s) = 1 then if Pos('ongoing', LowerCase(v.get(i).toString)) > 0 then + status := '1' else status := '0'; + Inc(i); + end; end; - end; - summary := query.XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); - if cu and (cl <> '') then - if GET(FillHost(Module.RootURL, cl)) then - begin - query.ParseHTML(StreamToString(Document)); - //selected chapter - //s:=query.XPathString('//select[@name="chapter"]/option[@selected="selected"]'); - //if s<>'' then begin - // chapterLinks.Add(cl); - // chapterName.Add(s); - //end; - //all chapter - for v in query.XPath('//select[@name="chapter"]/option') do begin - chapterLinks.Add(m + v.toNode.getAttribute('value')); + summary := XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); + if not cu then + for v in XPath('//*[@id="content"]/*[@id="post"]//tr[@class="even" or @class="odd"]/td[2]/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); + end + else if cl <> '' then + if GET(FillHost(Module.RootURL, cl)) then + begin + ParseHTML(Document); + for v in XPath('//select[@name="chapter"]/option') do begin + chapterLinks.Add(m + v.toNode.getAttribute('value')); + chapterName.Add(v.toString); + end; end; - InvertStrings([chapterLinks, chapterName]); - end; - finally - query.Free; - end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; end; end; end; From 1257f39603f254f68950126653388145eb1bd739 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Apr 2016 15:11:40 +0800 Subject: [PATCH 1121/2794] rsm, fixed faster get image url --- baseunits/modules/RawSenManga.pas | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index b65acf3bf..c683ad733 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -109,7 +109,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; s: String; begin Result := False; @@ -131,22 +130,22 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, s + '/1')) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber := query.XPath('//select[@name="page"]/option').Count; - if PageNumber > 0 then begin - s := MaybeFillHost(Module.RootURL, query.XPathString('//img[@id="picture"]/@src')); - if Pos('/raw-viewer.php?', LowerCase(s)) > 0 then begin - if LowerCase(RightStr(s, 7)) = '&page=1' then begin + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('//select[@name="page"]/option').Count; + if PageNumber > 0 then begin + s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); + if ((Pos('/raw-viewer.php?', LowerCase(s)) > 0) and (LowerCase(RightStr(s, 7)) = '&page=1')) or + ((Pos('/viewer/', AnsiLowerCase(s)) > 0) and (RightStr(s, 2) = '/1')) then + begin SetLength(s, Length(s) - 1); - while PageLinks.Count < PageNumber do PageLinks.Add(s + IncStr(PageLinks.Count)); + while PageLinks.Count < PageNumber do + PageLinks.Add(s + IncStr(PageLinks.Count)); end; end; + finally + Free; end; - finally - query.Free; - end; end; end; end; From 8c8f03688d0ff87cc13934b8c6b0b52543550769 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Apr 2016 15:26:23 +0800 Subject: [PATCH 1122/2794] added gomanga closed #229 --- baseunits/modules/FoOlSlide.pas | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index b4f5642db..c6f2fd772 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -23,8 +23,11 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if Module.Website = 'YoManga' then s := yomangadirurl - else s := dirurl; + if (Module.Website = 'YoManga') or + (Module.Website = 'GoManga') then + s := yomangadirurl + else + s := dirurl; if MangaInfo.FHTTP.GET(Module.RootURL + s) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; @@ -51,8 +54,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if Module.Website = 'YoManga' then s := yomangadirurl - else s := dirurl; + if (Module.Website = 'YoManga') or + (Module.Website = 'GoManga') then + s := yomangadirurl + else + s := dirurl; s := Module.RootURL + s; if AURL <> '0' then s += IncStr(AURL) + '/'; if MangaInfo.FHTTP.GET(s) then begin @@ -187,6 +193,7 @@ procedure RegisterModule; AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); AddWebsiteModule('YoManga', 'http://yomanga.co'); AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); + AddWebsiteModule('GoManga', 'http://gomanga.co'); end; initialization From 9a58aef05a8020ef16d0783717ef15ce294a7f32 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Apr 2016 15:33:52 +0800 Subject: [PATCH 1123/2794] cleanup --- baseunits/modules/FoOlSlide.pas | 124 ++++++++++++++---------------- baseunits/modules/RawSenManga.pas | 36 ++++----- 2 files changed, 73 insertions(+), 87 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index c6f2fd772..5cb04e065 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -17,7 +17,6 @@ implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; s: String; begin Result := NET_PROBLEM; @@ -30,17 +29,16 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; s := dirurl; if MangaInfo.FHTTP.GET(Module.RootURL + s) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s := query.XPathString('//div[@class="next"]/a[contains(text(),"Last")]/@href'); - if s <> '' then begin - s := ReplaceRegExpr('.*/(\d+)/$', s, '$1', True); - Page := StrToIntDef(s, 1); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('//div[@class="next"]/a[contains(text(),"Last")]/@href'); + if s <> '' then begin + s := ReplaceRegExpr('.*/(\d+)/$', s, '$1', True); + Page := StrToIntDef(s, 1); + end; + finally + Free; end; - finally - query.Free; - end; end; end; @@ -48,7 +46,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; s: String; begin @@ -63,23 +60,21 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if AURL <> '0' then s += IncStr(AURL) + '/'; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//div[@class="list series"]/div/div[@class="title"]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="list series"]/div/div[@class="title"]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - query.Free; - end; end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; begin Result := NET_PROBLEM; @@ -87,28 +82,27 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin if GET(FillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink := query.XPathString('//div[@class="thumbnail"]/img/@src'); - if title = '' then title := query.XPathString('//h1[@class="title"]'); - authors := TrimLeftChar(query.XPathString( - '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), [':', ' ']); - artists := TrimLeftChar(query.XPathString( - '//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), [':', ' ']); - summary := TrimLeftChar(query.XPathString( - '//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), [':', ' ']); - for v in query.XPath('//div[@class="list"]//div[@class="title"]/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - if v.toNode.getAttribute('title') <> '' then - chapterName.Add(v.toNode.getAttribute('title')) - else chapterName.Add(v.toString); + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="thumbnail"]/img/@src'); + if title = '' then title := XPathString('//h1[@class="title"]'); + authors := TrimLeftChar(XPathString( + '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), [':', ' ']); + artists := TrimLeftChar(XPathString( + '//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), [':', ' ']); + summary := TrimLeftChar(XPathString( + '//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), [':', ' ']); + for v in XPath('//div[@class="list"]//div[@class="title"]/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + if v.toNode.getAttribute('title') <> '' then + chapterName.Add(v.toNode.getAttribute('title')) + else chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; end; - InvertStrings([chapterLinks, chapterName]); - finally - query.Free; - end; end; end; end; @@ -116,7 +110,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; v: IXQValue; s: String; begin @@ -127,23 +120,22 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber := query.XPath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').Count; - s := query.XPathString('//script[contains(.,"var pages")]'); - if s <> '' then begin - s := GetBetween('var pages = ', ';', s); - try - query.ParseHTML(s); - for v in query.XPath('json(*)()("url")') do - PageLinks.Add(v.toString); - except + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').Count; + s := XPathString('//script[contains(.,"var pages")]'); + if s <> '' then begin + s := GetBetween('var pages = ', ';', s); + try + ParseHTML(s); + for v in XPath('json(*)()("url")') do + PageLinks.Add(v.toString); + except + end; end; + finally + Free; end; - finally - query.Free; - end; end; end; end; @@ -151,7 +143,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; s: String; begin Result := False; @@ -162,13 +153,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; s := AppendURLDelim(s) + 'page/' + IncStr(DownloadThread.workCounter); if GET(FillHost(Module.RootURL, s)) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := query.XPathString('//div[@id="page"]//img/@src'); - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := XPathString('//div[@id="page"]//img/@src'); + finally + Free; + end; end; end; end; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index c683ad733..31253e2ce 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -14,23 +14,21 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if MangaInfo.FHTTP.GET(Module.RootURL + '/Manga/?order=text-version') then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table//tr/td[2]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//table//tr/td[2]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - query.Free; - end; end; end; @@ -153,7 +151,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; s: String; begin Result := False; @@ -161,15 +158,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.manager.container, DownloadThread.FHTTP do begin if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(DownloadThread.WorkCounter)) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - s := MaybeFillHost(Module.RootURL, query.XPathString('//img[@id="picture"]/@src')); - if s <> '' then - PageLinks[DownloadThread.workCounter] := s; - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); + if s <> '' then + PageLinks[DownloadThread.workCounter] := s; + finally + Free; + end; end; end; end; From bb3c81f06e631925d30222523e99be26cb26f4c9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Apr 2016 15:45:20 +0800 Subject: [PATCH 1124/2794] added gomanga to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 1f27a02fa..a67ae7a96 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 0c1a9a3ff9161ff890ab887d36c241dbc5c6b3ec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 11 Apr 2016 15:47:36 +0800 Subject: [PATCH 1125/2794] Bump version 0.9.50.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index e2929d8aa..67c16af78 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.50.0 (11-04-2016) +[*] Added GoManga[EN] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.49.0...0.9.50.0 + 0.9.49.0 (08-04-2016) [*] Preserve file last modified date from server [*] Added more website advanced option diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0a0230efd..b4b671f77 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="49"/> + <RevisionNr Value="50"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 582bca74d..c9c27a8bf 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.49.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.49.0/fmd_0.9.49.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.49.0/fmd_0.9.49.0_Win64.7z +VERSION=0.9.50.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.50.0/fmd_0.9.50.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.50.0/fmd_0.9.50.0_Win64.7z From f04f6c27749a17d2d6d6b6426cbb0e5d46f678f8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 12 Apr 2016 15:36:18 +0800 Subject: [PATCH 1126/2794] simplelogger, fixed directive --- baseunits/SimpleException/SimpleLogger.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/SimpleException/SimpleLogger.pas b/baseunits/SimpleException/SimpleLogger.pas index ee736bae9..cf52d9b56 100644 --- a/baseunits/SimpleException/SimpleLogger.pas +++ b/baseunits/SimpleException/SimpleLogger.pas @@ -26,7 +26,7 @@ interface uses Classes, SysUtils, DbgInfoReader, LazFileUtils, LazUTF8 - {$ifdef traplazlogger or sendtolazlogger} + {$if defined(traplazlogger) or defined(sendtolazlogger)} , LazLogger {$endif}; From a561e1e965446fecff328342b4b5c7d2e874f821 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 18:59:50 +0800 Subject: [PATCH 1127/2794] move restore form information to onshow fixed #232 --- mangadownloader/forms/frmMain.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ca5e66f14..6939b0d6d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1151,7 +1151,6 @@ procedure TMainForm.FormCreate(Sender: TObject); // load configfile isStartup := False; CollectLanguagesFromFiles; - LoadFormInformation; LoadMangaOptions; LoadOptions; ApplyOptions; @@ -1274,7 +1273,10 @@ procedure TMainForm.FormDestroy(Sender: TObject); procedure TMainForm.FormShow(Sender: TObject); begin if not isStartup then + begin + LoadFormInformation; itStartup.Enabled := True; + end; end; procedure TMainForm.cbOptionUseProxyChange(Sender: TObject); From c766a6d815cceca32623d693179888215b728bca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:07:23 +0800 Subject: [PATCH 1128/2794] removed mangaeden/perveden old code --- .../MangaEden/chapter_page_number.inc | 40 ----- .../MangaEden/directory_page_number.inc | 36 ----- baseunits/includes/MangaEden/image_url.inc | 36 ----- .../includes/MangaEden/manga_information.inc | 134 ----------------- .../includes/MangaEden/names_and_links.inc | 38 ----- baseunits/uBaseUnit.pas | 142 ++++++++---------- baseunits/uData.pas | 24 --- baseunits/uDownloadsManager.pas | 12 -- baseunits/uUpdateThread.pas | 17 +-- 9 files changed, 67 insertions(+), 412 deletions(-) delete mode 100644 baseunits/includes/MangaEden/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaEden/directory_page_number.inc delete mode 100644 baseunits/includes/MangaEden/image_url.inc delete mode 100644 baseunits/includes/MangaEden/manga_information.inc delete mode 100644 baseunits/includes/MangaEden/names_and_links.inc diff --git a/baseunits/includes/MangaEden/chapter_page_number.inc b/baseunits/includes/MangaEden/chapter_page_number.inc deleted file mode 100644 index f8a7cc2da..000000000 --- a/baseunits/includes/MangaEden/chapter_page_number.inc +++ /dev/null @@ -1,40 +0,0 @@ - function GetMangaEdenPageNumber: Boolean; - var - s: String; - i, j: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - if manager.container.MangaSiteID = MANGAEDEN_ID then - s := FillMangaSiteHost(MANGAEDEN_ID, URL) + '1/' - else - s := FillMangaSiteHost(PERVEDEN_ID, URL) + '1/'; - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - if (Pos('<select', parse[i]) > 0) and - (GetVal(parse[i], 'id') = 'pageSelect') then - begin - for j := i to parse.Count - 1 do - begin - if Pos('</select', parse[j]) > 0 then - Break - else if Pos('<option', parse[j]) > 0 then - Inc(manager.container.PageNumber); - end; - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaEden/directory_page_number.inc b/baseunits/includes/MangaEden/directory_page_number.inc deleted file mode 100644 index 371881b37..000000000 --- a/baseunits/includes/MangaEden/directory_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetMangaEdenDirectoryPageNumber(const root: String): Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), root + MANGAEDEN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'span') and - (GetVal(parse[i], 'class') = 'next') then - begin - s := TrimRight(TrimLeft(parse[i - 4])); - Page := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/MangaEden/image_url.inc b/baseunits/includes/MangaEden/image_url.inc deleted file mode 100644 index 7f09aa4e7..000000000 --- a/baseunits/includes/MangaEden/image_url.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetMangaEdenImageURL: Boolean; - var - s, imgURL: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - if manager.container.MangaSiteID = MANGAEDEN_ID then - s := FillMangaSiteHost(MANGAEDEN_ID, URL) + IntToStr(workCounter + 1) + '/' - else - s := FillMangaSiteHost(PERVEDEN_ID, URL) + IntToStr(workCounter + 1) + '/'; - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := parse.Count - 1 downto 0 do - if (Pos('"mainImg"', parse[i]) > 0) then - begin - imgURL := GetVal(parse[i], 'src'); - if Copy(imgURL, 1, 2) = '//' then - imgURL := 'http:' + imgURL; - manager.container.PageLinks[workCounter] := imgURL; - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaEden/manga_information.inc b/baseunits/includes/MangaEden/manga_information.inc deleted file mode 100644 index 87078618b..000000000 --- a/baseunits/includes/MangaEden/manga_information.inc +++ /dev/null @@ -1,134 +0,0 @@ - function GetMangaEdenInfoFromURL(const root: String): Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - if Pos('http', LowerCase(URL)) = 0 then - mangaInfo.url := root + URL;// + '&confirm=yes'; - if Pos('/en-manga/', URL) > 0 then - mangaInfo.genres := 'English, ' - else - mangaInfo.genres := 'Italian, '; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - if root = WebsiteRoots[MANGAEDEN_ID, 1] then - mangaInfo.website := WebsiteRoots[MANGAEDEN_ID, 0] - else - mangaInfo.website := WebsiteRoots[PERVEDEN_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse[i]) = 'div') and - (Pos('class="mangaImage2"', parse[i]) > 0) then - begin - mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 1], 'src')); - if Copy(mangaInfo.coverLink, 1, 2) = '//' then - mangaInfo.coverLink := 'http:' + mangaInfo.coverLink; - end; - - // get summary - if (Pos('hr style="margin-top:0;', parse[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 2; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if ((Pos('enIcon', parse[i]) <> 0) or (Pos('itIcon', parse[i]) <> 0)) and - (mangaInfo.title = '') then - begin - mangaInfo.title := StringFilter(TrimRight(TrimLeft(parse[i + 1]))); - mangaInfo.title := GetString('~!@' + mangaInfo.title, '~!@', ' Manga'); - end; - - // get chapter name and links - if (i + 7 < parse.Count) and (Pos('class="chapterLink"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse[i], 'href="', '1/"'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 3]))) + - ' ' + RemoveSymbols(TrimLeft(TrimRight(parse[i + 7]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 1 < parse.Count) and (Pos('/?author', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse[i + 1]); - - // get artists - if (i + 1 < parse.Count) and (Pos('/?artist', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse[i + 1]); - - // get genres - if (Pos('Genres', parse[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('/?categories', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse[i + 1])) + ', '; - if Pos('<br />', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if parse[i] = 'Status' then - begin - if Pos('Ongoing', parse[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaEden/names_and_links.inc b/baseunits/includes/MangaEden/names_and_links.inc deleted file mode 100644 index 5cc8f82f0..000000000 --- a/baseunits/includes/MangaEden/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function MangaEdenGetNamesAndLinks(const root: String): Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), root + MANGAEDEN_BROWSER + '?page=' + - IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if ((Pos('class="openManga"', parse[i]) > 0) or - (Pos('class="closedManga"', parse[i]) > 0)) then - begin - Result := NO_ERROR; - s := TrimLeft(TrimRight(StringFilter(parse[i + 1]))); - names.Add(s); - links.Add(StringReplace(GetVal(parse[i], 'href'), root, '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a3090c96f..2bb16f462 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -239,72 +239,70 @@ interface TRUYEN18_ID = 6; MANGAPARK_ID = 7; MANGATRADERS_ID = 8; - MANGAEDEN_ID = 9; - PERVEDEN_ID = 10; - TRUYENTRANHTUAN_ID = 11; - TURKCRAFT_ID = 12; - MANGAVADISI_ID = 13; - MANGAFRAME_ID = 14; - EATMANGA_ID = 15; - STARKANA_ID = 16; - BLOGTRUYEN_ID = 17; - KOMIKID_ID = 18; - ESMANGAHERE_ID = 19; - ANIMEEXTREMIST_ID = 20; - HUGEMANGA_ID = 21; - S2SCAN_ID = 22; - IMANHUA_ID = 23; - MABUNS_ID = 24; - MANGAESTA_ID = 25; - CENTRALDEMANGAS_ID = 26; - EGSCANS_ID = 27; - MANGAAR_ID = 28; - MANGAAE_ID = 29; - ANIMESTORY_ID = 30; - LECTUREENLIGNE_ID = 31; - SCANMANGA_ID = 32; - MANGAGO_ID = 33; - DM5_ID = 34; - MANGACOW_ID = 35; - KIVMANGA_ID = 36; - MEINMANGA_ID = 37; - MANGASPROJECT_ID = 38; - MANGAREADER_POR_ID = 39; - NINEMANGA_ID = 40; - NINEMANGA_ES_ID = 41; - NINEMANGA_CN_ID = 42; - NINEMANGA_RU_ID = 43; - NINEMANGA_DE_ID = 44; - NINEMANGA_IT_ID = 45; - NINEMANGA_BR_ID = 46; - JAPANSHIN_ID = 47; - JAPSCAN_ID = 48; - CENTRUMMANGI_PL_ID = 49; - MANGALIB_PL_ID = 50; - ONEMANGA_ID = 51; - MANGATOWN_ID = 52; - MANGAOKU_ID = 53; - MYREADINGMANGAINFO_ID = 54; - IKOMIK_ID = 55; - NHENTAI_ID = 56; - MANGAMINT_ID = 57; - UNIXMANGA_ID = 58; - EXTREMEMANGAS_ID = 59; - MANGAHOST_ID = 60; - PORNCOMIX_ID = 61; - PORNCOMIXRE_ID = 62; - PORNCOMIXIC_ID = 63; - XXCOMICS_ID = 64; - XXCOMICSMT_ID = 65; - XXCOMICS3D_ID = 66; - PORNXXXCOMICS_ID = 67; - MANGASEE_ID = 68; - MANGAKU_ID = 69; - MANGAAT_ID = 70; - READMANGATODAY_ID = 71; - DYNASTYSCANS_ID = 72; - - WebsiteRoots: array [0..72] of array [0..1] of String = ( + TRUYENTRANHTUAN_ID = 9; + TURKCRAFT_ID = 10; + MANGAVADISI_ID = 11; + MANGAFRAME_ID = 12; + EATMANGA_ID = 13; + STARKANA_ID = 14; + BLOGTRUYEN_ID = 15; + KOMIKID_ID = 16; + ESMANGAHERE_ID = 17; + ANIMEEXTREMIST_ID = 18; + HUGEMANGA_ID = 19; + S2SCAN_ID = 20; + IMANHUA_ID = 21; + MABUNS_ID = 22; + MANGAESTA_ID = 23; + CENTRALDEMANGAS_ID = 24; + EGSCANS_ID = 25; + MANGAAR_ID = 26; + MANGAAE_ID = 27; + ANIMESTORY_ID = 28; + LECTUREENLIGNE_ID = 29; + SCANMANGA_ID = 30; + MANGAGO_ID = 31; + DM5_ID = 32; + MANGACOW_ID = 33; + KIVMANGA_ID = 34; + MEINMANGA_ID = 35; + MANGASPROJECT_ID = 36; + MANGAREADER_POR_ID = 37; + NINEMANGA_ID = 38; + NINEMANGA_ES_ID = 39; + NINEMANGA_CN_ID = 40; + NINEMANGA_RU_ID = 41; + NINEMANGA_DE_ID = 42; + NINEMANGA_IT_ID = 43; + NINEMANGA_BR_ID = 44; + JAPANSHIN_ID = 45; + JAPSCAN_ID = 46; + CENTRUMMANGI_PL_ID = 47; + MANGALIB_PL_ID = 48; + ONEMANGA_ID = 49; + MANGATOWN_ID = 50; + MANGAOKU_ID = 51; + MYREADINGMANGAINFO_ID = 52; + IKOMIK_ID = 53; + NHENTAI_ID = 54; + MANGAMINT_ID = 55; + UNIXMANGA_ID = 56; + EXTREMEMANGAS_ID = 57; + MANGAHOST_ID = 58; + PORNCOMIX_ID = 59; + PORNCOMIXRE_ID = 60; + PORNCOMIXIC_ID = 61; + XXCOMICS_ID = 62; + XXCOMICSMT_ID = 63; + XXCOMICS3D_ID = 64; + PORNXXXCOMICS_ID = 65; + MANGASEE_ID = 66; + MANGAKU_ID = 67; + MANGAAT_ID = 68; + READMANGATODAY_ID = 69; + DYNASTYSCANS_ID = 70; + + WebsiteRoots: array [0..70] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -314,8 +312,6 @@ interface ('Truyen18', 'http://www.truyen18.org'), ('MangaPark', 'http://mangapark.me'), ('MangaTraders', 'http://mangatraders.org'), - ('MangaEden', 'http://www.mangaeden.com'), - ('PervEden', 'http://www.perveden.com'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), ('MangaVadisi', 'http://www.mangavadisi.net'), @@ -401,12 +397,6 @@ interface MANGATRADERS_BROWSER = '/directory/'; - MANGAEDEN_BROWSER_1 = '/en-directory/'; - MANGAEDEN_BROWSER_2 = '/it-directory/'; - - PERVEDEN_BROWSER_1 = '/en-directory/'; - PERVEDEN_BROWSER_2 = '/it-directory/'; - TRUYENTRANHTUAN_BROWSER = '/danh-sach-truyen'; TURKCRAFT_BROWSER = '/'; @@ -504,10 +494,6 @@ interface FAKKU_BROWSER: String = '/manga/newest'; - MANGAEDEN_BROWSER: String = '/en-directory/'; - - PERVEDEN_BROWSER: String = '/en-directory/'; - MANGALIB_PL_COOKIES: String; //------------------------------------------ diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b37c8ee61..77d63e82b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -783,8 +783,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/MangaGo/directory_page_number.inc} - {$I includes/MangaEden/directory_page_number.inc} - {$I includes/BlogTruyen/directory_page_number.inc} {$I includes/S2Scans/directory_page_number.inc} @@ -875,12 +873,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St if WebsiteID = MANGAGO_ID then Result := GetMangaGoDirectoryPageNumber else - if WebsiteID = MANGAEDEN_ID then - Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[MANGAEDEN_ID, 1]) - else - if WebsiteID = PERVEDEN_ID then - Result := GetMangaEdenDirectoryPageNumber(WebsiteRoots[PERVEDEN_ID, 1]) - else if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenDirectoryPageNumber else @@ -1040,8 +1032,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/BlogTruyen/names_and_links.inc} - {$I includes/MangaEden/names_and_links.inc} - {$I includes/Kivmanga/names_and_links.inc} {$I includes/MeinManga/names_and_links.inc} @@ -1140,12 +1130,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = EGSCANS_ID then Result := EGScansGetNamesAndLinks else - if WebsiteID = MANGAEDEN_ID then - Result := MangaEdenGetNamesAndLinks(WebsiteRoots[MANGAEDEN_ID, 1]) - else - if WebsiteID = PERVEDEN_ID then - Result := MangaEdenGetNamesAndLinks(WebsiteRoots[PERVEDEN_ID, 1]) - else if WebsiteID = MEINMANGA_ID then Result := MeinMangaGetNamesAndLinks else @@ -1331,8 +1315,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/MangaTraders/manga_information.inc} - {$I includes/MangaEden/manga_information.inc} - {$I includes/Starkana/manga_information.inc} {$I includes/EatManga/manga_information.inc} @@ -1490,12 +1472,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = TRUYENTRANHTUAN_ID then Result := GetTruyenTranhTuanInfoFromURL else - if WebsiteID = MANGAEDEN_ID then - Result := GetMangaEdenInfoFromURL(WebsiteRoots[MANGAEDEN_ID, 1]) - else - if WebsiteID = PERVEDEN_ID then - Result := GetMangaEdenInfoFromURL(WebsiteRoots[PERVEDEN_ID, 1]) - else if WebsiteID = MEINMANGA_ID then Result := GetMeinMangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 277d83640..93e1ffcbc 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -393,8 +393,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Mangacow/chapter_page_number.inc} - {$I includes/MangaEden/chapter_page_number.inc} - {$I includes/MangaFrame/chapter_page_number.inc} {$I includes/MangaGo/chapter_page_number.inc} @@ -526,10 +524,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = MANGACOW_ID then Result := GetMangaCowPageNumber else - if (manager.container.MangaSiteID = MANGAEDEN_ID) or - (manager.container.MangaSiteID = PERVEDEN_ID) then - Result := GetMangaEdenPageNumber - else if manager.container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else @@ -651,8 +645,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Mangacow/image_url.inc} - {$I includes/MangaEden/image_url.inc} - {$I includes/MangaEsta/image_url.inc} {$I includes/MangaFrame/image_url.inc} @@ -809,10 +801,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenImageURL else - if (manager.container.MangaSiteID = MANGAEDEN_ID) or - (manager.container.MangaSiteID = PERVEDEN_ID) then - Result := GetMangaEdenImageURL - else if manager.container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaImageURL else diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index a464ea111..8f4560679 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -137,17 +137,12 @@ procedure TUpdateListThread.Execute; end; end else - if SitesMemberOf(manager.website, - [FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then + if manager.website = WebsiteRoots[FAKKU_ID, 0] then begin FAKKU_BROWSER := FAKKU_BROWSER_1; - MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_1; - PERVEDEN_BROWSER := PERVEDEN_BROWSER_1; info.GetDirectoryPage(manager.directoryCount, manager.website); FAKKU_BROWSER := FAKKU_BROWSER_2; - MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_2; - PERVEDEN_BROWSER := PERVEDEN_BROWSER_2; info.GetDirectoryPage(manager.directoryCount2, manager.website); end else @@ -172,22 +167,17 @@ procedure TUpdateListThread.Execute; if checkStyle = CS_DIRECTORY_PAGE_2 then workPtr := manager.directoryCount2 - workPtr - 1; end; - if SitesMemberOf(manager.website, - [FAKKU_ID, MANGAEDEN_ID, PERVEDEN_ID]) then + if manager.website = WebsiteRoots[FAKKU_ID, 0] then begin if checkStyle = CS_DIRECTORY_PAGE then begin FAKKU_BROWSER := FAKKU_BROWSER_1; - MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_1; - PERVEDEN_BROWSER := PERVEDEN_BROWSER_1; Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); end else if checkStyle = CS_DIRECTORY_PAGE_2 then begin FAKKU_BROWSER := FAKKU_BROWSER_2; - MANGAEDEN_BROWSER := MANGAEDEN_BROWSER_2; - PERVEDEN_BROWSER := PERVEDEN_BROWSER_2; Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); end; end @@ -642,8 +632,7 @@ procedure TUpdateListManagerThread.Execute; end; end else - if SitesMemberOf(website, [FAKKU_ID, MANGAEDEN_ID, - PERVEDEN_ID]) then + if website = WebsiteRoots[FAKKU_ID, 0] then begin if directoryCount = 0 then directoryCount := 1; From b9c3e440564538cc25badb2946519013ef9b8f55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:26:17 +0800 Subject: [PATCH 1129/2794] added mangaeden/perveden modules fixed #230 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaEden.pas | 205 ++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaEden.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 4c68ff0b1..b06d0ace8 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -32,4 +32,5 @@ uses SubManga, MangaBackup, Hentai2Read, - Tumangaonline; + Tumangaonline, + MangaEden; diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas new file mode 100644 index 000000000..76f97261b --- /dev/null +++ b/baseunits/modules/MangaEden.pas @@ -0,0 +1,205 @@ +unit MangaEden; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurls: array[0..1] of String = ( + '/en/en-directory/', + '/en/it-directory/' + ); + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//*[@class="pagination pagination_bottom"]/a[last()-1]'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex]; + if AURL <> '0' then + s := s + '?page=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//table[@id="mangaList"]//tr/td[1]/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//*[starts-with(@class,"mangaImage")]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//*[@class="manga-title"]'); + authors := XPathStringAll('//*[@class="rightBox"]/a[contains(@href,"/?author=")]'); + artists := XPathStringAll('//*[@class="rightBox"]/a[contains(@href,"/?artist=")]'); + genres := XPathStringAll('//*[@class="rightBox"]/a[contains(@href,"/?categories")]'); + summary := XPathString('//*[@id="mangaDescription"]'); + s := CleanString(XPathString('//*[@class="rightBox"]')); + AddCommaString(genres, Trim(GetBetween('Type ', ' Status', s))); + s := AnsiLowerCase(s); + if Pos('status ongoing', s) > 0 then + status := '1' + else if Pos('status completed', s) > 0 then + status := '0'; + for v in XPath('//table//tr/td/a[@class="chapterLink"]') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathStringAll('*', ' ', v.toNode)); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + s, idManga, idCapitulo: String; + source: TStringList; + i: Integer; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin + Result := True; + + s := ''; + source := TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do + if Pos('var pages = ', source[i]) > 0 then + begin + s := source[i]; + s := GetBetween('[', ']', s); + if s <> '' then + s := '[' + s + ']'; + Break; + end; + finally + source.Free; + end; + + with TXQueryEngineHTML.Create do + try + if s <> '' then + begin + ParseHTML(s); + PageLinks.AddText(XPathStringAll('json(*)()("fs")', LineEnding)); + end; + + if PageLinks.Count = 0 then + begin + ParseHTML(Document); + PageNumber := XPath('//select[@id="pageSelect"]/option').Count; + end; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + s := RemoveURLDelim(AURL); + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 1); + with DownloadThread.manager.container, DownloadThread.FHTTP do begin + s := AppendURLDelim(s) + IncStr(DownloadThread.workCounter) + '/'; + if GET(FillHost(Module.RootURL, s)) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := + XPathString('//img[@id="mainImg"]/@src'); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; + + procedure AddWebsiteModule(const AWebsite, ARootURL: String); + begin + with AddModule do begin + Website := AWebsite; + RootURL := ARootURL; + TotalDirectory := Length(dirurls); + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + end; + +begin + AddWebsiteModule('MangaEden', 'http://www.mangaeden.com'); + AddWebsiteModule('PervEden', 'http://www.perveden.com'); +end; + +initialization + RegisterModule; + +end. From 8a813d0d24291a72d3cc00a9371b1a17c6bc7f22 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:31:37 +0800 Subject: [PATCH 1130/2794] mangaeden, cleanup --- baseunits/modules/MangaEden.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index 76f97261b..5d25d077f 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -102,10 +102,9 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - s, idManga, idCapitulo: String; + s: String; source: TStringList; i: Integer; - v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; From b3f2563a6fa5ab0a7623ca6a79638c88410ec328 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:32:03 +0800 Subject: [PATCH 1131/2794] mangahere, fixed genres fixed #231 --- baseunits/modules/MangaHere.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 1f436b764..c7f9eec65 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -76,7 +76,7 @@ function GetInfo(const MangaInfo: TMangaInformation; s := v.toString; if Pos('Author(s):', s) = 1 then authors := SeparateRight(s, ':') else if Pos('Artist(s):', s) = 1 then artists := SeparateRight(s, ':') - else if Pos('Genre(s):', s) = 1 then artists := SeparateRight(s, ':') + else if Pos('Genre(s):', s) = 1 then genres := SeparateRight(s, ':') else if Pos('Status:', s) = 1 then begin if Pos('Ongoing', s) > 0 then status := '1' else status := '0'; From 9970b52308af3a30ff3ace20c5cdee0cca00ff04 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:32:25 +0800 Subject: [PATCH 1132/2794] mangahere, fixed root url --- baseunits/modules/MangaHere.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index c7f9eec65..08597ada9 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -170,7 +170,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaHere'; - RootURL := 'http://www.mangahere.co/'; + RootURL := 'http://www.mangahere.co'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From bd0aecfeb64dee8e35e18edd5cb666940a1e9995 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:36:28 +0800 Subject: [PATCH 1133/2794] tinifilerun, secure copyfile insed tryexcept --- baseunits/FMDOptions.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 0f61f25e2..f5f7d664b 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -149,7 +149,10 @@ procedure TIniFileRun.UpdateFile; begin if CacheUpdates and (Dirty = False) then Exit; inherited UpdateFile; - CopyFile(FileName, FRealFileName, [cffOverwriteFile, cffPreserveTime, cffCreateDestDirectory]); + try + CopyFile(FileName, FRealFileName, [cffOverwriteFile, cffPreserveTime, cffCreateDestDirectory]); + except + end; end; procedure FreeNil(var Obj); From 4136635496f31e4be07bd5a65d51e47f2bd15f66 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:41:18 +0800 Subject: [PATCH 1134/2794] hentai2read, fixed update list fixed #233 --- baseunits/modules/Hentai2Read.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 37318b9ab..94dadfcc0 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -51,7 +51,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//a[@class="mangaPopover"]') do + for v in XPath('//*[@class="img-overlay text-center"]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); From 681749ef156b57fdce78c60fb88e75a2d147cef7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 13 Apr 2016 21:55:49 +0800 Subject: [PATCH 1135/2794] Bump version 0.9.51.0 --- changelog.txt | 8 ++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 67c16af78..0e9ca3997 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.51.0 (13-04-2016) +[*] Fixed restore window position +[*] MangaEden/PerEven: rewrite all script +[*] MangaHere: fixed missing genres +[*] Hentai2Read: fixed update list +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.50.0...0.9.51.0 + 0.9.50.0 (11-04-2016) [*] Added GoManga[EN] [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b4b671f77..5c4ca2f8d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="50"/> + <RevisionNr Value="51"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index c9c27a8bf..382d83eac 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.50.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.50.0/fmd_0.9.50.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.50.0/fmd_0.9.50.0_Win64.7z +VERSION=0.9.51.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.51.0/fmd_0.9.51.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.51.0/fmd_0.9.51.0_Win64.7z From ad91c207d9b2596dcd729a11440eea6a24bcf4b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 3 May 2016 17:55:46 +0800 Subject: [PATCH 1136/2794] added heymanga close #237 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/HeyMangaXyz.pas | 176 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/HeyMangaXyz.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index b06d0ace8..bbbf81f96 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -33,4 +33,5 @@ uses MangaBackup, Hentai2Read, Tumangaonline, - MangaEden; + MangaEden, + HeyMangaXyz; diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas new file mode 100644 index 000000000..4393ef6d6 --- /dev/null +++ b/baseunits/modules/HeyMangaXyz.pas @@ -0,0 +1,176 @@ +unit HeyMangaXyz; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/manga-series/new/'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + page := XPath('//div/a[@class="btn btn-sm btn-icon"]').Count; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="row"]/div/div/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="mangas"]/div[@class="manga"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := SeparateRight(XPathString('//ul[@class="lead"]/li[starts-with(.,"Name: ")]'), ': '); + s := XPathString('//ul[@class="lead"]/li[starts-with(.,"Status: ")]'); + if Pos('Ongoing', s) > 0 then + status := '1' + else if Pos('Completed', s) > 0 then + status := '0'; + genres := XPathStringAll('//ul[@class="lead"]/li[starts-with(.,"Genre: ")]/a'); + summary := SeparateRight(XPathString('//ul[@class="lead"]/li[starts-with(.,"Plot: ")]'), ': '); + for v in XPath('//div[@id="chapters"]/ul//li//a') do + begin + s := v.toNode.getAttribute('href'); + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 1); + chapterLinks.Add(s); + chapterName.Add(v.toString); + end; + if chapterLinks.Count > 0 then + begin + s := XPathString('//div[@id="chapters"]/ul/p[starts-with(.,"Next Chapter:")]/following-sibling::li//a/@href'); + if s <> '' then + begin + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 1); + if SameText(s, chapterLinks[chapterLinks.Count-1]) then + begin + chapterLinks.Delete(chapterLinks.Count - 1); + chapterName.Delete(chapterName.Count - 1); + end; + end; + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL) + '1') then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('//select[@id="page_list"]/option').Count - 1; + for v in XPath('//picture/img') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do + begin + if GET(FillHost(Module.RootURL, AURL) + IncStr(DownloadThread.workCounter)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := XPathString('//picture/img[@id="img-content"]/@src'); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'HeyManga'; + RootURL := 'http://www.heymanga.xyz'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index a67ae7a96..4ae08d043 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 07f203d9bfee1bb7fb003055833bfe633c8a3484 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 7 May 2016 13:50:15 +0800 Subject: [PATCH 1137/2794] hitomila, fixed incorrect update list count --- baseunits/modules/HitomiLa.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 39c75238b..c4a00df01 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -48,7 +48,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); s := Module.RootURL; if AURL <> '0' then - s := s + '/index-all-' + AURL + '.html'; + s := s + '/index-all-' + IncStr(AURL) + '.html'; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do From 439d8592a5e57164e5e96b8860f4e0fda81d21b2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 7 May 2016 14:19:35 +0800 Subject: [PATCH 1138/2794] Bump version 0.9.52.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0e9ca3997..704c55c29 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.52.0 (07-05-2016) +[*] Added HeyManga[EN] +[*] HitomiLa: fixed update list +Full changes: https://github.com/riderkick/FMD/compare/0.9.51.0...0.9.52.0 + 0.9.51.0 (13-04-2016) [*] Fixed restore window position [*] MangaEden/PerEven: rewrite all script diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5c4ca2f8d..c724f4c07 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="51"/> + <RevisionNr Value="52"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 382d83eac..5eb2cee31 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.51.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.51.0/fmd_0.9.51.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.51.0/fmd_0.9.51.0_Win64.7z +VERSION=0.9.52.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.52.0/fmd_0.9.52.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.52.0/fmd_0.9.52.0_Win64.7z From 8ea0b532401e7a6d4ea871dc6c38ecd3408a2363 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 8 May 2016 01:48:52 +0800 Subject: [PATCH 1139/2794] xqueryenginehtml , added xpath and xpathstring --- baseunits/XQueryEngineHTML.pas | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 9986f5486..f7de3ddaa 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -41,6 +41,11 @@ TXQueryEngineHTML = class IXQValue = xquery.IXQValue; TTreeNode = simplehtmltreeparser.TTreeNode; + function XPath(const Expression, HTMLString: String): IXQValue; overload; + function XPath(const Expression: String; const HTMLStream: TStream): IXQValue; overload; + function XPathString(const Expression, HTMLString: String): String; overload; + function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; + implementation function StreamToString(const Stream: TStream): String; @@ -76,6 +81,32 @@ function StringInArray(const S: String; const SS: array of String): Boolean; Result := False; end; +function XPath(const Expression, HTMLString: String): IXQValue; +begin + Result := xqvalue(); + with TXQueryEngineHTML.Create(HTMLString) do + try + Result := XPath(Expression); + finally + Free; + end; +end; + +function XPath(const Expression: String; const HTMLStream: TStream): IXQValue; +begin + Result := XPath(Expression, StreamToString(HTMLStream)); +end; + +function XPathString(const Expression, HTMLString: String): String; +begin + Result := XPath(Expression, HTMLString).toString; +end; + +function XPathString(const Expression: String; const HTMLStream: TStream): String; +begin + Result := XPathString(Expression, StreamToString(HTMLStream)); +end; + { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; From e1b8e1316ccff03acd385ec54ed7e5245528a7b8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 8 May 2016 02:03:04 +0800 Subject: [PATCH 1140/2794] tsumino, fixed update list fixed #241 --- baseunits/modules/Tsumino.pas | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index 3ad808208..b7e867c94 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -11,7 +11,11 @@ interface implementation const - dirurl = '/Browse/Index/1/'; + //dirurl = '/Browse/Index/1/'; + // '/?pageNumber=532&RawSearch=&SortOptions=Newest&PageMinimum=1&PageMaximum=10000&RateMinimum=0&RateMaximum=5' + dirurl = '/Browse/Query'; + dirurldata = 'pageNumber='; + dirurldataend = '&RawSearch=&SortOptions=Newest&PageMinimum=1&PageMaximum=10000&RateMinimum=0&RateMaximum=5'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -19,14 +23,10 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '10000000') then begin + if MangaInfo.FHTTP.POST(Module.RootURL + dirurl, dirurldata + '1' + dirurldataend) then + begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - page := StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'), 1); - finally - Free; - end; + Page := StrToIntDef(XPathString('json(*)("PageCount")', MangaInfo.FHTTP.Document), 1); end; end; @@ -39,15 +39,20 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL; - if AURL <> '0' then s := s + dirurl + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then begin + if MangaInfo.FHTTP.POST(Module.RootURL + dirurl, + dirurldata + IncStr(AURL) + dirurldataend) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//div[@class="row row-no-padding"]//div[@class="overlay"]') do begin - ALinks.Add(XPathString('a/@href', v.toNode)); - ANames.Add(XPathString('div/div[@class="overlay-title"]', v.toNode)); + s := XPathString('json(*)("Data")'); + if s <> '' then + begin + ParseHTML(s); + for v in XPath('//div[@class="overlay"]/a/@href') do + ALinks.Add(v.toString); + for v in XPath('//div[@class="overlay"]/div[@class="overlay-data"]/div[@class="overlay-title"]') do + ANames.Add(v.toString); end; finally Free; From 75f23f211fd7a8a3b1e1dc7dba1b43da768d76be Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 8 May 2016 02:10:27 +0800 Subject: [PATCH 1141/2794] Bump version 0.9.53.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 704c55c29..3413e2199 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.53.0 (08-05-2016) +[*] Tsumino: fixed update list +Full changes: https://github.com/riderkick/FMD/compare/0.9.52.0...0.9.53.0 + 0.9.52.0 (07-05-2016) [*] Added HeyManga[EN] [*] HitomiLa: fixed update list diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c724f4c07..4dd7b47dc 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="52"/> + <RevisionNr Value="53"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5eb2cee31..923b1dd42 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.52.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.52.0/fmd_0.9.52.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.52.0/fmd_0.9.52.0_Win64.7z +VERSION=0.9.53.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.53.0/fmd_0.9.53.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.53.0/fmd_0.9.53.0_Win64.7z From 4bfd9b325065521590e1828127fabe3cf2ce5c75 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 04:28:37 +0800 Subject: [PATCH 1142/2794] xqueryenginehtml, remove xpath, unsafe interface return --- baseunits/XQueryEngineHTML.pas | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index f7de3ddaa..f491283db 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -41,8 +41,6 @@ TXQueryEngineHTML = class IXQValue = xquery.IXQValue; TTreeNode = simplehtmltreeparser.TTreeNode; - function XPath(const Expression, HTMLString: String): IXQValue; overload; - function XPath(const Expression: String; const HTMLStream: TStream): IXQValue; overload; function XPathString(const Expression, HTMLString: String): String; overload; function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; @@ -81,27 +79,17 @@ function StringInArray(const S: String; const SS: array of String): Boolean; Result := False; end; -function XPath(const Expression, HTMLString: String): IXQValue; +function XPathString(const Expression, HTMLString: String): String; begin - Result := xqvalue(); + Result := ''; with TXQueryEngineHTML.Create(HTMLString) do try - Result := XPath(Expression); + Result := XPath(Expression).toString; finally Free; end; end; -function XPath(const Expression: String; const HTMLStream: TStream): IXQValue; -begin - Result := XPath(Expression, StreamToString(HTMLStream)); -end; - -function XPathString(const Expression, HTMLString: String): String; -begin - Result := XPath(Expression, HTMLString).toString; -end; - function XPathString(const Expression: String; const HTMLStream: TStream): String; begin Result := XPathString(Expression, StreamToString(HTMLStream)); From a7b64fd7d4a0c8aab48b385f8b8d01ddb003064c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 04:50:10 +0800 Subject: [PATCH 1143/2794] manga-tr, fixed get image url fixed #242 --- baseunits/modules/MangaTr.pas | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index d98ecf756..04b9239cc 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -92,6 +92,8 @@ function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; AHTTP.Reset; if AHTTP.GET(AURL) then begin if AHTTP.Cookies.Values['PHPSESSID'] <> '' then begin + // allpage = 1; perpage = 2 + AHTTP.Cookies.Values['read_type'] := '1'; mangatrcookie := AHTTP.GetCookies; AHTTP.Reset; AHTTP.Headers.Values['Referer'] := ' ' + AURL; @@ -104,7 +106,6 @@ function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - query: TXQueryEngineHTML; v: IXQValue; begin Result := False; @@ -115,16 +116,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - for v in query.XPath('//div[@class="chapter-content"]/select[2]/option') do - if StrToIntDef(v.toString, 0) > 0 then - PageContainerLinks.Add(v.toNode.getAttribute('value')); - PageNumber := PageContainerLinks.Count; - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@class="chapter-content"]//img[@class="chapter-img"]/@src') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)); + finally + Free; + end; end; end; end; From eafe0a17a6c79331429f0b67f74d0798879a80e9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 05:06:13 +0800 Subject: [PATCH 1144/2794] mangatr, fixed title and thumbnail --- baseunits/modules/MangaTr.pas | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index 04b9239cc..e4b69a1a3 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; + XQueryEngineHTML, httpsendthread, synautil; implementation @@ -54,8 +54,12 @@ function GetInfo(const MangaInfo: TMangaInformation; try query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); with MangaInfo.mangaInfo, query do begin - coverLink := XPathString('//img[@class="thumbnail"]/@src'); + coverLink := XPathString('//img[starts-with(@class,"thumbnail")]/@src'); if coverLink <> '' then coverLink := FillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//title'); + if title <> '' then + if Pos(' Manga - Oku ', title) > 0 then + title := SeparateLeft(title, ' Manga - Oku '); if title = '' then title := XPathString('//h1'); authors := XPathString('//table[2]/tbody/tr[2]/td[1]'); artists := XPathString('//table[2]/tbody/tr[2]/td[2]'); From 2f58de9f9a9ea90f41e318b2b26228576bda3029 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 05:25:44 +0800 Subject: [PATCH 1145/2794] mangatr, fix manga info --- baseunits/modules/MangaTr.pas | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index e4b69a1a3..7c1700365 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -41,19 +41,17 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; i: Integer; + s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); MangaInfo.mangaInfo.website := Module.Website; if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - with MangaInfo.mangaInfo, query do begin + with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try coverLink := XPathString('//img[starts-with(@class,"thumbnail")]/@src'); if coverLink <> '' then coverLink := FillHost(Module.RootURL, coverLink); if title = '' then title := XPathString('//title'); @@ -61,21 +59,27 @@ function GetInfo(const MangaInfo: TMangaInformation; if Pos(' Manga - Oku ', title) > 0 then title := SeparateLeft(title, ' Manga - Oku '); if title = '' then title := XPathString('//h1'); - authors := XPathString('//table[2]/tbody/tr[2]/td[1]'); - artists := XPathString('//table[2]/tbody/tr[2]/td[2]'); - genres := TrimRightChar(Trim(XPathString('//table[2]/tbody/tr[2]/td[3]')), [',']); + if Pos('Yazar', XPathString('//table[1]/tbody/tr[1]/td[1]')) > 0 then + s := '//table[1]/tbody/tr[2]' + else + s := '//table[2]/tbody/tr[2]/'; + authors := XPathString(s + '/td[1]'); + artists := XPathString(s + '/td[2]'); + genres := TrimRightChar(Trim(XPathString(s + '/td[3]')), [',']); summary := XPathString('//div[@class="well"]/p'); v := XPath('//table[4]/tbody/tr/td/a'); if v.Count = 0 then v := XPath('//table[3]/tbody/tr/td/a'); if v.Count > 0 then + begin for i := 1 to v.Count do begin chapterLinks.Add(v.get(i).toNode.getAttribute('href')); chapterName.Add(v.get(i).toString); end; + InvertStrings([chapterLinks, chapterName]); + end; + finally + Free; end; - finally - query.Free; - end; end; end; From c060a255102e3ffb0ef1693a8e110356625b4770 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 08:02:21 +0800 Subject: [PATCH 1146/2794] baseunit, faster fillhost and maybefillhost --- baseunits/uBaseUnit.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2bb16f462..e85d81d80 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1219,6 +1219,12 @@ function FillHost(const Host, URL: String): String; begin Result := CleanURL(URL); if Host = '' then Exit; + if Pos(Host, URL) = 1 then Exit; + if Pos('://', URL) = 0 then + begin + Result := RemoveURLDelim(Host) + AppendURLDelimLeft(Result); + Exit; + end; with TRegExpr.Create do try Expression := REGEX_HOST; @@ -1237,6 +1243,12 @@ function MaybeFillHost(const Host, URL: String): String; Result := CleanURL(URL); if Host = '' then Exit; if URL = '' then Exit; + if Pos(Host, URL) = 1 then Exit; + if Pos('://', URL) = 0 then + begin + Result := RemoveURLDelim(Host) + AppendURLDelimLeft(Result); + Exit; + end; with TRegExpr.Create do try Expression := REGEX_HOST; From 8e2130e4b7f912497b84c1c5a6e6062287f55ba4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 08:38:55 +0800 Subject: [PATCH 1147/2794] added puzzmos #242 --- baseunits/modules/MangaTr.pas | 150 +++++++++++++++++++++++----------- config/mangalist.ini | 2 +- 2 files changed, 103 insertions(+), 49 deletions(-) diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index 7c1700365..924c32bbe 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -12,29 +12,38 @@ implementation var mangatrcookie: String = ''; + puzzmoscookie: String = ''; + +const + mangatrdirurl = '/manga-list.html?listType=allABC'; + puzzmosdirurl = '/directory?type=text'; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; + s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list.html') then begin + s := Module.RootURL; + if Module.Website = 'Manga-Tr' then + s := s + mangatrdirurl + else if Module.Website = 'Puzzmos' then + s := s + puzzmosdirurl; + if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//span[starts-with(@class, "manga")]//a') do - begin - ANames.Add(v.toString); - ALinks.Add(v.toNode.getAttribute('href')); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//span[starts-with(@class, "manga")]//a') do + begin + ANames.Add(v.toString); + ALinks.Add(v.toNode.getAttribute('href')); + end; + finally + Free; end; - finally - query.Free; - end; end; end; @@ -56,8 +65,12 @@ function GetInfo(const MangaInfo: TMangaInformation; if coverLink <> '' then coverLink := FillHost(Module.RootURL, coverLink); if title = '' then title := XPathString('//title'); if title <> '' then + begin if Pos(' Manga - Oku ', title) > 0 then - title := SeparateLeft(title, ' Manga - Oku '); + title := SeparateLeft(title, ' Manga - Oku ') + else if Pos(' Mangasını Oku ', title) > 0 then + title := SeparateLeft(title, ' Mangasını Oku '); + end; if title = '' then title := XPathString('//h1'); if Pos('Yazar', XPathString('//table[1]/tbody/tr[1]/td[1]')) > 0 then s := '//table[1]/tbody/tr[2]' @@ -83,29 +96,49 @@ function GetInfo(const MangaInfo: TMangaInformation; end; end; -function GETWithCookie(const AHTTP: THTTPSendThread; AURL: String): Boolean; +function GETWithCookie(const AHTTP: THTTPSendThread; + const AURL: String; + const Module: TModuleContainer; + const usePOST: Boolean = False; + const POSTData: String = ''): Boolean; var - s: String; + iurl, s: String; + ccookie: PString; begin Result := False; - if mangatrcookie <> '' then begin - AHTTP.Cookies.Text := mangatrcookie; - if AHTTP.GET(AURL) then begin + if Module.Website = 'Manga-Tr' then + ccookie := @mangatrcookie + else if Module.Website = 'Puzzmos' then + ccookie := @puzzmoscookie; + iurl := MaybeFillHost(Module.RootURL, AURL); + if ccookie^ <> '' then + begin + AHTTP.Cookies.Text := ccookie^; + if AHTTP.GET(iurl) then + begin s := StreamToString(AHTTP.Document); if (Pos('class="chapter-content"', s) > 0) or (Pos('class=''chapter-content''', s) > 0) then Result := True; end; end; - if not Result then begin + if not Result then + begin AHTTP.Reset; - if AHTTP.GET(AURL) then begin - if AHTTP.Cookies.Values['PHPSESSID'] <> '' then begin - // allpage = 1; perpage = 2 - AHTTP.Cookies.Values['read_type'] := '1'; - mangatrcookie := AHTTP.GetCookies; + if usePOST then + Result := AHTTP.POST(iurl, POSTData) + else + Result := AHTTP.GET(iurl); + if Result then + begin + if AHTTP.Cookies.Values['PHPSESSID'] <> '' then + begin + // manga-tr allpage = 1; perpage = 2 + if Module.Website = 'Manga-Tr' then + AHTTP.Cookies.Values['read_type'] := '1'; + ccookie^ := AHTTP.GetCookies; AHTTP.Reset; - AHTTP.Headers.Values['Referer'] := ' ' + AURL; - Result := AHTTP.GET(AURL); + AHTTP.Headers.Values['Referer'] := ' ' + iurl; + Result := AHTTP.GET(iurl); end; end; end; @@ -115,6 +148,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var v: IXQValue; + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -122,10 +156,26 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin - Result := True; + //if Module.Website = 'Manga-Tr' then + // Result := GETWithCookie(DownloadThread.FHTTP, AURL, Module) + // puzzmos POST perpage = "sayfadansayfa:" allpage = "altalta:" + //else if Module.Website = 'Puzzmos' then + // Result := GETWithCookie(DownloadThread.FHTTP, AURL, Module, True, 'altalta:'); + Result := GETWithCookie(DownloadThread.FHTTP, AURL, Module); + if Result then + begin with TXQueryEngineHTML.Create(Document) do try + //perpage + if Module.Website = 'Manga-Tr' then + s := '//div[@class="chapter-content"]/select[2]/option' + else if Module.Website = 'Puzzmos' then + s := '(//select)[2]/option'; + for v in XPath(s) do + if Pos('Yorumlar', v.toString) = 0 then + PageContainerLinks.Add(v.toNode.getAttribute('value')); + PageNumber := PageContainerLinks.Count; + //allpage for v in XPath('//div[@class="chapter-content"]//img[@class="chapter-img"]/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)); finally @@ -137,40 +187,44 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.manager.container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + AURL; if DownloadThread.workCounter > PageContainerLinks.Count then Exit; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, - PageContainerLinks[DownloadThread.workCounter])) then begin + if GETWithCookie(DownloadThread.FHTTP, PageContainerLinks[DownloadThread.workCounter], Module) then + begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := - query.XPathString('//div[@class="chapter-content"]//img/@src'); - finally - query.Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.workCounter] := + MaybeFillHost(Module.RootURL, XPathString('//div[@class="chapter-content"]//img/@src')); + finally + Free; + end; end; end; end; procedure RegisterModule; -begin - with AddModule do + + procedure AddWebsiteModule(const AWebsite, ARootURL: String); begin - Website := 'Manga-Tr'; - RootURL := 'http://manga-tr.com'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; + with AddModule do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; end; + +begin + AddWebsiteModule('Manga-Tr', 'http://manga-tr.com'); + AddWebsiteModule('Puzzmos', 'http://puzzmos.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 4ae08d043..836b2fbf8 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -17,6 +17,6 @@ Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga,Tumangaonline Thai=MangaBoom -Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi +Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi,Puzzmos Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D From 356120d6bff3a634eacafad9dc8943915639b433 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 09:33:43 +0800 Subject: [PATCH 1148/2794] added webtoontr #242 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/WebtoonTr.pas | 123 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/WebtoonTr.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index bbbf81f96..a764cc9d7 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -34,4 +34,5 @@ uses Hentai2Read, Tumangaonline, MangaEden, - HeyMangaXyz; + HeyMangaXyz, + WebtoonTr; diff --git a/baseunits/modules/WebtoonTr.pas b/baseunits/modules/WebtoonTr.pas new file mode 100644 index 000000000..0b43707f6 --- /dev/null +++ b/baseunits/modules/WebtoonTr.pas @@ -0,0 +1,123 @@ +unit WebtoonTr; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurls: array[0..2] of String = ( + '/webtoon-listesi', + '/manga-listesi', + '/ero-listesi' + ); + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="list-inline"]/li/div/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="tanitim"]//img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//ul[@class="list-group tanitimdet"]/li[1]'); + s := XPathString('//ul[@class="list-group tanitimdet"]/li[3]'); + if Pos('Devam Ediyor', s) > 0 then + status := '1' + else if Pos('Tamamlandı', s) > 0 then + status := '0'; + authors := SeparateRight(XPathString('//ul[@class="list-group tanitimdet"]/li[5]'), ': '); + summary := XPathString('//ul[@class="list-group tanitimdet"]/li[7]/text'); + for v in XPath('//table[@class="table table-striped table-bordered"]/tbody/tr/td/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@class="images"]/img') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'WebtoonTr'; + RootURL := 'http://webtoontr.com'; + TotalDirectory := Length(dirurls); + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 836b2fbf8..aaaeaa7e1 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -17,6 +17,6 @@ Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga,Tumangaonline Thai=MangaBoom -Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi,Puzzmos +Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D From 2f39b2a87eea92db15a1c19c1e7f46ec40ec5704 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 May 2016 09:49:40 +0800 Subject: [PATCH 1149/2794] Bump version 0.9.54.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3413e2199..4d634760d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.54.0 (09-05-2016) +[*] Manga-Tr: fixed get image url +[+] Added Puzzmos[TR] +[+] Added WebtoonTr[TR] +Full changes: https://github.com/riderkick/FMD/compare/0.9.53.0...0.9.54.0 + 0.9.53.0 (08-05-2016) [*] Tsumino: fixed update list Full changes: https://github.com/riderkick/FMD/compare/0.9.52.0...0.9.53.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 4dd7b47dc..b2f15dcf5 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="53"/> + <RevisionNr Value="54"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 923b1dd42..69c787046 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.53.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.53.0/fmd_0.9.53.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.53.0/fmd_0.9.53.0_Win64.7z +VERSION=0.9.54.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.54.0/fmd_0.9.54.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.54.0/fmd_0.9.54.0_Win64.7z From f8e8644aef0890c92b58c82540198b7bcfabb6f5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 May 2016 17:54:57 +0800 Subject: [PATCH 1150/2794] upacker, use simple tzipper with compression level clnone #245 --- baseunits/uPacker.pas | 44 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 44c3ab0dd..76f6689a1 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -11,7 +11,7 @@ interface uses - Classes, Zipper, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, lazutf8classes, + Classes, Zipper, zstream, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, lazutf8classes, LazFileUtils, SimpleException, uMisc; type @@ -40,39 +40,27 @@ procedure TPacker.FileFound(FileIterator: TFileIterator); procedure TPacker.DoZipCbz; var - Zip: TZipper; - i: Cardinal; - fstream: TFileStreamUTF8; + i: Integer; begin - try - Zip := TZipper.Create; + with TZipper.Create do try - for i := 0 to FFileList.Count - 1 do - begin - Zip.Entries.AddFileEntry(TFileStreamUTF8.Create(FFileList[i], fmOpenRead), - ExtractFileName(FFileList[i])); - end; - if Zip.Entries.Count>0 then begin - fstream := TFileStreamUTF8.Create(FSavedFilename, fmCreate); - try - Zip.SaveToStream(fstream); - finally - fstream.Free; + try + FileName := FSavedFilename; + Entries.AddFileEntries(FFileList); + if Entries.Count > 0 then + for i := 0 to Entries.Count - 1 do + Entries[i].CompressionLevel := clnone; + ZipAllFiles; + except + on E: Exception do + begin + E.Message := 'DoZipCbz.Exception'#13#10 + E.Message; + SimpleException.ExceptionHandleSaveLogOnly(Self, E); end; - for i:=0 to Zip.Entries.Count-1 do - Zip.Entries[i].Stream.Free; - zip.Clear; end; finally - Zip.Free; + Free; end; - except - on E: Exception do - begin - E.Message := 'DoZipCbz.Exception'#13#10 + E.Message; - SimpleException.ExceptionHandleSaveLogOnly(Self, E); - end; - end; end; procedure TPacker.DoPdf; From 799acaa36a3f0ce532f2721725fc928b71efde66 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 18:38:45 +0800 Subject: [PATCH 1151/2794] frmmain, fixed draw progress bar --- mangadownloader/forms/frmMain.pas | 125 ++++++++++++++---------------- 1 file changed, 60 insertions(+), 65 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6939b0d6d..3ae764508 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -712,7 +712,7 @@ TSearchDBThread = class(TThread) CL_BarGreenLine = $25b006; CL_BarGreen = $42d932; - CL_BarOrangLine = $00b399; + CL_BarOrangeLine = $00b399; CL_BarOrange = $1870e9; CL_BarRedLine = $1a1ab1; @@ -3473,81 +3473,76 @@ procedure TMainForm.vtDownloadDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const CellText: String; const CellRect: TRect; var DefaultDraw: Boolean); var - BarRect, ProgressBarRect: TRect; + BarRect: TRect; Percents: double; ww, hh: Integer; begin - if Column = 2 then + if Column <> 2 then Exit; + DefaultDraw := False; + with DLManager.Items[Node^.Index], TargetCanvas do begin - DefaultDraw:=False; - if Node=nil then Exit; - if Node^.Index>=DLManager.Count then Exit; - with DLManager.Items[Node^.Index].DownloadInfo,TargetCanvas do begin - if DLManager.Items[Node^.Index].Status in - [STATUS_FINISH, STATUS_COMPRESS, STATUS_FAILED] then - Percents := 1 - else - if StrToIntDef(Trim(ExtractWord(2, Progress, ['/'])), 100) = 0 then - Percents:= 0 - else - Percents:=StrToIntDef(Trim(ExtractWord(1, Progress, ['/'])), 0) / - StrToIntDef(Trim(ExtractWord(2, Progress, ['/'])), 100); - - //base bar - BarRect.Left := CellRect.Left + 2; - BarRect.Top := CellRect.Top + 2; - BarRect.Right := CellRect.Right - 2; - BarRect.Bottom := CellRect.Bottom - 2; - Pen.Style := psSolid; - Brush.Style := bsSolid; - Pen.Color:=CL_BarGrayLine; - Brush.Color:=CL_BarGray; - Rectangle(BarRect); - //progress bar - ProgressBarRect := BarRect; - //Inc(ProgressBarRect.Left); - //Inc(ProgressBarRect.Top); - //Dec(ProgressBarRect.Right); - //Dec(ProgressBarRect.Bottom); - ProgressBarRect.Right := round((ProgressBarRect.Right - ProgressBarRect.Left) * - Percents) + ProgressBarRect.Left; - if (ProgressBarRect.Right - ProgressBarRect.Left) > 0 then - begin - case DLManager.Items[Node^.Index].Status of - STATUS_STOP, - STATUS_FAILED : begin - Pen.Color := CL_BarRedLine; - Brush.Color := CL_BarRed; - end; - STATUS_WAIT : begin - Pen.Color := CL_BarGrayLine; - Brush.Color := CL_BarGray; - end; - STATUS_DOWNLOAD: begin - Pen.Color := CL_BarBlueLine; - Brush.Color := CL_BarBlue; - end; - STATUS_PROBLEM : begin - Pen.Color := CL_BarYellowLine; - Brush.Color := CL_BarYellow; - end; - STATUS_FINISH : begin - Pen.Color := CL_BarGreenLine; - Brush.Color := CL_BarGreen; - end; - else begin + if Status in [STATUS_FINISH, STATUS_COMPRESS, STATUS_FAILED] then + Percents := 1 + else + if (DLManager.Items[Node^.Index].DownCounter = 0) or + (DLManager.Items[Node^.Index].PageNumber = 0) then + Percents := 0 + else + Percents := DLManager.Items[Node^.Index].DownCounter / DLManager.Items[Node^.Index].PageNumber; + + // base bar + BarRect.Left := CellRect.Left + 2; + BarRect.Top := CellRect.Top + 2; + BarRect.Right := CellRect.Right - 2; + BarRect.Bottom := CellRect.Bottom - 2; + Pen.Style := psSolid; + Brush.Style := bsSolid; + Pen.Color := CL_BarGrayLine; + Brush.Color := CL_BarGray; + Rectangle(BarRect); + + // progress bar + if Percents > 0 then + begin + BarRect.Right := round((BarRect.Right - BarRect.Left) * Percents) + BarRect.Left; + case DLManager.Items[Node^.Index].Status of + STATUS_STOP, + STATUS_FAILED : begin + Pen.Color := CL_BarRedLine; + Brush.Color := CL_BarRed; + end; + STATUS_WAIT : begin + Pen.Color := CL_BarGrayLine; + Brush.Color := CL_BarGray; + end; + STATUS_DOWNLOAD: begin + Pen.Color := CL_BarBlueLine; + Brush.Color := CL_BarBlue; + end; + STATUS_PROBLEM : begin + Pen.Color := CL_BarYellowLine; + Brush.Color := CL_BarYellow; + end; + STATUS_FINISH : begin + Pen.Color := CL_BarGreenLine; + Brush.Color := CL_BarGreen; + end; + else + begin Pen.Color := CL_BarBrownGoldLine; Brush.Color := CL_BarBrownGold; end; - end; - Rectangle(ProgressBarRect); end; - //text + Rectangle(BarRect); + end; + // text + if DownloadInfo.Progress <> '' then + begin Font.Color := clBlack; Brush.Style := bsClear; - GetTextSize(Progress, ww, hh); + GetTextSize(DownloadInfo.Progress, ww, hh); TextOut(CellRect.Left + ((CellRect.Right - CellRect.Left - ww) div 2), - CellRect.Top + ((CellRect.Bottom - CellRect.Top - hh) div 2), Progress); + CellRect.Top + ((CellRect.Bottom - CellRect.Top - hh) div 2), DownloadInfo.Progress); end; end; end; From 5d8d77ab090ffbf35949fd91c1a610b82df2a9d2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 18:39:20 +0800 Subject: [PATCH 1152/2794] downloadmanager, fixed restore download task --- baseunits/uDownloadsManager.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 93e1ffcbc..98ab5a5ca 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface lazutf8classes, LazFileUtils, FileUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, - DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils; + DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils, strutils; type TDownloadManager = class; @@ -1656,17 +1656,23 @@ procedure TDownloadManager.Restore; Exit; for i := 0 to tmp - 1 do begin - // Restore chapter links, chapter name and page links + // restore download task from file Containers.Add(TTaskContainer.Create); - with DownloadManagerFile, TTaskContainer(Containers.Last) do begin + with DownloadManagerFile, TTaskContainer(Containers.Last) do + begin tid := 'task' + IntToStr(i); Manager := Self; DownloadInfo.Website := ReadString(tid, 'Website', 'NULL'); DownloadInfo.Link := ReadString(tid, 'Link', ''); DownloadInfo.Title := ReadString(tid, 'Title', 'NULL'); - DownloadInfo.SaveTo := CorrectPathSys(ReadString(tid, 'SaveTo', 'NULL')); + DownloadInfo.SaveTo := CleanAndExpandDirectory(ReadString(tid, 'SaveTo', 'NULL')); DownloadInfo.Status := ReadString(tid, 'Status', 'NULL'); DownloadInfo.Progress := ReadString(tid, 'Progress', 'NULL'); + if Pos('/', DownloadInfo.Progress) > 0 then + begin + DownCounter := StrToIntDef(ExtractWord(1, DownloadInfo.Progress, ['/']), 0); + PageNumber := StrToIntDef(ExtractWord(2, DownloadInfo.Progress, ['/']), 0); + end; s := ReadString(tid, 'ChapterLinks', ''); if s <> '' then GetParams(ChapterLinks, s); s := ReadString(tid, 'ChapterName', ''); From 62d0d975522e5b9cb035e5234be5367618d8cf9e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 20:09:56 +0800 Subject: [PATCH 1153/2794] tumangaonline, rewrite all code, using new api which is json #243 --- baseunits/modules/Tumangaonline.pas | 208 ++++++++++------------------ 1 file changed, 75 insertions(+), 133 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index fdd279c75..34f80a9e4 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -11,32 +11,25 @@ interface implementation const - dirurls: array[0..5] of String = ( - '/listado-mangas/mangas?tipo=4&filter=Webtoon', - '/listado-mangas/mangas?tipo=4&filter=Manga', - '/listado-mangas/mangas?tipo=4&filter=OneShot', - '/listado-mangas/mangas?tipo=4&filter=Manhwa', - '/listado-mangas/mangas?tipo=4&filter=Manhua', - '/listado-mangas/mangas?tipo=4&filter=Novela' - ); + apiurl = '/api/v1/'; + apiurlmangas = apiurl + 'mangas'; + apiurlimagenes = apiurl + 'imagenes'; + dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage=1000&page='; + mangaurl = '/#!/biblioteca/mangas/'; + imgurl = 'http://img1.tumangaonline.com'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; -var - s: String; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - s := XPathString('//ul[@class="pagination"]/li[starts-with(.,"Página 1 de")]'); - if s <> '' then begin - s := SeparateRight(s, 'de '); - Page := StrToIntDef(s, 1); - end; + Page := StrToIntDef(XPathString('json(*).last_page'), 1); finally Free; end; @@ -51,16 +44,16 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex]; - if AURL <> '0' then - s := s + '&pag=' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//div[@class="row text-center"]/div/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + for v in XPath('json(*).data()/concat(id,"/",nombreUrl," ",nombre)') do + begin + s := v.toString; + ALinks.Add(mangaurl + SeparateLeft(s, ' ')); + ANames.Add(SeparateRight(s, ' ')); end; finally Free; @@ -72,29 +65,64 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + mangaid, purl, s: String; + p, i: Integer; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + if Pos(mangaurl, AURL) <> 0 then + begin + mangaid := SeparateRight(AURL, mangaurl); + if Pos('/', mangaid) <> 0 then + mangaid := SeparateLeft(mangaid, '/'); + end + else + Exit; url := FillHost(Module.RootURL, AURL); - if GET(url) then begin + if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//img[@itemprop="image"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h1[@class="panel-title"]'); - authors := XPathString('//table[@class="tbl table-hover"]/tbody/tr/td[@property="name"]/a[1]'); - artists := XPathString('//table[@class="tbl table-hover"]/tbody/tr/td[@property="name"]/a[2]'); - genres := XPathString('//table[@class="tbl table-hover"]/tbody/tr/td[@colspan="2"]'); - summary := XPathString('//div[@id="descripcion"]'); - MangaInfo.RemoveHostFromChapterLinks := False; - for v in XPath('//table[@class="tbl table-hover table-striped"]/tbody/tr/td/h5/a') do + coverLink := XPathString('json(*).imageUrl'); + if coverLink <> '' then coverLink := MaybeFillHost(imgurl, coverLink); + if title = '' then title := XPathString('json(*).nombre'); + s := XPathString('json(*).estado'); + if Pos('Activo', s) <> 0 then + status := '1' + else if Pos('Finalizado', s) <> 0 then + status := '0'; + summary := XPathString('json(*).info.sinopsis'); + genres := XPathStringAll('json(*).generos().genero'); + AddCommaString(genres, XPathStringAll('json(*).categorias().categoria')); + artists := XPathStringAll('json(*).artistas().artista'); + authors := XPathStringAll('json(*).autores().autor'); + purl := Module.RootURL + apiurlmangas + '/' + mangaid + '/capitulos?tomo=-1&page='; + if GET(purl + '1') then begin - chapterLinks.Add(v.toNode.getAttribute('onClick')); - chapterName.Add(v.toString); + ParseHTML(Document); + p := StrToIntDef(XPathString('json(*).last_page'), 1); + for i := 1 to p do + begin + if i > 1 then + if GET(purl + IntToStr(i)) then + ParseHTML(Document) + else + Break; + for v in XPath('json(*).data()/concat("?idManga=",idTomo,"&idScanlation=",subidas/idScan,"&numeroCapitulo=",numCapitulo,"&visto=true")') do + chapterLinks.Add(apiurlimagenes + v.toString); + for v in XPath('json(*).data()/concat(numCapitulo," ",nombre)') do + begin + s := v.toString; + if RightStr(s, 5) = ' null' then + SetLength(s, Length(s) - 5); + chapterName.Add(s); + end; + end; + InvertStrings([chapterLinks, chapterName]); end; - InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -102,111 +130,26 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; end; end; -function TaskStart(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; -begin - Result := True; - if Task = nil then Exit; - with Task.PageContainerLinks do - begin - NameValueSeparator := '='; - Delimiter := '&'; - end; -end; - function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - s, idManga, idCapitulo: String; - source: TStringList; - i: Integer; + s: String; + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.manager.container do + begin PageLinks.Clear; PageNumber := 0; - s := ''; - - if Pos('listacapitulos', LowerCase(AURL)) > 0 then + if GET(FillHost(Module.RootURL, AURL)) then begin - with TRegExpr.Create do - try - Expression := '(?i)listaCapitulos\((\d+),(\d+)[^d]*.*$'; - idManga := Replace(AURL, '$1', True); - idCapitulo := Replace(AURL, '$2', True); - finally - Free; - end; - - Headers.Values['Referer'] := ' ' + MaybeFillHost(Module.RootURL, DownloadInfo.Link); - if POST(Module.RootURL + '/index.php?option=com_controlmanga&view=capitulos&format=raw', - QueryString([KeyVal('idManga', idManga), KeyVal('idCapitulo', idCapitulo)])) then - begin - with TXQueryEngineHTML.Create(Document) do - try - s := XPathString('//a[@class="toViewer"]/@data-enlace'); - if s <> '' then - ChapterLinks[CurrentDownloadChapterPtr] := s; - finally - Free; - end; - end; - end - else if Pos('/visor/', AURL) > 0 then - s := AURL - else - Exit; - if s = '' then Exit; - - Headers.Values['Referer'] := ' ' + MaybeFillHost(Module.RootURL, DownloadInfo.Link); - if GET(MaybeFillHost(Module.RootURL, s)) then begin - Result := True; - with PageContainerLinks do begin - source := TStringList.Create; - try - source.LoadFromStream(Document); - if source.Count > 0 then - for i := 0 to source.Count - 1 do begin - if Pos('var tipo ', source[i]) > 0 then - Values['tipo'] := TrimChar(SeparateRight(source[i], '='), [';', ' ']) - else if Pos('var tam ', source[i]) > 0 then - Values['tam'] := TrimChar(SeparateRight(source[i], '='), [';', ' ']) - else if Pos('var sep ', source[i]) > 0 then - Values['sep'] := TrimChar(SeparateRight(source[i], '='), [';', ' ']) - else if Pos('function toggleFullScreen()', source[i]) > 0 then - Break; - end; - finally - source.Free; - end; - with TXQueryEngineHTML.Create(Document) do - try - Values['ruta'] := EncodeURL(XPathString('//input[@hidden=true]/@value')); - PageNumber := XPath('//select[@id="pageNumber"]/option').Count; - finally - Free; - end; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin - if PageContainerLinks.Count = 0 then Exit; - PageContainerLinks.Values['pagina'] := IncStr(DownloadThread.workCounter); - Headers.Values['Referer'] := - ' ' + MaybeFillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); - if POST(Module.RootURL + '/visor/x.php', PageContainerLinks.DelimitedText) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := - XPathString('//img[@class="img-responsive center-block"]/@src'); + s := imgurl + '/subidas/' + XPathString('json(*)/concat(capitulo/idTomo,"/",capitulo/numCapitulo,"/",idScan)') + '/'; + for v in XPath('json((json(*).imagenes))()') do + PageLinks.Add(s + v.toString); finally Free; end; @@ -219,13 +162,12 @@ procedure RegisterModule; with AddModule do begin Website := 'Tumangaonline'; RootURL := 'http://www.tumangaonline.com'; - TotalDirectory := Length(dirurls); - OnTaskStart := @TaskStart; + MaxTaskLimit := 1; + MaxConnectionLimit := 1; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; end; end; From 6285aa6b1286442edec68f6bb29bbe18c16909ac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 20:35:39 +0800 Subject: [PATCH 1154/2794] yomanga, fixed using cf fixed #246 --- baseunits/modules/FoOlSlide.pas | 42 ++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 5cb04e065..a5fdf8517 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -6,14 +6,27 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, Cloudflare, RegExpr, synautil; implementation +var + yomangalockget: TRTLCriticalSection; + yomangacookies: String; + const dirurl = '/directory/'; yomangadirurl = '/reader/directory/'; +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + if Module.Website = 'YoManga' then + Result := Cloudflare.GETCF(AHTTP, AURL, yomangacookies, yomangalockget) + else + Result := AHTTP.GET(AURL); +end; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var @@ -27,7 +40,8 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; s := yomangadirurl else s := dirurl; - if MangaInfo.FHTTP.GET(Module.RootURL + s) then begin + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + s, Module) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -58,7 +72,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; s := dirurl; s := Module.RootURL + s; if AURL <> '0' then s += IncStr(AURL) + '/'; - if MangaInfo.FHTTP.GET(s) then begin + if GETWithCookie(MangaInfo.FHTTP, s, Module) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -79,8 +94,10 @@ function GetInfo(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL, AURL)) then begin + with MangaInfo.FHTTP, MangaInfo.mangaInfo do + begin + if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL), Module) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try @@ -115,10 +132,12 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.manager.container do + begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then + begin Result := True; with TXQueryEngineHTML.Create(Document) do try @@ -147,11 +166,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.manager.container, DownloadThread.FHTTP do + begin s := AURL; if DownloadThread.workCounter > 0 then s := AppendURLDelim(s) + 'page/' + IncStr(DownloadThread.workCounter); - if GET(FillHost(Module.RootURL, s)) then begin + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, s), Module) then + begin Result := True; with TXQueryEngineHTML.Create(Document) do try @@ -187,6 +208,9 @@ procedure RegisterModule; end; initialization + InitCriticalSection(yomangalockget); RegisterModule; +finalization + DoneCriticalsection(yomangalockget); end. From 88168e557374b5d207b2c0d401d3cbbc0ec0d711 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 20:38:20 +0800 Subject: [PATCH 1155/2794] space --- baseunits/modules/FoOlSlide.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index a5fdf8517..03a073bd1 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -210,6 +210,7 @@ procedure RegisterModule; initialization InitCriticalSection(yomangalockget); RegisterModule; + finalization DoneCriticalsection(yomangalockget); From 3ea9fedfb7ba20601e6c6d9f8ceec55f264abc6d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 20:50:12 +0800 Subject: [PATCH 1156/2794] gos, fixed download fixed #247 --- baseunits/modules/GameofScanlation.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 4446c7d0f..f7596f8ad 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -111,7 +111,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - for v in XPath('//div[@id="comicMainImage"]//img/@src') do + for v in XPath('//div[@class="chapterPages"]//img/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)); finally Free; From ae01a20d7229b8aff436a21d9871a0976f9d19bb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 21:00:41 +0800 Subject: [PATCH 1157/2794] mangavadisi and mangaframe removed #244 --- .../MangaFrame/chapter_page_number.inc | 38 ------ .../MangaFrame/directory_page_number.inc | 30 ---- baseunits/includes/MangaFrame/image_url.inc | 38 ------ .../includes/MangaFrame/manga_information.inc | 82 ----------- .../includes/MangaFrame/names_and_links.inc | 32 ----- .../MangaVadisi/chapter_page_number.inc | 33 ----- baseunits/includes/MangaVadisi/image_url.inc | 33 ----- .../MangaVadisi/manga_information.inc | 61 --------- .../includes/MangaVadisi/names_and_links.inc | 37 ----- baseunits/uBaseUnit.pas | 129 ++++++++---------- baseunits/uData.pas | 25 ---- baseunits/uDownloadsManager.pas | 20 --- config/mangalist.ini | 2 +- 13 files changed, 61 insertions(+), 499 deletions(-) delete mode 100644 baseunits/includes/MangaFrame/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaFrame/directory_page_number.inc delete mode 100644 baseunits/includes/MangaFrame/image_url.inc delete mode 100644 baseunits/includes/MangaFrame/manga_information.inc delete mode 100644 baseunits/includes/MangaFrame/names_and_links.inc delete mode 100644 baseunits/includes/MangaVadisi/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaVadisi/image_url.inc delete mode 100644 baseunits/includes/MangaVadisi/manga_information.inc delete mode 100644 baseunits/includes/MangaVadisi/names_and_links.inc diff --git a/baseunits/includes/MangaFrame/chapter_page_number.inc b/baseunits/includes/MangaFrame/chapter_page_number.inc deleted file mode 100644 index 068eba0c2..000000000 --- a/baseunits/includes/MangaFrame/chapter_page_number.inc +++ /dev/null @@ -1,38 +0,0 @@ - function GetMangaFramePageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - isExtractPageNumber: Boolean = False; - begin - manager.container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAFRAME_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); - - l.Text := FixHTMLTagQuote(l.Text); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="tbtitle dropdown_parent dropdown_right"', parse[i]) > 0 then - isExtractPageNumber := True; - if isExtractPageNumber and (Pos('</ul', parse[i]) > 0) then - begin - isExtractPageNumber := False; - Break; - end; - if isExtractPageNumber and (Pos('<a', parse[i]) > 0) then - Inc(manager.container.PageNumber); - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/MangaFrame/directory_page_number.inc b/baseunits/includes/MangaFrame/directory_page_number.inc deleted file mode 100644 index af5ab336c..000000000 --- a/baseunits/includes/MangaFrame/directory_page_number.inc +++ /dev/null @@ -1,30 +0,0 @@ - function GetMangaFrameDirectoryPageNumber: Byte; - var - i: Integer; - begin - Page := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAFRAME_ID, 1] + MANGAFRAME_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if i + 1 < parse.Count - 1 then - if (Pos('class="gbutton fright"', parse[i]) > 0) and (Pos('<a', parse[i]) > 0) and - (Pos('Last', parse[i + 1]) > 0) then - begin - Page := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', Trim(GetVal(parse[i], 'href')), '$1', True), 1); - Break; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaFrame/image_url.inc b/baseunits/includes/MangaFrame/image_url.inc deleted file mode 100644 index 7567b04c9..000000000 --- a/baseunits/includes/MangaFrame/image_url.inc +++ /dev/null @@ -1,38 +0,0 @@ - function GetMangaFrameImageURL: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAFRAME_ID, URL); - if not ExecRegExpr('/$', s) then - s := s + '/'; - s := s + 'page/' + IntToStr(QWord(workCounter) + 1); - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - l.Text := FixHTMLTagQuote(l.Text); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - //if i + 2 < parse.Count - 1 then - if (Pos('class="open"', parse[i]) > 0) and (Pos('<img', parse[i]) > 0) then - begin - manager.container.PageLinks[workCounter] := Trim(GetVal(parse[i], 'src')); - Break; - end; - parse.Free; - end; diff --git a/baseunits/includes/MangaFrame/manga_information.inc b/baseunits/includes/MangaFrame/manga_information.inc deleted file mode 100644 index d10d85bab..000000000 --- a/baseunits/includes/MangaFrame/manga_information.inc +++ /dev/null @@ -1,82 +0,0 @@ - function GetMangaFrameInfoFromURL: Byte; - var - i: Integer; - begin - mangaInfo.website := WebsiteRoots[MANGAFRAME_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAFRAME_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit(INFORMATION_NOT_FOUND); - - mangaInfo.coverLink := ''; - mangaInfo.title := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.status := '1'; - - for i := 0 to parse.Count - 1 do - begin - //cover - if (i + 2 < parse.Count - 1) then - if (Pos('class="thumbnail"', parse[i]) > 0) and (Pos('<img', parse[i + 2]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - //title - if (i + 1 < parse.Count - 1) then - if (Pos('class="title"', parse[i]) > 0) and (Pos('<h1', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - - //author - if (i + 3 < parse.Count - 1) then - if (Pos('Author', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) - and (Pos('<', parse[i + 2]) = 0) then - mangaInfo.authors := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); - - //artist - if (i + 3 < parse.Count - 1) then - if (Pos('Artist', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) - and (Pos('<', parse[i + 2]) = 0) then - mangaInfo.artists := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); - - //synopsis - if (i + 3 < parse.Count - 1) then - if (Pos('Synopsis', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) - and (Pos('<', parse[i + 2]) = 0) then - mangaInfo.summary := Trim(TrimLeftChar(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))), [':'])); - - //chapters - if (i + 2 < parse.Count - 1) then - if (Pos('class="title"', parse[i]) > 0) and (Pos('<a', parse[i + 1]) > 0) - and (Pos('/okuyucu/read', parse[i + 1]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(Trim(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGAFRAME_ID, 1], '', [rfIgnoreCase]))); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); - end; - end; - - // invert chapters - if mangaInfo.chapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaFrame/names_and_links.inc b/baseunits/includes/MangaFrame/names_and_links.inc deleted file mode 100644 index d08dfec28..000000000 --- a/baseunits/includes/MangaFrame/names_and_links.inc +++ /dev/null @@ -1,32 +0,0 @@ - function MangaFrameNamesAndLinks: Byte; - var - i: Integer; - s: String; - //isExtractNames: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[MANGAFRAME_ID, 1] + MANGAFRAME_BROWSER + IntToStr(StrToInt(URL) + 1) + '/'; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if i + 2 < parse.Count - 1 then - if (Pos('class="title"', parse[i]) > 0) and (Pos('<a', parse[i + 1]) > 0) and - (Pos('/okuyucu/series/', parse[i + 1]) > 0) then - begin - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); - links.Add(Trim(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGAFRAME_ID, 1], '', [rfIgnoreCase]))); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaVadisi/chapter_page_number.inc b/baseunits/includes/MangaVadisi/chapter_page_number.inc deleted file mode 100644 index d3cffa5db..000000000 --- a/baseunits/includes/MangaVadisi/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangaVadisiPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL) + '/1'); - Result := GetPage(TObject(l), - s, - manager.container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - manager.container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Sonraki Sayfa"', parse[i]) > 0) then - begin - s := parse[i - 6]; - manager.container.PageNumber := StrToInt(GetString(s, '"', '"')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaVadisi/image_url.inc b/baseunits/includes/MangaVadisi/image_url.inc deleted file mode 100644 index 81579b593..000000000 --- a/baseunits/includes/MangaVadisi/image_url.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangaVadisiImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL) - + '/' + IntToStr(workCounter + 1)); - Result := GetPage(TObject(l), - s, - manager.container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse[i]) > 0) then - begin - manager.container.pageLinks[workCounter] := - EncodeURL(WebsiteRoots[MANGAVADISI_ID, 1] + MANGAVADISI_BROWSER + - GetVal(parse[i], 'src')); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaVadisi/manga_information.inc b/baseunits/includes/MangaVadisi/manga_information.inc deleted file mode 100644 index 218fc5e9b..000000000 --- a/baseunits/includes/MangaVadisi/manga_information.inc +++ /dev/null @@ -1,61 +0,0 @@ - function GetMangaVadisiInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAVADISI_ID, MANGAVADISI_BROWSER + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.website := WebsiteRoots[MANGAVADISI_ID, 0]; - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('Manga Vadisi - ', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i], 'Manga Vadisi - ', ' - Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := URL + '/' + GetVal(parse[i], 'value'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaVadisi/names_and_links.inc b/baseunits/includes/MangaVadisi/names_and_links.inc deleted file mode 100644 index a747d26d8..000000000 --- a/baseunits/includes/MangaVadisi/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function MangaVadisiGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAVADISI_ID, 1] + - MANGAVADISI_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('<option value="', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i], 'value'); - links.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e85d81d80..dea27cb3f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -241,68 +241,66 @@ interface MANGATRADERS_ID = 8; TRUYENTRANHTUAN_ID = 9; TURKCRAFT_ID = 10; - MANGAVADISI_ID = 11; - MANGAFRAME_ID = 12; - EATMANGA_ID = 13; - STARKANA_ID = 14; - BLOGTRUYEN_ID = 15; - KOMIKID_ID = 16; - ESMANGAHERE_ID = 17; - ANIMEEXTREMIST_ID = 18; - HUGEMANGA_ID = 19; - S2SCAN_ID = 20; - IMANHUA_ID = 21; - MABUNS_ID = 22; - MANGAESTA_ID = 23; - CENTRALDEMANGAS_ID = 24; - EGSCANS_ID = 25; - MANGAAR_ID = 26; - MANGAAE_ID = 27; - ANIMESTORY_ID = 28; - LECTUREENLIGNE_ID = 29; - SCANMANGA_ID = 30; - MANGAGO_ID = 31; - DM5_ID = 32; - MANGACOW_ID = 33; - KIVMANGA_ID = 34; - MEINMANGA_ID = 35; - MANGASPROJECT_ID = 36; - MANGAREADER_POR_ID = 37; - NINEMANGA_ID = 38; - NINEMANGA_ES_ID = 39; - NINEMANGA_CN_ID = 40; - NINEMANGA_RU_ID = 41; - NINEMANGA_DE_ID = 42; - NINEMANGA_IT_ID = 43; - NINEMANGA_BR_ID = 44; - JAPANSHIN_ID = 45; - JAPSCAN_ID = 46; - CENTRUMMANGI_PL_ID = 47; - MANGALIB_PL_ID = 48; - ONEMANGA_ID = 49; - MANGATOWN_ID = 50; - MANGAOKU_ID = 51; - MYREADINGMANGAINFO_ID = 52; - IKOMIK_ID = 53; - NHENTAI_ID = 54; - MANGAMINT_ID = 55; - UNIXMANGA_ID = 56; - EXTREMEMANGAS_ID = 57; - MANGAHOST_ID = 58; - PORNCOMIX_ID = 59; - PORNCOMIXRE_ID = 60; - PORNCOMIXIC_ID = 61; - XXCOMICS_ID = 62; - XXCOMICSMT_ID = 63; - XXCOMICS3D_ID = 64; - PORNXXXCOMICS_ID = 65; - MANGASEE_ID = 66; - MANGAKU_ID = 67; - MANGAAT_ID = 68; - READMANGATODAY_ID = 69; - DYNASTYSCANS_ID = 70; - - WebsiteRoots: array [0..70] of array [0..1] of String = ( + EATMANGA_ID = 11; + STARKANA_ID = 12; + BLOGTRUYEN_ID = 13; + KOMIKID_ID = 14; + ESMANGAHERE_ID = 15; + ANIMEEXTREMIST_ID = 16; + HUGEMANGA_ID = 17; + S2SCAN_ID = 18; + IMANHUA_ID = 19; + MABUNS_ID = 20; + MANGAESTA_ID = 21; + CENTRALDEMANGAS_ID = 22; + EGSCANS_ID = 23; + MANGAAR_ID = 24; + MANGAAE_ID = 25; + ANIMESTORY_ID = 26; + LECTUREENLIGNE_ID = 27; + SCANMANGA_ID = 28; + MANGAGO_ID = 29; + DM5_ID = 30; + MANGACOW_ID = 31; + KIVMANGA_ID = 32; + MEINMANGA_ID = 33; + MANGASPROJECT_ID = 34; + MANGAREADER_POR_ID = 35; + NINEMANGA_ID = 36; + NINEMANGA_ES_ID = 37; + NINEMANGA_CN_ID = 38; + NINEMANGA_RU_ID = 39; + NINEMANGA_DE_ID = 40; + NINEMANGA_IT_ID = 41; + NINEMANGA_BR_ID = 42; + JAPANSHIN_ID = 43; + JAPSCAN_ID = 44; + CENTRUMMANGI_PL_ID = 45; + MANGALIB_PL_ID = 46; + ONEMANGA_ID = 47; + MANGATOWN_ID = 48; + MANGAOKU_ID = 49; + MYREADINGMANGAINFO_ID = 50; + IKOMIK_ID = 51; + NHENTAI_ID = 52; + MANGAMINT_ID = 53; + UNIXMANGA_ID = 54; + EXTREMEMANGAS_ID = 55; + MANGAHOST_ID = 56; + PORNCOMIX_ID = 57; + PORNCOMIXRE_ID = 58; + PORNCOMIXIC_ID = 59; + XXCOMICS_ID = 60; + XXCOMICSMT_ID = 61; + XXCOMICS3D_ID = 62; + PORNXXXCOMICS_ID = 63; + MANGASEE_ID = 64; + MANGAKU_ID = 65; + MANGAAT_ID = 66; + READMANGATODAY_ID = 67; + DYNASTYSCANS_ID = 68; + + WebsiteRoots: array [0..68] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), @@ -314,8 +312,6 @@ interface ('MangaTraders', 'http://mangatraders.org'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), - ('MangaVadisi', 'http://www.mangavadisi.net'), - ('MangaFrame', 'http://www.mangaframe.com'), ('EatManga', 'http://eatmanga.com'), ('Starkana', 'http://starkana.jp'), ('BlogTruyen', 'http://blogtruyen.com'), @@ -401,10 +397,6 @@ interface TURKCRAFT_BROWSER = '/'; - MANGAVADISI_BROWSER = '/hemenoku/'; - - MANGAFRAME_BROWSER = '/okuyucu/directory/'; - EATMANGA_BROWSER = '/Manga-Scan/'; EATMANGA_maxDLTask: Cardinal = 1; @@ -1149,7 +1141,6 @@ function SitesWithoutInformation(const website: String): Boolean; end; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, - MANGAVADISI_ID, TURKCRAFT_ID, HUGEMANGA_ID, KIVMANGA_ID, diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 77d63e82b..11254d586 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -813,8 +813,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/MangaMint/directory_page_number.inc} - {$I includes/MangaFrame/directory_page_number.inc} - {$I includes/MangaHost/directory_page_number.inc} {$I includes/PornComix/directory_page_number.inc} @@ -924,9 +922,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St if WebsiteID = MANGAMINT_ID then Result := GetMangaMintDirectoryPageNumber else - if WebsiteID = MANGAFRAME_ID then - Result := GetMangaFrameDirectoryPageNumber - else if WebsiteID = MANGAHOST_ID then Result := GetMangaHostDirectoryPageNumber else @@ -1014,10 +1009,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Turkcraft/names_and_links.inc} - {$I includes/MangaVadisi/names_and_links.inc} - - {$I includes/MangaFrame/names_and_links.inc} - {$I includes/Mangacow/names_and_links.inc} {$I includes/Starkana/names_and_links.inc} @@ -1181,12 +1172,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else - if WebsiteID = MANGAVADISI_ID then - Result := MangaVadisiGetNamesAndLinks - else - if WebsiteID = MANGAFRAME_ID then - Result := MangaFrameNamesAndLinks - else if WebsiteID = MANGACOW_ID then Result := MangaCowGetNamesAndLinks else @@ -1343,10 +1328,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/Turkcraft/manga_information.inc} - {$I includes/MangaVadisi/manga_information.inc} - - {$I includes/MangaFrame/manga_information.inc} - {$I includes/MangaAr/manga_information.inc} {$I includes/MangaAe/manga_information.inc} @@ -1505,12 +1486,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = TURKCRAFT_ID then Result := GetTurkcraftInfoFromURL else - if WebsiteID = MANGAFRAME_ID then - Result := GetMangaframeInfoFromURL - else - if WebsiteID = MANGAVADISI_ID then - Result := GetMangaVadisiInfoFromURL - else if WebsiteID = MANGAAR_ID then Result := GetMangaArInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 98ab5a5ca..72bf13240 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -393,8 +393,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Mangacow/chapter_page_number.inc} - {$I includes/MangaFrame/chapter_page_number.inc} - {$I includes/MangaGo/chapter_page_number.inc} {$I includes/MangaInn/chapter_page_number.inc} @@ -403,8 +401,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaTraders/chapter_page_number.inc} - {$I includes/MangaVadisi/chapter_page_number.inc} - {$I includes/MeinManga/chapter_page_number.inc} {$I includes/S2Scans/chapter_page_number.inc} @@ -512,12 +508,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftPageNumber else - if manager.container.MangaSiteID = MANGAVADISI_ID then - Result := GetMangaVadisiPageNumber - else - if manager.container.MangaSiteID = MANGAFRAME_ID then - Result := GetMangaFramePageNumber - else if manager.container.MangaSiteID = MANGAAE_ID then Result := GetMangaAePageNumber else @@ -647,8 +637,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaEsta/image_url.inc} - {$I includes/MangaFrame/image_url.inc} - {$I includes/MangaGo/image_url.inc} {$I includes/MangaInn/image_url.inc} @@ -661,8 +649,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaTraders/image_url.inc} - {$I includes/MangaVadisi/image_url.inc} - {$I includes/ScanManga/image_url.inc} {$I includes/Starkana/image_url.inc} @@ -777,12 +763,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if manager.container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftImageURL else - if manager.container.MangaSiteID = MANGAVADISI_ID then - Result := GetMangaVadisiImageURL - else - if manager.container.MangaSiteID = MANGAFRAME_ID then - Result := GetMangaFrameImageURL - else if manager.container.MangaSiteID = MANGAAR_ID then Result := GetMangaArImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index aaaeaa7e1..7b4c09021 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -17,6 +17,6 @@ Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga,Tumangaonline Thai=MangaBoom -Turkish=MangaFrame,MangaOku,Manga-Tr,MangaVadisi,Puzzmos,WebtoonTr +Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D From c55f60af1a45ab60ad0d701b615012d317466b11 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 21:43:59 +0800 Subject: [PATCH 1158/2794] added mangadenizi closed #244 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaDenizi.pas | 142 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaDenizi.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a764cc9d7..b46133aab 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -35,4 +35,5 @@ uses Tumangaonline, MangaEden, HeyMangaXyz, - WebtoonTr; + WebtoonTr, + MangaDenizi; diff --git a/baseunits/modules/MangaDenizi.pas b/baseunits/modules/MangaDenizi.pas new file mode 100644 index 000000000..ca3a16a35 --- /dev/null +++ b/baseunits/modules/MangaDenizi.pas @@ -0,0 +1,142 @@ +unit MangaDenizi; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurlstart = '/filterList?page='; + dirurlend = '&cat=&alpha=&sortBy=name&asc=true&author='; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurlstart + '1' + dirurlend) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := XPath('//ul[@class="pagination"]/li').Count - 2; + if Page < 1 then + Page := 1; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurlstart + IncStr(AURL) + dirurlend) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//h5/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.FHTTP, MangaInfo.mangaInfo do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="boxed"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h2[@class="widget-title"]'); + s := XPathString('//dl[@class="dl-horizontal"]/dd[1]'); + if Pos('Devam Ediyor', s) > 0 then + status := '1' + else if Pos('Tamamlandı', s) > 0 then + status := '0'; + authors := XPathString('//dl[@class="dl-horizontal"]/dd[2]/a[1]'); + artists := XPathString('//dl[@class="dl-horizontal"]/dd[2]/a[2]'); + genres := XPathStringAll('//dl[@class="dl-horizontal"]/dd[3]/a'); + summary := XPathString('//div[@class="well"]/p'); + for v in XPath('//ul[@class="chapters"]/li//a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.manager.container do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div[@id="all"]/img/@data-src') do + PageLinks.Add(v.toString); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaDenizi'; + RootURL := 'http://www.mangadenizi.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 7b4c09021..3ddede82c 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -17,6 +17,6 @@ Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga,Tumangaonline Thai=MangaBoom -Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr +Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D From eab5d9413de065946c0ee4859d8bcd74f2987fb1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 20 May 2016 21:59:47 +0800 Subject: [PATCH 1159/2794] Bump version 0.9.55.0 --- changelog.txt | 11 ++++++++++- mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4d634760d..3d499654f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.55.0 (20-05-2016) +[*] Tumangaonline: rewrite all code, require new manga list +[*] Yomanga: fixed blocked by cf +[*] GameofScanlation: fixed download +[-] MangaVadisi and MangaFrame removed +[+] Added MangaDenizi[TR] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.54.0...0.9.55.0 + 0.9.54.0 (09-05-2016) [*] Manga-Tr: fixed get image url [+] Added Puzzmos[TR] @@ -90,7 +99,7 @@ Full changes: https://github.com/riderkick/FMD/compare/0.9.42.0...0.9.43.0 [*] Various changes and bug fixes 0.9.40.0 (12-03-2016) -[+] Added Tsumangaonline[ES] +[+] Added Tumangaonline[ES] [*] Various changes and bug fixes 0.9.39.0 (10-03-2016) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b2f15dcf5..ef5dec2ca 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="54"/> + <RevisionNr Value="55"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 69c787046..58b1a442c 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.54.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.54.0/fmd_0.9.54.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.54.0/fmd_0.9.54.0_Win64.7z +VERSION=0.9.55.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.55.0/fmd_0.9.55.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.55.0/fmd_0.9.55.0_Win64.7z From 887d372f9ad71954efd5fe9fd9127b37f3cba227 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 May 2016 03:41:21 +0800 Subject: [PATCH 1160/2794] baseunit, added imagefileexist --- baseunits/uBaseUnit.pas | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dea27cb3f..7c5d4efdc 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -802,6 +802,9 @@ function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; +// check file exist with known extensions. AFilename is a filename without extensions +function ImageFileExist(const AFilename: String): Boolean; + procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); // This method uses to sort the data. Use when we load all the lists. @@ -3290,9 +3293,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; // skip the download process. if Trim(URL) = 'D' then Exit(True); s := CleanAndExpandDirectory(Path) + Name; - if (FileExistsUTF8(s + '.jpg')) or - (FileExistsUTF8(s + '.png')) or - (FileExistsUTF8(s + '.gif')) then + if ImageFileExist(s) then Exit(True); URL := FixURL(URL); @@ -3473,6 +3474,13 @@ function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Result := SaveImage(nil, mangaSiteID, URL, Path, Name, SavedFilename, Reconnect); end; +function ImageFileExist(const AFilename: String): Boolean; +begin + Result := (FileExistsUTF8(AFilename + '.jpg')) or + (FileExistsUTF8(AFilename + '.png')) or + (FileExistsUTF8(AFilename + '.gif')); +end; + procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QSort(L, R: Cardinal); From 2754eb94d0cd270d8808eb19832f5f096da42895 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 May 2016 03:47:08 +0800 Subject: [PATCH 1161/2794] downloadmanager, check custom filenames in container if available --- baseunits/uDownloadsManager.pas | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 72bf13240..b081137e8 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1288,10 +1288,12 @@ procedure TTaskThread.Execute; begin for j := 0 to container.PageLinks.Count - 1 do begin - P := S + PathDelim + Format('%.3d', [j + 1]); - if (FileExistsUTF8(P + '.jpg')) or - (FileExistsUTF8(P + '.png')) or - (FileExistsUTF8(P + '.gif')) then + if container.Filenames.Count = container.PageLinks.Count then + P := S + PathDelim + container.Filenames[j] + else + P := S + PathDelim + Format('%.3d', [j + 1]); + + if ImageFileExist(P) then container.PageLinks[j] := 'D' else if container.PageLinks[j] = 'D' then From c8973bfca9e1e13c73e90ec83b098490e2f4b9ed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 May 2016 04:13:58 +0800 Subject: [PATCH 1162/2794] baseunit, overload saveimagestreamtofile with thttpsend as parameter to auto detect file age in header --- baseunits/uBaseUnit.pas | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7c5d4efdc..fdda03c3b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -789,7 +789,8 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0) function GetURLFromBitly(const URL: String): String; // try to save tmemorystream to file, return the saved filename if success, otherwise return empty string -function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; +function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; overload; +function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String; overload; // Download an image from url and save it to a specific location. function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; @@ -3259,13 +3260,30 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag end; end; +function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String; +var + s: String; + lastmodified: LongInt; +begin + Result := ''; + if AHTTP = nil then Exit; + s := Trim(AHTTP.Headers.Values['last-modified']); + lastmodified := 0; + if s <> '' then + try + lastmodified := DateTimeToFileDate(ScanDateTime(HTTPDateTimeFormatStr, s, FMDFormatSettings)); + except + end; + Result := SaveImageStreamToFile(AHTTP.Document, Path, FileName, lastmodified); +end; + function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; var HTTPHeader: TStringList; HTTP: THTTPSend; - counter, lastmodified: LongInt; + counter: Integer; s: String; procedure preTerminate; @@ -3440,14 +3458,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; end; end; if checkTerminate then Exit; - s := Trim(HTTP.Headers.Values['last-modified']); - lastmodified := 0; - if s <> '' then - try - lastmodified := DateTimeToFileDate(ScanDateTime(HTTPDateTimeFormatStr, s, FMDFormatSettings)); - except - end; - SavedFilename := SaveImageStreamToFile(HTTP.Document, Path, Name, lastmodified); + SavedFilename := SaveImageStreamToFile(HTTP, Path, Name); preTerminate; Result := SavedFilename <> ''; end; From ff170566e541b5cb6fbf6deefd660b4367c06022 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 May 2016 04:14:53 +0800 Subject: [PATCH 1163/2794] madokami, fixed preserve file last-modified time from server --- baseunits/modules/Madokami.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 461c78b73..92825a8b9 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -204,7 +204,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; if GETWithLogin(DownloadThread.FHTTP, AURL) then begin - SaveImageStreamToFile(DownloadThread.FHTTP.Document, APath, AName); + SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName); end; end; From c8889800c3f8b84f9af504de4da1ebdf7d1e51a8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 May 2016 04:20:36 +0800 Subject: [PATCH 1164/2794] yomanga, fixed download fixed #249 --- baseunits/modules/FoOlSlide.pas | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 03a073bd1..96c3b483e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -184,11 +184,21 @@ function GetImageURL(const DownloadThread: TDownloadThread; end; end; +function DownloadImageWithCookie(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + if GETWithCookie(DownloadThread.FHTTP, AURL, Module) then + SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName); +end; + procedure RegisterModule; - procedure AddWebsiteModule(AWebsite, ARootURL: String); + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - with AddModule do + Result := AddModule; + with Result do begin Website := AWebsite; RootURL := ARootURL; @@ -202,7 +212,12 @@ procedure RegisterModule; begin AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); - AddWebsiteModule('YoManga', 'http://yomanga.co'); + with AddWebsiteModule('YoManga', 'http://yomanga.co') do + begin + MaxTaskLimit := 1; + MaxConnectionLimit := 4; + OnDownloadImage := @DownloadImageWithCookie; + end; AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); AddWebsiteModule('GoManga', 'http://gomanga.co'); end; From 6febebc84b61107430f708716e67d85dfd255e39 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 May 2016 07:17:32 +0800 Subject: [PATCH 1165/2794] heymangaxyz, fixed download fixed #251 --- baseunits/modules/HeyMangaXyz.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index 4393ef6d6..f65bb2d9e 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -148,7 +148,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := XPathString('//picture/img[@id="img-content"]/@src'); + PageLinks[DownloadThread.workCounter] := XPathString('//img[@id="img-content"]/@src'); finally Free; end; From 0aaaf8318b45e3429702eeed9d024358fff48fbb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 May 2016 07:56:24 +0800 Subject: [PATCH 1166/2794] webtoons, download original files fixed #254 --- baseunits/modules/Webtoons.pas | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index b746cfc99..5ad8dc057 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation @@ -110,8 +110,14 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - for v in XPath('//div[@id="_imageList"]/img[@class="_images"]/@data-url') do - PageLinks.Add(v.toString); + with TRegExpr.Create do + try + Expression := '[\?\&]type=q\d+'; + for v in XPath('//div[@id="_imageList"]/img[@class="_images"]/@data-url') do + PageLinks.Add(Replace(v.toString, '', False)); + finally + Free; + end; finally Free; end; From e56ce4f311f2f32e73da3f47f92927dece1fb702 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 May 2016 08:39:55 +0800 Subject: [PATCH 1167/2794] baseunit, added const mangainfo.status --- baseunits/uBaseUnit.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fdda03c3b..cfbad2b23 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -480,6 +480,9 @@ interface '/series' ); + MangaInfo_StatusCompleted = '0'; + MangaInfo_StatusOngoing = '1'; + var // Sites var BROWSER_INVERT: Boolean = False; From 7e01ad940f6b04c5f26b97e373152dde87785c0a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 May 2016 10:11:28 +0800 Subject: [PATCH 1168/2794] added mangasaurus closed #252 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaSaurus.pas | 203 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaSaurus.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index b46133aab..8023135d5 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -36,4 +36,5 @@ uses MangaEden, HeyMangaXyz, WebtoonTr, - MangaDenizi; + MangaDenizi, + MangaSaurus; diff --git a/baseunits/modules/MangaSaurus.pas b/baseunits/modules/MangaSaurus.pas new file mode 100644 index 000000000..570ac8f99 --- /dev/null +++ b/baseunits/modules/MangaSaurus.pas @@ -0,0 +1,203 @@ +unit MangaSaurus; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr; + +implementation + +const + dirurl = '/browse/added/'; + domainImage = 'http://img.mangasaurus.com'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('//span[@class="pager__jumpLast"]/a/@href'); + if s <> '' then + begin + s := ReplaceRegExpr('^.+/(\d+$)', s, '$1', True); + Page := StrToIntDef(s, 1); + end; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//span[@class="comicInfo__comicTitle"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="gallery-info__cover"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1[@class="title"]'); + authors := XPathStringAll( + '//table[@class="table--info"]/tbody/tr/td[.="Author"]/following-sibling::td/ul[@class="tag-list"]/li/a'); + artists := XPathStringAll( + '//table[@class="table--info"]/tbody/tr/td[.="Artist"]/following-sibling::td/ul[@class="tag-list"]/li/a'); + genres := XPathStringAll( + '//table[@class="table--info"]/tbody/tr/td[.="Genres" or .="Contents" or .="Category"]/following-sibling::td/ul[@class="tag-list"]/li/a'); + summary := XPathString( + '//table[@class="table--info"]/tbody/tr/td[.="Description"]/following-sibling::td'); + s := XPathString('//table[@class="table--info"]/tbody/tr/td[.="Status"]/following-sibling::td/span'); + if s <> '' then + begin + s := LowerCase(s); + if Pos('ongoing', s) <> 0 then + status := MangaInfo_StatusOngoing + else if Pos('completed', s) <> 0 then + status := MangaInfo_StatusCompleted; + end; + for v in XPath('//table[@class="table--data table--chapters js-chapterList"]/tbody/tr/td/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('text()', v.toNode)); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + source: TStringList; + v: IXQValue; + i: Integer; + comicA, imagesA, slug, key, ext: String; + images: array of String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then + begin + Result := True; + comicA := ''; + imagesA := ''; + source := TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do + begin + if Pos('Mangasaurus.ImageReader.setComic(', source[i]) <> 0 then + comicA := TrimRightChar(Trim(SeparateRight(source[i], '{')), [')', ';']) + else + if Pos('Mangasaurus.ImageReader.setImages(', source[i]) <> 0 then + begin + imagesA := TrimRightChar(Trim(SeparateRight(source[i], '{')), [')', ';']); + Break; + end; + end; + finally + source.Free; + end; + if (comicA <> '') and (imagesA <> '') then + with TXQueryEngineHTML.Create('{' + comicA) do + try + slug := XPathString('json(*).slug'); + if slug <> '' then + begin + ParseHTML('{' + imagesA); + SetLength(images, 0); + for v in XPath('json(*)()') do + begin + SetLength(images, Length(images) + 1); + images[High(images)] := v.toString; + end; + if Length(images) <> 0 then + begin + for i := Low(images) to High(images) do + begin + key := XPathString('json(*)(' + images[i] + ').original.file'); + if key <> '' then + begin + ext := SeparateRight(key, '.'); + key := SeparateLeft(key, '.'); + if ext <> '' then + PageLinks.Add(domainImage + '/original/' + key + '/' + slug + '-' + images[i] + '.' + ext); + end; + end; + SetLength(images, 0); + end; + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaSaurus'; + RootURL := 'http://mangasaurus.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 3ddede82c..efbb5f6e3 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From b98845f96b91f65d1105c5ea82756e791208bab8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 May 2016 10:34:26 +0800 Subject: [PATCH 1169/2794] Bump version 0.9.56.0 --- changelog.txt | 8 ++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3d499654f..cd422b86e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.56.0 (25-05-2016) +[*] YoManga: fixed download +[*] HeyManga: fixed download +[*] Webtoons: download original images (#254) +[+] Added MangaSaurus[EN] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.55.0...0.9.56.0 + 0.9.55.0 (20-05-2016) [*] Tumangaonline: rewrite all code, require new manga list [*] Yomanga: fixed blocked by cf diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ef5dec2ca..8e816bc99 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="55"/> + <RevisionNr Value="56"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 58b1a442c..33be8c2f7 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.55.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.55.0/fmd_0.9.55.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.55.0/fmd_0.9.55.0_Win64.7z +VERSION=0.9.56.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.56.0/fmd_0.9.56.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.56.0/fmd_0.9.56.0_Win64.7z From a7306c273d9f52905121eb96e3d9666d2af77623 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 25 May 2016 21:40:42 +0800 Subject: [PATCH 1170/2794] dbdataprocess, getrecordcount before open --- baseunits/DBDataProcess.pas | 45 ++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index a959d49bd..bcacaaa84 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -366,15 +366,28 @@ procedure TDBDataProcess.VacuumTable; end; procedure TDBDataProcess.GetRecordCount; +var + bsql, s: String; + queryopen: Boolean; begin - if FQuery.Active then + FRecordCount := 0; + queryopen := FQuery.Active; + if queryopen then FQuery.Close; + bsql := Trim(FQuery.SQL.Text); + if UpperCase(LeftStr(bsql, 8)) = 'SELECT *' then begin - FQuery.Last; - FRecordCount := FQuery.RecordCount; - FQuery.Refresh; - end - else - FRecordCount := 0; + s := 'SELECT COUNT("link") as recordcount' + Copy(bsql, 9, Length(bsql)); + FQuery.SQL.Text := s; + FQuery.Open; + if FQuery.Active then + begin + FRecordCount := FQuery.Fields[0].AsInteger; + FQuery.Close; + end; + end; + FQuery.SQL.Text := bsql; + if FQuery.Active <> queryopen then + FQuery.Active := queryopen; end; procedure TDBDataProcess.AddSQLCond(const sqltext: String; useOR: Boolean); @@ -671,9 +684,9 @@ function TDBDataProcess.OpenTable(const ATableName: String; if FTrans.Active=False then FTrans.Active:=True; FSQLSelect := 'SELECT * FROM ' + QuotedStrd(FTableName); FQuery.SQL.Text := FSQLSelect; - FQuery.Open; if CheckRecordCount then GetRecordCount; + FQuery.Open; end; except on E: Exception do @@ -756,9 +769,11 @@ procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); FQuery.Refresh else if Trim(FQuery.SQL.Text) <> '' then + begin + if RecheckDataCount then + GetRecordCount; FQuery.Open; - if RecheckDataCount then - GetRecordCount; + end; end; end; @@ -892,8 +907,8 @@ function TDBDataProcess.Search(ATitle: String): Boolean; else FFiltered := FFilterApplied; end; - FQuery.Open; GetRecordCount; + FQuery.Open; except on E: Exception do WriteLog_E(Self.ClassName+'['+Website+'].Search.Error!'#13#10 + @@ -1031,6 +1046,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList GenerateSQLFilter; end; + Self.GetRecordCount; FQuery.Open; FFiltered := Active; FFilterApplied := FFiltered; @@ -1045,6 +1061,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); FQuery.Close; SQL.Text := tsql; + Self.GetRecordCount; FQuery.Open; FFilterAllSites := False; FFiltered := False; @@ -1052,7 +1069,6 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList FFilterSQL := ''; end; end; - GetRecordCount; Result := FFiltered; end; end; @@ -1089,10 +1105,7 @@ procedure TDBDataProcess.RemoveFilter; FRecordCount := 0; DetachAllSites; if FQuery.Active then - begin - OpenTable; - GetRecordCount; - end; + OpenTable(FTableName, True); end; end; From e28f8747ab04729686cfddb68a5bfd1476450f75 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 27 May 2016 01:10:42 +0800 Subject: [PATCH 1171/2794] upacker, fixed incorrectly store the full path inside archive fixed #257 --- baseunits/uPacker.pas | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 76f6689a1..9c9ff916e 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -46,10 +46,12 @@ procedure TPacker.DoZipCbz; try try FileName := FSavedFilename; - Entries.AddFileEntries(FFileList); - if Entries.Count > 0 then - for i := 0 to Entries.Count - 1 do - Entries[i].CompressionLevel := clnone; + for i := 0 to FFileList.Count - 1 do + with Entries.AddFileEntry(FFileList[i]) do + begin + CompressionLevel := clnone; + ArchiveFileName := ExtractFileName(FFileList[i]); + end; ZipAllFiles; except on E: Exception do From a6c88c3be184080f6fbc1437ac07c48cf8bf4bfa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 27 May 2016 01:52:58 +0800 Subject: [PATCH 1172/2794] baseunit, added function mangainfostatusifpos --- baseunits/uBaseUnit.pas | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cfbad2b23..1888ec646 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -823,6 +823,7 @@ function JDNToDate(const JDN: Longint): TDate; {function ConvertInt32ToStr(const aValue: Cardinal) : String; function ConvertStrToInt32(const aStr : String): Cardinal;} procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); +function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String): String; // cross platform funcs @@ -3695,6 +3696,16 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); dest.chapterLinks.Assign(Source.chapterLinks); end; +function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String): String; +begin + Result := ''; + if SearchStr = '' then Exit; + If Pos(OngoingStr, SearchStr) <> 0 then + Result := MangaInfo_StatusOngoing + else if Pos(CompletedStr, SearchStr) <> 0 then + Result := MangaInfo_StatusCompleted; +end; + { THTMLForm } constructor THTMLForm.Create; From 1227a5d077e23af5c53bdcabe469f86713847db8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 27 May 2016 03:11:37 +0800 Subject: [PATCH 1173/2794] xqueryenginehtml, publish treeparser --- baseunits/XQueryEngineHTML.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index f491283db..9560af1e9 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -36,6 +36,7 @@ TXQueryEngineHTML = class function CSSStringAll(const Expression: String; const Exc: array of String; const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; property Engine: TXQueryEngine read FEngine; + property TreeParser: TTreeParser read FTreeParser; end; IXQValue = xquery.IXQValue; @@ -103,8 +104,9 @@ function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; t: TTreeNode; begin Result := xqvalue(); - t := Tree; - if t = nil then + if Assigned(Tree) then + t := Tree + else t := FTreeParser.getLastTree; if Expression = '' then Exit; From 7dfaa81d22530c81f4b424ba7e8df23cb059a4ef Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 27 May 2016 03:41:05 +0800 Subject: [PATCH 1174/2794] baseunit, cleanstring normalize tab character --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1888ec646..9225385c5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2406,6 +2406,7 @@ function CleanString(const S: String): String; if Result = '' then Exit; Result := StringReplace(Result, #13, ' ', [rfReplaceAll]); Result := StringReplace(Result, #10, ' ', [rfReplaceAll]); + Result := StringReplace(Result, #9, ' ', [rfReplaceAll]); while Pos(' ', Result) > 0 do Result := StringReplace(Result, ' ', ' ', [rfReplaceAll]); Result := Trim(Result); From edede4a69ef5e857fe1f79239b18040d0cd1ea40 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 27 May 2016 03:41:40 +0800 Subject: [PATCH 1175/2794] udata, do cleanstring chaptername --- baseunits/uData.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 11254d586..53ac4192a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1658,8 +1658,8 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco RemoveHostFromURLsPair(chapterLinks, chapterName); // fixing chapter name for j := 0 to chapterName.Count - 1 do - chapterName.Strings[j] := Trim(RemoveStringBreaks( - CommonStringFilter(chapterName[j]))); + chapterName[j] := Trim(CleanString(RemoveStringBreaks( + CommonStringFilter(chapterName[j])))); //remove manga name from chapter if OptionRemoveMangaNameFromChapter and (title <> '') then From b62b431374417e4ee17d035e3932a5ea61338d56 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 27 May 2016 04:48:13 +0800 Subject: [PATCH 1176/2794] added gmanga closed #256 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/GMangaMe.pas | 173 +++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/GMangaMe.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 8023135d5..31ea7c25c 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -37,4 +37,5 @@ uses HeyMangaXyz, WebtoonTr, MangaDenizi, - MangaSaurus; + MangaSaurus, + GMangaMe; diff --git a/baseunits/modules/GMangaMe.pas b/baseunits/modules/GMangaMe.pas new file mode 100644 index 000000000..d3752915f --- /dev/null +++ b/baseunits/modules/GMangaMe.pas @@ -0,0 +1,173 @@ +unit GMangaMe; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/mangas'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('//ul[starts-with(@class,"pagination")]/li[last()-1]/a/@href'); + if Pos('page=', s) <> 0 then + begin + s := SeparateRight(s, 'page='); + Page := StrToIntDef(s, 1); + end; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then + s := s + '?&page=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//dd[@class="small-dd"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v, x: IXQValue; + s, t: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div/img[starts-with(@class,"img-responsive")]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="section-title en-text-center"]'); + summary := XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dd[contains(@class,"summary")]'); + authors := XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dt[.="المؤلفون"]/following-sibling::dd[1]'); + artists := XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dt[.="الرسامون"]/following-sibling::dd[1]'); + genres := XPathStringAll('//div/dl[starts-with(@class,"dl-horizontal")]/dt[.="التصنيف"]/following-sibling::dd[1]/span'); + status := MangaInfoStatusIfPos(XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dt[ends-with(.,"الـمانهوا")]/following-sibling::dd[1]'), + 'مستمرة', + 'منتهية'); + for v in XPath('//table[1]/tbody/tr') do + begin + s := XPathString('td/div[@class="c_edit"]', v.toNode); + for x in XPath('td/span[@dir="ltr"]/a', v.toNode) do + begin + chapterLinks.Add(x.toNode.getAttribute('href')); + t := x.toString; + if t <> '' then + t := ' [' + t + ']'; + chapterName.Add(s + t); + end; + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + source: TStringList; + i: Integer; + images: String; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.manager.container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then + begin + Result := True; + images := ''; + source := TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do + if Pos('chapterImgs = [', source[i]) <> 0 then + begin + images := SeparateRight(source[i], '['); + Break; + end; + finally + source.Free; + end; + if images <> '' then + with TXQueryEngineHTML.Create('[' + images) do + try + for v in XPath('json(*)()') do + PageLinks.Add(v.toString); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'GManga'; + RootURL := 'http://gmanga.me'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index efbb5f6e3..05a4589cb 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] -Arabic=MangaAe,MangaAr,MangaAt +Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga From 71970d470928756f0fedac932b1dd1a10d9216f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 03:14:00 +0800 Subject: [PATCH 1177/2794] fixed various path issue --- baseunits/includes/MeinManga/image_url.inc | 7 +-- baseunits/uDownloadsManager.pas | 31 +++++----- baseunits/uFavoritesManager.pas | 2 +- baseunits/uSilentThread.pas | 28 +++------ mangadownloader/forms/frmMain.lfm | 42 ++++++------- mangadownloader/forms/frmMain.pas | 69 ++++++++++++---------- 6 files changed, 86 insertions(+), 93 deletions(-) diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index f6c70564a..27f5f384c 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -57,9 +57,7 @@ SaveImage( manager.container.MangaSiteID, GetVal(parse[i], 'src'), - CorrectPathSys(manager.container.DownloadInfo.SaveTo + - manager.container.ChapterName[ - manager.container.CurrentDownloadChapterPtr]), + manager.container.CurrentWorkingDir, Format('%.3d', [workCounter + 1]) + '_' + IntToStr(prefix), manager.container.Manager.retryConnect); @@ -80,8 +78,7 @@ begin imageName := Format('%.3d', [workCounter + 1]); Merge2Images( - CorrectPathSys(manager.container.DownloadInfo.SaveTo + '/' + - manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr]), + manager.container.CurrentWorkingDir, imageName + '_' + IntToStr(prefix - 2) + '.jpg', imageName + '_' + IntToStr(prefix - 1) + '.jpg', imageName + '.jpg'); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b081137e8..2e78df74a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -122,6 +122,8 @@ TTaskContainer = class // download manager Manager: TDownloadManager; DownloadInfo: TDownloadInfo; + // current working dir, save to + chapter name + CurrentWorkingDir: String; // current link index CurrentPageNumber, // current chapter index @@ -985,8 +987,7 @@ procedure TTaskThread.Compress; 3: uPacker.Format := pfPDF; end; uPacker.CompressionQuality := OptionPDFQuality; - uPacker.Path := CorrectPathSys(container.DownloadInfo.SaveTo) + - container.ChapterName.Strings[container.CurrentDownloadChapterPtr]; + uPacker.Path := container.CurrentWorkingDir; uPacker.Execute; except on E: Exception do @@ -1027,8 +1028,8 @@ function TDownloadThread.DownloadImage: Boolean; begin sfilename := ''; - lpath := CleanAndExpandDirectory(CorrectPathSys(manager.container.DownloadInfo.SaveTo + - manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr])); + lpath := CleanAndExpandDirectory(manager.container.DownloadInfo.SaveTo + + manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr]); if not DirectoryExistsUTF8(lpath) then begin if not ForceDirectoriesUTF8(lpath) then @@ -1223,7 +1224,7 @@ procedure TTaskThread.Execute; var j: Integer; - S, P: String; + s: String; DynamicPageLink: Boolean; begin ModuleId := container.ModuleId; @@ -1240,14 +1241,12 @@ procedure TTaskThread.Execute; WaitForThreads; if Terminated then Exit; - //strip - container.DownloadInfo.SaveTo := CorrectPathSys(container.DownloadInfo.SaveTo); - S := CorrectPathSys(container.DownloadInfo.SaveTo + - container.ChapterName[container.CurrentDownloadChapterPtr]); //check path - if not DirectoryExistsUTF8(S) then + container.CurrentWorkingDir := CleanAndExpandDirectory(container.DownloadInfo.SaveTo + + container.ChapterName[container.CurrentDownloadChapterPtr]); + if not DirectoryExistsUTF8(container.CurrentWorkingDir) then begin - if not ForceDirectoriesUTF8(S) then + if not ForceDirectoriesUTF8(container.CurrentWorkingDir) then begin container.Status := STATUS_FAILED; container.DownloadInfo.Status := RS_FailedToCreateDir; @@ -1272,7 +1271,7 @@ procedure TTaskThread.Execute; [RS_Preparing, container.CurrentDownloadChapterPtr + 1, container.ChapterLinks.Count, - container.ChapterName.Strings[container.CurrentDownloadChapterPtr]]); + container.ChapterName[container.CurrentDownloadChapterPtr]]); container.Status := STATUS_PREPARE; CheckOut; WaitForThreads; @@ -1289,11 +1288,11 @@ procedure TTaskThread.Execute; for j := 0 to container.PageLinks.Count - 1 do begin if container.Filenames.Count = container.PageLinks.Count then - P := S + PathDelim + container.Filenames[j] + s := container.CurrentWorkingDir + container.Filenames[j] else - P := S + PathDelim + Format('%.3d', [j + 1]); + s := container.CurrentWorkingDir + Format('%.3d', [j + 1]); - if ImageFileExist(P) then + if ImageFileExist(s) then container.PageLinks[j] := 'D' else if container.PageLinks[j] = 'D' then @@ -1365,7 +1364,7 @@ procedure TTaskThread.Execute; [RS_Downloading, container.CurrentDownloadChapterPtr + 1, container.ChapterLinks.Count, - container.ChapterName.Strings[container.CurrentDownloadChapterPtr]]); + container.ChapterName[container.CurrentDownloadChapterPtr]]); while container.WorkCounter < container.PageLinks.Count do begin if Terminated then Exit; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 02af2f68d..82d51de59 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -906,7 +906,7 @@ procedure TFavoriteManager.Restore; currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); Website := ReadString(IntToStr(i), 'Website', ''); - SaveTo := CorrectPathSys(ReadString(IntToStr(i), 'SaveTo', '')); + SaveTo := CleanAndExpandDirectory(ReadString(IntToStr(i), 'SaveTo', '')); Link := ReadString(IntToStr(i), 'Link', ''); Website := Website; Status := STATUS_IDLE; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 3a9ad3194..45f28bb99 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -357,15 +357,11 @@ procedure TSilentThread.MainThreadAfterChecking; if FSavePath = '' then begin - if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH); - if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := DEFAULT_PATH; - edSaveTo.Text := CleanAndExpandDirectory(CorrectPathSys(edSaveTo.Text)); + FilledSaveTo; FSavePath := edSaveTo.Text; // save to if OptionGenerateMangaFolderName then - FSavePath := FSavePath + CustomRename( + FSavePath := AppendPathDelim(FSavePath) + CustomRename( OptionMangaCustomRename, website, title, @@ -374,9 +370,8 @@ procedure TSilentThread.MainThreadAfterChecking; '', '', OptionChangeUnicodeCharacter); - FSavePath := CorrectPathSys(FSavePath); end; - DLManager.Items[p].downloadInfo.SaveTo := FSavePath; + DLManager.Items[p].downloadInfo.SaveTo := CleanAndExpandDirectory(FSavePath); UpdateVtDownload; DLManager.CheckAndActiveTask(False); @@ -453,20 +448,13 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; title := Info.mangaInfo.title; if FSavePath = '' then begin - if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH); - if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := DEFAULT_PATH; - edSaveTo.Text := CorrectPathSys(edSaveTo.Text); + FilledSaveTo; s := edSaveTo.Text; end else - s := CorrectPathSys(FSavePath); - - s := CleanAndExpandDirectory(s); - + s := FSavePath; if OptionGenerateMangaFolderName then - s := s + CustomRename( + s := AppendPathDelim(s) + CustomRename( OptionMangaCustomRename, website, title, @@ -475,8 +463,6 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; '', '', OptionChangeUnicodeCharacter); - s := CorrectPathSys(s); - s2 := ''; if (Info.mangaInfo.numChapter > 0) then begin @@ -489,7 +475,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; IntToStr(Info.mangaInfo.numChapter), s2, website, - s, + CleanAndExpandDirectory(s), URL); UpdateVtFavorites; end; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 4923b9c18..505125860 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -36,13 +36,13 @@ object MainForm: TMainForm Height = 525 Top = 11 Width = 566 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 4 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -695,6 +695,7 @@ object MainForm: TMainForm Height = 23 Top = 150 Width = 334 + OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False ButtonWidth = 23 Glyph.Data = { @@ -1911,10 +1912,10 @@ object MainForm: TMainForm Height = 420 Top = 8 Width = 539 - ActivePage = tsGeneral + ActivePage = tsSaveTo Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 3 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2562,23 +2563,23 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 357 + ClientHeight = 392 ClientWidth = 531 object sbSaveTo: TScrollBox Left = 0 - Height = 357 + Height = 392 Top = 0 Width = 531 HorzScrollBar.Page = 198 - VertScrollBar.Page = 357 + VertScrollBar.Page = 390 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 - ClientWidth = 514 + ClientHeight = 392 + ClientWidth = 531 TabOrder = 0 object rgOptionCompress: TRadioGroup AnchorSideLeft.Control = lbDefaultDownloadPath @@ -2589,7 +2590,7 @@ object MainForm: TMainForm Left = 4 Height = 60 Top = 54 - Width = 506 + Width = 523 Anchors = [akTop, akLeft, akRight] AutoFill = True BorderSpacing.Top = 4 @@ -2603,7 +2604,7 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 40 - ClientWidth = 502 + ClientWidth = 519 Columns = 4 ItemIndex = 0 Items.Strings = ( @@ -2625,7 +2626,7 @@ object MainForm: TMainForm Left = 4 Height = 237 Top = 145 - Width = 506 + Width = 523 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 @@ -2635,14 +2636,14 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 217 - ClientWidth = 502 + ClientWidth = 519 ParentFont = False TabOrder = 4 object cbOptionRemoveMangaNameFromChapter: TCheckBox Left = 4 Height = 19 Top = 50 - Width = 494 + Width = 511 Align = alTop Caption = 'Remove manga name from chapter' ParentFont = False @@ -2652,7 +2653,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 27 - Width = 494 + Width = 511 Align = alTop Caption = 'Auto generate folder based on manga''s name' OnChange = cbOptionGenerateMangaFolderNameChange @@ -2663,7 +2664,7 @@ object MainForm: TMainForm Left = 4 Height = 15 Top = 79 - Width = 494 + Width = 511 Align = alTop BorderSpacing.Top = 10 Caption = 'Manga folder name:' @@ -2686,7 +2687,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 4 - Width = 494 + Width = 511 Align = alTop Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' ParentFont = False @@ -2817,7 +2818,7 @@ object MainForm: TMainForm Left = 4 Height = 15 Top = 8 - Width = 506 + Width = 523 Align = alTop Caption = 'Choose the default download path:' ParentColor = False @@ -2827,7 +2828,8 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 27 - Width = 506 + Width = 523 + OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False ButtonWidth = 23 Glyph.Data = { @@ -2877,7 +2879,7 @@ object MainForm: TMainForm Left = 4 Height = 0 Top = 54 - Width = 506 + Width = 523 Align = alTop AutoSize = True BevelOuter = bvNone diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3ae764508..a3e5b353d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -369,6 +369,7 @@ TMainForm = class(TForm) var CellText: String); procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure edSaveToAcceptDirectory(Sender: TObject; var Value: String); procedure edSearchChange(Sender: TObject); procedure edSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState ); @@ -606,6 +607,9 @@ TMainForm = class(TForm) // Add text to TRichMemo procedure AddTextToInfo(title, infoText: String); + // fill edSaveTo with default path + procedure FilledSaveTo; + // Show manga information procedure ShowInformation(const title, website, link: String); @@ -1559,7 +1563,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); with TTaskContainer(DLManager.Containers[xNode^.Index]) do begin if (Sender = miDownloadDeleteTaskData) and (ChapterName.Count > 0) then begin for i := 0 to ChapterName.Count - 1 do begin - f := CleanAndExpandDirectory(DownloadInfo.SaveTo) + ChapterName[i]; + f := CleanAndExpandDirectory(DownloadInfo.SaveTo + ChapterName[i]); if FileExistsUTF8(f + '.zip') then DeleteFileUTF8(f + '.zip') else if FileExistsUTF8(f + '.cbz') then @@ -1569,7 +1573,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); else if DirectoryExistsUTF8(f) then DeleteDirectory(f, False); end; - RemoveDirUTF8(CleanAndExpandDirectory(DownloadInfo.SaveTo)); + RemoveDirUTF8(DownloadInfo.SaveTo); end; TTaskContainer(DLManager.Containers[xNode^.Index]).Free; DLManager.Containers.Delete(xNode^.Index); @@ -1933,10 +1937,10 @@ procedure TMainForm.btDownloadClick(Sender: TObject); DLManager.Items[pos].DownloadInfo.Title := mangaInfo.title; DLManager.Items[pos].DownloadInfo.DateTime := Now; - s := CorrectPathSys(CleanAndExpandDirectory(edSaveTo.Text)); // save to + s := edSaveTo.Text; if OptionGenerateMangaFolderName then - s := s + CustomRename( + s := AppendPathDelim(s) + CustomRename( OptionMangaCustomRename, mangaInfo.website, mangaInfo.title, @@ -1945,8 +1949,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); '', '', OptionChangeUnicodeCharacter); - s := CorrectPathSys(s); - DLManager.Items[pos].DownloadInfo.SaveTo := s; + DLManager.Items[pos].DownloadInfo.SaveTo := CleanAndExpandDirectory(s); UpdateVtDownload; DLManager.CheckAndActiveTask; @@ -1965,11 +1968,10 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); begin if mangaInfo.title <> '' then begin - s := CorrectPathSys(edSaveTo.Text); - // save to + s := edSaveTo.Text; if OptionGenerateMangaFolderName then - s := s + CustomRename( + s := AppendPathDelim(s) + CustomRename( OptionMangaCustomRename, mangaInfo.website, mangaInfo.title, @@ -1978,17 +1980,15 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); '', '', OptionChangeUnicodeCharacter); - s := CorrectPathSys(s); + // downloaded chapters s2 := ''; - if (mangaInfo.numChapter > 0) {AND (mangaInfo.website = MANGASTREAM_NAME)} then - begin + if mangaInfo.numChapter > 0 then for i := 0 to mangaInfo.numChapter - 1 do s2 := s2 + mangaInfo.chapterLinks.Strings[i] + SEPERATOR; - end; FavoriteManager.Add(mangaInfo.title, IntToStr(mangaInfo.numChapter), s2, - mangaInfo.website, s, mangaInfo.link); + mangaInfo.website, CleanAndExpandDirectory(s), mangaInfo.link); vtFavorites.NodeDataSize := SizeOf(TFavoriteInfo); UpdateVtFavorites; btAddToFavorites.Enabled := False; @@ -2232,6 +2232,11 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; +procedure TMainForm.edSaveToAcceptDirectory(Sender: TObject; var Value: String); +begin + Value := CleanAndExpandDirectory(Value); +end; + procedure TMainForm.edURLKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then @@ -2920,9 +2925,7 @@ procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); begin if (vtDownload.SelectedCount = 0) or (Assigned(vtDownload.FocusedNode) = False) then Exit; - OpenDocument(TrimRightChar( - DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo, - [PathDelim])); + OpenDocument(ChompPathDelim(DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo)); end; procedure TMainForm.miFavoritesOpenWithClick(Sender: TObject); @@ -2961,20 +2964,18 @@ procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); f, fd, ff: String; Info: TSearchRec; l: TStringList; + task: TTaskContainer; begin if (not Assigned(vtDownload.FocusedNode)) then Exit; + task := DLManager.Items[vtDownload.FocusedNode^.Index]; l := TStringList.Create; try - fd := StringReplace(DLManager.Items[ - vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo, '/', '\', [rfReplaceAll]); - if fd[Length(fd)] <> PathDelim then - fd := fd + PathDelim; + fd := task.DownloadInfo.SaveTo; - if DLManager.Items[vtDownload.FocusedNode^.Index].ChapterName.Count > 0 then + if task.ChapterName.Count > 0 then begin - ff := DLManager.Items[vtDownload.FocusedNode^.Index]. - ChapterName[0]; + ff := task.ChapterName[0]; if FileExistsUTF8(fd + ff + '.zip') then f := ff + '.zip' else if FileExistsUTF8(fd + ff + '.cbz') then @@ -4104,16 +4105,24 @@ procedure TMainForm.AddTextToInfo(title, infoText: String); end; end; +procedure TMainForm.FilledSaveTo; +begin + if Trim(edSaveTo.Text) = '' then + begin + edSaveTo.Text := Trim(configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH)); + if edSaveTo.Text = '' then + edSaveTo.Text := DEFAULT_PATH; + end + else + edSaveTo.Text := CleanAndExpandDirectory(edSaveTo.Text); +end; + procedure TMainForm.ShowInformation(const title, website, link: String); var i: Integer; begin pcMain.ActivePage := tsInformation; - if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH); - if Trim(edSaveTo.Text) = '' then - edSaveTo.Text := DEFAULT_PATH; - edSaveTo.Text := CorrectPathSys(edSaveTo.Text); + FilledSaveTo; with rmInformation do begin @@ -4340,7 +4349,7 @@ procedure TMainForm.SaveOptions; // saveto if Trim(edOptionDefaultPath.Text) = '' then edOptionDefaultPath.Text := DEFAULT_PATH; - edOptionDefaultPath.Text := CorrectPathSys(edOptionDefaultPath.Text); + edOptionDefaultPath.Text := CleanAndExpandDirectory(edOptionDefaultPath.Text); WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); WriteBool('saveto', 'ChangeUnicodeCharacter', cbOptionChangeUnicodeCharacter.Checked); WriteBool('saveto', 'GenerateMangaName', cbOptionGenerateMangaFolderName.Checked); From 210edaf5e7bf88e11087a5b1ec9ebeda34240c9d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 03:27:33 +0800 Subject: [PATCH 1178/2794] Bump version 0.9.57.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index cd422b86e..09c7ab7de 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.57.0 (28-05-2016) +[*] Fixed incorrectly store full path inside archive (zip/cbz) +[+] Added GManga[AR] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.56.0...0.9.57.0 + 0.9.56.0 (25-05-2016) [*] YoManga: fixed download [*] HeyManga: fixed download diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8e816bc99..eaea90b5b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="56"/> + <RevisionNr Value="57"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 33be8c2f7..1d2fc82b2 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.56.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.56.0/fmd_0.9.56.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.56.0/fmd_0.9.56.0_Win64.7z +VERSION=0.9.57.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.57.0/fmd_0.9.57.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.57.0/fmd_0.9.57.0_Win64.7z From c1cc1f72d65046294cb3a88dc2609702c23683bd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 15:29:17 +0800 Subject: [PATCH 1179/2794] downloadmanager, properly show ballon hint when failed --- baseunits/uDownloadsManager.pas | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2e78df74a..875624f2f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1004,20 +1004,26 @@ procedure TTaskThread.SyncStop; procedure TTaskThread.SyncShowBaloon; begin - if container.Status = STATUS_FAILED then + with MainForm.TrayIcon, container.DownloadInfo do begin - MainForm.TrayIcon.BalloonFlags := bfError; - MainForm.TrayIcon.BalloonHint := - '"' + container.DownloadInfo.title + '" - ' + RS_Failed;; - end - else - if container.Status = STATUS_FINISH then - begin - MainForm.TrayIcon.BalloonFlags := bfInfo; - MainForm.TrayIcon.BalloonHint := - '"' + container.DownloadInfo.title + '" - ' + RS_Finish; + if container.Status = STATUS_FAILED then + begin + BalloonFlags := bfError; + BalloonHint := QuotedStrd(Title); + if Status = '' then + BalloonHint := BalloonHint + ' - ' + RS_Failed + else + BalloonHint := BalloonHint + LineEnding + Status; + end + else + if container.Status = STATUS_FINISH then + begin + BalloonFlags := bfInfo; + BalloonHint := + '"' + container.DownloadInfo.title + '" - ' + RS_Finish; + end; + ShowBalloonHint; end; - MainForm.TrayIcon.ShowBalloonHint; end; function TDownloadThread.DownloadImage: Boolean; @@ -1245,14 +1251,13 @@ procedure TTaskThread.Execute; container.CurrentWorkingDir := CleanAndExpandDirectory(container.DownloadInfo.SaveTo + container.ChapterName[container.CurrentDownloadChapterPtr]); if not DirectoryExistsUTF8(container.CurrentWorkingDir) then - begin if not ForceDirectoriesUTF8(container.CurrentWorkingDir) then begin container.Status := STATUS_FAILED; container.DownloadInfo.Status := RS_FailedToCreateDir; + SyncShowBaloon; Exit; end; - end; if ModuleId > -1 then Modules.TaskStart(container, ModuleId); From ac13993dd8ccf4fa02ec818c1b078bfb93fb10a9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 16:26:51 +0800 Subject: [PATCH 1180/2794] downloadmanager, fixed and cleanup downloadimage --- baseunits/uDownloadsManager.pas | 91 +++++++++++++++++---------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 875624f2f..3d3dc7ec6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -31,7 +31,6 @@ TDownloadThread = class(TFMDThread) private parse: TStringList; checkStyle: TFlagType; - ModuleId: Integer; public workCounter: Integer; FSortColumn: Cardinal; @@ -66,14 +65,12 @@ TDownloadThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; public - // ID of the site manager: TTaskThread; constructor Create; destructor Destroy; override; property SortColumn: Cardinal read FSortColumn write FSortColumn; property AnotherURL: String read FAnotherURL write FAnotherURL; - property GetworkCounter: Integer read workCounter; end; { TTaskThread } @@ -270,7 +267,6 @@ constructor TDownloadThread.Create; FHTTP := THTTPSendThread.Create(Self); FHTTP.Headers.NameValueSeparator := ':'; FHTTP.Sock.OnStatus := SockOnStatus; - ModuleId := -1; end; destructor TDownloadThread.Destroy; @@ -361,7 +357,7 @@ procedure TDownloadThread.DoTerminate; begin LockCreateConnection; try - Modules.DecActiveConnectionCount(ModuleId); + Modules.DecActiveConnectionCount(manager.ModuleId); manager.threads.Remove(Self); finally UnlockCreateConnection; @@ -461,8 +457,8 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := False; manager.container.PageNumber := 0; - if Modules.ModuleAvailable(ModuleId, MMGetPageNumber) then - Result := Modules.GetPageNumber(Self, URL, ModuleId) + if Modules.ModuleAvailable(manager.ModuleId, MMGetPageNumber) then + Result := Modules.GetPageNumber(Self, URL, manager.ModuleId) else begin if manager.container.MangaSiteID = ANIMEA_ID then @@ -701,8 +697,8 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; (manager.container.PageLinks.Strings[workCounter] <> 'W') then Exit; - if Modules.ModuleAvailable(ModuleId, MMGetImageURL) then - Result := Modules.GetImageURL(Self, URL, ModuleId) + if Modules.ModuleAvailable(manager.ModuleId, MMGetImageURL) then + Result := Modules.GetImageURL(Self, URL, manager.ModuleId) else begin if manager.container.MangaSiteID = ANIMEA_ID then @@ -1028,57 +1024,65 @@ procedure TTaskThread.SyncShowBaloon; function TDownloadThread.DownloadImage: Boolean; var - s, TURL, lpath, lname, sfilename: String; + workFilename, + workURL, + savedFilename: String; {$I includes/MeinManga/image_url.inc} begin - sfilename := ''; - lpath := CleanAndExpandDirectory(manager.container.DownloadInfo.SaveTo + - manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr]); - if not DirectoryExistsUTF8(lpath) then - begin - if not ForceDirectoriesUTF8(lpath) then + Result := True; + + // check download path + if not DirectoryExistsUTF8(manager.container.CurrentWorkingDir) then + if not ForceDirectoriesUTF8(manager.container.CurrentWorkingDir) then begin manager.container.Status := STATUS_FAILED; manager.container.DownloadInfo.Status := RS_FailedToCreateDir; Result := False; Exit; end; - end; - Result := True; - TURL := manager.container.PageLinks[workCounter]; - if (TURL = '') or (TURL = 'W') or (TURL = 'D') then + // check pagelinks url + workURL := manager.container.PageLinks[workCounter]; + if (workURL = '') or + (workURL = 'W') or + (workURL = 'D') then Exit; FHTTP.Clear; - if Modules.ModuleAvailable(ModuleId, MMBeforeDownloadImage) then - Result := Modules.BeforeDownloadImage(Self, TURL, ModuleId); + // call beforedownloadimage if available + if Modules.ModuleAvailable(manager.ModuleId, MMBeforeDownloadImage) then + Result := Modules.BeforeDownloadImage(Self, workURL, manager.ModuleId); - lname := ''; + // prepare filename + workFilename := ''; if workCounter < manager.container.Filenames.Count then - lname := manager.container.Filenames[workCounter]; - if lname = '' then - lname := Format('%.3d', [workCounter + 1]); + workFilename := manager.container.Filenames[workCounter]; + if workFilename = '' then + workFilename := Format('%.3d', [workCounter + 1]); - if Result then begin - if Modules.ModuleAvailable(ModuleId, MMDownloadImage) then begin - s := ''; + // download image + savedFilename := ''; + if Result then + begin + if Modules.ModuleAvailable(manager.ModuleId, MMDownloadImage) then + begin + workURL := ''; if (manager.container.PageNumber = manager.container.PageContainerLinks.Count) and (workCounter < manager.container.PageContainerLinks.Count) then - s := manager.container.PageContainerLinks[workCounter] + workURL := manager.container.PageContainerLinks[workCounter] else if workCounter < manager.container.PageLinks.Count then - s := manager.container.PageLinks[workCounter]; + workURL := manager.container.PageLinks[workCounter]; - if s <> '' then + if workURL <> '' then Result := Modules.DownloadImage( Self, - s, - lpath, - lname, - ModuleId); + workURL, + manager.container.CurrentWorkingDir, + workFilename, + manager.ModuleId); end else if manager.container.MangaSiteID = MEINMANGA_ID then @@ -1087,18 +1091,19 @@ function TDownloadThread.DownloadImage: Boolean; Result := uBaseUnit.SaveImage( FHTTP, manager.container.MangaSiteID, - TURL, - lpath, - lname, - sfilename, + workURL, + manager.container.CurrentWorkingDir, + workFilename, + savedFilename, manager.container.Manager.retryConnect); end; if Terminated then Exit(False); - if Result then begin + if Result then + begin manager.container.PageLinks[workCounter] := 'D'; - if Modules.ModuleAvailable(ModuleId, MMAfterImageSaved) then - Modules.AfterImageSaved(sfilename, ModuleId); + if Modules.ModuleAvailable(manager.ModuleId, MMAfterImageSaved) then + Modules.AfterImageSaved(savedFilename, manager.ModuleId); end; end; From 007bc938f9f2faf9a4cb17ee985269252994e1ab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 16:38:23 +0800 Subject: [PATCH 1181/2794] downlodmanager, fixed properly show status after task stopped --- baseunits/uDownloadsManager.pas | 36 ++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 3d3dc7ec6..138d7848c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1472,25 +1472,29 @@ procedure TTaskThread.DoTerminate; finally Manager.CS_Task.Release; end; - if (Status <> STATUS_STOP) and (not Manager.isReadyForExit) then + if not Manager.isReadyForExit then begin - if (WorkCounter >= PageLinks.Count) and - (CurrentDownloadChapterPtr >= ChapterLinks.Count) - and (FailedChapterLinks.Count = 0) then + if Status <> STATUS_STOP then begin - Status := STATUS_FINISH; - DownloadInfo.Status := RS_Finish; - DownloadInfo.Progress := ''; - end - else - begin - Status := STATUS_STOP; - DownloadInfo.Status := - Format('%s (%d/%d)', [RS_Stopped, CurrentDownloadChapterPtr + - 1, ChapterLinks.Count]); - FCheckAndActiveTaskFlag := False; + if (WorkCounter >= PageLinks.Count) and + (CurrentDownloadChapterPtr >= ChapterLinks.Count) and + (FailedChapterLinks.Count = 0) then + begin + Status := STATUS_FINISH; + DownloadInfo.Status := RS_Finish; + DownloadInfo.Progress := ''; + end + else + if not (Status in [STATUS_FAILED, STATUS_PROBLEM]) then + begin + Status := STATUS_STOP; + DownloadInfo.Status := + Format('%s (%d/%d)', [RS_Stopped, CurrentDownloadChapterPtr + + 1, ChapterLinks.Count]); + FCheckAndActiveTaskFlag := False; + end; + Synchronize(SyncStop); end; - Synchronize(SyncStop); end; end; inherited DoTerminate; From 1d2faa7f844383c13cc882a8f8219e5f6bb2b20a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 16:57:43 +0800 Subject: [PATCH 1182/2794] downloadmanager, fixed stopalltask and some cleanup do not validate for task id, throw the error instead --- baseunits/uDownloadsManager.pas | 42 +++++++++++++++------------------ 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 138d7848c..d732cbeba 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1556,7 +1556,6 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); function TDownloadManager.GetItems(Index: Integer): TTaskContainer; begin - if (Index < 0) or (Containers.Count = 0) then Exit(nil); Result := TTaskContainer(Containers[Index]); end; @@ -1862,7 +1861,6 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); procedure TDownloadManager.SetTaskActive(const taskID: Integer); begin - if (taskID < 0) or (taskID >= Containers.Count) then Exit; with TTaskContainer(Containers[taskID]) do if not ThreadState then begin @@ -1901,7 +1899,6 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; procedure TDownloadManager.ActiveTask(const taskID: Integer); begin - if (taskID < 0) or (taskID >= Containers.Count) then Exit; with TTaskContainer(Containers[taskID]) do begin if Status = STATUS_FINISH then Exit; if not ThreadState then begin @@ -1921,17 +1918,21 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); procedure TDownloadManager.StopTask(const taskID: Integer; const isCheckForActive: Boolean; isWaitFor: Boolean); begin - if (taskID < 0) or (taskID >= Containers.Count) then Exit; - with TTaskContainer(Containers[taskID]) do begin - if Status = STATUS_WAIT then begin + with TTaskContainer(Containers[taskID]) do + begin + if Status = STATUS_WAIT then + begin Status := STATUS_STOP; DownloadInfo.Status := RS_Stopped; end - else if ThreadState then begin + else if ThreadState then + begin Thread.Terminate; - if isWaitFor then Thread.WaitFor; + if isWaitFor then + Thread.WaitFor; end; - if isCheckForActive then CheckAndActiveTask(); + if isCheckForActive then + CheckAndActiveTask(); end; end; @@ -1939,10 +1940,12 @@ procedure TDownloadManager.StartAllTasks; var i: Integer; begin - if Containers.Count > 0 then begin + if Containers.Count > 0 then + begin for i := 0 to Containers.Count - 1 do with TTaskContainer(Containers[i]) do - if (Status <> STATUS_FINISH) and (not ThreadState) then begin + if (Status <> STATUS_FINISH) and (not ThreadState) then + begin Status := STATUS_WAIT; DownloadInfo.Status := RS_Waiting; end; @@ -1954,23 +1957,17 @@ procedure TDownloadManager.StopAllTasks; var i: Integer; begin - if Containers.Count > 0 then begin - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do - if ThreadState then - Thread.Terminate - else if Status <> STATUS_FINISH then begin - Status := STATUS_STOP; - DownloadInfo.Status := RS_Stopped; - end; - end; + if Containers.Count = 0 then Exit; + for i := 0 to Containers.Count - 1 do + StopTask(i, False, False); end; procedure TDownloadManager.StopAllDownloadTasksForExit; var i: Integer; begin - if Containers.Count > 0 then begin + if Containers.Count > 0 then + begin isReadyForExit := True; try for i := 0 to Containers.Count - 1 do @@ -1989,7 +1986,6 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; procedure TDownloadManager.RemoveTask(const taskID: Integer); begin - if (taskID < 0) or (taskID >= Containers.Count) then Exit; CS_Task.Acquire; try with TTaskContainer(Containers[taskID]) do From 4f022a8b1c91d3e5bec62c524529a87d626b38bc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 17:56:17 +0800 Subject: [PATCH 1183/2794] downloadmanager, move merge2image to baseunit --- baseunits/includes/MeinManga/image_url.inc | 2 +- baseunits/uBaseUnit.pas | 91 +++++++++++++++++++++- baseunits/uDownloadsManager.pas | 77 +----------------- 3 files changed, 90 insertions(+), 80 deletions(-) diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index 27f5f384c..8df124390 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -77,7 +77,7 @@ if prefix = 2 then begin imageName := Format('%.3d', [workCounter + 1]); - Merge2Images( + Merge2Image( manager.container.CurrentWorkingDir, imageName + '_' + IntToStr(prefix - 2) + '.jpg', imageName + '_' + IntToStr(prefix - 1) + '.jpg', diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9225385c5..5e268af02 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -20,9 +20,9 @@ interface {$endif} SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, dateutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, - FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, - synacode, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, - xquery, xquery_json, Imaging, ImagingExtras, SimpleException, SimpleLogger; + FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, + GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, + xquery_json, Imaging, ImagingTypes, ImagingExtras, SimpleException, SimpleLogger; const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -809,6 +809,12 @@ function SaveImage(const mangaSiteID: Integer; URL: String; // check file exist with known extensions. AFilename is a filename without extensions function ImageFileExist(const AFilename: String): Boolean; +// load TImageData from file with UTF8 aware +function LoadImageDataFromFileUTF8(const FileName: String; var Image: TImageData): Boolean; + +// merge 2 images to one +function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; const Landscape: Boolean = False): Boolean; + procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); // This method uses to sort the data. Use when we load all the lists. @@ -3497,6 +3503,85 @@ function ImageFileExist(const AFilename: String): Boolean; (FileExistsUTF8(AFilename + '.gif')); end; +function LoadImageDataFromFileUTF8(const FileName: String; var Image: TImageData): Boolean; +var + f: TFileStreamUTF8; +begin + Result := False; + FreeImage(Image); + if not FileExistsUTF8(FileName) then Exit; + f := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + Result := LoadImageFromStream(f, Image); + finally + f.Free; + end; +end; + +function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; const Landscape: Boolean): Boolean; +var + dir, ext, fullImgName1, fullImgName2, fullFileName: String; + img1, img2, imgProc: TImageData; + fileStream: TFileStreamUTF8; + newWidth, newHeigth: LongInt; +begin + Result := False; + dir := CleanAndExpandDirectory(Directory); + if not DirectoryExistsUTF8(dir) then Exit; + fullImgName1 := dir + ImgName1; + fullImgName2 := dir + ImgName2; + if not (FileExistsUTF8(fullImgName1) and FileExistsUTF8(fullImgName2)) then Exit; + InitImage(img1); + InitImage(img2); + InitImage(imgProc); + try + if LoadImageDataFromFileUTF8(fullImgName1, img1) and + LoadImageDataFromFileUTF8(fullImgName2, img2) then + begin + if Landscape then + begin + newWidth := img1.Width + img2.Width; + newHeigth := max(img1.Height, img2.Height); + end + else + begin + newWidth := max(img1.Width, img2.Width); + newHeigth := img1.Height + img2.Height; + end; + NewImage(newWidth, newHeigth, ifR8G8B8, imgProc); + CopyRect(img1, 0, 0, img1.Width, img1.Width, imgProc, 0, 0); + if Landscape then + CopyRect(img2, 0, 0, img2.Width, img2.Width, imgProc, img1.Width + 1, 0) + else + CopyRect(img2, 0, 0, img2.Width, img2.Width, imgProc, 0, img1.Height + 1); + fullFileName := dir + FinalName; + if FileExistsUTF8(fullFileName) then + DeleteFileUTF8(fullFileName); + if not FileExistsUTF8(fullFileName) then + begin + fileStream := TFileStreamUTF8.Create(fullFileName, fmCreate); + try + ext := ExtractFileExt(fullFileName); + if ext <> '' then + SaveImageToStream(ext, fileStream, imgProc); + finally + fileStream.Free; + end; + Result := FileExistsUTF8(fullFileName); + if Result then + begin + DeleteFileUTF8(fullImgName1); + DeleteFileUTF8(fullImgName2); + end; + end; + end; + finally + FreeImage(img1); + FreeImage(img2); + FreeImage(imgProc); + end; +end; + procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QSort(L, R: Cardinal); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d732cbeba..974ce4011 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -38,10 +38,7 @@ TDownloadThread = class(TFMDThread) FHTTP: THTTPSendThread; procedure MainThreadMessageDialog; - // Helper method allows to merge 2 images into 1 image. - // Final image format: png. (too big!) - procedure Merge2Images(const path, imgName1, imgName2, finalName: String); - // wait for changing directoet completed + // wait for changing directory completed procedure SetChangeDirectoryFalse; procedure SetChangeDirectoryTrue; // Get download link from URL @@ -855,78 +852,6 @@ procedure TDownloadThread.MainThreadMessageDialog; MessageDlg('TDownloadThread', FMessage, mtInformation, [mbOK], ''); end; -procedure TDownloadThread.Merge2Images( - const path, imgName1, imgName2, finalName: String); -var - rect: TRect; - img1, img2, finalImg: TImageData; - cv1, cv2, canvas: TImagingCanvas; - stream: TFileStreamUTF8; - fullImgName1, fullImgName2, fullFinalImgName, fext: String; -begin - fullImgName1 := Path + '/' + imgName1; - fullImgName2 := Path + '/' + imgName2; - fullFinalImgName := Path + '/' + finalName; - - if (not FileExistsUTF8(fullImgName1)) or (not FileExistsUTF8(fullImgName2)) then - Exit; - - Initialize(img1); - Initialize(img2); - Initialize(finalImg); - // Load first image to stream. - stream := TFileStreamUTF8.Create(fullImgName1, fmOpenRead); - LoadImageFromStream(stream, img1); - stream.Free; - cv1 := TImagingCanvas.CreateForData(@img1); - - // Load second image to stream. - stream := TFileStreamUTF8.Create(fullImgName2, fmOpenRead); - LoadImageFromStream(stream, img2); - stream.Free; - cv2 := TImagingCanvas.CreateForData(@img2); - - // Create new buffer for merging images ... - NewImage(img1.Width, img1.Height + img2.Height, ifR8G8B8, finalImg); - canvas := TImagingCanvas.CreateForData(@finalImg); - - // Merge images. - rect.Left := 0; - rect.Top := 0; - rect.Right := img1.Width; - rect.Bottom := img1.Height; - cv1.DrawBlend(rect, canvas, 0, 0, bfOne, bfZero); - - rect.Left := 0; - rect.Top := 0; - rect.Right := img2.Width; - rect.Bottom := img2.Height; - cv2.DrawBlend(rect, canvas, 0, img1.Height, bfOne, bfZero); - - // Save final image. - if FileExistsUTF8(fullFinalImgName) then - DeleteFileUTF8(fullFinalImgName); - stream := TFileStreamUTF8.Create(fullFinalImgName, fmCreate); - //SaveImageToStream('png', stream, finalImg); - fext := ExtractFileExt(finalName); - if fext[1] = '.' then - fext := Copy(fext, 2, Length(fext) - 1); - SaveImageToStream(fext, stream, finalImg); - stream.Free; - - // Remove old images. - DeleteFileUTF8(fullImgName1); - DeleteFileUTF8(fullImgName2); - - // Free memory. - cv1.Free; - cv2.Free; - canvas.Free; - FreeImage(img1); - FreeImage(img2); - FreeImage(finalImg); -end; - procedure TDownloadThread.SetChangeDirectoryFalse; begin isChangeDirectory := False; From 8099345068137241c876c1525c00aec9c125d9d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 18:53:04 +0800 Subject: [PATCH 1184/2794] downloadmanager, rename some variable name to make sense --- .../AnimExtremist/chapter_page_number.inc | 6 +- .../includes/AnimExtremist/image_url.inc | 4 +- .../includes/AnimeA/chapter_page_number.inc | 6 +- baseunits/includes/AnimeA/image_url.inc | 4 +- .../AnimeStory/chapter_page_number.inc | 6 +- baseunits/includes/AnimeStory/image_url.inc | 4 +- baseunits/includes/BlogTruyen/image_url.inc | 6 +- .../includes/CentralDeMangas/image_url.inc | 6 +- .../CentrumMangi_PL/chapter_page_number.inc | 6 +- .../includes/CentrumMangi_PL/image_url.inc | 6 +- .../Dynasty-Scans/chapter_page_number.inc | 4 +- .../includes/EGScans/chapter_page_number.inc | 6 +- baseunits/includes/EGScans/image_url.inc | 6 +- .../includes/EatManga/chapter_page_number.inc | 6 +- baseunits/includes/EatManga/image_url.inc | 4 +- .../EsMangaHere/chapter_page_number.inc | 6 +- baseunits/includes/EsMangaHere/image_url.inc | 6 +- .../ExtremeMangas/chapter_page_number.inc | 10 +- baseunits/includes/Fakku/image_url.inc | 6 +- .../HugeManga/chapter_page_number.inc | 6 +- baseunits/includes/HugeManga/image_url.inc | 4 +- .../includes/IKomik/chapter_page_number.inc | 8 +- baseunits/includes/IKomik/image_url.inc | 4 +- .../JapanShin/chapter_page_number.inc | 6 +- baseunits/includes/JapanShin/image_url.inc | 4 +- .../includes/Japscan/chapter_page_number.inc | 8 +- baseunits/includes/Japscan/image_url.inc | 4 +- .../includes/Kivmanga/chapter_page_number.inc | 6 +- baseunits/includes/Kivmanga/image_url.inc | 4 +- .../includes/Komikid/chapter_page_number.inc | 6 +- baseunits/includes/Komikid/image_url.inc | 4 +- .../LectureEnLigne/chapter_page_number.inc | 4 +- .../includes/LectureEnLigne/image_url.inc | 4 +- baseunits/includes/Mabuns/image_url.inc | 8 +- baseunits/includes/Manga24h/image_url.inc | 6 +- .../includes/MangaAe/chapter_page_number.inc | 8 +- baseunits/includes/MangaAe/image_url.inc | 4 +- .../includes/MangaAr/chapter_page_number.inc | 8 +- baseunits/includes/MangaAr/image_url.inc | 6 +- .../includes/MangaAt/chapter_page_number.inc | 6 +- baseunits/includes/MangaAt/image_url.inc | 4 +- baseunits/includes/MangaEsta/image_url.inc | 8 +- .../includes/MangaGo/chapter_page_number.inc | 6 +- baseunits/includes/MangaGo/image_url.inc | 4 +- .../MangaHost/chapter_page_number.inc | 6 +- baseunits/includes/MangaHost/image_url.inc | 4 +- .../includes/MangaInn/chapter_page_number.inc | 6 +- baseunits/includes/MangaInn/image_url.inc | 4 +- .../includes/MangaKu/chapter_page_number.inc | 8 +- .../MangaLib_PL/chapter_page_number.inc | 10 +- baseunits/includes/MangaLib_PL/image_url.inc | 6 +- .../MangaMint/chapter_page_number.inc | 6 +- baseunits/includes/MangaMint/image_url.inc | 4 +- .../includes/MangaOku/chapter_page_number.inc | 6 +- baseunits/includes/MangaOku/image_url.inc | 4 +- .../MangaPark/chapter_page_number.inc | 6 +- baseunits/includes/MangaPark/image_url.inc | 6 +- .../includes/MangaREADER_POR/image_url.inc | 8 +- .../includes/MangaSee/chapter_page_number.inc | 8 +- .../MangaTown/chapter_page_number.inc | 6 +- baseunits/includes/MangaTown/image_url.inc | 4 +- .../MangaTraders/chapter_page_number.inc | 6 +- baseunits/includes/MangaTraders/image_url.inc | 4 +- .../includes/Mangacow/chapter_page_number.inc | 4 +- baseunits/includes/Mangacow/image_url.inc | 4 +- .../includes/MangasPROJECT/image_url.inc | 6 +- .../MeinManga/chapter_page_number.inc | 14 +- baseunits/includes/MeinManga/image_url.inc | 18 +- .../chapter_page_number.inc | 12 +- .../includes/NHentai/chapter_page_number.inc | 8 +- baseunits/includes/NHentai/image_url.inc | 4 +- .../NineManga/chapter_page_number.inc | 8 +- baseunits/includes/NineManga/image_url.inc | 6 +- .../includes/OneManga/chapter_page_number.inc | 6 +- baseunits/includes/OneManga/image_url.inc | 4 +- .../PornComix/chapter_page_number.inc | 24 +- baseunits/includes/PornComix/image_url.inc | 8 +- .../ReadMangaToday/chapter_page_number.inc | 8 +- .../includes/S2Scans/chapter_page_number.inc | 6 +- baseunits/includes/ScanManga/image_url.inc | 6 +- .../includes/Starkana/chapter_page_number.inc | 6 +- baseunits/includes/Starkana/image_url.inc | 4 +- .../includes/TruyenTranhTuan/image_url.inc | 6 +- .../Turkcraft/chapter_page_number.inc | 6 +- baseunits/includes/Turkcraft/image_url.inc | 4 +- .../UnixManga/chapter_page_number.inc | 14 +- baseunits/includes/UnixManga/image_url.inc | 6 +- baseunits/includes/VnSharing/image_url.inc | 6 +- baseunits/modules/AcademyVN.pas | 2 +- baseunits/modules/Batoto.pas | 4 +- baseunits/modules/Doujinmoeus.pas | 2 +- baseunits/modules/EHentai.pas | 4 +- baseunits/modules/EightMuses.pas | 4 +- baseunits/modules/FoOlSlide.pas | 4 +- baseunits/modules/GMangaMe.pas | 2 +- baseunits/modules/GameofScanlation.pas | 4 +- baseunits/modules/Hakihome.pas | 4 +- baseunits/modules/Hentai2Read.pas | 4 +- baseunits/modules/HentaiCafe.pas | 2 +- baseunits/modules/HeyMangaXyz.pas | 4 +- baseunits/modules/HitomiLa.pas | 2 +- baseunits/modules/KissManga.pas | 2 +- baseunits/modules/Luscious.pas | 2 +- baseunits/modules/Madokami.pas | 2 +- baseunits/modules/MangaBackup.pas | 2 +- baseunits/modules/MangaChanRU.pas | 2 +- baseunits/modules/MangaDenizi.pas | 2 +- baseunits/modules/MangaEden.pas | 4 +- baseunits/modules/MangaFox.pas | 4 +- baseunits/modules/MangaHere.pas | 4 +- baseunits/modules/MangaKoi.pas | 4 +- baseunits/modules/MangaLife.pas | 2 +- baseunits/modules/MangaReader.pas | 4 +- baseunits/modules/MangaSaurus.pas | 2 +- baseunits/modules/MangaStream.pas | 4 +- baseunits/modules/MangaStreamTo.pas | 4 +- baseunits/modules/MangaTr.pas | 4 +- baseunits/modules/Mangacan.pas | 2 +- baseunits/modules/MintMangaRU.pas | 2 +- baseunits/modules/PecintaKomik.pas | 4 +- baseunits/modules/RawSenManga.pas | 6 +- baseunits/modules/Seemh.pas | 2 +- baseunits/modules/Submanga.pas | 4 +- baseunits/modules/Tsumino.pas | 2 +- baseunits/modules/Tumangaonline.pas | 2 +- baseunits/modules/UnionMangas.pas | 2 +- baseunits/modules/WPManga.pas | 4 +- baseunits/modules/WebtoonTr.pas | 2 +- baseunits/modules/Webtoons.pas | 4 +- baseunits/uDownloadsManager.pas | 660 +++++++++--------- 130 files changed, 672 insertions(+), 672 deletions(-) diff --git a/baseunits/includes/AnimExtremist/chapter_page_number.inc b/baseunits/includes/AnimExtremist/chapter_page_number.inc index 7e1c9c640..9e5bc20f8 100644 --- a/baseunits/includes/AnimExtremist/chapter_page_number.inc +++ b/baseunits/includes/AnimExtremist/chapter_page_number.inc @@ -8,7 +8,7 @@ Result := GetPage(TObject(l), StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), '.html', '', []) + '-1.html', - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -16,12 +16,12 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if Pos('</select>', parse[i]) > 0 then begin - manager.container.PageNumber := + Task.Container.PageNumber := StrToInt(GetString(TrimLeft(TrimRight(parse[i - 3] + '~!@')), 'Pagina ', '~!@')); Break; end; diff --git a/baseunits/includes/AnimExtremist/image_url.inc b/baseunits/includes/AnimExtremist/image_url.inc index d754211d9..eca64a9a0 100644 --- a/baseunits/includes/AnimExtremist/image_url.inc +++ b/baseunits/includes/AnimExtremist/image_url.inc @@ -9,7 +9,7 @@ '.html', '', []) + '-' + IntToStr(workCounter + 1) + '.html'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -23,7 +23,7 @@ if (Pos('id="photo"', parse[i]) > 0) then begin s := GetVal(parse[i], 'src'); - manager.container.pageLinks[workCounter] := + Task.Container.pageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/AnimeA/chapter_page_number.inc b/baseunits/includes/AnimeA/chapter_page_number.inc index 6056791f0..69b3bc0cf 100644 --- a/baseunits/includes/AnimeA/chapter_page_number.inc +++ b/baseunits/includes/AnimeA/chapter_page_number.inc @@ -4,11 +4,11 @@ l: TStringList; isPage: Boolean = False; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(ANIMEA_ID, StringReplace(URL, '.html', '', [])) + - '.html', manager.container.Manager.retryConnect); + '.html', Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -30,7 +30,7 @@ Break; end; if isPage and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/AnimeA/image_url.inc b/baseunits/includes/AnimeA/image_url.inc index afc2a933d..7740106a1 100644 --- a/baseunits/includes/AnimeA/image_url.inc +++ b/baseunits/includes/AnimeA/image_url.inc @@ -8,7 +8,7 @@ FillMangaSiteHost(ANIMEA_ID, StringReplace(URL, '.html', '', []) + '-page-' + IntToStr(workCounter + 1) + '.html'), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -24,7 +24,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="scanmr"', parse[i]) > 0) and (Pos('id="scanmr"', parse[i])> 0) then - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); end; end; parse.Free; diff --git a/baseunits/includes/AnimeStory/chapter_page_number.inc b/baseunits/includes/AnimeStory/chapter_page_number.inc index ae0639dd5..12f23eba4 100644 --- a/baseunits/includes/AnimeStory/chapter_page_number.inc +++ b/baseunits/includes/AnimeStory/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + '1'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,13 +17,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := parse.Count - 1 downto 5 do begin if (Pos('data-page=', parse[i]) > 0) then begin s := parse[i]; - manager.container.pageNumber := + Task.Container.pageNumber := StrToInt(GetVal(s, 'data-page')); Break; end; diff --git a/baseunits/includes/AnimeStory/image_url.inc b/baseunits/includes/AnimeStory/image_url.inc index e46728a98..c3fde76df 100644 --- a/baseunits/includes/AnimeStory/image_url.inc +++ b/baseunits/includes/AnimeStory/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(workCounter + 1)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('id="chpimg"', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := DecodeURL(GetVal(parse[i], 'src')); Break; end; diff --git a/baseunits/includes/BlogTruyen/image_url.inc b/baseunits/includes/BlogTruyen/image_url.inc index 175f0b6c8..73b03c232 100644 --- a/baseunits/includes/BlogTruyen/image_url.inc +++ b/baseunits/includes/BlogTruyen/image_url.inc @@ -7,7 +7,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(BLOGTRUYEN_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -16,13 +16,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if not (isExtrackLink) and (Pos('id="content"', parse[i]) > 0) then isExtrackLink := True; if (isExtrackLink) and (GetTagName(parse[i]) = 'img') then - manager.container.PageLinks.Add( + Task.Container.PageLinks.Add( EncodeUrl(GetVal(parse[i], 'src'))) else if (isExtrackLink) and (Pos('</article>', parse[i]) > 0) then diff --git a/baseunits/includes/CentralDeMangas/image_url.inc b/baseunits/includes/CentralDeMangas/image_url.inc index afcbe1a12..0d80cbce1 100644 --- a/baseunits/includes/CentralDeMangas/image_url.inc +++ b/baseunits/includes/CentralDeMangas/image_url.inc @@ -9,7 +9,7 @@ // + IntToStr(workCounter+1)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,7 +18,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('var pages = ', parse[i]) > 0 then @@ -26,7 +26,7 @@ s := StringReplace(parse[i], '\/', '/', [rfReplaceAll]); repeat j := Pos('http://', s); - manager.container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); + Task.Container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); s := StringReplace(s, '"', '', []); s := StringReplace(s, '"', '', []); Delete(s, j, 10); diff --git a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc index 564e21f16..d9b3b82a5 100644 --- a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc +++ b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc @@ -10,7 +10,7 @@ s := DecodeUrl(FillMangaSiteHost(CENTRUMMANGI_PL_ID, URL)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -18,14 +18,14 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('</select>', parse[i]) > 0) then if Count > 0 then begin s := parse[i - 2]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); + Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); Break; end else diff --git a/baseunits/includes/CentrumMangi_PL/image_url.inc b/baseunits/includes/CentrumMangi_PL/image_url.inc index cc77f7ac6..4db99d04c 100644 --- a/baseunits/includes/CentrumMangi_PL/image_url.inc +++ b/baseunits/includes/CentrumMangi_PL/image_url.inc @@ -9,7 +9,7 @@ StringReplace(URL, '-1.html', '.html', [])); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,7 +18,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do if (Pos('<img alt=', parse[i]) > 0) then begin @@ -26,7 +26,7 @@ s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); s := StringReplace(s, 'mangas/', WebsiteRoots[CENTRUMMANGI_PL_ID, 1] + '/mangas/', [rfReplaceAll]); - manager.container.PageLinks.Add(EncodeURL(s)); + Task.Container.PageLinks.Add(EncodeURL(s)); end; end; parse.Free; diff --git a/baseunits/includes/Dynasty-Scans/chapter_page_number.inc b/baseunits/includes/Dynasty-Scans/chapter_page_number.inc index f859020a9..02d06d6e7 100644 --- a/baseunits/includes/Dynasty-Scans/chapter_page_number.inc +++ b/baseunits/includes/Dynasty-Scans/chapter_page_number.inc @@ -8,7 +8,7 @@ Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(DYNASTYSCANS_ID, URL)), - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); imgs_ := ''; if l.Count > 0 then @@ -24,7 +24,7 @@ end; l.Free; - with manager.container do + with Task.Container do begin if imgs_ <> '' then begin diff --git a/baseunits/includes/EGScans/chapter_page_number.inc b/baseunits/includes/EGScans/chapter_page_number.inc index 672d43ac5..230f60225 100644 --- a/baseunits/includes/EGScans/chapter_page_number.inc +++ b/baseunits/includes/EGScans/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/1'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,13 +17,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := parse.Count - 1 downto 2 do begin if (Pos('</span>', parse[i]) > 0) then begin s := parse[i - 4]; - manager.container.PageNumber := + Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(GetString(s + ' ', 'of ', ' ')))); Break; end; diff --git a/baseunits/includes/EGScans/image_url.inc b/baseunits/includes/EGScans/image_url.inc index 7816b484c..e20229d88 100644 --- a/baseunits/includes/EGScans/image_url.inc +++ b/baseunits/includes/EGScans/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(workCounter + 1)); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,11 +18,11 @@ if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do if (Pos('<img ondragstart', parse[i]) > 0) then begin - manager.container.PageLinks.Add(WebsiteRoots[EGSCANS_ID, 1] + + Task.Container.PageLinks.Add(WebsiteRoots[EGSCANS_ID, 1] + '/' + EncodeURL(GetVal(parse[i], 'src'))); end; end; diff --git a/baseunits/includes/EatManga/chapter_page_number.inc b/baseunits/includes/EatManga/chapter_page_number.inc index df1cca393..8f7129c5d 100644 --- a/baseunits/includes/EatManga/chapter_page_number.inc +++ b/baseunits/includes/EatManga/chapter_page_number.inc @@ -9,7 +9,7 @@ try Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL)), - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); try @@ -22,7 +22,7 @@ if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'id') = 'pages') then @@ -32,7 +32,7 @@ if GetTagName(parse[i]) = '/select' then Break else if GetTagName(parse[i]) = 'option' then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; end; diff --git a/baseunits/includes/EatManga/image_url.inc b/baseunits/includes/EatManga/image_url.inc index 8923d05e1..d1c35253c 100644 --- a/baseunits/includes/EatManga/image_url.inc +++ b/baseunits/includes/EatManga/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(workCounter + 1)), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; try @@ -25,7 +25,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'eatmanga_image') then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/EsMangaHere/chapter_page_number.inc b/baseunits/includes/EsMangaHere/chapter_page_number.inc index 7b81a708a..96ad34a75 100644 --- a/baseunits/includes/EsMangaHere/chapter_page_number.inc +++ b/baseunits/includes/EsMangaHere/chapter_page_number.inc @@ -7,7 +7,7 @@ parse := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(ESMANGAHERE_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -15,12 +15,12 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := parse.Count - 1 downto 4 do begin if Pos('</select>', parse[i]) > 0 then begin - manager.container.PageNumber := + Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(parse[i - 3]))); Break; end; diff --git a/baseunits/includes/EsMangaHere/image_url.inc b/baseunits/includes/EsMangaHere/image_url.inc index db9ee2ba1..792aa05a5 100644 --- a/baseunits/includes/EsMangaHere/image_url.inc +++ b/baseunits/includes/EsMangaHere/image_url.inc @@ -8,11 +8,11 @@ Result := GetPage(TObject(l), FillMangaSiteHost(ESMANGAHERE_ID, URL) + IntToStr(workCounter + 1) + '.html', - manager.container.manager.retryConnect) + Task.Container.manager.retryConnect) else Result := GetPage(TObject(l), WebsiteRoots[ESMANGAHERE_ID, 1] + URL, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -25,7 +25,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="read_img"', parse[i]) <> 0) then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := GetVal(parse[i + 6], 'src'); parse.Free; l.Free; diff --git a/baseunits/includes/ExtremeMangas/chapter_page_number.inc b/baseunits/includes/ExtremeMangas/chapter_page_number.inc index 338ca58d5..09d61c74b 100644 --- a/baseunits/includes/ExtremeMangas/chapter_page_number.inc +++ b/baseunits/includes/ExtremeMangas/chapter_page_number.inc @@ -5,11 +5,11 @@ s: String; //isExtractPageNumber: Boolean = False; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(EXTREMEMANGAS_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); l.Text := FixHTMLTagQuote(l.Text); Parser := THTMLParser.Create(PChar(l.Text)); @@ -20,7 +20,7 @@ if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('addpage(', parse[i]) > 0) then @@ -32,8 +32,8 @@ l.Delete(j) else l[j] := Trim(TrimChar(StringReplace(l[j], 'addpage(', '', [rfIgnoreCase]), [',', ''''])); - manager.container.PageLinks.AddStrings(l); - manager.container.PageNumber := manager.container.PageLinks.Count; + Task.Container.PageLinks.AddStrings(l); + Task.Container.PageNumber := Task.Container.PageLinks.Count; Break; end; end; diff --git a/baseunits/includes/Fakku/image_url.inc b/baseunits/includes/Fakku/image_url.inc index 6c1582686..d2043ffa9 100644 --- a/baseunits/includes/Fakku/image_url.inc +++ b/baseunits/includes/Fakku/image_url.inc @@ -6,10 +6,10 @@ begin totalPages := 0; - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; l := TStringList.Create; s := FillMangaSiteHost(FAKKU_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); if l.Count > 0 then begin @@ -56,7 +56,7 @@ s := IntToStr(i); while Length(s) < 3 do s := '0' + s; - manager.container.PageLinks.Add(imgURL + s + imgExt); + Task.Container.PageLinks.Add(imgURL + s + imgExt); end; end; end; diff --git a/baseunits/includes/HugeManga/chapter_page_number.inc b/baseunits/includes/HugeManga/chapter_page_number.inc index 19f260753..fe6f07355 100644 --- a/baseunits/includes/HugeManga/chapter_page_number.inc +++ b/baseunits/includes/HugeManga/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/1'); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,13 +17,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.pageNumber := 0; + Task.Container.pageNumber := 0; for i := parse.Count - 1 downto 5 do begin if (Pos('</option>', parse[i]) > 0) then begin s := parse[i - 2]; - manager.container.pageNumber := + Task.Container.pageNumber := StrToInt(GetVal(s, 'value')); Break; end; diff --git a/baseunits/includes/HugeManga/image_url.inc b/baseunits/includes/HugeManga/image_url.inc index 079f6fb45..3c32f7e08 100644 --- a/baseunits/includes/HugeManga/image_url.inc +++ b/baseunits/includes/HugeManga/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="picture"', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := EncodeURL(WebsiteRoots[HUGEMANGA_ID, 1] + HUGEMANGA_BROWSER + GetVal(parse[i], 'src')); Break; diff --git a/baseunits/includes/IKomik/chapter_page_number.inc b/baseunits/includes/IKomik/chapter_page_number.inc index 49d725529..14dedb111 100644 --- a/baseunits/includes/IKomik/chapter_page_number.inc +++ b/baseunits/includes/IKomik/chapter_page_number.inc @@ -5,11 +5,11 @@ isExtractPage: Boolean = False; s: String; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(IKOMIK_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -19,7 +19,7 @@ l.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<select', parse[i]) > 0) and (Pos('class="cbo_wp_manga_page"', parse[i]) > 0) then @@ -30,7 +30,7 @@ Break; end; if isExtractPage and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/IKomik/image_url.inc b/baseunits/includes/IKomik/image_url.inc index 78400ee5b..88ec000fa 100644 --- a/baseunits/includes/IKomik/image_url.inc +++ b/baseunits/includes/IKomik/image_url.inc @@ -10,7 +10,7 @@ if s[Length(s)] <> '/' then s := s + '/'; s := s + IntToStr(QWord(workCounter) + 1); - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -36,7 +36,7 @@ begin if Pos('<img', parse[j]) > 0 then begin - manager.container.PageLinks[workCounter] := GetVal(parse[j], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[j], 'src'); Break; end; end; diff --git a/baseunits/includes/JapanShin/chapter_page_number.inc b/baseunits/includes/JapanShin/chapter_page_number.inc index e7ef3eaa5..4fe9f0d09 100644 --- a/baseunits/includes/JapanShin/chapter_page_number.inc +++ b/baseunits/includes/JapanShin/chapter_page_number.inc @@ -7,7 +7,7 @@ parse := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(JAPANSHIN_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -15,12 +15,12 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; //class="tbtitle dropdown_parent dropdown_right for i := 0 to parse.Count - 1 do if (Pos('onClick="changePage', parse[i]) > 0) and (Pos('return false', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; parse.Free; l.Free; diff --git a/baseunits/includes/JapanShin/image_url.inc b/baseunits/includes/JapanShin/image_url.inc index 54c98147a..7b7e842ce 100644 --- a/baseunits/includes/JapanShin/image_url.inc +++ b/baseunits/includes/JapanShin/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(JAPANSHIN_ID, URL) + '/page/' + IntToStr(workCounter), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -27,7 +27,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="open"', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/Japscan/chapter_page_number.inc b/baseunits/includes/Japscan/chapter_page_number.inc index 6a9b5d06c..2650e36e1 100644 --- a/baseunits/includes/Japscan/chapter_page_number.inc +++ b/baseunits/includes/Japscan/chapter_page_number.inc @@ -13,7 +13,7 @@ s := ReplaceRegExpr('/\d+\.html?$', s, '', False); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); CleanHTMLComments(l); Parser := THTMLParser.Create(PChar(l.Text)); @@ -22,7 +22,7 @@ Parser.Exec; Parser.Free; - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; if parse.Count > 0 then begin regx := TRegExpr.Create; @@ -42,8 +42,8 @@ begin s := GetVal(parse[i], 'href'); s := regx.Replace(s, '$1', True); - if manager.container.PageNumber < StrToIntDef(s, 0) then - manager.container.PageNumber := StrToIntDef(s, 0); + if Task.Container.PageNumber < StrToIntDef(s, 0) then + Task.Container.PageNumber := StrToIntDef(s, 0); end; end; finally diff --git a/baseunits/includes/Japscan/image_url.inc b/baseunits/includes/Japscan/image_url.inc index 84744f801..f573b647b 100644 --- a/baseunits/includes/Japscan/image_url.inc +++ b/baseunits/includes/Japscan/image_url.inc @@ -11,7 +11,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -24,7 +24,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'imgscan') then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/Kivmanga/chapter_page_number.inc b/baseunits/includes/Kivmanga/chapter_page_number.inc index 88945b811..17a86cfa4 100644 --- a/baseunits/includes/Kivmanga/chapter_page_number.inc +++ b/baseunits/includes/Kivmanga/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/1'); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,13 +17,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.pageNumber := 0; + Task.Container.pageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('title="Next Page"', parse[i]) > 0) then begin s := parse[i - 6]; - manager.container.PageNumber := StrToInt(GetString(s, '"', '"')); + Task.container.PageNumber := StrToInt(GetString(s, '"', '"')); Break; end; end; diff --git a/baseunits/includes/Kivmanga/image_url.inc b/baseunits/includes/Kivmanga/image_url.inc index 3675e2982..d2b120a94 100644 --- a/baseunits/includes/Kivmanga/image_url.inc +++ b/baseunits/includes/Kivmanga/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -23,7 +23,7 @@ begin s := WebsiteRoots[KIVMANGA_ID, 1] + KIVMANGA_BROWSER + GetVal(parse[i], 'src'); - manager.container.PageLinks[workCounter] := EncodeURL(s); + Task.Container.PageLinks[workCounter] := EncodeURL(s); Break; end; end; diff --git a/baseunits/includes/Komikid/chapter_page_number.inc b/baseunits/includes/Komikid/chapter_page_number.inc index 115857794..62ecf14b1 100644 --- a/baseunits/includes/Komikid/chapter_page_number.inc +++ b/baseunits/includes/Komikid/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(KOMIKID_ID, URL) + '/1'); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,13 +17,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.pageNumber := 0; + Task.Container.pageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('title="Next Page"', parse[i]) > 0) then begin s := parse[i - 6]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); + Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); Break; end; end; diff --git a/baseunits/includes/Komikid/image_url.inc b/baseunits/includes/Komikid/image_url.inc index 7d27184a4..7eeea39d4 100644 --- a/baseunits/includes/Komikid/image_url.inc +++ b/baseunits/includes/Komikid/image_url.inc @@ -10,7 +10,7 @@ IntToStr(workCounter + 1) + '/'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -32,7 +32,7 @@ if not regx.Exec(s) then s := WebsiteRoots[KOMIKID_ID, 1] + '/' + s; s := EncodeURL(s); - manager.container.PageLinks[workCounter] := s; + Task.container.PageLinks[workCounter] := s; finally regx.Free; end; diff --git a/baseunits/includes/LectureEnLigne/chapter_page_number.inc b/baseunits/includes/LectureEnLigne/chapter_page_number.inc index 5d2a7837c..650161365 100644 --- a/baseunits/includes/LectureEnLigne/chapter_page_number.inc +++ b/baseunits/includes/LectureEnLigne/chapter_page_number.inc @@ -13,7 +13,7 @@ s := s + '/1.html'; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -30,7 +30,7 @@ if isGetPageNumber and (GetTagName(parse[i]) = '/select') then Break; if isGetPageNumber and (GetTagName(parse[i]) = 'option') then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; parse.Free; l.Free; diff --git a/baseunits/includes/LectureEnLigne/image_url.inc b/baseunits/includes/LectureEnLigne/image_url.inc index fb209be44..c5efbe89f 100644 --- a/baseunits/includes/LectureEnLigne/image_url.inc +++ b/baseunits/includes/LectureEnLigne/image_url.inc @@ -11,7 +11,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -24,7 +24,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'image') then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/Mabuns/image_url.inc b/baseunits/includes/Mabuns/image_url.inc index ed59702f4..10e3391af 100644 --- a/baseunits/includes/Mabuns/image_url.inc +++ b/baseunits/includes/Mabuns/image_url.inc @@ -8,7 +8,7 @@ s := FillMangaSiteHost(MABUNS_ID, URL); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -17,7 +17,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('addpage(''', parse[i]) > 0 then @@ -27,10 +27,10 @@ repeat j := Pos('addpage(''', s); if Pos('googleusercontent', s) > 0 then - manager.container.PageLinks.Add( + Task.Container.PageLinks.Add( EncodeUrl(GetString(s, 'addpage(''', ''','))) else - manager.container.PageLinks.Add( + Task.Container.PageLinks.Add( EncodeUrl(GetString(s, 'addpage(''', ');'))); Delete(s, Pos('addpage(''', s), 16); j := Pos('addpage(''', s); diff --git a/baseunits/includes/Manga24h/image_url.inc b/baseunits/includes/Manga24h/image_url.inc index 8b1038cf9..5861afb8c 100644 --- a/baseunits/includes/Manga24h/image_url.inc +++ b/baseunits/includes/Manga24h/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(MANGA24H_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -15,14 +15,14 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if (GetTagName(parse[i]) = 'img') and (Pos('style="border:3px', parse[i]) <> 0) then // (GetVal(parse[i], 'class') = 'm_picture') then begin - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); + Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); end; end; end; diff --git a/baseunits/includes/MangaAe/chapter_page_number.inc b/baseunits/includes/MangaAe/chapter_page_number.inc index 5e1a5db1f..2f6874076 100644 --- a/baseunits/includes/MangaAe/chapter_page_number.inc +++ b/baseunits/includes/MangaAe/chapter_page_number.inc @@ -10,7 +10,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/1'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -18,7 +18,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<a', parse[i]) <> 0) and (Pos('class="active"', parse[i]) <> 0) then @@ -29,8 +29,8 @@ (Pos('<a', parse[i]) <> 0) and (Pos(URL, parse[i]) <> 0) then begin p := StrToIntDef(Trim(parse[i + 1]), 0); - if p > manager.container.PageNumber then - manager.container.PageNumber := p; + if p > Task.Container.PageNumber then + Task.Container.PageNumber := p; end; end; end; diff --git a/baseunits/includes/MangaAe/image_url.inc b/baseunits/includes/MangaAe/image_url.inc index a41ccdea2..0393f348d 100644 --- a/baseunits/includes/MangaAe/image_url.inc +++ b/baseunits/includes/MangaAe/image_url.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(workCounter + 1)); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -25,7 +25,7 @@ isImageURL := True; if isImageURL and (Pos('<img', parse[i]) <> 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaAr/chapter_page_number.inc b/baseunits/includes/MangaAr/chapter_page_number.inc index 9e9082bc1..3f2af60f3 100644 --- a/baseunits/includes/MangaAr/chapter_page_number.inc +++ b/baseunits/includes/MangaAr/chapter_page_number.inc @@ -9,7 +9,7 @@ s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); if l.Count > 0 then try @@ -23,9 +23,9 @@ end; if s <> '' then begin - manager.container.PageLinks.Clear; - ParseJSONArray(s, 'url', manager.container.PageLinks); - manager.container.PageNumber := manager.container.PageLinks.Count; + Task.Container.PageLinks.Clear; + ParseJSONArray(s, 'url', Task.Container.PageLinks); + Task.Container.PageNumber := Task.Container.PageLinks.Count; end; finally parse.Free; diff --git a/baseunits/includes/MangaAr/image_url.inc b/baseunits/includes/MangaAr/image_url.inc index 93cec135d..0984bee47 100644 --- a/baseunits/includes/MangaAr/image_url.inc +++ b/baseunits/includes/MangaAr/image_url.inc @@ -8,7 +8,7 @@ s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -17,7 +17,7 @@ Parser.Exec; Parser.Free; - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; if parse.Count > 0 then begin for i := 0 to parse.Count - 1 do @@ -35,7 +35,7 @@ begin s := ts[j + 1]; s := 'http' + GetString(s, 'http', '?w='); //original resolution - manager.container.PageLinks.Add(s); + Task.Container.PageLinks.Add(s); end; end; ts.Free; diff --git a/baseunits/includes/MangaAt/chapter_page_number.inc b/baseunits/includes/MangaAt/chapter_page_number.inc index aa4c97152..68de629f3 100644 --- a/baseunits/includes/MangaAt/chapter_page_number.inc +++ b/baseunits/includes/MangaAt/chapter_page_number.inc @@ -10,7 +10,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGAAT_ID, URL + '/1/')); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(l.Text); try @@ -23,7 +23,7 @@ if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'active') then @@ -32,7 +32,7 @@ if GetVal(parse[i], 'class') = 'chapter' then Break else - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/MangaAt/image_url.inc b/baseunits/includes/MangaAt/image_url.inc index f1a18eb71..e290710d6 100644 --- a/baseunits/includes/MangaAt/image_url.inc +++ b/baseunits/includes/MangaAt/image_url.inc @@ -9,7 +9,7 @@ '/' + IntToStr(workCounter + 1) + '/'; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -26,7 +26,7 @@ if GetVal(parse[i], 'id') = 'showchaptercontainer' then if (GetTagName(parse[i + 3]) = 'img') then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i + 3], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i + 3], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/MangaEsta/image_url.inc b/baseunits/includes/MangaEsta/image_url.inc index 1f8b2224b..fe5e28bf4 100644 --- a/baseunits/includes/MangaEsta/image_url.inc +++ b/baseunits/includes/MangaEsta/image_url.inc @@ -8,7 +8,7 @@ s := FillMangaSiteHost(MANGAESTA_ID, URL); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -17,7 +17,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('addpage(''', parse[i]) > 0 then @@ -27,10 +27,10 @@ repeat j := Pos('addpage(''', s); if Pos('googleusercontent', s) > 0 then - manager.container.PageLinks.Add( + Task.Container.PageLinks.Add( EncodeUrl(GetString(s, 'addpage(''', ''','))) else - manager.container.PageLinks.Add( + Task.Container.PageLinks.Add( EncodeUrl(GetString(s, 'addpage(''', ');'))); Delete(s, Pos('addpage(''', s), 16); j := Pos('addpage(''', s); diff --git a/baseunits/includes/MangaGo/chapter_page_number.inc b/baseunits/includes/MangaGo/chapter_page_number.inc index b20b382c8..21bcdb5ce 100644 --- a/baseunits/includes/MangaGo/chapter_page_number.inc +++ b/baseunits/includes/MangaGo/chapter_page_number.inc @@ -8,7 +8,7 @@ l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(MANGAGO_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -16,13 +16,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do if Pos('total_pages=', parse[i]) > 0 then begin regx := TRegExpr.Create; regx.Expression := '^.*total_pages=(\d+)\b.*$'; - manager.container.PageNumber := + Task.container.PageNumber := StrToIntDef(regx.Replace(parse[i], '$1', True), 0); regx.Free; Break; diff --git a/baseunits/includes/MangaGo/image_url.inc b/baseunits/includes/MangaGo/image_url.inc index 5da91c04d..21665d2b1 100644 --- a/baseunits/includes/MangaGo/image_url.inc +++ b/baseunits/includes/MangaGo/image_url.inc @@ -15,7 +15,7 @@ s := s + '/'; s := FillMangaSiteHost(MANGAGO_ID, s); Result := GetPage(TObject(l), s + IntToStr(workCounter + 1) + '/', - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -38,7 +38,7 @@ if (Pos('imgReady(''', parse[i]) > 0) then begin regx.Expression := '^.*imgReady\(''([^'']*)''.*$'; - manager.container.PageLinks[workCounter] := regx.Replace(parse[i], '$1', True); + Task.Container.PageLinks[workCounter] := regx.Replace(parse[i], '$1', True); Break; end; end; diff --git a/baseunits/includes/MangaHost/chapter_page_number.inc b/baseunits/includes/MangaHost/chapter_page_number.inc index d7a29749d..e1f534e2c 100644 --- a/baseunits/includes/MangaHost/chapter_page_number.inc +++ b/baseunits/includes/MangaHost/chapter_page_number.inc @@ -8,7 +8,7 @@ parse := TStringList.Create; Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL)), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -16,7 +16,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<select', parse[i]) > 0) and (Pos('class="viewerPage', parse[i]) > 0) then @@ -24,7 +24,7 @@ if isGetPageNumber and (Pos('</select', parse[i]) > 0) then Break; if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/MangaHost/image_url.inc b/baseunits/includes/MangaHost/image_url.inc index 11db27645..628d501ac 100644 --- a/baseunits/includes/MangaHost/image_url.inc +++ b/baseunits/includes/MangaHost/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL) + '/' + IntToStr(workCounter + 1)), - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -19,7 +19,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) > 0) and (Pos('class="open', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaInn/chapter_page_number.inc b/baseunits/includes/MangaInn/chapter_page_number.inc index cbf9cc470..d9ecd0a96 100644 --- a/baseunits/includes/MangaInn/chapter_page_number.inc +++ b/baseunits/includes/MangaInn/chapter_page_number.inc @@ -7,7 +7,7 @@ parse := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(MANGAINN_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -19,9 +19,9 @@ if Pos('</select>', parse[i]) <> 0 then begin try - manager.container.PageNumber := StrToInt(Trim(parse[i - 3])); + Task.Container.PageNumber := StrToInt(Trim(parse[i - 3])); except - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; end; Break; end; diff --git a/baseunits/includes/MangaInn/image_url.inc b/baseunits/includes/MangaInn/image_url.inc index 57e358b74..2b457687b 100644 --- a/baseunits/includes/MangaInn/image_url.inc +++ b/baseunits/includes/MangaInn/image_url.inc @@ -7,7 +7,7 @@ Result := GetPage(TObject(l), FillMangaSiteHost(MANGAINN_ID, URL) + '/page_' + IntToStr(workCounter + 1), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -21,7 +21,7 @@ if GetTagName(parse[i]) = 'img' then if GetVal(parse[i], 'id') = 'imgPage' then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/MangaKu/chapter_page_number.inc b/baseunits/includes/MangaKu/chapter_page_number.inc index d388e06eb..e85f55850 100644 --- a/baseunits/includes/MangaKu/chapter_page_number.inc +++ b/baseunits/includes/MangaKu/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGAKU_ID, URL)); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(l.Text); try @@ -22,12 +22,12 @@ if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'imageanchor') = '1') then if GetTagName(parse[i + 1]) = 'img' then - manager.container.PageLinks.Add(GetVal(parse[i + 1], 'src')); - manager.container.PageNumber := manager.container.PageLinks.Count; + Task.Container.PageLinks.Add(GetVal(parse[i + 1], 'src')); + Task.Container.PageNumber := Task.container.PageLinks.Count; end; parse.Free; l.Free; diff --git a/baseunits/includes/MangaLib_PL/chapter_page_number.inc b/baseunits/includes/MangaLib_PL/chapter_page_number.inc index 6c9ab337d..6dbfb70fe 100644 --- a/baseunits/includes/MangaLib_PL/chapter_page_number.inc +++ b/baseunits/includes/MangaLib_PL/chapter_page_number.inc @@ -11,7 +11,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGALIB_PL_ID, URL)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); //check confirm if l.Count > 0 then @@ -38,7 +38,7 @@ l.Clear; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); end; end; @@ -47,10 +47,10 @@ Parser.OnFoundText := OnText; Parser.Exec; Parser.Free; - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<select ', parse[i]) > 0) and @@ -64,7 +64,7 @@ end; if isExtractPage and (Pos('<option ', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/MangaLib_PL/image_url.inc b/baseunits/includes/MangaLib_PL/image_url.inc index 8ccfb8ebe..657090942 100644 --- a/baseunits/includes/MangaLib_PL/image_url.inc +++ b/baseunits/includes/MangaLib_PL/image_url.inc @@ -10,7 +10,7 @@ Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); //check confirm if l.Count > 0 then @@ -37,7 +37,7 @@ l.Clear; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); end; end; @@ -53,7 +53,7 @@ if (Pos('<img ', parse[i]) > 0) and (Pos('id="img_curr"', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaMint/chapter_page_number.inc b/baseunits/includes/MangaMint/chapter_page_number.inc index 5ff33abfb..212c8febb 100644 --- a/baseunits/includes/MangaMint/chapter_page_number.inc +++ b/baseunits/includes/MangaMint/chapter_page_number.inc @@ -9,7 +9,7 @@ try Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(MANGAMINT_ID, URL)), - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(l.Text); try @@ -22,7 +22,7 @@ if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'name') = 'manga_page') then @@ -33,7 +33,7 @@ Break else if GetTagName(parse[i]) = 'option' then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; end; diff --git a/baseunits/includes/MangaMint/image_url.inc b/baseunits/includes/MangaMint/image_url.inc index fe4842fe0..4a7ec1d61 100644 --- a/baseunits/includes/MangaMint/image_url.inc +++ b/baseunits/includes/MangaMint/image_url.inc @@ -13,7 +13,7 @@ s := s + '?page=' + IntToStr(workCounter); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); try @@ -33,7 +33,7 @@ begin if Pos('src =', parse[i]) > 0 then parse[i] := StringReplace(parse[i], 'src =', 'src=', []); - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaOku/chapter_page_number.inc b/baseunits/includes/MangaOku/chapter_page_number.inc index 2101b92e1..c037ef663 100644 --- a/baseunits/includes/MangaOku/chapter_page_number.inc +++ b/baseunits/includes/MangaOku/chapter_page_number.inc @@ -5,11 +5,11 @@ s: String; isExtractPage: Boolean = False; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(MANGAOKU_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -29,7 +29,7 @@ end; if isExtractPage and (Pos('<option', parse[i]) > 0) then begin - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; end; diff --git a/baseunits/includes/MangaOku/image_url.inc b/baseunits/includes/MangaOku/image_url.inc index e05afbaa0..f8f61281b 100644 --- a/baseunits/includes/MangaOku/image_url.inc +++ b/baseunits/includes/MangaOku/image_url.inc @@ -10,7 +10,7 @@ if s[Length(s)] <> '/' then s := s + '/'; s := s + IntToStr(workCounter + 1) + '/'; - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -35,7 +35,7 @@ s := GetVal(parse[i], 'src'); if Pos(WebsiteRoots[MANGAOKU_ID, 1], s) = 0 then s := WebsiteRoots[MANGAOKU_ID, 1] + '/' + s; - manager.container.PageLinks[workCounter] := s; + Task.Container.PageLinks[workCounter] := s; Break; end; end; diff --git a/baseunits/includes/MangaPark/chapter_page_number.inc b/baseunits/includes/MangaPark/chapter_page_number.inc index 4d478ecfc..8c1674a46 100644 --- a/baseunits/includes/MangaPark/chapter_page_number.inc +++ b/baseunits/includes/MangaPark/chapter_page_number.inc @@ -11,7 +11,7 @@ SetLength(s, Length(s) - 2); Result := GetPage(TObject(l), FillMangaSiteHost(MANGAPARK_ID, s), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -21,8 +21,8 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('id="img-', parse[i]) <> 0) then begin - Inc(manager.container.PageNumber); - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); + Inc(Task.Container.PageNumber); + Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); end; parse.Free; l.Free; diff --git a/baseunits/includes/MangaPark/image_url.inc b/baseunits/includes/MangaPark/image_url.inc index 12a83d8e2..f2c80b7a7 100644 --- a/baseunits/includes/MangaPark/image_url.inc +++ b/baseunits/includes/MangaPark/image_url.inc @@ -7,7 +7,7 @@ Result := GetPage(TObject(l), FillMangaSiteHost(MANGAPARK_ID, URL) + 'all',//IntToStr(workCounter+1), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -17,12 +17,12 @@ if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do // if GetTagName(parse[i]) = 'img' then if (Pos('a target="_blank"', parse[i]) > 0) then begin - manager.container.PageLinks.Add(GetVal(parse[i], 'href')); + Task.Container.PageLinks.Add(GetVal(parse[i], 'href')); // break; end; end; diff --git a/baseunits/includes/MangaREADER_POR/image_url.inc b/baseunits/includes/MangaREADER_POR/image_url.inc index 3fe4a3490..9ea605f2c 100644 --- a/baseunits/includes/MangaREADER_POR/image_url.inc +++ b/baseunits/includes/MangaREADER_POR/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGAREADER_POR_ID, URL) + '/#1'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,7 +18,7 @@ if parse.Count > 0 then begin - manager.container.pageLinks.Clear; + Task.Container.pageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('function Proxima()', parse[i]) > 0 then @@ -26,11 +26,11 @@ //s:= GetString(parse[i], 'new Array("",', 'function Proxima'); s := GetString(parse[i], 'new Array("",', ');'); s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); - manager.container.PageLinks.DelimitedText := s; + Task.Container.PageLinks.DelimitedText := s; Break; //repeat // j:= Pos('http://', s); - // manager.container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); + // Task.Container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); // s:= StringReplace(s, '"', '', []); // s:= StringReplace(s, '"', '', []); // Delete(s, j, 7); diff --git a/baseunits/includes/MangaSee/chapter_page_number.inc b/baseunits/includes/MangaSee/chapter_page_number.inc index 1c6e61c82..45954dcfc 100644 --- a/baseunits/includes/MangaSee/chapter_page_number.inc +++ b/baseunits/includes/MangaSee/chapter_page_number.inc @@ -10,9 +10,9 @@ s := DecodeUrl(URL); if RightStr(s, 7) = '&page=1' then SetLength(s, Length(s) - 7); - s := FillMangaSiteHost(manager.container.MangaSiteID, s); + s := FillMangaSiteHost(Task.Container.MangaSiteID, s); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -29,8 +29,8 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('this.onerror=null', parse[i]) <> 0) then begin - Inc(manager.container.PageNumber); - manager.container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); + Inc(Task.Container.PageNumber); + Task.Container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); end; finally regx.Free; diff --git a/baseunits/includes/MangaTown/chapter_page_number.inc b/baseunits/includes/MangaTown/chapter_page_number.inc index 74995897a..c583f1ca3 100644 --- a/baseunits/includes/MangaTown/chapter_page_number.inc +++ b/baseunits/includes/MangaTown/chapter_page_number.inc @@ -5,11 +5,11 @@ s: String; isExtractPage: Boolean = False; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(MANGATOWN_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -32,7 +32,7 @@ if isExtractPage and (Pos('<option', parse[i]) > 0) then begin - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; end; diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index b9827649b..7212d7f51 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -8,7 +8,7 @@ s := AppendURLDelim(FillMangaSiteHost(MANGATOWN_ID, URL)); if workCounter > 0 then s := s + IncStr(workCounter) + '.html'; - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -30,7 +30,7 @@ begin if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaTraders/chapter_page_number.inc b/baseunits/includes/MangaTraders/chapter_page_number.inc index 703fbe28a..7d8e73730 100644 --- a/baseunits/includes/MangaTraders/chapter_page_number.inc +++ b/baseunits/includes/MangaTraders/chapter_page_number.inc @@ -9,7 +9,7 @@ parse := TStringList.Create; s := FillMangaSiteHost(MANGATRADERS_ID, URL); s := s + '/page-1'; - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,7 +17,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if Pos('<select', parse[i]) > 0 then @@ -28,7 +28,7 @@ Break; end; if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/MangaTraders/image_url.inc b/baseunits/includes/MangaTraders/image_url.inc index 43fecf3ac..73609fe46 100644 --- a/baseunits/includes/MangaTraders/image_url.inc +++ b/baseunits/includes/MangaTraders/image_url.inc @@ -7,7 +7,7 @@ l := TStringList.Create; s := FillMangaSiteHost(MANGATRADERS_ID, URL); s := s + '/page-' + IntToStr(workCounter + 1); - Result := GetPage(TObject(l), s, manager.container.manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -24,7 +24,7 @@ parse[i] := RemoveBreaks(parse[i]); if Pos(#9, parse[i]) > 0 then parse[i] := StringReplace(parse[i], #9, ' ', [rfReplaceAll, rfIgnoreCase]); - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Mangacow/chapter_page_number.inc b/baseunits/includes/Mangacow/chapter_page_number.inc index e1c8b2baf..765a6d823 100644 --- a/baseunits/includes/Mangacow/chapter_page_number.inc +++ b/baseunits/includes/Mangacow/chapter_page_number.inc @@ -10,7 +10,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + '1/'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -24,7 +24,7 @@ regx.ModifierI := True; for i := 0 to parse.Count - 1 do if Pos('arr_img.push(', parse[i]) > 0 then - manager.container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); + Task.Container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); finally regx.Free end; diff --git a/baseunits/includes/Mangacow/image_url.inc b/baseunits/includes/Mangacow/image_url.inc index 55a689e24..5d582e710 100644 --- a/baseunits/includes/Mangacow/image_url.inc +++ b/baseunits/includes/Mangacow/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(workCounter + 1) + '/'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -22,7 +22,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'style') = 'width:0px; height:0px') then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangasPROJECT/image_url.inc b/baseunits/includes/MangasPROJECT/image_url.inc index 6b5b21135..9f6b65b13 100644 --- a/baseunits/includes/MangasPROJECT/image_url.inc +++ b/baseunits/includes/MangasPROJECT/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(MANGASPROJECT_ID, URL) + '/#1'); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,7 +18,7 @@ if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('{ path: ', parse[i]) > 0 then @@ -31,7 +31,7 @@ for j := 0 to ts.Count - 1 do begin if Pos('http', ts[j]) > 0 then - manager.container.PageLinks.Add(ts[j]); + Task.Container.PageLinks.Add(ts[j]); end; finally ts.Free; diff --git a/baseunits/includes/MeinManga/chapter_page_number.inc b/baseunits/includes/MeinManga/chapter_page_number.inc index 7d977b0c8..3941df5f1 100644 --- a/baseunits/includes/MeinManga/chapter_page_number.inc +++ b/baseunits/includes/MeinManga/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(MEINMANGA_ID, URL)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,20 +17,20 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; - manager.container.PageLinks.Clear; + Task.Container.PageNumber := 0; + Task.container.PageLinks.Clear; for i := parse.Count - 1 downto 0 do begin if (Pos('</select>', parse[i]) > 0) then begin - manager.container.PageNumber := + Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(parse[i - 3]))); Break; end; end; - if manager.container.PageNumber > 0 then - for i := 0 to manager.container.PageNumber - 1 do - manager.container.pageLinks.Add(s + IntToStr(i + 1) + '.html'); + if Task.Container.PageNumber > 0 then + for i := 0 to Task.Container.PageNumber - 1 do + Task.Container.pageLinks.Add(s + IntToStr(i + 1) + '.html'); end; parse.Free; l.Free; diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index 8df124390..3a831d337 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -6,9 +6,9 @@ l: TStringList; Parser: THTMLParser; begin - s := manager.container.DownloadInfo.SaveTo + - '/' + manager.container.ChapterName[ - manager.container.CurrentDownloadChapterPtr] + '/' + + s := Task.Container.DownloadInfo.SaveTo + + '/' + Task.Container.ChapterName[ + Task.Container.CurrentDownloadChapterPtr] + '/' + Format('%.3d', [workCounter + 1]); // Check to see if a file with similar name was already exist. If so then we // skip the download process. @@ -27,8 +27,8 @@ FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; Result := GetPage(TObject(l), - manager.container.PageLinks[workCounter], - manager.container.Manager.retryConnect); + Task.Container.PageLinks[workCounter], + Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -55,12 +55,12 @@ FHTTP.Clear; SaveImage( - manager.container.MangaSiteID, + Task.Container.MangaSiteID, GetVal(parse[i], 'src'), - manager.container.CurrentWorkingDir, + Task.Container.CurrentWorkingDir, Format('%.3d', [workCounter + 1]) + '_' + IntToStr(prefix), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Inc(prefix); @@ -78,7 +78,7 @@ begin imageName := Format('%.3d', [workCounter + 1]); Merge2Image( - manager.container.CurrentWorkingDir, + Task.Container.CurrentWorkingDir, imageName + '_' + IntToStr(prefix - 2) + '.jpg', imageName + '_' + IntToStr(prefix - 1) + '.jpg', imageName + '.jpg'); diff --git a/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc b/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc index 2a36b9b71..fbd6bf3cb 100644 --- a/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc +++ b/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc @@ -6,11 +6,11 @@ s: String; isExtractImg: Boolean = False; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(MYREADINGMANGAINFO_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -19,7 +19,7 @@ l.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin //if (Pos('class="separator"', parse[i]) > 0) and @@ -27,7 +27,7 @@ // for j := i + 1 to parse.Count - 1 do // if (Pos('<img', parse[j]) > 0) then // begin - // manager.container.PageLinks.Add(GetVal(parse[j], 'src')); + // Task.Container.PageLinks.Add(GetVal(parse[j], 'src')); // Break; // end; if isExtractImg and (Pos('<footer', parse[i]) > 0) and @@ -40,9 +40,9 @@ (Pos('class="entry-content"', parse[i]) > 0) then isExtractImg := True; if isExtractImg and (Pos('<img', parse[i]) > 0) then - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); + Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); end; - manager.container.PageNumber := manager.container.PageLinks.Count; + Task.Container.PageNumber := Task.Container.PageLinks.Count; end; parse.Free; end; diff --git a/baseunits/includes/NHentai/chapter_page_number.inc b/baseunits/includes/NHentai/chapter_page_number.inc index f2e99e7ab..1999aa2c6 100644 --- a/baseunits/includes/NHentai/chapter_page_number.inc +++ b/baseunits/includes/NHentai/chapter_page_number.inc @@ -4,14 +4,14 @@ l: TStringList; s: String; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(NHENTAI_ID, URL); if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - Result := GetPage(TObject(l), s + '1/', manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s + '1/', Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -21,13 +21,13 @@ l.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<a', parse[i]) > 0) and (Pos('class="last"', parse[i]) > 0) and (Pos('/g/', parse[i]) > 0) then begin - manager.container.PageNumber := + Task.Container.PageNumber := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)\/.*$', GetVal(parse[i], 'href'), '$1', True), 1); Break; end; diff --git a/baseunits/includes/NHentai/image_url.inc b/baseunits/includes/NHentai/image_url.inc index a19dd9d5f..ce340948b 100644 --- a/baseunits/includes/NHentai/image_url.inc +++ b/baseunits/includes/NHentai/image_url.inc @@ -10,7 +10,7 @@ if s[Length(s)] <> '/' then s := s + '/'; s := s + IntToStr(QWord(workCounter) + 1) + '/'; - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -42,7 +42,7 @@ s := TrimLeftChar(s, ['/', ':']); s := 'http://' + s; end; - manager.container.PageLinks[workCounter] := s; + Task.Container.PageLinks[workCounter] := s; Break; end; end; diff --git a/baseunits/includes/NineManga/chapter_page_number.inc b/baseunits/includes/NineManga/chapter_page_number.inc index 98c980f23..c4b17aa3f 100644 --- a/baseunits/includes/NineManga/chapter_page_number.inc +++ b/baseunits/includes/NineManga/chapter_page_number.inc @@ -8,8 +8,8 @@ parse := TStringList.Create; Result := GetPage(TObject(l), - FillMangaSiteHost(manager.container.MangaSiteID, URL), - manager.container.Manager.retryConnect); + FillMangaSiteHost(Task.Container.MangaSiteID, URL), + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,7 +18,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<select', parse[i]) > 0) and @@ -31,7 +31,7 @@ Break; end; if isExtractPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/NineManga/image_url.inc b/baseunits/includes/NineManga/image_url.inc index 814c5b3aa..5079df4ad 100644 --- a/baseunits/includes/NineManga/image_url.inc +++ b/baseunits/includes/NineManga/image_url.inc @@ -5,14 +5,14 @@ l: TStringList; begin l := TStringList.Create; - s := FillMangaSiteHost(manager.container.MangaSiteID, URL); + s := FillMangaSiteHost(Task.Container.MangaSiteID, URL); s := StringReplace(s, '.html', '', []); s := StringReplace(s, '.htm', '', []); s := s + '-' + IntToStr(workCounter + 1) + '.html'; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.container.Manager.retryConnect); if Self.Terminated then begin l.Free; @@ -32,7 +32,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="manga_pic', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/OneManga/chapter_page_number.inc b/baseunits/includes/OneManga/chapter_page_number.inc index ef03ca138..91a663ef1 100644 --- a/baseunits/includes/OneManga/chapter_page_number.inc +++ b/baseunits/includes/OneManga/chapter_page_number.inc @@ -10,13 +10,13 @@ s := FillMangaSiteHost(ONEMANGA_ID, URL); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; Parser.Exec; Parser.Free; - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; if parse.Count > 0 then for i := 1 to parse.Count - 1 do begin @@ -30,7 +30,7 @@ Break; end; if isGetPage and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; parse.Free; l.Free; diff --git a/baseunits/includes/OneManga/image_url.inc b/baseunits/includes/OneManga/image_url.inc index a2b9659ba..0eede3d22 100644 --- a/baseunits/includes/OneManga/image_url.inc +++ b/baseunits/includes/OneManga/image_url.inc @@ -9,7 +9,7 @@ s := s + IntToStr(workCounter + 1) + '/'; Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -22,7 +22,7 @@ if (Pos('<img ', parse[i]) > 0) and (Pos('class="manga-page"', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/PornComix/chapter_page_number.inc b/baseunits/includes/PornComix/chapter_page_number.inc index e51c1aba4..4103ecc4a 100644 --- a/baseunits/includes/PornComix/chapter_page_number.inc +++ b/baseunits/includes/PornComix/chapter_page_number.inc @@ -15,16 +15,16 @@ RepeatGet := False; l.Clear; parse.Clear; - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; Parser.Exec; Parser.Free; - manager.container.PageNumber := 0; - manager.container.PageLinks.Clear; - manager.container.PageContainerLinks.Clear; + Task.Container.PageNumber := 0; + Task.Container.PageLinks.Clear; + Task.Container.PageContainerLinks.Clear; if parse.Count > 0 then begin regx := TRegExpr.Create; @@ -42,28 +42,28 @@ ((Pos('target="_blank', parse[i]) <> 0) or (Pos('rel="nofollow', parse[i]) <> 0)) then begin - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); s := GetVal(parse[i], 'href'); if (Pos('<img', parse[i + 1]) <> 0) and (Pos('/upload/small/', parse[i + 1]) <> 0) then begin s := GetVal(parse[i + 1], 'src'); s := StringReplace(s, '/small/', '/big/', [rfIgnoreCase]); - manager.container.PageLinks.Add(s); - manager.container.PageContainerLinks.Add('W'); + Task.Container.PageLinks.Add(s); + Task.Container.PageContainerLinks.Add('W'); end else if (Pos('imagetwist.', s) <> 0) or (Pos('imgmega.', s) <> 0) or (Pos('imgchili.', s) <> 0) then begin - manager.container.PageContainerLinks.Add(s); - manager.container.PageLinks.Add('W'); + Task.Container.PageContainerLinks.Add(s); + Task.Container.PageLinks.Add('W'); end else if regx.Exec(s) then begin s := regx.Replace(s, '$1/dlimg.php?id=$2', True); - manager.container.PageLinks.Add(s); - manager.container.PageContainerLinks.Add('W'); + Task.Container.PageLinks.Add(s); + Task.Container.PageContainerLinks.Add('W'); end else if (Pos('/category/', s) = 0) and ((Pos(WebsiteRoots[PORNCOMIX_ID, 1], s) <> 0) or @@ -82,7 +82,7 @@ Break; end else - Dec(manager.container.PageNumber); + Dec(Task.Container.PageNumber); end; end; finally diff --git a/baseunits/includes/PornComix/image_url.inc b/baseunits/includes/PornComix/image_url.inc index 88a7007a6..3d2747b48 100644 --- a/baseunits/includes/PornComix/image_url.inc +++ b/baseunits/includes/PornComix/image_url.inc @@ -4,13 +4,13 @@ s, surl: String; l: TStringList; begin - surl := manager.container.PageContainerLinks[workCounter]; + surl := Task.Container.PageContainerLinks[workCounter]; if not ((Pos('imagetwist.', surl) <> 0) or (Pos('imgmega.', surl) <> 0) or (Pos('imgchili.', surl) <> 0)) then Exit(False); l := TStringList.Create; - Result := GetPage(TObject(l), DecodeUrl(surl), manager.container.manager.retryConnect); + Result := GetPage(TObject(l), DecodeUrl(surl), Task.Container.manager.retryConnect); //broken source if l.Count > 0 then @@ -43,7 +43,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('class="pic', parse[i]) <> 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end @@ -54,7 +54,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('id="show_image', parse[i]) <> 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/ReadMangaToday/chapter_page_number.inc b/baseunits/includes/ReadMangaToday/chapter_page_number.inc index 75f72c4d7..911a5378b 100644 --- a/baseunits/includes/ReadMangaToday/chapter_page_number.inc +++ b/baseunits/includes/ReadMangaToday/chapter_page_number.inc @@ -9,17 +9,17 @@ s := DecodeUrl(FillMangaSiteHost(READMANGATODAY_ID, URL)+'/all-pages'); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); ParseHTML(l.Text, parse); if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count-1 do if (GetTagName(parse[i]) = 'img') and (Pos('img-responsive-', parse[i]) <> 0) then - manager.container.PageLinks.Add(GetVal(parse[i], 'src')); - manager.container.PageNumber := manager.container.PageLinks.Count; + Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); + Task.Container.PageNumber := Task.Container.PageLinks.Count; end; parse.Free; l.Free; diff --git a/baseunits/includes/S2Scans/chapter_page_number.inc b/baseunits/includes/S2Scans/chapter_page_number.inc index 7b99b4476..af8151ae3 100644 --- a/baseunits/includes/S2Scans/chapter_page_number.inc +++ b/baseunits/includes/S2Scans/chapter_page_number.inc @@ -8,18 +8,18 @@ try Result := GetPage(TObject(l), FillMangaSiteHost(S2SCAN_ID, URL) + 'page/1', - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); if l.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to l.Count - 1 do begin if Pos('var pages = [', l[i]) > 0 then begin s := StringReplace(l[i], 'var pages = [', '[', []); s := Trim(TrimChar(s, [';'])); - ParseJSONArray(s, 'url', manager.container.PageLinks); + ParseJSONArray(s, 'url', Task.Container.PageLinks); Break; end; end; diff --git a/baseunits/includes/ScanManga/image_url.inc b/baseunits/includes/ScanManga/image_url.inc index b5550cc6b..8ef4c914f 100644 --- a/baseunits/includes/ScanManga/image_url.inc +++ b/baseunits/includes/ScanManga/image_url.inc @@ -11,7 +11,7 @@ s := DecodeUrl(FillMangaSiteHost(SCANMANGA_ID, URL)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); for i := 0 to l.Count - 1 do begin @@ -24,7 +24,7 @@ Break; end; end; - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to l.Count - 1 do begin if (Pos('var c = new Array;', l[i]) > 0) and @@ -36,7 +36,7 @@ t.DelimitedText := s; for j := 0 to t.Count - 1 do if Pos(']="', t[j]) > 0 then - manager.container.PageLinks.Add(h + GetString(t[j], '="', '"')); + Task.Container.PageLinks.Add(h + GetString(t[j], '="', '"')); Break; end; end; diff --git a/baseunits/includes/Starkana/chapter_page_number.inc b/baseunits/includes/Starkana/chapter_page_number.inc index 554ef1ea1..d28fa0b10 100644 --- a/baseunits/includes/Starkana/chapter_page_number.inc +++ b/baseunits/includes/Starkana/chapter_page_number.inc @@ -8,7 +8,7 @@ parse := TStringList.Create; Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL)), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -16,7 +16,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('<select', parse[i]) > 0) and (Pos('id="page_switch', parse[i]) > 0) then @@ -24,7 +24,7 @@ if isGetPageNumber and (Pos('</select', parse[i]) > 0) then Break; if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(manager.container.PageNumber); + Inc(Task.Container.PageNumber); end; end; parse.Free; diff --git a/baseunits/includes/Starkana/image_url.inc b/baseunits/includes/Starkana/image_url.inc index 77ac25600..ccd96f20e 100644 --- a/baseunits/includes/Starkana/image_url.inc +++ b/baseunits/includes/Starkana/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(workCounter + 1)), - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -20,7 +20,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="dyn', parse[i]) > 0) and (Pos('style="cursor: pointer', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/TruyenTranhTuan/image_url.inc b/baseunits/includes/TruyenTranhTuan/image_url.inc index f58f06b3b..302c7af5a 100644 --- a/baseunits/includes/TruyenTranhTuan/image_url.inc +++ b/baseunits/includes/TruyenTranhTuan/image_url.inc @@ -7,7 +7,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -16,7 +16,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('var slides_page = ["', parse[i]) > 0 then @@ -26,7 +26,7 @@ j := Pos('"/manga/', s); s2 := EncodeUrl(WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + '/manga/' + GetString(s, '"/manga/', '"')); - manager.container.PageLinks.Add(s2); + Task.Container.PageLinks.Add(s2); Delete(s, Pos('"/manga/', s), 10); j := Pos('"/manga/', s); until j = 0; diff --git a/baseunits/includes/Turkcraft/chapter_page_number.inc b/baseunits/includes/Turkcraft/chapter_page_number.inc index 81c290c02..60864e8ac 100644 --- a/baseunits/includes/Turkcraft/chapter_page_number.inc +++ b/baseunits/includes/Turkcraft/chapter_page_number.inc @@ -9,7 +9,7 @@ s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/1'); Result := GetPage(TObject(l), s, - manager.container.manager.retryConnect); + Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; Parser.OnFoundText := OnText; @@ -17,13 +17,13 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.pageNumber := 0; + Task.Container.pageNumber := 0; for i := 0 to parse.Count - 1 do begin if (Pos('title="Next Page"', parse[i]) > 0) then begin s := parse[i - 5]; - manager.container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); + Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); Break; end; end; diff --git a/baseunits/includes/Turkcraft/image_url.inc b/baseunits/includes/Turkcraft/image_url.inc index 6d21c5fb7..14dc17cde 100644 --- a/baseunits/includes/Turkcraft/image_url.inc +++ b/baseunits/includes/Turkcraft/image_url.inc @@ -8,7 +8,7 @@ s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(workCounter + 1)); Result := GetPage(TObject(l), s, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="picture"', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := + Task.Container.PageLinks[workCounter] := EncodeURL(WebsiteRoots[TURKCRAFT_ID, 1] + TURKCRAFT_BROWSER + GetVal(parse[i], 'src')); Break; diff --git a/baseunits/includes/UnixManga/chapter_page_number.inc b/baseunits/includes/UnixManga/chapter_page_number.inc index 310d4899f..1241d57f0 100644 --- a/baseunits/includes/UnixManga/chapter_page_number.inc +++ b/baseunits/includes/UnixManga/chapter_page_number.inc @@ -4,11 +4,11 @@ l: TStringList; s: String; begin - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; l := TStringList.Create; parse := TStringList.Create; s := FillMangaSiteHost(UNIXMANGA_ID, URL); - Result := GetPage(TObject(l), s, manager.container.Manager.retryConnect); + Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -18,15 +18,15 @@ l.Free; if parse.Count > 0 then begin - manager.container.PageNumber := 0; - manager.container.PageLinks.Clear; - manager.container.PageContainerLinks.Clear; + Task.Container.PageNumber := 0; + Task.Container.PageLinks.Clear; + Task.Container.PageContainerLinks.Clear; for i := 0 to parse.Count - 1 do begin if (Pos('class="td2"', parse[i]) > 0) and (Pos('<A', parse[i]) > 0) then - manager.container.PageContainerLinks.Add(EncodeURL(GetVal(parse[i], 'HREF'))); + Task.Container.PageContainerLinks.Add(EncodeURL(GetVal(parse[i], 'HREF'))); end; - manager.container.PageNumber := manager.container.PageContainerLinks.Count; + Task.Container.PageNumber := Task.Container.PageContainerLinks.Count; end; parse.Free; end; diff --git a/baseunits/includes/UnixManga/image_url.inc b/baseunits/includes/UnixManga/image_url.inc index 9f7090fae..e5d2a7f2e 100644 --- a/baseunits/includes/UnixManga/image_url.inc +++ b/baseunits/includes/UnixManga/image_url.inc @@ -5,8 +5,8 @@ s: String; begin l := TStringList.Create; - s := manager.container.PageContainerLinks[workCounter]; - Result := GetPage(TObject(l), s , manager.container.Manager.retryConnect); + s := Task.Container.PageContainerLinks[workCounter]; + Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then begin @@ -28,7 +28,7 @@ begin if (Pos('STYLE="border', parse[i]) > 0) and (Pos('<IMG', parse[i]) > 0) then begin - manager.container.PageLinks[workCounter] := Trim(GetVal(parse[i], 'SRC')); + Task.Container.PageLinks[workCounter] := Trim(GetVal(parse[i], 'SRC')); Break; end; end; diff --git a/baseunits/includes/VnSharing/image_url.inc b/baseunits/includes/VnSharing/image_url.inc index 969fda71a..3ebecbbd4 100644 --- a/baseunits/includes/VnSharing/image_url.inc +++ b/baseunits/includes/VnSharing/image_url.inc @@ -7,7 +7,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(VNSHARING_ID, URL), - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); Parser.OnFoundTag := OnTag; @@ -16,7 +16,7 @@ Parser.Free; if parse.Count > 0 then begin - manager.container.PageLinks.Clear; + Task.Container.PageLinks.Clear; for i := 0 to parse.Count - 1 do begin if Pos('lstImages.push("', parse[i]) > 0 then @@ -24,7 +24,7 @@ s := parse[i]; repeat j := Pos('lstImages.push("', s); - manager.container.PageLinks.Add( + Task.Container.PageLinks.Add( EncodeUrl(GetString(s, 'lstImages.push("', '");'))); Delete(s, Pos('lstImages.push("', s), 16); j := Pos('lstImages.push("', s); diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 93066adbc..5f127eeb2 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -98,7 +98,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 99a663515..8bff51994 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -251,7 +251,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + urlroot + '/reader'; cid := SeparateRight(AURL, '/reader#'); if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin @@ -286,7 +286,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + IntToStr(DownloadThread.WorkCounter + 1); diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index 26c2a7bd8..61c4ec5c9 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -128,7 +128,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; + Container := DownloadThread.Task.Container; Container.PageLinks.Clear; Container.PageContainerLinks.Clear; Container.PageNumber := 0; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index afbf2f225..15e2bcd0e 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -224,7 +224,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; var x: IXQValue; begin - with DownloadThread.manager.container, query do begin + with DownloadThread.Task.Container, query do begin ParseHTML(DownloadThread.FHTTP.Document); for x in XPath('//div[@id="gdt"]//a') do begin @@ -240,7 +240,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageContainerLinks.Clear; Filenames.Clear; diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index cd225df94..a881ca211 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -56,7 +56,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; @@ -93,7 +93,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkCounter])); if GET(rurl) then begin Result := True; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 96c3b483e..94f2cc10f 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -132,7 +132,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; @@ -166,7 +166,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AURL; if DownloadThread.workCounter > 0 then diff --git a/baseunits/modules/GMangaMe.pas b/baseunits/modules/GMangaMe.pas index d3752915f..94398c155 100644 --- a/baseunits/modules/GMangaMe.pas +++ b/baseunits/modules/GMangaMe.pas @@ -121,7 +121,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index f7596f8ad..fdab81265 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -102,7 +102,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; s := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); @@ -125,7 +125,7 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do + with DownloadThread.Task.Container, DownloadThread.FHTTP do if CurrentDownloadChapterPtr < ChapterLinks.Count then begin Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); Cookies.Text := goscookies; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index a19e8089b..6d413ad55 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -105,7 +105,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; Cookies.Values['ReadType'] := '2'; @@ -137,7 +137,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AppendURLDelim(AURL) + IncStr(DownloadThread.workCounter) + '/'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 94dadfcc0..ae964ff2e 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -129,7 +129,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; @@ -180,7 +180,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := FillHost(Module.RootURL, AURL); if DownloadThread.workCounter > 0 then diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index f76ab864c..0a24f26b4 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -103,7 +103,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index f65bb2d9e..2a417ee26 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -117,7 +117,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; @@ -141,7 +141,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if GET(FillHost(Module.RootURL, AURL) + IncStr(DownloadThread.workCounter)) then begin diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index c4a00df01..fec34217d 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -103,7 +103,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index fb2c998f9..2ac4cc05c 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -136,7 +136,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then begin diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 5c9e51aff..674265a95 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -139,7 +139,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; + Container := DownloadThread.Task.Container; with Container do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 92825a8b9..b51be6767 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -173,7 +173,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin + with DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index bd7d99f6c..7d6ddb63f 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -108,7 +108,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 9a395dda6..63e77df25 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -108,7 +108,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/MangaDenizi.pas b/baseunits/modules/MangaDenizi.pas index ca3a16a35..a948dc506 100644 --- a/baseunits/modules/MangaDenizi.pas +++ b/baseunits/modules/MangaDenizi.pas @@ -105,7 +105,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index 5d25d077f..9a2ca6370 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -108,7 +108,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(MaybeFillHost(Module.RootURL, AURL)) then begin @@ -162,7 +162,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; s := RemoveURLDelim(AURL); if RightStr(s, 2) = '/1' then SetLength(s, Length(s) - 1); - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AppendURLDelim(s) + IncStr(DownloadThread.workCounter) + '/'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 0ba928295..f155e04a1 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -92,7 +92,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; s := ChapterLinks[CurrentDownloadChapterPtr]; @@ -124,7 +124,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '.html') then begin diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 08597ada9..2b0d589b1 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -109,7 +109,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; + Container := DownloadThread.Task.Container; with Container do begin Source := TStringList.Create; try @@ -141,7 +141,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin + with DownloadThread.Task.Container do begin Source := TStringList.Create; try rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 009f7ffa2..5d635b244 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -113,7 +113,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin @@ -137,7 +137,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := RemoveURLDelim(AURL); if DownloadThread.workCounter > 0 then s += '/' + IncStr(DownloadThread.workCounter) + '.html'; if GET(FillHost(Module.RootURL, s)) then begin diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 8f57f2d48..9cefede99 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -117,7 +117,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; + Container := DownloadThread.Task.Container; with Container do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 7102fed7a..15d040fdd 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -137,7 +137,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin + with DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; Source := TStringList.Create; @@ -170,7 +170,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin + with DownloadThread.Task.Container do begin Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), diff --git a/baseunits/modules/MangaSaurus.pas b/baseunits/modules/MangaSaurus.pas index 570ac8f99..f65462e01 100644 --- a/baseunits/modules/MangaSaurus.pas +++ b/baseunits/modules/MangaSaurus.pas @@ -121,7 +121,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 85c8b3f04..98f5bb56b 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -114,7 +114,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; + Container := DownloadThread.Task.Container; Container.PageLinks.Clear; Container.PageContainerLinks.Clear; Container.PageNumber := 0; @@ -152,7 +152,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do begin + with DownloadThread.Task.Container do begin Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index e829390be..60b4941e1 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -70,7 +70,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin @@ -94,7 +94,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AURL; s := ReplaceRegExpr('\.html?$', s, '', False); s += '-page-' + IncStr(DownloadThread.workCounter) + '.html'; diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index 924c32bbe..abbbacd4a 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -152,7 +152,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageContainerLinks.Clear; PageNumber := 0; @@ -190,7 +190,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + AURL; if DownloadThread.workCounter > PageContainerLinks.Count then Exit; if GETWithCookie(DownloadThread.FHTTP, PageContainerLinks[DownloadThread.workCounter], Module) then diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index b7bb99aa1..a5e98cd13 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -152,7 +152,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.manager.container; + Container := DownloadThread.Task.Container; Container.PageLinks.Clear; Container.PageContainerLinks.Clear; Container.PageNumber := 0; diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index df9fbc5d1..a0647cafb 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -114,7 +114,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; s := AURL; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 25b8f6727..2761cad17 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -81,7 +81,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin @@ -105,7 +105,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := RemoveURLDelim(AURL); if DownloadThread.workCounter > 0 then s += '/' + IncStr(DownloadThread.workCounter); if GET(FillHost(Module.RootURL, s)) then begin diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 31253e2ce..f051ae446 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -111,7 +111,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin s := RemoveURLDelim(ChapterLinks[CurrentDownloadChapterPtr]); with TRegExpr.Create do try @@ -155,7 +155,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(DownloadThread.WorkCounter)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -175,7 +175,7 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do + with DownloadThread.Task.Container do if CurrentDownloadChapterPtr < ChapterLinks.Count then begin DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); diff --git a/baseunits/modules/Seemh.pas b/baseunits/modules/Seemh.pas index 547863def..43d748e6b 100644 --- a/baseunits/modules/Seemh.pas +++ b/baseunits/modules/Seemh.pas @@ -100,7 +100,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result:=False; if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.manager.container do begin + with DownloadThread.FHTTP,DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL,AURL)) then begin diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 05da78d28..df7b28bdd 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -103,7 +103,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin @@ -125,7 +125,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container, DownloadThread.FHTTP do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := FillHost(Module.RootURL, AURL); if DownloadThread.workCounter > 0 then s := s + '/' + IncStr(DownloadThread.workCounter); diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index b7e867c94..5c0ef2a99 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -98,7 +98,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 34f80a9e4..c031f6df8 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -138,7 +138,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 7f1b70fda..c6b3c94cd 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -112,7 +112,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index d1ae741b8..04ae55478 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -226,7 +226,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; Cookies.Values['viewer'] := '1'; @@ -271,7 +271,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then begin Result := True; diff --git a/baseunits/modules/WebtoonTr.pas b/baseunits/modules/WebtoonTr.pas index 0b43707f6..689bcb722 100644 --- a/baseunits/modules/WebtoonTr.pas +++ b/baseunits/modules/WebtoonTr.pas @@ -86,7 +86,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index 5ad8dc057..0dbe02e7e 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -103,7 +103,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.manager.container do begin + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin @@ -130,7 +130,7 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.manager.container do + with DownloadThread.Task.Container do if CurrentDownloadChapterPtr < ChapterLinks.Count then begin DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 974ce4011..496c8035f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -62,7 +62,7 @@ TDownloadThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; public - manager: TTaskThread; + Task: TTaskThread; constructor Create; destructor Destroy; override; @@ -92,9 +92,9 @@ TTaskThread = class(TFMDThread) httpCookies: String; Flag: TFlagType; // container (for storing information) - container: TTaskContainer; + Container: TTaskContainer; // download threads - threads: TFPList; + Threads: TFPList; constructor Create; destructor Destroy; override; property AnotherURL: String read FAnotherURL write FAnotherURL; @@ -112,7 +112,7 @@ TTaskContainer = class // read count for transfer rate ReadCount: Integer; // task thread of this container - Thread: TTaskThread; + Task: TTaskThread; // download manager Manager: TDownloadManager; DownloadInfo: TDownloadInfo; @@ -255,7 +255,7 @@ procedure TDownloadThread.SockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); begin if Reason = HR_ReadCount then - manager.container.IncReadCount(StrToIntDef(Value, 0)); + Task.Container.IncReadCount(StrToIntDef(Value, 0)); end; constructor TDownloadThread.Create; @@ -296,14 +296,14 @@ procedure TDownloadThread.Execute; CS_GETPAGENUMBER: begin Reslt := GetPageNumberFromURL( - manager.container.ChapterLinks.Strings[ - manager.container.CurrentDownloadChapterPtr]); + Task.Container.ChapterLinks.Strings[ + Task.Container.CurrentDownloadChapterPtr]); // Prepare 'space' for storing image url. if (not Terminated) and - (manager.container.PageNumber > 0) then + (Task.Container.PageNumber > 0) then begin - while manager.container.PageLinks.Count < manager.container.PageNumber do - manager.container.PageLinks.Add('W'); + while Task.Container.PageLinks.Count < Task.Container.PageNumber do + Task.Container.PageLinks.Add('W'); end else Reslt := False; @@ -312,8 +312,8 @@ procedure TDownloadThread.Execute; CS_GETPAGELINK: begin Reslt := GetLinkPageFromURL( - manager.container.ChapterLinks.Strings[ - manager.container.CurrentDownloadChapterPtr]); + Task.Container.ChapterLinks.Strings[ + Task.Container.CurrentDownloadChapterPtr]); end; // Download images. CS_DOWNLOAD: @@ -324,13 +324,13 @@ procedure TDownloadThread.Execute; if not Terminated and Reslt then begin - manager.container.CS_Container.Acquire; + Task.Container.CS_Container.Acquire; try - manager.container.DownCounter := InterLockedIncrement(manager.container.DownCounter); - manager.container.DownloadInfo.Progress := - Format('%d/%d', [manager.container.DownCounter, manager.container.PageNumber]); + Task.Container.DownCounter := InterLockedIncrement(Task.Container.DownCounter); + Task.Container.DownloadInfo.Progress := + Format('%d/%d', [Task.Container.DownCounter, Task.Container.PageNumber]); finally - manager.container.CS_Container.Release; + Task.Container.CS_Container.Release; end; end; except @@ -339,11 +339,11 @@ procedure TDownloadThread.Execute; E.Message := E.Message + LineEnding + ' In TDownloadThread.Execute : ' + GetEnumName(TypeInfo(TFlagType), Integer(checkStyle)) + LineEnding + - ' Website : ' + manager.container.DownloadInfo.Website + LineEnding + - ' URL : ' + FillMangaSiteHost(manager.container.MangaSiteID, - manager.container.ChapterLinks[manager.container.CurrentDownloadChapterPtr]) + LineEnding + - ' Title : ' + manager.container.DownloadInfo.title + LineEnding + - ' Chapter : ' + manager.container.ChapterName[manager.container.CurrentDownloadChapterPtr] + + ' Website : ' + Task.Container.DownloadInfo.Website + LineEnding + + ' URL : ' + FillMangaSiteHost(Task.Container.MangaSiteID, + Task.Container.ChapterLinks[Task.Container.CurrentDownloadChapterPtr]) + LineEnding + + ' Title : ' + Task.Container.DownloadInfo.title + LineEnding + + ' Chapter : ' + Task.Container.ChapterName[Task.Container.CurrentDownloadChapterPtr] + LineEnding; MainForm.ExceptionHandler(Self, E); end; @@ -354,8 +354,8 @@ procedure TDownloadThread.DoTerminate; begin LockCreateConnection; try - Modules.DecActiveConnectionCount(manager.ModuleId); - manager.threads.Remove(Self); + Modules.DecActiveConnectionCount(Task.ModuleId); + Task.Threads.Remove(Self); finally UnlockCreateConnection; end; @@ -452,146 +452,146 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; begin Result := False; - manager.container.PageNumber := 0; + Task.Container.PageNumber := 0; - if Modules.ModuleAvailable(manager.ModuleId, MMGetPageNumber) then - Result := Modules.GetPageNumber(Self, URL, manager.ModuleId) + if Modules.ModuleAvailable(Task.ModuleId, MMGetPageNumber) then + Result := Modules.GetPageNumber(Self, URL, Task.ModuleId) else begin - if manager.container.MangaSiteID = ANIMEA_ID then + if Task.Container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAPageNumber else - if manager.container.MangaSiteID = MANGAINN_ID then + if Task.Container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnPageNumber else - if manager.container.MangaSiteID = MANGATRADERS_ID then + if Task.Container.MangaSiteID = MANGATRADERS_ID then Result := GetMangaTradersPageNumber else - if manager.container.MangaSiteID = STARKANA_ID then + if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaPageNumber else - if manager.container.MangaSiteID = EATMANGA_ID then + if Task.Container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaPageNumber else - if manager.container.MangaSiteID = MANGAPARK_ID then + if Task.Container.MangaSiteID = MANGAPARK_ID then Result := GetMangaParkPageNumber else - if manager.container.MangaSiteID = MANGAGO_ID then + if Task.Container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoPageNumber else - if manager.container.MangaSiteID = S2SCAN_ID then + if Task.Container.MangaSiteID = S2SCAN_ID then Result := GetS2scanPageNumber else - if manager.container.MangaSiteID = MEINMANGA_ID then + if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaPageNumber else - if manager.container.MangaSiteID = ESMANGAHERE_ID then + if Task.Container.MangaSiteID = ESMANGAHERE_ID then Result := GetEsMangaHerePageNumber else - if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then + if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistPageNumber else - if manager.container.MangaSiteID = KOMIKID_ID then + if Task.Container.MangaSiteID = KOMIKID_ID then Result := GetKomikidPageNumber else - if manager.container.MangaSiteID = HUGEMANGA_ID then + if Task.Container.MangaSiteID = HUGEMANGA_ID then Result := GetHugeMangaPageNumber else - if manager.container.MangaSiteID = ANIMESTORY_ID then + if Task.Container.MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryPageNumber else - if manager.container.MangaSiteID = TURKCRAFT_ID then + if Task.Container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftPageNumber else - if manager.container.MangaSiteID = MANGAAE_ID then + if Task.Container.MangaSiteID = MANGAAE_ID then Result := GetMangaAePageNumber else - if manager.container.MangaSiteID = MANGACOW_ID then + if Task.Container.MangaSiteID = MANGACOW_ID then Result := GetMangaCowPageNumber else - if manager.container.MangaSiteID = KIVMANGA_ID then + if Task.Container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else - if (manager.container.MangaSiteID = NINEMANGA_ID) or - (manager.container.MangaSiteID = NINEMANGA_ES_ID) or - (manager.container.MangaSiteID = NINEMANGA_CN_ID) or - (manager.container.MangaSiteID = NINEMANGA_RU_ID) or - (manager.container.MangaSiteID = NINEMANGA_DE_ID) or - (manager.container.MangaSiteID = NINEMANGA_IT_ID) or - (manager.container.MangaSiteID = NINEMANGA_BR_ID) then + if (Task.Container.MangaSiteID = NINEMANGA_ID) or + (Task.Container.MangaSiteID = NINEMANGA_ES_ID) or + (Task.Container.MangaSiteID = NINEMANGA_CN_ID) or + (Task.Container.MangaSiteID = NINEMANGA_RU_ID) or + (Task.Container.MangaSiteID = NINEMANGA_DE_ID) or + (Task.Container.MangaSiteID = NINEMANGA_IT_ID) or + (Task.Container.MangaSiteID = NINEMANGA_BR_ID) then Result := GetNineMangaPageNumber else - if manager.container.MangaSiteID = LECTUREENLIGNE_ID then + if Task.Container.MangaSiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLignePageNumber else - if manager.container.MangaSiteID = JAPANSHIN_ID then + if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinPageNumber else - if manager.container.MangaSiteID = JAPSCAN_ID then + if Task.Container.MangaSiteID = JAPSCAN_ID then Result := GetJapscanPageNumber else - if manager.container.MangaSiteID = CENTRUMMANGI_PL_ID then + if Task.Container.MangaSiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLPageNumber else - if manager.container.MangaSiteID = MANGALIB_PL_ID then + if Task.Container.MangaSiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLPageNumber else - if manager.container.MangaSiteID = ONEMANGA_ID then + if Task.Container.MangaSiteID = ONEMANGA_ID then Result := GetOneMangaPageNumber else - if manager.container.MangaSiteID = MANGATOWN_ID then + if Task.Container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownPageNumber else - if manager.container.MangaSiteID = MANGAOKU_ID then + if Task.Container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuPageNumber else - if manager.container.MangaSiteID = MYREADINGMANGAINFO_ID then + if Task.Container.MangaSiteID = MYREADINGMANGAINFO_ID then Result := GetMyReadingMangaInfoPageNumber else - if manager.container.MangaSiteID = IKOMIK_ID then + if Task.Container.MangaSiteID = IKOMIK_ID then Result := GetIKomikPageNumber else - if manager.container.MangaSiteID = NHENTAI_ID then + if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiPageNumber else - if manager.container.MangaSiteID = MANGAMINT_ID then + if Task.Container.MangaSiteID = MANGAMINT_ID then Result := GetMangaMintPageNumber else - if manager.container.MangaSiteID = UNIXMANGA_ID then + if Task.Container.MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaPageNumber else - if manager.container.MangaSiteID = EXTREMEMANGAS_ID then + if Task.Container.MangaSiteID = EXTREMEMANGAS_ID then Result := GetExtremeMangasPageNumber else - if manager.container.MangaSiteID = MANGAHOST_ID then + if Task.Container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostPageNumber else - if (manager.container.MangaSiteID = PORNCOMIX_ID) or - (manager.container.MangaSiteID = XXCOMICS_ID) or - (manager.container.MangaSiteID = XXCOMICSMT_ID) or - (manager.container.MangaSiteID = XXCOMICS3D_ID) or - (manager.container.MangaSiteID = PORNCOMIXRE_ID) or - (manager.container.MangaSiteID = PORNCOMIXIC_ID) or - (manager.container.MangaSiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixPageNumber(manager.container.MangaSiteID) + if (Task.Container.MangaSiteID = PORNCOMIX_ID) or + (Task.Container.MangaSiteID = XXCOMICS_ID) or + (Task.Container.MangaSiteID = XXCOMICSMT_ID) or + (Task.Container.MangaSiteID = XXCOMICS3D_ID) or + (Task.Container.MangaSiteID = PORNCOMIXRE_ID) or + (Task.Container.MangaSiteID = PORNCOMIXIC_ID) or + (Task.Container.MangaSiteID = PORNXXXCOMICS_ID) then + Result := GetPornComixPageNumber(Task.Container.MangaSiteID) else - if manager.container.MangaSiteID = MANGASEE_ID then + if Task.Container.MangaSiteID = MANGASEE_ID then Result := GetMangaSeePageNumber else - if manager.container.MangaSiteID = MANGAKU_ID then + if Task.Container.MangaSiteID = MANGAKU_ID then Result := GetMangaKuPageNumber else - if manager.container.MangaSiteID = MANGAAT_ID then + if Task.Container.MangaSiteID = MANGAAT_ID then Result := GetMangaAtPageNumber else - if manager.container.MangaSiteID = READMANGATODAY_ID then + if Task.Container.MangaSiteID = READMANGATODAY_ID then Result := GetReadMangaTodayPageNumber else - if manager.container.MangaSiteID = DYNASTYSCANS_ID then + if Task.Container.MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansPageNumber; end; - if manager.container.PageLinks.Count > 0 then - TrimStrings(manager.container.PageLinks); + if Task.Container.PageLinks.Count > 0 then + TrimStrings(Task.Container.PageLinks); end; function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; @@ -690,159 +690,159 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; begin Result := False; - if (manager.container.PageLinks.Count > 0) and - (manager.container.PageLinks.Strings[workCounter] <> 'W') then + if (Task.Container.PageLinks.Count > 0) and + (Task.Container.PageLinks.Strings[workCounter] <> 'W') then Exit; - if Modules.ModuleAvailable(manager.ModuleId, MMGetImageURL) then - Result := Modules.GetImageURL(Self, URL, manager.ModuleId) + if Modules.ModuleAvailable(Task.ModuleId, MMGetImageURL) then + Result := Modules.GetImageURL(Self, URL, Task.ModuleId) else begin - if manager.container.MangaSiteID = ANIMEA_ID then + if Task.Container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAImageURL else - if manager.container.MangaSiteID = MANGATRADERS_ID then + if Task.Container.MangaSiteID = MANGATRADERS_ID then Result := GetMangaTradersImageURL else - if manager.container.MangaSiteID = MANGAINN_ID then + if Task.Container.MangaSiteID = MANGAINN_ID then Result := GetMangaInnImageURL else - if manager.container.MangaSiteID = MANGA24H_ID then + if Task.Container.MangaSiteID = MANGA24H_ID then Result := GetManga24hImageURL else - if manager.container.MangaSiteID = VNSHARING_ID then + if Task.Container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else - if manager.container.MangaSiteID = FAKKU_ID then + if Task.Container.MangaSiteID = FAKKU_ID then Result := GetFakkuImageURL else - //if manager.container.MangaSiteID = MANGAPARK_ID then + //if Task.Container.MangaSiteID = MANGAPARK_ID then // Result := GetMangaParkImageURL //else - if manager.container.MangaSiteID = STARKANA_ID then + if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaImageURL else - if manager.container.MangaSiteID = EATMANGA_ID then + if Task.Container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaImageURL else - if manager.container.MangaSiteID = MANGAGO_ID then + if Task.Container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoImageURL else - if manager.container.MangaSiteID = EGSCANS_ID then + if Task.Container.MangaSiteID = EGSCANS_ID then Result := GetEGScansImageURL else - if manager.container.MangaSiteID = ESMANGAHERE_ID then + if Task.Container.MangaSiteID = ESMANGAHERE_ID then Result := GetEsMangaHereImageURL else - if manager.container.MangaSiteID = ANIMEEXTREMIST_ID then + if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else - if manager.container.MangaSiteID = KOMIKID_ID then + if Task.Container.MangaSiteID = KOMIKID_ID then Result := GetKomikidImageURL else - if manager.container.MangaSiteID = MABUNS_ID then + if Task.Container.MangaSiteID = MABUNS_ID then Result := GetMabunsImageURL else - if manager.container.MangaSiteID = MANGAESTA_ID then + if Task.Container.MangaSiteID = MANGAESTA_ID then Result := GetMangaEstaImageURL else - if manager.container.MangaSiteID = HUGEMANGA_ID then + if Task.Container.MangaSiteID = HUGEMANGA_ID then Result := GetHugeMangaImageURL else - if manager.container.MangaSiteID = ANIMESTORY_ID then + if Task.Container.MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryImageURL else - if manager.container.MangaSiteID = SCANMANGA_ID then + if Task.Container.MangaSiteID = SCANMANGA_ID then Result := GetScanMangaImageURL else - if manager.container.MangaSiteID = TURKCRAFT_ID then + if Task.Container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftImageURL else - if manager.container.MangaSiteID = MANGAAR_ID then + if Task.Container.MangaSiteID = MANGAAR_ID then Result := GetMangaArImageURL else - if manager.container.MangaSiteID = MANGAAE_ID then + if Task.Container.MangaSiteID = MANGAAE_ID then Result := GetMangaAeImageURL else - if manager.container.MangaSiteID = CENTRALDEMANGAS_ID then + if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else - if manager.container.MangaSiteID = MANGACOW_ID then + if Task.Container.MangaSiteID = MANGACOW_ID then Result := GetMangaCowImageURL else - if manager.container.MangaSiteID = TRUYENTRANHTUAN_ID then + if Task.Container.MangaSiteID = TRUYENTRANHTUAN_ID then Result := GetTruyenTranhTuanImageURL else - if manager.container.MangaSiteID = BLOGTRUYEN_ID then + if Task.Container.MangaSiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenImageURL else - if manager.container.MangaSiteID = KIVMANGA_ID then + if Task.Container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaImageURL else - if manager.container.MangaSiteID = MANGASPROJECT_ID then + if Task.Container.MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTImageURL else - if manager.container.MangaSiteID = MANGAREADER_POR_ID then + if Task.Container.MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORImageURL else - if (manager.container.MangaSiteID = NINEMANGA_ID) or - (manager.container.MangaSiteID = NINEMANGA_ES_ID) or - (manager.container.MangaSiteID = NINEMANGA_CN_ID) or - (manager.container.MangaSiteID = NINEMANGA_RU_ID) or - (manager.container.MangaSiteID = NINEMANGA_DE_ID) or - (manager.container.MangaSiteID = NINEMANGA_IT_ID) or - (manager.container.MangaSiteID = NINEMANGA_BR_ID) then + if (Task.Container.MangaSiteID = NINEMANGA_ID) or + (Task.Container.MangaSiteID = NINEMANGA_ES_ID) or + (Task.Container.MangaSiteID = NINEMANGA_CN_ID) or + (Task.Container.MangaSiteID = NINEMANGA_RU_ID) or + (Task.Container.MangaSiteID = NINEMANGA_DE_ID) or + (Task.Container.MangaSiteID = NINEMANGA_IT_ID) or + (Task.Container.MangaSiteID = NINEMANGA_BR_ID) then Result := GetNineMangaImageURL else - if manager.container.MangaSiteID = LECTUREENLIGNE_ID then + if Task.Container.MangaSiteID = LECTUREENLIGNE_ID then Result := GeLectureEnligneImageURL else - if manager.container.MangaSiteID = JAPANSHIN_ID then + if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinImageURL else - if manager.container.MangaSiteID = JAPSCAN_ID then + if Task.Container.MangaSiteID = JAPSCAN_ID then Result := GetJapscanImageURL else - if manager.container.MangaSiteID = CENTRUMMANGI_PL_ID then + if Task.Container.MangaSiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLImageURL else - if manager.container.MangaSiteID = MANGALIB_PL_ID then + if Task.Container.MangaSiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLImageURL else - if manager.container.MangaSiteID = ONEMANGA_ID then + if Task.Container.MangaSiteID = ONEMANGA_ID then Result := GetOneMangaImageURL else - if manager.container.MangaSiteID = MANGATOWN_ID then + if Task.Container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownImageURL else - if manager.container.MangaSiteID = MANGAOKU_ID then + if Task.Container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuImageURL else - if manager.container.MangaSiteID = IKOMIK_ID then + if Task.Container.MangaSiteID = IKOMIK_ID then Result := GetIKomikImageURL else - if manager.container.MangaSiteID = NHENTAI_ID then + if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiImageURL else - if manager.container.MangaSiteID = MANGAMINT_ID then + if Task.Container.MangaSiteID = MANGAMINT_ID then Result := GetMangaMintImageURL else - if manager.container.MangaSiteID = UNIXMANGA_ID then + if Task.Container.MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaImageURL else - if manager.container.MangaSiteID = MANGAHOST_ID then + if Task.Container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostImageURL else - if (manager.container.MangaSiteID = PORNCOMIX_ID) or - (manager.container.MangaSiteID = XXCOMICS_ID) or - (manager.container.MangaSiteID = XXCOMICSMT_ID) or - (manager.container.MangaSiteID = XXCOMICS3D_ID) or - (manager.container.MangaSiteID = PORNCOMIXRE_ID) or - (manager.container.MangaSiteID = PORNCOMIXIC_ID) or - (manager.container.MangaSiteID = PORNXXXCOMICS_ID) then + if (Task.Container.MangaSiteID = PORNCOMIX_ID) or + (Task.Container.MangaSiteID = XXCOMICS_ID) or + (Task.Container.MangaSiteID = XXCOMICSMT_ID) or + (Task.Container.MangaSiteID = XXCOMICS3D_ID) or + (Task.Container.MangaSiteID = PORNCOMIXRE_ID) or + (Task.Container.MangaSiteID = PORNCOMIXIC_ID) or + (Task.Container.MangaSiteID = PORNXXXCOMICS_ID) then Result := GetPornComixImageURL else - if manager.container.MangaSiteID = MANGAAT_ID then + if Task.Container.MangaSiteID = MANGAAT_ID then Result := GetMangaAtImageURL; end; end; @@ -867,7 +867,7 @@ procedure TDownloadThread.SetChangeDirectoryTrue; constructor TTaskThread.Create; begin inherited Create(True); - threads := TFPList.Create; + Threads := TFPList.Create; ModuleId := -1; FCheckAndActiveTaskFlag := True; anotherURL := ''; @@ -876,15 +876,15 @@ constructor TTaskThread.Create; destructor TTaskThread.Destroy; begin - threads.Free; + Threads.Free; inherited Destroy; end; procedure TTaskThread.MainThreadCompressRepaint; begin - container.DownloadInfo.Status := - Format('%s (%d/%d)', [RS_Compressing, container.CurrentDownloadChapterPtr + - 1, container.ChapterLinks.Count]); + Container.DownloadInfo.Status := + Format('%s (%d/%d)', [RS_Compressing, Container.CurrentDownloadChapterPtr + + 1, Container.ChapterLinks.Count]); MainForm.vtDownload.Repaint; end; @@ -897,18 +897,18 @@ procedure TTaskThread.Compress; var uPacker: TPacker; begin - if (container.Manager.compress >= 1) then + if (Container.Manager.compress >= 1) then begin Synchronize(MainThreadCompressRepaint); uPacker := TPacker.Create; try - case container.Manager.compress of + case Container.Manager.compress of 1: uPacker.Format := pfZIP; 2: uPacker.Format := pfCBZ; 3: uPacker.Format := pfPDF; end; uPacker.CompressionQuality := OptionPDFQuality; - uPacker.Path := container.CurrentWorkingDir; + uPacker.Path := Container.CurrentWorkingDir; uPacker.Execute; except on E: Exception do @@ -920,14 +920,14 @@ procedure TTaskThread.Compress; procedure TTaskThread.SyncStop; begin - container.Manager.CheckAndActiveTask(FCheckAndActiveTaskFlag); + Container.Manager.CheckAndActiveTask(FCheckAndActiveTaskFlag); end; procedure TTaskThread.SyncShowBaloon; begin - with MainForm.TrayIcon, container.DownloadInfo do + with MainForm.TrayIcon, Container.DownloadInfo do begin - if container.Status = STATUS_FAILED then + if Container.Status = STATUS_FAILED then begin BalloonFlags := bfError; BalloonHint := QuotedStrd(Title); @@ -937,11 +937,11 @@ procedure TTaskThread.SyncShowBaloon; BalloonHint := BalloonHint + LineEnding + Status; end else - if container.Status = STATUS_FINISH then + if Container.Status = STATUS_FINISH then begin BalloonFlags := bfInfo; BalloonHint := - '"' + container.DownloadInfo.title + '" - ' + RS_Finish; + '"' + Container.DownloadInfo.title + '" - ' + RS_Finish; end; ShowBalloonHint; end; @@ -959,17 +959,17 @@ function TDownloadThread.DownloadImage: Boolean; Result := True; // check download path - if not DirectoryExistsUTF8(manager.container.CurrentWorkingDir) then - if not ForceDirectoriesUTF8(manager.container.CurrentWorkingDir) then + if not DirectoryExistsUTF8(Task.Container.CurrentWorkingDir) then + if not ForceDirectoriesUTF8(Task.Container.CurrentWorkingDir) then begin - manager.container.Status := STATUS_FAILED; - manager.container.DownloadInfo.Status := RS_FailedToCreateDir; + Task.Container.Status := STATUS_FAILED; + Task.Container.DownloadInfo.Status := RS_FailedToCreateDir; Result := False; Exit; end; // check pagelinks url - workURL := manager.container.PageLinks[workCounter]; + workURL := Task.Container.PageLinks[workCounter]; if (workURL = '') or (workURL = 'W') or (workURL = 'D') then @@ -978,13 +978,13 @@ function TDownloadThread.DownloadImage: Boolean; FHTTP.Clear; // call beforedownloadimage if available - if Modules.ModuleAvailable(manager.ModuleId, MMBeforeDownloadImage) then - Result := Modules.BeforeDownloadImage(Self, workURL, manager.ModuleId); + if Modules.ModuleAvailable(Task.ModuleId, MMBeforeDownloadImage) then + Result := Modules.BeforeDownloadImage(Self, workURL, Task.ModuleId); // prepare filename workFilename := ''; - if workCounter < manager.container.Filenames.Count then - workFilename := manager.container.Filenames[workCounter]; + if workCounter < Task.Container.Filenames.Count then + workFilename := Task.Container.Filenames[workCounter]; if workFilename = '' then workFilename := Format('%.3d', [workCounter + 1]); @@ -992,43 +992,43 @@ function TDownloadThread.DownloadImage: Boolean; savedFilename := ''; if Result then begin - if Modules.ModuleAvailable(manager.ModuleId, MMDownloadImage) then + if Modules.ModuleAvailable(Task.ModuleId, MMDownloadImage) then begin workURL := ''; - if (manager.container.PageNumber = manager.container.PageContainerLinks.Count) - and (workCounter < manager.container.PageContainerLinks.Count) then - workURL := manager.container.PageContainerLinks[workCounter] - else if workCounter < manager.container.PageLinks.Count then - workURL := manager.container.PageLinks[workCounter]; + if (Task.Container.PageNumber = Task.Container.PageContainerLinks.Count) + and (workCounter < Task.Container.PageContainerLinks.Count) then + workURL := Task.Container.PageContainerLinks[workCounter] + else if workCounter < Task.Container.PageLinks.Count then + workURL := Task.Container.PageLinks[workCounter]; if workURL <> '' then Result := Modules.DownloadImage( Self, workURL, - manager.container.CurrentWorkingDir, + Task.Container.CurrentWorkingDir, workFilename, - manager.ModuleId); + Task.ModuleId); end else - if manager.container.MangaSiteID = MEINMANGA_ID then + if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL else Result := uBaseUnit.SaveImage( FHTTP, - manager.container.MangaSiteID, + Task.Container.MangaSiteID, workURL, - manager.container.CurrentWorkingDir, + Task.Container.CurrentWorkingDir, workFilename, savedFilename, - manager.container.Manager.retryConnect); + Task.Container.Manager.retryConnect); end; if Terminated then Exit(False); if Result then begin - manager.container.PageLinks[workCounter] := 'D'; + Task.Container.PageLinks[workCounter] := 'D'; - if Modules.ModuleAvailable(manager.ModuleId, MMAfterImageSaved) then - Modules.AfterImageSaved(savedFilename, manager.ModuleId); + if Modules.ModuleAvailable(Task.ModuleId, MMAfterImageSaved) then + Modules.AfterImageSaved(savedFilename, Task.ModuleId); end; end; @@ -1042,7 +1042,7 @@ procedure TTaskThread.CheckOut; //load advanced config if any mt := advancedfile.ReadInteger('DownloadMaxThreadsPerTask', - container.DownloadInfo.Website, -1); + Container.DownloadInfo.Website, -1); if (mt > 0) then begin if mt > MAX_CONNECTIONPERHOSTLIMIT then @@ -1054,23 +1054,23 @@ procedure TTaskThread.CheckOut; if Modules.MaxConnectionLimit[ModuleId] > 0 then currentMaxThread := Modules.MaxConnectionLimit[ModuleId] else - currentMaxThread := container.Manager.maxDLThreadsPerTask; - if currentMaxThread > container.Manager.maxDLThreadsPerTask then - currentMaxThread := container.Manager.maxDLThreadsPerTask; + currentMaxThread := Container.Manager.maxDLThreadsPerTask; + if currentMaxThread > Container.Manager.maxDLThreadsPerTask then + currentMaxThread := Container.Manager.maxDLThreadsPerTask; end; - if container.PageLinks.Count > 0 then + if Container.PageLinks.Count > 0 then begin - s := Trim(container.PageLinks[container.WorkCounter]); + s := Trim(Container.PageLinks[Container.WorkCounter]); if ((Flag = CS_GETPAGELINK) and (s <> 'W')) or ((Flag = CS_DOWNLOAD) and (s = 'D')) then begin - container.WorkCounter := InterLockedIncrement(container.WorkCounter); - container.DownCounter := InterLockedIncrement(container.DownCounter); - container.DownloadInfo.Progress := - Format('%d/%d', [container.DownCounter, container.PageNumber]); + Container.WorkCounter := InterLockedIncrement(Container.WorkCounter); + Container.DownCounter := InterLockedIncrement(Container.DownCounter); + Container.DownloadInfo.Progress := + Format('%d/%d', [Container.DownCounter, Container.PageNumber]); if Flag = CS_GETPAGELINK then - container.CurrentPageNumber := InterLockedIncrement(container.CurrentPageNumber); + Container.CurrentPageNumber := InterLockedIncrement(Container.CurrentPageNumber); Exit; end; end; @@ -1079,28 +1079,28 @@ procedure TTaskThread.CheckOut; while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do Sleep(SOCKHEARTBEATRATE) else - while (not Terminated) and (threads.Count >= currentMaxThread) do + while (not Terminated) and (Threads.Count >= currentMaxThread) do Sleep(SOCKHEARTBEATRATE); - if (not Terminated) and (threads.Count < currentMaxThread) then + if (not Terminated) and (Threads.Count < currentMaxThread) then begin LockCreateConnection; try if Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread then Exit; Modules.IncActiveConnectionCount(ModuleId); - threads.Add(TDownloadThread.Create); - with TDownloadThread(threads.Last) do begin - manager := Self; + Threads.Add(TDownloadThread.Create); + with TDownloadThread(Threads.Last) do begin + Task := Self; ModuleId := Self.ModuleId; - workCounter := container.WorkCounter; + workCounter := Container.WorkCounter; checkStyle := Flag; //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, container.DownloadInfo.Website); + AdvanceLoadHTTPConfig(FHTTP, Container.DownloadInfo.Website); Start; - container.WorkCounter := InterLockedIncrement(container.WorkCounter); + Container.WorkCounter := InterLockedIncrement(Container.WorkCounter); end; if Flag = CS_GETPAGELINK then - container.CurrentPageNumber := InterLockedIncrement(container.CurrentPageNumber); + Container.CurrentPageNumber := InterLockedIncrement(Container.CurrentPageNumber); finally UnlockCreateConnection; end; @@ -1113,13 +1113,13 @@ procedure TTaskThread.Execute; var i: Integer; begin - if container.PageLinks.Count = 0 then + if Container.PageLinks.Count = 0 then Exit(True); Result := False; - if container.PageLinks.Count > 0 then - for i := 0 to container.PageLinks.Count - 1 do - if (Trim(container.PageLinks[i]) = 'W') or - (Trim(container.PageLinks[i]) = '') then + if Container.PageLinks.Count > 0 then + for i := 0 to Container.PageLinks.Count - 1 do + if (Trim(Container.PageLinks[i]) = 'W') or + (Trim(Container.PageLinks[i]) = '') then Exit(True); end; @@ -1127,7 +1127,7 @@ procedure TTaskThread.Execute; var i, c: Integer; begin - if container.PageLinks.Count > 0 then + if Container.PageLinks.Count > 0 then Result := True else begin @@ -1136,25 +1136,25 @@ procedure TTaskThread.Execute; end; c := 0; - for i := 0 to container.PageLinks.Count - 1 do + for i := 0 to Container.PageLinks.Count - 1 do begin - if Trim(container.PageLinks[i]) <> 'D' then + if Trim(Container.PageLinks[i]) <> 'D' then Inc(c); end; if c > 0 then begin WriteLog_W(Format('%s, checkforfinish failed=%d/%d "%s" > "%s"', [Self.ClassName, c, - container.PageLinks.Count, - container.DownloadInfo.Title, - container.ChapterName[container.CurrentDownloadChapterPtr]])); + Container.PageLinks.Count, + Container.DownloadInfo.Title, + Container.ChapterName[Container.CurrentDownloadChapterPtr]])); Result := False; end; end; procedure WaitForThreads; begin - while (not Terminated) and (threads.Count > 0) do + while (not Terminated) and (Threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); end; @@ -1163,149 +1163,149 @@ procedure TTaskThread.Execute; s: String; DynamicPageLink: Boolean; begin - ModuleId := container.ModuleId; - container.ThreadState := True; - container.DownloadInfo.TransferRate := FormatByteSize(container.ReadCount, true); + ModuleId := Container.ModuleId; + Container.ThreadState := True; + Container.DownloadInfo.TransferRate := FormatByteSize(Container.ReadCount, true); try - if container.ModuleId > -1 then + if Container.ModuleId > -1 then DynamicPageLink := Modules.Module[ModuleId].DynamicPageLink else DynamicPageLink := False; - while container.CurrentDownloadChapterPtr < container.ChapterLinks.Count do + while Container.CurrentDownloadChapterPtr < Container.ChapterLinks.Count do begin WaitForThreads; if Terminated then Exit; //check path - container.CurrentWorkingDir := CleanAndExpandDirectory(container.DownloadInfo.SaveTo + - container.ChapterName[container.CurrentDownloadChapterPtr]); - if not DirectoryExistsUTF8(container.CurrentWorkingDir) then - if not ForceDirectoriesUTF8(container.CurrentWorkingDir) then + Container.CurrentWorkingDir := CleanAndExpandDirectory(Container.DownloadInfo.SaveTo + + Container.ChapterName[Container.CurrentDownloadChapterPtr]); + if not DirectoryExistsUTF8(Container.CurrentWorkingDir) then + if not ForceDirectoriesUTF8(Container.CurrentWorkingDir) then begin - container.Status := STATUS_FAILED; - container.DownloadInfo.Status := RS_FailedToCreateDir; + Container.Status := STATUS_FAILED; + Container.DownloadInfo.Status := RS_FailedToCreateDir; SyncShowBaloon; Exit; end; if ModuleId > -1 then - Modules.TaskStart(container, ModuleId); + Modules.TaskStart(Container, ModuleId); // Get page number. - if container.PageLinks.Count = 0 then + if Container.PageLinks.Count = 0 then begin - container.PageNumber := 0; + Container.PageNumber := 0; Flag := CS_GETPAGENUMBER; - container.WorkCounter := 0; - container.DownCounter := 0; - container.DownloadInfo.iProgress := 0; - container.DownloadInfo.Progress := '0/0'; - container.DownloadInfo.Status := + Container.WorkCounter := 0; + Container.DownCounter := 0; + Container.DownloadInfo.iProgress := 0; + Container.DownloadInfo.Progress := '0/0'; + Container.DownloadInfo.Status := Format('%s (%d/%d [%s])', [RS_Preparing, - container.CurrentDownloadChapterPtr + 1, - container.ChapterLinks.Count, - container.ChapterName[container.CurrentDownloadChapterPtr]]); - container.Status := STATUS_PREPARE; + Container.CurrentDownloadChapterPtr + 1, + Container.ChapterLinks.Count, + Container.ChapterName[Container.CurrentDownloadChapterPtr]]); + Container.Status := STATUS_PREPARE; CheckOut; WaitForThreads; if Terminated then begin - container.PageLinks.Clear; - container.PageNumber := 0; + Container.PageLinks.Clear; + Container.PageNumber := 0; Exit; end; end; //Check file, if exist set mark 'D', otherwise 'W' or 'G' for dynamic image url - if container.PageLinks.Count > 0 then + if Container.PageLinks.Count > 0 then begin - for j := 0 to container.PageLinks.Count - 1 do + for j := 0 to Container.PageLinks.Count - 1 do begin - if container.Filenames.Count = container.PageLinks.Count then - s := container.CurrentWorkingDir + container.Filenames[j] + if Container.Filenames.Count = Container.PageLinks.Count then + s := Container.CurrentWorkingDir + Container.Filenames[j] else - s := container.CurrentWorkingDir + Format('%.3d', [j + 1]); + s := Container.CurrentWorkingDir + Format('%.3d', [j + 1]); if ImageFileExist(s) then - container.PageLinks[j] := 'D' + Container.PageLinks[j] := 'D' else - if container.PageLinks[j] = 'D' then + if Container.PageLinks[j] = 'D' then begin if DynamicPageLink then - container.PageLinks[j] := 'G' + Container.PageLinks[j] := 'G' else - container.PageLinks[j] := 'W'; + Container.PageLinks[j] := 'W'; end; end; end; //Get page links - if container.PageLinks.Count = 0 then - container.PageLinks.Add('W'); - container.PageNumber := container.PageLinks.Count; + if Container.PageLinks.Count = 0 then + Container.PageLinks.Add('W'); + Container.PageNumber := Container.PageLinks.Count; if (not DynamicPageLink) and CheckForPrepare then begin Flag := CS_GETPAGELINK; - container.WorkCounter := 0; - container.DownCounter := 0; - container.DownloadInfo.iProgress := 0; - container.DownloadInfo.Progress := - Format('%d/%d', [container.DownCounter, container.PageNumber]); - container.DownloadInfo.Status := + Container.WorkCounter := 0; + Container.DownCounter := 0; + Container.DownloadInfo.iProgress := 0; + Container.DownloadInfo.Progress := + Format('%d/%d', [Container.DownCounter, Container.PageNumber]); + Container.DownloadInfo.Status := Format('%s (%d/%d [%s])', [RS_Preparing, - container.CurrentDownloadChapterPtr + 1, - container.ChapterLinks.Count, - container.ChapterName[container.CurrentDownloadChapterPtr]]); - container.Status := STATUS_PREPARE; - while container.WorkCounter < container.PageNumber do + Container.CurrentDownloadChapterPtr + 1, + Container.ChapterLinks.Count, + Container.ChapterName[Container.CurrentDownloadChapterPtr]]); + Container.Status := STATUS_PREPARE; + while Container.WorkCounter < Container.PageNumber do begin if Terminated then Exit; Checkout; - container.DownloadInfo.iProgress := - InterLockedIncrement(container.DownloadInfo.iProgress); + Container.DownloadInfo.iProgress := + InterLockedIncrement(Container.DownloadInfo.iProgress); end; WaitForThreads; if Terminated then Exit; //check if pagelink is found. Else set again to 'W'(some script return '') - if container.PageLinks.Count > 0 then + if Container.PageLinks.Count > 0 then begin - for j := 0 to container.PageLinks.Count - 1 do + for j := 0 to Container.PageLinks.Count - 1 do begin - if Trim(container.PageLinks[j]) = '' then - container.PageLinks[j] := 'W'; + if Trim(Container.PageLinks[j]) = '' then + Container.PageLinks[j] := 'W'; end; end; end; if Terminated then Exit; // download pages - // If container doesn't have any image, we will skip the loop. Otherwise + // If Container doesn't have any image, we will skip the loop. Otherwise // download them - container.PageNumber := container.PageLinks.Count; - if (container.PageLinks.Count > 0) then + Container.PageNumber := Container.PageLinks.Count; + if (Container.PageLinks.Count > 0) then begin Flag := CS_DOWNLOAD; - container.WorkCounter := 0; - container.DownCounter := 0; - container.DownloadInfo.iProgress := 0; - container.DownloadInfo.Progress := - Format('%d/%d', [container.DownCounter, container.PageNumber]); - container.Status := STATUS_DOWNLOAD; - container.DownloadInfo.Status := + Container.WorkCounter := 0; + Container.DownCounter := 0; + Container.DownloadInfo.iProgress := 0; + Container.DownloadInfo.Progress := + Format('%d/%d', [Container.DownCounter, Container.PageNumber]); + Container.Status := STATUS_DOWNLOAD; + Container.DownloadInfo.Status := Format('%s (%d/%d) [%s]', [RS_Downloading, - container.CurrentDownloadChapterPtr + 1, - container.ChapterLinks.Count, - container.ChapterName[container.CurrentDownloadChapterPtr]]); - while container.WorkCounter < container.PageLinks.Count do + Container.CurrentDownloadChapterPtr + 1, + Container.ChapterLinks.Count, + Container.ChapterName[Container.CurrentDownloadChapterPtr]]); + while Container.WorkCounter < Container.PageLinks.Count do begin if Terminated then Exit; Checkout; - container.DownloadInfo.iProgress := - InterLockedIncrement(container.DownloadInfo.iProgress); + Container.DownloadInfo.iProgress := + InterLockedIncrement(Container.DownloadInfo.iProgress); end; WaitForThreads; if Terminated then Exit; @@ -1313,54 +1313,54 @@ procedure TTaskThread.Execute; //check if all page is downloaded if CheckForFinish then begin - container.Status := STATUS_COMPRESS; - container.DownloadInfo.Progress := ''; + Container.Status := STATUS_COMPRESS; + Container.DownloadInfo.Progress := ''; Compress; end else - container.Status := STATUS_FAILED; + Container.Status := STATUS_FAILED; end else begin WriteLog_W(Format('%s, failed download image PageLinks=%d "%s" > "%s"', [Self.ClassName, - container.PageLinks.Count, - container.DownloadInfo.Title, - container.ChapterName[container.CurrentDownloadChapterPtr]])); - container.Status := STATUS_FAILED; + Container.PageLinks.Count, + Container.DownloadInfo.Title, + Container.ChapterName[Container.CurrentDownloadChapterPtr]])); + Container.Status := STATUS_FAILED; end; - if (container.Status = STATUS_FAILED) and - (not FindStrLinear(container.FailedChapterLinks, - container.ChapterName[container.CurrentDownloadChapterPtr])) then + if (Container.Status = STATUS_FAILED) and + (not FindStrLinear(Container.FailedChapterLinks, + Container.ChapterName[Container.CurrentDownloadChapterPtr])) then begin - container.FailedChapterName.Add(container.ChapterName[container.CurrentDownloadChapterPtr]); - container.FailedChapterLinks.Add(container.ChapterLinks[container.CurrentDownloadChapterPtr]); + Container.FailedChapterName.Add(Container.ChapterName[Container.CurrentDownloadChapterPtr]); + Container.FailedChapterLinks.Add(Container.ChapterLinks[Container.CurrentDownloadChapterPtr]); end; - container.CurrentPageNumber := 0; - container.PageLinks.Clear; - container.PageContainerLinks.Clear; - container.CurrentDownloadChapterPtr := - InterLockedIncrement(container.CurrentDownloadChapterPtr); + Container.CurrentPageNumber := 0; + Container.PageLinks.Clear; + Container.PageContainerLinks.Clear; + Container.CurrentDownloadChapterPtr := + InterLockedIncrement(Container.CurrentDownloadChapterPtr); end; - if container.FailedChapterLinks.Count > 0 then + if Container.FailedChapterLinks.Count > 0 then begin - container.Status := STATUS_FAILED; - container.DownloadInfo.Status := RS_FailedTryResumeTask; - container.DownloadInfo.Progress := ''; - container.CurrentDownloadChapterPtr := 0; - - container.ChapterName.Assign(container.FailedChapterName); - container.ChapterLinks.Assign(container.FailedChapterLinks); - container.FailedChapterName.Clear; - container.FailedChapterLinks.Clear; + Container.Status := STATUS_FAILED; + Container.DownloadInfo.Status := RS_FailedTryResumeTask; + Container.DownloadInfo.Progress := ''; + Container.CurrentDownloadChapterPtr := 0; + + Container.ChapterName.Assign(Container.FailedChapterName); + Container.ChapterLinks.Assign(Container.FailedChapterLinks); + Container.FailedChapterName.Clear; + Container.FailedChapterLinks.Clear; end else begin - container.Status := STATUS_FINISH; - container.DownloadInfo.Status := RS_Finish; - container.DownloadInfo.Progress := ''; + Container.Status := STATUS_FINISH; + Container.DownloadInfo.Status := RS_Finish; + Container.DownloadInfo.Progress := ''; end; Synchronize(SyncShowBaloon); except @@ -1373,27 +1373,27 @@ procedure TTaskThread.DoTerminate; var i: Integer; begin - if threads.Count > 0 then + if Threads.Count > 0 then begin LockCreateConnection; try - for i := 0 to threads.Count - 1 do - TDownloadThread(threads[i]).Terminate; + for i := 0 to Threads.Count - 1 do + TDownloadThread(Threads[i]).Terminate; finally UnlockCreateConnection; end; - while threads.Count > 0 do + while Threads.Count > 0 do Sleep(100); end; Modules.DecActiveTaskCount(ModuleId); - with container do begin - container.ReadCount := 0; + with Container do begin + Container.ReadCount := 0; DownloadInfo.TransferRate := ''; ThreadState := False; - Thread := nil; + Task := nil; Manager.CS_Task.Acquire; try - Manager.ContainersActiveTask.Remove(container); + Manager.ContainersActiveTask.Remove(Container); finally Manager.CS_Task.Release; end; @@ -1832,10 +1832,10 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); DownloadInfo.Status := RS_Downloading; end; Modules.IncActiveTaskCount(ModuleId); - Thread := TTaskThread.Create; - Thread.container := TTaskContainer(Containers[taskID]); - ContainersActiveTask.Add(Thread.container); - Thread.Start; + Task := TTaskThread.Create; + Task.Container := TTaskContainer(Containers[taskID]); + ContainersActiveTask.Add(Task.Container); + Task.Start; end; end; end; @@ -1852,9 +1852,9 @@ procedure TDownloadManager.StopTask(const taskID: Integer; end else if ThreadState then begin - Thread.Terminate; + Task.Terminate; if isWaitFor then - Thread.WaitFor; + Task.WaitFor; end; if isCheckForActive then CheckAndActiveTask(); @@ -1898,11 +1898,11 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; for i := 0 to Containers.Count - 1 do with TTaskContainer(Containers[i]) do if ThreadState then - Thread.Terminate; + Task.Terminate; for i := 0 to Containers.Count - 1 do with TTaskContainer(Containers[i]) do if ThreadState then - Thread.WaitFor; + Task.WaitFor; finally isReadyForExit := False; end; @@ -1915,8 +1915,8 @@ procedure TDownloadManager.RemoveTask(const taskID: Integer); try with TTaskContainer(Containers[taskID]) do if ThreadState then begin - Thread.Terminate; - Thread.WaitFor; + Task.Terminate; + Task.WaitFor; end; TTaskContainer(Containers[taskID]).Free; Containers.Delete(taskID); From 8c4f279e0f47a175c34be931a673804f0dbf08fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 28 May 2016 21:48:52 +0800 Subject: [PATCH 1185/2794] downloadmanager, cleanup and fix --- .../includes/AnimExtremist/image_url.inc | 4 +- baseunits/includes/AnimeA/image_url.inc | 4 +- baseunits/includes/AnimeStory/image_url.inc | 4 +- .../includes/CentralDeMangas/image_url.inc | 2 +- baseunits/includes/EGScans/image_url.inc | 2 +- baseunits/includes/EatManga/image_url.inc | 4 +- baseunits/includes/EsMangaHere/image_url.inc | 6 +- baseunits/includes/HugeManga/image_url.inc | 4 +- baseunits/includes/IKomik/image_url.inc | 4 +- baseunits/includes/JapanShin/image_url.inc | 4 +- baseunits/includes/Japscan/image_url.inc | 4 +- baseunits/includes/Kivmanga/image_url.inc | 4 +- baseunits/includes/Komikid/image_url.inc | 4 +- .../includes/LectureEnLigne/image_url.inc | 4 +- baseunits/includes/MangaAe/image_url.inc | 4 +- baseunits/includes/MangaAt/image_url.inc | 4 +- baseunits/includes/MangaGo/image_url.inc | 4 +- baseunits/includes/MangaHost/image_url.inc | 4 +- baseunits/includes/MangaInn/image_url.inc | 4 +- baseunits/includes/MangaLib_PL/image_url.inc | 4 +- baseunits/includes/MangaMint/image_url.inc | 6 +- baseunits/includes/MangaOku/image_url.inc | 4 +- baseunits/includes/MangaPark/image_url.inc | 2 +- baseunits/includes/MangaTown/image_url.inc | 6 +- baseunits/includes/MangaTraders/image_url.inc | 4 +- baseunits/includes/Mangacow/image_url.inc | 4 +- baseunits/includes/MeinManga/image_url.inc | 8 +- baseunits/includes/NHentai/image_url.inc | 4 +- baseunits/includes/NineManga/image_url.inc | 4 +- baseunits/includes/OneManga/image_url.inc | 4 +- baseunits/includes/PornComix/image_url.inc | 6 +- baseunits/includes/Starkana/image_url.inc | 4 +- baseunits/includes/Turkcraft/image_url.inc | 4 +- baseunits/includes/UnixManga/image_url.inc | 4 +- baseunits/modules/Batoto.pas | 4 +- baseunits/modules/EightMuses.pas | 4 +- baseunits/modules/FoOlSlide.pas | 6 +- baseunits/modules/Hakihome.pas | 4 +- baseunits/modules/Hentai2Read.pas | 6 +- baseunits/modules/HeyMangaXyz.pas | 4 +- baseunits/modules/MangaEden.pas | 4 +- baseunits/modules/MangaFox.pas | 4 +- baseunits/modules/MangaHere.pas | 6 +- baseunits/modules/MangaKoi.pas | 4 +- baseunits/modules/MangaReader.pas | 4 +- baseunits/modules/MangaStream.pas | 4 +- baseunits/modules/MangaStreamTo.pas | 4 +- baseunits/modules/MangaTr.pas | 6 +- baseunits/modules/PecintaKomik.pas | 4 +- baseunits/modules/RawSenManga.pas | 4 +- baseunits/modules/Submanga.pas | 6 +- baseunits/modules/WPManga.pas | 4 +- baseunits/uBaseUnit.pas | 1 - baseunits/uDownloadsManager.pas | 118 ++++++------------ 54 files changed, 150 insertions(+), 193 deletions(-) diff --git a/baseunits/includes/AnimExtremist/image_url.inc b/baseunits/includes/AnimExtremist/image_url.inc index eca64a9a0..66d612d01 100644 --- a/baseunits/includes/AnimExtremist/image_url.inc +++ b/baseunits/includes/AnimExtremist/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := DecodeUrl(StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), - '.html', '', []) + '-' + IntToStr(workCounter + 1) + '.html'); + '.html', '', []) + '-' + IntToStr(Task.Container.WorkCounter + 1) + '.html'); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -23,7 +23,7 @@ if (Pos('id="photo"', parse[i]) > 0) then begin s := GetVal(parse[i], 'src'); - Task.Container.pageLinks[workCounter] := + Task.Container.pageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/AnimeA/image_url.inc b/baseunits/includes/AnimeA/image_url.inc index 7740106a1..374865996 100644 --- a/baseunits/includes/AnimeA/image_url.inc +++ b/baseunits/includes/AnimeA/image_url.inc @@ -7,7 +7,7 @@ Result := GetPage(TObject(l), FillMangaSiteHost(ANIMEA_ID, StringReplace(URL, '.html', '', []) + - '-page-' + IntToStr(workCounter + 1) + '.html'), + '-page-' + IntToStr(Task.Container.WorkCounter + 1) + '.html'), Task.Container.Manager.retryConnect); parse := TStringList.Create; @@ -24,7 +24,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="scanmr"', parse[i]) > 0) and (Pos('id="scanmr"', parse[i])> 0) then - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); end; end; parse.Free; diff --git a/baseunits/includes/AnimeStory/image_url.inc b/baseunits/includes/AnimeStory/image_url.inc index c3fde76df..ac3be1721 100644 --- a/baseunits/includes/AnimeStory/image_url.inc +++ b/baseunits/includes/AnimeStory/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(workCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(Task.Container.WorkCounter + 1)); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('id="chpimg"', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := DecodeURL(GetVal(parse[i], 'src')); Break; end; diff --git a/baseunits/includes/CentralDeMangas/image_url.inc b/baseunits/includes/CentralDeMangas/image_url.inc index 0d80cbce1..06b4a399a 100644 --- a/baseunits/includes/CentralDeMangas/image_url.inc +++ b/baseunits/includes/CentralDeMangas/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := EncodeUrl(FillMangaSiteHost(CENTRALDEMANGAS_ID, URL)); - // + IntToStr(workCounter+1)); + // + IntToStr(Task.Container.WorkCounter+1)); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); diff --git a/baseunits/includes/EGScans/image_url.inc b/baseunits/includes/EGScans/image_url.inc index e20229d88..189896420 100644 --- a/baseunits/includes/EGScans/image_url.inc +++ b/baseunits/includes/EGScans/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(workCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); diff --git a/baseunits/includes/EatManga/image_url.inc b/baseunits/includes/EatManga/image_url.inc index d1c35253c..6bbb91b5e 100644 --- a/baseunits/includes/EatManga/image_url.inc +++ b/baseunits/includes/EatManga/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(workCounter + 1)), + DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(Task.Container.WorkCounter + 1)), Task.Container.Manager.retryConnect); parse := TStringList.Create; @@ -25,7 +25,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'eatmanga_image') then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/EsMangaHere/image_url.inc b/baseunits/includes/EsMangaHere/image_url.inc index 792aa05a5..b74c5e7c1 100644 --- a/baseunits/includes/EsMangaHere/image_url.inc +++ b/baseunits/includes/EsMangaHere/image_url.inc @@ -4,10 +4,10 @@ l: TStringList; begin l := TStringList.Create; - if workCounter > 0 then + if Task.Container.WorkCounter > 0 then Result := GetPage(TObject(l), FillMangaSiteHost(ESMANGAHERE_ID, URL) + - IntToStr(workCounter + 1) + '.html', + IntToStr(Task.Container.WorkCounter + 1) + '.html', Task.Container.manager.retryConnect) else Result := GetPage(TObject(l), @@ -25,7 +25,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="read_img"', parse[i]) <> 0) then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i + 6], 'src'); parse.Free; l.Free; diff --git a/baseunits/includes/HugeManga/image_url.inc b/baseunits/includes/HugeManga/image_url.inc index 3c32f7e08..56e9659fd 100644 --- a/baseunits/includes/HugeManga/image_url.inc +++ b/baseunits/includes/HugeManga/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="picture"', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := EncodeURL(WebsiteRoots[HUGEMANGA_ID, 1] + HUGEMANGA_BROWSER + GetVal(parse[i], 'src')); Break; diff --git a/baseunits/includes/IKomik/image_url.inc b/baseunits/includes/IKomik/image_url.inc index 88ec000fa..a7d749e57 100644 --- a/baseunits/includes/IKomik/image_url.inc +++ b/baseunits/includes/IKomik/image_url.inc @@ -9,7 +9,7 @@ if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - s := s + IntToStr(QWord(workCounter) + 1); + s := s + IntToStr(QWord(Task.Container.WorkCounter) + 1); Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -36,7 +36,7 @@ begin if Pos('<img', parse[j]) > 0 then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[j], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[j], 'src'); Break; end; end; diff --git a/baseunits/includes/JapanShin/image_url.inc b/baseunits/includes/JapanShin/image_url.inc index 7b7e842ce..589744a30 100644 --- a/baseunits/includes/JapanShin/image_url.inc +++ b/baseunits/includes/JapanShin/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - FillMangaSiteHost(JAPANSHIN_ID, URL) + '/page/' + IntToStr(workCounter), + FillMangaSiteHost(JAPANSHIN_ID, URL) + '/page/' + IntToStr(Task.Container.WorkCounter), Task.Container.Manager.retryConnect); if Self.Terminated then @@ -27,7 +27,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="open"', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/Japscan/image_url.inc b/baseunits/includes/Japscan/image_url.inc index f573b647b..fef8cb810 100644 --- a/baseunits/includes/Japscan/image_url.inc +++ b/baseunits/includes/Japscan/image_url.inc @@ -7,7 +7,7 @@ s := DecodeUrl(FillMangaSiteHost(JAPSCAN_ID, URL)); if Pos('.htm', s) > 0 then s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/' + IntToStr(workCounter + 1) + '.html'; + s := s + '/' + IntToStr(Task.Container.WorkCounter + 1) + '.html'; l := TStringList.Create; Result := GetPage(TObject(l), s, @@ -24,7 +24,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'imgscan') then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/Kivmanga/image_url.inc b/baseunits/includes/Kivmanga/image_url.inc index d2b120a94..c645cc044 100644 --- a/baseunits/includes/Kivmanga/image_url.inc +++ b/baseunits/includes/Kivmanga/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(workCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); @@ -23,7 +23,7 @@ begin s := WebsiteRoots[KIVMANGA_ID, 1] + KIVMANGA_BROWSER + GetVal(parse[i], 'src'); - Task.Container.PageLinks[workCounter] := EncodeURL(s); + Task.Container.PageLinks[Task.Container.WorkCounter] := EncodeURL(s); Break; end; end; diff --git a/baseunits/includes/Komikid/image_url.inc b/baseunits/includes/Komikid/image_url.inc index 7eeea39d4..8c6e297e9 100644 --- a/baseunits/includes/Komikid/image_url.inc +++ b/baseunits/includes/Komikid/image_url.inc @@ -7,7 +7,7 @@ begin l := TStringList.Create; s := EncodeURL(FillMangaSiteHost(KOMIKID_ID, URL) + '/' + - IntToStr(workCounter + 1) + '/'); + IntToStr(Task.Container.WorkCounter + 1) + '/'); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -32,7 +32,7 @@ if not regx.Exec(s) then s := WebsiteRoots[KOMIKID_ID, 1] + '/' + s; s := EncodeURL(s); - Task.container.PageLinks[workCounter] := s; + Task.container.PageLinks[Task.Container.WorkCounter] := s; finally regx.Free; end; diff --git a/baseunits/includes/LectureEnLigne/image_url.inc b/baseunits/includes/LectureEnLigne/image_url.inc index c5efbe89f..95b4070dd 100644 --- a/baseunits/includes/LectureEnLigne/image_url.inc +++ b/baseunits/includes/LectureEnLigne/image_url.inc @@ -7,7 +7,7 @@ s := DecodeUrl(FillMangaSiteHost(LECTUREENLIGNE_ID, URL)); if Pos('.htm', s) > 0 then s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/' + IntToStr(workCounter + 1) + '.html'; + s := s + '/' + IntToStr(Task.Container.WorkCounter + 1) + '.html'; l := TStringList.Create; Result := GetPage(TObject(l), s, @@ -24,7 +24,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'image') then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/MangaAe/image_url.inc b/baseunits/includes/MangaAe/image_url.inc index 0393f348d..b7ab17b7d 100644 --- a/baseunits/includes/MangaAe/image_url.inc +++ b/baseunits/includes/MangaAe/image_url.inc @@ -6,7 +6,7 @@ isImageURL: Boolean = False; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(workCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); @@ -25,7 +25,7 @@ isImageURL := True; if isImageURL and (Pos('<img', parse[i]) <> 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaAt/image_url.inc b/baseunits/includes/MangaAt/image_url.inc index e290710d6..796a13687 100644 --- a/baseunits/includes/MangaAt/image_url.inc +++ b/baseunits/includes/MangaAt/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := FillMangaSiteHost(MANGAAT_ID, URL) + - '/' + IntToStr(workCounter + 1) + '/'; + '/' + IntToStr(Task.Container.WorkCounter + 1) + '/'; Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -26,7 +26,7 @@ if GetVal(parse[i], 'id') = 'showchaptercontainer' then if (GetTagName(parse[i + 3]) = 'img') then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i + 3], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i + 3], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/MangaGo/image_url.inc b/baseunits/includes/MangaGo/image_url.inc index 21665d2b1..ed5d5a8cc 100644 --- a/baseunits/includes/MangaGo/image_url.inc +++ b/baseunits/includes/MangaGo/image_url.inc @@ -14,7 +14,7 @@ if (not regx.Exec(s)) and (s[Length(s)] <> '/') then s := s + '/'; s := FillMangaSiteHost(MANGAGO_ID, s); - Result := GetPage(TObject(l), s + IntToStr(workCounter + 1) + '/', + Result := GetPage(TObject(l), s + IntToStr(Task.Container.WorkCounter + 1) + '/', Task.Container.Manager.retryConnect); if Self.Terminated then @@ -38,7 +38,7 @@ if (Pos('imgReady(''', parse[i]) > 0) then begin regx.Expression := '^.*imgReady\(''([^'']*)''.*$'; - Task.Container.PageLinks[workCounter] := regx.Replace(parse[i], '$1', True); + Task.Container.PageLinks[Task.Container.WorkCounter] := regx.Replace(parse[i], '$1', True); Break; end; end; diff --git a/baseunits/includes/MangaHost/image_url.inc b/baseunits/includes/MangaHost/image_url.inc index 628d501ac..1b3f41034 100644 --- a/baseunits/includes/MangaHost/image_url.inc +++ b/baseunits/includes/MangaHost/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL) + '/' + IntToStr(workCounter + 1)), + DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)), Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -19,7 +19,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) > 0) and (Pos('class="open', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaInn/image_url.inc b/baseunits/includes/MangaInn/image_url.inc index 2b457687b..726f99d83 100644 --- a/baseunits/includes/MangaInn/image_url.inc +++ b/baseunits/includes/MangaInn/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(MANGAINN_ID, URL) + - '/page_' + IntToStr(workCounter + 1), + '/page_' + IntToStr(Task.Container.WorkCounter + 1), Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -21,7 +21,7 @@ if GetTagName(parse[i]) = 'img' then if GetVal(parse[i], 'id') = 'imgPage' then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/MangaLib_PL/image_url.inc b/baseunits/includes/MangaLib_PL/image_url.inc index 657090942..49de5966e 100644 --- a/baseunits/includes/MangaLib_PL/image_url.inc +++ b/baseunits/includes/MangaLib_PL/image_url.inc @@ -6,7 +6,7 @@ cf: Boolean = False; begin l := TStringList.Create; - s := FillMangaSiteHost(MANGALIB_PL_ID, URL) + ',' + IntToStr(workCounter + 1); + s := FillMangaSiteHost(MANGALIB_PL_ID, URL) + ',' + IntToStr(Task.Container.WorkCounter + 1); Result := GetPage(TObject(l), s, @@ -53,7 +53,7 @@ if (Pos('<img ', parse[i]) > 0) and (Pos('id="img_curr"', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaMint/image_url.inc b/baseunits/includes/MangaMint/image_url.inc index 4a7ec1d61..65a56b171 100644 --- a/baseunits/includes/MangaMint/image_url.inc +++ b/baseunits/includes/MangaMint/image_url.inc @@ -9,8 +9,8 @@ parse := TStringList.Create; try s := FillMangaSiteHost(MANGAMINT_ID, URL); - if workCounter > 0 then - s := s + '?page=' + IntToStr(workCounter); + if Task.Container.WorkCounter > 0 then + s := s + '?page=' + IntToStr(Task.Container.WorkCounter); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -33,7 +33,7 @@ begin if Pos('src =', parse[i]) > 0 then parse[i] := StringReplace(parse[i], 'src =', 'src=', []); - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaOku/image_url.inc b/baseunits/includes/MangaOku/image_url.inc index f8f61281b..9a777a9ea 100644 --- a/baseunits/includes/MangaOku/image_url.inc +++ b/baseunits/includes/MangaOku/image_url.inc @@ -9,7 +9,7 @@ if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - s := s + IntToStr(workCounter + 1) + '/'; + s := s + IntToStr(Task.Container.WorkCounter + 1) + '/'; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -35,7 +35,7 @@ s := GetVal(parse[i], 'src'); if Pos(WebsiteRoots[MANGAOKU_ID, 1], s) = 0 then s := WebsiteRoots[MANGAOKU_ID, 1] + '/' + s; - Task.Container.PageLinks[workCounter] := s; + Task.Container.PageLinks[Task.Container.WorkCounter] := s; Break; end; end; diff --git a/baseunits/includes/MangaPark/image_url.inc b/baseunits/includes/MangaPark/image_url.inc index f2c80b7a7..3adc9471d 100644 --- a/baseunits/includes/MangaPark/image_url.inc +++ b/baseunits/includes/MangaPark/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(MANGAPARK_ID, URL) + - 'all',//IntToStr(workCounter+1), + 'all',//IntToStr(Task.Container.WorkCounter+1), Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index 7212d7f51..74360e5c1 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -6,8 +6,8 @@ begin l := TStringList.Create; s := AppendURLDelim(FillMangaSiteHost(MANGATOWN_ID, URL)); - if workCounter > 0 then - s := s + IncStr(workCounter) + '.html'; + if Task.Container.WorkCounter > 0 then + s := s + IncStr(Task.Container.WorkCounter) + '.html'; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -30,7 +30,7 @@ begin if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaTraders/image_url.inc b/baseunits/includes/MangaTraders/image_url.inc index 73609fe46..a6c4b87a3 100644 --- a/baseunits/includes/MangaTraders/image_url.inc +++ b/baseunits/includes/MangaTraders/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := FillMangaSiteHost(MANGATRADERS_ID, URL); - s := s + '/page-' + IntToStr(workCounter + 1); + s := s + '/page-' + IntToStr(Task.Container.WorkCounter + 1); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -24,7 +24,7 @@ parse[i] := RemoveBreaks(parse[i]); if Pos(#9, parse[i]) > 0 then parse[i] := StringReplace(parse[i], #9, ' ', [rfReplaceAll, rfIgnoreCase]); - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Mangacow/image_url.inc b/baseunits/includes/Mangacow/image_url.inc index 5d582e710..2a3b43b5e 100644 --- a/baseunits/includes/Mangacow/image_url.inc +++ b/baseunits/includes/Mangacow/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(workCounter + 1) + '/'); + s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(Task.Container.WorkCounter + 1) + '/'); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -22,7 +22,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'style') = 'width:0px; height:0px') then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index 3a831d337..9b8cb2e65 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -9,7 +9,7 @@ s := Task.Container.DownloadInfo.SaveTo + '/' + Task.Container.ChapterName[ Task.Container.CurrentDownloadChapterPtr] + '/' + - Format('%.3d', [workCounter + 1]); + Format('%.3d', [Task.Container.WorkCounter + 1]); // Check to see if a file with similar name was already exist. If so then we // skip the download process. if (FileExistsUTF8(s + '.jpg')) or @@ -27,7 +27,7 @@ FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; Result := GetPage(TObject(l), - Task.Container.PageLinks[workCounter], + Task.Container.PageLinks[Task.Container.WorkCounter], Task.Container.Manager.retryConnect); if Self.Terminated then @@ -58,7 +58,7 @@ Task.Container.MangaSiteID, GetVal(parse[i], 'src'), Task.Container.CurrentWorkingDir, - Format('%.3d', [workCounter + 1]) + + Format('%.3d', [Task.Container.WorkCounter + 1]) + '_' + IntToStr(prefix), Task.Container.Manager.retryConnect); @@ -76,7 +76,7 @@ // If prefix = 2 then there're 2 separate images. We need to merge them into one ... if prefix = 2 then begin - imageName := Format('%.3d', [workCounter + 1]); + imageName := Format('%.3d', [Task.Container.WorkCounter + 1]); Merge2Image( Task.Container.CurrentWorkingDir, imageName + '_' + IntToStr(prefix - 2) + '.jpg', diff --git a/baseunits/includes/NHentai/image_url.inc b/baseunits/includes/NHentai/image_url.inc index ce340948b..2b6ebe33f 100644 --- a/baseunits/includes/NHentai/image_url.inc +++ b/baseunits/includes/NHentai/image_url.inc @@ -9,7 +9,7 @@ if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - s := s + IntToStr(QWord(workCounter) + 1) + '/'; + s := s + IntToStr(QWord(Task.Container.WorkCounter) + 1) + '/'; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -42,7 +42,7 @@ s := TrimLeftChar(s, ['/', ':']); s := 'http://' + s; end; - Task.Container.PageLinks[workCounter] := s; + Task.Container.PageLinks[Task.Container.WorkCounter] := s; Break; end; end; diff --git a/baseunits/includes/NineManga/image_url.inc b/baseunits/includes/NineManga/image_url.inc index 5079df4ad..6669729ad 100644 --- a/baseunits/includes/NineManga/image_url.inc +++ b/baseunits/includes/NineManga/image_url.inc @@ -8,7 +8,7 @@ s := FillMangaSiteHost(Task.Container.MangaSiteID, URL); s := StringReplace(s, '.html', '', []); s := StringReplace(s, '.htm', '', []); - s := s + '-' + IntToStr(workCounter + 1) + '.html'; + s := s + '-' + IntToStr(Task.Container.WorkCounter + 1) + '.html'; Result := GetPage(TObject(l), s, @@ -32,7 +32,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="manga_pic', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/OneManga/image_url.inc b/baseunits/includes/OneManga/image_url.inc index 0eede3d22..140fea2ef 100644 --- a/baseunits/includes/OneManga/image_url.inc +++ b/baseunits/includes/OneManga/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := FillMangaSiteHost(ONEMANGA_ID, URL); - s := s + IntToStr(workCounter + 1) + '/'; + s := s + IntToStr(Task.Container.WorkCounter + 1) + '/'; Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -22,7 +22,7 @@ if (Pos('<img ', parse[i]) > 0) and (Pos('class="manga-page"', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/PornComix/image_url.inc b/baseunits/includes/PornComix/image_url.inc index 3d2747b48..8e8ef8974 100644 --- a/baseunits/includes/PornComix/image_url.inc +++ b/baseunits/includes/PornComix/image_url.inc @@ -4,7 +4,7 @@ s, surl: String; l: TStringList; begin - surl := Task.Container.PageContainerLinks[workCounter]; + surl := Task.Container.PageContainerLinks[Task.Container.WorkCounter]; if not ((Pos('imagetwist.', surl) <> 0) or (Pos('imgmega.', surl) <> 0) or (Pos('imgchili.', surl) <> 0)) then @@ -43,7 +43,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('class="pic', parse[i]) <> 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end @@ -54,7 +54,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('id="show_image', parse[i]) <> 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Starkana/image_url.inc b/baseunits/includes/Starkana/image_url.inc index ccd96f20e..6f0db25cc 100644 --- a/baseunits/includes/Starkana/image_url.inc +++ b/baseunits/includes/Starkana/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(workCounter + 1)), + DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)), Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -20,7 +20,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="dyn', parse[i]) > 0) and (Pos('style="cursor: pointer', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Turkcraft/image_url.inc b/baseunits/includes/Turkcraft/image_url.inc index 14dc17cde..f0f612aa7 100644 --- a/baseunits/includes/Turkcraft/image_url.inc +++ b/baseunits/includes/Turkcraft/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(workCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="picture"', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := + Task.Container.PageLinks[Task.Container.WorkCounter] := EncodeURL(WebsiteRoots[TURKCRAFT_ID, 1] + TURKCRAFT_BROWSER + GetVal(parse[i], 'src')); Break; diff --git a/baseunits/includes/UnixManga/image_url.inc b/baseunits/includes/UnixManga/image_url.inc index e5d2a7f2e..672ab7a28 100644 --- a/baseunits/includes/UnixManga/image_url.inc +++ b/baseunits/includes/UnixManga/image_url.inc @@ -5,7 +5,7 @@ s: String; begin l := TStringList.Create; - s := Task.Container.PageContainerLinks[workCounter]; + s := Task.Container.PageContainerLinks[Task.Container.WorkCounter]; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -28,7 +28,7 @@ begin if (Pos('STYLE="border', parse[i]) > 0) and (Pos('<IMG', parse[i]) > 0) then begin - Task.Container.PageLinks[workCounter] := Trim(GetVal(parse[i], 'SRC')); + Task.Container.PageLinks[Task.Container.WorkCounter] := Trim(GetVal(parse[i], 'SRC')); Break; end; end; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 8bff51994..f49f3f21a 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -289,13 +289,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + - IntToStr(DownloadThread.WorkCounter + 1); + IntToStr(WorkCounter + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := XPathString('//div[@id="full_image"]//img/@src'); + PageLinks[WorkCounter] := XPathString('//div[@id="full_image"]//img/@src'); finally Free; end; diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index a881ca211..383266185 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -94,7 +94,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkCounter])); + rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[WorkCounter])); if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -102,7 +102,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; rurl := XPathString('//img[@id="image"]/@src'); if Pos('//', rurl) = 1 then rurl := 'https:' + rurl; - PageLinks[DownloadThread.workCounter] := rurl; + PageLinks[WorkCounter] := rurl; finally Free; end; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 94f2cc10f..772398139 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -169,14 +169,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AURL; - if DownloadThread.workCounter > 0 then - s := AppendURLDelim(s) + 'page/' + IncStr(DownloadThread.workCounter); + if WorkCounter > 0 then + s := AppendURLDelim(s) + 'page/' + IncStr(WorkCounter); if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, s), Module) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := XPathString('//div[@id="page"]//img/@src'); + PageLinks[WorkCounter] := XPathString('//div[@id="page"]//img/@src'); finally Free; end; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 6d413ad55..0720579df 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -138,13 +138,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AppendURLDelim(AURL) + IncStr(DownloadThread.workCounter) + '/'; + s := AppendURLDelim(AURL) + IncStr(WorkCounter) + '/'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := query.XPathString('//*[@id="con"]//img/@src'); + PageLinks[WorkCounter] := query.XPathString('//*[@id="con"]//img/@src'); finally query.Free; end; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index ae964ff2e..bc311d4f9 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -183,8 +183,8 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := FillHost(Module.RootURL, AURL); - if DownloadThread.workCounter > 0 then - s := AppendURLDelim(s) + IncStr(DownloadThread.workCounter) + '/'; + if WorkCounter > 0 then + s := AppendURLDelim(s) + IncStr(WorkCounter) + '/'; if GET(s) then begin Result := True; @@ -194,7 +194,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if s <> '' then begin s := TrimLeftChar(s, ['/']); - PageLinks[DownloadThread.workCounter] := MaybeFillHost(cdnurl, s); + PageLinks[WorkCounter] := MaybeFillHost(cdnurl, s); end; finally Free; diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index 2a417ee26..f1fe59f48 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -143,12 +143,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(FillHost(Module.RootURL, AURL) + IncStr(DownloadThread.workCounter)) then + if GET(FillHost(Module.RootURL, AURL) + IncStr(WorkCounter)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := XPathString('//img[@id="img-content"]/@src'); + PageLinks[WorkCounter] := XPathString('//img[@id="img-content"]/@src'); finally Free; end; diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index 9a2ca6370..51f1543e6 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -163,12 +163,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if RightStr(s, 2) = '/1' then SetLength(s, Length(s) - 1); with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AppendURLDelim(s) + IncStr(DownloadThread.workCounter) + '/'; + s := AppendURLDelim(s) + IncStr(WorkCounter) + '/'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := XPathString('//img[@id="mainImg"]/@src'); finally Free; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index f155e04a1..1e7d0c4c1 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -126,12 +126,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(DownloadThread.workCounter) + '.html') then + IncStr(WorkCounter) + '.html') then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := XPathString('//div[@class="read_img"]//img[@id="image"]/@src'); finally Free; diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 2b0d589b1..411b11fdb 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -145,15 +145,15 @@ function GetImageURL(const DownloadThread: TDownloadThread; Source := TStringList.Create; try rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if DownloadThread.workCounter > 0 then - rurl += IncStr(DownloadThread.workCounter) + '.html'; + if WorkCounter > 0 then + rurl += IncStr(WorkCounter) + '.html'; if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then if Source.Count > 0 then begin Result := True; Query := TXQueryEngineHTML.Create(Source.Text); try - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := Query.XPathString('//*[@id="viewer"]//img[@id="image"]/@src'); finally Query.Free; diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 5d635b244..e5a9ba0bf 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -139,13 +139,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := RemoveURLDelim(AURL); - if DownloadThread.workCounter > 0 then s += '/' + IncStr(DownloadThread.workCounter) + '.html'; + if WorkCounter > 0 then s += '/' + IncStr(WorkCounter) + '.html'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := query.XPathString('//section[@id="viewer"]//img/@src'); + PageLinks[WorkCounter] := query.XPathString('//section[@id="viewer"]//img/@src'); finally query.Free; end; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 15d040fdd..745e153c7 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -175,14 +175,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; try if GetPage(DownloadThread.FHTTP, TObject(Source), AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(DownloadThread.workCounter), Manager.retryConnect) then + IncStr(WorkCounter), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; Parser := TTreeParser.Create; try ParseHTMLTree(Parser, Source.Text); - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := SelectXPathString('//img[@id="img"]/@src', Parser); finally Parser.Free; diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 98f5bb56b..3a9b1b0b2 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -157,14 +157,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; try if GetPage(DownloadThread.FHTTP, TObject(Source), AppendURLDelim(FillHost(readURL, AURL)) + - IncStr(DownloadThread.workCounter), Manager.retryConnect) then + IncStr(WorkCounter), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; Parser := TTreeParser.Create; try ParseHTMLTree(Parser, Source.Text); - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := SelectXPathString('//img[@id="manga-page"]/@src', Parser); finally Parser.Free; diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index 60b4941e1..40eb74da2 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -97,13 +97,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AURL; s := ReplaceRegExpr('\.html?$', s, '', False); - s += '-page-' + IncStr(DownloadThread.workCounter) + '.html'; + s += '-page-' + IncStr(WorkCounter) + '.html'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := query.XPathString('//img[@class="manga-page center-block"]/@src'); finally query.Free; diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index abbbacd4a..c9890e7ef 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -192,13 +192,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + AURL; - if DownloadThread.workCounter > PageContainerLinks.Count then Exit; - if GETWithCookie(DownloadThread.FHTTP, PageContainerLinks[DownloadThread.workCounter], Module) then + if WorkCounter > PageContainerLinks.Count then Exit; + if GETWithCookie(DownloadThread.FHTTP, PageContainerLinks[WorkCounter], Module) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := + PageLinks[WorkCounter] := MaybeFillHost(Module.RootURL, XPathString('//div[@class="chapter-content"]//img/@src')); finally Free; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 2761cad17..5ff01c4a1 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -107,7 +107,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := RemoveURLDelim(AURL); - if DownloadThread.workCounter > 0 then s += '/' + IncStr(DownloadThread.workCounter); + if WorkCounter > 0 then s += '/' + IncStr(WorkCounter); if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; @@ -116,7 +116,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; b := query.XPathString('//base/@href'); if b = '' then b := Module.RootURL; s := query.XPathString('//img[@class="picture"]/@src'); - if s <> '' then PageLinks[DownloadThread.workCounter] := MaybeFillHost(b, s); + if s <> '' then PageLinks[WorkCounter] := MaybeFillHost(b, s); finally query.Free; end; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index f051ae446..65e0d14b1 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -156,13 +156,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(DownloadThread.WorkCounter)) then begin + if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(WorkCounter)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); if s <> '' then - PageLinks[DownloadThread.workCounter] := s; + PageLinks[WorkCounter] := s; finally Free; end; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index df7b28bdd..7768586b1 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -127,13 +127,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := FillHost(Module.RootURL, AURL); - if DownloadThread.workCounter > 0 then - s := s + '/' + IncStr(DownloadThread.workCounter); + if WorkCounter > 0 then + s := s + '/' + IncStr(WorkCounter); if GET(s) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.workCounter] := XPathString('//div[@id="ab"]/a/img/@src'); + PageLinks[WorkCounter] := XPathString('//div[@id="ab"]/a/img/@src'); finally Free; end; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 04ae55478..bc6212a56 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -272,7 +272,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.workCounter) + '/') then + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(WorkCounter) + '/') then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -283,7 +283,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; s := XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); if s = '' then s := XPathString('//*[@id="reader"]//img[@id="picture"]/@src'); - PageLinks[DownloadThread.WorkCounter] := s; + PageLinks[WorkCounter] := s; finally Free; end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5e268af02..706a1540b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -497,7 +497,6 @@ interface Revision: Cardinal; currentJDN: Integer; - isChangeDirectory: Boolean = False; type TArrayOfString = array of String; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 496c8035f..ce608b73b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -15,10 +15,10 @@ interface uses - lazutf8classes, LazFileUtils, FileUtil, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, - Imaging, ImagingTypes, ImagingCanvases, Classes, SysUtils, Dialogs, ExtCtrls, IniFiles, - typinfo, syncobjs, httpsend, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, - DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils, strutils; + LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Classes, SysUtils, + ExtCtrls, typinfo, syncobjs, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, + DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils, + strutils; type TDownloadManager = class; @@ -30,17 +30,9 @@ TTaskThread = class; TDownloadThread = class(TFMDThread) private parse: TStringList; - checkStyle: TFlagType; public - workCounter: Integer; - FSortColumn: Cardinal; - FMessage, FAnotherURL: String; FHTTP: THTTPSendThread; - procedure MainThreadMessageDialog; - // wait for changing directory completed - procedure SetChangeDirectoryFalse; - procedure SetChangeDirectoryTrue; // Get download link from URL function GetLinkPageFromURL(const URL: String): Boolean; // Get number of download link from URL @@ -65,22 +57,16 @@ TDownloadThread = class(TFMDThread) Task: TTaskThread; constructor Create; destructor Destroy; override; - - property SortColumn: Cardinal read FSortColumn write FSortColumn; - property AnotherURL: String read FAnotherURL write FAnotherURL; end; { TTaskThread } TTaskThread = class(TFMDThread) private - ModuleId: Integer; FCheckAndActiveTaskFlag: Boolean; protected - FMessage, FAnotherURL: String; procedure CheckOut; procedure MainThreadCompressRepaint; - procedure MainThreadMessageDialog; procedure Execute; override; procedure DoTerminate; override; procedure Compress; @@ -97,7 +83,6 @@ TTaskThread = class(TFMDThread) Threads: TFPList; constructor Create; destructor Destroy; override; - property AnotherURL: String read FAnotherURL write FAnotherURL; end; { TTaskContainer } @@ -231,8 +216,7 @@ TDownloadManager = class implementation -uses - frmMain, WebsiteModules; +uses frmMain, WebsiteModules; function IntToStr(Value: Cardinal): String; begin @@ -291,7 +275,7 @@ procedure TDownloadThread.Execute; Reslt: Boolean = False; begin try - case checkStyle of + case Task.Flag of // Get number of images. CS_GETPAGENUMBER: begin @@ -337,7 +321,7 @@ procedure TDownloadThread.Execute; on E: Exception do begin E.Message := E.Message + LineEnding + - ' In TDownloadThread.Execute : ' + GetEnumName(TypeInfo(TFlagType), Integer(checkStyle)) + + ' In TDownloadThread.Execute : ' + GetEnumName(TypeInfo(TFlagType), Integer(Task.Flag)) + LineEnding + ' Website : ' + Task.Container.DownloadInfo.Website + LineEnding + ' URL : ' + FillMangaSiteHost(Task.Container.MangaSiteID, @@ -354,7 +338,7 @@ procedure TDownloadThread.DoTerminate; begin LockCreateConnection; try - Modules.DecActiveConnectionCount(Task.ModuleId); + Modules.DecActiveConnectionCount(Task.Container.ModuleId); Task.Threads.Remove(Self); finally UnlockCreateConnection; @@ -454,8 +438,8 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := False; Task.Container.PageNumber := 0; - if Modules.ModuleAvailable(Task.ModuleId, MMGetPageNumber) then - Result := Modules.GetPageNumber(Self, URL, Task.ModuleId) + if Modules.ModuleAvailable(Task.Container.ModuleId, MMGetPageNumber) then + Result := Modules.GetPageNumber(Self, URL, Task.Container.ModuleId) else begin if Task.Container.MangaSiteID = ANIMEA_ID then @@ -691,11 +675,11 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; begin Result := False; if (Task.Container.PageLinks.Count > 0) and - (Task.Container.PageLinks.Strings[workCounter] <> 'W') then + (Task.Container.PageLinks.Strings[Task.Container.WorkCounter] <> 'W') then Exit; - if Modules.ModuleAvailable(Task.ModuleId, MMGetImageURL) then - Result := Modules.GetImageURL(Self, URL, Task.ModuleId) + if Modules.ModuleAvailable(Task.Container.ModuleId, MMGetImageURL) then + Result := Modules.GetImageURL(Self, URL, Task.Container.ModuleId) else begin if Task.Container.MangaSiteID = ANIMEA_ID then @@ -847,30 +831,13 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; end; end; -procedure TDownloadThread.MainThreadMessageDialog; -begin - MessageDlg('TDownloadThread', FMessage, mtInformation, [mbOK], ''); -end; - -procedure TDownloadThread.SetChangeDirectoryFalse; -begin - isChangeDirectory := False; -end; - -procedure TDownloadThread.SetChangeDirectoryTrue; -begin - isChangeDirectory := True; -end; - // ----- TTaskThread ----- constructor TTaskThread.Create; begin inherited Create(True); Threads := TFPList.Create; - ModuleId := -1; FCheckAndActiveTaskFlag := True; - anotherURL := ''; httpCookies := ''; end; @@ -888,11 +855,6 @@ procedure TTaskThread.MainThreadCompressRepaint; MainForm.vtDownload.Repaint; end; -procedure TTaskThread.MainThreadMessageDialog; -begin - MessageDlg('TTaskThread', FMessage, mtInformation, [mbOK], ''); -end; - procedure TTaskThread.Compress; var uPacker: TPacker; @@ -969,7 +931,7 @@ function TDownloadThread.DownloadImage: Boolean; end; // check pagelinks url - workURL := Task.Container.PageLinks[workCounter]; + workURL := Task.Container.PageLinks[Task.Container.WorkCounter]; if (workURL = '') or (workURL = 'W') or (workURL = 'D') then @@ -978,28 +940,28 @@ function TDownloadThread.DownloadImage: Boolean; FHTTP.Clear; // call beforedownloadimage if available - if Modules.ModuleAvailable(Task.ModuleId, MMBeforeDownloadImage) then - Result := Modules.BeforeDownloadImage(Self, workURL, Task.ModuleId); + if Modules.ModuleAvailable(Task.Container.ModuleId, MMBeforeDownloadImage) then + Result := Modules.BeforeDownloadImage(Self, workURL, Task.Container.ModuleId); // prepare filename workFilename := ''; - if workCounter < Task.Container.Filenames.Count then - workFilename := Task.Container.Filenames[workCounter]; + if Task.Container.WorkCounter < Task.Container.Filenames.Count then + workFilename := Task.Container.Filenames[Task.Container.WorkCounter]; if workFilename = '' then - workFilename := Format('%.3d', [workCounter + 1]); + workFilename := Format('%.3d', [Task.Container.WorkCounter + 1]); // download image savedFilename := ''; if Result then begin - if Modules.ModuleAvailable(Task.ModuleId, MMDownloadImage) then + if Modules.ModuleAvailable(Task.Container.ModuleId, MMDownloadImage) then begin workURL := ''; if (Task.Container.PageNumber = Task.Container.PageContainerLinks.Count) - and (workCounter < Task.Container.PageContainerLinks.Count) then - workURL := Task.Container.PageContainerLinks[workCounter] - else if workCounter < Task.Container.PageLinks.Count then - workURL := Task.Container.PageLinks[workCounter]; + and (Task.Container.WorkCounter < Task.Container.PageContainerLinks.Count) then + workURL := Task.Container.PageContainerLinks[Task.Container.WorkCounter] + else if Task.Container.WorkCounter < Task.Container.PageLinks.Count then + workURL := Task.Container.PageLinks[Task.Container.WorkCounter]; if workURL <> '' then Result := Modules.DownloadImage( @@ -1007,7 +969,7 @@ function TDownloadThread.DownloadImage: Boolean; workURL, Task.Container.CurrentWorkingDir, workFilename, - Task.ModuleId); + Task.Container.ModuleId); end else if Task.Container.MangaSiteID = MEINMANGA_ID then @@ -1025,10 +987,10 @@ function TDownloadThread.DownloadImage: Boolean; if Terminated then Exit(False); if Result then begin - Task.Container.PageLinks[workCounter] := 'D'; + Task.Container.PageLinks[Task.Container.WorkCounter] := 'D'; - if Modules.ModuleAvailable(Task.ModuleId, MMAfterImageSaved) then - Modules.AfterImageSaved(savedFilename, Task.ModuleId); + if Modules.ModuleAvailable(Task.Container.ModuleId, MMAfterImageSaved) then + Modules.AfterImageSaved(savedFilename, Task.Container.ModuleId); end; end; @@ -1051,8 +1013,8 @@ procedure TTaskThread.CheckOut; end else begin - if Modules.MaxConnectionLimit[ModuleId] > 0 then - currentMaxThread := Modules.MaxConnectionLimit[ModuleId] + if Modules.MaxConnectionLimit[Container.ModuleId] > 0 then + currentMaxThread := Modules.MaxConnectionLimit[Container.ModuleId] else currentMaxThread := Container.Manager.maxDLThreadsPerTask; if currentMaxThread > Container.Manager.maxDLThreadsPerTask then @@ -1075,8 +1037,8 @@ procedure TTaskThread.CheckOut; end; end; - if Modules.MaxConnectionLimit[ModuleId] > 0 then - while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread) do + if Modules.MaxConnectionLimit[Container.ModuleId] > 0 then + while (not Terminated) and (Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxThread) do Sleep(SOCKHEARTBEATRATE) else while (not Terminated) and (Threads.Count >= currentMaxThread) do @@ -1086,14 +1048,11 @@ procedure TTaskThread.CheckOut; begin LockCreateConnection; try - if Modules.ActiveConnectionCount[ModuleId] >= currentMaxThread then Exit; - Modules.IncActiveConnectionCount(ModuleId); + if Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxThread then Exit; + Modules.IncActiveConnectionCount(Container.ModuleId); Threads.Add(TDownloadThread.Create); with TDownloadThread(Threads.Last) do begin Task := Self; - ModuleId := Self.ModuleId; - workCounter := Container.WorkCounter; - checkStyle := Flag; //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, Container.DownloadInfo.Website); Start; @@ -1163,12 +1122,11 @@ procedure TTaskThread.Execute; s: String; DynamicPageLink: Boolean; begin - ModuleId := Container.ModuleId; Container.ThreadState := True; Container.DownloadInfo.TransferRate := FormatByteSize(Container.ReadCount, true); try if Container.ModuleId > -1 then - DynamicPageLink := Modules.Module[ModuleId].DynamicPageLink + DynamicPageLink := Modules.Module[Container.ModuleId].DynamicPageLink else DynamicPageLink := False; @@ -1189,8 +1147,8 @@ procedure TTaskThread.Execute; Exit; end; - if ModuleId > -1 then - Modules.TaskStart(Container, ModuleId); + if Container.ModuleId > -1 then + Modules.TaskStart(Container, Container.ModuleId); // Get page number. if Container.PageLinks.Count = 0 then @@ -1385,7 +1343,7 @@ procedure TTaskThread.DoTerminate; while Threads.Count > 0 do Sleep(100); end; - Modules.DecActiveTaskCount(ModuleId); + Modules.DecActiveTaskCount(Container.ModuleId); with Container do begin Container.ReadCount := 0; DownloadInfo.TransferRate := ''; From 1730186e6b08102bbf27744bbe7b5e959f5e5b83 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 29 May 2016 02:05:29 +0800 Subject: [PATCH 1186/2794] downloadmanager, fixed incorrect workcounter, rename to workid --- .../includes/AnimExtremist/image_url.inc | 4 +-- baseunits/includes/AnimeA/image_url.inc | 4 +-- baseunits/includes/AnimeStory/image_url.inc | 4 +-- .../includes/CentralDeMangas/image_url.inc | 2 +- baseunits/includes/EGScans/image_url.inc | 2 +- baseunits/includes/EatManga/image_url.inc | 4 +-- baseunits/includes/EsMangaHere/image_url.inc | 6 ++-- baseunits/includes/HugeManga/image_url.inc | 4 +-- baseunits/includes/IKomik/image_url.inc | 4 +-- baseunits/includes/JapanShin/image_url.inc | 4 +-- baseunits/includes/Japscan/image_url.inc | 4 +-- baseunits/includes/Kivmanga/image_url.inc | 4 +-- baseunits/includes/Komikid/image_url.inc | 4 +-- .../includes/LectureEnLigne/image_url.inc | 4 +-- baseunits/includes/MangaAe/image_url.inc | 4 +-- baseunits/includes/MangaAt/image_url.inc | 4 +-- baseunits/includes/MangaGo/image_url.inc | 4 +-- baseunits/includes/MangaHost/image_url.inc | 4 +-- baseunits/includes/MangaInn/image_url.inc | 4 +-- baseunits/includes/MangaLib_PL/image_url.inc | 4 +-- baseunits/includes/MangaMint/image_url.inc | 6 ++-- baseunits/includes/MangaOku/image_url.inc | 4 +-- baseunits/includes/MangaPark/image_url.inc | 2 +- baseunits/includes/MangaTown/image_url.inc | 6 ++-- baseunits/includes/MangaTraders/image_url.inc | 4 +-- baseunits/includes/Mangacow/image_url.inc | 4 +-- baseunits/includes/MeinManga/image_url.inc | 8 ++--- baseunits/includes/NHentai/image_url.inc | 4 +-- baseunits/includes/NineManga/image_url.inc | 4 +-- baseunits/includes/OneManga/image_url.inc | 4 +-- baseunits/includes/PornComix/image_url.inc | 6 ++-- baseunits/includes/Starkana/image_url.inc | 4 +-- baseunits/includes/Turkcraft/image_url.inc | 4 +-- baseunits/includes/UnixManga/image_url.inc | 4 +-- baseunits/modules/Batoto.pas | 4 +-- baseunits/modules/EightMuses.pas | 4 +-- baseunits/modules/FoOlSlide.pas | 6 ++-- baseunits/modules/Hakihome.pas | 4 +-- baseunits/modules/Hentai2Read.pas | 6 ++-- baseunits/modules/HeyMangaXyz.pas | 4 +-- baseunits/modules/MangaEden.pas | 4 +-- baseunits/modules/MangaFox.pas | 4 +-- baseunits/modules/MangaHere.pas | 6 ++-- baseunits/modules/MangaKoi.pas | 4 +-- baseunits/modules/MangaReader.pas | 4 +-- baseunits/modules/MangaStream.pas | 4 +-- baseunits/modules/MangaStreamTo.pas | 4 +-- baseunits/modules/MangaTr.pas | 6 ++-- baseunits/modules/PecintaKomik.pas | 4 +-- baseunits/modules/RawSenManga.pas | 4 +-- baseunits/modules/Submanga.pas | 6 ++-- baseunits/modules/WPManga.pas | 4 +-- baseunits/uDownloadsManager.pas | 31 +++++++++---------- 53 files changed, 127 insertions(+), 128 deletions(-) diff --git a/baseunits/includes/AnimExtremist/image_url.inc b/baseunits/includes/AnimExtremist/image_url.inc index 66d612d01..d4cefdfb4 100644 --- a/baseunits/includes/AnimExtremist/image_url.inc +++ b/baseunits/includes/AnimExtremist/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := DecodeUrl(StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), - '.html', '', []) + '-' + IntToStr(Task.Container.WorkCounter + 1) + '.html'); + '.html', '', []) + '-' + IntToStr(WorkId + 1) + '.html'); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -23,7 +23,7 @@ if (Pos('id="photo"', parse[i]) > 0) then begin s := GetVal(parse[i], 'src'); - Task.Container.pageLinks[Task.Container.WorkCounter] := + Task.Container.pageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/AnimeA/image_url.inc b/baseunits/includes/AnimeA/image_url.inc index 374865996..9a80149cd 100644 --- a/baseunits/includes/AnimeA/image_url.inc +++ b/baseunits/includes/AnimeA/image_url.inc @@ -7,7 +7,7 @@ Result := GetPage(TObject(l), FillMangaSiteHost(ANIMEA_ID, StringReplace(URL, '.html', '', []) + - '-page-' + IntToStr(Task.Container.WorkCounter + 1) + '.html'), + '-page-' + IntToStr(WorkId + 1) + '.html'), Task.Container.Manager.retryConnect); parse := TStringList.Create; @@ -24,7 +24,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="scanmr"', parse[i]) > 0) and (Pos('id="scanmr"', parse[i])> 0) then - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); end; end; parse.Free; diff --git a/baseunits/includes/AnimeStory/image_url.inc b/baseunits/includes/AnimeStory/image_url.inc index ac3be1721..01dd08137 100644 --- a/baseunits/includes/AnimeStory/image_url.inc +++ b/baseunits/includes/AnimeStory/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(Task.Container.WorkCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(WorkId + 1)); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('id="chpimg"', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := DecodeURL(GetVal(parse[i], 'src')); Break; end; diff --git a/baseunits/includes/CentralDeMangas/image_url.inc b/baseunits/includes/CentralDeMangas/image_url.inc index 06b4a399a..71d79d249 100644 --- a/baseunits/includes/CentralDeMangas/image_url.inc +++ b/baseunits/includes/CentralDeMangas/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := EncodeUrl(FillMangaSiteHost(CENTRALDEMANGAS_ID, URL)); - // + IntToStr(Task.Container.WorkCounter+1)); + // + IntToStr(WorkId+1)); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); diff --git a/baseunits/includes/EGScans/image_url.inc b/baseunits/includes/EGScans/image_url.inc index 189896420..4c498cff8 100644 --- a/baseunits/includes/EGScans/image_url.inc +++ b/baseunits/includes/EGScans/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(WorkId + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); diff --git a/baseunits/includes/EatManga/image_url.inc b/baseunits/includes/EatManga/image_url.inc index 6bbb91b5e..f5a54ed91 100644 --- a/baseunits/includes/EatManga/image_url.inc +++ b/baseunits/includes/EatManga/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(Task.Container.WorkCounter + 1)), + DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(WorkId + 1)), Task.Container.Manager.retryConnect); parse := TStringList.Create; @@ -25,7 +25,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'eatmanga_image') then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/EsMangaHere/image_url.inc b/baseunits/includes/EsMangaHere/image_url.inc index b74c5e7c1..30866d459 100644 --- a/baseunits/includes/EsMangaHere/image_url.inc +++ b/baseunits/includes/EsMangaHere/image_url.inc @@ -4,10 +4,10 @@ l: TStringList; begin l := TStringList.Create; - if Task.Container.WorkCounter > 0 then + if WorkId > 0 then Result := GetPage(TObject(l), FillMangaSiteHost(ESMANGAHERE_ID, URL) + - IntToStr(Task.Container.WorkCounter + 1) + '.html', + IntToStr(WorkId + 1) + '.html', Task.Container.manager.retryConnect) else Result := GetPage(TObject(l), @@ -25,7 +25,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="read_img"', parse[i]) <> 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := GetVal(parse[i + 6], 'src'); parse.Free; l.Free; diff --git a/baseunits/includes/HugeManga/image_url.inc b/baseunits/includes/HugeManga/image_url.inc index 56e9659fd..0dfe4565f 100644 --- a/baseunits/includes/HugeManga/image_url.inc +++ b/baseunits/includes/HugeManga/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(WorkId + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="picture"', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := EncodeURL(WebsiteRoots[HUGEMANGA_ID, 1] + HUGEMANGA_BROWSER + GetVal(parse[i], 'src')); Break; diff --git a/baseunits/includes/IKomik/image_url.inc b/baseunits/includes/IKomik/image_url.inc index a7d749e57..2e4a5f6e2 100644 --- a/baseunits/includes/IKomik/image_url.inc +++ b/baseunits/includes/IKomik/image_url.inc @@ -9,7 +9,7 @@ if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - s := s + IntToStr(QWord(Task.Container.WorkCounter) + 1); + s := s + IntToStr(QWord(WorkId) + 1); Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -36,7 +36,7 @@ begin if Pos('<img', parse[j]) > 0 then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[j], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[j], 'src'); Break; end; end; diff --git a/baseunits/includes/JapanShin/image_url.inc b/baseunits/includes/JapanShin/image_url.inc index 589744a30..8809fe75f 100644 --- a/baseunits/includes/JapanShin/image_url.inc +++ b/baseunits/includes/JapanShin/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - FillMangaSiteHost(JAPANSHIN_ID, URL) + '/page/' + IntToStr(Task.Container.WorkCounter), + FillMangaSiteHost(JAPANSHIN_ID, URL) + '/page/' + IntToStr(WorkId), Task.Container.Manager.retryConnect); if Self.Terminated then @@ -27,7 +27,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="open"', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/Japscan/image_url.inc b/baseunits/includes/Japscan/image_url.inc index fef8cb810..6751199ff 100644 --- a/baseunits/includes/Japscan/image_url.inc +++ b/baseunits/includes/Japscan/image_url.inc @@ -7,7 +7,7 @@ s := DecodeUrl(FillMangaSiteHost(JAPSCAN_ID, URL)); if Pos('.htm', s) > 0 then s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/' + IntToStr(Task.Container.WorkCounter + 1) + '.html'; + s := s + '/' + IntToStr(WorkId + 1) + '.html'; l := TStringList.Create; Result := GetPage(TObject(l), s, @@ -24,7 +24,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'imgscan') then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/Kivmanga/image_url.inc b/baseunits/includes/Kivmanga/image_url.inc index c645cc044..58e69968f 100644 --- a/baseunits/includes/Kivmanga/image_url.inc +++ b/baseunits/includes/Kivmanga/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(WorkId + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); @@ -23,7 +23,7 @@ begin s := WebsiteRoots[KIVMANGA_ID, 1] + KIVMANGA_BROWSER + GetVal(parse[i], 'src'); - Task.Container.PageLinks[Task.Container.WorkCounter] := EncodeURL(s); + Task.Container.PageLinks[WorkId] := EncodeURL(s); Break; end; end; diff --git a/baseunits/includes/Komikid/image_url.inc b/baseunits/includes/Komikid/image_url.inc index 8c6e297e9..5b6eb8305 100644 --- a/baseunits/includes/Komikid/image_url.inc +++ b/baseunits/includes/Komikid/image_url.inc @@ -7,7 +7,7 @@ begin l := TStringList.Create; s := EncodeURL(FillMangaSiteHost(KOMIKID_ID, URL) + '/' + - IntToStr(Task.Container.WorkCounter + 1) + '/'); + IntToStr(WorkId + 1) + '/'); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -32,7 +32,7 @@ if not regx.Exec(s) then s := WebsiteRoots[KOMIKID_ID, 1] + '/' + s; s := EncodeURL(s); - Task.container.PageLinks[Task.Container.WorkCounter] := s; + Task.container.PageLinks[WorkId] := s; finally regx.Free; end; diff --git a/baseunits/includes/LectureEnLigne/image_url.inc b/baseunits/includes/LectureEnLigne/image_url.inc index 95b4070dd..dc4792b24 100644 --- a/baseunits/includes/LectureEnLigne/image_url.inc +++ b/baseunits/includes/LectureEnLigne/image_url.inc @@ -7,7 +7,7 @@ s := DecodeUrl(FillMangaSiteHost(LECTUREENLIGNE_ID, URL)); if Pos('.htm', s) > 0 then s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/' + IntToStr(Task.Container.WorkCounter + 1) + '.html'; + s := s + '/' + IntToStr(WorkId + 1) + '.html'; l := TStringList.Create; Result := GetPage(TObject(l), s, @@ -24,7 +24,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'id') = 'image') then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/MangaAe/image_url.inc b/baseunits/includes/MangaAe/image_url.inc index b7ab17b7d..599f984d2 100644 --- a/baseunits/includes/MangaAe/image_url.inc +++ b/baseunits/includes/MangaAe/image_url.inc @@ -6,7 +6,7 @@ isImageURL: Boolean = False; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(WorkId + 1)); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); @@ -25,7 +25,7 @@ isImageURL := True; if isImageURL and (Pos('<img', parse[i]) <> 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaAt/image_url.inc b/baseunits/includes/MangaAt/image_url.inc index 796a13687..4c6b58c26 100644 --- a/baseunits/includes/MangaAt/image_url.inc +++ b/baseunits/includes/MangaAt/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := FillMangaSiteHost(MANGAAT_ID, URL) + - '/' + IntToStr(Task.Container.WorkCounter + 1) + '/'; + '/' + IntToStr(WorkId + 1) + '/'; Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -26,7 +26,7 @@ if GetVal(parse[i], 'id') = 'showchaptercontainer' then if (GetTagName(parse[i + 3]) = 'img') then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i + 3], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i + 3], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/MangaGo/image_url.inc b/baseunits/includes/MangaGo/image_url.inc index ed5d5a8cc..558621cb1 100644 --- a/baseunits/includes/MangaGo/image_url.inc +++ b/baseunits/includes/MangaGo/image_url.inc @@ -14,7 +14,7 @@ if (not regx.Exec(s)) and (s[Length(s)] <> '/') then s := s + '/'; s := FillMangaSiteHost(MANGAGO_ID, s); - Result := GetPage(TObject(l), s + IntToStr(Task.Container.WorkCounter + 1) + '/', + Result := GetPage(TObject(l), s + IntToStr(WorkId + 1) + '/', Task.Container.Manager.retryConnect); if Self.Terminated then @@ -38,7 +38,7 @@ if (Pos('imgReady(''', parse[i]) > 0) then begin regx.Expression := '^.*imgReady\(''([^'']*)''.*$'; - Task.Container.PageLinks[Task.Container.WorkCounter] := regx.Replace(parse[i], '$1', True); + Task.Container.PageLinks[WorkId] := regx.Replace(parse[i], '$1', True); Break; end; end; diff --git a/baseunits/includes/MangaHost/image_url.inc b/baseunits/includes/MangaHost/image_url.inc index 1b3f41034..c7991d2b6 100644 --- a/baseunits/includes/MangaHost/image_url.inc +++ b/baseunits/includes/MangaHost/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)), + DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL) + '/' + IntToStr(WorkId + 1)), Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -19,7 +19,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) > 0) and (Pos('class="open', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaInn/image_url.inc b/baseunits/includes/MangaInn/image_url.inc index 726f99d83..14e89829f 100644 --- a/baseunits/includes/MangaInn/image_url.inc +++ b/baseunits/includes/MangaInn/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(MANGAINN_ID, URL) + - '/page_' + IntToStr(Task.Container.WorkCounter + 1), + '/page_' + IntToStr(WorkId + 1), Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -21,7 +21,7 @@ if GetTagName(parse[i]) = 'img' then if GetVal(parse[i], 'id') = 'imgPage' then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/MangaLib_PL/image_url.inc b/baseunits/includes/MangaLib_PL/image_url.inc index 49de5966e..7d444fb24 100644 --- a/baseunits/includes/MangaLib_PL/image_url.inc +++ b/baseunits/includes/MangaLib_PL/image_url.inc @@ -6,7 +6,7 @@ cf: Boolean = False; begin l := TStringList.Create; - s := FillMangaSiteHost(MANGALIB_PL_ID, URL) + ',' + IntToStr(Task.Container.WorkCounter + 1); + s := FillMangaSiteHost(MANGALIB_PL_ID, URL) + ',' + IntToStr(WorkId + 1); Result := GetPage(TObject(l), s, @@ -53,7 +53,7 @@ if (Pos('<img ', parse[i]) > 0) and (Pos('id="img_curr"', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaMint/image_url.inc b/baseunits/includes/MangaMint/image_url.inc index 65a56b171..ddd07fa39 100644 --- a/baseunits/includes/MangaMint/image_url.inc +++ b/baseunits/includes/MangaMint/image_url.inc @@ -9,8 +9,8 @@ parse := TStringList.Create; try s := FillMangaSiteHost(MANGAMINT_ID, URL); - if Task.Container.WorkCounter > 0 then - s := s + '?page=' + IntToStr(Task.Container.WorkCounter); + if WorkId > 0 then + s := s + '?page=' + IntToStr(WorkId); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -33,7 +33,7 @@ begin if Pos('src =', parse[i]) > 0 then parse[i] := StringReplace(parse[i], 'src =', 'src=', []); - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaOku/image_url.inc b/baseunits/includes/MangaOku/image_url.inc index 9a777a9ea..cf91dc0a8 100644 --- a/baseunits/includes/MangaOku/image_url.inc +++ b/baseunits/includes/MangaOku/image_url.inc @@ -9,7 +9,7 @@ if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - s := s + IntToStr(Task.Container.WorkCounter + 1) + '/'; + s := s + IntToStr(WorkId + 1) + '/'; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -35,7 +35,7 @@ s := GetVal(parse[i], 'src'); if Pos(WebsiteRoots[MANGAOKU_ID, 1], s) = 0 then s := WebsiteRoots[MANGAOKU_ID, 1] + '/' + s; - Task.Container.PageLinks[Task.Container.WorkCounter] := s; + Task.Container.PageLinks[WorkId] := s; Break; end; end; diff --git a/baseunits/includes/MangaPark/image_url.inc b/baseunits/includes/MangaPark/image_url.inc index 3adc9471d..75f40e98f 100644 --- a/baseunits/includes/MangaPark/image_url.inc +++ b/baseunits/includes/MangaPark/image_url.inc @@ -6,7 +6,7 @@ l := TStringList.Create; Result := GetPage(TObject(l), FillMangaSiteHost(MANGAPARK_ID, URL) + - 'all',//IntToStr(Task.Container.WorkCounter+1), + 'all',//IntToStr(WorkId+1), Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index 74360e5c1..16ea09d1a 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -6,8 +6,8 @@ begin l := TStringList.Create; s := AppendURLDelim(FillMangaSiteHost(MANGATOWN_ID, URL)); - if Task.Container.WorkCounter > 0 then - s := s + IncStr(Task.Container.WorkCounter) + '.html'; + if WorkId > 0 then + s := s + IncStr(WorkId) + '.html'; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -30,7 +30,7 @@ begin if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MangaTraders/image_url.inc b/baseunits/includes/MangaTraders/image_url.inc index a6c4b87a3..084dfb77e 100644 --- a/baseunits/includes/MangaTraders/image_url.inc +++ b/baseunits/includes/MangaTraders/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := FillMangaSiteHost(MANGATRADERS_ID, URL); - s := s + '/page-' + IntToStr(Task.Container.WorkCounter + 1); + s := s + '/page-' + IntToStr(WorkId + 1); Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -24,7 +24,7 @@ parse[i] := RemoveBreaks(parse[i]); if Pos(#9, parse[i]) > 0 then parse[i] := StringReplace(parse[i], #9, ' ', [rfReplaceAll, rfIgnoreCase]); - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Mangacow/image_url.inc b/baseunits/includes/Mangacow/image_url.inc index 2a3b43b5e..5bd55f65b 100644 --- a/baseunits/includes/Mangacow/image_url.inc +++ b/baseunits/includes/Mangacow/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(Task.Container.WorkCounter + 1) + '/'); + s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(WorkId + 1) + '/'); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -22,7 +22,7 @@ if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'style') = 'width:0px; height:0px') then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index 9b8cb2e65..84043d215 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -9,7 +9,7 @@ s := Task.Container.DownloadInfo.SaveTo + '/' + Task.Container.ChapterName[ Task.Container.CurrentDownloadChapterPtr] + '/' + - Format('%.3d', [Task.Container.WorkCounter + 1]); + Format('%.3d', [WorkId + 1]); // Check to see if a file with similar name was already exist. If so then we // skip the download process. if (FileExistsUTF8(s + '.jpg')) or @@ -27,7 +27,7 @@ FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; Result := GetPage(TObject(l), - Task.Container.PageLinks[Task.Container.WorkCounter], + Task.Container.PageLinks[WorkId], Task.Container.Manager.retryConnect); if Self.Terminated then @@ -58,7 +58,7 @@ Task.Container.MangaSiteID, GetVal(parse[i], 'src'), Task.Container.CurrentWorkingDir, - Format('%.3d', [Task.Container.WorkCounter + 1]) + + Format('%.3d', [WorkId + 1]) + '_' + IntToStr(prefix), Task.Container.Manager.retryConnect); @@ -76,7 +76,7 @@ // If prefix = 2 then there're 2 separate images. We need to merge them into one ... if prefix = 2 then begin - imageName := Format('%.3d', [Task.Container.WorkCounter + 1]); + imageName := Format('%.3d', [WorkId + 1]); Merge2Image( Task.Container.CurrentWorkingDir, imageName + '_' + IntToStr(prefix - 2) + '.jpg', diff --git a/baseunits/includes/NHentai/image_url.inc b/baseunits/includes/NHentai/image_url.inc index 2b6ebe33f..ed1773217 100644 --- a/baseunits/includes/NHentai/image_url.inc +++ b/baseunits/includes/NHentai/image_url.inc @@ -9,7 +9,7 @@ if Length(s) > 0 then if s[Length(s)] <> '/' then s := s + '/'; - s := s + IntToStr(QWord(Task.Container.WorkCounter) + 1) + '/'; + s := s + IntToStr(QWord(WorkId) + 1) + '/'; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -42,7 +42,7 @@ s := TrimLeftChar(s, ['/', ':']); s := 'http://' + s; end; - Task.Container.PageLinks[Task.Container.WorkCounter] := s; + Task.Container.PageLinks[WorkId] := s; Break; end; end; diff --git a/baseunits/includes/NineManga/image_url.inc b/baseunits/includes/NineManga/image_url.inc index 6669729ad..9aa383532 100644 --- a/baseunits/includes/NineManga/image_url.inc +++ b/baseunits/includes/NineManga/image_url.inc @@ -8,7 +8,7 @@ s := FillMangaSiteHost(Task.Container.MangaSiteID, URL); s := StringReplace(s, '.html', '', []); s := StringReplace(s, '.htm', '', []); - s := s + '-' + IntToStr(Task.Container.WorkCounter + 1) + '.html'; + s := s + '-' + IntToStr(WorkId + 1) + '.html'; Result := GetPage(TObject(l), s, @@ -32,7 +32,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="manga_pic', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; diff --git a/baseunits/includes/OneManga/image_url.inc b/baseunits/includes/OneManga/image_url.inc index 140fea2ef..fa4dcfc4e 100644 --- a/baseunits/includes/OneManga/image_url.inc +++ b/baseunits/includes/OneManga/image_url.inc @@ -6,7 +6,7 @@ begin l := TStringList.Create; s := FillMangaSiteHost(ONEMANGA_ID, URL); - s := s + IntToStr(Task.Container.WorkCounter + 1) + '/'; + s := s + IntToStr(WorkId + 1) + '/'; Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -22,7 +22,7 @@ if (Pos('<img ', parse[i]) > 0) and (Pos('class="manga-page"', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; parse.Free; diff --git a/baseunits/includes/PornComix/image_url.inc b/baseunits/includes/PornComix/image_url.inc index 8e8ef8974..cd9cf70e2 100644 --- a/baseunits/includes/PornComix/image_url.inc +++ b/baseunits/includes/PornComix/image_url.inc @@ -4,7 +4,7 @@ s, surl: String; l: TStringList; begin - surl := Task.Container.PageContainerLinks[Task.Container.WorkCounter]; + surl := Task.Container.PageContainerLinks[WorkId]; if not ((Pos('imagetwist.', surl) <> 0) or (Pos('imgmega.', surl) <> 0) or (Pos('imgchili.', surl) <> 0)) then @@ -43,7 +43,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('class="pic', parse[i]) <> 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end @@ -54,7 +54,7 @@ for i := 0 to parse.Count - 1 do if (Pos('<img', parse[i]) <> 0) and (Pos('id="show_image', parse[i]) <> 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Starkana/image_url.inc b/baseunits/includes/Starkana/image_url.inc index 6f0db25cc..c2abe9f53 100644 --- a/baseunits/includes/Starkana/image_url.inc +++ b/baseunits/includes/Starkana/image_url.inc @@ -5,7 +5,7 @@ begin l := TStringList.Create; Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)), + DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(WorkId + 1)), Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); @@ -20,7 +20,7 @@ if (Pos('<img', parse[i]) > 0) and (Pos('class="dyn', parse[i]) > 0) and (Pos('style="cursor: pointer', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := GetVal(parse[i], 'src'); + Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; end; end; diff --git a/baseunits/includes/Turkcraft/image_url.inc b/baseunits/includes/Turkcraft/image_url.inc index f0f612aa7..c1e95913f 100644 --- a/baseunits/includes/Turkcraft/image_url.inc +++ b/baseunits/includes/Turkcraft/image_url.inc @@ -5,7 +5,7 @@ l: TStringList; begin l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(Task.Container.WorkCounter + 1)); + s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(WorkId + 1)); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); @@ -21,7 +21,7 @@ for i := 0 to parse.Count - 1 do if (Pos('class="picture"', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := + Task.Container.PageLinks[WorkId] := EncodeURL(WebsiteRoots[TURKCRAFT_ID, 1] + TURKCRAFT_BROWSER + GetVal(parse[i], 'src')); Break; diff --git a/baseunits/includes/UnixManga/image_url.inc b/baseunits/includes/UnixManga/image_url.inc index 672ab7a28..f6c942aac 100644 --- a/baseunits/includes/UnixManga/image_url.inc +++ b/baseunits/includes/UnixManga/image_url.inc @@ -5,7 +5,7 @@ s: String; begin l := TStringList.Create; - s := Task.Container.PageContainerLinks[Task.Container.WorkCounter]; + s := Task.Container.PageContainerLinks[WorkId]; Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); if Self.Terminated then @@ -28,7 +28,7 @@ begin if (Pos('STYLE="border', parse[i]) > 0) and (Pos('<IMG', parse[i]) > 0) then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := Trim(GetVal(parse[i], 'SRC')); + Task.Container.PageLinks[WorkId] := Trim(GetVal(parse[i], 'SRC')); Break; end; end; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index f49f3f21a..012ab96c5 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -289,13 +289,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if PageContainerLinks.Text = '' then Exit; rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + - IntToStr(WorkCounter + 1); + IntToStr(DownloadThread.WorkId + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := XPathString('//div[@id="full_image"]//img/@src'); + PageLinks[DownloadThread.WorkId] := XPathString('//div[@id="full_image"]//img/@src'); finally Free; end; diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index 383266185..82a79a828 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -94,7 +94,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[WorkCounter])); + rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkId])); if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -102,7 +102,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; rurl := XPathString('//img[@id="image"]/@src'); if Pos('//', rurl) = 1 then rurl := 'https:' + rurl; - PageLinks[WorkCounter] := rurl; + PageLinks[DownloadThread.WorkId] := rurl; finally Free; end; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 772398139..5a72d2e3e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -169,14 +169,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AURL; - if WorkCounter > 0 then - s := AppendURLDelim(s) + 'page/' + IncStr(WorkCounter); + if DownloadThread.WorkId > 0 then + s := AppendURLDelim(s) + 'page/' + IncStr(DownloadThread.WorkId); if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, s), Module) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := XPathString('//div[@id="page"]//img/@src'); + PageLinks[DownloadThread.WorkId] := XPathString('//div[@id="page"]//img/@src'); finally Free; end; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 0720579df..c75170140 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -138,13 +138,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AppendURLDelim(AURL) + IncStr(WorkCounter) + '/'; + s := AppendURLDelim(AURL) + IncStr(DownloadThread.WorkId) + '/'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[WorkCounter] := query.XPathString('//*[@id="con"]//img/@src'); + PageLinks[DownloadThread.WorkId] := query.XPathString('//*[@id="con"]//img/@src'); finally query.Free; end; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index bc311d4f9..7a1335cfc 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -183,8 +183,8 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := FillHost(Module.RootURL, AURL); - if WorkCounter > 0 then - s := AppendURLDelim(s) + IncStr(WorkCounter) + '/'; + if DownloadThread.WorkId > 0 then + s := AppendURLDelim(s) + IncStr(DownloadThread.WorkId) + '/'; if GET(s) then begin Result := True; @@ -194,7 +194,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if s <> '' then begin s := TrimLeftChar(s, ['/']); - PageLinks[WorkCounter] := MaybeFillHost(cdnurl, s); + PageLinks[DownloadThread.WorkId] := MaybeFillHost(cdnurl, s); end; finally Free; diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index f1fe59f48..c64a6664a 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -143,12 +143,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(FillHost(Module.RootURL, AURL) + IncStr(WorkCounter)) then + if GET(FillHost(Module.RootURL, AURL) + IncStr(DownloadThread.WorkId)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := XPathString('//img[@id="img-content"]/@src'); + PageLinks[DownloadThread.WorkId] := XPathString('//img[@id="img-content"]/@src'); finally Free; end; diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index 51f1543e6..2f0de077e 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -163,12 +163,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if RightStr(s, 2) = '/1' then SetLength(s, Length(s) - 1); with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AppendURLDelim(s) + IncStr(WorkCounter) + '/'; + s := AppendURLDelim(s) + IncStr(DownloadThread.WorkId) + '/'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := XPathString('//img[@id="mainImg"]/@src'); finally Free; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 1e7d0c4c1..d572bffa7 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -126,12 +126,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(WorkCounter) + '.html') then + IncStr(DownloadThread.WorkId) + '.html') then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := XPathString('//div[@class="read_img"]//img[@id="image"]/@src'); finally Free; diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 411b11fdb..615ac380f 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -145,15 +145,15 @@ function GetImageURL(const DownloadThread: TDownloadThread; Source := TStringList.Create; try rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if WorkCounter > 0 then - rurl += IncStr(WorkCounter) + '.html'; + if DownloadThread.WorkId > 0 then + rurl += IncStr(DownloadThread.WorkId) + '.html'; if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then if Source.Count > 0 then begin Result := True; Query := TXQueryEngineHTML.Create(Source.Text); try - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := Query.XPathString('//*[@id="viewer"]//img[@id="image"]/@src'); finally Query.Free; diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index e5a9ba0bf..60a88af06 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -139,13 +139,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := RemoveURLDelim(AURL); - if WorkCounter > 0 then s += '/' + IncStr(WorkCounter) + '.html'; + if DownloadThread.WorkId > 0 then s += '/' + IncStr(DownloadThread.WorkId) + '.html'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[WorkCounter] := query.XPathString('//section[@id="viewer"]//img/@src'); + PageLinks[DownloadThread.WorkId] := query.XPathString('//section[@id="viewer"]//img/@src'); finally query.Free; end; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 745e153c7..8b1dad06d 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -175,14 +175,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; try if GetPage(DownloadThread.FHTTP, TObject(Source), AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(WorkCounter), Manager.retryConnect) then + IncStr(DownloadThread.WorkId), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; Parser := TTreeParser.Create; try ParseHTMLTree(Parser, Source.Text); - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := SelectXPathString('//img[@id="img"]/@src', Parser); finally Parser.Free; diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 3a9b1b0b2..bcceb17a7 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -157,14 +157,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; try if GetPage(DownloadThread.FHTTP, TObject(Source), AppendURLDelim(FillHost(readURL, AURL)) + - IncStr(WorkCounter), Manager.retryConnect) then + IncStr(DownloadThread.WorkId), Manager.retryConnect) then if Source.Count > 0 then begin Result := True; Parser := TTreeParser.Create; try ParseHTMLTree(Parser, Source.Text); - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := SelectXPathString('//img[@id="manga-page"]/@src', Parser); finally Parser.Free; diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index 40eb74da2..b26144c92 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -97,13 +97,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := AURL; s := ReplaceRegExpr('\.html?$', s, '', False); - s += '-page-' + IncStr(WorkCounter) + '.html'; + s += '-page-' + IncStr(DownloadThread.WorkId) + '.html'; if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; try query.ParseHTML(StreamToString(Document)); - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := query.XPathString('//img[@class="manga-page center-block"]/@src'); finally query.Free; diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index c9890e7ef..2c2991d23 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -192,13 +192,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + AURL; - if WorkCounter > PageContainerLinks.Count then Exit; - if GETWithCookie(DownloadThread.FHTTP, PageContainerLinks[WorkCounter], Module) then + if DownloadThread.WorkId > PageContainerLinks.Count then Exit; + if GETWithCookie(DownloadThread.FHTTP, PageContainerLinks[DownloadThread.WorkId], Module) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := + PageLinks[DownloadThread.WorkId] := MaybeFillHost(Module.RootURL, XPathString('//div[@class="chapter-content"]//img/@src')); finally Free; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index 5ff01c4a1..e2d0a6752 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -107,7 +107,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := RemoveURLDelim(AURL); - if WorkCounter > 0 then s += '/' + IncStr(WorkCounter); + if DownloadThread.WorkId > 0 then s += '/' + IncStr(DownloadThread.WorkId); if GET(FillHost(Module.RootURL, s)) then begin Result := True; query := TXQueryEngineHTML.Create; @@ -116,7 +116,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; b := query.XPathString('//base/@href'); if b = '' then b := Module.RootURL; s := query.XPathString('//img[@class="picture"]/@src'); - if s <> '' then PageLinks[WorkCounter] := MaybeFillHost(b, s); + if s <> '' then PageLinks[DownloadThread.WorkId] := MaybeFillHost(b, s); finally query.Free; end; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 65e0d14b1..600e8612c 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -156,13 +156,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(WorkCounter)) then begin + if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(DownloadThread.WorkId)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); if s <> '' then - PageLinks[WorkCounter] := s; + PageLinks[DownloadThread.WorkId] := s; finally Free; end; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 7768586b1..a85300a54 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -127,13 +127,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin s := FillHost(Module.RootURL, AURL); - if WorkCounter > 0 then - s := s + '/' + IncStr(WorkCounter); + if DownloadThread.WorkId > 0 then + s := s + '/' + IncStr(DownloadThread.WorkId); if GET(s) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[WorkCounter] := XPathString('//div[@id="ab"]/a/img/@src'); + PageLinks[DownloadThread.WorkId] := XPathString('//div[@id="ab"]/a/img/@src'); finally Free; end; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index bc6212a56..1568c33da 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -272,7 +272,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(WorkCounter) + '/') then + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.WorkId) + '/') then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -283,7 +283,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; s := XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); if s = '' then s := XPathString('//*[@id="reader"]//img[@id="picture"]/@src'); - PageLinks[WorkCounter] := s; + PageLinks[DownloadThread.WorkId] := s; finally Free; end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ce608b73b..af2228f0a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -31,8 +31,6 @@ TDownloadThread = class(TFMDThread) private parse: TStringList; public - FHTTP: THTTPSendThread; - // Get download link from URL function GetLinkPageFromURL(const URL: String): Boolean; // Get number of download link from URL @@ -54,7 +52,9 @@ TDownloadThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; public + FHTTP: THTTPSendThread; Task: TTaskThread; + WorkId: Integer; constructor Create; destructor Destroy; override; end; @@ -216,7 +216,8 @@ TDownloadManager = class implementation -uses frmMain, WebsiteModules; +uses + frmMain, WebsiteModules; function IntToStr(Value: Cardinal): String; begin @@ -674,10 +675,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; begin Result := False; - if (Task.Container.PageLinks.Count > 0) and - (Task.Container.PageLinks.Strings[Task.Container.WorkCounter] <> 'W') then - Exit; - + if Task.Container.PageLinks[WorkId] <> 'W' then Exit; if Modules.ModuleAvailable(Task.Container.ModuleId, MMGetImageURL) then Result := Modules.GetImageURL(Self, URL, Task.Container.ModuleId) else @@ -931,7 +929,7 @@ function TDownloadThread.DownloadImage: Boolean; end; // check pagelinks url - workURL := Task.Container.PageLinks[Task.Container.WorkCounter]; + workURL := Task.Container.PageLinks[WorkId]; if (workURL = '') or (workURL = 'W') or (workURL = 'D') then @@ -945,10 +943,10 @@ function TDownloadThread.DownloadImage: Boolean; // prepare filename workFilename := ''; - if Task.Container.WorkCounter < Task.Container.Filenames.Count then - workFilename := Task.Container.Filenames[Task.Container.WorkCounter]; + if WorkId < Task.Container.Filenames.Count then + workFilename := Task.Container.Filenames[WorkId]; if workFilename = '' then - workFilename := Format('%.3d', [Task.Container.WorkCounter + 1]); + workFilename := Format('%.3d', [WorkId + 1]); // download image savedFilename := ''; @@ -958,10 +956,10 @@ function TDownloadThread.DownloadImage: Boolean; begin workURL := ''; if (Task.Container.PageNumber = Task.Container.PageContainerLinks.Count) - and (Task.Container.WorkCounter < Task.Container.PageContainerLinks.Count) then - workURL := Task.Container.PageContainerLinks[Task.Container.WorkCounter] - else if Task.Container.WorkCounter < Task.Container.PageLinks.Count then - workURL := Task.Container.PageLinks[Task.Container.WorkCounter]; + and (WorkId < Task.Container.PageContainerLinks.Count) then + workURL := Task.Container.PageContainerLinks[WorkId] + else if WorkId < Task.Container.PageLinks.Count then + workURL := Task.Container.PageLinks[WorkId]; if workURL <> '' then Result := Modules.DownloadImage( @@ -987,7 +985,7 @@ function TDownloadThread.DownloadImage: Boolean; if Terminated then Exit(False); if Result then begin - Task.Container.PageLinks[Task.Container.WorkCounter] := 'D'; + Task.Container.PageLinks[WorkId] := 'D'; if Modules.ModuleAvailable(Task.Container.ModuleId, MMAfterImageSaved) then Modules.AfterImageSaved(savedFilename, Task.Container.ModuleId); @@ -1053,6 +1051,7 @@ procedure TTaskThread.CheckOut; Threads.Add(TDownloadThread.Create); with TDownloadThread(Threads.Last) do begin Task := Self; + WorkId := Container.WorkCounter; //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, Container.DownloadInfo.Website); Start; From 616b2da716f53c77387b60964dd5be354591c8f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 29 May 2016 02:47:58 +0800 Subject: [PATCH 1187/2794] batoto, fixed download with account fixed #262 --- baseunits/modules/Batoto.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 012ab96c5..1780fdf77 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -254,7 +254,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin Headers.Values['Referer'] := ' ' + urlroot + '/reader'; cid := SeparateRight(AURL, '/reader#'); + Cookies.Text := Account.Cookies['Batoto']; if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin + begin Result := True; with TXQueryEngineHTML.Create(Document) do try @@ -277,6 +279,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; end; + end; end; function GetImageURL(const DownloadThread: TDownloadThread; @@ -291,6 +294,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + IntToStr(DownloadThread.WorkId + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; + Cookies.Text := Account.Cookies['Batoto']; if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do From 197ca86881d05fe3cd0fdf7dfc988811e61134f2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 29 May 2016 03:03:47 +0800 Subject: [PATCH 1188/2794] frmmain, fixed options save to. manga folder edit always enabled at startup --- mangadownloader/forms/frmMain.lfm | 13 ++++++++----- mangadownloader/forms/frmMain.pas | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 505125860..73a77367f 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -36,13 +36,13 @@ object MainForm: TMainForm Height = 525 Top = 11 Width = 566 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -1912,10 +1912,10 @@ object MainForm: TMainForm Height = 420 Top = 8 Width = 539 - ActivePage = tsSaveTo + ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 3 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2668,6 +2668,7 @@ object MainForm: TMainForm Align = alTop BorderSpacing.Top = 10 Caption = 'Manga folder name:' + Enabled = False ParentColor = False end object edOptionMangaCustomRename: TEdit @@ -2680,6 +2681,7 @@ object MainForm: TMainForm Height = 23 Top = 98 Width = 308 + Enabled = False TabOrder = 4 TextHint = 'Custom rename' end @@ -2754,6 +2756,7 @@ object MainForm: TMainForm Top = 102 Width = 13 Caption = '[?]' + Enabled = False Font.Color = clBlue ParentColor = False ParentFont = False @@ -3073,7 +3076,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 + ClientHeight = 392 ClientWidth = 531 object gbDialogs: TGroupBox Left = 4 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a3e5b353d..05738228d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2129,9 +2129,9 @@ procedure TMainForm.cbOptionDigitVolumeChange(Sender: TObject); procedure TMainForm.cbOptionGenerateMangaFolderNameChange(Sender: TObject); begin - lbOptionMangaCustomRename.Enabled := cbOptionGenerateMangaFolderName.Checked; edOptionMangaCustomRename.Enabled := cbOptionGenerateMangaFolderName.Checked; - lbOptionMangaCustomRenameHint.Enabled := cbOptionGenerateMangaFolderName.Checked; + lbOptionMangaCustomRename.Enabled := edOptionMangaCustomRename.Enabled; + lbOptionMangaCustomRenameHint.Enabled := edOptionMangaCustomRename.Enabled; end; procedure TMainForm.btReadOnlineClick(Sender: TObject); From 12d0a9fb4f8bdd2eadf2ce30ded6ead810b45338 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 29 May 2016 03:05:54 +0800 Subject: [PATCH 1189/2794] Bump version 0.9.58.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 09c7ab7de..2d9854d15 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.58.0 (29-05-2016) +[*] Batoto: fixed download +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.57.0...0.9.58.0 + 0.9.57.0 (28-05-2016) [*] Fixed incorrectly store full path inside archive (zip/cbz) [+] Added GManga[AR] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index eaea90b5b..6a7825711 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="57"/> + <RevisionNr Value="58"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 1d2fc82b2..481d0c5ea 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.57.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.57.0/fmd_0.9.57.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.57.0/fmd_0.9.57.0_Win64.7z +VERSION=0.9.58.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.58.0/fmd_0.9.58.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.58.0/fmd_0.9.58.0_Win64.7z From ef3d33455dfb034e6a80dd0105ac1cfdfc6202b7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 30 May 2016 02:35:42 +0800 Subject: [PATCH 1190/2794] xqueryenginehtml, overload xpathstringall and cssstringall with tstrings --- baseunits/XQueryEngineHTML.pas | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 9560af1e9..d26e79256 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -29,12 +29,16 @@ TXQueryEngineHTML = class const Tree: TTreeNode = nil): String; overload; function XPathStringAll(const Expression: String; const Exc: array of String; const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; + procedure XPathStringAll(const Expression: String; const TheStrings: TStrings; + const Tree: TTreeNode = nil); overload; function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function CSSString(const Expression: String; const Tree: TTreeNode = nil): String; inline; function CSSStringAll(const Expression: String; const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; function CSSStringAll(const Expression: String; const Exc: array of String; const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; + procedure CSSStringAll(const Expression: String; const TheStrings: TStrings; + const Tree: TTreeNode = nil); overload; property Engine: TXQueryEngine read FEngine; property TreeParser: TTreeParser read FTreeParser; end; @@ -42,8 +46,8 @@ TXQueryEngineHTML = class IXQValue = xquery.IXQValue; TTreeNode = simplehtmltreeparser.TTreeNode; - function XPathString(const Expression, HTMLString: String): String; overload; - function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; +function XPathString(const Expression, HTMLString: String): String; overload; +function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; implementation @@ -194,6 +198,15 @@ function TXQueryEngineHTML.XPathStringAll(const Expression: String; const Exc: a AddSeparatorString(Result, v.toString, Separator); end; +procedure TXQueryEngineHTML.XPathStringAll(const Expression: String; + const TheStrings: TStrings; const Tree: TTreeNode); +var + v: IXQValue; +begin + for v in Eval(Expression, False, Tree) do + TheStrings.Add(v.toString); +end; + function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, True, Tree); @@ -225,4 +238,13 @@ function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Exc: arr AddSeparatorString(Result, v.toString, Separator); end; +procedure TXQueryEngineHTML.CSSStringAll(const Expression: String; + const TheStrings: TStrings; const Tree: TTreeNode); +var + v: IXQValue; +begin + for v in Eval(Expression, True, Tree) do + TheStrings.Add(v.toString); +end; + end. From d115f2eba964ee2e28f83fad8a6a11fa06d6637a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 30 May 2016 02:49:09 +0800 Subject: [PATCH 1191/2794] added sekaimanga closed #264 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/SekaiManga.pas | 133 +++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/SekaiManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 31ea7c25c..7e2147e4f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -38,4 +38,5 @@ uses WebtoonTr, MangaDenizi, MangaSaurus, - GMangaMe; + GMangaMe, + SekaiManga; diff --git a/baseunits/modules/SekaiManga.pas b/baseunits/modules/SekaiManga.pas new file mode 100644 index 000000000..6c4ebec9d --- /dev/null +++ b/baseunits/modules/SekaiManga.pas @@ -0,0 +1,133 @@ +unit SekaiManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/Sekai/manga-list.html'; + urllead = '/Sekai/'; + +function FixURLLead(const S: String): String; +begin + Result := S; + if Result = '' then Exit; + if Pos(urllead, Result) = 0 then + begin + if Result[1] = '/' then + Delete(Result, 1, 1); + Result := urllead + Result; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in CSS('div.char>span a') do + begin + s := Trim(v.toString); + if s <> '' then + begin + ALinks.Add(FixURLLead(v.toNode.getAttribute('href'))); + ANames.Add(s); + end; + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v, x: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := CSS('img.img-rounded').toNode.getAttribute('src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := SeparateLeft(XPathString('//title'), ' - '#10); + authors := XPathString('//div[@id="info"]//table/tbody/tr/td[.="Autor(s):"]/following-sibling::td'); + artists := XPathString('//div[@id="info"]//table/tbody/tr/td[.="Artista(s):"]/following-sibling::td'); + status := MangaInfoStatusIfPos(XPathString('//div[@id="info"]//table/tbody/tr/td[.="Estado en SekaiManga:"]/following-sibling::td'), 'En curso', 'Terminado'); + genres := XPathString('//div[@id="info"]//table/tbody/tr/td[.="Género(s):"]/following-sibling::td'); + for v in XPath('//table[@id="example"]/tbody/tr') do + begin + x := XPath('td[2]//a', v.toNode); + s := XPathString('td[3]', v.toNode); + if s <> '' then s := ' ' + s; + chapterLinks.Add(FixURLLead(x.toNode.getAttribute('href'))); + chapterName.Add(x.toString + s); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + Cookies.Add('read_type=1'); + if GET(FillHost(Module.RootURL, AURL)) then + begin + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//div[@class="chapter-content"]//img/@src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'SekaiManga'; + RootURL := 'http://www.sekaimanga.net'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 05a4589cb..23575736d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -15,7 +15,7 @@ Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU -Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SubManga,Tumangaonline +Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SekaiManga,SubManga,Tumangaonline Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing From 7dfb3d03c641ef3b418070ccb9251b710456baa3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 30 May 2016 04:32:08 +0800 Subject: [PATCH 1192/2794] Bump version 0.9.59.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2d9854d15..bc28cebaf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.59.0 (30-05-2016) +[+] Added SekaiManga[ES] +Full changes: https://github.com/riderkick/FMD/compare/0.9.58.0...0.9.59.0 + 0.9.58.0 (29-05-2016) [*] Batoto: fixed download [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6a7825711..c005c9e65 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="58"/> + <RevisionNr Value="59"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 481d0c5ea..865ae1edc 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.58.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.58.0/fmd_0.9.58.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.58.0/fmd_0.9.58.0_Win64.7z +VERSION=0.9.59.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.59.0/fmd_0.9.59.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.59.0/fmd_0.9.59.0_Win64.7z From ccabc7a048faeabe716ca08ebfc5e4876c72becb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 05:43:14 +0800 Subject: [PATCH 1193/2794] baseunit, fixed correctpathsys --- baseunits/uBaseUnit.pas | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 706a1540b..424abad09 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1872,34 +1872,12 @@ procedure CleanHTMLComments(const Str: TStringList); function CorrectPathSys(const Path: String): String; begin - Result := Trim(Path); - if Length(Result) > 0 then - begin - {$IFDEF WINDOWS} - //max length = 260 - Result := StringReplace(Result, '/', '\', [rfReplaceAll]); - if Length(Result) > 0 then - begin - if Length(Result) > MAX_PATH - 13 then - SetLength(Result, MAX_PATH - 13); - Result := StringReplace(Result, '\\', '\', [rfReplaceAll]); - end; - if Length(Result) > 0 then - begin - if Result[Length(Result)] <> '\' then - Result := Result + '\'; - end; - {$ENDIF} - {$IFDEF UNIX} - Result := StringReplace(Result, '\', '/', [rfReplaceAll]); - Result := StringReplace(Result, '//', '/', [rfReplaceAll]); - if Length(Result) > 0 then - begin - if Result[Length(Result)] <> '/' then - Result := Result + '/'; - end; - {$ENDIF} - end; + Result := CleanAndExpandDirectory(GetForcedPathDelims(Path)); + {$IFDEF WINDOWS} + //max length = 247 (MAX_PATH(260) - 12 - 1) + if Length(Result) > 247 then + SetLength(Result, 247); + {$ENDIF} end; function StringOfString(c: String; l: Integer): String; From 04cf5f05db906aa14d240ae518f21b493192d96b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 06:19:09 +0800 Subject: [PATCH 1194/2794] baseunit, fixed removesymbols, replace with _ instead --- baseunits/uBaseUnit.pas | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 424abad09..d7faee7ec 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -56,8 +56,8 @@ interface 'Sports', 'Supernatural', 'Tragedy', 'Yaoi', 'Yuri', 'Webtoons'); - Symbols: array [0..10] of Char = - ('\', '/', ':', '*', '?', '"', '<', '>', '|', #9, ';'); + Symbols: set of Char = + ['\', '/', ':', '*', '?', '"', '<', '>', '|', #9, ';']; StringFilterChar: array [0..35] of array [0..1] of String = ( (#10, '\n'), @@ -1789,17 +1789,9 @@ function RemoveSymbols(const input: String): String; i: Integer; begin Result := input; - for i := Low(Symbols) to High(Symbols) do - begin - if Pos(Symbols[i], Result) > 0 then - Result := StringReplace(Result, Symbols[i], '', [rfReplaceAll]); - end; - - if (Length(Result) > 0) and - (Result[Length(Result)] = '.') then - begin - Result[Length(Result)] := '-'; - end; + for i := 1 to Length(Result) do + if CharInSet(Result[i], Symbols) then + Result[i] := '_'; end; procedure InvertStrings(const Sts: array of TStringList); From afd8c6dd4950b009d35c97a1cf41610f3780949f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 06:41:36 +0800 Subject: [PATCH 1195/2794] fixed path related issue, limit to 247 on windows fixed #267 --- baseunits/uBaseUnit.pas | 3 +-- baseunits/uDownloadsManager.pas | 34 ++++++++++++++++----------------- baseunits/uFavoritesManager.pas | 2 +- baseunits/uSilentThread.pas | 4 ++-- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d7faee7ec..9fb116645 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3209,8 +3209,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag if Stream = nil then Exit; if Stream.Size = 0 then Exit; p := CleanAndExpandDirectory(Path); - if not DirectoryExistsUTF8(p) then ForceDirectoriesUTF8(p); - if DirectoryExistsUTF8(p) then begin + if ForceDirectoriesUTF8(p) then begin f := DetermineStreamFormat(Stream); if f = '' then Exit; f := p + FileName + '.' + f; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index af2228f0a..889fc175c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -919,14 +919,13 @@ function TDownloadThread.DownloadImage: Boolean; Result := True; // check download path - if not DirectoryExistsUTF8(Task.Container.CurrentWorkingDir) then - if not ForceDirectoriesUTF8(Task.Container.CurrentWorkingDir) then - begin - Task.Container.Status := STATUS_FAILED; - Task.Container.DownloadInfo.Status := RS_FailedToCreateDir; - Result := False; - Exit; - end; + if not ForceDirectoriesUTF8(Task.Container.CurrentWorkingDir) then + begin + Task.Container.Status := STATUS_FAILED; + Task.Container.DownloadInfo.Status := RS_FailedToCreateDir; + Result := False; + Exit; + end; // check pagelinks url workURL := Task.Container.PageLinks[WorkId]; @@ -1135,16 +1134,15 @@ procedure TTaskThread.Execute; if Terminated then Exit; //check path - Container.CurrentWorkingDir := CleanAndExpandDirectory(Container.DownloadInfo.SaveTo + + Container.CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo + Container.ChapterName[Container.CurrentDownloadChapterPtr]); - if not DirectoryExistsUTF8(Container.CurrentWorkingDir) then - if not ForceDirectoriesUTF8(Container.CurrentWorkingDir) then - begin - Container.Status := STATUS_FAILED; - Container.DownloadInfo.Status := RS_FailedToCreateDir; - SyncShowBaloon; - Exit; - end; + if not ForceDirectoriesUTF8(Container.CurrentWorkingDir) then + begin + Container.Status := STATUS_FAILED; + Container.DownloadInfo.Status := RS_FailedToCreateDir; + SyncShowBaloon; + Exit; + end; if Container.ModuleId > -1 then Modules.TaskStart(Container, Container.ModuleId); @@ -1541,7 +1539,7 @@ procedure TDownloadManager.Restore; DownloadInfo.Website := ReadString(tid, 'Website', 'NULL'); DownloadInfo.Link := ReadString(tid, 'Link', ''); DownloadInfo.Title := ReadString(tid, 'Title', 'NULL'); - DownloadInfo.SaveTo := CleanAndExpandDirectory(ReadString(tid, 'SaveTo', 'NULL')); + DownloadInfo.SaveTo := CorrectPathSys(ReadString(tid, 'SaveTo', 'NULL')); DownloadInfo.Status := ReadString(tid, 'Status', 'NULL'); DownloadInfo.Progress := ReadString(tid, 'Progress', 'NULL'); if Pos('/', DownloadInfo.Progress) > 0 then diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 82d51de59..02af2f68d 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -906,7 +906,7 @@ procedure TFavoriteManager.Restore; currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); Website := ReadString(IntToStr(i), 'Website', ''); - SaveTo := CleanAndExpandDirectory(ReadString(IntToStr(i), 'SaveTo', '')); + SaveTo := CorrectPathSys(ReadString(IntToStr(i), 'SaveTo', '')); Link := ReadString(IntToStr(i), 'Link', ''); Website := Website; Status := STATUS_IDLE; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 45f28bb99..af42d05ef 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -371,7 +371,7 @@ procedure TSilentThread.MainThreadAfterChecking; '', OptionChangeUnicodeCharacter); end; - DLManager.Items[p].downloadInfo.SaveTo := CleanAndExpandDirectory(FSavePath); + DLManager.Items[p].downloadInfo.SaveTo := CorrectPathSys(FSavePath); UpdateVtDownload; DLManager.CheckAndActiveTask(False); @@ -475,7 +475,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; IntToStr(Info.mangaInfo.numChapter), s2, website, - CleanAndExpandDirectory(s), + CorrectPathSys(s), URL); UpdateVtFavorites; end; From 77bfdb158310bd88c1994c386f6081241b5e0f58 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 07:09:50 +0800 Subject: [PATCH 1196/2794] fixed readcomiconline domain fixed #265 --- baseunits/modules/KissManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 2ac4cc05c..015202116 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -174,7 +174,7 @@ procedure RegisterModule; begin AddWebsiteModule('KissManga', 'http://kissmanga.com'); - AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.com'); + AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.to'); end; initialization From 8598258c16f3cf41c8cb7cccb05acdf3a9a6aea1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 16:39:55 +0800 Subject: [PATCH 1197/2794] added option auto generate chapter folder and custom filename closed #266 --- baseunits/FMDOptions.pas | 5 +- baseunits/uBaseUnit.pas | 10 +- baseunits/uDownloadsManager.pas | 22 +- baseunits/uGetMangaInfosThread.pas | 2 +- baseunits/uSilentThread.pas | 4 +- mangadownloader/forms/frmMain.lfm | 313 +++++++++++++++++------------ mangadownloader/forms/frmMain.pas | 34 +++- mangadownloader/md.lpi | 2 +- 8 files changed, 244 insertions(+), 148 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index f5f7d664b..4ebfe0ff2 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -39,6 +39,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; + DEFAULT_FILENAME_CUSTOMRENAME = '%FILENAME%'; DATA_EXT = '.dat'; DBDATA_EXT = '.db'; @@ -90,9 +91,11 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionLetFMDDo: TFMDDo = DO_NOTHING; OptionChangeUnicodeCharacter: Boolean = False; - OptionGenerateMangaFolderName: Boolean = False; + OptionGenerateMangaFolder: Boolean = False; OptionMangaCustomRename: String; + OptionGenerateChapterFolder: Boolean = True; OptionChapterCustomRename: String; + OptionFilenameCustomRename: String; OptionPDFQuality: Cardinal = 95; OptionUpdateListNoMangaInfo: Boolean = False; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9fb116645..e9631ac23 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -756,7 +756,8 @@ function GetHeaderValue(const AHeaders: TStrings; HName: String): String; // custom rename feature function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, - AChapter, ANumbering: String; const AIsUnicodeRemove: Boolean): String; + AChapter, ANumbering: String; const ARemoveUnicode: Boolean; + const AFilename: String = ''): String; // Get substring from source function GetString(const Source, sStart, sEnd: String): String; @@ -2104,8 +2105,8 @@ function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: T end; end; -function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, - AChapter, ANumbering: String; const AIsUnicodeRemove: Boolean): String; +function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, + ANumbering: String; const ARemoveUnicode: Boolean; const AFilename: String): String; var chap: String; begin @@ -2154,13 +2155,14 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, Result := StringReplaceBrackets(Result, '%MANGA%', AMangaName, [rfReplaceAll]); Result := StringReplaceBrackets(Result, '%AUTHOR%', AAuthor, [rfReplaceAll]); Result := StringReplaceBrackets(Result, '%ARTIST%', AArtist, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%FILENAME%', AFilename, [rfReplaceAll]); if Result = '' then Result := AMangaName; if Result = '' then Exit; // strip unicode character - if AIsUnicodeRemove then + if ARemoveUnicode then Result := UnicodeRemove(Result); // replace htmlentities diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 889fc175c..e4926fab9 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -121,9 +121,11 @@ TTaskContainer = class PageContainerLinks, PageLinks: TStringList; Filenames: TStringList; + // custom filenames constructor Create; destructor Destroy; override; procedure IncReadCount(const ACount: Integer); + public property Website: String read FWebsite write SetWebsite; end; @@ -946,6 +948,19 @@ function TDownloadThread.DownloadImage: Boolean; workFilename := Task.Container.Filenames[WorkId]; if workFilename = '' then workFilename := Format('%.3d', [WorkId + 1]); + // custom filename + with task.Container.DownloadInfo do + begin + workFilename := CustomRename(OptionFilenameCustomRename, + Website, + Title, + '', + '', + Task.Container.ChapterName[Task.Container.CurrentDownloadChapterPtr], + '', + OptionChangeUnicodeCharacter, + workFilename); + end; // download image savedFilename := ''; @@ -1134,8 +1149,11 @@ procedure TTaskThread.Execute; if Terminated then Exit; //check path - Container.CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo + - Container.ChapterName[Container.CurrentDownloadChapterPtr]); + if OptionGenerateChapterFolder then + Container.CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo + + Container.ChapterName[Container.CurrentDownloadChapterPtr]) + else + Container.CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo); if not ForceDirectoriesUTF8(Container.CurrentWorkingDir) then begin Container.Status := STATUS_FAILED; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 34f38e02c..3e8d1dd0f 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -84,7 +84,7 @@ procedure TGetMangaInfosThread.DoGetInfos; FNumChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); end; - FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolderName; + FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolder; FInfo.isRemoveUnicode := OptionChangeUnicodeCharacter; infob := INFORMATION_NOT_FOUND; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index af42d05ef..7f17f218e 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -360,7 +360,7 @@ procedure TSilentThread.MainThreadAfterChecking; FilledSaveTo; FSavePath := edSaveTo.Text; // save to - if OptionGenerateMangaFolderName then + if OptionGenerateMangaFolder then FSavePath := AppendPathDelim(FSavePath) + CustomRename( OptionMangaCustomRename, website, @@ -453,7 +453,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; end else s := FSavePath; - if OptionGenerateMangaFolderName then + if OptionGenerateMangaFolder then s := AppendPathDelim(s) + CustomRename( OptionMangaCustomRename, website, diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 73a77367f..bb463579e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,11 +1,11 @@ object MainForm: TMainForm - Left = 379 - Height = 592 - Top = 113 + Left = 297 + Height = 538 + Top = 115 Width = 771 ActiveControl = pcMain Caption = 'Free Manga Downloader' - ClientHeight = 592 + ClientHeight = 538 ClientWidth = 771 OnClose = FormClose OnCreate = FormCreate @@ -17,7 +17,7 @@ object MainForm: TMainForm object sbUpdateList: TStatusBar Left = 0 Height = 30 - Top = 562 + Top = 508 Width = 771 AutoSize = False Panels = < @@ -33,7 +33,7 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 525 + Height = 471 Top = 11 Width = 566 ActivePage = tsDownload @@ -47,11 +47,11 @@ object MainForm: TMainForm OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' - ClientHeight = 497 + ClientHeight = 443 ClientWidth = 558 object vtDownload: TVirtualStringTree Left = 4 - Height = 461 + Height = 407 Top = 32 Width = 550 Align = alClient @@ -260,22 +260,22 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 497 + ClientHeight = 443 ClientWidth = 558 object sbInformation: TScrollBox Left = 0 - Height = 497 + Height = 443 Top = 0 Width = 558 HorzScrollBar.Page = 327 - VertScrollBar.Page = 487 + VertScrollBar.Page = 433 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 497 + ClientHeight = 443 ClientWidth = 558 TabOrder = 0 object pnInfomation: TPanel @@ -420,21 +420,21 @@ object MainForm: TMainForm end object pnChapterList: TPanel Left = 4 - Height = 206 + Height = 152 Top = 283 Width = 550 Align = alClient BevelOuter = bvNone ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 206 + ClientHeight = 152 ClientWidth = 550 TabOrder = 2 object clbChapterList: TVirtualStringTree AnchorSideTop.Side = asrBottom AnchorSideBottom.Control = lbSaveTo Left = 0 - Height = 127 + Height = 73 Top = 0 Width = 516 Anchors = [akTop, akLeft, akRight, akBottom] @@ -465,7 +465,7 @@ object MainForm: TMainForm AnchorSideBottom.Side = asrBottom Left = 338 Height = 26 - Top = 150 + Top = 96 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True @@ -517,7 +517,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 0 Height = 19 - Top = 177 + Top = 123 Width = 334 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' @@ -531,7 +531,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 442 Height = 26 - Top = 150 + Top = 96 Width = 108 Anchors = [akRight, akBottom] AutoSize = True @@ -629,7 +629,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 338 Height = 26 - Top = 180 + Top = 126 Width = 212 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True @@ -680,7 +680,7 @@ object MainForm: TMainForm AnchorSideBottom.Control = edSaveTo Left = 0 Height = 15 - Top = 131 + Top = 77 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' @@ -693,7 +693,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btDownload Left = 0 Height = 23 - Top = 150 + Top = 96 Width = 334 OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False @@ -746,18 +746,18 @@ object MainForm: TMainForm end object tsFilter: TTabSheet Caption = 'Filter' - ClientHeight = 462 + ClientHeight = 443 ClientWidth = 558 object sbFilter: TScrollBox Left = 0 - Height = 462 + Height = 443 Top = 0 Width = 558 HorzScrollBar.Page = 488 VertScrollBar.Page = 416 Align = alClient BorderStyle = bsNone - ClientHeight = 462 + ClientHeight = 443 ClientWidth = 558 TabOrder = 0 object pnCustomGenre: TPanel @@ -1905,11 +1905,11 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 497 + ClientHeight = 443 ClientWidth = 558 object pnOptions: TPageControl Left = 8 - Height = 420 + Height = 366 Top = 8 Width = 539 ActivePage = tsGeneral @@ -1923,7 +1923,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 338 ClientWidth = 531 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime @@ -2563,23 +2563,23 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 392 + ClientHeight = 338 ClientWidth = 531 object sbSaveTo: TScrollBox Left = 0 - Height = 392 + Height = 338 Top = 0 Width = 531 HorzScrollBar.Page = 198 - VertScrollBar.Page = 390 + VertScrollBar.Page = 338 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 - ClientWidth = 531 + ClientHeight = 338 + ClientWidth = 514 TabOrder = 0 object rgOptionCompress: TRadioGroup AnchorSideLeft.Control = lbDefaultDownloadPath @@ -2590,7 +2590,7 @@ object MainForm: TMainForm Left = 4 Height = 60 Top = 54 - Width = 523 + Width = 506 Anchors = [akTop, akLeft, akRight] AutoFill = True BorderSpacing.Top = 4 @@ -2604,7 +2604,7 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 40 - ClientWidth = 519 + ClientWidth = 502 Columns = 4 ItemIndex = 0 Items.Strings = ( @@ -2624,9 +2624,9 @@ object MainForm: TMainForm AnchorSideRight.Control = lbDefaultDownloadPath AnchorSideRight.Side = asrBottom Left = 4 - Height = 237 + Height = 302 Top = 145 - Width = 523 + Width = 506 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 @@ -2635,38 +2635,41 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 217 - ClientWidth = 519 + ClientHeight = 282 + ClientWidth = 502 ParentFont = False TabOrder = 4 - object cbOptionRemoveMangaNameFromChapter: TCheckBox + object cbOptionChangeUnicodeCharacter: TCheckBox Left = 4 Height = 19 - Top = 50 - Width = 511 + Top = 4 + Width = 494 Align = alTop - Caption = 'Remove manga name from chapter' + Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' ParentFont = False - TabOrder = 3 + TabOrder = 0 end - object cbOptionGenerateMangaFolderName: TCheckBox + object cbOptionGenerateMangaFolder: TCheckBox + AnchorSideLeft.Control = cbOptionChangeUnicodeCharacter + AnchorSideTop.Control = cbOptionChangeUnicodeCharacter + AnchorSideTop.Side = asrBottom Left = 4 Height = 19 Top = 27 - Width = 511 - Align = alTop + Width = 261 Caption = 'Auto generate folder based on manga''s name' - OnChange = cbOptionGenerateMangaFolderNameChange + OnChange = cbOptionGenerateMangaFolderChange ParentFont = False - TabOrder = 0 + TabOrder = 1 end object lbOptionMangaCustomRename: TLabel + AnchorSideLeft.Control = cbOptionGenerateMangaFolder + AnchorSideTop.Control = cbOptionGenerateMangaFolder + AnchorSideTop.Side = asrBottom Left = 4 Height = 15 - Top = 79 - Width = 511 - Align = alTop - BorderSpacing.Top = 10 + Top = 50 + Width = 107 Caption = 'Manga folder name:' Enabled = False ParentColor = False @@ -2679,44 +2682,78 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 4 Height = 23 - Top = 98 + Top = 69 Width = 308 Enabled = False - TabOrder = 4 + TabOrder = 3 TextHint = 'Custom rename' end - object cbOptionChangeUnicodeCharacter: TCheckBox + object lbOptionMangaCustomRenameHint: TLabel + AnchorSideLeft.Control = edOptionMangaCustomRename + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edOptionMangaCustomRename + AnchorSideTop.Side = asrCenter + Left = 316 + Height = 15 + Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10#13#10'Note:'#13#10'Manga folder name must have at least %MANGA%.' + Top = 73 + Width = 13 + Caption = '[?]' + Enabled = False + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object cbOptionRemoveMangaNameFromChapter: TCheckBox + AnchorSideLeft.Control = lbOptionMangaCustomRename + AnchorSideTop.Control = edOptionMangaCustomRename + AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 4 - Width = 511 - Align = alTop - Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' + Top = 96 + Width = 208 + Caption = 'Remove manga name from chapter' ParentFont = False - TabOrder = 1 + TabOrder = 2 end - object edOptionChapterCustomRename: TEdit - AnchorSideLeft.Control = lbOptionCustomRename - AnchorSideTop.Control = lbOptionCustomRename + object cbOptionGenerateChapterFolder: TCheckBox + AnchorSideLeft.Control = cbOptionRemoveMangaNameFromChapter + AnchorSideTop.Control = cbOptionRemoveMangaNameFromChapter AnchorSideTop.Side = asrBottom Left = 4 - Height = 23 - Top = 144 - Width = 308 - TabOrder = 2 - TextHint = 'Custom rename' + Height = 19 + Top = 119 + Width = 172 + Caption = 'Auto generate chapter folder' + Checked = True + ParentFont = False + State = cbChecked + TabOrder = 4 end - object lbOptionCustomRename: TLabel - AnchorSideLeft.Control = edOptionMangaCustomRename - AnchorSideTop.Control = edOptionMangaCustomRename + object lbOptionChapterCustomRename: TLabel + AnchorSideLeft.Control = cbOptionGenerateChapterFolder + AnchorSideTop.Control = cbOptionGenerateChapterFolder AnchorSideTop.Side = asrBottom Left = 4 Height = 15 - Top = 125 - Width = 112 - Caption = 'Chapter folder name:' + Top = 142 + Width = 78 + Caption = 'Chapter name:' ParentColor = False end + object edOptionChapterCustomRename: TEdit + AnchorSideLeft.Control = lbOptionChapterCustomRename + AnchorSideTop.Control = lbOptionChapterCustomRename + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 161 + Width = 308 + TabOrder = 5 + TextHint = 'Custom rename' + end object lbOptionChapterCustomRenameHint: TLabel AnchorSideLeft.Control = edOptionChapterCustomRename AnchorSideLeft.Side = asrBottom @@ -2725,7 +2762,7 @@ object MainForm: TMainForm Left = 316 Height = 15 Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10'%NUMBERING% : Numbering'#13#10#13#10'Note:'#13#10'Chapter folder name must have at least %CHAPTER% or %NUMBERING%.' - Top = 148 + Top = 165 Width = 13 Caption = '[?]' Font.Color = clBlue @@ -2740,28 +2777,22 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 15 - Top = 171 + Top = 188 Width = 78 Caption = 'Rename digits' ParentColor = False end - object lbOptionMangaCustomRenameHint: TLabel - AnchorSideLeft.Control = edOptionMangaCustomRename - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edOptionMangaCustomRename - AnchorSideTop.Side = asrCenter - Left = 316 - Height = 15 - Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%AUTHOR% : Author'#13#10'%ARTIST% : Artist'#13#10#13#10'Note:'#13#10'Manga folder name must have at least %MANGA%.' - Top = 102 - Width = 13 - Caption = '[?]' - Enabled = False - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True + object cbOptionDigitVolume: TCheckBox + AnchorSideLeft.Control = lbOptionRenameDigits + AnchorSideTop.Control = lbOptionRenameDigits + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 19 + Top = 207 + Width = 61 + Caption = 'Volume' + OnChange = cbOptionDigitVolumeChange + TabOrder = 8 end object seOptionDigitVolume: TSpinEdit AnchorSideLeft.Control = cbOptionDigitVolume @@ -2769,59 +2800,87 @@ object MainForm: TMainForm AnchorSideTop.Control = cbOptionDigitVolume Left = 69 Height = 23 - Top = 190 + Top = 207 Width = 50 BorderSpacing.Left = 4 MaxValue = 10 MinValue = 1 - TabOrder = 5 + TabOrder = 6 Value = 1 end + object cbOptionDigitChapter: TCheckBox + AnchorSideLeft.Control = seOptionDigitVolume + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionDigitVolume + Left = 139 + Height = 19 + Top = 207 + Width = 62 + BorderSpacing.Left = 20 + Caption = 'Chapter' + OnChange = cbOptionDigitChapterChange + TabOrder = 9 + end object seOptionDigitChapter: TSpinEdit AnchorSideLeft.Control = cbOptionDigitChapter AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = cbOptionDigitChapter Left = 205 Height = 23 - Top = 190 + Top = 207 Width = 50 BorderSpacing.Left = 4 MaxValue = 10 MinValue = 1 - TabOrder = 6 + TabOrder = 7 Value = 1 end - object cbOptionDigitVolume: TCheckBox - AnchorSideLeft.Control = lbOptionRenameDigits - AnchorSideTop.Control = lbOptionRenameDigits + object lbOptionFilenameCustomRenameHint: TLabel + AnchorSideLeft.Control = edOptionFilenameCustomRename + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edOptionFilenameCustomRename + AnchorSideTop.Side = asrCenter + Left = 316 + Height = 15 + Hint = '%WEBSITE% : Website name'#13#10'%MANGA% : Manga title'#13#10'%CHAPTER% : Chapter title'#13#10'%FILENAME% : Filename'#13#10#13#10'Note:'#13#10'Filename must have at least %FILENAME%' + Top = 259 + Width = 13 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object edOptionFilenameCustomRename: TEdit + AnchorSideLeft.Control = lbOptionFilenameCustomRename + AnchorSideTop.Control = lbOptionFilenameCustomRename AnchorSideTop.Side = asrBottom Left = 4 - Height = 19 - Top = 190 - Width = 61 - Caption = 'Volume' - OnChange = cbOptionDigitVolumeChange - TabOrder = 7 + Height = 23 + Top = 255 + Width = 308 + TabOrder = 10 + TextHint = 'Custom rename' end - object cbOptionDigitChapter: TCheckBox - AnchorSideLeft.Control = seOptionDigitVolume - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = seOptionDigitVolume - Left = 139 - Height = 19 - Top = 190 - Width = 62 - BorderSpacing.Left = 20 - Caption = 'Chapter' - OnChange = cbOptionDigitChapterChange - TabOrder = 8 + object lbOptionFilenameCustomRename: TLabel + AnchorSideLeft.Control = cbOptionGenerateChapterFolder + AnchorSideTop.Control = cbOptionDigitVolume + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 15 + Top = 236 + Width = 51 + BorderSpacing.Top = 10 + Caption = 'Filename:' + ParentColor = False end end object lbDefaultDownloadPath: TLabel Left = 4 Height = 15 Top = 8 - Width = 523 + Width = 506 Align = alTop Caption = 'Choose the default download path:' ParentColor = False @@ -2831,7 +2890,7 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 27 - Width = 523 + Width = 506 OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False ButtonWidth = 23 @@ -2882,7 +2941,7 @@ object MainForm: TMainForm Left = 4 Height = 0 Top = 54 - Width = 523 + Width = 506 Align = alTop AutoSize = True BevelOuter = bvNone @@ -3332,7 +3391,7 @@ object MainForm: TMainForm object btOptionApply: TBitBtn Left = 8 Height = 45 - Top = 439 + Top = 385 Width = 125 Anchors = [akLeft, akBottom] AutoSize = True @@ -3594,7 +3653,7 @@ object MainForm: TMainForm end object pcLeft: TPageControl Left = 4 - Height = 523 + Height = 469 Top = 12 Width = 195 ActivePage = tsMangaList @@ -3611,7 +3670,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 495 + ClientHeight = 441 ClientWidth = 187 object vtMangaList: TVirtualStringTree AnchorSideLeft.Control = lbMode @@ -3620,7 +3679,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btRemoveFilter AnchorSideRight.Side = asrBottom Left = 4 - Height = 406 + Height = 352 Top = 85 Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] @@ -3921,7 +3980,7 @@ object MainForm: TMainForm object sbMain: TStatusBar Left = 0 Height = 23 - Top = 539 + Top = 485 Width = 771 Panels = < item @@ -3935,7 +3994,7 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 531 + Height = 477 Top = 8 Width = 2 OnMoved = spMainSplitterMoved diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 05738228d..3f8dcac30 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -51,6 +51,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionEnableLoadCover: TCheckBox; + cbOptionGenerateChapterFolder: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadMangalistDialog: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; @@ -62,10 +63,13 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + edOptionFilenameCustomRename: TEdit; edOptionDefaultPath: TDirectoryEdit; edOptionMangaCustomRename: TEdit; edSaveTo: TDirectoryEdit; edURL: TEditButton; + lbOptionFilenameCustomRenameHint: TLabel; + lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; miChapterListHideDownloaded: TMenuItem; @@ -184,7 +188,7 @@ TMainForm = class(TForm) cbAddAsStopped: TCheckBox; cbOptionShowQuitDialog: TCheckBox; cbOptionChangeUnicodeCharacter: TCheckBox; - cbOptionGenerateMangaFolderName: TCheckBox; + cbOptionGenerateMangaFolder: TCheckBox; cbOptionMinimizeToTray: TCheckBox; cbSearchFromAllSites: TCheckBox; ckFilterDoujinshi: TCheckBox; @@ -215,7 +219,7 @@ TMainForm = class(TForm) itCheckFav: TIdleTimer; itAnimate: TIdleTimer; imCover: TImage; - lbOptionCustomRename: TLabel; + lbOptionChapterCustomRename: TLabel; lbOptionPDFQuality: TLabel; lbOptionAutoCheckFavIntervalMinutes: TLabel; lbOptionLetFMDDo: TLabel; @@ -359,7 +363,7 @@ TMainForm = class(TForm) procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); - procedure cbOptionGenerateMangaFolderNameChange(Sender: TObject); + procedure cbOptionGenerateMangaFolderChange(Sender: TObject); procedure cbSelectMangaChange(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; @@ -1939,7 +1943,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); // save to s := edSaveTo.Text; - if OptionGenerateMangaFolderName then + if OptionGenerateMangaFolder then s := AppendPathDelim(s) + CustomRename( OptionMangaCustomRename, mangaInfo.website, @@ -1970,7 +1974,7 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); begin // save to s := edSaveTo.Text; - if OptionGenerateMangaFolderName then + if OptionGenerateMangaFolder then s := AppendPathDelim(s) + CustomRename( OptionMangaCustomRename, mangaInfo.website, @@ -2127,9 +2131,9 @@ procedure TMainForm.cbOptionDigitVolumeChange(Sender: TObject); seOptionDigitVolume.Enabled := cbOptionDigitVolume.Checked; end; -procedure TMainForm.cbOptionGenerateMangaFolderNameChange(Sender: TObject); +procedure TMainForm.cbOptionGenerateMangaFolderChange(Sender: TObject); begin - edOptionMangaCustomRename.Enabled := cbOptionGenerateMangaFolderName.Checked; + edOptionMangaCustomRename.Enabled := cbOptionGenerateMangaFolder.Checked; lbOptionMangaCustomRename.Enabled := edOptionMangaCustomRename.Enabled; lbOptionMangaCustomRenameHint.Enabled := edOptionMangaCustomRename.Enabled; end; @@ -4232,10 +4236,11 @@ procedure TMainForm.LoadOptions; rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); cbOptionChangeUnicodeCharacter.Checked := ReadBool('saveto', 'ChangeUnicodeCharacter', False); cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', False); - cbOptionGenerateMangaFolderName.Checked := ReadBool('saveto', 'GenerateMangaName', True); + cbOptionGenerateMangaFolder.Checked := ReadBool('saveto', 'GenerateMangaFolder', True); edOptionMangaCustomRename.Text := ReadString('saveto', 'MangaCustomRename', DEFAULT_MANGA_CUSTOMRENAME); if Trim(edOptionMangaCustomRename.Text) = '' then edOptionMangaCustomRename.Text := DEFAULT_MANGA_CUSTOMRENAME; + cbOptionGenerateChapterFolder.Checked := ReadBool('saveto', 'GenerateChapterFolder', True); edOptionChapterCustomRename.Text := ReadString('saveto', 'ChapterCustomRename', DEFAULT_CHAPTER_CUSTOMRENAME); if Trim(edOptionChapterCustomRename.Text) = '' then edOptionChapterCustomRename.Text := DEFAULT_CHAPTER_CUSTOMRENAME; @@ -4245,6 +4250,9 @@ procedure TMainForm.LoadOptions; cbOptionDigitChapter.Checked := ReadBool('saveto', 'ConvertDigitChapter', True); seOptionDigitChapter.Value := ReadInteger('saveto', 'DigitChapterLength', 3); seOptionDigitChapter.Enabled := cbOptionDigitChapter.Checked; + edOptionFilenameCustomRename.Text := ReadString('saveto', 'FilenameCustomRename', DEFAULT_FILENAME_CUSTOMRENAME); + if Trim(edOptionFilenameCustomRename.Text) = '' then + edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; // update cbOptionAutoCheckLatestVersion.Checked := ReadBool('update', 'AutoCheckLatestVersion', True); @@ -4352,13 +4360,14 @@ procedure TMainForm.SaveOptions; edOptionDefaultPath.Text := CleanAndExpandDirectory(edOptionDefaultPath.Text); WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); WriteBool('saveto', 'ChangeUnicodeCharacter', cbOptionChangeUnicodeCharacter.Checked); - WriteBool('saveto', 'GenerateMangaName', cbOptionGenerateMangaFolderName.Checked); + WriteBool('saveto', 'GenerateMangaFolder', cbOptionGenerateMangaFolder.Checked); if Trim(edOptionMangaCustomRename.Text) = '' then edOptionMangaCustomRename.Text := DEFAULT_MANGA_CUSTOMRENAME; WriteString('saveto', 'MangaCustomRename', edOptionMangaCustomRename.Text); WriteInteger('saveto', 'Compress', rgOptionCompress.ItemIndex); WriteInteger('saveto', 'PDFQuality', seOptionPDFQuality.Value); WriteBool('saveto', 'RemoveMangaNameFromChapter', cbOptionRemoveMangaNameFromChapter.Checked); + WriteBool('saveto', 'GenerateChapterFolder', cbOptionGenerateChapterFolder.Checked); if Trim(edOptionChapterCustomRename.Text) = '' then edOptionChapterCustomRename.Text := DEFAULT_CHAPTER_CUSTOMRENAME; WriteString('saveto', 'ChapterCustomRename', edOptionChapterCustomRename.Text); @@ -4366,6 +4375,9 @@ procedure TMainForm.SaveOptions; WriteBool('saveto', 'ConvertDigitChapter', cbOptionDigitChapter.Checked); WriteInteger('saveto', 'DigitVolumeLength', seOptionDigitVolume.Value); WriteInteger('saveto', 'DigitChapterLength', seOptionDigitChapter.Value); + if Trim(edOptionFilenameCustomRename.Text) = '' then + edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; + WriteString('saveto', 'FilenameCustomRename', edOptionFilenameCustomRename.Text); // update WriteBool('update', 'AutoCheckLatestVersion', cbOptionAutoCheckLatestVersion.Checked); @@ -4490,9 +4502,11 @@ procedure TMainForm.ApplyOptions; DLManager.compress := rgOptionCompress.ItemIndex; OptionChangeUnicodeCharacter := cbOptionChangeUnicodeCharacter.Checked; OptionRemoveMangaNameFromChapter := cbOptionRemoveMangaNameFromChapter.Checked; - OptionGenerateMangaFolderName := cbOptionGenerateMangaFolderName.Checked; + OptionGenerateMangaFolder := cbOptionGenerateMangaFolder.Checked; OptionMangaCustomRename := edOptionMangaCustomRename.Text; + OptionGenerateChapterFolder := cbOptionGenerateChapterFolder.Checked; OptionChapterCustomRename := edOptionChapterCustomRename.Text; + OptionFilenameCustomRename := edOptionFilenameCustomRename.Text; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c005c9e65..17d66eaf8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="59"/> + <RevisionNr Value="60"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> From 870a3d8bad1b1a7a5108bd89c05095ca3ba37cdb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 16:46:17 +0800 Subject: [PATCH 1198/2794] update translations --- mangadownloader/languages/fmd.en.po | 49 +++++++++++++++++++++--- mangadownloader/languages/fmd.id_ID.po | 52 ++++++++++++++++++++++---- mangadownloader/languages/fmd.po | 41 +++++++++++++++++--- 3 files changed, 125 insertions(+), 17 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index fcbe39472..322535475 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -548,7 +548,12 @@ msgstr "Volume" msgid "Enable load manga cover" msgstr "Enable load manga cover" -#: tmainform.cboptiongeneratemangafoldername.caption +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Auto generate chapter folder" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" msgid "Auto generate folder based on manga's name" msgstr "Auto generate folder based on manga's name" @@ -976,6 +981,11 @@ msgctxt "tmainform.edoptionexternalpath.texthint" msgid "External program path" msgstr "External program path" +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Custom rename" + #: tmainform.edoptionhost.texthint msgid "Proxy host/IP" msgstr "Proxy host/IP" @@ -1116,6 +1126,12 @@ msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" +#: tmainform.lboptionchaptercustomrename.caption +#| msgid "Chapter folder name:" +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Chapter name:" + #: tmainform.lboptionchaptercustomrenamehint.caption msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" msgid "[?]" @@ -1148,10 +1164,6 @@ msgstr "" msgid "Connection timeout (seconds)" msgstr "Connection timeout (seconds)" -#: tmainform.lboptioncustomrename.caption -msgid "Chapter folder name:" -msgstr "Chapter folder name:" - #: tmainform.lboptionexternal.caption msgid "Open manga by using external program:" msgstr "Open manga by using external program:" @@ -1165,6 +1177,33 @@ msgctxt "tmainform.lboptionexternalparamshint.caption" msgid "[?]" msgstr "[?]" +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Filename:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" + #: tmainform.lboptionhost.caption msgid "Host" msgstr "Host" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 801c0485b..f2f284d86 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -538,7 +538,12 @@ msgstr "Volume" msgid "Enable load manga cover" msgstr "Aktifkan sampul komik" -#: tmainform.cboptiongeneratemangafoldername.caption +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Buat otomatis folder bab" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" msgid "Auto generate folder based on manga's name" msgstr "Buat otomatis folder berdasarkan nama komik" @@ -964,6 +969,11 @@ msgctxt "tmainform.edoptionexternalpath.texthint" msgid "External program path" msgstr "Parameter program" +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Ubah nama kustom" + #: tmainform.edoptionhost.texthint msgid "Proxy host/IP" msgstr "Host/IP" @@ -1101,6 +1111,11 @@ msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" msgid "Auto check for new chapter every %d minutes" msgstr "Otomatis periksa bab baru setiap %d menit" +#: tmainform.lboptionchaptercustomrename.caption +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Nama bab:" + #: tmainform.lboptionchaptercustomrenamehint.caption msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" msgid "[?]" @@ -1127,16 +1142,12 @@ msgstr "" "%NUMBERING% : Penomoran\n" "\n" "Catatan:\n" -"Nama folder harus memiliki setidaknya %CHAPTER% atau %NUMBERING%.\n" +"Nama bab setidaknya harus memiliki %CHAPTER% atau %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" msgstr "Batas waktu koneksi (detik)" -#: tmainform.lboptioncustomrename.caption -msgid "Chapter folder name:" -msgstr "Nama folder bab:" - #: tmainform.lboptionexternal.caption msgid "Open manga by using external program:" msgstr "Buka komik dengan program eksternal:" @@ -1150,6 +1161,33 @@ msgctxt "tmainform.lboptionexternalparamshint.caption" msgid "[?]" msgstr "[?]" +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Nama File:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nama situs\n" +"%MANGA% : Judul komik\n" +"%CHAPTER% : Judul bab\n" +"%FILENAME% : Nama file\n" +"\n" +"Note:\n" +"Nama file setidaknya harus memiliki %FILENAME%\n" + #: tmainform.lboptionhost.caption msgid "Host" msgstr "Host" @@ -1188,7 +1226,7 @@ msgstr "" "%ARTIST% : Seniman\n" "\n" "Catatan:\n" -"Nama folder harus memiliki setidaknya %MANGA%\n" +"Nama folder komik setidaknya harus meiliki %MANGA%\n" #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time (Max: 8)" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index a498858b1..c74c73f55 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -510,7 +510,12 @@ msgstr "" msgid "Enable load manga cover" msgstr "" -#: tmainform.cboptiongeneratemangafoldername.caption +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "TMAINFORM.CBOPTIONGENERATEMANGAFOLDER.CAPTION" msgid "Auto generate folder based on manga's name" msgstr "" @@ -934,6 +939,11 @@ msgctxt "TMAINFORM.EDOPTIONEXTERNALPATH.TEXTHINT" msgid "External program path" msgstr "" +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "TMAINFORM.EDOPTIONFILENAMECUSTOMRENAME.TEXTHINT" +msgid "Custom rename" +msgstr "" + #: tmainform.edoptionhost.texthint msgid "Proxy host/IP" msgstr "" @@ -1062,6 +1072,11 @@ msgctxt "TMAINFORM.LBOPTIONAUTOCHECKFAVINTERVALMINUTES.CAPTION" msgid "Auto check for new chapter every %d minutes" msgstr "" +#: tmainform.lboptionchaptercustomrename.caption +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAME.CAPTION" +msgid "Chapter name:" +msgstr "" + #: tmainform.lboptionchaptercustomrenamehint.caption msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.CAPTION" msgid "[?]" @@ -1085,10 +1100,6 @@ msgstr "" msgid "Connection timeout (seconds)" msgstr "" -#: tmainform.lboptioncustomrename.caption -msgid "Chapter folder name:" -msgstr "" - #: tmainform.lboptionexternal.caption msgid "Open manga by using external program:" msgstr "" @@ -1102,6 +1113,26 @@ msgctxt "TMAINFORM.LBOPTIONEXTERNALPARAMSHINT.CAPTION" msgid "[?]" msgstr "" +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "TMAINFORM.LBOPTIONFILENAMECUSTOMRENAMEHINT.CAPTION" +msgid "[?]" +msgstr "" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" + #: tmainform.lboptionhost.caption msgid "Host" msgstr "" From 3864e474d85f182a7b35f38fd46668c8276ed589 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Jun 2016 16:59:37 +0800 Subject: [PATCH 1199/2794] store convert volume and chapter digit to fmdoptions for easy access --- baseunits/FMDOptions.pas | 5 +++++ baseunits/uBaseUnit.pas | 22 +++++++++++----------- mangadownloader/forms/frmMain.pas | 4 ++++ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 4ebfe0ff2..26eae8447 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -97,6 +97,11 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionChapterCustomRename: String; OptionFilenameCustomRename: String; + OptionConvertDigitVolume: Boolean; + OptionConvertDigitChapter: Boolean; + OptionConvertDigitVolumeLength: Integer; + OptionConvertDigitChapterLength: Integer; + OptionPDFQuality: Cardinal = 95; OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e9631ac23..68040a2c3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2130,17 +2130,17 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh Result := StringReplaceBrackets(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); // pad number chap := Trim(AChapter); - with configfile do begin - if ReadBool('saveto', 'ConvertDigitVolume', False) then begin - if ReadBool('saveto', 'ConvertDigitChapter', False) then - VolumeChapterPadZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), - ReadInteger('saveto', 'DigitChapterLength', 3)) - else - VolumeChapterPadZero(chap, ReadInteger('saveto', 'DigitVolumeLength', 2), 0); - end - else if ReadBool('saveto', 'ConvertDigitChapter', False) then - VolumeChapterPadZero(chap, 0, ReadInteger('saveto', 'DigitChapterLength', 3)); - end; + if OptionConvertDigitVolume then + begin + if OptionConvertDigitChapter then + VolumeChapterPadZero(chap, OptionConvertDigitVolumeLength, OptionConvertDigitChapterLength) + else + VolumeChapterPadZero(chap, OptionConvertDigitVolumeLength, 0); + end + else + if OptionConvertDigitChapter then + VolumeChapterPadZero(chap, 0, OptionConvertDigitChapterLength); + Result := StringReplaceBrackets(Result, '%CHAPTER%', chap, [rfReplaceAll]); if Result = '' then begin diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3f8dcac30..58b77061b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4507,6 +4507,10 @@ procedure TMainForm.ApplyOptions; OptionGenerateChapterFolder := cbOptionGenerateChapterFolder.Checked; OptionChapterCustomRename := edOptionChapterCustomRename.Text; OptionFilenameCustomRename := edOptionFilenameCustomRename.Text; + OptionConvertDigitVolume := cbOptionDigitVolume.Checked; + OptionConvertDigitVolumeLength := seOptionDigitVolume.Value; + OptionConvertDigitChapter := cbOptionDigitChapter.Checked; + OptionConvertDigitChapterLength := seOptionDigitChapter.Value; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; From a98b0323ab61abc33280f6beb4ad538147ce492f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Jun 2016 07:13:12 +0800 Subject: [PATCH 1200/2794] frmmain, added popup menu to change all filter genre checkbox state #268 --- mangadownloader/forms/frmMain.lfm | 55 ++++++++++++++++++++++++++ mangadownloader/forms/frmMain.pas | 34 ++++++++++++++++ mangadownloader/languages/fmd.en.po | 16 ++++++++ mangadownloader/languages/fmd.id_ID.po | 16 ++++++++ mangadownloader/languages/fmd.po | 16 ++++++++ 5 files changed, 137 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index bb463579e..e05b238cd 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1032,6 +1032,7 @@ object MainForm: TMainForm ChildSizing.ControlsPerLine = 8 ClientHeight = 180 ClientWidth = 542 + PopupMenu = pmFilterGenreAll TabOrder = 0 object ckFilterAction: TCheckBox Left = 0 @@ -1043,6 +1044,7 @@ object MainForm: TMainForm Caption = 'Action' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 0 end @@ -1056,6 +1058,7 @@ object MainForm: TMainForm Caption = 'Adult' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 1 end @@ -1069,6 +1072,7 @@ object MainForm: TMainForm Caption = 'Adventure' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 2 end @@ -1082,6 +1086,7 @@ object MainForm: TMainForm Caption = 'Comedy' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 3 end @@ -1095,6 +1100,7 @@ object MainForm: TMainForm Caption = 'Doujinshi' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 4 end @@ -1108,6 +1114,7 @@ object MainForm: TMainForm Caption = 'Drama' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 5 end @@ -1121,6 +1128,7 @@ object MainForm: TMainForm Caption = 'Ecchi' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 6 end @@ -1134,6 +1142,7 @@ object MainForm: TMainForm Caption = 'Fantasy' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 7 end @@ -1147,6 +1156,7 @@ object MainForm: TMainForm Caption = 'Gender Bender' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 8 end @@ -1160,6 +1170,7 @@ object MainForm: TMainForm Caption = 'Harem' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 9 end @@ -1173,6 +1184,7 @@ object MainForm: TMainForm Caption = 'Hentai' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 10 end @@ -1186,6 +1198,7 @@ object MainForm: TMainForm Caption = 'Historical' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 11 end @@ -1199,6 +1212,7 @@ object MainForm: TMainForm Caption = 'Horror' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 12 end @@ -1212,6 +1226,7 @@ object MainForm: TMainForm Caption = 'Josei' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 13 end @@ -1225,6 +1240,7 @@ object MainForm: TMainForm Caption = 'Lolicon' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 14 end @@ -1238,6 +1254,7 @@ object MainForm: TMainForm Caption = 'Martial Arts' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 15 end @@ -1251,6 +1268,7 @@ object MainForm: TMainForm Caption = 'Mature' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 16 end @@ -1264,6 +1282,7 @@ object MainForm: TMainForm Caption = 'Mecha' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 17 end @@ -1277,6 +1296,7 @@ object MainForm: TMainForm Caption = 'Musical' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 18 end @@ -1290,6 +1310,7 @@ object MainForm: TMainForm Caption = 'Mystery' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 19 end @@ -1303,6 +1324,7 @@ object MainForm: TMainForm Caption = 'Psychological' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 20 end @@ -1316,6 +1338,7 @@ object MainForm: TMainForm Caption = 'Romance' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 21 end @@ -1329,6 +1352,7 @@ object MainForm: TMainForm Caption = 'School Life' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 22 end @@ -1342,6 +1366,7 @@ object MainForm: TMainForm Caption = 'Sci-Fi' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 23 end @@ -1355,6 +1380,7 @@ object MainForm: TMainForm Caption = 'Seinen' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 24 end @@ -1368,6 +1394,7 @@ object MainForm: TMainForm Caption = 'Shotacon' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 25 end @@ -1381,6 +1408,7 @@ object MainForm: TMainForm Caption = 'Shoujo' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 26 end @@ -1394,6 +1422,7 @@ object MainForm: TMainForm Caption = 'Shoujo Ai' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 27 end @@ -1407,6 +1436,7 @@ object MainForm: TMainForm Caption = 'Shounen' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 28 end @@ -1420,6 +1450,7 @@ object MainForm: TMainForm Caption = 'Shounen Ai' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 29 end @@ -1433,6 +1464,7 @@ object MainForm: TMainForm Caption = 'Slice of Life' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 30 end @@ -1447,6 +1479,7 @@ object MainForm: TMainForm Caption = 'Smut' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 31 end @@ -1460,6 +1493,7 @@ object MainForm: TMainForm Caption = 'Sports' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 32 end @@ -1473,6 +1507,7 @@ object MainForm: TMainForm Caption = 'Supernatural' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 33 end @@ -1486,6 +1521,7 @@ object MainForm: TMainForm Caption = 'Tragedy' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 34 end @@ -1499,6 +1535,7 @@ object MainForm: TMainForm Caption = 'Yaoi' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 35 end @@ -1512,6 +1549,7 @@ object MainForm: TMainForm Caption = 'Yuri' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 36 end @@ -1525,6 +1563,7 @@ object MainForm: TMainForm Caption = 'Weebtoons' ParentFont = False ParentShowHint = False + PopupMenu = pmFilterGenreAll ShowHint = True TabOrder = 37 end @@ -6320,4 +6359,20 @@ object MainForm: TMainForm OnClick = miAbortSilentThreadClick end end + object pmFilterGenreAll: TPopupMenu + left = 520 + top = 168 + object mnFilterGenreAllCheck: TMenuItem + Caption = 'Check all' + OnClick = mnFilterGenreAllCheckClick + end + object mnFilterGenreAllUncheck: TMenuItem + Caption = 'Uncheck all' + OnClick = mnFilterGenreAllUncheckClick + end + object mnFilterGenreAllIndeterminate: TMenuItem + Caption = 'Indeterminate all' + OnClick = mnFilterGenreAllIndeterminateClick + end + end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 58b77061b..bafc9c7d5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -72,6 +72,9 @@ TMainForm = class(TForm) lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; + mnFilterGenreAllIndeterminate: TMenuItem; + mnFilterGenreAllCheck: TMenuItem; + mnFilterGenreAllUncheck: TMenuItem; miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; @@ -82,6 +85,7 @@ TMainForm = class(TForm) Panel8: TPanel; pcAbout: TPageControl; pmSbMain: TPopupMenu; + pmFilterGenreAll: TPopupMenu; sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; tsWebsiteAdvanced: TTabSheet; @@ -441,6 +445,9 @@ TMainForm = class(TForm) procedure miFavoritesOpenWithClick(Sender: TObject); procedure miDownloadOpenWithClick(Sender: TObject); procedure mnDownload1ClickClick(Sender: TObject); + procedure mnFilterGenreAllCheckClick(Sender: TObject); + procedure mnFilterGenreAllIndeterminateClick(Sender: TObject); + procedure mnFilterGenreAllUncheckClick(Sender: TObject); procedure mnUpdate1ClickClick(Sender: TObject); procedure mnUpdateDownFromServerClick(Sender: TObject); procedure mnUpdateListClick(Sender: TObject); @@ -660,6 +667,9 @@ TMainForm = class(TForm) // search db with thread procedure SearchDataDB(const ATitle: String); + // change all filter genre checkbox state + procedure FilterGenreChangeAllState(const AState: TCheckBoxState); + // exception handle procedure ExceptionHandler(Sender: TObject; E: Exception); { public declarations } @@ -1367,6 +1377,15 @@ procedure TMainForm.SearchDataDB(const ATitle: String); end; end; +procedure TMainForm.FilterGenreChangeAllState(const AState: TCheckBoxState); +var + i: Integer; +begin + for i := 0 to pnGenres.ControlCount - 1 do + if pnGenres.Controls[i] is TCheckBox then + TCheckBox(pnGenres.Controls[i]).State := AState; +end; + procedure TMainForm.itMonitorTimer(Sender: TObject); begin itMonitor.Enabled := False; @@ -2650,6 +2669,21 @@ procedure TMainForm.mnDownload1ClickClick(Sender: TObject); MessageDlg('', RS_DlgFavoritesCheckIsRunning, mtInformation, [mbYes], 0); end; +procedure TMainForm.mnFilterGenreAllCheckClick(Sender: TObject); +begin + FilterGenreChangeAllState(cbChecked); +end; + +procedure TMainForm.mnFilterGenreAllIndeterminateClick(Sender: TObject); +begin + FilterGenreChangeAllState(cbGrayed); +end; + +procedure TMainForm.mnFilterGenreAllUncheckClick(Sender: TObject); +begin + FilterGenreChangeAllState(cbUnchecked); +end; + procedure TMainForm.mnUpdate1ClickClick(Sender: TObject); var i, j, e: Cardinal; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 322535475..da998e252 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1335,6 +1335,7 @@ msgid "Abort" msgstr "Abort" #: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" msgstr "Check all" @@ -1352,6 +1353,7 @@ msgid "Highlight downloaded chapters" msgstr "Highlight downloaded chapters" #: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" msgid "Uncheck all" msgstr "Uncheck all" @@ -1467,6 +1469,20 @@ msgstr "View manga infos" msgid "Download all lists from server at once" msgstr "Download all lists from server at once" +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Check all" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Indeterminate all" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Uncheck all" + #: tmainform.mnupdate1click.caption msgid "Update all lists at once" msgstr "Update all lists at once" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index f2f284d86..2cae7e56b 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1318,6 +1318,7 @@ msgid "Abort" msgstr "Batalkan" #: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" msgstr "Centang semua" @@ -1334,6 +1335,7 @@ msgid "Highlight downloaded chapters" msgstr "Sorot bab terunduh" #: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" msgid "Uncheck all" msgstr "Hapus semua centang" @@ -1449,6 +1451,20 @@ msgstr "Lihat informasi komik" msgid "Download all lists from server at once" msgstr "Unduh semua daftar dari server" +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Centang semua" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Semua tak tentu" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Hapus semua centang" + #: tmainform.mnupdate1click.caption msgid "Update all lists at once" msgstr "Perbarui semua daftar" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c74c73f55..0adf9abce 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1256,6 +1256,7 @@ msgid "Abort" msgstr "" #: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" msgstr "" @@ -1272,6 +1273,7 @@ msgid "Highlight downloaded chapters" msgstr "" #: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" msgid "Uncheck all" msgstr "" @@ -1387,6 +1389,20 @@ msgstr "" msgid "Download all lists from server at once" msgstr "" +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "TMAINFORM.MNFILTERGENREALLCHECK.CAPTION" +msgid "Check all" +msgstr "" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "TMAINFORM.MNFILTERGENREALLUNCHECK.CAPTION" +msgid "Uncheck all" +msgstr "" + #: tmainform.mnupdate1click.caption msgid "Update all lists at once" msgstr "" From 2c52fde81c973de4c5ec5a83eb59fc0c3b46af2d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Jun 2016 16:24:45 +0800 Subject: [PATCH 1201/2794] added chapters filter via popup menu - filter closed #270 --- mangadownloader/forms/frmMain.lfm | 137 +++++++++++++++++++++--------- mangadownloader/forms/frmMain.pas | 54 ++++++++++++ 2 files changed, 152 insertions(+), 39 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e05b238cd..04df76893 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1,11 +1,11 @@ object MainForm: TMainForm Left = 297 - Height = 538 - Top = 115 + Height = 587 + Top = 66 Width = 771 ActiveControl = pcMain Caption = 'Free Manga Downloader' - ClientHeight = 538 + ClientHeight = 587 ClientWidth = 771 OnClose = FormClose OnCreate = FormCreate @@ -17,7 +17,7 @@ object MainForm: TMainForm object sbUpdateList: TStatusBar Left = 0 Height = 30 - Top = 508 + Top = 557 Width = 771 AutoSize = False Panels = < @@ -33,7 +33,7 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 471 + Height = 520 Top = 11 Width = 566 ActivePage = tsDownload @@ -47,11 +47,11 @@ object MainForm: TMainForm OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' - ClientHeight = 443 + ClientHeight = 492 ClientWidth = 558 object vtDownload: TVirtualStringTree Left = 4 - Height = 407 + Height = 456 Top = 32 Width = 550 Align = alClient @@ -260,34 +260,34 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 443 + ClientHeight = 492 ClientWidth = 558 object sbInformation: TScrollBox Left = 0 - Height = 443 + Height = 492 Top = 0 Width = 558 HorzScrollBar.Page = 327 - VertScrollBar.Page = 433 + VertScrollBar.Page = 482 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 443 + ClientHeight = 492 ClientWidth = 558 TabOrder = 0 object pnInfomation: TPanel Left = 4 - Height = 262 + Height = 248 Top = 8 Width = 550 Align = alTop BevelOuter = bvNone ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 262 + ClientHeight = 248 ClientWidth = 550 ParentFont = False TabOrder = 0 @@ -299,7 +299,7 @@ object MainForm: TMainForm AnchorSideRight.Control = edURL AnchorSideRight.Side = asrBottom Left = 158 - Height = 233 + Height = 219 Top = 27 Width = 392 Anchors = [akTop, akLeft, akRight, akBottom] @@ -413,28 +413,28 @@ object MainForm: TMainForm Cursor = crVSplit Left = 4 Height = 5 - Top = 274 + Top = 260 Width = 550 Align = alTop ResizeAnchor = akTop end object pnChapterList: TPanel Left = 4 - Height = 152 - Top = 283 + Height = 215 + Top = 269 Width = 550 Align = alClient BevelOuter = bvNone ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 152 + ClientHeight = 215 ClientWidth = 550 TabOrder = 2 object clbChapterList: TVirtualStringTree - AnchorSideTop.Side = asrBottom + AnchorSideTop.Control = edFilterMangaInfoChapters AnchorSideBottom.Control = lbSaveTo Left = 0 - Height = 73 + Height = 136 Top = 0 Width = 516 Anchors = [akTop, akLeft, akRight, akBottom] @@ -465,7 +465,7 @@ object MainForm: TMainForm AnchorSideBottom.Side = asrBottom Left = 338 Height = 26 - Top = 96 + Top = 159 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True @@ -517,7 +517,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 0 Height = 19 - Top = 123 + Top = 186 Width = 334 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' @@ -531,7 +531,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 442 Height = 26 - Top = 96 + Top = 159 Width = 108 Anchors = [akRight, akBottom] AutoSize = True @@ -629,7 +629,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 338 Height = 26 - Top = 126 + Top = 189 Width = 212 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True @@ -680,7 +680,7 @@ object MainForm: TMainForm AnchorSideBottom.Control = edSaveTo Left = 0 Height = 15 - Top = 77 + Top = 140 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' @@ -693,7 +693,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btDownload Left = 0 Height = 23 - Top = 96 + Top = 159 Width = 334 OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False @@ -741,6 +741,57 @@ object MainForm: TMainForm TabOrder = 5 TextHint = 'Save to' end + object edFilterMangaInfoChapters: TEditButton + Left = 0 + Height = 23 + Top = 0 + Width = 250 + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edFilterMangaInfoChaptersButtonClick + OnChange = edFilterMangaInfoChaptersChange + PasswordChar = #0 + TabOrder = 6 + TextHint = 'Filter' + Visible = False + end end end end @@ -1944,11 +1995,11 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 443 + ClientHeight = 492 ClientWidth = 558 object pnOptions: TPageControl Left = 8 - Height = 366 + Height = 415 Top = 8 Width = 539 ActivePage = tsGeneral @@ -1962,7 +2013,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 338 + ClientHeight = 387 ClientWidth = 531 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime @@ -3229,11 +3280,11 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 387 ClientWidth = 531 object pcWebsiteOptions: TPageControl Left = 4 - Height = 376 + Height = 371 Top = 8 Width = 523 ActivePage = tsWebsiteSelection @@ -3242,11 +3293,11 @@ object MainForm: TMainForm TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' - ClientHeight = 348 + ClientHeight = 343 ClientWidth = 515 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 0 - Height = 313 + Height = 308 Top = 35 Width = 515 Align = alClient @@ -3430,7 +3481,7 @@ object MainForm: TMainForm object btOptionApply: TBitBtn Left = 8 Height = 45 - Top = 385 + Top = 434 Width = 125 Anchors = [akLeft, akBottom] AutoSize = True @@ -3692,7 +3743,7 @@ object MainForm: TMainForm end object pcLeft: TPageControl Left = 4 - Height = 469 + Height = 518 Top = 12 Width = 195 ActivePage = tsMangaList @@ -3709,7 +3760,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 441 + ClientHeight = 490 ClientWidth = 187 object vtMangaList: TVirtualStringTree AnchorSideLeft.Control = lbMode @@ -3718,7 +3769,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btRemoveFilter AnchorSideRight.Side = asrBottom Left = 4 - Height = 352 + Height = 401 Top = 85 Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] @@ -4019,7 +4070,7 @@ object MainForm: TMainForm object sbMain: TStatusBar Left = 0 Height = 23 - Top = 485 + Top = 534 Width = 771 Panels = < item @@ -4033,7 +4084,7 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 477 + Height = 526 Top = 8 Width = 2 OnMoved = spMainSplitterMoved @@ -4395,6 +4446,14 @@ object MainForm: TMainForm Caption = 'Hide downloaded chapters' OnClick = miChapterListHideDownloadedClick end + object MenuItem2: TMenuItem + Caption = '-' + end + object miChapterListFilter: TMenuItem + AutoCheck = True + Caption = 'Filter' + OnClick = miChapterListFilterClick + end end object pmFavorites: TPopupMenu Images = IconList diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bafc9c7d5..d756b02f1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -63,6 +63,7 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + edFilterMangaInfoChapters: TEditButton; edOptionFilenameCustomRename: TEdit; edOptionDefaultPath: TDirectoryEdit; edOptionMangaCustomRename: TEdit; @@ -72,6 +73,8 @@ TMainForm = class(TForm) lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; + MenuItem2: TMenuItem; + miChapterListFilter: TMenuItem; mnFilterGenreAllIndeterminate: TMenuItem; mnFilterGenreAllCheck: TMenuItem; mnFilterGenreAllUncheck: TMenuItem; @@ -377,6 +380,8 @@ TMainForm = class(TForm) var CellText: String); procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure edFilterMangaInfoChaptersButtonClick(Sender: TObject); + procedure edFilterMangaInfoChaptersChange(Sender: TObject); procedure edSaveToAcceptDirectory(Sender: TObject; var Value: String); procedure edSearchChange(Sender: TObject); procedure edSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState @@ -414,6 +419,7 @@ TMainForm = class(TForm) procedure medURLSelectAllClick(Sender: TObject); procedure medURLUndoClick(Sender: TObject); procedure miAbortSilentThreadClick(Sender: TObject); + procedure miChapterListFilterClick(Sender: TObject); procedure miChapterListHideDownloadedClick(Sender: TObject); procedure miDownloadViewMangaInfoClick(Sender: TObject); procedure miChapterListHighlightClick(Sender: TObject); @@ -1506,6 +1512,24 @@ procedure TMainForm.miAbortSilentThreadClick(Sender: TObject); SilentThreadManager.StopAll(False); end; +procedure TMainForm.miChapterListFilterClick(Sender: TObject); +begin + edFilterMangaInfoChapters.Visible := miChapterListFilter.Checked; + if edFilterMangaInfoChapters.Visible then + begin + clbChapterList.AnchorSide[akTop].Control := edFilterMangaInfoChapters; + clbChapterList.AnchorSide[akTop].Side := asrBottom; + edFilterMangaInfoChapters.SetFocus; + end + else + begin + edFilterMangaInfoChapters.Clear; + clbChapterList.AnchorSide[akTop].Control := nil; + clbChapterList.AnchorSide[akTop].Side := asrTop; + clbChapterList.Top := 0; + end; +end; + procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); var xnode: PVirtualNode; @@ -2255,6 +2279,35 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; +procedure TMainForm.edFilterMangaInfoChaptersButtonClick(Sender: TObject); +begin + edFilterMangaInfoChapters.Clear; +end; + +procedure TMainForm.edFilterMangaInfoChaptersChange(Sender: TObject); +var + Node: PVirtualNode; + s: String; +begin + if clbChapterList.RootNodeCount = 0 then Exit; + s := LowerCase(edFilterMangaInfoChapters.Text); + clbChapterList.BeginUpdate; + try + Node := clbChapterList.GetFirst(); + while Assigned(Node) do + begin + if s <> '' then + clbChapterList.IsVisible[Node] := + Pos(s, LowerCase(ChapterList[Node^.Index].Title)) <> 0 + else + clbChapterList.IsVisible[Node] := True; + Node := clbChapterList.GetNext(Node); + end; + finally + clbChapterList.EndUpdate; + end; +end; + procedure TMainForm.edSaveToAcceptDirectory(Sender: TObject; var Value: String); begin Value := CleanAndExpandDirectory(Value); @@ -4196,6 +4249,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); miChapterListHighlightClick(nil); UpdateVtChapter; miChapterListHideDownloadedClick(nil); + edFilterMangaInfoChaptersChange(nil); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); btReadOnline.Enabled := (mangaInfo.link <> ''); From 8ca6b6ba67555e1405b56560cdea278ef66cbf36 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Jun 2016 16:37:30 +0800 Subject: [PATCH 1202/2794] update translations --- mangadownloader/languages/fmd.en.po | 10 ++++++++++ mangadownloader/languages/fmd.id_ID.po | 10 ++++++++++ mangadownloader/languages/fmd.po | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index da998e252..a006f64f3 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -951,6 +951,11 @@ msgctxt "tmainform.edfilterauthors.texthint" msgid "Author" msgstr "Author" +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Filter" + #: tmainform.edfiltersummary.texthint msgid "Part of summary" msgstr "Part of summary" @@ -1343,6 +1348,11 @@ msgstr "Check all" msgid "Check selected" msgstr "Check selected" +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Filter" + #: tmainform.michapterlisthidedownloaded.caption msgid "Hide downloaded chapters" msgstr "Hide downloaded chapters" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 2cae7e56b..030920b7b 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -941,6 +941,11 @@ msgctxt "tmainform.edfilterauthors.texthint" msgid "Author" msgstr "Penulis" +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Saring" + #: tmainform.edfiltersummary.texthint msgid "Part of summary" msgstr "Bagian dari ringkasan" @@ -1326,6 +1331,11 @@ msgstr "Centang semua" msgid "Check selected" msgstr "Centang yang dipilih" +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Saring" + #: tmainform.michapterlisthidedownloaded.caption msgid "Hide downloaded chapters" msgstr "Sembunyikan bab terunduh" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 0adf9abce..1bd2e408d 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -911,6 +911,11 @@ msgctxt "tmainform.edfilterauthors.texthint" msgid "Author" msgstr "" +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "TMAINFORM.EDFILTERMANGAINFOCHAPTERS.TEXTHINT" +msgid "Filter" +msgstr "" + #: tmainform.edfiltersummary.texthint msgid "Part of summary" msgstr "" @@ -1264,6 +1269,11 @@ msgstr "" msgid "Check selected" msgstr "" +#: tmainform.michapterlistfilter.caption +msgctxt "TMAINFORM.MICHAPTERLISTFILTER.CAPTION" +msgid "Filter" +msgstr "" + #: tmainform.michapterlisthidedownloaded.caption msgid "Hide downloaded chapters" msgstr "" From 4f147cc74d7b99ebc7fbf0b3395b39f8bdd04e3f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Jun 2016 17:03:02 +0800 Subject: [PATCH 1203/2794] frmmain, fixed filter chapter list with hidedownloaded --- mangadownloader/forms/frmMain.pas | 65 +++++++++++++------------------ 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d756b02f1..53c103996 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -676,6 +676,9 @@ TMainForm = class(TForm) // change all filter genre checkbox state procedure FilterGenreChangeAllState(const AState: TCheckBoxState); + // filter chapter list + procedure FilterChapterList(const SearchStr: String; const HideDownloaded: Boolean); + // exception handle procedure ExceptionHandler(Sender: TObject; E: Exception); { public declarations } @@ -1392,6 +1395,28 @@ procedure TMainForm.FilterGenreChangeAllState(const AState: TCheckBoxState); TCheckBox(pnGenres.Controls[i]).State := AState; end; +procedure TMainForm.FilterChapterList(const SearchStr: String; + const HideDownloaded: Boolean); +var + xNode: PVirtualNode; + s: String; + isShow: Boolean; +begin + if clbChapterList.RootNodeCount = 0 then Exit; + xNode := clbChapterList.GetFirst(); + s := lowerCase(SearchStr); + while Assigned(xNode) do + begin + isShow := True; + if HideDownloaded then + isShow := not ChapterList[xNode^.Index].Downloaded; + if isShow and (s <> '') then + isShow := Pos(s, LowerCase(ChapterList[xNode^.Index].Title)) <> 0; + clbChapterList.IsVisible[xNode] := isShow; + xNode := clbChapterList.GetNext(xNode); + end; +end; + procedure TMainForm.itMonitorTimer(Sender: TObject); begin itMonitor.Enabled := False; @@ -1531,29 +1556,14 @@ procedure TMainForm.miChapterListFilterClick(Sender: TObject); end; procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); -var - xnode: PVirtualNode; begin if Sender = miChapterListHideDownloaded then begin miChapterListHideDownloaded.Checked := not miChapterListHideDownloaded.Checked; configfile.WriteBool('general', 'ChapterListHideDownloaded', miChapterListHideDownloaded.Checked); end; - if (Length(ChapterList) = 0) or (Length(ChapterList) <> clbChapterList.RootNodeCount) then Exit; - clbChapterList.BeginUpdate; - try - xnode := clbChapterList.GetFirst; - while Assigned (xnode) do - begin - if miChapterListHideDownloaded.Checked and ChapterList[xnode^.Index].Downloaded then - Exclude(xnode^.States, vsVisible) - else - Include(xnode^.States, vsVisible); - xnode := clbChapterList.GetNext(xnode); - end; - finally - clbChapterList.EndUpdate; - end; + + FilterChapterList(edFilterMangaInfoChapters.Text, miChapterListHideDownloaded.Checked); end; procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); @@ -2285,27 +2295,8 @@ procedure TMainForm.edFilterMangaInfoChaptersButtonClick(Sender: TObject); end; procedure TMainForm.edFilterMangaInfoChaptersChange(Sender: TObject); -var - Node: PVirtualNode; - s: String; begin - if clbChapterList.RootNodeCount = 0 then Exit; - s := LowerCase(edFilterMangaInfoChapters.Text); - clbChapterList.BeginUpdate; - try - Node := clbChapterList.GetFirst(); - while Assigned(Node) do - begin - if s <> '' then - clbChapterList.IsVisible[Node] := - Pos(s, LowerCase(ChapterList[Node^.Index].Title)) <> 0 - else - clbChapterList.IsVisible[Node] := True; - Node := clbChapterList.GetNext(Node); - end; - finally - clbChapterList.EndUpdate; - end; + FilterChapterList(edFilterMangaInfoChapters.Text, miChapterListHideDownloaded.Checked); end; procedure TMainForm.edSaveToAcceptDirectory(Sender: TObject; var Value: String); From 474c3d6c22bfb2f7436b2c8e1efc086814107fff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Jun 2016 11:16:17 +0800 Subject: [PATCH 1204/2794] baseunit, fixed correctpathsys allways append pathdelim --- baseunits/uBaseUnit.pas | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 68040a2c3..856aa3893 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -483,6 +483,11 @@ interface MangaInfo_StatusCompleted = '0'; MangaInfo_StatusOngoing = '1'; + {$ifdef windows} + // MAX_PATH(260) - 12 - 1 + MAX_PATH_LENGTH = 247; + {$endif} + var // Sites var BROWSER_INVERT: Boolean = False; @@ -1867,9 +1872,12 @@ function CorrectPathSys(const Path: String): String; begin Result := CleanAndExpandDirectory(GetForcedPathDelims(Path)); {$IFDEF WINDOWS} - //max length = 247 (MAX_PATH(260) - 12 - 1) - if Length(Result) > 247 then - SetLength(Result, 247); + if Length(Result) > MAX_PATH_LENGTH then + begin + SetLength(Result, MAX_PATH_LENGTH); + if Result[MAX_PATH_LENGTH] <> PathDelim then + Result[MAX_PATH_LENGTH] := PathDelim; + end; {$ENDIF} end; From 5b05a1df220f5249b6aca7850c41c3345df88d76 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Jun 2016 13:38:35 +0800 Subject: [PATCH 1205/2794] fixed open folder and open with --- baseunits/uBaseUnit.pas | 32 +++--- mangadownloader/forms/frmMain.pas | 180 +++++++++++++++--------------- 2 files changed, 106 insertions(+), 106 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 856aa3893..febba44c9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -483,6 +483,8 @@ interface MangaInfo_StatusCompleted = '0'; MangaInfo_StatusOngoing = '1'; + FMDSupportedOutputExt: array[0..2] of string = ('.zip', '.cbz', '.pdf'); + {$ifdef windows} // MAX_PATH(260) - 12 - 1 MAX_PATH_LENGTH = 247; @@ -736,7 +738,7 @@ function RemoveURLDelim(const URL: String): String; inline; function RemoveURLDelimLeft(const URL: String): String; inline; function FixURL(const URL: String): String; function FixPath(const path: String): String; -function GetLastDir(const path: String): String; +function GetLastDir(const Dir: String): String; function StringFilter(const Source: String): String; function HTMLEntitiesFilter(const Source: String): String; function CommonStringFilter(const Source: String): String; @@ -2494,24 +2496,24 @@ function FixPath(const path: String): String; end; end; -function GetLastDir(const path: String): String; +function GetLastDir(const Dir: String): String; var - i: Cardinal; s: String; + i: Integer; begin Result := ''; - if Length(path) = 0 then - Exit; - s := path; - while s[Length(s)] in ['/', '\'] do - SetLength(s, Length(s) - 1); - i := Length(s); - for i := 1 to Length(s) do - begin - Result := Result + s[i]; - if (s[i] in ['/', '\']) and (i < Length(s)) then - Result := ''; - end; + s := Trim(Dir); + if s = '' then Exit; + s := TrimRightChar(s, AllowDirectorySeparators); + if s <> '' then + for i := Length(s) downto 1 do + if s[i] in AllowDirectorySeparators then + begin + Result := Copy(s, i + 1, Length(s) - i); + Break; + end; + if Result = '' then + Result := s; end; function StringFilter(const Source: String): String; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 53c103996..97e729780 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -657,7 +657,9 @@ TMainForm = class(TForm) procedure ApplyLanguage; // openwith - procedure OpenWithExternalProgram(const dirPath, Filename: String); + procedure OpenWithExternalProgramChapters(const Dir: String; + const Chapters: TStrings = nil); + procedure OpenWithExternalProgram(const Dir, Filename: String); // transfer rate graph procedure TransferRateGraphInit(xCount: Integer = 10); @@ -2996,97 +2998,30 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); begin - if not Assigned(vtFavorites.FocusedNode) then - Exit; - OpenDocument(TrimRightChar( - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo, - [PathDelim])); + if Assigned(vtFavorites.FocusedNode) then + OpenDocument(ChompPathDelim( + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); end; procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); begin - if (vtDownload.SelectedCount = 0) or (Assigned(vtDownload.FocusedNode) = False) then - Exit; - OpenDocument(ChompPathDelim(DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo)); + if Assigned(vtDownload.FocusedNode) then + OpenDocument(ChompPathDelim( + DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo)); end; procedure TMainForm.miFavoritesOpenWithClick(Sender: TObject); -var - f, fd: String; - Info: TSearchRec; - l: TStringList; begin - if (not Assigned(vtFavorites.FocusedNode)) then - Exit; - l := TStringList.Create; - try - fd := StringReplace(FavoriteManager.Items[ - vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo, '/', '\', [rfReplaceAll]); - if fd[Length(fd)] <> PathDelim then - fd := fd + PathDelim; - - if FindFirstUTF8(fd + '*', faAnyFile and faDirectory, Info) = 0 then - repeat - l.Add(Info.Name); - until FindNextUTF8(Info) <> 0; - if l.Count >= 3 then - f := l.Strings[2] - else - f := ''; - FindCloseUTF8(Info); - - OpenWithExternalProgram(fd, f); - except - end; - l.Free; + if Assigned(vtFavorites.FocusedNode) then + OpenWithExternalProgramChapters( + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); end; procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); -var - f, fd, ff: String; - Info: TSearchRec; - l: TStringList; - task: TTaskContainer; begin - if (not Assigned(vtDownload.FocusedNode)) then - Exit; - task := DLManager.Items[vtDownload.FocusedNode^.Index]; - l := TStringList.Create; - try - fd := task.DownloadInfo.SaveTo; - - if task.ChapterName.Count > 0 then - begin - ff := task.ChapterName[0]; - if FileExistsUTF8(fd + ff + '.zip') then - f := ff + '.zip' - else if FileExistsUTF8(fd + ff + '.cbz') then - f := ff + '.cbz' - else if FileExistsUTF8(fd + ff + '.pdf') then - f := ff + '.pdf' - else if DirectoryExistsUTF8(fd + ff) then - f := ff - else - f := ''; - end; - - if f = '' then - begin - if FindFirstUTF8(fd + '*', faAnyFile and faDirectory, Info) = 0 then - repeat - l.Add(Info.Name); - until FindNextUTF8(Info) <> 0; - if l.Count >= 3 then - f := l.Strings[2] - else - f := ''; - FindCloseUTF8(Info); - end; - - OpenWithExternalProgram(fd, f); - except - end; - l.Free; + if Assigned(vtDownload.FocusedNode) then + with DLManager.Items[vtDownload.FocusedNode^.Index] do + OpenWithExternalProgramChapters(DownloadInfo.SaveTo, ChapterName); end; procedure TMainForm.pcMainChange(Sender: TObject); @@ -5041,30 +4976,93 @@ procedure TMainForm.ApplyLanguage; end; end; -procedure TMainForm.OpenWithExternalProgram(const dirPath, Filename: String); +procedure TMainForm.OpenWithExternalProgramChapters(const Dir: String; + const Chapters: TStrings); + + function FindSupportedOutputExt(const Dir, Filename: String): String; + var + i: Integer; + ADir, SDir: String; + begin + Result := ''; + if Filename = '' then Exit; + ADir := CorrectPathSys(Dir); + if not DirectoryExistsUTF8(ADir) then Exit; + for i := Low(FMDSupportedOutputExt) to High(FMDSupportedOutputExt) do + begin + SDir := ChompPathDelim(CorrectPathSys(ADir + Filename)); + if FileExistsUTF8(SDir + FMDSupportedOutputExt[i]) then + begin + Result := GetLastDir(SDir) + FMDSupportedOutputExt[i]; + Break; + end; + end; + if Result = '' then + begin + ADir := CorrectPathSys(ADir + Filename); + if DirectoryExistsUTF8(ADir) then + Result := GetLastDir(ADir); + end; + end; + +var + ADir, AFilename: String; + i: Integer; + FindList: TStringList; + SearchRec: TSearchRec; +begin + if Dir = '' then Exit; + ADir := CorrectPathSys(Dir); + if Assigned(Chapters) then + if Chapters.Count > 0 then + for i := 0 to Chapters.Count - 1 do + begin + AFilename := FindSupportedOutputExt(ADir, Chapters[i]); + if AFilename <> '' then + Break; + end; + + if AFilename = '' then + try + FindList := TStringList.Create; + if FindFirstUTF8(ADir + '*', faAnyFile and faDirectory, SearchRec) = 0 then + repeat + FindList.Add(SearchRec.Name); + until FindNextUTF8(SearchRec) <> 0; + if FindList.Count >= 3 then + AFilename := FindList.Strings[2] + else + AFilename := ''; + FindCloseUTF8(SearchRec); + finally + FindList.Free; + end; + OpenWithExternalProgram(ADir, AFilename); +end; + +procedure TMainForm.OpenWithExternalProgram(const Dir, Filename: String); var - Exe, Params, - p, f: String; + ADir, AParam, Exe, Params: String; begin Exe := Trim(configfile.ReadString('general', 'ExternalProgramPath', '')); Params := Trim(configfile.ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM)); - p := Trim(TrimRightChar(Trim(dirPath), [PathDelim])); - f := Trim(TrimChar(Trim(Filename), [PathDelim])); + ADir := Trim(ChompPathDelim(CorrectPathSys(Dir))); + AParam := Trim(ChompPathDelim(Filename)); if Exe <> '' then begin if (Pos(EXPARAM_PATH + EXPARAM_CHAPTER, Params) <> 0) then - f := PathDelim + f; - Params := StringReplace(Params, EXPARAM_PATH, p, [rfIgnoreCase, rfReplaceAll]); - Params := StringReplace(Params, EXPARAM_CHAPTER, f, [rfIgnoreCase, rfReplaceAll]); + AParam := PathDelim + AParam; + Params := StringReplace(Params, EXPARAM_PATH, ADir, [rfIgnoreCase, rfReplaceAll]); + Params := StringReplace(Params, EXPARAM_CHAPTER, AParam, [rfIgnoreCase, rfReplaceAll]); RunExternalProcess(Exe, Params, True, False); end else begin - if (p <> '') and (f <> '') then - f := p + PathDelim + f; - OpenDocument(f); + if (ADir <> '') and (AParam <> '') then + AParam := ADir + PathDelim + AParam; + OpenDocument(AParam); end; end; From 97c3c3175c3a6e2144c54a7b285fc0f3b3e7c421 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Jun 2016 13:45:25 +0800 Subject: [PATCH 1206/2794] frmmain, double click on save to column open folder --- mangadownloader/forms/frmMain.lfm | 10 +++++----- mangadownloader/forms/frmMain.pas | 10 ++++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 04df76893..9a6c24dcb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1790,12 +1790,12 @@ object MainForm: TMainForm end object tsFavorites: TTabSheet Caption = 'Favorites' - ClientHeight = 462 + ClientHeight = 492 ClientWidth = 558 object btFavoritesCheckNewChapter: TBitBtn Left = 33 Height = 40 - Top = 382 + Top = 412 Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Check for new chapter' @@ -1840,7 +1840,7 @@ object MainForm: TMainForm end object vtFavorites: TVirtualStringTree Left = 4 - Height = 371 + Height = 401 Top = 4 Width = 550 Align = alTop @@ -1903,7 +1903,7 @@ object MainForm: TMainForm object btFavoritesImport: TBitBtn Left = 33 Height = 24 - Top = 428 + Top = 458 Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Import list' @@ -1950,7 +1950,7 @@ object MainForm: TMainForm object btCancelFavoritesCheck: TSpeedButton Left = 490 Height = 40 - Top = 382 + Top = 412 Width = 34 Anchors = [akRight, akBottom] Glyph.Data = { diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 97e729780..68c0392ba 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3395,7 +3395,10 @@ procedure TMainForm.vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; procedure TMainForm.vtDownloadColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin - miDownloadOpenWithClick(Sender); + if Column = 5 then + miDownloadOpenFolderClick(Sender) + else + miDownloadOpenWithClick(Sender); end; procedure TMainForm.vtDownloadDragAllowed(Sender : TBaseVirtualTree; @@ -3724,7 +3727,10 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; procedure TMainForm.vtFavoritesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin - miFavoritesOpenWithClick(Sender); + if Column = 4 then + miFavoritesOpenFolderClick(Sender) + else + miFavoritesOpenWithClick(Sender); end; procedure TMainForm.vtFavoritesDragDrop(Sender: TBaseVirtualTree; From 7a80c58f0f1d1488b98fb2f0fe54105641d8f299 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Jun 2016 14:06:06 +0800 Subject: [PATCH 1207/2794] Bump version 0.9.60.0 --- changelog.txt | 11 +++++++++++ update | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index bc28cebaf..fbaaac2d6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,17 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.60.0 (03-06-2016) +[*] ReadComicOnline: fixed domain +[*] Fixed various path issue +[+] Added option for custom filename +[+] Added option to disable auto generate chapter folder +[+] Added popup menu to check/uncheck/indeterminate all genres in filter +[+] Added filter chapter list in mangainfo, activate via popup menu on chapter list +[*] Double click on "Save to" column on download list/favorite list will open folder +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.59.0...0.9.60.0 + 0.9.59.0 (30-05-2016) [+] Added SekaiManga[ES] Full changes: https://github.com/riderkick/FMD/compare/0.9.58.0...0.9.59.0 diff --git a/update b/update index 865ae1edc..fa2a60fc9 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.59.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.59.0/fmd_0.9.59.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.59.0/fmd_0.9.59.0_Win64.7z +VERSION=0.9.60.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.60.0/fmd_0.9.60.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.60.0/fmd_0.9.60.0_Win64.7z From b1e6cbc755a5116ce4d8b056610c964ce6f4549f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Jun 2016 23:30:29 +0800 Subject: [PATCH 1208/2794] mangafox, fixed typo fixed #273 --- baseunits/modules/MangaFox.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index d572bffa7..ef943965d 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -158,7 +158,7 @@ procedure RegisterModule; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; OnAfterImageSaved := @AfterImageSaved; - AddOption(woCheckBox, @removewatermark, 'RemoveWatermak', @RS_RemoveWatermark); + AddOption(woCheckBox, @removewatermark, 'RemoveWatermark', @RS_RemoveWatermark); AddOption(woCheckBox, @saveaspng, 'SaveAsPNG', @RS_SaveAsPNG); end; end; From 6d87a18516b824dc0520caf8190e4665f7f45ec2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Jun 2016 02:03:16 +0800 Subject: [PATCH 1209/2794] cf, fixed sometimes fail, javascript code differ for some website fixed #271 --- baseunits/modules/Cloudflare.pas | 54 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 4b13df9ec..0352937db 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -15,6 +15,9 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; overl implementation +const + MIN_WAIT_TIME = 4000; + function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; begin Result := False; @@ -54,32 +57,34 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; try ModifierG := False; ModifierI := True; - Expression := '^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; - Expression := '^.*setTimeout\(function\(\)\{\s+var t,r,a,f,\s*(\S.+a\.value =.+)\r?\n.*$'; - s := Replace(s, '$1', True); - Expression := '\s{3,}[a-z](\s*=\s*document\.|\.).+;\r?\n'; - s := Replace(s, '', False); - Expression := 't\s=\s*t\.firstChild.href;'; - s := Replace(s, ' t = "' + URL + '";', False); - Expression := 'a\.value\s*='; - s := Replace(s, 'a =', False); - Expression := '^.*\.submit\(.*\},\s*(\d{4,})\).*$'; - OSleepTime := StrToIntDef(Replace(Source, '$1', True), 5000); + + Expression := 'setTimeout\(function\(\)\{\s*var.*\w,\s+(\S.+a\.value =.+)\r?\n'; + Exec(s); + if SubExprMatchCount > 0 then + begin + s := Match[1]; + Expression := '\s{3,}[a-z](\s*=\s*document\.|\.).+;\r?\n'; + s := Replace(s, '', False); + Expression := 't\s=\s*t\.firstChild.href;'; + s := Replace(s, ' t = "' + URL + '";', False); + Expression := 'a\.value\s*='; + s := Replace(s, 'a =', False); + Expression := '^.*\.submit\(.*\},\s*(\d{4,})\).*$'; + OSleepTime := StrToIntDef(Replace(Source, '$1', True), MIN_WAIT_TIME); + + with TBESEN.Create do + try + v := Execute(s); + if v.ValueType = bvtNUMBER then + jschl_answer := FloatToStr(v.Num); + finally + Free; + end; + end; finally Free; end; - with TBESEN.Create do begin - try - v := Execute(s); - if v.ValueType = bvtNUMBER then - jschl_answer := FloatToStr(v.Num); - except - jschl_answer := ''; - end; - Free; - end; - if jschl_answer = '' then Exit; OMethod := meth; OURL := surl + '?jschl_vc=' + jschl_vc + '&pass=' + pass + '&jschl_answer=' + jschl_answer; @@ -101,13 +106,12 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B m := 'GET'; u := ''; h := AppendURLDelim(GetHostURL(AURL)); - st := 5000; + st := MIN_WAIT_TIME; if JSGetAnsweredURL(StreamToString(AHTTP.Document), h, m, u, st) then if (m <> '') and (u <> '') then begin AHTTP.Reset; AHTTP.Headers.Values['Referer'] := ' ' + AURL; - //minimum wait time is 5000 - if st < 5000 then st := 5000; + if st < MIN_WAIT_TIME then st := MIN_WAIT_TIME; Sleep(st); AHTTP.FollowRedirection := False; if AHTTP.HTTPRequest(m, FillHost(h, u)) then From bd8dc0f5232dc13e308c3696f49380aafccbb0f2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Jun 2016 02:32:46 +0800 Subject: [PATCH 1210/2794] thttpsendthread, publish ownerthread and thread terminated --- baseunits/httpsendthread.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 98355f260..d911c5a07 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -28,6 +28,7 @@ THTTPSendThread = class(THTTPSend) function GET(const URL: String; const Response: TObject = nil): Boolean; function POST(const URL: String; const POSTData: String = ''; const Response: TObject = nil): Boolean; function GetCookies: String; + function ThreadTerminated: Boolean; procedure RemoveCookie(const CookieName: String); procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); procedure SetNoProxy; @@ -36,6 +37,7 @@ THTTPSendThread = class(THTTPSend) property RetryCount: Integer read fretrycount write fretrycount; property GZip: Boolean read fgzip write fgzip; property FollowRedirection: Boolean read ffollowredirection write ffollowredirection; + property Thread: TFMDThread read fowner; end; TKeyValuePair = array[0..1] of String; @@ -327,6 +329,13 @@ function THTTPSendThread.GetCookies: String; end; end; +function THTTPSendThread.ThreadTerminated: Boolean; +begin + Result := False; + if Assigned(fowner) then + Result := fowner.IsTerminated; +end; + procedure THTTPSendThread.RemoveCookie(const CookieName: String); var i: Integer; From 682f55cc85c2063437bc15e4590cbd166c7c6535 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Jun 2016 02:39:52 +0800 Subject: [PATCH 1211/2794] cf, fixed can't immediately terminate the owner thread #271 --- baseunits/modules/Cloudflare.pas | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 0352937db..ec98f02e5 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -17,6 +17,7 @@ implementation const MIN_WAIT_TIME = 4000; + MAX_RETRY = 3; function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; begin @@ -94,13 +95,13 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): Boolean; var m, u, h: String; - st, counter: Integer; + st, sc, counter: Integer; begin Result := False; if AHTTP = nil then Exit; if Cookie <> '' then AHTTP.Cookies.Text := Cookie; counter := 0; - while counter < 3 do begin + while counter < MAX_RETRY do begin Inc(counter); if AntiBotActive(AHTTP) then begin m := 'GET'; @@ -112,7 +113,13 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B AHTTP.Reset; AHTTP.Headers.Values['Referer'] := ' ' + AURL; if st < MIN_WAIT_TIME then st := MIN_WAIT_TIME; - Sleep(st); + sc := 0; + while sc < st do begin + if AHTTP.ThreadTerminated then + Exit; + Inc(sc, 500); + Sleep(500); + end; AHTTP.FollowRedirection := False; if AHTTP.HTTPRequest(m, FillHost(h, u)) then Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; @@ -121,7 +128,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B end; end; if Result then Exit - else if counter < 3 then begin + else if counter < MAX_RETRY then begin AHTTP.Reset; Result := AHTTP.GET(AURL); end; @@ -149,7 +156,8 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: Str finally LeaveCriticalsection(CS); end; - Result := AHTTP.GET(AURL); + if not AHTTP.ThreadTerminated then + Result := AHTTP.GET(AURL); end; end; From 6d710c0cd5ee1093e9debfc5b80e9e1abbd1479b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Jun 2016 02:57:10 +0800 Subject: [PATCH 1212/2794] Bump version 0.9.61.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index fbaaac2d6..380ffdf78 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.61.0 (05-06-2016) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.60.0...0.9.61.0 + 0.9.60.0 (03-06-2016) [*] ReadComicOnline: fixed domain [*] Fixed various path issue diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 17d66eaf8..3e6cd55c0 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="60"/> + <RevisionNr Value="61"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index fa2a60fc9..7bc4b082e 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.60.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.60.0/fmd_0.9.60.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.60.0/fmd_0.9.60.0_Win64.7z +VERSION=0.9.61.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.61.0/fmd_0.9.61.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.61.0/fmd_0.9.61.0_Win64.7z From 14f3e2b6944f45d4949a26e713fa2f7419ed61f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Jun 2016 14:25:40 +0800 Subject: [PATCH 1213/2794] baseunit, customrename only remove symbol from params, to be able to use pathdelim to create dir #278 --- baseunits/uBaseUnit.pas | 58 +++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index febba44c9..283b7abad 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2117,10 +2117,22 @@ function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: T function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, ANumbering: String; const ARemoveUnicode: Boolean; const AFilename: String): String; + + function FixStringLocal(const S: String): String; + begin + // fix htmlentities + Result := CommonStringFilter(S); + // remove unaccepted character (Windows) + Result := RemoveSymbols(Result); + // strip unicode character + if ARemoveUnicode then + Result := UnicodeRemove(Result); + end; + var - chap: String; + fchapter: String; begin - Result := Trim(AString); + Result := AString; // for rename chapter only if AChapter <> '' then begin @@ -2138,54 +2150,44 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh end else Result := StringReplaceBrackets(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); + // pad number - chap := Trim(AChapter); + fchapter := Trim(AChapter); if OptionConvertDigitVolume then begin if OptionConvertDigitChapter then - VolumeChapterPadZero(chap, OptionConvertDigitVolumeLength, OptionConvertDigitChapterLength) + VolumeChapterPadZero(fchapter, OptionConvertDigitVolumeLength, OptionConvertDigitChapterLength) else - VolumeChapterPadZero(chap, OptionConvertDigitVolumeLength, 0); + VolumeChapterPadZero(fchapter, OptionConvertDigitVolumeLength, 0); end else if OptionConvertDigitChapter then - VolumeChapterPadZero(chap, 0, OptionConvertDigitChapterLength); + VolumeChapterPadZero(fchapter, 0, OptionConvertDigitChapterLength); - Result := StringReplaceBrackets(Result, '%CHAPTER%', chap, [rfReplaceAll]); + fchapter := FixStringLocal(fchapter); + + Result := StringReplaceBrackets(Result, '%CHAPTER%', fchapter, [rfReplaceAll]); if Result = '' then begin if AWebsite = WebsiteRoots[FAKKU_ID, 0] then - Result := chap + Result := fchapter else Result := ANumbering; end; end; - Result := StringReplaceBrackets(Result, '%WEBSITE%', AWebsite, [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%MANGA%', AMangaName, [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%AUTHOR%', AAuthor, [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%ARTIST%', AArtist, [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%FILENAME%', AFilename, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%WEBSITE%', FixStringLocal(AWebsite), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%MANGA%', FixStringLocal(AMangaName), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%AUTHOR%', FixStringLocal(AAuthor), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%ARTIST%', FixStringLocal(AArtist), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, '%FILENAME%', FixStringLocal(AFilename), [rfReplaceAll]); - if Result = '' then Result := AMangaName; + if Result = '' then Result := FixStringLocal(AMangaName); if Result = '' then Exit; - // strip unicode character - if ARemoveUnicode then - Result := UnicodeRemove(Result); - - // replace htmlentities - Result := HTMLEntitiesFilter(StringFilter(Result)); - - // remove unaccepted character (Windows) - Result := RemoveSymbols(Result); - // remove pathdelim - Result := StringReplace(Result, '/', '', [rfReplaceAll]); - Result := StringReplace(Result, '\', '', [rfReplaceAll]); - - Result := Trim(Result); + Result := TrimChar(Result, AllowDirectorySeparators); end; function GetString(const Source, sStart, sEnd: String): String; From e016362dd9570633ca1193751d1c96096d65e8ec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Jun 2016 14:29:28 +0800 Subject: [PATCH 1214/2794] baseunit, fixed trimchar --- baseunits/uBaseUnit.pas | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 283b7abad..6c6f8a41f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2661,13 +2661,8 @@ function RemoveDoubleSpace(const Source: String): String; function TrimChar(const Source: String; const Chars: TSysCharSet): String; begin - Result := Source; - if Length(Result) > 0 then - while (Length(Result) > 0) and (Result[1] in Chars) do - Delete(Result, 1, 1); - if Length(Result) > 0 then - while (Length(Result) > 0) and (Result[Length(Result)] in Chars) do - Delete(Result, Length(Result), 1); + Result := TrimLeftChar(Source, Chars); + Result := TrimRightChar(Result, Chars); end; function TrimLeftChar(const Source: String; const Chars: TSysCharSet): String; From e7bb4c602692c36bc08235b657da228ba3d898d6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Jun 2016 01:00:36 +0800 Subject: [PATCH 1215/2794] fixed working with folder that ended with dot fixed #279 --- baseunits/uBaseUnit.pas | 16 +++++++++++----- baseunits/uDownloadsManager.pas | 2 ++ baseunits/uPacker.pas | 34 +++++++++++++++++++++++---------- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6c6f8a41f..6a932673e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -726,6 +726,7 @@ function HTMLDecode(const AStr: String): String; function RemoveSymbols(const input: String): String; function CorrectPathSys(const Path: String): String; +function RemovePathDelim(const Path: string): string; function FixWhiteSpace(const S: String): String; function CleanString(const S: String): String; @@ -1872,17 +1873,22 @@ procedure CleanHTMLComments(const Str: TStringList); function CorrectPathSys(const Path: String): String; begin - Result := CleanAndExpandDirectory(GetForcedPathDelims(Path)); {$IFDEF WINDOWS} + Result := RemovePathDelim(CleanAndExpandFilename(GetForcedPathDelims(Path))); + Result := TrimRightChar(Result, ['.']); if Length(Result) > MAX_PATH_LENGTH then - begin SetLength(Result, MAX_PATH_LENGTH); - if Result[MAX_PATH_LENGTH] <> PathDelim then - Result[MAX_PATH_LENGTH] := PathDelim; - end; + Result := AppendPathDelim(Result); + {$ELSE} + Result := CleanAndExpandDirectory(GetForcedPathDelims(Path)); {$ENDIF} end; +function RemovePathDelim(const Path: string): string; +begin + Result := TrimRightChar(Path, AllowDirectorySeparators); +end; + function StringOfString(c: String; l: Integer): String; var i: Integer; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index e4926fab9..e3a663ba6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -871,6 +871,8 @@ procedure TTaskThread.Compress; end; uPacker.CompressionQuality := OptionPDFQuality; uPacker.Path := Container.CurrentWorkingDir; + uPacker.FileName := Container.DownloadInfo.SaveTo + + Container.ChapterName[Container.CurrentDownloadChapterPtr]; uPacker.Execute; except on E: Exception do diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 9c9ff916e..51dac6bab 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -17,18 +17,21 @@ interface type TPackerFormat = (pfZIP, pfCBZ, pfPDF); + { TPacker } + TPacker = class protected - FSavedFilename, FExt: String; + FSavedFileName, FExt: String; FFileList: TStringList; procedure FileFound(FileIterator: TFileIterator); procedure DoZipCbz; procedure DoPdf; public - Path: String; + Path, + FileName: String; Format: TPackerFormat; CompressionQuality: Cardinal; - procedure Execute; + function Execute: Boolean; end; implementation @@ -45,7 +48,7 @@ procedure TPacker.DoZipCbz; with TZipper.Create do try try - FileName := FSavedFilename; + FileName := FSavedFileName; for i := 0 to FFileList.Count - 1 do with Entries.AddFileEntry(FFileList[i]) do begin @@ -84,7 +87,7 @@ procedure TPacker.DoPdf; end; end; - fstream := TFileStreamUTF8.Create(FSavedFilename, fmCreate); + fstream := TFileStreamUTF8.Create(FSavedFileName, fmCreate); try pdf.SaveToStream(fstream); finally @@ -102,8 +105,9 @@ procedure TPacker.DoPdf; end; end; -procedure TPacker.Execute; +function TPacker.Execute: Boolean; begin + Result:=False; Path:=CleanAndExpandDirectory(Path); if DirectoryExistsUTF8(Path)=False then Exit; FFileList:=TStringList.Create; @@ -122,15 +126,25 @@ procedure TPacker.Execute; pfCBZ: FExt:='.cbz'; pfPDF: FExt:='.pdf'; end; - FSavedFilename:=TrimAndExpandFilename(Path)+FExt; - if FileExistsUTF8(FSavedFilename) then - if DeleteFileUTF8(FSavedFilename)=False then + if FileName<>'' then + begin + FSavedFileName:=FileName; + if Length(ExtractFileExt(FSavedFileName))>1 then + FSavedFileName:=ChangeFileExt(FSavedFileName,FExt) + else + FSavedFileName:=FSavedFileName+FExt; + end + else + FSavedFileName:=TrimAndExpandFilename(Path)+FExt; + if FileExistsUTF8(FSavedFileName) then + if DeleteFileUTF8(FSavedFileName)=False then Exit; case Format of pfZIP,pfCBZ: DoZipCbz; pfPDF: DoPdf; end; - if FileExistsUTF8(FSavedFilename) then + Result := FileExistsUTF8(FSavedFileName); + if Result then if DeleteDirectory(Path,False) then RemoveDirUTF8(Path); end; From b906c57d993f8c57ab5bd201c89c8e3cef27e66c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Jun 2016 01:35:42 +0800 Subject: [PATCH 1216/2794] tpacker, filename strictly without extension --- baseunits/uPacker.pas | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 51dac6bab..b0f1ebace 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -127,13 +127,7 @@ function TPacker.Execute: Boolean; pfPDF: FExt:='.pdf'; end; if FileName<>'' then - begin - FSavedFileName:=FileName; - if Length(ExtractFileExt(FSavedFileName))>1 then - FSavedFileName:=ChangeFileExt(FSavedFileName,FExt) - else - FSavedFileName:=FSavedFileName+FExt; - end + FSavedFileName:=FileName+FExt else FSavedFileName:=TrimAndExpandFilename(Path)+FExt; if FileExistsUTF8(FSavedFileName) then From 91ec761be6989949a57d97dfd19b891b175fd804 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Jun 2016 02:32:51 +0800 Subject: [PATCH 1217/2794] baseunit, fixed isdirectoryempty --- baseunits/uBaseUnit.pas | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6a932673e..c39efd14d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -962,10 +962,8 @@ function IsDirectoryEmpty(const ADir: String): Boolean; searchRec: TSearchRec; begin try - Result := (FindFirstUTF8(CorrectFilePath(ADir) + '*.*', faAnyFile -{$ifdef unix} or faSymLink -{$endif unix} - , searchRec) = 0) and + Result := (FindFirstUTF8(CleanAndExpandDirectory(ADir) + '*.*', + faAnyFile{$ifdef unix} or faSymLink{$endif unix}, searchRec) = 0) and (FindNextUTF8(searchRec) = 0) and (FindNextUTF8(searchRec) <> 0); finally From f51616cd00b9cbff20c800e2907d8db63c25c18c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Jun 2016 02:36:26 +0800 Subject: [PATCH 1218/2794] tpacker, only delete compressed files, remove dir if empty fixed #275 --- baseunits/uPacker.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index b0f1ebace..9c0539468 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -106,6 +106,8 @@ procedure TPacker.DoPdf; end; function TPacker.Execute: Boolean; +var + i: Integer; begin Result:=False; Path:=CleanAndExpandDirectory(Path); @@ -139,8 +141,12 @@ function TPacker.Execute: Boolean; end; Result := FileExistsUTF8(FSavedFileName); if Result then - if DeleteDirectory(Path,False) then + begin + for i:=0 to FFileList.Count-1 do + DeleteFileUTF8(FFileList[i]); + if IsDirectoryEmpty(Path) then RemoveDirUTF8(Path); + end; end; finally FFileList.Free; From a429b6486e1fb85d6c8a0cd793629b5c6497c0b8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Jun 2016 04:56:23 +0800 Subject: [PATCH 1219/2794] fixed working with custom filename, compress only process expected file #275 --- baseunits/uBaseUnit.pas | 54 ++++++++++++++------ baseunits/uDownloadsManager.pas | 74 ++++++++++++++++++---------- baseunits/uPacker.pas | 87 +++++++++++++++++++-------------- 3 files changed, 136 insertions(+), 79 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c39efd14d..cb81a5195 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -483,7 +483,17 @@ interface MangaInfo_StatusCompleted = '0'; MangaInfo_StatusOngoing = '1'; - FMDSupportedOutputExt: array[0..2] of string = ('.zip', '.cbz', '.pdf'); + FMDSupportedOutputExt: array[0..2] of ShortString = ('.zip', '.cbz', '.pdf'); + FMDImageFileExt: array[0..2] of ShortString = ('.png', '.gif', '.jpg'); + + // custom rename + CR_NUMBERING = '%NUMBERING%'; + CR_CHAPTER = '%CHAPTER%'; + CR_WEBSITE = '%WEBSITE%'; + CR_MANGA = '%MANGA%'; + CR_AUTHOR = '%AUTHOR%'; + CR_ARTIST = '%ARTIST%'; + CR_FILENAME = '%FILENAME%'; {$ifdef windows} // MAX_PATH(260) - 12 - 1 @@ -815,7 +825,8 @@ function SaveImage(const mangaSiteID: Integer; URL: String; overload; inline; // check file exist with known extensions. AFilename is a filename without extensions -function ImageFileExist(const AFilename: String): Boolean; +function ImageFileExist(const AFileName: String): Boolean; +function FindImageFile(const AFileName: String): String; // load TImageData from file with UTF8 aware function LoadImageDataFromFileUTF8(const FileName: String; var Image: TImageData): Boolean; @@ -2141,19 +2152,19 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh // for rename chapter only if AChapter <> '' then begin // numbering/index - if (Pos('%NUMBERING%', Result) = 0) and (Pos('%CHAPTER%', Result) = 0) then + if (Pos(CR_NUMBERING, Result) = 0) and (Pos(CR_CHAPTER, Result) = 0) then Result := ANumbering + Result else Result := Result; if AWebsite = WebsiteRoots[FAKKU_ID, 0] then begin if Pos('%NUMBERING% - ', Result) > 0 then - Result := StringReplaceBrackets(Result, '%NUMBERING% - ', '', [rfReplaceAll]) + Result := StringReplaceBrackets(Result, CR_NUMBERING + ' - ', '', [rfReplaceAll]) else - Result := StringReplaceBrackets(Result, '%NUMBERING%', '', [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_NUMBERING, '', [rfReplaceAll]); end else - Result := StringReplaceBrackets(Result, '%NUMBERING%', ANumbering, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_NUMBERING, ANumbering, [rfReplaceAll]); // pad number fchapter := Trim(AChapter); @@ -2170,7 +2181,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh fchapter := FixStringLocal(fchapter); - Result := StringReplaceBrackets(Result, '%CHAPTER%', fchapter, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_CHAPTER, fchapter, [rfReplaceAll]); if Result = '' then begin if AWebsite = WebsiteRoots[FAKKU_ID, 0] then @@ -2180,11 +2191,11 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh end; end; - Result := StringReplaceBrackets(Result, '%WEBSITE%', FixStringLocal(AWebsite), [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%MANGA%', FixStringLocal(AMangaName), [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%AUTHOR%', FixStringLocal(AAuthor), [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%ARTIST%', FixStringLocal(AArtist), [rfReplaceAll]); - Result := StringReplaceBrackets(Result, '%FILENAME%', FixStringLocal(AFilename), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_WEBSITE, FixStringLocal(AWebsite), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_MANGA, FixStringLocal(AMangaName), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_AUTHOR, FixStringLocal(AAuthor), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_ARTIST, FixStringLocal(AArtist), [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_FILENAME, FixStringLocal(AFilename), [rfReplaceAll]); if Result = '' then Result := FixStringLocal(AMangaName); @@ -3477,11 +3488,22 @@ function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Result := SaveImage(nil, mangaSiteID, URL, Path, Name, SavedFilename, Reconnect); end; -function ImageFileExist(const AFilename: String): Boolean; +function ImageFileExist(const AFileName: String): Boolean; begin - Result := (FileExistsUTF8(AFilename + '.jpg')) or - (FileExistsUTF8(AFilename + '.png')) or - (FileExistsUTF8(AFilename + '.gif')); + Result := FindImageFile(AFileName) <> ''; +end; + +function FindImageFile(const AFileName: String): String; +var + i: Byte; +begin + Result := ''; + for i := Low(FMDImageFileExt) to High(FMDImageFileExt) do + if FileExistsUTF8(AFileName + FMDImageFileExt[i]) then + begin + Result := AFileName + FMDImageFileExt[i]; + Break; + end; end; function LoadImageDataFromFileUTF8(const FileName: String; var Image: TImageData): Boolean; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index e3a663ba6..6da3d992d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -83,6 +83,7 @@ TTaskThread = class(TFMDThread) Threads: TFPList; constructor Create; destructor Destroy; override; + function GetFileName(const AWorkId: Integer): String; end; { TTaskContainer } @@ -103,6 +104,8 @@ TTaskContainer = class DownloadInfo: TDownloadInfo; // current working dir, save to + chapter name CurrentWorkingDir: String; + // current custom filename with only %FILENAME% left intact + CurrentCustomFileName: String; // current link index CurrentPageNumber, // current chapter index @@ -121,7 +124,8 @@ TTaskContainer = class PageContainerLinks, PageLinks: TStringList; Filenames: TStringList; - // custom filenames + // custom filename + CustomFileName: String; constructor Create; destructor Destroy; override; procedure IncReadCount(const ACount: Integer); @@ -847,6 +851,17 @@ destructor TTaskThread.Destroy; inherited Destroy; end; +function TTaskThread.GetFileName(const AWorkId: Integer): String; +begin + Result := ''; + if (Container.Filenames.Count = Container.PageLinks.Count) and + (AWorkId < Container.Filenames.Count) then + Result := Container.Filenames[AWorkId]; + if Result = '' then + Result := Format('%.3d', [AWorkId + 1]); + Result := StringReplace(Container.CurrentCustomFileName, CR_FILENAME, Result, [rfReplaceAll]); +end; + procedure TTaskThread.MainThreadCompressRepaint; begin Container.DownloadInfo.Status := @@ -858,6 +873,8 @@ procedure TTaskThread.MainThreadCompressRepaint; procedure TTaskThread.Compress; var uPacker: TPacker; + i: Integer; + s: String; begin if (Container.Manager.compress >= 1) then begin @@ -873,6 +890,12 @@ procedure TTaskThread.Compress; uPacker.Path := Container.CurrentWorkingDir; uPacker.FileName := Container.DownloadInfo.SaveTo + Container.ChapterName[Container.CurrentDownloadChapterPtr]; + for i := 0 to Container.PageLinks.Count - 1 do + begin + s := FindImageFile(Container.CurrentWorkingDir + GetFileName(i)); + if s <> '' then + uPacker.FileList.Add(s); + end; uPacker.Execute; except on E: Exception do @@ -945,24 +968,7 @@ function TDownloadThread.DownloadImage: Boolean; Result := Modules.BeforeDownloadImage(Self, workURL, Task.Container.ModuleId); // prepare filename - workFilename := ''; - if WorkId < Task.Container.Filenames.Count then - workFilename := Task.Container.Filenames[WorkId]; - if workFilename = '' then - workFilename := Format('%.3d', [WorkId + 1]); - // custom filename - with task.Container.DownloadInfo do - begin - workFilename := CustomRename(OptionFilenameCustomRename, - Website, - Title, - '', - '', - Task.Container.ChapterName[Task.Container.CurrentDownloadChapterPtr], - '', - OptionChangeUnicodeCharacter, - workFilename); - end; + workFilename := Task.GetFileName(WorkId); // download image savedFilename := ''; @@ -1134,7 +1140,6 @@ procedure TTaskThread.Execute; var j: Integer; - s: String; DynamicPageLink: Boolean; begin Container.ThreadState := True; @@ -1145,6 +1150,9 @@ procedure TTaskThread.Execute; else DynamicPageLink := False; + if Trim(Container.CustomFileName) = '' then + Container.CustomFileName := DEFAULT_FILENAME_CUSTOMRENAME; + while Container.CurrentDownloadChapterPtr < Container.ChapterLinks.Count do begin WaitForThreads; @@ -1167,6 +1175,17 @@ procedure TTaskThread.Execute; if Container.ModuleId > -1 then Modules.TaskStart(Container, Container.ModuleId); + // set current working custom filename + Container.CurrentCustomFileName := CustomRename(Container.CustomFileName, + Container.DownloadInfo.Website, + Container.DownloadInfo.Title, + '', + '', + Container.ChapterName[Container.CurrentDownloadChapterPtr], + '', + OptionChangeUnicodeCharacter, + CR_FILENAME); + // Get page number. if Container.PageLinks.Count = 0 then begin @@ -1197,12 +1216,7 @@ procedure TTaskThread.Execute; begin for j := 0 to Container.PageLinks.Count - 1 do begin - if Container.Filenames.Count = Container.PageLinks.Count then - s := Container.CurrentWorkingDir + Container.Filenames[j] - else - s := Container.CurrentWorkingDir + Format('%.3d', [j + 1]); - - if ImageFileExist(s) then + if ImageFileExist(Container.CurrentWorkingDir + GetFileName(j)) then Container.PageLinks[j] := 'D' else if Container.PageLinks[j] = 'D' then @@ -1567,6 +1581,7 @@ procedure TDownloadManager.Restore; DownCounter := StrToIntDef(ExtractWord(1, DownloadInfo.Progress, ['/']), 0); PageNumber := StrToIntDef(ExtractWord(2, DownloadInfo.Progress, ['/']), 0); end; + CustomFileName := ReadString(tid, 'CustomFileName', DEFAULT_FILENAME_CUSTOMRENAME); s := ReadString(tid, 'ChapterLinks', ''); if s <> '' then GetParams(ChapterLinks, s); s := ReadString(tid, 'ChapterName', ''); @@ -1653,6 +1668,7 @@ procedure TDownloadManager.Backup; WriteString(tid, 'Status', DownloadInfo.Status); WriteString(tid, 'Progress', DownloadInfo.Progress); WriteString(tid, 'DateTime', FloatToStr(DownloadInfo.dateTime, FMDFormatSettings)); + WriteString(tid, 'CustomFileName', CustomFileName); WriteString(tid, 'ChapterLinks', SetParams(ChapterLinks)); WriteString(tid, 'ChapterName', SetParams(ChapterName)); if FailedChapterLinks.Count > 0 then @@ -1706,7 +1722,11 @@ function TDownloadManager.AddTask: Integer; CS_Task.Acquire; try Result := Containers.Add(TTaskContainer.Create); - TTaskContainer(Containers.Last).Manager := Self; + with TTaskContainer(Containers[Result]) do + begin + Manager := Self; + CustomFileName := OptionFilenameCustomRename; + end; finally CS_Task.Release; end; diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 9c0539468..febf4bf05 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -32,6 +32,10 @@ TPacker = class Format: TPackerFormat; CompressionQuality: Cardinal; function Execute: Boolean; + property FileList: TStringList read FFileList; + public + constructor Create; + destructor Destroy; override; end; implementation @@ -109,48 +113,59 @@ function TPacker.Execute: Boolean; var i: Integer; begin - Result:=False; - Path:=CleanAndExpandDirectory(Path); - if DirectoryExistsUTF8(Path)=False then Exit; - FFileList:=TStringList.Create; - try + Result := False; + Path := CleanAndExpandDirectory(Path); + + if FFileList.Count = 0 then + begin + if DirectoryExistsUTF8(Path) = False then Exit; with TFileSearcher.Create do try - OnFileFound:=FileFound; - Search(Self.Path,'*.jpg;*.jpeg;*.png;*.gif',False,False); + OnFileFound := FileFound; + Search(Self.Path, '*.jpg;*.png;*.gif', False, False); finally Free; end; - if FFileList.Count>0 then begin - FFileList.CustomSort(NaturalCustomSort); - case Format of - pfZIP: FExt:='.zip'; - pfCBZ: FExt:='.cbz'; - pfPDF: FExt:='.pdf'; - end; - if FileName<>'' then - FSavedFileName:=FileName+FExt - else - FSavedFileName:=TrimAndExpandFilename(Path)+FExt; - if FileExistsUTF8(FSavedFileName) then - if DeleteFileUTF8(FSavedFileName)=False then - Exit; - case Format of - pfZIP,pfCBZ: DoZipCbz; - pfPDF: DoPdf; - end; - Result := FileExistsUTF8(FSavedFileName); - if Result then - begin - for i:=0 to FFileList.Count-1 do - DeleteFileUTF8(FFileList[i]); - if IsDirectoryEmpty(Path) then - RemoveDirUTF8(Path); - end; - end; - finally - FFileList.Free; end; + + if FFileList.Count = 0 then Exit; + + FFileList.CustomSort(NaturalCustomSort); + case Format of + pfZIP: FExt := '.zip'; + pfCBZ: FExt := '.cbz'; + pfPDF: FExt := '.pdf'; + end; + if FileName <> '' then + FSavedFileName := FileName + FExt + else + FSavedFileName := TrimAndExpandFilename(Path) + FExt; + if FileExistsUTF8(FSavedFileName) then + if DeleteFileUTF8(FSavedFileName) = False then + Exit; + case Format of + pfZIP, pfCBZ: DoZipCbz; + pfPDF: DoPdf; + end; + Result := FileExistsUTF8(FSavedFileName); + if Result then + begin + for i := 0 to FFileList.Count - 1 do + DeleteFileUTF8(FFileList[i]); + if IsDirectoryEmpty(Path) then + RemoveDirUTF8(Path); + end; +end; + +constructor TPacker.Create; +begin + FFileList := TStringList.Create; +end; + +destructor TPacker.Destroy; +begin + FFileList.Free; + inherited Destroy; end; end. From 794057d5abdb8b5ebe8556664fd3e32b84878fe9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Jun 2016 06:55:46 +0800 Subject: [PATCH 1220/2794] fixed issue with long filename fixed #276 preserve 4 char from right --- baseunits/uBaseUnit.pas | 29 +++++++++++++++++++++++++---- baseunits/uDownloadsManager.pas | 4 ++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cb81a5195..a79f1e058 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -485,6 +485,10 @@ interface FMDSupportedOutputExt: array[0..2] of ShortString = ('.zip', '.cbz', '.pdf'); FMDImageFileExt: array[0..2] of ShortString = ('.png', '.gif', '.jpg'); + // max file extension length = 4 + FMDImageFileExtLength = 4; + FMDMaxImageFilePath = MAX_PATH - FMDImageFileExtLength; + // custom rename CR_NUMBERING = '%NUMBERING%'; @@ -496,8 +500,8 @@ interface CR_FILENAME = '%FILENAME%'; {$ifdef windows} - // MAX_PATH(260) - 12 - 1 - MAX_PATH_LENGTH = 247; + // MAX_PATHDIR(260) - 12 - 1 + MAX_PATHDIR = 247; {$endif} var @@ -713,6 +717,9 @@ procedure PadZeros(S: TStrings; ATotalWidth: Integer = 3; // maintain the order of strings by adding serialized number if necessary procedure SerializeAndMaintainNames(F: TStrings); +function ShortenString(const S: String; const MaxWidth: Integer; + const RightLength: Integer = 0; const EllipsisStr: String = '...'): String; + function TitleCase(const S: string): string; function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; function StreamToString(const Stream: TStream): String; inline; @@ -1885,8 +1892,8 @@ function CorrectPathSys(const Path: String): String; {$IFDEF WINDOWS} Result := RemovePathDelim(CleanAndExpandFilename(GetForcedPathDelims(Path))); Result := TrimRightChar(Result, ['.']); - if Length(Result) > MAX_PATH_LENGTH then - SetLength(Result, MAX_PATH_LENGTH); + if Length(Result) > MAX_PATHDIR then + SetLength(Result, MAX_PATHDIR); Result := AppendPathDelim(Result); {$ELSE} Result := CleanAndExpandDirectory(GetForcedPathDelims(Path)); @@ -2096,6 +2103,20 @@ procedure SerializeAndMaintainNames(F: TStrings); end; end; +function ShortenString(const S: String; const MaxWidth: Integer; + const RightLength: Integer; const EllipsisStr: String): String; +var + r: String; +begin + Result := S; + if Length(Result) > MaxWidth then + begin + r := RightStr(Result, RightLength); + SetLength(Result, MaxWidth - RightLength - Length(EllipsisStr)); + Result := Result + EllipsisStr + r; + end; +end; + function TitleCase(const S: string): string; begin Result := AnsiProperCase(S, diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 6da3d992d..8ac38482e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -860,6 +860,10 @@ function TTaskThread.GetFileName(const AWorkId: Integer): String; if Result = '' then Result := Format('%.3d', [AWorkId + 1]); Result := StringReplace(Container.CurrentCustomFileName, CR_FILENAME, Result, [rfReplaceAll]); + {$IFDEF WINDOWS} + if Length(Container.CurrentWorkingDir + Result) > FMDMaxImageFilePath then + Result := ShortenString(Result, FMDMaxImageFilePath - Length(Container.CurrentWorkingDir), 4, ''); + {$ENDIF} end; procedure TTaskThread.MainThreadCompressRepaint; From 7d5de019e0986e4f5aa6b81e65d79c9a122b00e9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Jun 2016 07:05:15 +0800 Subject: [PATCH 1221/2794] added onetimescans #282 --- baseunits/modules/FoOlSlide.pas | 6 ++++++ config/mangalist.ini | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 5a72d2e3e..6734b5190 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -17,6 +17,7 @@ implementation const dirurl = '/directory/'; yomangadirurl = '/reader/directory/'; + onetimescansdirurl = '/foolslide/directory/'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; @@ -38,6 +39,8 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if (Module.Website = 'YoManga') or (Module.Website = 'GoManga') then s := yomangadirurl + else if Module.Website = 'OneTimeScans' then + s := onetimescansdirurl else s := dirurl; if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + s, Module) then @@ -68,6 +71,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if (Module.Website = 'YoManga') or (Module.Website = 'GoManga') then s := yomangadirurl + else if Module.Website = 'OneTimeScans' then + s := onetimescansdirurl else s := dirurl; s := Module.RootURL + s; @@ -220,6 +225,7 @@ procedure RegisterModule; end; AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); AddWebsiteModule('GoManga', 'http://gomanga.co'); + AddWebsiteModule('OneTimeScans', 'http://otscans.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 23575736d..0ec271a98 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,S2Scans,Shoujosense,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From 70b7a8f186bf687b9aa10304780bf169e45c84b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Jun 2016 07:06:05 +0800 Subject: [PATCH 1222/2794] added sensescans closed #282 --- baseunits/modules/FoOlSlide.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 6734b5190..6bfa45362 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -226,6 +226,7 @@ procedure RegisterModule; AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); AddWebsiteModule('GoManga', 'http://gomanga.co'); AddWebsiteModule('OneTimeScans', 'http://otscans.com'); + AddWebsiteModule('SenseScans', 'http://reader.sensescans.com/'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 0ec271a98..b0d5be985 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,Shoujosense,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From 33a19b21f2c4e410cb4265d5a4bc21dcfebbca9d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Jun 2016 09:00:00 +0800 Subject: [PATCH 1223/2794] added kumanga closed #283 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/KuManga.pas | 167 ++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/KuManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 7e2147e4f..14d72e142 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -39,4 +39,5 @@ uses MangaDenizi, MangaSaurus, GMangaMe, - SekaiManga; + SekaiManga, + KuManga; diff --git a/baseunits/modules/KuManga.pas b/baseunits/modules/KuManga.pas new file mode 100644 index 000000000..d98b906b8 --- /dev/null +++ b/baseunits/modules/KuManga.pas @@ -0,0 +1,167 @@ +unit KuManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/backend/ajax/searchengine.php'; + dirperpage = '15'; + dirpostdata = 'contentType=manga&retrieveCategories=true&retrieveAuthors=true&perPage=' + + dirperpage + '&page='; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.POST(Module.RootURL + dirurl, dirpostdata + '1') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('json(*).totalContents'); + Page := ceil(StrToIntDef(s, 1) / StrToInt(dirperpage)); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + c, i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.POST(Module.RootURL + dirurl, dirpostdata + IncStr(AURL)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + c := XPath('json(*).contents()').Count; + for i := 1 to c do + begin + ANames.Add(XPathString('json(*).contents(' + IntToStr(i) + ').name')); + ALinks.Add(XPathString('json(*).contents(' + IntToStr(i) + ')/concat("/manga/",id,"/",slug)')); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := FillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="row"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h2'); + summary := XPathString('//div[@id="info"]/div[1]/div[1]/div[1]/div[2]'); + genres := XPathStringAll('//div[@id="info"]/div[1]/div[1]/div[1]/div[3]/a'); + authors := XPathString('//div[@id="info"]/div[1]/div[2]/div[1]/div[2]/p[2]/a'); + status := MangaInfoStatusIfPos( + XPathString('//div[@id="info"]/div[1]/div[2]/div[1]/div[2]/p[3]/span'), 'Activo', 'Completo'); + for v in XPath('//div[@id="info"]/div[2]//table/tbody/tr/td/a') do + begin + chapterLinks.Add(StringReplace(v.toNode.getAttribute('href'), + '/c/', '/leer/', [rfIgnoreCase])); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + source: TStringList; + i, p: Integer; + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then + begin + Result := True; + source := TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do + if Pos('konekomangareader(''setup'',{', source[i]) <> 0 then + begin + s := GetBetween('.konekomangareader(''setup'',{', '});', source[i]); + Break; + end; + finally + source.Free; + end; + if s <> '' then + begin + s := '{' + s + '}'; + with TXQueryEngineHTML.Create(s) do + try + p := StrToIntDef(XPathString('json(*).pages'), 0); + if p > 0 then + begin + s := XPathString('json(*).pageFormat'); + if Pos('{pnumber}', s) <> 0 then + for i := 1 to p do + PageLinks.Add(StringReplace(s, '{pnumber}', IntToStr(i), [rfReplaceAll])); + end; + finally + Free; + end; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'KuManga'; + RootURL := 'http://www.kumanga.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index b0d5be985..ccb6a6775 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -15,7 +15,7 @@ Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU -Spanish=AnimExtremist,ESMangaHere,NineManga_ES,SekaiManga,SubManga,Tumangaonline +Spanish=AnimExtremist,ESMangaHere,KuManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing From 04ca8f178b0f670e3c64368a0f6c1d99428939bc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Jun 2016 09:11:55 +0800 Subject: [PATCH 1224/2794] Bump version 0.9.62.0 --- changelog.txt | 8 ++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 380ffdf78..274edc2d6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.62.0 (09-06-2016) +[*] Fixed various path issue (#275, #276, #279) +[+] Added OneTimeScans[EN-SC] +[+] Added SenseScan[EN-SC] +[+] Added KuManga[ES] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.61.0...0.9.62.0 + 0.9.61.0 (05-06-2016) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.60.0...0.9.61.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 3e6cd55c0..55d6aa7e4 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="61"/> + <RevisionNr Value="62"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 7bc4b082e..5979938a8 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.61.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.61.0/fmd_0.9.61.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.61.0/fmd_0.9.61.0_Win64.7z +VERSION=0.9.62.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.62.0/fmd_0.9.62.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.62.0/fmd_0.9.62.0_Win64.7z From 8b10940730d4445f0da145f1f144ed41fa58e104 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Jun 2016 21:07:36 +0800 Subject: [PATCH 1225/2794] fixed cf fixed #285 --- baseunits/modules/Cloudflare.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index ec98f02e5..0b208d873 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -59,7 +59,7 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; ModifierG := False; ModifierI := True; - Expression := 'setTimeout\(function\(\)\{\s*var.*\w,\s+(\S.+a\.value =.+)\r?\n'; + Expression := 'setTimeout\(function\(\)\{\s*var.*\w,\s+(\S.+a\.value =[^;]+;)'; Exec(s); if SubExprMatchCount > 0 then begin From 42f6c8a8ec690e28d55f44f81bdb1e9e67982571 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Jun 2016 18:43:52 +0800 Subject: [PATCH 1226/2794] Bump version 0.9.63.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 274edc2d6..8d4e2f88c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.63.0 (11-06-2016) +[*] Fixed an issue with CF +Full changes: https://github.com/riderkick/FMD/compare/0.9.62.0...0.9.63.0 + 0.9.62.0 (09-06-2016) [*] Fixed various path issue (#275, #276, #279) [+] Added OneTimeScans[EN-SC] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 55d6aa7e4..ce2fe642c 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="62"/> + <RevisionNr Value="63"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5979938a8..0884e3e37 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.62.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.62.0/fmd_0.9.62.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.62.0/fmd_0.9.62.0_Win64.7z +VERSION=0.9.63.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.63.0/fmd_0.9.63.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.63.0/fmd_0.9.63.0_Win64.7z From f1420c91eff5a747889b50f149c5807e87642fac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 20:00:20 +0800 Subject: [PATCH 1227/2794] webtoons, fixed not immedietly terminated when called --- baseunits/modules/Webtoons.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index 0dbe02e7e..c69ed6c08 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -77,7 +77,7 @@ function GetInfo(const MangaInfo: TMangaInformation; getp; if p > 1 then begin i := 2; - while i <= p do begin + while (i <= p) and (Thread.IsTerminated = False) do begin if GET(url + '&page=' + IntToStr(i)) then begin ParseHTML(Document); getchapters; From 1aaa493fb0d1288c00221d28e27bf77793ff4698 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 21:29:25 +0800 Subject: [PATCH 1228/2794] favoritesmananger, cleanup and use generic --- baseunits/uFavoritesManager.pas | 259 ++++++++++++++---------------- mangadownloader/forms/frmMain.pas | 40 ++--- 2 files changed, 142 insertions(+), 157 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 02af2f68d..d0810f53f 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -11,9 +11,9 @@ interface uses - Classes, SysUtils, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, FileUtil, - uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, FMDOptions, - httpsendthread, SimpleException; + Classes, SysUtils, fgl, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, + FileUtil, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, + FMDOptions, httpsendthread, SimpleException; type TFavoriteManager = class; @@ -78,6 +78,8 @@ TFavoriteContainer = class property Website: String read FWebsite write SetWebsite; end; + TFavoriteContainers = TFPGList<TFavoriteContainer>; + { TFavoriteManager } TFavoriteManager = class @@ -85,11 +87,9 @@ TFavoriteManager = class CS_Favorites: TCriticalSection; FSortColumn: Integer; FSortDirection, FIsAuto, FIsRunning: Boolean; - FFavorites: TFPList; - function GetItems(Index: Integer): TFavoriteContainer; - protected function GetFavoritesCount: Integer; public + Favorites: TFavoriteContainers; favoritesFile: TIniFileRun; taskthread: TFavoriteTask; DLManager: TDownloadManager; @@ -136,7 +136,6 @@ TFavoriteManager = class property SortColumn: Integer read FSortColumn write FSortColumn; property isAuto: Boolean read FIsAuto write FIsAuto; property isRunning: Boolean read FIsRunning write FIsRunning; - property Items[Index: Integer]: TFavoriteContainer read GetItems; end; resourcestring @@ -279,14 +278,14 @@ procedure TFavoriteTask.Checkout; i: Integer; begin if Terminated then Exit; - if manager.FFavorites.Count = 0 then Exit; + if manager.Favorites.Count = 0 then Exit; manager.CS_Favorites.Acquire; try statuscheck := 0; - for i := 0 to manager.FFavorites.Count - 1 do + for i := 0 to manager.Favorites.Count - 1 do begin if Terminated then Break; - with TFavoriteContainer(manager.FFavorites[i]) do + with manager.Favorites[i] do if Status = STATUS_CHECK then begin LockCreateConnection; @@ -301,7 +300,7 @@ procedure TFavoriteTask.Checkout; with thread do begin task := Self; - container := manager.Items[i]; + container := manager.Favorites[i]; workCounter := i; Start; end; @@ -377,9 +376,9 @@ procedure TFavoriteTask.Execute; end; manager.CS_Favorites.Acquire; try - for i := 0 to manager.FFavorites.Count - 1 do - if TFavoriteContainer(manager.FFavorites[i]).Status <> STATUS_IDLE then - TFavoriteContainer(manager.FFavorites[i]).Status := STATUS_IDLE; + for i := 0 to manager.Favorites.Count - 1 do + if manager.Favorites[i].Status <> STATUS_IDLE then + manager.Favorites[i].Status := STATUS_IDLE; finally manager.CS_Favorites.Release; end; @@ -406,20 +405,9 @@ destructor TFavoriteTask.Destroy; { TFavoriteManager } -function TFavoriteManager.GetItems(Index: Integer): TFavoriteContainer; -begin - if (Index<0) or (Index>=FFavorites.Count) then Exit(nil); - Result := TFavoriteContainer(FFavorites.Items[Index]); -end; - function TFavoriteManager.GetFavoritesCount: Integer; begin - CS_Favorites.Acquire; - try - Result := FFavorites.Count; - finally - CS_Favorites.Release; - end; + Result := Favorites.Count; end; constructor TFavoriteManager.Create; @@ -429,7 +417,7 @@ constructor TFavoriteManager.Create; CS_Favorites := TCriticalSection.Create; isRunning := False; favoritesFile := TIniFileRun.Create(FAVORITES_FILE); - FFavorites := TFPList.Create; + Favorites := TFavoriteContainers.Create; Restore; end; @@ -437,14 +425,14 @@ destructor TFavoriteManager.Destroy; begin Backup; favoritesFile.Free; - if FFavorites.Count > 0 then begin + if Favorites.Count > 0 then begin StopChekForNewChapter; - while FFavorites.Count > 0 do begin - TFavoriteContainer(FFavorites.Last).Free; - FFavorites.Remove(FFavorites.Last); + while Favorites.Count > 0 do begin + Favorites.Last.Free; + Favorites.Remove(Favorites.Last); end; end; - FFavorites.Free; + Favorites.Free; CS_Favorites.Free; inherited Destroy; end; @@ -457,7 +445,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); try if FavoriteIndex > -1 then begin - with TFavoriteContainer(FFavorites[FavoriteIndex]) do + with Favorites[FavoriteIndex] do if Status = STATUS_IDLE then begin Status := STATUS_CHECK; @@ -475,8 +463,8 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); begin CS_Favorites.Acquire; try - for i := 0 to FFavorites.Count - 1 do - with TFavoriteContainer(FFavorites[i]) do + for i := 0 to Favorites.Count - 1 do + with Favorites[i] do if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then Status := STATUS_CHECK; finally @@ -500,7 +488,7 @@ procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; FavoriteIndex if isRunning then if FavoriteIndex > -1 then begin - with TFavoriteContainer(FFavorites[FavoriteIndex]) do begin + with Favorites[FavoriteIndex] do begin if Thread <> nil then begin Thread.Terminate; @@ -540,8 +528,8 @@ procedure TFavoriteManager.ShowResult; numOfMangaNewChapters := 0; numOfCompleted := 0; counter := 0; - while counter < FFavorites.Count do - with Items[counter] do try + while counter < Favorites.Count do + with Favorites[counter] do try if Assigned(MangaInfo) then if MangaInfo.chapterLinks.Count > 0 then begin @@ -569,7 +557,7 @@ procedure TFavoriteManager.ShowResult; begin newChapterListStr := newChapterListStr + LineEnding + '- ' + Format(RS_FavoriteHasNewChapter, - [FavoriteInfo.Title, Items[counter].FavoriteInfo.Website, + [FavoriteInfo.Title, FavoriteInfo.Website, NewMangaInfo.chapterLinks.Count]); Inc(numOfMangaNewChapters); end; @@ -613,17 +601,18 @@ procedure TFavoriteManager.ShowResult; if LNCResult = ncrDownload then begin counter := 0; - while counter < FFavorites.Count do + while counter < Favorites.Count do begin favDelete := False; - with Items[counter] do if Assigned(NewMangaInfo) then - if (NewMangaInfo.chapterLinks.Count = 0) and - (NewMangaInfo.status = '0') then - begin - Items[counter].Free; - FFavorites.Delete(counter); - favDelete := True; - end; + with Favorites[counter] do + if Assigned(NewMangaInfo) and + (NewMangaInfo.chapterLinks.Count = 0) and + (NewMangaInfo.status = '0') then + begin + Favorites[counter].Free; + Favorites.Delete(counter); + favDelete := True; + end; if not favDelete then Inc(counter); end; @@ -662,59 +651,60 @@ procedure TFavoriteManager.ShowResult; while DLManager.isRunningBackup do Sleep(100); counter := 0; - while counter < FFavorites.Count do + while counter < Favorites.Count do begin - with Items[counter] do if Assigned(NewMangaInfo) then - if NewMangaInfo.chapterLinks.Count > 0 then - begin - DLManager.CS_Task.Acquire; - try - DLManager.containers.Add(TTaskContainer.Create); - with TTaskContainer(DLManager.Containers.Last) do begin - Manager := DLManager; - CurrentDownloadChapterPtr := 0; - Website := FavoriteInfo.Website; - with DownloadInfo do begin - Link := FavoriteInfo.Link; - Title := FavoriteInfo.Title; - SaveTo := FavoriteInfo.SaveTo; - dateTime := Now; - end; - ChapterLinks.Assign(NewMangaInfo.chapterLinks); - for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do - ChapterName.Add(CustomRename( - OptionChapterCustomRename, - FavoriteInfo.Website, - FavoriteInfo.Title, - NewMangaInfo.authors, - NewMangaInfo.artists, - NewMangaInfo.chapterName[i], - Format('%.4d', [NewMangaInfoChaptersPos[i] + 1]), - OptionChangeUnicodeCharacter)); - if LNCResult = ncrDownload then - begin - DownloadInfo.Status := RS_Waiting; - Status := STATUS_WAIT; - end - else - begin - DownloadInfo.Status := RS_Stopped; - Status := STATUS_STOP; - end; + with Favorites[counter] do + if Assigned(NewMangaInfo) and + (NewMangaInfo.chapterLinks.Count > 0) then + begin + DLManager.CS_Task.Acquire; + try + DLManager.containers.Add(TTaskContainer.Create); + with TTaskContainer(DLManager.Containers.Last) do begin + Manager := DLManager; + CurrentDownloadChapterPtr := 0; + Website := FavoriteInfo.Website; + with DownloadInfo do begin + Link := FavoriteInfo.Link; + Title := FavoriteInfo.Title; + SaveTo := FavoriteInfo.SaveTo; + dateTime := Now; + end; + ChapterLinks.Assign(NewMangaInfo.chapterLinks); + for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do + ChapterName.Add(CustomRename( + OptionChapterCustomRename, + FavoriteInfo.Website, + FavoriteInfo.Title, + NewMangaInfo.authors, + NewMangaInfo.artists, + NewMangaInfo.chapterName[i], + Format('%.4d', [NewMangaInfoChaptersPos[i] + 1]), + OptionChangeUnicodeCharacter)); + if LNCResult = ncrDownload then + begin + DownloadInfo.Status := RS_Waiting; + Status := STATUS_WAIT; + end + else + begin + DownloadInfo.Status := RS_Stopped; + Status := STATUS_STOP; end; - FavoriteInfo.currentChapter := - IntToStr(MangaInfo.chapterLinks.Count); - finally - DLManager.CS_Task.Release; end; - //mark downloaded - FavoriteInfo.downloadedChapterList := - FavoriteInfo.downloadedChapterList + - SetParams(NewMangaInfo.chapterLinks); - //save to downloaded chapter list from dlmanager. - DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := - NewMangaInfo.chapterLinks.Text; + FavoriteInfo.currentChapter := + IntToStr(MangaInfo.chapterLinks.Count); + finally + DLManager.CS_Task.Release; end; + //mark downloaded + FavoriteInfo.downloadedChapterList := + FavoriteInfo.downloadedChapterList + + SetParams(NewMangaInfo.chapterLinks); + //save to downloaded chapter list from dlmanager. + DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := + NewMangaInfo.chapterLinks.Text; + end; Inc(counter); end; Backup; @@ -732,9 +722,9 @@ procedure TFavoriteManager.ShowResult; finally //free used memory counter := 0; - while counter < FFavorites.Count do + while counter < Favorites.Count do begin - with Items[counter] do begin + with Favorites[counter] do begin if Assigned(MangaInfo) then FreeAndNil(MangaInfo); if Assigned(NewMangaInfo) then @@ -758,9 +748,9 @@ function TFavoriteManager.IsMangaExist(const ATitle, AWebsite: String): Boolean; i: Integer; begin Result := False; - if FFavorites.Count > 0 then - for i := 0 to FFavorites.Count - 1 do - with TFavoriteContainer(FFavorites[i]).FavoriteInfo do + if Favorites.Count > 0 then + for i := 0 to Favorites.Count - 1 do + with Favorites[i].FavoriteInfo do if SameText(ATitle, Title) and SameText(AWebsite, Website) then Exit(True); end; @@ -770,9 +760,9 @@ function TFavoriteManager.IsMangaExistURL(const AWebsite, AURL: String): Boolean i: Integer; begin Result := False; - if FFavorites.Count > 0 then - for i := 0 to FFavorites.Count - 1 do - with TFavoriteContainer(FFavorites[i]).FavoriteInfo do + if Favorites.Count > 0 then + for i := 0 to Favorites.Count - 1 do + with Favorites[i].FavoriteInfo do if SameText(AWebsite, Website) and SameText(AURL, Link) then Exit(True); end; @@ -783,8 +773,8 @@ procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapter if IsMangaExist(ATitle, AWebsite) then Exit; CS_Favorites.Acquire; try - FFavorites.Add(TFavoriteContainer.Create); - with TFavoriteContainer(FFavorites.Last) do begin + Favorites.Add(TFavoriteContainer.Create); + with Favorites.Last do begin Manager := Self; Website := AWebsite; with FavoriteInfo do begin @@ -813,8 +803,8 @@ procedure TFavoriteManager.AddMerge(const ATitle, ACurrentChapter, ADownloadedCh Exit; CS_Favorites.Acquire; try - FFavorites.Add(TFavoriteContainer.Create); - with TFavoriteContainer(FFavorites.Last) do begin + Favorites.Add(TFavoriteContainer.Create); + with Favorites.Last do begin Manager := Self; Website := AWebsite; with FavoriteInfo do begin @@ -876,12 +866,12 @@ procedure TFavoriteManager.MergeWith(const APath: String); procedure TFavoriteManager.Remove(const pos: Integer; const isBackup: Boolean); begin - if (not isRunning) and (pos < FFavorites.Count) then + if (not isRunning) and (pos < Favorites.Count) then begin CS_Favorites.Acquire; try - TFavoriteContainer(FFavorites[pos]).Free; - FFavorites.Delete(pos); + Favorites[pos].Free; + Favorites.Delete(pos); if isBackup then Backup; finally @@ -898,8 +888,8 @@ procedure TFavoriteManager.Restore; if c > 0 then for i := 0 to c - 1 do begin - FFavorites.Add(TFavoriteContainer.Create); - with TFavoriteContainer(FFavorites.Last) do begin + Favorites.Add(TFavoriteContainer.Create); + with Favorites.Last do begin Manager := Self; with favoritesFile, FavoriteInfo do begin Title := ReadString(IntToStr(i), 'Title', ''); @@ -925,10 +915,10 @@ procedure TFavoriteManager.Backup; for i := 0 to ReadInteger('general', 'NumberOfFavorites', 0) - 1 do EraseSection(IntToStr(i)); - WriteInteger('general', 'NumberOfFavorites', FFavorites.Count); - if FFavorites.Count > 0 then - for i := 0 to FFavorites.Count - 1 do - with TFavoriteContainer(FFavorites[i]).FavoriteInfo do begin + WriteInteger('general', 'NumberOfFavorites', Favorites.Count); + if Favorites.Count > 0 then + for i := 0 to Favorites.Count - 1 do + with Favorites[i].FavoriteInfo do begin WriteString(IntToStr(i), 'Title', Title); WriteString(IntToStr(i), 'CurrentChapter', currentChapter); WriteString(IntToStr(i), 'DownloadedChapterList', downloadedChapterList); @@ -971,9 +961,9 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St try p := -1; //locate the link - if FFavorites.Count > 1 then - for i := 0 to FFavorites.Count - 1 do - with TFavoriteContainer(FFavorites[i]).FavoriteInfo do + if Favorites.Count > 1 then + for i := 0 to Favorites.Count - 1 do + with Favorites[i].FavoriteInfo do if SameText(AWebsite, Website) and SameText(Alink, Link) then begin p := i; @@ -998,7 +988,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St end; //merge the links - with TFavoriteContainer(FFavorites[p]).FavoriteInfo do begin + with Favorites[p].FavoriteInfo do begin downloadedChapterList := downloadedChapterList + SetParams(ch); currentChapter := IntToStr(dlCh.Count + ch.Count); end; @@ -1012,12 +1002,12 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St end; end; -function CompareFavoriteContainer(Item1, Item2: Pointer): Integer; +function CompareFavoriteContainer(const Item1, Item2: TFavoriteContainer): Integer; - function GetStr(ARow: Pointer): String; + function GetStr(ARow: TFavoriteContainer): String; begin - with TFavoriteContainer(ARow).FavoriteInfo do - case TFavoriteContainer(ARow).Manager.SortColumn of + with ARow.FavoriteInfo do + case ARow.Manager.SortColumn of 1: Result := Title; 2: Result := currentChapter; 3: Result := website; @@ -1027,25 +1017,20 @@ function CompareFavoriteContainer(Item1, Item2: Pointer): Integer; end; end; -var - ItemT: Pointer; begin - if TFavoriteContainer(Item1).Manager.SortDirection then - begin - ItemT := Item1; - Item1 := Item2; - Item2 := ItemT; - end; - Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); + if Item1.Manager.SortDirection then + Result := NaturalCompareStr(GetStr(Item2), GetStr(Item1)) + else + Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); end; procedure TFavoriteManager.Sort(const AColumn: Integer); begin - if FFavorites.Count < 2 then Exit; + if Favorites.Count < 2 then Exit; CS_Favorites.Acquire; try SortColumn := AColumn; - FFavorites.Sort(CompareFavoriteContainer); + Favorites.Sort(CompareFavoriteContainer); finally CS_Favorites.Release; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 68c0392ba..15f5f1017 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1711,7 +1711,7 @@ procedure TMainForm.miFavoritesDownloadAllClick(Sender: TObject); for i := 0 to vtFavorites.SelectedCount - 1 do begin if vtFavorites.Selected[xNode] then - with FavoriteManager.Items[xNode^.Index].FavoriteInfo do + with FavoriteManager.Favorites[xNode^.Index].FavoriteInfo do SilentThreadManager.Add(MD_DownloadAll, Website, Title, Link, SaveTo); xNode := vtFavorites.GetNextSelected(xNode); end; @@ -1754,9 +1754,9 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); rmInformation.Lines.Add('Loading ...'); clbChapterList.Clear; - website := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Website; - link := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.link; - title := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Title; + website := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.Website; + link := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.link; + title := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.Title; if isGetMangaInfos then begin @@ -2585,13 +2585,13 @@ procedure TMainForm.miFavoritesChangeCurrentChapterClick(Sender: TObject); end; if not Assigned(vtFavorites.FocusedNode) then Exit; - s := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter; + s := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter; repeat if InputQuery('', RS_DlgTypeInNewChapter, s) then until TryStrToInt(s, i); - if s <> FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter then + if s <> FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter then begin - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter := s; + FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter := s; UpdateVtFavorites; FavoriteManager.Backup; end; @@ -2608,10 +2608,10 @@ procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); if not Assigned(vtFavorites.FocusedNode) then Exit; if InputQuery('', RS_DlgTypeInNewSavePath, - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo) then + FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo) then begin - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := - CorrectFilePath(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := + CorrectFilePath(FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); UpdateVtFavorites; FavoriteManager.Backup; end; @@ -3000,7 +3000,7 @@ procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then OpenDocument(ChompPathDelim( - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); + FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); end; procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); @@ -3014,7 +3014,7 @@ procedure TMainForm.miFavoritesOpenWithClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then OpenWithExternalProgramChapters( - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); end; procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); @@ -3155,7 +3155,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); repeat if Assigned(xNode) then begin - if FavoriteManager.Items[xNode^.Index].Status in Stats then + if FavoriteManager.Favorites[xNode^.Index].Status in Stats then begin Result := True; Break; @@ -3187,12 +3187,12 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesStopCheckNewChapter.Visible := SelectedStatusPresent([STATUS_CHECK, STATUS_CHECKING]); miFavoritesViewInfos.Enabled := True; - miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.Items[ + miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.Favorites[ vtFavorites.FocusedNode^.Index].FavoriteInfo.Link) <> ''); miFavoritesDelete.Enabled := True; miFavoritesChangeSaveTo.Enabled := True; miFavoritesOpenFolder.Enabled := - DirectoryExistsUTF8(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + DirectoryExistsUTF8(FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); miFavoritesOpenWith.Enabled := miFavoritesOpenFolder.Enabled; end else @@ -3707,7 +3707,7 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; Data := Sender.GetNodeData(Node); if Assigned(Data) then begin - with FavoriteManager.Items[Node^.Index] do + with FavoriteManager.Favorites[Node^.Index] do begin if Trim(FavoriteInfo.Link) = '' then begin @@ -3753,7 +3753,7 @@ procedure TMainForm.vtFavoritesGetHint(Sender: TBaseVirtualTree; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); begin if Node^.Index>=FavoriteManager.Count then Exit; - with FavoriteManager.Items[Node^.Index].FavoriteInfo do + with FavoriteManager.Favorites[Node^.Index].FavoriteInfo do case Column of 1: if Trim(Link)='' then HintText:=RS_HintFavoriteProblem else HintText:=Title; @@ -3769,10 +3769,10 @@ procedure TMainForm.vtFavoritesGetImageIndex(Sender: TBaseVirtualTree; begin if vtFavorites.Header.Columns[Column].Position<>1 then Exit; if Node^.Index>=FavoriteManager.Count then Exit; - if Trim(FavoriteManager.Items[Node^.Index].FavoriteInfo.Link)='' then + if Trim(FavoriteManager.Favorites[Node^.Index].FavoriteInfo.Link)='' then ImageIndex:=16 else - case FavoriteManager.Items[Node^.Index].Status of + case FavoriteManager.Favorites[Node^.Index].Status of STATUS_CHECK : ImageIndex:=19; STATUS_CHECKING : ImageIndex:=12; STATUS_CHECKED : ImageIndex:=20; @@ -3788,7 +3788,7 @@ procedure TMainForm.vtFavoritesGetText(Sender: TBaseVirtualTree; var CellText: String); begin if Node^.Index>=FavoriteManager.Count then Exit; - with FavoriteManager.Items[Node^.Index].FavoriteInfo do + with FavoriteManager.Favorites[Node^.Index].FavoriteInfo do case Column of 0: CellText:=IntToStr(Node^.Index+1); 1: CellText:=Title; From d633f6ff41ec1b73332eb046b7015fe31a155b78 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 21:41:27 +0800 Subject: [PATCH 1229/2794] frmmain, fixed save restore download list and favorite list sort column --- mangadownloader/forms/frmMain.pas | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 15f5f1017..72b5d1b8b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1117,19 +1117,6 @@ procedure TMainForm.FormCreate(Sender: TObject); mangaCover := TPicture.Create; - // refresh sort - if DLManager.Count > 1 then - begin - DLManager.SortDirection := Boolean(vtDownload.Header.SortDirection); - vtDownload.Repaint; - end; - if FavoriteManager.Count > 0 then - begin - FavoriteManager.SortDirection := Boolean(vtFavorites.Header.SortDirection); - FavoriteManager.Sort(vtFavorites.Header.SortColumn); - vtFavorites.Repaint; - end; - //textstyle for updatestatusbar with UpdateStatusTextStyle do begin @@ -3808,8 +3795,9 @@ procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; FavoriteManager.isRunning := True; try if FavoriteManager.SortColumn = Column then - FavoriteManager.sortDirection := not FavoriteManager.sortDirection; - FavoriteManager.SortColumn := Column; + FavoriteManager.sortDirection := not FavoriteManager.sortDirection + else + FavoriteManager.SortColumn := Column; vtFavorites.Header.SortColumn := Column; vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); FavoriteManager.Sort(Column); @@ -4857,12 +4845,14 @@ procedure TMainForm.LoadFormInformation; for i := 0 to Count - 1 do Items[i].Width := ReadInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', 50); + FavoriteManager.SortColumn := ReadInteger('misc', 'SortFavoritesColumn', 1); FavoriteManager.sortDirection := ReadBool('misc', 'SortFavoritesDirection', False); - vtFavorites.Header.SortColumn := ReadInteger('misc', 'SortFavoritesColumn', 1); + vtFavorites.Header.SortColumn := FavoriteManager.SortColumn; vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); + DLManager.SortColumn := ReadInteger('misc', 'SortDownloadColumn', 0); DLManager.SortDirection := ReadBool('misc', 'SortDownloadDirection', False); - vtDownload.Header.SortColumn := ReadInteger('misc', 'SortDownloadColumn', 0); + vtDownload.Header.SortColumn := DLManager.SortColumn; vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); end; end; From 6c03897362b4250a737ce30b780f6e0dee7f355a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 21:49:03 +0800 Subject: [PATCH 1230/2794] favoritesmanager, rename and use generic --- baseunits/uFavoritesManager.pas | 110 ++++++++++++++++---------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index d0810f53f..c01726fed 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -28,14 +28,16 @@ TFavoriteThread = class(TFMDThread) procedure Execute; override; procedure DoTerminate; override; public - workCounter: Cardinal; - getInfo: TMangaInformation; - task: TFavoriteTask; - container: TfavoriteContainer; + WorkId: Cardinal; + GetInfo: TMangaInformation; + Task: TFavoriteTask; + Container: TfavoriteContainer; constructor Create; destructor Destroy; override; end; + TFavoriteThreads = TFPGList<TFavoriteThread>; + { TFavoriteTask } TFavoriteTask = class(TFMDThread) @@ -50,8 +52,8 @@ TFavoriteTask = class(TFMDThread) procedure DoTerminate; override; procedure Execute; override; public - manager: TFavoriteManager; - threads: TFPList; + Manager: TFavoriteManager; + Threads: TFavoriteThreads; procedure UpdateBtnCaption(Cap: String); constructor Create; destructor Destroy; override; @@ -198,24 +200,24 @@ procedure TFavoriteThread.SyncStatus; procedure TFavoriteThread.Execute; begin - if (container.FavoriteInfo.Link) = '' then Exit; - //Modules.IncActiveConnectionCount(container.ModuleId); + if (Container.FavoriteInfo.Link) = '' then Exit; + //Modules.IncActiveConnectionCount(Container.ModuleId); try Synchronize(SyncStatus); - getInfo.mangaInfo.title := container.FavoriteInfo.Title; - getInfo.GetInfoFromURL(container.FavoriteInfo.Website, - container.FavoriteInfo.Link, DefaultRetryCount); - if container.MangaInfo = nil then - container.MangaInfo := TMangaInfo.Create; - TransferMangaInfo(container.MangaInfo, getInfo.mangaInfo); + GetInfo.mangaInfo.title := Container.FavoriteInfo.Title; + GetInfo.GetInfoFromURL(Container.FavoriteInfo.Website, + Container.FavoriteInfo.Link, DefaultRetryCount); + if Container.MangaInfo = nil then + Container.MangaInfo := TMangaInfo.Create; + TransferMangaInfo(Container.MangaInfo, GetInfo.mangaInfo); except on E: Exception do ExceptionHandle(Self, E); end; if Self.Terminated then - container.Status := STATUS_IDLE + Container.Status := STATUS_IDLE else - container.Status := STATUS_CHECKED; + Container.Status := STATUS_CHECKED; Synchronize(SyncStatus); end; @@ -223,9 +225,9 @@ procedure TFavoriteThread.DoTerminate; begin LockCreateConnection; try - Modules.DecActiveConnectionCount(container.ModuleId); - container.Thread := nil; - task.threads.Remove(Self); + Modules.DecActiveConnectionCount(Container.ModuleId); + Container.Thread := nil; + Task.Threads.Remove(Self); finally UnlockCreateConnection; end; @@ -235,13 +237,13 @@ procedure TFavoriteThread.DoTerminate; constructor TFavoriteThread.Create; begin inherited Create(True); - getInfo := TMangaInformation.Create(Self); - getInfo.isGetByUpdater := False; + GetInfo := TMangaInformation.Create(Self); + GetInfo.isGetByUpdater := False; end; destructor TFavoriteThread.Destroy; begin - getInfo.Free; + GetInfo.Free; inherited Destroy; end; @@ -278,30 +280,30 @@ procedure TFavoriteTask.Checkout; i: Integer; begin if Terminated then Exit; - if manager.Favorites.Count = 0 then Exit; - manager.CS_Favorites.Acquire; + if Manager.Favorites.Count = 0 then Exit; + Manager.CS_Favorites.Acquire; try statuscheck := 0; - for i := 0 to manager.Favorites.Count - 1 do + for i := 0 to Manager.Favorites.Count - 1 do begin if Terminated then Break; - with manager.Favorites[i] do + with Manager.Favorites[i] do if Status = STATUS_CHECK then begin LockCreateConnection; try - if (threads.Count < OptionMaxThreads) and + if (Threads.Count < OptionMaxThreads) and Modules.CanCreateConnection(ModuleId) then begin Modules.IncActiveConnectionCount(ModuleId); Thread := TFavoriteThread.Create; - threads.Add(Thread); + Threads.Add(Thread); Status := STATUS_CHECKING; with thread do begin - task := Self; - container := manager.Favorites[i]; - workCounter := i; + Task := Self; + Container := manager.Favorites[i]; + WorkId := i; Start; end; end @@ -313,14 +315,14 @@ procedure TFavoriteTask.Checkout; end; end; finally - manager.CS_Favorites.Release; + Manager.CS_Favorites.Release; end; end; procedure TFavoriteTask.DoTerminate; begin - manager.isRunning := False; - manager.taskthread := nil; + Manager.isRunning := False; + Manager.taskthread := nil; inherited DoTerminate; end; @@ -328,59 +330,59 @@ procedure TFavoriteTask.Execute; var i, cthread, cmaxthreads: Integer; begin - manager.isRunning := True; + Manager.isRunning := True; Synchronize(SyncStartChecking); try while not Terminated do begin cmaxthreads := OptionMaxThreads; - // if current thread count > max threads allowed we wait until thread count decreased - while (not Terminated) and (threads.Count >= cmaxthreads) do + // if current thread count > max Threads allowed we wait until thread count decreased + while (not Terminated) and (Threads.Count >= cmaxthreads) do Sleep(SOCKHEARTBEATRATE); Checkout; // if there is concurent connection limit applied and no more possible item to check // we will wait until thread count decreased // break wait if OptionMaxThreads changed - cthread := threads.Count; - while (not Terminated) and (threads.Count > 0) and (threads.Count = cthread) and + cthread := Threads.Count; + while (not Terminated) and (Threads.Count > 0) and (Threads.Count = cthread) and (cmaxthreads = OptionMaxThreads) do Sleep(SOCKHEARTBEATRATE); // if there is no more item need to be checked, but thread count still > 0 we will wait for it // we will also wait if there is new item pushed, so we will check it after it - while (not Terminated) and (statuscheck = 0) and (threads.Count > 0) do + while (not Terminated) and (statuscheck = 0) and (Threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); if statuscheck = 0 then Break; end; - while (not Terminated) and (threads.Count > 0) do + while (not Terminated) and (Threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); - if Terminated and (threads.Count > 0) then + if Terminated and (Threads.Count > 0) then begin LockCreateConnection; try - for i := 0 to threads.Count - 1 do - TFavoriteThread(threads[i]).Terminate; + for i := 0 to Threads.Count - 1 do + Threads[i].Terminate; finally UnlockCreateConnection; end; - while threads.Count > 0 do + while Threads.Count > 0 do Sleep(100); end; if (not Terminated) and (not isDlgCounter) then - Synchronize(manager.ShowResult); + Synchronize(Manager.ShowResult); except on E: Exception do ExceptionHandle(Self, E); end; - manager.CS_Favorites.Acquire; + Manager.CS_Favorites.Acquire; try - for i := 0 to manager.Favorites.Count - 1 do - if manager.Favorites[i].Status <> STATUS_IDLE then - manager.Favorites[i].Status := STATUS_IDLE; + for i := 0 to Manager.Favorites.Count - 1 do + if Manager.Favorites[i].Status <> STATUS_IDLE then + Manager.Favorites[i].Status := STATUS_IDLE; finally - manager.CS_Favorites.Release; + Manager.CS_Favorites.Release; end; Synchronize(SyncFinishChecking); end; @@ -394,12 +396,12 @@ procedure TFavoriteTask.UpdateBtnCaption(Cap: String); constructor TFavoriteTask.Create; begin inherited Create(True); - threads := TFPList.Create; + Threads := TFavoriteThreads.Create; end; destructor TFavoriteTask.Destroy; begin - threads.Free; + Threads.Free; inherited Destroy; end; @@ -474,7 +476,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); if taskthread = nil then begin taskthread := TFavoriteTask.Create; - taskthread.manager := Self; + taskthread.Manager := Self; taskthread.Start; end; except From b45d973c608c0d7dbc054c5130e4614323148168 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 22:46:02 +0800 Subject: [PATCH 1231/2794] downloadmanager, cleanup and use generics --- baseunits/uDownloadsManager.pas | 173 +++++++++++++++--------------- baseunits/uFavoritesManager.pas | 4 +- mangadownloader/forms/frmMain.pas | 14 +-- 3 files changed, 95 insertions(+), 96 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8ac38482e..e4f5db0a5 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -16,7 +16,7 @@ interface uses LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Classes, SysUtils, - ExtCtrls, typinfo, syncobjs, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, + ExtCtrls, typinfo, fgl, syncobjs, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils, strutils; @@ -59,6 +59,8 @@ TDownloadThread = class(TFMDThread) destructor Destroy; override; end; + TDownloadThreads = TFPGList<TDownloadThread>; + { TTaskThread } TTaskThread = class(TFMDThread) @@ -80,7 +82,7 @@ TTaskThread = class(TFMDThread) // container (for storing information) Container: TTaskContainer; // download threads - Threads: TFPList; + Threads: TDownloadThreads; constructor Create; destructor Destroy; override; function GetFileName(const AWorkId: Integer): String; @@ -133,6 +135,8 @@ TTaskContainer = class property Website: String read FWebsite write SetWebsite; end; + TTaskContainers = TFPGList<TTaskContainer>; + { TDownloadManager } TDownloadManager = class @@ -140,14 +144,13 @@ TDownloadManager = class FSortDirection: Boolean; FSortColumn: Integer; DownloadManagerFile: TIniFileRun; - function GetItems(Index: Integer): TTaskContainer; protected - function GetTaskCount: Integer; + function GetTaskCount: Integer; inline; function GetTransferRate: Integer; public CS_Task: TCriticalSection; - Containers: TFPList; - ContainersActiveTask: TFPList; + Items, + ItemsActiveTask: TTaskContainers; isRunningBackup, isFinishTaskAccessed, isRunningBackupDownloadedChaptersList, isReadyForExit: Boolean; @@ -206,7 +209,6 @@ TDownloadManager = class property SortDirection: Boolean read FSortDirection write FSortDirection; property SortColumn: Integer read FSortColumn write FSortColumn; property TransferRate: Integer read GetTransferRate; - property Items[Index: Integer]: TTaskContainer read GetItems; end; resourcestring @@ -840,7 +842,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; constructor TTaskThread.Create; begin inherited Create(True); - Threads := TFPList.Create; + Threads := TDownloadThreads.Create; FCheckAndActiveTaskFlag := True; httpCookies := ''; end; @@ -1386,7 +1388,7 @@ procedure TTaskThread.DoTerminate; Task := nil; Manager.CS_Task.Acquire; try - Manager.ContainersActiveTask.Remove(Container); + Manager.ItemsActiveTask.Remove(Container); finally Manager.CS_Task.Release; end; @@ -1472,14 +1474,9 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); { TDownloadManager } -function TDownloadManager.GetItems(Index: Integer): TTaskContainer; -begin - Result := TTaskContainer(Containers[Index]); -end; - function TDownloadManager.GetTaskCount: Integer; begin - Result := Containers.Count; + Result := Items.Count; end; function TDownloadManager.GetTransferRate: Integer; @@ -1487,11 +1484,11 @@ function TDownloadManager.GetTransferRate: Integer; i: Integer; begin Result := 0; - if ContainersActiveTask.Count = 0 then Exit; + if ItemsActiveTask.Count = 0 then Exit; CS_Task.Acquire; try - for i := 0 to ContainersActiveTask.Count - 1 do - with TTaskContainer(ContainersActiveTask[i]) do + for i := 0 to ItemsActiveTask.Count - 1 do + with ItemsActiveTask[i] do begin CS_Container.Acquire; try @@ -1522,8 +1519,8 @@ constructor TDownloadManager.Create; if DownloadedChapters.ImportFromIni(DOWNLOADEDCHAPTERS_FILE) then DeleteFileUTF8(DOWNLOADEDCHAPTERS_FILE); - Containers := TFPList.Create; - ContainersActiveTask := TFPList.Create; + Items := TTaskContainers.Create; + ItemsActiveTask := TTaskContainers.Create; isFinishTaskAccessed := False; isRunningBackup := False; isRunningBackupDownloadedChaptersList := False; @@ -1534,17 +1531,17 @@ destructor TDownloadManager.Destroy; begin CS_Task.Acquire; try - while Containers.Count > 0 do + while Items.Count > 0 do begin - TTaskContainer(Containers.Last).Free; - Containers.Remove(Containers.Last); + Items.Last.Free; + Items.Remove(Items.Last); end; finally CS_Task.Release; end; - Containers.Free; + Items.Free; DownloadManagerFile.Free; - ContainersActiveTask.Free; + ItemsActiveTask.Free; DownloadedChapters.Free; CS_Task.Free; inherited Destroy; @@ -1557,10 +1554,10 @@ procedure TDownloadManager.Restore; begin CS_Task.Acquire; try - while Containers.Count > 0 do + while Items.Count > 0 do begin - TTaskContainer(Containers.Last).Free; - Containers.Remove(Containers.Last); + Items.Last.Free; + Items.Remove(Items.Last); end; tmp := DownloadManagerFile.ReadInteger('general', 'NumberOfTasks', 0); @@ -1569,8 +1566,8 @@ procedure TDownloadManager.Restore; for i := 0 to tmp - 1 do begin // restore download task from file - Containers.Add(TTaskContainer.Create); - with DownloadManagerFile, TTaskContainer(Containers.Last) do + Items.Add(TTaskContainer.Create); + with DownloadManagerFile, Items.Last do begin tid := 'task' + IntToStr(i); Manager := Self; @@ -1658,13 +1655,13 @@ procedure TDownloadManager.Backup; EraseSection('general'); // backup - if Containers.Count > 0 then + if Items.Count > 0 then begin - WriteInteger('general', 'NumberOfTasks', Containers.Count); - for i := 0 to Containers.Count - 1 do + WriteInteger('general', 'NumberOfTasks', Items.Count); + for i := 0 to Items.Count - 1 do begin tid := 'task' + IntToStr(i); - with TTaskContainer(Containers[i]) do begin + with Items[i] do begin WriteString(tid, 'Website', DownloadInfo.Website); WriteString(tid, 'Link', DownloadInfo.Link); WriteString(tid, 'Title', DownloadInfo.Title); @@ -1725,8 +1722,8 @@ function TDownloadManager.AddTask: Integer; Result := -1; CS_Task.Acquire; try - Result := Containers.Add(TTaskContainer.Create); - with TTaskContainer(Containers[Result]) do + Result := Items.Add(TTaskContainer.Create); + with Items[Result] do begin Manager := Self; CustomFileName := OptionFilenameCustomRename; @@ -1740,17 +1737,17 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); var i, tcount: Integer; begin - if Containers.Count = 0 then Exit; + if Items.Count = 0 then Exit; CS_Task.Acquire; try tcount := 0; - for i := 0 to Containers.Count - 1 do - if TTaskContainer(Containers[i]).ThreadState then + for i := 0 to Items.Count - 1 do + if Items[i].ThreadState then Inc(tcount); if tcount < maxDLTasks then - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do + for i := 0 to Items.Count - 1 do + with Items[i] do if (tcount < maxDLTasks) and (Status = STATUS_WAIT) and Modules.CanCreateTask(ModuleId) then @@ -1785,7 +1782,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); procedure TDownloadManager.SetTaskActive(const taskID: Integer); begin - with TTaskContainer(Containers[taskID]) do + with Items[taskID] do if not ThreadState then begin Status := STATUS_WAIT; @@ -1797,10 +1794,10 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; var i, tcount: Integer; begin - if Containers.Count = 0 then Exit; + if Items.Count = 0 then Exit; tcount := 0; - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do + for i := 0 to Items.Count - 1 do + with Items[i] do if Status in [STATUS_DOWNLOAD, STATUS_PREPARE] then if (tcount < maxDLTasks) and Modules.CanCreateTask(ModuleId) then @@ -1823,7 +1820,7 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; procedure TDownloadManager.ActiveTask(const taskID: Integer); begin - with TTaskContainer(Containers[taskID]) do begin + with Items[taskID] do begin if Status = STATUS_FINISH then Exit; if not ThreadState then begin if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then begin @@ -1832,8 +1829,8 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); end; Modules.IncActiveTaskCount(ModuleId); Task := TTaskThread.Create; - Task.Container := TTaskContainer(Containers[taskID]); - ContainersActiveTask.Add(Task.Container); + Task.Container := Items[taskID]; + ItemsActiveTask.Add(Task.Container); Task.Start; end; end; @@ -1842,7 +1839,7 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); procedure TDownloadManager.StopTask(const taskID: Integer; const isCheckForActive: Boolean; isWaitFor: Boolean); begin - with TTaskContainer(Containers[taskID]) do + with Items[taskID] do begin if Status = STATUS_WAIT then begin @@ -1864,10 +1861,10 @@ procedure TDownloadManager.StartAllTasks; var i: Integer; begin - if Containers.Count > 0 then + if Items.Count > 0 then begin - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do + for i := 0 to Items.Count - 1 do + with Items[i] do if (Status <> STATUS_FINISH) and (not ThreadState) then begin Status := STATUS_WAIT; @@ -1881,8 +1878,8 @@ procedure TDownloadManager.StopAllTasks; var i: Integer; begin - if Containers.Count = 0 then Exit; - for i := 0 to Containers.Count - 1 do + if Items.Count = 0 then Exit; + for i := 0 to Items.Count - 1 do StopTask(i, False, False); end; @@ -1890,16 +1887,16 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; var i: Integer; begin - if Containers.Count > 0 then + if Items.Count > 0 then begin isReadyForExit := True; try - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do + for i := 0 to Items.Count - 1 do + with Items[i] do if ThreadState then Task.Terminate; - for i := 0 to Containers.Count - 1 do - with TTaskContainer(Containers[i]) do + for i := 0 to Items.Count - 1 do + with Items[i] do if ThreadState then Task.WaitFor; finally @@ -1912,13 +1909,13 @@ procedure TDownloadManager.RemoveTask(const taskID: Integer); begin CS_Task.Acquire; try - with TTaskContainer(Containers[taskID]) do + with Items[taskID] do if ThreadState then begin Task.Terminate; Task.WaitFor; end; - TTaskContainer(Containers[taskID]).Free; - Containers.Delete(taskID); + Items[taskID].Free; + Items.Delete(taskID); finally CS_Task.Release; end; @@ -1929,11 +1926,11 @@ procedure TDownloadManager.RemoveAllFinishedTasks; var i: Integer; begin - if Containers.Count > 0 then begin + if Items.Count > 0 then begin i := 0; - while i < Containers.Count do - if TTaskContainer(Containers[i]).Status = STATUS_FINISH then - Containers.Delete(i) + while i < Items.Count do + if Items[i].Status = STATUS_FINISH then + Items.Delete(i) else Inc(i); end; end; @@ -1943,12 +1940,12 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea i: Integer; begin Result := False; - if Containers.Count > 0 then + if Items.Count > 0 then begin CS_Task.Acquire; try - for i := 0 to Containers.Count - 1 do - if TTaskContainer(Containers[i]).Status in Stats then begin + for i := 0 to Items.Count - 1 do + if Items[i].Status in Stats then begin Result := True; Break; end; @@ -1958,12 +1955,12 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea end; end; -function CompareTaskContainer(Item1, Item2: Pointer): Integer; +function CompareTaskContainer(const Item1, Item2: TTaskContainer): Integer; - function GetStr(ARow: Pointer): String; + function GetStr(ARow: TTaskContainer): String; begin - with TTaskContainer(ARow).DownloadInfo do - case TTaskContainer(ARow).Manager.SortColumn of + with ARow.DownloadInfo do + case ARow.Manager.SortColumn of 0: Result := Title; 1: Result := Status; 2: Result := Progress; @@ -1975,33 +1972,35 @@ function CompareTaskContainer(Item1, Item2: Pointer): Integer; end; end; - function GetDateTime(ARow: Pointer): TDateTime; + function GetDateTime(ARow: TTaskContainer): TDateTime; begin - Result := TTaskContainer(ARow).DownloadInfo.DateTime; + Result := ARow.DownloadInfo.DateTime; end; -var - ItemT: Pointer; begin - if TTaskContainer(Item1).Manager.SortDirection then + if Item1.Manager.SortColumn = 6 then begin - ItemT := Item1; - Item1 := Item2; - Item2 := ItemT; - end; - if TTaskContainer(Item1).Manager.SortColumn = 6 then - Result := CompareDateTime(GetDateTime(Item1), GetDateTime(Item2)) + if Item1.Manager.SortDirection then + Result := CompareDateTime(GetDateTime(Item2), GetDateTime(Item1)) + else + Result := CompareDateTime(GetDateTime(Item1), GetDateTime(Item2)); + end else - Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); + begin + if Item1.Manager.SortDirection then + Result := NaturalCompareStr(GetStr(Item2), GetStr(Item1)) + else + Result := NaturalCompareStr(GetStr(Item1), GetStr(Item2)); + end; end; procedure TDownloadManager.Sort(const AColumn: Integer); begin - if Containers.Count < 2 then Exit; + if Items.Count < 2 then Exit; CS_Task.Acquire; try SortColumn := AColumn; - Containers.Sort(CompareTaskContainer); + Items.Sort(CompareTaskContainer); finally CS_Task.Release; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index c01726fed..077f98ef8 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -661,8 +661,8 @@ procedure TFavoriteManager.ShowResult; begin DLManager.CS_Task.Acquire; try - DLManager.containers.Add(TTaskContainer.Create); - with TTaskContainer(DLManager.Containers.Last) do begin + DLManager.Items.Add(TTaskContainer.Create); + with DLManager.Items.Last do begin Manager := DLManager; CurrentDownloadChapterPtr := 0; Website := FavoriteInfo.Website; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 72b5d1b8b..d2b1c9716 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1606,7 +1606,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); while Assigned(xNode) do begin if vtDownload.Selected[xNode] then begin DLManager.StopTask(xNode^.Index, False, True); - with TTaskContainer(DLManager.Containers[xNode^.Index]) do begin + with DLManager.Items[xNode^.Index] do begin if (Sender = miDownloadDeleteTaskData) and (ChapterName.Count > 0) then begin for i := 0 to ChapterName.Count - 1 do begin f := CleanAndExpandDirectory(DownloadInfo.SaveTo + ChapterName[i]); @@ -1621,8 +1621,8 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); end; RemoveDirUTF8(DownloadInfo.SaveTo); end; - TTaskContainer(DLManager.Containers[xNode^.Index]).Free; - DLManager.Containers.Delete(xNode^.Index); + DLManager.Items[xNode^.Index].Free; + DLManager.Items.Delete(xNode^.Index); end; end; xNode := vtDownload.GetPreviousSelected(xNode); @@ -3398,12 +3398,12 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); var i, nIndex: Cardinal; cNode: PVirtualNode; - ConTemp: TFPList; + ConTemp: TTaskContainers; begin if vtDownload.SelectedCount=0 then Exit; nIndex:=NextIndex; vtDownload.BeginUpdate; - ConTemp:=TFPList.Create; + ConTemp:=TTaskContainers.Create; DLManager.CS_Task.Acquire; try i:=0; @@ -3412,7 +3412,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); begin vtDownload.Selected[cNode]:=False; ConTemp.Add(DLManager.Items[cNode^.Index-i]); - DLManager.Containers.Delete(cNode^.Index-i); + DLManager.Items.Delete(cNode^.Index-i); if (nIndex>0) and (cNode^.Index<nIndex) then Dec(nIndex); Inc(i); @@ -3427,7 +3427,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); Inc(nIndex); if nIndex>DLManager.Count then nIndex:=DLManager.Count; - DLManager.containers.Insert(nIndex, ConTemp[i]); + DLManager.Items.Insert(nIndex, ConTemp[i]); end; cNode:=vtDownload.GetFirst; From 6c3ddadb5982381cd1e45349d7f022a37e77b222 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 22:48:23 +0800 Subject: [PATCH 1232/2794] favoritesmanager, rename --- baseunits/uFavoritesManager.pas | 110 +++++++++++++++--------------- mangadownloader/forms/frmMain.pas | 40 +++++------ 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 077f98ef8..04e235b45 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -89,9 +89,9 @@ TFavoriteManager = class CS_Favorites: TCriticalSection; FSortColumn: Integer; FSortDirection, FIsAuto, FIsRunning: Boolean; - function GetFavoritesCount: Integer; + function GetFavoritesCount: Integer; inline; public - Favorites: TFavoriteContainers; + Items: TFavoriteContainers; favoritesFile: TIniFileRun; taskthread: TFavoriteTask; DLManager: TDownloadManager; @@ -280,14 +280,14 @@ procedure TFavoriteTask.Checkout; i: Integer; begin if Terminated then Exit; - if Manager.Favorites.Count = 0 then Exit; + if Manager.Items.Count = 0 then Exit; Manager.CS_Favorites.Acquire; try statuscheck := 0; - for i := 0 to Manager.Favorites.Count - 1 do + for i := 0 to Manager.Items.Count - 1 do begin if Terminated then Break; - with Manager.Favorites[i] do + with Manager.Items[i] do if Status = STATUS_CHECK then begin LockCreateConnection; @@ -302,7 +302,7 @@ procedure TFavoriteTask.Checkout; with thread do begin Task := Self; - Container := manager.Favorites[i]; + Container := manager.Items[i]; WorkId := i; Start; end; @@ -378,9 +378,9 @@ procedure TFavoriteTask.Execute; end; Manager.CS_Favorites.Acquire; try - for i := 0 to Manager.Favorites.Count - 1 do - if Manager.Favorites[i].Status <> STATUS_IDLE then - Manager.Favorites[i].Status := STATUS_IDLE; + for i := 0 to Manager.Items.Count - 1 do + if Manager.Items[i].Status <> STATUS_IDLE then + Manager.Items[i].Status := STATUS_IDLE; finally Manager.CS_Favorites.Release; end; @@ -409,7 +409,7 @@ destructor TFavoriteTask.Destroy; function TFavoriteManager.GetFavoritesCount: Integer; begin - Result := Favorites.Count; + Result := Items.Count; end; constructor TFavoriteManager.Create; @@ -419,7 +419,7 @@ constructor TFavoriteManager.Create; CS_Favorites := TCriticalSection.Create; isRunning := False; favoritesFile := TIniFileRun.Create(FAVORITES_FILE); - Favorites := TFavoriteContainers.Create; + Items := TFavoriteContainers.Create; Restore; end; @@ -427,14 +427,14 @@ destructor TFavoriteManager.Destroy; begin Backup; favoritesFile.Free; - if Favorites.Count > 0 then begin + if Items.Count > 0 then begin StopChekForNewChapter; - while Favorites.Count > 0 do begin - Favorites.Last.Free; - Favorites.Remove(Favorites.Last); + while Items.Count > 0 do begin + Items.Last.Free; + Items.Remove(Items.Last); end; end; - Favorites.Free; + Items.Free; CS_Favorites.Free; inherited Destroy; end; @@ -447,7 +447,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); try if FavoriteIndex > -1 then begin - with Favorites[FavoriteIndex] do + with Items[FavoriteIndex] do if Status = STATUS_IDLE then begin Status := STATUS_CHECK; @@ -465,8 +465,8 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); begin CS_Favorites.Acquire; try - for i := 0 to Favorites.Count - 1 do - with Favorites[i] do + for i := 0 to Items.Count - 1 do + with Items[i] do if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then Status := STATUS_CHECK; finally @@ -490,7 +490,7 @@ procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; FavoriteIndex if isRunning then if FavoriteIndex > -1 then begin - with Favorites[FavoriteIndex] do begin + with Items[FavoriteIndex] do begin if Thread <> nil then begin Thread.Terminate; @@ -530,8 +530,8 @@ procedure TFavoriteManager.ShowResult; numOfMangaNewChapters := 0; numOfCompleted := 0; counter := 0; - while counter < Favorites.Count do - with Favorites[counter] do try + while counter < Items.Count do + with Items[counter] do try if Assigned(MangaInfo) then if MangaInfo.chapterLinks.Count > 0 then begin @@ -603,16 +603,16 @@ procedure TFavoriteManager.ShowResult; if LNCResult = ncrDownload then begin counter := 0; - while counter < Favorites.Count do + while counter < Items.Count do begin favDelete := False; - with Favorites[counter] do + with Items[counter] do if Assigned(NewMangaInfo) and (NewMangaInfo.chapterLinks.Count = 0) and (NewMangaInfo.status = '0') then begin - Favorites[counter].Free; - Favorites.Delete(counter); + Items[counter].Free; + Items.Delete(counter); favDelete := True; end; if not favDelete then @@ -653,9 +653,9 @@ procedure TFavoriteManager.ShowResult; while DLManager.isRunningBackup do Sleep(100); counter := 0; - while counter < Favorites.Count do + while counter < Items.Count do begin - with Favorites[counter] do + with Items[counter] do if Assigned(NewMangaInfo) and (NewMangaInfo.chapterLinks.Count > 0) then begin @@ -724,9 +724,9 @@ procedure TFavoriteManager.ShowResult; finally //free used memory counter := 0; - while counter < Favorites.Count do + while counter < Items.Count do begin - with Favorites[counter] do begin + with Items[counter] do begin if Assigned(MangaInfo) then FreeAndNil(MangaInfo); if Assigned(NewMangaInfo) then @@ -750,9 +750,9 @@ function TFavoriteManager.IsMangaExist(const ATitle, AWebsite: String): Boolean; i: Integer; begin Result := False; - if Favorites.Count > 0 then - for i := 0 to Favorites.Count - 1 do - with Favorites[i].FavoriteInfo do + if Items.Count > 0 then + for i := 0 to Items.Count - 1 do + with Items[i].FavoriteInfo do if SameText(ATitle, Title) and SameText(AWebsite, Website) then Exit(True); end; @@ -762,9 +762,9 @@ function TFavoriteManager.IsMangaExistURL(const AWebsite, AURL: String): Boolean i: Integer; begin Result := False; - if Favorites.Count > 0 then - for i := 0 to Favorites.Count - 1 do - with Favorites[i].FavoriteInfo do + if Items.Count > 0 then + for i := 0 to Items.Count - 1 do + with Items[i].FavoriteInfo do if SameText(AWebsite, Website) and SameText(AURL, Link) then Exit(True); end; @@ -775,8 +775,8 @@ procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapter if IsMangaExist(ATitle, AWebsite) then Exit; CS_Favorites.Acquire; try - Favorites.Add(TFavoriteContainer.Create); - with Favorites.Last do begin + Items.Add(TFavoriteContainer.Create); + with Items.Last do begin Manager := Self; Website := AWebsite; with FavoriteInfo do begin @@ -805,8 +805,8 @@ procedure TFavoriteManager.AddMerge(const ATitle, ACurrentChapter, ADownloadedCh Exit; CS_Favorites.Acquire; try - Favorites.Add(TFavoriteContainer.Create); - with Favorites.Last do begin + Items.Add(TFavoriteContainer.Create); + with Items.Last do begin Manager := Self; Website := AWebsite; with FavoriteInfo do begin @@ -868,12 +868,12 @@ procedure TFavoriteManager.MergeWith(const APath: String); procedure TFavoriteManager.Remove(const pos: Integer; const isBackup: Boolean); begin - if (not isRunning) and (pos < Favorites.Count) then + if (not isRunning) and (pos < Items.Count) then begin CS_Favorites.Acquire; try - Favorites[pos].Free; - Favorites.Delete(pos); + Items[pos].Free; + Items.Delete(pos); if isBackup then Backup; finally @@ -890,8 +890,8 @@ procedure TFavoriteManager.Restore; if c > 0 then for i := 0 to c - 1 do begin - Favorites.Add(TFavoriteContainer.Create); - with Favorites.Last do begin + Items.Add(TFavoriteContainer.Create); + with Items.Last do begin Manager := Self; with favoritesFile, FavoriteInfo do begin Title := ReadString(IntToStr(i), 'Title', ''); @@ -917,10 +917,10 @@ procedure TFavoriteManager.Backup; for i := 0 to ReadInteger('general', 'NumberOfFavorites', 0) - 1 do EraseSection(IntToStr(i)); - WriteInteger('general', 'NumberOfFavorites', Favorites.Count); - if Favorites.Count > 0 then - for i := 0 to Favorites.Count - 1 do - with Favorites[i].FavoriteInfo do begin + WriteInteger('general', 'NumberOfFavorites', Items.Count); + if Items.Count > 0 then + for i := 0 to Items.Count - 1 do + with Items[i].FavoriteInfo do begin WriteString(IntToStr(i), 'Title', Title); WriteString(IntToStr(i), 'CurrentChapter', currentChapter); WriteString(IntToStr(i), 'DownloadedChapterList', downloadedChapterList); @@ -963,9 +963,9 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St try p := -1; //locate the link - if Favorites.Count > 1 then - for i := 0 to Favorites.Count - 1 do - with Favorites[i].FavoriteInfo do + if Items.Count > 1 then + for i := 0 to Items.Count - 1 do + with Items[i].FavoriteInfo do if SameText(AWebsite, Website) and SameText(Alink, Link) then begin p := i; @@ -990,7 +990,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St end; //merge the links - with Favorites[p].FavoriteInfo do begin + with Items[p].FavoriteInfo do begin downloadedChapterList := downloadedChapterList + SetParams(ch); currentChapter := IntToStr(dlCh.Count + ch.Count); end; @@ -1028,11 +1028,11 @@ function CompareFavoriteContainer(const Item1, Item2: TFavoriteContainer): Integ procedure TFavoriteManager.Sort(const AColumn: Integer); begin - if Favorites.Count < 2 then Exit; + if Items.Count < 2 then Exit; CS_Favorites.Acquire; try SortColumn := AColumn; - Favorites.Sort(CompareFavoriteContainer); + Items.Sort(CompareFavoriteContainer); finally CS_Favorites.Release; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d2b1c9716..0ffbea187 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1698,7 +1698,7 @@ procedure TMainForm.miFavoritesDownloadAllClick(Sender: TObject); for i := 0 to vtFavorites.SelectedCount - 1 do begin if vtFavorites.Selected[xNode] then - with FavoriteManager.Favorites[xNode^.Index].FavoriteInfo do + with FavoriteManager.Items[xNode^.Index].FavoriteInfo do SilentThreadManager.Add(MD_DownloadAll, Website, Title, Link, SaveTo); xNode := vtFavorites.GetNextSelected(xNode); end; @@ -1741,9 +1741,9 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); rmInformation.Lines.Add('Loading ...'); clbChapterList.Clear; - website := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.Website; - link := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.link; - title := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.Title; + website := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Website; + link := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.link; + title := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Title; if isGetMangaInfos then begin @@ -2572,13 +2572,13 @@ procedure TMainForm.miFavoritesChangeCurrentChapterClick(Sender: TObject); end; if not Assigned(vtFavorites.FocusedNode) then Exit; - s := FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter; + s := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter; repeat if InputQuery('', RS_DlgTypeInNewChapter, s) then until TryStrToInt(s, i); - if s <> FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter then + if s <> FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter then begin - FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter := s; + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.currentChapter := s; UpdateVtFavorites; FavoriteManager.Backup; end; @@ -2595,10 +2595,10 @@ procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); if not Assigned(vtFavorites.FocusedNode) then Exit; if InputQuery('', RS_DlgTypeInNewSavePath, - FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo) then + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo) then begin - FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := - CorrectFilePath(FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := + CorrectFilePath(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); UpdateVtFavorites; FavoriteManager.Backup; end; @@ -2987,7 +2987,7 @@ procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then OpenDocument(ChompPathDelim( - FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); end; procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); @@ -3001,7 +3001,7 @@ procedure TMainForm.miFavoritesOpenWithClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then OpenWithExternalProgramChapters( - FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); end; procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); @@ -3142,7 +3142,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); repeat if Assigned(xNode) then begin - if FavoriteManager.Favorites[xNode^.Index].Status in Stats then + if FavoriteManager.Items[xNode^.Index].Status in Stats then begin Result := True; Break; @@ -3174,12 +3174,12 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesStopCheckNewChapter.Visible := SelectedStatusPresent([STATUS_CHECK, STATUS_CHECKING]); miFavoritesViewInfos.Enabled := True; - miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.Favorites[ + miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.Items[ vtFavorites.FocusedNode^.Index].FavoriteInfo.Link) <> ''); miFavoritesDelete.Enabled := True; miFavoritesChangeSaveTo.Enabled := True; miFavoritesOpenFolder.Enabled := - DirectoryExistsUTF8(FavoriteManager.Favorites[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + DirectoryExistsUTF8(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); miFavoritesOpenWith.Enabled := miFavoritesOpenFolder.Enabled; end else @@ -3694,7 +3694,7 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; Data := Sender.GetNodeData(Node); if Assigned(Data) then begin - with FavoriteManager.Favorites[Node^.Index] do + with FavoriteManager.Items[Node^.Index] do begin if Trim(FavoriteInfo.Link) = '' then begin @@ -3740,7 +3740,7 @@ procedure TMainForm.vtFavoritesGetHint(Sender: TBaseVirtualTree; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); begin if Node^.Index>=FavoriteManager.Count then Exit; - with FavoriteManager.Favorites[Node^.Index].FavoriteInfo do + with FavoriteManager.Items[Node^.Index].FavoriteInfo do case Column of 1: if Trim(Link)='' then HintText:=RS_HintFavoriteProblem else HintText:=Title; @@ -3756,10 +3756,10 @@ procedure TMainForm.vtFavoritesGetImageIndex(Sender: TBaseVirtualTree; begin if vtFavorites.Header.Columns[Column].Position<>1 then Exit; if Node^.Index>=FavoriteManager.Count then Exit; - if Trim(FavoriteManager.Favorites[Node^.Index].FavoriteInfo.Link)='' then + if Trim(FavoriteManager.Items[Node^.Index].FavoriteInfo.Link)='' then ImageIndex:=16 else - case FavoriteManager.Favorites[Node^.Index].Status of + case FavoriteManager.Items[Node^.Index].Status of STATUS_CHECK : ImageIndex:=19; STATUS_CHECKING : ImageIndex:=12; STATUS_CHECKED : ImageIndex:=20; @@ -3775,7 +3775,7 @@ procedure TMainForm.vtFavoritesGetText(Sender: TBaseVirtualTree; var CellText: String); begin if Node^.Index>=FavoriteManager.Count then Exit; - with FavoriteManager.Favorites[Node^.Index].FavoriteInfo do + with FavoriteManager.Items[Node^.Index].FavoriteInfo do case Column of 0: CellText:=IntToStr(Node^.Index+1); 1: CellText:=Title; From a21c3c5636980d0e83ddcda06c6d8fde353642f2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 22:56:40 +0800 Subject: [PATCH 1233/2794] silentthread, rename and use generics --- baseunits/uSilentThread.pas | 69 +++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 7f17f218e..151518b47 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -15,7 +15,7 @@ interface uses - Classes, SysUtils, uBaseUnit, uData, uFMDThread, uDownloadsManager, + Classes, SysUtils, fgl, uBaseUnit, uData, uFMDThread, uDownloadsManager, WebsiteModules, FMDOptions, httpsendthread, LazFileUtils; type @@ -72,6 +72,9 @@ TSilentThreadManagerThread = class(TFMDThread) destructor Destroy; override; end; + TSilentThreadMetaDatas = TFPGList<TSilentThreadMetaData>; + TSilentThreads = TFPGList<TSilentThread>; + { TSilentThreadManager } TSilentThreadManager = class @@ -82,8 +85,8 @@ TSilentThreadManager = class procedure StartManagerThread; procedure Checkout(Index: Integer); public - MetaData: TFPList; - Threads: TFPList; + MetaDatas: TSilentThreadMetaDatas; + Threads: TSilentThreads; procedure Add(AType: TMetaDataType; AWebsite, AManga, AURL: String; ASavePath: String = ''); procedure StopAll(WaitFor: Boolean = True); @@ -110,14 +113,14 @@ procedure TSilentThreadManagerThread.Checkout; i: Integer; begin if Terminated then Exit; - if Manager.MetaData.Count = 0 then Exit; + if Manager.MetaDatas.Count = 0 then Exit; with Manager do begin i := 0; - while i < MetaData.Count do + while i < MetaDatas.Count do begin if Terminated then Break; - with TSilentThreadMetaData(MetaData[i]) do + with MetaDatas[i] do if (Threads.Count < OptionMaxThreads) and Modules.CanCreateConnection(ModuleId) then begin @@ -140,7 +143,7 @@ procedure TSilentThreadManagerThread.Execute; if Manager = nil then Exit; Self.Checkout; with manager do - while (not Terminated) and (MetaData.Count > 0) do + while (not Terminated) and (MetaDatas.Count > 0) do begin Sleep(SOCKHEARTBEATRATE); while (not Terminated) and (Threads.Count >= OptionMaxThreads) do @@ -159,7 +162,7 @@ destructor TSilentThreadManagerThread.Destroy; function TSilentThreadManager.GetItemCount: Integer; begin - Result := MetaData.Count + Threads.Count; + Result := MetaDatas.Count + Threads.Count; end; procedure TSilentThreadManager.StartManagerThread; @@ -178,7 +181,7 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; if not ((AType = MD_AddToFavorites) and (MainForm.FavoriteManager.IsMangaExist(AManga, AWebsite))) then begin - MetaData.Add(TSilentThreadMetaData.Create( + MetaDatas.Add(TSilentThreadMetaData.Create( AType, AWebsite, AManga, AURL, ASavePath)); if not FLockAdd then begin @@ -190,23 +193,23 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; procedure TSilentThreadManager.Checkout(Index: Integer); begin - if (Index < 0) or (Index >= MetaData.Count) then Exit; - Modules.IncActiveConnectionCount(TSilentThreadMetaData(MetaData[Index]).ModuleId); - case TSilentThreadMetaData(MetaData[Index]).MetaDataType of + if (Index < 0) or (Index >= MetaDatas.Count) then Exit; + Modules.IncActiveConnectionCount(MetaDatas[Index].ModuleId); + case MetaDatas[Index].MetaDataType of MD_DownloadAll: Threads.Add(TSilentThread.Create); MD_AddToFavorites: Threads.Add(TSilentAddToFavThread.Create); end; - with TSilentThread(Threads.Last) do + with Threads.Last do begin Manager := Self; - website := TSilentThreadMetaData(MetaData[Index]).Website; - title := TSilentThreadMetaData(MetaData[Index]).Title; - URL := TSilentThreadMetaData(MetaData[Index]).URL; - SavePath := TSilentThreadMetaData(MetaData[Index]).SaveTo; - ModuleId := TSilentThreadMetaData(MetaData[Index]).ModuleId; + website := MetaDatas[Index].Website; + title := MetaDatas[Index].Title; + URL := MetaDatas[Index].URL; + SavePath := MetaDatas[Index].SaveTo; + ModuleId := MetaDatas[Index].ModuleId; Start; - TSilentThreadMetaData(MetaData[Index]).Free; - MetaData.Delete(Index); + MetaDatas[Index].Free; + MetaDatas.Delete(Index); end; end; @@ -214,12 +217,12 @@ procedure TSilentThreadManager.StopAll(WaitFor: Boolean); var i: Integer; begin - if MetaData.Count or Threads.Count > 0 then + if MetaDatas.Count or Threads.Count > 0 then begin - while MetaData.Count > 0 do + while MetaDatas.Count > 0 do begin - TSilentThreadMetaData(MetaData.Last).Free; - MetaData.Remove(MetaData.Last); + MetaDatas.Last.Free; + MetaDatas.Remove(MetaDatas.Last); end; if Assigned(FManagerThread) then begin @@ -229,7 +232,7 @@ procedure TSilentThreadManager.StopAll(WaitFor: Boolean); end; if Threads.Count > 0 then for i := 0 to Threads.Count - 1 do - TSilentThread(Threads[i]).Terminate; + Threads[i].Terminate; if WaitFor then while ItemCount > 0 do Sleep(100); @@ -253,7 +256,7 @@ procedure TSilentThreadManager.BeginAdd; procedure TSilentThreadManager.EndAdd; begin FLockAdd := False; - if MetaData.Count > 0 then + if MetaDatas.Count > 0 then begin StartManagerThread; UpdateLoadStatus; @@ -263,8 +266,8 @@ procedure TSilentThreadManager.EndAdd; constructor TSilentThreadManager.Create; begin inherited Create; - MetaData := TFPList.Create; - Threads := TFPList.Create; + MetaDatas := TSilentThreadMetaDatas.Create; + Threads := TSilentThreads.Create; FLockAdd := False; end; @@ -274,18 +277,18 @@ destructor TSilentThreadManager.Destroy; begin if ItemCount > 0 then begin - while MetaData.Count > 0 do + while MetaDatas.Count > 0 do begin - TSilentThreadMetaData(MetaData.Last).Free; - MetaData.Remove(MetaData.Last); + MetaDatas.Last.Free; + MetaDatas.Remove(MetaDatas.Last); end; if Threads.Count > 0 then for i := 0 to Threads.Count - 1 do - TSilentThread(Threads[i]).Terminate; + Threads[i].Terminate; while ItemCount > 0 do Sleep(100); end; - MetaData.Free; + MetaDatas.Free; Threads.Free; inherited Destroy; end; From e8b65a3e19d08d0dbe206ec39c24913251594d8f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Jun 2016 23:18:28 +0800 Subject: [PATCH 1234/2794] downloadmanager, fixed customfilename always follow optionfilenamecustomerename fixed #291 --- baseunits/uDownloadsManager.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index e4f5db0a5..b4516cf3f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1156,6 +1156,8 @@ procedure TTaskThread.Execute; else DynamicPageLink := False; + if Trim(Container.CustomFileName) = '' then + Container.CustomFileName := OptionFilenameCustomRename; if Trim(Container.CustomFileName) = '' then Container.CustomFileName := DEFAULT_FILENAME_CUSTOMRENAME; @@ -1447,6 +1449,7 @@ constructor TTaskContainer.Create; WorkCounter := 0; CurrentPageNumber := 0; CurrentDownloadChapterPtr := 0; + CustomFileName := OptionFilenameCustomRename; end; destructor TTaskContainer.Destroy; @@ -1724,10 +1727,7 @@ function TDownloadManager.AddTask: Integer; try Result := Items.Add(TTaskContainer.Create); with Items[Result] do - begin Manager := Self; - CustomFileName := OptionFilenameCustomRename; - end; finally CS_Task.Release; end; From 9226829076ccccac49efdc944dee929399d436db Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 13 Jun 2016 07:12:20 +0800 Subject: [PATCH 1235/2794] fmdthread, fixed sometimes access violation, customterminate call with synchonize --- baseunits/uFMDThread.pas | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/baseunits/uFMDThread.pas b/baseunits/uFMDThread.pas index 0719fc019..c9bb71393 100644 --- a/baseunits/uFMDThread.pas +++ b/baseunits/uFMDThread.pas @@ -21,12 +21,13 @@ TFMDThread = class(TThread) private FOnCustomTerminate: TNotifyEvent; function GetTerminated: Boolean; + procedure CallCustomTerminate; protected procedure DoTerminate; override; public constructor Create(CreateSuspended: Boolean = True); - property IsTerminated: Boolean read GetTerminated; procedure Terminate; + property IsTerminated: Boolean read GetTerminated; property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; end; @@ -37,6 +38,11 @@ function TFMDThread.GetTerminated: Boolean; Result := Self.Terminated; end; +procedure TFMDThread.CallCustomTerminate; +begin + FOnCustomTerminate(Self); +end; + procedure TFMDThread.DoTerminate; begin if (FatalException <> nil) and (FatalException is Exception) then @@ -54,7 +60,7 @@ procedure TFMDThread.Terminate; begin inherited Terminate; if Assigned(FOnCustomTerminate) then - FOnCustomTerminate(Self); + Synchronize(CallCustomTerminate); end; end. From 6111e15f19e92f1f245928600dafa2d3392cc395 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 13 Jun 2016 20:55:10 +0800 Subject: [PATCH 1236/2794] favoritemanager, check new chapters at favoritethread check, possible to immedietly show status, cleanup and fix --- baseunits/uFavoritesManager.pas | 585 +++++++++++++++++--------------- 1 file changed, 308 insertions(+), 277 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 04e235b45..4512ef87f 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, fgl, Dialogs, IniFiles, syncobjs, lazutf8classes, LazFileUtils, + Classes, SysUtils, fgl, Dialogs, IniFiles, lazutf8classes, LazFileUtils, FileUtil, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, FMDOptions, httpsendthread, SimpleException; @@ -29,11 +29,9 @@ TFavoriteThread = class(TFMDThread) procedure DoTerminate; override; public WorkId: Cardinal; - GetInfo: TMangaInformation; Task: TFavoriteTask; Container: TfavoriteContainer; constructor Create; - destructor Destroy; override; end; TFavoriteThreads = TFPGList<TFavoriteThread>; @@ -43,15 +41,16 @@ TFavoriteThread = class(TFMDThread) TFavoriteTask = class(TFMDThread) private FBtnCaption: String; - statuscheck: Integer; + FPendingCount: Integer; protected procedure SyncStartChecking; procedure SyncFinishChecking; procedure SyncUpdateBtnCaption; procedure Checkout; - procedure DoTerminate; override; procedure Execute; override; + procedure DoTerminate; override; public + CS_Threads: TRTLCriticalSection; Manager: TFavoriteManager; Threads: TFavoriteThreads; procedure UpdateBtnCaption(Cap: String); @@ -68,7 +67,6 @@ TFavoriteContainer = class procedure SetWebsite(AValue: String); public FavoriteInfo: TFavoriteInfo; - MangaInfo: TMangaInfo; NewMangaInfo: TMangaInfo; NewMangaInfoChaptersPos: TCardinalList; Thread: TFavoriteThread; @@ -86,7 +84,7 @@ TFavoriteContainer = class TFavoriteManager = class private - CS_Favorites: TCriticalSection; + CS_Favorites: TRTLCriticalSection; FSortColumn: Integer; FSortDirection, FIsAuto, FIsRunning: Boolean; function GetFavoritesCount: Integer; inline; @@ -118,7 +116,7 @@ TFavoriteManager = class // Merge a FFavorites.ini with another FFavorites.ini procedure MergeWith(const APath: String); // Remove a manga from FFavorites - procedure Remove(const pos: Integer; const isBackup: Boolean = True); + procedure Remove(const Pos: Integer; const isBackup: Boolean = True); // Restore information from FFavorites.ini procedure Restore; // Backup to FFavorites.ini @@ -181,12 +179,11 @@ destructor TFavoriteContainer.Destroy; Thread.WaitFor; Thread := nil; end; - if Assigned(MangaInfo) then - MangaInfo.Free; if Assigned(NewMangaInfo) then + begin NewMangaInfo.Free; - if Assigned(NewMangaInfoChaptersPos) then NewMangaInfoChaptersPos.Free; + end; inherited Destroy; end; @@ -199,52 +196,97 @@ procedure TFavoriteThread.SyncStatus; end; procedure TFavoriteThread.Execute; +var + DLChapters: TStringList; + i: Integer; begin if (Container.FavoriteInfo.Link) = '' then Exit; - //Modules.IncActiveConnectionCount(Container.ModuleId); - try - Synchronize(SyncStatus); - GetInfo.mangaInfo.title := Container.FavoriteInfo.Title; - GetInfo.GetInfoFromURL(Container.FavoriteInfo.Website, - Container.FavoriteInfo.Link, DefaultRetryCount); - if Container.MangaInfo = nil then - Container.MangaInfo := TMangaInfo.Create; - TransferMangaInfo(Container.MangaInfo, GetInfo.mangaInfo); - except - on E: Exception do - ExceptionHandle(Self, E); - end; - if Self.Terminated then - Container.Status := STATUS_IDLE - else - Container.Status := STATUS_CHECKED; + Synchronize(SyncStatus); + with Container do + try + // get new manga info + with TMangaInformation.Create(Self) do + try + isGetByUpdater := False; + mangaInfo.title := FavoriteInfo.Title; + GetInfoFromURL(FavoriteInfo.Website, FavoriteInfo.Link, DefaultRetryCount); + if not Terminated then + begin + NewMangaInfoChaptersPos := TCardinalList.Create; + NewMangaInfo := mangaInfo; + mangaInfo := nil; + end; + finally + Free; + end; + + // check for new chapters + if (not Terminated) and Assigned(NewMangaInfo) then + begin + if NewMangaInfo.chapterLinks.Count > 0 then + try + DLChapters := TStringList.Create; + DLChapters.Sorted := False; + GetParams(DLChapters, FavoriteInfo.DownloadedChapterList); + DLChapters.Sorted := True; + for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do + if DLChapters.IndexOf(NewMangaInfo.chapterLinks[i]) > -1 then + NewMangaInfoChaptersPos.Add(i); + finally + DLChapters.Free; + end; + + // free unneeded objects + if (NewMangaInfoChaptersPos.Count = 0) and + (NewMangaInfo.status <> MangaInfo_StatusCompleted) then + begin + FreeAndNil(NewMangaInfo); + FreeAndNil(NewMangaInfoChaptersPos); + end; + end; + except + on E: Exception do + ExceptionHandle(Self, E); + end; end; procedure TFavoriteThread.DoTerminate; begin - LockCreateConnection; + EnterCriticalsection(Container.Manager.CS_Favorites); try - Modules.DecActiveConnectionCount(Container.ModuleId); + if Terminated then + begin + Container.Status := STATUS_IDLE; + // free unused objects + if Assigned(Container.NewMangaInfo) then + begin + FreeAndNil(Container.NewMangaInfo); + FreeAndNil(Container.NewMangaInfoChaptersPos); + end; + end + else + Container.Status := STATUS_CHECKED; Container.Thread := nil; - Task.Threads.Remove(Self); + + EnterCriticalsection(Task.CS_Threads); + try + Modules.DecActiveConnectionCount(Container.ModuleId); + Task.Threads.Remove(Self); + finally + LeaveCriticalsection(Task.CS_Threads); + end; finally - UnlockCreateConnection; + LeaveCriticalsection(Container.Manager.CS_Favorites); end; + if not Terminated then + Synchronize(SyncStatus); inherited DoTerminate; end; constructor TFavoriteThread.Create; begin inherited Create(True); - GetInfo := TMangaInformation.Create(Self); - GetInfo.isGetByUpdater := False; -end; - -destructor TFavoriteThread.Destroy; -begin - GetInfo.Free; - inherited Destroy; end; { TFavoriteTask } @@ -261,13 +303,21 @@ procedure TFavoriteTask.SyncStartChecking; procedure TFavoriteTask.SyncFinishChecking; begin - with MainForm do begin + with MainForm do + begin btCancelFavoritesCheck.Visible := False; - btFavoritesCheckNewChapter.Width := - btFavoritesCheckNewChapter.Width + btCancelFavoritesCheck.Width + 6; + btFavoritesCheckNewChapter.Width := btFavoritesCheckNewChapter.Width + + btCancelFavoritesCheck.Width + 6; btFavoritesCheckNewChapter.Caption := RS_BtnCheckFavorites; vtFavorites.Repaint; end; + try + EnterCriticalsection(Manager.CS_Favorites); + Manager.isRunning := False; + Manager.taskthread := nil; + finally + LeaveCriticalsection(Manager.CS_Favorites); + end; end; procedure TFavoriteTask.SyncUpdateBtnCaption; @@ -281,54 +331,41 @@ procedure TFavoriteTask.Checkout; begin if Terminated then Exit; if Manager.Items.Count = 0 then Exit; - Manager.CS_Favorites.Acquire; - try - statuscheck := 0; - for i := 0 to Manager.Items.Count - 1 do - begin - if Terminated then Break; - with Manager.Items[i] do - if Status = STATUS_CHECK then + + FPendingCount := 0; + for i := 0 to Manager.Items.Count - 1 do + begin + if Terminated then Break; + with Manager.Items[i] do + if (Status = STATUS_CHECK) then + begin + if (Threads.Count < OptionMaxThreads) and + Modules.CanCreateConnection(ModuleId) then begin - LockCreateConnection; + EnterCriticalsection(CS_Threads); try - if (Threads.Count < OptionMaxThreads) and - Modules.CanCreateConnection(ModuleId) then - begin - Modules.IncActiveConnectionCount(ModuleId); - Thread := TFavoriteThread.Create; - Threads.Add(Thread); - Status := STATUS_CHECKING; - with thread do - begin - Task := Self; - Container := manager.Items[i]; - WorkId := i; - Start; - end; - end - else - Inc(statuscheck); + Modules.IncActiveConnectionCount(ModuleId); + Status := STATUS_CHECKING; + Threads.Add(TFavoriteThread.Create); + Thread := Threads.Last; + Thread.Task := Self; + Thread.Container := Manager.Items[i]; + Thread.WorkId := i; + Thread.Start; finally - UnlockCreateConnection; - end; - end; - end; - finally - Manager.CS_Favorites.Release; + LeaveCriticalsection(CS_Threads); + end + end + else + Inc(FPendingCount); + end; end; end; -procedure TFavoriteTask.DoTerminate; -begin - Manager.isRunning := False; - Manager.taskthread := nil; - inherited DoTerminate; -end; - procedure TFavoriteTask.Execute; var - i, cthread, cmaxthreads: Integer; + cthread, + cmaxthreads: Integer; begin Manager.isRunning := True; Synchronize(SyncStartChecking); @@ -349,42 +386,66 @@ procedure TFavoriteTask.Execute; Sleep(SOCKHEARTBEATRATE); // if there is no more item need to be checked, but thread count still > 0 we will wait for it // we will also wait if there is new item pushed, so we will check it after it - while (not Terminated) and (statuscheck = 0) and (Threads.Count > 0) do + while (not Terminated) and (FPendingCount = 0) and (Threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); - if statuscheck = 0 then Break; + if FPendingCount = 0 then Break; end; while (not Terminated) and (Threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); - - if Terminated and (Threads.Count > 0) then - begin - LockCreateConnection; - try - for i := 0 to Threads.Count - 1 do - Threads[i].Terminate; - finally - UnlockCreateConnection; - end; - while Threads.Count > 0 do - Sleep(100); - end; - - if (not Terminated) and (not isDlgCounter) then - Synchronize(Manager.ShowResult); except on E: Exception do ExceptionHandle(Self, E); end; - Manager.CS_Favorites.Acquire; +end; + +procedure TFavoriteTask.DoTerminate; +var + i: Integer; +begin + // reset all status + EnterCriticalsection(Manager.CS_Favorites); try for i := 0 to Manager.Items.Count - 1 do - if Manager.Items[i].Status <> STATUS_IDLE then - Manager.Items[i].Status := STATUS_IDLE; + Manager.Items[i].Status := STATUS_IDLE; finally - Manager.CS_Favorites.Release; + LeaveCriticalsection(Manager.CS_Favorites); end; + + // terminate all threads and wait + EnterCriticalsection(CS_Threads); + try + if Threads.Count > 0 then + for i := 0 to Threads.Count - 1 do + Threads[i].Terminate; + finally + LeaveCriticalsection(CS_Threads); + end; + while Threads.Count > 0 do + Sleep(100); + + // reset the ui Synchronize(SyncFinishChecking); + + if (not Terminated) and (not isDlgCounter) then + Synchronize(Manager.ShowResult) + else + // free unused unit + begin + EnterCriticalsection(Manager.CS_Favorites); + try + for i := 0 to Manager.Items.Count - 1 do + with Manager.Items[i] do + if Assigned(NewMangaInfo) then + begin + FreeAndNil(NewMangaInfo); + FreeAndNil(NewMangaInfoChaptersPos); + end; + finally + LeaveCriticalsection(Manager.CS_Favorites); + end; + end; + inherited DoTerminate; end; procedure TFavoriteTask.UpdateBtnCaption(Cap: String); @@ -396,12 +457,14 @@ procedure TFavoriteTask.UpdateBtnCaption(Cap: String); constructor TFavoriteTask.Create; begin inherited Create(True); + InitCriticalSection(CS_Threads); Threads := TFavoriteThreads.Create; end; destructor TFavoriteTask.Destroy; begin Threads.Free; + DoneCriticalsection(CS_Threads); inherited Destroy; end; @@ -416,7 +479,7 @@ constructor TFavoriteManager.Create; begin inherited Create; ForceDirectoriesUTF8(WORK_FOLDER); - CS_Favorites := TCriticalSection.Create; + InitCriticalSection(CS_Favorites); isRunning := False; favoritesFile := TIniFileRun.Create(FAVORITES_FILE); Items := TFavoriteContainers.Create; @@ -435,7 +498,7 @@ destructor TFavoriteManager.Destroy; end; end; Items.Free; - CS_Favorites.Free; + DoneCriticalsection(CS_Favorites); inherited Destroy; end; @@ -452,7 +515,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); begin Status := STATUS_CHECK; if Assigned(taskthread) then - taskthread.statuscheck := InterLockedIncrement(taskthread.statuscheck); + taskthread.FPendingCount := InterLockedIncrement(taskthread.FPendingCount); end; end else @@ -463,14 +526,14 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); end else begin - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); try for i := 0 to Items.Count - 1 do with Items[i] do if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then Status := STATUS_CHECK; finally - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; end; if taskthread = nil then @@ -511,126 +574,99 @@ procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; FavoriteIndex procedure TFavoriteManager.ShowResult; var - i, p, counter, numOfNewChapters, numOfMangaNewChapters, numOfCompleted: Integer; - dlChapters: TStringList; + i, j, + numOfNewChapters, + numOfMangaNewChapters, + numOfCompleted: Integer; LNCResult: TNewChapterResult = ncrCancel; newChapterListStr: String = ''; removeListStr: String = ''; - favDelete: Boolean; begin if isDlgCounter then Exit; if (Self.DLManager = nil) and Assigned(MainForm.DLManager) then Self.DLManager := MainForm.DLManager; if Self.DLManager = nil then Exit; + + EnterCriticalsection(CS_Favorites); try - CS_Favorites.Acquire; - dlChapters := TStringList.Create; - try - numOfNewChapters := 0; - numOfMangaNewChapters := 0; - numOfCompleted := 0; - counter := 0; - while counter < Items.Count do - with Items[counter] do try - if Assigned(MangaInfo) then - if MangaInfo.chapterLinks.Count > 0 then - begin - //compare new mangainfo's chapters with downloadedchapter from favorites - NewMangaInfo := TMangaInfo.Create; - NewMangaInfoChaptersPos := TCardinalList.Create; - TransferMangaInfo(NewMangaInfo, MangaInfo); - NewMangaInfo.chapterLinks.Clear; - NewMangaInfo.chapterName.Clear; - dlChapters.Clear; - dlChapters.Sorted := False; - GetParams(dlChapters, FavoriteInfo.downloadedChapterList); - dlChapters.Sorted := True; - for i := 0 to MangaInfo.chapterLinks.Count - 1 do - if not dlChapters.Find(MangaInfo.chapterLinks[i], p) then - begin - NewMangaInfo.chapterLinks.Add(MangaInfo.chapterLinks[i]); - NewMangaInfo.chapterName.Add(MangaInfo.chapterName[i]); - NewMangaInfoChaptersPos.Add(i); - Inc(numOfNewChapters); - end; + numOfNewChapters := 0; + numOfMangaNewChapters := 0; + numOfCompleted := 0; - //add to notification - if NewMangaInfo.chapterLinks.Count > 0 then - begin - newChapterListStr := newChapterListStr + LineEnding + '- ' + - Format(RS_FavoriteHasNewChapter, - [FavoriteInfo.Title, FavoriteInfo.Website, - NewMangaInfo.chapterLinks.Count]); - Inc(numOfMangaNewChapters); - end; + try + // check for all favorites + for i := 0 to Items.Count - 1 do + with Items[i] do + if Assigned(NewMangaInfo) then + begin + // new chapters add to notification + if NewMangaInfoChaptersPos.Count > 0 then + begin + newChapterListStr += LineEnding + '- ' + Format( + RS_FavoriteHasNewChapter, [FavoriteInfo.Title, FavoriteInfo.Website, + NewMangaInfoChaptersPos.Count]); + Inc(numOfMangaNewChapters); + Inc(numOfNewChapters, NewMangaInfoChaptersPos.Count); + end + else + // completed series add to notification + if OptionAutoCheckFavRemoveCompletedManga and + (NewMangaInfo.status = MangaInfo_StatusCompleted) then + begin + removeListStr += LineEnding + Format('- %s <%s>', + [FavoriteInfo.Title, FavoriteInfo.Website]); + Inc(numOfCompleted); + end; + end; - //add completed manga - if (OptionAutoCheckFavRemoveCompletedManga) and - (NewMangaInfo.status = '0') then - begin - removeListStr := removeListStr + LineEnding + - Format('- %s <%s>', [FavoriteInfo.Title, FavoriteInfo.Website]); - Inc(numOfCompleted); - end; - end; + // if there is completed mangas, show dialog + if numOfCompleted > 0 then + begin + with TNewChapter.Create(MainForm) do + try + Caption := Format(RS_DlgCompletedMangaCaption, [numOfCompleted]); + lbNotification.Caption := RS_LblMangaWillBeRemoved; + mmMemo.Lines.Text := Trim(removeListStr); + btDownload.Caption := RS_BtnRemove; + btCancel.Caption := RS_BtnCancel; + btDownload.Show; + btCancel.Show; + btQueue.Hide; + ShowModal; + LNCResult := FormResult; finally - Inc(counter); + Free; end; - dlChapters.Clear; - - if numOfNewChapters = 0 then - begin - // If there's no new chapter, but there're completed mangas, show dialog - if numOfCompleted > 0 then + //delete complete FFavorites + if LNCResult = ncrDownload then begin - with TNewChapter.Create(MainForm) do try - Caption := Format(RS_DlgCompletedMangaCaption, [numOfCompleted]); - lbNotification.Caption := RS_LblMangaWillBeRemoved; - mmMemo.Lines.Text := Trim(removeListStr); - btDownload.Caption := RS_BtnRemove; - btCancel.Caption := RS_BtnCancel; - btDownload.Show; - btCancel.Show; - btQueue.Hide; - ShowModal; - LNCResult := FormResult; - finally - Free; - end; - - //delete complete FFavorites - if LNCResult = ncrDownload then - begin - counter := 0; - while counter < Items.Count do + i := 0; + while i < Items.Count do + with Items[i] do begin - favDelete := False; - with Items[counter] do - if Assigned(NewMangaInfo) and - (NewMangaInfo.chapterLinks.Count = 0) and - (NewMangaInfo.status = '0') then - begin - Items[counter].Free; - Items.Delete(counter); - favDelete := True; - end; - if not favDelete then - Inc(counter); + if Assigned(NewMangaInfo) and + (NewMangaInfoChaptersPos.Count = 0) and + (NewMangaInfo.status = MangaInfo_StatusCompleted) then + begin + Items[i].Free; + Items.Delete(i); + end + else + Inc(i); end; - end; - Backup; - if Assigned(OnUpdateFavorite) then - OnUpdateFavorite; end; - end - else + Backup; + end; + + // if there is new chapters + if numOfNewChapters > 0 then begin - //if there's new chapters if OptionAutoCheckFavDownload then LNCResult := ncrDownload else - with TNewChapter.Create(MainForm) do try + with TNewChapter.Create(MainForm) do + try Caption := Format(RS_DlgNewChapterCaption, [numOfNewChapters]); lbNotification.Caption := Format(RS_LblNewChapterFound, [numOfNewChapters, numOfMangaNewChapters]); @@ -647,42 +683,43 @@ procedure TFavoriteManager.ShowResult; Free; end; + // generate download task if LNCResult <> ncrCancel then - //generate new download task begin while DLManager.isRunningBackup do Sleep(100); - counter := 0; - while counter < Items.Count do - begin - with Items[counter] do + + for i := 0 to Items.Count - 1 do + with Items[i] do if Assigned(NewMangaInfo) and - (NewMangaInfo.chapterLinks.Count > 0) then - begin - DLManager.CS_Task.Acquire; + (NewMangaInfoChaptersPos.Count > 0) then try + DLManager.CS_Task.Acquire; DLManager.Items.Add(TTaskContainer.Create); - with DLManager.Items.Last do begin + with DLManager.Items.Last do + begin Manager := DLManager; CurrentDownloadChapterPtr := 0; Website := FavoriteInfo.Website; - with DownloadInfo do begin - Link := FavoriteInfo.Link; - Title := FavoriteInfo.Title; - SaveTo := FavoriteInfo.SaveTo; - dateTime := Now; - end; - ChapterLinks.Assign(NewMangaInfo.chapterLinks); - for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do + DownloadInfo.Link := FavoriteInfo.Link; + DownloadInfo.Title := FavoriteInfo.Title; + DownloadInfo.SaveTo := FavoriteInfo.SaveTo; + DownloadInfo.dateTime := Now; + + for j := 0 to NewMangaInfoChaptersPos.Count - 1 do + begin + ChapterLinks.Add(NewMangaInfo.chapterLinks[NewMangaInfoChaptersPos[j]]); ChapterName.Add(CustomRename( OptionChapterCustomRename, FavoriteInfo.Website, FavoriteInfo.Title, NewMangaInfo.authors, NewMangaInfo.artists, - NewMangaInfo.chapterName[i], - Format('%.4d', [NewMangaInfoChaptersPos[i] + 1]), + NewMangaInfo.chapterName[NewMangaInfoChaptersPos[j]], + Format('%.4d', [NewMangaInfoChaptersPos[j] + 1]), OptionChangeUnicodeCharacter)); + end; + if LNCResult = ncrDownload then begin DownloadInfo.Status := RS_Waiting; @@ -694,54 +731,48 @@ procedure TFavoriteManager.ShowResult; Status := STATUS_STOP; end; end; - FavoriteInfo.currentChapter := - IntToStr(MangaInfo.chapterLinks.Count); + FavoriteInfo.currentChapter := IntToStr(NewMangaInfoChaptersPos.Count); + // add to downloaded chapter list + FavoriteInfo.downloadedChapterList += SetParams(NewMangaInfo.chapterLinks); + // add to downloaded chapter list in downloadmanager + DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := + NewMangaInfo.chapterLinks.Text; + + // free unused objects + FreeAndNil(NewMangaInfo); + FreeAndNil(NewMangaInfoChaptersPos); finally DLManager.CS_Task.Release; end; - //mark downloaded - FavoriteInfo.downloadedChapterList := - FavoriteInfo.downloadedChapterList + - SetParams(NewMangaInfo.chapterLinks); - //save to downloaded chapter list from dlmanager. - DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := - NewMangaInfo.chapterLinks.Text; - end; - Inc(counter); - end; + Backup; - if Assigned(OnUpdateDownload) then - OnUpdateDownload; if LNCResult = ncrDownload then begin DLManager.CheckAndActiveTask; MainForm.pcMain.ActivePage := MainForm.tsDownload; end; + if Assigned(OnUpdateDownload) then + OnUpdateDownload; if Assigned(OnUpdateFavorite) then OnUpdateFavorite; end; end; - finally - //free used memory - counter := 0; - while counter < Items.Count do - begin - with Items[counter] do begin - if Assigned(MangaInfo) then - FreeAndNil(MangaInfo); - if Assigned(NewMangaInfo) then - FreeAndNil(NewMangaInfo); - if Assigned(NewMangaInfoChaptersPos) then - FreeAndNil(NewMangaInfoChaptersPos); - end; - Inc(counter); - end; - FreeAndNil(dlChapters); - CS_Favorites.Release; + + except + on E: Exception do + ExceptionHandle(Self, E); end; - except - on E: Exception do - ExceptionHandle(Self, E); + + // check again for unused objects and free them + for i := 0 to Items.Count - 1 do + with Items[i] do + if Assigned(NewMangaInfo) then + begin + FreeAndNil(NewMangaInfo); + FreeAndNil(NewMangaInfoChaptersPos); + end; + finally + LeaveCriticalsection(CS_Favorites); end; end; @@ -773,7 +804,7 @@ procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapter AWebsite, ASaveTo, ALink: String); begin if IsMangaExist(ATitle, AWebsite) then Exit; - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); try Items.Add(TFavoriteContainer.Create); with Items.Last do begin @@ -794,7 +825,7 @@ procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapter Backup; end; finally - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; end; @@ -803,7 +834,7 @@ procedure TFavoriteManager.AddMerge(const ATitle, ACurrentChapter, ADownloadedCh begin if IsMangaExist(ATitle, AWebsite) then Exit; - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); try Items.Add(TFavoriteContainer.Create); with Items.Last do begin @@ -818,7 +849,7 @@ procedure TFavoriteManager.AddMerge(const ATitle, ACurrentChapter, ADownloadedCh end; end; except - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; end; @@ -866,18 +897,18 @@ procedure TFavoriteManager.MergeWith(const APath: String); isRunning := False; end; -procedure TFavoriteManager.Remove(const pos: Integer; const isBackup: Boolean); +procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); begin - if (not isRunning) and (pos < Items.Count) then + if (not isRunning) and (Pos < Items.Count) then begin - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); try - Items[pos].Free; - Items.Delete(pos); + Items[Pos].Free; + Items.Delete(Pos); if isBackup then Backup; finally - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; end; end; @@ -959,7 +990,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St begin Ch := TStringList.Create; dlCh := TStringList.Create; - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); try p := -1; //locate the link @@ -997,7 +1028,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St MainForm.UpdateVtFavorites; end; finally - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; dlCh.Free; Ch.Free; @@ -1029,23 +1060,23 @@ function CompareFavoriteContainer(const Item1, Item2: TFavoriteContainer): Integ procedure TFavoriteManager.Sort(const AColumn: Integer); begin if Items.Count < 2 then Exit; - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); try SortColumn := AColumn; Items.Sort(CompareFavoriteContainer); finally - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; end; procedure TFavoriteManager.Lock; begin - CS_Favorites.Acquire; + EnterCriticalsection(CS_Favorites); end; procedure TFavoriteManager.LockRelease; begin - CS_Favorites.Release; + LeaveCriticalsection(CS_Favorites); end; end. From 3082a02430c37afe021770d2f7b7042aaf69caab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 13 Jun 2016 20:56:11 +0800 Subject: [PATCH 1237/2794] frmmain, favorite list show favorite status when checking for new chapters with icon and highlight --- mangadownloader/forms/frmMain.lfm | 38 ++++++++--------- mangadownloader/forms/frmMain.pas | 71 +++++++++++++++++++------------ 2 files changed, 63 insertions(+), 46 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9a6c24dcb..6b076a492 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4048,7 +4048,7 @@ object MainForm: TMainForm Caption = '>>' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 - ClientHeight = 509 + ClientHeight = 490 ClientWidth = 187 ImageIndex = 4 object tvDownloadFilter: TTreeView @@ -5651,24 +5651,24 @@ object MainForm: TMainForm 7CFFA451009FA4510000A45100000101010001010100010101B5797979FFDFAC 79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A370FFD6A370FFBE8B58FFDFAC 79FFA14F00A1A14F0000A14F00000101010001010100010101B8757575FFDBA8 - 75FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F6CFF84A791FF3FA6A6FF8CAF - 99FF9E4D00A39E4D00009E4D00000101010001010100010101BB727272FFD8A5 - 72FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D6CFF50ACA8FFA2E5E7FF53AF - ABFF94500AA89B4B00009B4B00000101010001010100010101BE6E6E6EFFD4A1 - 6EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F83FF6BC5C6FFABF5FCFF6CC7 - C8FF636E48C38F4F0D008F4F0D000101010001010100010101C16B6B6BFFD19E - 6BFFBF8C59FFC89562FFC89562FFC59563FF4FA39FFF90E3E9FF555555FF88E1 - E9FF2E8E8ADE01ABC40401ABC4000101010001010100010101C5676767FFCD9A - 67FFBF8C59FFC4915EFFC4915EFF919778FF56B6BAFF7CE4F1FF000000FF68D8 - E7FF38A6ABEE01A8C04301A7BF000101010001010100010101C9646464FFCA97 - 64FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1D7FF46D3D7FF75B4B5FF40D0 - D2FF40C3C6F901A4BC9801A2BA010000000001010100010101CE626262FFC895 - 62FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9E0FF33D5DDFF000000FF33D5 - DDFF34D5DDFF0DACC1C7019EB63A0000000900000016000000DB606060FFCA97 - 64FFC5925FFFC5925FFF4C9590FF32C6D1FF29DBE9FF28DAE9FF79EDF5FF28DA - E9FF28DAE9FF1CC7D8EA0198AF9F000000000000002C00000087000000E7702E - 00C7702E00C7702E00C72C6662E8157882F2157882F2157882F2157882F21578 - 82F2107B87EA008398D00066779A + 75FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F6CFFD29F6CFFBE8B58FFDBA8 + 75FF9E4D00A39E4D00009E4D00000101010001010100010101BB727272FFD8A5 + 72FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFCF9C69FFCF9C69FFBF8C59FFD8A5 + 72FF9B4B00A59B4B00009B4B00000101010001010100010101BE6E6E6EFFD4A1 + 6EFFBF8C59FFCB9865FFCB9865FFCB9865FFCB9865FFCB9865FF599D24FF3BA8 + 16FF448700DC60720000567300000101010001010100010101C16B6B6BFFD19E + 6BFFBF8C59FFC89562FFC89562FFC89562FFC89562FFC89562FF369F12FF75EE + 64FF269700EE179E0000129D00000101010001010100010101C5676767FFCD9A + 67FFBF8C59FFC4915EFFC4915EFFC4915EFF5A9826FF369B13FF359A12FF66EB + 55FF249000EF129D00CC129C00990101010001010100010101C9646464FFCA97 + 64FFBE8B58FFC18E5BFFC18E5BFFC18E5BFF339412FF52E741FF52E741FF52E7 + 41FF52E741FF52E741FF109500CC0000000001010100010101CE626262FFC895 + 62FFBD8A57FFBF8C59FFBF8C59FFBF8C59FF548D24FF318C12FF318C11FF3DE2 + 2CFF208100F00E8C00CC0E8D00990000000900000016000000DB606060FFCA97 + 64FFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFF318613FF2BDF + 1AFF1E7700F20000001600000009000000000000002C00000087000000E7702E + 00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E00C72D5500E9175F + 00F4124A00C40000002C00000000 } end object IconDL: TImageList diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0ffbea187..e4849283b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -734,6 +734,7 @@ TSearchDBThread = class(TThread) CL_HLBlueMarks = $FDC594; CL_HLGreenMarks = $B8FFB8; CL_HLRedMarks = $8080FF; + CL_HLYellowMarks = $80EBFE; CL_BarGrayLine = $bcbcbc; CL_BarGray = $e6e6e6; @@ -3683,30 +3684,33 @@ procedure TMainForm.vtDownloadKeyUp(Sender: TObject; var Key: Word; Shift: TShif procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); -var - Data: PFavoriteInfo; -begin - if Column=TVirtualStringTree(Sender).Header.SortColumn then + + procedure FillRectBC(const AColor: TColor); begin - TargetCanvas.Brush.Color:=CL_BlueLight; + TargetCanvas.Brush.Color := AColor; TargetCanvas.FillRect(CellRect); end; - Data := Sender.GetNodeData(Node); - if Assigned(Data) then + +begin + if Column=TVirtualStringTree(Sender).Header.SortColumn then + FillRectBC(CL_BlueLight); + + with TargetCanvas, FavoriteManager.Items[Node^.Index] do begin - with FavoriteManager.Items[Node^.Index] do + if Trim(FavoriteInfo.Link) = '' then + FillRectBC(CL_HLRedMarks) + else + if Status = STATUS_CHECKING then + FillRectBC(CL_HLYellowMarks) + else + if (Status = STATUS_CHECKED) and + Assigned(NewMangaInfo) then begin - if Trim(FavoriteInfo.Link) = '' then - begin - TargetCanvas.Brush.Color := CL_HLRedMarks; - TargetCanvas.FillRect(CellRect); - end + if NewMangaInfoChaptersPos.Count > 0 then + FillRectBC(CL_HLBlueMarks) else - if Status = STATUS_CHECKING then - begin - TargetCanvas.Brush.Color := CL_HLGreenMarks; - TargetCanvas.FillRect(CellRect); - end; + if NewMangaInfo.status = MangaInfo_StatusCompleted then + FillRectBC(CL_HLGreenMarks); end; end; end; @@ -3755,16 +3759,29 @@ procedure TMainForm.vtFavoritesGetImageIndex(Sender: TBaseVirtualTree; var Ghosted: Boolean; var ImageIndex: Integer); begin if vtFavorites.Header.Columns[Column].Position<>1 then Exit; - if Node^.Index>=FavoriteManager.Count then Exit; - if Trim(FavoriteManager.Items[Node^.Index].FavoriteInfo.Link)='' then - ImageIndex:=16 - else - case FavoriteManager.Items[Node^.Index].Status of - STATUS_CHECK : ImageIndex:=19; - STATUS_CHECKING : ImageIndex:=12; - STATUS_CHECKED : ImageIndex:=20; + with FavoriteManager.Items[Node^.Index] do + begin + if Trim(FavoriteInfo.Link)='' then + ImageIndex:=16 else - ImageIndex:=-1; + case FavoriteManager.Items[Node^.Index].Status of + STATUS_CHECK : ImageIndex:=19; + STATUS_CHECKING : ImageIndex:=12; + STATUS_CHECKED : + begin + ImageIndex:=20; + if Assigned(NewMangaInfo) then + begin + if NewMangaInfoChaptersPos.Count>0 then + ImageIndex:=21 + else + if NewMangaInfo.status=MangaInfo_StatusCompleted then + ImageIndex:=5 + end; + end; + else + ImageIndex:=-1; + end; end; end; From 96959d68fd86ab476e3717e2540517df8030e5c2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 14 Jun 2016 16:16:17 +0800 Subject: [PATCH 1238/2794] frmmain, fixed view manga info, added method viewmangainfo and cleanup the related method that use it --- mangadownloader/forms/frmMain.pas | 206 +++++++++++------------------- 1 file changed, 75 insertions(+), 131 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e4849283b..737b928a8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -627,6 +627,10 @@ TMainForm = class(TForm) // fill edSaveTo with default path procedure FilledSaveTo; + // View manga information + procedure ViewMangaInfo(const AURL, AWebsite, ATitle: String; + const AMangaListPos: Integer = -1); + // Show manga information procedure ShowInformation(const title, website, link: String); @@ -1557,20 +1561,10 @@ procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); end; procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); -var - i: Integer; begin - if vtDownload.Focused then - with DLManager.Items[vtDownload.FocusedNode^.Index] do - begin - i := Modules.LocateModule(DownloadInfo.Website); - if i > -1 then - edURL.Text := FillHost(Modules.Module[i].RootURL, DownloadInfo.Link) - else - edURL.Text := FillMangaSiteHost(DownloadInfo.Website, DownloadInfo.Link); - edURLButtonClick(edURL); - pcMain.ActivePage := tsInformation; - end; + if Assigned(vtDownload.FocusedNode) then + with DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo do + ViewMangaInfo(Link, Website, Title); end; procedure TMainForm.miChapterListHighlightClick(Sender: TObject); @@ -1729,55 +1723,10 @@ procedure TMainForm.miFavoritesStopCheckNewChapterClick(Sender: TObject); end; procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); -var - title, website, link: String; - i: Integer; begin - if (not vtFavorites.Focused) then - Exit; - btDownload.Enabled := False; - pcMain.ActivePage := tsInformation; - imCover.Picture.Assign(nil); - rmInformation.Clear; - rmInformation.Lines.Add('Loading ...'); - clbChapterList.Clear; - - website := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Website; - link := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.link; - title := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.Title; - - if isGetMangaInfos then - begin - GetInfosThread.IsFlushed := True; - GetInfosThread.Terminate; - //GetInfosThread.WaitFor; - end; - GetInfosThread := TGetMangaInfosThread.Create; - GetInfosThread.MangaListPos := -2; - GetInfosThread.Title := title; - GetInfosThread.Website := website; - GetInfosThread.Link := link; - GetInfosThread.Start; - - if Assigned(gifWaiting) then - begin - itAnimate.Enabled := True; - pbWait.Visible := True; - end; - - if ExecRegExpr('^https?://', link) then - edURL.Text := link - else - begin - i := Modules.LocateModule(website); - if i > -1 then - edURL.Text := FillHost(Modules.Module[i].RootURL, link) - else - edURL.Text := FillMangaSiteHost(website, link); - end; - - btDownload.Enabled := (clbChapterList.RootNodeCount > 0); - btReadOnline.Enabled := (edURL.Text <> ''); + if Assigned(vtFavorites.FocusedNode) then + with FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo do + ViewMangaInfo(Link, Website, Title); end; procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); @@ -2937,51 +2886,12 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); end; procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); -var - title, website, link: String; - i: Integer; begin - if (not vtMangaList.Focused) or (vtMangaList.SelectedCount = 0) then - Exit; - btDownload.Enabled := False; - btAddToFavorites.Enabled := False; - pcMain.ActivePage := tsInformation; - imCover.Picture.Assign(nil); - rmInformation.Clear; - rmInformation.Lines.Add(RS_Loading); - clbChapterList.Clear; - - if isGetMangaInfos then - begin - GetInfosThread.IsFlushed := True; - GetInfosThread.Terminate; - //GetInfosThread.WaitFor; - end; - GetInfosThread := TGetMangaInfosThread.Create; - GetInfosThread.MangaListPos := vtMangaList.FocusedNode^.Index; - - website := dataProcess.WebsiteName[GetInfosThread.MangaListPos]; - title := DataProcess.Value[GetInfosThread.mangaListPos, DATA_PARAM_TITLE]; - link := DataProcess.Value[GetInfosThread.mangaListPos, DATA_PARAM_LINK]; - - GetInfosThread.Title := title; - GetInfosThread.Website := website; - GetInfosThread.Link := link; - GetInfosThread.Start; - - i := Modules.LocateModule(website); - if i > -1 then - edURL.Text := FillHost(Modules.Module[i].RootURL, link) - else - edURL.Text := FillMangaSiteHost(website, link); - - if Assigned(gifWaiting) then - begin - itAnimate.Enabled := True; - pbWait.Visible := True; - end; - - btReadOnline.Enabled := (link <> ''); + if Assigned(vtMangaList.FocusedNode) then + ViewMangaInfo(DataProcess.Value[vtMangaList.FocusedNode^.Index, DATA_PARAM_LINK], + DataProcess.WebsiteName[vtMangaList.FocusedNode^.Index], + DataProcess.Value[vtMangaList.FocusedNode^.Index, DATA_PARAM_TITLE], + vtMangaList.FocusedNode^.Index); end; procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); @@ -4145,6 +4055,59 @@ procedure TMainForm.FilledSaveTo; edSaveTo.Text := CleanAndExpandDirectory(edSaveTo.Text); end; +procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; + const AMangaListPos: Integer); +var + TURL: String; + i: Integer; +begin + if (AURL = '') or (AWebsite = '') then Exit; + TURL := Trim(AURL); + + // fix url + i := Modules.LocateModule(AWebsite); + if i > -1 then + TURL := FillHost(Modules.Module[i].RootURL, TURL) + else + TURL := FillMangaSiteHost(AWebsite, TURL); + + // terminate exisiting getmangainfo thread + if isGetMangaInfos then + begin + GetInfosThread.IsFlushed := True; + GetInfosThread.Terminate; + end; + + // set the UI + pcMain.ActivePage := tsInformation; + edURL.Text := TURL; + imCover.Picture.Assign(nil); + rmInformation.Clear; + rmInformation.Lines.Add(RS_Loading); + clbChapterList.Clear; + if Assigned(gifWaiting) then + begin + itAnimate.Enabled := True; + pbWait.Visible := True; + end; + btDownload.Enabled := False; + btReadOnline.Enabled := True; + DisableAddToFavorites(AWebsite); + //check if manga already in FavoriteManager list + if btAddToFavorites.Enabled and + (ATitle <> '') and + (FavoriteManager.Count > 0) then + btAddToFavorites.Enabled := not FavoriteManager.IsMangaExist(ATitle, AWebsite); + + // start the thread + GetInfosThread := TGetMangaInfosThread.Create; + GetInfosThread.MangaListPos := AMangaListPos; + GetInfosThread.Title := ATitle; + GetInfosThread.Website := AWebsite; + GetInfosThread.Link := TURL; + GetInfosThread.Start; +end; + procedure TMainForm.ShowInformation(const title, website, link: String); var i: Integer; @@ -4190,7 +4153,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); btReadOnline.Enabled := (mangaInfo.link <> ''); - btAddToFavorites.Enabled := not SitesWithoutFavorites(website); + DisableAddToFavorites(website); //check if manga already in FavoriteManager list if btAddToFavorites.Enabled and (FavoriteManager.Count > 0) then @@ -4732,10 +4695,15 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); link: String; regx: TRegExpr; begin + btDownload.Enabled := False; + btAddToFavorites.Enabled := False; + btReadOnline.Enabled := False; + website := ''; host := ''; link := ''; edURL.Text := FixURL(edURL.Text); + regx := TRegExpr.Create; try regx.Expression := '^https?\://'; @@ -4775,37 +4743,13 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); regx.Free; end; - DisableAddToFavorites(website); if (website = '') or (link = '') then begin MessageDlg('', RS_DlgURLNotSupport, mtInformation, [mbYes], 0); Exit; end; - if isGetMangaInfos then - begin - GetInfosThread.IsFlushed := True; - GetInfosThread.Terminate; - //GetInfosThread.WaitFor; - end; - GetInfosThread := TGetMangaInfosThread.Create; - GetInfosThread.MangaListPos := -1; - GetInfosThread.Title := ''; - GetInfosThread.Website := website; - GetInfosThread.Link := link; - GetInfosThread.Start; - - pcMain.ActivePage := tsInformation; - imCover.Picture.Assign(nil); - clbChapterList.Clear; - if Assigned(gifWaiting) then - begin - itAnimate.Enabled := True; - pbWait.Visible := True; - end; - btAddToFavorites.Enabled := not SitesWithoutFavorites(website); - rmInformation.Clear; - rmInformation.Lines.Add(RS_Loading); + ViewMangaInfo(link, website, ''); end; procedure TMainForm.UpdateVtChapter; From 26f9f17cbfb70d07e2069d5a1ac5a9c3bff9ec9a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 14 Jun 2016 16:57:12 +0800 Subject: [PATCH 1239/2794] cleanup use of syncobjs --- baseunits/uDownloadsManager.pas | 67 +++++++++++++++---------------- baseunits/uFavoritesManager.pas | 4 +- baseunits/uMisc.pas | 12 +++--- baseunits/uUpdateThread.pas | 20 ++++----- mangadownloader/forms/frmMain.pas | 16 ++++---- 5 files changed, 59 insertions(+), 60 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b4516cf3f..4a4ed75f7 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -16,7 +16,7 @@ interface uses LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Classes, SysUtils, - ExtCtrls, typinfo, fgl, syncobjs, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, + ExtCtrls, typinfo, fgl, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils, strutils; @@ -96,7 +96,7 @@ TTaskContainer = class procedure SetWebsite(AValue: String); public // critical section - CS_Container: TCriticalSection; + CS_Container: TRTLCriticalSection; // read count for transfer rate ReadCount: Integer; // task thread of this container @@ -148,7 +148,7 @@ TDownloadManager = class function GetTaskCount: Integer; inline; function GetTransferRate: Integer; public - CS_Task: TCriticalSection; + CS_Task: TRTLCriticalSection; Items, ItemsActiveTask: TTaskContainers; isRunningBackup, isFinishTaskAccessed, isRunningBackupDownloadedChaptersList, @@ -317,13 +317,13 @@ procedure TDownloadThread.Execute; if not Terminated and Reslt then begin - Task.Container.CS_Container.Acquire; + EnterCriticalSection(Task.Container.CS_Container); try Task.Container.DownCounter := InterLockedIncrement(Task.Container.DownCounter); Task.Container.DownloadInfo.Progress := Format('%d/%d', [Task.Container.DownCounter, Task.Container.PageNumber]); finally - Task.Container.CS_Container.Release; + LeaveCriticalSection(Task.Container.CS_Container); end; end; except @@ -1388,11 +1388,11 @@ procedure TTaskThread.DoTerminate; DownloadInfo.TransferRate := ''; ThreadState := False; Task := nil; - Manager.CS_Task.Acquire; + EnterCriticalSection(Manager.CS_Task); try Manager.ItemsActiveTask.Remove(Container); finally - Manager.CS_Task.Release; + LeaveCriticalSection(Manager.CS_Task); end; if not Manager.isReadyForExit then begin @@ -1436,8 +1436,8 @@ procedure TTaskContainer.SetWebsite(AValue: String); constructor TTaskContainer.Create; begin inherited Create; + InitCriticalSection(CS_Container); ThreadState := False; - CS_Container := TCriticalSection.Create; ChapterLinks := TStringList.Create; ChapterName := TStringList.Create; FailedChapterName := TStringList.Create; @@ -1461,17 +1461,17 @@ destructor TTaskContainer.Destroy; ChapterLinks.Free; FailedChapterName.Free; FailedChapterLinks.Free; - CS_Container.Free; + DoneCriticalsection(CS_Container); inherited Destroy; end; procedure TTaskContainer.IncReadCount(const ACount: Integer); begin - CS_Container.Acquire; + EnterCriticalSection(CS_Container); try Inc(ReadCount, ACount); finally - CS_Container.Release; + LeaveCriticalSection(CS_Container); end; end; @@ -1488,31 +1488,30 @@ function TDownloadManager.GetTransferRate: Integer; begin Result := 0; if ItemsActiveTask.Count = 0 then Exit; - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try for i := 0 to ItemsActiveTask.Count - 1 do with ItemsActiveTask[i] do begin - CS_Container.Acquire; + EnterCriticalSection(CS_Container); try DownloadInfo.TransferRate := FormatByteSize(ReadCount, True); Inc(Result, ReadCount); ReadCount := 0; finally - CS_Container.Release; + LeaveCriticalSection(CS_Container); end; end; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; constructor TDownloadManager.Create; begin inherited Create; + InitCriticalSection(CS_Task); ForceDirectoriesUTF8(WORK_FOLDER); - - CS_Task := TCriticalSection.Create; DownloadManagerFile := TIniFileRun.Create(WORK_FILE); DownloadedChapters := TDownloadedChaptersDB.Create; DownloadedChapters.Filename := DOWNLOADEDCHAPTERSDB_FILE; @@ -1532,7 +1531,7 @@ constructor TDownloadManager.Create; destructor TDownloadManager.Destroy; begin - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try while Items.Count > 0 do begin @@ -1540,13 +1539,13 @@ destructor TDownloadManager.Destroy; Items.Remove(Items.Last); end; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; Items.Free; DownloadManagerFile.Free; ItemsActiveTask.Free; DownloadedChapters.Free; - CS_Task.Free; + DoneCriticalsection(CS_Task); inherited Destroy; end; @@ -1555,7 +1554,7 @@ procedure TDownloadManager.Restore; tid, s: String; tmp, i, j: Integer; begin - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try while Items.Count > 0 do begin @@ -1636,7 +1635,7 @@ procedure TDownloadManager.Restore; end; end; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; @@ -1649,7 +1648,7 @@ procedure TDownloadManager.Backup; Exit; isRunningBackup := True; - CS_Task.Acquire; + EnterCriticalSection(CS_Task); with DownloadManagerFile do try // Erase all sections @@ -1694,7 +1693,7 @@ procedure TDownloadManager.Backup; end; UpdateFile; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; isRunningBackup := False; end; @@ -1723,13 +1722,13 @@ procedure TDownloadManager.GetDownloadedChaptersState(const Alink: String; function TDownloadManager.AddTask: Integer; begin Result := -1; - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try Result := Items.Add(TTaskContainer.Create); with Items[Result] do Manager := Self; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; @@ -1738,7 +1737,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); i, tcount: Integer; begin if Items.Count = 0 then Exit; - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try tcount := 0; for i := 0 to Items.Count - 1 do @@ -1756,7 +1755,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); Inc(tcount); end; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; try @@ -1907,7 +1906,7 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; procedure TDownloadManager.RemoveTask(const taskID: Integer); begin - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try with Items[taskID] do if ThreadState then begin @@ -1917,7 +1916,7 @@ procedure TDownloadManager.RemoveTask(const taskID: Integer); Items[taskID].Free; Items.Delete(taskID); finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; CheckAndActiveTask; end; @@ -1942,7 +1941,7 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea Result := False; if Items.Count > 0 then begin - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try for i := 0 to Items.Count - 1 do if Items[i].Status in Stats then begin @@ -1950,7 +1949,7 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea Break; end; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; end; @@ -1997,12 +1996,12 @@ function CompareTaskContainer(const Item1, Item2: TTaskContainer): Integer; procedure TDownloadManager.Sort(const AColumn: Integer); begin if Items.Count < 2 then Exit; - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try SortColumn := AColumn; Items.Sort(CompareTaskContainer); finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 4512ef87f..195e32748 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -694,7 +694,7 @@ procedure TFavoriteManager.ShowResult; if Assigned(NewMangaInfo) and (NewMangaInfoChaptersPos.Count > 0) then try - DLManager.CS_Task.Acquire; + EnterCriticalSection(DLManager.CS_Task); DLManager.Items.Add(TTaskContainer.Create); with DLManager.Items.Last do begin @@ -742,7 +742,7 @@ procedure TFavoriteManager.ShowResult; FreeAndNil(NewMangaInfo); FreeAndNil(NewMangaInfoChaptersPos); finally - DLManager.CS_Task.Release; + LeaveCriticalSection(DLManager.CS_Task); end; Backup; diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index f170b30a5..40370c0af 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -10,7 +10,7 @@ interface {$else} UTF8Process, {$endif} - Classes, SysUtils, Graphics, LazFileUtils, strutils, syncobjs, IniFiles, + Classes, SysUtils, Graphics, LazFileUtils, strutils, IniFiles, NaturalSortUnit; type @@ -18,7 +18,7 @@ interface TIniFileR = class(TMemIniFile) private - FCSReload: TCriticalSection; + FCSReload: TRTLCriticalSection; FFileAge: Longint; public constructor Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); @@ -98,13 +98,13 @@ implementation constructor TIniFileR.Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); begin inherited Create(AFileName, AEscapeLineFeeds); - FCSReload := TCriticalSection.Create; + InitCriticalSection(FCSReload); FFileAge := FileAge(Self.FileName); end; destructor TIniFileR.Destroy; begin - FCSReload.Free; + DoneCriticalsection(FCSReload); inherited Destroy; end; @@ -112,7 +112,7 @@ procedure TIniFileR.Reload; var slLines: TStringList; begin - if FCSReload.TryEnter then try + if TryEnterCriticalSection(FCSReload) then try if FileExistsUTF8(FileName) then if FileAgeUTF8(FileName) <> FFileAge then begin @@ -126,7 +126,7 @@ procedure TIniFileR.Reload; end; end; finally - FCSReload.Release; + LeaveCriticalSection(FCSReload); end; end; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 8f4560679..fc9ed94f2 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, typinfo, syncobjs, uData, LazFileUtils, uBaseUnit, uFMDThread, uMisc, + Classes, SysUtils, typinfo, uData, LazFileUtils, uBaseUnit, uFMDThread, uMisc, WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread; type @@ -59,7 +59,7 @@ TUpdateListManagerThread = class(TFMDThread) procedure GetInfo(const limit: Integer; const cs: TCheckStyleType); procedure DoTerminate; override; public - CS_AddInfoToData, CS_AddNamesAndLinks: TCriticalSection; + CS_AddInfoToData, CS_AddNamesAndLinks: TRTLCriticalSection; isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; mainDataProcess: TDBDataProcess; tempDataProcess: TDBDataProcess; @@ -188,7 +188,7 @@ procedure TUpdateListThread.Execute; //we will stop at first found against current db if links.Count > 0 then begin - manager.CS_AddNamesAndLinks.Acquire; + EnterCriticalSection(manager.CS_AddNamesAndLinks); try if manager.FIsPreListAvailable then begin for i:=0 to links.Count-1 do begin @@ -204,7 +204,7 @@ procedure TUpdateListThread.Execute; manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0); manager.tempDataProcess.Commit; finally - manager.CS_AddNamesAndLinks.Release; + LeaveCriticalSection(manager.CS_AddNamesAndLinks); end; end; finally @@ -220,12 +220,12 @@ procedure TUpdateListThread.Execute; Info.GetInfoFromURL(manager.website,link,DefaultRetryCount); if not Terminated then begin - manager.CS_AddInfoToData.Acquire; + EnterCriticalSection(manager.CS_AddInfoToData); try Info.AddInfoToData(title,link,manager.mainDataProcess); manager.CheckCommit(manager.numberOfThreads); finally - manager.CS_AddInfoToData.Release; + LeaveCriticalSection(manager.CS_AddInfoToData); end; end; end; @@ -331,8 +331,8 @@ procedure TUpdateListManagerThread.ExtractFile; constructor TUpdateListManagerThread.Create; begin inherited Create(True); - CS_AddInfoToData := TCriticalSection.Create; - CS_AddNamesAndLinks := TCriticalSection.Create; + InitCriticalSection(CS_AddInfoToData); + InitCriticalSection(CS_AddNamesAndLinks); FreeOnTerminate := True; websites := TStringList.Create; @@ -362,8 +362,8 @@ destructor TUpdateListManagerThread.Destroy; tempDataProcess.Free; threads.Free; MainForm.isUpdating := False; - CS_AddInfoToData.Free; - CS_AddNamesAndLinks.Free; + DoneCriticalsection(CS_AddInfoToData); + DoneCriticalsection(CS_AddNamesAndLinks); inherited Destroy; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 737b928a8..7f350a664 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1595,7 +1595,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if MessageDlg('', RS_DlgRemoveTask, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then Exit; - DLManager.CS_Task.Acquire; + EnterCriticalSection(DLManager.CS_Task); try xNode := vtDownload.GetLast(); while Assigned(xNode) do begin @@ -1623,7 +1623,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); xNode := vtDownload.GetPreviousSelected(xNode); end; finally - DLManager.CS_Task.Release; + LeaveCriticalSection(DLManager.CS_Task); end; DLManager.CheckAndActiveTask; UpdateVtDownload; @@ -2938,7 +2938,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); begin Result := False; with DLManager do begin - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try for i := 0 to Count - 1 do if Items[i].Status = STATUS_FINISH then @@ -2947,7 +2947,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); Break; end; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; end; @@ -2961,7 +2961,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); begin with DLManager do begin - CS_Task.Acquire; + EnterCriticalSection(CS_Task); try xNode := vtDownload.GetFirstSelected; repeat @@ -2973,7 +2973,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); xNode := vtDownload.GetNextSelected(xNode); until xNode = nil; finally - CS_Task.Release; + LeaveCriticalSection(CS_Task); end; end; end; @@ -3315,7 +3315,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); nIndex:=NextIndex; vtDownload.BeginUpdate; ConTemp:=TTaskContainers.Create; - DLManager.CS_Task.Acquire; + EnterCriticalSection(DLManager.CS_Task); try i:=0; cNode:=vtDownload.GetFirstSelected(); @@ -3358,7 +3358,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); if Mode=dmAbove then vtDownload.FocusedNode:=cNode; finally - DLManager.CS_Task.Release; + LeaveCriticalSection(DLManager.CS_Task); end; ConTemp.Free; vtDownload.EndUpdate; From 77a787a5b3c7785ae7e3c767d81bdb4785807479 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 14 Jun 2016 18:07:13 +0800 Subject: [PATCH 1240/2794] added new senmanga module, removed from wpmanga fixed #290 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/SenManga.pas | 145 +++++++++++++++++++++++++++++++++ baseunits/modules/WPManga.pas | 9 -- 3 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 baseunits/modules/SenManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 14d72e142..97fc532b6 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -40,4 +40,5 @@ uses MangaSaurus, GMangaMe, SekaiManga, - KuManga; + KuManga, + SenManga; diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas new file mode 100644 index 000000000..27f528b24 --- /dev/null +++ b/baseunits/modules/SenManga.pas @@ -0,0 +1,145 @@ +unit SenManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/directory'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(SeparateRight( + XPathString('//*[@id="Navigation"]//ul/li[last()]/a/@href'), '/page/'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then + s += '/page/' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@id="search-results"]/*[@class="media_box"]/*[@class="media-body"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//*[@class="cover"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//*[@class="info"]/h1[@class="title"]'); + status := MangaInfoStatusIfPos( + XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), + 'Ongoing', + 'Complete'); + artists := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Artist:")]/following-sibling::*[@class="desc"][1]/a'); + authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); + for v in XPath('//table[@id="chapter-list"]//tr/td/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + Cookies.Values['viewer'] := '1'; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//script[contains(.,"var imglist = [")]'); + if s <> '' then + begin + s := '[' + GetBetween('var imglist = [', '];', s) + ']'; + ParseHTML(s); + XPathStringAll('json(*)().url', PageLinks); + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'SenManga'; + RootURL := 'http://www.senmanga.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 1568c33da..fc1f94afe 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -15,7 +15,6 @@ implementation dirURLmangaindo = '/daftar-manga/all/any/last-added/'; dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; dirURLmangahen = '/manga_list/all/any/last-added/'; - dirURLsenmanga = '/directory/all/any/last-added/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -29,7 +28,6 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else if Module.Website = 'MangaHen' then s := dirURLmangahen - else if Module.Website = 'SenManga' then s := dirURLsenmanga else s := dirURL; if GET(Module.RootURL + s) then begin Result := NO_ERROR; @@ -57,7 +55,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks if Module.Website = 'MangaIndo' then s := dirURLmangaindo else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else if Module.Website = 'MangaHen' then s := dirURLmangahen - else if Module.Website = 'SenManga' then s := dirURLsenmanga else s := dirURL; if GET(Module.RootURL + s + IncStr(AURL) + '/') then begin Result := NO_ERROR; @@ -74,11 +71,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toNode.getAttribute('title')); end - else if Module.Website = 'SenManga' then - for v in XPath('//table[@id="wpm_mng_lst"]/tbody/tr/td/a[1]') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toNode.getAttribute('title')); - end else if (Module.Website = 'EyeOnManga') or (Module.Website = 'MangaBoom') then for v in XPath('//*[@id="sct_content"]//h2/a[1]') do begin @@ -316,7 +308,6 @@ procedure RegisterModule; AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); AddWebsiteModule('MangaBug', 'http://www.mangabug.com'); - AddWebsiteModule('SenManga', 'http://www.senmanga.com'); end; initialization From ecf51f108462c34fd92a86cda250512942268122 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 14 Jun 2016 18:11:12 +0800 Subject: [PATCH 1241/2794] frmmain, enclose wndcallback in tryexcept --- mangadownloader/forms/frmMain.pas | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7f350a664..f6250e653 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -843,17 +843,20 @@ implementation function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall; begin - if uMsg = WM_DISPLAYCHANGE then - begin - Screen.UpdateMonitors; - Screen.UpdateScreen; - if Screen.MonitorCount < MainForm.Monitor.MonitorNum then - MainForm.DefaultMonitor := dmMainForm; - if (MainForm.Left > Screen.Width) or (MainForm.Top > Screen.Height) then - MainForm.MoveToDefaultPosition; - end - else - Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam); + try + if uMsg = WM_DISPLAYCHANGE then + begin + Screen.UpdateMonitors; + Screen.UpdateScreen; + if Screen.MonitorCount < MainForm.Monitor.MonitorNum then + MainForm.DefaultMonitor := dmMainForm; + if (MainForm.Left > Screen.Width) or (MainForm.Top > Screen.Height) then + MainForm.MoveToDefaultPosition; + end + else + Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam); + except + end; end; {$endif} From 900565c0776bbe0782c2933bbff51dc7e160cdfe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Jun 2016 05:48:55 +0800 Subject: [PATCH 1242/2794] websiteoptioncustom, added wocombobox, changed websitemodules addoption to specifix type --- baseunits/WebsiteModules.pas | 43 ++++++++++-- baseunits/modules/Batoto.pas | 4 +- baseunits/modules/EHentai.pas | 2 +- baseunits/modules/MangaFox.pas | 4 +- .../forms/frmWebsiteOptionCustom.pas | 66 +++++++++++++++++-- mangadownloader/md.lpi | 1 + 6 files changed, 105 insertions(+), 15 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index a13da7bbf..15ac9cf08 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -54,13 +54,14 @@ TModuleContainer = class; MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, MMDownloadImage, MMAfterImageSaved, MMLogin); - TWebsiteOptionType = (woCheckBox, woEdit, woSpinEdit); + TWebsiteOptionType = (woCheckBox, woEdit, woSpinEdit, woComboBox); TWebsiteOptionItem = record OptionType: TWebsiteOptionType; Name: String; Caption: PString; BindValue: Pointer; + Items: PString; end; { TModuleContainer } @@ -69,6 +70,8 @@ TModuleContainer = class private FTotalDirectory: Integer; procedure SetTotalDirectory(AValue: Integer); + procedure AddOption(const AOptionType: TWebsiteOptionType; + const ABindValue: Pointer; const AName: String; const ACaption: PString); public Website: String; RootURL: String; @@ -98,8 +101,14 @@ TModuleContainer = class destructor Destroy; override; public property TotalDirectory: Integer read FTotalDirectory write SetTotalDirectory; - procedure AddOption(const AOptionType: TWebsiteOptionType; - const ABindValue: Pointer; const AName: String; const ACaption: PString); + procedure AddOptionCheckBox(const ABindValue: PBoolean; const AName: String; + const ACaption: PString); + procedure AddOptionEdit(const ABindValue: PString; const AName: String; + const ACaption: PString); + procedure AddOptionSpinEdit(const ABindValue: PInteger; const AName: String; + const ACaption: PString); + procedure AddOptionComboBox(const ABindValue: PInteger; const AName: String; + const ACaption, AItems: PString); end; { TWebsiteModules } @@ -281,8 +290,34 @@ destructor TModuleContainer.Destroy; inherited Destroy; end; -procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; +procedure TModuleContainer.AddOptionCheckBox(const ABindValue: PBoolean; + const AName: String; const ACaption: PString); +begin + AddOption(woCheckBox, ABindValue, AName, ACaption); +end; + +procedure TModuleContainer.AddOptionEdit(const ABindValue: PString; const AName: String; + const ACaption: PString); +begin + AddOption(woEdit, ABindValue, AName, ACaption); +end; + +procedure TModuleContainer.AddOptionSpinEdit(const ABindValue: PInteger; const AName: String; const ACaption: PString); +begin + AddOption(woSpinEdit, ABindValue, AName, ACaption); +end; + +procedure TModuleContainer.AddOptionComboBox(const ABindValue: PInteger; + const AName: String; const ACaption, AItems: PString); +begin + AddOption(woComboBox, ABindValue, AName, ACaption); + with OptionList[High(OptionList)] do + Items := AItems; +end; + +procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; + const ABindValue: Pointer; const AName: String; const ACaption: PString); begin if ABindValue = nil then Exit; if AName = '' then Exit; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 1780fdf77..f66182f3b 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -325,8 +325,8 @@ procedure RegisterModule; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; OnLogin := @Login; - AddOption(woCheckBox, @showalllang,'ShowAllLang', @RS_ShowAllLang); - AddOption(woCheckBox, @showscangroup,'ShowScanGroup', @RS_ShowScanGroup); + AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); + AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); end; end; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 15e2bcd0e..e28755cb4 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -393,7 +393,7 @@ procedure RegisterModule; begin with AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org') do - AddOption(woCheckBox, @downloadoriginalimage, 'DownloadOriginalImage', @RS_DownloadOriginalImage); + AddOptionCheckBox(@downloadoriginalimage, 'DownloadOriginalImage', @RS_DownloadOriginalImage); with AddWebsiteModule('ExHentai', 'http://exhentai.org') do begin AccountSupport := True; OnLogin := @ExHentaiLogin; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index ef943965d..738a09d68 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -158,8 +158,8 @@ procedure RegisterModule; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; OnAfterImageSaved := @AfterImageSaved; - AddOption(woCheckBox, @removewatermark, 'RemoveWatermark', @RS_RemoveWatermark); - AddOption(woCheckBox, @saveaspng, 'SaveAsPNG', @RS_SaveAsPNG); + AddOptionCheckBox(@removewatermark, 'RemoveWatermark', @RS_RemoveWatermark); + AddOptionCheckBox(@saveaspng, 'SaveAsPNG', @RS_SaveAsPNG); end; end; diff --git a/mangadownloader/forms/frmWebsiteOptionCustom.pas b/mangadownloader/forms/frmWebsiteOptionCustom.pas index 6e201a0c5..d265e9277 100644 --- a/mangadownloader/forms/frmWebsiteOptionCustom.pas +++ b/mangadownloader/forms/frmWebsiteOptionCustom.pas @@ -48,6 +48,19 @@ TSpinEditBindValue = class(TSpinEdit) property BindValue: PInteger read FBindValue write SetBindValue; end; + { TComboBoxBindValue } + + TComboBoxBindValue = class(TComboBox) + private + FBindValue: PInteger; + procedure SetBindValue(AValue: PInteger); + protected + procedure ValueChange(Sender: TObject); + public + constructor Create(TheOwner: TComponent); override; + property BindValue: PInteger read FBindValue write SetBindValue; + end; + { TCustomOptionForm } TCustomOptionForm = class(TForm) @@ -65,6 +78,8 @@ TCustomOptionForm = class(TForm) const AName, ACaption, AGroup, AGroupCaption: String): TWinControl; function AddSpinEdit(const ABindValue: PInteger; AName, ACaption, AGroup, AGroupCaption: String): TWinControl; + function AddComboBox(const ABindValue: PInteger; + AName, ACaption, AGroup, AGroupCaption, AItems: String): TWinControl; procedure CreateWebsiteOption; end; @@ -78,7 +93,7 @@ TCustomOptionForm = class(TForm) const TWebsiteOptionItemTypeStr: array[TWebsiteOptionType] of String = - ('ack', 'ae', 'ase'); + ('ack', 'ae', 'ase', 'acb'); implementation @@ -152,6 +167,30 @@ constructor TSpinEditBindValue.Create(TheOwner: TComponent); OnChange := @ValueChange; end; +{ TComboBoxBindValue } + +procedure TComboBoxBindValue.SetBindValue(AValue: PInteger); +begin + if FBindValue = AValue then Exit; + FBindValue := AValue; + if Assigned(FBindValue) then + if FBindValue^ < Items.Count then + ItemIndex := FBindValue^; +end; + +procedure TComboBoxBindValue.ValueChange(Sender: TObject); +begin + if Assigned(FBindValue) then + FBindValue^ := ItemIndex; +end; + +constructor TComboBoxBindValue.Create(TheOwner: TComponent); +begin + inherited Create(TheOwner); + OnChange := @ValueChange; + Style := csDropDownList; +end; + { TCustomOptionForm } procedure TCustomOptionForm.FormCreate(Sender: TObject); @@ -173,8 +212,8 @@ procedure TCustomOptionForm.FormDestroy(Sender: TObject); Modules.SaveWebsiteOption; end; -function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionType; const AName, ACaption, - AGroup, AGroupCaption: String): TWinControl; +function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionType; + const AName, ACaption, AGroup, AGroupCaption: String): TWinControl; var i, j: Integer; compparent: TWinControl; @@ -288,12 +327,15 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy SetControlProp(Result, compsibling, compparent, lcomp, lcompcaption); end; - woEdit: + woEdit, woComboBox: begin lb := TLabel.Create(compparent); SetControlProp(lb, compsibling, compparent, lcomp + 'Lbl', lcompcaption); compsibling := lb; - Result := TEditBindValue.Create(compparent); + case AOptionItemType of + woEdit : Result := TEditBindValue.Create(compparent); + woComboBox: Result := TComboBoxBindValue.Create(compparent); + end; SetControlProp(Result, compsibling, compparent, lcomp, ''); with Result do begin @@ -305,10 +347,10 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy woSpinEdit: begin - lb := TLabel.Create(compparent); Result := TSpinEditBindValue.Create(compparent); SetControlProp(Result, compsibling, compparent, lcomp, lcompcaption); Result.Width := Result.Width + (Result.Width div 4); + lb := TLabel.Create(compparent); SetControlProp(lb, Result, compparent, lcomp + 'Lbl', lcompcaption); with lb do begin @@ -346,6 +388,17 @@ function TCustomOptionForm.AddSpinEdit(const ABindValue: PInteger; TSpinEditBindValue(Result).BindValue := ABindValue; end; +function TCustomOptionForm.AddComboBox(const ABindValue: PInteger; AName, ACaption, + AGroup, AGroupCaption, AItems: String): TWinControl; +begin + Result := AddOptionItem(woComboBox, AName, ACaption, AGroup, AGroupCaption); + with TComboBoxBindValue(Result) do + begin + Items.Text := AItems; + TComboBoxBindValue(Result).BindValue := ABindValue; + end; +end; + procedure TCustomOptionForm.CreateWebsiteOption; var i, j: Integer; @@ -376,6 +429,7 @@ procedure TCustomOptionForm.CreateWebsiteOption; woCheckBox: AddCheckbox(BindValue, Name, cap, Website, Website); woEdit: AddEdit(BindValue, Name, cap, Website, Website); woSpinEdit: AddSpinEdit(BindValue, Name, cap, Website, Website); + woComboBox: AddComboBox(BindValue, Name, cap, Website, Website, Items^); end; end; end; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ce2fe642c..24c88e18b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -310,6 +310,7 @@ <Filename Value="forms\frmWebsiteSelection.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="WebsiteSelectionForm"/> + <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit10> </Units> From 96a4b6662442d43e5a75b1d9c5b2b8f5f0b1d997 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Jun 2016 06:24:29 +0800 Subject: [PATCH 1243/2794] ehentai, added image size option fixed #280 --- baseunits/modules/EHentai.pas | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index e28755cb4..7337163bb 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -19,10 +19,26 @@ implementation var onlogin: Boolean = False; locklogin: TRTLCriticalSection; - downloadoriginalimage: Boolean = False; + settingsimagesize: Integer = 0; + settingsimagesizestr: array [0..5] of string = ( + 'xr_a', + 'xr_780', + 'xr_980', + 'xr_1280', + 'xr_1600', + 'xr_2400'); resourcestring RS_DownloadOriginalImage = 'Download original image(require ExHentai account)'; + RS_SettingsImageSize = 'Image size'; + RS_SettingsImageSizeItems = + 'Auto' + LineEnding + + '780x' + LineEnding + + '980x' + LineEnding + + '1280x' + LineEnding + + '1600x' + LineEnding + + '2400x' + LineEnding + + 'Original'; function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; var @@ -66,16 +82,24 @@ function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; end; function GETWithLogin(const AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; +var + ACookies: String; begin Result := False; if Account.Enabled[accname] then begin AHTTP.FollowRedirection := False; - AHTTP.Cookies.Text := Account.Cookies[accname]; + if AHTTP.Cookies.Count > 0 then ACookies := AHTTP.Cookies.Text + else ACookies := ''; + //AHTTP.Cookies.Text := Account.Cookies[accname]; + AHTTP.Cookies.AddText(Account.Cookies[accname]); Result := AHTTP.GET(AURL); if Result and (AHTTP.ResultCode > 300) then begin Result := ExHentaiLogin(AHTTP); if Result then + begin + if ACookies <> '' then AHTTP.Cookies.AddText(ACookies); Result := AHTTP.GET(AURL); + end; end; end else @@ -293,7 +317,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; s := StreamToString(DownloadThread.FHTTP.Document); query.ParseHTML(DownloadThread.FHTTP.Document); iurl := ''; - if downloadoriginalimage and (Account.Status[accname] = asValid) then + if (settingsimagesize > High(settingsimagesizestr)) and (Account.Status[accname] = asValid) then iurl := query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); if iurl = '' then iurl := query.XPathString('//*[@id="img"]/@src'); @@ -361,6 +385,8 @@ function DownloadImage(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; reconnect := DownloadThread.FHTTP.RetryCount; iurl := FillHost(Module.RootURL, AURL); + if settingsimagesize <= High(settingsimagesizestr) then + DownloadThread.FHTTP.Cookies.Values['uconfig'] := settingsimagesizestr[settingsimagesize]; if GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then begin query := TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document); try @@ -393,7 +419,7 @@ procedure RegisterModule; begin with AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org') do - AddOptionCheckBox(@downloadoriginalimage, 'DownloadOriginalImage', @RS_DownloadOriginalImage); + AddOptionComboBox(@settingsimagesize, 'SettingsImageSize', @RS_SettingsImageSize, @RS_SettingsImageSizeItems); with AddWebsiteModule('ExHentai', 'http://exhentai.org') do begin AccountSupport := True; OnLogin := @ExHentaiLogin; From 47e6acade14652ce275c6c475027e126d1361cc8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Jun 2016 06:31:08 +0800 Subject: [PATCH 1244/2794] websitemodules, fixed option combobox doesn't save and load --- baseunits/WebsiteModules.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 15ac9cf08..25cf63a40 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -694,7 +694,7 @@ procedure TWebsiteModules.LoadWebsiteOption; case OptionType of woCheckBox: PBoolean(BindValue)^ := ReadBool(Website, Name, PBoolean(BindValue)^); woEdit: PString(BindValue)^ := ReadString(Website, Name, PString(BindValue)^); - woSpinEdit: PInteger(BindValue)^ := ReadInteger(Website, Name, PInteger(BindValue)^); + woSpinEdit, woComboBox: PInteger(BindValue)^ := ReadInteger(Website, Name, PInteger(BindValue)^); end; end; end; @@ -713,7 +713,7 @@ procedure TWebsiteModules.SaveWebsiteOption; case OptionType of woCheckBox: WriteBool(Website, Name, PBoolean(BindValue)^); woEdit: WriteString(Website, Name, PString(BindValue)^); - woSpinEdit: WriteInteger(Website, Name, PInteger(BindValue)^); + woSpinEdit, woComboBox: WriteInteger(Website, Name, PInteger(BindValue)^); end; end; configfile.UpdateFile; From a9383700923b22e21562d12a2bac5318564312c4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Jun 2016 06:41:40 +0800 Subject: [PATCH 1245/2794] update translations --- baseunits/modules/EHentai.pas | 2 +- mangadownloader/languages/fmd.en.po | 25 ++++++++++++++++++++++++- mangadownloader/languages/fmd.id_ID.po | 24 +++++++++++++++++++++++- mangadownloader/languages/fmd.po | 15 +++++++++++++++ mangadownloader/md.lpr | 3 ++- 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 7337163bb..03ee116fe 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -30,7 +30,7 @@ implementation resourcestring RS_DownloadOriginalImage = 'Download original image(require ExHentai account)'; - RS_SettingsImageSize = 'Image size'; + RS_SettingsImageSize = 'Image size:'; RS_SettingsImageSizeItems = 'Auto' + LineEnding + '780x' + LineEnding + diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index a006f64f3..ffa21e743 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_US\n" -"X-Generator: Poedit 1.8.7\n" +"X-Generator: Poedit 1.8.8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: batoto.rs_showalllang @@ -24,6 +24,29 @@ msgstr "Show scanlation group" msgid "Download original image(require ExHentai account)" msgstr "Download original image(require ExHentai account)" +#: ehentai.rs_settingsimagesize +#| msgid "Image size" +msgid "Image size:" +msgstr "Image size:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" + #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" msgstr "Are you sure you want to delete this account?" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 030920b7b..02fd6cf37 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.8.7\n" +"X-Generator: Poedit 1.8.8\n" "Plural-Forms: nplurals=1; plural=0;\n" #: batoto.rs_showalllang @@ -24,6 +24,28 @@ msgstr "Tampilkan nama grup scan" msgid "Download original image(require ExHentai account)" msgstr "Unduh gambar asli(membutuhkan akun ExHentai)" +#: ehentai.rs_settingsimagesize +msgid "Image size:" +msgstr "Ukuran gambar:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Otomatis\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Asli\n" + #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" msgstr "Apakah anda yakin ingin menghapus akun ini?" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 1bd2e408d..f15cf5bbc 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -13,6 +13,21 @@ msgstr "" msgid "Download original image(require ExHentai account)" msgstr "" +#: ehentai.rs_settingsimagesize +msgid "Image size:" +msgstr "" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" + #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" msgstr "" diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 5486086fd..9c6045f36 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -12,7 +12,8 @@ cthreads, {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, frmMain; + Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, + frmMain; var CheckInstance: Boolean = True; From 36feac7e3d9b5b5bb614ad33294ee9dc053d4c63 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Jun 2016 07:57:23 +0800 Subject: [PATCH 1246/2794] baseunit, fixed long path --- baseunits/uBaseUnit.pas | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a79f1e058..dd274780b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -485,9 +485,18 @@ interface FMDSupportedOutputExt: array[0..2] of ShortString = ('.zip', '.cbz', '.pdf'); FMDImageFileExt: array[0..2] of ShortString = ('.png', '.gif', '.jpg'); - // max file extension length = 4 - FMDImageFileExtLength = 4; - FMDMaxImageFilePath = MAX_PATH - FMDImageFileExtLength; + {$ifdef windows} + // MAX_PATH = 260 + // MAX_PATH - 12 - 1 + MAX_PATHDIR = 247; + // fmd max file extension = 4 + // max path + file in windows explorer is 259 + // = MAX_PATH - fmd max file extension - 1 + // 1 is pahtdelim "/" + FMDMaxImageFilePath = 255; + // if directory length is max_pathdir, the remaining allowed filename is 7 + // = 259 - fmd max file extension - 1 + {$endif} // custom rename @@ -499,11 +508,6 @@ interface CR_ARTIST = '%ARTIST%'; CR_FILENAME = '%FILENAME%'; - {$ifdef windows} - // MAX_PATHDIR(260) - 12 - 1 - MAX_PATHDIR = 247; - {$endif} - var // Sites var BROWSER_INVERT: Boolean = False; @@ -2111,6 +2115,11 @@ function ShortenString(const S: String; const MaxWidth: Integer; Result := S; if Length(Result) > MaxWidth then begin + if RightLength + Length(EllipsisStr) > MaxWidth then + begin + Result := RightStr(Result, MaxWidth); + Exit; + end; r := RightStr(Result, RightLength); SetLength(Result, MaxWidth - RightLength - Length(EllipsisStr)); Result := Result + EllipsisStr + r; From 66e64cde0c36b366100925cc9041418c8efa5663 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Jun 2016 08:14:24 +0800 Subject: [PATCH 1247/2794] Bump version 0.9.64.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8d4e2f88c..7390f8f88 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.64.0 (15-06-2016) +[+] Show new chapters and status downloaded while checking favorites with icon and highlight +[*] SenManga: fixed all +[+] E-Hentai/ExHentai: replace option download original image with image size with combobox +[*] Various changes and bug fix +Full changes: https://github.com/riderkick/FMD/compare/0.9.62.0...0.9.63.0 + 0.9.63.0 (11-06-2016) [*] Fixed an issue with CF Full changes: https://github.com/riderkick/FMD/compare/0.9.62.0...0.9.63.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 24c88e18b..994f7f5a8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="63"/> + <RevisionNr Value="64"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 0884e3e37..b4307c8e7 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.63.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.63.0/fmd_0.9.63.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.63.0/fmd_0.9.63.0_Win64.7z +VERSION=0.9.64.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.64.0/fmd_0.9.64.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.64.0/fmd_0.9.64.0_Win64.7z From d3595f1c600013df80fd9fd8f9b80cccc534d4dd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 02:51:05 +0800 Subject: [PATCH 1248/2794] fixed check for new chapters download what exist in downloadedchapterlist instead of what not fixed #293 --- baseunits/uFavoritesManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 195e32748..bd43ddf71 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -231,7 +231,7 @@ procedure TFavoriteThread.Execute; GetParams(DLChapters, FavoriteInfo.DownloadedChapterList); DLChapters.Sorted := True; for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do - if DLChapters.IndexOf(NewMangaInfo.chapterLinks[i]) > -1 then + if DLChapters.IndexOf(NewMangaInfo.chapterLinks[i]) = -1 then NewMangaInfoChaptersPos.Add(i); finally DLChapters.Free; From dfb6e1756451c88cde143c838c70ed57dfe58c28 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 03:16:40 +0800 Subject: [PATCH 1249/2794] tumangaonline, try to fix invalid url #264 --- baseunits/modules/Tumangaonline.pas | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index c031f6df8..ff382d8a6 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -16,6 +16,7 @@ implementation apiurlimagenes = apiurl + 'imagenes'; dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage=1000&page='; mangaurl = '/#!/biblioteca/mangas/'; + mangaurlpart = '/biblioteca/mangas/'; imgurl = 'http://img1.tumangaonline.com'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; @@ -72,15 +73,19 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - if Pos(mangaurl, AURL) <> 0 then + url := AURL; + mangaid := ''; + if Pos(mangaurlpart, url) <> 0 then begin - mangaid := SeparateRight(AURL, mangaurl); + if Pos(mangaurl, AURL) = -1 then + url := StringReplace(url, mangaurlpart, mangaurl, [rfIgnoreCase]); + mangaid := SeparateRight(url, mangaurl); if Pos('/', mangaid) <> 0 then mangaid := SeparateLeft(mangaid, '/'); - end - else + end; + if mangaid = '' then Exit; - url := FillHost(Module.RootURL, AURL); + url := FillHost(Module.RootURL, url); if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then begin Result := NO_ERROR; From b6a0cd53d542d1a0292021db7b1720b001464a5c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 04:23:35 +0800 Subject: [PATCH 1250/2794] tumangaonline, fixed get all chapters fixed #294 --- baseunits/modules/Tumangaonline.pas | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index ff382d8a6..d4304b65f 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -66,7 +66,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - mangaid, purl, s: String; + mangaid, purl, s, c: String; p, i: Integer; begin Result := NET_PROBLEM; @@ -116,13 +116,21 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; ParseHTML(Document) else Break; - for v in XPath('json(*).data()/concat("?idManga=",idTomo,"&idScanlation=",subidas/idScan,"&numeroCapitulo=",numCapitulo,"&visto=true")') do - chapterLinks.Add(apiurlimagenes + v.toString); - for v in XPath('json(*).data()/concat(numCapitulo," ",nombre)') do + for v in XPath( + 'json(*).data()/string-join((' + + '"?idManga=",idTomo,' + + '"&idScanlation=",subidas/idScan,' + + '"&numeroCapitulo=",numCapitulo,' + + '"&visto=true",' + + '"/",numCapitulo,"/",nombre),"")') do begin s := v.toString; - if RightStr(s, 5) = ' null' then - SetLength(s, Length(s) - 5); + chapterLinks.Add(apiurlimagenes + SeparateLeft(s, '/')); + s := SeparateRight(s, '/'); + c := SeparateRight(s, '/'); + s := SeparateLeft(s, '/'); + if (c <> '') and (c <> 'null') then + s := s + ' ' + c; chapterName.Add(s); end; end; @@ -152,7 +160,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String Result := True; with TXQueryEngineHTML.Create(Document) do try - s := imgurl + '/subidas/' + XPathString('json(*)/concat(capitulo/idTomo,"/",capitulo/numCapitulo,"/",idScan)') + '/'; + s := imgurl + '/subidas/' + + XPathString('json(*)/concat(capitulo/idTomo,"/",capitulo/numCapitulo,"/",idScan)') + '/'; for v in XPath('json((json(*).imagenes))()') do PageLinks.Add(s + v.toString); finally From 705e47e9daf81a84b23b2c2eaefdd22be87c20e4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 04:59:44 +0800 Subject: [PATCH 1251/2794] tumangaonline, fixed update list, request only 1 record to get directory page --- baseunits/modules/Tumangaonline.pas | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index d4304b65f..941aa9b8e 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, XQueryEngineHTML, httpsendthread, synautil, synacode, RegExpr; implementation @@ -14,7 +14,8 @@ implementation apiurl = '/api/v1/'; apiurlmangas = apiurl + 'mangas'; apiurlimagenes = apiurl + 'imagenes'; - dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage=1000&page='; + dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage='; + perpage = '1000'; mangaurl = '/#!/biblioteca/mangas/'; mangaurlpart = '/biblioteca/mangas/'; imgurl = 'http://img1.tumangaonline.com'; @@ -25,12 +26,12 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1&page=1') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - Page := StrToIntDef(XPathString('json(*).last_page'), 1); + Page := ceil(StrToIntDef(XPathString('json(*).total'), 1) / StrToInt(perpage)); finally Free; end; @@ -45,16 +46,16 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('json(*).data()/concat(id,"/",nombreUrl," ",nombre)') do + for v in XPath('json(*).data()/string-join((id,"/",nombreUrl,codepoints-to-string(10),nombre),"")') do begin s := v.toString; - ALinks.Add(mangaurl + SeparateLeft(s, ' ')); - ANames.Add(SeparateRight(s, ' ')); + ALinks.Add(mangaurl + SeparateLeft(s, #10)); + ANames.Add(Trim(SeparateRight(s, #10))); end; finally Free; From 87e62d8ccbb174a6b6ccdaf71218da91140b43d9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 06:17:00 +0800 Subject: [PATCH 1252/2794] baseunit, use integer and cleanup --- baseunits/uBaseUnit.pas | 70 ++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 39 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dd274780b..0d1676fa4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -575,7 +575,7 @@ TMangaInfo = class genres, status, summary: String; - numChapter: Cardinal; + numChapter: Integer; chapterName, chapterLinks: TStringList; constructor Create; @@ -616,7 +616,7 @@ TDownloadPageThread = class(TThread) procedure Execute; override; public isSuccess, isDone: Boolean; - Retry: Cardinal; + Retry: Integer; URL, Path: String; constructor Create(CreateSuspended: Boolean); end; @@ -737,7 +737,7 @@ function GetValuesFromString(Str: String; Sepr: Char): String; procedure InvertStrings(const St: TStringList); overload; procedure InvertStrings(const Sts: array of TStringList); overload; procedure TrimStrings(TheStrings: TStrings); -procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Cardinal = 0); +procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Integer = 0); procedure CleanHTMLComments(const Str: TStringList); function FixHTMLTagQuote(const s: String): String; @@ -773,7 +773,7 @@ function TrimChar(const Source: String; const Chars: TSysCharSet): String; function TrimLeftChar(const Source: String; const Chars: TSysCharSet): String; function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; -function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): String; +function PrepareSummaryForHint(const Source: String; MaxLength: Integer = 80): String; procedure AddCommaString(var Dest: String; S: String); function StringOfString(c: String; l: Integer): String; @@ -864,7 +864,6 @@ function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String) // cross platform funcs function fmdGetTempPath: String; -function fmdGetTickCount: Cardinal; procedure fmdPowerOff; procedure fmdHibernate; @@ -966,7 +965,7 @@ function NTSetPrivilege(sPrivilege: String; bEnabled: Boolean): Boolean; function UnicodeRemove(const S: String): String; var - i: Cardinal; + i: Integer; begin Result := S; for i := 1 to Length(Result) do @@ -1018,7 +1017,7 @@ function CorrectFilePath(const APath: String): String; procedure CheckPath(const S: String); var wS, lcS, lcS2: String; - i, j: Word; + i, j: Integer; begin wS := s; lcS2 := ''; @@ -1703,7 +1702,7 @@ function URLDecode(const s: String): String; sUtf8: String; sWide: WideString; - i, len: Cardinal; + i, len: Integer; ESC: String[2]; CharCode: Integer; c: Char; @@ -1847,8 +1846,7 @@ procedure TrimStrings(TheStrings: TStrings); end; end; -procedure RemoveDuplicateStrings(Strs: array of TStringList; - RemIndex: Cardinal); +procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Integer); var i, j, k: Integer; begin @@ -2256,7 +2254,7 @@ function GetString(const Source, sStart, sEnd: String): String; function Find(const S: String; var List: TStringList; out index: Integer): Boolean; var - i: Cardinal; + i: Integer; begin Result := False; index := -1; @@ -2289,7 +2287,7 @@ function FindStrQuick(const s: String; var AStrings: TStringList): Boolean; procedure GetParams(const output: TStrings; input: String); var - l: Word; + l: Integer; begin repeat l := Pos(SEPERATOR, input); @@ -2303,7 +2301,7 @@ procedure GetParams(const output: TStrings; input: String); procedure GetParams(var output: TCardinalList; input: String); var - l: Word; + l: Integer; begin repeat l := Pos(SEPERATOR, input); @@ -2317,7 +2315,7 @@ procedure GetParams(var output: TCardinalList; input: String); procedure GetParams(var output: TList; input: String); var - l: Word; + l: Integer; begin repeat l := Pos(SEPERATOR, input); @@ -2332,7 +2330,7 @@ procedure GetParams(var output: TList; input: String); function ExtractParam(const output: TStrings; input, sep: String; WhiteSp: Boolean): Integer; var - l, lse: QWord; + l, lse: Integer; s: String; begin Result := 0; @@ -2387,7 +2385,7 @@ function RemoveDuplicateNumbersInString(const AString: String): String; function SetParams(input: TObject): String; var - i: Cardinal; + i: Integer; begin Result := ''; if input is TStringList then @@ -2417,7 +2415,7 @@ function SetParams(input: TObject): String; function SetParams(const input: array of String): String; var - i: Cardinal; + i: Integer; begin Result := ''; if Length(input) = 0 then @@ -2529,7 +2527,7 @@ function FixURL(const URL: String): String; function FixPath(const path: String): String; var - i: Cardinal; + i: Integer; begin Result := path; if Length(path) = 0 then @@ -2629,7 +2627,7 @@ function HTMLEntitiesFilter(const Source: String): String; procedure CustomGenres(var output: TStringList; input: String); var s: String = ''; - i: Word; + i: Integer; begin if Length(input) = 0 then Exit; @@ -2742,12 +2740,13 @@ function TrimRightChar(const Source: String; const Chars: TSysCharSet): String; end; end; -function PrepareSummaryForHint(const Source: String; MaxLength: Cardinal = 80): String; +function PrepareSummaryForHint(const Source: String; MaxLength: Integer = 80): String; var - i: Cardinal = 1; - j: Cardinal = 1; + i, j: Integer; begin Result := Source; + i := 1; + j := 1; repeat if (j > MaxLength) and (Result[i] = ' ') then begin @@ -3237,7 +3236,7 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer function GetURLFromBitly(const URL: String): String; var - i: Cardinal; + i: Integer; httpSource: TStringList; begin Result := ''; @@ -3617,9 +3616,9 @@ function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; con procedure QuickSortChapters(var chapterList, linkList: TStringList); - procedure QSort(L, R: Cardinal); + procedure QSort(L, R: Integer); var - i, j: Cardinal; + i, j: Integer; X: String; begin X := chapterList.Strings[(L + R) div 2]; @@ -3656,9 +3655,9 @@ procedure QuickSortData(var merge: TStringList); var names, output: TStringList; - procedure QSort(L, R: Cardinal); + procedure QSort(L, R: Integer); var - i, j: Cardinal; + i, j: Integer; X: String; begin X := names.Strings[(L + R) div 2]; @@ -3686,7 +3685,7 @@ procedure QuickSortData(var merge: TStringList); end; var - i: Cardinal; + i: Integer; begin names := TStringList.Create; @@ -3707,9 +3706,9 @@ procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteL var names, output: TStringList; - procedure QSort(L, R: Cardinal); + procedure QSort(L, R: Integer); var - i, j: Cardinal; + i, j: Integer; X: String; begin X := names.Strings[(L + R) div 2]; @@ -3738,7 +3737,7 @@ procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteL end; var - i: Cardinal; + i: Integer; begin names := TStringList.Create; @@ -3942,7 +3941,7 @@ procedure TDownloadPageThread.Execute; // OS dependent function fmdGetTempPath: String; var - l: Cardinal; + l: Integer; begin {$IFDEF WINDOWS} SetLength(Result, 4096); @@ -3954,13 +3953,6 @@ function fmdGetTempPath: String; {$ENDIF} end; -function fmdGetTickCount: Cardinal; -begin - {$IFDEF WINDOWS} - Result := GetTickCount64; - {$ENDIF} -end; - procedure fmdPowerOff; begin {$IFDEF WINDOWS} From 28d14bbbd43a8ff615bd7f041afefa4b0f5a8cf2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 06:18:05 +0800 Subject: [PATCH 1253/2794] favoritemanager, remove duplicate of downloadedchapterlist at restore --- baseunits/uFavoritesManager.pas | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index bd43ddf71..98c731476 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -916,26 +916,38 @@ procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); procedure TFavoriteManager.Restore; var i, c: Integer; + s: TStringList; begin c := favoritesFile.ReadInteger('general', 'NumberOfFavorites', 0); - if c > 0 then - for i := 0 to c - 1 do - begin + if c = 0 then Exit; + s := TStringList.Create; + try + s.Sorted := True; + s.Duplicates := dupIgnore; + for i := 0 to c - 1 do begin Items.Add(TFavoriteContainer.Create); with Items.Last do begin Manager := Self; with favoritesFile, FavoriteInfo do begin - Title := ReadString(IntToStr(i), 'Title', ''); currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); - downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); + Title := ReadString(IntToStr(i), 'Title', ''); Website := ReadString(IntToStr(i), 'Website', ''); SaveTo := CorrectPathSys(ReadString(IntToStr(i), 'SaveTo', '')); Link := ReadString(IntToStr(i), 'Link', ''); Website := Website; Status := STATUS_IDLE; + + downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); + // remove duplicate + GetParams(s, DownloadedChapterList); + DownloadedChapterList := SetParams(s); + s.Clear; end; end; end; + finally + s.Free; + end; end; procedure TFavoriteManager.Backup; From 73802c777c3da39acd0a8f949025401a9b114359 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 07:23:35 +0800 Subject: [PATCH 1254/2794] mangainn, rewrite all code, removed old code fixed #296 --- baseunits/ModuleList.inc | 3 +- .../includes/MangaInn/chapter_page_number.inc | 31 ---- baseunits/includes/MangaInn/image_url.inc | 31 ---- .../includes/MangaInn/manga_information.inc | 122 --------------- .../includes/MangaInn/names_and_links.inc | 41 ----- baseunits/modules/MangaInn.pas | 144 ++++++++++++++++++ baseunits/uBaseUnit.pas | 142 +++++++++-------- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 10 -- 9 files changed, 215 insertions(+), 319 deletions(-) delete mode 100644 baseunits/includes/MangaInn/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaInn/image_url.inc delete mode 100644 baseunits/includes/MangaInn/manga_information.inc delete mode 100644 baseunits/includes/MangaInn/names_and_links.inc create mode 100644 baseunits/modules/MangaInn.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 97fc532b6..788668f0b 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -41,4 +41,5 @@ uses GMangaMe, SekaiManga, KuManga, - SenManga; + SenManga, + MangaInn; diff --git a/baseunits/includes/MangaInn/chapter_page_number.inc b/baseunits/includes/MangaInn/chapter_page_number.inc deleted file mode 100644 index d9ecd0a96..000000000 --- a/baseunits/includes/MangaInn/chapter_page_number.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetMangaInnPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAINN_ID, URL), - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - for i := parse.Count - 1 downto 5 do - begin - if Pos('</select>', parse[i]) <> 0 then - begin - try - Task.Container.PageNumber := StrToInt(Trim(parse[i - 3])); - except - Task.Container.PageNumber := 0; - end; - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaInn/image_url.inc b/baseunits/includes/MangaInn/image_url.inc deleted file mode 100644 index 14e89829f..000000000 --- a/baseunits/includes/MangaInn/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetMangaInnImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAINN_ID, URL) + - '/page_' + IntToStr(WorkId + 1), - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if GetTagName(parse[i]) = 'img' then - if GetVal(parse[i], 'id') = 'imgPage' then - begin - Task.Container.PageLinks[WorkId] := - GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaInn/manga_information.inc b/baseunits/includes/MangaInn/manga_information.inc deleted file mode 100644 index 21ad4e035..000000000 --- a/baseunits/includes/MangaInn/manga_information.inc +++ /dev/null @@ -1,122 +0,0 @@ - function GetMangaInnInfoFromURL: Byte; - var - i, j: Cardinal; - s: String; - isExtractChapters: Boolean = False; - begin - mangaInfo.url := FillMangaSiteHost(MANGAINN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAINN_ID, 0]; - - if parse.Count = 0 then - Exit; - - // using parser - mangaInfo.genres := ''; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i + 1], ' - Read ', ' Online For Free'); - - // get cover link - if GetTagName(parse[i]) = 'img' then - if Pos('/mangas/logos/', parse[i]) <> 0 then - mangaInfo.coverLink := - CorrectURL(GetVal(parse[i], 'src')); - - // get summary - if (Pos('Summary', parse[i])) <> 0 then - begin - j := i; - while Pos('</td>', parse[j]) = 0 do - begin - Inc(j); - if (GetTagName(parse[j]) = 'span') and - (GetVal(parse[j], 'class') <> '') then - begin - parse[j + 1] := StringFilter(parse[j + 1]); - parse[j + 1] := - StringReplace(parse[j + 1], #10, '\n', [rfReplaceAll]); - parse[j + 1] := - StringReplace(parse[j + 1], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := Trim(parse[j + 1]); - end; - end; - end; - - // get authors - if (Pos('Author(s)', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(TrimRight(parse[i + 4])); - - // get artists - if (Pos('Artist(s)', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(TrimRight(parse[i + 4])); - - // get genres - if (Pos('class="RedHeadLabel"', parse[i]) > 0) then - if (Pos('Genre(s)', parse[i + 1]) > 0) then - if mangaInfo.genres <> '' then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 5]) - else - mangaInfo.genres := Trim(parse[i + 5]); - - // get type(genres) - if (Pos('class="RedHeadLabel"', parse[i]) > 0) then - if (Pos('Type', parse[i + 1]) > 0) then - if mangaInfo.genres <> '' then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 6]) - else - mangaInfo.genres := Trim(parse[i + 6]); - - // get status - if (Pos('Status', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - if Pos('Completed', parse[i + 3]) <> 0 then - mangaInfo.status := '0'; // completed - end; - - if Pos('class="m"', parse[i]) > 0 then - if Pos('Chapter Name', parse[i + 1]) > 0 then - isExtractChapters := True; - //if isExtractChapters and - //(Pos('</table', parse[i]) > 0) then - //isExtractChapters := False; - // get chapter name and links - if isExtractChapters and - (Pos('/manga/chapter/', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - CorrectURL(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGAINN_ID, 1], - '', [rfReplaceAll]))); - s := Trim(parse[i + 2]); - if Length(s) > 0 then - if s[Length(s)] = ':' then - Delete(s, Length(s), 1); - s := Trim(s); - if Trim(parse[i + 4]) <> '' then - s := s + ' ' + Trim(parse[i + 4]); - mangaInfo.chapterName.Add(Trim(StringFilter(RemoveSymbols(s)))); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaInn/names_and_links.inc b/baseunits/includes/MangaInn/names_and_links.inc deleted file mode 100644 index 37db1e3f5..000000000 --- a/baseunits/includes/MangaInn/names_and_links.inc +++ /dev/null @@ -1,41 +0,0 @@ - function MangaInnGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAINN_ID, 1] + - MANGAINN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<li ', parse[i]) > 0) and - (Pos('class="mangalistItems"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := GetVal(parse[i + 1], 'href'); - s := StringReplace(s, WebsiteRoots[MANGAINN_ID, 1], '', - [rfIgnoreCase, rfReplaceAll]); - s := StringReplace(s, 'http://www.mangainn.com', '', - [rfIgnoreCase, rfReplaceAll]); - links.Add(s); - names.Add(Trim(StringFilter(parse[i + 2]))); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas new file mode 100644 index 000000000..ca75134f7 --- /dev/null +++ b/baseunits/modules/MangaInn.pas @@ -0,0 +1,144 @@ +unit MangaInn; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/MangaList'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@class="mangalistItems"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@itemprop="image"]/@src')); + if title = '' then + begin + title := XPathString('//title'); + if Pos(' - Read ', title) <> 0 then + title := Trim(GetBetween(' - Read ', ' Online For Free', title)); + end; + status := MangaInfoStatusIfPos( + XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Status")]/following-sibling::*[1]'), + 'Ongoing', + 'Complete'); + authors := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Author(s)")]/following-sibling::*[1]'); + artists := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Artist(s)")]/following-sibling::*[1]'); + genres := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Genre(s)")]/following-sibling::*[1]'); + summary := Trim(XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Summary")]/following-sibling::*')); + for v in XPath('//tr/td[1]/span/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('//select[@id="cmbpages"]/option').Count; + PageLinks.Add(XPathString('//*[@id="divimgPage"]/img/@src')); + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + s := MaybeFillHost(Module.RootURL, AURL); + if DownloadThread.WorkId > 0 then + s += '/page_' + IntToStr(DownloadThread.WorkId); + if GET(s) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.WorkId] := XPathString('//*[@id="divimgPage"]/img/@src'); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaInn'; + RootURL := 'http://www.mangainn.me'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 0d1676fa4..696ba9927 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -231,78 +231,76 @@ interface REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; ANIMEA_ID = 0; - MANGAINN_ID = 1; - OURMANGA_ID = 2; - MANGA24H_ID = 3; - VNSHARING_ID = 4; - FAKKU_ID = 5; - TRUYEN18_ID = 6; - MANGAPARK_ID = 7; - MANGATRADERS_ID = 8; - TRUYENTRANHTUAN_ID = 9; - TURKCRAFT_ID = 10; - EATMANGA_ID = 11; - STARKANA_ID = 12; - BLOGTRUYEN_ID = 13; - KOMIKID_ID = 14; - ESMANGAHERE_ID = 15; - ANIMEEXTREMIST_ID = 16; - HUGEMANGA_ID = 17; - S2SCAN_ID = 18; - IMANHUA_ID = 19; - MABUNS_ID = 20; - MANGAESTA_ID = 21; - CENTRALDEMANGAS_ID = 22; - EGSCANS_ID = 23; - MANGAAR_ID = 24; - MANGAAE_ID = 25; - ANIMESTORY_ID = 26; - LECTUREENLIGNE_ID = 27; - SCANMANGA_ID = 28; - MANGAGO_ID = 29; - DM5_ID = 30; - MANGACOW_ID = 31; - KIVMANGA_ID = 32; - MEINMANGA_ID = 33; - MANGASPROJECT_ID = 34; - MANGAREADER_POR_ID = 35; - NINEMANGA_ID = 36; - NINEMANGA_ES_ID = 37; - NINEMANGA_CN_ID = 38; - NINEMANGA_RU_ID = 39; - NINEMANGA_DE_ID = 40; - NINEMANGA_IT_ID = 41; - NINEMANGA_BR_ID = 42; - JAPANSHIN_ID = 43; - JAPSCAN_ID = 44; - CENTRUMMANGI_PL_ID = 45; - MANGALIB_PL_ID = 46; - ONEMANGA_ID = 47; - MANGATOWN_ID = 48; - MANGAOKU_ID = 49; - MYREADINGMANGAINFO_ID = 50; - IKOMIK_ID = 51; - NHENTAI_ID = 52; - MANGAMINT_ID = 53; - UNIXMANGA_ID = 54; - EXTREMEMANGAS_ID = 55; - MANGAHOST_ID = 56; - PORNCOMIX_ID = 57; - PORNCOMIXRE_ID = 58; - PORNCOMIXIC_ID = 59; - XXCOMICS_ID = 60; - XXCOMICSMT_ID = 61; - XXCOMICS3D_ID = 62; - PORNXXXCOMICS_ID = 63; - MANGASEE_ID = 64; - MANGAKU_ID = 65; - MANGAAT_ID = 66; - READMANGATODAY_ID = 67; - DYNASTYSCANS_ID = 68; - - WebsiteRoots: array [0..68] of array [0..1] of String = ( + OURMANGA_ID = 1; + MANGA24H_ID = 2; + VNSHARING_ID = 3; + FAKKU_ID = 4; + TRUYEN18_ID = 5; + MANGAPARK_ID = 6; + MANGATRADERS_ID = 7; + TRUYENTRANHTUAN_ID = 8; + TURKCRAFT_ID = 9; + EATMANGA_ID = 10; + STARKANA_ID = 11; + BLOGTRUYEN_ID = 12; + KOMIKID_ID = 13; + ESMANGAHERE_ID = 14; + ANIMEEXTREMIST_ID = 15; + HUGEMANGA_ID = 16; + S2SCAN_ID = 17; + IMANHUA_ID = 18; + MABUNS_ID = 19; + MANGAESTA_ID = 20; + CENTRALDEMANGAS_ID = 21; + EGSCANS_ID = 22; + MANGAAR_ID = 23; + MANGAAE_ID = 24; + ANIMESTORY_ID = 25; + LECTUREENLIGNE_ID = 26; + SCANMANGA_ID = 27; + MANGAGO_ID = 28; + DM5_ID = 29; + MANGACOW_ID = 30; + KIVMANGA_ID = 31; + MEINMANGA_ID = 32; + MANGASPROJECT_ID = 33; + MANGAREADER_POR_ID = 34; + NINEMANGA_ID = 35; + NINEMANGA_ES_ID = 36; + NINEMANGA_CN_ID = 37; + NINEMANGA_RU_ID = 38; + NINEMANGA_DE_ID = 39; + NINEMANGA_IT_ID = 40; + NINEMANGA_BR_ID = 41; + JAPANSHIN_ID = 42; + JAPSCAN_ID = 43; + CENTRUMMANGI_PL_ID = 44; + MANGALIB_PL_ID = 45; + ONEMANGA_ID = 46; + MANGATOWN_ID = 47; + MANGAOKU_ID = 48; + MYREADINGMANGAINFO_ID = 49; + IKOMIK_ID = 50; + NHENTAI_ID = 51; + MANGAMINT_ID = 52; + UNIXMANGA_ID = 53; + EXTREMEMANGAS_ID = 54; + MANGAHOST_ID = 55; + PORNCOMIX_ID = 56; + PORNCOMIXRE_ID = 57; + PORNCOMIXIC_ID = 58; + XXCOMICS_ID = 59; + XXCOMICSMT_ID = 60; + XXCOMICS3D_ID = 61; + PORNXXXCOMICS_ID = 62; + MANGASEE_ID = 63; + MANGAKU_ID = 64; + MANGAAT_ID = 65; + READMANGATODAY_ID = 66; + DYNASTYSCANS_ID = 67; + + WebsiteRoots: array [0..67] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), - ('MangaInn', 'http://www.mangainn.me'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), @@ -377,8 +375,6 @@ interface ANIMEA_BROWSER = '/browse.html?page='; ANIMEA_SKIP = '?skip=1'; - MANGAINN_BROWSER = '/mangalist/'; - OURMANGA_BROWSER = '/directory/'; MANGA24H_BROWSER = '/manga/update/page/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 53ac4192a..d18072042 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -971,8 +971,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/AnimExtremist/names_and_links.inc} - {$I includes/MangaInn/names_and_links.inc} - {$I includes/Manga24h/names_and_links.inc} {$I includes/VnSharing/names_and_links.inc} @@ -1088,9 +1086,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = ANIMEA_ID then Result := AnimeAGetNamesAndLinks else - if WebsiteID = MANGAINN_ID then - Result := MangaInnGetNamesAndLinks - else if WebsiteID = MANGA24H_ID then Result := Manga24hGetNamesAndLinks else @@ -1288,8 +1283,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/AnimExtremist/manga_information.inc} - {$I includes/MangaInn/manga_information.inc} - {$I includes/Manga24h/manga_information.inc} {$I includes/VnSharing/manga_information.inc} @@ -1417,9 +1410,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = ANIMEA_ID then Result := GetAnimeAInfoFromURL else - if WebsiteID = MANGAINN_ID then - Result := GetMangaInnInfoFromURL - else if WebsiteID = MANGA24H_ID then Result := GetManga24hInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4a4ed75f7..9c0a1775b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -383,8 +383,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaGo/chapter_page_number.inc} - {$I includes/MangaInn/chapter_page_number.inc} - {$I includes/MangaPark/chapter_page_number.inc} {$I includes/MangaTraders/chapter_page_number.inc} @@ -454,9 +452,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAPageNumber else - if Task.Container.MangaSiteID = MANGAINN_ID then - Result := GetMangaInnPageNumber - else if Task.Container.MangaSiteID = MANGATRADERS_ID then Result := GetMangaTradersPageNumber else @@ -627,8 +622,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaGo/image_url.inc} - {$I includes/MangaInn/image_url.inc} - //{$I includes/MangaPark/image_url.inc} {$I includes/MangaREADER_POR/image_url.inc} @@ -694,9 +687,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGATRADERS_ID then Result := GetMangaTradersImageURL else - if Task.Container.MangaSiteID = MANGAINN_ID then - Result := GetMangaInnImageURL - else if Task.Container.MangaSiteID = MANGA24H_ID then Result := GetManga24hImageURL else From 88f627029b39eaff280902612471fb0de0a9ee5c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Jun 2016 07:28:55 +0800 Subject: [PATCH 1255/2794] Bump version 0.9.65.0 --- changelog.txt | 9 ++++++++- mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7390f8f88..a28dae7a6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,12 +4,19 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.65.0 (16-06-2016) +[*] Fixed check for new chapters +[*] Tumangaonline: fixed get all chapters +[*] MangaInn: rewrite all code +[*] Various changes and bug fix +Full changes: https://github.com/riderkick/FMD/compare/0.9.64.0...0.9.65.0 + 0.9.64.0 (15-06-2016) [+] Show new chapters and status downloaded while checking favorites with icon and highlight [*] SenManga: fixed all [+] E-Hentai/ExHentai: replace option download original image with image size with combobox [*] Various changes and bug fix -Full changes: https://github.com/riderkick/FMD/compare/0.9.62.0...0.9.63.0 +Full changes: https://github.com/riderkick/FMD/compare/0.9.63.0...0.9.64.0 0.9.63.0 (11-06-2016) [*] Fixed an issue with CF diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 994f7f5a8..79618f077 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="64"/> + <RevisionNr Value="65"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index b4307c8e7..f0eb057ed 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.64.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.64.0/fmd_0.9.64.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.64.0/fmd_0.9.64.0_Win64.7z +VERSION=0.9.65.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.65.0/fmd_0.9.65.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.65.0/fmd_0.9.65.0_Win64.7z From 523264fc249ee16a830425dc38e5dac9afb34358 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Jun 2016 19:04:18 +0800 Subject: [PATCH 1256/2794] fixed kissmanga and readcomiconline mangainfo fixed #300 --- baseunits/modules/KissManga.pas | 41 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 015202116..8efd05043 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -91,7 +91,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - i: Integer; s: String; begin Result := NET_PROBLEM; @@ -101,25 +100,35 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try coverLink := XPathString('//div[@id="rightside"]//img/@src'); - if title = '' then title := XPathString('//div[@id="leftside"]//a[@class="bigChar"]'); - v := XPath('//div[@id="leftside"]//div[@class="barContent"]/div/p'); - for i := 1 to v.Count do + if title = '' then begin - s := v.get(i).toString; - if Pos('Genres', s) = 1 then genres := SeparateRight(s, ':') else - if (Pos('Author', s) = 1) or (Pos('Writer', s) = 1) then authors := SeparateRight(s, ':') else - if Pos('Artist', s) = 1 then artists := SeparateRight(s, ':') else - if Pos('Status', s) = 1 then begin - if Pos('ONGOING', UpperCase(s)) > 0 then - status := '1' - else if Pos('COMPLETED', UpperCase(s)) > 0 then - status := '0'; - end else - if Pos('Summary:', s) = 1 then summary := v.get(i + 1).toString; + title := XPathString('//title'); + if title <> '' then + begin + if Pos('manga | Read', title) <> 0 then + title := SeparateLeft(title, 'manga | Read') + else if Pos('comic | Read', title) <> 0 then + title := SeparateLeft(title, 'comic | Read'); + end; end; + genres := SeparateRight(XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Genres:")]'), ':'); + authors := SeparateRight(XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Author:")]'), ':'); + artists := SeparateRight(XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Artist:")]'), ':'); + status := MangaInfoStatusIfPos(XPathString( + '//div[@class="barContent"]/div/p[starts-with(.,"Status:")]'), + 'Ongoing', + 'Completed'); + summary := XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Summary:")]//following-sibling::p[1]'); for v in XPath('//table[@class="listing"]/tbody/tr/td/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + s := v.toNode.getAttribute('title'); + if LeftStr(s, 5) = 'Read ' then + Delete(s, 1, 5); + if RightStr(s, 7) = ' online' then + SetLength(s, Length(s) - 7) + else if RightStr(s, 29) = ' comic online in high quality' then + SetLength(s, Length(s) - 29); + chapterName.Add(s); end; InvertStrings([chapterLinks, chapterName]); finally From 521e6b9fe9593a024fa1d852d8e0fd912e0fda73 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Jun 2016 21:33:00 +0800 Subject: [PATCH 1257/2794] added leomanga fixed #299 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/LeoManga.pas | 164 +++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/LeoManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 788668f0b..e9d6c20b0 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -42,4 +42,5 @@ uses SekaiManga, KuManga, SenManga, - MangaInn; + MangaInn, + LeoManga; diff --git a/baseunits/modules/LeoManga.pas b/baseunits/modules/LeoManga.pas new file mode 100644 index 000000000..020a790f5 --- /dev/null +++ b/baseunits/modules/LeoManga.pas @@ -0,0 +1,164 @@ +unit LeoManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/directorio-manga?orden=alfabetico'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(SeparateRight( + XPathString('//ul[@class="pagination"]/li[last()-1]/a/@href'), 'pagina='), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + s := Module.RootURL + dirurl; + if AURL <> '0' then + s += '&pagina=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="list-inline reset-floats"]/li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(Trim(XPathString('div//h2/text()[1]', v.toNode))); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v, x: IXQValue; + s, t: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@class="manga-picture"]/@src')); + if title = '' then + begin + title := XPathString('//*[@id="page-manga"]/h1'); + if RightStr(title, 6) = ' Manga' then + SetLength(title, Length(title) - 6); + end; + summary := XPathString('//*[@id="page-manga"]/h2[.="Sinopsis"]/following-sibling::p/text()'); + authors := XPathStringAll('//*[@id="page-manga"]/div[@class="row"]/div/strong[.="Autor:"]/following-sibling::a'); + genres := XPathStringAll('//*[@id="page-manga"]/div[@class="row"]/div/strong[.="Géneros:"]/following-sibling::a'); + for v in XPath('//ul[@class="list-unstyled caps-list"]/li') do + begin + s := Trim(XPathString('div[1]/h3/text()[2]', v.toNode)); + for x in XPath('div[2]/ul/li/a', v.toNode) do + begin + chapterLinks.Add(x.toNode.getAttribute('href')); + t := x.toString; + if s <> '' then + t := s + ' ' + t; + chapterName.Add(t); + end; + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s, p: String; + i: Integer; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//a[contains(@class,"btn")][.="Online"]/@href'); + if s = '' then Exit; + if GET(MaybeFillHost(Module.RootURL, s)) then + begin + ParseHTML(Document); + s := XPathString('//*[@id="read-chapter"]/@name'); + if s <> '' then + s := AppendURLDelim(MaybeFillHost(Module.RootURL, s)); + p := XPathString('//*[@id="read-chapter"]/@pos'); + if p <> '' then + begin + ExtractStrings([';'],[], PChar(p), PageLinks, False); + if (s <> '') and (PageLinks.Count > 0) then + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := s + PageLinks[i]; + end; + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'LeoManga'; + RootURL := 'http://www.leomanga.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index ccb6a6775..3c8451fa1 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -15,7 +15,7 @@ Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU -Spanish=AnimExtremist,ESMangaHere,KuManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline +Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing From 0492617e1222d576a6cdd01f98349963dc196372 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Jun 2016 21:40:25 +0800 Subject: [PATCH 1258/2794] Bump version 0.9.66.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index a28dae7a6..8ce74ace1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.66.0 (18-06-2016) +[*] KissManga: fixed manga info +[+] Added LeoManga[ES] +Full changes: https://github.com/riderkick/FMD/compare/0.9.65.0...0.9.66.0 + 0.9.65.0 (16-06-2016) [*] Fixed check for new chapters [*] Tumangaonline: fixed get all chapters diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 79618f077..cab57f774 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="65"/> + <RevisionNr Value="66"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index f0eb057ed..5ba097b41 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.65.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.65.0/fmd_0.9.65.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.65.0/fmd_0.9.65.0_Win64.7z +VERSION=0.9.66.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.66.0/fmd_0.9.66.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.66.0/fmd_0.9.66.0_Win64.7z From d33a284ccf8cb2ad26448039494eccb7394a1fc1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 08:26:04 +0800 Subject: [PATCH 1259/2794] mangapark, rewrite all code #302 --- baseunits/ModuleList.inc | 3 +- .../MangaPark/chapter_page_number.inc | 29 ---- .../MangaPark/directory_page_number.inc | 42 ----- baseunits/includes/MangaPark/image_url.inc | 31 ---- .../includes/MangaPark/manga_information.inc | 142 ---------------- .../includes/MangaPark/names_and_links.inc | 34 ---- baseunits/modules/MangaPark.pas | 155 ++++++++++++++++++ baseunits/uBaseUnit.pas | 131 ++++++++------- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- 10 files changed, 221 insertions(+), 371 deletions(-) delete mode 100644 baseunits/includes/MangaPark/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaPark/directory_page_number.inc delete mode 100644 baseunits/includes/MangaPark/image_url.inc delete mode 100644 baseunits/includes/MangaPark/manga_information.inc delete mode 100644 baseunits/includes/MangaPark/names_and_links.inc create mode 100644 baseunits/modules/MangaPark.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e9d6c20b0..ad56d9d53 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -43,4 +43,5 @@ uses KuManga, SenManga, MangaInn, - LeoManga; + LeoManga, + MangaPark; diff --git a/baseunits/includes/MangaPark/chapter_page_number.inc b/baseunits/includes/MangaPark/chapter_page_number.inc deleted file mode 100644 index 8c1674a46..000000000 --- a/baseunits/includes/MangaPark/chapter_page_number.inc +++ /dev/null @@ -1,29 +0,0 @@ - function GetMangaParkPageNumber: Boolean; - var - i: LongInt; - s: String; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := URL; - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAPARK_ID, s), - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) <> 0) and (Pos('id="img-', parse[i]) <> 0) then - begin - Inc(Task.Container.PageNumber); - Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaPark/directory_page_number.inc b/baseunits/includes/MangaPark/directory_page_number.inc deleted file mode 100644 index bf32cc338..000000000 --- a/baseunits/includes/MangaPark/directory_page_number.inc +++ /dev/null @@ -1,42 +0,0 @@ - function GetMangaParkDirectoryPageNumber: Byte; - var - i: LongInt; - isExtractPage: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAPARK_ID, 1] + - '/search?orderby=add', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'onchange') = - 'javascript:window.location.href=this.options[this.selectedIndex].value;') then - isExtractPage := True; - if isExtractPage then - begin - if GetTagName(parse[i]) = '/select' then - Break - else if GetTagName(parse[i]) = 'option' then - Inc(Page); - end; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MangaPark/image_url.inc b/baseunits/includes/MangaPark/image_url.inc deleted file mode 100644 index 75f40e98f..000000000 --- a/baseunits/includes/MangaPark/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetMangaParkImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGAPARK_ID, URL) + - 'all',//IntToStr(WorkId+1), - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - // if GetTagName(parse[i]) = 'img' then - if (Pos('a target="_blank"', parse[i]) > 0) then - begin - Task.Container.PageLinks.Add(GetVal(parse[i], 'href')); - // break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaPark/manga_information.inc b/baseunits/includes/MangaPark/manga_information.inc deleted file mode 100644 index 990e043d7..000000000 --- a/baseunits/includes/MangaPark/manga_information.inc +++ /dev/null @@ -1,142 +0,0 @@ - function GetMangaParkInfoFromURL: Byte; - var - s, sver: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - tnames, tlinks: TStringList; - begin - mangaInfo.website := WebsiteRoots[MANGAPARK_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAPARK_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count > 0 then - begin - tnames:= TStringList.Create; - tlinks:= TStringList.Create; - try - sver := ''; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('property="og:title"', parse[i]) <> 0) then - begin - mangaInfo.title := CommonStringFilter(GetVal(parse[i], 'content')); - mangaInfo.title := ReplaceRegExpr('\sManga$', mangaInfo.title, '', False); - end; - - // get cover - if (GetTagName(parse[i]) = 'meta') and - (Pos('property="og:image"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'content')); - - // get summary - if (Pos('<h2>', parse[i]) <> 0) and - (Pos('Summary', parse[i + 1]) <> 0) and - (isExtractSummary) then - begin - j := i + 3; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get chapter name and links - if (Pos('<a', parse[i]) <> 0) and (Pos('class="st st', parse[i]) <> 0) then - begin - if tlinks.Count > 0 then - begin - InvertStrings([tnames, tlinks]); - mangaInfo.chapterName.AddStrings(tnames); - mangaInfo.chapterLinks.AddStrings(tlinks); - tnames.Clear; - tlinks.Clear; - end; - sver := Trim(parse[i + 1]); - end; - if (Pos('<a', parse[i]) <> 0) and (Pos('class="ch sts sts', parse[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - tlinks.Add(s); - tnames.Add(CommonStringFilter( - Format('%s %s %s', [sver, Trim(parse[i + 1]), Trim(parse[i + 3])]))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Author(s)', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse[i + 6]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist(s)', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse[i + 6]); - - // get genres - if (Pos('Genre(s)', parse[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if Pos('/genre/', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse[i + 1])) + ', '; - if Pos('</td>', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - finally - if tlinks.Count > 0 then - begin - InvertStrings([tnames, tlinks]); - mangaInfo.chapterName.AddStrings(tnames); - mangaInfo.chapterLinks.AddStrings(tlinks); - end; - tnames.Free; - tlinks.Free; - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaPark/names_and_links.inc b/baseunits/includes/MangaPark/names_and_links.inc deleted file mode 100644 index 1bc62ecae..000000000 --- a/baseunits/includes/MangaPark/names_and_links.inc +++ /dev/null @@ -1,34 +0,0 @@ - function MangaParkGetNamesAndLinks: Byte; - var - i: LongInt; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAPARK_ID, 1] + - '/search?orderby=add&page=' + IntToStr(StrToInt(URL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'em') and (GetVal(parse[i], 'class') = 'icon') then - begin - links.Add(GetVal(parse[i + 3], 'href')); - names.Add(CommonStringFilter(GetVal(parse[i + 3], 'title'))); - end; - end; - Source.Free; - end; diff --git a/baseunits/modules/MangaPark.pas b/baseunits/modules/MangaPark.pas new file mode 100644 index 000000000..a9ba99fcc --- /dev/null +++ b/baseunits/modules/MangaPark.pas @@ -0,0 +1,155 @@ +unit MangaPark; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/search?orderby=add'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(SeparateRight( + XPathString('//ul[@class="paging full"]/li[last()-2]/a/@href'), 'page='), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + s := Module.RootURL + dirurl; + if AURL <> '0' then + s += '&page=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@class="manga-list"]/div//td/h2/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v, x: IXQValue; + s, t: String; + i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); + if title = '' then title := XPathString('//*[@class="content"]//h1'); + authors := XPathStringAll('//table[@class="attr"]//tr/th[.="Author(s)"]/following-sibling::td/a'); + artists := XPathStringAll('//table[@class="attr"]//tr/th[.="Artist(s)"]/following-sibling::td/a'); + genres := XPathStringAll('//table[@class="attr"]//tr/th[.="Genre(s)"]/following-sibling::td/a'); + status := MangaInfoStatusIfPos(XPathString( + '//table[@class="attr"]//tr/th[.="Status"]/following-sibling::td'), + 'Ongoing', + 'Completed'); + summary := XPathString('//*[@class="content"]/p[@class="summary"]'); + for v in XPath('//*[@id="list"]/*[contains(@id,"stream")]') do + begin + s := Trim(XPathString('h3', v.toNode)); + x := XPath('div/ul/li/span', v.toNode); + for i := x.Count downto 1 do + begin + t := XPathString('a/@href', x.get(i).toNode); + if RightStr(t, 2) = '/1' then + SetLength(t, Length(t) - 2); + chapterLinks.Add(t); + t := x.get(i).toString; + if s <> '' then + t := s + ' ' + t; + chapterName.Add(t); + end; + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + s := MaybeFillHost(Module.RootURL, AURL); + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 2); + if GET(s) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//img[@class="img"]/@src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaPark'; + RootURL := 'http://mangapark.me'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 696ba9927..9d5a65612 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -236,77 +236,75 @@ interface VNSHARING_ID = 3; FAKKU_ID = 4; TRUYEN18_ID = 5; - MANGAPARK_ID = 6; - MANGATRADERS_ID = 7; - TRUYENTRANHTUAN_ID = 8; - TURKCRAFT_ID = 9; - EATMANGA_ID = 10; - STARKANA_ID = 11; - BLOGTRUYEN_ID = 12; - KOMIKID_ID = 13; - ESMANGAHERE_ID = 14; - ANIMEEXTREMIST_ID = 15; - HUGEMANGA_ID = 16; - S2SCAN_ID = 17; - IMANHUA_ID = 18; - MABUNS_ID = 19; - MANGAESTA_ID = 20; - CENTRALDEMANGAS_ID = 21; - EGSCANS_ID = 22; - MANGAAR_ID = 23; - MANGAAE_ID = 24; - ANIMESTORY_ID = 25; - LECTUREENLIGNE_ID = 26; - SCANMANGA_ID = 27; - MANGAGO_ID = 28; - DM5_ID = 29; - MANGACOW_ID = 30; - KIVMANGA_ID = 31; - MEINMANGA_ID = 32; - MANGASPROJECT_ID = 33; - MANGAREADER_POR_ID = 34; - NINEMANGA_ID = 35; - NINEMANGA_ES_ID = 36; - NINEMANGA_CN_ID = 37; - NINEMANGA_RU_ID = 38; - NINEMANGA_DE_ID = 39; - NINEMANGA_IT_ID = 40; - NINEMANGA_BR_ID = 41; - JAPANSHIN_ID = 42; - JAPSCAN_ID = 43; - CENTRUMMANGI_PL_ID = 44; - MANGALIB_PL_ID = 45; - ONEMANGA_ID = 46; - MANGATOWN_ID = 47; - MANGAOKU_ID = 48; - MYREADINGMANGAINFO_ID = 49; - IKOMIK_ID = 50; - NHENTAI_ID = 51; - MANGAMINT_ID = 52; - UNIXMANGA_ID = 53; - EXTREMEMANGAS_ID = 54; - MANGAHOST_ID = 55; - PORNCOMIX_ID = 56; - PORNCOMIXRE_ID = 57; - PORNCOMIXIC_ID = 58; - XXCOMICS_ID = 59; - XXCOMICSMT_ID = 60; - XXCOMICS3D_ID = 61; - PORNXXXCOMICS_ID = 62; - MANGASEE_ID = 63; - MANGAKU_ID = 64; - MANGAAT_ID = 65; - READMANGATODAY_ID = 66; - DYNASTYSCANS_ID = 67; - - WebsiteRoots: array [0..67] of array [0..1] of String = ( + MANGATRADERS_ID = 6; + TRUYENTRANHTUAN_ID = 7; + TURKCRAFT_ID = 8; + EATMANGA_ID = 9; + STARKANA_ID = 10; + BLOGTRUYEN_ID = 11; + KOMIKID_ID = 12; + ESMANGAHERE_ID = 13; + ANIMEEXTREMIST_ID = 14; + HUGEMANGA_ID = 15; + S2SCAN_ID = 16; + IMANHUA_ID = 17; + MABUNS_ID = 18; + MANGAESTA_ID = 19; + CENTRALDEMANGAS_ID = 20; + EGSCANS_ID = 21; + MANGAAR_ID = 22; + MANGAAE_ID = 23; + ANIMESTORY_ID = 24; + LECTUREENLIGNE_ID = 25; + SCANMANGA_ID = 26; + MANGAGO_ID = 27; + DM5_ID = 28; + MANGACOW_ID = 29; + KIVMANGA_ID = 30; + MEINMANGA_ID = 31; + MANGASPROJECT_ID = 32; + MANGAREADER_POR_ID = 33; + NINEMANGA_ID = 34; + NINEMANGA_ES_ID = 35; + NINEMANGA_CN_ID = 36; + NINEMANGA_RU_ID = 37; + NINEMANGA_DE_ID = 38; + NINEMANGA_IT_ID = 39; + NINEMANGA_BR_ID = 40; + JAPANSHIN_ID = 41; + JAPSCAN_ID = 42; + CENTRUMMANGI_PL_ID = 43; + MANGALIB_PL_ID = 44; + ONEMANGA_ID = 45; + MANGATOWN_ID = 46; + MANGAOKU_ID = 47; + MYREADINGMANGAINFO_ID = 48; + IKOMIK_ID = 49; + NHENTAI_ID = 50; + MANGAMINT_ID = 51; + UNIXMANGA_ID = 52; + EXTREMEMANGAS_ID = 53; + MANGAHOST_ID = 54; + PORNCOMIX_ID = 55; + PORNCOMIXRE_ID = 56; + PORNCOMIXIC_ID = 57; + XXCOMICS_ID = 58; + XXCOMICSMT_ID = 59; + XXCOMICS3D_ID = 60; + PORNXXXCOMICS_ID = 61; + MANGASEE_ID = 62; + MANGAKU_ID = 63; + MANGAAT_ID = 64; + READMANGATODAY_ID = 65; + DYNASTYSCANS_ID = 66; + + WebsiteRoots: array [0..66] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Fakku', 'https://www.fakku.net'), ('Truyen18', 'http://www.truyen18.org'), - ('MangaPark', 'http://mangapark.me'), ('MangaTraders', 'http://mangatraders.org'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), @@ -1137,8 +1135,7 @@ function SitesWithSortedList(const website: String): Boolean; XXCOMICS3D_ID, PORNCOMIXRE_ID, PORNCOMIXIC_ID, - PORNXXXCOMICS_ID, - MANGAPARK_ID + PORNXXXCOMICS_ID ]); end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d18072042..871fa8a6c 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -777,8 +777,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/Fakku/directory_page_number.inc} - {$I includes/MangaPark/directory_page_number.inc} - //{$I includes/MangaTraders/directory_page_number.inc} {$I includes/MangaGo/directory_page_number.inc} @@ -862,9 +860,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St if WebsiteID = FAKKU_ID then Result := GetFakkuDirectoryPageNumber else - if WebsiteID = MANGAPARK_ID then - Result := GetMangaParkDirectoryPageNumber - else //if WebsiteID = MANGATRADERS_ID then // Result := GetMangaTradersDirectoryPageNumber //else @@ -977,8 +972,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Fakku/names_and_links.inc} - {$I includes/MangaPark/names_and_links.inc} - {$I includes/MangaTraders/names_and_links.inc} {$I includes/TruyenTranhTuan/names_and_links.inc} @@ -1095,9 +1088,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = FAKKU_ID then Result := FakkuGetNamesAndLinks else - if WebsiteID = MANGAPARK_ID then - Result := MangaParkGetNamesAndLinks - else if WebsiteID = MANGATRADERS_ID then Result := MangaTradersGetNamesAndLinks else @@ -1289,8 +1279,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/Fakku/manga_information.inc} - {$I includes/MangaPark/manga_information.inc} - {$I includes/MangaTraders/manga_information.inc} {$I includes/Starkana/manga_information.inc} @@ -1419,9 +1407,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = FAKKU_ID then Result := GetFakkuInfoFromURL else - if WebsiteID = MANGAPARK_ID then - Result := GetMangaParkInfoFromURL - else if WebsiteID = MANGATRADERS_ID then Result := GetMangaTradersInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9c0a1775b..d1f05d7ca 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -383,8 +383,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaGo/chapter_page_number.inc} - {$I includes/MangaPark/chapter_page_number.inc} - {$I includes/MangaTraders/chapter_page_number.inc} {$I includes/MeinManga/chapter_page_number.inc} @@ -461,9 +459,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaPageNumber else - if Task.Container.MangaSiteID = MANGAPARK_ID then - Result := GetMangaParkPageNumber - else if Task.Container.MangaSiteID = MANGAGO_ID then Result := GetMangaGoPageNumber else @@ -622,8 +617,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaGo/image_url.inc} - //{$I includes/MangaPark/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -696,9 +689,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = FAKKU_ID then Result := GetFakkuImageURL else - //if Task.Container.MangaSiteID = MANGAPARK_ID then - // Result := GetMangaParkImageURL - //else if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaImageURL else From 7f644a0c3f35f677bc37b14b9f1539bdcb30c94e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 09:06:35 +0800 Subject: [PATCH 1260/2794] httpsendthread, added maybeencodeurl, only encode unencoded url fixed #302 --- baseunits/httpsendthread.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index d911c5a07..fe75a8353 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -49,6 +49,8 @@ procedure SetDefaultProxyAndApply(const ProxyType, Host, Port, User, Pass: Strin procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); +function MaybeEncodeURL(const AValue: String): String; + var DefaultUserAgent: String = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; @@ -148,6 +150,14 @@ procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); end; end; +function MaybeEncodeURL(const AValue: String): String; +begin + Result := Trim(AValue); + if Result = '' then Exit; + if Length(DecodeURL(Result)) >= Length(Result) then + Result := EncodeURL(Result); +end; + { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); @@ -218,7 +228,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: mstream: TMemoryStream; begin Result := False; - rurl := EncodeURL(DecodeURL(URL)); + rurl := MaybeEncodeURL(URL); if Pos('HTTP/', Headers.Text) = 1 then Reset; HTTPHeader := TStringList.Create; HTTPHeader.Assign(Headers); From 4d82af68cd3723c1ad8dec3565d3589943fc9b38 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 09:35:01 +0800 Subject: [PATCH 1261/2794] httpsendthread, httprequest return true if size of document > 0 --- baseunits/httpsendthread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index fe75a8353..e17544fa7 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -300,7 +300,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: on E: Exception do WriteLog_E('HTTPRequest.WriteOutput.Error!', E); end; - Result := ResultCode < 500; + Result := Document.Size > 0; finally HTTPHeader.Free; end; From 5963ed75fded68464e8830d0673957c168cf72f4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 10:28:57 +0800 Subject: [PATCH 1262/2794] properly register unregister gwl_wndproc --- mangadownloader/forms/frmMain.pas | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f6250e653..2d1dadf19 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -843,20 +843,16 @@ implementation function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall; begin - try - if uMsg = WM_DISPLAYCHANGE then - begin - Screen.UpdateMonitors; - Screen.UpdateScreen; - if Screen.MonitorCount < MainForm.Monitor.MonitorNum then - MainForm.DefaultMonitor := dmMainForm; - if (MainForm.Left > Screen.Width) or (MainForm.Top > Screen.Height) then - MainForm.MoveToDefaultPosition; - end - else - Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam); - except + if uMsg = WM_DISPLAYCHANGE then + begin + Screen.UpdateMonitors; + Screen.UpdateScreen; + if Screen.MonitorCount < MainForm.Monitor.MonitorNum then + MainForm.DefaultMonitor := dmMainForm; + if (MainForm.Left > Screen.Width) or (MainForm.Top > Screen.Height) then + MainForm.MoveToDefaultPosition; end; + Result := CallWindowProc(PrevWndProc, Ahwnd, uMsg, WParam, LParam); end; {$endif} @@ -1028,7 +1024,8 @@ procedure TMainForm.FormCreate(Sender: TObject); begin Randomize; {$ifdef windows} - PrevWndProc := Windows.WNDPROC(SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback))); + PrevWndProc := windows.WNDPROC(GetWindowLong(Self.Handle, GWL_WNDPROC)); + windows.SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)); {$endif} SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), FormatDateTime('dd-mm-yyyy', Now)])); @@ -1198,6 +1195,10 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin + {$ifdef windows} + if Assigned(PrevWndProc) then + windows.SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(PrevWndProc)); + {$endif} Writelog_D(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); FavoriteManager.StopChekForNewChapter(True); SilentThreadManager.StopAll(True); From e4f8bf790c39e1f657f2c8abbaa71c57c76c744d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 10:49:02 +0800 Subject: [PATCH 1263/2794] httpsendthread, added property allowservererrorresponse --- baseunits/httpsendthread.pas | 47 ++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index e17544fa7..58477b44a 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -14,10 +14,11 @@ interface THTTPSendThread = class(THTTPSend) private - fowner: TFMDThread; - fretrycount: Integer; - fgzip: Boolean; - ffollowredirection: Boolean; + FOwner: TFMDThread; + FRetryCount: Integer; + FGZip: Boolean; + FFollowRedirection: Boolean; + FAllowServerErrorResponse: Boolean; procedure SetTimeout(AValue: Integer); procedure OnOwnerTerminate(Sender: TObject); public @@ -34,10 +35,11 @@ THTTPSendThread = class(THTTPSend) procedure SetNoProxy; procedure Reset; property Timeout: Integer read FTimeout write SetTimeout; - property RetryCount: Integer read fretrycount write fretrycount; - property GZip: Boolean read fgzip write fgzip; - property FollowRedirection: Boolean read ffollowredirection write ffollowredirection; - property Thread: TFMDThread read fowner; + property RetryCount: Integer read FRetryCount write FRetryCount; + property GZip: Boolean read FGZip write FGZip; + property FollowRedirection: Boolean read FFollowRedirection write FFollowRedirection; + property AllowServerErrorResponse: Boolean read FAllowServerErrorResponse write FAllowServerErrorResponse; + property Thread: TFMDThread read FOwner; end; TKeyValuePair = array[0..1] of String; @@ -183,16 +185,17 @@ constructor THTTPSendThread.Create(AOwner: TFMDThread); Protocol := '1.1'; Headers.NameValueSeparator := ':'; Cookies.NameValueSeparator := '='; - fgzip := True; - ffollowredirection := True; - fretrycount := DefaultRetryCount; + FGZip := True; + FFollowRedirection := True; + FAllowServerErrorResponse := False; + FRetryCount := DefaultRetryCount; SetTimeout(DefaultTimeout); SetProxy(DefaultProxyType, DefaultProxyHost, DefaultProxyPort, DefaultProxyUser, DefaultProxyPass); Reset; if Assigned(AOwner) then begin - fowner := AOwner; - fowner.OnCustomTerminate := @OnOwnerTerminate; + FOwner := AOwner; + FOwner.OnCustomTerminate := @OnOwnerTerminate; end; EnterCriticalsection(CS_ALLHTTPSendThread); try @@ -234,15 +237,16 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: HTTPHeader.Assign(Headers); try // first request - while (not HTTPMethod(Method, rurl)) or (ResultCode = 500) do begin + while (not HTTPMethod(Method, rurl)) or + ((not FAllowServerErrorResponse) and (ResultCode > 500)) do begin if CheckTerminate then Exit; - if (fretrycount > -1) and (fretrycount <= counter) then Exit; + if (FRetryCount > -1) and (FRetryCount <= counter) then Exit; Inc(Counter); Headers.Assign(HTTPHeader); end; // redirection ' - if ffollowredirection then + if FFollowRedirection then while (ResultCode > 300) and (ResultCode < 400) do begin if CheckTerminate then Exit; HTTPHeader.Values['Referer'] := ' ' + rurl; @@ -263,9 +267,10 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: Clear; Headers.Assign(HTTPHeader); counter := 0; - while (not HTTPMethod('GET', rurl)) or (ResultCode > 500) do begin + while (not HTTPMethod('GET', rurl)) or + ((not FAllowServerErrorResponse) and (ResultCode > 500)) do begin if checkTerminate then Exit; - if (fretrycount > -1) and (fretrycount <= counter) then Exit; + if (FRetryCount > -1) and (FRetryCount <= counter) then Exit; Inc(counter); Clear; Headers.Assign(HTTPHeader); @@ -342,8 +347,8 @@ function THTTPSendThread.GetCookies: String; function THTTPSendThread.ThreadTerminated: Boolean; begin Result := False; - if Assigned(fowner) then - Result := fowner.IsTerminated; + if Assigned(FOwner) then + Result := FOwner.IsTerminated; end; procedure THTTPSendThread.RemoveCookie(const CookieName: String); @@ -407,7 +412,7 @@ procedure THTTPSendThread.Reset; Headers.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; Headers.Values['Accept-Charset'] := ' utf8'; Headers.Values['Accept-Language'] := ' en-US,en;q=0.8'; - if fgzip then Headers.Values['Accept-Encoding'] := ' gzip, deflate'; + if FGZip then Headers.Values['Accept-Encoding'] := ' gzip, deflate'; end; initialization From f02fa29fdf0ded92ab707b86f97834dc23c8ed7b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 12:37:16 +0800 Subject: [PATCH 1264/2794] wpmanga, fixed mangainfo and get images, added mangajoy closed #302 --- baseunits/modules/WPManga.pas | 83 +++++++++++++++++++++-------------- config/mangalist.ini | 2 +- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index fc1f94afe..27075614a 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -29,6 +29,8 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else if Module.Website = 'MangaHen' then s := dirURLmangahen else s := dirURL; + if Module.Website = 'Manga-Joy' then + AllowServerErrorResponse := True; if GET(Module.RootURL + s) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -56,6 +58,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga else if Module.Website = 'MangaHen' then s := dirURLmangahen else s := dirURL; + if Module.Website = 'Manga-Joy' then + AllowServerErrorResponse := True; if GET(Module.RootURL + s + IncStr(AURL) + '/') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -98,29 +102,25 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; i, pagecount: Integer; procedure scanchapters; + var + t: String; begin - with MangaInfo.mangaInfo, query do if Module.Website = 'MangaBoom' then - for v in XPath('//ul[@class="lst"]//a[1]') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toNode.Next.toString()); - end - else if (Module.Website = 'EyeOnManga') or - (Module.Website = 'MangaIndo') then - for v in XPath('//ul[@class="chp_lst"]//a[1]') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end - else begin - for v in XPath('//ul[@class="lst"]//a[1]/@href') do - chapterLinks.Add(v.toString); - for v in XPath('//ul[@class="lst"]//a[1]/b[1]') do - chapterName.Add(v.toString); + with MangaInfo.mangaInfo, query, TRegExpr.Create do + for v in XPath('//ul[contains(@class,"lst")]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + t := v.toNode.getAttribute('title'); + if t = '' then + t := XPathString('*[@class="val"]', v.toNode); + if t = '' then + t := XPathString('text()[1]', v.toNode); + chapterName.Add(t); end; end; function getwpmangavalue(aname: String): String; begin - Result := query.XPathString('(//*[@class="mng_ifo"]//p)[starts-with(.,"' + + Result := query.XPathString('//*[contains(@class,"mng_det")]//p[starts-with(.,"' + aname + '")]'); if Result <> '' then Result := Trim(TrimChar(SeparateRight(Result, aname), [':', ' '])); if Result = '-' then @@ -130,21 +130,18 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; procedure scaninfo; begin with MangaInfo.mangaInfo, query do begin - if Module.Website = 'EyeOnManga' then - summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]') - else - summary := XPathString('//*[@class="det"]/p[1]'); - if summary <> '' then - summary := TrimChar(SeparateRight(summary, 'Summary'), [':', ' ']); authors := getwpmangavalue('Author'); artists := getwpmangavalue('Artist'); - genres := getwpmangavalue('Category'); - status := getwpmangavalue('Status'); - if status <> '' then begin - status := LowerCase(status); - if Pos('ongoing', status) > 0 then status := '1' - else if Pos('completed', status) > 0 then status := '0' - else status := ''; + genres := ''; + AddCommaString(genres, getwpmangavalue('Category')); + AddCommaString(genres, getwpmangavalue('Genres')); + status := MangaInfoStatusIfPos(getwpmangavalue('Status'), 'Ongoing', 'Completed'); + summary := getwpmangavalue('Summary'); + if summary = '' then + begin + summary := XPathString('//*[contains(@class,"mng_det")]//p'); + if (summary <> '') and (Pos('name:', LowerCase(summary)) <> 0) then + summary := ''; end; scanchapters; end; @@ -174,6 +171,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin website := Module.Website; url := AppendURLDelim(FillHost(Module.RootURL, AURL)); + if Module.Website = 'Manga-Joy' then + AllowServerErrorResponse := True; if GET(MangaInfo.mangaInfo.url) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; @@ -214,7 +213,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String const Module: TModuleContainer): Boolean; var s: String; - v: IXQValue; + v, x: IXQValue; + allnum: Boolean; begin Result := False; if DownloadThread = nil then Exit; @@ -249,6 +249,24 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String PageNumber := XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; if PageNumber = 0 then PageNumber := XPath('(//select[@name="page"])[1]/option').Count; + if PageNumber = 0 then + for v in XPath('//select') do + begin + allnum := True; + for x in XPath('option', v.toNode) do + begin + if StrToIntDef(x.toString, -1) = -1 then + begin + allnum := False; + Break; + end; + end; + if allnum then + begin + PageNumber := XPath('option', v.toNode).Count; + Break; + end; + end; finally Free; end; @@ -272,7 +290,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if Module.Website = 'ReadHentaiManga' then s := HTMLDecode(XPathString('//img[@id="main_img"]/@src')) else - s := XPathString('//*[@class="wpm_pag mng_rdr"]//img/@src'); + s := XPathString('//*[contains(@class,"mng_rdr")]//img/@src'); if s = '' then s := XPathString('//*[@id="reader"]//img[@id="picture"]/@src'); PageLinks[DownloadThread.WorkId] := s; @@ -308,6 +326,7 @@ procedure RegisterModule; AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); AddWebsiteModule('MangaBug', 'http://www.mangabug.com'); + AddWebsiteModule('MangaJoy', 'http://manga-joy.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 3c8451fa1..44bb23d30 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaJoy,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 26f0bac273e57eeffea042f4223c9bf1bceff3ac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 12:40:16 +0800 Subject: [PATCH 1265/2794] replace mangabug with mangaice --- baseunits/modules/WPManga.pas | 2 +- config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 27075614a..1a06beae2 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -325,7 +325,7 @@ procedure RegisterModule; AddWebsiteModule('MangaIndo', 'http://mangaindo.id'); AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); - AddWebsiteModule('MangaBug', 'http://www.mangabug.com'); + AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); AddWebsiteModule('MangaJoy', 'http://manga-joy.com'); end; diff --git a/config/mangalist.ini b/config/mangalist.ini index 44bb23d30..b6bb762de 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaBug,MangaFox,MangaGo,MangaHen,MangaHere,MangaInn,MangaJoy,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaJoy,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 64ab6e1f25d204d8da73357c166c7a602b0a54a6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 12:56:13 +0800 Subject: [PATCH 1266/2794] Bump version 0.9.67.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8ce74ace1..a0af8f676 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.67.0 (18-06-2016) +[*] MangaPark: rewrite all code +[*] MangaBug: replaced with MangaIce +[+] Added MangaJoy[EN] +[*] Various changes and bug fix +Full changes: https://github.com/riderkick/FMD/compare/0.9.66.0...0.9.67.0 + 0.9.66.0 (18-06-2016) [*] KissManga: fixed manga info [+] Added LeoManga[ES] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index cab57f774..d20f0e1d4 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="66"/> + <RevisionNr Value="67"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5ba097b41..fdc793419 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.66.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.66.0/fmd_0.9.66.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.66.0/fmd_0.9.66.0_Win64.7z +VERSION=0.9.67.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.67.0/fmd_0.9.67.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.67.0/fmd_0.9.67.0_Win64.7z From f34edf722ca61e62da87b7aea7b7d579c78e4af1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 20:19:44 +0800 Subject: [PATCH 1267/2794] fixed set wndproc fixed #303 --- mangadownloader/forms/frmMain.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2d1dadf19..2e4fdd1d7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -839,7 +839,7 @@ implementation UpdateStatusTextStyle: TTextStyle; {$ifdef windows} - PrevWndProc: WNDPROC; + PrevWndProc: windows.WNDPROC; function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam): LRESULT; stdcall; begin @@ -1024,8 +1024,8 @@ procedure TMainForm.FormCreate(Sender: TObject); begin Randomize; {$ifdef windows} - PrevWndProc := windows.WNDPROC(GetWindowLong(Self.Handle, GWL_WNDPROC)); - windows.SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)); + PrevWndProc := windows.WNDPROC(windows.GetWindowLongPtr(Self.Handle, GWL_WNDPROC)); + windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)); {$endif} SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), FormatDateTime('dd-mm-yyyy', Now)])); @@ -1197,7 +1197,7 @@ procedure TMainForm.CloseNow; begin {$ifdef windows} if Assigned(PrevWndProc) then - windows.SetWindowLong(Self.Handle, GWL_WNDPROC, PtrInt(PrevWndProc)); + windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(PrevWndProc)); {$endif} Writelog_D(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); FavoriteManager.StopChekForNewChapter(True); From 53de2b3818272d5bab29c945c2ebf6372484af45 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Jun 2016 20:24:49 +0800 Subject: [PATCH 1268/2794] Bump version 0.9.68.0 --- changelog.txt | 6 +++++- mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index a0af8f676..d98c7f7f2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.67.0 (18-06-2016) +0.9.68.0 (20-06-2016) +[*] Fixed error at start +Full changes: https://github.com/riderkick/FMD/compare/0.9.67.0...0.9.68.0 + +0.9.67.0 (20-06-2016) [*] MangaPark: rewrite all code [*] MangaBug: replaced with MangaIce [+] Added MangaJoy[EN] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index d20f0e1d4..e40c2d372 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="67"/> + <RevisionNr Value="68"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index fdc793419..7c632a791 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.67.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.67.0/fmd_0.9.67.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.67.0/fmd_0.9.67.0_Win64.7z +VERSION=0.9.68.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.68.0/fmd_0.9.68.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.68.0/fmd_0.9.68.0_Win64.7z From 89db5a96a5bbb715738ae2a4f398afd4198fa3d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 02:03:28 +0800 Subject: [PATCH 1269/2794] mangajoy, fixed update list #304 --- baseunits/modules/WPManga.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 1a06beae2..c392652a5 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -81,6 +81,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end + else if (Module.Website = 'MangaJoy') then + for v in XPath('//*[@id="sct_manga_list"]//*[@class="det"]/h2/a[1]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end else for v in XPath('//*[@id="sct_content"]//div[@class="det"]/a[1]') do begin ALinks.Add(v.toNode.getAttribute('href')); From d0ee388165772dea3527055db3b5aadf3afcd3b3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 02:11:18 +0800 Subject: [PATCH 1270/2794] wpmanga, check for wrong summary --- baseunits/modules/WPManga.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index c392652a5..c93917251 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -145,7 +145,9 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; if summary = '' then begin summary := XPathString('//*[contains(@class,"mng_det")]//p'); - if (summary <> '') and (Pos('name:', LowerCase(summary)) <> 0) then + if (summary <> '') and + ((Pos('name:', LowerCase(summary)) <> 0) or + (Pos('alternative name', LowerCase(summary)) = 1)) then summary := ''; end; scanchapters; From 86aa5639022ada47455d076e7e88b8faeb9ae01b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 03:29:02 +0800 Subject: [PATCH 1271/2794] added es-scanlation dangoonlinenofansub,dejameprobar,hoshinofansub,mangaworksfansub,masterpiecescans,menudofansub,neoprojectscan,pzykosis666hfansub,r15teamscanlation,santosscan,seinagifansub,seinagiadultofansub,solitarionofansub closed #307 --- baseunits/modules/FoOlSlide.pas | 64 +++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 6bfa45362..ae6513cfe 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -16,8 +16,10 @@ implementation const dirurl = '/directory/'; - yomangadirurl = '/reader/directory/'; - onetimescansdirurl = '/foolslide/directory/'; + dirurlreader = '/reader/directory/'; + dirurlfoolslide = '/foolslide/directory/'; + dirurlslide = '/slide/directory/'; + dirurlonline = '/online/directory/'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; @@ -28,6 +30,29 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; Result := AHTTP.GET(AURL); end; +function GetDirUrl(const AWebsite: String): String; +begin + if (AWebsite = 'YoManga') or + (AWebsite = 'GoManga') then + Result := dirurlreader + else + if AWebsite = 'OneTimeScans' then + Result := dirurlfoolslide + else + if (AWebsite = 'DejameProbar') or + (AWebsite = 'MenudoFansub') or + (AWebsite = 'NeoProjectScan') or + (AWebsite = 'SantosScan') or + (AWebsite = 'SolitarioNoFansub') then + Result := dirurlslide + else + if (AWebsite = 'Pzykosis666HFansub') or + (AWebsite = 'SeinagiFansub') then + Result := dirurlonline + else + Result := dirurl; +end; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var @@ -36,14 +61,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if (Module.Website = 'YoManga') or - (Module.Website = 'GoManga') then - s := yomangadirurl - else if Module.Website = 'OneTimeScans' then - s := onetimescansdirurl - else - s := dirurl; - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + s, Module) then + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + GetDirUrl(Module.Website), Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -68,14 +86,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if (Module.Website = 'YoManga') or - (Module.Website = 'GoManga') then - s := yomangadirurl - else if Module.Website = 'OneTimeScans' then - s := onetimescansdirurl - else - s := dirurl; - s := Module.RootURL + s; + s := Module.RootURL + GetDirUrl(Module.Website); if AURL <> '0' then s += IncStr(AURL) + '/'; if GETWithCookie(MangaInfo.FHTTP, s, Module) then begin @@ -226,7 +237,22 @@ procedure RegisterModule; AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); AddWebsiteModule('GoManga', 'http://gomanga.co'); AddWebsiteModule('OneTimeScans', 'http://otscans.com'); - AddWebsiteModule('SenseScans', 'http://reader.sensescans.com/'); + AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); + + //es-san + AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); + AddWebsiteModule('DejameProbar', 'http://dejameprobar.es'); + AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com'); + AddWebsiteModule('MangaWorksFansub', 'http://lector.mangaworksfansub.net'); + AddWebsiteModule('MasterPieceScans', 'http://reader.manga2me.net'); + AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com'); + AddWebsiteModule('NeoProjectScan', 'http://npscan.scans-es.com'); + AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com'); + AddWebsiteModule('R15TeamScanlation', 'http://www.r15team.com'); + AddWebsiteModule('SantosScan', 'http://santosfansub.com'); + AddWebsiteModule('SeinagiFansub', 'http://seinagi.org'); + AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org'); + AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net'); end; initialization From 34d895ed14c7c3d994730915adbd2315b5155ef7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 03:38:40 +0800 Subject: [PATCH 1272/2794] updatethread, cleanup --- baseunits/uUpdateThread.pas | 40 ++++++++++--------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index fc9ed94f2..57a0c7857 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -290,10 +290,8 @@ procedure TUpdateListManagerThread.MainThreadEndGetting; MainForm.sbUpdateList.Hide; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; MainForm.isUpdating:=False; - if MainForm.isPendingExitCounter then begin - Writelog_D(Self.ClassName+', pending exit counter executed'); + if MainForm.isPendingExitCounter then MainForm.DoExitWaitCounter; - end; end; procedure TUpdateListManagerThread.MainThreadRemoveFilter; @@ -551,7 +549,6 @@ procedure TUpdateListManagerThread.Execute; begin if websites.Count = 0 then Exit; - Writelog_D(Self.ClassName+', thread started'); try websitePtr := 0; if isDownloadFromServer then @@ -578,9 +575,6 @@ procedure TUpdateListManagerThread.Execute; Inc(websitePtr); cloghead:=Self.ClassName+', '+website+': '; - Writelog_D(cloghead+'update list started'); - Writelog_D(cloghead+'sortedlist='+BoolToStr(SortedList,True)+'; '+'nomangainfo='+BoolToStr(NoMangaInfo,True)); - Writelog_D(cloghead+'prepare database file'); FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; Synchronize(MainThreadShowGetting); @@ -604,7 +598,6 @@ procedure TUpdateListManagerThread.Execute; mainDataProcess.CreateDatabase(twebsite); tempDataProcess.CreateDatabase(twebsitetemp); - Writelog_D(cloghead+'get number of directory page'); // get directory page count directoryCount := 0; directoryCount2 := 0; @@ -616,7 +609,6 @@ procedure TUpdateListManagerThread.Execute; FIsPreListAvailable:=mainDataProcess.RecordCount>0; mainDataProcess.CloseTable; - Writelog_D(cloghead+'get names and links'); // get names and links workPtr := 0; isFinishSearchingForNewManga := False; @@ -657,7 +649,6 @@ procedure TUpdateListManagerThread.Execute; // get manga info if tempDataProcess.RecordCount>0 then begin - Writelog_D(cloghead+'get info '+IntToStr(tempDataProcess.RecordCount)); workPtr := 0; FCommitCount := 0; if NoMangaInfo or @@ -683,28 +674,22 @@ procedure TUpdateListManagerThread.Execute; else GetInfo(tempDataProcess.RecordCount, CS_INFO); mainDataProcess.Commit; - Writelog_D(cloghead+'get info finished '+IntToStr(workPtr)); - if workPtr > 0 then - if not (Terminated and SortedList) then - begin - Writelog_D(cloghead+'saving data '+IntToStr(workPtr)); - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; - Synchronize(MainThreadShowGetting); - mainDataProcess.Sort; - mainDataProcess.Close; - Synchronize(RefreshList); - end - else - Writelog_D(cloghead+'sorted list, data abandoned'); + if (workPtr > 0) and (not (Terminated and SortedList)) then + begin + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; + Synchronize(MainThreadShowGetting); + mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); + end; end; except on E: Exception do WriteLog_E(cloghead+'error occured!', E, Self); end; - Writelog_D(cloghead+'close database file'); tempDataProcess.Close; mainDataProcess.Close; DeleteDBDataProcess(twebsite); @@ -712,9 +697,7 @@ procedure TUpdateListManagerThread.Execute; if Terminated then Break; - websites[websitePtr - 1] := - UTF8Encode(#$2714 + WideString(websites[websitePtr - 1])); - Writelog_D(cloghead+'update list finished'); + websites[websitePtr - 1] := UTF8Encode(#$2714) + websites[websitePtr - 1]; FThreadAborted:=False; end; except @@ -723,7 +706,6 @@ procedure TUpdateListManagerThread.Execute; end; FThreadEndNormally:=True; Synchronize(MainThreadEndGetting); - Writelog_D(Self.ClassName+', thread ended'); end; end. From 5d1026ff9532fa69fe3118d5740be5bff169c616 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 03:53:12 +0800 Subject: [PATCH 1273/2794] foolslide, fixed get directory page number --- baseunits/modules/FoOlSlide.pas | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index ae6513cfe..83d9ad1d7 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -56,7 +56,9 @@ function GetDirUrl(const AWebsite: String): String; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var + v: IXQValue; s: String; + p: Integer; begin Result := NET_PROBLEM; Page := 1; @@ -66,11 +68,23 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - s := XPathString('//div[@class="next"]/a[contains(text(),"Last")]/@href'); - if s <> '' then begin - s := ReplaceRegExpr('.*/(\d+)/$', s, '$1', True); - Page := StrToIntDef(s, 1); - end; + with TRegExpr.Create do + try + Expression := '/(\d+)/$'; + for v in XPath('//*[@class="next"]/a/@href') do + begin + s := v.toString; + Exec(s); + if SubExprMatchCount > 0 then + begin + p := StrToIntDef(Match[1], -1); + if p > Page then + Page := p; + end; + end; + finally + Free; + end; finally Free; end; From 0d437f51667d45a221ff1993d34eca97b21cef5b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 04:01:37 +0800 Subject: [PATCH 1274/2794] code cleanup --- baseunits/modules/FoOlSlide.pas | 10 ++++------ baseunits/modules/WPManga.pas | 27 ++++++++++++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 83d9ad1d7..433ef421b 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -30,7 +30,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; Result := AHTTP.GET(AURL); end; -function GetDirUrl(const AWebsite: String): String; +function GetDirURL(const AWebsite: String): String; begin if (AWebsite = 'YoManga') or (AWebsite = 'GoManga') then @@ -57,13 +57,12 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; p: Integer; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + GetDirUrl(Module.Website), Module) then + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + GetDirURL(Module.Website), Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -73,8 +72,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Expression := '/(\d+)/$'; for v in XPath('//*[@class="next"]/a/@href') do begin - s := v.toString; - Exec(s); + Exec(v.toString); if SubExprMatchCount > 0 then begin p := StrToIntDef(Match[1], -1); @@ -100,7 +98,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + GetDirUrl(Module.Website); + s := Module.RootURL + GetDirURL(Module.Website); if AURL <> '0' then s += IncStr(AURL) + '/'; if GETWithCookie(MangaInfo.FHTTP, s, Module) then begin diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index c93917251..d9c2eaede 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -16,6 +16,20 @@ implementation dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; dirURLmangahen = '/manga_list/all/any/last-added/'; +function GetDirURL(const AWebsite: String): String; +begin + if AWebsite = 'MangaIndo' then + Result := dirURLmangaindo + else + if AWebsite = 'ReadHentaiManga' then + Result := dirURLreadhentaimanga + else + if AWebsite = 'MangaHen' then + Result := dirURLmangahen + else + Result := dirURL; +end; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; var @@ -25,13 +39,9 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; with MangaInfo.FHTTP do begin - if Module.Website = 'MangaIndo' then s := dirURLmangaindo - else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga - else if Module.Website = 'MangaHen' then s := dirURLmangahen - else s := dirURL; if Module.Website = 'Manga-Joy' then AllowServerErrorResponse := True; - if GET(Module.RootURL + s) then begin + if GET(Module.RootURL + GetDirURL(Module.Website)) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try @@ -49,18 +59,13 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; with MangaInfo.FHTTP do begin - if Module.Website = 'MangaIndo' then s := dirURLmangaindo - else if Module.Website = 'ReadHentaiManga' then s := dirURLreadhentaimanga - else if Module.Website = 'MangaHen' then s := dirURLmangahen - else s := dirURL; if Module.Website = 'Manga-Joy' then AllowServerErrorResponse := True; - if GET(Module.RootURL + s + IncStr(AURL) + '/') then begin + if GET(Module.RootURL + GetDirURL(Module.Website) + IncStr(AURL) + '/') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try From a86c8a52012f870deb1eae01a7dc350dc9f180bf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 04:06:47 +0800 Subject: [PATCH 1275/2794] foolslide, fixed dirurl --- baseunits/modules/FoOlSlide.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 433ef421b..ffa58f289 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -18,7 +18,7 @@ implementation dirurl = '/directory/'; dirurlreader = '/reader/directory/'; dirurlfoolslide = '/foolslide/directory/'; - dirurlslide = '/slide/directory/'; + dirurlslide = '/Slide/directory/'; dirurlonline = '/online/directory/'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; From 3ac50569cb521121bfe64fdbe857aba07a7fbf07 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 04:14:27 +0800 Subject: [PATCH 1276/2794] foolslide, fixed dirurl --- baseunits/modules/FoOlSlide.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index ffa58f289..2e8415405 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -18,7 +18,8 @@ implementation dirurl = '/directory/'; dirurlreader = '/reader/directory/'; dirurlfoolslide = '/foolslide/directory/'; - dirurlslide = '/Slide/directory/'; + dirurlslide = '/slide/directory/'; + dirurlslideU = '/Slide/directory/'; dirurlonline = '/online/directory/'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; @@ -42,10 +43,12 @@ function GetDirURL(const AWebsite: String): String; if (AWebsite = 'DejameProbar') or (AWebsite = 'MenudoFansub') or (AWebsite = 'NeoProjectScan') or - (AWebsite = 'SantosScan') or (AWebsite = 'SolitarioNoFansub') then Result := dirurlslide else + if AWebsite = 'SantosScan' then + Result := dirurlslideU + else if (AWebsite = 'Pzykosis666HFansub') or (AWebsite = 'SeinagiFansub') then Result := dirurlonline From 6603f46800fe665d3ab37d4fa5635eeb7a31f1a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 04:18:24 +0800 Subject: [PATCH 1277/2794] added es-scanlation to mangalist --- config/mangalist.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/config/mangalist.ini b/config/mangalist.ini index b6bb762de..e268d02f7 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,6 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,U Raw=MangaMint,RawSenManga,RawYoManga Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing From fea91ccd5d060aa1079f1b46d8bd9301d64e0265 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 04:29:02 +0800 Subject: [PATCH 1278/2794] Bump version 0.9.69.0 --- changelog.txt | 17 +++++++++++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index d98c7f7f2..7ed1f811d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,23 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.69.0 (22-06-2016) +[*] MangaJoy: fixed update list +[+] Added DangoOnlineNoFansub[ES-SC] +[+] Added DejameProbar[ES-SC] +[+] Added HoshinoFansub[ES-SC] +[+] Added MangaWorksFansub[ES-SC] +[+] Added MasterPieceScans[ES-SC] +[+] Added MenudoFansub[ES-SC] +[+] Added NeoProjectScan[ES-SC] +[+] Added Pzykosis666HFansub[ES-SC] +[+] Added R15TeamScanlation[ES-SC] +[+] Added SantosScan[ES-SC] +[+] Added SeinagiFansub[ES-SC] +[+] Added SeinagiAdultoFansub[ES-SC] +[+] Added SolitarioNoFansub[ES-SC] +Full changes: https://github.com/riderkick/FMD/compare/0.9.69.0...0.9.69.0 + 0.9.68.0 (20-06-2016) [*] Fixed error at start Full changes: https://github.com/riderkick/FMD/compare/0.9.67.0...0.9.68.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e40c2d372..b59d881b5 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="68"/> + <RevisionNr Value="69"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 7c632a791..11a407a7e 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.68.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.68.0/fmd_0.9.68.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.68.0/fmd_0.9.68.0_Win64.7z +VERSION=0.9.69.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.69.0/fmd_0.9.69.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.69.0/fmd_0.9.69.0_Win64.7z From 51fb054d80c7bdeecf2ebe04e94e859a8431e310 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Jun 2016 08:22:32 +0800 Subject: [PATCH 1279/2794] seinagiadultofansub, fixed mangainfo and download fixed #308 --- baseunits/modules/FoOlSlide.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 2e8415405..11ec80d42 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -27,6 +27,10 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; begin if Module.Website = 'YoManga' then Result := Cloudflare.GETCF(AHTTP, AURL, yomangacookies, yomangalockget) + else + if (Module.Website = 'SeinagiAdultoFansub') and + (Pos(dirurl, AURL) = 0)then + Result := AHTTP.POST(AURL, 'adult=true') else Result := AHTTP.GET(AURL); end; @@ -122,12 +126,14 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + netOK: Boolean; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL), Module) then + url := FillHost(Module.RootURL, AURL); + if GETWithCookie(MangaInfo.FHTTP, url, Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do From f5f73ef0450af3a7766be95f228fa09fd6fbe595 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Jun 2016 02:16:32 +0800 Subject: [PATCH 1280/2794] cf, allowservererrorresponse, fixed infinite loop when user set retrycount to -1/infinite, because the server actually reply with 503 fixed #305 --- baseunits/modules/Cloudflare.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 0b208d873..921bd9891 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -141,6 +141,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: Str Result := False; if AHTTP = nil then Exit; AHTTP.Cookies.Text := Cookie; + AHTTP.AllowServerErrorResponse := True; Result := AHTTP.GET(AURL); if (AHTTP.ResultCode > 500) and AntiBotActive(AHTTP) then begin if TryEnterCriticalsection(CS) > 0 then @@ -166,6 +167,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: Str Result := False; if AHTTP = nil then Exit; AHTTP.Cookies.Text := Cookie; + AHTTP.AllowServerErrorResponse := True; Result := AHTTP.GET(AURL); if (AHTTP.ResultCode > 500) and AntiBotActive(AHTTP) then begin Result := CFJS(AHTTP, AURL, Cookie); From 09795938e48367ed528feb2f0b4887ff96fe06ab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Jun 2016 02:50:18 +0800 Subject: [PATCH 1281/2794] Bump version 0.9.70.0 --- changelog.txt | 7 ++++++- mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7ed1f811d..9a1fcaa73 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.70.0 (29-06-2016) +[*] SeinagiAdultoFansub: fixed manga info and download +[*] Fixed an issue with CF +Full changes: https://github.com/riderkick/FMD/compare/0.9.69.0...0.9.70.0 + 0.9.69.0 (22-06-2016) [*] MangaJoy: fixed update list [+] Added DangoOnlineNoFansub[ES-SC] @@ -19,7 +24,7 @@ Changelog: [+] Added SeinagiFansub[ES-SC] [+] Added SeinagiAdultoFansub[ES-SC] [+] Added SolitarioNoFansub[ES-SC] -Full changes: https://github.com/riderkick/FMD/compare/0.9.69.0...0.9.69.0 +Full changes: https://github.com/riderkick/FMD/compare/0.9.68.0...0.9.69.0 0.9.68.0 (20-06-2016) [*] Fixed error at start diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b59d881b5..14511d8e7 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="69"/> + <RevisionNr Value="70"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 11a407a7e..c9ae27618 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.69.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.69.0/fmd_0.9.69.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.69.0/fmd_0.9.69.0_Win64.7z +VERSION=0.9.70.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.70.0/fmd_0.9.70.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.70.0/fmd_0.9.70.0_Win64.7z From b9fcedfcebf3243d519b97799b8b3e9a5d4e62a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Jun 2016 03:40:18 +0800 Subject: [PATCH 1282/2794] baseunit, added regexprgetmatch --- baseunits/uBaseUnit.pas | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9d5a65612..152bf5eba 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -712,6 +712,9 @@ function PadZero(const S: String; ATotalWidth: Integer = 3; procedure PadZeros(S: TStrings; ATotalWidth: Integer = 3; PadAll: Boolean = False; StripZeros: Boolean = False); +// RegExpr +function RegExprGetMatch(const ARegExpr, AInputStr : RegExprString; const AMatchIdx: Integer): String; + // maintain the order of strings by adding serialized number if necessary procedure SerializeAndMaintainNames(F: TStrings); @@ -2024,6 +2027,21 @@ procedure PadZeros(S: TStrings; ATotalWidth: Integer; PadAll: Boolean; StripZero end; end; +function RegExprGetMatch(const ARegExpr, AInputStr : RegExprString; + const AMatchIdx: Integer): String; +begin + Result := ''; + if AMatchIdx < 0 then Exit; + with TRegExpr.Create do + try + Expression := ARegExpr; + if Exec(AInputStr) then + Result := Match[AMatchIdx]; + finally + Free; + end; +end; + procedure SerializeAndMaintainNames(F: TStrings); var s, so: TStringList; From 7d693093371993778ecce21e404bfda32d840581 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Jun 2016 03:44:27 +0800 Subject: [PATCH 1283/2794] tumangaonline, fixed get mangaid --- baseunits/modules/Tumangaonline.pas | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 941aa9b8e..86f4db33a 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -16,8 +16,7 @@ implementation apiurlimagenes = apiurl + 'imagenes'; dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage='; perpage = '1000'; - mangaurl = '/#!/biblioteca/mangas/'; - mangaurlpart = '/biblioteca/mangas/'; + mangaurl = '/biblioteca/mangas/'; imgurl = 'http://img1.tumangaonline.com'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; @@ -74,19 +73,9 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := AURL; - mangaid := ''; - if Pos(mangaurlpart, url) <> 0 then - begin - if Pos(mangaurl, AURL) = -1 then - url := StringReplace(url, mangaurlpart, mangaurl, [rfIgnoreCase]); - mangaid := SeparateRight(url, mangaurl); - if Pos('/', mangaid) <> 0 then - mangaid := SeparateLeft(mangaid, '/'); - end; - if mangaid = '' then - Exit; - url := FillHost(Module.RootURL, url); + url := FillHost(Module.RootURL, AURL); + mangaid := RegExprGetMatch('/mangas/(\d+)/', url, 1); + if mangaid = '' then Exit; if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then begin Result := NO_ERROR; From 6aeeae608500f2d1dff4ea39e3a3f755e76e0713 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Jun 2016 12:14:09 +0800 Subject: [PATCH 1284/2794] xqueryenginehtml, added overload with contextitem, cleanup and fixed --- baseunits/XQueryEngineHTML.pas | 182 +++++++++++++++++++++----------- baseunits/modules/MangaEden.pas | 2 +- 2 files changed, 120 insertions(+), 64 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index d26e79256..7e8ba74fb 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -16,29 +16,43 @@ TXQueryEngineHTML = class FEngine: TXQueryEngine; FTreeParser: TTreeParser; function Eval(const Expression: String; const isCSS: Boolean = False; - const Tree: TTreeNode = nil): IXQValue; + const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): IXQValue; + function EvalStringAll(const Expression: String; const isCSS: Boolean; + const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; + function EvalStringAll(const Expression: String; const isCSS: Boolean; + const Exc: array of String; const Separator: String = ', '; + const ContextItem: IXQValue = nil): String; overload; + procedure EvalStringAll(const Expression: String; const isCSS: Boolean; + const TheStrings: TStrings; ContextItem: IXQValue = nil); overload; public constructor Create(const HTML: String = ''); overload; constructor Create(const HTMLStream: TStream); overload; destructor Destroy; override; procedure ParseHTML(const HTML: String); overload; procedure ParseHTML(const HTMLStream: TStream); overload; + // xpath function XPath(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; + function XPath(const Expression: String; const ContextItem: IXQValue): IXQValue; inline; function XPathString(const Expression: String; const Tree: TTreeNode = nil): String; inline; + function XPathString(const Expression: String; const ContextItem: IXQValue): String; inline; function XPathStringAll(const Expression: String; const Separator: String = ', '; - const Tree: TTreeNode = nil): String; overload; + const ContextItem: IXQValue = nil): String; overload; inline; function XPathStringAll(const Expression: String; const Exc: array of String; - const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; + const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; inline; procedure XPathStringAll(const Expression: String; const TheStrings: TStrings; - const Tree: TTreeNode = nil); overload; + const ContextItem: IXQValue = nil); overload; inline; + // css function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; + function CSS(const Expression: String; const ContextItem: IXQValue): IXQValue; inline; function CSSString(const Expression: String; const Tree: TTreeNode = nil): String; inline; + function CSSString(const Expression: String; const ContextItem: IXQValue): String; inline; function CSSStringAll(const Expression: String; const Separator: String = ', '; - const Tree: TTreeNode = nil): String; overload; + const ContextItem: IXQValue = nil): String; overload; inline; function CSSStringAll(const Expression: String; const Exc: array of String; - const Separator: String = ', '; const Tree: TTreeNode = nil): String; overload; + const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; inline; procedure CSSStringAll(const Expression: String; const TheStrings: TStrings; - const Tree: TTreeNode = nil); overload; + const ContextItem: IXQValue = nil); overload; inline; + property Engine: TXQueryEngine read FEngine; property TreeParser: TTreeParser read FTreeParser; end; @@ -103,26 +117,66 @@ function XPathString(const Expression: String; const HTMLStream: TStream): Strin { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; - const Tree: TTreeNode): IXQValue; -var - t: TTreeNode; + const ContextItem: IXQValue; const Tree: TTreeNode): IXQValue; begin Result := xqvalue(); - if Assigned(Tree) then - t := Tree - else - t := FTreeParser.getLastTree; - if Expression = '' then - Exit; try - if isCSS then - Result := FEngine.evaluateCSS3(Expression, t) + if Assigned(ContextItem) then + begin + if isCSS then + Result := FEngine.evaluateCSS3(Expression, ContextItem) + else + Result := FEngine.evaluateXPath3(Expression, ContextItem); + end + else if Assigned(Tree) then + begin + if isCSS then + Result := FEngine.evaluateCSS3(Expression, Tree) + else + Result := FEngine.evaluateXPath3(Expression, Tree); + end else - Result := FEngine.evaluateXPath3(Expression, t); + begin + if isCSS then + Result := FEngine.evaluateCSS3(Expression, FTreeParser.getLastTree) + else + Result := FEngine.evaluateXPath3(Expression, FTreeParser.getLastTree); + end; except end; end; +function TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; + const Separator: String; const ContextItem: IXQValue): String; +var + v: IXQValue; +begin + Result := ''; + for v in Eval(Expression, isCSS, ContextItem) do + AddSeparatorString(Result, v.toString, Separator); +end; + +function TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; + const Exc: array of String; const Separator: String; const ContextItem: IXQValue + ): String; +var + v: IXQValue; +begin + Result := ''; + for v in Eval(Expression, isCSS, ContextItem) do + if StringInArray(Trim(v.toString), Exc) = False then + AddSeparatorString(Result, v.toString, Separator); +end; + +procedure TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; + const TheStrings: TStrings; ContextItem: IXQValue); +var + v: IXQValue; +begin + for v in Eval(Expression, isCSS, ContextItem) do + TheStrings.Add(v.toString); +end; + constructor TXQueryEngineHTML.Create(const HTML: String); begin FEngine := TXQueryEngine.Create; @@ -169,82 +223,84 @@ procedure TXQueryEngineHTML.ParseHTML(const HTMLStream: TStream); function TXQueryEngineHTML.XPath(const Expression: String; const Tree: TTreeNode): IXQValue; begin - Result := Eval(Expression, False, Tree); + Result := Eval(Expression, False, nil, Tree); +end; + +function TXQueryEngineHTML.XPath(const Expression: String; const ContextItem: IXQValue + ): IXQValue; +begin + Result := Eval(Expression, False, ContextItem); end; function TXQueryEngineHTML.XPathString(const Expression: String; const Tree: TTreeNode): String; begin - Result := Eval(Expression, False, Tree).toString; + Result := Eval(Expression, False, nil, Tree).toString; end; -function TXQueryEngineHTML.XPathStringAll(const Expression: String; const Separator: String; - const Tree: TTreeNode): String; -var - v: IXQValue; +function TXQueryEngineHTML.XPathString(const Expression: String; + const ContextItem: IXQValue): String; begin - Result := ''; - for v in Eval(Expression, False, Tree) do - AddSeparatorString(Result, v.toString, Separator); + Result := Eval(Expression, False, ContextItem).toString; end; -function TXQueryEngineHTML.XPathStringAll(const Expression: String; const Exc: array of String; - const Separator: String; const Tree: TTreeNode): String; -var - v: IXQValue; +function TXQueryEngineHTML.XPathStringAll(const Expression: String; + const Separator: String; const ContextItem: IXQValue): String; begin - Result := ''; - for v in Eval(Expression, False, Tree) do - if StringInArray(Trim(v.toString), Exc) = False then - AddSeparatorString(Result, v.toString, Separator); + Result := EvalStringAll(Expression, False, Separator, ContextItem); +end; + +function TXQueryEngineHTML.XPathStringAll(const Expression: String; + const Exc: array of String; const Separator: String; const ContextItem: IXQValue + ): String; +begin + Result := EvalStringAll(Expression, False, Exc, Separator, ContextItem); end; procedure TXQueryEngineHTML.XPathStringAll(const Expression: String; - const TheStrings: TStrings; const Tree: TTreeNode); -var - v: IXQValue; + const TheStrings: TStrings; const ContextItem: IXQValue); begin - for v in Eval(Expression, False, Tree) do - TheStrings.Add(v.toString); + EvalStringAll(Expression, False, TheStrings, ContextItem); end; function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin - Result := Eval(Expression, True, Tree); + Result := Eval(Expression, True, nil, Tree); +end; + +function TXQueryEngineHTML.CSS(const Expression: String; const ContextItem: IXQValue + ): IXQValue; +begin + Result := Eval(Expression, True, ContextItem); end; function TXQueryEngineHTML.CSSString(const Expression: String; const Tree: TTreeNode): String; begin - Result := Eval(Expression, True, Tree).toString; + Result := Eval(Expression, True, nil, Tree).toString; end; -function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Separator: String; - const Tree: TTreeNode): String; -var - v: IXQValue; +function TXQueryEngineHTML.CSSString(const Expression: String; + const ContextItem: IXQValue): String; begin - Result := ''; - for v in Eval(Expression, False, Tree) do - AddSeparatorString(Result, v.toString, Separator); + Result := Eval(Expression, True, ContextItem).toString; end; -function TXQueryEngineHTML.CSSStringAll(const Expression: String; const Exc: array of String; - const Separator: String; const Tree: TTreeNode): String; -var - v: IXQValue; +function TXQueryEngineHTML.CSSStringAll(const Expression: String; + const Separator: String; const ContextItem: IXQValue): String; begin - Result := ''; - for v in Eval(Expression, False, Tree) do - if StringInArray(Trim(v.toString), Exc) = False then - AddSeparatorString(Result, v.toString, Separator); + Result := EvalStringAll(Expression, True, Separator, ContextItem); +end; + +function TXQueryEngineHTML.CSSStringAll(const Expression: String; + const Exc: array of String; const Separator: String; const ContextItem: IXQValue + ): String; +begin + Result := EvalStringAll(Expression, True, Exc, Separator, ContextItem); end; procedure TXQueryEngineHTML.CSSStringAll(const Expression: String; - const TheStrings: TStrings; const Tree: TTreeNode); -var - v: IXQValue; + const TheStrings: TStrings; const ContextItem: IXQValue); begin - for v in Eval(Expression, True, Tree) do - TheStrings.Add(v.toString); + EvalStringAll(Expression, True, TheStrings, ContextItem); end; end. diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index 2f0de077e..aa5fd9db1 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -89,7 +89,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; for v in XPath('//table//tr/td/a[@class="chapterLink"]') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathStringAll('*', ' ', v.toNode)); + chapterName.Add(XPathStringAll('*', ' ', v)); end; InvertStrings([chapterLinks, chapterName]); finally From 44f62a3da0b65dbe5b33853ad25afb02b248617b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Jun 2016 12:20:26 +0800 Subject: [PATCH 1285/2794] tumangaonline, fixed get all chapter from various scanlation, fixed download fixed #310 --- baseunits/modules/Tumangaonline.pas | 35 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 86f4db33a..f3e528bfb 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, synacode, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation @@ -65,8 +65,9 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - v: IXQValue; - mangaid, purl, s, c: String; + v, x: IXQValue; + mangaid, purl: String; + s, cl, cn, vs: String; p, i: Integer; begin Result := NET_PROBLEM; @@ -106,22 +107,20 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; ParseHTML(Document) else Break; - for v in XPath( - 'json(*).data()/string-join((' + - '"?idManga=",idTomo,' + - '"&idScanlation=",subidas/idScan,' + - '"&numeroCapitulo=",numCapitulo,' + - '"&visto=true",' + - '"/",numCapitulo,"/",nombre),"")') do + for v in XPath('json(*).data()') do begin - s := v.toString; - chapterLinks.Add(apiurlimagenes + SeparateLeft(s, '/')); - s := SeparateRight(s, '/'); - c := SeparateRight(s, '/'); - s := SeparateLeft(s, '/'); - if (c <> '') and (c <> 'null') then - s := s + ' ' + c; - chapterName.Add(s); + cl := apiurlimagenes + XPathString('string-join(("?idManga=",idTomo,"&numeroCapitulo=",numCapitulo),"")', v); + vs := '&visto=' + XPathString('visto', v); + cn := Trim(XPathString('string-join((numCapitulo,nombre)," ")', v)); + if RightStr(cn, 5) = ' null' then + SetLength(cn, Length(cn) - 5); + for x in XPath('(subidas)()', v) do + begin + chapterLinks.Add(cl + '&idScanlation='+ XPathString('idScan', x) + vs); + s := XPathString('scanlation/nombre', x); + if s <> '' then chapterName.Add(cn + ' [' + s + ']') + else chapterName.Add(s); + end; end; end; InvertStrings([chapterLinks, chapterName]); From d69eaf78c90940732dec37d72934cbe84d29f4f3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Jun 2016 06:45:08 +0800 Subject: [PATCH 1286/2794] frmmain, fixed download list filter not updating after sort fixed #312 --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2e4fdd1d7..89405694e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3560,7 +3560,7 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); vtDownload.Header.SortColumn := Column; DLManager.Sort(Column); - vtDownload.Repaint; + UpdateVtDownload; end; procedure TMainForm.vtDownloadKeyAction(Sender: TBaseVirtualTree; From 9f43d6378fe419b73992983de73fc3e43c2d73e3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Jun 2016 06:55:59 +0800 Subject: [PATCH 1287/2794] frmmain, rename tvdownloadfilterrepaint to updatetvdownloadfilter, cleanup --- mangadownloader/forms/frmMain.pas | 65 ++++++++++++++++++------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 89405694e..b163c2cf6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -591,8 +591,8 @@ TMainForm = class(TForm) // check update CheckUpdateThread: TCheckUpdateThread; - // repaint treeview - procedure tvDownloadFilterRepaint; + // update download filter treeview + procedure UpdatetvDownloadFilter; // generate >> nodes procedure GeneratetvDownloadFilterNodes; @@ -1781,14 +1781,19 @@ procedure TMainForm.LoadAbout; if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); end; -procedure TMainForm.tvDownloadFilterRepaint; +procedure TMainForm.UpdatetvDownloadFilter; var - i: Cardinal; - LFinishedTasks: Cardinal = 0; - LInProgressTasks: Cardinal = 0; - LStoppedTasks: Cardinal = 0; - LFailedTask: Cardinal = 0; + i, + LFinishedTasks, + LInProgressTasks, + LStoppedTasks, + LFailedTask: Integer; begin + LFinishedTasks := 0; + LInProgressTasks := 0; + LStoppedTasks := 0; + LFailedTask := 0; + if (Assigned(DLManager)) and (DLManager.Count > 0) then for i := 0 to DLManager.Count - 1 do begin @@ -1803,24 +1808,28 @@ procedure TMainForm.tvDownloadFilterRepaint; end; end; - with tvDownloadFilter do begin - // root - Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); - - // childs - Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); - Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); - Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); - Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); - - // root - Items[5].Text := RS_History; - - // childs - Items[6].Text := RS_Today; - Items[7].Text := RS_Yesterday; - Items[8].Text := RS_OneWeek; - Items[9].Text := RS_OneMonth; + tvDownloadFilter.BeginUpdate; + with tvDownloadFilter do + try + // root + Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); + + // childs + Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); + Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); + Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); + Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); + + // root + Items[5].Text := RS_History; + + // childs + Items[6].Text := RS_Today; + Items[7].Text := RS_Yesterday; + Items[8].Text := RS_OneWeek; + Items[9].Text := RS_OneMonth; + finally + tvDownloadFilter.EndUpdate; end; end; @@ -3942,7 +3951,7 @@ procedure TMainForm.vtDownloadFilters; 8: ShowOneWeekTasks; 9: ShowOneMonthTasks; end; - tvDownloadFilterRepaint; + UpdatetvDownloadFilter; isRunDownloadFilter := False; end; @@ -4929,7 +4938,7 @@ procedure TMainForm.ApplyLanguage; rgDropTargetMode.ItemIndex := idxDropTargetMode; Self.Repaint; vtMangaList.Repaint; - tvDownloadFilterRepaint; + UpdatetvDownloadFilter; // refresh custom option WebsiteOptionCustomForm.CreateWebsiteOption; From cbbdaa5a12920b8615cc0ed505ef3a9de4c020f8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Jun 2016 07:59:24 +0800 Subject: [PATCH 1288/2794] frmain, cleanup and fix vtdownloadfilter --- mangadownloader/forms/frmMain.pas | 250 ++++++++++++------------------ 1 file changed, 100 insertions(+), 150 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b163c2cf6..aaad37255 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -606,14 +606,7 @@ TMainForm = class(TForm) procedure InitCheckboxes; // download task filters - procedure ShowTasks(Status: TDownloadStatusTypes = []); - - procedure ShowTasksOnCertainDays(const L, H: longint); - procedure ShowTodayTasks; - procedure ShowYesterdayTasks; - procedure ShowOneWeekTasks; - procedure ShowOneMonthTasks; - procedure vtDownloadFilters; + procedure vtDownloadUpdateFilters(const RepaintTree: Boolean = True); procedure AddChapterNameToList; @@ -648,7 +641,7 @@ TMainForm = class(TForm) function SaveMangaOptions: String; procedure UpdateVtChapter; - procedure UpdateVtDownload; + procedure UpdateVtDownload; inline; procedure UpdateVtFavorites; // Load form information, like previous position, size, ... @@ -1782,55 +1775,8 @@ procedure TMainForm.LoadAbout; end; procedure TMainForm.UpdatetvDownloadFilter; -var - i, - LFinishedTasks, - LInProgressTasks, - LStoppedTasks, - LFailedTask: Integer; begin - LFinishedTasks := 0; - LInProgressTasks := 0; - LStoppedTasks := 0; - LFailedTask := 0; - - if (Assigned(DLManager)) and (DLManager.Count > 0) then - for i := 0 to DLManager.Count - 1 do - begin - case DLManager.Items[i].Status of - STATUS_FINISH : Inc(LFinishedTasks); - STATUS_DOWNLOAD, - STATUS_PREPARE, - STATUS_WAIT : Inc(LInProgressTasks); - STATUS_STOP : Inc(LStoppedTasks); - STATUS_PROBLEM, - STATUS_FAILED : Inc(LFailedTask); - end; - end; - - tvDownloadFilter.BeginUpdate; - with tvDownloadFilter do - try - // root - Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); - - // childs - Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); - Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); - Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); - Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); - - // root - Items[5].Text := RS_History; - // childs - Items[6].Text := RS_Today; - Items[7].Text := RS_Yesterday; - Items[8].Text := RS_OneWeek; - Items[9].Text := RS_OneMonth; - finally - tvDownloadFilter.EndUpdate; - end; end; procedure TMainForm.GeneratetvDownloadFilterNodes; @@ -3277,7 +3223,7 @@ procedure TMainForm.TrayIconDblClick(Sender: TObject); procedure TMainForm.tvDownloadFilterSelectionChanged(Sender: TObject); begin - vtDownloadFilters; + vtDownloadUpdateFilters(False); pcMain.ActivePage := tsDownload; configfile.WriteInteger('general', 'DownloadFilterSelect', tvDownloadFilter.Selected.AbsoluteIndex); @@ -3375,7 +3321,7 @@ procedure TMainForm.vtDownloadMoveItems(NextIndex: Cardinal; Mode: TDropMode); end; ConTemp.Free; vtDownload.EndUpdate; - vtDownloadFilters; + vtDownloadUpdateFilters; end; procedure TMainForm.vtDownloadDragDrop(Sender : TBaseVirtualTree; @@ -3851,108 +3797,117 @@ procedure TMainForm.InitCheckboxes; TCheckBox(pnGenres.Controls[i]).State := cbGrayed; end; -procedure TMainForm.ShowTasks(Status: TDownloadStatusTypes); +procedure TMainForm.vtDownloadUpdateFilters(const RepaintTree: Boolean); var - i: Cardinal; - xNode: PVirtualNode; - canExit: Boolean = False; -begin - if vtDownload.RootNodeCount = 0 then - Exit; - xNode := vtDownload.GetLast; - for i := vtDownload.RootNodeCount - 1 downto 0 do + ACurrentJDN: LongInt; + LFinishedTasks, + LInProgressTasks, + LStoppedTasks, + LFailedTask: Integer; + + procedure CountDownloadFilter(const Idx: Integer); begin - if Status = [] then - vtDownload.isVisible[xNode] := True - else - vtDownload.IsVisible[xNode] := DLManager.Items[i].Status in Status; - if canExit then - Exit; - if xNode = vtDownload.GetFirst then - canExit := True; - xNode := vtDownload.GetPrevious(xNode); - if xNode = vtDownload.GetFirst then - canExit := True; + case DLManager.Items[Idx].Status of + STATUS_FINISH : Inc(LFinishedTasks); + STATUS_DOWNLOAD, + STATUS_PREPARE, + STATUS_WAIT : Inc(LInProgressTasks); + STATUS_STOP : Inc(LStoppedTasks); + STATUS_PROBLEM, + STATUS_FAILED : Inc(LFailedTask); + end; end; -end; -procedure TMainForm.ShowTasksOnCertainDays(const L, H: longint); -var - i: Cardinal; - jdn: longint; - xNode: PVirtualNode; - canExit: Boolean = False; - dt: TDateTime; - day, month, year: Word; -begin - if vtDownload.RootNodeCount = 0 then - Exit; - if vtDownload.RootNodeCount <> DLManager.Count then - vtDownload.RootNodeCount := DLManager.Count; - xNode := vtDownload.GetLast; - for i := DLManager.Count-1 downto 0 do + procedure ShowTasks(Status: TDownloadStatusTypes = []); + var + xNode: PVirtualNode; begin - if i < DLManager.Count then + xNode := vtDownload.GetFirst(); + while Assigned(xNode) do begin - dt := DLManager.Items[i].DownloadInfo.dateTime; - DecodeDate(dt, year, month, day); - jdn := DateToJDN(year, month, day); - - if (jdn >= L) and (jdn <= H) then - vtDownload.isVisible[xNode] := True + if Status = [] then + vtDownload.IsVisible[xNode] := True else - vtDownload.isVisible[xNode] := False; - - if canExit then - Exit; - if xNode = vtDownload.GetFirst then - canExit := True; - xNode := vtDownload.GetPrevious(xNode); - if xNode = vtDownload.GetFirst then - canExit := True; + vtDownload.IsVisible[xNode] := DLManager.Items[xNode^.Index].Status in Status; + if RepaintTree then + CountDownloadFilter(xNode^.Index); + xNode := vtDownload.GetNext(xNode); end; end; -end; -procedure TMainForm.ShowTodayTasks; -begin - ShowTasksOnCertainDays(GetCurrentJDN, GetCurrentJDN); -end; + procedure ShowTasksOnCertainDays(const L, H: LongInt); + var + jdn: LongInt; + xNode: PVirtualNode; + begin + xNode := vtDownload.GetFirst(); + while Assigned(xNode) do + begin + jdn := DateToJDN(DLManager.Items[xNode^.Index].DownloadInfo.DateTime); + vtDownload.IsVisible[xNode] := (jdn >= L) and (jdn <= H); + if RepaintTree then + CountDownloadFilter(xNode^.Index); + xNode := vtDownload.GetNext(xNode); + end; + end; -procedure TMainForm.ShowYesterdayTasks; begin - ShowTasksOnCertainDays(GetCurrentJDN - 1, GetCurrentJDN - 1); -end; + if tvDownloadFilter.Selected = nil then Exit; -procedure TMainForm.ShowOneWeekTasks; -begin - ShowTasksOnCertainDays(GetCurrentJDN - 7, GetCurrentJDN); -end; + LFinishedTasks := 0; + LInProgressTasks := 0; + LStoppedTasks := 0; + LFailedTask := 0; -procedure TMainForm.ShowOneMonthTasks; -begin - ShowTasksOnCertainDays(GetCurrentJDN - 30, GetCurrentJDN); -end; + vtDownload.BeginUpdate; + try + if vtDownload.RootNodeCount <> DLManager.Count then + vtDownload.RootNodeCount := DLManager.Count; + + // filter download list + if tvDownloadFilter.Selected.AbsoluteIndex > 5 then + ACurrentJDN := DateToJDN(Now); + case tvDownloadFilter.Selected.AbsoluteIndex of + 0, 5: ShowTasks; + 1: ShowTasks([STATUS_FINISH]); + 2: ShowTasks([STATUS_WAIT, STATUS_PREPARE, STATUS_DOWNLOAD, STATUS_COMPRESS]); + 3: ShowTasks([STATUS_STOP]); + 4: ShowTasks([STATUS_PROBLEM, STATUS_FAILED]); + 6: ShowTasksOnCertainDays(ACurrentJDN, ACurrentJDN); + 7: ShowTasksOnCertainDays(ACurrentJDN - 1, ACurrentJDN - 1); + 8: ShowTasksOnCertainDays(ACurrentJDN - 7, ACurrentJDN); + 9: ShowTasksOnCertainDays(ACurrentJDN - 30, ACurrentJDN); + end; + finally + vtDownload.EndUpdate; + end; -procedure TMainForm.vtDownloadFilters; -begin - if (isRunDownloadFilter) or - (not Assigned(tvDownloadFilter.Selected)) then - Exit; - isRunDownloadFilter := True; - case tvDownloadFilter.Selected.AbsoluteIndex of - 0, 5: ShowTasks; - 1: ShowTasks([STATUS_FINISH]); - 2: ShowTasks([STATUS_WAIT, STATUS_PREPARE, STATUS_DOWNLOAD, STATUS_COMPRESS]); - 3: ShowTasks([STATUS_STOP]); - 4: ShowTasks([STATUS_PROBLEM, STATUS_FAILED]); - 6: ShowTodayTasks; - 7: ShowYesterdayTasks; - 8: ShowOneWeekTasks; - 9: ShowOneMonthTasks; + if not RepaintTree then Exit; + + // update download filter treeview + tvDownloadFilter.BeginUpdate; + with tvDownloadFilter do + try + // root + Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); + + // childs + Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); + Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); + Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); + Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); + + // root + Items[5].Text := RS_History; + + // childs + Items[6].Text := RS_Today; + Items[7].Text := RS_Yesterday; + Items[8].Text := RS_OneWeek; + Items[9].Text := RS_OneMonth; + finally + tvDownloadFilter.EndUpdate; end; - UpdatetvDownloadFilter; - isRunDownloadFilter := False; end; procedure TMainForm.AddChapterNameToList; @@ -4773,12 +4728,7 @@ procedure TMainForm.UpdateVtChapter; procedure TMainForm.UpdateVtDownload; begin - if vtDownload.RootNodeCount <> DLManager.Count then - vtDownload.RootNodeCount := DLManager.Count; - // the reason we put vtDownloadFilters in here instead of in DLManager because - // the size of download list can change while this method is running - vtDownloadFilters; - vtDownload.Repaint; + vtDownloadUpdateFilters; end; procedure TMainForm.UpdateVtFavorites; From 6e034830e867a051bf323ff437b319598e4f44a9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Jun 2016 09:38:48 +0800 Subject: [PATCH 1289/2794] cleanup refresh download list filter and status, count download status when changed only, cleanup unnecessary procedure --- baseunits/uBaseUnit.pas | 4 -- baseunits/uDownloadsManager.pas | 57 +++++++++++++++- mangadownloader/forms/frmMain.pas | 107 ++++++++++++------------------ 3 files changed, 99 insertions(+), 69 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 152bf5eba..6dada0b9e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -522,10 +522,6 @@ interface TCheckStyleType = (CS_DIRECTORY_COUNT, CS_DIRECTORY_PAGE, CS_DIRECTORY_PAGE_2, CS_INFO); TFlagType = (CS_GETPAGENUMBER, CS_GETPAGELINK, CS_DOWNLOAD); - TDownloadStatusType = (STATUS_STOP, STATUS_WAIT, STATUS_PREPARE, - STATUS_DOWNLOAD, STATUS_FINISH, STATUS_COMPRESS, - STATUS_PROBLEM, STATUS_FAILED); - TDownloadStatusTypes = set of TDownloadStatusType; TFavoriteStatusType = (STATUS_IDLE, STATUS_CHECK, STATUS_CHECKING, STATUS_CHECKED); TFavoriteStatusTypes = set of TFavoriteStatusType; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d1f05d7ca..a9ef81a5f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -21,6 +21,19 @@ interface strutils; type + TDownloadStatusType = ( + STATUS_STOP, + STATUS_WAIT, + STATUS_PREPARE, + STATUS_DOWNLOAD, + STATUS_FINISH, + STATUS_COMPRESS, + STATUS_PROBLEM, + STATUS_FAILED, + STATUS_NONE // devault value oncreate, don't use + ); + TDownloadStatusTypes = set of TDownloadStatusType; + TDownloadManager = class; TTaskContainer = class; TTaskThread = class; @@ -93,6 +106,8 @@ TTaskThread = class(TFMDThread) TTaskContainer = class private FWebsite: String; + FStatus: TDownloadStatusType; + procedure SetStatus(AValue: TDownloadStatusType); procedure SetWebsite(AValue: String); public // critical section @@ -117,7 +132,7 @@ TTaskContainer = class PageNumber: Integer; MangaSiteID: Cardinal; ModuleId: Integer; - Status: TDownloadStatusType; + //Status: TDownloadStatusType; ThreadState: Boolean; ChapterName, ChapterLinks, @@ -133,6 +148,7 @@ TTaskContainer = class procedure IncReadCount(const ACount: Integer); public property Website: String read FWebsite write SetWebsite; + property Status: TDownloadStatusType read FStatus write SetStatus; end; TTaskContainers = TFPGList<TTaskContainer>; @@ -147,6 +163,7 @@ TDownloadManager = class protected function GetTaskCount: Integer; inline; function GetTransferRate: Integer; + procedure ChangeStatusCount(const OldStatus, NewStatus: TDownloadStatusType); public CS_Task: TRTLCriticalSection; Items, @@ -154,6 +171,10 @@ TDownloadManager = class isRunningBackup, isFinishTaskAccessed, isRunningBackupDownloadedChaptersList, isReadyForExit: Boolean; + // status count + CS_StatusCount: TRTLCriticalSection; + StatusCount: array [TDownloadStatusType] of Integer; + compress, retryConnect, // max. active tasks maxDLTasks, @@ -1413,6 +1434,14 @@ procedure TTaskContainer.SetWebsite(AValue: String); ModuleId := Modules.LocateModule(AValue); end; +procedure TTaskContainer.SetStatus(AValue: TDownloadStatusType); +begin + if FStatus = AValue then Exit; + if Assigned(Manager) then + Manager.ChangeStatusCount(FStatus, AValue); + FStatus := AValue; +end; + constructor TTaskContainer.Create; begin inherited Create; @@ -1430,6 +1459,7 @@ constructor TTaskContainer.Create; CurrentPageNumber := 0; CurrentDownloadChapterPtr := 0; CustomFileName := OptionFilenameCustomRename; + FStatus := STATUS_NONE; end; destructor TTaskContainer.Destroy; @@ -1487,7 +1517,22 @@ function TDownloadManager.GetTransferRate: Integer; end; end; +procedure TDownloadManager.ChangeStatusCount(const OldStatus, + NewStatus: TDownloadStatusType); +begin + EnterCriticalsection(CS_StatusCount); + try + if StatusCount[OldStatus] > 0 then + Dec(StatusCount[OldStatus]); + Inc(StatusCount[NewStatus]); + finally + LeaveCriticalsection(CS_StatusCount); + end; +end; + constructor TDownloadManager.Create; +var + ds: TDownloadStatusType; begin inherited Create; InitCriticalSection(CS_Task); @@ -1507,6 +1552,10 @@ constructor TDownloadManager.Create; isRunningBackup := False; isRunningBackupDownloadedChaptersList := False; isReadyForExit := False; + + InitCriticalSection(CS_StatusCount); + for ds := Low(StatusCount) to High(StatusCount) do + StatusCount[ds] := 0; end; destructor TDownloadManager.Destroy; @@ -1526,6 +1575,7 @@ destructor TDownloadManager.Destroy; ItemsActiveTask.Free; DownloadedChapters.Free; DoneCriticalsection(CS_Task); + DoneCriticalsection(CS_StatusCount); inherited Destroy; end; @@ -1706,7 +1756,10 @@ function TDownloadManager.AddTask: Integer; try Result := Items.Add(TTaskContainer.Create); with Items[Result] do + begin Manager := Self; + Status := STATUS_STOP; + end; finally LeaveCriticalSection(CS_Task); end; @@ -1794,7 +1847,7 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; CheckAndActiveTask else if MainForm.itRefreshDLInfo.Enabled = False then MainForm.itRefreshDLInfo.Enabled := True; - MainForm.vtDownloadFilters; + MainForm.UpdateVtDownload; end; procedure TDownloadManager.ActiveTask(const taskID: Integer); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index aaad37255..d56cf42d4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -591,9 +591,6 @@ TMainForm = class(TForm) // check update CheckUpdateThread: TCheckUpdateThread; - // update download filter treeview - procedure UpdatetvDownloadFilter; - // generate >> nodes procedure GeneratetvDownloadFilterNodes; @@ -606,7 +603,8 @@ TMainForm = class(TForm) procedure InitCheckboxes; // download task filters - procedure vtDownloadUpdateFilters(const RepaintTree: Boolean = True); + procedure tvDownloadFilterRefresh(const ResourceChanged: Boolean = False); + procedure vtDownloadUpdateFilters(const RefreshTree: Boolean = True); procedure AddChapterNameToList; @@ -1774,11 +1772,6 @@ procedure TMainForm.LoadAbout; if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); end; -procedure TMainForm.UpdatetvDownloadFilter; -begin - -end; - procedure TMainForm.GeneratetvDownloadFilterNodes; begin with tvDownloadFilter do begin @@ -3797,31 +3790,52 @@ procedure TMainForm.InitCheckboxes; TCheckBox(pnGenres.Controls[i]).State := cbGrayed; end; -procedure TMainForm.vtDownloadUpdateFilters(const RepaintTree: Boolean); -var - ACurrentJDN: LongInt; - LFinishedTasks, - LInProgressTasks, - LStoppedTasks, - LFailedTask: Integer; +procedure TMainForm.tvDownloadFilterRefresh(const ResourceChanged: Boolean); +begin + // update download filter treeview + tvDownloadFilter.BeginUpdate; + with DLManager, tvDownloadFilter do + try + // root + Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); - procedure CountDownloadFilter(const Idx: Integer); - begin - case DLManager.Items[Idx].Status of - STATUS_FINISH : Inc(LFinishedTasks); - STATUS_DOWNLOAD, - STATUS_PREPARE, - STATUS_WAIT : Inc(LInProgressTasks); - STATUS_STOP : Inc(LStoppedTasks); - STATUS_PROBLEM, - STATUS_FAILED : Inc(LFailedTask); + // childs + Items[1].Text := Format('%s (%d)', [RS_Finish, StatusCount[STATUS_FINISH]]); + Items[2].Text := Format('%s (%d)', [RS_InProgress, + StatusCount[STATUS_DOWNLOAD] + + StatusCount[STATUS_PREPARE] + + StatusCount[STATUS_WAIT]]); + Items[3].Text := Format('%s (%d)', [RS_Stopped, StatusCount[STATUS_STOP]]); + Items[4].Text := Format('%s (%d)', [RS_Failed, + StatusCount[STATUS_PROBLEM] + + StatusCount[STATUS_FAILED]]); + + if ResourceChanged then + begin + // root + Items[5].Text := RS_History; + + // childs + Items[6].Text := RS_Today; + Items[7].Text := RS_Yesterday; + Items[8].Text := RS_OneWeek; + Items[9].Text := RS_OneMonth; + end; + finally + tvDownloadFilter.EndUpdate; end; - end; +end; + +procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); +var + ACurrentJDN: LongInt; procedure ShowTasks(Status: TDownloadStatusTypes = []); var xNode: PVirtualNode; begin + if (Status = []) and (vtDownload.VisibleCount = vtDownload.RootNodeCount) then + Exit; xNode := vtDownload.GetFirst(); while Assigned(xNode) do begin @@ -3829,8 +3843,6 @@ procedure TMainForm.vtDownloadUpdateFilters(const RepaintTree: Boolean); vtDownload.IsVisible[xNode] := True else vtDownload.IsVisible[xNode] := DLManager.Items[xNode^.Index].Status in Status; - if RepaintTree then - CountDownloadFilter(xNode^.Index); xNode := vtDownload.GetNext(xNode); end; end; @@ -3845,8 +3857,6 @@ procedure TMainForm.vtDownloadUpdateFilters(const RepaintTree: Boolean); begin jdn := DateToJDN(DLManager.Items[xNode^.Index].DownloadInfo.DateTime); vtDownload.IsVisible[xNode] := (jdn >= L) and (jdn <= H); - if RepaintTree then - CountDownloadFilter(xNode^.Index); xNode := vtDownload.GetNext(xNode); end; end; @@ -3854,11 +3864,6 @@ procedure TMainForm.vtDownloadUpdateFilters(const RepaintTree: Boolean); begin if tvDownloadFilter.Selected = nil then Exit; - LFinishedTasks := 0; - LInProgressTasks := 0; - LStoppedTasks := 0; - LFailedTask := 0; - vtDownload.BeginUpdate; try if vtDownload.RootNodeCount <> DLManager.Count then @@ -3882,32 +3887,8 @@ procedure TMainForm.vtDownloadUpdateFilters(const RepaintTree: Boolean); vtDownload.EndUpdate; end; - if not RepaintTree then Exit; - - // update download filter treeview - tvDownloadFilter.BeginUpdate; - with tvDownloadFilter do - try - // root - Items[0].Text := Format('%s (%d)', [RS_AllDownloads, vtDownload.RootNodeCount]); - - // childs - Items[1].Text := Format('%s (%d)', [RS_Finish, LFinishedTasks]); - Items[2].Text := Format('%s (%d)', [RS_InProgress, LInProgressTasks]); - Items[3].Text := Format('%s (%d)', [RS_Stopped, LStoppedTasks]); - Items[4].Text := Format('%s (%d)', [RS_Failed, LFailedTask]); - - // root - Items[5].Text := RS_History; - - // childs - Items[6].Text := RS_Today; - Items[7].Text := RS_Yesterday; - Items[8].Text := RS_OneWeek; - Items[9].Text := RS_OneMonth; - finally - tvDownloadFilter.EndUpdate; - end; + if RefreshTree then + tvDownloadFilterRefresh; end; procedure TMainForm.AddChapterNameToList; @@ -4888,7 +4869,7 @@ procedure TMainForm.ApplyLanguage; rgDropTargetMode.ItemIndex := idxDropTargetMode; Self.Repaint; vtMangaList.Repaint; - UpdatetvDownloadFilter; + tvDownloadFilterRefresh(True); // refresh custom option WebsiteOptionCustomForm.CreateWebsiteOption; From 4eb8399551f29b23a419b3e56d1223795d0afa24 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Jun 2016 22:05:23 +0800 Subject: [PATCH 1290/2794] frmmain, fixed immediately show download list and favorites oncreate --- mangadownloader/forms/frmMain.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d56cf42d4..1304b90ee 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1080,10 +1080,10 @@ procedure TMainForm.FormCreate(Sender: TObject); if cbFilterStatus.Items.Count > 2 then cbFilterStatus.ItemIndex := 2; - vtDownload.NodeDataSize := SizeOf(TDownloadInfo) - 4; - vtDownload.RootNodeCount := DLManager.Count; + // show download list + UpdateVtDownload; - vtFavorites.NodeDataSize := SizeOf(TFavoriteInfo); + // show favorite list UpdateVtFavorites; InitCheckboxes; From 36d7a7a7486893b74da9250a4c46c7108c91e1ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jul 2016 01:34:28 +0800 Subject: [PATCH 1291/2794] Bump version 0.9.71.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9a1fcaa73..ff91e15ab 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.71.0 (01-07-2016) +[*] Tumangaonline: show all available chapter with scanlation name, fixed download +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.70.0...0.9.71.0 + 0.9.70.0 (29-06-2016) [*] SeinagiAdultoFansub: fixed manga info and download [*] Fixed an issue with CF diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 14511d8e7..9e0d6c9ea 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="70"/> + <RevisionNr Value="71"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index c9ae27618..84ac1d43e 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.70.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.70.0/fmd_0.9.70.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.70.0/fmd_0.9.70.0_Win64.7z +VERSION=0.9.71.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.71.0/fmd_0.9.71.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.71.0/fmd_0.9.71.0_Win64.7z From 873df3d55756116df149b4e97ab9439bf09de081 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 1 Jul 2016 13:40:17 +0800 Subject: [PATCH 1292/2794] changed list selection color --- mangadownloader/forms/frmAccountManager.lfm | 4 ++++ mangadownloader/forms/frmMain.lfm | 24 ++++++++++++++++--- .../forms/frmWebsiteOptionAdvanced.lfm | 20 ++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index e712425fc..4c21d42ad 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -229,6 +229,10 @@ object AccountManagerForm: TAccountManagerForm Top = 8 Width = 287 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow Header.AutoSizeIndex = 0 Header.Columns = < item diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 6b076a492..840829c07 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -58,6 +58,10 @@ object MainForm: TMainForm BorderSpacing.Left = 4 BorderSpacing.Right = 4 BorderSpacing.Bottom = 4 + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' DragOperations = [doMove] Header.AutoSizeIndex = 0 @@ -438,7 +442,10 @@ object MainForm: TMainForm Top = 0 Width = 516 Anchors = [akTop, akLeft, akRight, akBottom] - Colors.UnfocusedSelectionColor = clHighlight + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = <> @@ -1846,6 +1853,10 @@ object MainForm: TMainForm Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Around = 4 + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < @@ -3301,16 +3312,19 @@ object MainForm: TMainForm Top = 35 Width = 515 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 Header.Height = 23 Header.MainColumn = -1 - Margin = 0 + Margin = 1 ParentFont = False TabOrder = 0 - TextMargin = 0 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] @@ -3774,6 +3788,10 @@ object MainForm: TMainForm Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] BorderSpacing.Top = 8 + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' DragOperations = [] Header.AutoSizeIndex = 0 diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index d40638d44..e5e09abcf 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -30,6 +30,10 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Top = 6 Width = 490 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < @@ -75,6 +79,10 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Top = 6 Width = 490 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < @@ -137,6 +145,10 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Top = 6 Width = 470 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < @@ -201,6 +213,10 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Top = 6 Width = 470 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < @@ -246,6 +262,10 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm Top = 6 Width = 470 Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < From ca4fdc36c8d5909ad8355355f95709ad37048fad Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Jul 2016 06:18:15 +0800 Subject: [PATCH 1293/2794] downloadmanager, fixed decrease status count when task removed #313 --- baseunits/uDownloadsManager.pas | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a9ef81a5f..35aaec156 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -164,6 +164,8 @@ TDownloadManager = class function GetTaskCount: Integer; inline; function GetTransferRate: Integer; procedure ChangeStatusCount(const OldStatus, NewStatus: TDownloadStatusType); + procedure DecStatusCount(const Status: TDownloadStatusType); + procedure IncStatusCount(const Status: TDownloadStatusType); public CS_Task: TRTLCriticalSection; Items, @@ -1472,6 +1474,8 @@ destructor TTaskContainer.Destroy; FailedChapterName.Free; FailedChapterLinks.Free; DoneCriticalsection(CS_Container); + if Assigned(Manager) then + Manager.DecStatusCount(Status); inherited Destroy; end; @@ -1522,6 +1526,7 @@ procedure TDownloadManager.ChangeStatusCount(const OldStatus, begin EnterCriticalsection(CS_StatusCount); try + if OldStatus = NewStatus then Exit; if StatusCount[OldStatus] > 0 then Dec(StatusCount[OldStatus]); Inc(StatusCount[NewStatus]); @@ -1530,6 +1535,27 @@ procedure TDownloadManager.ChangeStatusCount(const OldStatus, end; end; +procedure TDownloadManager.DecStatusCount(const Status: TDownloadStatusType); +begin + EnterCriticalsection(CS_StatusCount); + try + if StatusCount[Status] > 0 then + Dec(StatusCount[Status]); + finally + LeaveCriticalsection(CS_StatusCount); + end; +end; + +procedure TDownloadManager.IncStatusCount(const Status: TDownloadStatusType); +begin + EnterCriticalsection(CS_StatusCount); + try + Inc(StatusCount[Status]); + finally + LeaveCriticalsection(CS_StatusCount); + end; +end; + constructor TDownloadManager.Create; var ds: TDownloadStatusType; From ab902d975f7a184c7bb12033d50227f161148374 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 2 Jul 2016 06:27:42 +0800 Subject: [PATCH 1294/2794] downloadmanager, fixed removeallcompletedtask doesn't change the status count and memory leaks fixed #313 --- baseunits/uDownloadsManager.pas | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 35aaec156..7325a4092 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1984,12 +1984,17 @@ procedure TDownloadManager.RemoveAllFinishedTasks; var i: Integer; begin - if Items.Count > 0 then begin - i := 0; - while i < Items.Count do + if Items.Count = 0 then Exit; + EnterCriticalsection(CS_Task); + try + for i := Items.Count - 1 downto 0 do if Items[i].Status = STATUS_FINISH then + begin + Items[i].Free; Items.Delete(i) - else Inc(i); + end; + finally + LeaveCriticalsection(CS_Task); end; end; From 7bcf281739d1ad593634dbf5c38416d0e77c88ba Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 3 Jul 2016 03:23:55 +0800 Subject: [PATCH 1295/2794] fixed cf fixed #314 --- baseunits/modules/Cloudflare.pas | 59 +++++++++++++++++--------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 921bd9891..6a1e8baa9 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -16,14 +16,20 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; overl implementation const - MIN_WAIT_TIME = 4000; + MIN_WAIT_TIME = 5000; MAX_RETRY = 3; function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; begin Result := False; if AHTTP = nil then Exit; - Result := Pos('URL=/cdn-cgi/', AHTTP.Headers.Values['Refresh']) > 0; + if AHTTP.ResultCode < 500 then Exit; + with TXQueryEngineHTML.Create(AHTTP.Document) do + try + Result := XPathString('//input[@name="jschl_vc"]/@value') <> ''; + finally + Free; + end; end; function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; @@ -103,34 +109,33 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B counter := 0; while counter < MAX_RETRY do begin Inc(counter); - if AntiBotActive(AHTTP) then begin - m := 'GET'; - u := ''; - h := AppendURLDelim(GetHostURL(AURL)); - st := MIN_WAIT_TIME; - if JSGetAnsweredURL(StreamToString(AHTTP.Document), h, m, u, st) then - if (m <> '') and (u <> '') then begin - AHTTP.Reset; - AHTTP.Headers.Values['Referer'] := ' ' + AURL; - if st < MIN_WAIT_TIME then st := MIN_WAIT_TIME; - sc := 0; - while sc < st do begin - if AHTTP.ThreadTerminated then - Exit; - Inc(sc, 500); - Sleep(500); - end; - AHTTP.FollowRedirection := False; - if AHTTP.HTTPRequest(m, FillHost(h, u)) then - Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; - AHTTP.FollowRedirection := True; - if Result then Cookie := AHTTP.GetCookies; + m := 'GET'; + u := ''; + h := AppendURLDelim(GetHostURL(AURL)); + st := MIN_WAIT_TIME; + if JSGetAnsweredURL(StreamToString(AHTTP.Document), h, m, u, st) then + if (m <> '') and (u <> '') then begin + AHTTP.Reset; + AHTTP.Headers.Values['Referer'] := ' ' + AURL; + if st < MIN_WAIT_TIME then st := MIN_WAIT_TIME; + sc := 0; + while sc < st do begin + if AHTTP.ThreadTerminated then + Exit; + Inc(sc, 500); + Sleep(500); end; - end; + AHTTP.FollowRedirection := False; + if AHTTP.HTTPRequest(m, FillHost(h, u)) then + Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; + AHTTP.FollowRedirection := True; + if Result then Cookie := AHTTP.GetCookies; + end; if Result then Exit else if counter < MAX_RETRY then begin AHTTP.Reset; Result := AHTTP.GET(AURL); + if not AntiBotActive(AHTTP) then Exit; end; end; end; @@ -143,7 +148,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: Str AHTTP.Cookies.Text := Cookie; AHTTP.AllowServerErrorResponse := True; Result := AHTTP.GET(AURL); - if (AHTTP.ResultCode > 500) and AntiBotActive(AHTTP) then begin + if AntiBotActive(AHTTP) then begin if TryEnterCriticalsection(CS) > 0 then try Result := CFJS(AHTTP, AURL, Cookie); @@ -169,7 +174,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: Str AHTTP.Cookies.Text := Cookie; AHTTP.AllowServerErrorResponse := True; Result := AHTTP.GET(AURL); - if (AHTTP.ResultCode > 500) and AntiBotActive(AHTTP) then begin + if AntiBotActive(AHTTP) then begin Result := CFJS(AHTTP, AURL, Cookie); Result := AHTTP.GET(AURL); end; From c4acb8c56e18288d1b0dda94cc36123d94100014 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 3 Jul 2016 23:27:22 +0800 Subject: [PATCH 1296/2794] added custom color options to misc closed #301 --- baseunits/FMDOptions.pas | 21 +- mangadownloader/forms/frmCustomColor.lfm | 173 +++++++ mangadownloader/forms/frmCustomColor.pas | 558 +++++++++++++++++++++++ mangadownloader/forms/frmMain.lfm | 5 +- mangadownloader/forms/frmMain.pas | 81 ++-- mangadownloader/forms/mainunit.lrs | 332 -------------- mangadownloader/languages/fmd.en.po | 20 + mangadownloader/languages/fmd.id_ID.po | 20 + mangadownloader/languages/fmd.po | 20 + mangadownloader/md.lpi | 9 +- 10 files changed, 865 insertions(+), 374 deletions(-) create mode 100644 mangadownloader/forms/frmCustomColor.lfm create mode 100644 mangadownloader/forms/frmCustomColor.pas delete mode 100644 mangadownloader/forms/mainunit.lrs diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 26eae8447..765c44aa0 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, IniFiles, fileinfo, LazFileUtils, LazUTF8, FileUtil, Forms; + Classes, SysUtils, IniFiles, fileinfo, LazFileUtils, LazUTF8, FileUtil, Forms, Graphics; type @@ -122,6 +122,25 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionRemoveMangaNameFromChapter: Boolean = False; + //custom color + //basiclist + CL_BSNormalText: TColor = clWindowText; + CL_BSFocusedSelectionText: TColor = clHighlightText; + CL_BSUnfocesedSelectionText: TColor = clWindowText; + + //mangalist color + CL_MNNewManga: TColor = $FDC594; + CL_MNCompletedManga: TColor = $B8FFB8; + + //favoritelist color + CL_FVBrokenFavorite: TColor = $8080FF; + CL_FVChecking: TColor = $80EBFE; + CL_FVNewChapterFound: TColor = $FDC594; + CL_FVCompletedManga: TColor = $B8FFB8; + + //chapterlist color + CL_CHDownloaded: TColor = $B8FFB8; + // set base directory procedure SetFMDdirectory(const ADir: String); procedure SetAppDataDirectory(const ADir: String); diff --git a/mangadownloader/forms/frmCustomColor.lfm b/mangadownloader/forms/frmCustomColor.lfm new file mode 100644 index 000000000..e6b0e6fa7 --- /dev/null +++ b/mangadownloader/forms/frmCustomColor.lfm @@ -0,0 +1,173 @@ +object CustomColorForm: TCustomColorForm + Left = 295 + Height = 352 + Top = 191 + Width = 535 + Caption = 'CustomColorForm' + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 352 + ClientWidth = 535 + OnCreate = FormCreate + LCLVersion = '1.7' + object CBColors: TColorBox + AnchorSideRight.Control = btColors + Left = 363 + Height = 22 + Top = 32 + Width = 136 + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames] + Anchors = [akTop, akRight] + ItemHeight = 16 + OnChange = CBColorsChange + TabOrder = 0 + end + object btColors: TColorButton + AnchorSideLeft.Control = CBColors + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = CBColors + AnchorSideBottom.Control = CBColors + AnchorSideBottom.Side = asrBottom + Left = 503 + Height = 22 + Top = 32 + Width = 24 + Anchors = [akTop, akRight, akBottom] + BorderWidth = 2 + ButtonColorSize = 16 + ButtonColor = clBlack + OnColorChanged = btColorsColorChanged + end + object pcCustomColorList: TPageControl + AnchorSideRight.Control = CBColors + Left = 0 + Height = 352 + Top = 0 + Width = 359 + ActivePage = tsBasicList + Align = alLeft + Anchors = [akTop, akLeft, akRight, akBottom] + TabIndex = 0 + TabOrder = 1 + object tsBasicList: TTabSheet + Caption = 'Basic list' + ClientHeight = 324 + ClientWidth = 351 + object VTBasicList: TVirtualStringTree + Left = 0 + Height = 324 + Top = 0 + Width = 351 + Align = alClient + Color = clWindow + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + TabOrder = 0 + TextMargin = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnDrawText = VTBasicListDrawText + OnFocusChanged = VTBasicListFocusChanged + OnGetText = VTBasicListGetText + OnPaintText = VTBasicListPaintText + end + end + object tsMangaList: TTabSheet + Caption = 'Manga list' + ClientHeight = 324 + ClientWidth = 351 + object VTMangaList: TVirtualStringTree + Left = 0 + Height = 324 + Top = 0 + Width = 351 + Align = alClient + Color = clWindow + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + TabOrder = 0 + TextMargin = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnDrawText = VTBasicListDrawText + OnFocusChanged = VTBasicListFocusChanged + OnGetText = VTBasicListGetText + OnPaintText = VTBasicListPaintText + end + end + object tsFavoriteList: TTabSheet + Caption = 'Favorite list' + ClientHeight = 324 + ClientWidth = 351 + object VTFavoriteList: TVirtualStringTree + Left = 0 + Height = 324 + Top = 0 + Width = 351 + Align = alClient + Color = clWindow + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + TabOrder = 0 + TextMargin = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnDrawText = VTBasicListDrawText + OnFocusChanged = VTBasicListFocusChanged + OnGetText = VTBasicListGetText + OnPaintText = VTBasicListPaintText + end + end + object tsChapterList: TTabSheet + Caption = 'Chapter list' + ClientHeight = 308 + ClientWidth = 343 + object VTChapterList: TVirtualStringTree + Left = 0 + Height = 308 + Top = 0 + Width = 343 + Align = alClient + Color = clWindow + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + TabOrder = 0 + TextMargin = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnDrawText = VTBasicListDrawText + OnFocusChanged = VTBasicListFocusChanged + OnGetText = VTBasicListGetText + OnPaintText = VTBasicListPaintText + end + end + end +end diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas new file mode 100644 index 000000000..9989974fc --- /dev/null +++ b/mangadownloader/forms/frmCustomColor.pas @@ -0,0 +1,558 @@ +unit frmCustomColor; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fgl, Forms, + Graphics, Dialogs, ColorBox, ComCtrls, VirtualTrees, FMDOptions, IniFiles; + +type + TColorItem = record + N: String; + C: TColor; + end; + + { TColorItems } + + TColorItems = class + private + FColors: array of TColorItem; + function GetC(Index: Integer): TColor; + function GetN(Index: Integer): String; + procedure SetC(Index: Integer; AValue: TColor); + procedure SetN(Index: Integer; AValue: String); + public + destructor Destroy; override; + public + function Count: Integer; + procedure Add(const AName: String; const AColor: TColor); + property N[Index: Integer]: String read GetN write SetN; + property C[Index: Integer]: TColor read GetC write SetC; default; + end; + + { TVirtualStringTree } + + TVirtualStringTree = class(VirtualTrees.TVirtualStringTree) + private + FCI: TColorItems; + procedure SetCI(AValue: TColorItems); + public + property CI: TColorItems read FCI write SetCI; + end; + + { TCustomColorForm } + + TCustomColorForm = class(TForm) + CBColors: TColorBox; + btColors: TColorButton; + pcCustomColorList: TPageControl; + tsChapterList: TTabSheet; + tsMangaList: TTabSheet; + tsFavoriteList: TTabSheet; + tsBasicList: TTabSheet; + VTBasicList: TVirtualStringTree; + VTChapterList: TVirtualStringTree; + VTMangaList: TVirtualStringTree; + VTFavoriteList: TVirtualStringTree; + procedure btColorsColorChanged(Sender: TObject); + procedure CBColorsChange(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure VTBasicListDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; const CellText: String; + const CellRect: TRect; var DefaultDraw: Boolean); + procedure VTBasicListFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); + procedure VTBasicListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure VTBasicListPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + private + { private declarations } + procedure DrawBoxColorText(const TargetCanvas: TCanvas; const BoxColor: TColor; + const CellText: String; CellRect: TRect); + procedure SetSelectedColor(const AColor: TColor); + public + { public declarations } + end; + + TVTList = specialize TFPGList<VirtualTrees.TVirtualStringTree>; + + { TVTApplyList } + + TVTApplyList = class + private + FVTList: TVTList; + procedure VTOnPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); + procedure ApplyOnPaintText(Index: Integer); + function GetItems(Index: Integer): VirtualTrees.TVirtualStringTree; + procedure SetItems(Index: Integer; AValue: VirtualTrees.TVirtualStringTree); + public + constructor Create; + destructor Destroy; override; + procedure Add(const AVT: VirtualTrees.TVirtualStringTree); + procedure Remove(const AVT: VirtualTrees.TVirtualStringTree); + function Count: Integer; + property Items[Index: Integer]: VirtualTrees.TVirtualStringTree read GetItems write SetItems; default; + end; + +procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); +procedure RemoveVT(const AVT: VirtualTrees.TVirtualStringTree); +procedure Apply; +procedure LoadFromIniFile(const IniFile: TIniFile); +procedure SaveToIniFile(const IniFile: TIniFile); + +var + CustomColorForm: TCustomColorForm; + +implementation + +const + TextStyleLeftCenter: TTextStyle = ( + Alignment: taLeftJustify; + Layout: tlCenter; + SingleLine: True; + Clipping: False; + ExpandTabs: True; + ShowPrefix: False; + Wordbreak: False; + Opaque: False; + SystemFont: False; + RightToLeft: False; + EndEllipsis: True); + +var + // color collection + BasicListColors, + MangaListColors, + FavoriteListColors, + ChapterListColor: TColorItems; + + // current selected color list + SelectedColorList: TVirtualStringTree; + + // vt list to apply + VTApplyList: TVTApplyList; + +procedure DoInit; +begin + BasicListColors := TColorItems.Create; + with BasicListColors do + begin + Add('BackgroundColor', clWindow); + Add('BorderColor', clBtnFace); + Add('DisabledColor', clBtnShadow); + Add('DropMarkColor', clHighlight); + Add('DropTargetColor', clHighLight); + Add('DropTargetBorderColor', clHotLight); + Add('FocusedSelectionColor', clHighLight); + Add('FocusedSelectionBorderColor', clHotLight); + Add('GridLineColor', clBtnFace); + Add('HeaderHotColor', clBtnShadow); + Add('HotColor', clWindowText); + Add('SelectionRectangleBlendColor', clHighlight); + Add('SelectionRectangleBorderColor', clHotLight); + Add('TreeLineColor', clBtnShadow); + Add('UnfocusedSelectionColor', clBtnFace); + Add('UnfocusedSelectionBorderColor', clBtnShadow); + Add('NormalTextColor', clWindowText); + Add('FocusedSelectionTextColor', clHighlightText); + Add('UnfocusedSelectionTextColor', clWindowText); + end; + + MangaListColors := TColorItems.Create; + with MangaListColors do + begin + Add('NewMangaColor', CL_MNNewManga); + Add('CompletedMangaColor', CL_MNCompletedManga); + end; + + FavoriteListColors := TColorItems.Create; + with FavoriteListColors do + begin + Add('BrokenFavoriteColor', CL_FVBrokenFavorite); + Add('CheckingColor', CL_FVChecking); + Add('NewChapterFoundColor', CL_FVNewChapterFound); + Add('CompletedSeriesColor', CL_FVCompletedManga); + end; + + ChapterListColor := TColorItems.Create; + with ChapterListColor do + begin + Add('DownloadedColor', CL_CHDownloaded); + end; + + SelectedColorList := nil; + VTApplyList := TVTApplyList.Create; +end; + +procedure DoFinal; +begin + BasicListColors.Free; + MangaListColors.Free; + FavoriteListColors.Free; + ChapterListColor.Free; + VTApplyList.Free; +end; + +procedure ApplyBasicColorToVT(const AVT: VirtualTrees.TVirtualStringTree); +begin + with AVT.Colors do + begin + AVT.Color := BasicListColors[0]; + BorderColor := BasicListColors[1]; + DisabledColor := BasicListColors[2]; + DropMarkColor := BasicListColors[3]; + DropTargetColor := BasicListColors[4]; + DropTargetBorderColor := BasicListColors[5]; + FocusedSelectionColor := BasicListColors[6]; + FocusedSelectionBorderColor := BasicListColors[7]; + GridLineColor := BasicListColors[8]; + HeaderHotColor := BasicListColors[9]; + HotColor := BasicListColors[10]; + SelectionRectangleBlendColor := BasicListColors[11]; + SelectionRectangleBorderColor := BasicListColors[12]; + TreeLineColor := BasicListColors[13]; + UnfocusedSelectionColor := BasicListColors[14]; + UnfocusedSelectionBorderColor := BasicListColors[15]; + AVT.Repaint; + end; +end; + +procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); +begin + VTApplyList.Add(AVT); +end; + +procedure RemoveVT(const AVT: VirtualTrees.TVirtualStringTree); +begin + VTApplyList.Remove(AVT); +end; + +procedure ApplyToFMDOptions; +begin + //basiclist + CL_BSNormalText := BasicListColors[16]; + CL_BSFocusedSelectionText := BasicListColors[17]; + CL_BSUnfocesedSelectionText := BasicListColors[18]; + + //mangalist + CL_MNNewManga := MangaListColors[0]; + CL_MNCompletedManga := MangaListColors[1]; + + //favoritelist + CL_FVBrokenFavorite := FavoriteListColors[0]; + CL_FVChecking := FavoriteListColors[1]; + CL_FVNewChapterFound := FavoriteListColors[2]; + CL_FVCompletedManga := FavoriteListColors[3]; + + //chapterlist + CL_CHDownloaded := ChapterListColor[0]; +end; + +procedure Apply; +var + i: Integer; +begin + ApplyToFMDOptions; + if VTApplyList.Count > 0 then + for i := 0 to VTApplyList.Count - 1 do + ApplyBasicColorToVT(VTApplyList[i]); +end; + +procedure LoadFromIniFile(const IniFile: TIniFile); +var + i: Integer; +begin + with IniFile do + begin + //basiclist + for i := 0 to BasicListColors.Count - 1 do + BasicListColors[i] := StringToColor(ReadString('BasicListColors', BasicListColors.N[i], ColorToString(BasicListColors[i]))); + + //mangalist + for i := 0 to MangaListColors.Count - 1 do + MangaListColors[i] := StringToColor(ReadString('MangaListColors', MangaListColors.N[i], ColorToString(MangaListColors[i]))); + + //favoritelist + for i := 0 to FavoriteListColors.Count - 1 do + FavoriteListColors[i] := StringToColor(ReadString('FavoriteListColors', FavoriteListColors.N[i], + ColorToString(FavoriteListColors[i]))); + + //chapterlist + for i := 0 to ChapterListColor.Count - 1 do + ChapterListColor[i] := StringToColor(ReadString('ChapterListColor', ChapterListColor.N[i], ColorToString(ChapterListColor[i]))); + + ApplyToFMDOptions; + end; +end; + +procedure SaveToIniFile(const IniFile: TIniFile); +var + i: Integer; +begin + with IniFile do + begin + //basiclist + for i := 0 to BasicListColors.Count - 1 do + WriteString('BasicListColors', BasicListColors.N[i], ColorToString(BasicListColors[i])); + + //mangalist + for i := 0 to MangaListColors.Count - 1 do + WriteString('MangaListColors', MangaListColors.N[i], ColorToString(MangaListColors[i])); + + //favoritelist + for i := 0 to FavoriteListColors.Count - 1 do + WriteString('FavoriteListColors', FavoriteListColors.N[i], ColorToString(FavoriteListColors[i])); + + //chapterlist + for i := 0 to ChapterListColor.Count - 1 do + WriteString('ChapterListColor', ChapterListColor.N[i], ColorToString(ChapterListColor[i])); + end; +end; + +{$R *.lfm} + +{ TVTApplyList } + +procedure TVTApplyList.VTOnPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + with TargetCanvas.Font do + begin + if Sender.Selected[Node] then + begin + if Sender.Focused then + Color := CL_BSFocusedSelectionText + else + Color := CL_BSUnfocesedSelectionText; + end + else + Color := CL_BSNormalText; + end; +end; + +procedure TVTApplyList.ApplyOnPaintText(Index: Integer); +begin + if not Assigned(FVTList[Index].OnPaintText) then + FVTList[Index].OnPaintText := @VTOnPaintText; +end; + +function TVTApplyList.GetItems(Index: Integer): VirtualTrees.TVirtualStringTree; +begin + Result := FVTList[Index]; +end; + +procedure TVTApplyList.SetItems(Index: Integer; AValue: VirtualTrees.TVirtualStringTree); +begin + if FVTList[Index] <> AValue then + FVTList[Index] := AValue; +end; + +constructor TVTApplyList.Create; +begin + FVTList := TVTList.Create; +end; + +destructor TVTApplyList.Destroy; +begin + FVTList.Free; + inherited Destroy; +end; + +procedure TVTApplyList.Add(const AVT: VirtualTrees.TVirtualStringTree); +begin + if FVTList.IndexOf(AVT) = -1 then + ApplyOnPaintText(FVTList.Add(AVT)); +end; + +procedure TVTApplyList.Remove(const AVT: VirtualTrees.TVirtualStringTree); +begin + +end; + +function TVTApplyList.Count: Integer; +begin + Result := FVTList.Count; +end; + +{ TVirtualStringTree } + +procedure TVirtualStringTree.SetCI(AValue: TColorItems); +begin + if FCI = AValue then Exit; + FCI := AValue; + RootNodeCount := FCI.Count; +end; + +{ TColorItems } + +function TColorItems.GetC(Index: Integer): TColor; +begin + Result := FColors[Index].C; +end; + +function TColorItems.GetN(Index: Integer): String; +begin + Result := FColors[Index].N; +end; + +procedure TColorItems.SetC(Index: Integer; AValue: TColor); +begin + if FColors[Index].C <> AValue then + FColors[Index].C := AValue; +end; + +procedure TColorItems.SetN(Index: Integer; AValue: String); +begin + if FColors[Index].N <> AValue then + FColors[Index].N := AValue; +end; + +destructor TColorItems.Destroy; +begin + SetLength(FColors, 0); + inherited Destroy; +end; + +function TColorItems.Count: Integer; +begin + Result := Length(FColors); +end; + +procedure TColorItems.Add(const AName: String; const AColor: TColor); +begin + SetLength(FColors, Length(FColors) + 1); + with FColors[High(FColors)] do + begin + N := AName; + C := AColor; + end; +end; + +{ TCustomColorForm } + +procedure TCustomColorForm.FormCreate(Sender: TObject); +begin + AddVT(VTBasicList); + AddVT(VTMangaList); + AddVT(VTFavoriteList); + AddVT(VTChapterList); + VTBasicList.CI := BasicListColors; + VTMangaList.CI := MangaListColors; + VTFavoriteList.CI := FavoriteListColors; + VTChapterList.CI := ChapterListColor; +end; + +procedure TCustomColorForm.CBColorsChange(Sender: TObject); +begin + btColors.ButtonColor := CBColors.Selected; + SetSelectedColor(CBColors.Selected); +end; + +procedure TCustomColorForm.btColorsColorChanged(Sender: TObject); +begin + CBColors.Selected := btColors.ButtonColor; + SetSelectedColor(btColors.ButtonColor); +end; + +procedure TCustomColorForm.VTBasicListDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; const CellText: String; + const CellRect: TRect; var DefaultDraw: Boolean); +begin + DefaultDraw := False; + DrawBoxColorText(TargetCanvas, TVirtualStringTree(Sender).CI[Node^.Index], + CellText, CellRect); +end; + +procedure TCustomColorForm.VTBasicListFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); +begin + if SelectedColorList <> TVirtualStringTree(Sender) then + SelectedColorList := TVirtualStringTree(Sender); + CBColors.Selected := TVirtualStringTree(Sender).CI[Node^.Index]; + btColors.ButtonColor := CBColors.Selected; +end; + +procedure TCustomColorForm.VTBasicListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +begin + CellText := TVirtualStringTree(Sender).CI.N[Node^.Index]; +end; + +procedure TCustomColorForm.VTBasicListPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + with TargetCanvas.Font do + begin + if Sender.Selected[Node] then + begin + if Sender.Focused then + Color := BasicListColors[17] + else + Color := BasicListColors[18]; + end + else + Color := BasicListColors[16]; + end; +end; + +procedure TCustomColorForm.DrawBoxColorText(const TargetCanvas: TCanvas; const BoxColor: TColor; + const CellText: String; CellRect: TRect); +var + ABoxRect: TRect; + ATextRect: TRect; +begin + with TargetCanvas do + begin + // box color rect + ABoxRect := CellRect; + ABoxRect.Inflate(-2, -2); + ABoxRect.Left := CellRect.Left; + ABoxRect.Width := ABoxRect.Height; + // text rect + ATextRect := CellRect; + ATextRect.Left := ABoxRect.Right + 4; + // box color + Brush.Style := bsSolid; + Pen.Color := clGray; + Brush.Color := BoxColor; + Rectangle(ABoxRect); + // extra border + Brush.Style := bsClear; + Pen.Color := clWhite; + ABoxRect.Inflate(-1, -1); + Rectangle(ABoxRect); + // text + TextRect(ATextRect, ATextRect.Left, 0, CellText, TextStyleLeftCenter); + end; +end; + +procedure TCustomColorForm.SetSelectedColor(const AColor: TColor); +begin + if (SelectedColorList = nil) or (SelectedColorList.FocusedNode = nil) then Exit; + if SelectedColorList.CI[SelectedColorList.FocusedNode^.Index] = AColor then Exit; + SelectedColorList.CI[SelectedColorList.FocusedNode^.Index] := AColor; + if SelectedColorList = VTBasicList then + begin + ApplyBasicColorToVT(VTBasicList); + ApplyBasicColorToVT(VTMangaList); + ApplyBasicColorToVT(VTFavoriteList); + ApplyBasicColorToVT(VTChapterList); + end + else + SelectedColorList.Repaint; +end; + +initialization + DoInit; + +finalization + DoFinal; + +end. diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 840829c07..55637287c 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -36,13 +36,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsDownload + ActivePage = tsFavorites Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 3 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -116,7 +116,6 @@ object MainForm: TMainForm TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnBeforeCellPaint = vtDownloadBeforeCellPaint OnColumnDblClick = vtDownloadColumnDblClick OnDragAllowed = vtDownloadDragAllowed OnDragOver = vtDownloadDragOver diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1304b90ee..98c0856ff 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,7 +22,7 @@ interface TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, - frmWebsiteOptionAdvanced, CheckUpdate, accountmanagerdb, DBDataProcess, + frmWebsiteOptionAdvanced, frmCustomColor, CheckUpdate, accountmanagerdb, DBDataProcess, mangafoxwatermarkremover, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, SimpleLogger; @@ -478,9 +478,6 @@ TMainForm = class(TForm) procedure tvDownloadFilterSelectionChanged(Sender: TObject); procedure UniqueInstanceFMDOtherInstance(Sender: TObject; ParamCount: Integer; Parameters: array of String); - procedure vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); procedure vtDownloadColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); procedure vtDownloadDragAllowed(Sender : TBaseVirtualTree; @@ -1157,6 +1154,26 @@ procedure TMainForm.FormCreate(Sender: TObject); Show; end; + CustomColorForm := TCustomColorForm.Create(Self); + with CustomColorForm do + begin + Parent := tsMisc; + BorderStyle := bsNone; + Align := alClient; + Show; + AddVT(Self.vtMangaList); + AddVT(Self.clbChapterList); + AddVT(Self.vtDownload); + AddVT(Self.vtFavorites); + AddVT(Self.vtOptionMangaSiteSelection); + AddVT(AccountManagerForm.vtAccountList); + AddVT(WebsiteOptionAdvancedForm.vtCookies); + AddVT(WebsiteOptionAdvancedForm.vtUserAgent); + AddVT(WebsiteOptionAdvancedForm.vtDownloadMaxThreadsPerTask); + AddVT(WebsiteOptionAdvancedForm.vtUpdateListDirectoryPageNumber); + AddVT(WebsiteOptionAdvancedForm.vtUpdateListNumberOfThreads); + end; + // load mangafox template mangafoxwatermarkremover.LoadTemplate(MANGAFOXTEMPLATE_FOLDER); @@ -2158,7 +2175,7 @@ procedure TMainForm.clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; if Node^.Index>=Length(ChapterList) then Exit; if ChapterList[Node^.Index].Downloaded then begin - TargetCanvas.Brush.Color:=CL_HLGreenMarks; + TargetCanvas.Brush.Color:=CL_CHDownloaded; TargetCanvas.FillRect(CellRect); end; end; @@ -3231,17 +3248,6 @@ procedure TMainForm.UniqueInstanceFMDOtherInstance(Sender: TObject; BringToFront; end; -procedure TMainForm.vtDownloadBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); -begin - if Column=TVirtualStringTree(Sender).Header.SortColumn then - begin - TargetCanvas.Brush.Color:=CL_BlueLight; - TargetCanvas.FillRect(CellRect); - end; -end; - procedure TMainForm.vtDownloadColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); begin @@ -3547,33 +3553,27 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure FillRectBC(const AColor: TColor); - begin - TargetCanvas.Brush.Color := AColor; - TargetCanvas.FillRect(CellRect); - end; - begin - if Column=TVirtualStringTree(Sender).Header.SortColumn then - FillRectBC(CL_BlueLight); - with TargetCanvas, FavoriteManager.Items[Node^.Index] do begin + Brush.Color := clNone; if Trim(FavoriteInfo.Link) = '' then - FillRectBC(CL_HLRedMarks) + Brush.Color := CL_FVBrokenFavorite else if Status = STATUS_CHECKING then - FillRectBC(CL_HLYellowMarks) + Brush.Color := CL_FVChecking else if (Status = STATUS_CHECKED) and Assigned(NewMangaInfo) then begin if NewMangaInfoChaptersPos.Count > 0 then - FillRectBC(CL_HLBlueMarks) + Brush.Color := CL_FVNewChapterFound else if NewMangaInfo.status = MangaInfo_StatusCompleted then - FillRectBC(CL_HLGreenMarks); + Brush.Color := CL_FVCompletedManga; end; + if Brush.Color <> clNone then + FillRect(CellRect); end; end; @@ -3719,12 +3719,18 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin if Node^.Index>=dataProcess.RecordCount then Exit; - if miHighlightNewManga.Checked then - if StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - OptionNewMangaTime) then - begin - TargetCanvas.Brush.Color := CL_HLBlueMarks; - TargetCanvas.FillRect(CellRect); - end; + with TargetCanvas do + begin + Brush.Color := clNone; + if dataProcess.Value[Node^.Index, DATA_PARAM_STATUS] = MangaInfo_StatusCompleted then + Brush.Color := CL_MNCompletedManga; + if miHighlightNewManga.Checked and + (StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - OptionNewMangaTime)) then + Brush.Color := CL_MNNewManga; + + if Brush.Color <> clNone then + FillRect(CellRect); + end; end; procedure TMainForm.vtMangaListGetCursor(Sender: TBaseVirtualTree; @@ -4210,7 +4216,7 @@ procedure TMainForm.LoadOptions; cbOptionShowDownloadMangalistDialog.Checked := ReadBool('dialogs', 'ShowDownloadMangalistDialog', True); // misc - + frmCustomColor.LoadFromIniFile(configfile); // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4333,7 +4339,7 @@ procedure TMainForm.SaveOptions; WriteBool('dialogs', 'ShowDownloadMangalistDialog', cbOptionShowDownloadMangalistDialog.Checked); // misc - + frmCustomColor.SaveToIniFile(configfile); finally UpdateFile; end; @@ -4463,6 +4469,7 @@ procedure TMainForm.ApplyOptions; itCheckFav.Enabled := OptionAutoCheckFavInterval; //misc + frmCustomColor.Apply; //languages ApplyLanguage; diff --git a/mangadownloader/forms/mainunit.lrs b/mangadownloader/forms/mainunit.lrs deleted file mode 100644 index caf37ef20..000000000 --- a/mangadownloader/forms/mainunit.lrs +++ /dev/null @@ -1,332 +0,0 @@ -{ This is an automatically generated lazarus resource file } - -LazarusResources.Add('TMainForm','FORMDATA',[ - 'TPF0'#9'TMainForm'#8'MainForm'#4'Left'#3#172#0#6'Height'#3#210#1#3'Top'#2'6' - +#5'Width'#3#238#2#5'Align'#7#8'alBottom'#7'Caption'#6#21'Free Manga Download' - +'er'#12'ClientHeight'#3#210#1#11'ClientWidth'#3#238#2#8'OnCreate'#7#10'FormC' - +'reate'#9'OnDestroy'#7#11'FormDestroy'#10'LCLVersion'#6#3'1.1'#0#6'TPanel'#10 - +'pnMainLeft'#23'AnchorSideRight.Control'#7#14'spMainSplitter'#4'Left'#2#0#6 - +'Height'#3#210#1#3'Top'#2#0#5'Width'#3#195#0#5'Align'#7#6'alLeft'#7'Anchors' - +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#12'ClientHeight'#3#210#1#11 - +'ClientWidth'#3#195#0#8'TabOrder'#2#0#0#9'TComboBox'#13'cbSelectManga'#4'Lef' - +'t'#2#8#6'Height'#2#21#3'Top'#2#8#5'Width'#3#144#0#7'Anchors'#11#5'akTop'#6 - +'akLeft'#7'akRight'#0#10'ItemHeight'#2#13#13'Items.Strings'#1#6#0#0#8'TabOrd' - +'er'#2#0#0#0#5'TEdit'#8'edSearch'#4'Left'#2#8#6'Height'#2#21#3'Top'#2'$'#5'W' - +'idth'#3#144#0#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#10'OnKeyPress'#7 - +#16'edSearchKeyPress'#8'TabOrder'#2#1#4'Text'#6#9'Search...'#0#0#18'TVirtual' - +'StringTree'#11'vtMangaList'#4'Left'#2#8#6'Height'#3'q'#1#3'Top'#2'X'#5'Widt' - +'h'#3#176#0#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#11'Def' - +'aultText'#6#4'Node'#20'Header.AutoSizeIndex'#2#0#14'Header.Columns'#14#0#20 - +'Header.DefaultHeight'#2#17#17'Header.MainColumn'#2#255#14'ParentShowHint'#8 - +#8'ShowHint'#9#8'TabOrder'#2#2#24'TreeOptions.PaintOptions'#11#13'toShowButt' - +'ons'#14'toShowDropmark'#10'toShowRoot'#12'toThemeAware'#18'toUseBlendedImag' - +'es'#0#28'TreeOptions.SelectionOptions'#11#15'toFullRowSelect'#0#10'OnDblCli' - +'ck'#7#19'vtMangaListDblClick'#10'OnFreeNode'#7#19'vtMangaListFreeNode'#9'On' - +'GetText'#7#18'vtMangaListGetText'#9'OnGetHint'#7#18'vtMangaListGetHint'#10 - +'OnInitNode'#7#19'vtMangaListInitNode'#0#0#7'TBitBtn'#8'btSearch'#19'AnchorS' - +'ideLeft.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3 - +#160#0#6'Height'#2#21#4'Hint'#6#22'Search manga from list'#3'Top'#2'$'#5'Wid' - +'th'#2#24#7'Anchors'#11#5'akTop'#7'akRight'#0#7'OnClick'#7#13'btSearchClick' - +#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#3#0#0#6'TLabel'#6'lbMode'#4 - +'Left'#2#8#6'Height'#2#13#3'Top'#2'@'#5'Width'#2'}'#7'Caption'#6#20'Mode: Sh' - +'ow all manga'#10'Font.Style'#11#6'fsBold'#0#11'ParentColor'#8#10'ParentFont' - +#8#0#0#7'TBitBtn'#14'btRemoveFilter'#19'AnchorSideLeft.Side'#7#9'asrBottom' - +#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3#160#0#6'Height'#2#21#4'Hint' - +#6#13'Remove filter'#3'Top'#2'@'#5'Width'#2#24#7'Anchors'#11#5'akTop'#7'akRi' - +'ght'#0#7'OnClick'#7#19'btRemoveFilterClick'#14'ParentShowHint'#8#8'ShowHint' - +#9#8'TabOrder'#2#4#0#0#0#12'TPageControl'#6'pcMain'#4'Left'#3#195#0#6'Height' - +#3#210#1#3'Top'#2#0#5'Width'#3'+'#2#10'ActivePage'#7#11'tsFavorites'#5'Align' - +#7#8'alClient'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabIndex'#2#3 - +#8'TabOrder'#2#1#8'OnChange'#7#12'pcMainChange'#0#9'TTabSheet'#10'tsDownload' - +#7'Caption'#6#8'Download'#12'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0 - +#18'TVirtualStringTree'#10'vtDownload'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2 - +#0#5'Width'#3'#'#2#5'Align'#7#8'alClient'#11'DefaultText'#6#4'Node'#20'Heade' - +'r.AutoSizeIndex'#2#0#14'Header.Columns'#14#1#8'Position'#2#0#4'Text'#6#5'Ma' - +'nga'#5'Width'#2'd'#0#1#8'Position'#2#1#4'Text'#6#6'Status'#5'Width'#3#200#0 - +#0#1#8'Position'#2#2#4'Text'#6#8'Progress'#5'Width'#2'7'#0#1#8'Position'#2#3 - +#4'Text'#6#7'Website'#5'Width'#2'A'#0#1#8'Position'#2#4#4'Text'#6#7'Save to' - +#5'Width'#3#150#0#0#1#8'Position'#2#5#4'Text'#6#5'Added'#5'Width'#2'P'#0#0#20 - +'Header.DefaultHeight'#2#17#13'Header.Height'#2#25#14'Header.Options'#11#14 - +'hoColumnResize'#6'hoDrag'#16'hoShowSortGlyphs'#9'hoVisible'#0#12'Header.Sty' - +'le'#7#9'hsXPStyle'#10'ParentFont'#8#9'PopupMenu'#7#10'pmDownload'#8'TabOrde' - +'r'#2#0#24'TreeOptions.PaintOptions'#11#13'toShowButtons'#14'toShowDropmark' - +#10'toShowRoot'#12'toThemeAware'#18'toUseBlendedImages'#0#28'TreeOptions.Sel' - +'ectionOptions'#11#15'toFullRowSelect'#0#10'OnFreeNode'#7#18'vtDownloadFreeN' - +'ode'#9'OnGetText'#7#17'vtDownloadGetText'#10'OnInitNode'#7#18'vtDownloadIni' - +'tNode'#0#0#0#9'TTabSheet'#13'tsInformation'#7'Caption'#6#11'Manga Infos'#12 - +'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0#10'TScrollBox'#13'sbInformat' - +'ion'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2#0#5'Width'#3'#'#2#18'HorzScroll' - +'Bar.Page'#3#31#2#18'VertScrollBar.Page'#3#180#1#5'Align'#7#8'alClient'#12'C' - +'lientHeight'#3#180#1#11'ClientWidth'#3#31#2#8'TabOrder'#2#0#0#6'TPanel'#12 - +'pnInfomation'#4'Left'#2#0#6'Height'#3#234#0#3'Top'#2#0#5'Width'#3#31#2#5'Al' - +'ign'#7#5'alTop'#12'ClientHeight'#3#234#0#11'ClientWidth'#3#31#2#10'ParentFo' - +'nt'#8#8'TabOrder'#2#0#0#6'TImage'#7'imCover'#18'AnchorSideTop.Side'#7#9'asr' - +'Center'#21'AnchorSideBottom.Side'#7#9'asrCenter'#4'Left'#2#8#6'Height'#3#216 - +#0#3'Top'#2#8#5'Width'#3#154#0#7'Stretch'#9#0#0#9'TRichMemo'#13'rmInformatio' - +'n'#4'Left'#3#175#0#6'Height'#3#216#0#3'Top'#2#8#5'Width'#3'k'#1#7'Anchors' - +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#13'HideSelection'#8#10'Paren' - ,'tFont'#8#8'ReadOnly'#9#10'ScrollBars'#7#10'ssVertical'#8'TabOrder'#2#0#0#0#0 - +#9'TSplitter'#7'spInfos'#6'Cursor'#7#8'crVSplit'#4'Left'#2#0#6'Height'#2#5#3 - +'Top'#3#234#0#5'Width'#3#31#2#5'Align'#7#5'alTop'#12'ResizeAnchor'#7#5'akTop' - +#0#0#6'TPanel'#13'pnChapterList'#4'Left'#2#0#6'Height'#3#197#0#3'Top'#3#239#0 - +#5'Width'#3#31#2#5'Align'#7#8'alClient'#12'ClientHeight'#3#197#0#11'ClientWi' - +'dth'#3#31#2#8'TabOrder'#2#2#0#13'TCheckListBox'#14'clbChapterList'#18'Ancho' - +'rSideTop.Side'#7#9'asrBottom'#4'Left'#2#8#6'Height'#2'h'#3'Top'#2#9#5'Width' - +#3#15#2#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#10'ItemHei' - +'ght'#2#0#11'MultiSelect'#9#10'OnKeyPress'#7#22'clbChapterListKeyPress'#10'P' - +'arentFont'#8#9'PopupMenu'#7#13'pmChapterList'#8'TabOrder'#2#0#0#0#12'TLabel' - +'edEdit'#8'edSaveTo'#4'Left'#2#8#6'Height'#2#21#3'Top'#3#137#0#5'Width'#3#31 - +#1#7'Anchors'#11#6'akLeft'#8'akBottom'#0' EditLabel.AnchorSideLeft.Control'#7 - +#8'edSaveTo!EditLabel.AnchorSideRight.Control'#7#8'edSaveTo'#30'EditLabel.An' - +'chorSideRight.Side'#7#9'asrBottom"EditLabel.AnchorSideBottom.Control'#7#8'e' - +'dSaveTo'#14'EditLabel.Left'#2#8#16'EditLabel.Height'#2#13#13'EditLabel.Top' - +#2'y'#15'EditLabel.Width'#3#31#1#17'EditLabel.Caption'#6#7'Save to'#21'EditL' - +'abel.ParentColor'#8#20'EditLabel.ParentFont'#8#10'ParentFont'#8#8'TabOrder' - +#2#1#0#0#7'TBitBtn'#10'btDownload'#4'Left'#3#159#1#6'Height'#2#30#3'Top'#3 - +#128#0#5'Width'#2'['#7'Anchors'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#8'Do' - +'wnload'#7'OnClick'#7#15'btDownloadClick'#8'TabOrder'#2#2#0#0#7'TBitBtn'#8'b' - +'tBrowse'#4'Left'#3'7'#1#6'Height'#2#30#3'Top'#3#128#0#5'Width'#2'['#7'Ancho' - +'rs'#11#6'akLeft'#8'akBottom'#0#7'Caption'#6#6'Browse'#7'OnClick'#7#13'btBro' - +'wseClick'#8'TabOrder'#2#3#0#0#9'TCheckBox'#14'cbAddAsStopped'#4'Left'#2#8#6 - +'Height'#2#17#3'Top'#3#168#0#5'Width'#3#196#0#7'Caption'#6'$Add to download ' - +'list as stopped task'#8'OnChange'#7#20'cbAddAsStoppedChange'#10'ParentFont' - +#8#8'TabOrder'#2#4#0#0#9'TCheckBox'#16'cbAddToFavorites'#4'Left'#3'7'#1#6'He' - +'ight'#2#17#3'Top'#3#168#0#5'Width'#2'd'#7'Caption'#6#16'Add to Favorites'#10 - +'ParentFont'#8#8'TabOrder'#2#5#0#0#0#0#0#9'TTabSheet'#8'tsFilter'#7'Caption' - +#6#6'Filter'#12'ClientHeight'#3#184#1#11'ClientWidth'#3'#'#2#0#10'TScrollBox' - +#8'sbFilter'#4'Left'#2#0#6'Height'#3#184#1#3'Top'#2#0#5'Width'#3'#'#2#18'Hor' - +'zScrollBar.Page'#3#31#2#18'VertScrollBar.Page'#3#180#1#5'Align'#7#8'alClien' - +'t'#12'ClientHeight'#3#180#1#11'ClientWidth'#3#31#2#8'TabOrder'#2#0#0#6'TPan' - +'el'#8'pnGenres'#4'Left'#2#0#6'Height'#3#216#0#3'Top'#2#0#5'Width'#3#31#2#5 - +'Align'#7#5'alTop'#12'ClientHeight'#3#216#0#11'ClientWidth'#3#31#2#8'TabOrde' - +'r'#2#0#0#9'TCheckBox'#9'CheckBox1'#4'Left'#2#23#6'Height'#2#17#3'Top'#2#16#5 - +'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'Tab' - +'Order'#2#0#0#0#9'TCheckBox'#9'CheckBox2'#4'Left'#2#23#6'Height'#2#17#3'Top' - +#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8 - +#8'TabOrder'#2#1#0#0#9'TCheckBox'#9'CheckBox3'#4'Left'#2#23#6'Height'#2#17#3 - +'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentF' - +'ont'#8#8'TabOrder'#2#2#0#0#9'TCheckBox'#9'CheckBox4'#4'Left'#2#23#6'Height' - +#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10 - +'ParentFont'#8#8'TabOrder'#2#3#0#0#9'TCheckBox'#9'CheckBox5'#4'Left'#2#23#6 - +'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Act' - +'ion'#10'ParentFont'#8#8'TabOrder'#2#4#0#0#9'TCheckBox'#9'CheckBox6'#4'Left' - +#2#23#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Captio' - +'n'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#5#0#0#9'TCheckBox'#9'CheckBox' - +'7'#4'Left'#2#23#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed' - +#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#6#0#0#9'TCheckBox'#9 - +'CheckBox8'#4'Left'#2#23#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'Allo' - +'wGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#7#0#0#9'TC' - +'heckBox'#9'CheckBox9'#4'Left'#2#127#6'Height'#2#17#3'Top'#2#16#5'Width'#2'2' - +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#8#0 - +#0#9'TCheckBox'#10'CheckBox10'#4'Left'#2#127#6'Height'#2#17#3'Top'#2'('#5'Wi' - +'dth'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOr' - +'der'#2#9#0#0#9'TCheckBox'#10'CheckBox11'#4'Left'#2#127#6'Height'#2#17#3'Top' - +#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8 - +#8'TabOrder'#2#10#0#0#9'TCheckBox'#10'CheckBox12'#4'Left'#2#127#6'Height'#2 - +#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Pa' - +'rentFont'#8#8'TabOrder'#2#11#0#0#9'TCheckBox'#10'CheckBox13'#4'Left'#2#127#6 - +'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Act' - +'ion'#10'ParentFont'#8#8'TabOrder'#2#12#0#0#9'TCheckBox'#10'CheckBox14'#4'Le' - +'ft'#2#127#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'C' - +'aption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#13#0#0#9'TCheckBox'#10'C' - ,'heckBox15'#4'Left'#2#127#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'All' - +'owGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#14#0#0#9 - +'TCheckBox'#10'CheckBox16'#4'Left'#2#127#6'Height'#2#17#3'Top'#3#184#0#5'Wid' - +'th'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrd' - +'er'#2#15#0#0#9'TCheckBox'#10'CheckBox17'#4'Left'#3#223#0#6'Height'#2#17#3'T' - +'op'#2#16#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFo' - +'nt'#8#8'TabOrder'#2#16#0#0#9'TCheckBox'#10'CheckBox18'#4'Left'#3#223#0#6'He' - +'ight'#2#17#3'Top'#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Actio' - +'n'#10'ParentFont'#8#8'TabOrder'#2#17#0#0#9'TCheckBox'#10'CheckBox19'#4'Left' - +#3#223#0#6'Height'#2#17#3'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Captio' - +'n'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#18#0#0#9'TCheckBox'#10'CheckB' - +'ox20'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGray' - +'ed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#19#0#0#9'TCheck' - +'Box'#10'CheckBox21'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#2'p'#5'Width'#2'2' - +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#20#0 - +#0#9'TCheckBox'#10'CheckBox22'#4'Left'#3#223#0#6'Height'#2#17#3'Top'#3#136#0 - +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' - +'abOrder'#2#21#0#0#9'TCheckBox'#10'CheckBox23'#4'Left'#3#223#0#6'Height'#2#17 - +#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Pa' - +'rentFont'#8#8'TabOrder'#2#22#0#0#9'TCheckBox'#10'CheckBox24'#4'Left'#3#223#0 - +#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6 - +'Action'#10'ParentFont'#8#8'TabOrder'#2#23#0#0#9'TCheckBox'#10'CheckBox25'#4 - +'Left'#3'?'#1#6'Height'#2#17#3'Top'#2#16#5'Width'#2'2'#11'AllowGrayed'#9#7'C' - +'aption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#24#0#0#9'TCheckBox'#10'C' - +'heckBox26'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'('#5'Width'#2'2'#11'Allow' - +'Grayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#25#0#0#9'TC' - +'heckBox'#10'CheckBox27'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'@'#5'Width'#2 - +'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2 - +#26#0#0#9'TCheckBox'#10'CheckBox28'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#2'X' - +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' - +'abOrder'#2#27#0#0#9'TCheckBox'#10'CheckBox29'#4'Left'#3'?'#1#6'Height'#2#17 - +#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'Paren' - +'tFont'#8#8'TabOrder'#2#28#0#0#9'TCheckBox'#10'CheckBox30'#4'Left'#3'?'#1#6 - +'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6 - +'Action'#10'ParentFont'#8#8'TabOrder'#2#29#0#0#9'TCheckBox'#10'CheckBox31'#4 - +'Left'#3'?'#1#6'Height'#2#17#3'Top'#3#160#0#5'Width'#2'2'#11'AllowGrayed'#9#7 - +'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#30#0#0#9'TCheckBox'#10 - +'CheckBox32'#4'Left'#3'?'#1#6'Height'#2#17#3'Top'#3#184#0#5'Width'#2'2'#11'A' - +'llowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2#31#0#0#9 - +'TCheckBox'#10'CheckBox33'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#2#16#5'Widt' - +'h'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrde' - +'r'#2' '#0#0#9'TCheckBox'#10'CheckBox34'#4'Left'#3#167#1#6'Height'#2#17#3'To' - +'p'#2'('#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFon' - +'t'#8#8'TabOrder'#2'!'#0#0#9'TCheckBox'#10'CheckBox35'#4'Left'#3#167#1#6'Hei' - +'ght'#2#17#3'Top'#2'@'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action' - +#10'ParentFont'#8#8'TabOrder'#2'"'#0#0#9'TCheckBox'#10'CheckBox36'#4'Left'#3 - +#167#1#6'Height'#2#17#3'Top'#2'X'#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption' - +#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'#'#0#0#9'TCheckBox'#10'CheckBox3' - +'7'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#2'p'#5'Width'#2'2'#11'AllowGrayed' - +#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'$'#0#0#9'TCheckBox' - +#10'CheckBox38'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#3#136#0#5'Width'#2'2' - +#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'TabOrder'#2'%'#0 - +#0#9'TCheckBox'#10'CheckBox39'#4'Left'#3#167#1#6'Height'#2#17#3'Top'#3#160#0 - +#5'Width'#2'2'#11'AllowGrayed'#9#7'Caption'#6#6'Action'#10'ParentFont'#8#8'T' - +'abOrder'#2'&'#0#0#0#6'TPanel'#8'pnFilter'#4'Left'#2#0#6'Height'#3#192#0#3'T' - +'op'#3#216#0#5'Width'#3#31#2#5'Align'#7#5'alTop'#12'ClientHeight'#3#192#0#11 - +'ClientWidth'#3#31#2#10'ParentFont'#8#8'TabOrder'#2#1#0#12'TRadioButton'#5'r' - +'bOne'#4'Left'#3'C'#1#6'Height'#2#17#3'Top'#2' '#5'Width'#3#157#0#7'Caption' - +#6#26'Have one of genres checked'#10'ParentFont'#8#8'TabOrder'#2#1#0#0#12'TR' - +'adioButton'#5'rbAll'#4'Left'#3'C'#1#6'Height'#2#17#3'Top'#2#8#5'Width'#3#131 - +#0#7'Caption'#6#22'Have all genre checked'#7'Checked'#9#10'ParentFont'#8#8'T' - +'abOrder'#2#0#7'TabStop'#9#0#0#9'TCheckBox'#9'cbOnlyNew'#4'Left'#3'C'#1#6'He' - +'ight'#2#17#3'Top'#2'8'#5'Width'#3#134#0#7'Caption'#6#21'Search only new man' - +'ga'#10'ParentFont'#8#8'TabOrder'#2#2#0#0#5'TEdit'#13'edFilterTitle'#4'Left' - ,#2'~'#6'Height'#2#21#3'Top'#2#8#5'Width'#3#146#0#8'TabOrder'#2#3#0#0#5'TEdit' - +#15'edFilterArtists'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2'8'#5'Width'#3#146#0 - +#8'TabOrder'#2#4#0#0#5'TEdit'#15'edFilterAuthors'#4'Left'#2'~'#6'Height'#2#21 - +#3'Top'#2' '#5'Width'#3#146#0#8'TabOrder'#2#5#0#0#6'TLabel'#13'lbFilterTitle' - +#4'Left'#2''''#6'Height'#2#16#3'Top'#2#8#5'Width'#2#27#9'Alignment'#7#14'taR' - +'ightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#5'Title'#11'Font.' - +'Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentC' - +'olor'#8#10'ParentFont'#8#0#0#6'TLabel'#15'lbFilterAuthors'#4'Left'#2''''#6 - +'Height'#2#16#3'Top'#2' '#5'Width'#2'5'#9'Alignment'#7#14'taRightJustify'#8 - +'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#7'Authors'#11'Font.Height'#2#243 - +#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentColor'#8#10'Par' - +'entFont'#8#0#0#6'TLabel'#15'lbFilterArtists'#4'Left'#2''''#6'Height'#2#16#3 - +'Top'#2'8'#5'Width'#2'-'#9'Alignment'#7#14'taRightJustify'#8'BidiMode'#7#13 - +'bdRightToLeft'#7'Caption'#6#7'Artists'#11'Font.Height'#2#243#10'Font.Style' - +#11#6'fsBold'#0#14'ParentBidiMode'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#9 - +'TComboBox'#14'cbFilterStatus'#4'Left'#2'~'#6'Height'#2#21#3'Top'#2'P'#5'Wid' - +'th'#3#146#0#10'ItemHeight'#2#13#9'ItemIndex'#2#2#13'Items.Strings'#1#6#9'Co' - +'mpleted'#6#7'Ongoing'#6#6'<none>'#0#8'TabOrder'#2#6#4'Text'#6#6'<none>'#0#0 - +#6'TLabel'#14'lbFilterStatus'#4'Left'#2''''#6'Height'#2#16#3'Top'#2'P'#5'Wid' - +'th'#2'+'#9'Alignment'#7#14'taRightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7 - +'Caption'#6#6'Status'#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14 - +'ParentBidiMode'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#6'TLabel'#15'lbFil' - +'terSummary'#4'Left'#2''''#6'Height'#2#16#3'Top'#2'h'#5'Width'#2'<'#9'Alignm' - +'ent'#7#14'taRightJustify'#8'BidiMode'#7#13'bdRightToLeft'#7'Caption'#6#7'Su' - +'mmary'#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#14'ParentBidiMod' - +'e'#8#11'ParentColor'#8#10'ParentFont'#8#0#0#5'TEdit'#15'edFilterSummary'#4 - +'Left'#2'~'#6'Height'#2#21#3'Top'#2'h'#5'Width'#3'a'#1#8'TabOrder'#2#7#0#0#7 - +'TButton'#8'btFilter'#4'Left'#2''''#6'Height'#2'%'#3'Top'#3#139#0#5'Width'#3 - +#130#0#7'Caption'#6#6'Filter'#10'Font.Color'#7#11'clHighlight'#11'Font.Heigh' - +'t'#2#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#13'btFilterClick'#10'Pa' - +'rentFont'#8#8'TabOrder'#2#8#0#0#7'TButton'#13'btFilterReset'#4'Left'#3'_'#1 - +#6'Height'#2'%'#3'Top'#3#139#0#5'Width'#3#128#0#7'Caption'#6#11'Reset value' - +#11'Font.Height'#2#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#18'btFilte' - +'rResetClick'#10'ParentFont'#8#8'TabOrder'#2#9#0#0#7'TBitBtn'#19'btRemoveFil' - +'terLarge'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9 - +'asrBottom'#4'Left'#3#191#0#6'Height'#2'%'#4'Hint'#6#13'Remove filter'#3'Top' - +#3#139#0#5'Width'#3#136#0#7'Caption'#6#13'Remove filter'#11'Font.Height'#2 - +#243#10'Font.Style'#11#6'fsBold'#0#7'OnClick'#7#19'btRemoveFilterClick'#10'P' - +'arentFont'#8#14'ParentShowHint'#8#8'ShowHint'#9#8'TabOrder'#2#10#0#0#0#0#0#9 - +'TTabSheet'#11'tsFavorites'#7'Caption'#6#9'Favorites'#12'ClientHeight'#3#184 - +#1#11'ClientWidth'#3'#'#2#0#18'TVirtualStringTree'#11'vtFavorites'#4'Left'#2 - +#0#6'Height'#3't'#1#3'Top'#2#0#5'Width'#3'#'#2#5'Align'#7#5'alTop'#7'Anchors' - +#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom'#0#11'DefaultText'#6#4'Node'#20 - +'Header.AutoSizeIndex'#2#0#14'Header.Columns'#14#1#8'Position'#2#0#4'Text'#6 - +#5'Title'#5'Width'#3#150#0#0#1#8'Position'#2#1#4'Text'#6#15'Current chapter' - +#5'Width'#2'd'#0#1#8'Position'#2#2#4'Text'#6#7'Website'#5'Width'#2'A'#0#1#8 - +'Position'#2#3#4'Text'#6#7'Save to'#5'Width'#3#200#0#0#0#20'Header.DefaultHe' - +'ight'#2#24#13'Header.Height'#2#24#14'Header.Options'#11#14'hoColumnResize'#6 - +'hoDrag'#16'hoShowSortGlyphs'#9'hoVisible'#0#12'Header.Style'#7#9'hsXPStyle' - +#8'TabOrder'#2#0#0#0#0#9'TTabSheet'#8'tsOption'#7'Caption'#6#7'Options'#12'C' - +'lientHeight'#3#160#1#11'ClientWidth'#3'!'#2#0#12'TPageControl'#9'pnOptions' - +#4'Left'#2#9#6'Height'#3'C'#1#3'Top'#2#26#5'Width'#3#14#2#10'ActivePage'#7#19 - +'tsOptionConnections'#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#8'akBottom' - +#0#8'TabIndex'#2#0#8'TabOrder'#2#0#0#9'TTabSheet'#19'tsOptionConnections'#7 - +'Caption'#6#11'Connections'#12'ClientHeight'#3')'#1#11'ClientWidth'#3#6#2#0 - +#10'TScrollBox'#21'sbDownloadConnections'#4'Left'#2#0#6'Height'#3')'#1#3'Top' - +#2#0#5'Width'#3#6#2#18'HorzScrollBar.Page'#3#2#2#18'VertScrollBar.Page'#3'%' - +#1#5'Align'#7#8'alClient'#12'ClientHeight'#3'%'#1#11'ClientWidth'#3#2#2#8'Ta' - +'bOrder'#2#0#0#9'TCheckBox'#16'cbOptionUseProxy'#4'Left'#2' '#6'Height'#2#17 - +#3'Top'#3#154#0#5'Width'#2'E'#7'Caption'#6#9'Use proxy'#8'OnChange'#7#22'cbO' - +'ptionUseProxyChange'#10'ParentFont'#8#8'TabOrder'#2#0#0#0#9'TGroupBox'#13'g' - +'bOptionProxy'#4'Left'#2#12#6'Height'#2'h'#3'Top'#3#178#0#5'Width'#3#240#1#7 - +'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0#7'Caption'#6#12'Proxy config'#12 - +'ClientHeight'#2'T'#11'ClientWidth'#3#236#1#7'Enabled'#8#8'TabOrder'#2#1#0#6 - ,'TLabel'#12'lbOptionHost'#4'Left'#2#14#6'Height'#2#13#3'Top'#2#14#5'Width'#2 - +#26#7'Caption'#6#4'Host'#10'Font.Style'#11#6'fsBold'#0#11'ParentColor'#8#10 - +'ParentFont'#8#0#0#6'TLabel'#12'lbOptionPort'#4'Left'#2#14#6'Height'#2#13#3 - +'Top'#2'.'#5'Width'#2#24#7'Caption'#6#4'Port'#11'ParentColor'#8#0#0#5'TEdit' - +#12'edOptionHost'#4'Left'#2'7'#6'Height'#2#23#3'Top'#2#7#5'Width'#3#154#0#12 - +'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name'#6#7'Def' - +'ault'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#0#0#0#5 - +'TEdit'#12'edOptionPort'#4'Left'#2'7'#6'Height'#2#23#3'Top'#2''''#5'Width'#3 - +#154#0#12'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name' - +#6#7'Default'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#1 - +#0#0#6'TLabel'#12'lbOptionUser'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'An' - +'chorSideTop.Side'#7#9'asrBottom'#4'Left'#3#230#0#6'Height'#2#13#3'Top'#2#14 - +#5'Width'#2':'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Caption'#6#8'Username' - +#11'ParentColor'#8#0#0#6'TLabel'#12'lbOptionPass'#19'AnchorSideLeft.Side'#7#9 - +'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3#234#0#6'Height'#2 - +#13#3'Top'#2'.'#5'Width'#2'6'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Caption' - +#6#8'Password'#11'ParentColor'#8#0#0#5'TEdit'#12'edOptionUser'#19'AnchorSide' - +'Left.Side'#7#9'asrBottom'#18'AnchorSideTop.Side'#7#9'asrBottom'#4'Left'#3',' - +#1#6'Height'#2#23#3'Top'#2#7#5'Width'#3#154#0#7'Anchors'#11#5'akTop'#7'akRig' - +'ht'#0#12'Font.CharSet'#7#12'ANSI_CHARSET'#11'Font.Height'#2#244#9'Font.Name' - +#6#7'Default'#10'Font.Style'#11#6'fsBold'#0#10'ParentFont'#8#8'TabOrder'#2#2 - +#0#0#5'TEdit'#12'edOptionPass'#19'AnchorSideLeft.Side'#7#9'asrBottom'#18'Anc' - +'horSideTop.Side'#7#9'asrBottom'#4'Left'#3','#1#6'Height'#2#23#3'Top'#2''''#5 - +'Width'#3#154#0#7'Anchors'#11#5'akTop'#7'akRight'#0#12'Font.CharSet'#7#12'AN' - +'SI_CHARSET'#11'Font.Height'#2#244#9'Font.Name'#6#7'Default'#10'ParentFont'#8 - +#8'TabOrder'#2#3#0#0#0#9'TSpinEdit'#19'seOptionMaxParallel'#4'Left'#2#12#6'H' - +'eight'#2#21#3'Top'#2#26#5'Width'#2'0'#8'MaxValue'#2#8#8'MinValue'#2#1#10'Pa' - +'rentFont'#8#14'ParentShowHint'#8#8'TabOrder'#2#2#5'Value'#2#1#0#0#6'TLabel' - +#19'lbOptionMaxParallel'#4'Left'#2'L'#6'Height'#2#13#3'Top'#2#26#5'Width'#3 - +#10#1#7'Caption'#6'4Number of downloaded tasks at the same time (Max: 8)'#11 - +'ParentColor'#8#10'ParentFont'#8#0#0#6'TLabel'#17'lbOptionMaxThread'#4'Left' - +#2'L'#6'Height'#2#13#3'Top'#2':'#5'Width'#3'.'#1#7'Caption'#6'=Number of dow' - +'nloaded files per task at the same time (Max: 8)'#11'ParentColor'#8#10'Pare' - +'ntFont'#8#0#0#9'TSpinEdit'#17'seOptionMaxThread'#4'Left'#2#12#6'Height'#2#21 - +#3'Top'#2':'#5'Width'#2'0'#8'MaxValue'#2#8#8'MinValue'#2#1#10'ParentFont'#8 - +#14'ParentShowHint'#8#8'TabOrder'#2#3#5'Value'#2#1#0#0#9'TSpinEdit'#16'seOpt' - +'ionMaxRetry'#4'Left'#2#12#6'Height'#2#21#3'Top'#2'Z'#5'Width'#2'0'#8'MaxVal' - +'ue'#2#0#10'ParentFont'#8#14'ParentShowHint'#8#8'TabOrder'#2#4#0#0#6'TLabel' - +#16'lbOptionMaxRetry'#4'Left'#2'L'#6'Height'#2#13#3'Top'#2'Z'#5'Width'#3'c'#1 - +#7'Caption'#6'HNumber of retry times if tasks have download problems (0 = al' - +'ways retry)'#11'ParentColor'#8#10'ParentFont'#8#0#0#0#0#9'TTabSheet'#8'tsSa' - +'veTo'#7'Caption'#6#7'Save to'#12'ClientHeight'#3')'#1#11'ClientWidth'#3#6#2 - +#0#12'TLabeledEdit'#19'edOptionDefaultPath'#4'Left'#2#28#6'Height'#2#21#3'To' - +'p'#2'*'#5'Width'#3#198#1#7'Anchors'#11#5'akTop'#6'akLeft'#7'akRight'#0' Edi' - +'tLabel.AnchorSideLeft.Control'#7#19'edOptionDefaultPath!EditLabel.AnchorSid' - +'eRight.Control'#7#19'edOptionDefaultPath'#30'EditLabel.AnchorSideRight.Side' - +#7#9'asrBottom"EditLabel.AnchorSideBottom.Control'#7#19'edOptionDefaultPath' - +#14'EditLabel.Left'#2#28#16'EditLabel.Height'#2#13#13'EditLabel.Top'#2#26#15 - +'EditLabel.Width'#3#198#1#17'EditLabel.Caption'#6#29'Choose default download' - +' path:'#21'EditLabel.ParentColor'#8#20'EditLabel.ParentFont'#8#10'ParentFon' - +'t'#8#8'TabOrder'#2#0#0#0#0#0#7'TButton'#13'btOptionApply'#4'Left'#2'&'#6'He' - +'ight'#2'!'#3'Top'#3'm'#1#5'Width'#2'c'#7'Anchors'#11#8'akBottom'#0#7'Captio' - +'n'#6#5'Apply'#7'OnClick'#7#18'btOptionApplyClick'#8'TabOrder'#2#1#0#0#0#0#9 - +'TSplitter'#14'spMainSplitter'#23'AnchorSideRight.Control'#7#6'pcMain'#4'Lef' - +'t'#3#195#0#6'Height'#3#210#1#3'Top'#2#8#5'Width'#2#5#5'Align'#7#6'alNone'#7 - +'Anchors'#11#5'akTop'#6'akLeft'#8'akBottom'#0#0#0#22'TSelectDirectoryDialog' - +#9'dlgSaveTo'#4'left'#2'P'#3'top'#3#184#0#0#0#10'TPopupMenu'#10'pmDownload'#4 - +'left'#2'P'#3'top'#3#239#0#0#9'TMenuItem'#14'miDownloadStop'#7'Caption'#6#4 - +'Stop'#7'OnClick'#7#19'miDownloadStopClick'#0#0#9'TMenuItem'#16'miDownloadRe' - +'muse'#7'Caption'#6#6'Resume'#7'OnClick'#7#21'miDownloadResumeClick'#0#0#9'T' - +'MenuItem'#16'miDownloadRemove'#7'Caption'#6#6'Remove'#7'OnClick'#7#21'miDow' - +'nloadRemoveClick'#0#0#9'TMenuItem'#29'miDownloadRemoveFinishedTasks'#7'Capt' - +'ion'#6#21'Remove finished tasks'#7'OnClick'#7'"miDownloadRemoveFinishedTask' - +'sClick'#0#0#0#10'TPopupMenu'#13'pmChapterList'#4'left'#2'P'#3'top'#3'('#1#0 - ,#9'TMenuItem'#26'miChapterListCheckSelected'#7'Caption'#6#14'Check selected' - +#7'OnClick'#7#31'miChapterListCheckSelectedClick'#0#0#9'TMenuItem'#28'miChap' - +'terListUncheckSelected'#7'Caption'#6#16'Uncheck selected'#7'OnClick'#7'!miC' - +'hapterListUncheckSelectedClick'#0#0#9'TMenuItem'#4'miI1'#7'Caption'#6#1'-'#0 - +#0#9'TMenuItem'#21'miChapterListCheckAll'#7'Caption'#6#9'Check all'#7'OnClic' - +'k'#7#26'miChapterListCheckAllClick'#0#0#9'TMenuItem'#23'miChapterListUnchec' - +'kAll'#7'Caption'#6#11'Uncheck all'#7'OnClick'#7#28'miChapterListUncheckAllC' - +'lick'#0#0#0#0 -]); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index ffa21e743..53af8671e 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -406,6 +406,26 @@ msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Password" +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Basic list" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Chapter list" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Favorite list" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Manga list" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 02fd6cf37..b05f591fd 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -398,6 +398,26 @@ msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Kata kunci" +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Semua daftar" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Daftar bab" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Daftar kesukaan" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Daftar komik" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index f15cf5bbc..611dbdff7 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -363,6 +363,26 @@ msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" msgid "Password" msgstr "" +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9e0d6c9ea..1e12487a0 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -238,7 +238,7 @@ <PackageName Value="LCL"/> </Item7> </RequiredPackages> - <Units Count="11"> + <Units Count="12"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -313,6 +313,13 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit10> + <Unit11> + <Filename Value="forms\frmCustomColor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="CustomColorForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit11> </Units> </ProjectOptions> <CompilerOptions> From 6ffe53a3668b4bff02110c874133de1345327c47 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 3 Jul 2016 23:38:37 +0800 Subject: [PATCH 1297/2794] dbdataprocess, added valueint and value as default property --- baseunits/DBDataProcess.pas | 23 ++++++++++++++++------- mangadownloader/forms/frmMain.pas | 6 +++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index bcacaaa84..152f40eb3 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -53,6 +53,7 @@ TDBDataProcess = class(TObject) function InternalOpen(const FilePath: String = ''): Boolean; function GetWebsiteName(RecIndex: Integer): String; function GetValue(RecIndex, FieldIndex: Integer): String; + function GetValueInt(RecIndex, FieldIndex: Integer): Integer; procedure AttachAllSites; procedure DetachAllSites; function ExecuteDirect(SQL: String): Boolean; @@ -105,7 +106,8 @@ TDBDataProcess = class(TObject) property FilterAllSites: Boolean read FFilterAllSites write FFilterAllSites; property SitesList: TStringList read FSitesList write FSitesList; property WebsiteName[RecIndex: Integer]: String read GetWebsiteName; - property Value[RecIndex, ParamNo: Integer]: String read GetValue; + property Value[RecIndex, FieldIndex: Integer]: String read GetValue; default; + property ValueInt[RecIndex, FieldIndex: Integer]: Integer read GetValueInt; property LinkCount: Integer read GetLinkCount; property Table: TSQLQuery read FQuery; end; @@ -480,16 +482,23 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; else Result:=''; if FQuery.Active=False then Exit; - if FieldIndex>=FQuery.Fields.Count then Exit; - if (RecIndex<0) or (RecIndex>FRecordCount) then Exit; try FQuery.RecNo:=RecIndex+1; Result:=FQuery.Fields[FieldIndex].AsString; except - on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].GetValue.Error!'+ - ' RecIndex: '+IntToStr(RecIndex)+', FieldIndex: '+IntToStr(FieldIndex)+ - ', RecordCount: '+IntToStr(FQuery.RecordCount), E, Self); + end; +end; + +function TDBDataProcess.GetValueInt(RecIndex, FieldIndex: Integer): Integer; +begin + Result:=0; + if FQuery.Active=False then Exit; + if not (FieldIndex in [DATA_PARAM_NUMCHAPTER,DATA_PARAM_JDN]) then + Exit; + try + FQuery.RecNo:=RecIndex+1; + Result:=FQuery.Fields[FieldIndex].AsInteger; + except end; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 98c0856ff..6131bf9d8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3725,7 +3725,7 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; if dataProcess.Value[Node^.Index, DATA_PARAM_STATUS] = MangaInfo_StatusCompleted then Brush.Color := CL_MNCompletedManga; if miHighlightNewManga.Checked and - (StrToIntDef(dataProcess.Value[Node^.Index, DATA_PARAM_JDN], 0) > (currentJDN - OptionNewMangaTime)) then + (dataProcess.ValueInt[Node^.Index, DATA_PARAM_JDN] > (currentJDN - OptionNewMangaTime)) then Brush.Color := CL_MNNewManga; if Brush.Color <> clNone then @@ -3784,8 +3784,8 @@ procedure TMainForm.vtMangaListGetText(Sender: TBaseVirtualTree; var CellText: String); begin if Assigned(Node) then - CellText := Format('%s (%s)', [dataProcess.Value[Node^.Index, DATA_PARAM_TITLE], - dataProcess.Value[Node^.Index, DATA_PARAM_NUMCHAPTER]]); + CellText := Format('%s (%d)', [dataProcess.Value[Node^.Index, DATA_PARAM_TITLE], + dataProcess.ValueInt[Node^.Index, DATA_PARAM_NUMCHAPTER]]); end; procedure TMainForm.InitCheckboxes; From 9ebe19f7ad673ac60f490f5993da489420407634 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 4 Jul 2016 01:08:45 +0800 Subject: [PATCH 1298/2794] baseunit, mangainfostatusifpos use lowercase --- baseunits/uBaseUnit.pas | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 6dada0b9e..a2aa71c8c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3822,12 +3822,17 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); end; function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String): String; +var + s, o, c: String; begin Result := ''; if SearchStr = '' then Exit; - If Pos(OngoingStr, SearchStr) <> 0 then + s := LowerCase(SearchStr); + o := LowerCase(OngoingStr); + c := LowerCase(CompletedStr); + If Pos(o, s) <> 0 then Result := MangaInfo_StatusOngoing - else if Pos(CompletedStr, SearchStr) <> 0 then + else if Pos(c, s) <> 0 then Result := MangaInfo_StatusCompleted; end; From 76c6ed2ef9333be7c50d06f42c4fadc5056ccbb0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 4 Jul 2016 01:50:29 +0800 Subject: [PATCH 1299/2794] rewrite mangasee, mangalife fixed #315 --- .../includes/MangaSee/chapter_page_number.inc | 41 ---- .../MangaSee/directory_page_number.inc | 6 - .../includes/MangaSee/manga_information.inc | 102 --------- .../includes/MangaSee/names_and_links.inc | 37 ---- baseunits/modules/MangaLife.pas | 198 +++++++++--------- baseunits/uBaseUnit.pas | 12 +- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 5 - 8 files changed, 107 insertions(+), 309 deletions(-) delete mode 100644 baseunits/includes/MangaSee/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaSee/directory_page_number.inc delete mode 100644 baseunits/includes/MangaSee/manga_information.inc delete mode 100644 baseunits/includes/MangaSee/names_and_links.inc diff --git a/baseunits/includes/MangaSee/chapter_page_number.inc b/baseunits/includes/MangaSee/chapter_page_number.inc deleted file mode 100644 index 45954dcfc..000000000 --- a/baseunits/includes/MangaSee/chapter_page_number.inc +++ /dev/null @@ -1,41 +0,0 @@ - function GetMangaSeePageNumber: Boolean; - var - s: String; - i: LongInt; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - - s := DecodeUrl(URL); - if RightStr(s, 7) = '&page=1' then - SetLength(s, Length(s) - 7); - s := FillMangaSiteHost(Task.Container.MangaSiteID, s); - - Result := GetPage(TObject(l), s, Task.container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '^.*src="([^"]+)".*$'; - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) <> 0) and (Pos('this.onerror=null', parse[i]) <> 0) then - begin - Inc(Task.Container.PageNumber); - Task.Container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); - end; - finally - regx.Free; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaSee/directory_page_number.inc b/baseunits/includes/MangaSee/directory_page_number.inc deleted file mode 100644 index 33bddf35a..000000000 --- a/baseunits/includes/MangaSee/directory_page_number.inc +++ /dev/null @@ -1,6 +0,0 @@ - function GetMangaSeeDirectoryPageNumber: Byte; - begin - Source.Free; - Result := NO_ERROR; - Page := 27; //# to Z - end; diff --git a/baseunits/includes/MangaSee/manga_information.inc b/baseunits/includes/MangaSee/manga_information.inc deleted file mode 100644 index 03928679e..000000000 --- a/baseunits/includes/MangaSee/manga_information.inc +++ /dev/null @@ -1,102 +0,0 @@ - function GetMangaSeeInfoFromURL: Byte; - var - i: LongInt; - s: String; - isExtractGenres : Boolean = False; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGASEE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGASEE_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.genres := ''; - - if parse.Count = 0 then - Exit; - - for i := 0 to parse.Count - 1 do - begin - //title - if Pos('<h1', parse[i]) <> 0 then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //cover - if (Pos('<img', parse[i]) <> 0) and (Pos('/cover/', parse[i]) <> 0) then - mangaInfo.coverLink := GetMangaSiteRoot(MANGASEE_ID) + TrimLeftChar(GetVal(parse[i], 'src'), ['.']); - - if i + 2 < parse.Count - 1 then - if Pos('</b', parse[i + 1]) <> 0 then - begin - //author - if (Pos('Author:', parse[i]) <> 0) then - mangaInfo.authors := CommonStringFilter(parse[i + 3]); - - //status - if (Pos('Scanlation Status:', parse[i]) <> 0) then - if Trim(LowerCase(parse[i + 2])) = 'ongoing' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - - //summary - if (Pos('Description:', parse[i]) <> 0) then - mangaInfo.summary := CommonStringFilter(parse[i + 4]); - - //genres - if (Pos('Genre:', parse[i]) <> 0) then - isExtractGenres := True; - end; - - //genres - if isExtractGenres and (Pos('</div', parse[i]) <> 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('<a', parse[i]) <> 0) then - if (Pos('<', parse[i + 1]) = 0) then - if mangaInfo.genres = '' then - mangaInfo.genres := parse[i + 1] - else - mangaInfo.genres := mangaInfo.genres + ', ' + parse[i + 1]; - - //chapters - if (not isExtractChapters) and (Pos('<!--Chapter Row-->', parse[i]) <> 0) then - isExtractChapters := True; - if isExtractChapters and (Pos('<!-- Divider -->', parse[i]) <> 0) then - Break; - if isExtractChapters and - (Pos('<a', parse[i]) <> 0) and (Pos('chapter_link', parse[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - s := TrimLeftChar(GetVal(parse[i], 'href'), ['.']); - if RightStr(s, 7) = '&page=1' then - SetLength(s, Length(s) - 7); - mangaInfo.chapterLinks.Add(s); - s := Trim(parse[i + 1]); - if Pos('<gray', parse[i + 3]) <> 0 then - s := s + ' ' + Trim(parse[i + 4]); - mangaInfo.chapterName.Add(CommonStringFilter(s)); - end; - end; - - //invert - if mangainfo.ChapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterLinks); - InvertStrings(mangaInfo.chapterName); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaSee/names_and_links.inc b/baseunits/includes/MangaSee/names_and_links.inc deleted file mode 100644 index 678f340d8..000000000 --- a/baseunits/includes/MangaSee/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function MangaSeeGetNamesAndLinks: Byte; - var - i: LongInt; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[MANGASEE_ID, 1] + '/directory.php'; - i := StrToIntDef(URL, 0); - if i > 0 then - s := s + '?c=' + chr(i + 64); - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (Pos('<a', parse[i]) <> 0) and (Pos('id=', parse[i]) <> 0) and - (GetVal(parse[i], 'class') = 'directory_link') then - begin - s := GetVal(parse[i], 'href'); - s := TrimLeftChar(s, ['.']); - links.Add(s); - names.Add(CommonStringFilter(parse[i + 1])); - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 9cefede99..8c7725234 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -15,143 +15,149 @@ implementation const dirURL = '/directory/'; + diralpha = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + dirURLmangasee = '/directory.php'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + if Module.Website = 'MangaSee' then + Page := Length(diralpha) + else + Page := 1; +end; + +function fixcleanurl(const u: string): string; +begin + result:=u; + if pos('../',result)<>0 then + result:=stringreplace(result,'../','/',[]); +end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; v: IXQValue; + s: String; begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL, 3) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - for v in Query.XPath('//*[@id="content"]/p/a') do begin - ALinks.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); - ANames.Add(v.toString); - end; - finally - Query.Free; + s := Module.RootURL; + if Module.Website = 'MangaSee' then + s += dirURLmangasee + else + s+=dirURL; + //mangasee + if AURL <> '0' then + s += '?c=' + diralpha[StrToInt(AURL) + 1]; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@id="content"]//a') do + begin + ALinks.Add(fixcleanurl(v.toNode.getAttribute('href'))); + ANames.Add(v.toString); end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + finally + Free; + end; end; end; +function fixchapterurl(const u: string): string; +begin + result:=fixcleanurl(u); + if (pos('&page=1',result)<>0) or + (pos('/page-1',result)<>0) then + setlength(result,length(result)-7); +end; + function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; - info: TMangaInfo; v: IXQValue; s: String; begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, AURL)); - Source := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try - with info do begin - coverLink := Query.XPathString('//div[@class="well"]/div[1]/div/img/@src'); - if coverLink <> '' then - coverLink := MaybeFillHost(Module.RootURL, coverLink); - title := Query.XPathString('//h1'); - for v in Query.XPath('//span[@class="details hidden-xs"]/div') do begin - s := v.toString; - if Pos('Author:', s) = 1 then authors := SeparateRight(s, ':') - else if Pos('Artist:', s) = 1 then artists := SeparateRight(s, ':') - else if Pos('Genre:', s) = 1 then artists := SeparateRight(s, ':') - else if Pos('Scanlation Status:', s) = 1 then begin - if Pos('Ongoing', s) > 0 then status := '1' - else status := '0'; - end; - end; - summary := Query.XPathString('//span[@class="details hidden-xs"]/div/div/div'); - //chapters - for v in Query.XPath('//div[@class="list"]/div/div/a') do begin - s := v.toNode.getAttribute('href'); - if RightStr(s, 6) = 'page-1' then SetLength(s, Length(s) - 6); - chapterLinks.Add(s); - chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks, chapterName]); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); + if title = '' then title := XPathString('//*[@class="row"]//h1'); + authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author:")]'), ':'); + artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist:")]'), ':'); + status := MangaInfoStatusIfPos(XPathString( + '//*[@class="row"][starts-with(.,"Scanlation Status:")]'), + 'ongoing', + 'completed'); + genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre:")]'), ':'); + summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description:")]'), ':')); + if Module.Website = 'MangaSee' then + s := 'div.col-lg-12:nth-child(8)>div>div:nth-child(1)>a' + else + s := 'div.list>div>div>a'; + for v in CSS(s) do + begin + chapterLinks.Add(fixchapterurl(v.toNode.getAttribute('href'))); + chapterName.Add(v.toString); end; + InvertStrings([chapterLinks, chapterName]); finally - Query.Free; + Free; end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; - v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.Task.Container; - with Container do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin PageLinks.Clear; PageNumber := 0; - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, AURL)), Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - for v in Query.XPath('//*[@class="imagePage"]/img/@src') do - Container.PageLinks.Add(v.toString); - finally - Query.Free; - end; + if GET(fixchapterurl(MaybeFillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//p/img/@src', PageLinks); + finally + Free; end; - finally - Source.Free; end; end; end; procedure RegisterModule; -begin - with AddModule do + + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - Website := 'MangaLife'; - RootURL := 'http://manga.life'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; end; + +begin + AddWebsiteModule('MangaLife', 'http://manga.life'); + AddWebsiteModule('MangaSee', 'http://mangasee.co'); end; initialization diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a2aa71c8c..aedd2a5b2 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -292,13 +292,12 @@ interface XXCOMICSMT_ID = 59; XXCOMICS3D_ID = 60; PORNXXXCOMICS_ID = 61; - MANGASEE_ID = 62; - MANGAKU_ID = 63; - MANGAAT_ID = 64; - READMANGATODAY_ID = 65; - DYNASTYSCANS_ID = 66; + MANGAKU_ID = 62; + MANGAAT_ID = 63; + READMANGATODAY_ID = 64; + DYNASTYSCANS_ID = 65; - WebsiteRoots: array [0..66] of array [0..1] of String = ( + WebsiteRoots: array [0..65] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -361,7 +360,6 @@ interface ('XXComicsMT', 'http://milftoon.xxcomics.net'), ('XXComics3D', 'http://3dincest.xxcomics.net'), ('PornXXXComics', 'http://pornxxxcomics.com'), - ('MangaSee', 'http://mangasee.co'), ('MangaKu', 'http://mangaku.web.id'), ('MangaAt', 'http://www.mangaat.com'), ('ReadMangaToday', 'http://www.readmanga.today'), diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 871fa8a6c..08bc45d93 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -815,8 +815,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/PornComix/directory_page_number.inc} - {$I includes/MangaSee/directory_page_number.inc} - {$I includes/MangaAt/directory_page_number.inc} {$I includes/ReadMangaToday/directory_page_number.inc} @@ -929,9 +927,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St (WebsiteID = PORNXXXCOMICS_ID) then Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(website)) else - if WebsiteID = MANGASEE_ID then - Result := GetMangaSeeDirectoryPageNumber - else if WebsiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber else @@ -1054,8 +1049,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/PornComix/names_and_links.inc} - {$I includes/MangaSee/names_and_links.inc} - {$I includes/MangaKu/names_and_links.inc} {$I includes/MangaAt/names_and_links.inc} @@ -1229,9 +1222,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; (WebsiteID = PORNXXXCOMICS_ID) then Result := PornComixGetNamesAndLinks(GetMangaSiteID(website)) else - if WebsiteID = MANGASEE_ID then - Result := MangaSeeGetNamesAndLinks - else if WebsiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks else @@ -1359,8 +1349,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/PornComix/manga_information.inc} - {$I includes/MangaSee/manga_information.inc} - {$I includes/MangaKu/manga_information.inc} {$I includes/MangaAt/manga_information.inc} @@ -1545,9 +1533,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco (WebsiteID = PORNXXXCOMICS_ID) then Result := GetPornComixInfoFromURL(GetMangaSiteID(website)) else - if WebsiteID = MANGASEE_ID then - Result := GetMangaSeeInfoFromURL - else if WebsiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 7325a4092..aabecdeba 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -452,8 +452,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/PornComix/chapter_page_number.inc} - {$I includes/MangaSee/chapter_page_number.inc} - {$I includes/MangaKu/chapter_page_number.inc} {$I includes/MangaAt/chapter_page_number.inc} @@ -581,9 +579,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; (Task.Container.MangaSiteID = PORNXXXCOMICS_ID) then Result := GetPornComixPageNumber(Task.Container.MangaSiteID) else - if Task.Container.MangaSiteID = MANGASEE_ID then - Result := GetMangaSeePageNumber - else if Task.Container.MangaSiteID = MANGAKU_ID then Result := GetMangaKuPageNumber else From 9387d25a381d4e5ed8d511e776d8e464f659e523 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 4 Jul 2016 02:07:25 +0800 Subject: [PATCH 1300/2794] Bump version 0.9.72.0 --- baseunits/modules/FoOlSlide.pas | 1 - changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 11ec80d42..117fb18eb 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -126,7 +126,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - netOK: Boolean; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); diff --git a/changelog.txt b/changelog.txt index ff91e15ab..641f9dd7e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.72.0 (04-07-2016) +[*] Fixed CF +[+] Added custom color options for list, Options > Misc +[*] MangaSee, MangaLife: rewrite all code +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.71.0...0.9.72.0 + 0.9.71.0 (01-07-2016) [*] Tumangaonline: show all available chapter with scanlation name, fixed download [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1e12487a0..ff8d7254e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="71"/> + <RevisionNr Value="72"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 84ac1d43e..6bc0c1dda 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.71.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.71.0/fmd_0.9.71.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.71.0/fmd_0.9.71.0_Win64.7z +VERSION=0.9.72.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.72.0/fmd_0.9.72.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.72.0/fmd_0.9.72.0_Win64.7z From 20780523eaf101beffe332e3dd047dbd3ce0f240 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 5 Jul 2016 07:17:15 +0800 Subject: [PATCH 1301/2794] favoritemanager, immedietly update current chapters count after get manga info --- baseunits/uFavoritesManager.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 98c731476..721d434a1 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -224,6 +224,8 @@ procedure TFavoriteThread.Execute; // check for new chapters if (not Terminated) and Assigned(NewMangaInfo) then begin + // update current chapters count immedietly + FavoriteInfo.CurrentChapter := IntToStr(NewMangaInfo.chapterLinks.Count); if NewMangaInfo.chapterLinks.Count > 0 then try DLChapters := TStringList.Create; @@ -731,7 +733,6 @@ procedure TFavoriteManager.ShowResult; Status := STATUS_STOP; end; end; - FavoriteInfo.currentChapter := IntToStr(NewMangaInfoChaptersPos.Count); // add to downloaded chapter list FavoriteInfo.downloadedChapterList += SetParams(NewMangaInfo.chapterLinks); // add to downloaded chapter list in downloadmanager From dc587a11e1b644e332075eef81b59ba933c9e095 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 5 Jul 2016 07:40:28 +0800 Subject: [PATCH 1302/2794] added favorites custom color for empty chapters closed #316 --- baseunits/FMDOptions.pas | 1 + mangadownloader/forms/frmCustomColor.pas | 2 ++ mangadownloader/forms/frmMain.pas | 22 +++++++++++++--------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 765c44aa0..29f2e75d2 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -137,6 +137,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) CL_FVChecking: TColor = $80EBFE; CL_FVNewChapterFound: TColor = $FDC594; CL_FVCompletedManga: TColor = $B8FFB8; + CL_FVEmptyChapters: TColor = $CCDDFF; //chapterlist color CL_CHDownloaded: TColor = $B8FFB8; diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 9989974fc..3db403d21 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -177,6 +177,7 @@ procedure DoInit; Add('CheckingColor', CL_FVChecking); Add('NewChapterFoundColor', CL_FVNewChapterFound); Add('CompletedSeriesColor', CL_FVCompletedManga); + Add('EmptyChapters', CL_FVEmptyChapters); end; ChapterListColor := TColorItems.Create; @@ -248,6 +249,7 @@ procedure ApplyToFMDOptions; CL_FVChecking := FavoriteListColors[1]; CL_FVNewChapterFound := FavoriteListColors[2]; CL_FVCompletedManga := FavoriteListColors[3]; + CL_FVEmptyChapters := FavoriteListColors[4]; //chapterlist CL_CHDownloaded := ChapterListColor[0]; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6131bf9d8..953ae27a3 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3560,17 +3560,21 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; if Trim(FavoriteInfo.Link) = '' then Brush.Color := CL_FVBrokenFavorite else - if Status = STATUS_CHECKING then - Brush.Color := CL_FVChecking - else - if (Status = STATUS_CHECKED) and - Assigned(NewMangaInfo) then begin - if NewMangaInfoChaptersPos.Count > 0 then - Brush.Color := CL_FVNewChapterFound + if FavoriteInfo.CurrentChapter = '0' then + Brush.Color := CL_FVEmptyChapters; + if Status = STATUS_CHECKING then + Brush.Color := CL_FVChecking else - if NewMangaInfo.status = MangaInfo_StatusCompleted then - Brush.Color := CL_FVCompletedManga; + if (Status = STATUS_CHECKED) and + Assigned(NewMangaInfo) then + begin + if NewMangaInfoChaptersPos.Count > 0 then + Brush.Color := CL_FVNewChapterFound + else + if NewMangaInfo.status = MangaInfo_StatusCompleted then + Brush.Color := CL_FVCompletedManga; + end; end; if Brush.Color <> clNone then FillRect(CellRect); From 785c9d5dcfb6317f2758b909e9c7f878a568886e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 5 Jul 2016 11:48:26 +0800 Subject: [PATCH 1303/2794] added custom color for odd, even and sorted column --- baseunits/FMDOptions.pas | 3 + mangadownloader/forms/frmCustomColor.lfm | 16 ++- mangadownloader/forms/frmCustomColor.pas | 136 +++++++++++++++++------ 3 files changed, 116 insertions(+), 39 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 29f2e75d2..10030e367 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -127,6 +127,9 @@ TIniFileRun = class(IniFiles.TMemIniFile) CL_BSNormalText: TColor = clWindowText; CL_BSFocusedSelectionText: TColor = clHighlightText; CL_BSUnfocesedSelectionText: TColor = clWindowText; + CL_BSOdd: TColor = clBtnFace; + CL_BSEven: TColor = clWindow; + CL_BSSortedColumn: TColor = $CAFFFF; //mangalist color CL_MNNewManga: TColor = $FDC594; diff --git a/mangadownloader/forms/frmCustomColor.lfm b/mangadownloader/forms/frmCustomColor.lfm index e6b0e6fa7..06034e634 100644 --- a/mangadownloader/forms/frmCustomColor.lfm +++ b/mangadownloader/forms/frmCustomColor.lfm @@ -20,7 +20,7 @@ object CustomColorForm: TCustomColorForm Anchors = [akTop, akRight] ItemHeight = 16 OnChange = CBColorsChange - TabOrder = 0 + TabOrder = 1 end object btColors: TColorButton AnchorSideLeft.Control = CBColors @@ -48,7 +48,7 @@ object CustomColorForm: TCustomColorForm Align = alLeft Anchors = [akTop, akLeft, akRight, akBottom] TabIndex = 0 - TabOrder = 1 + TabOrder = 0 object tsBasicList: TTabSheet Caption = 'Basic list' ClientHeight = 324 @@ -73,6 +73,7 @@ object CustomColorForm: TCustomColorForm TextMargin = 0 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] + OnBeforeCellPaint = VTBasicListBeforeCellPaint OnDrawText = VTBasicListDrawText OnFocusChanged = VTBasicListFocusChanged OnGetText = VTBasicListGetText @@ -103,6 +104,7 @@ object CustomColorForm: TCustomColorForm TextMargin = 0 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] + OnBeforeCellPaint = VTBasicListBeforeCellPaint OnDrawText = VTBasicListDrawText OnFocusChanged = VTBasicListFocusChanged OnGetText = VTBasicListGetText @@ -133,6 +135,7 @@ object CustomColorForm: TCustomColorForm TextMargin = 0 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] + OnBeforeCellPaint = VTBasicListBeforeCellPaint OnDrawText = VTBasicListDrawText OnFocusChanged = VTBasicListFocusChanged OnGetText = VTBasicListGetText @@ -141,13 +144,13 @@ object CustomColorForm: TCustomColorForm end object tsChapterList: TTabSheet Caption = 'Chapter list' - ClientHeight = 308 - ClientWidth = 343 + ClientHeight = 324 + ClientWidth = 351 object VTChapterList: TVirtualStringTree Left = 0 - Height = 308 + Height = 324 Top = 0 - Width = 343 + Width = 351 Align = alClient Color = clWindow Colors.DropTargetBorderColor = clHotLight @@ -163,6 +166,7 @@ object CustomColorForm: TCustomColorForm TextMargin = 0 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] + OnBeforeCellPaint = VTBasicListBeforeCellPaint OnDrawText = VTBasicListDrawText OnFocusChanged = VTBasicListFocusChanged OnGetText = VTBasicListGetText diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 3db403d21..afd172b64 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, fgl, Forms, - Graphics, Dialogs, ColorBox, ComCtrls, VirtualTrees, FMDOptions, IniFiles; + Graphics, Dialogs, ColorBox, ComCtrls, VirtualTrees, VTGraphics, FMDOptions, IniFiles; type TColorItem = record @@ -59,6 +59,9 @@ TCustomColorForm = class(TForm) procedure btColorsColorChanged(Sender: TObject); procedure CBColorsChange(Sender: TObject); procedure FormCreate(Sender: TObject); + procedure VTBasicListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; + CellRect: TRect; var ContentRect: TRect); procedure VTBasicListDrawText(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const CellText: String; const CellRect: TRect; var DefaultDraw: Boolean); @@ -77,30 +80,36 @@ TCustomColorForm = class(TForm) { public declarations } end; - TVTList = specialize TFPGList<VirtualTrees.TVirtualStringTree>; + TVTList = record + VT: VirtualTrees.TVirtualStringTree; + PaintText: TVTPaintText; + BeforeCellPaint: TVTBeforeCellPaintEvent; + end; { TVTApplyList } TVTApplyList = class private - FVTList: TVTList; + FCount: Integer; + FVTList: array of TVTList; procedure VTOnPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure ApplyOnPaintText(Index: Integer); + procedure VTOnBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; + Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure InstallCustomColors(Index: Integer); function GetItems(Index: Integer): VirtualTrees.TVirtualStringTree; procedure SetItems(Index: Integer; AValue: VirtualTrees.TVirtualStringTree); public constructor Create; destructor Destroy; override; + function IndexOf(const AVT: VirtualTrees.TVirtualStringTree): Integer; procedure Add(const AVT: VirtualTrees.TVirtualStringTree); - procedure Remove(const AVT: VirtualTrees.TVirtualStringTree); - function Count: Integer; property Items[Index: Integer]: VirtualTrees.TVirtualStringTree read GetItems write SetItems; default; + property Count: Integer read FCount; end; procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); -procedure RemoveVT(const AVT: VirtualTrees.TVirtualStringTree); procedure Apply; procedure LoadFromIniFile(const IniFile: TIniFile); procedure SaveToIniFile(const IniFile: TIniFile); @@ -161,6 +170,9 @@ procedure DoInit; Add('NormalTextColor', clWindowText); Add('FocusedSelectionTextColor', clHighlightText); Add('UnfocusedSelectionTextColor', clWindowText); + Add('OddColor', CL_BSOdd); + Add('EvenColor', CL_BSEven); + Add('SortedColumnColor', CL_BSSortedColumn); end; MangaListColors := TColorItems.Create; @@ -228,17 +240,15 @@ procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); VTApplyList.Add(AVT); end; -procedure RemoveVT(const AVT: VirtualTrees.TVirtualStringTree); -begin - VTApplyList.Remove(AVT); -end; - procedure ApplyToFMDOptions; begin //basiclist CL_BSNormalText := BasicListColors[16]; CL_BSFocusedSelectionText := BasicListColors[17]; CL_BSUnfocesedSelectionText := BasicListColors[18]; + CL_BSOdd := BasicListColors[19]; + CL_BSEven := BasicListColors[20]; + CL_BSSortedColumn := BasicListColors[21]; //mangalist CL_MNNewManga := MangaListColors[0]; @@ -273,11 +283,13 @@ procedure LoadFromIniFile(const IniFile: TIniFile); begin //basiclist for i := 0 to BasicListColors.Count - 1 do - BasicListColors[i] := StringToColor(ReadString('BasicListColors', BasicListColors.N[i], ColorToString(BasicListColors[i]))); + BasicListColors[i] := StringToColor(ReadString('BasicListColors', BasicListColors.N[i], + ColorToString(BasicListColors[i]))); //mangalist for i := 0 to MangaListColors.Count - 1 do - MangaListColors[i] := StringToColor(ReadString('MangaListColors', MangaListColors.N[i], ColorToString(MangaListColors[i]))); + MangaListColors[i] := StringToColor(ReadString('MangaListColors', MangaListColors.N[i], + ColorToString(MangaListColors[i]))); //favoritelist for i := 0 to FavoriteListColors.Count - 1 do @@ -286,7 +298,8 @@ procedure LoadFromIniFile(const IniFile: TIniFile); //chapterlist for i := 0 to ChapterListColor.Count - 1 do - ChapterListColor[i] := StringToColor(ReadString('ChapterListColor', ChapterListColor.N[i], ColorToString(ChapterListColor[i]))); + ChapterListColor[i] := StringToColor(ReadString('ChapterListColor', ChapterListColor.N[i], + ColorToString(ChapterListColor[i]))); ApplyToFMDOptions; end; @@ -336,50 +349,93 @@ procedure TVTApplyList.VTOnPaintText(Sender: TBaseVirtualTree; else Color := CL_BSNormalText; end; + + if Assigned(FVTList[Sender.Tag].PaintText) then + FVTList[Sender.Tag].PaintText(Sender, TargetCanvas, Node, Column, TextType); end; -procedure TVTApplyList.ApplyOnPaintText(Index: Integer); +procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin - if not Assigned(FVTList[Index].OnPaintText) then - FVTList[Index].OnPaintText := @VTOnPaintText; + with VirtualTrees.TVirtualStringTree(Sender), TargetCanvas do + begin + //if (Header.Columns.Count <> 0) and (Header.SortColumn = Column) then + // Brush.Color := CL_BSSortedColumn + //else + if odd(Node^.Index) then + Brush.Color := CL_BSOdd + else + Brush.Color := CL_BSEven; + FillRect(CellRect); + + if Assigned(FVTList[Sender.Tag].BeforeCellPaint) then + FVTList[Sender.Tag].BeforeCellPaint(Sender, TargetCanvas, Node, Column, CellPaintMode, + CellRect, ContentRect); + + if (Header.Columns.Count <> 0) and (Header.SortColumn = Column) then + VTGraphics.AlphaBlend(0, TargetCanvas.Handle, CellRect, Point(0, 0), + bmConstantAlphaAndColor, 128, ColorToRGB(CL_BSSortedColumn)); + end; +end; + +procedure TVTApplyList.InstallCustomColors(Index: Integer); +begin + with FVTList[Index], VT do + begin + // save original event + PaintText := OnPaintText; + BeforeCellPaint := OnBeforeCellPaint; + // set custom event + OnPaintText := @VTOnPaintText; + OnBeforeCellPaint := @VTOnBeforeCellPaint; + + // set addition option + LineStyle := lsSolid; + end; end; function TVTApplyList.GetItems(Index: Integer): VirtualTrees.TVirtualStringTree; begin - Result := FVTList[Index]; + Result := FVTList[Index].VT; end; procedure TVTApplyList.SetItems(Index: Integer; AValue: VirtualTrees.TVirtualStringTree); begin - if FVTList[Index] <> AValue then - FVTList[Index] := AValue; + if FVTList[Index].VT <> AValue then + FVTList[Index].VT := AValue; end; constructor TVTApplyList.Create; begin - FVTList := TVTList.Create; + FCount := 0; end; destructor TVTApplyList.Destroy; begin - FVTList.Free; + SetLength(FVTList, 0); inherited Destroy; end; -procedure TVTApplyList.Add(const AVT: VirtualTrees.TVirtualStringTree); -begin - if FVTList.IndexOf(AVT) = -1 then - ApplyOnPaintText(FVTList.Add(AVT)); -end; - -procedure TVTApplyList.Remove(const AVT: VirtualTrees.TVirtualStringTree); +function TVTApplyList.IndexOf(const AVT: VirtualTrees.TVirtualStringTree): Integer; begin - + Result := 0; + while (Result < FCount) and (FVTList[Result].VT <> AVT) do + Inc(Result); + if Result = FCount then + Result := -1; end; -function TVTApplyList.Count: Integer; +procedure TVTApplyList.Add(const AVT: VirtualTrees.TVirtualStringTree); begin - Result := FVTList.Count; + if IndexOf(AVT) = -1 then + begin + SetLength(FVTList, FCount + 1); + FVTList[FCount].VT := AVT; + AVT.Tag := FCount; + InstallCustomColors(FCount); + Inc(FCount); + end; end; { TVirtualStringTree } @@ -450,6 +506,20 @@ procedure TCustomColorForm.FormCreate(Sender: TObject); VTChapterList.CI := ChapterListColor; end; +procedure TCustomColorForm.VTBasicListBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +begin + with VirtualTrees.TVirtualStringTree(Sender), TargetCanvas do + begin + if odd(Node^.Index) then + Brush.Color := BasicListColors[19] + else + Brush.Color := BasicListColors[20]; + FillRect(CellRect); + end; +end; + procedure TCustomColorForm.CBColorsChange(Sender: TObject); begin btColors.ButtonColor := CBColors.Selected; From 0634fe7bd4a1d73c52510ffcfe8a813c2dd67f36 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 5 Jul 2016 13:55:53 +0800 Subject: [PATCH 1304/2794] use simple drawing for sorted column --- baseunits/FMDOptions.pas | 2 +- mangadownloader/forms/frmCustomColor.pas | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 10030e367..99842298c 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -129,7 +129,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) CL_BSUnfocesedSelectionText: TColor = clWindowText; CL_BSOdd: TColor = clBtnFace; CL_BSEven: TColor = clWindow; - CL_BSSortedColumn: TColor = $CAFFFF; + CL_BSSortedColumn: TColor = $EAFFFF; //mangalist color CL_MNNewManga: TColor = $FDC594; diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index afd172b64..062aa5b7b 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -5,8 +5,8 @@ interface uses - Classes, SysUtils, fgl, Forms, - Graphics, Dialogs, ColorBox, ComCtrls, VirtualTrees, VTGraphics, FMDOptions, IniFiles; + Classes, SysUtils, fgl, Forms, Graphics, Dialogs, ColorBox, ComCtrls, + VirtualTrees, FMDOptions, IniFiles; type TColorItem = record @@ -360,9 +360,9 @@ procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; begin with VirtualTrees.TVirtualStringTree(Sender), TargetCanvas do begin - //if (Header.Columns.Count <> 0) and (Header.SortColumn = Column) then - // Brush.Color := CL_BSSortedColumn - //else + if (Header.Columns.Count <> 0) and (Header.SortColumn = Column) then + Brush.Color := CL_BSSortedColumn + else if odd(Node^.Index) then Brush.Color := CL_BSOdd else @@ -372,10 +372,6 @@ procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; if Assigned(FVTList[Sender.Tag].BeforeCellPaint) then FVTList[Sender.Tag].BeforeCellPaint(Sender, TargetCanvas, Node, Column, CellPaintMode, CellRect, ContentRect); - - if (Header.Columns.Count <> 0) and (Header.SortColumn = Column) then - VTGraphics.AlphaBlend(0, TargetCanvas.Handle, CellRect, Point(0, 0), - bmConstantAlphaAndColor, 128, ColorToRGB(CL_BSSortedColumn)); end; end; From 6069b17f3cde0d35a26cf23fabffbcad9c37f511 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 6 Jul 2016 18:11:35 +0800 Subject: [PATCH 1305/2794] frmmain, beforecellpaint only when cpmpaint --- mangadownloader/forms/frmMain.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 953ae27a3..67ee87ce7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2172,6 +2172,7 @@ procedure TMainForm.clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin + if CellPaintMode <> cpmPaint then Exit; if Node^.Index>=Length(ChapterList) then Exit; if ChapterList[Node^.Index].Downloaded then begin @@ -3554,6 +3555,7 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin + if CellPaintMode <> cpmPaint then Exit; with TargetCanvas, FavoriteManager.Items[Node^.Index] do begin Brush.Color := clNone; @@ -3722,6 +3724,7 @@ procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin + if CellPaintMode <> cpmPaint then Exit; if Node^.Index>=dataProcess.RecordCount then Exit; with TargetCanvas do begin From 3431fdcdb30efdb258b1ebc75e45730fae4d3295 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 6 Jul 2016 18:35:39 +0800 Subject: [PATCH 1306/2794] paint flat blended color for sortedcolumn --- baseunits/FMDOptions.pas | 2 +- mangadownloader/forms/frmCustomColor.lfm | 6 +-- mangadownloader/forms/frmCustomColor.pas | 59 +++++++++++++++++++----- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 99842298c..58da15052 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -129,7 +129,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) CL_BSUnfocesedSelectionText: TColor = clWindowText; CL_BSOdd: TColor = clBtnFace; CL_BSEven: TColor = clWindow; - CL_BSSortedColumn: TColor = $EAFFFF; + CL_BSSortedColumn: TColor = $F8E6D6; //mangalist color CL_MNNewManga: TColor = $FDC594; diff --git a/mangadownloader/forms/frmCustomColor.lfm b/mangadownloader/forms/frmCustomColor.lfm index 06034e634..19adba964 100644 --- a/mangadownloader/forms/frmCustomColor.lfm +++ b/mangadownloader/forms/frmCustomColor.lfm @@ -14,9 +14,9 @@ object CustomColorForm: TCustomColorForm AnchorSideRight.Control = btColors Left = 363 Height = 22 - Top = 32 + Top = 22 Width = 136 - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames] + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] Anchors = [akTop, akRight] ItemHeight = 16 OnChange = CBColorsChange @@ -30,7 +30,7 @@ object CustomColorForm: TCustomColorForm AnchorSideBottom.Side = asrBottom Left = 503 Height = 22 - Top = 32 + Top = 22 Width = 24 Anchors = [akTop, akRight, akBottom] BorderWidth = 2 diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 062aa5b7b..4e25ed6fe 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, fgl, Forms, Graphics, Dialogs, ColorBox, ComCtrls, + Classes, SysUtils, Forms, Graphics, Dialogs, ColorBox, ComCtrls, VirtualTrees, FMDOptions, IniFiles; type @@ -92,11 +92,13 @@ TVTApplyList = class private FCount: Integer; FVTList: array of TVTList; + private procedure VTOnPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); procedure VTOnBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + private procedure InstallCustomColors(Index: Integer); function GetItems(Index: Integer): VirtualTrees.TVirtualStringTree; procedure SetItems(Index: Integer; AValue: VirtualTrees.TVirtualStringTree); @@ -354,24 +356,54 @@ procedure TVTApplyList.VTOnPaintText(Sender: TBaseVirtualTree; FVTList[Sender.Tag].PaintText(Sender, TargetCanvas, Node, Column, TextType); end; +function BlendColor(FG, BG: TColor; T: Byte): TColor; + function MixByte(B1, B2: Byte): Byte; + begin + Result := Byte(T * (B1 - B2) shr 8 + B2); + end; + +var + C1, C2: LongInt; +begin + C1 := ColorToRGB(FG); + C2 := ColorToRGB(BG); + Result := (MixByte(Byte(C1 shr 16), Byte(C2 shr 16)) shl 16) + + (MixByte(Byte(C1 shr 8), Byte(C2 shr 8)) shl 8) + + MixByte(Byte(C1), Byte(C2)); +end; + procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + isSortedColumn: Boolean; begin with VirtualTrees.TVirtualStringTree(Sender), TargetCanvas do begin - if (Header.Columns.Count <> 0) and (Header.SortColumn = Column) then - Brush.Color := CL_BSSortedColumn - else - if odd(Node^.Index) then - Brush.Color := CL_BSOdd - else - Brush.Color := CL_BSEven; - FillRect(CellRect); + if CellPaintMode = cpmPaint then + begin + if odd(Node^.Index) then + Brush.Color := CL_BSOdd + else + Brush.Color := CL_BSEven; + isSortedColumn := (Header.Columns.Count <> 0) and (Header.SortColumn = Column) + and (CL_BSSortedColumn <> clNone); + if (not isSortedColumn) and (Brush.Color <> clNone) then + FillRect(CellRect); + end; if Assigned(FVTList[Sender.Tag].BeforeCellPaint) then FVTList[Sender.Tag].BeforeCellPaint(Sender, TargetCanvas, Node, Column, CellPaintMode, CellRect, ContentRect); + + if isSortedColumn and (CellPaintMode = cpmPaint) then + begin + Brush.Color := BlendColor(CL_BSSortedColumn, Brush.Color, SelectionBlendFactor); + FillRect(CellRect); + Pen.Color := CL_BSSortedColumn; + Line(CellRect.Left, CellRect.Top, CellRect.Left, CellRect.Bottom); + Line(CellRect.Right - 1, CellRect.Top, CellRect.Right - 1, CellRect.Bottom); + end; end; end; @@ -379,15 +411,18 @@ procedure TVTApplyList.InstallCustomColors(Index: Integer); begin with FVTList[Index], VT do begin + // set addition option + LineStyle := lsSolid; + if Color = clDefault then + Color := clWindow; + // save original event PaintText := OnPaintText; BeforeCellPaint := OnBeforeCellPaint; + // set custom event OnPaintText := @VTOnPaintText; OnBeforeCellPaint := @VTOnBeforeCellPaint; - - // set addition option - LineStyle := lsSolid; end; end; From 54264e4e782d9cf1dc7fc0f6026c135ac22288a7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 6 Jul 2016 19:35:43 +0800 Subject: [PATCH 1307/2794] Bump version 0.9.73.0 --- changelog.txt | 6 +++++- mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 641f9dd7e..3c18827b5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,11 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.73.0 (06-07-2016) +[+] Added custom color for favorite with empty chapters +[*] Various changes +Full changes: https://github.com/riderkick/FMD/compare/0.9.72.0...0.9.73.0 + 0.9.72.0 (04-07-2016) [*] Fixed CF [+] Added custom color options for list, Options > Misc [*] MangaSee, MangaLife: rewrite all code -[*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.71.0...0.9.72.0 0.9.71.0 (01-07-2016) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ff8d7254e..9e40ce5c4 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="72"/> + <RevisionNr Value="73"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 6bc0c1dda..fdcf86052 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.72.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.72.0/fmd_0.9.72.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.72.0/fmd_0.9.72.0_Win64.7z +VERSION=0.9.73.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.73.0/fmd_0.9.73.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.73.0/fmd_0.9.73.0_Win64.7z From 468a1a0b793fb6cdb7faa167d3200d8f132c5f59 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Jul 2016 05:12:56 +0800 Subject: [PATCH 1308/2794] fixed text color for node without full row select always painted with focused color --- mangadownloader/forms/frmCustomColor.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 4e25ed6fe..320ca16e3 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -339,11 +339,12 @@ procedure TVTApplyList.VTOnPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); begin - with TargetCanvas.Font do + with VirtualTrees.TVirtualStringTree(Sender), TargetCanvas.Font do begin - if Sender.Selected[Node] then + if Selected[Node] and + ((toFullRowSelect in TreeOptions.SelectionOptions) or (FocusedColumn = Column)) then begin - if Sender.Focused then + if Focused then Color := CL_BSFocusedSelectionText else Color := CL_BSUnfocesedSelectionText; From 2a8085d38fb5e7312e2224ecd425b0a7d0b849a8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 7 Jul 2016 09:34:29 +0800 Subject: [PATCH 1309/2794] added enable/disable task feature, disabled task can't be resumed unless enabled by user. resume/all will skip this task. --- baseunits/uDownloadsManager.pas | 72 ++++++- mangadownloader/forms/frmMain.lfm | 96 ++++++++- mangadownloader/forms/frmMain.pas | 281 ++++++++++++++----------- mangadownloader/languages/fmd.en.po | 12 ++ mangadownloader/languages/fmd.id_ID.po | 12 ++ mangadownloader/languages/fmd.po | 12 ++ 6 files changed, 342 insertions(+), 143 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index aabecdeba..97ea9d072 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -107,6 +107,8 @@ TTaskContainer = class private FWebsite: String; FStatus: TDownloadStatusType; + FEnabled: Boolean; + procedure SetEnabled(AValue: Boolean); procedure SetStatus(AValue: TDownloadStatusType); procedure SetWebsite(AValue: String); public @@ -149,6 +151,7 @@ TTaskContainer = class public property Website: String read FWebsite write SetWebsite; property Status: TDownloadStatusType read FStatus write SetStatus; + property Enabled: Boolean read FEnabled write SetEnabled; end; TTaskContainers = TFPGList<TTaskContainer>; @@ -160,6 +163,7 @@ TDownloadManager = class FSortDirection: Boolean; FSortColumn: Integer; DownloadManagerFile: TIniFileRun; + function GetTask(const TaskId: Integer): TTaskContainer; protected function GetTaskCount: Integer; inline; function GetTransferRate: Integer; @@ -176,6 +180,8 @@ TDownloadManager = class // status count CS_StatusCount: TRTLCriticalSection; StatusCount: array [TDownloadStatusType] of Integer; + // disabled count + DisabledCount: Integer; compress, retryConnect, // max. active tasks @@ -225,6 +231,9 @@ TDownloadManager = class procedure RemoveAllFinishedTasks; // check status of task function TaskStatusPresent(Stats: TDownloadStatusTypes): Boolean; + // enable task + procedure EnableTask(const TaskId: Integer); + procedure DisableTask(const TaskId: Integer); // Sort procedure Sort(const AColumn: Integer); @@ -232,6 +241,7 @@ TDownloadManager = class property SortDirection: Boolean read FSortDirection write FSortDirection; property SortColumn: Integer read FSortColumn write FSortColumn; property TransferRate: Integer read GetTransferRate; + property Task[const TaskId: Integer]: TTaskContainer read GetTask; default; end; resourcestring @@ -244,6 +254,7 @@ TDownloadManager = class RS_Waiting = 'Waiting...'; RS_Compressing = 'Compressing...'; RS_Failed = 'Failed'; + RS_Disabled = 'Disabled'; implementation @@ -1439,6 +1450,19 @@ procedure TTaskContainer.SetStatus(AValue: TDownloadStatusType); FStatus := AValue; end; +procedure TTaskContainer.SetEnabled(AValue: Boolean); +begin + if FEnabled = AValue then Exit; + FEnabled := AValue; + if Assigned(Manager) then + begin + if Enabled then + Dec(Manager.DisabledCount) + else + Inc(Manager.DisabledCount); + end; +end; + constructor TTaskContainer.Create; begin inherited Create; @@ -1457,6 +1481,7 @@ constructor TTaskContainer.Create; CurrentDownloadChapterPtr := 0; CustomFileName := OptionFilenameCustomRename; FStatus := STATUS_NONE; + FEnabled := True; end; destructor TTaskContainer.Destroy; @@ -1486,6 +1511,11 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); { TDownloadManager } +function TDownloadManager.GetTask(const TaskId: Integer): TTaskContainer; +begin + Result := Items[TaskId]; +end; + function TDownloadManager.GetTaskCount: Integer; begin Result := Items.Count; @@ -1577,6 +1607,7 @@ constructor TDownloadManager.Create; InitCriticalSection(CS_StatusCount); for ds := Low(StatusCount) to High(StatusCount) do StatusCount[ds] := 0; + DisabledCount := 0; end; destructor TDownloadManager.Destroy; @@ -1630,6 +1661,7 @@ procedure TDownloadManager.Restore; DownloadInfo.SaveTo := CorrectPathSys(ReadString(tid, 'SaveTo', 'NULL')); DownloadInfo.Status := ReadString(tid, 'Status', 'NULL'); DownloadInfo.Progress := ReadString(tid, 'Progress', 'NULL'); + Enabled := ReadBool(tid, 'Enabled', True); if Pos('/', DownloadInfo.Progress) > 0 then begin DownCounter := StrToIntDef(ExtractWord(1, DownloadInfo.Progress, ['/']), 0); @@ -1721,6 +1753,7 @@ procedure TDownloadManager.Backup; WriteString(tid, 'SaveTo', DownloadInfo.SaveTo); WriteString(tid, 'Status', DownloadInfo.Status); WriteString(tid, 'Progress', DownloadInfo.Progress); + WriteBool(tid, 'Enabled', Enabled); WriteString(tid, 'DateTime', FloatToStr(DownloadInfo.dateTime, FMDFormatSettings)); WriteString(tid, 'CustomFileName', CustomFileName); WriteString(tid, 'ChapterLinks', SetParams(ChapterLinks)); @@ -1835,6 +1868,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); procedure TDownloadManager.SetTaskActive(const taskID: Integer); begin + if not Items[taskID].Enabled then Exit; with Items[taskID] do if not ThreadState then begin @@ -1873,10 +1907,13 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; procedure TDownloadManager.ActiveTask(const taskID: Integer); begin - with Items[taskID] do begin - if Status = STATUS_FINISH then Exit; - if not ThreadState then begin - if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then begin + if not Items[taskID].Enabled then Exit; + if Items[taskID].Status = STATUS_FINISH then Exit; + with Items[taskID] do + if not ThreadState then + begin + if not (Status in [STATUS_DOWNLOAD, STATUS_PREPARE]) then + begin Status := STATUS_DOWNLOAD; DownloadInfo.Status := RS_Downloading; end; @@ -1886,7 +1923,6 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); ItemsActiveTask.Add(Task.Container); Task.Start; end; - end; end; procedure TDownloadManager.StopTask(const taskID: Integer; @@ -1918,7 +1954,7 @@ procedure TDownloadManager.StartAllTasks; begin for i := 0 to Items.Count - 1 do with Items[i] do - if (Status <> STATUS_FINISH) and (not ThreadState) then + if Enabled and (Status <> STATUS_FINISH) and (not ThreadState) then begin Status := STATUS_WAIT; DownloadInfo.Status := RS_Waiting; @@ -2013,6 +2049,30 @@ function TDownloadManager.TaskStatusPresent(Stats: TDownloadStatusTypes): Boolea end; end; +procedure TDownloadManager.EnableTask(const TaskId: Integer); +begin + If not Items[TaskId].Enabled then + Items[TaskId].Enabled := True; +end; + +procedure TDownloadManager.DisableTask(const TaskId: Integer); +begin + with Items[TaskId] do + begin + if ThreadState then + StopTask(TaskId, False); + if Enabled then + begin + if Status = STATUS_WAIT then + begin + Status := STATUS_STOP; + DownloadInfo.Status := RS_Stopped; + end; + Enabled := False; + end; + end; +end; + function CompareTaskContainer(const Item1, Item2: TTaskContainer): Integer; function GetStr(ARow: TTaskContainer): String; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 55637287c..9f9611119 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -36,13 +36,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsFavorites + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 3 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -123,6 +123,7 @@ object MainForm: TMainForm OnDrawText = vtDownloadDrawText OnFocusChanged = vtDownloadFocusChanged OnGetText = vtDownloadGetText + OnPaintText = vtDownloadPaintText OnGetImageIndex = vtDownloadGetImageIndex OnGetHint = vtDownloadGetHint OnHeaderClick = vtDownloadHeaderClick @@ -803,18 +804,18 @@ object MainForm: TMainForm end object tsFilter: TTabSheet Caption = 'Filter' - ClientHeight = 443 + ClientHeight = 492 ClientWidth = 558 object sbFilter: TScrollBox Left = 0 - Height = 443 + Height = 492 Top = 0 Width = 558 HorzScrollBar.Page = 488 VertScrollBar.Page = 416 Align = alClient BorderStyle = bsNone - ClientHeight = 443 + ClientHeight = 492 ClientWidth = 558 TabOrder = 0 object pnCustomGenre: TPanel @@ -2268,7 +2269,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 + ClientHeight = 387 ClientWidth = 531 object cbOptionShowDownloadToolbar: TCheckBox Left = 4 @@ -4070,7 +4071,7 @@ object MainForm: TMainForm ImageIndex = 4 object tvDownloadFilter: TTreeView Left = 4 - Height = 501 + Height = 482 Top = 4 Width = 179 Align = alClient @@ -4199,6 +4200,15 @@ object MainForm: TMainForm ImageIndex = 12 OnClick = miDownloadResumeClick end + object miDownloadEnable: TMenuItem + Caption = 'Enable' + OnClick = miDownloadEnableClick + end + object miDownloadDisable: TMenuItem + Caption = 'Disable' + ShowAlwaysCheckable = True + OnClick = miDownloadDisableClick + end object miDownloadDelete: TMenuItem Caption = 'Delete' Enabled = False @@ -4981,7 +4991,7 @@ object MainForm: TMainForm left = 24 top = 136 Bitmap = { - 4C691600000010000000100000004F4F4F005050500052525200535353005454 + 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 530052525200505050004F4F4F004F4F4F0050505000525252075353533D7373 7378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEAEAFFC7C7C7D2727272785353 @@ -5685,14 +5695,46 @@ object MainForm: TMainForm 64FFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFFC5925FFF318613FF2BDF 1AFF1E7700F20000001600000009000000000000002C00000087000000E7702E 00C7702E00C7702E00C7702E00C7702E00C7702E00C7702E00C72D5500E9175F - 00F4124A00C40000002C00000000 + 00F4124A00C40000002C00000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0088888899888888CC8888 + 88CC888888CC888888CC888888CC888888CC888888CC888888CC888888CC8888 + 8899FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00838383CCBCBCBCFFB9B9 + B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFBBBBBBFF8383 + 83CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF007F7F7FCCB5B5B5FFABAB + ABFFABABABFFABABABFFABABABFFABABABFFABABABFFABABABFFB3B3B3FF7F7F + 7FCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00797979CCAFAFAFFFA0A0 + A0FFA0A0A0FFA0A0A0FF9B9B9BFF969696FF919191FF909090FF9F9F9FFF7979 + 79CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00727272CCABABABFF9B9B + 9BFF909090FF848484FF7F7F7FFF7E7E7EFF7E7E7EFF7E7E7EFF8D8D8DFF7272 + 72CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00686868CCA0A0A0FF8181 + 81FF7E7E7EFF7E7E7EFF7E7E7EFF7E7E7EFF7E7E7EFF7E7E7EFF8A8A8AFF6868 + 68CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00606060CC8E8E8EFF7C7C + 7CFF7C7C7CFF7C7C7CFF7C7C7CFF7C7C7CFF7C7C7CFF7C7C7CFF858585FF6060 + 60CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00575757CC888888FF7979 + 79FF797979FF797979FF797979FF797979FF797979FF797979FF808080FF5757 + 57CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00505050CC848484FF7878 + 78FF787878FF787878FF787878FF787878FF787878FF787878FF7D7D7DFF5050 + 50CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004A4A4ACC858585FF7F7F + 7FFF7E7E7EFF7E7E7EFF7D7D7DFF7C7C7CFF7C7C7CFF7C7C7CFF7D7D7DFF4A4A + 4ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF0016161603353535A0454545CC4545 + 45CC454545CC454545CC454545CC454545CC454545CC454545CC454545CC3535 + 35A116161604FFFFFF00FFFFFF00FFFFFF0016161603161616111616161A1616 + 161A1616161A1616161A1616161A1616161A1616161A1616161A1616161A1616 + 161316161604FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 } end object IconDL: TImageList left = 24 top = 184 Bitmap = { - 4C69080000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -5948,7 +5990,39 @@ object MainForm: TMainForm 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 00170000000C00000002FFFFFF00 + 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0088888899888888CC8888 + 88CC888888CC888888CC888888CC888888CC888888CC888888CC888888CC8888 + 8899FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00838383CCBCBCBCFFB9B9 + B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFBBBBBBFF8383 + 83CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF007F7F7FCCB5B5B5FFABAB + ABFFABABABFFABABABFFABABABFFABABABFFABABABFFABABABFFB3B3B3FF7F7F + 7FCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00797979CCAFAFAFFFA0A0 + A0FFA0A0A0FFA0A0A0FF9B9B9BFF969696FF919191FF909090FF9F9F9FFF7979 + 79CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00727272CCABABABFF9B9B + 9BFF909090FF848484FF7F7F7FFF7E7E7EFF7E7E7EFF7E7E7EFF8D8D8DFF7272 + 72CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00686868CCA0A0A0FF8181 + 81FF7E7E7EFF7E7E7EFF7E7E7EFF7E7E7EFF7E7E7EFF7E7E7EFF8A8A8AFF6868 + 68CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00606060CC8E8E8EFF7C7C + 7CFF7C7C7CFF7C7C7CFF7C7C7CFF7C7C7CFF7C7C7CFF7C7C7CFF858585FF6060 + 60CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00575757CC888888FF7979 + 79FF797979FF797979FF797979FF797979FF797979FF797979FF808080FF5757 + 57CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00505050CC848484FF7878 + 78FF787878FF787878FF787878FF787878FF787878FF787878FF7D7D7DFF5050 + 50CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF004A4A4ACC858585FF7F7F + 7FFF7E7E7EFF7E7E7EFF7D7D7DFF7C7C7CFF7C7C7CFF7C7C7CFF7D7D7DFF4A4A + 4ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF0016161603353535A0454545CC4545 + 45CC454545CC454545CC454545CC454545CC454545CC454545CC454545CC3535 + 35A116161604FFFFFF00FFFFFF00FFFFFF0016161603161616111616161A1616 + 161A1616161A1616161A1616161A1616161A1616161A1616161A1616161A1616 + 161316161604FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00 } end object IconMed: TImageList diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 67ee87ce7..f6858ac2e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -74,6 +74,8 @@ TMainForm = class(TForm) lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; MenuItem2: TMenuItem; + miDownloadEnable: TMenuItem; + miDownloadDisable: TMenuItem; miChapterListFilter: TMenuItem; mnFilterGenreAllIndeterminate: TMenuItem; mnFilterGenreAllCheck: TMenuItem; @@ -421,6 +423,8 @@ TMainForm = class(TForm) procedure miAbortSilentThreadClick(Sender: TObject); procedure miChapterListFilterClick(Sender: TObject); procedure miChapterListHideDownloadedClick(Sender: TObject); + procedure miDownloadDisableClick(Sender: TObject); + procedure miDownloadEnableClick(Sender: TObject); procedure miDownloadViewMangaInfoClick(Sender: TObject); procedure miChapterListHighlightClick(Sender: TObject); procedure miDownloadDeleteTaskClick(Sender: TObject); @@ -508,6 +512,8 @@ TMainForm = class(TForm) procedure vtDownloadKeyDown(Sender : TObject; var Key : Word; Shift : TShiftState); procedure vtDownloadKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure vtDownloadPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); procedure vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -1572,6 +1578,35 @@ procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); FilterChapterList(edFilterMangaInfoChapters.Text, miChapterListHideDownloaded.Checked); end; +procedure TMainForm.miDownloadDisableClick(Sender: TObject); +var + Node: PVirtualNode; +begin + if vtDownload.SelectedCount = 0 then Exit; + Node := vtDownload.GetFirstSelected(); + while Assigned(Node) do + begin + DLManager.DisableTask(Node^.Index); + Node := vtDownload.GetNextSelected(Node); + end; + UpdateVtDownload; + DLManager.CheckAndActiveTask(); +end; + +procedure TMainForm.miDownloadEnableClick(Sender: TObject); +var + Node: PVirtualNode; +begin + if vtDownload.SelectedCount = 0 then Exit; + Node := vtDownload.GetFirstSelected(); + while Assigned(Node) do + begin + DLManager.EnableTask(Node^.Index); + Node := vtDownload.GetNextSelected(Node); + end; + UpdateVtDownload; +end; + procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); begin if Assigned(vtDownload.FocusedNode) then @@ -1790,59 +1825,45 @@ procedure TMainForm.LoadAbout; end; procedure TMainForm.GeneratetvDownloadFilterNodes; + + function Add(const ParentNode: TTreeNode; const S: String; + const ImgIdx: Integer = -1): TTreeNode; + begin + if Assigned(ParentNode) then + Result := tvDownloadFilter.Items.AddChild(ParentNode, S) + else + Result := tvDownloadFilter.Items.Add(nil, S); + with Result do + begin + ImageIndex := ImgIdx; + SelectedIndex := ImgIdx; + StateIndex := ImgIdx; + end; + end; + +var + Node: TTreeNode; + begin with tvDownloadFilter do begin Items.Clear; - // root - Items.Add(nil, RS_AllDownloads); - Items[0].ImageIndex := 4; - Items[0].SelectedIndex := 4; - Items[0].StateIndex := 4; - - // childs - Items.AddChild(tvDownloadFilter.Items[0], RS_Finish); - Items[1].ImageIndex := 5; - Items[1].SelectedIndex := 5; - Items[1].StateIndex := 5; - Items.AddChild(tvDownloadFilter.Items[0], RS_InProgress); - Items[2].ImageIndex := 6; - Items[2].SelectedIndex := 6; - Items[2].StateIndex := 6; - Items.AddChild(tvDownloadFilter.Items[0], RS_Stopped); - Items[3].ImageIndex := 7; - Items[3].SelectedIndex := 7; - Items[3].StateIndex := 7; - Items.AddChild(tvDownloadFilter.Items[0], RS_Failed); - Items[4].ImageIndex := 16; - Items[4].SelectedIndex := 16; - Items[4].StateIndex := 16; - - // root - Items.Add(nil, RS_History); - Items[5].ImageIndex := 4; - Items[5].SelectedIndex := 4; - Items[5].StateIndex := 4; - - // childs - Items.AddChild(tvDownloadFilter.Items[5], RS_Today); - Items[6].ImageIndex := 8; - Items[6].SelectedIndex := 8; - Items[6].StateIndex := 8; - Items.AddChild(tvDownloadFilter.Items[5], RS_Yesterday); - Items[7].ImageIndex := 8; - Items[7].SelectedIndex := 8; - Items[7].StateIndex := 8; - Items.AddChild(tvDownloadFilter.Items[5], RS_OneWeek); - Items[8].ImageIndex := 8; - Items[8].SelectedIndex := 8; - Items[8].StateIndex := 8; - Items.AddChild(tvDownloadFilter.Items[5], RS_OneMonth); - Items[9].ImageIndex := 8; - Items[9].SelectedIndex := 8; - Items[9].StateIndex := 8; - - Items[configfile.ReadInteger('general', 'DownloadFilterSelect',0)].Selected := True; + // download + Node := Add(nil, RS_AllDownloads, 4); + Add(Node, RS_Finish, 5); + Add(Node, RS_InProgress, 6); + Add(Node, RS_Stopped, 7); + Add(Node, RS_Failed, 16); + Add(Node, RS_Disabled, 22); + + // history + Node := Add(nil, RS_History, 4); + Add(Node, RS_Today, 8); + Add(Node, RS_Yesterday, 8); + Add(Node, RS_OneWeek, 8); + Add(Node, RS_OneMonth, 8); + + Items[configfile.ReadInteger('general', 'DownloadFilterSelect', 0)].Selected := True; end; end; @@ -2901,51 +2922,44 @@ procedure TMainForm.pcMainChange(Sender: TObject); end; procedure TMainForm.pmDownloadPopup(Sender: TObject); +var + iStop, + iResume, + iFinish, + iEnable, + iDisable: Boolean; - function FinishedTaskPresent: Boolean; - var - i: Integer; - begin - Result := False; - with DLManager do begin - EnterCriticalSection(CS_Task); - try - for i := 0 to Count - 1 do - if Items[i].Status = STATUS_FINISH then - begin - Result := True; - Break; - end; - finally - LeaveCriticalSection(CS_Task); - end; - end; - end; - - function SelectedTaskStatusPresent(Stats: TDownloadStatusTypes): Boolean; + procedure ScanTasks; var - xNode: PVirtualNode; + Node: PVirtualNode; begin - Result := False; - if vtDownload.SelectedCount > 0 then + iStop := False; + iResume := False; + iFinish := False; + iEnable := False; + iDisable := False; + Node := vtDownload.GetFirstSelected(); + while Assigned(Node) do begin - with DLManager do + if DLManager[Node^.Index].Enabled then begin - EnterCriticalSection(CS_Task); - try - xNode := vtDownload.GetFirstSelected; - repeat - if Items[xNode^.Index].Status in Stats then - begin - Result := True; - Break; - end; - xNode := vtDownload.GetNextSelected(xNode); - until xNode = nil; - finally - LeaveCriticalSection(CS_Task); + if not iDisable then + iDisable := True; + case DLManager[Node^.Index].Status of + STATUS_DOWNLOAD, + STATUS_PREPARE, + STATUS_WAIT : if not iStop then iStop := True; + STATUS_STOP, + STATUS_FAILED, + STATUS_PROBLEM : if not iResume then iResume := True; + STATUS_FINISH : if not iFinish then iFinish := True; end; - end; + end + else if not iEnable then + iEnable := True; + if iStop and iResume and iStop and iEnable and iDisable then + Break; + Node := vtDownload.GetNextSelected(Node); end; end; @@ -2958,38 +2972,30 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); miDownloadDelete.Enabled := False; miDownloadDeleteTask.Enabled := False; miDownloadDeleteTaskData.Enabled := False; - miDownloadDeleteCompleted.Enabled := FinishedTaskPresent; - miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; + miDownloadDeleteCompleted.Enabled := False; + miDownloadMergeCompleted.Enabled := False; miDownloadViewMangaInfo.Enabled := False; miDownloadOpenFolder.Enabled := False; miDownloadOpenWith.Enabled := False; + miDownloadEnable.Enabled := False; + miDownloadDisable.Enabled := False; end else - if vtDownload.SelectedCount = 1 then begin - miDownloadStop.Enabled := (Items[vtDownload.FocusedNode^.Index].Status in [STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT]); - miDownloadResume.Enabled := (Items[vtDownload.FocusedNode^.Index].Status in [STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM]); + ScanTasks; + miDownloadStop.Enabled := iStop; + miDownloadResume.Enabled := iResume; miDownloadDelete.Enabled := True; miDownloadDeleteTask.Enabled := True; miDownloadDeleteTaskData.Enabled := True; - miDownloadDeleteCompleted.Enabled := FinishedTaskPresent; + miDownloadDeleteCompleted.Enabled := iFinish; miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; - miDownloadViewMangaInfo.Enabled := (Items[vtDownload.FocusedNode^.Index].DownloadInfo.Link <> ''); - miDownloadOpenFolder.Enabled := True; - miDownloadOpenWith.Enabled := True; - end - else - begin - miDownloadStop.Enabled := SelectedTaskStatusPresent([STATUS_DOWNLOAD, STATUS_PREPARE, STATUS_WAIT]); - miDownloadResume.Enabled := SelectedTaskStatusPresent([STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM]); - miDownloadDelete.Enabled := True; - miDownloadDeleteTask.Enabled := True; - miDownloadDeleteTaskData.Enabled := True; - miDownloadDeleteCompleted.Enabled := FinishedTaskPresent; - miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; - miDownloadViewMangaInfo.Enabled := False; - miDownloadOpenFolder.Enabled := False; - miDownloadOpenWith.Enabled := False; + miDownloadOpenWith.Enabled := vtDownload.SelectedCount = 1; + miDownloadOpenFolder.Enabled := miDownloadOpenWith.Enabled; + miDownloadViewMangaInfo.Enabled := miDownloadOpenFolder.Enabled and + (DLManager[vtDownload.FocusedNode^.Index].DownloadInfo.Link <> ''); + miDownloadEnable.Enabled := iEnable; + miDownloadDisable.Enabled := iDisable; end; end; end; @@ -3439,7 +3445,6 @@ procedure TMainForm.vtDownloadGetHint(Sender: TBaseVirtualTree; var l, i: Cardinal; begin - if Node^.Index>=DLManager.Count then Exit; with DLManager.Items[Node^.Index],DLManager.Items[Node^.Index].DownloadInfo do case Column of 0: begin @@ -3478,17 +3483,18 @@ procedure TMainForm.vtDownloadGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); begin - if (Node^.Index < DLManager.Count) and - (vtDownload.Header.Columns[Column].Position = 0) then - ImageIndex := Integer(DLManager.Items[Node^.Index].Status); + if vtDownload.Header.Columns[Column].Position = 0 then + if not DLManager[Node^.Index].Enabled then + ImageIndex := 8 + else + ImageIndex := Integer(DLManager[Node^.Index].Status); end; procedure TMainForm.vtDownloadGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); begin - if Node^.Index >= DLManager.Count then Exit; - with DLManager.Items[Node^.Index].DownloadInfo do + with DLManager[Node^.Index].DownloadInfo do case Column of 0: CellText:=Title; 1: CellText:=Status; @@ -3550,6 +3556,14 @@ procedure TMainForm.vtDownloadKeyUp(Sender: TObject; var Key: Word; Shift: TShif miDownloadDeleteTaskClick(miDownloadDeleteTask); end; +procedure TMainForm.vtDownloadPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + if not DLManager[Node^.Index].Enabled then + TargetCanvas.Font.Color := TVirtualStringTree(Sender).Colors.DisabledColor; +end; + procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -3822,17 +3836,18 @@ procedure TMainForm.tvDownloadFilterRefresh(const ResourceChanged: Boolean); Items[4].Text := Format('%s (%d)', [RS_Failed, StatusCount[STATUS_PROBLEM] + StatusCount[STATUS_FAILED]]); + Items[5].Text := Format('%s (%d)', [RS_Disabled, DisabledCount]); if ResourceChanged then begin // root - Items[5].Text := RS_History; + Items[6].Text := RS_History; // childs - Items[6].Text := RS_Today; - Items[7].Text := RS_Yesterday; - Items[8].Text := RS_OneWeek; - Items[9].Text := RS_OneMonth; + Items[7].Text := RS_Today; + Items[8].Text := RS_Yesterday; + Items[9].Text := RS_OneWeek; + Items[10].Text := RS_OneMonth; end; finally tvDownloadFilter.EndUpdate; @@ -3874,6 +3889,18 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); end; end; + procedure ShowDisabled; + var + xNode: PVirtualNode; + begin + xNode := vtDownload.GetFirst(); + while Assigned(xNode) do + begin + vtDownload.IsVisible[xNode] := not DLManager[xNode^.Index].Enabled; + xNode := vtDownload.GetNext(xNode); + end; + end; + begin if tvDownloadFilter.Selected = nil then Exit; @@ -3886,15 +3913,17 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); if tvDownloadFilter.Selected.AbsoluteIndex > 5 then ACurrentJDN := DateToJDN(Now); case tvDownloadFilter.Selected.AbsoluteIndex of - 0, 5: ShowTasks; + 0, 6: ShowTasks; 1: ShowTasks([STATUS_FINISH]); 2: ShowTasks([STATUS_WAIT, STATUS_PREPARE, STATUS_DOWNLOAD, STATUS_COMPRESS]); 3: ShowTasks([STATUS_STOP]); 4: ShowTasks([STATUS_PROBLEM, STATUS_FAILED]); - 6: ShowTasksOnCertainDays(ACurrentJDN, ACurrentJDN); - 7: ShowTasksOnCertainDays(ACurrentJDN - 1, ACurrentJDN - 1); - 8: ShowTasksOnCertainDays(ACurrentJDN - 7, ACurrentJDN); - 9: ShowTasksOnCertainDays(ACurrentJDN - 30, ACurrentJDN); + 5: ShowDisabled; + + 7: ShowTasksOnCertainDays(ACurrentJDN, ACurrentJDN); + 8: ShowTasksOnCertainDays(ACurrentJDN - 1, ACurrentJDN - 1); + 9: ShowTasksOnCertainDays(ACurrentJDN - 7, ACurrentJDN); + 10: ShowTasksOnCertainDays(ACurrentJDN - 30, ACurrentJDN); end; finally vtDownload.EndUpdate; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 53af8671e..2298c8201 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1432,6 +1432,14 @@ msgstr "Task only" msgid "Task + Data" msgstr "Task + Data" +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "Disable" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "Enable" + #: tmainform.midownloadmergecompleted.caption msgid "Merge completed tasks" msgstr "Merge completed tasks" @@ -1899,6 +1907,10 @@ msgstr "Select a website" msgid "Compressing..." msgstr "Compressing..." +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Disabled" + #: udownloadsmanager.rs_downloading msgid "Downloading" msgstr "Downloading" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index b05f591fd..7aef634f9 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1413,6 +1413,14 @@ msgstr "Daftar saja" msgid "Task + Data" msgstr "Daftar dan data" +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "Matikan" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "Nyalakan" + #: tmainform.midownloadmergecompleted.caption msgid "Merge completed tasks" msgstr "Gabungkan unduhan selesai" @@ -1880,6 +1888,10 @@ msgstr "Pilih situs web" msgid "Compressing..." msgstr "Mengompresi..." +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Dimatikan" + #: udownloadsmanager.rs_downloading msgid "Downloading" msgstr "Mengunduh" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 611dbdff7..55004348a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1344,6 +1344,14 @@ msgstr "" msgid "Task + Data" msgstr "" +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "" + #: tmainform.midownloadmergecompleted.caption msgid "Merge completed tasks" msgstr "" @@ -1809,6 +1817,10 @@ msgstr "" msgid "Compressing..." msgstr "" +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "" + #: udownloadsmanager.rs_downloading msgid "Downloading" msgstr "" From c98c61009dabc94f9a905d1d8c73a515b2f45bf6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Jul 2016 05:11:35 +0800 Subject: [PATCH 1310/2794] added tray icon popup menu -resume all -stop all -after download finish -show drop box -restore -exit. --- mangadownloader/forms/frmMain.lfm | 68 ++++++++++++++++++- mangadownloader/forms/frmMain.pas | 90 +++++++++++++++++++++----- mangadownloader/languages/fmd.en.po | 52 +++++++++++++-- mangadownloader/languages/fmd.id_ID.po | 50 +++++++++++++- mangadownloader/languages/fmd.po | 48 +++++++++++++- 5 files changed, 281 insertions(+), 27 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9f9611119..9d3bf632b 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4936,10 +4936,11 @@ object MainForm: TMainForm BalloonFlags = bfInfo BalloonTimeout = 5000 BalloonTitle = 'Free Manga Downloader' + PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - left = 32 - top = 448 + left = 288 + top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False @@ -6525,4 +6526,67 @@ object MainForm: TMainForm OnClick = mnFilterGenreAllIndeterminateClick end end + object pmTray: TPopupMenu + OnPopup = pmTrayPopup + left = 341 + top = 432 + object miTrayResumeAll: TMenuItem + Caption = 'Resume all' + OnClick = tbDownloadResumeAllClick + end + object miTrayStopAll: TMenuItem + Caption = 'Stop all' + OnClick = tbDownloadStopAllClick + end + object miTrayAfterDownloadFinish: TMenuItem + Caption = 'After download finish' + object miTrayFinishNothing: TMenuItem + AutoCheck = True + Caption = 'Nothing' + RadioItem = True + OnClick = miTrayFinishNothingClick + end + object miTrayFinishExit: TMenuItem + Tag = 1 + AutoCheck = True + Caption = 'Exit' + RadioItem = True + OnClick = miTrayFinishNothingClick + end + object miTrayFinishShutdown: TMenuItem + Tag = 2 + AutoCheck = True + Caption = 'Shutdown' + RadioItem = True + OnClick = miTrayFinishNothingClick + end + object miTrayFinishHibernate: TMenuItem + Tag = 3 + AutoCheck = True + Caption = 'Hibernate' + RadioItem = True + OnClick = miTrayFinishNothingClick + end + end + object MenuItem8: TMenuItem + Caption = '-' + end + object miTrayShowDropBox: TMenuItem + AutoCheck = True + Caption = 'Show Drop Box' + Checked = True + OnClick = miTrayShowDropBoxClick + end + object miTrayRestore: TMenuItem + Caption = 'Restore' + OnClick = TrayIconDblClick + end + object MenuItem10: TMenuItem + Caption = '-' + end + object miTrayExit: TMenuItem + Caption = 'Exit' + OnClick = miTrayExitClick + end + end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f6858ac2e..d64f0b60b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -73,7 +73,19 @@ TMainForm = class(TForm) lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; + MenuItem10: TMenuItem; + miTrayExit: TMenuItem; + miTrayRestore: TMenuItem; + miTrayShowDropBox: TMenuItem; + MenuItem8: TMenuItem; + miTrayFinishNothing: TMenuItem; + miTrayFinishExit: TMenuItem; + miTrayFinishShutdown: TMenuItem; MenuItem2: TMenuItem; + miTrayFinishHibernate: TMenuItem; + miTrayAfterDownloadFinish: TMenuItem; + miTrayStopAll: TMenuItem; + miTrayResumeAll: TMenuItem; miDownloadEnable: TMenuItem; miDownloadDisable: TMenuItem; miChapterListFilter: TMenuItem; @@ -91,6 +103,7 @@ TMainForm = class(TForm) pcAbout: TPageControl; pmSbMain: TPopupMenu; pmFilterGenreAll: TPopupMenu; + pmTray: TPopupMenu; sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; tsWebsiteAdvanced: TTabSheet; @@ -454,6 +467,9 @@ TMainForm = class(TForm) procedure miDownloadOpenFolderClick(Sender: TObject); procedure miFavoritesOpenWithClick(Sender: TObject); procedure miDownloadOpenWithClick(Sender: TObject); + procedure miTrayExitClick(Sender: TObject); + procedure miTrayFinishNothingClick(Sender: TObject); + procedure miTrayShowDropBoxClick(Sender: TObject); procedure mnDownload1ClickClick(Sender: TObject); procedure mnFilterGenreAllCheckClick(Sender: TObject); procedure mnFilterGenreAllIndeterminateClick(Sender: TObject); @@ -467,6 +483,7 @@ TMainForm = class(TForm) procedure pmFavoritesPopup(Sender: TObject); procedure pmMangaListPopup(Sender: TObject); procedure pmSbMainPopup(Sender: TObject); + procedure pmTrayPopup(Sender: TObject); procedure rgOptionCompressSelectionChanged(Sender: TObject); procedure sbUpdateListDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); @@ -645,9 +662,12 @@ TMainForm = class(TForm) procedure UpdateVtDownload; inline; procedure UpdateVtFavorites; - // Load form information, like previous position, size, ... + // load form information, like previous position, size, ... procedure LoadFormInformation; procedure SaveFormInformation; + + // drop target + procedure ShowDropTarget(const AShow: Boolean = True); procedure SaveDropTargetFormInformation; // load language from file @@ -763,7 +783,7 @@ TSearchDBThread = class(TThread) resourcestring RS_FilterStatusItems = 'Completed'#13#10'Ongoing'#13#10'<none>'; - RS_OptionFMDDoItems = 'Do nothing'#13#10'Exit FMD'#13#10'Shutdown'#13#10'Hibernate'; + RS_OptionFMDDoItems = 'Nothing'#13#10'Exit'#13#10'Shutdown'#13#10'Hibernate'; RS_DropTargetModeItems = 'Download all'#13#10'Add to favorites'; RS_HintFavoriteProblem = 'There is a problem with this data!'#13#10 @@ -2913,6 +2933,25 @@ procedure TMainForm.miDownloadOpenWithClick(Sender: TObject); OpenWithExternalProgramChapters(DownloadInfo.SaveTo, ChapterName); end; +procedure TMainForm.miTrayExitClick(Sender: TObject); +begin + Self.Close; +end; + +procedure TMainForm.miTrayFinishNothingClick(Sender: TObject); +begin + if Sender is TMenuItem then + begin + OptionLetFMDDo := TFMDDo(TMenuItem(Sender).Tag); + configfile.WriteInteger('general', 'LetFMDDo', Integer(OptionLetFMDDo)); + end; +end; + +procedure TMainForm.miTrayShowDropBoxClick(Sender: TObject); +begin + ShowDropTarget(TMenuItem(Sender).Checked); +end; + procedure TMainForm.pcMainChange(Sender: TObject); begin if pcMain.ActivePage = tsFavorites then @@ -3117,6 +3156,20 @@ procedure TMainForm.pmSbMainPopup(Sender: TObject); Abort; end; +procedure TMainForm.pmTrayPopup(Sender: TObject); +var + i: Integer; +begin + with miTrayAfterDownloadFinish do + for i := 0 to Count - 1 do + if Items[i].Tag = Integer(OptionLetFMDDo) then + begin + Items[i].Checked := True; + Break; + end; + miTrayShowDropBox.Checked := Assigned(FormDropTarget); +end; + procedure TMainForm.rgOptionCompressSelectionChanged(Sender: TObject); begin seOptionPDFQuality.Enabled:=rgOptionCompress.ItemIndex=3; @@ -4449,19 +4502,7 @@ procedure TMainForm.ApplyOptions; //view ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; - if ckDropTarget.Checked then - begin - if FormDropTarget = nil then - Application.CreateForm(TFormDropTarget, FormDropTarget); - frmDropTarget.OnDropChekout := @AddSilentThread; - frmDropTarget.FAlphaBlendValue := tbDropTargetOpacity.Position; - FormDropTarget.Show; - end - else - begin - if Assigned(FormDropTarget) then - FormDropTarget.Close; - end; + ShowDropTarget(ckDropTarget.Checked); //connection DLManager.maxDLTasks := seOptionMaxParallel.Value; @@ -4840,11 +4881,28 @@ procedure TMainForm.SaveFormInformation; end; end; +procedure TMainForm.ShowDropTarget(const AShow: Boolean); +begin + configfile.WriteBool('droptarget', 'Show', AShow); + if AShow then + begin + if FormDropTarget = nil then + Application.CreateForm(TFormDropTarget, FormDropTarget); + frmDropTarget.OnDropChekout := @AddSilentThread; + frmDropTarget.FAlphaBlendValue := tbDropTargetOpacity.Position; + FormDropTarget.Show; + end + else + begin + if Assigned(FormDropTarget) then + FormDropTarget.Close; + end; +end; + procedure TMainForm.SaveDropTargetFormInformation; begin with configfile do begin - WriteBool('droptarget', 'Show', ckDropTarget.Checked); WriteInteger('droptarget', 'Mode', rgDropTargetMode.ItemIndex); WriteInteger('droptarget', 'Opacity', frmDropTarget.FAlphaBlendValue); WriteInteger('droptarget', 'Width', frmDropTarget.FWidth); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 2298c8201..ec6bd313d 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -269,13 +269,13 @@ msgstr "One week" #: frmmain.rs_optionfmddoitems msgid "" -"Do nothing\n" -"Exit FMD\n" +"Nothing\n" +"Exit\n" "Shutdown\n" "Hibernate\n" msgstr "" -"Do nothing\n" -"Exit FMD\n" +"Nothing\n" +"Exit\n" "Shutdown\n" "Hibernate\n" @@ -661,6 +661,7 @@ msgid "Regular Expression" msgstr "Regular Expression" #: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" msgstr "Show Drop Box" @@ -1526,6 +1527,49 @@ msgstr "Download all" msgid "View manga infos" msgstr "View manga infos" +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "After download finish" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Exit" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Exit" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Hibernate" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Nothing" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Shutdown" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Restore" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Resume all" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Show Drop Box" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Stop all" + #: tmainform.mndownload1click.caption msgid "Download all lists from server at once" msgstr "Download all lists from server at once" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 7aef634f9..95c442a00 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -267,13 +267,13 @@ msgstr "Satu minggu" #: frmmain.rs_optionfmddoitems msgid "" -"Do nothing\n" -"Exit FMD\n" +"Nothing\n" +"Exit\n" "Shutdown\n" "Hibernate\n" msgstr "" "Tidak ada\n" -"Tutup FMD\n" +"Keluar\n" "Matikan komputer\n" "Tidurkan komputer\n" @@ -650,6 +650,7 @@ msgid "Regular Expression" msgstr "Regular Expression" #: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" msgstr "Tampilkan kotak unduh" @@ -1507,6 +1508,49 @@ msgstr "Unduh semua" msgid "View manga infos" msgstr "Lihat informasi komik" +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "Setelah download selesai" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Keluar" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Keluar" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Tidurkan komputer" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "TIdak ada" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Matikan komputer" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Pulihkan" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Lanjutkan semua" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Tampilkan kotak unduh" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Hentikan semua" + #: tmainform.mndownload1click.caption msgid "Download all lists from server at once" msgstr "Unduh semua daftar dari server" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 55004348a..e644e08e9 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -236,8 +236,8 @@ msgstr "" #: frmmain.rs_optionfmddoitems msgid "" -"Do nothing\n" -"Exit FMD\n" +"Nothing\n" +"Exit\n" "Shutdown\n" "Hibernate\n" msgstr "" @@ -615,6 +615,7 @@ msgid "Regular Expression" msgstr "" #: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" msgstr "" @@ -1438,6 +1439,49 @@ msgstr "" msgid "View manga infos" msgstr "" +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "" + +#: tmainform.mitrayexit.caption +msgctxt "TMAINFORM.MITRAYEXIT.CAPTION" +msgid "Exit" +msgstr "" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "TMAINFORM.MITRAYSHOWDROPBOX.CAPTION" +msgid "Show Drop Box" +msgstr "" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "" + #: tmainform.mndownload1click.caption msgid "Download all lists from server at once" msgstr "" From 55a7cc53bbeeb7bd92995be2d29671e905c526cb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Jul 2016 05:24:36 +0800 Subject: [PATCH 1311/2794] fixed save drop target option --- mangadownloader/forms/frmDropTarget.pas | 2 +- mangadownloader/forms/frmMain.pas | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 9b057709e..45a8f7629 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -256,7 +256,7 @@ procedure TFormDropTarget.FormClose(Sender: TObject; FHeight := Height; FLeft := Left; FTop := Top; - MainForm.SaveDropTargetFormInformation; + MainForm.SaveDropTargetFormInformation(True); CloseAction := caFree; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d64f0b60b..86eeaf78f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -667,8 +667,8 @@ TMainForm = class(TForm) procedure SaveFormInformation; // drop target - procedure ShowDropTarget(const AShow: Boolean = True); - procedure SaveDropTargetFormInformation; + procedure ShowDropTarget(const AShow: Boolean); + procedure SaveDropTargetFormInformation(const isClose: Boolean = False); // load language from file procedure CollectLanguagesFromFiles; @@ -4899,10 +4899,12 @@ procedure TMainForm.ShowDropTarget(const AShow: Boolean); end; end; -procedure TMainForm.SaveDropTargetFormInformation; +procedure TMainForm.SaveDropTargetFormInformation(const isClose: Boolean); begin with configfile do begin + if isClose then + WriteBool('droptarget', 'Show', False); WriteInteger('droptarget', 'Mode', rgDropTargetMode.ItemIndex); WriteInteger('droptarget', 'Opacity', frmDropTarget.FAlphaBlendValue); WriteInteger('droptarget', 'Width', frmDropTarget.FWidth); From 0d8f3e480bce738aeb5a9362f857832d714b9097 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Jul 2016 05:32:42 +0800 Subject: [PATCH 1312/2794] fixed mangainn download, incorrect page url fixed #317 --- baseunits/modules/MangaInn.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas index ca75134f7..e75c7a5f0 100644 --- a/baseunits/modules/MangaInn.pas +++ b/baseunits/modules/MangaInn.pas @@ -111,7 +111,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; begin s := MaybeFillHost(Module.RootURL, AURL); if DownloadThread.WorkId > 0 then - s += '/page_' + IntToStr(DownloadThread.WorkId); + s += '/page_' + IntToStr(DownloadThread.WorkId + 1); if GET(s) then begin Result := True; From 1b41da39ffdf4460c018843010340efb5568758a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 8 Jul 2016 05:44:27 +0800 Subject: [PATCH 1313/2794] Bump version 0.9.74.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3c18827b5..2e28e435e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.74.0 (06-07-2016) +[+] Added enable/disable task. Disabled task can't be resumed unless it's enabled manually, this task will be skipped on resume all. +[+] Added tray icon popup menu. Resume all, Stop all, Action after download finish, Show drop box, Restore and Exit. +[*] MangaInn: fixed incorrectly download second page and forth (#317) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.73.0...0.9.74.0 + 0.9.73.0 (06-07-2016) [+] Added custom color for favorite with empty chapters [*] Various changes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9e40ce5c4..ed485b591 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="73"/> + <RevisionNr Value="74"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index fdcf86052..dcb551d78 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.73.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.73.0/fmd_0.9.73.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.73.0/fmd_0.9.73.0_Win64.7z +VERSION=0.9.74.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.74.0/fmd_0.9.74.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.74.0/fmd_0.9.74.0_Win64.7z From 6d2be8e137300147abb59d0c23c47c4880991f5a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 10 Jul 2016 21:36:54 +0800 Subject: [PATCH 1314/2794] paint empty area on vst, handled sorted column and vertical grid line --- mangadownloader/forms/frmCustomColor.pas | 78 ++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 320ca16e3..62247103b 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -84,6 +84,7 @@ TVTList = record VT: VirtualTrees.TVirtualStringTree; PaintText: TVTPaintText; BeforeCellPaint: TVTBeforeCellPaintEvent; + PaintBackground: TVTBackgroundPaintEvent; end; { TVTApplyList } @@ -98,6 +99,8 @@ TVTApplyList = class TextType: TVSTTextType); procedure VTOnBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure VTOnPaintBackground(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; const R: TRect; + var Handled: Boolean); private procedure InstallCustomColors(Index: Integer); function GetItems(Index: Integer): VirtualTrees.TVirtualStringTree; @@ -387,8 +390,7 @@ procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; Brush.Color := CL_BSOdd else Brush.Color := CL_BSEven; - isSortedColumn := (Header.Columns.Count <> 0) and (Header.SortColumn = Column) - and (CL_BSSortedColumn <> clNone); + isSortedColumn := (Header.SortColumn <> -1) and (Header.SortColumn = Column); if (not isSortedColumn) and (Brush.Color <> clNone) then FillRect(CellRect); end; @@ -397,7 +399,7 @@ procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; FVTList[Sender.Tag].BeforeCellPaint(Sender, TargetCanvas, Node, Column, CellPaintMode, CellRect, ContentRect); - if isSortedColumn and (CellPaintMode = cpmPaint) then + if isSortedColumn and (CellPaintMode = cpmPaint) and (CL_BSSortedColumn <> clNone) then begin Brush.Color := BlendColor(CL_BSSortedColumn, Brush.Color, SelectionBlendFactor); FillRect(CellRect); @@ -408,11 +410,77 @@ procedure TVTApplyList.VTOnBeforeCellPaint(Sender: TBaseVirtualTree; end; end; +procedure TVTApplyList.VTOnPaintBackground(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; const R: TRect; var Handled: Boolean); +var + AColumnRect: TRect; + i: Integer; +begin + with VirtualTrees.TVirtualStringTree(Sender) do + begin + if Header.Columns.Count <> 0 then + begin + Handled := True; + + // draw background + TargetCanvas.Brush.Color := Color; + TargetCanvas.FillRect(TargetCanvas.ClipRect); + + // draw vertgridline for each column + i := Header.Columns.GetFirstVisibleColumn(); + while i <> InvalidColumn do + begin + AColumnRect := R; + AColumnRect.Left := Header.Columns[i].Left; + AColumnRect.Width := Header.Columns[i].Width - 1; + if toShowVertGridLines in TreeOptions.PaintOptions then + begin + TargetCanvas.Pen.Color := Colors.GridLineColor; + TargetCanvas.Line(AColumnRect.Right, AColumnRect.Top, AColumnRect.Right, AColumnRect.Bottom); + end; + // draw sorted column + if (i = Header.SortColumn) and (CL_BSSortedColumn <> clNone) then + begin + TargetCanvas.Brush.Color := + BlendColor(CL_BSSortedColumn, TargetCanvas.Brush.Color, SelectionBlendFactor); + TargetCanvas.FillRect(AColumnRect); + TargetCanvas.Pen.Color := CL_BSSortedColumn; + TargetCanvas.Line(AColumnRect.Left, AColumnRect.Top, AColumnRect.Left, AColumnRect.Bottom); + TargetCanvas.Line(AColumnRect.Right - 1, AColumnRect.Top, AColumnRect.Right - 1, + AColumnRect.Bottom); + end; + i := Header.Columns.GetNextVisibleColumn(i); + end; + + // draw fixed column on top of others + TargetCanvas.Brush.Color := Color; + TargetCanvas.Pen.Color := Colors.GridLineColor; + i := Header.Columns.GetFirstVisibleColumn(); + while i <> InvalidColumn do + begin + if coFixed in Header.Columns[i].Options then + begin + AColumnRect := R; + AColumnRect.Left := Header.Columns[i].Left; + AColumnRect.Width := Header.Columns[i].Width - 1; + TargetCanvas.FillRect(AColumnRect); + if toShowVertGridLines in TreeOptions.PaintOptions then + TargetCanvas.Line(AColumnRect.Right, AColumnRect.Top, AColumnRect.Right, AColumnRect.Bottom); + end; + i := Header.Columns.GetNextVisibleColumn(i); + end; + end; + end; + + if Assigned(FVTList[Sender.Tag].PaintBackground) then + FVTList[Sender.Tag].PaintBackground(Sender, TargetCanvas, R, Handled); +end; + procedure TVTApplyList.InstallCustomColors(Index: Integer); begin with FVTList[Index], VT do begin - // set addition option + // set options LineStyle := lsSolid; if Color = clDefault then Color := clWindow; @@ -420,10 +488,12 @@ procedure TVTApplyList.InstallCustomColors(Index: Integer); // save original event PaintText := OnPaintText; BeforeCellPaint := OnBeforeCellPaint; + PaintBackground := OnPaintBackground; // set custom event OnPaintText := @VTOnPaintText; OnBeforeCellPaint := @VTOnBeforeCellPaint; + OnPaintBackground := @VTOnPaintBackground; end; end; From 205def8710cbb395d570fa208c82a48168a7beec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jul 2016 21:35:02 +0800 Subject: [PATCH 1315/2794] rewrite img2pdf, process page per page to reduce memory consumption, process only on savetostream/savetofile --- baseunits/Img2Pdf.pas | 499 +++++++++++++++++++++++++++++++++++++++++ baseunits/uImg2Pdf.pas | 465 -------------------------------------- baseunits/uPacker.pas | 5 +- 3 files changed, 502 insertions(+), 467 deletions(-) create mode 100644 baseunits/Img2Pdf.pas delete mode 100644 baseunits/uImg2Pdf.pas diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas new file mode 100644 index 000000000..52c4acf5f --- /dev/null +++ b/baseunits/Img2Pdf.pas @@ -0,0 +1,499 @@ +{ Img2Pdf + + Copyright (C) 2016 + + This source is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This code is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + A copy of the GNU General Public License is available on the World Wide Web + at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing + to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. +} +unit Img2Pdf; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, LazFileUtils, LazUTF8Classes, + Imaging, ImagingTypes, ImagingExtras, zstream; + +type + TPDFFloat = Single; + TCompressionQuality = 0..100; + + TImg2PDF = class; + + { TPageInfo } + + TPageInfo = class + private + FOwner: TImg2PDF; + public + constructor Create(const AOwner: TImg2PDF); + destructor Destroy; override; + public + FileName: String; + Extension: String; + Width: Integer; + Height: Integer; + ColorSpace: String; + Filter: String; + Stream: TMemoryStreamUTF8; + public + procedure GetInfo; + procedure LoadImageData; + procedure FlushImageData; + end; + + TPDFInfos = record + Title, + Subject, + Author, + Creator, + Producer, + Keywords: String; + CreationDate: TDateTime; + ModDate: TDateTime; + end; + + { TImg2PDF } + + TImg2PDF = class + private + FPageInfos: TFPList; + function GetPageInfo(const Index: Integer): TPageInfo; + public + constructor Create; + destructor Destroy; override; + public + Infos: TPDFInfos; + CompressionQuality: TCompressionQuality; + function AddImage(const AFileName: String): Integer; + procedure DeleteImage(const Index: Integer); + procedure SaveToStream(const Stream: TStream); + procedure SaveToFile(const AFileName: String); + public + property PageInfo[const Index: Integer]: TPageInfo read GetPageInfo; + end; + +implementation + +const + CRLF = #13#10; + PDF_VERSION = '%PDF-1.3'; + PDF_FILE_END = '%%EOF'; + PDF_MAX_GEN_NUM = 65535; + +function PDFString(const S: String): String; +begin + Result := S; + if Pos(Result, '\') <> -1 then + Result := StringReplace(Result, '\', '\\', [rfReplaceAll]); + if Pos(Result, ')') <> -1 then + Result := StringReplace(Result, ')', '\)', [rfReplaceAll]); + if Pos(Result, '(') <> -1 then + Result := StringReplace(Result, '(', '\(', [rfReplaceAll]); +end; + +function PDFInt(const I: Integer; PadLength: Integer): String; +begin + Result := IntToStr(I); + PadLength := PadLength - Length(Result); + if PadLength > 0 then + Result := StringOfChar('0', PadLength) + Result; +end; + +{ TPageInfo } + +constructor TPageInfo.Create(const AOwner: TImg2PDF); +begin + FOwner := AOwner; + FileName := ''; + Extension := ''; + Width := 0; + Height := 0; + ColorSpace := ''; + Filter := ''; +end; + +destructor TPageInfo.Destroy; +begin + FlushImageData; + inherited Destroy; +end; + +function GetColorSpace(const AImageData: TImageData): String; +begin + case AImageData.Format of + ifIndex8: Result := 'Indexed'; + + ifGray8, + ifA8Gray8, + ifGray16, + ifGray32, + ifGray64, + ifA16Gray16: Result := 'DeviceGray'; + + ifX5R1G1B1, + ifR3G3B2, + ifR5G6B5, + ifA1R5G5B5, + ifA4R4G4B4, + ifX1R5G5B5, + ifX4R4G4B4, + ifR8G8B8, + ifA8R8G8B8, + ifX8R8G8B8, + ifR16G16B16, + ifA16R16G16B16, + ifB16G16R16, + ifA16B16G16R16, + ifR32F, + ifA32R32G32B32F, + ifA32B32G32R32F, + ifR16F, + ifA16R16G16B16F, + ifA16B16G16R16F, + ifR32G32B32F, + ifB32G32R32F: Result := 'DeviceRGB'; + else + Result := ''; + end; +end; + +procedure TPageInfo.GetInfo; +var + AMS: TMemoryStreamUTF8; + AImg: TImageData; +begin + AMS := TMemoryStreamUTF8.Create; + try + AMS.LoadFromFile(FileName); + Extension := LowerCase(DetermineFileFormat(FileName)); + if Extension = '' then Exit; + InitImage(AImg); + try + if LoadImageFromStream(AMS, AImg) then + begin + Width := AImg.Width; + Height := AImg.Height; + ColorSpace := GetColorSpace(AImg); + end; + finally + FreeImage(AImg); + end; + finally + AMS.Free; + end; +end; + +procedure TPageInfo.LoadImageData; +var + AImg: TImageData; + ADefaultJpegQuality: LongInt; + AImgInfo: TImageFormatInfo; + i: Integer; +begin + if Assigned(Stream) then Exit; + Stream := TMemoryStreamUTF8.Create; + try + Stream.LoadFromFile(FileName); + InitImage(AImg); + LoadImageFromStream(Stream, AImg); + if Extension = 'jpg' then + Filter := 'DCTDecode' + else + begin + Stream.Clear; + if FOwner.CompressionQuality < 100 then + begin + //DCTDecode for jpg, convert to jpg for non jpg + Filter := 'DCTDecode'; + ADefaultJpegQuality := Imaging.GetOption(ImagingJpegQuality); + try + Imaging.SetOption(ImagingJpegQuality, FOwner.CompressionQuality); + SaveImageToStream('jpg', Stream, AImg); + finally + Imaging.SetOption(ImagingJpegQuality, ADefaultJpegQuality); + end; + end + else + begin + //FlateDecode + Filter := 'FlateDecode'; + GetImageFormatInfo(AImg.Format, AImgInfo); + if (AImgInfo.IsIndexed) and (AImgInfo.PaletteEntries > 0) then begin + ColorSpace := 'Indexed /DeviceRGB ' + IntToStr(AImgInfo.PaletteEntries - 1) + ' <'; + for i := 0 to AImgInfo.PaletteEntries - 1 do + with AImg.Palette^[i] do + ColorSpace += IntToHex(R, 2) + IntToHex(G, 2) + IntToHex(B, 2); + ColorSpace += '>'; + end; + if ColorSpace = 'DeviceRGB' then + try + SwapChannels(AImg, ChannelRed, ChannelBlue); + except + end; + with Tcompressionstream.Create(clmax, Stream, False) do + try + Write(AImg.Bits^, AImg.Size); + finally + Free; + end; + end; + end; + finally + FreeImage(AImg); + end; +end; + +procedure TPageInfo.FlushImageData; +begin + if Assigned(Stream) then + FreeAndNil(Stream); +end; + +{ TImg2PDF } + +function TImg2PDF.GetPageInfo(const Index: Integer): TPageInfo; +begin + Result := TPageInfo(FPageInfos[Index]); +end; + +constructor TImg2PDF.Create; +begin + FPageInfos := TFPList.Create; + Infos.Title := ''; + Infos.Subject := ''; + Infos.Author := ''; + Infos.Creator := ''; + Infos.Producer := 'Img2Pdf'; + Infos.Keywords := ''; + Infos.CreationDate := Now; + Infos.ModDate := Now; + CompressionQuality := 100; +end; + +destructor TImg2PDF.Destroy; +begin + while FPageInfos.Count <> 0 do + DeleteImage(FPageInfos.Count - 1); + FPageInfos.Free; + inherited Destroy; +end; + +function TImg2PDF.AddImage(const AFileName: String): Integer; +var + P: TPageInfo; +begin + Result := -1; + if not FileExistsUTF8(AFileName) then Exit; + P := TPageInfo.Create(Self); + P.FileName := AFileName; + P.GetInfo; + if P.Extension <> '' then + Result := FPageInfos.Add(P) + else + p.Free; +end; + +procedure TImg2PDF.DeleteImage(const Index: Integer); +begin + TPageInfo(FPageInfos[Index]).Free; + FPageInfos.Delete(Index); +end; + +procedure TImg2PDF.SaveToStream(const Stream: TStream); +var + PDFBuffer: String; + AData, vkids: String; + AObjs: array of Integer; + AObjCount, i, vnbpal, vni, vo: Integer; + + procedure PDFFlush; + begin + if PDFBuffer = '' then Exit; + Stream.Write(Pointer(PDFBuffer)^, Length(PDFBuffer)); + PDFBuffer := ''; + end; + + procedure PDFWrite(const S: String); + begin + PDFBuffer := PDFBuffer + S + CRLF; + end; + + procedure CreateNewObj; + begin + Inc(AObjCount); + SetLength(AObjs, Length(AObjs) + 1); + AObjs[AObjCount] := Stream.Size; + PDFWrite(IntToStr(AObjCount) + ' 0 obj'); + end; + +begin + if FPageInfos.Count = 0 then Exit; + + PDFBuffer := ''; + AObjCount := 2; + SetLength(AObjs, 3); + + try + PDFWrite(PDF_VERSION); + + for i := 0 to FPageInfos.Count - 1 do + begin + CreateNewObj; + PDFWrite('<<'); + PDFWrite('/Type /Page'); + PDFWrite('/Parent 1 0 R'); + PDFWrite('/MediaBox [0 0 ' + IntToStr(PageInfo[i].Width) + ' ' + IntToStr(PageInfo[i].Height) + ']'); + PDFWrite('/Resources 2 0 R'); + PDFWrite('/Contents ' + IntToStr(AObjCount + 1) + ' 0 R'); + PDFWrite('>>'); + PDFWrite('endobj'); + + CreateNewObj; + AData := '1 0 0 1 0 ' + IntToStr(PageInfo[i].Height) + ' cm' + CRLF + + Format('q %d 0 0 %d 0 -%d cm /I%d Do Q', [PageInfo[i].Width, PageInfo[i].Height, + PageInfo[i].Height, i + 1]); + PDFWrite('<<'); + PDFWrite('/Length ' + IntToStr(Length(AData))); + PDFWrite('>>'); + PDFWrite('stream'); + PDFWrite(AData + CRLF + 'endstream'); + PDFWrite('endobj'); + end; + PDFFlush; + + vni := AObjCount; + for i := 0 to FPageInfos.Count - 1 do + try + PageInfo[i].LoadImageData; + CreateNewObj; + PDFWrite('<<'); + PDFWrite('/Type /XObject'); + PDFWrite('/Subtype /Image'); + PDFWrite('/Width ' + IntToStr(PageInfo[i].Width)); + PDFWrite('/Height ' + IntToStr(PageInfo[i].Height)); + PDFWrite('/ColorSpace [/' + PageInfo[i].ColorSpace + ']'); + PDFWrite('/BitsPerComponent 8'); + PDFWrite('/Filter /' + PageInfo[i].Filter); + PDFWrite('/Length ' + IntToStr(PageInfo[i].Stream.Size)); + PDFWrite('>>'); + PDFWrite('stream'); + PDFFlush; + PageInfo[i].Stream.Position := 0; + Stream.CopyFrom(PageInfo[i].Stream, PageInfo[i].Stream.Size); + PDFWrite(CRLF + 'endstream'); + PDFWrite('endobj'); + finally + PageInfo[i].FlushImageData; + end; + PDFFlush; + + AObjs[1] := Stream.Size; + PDFWrite('1 0 obj'); + PDFWrite('<<'); + PDFWrite('/Type /Pages'); + vkids := '/Kids ['; + for i := 0 to FPageInfos.Count - 1 do + vkids := vkids + IntToStr(3 + 2 * i) + ' 0 R '; + PDFWrite(vkids + ']'); + PDFWrite('/Count ' + IntToStr(FPageInfos.Count)); + PDFWrite('/MediaBox [0 0 800 600]'); + PDFWrite('>>'); + PDFWrite('endobj'); + + AObjs[2] := Stream.Size; + PDFWrite('2 0 obj'); + PDFWrite('<<'); + PDFWrite('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); + PDFWrite('/Font'); + PDFWrite('<<'); + PDFWrite('>>'); + PDFWrite('/XObject'); + PDFWrite('<<'); + vnbpal := 0; + for i := 1 to FPageInfos.Count do + begin + PDFWrite('/I' + IntToStr(i) + ' ' + IntToStr(vni + (i) + vnbpal) + ' 0 R'); + if (PageInfo[i - 1].ColorSpace = 'Indexed') then + vnbpal := vnbpal + 1; + end; + PDFWrite('>>'); + PDFWrite('>>'); + PDFWrite('endobj'); + + CreateNewObj; + PDFWrite('<<'); + PDFWrite('/CreationDate (D:' + FormatDateTime('yyyymmddhhnnss', Infos.CreationDate) + ')'); + PDFWrite('/ModDate (D:' + FormatDateTime('yyyymmddhhnnss', Infos.ModDate) + ')'); + if Infos.Title <> '' then + PDFWrite('/Title (' + PDFString(Infos.Title) + ')'); + if Infos.Subject <> '' then + PDFWrite('/Subject (' + PDFString(Infos.Subject) + ')'); + if Infos.Author <> '' then + PDFWrite('/Author (' + PDFString(Infos.Author) + ')'); + if Infos.Creator <> '' then + PDFWrite('/Creator (' + PDFString(Infos.Creator) + ')'); + if Infos.Producer <> '' then + PDFWrite('/Producer (' + PDFString(Infos.Producer) + ')'); + if Infos.Keywords <> '' then + PDFWrite('/Keywords (' + PDFString(Infos.Keywords) + ')'); + PDFWrite('>>'); + PDFWrite('endobj'); + + CreateNewObj; + PDFWrite('<<'); + PDFWrite('/Type /Catalog'); + PDFWrite('/OpenAction [3 0 R /FitH null]'); + PDFWrite('/Pages 1 0 R'); + PDFWrite('>>'); + PDFWrite('endobj'); + + vo := Stream.Size; + PDFWrite('xref'); + PDFWrite('0 ' + IntToStr(AObjCount + 1)); + PDFWrite('0000000000 ' + PDFInt(PDF_MAX_GEN_NUM, 5) + ' f'); + for i := 1 to AObjCount do + PDFWrite(PDFInt(AObjs[i], 10) + ' 00000 n'); + PDFWrite('trailer'); + PDFWrite('<<'); + PDFWrite('/Size ' + IntToStr(AObjCount + 1)); + PDFWrite('/Root ' + IntToStr(AObjCount) + ' 0 R'); + PDFWrite('/Info ' + IntToStr(AObjCount - 1) + ' 0 R'); + PDFWrite('>>'); + PDFWrite('startxref'); + PDFWrite(IntToStr(vo)); + + PDFWrite(PDF_FILE_END); + PDFFlush; + finally + SetLength(AObjs, 0); + end; +end; + +procedure TImg2PDF.SaveToFile(const AFileName: String); +var + fs: TFileStreamUTF8; +begin + if FPageInfos.Count = 0 then Exit; + fs := TFileStreamUTF8.Create(AFileName, fmCreate); + try + SaveToStream(fs); + finally + fs.Free; + end; +end; + +end. diff --git a/baseunits/uImg2Pdf.pas b/baseunits/uImg2Pdf.pas deleted file mode 100644 index 848d523bf..000000000 --- a/baseunits/uImg2Pdf.pas +++ /dev/null @@ -1,465 +0,0 @@ -{ - File: img2pdf.pas - License: GPLv2 - This unit is a part of Free Manga Downloader -} - -unit uImg2Pdf; - -{$mode delphi} - -interface - -uses - Classes, SysUtils, lazutf8classes, LazFileUtils, - ZStream, ImagingTypes, Imaging, ImagingExtras, - SimpleLogger, SimpleException; - -const - TPDFFormatSetings: TFormatSettings = ( - CurrencyFormat: 1; - NegCurrFormat: 5; - ThousandSeparator: #0; - DecimalSeparator: '.'; - CurrencyDecimals: 2; - DateSeparator: '-'; - TimeSeparator: ':'; - ListSeparator: ','; - CurrencyString: '$'; - ShortDateFormat: 'd/m/y'; - LongDateFormat: 'dd" "mmmm" "yyyy'; - TimeAMString: 'AM'; - TimePMString: 'PM'; - ShortTimeFormat: 'hh:nn'; - LongTimeFormat: 'hh:nn:ss'; - ShortMonthNames: ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', - 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); - LongMonthNames: ('January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December'); - ShortDayNames: ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); - LongDayNames: ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', - 'Friday', 'Saturday'); - TwoDigitYearCenturyWindow: 50; - ); - -type - TPageInfo = record - Width, - Height: Single; - BitsPerComponent: Byte; - ColorSpace, - Filter: String; - Stream: TMemoryStreamUTF8; - end; - - { TImg2Pdf } - - TImg2Pdf = class(TObject) - private - FBuffer : TMemoryStreamUTF8; - FState : Integer; - FCompressionQuality, - FObjCount, - FCurrentPage: Cardinal; - FTitle : String; - FPages : array of String; - FOffsets : array of Cardinal; - FPageInfos : array of TPageInfo; - - procedure CreateNewObj; - procedure BeginPDF; - procedure EndPDF; - procedure BeginPDFPage(const AFWidth, AFHeight: Single); - procedure EndPDFPage; - procedure PDFWrite(AText: String); - function PDFString(const AText: String): String; - procedure Error(AMsg: String); - function GetImageFormat(imData: TImageData): string; - public - constructor Create; - destructor Destroy; override; - procedure AddImage(const AName: String); - procedure SaveToStream(const AStream: TStream); - procedure SaveToFile(const AFile: String); - - property Title: String read FTitle write FTitle; - property CompressionQuality: Cardinal read FCompressionQuality write FCompressionQuality; - end; - -implementation - -// private - -procedure TImg2Pdf.CreateNewObj; -begin - Inc(FObjCount); - SetLength(FOffsets, Length(FOffsets) + 1); - FOffsets[FObjCount]:= FBuffer.Size; - PDFWrite(IntToStr(FObjCount) + ' 0 obj'); -end; - -procedure TImg2Pdf.BeginPDF; -begin - FState:= 0; - SetLength(FPages, 1); - SetLength(FPageInfos, 1); - PDFWrite('%PDF-1.7'); -end; - -procedure TImg2Pdf.EndPDF; -var - vni, vo, - vnbpal, - i : Integer; - vkids, - data: String; -begin - for i:= 1 to FCurrentPage do - begin - CreateNewObj; - - PDFWrite('<</Type /Page'); - PDFWrite('/Parent 1 0 R'); - PDFWrite('/MediaBox [0 0 ' + FloatToStr(FPageInfos[i].Width) + ' ' + FloatToStr(FPageInfos[i].Height) + ']'); - PDFWrite('/Resources 2 0 R'); - PDFWrite('/Contents ' + IntToStr(QWord(FObjCount) + 1) + ' 0 R>>'); - PDFWrite('endobj'); - - data:= FPages[i]; - CreateNewObj; - PDFWrite('<</Length ' + IntToStr(Length(data)) + '>>'); - PDFWrite('stream'); - PDFWrite(data + 'endstream'); - PDFWrite('endobj'); - end; - - vni:= FObjCount; - for i:= 1 to FCurrentPage do - begin - CreateNewObj; - PDFWrite('<</Type /XObject'); - PDFWrite('/Subtype /Image'); - PDFWrite('/Width ' + FloatToStr(FPageInfos[i].Width)); - PDFWrite('/Height ' + FloatToStr(FPageInfos[i].Height)); - PDFWrite('/ColorSpace [/' + FPageInfos[i].ColorSpace + ']'); - PDFWrite('/BitsPerComponent ' + IntToStr(FPageInfos[i].BitsPerComponent)); - PDFWrite('/Filter /' + FPageInfos[i].Filter); - PDFWrite('/Length ' + IntToStr(FPageInfos[i].Stream.Size) + '>>'); - PDFWrite('stream'); - FPageInfos[i].Stream.Position := 0; - FBuffer.CopyFrom(FPageInfos[i].Stream, FPageInfos[i].Stream.Size); - PDFWrite(#10 + 'endstream'); - PDFWrite('endobj'); - end; - - FOffsets[1]:= FBuffer.Size; - PDFWrite('1 0 obj'); - PDFWrite('<</Type /Pages'); - vkids:= '/Kids ['; - for i:= 0 to FCurrentPage - 1 do - vkids:= vkids + IntToStr(3 + 2 * i) + ' 0 R '; - PDFWrite(vkids + ']'); - PDFWrite('/Count ' + IntToStr(FCurrentPage)); - PDFWrite('/MediaBox [0 0 ' + FloatToStr(800) + ' ' + FloatToStr(600) + ']'); - PDFWrite('>>'); - PDFWrite('endobj'); - - FOffsets[2]:= FBuffer.Size; - PDFWrite('2 0 obj'); - PDFWrite('<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]'); - PDFWrite('/Font <<'); - PDFWrite('>>'); - PDFWrite('/XObject <<'); - vnbpal:= 0; - for i:= 1 to FCurrentPage do - begin - PDFWrite('/I' + IntToStr(i) + ' ' + - IntToStr(vni + (i) + vnbpal) + ' 0 R'); - if (FPageInfos[i].ColorSpace = 'Indexed') then - vnbpal:= vnbpal + 1; - end; - PDFWrite('>>'); - PDFWrite('>>'); - PDFWrite('endobj'); - - CreateNewObj; - PDFWrite('<</Producer (FMD - IMG2PDF)'); - if FTitle <> '' then - PDFWrite('/Title (' + PDFString(FTitle) + ')'); - - PDFWrite('/ModDate (D:' + FormatDateTime('yyyymmddhhnnss', now) +')'); - PDFWrite('/CreationDate (D:' + FormatDateTime('yyyymmddhhnnss', now) +')>>'); - PDFWrite('endobj'); - - CreateNewObj; - PDFWrite('<</Type /Catalog'); - PDFWrite('/OpenAction [3 0 R /FitH null]'); - PDFWrite('/Pages 1 0 R>>'); - PDFWrite('endobj'); - - vo:= FBuffer.Size; - PDFWrite('xref'); - PDFWrite('0 ' + IntToStr(QWord(FObjCount) + 1)); - PDFWrite('0000000000 65535 f '); - for i:= 1 to FObjCount do - PDFWrite(Format('%.10d 00000 n ', [FOffsets[i]], TPDFFormatSetings)); - PDFWrite('trailer'); - PDFWrite('<</Size ' + IntToStr(QWord(FObjCount) + 1)); - PDFWrite('/Root ' + IntToStr(FObjCount) + ' 0 R'); - PDFWrite('/Info ' + IntToStr(FObjCount - 1) + ' 0 R>>'); - PDFWrite('startxref'); - PDFWrite(IntToStr(vo)); - - // TODO: add compress method - - PDFWrite('%%EOF'); -end; - -procedure TImg2Pdf.BeginPDFPage(const AFWidth, AFHeight: Single); -begin - Inc(FCurrentPage); - SetLength(FPages, Length(FPages) + 1); - SetLength(FPageInfos, Length(FPageInfos) + 1); - - FPages[FCurrentPage]:= ''; - FState:= 1; - - PDFWrite(FloatToStrF(1, ffNumber, 14, 6, TPDFFormatSetings) + - ' 0 0 ' + FloatToStrF(1, ffNumber, 14, 6, TPDFFormatSetings) + - ' 0 ' + FloatToStr(AFHeight) + ' cm'); -end; - -procedure TImg2Pdf.EndPDFPage; -begin - FState:= 0; -end; - -procedure TImg2Pdf.PDFWrite(AText: String); -begin - if FState = 1 then - FPages[FCurrentPage]:= FPages[FCurrentPage] + AText + #10 - else - begin - AText := AText + #10; - FBuffer.Write(Pointer(AText)^, Length(AText)); - end; -end; - -function TImg2Pdf.PDFString(const AText: String): String; -begin - Result:= StringReplace(StringReplace(StringReplace(AText, '\', '\\', [rfReplaceAll]), - ')', '\)', [rfReplaceAll]), '(', '\(', [rfReplaceAll]); -end; - -procedure TImg2Pdf.Error(AMsg: String); -begin - raise Exception.Create('IMG2PDF error: ' + AMsg); -end; - -// public - -constructor TImg2Pdf.Create; -begin - inherited; - Imaging.SetOption(ImagingJpegProgressive, 1); - FTitle := ''; - FState := 0; - FObjCount := 2; - FCurrentPage:= 0; - FCompressionQuality:= 100; - SetLength(FPages, 0); - SetLength(FOffsets, 3); - SetLength(FPageInfos, 0); - FBuffer:= TMemoryStreamUTF8.Create; - - BeginPDF; -end; - -destructor TImg2Pdf.Destroy; -var - i: Cardinal; -begin - if FCurrentPage > 0 then - for i:= 1 to FCurrentPage do - FPageInfos[i].Stream.Free; - SetLength(FPageInfos, 0); - SetLength(FOffsets, 0); - SetLength(FPages, 0); - FBuffer.Free; - inherited; -end; - -function TImg2Pdf.GetImageFormat(imData: TImageData): string; -begin - case imData.Format of - ifIndex8: Result := 'Indexed'; - - ifGray8, - ifA8Gray8, - ifGray16, - ifGray32, - ifGray64, - ifA16Gray16: Result := 'DeviceGray'; - - ifX5R1G1B1, - ifR3G3B2, - ifR5G6B5, - ifA1R5G5B5, - ifA4R4G4B4, - ifX1R5G5B5, - ifX4R4G4B4, - ifR8G8B8, - ifA8R8G8B8, - ifX8R8G8B8, - ifR16G16B16, - ifA16R16G16B16, - ifB16G16R16, - ifA16B16G16R16, - ifR32F, - ifA32R32G32B32F, - ifA32B32G32R32F, - ifR16F, - ifA16R16G16B16F, - ifA16B16G16R16F, - ifR32G32B32F, - ifB32G32R32F: Result := 'DeviceRGB'; - else - Result := 'DeviceCMYK'; - end; -end; - -procedure TImg2Pdf.AddImage(const AName: String); -var - ms: TMemoryStreamUTF8; - img: TImageData; - imgloaded: Boolean; - imgext,imgc: String; - imgwidth,imgheight,defaultjpeg: LongInt; - i: Integer; - imginfo: TImageFormatInfo; -begin - if not FileExistsUTF8(AName) then Exit; - imgloaded:=False; - ms:=TMemoryStreamUTF8.Create; - try - ms.LoadFromFile(AName); - imgext:=LowerCase(DetermineStreamFormat(ms)); - - if imgext<> '' then begin - InitImage(img); - try - if LoadImageFromStream(ms,img) then begin - imgc:=GetImageFormat(img); - imgwidth:=img.Width; - imgheight:=img.Height; - if (imgext<>'jpg') and (imgext<>'jpeg') then begin - ms.Clear; - if FCompressionQuality<100 then begin - //DCTDecode - //convert to jpg for non jpg - defaultjpeg:=Imaging.GetOption(ImagingJpegQuality); - try - Imaging.SetOption(ImagingJpegQuality,FCompressionQuality); - imgloaded:=SaveImageToStream('jpg',ms,img); - imgext:='jpg'; - finally - Imaging.SetOption(ImagingJpegQuality,defaultjpeg); - end; - end - else begin - //FlateDecode - GetImageFormatInfo(img.Format,imginfo); - if (imginfo.IsIndexed) and (imginfo.PaletteEntries>0) then begin - imgc:='Indexed /DeviceRGB '+IntToStr(imginfo.PaletteEntries-1)+' <'; - for i:=0 to imginfo.PaletteEntries-1 do - with img.Palette^[i] do - imgc+=IntToHex(R,2)+IntToHex(G,2)+IntToHex(B,2); - imgc+='>'; - end; - if imgc='DeviceRGB' then - try - SwapChannels(img,ChannelRed,ChannelBlue); - except - end; - with Tcompressionstream.create(clmax,ms) do - try - write(img.Bits^,img.Size); - imgloaded:=True; - finally - Free; - end; - end; - end - else - imgloaded:=True; - end; - finally - FreeImage(img); - end; - - if imgloaded then begin - try - BeginPDFPage(imgwidth,imgheight); - with FPageInfos[FCurrentPage] do begin - if (imgext='jpg') or (imgext='jpeg') then - Filter:='DCTDecode' - else - Filter:='FlateDecode'; - Stream:=ms; - BitsPerComponent:=8; - ColorSpace:=imgc; - Width:=imgwidth; - Height:=imgheight; - PDFWrite(Format('q %d 0 0 %d 0 -%d cm /I%d Do Q',[imgwidth,imgheight,imgheight,FCurrentPage])); - end - finally - EndPDFPage; - end; - end; - end; - except - on E :Exception do begin - WriteLog_E('TImg2Pdf.AddFlateImage.Error, '+E.Message); - SimpleException.ExceptionHandleSaveLogOnly(Self, E); - end; - end; - if (imgloaded=False) and Assigned(ms) then - FreeAndNil(ms); -end; - -procedure TImg2Pdf.SaveToStream(const AStream: TStream); -begin - // close PDF - if FCurrentPage = 0 then exit; - EndPDFPage; - EndPDF; - - // save to stream - try - FBuffer.Position:= 0; - AStream.CopyFrom(FBuffer, FBuffer.Size); - finally - end; -end; - -procedure TImg2Pdf.SaveToFile(const AFile: String); -var - fstream: TFileStreamUTF8; -begin - if FCurrentPage = 0 then exit; - EndPDFPage; - EndPDF; - - // save to file - try - FBuffer.Position:= 0; - fstream:= TFileStreamUTF8.Create(AFile, fmCreate); - fstream.CopyFrom(FBuffer, FBuffer.Size); - finally - fstream.Free; - end; -end; - -end. - - diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index febf4bf05..80bb98310 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -11,7 +11,7 @@ interface uses - Classes, Zipper, zstream, SysUtils, uBaseUnit, uImg2Pdf, FileUtil, lazutf8classes, + Classes, Zipper, zstream, SysUtils, uBaseUnit, Img2Pdf, FileUtil, lazutf8classes, LazFileUtils, SimpleException, uMisc; type @@ -82,7 +82,8 @@ procedure TPacker.DoPdf; pdf := TImg2Pdf.Create; try pdf.CompressionQuality := CompressionQuality; - pdf.Title := GetLastDir(Path); + pdf.Infos.Title := GetLastDir(Path); + pdf.Infos.Creator := ApplicationName; for i := 0 to FFileList.Count - 1 do begin try From e7976e467f9da87b168fb0c23c5e88a06dae5c57 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jul 2016 21:44:57 +0800 Subject: [PATCH 1316/2794] cf, maxretry follow http retrycount, set temporary http retry count to 0 #320 --- baseunits/modules/Cloudflare.pas | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 6a1e8baa9..ba55c4909 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -17,7 +17,6 @@ implementation const MIN_WAIT_TIME = 5000; - MAX_RETRY = 3; function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; begin @@ -101,13 +100,15 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): Boolean; var m, u, h: String; - st, sc, counter: Integer; + st, sc, counter, maxretry: Integer; begin Result := False; if AHTTP = nil then Exit; if Cookie <> '' then AHTTP.Cookies.Text := Cookie; counter := 0; - while counter < MAX_RETRY do begin + maxretry := AHTTP.RetryCount; + AHTTP.RetryCount := 0; + while counter < maxretry do begin Inc(counter); m := 'GET'; u := ''; @@ -121,7 +122,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B sc := 0; while sc < st do begin if AHTTP.ThreadTerminated then - Exit; + Break; Inc(sc, 500); Sleep(500); end; @@ -131,13 +132,14 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B AHTTP.FollowRedirection := True; if Result then Cookie := AHTTP.GetCookies; end; - if Result then Exit - else if counter < MAX_RETRY then begin + if Result then Break + else if counter < maxretry then begin AHTTP.Reset; Result := AHTTP.GET(AURL); - if not AntiBotActive(AHTTP) then Exit; + if not AntiBotActive(AHTTP) then Break; end; end; + AHTTP.RetryCount := maxretry; end; function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; From a6c09891b24843d7e5d93015541ca591c6b75061 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 17 Jul 2016 22:02:41 +0800 Subject: [PATCH 1317/2794] httpsendthread, changed default user-agent to latest chrome stable --- baseunits/httpsendthread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 58477b44a..abb6bee8e 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -55,7 +55,7 @@ function MaybeEncodeURL(const AValue: String): String; var DefaultUserAgent: String = - 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0'; + 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36'; DefaultRetryCount: Integer = 0; DefaultTimeout: Integer = 15000; DefaultProxyType: String = ''; From 6ca2e78b70dcb068bc8e8aec9393c6e6765c57d4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jul 2016 13:14:05 +0800 Subject: [PATCH 1318/2794] img2pdf, changed getinfo to getimagesize --- baseunits/Img2Pdf.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 52c4acf5f..798ae86f7 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -50,7 +50,7 @@ TPageInfo = class Filter: String; Stream: TMemoryStreamUTF8; public - procedure GetInfo; + procedure GetImageSize; procedure LoadImageData; procedure FlushImageData; end; @@ -171,7 +171,7 @@ function GetColorSpace(const AImageData: TImageData): String; end; end; -procedure TPageInfo.GetInfo; +procedure TPageInfo.GetImageSize; var AMS: TMemoryStreamUTF8; AImg: TImageData; @@ -179,7 +179,7 @@ procedure TPageInfo.GetInfo; AMS := TMemoryStreamUTF8.Create; try AMS.LoadFromFile(FileName); - Extension := LowerCase(DetermineFileFormat(FileName)); + Extension := LowerCase(DetermineStreamFormat(AMS)); if Extension = '' then Exit; InitImage(AImg); try @@ -187,7 +187,6 @@ procedure TPageInfo.GetInfo; begin Width := AImg.Width; Height := AImg.Height; - ColorSpace := GetColorSpace(AImg); end; finally FreeImage(AImg); @@ -210,6 +209,7 @@ procedure TPageInfo.LoadImageData; Stream.LoadFromFile(FileName); InitImage(AImg); LoadImageFromStream(Stream, AImg); + ColorSpace := GetColorSpace(AImg); if Extension = 'jpg' then Filter := 'DCTDecode' else @@ -300,7 +300,7 @@ function TImg2PDF.AddImage(const AFileName: String): Integer; if not FileExistsUTF8(AFileName) then Exit; P := TPageInfo.Create(Self); P.FileName := AFileName; - P.GetInfo; + P.GetImageSize; if P.Extension <> '' then Result := FPageInfos.Add(P) else From c1b413fec441d9a1a006502f5bb10bd0eb70a80c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 18 Jul 2016 13:38:08 +0800 Subject: [PATCH 1319/2794] img2pdf, getimagesize use tfilestream --- baseunits/Img2Pdf.pas | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 798ae86f7..d53b727fe 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -173,17 +173,16 @@ function GetColorSpace(const AImageData: TImageData): String; procedure TPageInfo.GetImageSize; var - AMS: TMemoryStreamUTF8; + AFS: TFileStreamUTF8; AImg: TImageData; begin - AMS := TMemoryStreamUTF8.Create; + AFS := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); try - AMS.LoadFromFile(FileName); - Extension := LowerCase(DetermineStreamFormat(AMS)); + Extension := LowerCase(DetermineStreamFormat(AFS)); if Extension = '' then Exit; InitImage(AImg); try - if LoadImageFromStream(AMS, AImg) then + if LoadImageFromStream(AFS, AImg) then begin Width := AImg.Width; Height := AImg.Height; @@ -192,7 +191,7 @@ procedure TPageInfo.GetImageSize; FreeImage(AImg); end; finally - AMS.Free; + AFS.Free; end; end; From 99e1d7e14638c1bdad1bc6b8bdac27104476b77e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 19 Jul 2016 05:34:06 +0800 Subject: [PATCH 1320/2794] getmangainfosthread, fixed getinfo ignoring title param #322 --- baseunits/uGetMangaInfosThread.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 3e8d1dd0f..b8a18bd14 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -68,13 +68,16 @@ procedure TGetMangaInfosThread.DoGetInfos; try FInfo.mangaInfo.website := Website; FInfo.mangaInfo.link := Link; + FInfo.mangaInfo.title := Title; FInfo.ModuleId := Modules.LocateModule(Website); if (FMangaListPos >= 0) and (MainForm.cbSelectManga.ItemIndex<>-1) and (website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex]) then begin filterPos := FMangaListPos; - FInfo.mangaInfo.title := MainForm.dataProcess.Value[filterPos, DATA_PARAM_TITLE]; - FInfo.mangaInfo.link := MainForm.dataProcess.Value[filterPos, DATA_PARAM_LINK]; + if FInfo.mangaInfo.title = '' then + FInfo.mangaInfo.title := MainForm.dataProcess.Value[filterPos, DATA_PARAM_TITLE]; + if FInfo.mangaInfo.link = '' then + FInfo.mangaInfo.link := MainForm.dataProcess.Value[filterPos, DATA_PARAM_LINK]; FInfo.mangaInfo.authors := MainForm.dataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; FInfo.mangaInfo.artists := MainForm.dataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; FInfo.mangaInfo.status := MainForm.dataProcess.Value[filterPos, DATA_PARAM_STATUS]; From 9286b58ba7c07a9060c74e2f6f441847c76ddabf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 20 Jul 2016 13:55:23 +0800 Subject: [PATCH 1321/2794] updated to lazarus trunk that use lrj --- mangadownloader/forms/frmAccountManager.lrj | 10 + mangadownloader/forms/frmAccountSet.lrj | 11 + mangadownloader/forms/frmCustomColor.lfm | 4 + mangadownloader/forms/frmCustomColor.lrj | 7 + mangadownloader/forms/frmDropTarget.lfm | 2 +- mangadownloader/forms/frmDropTarget.lrj | 5 + mangadownloader/forms/frmImportFavorites.lrj | 8 + mangadownloader/forms/frmMain.lrj | 291 ++++++++++++++++++ mangadownloader/forms/frmNewChapter.lrj | 6 + mangadownloader/forms/frmUpdateDialog.lrj | 6 + .../forms/frmWebsiteOptionAdvanced.lrj | 22 ++ mangadownloader/forms/frmWebsiteSelection.lrj | 3 + mangadownloader/languages/fmd.en.po | 1 + mangadownloader/languages/fmd.id_ID.po | 1 + updater/languages/updater.en.po | 9 +- updater/languages/updater.id_ID.po | 9 +- updater/languages/updater.po | 4 + updater/uMain.lrj | 6 + updater/uMessage.lfm | 4 +- updater/uMessage.lrj | 3 + 20 files changed, 403 insertions(+), 9 deletions(-) create mode 100644 mangadownloader/forms/frmAccountManager.lrj create mode 100644 mangadownloader/forms/frmAccountSet.lrj create mode 100644 mangadownloader/forms/frmCustomColor.lrj create mode 100644 mangadownloader/forms/frmDropTarget.lrj create mode 100644 mangadownloader/forms/frmImportFavorites.lrj create mode 100644 mangadownloader/forms/frmMain.lrj create mode 100644 mangadownloader/forms/frmNewChapter.lrj create mode 100644 mangadownloader/forms/frmUpdateDialog.lrj create mode 100644 mangadownloader/forms/frmWebsiteOptionAdvanced.lrj create mode 100644 mangadownloader/forms/frmWebsiteSelection.lrj create mode 100644 updater/uMain.lrj create mode 100644 updater/uMessage.lrj diff --git a/mangadownloader/forms/frmAccountManager.lrj b/mangadownloader/forms/frmAccountManager.lrj new file mode 100644 index 000000000..ec0fc437e --- /dev/null +++ b/mangadownloader/forms/frmAccountManager.lrj @@ -0,0 +1,10 @@ +{"version":1,"strings":[ +{"hash":265040957,"name":"taccountmanagerform.caption","sourcebytes":[65,99,99,111,117,110,116,77,97,110,97,103,101,114,70,111,114,109],"value":"AccountManagerForm"}, +{"hash":78392485,"name":"taccountmanagerform.btdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, +{"hash":310020,"name":"taccountmanagerform.btedit.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, +{"hash":18340,"name":"taccountmanagerform.btadd.caption","sourcebytes":[65,100,100],"value":"Add"}, +{"hash":146640072,"name":"taccountmanagerform.btrefresh.caption","sourcebytes":[82,101,102,114,101,115,104],"value":"Refresh"}, +{"hash":230269173,"name":"taccountmanagerform.vtaccountlist.header.columns[1].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":164185077,"name":"taccountmanagerform.vtaccountlist.header.columns[2].text","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, +{"hash":95062979,"name":"taccountmanagerform.vtaccountlist.header.columns[3].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"} +]} diff --git a/mangadownloader/forms/frmAccountSet.lrj b/mangadownloader/forms/frmAccountSet.lrj new file mode 100644 index 000000000..ee75e64e2 --- /dev/null +++ b/mangadownloader/forms/frmAccountSet.lrj @@ -0,0 +1,11 @@ +{"version":1,"strings":[ +{"hash":127560724,"name":"taccountsetform.caption","sourcebytes":[65,99,99,111,117,110,116],"value":"Account"}, +{"hash":230269173,"name":"taccountsetform.label1.caption","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":164185077,"name":"taccountsetform.label2.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, +{"hash":145417188,"name":"taccountsetform.label3.caption","sourcebytes":[80,97,115,115,119,111,114,100],"value":"Password"}, +{"hash":164185077,"name":"taccountsetform.edusername.texthint","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, +{"hash":145417188,"name":"taccountsetform.edpassword.texthint","sourcebytes":[80,97,115,115,119,111,114,100],"value":"Password"}, +{"hash":22827444,"name":"taccountsetform.ckshowpassword.caption","sourcebytes":[83,104,111,119,32,112,97,115,115,119,111,114,100],"value":"Show password"}, +{"hash":1371,"name":"taccountsetform.btok.caption","sourcebytes":[79,107],"value":"Ok"}, +{"hash":77089212,"name":"taccountsetform.btcancel.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"} +]} diff --git a/mangadownloader/forms/frmCustomColor.lfm b/mangadownloader/forms/frmCustomColor.lfm index 19adba964..15b4b4559 100644 --- a/mangadownloader/forms/frmCustomColor.lfm +++ b/mangadownloader/forms/frmCustomColor.lfm @@ -68,6 +68,7 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 @@ -99,6 +100,7 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 @@ -130,6 +132,7 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 @@ -161,6 +164,7 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 + Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 diff --git a/mangadownloader/forms/frmCustomColor.lrj b/mangadownloader/forms/frmCustomColor.lrj new file mode 100644 index 000000000..5cd228657 --- /dev/null +++ b/mangadownloader/forms/frmCustomColor.lrj @@ -0,0 +1,7 @@ +{"version":1,"strings":[ +{"hash":164667949,"name":"tcustomcolorform.caption","sourcebytes":[67,117,115,116,111,109,67,111,108,111,114,70,111,114,109],"value":"CustomColorForm"}, +{"hash":257144884,"name":"tcustomcolorform.tsbasiclist.caption","sourcebytes":[66,97,115,105,99,32,108,105,115,116],"value":"Basic list"}, +{"hash":221522148,"name":"tcustomcolorform.tsmangalist.caption","sourcebytes":[77,97,110,103,97,32,108,105,115,116],"value":"Manga list"}, +{"hash":117201380,"name":"tcustomcolorform.tsfavoritelist.caption","sourcebytes":[70,97,118,111,114,105,116,101,32,108,105,115,116],"value":"Favorite list"}, +{"hash":148485892,"name":"tcustomcolorform.tschapterlist.caption","sourcebytes":[67,104,97,112,116,101,114,32,108,105,115,116],"value":"Chapter list"} +]} diff --git a/mangadownloader/forms/frmDropTarget.lfm b/mangadownloader/forms/frmDropTarget.lfm index 6363101b5..f5067a276 100644 --- a/mangadownloader/forms/frmDropTarget.lfm +++ b/mangadownloader/forms/frmDropTarget.lfm @@ -18,7 +18,7 @@ object FormDropTarget: TFormDropTarget OnMouseMove = FormMouseMove OnMouseUp = FormMouseUp OnShow = FormShow - LCLVersion = '1.5' + LCLVersion = '1.7' object shBorder: TShape Left = 0 Height = 156 diff --git a/mangadownloader/forms/frmDropTarget.lrj b/mangadownloader/forms/frmDropTarget.lrj new file mode 100644 index 000000000..add1a15e6 --- /dev/null +++ b/mangadownloader/forms/frmDropTarget.lrj @@ -0,0 +1,5 @@ +{"version":1,"strings":[ +{"hash":29393692,"name":"tformdroptarget.midownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, +{"hash":215882787,"name":"tformdroptarget.miaddtofavorites.caption","sourcebytes":[65,100,100,32,116,111,32,102,97,118,111,114,105,116,101,115],"value":"Add to favorites"}, +{"hash":44709525,"name":"tformdroptarget.miclose.caption","sourcebytes":[38,67,108,111,115,101],"value":"&Close"} +]} diff --git a/mangadownloader/forms/frmImportFavorites.lrj b/mangadownloader/forms/frmImportFavorites.lrj new file mode 100644 index 000000000..34c413e06 --- /dev/null +++ b/mangadownloader/forms/frmImportFavorites.lrj @@ -0,0 +1,8 @@ +{"version":1,"strings":[ +{"hash":131016830,"name":"timportfavorites.caption","sourcebytes":[73,109,112,111,114,116,32,108,105,115,116,32,46,46,46],"value":"Import list ..."}, +{"hash":230544090,"name":"timportfavorites.lbselectsoftware.caption","sourcebytes":[83,111,102,116,119,97,114,101,58],"value":"Software:"}, +{"hash":148035954,"name":"timportfavorites.cbsoftware.text","sourcebytes":[68,111,109,100,111,109,115,111,102,116,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Domdomsoft Manga Downloader"}, +{"hash":161483657,"name":"timportfavorites.edpath.texthint","sourcebytes":[80,97,116,104,32,116,111,32,116,104,101,32,115,111,102,116,119,97,114,101,32,40,101,46,103,46,32,67,58,92,77,97,110,103,97,68,111,119,110,108,111,97,100,101,114,41],"value":"Path to the software (e.g. C:\\MangaDownloader)"}, +{"hash":11067,"name":"timportfavorites.btimport.caption","sourcebytes":[38,79,75],"value":"&OK"}, +{"hash":77089212,"name":"timportfavorites.btcancel.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"} +]} diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj new file mode 100644 index 000000000..ad5ef1bb0 --- /dev/null +++ b/mangadownloader/forms/frmMain.lrj @@ -0,0 +1,291 @@ +{"version":1,"strings":[ +{"hash":57972706,"name":"tmainform.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Free Manga Downloader"}, +{"hash":240327891,"name":"tmainform.tsdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, +{"hash":5473489,"name":"tmainform.vtdownload.header.columns[0].text","sourcebytes":[77,97,110,103,97],"value":"Manga"}, +{"hash":95062979,"name":"tmainform.vtdownload.header.columns[1].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, +{"hash":157190611,"name":"tmainform.vtdownload.header.columns[2].text","sourcebytes":[80,114,111,103,114,101,115,115],"value":"Progress"}, +{"hash":131060021,"name":"tmainform.vtdownload.header.columns[3].text","sourcebytes":[84,114,97,110,115,102,101,114,32,114,97,116,101],"value":"Transfer rate"}, +{"hash":230269173,"name":"tmainform.vtdownload.header.columns[4].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":160200703,"name":"tmainform.vtdownload.header.columns[5].text","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, +{"hash":4696756,"name":"tmainform.vtdownload.header.columns[6].text","sourcebytes":[65,100,100,101,100],"value":"Added"}, +{"hash":204655756,"name":"tmainform.tbdownloadresumeall.caption","sourcebytes":[82,101,115,117,109,101,32,65,108,108],"value":"Resume All"}, +{"hash":190989196,"name":"tmainform.tbdownloadstopall.caption","sourcebytes":[83,116,111,112,32,65,108,108],"value":"Stop All"}, +{"hash":235571507,"name":"tmainform.tbdownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, +{"hash":221371535,"name":"tmainform.tsinformation.caption","sourcebytes":[77,97,110,103,97,32,73,110,102,111],"value":"Manga Info"}, +{"hash":60460069,"name":"tmainform.edurl.texthint","sourcebytes":[73,110,112,117,116,32,85,82,76,32,104,101,114,101],"value":"Input URL here"}, +{"hash":115683780,"name":"tmainform.btdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100],"value":"Download"}, +{"hash":70044827,"name":"tmainform.cbaddasstopped.caption","sourcebytes":[65,100,100,32,116,111,32,100,111,119,110,108,111,97,100,32,108,105,115,116,32,97,115,32,115,116,111,112,112,101,100,32,116,97,115,107],"value":"Add to download list as stopped task"}, +{"hash":119380261,"name":"tmainform.btreadonline.caption","sourcebytes":[82,101,97,100,32,111,110,108,105,110,101],"value":"Read online"}, +{"hash":215882787,"name":"tmainform.btaddtofavorites.caption","sourcebytes":[65,100,100,32,116,111,32,102,97,118,111,114,105,116,101,115],"value":"Add to favorites"}, +{"hash":147292346,"name":"tmainform.lbsaveto.caption","sourcebytes":[83,97,118,101,32,116,111,58],"value":"Save to:"}, +{"hash":160200703,"name":"tmainform.edsaveto.texthint","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, +{"hash":80755394,"name":"tmainform.edfiltermangainfochapters.texthint","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":80755394,"name":"tmainform.tsfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":236121459,"name":"tmainform.lbfiltercustomgenres.caption","sourcebytes":[67,117,115,116,111,109,32,71,101,110,114,101,115],"value":"Custom Genres"}, +{"hash":58090881,"name":"tmainform.edcustomgenres.texthint","sourcebytes":[73,110,112,117,116,32,99,117,115,116,111,109,32,103,101,110,114,101,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,99,111,109,109,97],"value":"Input custom genres, separated by comma"}, +{"hash":255353502,"name":"tmainform.lbfilterhint.hint","sourcebytes":[71,101,110,114,101,115,58,13,10,45,32,67,104,101,99,107,101,100,58,32,73,110,99,108,117,100,101,32,116,104,105,115,32,103,101,110,114,101,46,13,10,45,32,85,110,99,104,101,99,107,101,100,58,32,69,120,99,108,117,100,101,32,116,104,105,115,32,103,101,110,114,101,46,13,10,45,32,71,114,97,121,101,100,58,32,68,111,101,115,110,39,116,32,109,97,116,116,101,114,46,13,10,13,10,67,117,115,116,111,109,32,71,101,110,114,101,115,58,13,10,45,32,83,101,112,97,114,97,116,101,32,109,117,108,116,105,112,108,101,32,103,101,110,114,101,115,32,119,105,116,104,32,39,44,39,46,13,10,45,32,69,120,99,108,117,100,101,32,97,32,103,101,110,114,101,32,98,121,32,112,108,97,99,105,110,103,32,39,33,39,32,111,114,32,39,45,39,32,97,116,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,97,32,103,101,110,114,101,46,13,10,45,32,69,120,97,109,112,108,101,58,32,65,100,118,101,110,116,117,114,101,44,33,69,99,99,104,105,44,67,111,109,101,100,121,46],"value":"Genres:\r\n- Checked: Include this genre.\r\n- Unchecked: Exclude this genre.\r\n- Grayed: Doesn't matter.\r\n\r\nCustom Genres:\r\n- Separate multiple genres with ','.\r\n- Exclude a genre by placing '!' or '-' at the beginning of a genre.\r\n- Example: Adventure,!Ecchi,Comedy."}, +{"hash":24397,"name":"tmainform.lbfilterhint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":5966629,"name":"tmainform.lbfiltertitle.caption","sourcebytes":[84,105,116,108,101],"value":"Title"}, +{"hash":5966629,"name":"tmainform.edfiltertitle.texthint","sourcebytes":[84,105,116,108,101],"value":"Title"}, +{"hash":76328802,"name":"tmainform.lbfilterauthors.caption","sourcebytes":[65,117,116,104,111,114],"value":"Author"}, +{"hash":76328802,"name":"tmainform.edfilterauthors.texthint","sourcebytes":[65,117,116,104,111,114],"value":"Author"}, +{"hash":76132516,"name":"tmainform.lbfilterartists.caption","sourcebytes":[65,114,116,105,115,116],"value":"Artist"}, +{"hash":76132516,"name":"tmainform.edfilterartists.texthint","sourcebytes":[65,114,116,105,115,116],"value":"Artist"}, +{"hash":95062979,"name":"tmainform.lbfilterstatus.caption","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, +{"hash":70608014,"name":"tmainform.cbfilterstatus.text","sourcebytes":[60,110,111,110,101,62],"value":"<none>"}, +{"hash":180631753,"name":"tmainform.lbfiltersummary.caption","sourcebytes":[83,117,109,109,97,114,121],"value":"Summary"}, +{"hash":65353321,"name":"tmainform.edfiltersummary.texthint","sourcebytes":[80,97,114,116,32,111,102,32,115,117,109,109,97,114,121],"value":"Part of summary"}, +{"hash":201437348,"name":"tmainform.rbone.caption","sourcebytes":[72,97,118,101,32,111,110,101,32,111,102,32,103,101,110,114,101,115,32,99,104,101,99,107,101,100],"value":"Have one of genres checked"}, +{"hash":51044468,"name":"tmainform.rball.caption","sourcebytes":[72,97,118,101,32,97,108,108,32,103,101,110,114,101,32,99,104,101,99,107,101,100],"value":"Have all genre checked"}, +{"hash":81924321,"name":"tmainform.cbonlynew.caption","sourcebytes":[83,101,97,114,99,104,32,111,110,108,121,32,110,101,119,32,109,97,110,103,97],"value":"Search only new manga"}, +{"hash":36938179,"name":"tmainform.cbsearchfromallsites.caption","sourcebytes":[83,101,97,114,99,104,32,105,110,32,97,108,108,32,109,97,110,103,97,32,115,105,116,101,115],"value":"Search in all manga sites"}, +{"hash":84262158,"name":"tmainform.cbuseregexpr.caption","sourcebytes":[82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110],"value":"Regular Expression"}, +{"hash":111905342,"name":"tmainform.ckfilteraction.hint","sourcebytes":[65,32,119,111,114,107,32,116,121,112,105,99,97,108,108,121,32,100,101,112,105,99,116,105,110,103,32,102,105,103,104,116,105,110,103,44,32,118,105,111,108,101,110,99,101,44,32,99,104,97,111,115,44,32,97,110,100,32,102,97,115,116,32,112,97,99,101,100,32,109,111,116,105,111,110,46],"value":"A work typically depicting fighting, violence, chaos, and fast paced motion."}, +{"hash":75149406,"name":"tmainform.ckfilteraction.caption","sourcebytes":[65,99,116,105,111,110],"value":"Action"}, +{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and\/or graphic sexual content and nudity."}, +{"hash":4701236,"name":"tmainform.ckfilteradult.caption","sourcebytes":[65,100,117,108,116],"value":"Adult"}, +{"hash":267284606,"name":"tmainform.ckfilteradventure.hint","sourcebytes":[73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,111,114,121,32,103,111,101,115,32,111,110,32,97,32,116,114,105,112,32,111,114,32,97,108,111,110,103,32,116,104,97,116,32,108,105,110,101,44,32,121,111,117,114,32,98,101,115,116,32,98,101,116,32,105,115,32,116,104,97,116,32,105,116,32,105,115,32,97,110,32,97,100,118,101,110,116,117,114,101,32,109,97,110,103,97,46,32,79,116,104,101,114,119,105,115,101,44,32,105,116,39,115,32,117,112,32,116,111,32,121,111,117,114,32,112,101,114,115,111,110,97,108,32,112,114,101,106,117,100,105,99,101,32,111,110,32,116,104,105,115,32,99,97,115,101,46],"value":"If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case."}, +{"hash":214301493,"name":"tmainform.ckfilteradventure.caption","sourcebytes":[65,100,118,101,110,116,117,114,101],"value":"Adventure"}, +{"hash":11846766,"name":"tmainform.ckfiltercomedy.hint","sourcebytes":[65,32,100,114,97,109,97,116,105,99,32,119,111,114,107,32,116,104,97,116,32,105,115,32,108,105,103,104,116,32,97,110,100,32,111,102,116,101,110,32,104,117,109,111,114,111,117,115,32,111,114,32,115,97,116,105,114,105,99,97,108,32,105,110,32,116,111,110,101,32,97,110,100,32,116,104,97,116,32,117,115,117,97,108,108,121,32,99,111,110,116,97,105,110,115,32,97,32,104,97,112,112,121,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,104,101,109,97,116,105,99,32,99,111,110,102,108,105,99,116,46],"value":"A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict."}, +{"hash":78003129,"name":"tmainform.ckfiltercomedy.caption","sourcebytes":[67,111,109,101,100,121],"value":"Comedy"}, +{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga\/anime."}, +{"hash":202379913,"name":"tmainform.ckfilterdoujinshi.caption","sourcebytes":[68,111,117,106,105,110,115,104,105],"value":"Doujinshi"}, +{"hash":221112350,"name":"tmainform.ckfilterdrama.hint","sourcebytes":[65,32,119,111,114,107,32,109,101,97,110,116,32,116,111,32,98,114,105,110,103,32,111,110,32,97,110,32,101,109,111,116,105,111,110,97,108,32,114,101,115,112,111,110,115,101,44,32,115,117,99,104,32,97,115,32,105,110,115,116,105,108,108,105,110,103,32,115,97,100,110,101,115,115,32,111,114,32,116,101,110,115,105,111,110,46],"value":"A work meant to bring on an emotional response, such as instilling sadness or tension."}, +{"hash":4950065,"name":"tmainform.ckfilterdrama.caption","sourcebytes":[68,114,97,109,97],"value":"Drama"}, +{"hash":33591486,"name":"tmainform.ckfilterechi.hint","sourcebytes":[80,111,115,115,105,98,108,121,32,116,104,101,32,108,105,110,101,32,98,101,116,119,101,101,110,32,104,101,110,116,97,105,32,97,110,100,32,110,111,110,45,104,101,110,116,97,105,44,32,101,99,99,104,105,32,117,115,117,97,108,108,121,32,114,101,102,101,114,115,32,116,111,32,102,97,110,115,101,114,118,105,99,101,32,112,117,116,32,105,110,32,116,111,32,97,116,116,114,97,99,116,32,97,32,99,101,114,116,97,105,110,32,103,114,111,117,112,32,111,102,32,102,97,110,115,46],"value":"Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans."}, +{"hash":4954601,"name":"tmainform.ckfilterechi.caption","sourcebytes":[69,99,99,104,105],"value":"Ecchi"}, +{"hash":149295550,"name":"tmainform.ckfilterfantasy.hint","sourcebytes":[65,110,121,116,104,105,110,103,32,116,104,97,116,32,105,110,118,111,108,118,101,115,44,32,98,117,116,32,110,111,116,32,108,105,109,105,116,101,100,32,116,111,44,32,109,97,103,105,99,44,32,100,114,101,97,109,32,119,111,114,108,100,44,32,97,110,100,32,102,97,105,114,121,32,116,97,108,101,115,46],"value":"Anything that involves, but not limited to, magic, dream world, and fairy tales."}, +{"hash":210086121,"name":"tmainform.ckfilterfantasy.caption","sourcebytes":[70,97,110,116,97,115,121],"value":"Fantasy"}, +{"hash":124460254,"name":"tmainform.ckfiltergenderbender.hint","sourcebytes":[71,105,114,108,115,32,100,114,101,115,115,105,110,103,32,117,112,32,97,115,32,103,117,121,115,44,32,103,117,121,115,32,100,114,101,115,115,105,110,103,32,117,112,32,97,115,32,103,105,114,108,115,46,13,10,71,117,121,115,32,116,117,114,110,105,110,103,32,105,110,116,111,32,103,105,114,108,115,44,32,103,105,114,108,115,32,116,117,114,110,105,110,103,32,105,110,116,111,32,103,117,121,115,46],"value":"Girls dressing up as guys, guys dressing up as girls.\r\nGuys turning into girls, girls turning into guys."}, +{"hash":156296898,"name":"tmainform.ckfiltergenderbender.caption","sourcebytes":[71,101,110,100,101,114,32,66,101,110,100,101,114],"value":"Gender Bender"}, +{"hash":237637310,"name":"tmainform.ckfilterharem.hint","sourcebytes":[65,32,115,101,114,105,101,115,32,105,110,118,111,108,118,105,110,103,32,111,110,101,32,109,97,108,101,32,99,104,97,114,97,99,116,101,114,32,97,110,100,32,109,97,110,121,32,102,101,109,97,108,101,32,99,104,97,114,97,99,116,101,114,115,32,40,117,115,117,97,108,108,121,32,97,116,116,114,97,99,116,101,100,32,116,111,32,116,104,101,32,109,97,108,101,32,99,104,97,114,97,99,116,101,114,41,46,32,65,32,82,101,118,101,114,115,101,32,72,97,114,101,109,32,105,115,32,119,104,101,110,32,116,104,101,32,103,101,110,100,101,114,115,32,97,114,101,32,114,101,118,101,114,115,101,100,46],"value":"A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed."}, +{"hash":5146813,"name":"tmainform.ckfilterharem.caption","sourcebytes":[72,97,114,101,109],"value":"Harem"}, +{"hash":82598521,"name":"tmainform.ckfilterhentai.hint","sourcebytes":[72,101,110,116,97,105],"value":"Hentai"}, +{"hash":82598521,"name":"tmainform.ckfilterhentai.caption","sourcebytes":[72,101,110,116,97,105],"value":"Hentai"}, +{"hash":159671182,"name":"tmainform.ckfilterhistorical.hint","sourcebytes":[72,97,118,105,110,103,32,116,111,32,100,111,32,119,105,116,104,32,111,108,100,32,111,114,32,97,110,99,105,101,110,116,32,116,105,109,101,115,46],"value":"Having to do with old or ancient times."}, +{"hash":191629788,"name":"tmainform.ckfilterhistorical.caption","sourcebytes":[72,105,115,116,111,114,105,99,97,108],"value":"Historical"}, +{"hash":69062670,"name":"tmainform.ckfilterhorror.hint","sourcebytes":[65,32,112,97,105,110,102,117,108,32,101,109,111,116,105,111,110,32,111,102,32,102,101,97,114,44,32,100,114,101,97,100,44,32,97,110,100,32,97,98,104,111,114,114,101,110,99,101,59,32,97,32,115,104,117,100,100,101,114,105,110,103,32,119,105,116,104,32,116,101,114,114,111,114,32,97,110,100,32,100,101,116,101,115,116,97,116,105,111,110,59,32,116,104,101,32,102,101,101,108,105,110,103,32,105,110,115,112,105,114,101,100,32,98,121,32,115,111,109,101,116,104,105,110,103,32,102,114,105,103,104,116,102,117,108,32,97,110,100,32,115,104,111,99,107,105,110,103,46],"value":"A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking."}, +{"hash":83269986,"name":"tmainform.ckfilterhorror.caption","sourcebytes":[72,111,114,114,111,114],"value":"Horror"}, +{"hash":76590862,"name":"tmainform.ckfilterjosei.hint","sourcebytes":[76,105,116,101,114,97,108,108,121,32,34,87,111,109,97,110,34,46,32,84,97,114,103,101,116,115,32,119,111,109,101,110,32,49,56,45,51,48,46,32,70,101,109,97,108,101,32,101,113,117,105,118,97,108,101,110,116,32,116,111,32,115,101,105,110,101,110,46,32,85,110,108,105,107,101,32,115,104,111,117,106,111,32,116,104,101,32,114,111,109,97,110,99,101,32,105,115,32,109,111,114,101,32,114,101,97,108,105,115,116,105,99,32,97,110,100,32,108,101,115,115,32,105,100,101,97,108,105,122,101,100,46,32,84,104,101,32,115,116,111,114,121,116,101,108,108,105,110,103,32,105,115,32,109,111,114,101,32,101,120,112,108,105,99,105,116,32,97,110,100,32,109,97,116,117,114,101,46],"value":"Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature."}, +{"hash":5335481,"name":"tmainform.ckfilterjosei.caption","sourcebytes":[74,111,115,101,105],"value":"Josei"}, +{"hash":76842110,"name":"tmainform.ckfilterlolicon.hint","sourcebytes":[82,101,112,114,101,115,101,110,116,105,110,103,32,97,32,115,101,120,117,97,108,32,97,116,116,114,97,99,116,105,111,110,32,116,111,32,121,111,117,110,103,32,111,114,32,117,110,100,101,114,45,97,103,101,32,103,105,114,108,115,46],"value":"Representing a sexual attraction to young or under-age girls."}, +{"hash":56818190,"name":"tmainform.ckfilterlolicon.caption","sourcebytes":[76,111,108,105,99,111,110],"value":"Lolicon"}, +{"hash":104001182,"name":"tmainform.ckfiltermartialarts.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,109,97,114,116,105,97,108,32,97,114,116,115,32,114,101,108,97,116,101,100,46,32,65,110,121,32,111,102,32,115,101,118,101,114,97,108,32,97,114,116,115,32,111,102,32,99,111,109,98,97,116,32,111,114,32,115,101,108,102,45,100,101,102,101,110,115,101,44,32,115,117,99,104,32,97,115,32,97,105,107,105,100,111,44,32,107,97,114,97,116,101,44,32,106,117,100,111,44,32,111,114,32,116,97,101,107,119,111,110,100,111,44,32,107,101,110,100,111,44,32,102,101,110,99,105,110,103,44,32,97,110,100,32,115,111,32,111,110,32,97,110,100,32,115,111,32,102,111,114,116,104,46],"value":"As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth."}, +{"hash":47977283,"name":"tmainform.ckfiltermartialarts.caption","sourcebytes":[77,97,114,116,105,97,108,32,65,114,116,115],"value":"Martial Arts"}, +{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and\/or strong language."}, +{"hash":87604357,"name":"tmainform.ckfiltermature.caption","sourcebytes":[77,97,116,117,114,101],"value":"Mature"}, +{"hash":187133582,"name":"tmainform.ckfiltermecha.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,118,111,108,118,105,110,103,32,97,110,100,32,117,115,117,97,108,108,121,32,99,111,110,99,101,110,116,114,97,116,105,110,103,32,111,110,32,97,108,108,32,116,121,112,101,115,32,111,102,32,108,97,114,103,101,32,114,111,98,111,116,105,99,32,109,97,99,104,105,110,101,115,46],"value":"A work involving and usually concentrating on all types of large robotic machines."}, +{"hash":5487073,"name":"tmainform.ckfiltermecha.caption","sourcebytes":[77,101,99,104,97],"value":"Mecha"}, +{"hash":80345388,"name":"tmainform.ckfiltermusical.hint","sourcebytes":[77,117,115,105,99,97,108],"value":"Musical"}, +{"hash":80345388,"name":"tmainform.ckfiltermusical.caption","sourcebytes":[77,117,115,105,99,97,108],"value":"Musical"}, +{"hash":80699502,"name":"tmainform.ckfiltermystery.hint","sourcebytes":[85,115,117,97,108,108,121,32,97,110,32,117,110,101,120,112,108,97,105,110,101,100,32,101,118,101,110,116,32,111,99,99,117,114,115,44,32,97,110,100,32,116,104,101,32,109,97,105,110,32,112,114,111,116,97,103,111,110,105,115,116,32,97,116,116,101,109,112,116,115,32,116,111,32,102,105,110,100,32,111,117,116,32,119,104,97,116,32,99,97,117,115,101,100,32,105,116,46],"value":"Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it."}, +{"hash":84585673,"name":"tmainform.ckfiltermystery.caption","sourcebytes":[77,121,115,116,101,114,121],"value":"Mystery"}, +{"hash":140769566,"name":"tmainform.ckfilterpsychological.hint","sourcebytes":[85,115,117,97,108,108,121,32,100,101,97,108,115,32,119,105,116,104,32,116,104,101,32,112,104,105,108,111,115,111,112,104,121,32,111,102,32,97,32,115,116,97,116,101,32,111,102,32,109,105,110,100,44,32,105,110,32,109,111,115,116,32,99,97,115,101,115,32,100,101,116,97,105,108,105,110,103,32,97,98,110,111,114,109,97,108,32,112,115,121,99,104,111,108,111,103,121,46],"value":"Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology."}, +{"hash":116549228,"name":"tmainform.ckfilterpsychological.caption","sourcebytes":[80,115,121,99,104,111,108,111,103,105,99,97,108],"value":"Psychological"}, +{"hash":6796286,"name":"tmainform.ckfilterromance.hint","sourcebytes":[65,110,121,32,108,111,118,101,32,114,101,108,97,116,101,100,32,115,116,111,114,121,46,32,87,101,32,119,105,108,108,32,100,101,102,105,110,101,32,108,111,118,101,32,97,115,32,98,101,116,119,101,101,110,32,109,97,110,32,97,110,100,32,119,111,109,97,110,32,105,110,32,116,104,105,115,32,99,97,115,101,46,32,79,116,104,101,114,32,116,104,97,110,32,116,104,97,116,44,32,105,116,32,105,115,32,117,112,32,116,111,32,121,111,117,114,32,111,119,110,32,105,109,97,103,105,110,97,116,105,111,110,32,111,102,32,119,104,97,116,32,108,111,118,101,32,105,115,46],"value":"Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is."}, +{"hash":157516997,"name":"tmainform.ckfilterromance.caption","sourcebytes":[82,111,109,97,110,99,101],"value":"Romance"}, +{"hash":101821054,"name":"tmainform.ckfilterschoollife.hint","sourcebytes":[72,97,118,105,110,103,32,97,32,109,97,106,111,114,32,115,101,116,116,105,110,103,32,111,102,32,116,104,101,32,115,116,111,114,121,32,100,101,97,108,32,119,105,116,104,32,115,111,109,101,32,116,121,112,101,32,111,102,32,115,99,104,111,111,108,46],"value":"Having a major setting of the story deal with some type of school."}, +{"hash":96383141,"name":"tmainform.ckfilterschoollife.caption","sourcebytes":[83,99,104,111,111,108,32,76,105,102,101],"value":"School Life"}, +{"hash":119378158,"name":"tmainform.ckfilterscifi.hint","sourcebytes":[83,104,111,114,116,32,102,111,114,32,115,99,105,101,110,99,101,32,102,105,99,116,105,111,110,44,32,116,104,101,115,101,32,119,111,114,107,115,32,105,110,118,111,108,118,101,32,116,119,105,115,116,115,32,111,110,32,116,101,99,104,110,111,108,111,103,121,32,97,110,100,32,111,116,104,101,114,32,115,99,105,101,110,99,101,32,114,101,108,97,116,101,100,32,112,104,101,110,111,109,101,110,97,32,119,104,105,99,104,32,97,114,101,32,99,111,110,116,114,97,114,121,32,111,114,32,115,116,114,101,116,99,104,101,115,32,111,102,32,116,104,101,32,109,111,100,101,114,110,32,100,97,121,32,115,99,105,101,110,116,105,102,105,99,32,119,111,114,108,100,46],"value":"Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world."}, +{"hash":93962697,"name":"tmainform.ckfilterscifi.caption","sourcebytes":[83,99,105,45,70,105],"value":"Sci-Fi"}, +{"hash":1010254,"name":"tmainform.ckfilterseinen.hint","sourcebytes":[70,114,111,109,32,71,111,111,103,108,101,58,32,83,101,105,110,101,110,32,109,101,97,110,115,32,39,121,111,117,110,103,32,77,97,110,39,46,32,77,97,110,103,97,32,97,110,100,32,97,110,105,109,101,32,116,104,97,116,32,115,112,101,99,105,102,105,99,97,108,108,121,32,116,97,114,103,101,116,115,32,121,111,117,110,103,32,97,100,117,108,116,32,109,97,108,101,115,32,97,114,111,117,110,100,32,116,104,101,32,97,103,101,115,32,111,102,32,49,56,32,116,111,32,50,53,32,97,114,101,32,115,101,105,110,101,110,32,116,105,116,108,101,115,46,32,84,104,101,32,115,116,111,114,105,101,115,32,105,110,32,115,101,105,110,101,110,32,119,111,114,107,115,32,97,112,112,101,97,108,32,116,111,32,117,110,105,118,101,114,115,105,116,121,32,115,116,117,100,101,110,116,115,32,97,110,100,32,116,104,111,115,101,32,105,110,32,116,104,101,32,119,111,114,107,105,110,103,32,119,111,114,108,100,46,32,84,121,112,105,99,97,108,108,121,32,116,104,101,32,115,116,111,114,121,32,108,105,110,101,115,32,100,101,97,108,32,119,105,116,104,32,116,104,101,32,105,115,115,117,101,115,32,111,102,32,97,100,117,108,116,104,111,111,100,46],"value":"From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood."}, +{"hash":94110910,"name":"tmainform.ckfilterseinen.caption","sourcebytes":[83,101,105,110,101,110],"value":"Seinen"}, +{"hash":38682414,"name":"tmainform.ckfiltershotacon.hint","sourcebytes":[82,101,112,114,101,115,101,110,116,105,110,103,32,97,32,115,101,120,117,97,108,32,97,116,116,114,97,99,116,105,111,110,32,116,111,32,121,111,117,110,103,32,111,114,32,117,110,100,101,114,45,97,103,101,32,98,111,121,115,46],"value":"Representing a sexual attraction to young or under-age boys."}, +{"hash":258637262,"name":"tmainform.ckfiltershotacon.caption","sourcebytes":[83,104,111,116,97,99,111,110],"value":"Shotacon"}, +{"hash":153596830,"name":"tmainform.ckfiltershoujo.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,102,101,109,97,108,101,115,46,32,85,115,117,97,108,108,121,32,105,110,118,111,108,118,101,115,32,97,32,108,111,116,32,111,102,32,114,111,109,97,110,99,101,32,97,110,100,32,115,116,114,111,110,103,32,99,104,97,114,97,99,116,101,114,32,100,101,118,101,108,111,112,109,101,110,116,46],"value":"A work intended and primarily written for females. Usually involves a lot of romance and strong character development."}, +{"hash":94333967,"name":"tmainform.ckfiltershoujo.caption","sourcebytes":[83,104,111,117,106,111],"value":"Shoujo"}, +{"hash":171132846,"name":"tmainform.ckfiltershoujoai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,117,114,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,71,105,114,108,39,39,115,32,76,111,118,101,34,44,32,115,111,32,116,111,32,115,112,101,97,107,46],"value":"Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak."}, +{"hash":113331593,"name":"tmainform.ckfiltershoujoai.caption","sourcebytes":[83,104,111,117,106,111,32,65,105],"value":"Shoujo Ai"}, +{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and\/or violence."}, +{"hash":167167214,"name":"tmainform.ckfiltershounen.caption","sourcebytes":[83,104,111,117,110,101,110],"value":"Shounen"}, +{"hash":19597467,"name":"tmainform.ckfiltershounenai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,97,111,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,66,111,121,39,39,115,32,76,111,118,101,34,194,157,44,32,115,111,32,116,111,32,115,112,101,97,107],"value":"Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\"\u009D, so to speak"}, +{"hash":206543641,"name":"tmainform.ckfiltershounenai.caption","sourcebytes":[83,104,111,117,110,101,110,32,65,105],"value":"Shounen Ai"}, +{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one\/many character(s). These challenges\/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, +{"hash":262977669,"name":"tmainform.ckfiltersliceoflife.caption","sourcebytes":[83,108,105,99,101,32,111,102,32,76,105,102,101],"value":"Slice of Life"}, +{"hash":68245006,"name":"tmainform.ckfiltersmut.hint","sourcebytes":[68,101,97,108,115,32,119,105,116,104,32,115,101,114,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,112,114,111,102,97,110,101,32,111,114,32,111,102,102,101,110,115,105,118,101,44,32,112,97,114,116,105,99,117,108,97,114,108,121,32,119,105,116,104,32,114,101,103,97,114,100,115,32,116,111,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,46],"value":"Deals with series that are considered profane or offensive, particularly with regards to sexual content."}, +{"hash":369860,"name":"tmainform.ckfiltersmut.caption","sourcebytes":[83,109,117,116],"value":"Smut"}, +{"hash":176420878,"name":"tmainform.ckfiltersports.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,115,112,111,114,116,115,32,114,101,108,97,116,101,100,46,32,66,97,115,101,98,97,108,108,44,32,98,97,115,107,101,116,98,97,108,108,44,32,104,111,99,107,101,121,44,32,115,111,99,99,101,114,44,32,103,111,108,102,44,32,97,110,100,32,114,97,99,105,110,103,32,106,117,115,116,32,116,111,32,110,97,109,101,32,97,32,102,101,119,46],"value":"As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few."}, +{"hash":94857651,"name":"tmainform.ckfiltersports.caption","sourcebytes":[83,112,111,114,116,115],"value":"Sports"}, +{"hash":148813966,"name":"tmainform.ckfiltersupernatural.hint","sourcebytes":[85,115,117,97,108,108,121,32,101,110,116,97,105,108,115,32,97,109,97,122,105,110,103,32,97,110,100,32,117,110,101,120,112,108,97,105,110,101,100,32,112,111,119,101,114,115,32,111,114,32,101,118,101,110,116,115,32,119,104,105,99,104,32,100,101,102,121,32,116,104,101,32,108,97,119,115,32,111,102,32,112,104,121,115,105,99,115,46],"value":"Usually entails amazing and unexplained powers or events which defy the laws of physics."}, +{"hash":19375340,"name":"tmainform.ckfiltersupernatural.caption","sourcebytes":[83,117,112,101,114,110,97,116,117,114,97,108],"value":"Supernatural"}, +{"hash":134027038,"name":"tmainform.ckfiltertragedy.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,101,118,101,110,116,115,32,114,101,115,117,108,116,105,110,103,32,105,110,32,103,114,101,97,116,32,108,111,115,115,32,97,110,100,32,109,105,115,102,111,114,116,117,110,101,46],"value":"Contains events resulting in great loss and misfortune."}, +{"hash":193453033,"name":"tmainform.ckfiltertragedy.caption","sourcebytes":[84,114,97,103,101,100,121],"value":"Tragedy"}, +{"hash":67321502,"name":"tmainform.ckfilteryaoi.hint","sourcebytes":[84,104,105,115,32,119,111,114,107,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,115,32,105,110,116,105,109,97,116,101,32,114,101,108,97,116,105,111,110,115,104,105,112,115,32,98,101,116,119,101,101,110,32,109,101,110,46],"value":"This work usually involves intimate relationships between men."}, +{"hash":391257,"name":"tmainform.ckfilteryaoi.caption","sourcebytes":[89,97,111,105],"value":"Yaoi"}, +{"hash":65318926,"name":"tmainform.ckfilteryuri.hint","sourcebytes":[84,104,105,115,32,119,111,114,107,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,115,32,105,110,116,105,109,97,116,101,32,114,101,108,97,116,105,111,110,115,104,105,112,115,32,98,101,116,119,101,101,110,32,119,111,109,101,110,46],"value":"This work usually involves intimate relationships between women."}, +{"hash":396425,"name":"tmainform.ckfilteryuri.caption","sourcebytes":[89,117,114,105],"value":"Yuri"}, +{"hash":194714083,"name":"tmainform.ckfilterweebtons.hint","sourcebytes":[87,101,101,98,116,111,111,110,115],"value":"Weebtoons"}, +{"hash":194714083,"name":"tmainform.ckfilterweebtons.caption","sourcebytes":[87,101,101,98,116,111,111,110,115],"value":"Weebtoons"}, +{"hash":80755394,"name":"tmainform.btfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":235689698,"name":"tmainform.btremovefilterlarge.hint","sourcebytes":[82,101,109,111,118,101,32,102,105,108,116,101,114],"value":"Remove filter"}, +{"hash":235689698,"name":"tmainform.btremovefilterlarge.caption","sourcebytes":[82,101,109,111,118,101,32,102,105,108,116,101,114],"value":"Remove filter"}, +{"hash":103074421,"name":"tmainform.btfilterreset.caption","sourcebytes":[82,101,115,101,116,32,118,97,108,117,101],"value":"Reset value"}, +{"hash":225003075,"name":"tmainform.tsfavorites.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, +{"hash":165778738,"name":"tmainform.btfavoriteschecknewchapter.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Check for new chapter"}, +{"hash":35,"name":"tmainform.vtfavorites.header.columns[0].text","sourcebytes":[35],"value":"#"}, +{"hash":5966629,"name":"tmainform.vtfavorites.header.columns[1].text","sourcebytes":[84,105,116,108,101],"value":"Title"}, +{"hash":6579810,"name":"tmainform.vtfavorites.header.columns[2].text","sourcebytes":[67,117,114,114,101,110,116,32,99,104,97,112,116,101,114],"value":"Current chapter"}, +{"hash":230269173,"name":"tmainform.vtfavorites.header.columns[3].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":160200703,"name":"tmainform.vtfavorites.header.columns[4].text","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, +{"hash":154630084,"name":"tmainform.btfavoritesimport.caption","sourcebytes":[73,109,112,111,114,116,32,108,105,115,116],"value":"Import list"}, +{"hash":108725763,"name":"tmainform.tsoption.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, +{"hash":231000124,"name":"tmainform.tsgeneral.caption","sourcebytes":[71,101,110,101,114,97,108],"value":"General"}, +{"hash":189923241,"name":"tmainform.cboptionminimizetotray.caption","sourcebytes":[77,105,110,105,109,105,122,101,32,116,111,32,116,114,97,121],"value":"Minimize to tray"}, +{"hash":9911767,"name":"tmainform.cboptiononeinstanceonly.caption","sourcebytes":[80,101,114,109,105,116,32,111,110,108,121,32,111,110,101,32,70,77,68,32,114,117,110,110,105,110,103],"value":"Permit only one FMD running"}, +{"hash":251042137,"name":"tmainform.cboptionlivesearch.caption","sourcebytes":[69,110,97,98,108,101,32,108,105,118,101,32,115,101,97,114,99,104,32,40,115,108,111,119,32,111,110,32,108,111,110,103,32,108,105,115,116,41],"value":"Enable live search (slow on long list)"}, +{"hash":186997165,"name":"tmainform.gboptionexternal.caption","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109],"value":"External program"}, +{"hash":36189706,"name":"tmainform.lboptionexternal.caption","sourcebytes":[79,112,101,110,32,109,97,110,103,97,32,98,121,32,117,115,105,110,103,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,58],"value":"Open manga by using external program:"}, +{"hash":172309816,"name":"tmainform.edoptionexternalpath.texthint","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,112,97,116,104],"value":"External program path"}, +{"hash":60572138,"name":"tmainform.lboptionexternalparams.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115,58],"value":"Parameters:"}, +{"hash":242848131,"name":"tmainform.edoptionexternalparams.texthint","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,112,97,114,97,109,101,116,101,114,115],"value":"External program parameters"}, +{"hash":24397,"name":"tmainform.lboptionexternalparamshint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":82521866,"name":"tmainform.lboptionlanguage.caption","sourcebytes":[76,97,110,103,117,97,103,101,58],"value":"Language:"}, +{"hash":93623386,"name":"tmainform.lboptionletfmddo.caption","sourcebytes":[65,102,116,101,114,32,100,111,119,110,108,111,97,100,32,102,105,110,105,115,104,58],"value":"After download finish:"}, +{"hash":160062057,"name":"tmainform.lboptionnewmangatime.caption","sourcebytes":[78,101,119,32,109,97,110,103,97,32,98,97,115,101,100,32,111,110,32,32,105,116,39,115,32,117,112,100,97,116,101,32,116,105,109,101,32,40,100,97,121,115,41],"value":"New manga based on it's update time (days)"}, +{"hash":380871,"name":"tmainform.tsview.caption","sourcebytes":[86,105,101,119],"value":"View"}, +{"hash":126054082,"name":"tmainform.cboptionshowdownloadtoolbar.caption","sourcebytes":[83,104,111,119,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show downloads toolbar"}, +{"hash":157437400,"name":"tmainform.gbdroptarget.caption","sourcebytes":[68,114,111,112,32,66,111,120],"value":"Drop Box"}, +{"hash":43310472,"name":"tmainform.ckdroptarget.caption","sourcebytes":[83,104,111,119,32,68,114,111,112,32,66,111,120],"value":"Show Drop Box"}, +{"hash":107454697,"name":"tmainform.lbdroptargetopacity.caption","sourcebytes":[79,112,97,99,105,116,121],"value":"Opacity"}, +{"hash":345509,"name":"tmainform.rgdroptargetmode.caption","sourcebytes":[77,111,100,101],"value":"Mode"}, +{"hash":117603058,"name":"tmainform.cboptionenableloadcover.caption","sourcebytes":[69,110,97,98,108,101,32,108,111,97,100,32,109,97,110,103,97,32,99,111,118,101,114],"value":"Enable load manga cover"}, +{"hash":199270675,"name":"tmainform.tsconnections.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,115],"value":"Connections"}, +{"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, +{"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, +{"hash":325284,"name":"tmainform.lboptionhost.caption","sourcebytes":[72,111,115,116],"value":"Host"}, +{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host\/IP"}, +{"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, +{"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, +{"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, +{"hash":263204852,"name":"tmainform.edoptionport.texthint","sourcebytes":[80,114,111,120,121,32,80,111,114,116],"value":"Proxy Port"}, +{"hash":145417188,"name":"tmainform.lboptionpass.caption","sourcebytes":[80,97,115,115,119,111,114,100],"value":"Password"}, +{"hash":29717652,"name":"tmainform.edoptionpass.texthint","sourcebytes":[80,114,111,120,121,32,112,97,115,115,119,111,114,100],"value":"Proxy password"}, +{"hash":376933,"name":"tmainform.lboptionproxytype.caption","sourcebytes":[84,121,112,101],"value":"Type"}, +{"hash":317840,"name":"tmainform.cboptionproxytype.text","sourcebytes":[72,84,84,80],"value":"HTTP"}, +{"hash":119412009,"name":"tmainform.lboptionmaxparallel.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,116,97,115,107,115,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,40,77,97,120,58,32,56,41],"value":"Number of downloaded tasks at the same time (Max: 8)"}, +{"hash":12948617,"name":"tmainform.lboptionmaxthread.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,102,105,108,101,115,32,112,101,114,32,116,97,115,107,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,40,77,97,120,58,32,51,50,41],"value":"Number of downloaded files per task at the same time (Max: 32)"}, +{"hash":34874153,"name":"tmainform.lboptionmaxretry.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,114,101,116,114,121,32,116,105,109,101,115,32,105,102,32,116,97,115,107,115,32,104,97,118,101,32,100,111,119,110,108,111,97,100,32,112,114,111,98,108,101,109,115,32,40,45,49,32,61,32,97,108,119,97,121,115,32,114,101,116,114,121,41],"value":"Number of retry times if tasks have download problems (-1 = always retry)"}, +{"hash":161967481,"name":"tmainform.lboptionconnectiontimeout.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,32,116,105,109,101,111,117,116,32,40,115,101,99,111,110,100,115,41],"value":"Connection timeout (seconds)"}, +{"hash":160200703,"name":"tmainform.tssaveto.caption","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, +{"hash":96652067,"name":"tmainform.rgoptioncompress.caption","sourcebytes":[83,97,118,101,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115,32,97,115],"value":"Save downloaded chapters as"}, +{"hash":206060487,"name":"tmainform.gboptionrenaming.caption","sourcebytes":[82,101,110,97,109,105,110,103],"value":"Renaming"}, +{"hash":25140969,"name":"tmainform.cboptionchangeunicodecharacter.caption","sourcebytes":[67,104,97,110,103,101,32,97,108,108,32,97,108,108,32,117,110,105,99,111,100,101,32,115,121,109,98,111,108,115,32,116,111,32,34,95,34,32,40,99,104,111,111,115,101,32,116,104,105,115,32,119,104,101,110,32,121,111,117,32,104,97,118,101,32,112,114,111,98,108,101,109,32,119,105,116,104,32,117,110,105,99,111,100,101,32,112,97,116,104,41],"value":"Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)"}, +{"hash":153869381,"name":"tmainform.cboptiongeneratemangafolder.caption","sourcebytes":[65,117,116,111,32,103,101,110,101,114,97,116,101,32,102,111,108,100,101,114,32,98,97,115,101,100,32,111,110,32,109,97,110,103,97,39,115,32,110,97,109,101],"value":"Auto generate folder based on manga's name"}, +{"hash":8004730,"name":"tmainform.lboptionmangacustomrename.caption","sourcebytes":[77,97,110,103,97,32,102,111,108,100,101,114,32,110,97,109,101,58],"value":"Manga folder name:"}, +{"hash":222491525,"name":"tmainform.edoptionmangacustomrename.texthint","sourcebytes":[67,117,115,116,111,109,32,114,101,110,97,109,101],"value":"Custom rename"}, +{"hash":158256302,"name":"tmainform.lboptionmangacustomrenamehint.hint","sourcebytes":[37,87,69,66,83,73,84,69,37,32,58,32,87,101,98,115,105,116,101,32,110,97,109,101,13,10,37,77,65,78,71,65,37,32,58,32,77,97,110,103,97,32,116,105,116,108,101,13,10,37,65,85,84,72,79,82,37,32,58,32,65,117,116,104,111,114,13,10,37,65,82,84,73,83,84,37,32,58,32,65,114,116,105,115,116,13,10,13,10,78,111,116,101,58,13,10,77,97,110,103,97,32,102,111,108,100,101,114,32,110,97,109,101,32,109,117,115,116,32,104,97,118,101,32,97,116,32,108,101,97,115,116,32,37,77,65,78,71,65,37,46],"value":"%WEBSITE% : Website name\r\n%MANGA% : Manga title\r\n%AUTHOR% : Author\r\n%ARTIST% : Artist\r\n\r\nNote:\r\nManga folder name must have at least %MANGA%."}, +{"hash":24397,"name":"tmainform.lboptionmangacustomrenamehint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":245130434,"name":"tmainform.cboptionremovemanganamefromchapter.caption","sourcebytes":[82,101,109,111,118,101,32,109,97,110,103,97,32,110,97,109,101,32,102,114,111,109,32,99,104,97,112,116,101,114],"value":"Remove manga name from chapter"}, +{"hash":28489826,"name":"tmainform.cboptiongeneratechapterfolder.caption","sourcebytes":[65,117,116,111,32,103,101,110,101,114,97,116,101,32,99,104,97,112,116,101,114,32,102,111,108,100,101,114],"value":"Auto generate chapter folder"}, +{"hash":228333834,"name":"tmainform.lboptionchaptercustomrename.caption","sourcebytes":[67,104,97,112,116,101,114,32,110,97,109,101,58],"value":"Chapter name:"}, +{"hash":222491525,"name":"tmainform.edoptionchaptercustomrename.texthint","sourcebytes":[67,117,115,116,111,109,32,114,101,110,97,109,101],"value":"Custom rename"}, +{"hash":157813262,"name":"tmainform.lboptionchaptercustomrenamehint.hint","sourcebytes":[37,87,69,66,83,73,84,69,37,32,58,32,87,101,98,115,105,116,101,32,110,97,109,101,13,10,37,77,65,78,71,65,37,32,58,32,77,97,110,103,97,32,116,105,116,108,101,13,10,37,67,72,65,80,84,69,82,37,32,58,32,67,104,97,112,116,101,114,32,116,105,116,108,101,13,10,37,65,85,84,72,79,82,37,32,58,32,65,117,116,104,111,114,13,10,37,65,82,84,73,83,84,37,32,58,32,65,114,116,105,115,116,13,10,37,78,85,77,66,69,82,73,78,71,37,32,58,32,78,117,109,98,101,114,105,110,103,13,10,13,10,78,111,116,101,58,13,10,67,104,97,112,116,101,114,32,102,111,108,100,101,114,32,110,97,109,101,32,109,117,115,116,32,104,97,118,101,32,97,116,32,108,101,97,115,116,32,37,67,72,65,80,84,69,82,37,32,111,114,32,37,78,85,77,66,69,82,73,78,71,37,46],"value":"%WEBSITE% : Website name\r\n%MANGA% : Manga title\r\n%CHAPTER% : Chapter title\r\n%AUTHOR% : Author\r\n%ARTIST% : Artist\r\n%NUMBERING% : Numbering\r\n\r\nNote:\r\nChapter folder name must have at least %CHAPTER% or %NUMBERING%."}, +{"hash":24397,"name":"tmainform.lboptionchaptercustomrenamehint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":182972947,"name":"tmainform.lboptionrenamedigits.caption","sourcebytes":[82,101,110,97,109,101,32,32,100,105,103,105,116,115],"value":"Rename digits"}, +{"hash":97926197,"name":"tmainform.cboptiondigitvolume.caption","sourcebytes":[86,111,108,117,109,101],"value":"Volume"}, +{"hash":166230658,"name":"tmainform.cboptiondigitchapter.caption","sourcebytes":[67,104,97,112,116,101,114],"value":"Chapter"}, +{"hash":225313701,"name":"tmainform.lboptionfilenamecustomrenamehint.hint","sourcebytes":[37,87,69,66,83,73,84,69,37,32,58,32,87,101,98,115,105,116,101,32,110,97,109,101,13,10,37,77,65,78,71,65,37,32,58,32,77,97,110,103,97,32,116,105,116,108,101,13,10,37,67,72,65,80,84,69,82,37,32,58,32,67,104,97,112,116,101,114,32,116,105,116,108,101,13,10,37,70,73,76,69,78,65,77,69,37,32,58,32,70,105,108,101,110,97,109,101,13,10,13,10,78,111,116,101,58,13,10,70,105,108,101,110,97,109,101,32,109,117,115,116,32,104,97,118,101,32,97,116,32,108,101,97,115,116,32,37,70,73,76,69,78,65,77,69,37],"value":"%WEBSITE% : Website name\r\n%MANGA% : Manga title\r\n%CHAPTER% : Chapter title\r\n%FILENAME% : Filename\r\n\r\nNote:\r\nFilename must have at least %FILENAME%"}, +{"hash":24397,"name":"tmainform.lboptionfilenamecustomrenamehint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":222491525,"name":"tmainform.edoptionfilenamecustomrename.texthint","sourcebytes":[67,117,115,116,111,109,32,114,101,110,97,109,101],"value":"Custom rename"}, +{"hash":46419594,"name":"tmainform.lboptionfilenamecustomrename.caption","sourcebytes":[70,105,108,101,110,97,109,101,58],"value":"Filename:"}, +{"hash":1010826,"name":"tmainform.lbdefaultdownloadpath.caption","sourcebytes":[67,104,111,111,115,101,32,116,104,101,32,100,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104,58],"value":"Choose the default download path:"}, +{"hash":8726312,"name":"tmainform.edoptiondefaultpath.texthint","sourcebytes":[68,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104],"value":"Default download path"}, +{"hash":24397,"name":"tmainform.lboptionpdfqualityhint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":265971401,"name":"tmainform.seoptionpdfquality.hint","sourcebytes":[49,48,48,32,61,32,70,108,97,116,101,69,110,99,111,100,101,32,40,108,111,115,115,108,101,115,115,41,44,32,108,111,119,101,114,32,61,32,68,67,84,69,110,99,111,100,101,32,40,108,111,115,115,121,41],"value":"100 = FlateEncode (lossless), lower = DCTEncode (lossy)"}, +{"hash":265971401,"name":"tmainform.lboptionpdfquality.hint","sourcebytes":[49,48,48,32,61,32,70,108,97,116,101,69,110,99,111,100,101,32,40,108,111,115,115,108,101,115,115,41,44,32,108,111,119,101,114,32,61,32,68,67,84,69,110,99,111,100,101,32,40,108,111,115,115,121,41],"value":"100 = FlateEncode (lossless), lower = DCTEncode (lossy)"}, +{"hash":13786124,"name":"tmainform.lboptionpdfquality.caption","sourcebytes":[80,68,70,32,99,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PDF compression level"}, +{"hash":208308883,"name":"tmainform.tsupdate.caption","sourcebytes":[85,112,100,97,116,101,115],"value":"Updates"}, +{"hash":72408384,"name":"tmainform.cboptionautochecklatestversion.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,108,97,116,101,115,116,32,118,101,114,115,105,111,110,32],"value":"Auto check for latest version "}, +{"hash":225003075,"name":"tmainform.gboptionfavorites.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, +{"hash":4527776,"name":"tmainform.cboptionautocheckfavstartup.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114,32,97,116,32,115,116,97,114,116,117,112],"value":"Auto check for new chapter at startup"}, +{"hash":12237571,"name":"tmainform.lboptionautocheckfavintervalminutes.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114,32,101,118,101,114,121,32,37,100,32,109,105,110,117,116,101,115],"value":"Auto check for new chapter every %d minutes"}, +{"hash":234489075,"name":"tmainform.cboptionautocheckfavremovecompletedmanga.caption","sourcebytes":[65,117,116,111,109,97,116,105,99,32,114,101,109,111,118,101,32,99,111,109,112,108,101,116,101,100,32,109,97,110,103,97,32,102,114,111,109,32,70,97,118,111,114,105,116,101,115],"value":"Automatic remove completed manga from Favorites"}, +{"hash":44744407,"name":"tmainform.cboptionautocheckfavdownload.caption","sourcebytes":[65,117,116,111,109,97,116,105,99,32,100,111,119,110,108,111,97,100,32,97,102,116,101,114,32,102,105,110,105,115,104,32,99,104,101,99,107,105,110,103],"value":"Automatic download after finish checking"}, +{"hash":248673660,"name":"tmainform.cboptionautocheckfavinterval.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114,32,105,110,32,97,110,32,105,110,116,101,114,118,97,108],"value":"Auto check for new chapter in an interval"}, +{"hash":9269721,"name":"tmainform.cboptionupdatelistnomangainfo.caption","sourcebytes":[68,111,110,39,116,32,108,111,97,100,32,109,97,110,103,97,32,105,110,102,111,114,109,97,116,105,111,110,32,119,104,101,110,32,117,112,100,97,116,105,110,103,32,108,105,115,116,32,40,102,105,108,116,101,114,32,119,105,108,108,32,98,101,32,110,111,116,32,119,111,114,107,33,41],"value":"Don't load manga information when updating list (filter will be not work!)"}, +{"hash":182501908,"name":"tmainform.cboptionupdatelistremoveduplicatelocaldata.caption","sourcebytes":[82,101,109,111,118,101,32,100,117,112,108,105,99,97,116,101,32,108,111,99,97,108,32,100,97,116,97,32,119,104,101,110,32,117,112,100,97,116,105,110,103,32,109,97,110,103,97,32,108,105,115,116],"value":"Remove duplicate local data when updating manga list"}, +{"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, +{"hash":263412434,"name":"tmainform.gbdialogs.caption","sourcebytes":[83,104,111,119,32,100,105,97,108,111,103,32,99,111,110,102,105,114,109,97,116,105,111,110,32,102,111,114],"value":"Show dialog confirmation for"}, +{"hash":252071892,"name":"tmainform.cboptionshowquitdialog.caption","sourcebytes":[69,120,105,116,32,70,77,68],"value":"Exit FMD"}, +{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task\/favorite"}, +{"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, +{"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, +{"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, +{"hash":32777246,"name":"tmainform.edwebsitessearch.texthint","sourcebytes":[83,101,97,114,99,104,32,119,101,98,115,105,116,101,46,46,46],"value":"Search website..."}, +{"hash":138578252,"name":"tmainform.tbwebsitesexpandall.caption","sourcebytes":[69,120,112,97,110,100,32,65,108,108],"value":"Expand All"}, +{"hash":53573292,"name":"tmainform.tbwebsitescollapseall.caption","sourcebytes":[67,111,108,108,97,112,115,101,32,65,108,108],"value":"Collapse All"}, +{"hash":108725763,"name":"tmainform.tswebsiteoptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, +{"hash":197676484,"name":"tmainform.tswebsiteadvanced.caption","sourcebytes":[65,100,118,97,110,99,101,100],"value":"Advanced"}, +{"hash":161923523,"name":"tmainform.tsaccounts.caption","sourcebytes":[65,99,99,111,117,110,116,115],"value":"Accounts"}, +{"hash":344211,"name":"tmainform.tsmisc.caption","sourcebytes":[77,105,115,99],"value":"Misc"}, +{"hash":4749113,"name":"tmainform.btoptionapply.caption","sourcebytes":[65,112,112,108,121],"value":"Apply"}, +{"hash":4691652,"name":"tmainform.tsabout.caption","sourcebytes":[65,98,111,117,116],"value":"About"}, +{"hash":101464798,"name":"tmainform.btchecklatestversion.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,108,97,116,101,115,116,32,118,101,114,115,105,111,110],"value":"Check for latest version"}, +{"hash":163353879,"name":"tmainform.btvisitmyblog.caption","sourcebytes":[86,105,115,105,116,32,109,121,32,98,108,111,103],"value":"Visit my blog"}, +{"hash":113643140,"name":"tmainform.tsabouttext.caption","sourcebytes":[65,98,111,117,116,32,70,77,68],"value":"About FMD"}, +{"hash":139332791,"name":"tmainform.tschangelogtext.caption","sourcebytes":[67,104,97,110,103,101,108,111,103],"value":"Changelog"}, +{"hash":221391076,"name":"tmainform.tsmangalist.caption","sourcebytes":[77,97,110,103,97,32,76,105,115,116],"value":"Manga List"}, +{"hash":206498996,"name":"tmainform.btabortupdatelist.hint","sourcebytes":[65,98,111,114,116,32,117,112,100,97,116,101,32,108,105,115,116],"value":"Abort update list"}, +{"hash":158194067,"name":"tmainform.cbselectmanga.hint","sourcebytes":[70,111,114,32,109,111,114,101,32,109,97,110,103,97,32,115,105,116,101,115,44,32,112,108,101,97,115,101,32,103,111,32,116,111,32,79,112,116,105,111,110,115,45,62,77,97,110,103,97,32,115,105,116,101,115],"value":"For more manga sites, please go to Options->Manga sites"}, +{"hash":119443044,"name":"tmainform.btupdatelist.hint","sourcebytes":[85,112,100,97,116,101,32,109,97,110,103,97,32,108,105,115,116],"value":"Update manga list"}, +{"hash":138125102,"name":"tmainform.edsearch.texthint","sourcebytes":[83,101,97,114,99,104,32,116,105,116,108,101,46,46,46],"value":"Search title..."}, +{"hash":150137481,"name":"tmainform.lbmode.caption","sourcebytes":[77,111,100,101,58,32,83,104,111,119,32,97,108,108,32,40,48,41],"value":"Mode: Show all (0)"}, +{"hash":1054,"name":"tmainform.tsdownloadfilter.caption","sourcebytes":[62,62],"value":">>"}, +{"hash":371552,"name":"tmainform.midownloadstop.caption","sourcebytes":[83,116,111,112],"value":"Stop"}, +{"hash":93105205,"name":"tmainform.midownloadresume.caption","sourcebytes":[82,101,115,117,109,101],"value":"Resume"}, +{"hash":79984933,"name":"tmainform.midownloadenable.caption","sourcebytes":[69,110,97,98,108,101],"value":"Enable"}, +{"hash":185170277,"name":"tmainform.midownloaddisable.caption","sourcebytes":[68,105,115,97,98,108,101],"value":"Disable"}, +{"hash":78392485,"name":"tmainform.midownloaddelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, +{"hash":165093305,"name":"tmainform.midownloaddeletetask.caption","sourcebytes":[84,97,115,107,32,111,110,108,121],"value":"Task only"}, +{"hash":42869105,"name":"tmainform.midownloaddeletetaskdata.caption","sourcebytes":[84,97,115,107,32,43,32,68,97,116,97],"value":"Task + Data"}, +{"hash":235571507,"name":"tmainform.midownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, +{"hash":180320563,"name":"tmainform.midownloadmergecompleted.caption","sourcebytes":[77,101,114,103,101,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Merge completed tasks"}, +{"hash":27371647,"name":"tmainform.midownloadviewmangainfo.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, +{"hash":77874882,"name":"tmainform.midownloadopenfolder.caption","sourcebytes":[79,112,101,110,32,70,111,108,100,101,114],"value":"Open Folder"}, +{"hash":113260142,"name":"tmainform.midownloadopenwith.caption","sourcebytes":[79,112,101,110,32,46,46,46],"value":"Open ..."}, +{"hash":110262708,"name":"tmainform.michapterlistcheckselected.caption","sourcebytes":[67,104,101,99,107,32,115,101,108,101,99,116,101,100],"value":"Check selected"}, +{"hash":110606772,"name":"tmainform.michapterlistuncheckselected.caption","sourcebytes":[85,110,99,104,101,99,107,32,115,101,108,101,99,116,101,100],"value":"Uncheck selected"}, +{"hash":194850764,"name":"tmainform.michapterlistcheckall.caption","sourcebytes":[67,104,101,99,107,32,97,108,108],"value":"Check all"}, +{"hash":197210060,"name":"tmainform.michapterlistuncheckall.caption","sourcebytes":[85,110,99,104,101,99,107,32,97,108,108],"value":"Uncheck all"}, +{"hash":15962307,"name":"tmainform.michapterlisthighlight.caption","sourcebytes":[72,105,103,104,108,105,103,104,116,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115],"value":"Highlight downloaded chapters"}, +{"hash":112147507,"name":"tmainform.michapterlisthidedownloaded.caption","sourcebytes":[72,105,100,101,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115],"value":"Hide downloaded chapters"}, +{"hash":80755394,"name":"tmainform.michapterlistfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":165778738,"name":"tmainform.mifavoriteschecknewchapter.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Check for new chapter"}, +{"hash":222540418,"name":"tmainform.mifavoritesstopchecknewchapter.caption","sourcebytes":[83,116,111,112,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Stop check for new chapter"}, +{"hash":27371647,"name":"tmainform.mifavoritesviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, +{"hash":29393692,"name":"tmainform.mifavoritesdownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, +{"hash":78392485,"name":"tmainform.mifavoritesdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, +{"hash":94036626,"name":"tmainform.mifavoriteschangecurrentchapter.caption","sourcebytes":[67,104,97,110,103,101,32,34,67,117,114,114,101,110,116,32,99,104,97,112,116,101,114,34],"value":"Change \"Current chapter\""}, +{"hash":202687490,"name":"tmainform.mifavoriteschangesaveto.caption","sourcebytes":[67,104,97,110,103,101,32,34,83,97,118,101,32,116,111,34],"value":"Change \"Save to\""}, +{"hash":77874882,"name":"tmainform.mifavoritesopenfolder.caption","sourcebytes":[79,112,101,110,32,70,111,108,100,101,114],"value":"Open Folder"}, +{"hash":113260142,"name":"tmainform.mifavoritesopenwith.caption","sourcebytes":[79,112,101,110,32,46,46,46],"value":"Open ..."}, +{"hash":169511027,"name":"tmainform.mimangalistviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111,115],"value":"View manga infos"}, +{"hash":29393692,"name":"tmainform.mimangalistdownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, +{"hash":215890979,"name":"tmainform.mimangalistaddtofavorites.caption","sourcebytes":[65,100,100,32,116,111,32,70,97,118,111,114,105,116,101,115],"value":"Add to Favorites"}, +{"hash":175694497,"name":"tmainform.mihighlightnewmanga.caption","sourcebytes":[72,105,103,104,108,105,103,104,116,32,110,101,119,32,109,97,110,103,97],"value":"Highlight new manga"}, +{"hash":119443044,"name":"tmainform.mnupdatelist.caption","sourcebytes":[85,112,100,97,116,101,32,109,97,110,103,97,32,108,105,115,116],"value":"Update manga list"}, +{"hash":11631810,"name":"tmainform.mnupdatedownfromserver.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,102,114,111,109,32,115,101,114,118,101,114],"value":"Download manga list from server"}, +{"hash":164591397,"name":"tmainform.mnupdate1click.caption","sourcebytes":[85,112,100,97,116,101,32,97,108,108,32,108,105,115,116,115,32,97,116,32,111,110,99,101],"value":"Update all lists at once"}, +{"hash":182967733,"name":"tmainform.mndownload1click.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108,32,108,105,115,116,115,32,102,114,111,109,32,115,101,114,118,101,114,32,97,116,32,111,110,99,101],"value":"Download all lists from server at once"}, +{"hash":378031,"name":"tmainform.medurlundo.caption","sourcebytes":[85,110,100,111],"value":"Undo"}, +{"hash":19140,"name":"tmainform.medurlcut.caption","sourcebytes":[67,117,116],"value":"Cut"}, +{"hash":304761,"name":"tmainform.medurlcopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"}, +{"hash":5671589,"name":"tmainform.medurlpaste.caption","sourcebytes":[80,97,115,116,101],"value":"Paste"}, +{"hash":53267631,"name":"tmainform.medurlpasteandgo.caption","sourcebytes":[80,97,115,116,101,32,97,110,100,32,103,111],"value":"Paste and go"}, +{"hash":78392485,"name":"tmainform.medturldelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, +{"hash":195296268,"name":"tmainform.medurlselectall.caption","sourcebytes":[83,101,108,101,99,116,32,97,108,108],"value":"Select all"}, +{"hash":4691604,"name":"tmainform.miabortsilentthread.caption","sourcebytes":[65,98,111,114,116],"value":"Abort"}, +{"hash":194850764,"name":"tmainform.mnfiltergenreallcheck.caption","sourcebytes":[67,104,101,99,107,32,97,108,108],"value":"Check all"}, +{"hash":197210060,"name":"tmainform.mnfiltergenrealluncheck.caption","sourcebytes":[85,110,99,104,101,99,107,32,97,108,108],"value":"Uncheck all"}, +{"hash":37622444,"name":"tmainform.mnfiltergenreallindeterminate.caption","sourcebytes":[73,110,100,101,116,101,114,109,105,110,97,116,101,32,97,108,108],"value":"Indeterminate all"}, +{"hash":204663948,"name":"tmainform.mitrayresumeall.caption","sourcebytes":[82,101,115,117,109,101,32,97,108,108],"value":"Resume all"}, +{"hash":190997388,"name":"tmainform.mitraystopall.caption","sourcebytes":[83,116,111,112,32,97,108,108],"value":"Stop all"}, +{"hash":240732488,"name":"tmainform.mitrayafterdownloadfinish.caption","sourcebytes":[65,102,116,101,114,32,100,111,119,110,108,111,97,100,32,102,105,110,105,115,104],"value":"After download finish"}, +{"hash":90894359,"name":"tmainform.mitrayfinishnothing.caption","sourcebytes":[78,111,116,104,105,110,103],"value":"Nothing"}, +{"hash":315140,"name":"tmainform.mitrayfinishexit.caption","sourcebytes":[69,120,105,116],"value":"Exit"}, +{"hash":264942414,"name":"tmainform.mitrayfinishshutdown.caption","sourcebytes":[83,104,117,116,100,111,119,110],"value":"Shutdown"}, +{"hash":147392085,"name":"tmainform.mitrayfinishhibernate.caption","sourcebytes":[72,105,98,101,114,110,97,116,101],"value":"Hibernate"}, +{"hash":43310472,"name":"tmainform.mitrayshowdropbox.caption","sourcebytes":[83,104,111,119,32,68,114,111,112,32,66,111,120],"value":"Show Drop Box"}, +{"hash":147502805,"name":"tmainform.mitrayrestore.caption","sourcebytes":[82,101,115,116,111,114,101],"value":"Restore"}, +{"hash":315140,"name":"tmainform.mitrayexit.caption","sourcebytes":[69,120,105,116],"value":"Exit"} +]} diff --git a/mangadownloader/forms/frmNewChapter.lrj b/mangadownloader/forms/frmNewChapter.lrj new file mode 100644 index 000000000..dbe400e95 --- /dev/null +++ b/mangadownloader/forms/frmNewChapter.lrj @@ -0,0 +1,6 @@ +{"version":1,"strings":[ +{"hash":252000638,"name":"tnewchapter.caption","sourcebytes":[78,101,119,32,67,104,97,112,116,101,114,32,78,111,116,105,102,105,99,97,116,105,111,110],"value":"New Chapter Notification"}, +{"hash":115679172,"name":"tnewchapter.btdownload.caption","sourcebytes":[38,68,111,119,110,108,111,97,100],"value":"&Download"}, +{"hash":184736549,"name":"tnewchapter.btqueue.caption","sourcebytes":[38,65,100,100,32,116,111,32,113,117,101,117,101],"value":"&Add to queue"}, +{"hash":177752476,"name":"tnewchapter.btcancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} +]} diff --git a/mangadownloader/forms/frmUpdateDialog.lrj b/mangadownloader/forms/frmUpdateDialog.lrj new file mode 100644 index 000000000..721e0072e --- /dev/null +++ b/mangadownloader/forms/frmUpdateDialog.lrj @@ -0,0 +1,6 @@ +{"version":1,"strings":[ +{"hash":215104852,"name":"tupdatedialogform.caption","sourcebytes":[78,101,119,32,86,101,114,115,105,111,110,32,70,111,117,110,100],"value":"New Version Found"}, +{"hash":60067406,"name":"tupdatedialogform.lbmessage.caption","sourcebytes":[78,101,119,32,118,101,114,115,105,111,110,32,102,111,117,110,100,33,32,68,111,32,121,111,117,32,119,97,110,116,32,116,111,32,117,112,100,97,116,101,32,110,111,119,63,13,10,70,77,68,32,119,105,108,108,32,98,101,32,99,108,111,115,101,100,32,116,111,32,102,105,110,105,115,104,32,116,104,101,32,117,112,100,97,116,101,46],"value":"New version found! Do you want to update now?\r\nFMD will be closed to finish the update."}, +{"hash":197568645,"name":"tupdatedialogform.btnupdate.caption","sourcebytes":[38,85,112,100,97,116,101],"value":"&Update"}, +{"hash":45255362,"name":"tupdatedialogform.btnlater.caption","sourcebytes":[38,76,97,116,101,114],"value":"&Later"} +]} diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lrj b/mangadownloader/forms/frmWebsiteOptionAdvanced.lrj new file mode 100644 index 000000000..7f6e482e9 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lrj @@ -0,0 +1,22 @@ +{"version":1,"strings":[ +{"hash":174464899,"name":"twebsiteoptionadvancedform.tscookies.caption","sourcebytes":[67,111,111,107,105,101,115],"value":"Cookies"}, +{"hash":230269173,"name":"twebsiteoptionadvancedform.vtcookies.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":174464899,"name":"twebsiteoptionadvancedform.vtcookies.header.columns[1].text","sourcebytes":[67,111,111,107,105,101,115],"value":"Cookies"}, +{"hash":71439252,"name":"twebsiteoptionadvancedform.tsuseragent.caption","sourcebytes":[85,115,101,114,32,65,103,101,110,116],"value":"User Agent"}, +{"hash":230269173,"name":"twebsiteoptionadvancedform.vtuseragent.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":71439252,"name":"twebsiteoptionadvancedform.vtuseragent.header.columns[1].text","sourcebytes":[85,115,101,114,32,65,103,101,110,116],"value":"User Agent"}, +{"hash":240327891,"name":"twebsiteoptionadvancedform.tsdownloads.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, +{"hash":261838155,"name":"twebsiteoptionadvancedform.tsmaxthreadspertask.caption","sourcebytes":[77,97,120,32,116,104,114,101,97,100,115,32,112,101,114,32,116,97,115,107],"value":"Max threads per task"}, +{"hash":230269173,"name":"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":6063029,"name":"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, +{"hash":170482212,"name":"twebsiteoptionadvancedform.tsupdatelist.caption","sourcebytes":[85,112,100,97,116,101,32,76,105,115,116],"value":"Update List"}, +{"hash":110671906,"name":"twebsiteoptionadvancedform.tsdirectorypagenumber.caption","sourcebytes":[68,105,114,101,99,116,111,114,121,32,112,97,103,101,32,110,117,109,98,101,114],"value":"Directory page number"}, +{"hash":230269173,"name":"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":6063029,"name":"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, +{"hash":116141123,"name":"twebsiteoptionadvancedform.tsnumberofthreads.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,116,104,114,101,97,100,115],"value":"Number of threads"}, +{"hash":230269173,"name":"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":6063029,"name":"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, +{"hash":18340,"name":"twebsiteoptionadvancedform.menuitem1.caption","sourcebytes":[65,100,100],"value":"Add"}, +{"hash":310020,"name":"twebsiteoptionadvancedform.menuitem2.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, +{"hash":78392485,"name":"twebsiteoptionadvancedform.menuitem4.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"} +]} diff --git a/mangadownloader/forms/frmWebsiteSelection.lrj b/mangadownloader/forms/frmWebsiteSelection.lrj new file mode 100644 index 000000000..9772f6136 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteSelection.lrj @@ -0,0 +1,3 @@ +{"version":1,"strings":[ +{"hash":102399989,"name":"twebsiteselectionform.caption","sourcebytes":[83,101,108,101,99,116,32,97,32,119,101,98,115,105,116,101],"value":"Select a website"} +]} diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index ec6bd313d..f7be6186d 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -2113,3 +2113,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 95c442a00..69476fbb9 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -2094,3 +2094,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index bb6f9bd14..1ce117fed 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -9,11 +9,11 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en\n" -"X-Generator: Poedit 1.8.2\n" +"X-Generator: Poedit 1.8.8\n" #: tfrmmain.caption msgid "Free Manga Downloader - Updater" -msgstr "" +msgstr "Free Manga Downloader - Updater" #: tfrmmain.lbfilesize.caption msgid "File size" @@ -27,6 +27,10 @@ msgstr "Waiting..." msgid "Transfer rate" msgstr "Transfer rate" +#: tfrmmessage.caption +msgid "Help" +msgstr "Help" + #: umain.rs_7znotfound msgid "Can't extract file because 7za.exe not found!" msgstr "Can't extract file because 7za.exe not found!" @@ -102,4 +106,3 @@ msgstr "Unpacking file [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Waiting main app to close..." - diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 85672136c..fd8a03916 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -9,11 +9,11 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.8.2\n" +"X-Generator: Poedit 1.8.8\n" #: tfrmmain.caption msgid "Free Manga Downloader - Updater" -msgstr "" +msgstr "Free Manga Downloader - Updater" #: tfrmmain.lbfilesize.caption msgid "File size" @@ -27,6 +27,10 @@ msgstr "Menunggu..." msgid "Transfer rate" msgstr "Kecepatan" +#: tfrmmessage.caption +msgid "Help" +msgstr "Bantuan" + #: umain.rs_7znotfound msgid "Can't extract file because 7za.exe not found!" msgstr "Tidak bisa meng-ekstrak karena 7za.exe tidak ditemukan!" @@ -102,4 +106,3 @@ msgstr "Membuka berkas [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Menunggu aplikasi utama untuk berhenti..." - diff --git a/updater/languages/updater.po b/updater/languages/updater.po index b7474ab66..56c7490de 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -17,6 +17,10 @@ msgstr "" msgid "Transfer rate" msgstr "" +#: tfrmmessage.caption +msgid "Help" +msgstr "" + #: umain.rs_7znotfound msgid "Can't extract file because 7za.exe not found!" msgstr "" diff --git a/updater/uMain.lrj b/updater/uMain.lrj new file mode 100644 index 000000000..8a7917a17 --- /dev/null +++ b/updater/uMain.lrj @@ -0,0 +1,6 @@ +{"version":1,"strings":[ +{"hash":193843458,"name":"tfrmmain.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114,32,45,32,85,112,100,97,116,101,114],"value":"Free Manga Downloader - Updater"}, +{"hash":131060021,"name":"tfrmmain.lbtransferrate.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,114,97,116,101],"value":"Transfer rate"}, +{"hash":41414149,"name":"tfrmmain.lbfilesize.caption","sourcebytes":[70,105,108,101,32,115,105,122,101],"value":"File size"}, +{"hash":184637710,"name":"tfrmmain.lbstatus.caption","sourcebytes":[87,97,105,116,105,110,103,46,46,46],"value":"Waiting..."} +]} diff --git a/updater/uMessage.lfm b/updater/uMessage.lfm index adf35e6fc..5a7145919 100644 --- a/updater/uMessage.lfm +++ b/updater/uMessage.lfm @@ -4,12 +4,12 @@ object frmMessage: TfrmMessage Top = 235 Width = 642 BorderIcons = [biSystemMenu] - Caption = 'frmMessage' + Caption = 'Help' ClientHeight = 239 ClientWidth = 642 FormStyle = fsSystemStayOnTop Position = poDesktopCenter - LCLVersion = '1.5' + LCLVersion = '1.7' object mmMessage: TMemo Left = 0 Height = 239 diff --git a/updater/uMessage.lrj b/updater/uMessage.lrj new file mode 100644 index 000000000..d4f021028 --- /dev/null +++ b/updater/uMessage.lrj @@ -0,0 +1,3 @@ +{"version":1,"strings":[ +{"hash":322608,"name":"tfrmmessage.caption","sourcebytes":[72,101,108,112],"value":"Help"} +]} From ff46066203d9a2e9217314f09ab6c589da9c276a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 20 Jul 2016 18:18:04 +0800 Subject: [PATCH 1322/2794] frmmain, fixed draw odd/even color on favorite list --- mangadownloader/forms/frmMain.pas | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 86eeaf78f..5f13bdf03 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3621,10 +3621,13 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + C: TColor; begin if CellPaintMode <> cpmPaint then Exit; with TargetCanvas, FavoriteManager.Items[Node^.Index] do begin + C := Brush.Color; Brush.Color := clNone; if Trim(FavoriteInfo.Link) = '' then Brush.Color := CL_FVBrokenFavorite @@ -3646,7 +3649,9 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; end; end; if Brush.Color <> clNone then - FillRect(CellRect); + FillRect(CellRect) + else + Brush.Color := C; end; end; From f0b0ef059595bcd6d002e15bf05ee8a63f71f5a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jul 2016 05:03:44 +0800 Subject: [PATCH 1323/2794] added popup menu to delete task + data + favorite closed #325 --- baseunits/uFavoritesManager.pas | 7 +++++++ mangadownloader/forms/frmMain.lfm | 4 ++++ mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 23 ++++++++++++++++++++++- mangadownloader/languages/fmd.en.po | 4 ++++ mangadownloader/languages/fmd.id_ID.po | 5 ++++- mangadownloader/languages/fmd.po | 4 ++++ 7 files changed, 46 insertions(+), 2 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 721d434a1..30a4ffcfb 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -88,6 +88,7 @@ TFavoriteManager = class FSortColumn: Integer; FSortDirection, FIsAuto, FIsRunning: Boolean; function GetFavoritesCount: Integer; inline; + function GetFavorite(const Index: Integer): TFavoriteContainer; public Items: TFavoriteContainers; favoritesFile: TIniFileRun; @@ -136,6 +137,7 @@ TFavoriteManager = class property SortColumn: Integer read FSortColumn write FSortColumn; property isAuto: Boolean read FIsAuto write FIsAuto; property isRunning: Boolean read FIsRunning write FIsRunning; + property Favorite[const Index: Integer]: TFavoriteContainer read GetFavorite; default; end; resourcestring @@ -477,6 +479,11 @@ function TFavoriteManager.GetFavoritesCount: Integer; Result := Items.Count; end; +function TFavoriteManager.GetFavorite(const Index: Integer): TFavoriteContainer; +begin + Result := Items[Index]; +end; + constructor TFavoriteManager.Create; begin inherited Create; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9d3bf632b..f7273a1d6 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4259,6 +4259,10 @@ object MainForm: TMainForm Enabled = False OnClick = miDownloadDeleteTaskClick end + object miDownloadDeleteTaskDataFavorite: TMenuItem + Caption = 'Task + Data + Favorite' + OnClick = miDownloadDeleteTaskClick + end end object miDownloadDeleteCompleted: TMenuItem Caption = 'Delete all completed tasks' diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index ad5ef1bb0..9aa77892a 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -238,6 +238,7 @@ {"hash":78392485,"name":"tmainform.midownloaddelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":165093305,"name":"tmainform.midownloaddeletetask.caption","sourcebytes":[84,97,115,107,32,111,110,108,121],"value":"Task only"}, {"hash":42869105,"name":"tmainform.midownloaddeletetaskdata.caption","sourcebytes":[84,97,115,107,32,43,32,68,97,116,97],"value":"Task + Data"}, +{"hash":267175541,"name":"tmainform.midownloaddeletetaskdatafavorite.caption","sourcebytes":[84,97,115,107,32,43,32,68,97,116,97,32,43,32,70,97,118,111,114,105,116,101],"value":"Task + Data + Favorite"}, {"hash":235571507,"name":"tmainform.midownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, {"hash":180320563,"name":"tmainform.midownloadmergecompleted.caption","sourcebytes":[77,101,114,103,101,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Merge completed tasks"}, {"hash":27371647,"name":"tmainform.midownloadviewmangainfo.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5f13bdf03..f8ea3f877 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -74,6 +74,7 @@ TMainForm = class(TForm) lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; MenuItem10: TMenuItem; + miDownloadDeleteTaskDataFavorite: TMenuItem; miTrayExit: TMenuItem; miTrayRestore: TMenuItem; miTrayShowDropBox: TMenuItem; @@ -1669,7 +1670,8 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if vtDownload.Selected[xNode] then begin DLManager.StopTask(xNode^.Index, False, True); with DLManager.Items[xNode^.Index] do begin - if (Sender = miDownloadDeleteTaskData) and (ChapterName.Count > 0) then begin + if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) + and (ChapterName.Count > 0) then begin for i := 0 to ChapterName.Count - 1 do begin f := CleanAndExpandDirectory(DownloadInfo.SaveTo + ChapterName[i]); if FileExistsUTF8(f + '.zip') then @@ -1683,6 +1685,25 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); end; RemoveDirUTF8(DownloadInfo.SaveTo); end; + if (Sender = miDownloadDeleteTaskDataFavorite) and + (FavoriteManager.Items.Count <> 0) and + (FavoriteManager.isRunning = False) then + try + FavoriteManager.Lock; + for i := 0 to FavoriteManager.Count - 1 do + begin + if SameText(DLManager[xNode^.Index].DownloadInfo.Link, FavoriteManager[i].FavoriteInfo.Link) + and SameText(DLManager[xNode^.Index].DownloadInfo.Website, FavoriteManager[i].FavoriteInfo.Website) then + begin + FavoriteManager.Items[i].Free; + FavoriteManager.Items.Delete(i); + UpdateVtFavorites; + Break; + end; + end; + finally + FavoriteManager.LockRelease; + end; DLManager.Items[xNode^.Index].Free; DLManager.Items.Delete(xNode^.Index); end; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index f7be6186d..56e05cf1b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1433,6 +1433,10 @@ msgstr "Task only" msgid "Task + Data" msgstr "Task + Data" +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "" + #: tmainform.midownloaddisable.caption msgid "Disable" msgstr "Disable" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 69476fbb9..e91570625 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1414,6 +1414,10 @@ msgstr "Daftar saja" msgid "Task + Data" msgstr "Daftar dan data" +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Daftar, data dan kesukaan" + #: tmainform.midownloaddisable.caption msgid "Disable" msgstr "Matikan" @@ -2094,4 +2098,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index e644e08e9..adb4f4113 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1345,6 +1345,10 @@ msgstr "" msgid "Task + Data" msgstr "" +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "" + #: tmainform.midownloaddisable.caption msgid "Disable" msgstr "" From f403e07455e86a077aa5374ee643501689068310 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jul 2016 05:11:56 +0800 Subject: [PATCH 1324/2794] fixed update vtfavorite and vtchapter --- mangadownloader/forms/frmMain.pas | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f8ea3f877..ce51da60e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4813,8 +4813,14 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); procedure TMainForm.UpdateVtChapter; begin - clbChapterList.Clear; - clbChapterList.RootNodeCount := Length(ChapterList); + if clbChapterList.RootNodeCount = Length(ChapterList) then + clbChapterList.Repaint + else + begin + clbChapterList.BeginUpdate; + clbChapterList.RootNodeCount := Length(ChapterList); + clbChapterList.EndUpdate; + end; end; procedure TMainForm.UpdateVtDownload; @@ -4824,8 +4830,14 @@ procedure TMainForm.UpdateVtDownload; procedure TMainForm.UpdateVtFavorites; begin - vtFavorites.Clear; - vtFavorites.RootNodeCount := FavoriteManager.Count; + if vtFavorites.RootNodeCount = FavoriteManager.Items.Count then + vtFavorites.Repaint + else + begin + vtFavorites.BeginUpdate; + vtFavorites.RootNodeCount := FavoriteManager.Count; + vtFavorites.EndUpdate; + end; end; procedure TMainForm.LoadFormInformation; From 2d6294014da029d2cdab9a59edfa99d3f25ea661 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 21 Jul 2016 06:18:44 +0800 Subject: [PATCH 1325/2794] implement delete manga list item(s) close #323 --- baseunits/DBDataProcess.pas | 22 ++++++++++++----- mangadownloader/forms/frmMain.lfm | 4 ++++ mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 33 ++++++++++++++++++++++++++ mangadownloader/languages/fmd.en.po | 10 ++++++++ mangadownloader/languages/fmd.id_ID.po | 9 +++++++ mangadownloader/languages/fmd.po | 9 +++++++ 7 files changed, 82 insertions(+), 6 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 152f40eb3..b775495d0 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -15,11 +15,6 @@ interface type - TSQLite3Connectionx = class(TSQLite3Connection) - public - property Handle read GetHandle; - end; - { TDBDataProcess } TDBDataProcess = class(TObject) @@ -93,6 +88,7 @@ TDBDataProcess = class(TObject) NumChapter: Integer; JDN: TDateTime): Boolean; overload; function UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String = ''): Boolean; + function DeleteData(const RecIndex: Integer): Boolean; procedure Commit; procedure Rollback; procedure RemoveFilter; @@ -109,6 +105,8 @@ TDBDataProcess = class(TObject) property Value[RecIndex, FieldIndex: Integer]: String read GetValue; default; property ValueInt[RecIndex, FieldIndex: Integer]: Integer read GetValueInt; property LinkCount: Integer read GetLinkCount; + property Connection: TSQLite3Connection read FConn; + property Transaction: TSQLTransaction read FTrans; property Table: TSQLQuery read FQuery; end; @@ -587,7 +585,7 @@ function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; constructor TDBDataProcess.Create; begin inherited Create; - FConn := TSQLite3Connectionx.Create(nil); + FConn := TSQLite3Connection.Create(nil); FTrans := TSQLTransaction.Create(nil); FQuery := TSQLQuery.Create(nil); FConn.Transaction := FTrans; @@ -844,6 +842,18 @@ function TDBDataProcess.UpdateData(const Title, Link, Authors, Artists, Genres, end; end; +function TDBDataProcess.DeleteData(const RecIndex: Integer): Boolean; +begin + Result := False; + try + FQuery.RecNo := RecIndex + 1; + FQuery.Delete; + Dec(FRecordCount); + Result := True; + except + end; +end; + procedure TDBDataProcess.Commit; var queryactive: Boolean; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f7273a1d6..e1463908e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4928,6 +4928,10 @@ object MainForm: TMainForm SubMenuImages = IconList OnClick = miMangaListAddToFavoritesClick end + object miMangaListDelete: TMenuItem + Caption = 'Delete' + OnClick = miMangaListDeleteClick + end object miI2: TMenuItem Caption = '-' end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 9aa77892a..406c6720d 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -263,6 +263,7 @@ {"hash":169511027,"name":"tmainform.mimangalistviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111,115],"value":"View manga infos"}, {"hash":29393692,"name":"tmainform.mimangalistdownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, {"hash":215890979,"name":"tmainform.mimangalistaddtofavorites.caption","sourcebytes":[65,100,100,32,116,111,32,70,97,118,111,114,105,116,101,115],"value":"Add to Favorites"}, +{"hash":78392485,"name":"tmainform.mimangalistdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":175694497,"name":"tmainform.mihighlightnewmanga.caption","sourcebytes":[72,105,103,104,108,105,103,104,116,32,110,101,119,32,109,97,110,103,97],"value":"Highlight new manga"}, {"hash":119443044,"name":"tmainform.mnupdatelist.caption","sourcebytes":[85,112,100,97,116,101,32,109,97,110,103,97,32,108,105,115,116],"value":"Update manga list"}, {"hash":11631810,"name":"tmainform.mnupdatedownfromserver.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,102,114,111,109,32,115,101,114,118,101,114],"value":"Download manga list from server"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ce51da60e..5e720631d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -74,6 +74,7 @@ TMainForm = class(TForm) lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; MenuItem10: TMenuItem; + miMangaListDelete: TMenuItem; miDownloadDeleteTaskDataFavorite: TMenuItem; miTrayExit: TMenuItem; miTrayRestore: TMenuItem; @@ -462,6 +463,7 @@ TMainForm = class(TForm) procedure miDownloadDeleteCompletedClick(Sender: TObject); procedure miDownloadResumeClick(Sender: TObject); procedure miDownloadStopClick(Sender: TObject); + procedure miMangaListDeleteClick(Sender: TObject); procedure miMangaListDownloadAllClick(Sender: TObject); procedure miMangaListViewInfosClick(Sender: TObject); procedure miFavoritesOpenFolderClick(Sender: TObject); @@ -792,6 +794,7 @@ TSearchDBThread = class(TThread) RS_DlgTitleExistInDLlist = 'This title are already in download list.'#13#10 + 'Do you want to download it anyway?'; RS_DlgQuit = 'Are you sure you want to exit?'; + RS_DlgRemoveItem = 'Are you sure you want to delete this item(s)?'; RS_DlgRemoveTask = 'Are you sure you want to delete the task(s)?'; RS_DlgRemoveFavorite = 'Are you sure you want to delete the favorite(s)?'; RS_DlgURLNotSupport = 'URL not supported!'; @@ -2842,6 +2845,36 @@ procedure TMainForm.miDownloadStopClick(Sender: TObject); end; end; +procedure TMainForm.miMangaListDeleteClick(Sender: TObject); +var + Node: PVirtualNode; + DeleteCount: Integer; +begin + if vtMangaList.SelectedCount = 0 then Exit; + if dataProcess.Table.Active = False then Exit; + if MessageDlg('', RS_DlgRemoveItem, mtConfirmation, [mbYes, mbNo], 0) = mrNo then Exit; + try + vtMangaList.BeginUpdate; + DeleteCount := 0; + Node := vtMangaList.GetPreviousSelected(nil); + while Assigned(Node) do + begin + if dataProcess.DeleteData(Node^.Index) then + Inc(DeleteCount); + Node := vtMangaList.GetPreviousSelected(Node); + end; + dataProcess.Table.ApplyUpdates; + dataProcess.Table.SQLTransaction.CommitRetaining; + if DeleteCount <> 0 then + begin + vtMangaList.ClearSelection; + vtMangaList.RootNodeCount := dataProcess.RecordCount; + end; + finally + vtMangaList.EndUpdate; + end; +end; + procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); var xNode: PVirtualNode; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 56e05cf1b..d05ae54a2 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -121,6 +121,10 @@ msgstr "Are you sure you want to delete the favorite(s)?" msgid "Are you sure you want to delete all finished tasks?" msgstr "Are you sure you want to delete all finished tasks?" +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "" + #: frmmain.rs_dlgremovetask msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" @@ -1522,6 +1526,12 @@ msgstr "Highlight new manga" msgid "Add to Favorites" msgstr "Add to Favorites" +#: tmainform.mimangalistdelete.caption +#, fuzzy +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Delete" + #: tmainform.mimangalistdownloadall.caption msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" msgid "Download all" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index e91570625..be75c8ae3 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -120,6 +120,10 @@ msgstr "Apakah Anda yakin Anda ingin menghapus kesukaan ini?" msgid "Are you sure you want to delete all finished tasks?" msgstr "Apakah Anda yakin Anda ingin menghapus semua unduhan yang sudah selesai?" +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Apakah Anda yakin ingin menghapus data ini?" + #: frmmain.rs_dlgremovetask msgid "Are you sure you want to delete the task(s)?" msgstr "Apakah Anda yakin ingin menghapus unduhan ini?" @@ -1503,6 +1507,11 @@ msgstr "Sorot komik baru" msgid "Add to Favorites" msgstr "Tambahkan ke kesukaan" +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Hapus" + #: tmainform.mimangalistdownloadall.caption msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" msgid "Download all" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index adb4f4113..f290f6372 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -102,6 +102,10 @@ msgstr "" msgid "Are you sure you want to delete all finished tasks?" msgstr "" +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "" + #: frmmain.rs_dlgremovetask msgid "Are you sure you want to delete the task(s)?" msgstr "" @@ -1434,6 +1438,11 @@ msgstr "" msgid "Add to Favorites" msgstr "" +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "" + #: tmainform.mimangalistdownloadall.caption msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" msgid "Download all" From 3e7cde14eca9d3497d68535ea5a57a75ff3c469c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jul 2016 11:18:14 +0800 Subject: [PATCH 1326/2794] added imginfos unit --- baseunits/ImgInfos.pas | 359 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 baseunits/ImgInfos.pas diff --git a/baseunits/ImgInfos.pas b/baseunits/ImgInfos.pas new file mode 100644 index 000000000..c6864ab62 --- /dev/null +++ b/baseunits/ImgInfos.pas @@ -0,0 +1,359 @@ +{ ImgInfos.pas + + Copyright (C) 2016 + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version with the following modification: + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules,and + to copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the terms + and conditions of the license of that module. An independent module is a + module which is not derived from or based on this library. If you modify + this library, you may extend this exception to your version of the library, + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +} +unit ImgInfos; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, LazUTF8Classes, LazUTF8, LazFileUtils, FPimage, + FPReadJPEG, FPReadPNG, FPReadGif, FPReadBMP, FPReadTiff, + FPWriteJPEG, FPWritePNG, FPWriteBMP, FPWriteTiff; + +type + PImageHandlerRec = ^TImageHandlerRec; + TImageHandlerRec = record + Ext: String; + WExt: String; + ReaderClass: TFPCustomImageReaderClass; + WriterClass: TFPCustomImageWriterClass; + Reader: TFPCustomImageReader + end; + + { TimageHandlerMgr } + + TimageHandlerMgr = class + private + FList: array of TImageHandlerRec; + FEmptyHandlerRec: TImageHandlerRec; + function GetCount: Integer; + public + constructor Create; + destructor Destroy; override; + procedure Add(const ReaderClass: TFPCustomImageReaderClass; const WriterClass: TFPCustomImageWriterClass; + const Ext: String; WExt: String = ''); + function GetImageHandlerByStream(const Stream: TStream): PImageHandlerRec; + function GetImageHandlerByFile(const FileName: String): PImageHandlerRec; + function GetImageHandlerByExt(const Ext: String): PImageHandlerRec; + function GetImageStreamExt(const Stream: TStream): String; inline; + function GetImageFileExt(const FileName: String): String; inline; + function GetImageStreamSize(const Stream: TStream; out Width, Height: Integer): String; + function GetImageFileSize(const FileName: String; out Width, Height: Integer): String; + function GetImageStreamReaderClass(const Stream: TStream): TFPCustomImageReaderClass; inline; + function GetImageFileReaderClass(const FileName: String): TFPCustomImageReaderClass; inline; + function GetImageExtReaderClass(const Ext: String): TFPCustomImageReaderClass; inline; + function GetImageStreamWriterClass(const Stream: TStream): TFPCustomImageWriterClass; inline; + function GetImageFileWriterClass(const FileName: String): TFPCustomImageWriterClass; inline; + function GetImageExtWriterClass(const Ext: String): TFPCustomImageWriterClass; inline; + function GetImageWriterExt(const Ext: String): String; inline; + public + property Count: Integer read GetCount; + end; + +function GetImageHandlerByStream(const Stream: TStream): TImageHandlerRec; inline; +function GetImageHandlerByFile(const FileName: String): TImageHandlerRec; inline; +function GetImageHandlerByExt(const Ext: String): TImageHandlerRec; inline; +function GetImageStreamExt(const Stream: TStream): String; inline; +function GetImageFileExt(const FileName: String): String; inline; +function GetImageStreamSize(const Stream: TStream; out Width, Height: Integer): String; inline; +function GetImageFileSize(const FileName: String; out Width, Height: Integer): String; inline; +function GetImageStreamReaderClass(const Stream: TStream): TFPCustomImageReaderClass; inline; +function GetImageFileReaderClass(const FileName: String): TFPCustomImageReaderClass; inline; +function GetImageExtReaderClass(const Ext: String): TFPCustomImageReaderClass; inline; +function GetImageStreamWriterClass(const Stream: TStream): TFPCustomImageWriterClass; inline; +function GetImageFileWriterClass(const FileName: String): TFPCustomImageWriterClass; inline; +function GetImageExtWriterClass(const Ext: String): TFPCustomImageWriterClass; inline; +function GetImageWriterExt(const Ext: String): String; inline; + +var + ImageHandlerMgr: TimageHandlerMgr; + +implementation + +function GetImageHandlerByStream(const Stream: TStream): TImageHandlerRec; +begin + Result := ImageHandlerMgr.GetImageHandlerByStream(Stream)^; +end; + +function GetImageHandlerByFile(const FileName: String): TImageHandlerRec; +begin + Result := ImageHandlerMgr.GetImageHandlerByFile(FileName)^; +end; + +function GetImageHandlerByExt(const Ext: String): TImageHandlerRec; +begin + Result := ImageHandlerMgr.GetImageHandlerByExt(Ext)^; +end; + +function GetImageStreamExt(const Stream: TStream): String; +begin + Result := ImageHandlerMgr.GetImageStreamExt(Stream); +end; + +function GetImageFileExt(const FileName: String): String; +begin + Result := ImageHandlerMgr.GetImageFileExt(FileName); +end; + +function GetImageStreamSize(const Stream: TStream; out Width, Height: Integer): String; +begin + Result := ImageHandlerMgr.GetImageStreamSize(Stream, Width, Height); +end; + +function GetImageFileSize(const FileName: String; out Width, Height: Integer): String; +begin + Result := ImageHandlerMgr.GetImageFileSize(FileName, Width, Height); +end; + +function GetImageStreamReaderClass(const Stream: TStream): TFPCustomImageReaderClass; +begin + Result := ImageHandlerMgr.GetImageStreamReaderClass(Stream); +end; + +function GetImageFileReaderClass(const FileName: String): TFPCustomImageReaderClass; +begin + Result := ImageHandlerMgr.GetImageFileReaderClass(FileName); +end; + +function GetImageExtReaderClass(const Ext: String): TFPCustomImageReaderClass; +begin + Result := ImageHandlerMgr.GetImageExtReaderClass(Ext); +end; + +function GetImageStreamWriterClass(const Stream: TStream): TFPCustomImageWriterClass; +begin + Result := ImageHandlerMgr.GetImageStreamWriterClass(Stream); +end; + +function GetImageFileWriterClass(const FileName: String): TFPCustomImageWriterClass; +begin + Result := GetImageFileWriterClass(FileName); +end; + +function GetImageExtWriterClass(const Ext: String): TFPCustomImageWriterClass; +begin + Result := GetImageExtWriterClass(Ext); +end; + +function GetImageWriterExt(const Ext: String): String; +begin + Result := GetImageWriterExt(Ext); +end; + +{ TimageHandlerMgr } + +function TimageHandlerMgr.GetCount: Integer; +begin + Result := Length(FList); +end; + +constructor TimageHandlerMgr.Create; +begin + FillChar(FEmptyHandlerRec, SizeOf(FEmptyHandlerRec), 0); +end; + +destructor TimageHandlerMgr.Destroy; +var + i: Integer; +begin + if Length(FList) <> 0 then + for i := High(FList) downto Low(FList) do + Flist[i].Reader.Free; + SetLength(Flist, 0); + inherited Destroy; +end; + +procedure TimageHandlerMgr.Add(const ReaderClass: TFPCustomImageReaderClass; + const WriterClass: TFPCustomImageWriterClass; const Ext: String; WExt: String); +var + i: Integer; +begin + i := Length(FList); + SetLength(FList, i + 1); + FList[i].ReaderClass := ReaderClass; + FList[i].WriterClass := WriterClass; + FList[i].Reader := ReaderClass.Create; + FList[i].Ext := Ext; + if WExt <> '' then + FList[i].WExt := WExt + else + FList[i].WExt := Ext; +end; + +function TimageHandlerMgr.GetImageHandlerByStream(const Stream: TStream): PImageHandlerRec; +var + P: Int64; + i: Integer; +begin + Result := @FEmptyHandlerRec; + if Stream = nil then Exit; + if Stream.Size = 0 then Exit; + P := Stream.Position; + try + for i := 0 to Length(Flist) - 1 do + begin + Stream.Position := 0; + if FList[i].Reader.CheckContents(Stream) then + begin + Result := @FList[i]; + Break; + end; + end; + finally + Stream.Position := P; + end; +end; + +function TimageHandlerMgr.GetImageHandlerByFile(const FileName: String): PImageHandlerRec; +var + FS: TFileStreamUTF8; +begin + Result := @FEmptyHandlerRec; + if not FileExistsUTF8(FileName) then Exit; + try + FS := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + Result := GetImageHandlerByStream(FS); + finally + FS.Free; + end; +end; + +function TimageHandlerMgr.GetImageHandlerByExt(const Ext: String): PImageHandlerRec; +var + i: Integer; +begin + Result := @FEmptyHandlerRec; + for i := Low(FList) to High(Flist) do + if Ext = FList[i].Ext then + begin + Result := @FList[i]; + Break; + end; +end; + +function TimageHandlerMgr.GetImageStreamExt(const Stream: TStream): String; +begin + Result := GetImageHandlerByStream(Stream)^.Ext; +end; + +function TimageHandlerMgr.GetImageFileExt(const FileName: String): String; +begin + Result := GetImageHandlerByFile(FileName)^.Ext; +end; + +function TimageHandlerMgr.GetImageStreamSize(const Stream: TStream; out Width, + Height: Integer): String; +var + H: PImageHandlerRec; + S: TPoint; +begin + Width := 0; + Height := 0; + H := GetImageHandlerByStream(Stream); + Result := H^.Ext; + if Assigned(H^.Reader) then + begin + S := H^.Reader.ImageSize(Stream); + Width := S.x; + Height := S.y; + end; +end; + +function TimageHandlerMgr.GetImageFileSize(const FileName: String; out Width, + Height: Integer): String; +var + FS: TFileStreamUTF8; +begin + Result := ''; + Width := 0; + Height := 0; + if not FileExistsUTF8(FileName) then Exit; + try + FS := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + Result := GetImageStreamSize(FS, Width, Height); + finally + FS.Free; + end; +end; + +function TimageHandlerMgr.GetImageStreamReaderClass(const Stream: TStream + ): TFPCustomImageReaderClass; +begin + Result := GetImageHandlerByStream(Stream)^.ReaderClass; +end; + +function TimageHandlerMgr.GetImageFileReaderClass(const FileName: String + ): TFPCustomImageReaderClass; +begin + Result := GetImageHandlerByFile(FileName)^.ReaderClass; +end; + +function TimageHandlerMgr.GetImageExtReaderClass(const Ext: String + ): TFPCustomImageReaderClass; +begin + Result := GetImageHandlerByExt(Ext)^.ReaderClass; +end; + +function TimageHandlerMgr.GetImageStreamWriterClass(const Stream: TStream + ): TFPCustomImageWriterClass; +begin + Result := GetImageHandlerByStream(Stream)^.WriterClass; +end; + +function TimageHandlerMgr.GetImageFileWriterClass(const FileName: String + ): TFPCustomImageWriterClass; +begin + Result := GetImageHandlerByFile(FileName)^.WriterClass; +end; + +function TimageHandlerMgr.GetImageExtWriterClass(const Ext: String + ): TFPCustomImageWriterClass; +begin + Result := GetImageHandlerByExt(Ext)^.WriterClass; +end; + +function TimageHandlerMgr.GetImageWriterExt(const Ext: String): String; +begin + Result := GetImageHandlerByExt(Ext)^.WExt; +end; + +initialization + ImageHandlerMgr := TimageHandlerMgr.Create; + ImageHandlerMgr.Add(TFPReaderJPEG, TFPWriterJPEG, 'jpg'); + ImageHandlerMgr.Add(TFPReaderPNG, TFPWriterPNG, 'png'); + ImageHandlerMgr.Add(TFPReaderGif, TFPWriterPNG, 'gif', 'png'); + ImageHandlerMgr.Add(TFPReaderBMP, TFPWriterBMP, 'bmp'); + ImageHandlerMgr.Add(TFPReaderTiff, TFPWriterTiff, 'tif'); + +finalization + ImageHandlerMgr.Free; + +end. From 8ddf9093abd7949fe8b73dbfd2e4c62ee84afd90 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jul 2016 11:20:43 +0800 Subject: [PATCH 1327/2794] img2pdf, parse image manually using fpimages, imginfos and remove vampyre imaging library dependency --- baseunits/Img2Pdf.pas | 382 ++++++++++++++++++++++++++++-------------- 1 file changed, 260 insertions(+), 122 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index d53b727fe..67c4f376e 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -1,21 +1,31 @@ -{ Img2Pdf +{ Img2Pdf.pas Copyright (C) 2016 - This source is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - A copy of the GNU General Public License is available on the World Wide Web - at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing - to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version with the following modification: + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules,and + to copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the terms + and conditions of the license of that module. An independent module is a + module which is not derived from or based on this library. If you modify + this library, you may extend this exception to your version of the library, + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. } unit Img2Pdf; @@ -24,11 +34,11 @@ interface uses - Classes, SysUtils, LazFileUtils, LazUTF8Classes, - Imaging, ImagingTypes, ImagingExtras, zstream; + Classes, SysUtils, LazFileUtils, LazUTF8Classes, FPimage, ImgInfos, + FPReadJPEG, FPWriteJPEG, FPReadPNG, JPEGLib, JdAPImin, JDataSrc, Jerror, + zstream; type - TPDFFloat = Single; TCompressionQuality = 0..100; TImg2PDF = class; @@ -36,21 +46,21 @@ TImg2PDF = class; { TPageInfo } TPageInfo = class - private - FOwner: TImg2PDF; public constructor Create(const AOwner: TImg2PDF); destructor Destroy; override; public + Owner: TImg2PDF; FileName: String; - Extension: String; + Ext: String; Width: Integer; Height: Integer; + BitsPerComponent: Integer; ColorSpace: String; Filter: String; Stream: TMemoryStreamUTF8; public - procedure GetImageSize; + procedure GetImageInfos; procedure LoadImageData; procedure FlushImageData; end; @@ -88,12 +98,26 @@ TImg2PDF = class implementation +type + + { TFPReaderPNGInfo } + + TFPReaderPNGInfo = class(TFPReaderPNG) + public + property Header; + end; + const CRLF = #13#10; PDF_VERSION = '%PDF-1.3'; PDF_FILE_END = '%%EOF'; PDF_MAX_GEN_NUM = 65535; +var + JPEGError: jpeg_error_mgr; + +{ TFPReaderPNGToPageInfo } + function PDFString(const S: String): String; begin Result := S; @@ -117,11 +141,12 @@ function PDFInt(const I: Integer; PadLength: Integer): String; constructor TPageInfo.Create(const AOwner: TImg2PDF); begin - FOwner := AOwner; + Owner := AOwner; FileName := ''; - Extension := ''; + Ext := ''; Width := 0; Height := 0; + BitsPerComponent := 8; ColorSpace := ''; Filter := ''; end; @@ -132,127 +157,233 @@ destructor TPageInfo.Destroy; inherited Destroy; end; -function GetColorSpace(const AImageData: TImageData): String; +procedure TPageInfo.GetImageInfos; begin - case AImageData.Format of - ifIndex8: Result := 'Indexed'; - - ifGray8, - ifA8Gray8, - ifGray16, - ifGray32, - ifGray64, - ifA16Gray16: Result := 'DeviceGray'; - - ifX5R1G1B1, - ifR3G3B2, - ifR5G6B5, - ifA1R5G5B5, - ifA4R4G4B4, - ifX1R5G5B5, - ifX4R4G4B4, - ifR8G8B8, - ifA8R8G8B8, - ifX8R8G8B8, - ifR16G16B16, - ifA16R16G16B16, - ifB16G16R16, - ifA16B16G16R16, - ifR32F, - ifA32R32G32B32F, - ifA32B32G32R32F, - ifR16F, - ifA16R16G16B16F, - ifA16B16G16R16F, - ifR32G32B32F, - ifB32G32R32F: Result := 'DeviceRGB'; - else - Result := ''; - end; + Ext := GetImageFileSize(FileName, Width, Height); end; -procedure TPageInfo.GetImageSize; +procedure JPEGToPageInfo(const PageInfo: TPageInfo); var AFS: TFileStreamUTF8; - AImg: TImageData; + JDS: jpeg_decompress_struct; begin - AFS := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + PageInfo.Filter := 'DCTDecode'; try - Extension := LowerCase(DetermineStreamFormat(AFS)); - if Extension = '' then Exit; - InitImage(AImg); + AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite); + FillChar(JDS, SizeOf(JDS), 0); + JDS.err := @JPEGError; + jpeg_CreateDecompress(@JDS, JPEG_LIB_VERSION, SizeOf(JDS)); try - if LoadImageFromStream(AFS, AImg) then - begin - Width := AImg.Width; - Height := AImg.Height; + jpeg_stdio_src(@JDS, @AFS); + jpeg_read_header(@JDS, True); + case JDS.jpeg_color_space of + JCS_GRAYSCALE: PageInfo.ColorSpace := 'DeviceGray'; + JCS_RGB: PageInfo.ColorSpace := 'DeviceRGB'; + JCS_CMYK: PageInfo.ColorSpace := 'DeviceCMYK'; + else + PageInfo.ColorSpace := 'DeviceRGB'; end; finally - FreeImage(AImg); + jpeg_Destroy_Decompress(@JDS); end; + PageInfo.Stream.LoadFromStream(AFS); finally AFS.Free; end; end; -procedure TPageInfo.LoadImageData; +procedure JPEGCompressToPageInfo(const PageInfo: TPageInfo); var - AImg: TImageData; - ADefaultJpegQuality: LongInt; - AImgInfo: TImageFormatInfo; - i: Integer; + IMG: TFPMemoryImage; + RDR: TFPCustomImageReader; + AFS: TFileStreamUTF8; + WRT: TFPWriterJPEG; begin - if Assigned(Stream) then Exit; - Stream := TMemoryStreamUTF8.Create; + PageInfo.Filter := 'DCTDecode'; + IMG := TFPMemoryImage.Create(0, 0); try - Stream.LoadFromFile(FileName); - InitImage(AImg); - LoadImageFromStream(Stream, AImg); - ColorSpace := GetColorSpace(AImg); - if Extension = 'jpg' then - Filter := 'DCTDecode' - else - begin - Stream.Clear; - if FOwner.CompressionQuality < 100 then - begin - //DCTDecode for jpg, convert to jpg for non jpg - Filter := 'DCTDecode'; - ADefaultJpegQuality := Imaging.GetOption(ImagingJpegQuality); - try - Imaging.SetOption(ImagingJpegQuality, FOwner.CompressionQuality); - SaveImageToStream('jpg', Stream, AImg); - finally - Imaging.SetOption(ImagingJpegQuality, ADefaultJpegQuality); - end; - end + try + RDR := GetImageExtReaderClass(PageInfo.Ext).Create; + AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite); + IMG.LoadFromStream(AFS, RDR); + if (RDR is TFPReaderJPEG) and TFPReaderJPEG(RDR).GrayScale then + PageInfo.ColorSpace := 'DeviceGray' else - begin - //FlateDecode - Filter := 'FlateDecode'; - GetImageFormatInfo(AImg.Format, AImgInfo); - if (AImgInfo.IsIndexed) and (AImgInfo.PaletteEntries > 0) then begin - ColorSpace := 'Indexed /DeviceRGB ' + IntToStr(AImgInfo.PaletteEntries - 1) + ' <'; - for i := 0 to AImgInfo.PaletteEntries - 1 do - with AImg.Palette^[i] do - ColorSpace += IntToHex(R, 2) + IntToHex(G, 2) + IntToHex(B, 2); - ColorSpace += '>'; - end; - if ColorSpace = 'DeviceRGB' then - try - SwapChannels(AImg, ChannelRed, ChannelBlue); - except + PageInfo.ColorSpace := 'DeviceRGB'; + finally + RDR.Free; + AFS.Free; + end; + WRT := TFPWriterJPEG.Create; + try + WRT.CompressionQuality := PageInfo.Owner.CompressionQuality; + WRT.GrayScale := (PageInfo.ColorSpace = 'DeviceGray'); + IMG.SaveToStream(PageInfo.Stream, WRT); + finally + WRT.Free; + end; + finally + IMG.Free; + end; +end; + +procedure PNGToPageInfo(const PageInfo: TPageInfo); +var + AFS: TFileStreamUTF8; + IMG: TFPCustomImage; + RDR: TFPReaderPNGInfo; + AMS: TMemoryStreamUTF8; + X, Y: Integer; + CLW, C: TFPColor; +begin + IMG := TFPMemoryImage.Create(0, 0); + try + try + RDR := TFPReaderPNGInfo.Create; + AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite); + RDR.CheckContents(AFS); + if RDR.Header.ColorType = 3 then + IMG.UsePalette := True; + AFS.Position := 0; + IMG.LoadFromStream(AFS, RDR); + + PageInfo.Filter := 'FlateDecode'; + PageInfo.BitsPerComponent := RDR.Header.BitDepth; + if PageInfo.BitsPerComponent > 8 then + PageInfo.BitsPerComponent := 8; + + AMS := TMemoryStreamUTF8.Create; + try + case RDR.Header.ColorType of + 0, 4: + begin + PageInfo.ColorSpace := 'DeviceGray'; + for Y := 0 to IMG.Height - 1 do + for X := 0 to IMG.Width - 1 do + AMS.WriteByte(IMG.Colors[X, Y].red shr 8); + end; + 3: + begin + PageInfo.ColorSpace := 'Indexed /DeviceRGB'; + if Assigned(IMG.Palette) then + begin + PageInfo.ColorSpace := PageInfo.ColorSpace + ' ' + IntToStr(IMG.Palette.Count) + ' <'; + for X := 0 to IMG.Palette.Count - 1 do + begin + C := IMG.Palette.Color[X]; + PageInfo.ColorSpace := PageInfo.ColorSpace + + IntToHex(C.red shr 8, 2) + IntToHex(C.green shr 8, 2) + IntToHex(C.blue shr 8, 2); + end; + PageInfo.ColorSpace := PageInfo.ColorSpace + '>'; + end; + + for Y := 0 to IMG.Height - 1 do + for X := 0 to IMG.Width - 1 do + AMS.WriteByte(Byte(IMG.Pixels[X, Y])); + end; + else + begin + PageInfo.ColorSpace := 'DeviceRGB'; + FillChar(CLW, SizeOf(CLW), $FF); + for Y := 0 to IMG.Height - 1 do + for X := 0 to IMG.Width - 1 do + begin + C := IMG.Colors[X, Y]; + if C.alpha < $FFFF then + C := AlphaBlend(CLW, C); + AMS.WriteByte(C.Red shr 8); + AMS.WriteByte(C.Green shr 8); + AMS.WriteByte(C.blue shr 8); + end; end; - with Tcompressionstream.Create(clmax, Stream, False) do + end; + with Tcompressionstream.Create(cldefault, PageInfo.Stream) do try - Write(AImg.Bits^, AImg.Size); + AMS.Position := 0; + Write(AMS.Memory^, AMS.Size); + flush; finally Free; end; + finally + AMS.Free; end; + finally + RDR.Free; + AFS.Free; + end + finally + IMG.Free; + end; +end; + +procedure ImageToPageInfo(const PageInfo: TPageInfo); +var + IMG: TFPCustomImage; + RDR: TFPCustomImageReader; + AFS: TFileStreamUTF8; + AMS: TMemoryStreamUTF8; + CLW, C: TFPColor; + X, Y: Integer; +begin + PageInfo.Filter := 'FlateDecode'; + PageInfo.ColorSpace := 'DeviceRGB'; + IMG := TFPMemoryImage.Create(0, 0); + try + try + RDR := GetImageExtReaderClass(PageInfo.Ext).Create; + AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite); + IMG.LoadFromStream(AFS, RDR); + finally + RDR.Free; + AFS.Free; + end; + AMS := TMemoryStreamUTF8.Create; + try + FillChar(CLW, SizeOf(CLW), $FF); + for Y := 0 to IMG.Height - 1 do + for X := 0 to IMG.Width - 1 do + begin + C := IMG.Colors[X, Y]; + if C.alpha < $FFFF then + C := AlphaBlend(CLW, C); + AMS.WriteByte(C.Red shr 8); + AMS.WriteByte(C.Green shr 8); + AMS.WriteByte(C.blue shr 8); + end; + with Tcompressionstream.Create(cldefault, PageInfo.Stream) do + try + AMS.Position := 0; + Write(AMS.Memory^, AMS.Size); + flush; + finally + Free; + end; + finally + AMS.Free; end; finally - FreeImage(AImg); + IMG.Free; + end; +end; + +procedure TPageInfo.LoadImageData; +begin + if Assigned(Stream) then Exit; + if Ext = '' then Exit; + Stream := TMemoryStreamUTF8.Create; + try + if (Ext = 'jpg') and (Owner.CompressionQuality >= 75) then + JPEGToPageInfo(Self) + else + if Owner.CompressionQuality < 100 then + JPEGCompressToPageInfo(Self) + else + if Ext = 'png' then + PNGToPageInfo(Self) + else + ImageToPageInfo(Self); + except end; end; @@ -299,8 +430,8 @@ function TImg2PDF.AddImage(const AFileName: String): Integer; if not FileExistsUTF8(AFileName) then Exit; P := TPageInfo.Create(Self); P.FileName := AFileName; - P.GetImageSize; - if P.Extension <> '' then + P.GetImageInfos; + if P.Ext <> '' then Result := FPageInfos.Add(P) else p.Free; @@ -385,14 +516,17 @@ procedure TImg2PDF.SaveToStream(const Stream: TStream); PDFWrite('/Width ' + IntToStr(PageInfo[i].Width)); PDFWrite('/Height ' + IntToStr(PageInfo[i].Height)); PDFWrite('/ColorSpace [/' + PageInfo[i].ColorSpace + ']'); - PDFWrite('/BitsPerComponent 8'); + PDFWrite('/BitsPerComponent ' + IntToStr(PageInfo[i].BitsPerComponent)); PDFWrite('/Filter /' + PageInfo[i].Filter); PDFWrite('/Length ' + IntToStr(PageInfo[i].Stream.Size)); PDFWrite('>>'); PDFWrite('stream'); PDFFlush; - PageInfo[i].Stream.Position := 0; - Stream.CopyFrom(PageInfo[i].Stream, PageInfo[i].Stream.Size); + if Assigned(PageInfo[i].Stream) then + begin + PageInfo[i].Stream.Position := 0; + Stream.CopyFrom(PageInfo[i].Stream, PageInfo[i].Stream.Size); + end; PDFWrite(CRLF + 'endstream'); PDFWrite('endobj'); finally @@ -495,4 +629,8 @@ procedure TImg2PDF.SaveToFile(const AFileName: String); end; end; +initialization + FillChar(JPEGError, SizeOf(JPEGError), 0); + jpeg_std_error(JPEGError); + end. From e45468de4e8421f20d7b8f53ab05c7ab6e128844 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jul 2016 11:21:37 +0800 Subject: [PATCH 1328/2794] rewrite merge2image with fpimages, remove vampyre imaging library dependency --- baseunits/uBaseUnit.pas | 139 ++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 54 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index aedd2a5b2..d285039ad 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -21,8 +21,8 @@ interface SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, dateutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, - GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, - xquery_json, Imaging, ImagingTypes, ImagingExtras, SimpleException, SimpleLogger; + FPimage, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, + xquery, xquery_json, ImgInfos, SimpleException, SimpleLogger; const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -830,8 +830,11 @@ function SaveImage(const mangaSiteID: Integer; URL: String; function ImageFileExist(const AFileName: String): Boolean; function FindImageFile(const AFileName: String): String; -// load TImageData from file with UTF8 aware -function LoadImageDataFromFileUTF8(const FileName: String; var Image: TImageData): Boolean; +// load iamge from file with UTF8 aware +function LoadImageFromFileUTF8(const FileName: String; var Image: TFPCustomImage): Boolean; + +// copy image from one image rect to dest point +procedure CopyImageRect(const Source, Dest: TFPCustomImage; const DestX, DestY: Integer; const SourceRect: TRect); // merge 2 images to one function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; const Landscape: Boolean = False): Boolean; @@ -3268,7 +3271,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag if Stream.Size = 0 then Exit; p := CleanAndExpandDirectory(Path); if ForceDirectoriesUTF8(p) then begin - f := DetermineStreamFormat(Stream); + f := GetImageStreamExt(Stream); if f = '' then Exit; f := p + FileName + '.' + f; if FileExistsUTF8(f) then DeleteFileUTF8(f); @@ -3540,82 +3543,110 @@ function FindImageFile(const AFileName: String): String; end; end; -function LoadImageDataFromFileUTF8(const FileName: String; var Image: TImageData): Boolean; +function LoadImageFromFileUTF8(const FileName: String; var Image: TFPCustomImage): Boolean; var - f: TFileStreamUTF8; + fs: TFileStreamUTF8; + h: TFPCustomImageReaderClass; + r: TFPCustomImageReader; begin Result := False; - FreeImage(Image); if not FileExistsUTF8(FileName) then Exit; - f := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + h := GetImageFileReaderClass(FileName); + if h = nil then Exit; + r := h.Create; + fs := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); try - Result := LoadImageFromStream(f, Image); + Image.LoadFromStream(fs, r); + Result := True; finally - f.Free; + r.Free; + fs.Free; + end; +end; + +procedure CopyImageRect(const Source, Dest: TFPCustomImage; const DestX, DestY: Integer; const SourceRect: TRect); +var + x, y, dx, dy: Integer; +begin + dx := DestX; + dy := DestY; + for y := SourceRect.Top to SourceRect.Bottom -1 do + begin + for x := SourceRect.Left to SourceRect.Right - 1 do + begin + Dest.Colors[dx, dy] := Source.Colors[x, y]; + Inc(dx); + end; + Inc(dy); end; end; function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; const Landscape: Boolean): Boolean; var - dir, ext, fullImgName1, fullImgName2, fullFileName: String; - img1, img2, imgProc: TImageData; - fileStream: TFileStreamUTF8; - newWidth, newHeigth: LongInt; + D, AImgName1, AImgName2, AFinalName: String; + Img1, Img2, ImgNew: TFPCustomImage; + newWidth: Integer; + newHeigth: LongInt; + h: TFPCustomImageWriterClass; + w: TFPCustomImageWriter; + fs: TFileStreamUTF8; begin Result := False; - dir := CleanAndExpandDirectory(Directory); - if not DirectoryExistsUTF8(dir) then Exit; - fullImgName1 := dir + ImgName1; - fullImgName2 := dir + ImgName2; - if not (FileExistsUTF8(fullImgName1) and FileExistsUTF8(fullImgName2)) then Exit; - InitImage(img1); - InitImage(img2); - InitImage(imgProc); + if not DirectoryExistsUTF8(Directory) then Exit; + D := CleanAndExpandDirectory(Directory); + AImgName1 := D + ImgName1; + AImgName2 := D + ImgName2; + if not (FileExistsUTF8(AImgName1) and FileExistsUTF8(AImgName2)) then Exit; + Img1 := TFPMemoryImage.create(0,0); + Img2 := TFPMemoryImage.create(0,0); try - if LoadImageDataFromFileUTF8(fullImgName1, img1) and - LoadImageDataFromFileUTF8(fullImgName2, img2) then + if (LoadImageFromFileUTF8(AImgName1, Img1) and LoadImageFromFileUTF8(AImgName2, Img2)) then Exit; + if Landscape then begin + newWidth := img1.Width + img2.Width; + newHeigth := max(img1.Height, img2.Height); + end + else + begin + newWidth := max(img1.Width, img2.Width); + newHeigth := img1.Height + img2.Height; + end; + + ImgNew := TFPMemoryImage.create(newWidth, newHeigth); + try + CopyImageRect(Img1, ImgNew, 0, 0, Rect(0, 0, Img1.Width, Img1.Height)); if Landscape then - begin - newWidth := img1.Width + img2.Width; - newHeigth := max(img1.Height, img2.Height); - end - else - begin - newWidth := max(img1.Width, img2.Width); - newHeigth := img1.Height + img2.Height; - end; - NewImage(newWidth, newHeigth, ifR8G8B8, imgProc); - CopyRect(img1, 0, 0, img1.Width, img1.Width, imgProc, 0, 0); - if Landscape then - CopyRect(img2, 0, 0, img2.Width, img2.Width, imgProc, img1.Width + 1, 0) + CopyImageRect(Img2, ImgNew, Img1.Width + 1, 0, Rect(0, 0, Img2.Width, Img2.Height)) else - CopyRect(img2, 0, 0, img2.Width, img2.Width, imgProc, 0, img1.Height + 1); - fullFileName := dir + FinalName; - if FileExistsUTF8(fullFileName) then - DeleteFileUTF8(fullFileName); - if not FileExistsUTF8(fullFileName) then + CopyImageRect(Img2, ImgNew, 0, Img1.Height + 1, Rect(0, 0, Img2.Width, Img2.Height)); + AFinalName := D + FinalName; + if FileExistsUTF8(AFinalName) then + DeleteFileUTF8(AFinalName); + if not FileExistsUTF8(AFinalName) then begin - fileStream := TFileStreamUTF8.Create(fullFileName, fmCreate); + h := GetImageFileWriterClass(AImgName1); + if h = nil then Exit; try - ext := ExtractFileExt(fullFileName); - if ext <> '' then - SaveImageToStream(ext, fileStream, imgProc); + w := h.Create; + fs := TFileStreamUTF8.Create(AFinalName, fmCreate); + ImgNew.SaveToStream(fs, w); + Result := True; finally - fileStream.Free; + w.Free; + fs.Free; end; - Result := FileExistsUTF8(fullFileName); if Result then begin - DeleteFileUTF8(fullImgName1); - DeleteFileUTF8(fullImgName2); + DeleteFileUTF8(AImgName1); + DeleteFileUTF8(AImgName2); end; end; + finally + ImgNew.Free; end; finally - FreeImage(img1); - FreeImage(img2); - FreeImage(imgProc); + Img1.Free; + Img2.Free; end; end; From 999622d5b52ea86ab5ad072229d032db42ef6e0a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jul 2016 11:22:34 +0800 Subject: [PATCH 1329/2794] rewrite mangafoxwatermarkremover with fpimages --- baseunits/extras/MangaFoxWatermark.pas | 494 ++++++++++++++++++ baseunits/extras/mangafoxwatermarkremover.pas | 230 -------- baseunits/modules/MangaFox.pas | 4 +- mangadownloader/forms/frmMain.pas | 4 +- 4 files changed, 498 insertions(+), 234 deletions(-) create mode 100644 baseunits/extras/MangaFoxWatermark.pas delete mode 100644 baseunits/extras/mangafoxwatermarkremover.pas diff --git a/baseunits/extras/MangaFoxWatermark.pas b/baseunits/extras/MangaFoxWatermark.pas new file mode 100644 index 000000000..6a2e94410 --- /dev/null +++ b/baseunits/extras/MangaFoxWatermark.pas @@ -0,0 +1,494 @@ +{ MangaFoxWatermark.pas + + Copyright (C) 2016 + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version with the following modification: + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules,and + to copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the terms + and conditions of the license of that module. An independent module is a + module which is not derived from or based on this library. If you modify + this library, you may extend this exception to your version of the library, + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +} + +unit MangaFoxWatermark; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, LazFileUtils, LazUTF8Classes, Math, FPimage, FPReadJPEG, FPWriteJPEG, + FPWritePNG, ImgInfos; + +procedure SetTemplateDirectory(const Directory: String); +function LoadTemplate(const Directory: String = ''): Integer; +procedure ClearTemplate; +function RemoveWatermark(const FileName: String; const SaveAsPNG: Boolean = False): Boolean; inline; + +implementation + +type + POneBitImage = ^TOneBitImage; + TOneBitImage = record + Width: Integer; + Heigth: Integer; + Bits: Pointer; + BitsLength: Integer; + end; + + { TWatermarkRemover } + + TWatermarkRemover = class + private + FCS_Templates: TRTLCriticalSection; + FCS_RemoveWatermark: TRTLCriticalSection; + FTemplates: array of TOneBitImage; + FTemplateDirectory: String; + FCleared: Boolean; + procedure AddTemplate(const Image: TOneBitImage); + function GetTemplate(const Index: Integer): POneBitImage; + function GetTemplateCount: Integer; + protected + function AddFileToTemplates(const FileName: String): Boolean; + public + MinPSNR: Single; + MinWhiteBorder: Integer; + constructor Create; + destructor Destroy; override; + function LoadTemplate(const Directory: String = ''): Integer; + procedure ClearTemplate; + function RemoveWatermark(const FileName: String; const SaveAsPNG: Boolean = False): Boolean; + property TemplateDirectory: String read FTemplateDirectory write FTemplateDirectory; + property TemplateCount: Integer read GetTemplateCount; + property Template[const Index: Integer]: POneBitImage read GetTemplate; + end; + +var + WatermarkRemover: TWatermarkRemover; + +procedure SetTemplateDirectory(const Directory: String); +begin + if WatermarkRemover = nil then + WatermarkRemover := TWatermarkRemover.Create; + WatermarkRemover.TemplateDirectory := Directory; +end; + +function LoadTemplate(const Directory: String): Integer; +begin + if WatermarkRemover = nil then + WatermarkRemover := TWatermarkRemover.Create; + Result := WatermarkRemover.LoadTemplate(Directory); +end; + +procedure ClearTemplate; +begin + if Assigned(WatermarkRemover) then + begin + WatermarkRemover.ClearTemplate; + FreeAndNil(WatermarkRemover); + end; +end; + +function RemoveWatermark(const FileName: String; const SaveAsPNG: Boolean): Boolean; +begin + Result := False; + if Assigned(WatermarkRemover) then + Result := WatermarkRemover.RemoveWatermark(FileName, SaveAsPNG); +end; + +{ TWatermarkTemplates } + +procedure TWatermarkRemover.AddTemplate(const Image: TOneBitImage); +var + i: Integer; +begin + i := Length(FTemplates); + SetLength(FTemplates, i + 1); + FTemplates[i] := Image; +end; + +function TWatermarkRemover.GetTemplate(const Index: Integer): POneBitImage; +begin + Result := @FTemplates[Index]; +end; + +function TWatermarkRemover.GetTemplateCount: Integer; +begin + Result := Length(FTemplates); +end; + +procedure OtsuThresholding(const Image: TOneBitImage); +var + histogram: array[0..255] of Integer; + threshold: Byte; + meanTotal, variance, maxVariance, zerothCumuMoment, firstCumuMoment: Single; + i: Integer; + bit: PByte; +begin + FillChar(histogram, SizeOf(histogram), 0); + bit := Image.Bits; + for i := 0 to Image.BitsLength - 1 do + begin + Inc(histogram[bit^]); + Inc(bit); + end; + threshold := 0; + meanTotal := 0; + maxVariance := 0; + firstCumuMoment := 0; + zerothCumuMoment := 0; + for i := 0 to 255 do + meanTotal := meanTotal + (i * histogram[i] / Image.BitsLength); + for i := 0 to 255 do + begin + zerothCumuMoment := zerothCumuMoment + histogram[i] / Image.BitsLength; + firstCumuMoment := firstCumuMoment + (i * histogram[i] / Image.BitsLength); + variance := meanTotal * zerothCumuMoment - firstCumuMoment; + variance := variance * variance; + if ((zerothCumuMoment <> 0) and (zerothCumuMoment <> 1)) then + begin + variance := variance / (zerothCumuMoment * (1 - zerothCumuMoment)); + if (maxVariance < variance) then + begin + maxVariance := variance; + threshold := i; + end; + end; + end; + + bit := Image.Bits; + for i := 0 to Image.BitsLength - 1 do + begin + if bit^ > threshold then + bit^ := 255 + else + bit^ := 0; + Inc(bit); + end; +end; + +procedure BuildImageToOneBit(const Image: TFPCustomImage; + var OutImage: TOneBitImage; + const Left: Integer = -1; + const Top: Integer = -1; + const Right: Integer = -1; + const Bottom: Integer = -1); +var + X, Y, L, R, T, B: Integer; + Bit: PByte; + ML, MT: Integer; +begin + L := Left; + T := Top; + R := Right; + B := Bottom; + if (L < 0) or (L > Image.Width) then L := 0; + if (T < 0) or (T > Image.Height) then T := 0; + if (R < 0) or (R <= L) then R := Image.Width; + if (B < 0) or (B <= T) then B := Image.Height; + OutImage.Width := R - L; + OutImage.Heigth := B - T; + OutImage.BitsLength := OutImage.Width * OutImage.Heigth; + Getmem(OutImage.Bits, OutImage.BitsLength); + Bit := OutImage.Bits; + if (R <= Image.Width) and (B <= Image.Height) then + begin + for Y := T to B - 1 do + for X := L to R - 1 do + begin + Bit^ := CalculateGray(Image.Colors[X, Y]) shr 8; + Inc(Bit); + end; + end + else + begin + FillChar(OutImage.Bits^, OutImage.BitsLength, $ff); + ML := (R - Image.Width) div 2; + MT := ((B - Image.Height) div 2) * OutImage.Width; + if MT > 0 then + Inc(Bit, MT); + if ML > 0 then + begin + Inc(Bit, ML); + ML := (ML * 2) + 1; + end; + for Y := T to B - 1 do + begin + for X := L to Image.Width - 1 do + begin + Bit^ := CalculateGray(Image.Colors[X, Y]) shr 8; + Inc(Bit); + end; + if ML > 0 then + Inc(Bit, ML); + end; + end; + OtsuThresholding(OutImage); +end; + +function TWatermarkRemover.AddFileToTemplates(const FileName: String): Boolean; +var + FS: TFileStreamUTF8; + IMG: TFPCustomImage; + H: TFPCustomImageReaderClass; + R: TFPCustomImageReader; + BIMG: TOneBitImage; +begin + Result := False; + H := GetImageFileReaderClass(FileName); + if H = nil then Exit; + IMG := TFPMemoryImage.Create(0, 0); + try + try + R := H.Create; + FS := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + IMG.LoadFromStream(FS, R); + finally + R.Free; + FS.Free; + end; + FillChar(BIMG, SizeOf(BIMG), 0); + BuildImageToOneBit(IMG, BIMG); + AddTemplate(BIMG); + Result := True; + finally + IMG.Free; + end; +end; + +constructor TWatermarkRemover.Create; +begin + InitCriticalSection(FCS_Templates); + InitCriticalSection(FCS_RemoveWatermark); + FCleared := True; + MinPSNR := 9.0; + MinWhiteBorder := 4; +end; + +destructor TWatermarkRemover.Destroy; +begin + ClearTemplate; + DoneCriticalsection(FCS_Templates); + DoneCriticalsection(FCS_RemoveWatermark); +end; + +function TWatermarkRemover.LoadTemplate(const Directory: String): Integer; +var + Files: TStrings; + D: String; + I: Integer; +begin + Result := 0; + FCleared := False; + if (Directory <> '') and (Directory <> FTemplateDirectory) then + FTemplateDirectory := Directory; + if FTemplateDirectory = '' then Exit; + D := CleanAndExpandDirectory(FTemplateDirectory); + if not DirectoryExistsUTF8(D) then Exit; + if TryEnterCriticalsection(FCS_Templates) <> 0 then + try + Files := TStringList.Create; + ClearTemplate; + FCleared := False; + FindAllFiles(Files, CleanAndExpandDirectory(D), '*.*', False); + if Files.Count = 0 then Exit; + for I := 0 to Files.Count - 1 do + if AddFileToTemplates(Files[I]) then + Inc(Result); + finally + Files.Free; + LeaveCriticalsection(FCS_Templates); + end; +end; + +procedure TWatermarkRemover.ClearTemplate; +var + i: Integer; +begin + for i := Low(FTemplates) to High(FTemplates) do + FreeMemAndNil(FTemplates[i].Bits); + SetLength(FTemplates, 0); + FCleared := True; +end; + +function CalculatePSNR(const Image1, Image2: TOneBitImage): Single; +var + MSE: Single; + i: Integer; + bit1, bit2: PByte; +begin + Result := 0.0; + if Image1.BitsLength <> Image2.BitsLength then + Exit; + MSE := 0.0; + bit1 := Image1.Bits; + bit2 := Image2.Bits; + for i := 0 to Image1.BitsLength - 1 do + begin + if bit1^ <> bit2^ then + MSE := MSE + sqr(abs(bit2^ - bit1^)); + Inc(bit1); + Inc(bit2); + end; + MSE := MSE / Image1.BitsLength; + if Sqrt(MSE) < 0.0001 then + Result := 1e06 + else + Result := 10 * log10(sqr(255) / MSE); +end; + +function TWatermarkRemover.RemoveWatermark(const FileName: String; + const SaveAsPNG: Boolean): Boolean; +var + Handler: TImageHandlerRec; + Reader: TFPCustomImageReader; + Writer: TFPCustomImageWriter; + Image, ImageTemp: TFPCustomImage; + FileStream: TFileStreamUTF8; + BestIndex, I, L, T, R, B: Integer; + BestValue, PSNR: Single; + TIMG: TOneBitImage; + NewFileName: String; + GrayScale: Boolean; + InvalidBorder: Boolean; + Bit: PByte; +begin + Result := False; + EnterCriticalsection(FCS_RemoveWatermark); + try + if TemplateCount = 0 then + begin + if not FCleared then Exit; + LoadTemplate; + end; + if TemplateCount = 0 then Exit; + Handler := GetImageHandlerByFile(FileName); + if Handler.Ext = '' then Exit; + Image := TFPMemoryImage.Create(0, 0); + try + GrayScale := False; + try + Reader := Handler.ReaderClass.Create; + FileStream := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + Image.LoadFromStream(FileStream, Reader); + if Reader is TFPReaderJPEG then + GrayScale := TFPReaderJPEG(Reader).GrayScale; + finally + Reader.Free; + FileStream.Free; + end; + BestIndex := -1; + BestValue := 0.0; + FillChar(TIMG, SizeOf(TIMG), 0); + for I := 0 to TemplateCount - 1 do + if Image.Height >= FTemplates[i].Heigth then + begin + if Image.Width > FTemplates[i].Width then + L := (Image.Width - FTemplates[i].Width) div 2 + else + L := 0; + R := L + FTemplates[i].Width; + T := Image.Height - FTemplates[i].Heigth; + B := Image.Height; + BuildImageToOneBit(Image, TIMG, L, T, R, B); + try + InvalidBorder := False; + if MinWhiteBorder > 0 then + begin + Bit := TIMG.Bits; + R := MinWhiteBorder * TIMG.Width; + for L := 0 to R - 1 do + begin + if Bit^ = 0 then + begin + InvalidBorder := True; + Break; + end; + Inc(Bit); + end; + end; + if not InvalidBorder then + begin + PSNR := CalculatePSNR(TIMG, FTemplates[I]); + if PSNR > BestValue then + begin + BestValue := PSNR; + BestIndex := I; + end; + Bit := TIMG.Bits; + end; + finally + Freemem(TIMG.Bits); + end; + end; + if (BestValue >= MinPSNR) and (BestIndex <> -1) then + try + ImageTemp := TFPMemoryImage.Create(Image.Width, Image.Height - FTemplates[BestIndex].Heigth); + for T := 0 to ImageTemp.Height - 1 do + for L := 0 to ImageTemp.Width - 1 do + ImageTemp.Colors[L, T] := Image.Colors[L, T]; + if SaveAsPNG then + begin + Handler.WriterClass := TFPWriterPNG; + Handler.WExt := 'png'; + end; + NewFileName := ExtractFileNameWithoutExt(FileName) + '.' + Handler.WExt; + if FileExistsUTF8(FileName) then + DeleteFileUTF8(FileName); + if FileExistsUTF8(NewFileName) then + DeleteFileUTF8(NewFileName); + if not FileExistsUTF8(NewFileName) then + begin + try + Writer := Handler.WriterClass.Create; + FileStream := TFileStreamUTF8.Create(NewFileName, fmCreate); + if Writer is TFPWriterJPEG then + TFPWriterJPEG(Writer).GrayScale := GrayScale + else + if Writer is TFPWriterPNG then + begin + if GrayScale then + TFPWriterPNG(Writer).Indexed := True; + end; + ImageTemp.SaveToStream(FileStream, Writer); + finally + Writer.Free; + FileStream.Free; + end; + Result := FileExistsUTF8(NewFileName); + end; + finally + ImageTemp.Free; + end; + finally + Image.Free; + end; + finally + LeaveCriticalsection(FCS_RemoveWatermark); + end; +end; + +initialization + +finalization + if Assigned(WatermarkRemover) then WatermarkRemover.Free; + +end. diff --git a/baseunits/extras/mangafoxwatermarkremover.pas b/baseunits/extras/mangafoxwatermarkremover.pas deleted file mode 100644 index 1c0282456..000000000 --- a/baseunits/extras/mangafoxwatermarkremover.pas +++ /dev/null @@ -1,230 +0,0 @@ -unit mangafoxwatermarkremover; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, ImagingCompare, ImagingExtras, ImagingBinary, - ImagingTypes, ImagingCanvases, Imaging, FileUtil, LazFileUtils, - LazUTF8Classes, SimpleLogger; - -function LoadTemplate(const TempDir: String): Integer; -function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean = False): Boolean; -procedure ClearTemplate; - -var - minwhiteborder: Integer = 4; - minpsnr: Single = 9.0; - -implementation - -var - imgtemplate: TDynImageDataArray; - lockproc: TRTLCriticalSection; - colorwhite: TColor32Rec = (Color: $FFFFFFFF); - -const - mftempfile = 'mangafoxremovewatermarktempfile'; - -function LoadTemplate(const TempDir: String): Integer; -var - flist: TStringList; - i: Integer; -begin - Result := Length(imgtemplate); - if DirectoryExists(TempDir) = False then Exit; - if TryEnterCriticalsection(lockproc) > 0 then begin - flist := TStringList.Create; - try - FreeImagesInArray(imgtemplate); - // load all images in template folder - FindAllFiles(flist, CleanAndExpandDirectory(TempDir), '*.*', False); - if flist.Count > 0 then - for i := 0 to flist.Count - 1 do begin - SetLength(imgtemplate, Length(imgtemplate) + 1); - InitImage(imgtemplate[High(imgtemplate)]); - if LoadImageFromFile(flist.Strings[i], imgtemplate[High(imgtemplate)]) then begin - // convert to grayscale and do thresholding - ConvertImage(imgtemplate[High(imgtemplate)], ifGray8); - OtsuThresholding(imgtemplate[High(imgtemplate)], True); - end - else begin - FreeImage(imgtemplate[High(imgtemplate)]); - SetLength(imgtemplate, Length(imgtemplate) - 1); - end; - end; - finally - flist.Free; - end; - Result := Length(imgtemplate); - LeaveCriticalsection(lockproc); - end; -end; - -procedure ClearTemplate; -begin - FreeImagesInArray(imgtemplate); -end; - -function ColorIsWhite(const Color: TColor32Rec): Boolean; -begin - Result := (Color.R = 255) and (Color.G = 255) and (Color.B = 255); -end; - -function RemoveWatermark(const AFilename: String; SaveAsPNG: Boolean): Boolean; -var - fs: TFileStreamUTF8; - ms: TMemoryStreamUTF8; - imgbase, imgproc, imgtemp: TImageData; - i, x, y, bmi: Integer; - bmv, PSNR, MSE, RMSE, PAE, MAE: Single; - invalidborder: Boolean; - tempfilename, newfilename, newfileext: String; -begin - Result := False; - if not FileExistsUTF8(AFilename) then Exit; - if Length(imgtemplate) = 0 then Exit; - - tempfilename:=''; - newfilename:=''; - newfileext:=''; - - EnterCriticalsection(lockproc); - try - InitImage(imgbase); - fs:=TFileStreamUTF8.Create(AFilename,fmOpenRead or fmShareDenyWrite); - try - newfileext:=DetermineStreamFormat(fs); - if newfileext<>'' then - Result:=LoadImageFromStream(fs,imgbase); - finally - fs.Free; - end; - if not Result then begin - FreeImage(imgbase); - Exit; - end; - Result:=False; - - bmi := -1; - bmv := 0; - // compare image to all template - for i := Low(imgtemplate) to High(imgtemplate) do - if imgbase.Height > imgtemplate[i].Height then begin - try - InitImage(imgproc); - InitImage(imgtemp); - invalidborder := False; - - // crop image to match template - NewImage(imgbase.Width, imgtemplate[i].Height, imgtemplate[i].Format, imgproc); - CopyRect(imgbase, 0, imgbase.Height - imgtemplate[i].Height, imgbase.Width, imgbase.Height - imgtemplate[i].Height, imgproc, 0, 0); - // do thresholding - OtsuThresholding(imgproc, True); - - // check minimal white border - for y := 1 to minwhiteborder do begin - for x := 1 to imgproc.Width do begin - if not ColorIsWhite(GetPixel32(imgproc, x, y)) then begin - invalidborder := True; - Break; - end; - end; - if invalidborder then Break; - end; - - if not invalidborder then begin - // adjust imagetemp width - if imgbase.Width <> imgtemplate[i].Width then begin - NewImage(imgbase.Width, imgtemplate[i].Height, imgtemplate[i].Format, imgtemp); - FillRect(imgtemp, 0, 0, imgtemp.Width, imgtemp.Height, @colorwhite); - if imgbase.Width > imgtemplate[i].Width then begin - CopyRect(imgtemplate[i], 0, 0, imgtemplate[i].Width, imgtemp.Height, imgtemp, round((imgtemp.Width - imgtemplate[i].Width) / 2), 0); - end - else begin - CopyRect(imgtemplate[i], round((imgtemplate[i].Width-imgtemp.Width) / 2), 0, imgtemp.Width, imgtemp.Height, imgtemp, 0, 0); - end; - end - else - CloneImage(imgtemplate[i], imgtemp); - - // compute error metrics - ComputeErrorMetrics(imgtemp, imgproc, PSNR, MSE, RMSE, PAE, MAE); - if PSNR > bmv then begin - bmi := i; - bmv := PSNR; - end; - end; - finally - FreeImage(imgproc); - FreeImage(imgtemp); - end; - end; - - // save cropped image - if (bmi > -1) and (bmv > minpsnr) then begin - InitImage(imgproc); - try - NewImage(imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgbase.Format, imgproc); - CopyRect(imgbase, 0, 0, imgbase.Width, imgbase.Height - imgtemplate[bmi].Height, imgproc, 0, 0); - - tempfilename:=ExtractFileDir(AFilename)+mftempfile; - - if SaveAsPNG then begin - newfilename:=ChangeFileExt(AFilename,'.png'); - newfileext:='png'; - end - else - newfilename:=AFilename; - - ms:=TMemoryStreamUTF8.Create; - try - Result:=SaveImageToStream(newfileext,ms,imgproc); - if Result then begin - Result:=DeleteFileUTF8(AFilename); - if Result then begin - ms.SaveToFile(newfilename); - Result:=FileExistsUTF8(newfilename); - end - else - WriteLog_E('MangaFoxRemoveWatermark, failed to replace file! '+AFilename); - end - else begin - WriteLog_E('MangaFoxRemoveWatermark, failed to save to file! '+AFilename); - if FileExistsUTF8(tempfilename) then - DeleteFileUTF8(tempfilename); - end; - finally - ms.Free; - end; - finally - FreeImage(imgproc); - end; - end; - finally - FreeImage(imgbase); - LeaveCriticalsection(lockproc); - end; -end; - -procedure doInitialize; -begin - InitCriticalSection(lockproc); - Initialize(imgtemplate); -end; - -procedure doFinalize; -begin - FreeImagesInArray(imgtemplate); - DoneCriticalsection(lockproc); -end; - -initialization - doInitialize; - -finalization - doFinalize; - -end. - diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 738a09d68..13b875223 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, mangafoxwatermarkremover; + XQueryEngineHTML, httpsendthread, MangaFoxWatermark; implementation @@ -144,7 +144,7 @@ function AfterImageSaved(const AFilename: String; const Module: TModuleContainer begin Result := True; if removewatermark then - Result := mangafoxwatermarkremover.RemoveWatermark(AFilename, saveaspng); + Result := MangaFoxWatermark.RemoveWatermark(AFilename, saveaspng); end; procedure RegisterModule; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5e720631d..6f45ca359 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, frmWebsiteOptionAdvanced, frmCustomColor, CheckUpdate, accountmanagerdb, DBDataProcess, - mangafoxwatermarkremover, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, + MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, SimpleLogger; type @@ -1205,7 +1205,7 @@ procedure TMainForm.FormCreate(Sender: TObject); end; // load mangafox template - mangafoxwatermarkremover.LoadTemplate(MANGAFOXTEMPLATE_FOLDER); + MangaFoxWatermark.SetTemplateDirectory(MANGAFOXTEMPLATE_FOLDER); // load configfile isStartup := False; From c852d6694edf4c250daf6fa891b9c0e9906d1051 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 27 Jul 2016 11:24:55 +0800 Subject: [PATCH 1330/2794] remove vampyre imaging library dependency we don't really use it, using fcl-images that come with fpc is enough --- mangadownloader/md.lpi | 15 ++++++--------- readme.txt | 1 - 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ed485b591..720c46b25 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -215,28 +215,25 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="7"> + <RequiredPackages Count="6"> <Item1> <PackageName Value="laz_synapse"/> </Item1> <Item2> - <PackageName Value="VampyreImagingPackage"/> + <PackageName Value="internettools"/> </Item2> <Item3> - <PackageName Value="internettools"/> + <PackageName Value="TAChartLazarusPkg"/> </Item3> <Item4> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="richmemopackage"/> </Item4> <Item5> - <PackageName Value="richmemopackage"/> + <PackageName Value="virtualtreeview_package"/> </Item5> <Item6> - <PackageName Value="virtualtreeview_package"/> - </Item6> - <Item7> <PackageName Value="LCL"/> - </Item7> + </Item6> </RequiredPackages> <Units Count="12"> <Unit0> diff --git a/readme.txt b/readme.txt index 3d3ab3967..a2feaae63 100644 --- a/readme.txt +++ b/readme.txt @@ -24,7 +24,6 @@ In order to build FMD from the source code, you must install Lazarus latest vers - RichMemo, https://sourceforge.net/projects/lazarus-ccr/ - Virtual TreeView, https://sourceforge.net/projects/lazarus-ccr/ - Synapse, http://synapse.ararat.cz/ - - Vampyre Imaging Library, http://imaginglib.sourceforge.net/ - InternetTools, https://github.com/benibela/internettools - BESEN, https://github.com/BeRo1985/besen From 1b9dfca615b27ea1a6025a5392530e019d62b0e2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 29 Jul 2016 10:48:50 +0800 Subject: [PATCH 1331/2794] frmmain, changed timer class and give it proper name, tmbackup also backup favorites changed tidletimer to ttimer changed tmbackup interval to 2 minute --- baseunits/CheckUpdate.pas | 2 +- baseunits/uDownloadsManager.pas | 10 ++-- baseunits/uGetMangaInfosThread.pas | 4 +- mangadownloader/forms/frmMain.lfm | 80 +++++++++++++------------- mangadownloader/forms/frmMain.lrj | 1 - mangadownloader/forms/frmMain.pas | 66 ++++++++++----------- mangadownloader/languages/fmd.en.po | 5 -- mangadownloader/languages/fmd.id_ID.po | 6 +- mangadownloader/languages/fmd.po | 5 -- 9 files changed, 83 insertions(+), 96 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 13533cb56..05aec89b0 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -62,7 +62,7 @@ procedure TCheckUpdateThread.MainThreadUpdate; begin frmMain.FUpdateURL := fUpdateURL; DoAfterFMD := DO_UPDATE; - MainForm.itMonitor.Enabled := True; + MainForm.tmExitCommand.Enabled := True; end else MainForm.btCheckLatestVersion.Caption := RS_BtnCheckUpdates; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 97ea9d072..2339be6fe 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1848,12 +1848,12 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); try if tcount > 0 then begin - if not MainForm.itRefreshDLInfo.Enabled then - MainForm.itRefreshDLInfo.Enabled := True; + if not MainForm.tmRefreshDownloadsInfo.Enabled then + MainForm.tmRefreshDownloadsInfo.Enabled := True; end else begin - MainForm.itRefreshDLInfo.Enabled := False; + MainForm.tmRefreshDownloadsInfo.Enabled := False; MainForm.UpdateVtDownload; if isCheckForFMDDo and (OptionLetFMDDo <> DO_NOTHING) then begin frmMain.DoAfterFMD := OptionLetFMDDo; @@ -1900,8 +1900,8 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; //force to check task if all task loaded is STATUS_WAIT if tcount = 0 then CheckAndActiveTask - else if MainForm.itRefreshDLInfo.Enabled = False then - MainForm.itRefreshDLInfo.Enabled := True; + else if MainForm.tmRefreshDownloadsInfo.Enabled = False then + MainForm.tmRefreshDownloadsInfo.Enabled := True; MainForm.UpdateVtDownload; end; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index b8a18bd14..1c2f5ef3f 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -192,7 +192,7 @@ procedure TGetMangaInfosThread.MainThreadShowCannotGetInfo; MessageDlg('', RS_DlgCannotGetMangaInfo, mtInformation, [mbYes], 0); MainForm.rmInformation.Clear; - MainForm.itAnimate.Enabled := False; + MainForm.tmAnimateMangaInfo.Enabled := False; MainForm.pbWait.Visible := False; MainForm.imCover.Picture.Assign(nil); except @@ -226,7 +226,7 @@ procedure TGetMangaInfosThread.MainThreadShowCover; if IsFlushed then Exit; try - MainForm.itAnimate.Enabled := False; + MainForm.tmAnimateMangaInfo.Enabled := False; MainForm.pbWait.Visible := False; if FIsHasMangaCover then begin diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e1463908e..cd4cc310e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,7 +13,7 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter - LCLVersion = '1.7' + Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -4974,28 +4974,6 @@ object MainForm: TMainForm OnClick = mnDownload1ClickClick end end - object itAnimate: TIdleTimer - Enabled = False - Interval = 48 - OnTimer = itAnimateTimer - left = 752 - top = 72 - end - object itCheckFav: TIdleTimer - Enabled = False - Interval = 600000 - OnTimer = itCheckFavTimer - left = 696 - top = 228 - end - object itRefreshDLInfo: TIdleTimer - Enabled = False - OnTimer = itRefreshDLInfoTimer - OnStartTimer = itRefreshDLInfoStartTimer - OnStopTimer = itRefreshDLInfoStopTimer - left = 696 - top = 168 - end object IconList: TImageList left = 24 top = 136 @@ -6479,24 +6457,11 @@ object MainForm: TMainForm left = 80 top = 448 end - object itStartup: TIdleTimer - Enabled = False - Interval = 500 - OnTimer = itStartupTimer - left = 648 - top = 120 - end - object tmBackup: TIdleTimer - Interval = 60000 - OnTimer = tmBackupTimer - left = 696 - top = 120 - end - object itMonitor: TTimer + object tmExitCommand: TTimer Enabled = False - OnTimer = itMonitorTimer - left = 648 - top = 224 + OnTimer = tmExitCommandTimer + left = 240 + top = 184 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( @@ -6597,4 +6562,39 @@ object MainForm: TMainForm OnClick = miTrayExitClick end end + object tmAnimateMangaInfo: TTimer + Enabled = False + Interval = 48 + OnTimer = tmAnimateMangaInfoTimer + left = 336 + top = 128 + end + object tmStartup: TTimer + Enabled = False + Interval = 500 + OnTimer = tmStartupTimer + left = 240 + top = 128 + end + object tmRefreshDownloadsInfo: TTimer + Enabled = False + OnTimer = tmRefreshDownloadsInfoTimer + OnStartTimer = tmRefreshDownloadsInfoStartTimer + OnStopTimer = tmRefreshDownloadsInfoStopTimer + left = 240 + top = 256 + end + object tmBackup: TTimer + Interval = 120000 + OnTimer = tmBackupTimer + left = 336 + top = 184 + end + object tmCheckFavorites: TTimer + Enabled = False + Interval = 600000 + OnTimer = tmCheckFavoritesTimer + left = 376 + top = 256 + end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 406c6720d..fd5aaa5c0 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":57972706,"name":"tmainform.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Free Manga Downloader"}, {"hash":240327891,"name":"tmainform.tsdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, {"hash":5473489,"name":"tmainform.vtdownload.header.columns[0].text","sourcebytes":[77,97,110,103,97],"value":"Manga"}, {"hash":95062979,"name":"tmainform.vtdownload.header.columns[1].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6f45ca359..6dced031c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -108,6 +108,11 @@ TMainForm = class(TForm) pmTray: TPopupMenu; sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; + tmAnimateMangaInfo: TTimer; + tmBackup: TTimer; + tmCheckFavorites: TTimer; + tmRefreshDownloadsInfo: TTimer; + tmStartup: TTimer; tsWebsiteAdvanced: TTabSheet; tsWebsiteSelection: TTabSheet; tsWebsiteOptions: TTabSheet; @@ -130,8 +135,7 @@ TMainForm = class(TForm) IconDL: TImageList; IconMed: TImageList; IconSmall: TImageList; - itMonitor: TTimer; - itStartup: TIdleTimer; + tmExitCommand: TTimer; lbDefaultDownloadPath: TLabel; lbDropTargetOpacity: TLabel; lbOptionExternalParams: TLabel; @@ -239,9 +243,6 @@ TMainForm = class(TForm) gbOptionRenaming: TGroupBox; gbOptionFavorites: TGroupBox; IconList: TImageList; - itRefreshDLInfo: TIdleTimer; - itCheckFav: TIdleTimer; - itAnimate: TIdleTimer; imCover: TImage; lbOptionChapterCustomRename: TLabel; lbOptionPDFQuality: TLabel; @@ -338,7 +339,6 @@ TMainForm = class(TForm) tbWebsitesExpandAll: TToolButton; ToolBarWebsites: TToolBar; tsView: TTabSheet; - tmBackup: TIdleTimer; ToolBarDownload: TToolBar; tbDownloadResumeAll: TToolButton; tbDownloadStopAll: TToolButton; @@ -421,13 +421,13 @@ TMainForm = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormWindowStateChange(Sender: TObject); - procedure itAnimateTimer(Sender: TObject); - procedure itCheckFavTimer(Sender: TObject); - procedure itMonitorTimer(Sender: TObject); - procedure itRefreshDLInfoStartTimer(Sender: TObject); - procedure itRefreshDLInfoStopTimer(Sender: TObject); - procedure itRefreshDLInfoTimer(Sender: TObject); - procedure itStartupTimer(Sender: TObject); + procedure tmAnimateMangaInfoTimer(Sender: TObject); + procedure tmCheckFavoritesTimer(Sender: TObject); + procedure tmExitCommandTimer(Sender: TObject); + procedure tmRefreshDownloadsInfoStartTimer(Sender: TObject); + procedure tmRefreshDownloadsInfoStopTimer(Sender: TObject); + procedure tmRefreshDownloadsInfoTimer(Sender: TObject); + procedure tmStartupTimer(Sender: TObject); procedure medURLCutClick(Sender: TObject); procedure medURLCopyClick(Sender: TObject); procedure medURLPasteClick(Sender: TObject); @@ -1281,11 +1281,11 @@ procedure TMainForm.CloseNow; Writelog_D(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; - itRefreshDLInfo.Enabled := False; - itCheckFav.Enabled := False; - itAnimate.Enabled := False; - itStartup.Enabled := False; - itMonitor.Enabled := False; + tmRefreshDownloadsInfo.Enabled := False; + tmCheckFavorites.Enabled := False; + tmAnimateMangaInfo.Enabled := False; + tmStartup.Enabled := False; + tmExitCommand.Enabled := False; Writelog_D(Self.ClassName+'.CloseNow, backup all data to file'); //Backup data @@ -1338,7 +1338,7 @@ procedure TMainForm.FormShow(Sender: TObject); if not isStartup then begin LoadFormInformation; - itStartup.Enabled := True; + tmStartup.Enabled := True; end; end; @@ -1363,12 +1363,12 @@ procedure TMainForm.FormWindowStateChange(Sender: TObject); PrevWindowState := WindowState; end; -procedure TMainForm.itAnimateTimer(Sender: TObject); +procedure TMainForm.tmAnimateMangaInfoTimer(Sender: TObject); begin gifWaiting.Update(pbWait.Canvas, gifWaitingRect); end; -procedure TMainForm.itCheckFavTimer(Sender: TObject); +procedure TMainForm.tmCheckFavoritesTimer(Sender: TObject); begin if IsDlgCounter then Exit; if OptionAutoCheckLatestVersion then @@ -1453,9 +1453,9 @@ procedure TMainForm.FilterChapterList(const SearchStr: String; end; end; -procedure TMainForm.itMonitorTimer(Sender: TObject); +procedure TMainForm.tmExitCommandTimer(Sender: TObject); begin - itMonitor.Enabled := False; + tmExitCommand.Enabled := False; if DoAfterFMD <> DO_NOTHING then begin if DoAfterFMD in [DO_POWEROFF, DO_HIBERNATE, DO_EXIT] then @@ -1489,7 +1489,7 @@ procedure TMainForm.itMonitorTimer(Sender: TObject); end; end; -procedure TMainForm.itRefreshDLInfoStartTimer(Sender: TObject); +procedure TMainForm.tmRefreshDownloadsInfoStartTimer(Sender: TObject); begin if Assigned(DLManager) then begin @@ -1498,22 +1498,22 @@ procedure TMainForm.itRefreshDLInfoStartTimer(Sender: TObject); end; end; -procedure TMainForm.itRefreshDLInfoStopTimer(Sender: TObject); +procedure TMainForm.tmRefreshDownloadsInfoStopTimer(Sender: TObject); begin TransferRateGraph.Visible := False; vtDownload.Repaint; end; -procedure TMainForm.itRefreshDLInfoTimer(Sender: TObject); +procedure TMainForm.tmRefreshDownloadsInfoTimer(Sender: TObject); begin if Assigned(DLManager) then TransferRateGraphAddItem(DLManager.TransferRate); vtDownload.Repaint; end; -procedure TMainForm.itStartupTimer(Sender: TObject); +procedure TMainForm.tmStartupTimer(Sender: TObject); begin - itStartup.Enabled := False; + tmStartup.Enabled := False; if not isStartup then begin isStartup := True; @@ -4190,7 +4190,7 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; clbChapterList.Clear; if Assigned(gifWaiting) then begin - itAnimate.Enabled := True; + tmAnimateMangaInfo.Enabled := True; pbWait.Visible := True; end; btDownload.Enabled := False; @@ -4601,8 +4601,8 @@ procedure TMainForm.ApplyOptions; OptionAutoCheckFavRemoveCompletedManga := cbOptionAutoCheckFavRemoveCompletedManga.Checked; OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; OptionUpdateListRemoveDuplicateLocalData := cbOptionUpdateListRemoveDuplicateLocalData.Checked; - itCheckFav.Interval := OptionAutoCheckFavIntervalMinutes * 60000; - itCheckFav.Enabled := OptionAutoCheckFavInterval; + tmCheckFavorites.Interval := OptionAutoCheckFavIntervalMinutes * 60000; + tmCheckFavorites.Enabled := OptionAutoCheckFavInterval; //misc frmCustomColor.Apply; @@ -5178,7 +5178,7 @@ procedure TMainForm.DoExitWaitCounter; Writelog_D(Self.ClassName+', Update thread still exist, pending exit counter'); isPendingExitCounter:=True end - else itMonitor.Enabled:=True; + else tmExitCommand.Enabled:=True; end; procedure TMainForm.ExceptionHandler(Sender: TObject; E: Exception); @@ -5190,6 +5190,8 @@ procedure TMainForm.tmBackupTimer(Sender: TObject); begin if not DLManager.isRunningBackup then DLManager.Backup; + if not FavoriteManager.isRunning then + FavoriteManager.Backup; end; procedure TMainForm.vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d05ae54a2..75e6ef265 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -536,11 +536,6 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index be75c8ae3..ab9d655fb 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -527,11 +527,6 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" -#: tmainform.caption -msgctxt "tmainform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" @@ -2107,3 +2102,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index f290f6372..df56cc8de 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -492,11 +492,6 @@ msgstr "" msgid "Visit my blog" msgstr "" -#: tmainform.caption -msgctxt "TMAINFORM.CAPTION" -msgid "Free Manga Downloader" -msgstr "" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From c8b126674fd56741596cb4d6efacf483646f9a1f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 29 Jul 2016 11:35:02 +0800 Subject: [PATCH 1332/2794] removed tmstartup, create it at runtime, and freed after use --- mangadownloader/forms/frmMain.lfm | 15 ++++----------- mangadownloader/forms/frmMain.pas | 12 ++++++++---- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index cd4cc310e..b6b257918 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4114,8 +4114,8 @@ object MainForm: TMainForm object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - left = 584 - top = 180 + left = 592 + top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -4445,8 +4445,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - left = 584 - top = 212 + left = 592 + top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -6569,13 +6569,6 @@ object MainForm: TMainForm left = 336 top = 128 end - object tmStartup: TTimer - Enabled = False - Interval = 500 - OnTimer = tmStartupTimer - left = 240 - top = 128 - end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6dced031c..9793f5a22 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -112,7 +112,6 @@ TMainForm = class(TForm) tmBackup: TTimer; tmCheckFavorites: TTimer; tmRefreshDownloadsInfo: TTimer; - tmStartup: TTimer; tsWebsiteAdvanced: TTabSheet; tsWebsiteSelection: TTabSheet; tsWebsiteOptions: TTabSheet; @@ -1284,7 +1283,6 @@ procedure TMainForm.CloseNow; tmRefreshDownloadsInfo.Enabled := False; tmCheckFavorites.Enabled := False; tmAnimateMangaInfo.Enabled := False; - tmStartup.Enabled := False; tmExitCommand.Enabled := False; Writelog_D(Self.ClassName+'.CloseNow, backup all data to file'); @@ -1338,7 +1336,12 @@ procedure TMainForm.FormShow(Sender: TObject); if not isStartup then begin LoadFormInformation; - tmStartup.Enabled := True; + with TTimer.Create(nil) do + begin + OnTimer := @tmStartupTimer; + Interval := 1000; + Enabled := True; + end; end; end; @@ -1513,7 +1516,6 @@ procedure TMainForm.tmRefreshDownloadsInfoTimer(Sender: TObject); procedure TMainForm.tmStartupTimer(Sender: TObject); begin - tmStartup.Enabled := False; if not isStartup then begin isStartup := True; @@ -1528,6 +1530,8 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); end; DLManager.CheckAndActiveTaskAtStartup; end; + if Sender is TTimer then + TTimer(Sender).Free; end; procedure TMainForm.medURLCutClick(Sender: TObject); From 5539f4816fdc785b83f694ec341d345ee9efad74 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 30 Jul 2016 21:59:01 +0800 Subject: [PATCH 1333/2794] added favorites filter, fix chapterlist filter and fix layout --- baseunits/uUpdateDBThread.pas | 2 +- mangadownloader/forms/frmMain.lfm | 210 ++++++++++++++++--------- mangadownloader/forms/frmMain.lrj | 5 +- mangadownloader/forms/frmMain.pas | 147 +++++++++++------ mangadownloader/languages/fmd.en.po | 21 +-- mangadownloader/languages/fmd.id_ID.po | 15 +- mangadownloader/languages/fmd.po | 14 +- 7 files changed, 266 insertions(+), 148 deletions(-) diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 2e608988f..2e67bb744 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -43,7 +43,7 @@ procedure TUpdateDBThread.MainThreadRefreshList; try if MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex] = websiteName then begin - MainForm.edSearch.Clear; + MainForm.edMangaListSearch.Clear; MainForm.vtMangaList.Clear; MainForm.dataProcess.Close; ExtractFile; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b6b257918..b94d0c308 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -47,6 +47,10 @@ object MainForm: TMainForm OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ClientHeight = 492 ClientWidth = 558 object vtDownload: TVirtualStringTree @@ -55,9 +59,6 @@ object MainForm: TMainForm Top = 32 Width = 550 Align = alClient - BorderSpacing.Left = 4 - BorderSpacing.Right = 4 - BorderSpacing.Bottom = 4 Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight Colors.SelectionRectangleBorderColor = clHotLight @@ -137,16 +138,15 @@ object MainForm: TMainForm Top = 4 Width = 550 Align = alTop - BorderSpacing.Around = 4 BevelOuter = bvNone ClientHeight = 24 ClientWidth = 550 TabOrder = 1 object TransferRateGraph: TChart - Left = 321 + Left = 84 Height = 24 Top = 0 - Width = 229 + Width = 466 AllowZoom = False AxisList = < item @@ -204,18 +204,18 @@ object MainForm: TMainForm Left = 0 Height = 24 Top = 0 - Width = 321 + Width = 84 Align = alLeft AutoSize = True BevelOuter = bvNone ClientHeight = 24 - ClientWidth = 321 + ClientWidth = 84 TabOrder = 1 object ToolBarDownload: TToolBar Left = 0 Height = 24 Top = 0 - Width = 321 + Width = 84 Align = alClient AutoSize = True ButtonHeight = 25 @@ -236,7 +236,7 @@ object MainForm: TMainForm OnClick = tbDownloadResumeAllClick end object tbDownloadStopAll: TToolButton - Left = 86 + Left = 27 Top = 0 AutoSize = True Caption = 'Stop All' @@ -244,14 +244,14 @@ object MainForm: TMainForm OnClick = tbDownloadStopAllClick end object ToolButton1: TToolButton - Left = 153 + Left = 53 Height = 25 Top = 0 Width = 5 Style = tbsDivider end object tbDownloadDeleteCompleted: TToolButton - Left = 158 + Left = 58 Top = 0 AutoSize = True Caption = 'Delete all completed tasks' @@ -1797,62 +1797,20 @@ object MainForm: TMainForm end object tsFavorites: TTabSheet Caption = 'Favorites' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 ClientHeight = 492 ClientWidth = 558 - object btFavoritesCheckNewChapter: TBitBtn - Left = 33 - Height = 40 - Top = 412 - Width = 491 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Check for new chapter' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 - 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 - 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB - E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 - 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 - E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 - 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 - D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 - 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 - BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 - 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 - 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 - 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F - 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 - 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D - 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 - 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F - 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 - 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 - 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 - 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 - 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 - 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 - 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 - 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 - 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 - 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 - 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 - E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 - 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550073AA550000AA550000 - } - OnClick = btFavoritesCheckNewChapterClick - TabOrder = 1 - end object vtFavorites: TVirtualStringTree + AnchorSideTop.Control = edFavoritesSearch + AnchorSideTop.Side = asrBottom Left = 4 - Height = 401 - Top = 4 + Height = 373 + Top = 32 Width = 550 - Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Around = 4 Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight Colors.SelectionRectangleBorderColor = clHotLight @@ -2003,6 +1961,110 @@ object MainForm: TMainForm Visible = False OnClick = btCancelFavoritesCheckClick end + object btFavoritesCheckNewChapter: TBitBtn + Left = 33 + Height = 40 + Top = 412 + Width = 491 + Anchors = [akLeft, akRight, akBottom] + Caption = 'Check for new chapter' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 + 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 + 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB + E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 + 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 + E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 + 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 + D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 + 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 + BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 + 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 + 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 + 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F + 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 + 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D + 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 + 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F + 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 + 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 + 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 + 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 + 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 + 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 + 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 + 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 + 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 + 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 + 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 + E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 + 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550073AA550000AA550000 + } + OnClick = btFavoritesCheckNewChapterClick + TabOrder = 1 + end + object edFavoritesSearch: TEdit + Left = 4 + Height = 23 + Top = 5 + Width = 200 + OnChange = edFavoritesSearchChange + TabOrder = 3 + TextHint = 'Search favorites...' + end + object btFavoritesSearchClear: TSpeedButton + AnchorSideLeft.Control = edFavoritesSearch + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edFavoritesSearch + AnchorSideBottom.Control = edFavoritesSearch + AnchorSideBottom.Side = asrBottom + Left = 208 + Height = 23 + Top = 5 + Width = 23 + Anchors = [akTop, akLeft, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btFavoritesSearchClearClick + end end object tsOption: TTabSheet Caption = 'Options' @@ -2013,10 +2075,10 @@ object MainForm: TMainForm Height = 415 Top = 8 Width = 539 - ActivePage = tsGeneral + ActivePage = tsWebsites Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 6 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -3932,7 +3994,7 @@ object MainForm: TMainForm OnClick = btUpdateListClick ShowCaption = False end - object edSearch: TEdit + object edMangaListSearch: TEdit AnchorSideLeft.Control = cbSelectManga AnchorSideTop.Control = cbSelectManga AnchorSideTop.Side = asrBottom @@ -3943,15 +4005,15 @@ object MainForm: TMainForm Top = 31 Width = 150 Anchors = [akTop, akLeft, akRight] - OnChange = edSearchChange - OnKeyDown = edSearchKeyDown + OnChange = edMangaListSearchChange + OnKeyDown = edMangaListSearchKeyDown TabOrder = 2 TextHint = 'Search title...' end - object btSearchClear: TSpeedButton - AnchorSideLeft.Control = edSearch + object btMangaListSearchClear: TSpeedButton + AnchorSideLeft.Control = edMangaListSearch AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edSearch + AnchorSideTop.Control = edMangaListSearch AnchorSideTop.Side = asrCenter Left = 158 Height = 23 @@ -3993,14 +4055,14 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btSearchClearClick + OnClick = btMangaListSearchClearClick ShowCaption = False end object lbMode: TLabel - AnchorSideLeft.Control = edSearch - AnchorSideTop.Control = edSearch + AnchorSideLeft.Control = edMangaListSearch + AnchorSideTop.Control = edMangaListSearch AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = edSearch + AnchorSideRight.Control = edMangaListSearch AnchorSideRight.Side = asrBottom Left = 4 Height = 15 diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index fd5aaa5c0..b03e23c52 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -120,13 +120,14 @@ {"hash":235689698,"name":"tmainform.btremovefilterlarge.caption","sourcebytes":[82,101,109,111,118,101,32,102,105,108,116,101,114],"value":"Remove filter"}, {"hash":103074421,"name":"tmainform.btfilterreset.caption","sourcebytes":[82,101,115,101,116,32,118,97,108,117,101],"value":"Reset value"}, {"hash":225003075,"name":"tmainform.tsfavorites.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, -{"hash":165778738,"name":"tmainform.btfavoriteschecknewchapter.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Check for new chapter"}, {"hash":35,"name":"tmainform.vtfavorites.header.columns[0].text","sourcebytes":[35],"value":"#"}, {"hash":5966629,"name":"tmainform.vtfavorites.header.columns[1].text","sourcebytes":[84,105,116,108,101],"value":"Title"}, {"hash":6579810,"name":"tmainform.vtfavorites.header.columns[2].text","sourcebytes":[67,117,114,114,101,110,116,32,99,104,97,112,116,101,114],"value":"Current chapter"}, {"hash":230269173,"name":"tmainform.vtfavorites.header.columns[3].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, {"hash":160200703,"name":"tmainform.vtfavorites.header.columns[4].text","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":154630084,"name":"tmainform.btfavoritesimport.caption","sourcebytes":[73,109,112,111,114,116,32,108,105,115,116],"value":"Import list"}, +{"hash":165778738,"name":"tmainform.btfavoriteschecknewchapter.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Check for new chapter"}, +{"hash":266084494,"name":"tmainform.edfavoritessearch.texthint","sourcebytes":[83,101,97,114,99,104,32,102,97,118,111,114,105,116,101,115,46,46,46],"value":"Search favorites..."}, {"hash":108725763,"name":"tmainform.tsoption.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, {"hash":231000124,"name":"tmainform.tsgeneral.caption","sourcebytes":[71,101,110,101,114,97,108],"value":"General"}, {"hash":189923241,"name":"tmainform.cboptionminimizetotray.caption","sourcebytes":[77,105,110,105,109,105,122,101,32,116,111,32,116,114,97,121],"value":"Minimize to tray"}, @@ -227,7 +228,7 @@ {"hash":206498996,"name":"tmainform.btabortupdatelist.hint","sourcebytes":[65,98,111,114,116,32,117,112,100,97,116,101,32,108,105,115,116],"value":"Abort update list"}, {"hash":158194067,"name":"tmainform.cbselectmanga.hint","sourcebytes":[70,111,114,32,109,111,114,101,32,109,97,110,103,97,32,115,105,116,101,115,44,32,112,108,101,97,115,101,32,103,111,32,116,111,32,79,112,116,105,111,110,115,45,62,77,97,110,103,97,32,115,105,116,101,115],"value":"For more manga sites, please go to Options->Manga sites"}, {"hash":119443044,"name":"tmainform.btupdatelist.hint","sourcebytes":[85,112,100,97,116,101,32,109,97,110,103,97,32,108,105,115,116],"value":"Update manga list"}, -{"hash":138125102,"name":"tmainform.edsearch.texthint","sourcebytes":[83,101,97,114,99,104,32,116,105,116,108,101,46,46,46],"value":"Search title..."}, +{"hash":138125102,"name":"tmainform.edmangalistsearch.texthint","sourcebytes":[83,101,97,114,99,104,32,116,105,116,108,101,46,46,46],"value":"Search title..."}, {"hash":150137481,"name":"tmainform.lbmode.caption","sourcebytes":[77,111,100,101,58,32,83,104,111,119,32,97,108,108,32,40,48,41],"value":"Mode: Show all (0)"}, {"hash":1054,"name":"tmainform.tsdownloadfilter.caption","sourcebytes":[62,62],"value":">>"}, {"hash":371552,"name":"tmainform.midownloadstop.caption","sourcebytes":[83,116,111,112],"value":"Stop"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9793f5a22..809034456 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -43,7 +43,7 @@ TMainForm = class(TForm) btOptionApply: TBitBtn; btReadOnline: TBitBtn; btRemoveFilter: TSpeedButton; - btSearchClear: TSpeedButton; + btMangaListSearchClear: TSpeedButton; btWebsitesSearchClear: TSpeedButton; btUpdateList: TSpeedButton; cbOptionAutoCheckFavStartup: TCheckBox; @@ -64,6 +64,7 @@ TMainForm = class(TForm) cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; edFilterMangaInfoChapters: TEditButton; + edFavoritesSearch: TEdit; edOptionFilenameCustomRename: TEdit; edOptionDefaultPath: TDirectoryEdit; edOptionMangaCustomRename: TEdit; @@ -108,6 +109,7 @@ TMainForm = class(TForm) pmTray: TPopupMenu; sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; + btFavoritesSearchClear: TSpeedButton; tmAnimateMangaInfo: TTimer; tmBackup: TTimer; tmCheckFavorites: TTimer; @@ -236,7 +238,7 @@ TMainForm = class(TForm) edOptionPass: TEdit; edOptionPort: TEdit; edOptionUser: TEdit; - edSearch: TEdit; + edMangaListSearch: TEdit; gbDialogs: TGroupBox; gbOptionProxy: TGroupBox; gbOptionRenaming: TGroupBox; @@ -376,9 +378,10 @@ TMainForm = class(TForm) procedure btChecksClick(Sender: TObject); procedure btCheckLatestVersionClick(Sender: TObject); procedure btDonateClick(Sender: TObject); + procedure btFavoritesSearchClearClick(Sender: TObject); procedure btFavoritesImportClick(Sender: TObject); procedure btReadOnlineClick(Sender: TObject); - procedure btSearchClearClick(Sender: TObject); + procedure btMangaListSearchClearClick(Sender: TObject); procedure btUpdateListClick(Sender: TObject); procedure btVisitMyBlogClick(Sender: TObject); procedure btWebsitesSearchClearClick(Sender: TObject); @@ -396,11 +399,12 @@ TMainForm = class(TForm) var CellText: String); procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure edFavoritesSearchChange(Sender: TObject); procedure edFilterMangaInfoChaptersButtonClick(Sender: TObject); procedure edFilterMangaInfoChaptersChange(Sender: TObject); procedure edSaveToAcceptDirectory(Sender: TObject; var Value: String); - procedure edSearchChange(Sender: TObject); - procedure edSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState + procedure edMangaListSearchChange(Sender: TObject); + procedure edMangaListSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState ); procedure edURLButtonClick(Sender: TObject); procedure edURLKeyPress(Sender: TObject; var Key: Char); @@ -903,8 +907,8 @@ procedure TSearchDBThread.SyncBeforeSearch; with MainForm do begin vtMangaList.Cursor := crHourGlass; - vtMangaList.Clear; lbMode.Caption := RS_ModeSearching; + vtMangaList.BeginUpdate; end; end; @@ -912,15 +916,14 @@ procedure TSearchDBThread.SyncAfterSearch; begin with MainForm do begin + vtMangaList.RootNodeCount := dataProcess.RecordCount; + vtMangaList.EndUpdate; if dataProcess.Filtered then lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]) else lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); LastSearchWeb := dataProcess.Website; LastSearchStr := UpCase(FSearchStr); - vtMangaList.BeginUpdate; - vtMangaList.RootNodeCount := dataProcess.RecordCount; - vtMangaList.EndUpdate; vtMangaList.Cursor := crDefault; end; end; @@ -971,8 +974,8 @@ procedure TOpenDBThread.SetControlEnabled(const Value: Boolean); begin cbSelectManga.Enabled := Value; btUpdateList.Enabled := Value; - edSearch.Enabled := Value; - btSearchClear.Enabled := Value; + edMangaListSearch.Enabled := Value; + btMangaListSearchClear.Enabled := Value; btRemoveFilter.Enabled := Value; end; end; @@ -992,7 +995,7 @@ procedure TOpenDBThread.SyncOpenFinish; begin with MainForm do begin - LastSearchStr := upcase(edSearch.Text); + LastSearchStr := upcase(edMangaListSearch.Text); LastSearchWeb := currentWebsite; if dataProcess.Filtered then lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]) @@ -1014,8 +1017,8 @@ procedure TOpenDBThread.Execute; if MainForm.dataProcess <> nil then begin MainForm.dataProcess.Open(FWebsite); - if MainForm.edSearch.Text <> '' then - MainForm.dataProcess.Search(MainForm.edSearch.Text); + if MainForm.edMangaListSearch.Text <> '' then + MainForm.dataProcess.Search(MainForm.edMangaListSearch.Text); end; if not Terminated then Synchronize(@SyncOpenFinish); @@ -1437,23 +1440,29 @@ procedure TMainForm.FilterGenreChangeAllState(const AState: TCheckBoxState); procedure TMainForm.FilterChapterList(const SearchStr: String; const HideDownloaded: Boolean); var - xNode: PVirtualNode; - s: String; + Node: PVirtualNode; + S: String; isShow: Boolean; begin if clbChapterList.RootNodeCount = 0 then Exit; - xNode := clbChapterList.GetFirst(); - s := lowerCase(SearchStr); - while Assigned(xNode) do - begin - isShow := True; - if HideDownloaded then - isShow := not ChapterList[xNode^.Index].Downloaded; - if isShow and (s <> '') then - isShow := Pos(s, LowerCase(ChapterList[xNode^.Index].Title)) <> 0; - clbChapterList.IsVisible[xNode] := isShow; - xNode := clbChapterList.GetNext(xNode); - end; + with clbChapterList do + try + BeginUpdate; + S := AnsiUpperCase(SearchStr); + Node := GetFirst(); + while Assigned(Node) do + begin + isShow := True; + if HideDownloaded then + isShow := not ChapterList[Node^.Index].Downloaded; + if isShow and (S <> '') then + isShow := Pos(S, AnsiUpperCase(ChapterList[Node^.Index].Title)) <> 0; + IsVisible[Node] := isShow; + Node := GetNext(Node); + end; + finally + EndUpdate; + end; end; procedure TMainForm.tmExitCommandTimer(Sender: TObject); @@ -2173,10 +2182,10 @@ procedure TMainForm.btReadOnlineClick(Sender: TObject); OpenURL(mangaInfo.url); end; -procedure TMainForm.btSearchClearClick(Sender: TObject); +procedure TMainForm.btMangaListSearchClearClick(Sender: TObject); begin - edSearch.Tag := 1; - edSearch.Clear; + edMangaListSearch.Tag := 1; + edMangaListSearch.Clear; end; procedure TMainForm.btCheckLatestVersionClick(Sender: TObject); @@ -2192,6 +2201,11 @@ procedure TMainForm.btDonateClick(Sender: TObject); OpenURL('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=akarin.km@gmail.com&item_name=Donation+to+Free+Manga+Downloader'); end; +procedure TMainForm.btFavoritesSearchClearClick(Sender: TObject); +begin + edFavoritesSearch.Clear; +end; + procedure TMainForm.btFavoritesImportClick(Sender: TObject); begin with TImportFavorites.Create(Self) do try @@ -2267,6 +2281,39 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; +procedure TMainForm.edFavoritesSearchChange(Sender: TObject); +var + Node: PVirtualNode; + S: String; +begin + if vtFavorites.RootNodeCount = 0 then Exit; + with vtFavorites do + try + BeginUpdate; + if (edFavoritesSearch.Text = '') and (VisibleCount <> RootNodeCount) then + begin + Node := GetFirst(); + while Assigned(Node) do + begin + IsVisible[Node] := True; + Node := GetNext(Node); + end; + end + else + begin + S := AnsiUpperCase(edFavoritesSearch.Text); + Node := GetFirst(); + while Assigned(Node) do + begin + IsVisible[Node] := Pos(S, AnsiUpperCase(FavoriteManager[Node^.Index].FavoriteInfo.Title)) > 0; + Node := GetNext(Node); + end; + end; + finally + EndUpdate; + end; +end; + procedure TMainForm.edFilterMangaInfoChaptersButtonClick(Sender: TObject); begin edFilterMangaInfoChapters.Clear; @@ -2381,8 +2428,8 @@ procedure TMainForm.btRemoveFilterClick(Sender: TObject); dataProcess.RemoveFilter; vtMangaList.RootNodeCount := dataProcess.RecordCount; lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); - edSearch.Tag := -1; - edSearch.Clear; + edMangaListSearch.Tag := -1; + edMangaListSearch.Clear; except on E: Exception do ExceptionHandler(Self, E); @@ -2449,8 +2496,8 @@ procedure TMainForm.btFilterClick(Sender: TObject); if cbSearchFromAllSites.Checked then dataProcess.SitesList.Assign(cbSelectManga.Items); - edSearch.Tag := -1; - edSearch.Clear; + edMangaListSearch.Tag := -1; + edMangaListSearch.Clear; vtMangaList.Clear; dataProcess.Filter( @@ -4743,25 +4790,25 @@ function TMainForm.SaveMangaOptions: String; end; end; -procedure TMainForm.edSearchChange(Sender: TObject); +procedure TMainForm.edMangaListSearchChange(Sender: TObject); begin - if edSearch.Tag = -1 then + if edMangaListSearch.Tag = -1 then begin - edSearch.Tag := 0; + edMangaListSearch.Tag := 0; LastSearchWeb := currentWebsite; - LastSearchStr := UpCase(edSearch.Text); + LastSearchStr := UpCase(edMangaListSearch.Text); Exit; end; - if (not cbOptionLiveSearch.Checked) and (edSearch.Tag = 0) then Exit; - if edSearch.Tag <> 0 then - edSearch.Tag := 0; - if (upcase(edSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb) then + if (not cbOptionLiveSearch.Checked) and (edMangaListSearch.Tag = 0) then Exit; + if edMangaListSearch.Tag <> 0 then + edMangaListSearch.Tag := 0; + if (upcase(edMangaListSearch.Text) = LastSearchStr) and (currentWebsite = LastSearchWeb) then Exit; - SearchDataDB(edSearch.Text); + SearchDataDB(edMangaListSearch.Text); //vtMangaList.Clear; - //dataProcess.Search(edSearch.Text); + //dataProcess.Search(edMangaListSearch.Text); //vtMangaList.RootNodeCount := dataProcess.RecordCount; //if dataProcess.Filtered then // lbMode.Caption := Format(RS_ModeFiltered, [vtMangaList.RootNodeCount]) @@ -4769,17 +4816,17 @@ procedure TMainForm.edSearchChange(Sender: TObject); // lbMode.Caption := Format(RS_ModeAll, [vtMangaList.RootNodeCount]); end; -procedure TMainForm.edSearchKeyDown(Sender: TObject; var Key: Word; +procedure TMainForm.edMangaListSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_RETURN then begin - edSearch.Tag := 1; - edSearchChange(edSearch); + edMangaListSearch.Tag := 1; + edMangaListSearchChange(edMangaListSearch); end else - if edSearch.Tag <> 0 then - edSearch.Tag := 0; + if edMangaListSearch.Tag <> 0 then + edMangaListSearch.Tag := 0; end; procedure TMainForm.edURLButtonClick(Sender: TObject); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 75e6ef265..a48dcf0d7 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -123,7 +123,7 @@ msgstr "Are you sure you want to delete all finished tasks?" #: frmmain.rs_dlgremoveitem msgid "Are you sure you want to delete this item(s)?" -msgstr "" +msgstr "Are you sure you want to delete this item(s)?" #: frmmain.rs_dlgremovetask msgid "Are you sure you want to delete the task(s)?" @@ -984,6 +984,10 @@ msgstr "This work usually involves intimate relationships between women." msgid "Input custom genres, separated by comma" msgstr "Input custom genres, separated by comma" +#: tmainform.edfavoritessearch.texthint +msgid "Search favorites..." +msgstr "Search favorites..." + #: tmainform.edfilterartists.texthint msgctxt "tmainform.edfilterartists.texthint" msgid "Artist" @@ -1008,6 +1012,11 @@ msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" msgid "Title" msgstr "Title" +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Search title..." + #: tmainform.edoptionchaptercustomrename.texthint msgctxt "tmainform.edoptionchaptercustomrename.texthint" msgid "Custom rename" @@ -1060,12 +1069,6 @@ msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" msgid "Save to" msgstr "Save to" -#: tmainform.edsearch.texthint -#| msgid "Search..." -msgctxt "tmainform.edsearch.texthint" -msgid "Search title..." -msgstr "Search title..." - #: tmainform.edurl.texthint msgid "Input URL here" msgstr "Input URL here" @@ -1434,7 +1437,7 @@ msgstr "Task + Data" #: tmainform.midownloaddeletetaskdatafavorite.caption msgid "Task + Data + Favorite" -msgstr "" +msgstr "Task + Data + Favorite" #: tmainform.midownloaddisable.caption msgid "Disable" @@ -1522,7 +1525,6 @@ msgid "Add to Favorites" msgstr "Add to Favorites" #: tmainform.mimangalistdelete.caption -#, fuzzy msgctxt "tmainform.mimangalistdelete.caption" msgid "Delete" msgstr "Delete" @@ -2122,4 +2124,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index ab9d655fb..e026c12f2 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -973,6 +973,10 @@ msgstr "Biasanya melibatkan hubungan yang intim antara sesama perempuan." msgid "Input custom genres, separated by comma" msgstr "Masukan genre pilihan, dipisahkan dengan koma" +#: tmainform.edfavoritessearch.texthint +msgid "Search favorites..." +msgstr "Cari kesukaan..." + #: tmainform.edfilterartists.texthint msgctxt "tmainform.edfilterartists.texthint" msgid "Artist" @@ -997,6 +1001,11 @@ msgctxt "tmainform.edfiltertitle.texthint" msgid "Title" msgstr "Judul" +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Cari nama komik..." + #: tmainform.edoptionchaptercustomrename.texthint msgctxt "tmainform.edoptionchaptercustomrename.texthint" msgid "Custom rename" @@ -1047,11 +1056,6 @@ msgctxt "tmainform.edsaveto.texthint" msgid "Save to" msgstr "Lokasi penyimpanan" -#: tmainform.edsearch.texthint -msgctxt "tmainform.edsearch.texthint" -msgid "Search title..." -msgstr "Cari nama komik..." - #: tmainform.edurl.texthint msgid "Input URL here" msgstr "Masukkan URL disini" @@ -2102,4 +2106,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index df56cc8de..092b92b21 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -936,6 +936,10 @@ msgstr "" msgid "Input custom genres, separated by comma" msgstr "" +#: tmainform.edfavoritessearch.texthint +msgid "Search favorites..." +msgstr "" + #: tmainform.edfilterartists.texthint msgctxt "tmainform.edfilterartists.texthint" msgid "Artist" @@ -960,6 +964,11 @@ msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" msgid "Title" msgstr "" +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "" + #: tmainform.edoptionchaptercustomrename.texthint msgctxt "TMAINFORM.EDOPTIONCHAPTERCUSTOMRENAME.TEXTHINT" msgid "Custom rename" @@ -1010,11 +1019,6 @@ msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" msgid "Save to" msgstr "" -#: tmainform.edsearch.texthint -msgctxt "tmainform.edsearch.texthint" -msgid "Search title..." -msgstr "" - #: tmainform.edurl.texthint msgid "Input URL here" msgstr "" From cd018ad032d44fc2dae00d6efa1c007e69edb18c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 30 Jul 2016 22:57:03 +0800 Subject: [PATCH 1334/2794] added downloads search --- baseunits/uDownloadsManager.pas | 2 + mangadownloader/forms/frmMain.lfm | 110 +++++++++++++++++++------ mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 75 +++++++++++++++-- mangadownloader/languages/fmd.en.po | 7 ++ mangadownloader/languages/fmd.id_ID.po | 6 ++ mangadownloader/languages/fmd.po | 6 ++ 7 files changed, 175 insertions(+), 32 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2339be6fe..cf46f4a7c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -149,6 +149,7 @@ TTaskContainer = class destructor Destroy; override; procedure IncReadCount(const ACount: Integer); public + Visible: Boolean; property Website: String read FWebsite write SetWebsite; property Status: TDownloadStatusType read FStatus write SetStatus; property Enabled: Boolean read FEnabled write SetEnabled; @@ -1482,6 +1483,7 @@ constructor TTaskContainer.Create; CustomFileName := OptionFilenameCustomRename; FStatus := STATUS_NONE; FEnabled := True; + Visible := True; end; destructor TTaskContainer.Destroy; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b94d0c308..10b58a3d8 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -54,11 +54,13 @@ object MainForm: TMainForm ClientHeight = 492 ClientWidth = 558 object vtDownload: TVirtualStringTree + AnchorSideTop.Control = edDownloadsSearch + AnchorSideTop.Side = asrBottom Left = 4 Height = 456 - Top = 32 - Width = 550 - Align = alClient + Top = 31 + Width = 549 + Anchors = [akTop, akLeft, akRight, akBottom] Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight Colors.SelectionRectangleBorderColor = clHotLight @@ -133,20 +135,24 @@ object MainForm: TMainForm OnKeyUp = vtDownloadKeyUp end object pnDownloadToolbar: TPanel - Left = 4 + AnchorSideLeft.Control = btDownloadsSearchClear + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edDownloadsSearch + AnchorSideTop.Side = asrCenter + Left = 185 Height = 24 - Top = 4 - Width = 550 - Align = alTop + Top = 3 + Width = 368 + Anchors = [akTop, akLeft, akRight] BevelOuter = bvNone ClientHeight = 24 - ClientWidth = 550 + ClientWidth = 368 TabOrder = 1 object TransferRateGraph: TChart - Left = 84 + Left = 321 Height = 24 Top = 0 - Width = 466 + Width = 47 AllowZoom = False AxisList = < item @@ -204,18 +210,18 @@ object MainForm: TMainForm Left = 0 Height = 24 Top = 0 - Width = 84 + Width = 321 Align = alLeft AutoSize = True BevelOuter = bvNone ClientHeight = 24 - ClientWidth = 84 + ClientWidth = 321 TabOrder = 1 object ToolBarDownload: TToolBar Left = 0 Height = 24 Top = 0 - Width = 84 + Width = 321 Align = alClient AutoSize = True ButtonHeight = 25 @@ -236,7 +242,7 @@ object MainForm: TMainForm OnClick = tbDownloadResumeAllClick end object tbDownloadStopAll: TToolButton - Left = 27 + Left = 86 Top = 0 AutoSize = True Caption = 'Stop All' @@ -244,14 +250,14 @@ object MainForm: TMainForm OnClick = tbDownloadStopAllClick end object ToolButton1: TToolButton - Left = 53 + Left = 153 Height = 25 Top = 0 Width = 5 Style = tbsDivider end object tbDownloadDeleteCompleted: TToolButton - Left = 58 + Left = 158 Top = 0 AutoSize = True Caption = 'Delete all completed tasks' @@ -261,6 +267,64 @@ object MainForm: TMainForm end end end + object edDownloadsSearch: TEdit + Left = 4 + Height = 23 + Top = 4 + Width = 150 + OnChange = edDownloadsSearchChange + TabOrder = 2 + TextHint = 'Search downloads...' + end + object btDownloadsSearchClear: TSpeedButton + AnchorSideLeft.Control = edDownloadsSearch + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edDownloadsSearch + AnchorSideBottom.Control = edDownloadsSearch + AnchorSideBottom.Side = asrBottom + Left = 158 + Height = 23 + Top = 4 + Width = 23 + Anchors = [akTop, akLeft, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 + 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 + 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 + 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 + D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 + 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 + 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 + 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 + 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 + 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 + 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 + 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 + 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 + A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 + A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 + A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D + F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 + A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 + AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btDownloadsSearchClearClick + end end object tsInformation: TTabSheet Caption = 'Manga Info' @@ -1807,9 +1871,9 @@ object MainForm: TMainForm AnchorSideTop.Control = edFavoritesSearch AnchorSideTop.Side = asrBottom Left = 4 - Height = 373 - Top = 32 - Width = 550 + Height = 374 + Top = 31 + Width = 549 Anchors = [akTop, akLeft, akRight, akBottom] Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight @@ -2010,8 +2074,8 @@ object MainForm: TMainForm object edFavoritesSearch: TEdit Left = 4 Height = 23 - Top = 5 - Width = 200 + Top = 4 + Width = 150 OnChange = edFavoritesSearchChange TabOrder = 3 TextHint = 'Search favorites...' @@ -2022,9 +2086,9 @@ object MainForm: TMainForm AnchorSideTop.Control = edFavoritesSearch AnchorSideBottom.Control = edFavoritesSearch AnchorSideBottom.Side = asrBottom - Left = 208 + Left = 158 Height = 23 - Top = 5 + Top = 4 Width = 23 Anchors = [akTop, akLeft, akBottom] Glyph.Data = { diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index b03e23c52..d3ce10e0d 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -10,6 +10,7 @@ {"hash":204655756,"name":"tmainform.tbdownloadresumeall.caption","sourcebytes":[82,101,115,117,109,101,32,65,108,108],"value":"Resume All"}, {"hash":190989196,"name":"tmainform.tbdownloadstopall.caption","sourcebytes":[83,116,111,112,32,65,108,108],"value":"Stop All"}, {"hash":235571507,"name":"tmainform.tbdownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, +{"hash":173363182,"name":"tmainform.eddownloadssearch.texthint","sourcebytes":[83,101,97,114,99,104,32,100,111,119,110,108,111,97,100,115,46,46,46],"value":"Search downloads..."}, {"hash":221371535,"name":"tmainform.tsinformation.caption","sourcebytes":[77,97,110,103,97,32,73,110,102,111],"value":"Manga Info"}, {"hash":60460069,"name":"tmainform.edurl.texthint","sourcebytes":[73,110,112,117,116,32,85,82,76,32,104,101,114,101],"value":"Input URL here"}, {"hash":115683780,"name":"tmainform.btdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100],"value":"Download"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 809034456..f89d6f3d7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -38,6 +38,7 @@ TMainForm = class(TForm) btChecks: TSpeedButton; btDonate: TImage; btFavoritesImport: TBitBtn; + btDownloadsSearchClear: TSpeedButton; btFilter: TBitBtn; btFilterReset: TBitBtn; btOptionApply: TBitBtn; @@ -63,6 +64,7 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + edDownloadsSearch: TEdit; edFilterMangaInfoChapters: TEditButton; edFavoritesSearch: TEdit; edOptionFilenameCustomRename: TEdit; @@ -378,6 +380,7 @@ TMainForm = class(TForm) procedure btChecksClick(Sender: TObject); procedure btCheckLatestVersionClick(Sender: TObject); procedure btDonateClick(Sender: TObject); + procedure btDownloadsSearchClearClick(Sender: TObject); procedure btFavoritesSearchClearClick(Sender: TObject); procedure btFavoritesImportClick(Sender: TObject); procedure btReadOnlineClick(Sender: TObject); @@ -399,6 +402,7 @@ TMainForm = class(TForm) var CellText: String); procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure edDownloadsSearchChange(Sender: TObject); procedure edFavoritesSearchChange(Sender: TObject); procedure edFilterMangaInfoChaptersButtonClick(Sender: TObject); procedure edFilterMangaInfoChaptersChange(Sender: TObject); @@ -2201,6 +2205,11 @@ procedure TMainForm.btDonateClick(Sender: TObject); OpenURL('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=akarin.km@gmail.com&item_name=Donation+to+Free+Manga+Downloader'); end; +procedure TMainForm.btDownloadsSearchClearClick(Sender: TObject); +begin + edDownloadsSearch.Clear; +end; + procedure TMainForm.btFavoritesSearchClearClick(Sender: TObject); begin edFavoritesSearch.Clear; @@ -2281,6 +2290,40 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; +procedure TMainForm.edDownloadsSearchChange(Sender: TObject); +var + Node: PVirtualNode; + S: String; +begin + if vtDownload.RootNodeCount = 0 then Exit; + with vtDownload do + try + BeginUpdate; + if (edDownloadsSearch.Text = '') and (VisibleCount <> RootNodeCount) then + begin + Node := GetFirst(); + while Assigned(Node) do + begin + IsVisible[Node] := DLManager[Node^.Index].Visible; + Node := GetNext(Node); + end; + end + else + begin + S := AnsiUpperCase(edDownloadsSearch.Text); + Node := GetFirst(); + while Assigned(Node) do + begin + if DLManager[Node^.Index].Visible then + IsVisible[Node] := Pos(S, AnsiUpperCase(DLManager[Node^.Index].DownloadInfo.Title)) > 0; + Node := GetNext(Node); + end; + end; + finally + EndUpdate; + end; +end; + procedure TMainForm.edFavoritesSearchChange(Sender: TObject); var Node: PVirtualNode; @@ -4021,19 +4064,23 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); var ACurrentJDN: LongInt; - procedure ShowTasks(Status: TDownloadStatusTypes = []); + procedure ShowTasks(S: TDownloadStatusTypes = []); var xNode: PVirtualNode; begin - if (Status = []) and (vtDownload.VisibleCount = vtDownload.RootNodeCount) then + if (S = []) and (vtDownload.VisibleCount = vtDownload.RootNodeCount) then Exit; xNode := vtDownload.GetFirst(); while Assigned(xNode) do begin - if Status = [] then - vtDownload.IsVisible[xNode] := True - else - vtDownload.IsVisible[xNode] := DLManager.Items[xNode^.Index].Status in Status; + with DLManager[xNode^.Index] do + begin + if S = [] then + Visible := True + else + Visible := Status in S; + vtDownload.IsVisible[xNode] := Visible; + end; xNode := vtDownload.GetNext(xNode); end; end; @@ -4046,8 +4093,12 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); xNode := vtDownload.GetFirst(); while Assigned(xNode) do begin - jdn := DateToJDN(DLManager.Items[xNode^.Index].DownloadInfo.DateTime); - vtDownload.IsVisible[xNode] := (jdn >= L) and (jdn <= H); + with DLManager.Items[xNode^.Index] do + begin + jdn := DateToJDN(DownloadInfo.DateTime); + Visible := (jdn >= L) and (jdn <= H);; + vtDownload.IsVisible[xNode] := Visible; + end; xNode := vtDownload.GetNext(xNode); end; end; @@ -4059,7 +4110,11 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); xNode := vtDownload.GetFirst(); while Assigned(xNode) do begin - vtDownload.IsVisible[xNode] := not DLManager[xNode^.Index].Enabled; + with DLManager.Items[xNode^.Index] do + begin + Visible := not Enabled; + vtDownload.IsVisible[xNode] := Visible; + end; xNode := vtDownload.GetNext(xNode); end; end; @@ -4094,6 +4149,8 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); if RefreshTree then tvDownloadFilterRefresh; + if edDownloadsSearch.Text <> '' then + edDownloadsSearchChange(edDownloadsSearch); end; procedure TMainForm.AddChapterNameToList; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index a48dcf0d7..3a530887d 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -984,7 +984,14 @@ msgstr "This work usually involves intimate relationships between women." msgid "Input custom genres, separated by comma" msgstr "Input custom genres, separated by comma" +#: tmainform.eddownloadssearch.texthint +#| msgid "Search favorites..." +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Search downloads..." + #: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" msgid "Search favorites..." msgstr "Search favorites..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index e026c12f2..63453bcfb 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -973,7 +973,13 @@ msgstr "Biasanya melibatkan hubungan yang intim antara sesama perempuan." msgid "Input custom genres, separated by comma" msgstr "Masukan genre pilihan, dipisahkan dengan koma" +#: tmainform.eddownloadssearch.texthint +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Cari unduhan..." + #: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" msgid "Search favorites..." msgstr "Cari kesukaan..." diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 092b92b21..d2ec57ca8 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -936,7 +936,13 @@ msgstr "" msgid "Input custom genres, separated by comma" msgstr "" +#: tmainform.eddownloadssearch.texthint +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "" + #: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" msgid "Search favorites..." msgstr "" From a194f1ab0513c48678b9af315e2d326ec1d036fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 30 Jul 2016 23:39:05 +0800 Subject: [PATCH 1335/2794] Bump version 0.9.75.0 --- changelog.txt | 8 ++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2e28e435e..295f0291b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.75.0 (30-07-2016) +[+] Added "Delete task + data + favorite" in download list popup menu +[+] Added "Delete" in manga list popup menu +[+] Added Favorite list search +[+] Added Download list search +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.74.0...0.9.75.0 + 0.9.74.0 (06-07-2016) [+] Added enable/disable task. Disabled task can't be resumed unless it's enabled manually, this task will be skipped on resume all. [+] Added tray icon popup menu. Resume all, Stop all, Action after download finish, Show drop box, Restore and Exit. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 720c46b25..8996db647 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="74"/> + <RevisionNr Value="75"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index dcb551d78..fa069b47e 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.74.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.74.0/fmd_0.9.74.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.74.0/fmd_0.9.74.0_Win64.7z +VERSION=0.9.75.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.75.0/fmd_0.9.75.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.75.0/fmd_0.9.75.0_Win64.7z From a542ef58064ee0bb163642ab6015d76e390c1c6c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Aug 2016 16:38:47 +0800 Subject: [PATCH 1336/2794] fixed download task finish not updating download tree status fixed #335 --- baseunits/uDownloadsManager.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index cf46f4a7c..9459d9c4d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1852,6 +1852,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); begin if not MainForm.tmRefreshDownloadsInfo.Enabled then MainForm.tmRefreshDownloadsInfo.Enabled := True; + MainForm.UpdateVtDownload; end else begin From 624beb5f0b9ae9df59b4bab86918b7a7bcfca92d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 3 Aug 2016 00:09:47 +0800 Subject: [PATCH 1337/2794] added besen as package and disable debug info --- 3rd/BESENPkg.lpk | 428 +++++++++++++++++++++++++++++++++++++++++ 3rd/BESENPkg.pas | 41 ++++ mangadownloader/md.lpi | 48 ++--- 3 files changed, 487 insertions(+), 30 deletions(-) create mode 100644 3rd/BESENPkg.lpk create mode 100644 3rd/BESENPkg.pas diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk new file mode 100644 index 000000000..4e9d56eec --- /dev/null +++ b/3rd/BESENPkg.lpk @@ -0,0 +1,428 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <PathDelim Value="\"/> + <Name Value="BESENPkg"/> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="BESEN\src"/> + <OtherUnitFiles Value="BESEN\src"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + </Linking> + </CompilerOptions> + <Files Count="97"> + <Item1> + <Filename Value="BESEN\src\BESEN.inc"/> + <Type Value="Include"/> + </Item1> + <Item2> + <Filename Value="BESEN\src\BESEN.pas"/> + <UnitName Value="BESEN"/> + </Item2> + <Item3> + <Filename Value="BESEN\src\BESENArrayUtils.pas"/> + <UnitName Value="BESENArrayUtils"/> + </Item3> + <Item4> + <Filename Value="BESEN\src\BESENASTNodes.pas"/> + <UnitName Value="BESENASTNodes"/> + </Item4> + <Item5> + <Filename Value="BESEN\src\BESENBaseObject.pas"/> + <UnitName Value="BESENBaseObject"/> + </Item5> + <Item6> + <Filename Value="BESEN\src\BESENCharset.pas"/> + <UnitName Value="BESENCharset"/> + </Item6> + <Item7> + <Filename Value="BESEN\src\BESENCode.pas"/> + <UnitName Value="BESENCode"/> + </Item7> + <Item8> + <Filename Value="BESEN\src\BESENCodeContext.pas"/> + <UnitName Value="BESENCodeContext"/> + </Item8> + <Item9> + <Filename Value="BESEN\src\BESENCodeGeneratorContext.pas"/> + <UnitName Value="BESENCodeGeneratorContext"/> + </Item9> + <Item10> + <Filename Value="BESEN\src\BESENCodeJIT.pas"/> + <UnitName Value="BESENCodeJIT"/> + </Item10> + <Item11> + <Filename Value="BESEN\src\BESENCodeJITx64.pas"/> + <UnitName Value="BESENCodeJITx64"/> + </Item11> + <Item12> + <Filename Value="BESEN\src\BESENCodeJITx86.pas"/> + <UnitName Value="BESENCodeJITx86"/> + </Item12> + <Item13> + <Filename Value="BESEN\src\BESENCodeSnapshot.pas"/> + <UnitName Value="BESENCodeSnapshot"/> + </Item13> + <Item14> + <Filename Value="BESEN\src\BESENCollector.pas"/> + <UnitName Value="BESENCollector"/> + </Item14> + <Item15> + <Filename Value="BESEN\src\BESENCollectorObject.pas"/> + <UnitName Value="BESENCollectorObject"/> + </Item15> + <Item16> + <Filename Value="BESEN\src\BESENCompiler.pas"/> + <UnitName Value="BESENCompiler"/> + </Item16> + <Item17> + <Filename Value="BESEN\src\BESENConstants.pas"/> + <UnitName Value="BESENConstants"/> + </Item17> + <Item18> + <Filename Value="BESEN\src\BESENContext.pas"/> + <UnitName Value="BESENContext"/> + </Item18> + <Item19> + <Filename Value="BESEN\src\BESENDateUtils.pas"/> + <UnitName Value="BESENDateUtils"/> + </Item19> + <Item20> + <Filename Value="BESEN\src\BESENDeclarativeEnvironmentRecord.pas"/> + <UnitName Value="BESENDeclarativeEnvironmentRecord"/> + </Item20> + <Item21> + <Filename Value="BESEN\src\BESENDecompiler.pas"/> + <UnitName Value="BESENDecompiler"/> + </Item21> + <Item22> + <Filename Value="BESEN\src\BESENDoubleList.pas"/> + <UnitName Value="BESENDoubleList"/> + </Item22> + <Item23> + <Filename Value="BESEN\src\BESENEnvironmentRecord.pas"/> + <UnitName Value="BESENEnvironmentRecord"/> + </Item23> + <Item24> + <Filename Value="BESEN\src\BESENErrors.pas"/> + <UnitName Value="BESENErrors"/> + </Item24> + <Item25> + <Filename Value="BESEN\src\BESENEvalCache.pas"/> + <UnitName Value="BESENEvalCache"/> + </Item25> + <Item26> + <Filename Value="BESEN\src\BESENEvalCacheItem.pas"/> + <UnitName Value="BESENEvalCacheItem"/> + </Item26> + <Item27> + <Filename Value="BESEN\src\BESENGarbageCollector.pas"/> + <UnitName Value="BESENGarbageCollector"/> + </Item27> + <Item28> + <Filename Value="BESEN\src\BESENGlobals.pas"/> + <UnitName Value="BESENGlobals"/> + </Item28> + <Item29> + <Filename Value="BESEN\src\BESENHashMap.pas"/> + <UnitName Value="BESENHashMap"/> + </Item29> + <Item30> + <Filename Value="BESEN\src\BESENHashUtils.pas"/> + <UnitName Value="BESENHashUtils"/> + </Item30> + <Item31> + <Filename Value="BESEN\src\BESENInt64SelfBalancedTree.pas"/> + <UnitName Value="BESENInt64SelfBalancedTree"/> + </Item31> + <Item32> + <Filename Value="BESEN\src\BESENIntegerList.pas"/> + <UnitName Value="BESENIntegerList"/> + </Item32> + <Item33> + <Filename Value="BESEN\src\BESENKeyIDManager.pas"/> + <UnitName Value="BESENKeyIDManager"/> + </Item33> + <Item34> + <Filename Value="BESEN\src\BESENLexer.pas"/> + <UnitName Value="BESENLexer"/> + </Item34> + <Item35> + <Filename Value="BESEN\src\BESENLexicalEnvironment.pas"/> + <UnitName Value="BESENLexicalEnvironment"/> + </Item35> + <Item36> + <Filename Value="BESEN\src\BESENLocale.pas"/> + <UnitName Value="BESENLocale"/> + </Item36> + <Item37> + <Filename Value="BESEN\src\BESENNativeCodeMemoryManager.pas"/> + <UnitName Value="BESENNativeCodeMemoryManager"/> + </Item37> + <Item38> + <Filename Value="BESEN\src\BESENNativeObject.pas"/> + <UnitName Value="BESENNativeObject"/> + </Item38> + <Item39> + <Filename Value="BESEN\src\BESENNumberUtils.pas"/> + <UnitName Value="BESENNumberUtils"/> + </Item39> + <Item40> + <Filename Value="BESEN\src\BESENObject.pas"/> + <UnitName Value="BESENObject"/> + </Item40> + <Item41> + <Filename Value="BESEN\src\BESENObjectArgGetterFunction.pas"/> + <UnitName Value="BESENObjectArgGetterFunction"/> + </Item41> + <Item42> + <Filename Value="BESEN\src\BESENObjectArgSetterFunction.pas"/> + <UnitName Value="BESENObjectArgSetterFunction"/> + </Item42> + <Item43> + <Filename Value="BESEN\src\BESENObjectArray.pas"/> + <UnitName Value="BESENObjectArray"/> + </Item43> + <Item44> + <Filename Value="BESEN\src\BESENObjectArrayConstructor.pas"/> + <UnitName Value="BESENObjectArrayConstructor"/> + </Item44> + <Item45> + <Filename Value="BESEN\src\BESENObjectArrayPrototype.pas"/> + <UnitName Value="BESENObjectArrayPrototype"/> + </Item45> + <Item46> + <Filename Value="BESEN\src\BESENObjectBindingFunction.pas"/> + <UnitName Value="BESENObjectBindingFunction"/> + </Item46> + <Item47> + <Filename Value="BESEN\src\BESENObjectBoolean.pas"/> + <UnitName Value="BESENObjectBoolean"/> + </Item47> + <Item48> + <Filename Value="BESEN\src\BESENObjectBooleanConstructor.pas"/> + <UnitName Value="BESENObjectBooleanConstructor"/> + </Item48> + <Item49> + <Filename Value="BESEN\src\BESENObjectBooleanPrototype.pas"/> + <UnitName Value="BESENObjectBooleanPrototype"/> + </Item49> + <Item50> + <Filename Value="BESEN\src\BESENObjectConsole.pas"/> + <UnitName Value="BESENObjectConsole"/> + </Item50> + <Item51> + <Filename Value="BESEN\src\BESENObjectConstructor.pas"/> + <UnitName Value="BESENObjectConstructor"/> + </Item51> + <Item52> + <Filename Value="BESEN\src\BESENObjectDate.pas"/> + <UnitName Value="BESENObjectDate"/> + </Item52> + <Item53> + <Filename Value="BESEN\src\BESENObjectDateConstructor.pas"/> + <UnitName Value="BESENObjectDateConstructor"/> + </Item53> + <Item54> + <Filename Value="BESEN\src\BESENObjectDatePrototype.pas"/> + <UnitName Value="BESENObjectDatePrototype"/> + </Item54> + <Item55> + <Filename Value="BESEN\src\BESENObjectDeclaredFunction.pas"/> + <UnitName Value="BESENObjectDeclaredFunction"/> + </Item55> + <Item56> + <Filename Value="BESEN\src\BESENObjectEnvironmentRecord.pas"/> + <UnitName Value="BESENObjectEnvironmentRecord"/> + </Item56> + <Item57> + <Filename Value="BESEN\src\BESENObjectError.pas"/> + <UnitName Value="BESENObjectError"/> + </Item57> + <Item58> + <Filename Value="BESEN\src\BESENObjectErrorConstructor.pas"/> + <UnitName Value="BESENObjectErrorConstructor"/> + </Item58> + <Item59> + <Filename Value="BESEN\src\BESENObjectErrorPrototype.pas"/> + <UnitName Value="BESENObjectErrorPrototype"/> + </Item59> + <Item60> + <Filename Value="BESEN\src\BESENObjectFunction.pas"/> + <UnitName Value="BESENObjectFunction"/> + </Item60> + <Item61> + <Filename Value="BESEN\src\BESENObjectFunctionArguments.pas"/> + <UnitName Value="BESENObjectFunctionArguments"/> + </Item61> + <Item62> + <Filename Value="BESEN\src\BESENObjectFunctionConstructor.pas"/> + <UnitName Value="BESENObjectFunctionConstructor"/> + </Item62> + <Item63> + <Filename Value="BESEN\src\BESENObjectFunctionPrototype.pas"/> + <UnitName Value="BESENObjectFunctionPrototype"/> + </Item63> + <Item64> + <Filename Value="BESEN\src\BESENObjectGlobal.pas"/> + <UnitName Value="BESENObjectGlobal"/> + </Item64> + <Item65> + <Filename Value="BESEN\src\BESENObjectJSON.pas"/> + <UnitName Value="BESENObjectJSON"/> + </Item65> + <Item66> + <Filename Value="BESEN\src\BESENObjectMath.pas"/> + <UnitName Value="BESENObjectMath"/> + </Item66> + <Item67> + <Filename Value="BESEN\src\BESENObjectNativeFunction.pas"/> + <UnitName Value="BESENObjectNativeFunction"/> + </Item67> + <Item68> + <Filename Value="BESEN\src\BESENObjectNumber.pas"/> + <UnitName Value="BESENObjectNumber"/> + </Item68> + <Item69> + <Filename Value="BESEN\src\BESENObjectNumberConstructor.pas"/> + <UnitName Value="BESENObjectNumberConstructor"/> + </Item69> + <Item70> + <Filename Value="BESEN\src\BESENObjectNumberPrototype.pas"/> + <UnitName Value="BESENObjectNumberPrototype"/> + </Item70> + <Item71> + <Filename Value="BESEN\src\BESENObjectPropertyDescriptor.pas"/> + <UnitName Value="BESENObjectPropertyDescriptor"/> + </Item71> + <Item72> + <Filename Value="BESEN\src\BESENObjectPrototype.pas"/> + <UnitName Value="BESENObjectPrototype"/> + </Item72> + <Item73> + <Filename Value="BESEN\src\BESENObjectRegExp.pas"/> + <UnitName Value="BESENObjectRegExp"/> + </Item73> + <Item74> + <Filename Value="BESEN\src\BESENObjectRegExpConstructor.pas"/> + <UnitName Value="BESENObjectRegExpConstructor"/> + </Item74> + <Item75> + <Filename Value="BESEN\src\BESENObjectRegExpPrototype.pas"/> + <UnitName Value="BESENObjectRegExpPrototype"/> + </Item75> + <Item76> + <Filename Value="BESEN\src\BESENObjectString.pas"/> + <UnitName Value="BESENObjectString"/> + </Item76> + <Item77> + <Filename Value="BESEN\src\BESENObjectStringConstructor.pas"/> + <UnitName Value="BESENObjectStringConstructor"/> + </Item77> + <Item78> + <Filename Value="BESEN\src\BESENObjectStringPrototype.pas"/> + <UnitName Value="BESENObjectStringPrototype"/> + </Item78> + <Item79> + <Filename Value="BESEN\src\BESENObjectThrowTypeErrorFunction.pas"/> + <UnitName Value="BESENObjectThrowTypeErrorFunction"/> + </Item79> + <Item80> + <Filename Value="BESEN\src\BESENOpcodes.pas"/> + <UnitName Value="BESENOpcodes"/> + </Item80> + <Item81> + <Filename Value="BESEN\src\BESENParser.pas"/> + <UnitName Value="BESENParser"/> + </Item81> + <Item82> + <Filename Value="BESEN\src\BESENPointerList.pas"/> + <UnitName Value="BESENPointerList"/> + </Item82> + <Item83> + <Filename Value="BESEN\src\BESENPointerSelfBalancedTree.pas"/> + <UnitName Value="BESENPointerSelfBalancedTree"/> + </Item83> + <Item84> + <Filename Value="BESEN\src\BESENRandomGenerator.pas"/> + <UnitName Value="BESENRandomGenerator"/> + </Item84> + <Item85> + <Filename Value="BESEN\src\BESENRegExp.pas"/> + <UnitName Value="BESENRegExp"/> + </Item85> + <Item86> + <Filename Value="BESEN\src\BESENRegExpCache.pas"/> + <UnitName Value="BESENRegExpCache"/> + </Item86> + <Item87> + <Filename Value="BESEN\src\BESENScope.pas"/> + <UnitName Value="BESENScope"/> + </Item87> + <Item88> + <Filename Value="BESEN\src\BESENSelfBalancedTree.pas"/> + <UnitName Value="BESENSelfBalancedTree"/> + </Item88> + <Item89> + <Filename Value="BESEN\src\BESENStringList.pas"/> + <UnitName Value="BESENStringList"/> + </Item89> + <Item90> + <Filename Value="BESEN\src\BESENStringTree.pas"/> + <UnitName Value="BESENStringTree"/> + </Item90> + <Item91> + <Filename Value="BESEN\src\BESENStringUtils.pas"/> + <UnitName Value="BESENStringUtils"/> + </Item91> + <Item92> + <Filename Value="BESEN\src\BESENTypes.pas"/> + <UnitName Value="BESENTypes"/> + </Item92> + <Item93> + <Filename Value="BESEN\src\BESENUnicodeTables.pas"/> + <UnitName Value="BESENUnicodeTables"/> + </Item93> + <Item94> + <Filename Value="BESEN\src\BESENUtils.pas"/> + <UnitName Value="BESENUtils"/> + </Item94> + <Item95> + <Filename Value="BESEN\src\BESENValue.pas"/> + <UnitName Value="BESENValue"/> + </Item95> + <Item96> + <Filename Value="BESEN\src\BESENValueContainer.pas"/> + <UnitName Value="BESENValueContainer"/> + </Item96> + <Item97> + <Filename Value="BESEN\src\BESENVersionConstants.pas"/> + <UnitName Value="BESENVersionConstants"/> + </Item97> + </Files> + <RequiredPkgs Count="1"> + <Item1> + <PackageName Value="FCL"/> + </Item1> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + </Package> +</CONFIG> diff --git a/3rd/BESENPkg.pas b/3rd/BESENPkg.pas new file mode 100644 index 000000000..10ae7944c --- /dev/null +++ b/3rd/BESENPkg.pas @@ -0,0 +1,41 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit BESENPkg; + +{$warn 5023 off : no warning about unused units} +interface + +uses + BESEN, BESENArrayUtils, BESENASTNodes, BESENBaseObject, BESENCharset, BESENCode, + BESENCodeContext, BESENCodeGeneratorContext, BESENCodeJIT, BESENCodeJITx64, + BESENCodeJITx86, BESENCodeSnapshot, BESENCollector, BESENCollectorObject, + BESENCompiler, BESENConstants, BESENContext, BESENDateUtils, + BESENDeclarativeEnvironmentRecord, BESENDecompiler, BESENDoubleList, + BESENEnvironmentRecord, BESENErrors, BESENEvalCache, BESENEvalCacheItem, + BESENGarbageCollector, BESENGlobals, BESENHashMap, BESENHashUtils, + BESENInt64SelfBalancedTree, BESENIntegerList, BESENKeyIDManager, BESENLexer, + BESENLexicalEnvironment, BESENLocale, BESENNativeCodeMemoryManager, BESENNativeObject, + BESENNumberUtils, BESENObject, BESENObjectArgGetterFunction, + BESENObjectArgSetterFunction, BESENObjectArray, BESENObjectArrayConstructor, + BESENObjectArrayPrototype, BESENObjectBindingFunction, BESENObjectBoolean, + BESENObjectBooleanConstructor, BESENObjectBooleanPrototype, BESENObjectConsole, + BESENObjectConstructor, BESENObjectDate, BESENObjectDateConstructor, + BESENObjectDatePrototype, BESENObjectDeclaredFunction, BESENObjectEnvironmentRecord, + BESENObjectError, BESENObjectErrorConstructor, BESENObjectErrorPrototype, + BESENObjectFunction, BESENObjectFunctionArguments, BESENObjectFunctionConstructor, + BESENObjectFunctionPrototype, BESENObjectGlobal, BESENObjectJSON, BESENObjectMath, + BESENObjectNativeFunction, BESENObjectNumber, BESENObjectNumberConstructor, + BESENObjectNumberPrototype, BESENObjectPropertyDescriptor, BESENObjectPrototype, + BESENObjectRegExp, BESENObjectRegExpConstructor, BESENObjectRegExpPrototype, + BESENObjectString, BESENObjectStringConstructor, BESENObjectStringPrototype, + BESENObjectThrowTypeErrorFunction, BESENOpcodes, BESENParser, BESENPointerList, + BESENPointerSelfBalancedTree, BESENRandomGenerator, BESENRegExp, BESENRegExpCache, + BESENScope, BESENSelfBalancedTree, BESENStringList, BESENStringTree, BESENStringUtils, + BESENTypes, BESENUnicodeTables, BESENUtils, BESENValue, BESENValueContainer, + BESENVersionConstants; + +implementation + +end. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8996db647..ffc537050 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -33,7 +33,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -76,16 +76,10 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> - <Checks> - <IOChecks Value="True"/> - <RangeChecks Value="True"/> - <OverflowChecks Value="True"/> - <StackChecks Value="True"/> - </Checks> <TargetCPU Value="i386"/> <TargetOS Value="win32"/> <Optimizations> @@ -94,6 +88,7 @@ </CodeGeneration> <Linking> <Debugging> + <DebugInfoType Value="dsDwarf3"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> @@ -122,16 +117,10 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> - <Checks> - <IOChecks Value="True"/> - <RangeChecks Value="True"/> - <OverflowChecks Value="True"/> - <StackChecks Value="True"/> - </Checks> <TargetCPU Value="x86_64"/> <TargetOS Value="win64"/> <Optimizations> @@ -140,6 +129,7 @@ </CodeGeneration> <Linking> <Debugging> + <DebugInfoType Value="dsDwarf3"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> @@ -165,16 +155,10 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> - <Checks> - <IOChecks Value="True"/> - <RangeChecks Value="True"/> - <OverflowChecks Value="True"/> - <StackChecks Value="True"/> - </Checks> <TargetCPU Value="i386"/> <TargetOS Value="win32"/> <Optimizations> @@ -183,6 +167,7 @@ </CodeGeneration> <Linking> <Debugging> + <DebugInfoType Value="dsDwarf3"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> @@ -215,25 +200,28 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="6"> + <RequiredPackages Count="7"> <Item1> - <PackageName Value="laz_synapse"/> + <PackageName Value="BESENPkg"/> </Item1> <Item2> - <PackageName Value="internettools"/> + <PackageName Value="laz_synapse"/> </Item2> <Item3> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="internettools"/> </Item3> <Item4> - <PackageName Value="richmemopackage"/> + <PackageName Value="TAChartLazarusPkg"/> </Item4> <Item5> - <PackageName Value="virtualtreeview_package"/> + <PackageName Value="richmemopackage"/> </Item5> <Item6> - <PackageName Value="LCL"/> + <PackageName Value="virtualtreeview_package"/> </Item6> + <Item7> + <PackageName Value="LCL"/> + </Item7> </RequiredPackages> <Units Count="12"> <Unit0> @@ -327,7 +315,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\3rd\BESEN\src;..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 37abd606f1a0bea91d41cfd40522107adbd7f76c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 3 Aug 2016 01:09:44 +0800 Subject: [PATCH 1338/2794] downloadmanager, additemsactivetask with criticalsection --- baseunits/uDownloadsManager.pas | 44 +++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9459d9c4d..5c1c1208f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -164,6 +164,8 @@ TDownloadManager = class FSortDirection: Boolean; FSortColumn: Integer; DownloadManagerFile: TIniFileRun; + procedure AddItemsActiveTask(const Item: TTaskContainer); + procedure RemoveItemsActiveTask(const Item: TTaskContainer); function GetTask(const TaskId: Integer): TTaskContainer; protected function GetTaskCount: Integer; inline; @@ -1396,14 +1398,9 @@ procedure TTaskThread.DoTerminate; with Container do begin Container.ReadCount := 0; DownloadInfo.TransferRate := ''; + Manager.RemoveItemsActiveTask(Container); ThreadState := False; Task := nil; - EnterCriticalSection(Manager.CS_Task); - try - Manager.ItemsActiveTask.Remove(Container); - finally - LeaveCriticalSection(Manager.CS_Task); - end; if not Manager.isReadyForExit then begin if Status <> STATUS_STOP then @@ -1513,6 +1510,26 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); { TDownloadManager } +procedure TDownloadManager.AddItemsActiveTask(const Item: TTaskContainer); +begin + EnterCriticalsection(CS_Task); + try + ItemsActiveTask.Add(Item); + finally + LeaveCriticalsection(CS_Task); + end; +end; + +procedure TDownloadManager.RemoveItemsActiveTask(const Item: TTaskContainer); +begin + EnterCriticalsection(CS_Task); + try + ItemsActiveTask.Remove(Item); + finally + LeaveCriticalsection(CS_Task); + end; +end; + function TDownloadManager.GetTask(const TaskId: Integer): TTaskContainer; begin Result := Items[TaskId]; @@ -1614,15 +1631,10 @@ constructor TDownloadManager.Create; destructor TDownloadManager.Destroy; begin - EnterCriticalSection(CS_Task); - try - while Items.Count > 0 do - begin - Items.Last.Free; - Items.Remove(Items.Last); - end; - finally - LeaveCriticalSection(CS_Task); + while Items.Count > 0 do + begin + Items.Last.Free; + Items.Remove(Items.Last); end; Items.Free; DownloadManagerFile.Free; @@ -1923,7 +1935,7 @@ procedure TDownloadManager.ActiveTask(const taskID: Integer); Modules.IncActiveTaskCount(ModuleId); Task := TTaskThread.Create; Task.Container := Items[taskID]; - ItemsActiveTask.Add(Task.Container); + AddItemsActiveTask(Task.Container); Task.Start; end; end; From 9ef3ad6ee7358d16fc8662dcc5a5665c8b14aa06 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:00:10 +0800 Subject: [PATCH 1339/2794] update simpleexception to work with multilog, added multilog to packages dependency --- baseunits/SimpleException/SimpleException.pas | 402 ++++---- baseunits/SimpleException/SimpleLogger.pas | 392 -------- baseunits/SimpleException/dbginforeader.pas | 922 ------------------ mangadownloader/md.lpi | 27 +- readme.txt | 1 + 5 files changed, 253 insertions(+), 1491 deletions(-) delete mode 100644 baseunits/SimpleException/SimpleLogger.pas delete mode 100644 baseunits/SimpleException/dbginforeader.pas diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 10d10b401..2231fa267 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -1,21 +1,31 @@ { SimpleException Class - Copyright (C) 2014 Nur Cholif - - This source is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - A copy of the GNU General Public License is available on the World Wide Web - at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing - to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + Copyright (C) 2014-2016 Nur Cholif + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version with the following modification: + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent modules,and + to copy and distribute the resulting executable under terms of your choice, + provided that you also meet, for each linked independent module, the terms + and conditions of the license of that module. An independent module is a + module which is not derived from or based on this library. If you modify + this library, you may extend this exception to your version of the library, + but you are not obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. } unit SimpleException; @@ -26,9 +36,9 @@ interface uses Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, LCLVersion, - SimpleExceptionForm, SimpleLogger, + SimpleExceptionForm, {$IFDEF WINDOWS} - windows, win32proc, + Windows, win32proc, {$ENDIF} {$IFDEF LINUX} elfreader, @@ -36,7 +46,8 @@ interface {$IF DEFINED(DARWIN) OR DEFINED(MACOS)} machoreader, {$ENDIF} - fileinfo; + fileinfo, + MultiLog; type @@ -44,58 +55,53 @@ interface TSimpleException = class private - FAppInfo_comments, - FAppInfo_companyname, - FAppInfo_filedescription, - FAppInfo_fileversion, - FAppInfo_internalname, - FAppInfo_legalcopyright, - FAppInfo_legaltrademarks, - FAppInfo_originalfilename, - FAppInfo_productname, - FAppInfo_productversion: String; - FAppVerInfo: TStringList; - FOSversion: string; + FLogFileName: String; FLastSender: TObject; FLastException: Exception; + FApplicationInfo, FLastReport: String; FMaxStackCount: Integer; FSimpleCriticalSection: TRTLCriticalSection; FDefaultAppFlags: TApplicationFlags; FUnhandled: Boolean; - function OSVer: String; + procedure SetLogFileName(const AValue: String); procedure SetMaxStackCount(AMaxStackCount: Integer); protected - function ExceptionHeaderMessage: string; + function ExceptionHeaderMessage: String; + function GetStackTraceStr: String; procedure CreateExceptionReport; - procedure SaveLogToFile(LogMsg: string); + procedure SaveLogToFile(const LogMsg: String); procedure CallExceptionHandler; procedure ExceptionHandler; - procedure UnhandledException(Obj : TObject; Addr: CodePointer; FrameCount: Longint; Frames: PCodePointer); + procedure UnhandledException(Obj: TObject; Addr: CodePointer; FrameCount: LongInt; + Frames: PCodePointer); public - LogFilename: String; - IgnoredExceptionList: TStringlist; + IgnoredExceptionList: TStringList; + property ApplicationInfo: String read FApplicationInfo; + property LogFileName: String read FLogFileName write SetLogFileName; property MaxStackCount: Integer read FMaxStackCount write SetMaxStackCount; property LastSender: TObject read FLastSender; property LastException: Exception read FLastException; property LastReport: String read FLastReport; procedure SimpleExceptionHandler(Sender: TObject; E: Exception); procedure SimpleExceptionHandlerSaveLogOnly(Sender: TObject; E: Exception); - constructor Create(Filename: string = ''); + constructor Create(const FileName: String = ''); destructor Destroy; override; end; +function GetApplicationInfo: String; function AddIgnoredException(const EClassName: String): Boolean; function RemoveIgnoredClass(const EClassName: String): Boolean; procedure SetMaxStackCount(const ACount: Integer); procedure ClearIgnoredException; procedure ExceptionHandle(Sender: TObject; E: Exception); procedure ExceptionHandleSaveLogOnly(Sender: TObject; E: Exception); -procedure InitSimpleExceptionHandler(const LogFilename: String = ''); +procedure InitSimpleExceptionHandler(const LogFileName: String = ''); +procedure SetLogFileName(const LogFileName: String); procedure DoneSimpleExceptionHandler; var - MyException: TSimpleException; + MainExceptionHandler: TSimpleException; resourcestring SExceptionDialogTitle = 'Exception Info'; @@ -108,65 +114,95 @@ procedure DoneSimpleExceptionHandler; implementation -procedure SetMaxStackCount(const ACount : Integer); +type + + { TLoggerException } + + TLoggerException = class helper for TLogger + public + procedure SendExceptionStr(const AText: String; AExceptionStr: String); + end; + + +procedure SetMaxStackCount(const ACount: Integer); +begin + if MainExceptionHandler <> nil then + MainExceptionHandler.MaxStackCount := ACount; +end; + +function GetApplicationInfo: String; begin - if MyException <> nil then - MyException.MaxStackCount := ACount; + Result := ''; + if Assigned(MainExceptionHandler) then + Result := MainExceptionHandler.ApplicationInfo; end; -function AddIgnoredException(const EClassName : String) : Boolean; +function AddIgnoredException(const EClassName: String): Boolean; begin Result := False; - if MyException <> nil then - if MyException.IgnoredExceptionList.IndexOf(EClassName) < 0 then + if MainExceptionHandler <> nil then + if MainExceptionHandler.IgnoredExceptionList.IndexOf(EClassName) < 0 then begin Result := True; - MyException.IgnoredExceptionList.Add(EClassName); + MainExceptionHandler.IgnoredExceptionList.Add(EClassName); end; end; -function RemoveIgnoredClass(const EClassName : String) : Boolean; +function RemoveIgnoredClass(const EClassName: String): Boolean; begin Result := False; - if MyException <> nil then - if MyException.IgnoredExceptionList.IndexOf(EClassName) > -1 then + if MainExceptionHandler <> nil then + if MainExceptionHandler.IgnoredExceptionList.IndexOf(EClassName) > -1 then begin Result := True; - MyException.IgnoredExceptionList.Delete( - MyException.IgnoredExceptionList.IndexOf(EClassName)); + MainExceptionHandler.IgnoredExceptionList.Delete( + MainExceptionHandler.IgnoredExceptionList.IndexOf(EClassName)); end; end; procedure ClearIgnoredException; begin - if MyException <> nil then - MyException.IgnoredExceptionList.Clear; + if MainExceptionHandler <> nil then + MainExceptionHandler.IgnoredExceptionList.Clear; end; procedure ExceptionHandle(Sender: TObject; E: Exception); begin - if not Assigned(MyException) then + if not Assigned(MainExceptionHandler) then InitSimpleExceptionHandler; - MyException.SimpleExceptionHandler(Sender, E); + MainExceptionHandler.SimpleExceptionHandler(Sender, E); end; procedure ExceptionHandleSaveLogOnly(Sender: TObject; E: Exception); begin - if not Assigned(MyException) then + if not Assigned(MainExceptionHandler) then InitSimpleExceptionHandler; - MyException.SimpleExceptionHandlerSaveLogOnly(Sender, E); + MainExceptionHandler.SimpleExceptionHandlerSaveLogOnly(Sender, E); end; -procedure InitSimpleExceptionHandler(const LogFilename : String); +procedure InitSimpleExceptionHandler(const LogFileName: String); begin - if MyException = nil then - MyException := TSimpleException.Create(LogFilename); + if MainExceptionHandler = nil then + MainExceptionHandler := TSimpleException.Create(LogFilename); +end; + +procedure SetLogFileName(const LogFileName: String); +begin + if MainExceptionHandler <> nil then + MainExceptionHandler.LogFileName := LogFileName; end; procedure DoneSimpleExceptionHandler; begin - if MyException <> nil then - FreeAndNil(MyException); + if MainExceptionHandler <> nil then + FreeAndNil(MainExceptionHandler); +end; + +{ TLoggerException } + +procedure TLoggerException.SendExceptionStr(const AText: String; AExceptionStr: String); +begin + SendBuffer(ltException, AText, AExceptionStr[1], Length(AExceptionStr)); end; { TSimpleException } @@ -174,16 +210,28 @@ procedure DoneSimpleExceptionHandler; procedure TSimpleException.SetMaxStackCount(AMaxStackCount: Integer); begin if FMaxStackCount <> AMaxStackCount then + begin if AMaxStackCount < 1 then FMaxStackCount := 1 + else + if AMaxStackCount > 255 then + FMaxStackCount := 255 else FMaxStackCount := AMaxStackCount; + end; end; -function TSimpleException.OSVer: String; +procedure TSimpleException.SetLogFileName(const AValue: String); +begin + if FLogFileName = AValue then Exit; + FLogFileName := AValue; +end; + +function GetOSVer: String; {$IFDEF WINDOWS} var wdir: array [0..MAX_PATH] of Char; + function WinLater: String; begin if (Win32MajorVersion = 6) and (Win32MinorVersion = 3) then @@ -220,7 +268,7 @@ function TSimpleException.OSVer: String; else Result := WinLater; end; - Initialize(wdir); + FillChar({%H-}wdir, SizeOf(wdir), 0); GetWindowsDirectory(PChar(wdir), MAX_PATH); if DirectoryExists(wdir + '\SysWOW64') then Result := Result + ' 64-bit'; @@ -233,25 +281,26 @@ procedure TSimpleException.ExceptionHandler; if (IgnoredExceptionList.IndexOf(FLastException.ClassName) > -1) then Exit; with TSimpleExceptionForm.Create(nil) do try - MemoExceptionLog.Lines.Text := FLastReport; - if Assigned(FLastException) then - LabelExceptionMessage.Caption := FLastException.Message; - if FUnhandled then - begin - CheckBoxIgnoreException.Visible := False; - ButtonContinue.Visible := False; + MemoExceptionLog.Lines.Text := FLastReport; + if Assigned(FLastException) then + LabelExceptionMessage.Caption := FLastException.Message; + if FUnhandled then + begin + CheckBoxIgnoreException.Visible := False; + ButtonContinue.Visible := False; + end; + if ShowModal = mrIgnore then + AddIgnoredException(FLastException.ClassName); + finally + Free; end; - if ShowModal = mrIgnore then - AddIgnoredException(FLastException.ClassName); - finally - Free; - end; end; procedure TSimpleException.UnhandledException(Obj: TObject; Addr: CodePointer; - FrameCount: Longint; Frames: PCodePointer); + FrameCount: LongInt; Frames: PCodePointer); var i: Integer; + S: String; begin EnterCriticalSection(FSimpleCriticalSection); try @@ -268,13 +317,18 @@ procedure TSimpleException.UnhandledException(Obj: TObject; Addr: CodePointer; FLastReport := ExceptionHeaderMessage; if Obj is TObject then FLastReport := FLastReport + - 'Sender Class : ' + Obj.ClassName + LineEnding; + 'Sender Class : ' + Obj.ClassName + LineEnding; FLastReport := FLastReport + - 'Exception Address : $' + SimpleBackTraceStr(Addr) + LineEnding; + 'Exception Address : $' + BackTraceStrFunc(Addr) + LineEnding; + S := ''; if FrameCount > 0 then - for i := 0 to FrameCount-1 do - FLastReport := FLastReport + ' ' + SimpleBackTraceStr(Frames[i]) + LineEnding; - SaveLogToFile(FLastReport); + for i := 0 to FrameCount - 1 do + S := S + ' ' + BackTraceStrFunc(Frames[i]) + LineEnding; + FLastReport := FLastReport + S; + if Logger.Enabled then + Logger.SendExceptionStr('Unhandled Exception occured at $' + BackTraceStrFunc(Addr), S) + else + SaveLogToFile(FLastReport); CallExceptionHandler; end; finally @@ -282,7 +336,9 @@ procedure TSimpleException.UnhandledException(Obj: TObject; Addr: CodePointer; end; end; -function TSimpleException.ExceptionHeaderMessage: string; +function TSimpleException.ExceptionHeaderMessage: String; +var + i: Integer; begin try if FUnhandled then @@ -290,61 +346,77 @@ function TSimpleException.ExceptionHeaderMessage: string; else Result := 'Program exception!'; Result := Result + LineEnding + - 'Application : ' + Application.Title + LineEnding + - 'Version : ' + FAppInfo_fileversion + LineEnding + - 'Product Version : ' + FAppInfo_productversion + LineEnding + - 'FPC Version : ' + {$i %FPCVERSION%} + LineEnding + - 'LCL Version : ' + LCLVersion.lcl_version + LineEnding + - 'Target CPU_OS : ' + {$i %FPCTARGETCPU%} +'_' + {$i %FPCTARGETOS%} +LineEnding + - 'Host Machine : ' + FOSversion + LineEnding + - 'Path : ' + ParamStrUTF8(0) + LineEnding + - 'Proccess Id : ' + IntToStr(GetProcessID) + LineEnding + - 'Thread Id : ' + IntToStr(GetThreadID) + LineEnding + - 'Time : ' + DateTimeToStr(Now) + LineEnding; + FApplicationInfo + LineEnding + + 'Thread ID : ' + IntToStr(GetThreadID) + LineEnding + + 'Time : ' + FormatDateTime('dd/mm/yyyy hh:nn:ss.zzz', Now) + LineEnding; if IgnoredExceptionList.Count > 0 then - Result := Result + - 'Ignored Exception : ' + IgnoredExceptionList.DelimitedText + LineEnding; + begin + Result := Result + 'Ignored Exception : ' + IgnoredExceptionList[0]; + for i := 1 to IgnoredExceptionList.Count - 1 do + Result := Result + ', ' + IgnoredExceptionList[i]; + Result := Result + LineEnding; + end; except Result := ''; end; end; -procedure TSimpleException.CreateExceptionReport; +function TSimpleException.GetStackTraceStr: String; +var + Frames: PPointer; + i, AMaxStackCount: Integer; begin + Result := ''; try - FLastReport := ExceptionHeaderMessage; - if Assigned(FLastSender) then - FLastReport := FLastReport + - 'Sender Class : ' + FLastSender.ClassName + LineEnding; - if Assigned(FLastException) then - begin - FLastReport := FLastReport + - 'Exception Class : ' + FLastException.ClassName + LineEnding + - 'Message : ' + FLastException.Message + LineEnding; - end; - FLastReport := FLastReport + GetStackTraceInfo + LineEnding; + Result := BackTraceStrFunc(ExceptAddr); + Frames := ExceptFrames; + if ExceptFrameCount > FMaxStackCount then + AMaxStackCount := FMaxStackCount + else + AMaxStackCount := ExceptFrameCount; + for i := 0 to AMaxStackCount - 1 do + Result := Result + (LineEnding + BackTraceStrFunc(Frames[i])); except - on E: Exception do - begin - FLastReport := 'Failed to create exception FLastReport!' + LineEnding + - FLastReport + LineEnding; - if Assigned(LastSender) then - FLastReport := FLastReport + 'Sender Class: ' + LastSender.ClassName + LineEnding; - FLastReport := FLastReport + E.ClassName + ': ' + E.Message; - end; end; - SaveLogToFile(FLastReport); end; -procedure TSimpleException.SaveLogToFile(LogMsg: string); +procedure TSimpleException.CreateExceptionReport; +var + S: String; +begin + S := ''; + FLastReport := ExceptionHeaderMessage; + if Assigned(FLastSender) then + FLastReport := FLastReport + + 'Sender Class : ' + FLastSender.ClassName + LineEnding; + if Assigned(FLastException) then + begin + FLastReport := FLastReport + + 'Exception Class : ' + FLastException.ClassName + LineEnding + + 'Message : ' + FLastException.Message + LineEnding; + end; + S := GetStackTraceStr; + FLastReport := FLastReport + S; + if Logger.Enabled then + begin + if Assigned(FLastException) then + Logger.SendExceptionStr(FLastException.ClassName + ' - ' + FLastException.Message, S) + else + Logger.SendExceptionStr('Program exception!', S); + end + else + SaveLogToFile(FLastReport); +end; + +procedure TSimpleException.SaveLogToFile(const LogMsg: String); var f: TextFile; begin - if LogFilename <> '' then + if LogFileName <> '' then begin - AssignFile(f, LogFilename); + AssignFile(f, LogFileName); try - if FileExistsUTF8(LogFilename) then + if FileExistsUTF8(LogFileName) then Append(f) else Rewrite(f); @@ -353,7 +425,6 @@ procedure TSimpleException.SaveLogToFile(LogMsg: string); CloseFile(f); end; end; - WriteLog_E('From ExceptionHandler:'#13#10+LogMsg); end; procedure TSimpleException.CallExceptionHandler; @@ -367,7 +438,10 @@ procedure TSimpleException.CallExceptionHandler; TThread.Synchronize((Sender as TThread), @ExceptionHandler) {$ENDIF} except - SaveLogToFile(SCantHandleException); + if Logger.Enabled then + Logger.SendError(SCantHandleException) + else + SaveLogToFile(SCantHandleException); end else ExceptionHandler; @@ -405,63 +479,54 @@ procedure TSimpleException.SimpleExceptionHandlerSaveLogOnly(Sender: TObject; end; end; -Procedure CatchUnhandledExcept(Obj : TObject; Addr: CodePointer; FrameCount: Longint; Frames: PCodePointer); +procedure CatchUnhandledExcept(Obj: TObject; Addr: CodePointer; FrameCount: LongInt; Frames: PCodePointer); begin - if Assigned(MyException) then - MyException.UnhandledException(Obj, Addr, FrameCount, Frames); + if Assigned(MainExceptionHandler) then + MainExceptionHandler.UnhandledException(Obj, Addr, FrameCount, Frames); end; -constructor TSimpleException.Create(Filename : string); +constructor TSimpleException.Create(const FileName: String); var - i: Integer; + AFileVersion, AProductVersion: String; begin inherited Create; - InitCriticalSection(FSimpleCriticalSection); - if Trim(Filename) <> '' then - LogFilename := Filename + if Trim(FileName) <> '' then + LogFileName := FileName else - LogFilename := ExtractFileNameOnly(Application.ExeName) + '.log'; - FMaxStackCount := 20; - FAppVerInfo := TStringList.Create; + LogFileName := ChangeFileExt(Application.ExeName, '.log'); + InitCriticalSection(FSimpleCriticalSection); IgnoredExceptionList := TStringList.Create; - FOSversion := OSVer; + FMaxStackCount := 20; with TFileVersionInfo.Create(nil) do try - try - fileName := ParamStrUTF8(0); - if fileName = '' then - fileName := Application.ExeName; - {$IF FPC_FULLVERSION >= 20701} - ReadFileInfo; - {$ENDIF} - if VersionStrings.Count > 0 then - begin - {$IF FPC_FULLVERSION >= 20701} - FAppVerInfo.Assign(VersionStrings); - {$ELSE} - for i := 0 to VersionStrings.Count - 1 do - FAppVerInfo.Add(VersionCategories.Strings[i] + '=' + - VersionStrings.Strings[i]); - {$ENDIF} - for i := 0 to FAppVerInfo.Count - 1 do - FAppVerInfo.Strings[i] := - LowerCase(FAppVerInfo.Names[i]) + '=' + FAppVerInfo.ValueFromIndex[i]; - FAppInfo_comments := FAppVerInfo.Values['comments']; - FAppInfo_companyname := FAppVerInfo.Values['companyname']; - FAppInfo_filedescription := FAppVerInfo.Values['filedescription']; - FAppInfo_fileversion := FAppVerInfo.Values['fileversion']; - FAppInfo_internalname := FAppVerInfo.Values['internalname']; - FAppInfo_legalcopyright := FAppVerInfo.Values['legalcopyright']; - FAppInfo_legaltrademarks := FAppVerInfo.Values['legaltrademarks']; - FAppInfo_originalfilename := FAppVerInfo.Values['originalfilename']; - FAppInfo_productname := FAppVerInfo.Values['productname']; - FAppInfo_productversion := FAppVerInfo.Values['productversion']; - end; - except + FileName := ParamStrUTF8(0); + if FileName = '' then + FileName := Application.ExeName; + Enabled := True; + if VersionStrings.Count <> 0 then + begin + AFileVersion := VersionStrings.Values['fileversion']; + AProductVersion := VersionStrings.Values['productversion']; end; finally Free; end; + FApplicationInfo := + 'Application : ' + Application.Title + LineEnding; + if AFileVersion <> '' then + FApplicationInfo := FApplicationInfo + + 'Version : ' + AFileVersion + LineEnding; + if AProductVersion <> '' then + FApplicationInfo := FApplicationInfo + + 'Product Version : ' + AProductVersion + LineEnding; + FApplicationInfo := FApplicationInfo + + 'Host Machine : ' + GetOSVer + LineEnding + + 'Target CPU_OS : ' + {$i %FPCTARGETCPU%} +'_' + {$i %FPCTARGETOS%} +LineEnding + + 'FPC Version : ' + {$i %FPCVERSION%} +LineEnding + + 'LCL Version : ' + LCLVersion.lcl_version + LineEnding + + 'Path : ' + ParamStrUTF8(0) + LineEnding + + 'Process ID : ' + IntToStr(GetProcessID) + LineEnding + + 'MainThread ID : ' + IntToStr(MainThreadID); if Assigned(Application) then begin FDefaultAppFlags := Application.Flags; @@ -479,11 +544,12 @@ destructor TSimpleException.Destroy; Application.Flags := FDefaultAppFlags; end; IgnoredExceptionList.Free; - FAppVerInfo.Free; DoneCriticalsection(FSimpleCriticalSection); inherited Destroy; end; +initialization + finalization DoneSimpleExceptionHandler; diff --git a/baseunits/SimpleException/SimpleLogger.pas b/baseunits/SimpleException/SimpleLogger.pas deleted file mode 100644 index cf52d9b56..000000000 --- a/baseunits/SimpleException/SimpleLogger.pas +++ /dev/null @@ -1,392 +0,0 @@ -{ Simple Logger Class, part of SimpleException - - Copyright (C) 2014 Nur Cholif - - This source is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at your option) - any later version. - - This code is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - A copy of the GNU General Public License is available on the World Wide Web - at <http://www.gnu.org/copyleft/gpl.html>. You can also obtain it by writing - to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. -} - -unit SimpleLogger; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, DbgInfoReader, LazFileUtils, LazUTF8 - {$if defined(traplazlogger) or defined(sendtolazlogger)} - , LazLogger - {$endif}; - -type - TLogType = (ERROR, WARNING, INFO, DEBUG, VERBOSE); - - {$ifdef traplazlogger} - { TLazloggerHelper } - - TLazloggerHelper = class - public - procedure DbgLn(Sender: TObject; S: String; var Handled: Boolean); - end; - - {$endif} - -var - {$ifdef traplazlogger} - lazloggerhelper: TLazloggerHelper; - {$endif} - _CS_LOG: TRTLCriticalSection; - _LOG_ACTIVE: Boolean = False; - _LOG_LEVEL: Integer = 2; - _FLOGFILE: String; - _HAS_DEBUG_LINE: Boolean; - -const - _LOG_SYMBOL = 'EWIDV'; - -function ArrayToString(Args: array of const): String; -procedure SetLogFile(const LogFileName: String); -procedure WriteLog_E(const msg: String); overload; inline; -procedure WriteLog_E(msg: array of const); overload; inline; -procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject = nil); overload; -procedure WriteLog_E(msg: array of const; Exc: Exception; Sender: TObject = nil); overload; inline; -procedure Writelog_W(const msg: String); inline; -procedure WriteLog_W(msg: array of const); overload; inline; -procedure Writelog_I(const msg: String); inline; -procedure WriteLog_I(msg: array of const); overload; inline; -procedure Writelog_D(const msg: String); inline; -procedure WriteLog_D(msg: array of const); overload; inline; -procedure Writelog_V(const msg: String); inline; -procedure WriteLog_V(msg: array of const); overload; inline; -function SimpleBackTraceStr(const Addr: Pointer): String; -function GetStackTraceInfo(const MaxStackCount: Integer = 20): String; - -implementation - -procedure ForceLogFile(const logfilename: String); -var - f: String; -begin - f := ExtractFileDir(logfilename); - if f <> '' then - begin - if _LOG_ACTIVE and (not DirectoryExists(f)) then - ForceDirectoriesUTF8(f); - f := f + PathDelim + ExtractFileName(logfilename); - end - else - f := logfilename; - _FLOGFILE := f; -end; - -procedure SetLogFile(const LogFileName: String); -begin - if Trim(LogFileName) <> '' then - begin - EnterCriticalsection(_CS_LOG); - try - ForceLogFile(LogFileName); - finally - LeaveCriticalsection(_CS_LOG); - end; - end; -end; - -function FormatLogMessage(const msg: String; LogType: TLogType = DEBUG): String; -begin - Result := FormatDateTime('dd/mm/yyyy|hh:nn:ss.zzz ', Now) + - '[' + _LOG_SYMBOL[Integer(logType) + 1] + '] ' + msg; -end; - -procedure WriteLog(const msg: String; LogType: TLogType = DEBUG); -var - f: TextFile; -begin - if not _LOG_ACTIVE then Exit; - if _FLOGFILE = '' then Exit; - if Integer(logType) > _LOG_LEVEL then Exit; - EnterCriticalsection(_CS_LOG); - try - AssignFile(f, _FLOGFILE); - try - if FileExistsUTF8(_FLOGFILE) then - Append(f) - else - begin - ForceLogFile(_FLOGFILE); - Rewrite(f); - end; - WriteLn(f, FormatLogMessage(msg, LogType)); - finally - CloseFile(f); - end; - finally - LeaveCriticalsection(_CS_LOG); - end; -end; - -function VarRecToString(AVarRec: TVarRec): String; -begin - case AVarRec.VType of - vtInteger: Result := IntToStr(AVarRec.VInteger); - vtBoolean: Result := BoolToStr(AVarRec.VBoolean, True); - vtChar: Result := AVarRec.VChar; - vtWideChar: Result := WideString(AVarRec.VWideChar); - vtExtended: Result := FloatToStr(AVarRec.VExtended^); - vtString: Result := AVarRec.VString^; - vtPointer: Result := hexStr(AVarRec.VPointer); - vtPChar: Result := AVarRec.VPChar; - vtObject: Result := AVarRec.VObject.ClassName; - vtClass: Result := AVarRec.VClass.ClassName; - vtPWideChar: Result := AVarRec.VPWideChar; - vtAnsiString: Result := Ansistring(AVarRec.VAnsiString); - vtCurrency: Result := CurrToStr(AVarRec.VCurrency^); - vtVariant: Result := String(AVarRec.VVariant); - vtWideString: Result := WideString(AVarRec.VWideString); - vtInt64: Result := IntToStr(AVarRec.VInt64^); - vtUnicodeString: Result := UnicodeString(AVarRec.VUnicodeString); - vtQWord: Result := IntToStr(AVarRec.VQWord^); - else - Result := ''; - end; -end; - -function ArrayToString(Args: array of const): String; -var - i: Integer; -begin - Result := ''; - if High(Args) < 0 then Exit; - for i := Low(Args) to High(Args) do - Result += VarRecToString(Args[i]); -end; - -procedure WriteLog_E(const msg: String); -begin - WriteLog(msg, ERROR); -end; - -procedure WriteLog_E(msg: array of const); -begin - WriteLog_E(ArrayToString(msg)); -end; - -procedure WriteLog_E(const msg: String; Exc: Exception; Sender: TObject); -var - s: String; -begin - s := ''; - if Assigned(Sender) then - s += LineEnding + - 'Sender Class : ' + Sender.ClassName; - if Assigned(Exc) then - begin - s += LineEnding + - 'Exception Class : ' + Exc.ClassName + LineEnding + - 'Exception Message : ' + Exc.Message; - end; - s += LineEnding + GetStackTraceInfo; - WriteLog_E(msg + s); -end; - -procedure WriteLog_E(msg: array of const; Exc: Exception; Sender: TObject); -begin - WriteLog_E(ArrayToString(msg), Exc, Sender); -end; - -procedure Writelog_W(const msg: String); -begin - WriteLog(msg, WARNING); -end; - -procedure WriteLog_W(msg: array of const); -begin - WriteLog_W(ArrayToString(msg)); -end; - -procedure Writelog_I(const msg: String); -begin - WriteLog(msg, INFO); -end; - -procedure WriteLog_I(msg: array of const); -begin - WriteLog_I(ArrayToString(msg)); -end; - -procedure Writelog_D(const msg: String); -begin - {$ifdef sendtolazlogger} - DebugLn(msg); - {$else} - WriteLog(msg, DEBUG); - {$endif} -end; - -procedure WriteLog_D(msg: array of const); -begin - WriteLog_D(ArrayToString(msg)); -end; - -procedure Writelog_V(const msg: String); -begin - WriteLog(msg, VERBOSE); -end; - -procedure WriteLog_V(msg: array of const); -begin - WriteLog_V(ArrayToString(msg)); -end; - -function SimpleBackTraceStr(const Addr: Pointer): String; -var - func, Source: ShortString; - hs: String[32]; - line: LongInt; -begin - Result := '$' + hexStr(Addr); - if _HAS_DEBUG_LINE then - begin - try - GetLineInfo({%H-}PtrUInt(Addr), func, Source, line); - if func <> '' then - Result := Result + ' ' + func; - if Source <> '' then - begin - if func <> '' then - Result := Result + ','; - if line <> 0 then - begin - str(line, hs); - Result := Result + ' line ' + hs; - end; - Result := Result + ' of ' + Source; - end; - except - Result := Result + ' ??'; - end; - end; -end; - -function GetStackTraceInfo(const MaxStackCount: Integer): String; -var - i, maxStack: Integer; - cf, pcf, cAddress, cFrame: Pointer; -begin - try - if ExceptFrameCount > 0 then - begin - Result := - 'Exception Address : $' + hexStr(ExceptAddr) + LineEnding; - if ExceptFrameCount > MaxStackCount then - maxStack := MaxStackCount - 1 - else - maxStack := ExceptFrameCount - 1; - for i := 0 to maxStack do - Result := Result + ' ' + SimpleBackTraceStr(ExceptFrames[i]) + LineEnding; - end - else - begin - cf := get_caller_frame(get_frame); - //cf := get_caller_frame(get_caller_frame(get_frame)); - if cf <> nil then - begin - Result := - 'Caller Address : ' + '$' + hexStr(cf) + LineEnding; - try - i := 0; - pcf := cf - 1; - while cf > pcf do - begin - cAddress := get_caller_addr(cf); - cFrame := get_caller_frame(cf); - if cAddress = nil then - Break; - Result := Result + ' ' + SimpleBackTraceStr(cAddress) + LineEnding; - Inc(i); - if (i >= MaxStackCount) or (cFrame = nil) then - Break; - pcf := cf; - cf := cFrame; - end; - except - end; - end; - end; - except - Result := 'Can''t get stack trace information!'; - end; - Result := TrimRight(Result); -end; - -procedure doInitialization; -var - i: Integer; -begin - InitCriticalSection(_CS_LOG); - _HAS_DEBUG_LINE := OpenSymbolFile(ParamStrUTF8(0)); - {$IFDEF LOGACTIVE} - _LOG_ACTIVE := True; - _LOG_LEVEL := SizeOf(TLogType); - {$ENDIF} - {$ifdef traplazlogger} - lazloggerhelper := TLazloggerHelper.Create; - LazLogger.DebugLogger.OnDebugLn := @lazloggerhelper.DbgLn; - {$endif} - _FLOGFILE := ChangeFileExt(ExtractFileName(ParamStrUTF8(0)), '_LOG.txt'); - for i := 1 to Paramcount do - begin - if UpperCase(ParamStrUTF8(i)) = '-LOGACTIVE' then - begin - _LOG_ACTIVE := True; - if i < Paramcount then - begin - if StrToIntDef(ParamStr(i + 1), -1) > -1 then - _LOG_LEVEL := StrToInt(ParamStr(i + 1)); - end; - if _LOG_LEVEL > SizeOf(TLogType) then - _LOG_LEVEL := SizeOf(TLogType); - end; - end; -end; - -procedure doFinalization; -begin - {$ifdef traplazlogger} - DebugLogger.OnDebugLn := nil; - lazloggerhelper.Free; - {$endif} - CloseSymbolFile; - DoneCriticalsection(_CS_LOG); -end; - -{$ifdef traplazlogger} -{ TLazloggerHelper } - -procedure TLazloggerHelper.DbgLn(Sender: TObject; S: String; var Handled: Boolean); -begin - Handled := False; - WriteLog(S, DEBUG); -end; - -{$endif} - -initialization - doInitialization; - -finalization - doFinalization; - -end. diff --git a/baseunits/SimpleException/dbginforeader.pas b/baseunits/SimpleException/dbginforeader.pas deleted file mode 100644 index 324103cfe..000000000 --- a/baseunits/SimpleException/dbginforeader.pas +++ /dev/null @@ -1,922 +0,0 @@ -{ - This file is a modified copy of the FreePascal units lnfodwrf and lineinfo -} -unit DbgInfoReader; - -{$mode objfpc}{$H-}{$S-} - -interface - -function OpenSymbolFile(AFileName: string): boolean; -procedure CloseSymbolFile; -function GetLineInfo(addr:ptruint; out func,source:string; out line:longint) : boolean; - -implementation - -uses - exeinfo, strings; - -var - { the input file to read DWARF/STABS debug info from, i.e. paramstr(0) } - e : TExeFile; - filename, dbgfn : string; - //baseaddr : pointer; - HasStabs, HasDwarf: Boolean; - -{%region ********************* lnfodwrf ************************************} - -{ Current issues: - - - ignores DW_LNS_SET_FILE -} - -{$MACRO ON} - -//{$DEFINE DEBUG_DWARF_PARSER} -{$ifdef DEBUG_DWARF_PARSER} - {$define DEBUG_WRITELN := WriteLn} - {$define DEBUG_COMMENT := } -{$else} - {$define DEBUG_WRITELN := //} - {$define DEBUG_COMMENT := //} -{$endif} - -{ some type definitions } -type - Bool8 = ByteBool; - -const - EBUF_SIZE = 100; - -//{$WARNING This code is not thread-safe, and needs improvement} -var - EBuf: Array [0..EBUF_SIZE-1] of Byte; - EBufCnt, EBufPos: Integer; - { the offset and size of the DWARF debug_line section in the file } - DwarfOffset : longint; - DwarfSize : longint; - -{ DWARF 2 default opcodes} -const - { Extended opcodes } - DW_LNE_END_SEQUENCE = 1; - DW_LNE_SET_ADDRESS = 2; - DW_LNE_DEFINE_FILE = 3; - { Standard opcodes } - DW_LNS_COPY = 1; - DW_LNS_ADVANCE_PC = 2; - DW_LNS_ADVANCE_LINE = 3; - DW_LNS_SET_FILE = 4; - DW_LNS_SET_COLUMN = 5; - DW_LNS_NEGATE_STMT = 6; - DW_LNS_SET_BASIC_BLOCK = 7; - DW_LNS_CONST_ADD_PC = 8; - DW_LNS_FIXED_ADVANCE_PC = 9; - DW_LNS_SET_PROLOGUE_END = 10; - DW_LNS_SET_EPILOGUE_BEGIN = 11; - DW_LNS_SET_ISA = 12; - -type - { state record for the line info state machine } - TMachineState = record - address : QWord; - file_id : DWord; - line : QWord; - column : DWord; - is_stmt : Boolean; - basic_block : Boolean; - end_sequence : Boolean; - prolouge_end : Boolean; - epilouge_begin : Boolean; - isa : DWord; - append_row : Boolean; - end; - -{ DWARF line number program header preceding the line number program, 64 bit version } - TLineNumberProgramHeader64 = packed record - magic : DWord; - unit_length : QWord; - version : Word; - length : QWord; - minimum_instruction_length : Byte; - default_is_stmt : Bool8; - line_base : ShortInt; - line_range : Byte; - opcode_base : Byte; - end; - -{ DWARF line number program header preceding the line number program, 32 bit version } - TLineNumberProgramHeader32 = packed record - unit_length : DWord; - version : Word; - length : DWord; - minimum_instruction_length : Byte; - default_is_stmt : Bool8; - line_base : ShortInt; - line_range : Byte; - opcode_base : Byte; - end; - -{--------------------------------------------------------------------------- - I/O utility functions ----------------------------------------------------------------------------} - -var - base, limit : SizeInt; - index : SizeInt; - -function Init(aBase, aLimit : Int64) : Boolean; -begin - base := aBase; - limit := aLimit; - Init := (aBase + limit) <= e.size; - seek(e.f, base); - EBufCnt := 0; - EBufPos := 0; - index := 0; -end; - -function Init(aBase : Int64) : Boolean; -begin - Init := Init(aBase, limit - (aBase - base)); -end; - - -function Pos() : Int64; -begin - Pos := index; -end; - - -procedure Seek(const newIndex : Int64); -begin - index := newIndex; - system.seek(e.f, base + index); - EBufCnt := 0; - EBufPos := 0; -end; - - -{ Returns the next Byte from the input stream, or -1 if there has been - an error } -function ReadNext() : Longint; inline; -var - bytesread : SizeInt; -begin - ReadNext := -1; - if EBufPos >= EBufCnt then begin - EBufPos := 0; - EBufCnt := EBUF_SIZE; - if EBufCnt > limit - index then - EBufCnt := limit - index; - blockread(e.f, EBuf, EBufCnt, bytesread{%H-}); - EBufCnt := bytesread; - end; - if EBufPos < EBufCnt then begin - ReadNext := EBuf[EBufPos]; - inc(EBufPos); - inc(index); - end - else - ReadNext := -1; -end; - -{ Reads the next size bytes into dest. Returns true if successful, - false otherwise. Note that dest may be partially overwritten after - returning false. } -function ReadNext(var dest; size : SizeInt) : Boolean; //inline; -var - bytesread, totalread : SizeInt; - r: Boolean; - d: PByte; -begin - d := @dest; - totalread := 0; - r := True; - while (totalread < size) and r do begin; - if EBufPos >= EBufCnt then begin - EBufPos := 0; - EBufCnt := EBUF_SIZE; - if EBufCnt > limit - index then - EBufCnt := limit - index; - blockread(e.f, EBuf, EBufCnt, bytesread{%H-}); - EBufCnt := bytesread; - if bytesread <= 0 then - r := False; - end; - if EBufPos < EBufCnt then begin - bytesread := EBufCnt - EBufPos; - if bytesread > size - totalread then bytesread := size - totalread; - System.Move(EBuf[EBufPos], d[totalread], bytesread); - inc(EBufPos, bytesread); - inc(index, bytesread); - inc(totalread, bytesread); - end; - end; - ReadNext := r; -end; - - -{ Reads an unsigned LEB encoded number from the input stream } -function ReadULEB128() : QWord; -var - shift : Byte; - data : PtrInt; - val : QWord; -begin - shift := 0; - ReadULEB128 := 0; - data := ReadNext(); - while (data <> -1) do begin - val := data and $7f; - ReadULEB128 := ReadULEB128 or (val shl shift); - inc(shift, 7); - if ((data and $80) = 0) then - break; - data := ReadNext(); - end; -end; - -{ Reads a signed LEB encoded number from the input stream } -function ReadLEB128() : Int64; -var - shift : Byte; - data : PtrInt; - val : Int64; -begin - shift := 0; - ReadLEB128 := 0; - data := ReadNext(); - while (data <> -1) do begin - val := data and $7f; - ReadLEB128 := ReadLEB128 or (val shl shift); - inc(shift, 7); - if ((data and $80) = 0) then - break; - data := ReadNext(); - end; - { extend sign. Note that we can not use shl/shr since the latter does not - translate to arithmetic shifting for signed types } - ReadLEB128 := (not ((ReadLEB128 and (1 shl (shift-1)))-1)) or ReadLEB128; -end; - - -{ Reads an address from the current input stream } -function ReadAddress() : PtrUInt; -begin - ReadNext(ReadAddress{%H-}, sizeof(ReadAddress)); -end; - - -{ Reads a zero-terminated string from the current input stream. If the - string is larger than 255 chars (maximum allowed number of elements in - a ShortString, excess characters will be chopped off. } -function ReadString() : ShortString; -var - temp : PtrInt; - i : PtrUInt; -begin - i := 1; - temp := ReadNext(); - while (temp > 0) do begin - ReadString[i] := char(temp); - if (i = 255) then begin - { skip remaining characters } - repeat - temp := ReadNext(); - until (temp <= 0); - break; - end; - inc(i); - temp := ReadNext(); - end; - { unexpected end of file occurred? } - if (temp = -1) then - ReadString := '' - else - Byte(ReadString[0]) := i-1; -end; - - -{ Reads an unsigned Half from the current input stream } -function ReadUHalf() : Word; -begin - ReadNext(ReadUHalf{%H-}, sizeof(ReadUHalf)); -end; - - -{--------------------------------------------------------------------------- - - Generic Dwarf lineinfo reader - - The line info reader is based on the information contained in - - DWARF Debugging Information Format Version 3 - Chapter 6.2 "Line Number Information" - - from the - - DWARF Debugging Information Format Workgroup. - - For more information on this document see also - - http://dwarf.freestandards.org/ - ----------------------------------------------------------------------------} - -{ initializes the line info state to the default values } -procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8); -begin - with state do begin - address := 0; - file_id := 1; - line := 1; - column := 0; - is_stmt := aIs_Stmt; - basic_block := false; - end_sequence := false; - prolouge_end := false; - epilouge_begin := false; - isa := 0; - append_row := false; - end; -end; - - -{ Skips all line info directory entries } -procedure SkipDirectories(); -var s : ShortString; -begin - while (true) do begin - s := ReadString(); - if (s = '') then break; - DEBUG_WRITELN('Skipping directory : ', s); - end; -end; - -{ Skips an LEB128 } -procedure SkipLEB128(); -{$ifdef DEBUG_DWARF_PARSER} -var temp : QWord; -{$endif} -begin - {$ifdef DEBUG_DWARF_PARSER}temp := {$endif}ReadLEB128(); - DEBUG_WRITELN('Skipping LEB128 : ', temp); -end; - -{ Skips the filename section from the current file stream } -procedure SkipFilenames(); -var s : ShortString; -begin - while (true) do begin - s := ReadString(); - if (s = '') then break; - DEBUG_WRITELN('Skipping filename : ', s); - SkipLEB128(); { skip the directory index for the file } - SkipLEB128(); { skip last modification time for file } - SkipLEB128(); { skip length of file } - end; -end; - -function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64; -begin - CalculateAddressIncrement := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length; -end; - -function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString; -var - i : DWord; - filename, directory : ShortString; - dirindex : Int64; -begin - filename := ''; - directory := ''; - i := 1; - Seek(filenameStart); - while (i <= file_id) do begin - filename := ReadString(); - DEBUG_WRITELN('Found "', filename, '"'); - if (filename = '') then break; - dirindex := ReadLEB128(); { read the directory index for the file } - SkipLEB128(); { skip last modification time for file } - SkipLEB128(); { skip length of file } - inc(i); - end; - { if we could not find the file index, exit } - if (filename = '') then begin - GetFullFilename := '(Unknown file)'; - exit; - end; - - Seek(directoryStart); - i := 1; - while (i <= dirindex) do begin - directory := ReadString(); - if (directory = '') then break; - inc(i); - end; - if (directory<>'') and (directory[length(directory)]<>'/') then - directory:=directory+'/'; - GetFullFilename := directory + filename; -end; - - -function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord; - var source : String; var line : longint; var found : Boolean) : QWord; -var - state : TMachineState; - { we need both headers on the stack, although we only use the 64 bit one internally } - header64 : TLineNumberProgramHeader64; - header32 : TLineNumberProgramHeader32; - - adjusted_opcode : Int64; - - opcode : PtrInt; - extended_opcode : Byte; - extended_opcode_length : PtrInt; - i, addrIncrement, lineIncrement : PtrInt; - - {$ifdef DEBUG_DWARF_PARSER} - s : ShortString; - {$endif} - - numoptable : array[1..255] of Byte; - { the offset into the file where the include directories are stored for this compilation unit } - include_directories : QWord; - { the offset into the file where the file names are stored for this compilation unit } - file_names : Int64; - - temp_length : DWord; - unit_length : QWord; - header_length : SizeInt; - - first_row : Boolean; - - prev_line : QWord; - prev_file : DWord; - -begin - prev_line := 0; - prev_file := 0; - first_row := true; - - found := false; - - ReadNext(temp_length{%H-}, sizeof(temp_length)); - if (temp_length <> $ffffffff) then begin - unit_length := temp_length + sizeof(temp_length) - end else begin - ReadNext(unit_length, sizeof(unit_length)); - inc(unit_length, 12); - end; - - ParseCompilationUnit := file_offset + unit_length; - - Init(file_offset, unit_length); - - DEBUG_WRITELN('Unit length: ', unit_length); - if (temp_length <> $ffffffff) then begin - DEBUG_WRITELN('32 bit DWARF detected'); - ReadNext(header32{%H-}, sizeof(header32)); - header64.magic := $ffffffff; - header64.unit_length := header32.unit_length; - header64.version := header32.version; - header64.length := header32.length; - header64.minimum_instruction_length := header32.minimum_instruction_length; - header64.default_is_stmt := header32.default_is_stmt; - header64.line_base := header32.line_base; - header64.line_range := header32.line_range; - header64.opcode_base := header32.opcode_base; - header_length := - sizeof(header32.length) + sizeof(header32.version) + - sizeof(header32.unit_length); - end else begin - DEBUG_WRITELN('64 bit DWARF detected'); - ReadNext(header64, sizeof(header64)); - header_length := - sizeof(header64.magic) + sizeof(header64.version) + - sizeof(header64.length) + sizeof(header64.unit_length); - end; - - inc(header_length, header64.length); - - fillchar(numoptable{%H-}, sizeof(numoptable), #0); - ReadNext(numoptable, header64.opcode_base-1); - DEBUG_WRITELN('Opcode parameter count table'); - for i := 1 to header64.opcode_base-1 do begin - DEBUG_WRITELN('Opcode[', i, '] - ', numoptable[i], ' parameters'); - end; - - DEBUG_WRITELN('Reading directories...'); - include_directories := Pos(); - SkipDirectories(); - DEBUG_WRITELN('Reading filenames...'); - file_names := Pos(); - SkipFilenames(); - - Seek(header_length); - - with header64 do begin - InitStateRegisters(state{%H-}, default_is_stmt); - end; - opcode := ReadNext(); - while (opcode <> -1) and (not found) do begin - DEBUG_WRITELN('Next opcode: '); - case (opcode) of - { extended opcode } - 0 : begin - extended_opcode_length := ReadULEB128(); - extended_opcode := ReadNext(); - case (extended_opcode) of - DW_LNE_END_SEQUENCE : begin - state.end_sequence := true; - state.append_row := true; - DEBUG_WRITELN('DW_LNE_END_SEQUENCE'); - end; - DW_LNE_SET_ADDRESS : begin - state.address := ReadAddress(); - DEBUG_WRITELN('DW_LNE_SET_ADDRESS (', hexstr(state.address, sizeof(state.address)*2), ')'); - end; - DW_LNE_DEFINE_FILE : begin - {$ifdef DEBUG_DWARF_PARSER}s := {$endif}ReadString(); - SkipLEB128(); - SkipLEB128(); - SkipLEB128(); - DEBUG_WRITELN('DW_LNE_DEFINE_FILE (', s, ')'); - end; - else begin - DEBUG_WRITELN('Unknown extended opcode (opcode ', extended_opcode, ' length ', extended_opcode_length, ')'); - for i := 0 to extended_opcode_length-2 do - ReadNext(); - end; - end; - end; - DW_LNS_COPY : begin - state.basic_block := false; - state.prolouge_end := false; - state.epilouge_begin := false; - state.append_row := true; - DEBUG_WRITELN('DW_LNS_COPY'); - end; - DW_LNS_ADVANCE_PC : begin - inc(state.address, ReadULEB128() * header64.minimum_instruction_length); - DEBUG_WRITELN('DW_LNS_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')'); - end; - DW_LNS_ADVANCE_LINE : begin - // inc(state.line, ReadLEB128()); negative values are allowed - // but those may generate a range check error - state.line := state.line + ReadLEB128(); - DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')'); - end; - DW_LNS_SET_FILE : begin - state.file_id := ReadULEB128(); - DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')'); - end; - DW_LNS_SET_COLUMN : begin - state.column := ReadULEB128(); - DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')'); - end; - DW_LNS_NEGATE_STMT : begin - state.is_stmt := not state.is_stmt; - DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')'); - end; - DW_LNS_SET_BASIC_BLOCK : begin - state.basic_block := true; - DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK'); - end; - DW_LNS_CONST_ADD_PC : begin - inc(state.address, CalculateAddressIncrement(255, header64)); - DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')'); - end; - DW_LNS_FIXED_ADVANCE_PC : begin - inc(state.address, ReadUHalf()); - DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')'); - end; - DW_LNS_SET_PROLOGUE_END : begin - state.prolouge_end := true; - DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END'); - end; - DW_LNS_SET_EPILOGUE_BEGIN : begin - state.epilouge_begin := true; - DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN'); - end; - DW_LNS_SET_ISA : begin - state.isa := ReadULEB128(); - DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')'); - end; - else begin { special opcode } - if (opcode < header64.opcode_base) then begin - DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping'); - for i := 1 to numoptable[opcode] do - SkipLEB128(); - end else begin - adjusted_opcode := opcode - header64.opcode_base; - addrIncrement := CalculateAddressIncrement(opcode, header64); - inc(state.address, addrIncrement); - lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range); - inc(state.line, lineIncrement); - DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement); - state.basic_block := false; - state.prolouge_end := false; - state.epilouge_begin := false; - state.append_row := true; - end; - end; - end; - - if (state.append_row) then begin - DEBUG_WRITELN('Current state : address = ', hexstr(state.address, sizeof(state.address) * 2), - DEBUG_COMMENT ' file_id = ', state.file_id, ' line = ', state.line, ' column = ', state.column, - DEBUG_COMMENT ' is_stmt = ', state.is_stmt, ' basic_block = ', state.basic_block, - DEBUG_COMMENT ' end_sequence = ', state.end_sequence, ' prolouge_end = ', state.prolouge_end, - DEBUG_COMMENT ' epilouge_begin = ', state.epilouge_begin, ' isa = ', state.isa); - - if (first_row) then begin - if (state.address > addr) then - break; - first_row := false; - end; - - { when we have found the address we need to return the previous - line because that contains the call instruction } - if (state.address >= addr) then - found:=true - else - begin - { save line information } - prev_file := state.file_id; - prev_line := state.line; - end; - - state.append_row := false; - if (state.end_sequence) then begin - InitStateRegisters(state, header64.default_is_stmt); - first_row := true; - end; - end; - - opcode := ReadNext(); - end; - - if (found) then begin - line := prev_line; - source := GetFullFilename(file_names, include_directories, prev_file); - end; -end; - -function GetLineInfoDwarf(addr : ptruint; var func, source : string; var line : longint) : boolean; -var - current_offset : QWord; - end_offset : QWord; - - found : Boolean; - -begin - func := ''; - source := ''; - found := false; - GetLineInfoDwarf:=false; - if not e.isopen then exit; - - addr := addr - e.processaddress; - - current_offset := DwarfOffset; - end_offset := DwarfOffset + DwarfSize; - - while (current_offset < end_offset) and (not found) do begin - Init(current_offset, end_offset - current_offset); - current_offset := ParseCompilationUnit(addr, current_offset, - source, line, found); - end; - GetLineInfoDwarf:=found; -end; - -{%endregion ********************* lnfodwrf ************************************} - -{%region ********************* lineinfo ************************************} - -const - N_Function = $24; - N_TextLine = $44; - N_DataLine = $46; - N_BssLine = $48; - N_SourceFile = $64; - N_IncludeFile = $84; - - maxstabs = 40; { size of the stabs buffer } - -var - { GDB after 4.18 uses offset to function begin - in text section but OS/2 version still uses 4.16 PM } - StabsFunctionRelative: boolean; - -type - //pstab=^tstab; - tstab=packed record - strpos : longint; - ntype : byte; - nother : byte; - ndesc : word; - nvalue : dword; - end; - -{ We use static variable so almost no stack is required, and is thus - more safe when an error has occured in the program } -//{$WARNING This code is not thread-safe, and needs improvement } -var - stabcnt, { amount of stabs } - stablen, - stabofs, { absolute stab section offset in executable } - stabstrlen, - stabstrofs : longint; { absolute stabstr section offset in executable } - dirlength : longint; { length of the dirctory part of the source file } - stabs : array[0..maxstabs-1] of tstab; { buffer } - funcstab, { stab with current function info } - linestab, { stab with current line info } - dirstab, { stab with current directory info } - filestab : tstab; { stab with current file info } - -function GetLineInfoStabs(addr:ptruint;var func,source:string;var line:longint) : boolean; -var - res, - stabsleft, - stabscnt,i : longint; - found : boolean; - lastfunc : tstab; -begin - GetLineInfoStabs:=false; -{$ifdef DEBUG_LINEINFO} - writeln(stderr,'GetLineInfo called'); -{$endif DEBUG_LINEINFO} - fillchar(func,high(func)+1,0); - fillchar(source,high(source)+1,0); - line:=0; - if not e.isopen then exit; - - { correct the value to the correct address in the file } - { processaddress is set in OpenStabs } - addr := dword(addr - e.processaddress); - -{$ifdef DEBUG_LINEINFO} - writeln(stderr,'Addr: ',hexstr(addr,sizeof(addr)*2)); -{$endif DEBUG_LINEINFO} - - fillchar(funcstab,sizeof(tstab),0); - fillchar(filestab,sizeof(tstab),0); - fillchar(dirstab,sizeof(tstab),0); - fillchar(linestab,sizeof(tstab),0); - fillchar(lastfunc{%H-},sizeof(tstab),0); - found:=false; - system.seek(e.f,stabofs); - stabsleft:=stabcnt; - repeat - if stabsleft>maxstabs then - stabscnt:=maxstabs - else - stabscnt:=stabsleft; - blockread(e.f,stabs,stabscnt*sizeof(tstab),res{%H-}); - stabscnt:=res div sizeof(tstab); - for i:=0 to stabscnt-1 do - begin - case stabs[i].ntype of - N_BssLine, - N_DataLine, - N_TextLine : - begin - if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then - inc(stabs[i].nvalue,lastfunc.nvalue); - if (stabs[i].nvalue<=addr) and - (stabs[i].nvalue>linestab.nvalue) then - begin - { if it's equal we can stop and take the last info } - if stabs[i].nvalue=addr then - found:=true - else - linestab:=stabs[i]; - end; - end; - N_Function : - begin - lastfunc:=stabs[i]; - if (stabs[i].nvalue<=addr) and - (stabs[i].nvalue>funcstab.nvalue) then - begin - funcstab:=stabs[i]; - fillchar(linestab,sizeof(tstab),0); - end; - end; - N_SourceFile, - N_IncludeFile : - begin - if (stabs[i].nvalue<=addr) and - (stabs[i].nvalue>=filestab.nvalue) then - begin - { if same value and type then the first one - contained the directory PM } - if (stabs[i].nvalue=filestab.nvalue) and - (stabs[i].ntype=filestab.ntype) then - dirstab:=filestab - else - fillchar(dirstab,sizeof(tstab),0); - filestab:=stabs[i]; - fillchar(linestab,sizeof(tstab),0); - { if new file then func is not valid anymore PM } - if stabs[i].ntype=N_SourceFile then - begin - fillchar(funcstab,sizeof(tstab),0); - fillchar(lastfunc,sizeof(tstab),0); - end; - end; - end; - end; - end; - dec(stabsleft,stabscnt); - until found or (stabsleft=0); - -{ get the line,source,function info } - line:=linestab.ndesc; - if dirstab.ntype<>0 then - begin - system.seek(e.f,stabstrofs+dirstab.strpos); - blockread(e.f,source[1],high(source)-1,res); - dirlength:=strlen(@source[1]); - source[0]:=chr(dirlength); - end - else - dirlength:=0; - if filestab.ntype<>0 then - begin - system.seek(e.f,stabstrofs+filestab.strpos); - blockread(e.f,source[dirlength+1],high(source)-(dirlength+1),res); - source[0]:=chr(strlen(@source[1])); - end; - if funcstab.ntype<>0 then - begin - system.seek(e.f,stabstrofs+funcstab.strpos); - blockread(e.f,func[1],high(func)-1,res); - func[0]:=chr(strlen(@func[1])); - i:=system.pos(':',func); - if i>0 then - Delete(func,i,255); - end; - GetLineInfoStabs:=found; -end; - -{%endregion ********************* lineinfo ************************************} - -function OpenSymbolFile(AFileName: string): boolean; -begin - Result := False; - HasStabs := False; - HasDwarf := False; - filename := AFileName; - - if not OpenExeFile(e,filename) then - exit; - if ReadDebugLink(e,dbgfn) then - begin - CloseExeFile(e); - if not OpenExeFile(e,dbgfn) then - exit; - end; - - e.processaddress:=0; -// e.processaddress:=ptruint(baseaddr)-e.processaddress; - - - {%region ********************* lnfodwrf ************************************} - if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then begin - HasDwarf := True; - Result:=true; - end; - {%endregion ********************* lnfodwrf ************************************} - - {%region ********************* lineinfo ************************************} - StabsFunctionRelative := E.FunctionRelative; - if FindExeSection(e,'.stab',stabofs,stablen) and - FindExeSection(e,'.stabstr',stabstrofs,stabstrlen) then - begin - stabcnt:=stablen div sizeof(tstab); - HasStabs := True; - Result:=true; - end; - {%endregion ********************* lineinfo ************************************} -end; - -procedure CloseSymbolFile; -begin - CloseExeFile(e); -end; - -function GetLineInfo(addr: ptruint; out func, source: string; out line: longint): boolean; -begin - Result := False; - if HasDwarf then - Result := GetLineInfoDwarf(addr, func{%H-}, source{%H-}, line{%H-}); - if (not Result) and HasStabs then - Result := GetLineInfoStabs(addr, func, source, line); -end; - - -end. - diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ffc537050..18b2b17a1 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -200,30 +200,33 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="7"> + <RequiredPackages Count="8"> <Item1> - <PackageName Value="BESENPkg"/> + <PackageName Value="multiloglaz"/> </Item1> <Item2> - <PackageName Value="laz_synapse"/> + <PackageName Value="BESENPkg"/> </Item2> <Item3> - <PackageName Value="internettools"/> + <PackageName Value="laz_synapse"/> </Item3> <Item4> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="internettools"/> </Item4> <Item5> - <PackageName Value="richmemopackage"/> + <PackageName Value="TAChartLazarusPkg"/> </Item5> <Item6> - <PackageName Value="virtualtreeview_package"/> + <PackageName Value="richmemopackage"/> </Item6> <Item7> - <PackageName Value="LCL"/> + <PackageName Value="virtualtreeview_package"/> </Item7> + <Item8> + <PackageName Value="LCL"/> + </Item8> </RequiredPackages> - <Units Count="12"> + <Units Count="13"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -305,6 +308,12 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit11> + <Unit12> + <Filename Value="forms\frmLogger.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="FormLogger"/> + <ResourceBaseClass Value="Form"/> + </Unit12> </Units> </ProjectOptions> <CompilerOptions> diff --git a/readme.txt b/readme.txt index a2feaae63..d87b51dcc 100644 --- a/readme.txt +++ b/readme.txt @@ -26,6 +26,7 @@ In order to build FMD from the source code, you must install Lazarus latest vers - Synapse, http://synapse.ararat.cz/ - InternetTools, https://github.com/benibela/internettools - BESEN, https://github.com/BeRo1985/besen + - MultiLog, https://github.com/blikblum/multilog After everything is installed, open the file md.lpi by using Lazarus IDE, select Run->Build to build the source code. If everything is ok, the binary file should be in FMD_source_code_folder/bin From 694aec844188d296f5200ceea42c3f30a325b8ab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:04:06 +0800 Subject: [PATCH 1340/2794] added log form, replace all logging with multilog --- baseunits/DBDataProcess.pas | 48 +-- baseunits/accountmanagerdb.pas | 18 +- baseunits/httpsendthread.pas | 25 +- baseunits/modules/Batoto.pas | 18 +- baseunits/uBaseUnit.pas | 10 +- baseunits/uData.pas | 5 +- baseunits/uDownloadsManager.pas | 8 +- baseunits/uFMDThread.pas | 11 +- baseunits/uUpdateThread.pas | 10 +- mangadownloader/forms/frmLogger.lfm | 123 +++++++ mangadownloader/forms/frmLogger.lrj | 5 + mangadownloader/forms/frmLogger.pas | 84 +++++ mangadownloader/forms/frmMain.lfm | 428 ++++++++++++++++++------- mangadownloader/forms/frmMain.lrj | 6 + mangadownloader/forms/frmMain.pas | 117 +++++-- mangadownloader/languages/fmd.en.po | 37 +++ mangadownloader/languages/fmd.id_ID.po | 37 +++ mangadownloader/languages/fmd.po | 36 +++ mangadownloader/md.lpr | 4 +- 19 files changed, 795 insertions(+), 235 deletions(-) create mode 100644 mangadownloader/forms/frmLogger.lfm create mode 100644 mangadownloader/forms/frmLogger.lrj create mode 100644 mangadownloader/forms/frmLogger.pas diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index b775495d0..24024385c 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -10,8 +10,8 @@ interface uses - Classes, SysUtils, FileUtil, LazFileUtils, FMDOptions, sqlite3conn, sqlite3backup, - sqlite3dyn, sqldb, DB, dateutils, RegExpr; + Classes, SysUtils, FileUtil, LazFileUtils, FMDOptions, MultiLog, sqlite3conn, + sqlite3backup, sqlite3dyn, sqldb, DB, dateutils, RegExpr; type @@ -138,7 +138,7 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); implementation uses - uBaseUnit, uData, uMisc, SimpleLogger; + uBaseUnit, uData, uMisc; function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; @@ -259,7 +259,7 @@ procedure CopyDBDataProcess(const AWebsite, NWebsite: String); [cffPreserveTime, cffOverwriteFile], True); except on E: Exception do - Writelog_E('CopyDBDataProcess.Error!', E); + Logger.SendException('CopyDBDataProcess.Error!', E); end; end; end; @@ -356,7 +356,7 @@ procedure TDBDataProcess.VacuumTable; ExecuteDirect('VACUUM'); except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].VacuumTable.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].VacuumTable.Error!', E); end; ExecuteDirect('BEGIN TRANSACTION'); end; @@ -449,7 +449,7 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; except on E: Exception do begin - WriteLog_E(Self.ClassName+'['+Website+'].InternalOpen.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].InternalOpen.Error!', E); Result := False; end; end; @@ -468,8 +468,8 @@ function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; Result:=FQuery.Fields[DBTempFieldWebsiteIndex].AsString; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].GetWebsiteName Error!'+ - 'RecIndex: '+IntToStr(RecIndex), E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].GetWebsiteName Error!'+ + 'RecIndex: '+IntToStr(RecIndex), E); end; end; @@ -537,8 +537,8 @@ procedure TDBDataProcess.AttachAllSites; end; except on E: Exception do - Writelog_E(Self.ClassName+'['+Website+'].AttachAllSites.Error!'+ - ' try to attach '+QuotedStr(SitesList[i]), E, Self) + Logger.SendException(Self.ClassName+'['+Website+'].AttachAllSites.Error!'+ + ' try to attach '+QuotedStr(SitesList[i]), E) end; FConn.ExecuteDirect('BEGIN TRANSACTION'); FAllSitesAttached := FAttachedSites.Count > 0; @@ -560,7 +560,7 @@ procedure TDBDataProcess.DetachAllSites; FAttachedSites.Delete(i); except on E: Exception do - Writelog_E(Self.ClassName+'['+Website+'].DetachAllSites.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].DetachAllSites.Error!', E); end; end; FConn.ExecuteDirect('BEGIN TRANSACTION'); @@ -577,8 +577,8 @@ function TDBDataProcess.ExecuteDirect(SQL: String): Boolean; Result := True; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].ExecuteDirect.Error!'#13#10 + - 'SQL: ' + SQL, E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].ExecuteDirect.Error!'#13#10 + + 'SQL: ' + SQL, E); end; end; @@ -617,7 +617,7 @@ destructor TDBDataProcess.Destroy; end; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Destroy.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].Destroy.Error!', E); end; DoneLocateLink; FAttachedSites.Free; @@ -669,7 +669,7 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; Result := FQuery.Active; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Open.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].Open.Error!', E); end; end; @@ -697,7 +697,7 @@ function TDBDataProcess.OpenTable(const ATableName: String; end; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].OpenTable.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].OpenTable.Error!', E); end; end; Result := FQuery.Active; @@ -734,7 +734,7 @@ procedure TDBDataProcess.Close; FConn.DatabaseName := ''; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Close.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].Close.Error!', E); end; end; @@ -867,7 +867,7 @@ procedure TDBDataProcess.Commit; FQuery.Active := queryactive; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Commit.Error!',E,Self); + Logger.SendException(Self.ClassName+'['+Website+'].Commit.Error!',E); end; end; @@ -878,7 +878,7 @@ procedure TDBDataProcess.Rollback; FTrans.Rollback; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Rollback.Error!',E,Self); + Logger.SendException(Self.ClassName+'['+Website+'].Rollback.Error!',E); end; end; @@ -930,8 +930,8 @@ function TDBDataProcess.Search(ATitle: String): Boolean; FQuery.Open; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Search.Error!'#13#10 + - 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].Search.Error!'#13#10 + + 'SQL:'#13#10 + FQuery.SQL.Text, E); end; end; Result := FQuery.Active; @@ -1076,8 +1076,8 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList except on E: Exception do begin - WriteLog_E(Self.ClassName+'['+Website+'].Filter.Error!'#13#10 + - 'SQL:'#13#10 + FQuery.SQL.Text, E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].Filter.Error!'#13#10 + + 'SQL:'#13#10 + FQuery.SQL.Text, E); FQuery.Close; SQL.Text := tsql; Self.GetRecordCount; @@ -1150,7 +1150,7 @@ procedure TDBDataProcess.Sort; VacuumTable; except on E: Exception do - WriteLog_E(Self.ClassName+'['+Website+'].Sort.Error!', E, Self); + Logger.SendException(Self.ClassName+'['+Website+'].Sort.Error!', E); end; if FQuery.Active <> queryactive then FQuery.Active := queryactive; diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index a26408caa..25ed25926 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, LazFileUtils, SimpleLogger, base64, sqlite3conn, + Classes, SysUtils, LazFileUtils, MultiLog, base64, sqlite3conn, sqldb, db; type @@ -226,7 +226,7 @@ function TAccountManager.InternalOpenDB: Boolean; Result := fconn.Connected; except on E: Exception do - WriteLog_E('TAccountManager.InternalOpenDB.Failed, ' + ffilename, E, Self); + Logger.SendException('TAccountManager.InternalOpenDB.Failed, ' + ffilename, E); end; end; @@ -242,7 +242,7 @@ function TAccountManager.CreateDBTable: Boolean; Result := True; except on E: Exception do - WriteLog_E('TAccountManager.CreateDBTable.Failed, ' + ffilename, E, Self); + Logger.SendException('TAccountManager.CreateDBTable.Failed, ' + ffilename, E); end; end; @@ -259,7 +259,7 @@ function TAccountManager.OpenDBTable: Boolean; Result := fquery.Active; except on E: Exception do - WriteLog_E('TAccountManager.OpenDBTable.Failed, ' + ffilename, E, Self); + Logger.SendException('TAccountManager.OpenDBTable.Failed, ' + ffilename, E); end; if Result then ConvertNewTable; end; @@ -468,7 +468,7 @@ procedure TAccountManager.Vacuum; fconn.ExecuteDirect('VACUUM'); except on E: Exception do - WriteLog_E('TAccountManager.Vacuum.Failed!', E, Self); + Logger.SendException('TAccountManager.Vacuum.Failed!', E); end; fconn.ExecuteDirect('BEGIN TRANSACTION'); fquery.Open; @@ -517,7 +517,7 @@ procedure TAccountManager.Save; GetRecordCount; except on E: Exception do - WriteLog_E('TAccountManager.Save.Failed, ' + ffilename, E, Self); + Logger.SendException('TAccountManager.Save.Failed, ' + ffilename, E); end; end; @@ -540,7 +540,7 @@ function TAccountManager.AddAccount(const AName, AUsername, APassword: string Result := True; except on E: Exception do - WriteLog_E('TAccountManager.AddAccount.Failed, ' + AName, E, Self); + Logger.SendException('TAccountManager.AddAccount.Failed, ' + AName, E); end; end; @@ -558,7 +558,7 @@ function TAccountManager.DeleteAccount(const AName: string): Boolean; end; except on E: Exception do - WriteLog_E('TAccountManager.DeleteAccount.Failed, ' + AName, E, Self); + Logger.SendException('TAccountManager.DeleteAccount.Failed, ' + AName, E); end; end; @@ -576,7 +576,7 @@ function TAccountManager.DeleteAccount(const RecIndex: Integer): Boolean; end; except on E: Exception do - WriteLog_E('TAccountManager.DeleteAccount.Failed, ' + IntToStr(RecIndex), E, Self); + Logger.SendException('TAccountManager.DeleteAccount.Failed, ' + IntToStr(RecIndex), E); end; end; diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index abb6bee8e..fd0c04a50 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - uFMDThread, GZIPUtils, Graphics, SimpleLogger, RegExpr; + uFMDThread, GZIPUtils, Graphics, RegExpr; type @@ -292,19 +292,16 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: mstream.Free; end; if Assigned(Response) then - try - if Response is TStringList then - TStringList(Response).LoadFromStream(Document) - else - if Response is TPicture then - TPicture(Response).LoadFromStream(Document) - else - if Response is TStream then - Document.SaveToStream(TStream(Response)); - except - on E: Exception do - WriteLog_E('HTTPRequest.WriteOutput.Error!', E); - end; + begin + if Response is TStringList then + TStringList(Response).LoadFromStream(Document) + else + if Response is TPicture then + TPicture(Response).LoadFromStream(Document) + else + if Response is TStream then + Document.SaveToStream(TStream(Response)); + end; Result := Document.Size > 0; finally HTTPHeader.Free; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index f66182f3b..f7b7fe00e 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -6,8 +6,8 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, httpsendthread, dateutils, SimpleLogger, - synautil; + accountmanagerdb, XQueryEngineHTML, httpsendthread, dateutils, + synautil, MultiLog; implementation @@ -46,7 +46,7 @@ function Login(const AHTTP: THTTPSendThread): Boolean; Account.Status[modulename] := asChecking; Reset; Cookies.Clear; - Writelog_V('Batoto, login: get login form'); + Logger.Send('Batoto, login: get login form'); if GET(urlroot) then begin loginform := THTMLForm.Create; query := TXQueryEngineHTML.Create(Document); @@ -62,26 +62,26 @@ function Login(const AHTTP: THTTPSendThread): Boolean; end; Clear; Headers.Values['Referer'] := ' https://bato.to/'; - Writelog_V('Batoto, login: send authentification'); + Logger.Send('Batoto, login: send authentification'); if POST(urllogin, loginform.GetData) then begin if ResultCode = 200 then begin Result := Cookies.Values['pass_hash'] <> ''; if Result then begin - Writelog_V('Batoto, login: success'); + Logger.Send('Batoto, login: success'); Account.Cookies[modulename] := GetCookies; Account.Status[modulename] := asValid; end else begin - Writelog_V('Batoto, login: failed, wrong user/password?'); + Logger.SendError('Batoto, login: failed, wrong user/password?'); Account.Status[modulename] := asInvalid; end; Account.Save; end else - Writelog_V(['Batoto, login: failed, unexpected server reply: ', - ResultCode, ' ', ResultString]); + Logger.SendError('Batoto, login: failed, unexpected server reply: ' + + IntToStr(ResultCode) + ' ' + ResultString); end else - Writelog_V('Batoto, login: connection failed'); + Logger.SendError('Batoto, login: connection failed'); end; finally query.Free; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d285039ad..83603aaba 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -21,8 +21,8 @@ interface SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, LConvEncoding, strutils, dateutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, - FPimage, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, - xquery, xquery_json, ImgInfos, SimpleException, SimpleLogger; + MultiLog, FPimage, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, + simplehtmltreeparser, xquery, xquery_json, ImgInfos, SimpleException; const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -3226,7 +3226,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTP.Document.SaveToStream(TStream(output)); except on E: Exception do - WriteLog_E('GetPage.WriteOutput.Error!', E); + Logger.SendException('GetPage.WriteOutput.Error!', E); end; Result := True; end @@ -3284,7 +3284,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag end; except on E: Exception do - WriteLog_E('SaveImageStreamToFile.WriteToFile Failed! ' + f, E); + Logger.SendException('SaveImageStreamToFile.WriteToFile Failed! ' + f, E); end; if FileExistsUTF8(f) then begin @@ -3294,7 +3294,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag FileSetDateUTF8(f, Age); except on E: Exception do - WriteLog_E('SaveImageStreamToFile.FileSetDate Error! ' + f, E); + Logger.SendException('SaveImageStreamToFile.FileSetDate Error! ' + f, E); end; end; end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 08bc45d93..fefff0151 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FMDOptions, httpsendthread, - FileUtil, LazFileUtils, SimpleLogger, strutils, dateutils, RegExpr, httpsend; + FileUtil, LazFileUtils, strutils, dateutils, RegExpr, httpsend, MultiLog; type @@ -658,7 +658,7 @@ function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; end; except on E: Exception do - WriteLog_E('TDataProcess.Filter.Error!', E, Self); + Logger.SendException(Self.ClassName + '.Filter.Error!', E); end; regx.Free; end; @@ -667,6 +667,7 @@ function TDataProcess.Search(AMangaName: String): Boolean; var i: Cardinal; begin + Result := False; searchPos.Clear; if filterPos.Count <= 0 then Exit; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5c1c1208f..028591e05 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -16,8 +16,8 @@ interface uses LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Classes, SysUtils, - ExtCtrls, typinfo, fgl, blcksock, uBaseUnit, uPacker, uFMDThread, uMisc, - DownloadedChaptersDB, FMDOptions, httpsendthread, SimpleLogger, dateutils, + ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, uFMDThread, uMisc, + DownloadedChaptersDB, FMDOptions, httpsendthread, dateutils, strutils; type @@ -1140,7 +1140,7 @@ procedure TTaskThread.Execute; Inc(c); end; if c > 0 then begin - WriteLog_W(Format('%s, checkforfinish failed=%d/%d "%s" > "%s"', + Logger.SendWarning(Format('%s, checkforfinish failed=%d/%d "%s" > "%s"', [Self.ClassName, c, Container.PageLinks.Count, @@ -1330,7 +1330,7 @@ procedure TTaskThread.Execute; Container.Status := STATUS_FAILED; end else begin - WriteLog_W(Format('%s, failed download image PageLinks=%d "%s" > "%s"', + Logger.SendWarning(Format('%s, failed download image PageLinks=%d "%s" > "%s"', [Self.ClassName, Container.PageLinks.Count, Container.DownloadInfo.Title, diff --git a/baseunits/uFMDThread.pas b/baseunits/uFMDThread.pas index c9bb71393..886ec0131 100644 --- a/baseunits/uFMDThread.pas +++ b/baseunits/uFMDThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, SimpleLogger; + Classes, SysUtils; type @@ -22,8 +22,6 @@ TFMDThread = class(TThread) FOnCustomTerminate: TNotifyEvent; function GetTerminated: Boolean; procedure CallCustomTerminate; - protected - procedure DoTerminate; override; public constructor Create(CreateSuspended: Boolean = True); procedure Terminate; @@ -43,13 +41,6 @@ procedure TFMDThread.CallCustomTerminate; FOnCustomTerminate(Self); end; -procedure TFMDThread.DoTerminate; -begin - if (FatalException <> nil) and (FatalException is Exception) then - WriteLog_E('TFMDThread.FatalException!', Exception(FatalException), Self); - inherited DoTerminate; -end; - constructor TFMDThread.Create(CreateSuspended: Boolean = True); begin inherited Create(CreateSuspended); diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 57a0c7857..d7b899b74 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, typinfo, uData, LazFileUtils, uBaseUnit, uFMDThread, uMisc, - WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread; + WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread, MultiLog; type TUpdateListManagerThread = class; @@ -95,7 +95,7 @@ TUpdateListManagerThread = class(TFMDThread) implementation uses - frmMain, Dialogs, ComCtrls, Forms, Controls, SimpleLogger; + frmMain, Dialogs, ComCtrls, Forms, Controls; { TUpdateListThread } @@ -349,8 +349,8 @@ constructor TUpdateListManagerThread.Create; destructor TUpdateListManagerThread.Destroy; begin - if FThreadAborted then WriteLog_W(Self.ClassName+', thread aborted by user?'); - if not FThreadEndNormally then WriteLog_W(Self.ClassName+', thread doesn''t end normally, ended by user?'); + if FThreadAborted then Logger.SendWarning(Self.ClassName+', thread aborted by user?'); + if not FThreadEndNormally then Logger.SendWarning(Self.ClassName+', thread doesn''t end normally, ended by user?'); websites.Free; mainDataProcess.Close; tempDataProcess.Close; @@ -687,7 +687,7 @@ procedure TUpdateListManagerThread.Execute; end; except on E: Exception do - WriteLog_E(cloghead+'error occured!', E, Self); + Logger.SendException(cloghead + 'error occured!', E); end; tempDataProcess.Close; diff --git a/mangadownloader/forms/frmLogger.lfm b/mangadownloader/forms/frmLogger.lfm new file mode 100644 index 000000000..fc69ec75d --- /dev/null +++ b/mangadownloader/forms/frmLogger.lfm @@ -0,0 +1,123 @@ +object FormLogger: TFormLogger + Left = 0 + Height = 283 + Top = 0 + Width = 457 + Caption = 'Log' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ClientHeight = 283 + ClientWidth = 457 + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + Position = poMainFormCenter + Visible = False + object tvLog: TLogTreeView + Left = 6 + Height = 237 + Top = 40 + Width = 445 + Align = alBottom + Anchors = [akTop, akLeft, akRight, akBottom] + DefaultItemHeight = 18 + HotTrack = True + ReadOnly = True + ScrollBars = ssAutoBoth + ShowTime = True + TabOrder = 0 + TimeFormat = 'hh:nn:ss:zzz' + Options = [tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] + end + object ckStayOnTop: TCheckBox + Left = 6 + Height = 19 + Top = 8 + Width = 80 + Caption = 'Stay on top' + OnChange = ckStayOnTopChange + TabOrder = 1 + end + object seLogLimit: TSpinEdit + Left = 373 + Height = 23 + Top = 8 + Width = 78 + Anchors = [akTop, akRight] + Increment = 10 + MaxValue = 100000 + MinValue = 10 + TabOrder = 2 + Value = 1000 + end + object lbLogLimit: TLabel + AnchorSideTop.Control = seLogLimit + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = seLogLimit + Left = 320 + Height = 15 + Top = 12 + Width = 47 + Anchors = [akTop, akRight] + Caption = 'Log limit' + ParentColor = False + end + object btnClearLog: TBitBtn + AnchorSideTop.Control = seLogLimit + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = lbLogLimit + Left = 241 + Height = 26 + Top = 6 + Width = 73 + Anchors = [akTop, akRight] + AutoSize = True + Caption = 'Clear' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btnClearLogClick + TabOrder = 3 + end + object tmClearLog: TTimer + Interval = 2000 + OnTimer = tmClearLogTimer + left = 288 + top = 80 + end +end diff --git a/mangadownloader/forms/frmLogger.lrj b/mangadownloader/forms/frmLogger.lrj new file mode 100644 index 000000000..f79b1ba10 --- /dev/null +++ b/mangadownloader/forms/frmLogger.lrj @@ -0,0 +1,5 @@ +{"version":1,"strings":[ +{"hash":119198672,"name":"tformlogger.ckstayontop.caption","sourcebytes":[83,116,97,121,32,111,110,32,116,111,112],"value":"Stay on top"}, +{"hash":158511444,"name":"tformlogger.lbloglimit.caption","sourcebytes":[76,111,103,32,108,105,109,105,116],"value":"Log limit"}, +{"hash":4860802,"name":"tformlogger.btnclearlog.caption","sourcebytes":[67,108,101,97,114],"value":"Clear"} +]} diff --git a/mangadownloader/forms/frmLogger.pas b/mangadownloader/forms/frmLogger.pas new file mode 100644 index 000000000..1af08d861 --- /dev/null +++ b/mangadownloader/forms/frmLogger.pas @@ -0,0 +1,84 @@ +unit frmLogger; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin, + ExtCtrls, Buttons, LogTreeView, MultiLog; + +type + + { TFormLogger } + + TFormLogger = class(TForm) + btnClearLog: TBitBtn; + ckStayOnTop: TCheckBox; + lbLogLimit: TLabel; + seLogLimit: TSpinEdit; + tmClearLog: TTimer; + tvLog: TLogTreeView; + procedure btnClearLogClick(Sender: TObject); + procedure ckStayOnTopChange(Sender: TObject); + procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure tmClearLogTimer(Sender: TObject); + private + { private declarations } + public + { public declarations } + end; + +var + FormLogger: TFormLogger; + +implementation + +{$R *.lfm} + +{ TFormLogger } + +procedure TFormLogger.tmClearLogTimer(Sender: TObject); +begin + if tvLog.Items.TopLvlCount > seLogLimit.Value then + try + tvLog.BeginUpdate; + while tvLog.Items.TopLvlCount > seLogLimit.Value do + tvLog.Items.TopLvlItems[0].Delete; + finally + tvLog.EndUpdate; + end; +end; + +procedure TFormLogger.FormCreate(Sender: TObject); +begin + Logger.Channels.Add(tvLog.Channel); +end; + +procedure TFormLogger.ckStayOnTopChange(Sender: TObject); +begin + if ckStayOnTop.Checked then + FormStyle := fsStayOnTop + else + FormStyle := fsNormal; +end; + +procedure TFormLogger.btnClearLogClick(Sender: TObject); +begin + tvLog.Clear; +end; + +procedure TFormLogger.FormClose(Sender: TObject; var CloseAction: TCloseAction); +begin + CloseAction := caHide; +end; + +procedure TFormLogger.FormDestroy(Sender: TObject); +begin + Logger.Channels.Remove(tvLog.Channel); +end; + +end. + diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 10b58a3d8..2f62d67db 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -5,6 +5,8 @@ object MainForm: TMainForm Width = 771 ActiveControl = pcMain Caption = 'Free Manga Downloader' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 ClientHeight = 587 ClientWidth = 771 OnClose = FormClose @@ -15,10 +17,10 @@ object MainForm: TMainForm Position = poScreenCenter Visible = False object sbUpdateList: TStatusBar - Left = 0 + Left = 4 Height = 30 - Top = 557 - Width = 771 + Top = 553 + Width = 763 AutoSize = False Panels = < item @@ -33,16 +35,16 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 520 - Top = 11 + Height = 512 + Top = 15 Width = 566 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 4 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -289,37 +291,37 @@ object MainForm: TMainForm Anchors = [akTop, akLeft, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } @@ -328,22 +330,22 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 object sbInformation: TScrollBox Left = 0 - Height = 492 + Height = 484 Top = 0 Width = 558 HorzScrollBar.Page = 327 - VertScrollBar.Page = 482 + VertScrollBar.Page = 474 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 TabOrder = 0 object pnInfomation: TPanel @@ -488,21 +490,21 @@ object MainForm: TMainForm end object pnChapterList: TPanel Left = 4 - Height = 215 + Height = 207 Top = 269 Width = 550 Align = alClient BevelOuter = bvNone ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 215 + ClientHeight = 207 ClientWidth = 550 TabOrder = 2 object clbChapterList: TVirtualStringTree AnchorSideTop.Control = edFilterMangaInfoChapters AnchorSideBottom.Control = lbSaveTo Left = 0 - Height = 136 + Height = 128 Top = 0 Width = 516 Anchors = [akTop, akLeft, akRight, akBottom] @@ -536,7 +538,7 @@ object MainForm: TMainForm AnchorSideBottom.Side = asrBottom Left = 338 Height = 26 - Top = 159 + Top = 151 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True @@ -588,7 +590,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 0 Height = 19 - Top = 186 + Top = 178 Width = 334 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' @@ -602,7 +604,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 442 Height = 26 - Top = 159 + Top = 151 Width = 108 Anchors = [akRight, akBottom] AutoSize = True @@ -700,7 +702,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 338 Height = 26 - Top = 189 + Top = 181 Width = 212 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True @@ -751,7 +753,7 @@ object MainForm: TMainForm AnchorSideBottom.Control = edSaveTo Left = 0 Height = 15 - Top = 140 + Top = 132 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' @@ -764,7 +766,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btDownload Left = 0 Height = 23 - Top = 159 + Top = 151 Width = 334 OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False @@ -2132,17 +2134,17 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 object pnOptions: TPageControl Left = 8 - Height = 415 + Height = 407 Top = 8 Width = 539 - ActivePage = tsWebsites + ActivePage = tsMisc Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 6 + TabIndex = 8 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2150,7 +2152,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime @@ -2501,11 +2503,11 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 357 + ClientHeight = 387 ClientWidth = 531 object sbDownloadConnections: TScrollBox Left = 0 - Height = 357 + Height = 387 Top = 0 Width = 531 HorzScrollBar.Page = 455 @@ -2516,7 +2518,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 357 + ClientHeight = 387 ClientWidth = 531 TabOrder = 0 object cbOptionUseProxy: TCheckBox @@ -3235,7 +3237,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 387 ClientWidth = 531 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 4 @@ -3362,7 +3364,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 387 ClientWidth = 531 object gbDialogs: TGroupBox Left = 4 @@ -3616,12 +3618,206 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 + ClientHeight = 379 + ClientWidth = 531 + object pcMisc: TPageControl + Left = 4 + Height = 363 + Top = 8 + Width = 523 + ActivePage = tsLog + Align = alClient + TabIndex = 1 + TabOrder = 0 + object tsCustomColor: TTabSheet + Caption = 'Custom color' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + end + object tsLog: TTabSheet + Caption = 'Log' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 335 + ClientWidth = 515 + object ckEnableLogging: TCheckBox + Left = 4 + Height = 19 + Top = 4 + Width = 99 + Caption = 'Enable logging' + TabOrder = 0 + end + object edLogFileName: TFileNameEdit + AnchorSideLeft.Control = ckEnableLogging + AnchorSideTop.Control = lbLogFileName + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 46 + Width = 506 + FilterIndex = 0 + HideDirectories = False + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C005884950000001F0000 + 001A0000001A0000001A0000001A0000001A0000001A00000011000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0075477E225250A932B2B + 0C8A2D2D0D872D2D0D872D2D0D872D2D0D872D2D0D8723230B6A000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF4186A8FFE5E5E5FFE5E5 + E4FFFEFEFDFFFEFEFCFFFDFDFAFFFCFCF9FFFEFEF9FF3B3B1B88000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF4489ACFFE4E4E4FFE3E3 + E2FFFCFCFBFFFBFBF8FFFAFAF6FFF8F8F4FFFBFBF5FF4F4F2C7D000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF468BAFFFB7B7A8FFB6B6 + A7FFDBDBCAFFD1D1C0FFF8F8F4FFF7F7F1FFFAFAF4FF58583276005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF488FB2FFD5D5C6FFD4D4 + C5FFEBEBDAFFE9E9D8FFF7F7F1FFF5F5EFFFFAFAF2FF5D5D37740076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF4C92B6FFB5B5A6FFC4C4 + B4FFC7C7B6FFD6D6C5FFD4D4C3FFCACAB9FFF8F8EEFF62623C720078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF4F96B8FFD3D3C4FFD1D1 + C2FFE7E7D6FFE5E5D4FFE4E4D3FFE2E2D1FFF6F6E8FF67674070007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF5299BCFFB3B3A3FFC0C0 + B1FFC3C3B2FFC2C2B1FFC0C0AFFFBEBEADFFF3F3E3FF6C6C446E007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF569CBFFFCFCFC0FFCECE + BEFFE4E4D3FFF0F0E6FFEBEBDDFFE7E7D6FFF2F2E1FF7171486C007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF589FC2FFAFAFA0FFBDBD + AEFFC8C8B7FFEBEBDDFFA4A493FFA4A493FFA4A493FF4949257C0082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF62A8C9FFDBDBD4FFD8D8 + CFFFEBEBDDFFE7E7D6FFB6B6A5FFFFFFFFFF79795069797950250084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF6DAFCDFFEDEDE4FFF4F4 + E7FFF4F4E3FFF2F2E1FFC2C2B1FF467F85B87C7C5225797950000085C8000085 + C8000085C885ADF1FFFFABEFFEFF94E2F8FF6EC8EDFF4397B9FF8EB7BAFF8EB7 + BAFF8EB7BAFF8EB7BAFF93BCBBFF1B84B0963E818E003D7F8C000087CA000087 + CA000087CA8388DBF4FF60C1E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + NumGlyphs = 1 + Anchors = [akTop, akLeft, akRight] + MaxLength = 0 + TabOrder = 1 + end + object btClearLogFile: TBitBtn + AnchorSideLeft.Control = edLogFileName + AnchorSideTop.Control = edLogFileName + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 26 + Top = 73 + Width = 112 + AutoSize = True + Caption = 'Clear log file' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + TabOrder = 2 + end + object lbLogFileName: TLabel + AnchorSideLeft.Control = ckEnableLogging + AnchorSideTop.Control = ckEnableLogging + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 15 + Top = 27 + Width = 42 + Caption = 'Log file:' + ParentColor = False + end + object btOpenLog: TBitBtn + AnchorSideLeft.Control = ckEnableLogging + AnchorSideTop.Control = btClearLogFile + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 26 + Top = 103 + Width = 95 + AutoSize = True + Caption = 'Open log' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A00000016000000090D0D0D671010 + 1085101010851010108510101085101010851010108510101085101010851010 + 108510101085101010851010108510101085101010850D0D0D672727277BEBEB + EBFFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7 + E7FFE7E7E7FFE7E7E7FFE7E7E7FFE7E7E7FFEBEBEBFF2727277B32323276EAEA + EAFF777777FFE2E2E2FFACACACFFC5C5C5FFACACACFFBDBDBDFFBDBDBDFFBDBD + BDFFB4B4B4FFBDBDBDFFE2E2E2FFE2E2E2FFEAEAEAFF3232327638383873EDED + EDFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 + E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFEDEDEDFF383838733E3E3E71F0F0 + F0FFFF9966FFEBEBEBFFC2C2C2FFB1B1B1FFC2C2C2FFC2C2C2FFB1B1B1FFC2C2 + C2FFCECECEFFEBEBEBFFEBEBEBFFEBEBEBFFF0F0F0FF3E3E3E714444446EF3F3 + F3FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEF + EFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFF3F3F3FF4444446E4949496CF7F7 + F7FF6E71C2FFF4F4F4FFB6B6B6FFC7C7C7FFC7C7C7FFC7C7C7FFBFBFBFFFC7C7 + C7FFBFBFBFFFC7C7C7FFC7C7C7FFD0D0D0FFF7F7F7FF4949496C4D4D4D6AFAFA + FAFFF8F8F8FFF8F8F8FFF8F8F8FFF8F8F8FFF8F8F8FFF8F8F8FFF8F8F8FFF8F8 + F8FFF8F8F8FFF8F8F8FFF8F8F8FFF8F8F8FFFAFAFAFF4D4D4D6A51515168FDFD + FDFF22AA33FFFCFCFCFFC3C3C3FFCCCCCCFFCCCCCCFFCCCCCCFFBBBBBBFFCCCC + CCFFE4E4E4FFFCFCFCFFFCFCFCFFFCFCFCFFFDFDFDFF5151516855555567FFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5555556750505069BBBB + BBFFBABABAFFB8B8B8FFB6B6B6FFB3B3B3FFB0B0B0FFAEAEAEFFABABABFFA8A8 + A8FFA6A6A6FFA3A3A3FFA0A0A0FF9E9E9EFF9C9C9CFF030303665252525BC6C6 + C6D4DCDCDCFFD8D9D9FFD5D5D5FFD0D1D1FFCCCCCCFFC8C8C8FFC6C6C6FFC6C5 + C5FFC9C5C5FFCDC6C6FFD1C7C7FFD7CBCBFFC4B8B8D45252525B555555225555 + 5559555555665555556655555566555555665555556655555566555555665555 + 5566555555665555556655555566555555665555555955555522FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOpenLogClick + TabOrder = 3 + end + end + end end end object btOptionApply: TBitBtn Left = 8 Height = 45 - Top = 434 + Top = 426 Width = 125 Anchors = [akLeft, akBottom] AutoSize = True @@ -3672,12 +3868,12 @@ object MainForm: TMainForm Caption = 'About' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 - ClientHeight = 511 - ClientWidth = 525 + ClientHeight = 484 + ClientWidth = 558 object btCheckLatestVersion: TBitBtn Left = 25 Height = 40 - Top = 460 + Top = 433 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Check for latest version' @@ -3723,7 +3919,7 @@ object MainForm: TMainForm object btAbortCheckLatestVersion: TSpeedButton Left = 193 Height = 40 - Top = 460 + Top = 433 Width = 40 Anchors = [akLeft, akBottom] Glyph.Data = { @@ -3768,7 +3964,7 @@ object MainForm: TMainForm object btVisitMyBlog: TBitBtn Left = 249 Height = 40 - Top = 460 + Top = 433 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Visit my blog' @@ -3813,9 +4009,9 @@ object MainForm: TMainForm end object pcAbout: TPageControl Left = 4 - Height = 441 + Height = 414 Top = 8 - Width = 517 + Width = 550 ActivePage = tsAboutText Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] @@ -3823,13 +4019,13 @@ object MainForm: TMainForm TabOrder = 2 object tsAboutText: TTabSheet Caption = 'About FMD' - ClientHeight = 413 - ClientWidth = 509 + ClientHeight = 386 + ClientWidth = 542 object rmAbout: TRichMemo Left = 2 - Height = 407 + Height = 380 Top = 4 - Width = 503 + Width = 536 Align = alClient BorderSpacing.Top = 2 BorderSpacing.Right = 2 @@ -3873,18 +4069,18 @@ object MainForm: TMainForm end end object pnMainTop: TPanel - Left = 0 + Left = 4 Height = 8 - Top = 0 - Width = 771 + Top = 4 + Width = 763 Align = alTop TabOrder = 1 Visible = False end object pcLeft: TPageControl Left = 4 - Height = 518 - Top = 12 + Height = 510 + Top = 16 Width = 195 ActivePage = tsMangaList Align = alLeft @@ -3900,7 +4096,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 490 + ClientHeight = 482 ClientWidth = 187 object vtMangaList: TVirtualStringTree AnchorSideLeft.Control = lbMode @@ -3909,7 +4105,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btRemoveFilter AnchorSideRight.Side = asrBottom Left = 4 - Height = 401 + Height = 393 Top = 85 Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] @@ -4085,37 +4281,37 @@ object MainForm: TMainForm Width = 25 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } @@ -4212,10 +4408,10 @@ object MainForm: TMainForm end end object sbMain: TStatusBar - Left = 0 + Left = 4 Height = 23 - Top = 534 - Width = 771 + Top = 530 + Width = 763 Panels = < item Width = 195 @@ -4228,8 +4424,8 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 526 - Top = 8 + Height = 518 + Top = 12 Width = 2 OnMoved = spMainSplitterMoved end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index d3ce10e0d..a49863a37 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -219,6 +219,12 @@ {"hash":197676484,"name":"tmainform.tswebsiteadvanced.caption","sourcebytes":[65,100,118,97,110,99,101,100],"value":"Advanced"}, {"hash":161923523,"name":"tmainform.tsaccounts.caption","sourcebytes":[65,99,99,111,117,110,116,115],"value":"Accounts"}, {"hash":344211,"name":"tmainform.tsmisc.caption","sourcebytes":[77,105,115,99],"value":"Misc"}, +{"hash":197593650,"name":"tmainform.tscustomcolor.caption","sourcebytes":[67,117,115,116,111,109,32,99,111,108,111,114],"value":"Custom color"}, +{"hash":21335,"name":"tmainform.tslog.caption","sourcebytes":[76,111,103],"value":"Log"}, +{"hash":119864823,"name":"tmainform.ckenablelogging.caption","sourcebytes":[69,110,97,98,108,101,32,108,111,103,103,105,110,103],"value":"Enable logging"}, +{"hash":120491445,"name":"tmainform.btclearlogfile.caption","sourcebytes":[67,108,101,97,114,32,108,111,103,32,102,105,108,101],"value":"Clear log file"}, +{"hash":158118362,"name":"tmainform.lblogfilename.caption","sourcebytes":[76,111,103,32,102,105,108,101,58],"value":"Log file:"}, +{"hash":113276983,"name":"tmainform.btopenlog.caption","sourcebytes":[79,112,101,110,32,108,111,103],"value":"Open log"}, {"hash":4749113,"name":"tmainform.btoptionapply.caption","sourcebytes":[65,112,112,108,121],"value":"Apply"}, {"hash":4691652,"name":"tmainform.tsabout.caption","sourcebytes":[65,98,111,117,116],"value":"About"}, {"hash":101464798,"name":"tmainform.btchecklatestversion.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,108,97,116,101,115,116,32,118,101,114,115,105,111,110],"value":"Check for latest version"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f89d6f3d7..c337d2d84 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -18,13 +18,13 @@ interface {$endif} Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, - types, strutils, LCLIntf, DefaultTranslator, EditBtn, FileUtil, LazUTF8Classes, TAGraph, - TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, - uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, - uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, - frmWebsiteOptionAdvanced, frmCustomColor, CheckUpdate, accountmanagerdb, DBDataProcess, - MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, SimpleException, - SimpleLogger; + types, strutils, LCLIntf, DefaultTranslator, EditBtn, MultiLog, FileChannel, FileUtil, + LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, + uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, + uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, + frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, CheckUpdate, accountmanagerdb, + DBDataProcess, MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, + SimpleException; type @@ -32,6 +32,8 @@ interface TMainForm = class(TForm) appPropertiesMain: TApplicationProperties; + btOpenLog: TBitBtn; + btClearLogFile: TBitBtn; btAddToFavorites: TBitBtn; btCancelFavoritesCheck: TSpeedButton; btAbortCheckLatestVersion: TSpeedButton; @@ -64,6 +66,7 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + ckEnableLogging: TCheckBox; edDownloadsSearch: TEdit; edFilterMangaInfoChapters: TEditButton; edFavoritesSearch: TEdit; @@ -72,6 +75,8 @@ TMainForm = class(TForm) edOptionMangaCustomRename: TEdit; edSaveTo: TDirectoryEdit; edURL: TEditButton; + edLogFileName: TFileNameEdit; + lbLogFileName: TLabel; lbOptionFilenameCustomRenameHint: TLabel; lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; @@ -100,6 +105,7 @@ TMainForm = class(TForm) miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; + pcMisc: TPageControl; pcWebsiteOptions: TPageControl; Panel1: TPanel; Panel2: TPanel; @@ -112,6 +118,8 @@ TMainForm = class(TForm) sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; btFavoritesSearchClear: TSpeedButton; + tsCustomColor: TTabSheet; + tsLog: TTabSheet; tmAnimateMangaInfo: TTimer; tmBackup: TTimer; tmCheckFavorites: TTimer; @@ -383,6 +391,7 @@ TMainForm = class(TForm) procedure btDownloadsSearchClearClick(Sender: TObject); procedure btFavoritesSearchClearClick(Sender: TObject); procedure btFavoritesImportClick(Sender: TObject); + procedure btOpenLogClick(Sender: TObject); procedure btReadOnlineClick(Sender: TObject); procedure btMangaListSearchClearClick(Sender: TObject); procedure btUpdateListClick(Sender: TObject); @@ -863,6 +872,9 @@ implementation // ... UpdateStatusTextStyle: TTextStyle; + // file logger + FileLogger: TFileChannel; + {$ifdef windows} PrevWndProc: windows.WNDPROC; @@ -1051,12 +1063,8 @@ procedure TMainForm.FormCreate(Sender: TObject); PrevWndProc := windows.WNDPROC(windows.GetWindowLongPtr(Self.Handle, GWL_WNDPROC)); windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)); {$endif} - SetLogFile(Format('%s\%s_LOG_%s.txt', ['log', ExtractFileNameOnly(ParamStrUTF8(0)), - FormatDateTime('dd-mm-yyyy', Now)])); - Writelog_I(['Starting ',QuotedStrd(Application.Title),' [PID:',GetProcessID,'] [HANDLE:',IntToStr(GetCurrentProcess),']']); + Logger.Enabled := False; InitSimpleExceptionHandler; - AddIgnoredException('EImagingError'); - AddIgnoredException('ERegExpr'); btAbortUpdateList.Parent := sbUpdateList; isRunDownloadFilter := False; isUpdating := False; @@ -1193,7 +1201,7 @@ procedure TMainForm.FormCreate(Sender: TObject); CustomColorForm := TCustomColorForm.Create(Self); with CustomColorForm do begin - Parent := tsMisc; + Parent := tsCustomColor; BorderStyle := bsNone; Align := alClient; Show; @@ -1210,6 +1218,9 @@ procedure TMainForm.FormCreate(Sender: TObject); AddVT(WebsiteOptionAdvancedForm.vtUpdateListNumberOfThreads); end; + // logger + FormLogger := TFormLogger.Create(Self); + // load mangafox template MangaFoxWatermark.SetTemplateDirectory(MANGAFOXTEMPLATE_FOLDER); @@ -1223,12 +1234,12 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin - Writelog_D(Self.ClassName+'.FormClose action'); + Logger.Send(Self.ClassName+'.FormClose'); if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then begin - Writelog_D(Self.ClassName+'.FormClose aborted'); + Logger.Send(Self.ClassName+'.FormClose aborted!'); CloseAction := caNone; Exit; end; @@ -1243,56 +1254,56 @@ procedure TMainForm.CloseNow; if Assigned(PrevWndProc) then windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(PrevWndProc)); {$endif} - Writelog_D(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); + Logger.Send(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); FavoriteManager.StopChekForNewChapter(True); SilentThreadManager.StopAll(True); DLManager.StopAllDownloadTasksForExit; //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin - Writelog_D(Self.ClassName+'.CloseNow, terminating CheckUpdateThread'); + Logger.Send(Self.ClassName+'.CloseNow, terminating CheckUpdateThread'); CheckUpdateThread.Terminate; CheckUpdateThread.WaitFor; - Writelog_D(Self.ClassName+'.CloseNow, CheckUpdateThread terminated'); + Logger.Send(Self.ClassName+'.CloseNow, CheckUpdateThread terminated'); end; if Assigned(SearchDBThread) then begin - Writelog_D(Self.ClassName+'.CloseNow, terminating SearchDBThread'); + Logger.Send(Self.ClassName+'.CloseNow, terminating SearchDBThread'); SearchDBThread.Terminate; SearchDBThread.WaitFor; - Writelog_D(Self.ClassName+'.CloseNow, SearchDBThread terminated'); + Logger.Send(Self.ClassName+'.CloseNow, SearchDBThread terminated'); end; if Assigned(OpenDBThread) then begin - Writelog_D(Self.ClassName+'.CloseNow, terminating OpenDBThread'); + Logger.Send(Self.ClassName+'.CloseNow, terminating OpenDBThread'); OpenDBThread.Terminate; OpenDBThread.WaitFor; - Writelog_D(Self.ClassName+'.CloseNow, OpenDBThread terminated'); + Logger.Send(Self.ClassName+'.CloseNow, OpenDBThread terminated'); end; if isGetMangaInfos then begin - Writelog_D(Self.ClassName+'.CloseNow, terminating GetInfosThread'); + Logger.Send(Self.ClassName+'.CloseNow, terminating GetInfosThread'); GetInfosThread.IsFlushed := True; GetInfosThread.Terminate; GetInfosThread.WaitFor; - Writelog_D(Self.ClassName+'.CloseNow, GetInfosThread terminated'); + Logger.Send(Self.ClassName+'.CloseNow, GetInfosThread terminated'); end; if isUpdating then begin - Writelog_D(Self.ClassName+'.CloseNow, terminating UpdateListThread'); + Logger.Send(Self.ClassName+'.CloseNow, terminating UpdateListThread'); updateList.Terminate; updateList.WaitFor; - Writelog_D(Self.ClassName+'.CloseNow, UpdateListThread terminated'); + Logger.Send(Self.ClassName+'.CloseNow, UpdateListThread terminated'); end; - Writelog_D(Self.ClassName+'.CloseNow, disabling all timer'); + Logger.Send(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; tmRefreshDownloadsInfo.Enabled := False; tmCheckFavorites.Enabled := False; tmAnimateMangaInfo.Enabled := False; tmExitCommand.Enabled := False; - Writelog_D(Self.ClassName+'.CloseNow, backup all data to file'); + Logger.Send(Self.ClassName+'.CloseNow, backup all data to file'); //Backup data DLManager.Backup; isExiting := True; @@ -1300,7 +1311,7 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; - Writelog_D(Self.ClassName+'.CloseNow, closing other forms'); + Logger.Send(Self.ClassName+'.CloseNow, closing other forms'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; @@ -1310,7 +1321,7 @@ procedure TMainForm.CloseNow; if FMDInstance <> nil then begin - Writelog_D(Self.ClassName+'.CloseNow, stop ipc server'); + Logger.Send(Self.ClassName+'.CloseNow, stop ipc server'); FMDInstance.StopServer; FreeAndNil(FMDInstance); end; @@ -1319,7 +1330,7 @@ procedure TMainForm.CloseNow; procedure TMainForm.FormDestroy(Sender: TObject); begin - Writelog_D(Self.ClassName+'.FormDestroy, freeing all objects'); + Logger.Send(Self.ClassName+'.FormDestroy, freeing all objects'); SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); @@ -1333,9 +1344,9 @@ procedure TMainForm.FormDestroy(Sender: TObject); FreeAndNil(mangaCover); if isNormalExit then - Writelog_I(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']') + Logger.Send(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']') else - Writelog_W(QuotedStrd(Application.Title)+' doesn''t exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); + Logger.SendWarning(QuotedStrd(Application.Title)+' doesn''t exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); end; procedure TMainForm.FormShow(Sender: TObject); @@ -2224,6 +2235,11 @@ procedure TMainForm.btFavoritesImportClick(Sender: TObject); end; end; +procedure TMainForm.btOpenLogClick(Sender: TObject); +begin + FormLogger.Show; +end; + procedure TMainForm.btChecksClick(Sender: TObject); begin if Sender is TControl then @@ -3400,6 +3416,7 @@ procedure TMainForm.tbDownloadDeleteCompletedClick(Sender: TObject); procedure TMainForm.tbDownloadResumeAllClick(Sender: TObject); begin + StrToInt('A'); DLManager.StartAllTasks; UpdateVtDownload; end; @@ -4473,6 +4490,10 @@ procedure TMainForm.LoadOptions; // misc frmCustomColor.LoadFromIniFile(configfile); + ckEnableLogging.Checked := ReadBool('logger', 'Enabled', False); + edLogFileName.Text := ReadString('logger', 'LogFileName', ''); + if edLogFileName.Text = '' then + edLogFileName.Text := ChangeFileExt(Application.ExeName, '.log'); // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4596,6 +4617,10 @@ procedure TMainForm.SaveOptions; // misc frmCustomColor.SaveToIniFile(configfile); + WriteBool('logger', 'Enabled', ckEnableLogging.Checked); + if edLogFileName.Text = '' then + edLogFileName.Text := ChangeFileExt(Application.ExeName, '.log'); + WriteString('logger', 'LogFileName', edLogFileName.Text); finally UpdateFile; end; @@ -4608,6 +4633,7 @@ procedure TMainForm.ApplyOptions; i: Integer; isStillHaveCurrentWebsite: Boolean = False; data: PSingleItem; + St: TStringList; begin try // general @@ -4714,6 +4740,27 @@ procedure TMainForm.ApplyOptions; //misc frmCustomColor.Apply; + SimpleException.SetLogFileName(edLogFileName.Text); + if ckEnableLogging.Checked and (not Logger.Enabled) then + begin + Logger.Enabled := True; + FileLogger := TFileChannel.Create(edLogFileName.Text, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); + Logger.Channels.Add(FileLogger); + St := TStringList.Create; + try + St.AddText(SimpleException.GetApplicationInfo); + Logger.Send('Application info', St); + finally + St.Free; + end; + end + else + if (not ckEnableLogging.Checked) and (Logger.Enabled) then + begin + Logger.Enabled := False; + Logger.Channels.Remove(FileLogger); + FreeAndNil(FileLogger); + end; //languages ApplyLanguage; @@ -5281,9 +5328,9 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); procedure TMainForm.DoExitWaitCounter; begin - Writelog_D(Self.ClassName+', Execute exit counter'); + Logger.Send(Self.ClassName+', Execute exit counter'); if isUpdating then begin - Writelog_D(Self.ClassName+', Update thread still exist, pending exit counter'); + Logger.Send(Self.ClassName+', Update thread still exist, pending exit counter'); isPendingExitCounter:=True end else tmExitCommand.Enabled:=True; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 3a530887d..92832c93e 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -444,6 +444,18 @@ msgctxt "tformdroptarget.midownloadall.caption" msgid "Download all" msgstr "Download all" +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "" + #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" msgid "Cancel" @@ -486,6 +498,10 @@ msgctxt "tmainform.btchecklatestversion.caption" msgid "Check for latest version" msgstr "Check for latest version" +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "" + #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" msgid "Download" @@ -509,6 +525,10 @@ msgstr "Filter" msgid "Reset value" msgstr "Reset value" +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "" + #: tmainform.btoptionapply.caption msgid "Apply" msgstr "Apply" @@ -664,6 +684,10 @@ msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" msgstr "Show Drop Box" +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "" + #: tmainform.ckfilteraction.caption msgid "Action" msgstr "Action" @@ -1174,6 +1198,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Title" +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "" + #: tmainform.lbmode.caption #| msgid "Mode: Show All (0)" msgid "Mode: Show all (0)" @@ -1681,6 +1709,10 @@ msgstr "Changelog" msgid "Connections" msgstr "Connections" +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "" + #: tmainform.tsdialogs.caption msgid "Dialogs" msgstr "Dialogs" @@ -1712,6 +1744,10 @@ msgstr "General" msgid "Manga Info" msgstr "Manga Info" +#: tmainform.tslog.caption +msgid "Log" +msgstr "" + #: tmainform.tsmangalist.caption msgid "Manga List" msgstr "Manga List" @@ -2131,3 +2167,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 63453bcfb..5b503b1c6 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -436,6 +436,18 @@ msgctxt "tformdroptarget.midownloadall.caption" msgid "Download all" msgstr "Unduh semua" +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "" + #: timportfavorites.btcancel.caption msgctxt "timportfavorites.btcancel.caption" msgid "Cancel" @@ -477,6 +489,10 @@ msgctxt "tmainform.btchecklatestversion.caption" msgid "Check for latest version" msgstr "Periksa versi terbaru" +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "" + #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" msgid "Download" @@ -500,6 +516,10 @@ msgstr "Saring" msgid "Reset value" msgstr "Atur Ulang" +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "" + #: tmainform.btoptionapply.caption msgid "Apply" msgstr "Terapkan" @@ -653,6 +673,10 @@ msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" msgstr "Tampilkan kotak unduh" +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "" + #: tmainform.ckfilteraction.caption msgid "Action" msgstr "Action" @@ -1159,6 +1183,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Judul" +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "" + #: tmainform.lbmode.caption msgid "Mode: Show all (0)" msgstr "Mode: Tampilkan semua (0)" @@ -1662,6 +1690,10 @@ msgstr "Catatan perubahan" msgid "Connections" msgstr "Koneksi" +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "" + #: tmainform.tsdialogs.caption msgid "Dialogs" msgstr "Dialog" @@ -1693,6 +1725,10 @@ msgstr "Umum" msgid "Manga Info" msgstr "Informasi Komik" +#: tmainform.tslog.caption +msgid "Log" +msgstr "" + #: tmainform.tsmangalist.caption msgid "Manga List" msgstr "Daftar Komik" @@ -2112,3 +2148,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index d2ec57ca8..c58d16e24 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -401,6 +401,18 @@ msgctxt "TFORMDROPTARGET.MIDOWNLOADALL.CAPTION" msgid "Download all" msgstr "" +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "" + #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" msgid "Cancel" @@ -442,6 +454,10 @@ msgctxt "TMAINFORM.BTCHECKLATESTVERSION.CAPTION" msgid "Check for latest version" msgstr "" +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "" + #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" msgid "Download" @@ -465,6 +481,10 @@ msgstr "" msgid "Reset value" msgstr "" +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "" + #: tmainform.btoptionapply.caption msgid "Apply" msgstr "" @@ -618,6 +638,10 @@ msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" msgstr "" +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "" + #: tmainform.ckfilteraction.caption msgid "Action" msgstr "" @@ -1113,6 +1137,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "" +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "" + #: tmainform.lbmode.caption msgid "Mode: Show all (0)" msgstr "" @@ -1593,6 +1621,10 @@ msgstr "" msgid "Connections" msgstr "" +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "" + #: tmainform.tsdialogs.caption msgid "Dialogs" msgstr "" @@ -1624,6 +1656,10 @@ msgstr "" msgid "Manga Info" msgstr "" +#: tmainform.tslog.caption +msgid "Log" +msgstr "" + #: tmainform.tsmangalist.caption msgid "Manga List" msgstr "" diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 9c6045f36..f1964b30f 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -12,8 +12,8 @@ cthreads, {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, - frmMain; + Forms, multiloglaz, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, + uBaseUnit, frmMain, frmLogger; var CheckInstance: Boolean = True; From ebc076b5b9ef15d8b4044feb5153969abcc9bd5a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:16:43 +0800 Subject: [PATCH 1341/2794] button delete log file --- mangadownloader/forms/frmMain.lfm | 17 +++++++++-------- mangadownloader/forms/frmMain.pas | 13 +++++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 2f62d67db..be85806e8 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -38,13 +38,13 @@ object MainForm: TMainForm Height = 512 Top = 15 Width = 566 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -53,13 +53,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 object vtDownload: TVirtualStringTree AnchorSideTop.Control = edDownloadsSearch AnchorSideTop.Side = asrBottom Left = 4 - Height = 456 + Height = 448 Top = 31 Width = 549 Anchors = [akTop, akLeft, akRight, akBottom] @@ -2141,10 +2141,10 @@ object MainForm: TMainForm Height = 407 Top = 8 Width = 539 - ActivePage = tsMisc + ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 8 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -3625,9 +3625,9 @@ object MainForm: TMainForm Height = 363 Top = 8 Width = 523 - ActivePage = tsLog + ActivePage = tsCustomColor Align = alClient - TabIndex = 1 + TabIndex = 0 TabOrder = 0 object tsCustomColor: TTabSheet Caption = 'Custom color' @@ -3748,6 +3748,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } + OnClick = btClearLogFileClick TabOrder = 2 end object lbLogFileName: TLabel diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c337d2d84..8810a3a48 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -387,6 +387,7 @@ TMainForm = class(TForm) procedure btCancelFavoritesCheckClick(Sender: TObject); procedure btChecksClick(Sender: TObject); procedure btCheckLatestVersionClick(Sender: TObject); + procedure btClearLogFileClick(Sender: TObject); procedure btDonateClick(Sender: TObject); procedure btDownloadsSearchClearClick(Sender: TObject); procedure btFavoritesSearchClearClick(Sender: TObject); @@ -2211,6 +2212,18 @@ procedure TMainForm.btCheckLatestVersionClick(Sender: TObject); CheckUpdateThread := TCheckUpdateThread.Create; end; +procedure TMainForm.btClearLogFileClick(Sender: TObject); +var + F: TextFile; +begin + if FileExistsUTF8(edLogFileName.Text) then + begin + system.Assign(F, edLogFileName.Text); + Rewrite(F); + CloseFile(F); + end; +end; + procedure TMainForm.btDonateClick(Sender: TObject); begin OpenURL('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=akarin.km@gmail.com&item_name=Donation+to+Free+Manga+Downloader'); From c9f4ed97ce2786ea94a47c207887815c48791cf6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:19:33 +0800 Subject: [PATCH 1342/2794] buttons, replace x icon for clear with broom --- mangadownloader/forms/frmMain.lfm | 230 +++++++++++++++--------------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index be85806e8..094578f24 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -822,37 +822,37 @@ object MainForm: TMainForm ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } @@ -870,18 +870,18 @@ object MainForm: TMainForm end object tsFilter: TTabSheet Caption = 'Filter' - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 object sbFilter: TScrollBox Left = 0 - Height = 492 + Height = 484 Top = 0 Width = 558 HorzScrollBar.Page = 488 VertScrollBar.Page = 416 Align = alClient BorderStyle = bsNone - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 TabOrder = 0 object pnCustomGenre: TPanel @@ -1867,13 +1867,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 492 + ClientHeight = 484 ClientWidth = 558 object vtFavorites: TVirtualStringTree AnchorSideTop.Control = edFavoritesSearch AnchorSideTop.Side = asrBottom Left = 4 - Height = 374 + Height = 366 Top = 31 Width = 549 Anchors = [akTop, akLeft, akRight, akBottom] @@ -1938,7 +1938,7 @@ object MainForm: TMainForm object btFavoritesImport: TBitBtn Left = 33 Height = 24 - Top = 458 + Top = 450 Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Import list' @@ -1985,7 +1985,7 @@ object MainForm: TMainForm object btCancelFavoritesCheck: TSpeedButton Left = 490 Height = 40 - Top = 412 + Top = 404 Width = 34 Anchors = [akRight, akBottom] Glyph.Data = { @@ -2030,7 +2030,7 @@ object MainForm: TMainForm object btFavoritesCheckNewChapter: TBitBtn Left = 33 Height = 40 - Top = 412 + Top = 404 Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Check for new chapter' @@ -2095,37 +2095,37 @@ object MainForm: TMainForm Anchors = [akTop, akLeft, akBottom] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } @@ -2397,7 +2397,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 object cbOptionShowDownloadToolbar: TCheckBox Left = 4 @@ -2503,11 +2503,11 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 object sbDownloadConnections: TScrollBox Left = 0 - Height = 387 + Height = 379 Top = 0 Width = 531 HorzScrollBar.Page = 455 @@ -2518,7 +2518,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 TabOrder = 0 object cbOptionUseProxy: TCheckBox @@ -2792,22 +2792,22 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 338 + ClientHeight = 379 ClientWidth = 531 object sbSaveTo: TScrollBox Left = 0 - Height = 338 + Height = 379 Top = 0 Width = 531 HorzScrollBar.Page = 198 - VertScrollBar.Page = 338 + VertScrollBar.Page = 379 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 338 + ClientHeight = 379 ClientWidth = 514 TabOrder = 0 object rgOptionCompress: TRadioGroup @@ -3237,7 +3237,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 4 @@ -3364,7 +3364,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 object gbDialogs: TGroupBox Left = 4 @@ -3419,11 +3419,11 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 + ClientHeight = 379 ClientWidth = 531 object pcWebsiteOptions: TPageControl Left = 4 - Height = 371 + Height = 363 Top = 8 Width = 523 ActivePage = tsWebsiteSelection @@ -3432,11 +3432,11 @@ object MainForm: TMainForm TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' - ClientHeight = 343 + ClientHeight = 335 ClientWidth = 515 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 0 - Height = 308 + Height = 300 Top = 35 Width = 515 Align = alClient @@ -3498,37 +3498,37 @@ object MainForm: TMainForm Align = alLeft Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A0000001600000009000000120000 - 0E3300004A8300005DBC00005DCC00005DCC00005DCC00005DCC00005DCC0000 - 5DCC00005DCC00005DCC00005DBC00004A8300000E330000001200001D000000 - 6D73080893DD1010CCF91111D9FF1111D9FF1111D9FF1111D9FF1111D9FF1111 - D9FF1111D9FF1111D9FF0F0FCCF9070792DD00006D7300001D0000007D000000 - 7DBA1616CBF91111D1FF1111D1FF1111B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF1111D1FF1111D1FF0F0FC8F900007DBA00007D00000084000000 - 84CC1C1CCEFF1111C8FF1111B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF1111C8FF1111C8FF000084CC00008400000089000000 - 89CC2222C8FF1111BEFFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF1212BEFF000089CC0000890000008D000000 - 8DCC3434C7FF1212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1414B6FF00008DCC00008D00000092000000 - 92CC4646CEFF2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818B0FF000092CC00009200000096000000 - 96CC4A4AD2FF3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFF000096CC0000960000009A000000 - 9ACC5050D8FF3737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2B2BB5FF00009ACC00009A0000009E000000 - 9ECC5A5AE2FF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4242CAFF4E4ED6FF00009ECC00009E000000A2000000 - A2CC6262EAFF4F4FD7FF4F4FD7FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF4F4FD7FF4F4FD7FF5A5AE2FF0000A2CC0000A2000000A5000000 - A5BA6060ECF95B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE7F90000A5BA0000A5000000A8000000 - A8732A2AC7DD6363EFF96D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6DF5FF6D6D - F5FF6D6DF5FF6C6CF4FF6262EEF92929C5DD0000A8730000A8000000A8000000 - A90C0000AA730000AABA0000AACC0000AACC0000AACC0000AACC0000AACC0000 - AACC0000AACC0000AACC0000AABA0000AA730000A90C0000A800FFFFFF00FFFF + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } From 2d0280d97f8e8f7091e9441559f6df081c148f68 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:21:04 +0800 Subject: [PATCH 1343/2794] update translations --- mangadownloader/languages/fmd.en.po | 19 +++++++++---------- mangadownloader/languages/fmd.id_ID.po | 19 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 92832c93e..7d02f8691 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -446,15 +446,15 @@ msgstr "Download all" #: tformlogger.btnclearlog.caption msgid "Clear" -msgstr "" +msgstr "Clear" #: tformlogger.ckstayontop.caption msgid "Stay on top" -msgstr "" +msgstr "Stay on top" #: tformlogger.lbloglimit.caption msgid "Log limit" -msgstr "" +msgstr "Log limit" #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" @@ -500,7 +500,7 @@ msgstr "Check for latest version" #: tmainform.btclearlogfile.caption msgid "Clear log file" -msgstr "" +msgstr "Clear log file" #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" @@ -527,7 +527,7 @@ msgstr "Reset value" #: tmainform.btopenlog.caption msgid "Open log" -msgstr "" +msgstr "Open log" #: tmainform.btoptionapply.caption msgid "Apply" @@ -686,7 +686,7 @@ msgstr "Show Drop Box" #: tmainform.ckenablelogging.caption msgid "Enable logging" -msgstr "" +msgstr "Enable logging" #: tmainform.ckfilteraction.caption msgid "Action" @@ -1200,7 +1200,7 @@ msgstr "Title" #: tmainform.lblogfilename.caption msgid "Log file:" -msgstr "" +msgstr "Log file:" #: tmainform.lbmode.caption #| msgid "Mode: Show All (0)" @@ -1711,7 +1711,7 @@ msgstr "Connections" #: tmainform.tscustomcolor.caption msgid "Custom color" -msgstr "" +msgstr "Custom color" #: tmainform.tsdialogs.caption msgid "Dialogs" @@ -1746,7 +1746,7 @@ msgstr "Manga Info" #: tmainform.tslog.caption msgid "Log" -msgstr "" +msgstr "Log" #: tmainform.tsmangalist.caption msgid "Manga List" @@ -2167,4 +2167,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 5b503b1c6..78beeb10e 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -438,15 +438,15 @@ msgstr "Unduh semua" #: tformlogger.btnclearlog.caption msgid "Clear" -msgstr "" +msgstr "Bersihkan" #: tformlogger.ckstayontop.caption msgid "Stay on top" -msgstr "" +msgstr "Tetap di atas" #: tformlogger.lbloglimit.caption msgid "Log limit" -msgstr "" +msgstr "Batasi log" #: timportfavorites.btcancel.caption msgctxt "timportfavorites.btcancel.caption" @@ -491,7 +491,7 @@ msgstr "Periksa versi terbaru" #: tmainform.btclearlogfile.caption msgid "Clear log file" -msgstr "" +msgstr "Bersihkan berkas log" #: tmainform.btdownload.caption msgctxt "tmainform.btdownload.caption" @@ -518,7 +518,7 @@ msgstr "Atur Ulang" #: tmainform.btopenlog.caption msgid "Open log" -msgstr "" +msgstr "Buka log" #: tmainform.btoptionapply.caption msgid "Apply" @@ -675,7 +675,7 @@ msgstr "Tampilkan kotak unduh" #: tmainform.ckenablelogging.caption msgid "Enable logging" -msgstr "" +msgstr "Aktifkan logging" #: tmainform.ckfilteraction.caption msgid "Action" @@ -1185,7 +1185,7 @@ msgstr "Judul" #: tmainform.lblogfilename.caption msgid "Log file:" -msgstr "" +msgstr "Berkas log:" #: tmainform.lbmode.caption msgid "Mode: Show all (0)" @@ -1692,7 +1692,7 @@ msgstr "Koneksi" #: tmainform.tscustomcolor.caption msgid "Custom color" -msgstr "" +msgstr "Kustomisasi warna" #: tmainform.tsdialogs.caption msgid "Dialogs" @@ -1727,7 +1727,7 @@ msgstr "Informasi Komik" #: tmainform.tslog.caption msgid "Log" -msgstr "" +msgstr "Log" #: tmainform.tsmangalist.caption msgid "Manga List" @@ -2148,4 +2148,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - From 6f1e036532eebf16070b18ab6f750477fe0fa499 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:29:49 +0800 Subject: [PATCH 1344/2794] added triplesevenscan closed #339 --- baseunits/modules/FoOlSlide.pas | 4 +++- config/mangalist.ini | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 117fb18eb..9f20269db 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -38,7 +38,8 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; function GetDirURL(const AWebsite: String): String; begin if (AWebsite = 'YoManga') or - (AWebsite = 'GoManga') then + (AWebsite = 'GoManga') or + (AWebsite = 'TripleSevenScan') then Result := dirurlreader else if AWebsite = 'OneTimeScans' then @@ -273,6 +274,7 @@ procedure RegisterModule; AddWebsiteModule('SeinagiFansub', 'http://seinagi.org'); AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org'); AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net'); + AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index e268d02f7..89d8d4a56 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaJoy,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From 5a71053c778aa1ab78c2feec37b617c5b625fd36 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:34:28 +0800 Subject: [PATCH 1345/2794] added log at enabled --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 1 + 2 files changed, 2 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 094578f24..7d1e18fca 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -15,6 +15,7 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 4 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8810a3a48..bd7c413ae 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4759,6 +4759,7 @@ procedure TMainForm.ApplyOptions; Logger.Enabled := True; FileLogger := TFileChannel.Create(edLogFileName.Text, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); Logger.Channels.Add(FileLogger); + Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); St := TStringList.Create; try St.AddText(SimpleException.GetApplicationInfo); From cf04a0229fb6f35df01188bfe959fddd7b8e772f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 18:44:20 +0800 Subject: [PATCH 1346/2794] remove date in readme --- readme.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/readme.txt b/readme.txt index d87b51dcc..25dc152b6 100644 --- a/readme.txt +++ b/readme.txt @@ -35,5 +35,3 @@ After everything is installed, open the file md.lpi by using Lazarus IDE, select Translations are stored inside "languages" folder with .po extension. In order to translate FMD to your native languages you can copy "fmd.po" and rename it to "fmd.xx.po", where xx stand for two-letter language code. Additionally you can add country code at the end of language code. For reference you can look at http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes and http://en.wikipedia.org/wiki/ISO_3166-1. For example "id_ID" will be recognized as "Bahasa Indonesia (Indonesia)". To translate the content of the file you need to use translation tools like Poedit. Once you have finished translating all of its content you can launch FMD and it will automatically detect your new languages upon startup. --------------------------------- - -Last update 27-01-2016 From 3638ac0330d6205257fa721d0203a3b12846ee0a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 20:23:17 +0800 Subject: [PATCH 1347/2794] simpleexception, ignore if res not found --- baseunits/SimpleException/SimpleException.pas | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 2231fa267..7da628df9 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -502,11 +502,14 @@ constructor TSimpleException.Create(const FileName: String); FileName := ParamStrUTF8(0); if FileName = '' then FileName := Application.ExeName; - Enabled := True; - if VersionStrings.Count <> 0 then - begin - AFileVersion := VersionStrings.Values['fileversion']; - AProductVersion := VersionStrings.Values['productversion']; + try + Enabled := True; + if VersionStrings.Count <> 0 then + begin + AFileVersion := VersionStrings.Values['fileversion']; + AProductVersion := VersionStrings.Values['productversion']; + end; + except end; finally Free; From 7efdb95d109d3374f83957d864bada7a0fe0f979 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 21:56:55 +0800 Subject: [PATCH 1348/2794] removed test code --- mangadownloader/forms/frmMain.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bd7c413ae..5b0ab3f8e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3429,7 +3429,6 @@ procedure TMainForm.tbDownloadDeleteCompletedClick(Sender: TObject); procedure TMainForm.tbDownloadResumeAllClick(Sender: TObject); begin - StrToInt('A'); DLManager.StartAllTasks; UpdateVtDownload; end; From 2034f0602f3f9d13045c52a61574e5bd473dab45 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 21:58:41 +0800 Subject: [PATCH 1349/2794] fixed mangafox remove watermark fixed #337 --- baseunits/extras/MangaFoxWatermark.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/extras/MangaFoxWatermark.pas b/baseunits/extras/MangaFoxWatermark.pas index 6a2e94410..9c71b47d8 100644 --- a/baseunits/extras/MangaFoxWatermark.pas +++ b/baseunits/extras/MangaFoxWatermark.pas @@ -228,7 +228,7 @@ procedure BuildImageToOneBit(const Image: TFPCustomImage; if ML > 0 then begin Inc(Bit, ML); - ML := (ML * 2) + 1; + ML := ML + (R - Image.Width - ML); end; for Y := T to B - 1 do begin @@ -436,7 +436,7 @@ function TWatermarkRemover.RemoveWatermark(const FileName: String; Bit := TIMG.Bits; end; finally - Freemem(TIMG.Bits); + FreeMemAndNil(TIMG.Bits); end; end; if (BestValue >= MinPSNR) and (BestIndex <> -1) then From 655f13bdee5af075d07c95820ad132a7f9b93fae Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 22:23:48 +0800 Subject: [PATCH 1350/2794] mainform, clear selection after delete task --- mangadownloader/forms/frmMain.pas | 77 +++++++++++++++---------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5b0ab3f8e..87f8a99b9 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1697,54 +1697,53 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); Exit; EnterCriticalSection(DLManager.CS_Task); try - xNode := vtDownload.GetLast(); + xNode := vtDownload.GetPreviousSelected(nil); while Assigned(xNode) do begin - if vtDownload.Selected[xNode] then begin - DLManager.StopTask(xNode^.Index, False, True); - with DLManager.Items[xNode^.Index] do begin - if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) - and (ChapterName.Count > 0) then begin - for i := 0 to ChapterName.Count - 1 do begin - f := CleanAndExpandDirectory(DownloadInfo.SaveTo + ChapterName[i]); - if FileExistsUTF8(f + '.zip') then - DeleteFileUTF8(f + '.zip') - else if FileExistsUTF8(f + '.cbz') then - DeleteFileUTF8(f + '.cbz') - else if FileExistsUTF8(f + '.pdf') then - DeleteFileUTF8(f + '.pdf') - else if DirectoryExistsUTF8(f) then - DeleteDirectory(f, False); - end; - RemoveDirUTF8(DownloadInfo.SaveTo); + DLManager.StopTask(xNode^.Index, False, True); + with DLManager.Items[xNode^.Index] do begin + if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) + and (ChapterName.Count > 0) then begin + for i := 0 to ChapterName.Count - 1 do begin + f := CleanAndExpandDirectory(DownloadInfo.SaveTo + ChapterName[i]); + if FileExistsUTF8(f + '.zip') then + DeleteFileUTF8(f + '.zip') + else if FileExistsUTF8(f + '.cbz') then + DeleteFileUTF8(f + '.cbz') + else if FileExistsUTF8(f + '.pdf') then + DeleteFileUTF8(f + '.pdf') + else if DirectoryExistsUTF8(f) then + DeleteDirectory(f, False); end; - if (Sender = miDownloadDeleteTaskDataFavorite) and - (FavoriteManager.Items.Count <> 0) and - (FavoriteManager.isRunning = False) then - try - FavoriteManager.Lock; - for i := 0 to FavoriteManager.Count - 1 do - begin - if SameText(DLManager[xNode^.Index].DownloadInfo.Link, FavoriteManager[i].FavoriteInfo.Link) - and SameText(DLManager[xNode^.Index].DownloadInfo.Website, FavoriteManager[i].FavoriteInfo.Website) then - begin - FavoriteManager.Items[i].Free; - FavoriteManager.Items.Delete(i); - UpdateVtFavorites; - Break; - end; - end; - finally - FavoriteManager.LockRelease; - end; - DLManager.Items[xNode^.Index].Free; - DLManager.Items.Delete(xNode^.Index); + RemoveDirUTF8(DownloadInfo.SaveTo); end; + if (Sender = miDownloadDeleteTaskDataFavorite) and + (FavoriteManager.Items.Count <> 0) and + (FavoriteManager.isRunning = False) then + try + FavoriteManager.Lock; + for i := 0 to FavoriteManager.Count - 1 do + begin + if SameText(DLManager[xNode^.Index].DownloadInfo.Link, FavoriteManager[i].FavoriteInfo.Link) + and SameText(DLManager[xNode^.Index].DownloadInfo.Website, FavoriteManager[i].FavoriteInfo.Website) then + begin + FavoriteManager.Items[i].Free; + FavoriteManager.Items.Delete(i); + UpdateVtFavorites; + Break; + end; + end; + finally + FavoriteManager.LockRelease; + end; + DLManager.Items[xNode^.Index].Free; + DLManager.Items.Delete(xNode^.Index); end; xNode := vtDownload.GetPreviousSelected(xNode); end; finally LeaveCriticalSection(DLManager.CS_Task); end; + vtDownload.ClearSelection; DLManager.CheckAndActiveTask; UpdateVtDownload; end; From cc393119be8513eb260a6f7fe1038834f08a3a79 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 23:53:25 +0800 Subject: [PATCH 1351/2794] ehentai, break load subpage if thread terminate --- baseunits/modules/EHentai.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 03ee116fe..7f02fa35f 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -286,8 +286,11 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if p > 1 then begin Dec(p); for i := 1 to p do + begin + if DownloadThread.IsTerminated then Break; if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then GetImageLink; + end; end; SerializeAndMaintainNames(Filenames); end; From 21d4c577246ad17897854464efbff62ef42c256e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 4 Aug 2016 23:55:42 +0800 Subject: [PATCH 1352/2794] baseunit, fixed padzero --- baseunits/uBaseUnit.pas | 61 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 83603aaba..21a35f302 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1962,54 +1962,51 @@ function Base64Decode(const s: String): String; end; function PadZero(const S: String; ATotalWidth: Integer; PadAll: Boolean; StripZero: Boolean): String; -var - isnumber: Boolean; - n: String; - i: Integer; - procedure padn(var R: String); + function PadN(const SN: String): String; begin - if isnumber then - begin - if StripZero then - while (Length(n) > 0) and (n[1] = '0') do - Delete(n, 1, 1); - R := R + StringOfChar('0', ATotalWidth - Length(n)) + n; - n := ''; - isnumber := False; - end; + Result := SN; + if StripZero and (Length(Result) > ATotalWidth) then + while (Result[1] = '0') and (Length(Result) > ATotalWidth) do + Delete(Result, 1, 1); + if Length(Result) < ATotalWidth then + Result := StringOfChar('0', ATotalWidth - Length(Result)) + Result; end; +var + ls, i: Integer; + n: String; begin - if S = '' then Exit(S); Result := ''; - isnumber := False; + if S = '' then Exit; + ls := Length(S); + i := 1; n := ''; - for i := 1 to Length(S) do - begin + Result := ''; + repeat if S[i] in ['0'..'9'] then - begin - n := n + S[i]; - isnumber := True; - end + n := n + s[i] else begin - if isnumber then + if n <> '' then begin - padn(Result); - if not PadAll then + Result := Result + PadN(n); + n := ''; + if PadAll then begin - Result := Result + S[i]; - Break; + Result := Result + PadZero(Copy(S, i, ls), ATotalWidth, PadAll, StripZero); + i := ls; end; + Break; end; Result := Result + S[i]; end; - end; - padn(Result); - Inc(i); - if i < Length(S) then - Result := Result + Copy(S, i, Length(S) - i + 1); + Inc(i); + until i > ls; + if n <> '' then + Result := Result + PadN(n); + if i < ls then + Result := Result + Copy(S, i, ls); end; procedure PadZeros(S: TStrings; ATotalWidth: Integer; PadAll: Boolean; StripZeros: Boolean); From 98df01f50df7cd99470a4d56e05f83f395c5445f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Aug 2016 00:00:17 +0800 Subject: [PATCH 1353/2794] baseunit, enclose modify tstrings in beginupdate endupdate --- baseunits/uBaseUnit.pas | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 21a35f302..ca6513287 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -703,14 +703,14 @@ function Base64Decode(const s: String): String; // StringUtils function PadZero(const S: String; ATotalWidth: Integer = 3; PadAll: Boolean = False; StripZero: Boolean = False): String; -procedure PadZeros(S: TStrings; ATotalWidth: Integer = 3; +procedure PadZeros(const S: TStrings; ATotalWidth: Integer = 3; PadAll: Boolean = False; StripZeros: Boolean = False); // RegExpr function RegExprGetMatch(const ARegExpr, AInputStr : RegExprString; const AMatchIdx: Integer): String; // maintain the order of strings by adding serialized number if necessary -procedure SerializeAndMaintainNames(F: TStrings); +procedure SerializeAndMaintainNames(const F: TStrings); function ShortenString(const S: String; const MaxWidth: Integer; const RightLength: Integer = 0; const EllipsisStr: String = '...'): String; @@ -2009,15 +2009,18 @@ function PadZero(const S: String; ATotalWidth: Integer; PadAll: Boolean; StripZe Result := Result + Copy(S, i, ls); end; -procedure PadZeros(S: TStrings; ATotalWidth: Integer; PadAll: Boolean; StripZeros: Boolean); +procedure PadZeros(const S: TStrings; ATotalWidth: Integer; PadAll: Boolean; StripZeros: Boolean); var i: Integer; begin if S = nil then Exit; if S.Count = 0 then Exit; - for i := 0 to S.Count - 1 do - begin - S[i] := PadZero(S[i], ATotalWidth, PadAll, StripZeros); + S.BeginUpdate; + try + for i := 0 to S.Count - 1 do + S[i] := PadZero(S[i], ATotalWidth, PadAll, StripZeros); + finally + S.EndUpdate; end; end; @@ -2036,7 +2039,7 @@ function RegExprGetMatch(const ARegExpr, AInputStr : RegExprString; end; end; -procedure SerializeAndMaintainNames(F: TStrings); +procedure SerializeAndMaintainNames(const F: TStrings); var s, so: TStringList; sameorder: Boolean; @@ -2067,6 +2070,7 @@ procedure SerializeAndMaintainNames(F: TStrings); if F = nil then Exit; if F.Count = 0 then Exit; s := TStringList.Create; + F.BeginUpdate; try //try sorting it s.AddStrings(F); @@ -2106,6 +2110,7 @@ procedure SerializeAndMaintainNames(F: TStrings); F.AddStrings(s); end; finally + F.EndUpdate; s.Free; end; end; From 26ab339e7be7b4338ea83bae38965c53000ca5de Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Aug 2016 00:31:19 +0800 Subject: [PATCH 1354/2794] readme, changed virtualtreeview url to branch lazarus-v4 on github --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 25dc152b6..00fc4a173 100644 --- a/readme.txt +++ b/readme.txt @@ -22,7 +22,7 @@ The Free Manga Downloader is a free open source application written in Object Pa In order to build FMD from the source code, you must install Lazarus latest version and Free Pascal Compiler v2.6.4. Then you must install the following 3rd party libraries and components: - RichMemo, https://sourceforge.net/projects/lazarus-ccr/ - - Virtual TreeView, https://sourceforge.net/projects/lazarus-ccr/ + - Virtual TreeView, https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4 - Synapse, http://synapse.ararat.cz/ - InternetTools, https://github.com/benibela/internettools - BESEN, https://github.com/BeRo1985/besen From 09bd670aedb29eb3ede936af2ebb1ac2ede7a837 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Aug 2016 07:47:58 +0800 Subject: [PATCH 1355/2794] img2pdf, fixed png indexed hival incorrect value #340 --- baseunits/Img2Pdf.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 67c4f376e..20e3e0cd1 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -267,7 +267,7 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); PageInfo.ColorSpace := 'Indexed /DeviceRGB'; if Assigned(IMG.Palette) then begin - PageInfo.ColorSpace := PageInfo.ColorSpace + ' ' + IntToStr(IMG.Palette.Count) + ' <'; + PageInfo.ColorSpace := PageInfo.ColorSpace + ' ' + IntToStr(IMG.Palette.Count - 1) + ' <'; for X := 0 to IMG.Palette.Count - 1 do begin C := IMG.Palette.Color[X]; From fcc6b53b2e64fe68eb5638eba59f06cc8b42699e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Aug 2016 08:24:57 +0800 Subject: [PATCH 1356/2794] img2pdf, for indexed png, check for grayscale palettes and store them as devicegray, save some bytes --- baseunits/Img2Pdf.pas | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 20e3e0cd1..18c6f7dac 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -235,6 +235,7 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); AMS: TMemoryStreamUTF8; X, Y: Integer; CLW, C: TFPColor; + isGrayScale: Boolean; begin IMG := TFPMemoryImage.Create(0, 0); try @@ -264,16 +265,34 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); end; 3: begin - PageInfo.ColorSpace := 'Indexed /DeviceRGB'; + PageInfo.ColorSpace := 'Indexed '; if Assigned(IMG.Palette) then begin - PageInfo.ColorSpace := PageInfo.ColorSpace + ' ' + IntToStr(IMG.Palette.Count - 1) + ' <'; + isGrayScale := True; for X := 0 to IMG.Palette.Count - 1 do begin C := IMG.Palette.Color[X]; - PageInfo.ColorSpace := PageInfo.ColorSpace + - IntToHex(C.red shr 8, 2) + IntToHex(C.green shr 8, 2) + IntToHex(C.blue shr 8, 2); + if (C.red <> C.green) or (C.red <> C.blue) or (C.green <> C.blue) then + begin + isGrayScale := False; + Break; + end; end; + if isGrayScale then + PageInfo.ColorSpace := PageInfo.ColorSpace + '/DeviceGray' + else + PageInfo.ColorSpace := PageInfo.ColorSpace + '/DeviceRGB'; + PageInfo.ColorSpace := PageInfo.ColorSpace + ' ' + IntToStr(IMG.Palette.Count - 1) + ' <'; + if isGrayScale then + for X := 0 to IMG.Palette.Count - 1 do + PageInfo.ColorSpace := PageInfo.ColorSpace + IntToHex(IMG.Palette.Color[X].red shr 8, 2) + else + for X := 0 to IMG.Palette.Count - 1 do + begin + C := IMG.Palette.Color[X]; + PageInfo.ColorSpace := PageInfo.ColorSpace + + IntToHex(C.red shr 8, 2) + IntToHex(C.green shr 8, 2) + IntToHex(C.blue shr 8, 2); + end; PageInfo.ColorSpace := PageInfo.ColorSpace + '>'; end; From 1853942e426cd2f81f830de57f7e5240f7b27a26 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 5 Aug 2016 19:43:19 +0800 Subject: [PATCH 1357/2794] fmdoptions, rearrange uses clause to move lazfileutils to the later --- baseunits/FMDOptions.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 58da15052..00ee6038d 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, IniFiles, fileinfo, LazFileUtils, LazUTF8, FileUtil, Forms, Graphics; + Classes, SysUtils, IniFiles, fileinfo, FileUtil, Forms, Graphics, LazFileUtils, LazUTF8; type From 21a94112f4f24a89d41a446e3ae03488a1087142 Mon Sep 17 00:00:00 2001 From: Aleksey <Aleksey-Nyaka@yandex.ru> Date: Fri, 5 Aug 2016 17:45:41 +0300 Subject: [PATCH 1358/2794] Fix mangachan domain Change domain on mangachan.me --- baseunits/modules/MangaChanRU.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 63e77df25..65ff28e66 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -144,7 +144,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaChanRU'; - RootURL := 'http://mangachan.ru'; + RootURL := 'http://mangachan.me'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; From bb4383eb2fa6981183ad6c8b1ed63ad3878bf39d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Aug 2016 11:43:04 +0800 Subject: [PATCH 1359/2794] cleanup md.lpr --- mangadownloader/md.lpr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index f1964b30f..ce56b6a10 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -12,8 +12,8 @@ cthreads, {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, multiloglaz, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, - uBaseUnit, frmMain, frmLogger; + Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, + uBaseUnit, frmMain; var CheckInstance: Boolean = True; From 2fd047bb47aaa03c1867d1efecad34346b58bb75 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Aug 2016 11:54:52 +0800 Subject: [PATCH 1360/2794] added hentaichanru, yaoichanru closed #342 --- baseunits/modules/MangaChanRU.pas | 26 +++++++++++++++++--------- config/mangalist.ini | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 65ff28e66..903c9a915 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -140,17 +140,25 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; procedure RegisterModule; -begin - with AddModule do + + procedure AddWebsiteModule(const AWebsite, ARootURL: String); begin - Website := 'MangaChanRU'; - RootURL := 'http://mangachan.me'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; + with AddModule do + begin + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; end; + +begin + AddWebsiteModule('MangaChanRU', 'http://mangachan.me'); + AddWebsiteModule('HentaiChanRU', 'http://hentaichan.me'); + AddWebsiteModule('YaoiChanRU', 'http://yaoichan.me'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 89d8d4a56..6edd68c28 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -20,4 +20,4 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D,YaoiChanRU From e7b3bbd1859bec9984fbb1dd56489474940f6c69 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Aug 2016 13:48:24 +0800 Subject: [PATCH 1361/2794] baesunit, added saveimagebase64stringtofile --- baseunits/uBaseUnit.pas | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ca6513287..7e5d9bc9b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -815,6 +815,9 @@ function GetURLFromBitly(const URL: String): String; function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; overload; function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String; overload; +// detect and save image from base64 string +function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; + // Download an image from url and save it to a specific location. function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; @@ -3319,6 +3322,28 @@ function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String Result := SaveImageStreamToFile(AHTTP.Document, Path, FileName, lastmodified); end; +function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; +var + ES: String; + i: Integer; + MS: TMemoryStream; +begin + Result := False; + if S = '' then Exit; + ES := AnsiLowerCase(Copy(S, 1, 100)); + if Pos('data:image/', ES) <> 1 then Exit; + i := Pos('base64,', ES); + if i = 0 then Exit; + ES := Base64Decode(Copy(S, i + 7, Length(S))); + MS := TMemoryStream.Create; + try + MS.Write(ES[1], Length(ES)); + Result := SaveImageStreamToFile(MS, Path, FileName) <> ''; + finally + MS.Free; + end; +end; + function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; From 977b00d279897166d42c17d9f6729843d6658650 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Aug 2016 13:50:09 +0800 Subject: [PATCH 1362/2794] gos, fixed download embedded base64 images fixed #338 --- baseunits/modules/GameofScanlation.pas | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index fdab81265..601648d93 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -112,7 +112,15 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with TXQueryEngineHTML.Create(Document) do try for v in XPath('//div[@class="chapterPages"]//img/@src') do - PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)); + begin + s := v.toString; + if SaveImageBase64StringToFile(s, + DownloadThread.Task.Container.CurrentWorkingDir, + DownloadThread.Task.GetFileName(PageLinks.Count)) then + PageLinks.Add('D') + else + PageLinks.Add(MaybeFillHost(Module.RootURL, s)); + end; finally Free; end; From e131ab70053a43b2ed1f1f7b8f391a4bab30eb23 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Aug 2016 14:08:33 +0800 Subject: [PATCH 1363/2794] Bump version 0.9.76.0 --- changelog.txt | 12 ++++++++++++ mangadownloader/md.lpi | 2 +- update | 6 +++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 295f0291b..89eabadc1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,18 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.76.0 (07-08-2016) +[*] Fixed download tree status not updating +[+] Added Log form, Options > Misc > Log +[+] Added TripleSevenScan[EN] +[*] MangaFox: fixed remove watermark +[*] E-Hentai/ExHentai: fixed download causing by incorrect filenames +[*] Fixed export to PDF issue with indexed PNG images +[+] Added HentaiChanRU[H], YaoiChanRU[H] +[*] GameofScanlation: fixed download embedded base64 images +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.75.0...0.9.76.0 + 0.9.75.0 (30-07-2016) [+] Added "Delete task + data + favorite" in download list popup menu [+] Added "Delete" in manga list popup menu diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 18b2b17a1..c35a914b9 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="75"/> + <RevisionNr Value="76"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index fa069b47e..923a717fb 100644 --- a/update +++ b/update @@ -3,6 +3,6 @@ https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z ## update info above was deprecated -VERSION=0.9.75.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.75.0/fmd_0.9.75.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.75.0/fmd_0.9.75.0_Win64.7z +VERSION=0.9.76.0 +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.76.0/fmd_0.9.76.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.76.0/fmd_0.9.76.0_Win64.7z From 4a49653312079ff30eafde5e9214906975950cc0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Aug 2016 15:23:53 +0800 Subject: [PATCH 1364/2794] cleanup and fixed updater --- updater/languages/updater.en.po | 5 +- updater/languages/updater.id_ID.po | 5 +- updater/languages/updater.po | 4 - updater/uMain.lfm | 1 + updater/uMain.lrj | 1 - updater/uMain.pas | 180 ++++++++++++++--------------- updater/updater.lpi | 6 +- 7 files changed, 91 insertions(+), 111 deletions(-) diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index 1ce117fed..18c436bfa 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -11,10 +11,6 @@ msgstr "" "Language: en\n" "X-Generator: Poedit 1.8.8\n" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Updater" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "File size" @@ -106,3 +102,4 @@ msgstr "Unpacking file [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Waiting main app to close..." + diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index fd8a03916..924bc1912 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -11,10 +11,6 @@ msgstr "" "Language: id_ID\n" "X-Generator: Poedit 1.8.8\n" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Updater" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Ukuran" @@ -106,3 +102,4 @@ msgstr "Membuka berkas [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Menunggu aplikasi utama untuk berhenti..." + diff --git a/updater/languages/updater.po b/updater/languages/updater.po index 56c7490de..00ea74156 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -1,10 +1,6 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "" - #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "" diff --git a/updater/uMain.lfm b/updater/uMain.lfm index 92e5ab6e8..2f5f24a4f 100644 --- a/updater/uMain.lfm +++ b/updater/uMain.lfm @@ -14,6 +14,7 @@ object frmMain: TfrmMain OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '1.7' + Visible = False object pbDownload: TProgressBar Left = 8 Height = 20 diff --git a/updater/uMain.lrj b/updater/uMain.lrj index 8a7917a17..f906dfa05 100644 --- a/updater/uMain.lrj +++ b/updater/uMain.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":193843458,"name":"tfrmmain.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114,32,45,32,85,112,100,97,116,101,114],"value":"Free Manga Downloader - Updater"}, {"hash":131060021,"name":"tfrmmain.lbtransferrate.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,114,97,116,101],"value":"Transfer rate"}, {"hash":41414149,"name":"tfrmmain.lbfilesize.caption","sourcebytes":[70,105,108,101,32,115,105,122,101],"value":"File size"}, {"hash":184637710,"name":"tfrmmain.lbstatus.caption","sourcebytes":[87,97,105,116,105,110,103,46,46,46],"value":"Waiting..."} diff --git a/updater/uMain.pas b/updater/uMain.pas index bdc225a3e..7f4b611f9 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -10,9 +10,9 @@ interface cmem, {$endif} Classes, SysUtils, zipper, FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, - Forms, Dialogs, ComCtrls, StdCtrls, Clipbrd, ExtCtrls, DefaultTranslator, - RegExpr, IniFiles, SimpleException, uMisc, httpsend, blcksock, ssl_openssl, - ssl_openssl_lib, synacode, uFMDThread, SimpleTranslator, httpsendthread; + Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls, RegExpr, IniFiles, blcksock, + ssl_openssl, ssl_openssl_lib, synacode, uFMDThread, httpsendthread, uMisc, + SimpleTranslator; type @@ -25,16 +25,15 @@ TfrmMain = class(TForm) lbFileSizeValue: TLabel; lbStatus: TLabel; lbTransferRateValue: TLabel; - pbDownload :TProgressBar; + pbDownload: TProgressBar; procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); - procedure FormCreate(Sender :TObject); + procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender :TObject); + procedure FormShow(Sender: TObject); procedure itMonitorTimer(Sender: TObject); private { private declarations } public - procedure ExceptionHandler(Sender: TObject; E: Exception); { public declarations } end; @@ -42,30 +41,30 @@ TfrmMain = class(TForm) TDownloadThread = class(TFMDThread) private - FTotalSize, FCurrentSize :integer; - FHTTP :THTTPSendThread; - FStatus :string; - FProgress :string; - FErrorMessage :string; - UZip :TUnZipper; + FTotalSize, FCurrentSize: Integer; + FHTTP: THTTPSendThread; + FStatus: String; + FProgress: String; + FErrorMessage: String; + UZip: TUnZipper; protected - procedure SockOnStatus(Sender :TObject; Reason :THookSocketReason; - const Value :string); - procedure UZipOnStartFile(Sender :TObject; const AFileName :string); + procedure SockOnStatus(Sender: TObject; Reason: THookSocketReason; + const Value: String); + procedure UZipOnStartFile(Sender: TObject; const AFileName: String); procedure MainThreadUpdateStatus; procedure MainThreadUpdateProgress; procedure MainThreadUpdateProgressLabel; procedure MainThreadErrorGetting; - procedure UpdateStatus(AStatus :string); - procedure ShowErrorMessage(AMessage :string); + procedure UpdateStatus(AStatus: String); + procedure ShowErrorMessage(AMessage: String); procedure Execute; override; procedure OnThreadTerminate(Sender: TObject); public - URL :string; - FileName :string; - DirPath :string; - MaxRetry :cardinal; - Extract :boolean; + URL: String; + FileName: String; + DirPath: String; + MaxRetry: Cardinal; + Extract: Boolean; constructor Create; destructor Destroy; override; end; @@ -73,30 +72,30 @@ TDownloadThread = class(TFMDThread) procedure IncReadCount(const ACount: Int64); var - frmMain :TfrmMain; - dl :TDownloadThread; - isDownload :boolean = False; - ReadCount :Integer = 0; - CS_ReadCount :TRTLCriticalSection; - - _UpdApp :boolean = False; - _Extract :boolean = False; - _NoError :boolean = False; - _URL :string = ''; - _MaxRetry :cardinal = 1; - _LaunchApp :string = ''; - - ProxyType :string; - ProxyHost :string; - ProxyPort :string; - ProxyUser :string; - ProxyPass :string; + frmMain: TfrmMain; + dl: TDownloadThread; + isDownload: Boolean = False; + ReadCount: Integer = 0; + CS_ReadCount: TRTLCriticalSection; + + _UpdApp: Boolean = False; + _Extract: Boolean = False; + _NoError: Boolean = False; + _URL: String = ''; + _MaxRetry: Cardinal = 1; + _LaunchApp: String = ''; + + ProxyType: String; + ProxyHost: String; + ProxyPort: String; + ProxyUser: String; + ProxyPass: String; const Symbols: array [0..10] of Char = ('\', '/', ':', '*', '?', '"', '<', '>', '|', #9, ';'); - mf_data_link = 'https://www.mediafire.com/folder/fwa8eomz80uk1/Data'; + UA_CURL = 'curl/7.42.1'; resourcestring RS_InvalidURL = 'Invalid URL!'; @@ -121,7 +120,8 @@ procedure IncReadCount(const ACount: Int64); implementation -uses uMessage; +uses + uMessage; {$R *.lfm} @@ -162,7 +162,7 @@ constructor TDownloadThread.Create; FHTTP := THTTPSendThread.Create(Self); FHTTP.Sock.OnStatus := @SockOnStatus; FHTTP.Timeout := 10000; - FHTTP.SetProxy(ProxyType,ProxyHost,ProxyPort,ProxyUser,ProxyPass); + FHTTP.SetProxy(ProxyType, ProxyHost, ProxyPort, ProxyUser, ProxyPass); FTotalSize := 0; FCurrentSize := 0; URL := ''; @@ -184,13 +184,13 @@ procedure TDownloadThread.MainThreadUpdateStatus; frmMain.lbStatus.Caption := FStatus; end; -procedure TDownloadThread.UpdateStatus(AStatus :string); +procedure TDownloadThread.UpdateStatus(AStatus: String); begin FStatus := AStatus; Synchronize(@MainThreadUpdateStatus); end; -procedure TDownloadThread.ShowErrorMessage(AMessage: string); +procedure TDownloadThread.ShowErrorMessage(AMessage: String); begin FErrorMessage := AMessage; Synchronize(@MainThreadErrorGetting); @@ -199,7 +199,7 @@ procedure TDownloadThread.ShowErrorMessage(AMessage: string); procedure TDownloadThread.MainThreadUpdateProgress; var barPos: Integer; - prgText: string; + prgText: String; begin if Terminated then Exit; if FCurrentSize > 0 then @@ -231,19 +231,19 @@ procedure TDownloadThread.MainThreadErrorGetting; mtError, [mbOK], 0); end; -procedure TDownloadThread.SockOnStatus(Sender :TObject; Reason :THookSocketReason; - const Value :string); +procedure TDownloadThread.SockOnStatus(Sender: TObject; Reason: THookSocketReason; + const Value: String); begin if Terminated then Exit; if FHTTP.Headers.IndexOfName('Content-Length') > -1 then FTotalSize := StrToIntDef(FHTTP.Headers.Values['Content-Length'], 0); case Reason of - HR_Connect :FCurrentSize := 0; - HR_ReadCount : - begin - Inc(FCurrentSize, StrToIntDef(Value, 0)); - IncReadCount(StrToIntDef(Value, 0)); - end; + HR_Connect: FCurrentSize := 0; + HR_ReadCount: + begin + Inc(FCurrentSize, StrToIntDef(Value, 0)); + IncReadCount(StrToIntDef(Value, 0)); + end; end; Synchronize(@MainThreadUpdateProgress); end; @@ -253,7 +253,7 @@ procedure TDownloadThread.MainThreadUpdateProgressLabel; frmMain.lbFileSizeValue.Caption := FProgress; end; -procedure TDownloadThread.UZipOnStartFile(Sender :TObject; const AFileName :string); +procedure TDownloadThread.UZipOnStartFile(Sender: TObject; const AFileName: String); begin if FileExistsUTF8(AFileName) then DeleteFileUTF8(AFileName); @@ -262,17 +262,17 @@ procedure TDownloadThread.UZipOnStartFile(Sender :TObject; const AFileName :stri procedure TDownloadThread.Execute; var - sf : Boolean = False; - regx : TRegExpr; - i, ctry : Cardinal; + sf: Boolean = False; + regx: TRegExpr; + i, ctry: Cardinal; Sza, rurl, fname, sproject, sdir, - s, sfile : String; + s, sfile: String; st, HTTPHeaders: TStringList; - filestream : TFileStreamUTF8; + filestream: TFileStreamUTF8; begin URL := EncodeURL(DecodeURL(Trim(URL))); HTTPHeaders := TStringList.Create; @@ -306,10 +306,10 @@ procedure TDownloadThread.Execute; sfile := regx.Replace(URL, '$3', True); if FileName = '' then FileName := sfile; - if Pos('https://',LowerCase(URL)) = 1 then + if Pos('https://', LowerCase(URL)) = 1 then rurl := 'https://' else - rurl:='http://'; + rurl := 'http://'; rurl := rurl + 'sourceforge.net/projects/' + sproject + '/files/' + sdir + '/' + sfile + '/download'; end @@ -395,7 +395,7 @@ procedure TDownloadThread.Execute; else if (FHTTP.ResultCode >= 400) and (FHTTP.ResultCode < 500) then begin - if ctry>=MaxRetry then + if ctry >= MaxRetry then begin UpdateStatus(RS_FileNotFound); ShowErrorMessage(RS_FileNotFound + LineEnding + LineEnding + @@ -404,8 +404,8 @@ procedure TDownloadThread.Execute; Break; end; //try to load previous url, in case it was temporary url - if ctry>0 then begin - rurl:=URL; + if ctry > 0 then begin + rurl := URL; FHTTP.Cookies.Clear; end; Inc(ctry); @@ -454,20 +454,20 @@ procedure TDownloadThread.Execute; Sza := GetCurrentDirUTF8 + DirectorySeparator + '7za.exe'; if _UpdApp and FileExistsUTF8(GetCurrentDirUTF8 + DirectorySeparator + '7za.exe') then - begin - st := TStringList.Create; - try - FindAllFiles(st, GetCurrentDirUTF8, '*.dbg', False); - if st.Count > 0 then - for i := 0 to st.Count - 1 do - DeleteFileUTF8(st[i]); - finally - st.Free; - end; - CopyFile(GetCurrentDirUTF8 + DirectorySeparator + '7za.exe', - GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe'); - Sza := GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe'; + begin + st := TStringList.Create; + try + FindAllFiles(st, GetCurrentDirUTF8, '*.dbg', False); + if st.Count > 0 then + for i := 0 to st.Count - 1 do + DeleteFileUTF8(st[i]); + finally + st.Free; end; + CopyFile(GetCurrentDirUTF8 + DirectorySeparator + '7za.exe', + GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe'); + Sza := GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe'; + end; if Pos('.zip', LowerCase(FileName)) <> 0 then begin UZip := TUnZipper.Create; @@ -505,8 +505,6 @@ procedure TDownloadThread.Execute; if (not Self.Terminated) and _UpdApp and (_LaunchApp <> '') then RunExternalProcess(_LaunchApp, [''], True, False); except - on E: Exception do - frmMain.ExceptionHandler(Self, E); end; regx.Free; HTTPHeaders.Free; @@ -529,12 +527,11 @@ procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); CloseAction := caFree; end; -procedure TfrmMain.FormCreate(Sender :TObject); +procedure TfrmMain.FormCreate(Sender: TObject); var - config :TIniFile; + config: TIniFile; begin Randomize; - InitSimpleExceptionHandler(ChangeFileExt(Application.ExeName, '.log')); SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; SimpleTranslator.LangAppName := 'updater'; SimpleTranslator.CollectLanguagesFiles; @@ -568,11 +565,11 @@ procedure TfrmMain.FormDestroy(Sender: TObject); DoneCriticalsection(CS_ReadCount); end; -procedure TfrmMain.FormShow(Sender :TObject); +procedure TfrmMain.FormShow(Sender: TObject); var - s :string; - i :Integer; - sh :boolean = False; + s: String; + i: Integer; + sh: Boolean = False; begin if Paramcount > 0 then begin @@ -656,13 +653,8 @@ procedure TfrmMain.itMonitorTimer(Sender: TObject); else begin itMonitor.Enabled := False; - Self.Close + Self.Close; end; end; -procedure TfrmMain.ExceptionHandler(Sender : TObject; E : Exception); -begin - SimpleException.ExceptionHandle(Sender, E); -end; - end. diff --git a/updater/updater.lpi b/updater/updater.lpi index 601587523..05706fc64 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -33,7 +33,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits\SimpleException;..\baseunits"/> + <OtherUnitFiles Value="..\baseunits"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -47,7 +47,6 @@ <Linking> <Debugging> <GenerateDebugInfo Value="False"/> - <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> @@ -108,7 +107,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> - <OtherUnitFiles Value="..\3rd\synapse\source;..\baseunits\SimpleException;..\baseunits"/> + <OtherUnitFiles Value="..\baseunits"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -122,7 +121,6 @@ <Linking> <Debugging> <GenerateDebugInfo Value="False"/> - <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> From 20a03b0fc5641c26cce133400d9e5ec4c28f6658 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 8 Aug 2016 07:43:44 +0800 Subject: [PATCH 1365/2794] fmdoptions, remove stripquotes, false by default --- baseunits/FMDOptions.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 00ee6038d..29086f704 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -241,7 +241,6 @@ procedure SetIniFiles; mangalistfile := TIniFile.Create(MANGALIST_FILE); GetAvailableWebsite; configfile := TIniFileRun.Create(CONFIG_FILE); - configfile.Options := configfile.Options - [ifoStripQuotes]; advancedfile := TIniFileRun.Create(CONFIG_ADVANCED); end; From 9902f70a64696a45171111793cd85cd6bbe87fc3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 8 Aug 2016 08:03:26 +0800 Subject: [PATCH 1366/2794] simpleexception, enclose multilog part with ifdef. added define multilog in project options and celanup --- baseunits/SimpleException/SimpleException.pas | 29 +++++++++++++------ mangadownloader/md.lpi | 15 ++++------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 7da628df9..02db6ed63 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -46,8 +46,11 @@ interface {$IF DEFINED(DARWIN) OR DEFINED(MACOS)} machoreader, {$ENDIF} - fileinfo, - MultiLog; + fileinfo + {$IFDEF MULTILOG} + ,MultiLog + {$ENDIF} + ; type @@ -114,6 +117,7 @@ procedure DoneSimpleExceptionHandler; implementation +{$IFDEF MULTILOG} type { TLoggerException } @@ -123,6 +127,14 @@ TLoggerException = class helper for TLogger procedure SendExceptionStr(const AText: String; AExceptionStr: String); end; +{ TLoggerException } + +procedure TLoggerException.SendExceptionStr(const AText: String; AExceptionStr: String); +begin + SendBuffer(ltException, AText, AExceptionStr[1], Length(AExceptionStr)); +end; +{$ENDIF} + procedure SetMaxStackCount(const ACount: Integer); begin @@ -198,13 +210,6 @@ procedure DoneSimpleExceptionHandler; FreeAndNil(MainExceptionHandler); end; -{ TLoggerException } - -procedure TLoggerException.SendExceptionStr(const AText: String; AExceptionStr: String); -begin - SendBuffer(ltException, AText, AExceptionStr[1], Length(AExceptionStr)); -end; - { TSimpleException } procedure TSimpleException.SetMaxStackCount(AMaxStackCount: Integer); @@ -325,9 +330,11 @@ procedure TSimpleException.UnhandledException(Obj: TObject; Addr: CodePointer; for i := 0 to FrameCount - 1 do S := S + ' ' + BackTraceStrFunc(Frames[i]) + LineEnding; FLastReport := FLastReport + S; + {$IFDEF MULTILOG} if Logger.Enabled then Logger.SendExceptionStr('Unhandled Exception occured at $' + BackTraceStrFunc(Addr), S) else + {$ENDIF} SaveLogToFile(FLastReport); CallExceptionHandler; end; @@ -397,6 +404,7 @@ procedure TSimpleException.CreateExceptionReport; end; S := GetStackTraceStr; FLastReport := FLastReport + S; + {$IFDEF MULTILOG} if Logger.Enabled then begin if Assigned(FLastException) then @@ -405,6 +413,7 @@ procedure TSimpleException.CreateExceptionReport; Logger.SendExceptionStr('Program exception!', S); end else + {$ENDIF} SaveLogToFile(FLastReport); end; @@ -438,9 +447,11 @@ procedure TSimpleException.CallExceptionHandler; TThread.Synchronize((Sender as TThread), @ExceptionHandler) {$ENDIF} except + {$IFDEF MULTILOG} if Logger.Enabled then Logger.SendError(SCantHandleException) else + {$ENDIF} SaveLogToFile(SCantHandleException); end else diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c35a914b9..dd755132c 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -63,7 +63,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dRELEASEWIN64"/> +-dMULTILOG"/> </Other> </CompilerOptions> </Item2> @@ -104,7 +104,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dDEBUGWIN32"/> +-dMULTILOG"/> </Other> </CompilerOptions> </Item3> @@ -142,7 +142,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dDEBUGWIN64"/> +-dMULTILOG"/> </Other> </CompilerOptions> </Item4> @@ -176,11 +176,8 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dLOGACTIVE --dTRAPLAZLOGGER --dSENDTOLAZLOGGER --dDEBUGWIN32 --dDEBUGLEAKS"/> +-dDEBUGLEAKS +-dMULTILOG"/> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> @@ -357,7 +354,7 @@ <CustomOptions Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE --dRELEASEWIN32"/> +-dMULTILOG"/> </Other> </CompilerOptions> <Debugging> From f6b00158b6e1004dab482b1c26f507e4358007ab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 8 Aug 2016 10:21:49 +0800 Subject: [PATCH 1367/2794] downloadmanager, move currentworkingdir, currentcustomfilename to ttaskthread, and added currentmaxfilenamelength --- baseunits/includes/MeinManga/image_url.inc | 4 +- baseunits/modules/GameofScanlation.pas | 2 +- baseunits/uDownloadsManager.pas | 72 ++++++++++++++-------- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index 84043d215..8ef95e219 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -57,7 +57,7 @@ SaveImage( Task.Container.MangaSiteID, GetVal(parse[i], 'src'), - Task.Container.CurrentWorkingDir, + Task.CurrentWorkingDir, Format('%.3d', [WorkId + 1]) + '_' + IntToStr(prefix), Task.Container.Manager.retryConnect); @@ -78,7 +78,7 @@ begin imageName := Format('%.3d', [WorkId + 1]); Merge2Image( - Task.Container.CurrentWorkingDir, + Task.CurrentWorkingDir, imageName + '_' + IntToStr(prefix - 2) + '.jpg', imageName + '_' + IntToStr(prefix - 1) + '.jpg', imageName + '.jpg'); diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 601648d93..0fa3780c6 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -115,7 +115,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin s := v.toString; if SaveImageBase64StringToFile(s, - DownloadThread.Task.Container.CurrentWorkingDir, + DownloadThread.Task.CurrentWorkingDir, DownloadThread.Task.GetFileName(PageLinks.Count)) then PageLinks.Add('D') else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 028591e05..43ebd3e31 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -79,6 +79,12 @@ TDownloadThread = class(TFMDThread) TTaskThread = class(TFMDThread) private FCheckAndActiveTaskFlag: Boolean; + FCurrentWorkingDir: String; + {$IFDEF Windows} + FCurrentMaxFileNameLength: Integer; + {$ENDIF} + FCurrentCustomFileName: String; + procedure SetCurrentWorkingDir(AValue: String); protected procedure CheckOut; procedure MainThreadCompressRepaint; @@ -99,6 +105,10 @@ TTaskThread = class(TFMDThread) constructor Create; destructor Destroy; override; function GetFileName(const AWorkId: Integer): String; + property CurrentWorkingDir: String read FCurrentWorkingDir write SetCurrentWorkingDir; + property CurrentMaxFileNameLength: Integer read FCurrentMaxFileNameLength; + // current custom filename with only %FILENAME% left intact + property CurrentCustomFileName: String read FCurrentCustomFileName write FCurrentCustomFileName; end; { TTaskContainer } @@ -121,10 +131,6 @@ TTaskContainer = class // download manager Manager: TDownloadManager; DownloadInfo: TDownloadInfo; - // current working dir, save to + chapter name - CurrentWorkingDir: String; - // current custom filename with only %FILENAME% left intact - CurrentCustomFileName: String; // current link index CurrentPageNumber, // current chapter index @@ -142,7 +148,7 @@ TTaskContainer = class FailedChapterLinks, PageContainerLinks, PageLinks: TStringList; - Filenames: TStringList; + FileNames: TStringList; // custom filename CustomFileName: String; constructor Create; @@ -857,6 +863,9 @@ constructor TTaskThread.Create; Threads := TDownloadThreads.Create; FCheckAndActiveTaskFlag := True; httpCookies := ''; + FCurrentWorkingDir := ''; + FCurrentCustomFileName := ''; + FCurrentMaxFileNameLength := 0; end; destructor TTaskThread.Destroy; @@ -868,15 +877,15 @@ destructor TTaskThread.Destroy; function TTaskThread.GetFileName(const AWorkId: Integer): String; begin Result := ''; - if (Container.Filenames.Count = Container.PageLinks.Count) and - (AWorkId < Container.Filenames.Count) then - Result := Container.Filenames[AWorkId]; + if (Container.FileNames.Count = Container.PageLinks.Count) and + (AWorkId < Container.FileNames.Count) then + Result := Container.FileNames[AWorkId]; if Result = '' then Result := Format('%.3d', [AWorkId + 1]); - Result := StringReplace(Container.CurrentCustomFileName, CR_FILENAME, Result, [rfReplaceAll]); + Result := StringReplace(CurrentCustomFileName, CR_FILENAME, Result, [rfReplaceAll]); {$IFDEF WINDOWS} - if Length(Container.CurrentWorkingDir + Result) > FMDMaxImageFilePath then - Result := ShortenString(Result, FMDMaxImageFilePath - Length(Container.CurrentWorkingDir), 4, ''); + if Length(Result) > FCurrentMaxFileNameLength then + Result := ShortenString(Result, FCurrentMaxFileNameLength, 4, ''); {$ENDIF} end; @@ -905,12 +914,12 @@ procedure TTaskThread.Compress; 3: uPacker.Format := pfPDF; end; uPacker.CompressionQuality := OptionPDFQuality; - uPacker.Path := Container.CurrentWorkingDir; + uPacker.Path := CurrentWorkingDir; uPacker.FileName := Container.DownloadInfo.SaveTo + Container.ChapterName[Container.CurrentDownloadChapterPtr]; for i := 0 to Container.PageLinks.Count - 1 do begin - s := FindImageFile(Container.CurrentWorkingDir + GetFileName(i)); + s := FindImageFile(CurrentWorkingDir + GetFileName(i)); if s <> '' then uPacker.FileList.Add(s); end; @@ -964,7 +973,7 @@ function TDownloadThread.DownloadImage: Boolean; Result := True; // check download path - if not ForceDirectoriesUTF8(Task.Container.CurrentWorkingDir) then + if not ForceDirectoriesUTF8(Task.CurrentWorkingDir) then begin Task.Container.Status := STATUS_FAILED; Task.Container.DownloadInfo.Status := RS_FailedToCreateDir; @@ -1005,7 +1014,7 @@ function TDownloadThread.DownloadImage: Boolean; Result := Modules.DownloadImage( Self, workURL, - Task.Container.CurrentWorkingDir, + Task.CurrentWorkingDir, workFilename, Task.Container.ModuleId); end @@ -1017,7 +1026,7 @@ function TDownloadThread.DownloadImage: Boolean; FHTTP, Task.Container.MangaSiteID, workURL, - Task.Container.CurrentWorkingDir, + Task.CurrentWorkingDir, workFilename, savedFilename, Task.Container.Manager.retryConnect); @@ -1032,6 +1041,15 @@ function TDownloadThread.DownloadImage: Boolean; end; end; +procedure TTaskThread.SetCurrentWorkingDir(AValue: String); +begin + if FCurrentWorkingDir = AValue then Exit; + FCurrentWorkingDir := CorrectPathSys(AValue); + {$IFDEF Windows} + FCurrentMaxFileNameLength := FMDMaxImageFilePath - Length(FCurrentWorkingDir); + {$ENDIF} +end; + procedure TTaskThread.CheckOut; var currentMaxThread: Integer; @@ -1180,11 +1198,11 @@ procedure TTaskThread.Execute; //check path if OptionGenerateChapterFolder then - Container.CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo + - Container.ChapterName[Container.CurrentDownloadChapterPtr]) + CurrentWorkingDir := Container.DownloadInfo.SaveTo + + Container.ChapterName[Container.CurrentDownloadChapterPtr] else - Container.CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo); - if not ForceDirectoriesUTF8(Container.CurrentWorkingDir) then + CurrentWorkingDir := Container.DownloadInfo.SaveTo; + if not ForceDirectoriesUTF8(CurrentWorkingDir) then begin Container.Status := STATUS_FAILED; Container.DownloadInfo.Status := RS_FailedToCreateDir; @@ -1196,7 +1214,7 @@ procedure TTaskThread.Execute; Modules.TaskStart(Container, Container.ModuleId); // set current working custom filename - Container.CurrentCustomFileName := CustomRename(Container.CustomFileName, + CurrentCustomFileName := CustomRename(Container.CustomFileName, Container.DownloadInfo.Website, Container.DownloadInfo.Title, '', @@ -1236,7 +1254,7 @@ procedure TTaskThread.Execute; begin for j := 0 to Container.PageLinks.Count - 1 do begin - if ImageFileExist(Container.CurrentWorkingDir + GetFileName(j)) then + if ImageFileExist(CurrentWorkingDir + GetFileName(j)) then Container.PageLinks[j] := 'D' else if Container.PageLinks[j] = 'D' then @@ -1472,7 +1490,7 @@ constructor TTaskContainer.Create; FailedChapterLinks := TStringList.Create; PageLinks := TStringList.Create; PageContainerLinks := TStringList.Create; - Filenames := TStringList.Create; + FileNames := TStringList.Create; ReadCount := 0; WorkCounter := 0; CurrentPageNumber := 0; @@ -1485,7 +1503,7 @@ constructor TTaskContainer.Create; destructor TTaskContainer.Destroy; begin - Filenames.Free; + FileNames.Free; PageContainerLinks.Free; PageLinks.Free; ChapterName.Free; @@ -1695,7 +1713,7 @@ procedure TDownloadManager.Restore; s := ReadString(tid, 'PageContainerLinks', ''); if s <> '' then GetParams(PageContainerLinks, s); s := ReadString(tid, 'Filenames', ''); - if s <> '' then GetParams(Filenames, s); + if s <> '' then GetParams(FileNames, s); j := ReadInteger(tid, 'TaskStatus', -1); if j >= 0 then Status := TDownloadStatusType(j) @@ -1780,8 +1798,8 @@ procedure TDownloadManager.Backup; WriteString(tid, 'PageLinks', SetParams(PageLinks)); if PageContainerLinks.Count > 0 then WriteString(tid, 'PageContainerLinks', SetParams(PageContainerLinks)); - if Filenames.Count > 0 then - WriteString(tid, 'Filenames', SetParams(Filenames)); + if FileNames.Count > 0 then + WriteString(tid, 'Filenames', SetParams(FileNames)); WriteString(tid, 'TaskStatus', GetEnumName(TypeInfo(TDownloadStatusType), Integer(Status))); WriteInteger(tid, 'ChapterPtr', CurrentDownloadChapterPtr); WriteInteger(tid, 'NumberOfPages', PageNumber); From 52bd239bc8423491f263459f770c1115354e62d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 8 Aug 2016 10:26:29 +0800 Subject: [PATCH 1368/2794] ehentai, clear customfilename if max length exceeds available space on windows, will be serialized by ttaskthread.getfilename #332 --- baseunits/modules/EHentai.pas | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 7f02fa35f..2f57157ad 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -253,7 +253,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; for x in XPath('//div[@id="gdt"]//a') do begin PageContainerLinks.Add(x.toNode.getAttribute('href')); - Filenames.Add(ExtractFileNameOnly(Trim(SeparateRight( + FileNames.Add(ExtractFileNameOnly(Trim(SeparateRight( XPathString('img/@title', x.toNode), ':')))); end; while PageLinks.Count < PageContainerLinks.Count do @@ -292,7 +292,16 @@ function GetPageNumber(const DownloadThread: TDownloadThread; GetImageLink; end; end; - SerializeAndMaintainNames(Filenames); + SerializeAndMaintainNames(FileNames); + // check the max length of filenames, serialize the filenames if it's exceds available space + p := 0; + for i := 0 to FileNames.Count - 1 do + begin + if Length(FileNames[i]) > p then + p := Length(FileNames[i]); + end; + if p > Task.CurrentMaxFileNameLength then + FileNames.Clear; end; finally query.Free; From 8c2f999d1e996a29bb4cc0c0be01354ef4d1b972 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 8 Aug 2016 10:45:20 +0800 Subject: [PATCH 1369/2794] delete old_updater only when update doesn't exist, otherwise rename it to updater The latest release doesn't including updater due to unexpected fail while compiling updater with batch script (and not monitored). This code will preserve updater if the new release doesn't come with new updater. --- mangadownloader/forms/frmMain.pas | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 87f8a99b9..c4cebb3ff 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1084,7 +1084,12 @@ procedure TMainForm.FormCreate(Sender: TObject); // remove old updater if FileExistsUTF8(FMD_DIRECTORY + 'old_updater.exe') then - DeleteFileUTF8(FMD_DIRECTORY + 'old_updater.exe'); + begin + if FileExistsUTF8(FMD_DIRECTORY + 'updater.exe') then + DeleteFileUTF8(FMD_DIRECTORY + 'old_updater.exe') + else + RenameFileUTF8(FMD_DIRECTORY + 'old_updater.exe', FMD_DIRECTORY + 'updater.exe'); + end; // TrayIcon TrayIcon.Icon.Assign(Application.Icon); From d08b4805bd1d87e88e509f28987980918bc1bec4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 9 Aug 2016 00:22:28 +0800 Subject: [PATCH 1370/2794] replace tfmdthread with thttpthread in httpsendthread, cleanup usused unit in uses clause --- baseunits/CheckUpdate.pas | 4 +- baseunits/ImgInfos.pas | 2 +- baseunits/SQLiteData.pas | 2 +- baseunits/WebsiteModules.pas | 2 +- baseunits/accountmanagerdb.pas | 2 +- baseunits/httpsendthread.pas | 42 +++++++++++++-- baseunits/uBaseUnit.pas | 10 ++-- baseunits/uData.pas | 10 ++-- baseunits/uDownloadsManager.pas | 9 ++-- baseunits/uFMDThread.pas | 57 --------------------- baseunits/uFavoritesManager.pas | 6 +-- baseunits/uGetMangaInfosThread.pas | 4 +- baseunits/uOption.pas | 21 -------- baseunits/uSilentThread.pas | 6 +-- baseunits/uUpdateThread.pas | 8 +-- mangadownloader/forms/frmAccountManager.lfm | 1 + mangadownloader/forms/frmAccountManager.lrj | 1 - mangadownloader/forms/frmAccountManager.pas | 6 +-- mangadownloader/languages/fmd.en.po | 5 +- mangadownloader/languages/fmd.id_ID.po | 5 +- mangadownloader/languages/fmd.po | 4 -- updater/uMain.pas | 4 +- 22 files changed, 77 insertions(+), 134 deletions(-) delete mode 100644 baseunits/uFMDThread.pas delete mode 100644 baseunits/uOption.pas diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 05aec89b0..7dc60d3db 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -10,11 +10,11 @@ interface uses - Classes, SysUtils, Forms, Controls, uFMDThread, uBaseUnit, FMDOptions, httpsendthread; + Classes, SysUtils, Forms, Controls, uBaseUnit, FMDOptions, httpsendthread; type - TCheckUpdateThread = class(TFMDThread) + TCheckUpdateThread = class(THTTPThread) private FHTTP: THTTPSendThread; fNewVersionNumber, fUpdateURL, fChangelog: String; diff --git a/baseunits/ImgInfos.pas b/baseunits/ImgInfos.pas index c6864ab62..754e50794 100644 --- a/baseunits/ImgInfos.pas +++ b/baseunits/ImgInfos.pas @@ -34,7 +34,7 @@ interface uses - Classes, SysUtils, LazUTF8Classes, LazUTF8, LazFileUtils, FPimage, + Classes, SysUtils, LazUTF8Classes, LazFileUtils, FPimage, FPReadJPEG, FPReadPNG, FPReadGif, FPReadBMP, FPReadTiff, FPWriteJPEG, FPWritePNG, FPWriteBMP, FPWriteTiff; diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index cd61834ad..98d2bdef7 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, LazFileUtils, strutils, sqlite3conn, sqldb, DB; + SysUtils, LazFileUtils, strutils, sqlite3conn, sqldb; type diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 25cf63a40..4a91171f0 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -11,7 +11,7 @@ interface uses Classes, SysUtils, uData, uDownloadsManager, FMDOptions, httpsendthread, - RegExpr, IniFiles; + RegExpr; const MODULE_NOT_FOUND = -1; diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 25ed25926..19293d897 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -10,7 +10,7 @@ interface uses - Classes, SysUtils, LazFileUtils, MultiLog, base64, sqlite3conn, + SysUtils, LazFileUtils, MultiLog, base64, sqlite3conn, sqldb, db; type diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index fd0c04a50..5b802a2ed 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,15 +6,28 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - uFMDThread, GZIPUtils, Graphics, RegExpr; + GZIPUtils, Graphics, RegExpr; type + { THTTPThread } + + THTTPThread = class(TThread) + private + FOnCustomTerminate: TNotifyEvent; + function GetTerminated: Boolean; + public + constructor Create(CreateSuspended: Boolean = True); + procedure Terminate; + property IsTerminated: Boolean read GetTerminated; + property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; + end; + { THTTPSendThread } THTTPSendThread = class(THTTPSend) private - FOwner: TFMDThread; + FOwner: THTTPThread; FRetryCount: Integer; FGZip: Boolean; FFollowRedirection: Boolean; @@ -22,7 +35,7 @@ THTTPSendThread = class(THTTPSend) procedure SetTimeout(AValue: Integer); procedure OnOwnerTerminate(Sender: TObject); public - constructor Create(AOwner: TFMDThread = nil); + constructor Create(AOwner: THTTPThread = nil); destructor Destroy; override; function HTTPRequest(const Method, URL: String; const Response: TObject = nil): Boolean; function HEAD(const URL: String; const Response: TObject = nil): Boolean; @@ -39,7 +52,7 @@ THTTPSendThread = class(THTTPSend) property GZip: Boolean read FGZip write FGZip; property FollowRedirection: Boolean read FFollowRedirection write FFollowRedirection; property AllowServerErrorResponse: Boolean read FAllowServerErrorResponse write FAllowServerErrorResponse; - property Thread: TFMDThread read FOwner; + property Thread: THTTPThread read FOwner; end; TKeyValuePair = array[0..1] of String; @@ -160,6 +173,25 @@ function MaybeEncodeURL(const AValue: String): String; Result := EncodeURL(Result); end; +{ THTTPThread } + +function THTTPThread.GetTerminated: Boolean; +begin + Result := Self.Terminated; +end; + +constructor THTTPThread.Create(CreateSuspended: Boolean); +begin + inherited Create(CreateSuspended); +end; + +procedure THTTPThread.Terminate; +begin + inherited Terminate; + if Assigned(FOnCustomTerminate) then + FOnCustomTerminate(Self); +end; + { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); @@ -176,7 +208,7 @@ procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); Sock.AbortSocket; end; -constructor THTTPSendThread.Create(AOwner: TFMDThread); +constructor THTTPSendThread.Create(AOwner: THTTPThread); begin inherited Create; KeepAlive := True; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7e5d9bc9b..fa78bd492 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -18,11 +18,11 @@ interface {$else} UTF8Process, {$endif} - SysUtils, Classes, Graphics, Forms, lazutf8classes, LazUTF8, LazFileUtils, - LConvEncoding, strutils, dateutils, fileinfo, base64, fpjson, jsonparser, jsonscanner, + SysUtils, Classes, Graphics, lazutf8classes, LazFileUtils, + LConvEncoding, strutils, dateutils, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, - MultiLog, FPimage, GZIPUtils, uFMDThread, uMisc, httpsendthread, FMDOptions, - simplehtmltreeparser, xquery, xquery_json, ImgInfos, SimpleException; + MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, + simplehtmltreeparser, xquery, xquery_json, ImgInfos; const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -867,7 +867,7 @@ procedure fmdHibernate; implementation uses - {$IFDEF DOWNLOADER}frmMain, WebsiteModules;{$ENDIF} + {$IFDEF DOWNLOADER}WebsiteModules;{$ENDIF} {$IFDEF WINDOWS} // thanks Leledumbo for the code diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fefff0151..fb8dda5ea 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -14,8 +14,8 @@ interface uses - Classes, SysUtils, uBaseUnit, uFMDThread, DBDataProcess, FMDOptions, httpsendthread, - FileUtil, LazFileUtils, strutils, dateutils, RegExpr, httpsend, MultiLog; + Classes, SysUtils, uBaseUnit, DBDataProcess, FMDOptions, httpsendthread, + LazFileUtils, strutils, dateutils, RegExpr, httpsend, MultiLog; type @@ -89,7 +89,7 @@ TMangaInformation = class(TObject) procedure OnTag(NoCaseTag, ActualTag: String); procedure OnText(Text: String); - constructor Create(AOwnerThread: TFMDThread = nil; CreateInfo: Boolean = True); + constructor Create(AOwnerThread: THTTPThread = nil; CreateInfo: Boolean = True); destructor Destroy; override; procedure ClearInfo; function GetDirectoryPage(var Page: Integer; const website: String): Byte; @@ -116,7 +116,7 @@ TMangaInformation = class(TObject) implementation uses - Dialogs, fpJSON, JSONParser, jsonscanner, IniFiles, FastHTMLParser, HTMLUtil, + Dialogs, fpJSON, JSONParser, jsonscanner, FastHTMLParser, HTMLUtil, SynaCode, uMisc, frmMain, WebsiteModules; // ----- TDataProcess ----- @@ -713,7 +713,7 @@ procedure TDataProcess.Sort; { TMangaInformation } -constructor TMangaInformation.Create(AOwnerThread: TFMDThread; CreateInfo: Boolean); +constructor TMangaInformation.Create(AOwnerThread: THTTPThread; CreateInfo: Boolean); begin inherited Create; FHTTP := THTTPSendThread.Create(AOwnerThread); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 43ebd3e31..f6669a63e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -16,9 +16,8 @@ interface uses LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Classes, SysUtils, - ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, uFMDThread, uMisc, - DownloadedChaptersDB, FMDOptions, httpsendthread, dateutils, - strutils; + ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, uMisc, + DownloadedChaptersDB, FMDOptions, httpsendthread, dateutils, strutils; type TDownloadStatusType = ( @@ -40,7 +39,7 @@ TTaskThread = class; { TDownloadThread } - TDownloadThread = class(TFMDThread) + TDownloadThread = class(THTTPThread) private parse: TStringList; public @@ -76,7 +75,7 @@ TDownloadThread = class(TFMDThread) { TTaskThread } - TTaskThread = class(TFMDThread) + TTaskThread = class(THTTPThread) private FCheckAndActiveTaskFlag: Boolean; FCurrentWorkingDir: String; diff --git a/baseunits/uFMDThread.pas b/baseunits/uFMDThread.pas deleted file mode 100644 index 886ec0131..000000000 --- a/baseunits/uFMDThread.pas +++ /dev/null @@ -1,57 +0,0 @@ -{ - File: uFMDThread.pas - License: GPLv2 - This unit is a part of Free Manga Downloader -} - -unit uFMDThread; - -{$mode delphi} - -interface - -uses - Classes, SysUtils; - -type - - { TFMDThread } - - TFMDThread = class(TThread) - private - FOnCustomTerminate: TNotifyEvent; - function GetTerminated: Boolean; - procedure CallCustomTerminate; - public - constructor Create(CreateSuspended: Boolean = True); - procedure Terminate; - property IsTerminated: Boolean read GetTerminated; - property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; - end; - -implementation - -function TFMDThread.GetTerminated: Boolean; -begin - Result := Self.Terminated; -end; - -procedure TFMDThread.CallCustomTerminate; -begin - FOnCustomTerminate(Self); -end; - -constructor TFMDThread.Create(CreateSuspended: Boolean = True); -begin - inherited Create(CreateSuspended); - FreeOnTerminate := True; -end; - -procedure TFMDThread.Terminate; -begin - inherited Terminate; - if Assigned(FOnCustomTerminate) then - Synchronize(CallCustomTerminate); -end; - -end. diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 30a4ffcfb..f5ee006a3 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, fgl, Dialogs, IniFiles, lazutf8classes, LazFileUtils, - FileUtil, uBaseUnit, uData, uDownloadsManager, uFMDThread, uMisc, WebsiteModules, + uBaseUnit, uData, uDownloadsManager, uMisc, WebsiteModules, FMDOptions, httpsendthread, SimpleException; type @@ -22,7 +22,7 @@ TfavoriteContainer = class; { TFavoriteThread } - TFavoriteThread = class(TFMDThread) + TFavoriteThread = class(THTTPThread) protected procedure SyncStatus; procedure Execute; override; @@ -38,7 +38,7 @@ TFavoriteThread = class(TFMDThread) { TFavoriteTask } - TFavoriteTask = class(TFMDThread) + TFavoriteTask = class(THTTPThread) private FBtnCaption: String; FPendingCount: Integer; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 1c2f5ef3f..9f1b19e8a 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -16,13 +16,13 @@ interface uses - SysUtils, Graphics, Dialogs, uBaseUnit, uData, uFMDThread, FMDOptions; + SysUtils, Graphics, Dialogs, uBaseUnit, uData, httpsendthread, FMDOptions; type { TGetMangaInfosThread } - TGetMangaInfosThread = class(TFMDThread) + TGetMangaInfosThread = class(THTTPThread) protected FMangaListPos: Integer; FCover: TPicture; diff --git a/baseunits/uOption.pas b/baseunits/uOption.pas deleted file mode 100644 index 632a228f3..000000000 --- a/baseunits/uOption.pas +++ /dev/null @@ -1,21 +0,0 @@ -unit uOption; - -{$mode delphi} - -interface - -uses - Classes, SysUtils, IniFiles; - -type - TOption = class - public - - protected - - end; - -implementation - -end. - diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 151518b47..6a07b66ba 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -15,7 +15,7 @@ interface uses - Classes, SysUtils, fgl, uBaseUnit, uData, uFMDThread, uDownloadsManager, + SysUtils, fgl, uBaseUnit, uData, uDownloadsManager, WebsiteModules, FMDOptions, httpsendthread, LazFileUtils; type @@ -36,7 +36,7 @@ TSilentThreadManager = class; { TSilentThread } - TSilentThread = class(TFMDThread) + TSilentThread = class(THTTPThread) protected FSavePath: String; Info: TMangaInformation; @@ -63,7 +63,7 @@ TSilentAddToFavThread = class(TSilentThread) { TSilentThreadManagerThread } - TSilentThreadManagerThread = class(TFMDThread) + TSilentThreadManagerThread = class(THTTPThread) protected procedure Checkout; procedure Execute; override; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index d7b899b74..96b7617a3 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -11,7 +11,7 @@ interface uses - Classes, SysUtils, typinfo, uData, LazFileUtils, uBaseUnit, uFMDThread, uMisc, + Classes, SysUtils, typinfo, uData, LazFileUtils, uBaseUnit, uMisc, WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread, MultiLog; type @@ -19,7 +19,7 @@ TUpdateListManagerThread = class; { TUpdateListThread } - TUpdateListThread = class(TFMDThread) + TUpdateListThread = class(THTTPThread) protected Info: TMangaInformation; checkStyle: TCheckStyleType; @@ -36,7 +36,7 @@ TUpdateListThread = class(TFMDThread) { TUpdateListManagerThread } - TUpdateListManagerThread = class(TFMDThread) + TUpdateListManagerThread = class(THTTPThread) private FStatus: String; FCommitCount: Integer; @@ -95,7 +95,7 @@ TUpdateListManagerThread = class(TFMDThread) implementation uses - frmMain, Dialogs, ComCtrls, Forms, Controls; + frmMain, Dialogs, ComCtrls; { TUpdateListThread } diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 4c21d42ad..6dfa9a1eb 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -15,6 +15,7 @@ object AccountManagerForm: TAccountManagerForm OnDestroy = FormDestroy OnShow = FormShow LCLVersion = '1.7' + Visible = False object pnBtContainer: TPanel Left = 299 Height = 300 diff --git a/mangadownloader/forms/frmAccountManager.lrj b/mangadownloader/forms/frmAccountManager.lrj index ec0fc437e..efdf77b0a 100644 --- a/mangadownloader/forms/frmAccountManager.lrj +++ b/mangadownloader/forms/frmAccountManager.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":265040957,"name":"taccountmanagerform.caption","sourcebytes":[65,99,99,111,117,110,116,77,97,110,97,103,101,114,70,111,114,109],"value":"AccountManagerForm"}, {"hash":78392485,"name":"taccountmanagerform.btdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":310020,"name":"taccountmanagerform.btedit.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, {"hash":18340,"name":"taccountmanagerform.btadd.caption","sourcebytes":[65,100,100],"value":"Add"}, diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index d25b47c20..4b4280870 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -6,8 +6,8 @@ interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, - ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, uFMDThread, - uBaseUnit, FMDOptions, httpsendthread, frmAccountSet, SimpleException; + ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, + FMDOptions, HTTPSendThread, frmAccountSet, SimpleException; type @@ -58,7 +58,7 @@ TAccountCheck = class; { TAccountCheckThread } - TAccountCheckThread = class(TFMDThread) + TAccountCheckThread = class(THTTPThread) private fwebsite: String; fhttp: THTTPSendThread; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 7d02f8691..91c37df33 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -343,10 +343,6 @@ msgstr "Edit" msgid "Refresh" msgstr "Refresh" -#: taccountmanagerform.caption -msgid "AccountManagerForm" -msgstr "AccountManagerForm" - #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -2167,3 +2163,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 78beeb10e..1d311aa72 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -341,10 +341,6 @@ msgstr "Ubah" msgid "Refresh" msgstr "Segarkan" -#: taccountmanagerform.caption -msgid "AccountManagerForm" -msgstr "AccountManagerForm" - #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" @@ -2148,3 +2144,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c58d16e24..76bb55dd0 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -306,10 +306,6 @@ msgstr "" msgid "Refresh" msgstr "" -#: taccountmanagerform.caption -msgid "AccountManagerForm" -msgstr "" - #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" diff --git a/updater/uMain.pas b/updater/uMain.pas index 7f4b611f9..414b2347b 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -11,7 +11,7 @@ interface {$endif} Classes, SysUtils, zipper, FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls, RegExpr, IniFiles, blcksock, - ssl_openssl, ssl_openssl_lib, synacode, uFMDThread, httpsendthread, uMisc, + ssl_openssl, ssl_openssl_lib, synacode, httpsendthread, uMisc, SimpleTranslator; type @@ -39,7 +39,7 @@ TfrmMain = class(TForm) { TDownloadThread } - TDownloadThread = class(TFMDThread) + TDownloadThread = class(THTTPThread) private FTotalSize, FCurrentSize: Integer; FHTTP: THTTPSendThread; From 49236540e9762d52be21efbbcc104027319469b6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 9 Aug 2016 01:51:42 +0800 Subject: [PATCH 1371/2794] httpsendthread, remove uses graphics, handle it manually by caller --- baseunits/httpsendthread.pas | 5 +---- baseunits/uGetMangaInfosThread.pas | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 5b802a2ed..66c6f5ef5 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - GZIPUtils, Graphics, RegExpr; + GZIPUtils, RegExpr; type @@ -328,9 +328,6 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: if Response is TStringList then TStringList(Response).LoadFromStream(Document) else - if Response is TPicture then - TPicture(Response).LoadFromStream(Document) - else if Response is TStream then Document.SaveToStream(TStream(Response)); end; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 9f1b19e8a..1717eecbe 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -155,7 +155,9 @@ procedure TGetMangaInfosThread.DoGetInfos; if OptionEnableLoadCover and (Trim(FInfo.mangaInfo.coverLink) <> '') then begin FInfo.FHTTP.Document.Clear; - FIsHasMangaCover := FInfo.FHTTP.GET(FInfo.mangaInfo.coverLink, FCover); + FIsHasMangaCover := FInfo.FHTTP.GET(FInfo.mangaInfo.coverLink); + if FIsHasMangaCover then + FCover.LoadFromStream(FInfo.FHTTP.Document); end else FIsHasMangaCover := False; From 053739771233cea2f99d6f5fe59e021786958d17 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 9 Aug 2016 02:19:22 +0800 Subject: [PATCH 1372/2794] cleanup umisc and move some method to baseunit --- baseunits/DBDataProcess.pas | 2 +- baseunits/uBaseUnit.pas | 99 +++++++++++++++++- baseunits/uData.pas | 6 +- baseunits/uFavoritesManager.pas | 2 +- baseunits/uMisc.pas | 174 +------------------------------- baseunits/uPacker.pas | 2 +- 6 files changed, 105 insertions(+), 180 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 24024385c..0bee7be62 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -138,7 +138,7 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); implementation uses - uBaseUnit, uData, uMisc; + uBaseUnit, uData; function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fa78bd492..056b878ef 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -22,7 +22,7 @@ interface LConvEncoding, strutils, dateutils, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, - simplehtmltreeparser, xquery, xquery_json, ImgInfos; + simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit; const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -842,11 +842,19 @@ procedure CopyImageRect(const Source, Dest: TFPCustomImage; const DestX, DestY: // merge 2 images to one function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; const Landscape: Boolean = False): Boolean; +// sort procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); // This method uses to sort the data. Use when we load all the lists. procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteList); +function NaturalCompareStr(Str1, Str2: String): Integer; inline; +function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; inline; +procedure QuickSortNaturalPart(var Alist: TStringList; Separator: String; + PartIndex: Integer); + +function GetStringPart(const S, Sep: String; PartIndex: Integer): String; + function GetCurrentJDN: Longint; function DateToJDN(const year, month, day: Word): Longint; overload; @@ -3816,6 +3824,95 @@ procedure QuickSortDataWithWebID(var merge: TStringList; const webIDList: TByteL names.Free; end; +function NaturalCompareStr(Str1, Str2: String): Integer; +begin + Result := NaturalSortUnit.UTF8LogicalCompareText(Str1, Str2); +end; + +function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; +begin + Result := NaturalCompareStr(List[Index1], List[Index2]); +end; + +procedure QuickSortNaturalPart(var Alist: TStringList; Separator: String; + PartIndex: Integer); + + function CompareFn(Index1, Index2: Integer): Integer; + begin + Result := NaturalCompareStr(getStringPart(Alist[Index1], Separator, PartIndex), + getStringPart(Alist[Index2], Separator, PartIndex)); + end; + + procedure QSort(L, R: Integer); + var + Pivot, vL, vR: Integer; + begin + if R - L <= 1 then begin // a little bit of time saver + if L < R then + if CompareFn(L, R) > 0 then + Alist.Exchange(L, R); + + Exit; + end; + + vL := L; + vR := R; + + Pivot := L + Random(R - L); // they say random is best + + while vL < vR do begin + while (vL < Pivot) and (CompareFn(vL, Pivot) <= 0) do + Inc(vL); + + while (vR > Pivot) and (CompareFn(vR, Pivot) > 0) do + Dec(vR); + + Alist.Exchange(vL, vR); + + if Pivot = vL then // swap pivot if we just hit it from one side + Pivot := vR + else if Pivot = vR then + Pivot := vL; + end; + + if Pivot - 1 >= L then + QSort(L, Pivot - 1); + if Pivot + 1 <= R then + QSort(Pivot + 1, R); + end; + +begin + if Alist.Count < 2 then Exit; + Alist.BeginUpdate; + try + QSort(0, Alist.Count - 1); + finally + Alist.EndUpdate; + end; +end; + +function GetStringPart(const S, Sep: String; PartIndex: Integer): String; +var + i, j, lpos, rpos: Integer; +begin + lpos := 1; + rpos := 1; + Result := ''; + + for i := 0 to partIndex do + begin + j := PosEx(Sep, S, rpos); + if (j > 0) then + begin + lpos := rpos; + rpos := j + Length(Sep); + end + else + Break; + end; + Result := Copy(S, lpos, rpos - lpos - Length(Sep)); +end; + function DateToJDN(const year, month, day: Word): Longint; var a, y, m: Longint; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fb8dda5ea..1e8431f01 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, DBDataProcess, FMDOptions, httpsendthread, - LazFileUtils, strutils, dateutils, RegExpr, httpsend, MultiLog; + LazFileUtils, strutils, RegExpr, httpsend, MultiLog; type @@ -117,7 +117,7 @@ implementation uses Dialogs, fpJSON, JSONParser, jsonscanner, FastHTMLParser, HTMLUtil, - SynaCode, uMisc, frmMain, WebsiteModules; + SynaCode, frmMain, WebsiteModules; // ----- TDataProcess ----- @@ -708,7 +708,7 @@ procedure TDataProcess.RemoveFilter; procedure TDataProcess.Sort; begin //QuickSortData(data); - uMisc.QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_TITLE); + QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_TITLE); end; { TMangaInformation } diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index f5ee006a3..84d087a2c 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -12,7 +12,7 @@ interface uses Classes, SysUtils, fgl, Dialogs, IniFiles, lazutf8classes, LazFileUtils, - uBaseUnit, uData, uDownloadsManager, uMisc, WebsiteModules, + uBaseUnit, uData, uDownloadsManager, WebsiteModules, FMDOptions, httpsendthread, SimpleException; type diff --git a/baseunits/uMisc.pas b/baseunits/uMisc.pas index 40370c0af..4c563c2a2 100644 --- a/baseunits/uMisc.pas +++ b/baseunits/uMisc.pas @@ -10,23 +10,11 @@ interface {$else} UTF8Process, {$endif} - Classes, SysUtils, Graphics, LazFileUtils, strutils, IniFiles, - NaturalSortUnit; + Classes, SysUtils, strutils; type TArrayOfString = array of String; - TIniFileR = class(TMemIniFile) - private - FCSReload: TRTLCriticalSection; - FFileAge: Longint; - public - constructor Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); - override; - destructor Destroy; override; - procedure Reload; - end; - //String utils procedure VolumeChapterPadZero(var S: String; VolLength, ChapLength: Integer); function padZeros(const S: String; VolLength, ChapLength: Integer): String; inline; @@ -39,12 +27,6 @@ function BrackTextQuoted(const S: Integer): String; overload; inline; function StringToASCII(S: String): String; function StringToHex(S: String): String; -procedure QuickSortNaturalPart(var Alist: TStringList; Separator: String; - PartIndex: Integer); - -//Images -function MangaFoxRemoveWatermarks(const Filename: String): Boolean; - //Searching function FindStrLinear(aList: TStrings; aValue: String): Boolean; function FindStrLinearPos(aList: TStrings; aValue: String): Integer; @@ -52,10 +34,6 @@ function FindStrLinearPos(aList: TStrings; aValue: String): Integer; //formatting function FormatByteSize(const bytes: Longint; persecond: Boolean = False): String; -//sorting -function NaturalCompareStr(Str1, Str2: String): Integer; inline; -function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; inline; - //run external process function RunExternalProcessAsAdmin(Exe, Params: String; ShowWind: Boolean = True; isPersistent: Boolean = True): Boolean; @@ -93,43 +71,6 @@ procedure DeleteArrayOfString(var TheStrings: TArrayOfString; Index: Integer); implementation -{ TIniFileR } - -constructor TIniFileR.Create(const AFileName: String; AEscapeLineFeeds: Boolean = False); -begin - inherited Create(AFileName, AEscapeLineFeeds); - InitCriticalSection(FCSReload); - FFileAge := FileAge(Self.FileName); -end; - -destructor TIniFileR.Destroy; -begin - DoneCriticalsection(FCSReload); - inherited Destroy; -end; - -procedure TIniFileR.Reload; -var - slLines: TStringList; -begin - if TryEnterCriticalSection(FCSReload) then try - if FileExistsUTF8(FileName) then - if FileAgeUTF8(FileName) <> FFileAge then - begin - slLines := TStringList.Create; - try - FFileAge := FileAge(FileName); - slLines.LoadFromFile(FileName); - SetStrings(slLines); - finally - slLines.Free; - end; - end; - finally - LeaveCriticalSection(FCSReload); - end; -end; - { uMisc } function BrackText(const S: String): String; @@ -335,119 +276,6 @@ function padZeros(const S: String; VolLength, ChapLength: Integer): String; VolumeChapterPadZero(Result, VolLength, ChapLength); end; -//loading directly from stream accepted as raw (file become bigger) -//Not all mangafox image has watermarks, old manga doesn't have watermarks -//recognizing by file age or by scanning images manually. -function MangaFoxRemoveWatermarks(const Filename: String): Boolean; -var - fpic: TPicture; -begin - Result := False; - Exit; //Disable for a moment - fpic := TPicture.Create; - try - fpic.LoadFromFile(Filename); - if fpic.Bitmap.Height < 100 then - Exit; - fpic.Bitmap.Height := fpic.Bitmap.Height - 90;// crop by 90px - if FileExistsUTF8(Filename) then - DeleteFileUTF8(Filename); - fpic.SaveToFile(Filename); - Result := True; - finally - fpic.Free; - end; -end; - -function getStringPart(const txt, sep: String; partIndex: Cardinal): String; -var - i, j, lpos, rpos: Integer; -begin - lpos := 1; - rpos := 1; - Result := ''; - - for i := 0 to partIndex do - begin - j := PosEx(sep, txt, rpos); - if (j > 0) then - begin - lpos := rpos; - rpos := j + Length(sep); - end - else - Break; - end; - Result := Copy(txt, lpos, rpos - lpos - Length(sep)); -end; - -function NaturalCompareStr(Str1, Str2: String): Integer; -begin - Result := NaturalSortUnit.UTF8LogicalCompareText(Str1, Str2); -end; - -function NaturalCustomSort(List: TStringList; Index1, Index2: Integer): Integer; -begin - Result := NaturalCompareStr(List[Index1], List[Index2]); -end; - -procedure QuickSortNaturalPart(var Alist: TStringList; Separator: String; - PartIndex: Integer); - - function CompareFn(Index1, Index2: Integer): Integer; - begin - Result := NaturalCompareStr(getStringPart(Alist[Index1], Separator, PartIndex), - getStringPart(Alist[Index2], Separator, PartIndex)); - end; - - procedure QSort(L, R: Integer); - var - Pivot, vL, vR: Integer; - begin - if R - L <= 1 then begin // a little bit of time saver - if L < R then - if CompareFn(L, R) > 0 then - Alist.Exchange(L, R); - - Exit; - end; - - vL := L; - vR := R; - - Pivot := L + Random(R - L); // they say random is best - - while vL < vR do begin - while (vL < Pivot) and (CompareFn(vL, Pivot) <= 0) do - Inc(vL); - - while (vR > Pivot) and (CompareFn(vR, Pivot) > 0) do - Dec(vR); - - Alist.Exchange(vL, vR); - - if Pivot = vL then // swap pivot if we just hit it from one side - Pivot := vR - else if Pivot = vR then - Pivot := vL; - end; - - if Pivot - 1 >= L then - QSort(L, Pivot - 1); - if Pivot + 1 <= R then - QSort(Pivot + 1, R); - end; - -begin - if Alist.Count < 2 then Exit; - Alist.BeginUpdate; - try - QSort(0, Alist.Count - 1); - finally - Alist.EndUpdate; - end; -end; - function FindStrLinearPos(aList: TStrings; aValue: String): Integer; var i: Integer; diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 80bb98310..775bef597 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -12,7 +12,7 @@ interface uses Classes, Zipper, zstream, SysUtils, uBaseUnit, Img2Pdf, FileUtil, lazutf8classes, - LazFileUtils, SimpleException, uMisc; + LazFileUtils, SimpleException; type TPackerFormat = (pfZIP, pfCBZ, pfPDF); From ba8318129a60efd822a6d34a9d8b18ec8bde2533 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 9 Aug 2016 23:48:44 +0800 Subject: [PATCH 1373/2794] thttpthread, freeonterminate --- baseunits/httpsendthread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 66c6f5ef5..64b8624d5 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -183,6 +183,7 @@ function THTTPThread.GetTerminated: Boolean; constructor THTTPThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); + FreeOnTerminate := True; end; procedure THTTPThread.Terminate; From 5efc2fbe155b715a58e4ddd8a1ce621fec3d65eb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 10 Aug 2016 11:57:28 +0800 Subject: [PATCH 1374/2794] dbdataprocess, forcedirectories when creating new database #345 --- baseunits/DBDataProcess.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 0bee7be62..da029a883 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -1102,8 +1102,11 @@ procedure TDBDataProcess.CreateDatabase(AWebsite: String); filepath := DATA_FOLDER + FWebsite + DBDATA_EXT; if FileExistsUTF8(filepath) then DeleteFileUTF8(filepath); - InternalOpen(filepath); - CreateTable; + if ForceDirectoriesUTF8(DATA_FOLDER) then + begin + InternalOpen(filepath); + CreateTable; + end; end; procedure TDBDataProcess.GetFieldNames(List: TStringList); From 3825f696e34bd1b203789a8f4d126251d9ebfbec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 10 Aug 2016 12:35:37 +0800 Subject: [PATCH 1375/2794] httpsendthread, added common useragent const --- baseunits/httpsendthread.pas | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 64b8624d5..dffa8e16d 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -66,9 +66,19 @@ procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); function MaybeEncodeURL(const AValue: String): String; +const + UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; + UserAgentCURL = 'curl/7.42.1'; + UserAgentGooglebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; + UserAgentInternetExplorer = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; + UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0'; + UserAgentChrome = + 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'; + UserAgentOpera = + 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48'; + var - DefaultUserAgent: String = - 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36'; + DefaultUserAgent: String = UserAgentChrome; DefaultRetryCount: Integer = 0; DefaultTimeout: Integer = 15000; DefaultProxyType: String = ''; From 10b1e3af4eea81de0074161d08cfdbdc35c9e4d7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 10 Aug 2016 12:45:09 +0800 Subject: [PATCH 1376/2794] httpsendthread, fixed repair redirected url --- baseunits/httpsendthread.pas | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index dffa8e16d..411af08ae 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -298,10 +298,16 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: with TRegExpr.Create do try Expression := '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - if Replace(s, '$1', True) = '' then begin - if s[1] <> '/' then s := '/' + s; + if Replace(s, '$1', True) = '' then + begin + while s[1] = '.' do + Delete(s, 1, 1); + if (s <> '') and (s[1] <> '/') then + s := '/' + s; rurl := Replace(rurl, '$1$2$3', True) + s; - end else rurl := s; + end + else + rurl := s; finally Free; end; From 445dfe53b4f05bf77a83a4b11986304654a673ab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 10 Aug 2016 13:23:41 +0800 Subject: [PATCH 1377/2794] rewrite mangatraders code, remove old code and merge with mangalife module #345 --- .../MangaTraders/chapter_page_number.inc | 36 ----- baseunits/includes/MangaTraders/image_url.inc | 33 ----- .../MangaTraders/manga_information.inc | 112 ---------------- .../includes/MangaTraders/names_and_links.inc | 46 ------- baseunits/modules/MangaLife.pas | 44 ++++-- baseunits/uBaseUnit.pas | 125 +++++++++--------- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 10 -- 8 files changed, 93 insertions(+), 328 deletions(-) delete mode 100644 baseunits/includes/MangaTraders/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaTraders/image_url.inc delete mode 100644 baseunits/includes/MangaTraders/manga_information.inc delete mode 100644 baseunits/includes/MangaTraders/names_and_links.inc diff --git a/baseunits/includes/MangaTraders/chapter_page_number.inc b/baseunits/includes/MangaTraders/chapter_page_number.inc deleted file mode 100644 index 7d8e73730..000000000 --- a/baseunits/includes/MangaTraders/chapter_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetMangaTradersPageNumber: Boolean; - var - isGetPageNumber: Boolean = False; - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGATRADERS_ID, URL); - s := s + '/page-1'; - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if Pos('<select', parse[i]) > 0 then - isGetPageNumber := True; - if isGetPageNumber and (Pos('</select', parse[i]) > 0) then - begin - isGetPageNumber := False; - Break; - end; - if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaTraders/image_url.inc b/baseunits/includes/MangaTraders/image_url.inc deleted file mode 100644 index 084dfb77e..000000000 --- a/baseunits/includes/MangaTraders/image_url.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangaTradersImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGATRADERS_ID, URL); - s := s + '/page-' + IntToStr(WorkId + 1); - Result := GetPage(TObject(l), s, Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then - begin - //fix line - parse[i] := RemoveBreaks(parse[i]); - if Pos(#9, parse[i]) > 0 then - parse[i] := StringReplace(parse[i], #9, ' ', [rfReplaceAll, rfIgnoreCase]); - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaTraders/manga_information.inc b/baseunits/includes/MangaTraders/manga_information.inc deleted file mode 100644 index 0aef311d3..000000000 --- a/baseunits/includes/MangaTraders/manga_information.inc +++ /dev/null @@ -1,112 +0,0 @@ - function GetMangaTradersInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - i: Integer; - regx: TRegExpr; - begin - mangaInfo.website := WebsiteRoots[MANGATRADERS_ID, 0]; - // fixing url - mangaInfo.url := FillMangaSiteHost(MANGATRADERS_ID, URL); - regx := TRegExpr.Create; - try - regx.Expression := '\/manga\/\?series\=(.*)$'; - if regx.Exec(mangaInfo.url) then - mangaInfo.url := regx.Replace(mangaInfo.url, '/read-online/$1', True); - finally - regx.Free; - end; - - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - begin - Parser.Free; - Source.Free; - Exit; - end; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.summary := ''; - - regx := TRegExpr.Create; - regx.Expression := '\/page\-\d+$'; - for i := 0 to parse.Count - 1 do - begin - //title - if Pos('<h1', parse[i]) > 0 then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //cover - if Pos('property="og:image:url"', parse[i]) > 0 then - mangaInfo.coverLink := GetVal(parse[i], 'content'); - - //author - if Pos('<b', parse[i]) > 0 then - if Pos('Author:', parse[i + 1]) > 0 then - mangaInfo.authors := CommonStringFilter(parse[i + 4]); - - //status - if Pos('<b', parse[i]) > 0 then - if Pos('Publishing Status:', parse[i + 1]) > 0 then - begin - if LowerCase(Trim(parse[i + 3])) = 'ongoing' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - - //genres - if Pos('Genre:', parse[i]) > 0 then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - if isExtractGenres and (Pos('</div', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('Genre:', parse[i]) = 0) and - (Pos('<', parse[i]) = 0) then - mangaInfo.genres := mangaInfo.genres + parse[i]; - - //description - if Pos('Description:', parse[i]) > 0 then - mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 4])); - - //chapters - if (Pos('<a', parse[i]) > 0) and (Pos('/chapter-', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - if regx.Exec(s) then - s := regx.Replace(s, '', False); - mangaInfo.chapterLinks.Add(s); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - regx.Free; - - //remove duplicate links - RemoveDuplicateStrings([mangaInfo.chapterLinks, mangaInfo.chapterName]); - //inverts - InvertStrings(mangaInfo.chapterLinks); - InvertStrings(mangaInfo.chapterName); - - Parser.Free; - Source.Free; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaTraders/names_and_links.inc b/baseunits/includes/MangaTraders/names_and_links.inc deleted file mode 100644 index 54e9b8d96..000000000 --- a/baseunits/includes/MangaTraders/names_and_links.inc +++ /dev/null @@ -1,46 +0,0 @@ - function MangaTradersGetNamesAndLinks: Byte; - var - i: Integer; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGATRADERS_ID, 1] + - MANGATRADERS_BROWSER , 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - regx := TRegExpr.Create; - try - regx.Expression := '\/manga\/\?series\=(.*)$'; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="seriesList', parse[i]) > 0 then - begin - Result := NO_ERROR; - names.Add(CommonStringFilter(parse[i + 3])); - s := TrimLeftChar(GetVal(parse[i + 2], 'href'), ['.']); - if regx.Exec(s) then - s := regx.Replace(s, '/read-online/$1', True); - links.Add(s); - end; - end; - finally - regx.Free; - end; - Source.Free; - end; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 8c7725234..460cfd982 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -22,7 +22,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; - if Module.Website = 'MangaSee' then + if (Module.Website = 'MangaSee') or (Module.Website = 'MangaTraders') then Page := Length(diralpha) else Page := 1; @@ -30,9 +30,10 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; function fixcleanurl(const u: string): string; begin - result:=u; - if pos('../',result)<>0 then - result:=stringreplace(result,'../','/',[]); + Result := u; + if Result = '' then Exit; + while Result[1] = '.' do + Delete(Result, 1, 1); end; function GetNameAndLink(const MangaInfo: TMangaInformation; @@ -48,9 +49,15 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; s += dirURLmangasee else s+=dirURL; - //mangasee if AURL <> '0' then - s += '?c=' + diralpha[StrToInt(AURL) + 1]; + begin + if Module.Website = 'MangaSee' then + s += '?c=' + else + if Module.Website = 'MangaTraders' then + s += '?start='; + s += diralpha[StrToIntDef(AURL, 0) + 1] + end; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; @@ -80,6 +87,7 @@ function GetInfo(const MangaInfo: TMangaInformation; var v: IXQValue; s: String; + i: Integer; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -100,16 +108,25 @@ function GetInfo(const MangaInfo: TMangaInformation; 'completed'); genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre:")]'), ':'); summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description:")]'), ':')); - if Module.Website = 'MangaSee' then - s := 'div.col-lg-12:nth-child(8)>div>div:nth-child(1)>a' + if Module.Website = 'MangaTraders' then + v := XPath('//div[@class="well"]/div[@class="row"]/div/a[contains(@href,"/read-online/") and not(@class)]') else - s := 'div.list>div>div>a'; - for v in CSS(s) do begin - chapterLinks.Add(fixchapterurl(v.toNode.getAttribute('href'))); - chapterName.Add(v.toString); + if Module.Website = 'MangaSee' then + s := 'div.col-lg-12:nth-child(8)>div>div:nth-child(1)>a' + else + s := 'div.list>div>div>a'; + v := CSS(s) + end; + if v.Count > 0 then + begin + for i := 1 to v.Count do + begin + chapterLinks.Add(fixchapterurl(v.get(i).toNode.getAttribute('href'))); + chapterName.Add(v.get(i).toString); + end; + InvertStrings([chapterLinks, chapterName]); end; - InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -158,6 +175,7 @@ procedure RegisterModule; begin AddWebsiteModule('MangaLife', 'http://manga.life'); AddWebsiteModule('MangaSee', 'http://mangasee.co'); + AddWebsiteModule('MangaTraders', 'http://mangatraders.org') end; initialization diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 056b878ef..a06762707 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -236,75 +236,74 @@ interface VNSHARING_ID = 3; FAKKU_ID = 4; TRUYEN18_ID = 5; - MANGATRADERS_ID = 6; - TRUYENTRANHTUAN_ID = 7; - TURKCRAFT_ID = 8; - EATMANGA_ID = 9; - STARKANA_ID = 10; - BLOGTRUYEN_ID = 11; - KOMIKID_ID = 12; - ESMANGAHERE_ID = 13; - ANIMEEXTREMIST_ID = 14; - HUGEMANGA_ID = 15; - S2SCAN_ID = 16; - IMANHUA_ID = 17; - MABUNS_ID = 18; - MANGAESTA_ID = 19; - CENTRALDEMANGAS_ID = 20; - EGSCANS_ID = 21; - MANGAAR_ID = 22; - MANGAAE_ID = 23; - ANIMESTORY_ID = 24; - LECTUREENLIGNE_ID = 25; - SCANMANGA_ID = 26; - MANGAGO_ID = 27; - DM5_ID = 28; - MANGACOW_ID = 29; - KIVMANGA_ID = 30; - MEINMANGA_ID = 31; - MANGASPROJECT_ID = 32; - MANGAREADER_POR_ID = 33; - NINEMANGA_ID = 34; - NINEMANGA_ES_ID = 35; - NINEMANGA_CN_ID = 36; - NINEMANGA_RU_ID = 37; - NINEMANGA_DE_ID = 38; - NINEMANGA_IT_ID = 39; - NINEMANGA_BR_ID = 40; - JAPANSHIN_ID = 41; - JAPSCAN_ID = 42; - CENTRUMMANGI_PL_ID = 43; - MANGALIB_PL_ID = 44; - ONEMANGA_ID = 45; - MANGATOWN_ID = 46; - MANGAOKU_ID = 47; - MYREADINGMANGAINFO_ID = 48; - IKOMIK_ID = 49; - NHENTAI_ID = 50; - MANGAMINT_ID = 51; - UNIXMANGA_ID = 52; - EXTREMEMANGAS_ID = 53; - MANGAHOST_ID = 54; - PORNCOMIX_ID = 55; - PORNCOMIXRE_ID = 56; - PORNCOMIXIC_ID = 57; - XXCOMICS_ID = 58; - XXCOMICSMT_ID = 59; - XXCOMICS3D_ID = 60; - PORNXXXCOMICS_ID = 61; - MANGAKU_ID = 62; - MANGAAT_ID = 63; - READMANGATODAY_ID = 64; - DYNASTYSCANS_ID = 65; - - WebsiteRoots: array [0..65] of array [0..1] of String = ( + + TRUYENTRANHTUAN_ID = 6; + TURKCRAFT_ID = 7; + EATMANGA_ID = 8; + STARKANA_ID = 9; + BLOGTRUYEN_ID = 10; + KOMIKID_ID = 11; + ESMANGAHERE_ID = 12; + ANIMEEXTREMIST_ID = 13; + HUGEMANGA_ID = 14; + S2SCAN_ID = 15; + IMANHUA_ID = 16; + MABUNS_ID = 17; + MANGAESTA_ID = 18; + CENTRALDEMANGAS_ID = 19; + EGSCANS_ID = 20; + MANGAAR_ID = 21; + MANGAAE_ID = 22; + ANIMESTORY_ID = 23; + LECTUREENLIGNE_ID = 24; + SCANMANGA_ID = 25; + MANGAGO_ID = 26; + DM5_ID = 27; + MANGACOW_ID = 28; + KIVMANGA_ID = 29; + MEINMANGA_ID = 30; + MANGASPROJECT_ID = 31; + MANGAREADER_POR_ID = 32; + NINEMANGA_ID = 33; + NINEMANGA_ES_ID = 34; + NINEMANGA_CN_ID = 35; + NINEMANGA_RU_ID = 36; + NINEMANGA_DE_ID = 37; + NINEMANGA_IT_ID = 38; + NINEMANGA_BR_ID = 39; + JAPANSHIN_ID = 40; + JAPSCAN_ID = 41; + CENTRUMMANGI_PL_ID = 42; + MANGALIB_PL_ID = 43; + ONEMANGA_ID = 44; + MANGATOWN_ID = 45; + MANGAOKU_ID = 46; + MYREADINGMANGAINFO_ID = 47; + IKOMIK_ID = 48; + NHENTAI_ID = 49; + MANGAMINT_ID = 50; + UNIXMANGA_ID = 51; + EXTREMEMANGAS_ID = 52; + MANGAHOST_ID = 53; + PORNCOMIX_ID = 54; + PORNCOMIXRE_ID = 55; + PORNCOMIXIC_ID = 56; + XXCOMICS_ID = 57; + XXCOMICSMT_ID = 58; + XXCOMICS3D_ID = 59; + PORNXXXCOMICS_ID = 60; + MANGAKU_ID = 61; + MANGAAT_ID = 62; + READMANGATODAY_ID = 63; + DYNASTYSCANS_ID = 64; + + WebsiteRoots: array [0..64] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Fakku', 'https://www.fakku.net'), ('Truyen18', 'http://www.truyen18.org'), - ('MangaTraders', 'http://mangatraders.org'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), ('EatManga', 'http://eatmanga.com'), diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1e8431f01..c1b54f3af 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -778,8 +778,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/Fakku/directory_page_number.inc} - //{$I includes/MangaTraders/directory_page_number.inc} - {$I includes/MangaGo/directory_page_number.inc} {$I includes/BlogTruyen/directory_page_number.inc} @@ -859,9 +857,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St if WebsiteID = FAKKU_ID then Result := GetFakkuDirectoryPageNumber else - //if WebsiteID = MANGATRADERS_ID then - // Result := GetMangaTradersDirectoryPageNumber - //else if WebsiteID = MANGAGO_ID then Result := GetMangaGoDirectoryPageNumber else @@ -968,8 +963,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Fakku/names_and_links.inc} - {$I includes/MangaTraders/names_and_links.inc} - {$I includes/TruyenTranhTuan/names_and_links.inc} {$I includes/Komikid/names_and_links.inc} @@ -1082,9 +1075,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = FAKKU_ID then Result := FakkuGetNamesAndLinks else - if WebsiteID = MANGATRADERS_ID then - Result := MangaTradersGetNamesAndLinks - else if WebsiteID = STARKANA_ID then Result := StarkanaGetNamesAndLinks else @@ -1270,8 +1260,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/Fakku/manga_information.inc} - {$I includes/MangaTraders/manga_information.inc} - {$I includes/Starkana/manga_information.inc} {$I includes/EatManga/manga_information.inc} @@ -1396,9 +1384,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = FAKKU_ID then Result := GetFakkuInfoFromURL else - if WebsiteID = MANGATRADERS_ID then - Result := GetMangaTradersInfoFromURL - else if WebsiteID = STARKANA_ID then Result := GetStarkanaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index f6669a63e..157d18d61 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -425,8 +425,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaGo/chapter_page_number.inc} - {$I includes/MangaTraders/chapter_page_number.inc} - {$I includes/MeinManga/chapter_page_number.inc} {$I includes/S2Scans/chapter_page_number.inc} @@ -490,9 +488,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAPageNumber else - if Task.Container.MangaSiteID = MANGATRADERS_ID then - Result := GetMangaTradersPageNumber - else if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaPageNumber else @@ -658,8 +653,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangasPROJECT/image_url.inc} - {$I includes/MangaTraders/image_url.inc} - {$I includes/ScanManga/image_url.inc} {$I includes/Starkana/image_url.inc} @@ -714,9 +707,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAImageURL else - if Task.Container.MangaSiteID = MANGATRADERS_ID then - Result := GetMangaTradersImageURL - else if Task.Container.MangaSiteID = MANGA24H_ID then Result := GetManga24hImageURL else From 0e34f91724b82bea72ce5e8eeb7fe7f866141d57 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 10 Aug 2016 14:54:28 +0800 Subject: [PATCH 1378/2794] downloadmanager, reformat task status, move chapter downloaded progress to front for easier read --- baseunits/uDownloadsManager.pas | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 157d18d61..17f792b64 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -881,8 +881,8 @@ function TTaskThread.GetFileName(const AWorkId: Integer): String; procedure TTaskThread.MainThreadCompressRepaint; begin Container.DownloadInfo.Status := - Format('%s (%d/%d)', [RS_Compressing, Container.CurrentDownloadChapterPtr + - 1, Container.ChapterLinks.Count]); + Format('[%d/%d] %s', [Container.CurrentDownloadChapterPtr + 1, + Container.ChapterLinks.Count, RS_Compressing]); MainForm.vtDownload.Repaint; end; @@ -1223,10 +1223,10 @@ procedure TTaskThread.Execute; Container.DownloadInfo.iProgress := 0; Container.DownloadInfo.Progress := '0/0'; Container.DownloadInfo.Status := - Format('%s (%d/%d [%s])', - [RS_Preparing, - Container.CurrentDownloadChapterPtr + 1, + Format('[%d/%d] %s (%s)', + [Container.CurrentDownloadChapterPtr + 1, Container.ChapterLinks.Count, + RS_Preparing, Container.ChapterName[Container.CurrentDownloadChapterPtr]]); Container.Status := STATUS_PREPARE; CheckOut; @@ -1311,10 +1311,10 @@ procedure TTaskThread.Execute; Format('%d/%d', [Container.DownCounter, Container.PageNumber]); Container.Status := STATUS_DOWNLOAD; Container.DownloadInfo.Status := - Format('%s (%d/%d) [%s]', - [RS_Downloading, - Container.CurrentDownloadChapterPtr + 1, + Format('[%d/%d] %s (%s)', + [Container.CurrentDownloadChapterPtr + 1, Container.ChapterLinks.Count, + RS_Downloading, Container.ChapterName[Container.CurrentDownloadChapterPtr]]); while Container.WorkCounter < Container.PageLinks.Count do begin @@ -1425,8 +1425,8 @@ procedure TTaskThread.DoTerminate; begin Status := STATUS_STOP; DownloadInfo.Status := - Format('%s (%d/%d)', [RS_Stopped, CurrentDownloadChapterPtr + - 1, ChapterLinks.Count]); + Format('[%d/%d] %s', [CurrentDownloadChapterPtr + 1, + ChapterLinks.Count, RS_Stopped]); FCheckAndActiveTaskFlag := False; end; Synchronize(SyncStop); From 6a2fc779717c59f1e5abe7b64f63ceca431a752d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 10 Aug 2016 15:15:56 +0800 Subject: [PATCH 1379/2794] frmmain, fixed margin --- mangadownloader/forms/frmMain.lfm | 40 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 7d1e18fca..2b86311b3 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -5,8 +5,6 @@ object MainForm: TMainForm Width = 771 ActiveControl = pcMain Caption = 'Free Manga Downloader' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 ClientHeight = 587 ClientWidth = 771 OnClose = FormClose @@ -18,10 +16,10 @@ object MainForm: TMainForm LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar - Left = 4 + Left = 0 Height = 30 - Top = 553 - Width = 763 + Top = 557 + Width = 771 AutoSize = False Panels = < item @@ -36,8 +34,8 @@ object MainForm: TMainForm end object pcMain: TPageControl Left = 201 - Height = 512 - Top = 15 + Height = 520 + Top = 11 Width = 566 ActivePage = tsDownload Align = alClient @@ -54,13 +52,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 object vtDownload: TVirtualStringTree AnchorSideTop.Control = edDownloadsSearch AnchorSideTop.Side = asrBottom Left = 4 - Height = 448 + Height = 456 Top = 31 Width = 549 Anchors = [akTop, akLeft, akRight, akBottom] @@ -4071,18 +4069,18 @@ object MainForm: TMainForm end end object pnMainTop: TPanel - Left = 4 + Left = 0 Height = 8 - Top = 4 - Width = 763 + Top = 0 + Width = 771 Align = alTop TabOrder = 1 Visible = False end object pcLeft: TPageControl Left = 4 - Height = 510 - Top = 16 + Height = 518 + Top = 12 Width = 195 ActivePage = tsMangaList Align = alLeft @@ -4098,7 +4096,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 482 + ClientHeight = 490 ClientWidth = 187 object vtMangaList: TVirtualStringTree AnchorSideLeft.Control = lbMode @@ -4107,7 +4105,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btRemoveFilter AnchorSideRight.Side = asrBottom Left = 4 - Height = 393 + Height = 401 Top = 85 Width = 179 Anchors = [akTop, akLeft, akRight, akBottom] @@ -4410,10 +4408,10 @@ object MainForm: TMainForm end end object sbMain: TStatusBar - Left = 4 + Left = 0 Height = 23 - Top = 530 - Width = 763 + Top = 534 + Width = 771 Panels = < item Width = 195 @@ -4426,8 +4424,8 @@ object MainForm: TMainForm end object spMainSplitter: TSplitter Left = 199 - Height = 518 - Top = 12 + Height = 526 + Top = 8 Width = 2 OnMoved = spMainSplitterMoved end From f3bdfe863596c89249ae442a1a904d0ad34e1b73 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 12 Aug 2016 11:42:57 +0800 Subject: [PATCH 1380/2794] wpmanga, break get info subpage if thread terminate --- baseunits/modules/WPManga.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index d9c2eaede..b8344ac9f 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -201,10 +201,13 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; pagecount := StrToIntDef(s, 1); if pagecount > 1 then for i := 2 to pagecount do + begin + if MangaInfo.FHTTP.Thread.IsTerminated then Break; if GET(url + 'chapter-list/' + IntToStr(i) + '/') then begin query.ParseHTML(StreamToString(Document)); scanchapters; end; + end; end; if Module.Website <> 'EyeOnManga' then InvertStrings([chapterLinks, chapterName]); From 0406255765b9f5b5ad5c0346ab4add80ad548f29 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 12 Aug 2016 12:39:32 +0800 Subject: [PATCH 1381/2794] rewrite all mangaindo code, website completely changed closed #326 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaIndo.pas | 136 ++++++++++++++++++++++++++++++++ baseunits/modules/WPManga.pas | 37 +-------- 3 files changed, 141 insertions(+), 35 deletions(-) create mode 100644 baseunits/modules/MangaIndo.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ad56d9d53..e5ebed902 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -44,4 +44,5 @@ uses SenManga, MangaInn, LeoManga, - MangaPark; + MangaPark, + MangaIndo; diff --git a/baseunits/modules/MangaIndo.pas b/baseunits/modules/MangaIndo.pas new file mode 100644 index 000000000..7cc977c29 --- /dev/null +++ b/baseunits/modules/MangaIndo.pas @@ -0,0 +1,136 @@ +unit MangaIndo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/manga-list2/'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="entry-content"]/div/ul/li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + p: LongInt; + i: Integer; + + procedure ScanChapters; + var + v: IXQValue; + begin + with MangaInfo.mangaInfo, query do + for v in XPath('//ul[@class="lcp_catlist"]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + end; + +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(Document); + with query do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@id="main"]//img/@src')); + if title = '' then title := XPathString('//div[@class="title"]/h2'); + artists := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Artist:")]'),':')); + authors := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Author:")]'),':')); + genres := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Genre:")]'),':')); + status := MangaInfoStatusIfPos(XPathString( + '//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Genre:")]'), + 'Ongoing', + 'Completed'); + summary := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p[starts-with(.,"Synopsis:")]'), ':')); + ScanChapters; + p := StrToIntDef(XPathString('(//ul[@class="lcp_paginator"]/li/a[.!=">>"])[last()]') , 1); + if p > 1 then + for i := 2 to p do + begin + if Thread.IsTerminated then Break; + if GET(AppendURLDelim(url) + '?lcp_page0=' + IntToStr(i)) then + begin + ParseHTML(Document); + ScanChapters; + end; + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//div[@id="main"]//div[@class="entry-content"]//img/@src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaIndo'; + RootURL := 'http://mangaindo.web.id'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index b8344ac9f..8cfec5540 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -12,15 +12,11 @@ implementation const dirURL = '/manga-list/all/any/last-added/'; - dirURLmangaindo = '/daftar-manga/all/any/last-added/'; dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; dirURLmangahen = '/manga_list/all/any/last-added/'; function GetDirURL(const AWebsite: String): String; begin - if AWebsite = 'MangaIndo' then - Result := dirURLmangaindo - else if AWebsite = 'ReadHentaiManga' then Result := dirURLreadhentaimanga else @@ -69,13 +65,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - if Module.Website = 'MangaIndo' then begin - for v in XPath('//*[@id="sct_content"]//div[@class="node"]/a[1]/@href') do - ALinks.Add(v.toString); - for v in XPath('//*[@id="sct_content"]//div[@class="node"]/div[1]') do - ANames.Add(v.toString); - end - else if Module.Website = 'ReadHentaiManga' then + if Module.Website = 'ReadHentaiManga' then for v in XPath('//*[@id="content"]//*[@id="center"]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toNode.getAttribute('title')); @@ -159,24 +149,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; end; end; - procedure scaninfomangaindo; - begin - with MangaInfo.mangaInfo, query do begin - summary := XPathString('//*[@class="wpm_pag mng_det"]/p[1]'); - authors := getwpmangavalue('Penulis'); - artists := getwpmangavalue('Seniman'); - genres := getwpmangavalue('Kategori'); - status := getwpmangavalue('Status'); - if status <> '' then begin - status := LowerCase(status); - if Pos('berjalan', status) > 0 then status := '1' - else if Pos('tamat', status) > 0 then status := '0' - else status := ''; - end; - end; - scanchapters; - end; - begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; @@ -193,8 +165,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; coverLink := query.XPathString('//img[starts-with(@class,"cvr")]/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); title := query.XPathString('//*[@itemprop="itemreviewed"]'); - if Module.Website = 'MangaIndo' then scaninfomangaindo - else scaninfo; + scaninfo; s := query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); if s <> '' then begin s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); @@ -212,8 +183,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; if Module.Website <> 'EyeOnManga' then InvertStrings([chapterLinks, chapterName]); { add missing chapter number } - //if (Module.Website = 'EyeOnManga') or - // (Module.Website = 'MangaIndo') and + //if (Module.Website = 'EyeOnManga') and // (chapterName.Count > 0) then // for i := 0 to chapterName.Count - 1 do // chapterName[i] := 'Ch.' + IncStr(i) + ' ' + chapterName[i]; @@ -337,7 +307,6 @@ procedure RegisterModule; AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com'); AddWebsiteModule('Authrone', 'http://www.authrone.com'); AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); - AddWebsiteModule('MangaIndo', 'http://mangaindo.id'); AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); From 02a07b1f6a5c10603246950613f215ded4c6e04e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 12 Aug 2016 13:46:17 +0800 Subject: [PATCH 1382/2794] removed mangajoy, added funmanga module website changed entirely closed #324 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/FunManga.pas | 131 +++++++++++++++++++++++++++++++++ baseunits/modules/WPManga.pas | 1 - config/mangalist.ini | 2 +- 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 baseunits/modules/FunManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e5ebed902..f8e1c9fc4 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -45,4 +45,5 @@ uses MangaInn, LeoManga, MangaPark, - MangaIndo; + MangaIndo, + FunManga; diff --git a/baseunits/modules/FunManga.pas b/baseunits/modules/FunManga.pas new file mode 100644 index 000000000..4b84bb660 --- /dev/null +++ b/baseunits/modules/FunManga.pas @@ -0,0 +1,131 @@ +unit FunManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/manga-list'; + diralpha = '#abcdefghijklmnopqrstuvwxyz'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := Length(diralpha); +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; + v: IXQValue; +begin + Result := NET_PROBLEM; + s := Module.RootURL + dirurl; + if AURL <> '0' then + s := s + '/' + diralpha[StrToIntDef(AURL, 0) + 1] ; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="content"]/div/div[@class="row"]//li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="content"]//img/@src')); + if title = '' then title := XPathString('//div[@class="content"]//h5'); + authors := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Author")]/following-sibling::dd[1]/a'); + artists := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Artist")]/following-sibling::dd[1]/a'); + genres := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Categories")]/following-sibling::dd[1]/a'); + status := MangaInfoStatusIfPos(XPathString( + '//dl[@class="dl-horizontal"]/dt[starts-with(.,"Status")]/following-sibling::dd[1]'), + 'Ongoing', + 'Completed'); + summary := XPathString('//div[@class="content"]/div/div[contains(@class,"note")]'); + for v in XPath('//ul[@class="chapter-list"]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('span[1]', v)); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + s := MaybeFillHost(Module.RootURL, AURL); + if Pos('/all-pages', s) = 0 then + s := s + '/all-pages'; + if GET(s) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//div[contains(@class,"content-inner")]/img/@src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'FunManga'; + RootURL := 'http://funmanga.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 8cfec5540..e11b024b2 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -310,7 +310,6 @@ procedure RegisterModule; AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); - AddWebsiteModule('MangaJoy', 'http://manga-joy.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 6edd68c28..2664e552d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaJoy,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From b77fa0312e5c637284507b77905a34962b463859 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 12 Aug 2016 13:46:33 +0800 Subject: [PATCH 1383/2794] cleanup --- mangadownloader/forms/frmCustomColor.lfm | 5 +---- mangadownloader/forms/frmCustomColor.lrj | 1 - mangadownloader/languages/fmd.en.po | 4 ---- mangadownloader/languages/fmd.id_ID.po | 4 ---- mangadownloader/languages/fmd.po | 4 ---- 5 files changed, 1 insertion(+), 17 deletions(-) diff --git a/mangadownloader/forms/frmCustomColor.lfm b/mangadownloader/forms/frmCustomColor.lfm index 15b4b4559..79e4e8fd8 100644 --- a/mangadownloader/forms/frmCustomColor.lfm +++ b/mangadownloader/forms/frmCustomColor.lfm @@ -10,6 +10,7 @@ object CustomColorForm: TCustomColorForm ClientWidth = 535 OnCreate = FormCreate LCLVersion = '1.7' + Visible = False object CBColors: TColorBox AnchorSideRight.Control = btColors Left = 363 @@ -68,7 +69,6 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 - Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 @@ -100,7 +100,6 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 - Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 @@ -132,7 +131,6 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 - Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 @@ -164,7 +162,6 @@ object CustomColorForm: TCustomColorForm Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 - Header.Height = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 diff --git a/mangadownloader/forms/frmCustomColor.lrj b/mangadownloader/forms/frmCustomColor.lrj index 5cd228657..21b8ce672 100644 --- a/mangadownloader/forms/frmCustomColor.lrj +++ b/mangadownloader/forms/frmCustomColor.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":164667949,"name":"tcustomcolorform.caption","sourcebytes":[67,117,115,116,111,109,67,111,108,111,114,70,111,114,109],"value":"CustomColorForm"}, {"hash":257144884,"name":"tcustomcolorform.tsbasiclist.caption","sourcebytes":[66,97,115,105,99,32,108,105,115,116],"value":"Basic list"}, {"hash":221522148,"name":"tcustomcolorform.tsmangalist.caption","sourcebytes":[77,97,110,103,97,32,108,105,115,116],"value":"Manga list"}, {"hash":117201380,"name":"tcustomcolorform.tsfavoritelist.caption","sourcebytes":[70,97,118,111,114,105,116,101,32,108,105,115,116],"value":"Favorite list"}, diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 91c37df33..8c4e8536f 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -406,10 +406,6 @@ msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Password" -#: tcustomcolorform.caption -msgid "CustomColorForm" -msgstr "CustomColorForm" - #: tcustomcolorform.tsbasiclist.caption msgid "Basic list" msgstr "Basic list" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1d311aa72..da2022cb9 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -398,10 +398,6 @@ msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Kata kunci" -#: tcustomcolorform.caption -msgid "CustomColorForm" -msgstr "CustomColorForm" - #: tcustomcolorform.tsbasiclist.caption msgid "Basic list" msgstr "Semua daftar" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 76bb55dd0..db61fdf7a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -363,10 +363,6 @@ msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" msgid "Password" msgstr "" -#: tcustomcolorform.caption -msgid "CustomColorForm" -msgstr "" - #: tcustomcolorform.tsbasiclist.caption msgid "Basic list" msgstr "" From c8a9f1bdcda268d71e3c0fb194dd8c9f9f76d69d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 12 Aug 2016 17:18:33 +0800 Subject: [PATCH 1384/2794] added sundaywebry #327 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/SundayWebry.pas | 174 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/SundayWebry.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index f8e1c9fc4..befabac29 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -46,4 +46,5 @@ uses LeoManga, MangaPark, MangaIndo, - FunManga; + FunManga, + SundayWebry; diff --git a/baseunits/modules/SundayWebry.pas b/baseunits/modules/SundayWebry.pas new file mode 100644 index 000000000..6618b78a4 --- /dev/null +++ b/baseunits/modules/SundayWebry.pas @@ -0,0 +1,174 @@ +unit SundayWebry; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr; + +implementation + +const + dirurl = '/comics/'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="manga-list__list"]/li/h4/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s, n: String; + last_eps, i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@id="mainvisual"]/img/@src')); + if title = '' then title := XPathString('//*[@class="title"]/h1'); + summary := XPathString('//*[@class="title"]/h2'); + { there is no chapter list? + assuming the first chapter link in manga info is always the last chapters } + s := XPathString('//article/a[1]/@href'); + with TRegExpr.Create do + try + Expression := '^(.+?)(\d+)/?$'; + last_eps := StrToIntDef(Replace(s, '$2', True), 0); + s := Replace(s, '$1', True); + finally + Free; + end; + if (last_eps > 0) and (s <> '') then + for i := 1 to last_eps do + begin + n := Format('%.3d', [i]); + chapterLinks.Add(s + n); + chapterName.Add(n); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + source: TStringList; + i, j, bi, bv: Integer; + key: String; + v, x: IXQValue; + regx: TRegExpr; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(AppendURLDelim(MaybeFillHost(Module.RootURL, AURL))) then + begin + Result := True; + key := ''; + regx := TRegExpr.Create; + source := TStringList.Create; + try + source.LoadFromStream(Document); + if source.Count > 0 then + for i := 0 to source.Count - 1 do + begin + if Pos('key: ', source[i]) <> 0 then + begin + regx.Expression := '^.*["''](.+)["''].*$'; + key := regx.Replace(source[i], '$1', True); + Break; + end; + end; + finally + source.Free; + end; + if key <> '' then + begin + key := Module.RootURL + '/assets/episodes/' + key + '/'; + if GET(key + 'episode.json') then + begin + with TXQueryEngineHTML.Create(Document) do + try + { h1536, h128, h1024 + the available res is varie for every page/image, some only had h1024 + try to get the biggest available } + regx.Expression := '^.*-h(\d+)\.jpe?g'; + for v in XPath('json(*).pages().files') do + begin + x := XPath('*', v); + if x.Count > 0 then + begin + bi := 1; + bv := 0; + for i := 1 to x.Count do + begin + j := StrToIntDef(regx.Replace(x.get(i).toString, '$1', True), 0); + if j > bv then + begin + bv := j; + bi := i; + end; + end; + PageLinks.Add(key + x.get(bi).toString); + end; + end; + finally + Free; + end; + end; + end; + regx.Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'SundayWebry'; + RootURL := 'https://www.sunday-webry.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 2664e552d..1fadb4024 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -13,7 +13,7 @@ Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,Pecinta Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint,RawSenManga,RawYoManga +Raw=MangaMint,RawSenManga,RawYoManga,SundayWebry Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub From 8e2252ffdb3cfaaa82f4d9f142a17f2c8ce360be Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Aug 2016 14:43:23 +0800 Subject: [PATCH 1385/2794] frmmain, fixed exception if no language selected --- mangadownloader/forms/frmMain.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c4cebb3ff..bca4d5d75 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5184,6 +5184,8 @@ procedure TMainForm.ApplyLanguage; idxDropTargetMode: Integer; begin if AvailableLanguages.Count = 0 then Exit; + if cbLanguages.ItemIndex < 0 then Exit; + if cbLanguages.ItemIndex >= AvailableLanguages.Count then Exit; if SimpleTranslator.LastSelected <> AvailableLanguages.Names[cbLanguages.ItemIndex] then begin // TCombobox.Items will be cleared upon changing language, From cda187cb5b190bd5d2324c5b3c1e755b657343ea Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Aug 2016 14:57:12 +0800 Subject: [PATCH 1386/2794] Bump version 0.9.77.0 --- changelog.txt | 8 ++++++++ mangadownloader/md.lpi | 2 +- update | 13 +++++-------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/changelog.txt b/changelog.txt index 89eabadc1..c15a99fc6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.77.0 (13-08-2016) +[*] MangaTraders: rewrite all code +[*] MangaIndo: rewrite all code +[+] MangaJoy replaced with FunManga[EN] +[+] Added SundayWebry[RAW] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.76.0...0.9.77.0 + 0.9.76.0 (07-08-2016) [*] Fixed download tree status not updating [+] Added Log form, Options > Misc > Log diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index dd755132c..a4db2e467 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="76"/> + <RevisionNr Value="77"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 923a717fb..39b36a067 100644 --- a/update +++ b/update @@ -1,8 +1,5 @@ -0.9.8.1 -https://github.com/riderkick/FMD/releases/download/0.9.8.1/fmd_0.9.8.1.7z - -## update info above was deprecated - -VERSION=0.9.76.0 -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.76.0/fmd_0.9.76.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.76.0/fmd_0.9.76.0_Win64.7z +VERSION=0.9.77.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.77.0/fmd_0.9.77.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.77.0/fmd_0.9.77.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.77.0/fmd_0.9.77.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.77.0/fmd_0.9.77.0_Win64.7z From f08a25126ce2b68a7cbbcb8b06626c43ce813aec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Aug 2016 20:29:30 +0800 Subject: [PATCH 1387/2794] log failed create dir --- baseunits/uDownloadsManager.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 17f792b64..af847b3f2 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1193,6 +1193,7 @@ procedure TTaskThread.Execute; CurrentWorkingDir := Container.DownloadInfo.SaveTo; if not ForceDirectoriesUTF8(CurrentWorkingDir) then begin + Logger.SendError(Format('Failed to create dir(%d) = %s', [Length(CurrentWorkingDir), CurrentWorkingDir])); Container.Status := STATUS_FAILED; Container.DownloadInfo.Status := RS_FailedToCreateDir; SyncShowBaloon; From 7c1346f8be35292324a827aaa6bca3d4b2503ed9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Aug 2016 20:35:26 +0800 Subject: [PATCH 1388/2794] fixed failed dir when last character is space. space always trimmed by the system. --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a06762707..dcda1636f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1899,10 +1899,10 @@ function CorrectPathSys(const Path: String): String; Result := TrimRightChar(Result, ['.']); if Length(Result) > MAX_PATHDIR then SetLength(Result, MAX_PATHDIR); - Result := AppendPathDelim(Result); {$ELSE} - Result := CleanAndExpandDirectory(GetForcedPathDelims(Path)); + Result := CleanAndExpandFilename(GetForcedPathDelims(Path)); {$ENDIF} + Result := AppendPathDelim(Trim(Result)); end; function RemovePathDelim(const Path: string): string; From d85ca9df209573697822ca866a0bbdee7e9728d9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Aug 2016 21:08:14 +0800 Subject: [PATCH 1389/2794] fixed triplesevenscan adult warning --- baseunits/modules/FoOlSlide.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 9f20269db..0b341460b 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -28,8 +28,9 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; if Module.Website = 'YoManga' then Result := Cloudflare.GETCF(AHTTP, AURL, yomangacookies, yomangalockget) else - if (Module.Website = 'SeinagiAdultoFansub') and - (Pos(dirurl, AURL) = 0)then + if ((Module.Website = 'SeinagiAdultoFansub') or + (Module.Website = 'TripleSevenScan')) + and (Pos(dirurl, AURL) = 0)then Result := AHTTP.POST(AURL, 'adult=true') else Result := AHTTP.GET(AURL); From ed02907fe5ff67240cf4fa955abb0b11bad09f9e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Aug 2016 21:17:27 +0800 Subject: [PATCH 1390/2794] readme, added lazarus url --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 00fc4a173..7a708a645 100644 --- a/readme.txt +++ b/readme.txt @@ -20,7 +20,7 @@ The Free Manga Downloader is a free open source application written in Object Pa 2.) Build instructions -In order to build FMD from the source code, you must install Lazarus latest version and Free Pascal Compiler v2.6.4. Then you must install the following 3rd party libraries and components: +In order to build FMD from the source code, you must install the latest version of Lazarus and Free Pascal Compiler from http://www.lazarus-ide.org/. Then you must install the following 3rd party libraries and components: - RichMemo, https://sourceforge.net/projects/lazarus-ccr/ - Virtual TreeView, https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4 - Synapse, http://synapse.ararat.cz/ From ee92de816a72b58b0b12217aafd39cf05e7fb218 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 00:29:31 +0800 Subject: [PATCH 1391/2794] fixed an issue with unicode path and filename fixed #348 --- baseunits/uBaseUnit.pas | 17 +++++++++++++---- baseunits/uDownloadsManager.pas | 19 ++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dcda1636f..28277a888 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1893,14 +1893,23 @@ procedure CleanHTMLComments(const Str: TStringList); end; function CorrectPathSys(const Path: String): String; +{$IFDEF WINDOWS} +var + s: UnicodeString; +{$ENDIF} begin + Result := FixWhiteSpace(Path); {$IFDEF WINDOWS} - Result := RemovePathDelim(CleanAndExpandFilename(GetForcedPathDelims(Path))); + Result := RemovePathDelim(CleanAndExpandFilename(GetForcedPathDelims(Result))); Result := TrimRightChar(Result, ['.']); - if Length(Result) > MAX_PATHDIR then - SetLength(Result, MAX_PATHDIR); + s := UTF8Decode(Result); + if Length(s) > MAX_PATHDIR then + begin + SetLength(s, MAX_PATHDIR); + Result := UTF8Encode(s); + end; {$ELSE} - Result := CleanAndExpandFilename(GetForcedPathDelims(Path)); + s := CleanAndExpandFilename(GetForcedPathDelims(Path)); {$ENDIF} Result := AppendPathDelim(Trim(Result)); end; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index af847b3f2..4288cc8ae 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -864,6 +864,10 @@ destructor TTaskThread.Destroy; end; function TTaskThread.GetFileName(const AWorkId: Integer): String; +{$IFDEF WINDOWS} +var + s: UnicodeString; +{$ENDIF} begin Result := ''; if (Container.FileNames.Count = Container.PageLinks.Count) and @@ -873,8 +877,12 @@ function TTaskThread.GetFileName(const AWorkId: Integer): String; Result := Format('%.3d', [AWorkId + 1]); Result := StringReplace(CurrentCustomFileName, CR_FILENAME, Result, [rfReplaceAll]); {$IFDEF WINDOWS} - if Length(Result) > FCurrentMaxFileNameLength then - Result := ShortenString(Result, FCurrentMaxFileNameLength, 4, ''); + s := UTF8Decode(Result); + if Length(s) > FCurrentMaxFileNameLength then + begin + Delete(s, 1, Length(s) - FCurrentMaxFileNameLength); + Result := UTF8Encode(s); + end; {$ENDIF} end; @@ -1031,11 +1039,16 @@ function TDownloadThread.DownloadImage: Boolean; end; procedure TTaskThread.SetCurrentWorkingDir(AValue: String); +{$IFDEF WINDOWS} +var + s: UnicodeString; +{$ENDIF} begin if FCurrentWorkingDir = AValue then Exit; FCurrentWorkingDir := CorrectPathSys(AValue); {$IFDEF Windows} - FCurrentMaxFileNameLength := FMDMaxImageFilePath - Length(FCurrentWorkingDir); + s := UTF8Decode(FCurrentWorkingDir); + FCurrentMaxFileNameLength := FMDMaxImageFilePath - Length(s); {$ENDIF} end; From ba9f9010d3bdbf486fb9395e32c564076ffd94fb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 00:42:14 +0800 Subject: [PATCH 1392/2794] typo --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 28277a888..92698dd2f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1909,7 +1909,7 @@ function CorrectPathSys(const Path: String): String; Result := UTF8Encode(s); end; {$ELSE} - s := CleanAndExpandFilename(GetForcedPathDelims(Path)); + Result := CleanAndExpandFilename(GetForcedPathDelims(Path)); {$ENDIF} Result := AppendPathDelim(Trim(Result)); end; From d2468dd8c1bfc35714f63b431755fc4759360356 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 00:59:15 +0800 Subject: [PATCH 1393/2794] fixed delete task data with unicode --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bca4d5d75..023eb2133 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1709,7 +1709,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) and (ChapterName.Count > 0) then begin for i := 0 to ChapterName.Count - 1 do begin - f := CleanAndExpandDirectory(DownloadInfo.SaveTo + ChapterName[i]); + f := CorrectPathSys(DownloadInfo.SaveTo + ChapterName[i]); if FileExistsUTF8(f + '.zip') then DeleteFileUTF8(f + '.zip') else if FileExistsUTF8(f + '.cbz') then From a3ee0b928cc370a49fe6d4d27d79050f50e2096d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 01:26:49 +0800 Subject: [PATCH 1394/2794] frmmain, favorite list, change save to use select directory dialog instead input query --- mangadownloader/forms/frmMain.pas | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 023eb2133..54478ec95 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2697,6 +2697,8 @@ procedure TMainForm.miFavoritesChangeCurrentChapterClick(Sender: TObject); end; procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); +var + s: String; begin if FavoriteManager.isRunning then begin @@ -2706,11 +2708,19 @@ procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); end; if not Assigned(vtFavorites.FocusedNode) then Exit; - if InputQuery('', RS_DlgTypeInNewSavePath, - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo) then + s := ''; + with TSelectDirectoryDialog.Create(Self) do + try + InitialDir := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo; + if Execute then + s := FileName; + finally + Free; + end; + + if s <> '' then begin - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := - CorrectFilePath(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := CorrectFilePath(s); UpdateVtFavorites; FavoriteManager.Backup; end; From 01983e7cba8e2f9342624f4799254ac233c7be77 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 01:31:05 +0800 Subject: [PATCH 1395/2794] changed saveto in tdownloadinfo and tfavoriteinfo always use correctpathsys --- baseunits/uBaseUnit.pas | 32 +++++++++++++++++++++++++++++-- baseunits/uDownloadsManager.pas | 2 +- baseunits/uFavoritesManager.pas | 2 +- baseunits/uSilentThread.pas | 2 +- mangadownloader/forms/frmMain.pas | 4 ++-- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 92698dd2f..7f30a8257 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -571,28 +571,40 @@ TMangaInfo = class PDownloadInfo = ^TDownloadInfo; + { TDownloadInfo } + TDownloadInfo = record + private + FSaveTo: String; + procedure SetSaveTo(AValue: String); + public Website, Link, Title, - SaveTo, Status, Progress, TransferRate: String; DateTime: TDateTime; iProgress: Integer; + property SaveTo: String read FSaveTo write SetSaveTo; end; PFavoriteInfo = ^TFavoriteInfo; + { TFavoriteInfo } + TFavoriteInfo = record + private + FSaveTo: String; + procedure SetSaveTo(AValue: String); + public Website, Title, Link, - SaveTo, Numbering, DownloadedChapterList, CurrentChapter: String; + property SaveTo: String read FSaveTo write SetSaveTo; end; TCardinalList = TFPGList<Cardinal>; @@ -3997,6 +4009,22 @@ function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String) Result := MangaInfo_StatusCompleted; end; +{ TFavoriteInfo } + +procedure TFavoriteInfo.SetSaveTo(AValue: String); +begin + if FSaveTo = AValue then Exit; + FSaveTo := CorrectPathSys(AValue); +end; + +{ TDownloadInfo } + +procedure TDownloadInfo.SetSaveTo(AValue: String); +begin + if FSaveTo = AValue then Exit; + FSaveTo := CorrectPathSys(AValue); +end; + { THTMLForm } constructor THTMLForm.Create; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4288cc8ae..99ef8ea51 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1693,7 +1693,7 @@ procedure TDownloadManager.Restore; DownloadInfo.Website := ReadString(tid, 'Website', 'NULL'); DownloadInfo.Link := ReadString(tid, 'Link', ''); DownloadInfo.Title := ReadString(tid, 'Title', 'NULL'); - DownloadInfo.SaveTo := CorrectPathSys(ReadString(tid, 'SaveTo', 'NULL')); + DownloadInfo.SaveTo := ReadString(tid, 'SaveTo', 'NULL'); DownloadInfo.Status := ReadString(tid, 'Status', 'NULL'); DownloadInfo.Progress := ReadString(tid, 'Progress', 'NULL'); Enabled := ReadBool(tid, 'Enabled', True); diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 84d087a2c..bb229d9b2 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -940,7 +940,7 @@ procedure TFavoriteManager.Restore; currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); Title := ReadString(IntToStr(i), 'Title', ''); Website := ReadString(IntToStr(i), 'Website', ''); - SaveTo := CorrectPathSys(ReadString(IntToStr(i), 'SaveTo', '')); + SaveTo := ReadString(IntToStr(i), 'SaveTo', ''); Link := ReadString(IntToStr(i), 'Link', ''); Website := Website; Status := STATUS_IDLE; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 6a07b66ba..17932c287 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -374,7 +374,7 @@ procedure TSilentThread.MainThreadAfterChecking; '', OptionChangeUnicodeCharacter); end; - DLManager.Items[p].downloadInfo.SaveTo := CorrectPathSys(FSavePath); + DLManager.Items[p].downloadInfo.SaveTo := FSavePath; UpdateVtDownload; DLManager.CheckAndActiveTask(False); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 54478ec95..b19358edc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2012,7 +2012,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); '', '', OptionChangeUnicodeCharacter); - DLManager.Items[pos].DownloadInfo.SaveTo := CleanAndExpandDirectory(s); + DLManager.Items[pos].DownloadInfo.SaveTo := s; UpdateVtDownload; DLManager.CheckAndActiveTask; @@ -2720,7 +2720,7 @@ procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); if s <> '' then begin - FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := CorrectFilePath(s); + FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo := s; UpdateVtFavorites; FavoriteManager.Backup; end; From 4247a85dda9a578aa851c7ed5873b25991c15164 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 18:48:27 +0800 Subject: [PATCH 1396/2794] mangaindo, fixed manga info status --- baseunits/modules/MangaIndo.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaIndo.pas b/baseunits/modules/MangaIndo.pas index 7cc977c29..908853c91 100644 --- a/baseunits/modules/MangaIndo.pas +++ b/baseunits/modules/MangaIndo.pas @@ -72,7 +72,7 @@ function GetInfo(const MangaInfo: TMangaInformation; authors := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Author:")]'),':')); genres := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Genre:")]'),':')); status := MangaInfoStatusIfPos(XPathString( - '//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Genre:")]'), + '//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Episode:")]'), 'Ongoing', 'Completed'); summary := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p[starts-with(.,"Synopsis:")]'), ':')); From dee702c2ee301d8971c98b2db2b3ae339bc556e7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 18:56:11 +0800 Subject: [PATCH 1397/2794] httpsendthread, call oncustomterminate with synchronize --- baseunits/httpsendthread.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 411af08ae..dce73b42f 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -16,6 +16,7 @@ THTTPThread = class(TThread) private FOnCustomTerminate: TNotifyEvent; function GetTerminated: Boolean; + procedure CallOnCustomTerminate; public constructor Create(CreateSuspended: Boolean = True); procedure Terminate; @@ -190,6 +191,11 @@ function THTTPThread.GetTerminated: Boolean; Result := Self.Terminated; end; +procedure THTTPThread.CallOnCustomTerminate; +begin + FOnCustomTerminate(Self); +end; + constructor THTTPThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); @@ -200,7 +206,7 @@ procedure THTTPThread.Terminate; begin inherited Terminate; if Assigned(FOnCustomTerminate) then - FOnCustomTerminate(Self); + Synchronize(@CallOnCustomTerminate); end; { THTTPSendThread } From 3cd2c0bb115068a0060caf40ed15898c2590f398 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 19:10:31 +0800 Subject: [PATCH 1398/2794] httpsendthread, added module ID to tmodulecontainer --- baseunits/WebsiteModules.pas | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 4a91171f0..fe41aa19b 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -68,6 +68,7 @@ TWebsiteOptionItem = record TModuleContainer = class private + FID: Integer; FTotalDirectory: Integer; procedure SetTotalDirectory(AValue: Integer); procedure AddOption(const AOptionType: TWebsiteOptionType; @@ -100,6 +101,7 @@ TModuleContainer = class constructor Create; destructor Destroy; override; public + property ID: Integer read FID; property TotalDirectory: Integer read FTotalDirectory write SetTotalDirectory; procedure AddOptionCheckBox(const ABindValue: PBoolean; const AName: String; const ACaption: PString); @@ -270,6 +272,7 @@ procedure TModuleContainer.SetTotalDirectory(AValue: Integer); constructor TModuleContainer.Create; begin + FID := -1; MaxTaskLimit := 0; MaxConnectionLimit := 0; ActiveTaskCount := 0; @@ -355,8 +358,8 @@ function TWebsiteModules.AddModule: TModuleContainer; begin EnterCriticalsection(FCSModules); try - FModuleList.Add(TModuleContainer.Create); - Result := TModuleContainer(FModuleList.Last); + Result := TModuleContainer.Create; + Result.FID := FModuleList.Add(Result); finally LeaveCriticalsection(FCSModules); end; From e9f7efcc61570aad4f5f7e8ba77706730c86f28a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 20:17:04 +0800 Subject: [PATCH 1399/2794] mangatraders, fixed empty chapters #351 --- baseunits/modules/MangaLife.pas | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 460cfd982..d11c960e8 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -17,12 +17,16 @@ implementation dirURL = '/directory/'; diralpha = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; dirURLmangasee = '/directory.php'; +var + MMangaSee, + MMangaTraders: TModuleContainer; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; - if (Module.Website = 'MangaSee') or (Module.Website = 'MangaTraders') then + if (Module = MMangaSee) or + (Module = MMangaTraders) then Page := Length(diralpha) else Page := 1; @@ -45,16 +49,16 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; s := Module.RootURL; - if Module.Website = 'MangaSee' then + if Module = MMangaSee then s += dirURLmangasee else s+=dirURL; if AURL <> '0' then begin - if Module.Website = 'MangaSee' then + if Module = MMangaSee then s += '?c=' else - if Module.Website = 'MangaTraders' then + if Module = MMangaTraders then s += '?start='; s += diralpha[StrToIntDef(AURL, 0) + 1] end; @@ -94,6 +98,8 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := MaybeFillHost(Module.RootURL, AURL); + if (Module = MMangaTraders) and (Pos('?series=', url) <> 0) then + url := Module.RootURL + '/read-online/' + SeparateRight(url, '?series='); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -174,8 +180,8 @@ procedure RegisterModule; begin AddWebsiteModule('MangaLife', 'http://manga.life'); - AddWebsiteModule('MangaSee', 'http://mangasee.co'); - AddWebsiteModule('MangaTraders', 'http://mangatraders.org') + MMangaSee := AddWebsiteModule('MangaSee', 'http://mangasee.co'); + MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.org'); end; initialization From 0dc3b387835849b174671619ef67b58765aece78 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 20:53:39 +0800 Subject: [PATCH 1400/2794] getmangainfosthread, fixed update mangalist data, call updatedata with synchronize --- baseunits/uGetMangaInfosThread.pas | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 1717eecbe..0ab7f5a4c 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -38,6 +38,7 @@ TGetMangaInfosThread = class(THTTPThread) procedure Execute; override; procedure DoGetInfos; + procedure MainThreadSyncInfos; procedure MainThreadShowInfos; procedure MainThreadShowCover; procedure MainThreadShowCannotGetInfo; @@ -76,8 +77,7 @@ procedure TGetMangaInfosThread.DoGetInfos; filterPos := FMangaListPos; if FInfo.mangaInfo.title = '' then FInfo.mangaInfo.title := MainForm.dataProcess.Value[filterPos, DATA_PARAM_TITLE]; - if FInfo.mangaInfo.link = '' then - FInfo.mangaInfo.link := MainForm.dataProcess.Value[filterPos, DATA_PARAM_LINK]; + FInfo.mangaInfo.link := MainForm.dataProcess.Value[filterPos, DATA_PARAM_LINK]; FInfo.mangaInfo.authors := MainForm.dataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; FInfo.mangaInfo.artists := MainForm.dataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; FInfo.mangaInfo.status := MainForm.dataProcess.Value[filterPos, DATA_PARAM_STATUS]; @@ -129,8 +129,7 @@ procedure TGetMangaInfosThread.DoGetInfos; MainForm.DataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; end; - FInfo.SyncInfoToData(MainForm.DataProcess); - MainForm.dataProcess.Commit; + Synchronize(MainThreadSyncInfos); end; end; Result := True; @@ -169,6 +168,12 @@ procedure TGetMangaInfosThread.DoGetInfos; end; end; +procedure TGetMangaInfosThread.MainThreadSyncInfos; +begin + FInfo.SyncInfoToData(MainForm.DataProcess); + MainForm.dataProcess.Commit; +end; + procedure TGetMangaInfosThread.DoTerminate; begin Modules.DecActiveConnectionCount(FInfo.ModuleId); From 7d8a787a1ba4bf52aee990e654b5ab786a30fedc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 14 Aug 2016 23:09:01 +0800 Subject: [PATCH 1401/2794] downloadmanager, reformat status prepare --- baseunits/uDownloadsManager.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 99ef8ea51..8d96c9d7c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1283,10 +1283,10 @@ procedure TTaskThread.Execute; Container.DownloadInfo.Progress := Format('%d/%d', [Container.DownCounter, Container.PageNumber]); Container.DownloadInfo.Status := - Format('%s (%d/%d [%s])', - [RS_Preparing, - Container.CurrentDownloadChapterPtr + 1, + Format('[%d/%d] %s (%s)', + [Container.CurrentDownloadChapterPtr + 1, Container.ChapterLinks.Count, + RS_Preparing, Container.ChapterName[Container.CurrentDownloadChapterPtr]]); Container.Status := STATUS_PREPARE; while Container.WorkCounter < Container.PageNumber do From 46e34356803d3ce5e5b0bd598f061b591dbd5ec2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 15:59:59 +0800 Subject: [PATCH 1402/2794] fixed update status after manga list items deleted --- mangadownloader/forms/frmMain.pas | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b19358edc..d3dd6b590 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -681,6 +681,7 @@ TMainForm = class(TForm) procedure UpdateVtChapter; procedure UpdateVtDownload; inline; procedure UpdateVtFavorites; + procedure UpdateVtMangaListFilterStatus; // load form information, like previous position, size, ... procedure LoadFormInformation; @@ -935,10 +936,7 @@ procedure TSearchDBThread.SyncAfterSearch; begin vtMangaList.RootNodeCount := dataProcess.RecordCount; vtMangaList.EndUpdate; - if dataProcess.Filtered then - lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]) - else - lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); + UpdateVtMangaListFilterStatus; LastSearchWeb := dataProcess.Website; LastSearchStr := UpCase(FSearchStr); vtMangaList.Cursor := crDefault; @@ -3006,6 +3004,7 @@ procedure TMainForm.miMangaListDeleteClick(Sender: TObject); begin vtMangaList.ClearSelection; vtMangaList.RootNodeCount := dataProcess.RecordCount; + UpdateVtMangaListFilterStatus; end; finally vtMangaList.EndUpdate; @@ -5055,6 +5054,14 @@ procedure TMainForm.UpdateVtFavorites; end; end; +procedure TMainForm.UpdateVtMangaListFilterStatus; +begin + if dataProcess.Filtered then + lbMode.Caption := Format(RS_ModeFiltered, [dataProcess.RecordCount]) + else + lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); +end; + procedure TMainForm.LoadFormInformation; var i: Integer; From a55b9d04fb491595a82ff67844934f9e25ba4641 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 16:03:43 +0800 Subject: [PATCH 1403/2794] mangachanru,hentaichanru,yaoichanru, fixed manga info and fill empty chapters with read online url when available #347 --- baseunits/modules/MangaChanRU.pas | 33 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 903c9a915..805d6bf90 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -65,32 +65,35 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL, AURL)) then begin + with MangaInfo.FHTTP, MangaInfo.mangaInfo do + begin + if GET(FillHost(Module.RootURL, AURL)) then + begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//*[@id="manga_images"]//img[@id="cover"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@id="cover"]/@src')); if title = '' then title := XPathString('//*[@class="name_row"]/h1'); - authors := XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Автор")]/td[2]'); - genres := XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тип")]/td[2]'); - AddCommaString(genres, XPathString( - '//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Тэги")]/td[2]')); - s := XPathString('//table[@class="mangatitle"]/tbody/tr[starts-with(.,"Загружено")]/td[2]'); - if s <> '' then begin - if Pos('продолжается', s) > 0 then status := '1' - else status := '0'; - end; + authors := XPathString('//*[@class="item" and contains(.,"Автор")]/following-sibling::*[1]'); + genres := XPathString('//*[@class="item" and contains(.,"Тэги")]/following-sibling::*[1]'); + status := MangaInfoStatusIfPos( + XPathString('//*[@class="item" and contains(.,"Загружено")]/following-sibling::*[1]'), + 'продолжается', + ''); summary := XPathString('//*[@id="description"]/text()'); - for v in XPath('//table[@class="table_cha"]//tr/td/*[@class="manga"]/a') do begin + for v in XPath('//*[@class="table_cha"]//*[@class="manga"]/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(v.toString); end; + if chapterLinks.Count = 0 then + for v in XPath('//a[.="Читать онлайн"]') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(title); + end; InvertStrings([chapterLinks, chapterName]); finally Free; From c83ee2235f271454d9081ff2f6530592b4470f30 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 16:49:00 +0800 Subject: [PATCH 1404/2794] added custom text to be used for replace unicode character with, fixed changed replace unicode character method with unicode aware #347 --- baseunits/FMDOptions.pas | 1 + baseunits/uBaseUnit.pas | 36 ++++++++++++++++---------- baseunits/uFavoritesManager.pas | 3 ++- baseunits/uSilentThread.pas | 9 ++++--- mangadownloader/forms/frmMain.lfm | 35 ++++++++++++++++--------- mangadownloader/forms/frmMain.lrj | 3 ++- mangadownloader/forms/frmMain.pas | 19 +++++++++++--- mangadownloader/languages/fmd.en.po | 10 ++++--- mangadownloader/languages/fmd.id_ID.po | 9 ++++--- mangadownloader/languages/fmd.po | 6 ++++- 10 files changed, 90 insertions(+), 41 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 29086f704..6b9a36838 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -91,6 +91,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionLetFMDDo: TFMDDo = DO_NOTHING; OptionChangeUnicodeCharacter: Boolean = False; + OptionChangeUnicodeCharacterStr: String = '_'; OptionGenerateMangaFolder: Boolean = False; OptionMangaCustomRename: String; OptionGenerateChapterFolder: Boolean = True; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7f30a8257..434bc82bc 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -653,7 +653,7 @@ THTMLForm = class end; // Remove Unicode -function UnicodeRemove(const S: String): String; +function ReplaceUnicodeChar(const S, ReplaceStr: String): String; // Check a directory to see if it's empty (return TRUE) or not function IsDirectoryEmpty(const ADir: String): Boolean; function CheckRedirect(const HTTP: THTTPSend): String; @@ -786,8 +786,9 @@ function IncStr(const I: Integer; N: Integer = 1): String; overload; inline; function GetHeaderValue(const AHeaders: TStrings; HName: String): String; // custom rename feature -function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, - AChapter, ANumbering: String; const ARemoveUnicode: Boolean; +function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, ANumbering: String; + const AReplaceUnicode: Boolean; + const AReplaceUnicodeStr: String; const AFilename: String = ''): String; // Get substring from source @@ -979,19 +980,24 @@ function NTSetPrivilege(sPrivilege: String; bEnabled: Boolean): Boolean; {$ENDIF} -function UnicodeRemove(const S: String): String; +function ReplaceUnicodeChar(const S, ReplaceStr: String): String; var i: Integer; + s1, s2, sr: UnicodeString; begin Result := S; - for i := 1 to Length(Result) do + if Result = '' then Exit; + s1 := UTF8Decode(S); + s2 := UTF8Decode(ReplaceStr); + sr := ''; + for i := 1 to Length(s1) do begin - if (Byte(Result[i]) < 31) or (Byte(Result[i]) > 127) then - begin - Delete(Result, i, 1); - Insert('_', Result, i); - end; + if (Ord(s1[i]) < 31) or (Ord(s1[i]) > 127) then + sr := sr + s2 + else + sr := sr + s1[i]; end; + Result := UTF8Encode(sr); end; function IsDirectoryEmpty(const ADir: String): Boolean; @@ -2199,8 +2205,10 @@ function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: T end; end; -function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, - ANumbering: String; const ARemoveUnicode: Boolean; const AFilename: String): String; +function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, ANumbering: String; + const AReplaceUnicode: Boolean; + const AReplaceUnicodeStr: String; + const AFilename: String): String; function FixStringLocal(const S: String): String; begin @@ -2209,8 +2217,8 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh // remove unaccepted character (Windows) Result := RemoveSymbols(Result); // strip unicode character - if ARemoveUnicode then - Result := UnicodeRemove(Result); + if AReplaceUnicode then + Result := ReplaceUnicodeChar(Result, AReplaceUnicodeStr); end; var diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index bb229d9b2..a1d95c0ae 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -726,7 +726,8 @@ procedure TFavoriteManager.ShowResult; NewMangaInfo.artists, NewMangaInfo.chapterName[NewMangaInfoChaptersPos[j]], Format('%.4d', [NewMangaInfoChaptersPos[j] + 1]), - OptionChangeUnicodeCharacter)); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr)); end; if LNCResult = ncrDownload then diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 17932c287..53704746b 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -335,7 +335,8 @@ procedure TSilentThread.MainThreadAfterChecking; Info.mangaInfo.artists, Info.mangaInfo.chapterName.Strings[i], Format('%.4d', [i + 1]), - OptionChangeUnicodeCharacter); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); DLManager.Items[p].chapterName.Add(s); DLManager.Items[p].chapterLinks.Add( Info.mangaInfo.chapterLinks.Strings[i]); @@ -372,7 +373,8 @@ procedure TSilentThread.MainThreadAfterChecking; info.mangaInfo.artists, '', '', - OptionChangeUnicodeCharacter); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); end; DLManager.Items[p].downloadInfo.SaveTo := FSavePath; @@ -465,7 +467,8 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; info.mangaInfo.artists, '', '', - OptionChangeUnicodeCharacter); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); s2 := ''; if (Info.mangaInfo.numChapter > 0) then begin diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 2b86311b3..8b96abd09 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,7 +13,6 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter - LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 @@ -2133,11 +2132,11 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 object pnOptions: TPageControl Left = 8 - Height = 407 + Height = 415 Top = 8 Width = 539 ActivePage = tsGeneral @@ -2151,7 +2150,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime @@ -2791,22 +2790,22 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object sbSaveTo: TScrollBox Left = 0 - Height = 379 + Height = 387 Top = 0 Width = 531 HorzScrollBar.Page = 198 - VertScrollBar.Page = 379 + VertScrollBar.Page = 387 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 514 TabOrder = 0 object rgOptionCompress: TRadioGroup @@ -2870,10 +2869,11 @@ object MainForm: TMainForm object cbOptionChangeUnicodeCharacter: TCheckBox Left = 4 Height = 19 + Hint = 'Enable this if you have problem with unicode character in path.' Top = 4 - Width = 494 - Align = alTop - Caption = 'Change all all unicode symbols to "_" (choose this when you have problem with unicode path)' + Width = 200 + Caption = 'Replace all unicode character with' + OnChange = cbOptionChangeUnicodeCharacterChange ParentFont = False TabOrder = 0 end @@ -3103,6 +3103,17 @@ object MainForm: TMainForm Caption = 'Filename:' ParentColor = False end + object edOptionChangeUnicodeCharacterStr: TEdit + AnchorSideLeft.Control = cbOptionChangeUnicodeCharacter + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cbOptionChangeUnicodeCharacter + Left = 208 + Height = 23 + Top = 4 + Width = 80 + Enabled = False + TabOrder = 11 + end end object lbDefaultDownloadPath: TLabel Left = 4 @@ -3817,7 +3828,7 @@ object MainForm: TMainForm object btOptionApply: TBitBtn Left = 8 Height = 45 - Top = 426 + Top = 434 Width = 125 Anchors = [akLeft, akBottom] AutoSize = True diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index a49863a37..0d96fed33 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -170,7 +170,8 @@ {"hash":160200703,"name":"tmainform.tssaveto.caption","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":96652067,"name":"tmainform.rgoptioncompress.caption","sourcebytes":[83,97,118,101,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115,32,97,115],"value":"Save downloaded chapters as"}, {"hash":206060487,"name":"tmainform.gboptionrenaming.caption","sourcebytes":[82,101,110,97,109,105,110,103],"value":"Renaming"}, -{"hash":25140969,"name":"tmainform.cboptionchangeunicodecharacter.caption","sourcebytes":[67,104,97,110,103,101,32,97,108,108,32,97,108,108,32,117,110,105,99,111,100,101,32,115,121,109,98,111,108,115,32,116,111,32,34,95,34,32,40,99,104,111,111,115,101,32,116,104,105,115,32,119,104,101,110,32,121,111,117,32,104,97,118,101,32,112,114,111,98,108,101,109,32,119,105,116,104,32,117,110,105,99,111,100,101,32,112,97,116,104,41],"value":"Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)"}, +{"hash":117199758,"name":"tmainform.cboptionchangeunicodecharacter.hint","sourcebytes":[69,110,97,98,108,101,32,116,104,105,115,32,105,102,32,121,111,117,32,104,97,118,101,32,112,114,111,98,108,101,109,32,119,105,116,104,32,117,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,105,110,32,112,97,116,104,46],"value":"Enable this if you have problem with unicode character in path."}, +{"hash":135172728,"name":"tmainform.cboptionchangeunicodecharacter.caption","sourcebytes":[82,101,112,108,97,99,101,32,97,108,108,32,117,110,105,99,111,100,101,32,99,104,97,114,97,99,116,101,114,32,119,105,116,104],"value":"Replace all unicode character with"}, {"hash":153869381,"name":"tmainform.cboptiongeneratemangafolder.caption","sourcebytes":[65,117,116,111,32,103,101,110,101,114,97,116,101,32,102,111,108,100,101,114,32,98,97,115,101,100,32,111,110,32,109,97,110,103,97,39,115,32,110,97,109,101],"value":"Auto generate folder based on manga's name"}, {"hash":8004730,"name":"tmainform.lboptionmangacustomrename.caption","sourcebytes":[77,97,110,103,97,32,102,111,108,100,101,114,32,110,97,109,101,58],"value":"Manga folder name:"}, {"hash":222491525,"name":"tmainform.edoptionmangacustomrename.texthint","sourcebytes":[67,117,115,116,111,109,32,114,101,110,97,109,101],"value":"Custom rename"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d3dd6b590..0d0924fad 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -70,6 +70,7 @@ TMainForm = class(TForm) edDownloadsSearch: TEdit; edFilterMangaInfoChapters: TEditButton; edFavoritesSearch: TEdit; + edOptionChangeUnicodeCharacterStr: TEdit; edOptionFilenameCustomRename: TEdit; edOptionDefaultPath: TDirectoryEdit; edOptionMangaCustomRename: TEdit; @@ -400,6 +401,7 @@ TMainForm = class(TForm) procedure btWebsitesSearchClearClick(Sender: TObject); procedure cbAddAsStoppedChange(Sender: TObject); procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); + procedure cbOptionChangeUnicodeCharacterChange(Sender: TObject); procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderChange(Sender: TObject); @@ -1971,7 +1973,8 @@ procedure TMainForm.btDownloadClick(Sender: TObject); mangaInfo.artists, mangaInfo.chapterName.Strings[xNode^.Index], Format('%.4d', [xNode^.Index + 1]), - OptionChangeUnicodeCharacter); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); DLManager.Items[pos].ChapterName.Add(s); DLManager.Items[pos].ChapterLinks.Add( mangaInfo.chapterLinks.Strings[xNode^.Index]); @@ -2009,7 +2012,8 @@ procedure TMainForm.btDownloadClick(Sender: TObject); mangaInfo.artists, '', '', - OptionChangeUnicodeCharacter); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); DLManager.Items[pos].DownloadInfo.SaveTo := s; UpdateVtDownload; @@ -2040,7 +2044,8 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); mangaInfo.artists, '', '', - OptionChangeUnicodeCharacter); + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); // downloaded chapters s2 := ''; @@ -2178,6 +2183,11 @@ procedure TMainForm.cbOptionAutoCheckFavIntervalChange(Sender: TObject); lbOptionAutoCheckFavIntervalMinutes.Enabled := cbOptionAutoCheckFavInterval.Checked; end; +procedure TMainForm.cbOptionChangeUnicodeCharacterChange(Sender: TObject); +begin + edOptionChangeUnicodeCharacterStr.Enabled := cbOptionChangeUnicodeCharacter.Checked; +end; + procedure TMainForm.cbOptionDigitChapterChange(Sender: TObject); begin seOptionDigitChapter.Enabled := cbOptionDigitChapter.Checked; @@ -4476,6 +4486,7 @@ procedure TMainForm.LoadOptions; seOptionPDFQuality.Value := ReadInteger('saveto', 'PDFQuality', 100); rgOptionCompress.ItemIndex := ReadInteger('saveto', 'Compress', 0); cbOptionChangeUnicodeCharacter.Checked := ReadBool('saveto', 'ChangeUnicodeCharacter', False); + edOptionChangeUnicodeCharacterStr.Text := ReadString('saveto', 'ChangeUnicodeCharacterStr', OptionChangeUnicodeCharacterStr); cbOptionRemoveMangaNameFromChapter.Checked := ReadBool('saveto', 'RemoveMangaNameFromChapter', False); cbOptionGenerateMangaFolder.Checked := ReadBool('saveto', 'GenerateMangaFolder', True); edOptionMangaCustomRename.Text := ReadString('saveto', 'MangaCustomRename', DEFAULT_MANGA_CUSTOMRENAME); @@ -4605,6 +4616,7 @@ procedure TMainForm.SaveOptions; edOptionDefaultPath.Text := CleanAndExpandDirectory(edOptionDefaultPath.Text); WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); WriteBool('saveto', 'ChangeUnicodeCharacter', cbOptionChangeUnicodeCharacter.Checked); + WriteString('saveto', 'ChangeUnicodeCharacterStr', edOptionChangeUnicodeCharacterStr.Text); WriteBool('saveto', 'GenerateMangaFolder', cbOptionGenerateMangaFolder.Checked); if Trim(edOptionMangaCustomRename.Text) = '' then edOptionMangaCustomRename.Text := DEFAULT_MANGA_CUSTOMRENAME; @@ -4739,6 +4751,7 @@ procedure TMainForm.ApplyOptions; OptionPDFQuality := seOptionPDFQuality.Value; DLManager.compress := rgOptionCompress.ItemIndex; OptionChangeUnicodeCharacter := cbOptionChangeUnicodeCharacter.Checked; + OptionChangeUnicodeCharacterStr := edOptionChangeUnicodeCharacterStr.Text; OptionRemoveMangaNameFromChapter := cbOptionRemoveMangaNameFromChapter.Checked; OptionGenerateMangaFolder := cbOptionGenerateMangaFolder.Checked; OptionMangaCustomRename := edOptionMangaCustomRename.Text; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8c4e8536f..53b3ff1ee 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -586,9 +586,14 @@ msgid "Auto check for latest version " msgstr "Auto check for latest version " #: tmainform.cboptionchangeunicodecharacter.caption +#| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" -msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" -msgstr "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" +msgid "Replace all unicode character with" +msgstr "Replace all unicode character with" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Enable this if you have problem with unicode character in path." #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -2159,4 +2164,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index da2022cb9..cb8a049ee 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -576,8 +576,12 @@ msgstr "Otomatis periksa versi terbaru" #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "tmainform.cboptionchangeunicodecharacter.caption" -msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" -msgstr "Ubah semua simbol unicode menjadi \"_\" (pilih ini ketika Anda memiliki masalah dengan lokasi unicode)" +msgid "Replace all unicode character with" +msgstr "Ubah semua simbol unicode menjadi" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Aktifkan pilihan ini jika anda mengalami masalah dengan karakter unicode pada path." #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -2140,4 +2144,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index db61fdf7a..0d4929462 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -541,7 +541,11 @@ msgstr "" #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" -msgid "Change all all unicode symbols to \"_\" (choose this when you have problem with unicode path)" +msgid "Replace all unicode character with" +msgstr "" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." msgstr "" #: tmainform.cboptiondigitchapter.caption From 0a8a803a24d2feeea18fbb8862ee4a64eba23fec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 17:03:27 +0800 Subject: [PATCH 1405/2794] baseunit, method removesymbols actually remove symbols not replace --- baseunits/uBaseUnit.pas | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 434bc82bc..2e0dc9bf3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1838,9 +1838,13 @@ function RemoveSymbols(const input: String): String; i: Integer; begin Result := input; - for i := 1 to Length(Result) do + if Result = '' then Exit; + i := 1; + while i <= Length(Result) do if CharInSet(Result[i], Symbols) then - Result[i] := '_'; + Delete(Result, i, 1) + else + Inc(i); end; procedure InvertStrings(const Sts: array of TStringList); From cb5223b9d401122db61a2d4fd18fe656dd9e49d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 19:12:32 +0800 Subject: [PATCH 1406/2794] fixed manga info tab show unwanted char --- baseunits/uBaseUnit.pas | 11 +++++-- mangadownloader/forms/frmMain.lfm | 35 +++++++++++----------- mangadownloader/forms/frmMain.pas | 50 +++++++++++++------------------ 3 files changed, 47 insertions(+), 49 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2e0dc9bf3..839190c06 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2478,11 +2478,18 @@ function SetParams(const input: array of String): String; end; function FixWhiteSpace(const S: String): String; +const + R: array [0..1] of string = ( + #$C2#$A0, // no-break space /   U+00A0 #160 + #$EF#$BB#$BF // zero width no-break / BOM U+FEFF + ); +var + v: String; begin Result := S; if Result = '' then Exit; - while Pos(#$C2#$A0, Result) > 0 do - Result := StringReplace(Result, #$C2#$A0, ' ', [rfReplaceAll]); + for v in R do + Result := StringReplace(Result, v, '', [rfReplaceAll]); end; function CleanString(const S: String): String; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 8b96abd09..f115fac54 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,6 +13,7 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 @@ -36,13 +37,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsDownload + ActivePage = tsInformation Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 1 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -328,22 +329,22 @@ object MainForm: TMainForm end object tsInformation: TTabSheet Caption = 'Manga Info' - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 object sbInformation: TScrollBox Left = 0 - Height = 484 + Height = 492 Top = 0 Width = 558 HorzScrollBar.Page = 327 - VertScrollBar.Page = 474 + VertScrollBar.Page = 482 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 TabOrder = 0 object pnInfomation: TPanel @@ -371,11 +372,9 @@ object MainForm: TMainForm Top = 27 Width = 392 Anchors = [akTop, akLeft, akRight, akBottom] - Color = clWhite HideSelection = False - ParentFont = False ReadOnly = True - ScrollBars = ssVertical + ScrollBars = ssAutoVertical TabOrder = 0 ZoomFactor = 1 end @@ -488,21 +487,21 @@ object MainForm: TMainForm end object pnChapterList: TPanel Left = 4 - Height = 207 + Height = 215 Top = 269 Width = 550 Align = alClient BevelOuter = bvNone ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 207 + ClientHeight = 215 ClientWidth = 550 TabOrder = 2 object clbChapterList: TVirtualStringTree AnchorSideTop.Control = edFilterMangaInfoChapters AnchorSideBottom.Control = lbSaveTo Left = 0 - Height = 128 + Height = 136 Top = 0 Width = 516 Anchors = [akTop, akLeft, akRight, akBottom] @@ -536,7 +535,7 @@ object MainForm: TMainForm AnchorSideBottom.Side = asrBottom Left = 338 Height = 26 - Top = 151 + Top = 159 Width = 100 Anchors = [akTop, akRight, akBottom] AutoSize = True @@ -588,7 +587,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 0 Height = 19 - Top = 178 + Top = 186 Width = 334 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' @@ -602,7 +601,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 442 Height = 26 - Top = 151 + Top = 159 Width = 108 Anchors = [akRight, akBottom] AutoSize = True @@ -700,7 +699,7 @@ object MainForm: TMainForm AnchorSideRight.Side = asrBottom Left = 338 Height = 26 - Top = 181 + Top = 189 Width = 212 Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = True @@ -751,7 +750,7 @@ object MainForm: TMainForm AnchorSideBottom.Control = edSaveTo Left = 0 Height = 15 - Top = 132 + Top = 140 Width = 41 Anchors = [akLeft, akBottom] Caption = 'Save to:' @@ -764,7 +763,7 @@ object MainForm: TMainForm AnchorSideRight.Control = btDownload Left = 0 Height = 23 - Top = 151 + Top = 159 Width = 334 OnAcceptDirectory = edSaveToAcceptDirectory ShowHidden = False diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0d0924fad..3bc2cde56 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -655,7 +655,7 @@ TMainForm = class(TForm) procedure AddSilentThread(URL: string); overload; // Add text to TRichMemo - procedure AddTextToInfo(title, infoText: String); + procedure AddTextToInfo(const ATitle, AValue: String); // fill edSaveTo with default path procedure FilledSaveTo; @@ -4273,37 +4273,29 @@ procedure TMainForm.AddSilentThread(URL: string); AddSilentThread(URL,mt); end; -procedure TMainForm.AddTextToInfo(title, infoText: String); +procedure TMainForm.AddTextToInfo(const ATitle, AValue: String); var + p: Integer; fp: TFontParams; - cp, np: Integer; - fn: String; + s: string; begin - infoText := Trim(infoText); - if infoText <> '' then - with rmInformation do - begin - if Trim(Lines.Text) <> '' then - Lines.Add(''); - SelStart := UTF8Length(Lines.Text); - cp := SelStart; - GetTextAttributes(cp, fp); - fn := rmInformation.Font.Name; - fp.Style := [fsBold, fsUnderline]; - fp.Name := fn; - Inc(fp.Size); - Lines.Add(title); - SelStart := UTF8Length(Lines.Text); - np := SelStart; - SetTextAttributes(cp, np - cp, fp); - if title = RS_InfoSummary then - infoText := Trim(StringBreaks(infoText)); - Lines.Add(infoText); - fp.Style := []; - fp.Name := fn; - Dec(fp.Size); - SetTextAttributes(np, UTF8Length(Lines.Text) - np, fp); - end; + s := Trim(FixWhiteSpace(AValue)); + if s = '' then Exit; + if ATitle = RS_InfoSummary then + s := Trim(StringBreaks(s)); + with rmInformation do + begin + ReadOnly := False; + if Lines.Count > 0 then + Lines.Add(''); + p := SelStart; + GetTextAttributes(p, fp); + Lines.Add(ATitle); + Lines.Add(s); + fp.Style := [fsBold, fsUnderline]; + Inc(fp.Size); + SetTextAttributes(p, Length(ATitle), fp); + end; end; procedure TMainForm.FilledSaveTo; From 86a7bbdcee4a185fa4441f3eba8e3275cc937623 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 20:17:54 +0800 Subject: [PATCH 1407/2794] added context menu copy to log form --- mangadownloader/forms/frmLogger.lfm | 13 +++++++- mangadownloader/forms/frmLogger.lrj | 3 +- mangadownloader/forms/frmLogger.pas | 41 ++++++++++++++++++++++++-- mangadownloader/languages/fmd.en.po | 6 ++++ mangadownloader/languages/fmd.id_ID.po | 6 ++++ mangadownloader/languages/fmd.po | 6 ++++ mangadownloader/md.lpi | 1 + 7 files changed, 72 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmLogger.lfm b/mangadownloader/forms/frmLogger.lfm index fc69ec75d..b223688ee 100644 --- a/mangadownloader/forms/frmLogger.lfm +++ b/mangadownloader/forms/frmLogger.lfm @@ -3,6 +3,7 @@ object FormLogger: TFormLogger Height = 283 Top = 0 Width = 457 + ActiveControl = tvLog Caption = 'Log' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 @@ -24,12 +25,13 @@ object FormLogger: TFormLogger Anchors = [akTop, akLeft, akRight, akBottom] DefaultItemHeight = 18 HotTrack = True + PopupMenu = pmLog ReadOnly = True ScrollBars = ssAutoBoth ShowTime = True TabOrder = 0 TimeFormat = 'hh:nn:ss:zzz' - Options = [tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] + Options = [tvoAllowMultiselect, tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end object ckStayOnTop: TCheckBox Left = 6 @@ -120,4 +122,13 @@ object FormLogger: TFormLogger left = 288 top = 80 end + object pmLog: TPopupMenu + OnPopup = pmLogPopup + left = 48 + top = 147 + object miCopy: TMenuItem + Caption = 'Copy' + OnClick = miCopyClick + end + end end diff --git a/mangadownloader/forms/frmLogger.lrj b/mangadownloader/forms/frmLogger.lrj index f79b1ba10..c69f54ac8 100644 --- a/mangadownloader/forms/frmLogger.lrj +++ b/mangadownloader/forms/frmLogger.lrj @@ -1,5 +1,6 @@ {"version":1,"strings":[ {"hash":119198672,"name":"tformlogger.ckstayontop.caption","sourcebytes":[83,116,97,121,32,111,110,32,116,111,112],"value":"Stay on top"}, {"hash":158511444,"name":"tformlogger.lbloglimit.caption","sourcebytes":[76,111,103,32,108,105,109,105,116],"value":"Log limit"}, -{"hash":4860802,"name":"tformlogger.btnclearlog.caption","sourcebytes":[67,108,101,97,114],"value":"Clear"} +{"hash":4860802,"name":"tformlogger.btnclearlog.caption","sourcebytes":[67,108,101,97,114],"value":"Clear"}, +{"hash":304761,"name":"tformlogger.micopy.caption","sourcebytes":[67,111,112,121],"value":"Copy"} ]} diff --git a/mangadownloader/forms/frmLogger.pas b/mangadownloader/forms/frmLogger.pas index 1af08d861..2d500bb47 100644 --- a/mangadownloader/forms/frmLogger.pas +++ b/mangadownloader/forms/frmLogger.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin, - ExtCtrls, Buttons, LogTreeView, MultiLog; + ExtCtrls, Buttons, Menus, Clipbrd, ComCtrls, LogTreeView, MultiLog; type @@ -16,6 +16,8 @@ TFormLogger = class(TForm) btnClearLog: TBitBtn; ckStayOnTop: TCheckBox; lbLogLimit: TLabel; + miCopy: TMenuItem; + pmLog: TPopupMenu; seLogLimit: TSpinEdit; tmClearLog: TTimer; tvLog: TLogTreeView; @@ -24,6 +26,8 @@ TFormLogger = class(TForm) procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); + procedure miCopyClick(Sender: TObject); + procedure pmLogPopup(Sender: TObject); procedure tmClearLogTimer(Sender: TObject); private { private declarations } @@ -80,5 +84,38 @@ procedure TFormLogger.FormDestroy(Sender: TObject); Logger.Channels.Remove(tvLog.Channel); end; -end. +procedure TFormLogger.miCopyClick(Sender: TObject); + + procedure GetItemsText(const T: TTreeNode; var S: String; const Indent: Integer = 0); + var + i: Integer; + begin + if S <> '' then + S := S + LineEnding; + S := S + StringOfChar(' ', Indent) + T.Text; + if T.Count > 0 then + for i := 0 to T.Count - 1 do + begin + S := S + LineEnding + StringOfChar(' ', Indent + 2) + T.Items[i].Text; + if T.Items[i].Count > 0 then + GetItemsText(T.Items[i], S, Indent + 2); + end; + end; + +var + s: String; + i: Integer; +begin + if tvLog.SelectionCount = 0 then Exit; + s := ''; + for i := 0 to tvLog.SelectionCount - 1 do + GetItemsText(tvLog.Selections[i], s); + Clipboard.AsText := s; +end; +procedure TFormLogger.pmLogPopup(Sender: TObject); +begin + miCopy.Enabled := tvLog.SelectionCount > 0; +end; + +end. diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 53b3ff1ee..8a18b0ab5 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -448,6 +448,11 @@ msgstr "Stay on top" msgid "Log limit" msgstr "Log limit" +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Copy" + #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" msgid "Cancel" @@ -1390,6 +1395,7 @@ msgid "Delete" msgstr "Delete" #: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" msgid "Copy" msgstr "Copy" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index cb8a049ee..f5f6d8b74 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -440,6 +440,11 @@ msgstr "Tetap di atas" msgid "Log limit" msgstr "Batasi log" +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Copy" + #: timportfavorites.btcancel.caption msgctxt "timportfavorites.btcancel.caption" msgid "Cancel" @@ -1371,6 +1376,7 @@ msgid "Delete" msgstr "Hapus" #: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" msgid "Copy" msgstr "Salin" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 0d4929462..d9d7e1076 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -405,6 +405,11 @@ msgstr "" msgid "Log limit" msgstr "" +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "" + #: timportfavorites.btcancel.caption msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" msgid "Cancel" @@ -1302,6 +1307,7 @@ msgid "Delete" msgstr "" #: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" msgid "Copy" msgstr "" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index a4db2e467..55089bf4f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -309,6 +309,7 @@ <Filename Value="forms\frmLogger.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="FormLogger"/> + <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit12> </Units> From cb84912d8e438f22c9eafd528ef49d4c75b53ffe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 15 Aug 2016 20:59:04 +0800 Subject: [PATCH 1408/2794] downloadmanager, fixed customfilename --- baseunits/uBaseUnit.pas | 14 ++++++-------- baseunits/uDownloadsManager.pas | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 839190c06..57b0d171b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -789,7 +789,7 @@ function GetHeaderValue(const AHeaders: TStrings; HName: String): String; function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, ANumbering: String; const AReplaceUnicode: Boolean; const AReplaceUnicodeStr: String; - const AFilename: String = ''): String; + const AFileName: String = ''): String; // Get substring from source function GetString(const Source, sStart, sEnd: String): String; @@ -2209,10 +2209,11 @@ function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: T end; end; -function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, ANumbering: String; +function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, AChapter, + ANumbering: String; const AReplaceUnicode: Boolean; const AReplaceUnicodeStr: String; - const AFilename: String): String; + const AFileName: String): String; function FixStringLocal(const S: String): String; begin @@ -2234,9 +2235,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh if AChapter <> '' then begin // numbering/index if (Pos(CR_NUMBERING, Result) = 0) and (Pos(CR_CHAPTER, Result) = 0) then - Result := ANumbering + Result - else - Result := Result; + Result := ANumbering + Result; if AWebsite = WebsiteRoots[FAKKU_ID, 0] then begin if Pos('%NUMBERING% - ', Result) > 0 then @@ -2276,8 +2275,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh Result := StringReplaceBrackets(Result, CR_MANGA, FixStringLocal(AMangaName), [rfReplaceAll]); Result := StringReplaceBrackets(Result, CR_AUTHOR, FixStringLocal(AAuthor), [rfReplaceAll]); Result := StringReplaceBrackets(Result, CR_ARTIST, FixStringLocal(AArtist), [rfReplaceAll]); - Result := StringReplaceBrackets(Result, CR_FILENAME, FixStringLocal(AFilename), [rfReplaceAll]); - + Result := StringReplaceBrackets(Result, CR_FILENAME, FixStringLocal(AFileName), [rfReplaceAll]); if Result = '' then Result := FixStringLocal(AMangaName); if Result = '' then Exit; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8d96c9d7c..927dacd6f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1225,6 +1225,7 @@ procedure TTaskThread.Execute; Container.ChapterName[Container.CurrentDownloadChapterPtr], '', OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr, CR_FILENAME); // Get page number. From c506a7751a1b031a86e1d305df4f3f903370e2e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 10:01:50 +0800 Subject: [PATCH 1409/2794] imginfos, implement all supported image checkstream and getimagesize as fast as possible, stream position assumed to be always 0 --- baseunits/ImgInfos.pas | 279 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 253 insertions(+), 26 deletions(-) diff --git a/baseunits/ImgInfos.pas b/baseunits/ImgInfos.pas index 754e50794..c7c11baf4 100644 --- a/baseunits/ImgInfos.pas +++ b/baseunits/ImgInfos.pas @@ -40,14 +40,18 @@ interface type PImageHandlerRec = ^TImageHandlerRec; + TCheckImageStreamFunc = function(const Stream: TStream): Boolean; + TGetImageStreamSizeProc = procedure(const Stream: TStream; out Width, Height: Integer); TImageHandlerRec = record - Ext: String; - WExt: String; ReaderClass: TFPCustomImageReaderClass; WriterClass: TFPCustomImageWriterClass; - Reader: TFPCustomImageReader + CheckImageStream: TCheckImageStreamFunc; + GetImageStreamSize: TGetImageStreamSizeProc; + Ext: String; + WExt: String; end; + { TimageHandlerMgr } TimageHandlerMgr = class @@ -58,8 +62,12 @@ TimageHandlerMgr = class public constructor Create; destructor Destroy; override; - procedure Add(const ReaderClass: TFPCustomImageReaderClass; const WriterClass: TFPCustomImageWriterClass; - const Ext: String; WExt: String = ''); + procedure Add(const ReaderClass: TFPCustomImageReaderClass; + const WriterClass: TFPCustomImageWriterClass; + const CheckImageStreamFunc: TCheckImageStreamFunc; + const GetImageStreamSizeProc: TGetImageStreamSizeProc; + const Ext: String; + const WExt: String = ''); function GetImageHandlerByStream(const Stream: TStream): PImageHandlerRec; function GetImageHandlerByFile(const FileName: String): PImageHandlerRec; function GetImageHandlerByExt(const Ext: String): PImageHandlerRec; @@ -181,18 +189,16 @@ constructor TimageHandlerMgr.Create; end; destructor TimageHandlerMgr.Destroy; -var - i: Integer; begin - if Length(FList) <> 0 then - for i := High(FList) downto Low(FList) do - Flist[i].Reader.Free; SetLength(Flist, 0); inherited Destroy; end; procedure TimageHandlerMgr.Add(const ReaderClass: TFPCustomImageReaderClass; - const WriterClass: TFPCustomImageWriterClass; const Ext: String; WExt: String); + const WriterClass: TFPCustomImageWriterClass; + const CheckImageStreamFunc: TCheckImageStreamFunc; + const GetImageStreamSizeProc: TGetImageStreamSizeProc; const Ext: String; + const WExt: String); var i: Integer; begin @@ -200,7 +206,8 @@ procedure TimageHandlerMgr.Add(const ReaderClass: TFPCustomImageReaderClass; SetLength(FList, i + 1); FList[i].ReaderClass := ReaderClass; FList[i].WriterClass := WriterClass; - FList[i].Reader := ReaderClass.Create; + FList[i].CheckImageStream := CheckImageStreamFunc; + FList[i].GetImageStreamSize := GetImageStreamSizeProc; FList[i].Ext := Ext; if WExt <> '' then FList[i].WExt := WExt @@ -218,10 +225,10 @@ function TimageHandlerMgr.GetImageHandlerByStream(const Stream: TStream): PImage if Stream.Size = 0 then Exit; P := Stream.Position; try - for i := 0 to Length(Flist) - 1 do + for i := Low(FList) to High(Flist) do begin Stream.Position := 0; - if FList[i].Reader.CheckContents(Stream) then + if FList[i].CheckImageStream(Stream) then begin Result := @FList[i]; Break; @@ -273,18 +280,13 @@ function TimageHandlerMgr.GetImageStreamSize(const Stream: TStream; out Width, Height: Integer): String; var H: PImageHandlerRec; - S: TPoint; begin Width := 0; Height := 0; H := GetImageHandlerByStream(Stream); Result := H^.Ext; - if Assigned(H^.Reader) then - begin - S := H^.Reader.ImageSize(Stream); - Width := S.x; - Height := S.y; - end; + if Assigned(H^.GetImageStreamSize) then + H^.GetImageStreamSize(Stream, Width, Height); end; function TimageHandlerMgr.GetImageFileSize(const FileName: String; out Width, @@ -345,13 +347,238 @@ function TimageHandlerMgr.GetImageWriterExt(const Ext: String): String; Result := GetImageHandlerByExt(Ext)^.WExt; end; +function JPEGCheckImageStream(const Stream: TStream): Boolean; +var + Hdr: Word = 0; +begin + Result := (Stream.Read(Hdr, 2) = 2) and (Hdr = $D8FF); +end; + +procedure JPEGGetImageSize(const Stream: TStream; out Width, Height: Integer); +var + B: Byte = 0; + W: Word = 0; +begin + if Stream.Seek(2, soFromBeginning) <> 2 then Exit; + if Stream.Read(B, 1) <> 1 then Exit; + while (Stream.Position < Stream.Size) and (B = $FF) do + begin + Stream.Read(B, 1); + case B of + $C0..$C3: + begin + Stream.Seek(3, soFromCurrent); + Stream.Read(W, 2); + Height := Swap(W); + Stream.Read(W, 2); + Width := Swap(W); + Stream.Read(B, 1); + Exit; + end; + $FF: + Stream.Read(B, 1); + $D0..$D9, $01: + begin + Stream.Seek(1, soFromCurrent); + Stream.Read(B, 1); + end; + else + begin + Stream.Read(W, 2); + Stream.Seek(Swap(W) - 2, soFromCurrent); + Stream.Read(B, 1); + end; + end; + end; +end; + +function PNGCheckImageStream(const Stream: TStream): Boolean; +var + Hdr: array[0..7] of Char = (' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); +begin + Result := (Stream.Read(Hdr, 8) = 8) and (Hdr = #137'PNG'#13#10#26#10); +end; + +procedure PNGGetImageSize(const Stream: TStream; out Width, Height: Integer); +var + W: Word = 0; + H: Word = 0; +begin + if not ((Stream.Seek(18, soFromBeginning) = 18) + and (Stream.Read(W, 2) = 2) + and (Stream.Seek(2, soFromCurrent) = 22) + and (Stream.Read(H, 2) = 2)) then Exit; + {$IFDEF ENDIAN_LITTLE} + W := Swap(W); + H := Swap(H); + {$ENDIF} + Width := W; + Height := H; +end; + +function GIFCheckImageStream(const Stream: TStream): Boolean; +var + Hdr: array[0..5] of Char = (' ', ' ', ' ', ' ', ' ', ' '); +begin + Result := (Stream.Read(Hdr, 6) = 6) and ((Hdr = 'GIF87a') or (Hdr = 'GIF89a')); +end; + +procedure GIFGetImageSize(const Stream: TStream; out Width, Height: Integer); +type + TGifHeader = packed record + Sig: array[0..5] of Char; + ScreenWidth, + ScreenHeight: Word; + PackedBit, + BackgroundColor, + AspectRatio: Byte; + end; + TGifImageDescriptor = packed record + Left, + Top, + Width, + Height: Word; + PackedBit: Byte; + end; +var + Hdr: TGifHeader; + Des: TGifImageDescriptor; + PalleteSize: Integer = 0; + C: Byte = 0; +begin + FillChar(Hdr{%H-}, SizeOf(Hdr), 0); + if Stream.Read(Hdr, SizeOf(TGifHeader)) <> SizeOf(TGifHeader) then Exit; + if (Hdr.PackedBit and $80) <> 0 then + begin + PalleteSize := 3 * (1 shl (Hdr.Packedbit and 7 + 1)); + if Stream.Seek(PalleteSize, soFromCurrent) <> SizeOf(TGifHeader) + PalleteSize then Exit; + end; + FillChar(Des{%H-}, SizeOf(TGifImageDescriptor), 0); + while Stream.Position < Stream.Size do + begin + Stream.Read(C, 1); + if C = $2C then + begin + if Stream.Read(Des, SizeOf(TGifImageDescriptor)) <> SizeOf(TGifImageDescriptor) then Exit; + {$IFDEF ENDIAN_BIG} + Des.Width := LEtoN(Width); + Des.Height := LEtoN(Height); + {$ENDIF} + Width := Des.Width; + Height := Des.Height; + Break; + end; + end; +end; + +function BMPCheckImageStream(const Stream: TStream): Boolean; +var + Hdr: Word = 0; +begin + Result := (Stream.Read(Hdr, 2) = 2) and (Hdr = 19778); +end; + +procedure BMPGetImageSize(const Stream: TStream; out Width, Height: Integer); +var + W: LongInt = 0; + H: LongInt = 0; +begin + if not ((Stream.Seek(18, soFromBeginning) = 18) + and (Stream.Read(W, 4) = 4) + and (Stream.Read(H, 4) = 4)) then Exit; + Width := LEtoN(W); + Height := abs(LEtoN(H)); +end; + +function FixEndian(const W: Word; const BE: Boolean): Word; overload; +begin + if BE then + Result := BEtoN(W) + else + Result := LEtoN(W); +end; + +function TIFFCheckImageStream(const Stream: TStream): Boolean; +var + Hdr: array[0..1] of Char = (' ', ' '); + Sig: Word = 0; + BE: Boolean = False; + + function CheckHdr: Boolean; + begin + Result := True; + if Hdr = 'II' then BE := False + else if Hdr = 'MM' then BE := True + else Result := False; + end; + +begin + Result := (Stream.Read(Hdr, 2) = 2) and CheckHdr + and (Stream.Read(Sig, 2) = 2) and (FixEndian(Sig, BE) = 42); +end; + +function FixEndian(const W: DWord; const BE: Boolean): DWord; overload; +begin + if BE then + Result := BEtoN(W) + else + Result := LEtoN(W); +end; + +procedure TIFFGetImageSize(const Stream: TStream; out Width, Height: Integer); +type + TIDF_Field = packed record + Tag, + FieldType: Word; + ValCount, + ValOffset: DWord; + end; +var + Hdr: array[0..1] of Char = (' ', ' '); + BE: Boolean = False; + Imgs: Word = 0; + Field: TIDF_Field; + i: Word; + + function CheckHdr: Boolean; + begin + Result := True; + if Hdr = 'II' then BE := False + else if Hdr = 'MM' then BE := True + else Result := False; + end; + + function ReadDir: Boolean; + begin + Result := Stream.Read(Field, SizeOf(TIDF_Field)) = SizeOf(TIDF_Field); + if not Result then Exit; + Field.Tag := FixEndian(Field.Tag, BE); + Field.ValOffset := FixEndian(Field.ValOffset, BE); + end; + +begin + if not ((Stream.Read(Hdr, 2) = 2) and CheckHdr) then Exit; + if Stream.Seek(6, soFromCurrent) <> 8 then Exit; + if Stream.Read(Imgs, 2) <> 2 then Exit; + Imgs := FixEndian(Imgs, BE); + FillChar(Field{%H-}, SizeOf(TIDF_Field), 0); + for i := 1 to Imgs do + begin + if not ReadDir then Exit; + case Field.Tag of + $0100: Width := Field.ValOffset; + $0101: Height := Field.ValOffset; + end; + end; +end; + initialization ImageHandlerMgr := TimageHandlerMgr.Create; - ImageHandlerMgr.Add(TFPReaderJPEG, TFPWriterJPEG, 'jpg'); - ImageHandlerMgr.Add(TFPReaderPNG, TFPWriterPNG, 'png'); - ImageHandlerMgr.Add(TFPReaderGif, TFPWriterPNG, 'gif', 'png'); - ImageHandlerMgr.Add(TFPReaderBMP, TFPWriterBMP, 'bmp'); - ImageHandlerMgr.Add(TFPReaderTiff, TFPWriterTiff, 'tif'); + ImageHandlerMgr.Add(TFPReaderJPEG, TFPWriterJPEG, @JPEGCheckImageStream, @JPEGGetImageSize, 'jpg'); + ImageHandlerMgr.Add(TFPReaderPNG, TFPWriterPNG, @PNGCheckImageStream, @PNGGetImageSize, 'png'); + ImageHandlerMgr.Add(TFPReaderGif, TFPWriterPNG, @GIFCheckImageStream, @GIFGetImageSize, 'gif', 'png'); + ImageHandlerMgr.Add(TFPReaderBMP, TFPWriterBMP, @BMPCheckImageStream, @BMPGetImageSize, 'bmp'); + ImageHandlerMgr.Add(TFPReaderTiff, TFPWriterTiff, @TIFFCheckImageStream, @TIFFGetImageSize, 'tif'); finalization ImageHandlerMgr.Free; From ddfe323a7a057db04cbefc58f6768212071ddcaa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 10:02:51 +0800 Subject: [PATCH 1410/2794] img2pdf, ifdef code that available only in fpc 3.1.1, hide some warning --- baseunits/Img2Pdf.pas | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 18c6f7dac..37c0782c1 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -170,7 +170,7 @@ procedure JPEGToPageInfo(const PageInfo: TPageInfo); PageInfo.Filter := 'DCTDecode'; try AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite); - FillChar(JDS, SizeOf(JDS), 0); + FillChar(JDS{%H-}, SizeOf(JDS), 0); JDS.err := @JPEGError; jpeg_CreateDecompress(@JDS, JPEG_LIB_VERSION, SizeOf(JDS)); try @@ -217,7 +217,9 @@ procedure JPEGCompressToPageInfo(const PageInfo: TPageInfo); WRT := TFPWriterJPEG.Create; try WRT.CompressionQuality := PageInfo.Owner.CompressionQuality; + {$IF (FPC_FULLVERSION >= 30101)} WRT.GrayScale := (PageInfo.ColorSpace = 'DeviceGray'); + {$ENDIF} IMG.SaveToStream(PageInfo.Stream, WRT); finally WRT.Free; @@ -303,7 +305,7 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); else begin PageInfo.ColorSpace := 'DeviceRGB'; - FillChar(CLW, SizeOf(CLW), $FF); + FillChar(CLW{%H-}, SizeOf(CLW), $FF); for Y := 0 to IMG.Height - 1 do for X := 0 to IMG.Width - 1 do begin @@ -359,7 +361,7 @@ procedure ImageToPageInfo(const PageInfo: TPageInfo); end; AMS := TMemoryStreamUTF8.Create; try - FillChar(CLW, SizeOf(CLW), $FF); + FillChar(CLW{%H-}, SizeOf(CLW), $FF); for Y := 0 to IMG.Height - 1 do for X := 0 to IMG.Width - 1 do begin From 18f3b918a305e8ba5f51a45c8be729ced86836c2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 11:13:11 +0800 Subject: [PATCH 1411/2794] replace tdirectoryedit with teditbutton, compatibility wit laz 1.6 --- mangadownloader/forms/frmMain.lfm | 431 +++++++++++++++--------------- mangadownloader/forms/frmMain.lrj | 6 +- mangadownloader/forms/frmMain.pas | 64 ++++- 3 files changed, 273 insertions(+), 228 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f115fac54..f19b3c0fb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,7 +13,6 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter - LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 @@ -37,13 +36,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsInformation + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 1 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -757,60 +756,6 @@ object MainForm: TMainForm ParentColor = False ParentFont = False end - object edSaveTo: TDirectoryEdit - AnchorSideLeft.Control = lbSaveTo - AnchorSideTop.Control = btReadOnline - AnchorSideRight.Control = btDownload - Left = 0 - Height = 23 - Top = 159 - Width = 334 - OnAcceptDirectory = edSaveToAcceptDirectory - ShowHidden = False - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 - 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 - 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 - 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 - 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 - 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 - 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC - DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 - 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 - D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 - AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA - D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 - B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC - DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 - B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD - DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B - B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE - DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D - BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 - DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F - BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 - E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 - C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 - E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 - C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA - FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 - C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC - FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 - CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 - FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 - CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 - CC810088CC810088CC810088CC810088CC610087CB000087CB00 - } - NumGlyphs = 1 - Anchors = [akTop, akLeft, akRight] - MaxLength = 0 - ParentFont = False - TabOrder = 5 - TextHint = 'Save to' - end object edFilterMangaInfoChapters: TEditButton Left = 0 Height = 23 @@ -858,27 +803,81 @@ object MainForm: TMainForm OnButtonClick = edFilterMangaInfoChaptersButtonClick OnChange = edFilterMangaInfoChaptersChange PasswordChar = #0 - TabOrder = 6 + TabOrder = 5 TextHint = 'Filter' Visible = False end + object edSaveTo: TEditButton + AnchorSideLeft.Control = lbSaveTo + AnchorSideTop.Control = btReadOnline + AnchorSideRight.Control = btDownload + Left = 0 + Height = 23 + Top = 159 + Width = 334 + Anchors = [akTop, akLeft, akRight] + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edSaveToButtonClick + ParentFont = False + PasswordChar = #0 + TabOrder = 6 + TextHint = 'Save to' + end end end end object tsFilter: TTabSheet Caption = 'Filter' - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 object sbFilter: TScrollBox Left = 0 - Height = 484 + Height = 492 Top = 0 Width = 558 HorzScrollBar.Page = 488 VertScrollBar.Page = 416 Align = alClient BorderStyle = bsNone - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 TabOrder = 0 object pnCustomGenre: TPanel @@ -2216,13 +2215,49 @@ object MainForm: TMainForm Caption = 'Open manga by using external program:' ParentColor = False end - object edOptionExternalPath: TFileNameEdit + object lbOptionExternalParams: TLabel + Left = 4 + Height = 15 + Top = 50 + Width = 508 + Align = alTop + Caption = 'Parameters:' + ParentColor = False + end + object edOptionExternalParams: TEdit + AnchorSideLeft.Control = lbOptionExternalParams + AnchorSideTop.Control = lbOptionExternalParams + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 69 + Width = 481 + Anchors = [akTop, akLeft, akRight] + TabOrder = 0 + TextHint = 'External program parameters' + end + object lbOptionExternalParamsHint: TLabel + AnchorSideLeft.Control = edOptionExternalParams + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edOptionExternalParams + AnchorSideTop.Side = asrCenter + Left = 489 + Height = 15 + Top = 73 + Width = 13 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + object edOptionExternalPath: TEditButton Left = 4 Height = 23 Top = 23 Width = 508 - FilterIndex = 0 - HideDirectories = False + Align = alTop ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -2260,49 +2295,13 @@ object MainForm: TMainForm CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 CC810088CC810088CC810088CC810088CC610087CB000087CB00 } - NumGlyphs = 1 - Align = alTop MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edOptionExternalPathButtonClick + PasswordChar = #0 TabOrder = 1 TextHint = 'External program path' end - object lbOptionExternalParams: TLabel - Left = 4 - Height = 15 - Top = 50 - Width = 508 - Align = alTop - Caption = 'Parameters:' - ParentColor = False - end - object edOptionExternalParams: TEdit - AnchorSideLeft.Control = lbOptionExternalParams - AnchorSideTop.Control = lbOptionExternalParams - AnchorSideTop.Side = asrBottom - Left = 4 - Height = 23 - Top = 69 - Width = 481 - Anchors = [akTop, akLeft, akRight] - TabOrder = 0 - TextHint = 'External program parameters' - end - object lbOptionExternalParamsHint: TLabel - AnchorSideLeft.Control = edOptionExternalParams - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edOptionExternalParams - AnchorSideTop.Side = asrCenter - Left = 489 - Height = 15 - Top = 73 - Width = 13 - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end end object lbOptionLanguage: TLabel Left = 4 @@ -2394,7 +2393,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object cbOptionShowDownloadToolbar: TCheckBox Left = 4 @@ -2841,7 +2840,7 @@ object MainForm: TMainForm ) OnSelectionChanged = rgOptionCompressSelectionChanged ParentFont = False - TabOrder = 2 + TabOrder = 1 end object gbOptionRenaming: TGroupBox AnchorSideLeft.Control = lbDefaultDownloadPath @@ -2864,7 +2863,7 @@ object MainForm: TMainForm ClientHeight = 282 ClientWidth = 502 ParentFont = False - TabOrder = 4 + TabOrder = 3 object cbOptionChangeUnicodeCharacter: TCheckBox Left = 4 Height = 19 @@ -3124,57 +3123,6 @@ object MainForm: TMainForm ParentColor = False ParentFont = False end - object edOptionDefaultPath: TDirectoryEdit - Left = 4 - Height = 23 - Top = 27 - Width = 506 - OnAcceptDirectory = edSaveToAcceptDirectory - ShowHidden = False - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 - 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 - 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 - 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 - 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 - 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 - 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC - DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 - 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 - D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 - AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA - D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 - B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC - DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 - B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD - DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B - B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE - DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D - BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 - DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F - BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 - E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 - C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 - E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 - C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA - FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 - C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC - FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 - CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 - FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 - CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 - CC810088CC810088CC810088CC810088CC610087CB000087CB00 - } - NumGlyphs = 1 - Align = alTop - MaxLength = 0 - ParentFont = False - TabOrder = 0 - TextHint = 'Default download path' - end object Panel8: TPanel Left = 4 Height = 0 @@ -3183,7 +3131,7 @@ object MainForm: TMainForm Align = alTop AutoSize = True BevelOuter = bvNone - TabOrder = 1 + TabOrder = 0 end object lbOptionPDFQualityHint: TLabel AnchorSideLeft.Control = lbOptionPDFQuality @@ -3217,7 +3165,7 @@ object MainForm: TMainForm ParentFont = False ParentShowHint = False ShowHint = True - TabOrder = 3 + TabOrder = 2 Value = 100 end object lbOptionPDFQuality: TLabel @@ -3238,6 +3186,57 @@ object MainForm: TMainForm ParentShowHint = False ShowHint = True end + object edOptionDefaultPath: TEditButton + Left = 4 + Height = 23 + Top = 27 + Width = 506 + Align = alTop + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edOptionDefaultPathButtonClick + ParentFont = False + PasswordChar = #0 + TabOrder = 4 + TextHint = 'Default download path' + end end end object tsUpdate: TTabSheet @@ -3627,11 +3626,11 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object pcMisc: TPageControl Left = 4 - Height = 363 + Height = 371 Top = 8 Width = 523 ActivePage = tsCustomColor @@ -3649,7 +3648,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 335 + ClientHeight = 343 ClientWidth = 515 object ckEnableLogging: TCheckBox Left = 4 @@ -3659,60 +3658,8 @@ object MainForm: TMainForm Caption = 'Enable logging' TabOrder = 0 end - object edLogFileName: TFileNameEdit - AnchorSideLeft.Control = ckEnableLogging - AnchorSideTop.Control = lbLogFileName - AnchorSideTop.Side = asrBottom - Left = 4 - Height = 23 - Top = 46 - Width = 506 - FilterIndex = 0 - HideDirectories = False - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000002E45000064970000629300005E8E30005C8C7C005884950000001F0000 - 001A0000001A0000001A0000001A0000001A0000001A00000011000000000000 - 0000002E450000659950006497991C7AA9C052A5CDE0075477E225250A932B2B - 0C8A2D2D0D872D2D0D872D2D0D872D2D0D872D2D0D8723230B6A000000110000 - 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF4186A8FFE5E5E5FFE5E5 - E4FFFEFEFDFFFEFEFCFFFDFDFAFFFCFCF9FFFEFEF9FF3B3B1B88000000090000 - 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF4489ACFFE4E4E4FFE3E3 - E2FFFCFCFBFFFBFBF8FFFAFAF6FFF8F8F4FFFBFBF5FF4F4F2C7D000000000054 - 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF468BAFFFB7B7A8FFB6B6 - A7FFDBDBCAFFD1D1C0FFF8F8F4FFF7F7F1FFFAFAF4FF58583276005782000073 - AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF488FB2FFD5D5C6FFD4D4 - C5FFEBEBDAFFE9E9D8FFF7F7F1FFF5F5EFFFFAFAF2FF5D5D37740076B0000076 - B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF4C92B6FFB5B5A6FFC4C4 - B4FFC7C7B6FFD6D6C5FFD4D4C3FFCACAB9FFF8F8EEFF62623C720078B4000078 - B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF4F96B8FFD3D3C4FFD1D1 - C2FFE7E7D6FFE5E5D4FFE4E4D3FFE2E2D1FFF6F6E8FF67674070007BB800007B - B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF5299BCFFB3B3A3FFC0C0 - B1FFC3C3B2FFC2C2B1FFC0C0AFFFBEBEADFFF3F3E3FF6C6C446E007DBB00007D - BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF569CBFFFCFCFC0FFCECE - BEFFE4E4D3FFF0F0E6FFEBEBDDFFE7E7D6FFF2F2E1FF7171486C007FBF00007F - BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF589FC2FFAFAFA0FFBDBD - AEFFC8C8B7FFEBEBDDFFA4A493FFA4A493FFA4A493FF4949257C0082C2000082 - C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF62A8C9FFDBDBD4FFD8D8 - CFFFEBEBDDFFE7E7D6FFB6B6A5FFFFFFFFFF79795069797950250084C5000084 - C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF6DAFCDFFEDEDE4FFF4F4 - E7FFF4F4E3FFF2F2E1FFC2C2B1FF467F85B87C7C5225797950000085C8000085 - C8000085C885ADF1FFFFABEFFEFF94E2F8FF6EC8EDFF4397B9FF8EB7BAFF8EB7 - BAFF8EB7BAFF8EB7BAFF93BCBBFF1B84B0963E818E003D7F8C000087CA000087 - CA000087CA8388DBF4FF60C1E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 - FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 - CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 - CC810088CC810088CC810088CC810088CC610087CB000087CB00 - } - NumGlyphs = 1 - Anchors = [akTop, akLeft, akRight] - MaxLength = 0 - TabOrder = 1 - end object btClearLogFile: TBitBtn - AnchorSideLeft.Control = edLogFileName + AnchorSideLeft.Control = ckEnableLogging AnchorSideTop.Control = edLogFileName AnchorSideTop.Side = asrBottom Left = 4 @@ -3758,7 +3705,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btClearLogFileClick - TabOrder = 2 + TabOrder = 1 end object lbLogFileName: TLabel AnchorSideLeft.Control = ckEnableLogging @@ -3818,6 +3765,58 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btOpenLogClick + TabOrder = 2 + end + object edLogFileName: TEditButton + AnchorSideLeft.Control = ckEnableLogging + AnchorSideTop.Control = lbLogFileName + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 23 + Top = 46 + Width = 506 + Anchors = [akTop, akLeft, akRight] + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C005884950000001F0000 + 001A0000001A0000001A0000001A0000001A0000001A00000011000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0075477E225250A932B2B + 0C8A2D2D0D872D2D0D872D2D0D872D2D0D872D2D0D8723230B6A000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF4186A8FFE5E5E5FFE5E5 + E4FFFEFEFDFFFEFEFCFFFDFDFAFFFCFCF9FFFEFEF9FF3B3B1B88000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF4489ACFFE4E4E4FFE3E3 + E2FFFCFCFBFFFBFBF8FFFAFAF6FFF8F8F4FFFBFBF5FF4F4F2C7D000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF468BAFFFB7B7A8FFB6B6 + A7FFDBDBCAFFD1D1C0FFF8F8F4FFF7F7F1FFFAFAF4FF58583276005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF488FB2FFD5D5C6FFD4D4 + C5FFEBEBDAFFE9E9D8FFF7F7F1FFF5F5EFFFFAFAF2FF5D5D37740076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF4C92B6FFB5B5A6FFC4C4 + B4FFC7C7B6FFD6D6C5FFD4D4C3FFCACAB9FFF8F8EEFF62623C720078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF4F96B8FFD3D3C4FFD1D1 + C2FFE7E7D6FFE5E5D4FFE4E4D3FFE2E2D1FFF6F6E8FF67674070007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF5299BCFFB3B3A3FFC0C0 + B1FFC3C3B2FFC2C2B1FFC0C0AFFFBEBEADFFF3F3E3FF6C6C446E007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF569CBFFFCFCFC0FFCECE + BEFFE4E4D3FFF0F0E6FFEBEBDDFFE7E7D6FFF2F2E1FF7171486C007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF589FC2FFAFAFA0FFBDBD + AEFFC8C8B7FFEBEBDDFFA4A493FFA4A493FFA4A493FF4949257C0082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF62A8C9FFDBDBD4FFD8D8 + CFFFEBEBDDFFE7E7D6FFB6B6A5FFFFFFFFFF79795069797950250084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF6DAFCDFFEDEDE4FFF4F4 + E7FFF4F4E3FFF2F2E1FFC2C2B1FF467F85B87C7C5225797950000085C8000085 + C8000085C885ADF1FFFFABEFFEFF94E2F8FF6EC8EDFF4397B9FF8EB7BAFF8EB7 + BAFF8EB7BAFF8EB7BAFF93BCBBFF1B84B0963E818E003D7F8C000087CA000087 + CA000087CA8388DBF4FF60C1E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edLogFileNameButtonClick + PasswordChar = #0 TabOrder = 3 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 0d96fed33..57cf15ac3 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -18,8 +18,8 @@ {"hash":119380261,"name":"tmainform.btreadonline.caption","sourcebytes":[82,101,97,100,32,111,110,108,105,110,101],"value":"Read online"}, {"hash":215882787,"name":"tmainform.btaddtofavorites.caption","sourcebytes":[65,100,100,32,116,111,32,102,97,118,111,114,105,116,101,115],"value":"Add to favorites"}, {"hash":147292346,"name":"tmainform.lbsaveto.caption","sourcebytes":[83,97,118,101,32,116,111,58],"value":"Save to:"}, -{"hash":160200703,"name":"tmainform.edsaveto.texthint","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":80755394,"name":"tmainform.edfiltermangainfochapters.texthint","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":160200703,"name":"tmainform.edsaveto.texthint","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":80755394,"name":"tmainform.tsfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, {"hash":236121459,"name":"tmainform.lbfiltercustomgenres.caption","sourcebytes":[67,117,115,116,111,109,32,71,101,110,114,101,115],"value":"Custom Genres"}, {"hash":58090881,"name":"tmainform.edcustomgenres.texthint","sourcebytes":[73,110,112,117,116,32,99,117,115,116,111,109,32,103,101,110,114,101,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,99,111,109,109,97],"value":"Input custom genres, separated by comma"}, @@ -136,10 +136,10 @@ {"hash":251042137,"name":"tmainform.cboptionlivesearch.caption","sourcebytes":[69,110,97,98,108,101,32,108,105,118,101,32,115,101,97,114,99,104,32,40,115,108,111,119,32,111,110,32,108,111,110,103,32,108,105,115,116,41],"value":"Enable live search (slow on long list)"}, {"hash":186997165,"name":"tmainform.gboptionexternal.caption","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109],"value":"External program"}, {"hash":36189706,"name":"tmainform.lboptionexternal.caption","sourcebytes":[79,112,101,110,32,109,97,110,103,97,32,98,121,32,117,115,105,110,103,32,101,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,58],"value":"Open manga by using external program:"}, -{"hash":172309816,"name":"tmainform.edoptionexternalpath.texthint","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,112,97,116,104],"value":"External program path"}, {"hash":60572138,"name":"tmainform.lboptionexternalparams.caption","sourcebytes":[80,97,114,97,109,101,116,101,114,115,58],"value":"Parameters:"}, {"hash":242848131,"name":"tmainform.edoptionexternalparams.texthint","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,112,97,114,97,109,101,116,101,114,115],"value":"External program parameters"}, {"hash":24397,"name":"tmainform.lboptionexternalparamshint.caption","sourcebytes":[91,63,93],"value":"[?]"}, +{"hash":172309816,"name":"tmainform.edoptionexternalpath.texthint","sourcebytes":[69,120,116,101,114,110,97,108,32,112,114,111,103,114,97,109,32,112,97,116,104],"value":"External program path"}, {"hash":82521866,"name":"tmainform.lboptionlanguage.caption","sourcebytes":[76,97,110,103,117,97,103,101,58],"value":"Language:"}, {"hash":93623386,"name":"tmainform.lboptionletfmddo.caption","sourcebytes":[65,102,116,101,114,32,100,111,119,110,108,111,97,100,32,102,105,110,105,115,104,58],"value":"After download finish:"}, {"hash":160062057,"name":"tmainform.lboptionnewmangatime.caption","sourcebytes":[78,101,119,32,109,97,110,103,97,32,98,97,115,101,100,32,111,110,32,32,105,116,39,115,32,117,112,100,97,116,101,32,116,105,109,101,32,40,100,97,121,115,41],"value":"New manga based on it's update time (days)"}, @@ -191,11 +191,11 @@ {"hash":222491525,"name":"tmainform.edoptionfilenamecustomrename.texthint","sourcebytes":[67,117,115,116,111,109,32,114,101,110,97,109,101],"value":"Custom rename"}, {"hash":46419594,"name":"tmainform.lboptionfilenamecustomrename.caption","sourcebytes":[70,105,108,101,110,97,109,101,58],"value":"Filename:"}, {"hash":1010826,"name":"tmainform.lbdefaultdownloadpath.caption","sourcebytes":[67,104,111,111,115,101,32,116,104,101,32,100,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104,58],"value":"Choose the default download path:"}, -{"hash":8726312,"name":"tmainform.edoptiondefaultpath.texthint","sourcebytes":[68,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104],"value":"Default download path"}, {"hash":24397,"name":"tmainform.lboptionpdfqualityhint.caption","sourcebytes":[91,63,93],"value":"[?]"}, {"hash":265971401,"name":"tmainform.seoptionpdfquality.hint","sourcebytes":[49,48,48,32,61,32,70,108,97,116,101,69,110,99,111,100,101,32,40,108,111,115,115,108,101,115,115,41,44,32,108,111,119,101,114,32,61,32,68,67,84,69,110,99,111,100,101,32,40,108,111,115,115,121,41],"value":"100 = FlateEncode (lossless), lower = DCTEncode (lossy)"}, {"hash":265971401,"name":"tmainform.lboptionpdfquality.hint","sourcebytes":[49,48,48,32,61,32,70,108,97,116,101,69,110,99,111,100,101,32,40,108,111,115,115,108,101,115,115,41,44,32,108,111,119,101,114,32,61,32,68,67,84,69,110,99,111,100,101,32,40,108,111,115,115,121,41],"value":"100 = FlateEncode (lossless), lower = DCTEncode (lossy)"}, {"hash":13786124,"name":"tmainform.lboptionpdfquality.caption","sourcebytes":[80,68,70,32,99,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PDF compression level"}, +{"hash":8726312,"name":"tmainform.edoptiondefaultpath.texthint","sourcebytes":[68,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104],"value":"Default download path"}, {"hash":208308883,"name":"tmainform.tsupdate.caption","sourcebytes":[85,112,100,97,116,101,115],"value":"Updates"}, {"hash":72408384,"name":"tmainform.cboptionautochecklatestversion.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,108,97,116,101,115,116,32,118,101,114,115,105,111,110,32],"value":"Auto check for latest version "}, {"hash":225003075,"name":"tmainform.gboptionfavorites.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3bc2cde56..22ee38edc 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -70,13 +70,14 @@ TMainForm = class(TForm) edDownloadsSearch: TEdit; edFilterMangaInfoChapters: TEditButton; edFavoritesSearch: TEdit; + edLogFileName: TEditButton; edOptionChangeUnicodeCharacterStr: TEdit; + edOptionDefaultPath: TEditButton; + edOptionExternalPath: TEditButton; edOptionFilenameCustomRename: TEdit; - edOptionDefaultPath: TDirectoryEdit; edOptionMangaCustomRename: TEdit; - edSaveTo: TDirectoryEdit; + edSaveTo: TEditButton; edURL: TEditButton; - edLogFileName: TFileNameEdit; lbLogFileName: TLabel; lbOptionFilenameCustomRenameHint: TLabel; lbOptionFilenameCustomRename: TLabel; @@ -140,7 +141,6 @@ TMainForm = class(TForm) TransferRateGraph: TChart; ckDropTarget: TCheckBox; edOptionExternalParams: TEdit; - edOptionExternalPath: TFileNameEdit; edWebsitesSearch: TEdit; gbDropTarget: TGroupBox; gbOptionExternal: TGroupBox; @@ -418,10 +418,13 @@ TMainForm = class(TForm) procedure edFavoritesSearchChange(Sender: TObject); procedure edFilterMangaInfoChaptersButtonClick(Sender: TObject); procedure edFilterMangaInfoChaptersChange(Sender: TObject); - procedure edSaveToAcceptDirectory(Sender: TObject; var Value: String); + procedure edLogFileNameButtonClick(Sender: TObject); procedure edMangaListSearchChange(Sender: TObject); procedure edMangaListSearchKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState ); + procedure edOptionDefaultPathButtonClick(Sender: TObject); + procedure edOptionExternalPathButtonClick(Sender: TObject); + procedure edSaveToButtonClick(Sender: TObject); procedure edURLButtonClick(Sender: TObject); procedure edURLKeyPress(Sender: TObject; var Key: Char); procedure edWebsitesSearchChange(Sender: TObject); @@ -2408,9 +2411,16 @@ procedure TMainForm.edFilterMangaInfoChaptersChange(Sender: TObject); FilterChapterList(edFilterMangaInfoChapters.Text, miChapterListHideDownloaded.Checked); end; -procedure TMainForm.edSaveToAcceptDirectory(Sender: TObject; var Value: String); +procedure TMainForm.edLogFileNameButtonClick(Sender: TObject); begin - Value := CleanAndExpandDirectory(Value); + with TOpenDialog.Create(nil) do + try + InitialDir := ExtractFileDir(edLogFileName.Text); + if Execute then + edLogFileName.Text := FileName; + finally + Free; + end; end; procedure TMainForm.edURLKeyPress(Sender: TObject; var Key: Char); @@ -4441,7 +4451,7 @@ procedure TMainForm.LoadOptions; cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); cbOptionMinimizeToTray.Checked := ReadBool('general', 'MinimizeToTray', False); cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); - edOptionExternalPath.FileName := ReadString('general', 'ExternalProgramPath', ''); + edOptionExternalPath.Text := ReadString('general', 'ExternalProgramPath', ''); edOptionExternalParams.Text := ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); miChapterListHideDownloaded.Checked := ReadBool('general', 'ChapterListHideDownloaded', False); cbAddAsStopped.Checked := ReadBool('general', 'AddAsStopped', False); @@ -4578,7 +4588,7 @@ procedure TMainForm.SaveOptions; WriteString('languages', 'Selected', AvailableLanguages.Names[cbLanguages.ItemIndex]); WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); - WriteString('general', 'ExternalProgramPath', edOptionExternalPath.FileName); + WriteString('general', 'ExternalProgramPath', edOptionExternalPath.Text); WriteString('general', 'ExternalProgramParams', edOptionExternalParams.Text); WriteBool('general', 'ChapterListHideDownloaded', miChapterListHideDownloaded.Checked); WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); @@ -4964,6 +4974,42 @@ procedure TMainForm.edMangaListSearchKeyDown(Sender: TObject; var Key: Word; edMangaListSearch.Tag := 0; end; +procedure TMainForm.edOptionDefaultPathButtonClick(Sender: TObject); +begin + with TSelectDirectoryDialog.Create(nil) do + try + InitialDir := edOptionDefaultPath.Text; + if Execute then + edOptionDefaultPath.Text := CleanAndExpandDirectory(FileName); + finally + Free; + end; +end; + +procedure TMainForm.edOptionExternalPathButtonClick(Sender: TObject); +begin + with TOpenDialog.Create(nil) do + try + InitialDir := ExtractFileDir(edOptionExternalPath.Text); + if Execute then + edOptionExternalPath.Text := FileName; + finally + Free; + end; +end; + +procedure TMainForm.edSaveToButtonClick(Sender: TObject); +begin + with TSelectDirectoryDialog.Create(nil) do + try + InitialDir := edSaveTo.Text; + if Execute then + edSaveTo.Text := CleanAndExpandDirectory(FileName); + finally + Free; + end; +end; + procedure TMainForm.edURLButtonClick(Sender: TObject); var i: Integer; From 12882fd8c608c39f05b80f2726caa7e264277621 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 11:47:31 +0800 Subject: [PATCH 1412/2794] fixed compile with laz 1.6/fpc 3.0.0, lower version not tested --- baseunits/extras/MangaFoxWatermark.pas | 6 ++++-- .../includes/MangaREADER_POR/names_and_links.inc | 4 ++++ baseunits/includes/MangasPROJECT/names_and_links.inc | 4 ++++ baseunits/uBaseUnit.pas | 6 +++++- mangadownloader/forms/frmCustomColor.pas | 12 ++++++------ mangadownloader/forms/frmMain.pas | 2 +- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/baseunits/extras/MangaFoxWatermark.pas b/baseunits/extras/MangaFoxWatermark.pas index 9c71b47d8..b340c0915 100644 --- a/baseunits/extras/MangaFoxWatermark.pas +++ b/baseunits/extras/MangaFoxWatermark.pas @@ -324,7 +324,7 @@ procedure TWatermarkRemover.ClearTemplate; i: Integer; begin for i := Low(FTemplates) to High(FTemplates) do - FreeMemAndNil(FTemplates[i].Bits); + Freemem(FTemplates[i].Bits); SetLength(FTemplates, 0); FCleared := True; end; @@ -436,7 +436,7 @@ function TWatermarkRemover.RemoveWatermark(const FileName: String; Bit := TIMG.Bits; end; finally - FreeMemAndNil(TIMG.Bits); + Freemem(TIMG.Bits); end; end; if (BestValue >= MinPSNR) and (BestIndex <> -1) then @@ -460,9 +460,11 @@ function TWatermarkRemover.RemoveWatermark(const FileName: String; try Writer := Handler.WriterClass.Create; FileStream := TFileStreamUTF8.Create(NewFileName, fmCreate); + {$IF (FPC_FULLVERSION >= 30101)} if Writer is TFPWriterJPEG then TFPWriterJPEG(Writer).GrayScale := GrayScale else + {$ENDIF} if Writer is TFPWriterPNG then begin if GrayScale then diff --git a/baseunits/includes/MangaREADER_POR/names_and_links.inc b/baseunits/includes/MangaREADER_POR/names_and_links.inc index 373cfa4d9..cbd69c8ab 100644 --- a/baseunits/includes/MangaREADER_POR/names_and_links.inc +++ b/baseunits/includes/MangaREADER_POR/names_and_links.inc @@ -23,7 +23,11 @@ if Copy(s, 1, 3) = UTF8BOM then Delete(s, 1, 3); end; + {$IF (FPC_FULLVERSION >= 30101)} parser := TJSONParser.Create(s, [joUTF8]); + {$ELSE} + parser := TJSONParser.Create(s, True); + {$ENDIF} try Data := parser.Parse; try diff --git a/baseunits/includes/MangasPROJECT/names_and_links.inc b/baseunits/includes/MangasPROJECT/names_and_links.inc index 12d3d8ae9..768d8ca84 100644 --- a/baseunits/includes/MangasPROJECT/names_and_links.inc +++ b/baseunits/includes/MangasPROJECT/names_and_links.inc @@ -15,7 +15,11 @@ Exit; end; sstream := TStringStream.Create(Source.Text); + {$IF (FPC_FULLVERSION >= 30101)} parser := TJSONParser.Create(sstream, [joUTF8]); + {$ELSE} + parser := TJSONParser.Create(sstream, True); + {$ENDIF} try Data := Parser.Parse; if Data <> nil then diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 57b0d171b..78cd0b6e0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1399,7 +1399,11 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); i: Integer; begin OutArray.BeginUpdate; - P := TJSONParser.Create(Trim(S), jsonscanner.DefaultOptions); + {$IF (FPC_FULLVERSION >= 30101)} + P := TJSONParser.Create(Trim(S), [joUTF8]); + {$ELSE} + P := TJSONParser.Create(Trim(S), True); + {$ENDIF} try D := P.Parse; try diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 62247103b..9c6477da7 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, Forms, Graphics, Dialogs, ColorBox, ComCtrls, + Classes, SysUtils, Types, Forms, Graphics, Dialogs, ColorBox, ComCtrls, VirtualTrees, FMDOptions, IniFiles; type @@ -432,7 +432,7 @@ procedure TVTApplyList.VTOnPaintBackground(Sender: TBaseVirtualTree; begin AColumnRect := R; AColumnRect.Left := Header.Columns[i].Left; - AColumnRect.Width := Header.Columns[i].Width - 1; + AColumnRect.Right := AColumnRect.Left + (Header.Columns[i].Width - 1); if toShowVertGridLines in TreeOptions.PaintOptions then begin TargetCanvas.Pen.Color := Colors.GridLineColor; @@ -462,7 +462,7 @@ procedure TVTApplyList.VTOnPaintBackground(Sender: TBaseVirtualTree; begin AColumnRect := R; AColumnRect.Left := Header.Columns[i].Left; - AColumnRect.Width := Header.Columns[i].Width - 1; + AColumnRect.Right := AColumnRect.Left + (Header.Columns[i].Width - 1); TargetCanvas.FillRect(AColumnRect); if toShowVertGridLines in TreeOptions.PaintOptions then TargetCanvas.Line(AColumnRect.Right, AColumnRect.Top, AColumnRect.Right, AColumnRect.Bottom); @@ -686,9 +686,9 @@ procedure TCustomColorForm.DrawBoxColorText(const TargetCanvas: TCanvas; const B begin // box color rect ABoxRect := CellRect; - ABoxRect.Inflate(-2, -2); + InflateRect(ABoxRect, -2, -2); ABoxRect.Left := CellRect.Left; - ABoxRect.Width := ABoxRect.Height; + ABoxRect.Right := ABoxRect.Left + (ABoxRect.Bottom - ABoxRect.Top); // text rect ATextRect := CellRect; ATextRect.Left := ABoxRect.Right + 4; @@ -700,7 +700,7 @@ procedure TCustomColorForm.DrawBoxColorText(const TargetCanvas: TCanvas; const B // extra border Brush.Style := bsClear; Pen.Color := clWhite; - ABoxRect.Inflate(-1, -1); + InflateRect(ABoxRect, -1, -1); Rectangle(ABoxRect); // text TextRect(ATextRect, ATextRect.Left, 0, CellText, TextStyleLeftCenter); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 22ee38edc..3386d6cbf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -18,7 +18,7 @@ interface {$endif} Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, - types, strutils, LCLIntf, DefaultTranslator, EditBtn, MultiLog, FileChannel, FileUtil, + types, LCLIntf, DefaultTranslator, EditBtn, MultiLog, FileChannel, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, From 8da7ab2344758cc04f4b021ec72f71db18864fed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 14:31:01 +0800 Subject: [PATCH 1413/2794] added spliturl, changed modify url methods to use it instead regex --- baseunits/uBaseUnit.pas | 187 +++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 96 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 78cd0b6e0..c162578e9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -681,10 +681,11 @@ function FillURLProtocol(const AProtocol, AURL: String): String; // Fill in website host if it's not present function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; function FillMangaSiteHost(const Website, URL: String): String; overload; -function FillHost(const Host, URL: String): String; -function MaybeFillHost(const Host, URL: String): String; // modify url +procedure SplitURL(const URL: String; out Host, Path: String); +function FillHost(const Host, URL: String): String; +function MaybeFillHost(const Host, URL: String): String; function GetHostURL(URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(const URLs: TStringList); @@ -1266,129 +1267,123 @@ function FillMangaSiteHost(const Website, URL: String): String; Result := FillMangaSiteHost(GetMangaSiteID(Website), URL); end; -function FillHost(const Host, URL: String): String; +function poschar(const c:char;const s:string;const offset:cardinal=1):integer; +var + i:integer; +begin + for i:=offset to length(s) do + if s[i]=c then Exit(i); + Result:=0; +end; + +procedure SplitURL(const URL: String; out Host, Path: String); var - tu: String; + p: Integer; begin - Result := CleanURL(URL); - if Host = '' then Exit; - if Pos(Host, URL) = 1 then Exit; - if Pos('://', URL) = 0 then + Host:=''; + Path:=''; + if URL='' then Exit; + p:=poschar('.',URL); + if (p<>0) and (p<Length(URL)) then begin - Result := RemoveURLDelim(Host) + AppendURLDelimLeft(Result); - Exit; - end; - with TRegExpr.Create do - try - Expression := REGEX_HOST; - tu := Replace(Result, '$4', True); - if tu <> '' then - Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); - finally - Free; + p:=poschar('/',URL,p); + if p<>0 then Host:=Copy(URL,1,p-1) + else + begin + Host:=URL; + Exit; end; + end; + if Host<>'' then + begin + while (Length(Host)>0) and (Host[1] in [':','/']) do + Delete(Host,1,1); + if Pos('://',Host)=0 then + Host:='http://'+Host; + end; + if p<>0 then + Path:=Copy(URL,p,Length(URL)) + else + Path:=URL; + if Path<>'' then + begin + while Pos('//',Path)<>0 do Path:=StringReplace(Path,'//','/',[rfReplaceAll]); + if Path='/' then Path:='' + else if Path[1]<>'/' then Path:='/'+Path; + end; +end; + +function FillHost(const Host, URL: String): String; +var + H,P: String; +begin + SplitURL(URL,H,P); + Result:=RemoveURLDelim(Host)+P; end; function MaybeFillHost(const Host, URL: String): String; var - tu: String; + H,P: String; begin - Result := CleanURL(URL); - if Host = '' then Exit; - if URL = '' then Exit; - if Pos(Host, URL) = 1 then Exit; - if Pos('://', URL) = 0 then - begin - Result := RemoveURLDelim(Host) + AppendURLDelimLeft(Result); - Exit; - end; - with TRegExpr.Create do - try - Expression := REGEX_HOST; - if Replace(Result, '$2', True) = '' then - begin - tu := Replace(Result, '$4', True); - if tu <> '' then - Result := RemoveURLDelim(Host) + AppendURLDelimLeft(tu); - end; - finally - Free; - end; + SplitURL(URL,H,P); + Result:=Host+P; + if H='' then Result:=RemoveURLDelim(Host)+P + else Result:=URL; end; function GetHostURL(URL: String): String; +var + H,P: String; begin - Result := URL; - if URL = '' then Exit; - Result := ReplaceRegExpr(REGEX_HOST, Result, '$1$2', True); + SplitURL(URL,H,P); + Result:=H; end; function RemoveHostFromURL(URL: String): String; +var + H,P: String; begin - Result := ReplaceRegExpr(REGEX_HOST, URL, '$4', True); - if Result = '' then - Result := URL; - if (Result <> '') and (Result[1] <> '/') then - Result := '/' + Result; + SplitURL(URL,H,P); + Result:=P; end; procedure RemoveHostFromURLs(const URLs: TStringList); var i: Integer; - s: String; + H,P: String; begin - if URLs = nil then Exit; - if URLs.Count > 0 then - with TRegExpr.Create do - try - Expression := REGEX_HOST; - for i := 0 to URLs.Count - 1 do - begin - URLs[i] := Trim(URLs[i]); - s := Replace(URLs[i], '$4', True); - if s = '' then - s := URLs[i]; - if (s <> '') and (s[1] <> '/') then - s := '/' + s; - URLs[i] := s; - end; - finally - Free; - end; + if URLs=nil then Exit; + if URLs.Count=0 then Exit; + for i:=0 to URLs.Count-1 do + begin + SplitURL(URLs[i],H,P); + URLs[i]:=P; + end; end; procedure RemoveHostFromURLsPair(const URLs, Names: TStringList); var i: Integer; - s: String; + H,P: String; begin - if (URLs = nil) or (Names = nil) then Exit; - if (URLs.Count <> Names.Count) then Exit; - if URLs.Count > 0 then - with TRegExpr.Create do - try - Expression := REGEX_HOST; - i := 0; - while i < URLs.Count do - begin - URLs[i] := Trim(URLs[i]); - s := Replace(URLs[i], '$4', True); - if s = '' then - s := URLs[i]; - if (s <> '') and (s[1] <> '/') then - s := '/' + s; - URLs[i] := s; - if (URLs[i] = '') or (URLs[i] = '/') then - begin - URLs.Delete(i); - Names.Delete(i); - end - else - Inc(i); - end; - finally - Free; - end; + if (URLs= nil) or (Names=nil) then Exit; + if (URLs.Count<>Names.Count) then Exit; + if URLs.Count=0 then Exit; + i:=0; + while i<URLs.Count do + begin + SplitURL(URLs[i],H,P); + if P<>'' then + begin + URLs[i]:=P; + Inc(i); + end + else + begin + URLs.Delete(i); + Names.Delete(i); + end; + end; end; procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); From c4d44cd209f8a68be9ec53dc214ac548fa5240b4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 14:40:14 +0800 Subject: [PATCH 1414/2794] baseunit, added encodecriticalurlelements --- baseunits/uBaseUnit.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c162578e9..5b0099f02 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -690,6 +690,7 @@ function GetHostURL(URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(const URLs: TStringList); procedure RemoveHostFromURLsPair(const URLs, Names: TStringList); +function EncodeCriticalURLElements(const URL: String): String; //JSON procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); @@ -1386,6 +1387,14 @@ procedure RemoveHostFromURLsPair(const URLs, Names: TStringList); end; end; +function EncodeCriticalURLElements(const URL: String): String; +var + H,P: String; +begin + SplitURL(URL,H,P); + Result:=H+EncodeTriplet(P,'%',URLSpecialChar+URLFullSpecialChar-['/']); +end; + procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); var P: TJSONParser; From a6de23e182d09d37d60db33b1f86eef5a63a3e3a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 14:40:59 +0800 Subject: [PATCH 1415/2794] mangastream. fixed encode chapters uri fixed #351 --- baseunits/modules/MangaStream.pas | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index bcceb17a7..5ba67b6a0 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -86,12 +86,10 @@ function GetInfo(const MangaInfo: TMangaInformation; s := v.toNode.getAttribute('href'); if (Length(s) > 2) and (RightStr(s, 2) = '/1') then SetLength(s, Length(s) - 2); - chapterLinks.Add(s); + chapterLinks.Add(EncodeCriticalURLElements(s)); chapterName.Add(v.toString); end; - //invert chapters - if chapterLinks.Count > 0 then - InvertStrings([chapterLinks, chapterName]); + InvertStrings([chapterLinks, chapterName]); end; finally Parser.Free; From ce331e35c6b0e48227ed586d15762279f6007cd5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 16:45:34 +0800 Subject: [PATCH 1416/2794] moved spliturl to httpsendthread, added . as invalid leading char, its also used by updater without baseunit --- baseunits/httpsendthread.pas | 75 +++++++++++++++++++++++++++--------- baseunits/uBaseUnit.pas | 47 ---------------------- 2 files changed, 56 insertions(+), 66 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index dce73b42f..7fffe6c47 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - GZIPUtils, RegExpr; + GZIPUtils; type @@ -66,6 +66,7 @@ procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); function MaybeEncodeURL(const AValue: String): String; +procedure SplitURL(const URL: String; out Host, Path: String); const UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; @@ -94,6 +95,52 @@ implementation ALLHTTPSendThread: TFPList; CS_ALLHTTPSendThread: TRTLCriticalSection; +function poschar(const c:char;const s:string;const offset:cardinal=1):integer; +var + i:integer; +begin + for i:=offset to length(s) do + if s[i]=c then Exit(i); + Result:=0; +end; + +procedure SplitURL(const URL: String; out Host, Path: String); +var + p: Integer; +begin + Host:=''; + Path:=''; + if URL='' then Exit; + p:=poschar('.',URL); + if (p<>0) and (p<Length(URL)) then + begin + p:=poschar('/',URL,p); + if p<>0 then Host:=Copy(URL,1,p-1) + else + begin + Host:=URL; + Exit; + end; + end; + if Host<>'' then + begin + while (Length(Host)<>0) and (Host[1] in ['.',':','/']) do + Delete(Host,1,1); + if Pos('://',Host)=0 then + Host:='http://'+Host; + end; + if p<>0 then + Path:=Copy(URL,p,Length(URL)) + else + Path:=URL; + if Path<>'' then + begin + while Pos('//',Path)<>0 do Path:=StringReplace(Path,'//','/',[rfReplaceAll]); + if Path='/' then Path:='' + else if Path[1]<>'/' then Path:='/'+Path; + end; +end; + function KeyVal(const AKey, AValue: String): TKeyValuePair; begin Result[0] := AKey; @@ -275,7 +322,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: var counter: Integer = 0; - rurl, s: String; + rurl, s, h, p: String; HTTPHeader: TStringList; mstream: TMemoryStream; begin @@ -300,23 +347,13 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: if CheckTerminate then Exit; HTTPHeader.Values['Referer'] := ' ' + rurl; s := Trim(Headers.Values['Location']); - if s <> '' then begin - with TRegExpr.Create do - try - Expression := '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - if Replace(s, '$1', True) = '' then - begin - while s[1] = '.' do - Delete(s, 1, 1); - if (s <> '') and (s[1] <> '/') then - s := '/' + s; - rurl := Replace(rurl, '$1$2$3', True) + s; - end - else - rurl := s; - finally - Free; - end; + if s<>'' then + begin + SplitURL(s,h,p); + s:=p; + if h='' then + SplitURL(rurl,h,p); + rurl:=h+s; end; Clear; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5b0099f02..c6aa8e02d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -683,7 +683,6 @@ function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overlo function FillMangaSiteHost(const Website, URL: String): String; overload; // modify url -procedure SplitURL(const URL: String; out Host, Path: String); function FillHost(const Host, URL: String): String; function MaybeFillHost(const Host, URL: String): String; function GetHostURL(URL: String): String; @@ -1268,52 +1267,6 @@ function FillMangaSiteHost(const Website, URL: String): String; Result := FillMangaSiteHost(GetMangaSiteID(Website), URL); end; -function poschar(const c:char;const s:string;const offset:cardinal=1):integer; -var - i:integer; -begin - for i:=offset to length(s) do - if s[i]=c then Exit(i); - Result:=0; -end; - -procedure SplitURL(const URL: String; out Host, Path: String); -var - p: Integer; -begin - Host:=''; - Path:=''; - if URL='' then Exit; - p:=poschar('.',URL); - if (p<>0) and (p<Length(URL)) then - begin - p:=poschar('/',URL,p); - if p<>0 then Host:=Copy(URL,1,p-1) - else - begin - Host:=URL; - Exit; - end; - end; - if Host<>'' then - begin - while (Length(Host)>0) and (Host[1] in [':','/']) do - Delete(Host,1,1); - if Pos('://',Host)=0 then - Host:='http://'+Host; - end; - if p<>0 then - Path:=Copy(URL,p,Length(URL)) - else - Path:=URL; - if Path<>'' then - begin - while Pos('//',Path)<>0 do Path:=StringReplace(Path,'//','/',[rfReplaceAll]); - if Path='/' then Path:='' - else if Path[1]<>'/' then Path:='/'+Path; - end; -end; - function FillHost(const Host, URL: String): String; var H,P: String; From 9a55ee69fed09e3643b44b1dc4d95640035cdf82 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 17:58:19 +0800 Subject: [PATCH 1417/2794] frmmain, replace some button with tbuttonedit, added button split download and change the layout --- mangadownloader/forms/frmMain.lfm | 324 +++++++++++++++++------------- mangadownloader/forms/frmMain.lrj | 3 +- mangadownloader/forms/frmMain.pas | 46 ++--- 3 files changed, 203 insertions(+), 170 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f19b3c0fb..5828650fb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -54,7 +54,6 @@ object MainForm: TMainForm ClientHeight = 492 ClientWidth = 558 object vtDownload: TVirtualStringTree - AnchorSideTop.Control = edDownloadsSearch AnchorSideTop.Side = asrBottom Left = 4 Height = 456 @@ -135,24 +134,23 @@ object MainForm: TMainForm OnKeyUp = vtDownloadKeyUp end object pnDownloadToolbar: TPanel - AnchorSideLeft.Control = btDownloadsSearchClear + AnchorSideLeft.Control = edDownloadsSearch AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edDownloadsSearch AnchorSideTop.Side = asrCenter - Left = 185 + Left = 158 Height = 24 Top = 3 - Width = 368 + Width = 395 Anchors = [akTop, akLeft, akRight] BevelOuter = bvNone ClientHeight = 24 - ClientWidth = 368 + ClientWidth = 395 TabOrder = 1 object TransferRateGraph: TChart Left = 321 Height = 24 Top = 0 - Width = 47 + Width = 74 AllowZoom = False AxisList = < item @@ -267,26 +265,12 @@ object MainForm: TMainForm end end end - object edDownloadsSearch: TEdit + object edDownloadsSearch: TEditButton Left = 4 Height = 23 Top = 4 Width = 150 - OnChange = edDownloadsSearchChange - TabOrder = 2 - TextHint = 'Search downloads...' - end - object btDownloadsSearchClear: TSpeedButton - AnchorSideLeft.Control = edDownloadsSearch - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edDownloadsSearch - AnchorSideBottom.Control = edDownloadsSearch - AnchorSideBottom.Side = asrBottom - Left = 158 - Height = 23 - Top = 4 - Width = 23 - Anchors = [akTop, akLeft, akBottom] + ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF @@ -323,7 +307,13 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btDownloadsSearchClearClick + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edDownloadsSearchButtonClick + OnChange = edDownloadsSearchChange + PasswordChar = #0 + TabOrder = 2 + TextHint = 'Search downloads...' end end object tsInformation: TTabSheet @@ -335,8 +325,8 @@ object MainForm: TMainForm Height = 492 Top = 0 Width = 558 - HorzScrollBar.Page = 327 - VertScrollBar.Page = 482 + HorzScrollBar.Page = 316 + VertScrollBar.Page = 417 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 @@ -497,12 +487,14 @@ object MainForm: TMainForm ClientWidth = 550 TabOrder = 2 object clbChapterList: TVirtualStringTree + AnchorSideLeft.Control = edFilterMangaInfoChapters AnchorSideTop.Control = edFilterMangaInfoChapters - AnchorSideBottom.Control = lbSaveTo + AnchorSideRight.Control = btChecks + AnchorSideBottom.Control = btDownload Left = 0 - Height = 136 + Height = 125 Top = 0 - Width = 516 + Width = 520 Anchors = [akTop, akLeft, akRight, akBottom] Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight @@ -528,15 +520,15 @@ object MainForm: TMainForm OnInitNode = clbChapterListInitNode end object btDownload: TBitBtn - AnchorSideTop.Control = btReadOnline - AnchorSideRight.Control = btReadOnline + AnchorSideLeft.Control = btAddToFavorites + AnchorSideTop.Control = btDownloadSplit + AnchorSideRight.Control = btDownloadSplit AnchorSideBottom.Control = btReadOnline - AnchorSideBottom.Side = asrBottom - Left = 338 + Left = 420 Height = 26 - Top = 159 + Top = 129 Width = 100 - Anchors = [akTop, akRight, akBottom] + Anchors = [akLeft, akRight, akBottom] AutoSize = True Caption = 'Download' Glyph.Data = { @@ -580,14 +572,15 @@ object MainForm: TMainForm end object cbAddAsStopped: TCheckBox AnchorSideLeft.Control = edSaveTo - AnchorSideTop.Control = edSaveTo - AnchorSideTop.Side = asrBottom + AnchorSideTop.Control = btAddToFavorites AnchorSideRight.Control = edSaveTo AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btAddToFavorites + AnchorSideBottom.Side = asrBottom Left = 0 Height = 19 - Top = 186 - Width = 334 + Top = 189 + Width = 416 Anchors = [akTop, akLeft, akRight] Caption = 'Add to download list as stopped task' OnChange = cbAddAsStoppedChange @@ -595,14 +588,16 @@ object MainForm: TMainForm TabOrder = 3 end object btReadOnline: TBitBtn - AnchorSideTop.Control = edSaveTo + AnchorSideLeft.Control = btAddToFavorites + AnchorSideTop.Control = btDownload AnchorSideRight.Control = btChecks AnchorSideRight.Side = asrBottom - Left = 442 + AnchorSideBottom.Control = btAddToFavorites + Left = 420 Height = 26 Top = 159 - Width = 108 - Anchors = [akRight, akBottom] + Width = 130 + Anchors = [akLeft, akRight, akBottom] AutoSize = True Caption = 'Read online' Glyph.Data = { @@ -648,10 +643,11 @@ object MainForm: TMainForm AnchorSideLeft.Control = clbChapterList AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = clbChapterList - Left = 520 - Height = 30 + Left = 524 + Height = 26 Top = 0 - Width = 30 + Width = 26 + Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000090000 @@ -694,13 +690,13 @@ object MainForm: TMainForm AnchorSideLeft.Control = btDownload AnchorSideTop.Control = btReadOnline AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = btReadOnline + AnchorSideRight.Control = btChecks AnchorSideRight.Side = asrBottom - Left = 338 + Left = 420 Height = 26 Top = 189 - Width = 212 - Anchors = [akTop, akLeft, akRight, akBottom] + Width = 130 + Anchors = [akRight, akBottom] AutoSize = True Caption = 'Add to favorites' Glyph.Data = { @@ -744,8 +740,7 @@ object MainForm: TMainForm end object lbSaveTo: TLabel AnchorSideLeft.Control = clbChapterList - AnchorSideTop.Control = clbChapterList - AnchorSideTop.Side = asrBottom + AnchorSideTop.Control = btDownload AnchorSideBottom.Control = edSaveTo Left = 0 Height = 15 @@ -810,11 +805,12 @@ object MainForm: TMainForm object edSaveTo: TEditButton AnchorSideLeft.Control = lbSaveTo AnchorSideTop.Control = btReadOnline - AnchorSideRight.Control = btDownload + AnchorSideRight.Control = btReadOnline + AnchorSideBottom.Control = cbAddAsStopped Left = 0 Height = 23 Top = 159 - Width = 334 + Width = 416 Anchors = [akTop, akLeft, akRight] ButtonWidth = 23 Glyph.Data = { @@ -861,6 +857,56 @@ object MainForm: TMainForm TabOrder = 6 TextHint = 'Save to' end + object btDownloadSplit: TSpeedButton + AnchorSideLeft.Control = btDownload + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btDownload + AnchorSideRight.Control = btChecks + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btReadOnline + Left = 524 + Height = 26 + Hint = 'Split download' + Top = 129 + Width = 26 + Anchors = [akTop, akRight, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 000800000010000000170000001A00000016000000120000000E0000000E0000 + 0012000000160000001A000000180000001000000008FFFFFF00FFFFFF000000 + 00100000001F64330270984D02CC64330270000000230000001B0000001C0000 + 002364330270984D02CC643302710000002000000010FFFFFF00FFFFFF002815 + 0200753D045C9C5105CCFFB811FF9C5105CC753D045C2815020028150200753D + 045C9C5105CCFFB508FF9C5105CC753D045C28150200FFFFFF00FFFFFF00A257 + 0A5CA15609CCFFB917FFFFB201FFFFB814FFA15609CCA1560948A1560948A156 + 09CCFFB60DFFFFB201FFFFB50BFFA15609CCA2570A5CFFFFFF00FFFFFF00BF74 + 1599BF7415CCBF7415CCFBC23EFFBF7415CCBF7415CCBF741566BF741566BF74 + 15CCBF7415CCFABA27FFBF7415CCBF7415CCBF741599FFFFFF00FFFFFF00BF74 + 1500BB701500AD6212C9F2BC49FDB36A18D0B2671320BF741500BF741500B267 + 1320B36916D0F0B435FDAD6212C9BB701500BF741500FFFFFF00FFFFFF00BA6F + 1700B4691700B46917B4E3AA46F4C6842DDBB56A185EB56A1800B56A1800B56A + 185EC58128DBE1A53BF6B46917B9B4691700BA6F1700FFFFFF00FFFFFF00BA6F + 1C00BA6F1C00BA6F1C86D59A45E6DAA24CEFBA6F1CB8BE731F0ABE731F0ABA6F + 1CB8D89D45EFD3963FE8BA6F1C8CBA6F1C00BA6F1C00FFFFFF00FFFFFF00C075 + 2000C0752000C176213CC7802CD2EDC577FECD8C39D9C1772271C1772270CC89 + 37D9E7BB6DFFC8822ED4C0762148BF752000BF752000FFFFFF00FFFFFF00C77C + 2500C77C2500C77C2502C97E27A1DCA452E6E9BE70F6C97E27C6C97E27C6E6B8 + 6AF6DAA050E9C97E27ACC77C2505C77C2500C77C2500FFFFFF00FFFFFF00CC81 + 2900CC812900CC812900CF842C2CD18831CDF2C679FBDC9D49DBDB9B47DCE6B8 + 6BFCD28932CFCE832C36CD822B00CD822B00CD822B00FFFFFF00FFFFFF00D489 + 3000D4893000D4893000D4893000D68B3190E9B461E6EEB86AF4EEB869F4EAB3 + 61E7D68B3197D3882F00D2872F00D2872F00D2872F00FFFFFF00FFFFFF00DA8F + 3400DA8F3400DA8F3400DA8F3400DB903547E4A44DD8F6C679FEF5C679FEE4A4 + 4DD8DB903549DA8F3400DA8F3400DA8F3400DA8F3400FFFFFF00FFFFFF00E196 + 3900E1963900E1963900E1963900E1963917E39B3FCFFCD488FFFCD387FFE39C + 40CFE1963918E1963900E1963900E1963900E1963900FFFFFF00FFFFFF00E69B + 3D00E69B3D00E69B3D00E69B3D00E69B3D04E69B3DCCFFE094FFFFDF93FFE69B + 3DCCE69B3D04E69B3D00E69B3D00E69B3D00E69B3D00FFFFFF00FFFFFF003A27 + 1000AE752E00E79C3D00E79C3D00E79C3D00E99E4099E99E40CCE99E40CCE99E + 4099E79C3D00E79C3D00E79C3D00AE752E003A271000FFFFFF00 + } + end end end end @@ -1863,13 +1909,12 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 object vtFavorites: TVirtualStringTree - AnchorSideTop.Control = edFavoritesSearch AnchorSideTop.Side = asrBottom Left = 4 - Height = 366 + Height = 374 Top = 31 Width = 549 Anchors = [akTop, akLeft, akRight, akBottom] @@ -1934,7 +1979,7 @@ object MainForm: TMainForm object btFavoritesImport: TBitBtn Left = 33 Height = 24 - Top = 450 + Top = 458 Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Import list' @@ -1981,7 +2026,7 @@ object MainForm: TMainForm object btCancelFavoritesCheck: TSpeedButton Left = 490 Height = 40 - Top = 404 + Top = 412 Width = 34 Anchors = [akRight, akBottom] Glyph.Data = { @@ -2026,7 +2071,7 @@ object MainForm: TMainForm object btFavoritesCheckNewChapter: TBitBtn Left = 33 Height = 40 - Top = 404 + Top = 412 Width = 491 Anchors = [akLeft, akRight, akBottom] Caption = 'Check for new chapter' @@ -2069,26 +2114,12 @@ object MainForm: TMainForm OnClick = btFavoritesCheckNewChapterClick TabOrder = 1 end - object edFavoritesSearch: TEdit + object edFavoritesSearch: TEditButton Left = 4 Height = 23 Top = 4 Width = 150 - OnChange = edFavoritesSearchChange - TabOrder = 3 - TextHint = 'Search favorites...' - end - object btFavoritesSearchClear: TSpeedButton - AnchorSideLeft.Control = edFavoritesSearch - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edFavoritesSearch - AnchorSideBottom.Control = edFavoritesSearch - AnchorSideBottom.Side = asrBottom - Left = 158 - Height = 23 - Top = 4 - Width = 23 - Anchors = [akTop, akLeft, akBottom] + ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF @@ -2125,7 +2156,13 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btFavoritesSearchClearClick + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edFavoritesSearchButtonClick + OnChange = edFavoritesSearchChange + PasswordChar = #0 + TabOrder = 3 + TextHint = 'Search favorites...' end end object tsOption: TTabSheet @@ -2499,11 +2536,11 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object sbDownloadConnections: TScrollBox Left = 0 - Height = 379 + Height = 387 Top = 0 Width = 531 HorzScrollBar.Page = 455 @@ -2514,7 +2551,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 TabOrder = 0 object cbOptionUseProxy: TCheckBox @@ -3245,7 +3282,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 4 @@ -3372,7 +3409,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object gbDialogs: TGroupBox Left = 4 @@ -3427,11 +3464,11 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 379 + ClientHeight = 387 ClientWidth = 531 object pcWebsiteOptions: TPageControl Left = 4 - Height = 363 + Height = 371 Top = 8 Width = 523 ActivePage = tsWebsiteSelection @@ -3440,11 +3477,11 @@ object MainForm: TMainForm TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' - ClientHeight = 335 + ClientHeight = 343 ClientWidth = 515 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 0 - Height = 300 + Height = 308 Top = 35 Width = 515 Align = alClient @@ -3487,23 +3524,56 @@ object MainForm: TMainForm ClientHeight = 23 ClientWidth = 509 TabOrder = 1 - object edWebsitesSearch: TEdit - Left = 0 + object pnlWebsitesToolRight: TPanel + Left = 339 Height = 23 Top = 0 - Width = 184 - Align = alLeft - BorderSpacing.Right = 2 - OnChange = edWebsitesSearchChange + Width = 170 + Align = alRight + AutoSize = True + BevelOuter = bvNone + ClientHeight = 23 + ClientWidth = 170 TabOrder = 0 - TextHint = 'Search website...' + object ToolBarWebsites: TToolBar + Left = 0 + Height = 22 + Top = 0 + Width = 170 + AutoSize = True + EdgeBorders = [] + Images = IconList + List = True + ParentFont = False + ShowCaptions = True + TabOrder = 0 + Transparent = True + object tbWebsitesExpandAll: TToolButton + Left = 1 + Top = 0 + AutoSize = True + Caption = 'Expand All' + ImageIndex = 17 + OnClick = tbWebsitesExpandAllClick + end + object tbWebsitesCollapseAll: TToolButton + Left = 82 + Top = 0 + AutoSize = True + Caption = 'Collapse All' + ImageIndex = 18 + OnClick = tbWebsitesCollapseAllClick + end + end end - object btWebsitesSearchClear: TSpeedButton - Left = 188 + object edWebsitesSearch: TEditButton + Left = 0 Height = 23 Top = 0 - Width = 22 + Width = 184 Align = alLeft + BorderSpacing.Right = 2 + ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF @@ -3540,49 +3610,13 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btWebsitesSearchClearClick - end - object pnlWebsitesToolRight: TPanel - Left = 339 - Height = 23 - Top = 0 - Width = 170 - Align = alRight - AutoSize = True - BevelOuter = bvNone - ClientHeight = 23 - ClientWidth = 170 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edWebsitesSearchButtonClick + OnChange = edWebsitesSearchChange + PasswordChar = #0 TabOrder = 1 - object ToolBarWebsites: TToolBar - Left = 0 - Height = 22 - Top = 0 - Width = 170 - AutoSize = True - EdgeBorders = [] - Images = IconList - List = True - ParentFont = False - ShowCaptions = True - TabOrder = 0 - Transparent = True - object tbWebsitesExpandAll: TToolButton - Left = 1 - Top = 0 - AutoSize = True - Caption = 'Expand All' - ImageIndex = 17 - OnClick = tbWebsitesExpandAllClick - end - object tbWebsitesCollapseAll: TToolButton - Left = 82 - Top = 0 - AutoSize = True - Caption = 'Collapse All' - ImageIndex = 18 - OnClick = tbWebsitesCollapseAllClick - end - end + TextHint = 'Search website...' end end end @@ -3877,12 +3911,12 @@ object MainForm: TMainForm Caption = 'About' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 - ClientHeight = 484 + ClientHeight = 492 ClientWidth = 558 object btCheckLatestVersion: TBitBtn Left = 25 Height = 40 - Top = 433 + Top = 441 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Check for latest version' @@ -3928,7 +3962,7 @@ object MainForm: TMainForm object btAbortCheckLatestVersion: TSpeedButton Left = 193 Height = 40 - Top = 433 + Top = 441 Width = 40 Anchors = [akLeft, akBottom] Glyph.Data = { @@ -3973,7 +4007,7 @@ object MainForm: TMainForm object btVisitMyBlog: TBitBtn Left = 249 Height = 40 - Top = 433 + Top = 441 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Visit my blog' @@ -4018,7 +4052,7 @@ object MainForm: TMainForm end object pcAbout: TPageControl Left = 4 - Height = 414 + Height = 422 Top = 8 Width = 550 ActivePage = tsAboutText @@ -4028,11 +4062,11 @@ object MainForm: TMainForm TabOrder = 2 object tsAboutText: TTabSheet Caption = 'About FMD' - ClientHeight = 386 + ClientHeight = 394 ClientWidth = 542 object rmAbout: TRichMemo Left = 2 - Height = 380 + Height = 388 Top = 4 Width = 536 Align = alClient diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 57cf15ac3..24adb47bc 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -20,6 +20,7 @@ {"hash":147292346,"name":"tmainform.lbsaveto.caption","sourcebytes":[83,97,118,101,32,116,111,58],"value":"Save to:"}, {"hash":80755394,"name":"tmainform.edfiltermangainfochapters.texthint","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, {"hash":160200703,"name":"tmainform.edsaveto.texthint","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, +{"hash":32855652,"name":"tmainform.btdownloadsplit.hint","sourcebytes":[83,112,108,105,116,32,100,111,119,110,108,111,97,100],"value":"Split download"}, {"hash":80755394,"name":"tmainform.tsfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, {"hash":236121459,"name":"tmainform.lbfiltercustomgenres.caption","sourcebytes":[67,117,115,116,111,109,32,71,101,110,114,101,115],"value":"Custom Genres"}, {"hash":58090881,"name":"tmainform.edcustomgenres.texthint","sourcebytes":[73,110,112,117,116,32,99,117,115,116,111,109,32,103,101,110,114,101,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,99,111,109,109,97],"value":"Input custom genres, separated by comma"}, @@ -213,9 +214,9 @@ {"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, {"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, {"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, -{"hash":32777246,"name":"tmainform.edwebsitessearch.texthint","sourcebytes":[83,101,97,114,99,104,32,119,101,98,115,105,116,101,46,46,46],"value":"Search website..."}, {"hash":138578252,"name":"tmainform.tbwebsitesexpandall.caption","sourcebytes":[69,120,112,97,110,100,32,65,108,108],"value":"Expand All"}, {"hash":53573292,"name":"tmainform.tbwebsitescollapseall.caption","sourcebytes":[67,111,108,108,97,112,115,101,32,65,108,108],"value":"Collapse All"}, +{"hash":32777246,"name":"tmainform.edwebsitessearch.texthint","sourcebytes":[83,101,97,114,99,104,32,119,101,98,115,105,116,101,46,46,46],"value":"Search website..."}, {"hash":108725763,"name":"tmainform.tswebsiteoptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, {"hash":197676484,"name":"tmainform.tswebsiteadvanced.caption","sourcebytes":[65,100,118,97,110,99,101,100],"value":"Advanced"}, {"hash":161923523,"name":"tmainform.tsaccounts.caption","sourcebytes":[65,99,99,111,117,110,116,115],"value":"Accounts"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3386d6cbf..287accc4d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -40,14 +40,12 @@ TMainForm = class(TForm) btChecks: TSpeedButton; btDonate: TImage; btFavoritesImport: TBitBtn; - btDownloadsSearchClear: TSpeedButton; btFilter: TBitBtn; btFilterReset: TBitBtn; btOptionApply: TBitBtn; btReadOnline: TBitBtn; btRemoveFilter: TSpeedButton; btMangaListSearchClear: TSpeedButton; - btWebsitesSearchClear: TSpeedButton; btUpdateList: TSpeedButton; cbOptionAutoCheckFavStartup: TCheckBox; cbOptionAutoCheckFavInterval: TCheckBox; @@ -67,9 +65,9 @@ TMainForm = class(TForm) cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; ckEnableLogging: TCheckBox; - edDownloadsSearch: TEdit; + edDownloadsSearch: TEditButton; + edFavoritesSearch: TEditButton; edFilterMangaInfoChapters: TEditButton; - edFavoritesSearch: TEdit; edLogFileName: TEditButton; edOptionChangeUnicodeCharacterStr: TEdit; edOptionDefaultPath: TEditButton; @@ -78,6 +76,7 @@ TMainForm = class(TForm) edOptionMangaCustomRename: TEdit; edSaveTo: TEditButton; edURL: TEditButton; + edWebsitesSearch: TEditButton; lbLogFileName: TLabel; lbOptionFilenameCustomRenameHint: TLabel; lbOptionFilenameCustomRename: TLabel; @@ -119,7 +118,7 @@ TMainForm = class(TForm) pmTray: TPopupMenu; sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; - btFavoritesSearchClear: TSpeedButton; + btDownloadSplit: TSpeedButton; tsCustomColor: TTabSheet; tsLog: TTabSheet; tmAnimateMangaInfo: TTimer; @@ -141,7 +140,6 @@ TMainForm = class(TForm) TransferRateGraph: TChart; ckDropTarget: TCheckBox; edOptionExternalParams: TEdit; - edWebsitesSearch: TEdit; gbDropTarget: TGroupBox; gbOptionExternal: TGroupBox; IconDL: TImageList; @@ -390,15 +388,12 @@ TMainForm = class(TForm) procedure btCheckLatestVersionClick(Sender: TObject); procedure btClearLogFileClick(Sender: TObject); procedure btDonateClick(Sender: TObject); - procedure btDownloadsSearchClearClick(Sender: TObject); - procedure btFavoritesSearchClearClick(Sender: TObject); procedure btFavoritesImportClick(Sender: TObject); procedure btOpenLogClick(Sender: TObject); procedure btReadOnlineClick(Sender: TObject); procedure btMangaListSearchClearClick(Sender: TObject); procedure btUpdateListClick(Sender: TObject); procedure btVisitMyBlogClick(Sender: TObject); - procedure btWebsitesSearchClearClick(Sender: TObject); procedure cbAddAsStoppedChange(Sender: TObject); procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); procedure cbOptionChangeUnicodeCharacterChange(Sender: TObject); @@ -414,7 +409,9 @@ TMainForm = class(TForm) var CellText: String); procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure edDownloadsSearchButtonClick(Sender: TObject); procedure edDownloadsSearchChange(Sender: TObject); + procedure edFavoritesSearchButtonClick(Sender: TObject); procedure edFavoritesSearchChange(Sender: TObject); procedure edFilterMangaInfoChaptersButtonClick(Sender: TObject); procedure edFilterMangaInfoChaptersChange(Sender: TObject); @@ -427,6 +424,7 @@ TMainForm = class(TForm) procedure edSaveToButtonClick(Sender: TObject); procedure edURLButtonClick(Sender: TObject); procedure edURLKeyPress(Sender: TObject; var Key: Char); + procedure edWebsitesSearchButtonClick(Sender: TObject); procedure edWebsitesSearchChange(Sender: TObject); procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); @@ -2170,11 +2168,6 @@ procedure TMainForm.btVisitMyBlogClick(Sender: TObject); OpenURL('http://akarink.wordpress.com/'); end; -procedure TMainForm.btWebsitesSearchClearClick(Sender: TObject); -begin - edWebsitesSearch.Clear; -end; - procedure TMainForm.cbAddAsStoppedChange(Sender: TObject); begin configfile.WriteBool('general', 'AddAsStopped', cbAddAsStopped.Checked); @@ -2244,16 +2237,6 @@ procedure TMainForm.btDonateClick(Sender: TObject); OpenURL('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=akarin.km@gmail.com&item_name=Donation+to+Free+Manga+Downloader'); end; -procedure TMainForm.btDownloadsSearchClearClick(Sender: TObject); -begin - edDownloadsSearch.Clear; -end; - -procedure TMainForm.btFavoritesSearchClearClick(Sender: TObject); -begin - edFavoritesSearch.Clear; -end; - procedure TMainForm.btFavoritesImportClick(Sender: TObject); begin with TImportFavorites.Create(Self) do try @@ -2334,6 +2317,11 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; +procedure TMainForm.edDownloadsSearchButtonClick(Sender: TObject); +begin + edDownloadsSearch.Clear; +end; + procedure TMainForm.edDownloadsSearchChange(Sender: TObject); var Node: PVirtualNode; @@ -2368,6 +2356,11 @@ procedure TMainForm.edDownloadsSearchChange(Sender: TObject); end; end; +procedure TMainForm.edFavoritesSearchButtonClick(Sender: TObject); +begin + edFavoritesSearch.Clear; +end; + procedure TMainForm.edFavoritesSearchChange(Sender: TObject); var Node: PVirtualNode; @@ -2429,6 +2422,11 @@ procedure TMainForm.edURLKeyPress(Sender: TObject; var Key: Char); edURLButtonClick(edURL); end; +procedure TMainForm.edWebsitesSearchButtonClick(Sender: TObject); +begin + edWebsitesSearch.Clear; +end; + procedure TMainForm.edWebsitesSearchChange(Sender: TObject); var s: String; From 3e4dbc4ce23711e5ef9ce4d0f8d28050edb1f3d6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 16 Aug 2016 18:09:37 +0800 Subject: [PATCH 1418/2794] force resave all form with i18n and added minor update --- mangadownloader/forms/frmAccountSet.lfm | 1 + mangadownloader/forms/frmAccountSet.lrj | 1 - mangadownloader/forms/frmDropTarget.lfm | 1 + mangadownloader/forms/frmImportFavorites.lfm | 1 + mangadownloader/forms/frmImportFavorites.lrj | 1 - mangadownloader/forms/frmLogger.lfm | 1 + mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmNewChapter.lfm | 1 + mangadownloader/forms/frmNewChapter.lrj | 1 - mangadownloader/forms/frmShutdownCounter.lfm | 3 ++- mangadownloader/forms/frmShutdownCounter.lrj | 4 +++ mangadownloader/forms/frmUpdateDialog.lfm | 1 + mangadownloader/forms/frmUpdateDialog.lrj | 1 - .../forms/frmWebsiteOptionAdvanced.lfm | 1 + mangadownloader/forms/frmWebsiteSelection.lfm | 1 + mangadownloader/languages/fmd.en.po | 26 ++++--------------- mangadownloader/languages/fmd.id_ID.po | 26 ++++--------------- mangadownloader/languages/fmd.po | 25 +++--------------- 18 files changed, 29 insertions(+), 68 deletions(-) create mode 100644 mangadownloader/forms/frmShutdownCounter.lrj diff --git a/mangadownloader/forms/frmAccountSet.lfm b/mangadownloader/forms/frmAccountSet.lfm index 28df60f66..37ca9af35 100644 --- a/mangadownloader/forms/frmAccountSet.lfm +++ b/mangadownloader/forms/frmAccountSet.lfm @@ -13,6 +13,7 @@ object AccountSetForm: TAccountSetForm ClientWidth = 269 Position = poMainFormCenter LCLVersion = '1.7' + Visible = False object cbWebsiteName: TComboBox Left = 8 Height = 23 diff --git a/mangadownloader/forms/frmAccountSet.lrj b/mangadownloader/forms/frmAccountSet.lrj index ee75e64e2..c327d63af 100644 --- a/mangadownloader/forms/frmAccountSet.lrj +++ b/mangadownloader/forms/frmAccountSet.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":127560724,"name":"taccountsetform.caption","sourcebytes":[65,99,99,111,117,110,116],"value":"Account"}, {"hash":230269173,"name":"taccountsetform.label1.caption","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, {"hash":164185077,"name":"taccountsetform.label2.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":145417188,"name":"taccountsetform.label3.caption","sourcebytes":[80,97,115,115,119,111,114,100],"value":"Password"}, diff --git a/mangadownloader/forms/frmDropTarget.lfm b/mangadownloader/forms/frmDropTarget.lfm index f5067a276..fa10ef4d9 100644 --- a/mangadownloader/forms/frmDropTarget.lfm +++ b/mangadownloader/forms/frmDropTarget.lfm @@ -19,6 +19,7 @@ object FormDropTarget: TFormDropTarget OnMouseUp = FormMouseUp OnShow = FormShow LCLVersion = '1.7' + Visible = False object shBorder: TShape Left = 0 Height = 156 diff --git a/mangadownloader/forms/frmImportFavorites.lfm b/mangadownloader/forms/frmImportFavorites.lfm index 8b73f01a5..1ce7653f0 100644 --- a/mangadownloader/forms/frmImportFavorites.lfm +++ b/mangadownloader/forms/frmImportFavorites.lfm @@ -13,6 +13,7 @@ object ImportFavorites: TImportFavorites ClientWidth = 426 Position = poDesktopCenter LCLVersion = '1.7' + Visible = False object lbSelectSoftware: TLabel Left = 8 Height = 15 diff --git a/mangadownloader/forms/frmImportFavorites.lrj b/mangadownloader/forms/frmImportFavorites.lrj index 34c413e06..91ddac3c2 100644 --- a/mangadownloader/forms/frmImportFavorites.lrj +++ b/mangadownloader/forms/frmImportFavorites.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":131016830,"name":"timportfavorites.caption","sourcebytes":[73,109,112,111,114,116,32,108,105,115,116,32,46,46,46],"value":"Import list ..."}, {"hash":230544090,"name":"timportfavorites.lbselectsoftware.caption","sourcebytes":[83,111,102,116,119,97,114,101,58],"value":"Software:"}, {"hash":148035954,"name":"timportfavorites.cbsoftware.text","sourcebytes":[68,111,109,100,111,109,115,111,102,116,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Domdomsoft Manga Downloader"}, {"hash":161483657,"name":"timportfavorites.edpath.texthint","sourcebytes":[80,97,116,104,32,116,111,32,116,104,101,32,115,111,102,116,119,97,114,101,32,40,101,46,103,46,32,67,58,92,77,97,110,103,97,68,111,119,110,108,111,97,100,101,114,41],"value":"Path to the software (e.g. C:\\MangaDownloader)"}, diff --git a/mangadownloader/forms/frmLogger.lfm b/mangadownloader/forms/frmLogger.lfm index b223688ee..0c1f6a96f 100644 --- a/mangadownloader/forms/frmLogger.lfm +++ b/mangadownloader/forms/frmLogger.lfm @@ -15,6 +15,7 @@ object FormLogger: TFormLogger OnCreate = FormCreate OnDestroy = FormDestroy Position = poMainFormCenter + LCLVersion = '1.7' Visible = False object tvLog: TLogTreeView Left = 6 diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 5828650fb..42133894c 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,6 +13,7 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmNewChapter.lfm b/mangadownloader/forms/frmNewChapter.lfm index 766ad58cf..0722ca2dd 100644 --- a/mangadownloader/forms/frmNewChapter.lfm +++ b/mangadownloader/forms/frmNewChapter.lfm @@ -15,6 +15,7 @@ object NewChapter: TNewChapter OnCreate = FormCreate Position = poDesktopCenter LCLVersion = '1.7' + Visible = False object lbNotification: TLabel Left = 8 Height = 1 diff --git a/mangadownloader/forms/frmNewChapter.lrj b/mangadownloader/forms/frmNewChapter.lrj index dbe400e95..745cd03e7 100644 --- a/mangadownloader/forms/frmNewChapter.lrj +++ b/mangadownloader/forms/frmNewChapter.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":252000638,"name":"tnewchapter.caption","sourcebytes":[78,101,119,32,67,104,97,112,116,101,114,32,78,111,116,105,102,105,99,97,116,105,111,110],"value":"New Chapter Notification"}, {"hash":115679172,"name":"tnewchapter.btdownload.caption","sourcebytes":[38,68,111,119,110,108,111,97,100],"value":"&Download"}, {"hash":184736549,"name":"tnewchapter.btqueue.caption","sourcebytes":[38,65,100,100,32,116,111,32,113,117,101,117,101],"value":"&Add to queue"}, {"hash":177752476,"name":"tnewchapter.btcancel.caption","sourcebytes":[38,67,97,110,99,101,108],"value":"&Cancel"} diff --git a/mangadownloader/forms/frmShutdownCounter.lfm b/mangadownloader/forms/frmShutdownCounter.lfm index 20bcdcd76..63ee7e3d1 100644 --- a/mangadownloader/forms/frmShutdownCounter.lfm +++ b/mangadownloader/forms/frmShutdownCounter.lfm @@ -18,7 +18,8 @@ object ShutdownCounterForm: TShutdownCounterForm OnKeyDown = FormKeyDown OnShow = FormShow Position = poDesktopCenter - LCLVersion = '1.5' + LCLVersion = '1.7' + Visible = False object pnBottom: TPanel Left = 0 Height = 38 diff --git a/mangadownloader/forms/frmShutdownCounter.lrj b/mangadownloader/forms/frmShutdownCounter.lrj new file mode 100644 index 000000000..138413043 --- /dev/null +++ b/mangadownloader/forms/frmShutdownCounter.lrj @@ -0,0 +1,4 @@ +{"version":1,"strings":[ +{"hash":44537492,"name":"tshutdowncounterform.btabort.caption","sourcebytes":[38,65,98,111,114,116],"value":"&Abort"}, +{"hash":177511,"name":"tshutdowncounterform.btnow.caption","sourcebytes":[38,78,111,119],"value":"&Now"} +]} diff --git a/mangadownloader/forms/frmUpdateDialog.lfm b/mangadownloader/forms/frmUpdateDialog.lfm index 96194b458..a2b394625 100644 --- a/mangadownloader/forms/frmUpdateDialog.lfm +++ b/mangadownloader/forms/frmUpdateDialog.lfm @@ -13,6 +13,7 @@ object UpdateDialogForm: TUpdateDialogForm ClientWidth = 488 Position = poOwnerFormCenter LCLVersion = '1.7' + Visible = False object mmLog: TMemo Left = 8 Height = 336 diff --git a/mangadownloader/forms/frmUpdateDialog.lrj b/mangadownloader/forms/frmUpdateDialog.lrj index 721e0072e..e062b0e16 100644 --- a/mangadownloader/forms/frmUpdateDialog.lrj +++ b/mangadownloader/forms/frmUpdateDialog.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":215104852,"name":"tupdatedialogform.caption","sourcebytes":[78,101,119,32,86,101,114,115,105,111,110,32,70,111,117,110,100],"value":"New Version Found"}, {"hash":60067406,"name":"tupdatedialogform.lbmessage.caption","sourcebytes":[78,101,119,32,118,101,114,115,105,111,110,32,102,111,117,110,100,33,32,68,111,32,121,111,117,32,119,97,110,116,32,116,111,32,117,112,100,97,116,101,32,110,111,119,63,13,10,70,77,68,32,119,105,108,108,32,98,101,32,99,108,111,115,101,100,32,116,111,32,102,105,110,105,115,104,32,116,104,101,32,117,112,100,97,116,101,46],"value":"New version found! Do you want to update now?\r\nFMD will be closed to finish the update."}, {"hash":197568645,"name":"tupdatedialogform.btnupdate.caption","sourcebytes":[38,85,112,100,97,116,101],"value":"&Update"}, {"hash":45255362,"name":"tupdatedialogform.btnlater.caption","sourcebytes":[38,76,97,116,101,114],"value":"&Later"} diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index e5e09abcf..638ebd961 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -7,6 +7,7 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ClientWidth = 510 OnCreate = FormCreate LCLVersion = '1.7' + Visible = False object pcAdvanced: TPageControl Left = 0 Height = 307 diff --git a/mangadownloader/forms/frmWebsiteSelection.lfm b/mangadownloader/forms/frmWebsiteSelection.lfm index c5b82a54a..0a3dcb07e 100644 --- a/mangadownloader/forms/frmWebsiteSelection.lfm +++ b/mangadownloader/forms/frmWebsiteSelection.lfm @@ -13,6 +13,7 @@ object WebsiteSelectionForm: TWebsiteSelectionForm ClientWidth = 310 Position = poMainFormCenter LCLVersion = '1.7' + Visible = False object cbWebsites: TComboBox Left = 10 Height = 23 diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8a18b0ab5..2449a5849 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -370,10 +370,6 @@ msgstr "Cancel" msgid "Ok" msgstr "Ok" -#: taccountsetform.caption -msgid "Account" -msgstr "Account" - #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Show password" @@ -463,10 +459,6 @@ msgctxt "timportfavorites.btimport.caption" msgid "&OK" msgstr "&OK" -#: timportfavorites.caption -msgid "Import list ..." -msgstr "Import list ..." - #: timportfavorites.cbsoftware.text msgid "Domdomsoft Manga Downloader" msgstr "Domdomsoft Manga Downloader" @@ -504,6 +496,10 @@ msgctxt "tmainform.btdownload.caption" msgid "Download" msgstr "Download" +#: tmainform.btdownloadsplit.hint +msgid "Split download" +msgstr "Split download" + #: tmainform.btfavoriteschecknewchapter.caption msgctxt "tmainform.btfavoriteschecknewchapter.caption" msgid "Check for new chapter" @@ -1867,10 +1863,6 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Add to queue" -#: tnewchapter.caption -msgid "New Chapter Notification" -msgstr "New Chapter Notification" - #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Abort" @@ -1879,11 +1871,6 @@ msgstr "&Abort" msgid "&Now" msgstr "&Now" -#: tshutdowncounterform.caption -msgctxt "TSHUTDOWNCOUNTERFORM.CAPTION" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Later" @@ -1892,10 +1879,6 @@ msgstr "&Later" msgid "&Update" msgstr "&Update" -#: tupdatedialogform.caption -msgid "New Version Found" -msgstr "New Version Found" - #: tupdatedialogform.lbmessage.caption msgid "" "New version found! Do you want to update now?\n" @@ -2170,3 +2153,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index f5f6d8b74..1dc9b04a7 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -365,10 +365,6 @@ msgstr "Batal" msgid "Ok" msgstr "Ok" -#: taccountsetform.caption -msgid "Account" -msgstr "Akun" - #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Tampilkan kata kunci" @@ -455,10 +451,6 @@ msgctxt "timportfavorites.btimport.caption" msgid "&OK" msgstr "&OK" -#: timportfavorites.caption -msgid "Import list ..." -msgstr "Impor daftar ..." - #: timportfavorites.cbsoftware.text msgid "Domdomsoft Manga Downloader" msgstr "Domdomsoft Manga Downloader" @@ -495,6 +487,10 @@ msgctxt "tmainform.btdownload.caption" msgid "Download" msgstr "Unduh" +#: tmainform.btdownloadsplit.hint +msgid "Split download" +msgstr "Pecah unduhan" + #: tmainform.btfavoriteschecknewchapter.caption msgctxt "tmainform.btfavoriteschecknewchapter.caption" msgid "Check for new chapter" @@ -1847,10 +1843,6 @@ msgctxt "tnewchapter.btqueue.caption" msgid "&Add to queue" msgstr "&Tambahkan ke antrian" -#: tnewchapter.caption -msgid "New Chapter Notification" -msgstr "Pemberitahuan bab baru" - #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Batalkan" @@ -1859,11 +1851,6 @@ msgstr "&Batalkan" msgid "&Now" msgstr "&Sekarang" -#: tshutdowncounterform.caption -msgctxt "tshutdowncounterform.caption" -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Nanti saja" @@ -1872,10 +1859,6 @@ msgstr "&Nanti saja" msgid "&Update" msgstr "&Perbarui" -#: tupdatedialogform.caption -msgid "New Version Found" -msgstr "Versi baru ditemukan" - #: tupdatedialogform.lbmessage.caption msgid "" "New version found! Do you want to update now?\n" @@ -2150,3 +2133,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index d9d7e1076..7de031368 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -330,10 +330,6 @@ msgstr "" msgid "Ok" msgstr "" -#: taccountsetform.caption -msgid "Account" -msgstr "" - #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "" @@ -420,10 +416,6 @@ msgctxt "timportfavorites.btimport.caption" msgid "&OK" msgstr "" -#: timportfavorites.caption -msgid "Import list ..." -msgstr "" - #: timportfavorites.cbsoftware.text msgid "Domdomsoft Manga Downloader" msgstr "" @@ -460,6 +452,10 @@ msgctxt "tmainform.btdownload.caption" msgid "Download" msgstr "" +#: tmainform.btdownloadsplit.hint +msgid "Split download" +msgstr "" + #: tmainform.btfavoriteschecknewchapter.caption msgctxt "tmainform.btfavoriteschecknewchapter.caption" msgid "Check for new chapter" @@ -1778,10 +1774,6 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "" -#: tnewchapter.caption -msgid "New Chapter Notification" -msgstr "" - #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "" @@ -1790,11 +1782,6 @@ msgstr "" msgid "&Now" msgstr "" -#: tshutdowncounterform.caption -msgctxt "TSHUTDOWNCOUNTERFORM.CAPTION" -msgid "Free Manga Downloader" -msgstr "" - #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "" @@ -1803,10 +1790,6 @@ msgstr "" msgid "&Update" msgstr "" -#: tupdatedialogform.caption -msgid "New Version Found" -msgstr "" - #: tupdatedialogform.lbmessage.caption msgid "" "New version found! Do you want to update now?\n" From 3e7788de53ed8af36a7e6cea32fba018177c7edf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 05:23:48 +0800 Subject: [PATCH 1419/2794] downloadmanager, try to set task website with downloadinfo.website if empty and initialize website/moduleid/mangasiteid with invalid value --- baseunits/uDownloadsManager.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 927dacd6f..0da1900d7 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1183,6 +1183,8 @@ procedure TTaskThread.Execute; Container.ThreadState := True; Container.DownloadInfo.TransferRate := FormatByteSize(Container.ReadCount, true); try + if (Container.Website = '') and (Container.DownloadInfo.Website <> '') then + Container.Website := Container.DownloadInfo.Website; if Container.ModuleId > -1 then DynamicPageLink := Modules.Module[Container.ModuleId].DynamicPageLink else @@ -1495,6 +1497,9 @@ constructor TTaskContainer.Create; PageLinks := TStringList.Create; PageContainerLinks := TStringList.Create; FileNames := TStringList.Create; + FWebsite := ''; + ModuleId := -1; + MangaSiteID := High(WebsiteRoots) + 1; ReadCount := 0; WorkCounter := 0; CurrentPageNumber := 0; From e76c2fc0de3ddfaa21892a4d4385adc004d2075b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 06:07:25 +0800 Subject: [PATCH 1420/2794] frmmain, implement split download task with custom count closed #321 --- mangadownloader/forms/frmMain.lfm | 2 +- mangadownloader/forms/frmMain.pas | 184 +++++++++++++++---------- mangadownloader/languages/fmd.en.po | 15 +- mangadownloader/languages/fmd.id_ID.po | 15 +- mangadownloader/languages/fmd.po | 14 ++ 5 files changed, 157 insertions(+), 73 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 42133894c..e7a06c7b5 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,7 +13,6 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter - LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 @@ -907,6 +906,7 @@ object MainForm: TMainForm 1000AE752E00E79C3D00E79C3D00E79C3D00E99E4099E99E40CCE99E40CCE99E 4099E79C3D00E79C3D00E79C3D00AE752E003A271000FFFFFF00 } + OnClick = btDownloadSplitClick end end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 287accc4d..be41bfbad 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -388,6 +388,7 @@ TMainForm = class(TForm) procedure btCheckLatestVersionClick(Sender: TObject); procedure btClearLogFileClick(Sender: TObject); procedure btDonateClick(Sender: TObject); + procedure btDownloadSplitClick(Sender: TObject); procedure btFavoritesImportClick(Sender: TObject); procedure btOpenLogClick(Sender: TObject); procedure btReadOnlineClick(Sender: TObject); @@ -827,6 +828,9 @@ TSearchDBThread = class(TThread) RS_DlgMangaListSelect = 'You must choose at least 1 manga website!'; RS_DlgCannotGetMangaInfo = 'Cannot get manga info. Please check your internet connection and try it again.'; RS_DlgCannotConnectToServer = 'Cannot connect to the server.'; + RS_DlgSplitDownload = 'Split download'; + RS_DlgDownloadCount = 'Download count:'; + RS_WrongInput = 'Invalid input!'; RS_LblOptionExternalParamsHint = '%s : Path to the manga'#13#10+ '%s : Chapter filename'#13#10+ #13#10+ @@ -1144,6 +1148,7 @@ procedure TMainForm.FormCreate(Sender: TObject); // read online btDownload.Enabled := False; + btDownloadSplit.Enabled := btDownload.Enabled; btReadOnline.Enabled := False; btAddToFavorites.Enabled := False; @@ -1947,84 +1952,102 @@ procedure TMainForm.GeneratetvDownloadFilterNodes; procedure TMainForm.btDownloadClick(Sender: TObject); var - s: String; - i, pos: Integer; - isCreate: Boolean = False; - xNode: PVirtualNode; + links,names:TStrings; + node:PVirtualNode; + s:String; + c,p,i,j,k:Integer; begin if clbChapterList.CheckedCount = 0 then Exit; - Pos := -1; - xNode := clbChapterList.GetFirstChecked; - for i := 0 to clbChapterList.CheckedCount - 1 do - begin - if (xNode^.CheckState = csCheckedNormal) and (vsVisible in xNode^.States) then + links:=TStringList.Create; + names:=TStringList.Create; + try + node:=clbChapterList.GetFirstChecked(); + while Assigned(node) do begin - if not isCreate then + if (vsVisible in node^.States) then begin - pos := DLManager.AddTask; - isCreate := True; + links.Add(mangaInfo.chapterLinks[node^.Index]); + s:=CustomRename(OptionChapterCustomRename, + mangaInfo.website, + mangaInfo.title, + mangaInfo.authors, + mangaInfo.artists, + mangaInfo.chapterName[node^.Index], + Format('%.4d',[node^.Index+1]), + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); + names.Add(s); + ChapterList[node^.Index].Downloaded:=True; + clbChapterList.ReinitNode(node,False); end; - DLManager.Items[pos].Website := mangaInfo.website; - // generate chapter folder name - s := CustomRename(OptionChapterCustomRename, - mangaInfo.website, - mangaInfo.title, - mangaInfo.authors, - mangaInfo.artists, - mangaInfo.chapterName.Strings[xNode^.Index], - Format('%.4d', [xNode^.Index + 1]), - OptionChangeUnicodeCharacter, - OptionChangeUnicodeCharacterStr); - DLManager.Items[pos].ChapterName.Add(s); - DLManager.Items[pos].ChapterLinks.Add( - mangaInfo.chapterLinks.Strings[xNode^.Index]); - ChapterList[xNode^.Index].Downloaded := True; - clbChapterList.ReinitNode(xNode, False); + node:=clbChapterList.GetNextChecked(node); end; - xNode := clbChapterList.GetNextChecked(xNode); - end; - if not isCreate then - Exit; - if cbAddAsStopped.Checked then - begin - DLManager.Items[pos].DownloadInfo.Status := RS_Stopped; - DLManager.Items[pos].Status := STATUS_STOP; - end - else - begin - DLManager.Items[pos].DownloadInfo.Status := RS_Waiting; - DLManager.Items[pos].Status := STATUS_WAIT; + clbChapterList.Repaint; + if links.Count<>0 then + begin + s:=edSaveTo.Text; + if OptionGenerateMangaFolder then + s:=AppendPathDelim(s)+CustomRename( + OptionMangaCustomRename, + mangaInfo.website, + mangaInfo.title, + mangaInfo.authors, + mangaInfo.artists, + '', + '', + OptionChangeUnicodeCharacter, + OptionChangeUnicodeCharacterStr); + c:=1; + p:=links.Count; + if btDownload.Tag>1 then + begin + c:=btDownload.Tag; + p:=links.Count div btDownload.Tag; + end; + btDownload.Tag:=0; + k:=0; + for i:=1 to c do + begin + if i=c then + p:=links.Count-k; + with DLManager[DLManager.AddTask] do + begin + for j:=1 to p do + begin + ChapterLinks.Add(links[k]); + ChapterName.Add(names[k]); + Inc(k); + end; + if cbAddAsStopped.Checked then + begin + DownloadInfo.Status:=RS_Stopped; + Status:=STATUS_STOP; + end + else + begin + DownloadInfo.Status:=RS_Waiting; + Status:=STATUS_WAIT; + end; + Website:=mangaInfo.website; + DownloadInfo.Website:=mangaInfo.website; + DownloadInfo.Link:=mangaInfo.url; + DownloadInfo.Title:=mangaInfo.title; + DownloadInfo.DateTime:=Now; + DownloadInfo.SaveTo:=s; + CurrentDownloadChapterPtr:=0; + end; + end; + DLManager.DownloadedChapters.Chapters[mangaInfo.website+mangaInfo.link]:=links.Text; + FavoriteManager.AddToDownloadedChaptersList(mangaInfo.website,mangaInfo.link,links); + DLManager.CheckAndActiveTask; + pcMain.ActivePage:=tsDownload; + UpdateVtDownload; + end; + finally + links.Free; + names.Free; end; - DLManager.Items[pos].CurrentDownloadChapterPtr := 0; - DLManager.Items[pos].DownloadInfo.Website := mangaInfo.website; - DLManager.Items[pos].DownloadInfo.Link := mangaInfo.url; - DLManager.Items[pos].DownloadInfo.Title := mangaInfo.title; - DLManager.Items[pos].DownloadInfo.DateTime := Now; - - // save to - s := edSaveTo.Text; - if OptionGenerateMangaFolder then - s := AppendPathDelim(s) + CustomRename( - OptionMangaCustomRename, - mangaInfo.website, - mangaInfo.title, - mangaInfo.authors, - mangaInfo.artists, - '', - '', - OptionChangeUnicodeCharacter, - OptionChangeUnicodeCharacterStr); - DLManager.Items[pos].DownloadInfo.SaveTo := s; - UpdateVtDownload; - - DLManager.CheckAndActiveTask; - DLManager.DownloadedChapters.Chapters[mangaInfo.website + mangaInfo.link]:= - DLManager.Items[pos].ChapterLinks.Text; - FavoriteManager.AddToDownloadedChaptersList( - mangaInfo.website, mangaInfo.link, DLManager.Items[pos].ChapterLinks); - clbChapterList.Repaint; - pcMain.ActivePage := tsDownload; end; procedure TMainForm.btAddToFavoritesClick(Sender: TObject); @@ -2237,6 +2260,24 @@ procedure TMainForm.btDonateClick(Sender: TObject); OpenURL('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=akarin.km@gmail.com&item_name=Donation+to+Free+Manga+Downloader'); end; +procedure TMainForm.btDownloadSplitClick(Sender: TObject); +var + s:String=''; + c:Integer=-1; +begin + if InputQuery(RS_DlgSplitDownload,RS_DlgDownloadCount,s) and (s<>'') then + begin + c:=StrToIntDef(s,-1); + if c<=0 then + MessageDlg(RS_WrongInput,mtError,[mbOK],0) + else + begin + btDownload.Tag:=c; + btDownloadClick(btDownload); + end; + end; +end; + procedure TMainForm.btFavoritesImportClick(Sender: TObject); begin with TImportFavorites.Create(Self) do try @@ -4354,6 +4395,7 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; pbWait.Visible := True; end; btDownload.Enabled := False; + btDownloadSplit.Enabled := btDownload.Enabled; btReadOnline.Enabled := True; DisableAddToFavorites(AWebsite); //check if manga already in FavoriteManager list @@ -4415,6 +4457,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); edFilterMangaInfoChaptersChange(nil); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); + btDownloadSplit.Enabled := btDownload.Enabled; btReadOnline.Enabled := (mangaInfo.link <> ''); DisableAddToFavorites(website); @@ -5018,6 +5061,7 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); regx: TRegExpr; begin btDownload.Enabled := False; + btDownloadSplit.Enabled := btDownload.Enabled; btAddToFavorites.Enabled := False; btReadOnline.Enabled := False; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 2449a5849..ba033d609 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -105,6 +105,10 @@ msgstr "Cannot connect to the server." msgid "Cannot get manga info. Please check your internet connection and try it again." msgstr "Cannot get manga info. Please check your internet connection and try it again." +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Download count:" + #: frmmain.rs_dlgmangalistselect msgid "You must choose at least 1 manga website!" msgstr "You must choose at least 1 manga website!" @@ -129,6 +133,11 @@ msgstr "Are you sure you want to delete this item(s)?" msgid "Are you sure you want to delete the task(s)?" msgstr "Are you sure you want to delete the task(s)?" +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Split download" + #: frmmain.rs_dlgtitleexistindllist msgid "" "This title are already in download list.\n" @@ -300,6 +309,10 @@ msgstr "Path to the software (e.g. C:\\MangaDownloader)" msgid "Today" msgstr "Today" +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Invalid input!" + #: frmmain.rs_yesterday msgid "Yesterday" msgstr "Yesterday" @@ -497,6 +510,7 @@ msgid "Download" msgstr "Download" #: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" msgid "Split download" msgstr "Split download" @@ -2153,4 +2167,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1dc9b04a7..23837c61c 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -104,6 +104,10 @@ msgstr "Tidak dapat terhubung ke server." msgid "Cannot get manga info. Please check your internet connection and try it again." msgstr "Tidak bisa mendapatkan informasi komik. Silakan periksa koneksi internet Anda dan coba lagi." +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Jumlah unduhan:" + #: frmmain.rs_dlgmangalistselect msgid "You must choose at least 1 manga website!" msgstr "Anda harus memilih minimal 1 situs komik!" @@ -128,6 +132,11 @@ msgstr "Apakah Anda yakin ingin menghapus data ini?" msgid "Are you sure you want to delete the task(s)?" msgstr "Apakah Anda yakin ingin menghapus unduhan ini?" +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Pecah unduhan" + #: frmmain.rs_dlgtitleexistindllist msgid "" "This title are already in download list.\n" @@ -298,6 +307,10 @@ msgstr "Path ke perangkat lunak (misalnya C:\\MangaDownloader)" msgid "Today" msgstr "Hari ini" +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Input salah!" + #: frmmain.rs_yesterday msgid "Yesterday" msgstr "Kemarin" @@ -488,6 +501,7 @@ msgid "Download" msgstr "Unduh" #: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" msgid "Split download" msgstr "Pecah unduhan" @@ -2133,4 +2147,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 7de031368..9424803dd 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -86,6 +86,10 @@ msgstr "" msgid "Cannot get manga info. Please check your internet connection and try it again." msgstr "" +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "" + #: frmmain.rs_dlgmangalistselect msgid "You must choose at least 1 manga website!" msgstr "" @@ -110,6 +114,11 @@ msgstr "" msgid "Are you sure you want to delete the task(s)?" msgstr "" +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "" + #: frmmain.rs_dlgtitleexistindllist msgid "" "This title are already in download list.\n" @@ -263,6 +272,10 @@ msgstr "" msgid "Today" msgstr "" +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "" + #: frmmain.rs_yesterday msgid "Yesterday" msgstr "" @@ -453,6 +466,7 @@ msgid "Download" msgstr "" #: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" msgid "Split download" msgstr "" From df0395b89d075715fac7d36529b742dce087ec24 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 06:29:40 +0800 Subject: [PATCH 1421/2794] reformat download status, process count always on front --- baseunits/uDownloadsManager.pas | 16 ++++++++-------- baseunits/uFavoritesManager.pas | 4 ++-- baseunits/uSilentThread.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 0da1900d7..b7d8160ba 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1392,7 +1392,7 @@ procedure TTaskThread.Execute; else begin Container.Status := STATUS_FINISH; - Container.DownloadInfo.Status := RS_Finish; + Container.DownloadInfo.Status := Format('[%d/%d] %s',[Container.ChapterLinks.Count,Container.ChapterLinks.Count,RS_Finish]); Container.DownloadInfo.Progress := ''; end; Synchronize(SyncShowBaloon); @@ -1434,7 +1434,7 @@ procedure TTaskThread.DoTerminate; (FailedChapterLinks.Count = 0) then begin Status := STATUS_FINISH; - DownloadInfo.Status := RS_Finish; + DownloadInfo.Status := Format('[%d/%d] %s',[Container.ChapterLinks.Count,Container.ChapterLinks.Count,RS_Finish]); DownloadInfo.Progress := ''; end else @@ -1737,7 +1737,7 @@ procedure TDownloadManager.Restore; PageNumber := ReadInteger(tid, 'NumberOfPages', 0); CurrentPageNumber := ReadInteger(tid, 'CurrentPage', 0); if Status = STATUS_COMPRESS then - DownloadInfo.Status := RS_Waiting; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Waiting]); s := ReadString(tid, 'DateTime', ''); //for old config if (Pos('/', s) > 0) or (Pos('\', s) > 0) then @@ -1915,7 +1915,7 @@ procedure TDownloadManager.SetTaskActive(const taskID: Integer); if not ThreadState then begin Status := STATUS_WAIT; - DownloadInfo.Status := RS_Waiting; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Waiting]); end; end; @@ -1937,7 +1937,7 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; else begin Status := STATUS_WAIT; - DownloadInfo.Status := RS_Waiting; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Waiting]); end; //force to check task if all task loaded is STATUS_WAIT if tcount = 0 then @@ -1975,7 +1975,7 @@ procedure TDownloadManager.StopTask(const taskID: Integer; if Status = STATUS_WAIT then begin Status := STATUS_STOP; - DownloadInfo.Status := RS_Stopped; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Stopped]); end else if ThreadState then begin @@ -1999,7 +1999,7 @@ procedure TDownloadManager.StartAllTasks; if Enabled and (Status <> STATUS_FINISH) and (not ThreadState) then begin Status := STATUS_WAIT; - DownloadInfo.Status := RS_Waiting; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Waiting]); end; CheckAndActiveTask; end; @@ -2108,7 +2108,7 @@ procedure TDownloadManager.DisableTask(const TaskId: Integer); if Status = STATUS_WAIT then begin Status := STATUS_STOP; - DownloadInfo.Status := RS_Stopped; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Stopped]); end; Enabled := False; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index a1d95c0ae..651304bb7 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -732,12 +732,12 @@ procedure TFavoriteManager.ShowResult; if LNCResult = ncrDownload then begin - DownloadInfo.Status := RS_Waiting; + DownloadInfo.Status := Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Waiting]); Status := STATUS_WAIT; end else begin - DownloadInfo.Status := RS_Stopped; + DownloadInfo.Status := Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Stopped]); Status := STATUS_STOP; end; end; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 53704746b..01e2e014e 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -345,11 +345,11 @@ procedure TSilentThread.MainThreadAfterChecking; if cbAddAsStopped.Checked then begin DLManager.Items[p].Status := STATUS_STOP; - DLManager.Items[p].downloadInfo.Status := RS_Stopped; + DLManager.Items[p].downloadInfo.Status := Format('[%d/%d] %s',[1,DLManager[p].ChapterLinks.Count,RS_Stopped]); end else begin - DLManager.Items[p].downloadInfo.Status := RS_Waiting; + DLManager.Items[p].downloadInfo.Status := Format('[%d/%d] %s',[1,DLManager[p].ChapterLinks.Count,RS_Waiting]); DLManager.Items[p].Status := STATUS_WAIT; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index be41bfbad..1b695f695 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2021,12 +2021,12 @@ procedure TMainForm.btDownloadClick(Sender: TObject); end; if cbAddAsStopped.Checked then begin - DownloadInfo.Status:=RS_Stopped; + DownloadInfo.Status:=Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Stopped]); Status:=STATUS_STOP; end else begin - DownloadInfo.Status:=RS_Waiting; + DownloadInfo.Status:=Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Waiting]); Status:=STATUS_WAIT; end; Website:=mangaInfo.website; From 0756c5fb9f05ca2c86d3bad3d4a8ee1c7c725b16 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 06:32:25 +0800 Subject: [PATCH 1422/2794] downloadmanager, move manthreadcompressrepaint inline, don't need to synchronize --- baseunits/uDownloadsManager.pas | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b7d8160ba..4342e9f25 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -86,7 +86,6 @@ TTaskThread = class(THTTPThread) procedure SetCurrentWorkingDir(AValue: String); protected procedure CheckOut; - procedure MainThreadCompressRepaint; procedure Execute; override; procedure DoTerminate; override; procedure Compress; @@ -886,14 +885,6 @@ function TTaskThread.GetFileName(const AWorkId: Integer): String; {$ENDIF} end; -procedure TTaskThread.MainThreadCompressRepaint; -begin - Container.DownloadInfo.Status := - Format('[%d/%d] %s', [Container.CurrentDownloadChapterPtr + 1, - Container.ChapterLinks.Count, RS_Compressing]); - MainForm.vtDownload.Repaint; -end; - procedure TTaskThread.Compress; var uPacker: TPacker; @@ -902,7 +893,9 @@ procedure TTaskThread.Compress; begin if (Container.Manager.compress >= 1) then begin - Synchronize(MainThreadCompressRepaint); + Container.DownloadInfo.Status := + Format('[%d/%d] %s', [Container.CurrentDownloadChapterPtr + 1, + Container.ChapterLinks.Count, RS_Compressing]); uPacker := TPacker.Create; try case Container.Manager.compress of From 4985bd66b8adc3b1347e6f27ca9459ece343dee6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 06:37:49 +0800 Subject: [PATCH 1423/2794] reformat downloadinfo, newly added task always start with 0 --- baseunits/uFavoritesManager.pas | 4 ++-- baseunits/uSilentThread.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 651304bb7..881617a67 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -732,12 +732,12 @@ procedure TFavoriteManager.ShowResult; if LNCResult = ncrDownload then begin - DownloadInfo.Status := Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Waiting]); + DownloadInfo.Status := Format('[%d/%d] %s',[0,ChapterLinks.Count,RS_Waiting]); Status := STATUS_WAIT; end else begin - DownloadInfo.Status := Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Stopped]); + DownloadInfo.Status := Format('[%d/%d] %s',[0,ChapterLinks.Count,RS_Stopped]); Status := STATUS_STOP; end; end; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 01e2e014e..83a577d4d 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -345,11 +345,11 @@ procedure TSilentThread.MainThreadAfterChecking; if cbAddAsStopped.Checked then begin DLManager.Items[p].Status := STATUS_STOP; - DLManager.Items[p].downloadInfo.Status := Format('[%d/%d] %s',[1,DLManager[p].ChapterLinks.Count,RS_Stopped]); + DLManager.Items[p].downloadInfo.Status := Format('[%d/%d] %s',[0,DLManager[p].ChapterLinks.Count,RS_Stopped]); end else begin - DLManager.Items[p].downloadInfo.Status := Format('[%d/%d] %s',[1,DLManager[p].ChapterLinks.Count,RS_Waiting]); + DLManager.Items[p].downloadInfo.Status := Format('[%d/%d] %s',[0,DLManager[p].ChapterLinks.Count,RS_Waiting]); DLManager.Items[p].Status := STATUS_WAIT; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1b695f695..079bdcb70 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2021,12 +2021,12 @@ procedure TMainForm.btDownloadClick(Sender: TObject); end; if cbAddAsStopped.Checked then begin - DownloadInfo.Status:=Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Stopped]); + DownloadInfo.Status:=Format('[%d/%d] %s',[0,ChapterLinks.Count,RS_Stopped]); Status:=STATUS_STOP; end else begin - DownloadInfo.Status:=Format('[%d/%d] %s',[1,ChapterLinks.Count,RS_Waiting]); + DownloadInfo.Status:=Format('[%d/%d] %s',[0,ChapterLinks.Count,RS_Waiting]); Status:=STATUS_WAIT; end; Website:=mangaInfo.website; From 684798fae9f84e961d810e70551f15eeab334216 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 07:28:15 +0800 Subject: [PATCH 1424/2794] improve split download, share the rest among the first tasks, and check to avoid over count #321 --- mangadownloader/forms/frmMain.pas | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 079bdcb70..7b1c459fe 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1955,7 +1955,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); links,names:TStrings; node:PVirtualNode; s:String; - c,p,i,j,k:Integer; + c,p,r,i,j,k,l:Integer; begin if clbChapterList.CheckedCount = 0 then Exit; @@ -2000,20 +2000,32 @@ procedure TMainForm.btDownloadClick(Sender: TObject); OptionChangeUnicodeCharacterStr); c:=1; p:=links.Count; + if btDownload.Tag>=links.Count then + begin + c:=links.Count; + p:=1; + end + else if btDownload.Tag>1 then begin c:=btDownload.Tag; - p:=links.Count div btDownload.Tag; + p:=links.Count div c; + r:=links.Count mod c; end; btDownload.Tag:=0; k:=0; for i:=1 to c do begin + if i<=r then + l:=p+1 + else if i=c then - p:=links.Count-k; + l:=links.Count-k + else + l:=p; with DLManager[DLManager.AddTask] do begin - for j:=1 to p do + for j:=1 to l do begin ChapterLinks.Add(links[k]); ChapterName.Add(names[k]); From f443b73dcdcda098b659b01c81fc5692cd21dae6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 08:15:05 +0800 Subject: [PATCH 1425/2794] frmmain, enabled parent hint, hintpause to 500 and hinthidepause to 3000 --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e7a06c7b5..f9b83b8ac 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -13,6 +13,7 @@ object MainForm: TMainForm OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter + ShowHint = True Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7b1c459fe..5084dcac3 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1242,6 +1242,11 @@ procedure TMainForm.FormCreate(Sender: TObject); LoadMangaOptions; LoadOptions; ApplyOptions; + + // hint + ShowHint := True; + Application.HintPause := 500; + Application.HintHidePause := 3000; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); From 343e3ca7dbc4f09387994fa7953d24140de1b246 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 17 Aug 2016 08:18:54 +0800 Subject: [PATCH 1426/2794] Bump version 0.9.78.0 --- changelog.txt | 12 ++++++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index c15a99fc6..415956112 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,18 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.78.0 (17-08-2016) +[*] Fixed various issue with unicode path and filename +[*] TripleSevenScan: fixed accept adult warning +[*] MangaIndo: fixed manga info +[*] MangaChanRU/HentaiChanRU/YaoiChanRU: fixed manga info and empty chapters +[+] Added custom text to be used to replace unicode character +[+] Added context menu to copy log message +[*] MangaStream: fixed an issue with some chapters +[+] Added split download feature +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.77.0...0.9.78.0 + 0.9.77.0 (13-08-2016) [*] MangaTraders: rewrite all code [*] MangaIndo: rewrite all code diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 55089bf4f..a6b1f57a9 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="77"/> + <RevisionNr Value="78"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 39b36a067..03b08d56c 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.77.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.77.0/fmd_0.9.77.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.77.0/fmd_0.9.77.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.77.0/fmd_0.9.77.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.77.0/fmd_0.9.77.0_Win64.7z +VERSION=0.9.78.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.78.0/fmd_0.9.78.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.78.0/fmd_0.9.78.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.78.0/fmd_0.9.78.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.78.0/fmd_0.9.78.0_Win64.7z From c93f1e2c57363389c329c79a6264f745245fa76a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 18:28:02 +0800 Subject: [PATCH 1427/2794] fixed create download error when selected chapters is 1 fixed #355 --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5084dcac3..390d9b113 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2005,6 +2005,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); OptionChangeUnicodeCharacterStr); c:=1; p:=links.Count; + r:=0; if btDownload.Tag>=links.Count then begin c:=links.Count; From 43fb1bcb3bb8a34e2ac74dd58f3c46e501026c6c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 19:00:56 +0800 Subject: [PATCH 1428/2794] changed default connection timeout to 30 --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 390d9b113..88b4aeea0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4532,7 +4532,7 @@ procedure TMainForm.LoadOptions; seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', 1); seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', 1); seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', 5);; - seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', 30000); + seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', 30); cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); cbOptionProxyType.Text := ReadString('connections', 'ProxyType', 'HTTP'); edOptionHost.Text := ReadString('connections', 'Host', ''); From f574d0cb879ccb1ca4015662e68bf80eff73c326 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 21:59:33 +0800 Subject: [PATCH 1429/2794] fixed spliturl --- baseunits/httpsendthread.pas | 62 +++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 7fffe6c47..f9a558dee 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -66,7 +66,7 @@ procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); function MaybeEncodeURL(const AValue: String): String; -procedure SplitURL(const URL: String; out Host, Path: String); +procedure SplitURL(URL: String; out Host, Path: String); const UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; @@ -104,41 +104,65 @@ function poschar(const c:char;const s:string;const offset:cardinal=1):integer; Result:=0; end; -procedure SplitURL(const URL: String; out Host, Path: String); +procedure SplitURL(URL: String; out Host, Path: String); + +procedure cleanuri(var u:string); +begin + while (Length(u)<>0) and (u[1] in ['.',':','/']) do + Delete(u,1,1); +end; + var - p: Integer; + prot,port: String; + p,q: Integer; begin Host:=''; Path:=''; + URL:=Trim(URL); if URL='' then Exit; + prot:=''; + port:=''; + p:=poschar(':',URL); + if (p<>0) and (p<Length(URL)) and (URL[P+1]='/') then + begin + prot:=Copy(URL,1,p-1); + Delete(URL,1,p); + end; + p:=poschar(':',URL); + if (p<>0) and (p<Length(URL)) and (URL[P+1] in ['0'..'9']) then + begin + for q:=p+1 to Length(URL) do + if not (URL[q] in ['0'..'9']) then Break; + if q=Length(URL) then Inc(q); + port:=Copy(URL,p+1,q-p-1); + delete(URL,p,q-p); + end; + cleanuri(URL); p:=poschar('.',URL); + if (p<>0) and (p>poschar('/',URL)) then p:=0; if (p<>0) and (p<Length(URL)) then begin p:=poschar('/',URL,p); - if p<>0 then Host:=Copy(URL,1,p-1) + if p<>0 then + begin + Host:=Copy(URL,1,p-1); + Delete(URL,1,p-1); + cleanuri(URL); + end else begin Host:=URL; - Exit; + URL:=''; end; end; if Host<>'' then begin - while (Length(Host)<>0) and (Host[1] in ['.',':','/']) do - Delete(Host,1,1); - if Pos('://',Host)=0 then - Host:='http://'+Host; - end; - if p<>0 then - Path:=Copy(URL,p,Length(URL)) - else - Path:=URL; - if Path<>'' then - begin - while Pos('//',Path)<>0 do Path:=StringReplace(Path,'//','/',[rfReplaceAll]); - if Path='/' then Path:='' - else if Path[1]<>'/' then Path:='/'+Path; + if prot<>'' then Host:=prot+'://'+Host + else Host:='http://'+Host; + if port<>'' then Host:=Host+':'+port; end; + if URL='' then Exit; + Path:='/'+URL; end; function KeyVal(const AKey, AValue: String): TKeyValuePair; From c95d1eeaed97377b45add2bf356c67a0ab34b6e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 21:59:49 +0800 Subject: [PATCH 1430/2794] cleanup --- baseunits/uBaseUnit.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c6aa8e02d..3187264ee 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1280,7 +1280,6 @@ function MaybeFillHost(const Host, URL: String): String; H,P: String; begin SplitURL(URL,H,P); - Result:=Host+P; if H='' then Result:=RemoveURLDelim(Host)+P else Result:=URL; end; From 7bde57173138689dd47950c5ce8773890c9f58a7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 22:13:44 +0800 Subject: [PATCH 1431/2794] getmangainfosthread, enclose load cover in try except --- baseunits/uGetMangaInfosThread.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 0ab7f5a4c..84fa23398 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -156,7 +156,10 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.FHTTP.Document.Clear; FIsHasMangaCover := FInfo.FHTTP.GET(FInfo.mangaInfo.coverLink); if FIsHasMangaCover then - FCover.LoadFromStream(FInfo.FHTTP.Document); + try + FCover.LoadFromStream(FInfo.FHTTP.Document); + except + end; end else FIsHasMangaCover := False; From d05dafe4099dc3455b6346df3319dc35e6b3ad02 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 23:26:05 +0800 Subject: [PATCH 1432/2794] komikid, rewrite all code and remove old code fixed #354 --- baseunits/ModuleList.inc | 3 +- .../includes/Komikid/chapter_page_number.inc | 33 ----- baseunits/includes/Komikid/image_url.inc | 45 ------- .../includes/Komikid/manga_information.inc | 73 ----------- .../includes/Komikid/names_and_links.inc | 41 ------- baseunits/modules/Komikid.pas | 113 +++++++++++++++++ baseunits/uBaseUnit.pas | 115 +++++++++--------- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 10 -- 9 files changed, 170 insertions(+), 273 deletions(-) delete mode 100644 baseunits/includes/Komikid/chapter_page_number.inc delete mode 100644 baseunits/includes/Komikid/image_url.inc delete mode 100644 baseunits/includes/Komikid/manga_information.inc delete mode 100644 baseunits/includes/Komikid/names_and_links.inc create mode 100644 baseunits/modules/Komikid.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index befabac29..d07720ac6 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -47,4 +47,5 @@ uses MangaPark, MangaIndo, FunManga, - SundayWebry; + SundayWebry, + Komikid; diff --git a/baseunits/includes/Komikid/chapter_page_number.inc b/baseunits/includes/Komikid/chapter_page_number.inc deleted file mode 100644 index 62ecf14b1..000000000 --- a/baseunits/includes/Komikid/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetKomikidPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KOMIKID_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Next Page"', parse[i]) > 0) then - begin - s := parse[i - 6]; - Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Komikid/image_url.inc b/baseunits/includes/Komikid/image_url.inc deleted file mode 100644 index 5b6eb8305..000000000 --- a/baseunits/includes/Komikid/image_url.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetKomikidImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - s := EncodeURL(FillMangaSiteHost(KOMIKID_ID, URL) + '/' + - IntToStr(WorkId + 1) + '/'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', LowerCase(parse[i])) > 0) and - (Pos('class="picture"', LowerCase(parse[i])) > 0) then - begin - s := GetVal(parse[i], 'src'); - regx := TRegExpr.Create; - try - regx.Expression := 'https?://'; - if not regx.Exec(s) then - s := WebsiteRoots[KOMIKID_ID, 1] + '/' + s; - s := EncodeURL(s); - Task.container.PageLinks[WorkId] := s; - finally - regx.Free; - end; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Komikid/manga_information.inc b/baseunits/includes/Komikid/manga_information.inc deleted file mode 100644 index 33390d731..000000000 --- a/baseunits/includes/Komikid/manga_information.inc +++ /dev/null @@ -1,73 +0,0 @@ - function GetKomikidInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[KOMIKID_ID, 0]; - mangaInfo.url := FillMangaSiteHost(KOMIKID_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i - 2], 'content="', ' Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := URL + '/' + GetVal(parse[i], 'value'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Komikid/names_and_links.inc b/baseunits/includes/Komikid/names_and_links.inc deleted file mode 100644 index 114101927..000000000 --- a/baseunits/includes/Komikid/names_and_links.inc +++ /dev/null @@ -1,41 +0,0 @@ - function KomikidGetNamesAndLinks: Byte; - var - i: Cardinal; - isFound: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[KOMIKID_ID, 1] + KOMIKID_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="series_col"', LowerCase(parse[i])) > 0 then - isFound := True; - if isFound and (Pos('</html>', LowerCase(parse[i])) > 0) then - isFound := False; - if isFound and (Pos('<a ', parse[i]) > 0) then - if (Pos('<li>', parse[i - 1]) > 0) then - begin - Result := NO_ERROR; - links.Add('/' + GetVal(parse[i], 'href="')); - names.Add(Trim(RemoveStringBreaks(HTMLEntitiesFilter( - StringFilter(parse[i + 1]))))); - end; - end; - parse.Clear; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/modules/Komikid.pas b/baseunits/modules/Komikid.pas new file mode 100644 index 000000000..f17c48a56 --- /dev/null +++ b/baseunits/modules/Komikid.pas @@ -0,0 +1,113 @@ +unit Komikid; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/changeMangaList?type=text'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="manga-list"]/li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="content"]//img/@src')); + if title = '' then title := XPathString('//div[@class="content"]//h5'); + authors := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Author")]/following-sibling::dd[1]/*'); + artists := XPathString('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Artist")]/following-sibling::dd[1]'); + genres := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Categories")]/following-sibling::dd[1]/*'); + status := MangaInfoStatusIfPos(XPathString( + '//dl[@class="dl-horizontal"]/dt[starts-with(.,"Status")]/following-sibling::dd[1]'), + 'Ongoing', + 'Completed'); + summary := XPathString('//*[@class="well"]/p'); + for v in XPath('//ul[@class="chapters"]/li/h5') do + begin + chapterLinks.Add(XPathString('a/@href', v)); + chapterName.Add(XPathString('a||": "||em', v)); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//*[@id="all"]/img/@data-src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Komikid'; + RootURL := 'http://www.komikid.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3187264ee..7fc97a868 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -236,68 +236,66 @@ interface VNSHARING_ID = 3; FAKKU_ID = 4; TRUYEN18_ID = 5; - TRUYENTRANHTUAN_ID = 6; TURKCRAFT_ID = 7; EATMANGA_ID = 8; STARKANA_ID = 9; BLOGTRUYEN_ID = 10; - KOMIKID_ID = 11; - ESMANGAHERE_ID = 12; - ANIMEEXTREMIST_ID = 13; - HUGEMANGA_ID = 14; - S2SCAN_ID = 15; - IMANHUA_ID = 16; - MABUNS_ID = 17; - MANGAESTA_ID = 18; - CENTRALDEMANGAS_ID = 19; - EGSCANS_ID = 20; - MANGAAR_ID = 21; - MANGAAE_ID = 22; - ANIMESTORY_ID = 23; - LECTUREENLIGNE_ID = 24; - SCANMANGA_ID = 25; - MANGAGO_ID = 26; - DM5_ID = 27; - MANGACOW_ID = 28; - KIVMANGA_ID = 29; - MEINMANGA_ID = 30; - MANGASPROJECT_ID = 31; - MANGAREADER_POR_ID = 32; - NINEMANGA_ID = 33; - NINEMANGA_ES_ID = 34; - NINEMANGA_CN_ID = 35; - NINEMANGA_RU_ID = 36; - NINEMANGA_DE_ID = 37; - NINEMANGA_IT_ID = 38; - NINEMANGA_BR_ID = 39; - JAPANSHIN_ID = 40; - JAPSCAN_ID = 41; - CENTRUMMANGI_PL_ID = 42; - MANGALIB_PL_ID = 43; - ONEMANGA_ID = 44; - MANGATOWN_ID = 45; - MANGAOKU_ID = 46; - MYREADINGMANGAINFO_ID = 47; - IKOMIK_ID = 48; - NHENTAI_ID = 49; - MANGAMINT_ID = 50; - UNIXMANGA_ID = 51; - EXTREMEMANGAS_ID = 52; - MANGAHOST_ID = 53; - PORNCOMIX_ID = 54; - PORNCOMIXRE_ID = 55; - PORNCOMIXIC_ID = 56; - XXCOMICS_ID = 57; - XXCOMICSMT_ID = 58; - XXCOMICS3D_ID = 59; - PORNXXXCOMICS_ID = 60; - MANGAKU_ID = 61; - MANGAAT_ID = 62; - READMANGATODAY_ID = 63; - DYNASTYSCANS_ID = 64; - - WebsiteRoots: array [0..64] of array [0..1] of String = ( + ESMANGAHERE_ID = 11; + ANIMEEXTREMIST_ID = 12; + HUGEMANGA_ID = 13; + S2SCAN_ID = 14; + IMANHUA_ID = 15; + MABUNS_ID = 16; + MANGAESTA_ID = 17; + CENTRALDEMANGAS_ID = 18; + EGSCANS_ID = 19; + MANGAAR_ID = 20; + MANGAAE_ID = 21; + ANIMESTORY_ID = 22; + LECTUREENLIGNE_ID = 23; + SCANMANGA_ID = 24; + MANGAGO_ID = 25; + DM5_ID = 26; + MANGACOW_ID = 27; + KIVMANGA_ID = 28; + MEINMANGA_ID = 29; + MANGASPROJECT_ID = 30; + MANGAREADER_POR_ID = 31; + NINEMANGA_ID = 32; + NINEMANGA_ES_ID = 33; + NINEMANGA_CN_ID = 34; + NINEMANGA_RU_ID = 35; + NINEMANGA_DE_ID = 36; + NINEMANGA_IT_ID = 37; + NINEMANGA_BR_ID = 38; + JAPANSHIN_ID = 39; + JAPSCAN_ID = 40; + CENTRUMMANGI_PL_ID = 41; + MANGALIB_PL_ID = 42; + ONEMANGA_ID = 43; + MANGATOWN_ID = 44; + MANGAOKU_ID = 45; + MYREADINGMANGAINFO_ID = 46; + IKOMIK_ID = 47; + NHENTAI_ID = 48; + MANGAMINT_ID = 49; + UNIXMANGA_ID = 50; + EXTREMEMANGAS_ID = 51; + MANGAHOST_ID = 52; + PORNCOMIX_ID = 53; + PORNCOMIXRE_ID = 54; + PORNCOMIXIC_ID = 55; + XXCOMICS_ID = 56; + XXCOMICSMT_ID = 57; + XXCOMICS3D_ID = 58; + PORNXXXCOMICS_ID = 59; + MANGAKU_ID = 60; + MANGAAT_ID = 61; + READMANGATODAY_ID = 62; + DYNASTYSCANS_ID = 63; + + WebsiteRoots: array [0..63] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -309,7 +307,6 @@ interface ('EatManga', 'http://eatmanga.com'), ('Starkana', 'http://starkana.jp'), ('BlogTruyen', 'http://blogtruyen.com'), - ('Komikid', 'http://www.komikid.com'), ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), ('HugeManga', 'http://hugemanga.com'), @@ -397,8 +394,6 @@ interface BLOGTRUYEN_JS_BROWSER = '/ListStory/GetListStory/'; BLOGTRUYEN_POST_FORM = 'Url=tatca&OrderBy=1&PageIndex='; - KOMIKID_BROWSER = '/daftar.php'; - ESMANGAHERE_BROWSER = '/mangalist/'; ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c1b54f3af..dd4bde48b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -965,8 +965,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/TruyenTranhTuan/names_and_links.inc} - {$I includes/Komikid/names_and_links.inc} - {$I includes/Mabuns/names_and_links.inc} {$I includes/MangaEsta/names_and_links.inc} @@ -1105,9 +1103,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else - if WebsiteID = KOMIKID_ID then - Result := KomikidGetNamesAndLinks - else if WebsiteID = MABUNS_ID then Result := MabunsGetNamesAndLinks else @@ -1272,8 +1267,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/TruyenTranhTuan/manga_information.inc} - {$I includes/Komikid/manga_information.inc} - {$I includes/Mabuns/manga_information.inc} {$I includes/MangaEsta/manga_information.inc} @@ -1411,9 +1404,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else - if WebsiteID = KOMIKID_ID then - Result := GetKomikidInfoFromURL - else if WebsiteID = MABUNS_ID then Result := GetMabunsInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4342e9f25..15158f873 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -414,8 +414,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Kivmanga/chapter_page_number.inc} - {$I includes/Komikid/chapter_page_number.inc} - {$I includes/MangaAe/chapter_page_number.inc} {$I includes/MangaAr/chapter_page_number.inc} @@ -508,9 +506,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistPageNumber else - if Task.Container.MangaSiteID = KOMIKID_ID then - Result := GetKomikidPageNumber - else if Task.Container.MangaSiteID = HUGEMANGA_ID then Result := GetHugeMangaPageNumber else @@ -632,8 +627,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Kivmanga/image_url.inc} - {$I includes/Komikid/image_url.inc} - {$I includes/Mabuns/image_url.inc} {$I includes/Manga24h/image_url.inc} @@ -733,9 +726,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else - if Task.Container.MangaSiteID = KOMIKID_ID then - Result := GetKomikidImageURL - else if Task.Container.MangaSiteID = MABUNS_ID then Result := GetMabunsImageURL else From 01659a53b2041824d967fa9fa4b7c5ad2e1d219f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Aug 2016 23:40:51 +0800 Subject: [PATCH 1433/2794] Bump version 0.9.79.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 415956112..955f5ccd1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.79.0 (18-08-2016) +[*] Fixed an error when creating download task +[*] Fixed empty chapters with some website +[*] Komikid: rewrite all code +Full changes: https://github.com/riderkick/FMD/compare/0.9.78.0...0.9.79.0 + 0.9.78.0 (17-08-2016) [*] Fixed various issue with unicode path and filename [*] TripleSevenScan: fixed accept adult warning diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index a6b1f57a9..4fcd36620 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="78"/> + <RevisionNr Value="79"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 03b08d56c..3ce129c0d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.78.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.78.0/fmd_0.9.78.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.78.0/fmd_0.9.78.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.78.0/fmd_0.9.78.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.78.0/fmd_0.9.78.0_Win64.7z +VERSION=0.9.79.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.79.0/fmd_0.9.79.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.79.0/fmd_0.9.79.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.79.0/fmd_0.9.79.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.79.0/fmd_0.9.79.0_Win64.7z From 18d7158477255b921fd90282a816e52b8ccbf0f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 19 Aug 2016 18:31:07 +0800 Subject: [PATCH 1434/2794] tsumino, fixed download fixed #361 --- baseunits/modules/Tsumino.pas | 39 +++++++++++------------------------ 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index 5c0ef2a99..b261c4291 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil,synacode, RegExpr; implementation @@ -92,40 +92,25 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - source: TStringList; - i, pgLast: Integer; - thumbUrl: String; + bookid: String; + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin + bookid := RegExprGetMatch('(?i)/info/(\d+)/?',AURL,1); + Headers.Values['Referer'] := ' ' + Module.RootURL + '/Read/View/' + bookid; + if POST(Module.RootURL + '/Read/Load', 'q=' + bookid) then begin Result := True; - source := TStringList.Create; - try - source.LoadFromStream(Document); - pgLast := 0; - thumbUrl := ''; - if source.Count > 0 then - for i := 0 to source.Count - 1 do begin - if Pos('var pgLast', source[i]) > 0 then - pgLast := StrToIntDef(GetValuesFromString(source[i], '='), 0) - else if Pos('var thumbUrl', source[i]) > 0 then begin - thumbUrl := GetValuesFromString(source[i], '='); - Break; - end; - end; - if (pgLast > 0) and (thumbUrl <> '') then begin - thumbUrl := ReplaceRegExpr('(?i)/Thumb(/\d+/)[9]+', thumbUrl, '/Image$1', True); - thumbUrl := AppendURLDelim(FillHost(Module.RootURL, thumbUrl)); - for i := 1 to pgLast do - PageLinks.Add(thumbUrl + IntToStr(i)); + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('json(*).reader_page_urls()') do + PageLinks.Add(Module.RootURL + '/Image/Object?name=' + EncodeURLElement(v.toString)); + finally + Free; end; - finally - source.Free; - end; end; end; end; From 054eabb79f535990a3d31350eeaa0f617b397469 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Aug 2016 19:47:49 +0800 Subject: [PATCH 1435/2794] Bump version 0.9.80.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 955f5ccd1..102929d96 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.80.0 (20-08-2016) +[*] Tsumino: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.79.0...0.9.80.0 + 0.9.79.0 (18-08-2016) [*] Fixed an error when creating download task [*] Fixed empty chapters with some website diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 4fcd36620..8cdef3301 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="79"/> + <RevisionNr Value="80"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 3ce129c0d..c6f7d7627 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.79.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.79.0/fmd_0.9.79.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.79.0/fmd_0.9.79.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.79.0/fmd_0.9.79.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.79.0/fmd_0.9.79.0_Win64.7z +VERSION=0.9.80.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.80.0/fmd_0.9.80.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.80.0/fmd_0.9.80.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.80.0/fmd_0.9.80.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.80.0/fmd_0.9.80.0_Win64.7z From 8d0d96fdd4e9c4e9254322a650ae055702977993 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Aug 2016 01:21:54 +0800 Subject: [PATCH 1436/2794] mangahere, rewrite all --- baseunits/modules/MangaHere.pas | 173 ++++++++++++-------------------- 1 file changed, 66 insertions(+), 107 deletions(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 615ac380f..bf312589f 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -11,123 +11,90 @@ interface implementation const - dirURL = '/mangalist/'; + dirurl = '/mangalist/'; + imagepath = '//*[@id="viewer"]//img[@id="image"]/@src'; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; v: IXQValue; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + dirURL) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - for v in Query.XPath('//a[@class="manga_info"]') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Query.Free; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//a[@class="manga_info"]') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + finally + Free; + end; end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - Source: TStringList; - Query: TXQueryEngineHTML; - info: TMangaInfo; v: IXQValue; - s: String; begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, AURL)); - Source := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try - with info do begin - coverLink := Query.XPathString('//*[@class="manga_detail"]//img[@class="img"]/@src'); - if title = '' then - title := Query.XPathString('//h1[@class="title"]'); - for v in Query.XPath('//*[@class="detail_topText"]/li') do begin - s := v.toString; - if Pos('Author(s):', s) = 1 then authors := SeparateRight(s, ':') - else if Pos('Artist(s):', s) = 1 then artists := SeparateRight(s, ':') - else if Pos('Genre(s):', s) = 1 then genres := SeparateRight(s, ':') - else if Pos('Status:', s) = 1 then begin - if Pos('Ongoing', s) > 0 then status := '1' - else status := '0'; - end; - end; - summary := Query.XPathString('//*[@class="detail_topText"]/li/p[@id="show"]/text()'); - for v in Query.XPath('//*[@class="detail_list"]/ul/li/span[@class="left"]/a/@href') do - chapterLinks.Add(v.toString); - for v in Query.XPath('//*[@class="detail_list"]/ul/li/span[@class="left"]') do - chapterName.Add(CleanString(v.toString)); - InvertStrings([chapterLinks, chapterName]); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="manga_detail"]//img[@class="img"]/@src')); + if title = '' then title := XPathString('//h1[@class="title"]'); + authors := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Author")]'), ':'); + artists := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Artist")]'), ':'); + genres := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Genre")]'), ':'); + status := MangaInfoStatusIfPos(XPathString( + '//*[@class="detail_topText"]/li[starts-with(.,"Status")]'), + 'Ongoing', + 'Completed'); + summary := XPathString('//*[@class="detail_topText"]/li/p[@id="show"]/text()'); + for v in XPath('//*[@class="detail_list"]/ul/li/span[@class="left"]') do + begin + chapterLinks.Add(XPathString('a/@href', v)); + chapterName.Add(XPathString('string-join((a,span,text()[3])," ")', v)); end; + InvertStrings([chapterLinks, chapterName]); finally - Query.Free; + Free; end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.Task.Container; - with Container do begin - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, AURL)), Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - PageNumber := - Query.XPath('//section[@class="readpage_top"]//span[@class="right"]/select/option').Count; - finally - Query.Free; - end; + with DownloadThread, FHTTP, Task.Container do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('(//span[@class="right"]/select)[1]/option').Count; + PageLinks.Add(XPathString(imagepath)); + finally + Free; end; - finally - Source.Free; end; end; end; @@ -135,32 +102,24 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; - rurl: String; + s: String; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.Task.Container do begin - Source := TStringList.Create; - try - rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if DownloadThread.WorkId > 0 then - rurl += IncStr(DownloadThread.WorkId) + '.html'; - if GetPage(DownloadThread.FHTTP, TObject(Source), rurl, Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Query := TXQueryEngineHTML.Create(Source.Text); - try - PageLinks[DownloadThread.WorkId] := - Query.XPathString('//*[@id="viewer"]//img[@id="image"]/@src'); - finally - Query.Free; - end; + with DownloadThread, FHTTP, Task.Container do + begin + s := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if WorkId > 0 then + s := s + IncStr(WorkId) + '.html'; + if GET(s) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[WorkId] := XPathString(imagepath); + finally + Free; end; - finally - Source.Free; end; end; end; From ec198e1fd4a3c69477fd13484ba9cfdf9978c79b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Aug 2016 14:52:10 +0800 Subject: [PATCH 1437/2794] downloadmanager, reformat status --- baseunits/uDownloadsManager.pas | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 15158f873..85ab659cd 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -956,7 +956,10 @@ function TDownloadThread.DownloadImage: Boolean; if not ForceDirectoriesUTF8(Task.CurrentWorkingDir) then begin Task.Container.Status := STATUS_FAILED; - Task.Container.DownloadInfo.Status := RS_FailedToCreateDir; + Task.Container.DownloadInfo.Status := Format('[%d/%d] %s', [ + Task.Container.CurrentDownloadChapterPtr, + Task.Container.ChapterLinks.Count, + RS_FailedToCreateDir]); Result := False; Exit; end; @@ -1193,7 +1196,10 @@ procedure TTaskThread.Execute; begin Logger.SendError(Format('Failed to create dir(%d) = %s', [Length(CurrentWorkingDir), CurrentWorkingDir])); Container.Status := STATUS_FAILED; - Container.DownloadInfo.Status := RS_FailedToCreateDir; + Container.DownloadInfo.Status := Format('[%d/%d] %s', [ + Container.CurrentDownloadChapterPtr, + Container.ChapterLinks.Count, + RS_FailedToCreateDir]); SyncShowBaloon; Exit; end; @@ -1363,7 +1369,10 @@ procedure TTaskThread.Execute; if Container.FailedChapterLinks.Count > 0 then begin Container.Status := STATUS_FAILED; - Container.DownloadInfo.Status := RS_FailedTryResumeTask; + Container.DownloadInfo.Status := Format('[%d/%d] %s', [ + Container.CurrentDownloadChapterPtr, + Container.ChapterLinks.Count, + RS_FailedTryResumeTask]); Container.DownloadInfo.Progress := ''; Container.CurrentDownloadChapterPtr := 0; From f641620e7ec0663df1003d43a9b62ebec6e834d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Aug 2016 15:30:32 +0800 Subject: [PATCH 1438/2794] tumangaonline, fixed chapters url and download fixed #363 --- baseunits/modules/Tumangaonline.pas | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index f3e528bfb..df5b0485b 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -65,9 +65,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - v, x: IXQValue; - mangaid, purl: String; - s, cl, cn, vs: String; + v: IXQValue; + s, mangaid, purl: String; p, i: Integer; begin Result := NET_PROBLEM; @@ -109,18 +108,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; Break; for v in XPath('json(*).data()') do begin - cl := apiurlimagenes + XPathString('string-join(("?idManga=",idTomo,"&numeroCapitulo=",numCapitulo),"")', v); - vs := '&visto=' + XPathString('visto', v); - cn := Trim(XPathString('string-join((numCapitulo,nombre)," ")', v)); - if RightStr(cn, 5) = ' null' then - SetLength(cn, Length(cn) - 5); - for x in XPath('(subidas)()', v) do - begin - chapterLinks.Add(cl + '&idScanlation='+ XPathString('idScan', x) + vs); - s := XPathString('scanlation/nombre', x); - if s <> '' then chapterName.Add(cn + ' [' + s + ']') - else chapterName.Add(s); - end; + chapterLinks.Add(apiurlimagenes + XPathString('"?idManga="||tomo/idManga||"&idScanlation="||subidas/idScan||"&numeroCapitulo="||numCapitulo||"&visto=true"', v)); + chapterName.Add(XPathString('string-join((numCapitulo,nombre)," ")', v)); end; end; InvertStrings([chapterLinks, chapterName]); @@ -150,7 +139,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String with TXQueryEngineHTML.Create(Document) do try s := imgurl + '/subidas/' + - XPathString('json(*)/concat(capitulo/idTomo,"/",capitulo/numCapitulo,"/",idScan)') + '/'; + XPathString('json(*)/string-join((capitulo/tomo/idManga,capitulo/numCapitulo,idScan),"/")') + '/'; for v in XPath('json((json(*).imagenes))()') do PageLinks.Add(s + v.toString); finally From 8cf6ba207106fdd862b819fb9b8843e4a408b86a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Aug 2016 15:42:17 +0800 Subject: [PATCH 1439/2794] Bump version 0.9.81.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 102929d96..612e138b7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.81.0 (21-08-2016) +[*] Tumangaonline: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.80.0...0.9.81.0 + 0.9.80.0 (20-08-2016) [*] Tsumino: fixed download Full changes: https://github.com/riderkick/FMD/compare/0.9.79.0...0.9.80.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8cdef3301..aab2f61df 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="80"/> + <RevisionNr Value="81"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index c6f7d7627..99bee0656 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.80.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.80.0/fmd_0.9.80.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.80.0/fmd_0.9.80.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.80.0/fmd_0.9.80.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.80.0/fmd_0.9.80.0_Win64.7z +VERSION=0.9.81.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.81.0/fmd_0.9.81.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.81.0/fmd_0.9.81.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.81.0/fmd_0.9.81.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.81.0/fmd_0.9.81.0_Win64.7z From 6143dd38759baa99902a67f8ff2c1e904033bd0e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Aug 2016 02:45:38 +0800 Subject: [PATCH 1440/2794] changed some ui component properties --- mangadownloader/forms/frmCustomColor.lfm | 7 +++++-- mangadownloader/forms/frmCustomColor.lrj | 1 + mangadownloader/forms/frmCustomColor.pas | 3 +++ mangadownloader/forms/frmMain.lfm | 4 ++-- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/languages/fmd.en.po | 8 ++++++++ mangadownloader/languages/fmd.id_ID.po | 8 ++++++++ mangadownloader/languages/fmd.po | 8 ++++++++ 8 files changed, 36 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmCustomColor.lfm b/mangadownloader/forms/frmCustomColor.lfm index 79e4e8fd8..f5766077d 100644 --- a/mangadownloader/forms/frmCustomColor.lfm +++ b/mangadownloader/forms/frmCustomColor.lfm @@ -10,7 +10,6 @@ object CustomColorForm: TCustomColorForm ClientWidth = 535 OnCreate = FormCreate LCLVersion = '1.7' - Visible = False object CBColors: TColorBox AnchorSideRight.Control = btColors Left = 363 @@ -66,12 +65,13 @@ object CustomColorForm: TCustomColorForm Colors.SelectionRectangleBorderColor = clHotLight Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' - Header.AutoSizeIndex = 0 + Header.AutoSizeIndex = -1 Header.Columns = <> Header.DefaultHeight = 17 Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] OnBeforeCellPaint = VTBasicListBeforeCellPaint @@ -103,6 +103,7 @@ object CustomColorForm: TCustomColorForm Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] OnBeforeCellPaint = VTBasicListBeforeCellPaint @@ -134,6 +135,7 @@ object CustomColorForm: TCustomColorForm Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] OnBeforeCellPaint = VTBasicListBeforeCellPaint @@ -165,6 +167,7 @@ object CustomColorForm: TCustomColorForm Header.MainColumn = -1 TabOrder = 0 TextMargin = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] OnBeforeCellPaint = VTBasicListBeforeCellPaint diff --git a/mangadownloader/forms/frmCustomColor.lrj b/mangadownloader/forms/frmCustomColor.lrj index 21b8ce672..5cd228657 100644 --- a/mangadownloader/forms/frmCustomColor.lrj +++ b/mangadownloader/forms/frmCustomColor.lrj @@ -1,4 +1,5 @@ {"version":1,"strings":[ +{"hash":164667949,"name":"tcustomcolorform.caption","sourcebytes":[67,117,115,116,111,109,67,111,108,111,114,70,111,114,109],"value":"CustomColorForm"}, {"hash":257144884,"name":"tcustomcolorform.tsbasiclist.caption","sourcebytes":[66,97,115,105,99,32,108,105,115,116],"value":"Basic list"}, {"hash":221522148,"name":"tcustomcolorform.tsmangalist.caption","sourcebytes":[77,97,110,103,97,32,108,105,115,116],"value":"Manga list"}, {"hash":117201380,"name":"tcustomcolorform.tsfavoritelist.caption","sourcebytes":[70,97,118,111,114,105,116,101,32,108,105,115,116],"value":"Favorite list"}, diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 9c6477da7..663f1a37b 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -484,6 +484,9 @@ procedure TVTApplyList.InstallCustomColors(Index: Integer); LineStyle := lsSolid; if Color = clDefault then Color := clWindow; + LineStyle:=lsDotted; + Header.Options:=Header.Options+[hoHotTrack]; + TreeOptions.PaintOptions:=TreeOptions.PaintOptions+[toUseExplorerTheme,toHotTrack]; // save original event PaintText := OnPaintText; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f9b83b8ac..335b29c7d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - Visible = False + LCLVersion = '1.7' object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -513,7 +513,7 @@ object MainForm: TMainForm TabOrder = 0 TextMargin = 0 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = clbChapterListBeforeCellPaint diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 24adb47bc..b5d492e99 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -1,4 +1,5 @@ {"version":1,"strings":[ +{"hash":57972706,"name":"tmainform.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Free Manga Downloader"}, {"hash":240327891,"name":"tmainform.tsdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, {"hash":5473489,"name":"tmainform.vtdownload.header.columns[0].text","sourcebytes":[77,97,110,103,97],"value":"Manga"}, {"hash":95062979,"name":"tmainform.vtdownload.header.columns[1].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index ba033d609..5933f6e7e 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -415,6 +415,10 @@ msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Password" +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + #: tcustomcolorform.tsbasiclist.caption msgid "Basic list" msgstr "Basic list" @@ -563,6 +567,10 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 23837c61c..0a7dd844c 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -407,6 +407,10 @@ msgctxt "taccountsetform.label3.caption" msgid "Password" msgstr "Kata kunci" +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + #: tcustomcolorform.tsbasiclist.caption msgid "Basic list" msgstr "Semua daftar" @@ -554,6 +558,10 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 9424803dd..a01e2c80a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -372,6 +372,10 @@ msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" msgid "Password" msgstr "" +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "" + #: tcustomcolorform.tsbasiclist.caption msgid "Basic list" msgstr "" @@ -519,6 +523,10 @@ msgstr "" msgid "Visit my blog" msgstr "" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From dc6bf6f8b3d1125b1a610e6a0e7d3c50a2e82dd2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Aug 2016 03:20:00 +0800 Subject: [PATCH 1441/2794] changed default focusedselectiontextcolor to clwindowtext --- mangadownloader/forms/frmCustomColor.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 663f1a37b..fe3658753 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -173,7 +173,7 @@ procedure DoInit; Add('UnfocusedSelectionColor', clBtnFace); Add('UnfocusedSelectionBorderColor', clBtnShadow); Add('NormalTextColor', clWindowText); - Add('FocusedSelectionTextColor', clHighlightText); + Add('FocusedSelectionTextColor', clWindowText); Add('UnfocusedSelectionTextColor', clWindowText); Add('OddColor', CL_BSOdd); Add('EvenColor', CL_BSEven); From a744d445af4120e5f3469e09f8880bd53282fbe0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Aug 2016 00:59:19 +0800 Subject: [PATCH 1442/2794] added mangaonlineto --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MangaOnlineTo.pas | 113 ++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaOnlineTo.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index d07720ac6..a0128e0c3 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -48,4 +48,5 @@ uses MangaIndo, FunManga, SundayWebry, - Komikid; + Komikid, + MangaOnlineTo; diff --git a/baseunits/modules/MangaOnlineTo.pas b/baseunits/modules/MangaOnlineTo.pas new file mode 100644 index 000000000..f7ccad2a1 --- /dev/null +++ b/baseunits/modules/MangaOnlineTo.pas @@ -0,0 +1,113 @@ +unit MangaOnlineTo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread; + +implementation + +const + dirurl = '/manga-list.html'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="content-l"]//li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('text()[last()]', v)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="image-info"]/img/@src')); + if title = '' then title := XPathString('//div[@class="info"]/h2/text()[last()]'); + authors := XPathString('//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Author")]/following-sibling::*'); + artists := XPathString('//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Artist")]/following-sibling::*'); + genres := XPathString('//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Genre")]/string-join(following-sibling::*//a,", ")'); + status := MangaInfoStatusIfPos(XPathString( + '//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Status")]/following-sibling::*'), + 'Ongoing', + 'Completed'); + summary := XPathString('//div[@class="info"]/div[@class="row-info"]/p[starts-with(.,"Plot Summary")]/following-sibling::p/text()'); + for v in XPath('//div[@class="list-chapter"]//li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('string-join(text(),"")', v)); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//*[@id="list-img"]/img/@src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaOnlineTo'; + RootURL := 'http://mangaonline.to'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 1fadb4024..55d65a301 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 5fd3902a646b652b9b35e56fa11ebc9eb1f078bf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Aug 2016 01:10:04 +0800 Subject: [PATCH 1443/2794] Bump version 0.9.82.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 612e138b7..7ecf79584 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.82.0 (28-08-2016) +[+] Added MangaOnlineTo[EN] +Full changes: https://github.com/riderkick/FMD/compare/0.9.81.0...0.9.82.0 + 0.9.81.0 (21-08-2016) [*] Tumangaonline: fixed download Full changes: https://github.com/riderkick/FMD/compare/0.9.80.0...0.9.81.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index aab2f61df..f8caf760f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="81"/> + <RevisionNr Value="82"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 99bee0656..db30485d4 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.81.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.81.0/fmd_0.9.81.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.81.0/fmd_0.9.81.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.81.0/fmd_0.9.81.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.81.0/fmd_0.9.81.0_Win64.7z +VERSION=0.9.82.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.82.0/fmd_0.9.82.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.82.0/fmd_0.9.82.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.82.0/fmd_0.9.82.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.82.0/fmd_0.9.82.0_Win64.7z From 51fbd5296a19302239ac81988fd1f75dae4a7d93 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 4 Sep 2016 21:50:15 +0800 Subject: [PATCH 1444/2794] fixed png to pdf, ignore bit depth, always extracted to 8 bit per channel fixed #369 --- baseunits/Img2Pdf.pas | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 37c0782c1..a7920f604 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -251,9 +251,7 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); IMG.LoadFromStream(AFS, RDR); PageInfo.Filter := 'FlateDecode'; - PageInfo.BitsPerComponent := RDR.Header.BitDepth; - if PageInfo.BitsPerComponent > 8 then - PageInfo.BitsPerComponent := 8; + PageInfo.BitsPerComponent := 8; AMS := TMemoryStreamUTF8.Create; try From 952a7a4e5e3657665aac89680c14a1e135dd2d4c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Sep 2016 08:25:28 +0800 Subject: [PATCH 1445/2794] hentai2read, fixed mangainfo --- baseunits/modules/Hentai2Read.pas | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 7a1335cfc..d82e659fa 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -54,7 +54,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks for v in XPath('//*[@class="img-overlay text-center"]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + ANames.Add(XPathString('h2/@data-title', v)); end; finally Free; @@ -79,13 +79,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//img[@class="img-responsive border-black-op"]/@src'); - if coverLink <> '' then - coverLink := TrimLeftChar(coverLink, ['/']); - if coverlink <> '' then - coverLink := MaybeFillHost(cdnurl, coverLink); - if title = '' then - title := XPathString('//h3/a/text()'); + coverLink := MaybeFillHost(cdnurl, XPathString('//img[@class="img-responsive border-black-op"]/@src')); + title := XPathString('//title/substring-before(.," Hentai - Read ")'); authors := XPathStringAll( '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Author")]/*[position()>1]', ['-']); @@ -108,7 +103,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; for v in XPath('//ul[starts-with(@class,"nav-chapters")]/li/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathString('text()', v.toNode)); + chapterName.Add(XPathString('string-join(text()," ")', v.toNode)); end; InvertStrings([chapterLinks, chapterName]); finally From 295d85a62d636e43d8e1d0f191df5148686d7df0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Sep 2016 21:36:32 +0800 Subject: [PATCH 1446/2794] added mymangame closed #370 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MyMangaMe.pas | 160 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MyMangaMe.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a0128e0c3..70a3c055d 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -49,4 +49,5 @@ uses FunManga, SundayWebry, Komikid, - MangaOnlineTo; + MangaOnlineTo, + MyMangaMe; diff --git a/baseunits/modules/MyMangaMe.pas b/baseunits/modules/MyMangaMe.pas new file mode 100644 index 000000000..49cd14840 --- /dev/null +++ b/baseunits/modules/MyMangaMe.pas @@ -0,0 +1,160 @@ +unit MyMangaMe; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread; + +implementation + +const + dirurl = '/manga-directory/'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//script[contains(.,"totalPages")]/substring-before(substring-after(.,"totalPages: "),",")'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + s := Module.RootURL + dirurl; + if AURL <> '0' then + s := s + 'all/az/' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="manga-hover-wrapper"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('div[@class="manga-details directory"]', v)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="manga-cover"]//img/@src')); + if title = '' then title := XPathString('//h1'); + v := XPath('//div[@class="manga-data"]'); + authors := XPathString('b[starts-with(.,"Author:")]/following-sibling::text()[1]', v); + artists := XPathString('b[starts-with(.,"Artist:")]/following-sibling::text()[1]', v); + genres := XPathString('b[starts-with(.,"Genre:")]/string-join(following-sibling::a[preceding::b[1][starts-with(.,"Genre:")]],", ")', v); + status := MangaInfoStatusIfPos(XPathString( + 'b[starts-with(.,"Status:")]/following-sibling::text()[1]', v), + 'Ongoing', + 'Completed'); + summary := XPathStringAll('b[starts-with(.,"Sypnosis:")]/following-sibling::text()[preceding::b[1][[starts-with(.,"Sypnosis:")]]]', LineEnding, v); + for v in XPath('//section[@class="section-chapter"]/div/div[@class="row"]//a') do + begin + s := v.toNode.getAttribute('href'); + if RightStr(s, 2) = '/1' then + SetLength(s, Length(s) - 2); + chapterLinks.Add(s); + chapterName.Add(v.toString); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL) + '/1') then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('(//select[@id="page-dropdown"])[1]/option').Count; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread, FHTTP do + if GET(MaybeFillHost(Module.RootURL, AURL) + '/' + IncStr(WorkId)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[WorkId] := XPathString('//script[contains(.,"my_image0.src")]/substring-before(substring-after(.,"my_image0.src = ''"),"'';")'); + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MyMangaMe'; + RootURL := 'http://mymanga.me'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 55d65a301..c3954a121 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 43d9bec7f443edb19ed4082fb665944e70f8c3fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Sep 2016 22:30:13 +0800 Subject: [PATCH 1447/2794] Bump version 0.9.83.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7ecf79584..fc3b001e3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.83.0 (06-09-2016) +[*] Fixed an issue when saving to pdf +[*] Hentai2Read: fixed manga info +[+] Added MyMangaMe[EN] +Full changes: https://github.com/riderkick/FMD/compare/0.9.82.0...0.9.83.0 + 0.9.82.0 (28-08-2016) [+] Added MangaOnlineTo[EN] Full changes: https://github.com/riderkick/FMD/compare/0.9.81.0...0.9.82.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f8caf760f..5643ee7e7 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="82"/> + <RevisionNr Value="83"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index db30485d4..261794f78 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.82.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.82.0/fmd_0.9.82.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.82.0/fmd_0.9.82.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.82.0/fmd_0.9.82.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.82.0/fmd_0.9.82.0_Win64.7z +VERSION=0.9.83.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.83.0/fmd_0.9.83.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.83.0/fmd_0.9.83.0_Win64.7z From 58c1935ad26663abf80ea8e5ea256e522e4034f3 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sat, 12 Nov 2016 14:43:32 +0530 Subject: [PATCH 1448/2794] Add Tonari no Young Jump, Comico Added Tonari no Young Jump and Comico as Raw Official Sites --- baseunits/ModuleList.inc | 2 + baseunits/modules/Comico.pas | 187 ++++++++++++++++++++++++ baseunits/modules/TonarinoYoungJump.pas | 113 ++++++++++++++ config/mangalist.ini | 2 +- 4 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Comico.pas create mode 100644 baseunits/modules/TonarinoYoungJump.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 70a3c055d..e40f9180d 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -48,6 +48,8 @@ uses MangaIndo, FunManga, SundayWebry, + TonarinoYoungJump, + Comico, Komikid, MangaOnlineTo, MyMangaMe; diff --git a/baseunits/modules/Comico.pas b/baseunits/modules/Comico.pas new file mode 100644 index 000000000..a5040091a --- /dev/null +++ b/baseunits/modules/Comico.pas @@ -0,0 +1,187 @@ +unit Comico; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil,Dialogs; + +implementation + +const + dirurl = '/official'; + +// Get Series Name +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//p[@itemprop="name"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; +// Get Chapter List +function GetChapterPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; + url: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if MangaInfo.FHTTP.GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//*[@class="m-pager__item"]/a[last()-1]'), 1); + finally + Free; + end; + end; +end; + +// Get Series Info +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; + p, i: Integer; + new_url: String; + + procedure getchapters; + var + v: IXQValue; + begin + for v in query.XPath('//a[@class="m-thumb-episode__inner"]') do begin + MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); + MangaInfo.mangaInfo.chapterName.Add(v.toString); + end; + end; + + procedure getp; + begin + p := StrToIntDef(SeparateRight(query.XPathString('//ul[@class="m-pager__list"]/li[last()]/a/@href'), '&page='), 1); + end; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(Document); + with query do + try + coverLink := XPathString('//*[@class="m-title-hero m-title-hero__line o-mt-30"]@style/@background-image'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1[@class="m-title-hero__title--manga"]'); + status := MangaInfoStatusIfPos( + XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), + 'Ongoing', + 'Complete'); + artists := XPathStringAll('//a[itemprop="author"]/a'); + authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); + summary := XPathString('//div[@class="m-title-hero__description"]'); + getchapters; + getp; + if p > 1 then begin + i := 2; + while (i <= p) and (Thread.IsTerminated = False) do begin + new_url := url + '&page=' + IntToStr(i); + if GET(new_url) then begin + ParseHTML(Document); + getchapters; + getp; + end; + Inc(i); + end; + end; + InvertStrings([chapterLinks, chapterName]); + Reset; + Headers.Values['Referer'] := ' ' + url; + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; + ViewerURL: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//img[@itemprop="primaryImageOfPage"]') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container do + if CurrentDownloadChapterPtr < ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer'] := + ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + Result := True; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Comico'; + RootURL := 'http://www.comico.jp'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonarinoYoungJump.pas new file mode 100644 index 000000000..c28c06ddd --- /dev/null +++ b/baseunits/modules/TonarinoYoungJump.pas @@ -0,0 +1,113 @@ +unit TonariNoYoungJump; + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr, Dialogs; + +implementation + +const + dirurl = '/comics/'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="manga-list__list"]/li/h4/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s, n: String; + v: IXQValue; + i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="fancybox a-alpha"]/img/@src')); + if title = '' then title := XPathString('//strong'); + summary := XPathString('//*[@class="single-story"]/p'); + { there is no chapter list? + assuming the first chapter link in manga info is always the last chapters } + for v in XPath('//a[@class="single"]') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; + ViewerURL: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do + begin + PageLinks.Clear; + PageNumber := 0; + ViewerURL := 'http://viewer.tonarinoyj.jp'; + if GET(FillHost(ViewerURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//img[@class="js-page-image"]') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'TonarinoYoungJump'; + RootURL := 'http://www.tonarinoyj.jp'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index c3954a121..e00b20767 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -13,7 +13,7 @@ Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,Pecinta Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint,RawSenManga,RawYoManga,SundayWebry +Raw=MangaMint,RawSenManga,RawYoManga,SundayWebry,Comico,TonarinoYoungJump Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub From 76867ec0be123f9e2efd02a176734d343de90435 Mon Sep 17 00:00:00 2001 From: Brandan White <tom.chris.hanks@gmail.com> Date: Sun, 11 Dec 2016 21:10:47 +0530 Subject: [PATCH 1449/2794] Update MangaTown Image url --- baseunits/includes/MangaTown/image_url.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index 16ea09d1a..c2451f013 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -28,7 +28,7 @@ begin for i := 0 to parse.Count - 1 do begin - if (Pos('<img', parse[i]) > 0) and (Pos('onerror=', parse[i]) > 0) then + if (Pos('<img', parse[i]) > 0) and (Pos('alt=', parse[i]) > 0) then begin Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); Break; From 2dd9710103abe521205a72c414dbc6d25c0acbeb Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sun, 11 Dec 2016 21:51:46 +0530 Subject: [PATCH 1450/2794] Add NewType and fixed Sunday Web Every Add NewType and fixed Sunday Web Every --- 3rd/BESEN | 1 - 3rd/BESENPkg.lpk | 428 ------------------ 3rd/BESENPkg.pas | 57 +-- baseunits/ModuleList.inc | 11 +- baseunits/httpsendthread.pas | 2 +- baseunits/modules/MangaLife.pas | 18 +- baseunits/modules/NewType.pas | 137 ++++++ .../{SundayWebry.pas => SundayWebEvery.pas} | 48 +- baseunits/modules/YoungAceUp.pas | 113 +++++ baseunits/uBaseUnit.pas | 4 +- baseunits/uData.pas | 6 +- config/mangalist.ini | 2 +- mangadownloader/md.lpi | 4 +- 13 files changed, 321 insertions(+), 510 deletions(-) delete mode 160000 3rd/BESEN delete mode 100644 3rd/BESENPkg.lpk create mode 100644 baseunits/modules/NewType.pas rename baseunits/modules/{SundayWebry.pas => SundayWebEvery.pas} (77%) create mode 100644 baseunits/modules/YoungAceUp.pas diff --git a/3rd/BESEN b/3rd/BESEN deleted file mode 160000 index 9af50070a..000000000 --- a/3rd/BESEN +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9af50070a2625306ae5084c0af7328ee374a6856 diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk deleted file mode 100644 index 4e9d56eec..000000000 --- a/3rd/BESENPkg.lpk +++ /dev/null @@ -1,428 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<CONFIG> - <Package Version="4"> - <PathDelim Value="\"/> - <Name Value="BESENPkg"/> - <CompilerOptions> - <Version Value="11"/> - <PathDelim Value="\"/> - <SearchPaths> - <IncludeFiles Value="BESEN\src"/> - <OtherUnitFiles Value="BESEN\src"/> - <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <CodeGeneration> - <SmartLinkUnit Value="True"/> - <Optimizations> - <OptimizationLevel Value="3"/> - </Optimizations> - </CodeGeneration> - <Linking> - <Debugging> - <GenerateDebugInfo Value="False"/> - </Debugging> - </Linking> - </CompilerOptions> - <Files Count="97"> - <Item1> - <Filename Value="BESEN\src\BESEN.inc"/> - <Type Value="Include"/> - </Item1> - <Item2> - <Filename Value="BESEN\src\BESEN.pas"/> - <UnitName Value="BESEN"/> - </Item2> - <Item3> - <Filename Value="BESEN\src\BESENArrayUtils.pas"/> - <UnitName Value="BESENArrayUtils"/> - </Item3> - <Item4> - <Filename Value="BESEN\src\BESENASTNodes.pas"/> - <UnitName Value="BESENASTNodes"/> - </Item4> - <Item5> - <Filename Value="BESEN\src\BESENBaseObject.pas"/> - <UnitName Value="BESENBaseObject"/> - </Item5> - <Item6> - <Filename Value="BESEN\src\BESENCharset.pas"/> - <UnitName Value="BESENCharset"/> - </Item6> - <Item7> - <Filename Value="BESEN\src\BESENCode.pas"/> - <UnitName Value="BESENCode"/> - </Item7> - <Item8> - <Filename Value="BESEN\src\BESENCodeContext.pas"/> - <UnitName Value="BESENCodeContext"/> - </Item8> - <Item9> - <Filename Value="BESEN\src\BESENCodeGeneratorContext.pas"/> - <UnitName Value="BESENCodeGeneratorContext"/> - </Item9> - <Item10> - <Filename Value="BESEN\src\BESENCodeJIT.pas"/> - <UnitName Value="BESENCodeJIT"/> - </Item10> - <Item11> - <Filename Value="BESEN\src\BESENCodeJITx64.pas"/> - <UnitName Value="BESENCodeJITx64"/> - </Item11> - <Item12> - <Filename Value="BESEN\src\BESENCodeJITx86.pas"/> - <UnitName Value="BESENCodeJITx86"/> - </Item12> - <Item13> - <Filename Value="BESEN\src\BESENCodeSnapshot.pas"/> - <UnitName Value="BESENCodeSnapshot"/> - </Item13> - <Item14> - <Filename Value="BESEN\src\BESENCollector.pas"/> - <UnitName Value="BESENCollector"/> - </Item14> - <Item15> - <Filename Value="BESEN\src\BESENCollectorObject.pas"/> - <UnitName Value="BESENCollectorObject"/> - </Item15> - <Item16> - <Filename Value="BESEN\src\BESENCompiler.pas"/> - <UnitName Value="BESENCompiler"/> - </Item16> - <Item17> - <Filename Value="BESEN\src\BESENConstants.pas"/> - <UnitName Value="BESENConstants"/> - </Item17> - <Item18> - <Filename Value="BESEN\src\BESENContext.pas"/> - <UnitName Value="BESENContext"/> - </Item18> - <Item19> - <Filename Value="BESEN\src\BESENDateUtils.pas"/> - <UnitName Value="BESENDateUtils"/> - </Item19> - <Item20> - <Filename Value="BESEN\src\BESENDeclarativeEnvironmentRecord.pas"/> - <UnitName Value="BESENDeclarativeEnvironmentRecord"/> - </Item20> - <Item21> - <Filename Value="BESEN\src\BESENDecompiler.pas"/> - <UnitName Value="BESENDecompiler"/> - </Item21> - <Item22> - <Filename Value="BESEN\src\BESENDoubleList.pas"/> - <UnitName Value="BESENDoubleList"/> - </Item22> - <Item23> - <Filename Value="BESEN\src\BESENEnvironmentRecord.pas"/> - <UnitName Value="BESENEnvironmentRecord"/> - </Item23> - <Item24> - <Filename Value="BESEN\src\BESENErrors.pas"/> - <UnitName Value="BESENErrors"/> - </Item24> - <Item25> - <Filename Value="BESEN\src\BESENEvalCache.pas"/> - <UnitName Value="BESENEvalCache"/> - </Item25> - <Item26> - <Filename Value="BESEN\src\BESENEvalCacheItem.pas"/> - <UnitName Value="BESENEvalCacheItem"/> - </Item26> - <Item27> - <Filename Value="BESEN\src\BESENGarbageCollector.pas"/> - <UnitName Value="BESENGarbageCollector"/> - </Item27> - <Item28> - <Filename Value="BESEN\src\BESENGlobals.pas"/> - <UnitName Value="BESENGlobals"/> - </Item28> - <Item29> - <Filename Value="BESEN\src\BESENHashMap.pas"/> - <UnitName Value="BESENHashMap"/> - </Item29> - <Item30> - <Filename Value="BESEN\src\BESENHashUtils.pas"/> - <UnitName Value="BESENHashUtils"/> - </Item30> - <Item31> - <Filename Value="BESEN\src\BESENInt64SelfBalancedTree.pas"/> - <UnitName Value="BESENInt64SelfBalancedTree"/> - </Item31> - <Item32> - <Filename Value="BESEN\src\BESENIntegerList.pas"/> - <UnitName Value="BESENIntegerList"/> - </Item32> - <Item33> - <Filename Value="BESEN\src\BESENKeyIDManager.pas"/> - <UnitName Value="BESENKeyIDManager"/> - </Item33> - <Item34> - <Filename Value="BESEN\src\BESENLexer.pas"/> - <UnitName Value="BESENLexer"/> - </Item34> - <Item35> - <Filename Value="BESEN\src\BESENLexicalEnvironment.pas"/> - <UnitName Value="BESENLexicalEnvironment"/> - </Item35> - <Item36> - <Filename Value="BESEN\src\BESENLocale.pas"/> - <UnitName Value="BESENLocale"/> - </Item36> - <Item37> - <Filename Value="BESEN\src\BESENNativeCodeMemoryManager.pas"/> - <UnitName Value="BESENNativeCodeMemoryManager"/> - </Item37> - <Item38> - <Filename Value="BESEN\src\BESENNativeObject.pas"/> - <UnitName Value="BESENNativeObject"/> - </Item38> - <Item39> - <Filename Value="BESEN\src\BESENNumberUtils.pas"/> - <UnitName Value="BESENNumberUtils"/> - </Item39> - <Item40> - <Filename Value="BESEN\src\BESENObject.pas"/> - <UnitName Value="BESENObject"/> - </Item40> - <Item41> - <Filename Value="BESEN\src\BESENObjectArgGetterFunction.pas"/> - <UnitName Value="BESENObjectArgGetterFunction"/> - </Item41> - <Item42> - <Filename Value="BESEN\src\BESENObjectArgSetterFunction.pas"/> - <UnitName Value="BESENObjectArgSetterFunction"/> - </Item42> - <Item43> - <Filename Value="BESEN\src\BESENObjectArray.pas"/> - <UnitName Value="BESENObjectArray"/> - </Item43> - <Item44> - <Filename Value="BESEN\src\BESENObjectArrayConstructor.pas"/> - <UnitName Value="BESENObjectArrayConstructor"/> - </Item44> - <Item45> - <Filename Value="BESEN\src\BESENObjectArrayPrototype.pas"/> - <UnitName Value="BESENObjectArrayPrototype"/> - </Item45> - <Item46> - <Filename Value="BESEN\src\BESENObjectBindingFunction.pas"/> - <UnitName Value="BESENObjectBindingFunction"/> - </Item46> - <Item47> - <Filename Value="BESEN\src\BESENObjectBoolean.pas"/> - <UnitName Value="BESENObjectBoolean"/> - </Item47> - <Item48> - <Filename Value="BESEN\src\BESENObjectBooleanConstructor.pas"/> - <UnitName Value="BESENObjectBooleanConstructor"/> - </Item48> - <Item49> - <Filename Value="BESEN\src\BESENObjectBooleanPrototype.pas"/> - <UnitName Value="BESENObjectBooleanPrototype"/> - </Item49> - <Item50> - <Filename Value="BESEN\src\BESENObjectConsole.pas"/> - <UnitName Value="BESENObjectConsole"/> - </Item50> - <Item51> - <Filename Value="BESEN\src\BESENObjectConstructor.pas"/> - <UnitName Value="BESENObjectConstructor"/> - </Item51> - <Item52> - <Filename Value="BESEN\src\BESENObjectDate.pas"/> - <UnitName Value="BESENObjectDate"/> - </Item52> - <Item53> - <Filename Value="BESEN\src\BESENObjectDateConstructor.pas"/> - <UnitName Value="BESENObjectDateConstructor"/> - </Item53> - <Item54> - <Filename Value="BESEN\src\BESENObjectDatePrototype.pas"/> - <UnitName Value="BESENObjectDatePrototype"/> - </Item54> - <Item55> - <Filename Value="BESEN\src\BESENObjectDeclaredFunction.pas"/> - <UnitName Value="BESENObjectDeclaredFunction"/> - </Item55> - <Item56> - <Filename Value="BESEN\src\BESENObjectEnvironmentRecord.pas"/> - <UnitName Value="BESENObjectEnvironmentRecord"/> - </Item56> - <Item57> - <Filename Value="BESEN\src\BESENObjectError.pas"/> - <UnitName Value="BESENObjectError"/> - </Item57> - <Item58> - <Filename Value="BESEN\src\BESENObjectErrorConstructor.pas"/> - <UnitName Value="BESENObjectErrorConstructor"/> - </Item58> - <Item59> - <Filename Value="BESEN\src\BESENObjectErrorPrototype.pas"/> - <UnitName Value="BESENObjectErrorPrototype"/> - </Item59> - <Item60> - <Filename Value="BESEN\src\BESENObjectFunction.pas"/> - <UnitName Value="BESENObjectFunction"/> - </Item60> - <Item61> - <Filename Value="BESEN\src\BESENObjectFunctionArguments.pas"/> - <UnitName Value="BESENObjectFunctionArguments"/> - </Item61> - <Item62> - <Filename Value="BESEN\src\BESENObjectFunctionConstructor.pas"/> - <UnitName Value="BESENObjectFunctionConstructor"/> - </Item62> - <Item63> - <Filename Value="BESEN\src\BESENObjectFunctionPrototype.pas"/> - <UnitName Value="BESENObjectFunctionPrototype"/> - </Item63> - <Item64> - <Filename Value="BESEN\src\BESENObjectGlobal.pas"/> - <UnitName Value="BESENObjectGlobal"/> - </Item64> - <Item65> - <Filename Value="BESEN\src\BESENObjectJSON.pas"/> - <UnitName Value="BESENObjectJSON"/> - </Item65> - <Item66> - <Filename Value="BESEN\src\BESENObjectMath.pas"/> - <UnitName Value="BESENObjectMath"/> - </Item66> - <Item67> - <Filename Value="BESEN\src\BESENObjectNativeFunction.pas"/> - <UnitName Value="BESENObjectNativeFunction"/> - </Item67> - <Item68> - <Filename Value="BESEN\src\BESENObjectNumber.pas"/> - <UnitName Value="BESENObjectNumber"/> - </Item68> - <Item69> - <Filename Value="BESEN\src\BESENObjectNumberConstructor.pas"/> - <UnitName Value="BESENObjectNumberConstructor"/> - </Item69> - <Item70> - <Filename Value="BESEN\src\BESENObjectNumberPrototype.pas"/> - <UnitName Value="BESENObjectNumberPrototype"/> - </Item70> - <Item71> - <Filename Value="BESEN\src\BESENObjectPropertyDescriptor.pas"/> - <UnitName Value="BESENObjectPropertyDescriptor"/> - </Item71> - <Item72> - <Filename Value="BESEN\src\BESENObjectPrototype.pas"/> - <UnitName Value="BESENObjectPrototype"/> - </Item72> - <Item73> - <Filename Value="BESEN\src\BESENObjectRegExp.pas"/> - <UnitName Value="BESENObjectRegExp"/> - </Item73> - <Item74> - <Filename Value="BESEN\src\BESENObjectRegExpConstructor.pas"/> - <UnitName Value="BESENObjectRegExpConstructor"/> - </Item74> - <Item75> - <Filename Value="BESEN\src\BESENObjectRegExpPrototype.pas"/> - <UnitName Value="BESENObjectRegExpPrototype"/> - </Item75> - <Item76> - <Filename Value="BESEN\src\BESENObjectString.pas"/> - <UnitName Value="BESENObjectString"/> - </Item76> - <Item77> - <Filename Value="BESEN\src\BESENObjectStringConstructor.pas"/> - <UnitName Value="BESENObjectStringConstructor"/> - </Item77> - <Item78> - <Filename Value="BESEN\src\BESENObjectStringPrototype.pas"/> - <UnitName Value="BESENObjectStringPrototype"/> - </Item78> - <Item79> - <Filename Value="BESEN\src\BESENObjectThrowTypeErrorFunction.pas"/> - <UnitName Value="BESENObjectThrowTypeErrorFunction"/> - </Item79> - <Item80> - <Filename Value="BESEN\src\BESENOpcodes.pas"/> - <UnitName Value="BESENOpcodes"/> - </Item80> - <Item81> - <Filename Value="BESEN\src\BESENParser.pas"/> - <UnitName Value="BESENParser"/> - </Item81> - <Item82> - <Filename Value="BESEN\src\BESENPointerList.pas"/> - <UnitName Value="BESENPointerList"/> - </Item82> - <Item83> - <Filename Value="BESEN\src\BESENPointerSelfBalancedTree.pas"/> - <UnitName Value="BESENPointerSelfBalancedTree"/> - </Item83> - <Item84> - <Filename Value="BESEN\src\BESENRandomGenerator.pas"/> - <UnitName Value="BESENRandomGenerator"/> - </Item84> - <Item85> - <Filename Value="BESEN\src\BESENRegExp.pas"/> - <UnitName Value="BESENRegExp"/> - </Item85> - <Item86> - <Filename Value="BESEN\src\BESENRegExpCache.pas"/> - <UnitName Value="BESENRegExpCache"/> - </Item86> - <Item87> - <Filename Value="BESEN\src\BESENScope.pas"/> - <UnitName Value="BESENScope"/> - </Item87> - <Item88> - <Filename Value="BESEN\src\BESENSelfBalancedTree.pas"/> - <UnitName Value="BESENSelfBalancedTree"/> - </Item88> - <Item89> - <Filename Value="BESEN\src\BESENStringList.pas"/> - <UnitName Value="BESENStringList"/> - </Item89> - <Item90> - <Filename Value="BESEN\src\BESENStringTree.pas"/> - <UnitName Value="BESENStringTree"/> - </Item90> - <Item91> - <Filename Value="BESEN\src\BESENStringUtils.pas"/> - <UnitName Value="BESENStringUtils"/> - </Item91> - <Item92> - <Filename Value="BESEN\src\BESENTypes.pas"/> - <UnitName Value="BESENTypes"/> - </Item92> - <Item93> - <Filename Value="BESEN\src\BESENUnicodeTables.pas"/> - <UnitName Value="BESENUnicodeTables"/> - </Item93> - <Item94> - <Filename Value="BESEN\src\BESENUtils.pas"/> - <UnitName Value="BESENUtils"/> - </Item94> - <Item95> - <Filename Value="BESEN\src\BESENValue.pas"/> - <UnitName Value="BESENValue"/> - </Item95> - <Item96> - <Filename Value="BESEN\src\BESENValueContainer.pas"/> - <UnitName Value="BESENValueContainer"/> - </Item96> - <Item97> - <Filename Value="BESEN\src\BESENVersionConstants.pas"/> - <UnitName Value="BESENVersionConstants"/> - </Item97> - </Files> - <RequiredPkgs Count="1"> - <Item1> - <PackageName Value="FCL"/> - </Item1> - </RequiredPkgs> - <UsageOptions> - <UnitPath Value="$(PkgOutDir)"/> - </UsageOptions> - <PublishOptions> - <Version Value="2"/> - </PublishOptions> - </Package> -</CONFIG> diff --git a/3rd/BESENPkg.pas b/3rd/BESENPkg.pas index 10ae7944c..f96093a53 100644 --- a/3rd/BESENPkg.pas +++ b/3rd/BESENPkg.pas @@ -4,36 +4,39 @@ unit BESENPkg; -{$warn 5023 off : no warning about unused units} interface uses - BESEN, BESENArrayUtils, BESENASTNodes, BESENBaseObject, BESENCharset, BESENCode, - BESENCodeContext, BESENCodeGeneratorContext, BESENCodeJIT, BESENCodeJITx64, - BESENCodeJITx86, BESENCodeSnapshot, BESENCollector, BESENCollectorObject, - BESENCompiler, BESENConstants, BESENContext, BESENDateUtils, - BESENDeclarativeEnvironmentRecord, BESENDecompiler, BESENDoubleList, - BESENEnvironmentRecord, BESENErrors, BESENEvalCache, BESENEvalCacheItem, - BESENGarbageCollector, BESENGlobals, BESENHashMap, BESENHashUtils, - BESENInt64SelfBalancedTree, BESENIntegerList, BESENKeyIDManager, BESENLexer, - BESENLexicalEnvironment, BESENLocale, BESENNativeCodeMemoryManager, BESENNativeObject, - BESENNumberUtils, BESENObject, BESENObjectArgGetterFunction, - BESENObjectArgSetterFunction, BESENObjectArray, BESENObjectArrayConstructor, - BESENObjectArrayPrototype, BESENObjectBindingFunction, BESENObjectBoolean, - BESENObjectBooleanConstructor, BESENObjectBooleanPrototype, BESENObjectConsole, - BESENObjectConstructor, BESENObjectDate, BESENObjectDateConstructor, - BESENObjectDatePrototype, BESENObjectDeclaredFunction, BESENObjectEnvironmentRecord, - BESENObjectError, BESENObjectErrorConstructor, BESENObjectErrorPrototype, - BESENObjectFunction, BESENObjectFunctionArguments, BESENObjectFunctionConstructor, - BESENObjectFunctionPrototype, BESENObjectGlobal, BESENObjectJSON, BESENObjectMath, - BESENObjectNativeFunction, BESENObjectNumber, BESENObjectNumberConstructor, - BESENObjectNumberPrototype, BESENObjectPropertyDescriptor, BESENObjectPrototype, - BESENObjectRegExp, BESENObjectRegExpConstructor, BESENObjectRegExpPrototype, - BESENObjectString, BESENObjectStringConstructor, BESENObjectStringPrototype, - BESENObjectThrowTypeErrorFunction, BESENOpcodes, BESENParser, BESENPointerList, - BESENPointerSelfBalancedTree, BESENRandomGenerator, BESENRegExp, BESENRegExpCache, - BESENScope, BESENSelfBalancedTree, BESENStringList, BESENStringTree, BESENStringUtils, - BESENTypes, BESENUnicodeTables, BESENUtils, BESENValue, BESENValueContainer, + BESEN, BESENArrayUtils, BESENASTNodes, BESENBaseObject, BESENCharset, + BESENCode, BESENCodeContext, BESENCodeGeneratorContext, BESENCodeJIT, + BESENCodeJITx64, BESENCodeJITx86, BESENCodeSnapshot, BESENCollector, + BESENCollectorObject, BESENCompiler, BESENConstants, BESENContext, + BESENDateUtils, BESENDeclarativeEnvironmentRecord, BESENDecompiler, + BESENDoubleList, BESENEnvironmentRecord, BESENErrors, BESENEvalCache, + BESENEvalCacheItem, BESENGarbageCollector, BESENGlobals, BESENHashMap, + BESENHashUtils, BESENInt64SelfBalancedTree, BESENIntegerList, + BESENKeyIDManager, BESENLexer, BESENLexicalEnvironment, BESENLocale, + BESENNativeCodeMemoryManager, BESENNativeObject, BESENNumberUtils, + BESENObject, BESENObjectArgGetterFunction, BESENObjectArgSetterFunction, + BESENObjectArray, BESENObjectArrayConstructor, BESENObjectArrayPrototype, + BESENObjectBindingFunction, BESENObjectBoolean, + BESENObjectBooleanConstructor, BESENObjectBooleanPrototype, + BESENObjectConsole, BESENObjectConstructor, BESENObjectDate, + BESENObjectDateConstructor, BESENObjectDatePrototype, + BESENObjectDeclaredFunction, BESENObjectEnvironmentRecord, BESENObjectError, + BESENObjectErrorConstructor, BESENObjectErrorPrototype, BESENObjectFunction, + BESENObjectFunctionArguments, BESENObjectFunctionConstructor, + BESENObjectFunctionPrototype, BESENObjectGlobal, BESENObjectJSON, + BESENObjectMath, BESENObjectNativeFunction, BESENObjectNumber, + BESENObjectNumberConstructor, BESENObjectNumberPrototype, + BESENObjectPropertyDescriptor, BESENObjectPrototype, BESENObjectRegExp, + BESENObjectRegExpConstructor, BESENObjectRegExpPrototype, BESENObjectString, + BESENObjectStringConstructor, BESENObjectStringPrototype, + BESENObjectThrowTypeErrorFunction, BESENOpcodes, BESENParser, + BESENPointerList, BESENPointerSelfBalancedTree, BESENRandomGenerator, + BESENRegExp, BESENRegExpCache, BESENScope, BESENSelfBalancedTree, + BESENStringList, BESENStringTree, BESENStringUtils, BESENTypes, + BESENUnicodeTables, BESENUtils, BESENValue, BESENValueContainer, BESENVersionConstants; implementation diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e40f9180d..2871b7a8e 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -47,9 +47,12 @@ uses MangaPark, MangaIndo, FunManga, - SundayWebry, - TonarinoYoungJump, - Comico, Komikid, MangaOnlineTo, - MyMangaMe; + MyMangaMe, + // Raw Official + SundayWebEvery, + TonarinoYoungJump, + YoungAceUp, + NewType, + Comico; diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index f9a558dee..3feff160a 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -286,7 +286,7 @@ procedure THTTPSendThread.SetTimeout(AValue: Integer); begin if FTimeout = AValue then Exit; FTimeout := AValue; - Sock.ConnectionTimeout := FTimeout; + Sock.SocksTimeout := FTimeout; Sock.SetTimeout(FTimeout); end; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index d11c960e8..a9bf27d03 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; + XQueryEngineHTML, httpsendthread, Dialogs; implementation @@ -99,7 +99,7 @@ function GetInfo(const MangaInfo: TMangaInformation; begin url := MaybeFillHost(Module.RootURL, AURL); if (Module = MMangaTraders) and (Pos('?series=', url) <> 0) then - url := Module.RootURL + '/read-online/' + SeparateRight(url, '?series='); + url := Module.RootURL + '/manga/' + SeparateRight(url, '?series='); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -115,7 +115,7 @@ function GetInfo(const MangaInfo: TMangaInformation; genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre:")]'), ':'); summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description:")]'), ':')); if Module.Website = 'MangaTraders' then - v := XPath('//div[@class="well"]/div[@class="row"]/div/a[contains(@href,"/read-online/") and not(@class)]') + v := XPath('//a[@clas="chapterLink list-group-item"]') else begin if Module.Website = 'MangaSee' then @@ -128,10 +128,10 @@ function GetInfo(const MangaInfo: TMangaInformation; begin for i := 1 to v.Count do begin - chapterLinks.Add(fixchapterurl(v.get(i).toNode.getAttribute('href'))); - chapterName.Add(v.get(i).toString); + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); end; - InvertStrings([chapterLinks, chapterName]); + // InvertStrings([chapterLinks, chapterName]); end; finally Free; @@ -179,9 +179,9 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaLife', 'http://manga.life'); - MMangaSee := AddWebsiteModule('MangaSee', 'http://mangasee.co'); - MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.org'); + AddWebsiteModule('MangaLife', 'http://mangalife.org'); + MMangaSee := AddWebsiteModule('MangaSee', 'http://mangaseeonline.net'); + MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.biz'); end; initialization diff --git a/baseunits/modules/NewType.pas b/baseunits/modules/NewType.pas new file mode 100644 index 000000000..cdddf1032 --- /dev/null +++ b/baseunits/modules/NewType.pas @@ -0,0 +1,137 @@ +unit NewType; + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr, Dialogs, fpjson, jsonparser; + +implementation + +const + dirurl = '/contents/'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//li[@class="OblongCard--border"]/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + // h3[@class="OblongCard-title"] + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s, n: String; + v: IXQValue; + last_eps, i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//figure/img/@src')); + if title = '' then title := XPathString('//section[@class="WorkSummary"]/header/h1'); + summary := XPathString('//section[@id="workInfo"]/p'); + { there is no chapter list? + assuming the first chapter link in manga info is always the last chapters } + s := XPathString('//li[@class="ListCard"]/a[1]/@href'); + with TRegExpr.Create do + try + Expression := '^(.+?)(\d+)/?$'; + last_eps := StrToIntDef(Replace(s, '$2', True), 0); + s := Replace(s, '$1', True); + finally + Free; + end; + if (last_eps > 0) and (s <> '') then + for i := 1 to last_eps do + begin + n := Format('%.1d', [i]); + chapterLinks.Add(s + n); + chapterName.Add(n); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; + url,json_url: String; + jData : TJSONData; + jObject : TJSONObject; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do + begin + PageLinks.Clear; + PageNumber := 0; + url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if GET(url) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + + { Read Json } + json_url := XPathString('//div[@class="ViewerContainer"]/@data-url'); + + if GET(Module.RootURL + json_url) then + begin + with TXQueryEngineHTML.Create(Document) do + + for v in XPath('//*') do + showMessage(v.toString); + //PageLinks.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'NewType'; + RootURL := 'https://comic.webnewtype.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/modules/SundayWebry.pas b/baseunits/modules/SundayWebEvery.pas similarity index 77% rename from baseunits/modules/SundayWebry.pas rename to baseunits/modules/SundayWebEvery.pas index 6618b78a4..588db6b9b 100644 --- a/baseunits/modules/SundayWebry.pas +++ b/baseunits/modules/SundayWebEvery.pas @@ -1,12 +1,10 @@ -unit SundayWebry; - -{$mode objfpc}{$H+} +unit SundayWebEvery; interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, RegExpr, Dialogs; implementation @@ -87,7 +85,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; i, j, bi, bv: Integer; key: String; v, x: IXQValue; + data: IXQValue; regx: TRegExpr; + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -122,33 +122,17 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(key + 'episode.json') then begin with TXQueryEngineHTML.Create(Document) do - try - { h1536, h128, h1024 - the available res is varie for every page/image, some only had h1024 - try to get the biggest available } - regx.Expression := '^.*-h(\d+)\.jpe?g'; - for v in XPath('json(*).pages().files') do - begin - x := XPath('*', v); - if x.Count > 0 then - begin - bi := 1; - bv := 0; - for i := 1 to x.Count do - begin - j := StrToIntDef(regx.Replace(x.get(i).toString, '$1', True), 0); - if j > bv then - begin - bv := j; - bi := i; - end; - end; - PageLinks.Add(key + x.get(bi).toString); - end; - end; - finally - Free; - end; + + { h1536, h128, h1024 ++ the available res is varie for every page/image, some only had h1024 ++ try to get the biggest available } + + + for data in XPath('json(*).pages()/files/h1536.jpeg') do + PageLinks.Add(key + data.toString); + + + end; end; regx.Free; @@ -160,7 +144,7 @@ procedure RegisterModule; begin with AddModule do begin - Website := 'SundayWebry'; + Website := 'SundayWebEvery'; RootURL := 'https://www.sunday-webry.com'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/YoungAceUp.pas b/baseunits/modules/YoungAceUp.pas new file mode 100644 index 000000000..afa0563c7 --- /dev/null +++ b/baseunits/modules/YoungAceUp.pas @@ -0,0 +1,113 @@ +unit YoungAceUp; + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr, Dialogs; + +implementation + +const + dirurl = '/comics/'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="manga-list__list"]/li/h4/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s, n: String; + v: IXQValue; + i: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="fancybox a-alpha"]/img/@src')); + if title = '' then title := XPathString('//strong'); + summary := XPathString('//*[@class="single-story"]/p'); + { there is no chapter list? + assuming the first chapter link in manga info is always the last chapters } + for v in XPath('//a[@class="single"]') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; + ViewerURL: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do + begin + PageLinks.Clear; + PageNumber := 0; + ViewerURL := 'http://viewer.tonarinoyj.jp'; + if GET(FillHost(ViewerURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//img[@class="js-page-image"]') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'YoungAceUp'; + RootURL := 'https://web-ace.jp/youngaceup'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7fc97a868..235b57e4e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3040,7 +3040,7 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; begin HTTP := THTTPSend.Create; HTTP.Timeout := DefaultTimeout; - HTTP.Sock.ConnectionTimeout := DefaultTimeout; + // HTTP.Sock.ConnectionTimeout := DefaultTimeout; HTTP.Sock.SetTimeout(DefaultTimeout); end; HTTP.Headers.NameValueSeparator := ':'; @@ -3397,7 +3397,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; begin HTTP := THTTPSend.Create; HTTP.Timeout := DefaultTimeout; - HTTP.Sock.ConnectionTimeout := DefaultTimeout; + // HTTP.Sock.ConnectionTimeout := DefaultTimeout; HTTP.Sock.SetTimeout(DefaultTimeout); end; HTTP.Headers.NameValueSeparator := ':'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index dd4bde48b..8ab568287 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1021,7 +1021,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/OneManga/names_and_links.inc} - {$I includes/MangaTown/names_and_links.inc} + {$I includes/MangaTown/names_and_links.inc} {$I includes/MangaOku/names_and_links.inc} @@ -1172,7 +1172,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = ONEMANGA_ID then Result := OneMangaGetNamesAndLinks else - if WebsiteID = MANGATOWN_ID then + if WebsiteID = MANGATOWN_ID then Result := MangaTownGetNamesAndLinks else if WebsiteID = MANGAOKU_ID then @@ -1311,7 +1311,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/OneManga/manga_information.inc} - {$I includes/MangaTown/manga_information.inc} + {$I includes/MangaTown/manga_information.inc} {$I includes/MangaOku/manga_information.inc} diff --git a/config/mangalist.ini b/config/mangalist.ini index e00b20767..8973d9e93 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -13,7 +13,7 @@ Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,Pecinta Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint,RawSenManga,RawYoManga,SundayWebry,Comico,TonarinoYoungJump +Raw=MangaMint,RawSenManga,RawYoManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5643ee7e7..6746e1919 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -199,10 +199,10 @@ </RunParams> <RequiredPackages Count="8"> <Item1> - <PackageName Value="multiloglaz"/> + <PackageName Value="BESENPkg"/> </Item1> <Item2> - <PackageName Value="BESENPkg"/> + <PackageName Value="multiloglaz"/> </Item2> <Item3> <PackageName Value="laz_synapse"/> From 6d2e7f2dc0be42bea133afb4874849e03aeaab64 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sat, 24 Dec 2016 01:33:18 +0530 Subject: [PATCH 1451/2794] Fix MangaLife,MangaSee,MangaTraders Fix MangaLife,MangaSee,MangaTraders Chapter List --- baseunits/modules/MangaLife.pas | 45 ++++++++------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index a9bf27d03..44ce6b354 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -78,33 +78,21 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; end; end; -function fixchapterurl(const u: string): string; -begin - result:=fixcleanurl(u); - if (pos('&page=1',result)<>0) or - (pos('/page-1',result)<>0) then - setlength(result,length(result)-7); -end; - function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; - i: Integer; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := MaybeFillHost(Module.RootURL, AURL); - if (Module = MMangaTraders) and (Pos('?series=', url) <> 0) then - url := Module.RootURL + '/manga/' + SeparateRight(url, '?series='); + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); if title = '' then title := XPathString('//*[@class="row"]//h1'); authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author:")]'), ':'); artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist:")]'), ':'); @@ -114,24 +102,10 @@ function GetInfo(const MangaInfo: TMangaInformation; 'completed'); genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre:")]'), ':'); summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description:")]'), ':')); - if Module.Website = 'MangaTraders' then - v := XPath('//a[@clas="chapterLink list-group-item"]') - else + for v in XPath('//div[@class="list chapter-list"]/a') do begin - if Module.Website = 'MangaSee' then - s := 'div.col-lg-12:nth-child(8)>div>div:nth-child(1)>a' - else - s := 'div.list>div>div>a'; - v := CSS(s) - end; - if v.Count > 0 then - begin - for i := 1 to v.Count do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - // InvertStrings([chapterLinks, chapterName]); + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); end; finally Free; @@ -142,19 +116,22 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; - if GET(fixchapterurl(MaybeFillHost(Module.RootURL, AURL))) then + if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - XPathStringAll('//p/img/@src', PageLinks); + for v in XPath('//img[@class="CurImage"]') do + PageLinks.Add(v.toNode.getAttribute('src')); finally Free; end; From 8923863d32341412bf74c77406f352a1ad2798eb Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sat, 24 Dec 2016 21:09:05 +0530 Subject: [PATCH 1452/2794] Add PowerManga, Jaiminisbox Added PowerManga, Jaiminisbox. --- baseunits/modules/FoOlSlide.pas | 3 +++ config/mangalist.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 0b341460b..825bb086b 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -40,6 +40,7 @@ function GetDirURL(const AWebsite: String): String; begin if (AWebsite = 'YoManga') or (AWebsite = 'GoManga') or + (AWebsite = 'Jaiminisbox') or (AWebsite = 'TripleSevenScan') then Result := dirurlreader else @@ -260,6 +261,8 @@ procedure RegisterModule; AddWebsiteModule('GoManga', 'http://gomanga.co'); AddWebsiteModule('OneTimeScans', 'http://otscans.com'); AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); + AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com'); + AddWebsiteModule('PowerManga', 'http://read.powermanga.org'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index 8973d9e93..6531849da 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From 4f89458c5c39086cdfa5b3e9b557ddbdebcfd2e5 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sat, 24 Dec 2016 21:10:02 +0530 Subject: [PATCH 1453/2794] Add PoweManga --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 6531849da..ac3f1ed8c 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From b2493166e2b207017f2b8ef258087f859744e4e8 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sun, 25 Dec 2016 21:28:05 +0530 Subject: [PATCH 1454/2794] Fixed NewType --- baseunits/modules/NewType.pas | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/NewType.pas b/baseunits/modules/NewType.pas index cdddf1032..46e609271 100644 --- a/baseunits/modules/NewType.pas +++ b/baseunits/modules/NewType.pas @@ -84,9 +84,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var v: IXQValue; - url,json_url: String; - jData : TJSONData; - jObject : TJSONObject; + url,json_url,s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -108,9 +106,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin with TXQueryEngineHTML.Create(Document) do - for v in XPath('//*') do - showMessage(v.toString); - //PageLinks.Add(v.toString); + s := XPathString('//*'); + if s <> '' then + begin + s := GetBetween('{', '}', s); + ParseHTML(s); + XPathStringAll('json(*)()', PageLinks); + end; end; finally Free; From 28c155f156845a006a838950665899f2c8fcb3b4 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sun, 25 Dec 2016 21:29:24 +0530 Subject: [PATCH 1455/2794] Add Power Manga --- baseunits/modules/FoOlSlide.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 825bb086b..8b78c3e9f 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -250,6 +250,8 @@ procedure RegisterModule; end; begin + AddWebsiteModule('PowerManga', 'http://read.powermanga.org'); + AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); with AddWebsiteModule('YoManga', 'http://yomanga.co') do begin @@ -262,7 +264,6 @@ procedure RegisterModule; AddWebsiteModule('OneTimeScans', 'http://otscans.com'); AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com'); - AddWebsiteModule('PowerManga', 'http://read.powermanga.org'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); From 006c018cd1324d904f7c79e8ddae23d9abca8861 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sun, 25 Dec 2016 22:37:25 +0530 Subject: [PATCH 1456/2794] Add KireiCake and ReadComics, Fixed Madokami Url --- baseunits/ModuleList.inc | 1 + baseunits/modules/FoOlSlide.pas | 5 ++ baseunits/modules/Madokami.pas | 2 +- baseunits/modules/ReadComics.pas | 119 +++++++++++++++++++++++++++++++ baseunits/uBaseUnit.pas | 2 +- config/mangalist.ini | 4 +- 6 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 baseunits/modules/ReadComics.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 2871b7a8e..4bb8906a0 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -50,6 +50,7 @@ uses Komikid, MangaOnlineTo, MyMangaMe, + ReadComics, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 8b78c3e9f..5e503c7b8 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -17,6 +17,7 @@ implementation const dirurl = '/directory/'; dirurlreader = '/reader/directory/'; + dirurlreaderlist = '/reader/list/'; dirurlfoolslide = '/foolslide/directory/'; dirurlslide = '/slide/directory/'; dirurlslideU = '/Slide/directory/'; @@ -44,6 +45,9 @@ function GetDirURL(const AWebsite: String): String; (AWebsite = 'TripleSevenScan') then Result := dirurlreader else + if AWebsite = 'KireiCake' then + Result := dirurlreaderlist + else if AWebsite = 'OneTimeScans' then Result := dirurlfoolslide else @@ -264,6 +268,7 @@ procedure RegisterModule; AddWebsiteModule('OneTimeScans', 'http://otscans.com'); AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com'); + AddWebsiteModule('KireiCake', 'https://reader.kireicake.com'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index b51be6767..2f2b69b9c 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -12,7 +12,7 @@ implementation const modulename = 'Madokami'; - urlroot = 'https://manga.madokami.com'; + urlroot = 'https://manga.madokami.al'; madokamidirlist: array [0..12] of String = ( '/Manga/%23%20-%20F', '/Manga/G%20-%20M', diff --git a/baseunits/modules/ReadComics.pas b/baseunits/modules/ReadComics.pas new file mode 100644 index 000000000..9a934a9af --- /dev/null +++ b/baseunits/modules/ReadComics.pas @@ -0,0 +1,119 @@ +unit ReadComics; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil,Dialogs; + +implementation + +const + dirurl = '/comic-list'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="serie-box"]/li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@id="series_image"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h1[@class="manga-title"]'); + status := MangaInfoStatusIfPos( + XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), + 'Ongoing', + 'Complete'); + artists := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Artist:")]/following-sibling::*[@class="desc"][1]/a'); + authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); + for v in XPath('//ul[@class="basic-list"]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s,url: String; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL))+'full'; + if GET(url) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//img[@class="chapter_img"]') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'ReadComics'; + RootURL := 'http://readcomics.tv'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 235b57e4e..9c62578a5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -342,7 +342,7 @@ interface ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), ('MangaOku', 'http://www.mangaoku.net'), - ('MyReadingMangaInfo', 'http://myreadingmanga.info'), + ('MyReadingMangaInfo', 'https://myreadingmanga.info'), ('I-Komik', 'http://www.i-komik.com'), ('NHentai', 'http://nhentai.net'), ('MangaMint', 'http://www.mangamint.com'), diff --git a/config/mangalist.ini b/config/mangalist.ini index ac3f1ed8c..cd9946a28 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,9 +4,9 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics English-Italian=MangaEden,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From cd96870311f23fe08f8bb5798f851053a617604b Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Mon, 26 Dec 2016 18:55:32 +0530 Subject: [PATCH 1457/2794] Fix MangaFox Chapter List --- baseunits/modules/MangaFox.pas | 35 +++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 13b875223..91c151285 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, MangaFoxWatermark; + XQueryEngineHTML, httpsendthread, MangaFoxWatermark,Dialogs; implementation @@ -40,16 +40,17 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks end; end; -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; + s,chapter_title: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := FillHost(Module.RootURL, AURL); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -62,19 +63,22 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; if RightStr(title, 6) = ' Manga' then SetLength(title, Length(title) - 6); end; + status := MangaInfoStatusIfPos( + XPathString('//div[@id="series_info"]/div[5]/span'), + 'Ongoing', + 'Complete'); authors := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[2]'); artists := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[3]'); genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); summary := XPathString('//p[@class="summary"]'); - for v in XPath('//ul[@class="chlist"]/li') do - begin - s := XPathString('div/*/a[@class="tips"]/@href', v.toNode); - if RightStr(s, 6) = '1.html' then - SetLength(s, Length(s) - 6); - chapterLinks.Add(s); - chapterName.Add(Trim(XPathString('div/*/a[@class="tips"]', v.toNode) + ' ' + - XPathString('div/*/span[@class="title nowrap"]', v.toNode))); - end; + for v in XPath('//div/*/a[@class="tips"]') do + begin + s := v.toNode.getAttribute('href'); + s := StringReplace(s, '1.html', '', [rfReplaceAll]); + chapterLinks.Add(s); + chapter_title := v.toString; + chapterName.Add(chapter_title); + end; InvertStrings([chapterLinks, chapterName]); finally Free; @@ -167,3 +171,4 @@ initialization RegisterModule; end. + From 307fc8c1b141be36e563eb9ca9f85c16c8e5509d Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sat, 31 Dec 2016 18:29:04 +0530 Subject: [PATCH 1458/2794] Removed MangaCow and Added to WPManga Removed MangaCow and moved it to WPManga sites --- baseunits/modules/WPManga.pas | 1 + baseunits/uData.pas | 15 --------------- changelog.txt | 9 +++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index e11b024b2..ea288dfb5 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -310,6 +310,7 @@ procedure RegisterModule; AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); + AddWebsiteModule('MangaCow', 'http://mngcow.co'); end; initialization diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8ab568287..ce68c72a1 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -796,8 +796,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/JapanShin/directory_page_number.inc} - {$I includes/Mangacow/directory_page_number.inc} - {$I includes/OneManga/directory_page_number.inc} {$I includes/MangaTown/directory_page_number.inc} @@ -890,9 +888,6 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St if WebsiteID = JAPANSHIN_ID then Result := GetJapanShinDirectoryPageNumber else - if WebsiteID = MANGACOW_ID then - Result := GetMangaCowDirectoryPageNumber - else if WebsiteID = ONEMANGA_ID then Result := GetOneMangaDirectoryPageNumber else @@ -987,8 +982,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; {$I includes/Turkcraft/names_and_links.inc} - {$I includes/Mangacow/names_and_links.inc} - {$I includes/Starkana/names_and_links.inc} {$I includes/EatManga/names_and_links.inc} @@ -1136,9 +1129,6 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; if WebsiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else - if WebsiteID = MANGACOW_ID then - Result := MangaCowGetNamesAndLinks - else if WebsiteID = KIVMANGA_ID then Result := KivmangaGetNamesAndLinks else @@ -1287,8 +1277,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/CentralDeMangas/manga_information.inc} - {$I includes/Mangacow/manga_information.inc} - {$I includes/BlogTruyen/manga_information.inc} {$I includes/MeinManga/manga_information.inc} @@ -1434,9 +1422,6 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco if WebsiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else - if WebsiteID = MANGACOW_ID then - Result := GetMangaCowInfoFromURL - else if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenInfoFromURL else diff --git a/changelog.txt b/changelog.txt index fc3b001e3..1b12a100a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.84.0 (25-12-2016) +[*] Fixed an issue when saving to pdf +[*] MangaFox: fixed manga info and Status +[*] MangaTown: fixed Image Url +[+] Added Tonari no Young Jump, Comico, NewType and fixed Sunday Web Every[JP] +[+] Added PowerManga, Jaiminisbox, KireiCake and ReadComics[EN] +[*] Fixed Madokami Url +Full changes: https://github.com/riderkick/FMD/compare/0.9.82.0...0.9.83.0 + 0.9.83.0 (06-09-2016) [*] Fixed an issue when saving to pdf [*] Hentai2Read: fixed manga info diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6746e1919..d02bcfbf3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="83"/> + <RevisionNr Value="84"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 261794f78..fdcfa566f 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.83.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.83.0/fmd_0.9.83.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.83.0/fmd_0.9.83.0_Win64.7z +VERSION=0.9.84.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0_Win64.7z/download +WIN32=https://github.com/kavin-90/FMD/releases/download/0.9.84.0/fmd_0.9.84.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.84.0/fmd_0.9.84.0_Win64.7z From 6950508be4fd7dfa3c61ea35bf4a0271500c0168 Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Sat, 31 Dec 2016 18:29:43 +0530 Subject: [PATCH 1459/2794] Removed MangaCow --- .../includes/Mangacow/chapter_page_number.inc | 34 --- .../Mangacow/directory_page_number.inc | 37 ---- baseunits/includes/Mangacow/image_url.inc | 31 --- .../includes/Mangacow/manga_information.inc | 206 ------------------ .../includes/Mangacow/names_and_links.inc | 53 ----- 5 files changed, 361 deletions(-) delete mode 100644 baseunits/includes/Mangacow/chapter_page_number.inc delete mode 100644 baseunits/includes/Mangacow/directory_page_number.inc delete mode 100644 baseunits/includes/Mangacow/image_url.inc delete mode 100644 baseunits/includes/Mangacow/manga_information.inc delete mode 100644 baseunits/includes/Mangacow/names_and_links.inc diff --git a/baseunits/includes/Mangacow/chapter_page_number.inc b/baseunits/includes/Mangacow/chapter_page_number.inc deleted file mode 100644 index 765a6d823..000000000 --- a/baseunits/includes/Mangacow/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetMangaCowPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + '1/'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '^.*\.push\("([^"]+)"\);.*$'; - regx.ModifierI := True; - for i := 0 to parse.Count - 1 do - if Pos('arr_img.push(', parse[i]) > 0 then - Task.Container.PageLinks.Add(regx.Replace(parse[i], '$1', True)); - finally - regx.Free - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Mangacow/directory_page_number.inc b/baseunits/includes/Mangacow/directory_page_number.inc deleted file mode 100644 index 69d42fd6f..000000000 --- a/baseunits/includes/Mangacow/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetMangaCowDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGACOW_ID, 1] + - MANGACOW_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a ', parse[i]) > 0) then - if (Trim(parse[i + 1]) = 'Last') then - if (Pos('</a', parse[i + 2]) > 0) then - begin - Result := NO_ERROR; - Page := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)\/$', - GetVal(parse[i], 'href'), '$1', True), 1); - Break; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Mangacow/image_url.inc b/baseunits/includes/Mangacow/image_url.inc deleted file mode 100644 index 5bd55f65b..000000000 --- a/baseunits/includes/Mangacow/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetMangaCowImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGACOW_ID, URL) + IntToStr(WorkId + 1) + '/'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'style') = 'width:0px; height:0px') then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Mangacow/manga_information.inc b/baseunits/includes/Mangacow/manga_information.inc deleted file mode 100644 index 50d8e99a1..000000000 --- a/baseunits/includes/Mangacow/manga_information.inc +++ /dev/null @@ -1,206 +0,0 @@ - function GetMangaCowInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - isExtractInfo: Boolean = False; - isExtractGenres: Boolean = False; - chapterPage: Cardinal; - begin - mangaInfo.website := WebsiteRoots[MANGACOW_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGACOW_ID, URL); - - if mangaInfo.url[Length(mangaInfo.url)] <> '/' then - mangaInfo.url := mangaInfo.url + '/'; - - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - chapterPage := 0; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse[i]) = 'img') and (GetVal(parse[i], 'class') = 'cvr') then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // get title - if (Pos('<h1 ', parse[i]) > 0) and - (Pos('class="ttl"', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - - // get chapter name and links - if Pos('class="lst"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGACOW_ID, 1], - '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); - mangaInfo.chapterName.Add(s); - end; - - if (Pos('<a ', parse[i]) > 0) and (Pos('/chapter-list/', parse[i]) > 0) then - if Trim(parse[i + 1]) = 'Last' then - chapterPage := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', - GetVal(parse[i], 'href'), '$1', True), 0); - - if (Pos('class="mng_ifo"', parse[i]) > 0) then - isExtractInfo := True; - if isExtractInfo and - (Pos('class="lst mng_chp"', parse[i]) > 0) then - isExtractInfo := False; - - if isExtractInfo then - begin - // get summary - if (Pos('Subscribe', parse[i]) > 0) then - if (Pos('</b>', parse[i + 1]) > 0) then - mangaInfo.summary := - Trim(BreaksString(HTMLEntitiesFilter(StringFilter(parse[i + 12])))); - - // get authors - if (mangaInfo.authors = '') and - (Trim(parse[i]) = 'Author') then - begin - j := i + 1; - while j < parse.Count - 1 do - begin - if Pos('</p', parse[j]) > 0 then - Break; - if Pos('<', parse[j]) = 0 then - begin - if Trim(parse[j]) = ',' then - mangaInfo.authors := mangaInfo.authors + ', ' - else - mangaInfo.authors := mangainfo.authors + Trim(parse[j]); - end; - Inc(j); - end; - mangaInfo.authors := Trim(RemoveStringBreaks(StringFilter(mangaInfo.authors))); - mangaInfo.authors := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.authors), '', False)); - mangaInfo.authors := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.authors), '', False)); - end; - - // get artists - if (mangaInfo.artists = '') and - (Trim(parse[i]) = 'Artist') then - begin - j := i + 1; - while j < parse.Count - 1 do - begin - if Pos('</p', parse[j]) > 0 then - Break; - if Pos('<', parse[j]) = 0 then - begin - if Trim(parse[j]) = ',' then - mangaInfo.artists := mangaInfo.artists + ', ' - else - mangaInfo.artists := mangainfo.artists + Trim(parse[j]); - end; - Inc(j); - end; - mangaInfo.artists := Trim(RemoveStringBreaks(StringFilter(mangaInfo.artists))); - mangaInfo.artists := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.artists), '', False)); - mangaInfo.artists := Trim(ReplaceRegExpr('^[\:|\-]', - Trim(mangaInfo.artists), '', False)); - end; - - // get genres - if (Pos('Category', parse[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('manga-list/category/', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse[i + 1])) + ', '; - if Pos('</p>', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - end; - - // get the rest of chapter list - if chapterPage > 1 then - begin - for j := 2 to chapterPage do - begin - if GetPage(TObject(Source), mangaInfo.url + 'chapter-list/' + - IntToStr(j) + '/', Reconnect) then - begin - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if Pos('class="lst"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MANGACOW_ID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); - mangaInfo.chapterName.Add(s); - end; - end; - end; - end; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/includes/Mangacow/names_and_links.inc b/baseunits/includes/Mangacow/names_and_links.inc deleted file mode 100644 index 448dcf02f..000000000 --- a/baseunits/includes/Mangacow/names_and_links.inc +++ /dev/null @@ -1,53 +0,0 @@ - function MangaCowGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - //if Trim(URL) = '0' then - //s := '' - //else - s := IntToStr(StrToInt(URL) + 1) + '/'; - if not GetPage(TObject(Source), WebsiteRoots[MANGACOW_ID, 1] + - MANGACOW_BROWSER + s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a ', parse[i]) > 0) and (Pos('class="mng_det_pop"', parse[i]) > 0) then - if Pos('<br', parse[i + 3]) > 0 then - begin - Result := NO_ERROR; - s := Trim(HTMLEntitiesFilter(StringFilter(GetVal(parse[i], 'title')))); - names.Add(S); - s := StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[MANGACOW_ID, 1], - '', [rfIgnoreCase]); - links.Add(S); - end; - //if (Pos('class="img_wrp', parse[i]) > 0) then - //begin - // Result:= NO_ERROR; - // s:= StringFilter(GetVal(parse[i+1], 'title')); - // names.Add(HTMLEntitiesFilter(s)); - // s:= StringReplace(GetVal(parse[i+1], 'href'), WebsiteRoots[MANGACOW_ID,1], '', []); - // links.Add(s); - //end; - end; - Source.Free; - end; \ No newline at end of file From e953a5f8f80eeb2f54211cff7bf85ec06a2e3c6e Mon Sep 17 00:00:00 2001 From: Kavin White <tom.chris.hanks@gmail.com> Date: Wed, 4 Jan 2017 00:14:31 +0530 Subject: [PATCH 1460/2794] Upated Changelog --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 1b12a100a..18140745d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,9 +5,9 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.84.0 (25-12-2016) -[*] Fixed an issue when saving to pdf [*] MangaFox: fixed manga info and Status [*] MangaTown: fixed Image Url +[*] Removed MangaCow and Moved to WPManga [+] Added Tonari no Young Jump, Comico, NewType and fixed Sunday Web Every[JP] [+] Added PowerManga, Jaiminisbox, KireiCake and ReadComics[EN] [*] Fixed Madokami Url From ec0d81fa6d7ccfa440d2af82152838899d3da541 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 4 Jan 2017 11:50:30 +0800 Subject: [PATCH 1461/2794] fixed 8muses --- baseunits/modules/EightMuses.pas | 57 +++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index 82a79a828..df33f8bb8 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; + XQueryEngineHTML, httpsendthread, RegExpr; implementation @@ -24,22 +24,34 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//div[@class="holder"]/a/img/@src'); + coverLink := XPathString('//*[@class="gallery"]/a/div/img/@data-src'); + if coverLink <> '' then + coverLink := MaybeFillHost(Module.RootURL, coverLink); if Pos('//', coverLink) = 1 then coverLink := 'https:' + coverLink; if title = '' then - title := XPathString('//ul[@class="breadcrumbs"]/li[last()]'); + title := XPathString('//*[@class="top-menu-breadcrumb"]//li[last()]'); + if ExecRegExpr('^(?i)issue\s\d+', title) then + begin + s := title; + title := XPathString('//*[@class="top-menu-breadcrumb"]//li[last()-1]'); + end; //multi - if XPathString('//div[@class="holder"]/a') <> '' then begin - for v in XPath('//div[@class="holder"]/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - s := v.toString; - if (title <> '') and (Pos('Issue', s) = 1) then s := title + ' ' + s; - chapterName.Add(s); + if XPathString('//*[@class="gallery"]/a') <> '' then begin + for v in XPath('//*[@class="gallery"]/a') do begin + s := v.toNode.getAttribute('href'); + if s <> '' then + begin + chapterLinks.Add(s); + s := v.toString; + if (title <> '') and (Pos('Issue', s) = 1) then + s := title + ' - ' + s; + chapterName.Add(s); + end; end; end else begin chapterLinks.Add(url); - chapterName.Add(title); + chapterName.Add(title + ' - ' + s); end; finally Free; @@ -65,17 +77,19 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String Result := True; with TXQueryEngineHTML.Create(Document) do try - for v in XPath('//div[@class="holder"]/a/img/@src') do + for v in XPath('//*[@class="gallery"]/a/div/img/@data-src') do begin s := v.toString; - if LeftStr(s, 2) = '//' then - s := 'https:' + s; - s := StringReplace(s, '/th/', '/fu/', [rfIgnoreCase]); - PageLinks.Add(s); + if s <> '' then + begin + s := StringReplace(s, '/th/', '/fu/', [rfIgnoreCase]); + s := MaybeFillHost(Module.RootURL, s); + PageLinks.Add(s); + end; end; if PageLinks.Count = 0 then begin - for v in XPath('//div[@class="holder"]/a/@href') do + for v in XPath('//*[@class="gallery"]/a/@href') do PageContainerLinks.Add(v.toString); PageNumber := PageContainerLinks.Count; end; @@ -94,15 +108,18 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + if DownloadThread.WorkId >= PageContainerLinks.Count then Exit; rurl := RemoveURLDelim(FillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkId])); if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - rurl := XPathString('//img[@id="image"]/@src'); - if Pos('//', rurl) = 1 then - rurl := 'https:' + rurl; - PageLinks[DownloadThread.WorkId] := rurl; + rurl := XPathString('string-join((//*[@id="imageDir"]/@value,//*[@id="imageName"]/@value),"")'); + if rurl <> '' then + begin + rurl := MaybeFillHost(Module.RootURL, rurl); + PageLinks[DownloadThread.WorkId] := rurl; + end; finally Free; end; From 02392cea960c1f854d1eda7839c601a2aee0cae8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 4 Jan 2017 12:10:27 +0800 Subject: [PATCH 1462/2794] mangainfostatusifpos default string --- baseunits/uBaseUnit.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7fc97a868..396bb268b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -872,7 +872,8 @@ function JDNToDate(const JDN: Longint): TDate; {function ConvertInt32ToStr(const aValue: Cardinal) : String; function ConvertStrToInt32(const aStr : String): Cardinal;} procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); -function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String): String; +function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String = 'Ongoing'; + const CompletedStr: String = 'Completed'): String; // cross platform funcs @@ -3966,7 +3967,8 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); dest.chapterLinks.Assign(Source.chapterLinks); end; -function MangaInfoStatusIfPos(const SearchStr, OngoingStr, CompletedStr: String): String; +function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String; + const CompletedStr: String): String; var s, o, c: String; begin From 74a3a4a46628bd7119ac06fef6ac974ef58ca725 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 4 Jan 2017 12:11:27 +0800 Subject: [PATCH 1463/2794] mangafox, added status --- baseunits/modules/MangaFox.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 13b875223..e873b961d 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -66,6 +66,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; artists := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[3]'); genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); summary := XPathString('//p[@class="summary"]'); + status := MangaInfoStatusIfPos(XPathString('//div[@id="series_info"]/div[5]/span')); for v in XPath('//ul[@class="chlist"]/li') do begin s := XPathString('div/*/a[@class="tips"]/@href', v.toNode); From 40533c4cc81cc870e49482651d30ed1527827ee7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 4 Jan 2017 14:53:41 +0800 Subject: [PATCH 1464/2794] added back besen as submodule --- 3rd/BESEN | 1 + 3rd/BESENPkg.lpk | 428 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 429 insertions(+) create mode 160000 3rd/BESEN create mode 100644 3rd/BESENPkg.lpk diff --git a/3rd/BESEN b/3rd/BESEN new file mode 160000 index 000000000..bed9b6ccf --- /dev/null +++ b/3rd/BESEN @@ -0,0 +1 @@ +Subproject commit bed9b6ccf3d2986dc80e698c94dd0a63f02ba28f diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk new file mode 100644 index 000000000..4e9d56eec --- /dev/null +++ b/3rd/BESENPkg.lpk @@ -0,0 +1,428 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <PathDelim Value="\"/> + <Name Value="BESENPkg"/> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="BESEN\src"/> + <OtherUnitFiles Value="BESEN\src"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + </Linking> + </CompilerOptions> + <Files Count="97"> + <Item1> + <Filename Value="BESEN\src\BESEN.inc"/> + <Type Value="Include"/> + </Item1> + <Item2> + <Filename Value="BESEN\src\BESEN.pas"/> + <UnitName Value="BESEN"/> + </Item2> + <Item3> + <Filename Value="BESEN\src\BESENArrayUtils.pas"/> + <UnitName Value="BESENArrayUtils"/> + </Item3> + <Item4> + <Filename Value="BESEN\src\BESENASTNodes.pas"/> + <UnitName Value="BESENASTNodes"/> + </Item4> + <Item5> + <Filename Value="BESEN\src\BESENBaseObject.pas"/> + <UnitName Value="BESENBaseObject"/> + </Item5> + <Item6> + <Filename Value="BESEN\src\BESENCharset.pas"/> + <UnitName Value="BESENCharset"/> + </Item6> + <Item7> + <Filename Value="BESEN\src\BESENCode.pas"/> + <UnitName Value="BESENCode"/> + </Item7> + <Item8> + <Filename Value="BESEN\src\BESENCodeContext.pas"/> + <UnitName Value="BESENCodeContext"/> + </Item8> + <Item9> + <Filename Value="BESEN\src\BESENCodeGeneratorContext.pas"/> + <UnitName Value="BESENCodeGeneratorContext"/> + </Item9> + <Item10> + <Filename Value="BESEN\src\BESENCodeJIT.pas"/> + <UnitName Value="BESENCodeJIT"/> + </Item10> + <Item11> + <Filename Value="BESEN\src\BESENCodeJITx64.pas"/> + <UnitName Value="BESENCodeJITx64"/> + </Item11> + <Item12> + <Filename Value="BESEN\src\BESENCodeJITx86.pas"/> + <UnitName Value="BESENCodeJITx86"/> + </Item12> + <Item13> + <Filename Value="BESEN\src\BESENCodeSnapshot.pas"/> + <UnitName Value="BESENCodeSnapshot"/> + </Item13> + <Item14> + <Filename Value="BESEN\src\BESENCollector.pas"/> + <UnitName Value="BESENCollector"/> + </Item14> + <Item15> + <Filename Value="BESEN\src\BESENCollectorObject.pas"/> + <UnitName Value="BESENCollectorObject"/> + </Item15> + <Item16> + <Filename Value="BESEN\src\BESENCompiler.pas"/> + <UnitName Value="BESENCompiler"/> + </Item16> + <Item17> + <Filename Value="BESEN\src\BESENConstants.pas"/> + <UnitName Value="BESENConstants"/> + </Item17> + <Item18> + <Filename Value="BESEN\src\BESENContext.pas"/> + <UnitName Value="BESENContext"/> + </Item18> + <Item19> + <Filename Value="BESEN\src\BESENDateUtils.pas"/> + <UnitName Value="BESENDateUtils"/> + </Item19> + <Item20> + <Filename Value="BESEN\src\BESENDeclarativeEnvironmentRecord.pas"/> + <UnitName Value="BESENDeclarativeEnvironmentRecord"/> + </Item20> + <Item21> + <Filename Value="BESEN\src\BESENDecompiler.pas"/> + <UnitName Value="BESENDecompiler"/> + </Item21> + <Item22> + <Filename Value="BESEN\src\BESENDoubleList.pas"/> + <UnitName Value="BESENDoubleList"/> + </Item22> + <Item23> + <Filename Value="BESEN\src\BESENEnvironmentRecord.pas"/> + <UnitName Value="BESENEnvironmentRecord"/> + </Item23> + <Item24> + <Filename Value="BESEN\src\BESENErrors.pas"/> + <UnitName Value="BESENErrors"/> + </Item24> + <Item25> + <Filename Value="BESEN\src\BESENEvalCache.pas"/> + <UnitName Value="BESENEvalCache"/> + </Item25> + <Item26> + <Filename Value="BESEN\src\BESENEvalCacheItem.pas"/> + <UnitName Value="BESENEvalCacheItem"/> + </Item26> + <Item27> + <Filename Value="BESEN\src\BESENGarbageCollector.pas"/> + <UnitName Value="BESENGarbageCollector"/> + </Item27> + <Item28> + <Filename Value="BESEN\src\BESENGlobals.pas"/> + <UnitName Value="BESENGlobals"/> + </Item28> + <Item29> + <Filename Value="BESEN\src\BESENHashMap.pas"/> + <UnitName Value="BESENHashMap"/> + </Item29> + <Item30> + <Filename Value="BESEN\src\BESENHashUtils.pas"/> + <UnitName Value="BESENHashUtils"/> + </Item30> + <Item31> + <Filename Value="BESEN\src\BESENInt64SelfBalancedTree.pas"/> + <UnitName Value="BESENInt64SelfBalancedTree"/> + </Item31> + <Item32> + <Filename Value="BESEN\src\BESENIntegerList.pas"/> + <UnitName Value="BESENIntegerList"/> + </Item32> + <Item33> + <Filename Value="BESEN\src\BESENKeyIDManager.pas"/> + <UnitName Value="BESENKeyIDManager"/> + </Item33> + <Item34> + <Filename Value="BESEN\src\BESENLexer.pas"/> + <UnitName Value="BESENLexer"/> + </Item34> + <Item35> + <Filename Value="BESEN\src\BESENLexicalEnvironment.pas"/> + <UnitName Value="BESENLexicalEnvironment"/> + </Item35> + <Item36> + <Filename Value="BESEN\src\BESENLocale.pas"/> + <UnitName Value="BESENLocale"/> + </Item36> + <Item37> + <Filename Value="BESEN\src\BESENNativeCodeMemoryManager.pas"/> + <UnitName Value="BESENNativeCodeMemoryManager"/> + </Item37> + <Item38> + <Filename Value="BESEN\src\BESENNativeObject.pas"/> + <UnitName Value="BESENNativeObject"/> + </Item38> + <Item39> + <Filename Value="BESEN\src\BESENNumberUtils.pas"/> + <UnitName Value="BESENNumberUtils"/> + </Item39> + <Item40> + <Filename Value="BESEN\src\BESENObject.pas"/> + <UnitName Value="BESENObject"/> + </Item40> + <Item41> + <Filename Value="BESEN\src\BESENObjectArgGetterFunction.pas"/> + <UnitName Value="BESENObjectArgGetterFunction"/> + </Item41> + <Item42> + <Filename Value="BESEN\src\BESENObjectArgSetterFunction.pas"/> + <UnitName Value="BESENObjectArgSetterFunction"/> + </Item42> + <Item43> + <Filename Value="BESEN\src\BESENObjectArray.pas"/> + <UnitName Value="BESENObjectArray"/> + </Item43> + <Item44> + <Filename Value="BESEN\src\BESENObjectArrayConstructor.pas"/> + <UnitName Value="BESENObjectArrayConstructor"/> + </Item44> + <Item45> + <Filename Value="BESEN\src\BESENObjectArrayPrototype.pas"/> + <UnitName Value="BESENObjectArrayPrototype"/> + </Item45> + <Item46> + <Filename Value="BESEN\src\BESENObjectBindingFunction.pas"/> + <UnitName Value="BESENObjectBindingFunction"/> + </Item46> + <Item47> + <Filename Value="BESEN\src\BESENObjectBoolean.pas"/> + <UnitName Value="BESENObjectBoolean"/> + </Item47> + <Item48> + <Filename Value="BESEN\src\BESENObjectBooleanConstructor.pas"/> + <UnitName Value="BESENObjectBooleanConstructor"/> + </Item48> + <Item49> + <Filename Value="BESEN\src\BESENObjectBooleanPrototype.pas"/> + <UnitName Value="BESENObjectBooleanPrototype"/> + </Item49> + <Item50> + <Filename Value="BESEN\src\BESENObjectConsole.pas"/> + <UnitName Value="BESENObjectConsole"/> + </Item50> + <Item51> + <Filename Value="BESEN\src\BESENObjectConstructor.pas"/> + <UnitName Value="BESENObjectConstructor"/> + </Item51> + <Item52> + <Filename Value="BESEN\src\BESENObjectDate.pas"/> + <UnitName Value="BESENObjectDate"/> + </Item52> + <Item53> + <Filename Value="BESEN\src\BESENObjectDateConstructor.pas"/> + <UnitName Value="BESENObjectDateConstructor"/> + </Item53> + <Item54> + <Filename Value="BESEN\src\BESENObjectDatePrototype.pas"/> + <UnitName Value="BESENObjectDatePrototype"/> + </Item54> + <Item55> + <Filename Value="BESEN\src\BESENObjectDeclaredFunction.pas"/> + <UnitName Value="BESENObjectDeclaredFunction"/> + </Item55> + <Item56> + <Filename Value="BESEN\src\BESENObjectEnvironmentRecord.pas"/> + <UnitName Value="BESENObjectEnvironmentRecord"/> + </Item56> + <Item57> + <Filename Value="BESEN\src\BESENObjectError.pas"/> + <UnitName Value="BESENObjectError"/> + </Item57> + <Item58> + <Filename Value="BESEN\src\BESENObjectErrorConstructor.pas"/> + <UnitName Value="BESENObjectErrorConstructor"/> + </Item58> + <Item59> + <Filename Value="BESEN\src\BESENObjectErrorPrototype.pas"/> + <UnitName Value="BESENObjectErrorPrototype"/> + </Item59> + <Item60> + <Filename Value="BESEN\src\BESENObjectFunction.pas"/> + <UnitName Value="BESENObjectFunction"/> + </Item60> + <Item61> + <Filename Value="BESEN\src\BESENObjectFunctionArguments.pas"/> + <UnitName Value="BESENObjectFunctionArguments"/> + </Item61> + <Item62> + <Filename Value="BESEN\src\BESENObjectFunctionConstructor.pas"/> + <UnitName Value="BESENObjectFunctionConstructor"/> + </Item62> + <Item63> + <Filename Value="BESEN\src\BESENObjectFunctionPrototype.pas"/> + <UnitName Value="BESENObjectFunctionPrototype"/> + </Item63> + <Item64> + <Filename Value="BESEN\src\BESENObjectGlobal.pas"/> + <UnitName Value="BESENObjectGlobal"/> + </Item64> + <Item65> + <Filename Value="BESEN\src\BESENObjectJSON.pas"/> + <UnitName Value="BESENObjectJSON"/> + </Item65> + <Item66> + <Filename Value="BESEN\src\BESENObjectMath.pas"/> + <UnitName Value="BESENObjectMath"/> + </Item66> + <Item67> + <Filename Value="BESEN\src\BESENObjectNativeFunction.pas"/> + <UnitName Value="BESENObjectNativeFunction"/> + </Item67> + <Item68> + <Filename Value="BESEN\src\BESENObjectNumber.pas"/> + <UnitName Value="BESENObjectNumber"/> + </Item68> + <Item69> + <Filename Value="BESEN\src\BESENObjectNumberConstructor.pas"/> + <UnitName Value="BESENObjectNumberConstructor"/> + </Item69> + <Item70> + <Filename Value="BESEN\src\BESENObjectNumberPrototype.pas"/> + <UnitName Value="BESENObjectNumberPrototype"/> + </Item70> + <Item71> + <Filename Value="BESEN\src\BESENObjectPropertyDescriptor.pas"/> + <UnitName Value="BESENObjectPropertyDescriptor"/> + </Item71> + <Item72> + <Filename Value="BESEN\src\BESENObjectPrototype.pas"/> + <UnitName Value="BESENObjectPrototype"/> + </Item72> + <Item73> + <Filename Value="BESEN\src\BESENObjectRegExp.pas"/> + <UnitName Value="BESENObjectRegExp"/> + </Item73> + <Item74> + <Filename Value="BESEN\src\BESENObjectRegExpConstructor.pas"/> + <UnitName Value="BESENObjectRegExpConstructor"/> + </Item74> + <Item75> + <Filename Value="BESEN\src\BESENObjectRegExpPrototype.pas"/> + <UnitName Value="BESENObjectRegExpPrototype"/> + </Item75> + <Item76> + <Filename Value="BESEN\src\BESENObjectString.pas"/> + <UnitName Value="BESENObjectString"/> + </Item76> + <Item77> + <Filename Value="BESEN\src\BESENObjectStringConstructor.pas"/> + <UnitName Value="BESENObjectStringConstructor"/> + </Item77> + <Item78> + <Filename Value="BESEN\src\BESENObjectStringPrototype.pas"/> + <UnitName Value="BESENObjectStringPrototype"/> + </Item78> + <Item79> + <Filename Value="BESEN\src\BESENObjectThrowTypeErrorFunction.pas"/> + <UnitName Value="BESENObjectThrowTypeErrorFunction"/> + </Item79> + <Item80> + <Filename Value="BESEN\src\BESENOpcodes.pas"/> + <UnitName Value="BESENOpcodes"/> + </Item80> + <Item81> + <Filename Value="BESEN\src\BESENParser.pas"/> + <UnitName Value="BESENParser"/> + </Item81> + <Item82> + <Filename Value="BESEN\src\BESENPointerList.pas"/> + <UnitName Value="BESENPointerList"/> + </Item82> + <Item83> + <Filename Value="BESEN\src\BESENPointerSelfBalancedTree.pas"/> + <UnitName Value="BESENPointerSelfBalancedTree"/> + </Item83> + <Item84> + <Filename Value="BESEN\src\BESENRandomGenerator.pas"/> + <UnitName Value="BESENRandomGenerator"/> + </Item84> + <Item85> + <Filename Value="BESEN\src\BESENRegExp.pas"/> + <UnitName Value="BESENRegExp"/> + </Item85> + <Item86> + <Filename Value="BESEN\src\BESENRegExpCache.pas"/> + <UnitName Value="BESENRegExpCache"/> + </Item86> + <Item87> + <Filename Value="BESEN\src\BESENScope.pas"/> + <UnitName Value="BESENScope"/> + </Item87> + <Item88> + <Filename Value="BESEN\src\BESENSelfBalancedTree.pas"/> + <UnitName Value="BESENSelfBalancedTree"/> + </Item88> + <Item89> + <Filename Value="BESEN\src\BESENStringList.pas"/> + <UnitName Value="BESENStringList"/> + </Item89> + <Item90> + <Filename Value="BESEN\src\BESENStringTree.pas"/> + <UnitName Value="BESENStringTree"/> + </Item90> + <Item91> + <Filename Value="BESEN\src\BESENStringUtils.pas"/> + <UnitName Value="BESENStringUtils"/> + </Item91> + <Item92> + <Filename Value="BESEN\src\BESENTypes.pas"/> + <UnitName Value="BESENTypes"/> + </Item92> + <Item93> + <Filename Value="BESEN\src\BESENUnicodeTables.pas"/> + <UnitName Value="BESENUnicodeTables"/> + </Item93> + <Item94> + <Filename Value="BESEN\src\BESENUtils.pas"/> + <UnitName Value="BESENUtils"/> + </Item94> + <Item95> + <Filename Value="BESEN\src\BESENValue.pas"/> + <UnitName Value="BESENValue"/> + </Item95> + <Item96> + <Filename Value="BESEN\src\BESENValueContainer.pas"/> + <UnitName Value="BESENValueContainer"/> + </Item96> + <Item97> + <Filename Value="BESEN\src\BESENVersionConstants.pas"/> + <UnitName Value="BESENVersionConstants"/> + </Item97> + </Files> + <RequiredPkgs Count="1"> + <Item1> + <PackageName Value="FCL"/> + </Item1> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + </Package> +</CONFIG> From d817a5314f5e843f51fdb73923952daffac19930 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 4 Jan 2017 15:00:25 +0800 Subject: [PATCH 1465/2794] cleanup --- baseunits/uBaseUnit.pas | 83 ++++++++++++++++----------------- baseunits/uDownloadsManager.pas | 10 ---- 2 files changed, 39 insertions(+), 54 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ea0c0f597..8fde6e7d7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -257,45 +257,45 @@ interface SCANMANGA_ID = 24; MANGAGO_ID = 25; DM5_ID = 26; - MANGACOW_ID = 27; - KIVMANGA_ID = 28; - MEINMANGA_ID = 29; - MANGASPROJECT_ID = 30; - MANGAREADER_POR_ID = 31; - NINEMANGA_ID = 32; - NINEMANGA_ES_ID = 33; - NINEMANGA_CN_ID = 34; - NINEMANGA_RU_ID = 35; - NINEMANGA_DE_ID = 36; - NINEMANGA_IT_ID = 37; - NINEMANGA_BR_ID = 38; - JAPANSHIN_ID = 39; - JAPSCAN_ID = 40; - CENTRUMMANGI_PL_ID = 41; - MANGALIB_PL_ID = 42; - ONEMANGA_ID = 43; - MANGATOWN_ID = 44; - MANGAOKU_ID = 45; - MYREADINGMANGAINFO_ID = 46; - IKOMIK_ID = 47; - NHENTAI_ID = 48; - MANGAMINT_ID = 49; - UNIXMANGA_ID = 50; - EXTREMEMANGAS_ID = 51; - MANGAHOST_ID = 52; - PORNCOMIX_ID = 53; - PORNCOMIXRE_ID = 54; - PORNCOMIXIC_ID = 55; - XXCOMICS_ID = 56; - XXCOMICSMT_ID = 57; - XXCOMICS3D_ID = 58; - PORNXXXCOMICS_ID = 59; - MANGAKU_ID = 60; - MANGAAT_ID = 61; - READMANGATODAY_ID = 62; - DYNASTYSCANS_ID = 63; - - WebsiteRoots: array [0..63] of array [0..1] of String = ( + + KIVMANGA_ID = 27; + MEINMANGA_ID = 28; + MANGASPROJECT_ID = 29; + MANGAREADER_POR_ID = 30; + NINEMANGA_ID = 31; + NINEMANGA_ES_ID = 32; + NINEMANGA_CN_ID = 33; + NINEMANGA_RU_ID = 34; + NINEMANGA_DE_ID = 35; + NINEMANGA_IT_ID = 36; + NINEMANGA_BR_ID = 37; + JAPANSHIN_ID = 38; + JAPSCAN_ID = 39; + CENTRUMMANGI_PL_ID = 40; + MANGALIB_PL_ID = 41; + ONEMANGA_ID = 42; + MANGATOWN_ID = 43; + MANGAOKU_ID = 44; + MYREADINGMANGAINFO_ID = 45; + IKOMIK_ID = 46; + NHENTAI_ID = 47; + MANGAMINT_ID = 48; + UNIXMANGA_ID = 49; + EXTREMEMANGAS_ID = 50; + MANGAHOST_ID = 51; + PORNCOMIX_ID = 52; + PORNCOMIXRE_ID = 53; + PORNCOMIXIC_ID = 54; + XXCOMICS_ID = 55; + XXCOMICSMT_ID = 56; + XXCOMICS3D_ID = 57; + PORNXXXCOMICS_ID = 58; + MANGAKU_ID = 59; + MANGAAT_ID = 60; + READMANGATODAY_ID = 61; + DYNASTYSCANS_ID = 62; + + WebsiteRoots: array [0..62] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -323,7 +323,6 @@ interface ('ScanManga', 'http://www.scan-manga.com'), ('MangaGo', 'http://www.mangago.me'), ('DM5', 'http://www.dm5.com'), - ('Mangacow', 'http://mangacow.co'), ('KivManga', 'http://www.kivmanga.com'), ('MeinManga', 'http://www.meinmanga.com/'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), @@ -424,9 +423,6 @@ interface DM5_BROWSER = '/manhua-new'; - //MANGACOW_BROWSER :string = '/manga-list/all/any/name-az/'; - MANGACOW_BROWSER = '/manga-list/all/any/last-added/'; - KIVMANGA_BROWSER = '/'; MEINMANGA_BROWSER = '/directory/all/'; @@ -1150,7 +1146,6 @@ function SitesWithSortedList(const website: String): Boolean; NINEMANGA_DE_ID, NINEMANGA_IT_ID, NINEMANGA_BR_ID, - MANGACOW_ID, ONEMANGA_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID, diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 85ab659cd..beb7cc645 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -418,8 +418,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaAr/chapter_page_number.inc} - {$I includes/Mangacow/chapter_page_number.inc} - {$I includes/MangaGo/chapter_page_number.inc} {$I includes/MeinManga/chapter_page_number.inc} @@ -518,9 +516,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAAE_ID then Result := GetMangaAePageNumber else - if Task.Container.MangaSiteID = MANGACOW_ID then - Result := GetMangaCowPageNumber - else if Task.Container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else @@ -635,8 +630,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaAr/image_url.inc} - {$I includes/Mangacow/image_url.inc} - {$I includes/MangaEsta/image_url.inc} {$I includes/MangaGo/image_url.inc} @@ -753,9 +746,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else - if Task.Container.MangaSiteID = MANGACOW_ID then - Result := GetMangaCowImageURL - else if Task.Container.MangaSiteID = TRUYENTRANHTUAN_ID then Result := GetTruyenTranhTuanImageURL else From 9c81286f4eacecdc151a2bb7ee586144ddfdb89e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 4 Jan 2017 15:16:16 +0800 Subject: [PATCH 1466/2794] bump version 0.9.84.0 --- changelog.txt | 3 ++- update | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 18140745d..f97b61a2a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,13 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.84.0 (25-12-2016) +0.9.84.0 (04-01-2017) [*] MangaFox: fixed manga info and Status [*] MangaTown: fixed Image Url [*] Removed MangaCow and Moved to WPManga [+] Added Tonari no Young Jump, Comico, NewType and fixed Sunday Web Every[JP] [+] Added PowerManga, Jaiminisbox, KireiCake and ReadComics[EN] [*] Fixed Madokami Url +[*] Fixed 8Muses Full changes: https://github.com/riderkick/FMD/compare/0.9.82.0...0.9.83.0 0.9.83.0 (06-09-2016) diff --git a/update b/update index fdcfa566f..23a95d353 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ VERSION=0.9.84.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.83.0/fmd_0.9.83.0_Win64.7z/download -WIN32=https://github.com/kavin-90/FMD/releases/download/0.9.84.0/fmd_0.9.84.0.7z +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.84.0/fmd_0.9.84.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.84.0/fmd_0.9.84.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.84.0/fmd_0.9.84.0.7z ; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.84.0/fmd_0.9.84.0_Win64.7z From dc52b63536fe00f647f3c8047e4e5ec80bd38eb0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 5 Jan 2017 03:56:10 +0800 Subject: [PATCH 1467/2794] fixed mangafox missing chapter's title --- baseunits/modules/MangaFox.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 5bfed544e..a63cb4417 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -66,10 +66,10 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); summary := XPathString('//p[@class="summary"]'); status := MangaInfoStatusIfPos(XPathString('//div[@id="series_info"]/div[5]/span')); - for v in XPath('//div/*/a[@class="tips"]') do + for v in XPath('//ul[@class="chlist"]/li/div/*[self::h3 or self::h4]') do begin - chapterLinks.Add(StringReplace(v.toNode.getAttribute('href'), '1.html', '', [rfReplaceAll])); - chapterName.Add(v.toString); + chapterLinks.Add(StringReplace(XPathString('a/@href', v), '1.html', '', [rfReplaceAll])); + chapterName.Add(XPathString('string-join(*/text()," ")', v)); end; InvertStrings([chapterLinks, chapterName]); finally @@ -162,4 +162,4 @@ procedure RegisterModule; initialization RegisterModule; -end. \ No newline at end of file +end. From 525c8ef5f82aa7a429426fef91c9ee6f5fcbe0fc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 5 Jan 2017 06:56:48 +0800 Subject: [PATCH 1468/2794] fixed mangatraders directory url --- baseunits/modules/MangaLife.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 44ce6b354..5128477ef 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Dialogs; + XQueryEngineHTML; implementation @@ -59,7 +59,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; s += '?c=' else if Module = MMangaTraders then - s += '?start='; + s += '?q='; s += diralpha[StrToIntDef(AURL, 0) + 1] end; if MangaInfo.FHTTP.GET(s) then From a94b5c600b63912211e9c28de95eb2c920547af4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 5 Jan 2017 07:17:16 +0800 Subject: [PATCH 1469/2794] changed MangaInfoStatusIfPos default completed string --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8fde6e7d7..239cb636c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -869,7 +869,7 @@ function JDNToDate(const JDN: Longint): TDate; function ConvertStrToInt32(const aStr : String): Cardinal;} procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String = 'Ongoing'; - const CompletedStr: String = 'Completed'): String; + const CompletedStr: String = 'Complete'): String; // cross platform funcs From b707ce08fb8dcc6fc2cb5aa5718df6814f1cc6cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 5 Jan 2017 07:28:19 +0800 Subject: [PATCH 1470/2794] added basic logger to baseunit --- baseunits/uBaseUnit.pas | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 239cb636c..5e576c95b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -877,6 +877,10 @@ function fmdGetTempPath: String; procedure fmdPowerOff; procedure fmdHibernate; +// logger +procedure SendLog(const AText: String); overload; inline; +procedure SendLog(const AText, AValue: String); overload; inline; + implementation uses @@ -4150,6 +4154,16 @@ procedure fmdHibernate; {$ENDIF} end; +procedure SendLog(const AText: String); +begin + Logger.Send(AText); +end; + +procedure SendLog(const AText, AValue: String); +begin + Logger.Send(AText, AValue); +end; + function HeaderByName(const AHeaders: TStrings; const AHeaderName: String): String; var i, p: Integer; From 67c3784cf81673afe3cd4f84f950a0b41ad85111 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 5 Jan 2017 07:37:28 +0800 Subject: [PATCH 1471/2794] fixed mangatraders mangainfo --- baseunits/modules/MangaLife.pas | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 5128477ef..1368b1a9c 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -94,14 +94,15 @@ function GetInfo(const MangaInfo: TMangaInformation; try coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); if title = '' then title := XPathString('//*[@class="row"]//h1'); - authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author:")]'), ':'); - artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist:")]'), ':'); - status := MangaInfoStatusIfPos(XPathString( - '//*[@class="row"][starts-with(.,"Scanlation Status:")]'), - 'ongoing', - 'completed'); - genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre:")]'), ':'); - summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description:")]'), ':')); + authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author")]'), ':'); + artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist")]'), ':'); + status := XPathString('//*[@class="row"][starts-with(.,"Scanlation Status")]'); + if status = '' then + status := XPathString('//*[@class="row"][starts-with(.,"Status")]'); + if status <> '' then + status := MangaInfoStatusIfPos(status); + genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre")]'), ':'); + summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description")]'), ':')); for v in XPath('//div[@class="list chapter-list"]/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); From 8ac12517f766922e9617e8523f6553aca9545ee5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 6 Jan 2017 23:14:22 +0800 Subject: [PATCH 1472/2794] added mangatraders login function --- baseunits/modules/MangaLife.pas | 80 +++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 1368b1a9c..63225390a 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, accountmanagerdb, httpsendthread, synacode; implementation @@ -20,6 +20,69 @@ implementation var MMangaSee, MMangaTraders: TModuleContainer; + MangaTradersLockLogin: TRTLCriticalSection; + MangaTradersOnLogin: Boolean; + +function MangaTradersLogin(const AHTTP: THTTPSendThread): Boolean; +var + s: String; +begin + Result := False; + if Account.Enabled[MMangaTraders.Website] = False then Exit; + if TryEnterCriticalsection(MangaTradersLockLogin) > 0 then + try + MangaTradersOnLogin := True; + Account.Status[MMangaTraders.Website] := asChecking; + SendLog('MangaTraders: post login'); + s := + 'EmailAddress=' + EncodeURLElement(Account.Username[MMangaTraders.Website]) + + '&Password=' + EncodeURLElement(Account.Password[MMangaTraders.Website]) + + '&RememberMe=1'; + AHTTP.Headers.Clear; + if AHTTP.POST(MMangaTraders.RootURL + '/auth/process.login.php', s) then + begin + s := StreamToString(AHTTP.Document); + SendLog('MangaTraders: login result = ' + s); + if LowerCase(s) = 'ok' then + begin + Account.Status[MMangaTraders.Website] := asValid; + Account.Cookies[MMangaTraders.Website] := AHTTP.Cookies.Text; + end + else + Account.Status[MMangaTraders.Website] := asInvalid; + end + else + Account.Status[MMangaTraders.Website] := asUnknown; + Result := Account.Status[MMangaTraders.Website] = asValid; + finally + MangaTradersOnLogin := False; + LeaveCriticalsection(MangaTradersLockLogin); + end + else + begin + while MangaTradersOnLogin do Sleep(1000); + Result := Account.Status[MMangaTraders.Website] = asValid; + if Result then + AHTTP.Cookies.Text := Account.Cookies[MMangaTraders.Website]; + end; +end; + +function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +var + accstat: TAccountStatus; +begin + Result := False; + if Account.Enabled[MMangaTraders.Website] then + begin + accstat := Account.Status[MMangaTraders.Website]; + if accstat = asValid then + AHTTP.Cookies.AddText(Account.Cookies[MMangaTraders.Website]) + else + if accstat in [asChecking, asUnknown] then + Result := MangaTradersLogin(AHTTP); + end; + Result := AHTTP.GET(AURL); +end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -82,17 +145,22 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + r: Boolean; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - if GET(url) then begin + if Module = MMangaTraders then + r := GETMangaTraders(MangaInfo.FHTTP, url) + else + r := GET(url); + if r then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); if title = '' then title := XPathString('//*[@class="row"]//h1'); authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author")]'), ':'); artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist")]'), ':'); @@ -160,9 +228,15 @@ procedure RegisterModule; AddWebsiteModule('MangaLife', 'http://mangalife.org'); MMangaSee := AddWebsiteModule('MangaSee', 'http://mangaseeonline.net'); MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.biz'); + MMangaTraders.AccountSupport := True; + MMangaTraders.OnLogin := @MangaTradersLogin; end; initialization + InitCriticalSection(MangaTradersLockLogin); RegisterModule; +finalization + DoneCriticalsection(MangaTradersLockLogin); + end. From 42aee019a7a9375a103374af73544b6fee45e870 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 7 Jan 2017 10:07:37 +0800 Subject: [PATCH 1473/2794] fixed mangasee and mangalife get directory --- baseunits/modules/MangaLife.pas | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 63225390a..dab7bd940 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -16,7 +16,7 @@ implementation const dirURL = '/directory/'; diralpha = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - dirURLmangasee = '/directory.php'; + var MMangaSee, MMangaTraders: TModuleContainer; @@ -88,11 +88,10 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; - if (Module = MMangaSee) or - (Module = MMangaTraders) then + if Module = MMangaTraders then Page := Length(diralpha) else - Page := 1; + page := 1; end; function fixcleanurl(const u: string): string; @@ -111,19 +110,12 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; s: String; begin Result := NET_PROBLEM; - s := Module.RootURL; - if Module = MMangaSee then - s += dirURLmangasee - else - s+=dirURL; + s := Module.RootURL + dirURL; if AURL <> '0' then begin - if Module = MMangaSee then - s += '?c=' - else if Module = MMangaTraders then s += '?q='; - s += diralpha[StrToIntDef(AURL, 0) + 1] + s += diralpha[StrToIntDef(AURL, 0) + 1]; end; if MangaInfo.FHTTP.GET(s) then begin From a24b913fd1ad6d6690663886435eac3749d3c8dd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 7 Jan 2017 10:50:50 +0800 Subject: [PATCH 1474/2794] fixed mangalife,mangasee,mangatraders chapter list --- baseunits/modules/MangaLife.pas | 5 +++-- mangadownloader/md.lpi | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index dab7bd940..bbb5fd5a4 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -163,11 +163,12 @@ function GetInfo(const MangaInfo: TMangaInformation; status := MangaInfoStatusIfPos(status); genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre")]'), ':'); summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description")]'), ':')); - for v in XPath('//div[@class="list chapter-list"]/a') do + for v in XPath('//div[@class="list chapter-list"]//a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index d02bcfbf3..3114cde89 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="9"/> + <Version Value="10"/> <PathDelim Value="\"/> <General> <SessionStorage Value="InProjectDir"/> From 0717cfe22f16a948553044411a688138180ded52 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 7 Jan 2017 11:10:32 +0800 Subject: [PATCH 1475/2794] fixes download mangasee,mangalife,mangatraders. closed #422 --- baseunits/modules/MangaLife.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index bbb5fd5a4..82cee51bb 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -138,6 +138,7 @@ function GetInfo(const MangaInfo: TMangaInformation; var v: IXQValue; r: Boolean; + s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -165,7 +166,10 @@ function GetInfo(const MangaInfo: TMangaInformation; summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description")]'), ':')); for v in XPath('//div[@class="list chapter-list"]//a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); + s := v.toNode.getAttribute('href'); + if Pos('-page-1', s) > 0 then + s := StringReplace(s, '-page-1', '', []); + chapterLinks.Add(s); chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); end; InvertStrings([chapterLinks, chapterName]); @@ -192,8 +196,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - for v in XPath('//img[@class="CurImage"]') do - PageLinks.Add(v.toNode.getAttribute('src')); + XPathStringAll('//*[@class="image-container"]//img/@src', PageLinks); finally Free; end; From 689ee84f21ed4f3c4b2df615d6d00dd79a2a5523 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 7 Jan 2017 11:29:10 +0800 Subject: [PATCH 1476/2794] update future changelog --- changelog.txt | 7 ++++++- mangadownloader/md.lpi | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index f97b61a2a..94c41a02f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.85.0 (future) +[*] MangaFox: fixed missing chapter title +[*] MangaLife, MangaSee, MangaTraders: fixed all, MangaTraders require account +Full changes: https://github.com/riderkick/FMD/compare/0.9.84.0...0.9.85.0 + 0.9.84.0 (04-01-2017) [*] MangaFox: fixed manga info and Status [*] MangaTown: fixed Image Url @@ -12,7 +17,7 @@ Changelog: [+] Added PowerManga, Jaiminisbox, KireiCake and ReadComics[EN] [*] Fixed Madokami Url [*] Fixed 8Muses -Full changes: https://github.com/riderkick/FMD/compare/0.9.82.0...0.9.83.0 +Full changes: https://github.com/riderkick/FMD/compare/0.9.83.0...0.9.84.0 0.9.83.0 (06-09-2016) [*] Fixed an issue when saving to pdf diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 3114cde89..fb56962b8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="84"/> + <RevisionNr Value="85"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> From f63bb0d390b9eabc2eece441938b231207637997 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sat, 7 Jan 2017 12:35:30 +0530 Subject: [PATCH 1477/2794] Fixed KireiCake --- baseunits/modules/FoOlSlide.pas | 4 ---- 1 file changed, 4 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 5e503c7b8..771343dfb 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -17,7 +17,6 @@ implementation const dirurl = '/directory/'; dirurlreader = '/reader/directory/'; - dirurlreaderlist = '/reader/list/'; dirurlfoolslide = '/foolslide/directory/'; dirurlslide = '/slide/directory/'; dirurlslideU = '/Slide/directory/'; @@ -45,9 +44,6 @@ function GetDirURL(const AWebsite: String): String; (AWebsite = 'TripleSevenScan') then Result := dirurlreader else - if AWebsite = 'KireiCake' then - Result := dirurlreaderlist - else if AWebsite = 'OneTimeScans' then Result := dirurlfoolslide else From 40c9c71fb6ce396ce20af1283d0f9945d03b6f59 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sat, 7 Jan 2017 22:47:59 +0530 Subject: [PATCH 1478/2794] Fixed Read Comics Manga List --- baseunits/modules/ReadComics.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/ReadComics.pas b/baseunits/modules/ReadComics.pas index 9a934a9af..23a6fb835 100644 --- a/baseunits/modules/ReadComics.pas +++ b/baseunits/modules/ReadComics.pas @@ -28,7 +28,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//div[@class="serie-box"]/li/a') do + for v in XPath('//div[@class="serie-box"]/*/li/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); From 88072a3c00c6fc591d2a8bb15db1004aa45c86f3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 8 Jan 2017 18:09:48 +0800 Subject: [PATCH 1479/2794] fixed cf when retrycount=-1. closed #433 --- baseunits/modules/Cloudflare.pas | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index ba55c4909..4592bf9b3 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -108,14 +108,16 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B counter := 0; maxretry := AHTTP.RetryCount; AHTTP.RetryCount := 0; - while counter < maxretry do begin + while True do + begin Inc(counter); m := 'GET'; u := ''; h := AppendURLDelim(GetHostURL(AURL)); st := MIN_WAIT_TIME; if JSGetAnsweredURL(StreamToString(AHTTP.Document), h, m, u, st) then - if (m <> '') and (u <> '') then begin + if (m <> '') and (u <> '') then + begin AHTTP.Reset; AHTTP.Headers.Values['Referer'] := ' ' + AURL; if st < MIN_WAIT_TIME then st := MIN_WAIT_TIME; @@ -132,12 +134,15 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B AHTTP.FollowRedirection := True; if Result then Cookie := AHTTP.GetCookies; end; - if Result then Break - else if counter < maxretry then begin - AHTTP.Reset; - Result := AHTTP.GET(AURL); - if not AntiBotActive(AHTTP) then Break; + if AHTTP.RetryCount <> 0 then + begin + maxretry := AHTTP.RetryCount; + AHTTP.RetryCount := 0; end; + if Result then Break; + if (maxretry > -1) and (maxretry <= counter) then Break; + AHTTP.Reset; + AHTTP.GET(AURL); end; AHTTP.RetryCount := maxretry; end; From 8f32dc3dea969f25ef24500cf2c68de6f305e290 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 8 Jan 2017 18:22:22 +0800 Subject: [PATCH 1480/2794] bump version 0.9.85.0 --- changelog.txt | 5 ++++- update | 10 +++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 94c41a02f..cf3920444 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,9 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.85.0 (future) +0.9.85.0 (08-01-2017) [*] MangaFox: fixed missing chapter title [*] MangaLife, MangaSee, MangaTraders: fixed all, MangaTraders require account +[*] KireiCake: Fixed manga list +[*] ReadComic: Fixed manga list +[*] Fixed CF issue #433 Full changes: https://github.com/riderkick/FMD/compare/0.9.84.0...0.9.85.0 0.9.84.0 (04-01-2017) diff --git a/update b/update index 23a95d353..389602244 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.84.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.84.0/fmd_0.9.84.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.84.0/fmd_0.9.84.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.84.0/fmd_0.9.84.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.84.0/fmd_0.9.84.0_Win64.7z +VERSION=0.9.85.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.85.0/fmd_0.9.85.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.85.0/fmd_0.9.85.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.85.0/fmd_0.9.85.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.85.0/fmd_0.9.85.0_Win64.7z From 5fdc25907b1ba4c8db15eb0d17a1742494591c0d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 8 Jan 2017 23:29:26 +0800 Subject: [PATCH 1481/2794] added mangacool --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaCool.pas | 107 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaCool.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 4bb8906a0..129ec6974 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -51,6 +51,7 @@ uses MangaOnlineTo, MyMangaMe, ReadComics, + MangaCool, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaCool.pas b/baseunits/modules/MangaCool.pas new file mode 100644 index 000000000..48cd4be72 --- /dev/null +++ b/baseunits/modules/MangaCool.pas @@ -0,0 +1,107 @@ +unit MangaCool; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread; + +implementation + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/list') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('/html/body/div/div/div/ul/li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('/html/body/div/div/div/img/@src')); + title := XPathString('//h1/a/@title'); + genres := XPathString('string-join(/html/body/div/div/div/span/a,", ")'); + for v in XPath('/html/body/div/div/div[not(@id="ShowAllEpisodes")]/div/a') do + begin + s := v.toNode.getAttribute('href'); + if Pos('/page-1', s) > 0 then + s := StringReplace(s, '/page-1', '', []); + chapterLinks.Add(s); + chapterName.Add(v.toNode.getAttribute('title')); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('/html/body/div/div/img/@src', PageLinks); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaCool'; + RootURL := 'http://mangacool.se'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index cd9946a28..5cf8e7d54 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From eeb0dfc2188e7503f787501df151d2a7d16459f5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 Jan 2017 16:44:02 +0800 Subject: [PATCH 1482/2794] update useragent --- baseunits/httpsendthread.pas | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 3feff160a..5473f5186 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -69,15 +69,14 @@ function MaybeEncodeURL(const AValue: String): String; procedure SplitURL(URL: String; out Host, Path: String); const - UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; - UserAgentCURL = 'curl/7.42.1'; + UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; + UserAgentCURL = 'curl/7.52.1'; UserAgentGooglebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; - UserAgentInternetExplorer = 'Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)'; - UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0'; - UserAgentChrome = - 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'; - UserAgentOpera = - 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48'; + UserAgentMSIE = 'Mozilla/5.0 (Windows NT 10.0; Win64; Trident/7.0; rv:11.0) like Gecko'; + UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0'; + UserAgentChrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'; + UserAgentOpera = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94'; + UserAgentEdge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393'; var DefaultUserAgent: String = UserAgentChrome; From 82d76f9c44b892960e39bf7bfce42857f855ddd7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 9 Jan 2017 16:48:58 +0800 Subject: [PATCH 1483/2794] update translation --- mangadownloader/languages/fmd.id_ID.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 0a7dd844c..9e63d579f 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1920,7 +1920,7 @@ msgstr "Unduhan" #: twebsiteoptionadvancedform.tsmaxthreadspertask.caption msgid "Max threads per task" -msgstr "Max jumlah threafs per unduhan" +msgstr "Max jumlah threads per unduhan" #: twebsiteoptionadvancedform.tsnumberofthreads.caption msgid "Number of threads" From 7467fe0b2a8523d1f09ada4ee93ab3a8915093a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 07:36:30 +0800 Subject: [PATCH 1484/2794] mangatraders, auto redirect url if read online available. #437 --- baseunits/modules/MangaLife.pas | 43 ++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 82cee51bb..5ccc5311a 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -18,7 +18,6 @@ implementation diralpha = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; var - MMangaSee, MMangaTraders: TModuleContainer; MangaTradersLockLogin: TRTLCriticalSection; MangaTradersOnLogin: Boolean; @@ -108,6 +107,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; var v: IXQValue; s: String; + i: Integer; begin Result := NET_PROBLEM; s := Module.RootURL + dirURL; @@ -130,6 +130,9 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; finally Free; end; + if (Module = MMangaTraders) and (ALinks.Count > 0) then + for i := 0 to ALinks.Count - 1 do + ALinks[i] := StringReplace(ALinks[1], '/series/', '/manga/', []); end; end; @@ -153,8 +156,23 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); + if (Module = MMangaTraders) and (Pos('/series/', url) > 0) then + begin + s := XPathString('//div[@class="alert alert-success startReading"]/a/@href'); + if Pos('/manga/', s) > 0 then + begin + s := MaybeFillHost(Module.RootURL, s); + url := s; + if GET(url) then + ParseHTML(Document) + else + r := False; + end + else + r := False; + end; if title = '' then title := XPathString('//*[@class="row"]//h1'); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author")]'), ':'); artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist")]'), ':'); status := XPathString('//*[@class="row"][starts-with(.,"Scanlation Status")]'); @@ -164,15 +182,18 @@ function GetInfo(const MangaInfo: TMangaInformation; status := MangaInfoStatusIfPos(status); genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre")]'), ':'); summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description")]'), ':')); - for v in XPath('//div[@class="list chapter-list"]//a') do + if r then begin - s := v.toNode.getAttribute('href'); - if Pos('-page-1', s) > 0 then - s := StringReplace(s, '-page-1', '', []); - chapterLinks.Add(s); - chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); + for v in XPath('//div[@class="list chapter-list"]//a') do + begin + s := v.toNode.getAttribute('href'); + if Pos('-page-1', s) > 0 then + s := StringReplace(s, '-page-1', '', []); + chapterLinks.Add(s); + chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); + end; + InvertStrings([chapterLinks, chapterName]); end; - InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -182,8 +203,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; @@ -222,7 +241,7 @@ procedure RegisterModule; begin AddWebsiteModule('MangaLife', 'http://mangalife.org'); - MMangaSee := AddWebsiteModule('MangaSee', 'http://mangaseeonline.net'); + AddWebsiteModule('MangaSee', 'http://mangaseeonline.net'); MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.biz'); MMangaTraders.AccountSupport := True; MMangaTraders.OnLogin := @MangaTradersLogin; From a6b3703475b78b0e8859cf9ec853fa9f6a806d3c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 08:06:20 +0800 Subject: [PATCH 1485/2794] mangatraders, fixed update list, rule out 404 not found. #437 --- baseunits/modules/MangaLife.pas | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 5ccc5311a..73f41b0c2 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -132,7 +132,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; end; if (Module = MMangaTraders) and (ALinks.Count > 0) then for i := 0 to ALinks.Count - 1 do - ALinks[i] := StringReplace(ALinks[1], '/series/', '/manga/', []); + if Pos('/series/', ALinks[i]) <> 0 then + ALinks[i] := StringReplace(ALinks[i], '/series/', '/manga/', []); end; end; @@ -156,10 +157,16 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - if (Module = MMangaTraders) and (Pos('/series/', url) > 0) then + title := XPathString('//*[@class="row"]//h1'); + if ResultCode = 404 then + begin + status := '-1'; + Exit; + end; + if (Module = MMangaTraders) and (Pos('/series/', url) <> 0) then begin s := XPathString('//div[@class="alert alert-success startReading"]/a/@href'); - if Pos('/manga/', s) > 0 then + if Pos('/manga/', s) <> 0 then begin s := MaybeFillHost(Module.RootURL, s); url := s; @@ -171,7 +178,6 @@ function GetInfo(const MangaInfo: TMangaInformation; else r := False; end; - if title = '' then title := XPathString('//*[@class="row"]//h1'); coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author")]'), ':'); artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist")]'), ':'); @@ -187,7 +193,7 @@ function GetInfo(const MangaInfo: TMangaInformation; for v in XPath('//div[@class="list chapter-list"]//a') do begin s := v.toNode.getAttribute('href'); - if Pos('-page-1', s) > 0 then + if Pos('-page-1', s) <> 0 then s := StringReplace(s, '-page-1', '', []); chapterLinks.Add(s); chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); From d0e806879862c3a59b33fba4489b9a83a20950a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 08:07:08 +0800 Subject: [PATCH 1486/2794] updatethread, don't save staus=-1. #437 --- baseunits/uUpdateThread.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 96b7617a3..2150aaed2 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -218,7 +218,8 @@ procedure TUpdateListThread.Execute; Info.mangaInfo.title:=title; if link<>'' then begin Info.GetInfoFromURL(manager.website,link,DefaultRetryCount); - if not Terminated then + // status = '-1' mean it's not exist and shouldn't be saved to database + if (not Terminated) and (Info.mangaInfo.status <> '-1') then begin EnterCriticalSection(manager.CS_AddInfoToData); try From 4d5ee1a10853c0be0859742ab09982d94a0e7c4b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 08:50:30 +0800 Subject: [PATCH 1487/2794] bump version 0.9.86.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index cf3920444..96108b82b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.86.0 (11-01-2017) +[+] Added MangaCool[EN] +[*] MangaTraders: fixed issue #437 +Full changes: https://github.com/riderkick/FMD/compare/0.9.85.0...0.9.86.0 + 0.9.85.0 (08-01-2017) [*] MangaFox: fixed missing chapter title [*] MangaLife, MangaSee, MangaTraders: fixed all, MangaTraders require account diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index fb56962b8..530848473 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="85"/> + <RevisionNr Value="86"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 389602244..baa84975d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.85.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.85.0/fmd_0.9.85.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.85.0/fmd_0.9.85.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.85.0/fmd_0.9.85.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.85.0/fmd_0.9.85.0_Win64.7z +VERSION=0.9.86.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.86.0/fmd_0.9.86.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.86.0/fmd_0.9.86.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.86.0/fmd_0.9.86.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.86.0/fmd_0.9.86.0_Win64.7z From d2944f0114b4fb2b7a5ed26b6a5c58bb44f79bdd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 20:30:27 +0800 Subject: [PATCH 1488/2794] rename method parameters to avoid conflict --- .../AnimExtremist/manga_information.inc | 4 +- .../AnimExtremist/names_and_links.inc | 4 +- .../includes/AnimeA/directory_page_number.inc | 2 +- .../includes/AnimeA/manga_information.inc | 4 +- baseunits/includes/AnimeA/names_and_links.inc | 6 +- .../includes/AnimeStory/manga_information.inc | 4 +- .../includes/AnimeStory/names_and_links.inc | 4 +- .../BlogTruyen/directory_page_number.inc | 2 +- .../includes/BlogTruyen/manga_information.inc | 4 +- .../includes/BlogTruyen/names_and_links.inc | 10 +- .../CentralDeMangas/directory_page_number.inc | 2 +- .../CentralDeMangas/manga_information.inc | 4 +- .../CentralDeMangas/names_and_links.inc | 6 +- .../CentrumMangi_PL/manga_information.inc | 4 +- .../CentrumMangi_PL/names_and_links.inc | 10 +- .../includes/DM5/directory_page_number.inc | 2 +- .../Dynasty-Scans/directory_page_number.inc | 2 +- .../Dynasty-Scans/manga_information.inc | 4 +- .../Dynasty-Scans/names_and_links.inc | 6 +- .../includes/EGScans/manga_information.inc | 6 +- .../includes/EGScans/names_and_links.inc | 8 +- .../includes/EatManga/manga_information.inc | 4 +- .../includes/EatManga/names_and_links.inc | 6 +- .../EsMangaHere/manga_information.inc | 4 +- .../includes/EsMangaHere/names_and_links.inc | 4 +- .../ExtremeMangas/manga_information.inc | 4 +- .../ExtremeMangas/names_and_links.inc | 4 +- .../includes/Fakku/directory_page_number.inc | 2 +- .../includes/Fakku/manga_information.inc | 4 +- baseunits/includes/Fakku/names_and_links.inc | 6 +- .../includes/HugeManga/manga_information.inc | 6 +- .../includes/HugeManga/names_and_links.inc | 6 +- .../includes/IKomik/directory_page_number.inc | 4 +- .../includes/IKomik/manga_information.inc | 4 +- baseunits/includes/IKomik/names_and_links.inc | 6 +- .../includes/Imanhua/names_and_links.inc | 4 +- .../JapanShin/directory_page_number.inc | 8 +- .../includes/JapanShin/manga_information.inc | 2 +- .../includes/JapanShin/names_and_links.inc | 8 +- .../includes/Japscan/manga_information.inc | 4 +- .../includes/Japscan/names_and_links.inc | 8 +- .../includes/Kivmanga/manga_information.inc | 6 +- .../includes/Kivmanga/names_and_links.inc | 6 +- .../LectureEnLigne/directory_page_number.inc | 6 +- .../LectureEnLigne/manga_information.inc | 4 +- .../LectureEnLigne/names_and_links.inc | 10 +- .../includes/Mabuns/manga_information.inc | 4 +- baseunits/includes/Mabuns/names_and_links.inc | 6 +- .../Manga24h/directory_page_number.inc | 2 +- .../includes/Manga24h/manga_information.inc | 6 +- .../includes/Manga24h/names_and_links.inc | 6 +- .../MangaAe/directory_page_number.inc | 6 +- .../includes/MangaAe/manga_information.inc | 4 +- .../includes/MangaAe/names_and_links.inc | 6 +- .../includes/MangaAr/manga_information.inc | 4 +- .../includes/MangaAr/names_and_links.inc | 4 +- .../MangaAt/directory_page_number.inc | 6 +- .../includes/MangaAt/manga_information.inc | 4 +- .../includes/MangaAt/names_and_links.inc | 6 +- .../includes/MangaEsta/manga_information.inc | 4 +- .../includes/MangaEsta/names_and_links.inc | 6 +- .../MangaGo/directory_page_number.inc | 2 +- .../includes/MangaGo/manga_information.inc | 4 +- .../includes/MangaGo/names_and_links.inc | 8 +- .../MangaHost/directory_page_number.inc | 6 +- .../includes/MangaHost/manga_information.inc | 4 +- .../includes/MangaHost/names_and_links.inc | 8 +- .../includes/MangaKu/manga_information.inc | 4 +- .../includes/MangaKu/names_and_links.inc | 4 +- .../MangaLib_PL/manga_information.inc | 14 +- .../includes/MangaLib_PL/names_and_links.inc | 6 +- .../MangaMint/directory_page_number.inc | 2 +- .../includes/MangaMint/manga_information.inc | 6 +- .../includes/MangaMint/names_and_links.inc | 6 +- .../includes/MangaOku/manga_information.inc | 6 +- .../includes/MangaOku/names_and_links.inc | 12 +- .../MangaREADER_POR/manga_information.inc | 6 +- .../MangaREADER_POR/names_and_links.inc | 4 +- .../MangaTown/directory_page_number.inc | 4 +- .../includes/MangaTown/manga_information.inc | 4 +- .../includes/MangaTown/names_and_links.inc | 6 +- .../MangasPROJECT/manga_information.inc | 6 +- .../MangasPROJECT/names_and_links.inc | 4 +- .../includes/MeinManga/manga_information.inc | 8 +- .../includes/MeinManga/names_and_links.inc | 4 +- .../directory_page_number.inc | 4 +- .../MyReadingMangaInfo/manga_information.inc | 6 +- .../MyReadingMangaInfo/names_and_links.inc | 6 +- .../NHentai/directory_page_number.inc | 4 +- .../includes/NHentai/manga_information.inc | 6 +- .../includes/NHentai/names_and_links.inc | 6 +- .../NineManga/directory_page_number.inc | 22 +- .../includes/NineManga/manga_information.inc | 6 +- .../includes/NineManga/names_and_links.inc | 10 +- .../OneManga/directory_page_number.inc | 2 +- .../includes/OneManga/manga_information.inc | 4 +- .../includes/OneManga/names_and_links.inc | 6 +- .../PornComix/directory_page_number.inc | 4 +- .../includes/PornComix/manga_information.inc | 6 +- .../includes/PornComix/names_and_links.inc | 12 +- .../ReadMangaToday/directory_page_number.inc | 2 +- .../ReadMangaToday/manga_information.inc | 4 +- .../ReadMangaToday/names_and_links.inc | 6 +- .../S2Scans/directory_page_number.inc | 2 +- .../includes/S2Scans/manga_information.inc | 4 +- .../includes/S2Scans/names_and_links.inc | 6 +- .../includes/ScanManga/manga_information.inc | 4 +- .../includes/ScanManga/names_and_links.inc | 4 +- .../includes/Starkana/manga_information.inc | 4 +- .../includes/Starkana/names_and_links.inc | 4 +- .../TruyenTranhTuan/manga_information.inc | 4 +- .../TruyenTranhTuan/names_and_links.inc | 6 +- .../includes/Turkcraft/manga_information.inc | 6 +- .../includes/Turkcraft/names_and_links.inc | 4 +- .../includes/UnixManga/manga_information.inc | 4 +- .../includes/UnixManga/names_and_links.inc | 4 +- .../VnSharing/directory_page_number.inc | 2 +- .../includes/VnSharing/manga_information.inc | 4 +- .../includes/VnSharing/names_and_links.inc | 6 +- baseunits/uData.pas | 190 +++++++++--------- 120 files changed, 407 insertions(+), 407 deletions(-) diff --git a/baseunits/includes/AnimExtremist/manga_information.inc b/baseunits/includes/AnimExtremist/manga_information.inc index 70715521f..8249e04af 100644 --- a/baseunits/includes/AnimExtremist/manga_information.inc +++ b/baseunits/includes/AnimExtremist/manga_information.inc @@ -2,8 +2,8 @@ var i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(ANIMEEXTREMIST_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(ANIMEEXTREMIST_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/AnimExtremist/names_and_links.inc b/baseunits/includes/AnimExtremist/names_and_links.inc index 8970f4e24..d4e4d37eb 100644 --- a/baseunits/includes/AnimExtremist/names_and_links.inc +++ b/baseunits/includes/AnimExtremist/names_and_links.inc @@ -26,8 +26,8 @@ if Pos('id="manga" style="margin', parse[i]) <> 0 then begin Result := NO_ERROR; - names.Add(TrimLeft(TrimRight(parse[i + 4]))); - links.Add(StringReplace(GetString(parse[i + 3], 'href="', '">'), + ANames.Add(TrimLeft(TrimRight(parse[i + 4]))); + ALinks.Add(StringReplace(GetString(parse[i + 3], 'href="', '">'), WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [])); end; end; diff --git a/baseunits/includes/AnimeA/directory_page_number.inc b/baseunits/includes/AnimeA/directory_page_number.inc index f421c8afc..4efe91a29 100644 --- a/baseunits/includes/AnimeA/directory_page_number.inc +++ b/baseunits/includes/AnimeA/directory_page_number.inc @@ -27,7 +27,7 @@ 'http://manga.animea.net/browse.html?page=1') and (Pos('Next', parse[i + 1]) > 0) then begin - Page := StrToInt(TrimRight(TrimLeft(parse[i - 4]))); + APage := StrToInt(TrimRight(TrimLeft(parse[i - 4]))); Result := NO_ERROR; Source.Free; Exit; diff --git a/baseunits/includes/AnimeA/manga_information.inc b/baseunits/includes/AnimeA/manga_information.inc index 5e05c0cb8..b63cd4808 100644 --- a/baseunits/includes/AnimeA/manga_information.inc +++ b/baseunits/includes/AnimeA/manga_information.inc @@ -5,8 +5,8 @@ s: String; begin mangaInfo.website := WebsiteRoots[ANIMEA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ANIMEA_ID, URL + ANIMEA_SKIP); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(ANIMEA_ID, AURL + ANIMEA_SKIP); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/AnimeA/names_and_links.inc b/baseunits/includes/AnimeA/names_and_links.inc index 6e9efa3e1..7c8a33d5e 100644 --- a/baseunits/includes/AnimeA/names_and_links.inc +++ b/baseunits/includes/AnimeA/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + - ANIMEA_BROWSER + URL, 0) then + ANIMEA_BROWSER + AURL, 0) then begin Result := NET_PROBLEM; Source.Free; @@ -15,8 +15,8 @@ if Pos('manga_img', Source[i]) <> 0 then begin Result := NO_ERROR; - links.Add(GetString(Source[i], '"', '"')); - names.Add(GetString(Source[i], 'title="', ' Manga"')); + ALinks.Add(GetString(Source[i], '"', '"')); + ANames.Add(GetString(Source[i], 'title="', ' Manga"')); end; end; Source.Free; diff --git a/baseunits/includes/AnimeStory/manga_information.inc b/baseunits/includes/AnimeStory/manga_information.inc index 1605fe4e0..78693e1da 100644 --- a/baseunits/includes/AnimeStory/manga_information.inc +++ b/baseunits/includes/AnimeStory/manga_information.inc @@ -6,8 +6,8 @@ i, j: Cardinal; begin mangaInfo.website := WebsiteRoots[ANIMESTORY_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ANIMESTORY_ID, '/' + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(ANIMESTORY_ID, '/' + AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/AnimeStory/names_and_links.inc b/baseunits/includes/AnimeStory/names_and_links.inc index a820aa5b2..1595e7108 100644 --- a/baseunits/includes/AnimeStory/names_and_links.inc +++ b/baseunits/includes/AnimeStory/names_and_links.inc @@ -29,9 +29,9 @@ begin Result := NO_ERROR; s := StringFilter(parse[i + 2]); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := GetVal(parse[i + 1], 'href'); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; diff --git a/baseunits/includes/BlogTruyen/directory_page_number.inc b/baseunits/includes/BlogTruyen/directory_page_number.inc index 7ec9ddbdf..962083e37 100644 --- a/baseunits/includes/BlogTruyen/directory_page_number.inc +++ b/baseunits/includes/BlogTruyen/directory_page_number.inc @@ -26,7 +26,7 @@ if (Pos('[cuối]', parse[i]) > 0) then begin s := TrimRight(TrimLeft(GetString(parse[i - 1], 'LoadPage(', ')'))); - Page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Source.Free; Exit; diff --git a/baseunits/includes/BlogTruyen/manga_information.inc b/baseunits/includes/BlogTruyen/manga_information.inc index dadbb7363..c31c662bd 100644 --- a/baseunits/includes/BlogTruyen/manga_information.inc +++ b/baseunits/includes/BlogTruyen/manga_information.inc @@ -7,8 +7,8 @@ i, j: Cardinal; begin mangaInfo.website := WebsiteRoots[BLOGTRUYEN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(BLOGTRUYEN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(BLOGTRUYEN_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/BlogTruyen/names_and_links.inc b/baseunits/includes/BlogTruyen/names_and_links.inc index 0ee2a1064..9a0a616a6 100644 --- a/baseunits/includes/BlogTruyen/names_and_links.inc +++ b/baseunits/includes/BlogTruyen/names_and_links.inc @@ -7,9 +7,9 @@ Result := INFORMATION_NOT_FOUND; stream := TStringStream.Create(''); s := WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER; - s := BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(URL) + 1); + s := BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(AURL) + 1); while not HttpPostURL(WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER, - BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(URL) + 1), stream) do + BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(AURL) + 1), stream) do Sleep(32); Source.Text := stream.DataString; stream.Free; @@ -31,9 +31,9 @@ Result := NO_ERROR; s := StringFilter(TrimLeft( TrimRight(GetString(parse[i + 2], 'title="truyện tranh ', '">')))); - names.Add(HTMLEntitiesFilter(s)); - links.Add(GetVal(parse[i + 2], 'href="')); + ANames.Add(HTMLEntitiesFilter(s)); + ALinks.Add(GetVal(parse[i + 2], 'href="')); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/CentralDeMangas/directory_page_number.inc b/baseunits/includes/CentralDeMangas/directory_page_number.inc index af364441a..6696ea991 100644 --- a/baseunits/includes/CentralDeMangas/directory_page_number.inc +++ b/baseunits/includes/CentralDeMangas/directory_page_number.inc @@ -26,7 +26,7 @@ if (Pos('/mangas/list/*/', parse[i]) > 0) then begin s := TrimRight(TrimLeft(GetString(parse[i], '/mangas/list/*/', '">'))); - page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Exit; end; diff --git a/baseunits/includes/CentralDeMangas/manga_information.inc b/baseunits/includes/CentralDeMangas/manga_information.inc index 100a32d85..7ccc22421 100644 --- a/baseunits/includes/CentralDeMangas/manga_information.inc +++ b/baseunits/includes/CentralDeMangas/manga_information.inc @@ -4,8 +4,8 @@ i: Cardinal; begin mangaInfo.website := WebsiteRoots[CENTRALDEMANGAS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(CENTRALDEMANGAS_ID, URL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then + mangaInfo.url := FillMangaSiteHost(CENTRALDEMANGAS_ID, AURL); + if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/CentralDeMangas/names_and_links.inc b/baseunits/includes/CentralDeMangas/names_and_links.inc index f3bb5a7e9..e31fd2d60 100644 --- a/baseunits/includes/CentralDeMangas/names_and_links.inc +++ b/baseunits/includes/CentralDeMangas/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + - CENTRALDEMANGAS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1), 0) then + CENTRALDEMANGAS_BROWSER + '/' + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -29,10 +29,10 @@ begin Result := NO_ERROR; s := StringFilter(parse[i + 1]); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := StringReplace(GetString(parse[i], 'href="', '"'), WebsiteRoots[CENTRALDEMANGAS_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; diff --git a/baseunits/includes/CentrumMangi_PL/manga_information.inc b/baseunits/includes/CentrumMangi_PL/manga_information.inc index 091a25a69..e0e5894ce 100644 --- a/baseunits/includes/CentrumMangi_PL/manga_information.inc +++ b/baseunits/includes/CentrumMangi_PL/manga_information.inc @@ -6,8 +6,8 @@ isExtractChapter: Boolean = False; begin mangaInfo.website := WebsiteRoots[CENTRUMMANGI_PL_ID, 0]; - mangaInfo.url := FillMangaSiteHost(CENTRUMMANGI_PL_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(CENTRUMMANGI_PL_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/CentrumMangi_PL/names_and_links.inc b/baseunits/includes/CentrumMangi_PL/names_and_links.inc index 83fd8ee4b..0b7023efb 100644 --- a/baseunits/includes/CentrumMangi_PL/names_and_links.inc +++ b/baseunits/includes/CentrumMangi_PL/names_and_links.inc @@ -31,9 +31,9 @@ if (Pos('<td style="width:45%;text-align: left;">', parse[i]) > 0) then begin Result := NO_ERROR; - links.Add(StringReplace(GetVal(parse[i + 1], 'href'), + ALinks.Add(StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[CENTRUMMANGI_PL_ID, 1], '', [rfIgnoreCase])); - names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 2])))); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 2])))); end; //if isExtractItem then @@ -42,11 +42,11 @@ // (Pos('/spis/', parse[i]) = 0) then // begin // Result := NO_ERROR; - // links.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[CENTRUMMANGI_PL_ID, 1], '', [rfIgnoreCase])); - // names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); + // ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[CENTRUMMANGI_PL_ID, 1], '', [rfIgnoreCase])); + // ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); // end; //end; end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/DM5/directory_page_number.inc b/baseunits/includes/DM5/directory_page_number.inc index 24440ff8e..deef3fbef 100644 --- a/baseunits/includes/DM5/directory_page_number.inc +++ b/baseunits/includes/DM5/directory_page_number.inc @@ -25,7 +25,7 @@ if (Pos('/mangas/list/*/', parse[i]) > 0) then begin s := TrimRight(TrimLeft(GetString(parse[i], '/mangas/list/*/', '">'))); - page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Exit; end; diff --git a/baseunits/includes/Dynasty-Scans/directory_page_number.inc b/baseunits/includes/Dynasty-Scans/directory_page_number.inc index 0fa3abcdf..b2f9576b2 100644 --- a/baseunits/includes/Dynasty-Scans/directory_page_number.inc +++ b/baseunits/includes/Dynasty-Scans/directory_page_number.inc @@ -1,6 +1,6 @@ function GetDynastyScansDirectoryPageNumber: Byte; begin Source.Free; - Page := Length(DYNASTYSCANS_BROWSER); + APage := Length(DYNASTYSCANS_BROWSER); Result := NO_ERROR; end; diff --git a/baseunits/includes/Dynasty-Scans/manga_information.inc b/baseunits/includes/Dynasty-Scans/manga_information.inc index f7615aef9..64858eaf4 100644 --- a/baseunits/includes/Dynasty-Scans/manga_information.inc +++ b/baseunits/includes/Dynasty-Scans/manga_information.inc @@ -4,8 +4,8 @@ hs: String = ''; begin mangaInfo.website := WebsiteRoots[DYNASTYSCANS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(DYNASTYSCANS_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(DYNASTYSCANS_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/Dynasty-Scans/names_and_links.inc b/baseunits/includes/Dynasty-Scans/names_and_links.inc index c38287f2c..07ef40bd3 100644 --- a/baseunits/includes/Dynasty-Scans/names_and_links.inc +++ b/baseunits/includes/Dynasty-Scans/names_and_links.inc @@ -4,7 +4,7 @@ s: string; begin Result := INFORMATION_NOT_FOUND; - i := StrToIntDef(URL, 0); + i := StrToIntDef(AURL, 0); if i >= Length(DYNASTYSCANS_BROWSER) then begin Source.Free; @@ -26,8 +26,8 @@ if GetTagName(parse[i]) = 'dd' then if GetTagName(parse[i+1]) = 'a' then begin - links.Add(GetVal(parse[i+1], 'href')); - names.Add(CommonStringFilter(parse[i+2])); + ALinks.Add(GetVal(parse[i+1], 'href')); + ANames.Add(CommonStringFilter(parse[i+2])); end; Result := NO_ERROR; diff --git a/baseunits/includes/EGScans/manga_information.inc b/baseunits/includes/EGScans/manga_information.inc index e63e10616..6fd781efc 100644 --- a/baseunits/includes/EGScans/manga_information.inc +++ b/baseunits/includes/EGScans/manga_information.inc @@ -5,8 +5,8 @@ i: Cardinal; begin mangaInfo.website := WebsiteRoots[EGSCANS_ID, 0]; - mangaInfo.url :=FillMangaSiteHost(EGSCANS_ID, '/' + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url :=FillMangaSiteHost(EGSCANS_ID, '/' + AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -57,7 +57,7 @@ (Pos('<option value="', parse[i]) > 0) then begin Inc(mangaInfo.numChapter); - s := '/' + URL + '/' + StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[EGSCANS_ID, 1], '', []); + s := '/' + AURL + '/' + StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[EGSCANS_ID, 1], '', []); mangaInfo.chapterLinks.Add(s); s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); diff --git a/baseunits/includes/EGScans/names_and_links.inc b/baseunits/includes/EGScans/names_and_links.inc index 7df0bf512..d192b7201 100644 --- a/baseunits/includes/EGScans/names_and_links.inc +++ b/baseunits/includes/EGScans/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[EGSCANS_ID, 1] + - EGSCANS_BROWSER + '/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then + EGSCANS_BROWSER + '/' + IntToStr(StrToInt(AURL) + 1) + '/', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -29,14 +29,14 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := StringReplace(GetVal(parse[i], 'value="'), WebsiteRoots[S2SCAN_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); end; if Pos('<select name="manga"', parse[i]) > 0 then Break; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/EatManga/manga_information.inc b/baseunits/includes/EatManga/manga_information.inc index d53ce8cf5..eb4ecf948 100644 --- a/baseunits/includes/EatManga/manga_information.inc +++ b/baseunits/includes/EatManga/manga_information.inc @@ -4,8 +4,8 @@ i, j: Cardinal; begin mangaInfo.website := WebsiteRoots[EATMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(EATMANGA_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(EATMANGA_ID, AURL);// + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/EatManga/names_and_links.inc b/baseunits/includes/EatManga/names_and_links.inc index 1b6ce45f6..31f7f4275 100644 --- a/baseunits/includes/EatManga/names_and_links.inc +++ b/baseunits/includes/EatManga/names_and_links.inc @@ -29,10 +29,10 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := GetVal(parse[i], 'href="'); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/EsMangaHere/manga_information.inc b/baseunits/includes/EsMangaHere/manga_information.inc index 69b647f00..edeb728a8 100644 --- a/baseunits/includes/EsMangaHere/manga_information.inc +++ b/baseunits/includes/EsMangaHere/manga_information.inc @@ -3,8 +3,8 @@ i, j: Cardinal; begin mangaInfo.website := WebsiteRoots[ESMANGAHERE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ESMANGAHERE_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(ESMANGAHERE_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/EsMangaHere/names_and_links.inc b/baseunits/includes/EsMangaHere/names_and_links.inc index d9c94ae0d..162d68096 100644 --- a/baseunits/includes/EsMangaHere/names_and_links.inc +++ b/baseunits/includes/EsMangaHere/names_and_links.inc @@ -26,8 +26,8 @@ if Pos('manga_info', parse[i]) <> 0 then begin Result := NO_ERROR; - names.Add(StringFilter(GetString(parse[i], 'rel="', '" href'))); - links.Add(StringReplace(GetString(parse[i], 'href="', '">'), + ANames.Add(StringFilter(GetString(parse[i], 'rel="', '" href'))); + ALinks.Add(StringReplace(GetString(parse[i], 'href="', '">'), WebsiteRoots[ESMANGAHERE_ID, 1], '', [])); end; end; diff --git a/baseunits/includes/ExtremeMangas/manga_information.inc b/baseunits/includes/ExtremeMangas/manga_information.inc index 162d73ad8..5de28eb36 100644 --- a/baseunits/includes/ExtremeMangas/manga_information.inc +++ b/baseunits/includes/ExtremeMangas/manga_information.inc @@ -5,8 +5,8 @@ regxp: TRegExpr; begin mangaInfo.website := WebsiteRoots[EXTREMEMANGAS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(EXTREMEMANGAS_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(EXTREMEMANGAS_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/ExtremeMangas/names_and_links.inc b/baseunits/includes/ExtremeMangas/names_and_links.inc index 51aea709b..1fb089359 100644 --- a/baseunits/includes/ExtremeMangas/names_and_links.inc +++ b/baseunits/includes/ExtremeMangas/names_and_links.inc @@ -41,10 +41,10 @@ if isExtractNames and (Pos('<a', parse[i]) > 0) then begin Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); s := Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[EXTREMEMANGAS_ID, 1], '', [rfIgnoreCase])); s := Trim(regxp.Replace(s, '/', False)); - links.Add(s); + ALinks.Add(s); end; end; regxp.Free; diff --git a/baseunits/includes/Fakku/directory_page_number.inc b/baseunits/includes/Fakku/directory_page_number.inc index caa8361ac..6f30a509f 100644 --- a/baseunits/includes/Fakku/directory_page_number.inc +++ b/baseunits/includes/Fakku/directory_page_number.inc @@ -27,7 +27,7 @@ 'Last Page') then begin s := TrimRight(TrimLeft(GetString(parse[i], '/page/', '"'))); - Page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Source.Free; Exit; diff --git a/baseunits/includes/Fakku/manga_information.inc b/baseunits/includes/Fakku/manga_information.inc index a5d29243b..3839da21a 100644 --- a/baseunits/includes/Fakku/manga_information.inc +++ b/baseunits/includes/Fakku/manga_information.inc @@ -4,8 +4,8 @@ isExtractSummary: Boolean = False; i: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(FAKKU_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(FAKKU_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/Fakku/names_and_links.inc b/baseunits/includes/Fakku/names_and_links.inc index be64020cc..582fb222e 100644 --- a/baseunits/includes/Fakku/names_and_links.inc +++ b/baseunits/includes/Fakku/names_and_links.inc @@ -3,7 +3,7 @@ i: Cardinal; begin Result := INFORMATION_NOT_FOUND; - i := StrToInt(URL); + i := StrToInt(AURL); if i = 0 then begin if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then @@ -39,8 +39,8 @@ if Pos('class="content-title"', parse[i]) > 0 then begin Result := NO_ERROR; - names.Add(Trim(GetVal(parse[i], 'title'))); - links.Add(StringReplace(GetVal(parse[i], 'href'), + ANames.Add(Trim(GetVal(parse[i], 'title'))); + ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[FAKKU_ID, 1], '', [])); end; end; diff --git a/baseunits/includes/HugeManga/manga_information.inc b/baseunits/includes/HugeManga/manga_information.inc index 2a439531a..a4257581a 100644 --- a/baseunits/includes/HugeManga/manga_information.inc +++ b/baseunits/includes/HugeManga/manga_information.inc @@ -5,8 +5,8 @@ i, j: Cardinal; begin mangaInfo.website := WebsiteRoots[HUGEMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(HUGEMANGA_ID, HUGEMANGA_BROWSER + URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(HUGEMANGA_ID, HUGEMANGA_BROWSER + AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -50,7 +50,7 @@ if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then begin Inc(mangaInfo.numChapter); - s := '/' + URL + '/' + GetVal(parse[i], 'value'); + s := '/' + AURL + '/' + GetVal(parse[i], 'value'); mangaInfo.chapterLinks.Add(s); s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); diff --git a/baseunits/includes/HugeManga/names_and_links.inc b/baseunits/includes/HugeManga/names_and_links.inc index 29c4db3b4..45f089769 100644 --- a/baseunits/includes/HugeManga/names_and_links.inc +++ b/baseunits/includes/HugeManga/names_and_links.inc @@ -29,10 +29,10 @@ begin Result := NO_ERROR; s := StringFilter(parse[i + 1]); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := GetVal(parse[i], 'value'); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/IKomik/directory_page_number.inc b/baseunits/includes/IKomik/directory_page_number.inc index 60e9b807b..35f0197f6 100644 --- a/baseunits/includes/IKomik/directory_page_number.inc +++ b/baseunits/includes/IKomik/directory_page_number.inc @@ -2,7 +2,7 @@ var i: Integer; begin - Page := 0; + APage := 0; Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[IKOMIK_ID, 1] + IKOMIK_BROWSER, 0) then begin @@ -27,7 +27,7 @@ if (Pos('/page-', parse[i]) > 0) and (Pos('last', parse[i + 1]) > 0) then begin Result := NO_ERROR; - Page := StrToIntDef(ReplaceRegExpr('^.*\/page-(\d+)\/.*$', GetVal(parse[i], 'href'), '$1', True), 1); + APage := StrToIntDef(ReplaceRegExpr('^.*\/page-(\d+)\/.*$', GetVal(parse[i], 'href'), '$1', True), 1); Break; end; end; diff --git a/baseunits/includes/IKomik/manga_information.inc b/baseunits/includes/IKomik/manga_information.inc index 2999d620c..2b3677760 100644 --- a/baseunits/includes/IKomik/manga_information.inc +++ b/baseunits/includes/IKomik/manga_information.inc @@ -4,8 +4,8 @@ i: Integer; begin mangaInfo.website := WebsiteRoots[IKOMIK_ID, 0]; - mangaInfo.url := FillMangaSiteHost(IKOMIK_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(IKOMIK_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/IKomik/names_and_links.inc b/baseunits/includes/IKomik/names_and_links.inc index b7a720e13..4d57b2b69 100644 --- a/baseunits/includes/IKomik/names_and_links.inc +++ b/baseunits/includes/IKomik/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[IKOMIK_ID, 1] + IKOMIK_BROWSER + - 'page-' + IntToStr(StrToInt(URL) + 1) + '/', 0) then + 'page-' + IntToStr(StrToInt(AURL) + 1) + '/', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -26,8 +26,8 @@ if (Pos('class="list"', parse[i]) > 0) and (Pos('<a', parse[i]) > 0) then begin Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - links.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[IKOMIK_ID, 1], '', [rfIgnoreCase])); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); + ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[IKOMIK_ID, 1], '', [rfIgnoreCase])); end; end; Source.Free; diff --git a/baseunits/includes/Imanhua/names_and_links.inc b/baseunits/includes/Imanhua/names_and_links.inc index 949efedb1..ad2ba6c6a 100644 --- a/baseunits/includes/Imanhua/names_and_links.inc +++ b/baseunits/includes/Imanhua/names_and_links.inc @@ -28,9 +28,9 @@ begin Result := NO_ERROR; s := StringFilter(parse[i + 1]); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := GetVal(parse[i], 'href'); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; diff --git a/baseunits/includes/JapanShin/directory_page_number.inc b/baseunits/includes/JapanShin/directory_page_number.inc index 8ff20c3c0..7a5574d12 100644 --- a/baseunits/includes/JapanShin/directory_page_number.inc +++ b/baseunits/includes/JapanShin/directory_page_number.inc @@ -24,7 +24,7 @@ Exit; end; - Page := 0; + APage := 0; regx := TRegExpr.Create; regx.Expression := '^.*/reader/list/(\d+)/.*$'; for i := 0 to parse.Count - 1 do @@ -34,11 +34,11 @@ begin Result := NO_ERROR; p := StrToIntDef(regx.Replace(parse[i], '$1', True), 0); - if p > Page then - Page := p; + if p > APage then + APage := p; end; end; regx.Free; Source.Free; Result := NO_ERROR; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/JapanShin/manga_information.inc b/baseunits/includes/JapanShin/manga_information.inc index b5d0c3d4b..8fd573350 100644 --- a/baseunits/includes/JapanShin/manga_information.inc +++ b/baseunits/includes/JapanShin/manga_information.inc @@ -4,7 +4,7 @@ begin mangaInfo.website := WebsiteRoots[JAPANSHIN_ID, 0]; Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), FillMangaSiteHost(JAPANSHIN_ID, URL), Reconnect) then + if not GetPage(TObject(Source), FillMangaSiteHost(JAPANSHIN_ID, AURL), AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/JapanShin/names_and_links.inc b/baseunits/includes/JapanShin/names_and_links.inc index cbf9d5319..b7a17c870 100644 --- a/baseunits/includes/JapanShin/names_and_links.inc +++ b/baseunits/includes/JapanShin/names_and_links.inc @@ -6,7 +6,7 @@ Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[JAPANSHIN_ID, 1] + JAPANSHIN_BROWSER + - IntToStr(StrToInt(URL) + 1) + '/', + IntToStr(StrToInt(AURL) + 1) + '/', 0) then begin Result := NET_PROBLEM; @@ -32,10 +32,10 @@ begin Result := NO_ERROR; s := GetVal(parse[i], 'href'); - links.Add(StringReplace(s, WebsiteRoots[JAPANSHIN_ID, 1], '', [rfIgnoreCase])); + ALinks.Add(StringReplace(s, WebsiteRoots[JAPANSHIN_ID, 1], '', [rfIgnoreCase])); s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - names.Add(s); + ANames.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/Japscan/manga_information.inc b/baseunits/includes/Japscan/manga_information.inc index f95a3f667..6c3851e81 100644 --- a/baseunits/includes/Japscan/manga_information.inc +++ b/baseunits/includes/Japscan/manga_information.inc @@ -8,8 +8,8 @@ regx: TRegExpr; begin - mangaInfo.url := FillMangaSiteHost(JAPSCAN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(JAPSCAN_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/Japscan/names_and_links.inc b/baseunits/includes/Japscan/names_and_links.inc index 4cd6d280e..8d27137e5 100644 --- a/baseunits/includes/Japscan/names_and_links.inc +++ b/baseunits/includes/Japscan/names_and_links.inc @@ -20,16 +20,16 @@ if parse.Count = 0 then Exit; - links.Clear; - names.Clear; + ALinks.Clear; + ANames.Clear; for i := 0 to parse.Count - 1 do begin if (Pos('class="cell', parse[i]) > 0) then if (Pos(' href="/mangas/', parse[i + 1]) > 0) then begin Result := NO_ERROR; - links.Add(GetVal(parse[i + 1], 'href')); - names.Add(Trim(parse[i + 2])); + ALinks.Add(GetVal(parse[i + 1], 'href')); + ANames.Add(Trim(parse[i + 2])); end; end; end; \ No newline at end of file diff --git a/baseunits/includes/Kivmanga/manga_information.inc b/baseunits/includes/Kivmanga/manga_information.inc index 6dba60146..67585832e 100644 --- a/baseunits/includes/Kivmanga/manga_information.inc +++ b/baseunits/includes/Kivmanga/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapter: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(KIVMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(KIVMANGA_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -47,7 +47,7 @@ if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then begin Inc(mangaInfo.numChapter); - s := URL + '/' + GetVal(parse[i], 'value'); + s := AURL + '/' + GetVal(parse[i], 'value'); mangaInfo.chapterLinks.Add(s); s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); diff --git a/baseunits/includes/Kivmanga/names_and_links.inc b/baseunits/includes/Kivmanga/names_and_links.inc index bd4346d5c..5e9b425af 100644 --- a/baseunits/includes/Kivmanga/names_and_links.inc +++ b/baseunits/includes/Kivmanga/names_and_links.inc @@ -28,10 +28,10 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := '/' + GetVal(parse[i], 'value'); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/LectureEnLigne/directory_page_number.inc b/baseunits/includes/LectureEnLigne/directory_page_number.inc index 20aa3be4c..ef7233f21 100644 --- a/baseunits/includes/LectureEnLigne/directory_page_number.inc +++ b/baseunits/includes/LectureEnLigne/directory_page_number.inc @@ -24,7 +24,7 @@ Exit; end; - Page := 0; + APage := 0; regx := TRegExpr.Create; regx.Expression := '^.*\?page=liste.*ordre=.*p=(\d+)\".*$'; for i := 0 to parse.Count - 1 do @@ -34,8 +34,8 @@ begin Result := NO_ERROR; p := StrToIntDef(regx.Replace(parse[i], '$1', True), 0); - if p > Page then - Page := p; + if p > APage then + APage := p; end; end; regx.Free; diff --git a/baseunits/includes/LectureEnLigne/manga_information.inc b/baseunits/includes/LectureEnLigne/manga_information.inc index 1e832ce87..32918aef6 100644 --- a/baseunits/includes/LectureEnLigne/manga_information.inc +++ b/baseunits/includes/LectureEnLigne/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapter: Boolean = False; i, j: Integer; begin - mangaInfo.url := FillMangaSiteHost(LECTUREENLIGNE_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(LECTUREENLIGNE_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/LectureEnLigne/names_and_links.inc b/baseunits/includes/LectureEnLigne/names_and_links.inc index 39107b2a9..a9ba9deb4 100644 --- a/baseunits/includes/LectureEnLigne/names_and_links.inc +++ b/baseunits/includes/LectureEnLigne/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + - LECTUREENLIGNE_BROWSER + '&p=' + IntToStr(StrToInt(URL) + 1), 0) then + LECTUREENLIGNE_BROWSER + '&p=' + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -27,16 +27,16 @@ if (Pos('option value=', parse[i]) > 0) then begin Result:= NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i+1])))); - links.Add(StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[LECTUREENLIGNE_ID,1], '', [])); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i+1])))); + ALinks.Add(StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[LECTUREENLIGNE_ID,1], '', [])); end; } if (Pos('class="infoImages"', parse[i]) > 0) and (Pos('href="', parse[i]) > 0) then begin Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); - links.Add('/' + GetVal(parse[i], 'href')); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); + ALinks.Add('/' + GetVal(parse[i], 'href')); end; end; Source.Free; diff --git a/baseunits/includes/Mabuns/manga_information.inc b/baseunits/includes/Mabuns/manga_information.inc index 13edbd1ba..1312df2e1 100644 --- a/baseunits/includes/Mabuns/manga_information.inc +++ b/baseunits/includes/Mabuns/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapter: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(MABUNS_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MABUNS_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/Mabuns/names_and_links.inc b/baseunits/includes/Mabuns/names_and_links.inc index afe0ab886..847753490 100644 --- a/baseunits/includes/Mabuns/names_and_links.inc +++ b/baseunits/includes/Mabuns/names_and_links.inc @@ -27,11 +27,11 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := StringReplace(GetVal(parse[i + 6], 'href'), WebsiteRoots[MABUNS_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/Manga24h/directory_page_number.inc b/baseunits/includes/Manga24h/directory_page_number.inc index 74fdc1a03..5edda3a3c 100644 --- a/baseunits/includes/Manga24h/directory_page_number.inc +++ b/baseunits/includes/Manga24h/directory_page_number.inc @@ -26,7 +26,7 @@ if (Pos('Pages (', parse[i]) > 0) then begin s := GetString(parse[i], 'Pages (', ')'); - Page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Source.Free; Exit; diff --git a/baseunits/includes/Manga24h/manga_information.inc b/baseunits/includes/Manga24h/manga_information.inc index 569a811b4..2b4cb903a 100644 --- a/baseunits/includes/Manga24h/manga_information.inc +++ b/baseunits/includes/Manga24h/manga_information.inc @@ -6,10 +6,10 @@ isExtractChapters: Boolean = False; isExtractSummary: Boolean = False; begin - // patchURL:= UTF8ToANSI(URL); + // patchURL:= UTF8ToANSI(AURL); // Insert('comics/', patchURL, 10); - mangaInfo.url := FillMangaSiteHost(MANGA24H_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGA24H_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/Manga24h/names_and_links.inc b/baseunits/includes/Manga24h/names_and_links.inc index 536dcc856..82b47cdbc 100644 --- a/baseunits/includes/Manga24h/names_and_links.inc +++ b/baseunits/includes/Manga24h/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + - MANGA24H_BROWSER + IntToStr(StrToInt(URL) + 1), 0) then + MANGA24H_BROWSER + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -30,8 +30,8 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(s); - links.Add('/' + StringReplace(GetVal(parse[i - 1], 'href'), WebsiteRoots[MANGA24H_ID, 1], '', [])); + ANames.Add(s); + ALinks.Add('/' + StringReplace(GetVal(parse[i - 1], 'href'), WebsiteRoots[MANGA24H_ID, 1], '', [])); end; end; Source.Free; diff --git a/baseunits/includes/MangaAe/directory_page_number.inc b/baseunits/includes/MangaAe/directory_page_number.inc index f4d105735..d9b161bf8 100644 --- a/baseunits/includes/MangaAe/directory_page_number.inc +++ b/baseunits/includes/MangaAe/directory_page_number.inc @@ -16,7 +16,7 @@ Parser.OnFoundText := OnText; Parser.Exec; Parser.Free; - Page := 1; + APage := 1; if parse.Count > 0 then for i := 0 to parse.Count - 1 do begin @@ -28,8 +28,8 @@ begin s := ReplaceRegExpr('^.*/page\:(\d+)$', GetVal(parse[i], 'href'), '$1', True); p := StrToIntDef(s, 0); - if p > Page then - Page := p; + if p > APage then + APage := p; end; end; Result := NO_ERROR; diff --git a/baseunits/includes/MangaAe/manga_information.inc b/baseunits/includes/MangaAe/manga_information.inc index 1142484b1..00a229e02 100644 --- a/baseunits/includes/MangaAe/manga_information.inc +++ b/baseunits/includes/MangaAe/manga_information.inc @@ -6,8 +6,8 @@ isExtractGenres : Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGAAE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAAE_ID, URL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAAE_ID, AURL); + if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaAe/names_and_links.inc b/baseunits/includes/MangaAe/names_and_links.inc index 37ff3f4ec..999b12294 100644 --- a/baseunits/includes/MangaAe/names_and_links.inc +++ b/baseunits/includes/MangaAe/names_and_links.inc @@ -6,7 +6,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + - MANGAAE_BROWSER + 'page:' + IntToStr(StrToInt(URL) + 1), 0) then + MANGAAE_BROWSER + 'page:' + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -36,8 +36,8 @@ s := GetVal(parse[i], 'href'); if regx.Exec(s) then begin - links.Add(s); - names.Add(CommonStringFilter(parse[i + 1])); + ALinks.Add(s); + ANames.Add(CommonStringFilter(parse[i + 1])); end; end; end; diff --git a/baseunits/includes/MangaAr/manga_information.inc b/baseunits/includes/MangaAr/manga_information.inc index 91bca2bbd..475aeeb34 100644 --- a/baseunits/includes/MangaAr/manga_information.inc +++ b/baseunits/includes/MangaAr/manga_information.inc @@ -3,8 +3,8 @@ s: String; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(MANGAAR_ID, URL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAAR_ID, AURL); + if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaAr/names_and_links.inc b/baseunits/includes/MangaAr/names_and_links.inc index ff451e7b0..7c7e75814 100644 --- a/baseunits/includes/MangaAr/names_and_links.inc +++ b/baseunits/includes/MangaAr/names_and_links.inc @@ -34,10 +34,10 @@ begin s := GetVal(parse[i], 'href'); s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); s := Trim(StringFilter(parse[i + 1])); s := HTMLEntitiesFilter(s); - names.Add(s); + ANames.Add(s); end; end; end; diff --git a/baseunits/includes/MangaAt/directory_page_number.inc b/baseunits/includes/MangaAt/directory_page_number.inc index 0f7ef5944..a51086249 100644 --- a/baseunits/includes/MangaAt/directory_page_number.inc +++ b/baseunits/includes/MangaAt/directory_page_number.inc @@ -25,7 +25,7 @@ if parse.Count > 0 then begin - Page := 0; + APage := 0; regx := TRegExpr.Create; try regx.Expression := '^.*/manga/page\:(\d+)$'; @@ -36,8 +36,8 @@ s := GetVal(parse[i], 'href'); s := regx.Replace(s, '$1', True); p := StrToIntDef(s, 0); - if p > Page then - Page := p; + if p > APage then + APage := p; end; finally regx.Free; diff --git a/baseunits/includes/MangaAt/manga_information.inc b/baseunits/includes/MangaAt/manga_information.inc index 0918f12c0..b1935a676 100644 --- a/baseunits/includes/MangaAt/manga_information.inc +++ b/baseunits/includes/MangaAt/manga_information.inc @@ -4,8 +4,8 @@ i, j: Integer; begin mangaInfo.website := WebsiteRoots[MANGAAT_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAAT_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAAT_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaAt/names_and_links.inc b/baseunits/includes/MangaAt/names_and_links.inc index fbea1a8b6..cba90e1d2 100644 --- a/baseunits/includes/MangaAt/names_and_links.inc +++ b/baseunits/includes/MangaAt/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGAAT_ID, 1] + - '/manga/page:' + IntToStr(StrToInt(URL) + 1), 1) then + '/manga/page:' + IntToStr(StrToInt(AURL) + 1), 1) then begin Result := NET_PROBLEM; Source.Free; @@ -27,8 +27,8 @@ if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'manga') then begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter(parse[i + 1])); + ALinks.Add(GetVal(parse[i], 'href')); + ANames.Add(CommonStringFilter(parse[i + 1])); end; end; diff --git a/baseunits/includes/MangaEsta/manga_information.inc b/baseunits/includes/MangaEsta/manga_information.inc index fea20e879..28156456d 100644 --- a/baseunits/includes/MangaEsta/manga_information.inc +++ b/baseunits/includes/MangaEsta/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapter: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(MANGAESTA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAESTA_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaEsta/names_and_links.inc b/baseunits/includes/MangaEsta/names_and_links.inc index b42a8e304..9f0fe0930 100644 --- a/baseunits/includes/MangaEsta/names_and_links.inc +++ b/baseunits/includes/MangaEsta/names_and_links.inc @@ -29,11 +29,11 @@ Result := NO_ERROR; s := StringFilter(TrimLeft( TrimRight(GetVal(parse[i + 3], 'title')))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := StringReplace(GetVal(parse[i + 2], 'href'), WebsiteRoots[MANGAESTA_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/MangaGo/directory_page_number.inc b/baseunits/includes/MangaGo/directory_page_number.inc index 8e976ce7b..b6cf48981 100644 --- a/baseunits/includes/MangaGo/directory_page_number.inc +++ b/baseunits/includes/MangaGo/directory_page_number.inc @@ -26,7 +26,7 @@ if (Pos('class="pagination"', parse[i]) <> 0) then begin s := TrimLeft(TrimRight(GetVal(parse[i], 'total'))); - Page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Source.Free; Exit; diff --git a/baseunits/includes/MangaGo/manga_information.inc b/baseunits/includes/MangaGo/manga_information.inc index 480a76f1c..96a2a2aa3 100644 --- a/baseunits/includes/MangaGo/manga_information.inc +++ b/baseunits/includes/MangaGo/manga_information.inc @@ -5,8 +5,8 @@ isExtractChapters: Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGAGO_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAGO_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAGO_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaGo/names_and_links.inc b/baseunits/includes/MangaGo/names_and_links.inc index c2a9545df..7bbf0d2d8 100644 --- a/baseunits/includes/MangaGo/names_and_links.inc +++ b/baseunits/includes/MangaGo/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + - MANGAGO_BROWSER + IntToStr(StrToInt(URL) + 1) + '/', 0) then + MANGAGO_BROWSER + IntToStr(StrToInt(AURL) + 1) + '/', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -28,11 +28,11 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := GetVal(parse[i + 1], 'href'); s := StringReplace(s, WebsiteRoots[MANGAGO_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/MangaHost/directory_page_number.inc b/baseunits/includes/MangaHost/directory_page_number.inc index bd86b03ef..259a977fc 100644 --- a/baseunits/includes/MangaHost/directory_page_number.inc +++ b/baseunits/includes/MangaHost/directory_page_number.inc @@ -23,14 +23,14 @@ Exit; end; - Page := 1; + APage := 1; for i := parse.Count - 1 downto 2 do begin if (Pos('<a', parse[i]) > 0) and (Pos('class="last', parse[i]) > 0) then begin p := StrToIntDef(ReplaceRegExpr('^.*/(\d+)$', GetVal(parse[i], 'href'), '$1', True), 0); - if Page < p then - Page := p; + if APage < p then + APage := p; Break; end; end; diff --git a/baseunits/includes/MangaHost/manga_information.inc b/baseunits/includes/MangaHost/manga_information.inc index d36520e2f..e27df622d 100644 --- a/baseunits/includes/MangaHost/manga_information.inc +++ b/baseunits/includes/MangaHost/manga_information.inc @@ -5,8 +5,8 @@ isExtractSummary: Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGAHOST_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAHOST_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAHOST_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaHost/names_and_links.inc b/baseunits/includes/MangaHost/names_and_links.inc index 93430f0b4..fcf6ac062 100644 --- a/baseunits/includes/MangaHost/names_and_links.inc +++ b/baseunits/includes/MangaHost/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGAHOST_ID, 1] + - MANGAHOST_BROWSER + '/page/' + IntToStr(StrToInt(URL) + 1), 0) then + MANGAHOST_BROWSER + '/page/' + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -26,9 +26,9 @@ if (Pos('<a', parse[i]) > 0) and (Pos('class="pull-left', parse[i]) > 0) and (Pos('title=', parse[i]) > 0) then begin - links.Add(GetVal(parse[i], 'href')); - //names.Add(CommonStringFilter(GetVal(parse[i], 'title'))); - names.Add(CommonStringFilter(parse[i + 6])); + ALinks.Add(GetVal(parse[i], 'href')); + //ANames.Add(CommonStringFilter(GetVal(parse[i], 'title'))); + ANames.Add(CommonStringFilter(parse[i + 6])); end; end; Result := NO_ERROR; diff --git a/baseunits/includes/MangaKu/manga_information.inc b/baseunits/includes/MangaKu/manga_information.inc index 35f0923b2..2a9e722c0 100644 --- a/baseunits/includes/MangaKu/manga_information.inc +++ b/baseunits/includes/MangaKu/manga_information.inc @@ -5,11 +5,11 @@ isExtractChapter: Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGAKU_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAKU_ID, URL); + mangaInfo.url := FillMangaSiteHost(MANGAKU_ID, AURL); if mangaInfo.url <> '' then if mangaInfo.url[Length(mangaInfo.url)] <> '/' then mangaInfo.url := mangaInfo.url + '/'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaKu/names_and_links.inc b/baseunits/includes/MangaKu/names_and_links.inc index 9555930cc..cc4376c2b 100644 --- a/baseunits/includes/MangaKu/names_and_links.inc +++ b/baseunits/includes/MangaKu/names_and_links.inc @@ -30,8 +30,8 @@ begin if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'screenshot') then begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter(parse[i + 1])); + ALinks.Add(GetVal(parse[i], 'href')); + ANames.Add(CommonStringFilter(parse[i + 1])); end; end; diff --git a/baseunits/includes/MangaLib_PL/manga_information.inc b/baseunits/includes/MangaLib_PL/manga_information.inc index 0c2c1cb59..f46a36c7b 100644 --- a/baseunits/includes/MangaLib_PL/manga_information.inc +++ b/baseunits/includes/MangaLib_PL/manga_information.inc @@ -7,10 +7,10 @@ isExtractChapter: Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGALIB_PL_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGALIB_PL_ID, URL); + mangaInfo.url := FillMangaSiteHost(MANGALIB_PL_ID, AURL); s := mangaInfo.url; - if not GetPage(TObject(Source), s, Reconnect) then + if not GetPage(TObject(Source), s, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -25,11 +25,11 @@ if (Pos('<form ', Source[i]) > 0) and (Pos('name="confirm_', Source[i]) > 0) then begin - if (Length(URL) > 1) and - (URL[1] = '/') then - s := Copy(URL, 2, Length(URL) - 1) + if (Length(AURL) > 1) and + (AURL[1] = '/') then + s := Copy(AURL, 2, Length(AURL) - 1) else - s := URL; + s := AURL; s := WebsiteRoots[MANGALIB_PL_ID, 1] + '/page/' + GetVal(Source[i], 'name') + '?backlink=' + s; cf := True; @@ -40,7 +40,7 @@ begin MANGALIB_PL_COOKIES := FHTTP.Cookies.Text; Source.Clear; - if not GetPage(TObject(Source), s, Reconnect) then + if not GetPage(TObject(Source), s, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaLib_PL/names_and_links.inc b/baseunits/includes/MangaLib_PL/names_and_links.inc index 970c1202c..8ac8d572d 100644 --- a/baseunits/includes/MangaLib_PL/names_and_links.inc +++ b/baseunits/includes/MangaLib_PL/names_and_links.inc @@ -23,11 +23,11 @@ if (Pos('itemprop="name"', parse[i]) > 0) then begin Result := NO_ERROR; - links.Add(StringReplace(GetVal(parse[i - 1], 'href'), + ALinks.Add(StringReplace(GetVal(parse[i - 1], 'href'), WebsiteRoots[MANGALIB_PL_ID, 1], '', [rfIgnoreCase])); - names.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); end; end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/MangaMint/directory_page_number.inc b/baseunits/includes/MangaMint/directory_page_number.inc index 8d266c5ce..5221ac47d 100644 --- a/baseunits/includes/MangaMint/directory_page_number.inc +++ b/baseunits/includes/MangaMint/directory_page_number.inc @@ -26,7 +26,7 @@ for i := parse.Count - 1 downto 0 do if (GetTagName(parse[i]) = 'li') and (GetVal(parse[i], 'class') = 'pager-last last') then begin - Page := StrToIntDef( + APage := StrToIntDef( ReplaceRegExpr('^.*\?page=(\d+)$', GetVal(parse[i + 1], 'href'), '$1', True), 1); Break; end; diff --git a/baseunits/includes/MangaMint/manga_information.inc b/baseunits/includes/MangaMint/manga_information.inc index aa7436e8a..790c371a9 100644 --- a/baseunits/includes/MangaMint/manga_information.inc +++ b/baseunits/includes/MangaMint/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapters: Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGAMINT_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAMINT_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAMINT_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -100,7 +100,7 @@ begin isExtractChapters := False; Source.Clear; - if GetPage(TObject(Source), mangaInfo.url + '?page=' + IntToStr(j), Reconnect) then + if GetPage(TObject(Source), mangaInfo.url + '?page=' + IntToStr(j), AReconnect) then begin parse.Clear; Parser := THTMLParser.Create(Source.Text); diff --git a/baseunits/includes/MangaMint/names_and_links.inc b/baseunits/includes/MangaMint/names_and_links.inc index 1ad7aba98..a5052069a 100644 --- a/baseunits/includes/MangaMint/names_and_links.inc +++ b/baseunits/includes/MangaMint/names_and_links.inc @@ -6,7 +6,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGAMINT_ID, 1] + - '/directory?page=' + IntToStr(StrToInt(URL) + 1), 1) then + '/directory?page=' + IntToStr(StrToInt(AURL) + 1), 1) then begin Result := NET_PROBLEM; Source.Free; @@ -41,8 +41,8 @@ if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'cover') then if GetTagName(parse[i + 1]) = 'img' then begin - links.Add(GetVal(parse[i], 'href')); - names.Add(CommonStringFilter( + ALinks.Add(GetVal(parse[i], 'href')); + ANames.Add(CommonStringFilter( regx.Replace(Trim(GetVal(parse[i + 1], 'title')), '', False))); end; end; diff --git a/baseunits/includes/MangaOku/manga_information.inc b/baseunits/includes/MangaOku/manga_information.inc index 0492b657f..8ecbb0843 100644 --- a/baseunits/includes/MangaOku/manga_information.inc +++ b/baseunits/includes/MangaOku/manga_information.inc @@ -5,8 +5,8 @@ isExtractChapters: Boolean = False; begin mangaInfo.website := WebsiteRoots[MANGAOKU_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAOKU_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAOKU_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -41,7 +41,7 @@ s := Trim(TrimChar(s, ['-'])); mangaInfo.chapterName.Add(s); s := TrimChar(GetVal(parse[i], 'value'), ['/']); - s := URL + s + '/'; + s := AURL + s + '/'; mangaInfo.chapterLinks.Add(s); end; end; diff --git a/baseunits/includes/MangaOku/names_and_links.inc b/baseunits/includes/MangaOku/names_and_links.inc index a196b60ad..033486caa 100644 --- a/baseunits/includes/MangaOku/names_and_links.inc +++ b/baseunits/includes/MangaOku/names_and_links.inc @@ -35,17 +35,17 @@ if isExtractMangas and (Pos('<option', parse[i]) > 0) then begin s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - names.Add(s); + ANames.Add(s); s := TrimChar(GetVal(parse[i], 'value'), ['/']); s := '/' + s + '/'; - links.Add(s); + ALinks.Add(s); end; end; // index 0 isn't manga - if links.Count > 0 then - if links[0] = '/0/' then + if ALinks.Count > 0 then + if ALinks[0] = '/0/' then begin - links.Delete(0); - names.Delete(0); + ALinks.Delete(0); + ANames.Delete(0); end; end; diff --git a/baseunits/includes/MangaREADER_POR/manga_information.inc b/baseunits/includes/MangaREADER_POR/manga_information.inc index 2c6c92c09..b6216cdb8 100644 --- a/baseunits/includes/MangaREADER_POR/manga_information.inc +++ b/baseunits/includes/MangaREADER_POR/manga_information.inc @@ -31,8 +31,8 @@ end; begin - mangaInfo.url := FillMangaSiteHost(MANGAREADER_POR_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGAREADER_POR_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -149,7 +149,7 @@ Source.Clear; s := mangaInfo.url + '/' + IntToStr(n); if not GetPage(TObject(Source), mangaInfo.url + '/page/' + - IntToStr(n), Reconnect) then + IntToStr(n), AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaREADER_POR/names_and_links.inc b/baseunits/includes/MangaREADER_POR/names_and_links.inc index cbd69c8ab..4bf722d86 100644 --- a/baseunits/includes/MangaREADER_POR/names_and_links.inc +++ b/baseunits/includes/MangaREADER_POR/names_and_links.inc @@ -38,8 +38,8 @@ for i := 0 to Data.Count - 1 do begin jobject := TJSONObject(Data.Items[i]); - names.Add(jobject.Strings['title']); - links.Add(StringReplace(jobject.Strings['serie_url'], + ANames.Add(jobject.Strings['title']); + ALinks.Add(StringReplace(jobject.Strings['serie_url'], WebsiteRoots[MANGAREADER_POR_ID, 1], '', [])); end; end; diff --git a/baseunits/includes/MangaTown/directory_page_number.inc b/baseunits/includes/MangaTown/directory_page_number.inc index 7e9f6db10..4fc852e92 100644 --- a/baseunits/includes/MangaTown/directory_page_number.inc +++ b/baseunits/includes/MangaTown/directory_page_number.inc @@ -3,7 +3,7 @@ i: Cardinal; isExtractPage: Boolean = False; begin - Page := 0; + APage := 0; Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGATOWN_ID, 1] + MANGATOWN_BROWSER + '?name.az', 0) then @@ -33,7 +33,7 @@ if isExtractPage and (Pos('<option', parse[i]) > 0) then begin - Inc(Page); + Inc(APage); Result := NO_ERROR; end; end; diff --git a/baseunits/includes/MangaTown/manga_information.inc b/baseunits/includes/MangaTown/manga_information.inc index 5e89d647b..8bef7e3ec 100644 --- a/baseunits/includes/MangaTown/manga_information.inc +++ b/baseunits/includes/MangaTown/manga_information.inc @@ -6,8 +6,8 @@ i: Cardinal; begin mangaInfo.website := WebsiteRoots[MANGATOWN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGATOWN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGATOWN_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangaTown/names_and_links.inc b/baseunits/includes/MangaTown/names_and_links.inc index a03e72055..51ad361d7 100644 --- a/baseunits/includes/MangaTown/names_and_links.inc +++ b/baseunits/includes/MangaTown/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MANGATOWN_ID, 1] + - MANGATOWN_BROWSER + IntToStr(StrToInt(URL) + 1) + '.htm?name.az', 0) then + MANGATOWN_BROWSER + IntToStr(StrToInt(AURL) + 1) + '.htm?name.az', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -29,10 +29,10 @@ begin Result := NO_ERROR; s := Trim(HTMLEntitiesFilter(StringFilter(GetVal(parse[i + 2], 'title')))); - names.Add(s); + ANames.Add(s); s := GetVal(parse[i + 2], 'href'); s := StringReplace(s, WebsiteRoots[MANGATOWN_ID, 1], '', [rfIgnoreCase]); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; diff --git a/baseunits/includes/MangasPROJECT/manga_information.inc b/baseunits/includes/MangasPROJECT/manga_information.inc index 2d6e2356b..c058f461e 100644 --- a/baseunits/includes/MangasPROJECT/manga_information.inc +++ b/baseunits/includes/MangasPROJECT/manga_information.inc @@ -35,8 +35,8 @@ end; begin - mangaInfo.url := FillMangaSiteHost(MANGASPROJECT_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MANGASPROJECT_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -139,7 +139,7 @@ Source.Clear; s := mangaInfo.url + '/' + IntToStr(n); if not GetPage(TObject(Source), mangaInfo.url + '/page/' + - IntToStr(n), Reconnect) then + IntToStr(n), AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MangasPROJECT/names_and_links.inc b/baseunits/includes/MangasPROJECT/names_and_links.inc index 768d8ca84..533738b41 100644 --- a/baseunits/includes/MangasPROJECT/names_and_links.inc +++ b/baseunits/includes/MangasPROJECT/names_and_links.inc @@ -29,8 +29,8 @@ Result := NO_ERROR; for i := 0 to Data.Count - 1 do begin - names.Add(Data.Items[i].Items[0].AsString); - links.Add(StringReplace(Data.Items[i].Items[2].AsString, + ANames.Add(Data.Items[i].Items[0].AsString); + ALinks.Add(StringReplace(Data.Items[i].Items[2].AsString, WebsiteRoots[MangasPROJECT_ID, 1], '', [])); end; end; diff --git a/baseunits/includes/MeinManga/manga_information.inc b/baseunits/includes/MeinManga/manga_information.inc index 1916af253..969e76f07 100644 --- a/baseunits/includes/MeinManga/manga_information.inc +++ b/baseunits/includes/MeinManga/manga_information.inc @@ -19,8 +19,8 @@ end; begin - mangaInfo.url := FillMangaSiteHost(MEINMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MEINMANGA_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -72,7 +72,7 @@ if (mangaInfo.title = '') and (Pos('class="chrname"', parse[i]) <> 0) then mangaInfo.title := Trim(StringFilter(parse[i + 1])); - // Get chapter title and url + // Get chapter title and AURL GetChapterTitleAndChapterURL; // get authors @@ -129,7 +129,7 @@ for j := 0 to URLs.Count - 1 do begin Source := TStringList.Create; - if not GetPage(TObject(Source), URLs[j], Reconnect) then + if not GetPage(TObject(Source), URLs[j], AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/MeinManga/names_and_links.inc b/baseunits/includes/MeinManga/names_and_links.inc index b8033c6b5..80c318543 100644 --- a/baseunits/includes/MeinManga/names_and_links.inc +++ b/baseunits/includes/MeinManga/names_and_links.inc @@ -29,10 +29,10 @@ begin Result := NO_ERROR; s := GetVal(parse[i], 'href'); - links.Add(s); + ALinks.Add(s); s := StringFilter(Trim(parse[i + 1])); s := StringReplace(s, WebsiteRoots[MEINMANGA_ID, 1], '', []); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); end; end; Source.Free; diff --git a/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc b/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc index 5dd607f70..52ae35e61 100644 --- a/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc +++ b/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc @@ -3,7 +3,7 @@ i, j: Cardinal; isGetLastPage: Boolean = False; begin - Page := 0; + APage := 0; Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MYREADINGMANGAINFO_ID, 1] + '/', 0) then begin @@ -32,7 +32,7 @@ if (Pos('<a', parse[j]) > 0) and (Pos('/page/', parse[j]) > 0) then begin Result := NO_ERROR; - Page := StrToIntDef(Trim(parse[j + 1]), 1); + APage := StrToIntDef(Trim(parse[j + 1]), 1); isGetLastPage := True; Break; end; diff --git a/baseunits/includes/MyReadingMangaInfo/manga_information.inc b/baseunits/includes/MyReadingMangaInfo/manga_information.inc index a42400267..2f386cd32 100644 --- a/baseunits/includes/MyReadingMangaInfo/manga_information.inc +++ b/baseunits/includes/MyReadingMangaInfo/manga_information.inc @@ -7,8 +7,8 @@ isExtractChapters: Boolean = False; begin mangaInfo.website := WebsiteRoots[MYREADINGMANGAINFO_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MYREADINGMANGAINFO_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MYREADINGMANGAINFO_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -114,7 +114,7 @@ //chapter 1 Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Insert(0, URL); + mangaInfo.chapterLinks.Insert(0, AURL); if mangaInfo.numChapter = 1 then mangaInfo.chapterName.Insert(0, mangaInfo.title) else diff --git a/baseunits/includes/MyReadingMangaInfo/names_and_links.inc b/baseunits/includes/MyReadingMangaInfo/names_and_links.inc index 7b9f7cd06..d9918b055 100644 --- a/baseunits/includes/MyReadingMangaInfo/names_and_links.inc +++ b/baseunits/includes/MyReadingMangaInfo/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[MYREADINGMANGAINFO_ID, 1] + - '/page/' + IntToStr(StrToInt(URL) + 1) + '/', 0) then + '/page/' + IntToStr(StrToInt(AURL) + 1) + '/', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -28,10 +28,10 @@ begin Result := NO_ERROR; s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2])))); - names.Add(s); + ANames.Add(s); s := GetVal(parse[i + 1], 'href'); s := StringReplace(s, WebsiteRoots[MYREADINGMANGAINFO_ID, 1], '', [rfIgnoreCase]); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; diff --git a/baseunits/includes/NHentai/directory_page_number.inc b/baseunits/includes/NHentai/directory_page_number.inc index 3b30b3670..18a884353 100644 --- a/baseunits/includes/NHentai/directory_page_number.inc +++ b/baseunits/includes/NHentai/directory_page_number.inc @@ -2,7 +2,7 @@ var i: Integer; begin - Page := 0; + APage := 0; Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[NHENTAI_ID, 1] + '/', 0) then begin @@ -27,7 +27,7 @@ (Pos('class="last"', parse[i]) > 0) then begin Result := NO_ERROR; - Page := StrToIntDef(ReplaceRegExpr('^.*\?page=(\d+).*$', GetVal(parse[i], 'href'), '$1', True), 1); + APage := StrToIntDef(ReplaceRegExpr('^.*\?page=(\d+).*$', GetVal(parse[i], 'href'), '$1', True), 1); Break; end; end; diff --git a/baseunits/includes/NHentai/manga_information.inc b/baseunits/includes/NHentai/manga_information.inc index c35e59705..f0ade6e0e 100644 --- a/baseunits/includes/NHentai/manga_information.inc +++ b/baseunits/includes/NHentai/manga_information.inc @@ -3,8 +3,8 @@ i: Integer; begin mangaInfo.website := WebsiteRoots[NHENTAI_ID, 0]; - mangaInfo.url := FillMangaSiteHost(NHENTAI_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(NHENTAI_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -80,7 +80,7 @@ mangaInfo.status := '0'; mangaInfo.numChapter := 1; - mangaInfo.chapterLinks.Add(URL); + mangaInfo.chapterLinks.Add(AURL); mangaInfo.chapterName.Add(mangaInfo.title); if mangaInfo.chapterName.Count > 1 then diff --git a/baseunits/includes/NHentai/names_and_links.inc b/baseunits/includes/NHentai/names_and_links.inc index 2d5c18cb5..0813d27fd 100644 --- a/baseunits/includes/NHentai/names_and_links.inc +++ b/baseunits/includes/NHentai/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[NHENTAI_ID, 1] + - '/?page=' + IntToStr(StrToInt(URL) + 1), 0) then + '/?page=' + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -26,8 +26,8 @@ if (Pos('/g/', parse[i]) > 0) and (Pos('<a', parse[i]) > 0) then begin Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - links.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[NHENTAI_ID, 1], '', [rfIgnoreCase])); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); + ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[NHENTAI_ID, 1], '', [rfIgnoreCase])); end; end; Source.Free; diff --git a/baseunits/includes/NineManga/directory_page_number.inc b/baseunits/includes/NineManga/directory_page_number.inc index 46f7ea073..2eb74041a 100644 --- a/baseunits/includes/NineManga/directory_page_number.inc +++ b/baseunits/includes/NineManga/directory_page_number.inc @@ -8,22 +8,22 @@ BROWSER_INVERT := True; //I can't get manga directory total pages. Its not available on any page //The only option to get total pages is just checking manually with browser :( - p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', website, -1); + p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', AWebsite, -1); if p > 0 then - Page := p + APage := p else begin - SiteID := GetMangaSiteID(website); + SiteID := GetMangaSiteID(AWebsite); case SiteID of - NINEMANGA_ID: Page := 520; //latest check = 513 (01-11-2014) - NINEMANGA_ES_ID: Page := 596; - NINEMANGA_CN_ID: Page := 778; - NINEMANGA_RU_ID: Page := 205; - NINEMANGA_BR_ID: Page := 56; - NINEMANGA_IT_ID: Page := 50; - NINEMANGA_DE_ID: Page := 30; + NINEMANGA_ID: APage := 520; //latest check = 513 (01-11-2014) + NINEMANGA_ES_ID: APage := 596; + NINEMANGA_CN_ID: APage := 778; + NINEMANGA_RU_ID: APage := 205; + NINEMANGA_BR_ID: APage := 56; + NINEMANGA_IT_ID: APage := 50; + NINEMANGA_DE_ID: APage := 30; else - Page := 500; //not checked yet = 500 default + APage := 500; //not checked yet = 500 default end; end; end; diff --git a/baseunits/includes/NineManga/manga_information.inc b/baseunits/includes/NineManga/manga_information.inc index 510f104a8..38030251c 100644 --- a/baseunits/includes/NineManga/manga_information.inc +++ b/baseunits/includes/NineManga/manga_information.inc @@ -4,12 +4,12 @@ i, j, SiteID: Cardinal; s: String; begin - SiteID := GetMangaSiteID(website); + SiteID := GetMangaSiteID(AWebsite); mangaInfo.website := WebsiteRoots[SiteID, 0]; - mangaInfo.url := StringReplace(FillMangaSiteHost(SiteID, URL), '?waring=1', '', + mangaInfo.url := StringReplace(FillMangaSiteHost(SiteID, AURL), '?waring=1', '', [rfIgnoreCase, rfReplaceAll]); - if not GetPage(TObject(Source), mangaInfo.url + '?waring=1', Reconnect) then + if not GetPage(TObject(Source), mangaInfo.url + '?waring=1', AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/NineManga/names_and_links.inc b/baseunits/includes/NineManga/names_and_links.inc index 1ac1b8aaa..aea72cbf8 100644 --- a/baseunits/includes/NineManga/names_and_links.inc +++ b/baseunits/includes/NineManga/names_and_links.inc @@ -4,9 +4,9 @@ begin Result := INFORMATION_NOT_FOUND; - SiteID := GetMangaSiteID(website); + SiteID := GetMangaSiteID(AWebsite); if not GetPage(TObject(Source), WebsiteRoots[SiteID, 1] + - NINEMANGA_BROWSER + '&page=' + IntToStr(StrToIntDef(URL, 0) + 1) + '.html', 0) then + NINEMANGA_BROWSER + '&page=' + IntToStr(StrToIntDef(AURL, 0) + 1) + '.html', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -28,11 +28,11 @@ if (Pos('class="bookname"', parse[i]) > 0) then begin Result := NO_ERROR; - links.Add( + ALinks.Add( StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[SiteID, 1], '', [rfReplaceAll])); - names.Add(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); + ANames.Add(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/OneManga/directory_page_number.inc b/baseunits/includes/OneManga/directory_page_number.inc index 3b25af833..a8e5ef780 100644 --- a/baseunits/includes/OneManga/directory_page_number.inc +++ b/baseunits/includes/OneManga/directory_page_number.inc @@ -25,7 +25,7 @@ if Pos('Last', parse[i]) > 0 then if (Pos('<a ', parse[i - 1]) > 0) and (Pos('</a', parse[i + 1]) > 0) then begin - Page := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)\/$', + APage := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)\/$', GetVal(parse[i - 1], 'href'), '$1', True), 1); Result := NO_ERROR; Break; diff --git a/baseunits/includes/OneManga/manga_information.inc b/baseunits/includes/OneManga/manga_information.inc index bdad5e939..bdcc3111e 100644 --- a/baseunits/includes/OneManga/manga_information.inc +++ b/baseunits/includes/OneManga/manga_information.inc @@ -5,8 +5,8 @@ isExtractChapter: Boolean = False; begin mangaInfo.website := WebsiteRoots[ONEMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ONEMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(ONEMANGA_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/OneManga/names_and_links.inc b/baseunits/includes/OneManga/names_and_links.inc index 6f72b1117..80880006f 100644 --- a/baseunits/includes/OneManga/names_and_links.inc +++ b/baseunits/includes/OneManga/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[ONEMANGA_ID, 1] + - ONEMANGA_BROWSER + IntToStr(StrToInt(URL) + 1) + '/', 0) then + ONEMANGA_BROWSER + IntToStr(StrToInt(AURL) + 1) + '/', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -27,8 +27,8 @@ if Pos('<a ', parse[i + 2]) > 0 then begin Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 3]))))); - links.Add(StringReplace(GetVal(parse[i + 2], 'href'), + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 3]))))); + ALinks.Add(StringReplace(GetVal(parse[i + 2], 'href'), WebsiteRoots[ONEMANGA_ID, 1], '', [rfIgnoreCase])); end; end; diff --git a/baseunits/includes/PornComix/directory_page_number.inc b/baseunits/includes/PornComix/directory_page_number.inc index 051861434..ebbf92c36 100644 --- a/baseunits/includes/PornComix/directory_page_number.inc +++ b/baseunits/includes/PornComix/directory_page_number.inc @@ -30,8 +30,8 @@ if (Pos('<a', parse[i]) > 0) and (Pos('/page/', parse[i]) > 0) then begin p := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', GetVal(parse[i], 'href'), '$1', True), 0); - if Page < p then - Page := p; + if APage < p then + APage := p; end; Source.Free; end; diff --git a/baseunits/includes/PornComix/manga_information.inc b/baseunits/includes/PornComix/manga_information.inc index bb57c8334..fa983a4f6 100644 --- a/baseunits/includes/PornComix/manga_information.inc +++ b/baseunits/includes/PornComix/manga_information.inc @@ -5,8 +5,8 @@ isExtractGenres: Boolean = False; begin mangaInfo.website := WebsiteRoots[MangaID, 0]; - mangaInfo.url := FillMangaSiteHost(MangaID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(MangaID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -65,7 +65,7 @@ mangaInfo.status := '0'; //single chapter - mangaInfo.chapterLinks.Add(URL); + mangaInfo.chapterLinks.Add(AURL); mangaInfo.chapterName.Add(mangaInfo.title); Result := NO_ERROR; diff --git a/baseunits/includes/PornComix/names_and_links.inc b/baseunits/includes/PornComix/names_and_links.inc index cd39e3832..bf9a66f4b 100644 --- a/baseunits/includes/PornComix/names_and_links.inc +++ b/baseunits/includes/PornComix/names_and_links.inc @@ -8,8 +8,8 @@ s := WebsiteRoots[MangaID, 1] + '/'; if MangaID = PORNCOMIXRE_ID then s := s + 'online/'; - if URL <> '0' then - s := s + 'page/' + IntToStr(StrToInt(URL) + 1) + '/'; + if AURL <> '0' then + s := s + 'page/' + IntToStr(StrToInt(AURL) + 1) + '/'; if not GetPage(TObject(Source), s, 0) then begin Result := NET_PROBLEM; @@ -37,10 +37,10 @@ s := GetVal(parse[i + 2], 'href'); if regx.Exec(s) then begin - links.Add(s); - names.Add(CommonStringFilter(GetVal(parse[i + 2], 'title'))); - if names[names.Count - 1] = '' then - names[names.Count - 1] := 'Untitled_' + IntToStr(Random(99999)); + ALinks.Add(s); + ANames.Add(CommonStringFilter(GetVal(parse[i + 2], 'title'))); + if ANames[ANames.Count - 1] = '' then + ANames[ANames.Count - 1] := 'Untitled_' + IntToStr(Random(99999)); end; end; end; diff --git a/baseunits/includes/ReadMangaToday/directory_page_number.inc b/baseunits/includes/ReadMangaToday/directory_page_number.inc index 614d3cc90..a8a11a837 100644 --- a/baseunits/includes/ReadMangaToday/directory_page_number.inc +++ b/baseunits/includes/ReadMangaToday/directory_page_number.inc @@ -1,6 +1,6 @@ function GetReadMangaTodayDirectoryPageNumber: Byte; begin Source.Free; - Page := Length(ALPHA_LIST); + APage := Length(ALPHA_LIST); Result := NO_ERROR; end; diff --git a/baseunits/includes/ReadMangaToday/manga_information.inc b/baseunits/includes/ReadMangaToday/manga_information.inc index 6f5bfb1a0..d38d3ca05 100644 --- a/baseunits/includes/ReadMangaToday/manga_information.inc +++ b/baseunits/includes/ReadMangaToday/manga_information.inc @@ -4,8 +4,8 @@ i, j: Integer; begin mangaInfo.website := WebsiteRoots[READMANGATODAY_ID, 0]; - mangaInfo.url := FillMangaSiteHost(READMANGATODAY_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(READMANGATODAY_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/ReadMangaToday/names_and_links.inc b/baseunits/includes/ReadMangaToday/names_and_links.inc index 0376b7fd4..986dad5fb 100644 --- a/baseunits/includes/ReadMangaToday/names_and_links.inc +++ b/baseunits/includes/ReadMangaToday/names_and_links.inc @@ -5,7 +5,7 @@ begin Result := INFORMATION_NOT_FOUND; s := WebsiteRoots[READMANGATODAY_ID, 1] + '/manga-list'; - i := StrToIntDef(URL, 0); + i := StrToIntDef(AURL, 0); if i > 0 then s := s + '/' + ALPHA_LIST[i+1]; if not GetPage(TObject(Source), s, 1) then @@ -22,8 +22,8 @@ if (GetTagName(parse[i]) = 'span') and (GetVal(parse[i], 'class') = 'manga-item') then begin - links.Add(GetVal(parse[i+4], 'href')); - names.Add(CommonStringFilter(parse[i+5])); + ALinks.Add(GetVal(parse[i+4], 'href')); + ANames.Add(CommonStringFilter(parse[i+5])); end; Result := NO_ERROR; diff --git a/baseunits/includes/S2Scans/directory_page_number.inc b/baseunits/includes/S2Scans/directory_page_number.inc index 13ed80ee8..c13a8096d 100644 --- a/baseunits/includes/S2Scans/directory_page_number.inc +++ b/baseunits/includes/S2Scans/directory_page_number.inc @@ -25,7 +25,7 @@ if Pos('Last »»', parse[i]) > 0 then if GetTagName(parse[i - 1]) = 'a' then begin - Page := StrToIntDef(ReplaceRegExpr( + APage := StrToIntDef(ReplaceRegExpr( '^.*/(\d+)/$', GetVal(parse[i - 1], 'href'), '$1', True), 1); Break; end; diff --git a/baseunits/includes/S2Scans/manga_information.inc b/baseunits/includes/S2Scans/manga_information.inc index f452be48f..28776041e 100644 --- a/baseunits/includes/S2Scans/manga_information.inc +++ b/baseunits/includes/S2Scans/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapter: Boolean = False; begin mangaInfo.website := WebsiteRoots[S2SCAN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(S2SCAN_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(S2SCAN_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/S2Scans/names_and_links.inc b/baseunits/includes/S2Scans/names_and_links.inc index 52a4b5297..6c5143afb 100644 --- a/baseunits/includes/S2Scans/names_and_links.inc +++ b/baseunits/includes/S2Scans/names_and_links.inc @@ -4,7 +4,7 @@ begin Result := INFORMATION_NOT_FOUND; if not GetPage(TObject(Source), WebsiteRoots[S2SCAN_ID, 1] + - '/directory/' + '/' + IntToStr(StrToInt(URL)+1) + '/', 0) then + '/directory/' + '/' + IntToStr(StrToInt(AURL)+1) + '/', 0) then begin Result := NET_PROBLEM; Source.Free; @@ -27,8 +27,8 @@ if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'group') then if GetTagName(parse[i + 5]) = 'a' then begin - names.Add(GetVal(parse[i + 5], 'title')); - links.Add(GetVal(parse[i + 5], 'href')); + ANames.Add(GetVal(parse[i + 5], 'title')); + ALinks.Add(GetVal(parse[i + 5], 'href')); end; end; Source.Free; diff --git a/baseunits/includes/ScanManga/manga_information.inc b/baseunits/includes/ScanManga/manga_information.inc index 0cc9a207c..a958cae80 100644 --- a/baseunits/includes/ScanManga/manga_information.inc +++ b/baseunits/includes/ScanManga/manga_information.inc @@ -4,8 +4,8 @@ isExtractGenres: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(SCANMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(SCANMANGA_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/ScanManga/names_and_links.inc b/baseunits/includes/ScanManga/names_and_links.inc index 80ddfb7ec..8f776a6bb 100644 --- a/baseunits/includes/ScanManga/names_and_links.inc +++ b/baseunits/includes/ScanManga/names_and_links.inc @@ -37,9 +37,9 @@ (Pos('/scanlation/Josei.html', s) = 0) and (Pos('/scanlation/Seinen.html', s) = 0) then begin - links.Add(StringReplace(s, WebsiteRoots[SCANMANGA_ID, 1], '', [])); + ALinks.Add(StringReplace(s, WebsiteRoots[SCANMANGA_ID, 1], '', [])); s := StringFilter(parse[i + 2]); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); end; end; end; diff --git a/baseunits/includes/Starkana/manga_information.inc b/baseunits/includes/Starkana/manga_information.inc index e0a4c55f4..59894ec08 100644 --- a/baseunits/includes/Starkana/manga_information.inc +++ b/baseunits/includes/Starkana/manga_information.inc @@ -4,8 +4,8 @@ isExtractGenres: Boolean = False; begin mangaInfo.website := WebsiteRoots[STARKANA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(STARKANA_ID, URL) + '?mature_confirm=1'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(STARKANA_ID, AURL) + '?mature_confirm=1'; + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/Starkana/names_and_links.inc b/baseunits/includes/Starkana/names_and_links.inc index 789336074..d891d14ea 100644 --- a/baseunits/includes/Starkana/names_and_links.inc +++ b/baseunits/includes/Starkana/names_and_links.inc @@ -25,8 +25,8 @@ begin if (Pos('style="float:right;', parse[i]) > 0) then begin - links.Add(GetVal(parse[i + 2], 'href')); - names.Add(CommonStringFilter(parse[i + 3])); + ALinks.Add(GetVal(parse[i + 2], 'href')); + ANames.Add(CommonStringFilter(parse[i + 3])); end; end; Result := NO_ERROR; diff --git a/baseunits/includes/TruyenTranhTuan/manga_information.inc b/baseunits/includes/TruyenTranhTuan/manga_information.inc index 76b13b6ef..ef7fbcd65 100644 --- a/baseunits/includes/TruyenTranhTuan/manga_information.inc +++ b/baseunits/includes/TruyenTranhTuan/manga_information.inc @@ -5,8 +5,8 @@ isExtractGenres: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(TRUYENTRANHTUAN_ID, AURL);// + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/TruyenTranhTuan/names_and_links.inc b/baseunits/includes/TruyenTranhTuan/names_and_links.inc index 02a3a5f76..3ecbe4455 100644 --- a/baseunits/includes/TruyenTranhTuan/names_and_links.inc +++ b/baseunits/includes/TruyenTranhTuan/names_and_links.inc @@ -28,11 +28,11 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := GetVal(parse[i + 1], 'href'); s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/Turkcraft/manga_information.inc b/baseunits/includes/Turkcraft/manga_information.inc index 418258754..b37e80665 100644 --- a/baseunits/includes/Turkcraft/manga_information.inc +++ b/baseunits/includes/Turkcraft/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapter: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(TURKCRAFT_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(TURKCRAFT_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; @@ -49,7 +49,7 @@ if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then begin Inc(mangaInfo.numChapter); - s := URL + '/' + GetVal(parse[i], 'value'); + s := AURL + '/' + GetVal(parse[i], 'value'); mangaInfo.chapterLinks.Add(s); s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); diff --git a/baseunits/includes/Turkcraft/names_and_links.inc b/baseunits/includes/Turkcraft/names_and_links.inc index 776fd5255..84b1f7b22 100644 --- a/baseunits/includes/Turkcraft/names_and_links.inc +++ b/baseunits/includes/Turkcraft/names_and_links.inc @@ -28,9 +28,9 @@ begin Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); s := '/' + GetVal(parse[i], 'value'); - links.Add(s); + ALinks.Add(s); end; end; Source.Free; diff --git a/baseunits/includes/UnixManga/manga_information.inc b/baseunits/includes/UnixManga/manga_information.inc index 842d5a44e..8e027f1b4 100644 --- a/baseunits/includes/UnixManga/manga_information.inc +++ b/baseunits/includes/UnixManga/manga_information.inc @@ -4,8 +4,8 @@ isExtractChapters: Boolean = False; begin mangaInfo.website := WebsiteRoots[UNIXMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(UNIXMANGA_ID, URL); - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(UNIXMANGA_ID, AURL); + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/UnixManga/names_and_links.inc b/baseunits/includes/UnixManga/names_and_links.inc index 0c5dc6c72..6ab1e652f 100644 --- a/baseunits/includes/UnixManga/names_and_links.inc +++ b/baseunits/includes/UnixManga/names_and_links.inc @@ -26,8 +26,8 @@ (Pos('title=', parse[i]) > 0) and (Pos('<a ', parse[i]) > 0) then begin Result := NO_ERROR; - names.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - links.Add(Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[UNIXMANGA_ID, 1], '', [rfIgnoreCase]))); + ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); + ALinks.Add(Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[UNIXMANGA_ID, 1], '', [rfIgnoreCase]))); end; end; end; diff --git a/baseunits/includes/VnSharing/directory_page_number.inc b/baseunits/includes/VnSharing/directory_page_number.inc index d5470f3ee..41ebe10fb 100644 --- a/baseunits/includes/VnSharing/directory_page_number.inc +++ b/baseunits/includes/VnSharing/directory_page_number.inc @@ -27,7 +27,7 @@ begin s := GetVal(parse[i - 1], 'page'); SetLength(s, Length(s) - 1); - Page := StrToInt(s); + APage := StrToInt(s); Result := NO_ERROR; Source.Free; Exit; diff --git a/baseunits/includes/VnSharing/manga_information.inc b/baseunits/includes/VnSharing/manga_information.inc index 23f159f78..dc0af4fe4 100644 --- a/baseunits/includes/VnSharing/manga_information.inc +++ b/baseunits/includes/VnSharing/manga_information.inc @@ -5,8 +5,8 @@ isExtractGenres: Boolean = False; i, j: Cardinal; begin - mangaInfo.url := FillMangaSiteHost(VNSHARING_ID, URL) + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, Reconnect) then + mangaInfo.url := FillMangaSiteHost(VNSHARING_ID, AURL) + '&confirm=yes'; + if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then begin Result := NET_PROBLEM; Source.Free; diff --git a/baseunits/includes/VnSharing/names_and_links.inc b/baseunits/includes/VnSharing/names_and_links.inc index 9382fea28..fe4f469bb 100644 --- a/baseunits/includes/VnSharing/names_and_links.inc +++ b/baseunits/includes/VnSharing/names_and_links.inc @@ -7,7 +7,7 @@ Result := INFORMATION_NOT_FOUND; // bad code if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + - VNSHARING_BROWSER + '?page=' + IntToStr(StrToInt(URL) + 1), 0) then + VNSHARING_BROWSER + '?page=' + IntToStr(StrToInt(AURL) + 1), 0) then begin Result := NET_PROBLEM; Source.Free; @@ -38,9 +38,9 @@ // if s <> '/Truyen/Tenki-Yohou-no-Koibito?id=506' then if s <> '/Truyen/Bakuman-Fantasy-Weirdos?id=6238' then begin - links.Add(s); + ALinks.Add(s); s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - names.Add(HTMLEntitiesFilter(s)); + ANames.Add(HTMLEntitiesFilter(s)); end; end; end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index ce68c72a1..2a3f7c85e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -88,26 +88,26 @@ TMangaInformation = class(TObject) ModuleId: Integer; procedure OnTag(NoCaseTag, ActualTag: String); - procedure OnText(Text: String); - constructor Create(AOwnerThread: THTTPThread = nil; CreateInfo: Boolean = True); + procedure OnText(AText: String); + constructor Create(AOwnerThread: THTTPThread = nil; ACreateInfo: Boolean = True); destructor Destroy; override; procedure ClearInfo; - function GetDirectoryPage(var Page: Integer; const website: String): Byte; - function GetNameAndLink(const names, links: TStringList; const website, URL: String): Byte; - function GetInfoFromURL(const website, URL: String; const Reconnect: Integer = 0): Byte; - procedure SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); overload; - procedure SyncInfoToData(const DataProcess: TDBDataProcess); overload; - procedure SyncMinorInfoToData(const DataProcess: TDataProcess; const index: Cardinal); + function GetDirectoryPage(var APage: Integer; const AWebsite: String): Byte; + function GetNameAndLink(const ANames, ALinks: TStringList; const AWebsite, AURL: String): Byte; + function GetInfoFromURL(const AWebsite, AURL: String; const AReconnect: Integer = 0): Byte; + procedure SyncInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); overload; + procedure SyncInfoToData(const ADataProcess: TDBDataProcess); overload; + procedure SyncMinorInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); // Only use this function for getting manga infos for the first time - procedure AddInfoToDataWithoutBreak(const Name, link: String; const DataProcess: TDataProcess); + procedure AddInfoToDataWithoutBreak(const AName, ALink: String; const ADataProcess: TDataProcess); // Only use this function for update manga list - procedure AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); + procedure AddInfoToData(const AName, Alink: String; const ADataProcess: TDataProcess); overload; // to add data to TDBDataProcess - procedure AddInfoToData(const Title, Link: String; const DataProcess: TDBDataProcess); overload; + procedure AddInfoToData(const ATitle, ALink: String; const ADataProcess: TDBDataProcess); overload; //wrapper - function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; inline; + function GetPage(var AOutput: TObject; AURL: String; const AReconnect: Integer = 0): Boolean; inline; end; var @@ -713,13 +713,13 @@ procedure TDataProcess.Sort; { TMangaInformation } -constructor TMangaInformation.Create(AOwnerThread: THTTPThread; CreateInfo: Boolean); +constructor TMangaInformation.Create(AOwnerThread: THTTPThread; ACreateInfo: Boolean); begin inherited Create; FHTTP := THTTPSendThread.Create(AOwnerThread); FHTTP.Headers.NameValueSeparator := ':'; parse := TStringList.Create; - if CreateInfo then + if ACreateInfo then mangaInfo := TMangaInfo.Create; isGetByUpdater := False; ModuleId := -1; @@ -757,12 +757,12 @@ procedure TMangaInformation.OnTag(NoCaseTag, ActualTag: String); parse.Add(ActualTag); end; -procedure TMangaInformation.OnText(Text: String); +procedure TMangaInformation.OnText(AText: String); begin - parse.Add(Text); + parse.Add(AText); end; -function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: String): Byte; +function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: String): Byte; var s: String; p: Integer; @@ -819,29 +819,29 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St {$I includes/Dynasty-Scans/directory_page_number.inc} begin - Page := 0; + APage := 0; //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, website); + AdvanceLoadHTTPConfig(FHTTP, AWebsite); //load pagenumber_config if available - p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', website, -1); + p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', AWebsite, -1); if p > 0 then begin - Page := p; + APage := p; BROWSER_INVERT := True; end else begin BROWSER_INVERT := False; if ModuleId < 0 then - ModuleId := Modules.LocateModule(website); + ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then - Result := Modules.GetDirectoryPageNumber(Self, Page, ModuleId) + Result := Modules.GetDirectoryPageNumber(Self, APage, ModuleId) else begin - WebsiteID := GetMangaSiteID(website); + WebsiteID := GetMangaSiteID(AWebsite); Source := TStringList.Create; if WebsiteID = ANIMEA_ID then Result := GetAnimeADirectoryPageNumber @@ -916,7 +916,7 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St (WebsiteID = PORNCOMIXRE_ID) or (WebsiteID = PORNCOMIXIC_ID) or (WebsiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(website)) + Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(AWebsite)) else if WebsiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber @@ -929,18 +929,18 @@ function TMangaInformation.GetDirectoryPage(var Page: Integer; const website: St else begin Result := NO_ERROR; - Page := 1; + APage := 1; Source.Free; end; end; - if page < 1 then - Page := 1; + if APage < 1 then + APage := 1; end; end; -function TMangaInformation.GetNameAndLink(const names, links: TStringList; - const website, URL: String): Byte; +function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; + const AWebsite, AURL: String): Byte; var Source: TStringList; Parser: THTMLParser; @@ -1044,15 +1044,15 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; begin //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, website); + AdvanceLoadHTTPConfig(FHTTP, AWebsite); if ModuleId < 0 then - ModuleId := Modules.LocateModule(website); + ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetNameAndLink) then - Result := Modules.GetNameAndLink(Self, names, links, URL, ModuleId) + Result := Modules.GetNameAndLink(Self, ANames, ALinks, AURL, ModuleId) else begin - WebsiteID := GetMangaSiteID(website); + WebsiteID := GetMangaSiteID(AWebsite); Source := TStringList.Create; if WebsiteID = ANIMEA_ID then Result := AnimeAGetNamesAndLinks @@ -1196,7 +1196,7 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; (WebsiteID = PORNCOMIXRE_ID) or (WebsiteID = PORNCOMIXIC_ID) or (WebsiteID = PORNXXXCOMICS_ID) then - Result := PornComixGetNamesAndLinks(GetMangaSiteID(website)) + Result := PornComixGetNamesAndLinks(GetMangaSiteID(AWebsite)) else if WebsiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks @@ -1216,12 +1216,12 @@ function TMangaInformation.GetNameAndLink(const names, links: TStringList; end; end; - //remove host from url - if links.Count > 0 then - RemoveHostFromURLsPair(links, names); + //remove host from AURL + if ALinks.Count > 0 then + RemoveHostFromURLsPair(ALinks, ANames); end; -function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reconnect: Integer): Byte; +function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AReconnect: Integer): Byte; var s, s2: String; j, k: Integer; @@ -1328,30 +1328,30 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco {$I includes/Dynasty-Scans/manga_information.inc} begin - if Trim(URL) = '' then + if Trim(AURL) = '' then Exit(INFORMATION_NOT_FOUND); //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, website); + AdvanceLoadHTTPConfig(FHTTP, AWebsite); - mangaInfo.website := website; + mangaInfo.website := AWebsite; mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; mangaInfo.chapterName.Clear; mangaInfo.chapterLinks.Clear; if ModuleId < 0 then - ModuleId := Modules.LocateModule(website); + ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetInfo) then begin - mangaInfo.url := FillHost(Modules.Module[ModuleId].RootURL, URL); - Result := Modules.GetInfo(Self, URL, ModuleId); + mangaInfo.url := FillHost(Modules.Module[ModuleId].RootURL, AURL); + Result := Modules.GetInfo(Self, AURL, ModuleId); end else begin - WebsiteID := GetMangaSiteID(website); + WebsiteID := GetMangaSiteID(AWebsite); if WebsiteID > High(WebsiteRoots) then Exit(INFORMATION_NOT_FOUND); - mangaInfo.url := FillMangaSiteHost(WebsiteID, URL); + mangaInfo.url := FillMangaSiteHost(WebsiteID, AURL); Source := TStringList.Create; if WebsiteID = ANIMEA_ID then Result := GetAnimeAInfoFromURL @@ -1492,7 +1492,7 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco (WebsiteID = PORNCOMIXRE_ID) or (WebsiteID = PORNCOMIXIC_ID) or (WebsiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixInfoFromURL(GetMangaSiteID(website)) + Result := GetPornComixInfoFromURL(GetMangaSiteID(AWebsite)) else if WebsiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL @@ -1606,45 +1606,45 @@ function TMangaInformation.GetInfoFromURL(const website, URL: String; const Reco end; end; -procedure TMangaInformation.SyncMinorInfoToData(const DataProcess: TDataProcess; const index: Cardinal); +procedure TMangaInformation.SyncMinorInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); begin // sync info to data {$IFDEF DOWNLOADER} - if not dataProcess.isFilterAllSites then + if not ADataProcess.isFilterAllSites then {$ENDIF} - DataProcess.Data.Strings[index] := SetParams( - [DataProcess.Param[index, DATA_PARAM_TITLE], - DataProcess.Param[index, DATA_PARAM_LINK], - DataProcess.Param[index, DATA_PARAM_AUTHORS], - DataProcess.Param[index, DATA_PARAM_ARTISTS], - DataProcess.Param[index, DATA_PARAM_GENRES], + ADataProcess.Data.Strings[AIndex] := SetParams( + [ADataProcess.Param[AIndex, DATA_PARAM_TITLE], + ADataProcess.Param[AIndex, DATA_PARAM_LINK], + ADataProcess.Param[AIndex, DATA_PARAM_AUTHORS], + ADataProcess.Param[AIndex, DATA_PARAM_ARTISTS], + ADataProcess.Param[AIndex, DATA_PARAM_GENRES], mangaInfo.status, - DataProcess.Param[index, DATA_PARAM_SUMMARY], + ADataProcess.Param[AIndex, DATA_PARAM_SUMMARY], IntToStr(mangaInfo.numChapter), {$IFDEF DOWNLOADER} - DataProcess.Param[index, DATA_PARAM_JDN], + ADataProcess.Param[AIndex, DATA_PARAM_JDN], {$ELSE} '0', {$ENDIF} '0']); // then break it into parts - dataProcess.BreakDataToParts(index); + ADataProcess.BreakDataToParts(AIndex); end; -procedure TMangaInformation.SyncInfoToData(const DataProcess: TDataProcess; const index: Cardinal); +procedure TMangaInformation.SyncInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); begin // sync info to data {$IFDEF DOWNLOADER} - if not dataProcess.isFilterAllSites then + if not ADataProcess.isFilterAllSites then {$ENDIF} begin if Trim(mangaInfo.title) = '' then - mangaInfo.title := DataProcess.Param[index, DATA_PARAM_TITLE]; - DataProcess.Data.Strings[index] := SetParams( - //[DataProcess.Param[index, DATA_PARAM_TITLE], + mangaInfo.title := ADataProcess.Param[AIndex, DATA_PARAM_TITLE]; + ADataProcess.Data.Strings[AIndex] := SetParams( + //[ADataProcess.Param[AIndex, DATA_PARAM_TITLE], //sync title as well, some site possible to change title or when mangainfo script not work [mangaInfo.title, - DataProcess.Param[index, DATA_PARAM_LINK], + ADataProcess.Param[AIndex, DATA_PARAM_LINK], mangaInfo.authors, mangaInfo.artists, mangaInfo.genres, @@ -1652,37 +1652,37 @@ procedure TMangaInformation.SyncInfoToData(const DataProcess: TDataProcess; cons StringFilter(mangaInfo.summary), IntToStr(mangaInfo.numChapter), {$IFDEF DOWNLOADER} - DataProcess.Param[index, DATA_PARAM_JDN], + ADataProcess.Param[AIndex, DATA_PARAM_JDN], {$ELSE} '0', {$ENDIF} '0']); end; // then break it into parts - dataProcess.BreakDataToParts(index); + ADataProcess.BreakDataToParts(AIndex); end; -procedure TMangaInformation.SyncInfoToData(const DataProcess: TDBDataProcess); +procedure TMangaInformation.SyncInfoToData(const ADataProcess: TDBDataProcess); begin - if Assigned(DataProcess) then + if Assigned(ADataProcess) then with mangaInfo do - DataProcess.UpdateData(title, link, authors, artists, genres, status, summary, + ADataProcess.UpdateData(title, link, authors, artists, genres, status, summary, numChapter, website); end; -procedure TMangaInformation.AddInfoToDataWithoutBreak(const Name, link: String; - const DataProcess: TDataProcess); +procedure TMangaInformation.AddInfoToDataWithoutBreak(const AName, ALink: String; + const ADataProcess: TDataProcess); var S: String; begin if mangaInfo.title <> '' then S := mangaInfo.title else - S := Name; + S := AName; - DataProcess.Data.Add(RemoveStringBreaks(SetParams([ + ADataProcess.Data.Add(RemoveStringBreaks(SetParams([ S, - link, + ALink, mangaInfo.authors, mangaInfo.artists, mangaInfo.genres, @@ -1698,16 +1698,16 @@ procedure TMangaInformation.AddInfoToDataWithoutBreak(const Name, link: String; ]))); end; -procedure TMangaInformation.AddInfoToData(const Name, link: String; const DataProcess: TDataProcess); +procedure TMangaInformation.AddInfoToData(const AName, Alink: String; const ADataProcess: TDataProcess); var l: TStringList; begin l := TStringList.Create; - DataProcess.Data.Add( + ADataProcess.Data.Add( RemoveStringBreaks( SetParams( - [Name, - link, + [AName, + Alink, mangaInfo.authors, mangaInfo.artists, mangaInfo.genres, @@ -1716,37 +1716,37 @@ procedure TMangaInformation.AddInfoToData(const Name, link: String; const DataPr IntToStr(mangaInfo.numChapter), IntToStr(GetCurrentJDN), '0']))); - GetParams(l, DataProcess.Data.Strings[DataProcess.Data.Count - 1]); - DataProcess.title.Add(l.Strings[DATA_PARAM_TITLE]); - DataProcess.link.Add(l.Strings[DATA_PARAM_LINK]); - DataProcess.authors.Add(l.Strings[DATA_PARAM_AUTHORS]); - DataProcess.artists.Add(l.Strings[DATA_PARAM_ARTISTS]); - DataProcess.genres.Add(l.Strings[DATA_PARAM_GENRES]); - DataProcess.status.Add(l.Strings[DATA_PARAM_STATUS]); - DataProcess.summary.Add(l.Strings[DATA_PARAM_SUMMARY]); + GetParams(l, ADataProcess.Data.Strings[ADataProcess.Data.Count - 1]); + ADataProcess.title.Add(l.Strings[DATA_PARAM_TITLE]); + ADataProcess.link.Add(l.Strings[DATA_PARAM_LINK]); + ADataProcess.authors.Add(l.Strings[DATA_PARAM_AUTHORS]); + ADataProcess.artists.Add(l.Strings[DATA_PARAM_ARTISTS]); + ADataProcess.genres.Add(l.Strings[DATA_PARAM_GENRES]); + ADataProcess.status.Add(l.Strings[DATA_PARAM_STATUS]); + ADataProcess.summary.Add(l.Strings[DATA_PARAM_SUMMARY]); {$IFDEF DOWNLOADER} - DataProcess.jdn.Add(Pointer(StrToInt(l.Strings[DATA_PARAM_JDN]))); + ADataProcess.jdn.Add(Pointer(StrToInt(l.Strings[DATA_PARAM_JDN]))); {$ELSE} DataProcess.jdn.Add(Pointer(StrToInt('0'))); {$ENDIF} l.Free; end; -procedure TMangaInformation.AddInfoToData(const Title, Link: String; const DataProcess: TDBDataProcess); +procedure TMangaInformation.AddInfoToData(const ATitle, ALink: String; const ADataProcess: TDBDataProcess); begin - if Assigned(DataProcess) then + if Assigned(ADataProcess) then begin - if (mangaInfo.title = '') and (Title <> '') then mangaInfo.title := Title; - if (mangaInfo.link = '') and (Link <> '') then mangaInfo.link := Link; + if (mangaInfo.title = '') and (ATitle <> '') then mangaInfo.title := ATitle; + if (mangaInfo.link = '') and (ALink <> '') then mangaInfo.link := ALink; with mangaInfo do - DataProcess.AddData(title, link, authors, artists, genres, status, + ADataProcess.AddData(title, link, authors, artists, genres, status, StringBreaks(summary), numChapter, Now); end; end; -function TMangaInformation.GetPage(var output: TObject; URL: String; const Reconnect: Integer): Boolean; +function TMangaInformation.GetPage(var AOutput: TObject; AURL: String; const AReconnect: Integer): Boolean; begin - Result := uBaseUnit.GetPage(FHTTP, output, URL, Reconnect); + Result := uBaseUnit.GetPage(FHTTP, AOutput, AURL, AReconnect); end; end. From 7280af9cadb1f7d0a0b875890e7d92db0eacae6e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 20:31:57 +0800 Subject: [PATCH 1489/2794] updatethread, fill link before get --- baseunits/uUpdateThread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 2150aaed2..5a53fccd3 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -216,6 +216,7 @@ procedure TUpdateListThread.Execute; CS_INFO: begin Info.mangaInfo.title:=title; + Info.mangaInfo.link:=link; if link<>'' then begin Info.GetInfoFromURL(manager.website,link,DefaultRetryCount); // status = '-1' mean it's not exist and shouldn't be saved to database From dc0d793cc4d7b79a299632ad32ccd8d2d03e2e7e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 11 Jan 2017 20:47:39 +0800 Subject: [PATCH 1490/2794] mangatraders, don't replace directory url, use auto redirect --- baseunits/modules/MangaLife.pas | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 73f41b0c2..678cdb720 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -107,7 +107,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; var v: IXQValue; s: String; - i: Integer; begin Result := NET_PROBLEM; s := Module.RootURL + dirURL; @@ -130,10 +129,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; finally Free; end; - if (Module = MMangaTraders) and (ALinks.Count > 0) then - for i := 0 to ALinks.Count - 1 do - if Pos('/series/', ALinks[i]) <> 0 then - ALinks[i] := StringReplace(ALinks[i], '/series/', '/manga/', []); end; end; @@ -169,8 +164,7 @@ function GetInfo(const MangaInfo: TMangaInformation; if Pos('/manga/', s) <> 0 then begin s := MaybeFillHost(Module.RootURL, s); - url := s; - if GET(url) then + if GET(s) then ParseHTML(Document) else r := False; From c5b161f0303690cb4e7337b9c46f7c5b42cb2f09 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 07:59:29 +0800 Subject: [PATCH 1491/2794] added method xpathhrefall --- baseunits/XQueryEngineHTML.pas | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 7e8ba74fb..47fe86415 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -41,6 +41,8 @@ TXQueryEngineHTML = class const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; inline; procedure XPathStringAll(const Expression: String; const TheStrings: TStrings; const ContextItem: IXQValue = nil); overload; inline; + procedure XPathHREFAll(const Expression: String; const ALinks, ATexts: TStrings; + const ContextItem: IXQValue = nil); // css function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function CSS(const Expression: String; const ContextItem: IXQValue): IXQValue; inline; @@ -262,6 +264,18 @@ procedure TXQueryEngineHTML.XPathStringAll(const Expression: String; EvalStringAll(Expression, False, TheStrings, ContextItem); end; +procedure TXQueryEngineHTML.XPathHREFAll(const Expression: String; + const ALinks, ATexts: TStrings; const ContextItem: IXQValue); +var + v: IXQValue; +begin + for v in Eval(Expression, False, ContextItem) do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ATexts.Add(v.toString); + end; +end; + function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, True, nil, Tree); From 6cd6f36d28784cbc46192c171bd07ec95c5988c0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 08:59:18 +0800 Subject: [PATCH 1492/2794] rewrite all japscan code. closed #432 --- baseunits/ModuleList.inc | 1 + baseunits/modules/JapScan.pas | 119 ++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 baseunits/modules/JapScan.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 129ec6974..6d9910c95 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -52,6 +52,7 @@ uses MyMangaMe, ReadComics, MangaCool, + JapScan, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas new file mode 100644 index 000000000..979db0969 --- /dev/null +++ b/baseunits/modules/JapScan.pas @@ -0,0 +1,119 @@ +unit JapScan; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread; + +implementation + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/mangas/') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFAll('//*[@id="liste_mangas"]/div[@class="row"]/div[@class="cell"]/a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + title := XPathString('//title'); + if Pos(' | Japscan.Com', title) <> 0 then + title := GetString(title, 'Lecture En Ligne Des Chapitres ', ' | Japscan.Com'); + authors := XPathString('//div[@class="table"]/div[@class="row"]/div[1]'); + genres := XPathString('//div[@class="table"]/div[@class="row"]/div[4]'); + summary := XPathString('//div[@id="synopsis"]/text()'); + status := MangaInfoStatusIfPos(XPathString('//div[@class="table"]/div[@class="row"]/div[6]'), 'En Cours', 'Terminé'); + for v in XPath('//*[@id="liste_chapitres"]/ul/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + s := v.toString; + if Pos('[email protected]', s) <> 0 then + s := title + ' ' + XPathString('text()[2]', v) + else + if Pos('Scan ', s) = 1 then + Delete(s, 1, 5); + chapterName.Add(s); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; + dataimg, imgurl: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + v := XPath('//img[@id="image"]'); + dataimg := v.toNode.getAttribute('data-img'); + imgurl := v.toNode.getAttribute('src'); + if Pos(dataimg, imgurl) <> 0 then + begin + imgurl := StringReplace(imgurl, dataimg, '', []); + for v in XPath('//select[@id="pages"]/option/@data-img') do + PageLinks.Add(imgurl + v.toString); + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'JapScan'; + RootURL := 'http://www.japscan.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From faa747a6e0a5dfa87dd3db1d7eb2fd3667db73db Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 09:02:19 +0800 Subject: [PATCH 1493/2794] remove japscan old codes --- .../includes/Japscan/chapter_page_number.inc | 55 --------- baseunits/includes/Japscan/image_url.inc | 32 ----- .../includes/Japscan/manga_information.inc | 110 ------------------ .../includes/Japscan/names_and_links.inc | 35 ------ baseunits/uBaseUnit.pas | 54 +++++---- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 10 -- 7 files changed, 26 insertions(+), 280 deletions(-) delete mode 100644 baseunits/includes/Japscan/chapter_page_number.inc delete mode 100644 baseunits/includes/Japscan/image_url.inc delete mode 100644 baseunits/includes/Japscan/manga_information.inc delete mode 100644 baseunits/includes/Japscan/names_and_links.inc diff --git a/baseunits/includes/Japscan/chapter_page_number.inc b/baseunits/includes/Japscan/chapter_page_number.inc deleted file mode 100644 index 2650e36e1..000000000 --- a/baseunits/includes/Japscan/chapter_page_number.inc +++ /dev/null @@ -1,55 +0,0 @@ - function GetJapscanPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - regx: TRegExpr; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(JAPSCAN_ID, URL)); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - - CleanHTMLComments(l); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - Task.Container.PageNumber := 0; - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '^.*/(\d+)\.html?.*$'; - regx.ModifierI := True; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'nav') and - (GetVal(parse[i], 'id') = 'pagination') then - isGetPageNumber := True; - if isGetPageNumber and ((GetTagName(parse[i]) = '/nav') or - (GetVal(parse[i], 'id') = 'next_link') or - (GetVal(parse[i], 'id') = 'next_chapter')) then - Break; - if isGetPageNumber and (GetTagName(parse[i]) = 'a') then - begin - s := GetVal(parse[i], 'href'); - s := regx.Replace(s, '$1', True); - if Task.Container.PageNumber < StrToIntDef(s, 0) then - Task.Container.PageNumber := StrToIntDef(s, 0); - end; - end; - finally - regx.Free; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Japscan/image_url.inc b/baseunits/includes/Japscan/image_url.inc deleted file mode 100644 index 6751199ff..000000000 --- a/baseunits/includes/Japscan/image_url.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetJapscanImageURL: Boolean; - var - s: string; - i: Integer; - l: TStringList; - begin - s := DecodeUrl(FillMangaSiteHost(JAPSCAN_ID, URL)); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/' + IntToStr(WorkId + 1) + '.html'; - l := TStringList.Create; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = 'imgscan') then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Japscan/manga_information.inc b/baseunits/includes/Japscan/manga_information.inc deleted file mode 100644 index 6c3851e81..000000000 --- a/baseunits/includes/Japscan/manga_information.inc +++ /dev/null @@ -1,110 +0,0 @@ - function GetJapscanInfoFromURL: Byte; - var - s: String; - i: Cardinal; - row: TStringList; - isRow: Boolean = False; - isExtractChapter: Boolean = False; - regx: TRegExpr; - - begin - mangaInfo.url := FillMangaSiteHost(JAPSCAN_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[JAPSCAN_ID, 0]; - - mangaInfo.coverLink := ''; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - row := TStringList.Create; - for i := 0 to parse.Count - 1 do - begin - //get title - if Pos('<h1 class="bg-header"', parse[i]) > 0 then - begin - regx := TRegExpr.Create; - regx.ModifierI := True; - regx.Expression := '^Manga\s(.+)\sVF$'; - s := regx.Replace(Trim(parse[i + 2]), '$1', True); - mangaInfo.title := s; - regx.Free; - end; - - // author, year, genres, fansubs and status respectively - if (Pos('<div class="row"', parse[i]) > 0) then - isRow := True; - if isRow and (Pos('<h2', parse[i]) > 0) then - isRow := False; - - if isRow and (Pos('class="cell"', parse[i]) > 0) then - begin - if Pos('href="', parse[i + 1]) > 0 then - row.Add(Trim(parse[i + 2])) - else - row.Add(Trim(parse[i + 1])); - end; - - //get status - if isRow and (Pos('class="cell"', parse[i]) > 0) then - begin - if Trim(parse[i + 1]) = 'En Cours' then - mangaInfo.status := '1' - else - if Trim(parse[i + 1]) = 'Terminé' then - mangaInfo.status := '0'; - end; - - //get summary - if Pos('id="synopsis"', parse[i]) > 0 then - mangaInfo.summary := Trim(parse[i + 1]); - - // get chapter name and links - if Pos('id="liste_chapitres"', parse[i]) > 0 then - isExtractChapter := True; - if isExtractChapter and (Pos('</div', parse[i]) > 0) then - isExtractChapter := False; - - if (isExtractChapter) and (Pos('<a href="', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse[i + 1])); - mangaInfo.chapterName.Add(CommonStringFilter(s)); - end; - end; - - //author, year, genres, fansubs and status respectively - if row.Count >= 5 then - begin - mangaInfo.authors := row[0]; - mangaInfo.genres := row[2]; - if mangaInfo.genres = '' then - mangaInfo.genres := row[3] - else - mangaInfo.genres := mangaInfo.genres + ', ' + row[3]; - end; - row.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Japscan/names_and_links.inc b/baseunits/includes/Japscan/names_and_links.inc deleted file mode 100644 index 8d27137e5..000000000 --- a/baseunits/includes/Japscan/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function JapscanNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[JAPSCAN_ID, 1] + - JAPSCAN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - - ALinks.Clear; - ANames.Clear; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="cell', parse[i]) > 0) then - if (Pos(' href="/mangas/', parse[i + 1]) > 0) then - begin - Result := NO_ERROR; - ALinks.Add(GetVal(parse[i + 1], 'href')); - ANames.Add(Trim(parse[i + 2])); - end; - end; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5e576c95b..dd1f0b25a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -270,32 +270,32 @@ interface NINEMANGA_IT_ID = 36; NINEMANGA_BR_ID = 37; JAPANSHIN_ID = 38; - JAPSCAN_ID = 39; - CENTRUMMANGI_PL_ID = 40; - MANGALIB_PL_ID = 41; - ONEMANGA_ID = 42; - MANGATOWN_ID = 43; - MANGAOKU_ID = 44; - MYREADINGMANGAINFO_ID = 45; - IKOMIK_ID = 46; - NHENTAI_ID = 47; - MANGAMINT_ID = 48; - UNIXMANGA_ID = 49; - EXTREMEMANGAS_ID = 50; - MANGAHOST_ID = 51; - PORNCOMIX_ID = 52; - PORNCOMIXRE_ID = 53; - PORNCOMIXIC_ID = 54; - XXCOMICS_ID = 55; - XXCOMICSMT_ID = 56; - XXCOMICS3D_ID = 57; - PORNXXXCOMICS_ID = 58; - MANGAKU_ID = 59; - MANGAAT_ID = 60; - READMANGATODAY_ID = 61; - DYNASTYSCANS_ID = 62; - - WebsiteRoots: array [0..62] of array [0..1] of String = ( + + CENTRUMMANGI_PL_ID = 39; + MANGALIB_PL_ID = 40; + ONEMANGA_ID = 41; + MANGATOWN_ID = 42; + MANGAOKU_ID = 43; + MYREADINGMANGAINFO_ID = 44; + IKOMIK_ID = 45; + NHENTAI_ID = 46; + MANGAMINT_ID = 47; + UNIXMANGA_ID = 48; + EXTREMEMANGAS_ID = 49; + MANGAHOST_ID = 50; + PORNCOMIX_ID = 51; + PORNCOMIXRE_ID = 52; + PORNCOMIXIC_ID = 53; + XXCOMICS_ID = 54; + XXCOMICSMT_ID = 55; + XXCOMICS3D_ID = 56; + PORNXXXCOMICS_ID = 57; + MANGAKU_ID = 58; + MANGAAT_ID = 59; + READMANGATODAY_ID = 60; + DYNASTYSCANS_ID = 61; + + WebsiteRoots: array [0..61] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -335,7 +335,6 @@ interface ('NineManga_IT', 'http://it.ninemanga.com'), ('NineManga_BR', 'http://br.ninemanga.com'), ('Japan-Shin', 'http://www.japan-shin.com'), - ('Japscan', 'http://www.japscan.com'), ('Centrum-Mangi_PL', 'http://centrum-mangi.pl'), ('Manga-Lib_PL', 'http://www.manga-lib.pl/index.php'), ('OneManga', 'http://www.onemanga2.com'), @@ -435,7 +434,6 @@ interface '/search/?name_sel=contain&wd=&author_sel=contain&author=&artist_sel=contain&artist=&category_id=&out_category_id=&completed_series=either'; JAPANSHIN_BROWSER = '/lectureenligne/reader/list/'; - JAPSCAN_BROWSER = '/mangas/'; CENTRUMMANGI_PL_BROWSER = '/spis/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 2a3f7c85e..39d472b63 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1006,8 +1006,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/JapanShin/names_and_links.inc} - {$I includes/Japscan/names_and_links.inc} - {$I includes/CentrumMangi_PL/names_and_links.inc} {$I includes/MangaLib_PL/names_and_links.inc} @@ -1150,9 +1148,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if WebsiteID = JAPANSHIN_ID then Result := JapanShinGetNamesAndLinks else - if WebsiteID = JAPSCAN_ID then - Result := JapscanNamesAndLinks - else if WebsiteID = CENTRUMMANGI_PL_ID then Result := CentrumMangi_PLGetNamesAndLinks else @@ -1291,8 +1286,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/JapanShin/manga_information.inc} - {$I includes/Japscan/manga_information.inc} - {$I includes/CentrumMangi_PL/manga_information.inc} {$I includes/MangaLib_PL/manga_information.inc} @@ -1446,9 +1439,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if WebsiteID = JAPANSHIN_ID then Result := GetJapanShinInfoFromURL else - if WebsiteID = JAPSCAN_ID then - Result := GetJapscanInfoFromURL - else if WebsiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index beb7cc645..5423ce8d4 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -436,8 +436,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/JapanShin/chapter_page_number.inc} - {$I includes/Japscan/chapter_page_number.inc} - {$I includes/CentrumMangi_PL/chapter_page_number.inc} {$I includes/MangaLib_PL/chapter_page_number.inc} @@ -534,9 +532,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinPageNumber else - if Task.Container.MangaSiteID = JAPSCAN_ID then - Result := GetJapscanPageNumber - else if Task.Container.MangaSiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLPageNumber else @@ -656,8 +651,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/JapanShin/image_url.inc} - {$I includes/Japscan/image_url.inc} - {$I includes/CentrumMangi_PL/image_url.inc} {$I includes/MangaLib_PL/image_url.inc} @@ -776,9 +769,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinImageURL else - if Task.Container.MangaSiteID = JAPSCAN_ID then - Result := GetJapscanImageURL - else if Task.Container.MangaSiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLImageURL else From e74cffd8f8e9cce5965081fcf2ce4d8c7bf698cb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 09:56:19 +0800 Subject: [PATCH 1494/2794] added method xpathhreftitleall --- baseunits/XQueryEngineHTML.pas | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 47fe86415..0dedcbaad 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -43,6 +43,8 @@ TXQueryEngineHTML = class const ContextItem: IXQValue = nil); overload; inline; procedure XPathHREFAll(const Expression: String; const ALinks, ATexts: TStrings; const ContextItem: IXQValue = nil); + procedure XPathHREFtitleAll(const Expression: String; const ALinks, ATitles: TStrings; + const ContextItem: IXQValue = nil); // css function CSS(const Expression: String; const Tree: TTreeNode = nil): IXQValue; inline; function CSS(const Expression: String; const ContextItem: IXQValue): IXQValue; inline; @@ -276,6 +278,18 @@ procedure TXQueryEngineHTML.XPathHREFAll(const Expression: String; end; end; +procedure TXQueryEngineHTML.XPathHREFtitleAll(const Expression: String; + const ALinks, ATitles: TStrings; const ContextItem: IXQValue); +var + v: IXQValue; +begin + for v in Eval(Expression, False, ContextItem) do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ATitles.Add(v.toNode.getAttribute('title')); + end; +end; + function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; begin Result := Eval(Expression, True, nil, Tree); From e85188b690a8bf3a654177a091d4edfe7d6be0e2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 09:56:53 +0800 Subject: [PATCH 1495/2794] japscan, fixed multiline summary --- baseunits/modules/JapScan.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas index 979db0969..7bc9daeef 100644 --- a/baseunits/modules/JapScan.pas +++ b/baseunits/modules/JapScan.pas @@ -47,7 +47,7 @@ function GetInfo(const MangaInfo: TMangaInformation; title := GetString(title, 'Lecture En Ligne Des Chapitres ', ' | Japscan.Com'); authors := XPathString('//div[@class="table"]/div[@class="row"]/div[1]'); genres := XPathString('//div[@class="table"]/div[@class="row"]/div[4]'); - summary := XPathString('//div[@id="synopsis"]/text()'); + summary := XPathString('//div[@id="synopsis"]/string-join(text(),codepoints-to-string(10))'); status := MangaInfoStatusIfPos(XPathString('//div[@class="table"]/div[@class="row"]/div[6]'), 'En Cours', 'Terminé'); for v in XPath('//*[@id="liste_chapitres"]/ul/li/a') do begin From 154449585bf32208d54614a9fd20ff9c9854dae8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 12:20:23 +0800 Subject: [PATCH 1496/2794] rewrite all mangago codes. closed #440,#445 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaGo.pas | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 baseunits/modules/MangaGo.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 6d9910c95..99db297c9 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -53,6 +53,7 @@ uses ReadComics, MangaCool, JapScan, + MangaGo, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas new file mode 100644 index 000000000..68f0c0052 --- /dev/null +++ b/baseunits/modules/MangaGo.pas @@ -0,0 +1,136 @@ +unit MangaGo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, Cloudflare; + +implementation + +var + cookies: String; + lockget: TRTLCriticalSection; + +const + dirurl= '/list/directory/all/'; + +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +begin + Result := Cloudflare.GETCF(AHTTP, AURL, cookies, lockget) +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + '1/') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := XPath('//div[@class="pagination"]//ol/li//select/option').Count; + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + IncStr(AURL) + '/') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFtitleAll('//div[@class="directory_left"]//li/h3/a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GETWithCookie(MangaInfo.FHTTP, url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="left cover"]/img/@src')); + title := XPathString('//h1'); + status := MangaInfoStatusIfPos(XPathString('//div[@class="manga_right"]//td/label[.="Status:"]/following-sibling::*/text()')); + authors := XPathString('//div[@class="manga_right"]//td/label[.="Author:"]/string-join(following-sibling::*/text(),", ")'); + genres := XPathString('//div[@class="manga_right"]//td/label[.="Genre(s):"]/string-join(following-sibling::*/text(),", ")'); + summary := XPathString('//div[@class="manga_summary"]/string-join(text(),codepoints-to-string(10))'); + XPathHREFAll('//table[@id="chapter_table"]//td//a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + s := XPathString('//script[contains(.,"imgsrcs = new Array")]', Document); + if s <> '' then + begin + s := GetString(s, 'new Array(', ');'); + s := StringReplace(s, ''',''', LineEnding, [rfReplaceAll]); + s := StringReplace(s, '''', '', [rfReplaceAll]); + s := StringReplace(s, '","', LineEnding, [rfReplaceAll]); + s := StringReplace(s, '"', '', [rfReplaceAll]); + PageLinks.Text := s; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaGo'; + RootURL := 'http://www.mangago.me'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + InitCriticalSection(lockget); + RegisterModule; + +finalization + DoneCriticalsection(lockget); + +end. From f727c8836071a30812d7f050d61b964fa6f7be3e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 12:23:54 +0800 Subject: [PATCH 1497/2794] remove old mangago codes --- .../includes/MangaGo/chapter_page_number.inc | 33 ------ .../MangaGo/directory_page_number.inc | 36 ------ baseunits/includes/MangaGo/image_url.inc | 48 -------- .../includes/MangaGo/manga_information.inc | 103 ------------------ .../includes/MangaGo/names_and_links.inc | 38 ------- baseunits/uBaseUnit.pas | 82 +++++++------- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 10 -- 8 files changed, 38 insertions(+), 327 deletions(-) delete mode 100644 baseunits/includes/MangaGo/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaGo/directory_page_number.inc delete mode 100644 baseunits/includes/MangaGo/image_url.inc delete mode 100644 baseunits/includes/MangaGo/manga_information.inc delete mode 100644 baseunits/includes/MangaGo/names_and_links.inc diff --git a/baseunits/includes/MangaGo/chapter_page_number.inc b/baseunits/includes/MangaGo/chapter_page_number.inc deleted file mode 100644 index 21bcdb5ce..000000000 --- a/baseunits/includes/MangaGo/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetMangaGoPageNumber: Boolean; - var - i: Cardinal; - s: String; - l: TStringList; - regx: TRegExpr; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAGO_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - if Pos('total_pages=', parse[i]) > 0 then - begin - regx := TRegExpr.Create; - regx.Expression := '^.*total_pages=(\d+)\b.*$'; - Task.container.PageNumber := - StrToIntDef(regx.Replace(parse[i], '$1', True), 0); - regx.Free; - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaGo/directory_page_number.inc b/baseunits/includes/MangaGo/directory_page_number.inc deleted file mode 100644 index b6cf48981..000000000 --- a/baseunits/includes/MangaGo/directory_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetMangaGoDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + - MANGAGO_BROWSER + '1/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="pagination"', parse[i]) <> 0) then - begin - s := TrimLeft(TrimRight(GetVal(parse[i], 'total'))); - APage := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/MangaGo/image_url.inc b/baseunits/includes/MangaGo/image_url.inc deleted file mode 100644 index 558621cb1..000000000 --- a/baseunits/includes/MangaGo/image_url.inc +++ /dev/null @@ -1,48 +0,0 @@ - function GetMangaGoImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - regx: TRegExpr; - s: String; - begin - l := TStringList.Create; - regx := TRegExpr.Create; - regx.Expression := '^(.*/pg-)\d+/$'; - s := regx.Replace(URL, '$1', True); - //regx.Expression := '\.html?$'; - regx.Expression := '\-$'; - if (not regx.Exec(s)) and (s[Length(s)] <> '/') then - s := s + '/'; - s := FillMangaSiteHost(MANGAGO_ID, s); - Result := GetPage(TObject(l), s + IntToStr(WorkId + 1) + '/', - Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - regx.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('imgReady(''', parse[i]) > 0) then - begin - regx.Expression := '^.*imgReady\(''([^'']*)''.*$'; - Task.Container.PageLinks[WorkId] := regx.Replace(parse[i], '$1', True); - Break; - end; - end; - regx.Free; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaGo/manga_information.inc b/baseunits/includes/MangaGo/manga_information.inc deleted file mode 100644 index 96a2a2aa3..000000000 --- a/baseunits/includes/MangaGo/manga_information.inc +++ /dev/null @@ -1,103 +0,0 @@ - function GetMangaGoInfoFromURL: Byte; - var - i: Integer; - isExtractGenres: Boolean = False; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAGO_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAGO_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get title - if (i + 3 < parse.Count - 1) then - if (Pos('name="description"', parse[i]) > 0) and (mangaInfo.title = '') then - mangaInfo.title := StringReplace(TrimLeft(StringFilter(parse[i + 3])), - ' manga - Mangago', '', []); - - // get status - if (i + 5 < parse.Count - 1) then - if (Pos('<label>', parse[i]) > 0) and - (Pos('Status:', parse[i + 1]) > 0) and - (Pos('Completed', parse[i + 5]) > 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - - // get cover - if (Pos('<meta', parse[i]) > 0) and - (Pos('property="og:image"', parse[i]) > 0) then - mangaInfo.coverLink := - (GetVal(parse[i], 'content')); - - // get authors - if (i + 1 < parse.Count - 1) then - if (Pos('<label>', parse[i]) > 0) and - (Pos('Author:', parse[i + 1]) > 0) then - mangaInfo.authors := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 5]))); - - // get genres - if (i + 1 < parse.Count - 1) then - if (Pos('<label>', parse[i]) > 0) and - (Pos('Genre(s)', parse[i + 1]) > 0) then - isExtractGenres := True; - - if (i + 1 < parse.Count - 1) then - if isExtractGenres then - begin - if Pos('</td>', parse[i]) > 0 then - isExtractGenres := False; - if Pos('/genre/', parse[i]) > 0 then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - end; - end; - - // get summary - if (i + 1 < parse.Count - 1) then - if Pos('class="manga_summary"', parse[i]) > 0 then - mangaInfo.summary := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - - //get chapter links and names - if (GetTagName(parse[i]) = 'table') and - ((GetVal(parse[i], 'id') = 'chapter_table') or (GetVal(parse[i], 'id') = 'raws_table')) then - isExtractChapters := True; - if isExtractChapters then - begin - if GetTagName(parse[i]) = '/table' then - isExtractChapters := False; - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'chico') then - begin - Inc(mangaInfo.numChapter); - mangaInfo.ChapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.ChapterName.Add(CommonStringFilter(Trim(parse[i + 1]) + ' ' + - Trim(parse[i + 3]) + ' ' + Trim(parse[i + 5]))); - end; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - InvertStrings([mangaInfo.ChapterName, mangaInfo.ChapterLinks]); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaGo/names_and_links.inc b/baseunits/includes/MangaGo/names_and_links.inc deleted file mode 100644 index 7bbf0d2d8..000000000 --- a/baseunits/includes/MangaGo/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function MangaGoGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAGO_ID, 1] + - MANGAGO_BROWSER + IntToStr(StrToInt(AURL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('h3 class="title"', parse[i]) > 0 then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - ANames.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i + 1], 'href'); - s := StringReplace(s, WebsiteRoots[MANGAGO_ID, 1], '', []); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dd1f0b25a..7c5fd3183 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -255,47 +255,44 @@ interface ANIMESTORY_ID = 22; LECTUREENLIGNE_ID = 23; SCANMANGA_ID = 24; - MANGAGO_ID = 25; - DM5_ID = 26; - - KIVMANGA_ID = 27; - MEINMANGA_ID = 28; - MANGASPROJECT_ID = 29; - MANGAREADER_POR_ID = 30; - NINEMANGA_ID = 31; - NINEMANGA_ES_ID = 32; - NINEMANGA_CN_ID = 33; - NINEMANGA_RU_ID = 34; - NINEMANGA_DE_ID = 35; - NINEMANGA_IT_ID = 36; - NINEMANGA_BR_ID = 37; - JAPANSHIN_ID = 38; - - CENTRUMMANGI_PL_ID = 39; - MANGALIB_PL_ID = 40; - ONEMANGA_ID = 41; - MANGATOWN_ID = 42; - MANGAOKU_ID = 43; - MYREADINGMANGAINFO_ID = 44; - IKOMIK_ID = 45; - NHENTAI_ID = 46; - MANGAMINT_ID = 47; - UNIXMANGA_ID = 48; - EXTREMEMANGAS_ID = 49; - MANGAHOST_ID = 50; - PORNCOMIX_ID = 51; - PORNCOMIXRE_ID = 52; - PORNCOMIXIC_ID = 53; - XXCOMICS_ID = 54; - XXCOMICSMT_ID = 55; - XXCOMICS3D_ID = 56; - PORNXXXCOMICS_ID = 57; - MANGAKU_ID = 58; - MANGAAT_ID = 59; - READMANGATODAY_ID = 60; - DYNASTYSCANS_ID = 61; - - WebsiteRoots: array [0..61] of array [0..1] of String = ( + DM5_ID = 25; + KIVMANGA_ID = 26; + MEINMANGA_ID = 27; + MANGASPROJECT_ID = 28; + MANGAREADER_POR_ID = 29; + NINEMANGA_ID = 30; + NINEMANGA_ES_ID = 31; + NINEMANGA_CN_ID = 32; + NINEMANGA_RU_ID = 33; + NINEMANGA_DE_ID = 34; + NINEMANGA_IT_ID = 35; + NINEMANGA_BR_ID = 36; + JAPANSHIN_ID = 37; + CENTRUMMANGI_PL_ID = 38; + MANGALIB_PL_ID = 39; + ONEMANGA_ID = 40; + MANGATOWN_ID = 41; + MANGAOKU_ID = 42; + MYREADINGMANGAINFO_ID = 43; + IKOMIK_ID = 44; + NHENTAI_ID = 45; + MANGAMINT_ID = 46; + UNIXMANGA_ID = 47; + EXTREMEMANGAS_ID = 48; + MANGAHOST_ID = 49; + PORNCOMIX_ID = 50; + PORNCOMIXRE_ID = 51; + PORNCOMIXIC_ID = 52; + XXCOMICS_ID = 53; + XXCOMICSMT_ID = 54; + XXCOMICS3D_ID = 55; + PORNXXXCOMICS_ID = 56; + MANGAKU_ID = 57; + MANGAAT_ID = 58; + READMANGATODAY_ID = 59; + DYNASTYSCANS_ID = 60; + + WebsiteRoots: array [0..60] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -321,7 +318,6 @@ interface ('AnimeStory', 'http://www.anime-story.com'), ('Lecture-En-Ligne', 'http://www.lecture-en-ligne.com'), ('ScanManga', 'http://www.scan-manga.com'), - ('MangaGo', 'http://www.mangago.me'), ('DM5', 'http://www.dm5.com'), ('KivManga', 'http://www.kivmanga.com'), ('MeinManga', 'http://www.meinmanga.com/'), @@ -418,8 +414,6 @@ interface SCANMANGA_BROWSER = '/scanlation/liste_des_mangas.html'; - MANGAGO_BROWSER = '/list/directory/all/'; - DM5_BROWSER = '/manhua-new'; KIVMANGA_BROWSER = '/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 39d472b63..23685c64d 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -778,8 +778,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/Fakku/directory_page_number.inc} - {$I includes/MangaGo/directory_page_number.inc} - {$I includes/BlogTruyen/directory_page_number.inc} {$I includes/S2Scans/directory_page_number.inc} @@ -855,9 +853,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if WebsiteID = FAKKU_ID then Result := GetFakkuDirectoryPageNumber else - if WebsiteID = MANGAGO_ID then - Result := GetMangaGoDirectoryPageNumber - else if WebsiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenDirectoryPageNumber else @@ -986,8 +981,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/EatManga/names_and_links.inc} - {$I includes/MangaGo/names_and_links.inc} - {$I includes/S2Scans/names_and_links.inc} {$I includes/EGScans/names_and_links.inc} @@ -1070,9 +1063,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if WebsiteID = EATMANGA_ID then Result := EatMangaGetNamesAndLinks else - if WebsiteID = MANGAGO_ID then - Result := MangaGoGetNamesAndLinks - else if WebsiteID = S2SCAN_ID then Result := S2ScanGetNamesAndLinks else @@ -1248,8 +1238,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/EGScans/manga_information.inc} - {$I includes/MangaGo/manga_information.inc} - {$I includes/TruyenTranhTuan/manga_information.inc} {$I includes/Mabuns/manga_information.inc} @@ -1364,9 +1352,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if WebsiteID = EATMANGA_ID then Result := GetEatMangaInfoFromURL else - if WebsiteID = MANGAGO_ID then - Result := GetMangaGoInfoFromURL - else if WebsiteID = S2SCAN_ID then Result := GetS2scanInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5423ce8d4..8a8e02089 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -418,8 +418,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaAr/chapter_page_number.inc} - {$I includes/MangaGo/chapter_page_number.inc} - {$I includes/MeinManga/chapter_page_number.inc} {$I includes/S2Scans/chapter_page_number.inc} @@ -487,9 +485,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaPageNumber else - if Task.Container.MangaSiteID = MANGAGO_ID then - Result := GetMangaGoPageNumber - else if Task.Container.MangaSiteID = S2SCAN_ID then Result := GetS2scanPageNumber else @@ -627,8 +622,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaEsta/image_url.inc} - {$I includes/MangaGo/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -700,9 +693,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = EATMANGA_ID then Result := GetEatMangaImageURL else - if Task.Container.MangaSiteID = MANGAGO_ID then - Result := GetMangaGoImageURL - else if Task.Container.MangaSiteID = EGSCANS_ID then Result := GetEGScansImageURL else From bc721046f6102f72dd4f0c1e27459a426ff1aa6e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 12:28:58 +0800 Subject: [PATCH 1498/2794] japscan, match module name case with existed website --- baseunits/modules/JapScan.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas index 7bc9daeef..d66fd0af4 100644 --- a/baseunits/modules/JapScan.pas +++ b/baseunits/modules/JapScan.pas @@ -105,7 +105,7 @@ procedure RegisterModule; begin with AddModule do begin - Website := 'JapScan'; + Website := 'Japscan'; RootURL := 'http://www.japscan.com'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From c3d4bbf069593b64b507cac1bd77464c9a93d958 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 12 Jan 2017 12:43:32 +0800 Subject: [PATCH 1499/2794] bump version 0.9.87.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 96108b82b..90a6a1918 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.87.0 (12-01-2017) +[*] MangaTraders: fixed manga list +[*] Japscan: rewrite all codes +[*] MangaGo: rewrite all codes +Full changes: https://github.com/riderkick/FMD/compare/0.9.86.0...0.9.87.0 + 0.9.86.0 (11-01-2017) [+] Added MangaCool[EN] [*] MangaTraders: fixed issue #437 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 530848473..44725a99e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="86"/> + <RevisionNr Value="87"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index baa84975d..2099adb57 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.86.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.86.0/fmd_0.9.86.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.86.0/fmd_0.9.86.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.86.0/fmd_0.9.86.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.86.0/fmd_0.9.86.0_Win64.7z +VERSION=0.9.87.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.87.0/fmd_0.9.87.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.87.0/fmd_0.9.87.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.87.0/fmd_0.9.87.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.87.0/fmd_0.9.87.0_Win64.7z From b9e83aa07322f671f03949874d93ccdb72ba3985 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Thu, 19 Jan 2017 01:23:07 +0530 Subject: [PATCH 1500/2794] GoodManga Added GoodManga. Need to touch up it on Image Get because it download random order. --- baseunits/modules/GoodManga.pas | 136 ++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 baseunits/modules/GoodManga.pas diff --git a/baseunits/modules/GoodManga.pas b/baseunits/modules/GoodManga.pas new file mode 100644 index 000000000..c95a1bb62 --- /dev/null +++ b/baseunits/modules/GoodManga.pas @@ -0,0 +1,136 @@ +unit GoodManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/manga-list'; + imagepath = '//div[@id="manga_viewer"]/a/img/@src'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//td/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@id="series_image"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="right_col"]/h1'); + status := MangaInfoStatusIfPos( + XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), + 'Ongoing', + 'Complete'); + artists := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Artist:")]/following-sibling::*[@class="desc"][1]/a'); + authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); + for v in XPath('//div[@id="chapters"]/ul/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('//div[@id="asset_2"]/select[@class="page_select"]/option').Count; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.WorkId)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.WorkId] := + XPathString(imagepath); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'GoodManga'; + RootURL := 'http://www.goodmanga.net'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From bb4a6ca97186eab999a87a44049251790d6cdd78 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 Jan 2017 17:49:32 +0800 Subject: [PATCH 1501/2794] goodmaga, fixed mangainfo #454 --- baseunits/ModuleList.inc | 1 + baseunits/modules/GoodManga.pas | 270 ++++++++++++++++---------------- 2 files changed, 135 insertions(+), 136 deletions(-) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 99db297c9..eb0312719 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -54,6 +54,7 @@ uses MangaCool, JapScan, MangaGo, + GoodManga, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/GoodManga.pas b/baseunits/modules/GoodManga.pas index c95a1bb62..7c881c48c 100644 --- a/baseunits/modules/GoodManga.pas +++ b/baseunits/modules/GoodManga.pas @@ -1,136 +1,134 @@ -unit GoodManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/manga-list'; - imagepath = '//div[@id="manga_viewer"]/a/img/@src'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//td/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//img[@id="series_image"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@class="right_col"]/h1'); - status := MangaInfoStatusIfPos( - XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), - 'Ongoing', - 'Complete'); - artists := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Artist:")]/following-sibling::*[@class="desc"][1]/a'); - authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); - for v in XPath('//div[@id="chapters"]/ul/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('//div[@id="asset_2"]/select[@class="page_select"]/option').Count; - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.WorkId)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := - XPathString(imagepath); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'GoodManga'; - RootURL := 'http://www.goodmanga.net'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. +unit GoodManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/manga-list'; + imagepath = '//div[@id="manga_viewer"]/a/img/@src'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFAll('//td/a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@id="series_image"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="right_col"]/h1'); + authors := XPathString('//div[@id="series_details"]/div/span[starts-with(.,"Authors:")]/following-sibling::text()'); + summary := XPathString('//div[@id="series_details"]/div//span[@id="full_notes"]'); + if summary = '' then + summary := XPathString('//div[@id="series_details"]/div/span[starts-with(.,"Synopsis:")]/following-sibling::*'); + status := MangaInfoStatusIfPos(XPathString('//div[@id="series_details"]/div/span[starts-with(.,"Status:")]/following-sibling::text()')); + genres := XPathString('//div[@id="series_details"]/div/span[starts-with(.,"Genres:")]/string-join(following-sibling::*,", ")'); + while true do + begin + XPathHREFAll('//div[@id="chapters"]/ul/li/a', chapterLinks, chapterName); + if Thread.IsTerminated then Break; + s := XPathString('//ul[@class="pagination"]/li/a[.="Next"]/@href'); + if (s <> '') and GET(MaybeFillHost(Module.RootURL, s)) then + ParseHTML(Document) + else + Break; + end; + InvertStrings([chapterLinks,chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageNumber := XPath('//div[@id="asset_2"]/select[@class="page_select"]/option').Count; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.WorkId)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.WorkId] := + XPathString(imagepath); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'GoodManga'; + RootURL := 'http://www.goodmanga.net'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. From 8e9c3d6ffa5060712a033aa5f3734648c4c8fd46 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 Jan 2017 18:00:32 +0800 Subject: [PATCH 1502/2794] added goodmanga to mangaist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 5cf8e7d54..cbbdeb7ee 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics English-Italian=MangaEden,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 5ea66f716cc5fcba42479cf301b19b8117f0655a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 Jan 2017 18:25:53 +0800 Subject: [PATCH 1503/2794] hide button delete all completed task on download list toolbar --- mangadownloader/forms/frmMain.lfm | 97 +++++++++++++------------- mangadownloader/forms/frmMain.lrj | 15 ++-- mangadownloader/languages/fmd.en.po | 5 +- mangadownloader/languages/fmd.id_ID.po | 5 +- mangadownloader/languages/fmd.po | 4 -- 5 files changed, 59 insertions(+), 67 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 335b29c7d..0abfb62e4 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.7' + Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -254,6 +254,7 @@ object MainForm: TMainForm Top = 0 Width = 5 Style = tbsDivider + Visible = False end object tbDownloadDeleteCompleted: TToolButton Left = 158 @@ -262,6 +263,7 @@ object MainForm: TMainForm Caption = 'Delete all completed tasks' ImageIndex = 9 OnClick = tbDownloadDeleteCompletedClick + Visible = False end end end @@ -4444,6 +4446,7 @@ object MainForm: TMainForm Align = alClient AutoExpand = True DefaultItemHeight = 18 + ExpandSignSize = 16 Images = IconList ReadOnly = True TabOrder = 0 @@ -4475,14 +4478,14 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - left = 80 - top = 408 + Left = 80 + Top = 408 end object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - left = 592 - top = 184 + Left = 592 + Top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -4812,8 +4815,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - left = 592 - top = 224 + Left = 592 + Top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -4856,8 +4859,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - left = 520 - top = 212 + Left = 520 + Top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -5167,8 +5170,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - left = 128 - top = 272 + Left = 128 + Top = 272 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5314,13 +5317,13 @@ object MainForm: TMainForm PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - left = 288 - top = 432 + Left = 288 + Top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False - left = 128 - top = 144 + Left = 128 + Top = 144 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5342,8 +5345,8 @@ object MainForm: TMainForm end end object IconList: TImageList - left = 24 - top = 136 + Left = 24 + Top = 136 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6085,8 +6088,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - left = 24 - top = 184 + Left = 24 + Top = 184 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6382,8 +6385,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - left = 27 - top = 268 + Left = 27 + Top = 268 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6677,8 +6680,8 @@ object MainForm: TMainForm } end object IconSmall: TImageList - left = 27 - top = 328 + Left = 27 + Top = 328 Bitmap = { 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6781,8 +6784,8 @@ object MainForm: TMainForm end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup - left = 592 - top = 136 + Left = 592 + Top = 136 object medURLUndo: TMenuItem Caption = 'Undo' OnClick = medURLUndoClick @@ -6821,38 +6824,38 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - left = 80 - top = 448 + Left = 80 + Top = 448 end object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - left = 240 - top = 184 + Left = 240 + Top = 184 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - left = 504 - top = 120 + Left = 504 + Top = 120 end object TransferRateToolset: TChartToolset - left = 464 - top = 120 + Left = 464 + Top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - left = 152 - top = 376 + Left = 152 + Top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick end end object pmFilterGenreAll: TPopupMenu - left = 520 - top = 168 + Left = 520 + Top = 168 object mnFilterGenreAllCheck: TMenuItem Caption = 'Check all' OnClick = mnFilterGenreAllCheckClick @@ -6868,8 +6871,8 @@ object MainForm: TMainForm end object pmTray: TPopupMenu OnPopup = pmTrayPopup - left = 341 - top = 432 + Left = 341 + Top = 432 object miTrayResumeAll: TMenuItem Caption = 'Resume all' OnClick = tbDownloadResumeAllClick @@ -6933,28 +6936,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - left = 336 - top = 128 + Left = 336 + Top = 128 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - left = 240 - top = 256 + Left = 240 + Top = 256 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - left = 336 - top = 184 + Left = 336 + Top = 184 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - left = 376 - top = 256 + Left = 376 + Top = 256 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index b5d492e99..27fcfc56d 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -1,5 +1,4 @@ {"version":1,"strings":[ -{"hash":57972706,"name":"tmainform.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Free Manga Downloader"}, {"hash":240327891,"name":"tmainform.tsdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, {"hash":5473489,"name":"tmainform.vtdownload.header.columns[0].text","sourcebytes":[77,97,110,103,97],"value":"Manga"}, {"hash":95062979,"name":"tmainform.vtdownload.header.columns[1].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, @@ -44,13 +43,13 @@ {"hash":84262158,"name":"tmainform.cbuseregexpr.caption","sourcebytes":[82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110],"value":"Regular Expression"}, {"hash":111905342,"name":"tmainform.ckfilteraction.hint","sourcebytes":[65,32,119,111,114,107,32,116,121,112,105,99,97,108,108,121,32,100,101,112,105,99,116,105,110,103,32,102,105,103,104,116,105,110,103,44,32,118,105,111,108,101,110,99,101,44,32,99,104,97,111,115,44,32,97,110,100,32,102,97,115,116,32,112,97,99,101,100,32,109,111,116,105,111,110,46],"value":"A work typically depicting fighting, violence, chaos, and fast paced motion."}, {"hash":75149406,"name":"tmainform.ckfilteraction.caption","sourcebytes":[65,99,116,105,111,110],"value":"Action"}, -{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and\/or graphic sexual content and nudity."}, +{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity."}, {"hash":4701236,"name":"tmainform.ckfilteradult.caption","sourcebytes":[65,100,117,108,116],"value":"Adult"}, {"hash":267284606,"name":"tmainform.ckfilteradventure.hint","sourcebytes":[73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,111,114,121,32,103,111,101,115,32,111,110,32,97,32,116,114,105,112,32,111,114,32,97,108,111,110,103,32,116,104,97,116,32,108,105,110,101,44,32,121,111,117,114,32,98,101,115,116,32,98,101,116,32,105,115,32,116,104,97,116,32,105,116,32,105,115,32,97,110,32,97,100,118,101,110,116,117,114,101,32,109,97,110,103,97,46,32,79,116,104,101,114,119,105,115,101,44,32,105,116,39,115,32,117,112,32,116,111,32,121,111,117,114,32,112,101,114,115,111,110,97,108,32,112,114,101,106,117,100,105,99,101,32,111,110,32,116,104,105,115,32,99,97,115,101,46],"value":"If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case."}, {"hash":214301493,"name":"tmainform.ckfilteradventure.caption","sourcebytes":[65,100,118,101,110,116,117,114,101],"value":"Adventure"}, {"hash":11846766,"name":"tmainform.ckfiltercomedy.hint","sourcebytes":[65,32,100,114,97,109,97,116,105,99,32,119,111,114,107,32,116,104,97,116,32,105,115,32,108,105,103,104,116,32,97,110,100,32,111,102,116,101,110,32,104,117,109,111,114,111,117,115,32,111,114,32,115,97,116,105,114,105,99,97,108,32,105,110,32,116,111,110,101,32,97,110,100,32,116,104,97,116,32,117,115,117,97,108,108,121,32,99,111,110,116,97,105,110,115,32,97,32,104,97,112,112,121,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,104,101,109,97,116,105,99,32,99,111,110,102,108,105,99,116,46],"value":"A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict."}, {"hash":78003129,"name":"tmainform.ckfiltercomedy.caption","sourcebytes":[67,111,109,101,100,121],"value":"Comedy"}, -{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga\/anime."}, +{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga/anime."}, {"hash":202379913,"name":"tmainform.ckfilterdoujinshi.caption","sourcebytes":[68,111,117,106,105,110,115,104,105],"value":"Doujinshi"}, {"hash":221112350,"name":"tmainform.ckfilterdrama.hint","sourcebytes":[65,32,119,111,114,107,32,109,101,97,110,116,32,116,111,32,98,114,105,110,103,32,111,110,32,97,110,32,101,109,111,116,105,111,110,97,108,32,114,101,115,112,111,110,115,101,44,32,115,117,99,104,32,97,115,32,105,110,115,116,105,108,108,105,110,103,32,115,97,100,110,101,115,115,32,111,114,32,116,101,110,115,105,111,110,46],"value":"A work meant to bring on an emotional response, such as instilling sadness or tension."}, {"hash":4950065,"name":"tmainform.ckfilterdrama.caption","sourcebytes":[68,114,97,109,97],"value":"Drama"}, @@ -74,7 +73,7 @@ {"hash":56818190,"name":"tmainform.ckfilterlolicon.caption","sourcebytes":[76,111,108,105,99,111,110],"value":"Lolicon"}, {"hash":104001182,"name":"tmainform.ckfiltermartialarts.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,109,97,114,116,105,97,108,32,97,114,116,115,32,114,101,108,97,116,101,100,46,32,65,110,121,32,111,102,32,115,101,118,101,114,97,108,32,97,114,116,115,32,111,102,32,99,111,109,98,97,116,32,111,114,32,115,101,108,102,45,100,101,102,101,110,115,101,44,32,115,117,99,104,32,97,115,32,97,105,107,105,100,111,44,32,107,97,114,97,116,101,44,32,106,117,100,111,44,32,111,114,32,116,97,101,107,119,111,110,100,111,44,32,107,101,110,100,111,44,32,102,101,110,99,105,110,103,44,32,97,110,100,32,115,111,32,111,110,32,97,110,100,32,115,111,32,102,111,114,116,104,46],"value":"As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth."}, {"hash":47977283,"name":"tmainform.ckfiltermartialarts.caption","sourcebytes":[77,97,114,116,105,97,108,32,65,114,116,115],"value":"Martial Arts"}, -{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and\/or strong language."}, +{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language."}, {"hash":87604357,"name":"tmainform.ckfiltermature.caption","sourcebytes":[77,97,116,117,114,101],"value":"Mature"}, {"hash":187133582,"name":"tmainform.ckfiltermecha.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,118,111,108,118,105,110,103,32,97,110,100,32,117,115,117,97,108,108,121,32,99,111,110,99,101,110,116,114,97,116,105,110,103,32,111,110,32,97,108,108,32,116,121,112,101,115,32,111,102,32,108,97,114,103,101,32,114,111,98,111,116,105,99,32,109,97,99,104,105,110,101,115,46],"value":"A work involving and usually concentrating on all types of large robotic machines."}, {"hash":5487073,"name":"tmainform.ckfiltermecha.caption","sourcebytes":[77,101,99,104,97],"value":"Mecha"}, @@ -98,11 +97,11 @@ {"hash":94333967,"name":"tmainform.ckfiltershoujo.caption","sourcebytes":[83,104,111,117,106,111],"value":"Shoujo"}, {"hash":171132846,"name":"tmainform.ckfiltershoujoai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,117,114,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,71,105,114,108,39,39,115,32,76,111,118,101,34,44,32,115,111,32,116,111,32,115,112,101,97,107,46],"value":"Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak."}, {"hash":113331593,"name":"tmainform.ckfiltershoujoai.caption","sourcebytes":[83,104,111,117,106,111,32,65,105],"value":"Shoujo Ai"}, -{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and\/or violence."}, +{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and/or violence."}, {"hash":167167214,"name":"tmainform.ckfiltershounen.caption","sourcebytes":[83,104,111,117,110,101,110],"value":"Shounen"}, {"hash":19597467,"name":"tmainform.ckfiltershounenai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,97,111,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,66,111,121,39,39,115,32,76,111,118,101,34,194,157,44,32,115,111,32,116,111,32,115,112,101,97,107],"value":"Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\"\u009D, so to speak"}, {"hash":206543641,"name":"tmainform.ckfiltershounenai.caption","sourcebytes":[83,104,111,117,110,101,110,32,65,105],"value":"Shounen Ai"}, -{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one\/many character(s). These challenges\/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, +{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, {"hash":262977669,"name":"tmainform.ckfiltersliceoflife.caption","sourcebytes":[83,108,105,99,101,32,111,102,32,76,105,102,101],"value":"Slice of Life"}, {"hash":68245006,"name":"tmainform.ckfiltersmut.hint","sourcebytes":[68,101,97,108,115,32,119,105,116,104,32,115,101,114,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,112,114,111,102,97,110,101,32,111,114,32,111,102,102,101,110,115,105,118,101,44,32,112,97,114,116,105,99,117,108,97,114,108,121,32,119,105,116,104,32,114,101,103,97,114,100,115,32,116,111,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,46],"value":"Deals with series that are considered profane or offensive, particularly with regards to sexual content."}, {"hash":369860,"name":"tmainform.ckfiltersmut.caption","sourcebytes":[83,109,117,116],"value":"Smut"}, @@ -156,7 +155,7 @@ {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, {"hash":325284,"name":"tmainform.lboptionhost.caption","sourcebytes":[72,111,115,116],"value":"Host"}, -{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host\/IP"}, +{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host/IP"}, {"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, {"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, @@ -211,7 +210,7 @@ {"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, {"hash":263412434,"name":"tmainform.gbdialogs.caption","sourcebytes":[83,104,111,119,32,100,105,97,108,111,103,32,99,111,110,102,105,114,109,97,116,105,111,110,32,102,111,114],"value":"Show dialog confirmation for"}, {"hash":252071892,"name":"tmainform.cboptionshowquitdialog.caption","sourcebytes":[69,120,105,116,32,70,77,68],"value":"Exit FMD"}, -{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task\/favorite"}, +{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task/favorite"}, {"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, {"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, {"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 5933f6e7e..2ea0e2606 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -567,10 +567,6 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" -#: tmainform.caption -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" @@ -2175,3 +2171,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 9e63d579f..9520dbcf4 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -558,10 +558,6 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" -#: tmainform.caption -msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" @@ -2155,3 +2151,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index a01e2c80a..8bece7e44 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -523,10 +523,6 @@ msgstr "" msgid "Visit my blog" msgstr "" -#: tmainform.caption -msgid "Free Manga Downloader" -msgstr "" - #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" From e7f9873a3e005fd1774ae0a2a8bea94fd61a9b65 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 21 Jan 2017 18:41:24 +0800 Subject: [PATCH 1504/2794] bump version 0.9.88.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 90a6a1918..efe8def87 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.88.0 (21-01-2017) +[+] Added GoodManga[EN] +Full changes: https://github.com/riderkick/FMD/compare/0.9.87.0...0.9.88.0 + 0.9.87.0 (12-01-2017) [*] MangaTraders: fixed manga list [*] Japscan: rewrite all codes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 44725a99e..27712bb50 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="87"/> + <RevisionNr Value="88"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 2099adb57..976fb9577 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.87.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.87.0/fmd_0.9.87.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.87.0/fmd_0.9.87.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.87.0/fmd_0.9.87.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.87.0/fmd_0.9.87.0_Win64.7z +VERSION=0.9.88.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.88.0/fmd_0.9.88.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.88.0/fmd_0.9.88.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.88.0/fmd_0.9.88.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.88.0/fmd_0.9.88.0_Win64.7z From 53bc79897b5400379fae1dcdcd9c2a4d091647c4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 29 Jan 2017 22:37:11 +0800 Subject: [PATCH 1505/2794] fixed e-hentai root url --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 2f57157ad..e5abb97a1 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -430,7 +430,7 @@ procedure RegisterModule; end; begin - with AddWebsiteModule('E-Hentai', 'http://g.e-hentai.org') do + with AddWebsiteModule('E-Hentai', 'https://e-hentai.org') do AddOptionComboBox(@settingsimagesize, 'SettingsImageSize', @RS_SettingsImageSize, @RS_SettingsImageSizeItems); with AddWebsiteModule('ExHentai', 'http://exhentai.org') do begin AccountSupport := True; From 7568dc714dc72f6942d81ce0ff5e7cfb06c697c3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 30 Jan 2017 22:04:23 +0800 Subject: [PATCH 1506/2794] make delete/merge completed task always available #469 --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0abfb62e4..4ff2a3aeb 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,6 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 88b4aeea0..25f797d64 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3231,7 +3231,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); var iStop, iResume, - iFinish, + //iFinish, iEnable, iDisable: Boolean; @@ -3241,7 +3241,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); begin iStop := False; iResume := False; - iFinish := False; + //iFinish := False; iEnable := False; iDisable := False; Node := vtDownload.GetFirstSelected(); @@ -3258,7 +3258,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM : if not iResume then iResume := True; - STATUS_FINISH : if not iFinish then iFinish := True; + //STATUS_FINISH : if not iFinish then iFinish := True; end; end else if not iEnable then @@ -3270,6 +3270,8 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); end; begin + miDownloadDeleteCompleted.Enabled := True; + miDownloadMergeCompleted.Enabled := True; with DLManager do begin if vtDownload.SelectedCount = 0 then begin @@ -3278,8 +3280,8 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); miDownloadDelete.Enabled := False; miDownloadDeleteTask.Enabled := False; miDownloadDeleteTaskData.Enabled := False; - miDownloadDeleteCompleted.Enabled := False; - miDownloadMergeCompleted.Enabled := False; + //miDownloadDeleteCompleted.Enabled := False; + //miDownloadMergeCompleted.Enabled := False; miDownloadViewMangaInfo.Enabled := False; miDownloadOpenFolder.Enabled := False; miDownloadOpenWith.Enabled := False; @@ -3294,8 +3296,8 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); miDownloadDelete.Enabled := True; miDownloadDeleteTask.Enabled := True; miDownloadDeleteTaskData.Enabled := True; - miDownloadDeleteCompleted.Enabled := iFinish; - miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; + //miDownloadDeleteCompleted.Enabled := iFinish; + //miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; miDownloadOpenWith.Enabled := vtDownload.SelectedCount = 1; miDownloadOpenFolder.Enabled := miDownloadOpenWith.Enabled; miDownloadViewMangaInfo.Enabled := miDownloadOpenFolder.Enabled and From 201e089efa3ee60fe7f0843f854ddec998541d5e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Feb 2017 13:44:44 +0800 Subject: [PATCH 1507/2794] cleanup --- mangadownloader/forms/frmMain.pas | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 25f797d64..ac9e6da78 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3231,7 +3231,6 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); var iStop, iResume, - //iFinish, iEnable, iDisable: Boolean; @@ -3241,7 +3240,6 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); begin iStop := False; iResume := False; - //iFinish := False; iEnable := False; iDisable := False; Node := vtDownload.GetFirstSelected(); @@ -3258,7 +3256,6 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); STATUS_STOP, STATUS_FAILED, STATUS_PROBLEM : if not iResume then iResume := True; - //STATUS_FINISH : if not iFinish then iFinish := True; end; end else if not iEnable then @@ -3280,8 +3277,6 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); miDownloadDelete.Enabled := False; miDownloadDeleteTask.Enabled := False; miDownloadDeleteTaskData.Enabled := False; - //miDownloadDeleteCompleted.Enabled := False; - //miDownloadMergeCompleted.Enabled := False; miDownloadViewMangaInfo.Enabled := False; miDownloadOpenFolder.Enabled := False; miDownloadOpenWith.Enabled := False; @@ -3296,8 +3291,6 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); miDownloadDelete.Enabled := True; miDownloadDeleteTask.Enabled := True; miDownloadDeleteTaskData.Enabled := True; - //miDownloadDeleteCompleted.Enabled := iFinish; - //miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; miDownloadOpenWith.Enabled := vtDownload.SelectedCount = 1; miDownloadOpenFolder.Enabled := miDownloadOpenWith.Enabled; miDownloadViewMangaInfo.Enabled := miDownloadOpenFolder.Enabled and From 7c5a0c786dc570ede58b8b3ed054cb043f1331db Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Feb 2017 14:02:09 +0800 Subject: [PATCH 1508/2794] split mangaeden_it, perveden_it. closed #475 --- baseunits/modules/MangaEden.pas | 36 +++++++++++++++++++++++---------- config/mangalist.ini | 6 +++--- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index aa5fd9db1..c6ffa16dd 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -11,18 +11,26 @@ interface implementation const - dirurls: array[0..1] of String = ( - '/en/en-directory/', - '/en/it-directory/' - ); + diren = '/en/en-directory/'; + dirit = '/en/it-directory/'; +var + MMangaEden, MMangaEdenIT, + MPervEden, MPervEdenIT: TModuleContainer; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; +var + s: String; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then begin + s := Module.RootURL; + if (Module = MMangaEden) or (Module = MPervEden) then + s += diren + else + s += dirit; + if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -41,7 +49,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex]; + s := Module.RootURL; + if (Module = MMangaEden) or (Module = MPervEden) then + s += diren + else + s += dirit; if AURL <> '0' then s := s + '?page=' + IncStr(AURL); if MangaInfo.FHTTP.GET(s) then begin @@ -179,12 +191,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; procedure RegisterModule; - procedure AddWebsiteModule(const AWebsite, ARootURL: String); + function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; begin - with AddModule do begin + Result := AddModule; + with Result do begin Website := AWebsite; RootURL := ARootURL; - TotalDirectory := Length(dirurls); OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; @@ -194,8 +206,10 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaEden', 'http://www.mangaeden.com'); - AddWebsiteModule('PervEden', 'http://www.perveden.com'); + MMangaEden := AddWebsiteModule('MangaEden', 'http://www.mangaeden.com'); + MMangaEdenIT := AddWebsiteModule('MangaEden_IT', 'http://www.mangaeden.com'); + MPervEden := AddWebsiteModule('PervEden', 'http://www.perveden.com'); + MPervEdenIT := AddWebsiteModule('PervEden_IT', 'http://www.perveden.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index cbbdeb7ee..9d3dd413a 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,8 +4,8 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics -English-Italian=MangaEden,NineManga_IT +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics +Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE @@ -20,4 +20,4 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D,YaoiChanRU From 600b78e6e7790b5fb28385ad71172c684502910d Mon Sep 17 00:00:00 2001 From: Grzegorz M <grzesja@gmail.com> Date: Sun, 5 Feb 2017 16:37:49 +0100 Subject: [PATCH 1509/2794] Added polish language Polish language --- mangadownloader/languages/fmd.pl_PL.po | 2175 ++++++++++++++++++++++++ 1 file changed, 2175 insertions(+) create mode 100644 mangadownloader/languages/fmd.pl_PL.po diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po new file mode 100644 index 000000000..59bdd837f --- /dev/null +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -0,0 +1,2175 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl_PL\n" +"X-Generator: Poedit 1.7.4\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Pokaż wszystkie języki" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Pokaż grupę skanlacja" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Pobierz oryginalny obraz (wymaga konta ExHentai)" + +#: ehentai.rs_settingsimagesize +#| msgid "Image size" +msgid "Image size:" +msgstr "Rozmiar obrazka:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Orginał\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Czy na pewno chcesz usunąć to konto?" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Sprawdzanie" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "Niepoprawnie" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Nieznane" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "OK" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Nazwa użytkownika lub hasło nie może być puste!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "Importowanie zakończone." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "Lista niezaimportowanych mang" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Wszystkie pobrania" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&OK" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "Anuluj" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Sprawdzanie..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "Nie można się połączyć z serwerem." + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "Nie można uzyskać informacji o mandze. Proszę sprawdzić swoje połączenie z internetem i spróbuj ponownie." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Licznik pobrań" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "Musisz wybrać co najmniej 1 stronę z mangami!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Czy na pewno chcesz wyjść?" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Czy na pewno chcesz usunąć ulubione?" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Czy na pewno chcesz usunąć wszystkie zakończone zadania?" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Czy na pewno chcesz usunąć ten element?" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Czy jesteś pewien, że chcesz usunąć zadanie?" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Rozdzielone pobieranie" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "" +"Ten tytuł znajduje się juz na liście pobierania.\n" +"Czy chcesz go pobrać pomimo tego? \n" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Wpisz nowy rozdział:" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Wpisz nową ścieżkę zapisu:" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Updater jest uruchomiony!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Chcesz pobrać listę mang z serwera?" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "URL nie jest obsługiwany!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "" +"Pobierz wszystko\n" +"Dodaj do ulubionych\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "" +"Zakończone\n" +"W trakcie\n" +"<Nic>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader jest już uruchomiony!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "" +"Jest problem z tymi danymi!\n" +"Usunięcie i ponowne dodanie tych danych może rozwiązać ten problem.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "Historia" + +#: frmmain.rs_import +msgid "Import" +msgstr "Importuj" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Wykonawca:" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Autor:" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Gatunek:" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Status:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Streszczenie:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Tytuł:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Strona www:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "W trakcie" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Automatyczne sprawdzanie nowych rozdziałów co %d minut" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "" +"%s : Ścieżka do mangi\n" +"%s : Nazwa pliku rozdziału\n" +"\n" +"Przykład: \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Ładowanie ..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Tryb: Pokaż wszystko (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Tryb: Filtrowany (%d)" + +#: frmmain.rs_modesearching +#| msgid "Searching..." +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Tryb: Wyszukiwanie ..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "Miesiąc temu" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "Tydzień temu" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "" +"Nic\n" +"Wyjdź\n" +"Wyłącz\n" +"Hibernuj\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Wybrano: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Oprogramowanie" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Ścieżka do programu (np C:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Dzisiaj" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Nieprawidłowe wejście!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Wczoraj" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "FMD wyłączy się za %d sekund." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "System zahibernuje się za %d sekund." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "System wyłączy się za %d sekund." + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Usuń znak wodny" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Zapisz jako PNG" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Dodaj" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Usuń" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Edytuj" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Odśwież" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Strona WWW" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Nazwa użytkownika" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Status" + +#: taccountsetform.btcancel.caption +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Anuluj" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "OK" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Pokaż hasło" + +#: taccountsetform.edpassword.texthint +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Hasło" + +#: taccountsetform.edusername.texthint +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Nazwa użytkownika" + +#: taccountsetform.label1.caption +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Strona WWW" + +#: taccountsetform.label2.caption +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Nazwa użytkownika" + +#: taccountsetform.label3.caption +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Hasło" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Lista podstawowa" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Lista rozdziałów" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Lista ulubionych" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Lista mang" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Dodaj do ulubionych" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "&Zamknij" + +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Pobierz wszystko" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Wyczyść" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Zawsze na wierzchu" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Limit logów" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Kopia" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Anuluj" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&OK" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga Downloader" + +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Ścieżka do programu (np C:\\MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Oprogramowanie:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Przerwij aktualizacje list" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Dodaj do ulubionych" + +#: tmainform.btchecklatestversion.caption +#| msgid "Check for new version" +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Szukaj aktualizacji" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Wyczyść plik logów" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "Pobierz" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Rozdzielone pobieranie" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Sprawdź czy są nowe rozdziały" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Importuj listę" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Filtr" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Przywróć domyślne" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Otwórz Log" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Zastosuj" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Czytaj online" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Usuń filtr" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Usuń filtr" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Aktualizuj listę mang" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Odwiedź mój blog" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "Dodaj do listy pobieranych jako zatrzymane zadanie." + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<Nic>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Szukaj tylko nowych mang" + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Automatyczne pobieranie po sprawdzeniu " + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Automatyczne sprawdzanie nowego rozdziału w przedziale" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Automatycznie usuń ukończone mangi z Ulubionych" + +#: tmainform.cboptionautocheckfavstartup.caption +#| msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" +msgstr "Automatyczne sprawdzanie nowego rozdziału na starcie" + +#: tmainform.cboptionautochecklatestversion.caption +#| msgid "Check for new version " +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Automatyczne sprawdzanie aktualizacji" + +#: tmainform.cboptionchangeunicodecharacter.caption +#| msgid "Change all all character to" +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Replace all unicode character with" +msgstr "Wymień wszystkie znaki Unicode" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Włącz tę opcję, jeśli masz problem z znakami Unicode w ścieżce." + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Rozdział" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Tom" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Włącz ładowanie okładek mang" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Automatyczne generowanie folderu rozdziału" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgid "Auto generate folder based on manga's name" +msgstr "Automatyczne generowanie folderu używając nazwy mangi" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Włącz wyszukiwanie na żywo (wolne w przypadku długiej lisy)" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Zminimalizuj do zasobnika" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "Pozwól na tylko jedną instancje FMD uruchomioną" + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Usuń nazwę mangi z rozdziału" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Usuń zadanie/ulubione" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Pobierz listę mang jeżeli jest pusta" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "Pokaż pasek pobierania" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "Wyjdź z FMD" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "Nie ładuj informacji o mandze podczas aktualizowania listy (filtry nie będą działać!)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "Usuwanie zduplikowane lokalne dane podczas aktualizacji listy mang" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Użyj proxy" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Szukaj we wszystkich witrynach " + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Aby uzyskać więcej stron z mangami, przejdź do Opcje->Strony z mangami" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Wyrażenie regularne" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "Pokaż menu rozwijane" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Włącz zapis logów" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Akcja" + +#: tmainform.ckfilteraction.hint +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Dzieło zazwyczaj przedstawiających walke, przemoc, chaos i szybki ruch." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Dla dorosłych" + +#: tmainform.ckfilteradult.hint +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Zawiera treści, które są przeznaczone wyłącznie dla osób dorosłych. Tytuły w tej kategorii mogą zawierać długotrwałych intensywne sceny przemocy i/lub treści seksualne i nagość." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Przygoda" + +#: tmainform.ckfilteradventure.hint +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Jeśli postać idzie na wycieczkę lub coś w tym stylu, to zapewnie jest to manga przygodowa. W przeciwnym razie, to jest do osobistego uznania." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Komedia" + +#: tmainform.ckfiltercomedy.hint +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Dramatyczne dzieło, które jest lekkie, często humorystyczne, satyryczne w tonie i że zazwyczaj kończą się szczęśliwym sposobem rozwiązania konfliktu tematycznego." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Doujinshi" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Fanowska manga oparta/inspirowana na innej oficjalnej mandze/anime." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Drama" + +#: tmainform.ckfilterdrama.hint +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Dzieło ma na celu doprowadzić do reakcji emocjonalnej, takie jak smutek lub napięcie." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Ecchi" + +#: tmainform.ckfilterechi.hint +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Prawdopodobnie linia między hentai i non-hentai, ecchi zazwyczaj odnosi się do Fanserwisu aby przyciągnąć pewną grupę fanów." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Fantasy" + +#: tmainform.ckfilterfantasy.hint +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Wszystko co wiąże się z nie nieograniczonym światem magii, marzeń i bajek." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Tanswestytyzm" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "" +"Dziewczyny ubieranie się jak faceci, faceci ubieranie się jak dziewczyny.\n" +"Faceci zmieniający się w dziewczyny, dziewczyny zmienia się w facetów.\n" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Harem" + +#: tmainform.ckfilterharem.hint +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "Cykl obejmujący jedną męską postać i wiele kobiet(zwykle przyciągnięte do faceta). Odwrotny Harem jest wtedy gdy płcie są odwrócone." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Hentai ( ͡° ͜ʖ ͡°)" + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "Historyczne" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Mające odczynienia z dawanymi czasami lub starożytnością." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Horror" + +#: tmainform.ckfilterhorror.hint +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Ból, strach, płacz i zgrzytanie zębów; uczucie inspirowane przez coś strasznego i szokującego." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Josei" + +#: tmainform.ckfilterjosei.hint +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Dosłownie \"Kobieta\";. Głównie kobiety w wielku 18-30. Kobiecy odpowiednik seinen. W przeciwieństwie Shoujo romans jest bardziej realistyczny i mniej wyidealizowany. Historia jest bardziej wyraźna i dojrzała." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Lolicon" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Reprezentowanie pociągu seksualnego do młodych i młodocianych dziewcząt. (ps. Jest to nielegalne w Polsce)" + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Sztuki walk" + +#: tmainform.ckfiltermartialarts.hint +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "Jak sama nazwa wskazuje, wszystko co związane ze sztukami walk. Różne typy sztuk walk i samoobrony, takich jak aikido, karate, judo, taekwondo, czy kendo, szermierka, i tak dalej i tak dalej." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Dojrzałe" + +#: tmainform.ckfiltermature.hint +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "Zawiera temat który może być zbyt ekstremalny dla osób w wieku poniżej 17 roku życia. Tytuły w tej kategorii mogą zawierać przemoc, krew i gore, treści seksualnych i/lub wulgaryzmy." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Mecha" + +#: tmainform.ckfiltermecha.hint +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Dzieło głównie skoncentrowane na dużych robotycznych maszynach." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Tajemnica" + +#: tmainform.ckfiltermystery.hint +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Zwykle niewyjaśnione zdarzenie, a główny bohater próbuje dowiedzieć się co go spowodowało." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Psychologiczne" + +#: tmainform.ckfilterpsychological.hint +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Zazwyczaj zajmuje się filozofią stan umysłu, w większości przypadków z wyszczególnieniem pschologii niekonwencjonalnej." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Romans" + +#: tmainform.ckfilterromance.hint +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Każda historia powiązana z miłością. Tutaj zdefiniowana jako miłość między mężczyzną i kobietą. Poza tym, zależy to od twojego własnego wyobrażenia, czym jest miłość." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "Szkolne" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "Główne zdążenia dziejące się w szkole." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Sci-Fi" + +#: tmainform.ckfilterscifi.hint +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Skrót od science fiction, prace te obejmują przekręty na technologii i innych zjawiskach związanych z nauką, które są sprzeczne lub naciągnięte względem współczesnego naukowego świata" + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Seinen" + +#: tmainform.ckfilterseinen.hint +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "Seinen oznacza 'Młodego mężczyznę'. Grupą docelową mangi i anime tego gatunku są młodzi dorośli mężczyźni w wieku od 18 do 25 lat. Historia w Seinen odnosi się do studentów uniwersytetów i ich pracy. zazwyczaj historia opiera się na problemach dorosłego życia." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Shotacon" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "Reprezentuje pociąg seksualny do młodych i nieletnich chłopców." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Shoujo" + +#: tmainform.ckfiltershoujo.hint +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Dzieło przeznaczone przede wszystkim dla kobiet. Zwykle wiąże się z romantyzmem i silnym rozwojem postaci." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Shoujo Ai" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "Cęsto równoznaczny z yuri, może być uznane jako coś mniej ekstremalnego. \"Dziewczęca miłość\", że tak powiem." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Shounen" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Dzieło przeznaczone przede wszystkim dla mężczyzn. Dzieła te obejmują zazwyczaj walki i/lub przemoc." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Shounen Ai" + +#: tmainform.ckfiltershounenai.hint +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "Cęsto równoznaczny z yaoi, może być uznane jako coś mniej ekstremalnego. \"Chłopięca miłość\", że tak powiem." + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Okruchy życia" + +#: tmainform.ckfiltersliceoflife.hint +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "Jak sama nazwa wskazuje, ten gatunek reprezentuje codzienne zmagania jednej lub wielu postaci. Te wyzwania/wydarzenia mogłyby zdarzyć w realnym życiu, i często -jeśli nie zawsze- dzieją się w świecie przypominającym nasz własny." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Sprośne" + +#: tmainform.ckfiltersmut.hint +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Obejmuje zdarzenia, które są uważane za bluźniercze lub obraźliwe, zwłaszcza w odniesieniu do treści o charakterze seksualnym." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Sportowe" + +#: tmainform.ckfiltersports.hint +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "Jak sama nazwa wskazuje, cokolwiek związane ze sportem. Baseball, koszykówka, hokej, piłka nożna, golf, wyścigi itd." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Supernatural" + +#: tmainform.ckfiltersupernatural.hint +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Wiąże się ze zdumiewającymi i niewyjaśnionymi mocami lub zdarzeniami, które przeczą prawom fizyki." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Tragedia" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Zawiera zdarzenia powodujące wielkie straty i nieszczęścia." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Yaoi" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Dzieło to obejmuje zazwyczaj intymne relacje między mężczyznami." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Yuri" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Dzieło to obejmuje zazwyczaj intymne relacje między kobietami." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Lista gatunków oddzielone przecinkami" + +#: tmainform.eddownloadssearch.texthint +#| msgid "Search favorites..." +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Wyszukiwanie plików do pobrania ..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Wyszukiwanie ulubionych ..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Wykonawca" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Autor" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Filtr" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Część streszczenia" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Tytuł" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Szukaj tytułu ..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgid "Custom rename" +msgstr "Zmień nazwę" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Domyślna ścieżka pobierania" + +#: tmainform.edoptionexternalparams.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalparams.texthint" +msgid "External program parameters" +msgstr "Parametry programu zewnętrznego " + +#: tmainform.edoptionexternalpath.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalpath.texthint" +msgid "External program path" +msgstr "ścieżka programu zewnętrznego" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Zmień nazwę" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr "Proxy host/IP" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Zmień nazwę" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "hasło proxy" + +#: tmainform.edoptionport.texthint +msgid "Proxy Port" +msgstr "Port proxy" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "nazwa użytkownika Proxy" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Zapisz w" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "Adres URL" + +#: tmainform.edwebsitessearch.texthint +#| msgid "Search..." +msgctxt "tmainform.edwebsitessearch.texthint" +msgid "Search website..." +msgstr "Szukaj www ..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Pokaż potwierdzenie dialogowe" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "Pole rozwijane" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Program zewnętrzny" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Ulubione" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Konfiguracja Proxy" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Zmiana nazwy …" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Wybierz domyślną ścieżkę pobierania:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Przezroczystość" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Artysta" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Autor" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Niestandardowe Gatunki" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "" +"Gatunki: \n" +"- zaznaczone. Włączenie tego gatunku \n" +"- Niezaznaczony: Wyłącz ten gatunek \n" +"- nieaktywny. Nieważne \n" +" \n" +" NiestandardoweGatunki:. \n" +"- oddziel wiele gatunków poprzez ',' \n" +"Wyklucz gatunek poprzez '!' lub "-" na początku gatunek \n" +"- Przykład:.!. Przygoda, Ecchi, Komedia \n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Status" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Streszczenie" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Tytuł" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Plik logów:" + +#: tmainform.lbmode.caption +#| msgid "Mode: Show All (0)" +msgid "Mode: Show all (0)" +msgstr "Tryb: Pokaż wszystko (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgid "Auto check for new chapter every %d minutes" +msgstr "Automatyczna sprawdzenie nowego rozdziału raz na %d minut" + +#: tmainform.lboptionchaptercustomrename.caption +#| msgid "Chapter folder name:" +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Nazwa Rozdziału:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Nazwa strony \n" +"%MANGA% : Tytuł mangi \n" +"%CHAPTER% : Tytuł rozdziału\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artysta\n" +"%NUMBERING% : Numeracja\n" +"\n" +"Notka:\n" +"Nazwa folderu z rozdziałami musi mieć co najmniej %CHAPTER% lub %NUMBERING%.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Limit czasu połączenia (sekundy)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Otwórz mangę za pomocą zewnętrznego programu:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Parametry:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "tmainform.lboptionexternalparamshint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Nazwa pliku:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nazwa strony\n" +"%MANGA% : Tytuł mangi\n" +"%CHAPTER% : Tytuł rozdziału\n" +"%FILENAME% : Nazwa pliku\n" +"\n" +"Notka:\n" +"Nazwa pliku musi mieć co najmniej %FILENAME%\n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Host" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Język:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "Po ukończeniu pobierania:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Nazwa folderu z Mangą:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nazwa strony\n" +"%MANGA% : Tytuł mangi\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artysta\n" +"\n" +"Notka:\n" +"Nazwa folderu z mangą musi mieć przynajmniej %MANGA%.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Ilość pobierań w tym samym czasie (max: 8)" + +#: tmainform.lboptionmaxretry.caption +#| msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Ilość prób pobierania po nieudanym pobraniu (-1 = zawsze próbuj)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Liczba pobieranych plików na zadanie w tym samym czasie (Max: 32)" + +# WTF does that mean? +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "New manga based on it's update time (days)" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Hasło" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "Poziom kompresji PDF" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (bezstratny), niżej = DCTEncode (stratny)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Port" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Typ" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Zmiana nazwy cyfry" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Nazwa użytkownika" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Zapisz do:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Usuń" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Kopia" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Wytnij" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Wklej" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Wklej i przejdź" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Zaznacz wszystko" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Cofnij" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Anuluj" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Zaznacz wszystkie" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Zaznacz wybrane" + +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Filtr" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "Ukryj pobrane rozdziały" + +#: tmainform.michapterlisthighlight.caption +#| msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" +msgstr "Podświetl pobrane rozdziały" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Odznacz wszystkie" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Odznacz wybrane" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Usuń" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Usuń wszystkie zadania wykonane" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Tylko zadania" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Zadania + Data" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Zadania + Data + Ulubione" + +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "Wyłącz" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "Włącz" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Scal wykonane zadania" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Otwórz folder" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Otwórz ..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Wznów" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Stop" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Zobacz informacje o mandze" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Zmień \"obecny rozdział\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Zmień \"Zapisz do\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Sprawdź czy są nowe rozdziały" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Usuń" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Pobierz wszystko" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Otwórz folder" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Otwórz... " + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Zatrzymaj sprawdzanie nowych rozdziałów" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Zobacz informacje o mandze" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Podświetl nową mangę" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Dodaj do ulubionych" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Usuń" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Pobierz wszystko" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Zobacz informacje o mandze" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "Po pobieraniu zakończ" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Wyjdź" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Wyjdź" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Hibernacja" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Nic" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Wyłacz komputer" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Przywróć" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Wznów wszystkie" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Pokaż menu rozwijane" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Zatrzymaj wszystko" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Pobierz wszystkie listy z serwera na raz" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Zaznacz wszystko" + +# I dont understand that either... +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Indeterminate all" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Odznacz wszystko" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Aktualizacja wszystkich list na raz" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Pobierz listę manga z serwera " + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Aktualizacja listy manga" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Miej wszystkie gatunki zaznaczone" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Miej jeden gatunek zaznaczony " + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Tryb" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "Zapisz pobrane rozdziały jako " + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (bezstratne), niżej = DCTEncode (stratne)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Usuń wszystkie wykonane zadania " + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Wznów wszystkie" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Zatrzymaj wszystkie" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Zwiń wszystkie" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Rozwiń wszystkie" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "O programie" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "O FMD" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Konta" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Lista zmian" + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Połaczenia" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Kolor niestandardowe" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "Okna dialogowe" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr "Pobrane" + +#: tmainform.tsdownloadfilter.caption +msgid ">>" +msgstr ">>" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Ulubione" + +#: tmainform.tsfilter.caption +msgctxt "tmainform.tsfilter.caption" +msgid "Filter" +msgstr "Filtr" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "Główne" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Informacje o mandze" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Log" + +#: tmainform.tsmangalist.caption +msgid "Manga List" +msgstr "Lista Mang" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Różne" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Opcje" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Zapisz do" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Aktualizacje" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Wygląd" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Zaawansowane" + +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Opcje" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Strony internetowe" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" +msgid "Websites" +msgstr "Strony internetowe" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Manga" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Status" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "Postęp" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Prędkość transferu" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Strona WWW" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Zapisz do" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Dodano" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Tytuł" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Obecny rozdział" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Strona WWW" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Zapisz do" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "&Anuluj" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "&Pobieranie" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "&Dodaj do kolejki" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "&O" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "&Teraz" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "&później" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "&Aktualizacja" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "" +"Nowa wersja znaleziona! Czy chcesz zaktualizować teraz? \n" +"FMD zostanie zamknięty, aby zakończyć aktualizację. \n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Dodaj" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Edytuj" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Usuń" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Pliki cookie" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "numer strony katalogu" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Pobrane" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Max wątków na zadania" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Liczba wątków" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Aktualizuj Listę" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Strona WWW" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Pliki cookie" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Strona WWW" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Wartość" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Strona WWW" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Wartość" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Strona WWW" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Wartość" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Strona WWW" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Wybierz stronę internetową" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Kompresja danych..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Wyłączone" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "Pobieranie" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Niepowodzenie" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Nie udało się utworzyć folderu" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Nie powiodło się, spróbuj wznowić zadanie!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Ukończono" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Przygotowanie" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Zatrzymano" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Oczekiwanie..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "&Dodaj do kolejki" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "&Anuluj" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Sprawdź nowy rozdział" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "&Pobrane" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "&Usuń" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "Znaleziono %d zakończonych mang" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "Sprawdzanie ulubionych jest uruchomione!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d mang ma nowe rozdziały" + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "%s <%s> ma %d nowych rozdziałów." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "Zakończone mangi zostaną usunięte:" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "Znaleziono %d nowych rozdziałów w %d mang:" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Ładownanie: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Sprawdź czy jest nowa wersja" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "Zainstalowana wersja" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Najnowsza wersja" + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Znaleziono nową wersje" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "%s ma %d nowych mang" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Zdobądź folder" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Zdobądź informacje" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Zdobądź listę dla" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Indeksowanie nowych tytułów" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Szukanie nowych tytułów" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Szukanie nowych tytułów w innych folderach" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Przygotowywanie" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Usuwanie duplikatów z aktualnych danych" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Usuwanie duplikatów z lokalnych danych" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Usuwanie duplikatów z nowych tytułów" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Zapisywanie danych" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Synchronizacja danych" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Aktualizacja listy" From 038c9746676c8def089b9f666cbc4f4f4c477daf Mon Sep 17 00:00:00 2001 From: Grzegorz M <grzesja@gmail.com> Date: Sun, 5 Feb 2017 16:38:28 +0100 Subject: [PATCH 1510/2794] Add polish language Polish language --- updater/languages/updater.pl_PL.po | 105 +++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 updater/languages/updater.pl_PL.po diff --git a/updater/languages/updater.pl_PL.po b/updater/languages/updater.pl_PL.po new file mode 100644 index 000000000..febb2a8da --- /dev/null +++ b/updater/languages/updater.pl_PL.po @@ -0,0 +1,105 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl_PL\n" +"X-Generator: Poedit 1.7.4\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Rozmiar pliku" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Oczekiwanie..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Prędkość transferu" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Pomoc" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "Nie można wyodrębnić pliku, ponieważ 7za.exe nie znaleziono!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "Wystąpił błąd podczas próby pobrania pliku." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "Pobieranie [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Błąd zapisu pliku, sprawdź AntiVirus!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Niepowodzenie pobierania pliku!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Błąd ładowania strony!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Nie znaleziono pliku" + +#: umain.rs_finished +msgid "Finished." +msgstr "Zakończono." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "Nieprawidłowy URL" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Ładowanie strony ..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Przekierowany ..." + +#: umain.rs_response +msgid "Response" +msgstr "Odpowiedź" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "Ponów pobieranie [%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Ponowna próba załadowania strony [%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Zapisywanie pliku..." + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Serwer odpowiedział: Error!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(nieznany)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Rozpakowanie pliku [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Oczekiwanie aż główna aplikacja się zamknie..." From f06c6922957195016b29958ef15356f899435481 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Feb 2017 08:39:28 +0800 Subject: [PATCH 1511/2794] added option to open favorites at startup if check favorites checked. closed #478 --- mangadownloader/forms/frmMain.lfm | 64 +++++++++++++++----------- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 15 +++++- mangadownloader/languages/fmd.en.po | 4 ++ mangadownloader/languages/fmd.id_ID.po | 4 ++ mangadownloader/languages/fmd.pl_PL.po | 5 ++ mangadownloader/languages/fmd.po | 4 ++ 7 files changed, 69 insertions(+), 28 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 4ff2a3aeb..f220c9bed 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,6 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 @@ -2580,7 +2579,7 @@ object MainForm: TMainForm Left = 4 Height = 105 Top = 155 - Width = 403 + Width = 402 AutoSize = True Caption = 'Proxy config' ChildSizing.LeftRightSpacing = 4 @@ -2590,7 +2589,7 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 85 - ClientWidth = 399 + ClientWidth = 398 Enabled = False ParentFont = False TabOrder = 1 @@ -2598,13 +2597,13 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 4 - Width = 26 + Width = 25 Caption = 'Host' ParentColor = False ParentFont = False end object edOptionHost: TEdit - Left = 34 + Left = 33 Height = 23 Top = 4 Width = 150 @@ -2619,7 +2618,7 @@ object MainForm: TMainForm object lbOptionUser: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 188 + Left = 187 Height = 23 Top = 4 Width = 53 @@ -2629,7 +2628,7 @@ object MainForm: TMainForm object edOptionUser: TEdit AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 245 + Left = 244 Height = 23 Top = 4 Width = 150 @@ -2645,12 +2644,12 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 31 - Width = 26 + Width = 25 Caption = 'Port' ParentColor = False end object edOptionPort: TEdit - Left = 34 + Left = 33 Height = 23 Top = 31 Width = 150 @@ -2664,7 +2663,7 @@ object MainForm: TMainForm object lbOptionPass: TLabel AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 188 + Left = 187 Height = 23 Top = 31 Width = 53 @@ -2674,7 +2673,7 @@ object MainForm: TMainForm object edOptionPass: TEdit AnchorSideLeft.Side = asrBottom AnchorSideTop.Side = asrBottom - Left = 245 + Left = 244 Height = 23 Top = 31 Width = 150 @@ -2689,12 +2688,12 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 58 - Width = 26 + Width = 25 Caption = 'Type' ParentColor = False end object cbOptionProxyType: TComboBox - Left = 34 + Left = 33 Height = 23 Top = 58 Width = 150 @@ -3301,7 +3300,7 @@ object MainForm: TMainForm end object gbOptionFavorites: TGroupBox Left = 4 - Height = 143 + Height = 166 Top = 31 Width = 523 Align = alTop @@ -3311,7 +3310,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 123 + ClientHeight = 146 ClientWidth = 519 ParentFont = False TabOrder = 1 @@ -3322,8 +3321,9 @@ object MainForm: TMainForm Width = 511 Align = alTop Caption = 'Auto check for new chapter at startup' + OnChange = cbOptionAutoCheckFavStartupChange ParentFont = False - TabOrder = 3 + TabOrder = 0 end object seOptionAutoCheckFavIntervalMinutes: TSpinEdit AnchorSideLeft.Control = cbOptionAutoCheckFavInterval @@ -3331,12 +3331,12 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 23 - Top = 50 + Top = 73 Width = 58 MaxValue = 1440 MinValue = 1 OnChange = seOptionAutoCheckFavIntervalMinutesChange - TabOrder = 0 + TabOrder = 3 Value = 1 end object lbOptionAutoCheckFavIntervalMinutes: TLabel @@ -3346,7 +3346,7 @@ object MainForm: TMainForm AnchorSideTop.Side = asrCenter Left = 66 Height = 15 - Top = 54 + Top = 77 Width = 243 Caption = 'Auto check for new chapter every %d minutes' ParentColor = False @@ -3357,10 +3357,10 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 100 + Top = 123 Width = 298 Caption = 'Automatic remove completed manga from Favorites' - TabOrder = 1 + TabOrder = 5 end object cbOptionAutoCheckFavDownload: TCheckBox AnchorSideLeft.Control = seOptionAutoCheckFavIntervalMinutes @@ -3368,28 +3368,38 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 77 + Top = 100 Width = 242 Caption = 'Automatic download after finish checking' ParentFont = False - TabOrder = 2 + TabOrder = 4 end object cbOptionAutoCheckFavInterval: TCheckBox Left = 4 Height = 19 - Top = 27 + Top = 50 Width = 511 Align = alTop Caption = 'Auto check for new chapter in an interval' OnChange = cbOptionAutoCheckFavIntervalChange ParentFont = False - TabOrder = 4 + TabOrder = 2 + end + object cbOptionAutoOpenFavStartup: TCheckBox + Left = 4 + Height = 19 + Top = 27 + Width = 511 + Align = alTop + Caption = 'Open Favorites at startup' + ParentFont = False + TabOrder = 1 end end object cbOptionUpdateListNoMangaInfo: TCheckBox Left = 4 Height = 19 - Top = 178 + Top = 201 Width = 523 Align = alTop Caption = 'Don''t load manga information when updating list (filter will be not work!)' @@ -3399,7 +3409,7 @@ object MainForm: TMainForm object cbOptionUpdateListRemoveDuplicateLocalData: TCheckBox Left = 4 Height = 19 - Top = 201 + Top = 224 Width = 523 Align = alTop Caption = 'Remove duplicate local data when updating manga list' diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 27fcfc56d..179644a1a 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -205,6 +205,7 @@ {"hash":234489075,"name":"tmainform.cboptionautocheckfavremovecompletedmanga.caption","sourcebytes":[65,117,116,111,109,97,116,105,99,32,114,101,109,111,118,101,32,99,111,109,112,108,101,116,101,100,32,109,97,110,103,97,32,102,114,111,109,32,70,97,118,111,114,105,116,101,115],"value":"Automatic remove completed manga from Favorites"}, {"hash":44744407,"name":"tmainform.cboptionautocheckfavdownload.caption","sourcebytes":[65,117,116,111,109,97,116,105,99,32,100,111,119,110,108,111,97,100,32,97,102,116,101,114,32,102,105,110,105,115,104,32,99,104,101,99,107,105,110,103],"value":"Automatic download after finish checking"}, {"hash":248673660,"name":"tmainform.cboptionautocheckfavinterval.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114,32,105,110,32,97,110,32,105,110,116,101,114,118,97,108],"value":"Auto check for new chapter in an interval"}, +{"hash":138709376,"name":"tmainform.cboptionautoopenfavstartup.caption","sourcebytes":[79,112,101,110,32,70,97,118,111,114,105,116,101,115,32,97,116,32,115,116,97,114,116,117,112],"value":"Open Favorites at startup"}, {"hash":9269721,"name":"tmainform.cboptionupdatelistnomangainfo.caption","sourcebytes":[68,111,110,39,116,32,108,111,97,100,32,109,97,110,103,97,32,105,110,102,111,114,109,97,116,105,111,110,32,119,104,101,110,32,117,112,100,97,116,105,110,103,32,108,105,115,116,32,40,102,105,108,116,101,114,32,119,105,108,108,32,98,101,32,110,111,116,32,119,111,114,107,33,41],"value":"Don't load manga information when updating list (filter will be not work!)"}, {"hash":182501908,"name":"tmainform.cboptionupdatelistremoveduplicatelocaldata.caption","sourcebytes":[82,101,109,111,118,101,32,100,117,112,108,105,99,97,116,101,32,108,111,99,97,108,32,100,97,116,97,32,119,104,101,110,32,117,112,100,97,116,105,110,103,32,109,97,110,103,97,32,108,105,115,116],"value":"Remove duplicate local data when updating manga list"}, {"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ac9e6da78..9665be883 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -51,6 +51,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavInterval: TCheckBox; cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; + cbOptionAutoOpenFavStartup: TCheckBox; cbOptionEnableLoadCover: TCheckBox; cbOptionGenerateChapterFolder: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; @@ -397,6 +398,7 @@ TMainForm = class(TForm) procedure btVisitMyBlogClick(Sender: TObject); procedure cbAddAsStoppedChange(Sender: TObject); procedure cbOptionAutoCheckFavIntervalChange(Sender: TObject); + procedure cbOptionAutoCheckFavStartupChange(Sender: TObject); procedure cbOptionChangeUnicodeCharacterChange(Sender: TObject); procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); @@ -2220,6 +2222,11 @@ procedure TMainForm.cbOptionAutoCheckFavIntervalChange(Sender: TObject); lbOptionAutoCheckFavIntervalMinutes.Enabled := cbOptionAutoCheckFavInterval.Checked; end; +procedure TMainForm.cbOptionAutoCheckFavStartupChange(Sender: TObject); +begin + cbOptionAutoOpenFavStartup.Enabled := cbOptionAutoCheckFavStartup.Checked; +end; + procedure TMainForm.cbOptionChangeUnicodeCharacterChange(Sender: TObject); begin edOptionChangeUnicodeCharacterStr.Enabled := cbOptionChangeUnicodeCharacter.Checked; @@ -4565,6 +4572,8 @@ procedure TMainForm.LoadOptions; // update cbOptionAutoCheckLatestVersion.Checked := ReadBool('update', 'AutoCheckLatestVersion', True); cbOptionAutoCheckFavStartup.Checked := ReadBool('update', 'AutoCheckFavStartup', True); + cbOptionAutoCheckFavStartupChange(cbOptionAutoCheckFavStartup); + cbOptionAutoOpenFavStartup.Checked := ReadBool('update', 'AutoOpenFavStartup', True); cbOptionAutoCheckFavInterval.Checked := ReadBool('update', 'AutoCheckFavInterval', True); seOptionAutoCheckFavIntervalMinutes.Value := ReadInteger('update', 'AutoCheckFavIntervalMinutes', 60); lbOptionAutoCheckFavIntervalMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionAutoCheckFavIntervalMinutes.Value]); @@ -4695,6 +4704,7 @@ procedure TMainForm.SaveOptions; // update WriteBool('update', 'AutoCheckLatestVersion', cbOptionAutoCheckLatestVersion.Checked); WriteBool('update', 'AutoCheckFavStartup', cbOptionAutoCheckFavStartup.Checked); + WriteBool('update', 'AutoOpenFavStartup', cbOptionAutoOpenFavStartup.Checked); WriteBool('update', 'AutoCheckFavInterval', cbOptionAutoCheckFavInterval.Checked); WriteInteger('update', 'AutoCheckFavIntervalMinutes', seOptionAutoCheckFavIntervalMinutes.Value); WriteInteger('update', 'NewMangaTime', seOptionNewMangaTime.Value); @@ -5177,7 +5187,10 @@ procedure TMainForm.LoadFormInformation; pcLeft.Width := ReadInteger('form', 'MainSplitter', 195); sbMain.Panels[0].Width := pcLeft.Width + 4; - pcMain.PageIndex := ReadInteger('form', 'pcMainPageIndex', 0); + if cbOptionAutoCheckFavStartup.Checked and cbOptionAutoOpenFavStartup.Checked then + pcMain.ActivePage := tsFavorites + else + pcMain.PageIndex := ReadInteger('form', 'pcMainPageIndex', 0); Left := ReadInteger('form', 'MainFormLeft', MainForm.Left); Top := ReadInteger('form', 'MainFormTop', MainForm.Top); diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 2ea0e2606..001ee2137 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -604,6 +604,10 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Auto check for latest version " +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Open Favorites at startup" + #: tmainform.cboptionchangeunicodecharacter.caption #| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 9520dbcf4..c0c5e4f2d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -593,6 +593,10 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Otomatis periksa versi terbaru" +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Buka Kesukaan saat program dimulai" + #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "tmainform.cboptionchangeunicodecharacter.caption" msgid "Replace all unicode character with" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 59bdd837f..319089225 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -604,6 +604,10 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Automatyczne sprawdzanie aktualizacji" +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "" + #: tmainform.cboptionchangeunicodecharacter.caption #| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" @@ -2173,3 +2177,4 @@ msgstr "Synchronizacja danych" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Aktualizacja listy" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 8bece7e44..82054847f 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -558,6 +558,10 @@ msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" msgid "Auto check for latest version " msgstr "" +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "" + #: tmainform.cboptionchangeunicodecharacter.caption msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" msgid "Replace all unicode character with" From babf440f26f2f27d4af16ef314dfcd4d345d0e25 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Feb 2017 08:57:03 +0800 Subject: [PATCH 1512/2794] bump version 0.9.89.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index efe8def87..d908cf432 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.89.0 (06-02-2017) +[*] E-Hentai: fixed root url +[*] Split MangeEden_IT and PervEden_IT +[+] Added Polish language, thanks to grzesjam +[+] Added options to open favorites at startup +Full changes: https://github.com/riderkick/FMD/compare/0.9.88.0...0.9.89.0 + 0.9.88.0 (21-01-2017) [+] Added GoodManga[EN] Full changes: https://github.com/riderkick/FMD/compare/0.9.87.0...0.9.88.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 27712bb50..2a5432929 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="88"/> + <RevisionNr Value="89"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 976fb9577..a577597f1 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.88.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.88.0/fmd_0.9.88.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.88.0/fmd_0.9.88.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.88.0/fmd_0.9.88.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.88.0/fmd_0.9.88.0_Win64.7z +VERSION=0.9.89.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.89.0/fmd_0.9.89.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.89.0/fmd_0.9.89.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.89.0/fmd_0.9.89.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.89.0/fmd_0.9.89.0_Win64.7z From 99154310a0b62fe4ecc50bff22027da82a2fd19c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Feb 2017 12:49:26 +0800 Subject: [PATCH 1513/2794] added language pt_br by havokdan. closed #481 --- mangadownloader/languages/fmd.pt_BR.po | 2118 ++++++++++++++++++++ mangadownloader/languages/updater.pt_BR.po | 105 + 2 files changed, 2223 insertions(+) create mode 100644 mangadownloader/languages/fmd.pt_BR.po create mode 100644 mangadownloader/languages/updater.pt_BR.po diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po new file mode 100644 index 000000000..738772b9b --- /dev/null +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -0,0 +1,2118 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=utf-8\n" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt-BR\n" +"X-Generator: Poedit 1.8.8\n" +"Plural-Forms: \n" + +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Exibir todos os idiomas" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Exibir grupo de scans" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Baixar imagem original (exige uma conta ExHentai)" + +#: ehentai.rs_settingsimagesize +#| msgid "Image size" +msgid "Image size:" +msgstr "Tam. da imagem:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Você está certo que quer apagar esta conta?" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Checando" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "Inválido" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Desconhecido" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "OK" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Nome de usuário ou a senha não podem estar vazios!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "Importação concluída." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "Lista de mangás não importados" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Todos os downloads" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&OK" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "Cancelar" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Checando..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "Não é possível conectar ao servidor." + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "Não foi possível obter informações do mangá. Verifique a sua conexão com a Internet e tente novamente." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Número de downloads:" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "Você deve escolher ao menos um site de mangá!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Você está certo que quer sair?" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Você está certo que quer apagar o favorito(s)?" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Você está certo que quer apagar todas as tarefas terminadas?" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Você está certo que quer apagar este(s) item(ns)?" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Você está certo que quer apagar a(s) tarefa(s)?" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Dividir download" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Digite um novo capítulo:" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Digite um novo caminho para salvamento:" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Atualizador em execução!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Você quer baixar lista de mangás do servidor?" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "URL não suportada!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "Baixar tudo\nAdicionar aos favoritos\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "Completo\nEm Andamento\n<vazio>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader já está em execução!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "Histórico" + +#: frmmain.rs_import +msgid "Import" +msgstr "Importar" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Artista(s):" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Autor(es):" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Gênero(s):" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Status:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Resumo:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Título:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Website:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "Em progresso" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Auto checar por novos capítulos a cada %d minutos" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Carregando ..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Modo: Exibir Tudo (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Modo: Filtrado (%d)" + +#: frmmain.rs_modesearching +#| msgid "Searching..." +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Modo: Buscando..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "Um mês" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "Uma semana" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "Nada\nSair\nDesligar\nHibernar\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Selecionado: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Software" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Caminho para o software (e.g. C:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Hoje" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Entrada inválida!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Ontem" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "FMD irá sair em %d segundos." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "Sistema irá hibernar em %d segundos." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "Sistema irá desligar em %d segundos." + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Remover a marca d'água" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Salvar como PNG" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Adic" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Apagar" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Editar" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Atualizar" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Website" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Nome de usuário" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Status" + +#: taccountsetform.btcancel.caption +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Cancelar" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "Ok" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Exibir senha" + +#: taccountsetform.edpassword.texthint +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Senha" + +#: taccountsetform.edusername.texthint +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Nome de usuário" + +#: taccountsetform.label1.caption +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Website" + +#: taccountsetform.label2.caption +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Nome de usuário" + +#: taccountsetform.label3.caption +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Senha" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Lista básica" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Lista de capítulos" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Lista de favoritos" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Lista de mangás" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Adicionar aos favoritos" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "&Fechar" + +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Baixar tudo" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Limpar" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Ficar no topo" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Limite do registro" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Copiar" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Cancelar" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&OK" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga Downloader" + +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Caminho para o software (e.g. C:\\MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Software:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Abortar atualizações das lista" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Adicionar aos favoritos" + +#: tmainform.btchecklatestversion.caption +#| msgid "Check for new version" +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Checar pela última versão" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Limpar arquivo de registro" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "Baixar" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Dividir download" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Checar por novos capítulos" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Importar lista" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Filtros" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Restaurar valor" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Abrir registro" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Aplicar" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Ler online" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Remover filtro" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Remover filtro" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Atualizar lista de mangá" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Visite meu blog" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "Adicionar download de lista como uma tarefa parada" + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<vazio>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Buscar somente novos mangás" + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Download automático após terminar de checar" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Auto-checar por novos capítulos em um intervalo" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Remover automaticamente mangás completados dos Favoritos" + +#: tmainform.cboptionautocheckfavstartup.caption +#| msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" +msgstr "Auto-checar por novos capítulos ao iniciar" + +#: tmainform.cboptionautochecklatestversion.caption +#| msgid "Check for new version " +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Auto-checar pela última versão " + +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Abrir os Favoritos ao iniciar" + +#: tmainform.cboptionchangeunicodecharacter.caption +#| msgid "Change all all character to" +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Replace all unicode character with" +msgstr "Substituir todos caracteres unidcode com" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Habilite isto se você tem problemas com caminhos com caracteres unicode." + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Capítulo" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Volume" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Habilitar o carregamento da capa do mangá" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Auto-gerar pasta de capítulo" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgid "Auto generate folder based on manga's name" +msgstr "Auto-gerar pasta com o nome do mangá" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Habilitar buscar em tempo real (lento em lista longas)" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Minimizar para bandeja" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "Permitir somente um FMD em execução" + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Remover nome do mangá do capítulo" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Apagar tarefa/favorito" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Baixar lista de mangá se vazia" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "Exibir Barra de Ferramentas de Downloads" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "Sair do FMD" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "Não carregar infor dos mangás quando atualizar a lista (filtros pode não funcionar!)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "Remover dados locais duplicados quando atualizando lista de mangás" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Usar proxy" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Buscar em todos sites de mangá" + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Para mais sites de mangá, por favor vá em Opções->Sites de Mangá" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Expressão Regular" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "Exibir Caixa de Seleção" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Habilitar registro" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Ação" + +#: tmainform.ckfilteraction.hint +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Um trabalho que descreve tipicamente a luta, a violência, o caos e o movimento rápido." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Adulto" + +#: tmainform.ckfilteradult.hint +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Contém conteúdo adequado somente para adultos. Títulos nesta categoria podem incluir cenas prolongadas de violência intensa e/ou conteúdo sexual gráfico e nudez." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Aventura" + +#: tmainform.ckfilteradventure.hint +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Se um personagem da história vai em uma viagem ou ao longo dessa linha, a sua melhor aposta é que é um manga de aventura. Caso contrário, depende do seu preconceito pessoal neste caso." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Comédia" + +#: tmainform.ckfiltercomedy.hint +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Um trabalho dramático que é leve e muitas vezes humorístico ou satírico no tom e que geralmente contém uma resolução feliz do conflito temático." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Doujinshi" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Trabalho de fã baseado em um mangá/anime oficial." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Drama" + +#: tmainform.ckfilterdrama.hint +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Um trabalho destinado a trazer uma resposta emocional, como incutir tristeza ou tensão." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Ecchi" + +#: tmainform.ckfilterechi.hint +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Possivelmente a linha entre hentai e não-hentai, ecchi geralmente se refere a fanservice colocar em atrair um determinado grupo de fãs." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Fantasia" + +#: tmainform.ckfilterfantasy.hint +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Qualquer coisa que envolva, mas não limitado a, magia, mundo de sonho e contos de fadas." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Troca de Sexo" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\r\nRapazes se transformando em garotas, garotas se transformando em caras" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Harém" + +#: tmainform.ckfilterharem.hint +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "Uma série envolvendo um personagem masculino e muitas personagens femininas (normalmente atraídas pelo personagem masculino). Um Harem reverso é quando os sexos são invertidos." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "Histórico" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Tem a ver com tempos antigos ou antigos." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Horror" + +#: tmainform.ckfilterhorror.hint +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Uma dolorosa emoção de medo, temor e aborrecimento; Um estremecimento de terror e ódio; O sentimento inspirado por algo terrível e chocante." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Josei" + +#: tmainform.ckfilterjosei.hint +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Literalmente \"Mulher\". Alvos das mulheres 18-30. Feminino equivalente a seinen. Ao contrário shoujo o romance é mais realista e menos idealizado. A narrativa é mais explícita e madura." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Lolicon" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Representando uma atração sexual para meninas jovens ou menores." + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Artes Marciais" + +#: tmainform.ckfiltermartialarts.hint +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "Como o nome sugere, nada de artes marciais relacionadas. Qualquer uma das várias artes de combate ou autodefesa, como aikido, karate, judo, ou taekwondo, kendo, esgrima, e assim por diante." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Maduro" + +#: tmainform.ckfiltermature.hint +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "Contém matérias que podem ser demasiado extremas para pessoas com menos de 17 anos. Os títulos desta categoria podem conter violência intensa, sangue e sangue, conteúdo sexual e/ou linguagem forte." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Mecha" + +#: tmainform.ckfiltermecha.hint +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Um trabalho que envolve e geralmente se concentra em todos os tipos de grandes máquinas robóticas." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Mistério" + +#: tmainform.ckfiltermystery.hint +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Normalmente um evento inexplicado ocorre, eo principal protagonista tenta descobrir o que causou isso." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Psicológico" + +#: tmainform.ckfilterpsychological.hint +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Geralmente lida com a filosofia de um estado de espírito, na maioria dos casos detalhando psicologia anormal." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Romance" + +#: tmainform.ckfilterromance.hint +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Qualquer história relacionada com o amor. Vamos definir o amor como entre homem e mulher, neste caso. Fora isso, cabe a sua própria imaginação do que é o amor." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "Vida escolar" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "Ter um cenário importante da história lidar com algum tipo de escola." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Ficção Científica" + +#: tmainform.ckfilterscifi.hint +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Curto para a ficção científica, esses trabalhos envolvem voltas na tecnologia e outros fenômenos relacionados à ciência que são contrárias ou trechos do mundo científico moderno." + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Seinen" + +#: tmainform.ckfilterseinen.hint +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "Do Google: Seinen significa \"jovem homem\". Manga e anime que visa especificamente jovens adultos do sexo masculino em torno das idades de 18 a 25 são títulos seinen. As histórias em seinen obras atraem estudantes universitários e aqueles no mundo do trabalho. Normalmente, as linhas de história lidar com as questões da idade adulta." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Shotacon" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "Representando uma atração sexual para jovens ou meninos menores de idade." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Shoujo" + +#: tmainform.ckfiltershoujo.hint +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Um trabalho destinado e escrito principalmente para mulheres. Normalmente envolve muito romance e desenvolvimento de caráter forte." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Shoujo Ai" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "Muitas vezes sinônimo de yuri, isso pode ser pensado como um pouco menos extremo. \"Amor da menina\", por assim dizer." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Shounen" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Um trabalho destinado e escrito principalmente para homens. Esses trabalhos geralmente envolvem lutas e/ou violência." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Shounen Ai" + +#: tmainform.ckfiltershounenai.hint +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "Muitas vezes sinónimo de yaoi, isto pode ser pensado como um pouco menos extrema. \"Boy\"s Love\", por assim dizer" + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Slice of Life" + +#: tmainform.ckfiltersliceoflife.hint +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "Como o nome sugere, este gênero representa tribulações cotidianas de um/muitos personagens. Estes desafios / eventos podem acontecer tecnicamente na vida real e são muitas vezes - se não o tempo todo - definidos na linha do tempo presente em um mundo que espelha o nosso." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Smut" + +#: tmainform.ckfiltersmut.hint +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Trata de séries que são consideradas profanas ou ofensivas, particularmente no que diz respeito ao conteúdo sexual." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Esportes" + +#: tmainform.ckfiltersports.hint +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "Como o nome sugere, qualquer coisa relacionada com esportes. Basebol, basquete, hóquei, futebol, golfe e corrida apenas para citar alguns." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Sobrenatural" + +#: tmainform.ckfiltersupernatural.hint +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Normalmente implica poderes surpreendentes e inexplicados ou eventos que desafiam as leis da física." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Tragédia" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Contém eventos resultando em grande perda e infortúnio." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Yaoi" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Este trabalho geralmente envolve relações íntimas entre os homens." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Yuri" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Este trabalho geralmente envolve relações íntimas entre as mulheres." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Entrar gêneros personalizados, separados por vírgula" + +#: tmainform.eddownloadssearch.texthint +#| msgid "Search favorites..." +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Pesquisar downloads..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Pesquisar favoritos..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Artista" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Autor" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Filtros" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Parte do resumo" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Título" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Pesquisar pelo título..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgid "Custom rename" +msgstr "Renomear personalizado" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Caminho de download padrão" + +#: tmainform.edoptionexternalparams.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalparams.texthint" +msgid "External program parameters" +msgstr "Parâmetros externos do programa" + +#: tmainform.edoptionexternalpath.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalpath.texthint" +msgid "External program path" +msgstr "Caminho do programa externo" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Renomear personalizado" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr "Proxy host/IP" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Renomear personalizado" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "Senha do proxy" + +#: tmainform.edoptionport.texthint +msgid "Proxy Port" +msgstr "Porta proxy" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "Nome de usuário Proxy" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Salvar em" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "Introduza a URL aqui" + +#: tmainform.edwebsitessearch.texthint +#| msgid "Search..." +msgctxt "tmainform.edwebsitessearch.texthint" +msgid "Search website..." +msgstr "Pesquisar no site ..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Mostrar diálogo de confirmação para" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "Caixa de Seleção" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Programa externo" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Favoritos" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Config. do Proxy" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Renomeando" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Escolha o caminho de download padrão:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Opacidade" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Artista" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Autor" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Gêneros personalizados" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "Géneros:\r\n- Marcado: Inclua este gênero.\r\n- Desmarcado: exclua esse gênero.\r\n- Cinzento: Não importa.\r\n\r\nGéneros Personalizados:\r\n- Separar vários gêneros com ','.\r\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\r\n- Exemplo: Aventura, Ecchi, Comédia.\n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Status" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Resumo" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Título" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Arquivo de registro:" + +#: tmainform.lbmode.caption +#| msgid "Mode: Show All (0)" +msgid "Mode: Show all (0)" +msgstr "Modo: Exibir Tudo (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgid "Auto check for new chapter every %d minutes" +msgstr "Auto checar por novos capítulos a cada %d minutos" + +#: tmainform.lboptionchaptercustomrename.caption +#| msgid "Chapter folder name:" +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Nome do capítulo:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Tempo de espera da conexão (segundos)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Abrir mangá usando um programa externo:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Parâmetros:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "tmainform.lboptionexternalparamshint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Nome do arquivo:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Host" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Idioma:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "Depois do download terminar:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Nome da pasta do mangá:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Número de tarefas de download ao mesmo tempo (Máx: 8)" + +#: tmainform.lboptionmaxretry.caption +#| msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Número de tentativas de repetição se as tarefas tiverem problemas de download (-1 = sempre tentar novamente)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Número de arquivos baixados por tarefa ao mesmo tempo (Máx: 32)" + +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "Novo mangá baseado no seu tempo de atualização (dias)" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Senha" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "Nível de compressão PDF" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (lossless), baixo = DCTEncode (lossy)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Porta" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Tipo" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Renomear dígitos" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Nome de usuário" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Salvar em:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Apagar" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Copiar" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Cortar" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Colar" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Colar e ir" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Selecionar tudo" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Desfazer" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Abortar" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Marca tudo" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Marcar selecionado" + +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Filtros" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "Ocultar capítulos baixados" + +#: tmainform.michapterlisthighlight.caption +#| msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" +msgstr "Realçar capítulos baixados" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Desmarcar Tudo" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Desmarcar selecionado" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Apagar" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Apagar todas as tarefas concluídas" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Tarefa Somente" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Tarefa + Dados" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Tarefa + Dados + Favorito" + +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "Desabilitar" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "Habilitar" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Fundir tarefas completas" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Abrir Pasta" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Abrir ..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Resumir" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Parar" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Exibir info do mangá" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Alterar \"Capítulo atual\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Alterar \"Salvar em\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Checar por novos capítulos" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Apagar" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Baixar tudo" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Abrir Pasta" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Abrir ..." + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Parar de checar por novos capítulos" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Exibir info do mangá" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Realçar novo mangá" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Adicionar aos Favoritos" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Apagar" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Baixar tudo" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Exibir infos do mangá" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "Depois do download terminar" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Sair" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Sair" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Hibernar" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Nada" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Desligar" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Restaurar" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Resumir Todos" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Exibir Caixa de Seleção" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Parar Todos" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Faça o download de todas as listas do servidor de uma vez" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Marca tudo" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Indeterminar tudo" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Desmarcar Tudo" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Atualizar todas as listas de uma só vez" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Faça o download da lista de mangás do servidor" + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Atualizar lista de mangá" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Todos os gêneros marcados" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Um gênero marcado" + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Modo" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "Salvar os capítulos baixados como" + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (lossless), baixo = DCTEncode (lossy)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Apagar todas as tarefas concluídas" + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Resumir Tudo" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Parar Tudo" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Agrupar Tudo" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Expandir Tudo" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "Sobre" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "Sobre FMD" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Contas" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Changelog" + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Conexões" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Cores personalizadas" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "Diálogos" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr ">>" + +#: tmainform.tsdownloadfilter.caption +msgid ">>" +msgstr ">>" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Favoritos" + +#: tmainform.tsfilter.caption +msgctxt "tmainform.tsfilter.caption" +msgid "Filter" +msgstr "Filtros" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "Geral" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Info do Mangá" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Registro" + +#: tmainform.tsmangalist.caption +msgid "Manga List" +msgstr "Lista de Mangás" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Misc" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Opções" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Salvar em" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Atualizações" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Exibir" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Avançado" + +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Opções" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Websites" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" +msgid "Websites" +msgstr "Websites" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Mangá" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Status" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "Progresso" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Velocidade" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Website" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Salvar em" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Adicionado" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Título" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Capítulo atual" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Website" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Salvar em" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "&Cancelar" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "&Baixar" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "&Adic. à fila" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "&Abortar" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "&Agora" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "&Depois" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "&Atualizar" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Adic" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Editar" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Apagar" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Número de páginas do diretório" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Downloads" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Máx. de processos por tarefa" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Número de processos" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Atualizar Lista" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Valor" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Valor" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Valor" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Selecionar um website" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Compactando..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Desabilitado" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "Baixando" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Falhou" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Falha ao criar diretório!" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Falha, tente continuar com esta tarefa!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Completo" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Preparando" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Parado" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Aguardando..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "&Adic. à fila" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "&Cancelar" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Checar por novos capítulos" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "&Baixar" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "&Remover" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "Encontrado %d mangá completado" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "A verificação de favoritos está em execução!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d mangá(s) tem novo(s) capítulo(s)" + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "%s <%s> tem %d novo(s) capítulo(s)." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "O mangá completo será removido:" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "Encontrado %d novo(s) capítulo(s) para %d mangá(s):" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Carregando: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Verificar a nova versão" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "Versão Instalada" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Última versão " + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Nova Versão encontrada!" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "%s tem %d novo(s) mangá(s)" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Obtendo diretório" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Obtendo info" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Obtendo lista para" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Indexando novo(s) título(s)" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Procurando por novo(s) título(s)" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Procurando por novo(s) título(s) de outro diretório" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Preparando" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Removendo duplicados dos dados atuais" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Removendo duplicados dos dados locais" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Removendo duplicados dos novo(s) título(s)" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Salvando dados" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Sincronizando dados" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Atualizando a lista" + diff --git a/mangadownloader/languages/updater.pt_BR.po b/mangadownloader/languages/updater.pt_BR.po new file mode 100644 index 000000000..c69e7d3ba --- /dev/null +++ b/mangadownloader/languages/updater.pt_BR.po @@ -0,0 +1,105 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=utf-8\n" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pt-BR\n" +"X-Generator: Poedit 1.8.8\n" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Tamanho do arquivo" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Aguardando..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Velocidade" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Ajuda" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "Não pode extrair o arquivo porque 7za.exe não foi encontrado!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "Um erro ocorreu quando tentou baixar o arquivo." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "Baixando [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Erro ao salvar o arquivo, cheque seu antivírus!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Falha ao baixar arquivo!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Falha ao carregar página!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Arquivo não encontrado!" + +#: umain.rs_finished +msgid "Finished." +msgstr "Terminado." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "URL Inválida!" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Carregando página..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Redirecionado..." + +#: umain.rs_response +msgid "Response" +msgstr "Resposta" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "Tentar novamente o download[%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Tentar novamente carregar página[%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Salvando arquivo... " + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Erro de resposta do servidor!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(desconhecido)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Descompactar arquivo [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Esperando o aplicativo principal para fechar..." + From 69e9b4436cf7012a827c346a8114b165cd160cf9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Feb 2017 14:02:37 +0800 Subject: [PATCH 1514/2794] update translations langcodes and coutrycodes --- baseunits/SimpleTranslator.pas | 633 ++++++++++++--------------------- 1 file changed, 219 insertions(+), 414 deletions(-) diff --git a/baseunits/SimpleTranslator.pas b/baseunits/SimpleTranslator.pas index 53f24bb14..bd7cec87a 100644 --- a/baseunits/SimpleTranslator.pas +++ b/baseunits/SimpleTranslator.pas @@ -37,381 +37,202 @@ TLanguageItem = record TLanguageCollection = array of TLanguageItem; const - Lang_english: array[0..184] of array[0..1] of string = ( - ('ab', 'Abkhaz'), - ('aa', 'Afar'), - ('af', 'Afrikaans'), - ('ak', 'Akan'), - ('sq', 'Albanian'), - ('am', 'Amharic'), - ('ar', 'Arabic'), - ('an', 'Aragonese'), - ('hy', 'Armenian'), - ('as', 'Assamese'), - ('av', 'Avaric'), - ('ae', 'Avestan'), - ('ay', 'Aymara'), - ('az', 'Azerbaijani'), - ('bm', 'Bambara'), - ('ba', 'Bashkir'), - ('eu', 'Basque'), - ('be', 'Belarusian'), - ('bn', 'Bengali, Bangla'), - ('bh', 'Bihari'), - ('bi', 'Bislama'), - ('bs', 'Bosnian'), - ('br', 'Breton'), - ('bg', 'Bulgarian'), - ('my', 'Burmese'), - ('ca', 'Catalan'), - ('ch', 'Chamorro'), - ('ce', 'Chechen'), - ('ny', 'Chichewa, Chewa, Nyanja'), - ('zh', 'Chinese'), - ('cv', 'Chuvash'), - ('kw', 'Cornish'), - ('co', 'Corsican'), - ('cr', 'Cree'), - ('hr', 'Croatian'), - ('cs', 'Czech'), - ('da', 'Danish'), - ('dv', 'Divehi, Dhivehi, Maldivian'), - ('nl', 'Dutch'), - ('dz', 'Dzongkha'), - ('en', 'English'), - ('eo', 'Esperanto'), - ('et', 'Estonian'), - ('ee', 'Ewe'), - ('fo', 'Faroese'), - ('fj', 'Fijian'), - ('fi', 'Finnish'), - ('fr', 'French'), - ('ff', 'Fula, Fulah, Pulaar, Pular'), - ('gl', 'Galician'), - ('ka', 'Georgian'), - ('de', 'German'), - ('el', 'Greek (modern)'), - ('gn', 'Guaraní'), - ('gu', 'Gujarati'), - ('ht', 'Haitian, Haitian Creole'), - ('ha', 'Hausa'), - ('he', 'Hebrew (modern)'), - ('hz', 'Herero'), - ('hi', 'Hindi'), - ('ho', 'Hiri Motu'), - ('hu', 'Hungarian'), - ('ia', 'Interlingua'), - ('id', 'Indonesian'), - ('ie', 'Interlingue'), - ('ga', 'Irish'), - ('ig', 'Igbo'), - ('ik', 'Inupiaq'), - ('io', 'Ido'), - ('is', 'Icelandic'), - ('it', 'Italian'), - ('iu', 'Inuktitut'), - ('ja', 'Japanese'), - ('jv', 'Javanese'), - ('kl', 'Kalaallisut, Greenlandic'), - ('kn', 'Kannada'), - ('kr', 'Kanuri'), - ('ks', 'Kashmiri'), - ('kk', 'Kazakh'), - ('km', 'Khmer'), - ('ki', 'Kikuyu, Gikuyu'), - ('rw', 'Kinyarwanda'), - ('ky', 'Kyrgyz'), - ('kv', 'Komi'), - ('kg', 'Kongo'), - ('ko', 'Korean'), - ('ku', 'Kurdish'), - ('kj', 'Kwanyama, Kuanyama'), - ('la', 'Latin'), - ('lld', 'Ladin'), - ('lb', 'Luxembourgish, Letzeburgesch'), - ('lg', 'Ganda'), - ('li', 'Limburgish, Limburgan, Limburger'), - ('ln', 'Lingala'), - ('lo', 'Lao'), - ('lt', 'Lithuanian'), - ('lu', 'Luba-Katanga'), - ('lv', 'Latvian'), - ('gv', 'Manx'), - ('mk', 'Macedonian'), - ('mg', 'Malagasy'), - ('ms', 'Malay'), - ('ml', 'Malayalam'), - ('mt', 'Maltese'), - ('mi', 'Māori'), - ('mr', 'Marathi (Marāṭhī)'), - ('mh', 'Marshallese'), - ('mn', 'Mongolian'), - ('na', 'Nauru'), - ('nv', 'Navajo, Navaho'), - ('nd', 'Northern Ndebele'), - ('ne', 'Nepali'), - ('ng', 'Ndonga'), - ('nb', 'Norwegian Bokmål'), - ('nn', 'Norwegian Nynorsk'), - ('no', 'Norwegian'), - ('ii', 'Nuosu'), - ('nr', 'Southern Ndebele'), - ('oc', 'Occitan'), - ('oj', 'Ojibwe, Ojibwa'), - ('cu', 'Old Church Slavonic, Church Slavonic, Old Bulgarian'), - ('om', 'Oromo'), - ('or', 'Oriya'), - ('os', 'Ossetian, Ossetic'), - ('pa', 'Panjabi, Punjabi'), - ('pi', 'Pāli'), - ('fa', 'Persian (Farsi)'), - ('pl', 'Polish'), - ('ps', 'Pashto, Pushto'), - ('pt', 'Portuguese'), - ('qu', 'Quechua'), - ('rm', 'Romansh'), - ('rn', 'Kirundi'), - ('ro', 'Romanian'), - ('ru', 'Russian'), - ('sa', 'Sanskrit (Saṁskṛta)'), - ('sc', 'Sardinian'), - ('sd', 'Sindhi'), - ('se', 'Northern Sami'), - ('sm', 'Samoan'), - ('sg', 'Sango'), - ('sr', 'Serbian'), - ('gd', 'Scottish Gaelic, Gaelic'), - ('sn', 'Shona'), - ('si', 'Sinhala, Sinhalese'), - ('sk', 'Slovak'), - ('sl', 'Slovene'), - ('so', 'Somali'), - ('st', 'Southern Sotho'), - ('es', 'Spanish'), - ('su', 'Sundanese'), - ('sw', 'Swahili'), - ('ss', 'Swati'), - ('sv', 'Swedish'), - ('ta', 'Tamil'), - ('te', 'Telugu'), - ('tg', 'Tajik'), - ('th', 'Thai'), - ('ti', 'Tigrinya'), - ('bo', 'Tibetan Standard, Tibetan, Central'), - ('tk', 'Turkmen'), - ('tl', 'Tagalog'), - ('tn', 'Tswana'), - ('to', 'Tonga (Tonga Islands)'), - ('tr', 'Turkish'), - ('ts', 'Tsonga'), - ('tt', 'Tatar'), - ('tw', 'Twi'), - ('ty', 'Tahitian'), - ('ug', 'Uyghur'), - ('uk', 'Ukrainian'), - ('ur', 'Urdu'), - ('uz', 'Uzbek'), - ('ve', 'Venda'), - ('vi', 'Vietnamese'), - ('vo', 'Volapük'), - ('wa', 'Walloon'), - ('cy', 'Welsh'), - ('wo', 'Wolof'), - ('fy', 'Western Frisian'), - ('xh', 'Xhosa'), - ('yi', 'Yiddish'), - ('yo', 'Yoruba'), - ('za', 'Zhuang, Chuang'), - ('zu', 'Zulu')); - - Lang_native: array[0..184] of array[0..1] of string = ( - ('ab', 'аҧсуа бызшәа, аҧсшәа'), - ('aa', 'Afaraf'), - ('af', 'Afrikaans'), - ('ak', 'Akan'), - ('sq', 'Shqip'), - ('am', 'አማርኛ'), - ('ar', 'العربية'), - ('an', 'aragonés'), - ('hy', 'Հայերեն'), - ('as', 'অসমীয়া'), - ('av', 'авар мацӀ, магӀарул мацӀ'), - ('ae', 'avesta'), - ('ay', 'aymar aru'), - ('az', 'azərbaycan dili'), - ('bm', 'bamanankan'), - ('ba', 'башҡорт теле'), - ('eu', 'euskara, euskera'), - ('be', 'беларуская мова'), - ('bn', 'বাংলা'), - ('bh', 'भोजपुरी'), - ('bi', 'Bislama'), - ('bs', 'bosanski jezik'), - ('br', 'brezhoneg'), - ('bg', 'български език'), - ('my', 'ဗမာစာ'), - ('ca', 'català'), - ('ch', 'Chamoru'), - ('ce', 'нохчийн мотт'), - ('ny', 'chiCheŵa, chinyanja'), - ('zh', '中文 (Zhōngwén), 汉语, 漢語'), - ('cv', 'чӑваш чӗлхи'), - ('kw', 'Kernewek'), - ('co', 'corsu, lingua corsa'), - ('cr', 'ᓀᐦᐃᔭᐍᐏᐣ'), - ('hr', 'hrvatski jezik'), - ('cs', 'čeština, český jazyk'), - ('da', 'dansk'), - ('dv', 'ދިވެހި'), - ('nl', 'Nederlands, Vlaams'), - ('dz', 'རྫོང་ཁ'), - ('en', 'English'), - ('eo', 'Esperanto'), - ('et', 'eesti, eesti keel'), - ('ee', 'Eʋegbe'), - ('fo', 'føroyskt'), - ('fj', 'vosa Vakaviti'), - ('fi', 'suomi, suomen kieli'), - ('fr', 'français, langue française'), - ('ff', 'Fulfulde, Pulaar, Pular'), - ('gl', 'galego'), - ('ka', 'ქართული'), - ('de', 'Deutsch'), - ('el', 'ελληνικά'), - ('gn', 'Avañe''ẽ'), - ('gu', 'ગુજરાતી'), - ('ht', 'Kreyòl ayisyen'), - ('ha', '(Hausa) هَوُسَ'), - ('he', 'עברית'), - ('hz', 'Otjiherero'), - ('hi', 'हिन्दी, हिंदी'), - ('ho', 'Hiri Motu'), - ('hu', 'magyar'), - ('ia', 'Interlingua'), - ('id', 'Bahasa Indonesia'), - ('ie', 'Interlingue'), - ('ga', 'Gaeilge'), - ('ig', 'Asụsụ Igbo'), - ('ik', 'Iñupiaq, Iñupiatun'), - ('io', 'Ido'), - ('is', 'Íslenska'), - ('it', 'italiano'), - ('iu', 'ᐃᓄᒃᑎᑐᑦ'), - ('ja', '日本語 (にほんご)'), - ('jv', 'basa Jawa'), - ('kl', 'kalaallisut, kalaallit oqaasii'), - ('kn', 'ಕನ್ನಡ'), - ('kr', 'Kanuri'), - ('ks', 'कश्मीरी, كشميري‎'), - ('kk', 'қазақ тілі'), - ('km', 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ'), - ('ki', 'Gĩkũyũ'), - ('rw', 'Ikinyarwanda'), - ('ky', 'Кыргызча, Кыргыз тили'), - ('kv', 'коми кыв'), - ('kg', 'Kikongo'), - ('ko', '한국어, 조선어'), - ('ku', 'Kurdî, كوردی‎'), - ('kj', 'Kuanyama'), - ('la', 'latine, lingua latina'), - ('lld', 'ladin, lingua ladina'), - ('lb', 'Lëtzebuergesch'), - ('lg', 'Luganda'), - ('li', 'Limburgs'), - ('ln', 'Lingála'), - ('lo', 'ພາສາລາວ'), - ('lt', 'lietuvių kalba'), - ('lu', 'Tshiluba'), - ('lv', 'latviešu valoda'), - ('gv', 'Gaelg, Gailck'), - ('mk', 'македонски јазик'), - ('mg', 'fiteny malagasy'), - ('ms', 'bahasa Melayu, بهاس ملايو‎'), - ('ml', 'മലയാളം'), - ('mt', 'Malti'), - ('mi', 'te reo Māori'), - ('mr', 'मराठी'), - ('mh', 'Kajin M̧ajeļ'), - ('mn', 'монгол'), - ('na', 'Ekakairũ Naoero'), - ('nv', 'Diné bizaad'), - ('nd', 'isiNdebele'), - ('ne', 'नेपाली'), - ('ng', 'Owambo'), - ('nb', 'Norsk bokmål'), - ('nn', 'Norsk nynorsk'), - ('no', 'Norsk'), - ('ii', 'ꆈꌠ꒿ Nuosuhxop'), - ('nr', 'isiNdebele'), - ('oc', 'occitan, lenga d''òc'), - ('oj', 'ᐊᓂᔑᓈᐯᒧᐎᓐ'), - ('cu', 'ѩзыкъ словѣньскъ'), - ('om', 'Afaan Oromoo'), - ('or', 'ଓଡ଼ିଆ'), - ('os', 'ирон æвзаг'), - ('pa', 'ਪੰਜਾਬੀ, پنجابی‎'), - ('pi', 'पाऴि'), - ('fa', 'فارسی'), - ('pl', 'język polski, polszczyzna'), - ('ps', 'پښتو'), - ('pt', 'português'), - ('qu', 'Runa Simi, Kichwa'), - ('rm', 'rumantsch grischun'), - ('rn', 'Ikirundi'), - ('ro', 'limba română'), - ('ru', 'Русский'), - ('sa', 'संस्कृतम्'), - ('sc', 'sardu'), - ('sd', 'सिन्धी, سنڌي، سندھی‎'), - ('se', 'Davvisámegiella'), - ('sm', 'gagana fa''a Samoa'), - ('sg', 'yângâ tî sängö'), - ('sr', 'српски језик'), - ('gd', 'Gàidhlig'), - ('sn', 'chiShona'), - ('si', 'සිංහල'), - ('sk', 'slovenčina, slovenský jazyk'), - ('sl', 'slovenski jezik, slovenščina'), - ('so', 'Soomaaliga, af Soomaali'), - ('st', 'Sesotho'), - ('es', 'español'), - ('su', 'Basa Sunda'), - ('sw', 'Kiswahili'), - ('ss', 'SiSwati'), - ('sv', 'svenska'), - ('ta', 'தமிழ்'), - ('te', 'తెలుగు'), - ('tg', 'тоҷикӣ, toçikī, تاجیکی‎'), - ('th', 'ไทย'), - ('ti', 'ትግርኛ'), - ('bo', 'བོད་ཡིག'), - ('tk', 'Türkmen, Түркмен'), - ('tl', 'Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔'), - ('tn', 'Setswana'), - ('to', 'faka Tonga'), - ('tr', 'Türkçe'), - ('ts', 'Xitsonga'), - ('tt', 'татар теле, tatar tele'), - ('tw', 'Twi'), - ('ty', 'Reo Tahiti'), - ('ug', 'ئۇيغۇرچە‎, Uyghurche'), - ('uk', 'українська мова'), - ('ur', 'اردو'), - ('uz', 'Oʻzbek, Ўзбек, أۇزبېك‎'), - ('ve', 'Tshivenḓa'), - ('vi', 'Việt Nam'), - ('vo', 'Volapük'), - ('wa', 'walon'), - ('cy', 'Cymraeg'), - ('wo', 'Wollof'), - ('fy', 'Frysk'), - ('xh', 'isiXhosa'), - ('yi', 'ייִדיש'), - ('yo', 'Yorùbá'), - ('za', 'Saɯ cueŋƅ, Saw cuengh'), - ('zu', 'isiZulu')); - - Country_name: array[0..248] of array[0..1] of string = ( + { + https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + //table[2]/tbody/tr[position()>1]/concat("('",td[5],"', '",td[3],"', '",td[4],"'),") + } + lang_codes: array[0..183] of array[0..2] of string = ( + ('ab', 'Abkhaz', 'аҧсуа бызшәа, аҧсшәа'), + ('aa', 'Afar', 'Afaraf'), + ('af', 'Afrikaans', 'Afrikaans'), + ('ak', 'Akan', 'Akan'), + ('sq', 'Albanian', 'Shqip'), + ('am', 'Amharic', 'አማርኛ'), + ('ar', 'Arabic', 'العربية'), + ('an', 'Aragonese', 'aragonés'), + ('hy', 'Armenian', 'Հայերեն'), + ('as', 'Assamese', 'অসমীয়া'), + ('av', 'Avaric', 'авар мацӀ, магӀарул мацӀ'), + ('ae', 'Avestan', 'avesta'), + ('ay', 'Aymara', 'aymar aru'), + ('az', 'Azerbaijani', 'azərbaycan dili'), + ('bm', 'Bambara', 'bamanankan'), + ('ba', 'Bashkir', 'башҡорт теле'), + ('eu', 'Basque', 'euskara, euskera'), + ('be', 'Belarusian', 'беларуская мова'), + ('bn', 'Bengali, Bangla', 'বাংলা'), + ('bh', 'Bihari', 'भोजपुरी'), + ('bi', 'Bislama', 'Bislama'), + ('bs', 'Bosnian', 'bosanski jezik'), + ('br', 'Breton', 'brezhoneg'), + ('bg', 'Bulgarian', 'български език'), + ('my', 'Burmese', 'ဗမာစာ'), + ('ca', 'Catalan', 'català'), + ('ch', 'Chamorro', 'Chamoru'), + ('ce', 'Chechen', 'нохчийн мотт'), + ('ny', 'Chichewa, Chewa, Nyanja', 'chiCheŵa, chinyanja'), + ('zh', 'Chinese', '中文 (Zhōngwén), 汉语, 漢語'), + ('cv', 'Chuvash', 'чӑваш чӗлхи'), + ('kw', 'Cornish', 'Kernewek'), + ('co', 'Corsican', 'corsu, lingua corsa'), + ('cr', 'Cree', 'ᓀᐦᐃᔭᐍᐏᐣ'), + ('hr', 'Croatian', 'hrvatski jezik'), + ('cs', 'Czech', 'čeština, český jazyk'), + ('da', 'Danish', 'dansk'), + ('dv', 'Divehi, Dhivehi, Maldivian', 'ދިވެހި'), + ('nl', 'Dutch', 'Nederlands, Vlaams'), + ('dz', 'Dzongkha', 'རྫོང་ཁ'), + ('en', 'English', 'English'), + ('eo', 'Esperanto', 'Esperanto'), + ('et', 'Estonian', 'eesti, eesti keel'), + ('ee', 'Ewe', 'Eʋegbe'), + ('fo', 'Faroese', 'føroyskt'), + ('fj', 'Fijian', 'vosa Vakaviti'), + ('fi', 'Finnish', 'suomi, suomen kieli'), + ('fr', 'French', 'français, langue française'), + ('ff', 'Fula, Fulah, Pulaar, Pular', 'Fulfulde, Pulaar, Pular'), + ('gl', 'Galician', 'galego'), + ('ka', 'Georgian', 'ქართული'), + ('de', 'German', 'Deutsch'), + ('el', 'Greek (modern)', 'ελληνικά'), + ('gn', 'Guaraní', 'Avañe''ẽ'), + ('gu', 'Gujarati', 'ગુજરાતી'), + ('ht', 'Haitian, Haitian Creole', 'Kreyòl ayisyen'), + ('ha', 'Hausa', '(Hausa) هَوُسَ'), + ('he', 'Hebrew (modern)', 'עברית'), + ('hz', 'Herero', 'Otjiherero'), + ('hi', 'Hindi', 'हिन्दी, हिंदी'), + ('ho', 'Hiri Motu', 'Hiri Motu'), + ('hu', 'Hungarian', 'magyar'), + ('ia', 'Interlingua', 'Interlingua'), + ('id', 'Indonesian', 'Bahasa Indonesia'), + ('ie', 'Interlingue', 'Originally called Occidental; then Interlingue after WWII'), + ('ga', 'Irish', 'Gaeilge'), + ('ig', 'Igbo', 'Asụsụ Igbo'), + ('ik', 'Inupiaq', 'Iñupiaq, Iñupiatun'), + ('io', 'Ido', 'Ido'), + ('is', 'Icelandic', 'Íslenska'), + ('it', 'Italian', 'Italiano'), + ('iu', 'Inuktitut', 'ᐃᓄᒃᑎᑐᑦ'), + ('ja', 'Japanese', '日本語 (にほんご)'), + ('jv', 'Javanese', 'ꦧꦱꦗꦮ, Basa Jawa'), + ('kl', 'Kalaallisut, Greenlandic', 'kalaallisut, kalaallit oqaasii'), + ('kn', 'Kannada', 'ಕನ್ನಡ'), + ('kr', 'Kanuri', 'Kanuri'), + ('ks', 'Kashmiri', 'कश्मीरी, كشميري‎'), + ('kk', 'Kazakh', 'қазақ тілі'), + ('km', 'Khmer', 'ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ'), + ('ki', 'Kikuyu, Gikuyu', 'Gĩkũyũ'), + ('rw', 'Kinyarwanda', 'Ikinyarwanda'), + ('ky', 'Kyrgyz', 'Кыргызча, Кыргыз тили'), + ('kv', 'Komi', 'коми кыв'), + ('kg', 'Kongo', 'Kikongo'), + ('ko', 'Korean', '한국어'), + ('ku', 'Kurdish', 'Kurdî, كوردی‎'), + ('kj', 'Kwanyama, Kuanyama', 'Kuanyama'), + ('la', 'Latin', 'latine, lingua latina'), + ('lb', 'Luxembourgish, Letzeburgesch', 'Lëtzebuergesch'), + ('lg', 'Ganda', 'Luganda'), + ('li', 'Limburgish, Limburgan, Limburger', 'Limburgs'), + ('ln', 'Lingala', 'Lingála'), + ('lo', 'Lao', 'ພາສາລາວ'), + ('lt', 'Lithuanian', 'lietuvių kalba'), + ('lu', 'Luba-Katanga', 'Tshiluba'), + ('lv', 'Latvian', 'latviešu valoda'), + ('gv', 'Manx', 'Gaelg, Gailck'), + ('mk', 'Macedonian', 'македонски јазик'), + ('mg', 'Malagasy', 'fiteny malagasy'), + ('ms', 'Malay', 'bahasa Melayu, بهاس ملايو‎'), + ('ml', 'Malayalam', 'മലയാളം'), + ('mt', 'Maltese', 'Malti'), + ('mi', 'Māori', 'te reo Māori'), + ('mr', 'Marathi (Marāṭhī)', 'मराठी'), + ('mh', 'Marshallese', 'Kajin M̧ajeļ'), + ('mn', 'Mongolian', 'Монгол хэл'), + ('na', 'Nauruan', 'Dorerin Naoero'), + ('nv', 'Navajo, Navaho', 'Diné bizaad'), + ('nd', 'Northern Ndebele', 'isiNdebele'), + ('ne', 'Nepali', 'नेपाली'), + ('ng', 'Ndonga', 'Owambo'), + ('nb', 'Norwegian Bokmål', 'Norsk bokmål'), + ('nn', 'Norwegian Nynorsk', 'Norsk nynorsk'), + ('no', 'Norwegian', 'Norsk'), + ('ii', 'Nuosu', 'ꆈꌠ꒿ Nuosuhxop'), + ('nr', 'Southern Ndebele', 'isiNdebele'), + ('oc', 'Occitan', 'occitan, lenga d''òc'), + ('oj', 'Ojibwe, Ojibwa', 'ᐊᓂᔑᓈᐯᒧᐎᓐ'), + ('cu', 'Old Church Slavonic, Church Slavonic, Old Bulgarian', 'ѩзыкъ словѣньскъ'), + ('om', 'Oromo', 'Afaan Oromoo'), + ('or', 'Oriya', 'ଓଡ଼ିଆ'), + ('os', 'Ossetian, Ossetic', 'ирон æвзаг'), + ('pa', 'Eastern Punjabi, Eastern Panjabi', 'ਪੰਜਾਬੀ'), + ('pi', 'Pāli', 'पाऴि'), + ('fa', 'Persian (Farsi)', 'فارسی'), + ('pl', 'Polish', 'język polski, polszczyzna'), + ('ps', 'Pashto, Pushto', 'پښتو'), + ('pt', 'Portuguese', 'Português'), + ('qu', 'Quechua', 'Runa Simi, Kichwa'), + ('rm', 'Romansh', 'rumantsch grischun'), + ('rn', 'Kirundi', 'Ikirundi'), + ('ro', 'Romanian', 'Română'), + ('ru', 'Russian', 'Русский'), + ('sa', 'Sanskrit (Saṁskṛta)', 'संस्कृतम्'), + ('sc', 'Sardinian', 'sardu'), + ('sd', 'Sindhi', 'सिन्धी, سنڌي، سندھی‎'), + ('se', 'Northern Sami', 'Davvisámegiella'), + ('sm', 'Samoan', 'gagana fa''a Samoa'), + ('sg', 'Sango', 'yângâ tî sängö'), + ('sr', 'Serbian', 'српски језик'), + ('gd', 'Scottish Gaelic, Gaelic', 'Gàidhlig'), + ('sn', 'Shona', 'chiShona'), + ('si', 'Sinhalese, Sinhala', 'සිංහල'), + ('sk', 'Slovak', 'slovenčina, slovenský jazyk'), + ('sl', 'Slovene', 'slovenski jezik, slovenščina'), + ('so', 'Somali', 'Soomaaliga, af Soomaali'), + ('st', 'Southern Sotho', 'Sesotho'), + ('es', 'Spanish', 'Español'), + ('su', 'Sundanese', 'Basa Sunda'), + ('sw', 'Swahili', 'Kiswahili'), + ('ss', 'Swati', 'SiSwati'), + ('sv', 'Swedish', 'svenska'), + ('ta', 'Tamil', 'தமிழ்'), + ('te', 'Telugu', 'తెలుగు'), + ('tg', 'Tajik', 'тоҷикӣ, toçikī, تاجیکی‎'), + ('th', 'Thai', 'ไทย'), + ('ti', 'Tigrinya', 'ትግርኛ'), + ('bo', 'Tibetan Standard, Tibetan, Central', 'བོད་ཡིག'), + ('tk', 'Turkmen', 'Türkmen, Түркмен'), + ('tl', 'Tagalog', 'Wikang Tagalog'), + ('tn', 'Tswana', 'Setswana'), + ('to', 'Tonga (Tonga Islands)', 'faka Tonga'), + ('tr', 'Turkish', 'Türkçe'), + ('ts', 'Tsonga', 'Xitsonga'), + ('tt', 'Tatar', 'татар теле, tatar tele'), + ('tw', 'Twi', 'Twi'), + ('ty', 'Tahitian', 'Reo Tahiti'), + ('ug', 'Uyghur', 'ئۇيغۇرچە‎, Uyghurche'), + ('uk', 'Ukrainian', 'Українська'), + ('ur', 'Urdu', 'اردو'), + ('uz', 'Uzbek', 'Oʻzbek, Ўзбек, أۇزبېك‎'), + ('ve', 'Venda', 'Tshivenḓa'), + ('vi', 'Vietnamese', 'Tiếng Việt'), + ('vo', 'Volapük', 'Volapük'), + ('wa', 'Walloon', 'walon'), + ('cy', 'Welsh', 'Cymraeg'), + ('wo', 'Wolof', 'Wollof'), + ('fy', 'Western Frisian', 'Frysk'), + ('xh', 'Xhosa', 'isiXhosa'), + ('yi', 'Yiddish', 'ייִדיש'), + ('yo', 'Yoruba', 'Yorùbá'), + ('za', 'Zhuang, Chuang', 'Saɯ cueŋƅ, Saw cuengh'), + ('zu', 'Zulu', 'isiZulu') + ); + + { + https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 + //table[3]/tbody/tr[position()>1]/concat("('",td[1],"', '",td[2],"'),") + } + country_codes: array[0..248] of array[0..1] of string = ( ('AD', 'Andorra'), ('AE', 'United Arab Emirates'), ('AF', 'Afghanistan'), @@ -426,7 +247,7 @@ TLanguageItem = record ('AT', 'Austria'), ('AU', 'Australia'), ('AW', 'Aruba'), - ('AX', 'Åland Islands'), + ('AX', 'Aland Islands !Åland Islands'), ('AZ', 'Azerbaijan'), ('BA', 'Bosnia and Herzegovina'), ('BB', 'Barbados'), @@ -455,7 +276,7 @@ TLanguageItem = record ('CF', 'Central African Republic'), ('CG', 'Congo'), ('CH', 'Switzerland'), - ('CI', 'Côte d''Ivoire'), + ('CI', 'Cote d''Ivoire !Côte d''Ivoire'), ('CK', 'Cook Islands'), ('CL', 'Chile'), ('CM', 'Cameroon'), @@ -467,7 +288,7 @@ TLanguageItem = record ('CW', 'Curaçao'), ('CX', 'Christmas Island'), ('CY', 'Cyprus'), - ('CZ', 'Czech Republic'), + ('CZ', 'Czechia'), ('DE', 'Germany'), ('DJ', 'Djibouti'), ('DK', 'Denmark'), @@ -599,7 +420,7 @@ TLanguageItem = record ('PW', 'Palau'), ('PY', 'Paraguay'), ('QA', 'Qatar'), - ('RE', 'Réunion'), + ('RE', 'Reunion !Réunion'), ('RO', 'Romania'), ('RS', 'Serbia'), ('RU', 'Russian Federation'), @@ -660,7 +481,8 @@ TLanguageItem = record ('YT', 'Mayotte'), ('ZA', 'South Africa'), ('ZM', 'Zambia'), - ('ZW', 'Zimbabwe')); + ('ZW', 'Zimbabwe') + ); ldir: array[0..3] of string = ('LANG', 'languages', 'locale', 'locale' + PathDelim + 'LC_MESSAGES'); @@ -673,7 +495,7 @@ TLanguageItem = record procedure CollectLanguagesFiles(const appname: string = ''; const dir: string = ''; useNativeName: Boolean = True); - function GetLangName(const lcode: string; useNativeName: Boolean = True): string; + function GetLangName(const lcode: string; const useNativeName: Boolean = True): string; function SetLang(const lang: string; appname: string = ''): Boolean; function SetLangByIndex(const Index: Integer): Boolean; @@ -761,48 +583,34 @@ procedure CollectLanguagesFiles(const appname: string; const dir: string; AvailableLanguages.CustomSort(@SortValue); end; -function GetLangName(const lcode: string; useNativeName: Boolean): string; +function GetLangName(const lcode: string; const useNativeName: Boolean): string; - function GetLang(const l: string): string; + function getlangcodes(const l: string): string; var i: Integer; begin Result := l; - for i := Low(Lang_english) to High(Lang_english) do - begin - if SameText(l, Lang_english[i, 0]) then - begin - Result := Lang_english[i, 1]; - Break; - end; - end; - end; - - function GetLangNative(const l: string): string; - var - i: Integer; - begin - Result := l; - for i := Low(Lang_native) to High(Lang_native) do - begin - if SameText(l, Lang_native[i, 0]) then + for i := Low(lang_codes) to High(lang_codes) do + if SameText(l, lang_codes[i, 0]) then begin - Result := Lang_native[i, 1]; + if useNativeName then + Result := lang_codes[i, 2] + else + Result := lang_codes[i, 1]; Break; end; - end; end; - function GetCountry(l: string): string; + function getcountrycodes(l: string): string; var i: Integer; begin Result := l; - for i := Low(Country_name) to High(Country_name) do + for i := Low(country_codes) to High(country_codes) do begin - if SameText(l, Country_name[i, 0]) then + if SameText(l, country_codes[i, 0]) then begin - Result := Country_name[i, 1]; + Result := country_codes[i, 1]; Break; end; end; @@ -821,17 +629,14 @@ function GetLangName(const lcode: string; useNativeName: Boolean): string; if p > 1 then begin id := Copy(s, 1, p - 1); - if useNativeName then - Result := GetLangNative(id) - else - Result := GetLang(id); + Result := getlangcodes(id); id := Copy(s, P + 1, Length(s)); - s := GetCountry(id); + s := getcountrycodes(id); if s <> id then - Result := Format('%s (%s)', [Result, GetCountry(id)]); + Result := Format('%s (%s)', [Result, s]); end else - Result := GetLang(s); + Result := getlangcodes(s); end; function TranslateLCL(Lang: string): Boolean; From f9448c7dd1752ba1839398910f90623806bbb20e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Feb 2017 10:20:52 +0800 Subject: [PATCH 1515/2794] added greek translation by geogeo_gr. closed #460 --- mangadownloader/languages/fmd.el_GR.po | 2229 ++++++++++++++++++++ mangadownloader/languages/updater.el_GR.po | 109 + 2 files changed, 2338 insertions(+) create mode 100644 mangadownloader/languages/fmd.el_GR.po create mode 100644 mangadownloader/languages/updater.el_GR.po diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po new file mode 100644 index 000000000..cd43988b8 --- /dev/null +++ b/mangadownloader/languages/fmd.el_GR.po @@ -0,0 +1,2229 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: Free Manga Downloader 0.9.85\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: geogeo.gr <geogeo.gr@gmail.com>\n" +"Language-Team: Greek <www.geogeo.gr>\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en_US\n" +"X-Generator: Poedit 1.8.8\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Language: Greek\n" +"X-Poedit-Country: GREECE\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-Bookmarks: -1,-1,-1,-1,-1,-1,-1,29,-1,-1\n" + +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Εμφάνιση όλων των γλωσσών" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Εμφάνιση ομάδας scanlation" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Λήψη αρχικής εικόνας (απαιτείται λογαριασμός ExHentai)" + +#: ehentai.rs_settingsimagesize +#| msgid "Image size" +msgid "Image size:" +msgstr "Μέγεθος εικόνας:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Αυτόματα\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Αρχική\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Είστε βέβαιος ότι θέλετε να διαγράψετε αυτό το λογαριασμό;" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Έλεγχος" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "Μη έγκυρο" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Άγνωστο" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "Εντάξει" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Το όνομα χρήστη ή ο κωδικός πρόσβασης δεν μπορεί να είναι κενά!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "Η εισαγωγή ολοκληρώθηκε." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "Λίστα μη εισηγμένων manga" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Όλες οι λήψεις" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&Εντάξει" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "Άκυρο" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Έλεγχος..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "Δεν είναι δυνατή η σύνδεση με τον διακομιστή." + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "Δεν είναι δυνατή η λήψη πληροφοριών του manga. Ελέγξτε τη σύνδεσή σας στο διαδίκτυο και δοκιμάστε ξανά." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Πλήθος λήψεων:" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "Πρέπει να επιλέξετε τουλάχιστον 1 ιστότοπο manga!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Είστε βέβαιος ότι θέλετε έξοδο;" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Είστε βέβαιος ότι θέλετε να διαγράψετε τα αγαπημένα;" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Είστε βέβαιος ότι θέλετε να διαγράψετε όλες τις ολοκληρωμένες εργασίες;" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Είστε βέβαιος ότι θέλετε να διαγράψετε αυτά τα στοιχεία;" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Είστε βέβαιος ότι θέλετε να διαγράψετε τις εργασίες;" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Διαχωρισμός λήψης" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "" +"Ο τίτλος αυτός είναι ήδη στη λίστα λήψης.\n" +"Θέλετε οπωσδήποτε να τον κατεβάσετε;\n" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Γράψτε στο νέο κεφάλαιο:" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Γράψτε στη νέα διαδρομή αποθήκευσης:" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Η λειτουργία ενημέρωσης εκτελείται ήδη!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Θέλετε να κατεβάσετε τη λίστα manga από τον διακομιστή;" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "Η URL δεν υποστηρίζεται!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "" +"Λήψη όλων\n" +"Προσθήκη στα αγαπημένα\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "" +"Ολοκληρωμένο\n" +"Σε εξέλιξη\n" +"<καμία>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Το Free Manga Downloader εκτελείται ήδη!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "" +"Υπάρχει ένα πρόβλημα με αυτά τα δεδομένα!\n" +"Η αφαίρεση και προσθήκη ξανά αυτών των δεδομένων μπορεί να διορθώσει το πρόβλημα.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "History" + +#: frmmain.rs_import +msgid "Import" +msgstr "Εισαγωγή" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Καλλιτέχνης(ες):" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Δημιουργός(οί):" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Είδος(η):" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Κατάσταση:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Περίληψη:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Τίτλος:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Ιστότοπος:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "Σε εξέλιξη" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Αυτόματος έλεγχος για νέα κεφάλαια κάθε %d λεπτά" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "" +"%s : Η διαδρομή του manga\n" +"%s : Όνομα αρχείου κεφαλαίου\n" +"\n" +"Παράδειγμα : \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Φόρτωση..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Λειτ.: Εμφάνιση όλων (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Λειτ.: Φιλτράρισμα (%d)" + +#: frmmain.rs_modesearching +#| msgid "Searching..." +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Λειτ.: Αναζήτηση..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "Ένας μήνας" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "Μια εβδομάδα" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "" +"Καμία ενέργεια\n" +"Έξοδος\n" +"Τερματισμός υπολογιστή\n" +"Αδρανοποίηση υπολογιστή\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Επιλεγμένα: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Πρόγραμμα" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Διαδρομή του προγράμματος (π.χ. C:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Σήμερα" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Μη έγκυρη εισαγωγή!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Χθές" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "Θα γίνει έξοδος του FMD σε %d δευτερόλεπτα." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "Το σύστημα θα αδρανοποιηθεί σε %d δευτερόλεπτα." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "Το σύστημα θα τερματιστεί σε %d δευτερόλεπτα." + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Αφαίρεση υδατογραφήματος" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Αποθήκευση ως PNG" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Προσθήκη" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Διαγραφή" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Επεξεργασία" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Ανανέωση" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Όνομα χρήστη" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Κατάσταση" + +#: taccountsetform.btcancel.caption +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Άκυρο" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "Εντάξει" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Εμφάνιση κωδικού" + +#: taccountsetform.edpassword.texthint +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Κωδικός" + +#: taccountsetform.edusername.texthint +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Όνομα χρήστη" + +#: taccountsetform.label1.caption +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Ιστότοπος" + +#: taccountsetform.label2.caption +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Όνομα χρήστη" + +#: taccountsetform.label3.caption +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Κωδικός" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Βασική λίστα" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Λίστα κεφαλαίων" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Λίστα αγαπημένων" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Λίστα Manga" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Προσθήκη στα αγαπημένα" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "&Κλείσιμο" + +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Λήψη όλων" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Απαλοιφή" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Πάντα στην κορυφή" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Όριο καταγραφής" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Αντιγραφή" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Άκυρο" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&Εντάξει" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga Downloader" + +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Διαδρομή του προγράμματος (π.χ. C:\\MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Πρόγραμμα:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Ματαίωση ενημέρωσης λίστας" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Προσθήκη στα αγαπημένα" + +#: tmainform.btchecklatestversion.caption +#| msgid "Check for new version" +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Έλεγχος για νεότερη έκδοση" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Απαλοιφή αρχείου καταγραφής" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "Λήψη" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Διαχωρισμός λήψης" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Έλεγχος για νέα κεφάλαια" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Εισαγωγή λίστας" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Φίλτρο" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Επαναφορά τιμών" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Άνοιγμα αρχείου καταγραφής" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Εφαρμογή" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Άμεση ανάγνωση" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Αφαίρεση φίλτρου" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Αφαίρεση φίλτρου" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Ενημέρωση λίστας manga" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Επίσκεψη στο blog μου" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "Προσθήκη στη λίστα λήψης ως διακοπείσα εργασία" + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<καμία>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Αναζήτηση μόνο νέου manga" + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Αυτόματη λήψη μετά το τέλους του ελέγχου" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Αυτόματος έλεγχος για νέα κεφάλαια περιοδικά" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Αυτόματη κατάργηση ολοκληρωμένων mangas από τα Αγαπημένα" + +#: tmainform.cboptionautocheckfavstartup.caption +#| msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" +msgstr "Αυτόματος έλεγχος για νέα κεφάλαια στην έναρξη" + +#: tmainform.cboptionautochecklatestversion.caption +#| msgid "Check for new version " +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Αυτόματος έλεγχος για την τελευταία έκδοση" + +#: tmainform.cboptionchangeunicodecharacter.caption +#| msgid "Change all all character to" +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Replace all unicode character with" +msgstr "Αλλαγή όλων των unicode χαρακτήρων με" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Ενεργοποιήστε το αν έχετε πρόβλημα με χαρακτήρες unicode στη διαδρομή." + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Κεφάλαιο" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Τόμος" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Ενεργοποίηση φόρτωσης εξώφυλλου manga" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Αυτόματη δημιουργία φακέλου κεφαλαίου" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgid "Auto generate folder based on manga's name" +msgstr "Αυτόματη δημιουργία φακέλου βάσει του ονόματος του manga" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Ενεργοποίηση ζωντανής αναζήτησης (αργή σε μεγάλη λίστα)" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Ελαχιστοποίηση στην περιοχή ειδοποιήσεωνMinimize to tray" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "Επιτρέπεται μόνο μια παρουσία του FMD" + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Αφαίρεση ονόματος manga από το κεφάλαιο" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Διαγραφή εργασίας / αγαπημένου" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Λήψη λίστας manga εάν είναι κενή" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "Εμφάνιση εργαλειοθήκης λήψεων" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "Έξοδος του FMD" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "Να μη φορτώνονται πληροφορίες manga κατά την ενημέρωση λίστας (το φίλτρο δεν θα λειτουργήσει!)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "Κατάργηση διπλότυπων τοπικών δεδομένων στην ενημέρωση λίστας manga" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Χρήση διακομιστή μεσολάβησης" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Αναζήτηση σε όλους τους ιστότοπους manga" + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Για περισσότερους ιστότοπους manga, παρακαλώ δείτε στις Επιλογές->Ιστότοποι Manga" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Κανονική έκφραση" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "Εμφάνιση κουτιού φύλαξης" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Ενεργοποίηση καταγραφής" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Action" + +#: tmainform.ckfilteraction.hint +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Ένα έργο που απεικονίζει συνήθως μάχες, βία, χάος και γρήγορο ρυθμό κίνησης." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Adult" + +#: tmainform.ckfilteradult.hint +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "" +"Περιέχει περιεχόμενο που είναι κατάλληλο μόνο για ενήλικες.\n" +" Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν σκηνές παρατεταμένης έντονης \n" +"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Adventure" + +#: tmainform.ckfilteradventure.hint +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "" +"Αν ένας χαρακτήρας στην ιστορία πηγαίνει σε ταξίδι ή κατά μήκος αυτής της γραμμής, \n" +"το πιθανότερο είναι ότι πρόκειται για μια περιπέτεια manga. Ειδάλλως, είναι στο χέρι σας\n" +" να αποφασίσετε γι αυτή την περίπτωση." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Comedy" + +#: tmainform.ckfiltercomedy.hint +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Μια ελαφρά δραματική ιστορία και συχνά χιουμοριστική ή με σατυρικό τόνο και που συνήθως περιέχει ένα ευτυχισμένο τέλος." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Doujinshi" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Διασκεδαστικό με βάση έργο εμπνευσμένο από επίσημα manga/anime." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Drama" + +#: tmainform.ckfilterdrama.hint +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Ένα έργο με στόχο να προκαλέσει μια συναισθηματική αντίδραση, όπως θλίψη ή αναστάτωση." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Ecchi" + +#: tmainform.ckfilterechi.hint +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "" +"Ενδεχομένως η γραμμή μεταξύ Hentai και μη-Hentai, το Ecchi συνήθως αναφέρεται \n" +"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Fantasy" + +#: tmainform.ckfilterfantasy.hint +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Οτιδήποτε περιλαμβάνει, χωρίς να περιορίζεται σε αυτά, μαγεία, φανταστικό κόσμο και παραμύθια." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Gender Bender" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "" +"Κορίτσια που ντύνονται σαν αγόρια και αγόρια που ντύνονται σαν κορίτσια.\n" +"Αγόρια που γίνονται κορίτσια και κορίτσια που γίνονται αγόρια.\n" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Harem" + +#: tmainform.ckfilterharem.hint +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "" +"Μια σειρά που περιλαμβάνει έναν αρσενικό χαρακτήρα και πολλούς γυναικείους \n" +"(συνήθως έλκονται από τον αρσενικό χαρακτήρα). \n" +"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Πορνογραφικό περιεχόμενο με στοιχεία διαστροφής." + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "Historical" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Αναφέρεται σε παλαιούς ή αρχαίους χρόνους." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Horror" + +#: tmainform.ckfilterhorror.hint +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "" +"Ένα οδυνηρό συναίσθημα φόβου, τρόμου και αποστροφής. Ένα ανατριχιαστικό με τρόμο \n" +"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Josei" + +#: tmainform.ckfilterjosei.hint +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "" +"Κυριολεκτικά «Γυναίκα». Απευθύνεται σε γυναίκες 18-30. Ισοδύναμο με το θηλυκό. \n" +"Σε αντίθεση με το Shoujo το ειδύλλιο είναι πιο ρεαλιστικό και λιγότερο εξιδανικευμένο. \n" +"Η αφήγηση είναι πιο σαφής και ώριμη." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Lolicon" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Αναφέρεται στη σεξουαλική έλξη προς νεαρά ή ανήλικα κορίτσια." + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Martial Arts" + +#: tmainform.ckfiltermartialarts.hint +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "" +"Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με πολεμικές τέχνες. \n" +"Οποιεσδήποτε από τις διάφορες τέχνες μάχης ή αυτοάμυνας, όπως αϊκίντο, \n" +"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Mature" + +#: tmainform.ckfiltermature.hint +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "" +"Περιέχει θέμα το οποίο μπορεί να είναι πολύ ακραίο για άτομα κάτω των 17 ετών. \n" +"Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν έντονη βία, έντονη αιματοχυσία, \n" +"σεξουαλικό περιεχόμενο και σκληρή γλώσσα." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Mecha" + +#: tmainform.ckfiltermecha.hint +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "" +"Ένα έργο που περιλαμβάνει και συνήθως επικεντρώνεται σε όλους \n" +"τους τύπους των μεγάλων ρομποτικών μηχανημάτων." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Με μουσικό περιεχόμενο." + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Mystery" + +#: tmainform.ckfiltermystery.hint +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "" +"Συνήθως συμβαίνει κάποιο ανεξήγητο γεγονός και ο κεντρικός \n" +"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Psychological" + +#: tmainform.ckfilterpsychological.hint +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "" +"Συνήθως ασχολείται με τη φιλοσοφία μιας κατάστασης του μυαλού. \n" +"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Romance" + +#: tmainform.ckfilterromance.hint +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "" +"Οποιαδήποτε ιστορία σχετική με αγάπη. Εμείς θεωρούμε την αγάπη μεταξύ άνδρα και γυναίκας. \n" +"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "School Life" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "Είναι ένα μεγάλο φάσμα ιστοριών που σχετίζονται με κάποιο τύπο σχολείου." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Sci-Fi" + +#: tmainform.ckfilterscifi.hint +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "" +"Τα έργα αυτά αφορούν ανατροπές στην τεχνολογία και σε άλλα φαινόμενα σχετικά με την επιστήμη \n" +"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου." + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Seinen" + +#: tmainform.ckfilterseinen.hint +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "" +"Seinen σημαίνει «νέος άνθρωπος». Τα manga και anime που στοχεύουν ειδικά σε νεαρά ενήλικα αρσενικά,\n" +" ηλικίας μεταξύ 18 και 25 ετών. Οι ιστορίες αυτές εμφανίζουν φοιτητές Πανεπιστημίου και άτομα από τον \n" +"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Shotacon" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "Αναφέρεται στη σεξουαλική έλξη προς νεαρά ή ανήλικα αγόρια." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Shoujo" + +#: tmainform.ckfiltershoujo.hint +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "" +"Ένα έργο που προορίζεται και είναι κυρίως γραμμένο για γυναίκες. \n" +"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Shoujo Ai" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "" +"Συχνά συνώνυμη με το Yuri. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" +"Μπορείτε να το πείτε και «Έρωτας κοριτσιών»." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Shounen" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "" +"Ένα έργο που προορίζεται και είναι γραμμένο κυρίως για άνδρες. \n" +"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Shounen Ai" + +#: tmainform.ckfiltershounenai.hint +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "" +"Συχνά συνώνυμη με το Yaoi. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" +"Μπορείτε να το πείτε και «Έρωτας αγοριών»." + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Slice of Life" + +#: tmainform.ckfiltersliceoflife.hint +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "" +"Όπως υποδηλώνει το όνομα, το είδος αυτό αντιπροσωπεύει καθημερινές δοκιμασίες \n" +"από έναν ή περισσότερους χαρακτήρες. Αυτές οι προκλήσεις / εκδηλώσεις θα μπορούσαν \n" +"τεχνικά να συμβούν στην πραγματική ζωή και εμφανίζονται συχνά, αν όχι συνεχώς, σε \n" +"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Smut" + +#: tmainform.ckfiltersmut.hint +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Ασχολείται με σειρές που θεωρούνται βλάσφημες ή προσβλητικές, ιδιαίτερα σε σχέση με σεξουαλικό περιεχόμενο." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Sports" + +#: tmainform.ckfiltersports.hint +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "" +"Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με αθλήματα. \n" +"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Supernatural" + +#: tmainform.ckfiltersupernatural.hint +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "" +"Συνήθως συνεπάγεται εκπληκτικές και ανεξήγητες δυνάμεις ή γεγονότα \n" +"τα οποία αψηφούν τους νόμους της φυσικής." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Tragedy" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Περιέχει γεγονότα που οδήγησαν σε μεγάλη απώλεια και δυστυχία." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Yaoi" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Το έργο αυτό συνήθως περιλαμβάνει στενές σχέσεις μεταξύ ανδρών." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Yuri" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Το έργο αυτό συνήθως περιλαμβάνει στενές σχέσεις μεταξύ γυναικών." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Εισαγωγή προσαρμοσμένων ειδών, χωρισμένα με κόμμα" + +#: tmainform.eddownloadssearch.texthint +#| msgid "Search favorites..." +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Αναζήτηση λήψεων..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Αναζήτηση αγαπημένων..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Καλλιτέχνης" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Δημιουργός" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Φίλτρο" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Τμήμα της περίληψης" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Τίτλος" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Αναζήτηση τίτλου..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgid "Custom rename" +msgstr "Προσαρμ. μετονομασία" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Προεπιλεγμένη διαδρομή λήψης" + +#: tmainform.edoptionexternalparams.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalparams.texthint" +msgid "External program parameters" +msgstr "Ρυθμίσεις εξωτερικού προγράμματος" + +#: tmainform.edoptionexternalpath.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalpath.texthint" +msgid "External program path" +msgstr "Διαδρομή εξωτερικού προγράμματος" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Προσαρμ. μετονομασία" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr " Ηost/IP μεσολαβητή" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Προσαρμ. μετονομασία" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "Κωδικός μεσολαβητή" + +#: tmainform.edoptionport.texthint +msgid "Proxy Port" +msgstr "Θύρα μεσολαβητή" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "Όνομα χρήστη μεσολαβητή" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Αποθήκευση σε" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "Εισαγωγή της URL εδώ" + +#: tmainform.edwebsitessearch.texthint +#| msgid "Search..." +msgctxt "tmainform.edwebsitessearch.texthint" +msgid "Search website..." +msgstr "Αναζήτηση ιστότοπου..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Εμφάνιση παραθύρου επιβεβαίωσης όταν γίνει:" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "Κουτί φύλαξης" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Εξωτερικό πρόγραμμα" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Αγαπημένα" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Ρυθμίσεις διακομιστή μεσολάβησης" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Μετονομασία" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Καθορίστε την προεπιλεγμένη διαδρομή λήψης:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Αδιαφάνεια" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Καλλιτέχνης" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Δημιουργός" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Προσαρμ. είδη" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "" +"Είδη:\n" +" - Τσεκαρισμένο: Συμπερίληψη αυτού του είδους.\n" +" - Μη τσεκαρισμένο: Εξαίρεση αυτού του είδους.\n" +" - Γκρι χρώμα: Χωρίς σημασία.\n" +"\n" +"Προσαρμοσμένα είδη:\n" +" - Διαχωρισμός πολλαπλών ειδών με ','.\n" +" - Αποκλεισμός ενός είδους βάζοντας '!' ή '-' στην αρχή του είδους.\n" +" - Παράδειγμα: Adventure,!Ecchi,Comedy.\n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Κατάσταση" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Περίληψη" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Τίτλος" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Αρχείο καταγραφής:" + +#: tmainform.lbmode.caption +#| msgid "Mode: Show All (0)" +msgid "Mode: Show all (0)" +msgstr "Λειτ.: Εμφάνιση όλων (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgid "Auto check for new chapter every %d minutes" +msgstr "Αυτόματος έλεγχος για νέα κεφάλαια κάθε %d λεπτά" + +#: tmainform.lboptionchaptercustomrename.caption +#| msgid "Chapter folder name:" +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Όνομα κεφαλαίου:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Όνομα ιστότοπου\n" +"%MANGA% : Τίτλος manga\n" +"%CHAPTER% : Τίτλος κεφαλαίου\n" +"%AUTHOR% : Δημιουργός\n" +"%ARTIST% : Καλλιτέχνες\n" +"%NUMBERING% : Αρίθμηση\n" +"\n" +"Σημείωση:\n" +"Το όνομα φακέλου κεφαλαίου πρέπει να έχει τουλάχιστον %CHAPTER% ή %NUMBERING%.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Χρονικό όριο σύνδεσης (δευτ/λεπτα)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Άνοιγμα manga με χρήση εξωτερικού προγράμματος:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Παράμετροι:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "tmainform.lboptionexternalparamshint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Όνομα αρχείου:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Όνομα ιστότοπου\n" +"%MANGA% : Τίτλος Manga\n" +"%CHAPTER% : Τίτλος κεφαλαίου\n" +"%FILENAME% : Όνομα αρχείου\n" +"\n" +"Σημείωση:\n" +"Το όνομα αρχείου πρέπει να έχει τουλάχιστο %FILENAME%\n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Κεντρ. υπολογιστής" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Γλώσσα:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "Μετά την ολοκλήρωση της λήψης:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Όνομα φακέλου manga:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Όνομα ιστότοπου\n" +"%MANGA% : Τίτλος manga\n" +"%AUTHOR% : Δημιουργός\n" +"%ARTIST% : Καλλιτέχνης\n" +"\n" +"Σημείωση:\n" +"Το όνομα φακέλου Manga πρέπει να έχει τουλάχιστον %MANGA%.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Αριθμός ταυτόχρονων εργασιών λήψης (Μέγ.: 8)" + +#: tmainform.lboptionmaxretry.caption +#| msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Αριθμός επαναλήψεων αν οι εργασίες έχουν προβλήματα λήψης (-1 = συνεχής επανάληψη)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Αριθμός ταυτόχρονα ληφθέντων αρχείων ανά εργασία (Μέγ: 32)" + +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "Νέα manga με βάση τον χρόνο ενημέρωσης (ηµέρες)" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Κωδικός" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "Επίπεδο συμπίεσης PDF" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (χωρίς απώλειες). Χαμηλότερα = DCTEncode (με απώλειες)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Θύρα" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Τύπος" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Μετονομασία ψηφίων" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Όνομα χρήστη" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Αποθήκευση σε:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Διαγραφή" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Αντιγραφή" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Αποκοπή" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Επικόλληση" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Επικόλληση και μετάβαση" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Επιλογή όλων" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Αναίρεση" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Ματαίωση" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Σήμανση όλων" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Σήμανση επιλεγμένων" + +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Φίλτρο" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "Απόκρυψη ληφθέντων κεφαλαίων" + +#: tmainform.michapterlisthighlight.caption +#| msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" +msgstr "Επισήμανση ληφθέντων κεφαλαίων" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Αποσήμανση όλων" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Αποσήμανση επιλεγμένων" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Διαγραφή" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Διαγραφή όλων των ολοκληρωμένων εργασιών" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Εργασία μόνο" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Εργασία + Δεδομένα" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Εργασία + Δεδομένα + Αγαπημένο" + +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "Απενεργοποίηση" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "Ενεργοποίηση" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Συγχώνευση ολοκληρωμένων εργασιών" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Άνοιγμα φακέλου" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Άνοιγμα..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Συνέχιση" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Διακοπή" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Προβολή πληροφοριών manga" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Αλλαγή \"Τρέχοντος κεφαλαίου\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Αλλαγή \"Αποθήκευσης σε\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Έλεγχος για νέα κεφάλαια" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Διαγραφή" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Λήψη όλων" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Άνοιγμα φακέλου" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Άνοιγμα..." + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Διακοπή ελέγχου για νέα κεφάλαια" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Προβολή πληροφοριών manga" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Επισήμανση νέου manga" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Προσθήκη στα αγαπημένα" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Διαγραφή" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Λήψη όλων" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Προβολή πρηροφοριών manga" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "Μετά την ολοκλήρωση της λήψης" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Έξοδος" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Έξοδος" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Αδρανοποίηση υπολογιστή" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Καμία ενέργεια" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Τερματισμός υπολογιστή" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Επαναφορά" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Συνέχιση όλων" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Εμφάνιση κουτιού φύλαξης" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Διακοπή όλων" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Λήψη όλων των λιστών από τον διακομιστή ταυτόχρονα" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Σήμανση όλων" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Ακαθόριστα όλα" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Αποσήμανση όλων" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Λήψη όλων των λιστών ταυτόχρονα" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Λήψη λίστας manga από τον διακομιστή" + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Ενημέρωση λίστας manga" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Όλα τα είδη που έχουν σημανθεί" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Ένα από τα είδη που έχουν σημανθεί" + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Λειτουργία" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "Αποθήκευση ληφθέντων κεφαλαίων ως" + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (χωρίς απώλειες). Χαμηλότερα = DCTEncode (με απώλειες)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Διαγραφή όλων των ολοκληρωμένων εργασιών" + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Συνέχιση όλων" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Διακοπή όλων" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Σύμπτυξη όλων" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Ανάπτυξη όλων" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "Περί" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "Περί FMD" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Λογαριασμοί" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Ιστορικό εκδόσεων" + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Συνδέσεις" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Πρασαρμογή χρωμάτων" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "Διάλογοι" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr "Λήψεις" + +#: tmainform.tsdownloadfilter.caption +msgid ">>" +msgstr ">>" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Αγαπημένα" + +#: tmainform.tsfilter.caption +msgctxt "tmainform.tsfilter.caption" +msgid "Filter" +msgstr "Φίλτρο" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "Γενικές" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Πληροφορίες manga" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Αρχείο καταγραφής" + +#: tmainform.tsmangalist.caption +msgid "Manga List" +msgstr "Λίστα Manga" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Διάφορα" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Επιλογές" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Αποθήκευση" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Ενημερώσεις" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Προβολή" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Προηγμένες" + +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Επιλογές" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Ιστότοποι" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" +msgid "Websites" +msgstr "Ιστότοποι" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Manga" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Κατάσταση" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "Εξέλιξη" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Ρυθμός μεταφοράς" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Αποθήκευση σε" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Προστέθηκε" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Τίτλος" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Τρέχον κεφάλαιο" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Ιστότοπος" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Αποθήκευση σε" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "Ά&κυρο" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "&Λήψη" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "&Προσθήκη στην ουρά" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "&Ματαίωση" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "&Τώρα" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "&Αργότερα" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "&Ενημέρωση" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "" +"Βρέθηκε νέα έκδοση! Θέλετε να γίνει ενημέρωση τώρα;\n" +"Το FMD θα κλείσει για να ολοκληρωθεί η ενημέρωση.\n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Προσθήκη" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Επεξεργασία" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Διαγραφή" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Αριθμός σελίδας καταλόγου" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Λήψεις" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Μέγιστος αριθμός νημάτων ανά έργο" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Αριθμός νημάτων" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Ενημέρωση λίστας" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "Παράγοντας χρήστη" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Τιμή" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Τιμή" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Τιμή" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Ιστότοπος" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "Παράγοντας χρήστη" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Επιλέξτε έναν ιστότοπο" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Συμπίεση..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Απενεργ/μένο" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "Λήψη" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Απέτυχε" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Δεν ήταν δυνατή η δημιουργία καταλόγου!" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Απέτυχε. Δοκιμάστε να επαναλάβετε αυτή την εργασία!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Ολοκληρωμένο" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Προετοιμασία" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Σταματημένο" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Αναμονή..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "&Προσθήκη στην ουρά" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "Ά&κυρο" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Έλεγχος για νέα κεφάλαια" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "&Λήψη" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "&Κατάργηση" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "Βρέθηκαν %d ολοκληρωμένα manga" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "Ό έλεγχος αγαπημένων εκτελείται ήδη!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d manga έχουν νέα κεφάλαια." + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "Το %s <%s> έχει %d νέο(α) κεφάλαιο(α)." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "Το ολοκληρωμένο manga θα αφαιρεθεί:" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "Βρέθηκαν %d νέα κεφάλαια από %d manga:" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Φόρτωση: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Έλεγχος για νέα έκδοση" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "Εγκατεστημένη έκδοση" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Τελευταία έκδοση" + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Βρέθηκε νέα έκδοση!" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "Το %s έχει %d νέα manga" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Λήψη καταλόγου" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Λήψη πληροφοριών" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Λήψη λίστας για" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Ευρετηρίαση νέων τίτλων" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Αναζήτηση για νέους τίτλους" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Αναζήτηση για νέους τίτλους από άλλο κατάλογο" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Προετοιμασία" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Κατάργηση διπλότυπων από τα τρέχοντα δεδομένα" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Κατάργηση διπλότυπων από τα τοπικά δεδομένα" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Κατάργηση διπλότυπων από τους νέους τίτλους" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Αποθήκευση δεδομένων" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Συγχρονισμός δεδομένων" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Ενημέρωση λίστας" + diff --git a/mangadownloader/languages/updater.el_GR.po b/mangadownloader/languages/updater.el_GR.po new file mode 100644 index 000000000..2761840df --- /dev/null +++ b/mangadownloader/languages/updater.el_GR.po @@ -0,0 +1,109 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: Free Manga Downloader 0.9.85\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: geogeo.gr <geogeo.gr@gmail.com>\n" +"Language-Team: Greek <www.geogeo.gr>\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en\n" +"X-Generator: Poedit 1.8.8\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Language: Greek\n" +"X-Poedit-Country: GREECE\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Μέγεθος αρχείου" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Παρακαλώ περιμένετε..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Ρυθμός μεταφοράς" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Βοήθεια" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "Δεν είναι δυνατή η εξαγωγή του αρχείου επειδή το 7za.exe δεν βρέθηκε!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "Παρουσιάστηκε ένα σφάλμα κατά την προσπάθεια λήψης του αρχείου." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "Λήψη [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Σφάλμα κατά την αποθήκευση του αρχείου. Ελέγξτε το πρόγραμμά σας για την προστασία από ιούς!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Η λήψη του αρχείου απέτυχε!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Η φόρτωση της σελίδας απέτυχε!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Το αρχείο δεν βρέθηκε!" + +#: umain.rs_finished +msgid "Finished." +msgstr "Ολοκληρώθηκε." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "Μη έγκυρη URL!" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Φόρτωση σελίδας..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Ανακατεύθυνση..." + +#: umain.rs_response +msgid "Response" +msgstr "Απόκριση" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "Επανάληψη λήψης [%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Επανάληψη φόρτωσης σελίδας [%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Αποθήκευση αρχείου... " + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Σφάλμα απόκρισης διακομιστή!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(άγνωστο)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Αποσυμπίεση αρχείων [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Αναμονή κύριας εφαρμογής για κλείσιμο..." + From 379cb9b0c50f8dcb0d7f4da70112b79d6b369c79 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Feb 2017 10:46:52 +0800 Subject: [PATCH 1516/2794] fixed mangainfo styling --- changelog.txt | 5 +++ mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 19 ++++++----- mangadownloader/languages/fmd.el_GR.po | 46 ++++++++++++++------------ 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/changelog.txt b/changelog.txt index d908cf432..d32de4ebd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.90.0 (--2017) +[+] Added Portuguese (Brazil) translation by Havokdan +[+] Added Greek translation by geogeo_gr +Full changes: https://github.com/riderkick/FMD/compare/0.9.88.0...0.9.89.0 + 0.9.89.0 (06-02-2017) [*] E-Hentai: fixed root url [*] Split MangeEden_IT and PervEden_IT diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f220c9bed..0a60d6f77 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,6 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True + LCLVersion = '1.7' Visible = False object sbUpdateList: TStatusBar Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9665be883..3c79666a2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4354,16 +4354,19 @@ procedure TMainForm.AddTextToInfo(const ATitle, AValue: String); s := Trim(StringBreaks(s)); with rmInformation do begin - ReadOnly := False; if Lines.Count > 0 then Lines.Add(''); p := SelStart; GetTextAttributes(p, fp); + fp.Style += [fsBold, fsUnderline]; + Inc(fp.Size); + SetTextAttributes(p, 0, fp); Lines.Add(ATitle); + p := SelStart; + fp.Style -= [fsBold, fsUnderline]; + Dec(fp.Size); + SetTextAttributes(p, 0, fp); Lines.Add(s); - fp.Style := [fsBold, fsUnderline]; - Inc(fp.Size); - SetTextAttributes(p, Length(ATitle), fp); end; end; @@ -4454,10 +4457,10 @@ procedure TMainForm.ShowInformation(const title, website, link: String); else edURL.Text := mangaInfo.url; - AddTextToInfo(RS_InfoTitle, mangaInfo.title + LineEnding); - AddTextToInfo(RS_InfoAuthors, mangaInfo.authors + LineEnding); - AddTextToInfo(RS_InfoArtists, mangaInfo.artists + LineEnding); - AddTextToInfo(RS_InfoGenres, mangaInfo.genres + LineEnding); + AddTextToInfo(RS_InfoTitle, mangaInfo.title); + AddTextToInfo(RS_InfoAuthors, mangaInfo.authors); + AddTextToInfo(RS_InfoArtists, mangaInfo.artists); + AddTextToInfo(RS_InfoGenres, mangaInfo.genres); i := StrToIntDef(mangaInfo.status, -1); if (i > -1) and (i < cbFilterStatus.Items.Count) then AddTextToInfo(RS_InfoStatus, cbFilterStatus.Items[i]); diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index cd43988b8..a680e6102 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -608,6 +608,10 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Αυτόματος έλεγχος για την τελευταία έκδοση" +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "" + #: tmainform.cboptionchangeunicodecharacter.caption #| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" @@ -725,7 +729,7 @@ msgid "Contains content that is suitable only for adults. Titles in this categor msgstr "" "Περιέχει περιεχόμενο που είναι κατάλληλο μόνο για ενήλικες.\n" " Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν σκηνές παρατεταμένης έντονης \n" -"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό." +"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό.\n" #: tmainform.ckfilteradventure.caption msgid "Adventure" @@ -736,7 +740,7 @@ msgid "If a character in the story goes on a trip or along that line, your best msgstr "" "Αν ένας χαρακτήρας στην ιστορία πηγαίνει σε ταξίδι ή κατά μήκος αυτής της γραμμής, \n" "το πιθανότερο είναι ότι πρόκειται για μια περιπέτεια manga. Ειδάλλως, είναι στο χέρι σας\n" -" να αποφασίσετε γι αυτή την περίπτωση." +" να αποφασίσετε γι αυτή την περίπτωση.\n" #: tmainform.ckfiltercomedy.caption msgid "Comedy" @@ -770,7 +774,7 @@ msgstr "Ecchi" msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." msgstr "" "Ενδεχομένως η γραμμή μεταξύ Hentai και μη-Hentai, το Ecchi συνήθως αναφέρεται \n" -"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών." +"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών.\n" #: tmainform.ckfilterfantasy.caption msgid "Fantasy" @@ -801,7 +805,7 @@ msgid "A series involving one male character and many female characters (usually msgstr "" "Μια σειρά που περιλαμβάνει έναν αρσενικό χαρακτήρα και πολλούς γυναικείους \n" "(συνήθως έλκονται από τον αρσενικό χαρακτήρα). \n" -"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται." +"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται.\n" #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -829,7 +833,7 @@ msgstr "Horror" msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." msgstr "" "Ένα οδυνηρό συναίσθημα φόβου, τρόμου και αποστροφής. Ένα ανατριχιαστικό με τρόμο \n" -"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό." +"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό.\n" #: tmainform.ckfilterjosei.caption msgid "Josei" @@ -840,7 +844,7 @@ msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Un msgstr "" "Κυριολεκτικά «Γυναίκα». Απευθύνεται σε γυναίκες 18-30. Ισοδύναμο με το θηλυκό. \n" "Σε αντίθεση με το Shoujo το ειδύλλιο είναι πιο ρεαλιστικό και λιγότερο εξιδανικευμένο. \n" -"Η αφήγηση είναι πιο σαφής και ώριμη." +"Η αφήγηση είναι πιο σαφής και ώριμη.\n" #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -859,7 +863,7 @@ msgid "As the name suggests, anything martial arts related. Any of several arts msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με πολεμικές τέχνες. \n" "Οποιεσδήποτε από τις διάφορες τέχνες μάχης ή αυτοάμυνας, όπως αϊκίντο, \n" -"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά." +"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά.\n" #: tmainform.ckfiltermature.caption msgid "Mature" @@ -870,7 +874,7 @@ msgid "Contains subject matter which may be too extreme for people under the age msgstr "" "Περιέχει θέμα το οποίο μπορεί να είναι πολύ ακραίο για άτομα κάτω των 17 ετών. \n" "Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν έντονη βία, έντονη αιματοχυσία, \n" -"σεξουαλικό περιεχόμενο και σκληρή γλώσσα." +"σεξουαλικό περιεχόμενο και σκληρή γλώσσα.\n" #: tmainform.ckfiltermecha.caption msgid "Mecha" @@ -880,7 +884,7 @@ msgstr "Mecha" msgid "A work involving and usually concentrating on all types of large robotic machines." msgstr "" "Ένα έργο που περιλαμβάνει και συνήθως επικεντρώνεται σε όλους \n" -"τους τύπους των μεγάλων ρομποτικών μηχανημάτων." +"τους τύπους των μεγάλων ρομποτικών μηχανημάτων.\n" #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -900,7 +904,7 @@ msgstr "Mystery" msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." msgstr "" "Συνήθως συμβαίνει κάποιο ανεξήγητο γεγονός και ο κεντρικός \n" -"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε." +"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε.\n" #: tmainform.ckfilterpsychological.caption msgid "Psychological" @@ -910,7 +914,7 @@ msgstr "Psychological" msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." msgstr "" "Συνήθως ασχολείται με τη φιλοσοφία μιας κατάστασης του μυαλού. \n" -"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση." +"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση.\n" #: tmainform.ckfilterromance.caption msgid "Romance" @@ -920,7 +924,7 @@ msgstr "Romance" msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." msgstr "" "Οποιαδήποτε ιστορία σχετική με αγάπη. Εμείς θεωρούμε την αγάπη μεταξύ άνδρα και γυναίκας. \n" -"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι." +"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι.\n" #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -938,7 +942,7 @@ msgstr "Sci-Fi" msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." msgstr "" "Τα έργα αυτά αφορούν ανατροπές στην τεχνολογία και σε άλλα φαινόμενα σχετικά με την επιστήμη \n" -"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου." +"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου.\n" #: tmainform.ckfilterseinen.caption msgid "Seinen" @@ -949,7 +953,7 @@ msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically msgstr "" "Seinen σημαίνει «νέος άνθρωπος». Τα manga και anime που στοχεύουν ειδικά σε νεαρά ενήλικα αρσενικά,\n" " ηλικίας μεταξύ 18 και 25 ετών. Οι ιστορίες αυτές εμφανίζουν φοιτητές Πανεπιστημίου και άτομα από τον \n" -"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής." +"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής.\n" #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -967,7 +971,7 @@ msgstr "Shoujo" msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." msgstr "" "Ένα έργο που προορίζεται και είναι κυρίως γραμμένο για γυναίκες. \n" -"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα." +"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα.\n" #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -978,7 +982,7 @@ msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." msgstr "" "Συχνά συνώνυμη με το Yuri. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας κοριτσιών»." +"Μπορείτε να το πείτε και «Έρωτας κοριτσιών».\n" #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -989,7 +993,7 @@ msgctxt "tmainform.ckfiltershounen.hint" msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." msgstr "" "Ένα έργο που προορίζεται και είναι γραμμένο κυρίως για άνδρες. \n" -"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία." +"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία.\n" #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" @@ -999,7 +1003,7 @@ msgstr "Shounen Ai" msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" msgstr "" "Συχνά συνώνυμη με το Yaoi. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας αγοριών»." +"Μπορείτε να το πείτε και «Έρωτας αγοριών».\n" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" @@ -1011,7 +1015,7 @@ msgstr "" "Όπως υποδηλώνει το όνομα, το είδος αυτό αντιπροσωπεύει καθημερινές δοκιμασίες \n" "από έναν ή περισσότερους χαρακτήρες. Αυτές οι προκλήσεις / εκδηλώσεις θα μπορούσαν \n" "τεχνικά να συμβούν στην πραγματική ζωή και εμφανίζονται συχνά, αν όχι συνεχώς, σε \n" -"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές." +"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές.\n" #: tmainform.ckfiltersmut.caption msgid "Smut" @@ -1029,7 +1033,7 @@ msgstr "Sports" msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με αθλήματα. \n" -"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα." +"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα.\n" #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" @@ -1039,7 +1043,7 @@ msgstr "Supernatural" msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." msgstr "" "Συνήθως συνεπάγεται εκπληκτικές και ανεξήγητες δυνάμεις ή γεγονότα \n" -"τα οποία αψηφούν τους νόμους της φυσικής." +"τα οποία αψηφούν τους νόμους της φυσικής.\n" #: tmainform.ckfiltertragedy.caption msgid "Tragedy" From 8e1f53d7d6e4e3ec29f134b8e4dcfd62224b1cdf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Feb 2017 20:52:35 +0800 Subject: [PATCH 1517/2794] update greek translation by geogeo_gr #460 --- mangadownloader/languages/fmd.el_GR.po | 46 ++++++++++++-------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index a680e6102..cd43988b8 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -608,10 +608,6 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Αυτόματος έλεγχος για την τελευταία έκδοση" -#: tmainform.cboptionautoopenfavstartup.caption -msgid "Open Favorites at startup" -msgstr "" - #: tmainform.cboptionchangeunicodecharacter.caption #| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" @@ -729,7 +725,7 @@ msgid "Contains content that is suitable only for adults. Titles in this categor msgstr "" "Περιέχει περιεχόμενο που είναι κατάλληλο μόνο για ενήλικες.\n" " Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν σκηνές παρατεταμένης έντονης \n" -"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό.\n" +"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό." #: tmainform.ckfilteradventure.caption msgid "Adventure" @@ -740,7 +736,7 @@ msgid "If a character in the story goes on a trip or along that line, your best msgstr "" "Αν ένας χαρακτήρας στην ιστορία πηγαίνει σε ταξίδι ή κατά μήκος αυτής της γραμμής, \n" "το πιθανότερο είναι ότι πρόκειται για μια περιπέτεια manga. Ειδάλλως, είναι στο χέρι σας\n" -" να αποφασίσετε γι αυτή την περίπτωση.\n" +" να αποφασίσετε γι αυτή την περίπτωση." #: tmainform.ckfiltercomedy.caption msgid "Comedy" @@ -774,7 +770,7 @@ msgstr "Ecchi" msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." msgstr "" "Ενδεχομένως η γραμμή μεταξύ Hentai και μη-Hentai, το Ecchi συνήθως αναφέρεται \n" -"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών.\n" +"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών." #: tmainform.ckfilterfantasy.caption msgid "Fantasy" @@ -805,7 +801,7 @@ msgid "A series involving one male character and many female characters (usually msgstr "" "Μια σειρά που περιλαμβάνει έναν αρσενικό χαρακτήρα και πολλούς γυναικείους \n" "(συνήθως έλκονται από τον αρσενικό χαρακτήρα). \n" -"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται.\n" +"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται." #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -833,7 +829,7 @@ msgstr "Horror" msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." msgstr "" "Ένα οδυνηρό συναίσθημα φόβου, τρόμου και αποστροφής. Ένα ανατριχιαστικό με τρόμο \n" -"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό.\n" +"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό." #: tmainform.ckfilterjosei.caption msgid "Josei" @@ -844,7 +840,7 @@ msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Un msgstr "" "Κυριολεκτικά «Γυναίκα». Απευθύνεται σε γυναίκες 18-30. Ισοδύναμο με το θηλυκό. \n" "Σε αντίθεση με το Shoujo το ειδύλλιο είναι πιο ρεαλιστικό και λιγότερο εξιδανικευμένο. \n" -"Η αφήγηση είναι πιο σαφής και ώριμη.\n" +"Η αφήγηση είναι πιο σαφής και ώριμη." #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -863,7 +859,7 @@ msgid "As the name suggests, anything martial arts related. Any of several arts msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με πολεμικές τέχνες. \n" "Οποιεσδήποτε από τις διάφορες τέχνες μάχης ή αυτοάμυνας, όπως αϊκίντο, \n" -"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά.\n" +"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά." #: tmainform.ckfiltermature.caption msgid "Mature" @@ -874,7 +870,7 @@ msgid "Contains subject matter which may be too extreme for people under the age msgstr "" "Περιέχει θέμα το οποίο μπορεί να είναι πολύ ακραίο για άτομα κάτω των 17 ετών. \n" "Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν έντονη βία, έντονη αιματοχυσία, \n" -"σεξουαλικό περιεχόμενο και σκληρή γλώσσα.\n" +"σεξουαλικό περιεχόμενο και σκληρή γλώσσα." #: tmainform.ckfiltermecha.caption msgid "Mecha" @@ -884,7 +880,7 @@ msgstr "Mecha" msgid "A work involving and usually concentrating on all types of large robotic machines." msgstr "" "Ένα έργο που περιλαμβάνει και συνήθως επικεντρώνεται σε όλους \n" -"τους τύπους των μεγάλων ρομποτικών μηχανημάτων.\n" +"τους τύπους των μεγάλων ρομποτικών μηχανημάτων." #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -904,7 +900,7 @@ msgstr "Mystery" msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." msgstr "" "Συνήθως συμβαίνει κάποιο ανεξήγητο γεγονός και ο κεντρικός \n" -"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε.\n" +"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε." #: tmainform.ckfilterpsychological.caption msgid "Psychological" @@ -914,7 +910,7 @@ msgstr "Psychological" msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." msgstr "" "Συνήθως ασχολείται με τη φιλοσοφία μιας κατάστασης του μυαλού. \n" -"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση.\n" +"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση." #: tmainform.ckfilterromance.caption msgid "Romance" @@ -924,7 +920,7 @@ msgstr "Romance" msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." msgstr "" "Οποιαδήποτε ιστορία σχετική με αγάπη. Εμείς θεωρούμε την αγάπη μεταξύ άνδρα και γυναίκας. \n" -"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι.\n" +"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι." #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -942,7 +938,7 @@ msgstr "Sci-Fi" msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." msgstr "" "Τα έργα αυτά αφορούν ανατροπές στην τεχνολογία και σε άλλα φαινόμενα σχετικά με την επιστήμη \n" -"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου.\n" +"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου." #: tmainform.ckfilterseinen.caption msgid "Seinen" @@ -953,7 +949,7 @@ msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically msgstr "" "Seinen σημαίνει «νέος άνθρωπος». Τα manga και anime που στοχεύουν ειδικά σε νεαρά ενήλικα αρσενικά,\n" " ηλικίας μεταξύ 18 και 25 ετών. Οι ιστορίες αυτές εμφανίζουν φοιτητές Πανεπιστημίου και άτομα από τον \n" -"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής.\n" +"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής." #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -971,7 +967,7 @@ msgstr "Shoujo" msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." msgstr "" "Ένα έργο που προορίζεται και είναι κυρίως γραμμένο για γυναίκες. \n" -"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα.\n" +"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα." #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -982,7 +978,7 @@ msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." msgstr "" "Συχνά συνώνυμη με το Yuri. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας κοριτσιών».\n" +"Μπορείτε να το πείτε και «Έρωτας κοριτσιών»." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -993,7 +989,7 @@ msgctxt "tmainform.ckfiltershounen.hint" msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." msgstr "" "Ένα έργο που προορίζεται και είναι γραμμένο κυρίως για άνδρες. \n" -"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία.\n" +"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία." #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" @@ -1003,7 +999,7 @@ msgstr "Shounen Ai" msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" msgstr "" "Συχνά συνώνυμη με το Yaoi. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας αγοριών».\n" +"Μπορείτε να το πείτε και «Έρωτας αγοριών»." #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" @@ -1015,7 +1011,7 @@ msgstr "" "Όπως υποδηλώνει το όνομα, το είδος αυτό αντιπροσωπεύει καθημερινές δοκιμασίες \n" "από έναν ή περισσότερους χαρακτήρες. Αυτές οι προκλήσεις / εκδηλώσεις θα μπορούσαν \n" "τεχνικά να συμβούν στην πραγματική ζωή και εμφανίζονται συχνά, αν όχι συνεχώς, σε \n" -"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές.\n" +"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές." #: tmainform.ckfiltersmut.caption msgid "Smut" @@ -1033,7 +1029,7 @@ msgstr "Sports" msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με αθλήματα. \n" -"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα.\n" +"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα." #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" @@ -1043,7 +1039,7 @@ msgstr "Supernatural" msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." msgstr "" "Συνήθως συνεπάγεται εκπληκτικές και ανεξήγητες δυνάμεις ή γεγονότα \n" -"τα οποία αψηφούν τους νόμους της φυσικής.\n" +"τα οποία αψηφούν τους νόμους της φυσικής." #: tmainform.ckfiltertragedy.caption msgid "Tragedy" From f9a8eda04a30f957167419a05213e14ed16c4647 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Feb 2017 03:41:46 +0800 Subject: [PATCH 1518/2794] update drop box icon to a better quality --- mangadownloader/forms/frmDropTarget.lfm | 527 ++++++++++++++++++++---- mangadownloader/languages/fmd.el_GR.po | 46 ++- 2 files changed, 477 insertions(+), 96 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.lfm b/mangadownloader/forms/frmDropTarget.lfm index fa10ef4d9..c84a7f8ff 100644 --- a/mangadownloader/forms/frmDropTarget.lfm +++ b/mangadownloader/forms/frmDropTarget.lfm @@ -18,7 +18,6 @@ object FormDropTarget: TFormDropTarget OnMouseMove = FormMouseMove OnMouseUp = FormMouseUp OnShow = FormShow - LCLVersion = '1.7' Visible = False object shBorder: TShape Left = 0 @@ -43,78 +42,456 @@ object FormDropTarget: TFormDropTarget OnMouseMove = FormMouseMove OnMouseUp = FormMouseUp Picture.Data = { - 1754506F727461626C654E6574776F726B47726170686963E408000089504E47 - 0D0A1A0A0000000D49484452000000660000006608030000000E011450000000 - 72504C54454A4B4FFFFFFFFCFCFE47484C44454945464B4C4D5150515557585C - F7F7F8F3F3F4707174525357E0E0E1FAFAFB4142465D5E62E6E6E7D3D3D5AFAF - B1EEEEEF6364676E6F72C4C4C6BCBDBF88898CCCCCCD8283868E8E9168696DDB - DCDC7A7B7E9A9B9EA7A7AAB7B8BA9D9EA1ACACAE94949701732EBB0000082D49 - 4441546881BD9AD902AB280C4045D0D65DEBAE55ABD6FFFFC581964D40DBDEB9 - 33796C9563421242C002FF8B58BF3C1CFB45168D44A2ACF0E3FF0253DC9A796B - A76A28CBB42C8760BA3FF27AF4FF26C68E9676B85E2C881064821CE88669F0A8 - 8BBF83F1C7B54C123CAAA50B844902A725F3FE2D265AFA3031118420946EDD07 - 9DCE31D15C59E81CF2520A857D730A3AC3146B697D6650EB5D82E68F30457E64 - 2DF3AF2899BAC3393AC2C4DD04D5E1B0A3610BBA97CBC5C513A23B050A1FD16F - 187FBE3A0A2281E9749F97A6EEBAAE6EF2B5AD429420E5A1A0FE0533EE55C16A - 5CFBFC5678318F7C3BF6FCAC5E0317ED5C0486AB31624D9878B9CA5F89DC61AB - 5F2FDB7B213F45799FCAD6834960329C01E33D5DE93D749996C8D61002E5DDD6 - 41D63D19BA6F30FE2A51209A483651745041D133959C1296BA6B6B98E22E1C16 - 3A65E329102FBA65B1A21B00D923147686E1F209534C89783C9D554DBC7C8089 - 1560B80A1A5B610498E4E718FF9E0855A69BF2D9D8A02F1746EEACCD15F0F314 - 49FAC427186F15AAC02DD3C65A2E90FED9E91CFB16084E5A1F6362E163F0BAA8 - 86B14136B17192DE5331E4FF3B0F2227BD1D62164E4165A7FB30B85DF9579491 - C1C5412CBC14A5D90166E4A3A0E1661AA5BB704C6A7A0073E6903D92B4BE11E3 - 739398295F606C39B6DDDC848967115F07634898ABF911ACCF93A5049876064C - C74C06AFBA1B7D8DC111F460B91D4D858629268779F27234C237181C402DE3C0 - 59C3E4DC1537CD934D98038DC963514527198699822998C9D0A44725C784DF60 - 6C50B3C1924DC1ACC9B90BFD82B1ED1989C7644C54D2019C393EFE4A09139E61 - 40C1CDB679328639332C8B1363C898FA4C1B50330CCD396F4C54B19969CE3E52 - 241BEB1C63C72DE5388F586016EEE9475EF62306DC529ACBD38863FCFECD8697 - 73537C8FB1FD8DD927E79891DA9C84ED5FC270A78615C7306F768FE25FC75CCE - 26913CCB2C642523C5D8D49BE1605A44644CFA35C6060DC3CC1413D11FD0761C - 33AF37470973AE38899D2B9B89F88D59A8CDD0277B4B980FF6254F33BF22BE46 - 30D4C7E1D5570B3D4578AE7861F6A26398D5B07D09A618A8763DD831FC2C7A49 - C6A4E824CCB378892FC48B773090315F5B5F18E63FB886931EF2EA7B3510A95E - 1210A92E1697A17F4BFB923B966DAD77E6F0E80AE6F43EC134F465B8CBCD6B48 - 36E70E9464B76F227B2A220EE202C35E8EBB78A59311640443D3264CA567C0F3 - C3F6D92878D7218FD1B0816F18136FCCF1448507B2F40F28C4404F09C366E3D2 - 618C4F1D0DDD45D480DAFD238A05A5740522EA5BD68231052DCF90B4A081E5CF - 94D925125C0BBF7D003D3126A36B8D5CD030B3FE3B4C410314ADB1255493B214 - 88AE7F3837728EF7EF14B361CC4863CEDDA51AB1CFF94D9BA71C38CCB9EE9EC0 - 5CE4228287F06F820639703C5A7FA29660DEBE0B7718EC6B97DF39D0DD45B8F7 - 8012C6A48DB4CAFE8259E511CC98FDDCD8A2DAF95A1CA560F5366A343237264F - 7B3BF58F18B51215814F3C2D0BA86AB9BD17B0FDE66D7056DE97025FCA02ABB2 - 44836C4067C32A8202A52CE20A38F92BA771B753D5697EF036E8AA55B598F586 - 6468EA0F4EE52B181E5F5F29B3AA6FB3929B94F578BDC9DFD998EC79D407B3E9 - 5B0EECF54A92EECC6039124CCD6A4EBDB091F6671F28A9BE118937BA7A4EAFD5 - 939545C96AA889BEF436A46F8B805FBD271DDE5FB5801F501F080C5550F195B7 - A1CAD72D31B2A5F1F9AED31EAC8436D4B6621F7F66B2D0B093047342FFECDE98 - 9A559DB9C16A5253EA1833EBEFD936ED47C1217B630AA67A6FD844496DA74393 - 9936DF20A236432DDB784CACDA3537843E74F0CDBB6AC076D349C3300BDB90AE - 862E197EC1396658AF8AC2F052C6FCEC52300CABCACC1B1C9EF50E2881EE6536 - 6924D2BF7BBE5BF336A68EE9C3CEBD0D5E8C962E58FE80B5D849B30D3F4C8D9D - 14D10333608C5E061AE60041213045CF9A2C0FA33A457F343DA65CB68BEA45EE - 72F05D41381A39B7D06C36532EB34568E2B41FC99882F576516B9C50FE9E2289 - D964A26B3AEF3B500D1BC655D7EAF78BBED1DB5060EA8AF0AA16AF01D91EC342 - F4B0277B2B75B31DF40885C7246C87CA31BCBB8402B3B7E586BD88D964BC6B87 - 064FC578A2137A574F34F6961026337B19DF6F439777F045E7360A78B37B3572 - 2265253D4881BC6567C187A763F8628DBF6236CE6CBEC718D70D9071A5C9E26C - C0C4AC4384A3E769D08757916C0E8DCB462BB7434D18BC5A738EFB34F52D646F - 33AF983C9D602F7B02334694D316840F53982E52FFE1A9FF2D3AD038FE5B7084 - 0152B7C469F54501787C1367C86520AE4B714ED417C718D088DC85AADAD6468A - E88928D24F2B40318BF5024EFBD34FF5086F11DD0D749DF52FAED3044194849D - FA07187BB198A37204A718900B7D201A6AEDEC317B4ED5342B89021055A413C9 - 523DC9D58F579754AC2D08B5375F3D5DB53DE55017D84533C8E7ABD3A80EAA63 - E23A95C203A55BED1D1E15BFB9D932B9D22B4EAF9F4A9B8EBE6FA9B4B840787D - 5FA03023801DCD959C8560D21AAE5B180FF2B3563EFC7E1DE33799F73E30E5E3 - 93C37C7F9C03777792EF5C9FA611CDF705E41359469AD6E6462E0B7944FC221B - BB7CABDCFDC5040827C3F1FA210607AA7AC70293ACEB30F5F7EDF1786CED1494 - 21444A2182DC47661EEEF0CA4831EB3746207410228D49E7757D48FD37A9EAA3 - 3B23271760B2EDAA0D752C8E552EC797874EAFF3745B6ABC93A40BB2AAF9C05E - 9F31C0BB3DD2CFB7862082C17274F5E51B0C0ED628AF92E41805718273FB8FD7 - BABEB93816CD537A2133AF12F02FE1D09EDF7EFA1E43746AD63E482F96D4DB76 - C372BA3FBBB319F91543C4CF6EDDF25CB73BE9D56F73DE7463F6ED65BBDFEE0E - 6289E35716887FB93888E51F9AD58D5F41B024670000000049454E44AE426082 + 1754506F727461626C654E6574776F726B477261706869631138000089504E47 + 0D0A1A0A0000000D4948445200000320000003200803000000ECAEF65A000000 + 0467414D410000AFC837058AE90000001974455874536F667477617265004164 + 6F626520496D616765526561647971C9653C00000018504C5445FFFFFF949497 + B2B2B4F0F0F1E1E1E2CDCDCE4A4B4F717275392F01A60000377F4944415478DA + 62601805A36014E0040001348A46C128C003000268148D825180070004D0281A + 05A3000F0008A051340A46011E001040A368148C023C0020804611FD0133330B + 2B2B2B1313132310B043001B3A808A8394005502D5B330338F061DFD0140008D + 227AE50A1656508EC096178807E01C03CC2E2CA379855E0020804611EDF30528 + 5BB0511B80B3CA684EA1390008A05144D38CC1467B309A51680A00026814511B + D02D6760CB27A3C14F6D001040A388BA59839DFE5903ADE1359A4DA80A000268 + 1451A54135F05903239B8C36BAA8020002681451236FB00D46309A4BA8010002 + 681451D2A61AAC790325978CB6B828010001348A28E86FB00D0D30DA2FA10000 + 04D0281A9615C76855422D001040A36804648ED14C423E0008A051344232C768 + 26210F0004D0282276B06A18640E4426191DDE22160004D0282202003BE46CC3 + 0D003BEEA3114B040008A0513412DA55A3AD2DB20140008D2202B9836D7883D1 + 3C42000004D028C2DDB01AB65507468F6434B2710280001A45C3BF4F3EDA6BA7 + 000004D0281AF1B963348FE0030001348A4673C7681EC103000268148DE68ED1 + 3C82070004D0281A79BDF2D13E3B0900208046112C77308DE60E781E199D4484 + 0380001A4520C0329A3B30F2C8E8FC08180004D0281AED788C7647F00080001A + AD3C462B8FD16A040F0008A0115E790CFBA524942F4519E1D50840008DE8CA63 + B4694554536B4457230001345A798C82D16A040F0008A0D19EC72818ED8DE001 + 00013432E73C46DB56A3F387440280001A6D5B8D82D196161E001040A36DAB51 + 30DAD2C203000268B46D350A465B5A780040008DACEC319AC0A9D1D21A515904 + 2080460E1AED7A50B1333272920D40008D989EF968DB8ABA9D9191D25F0708A0 + D1EC310A46B3081E001040A3D963148C66113C00208046C77547C1E8A82F1E00 + 1040A3D963148C66113C00208046B3C72818CD22780040008DF63D46C1685F04 + 0F0008A0D1EC310A46B3081E001040A3D963148C66113C00208086271ACD1E03 + 90458667520208A0E18846D75C0DCC029461B9460B208046B3C72818CD227800 + 40000DBB91DDD105ED03D9CE1A7E073C0004D068DF7C148CF6D6F10080001AED + 9B8F82D1DE3A1E001040A39D8F5130DA15C10300026818753E4653E6E0C922C3 + A72B021040A39D8F5130DA15C10300026898B4AE46B3C7A0CB22C3A49D051040 + A3ADAB5130DACEC203000268B475350A46DB59780040008D8E5D8D82D1F12C3C + 002080465B57A360B49D85070004D0E8CCE028189D37C403000268B4FA1805A3 + 95081E001040A3D5C72818AD44F00080001AED9C8F82D1CE3A1E001040A363BB + A36074C4170F0008A0D1EA63148C5622780040008D561FA360B412C103000268 + B4FA1805A395081E001040A38357A36074380B0F0008A0D1EA63148C56227800 + 40008D561FA360B412C10300026874EA7C80120A3B3B2323231310B0B2B2B2B0 + B030030162140208806240199002A03AA0EAE153890CAD897580001A52CD2BF6 + 219F2B4079029821C819CF616601E517506619EAA130A49A5900013484067719 + 8772C600E60B166A0D7302B30A30A70CE18CC23884067C010268B4774EEB9C41 + BD8C812DA30CCD7C3284FAEA000134DA3BA751D60036A658E9535032B3821A5E + A37D75DA0080001AED9DD3206F006B0DFA0711A83619EDAB531D0004D068EF9C + DA796320DBD7CC4328970C91BE3A40008D36AF8649DE187AB9646834B3000268 + B479459DCC31D81A0C2C4321930C85661640008D36AF865FE6183A99640834B3 + 000268B479353C33C710C92483BF99051040A39383C337730C894C32D8270D01 + 0268747290BCDCC13AB4E2959975D0E691413E69081040A3DD8F615C750C8D8A + 6470774400026830773F46AB8E1152910CE68E0840008D8EEE8E98DC3188F3C8 + 201EEF0508A0D1EE07F1B9631805EE60CB23833770010268B4FB31D272C7E0CC + 2383B623021040A3DD8F91D1B21AFC6DAD41DA110108A0D1D90F4295FF303ECE + 8999695085F4A00C6880001AED9EE39FE81DEEBD479641B454615076D5010268 + B4FB31823A1E83BD3B32183B220001349A3F4660D36AD036B506610E0108A041 + D73D671FAD3C46703532F8162F0204D0E8F015B6581A89DDC5417224F860CB21 + 0001343A7C35E22B8F41568D0CB2C12C80001A1DBE1A61C356837F506B700D66 + 0104D068F77CC4B7AD065D4B6B5075D5010268347F8CAE07C26C698DE6103800 + 08A0D1FC31DAF5187C9D91419443000268747817923D46DBBDE8FDC1818D9041 + 3398051040A3C3BBA33DF341D95F1F2C3904208046F3C768F6189C596490E410 + 80001A1403278C03993D4607AE06E990D6E098100108A0919D3F46B3C760CE22 + 8322870004D060E80E8E668FD12C3268A70C010268E4E68FD1BEC7E0EF8B0C82 + 1C02104023357F8C0EEC0E8941DF818F2580001AE8901F0DF8D1820C6F4136D0 + 1105104023327F8CCE9A9301066801CA40E71080001AD830671FCD1EA3596470 + 2F3B0108A011973F4687AE86DA80D6C0E61080001A61F96374E86A080E680D68 + 0E0108A091953F46FBE643B2B73E90390420804652FE185D443D1A7324038000 + 1A39A13CDAF918C25D9181CB2100013462F2C768EB6A48B7B3062C870004D008 + C91F833D7C41779B33B24342859D9D9191899565340607450C0204D0C01440EC + A3AD2BE4160BD6851C83FCAA37BAB7B30668C61020804642FE18CC3383CCF82E + 0E641FD4E79FD27BDE7060720840000DFFFC3198B737135E0438A81755D2B912 + 19901C021040C3BE8337881318912131882BC0111097000134CCC3947D5824AE + 419C30E8DB591F8080000820BAB7B919470394F43EEE201E65A06F8147FF5DB8 + 0001349CF307FB306A9B0CE276165D2B11BAE7108000A233621CAD3EC8ECDD0E + E2B106BA56228C74F61C4000D139618C0E5E915F8D0EE2C2939EC359748E5780 + 001AAEF963E80F5E8D0C3F0DFA1C021040C3337F0CEAB90FF24BDBC1BCDC828E + 95085D231720808665676E308F0652344D3A987308FD2A11BA860240000DC7FC + 3198D76750B88C807D50AF9A198E39042080865FFE18D4A147F1329B41BDDC62 + 38C63140000D9994312C265BA9300D34A82702E8D6CCA25F390110404327650C + F9DE390375A68106F74400BDFAEA742B2700026808A58CA15FF552A7913EB8CB + 007A35B3E8554E0004D0B01AE01DE46BD9A8D4CC1CE4A500BD9A59742A270002 + 6818E58FC17EAF1DD59A9983BD7941A766167DA21B2080864FAD3BE847369846 + 4CD2184E110E1040C326B806FD56012A8EE30DFA311CFA34B3E89243000268B8 + 0CF00EFE43AFA89966067D0F953E9386F42828000268780CF00E816BB559A8EA + E1C15F76D2A5234287DE1840000D8B01DEA150D752371C86C020275D5AD6B40F + 0780001A0E03584361A7320B95FD3C14BC4C8FB291E64D078000A27531325ACF + D2A6221D0A45275D5AD7B46E3C0004D090AF66D9874419C24CED80601F12AD6F + 3A744468DDBC0608A0A15EC90E91F0611DA125271D4A481A37B00102688877D0 + 874AF941FD901822DD537AE4109A7A0020808676077DA8941ECCD44F26EC4364 + 84930EAD089A36B20102684877D087CC30380B0D3C3F545A1674E8AAD3B21901 + 104043B9721D3A2507D3A8EF876A431B2080866EC1C13E846A565A9415EC43A8 + ADCD3E749B12000134643BE843AAD4A049088CB626E8D1510708A0A15AAD0EA9 + FCC132E25BDE34CF21346B4E0004D0100D90A1D5EAA44D69C13E9A20E8902000 + 02884645268D8363884D0ED12834865692A0719B9B564BDF01026848764086DA + E429DB6806A17D0EA1513704208086620764C88D598C66107A8C6BD2A61B0210 + 4043B0BD39F4C6F44633083D72086DBA21000134F43A204370CC7B3483D02787 + D0A2E50D104043AE03321417DE8C6610FA34BE69D10D0108A0A11606437261DA + 680619BAA903208086580764682EDC1CCD2074CA2134E8860004D0D06A660ED1 + 85CDA319845E3984FA1D5480001A521D90A1BAF07F3483D02F8750DBB5000144 + ED06D668FE18CD20039A43A8DDC80208A02134C23B744F7819CD20F4CB21D41E + EB0508A0A1D3C01AC227208D66103AE6102A37B2000268C8F87B289F10369A41 + 866E4A0108A0A132C23BA44FD01BCD20F4CC21D41DEB0508A021D2C01ADA274C + 8E6610BAE610AA36B2000268D4CBA31964B438C5030002684834B086FA29F7A3 + 19040BA0E19432351B5900013414FC3BE46F8118CD204337C50004D01068600D + FD5B52463308BD7308F51A59000134F81B588C43FF9EADD10C821DD06E172EF5 + 1A59000134E80B83E1700FDD6806C19543D8077DB3032080067B036B58DC643A + 9A41E8DFF0A056230B208006B93F87C74DBFA31964E8A61C80001ADC63DAC3E4 + 26ECD10C320039844A7367000134B81B584C0CA31964986790C19E7800026850 + 77B58649FE18CD20039243A833BC03104083B981C5C8309A4146400619DCE907 + 208006710930F427084733C8C0CE1150A30502104083B781351C26404633C890 + 4F42000134682BC8613280359A410672288B0A8D2C8000A2DC6FA3F96334830C + DA1C42792A0208A0C1DA7E646218CD20232883D0AA234B793F16208006ABC718 + 4633C888CA200C83B5A00508A0C1D9BD1A3E0358A31964609B2214F7D3010268 + 50E6FB613480359A4106BAACA5D059000134187BE8C3AA833E9A4106B8A34E61 + 62020820CAAA45F661D96E1CCD20C3A93FCB4E59731D208006A18F865DFE18CD + 2043383D0104D0E06B350EB30EFA680619E88E3A653D5A80001A743DF4E1D641 + 1FCD20035FE452E22480001A6C3DF461D7411FCD2003DF51A7244D0104D060AB + 4098184633C808CE20B4E9865052850004D0A8574633C8A00283ADD80508A0C1 + 35C43B1C3B20A31964E0BB21140CF50204D0A0AA408665076434830C826E08F9 + 550840000DAA8CCEC4309A41467C06A14DD14B76D30420800653539191613483 + 8C66904196B600026810D583C3B403329A410643EB84ECD63B40000DA24CCECA + 309A41463308B8F81D44550840000D1E1F30318C6690D10C42BB6E0899E52F40 + 000D9A0A64182EC11ACD20E4025A2CCA22B30A0108A0C192C1876F076434830C + 926E08794D148000222B7FB38F36B04633C8D02B83C96AA30004D020713C23C3 + 680619CD20346EC59355080304D0E0A8408675036B34830C9246165955084000 + 0D8E0A645837B04633C86069649193CC000268505420C3BB81359A41064B238B + 9C2A0420800643CE1EE60DACD10C32681A59645421000134189CCDCA309A4146 + 330826601D0C453140000D820A64B837B04633C8E06964915E850004D0C05720 + C3BE81359A418672620308A081AF40867D036B34830CA24616C9550840000D78 + 9E1EFE0DACD10C32881A59245721000134D015C80868608D6690C15420935A85 + 0004106988997DA85579A319646803EA97C824CE850004D0003B772434B04633 + C8A06A649158240304D0C05620ECACA319643483E0EFA7B30F6C15021040035B + 818C8806D6680619CA890E208006B602611ECD20A3196470A73A80001AD0BC3C + 321A58A31984C246D68056210001440AA27656666418CD20A31984FEFD747652 + 2C0708A001AC4046C414C86806A11C507D3284942A04208006302333318C6690 + D10C32104533294D1780001AB8A6E048E9A18F6690C1D74F27A1F30B10400357 + 81B0328C6690D10C3230853309550840000D2B378E6690D17E3AB54B6780001A + 28278E9C1EFA68061984FD74E28B6780001A281732318C6690D10C3260FD74E2 + CB6780001A360E1CCD20A355082D0A6880001AA071841155818C669041584213 + 3B860A104003E33C46E6D10C329A41482BA21907A6880608A081E9A2B3328C66 + 90D10C32A0C3A8C476D301026818386E34838C0EF5D2AE900608A0D10A643483 + 8C5621780040000DC410C248AB404633C8602CA6891C480508A001E8A28FAC21 + DED10C3258CB69E2BAE90001340063BC23AE0219CD2083B30A216A2815208046 + 2B90D10C325A85E001000144FF8CCBC4309A414633C86028AA896ACA00041031 + F976B40219CD20C3B20A2126290204D06805329A4146AB103C002080E8DD4567 + 671ECD20A319640825468000A277A61D8915C8680619AC550811A9112080E8DC + C21A9115C8680619AC5508116D2C8000A273177D445620A31964D0562184BBE9 + 0001445F078DCC0A6434830CDA2A8470810D104043CD3DA319648467107A97D8 + 00014408517509E5489C0319CD205406D49D0B21B8B01C2080E8DA451FA115C8 + 680619BC5508C16E3A4000D133BB8ED40A6434830CDE2A84609A0408A0A1945B + 4733C86806A17BAB06208008A0D10A6434830CF32A848065000144C72EFA88AD + 404633C860AE420874D30102888E2D2CD6D10C329A41A80258E9D8C6020820FA + B5B0466E05329A4106731542A08D051040F4CBA9ACA3196434830CC62A047FC2 + 0408A02191514733C8680619A8A60D4000E143545D66C2349A41463308D50035 + 3BC7F8979B000410BD2AB211BA4C713483D00650B5ECC6DBC60208207AB5B046 + 7205329A4106771582B78D05104074CAA5237792703483D0045073B2106FEB06 + 2080E8D4C2626418CD20A31964B08EF4E26B630104D0E076C2680619CD20035C + 7C0304109D5A580CA3196434830CDA915E7C6D2C8000A24F16651ACD20A31964 + 1077D3F134700002882E2DAC113DC63B9A4106FF482F9E361640000D5AFB4733 + C86806190C25384000D1A585C53A9A414633C8A0EEA6E34EA10001448FFC39D2 + 2B90D10C32E8AB10DC49142080E83148C0349A414633C8E0EEA6E31E66050820 + 3AD45F23BD8B3E9A418640371D671B0B2080465B58A31964B48D852791020410 + 1D5A58ACA3196434830CF66E3ACE36164000E1402C03D9BC1BCD20A31984EEC5 + 38AED5B4000144FBFE0FD3683C8E6690C1DF4DC7954C010288F6AD3B96D1781C + CD2034022CB4EF840004D020B37834838C6690C155900304D0680B6B34838CB6 + B1F024548000A275C61C9D0419CD203404549C0AC1D1D40108205A8F0E8CB6B0 + 4633C8D06863E1186D0508205A8F2F8F4E828C66105A029A27558000A271CB6E + B485359A41864A1B0B7B27042080685C6F8DB6B04633C8506963614FAB000184 + 35578EB6B04633C8086C63616DED0004106DED1C5D66329A41680DD8695B9A03 + 04D0680B6B34838CB6B1F0A45680001A24797234838C6690016F63616DEF0004 + 1016C432DAC21ACD2023B28D856DB5094000D1749077B485359A4186521B0BDB + 402F4000D1D4C2D116D66806194A6D2C6C053A4000D1B2CA1A9D251CCD207400 + D49B2BC4D6250008205A7641465B58A3196468B5B1B07442000288965D90D116 + D66806195A6D2C2C9D108000A2617E1C6D618D669021D6C6C2D2E60108201A76 + 41465B58A3196488B5B1B07442000288865D90D1BD84A319843E8089869D1080 + 001A58CB4633C86806A102A065A10E1040035B5DD1B327C7481A60A722A05106 + 193097B033320DAED28F86DD0280001A115D10665646B65140EDECC934784629 + 6958AA030410ED6AABC1127C2C8CECA3A99946798471904432F5067A316A4680 + 00A299558363909785693477D0B81E190C8D2DEA0DF462E4788000A2591F9D71 + B4F21829D508CB306A6361F4D2010268E06C1ACD1EA35964F00DF46294EB0001 + 44B33EFA408719F368E38A9E0DAD016E5053ADEB8CD14B0708A081B288F6A3BA + A3C9969E60A0BBEB342BD801026898764146AB0FFA5722C3B313021040C3B20B + C2325A7D0C44253290AD6A9A95EC0001341CBB20A3F963E4E5109AF50D000208 + AD673B1CBA20ACA3CDAB816A660D6047846A918E36DC001040349A26641CCD1F + A33964687642D0BC001040346AC9318DE68FD11C32343B21684917208068940D + 5946F3C7680E199A9D10B4C60F4000D1A62137605D1096D1FC31D03964A0CA46 + 1AA55D8000A24D1F7DA0BA20A3E35723772C8B6A518FDA4B070820DAF4D107AA + 0B329A3F06430E19E29D10D446224000D1C60E96211E46A360E8158F2CB4713E + 4000D1A4001EA02EC868077D4477D4A915FBA835204000D1DB0A5AAEDF1D6D60 + 0D964616F3506E5FA316EF000144930CC234DAC01A6D640DD9F847CD20000144 + 9356DC8054B1A323BC237CAC976A434C288E0708209AD830A46BD85130441BD9 + CC3429DF010288BE75D46805325A850CFE5E3A4A03112080685106338E5620A3 + 55C8104E02286E0708A0E1D2471FAD4046AB109AB48000028816196420FAE8A3 + 4358A30359ACB4C8200001448B41AC01E8A3338F562083AD0AA17F2AA05A2F1D + B9F60308203A66C02131C4370A683E1634F87BE9C84E0708201AB4528672FF6C + 140CE56E3AB5520172F3102080E867FC680B6BB48D35443AA2C8791B20806890 + 4158475B58A36040D2012B0D32084000D1A005378407F846C1901EC7A2D63013 + 722F1A2080A83F0630107DF4D116D6606C630DDD7480D43A040820EA67BF01E8 + 9C318FA6C6C108E8DF09A1562F01A911041040746BC08D7641463B2143268320 + B91C2080A8DF8E671AED828C82014A093448C30001342C06B14667410625601C + B24D092497030410F55319F36806190503944198A9EF728000A2FA08C0E820D6 + 28404A0ACC433225202562800042A0D151DE51303ACE0B0508130102883EB513 + 8DC1685A1C9C60E836B611151F4000517D1A846934838C8201CB20D41AC6424C + 84000410D50700584733C82818B00C42FD540C1040F4C87BA3196434830CB1D5 + 5888761040000D8751DED10C329A4168D6930608206A67900139F26734298E66 + 10EA0E6321320840000D876990D161DED1615E9A25638000A243D61BCD20A319 + 64A88DF3229C0E1040D46EA60CC8B1C5A34B4D06251888C2925A634D70030102 + 88DABD9BD10C320A864306818F35010410B5C7C706E460F7D1E5EE83120C4461 + 49AD8910F86C054000D1DCE0D10D5323160C446149F5821E2080685E350DA5D1 + EF514055C03C849302BCF60308202A679001BA9D7074186B74108BBA49019E41 + 00026838CC138E764246BB20349BAE0008202A679001BA237BB41332DA05A151 + 420608A0E1304F38DAC61A942D2CE6A19C41E04D218000A275D36D742664A402 + C621DDDA86671080001A2619846534418E7641689241000288CA2B4D581946DB + 58A3000C5806262150AB3B0A330F2080A83C7C3C601964B49B3EDAC2A26A4280 + F5A0000288CA198465A032C8682F64B48B4ED5C636CCFD0001445B63477B21A3 + 3D90213A950E2BEA010288B62DB7D12A64A4562003970EA8DC59000820EA6690 + 010C97D12A643001D6814B07ECD4F50140000D9F0C325A858CF6D06990410002 + 6858AC5584B63E47877A47F8102F2D66F4000288BA1964204B8ED1258BA31508 + 151B12B00C021040C329838CCE168EF81E3AF5330840000D8BC5BCA3B385A343 + BCB45ACE0B104034CD76A3FDF4D10A64A836B46119042080865706191DEA1DD9 + 43BC34C820000134BC32C8681532C27BE8D4CF200001343C56BB8FF6D3070F60 + 1E1E1904D6500408209ACEAE8C0EF58E56204375A4069641000268B86590D12A + 6444F7D0A99F41000268D86590D1A1DE113CC44B830C021040D4CD202C039F41 + 46FBE923BB02A1D64826CC27000134FC32C8E8318B237788970619042080865F + 0619AD4246700F9DFA19042080A068980CF18DF6D347F6102F355B1050E30002 + 68386690D1A1DE115C81503B830004D070CC20A355C888EDA1533F830004D0B0 + CC20A343BD237488970619042080A89B4118060918EDA78FD80A84DA69192080 + 86670619DD7D3B328778699096010268786690D12A6484F6D0A99F9601026898 + 6690D17E3ADD1B58CCC333830004D070CD20A3FDF411D943A77E5A0608A0E19A + 41461B5923B3874EF5B40C1040C336838CEEBE1D913D74AAA76580001AB61964 + B40A19913D74AAA76580001ABE1964B49F4E47C0326C330840000DCB99F4D125 + 5923B802A1F24C3A40000DE30C325A858CBC215EEA671080001ACE196474A877 + C40DF1523F830004D070CE20A3FDF41137C44BFD0C021040D46D8DB0300CCBB0 + 1A054365889781EA3B0A010268586790D12A64A4F5D0A99F41000268786790D1 + 7EFA081BE2A57E06010820EA2624D6C1964146877A475A0542ED73B100026898 + 6790D12A6464F5D0A99F41000268B86790D1A1DE9134C44B830C021040D4CD20 + 832EB446FBE923AD02A1F6E9EE000144DD64340833C8E850EF081AE2A5620681 + 75AD000268D86790D12A6424F5D0A99F41000268F86790D17E3A0D01F3B0CF20 + 000144DD0CC2381833C8683F7D245520D44ECA000144D36C37DAC81AEDA10FD5 + D8863586000268246490D1DDB7236588970619042080683A36365A858C562043 + B5CB09CB20000144D3D9954133D43BDA4F1F1943BC3498F30608A01191414697 + 648D941E3AF5330840005179A467906690D1A1DE9131C40B0254AE1E010288CA + FDD8411A68A343BD23A602A1D6CA09D8227E8000A2ADB1A3FDF4D11EFA101DB2 + 8415F5000144E50CC2CA30CCC36D140CF29866A57206010820DAB6DC46AB90D1 + 0A648866109879000144DBD1E3D17EFA68053234072CE1050040008D9C0C323A + D43BFC7BE834C820000144E50C3278036EB40AA166038B79D0C6322395330840 + 00D1760DE4E850EFF00483B8A140ED840C1040B4CE78A3FDF4D11EFA506C27C0 + 33084000D1BAE9361CE790467BE8C33F83C0EB488000A276179679B40A19EDA1 + 0F8342109E41000288DA0D7496C19C4146FBE9C33E8E59A85D49020410CD0D1E + EDA78F5620433086E185004000D1BC6A1A6D648D0EF10EC1D92EB82701028881 + CA6B4D067906195D9235CC63985A19046E204000D17C786CB40A191DE21DCAF3 + 84000144ED0C32C8C36F74F7EDF0EE64523F190304101DB2DEE892ACD11EFAD0 + 9D27040820AAB73D98194646108E0EF10EE769104406010820AA97AC2C833D83 + 8C0EF50EE30A845A83308891088000A27ABA611DEC1964B49F3E8C1BD0D44FC5 + 0001448FBC373AD43B3AC43BC47A988876104000D1A3F5365A858C5620432C6A + 113D69800062A0F64CE1E00FC4D17EFAF06D3E532B6611260204103D46904787 + 7A477BE843761A042080E8533B8D5621C3010CFE98A5413F012080A89F415887 + 4006191DEA1D9E15082BF5BD0A1040D46F77300D810C32DA4F1F6D3B13998601 + 02884EB96FB8D6C5A343BCC3B2DC436A05010410F5A70786440619AD42866305 + 42B558459A06010820EA17AA43222447FBE9C3B16B49B548451A8E0008201A98 + CE322432C8683F7DF8B50B586850C6030410BD1A70A38DACD121DE2139880510 + 403448314C0CA355C86805329407B1907D0B1040F4337EB40A19EDA10F911845 + 2EE20102880645EA1009CDD1DDB7C3AED5CC4E03EF0204100DBA3843A3BDCA30 + BA246BB8B509A836B9853CCC04104074CC80A343BDA315C890E855A234810002 + 8816E98569A86490D17EFAB0EA5432D122830004102DFA3843254047FBE9C4A5 + 17E611169B28E9172080E89A0387EDCCD2B00643A641409316104000D1A4C5C1 + 3C5A858C0EF10EDD3E3A4A970B208068529E0E995EFA683F7D184526D5CA7794 + 412C8000A26F1D353AD43BDA431F627D748000A24906193A813A5A85905F9C0E + D7E6326A060108207A5B313AD43B5A810CF2A20ED5CB0001449BF606CB10CA21 + A3FDF4E151D451AD078DDA41000820DA94A643A81332BAFB76B437896F540220 + 8068935686522764B40A191E6D65AA4523EA24054000D1A61937940276B49F3E + 2CC6EB69957601028846B97028754246FBE9C3A121C042234F0304108DDA714C + A355C8E810EFD0EC82A0255D8000A251593AA43A21A355C8684F1267B3122080 + 6834A233B43A21A3FDF4D18E24AE3E3A4000D1CA9A21D50919DD7D3BE49BC92C + B42A160002885645E9D0EA848C2EC91AEA1508D52210BD5D0910400364CF683F + 7D748877703692D14B7680001AA09A6AB49F3EDA431F9C051C7ADF00208006CC + A2D17EFAE006CC432AF66857B00304D0405555C33788472B9061D5050108A081 + B369B40A19EDA10F812E084000D1AC2DCECE3CD472C8683F7DC8D6FFD41BA6C7 + 189A000820DAB53458875A06191DEA1D1D62C1EC3A030410EDCAD121D7C61AAD + 42866CE1C648BB9201208006D4AED1A1DED11EFAE02ADA307D0E1040346C68B0 + 0CB91C32DA4F1F9ADD47EAF50B30FB5E000134B0960DB6BEDE68E6189215082D + 0B7580001AD8EA6AB40A19EDA10FF22E084000D1D236E6A1974346FBE94370F8 + 919996653A4000D1B2BE621D7A196474A8770856FCD41B5CC1D22B0008205AF6 + 7886601B6BB40A19D1632B58FC0E1040B44C2343B18DC53A5A818CDC1616B62E + 084000D134430EC136D648EFA70FC1428D95A685034000D1B41D3E14DB58237C + F72DD3482ED2B0791E2080683AEDC23E0433C8C8EEA70FC518A35E8986AD0B02 + 1040B4B57128B6B146743F7D0846182B6D4B078000A26D9D3514DB5823B99F3E + 14E38BC6A915208006499E1CEDA78F0EF10E78858FB5FA040820ACFDD4115D65 + 8FE0DDB78C23BBBEC73A8007104083A5D61AAD42467BE883B285051040341EC8 + 198A738523B69F3E048778A9392A8FDDFB000144EB6A6B48B6B146E650EF90AC + 40689E54010288D625E8D06C638DC82A644896658CB42E1F000288E6D60ECD36 + D6081CEA1D92451933CD8B728000A27913836968562123AF9F3E244B32DA2754 + 8000A2F940E7106D63318F562023AC1CC3310704104083CDE2D12A64B4873EA8 + 0A7280001A6455D7683F7D7488777025538000A27DD6641FA2198469B4021949 + 8518AE860E4000D1C16AD6D12A64748877B08F35E22C210002880E4DF021DA4D + 1F4943BD43348AE891480102881E99939961C487FFE810EFE09E04C15D850204 + 103D1A1843B59B3E6276DF0ED10A848ABD44DC2D2C80001A94D5D7683F7DB487 + 3E5892284000D1A5053E54BBE923A49F3E44A3873E29142080E8D2BE18B25508 + EB680532222A103CDD6480001ABCF68FF6D3472B904150820304107D4ACFA1DA + 4D1F09BB6F876AF5CE449F32022080E89343876A2D3E02AA90215BBBB3D3270C + 0002884E6963C876D3877D3F7DA856EEAC74AA44010268703B6174A877B4873E + C0C5374000D1A917C4CE325A858CF6D0A9D939A4570B0B2080E89549876C377D + 780FF58ECEE1120A048000A257D218BA23BDC3BA9F3E542B76AAAE02C25B8B02 + 0410DD5C3174AB10E6D10A64585720F8CB6E8000A25BD93974477A876F153274 + AB7576BA9512000144BFE6F7D01DE91DB6FDF4215BABD331610204D090C8A8A3 + 43BDA343BC03D5B40108203AA68CD12A6474887710562004AA518000A2A34B86 + 7015322C877A19472B10228A098000A263D13984270B87653F7DC846070B5553 + 2501CB0002889EADEF215C850CC3DDB7A31508512D2C8000A26B661DAD42467B + E883AD0221942601026828E5D6D17EFA685CD0BD5503104074ED9E0EE52A8475 + B40219861508E12E3A4000D1B7F13D94AB90E1D5C8621DAD40885B4B00104043 + CE3D0357728DF6D087DF7009E1121B2080E89C2E46AB90C10198472B102287BA + 010288CEE962285721C3A89F3E5A81101D0E000144EF2C3B94AB9061B3248B7D + 340E884E8D000144EF3C3B5A858C0EF10EA9C4081040746F7B0FE52A8475B402 + 19561508312D2C8000A2FBF0CD509E0B1926FDF4A13BC44BDD3910A2BAE80001 + C4305A859052C38FF6D0475A05021040F477D66815323AC43B382A10A28A6A80 + 00A27FCF68289760C3A19FCE385A3C91D24507082086D12A64640DF50EE11EFA + 805420000134102E1BAD42467BE883A00221AE9C0608A001697A0FE1481AEA43 + BDECA3214F5A310D104043DF6DA3FDF4D10A8486210110400CA355C8481AEA1D + 3D3883D4900008A081E99B32328F562103D2C01ABAE1CE4CE56027B68B0E1040 + 0333D23BA4670B87703F7D08073BD300151500013450EE1BCA43BD43B69F3E3A + C44B7A51011040C3C681A38DAC61DDF51BB0021A2080062A510CE92A6488EEBE + 651CAD40480F0A80001AB076C5E8502FDDC1E8B16464D4A5000134BCDC48B721 + 15F6D10A6428F7FA48080A80001A38470EE9BD8543704916FB6879444EE10C10 + 400358CD8D0EF58E0EF10E4C71444A0502104003E8CCD1A1DED10A64407AE824 + 951500013490A5E6683F7D74887720829AA4B202208006B4E13D94FBE9436CA8 + 77B4874E660502104003DA57621F5D92353AC43BC8531D40000DECD8CD683F7D + B40219E4890E20800638330FE546D6101AEA1DCADBA406B8020108A0014E13A3 + BB6F478778E9DC9225312C00026880DB83A3072D8E5620F42D9249AD40000268 + C0DD3B7A4AD6E8102F1DA740482E91010268C01D3C941B594364F7EDE8495814 + 14C8000134F03D53D6D12A84C660E80EA653BF114B7205021040035FE70DE946 + 16FB680532CC131B40000D82C1CDA1DCC81A02FDF421DC43671C04150840000D + 825C3DDAC81A1DE2A553E943460502104083617E6C2837B258462B9021541493 + 51580004D060980B19D28DACC15E85B08E862C4573200001342806B286F274E1 + 20DF7D3B74CB9E4192CC000268702489A1DCC81ADC4BB286EC102F0D1A586455 + 200001344892C4506E64B18F562043A3E94A560502104083A55531841B598378 + A877E8F6D06950089357810004D0A071FDE8A14DA33D749A36B0C82C83010268 + D02489217CE03BCB68038BDA6D14C6411318000134785A15A37B16A80E866CAD + CC34786A5380001A444962084FA8B38F562083BDFC2537300002885C2FD02049 + 0CE16EC8A01CEA1DB24762D0A20342F6E66E80001A4CAD0AC6D12A64B4CD3AD8 + D21640000DA65C3EBAAE6E74889746D531F9AD1380001A5CDE185D3834DAA563 + 1D5C452F4000913F12C73E3C323AB58263B4873E889B261474C700026890754C + 4797468CF4215E9A842305150840008D7A6578F6D3876A4933E88A5D80001A6C + 1DD3A1DB0D1954FDF4A1DA43A7490784A2EE1840000DBADA70E876430653236B + 8856C434E9805056810004D020F4CE909DDF1AAD40281DE91884452E40000DBE + 06E3E804D7881DE21D8CE909208006DF50EFD0CD218366F72DE368FEA0DA102F + 40000DC68EE990EDA80F96255943B3914A9B0E3AA5B52940000DCA56C590EDA8 + B38F562083AC474B71600004D020F5D510EDA80F8AA1DEA1D943671EA4652D40 + 000DD256C5509DE71A0CFD74A6D190A362600004D020CDF84376207FB402195C + 052DC54D1180001AACAD8AA1DA511FF82A6448061C8D3AE854080C80001AB449 + 62A8E69081EEA7338EE60FAA060640000DDA7EFA501DCA1AE8A1DEA138BC3198 + 931040000DE224314487B2D8472B9041D28FA54A471620800673BB7B680E650D + E850EF90ECA10FEAF403104083B9861C1DB01C112146AB1608751A58000134B8 + DBDD433287308F5620C328F10004D0E02E3487E650D6C055214330B868358045 + AD061640000D725F0ECD1C3250FD74C6D1FC41F59403104083BD9E1C92396480 + FAE943F028459AE50FAA35B0000268B08FD40DCDE99081A942865E8F8D66C33B + D49B230008A0C15F1430B28C5621C3B487CEC238F81B1E000134F8072386E484 + E140F4D3875C639476CD0E2A56A6000134147C3B0473C800ECBE651CCD1FB448 + 3100013414FA5B433187D07F4916CB68FEA045030B208086469A1882E397ECA3 + 15C880B542A9D9C00208A0512F0F8F7EFA901BE21D2AC52940000D8D91ACA198 + 43E8DB4F671ACD1FB469600104D09069780FB91C42D7DDB7ECA3F98346290520 + 80864EA9C9345A850C9B215E5AE60F2A37B0000288CAA526FB680E19887E3AE3 + 68FEA0D5CA0B80001A4A5DD3D176F6F018E2651A4A752940000DA97605D36815 + 320C2A10A62115140001446DC43C9A43E83ED4CB3E9A3F6837A50C1040436AAC + 77C8E510FAF4D39946F307ED4678010268A8B5BC87560E611EAD40867AEA0008 + A021576C328D562143788897B6F983161D1080001A6A63BD436DE522EDFBE943 + A8874EDB0E2A6D4678010268E8754386560EA1FD502FF368FEA0650704208086 + 62AA185239847DB402A14FFEA051E31B20808664D37B28EDC2A5F150EFD0E9A1 + B3300EC9920220808664376448E590D1310BBAE40F5A75400002686876438652 + 7B93A6BB6FD94713048D130440000DD5CEE9688F6C480DF1D23A7FD0AE260508 + A0213B0330847208FB886F77B30EDDA10A80001AB263166CEC43A6D0A05D3F7D + 880CE731D13C7FD02E2000026808971A43A75A1DE117A8D07C2E8896AD098000 + 1ABA039C43A8E0A0D1EEDBA1D14367A6FD721B5AE60F80001AD225C79019EE65 + 1CB9E98285F6F983A62D0980001AD21DF5A153B9B28FD40A8475A82F460308A0 + A15E7A0C911CC234422B107AE40FDAB622000268C887CF1019CC621F91052713 + FB902F21010268C877D48748579DEA0131048E52641E0EBB61000268E877D487 + 48254BEDC432F82B4E167AE40F9A070340000D838EFAD0A866A9BCFB76F0F7D0 + 59E971A60BEDDB990001343CEAD9A1D011611C592D0B26F6E1D1BA0608203AD4 + B474391D8A69F00715FB082A3999E972681E3D96B80304D070A96B874047849A + 696690170774E97ED0A7650D1040C3A6353A04828B7AA9866534C2E915E10001 + 346C86B2864047846AFDF441EE5126FA1CB94A9F5000082086619443067D338B + 4A932183BB03C242A76B1FE8943F000268180DF60E815A972AC130B8876E58E9 + 746237BD4A0980001A4E83BD83BF99458DFDE9837B0A9D895EF9835EA1001040 + C36BB077D037B328CF21833A7FD0AB7945C7015E80001A7655EF206F66515A50 + 0CEAFC311CE31820808661E80DEE4943CA72C8606E5930D3ED462D7AE60F8000 + 1A8EE5CBE06E6651D21D1BCCF9836ECD2BFAE60F80001A8683BD83BEAFCE341C + AB4626FA5D594AD7C805082086E1994306772542E67CC8202E3859E878E7357D + F3074000310CD71C32A82B11729A598379E0868ED507BDF3074000D119D1B1A0 + 196695C8206E5EB1D03556E9EC3980001A423DD4E1D599236DCC673067765676 + 7AE60F7A97130001C4309C73C8E0AE44882F78D9477B1F03963F0002689807E8 + 209F356424CE0F833855D0B5FA1888020F2080867B9133D8979E308D904A70C8 + C62540000D44A8D2B5D019F4DB44F0253246D6D19589033C8E0710400CC33F87 + 0093D920EF97B1624B69EC4C833B7730B0D2B7FA18A0FC0110400C232187B00F + FE231D9859589918D9C1E1C2CECEC8C4CA32D85DCCCCC43E22F20740008D84AE + DD705EBE33323AE703188300013452C277A474F08665E77C20F30740008D9812 + 6828B4B38608A07BEB6A20F30740008D9C3A7AB49D351A73640080001A51E13C + DACE1A8AADAB81CD1F000134B24A22603B6B348B50943D98D84758FE0008A011 + 56578F76458658E763C0F30740008DB856D6E09F371CBCD1C5C836F2F2074000 + 0D708D3D203964348B0C9DEC31E0F3830001C4302273C8686F7D28F4CD0745FE + 0008A0111BF0A35984A4581AB1051940008DD8A26974406B700F5D0D96FC0110 + 4023B7F21E1DD01ACC435783267F0004D060888101CB21A3596430678FC1B1BF + 1620801846760E19CD2283367B0C92FC011040830331B10D641619ADC8075BDF + 030406C9465080006218CD21A3596410668F41933F000268B0A0818D8DD141DF + 4133B00B2BB3064B400004D0A041AC031A21C02C323ABB8E14198C031C1B8327 + 320002886134878C2E40C1C81E031C1383297F000410C3680E191DD21A340357 + 83307F0004D0E06AF7B20D7C1619E16BE3063E7B0CB2E94180001A5CA5D7C0E7 + 9011DD1919E8AEC7609CFE0008A0D1E1DED196D6A0695B0DC6E15D80001A1DEE + 1DAD46064DE531188777010268B4AB8EABA61F41D5083313E3E008F441D83D07 + 08A0D1C1AC115F8D0C92CA6390E60F80001A1DCC1AD9835A2C4CEC8326B407E5 + F01540008D0E668DE0A6D6A0695A0DE2E12B80001A1DCC22A6A9351CA38E79F0 + 34AD06F3F01540008D76444666776490E58EC1DBFD0008A0C11B816C6CA37964 + 84E48EC1BC0E0E208046BBEA23ACADC53CF872C7A0EE9E0304D068476424E591 + 41993B0677F7032080463B22A4E791213AF6CBC2C4383803745037AF000268B4 + 2332222A92415A750C81EE0740008DCE880CFF8A64B0561D4362F6032080067D + 4764F046ED90C824833A730C85C589000134DA1119BE996490678EA1D1FD0008 + A0D1F1DEE19949067FE61822A3BB000134DACCA25E2619241D7766D6A1903986 + 4AF30A2080469B59C329970C95BC31849A57000134DACCA2492EA17FDB816508 + E58DA1D4BC0208A0D16616AD7209DD2A1350B5C138D48267C834AF000268E834 + B318D9861E6007D726B4CA27CCE05A837D0886CB109A1C0408A0D149433AE513 + 2A661450C618A23963E84D0E0204D0685F9DBE19059453C8CB2AC06C01CA1743 + 39630CC5DE3940008DF6D5072AAF00330B30B780F20B2B0B0B0B331020F20210 + 00C55841390294278099827DD8F87C88F5CE010268B4AF3E0A467BE778004000 + 8DF6D547C168EF1C0F0008A0D14A64148C561F780040008D5622A360B4FAC003 + 000268480EF88E562243B2FA189283BB0001345A898C82D1EA030F0008A0D14A + 64148C561F780040008D5622A360B4FAC00300026874386B148C0E5EE1010001 + 343AB13E0A685D7D0CE9A97380001AAD4446C168F581070004D06825320A46AB + 0F3C002080463BEBA360B4738E070004D0E888EF28181DDBC503000268B49D35 + 0A465B57780040000D9376D6682532E8AA8F61D2BA0208A0D176D628186D5DE1 + 01000134DACE1A05A3AD2B3C00208046C7B346C1E8D8151E001040A3F386A360 + 7466100F0008A0D1AEC82818ED7CE001000134FCBA22A3596400B3C7F0EB7C00 + 04D0685764148C763EF00080001AEDAD8F82D1EC81070004D0686F7D148CF6CD + F10080001AEDAD8F82D1BE391E001040A3035AA360347BE0010001345A8B8C82 + D1EC81070004D0F01EF31DCD2274C81EC37B6417208086FBB4C8681619CD1E14 + 0180001AAD4546C168F6C003000268B42F320A46FB1E780040008D76D747C168 + F6C003000268B4161905A3D9030F0008A09183984617A0506D51C9089A350708 + A0918446D76851277B8CA83557000134B210EBE862784ADB56232D7B0004D0E8 + A8EF28181DD7C50300026824F6D7475B5AE4763D4660CF1C2080465B5AA360B4 + 6D85070004D0684B6B148CB6ADF00080001A6D698D82D1B6151E00104023BA1A + 196D6911D5B61AD1950740008D5623A360B4F2C003000268B41A19ED8D8CF63C + F00080001A450CCCA3835A3886AD462B0F060680001A45A3D5C868E581070004 + D02882CD8D8CE611A4DC313AE701030001348A90F2C868536B7446101D0004D0 + 281AED8E8C763CF00080001A45A379643477E0010001348A46F3C868EEC00300 + 0268148DE691D1DC81070004D0281AF17DF6D15E393E001040A3081F6019F64B + 511847E73BF00380001A4584F308FBB0AD3A46730741001040A38898C6D630AC + 481847270389020001348A4660AF7DB44F4E3C0008A05134C25A5BA3ED2AD200 + 40008DA2119449463307E900208046D108C924A399833C001040A388CC4CC23A + 747209306FB08E660E320140008DA2E15D958C561C140280001A45140F6F0DD6 + 5C02AA384607AB28050001348AA8964B064F36611FCD1B54030001348AA8DC2F + 611FF8AC31DAA6A2220008A051448B6C32008D2E76C6D1AC410B001040A38846 + 8D2EBAE51348CE186D50D1080004D028A24B4661A745636A3463D0010004D028 + A2634E016715768A7205285B8CE60B3A0280001A4503905780998515985D80F9 + 059C63D8B1E51AA83848095025503D0BF368AE1800001040A368148C023C0020 + 8046D1281805780040008DA251300AF00080001A45A36014E0010001348A46C1 + 28C003000268148D825180070004D0281A05A3000F000830007D899E2A640A52 + 5F0000000049454E44AE426082 } PopupMenu = pmDropTarget Proportional = True @@ -148,8 +525,8 @@ object FormDropTarget: TFormDropTarget end object pmDropTarget: TPopupMenu OnPopup = pmDropTargetPopup - left = 188 - top = 120 + Left = 188 + Top = 120 object miDownloadAll: TMenuItem Caption = 'Download all' RadioItem = True diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index cd43988b8..a680e6102 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -608,6 +608,10 @@ msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " msgstr "Αυτόματος έλεγχος για την τελευταία έκδοση" +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "" + #: tmainform.cboptionchangeunicodecharacter.caption #| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" @@ -725,7 +729,7 @@ msgid "Contains content that is suitable only for adults. Titles in this categor msgstr "" "Περιέχει περιεχόμενο που είναι κατάλληλο μόνο για ενήλικες.\n" " Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν σκηνές παρατεταμένης έντονης \n" -"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό." +"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό.\n" #: tmainform.ckfilteradventure.caption msgid "Adventure" @@ -736,7 +740,7 @@ msgid "If a character in the story goes on a trip or along that line, your best msgstr "" "Αν ένας χαρακτήρας στην ιστορία πηγαίνει σε ταξίδι ή κατά μήκος αυτής της γραμμής, \n" "το πιθανότερο είναι ότι πρόκειται για μια περιπέτεια manga. Ειδάλλως, είναι στο χέρι σας\n" -" να αποφασίσετε γι αυτή την περίπτωση." +" να αποφασίσετε γι αυτή την περίπτωση.\n" #: tmainform.ckfiltercomedy.caption msgid "Comedy" @@ -770,7 +774,7 @@ msgstr "Ecchi" msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." msgstr "" "Ενδεχομένως η γραμμή μεταξύ Hentai και μη-Hentai, το Ecchi συνήθως αναφέρεται \n" -"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών." +"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών.\n" #: tmainform.ckfilterfantasy.caption msgid "Fantasy" @@ -801,7 +805,7 @@ msgid "A series involving one male character and many female characters (usually msgstr "" "Μια σειρά που περιλαμβάνει έναν αρσενικό χαρακτήρα και πολλούς γυναικείους \n" "(συνήθως έλκονται από τον αρσενικό χαρακτήρα). \n" -"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται." +"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται.\n" #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -829,7 +833,7 @@ msgstr "Horror" msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." msgstr "" "Ένα οδυνηρό συναίσθημα φόβου, τρόμου και αποστροφής. Ένα ανατριχιαστικό με τρόμο \n" -"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό." +"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό.\n" #: tmainform.ckfilterjosei.caption msgid "Josei" @@ -840,7 +844,7 @@ msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Un msgstr "" "Κυριολεκτικά «Γυναίκα». Απευθύνεται σε γυναίκες 18-30. Ισοδύναμο με το θηλυκό. \n" "Σε αντίθεση με το Shoujo το ειδύλλιο είναι πιο ρεαλιστικό και λιγότερο εξιδανικευμένο. \n" -"Η αφήγηση είναι πιο σαφής και ώριμη." +"Η αφήγηση είναι πιο σαφής και ώριμη.\n" #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -859,7 +863,7 @@ msgid "As the name suggests, anything martial arts related. Any of several arts msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με πολεμικές τέχνες. \n" "Οποιεσδήποτε από τις διάφορες τέχνες μάχης ή αυτοάμυνας, όπως αϊκίντο, \n" -"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά." +"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά.\n" #: tmainform.ckfiltermature.caption msgid "Mature" @@ -870,7 +874,7 @@ msgid "Contains subject matter which may be too extreme for people under the age msgstr "" "Περιέχει θέμα το οποίο μπορεί να είναι πολύ ακραίο για άτομα κάτω των 17 ετών. \n" "Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν έντονη βία, έντονη αιματοχυσία, \n" -"σεξουαλικό περιεχόμενο και σκληρή γλώσσα." +"σεξουαλικό περιεχόμενο και σκληρή γλώσσα.\n" #: tmainform.ckfiltermecha.caption msgid "Mecha" @@ -880,7 +884,7 @@ msgstr "Mecha" msgid "A work involving and usually concentrating on all types of large robotic machines." msgstr "" "Ένα έργο που περιλαμβάνει και συνήθως επικεντρώνεται σε όλους \n" -"τους τύπους των μεγάλων ρομποτικών μηχανημάτων." +"τους τύπους των μεγάλων ρομποτικών μηχανημάτων.\n" #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -900,7 +904,7 @@ msgstr "Mystery" msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." msgstr "" "Συνήθως συμβαίνει κάποιο ανεξήγητο γεγονός και ο κεντρικός \n" -"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε." +"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε.\n" #: tmainform.ckfilterpsychological.caption msgid "Psychological" @@ -910,7 +914,7 @@ msgstr "Psychological" msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." msgstr "" "Συνήθως ασχολείται με τη φιλοσοφία μιας κατάστασης του μυαλού. \n" -"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση." +"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση.\n" #: tmainform.ckfilterromance.caption msgid "Romance" @@ -920,7 +924,7 @@ msgstr "Romance" msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." msgstr "" "Οποιαδήποτε ιστορία σχετική με αγάπη. Εμείς θεωρούμε την αγάπη μεταξύ άνδρα και γυναίκας. \n" -"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι." +"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι.\n" #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -938,7 +942,7 @@ msgstr "Sci-Fi" msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." msgstr "" "Τα έργα αυτά αφορούν ανατροπές στην τεχνολογία και σε άλλα φαινόμενα σχετικά με την επιστήμη \n" -"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου." +"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου.\n" #: tmainform.ckfilterseinen.caption msgid "Seinen" @@ -949,7 +953,7 @@ msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically msgstr "" "Seinen σημαίνει «νέος άνθρωπος». Τα manga και anime που στοχεύουν ειδικά σε νεαρά ενήλικα αρσενικά,\n" " ηλικίας μεταξύ 18 και 25 ετών. Οι ιστορίες αυτές εμφανίζουν φοιτητές Πανεπιστημίου και άτομα από τον \n" -"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής." +"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής.\n" #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -967,7 +971,7 @@ msgstr "Shoujo" msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." msgstr "" "Ένα έργο που προορίζεται και είναι κυρίως γραμμένο για γυναίκες. \n" -"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα." +"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα.\n" #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -978,7 +982,7 @@ msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." msgstr "" "Συχνά συνώνυμη με το Yuri. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας κοριτσιών»." +"Μπορείτε να το πείτε και «Έρωτας κοριτσιών».\n" #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -989,7 +993,7 @@ msgctxt "tmainform.ckfiltershounen.hint" msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." msgstr "" "Ένα έργο που προορίζεται και είναι γραμμένο κυρίως για άνδρες. \n" -"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία." +"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία.\n" #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" @@ -999,7 +1003,7 @@ msgstr "Shounen Ai" msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" msgstr "" "Συχνά συνώνυμη με το Yaoi. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας αγοριών»." +"Μπορείτε να το πείτε και «Έρωτας αγοριών».\n" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" @@ -1011,7 +1015,7 @@ msgstr "" "Όπως υποδηλώνει το όνομα, το είδος αυτό αντιπροσωπεύει καθημερινές δοκιμασίες \n" "από έναν ή περισσότερους χαρακτήρες. Αυτές οι προκλήσεις / εκδηλώσεις θα μπορούσαν \n" "τεχνικά να συμβούν στην πραγματική ζωή και εμφανίζονται συχνά, αν όχι συνεχώς, σε \n" -"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές." +"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές.\n" #: tmainform.ckfiltersmut.caption msgid "Smut" @@ -1029,7 +1033,7 @@ msgstr "Sports" msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με αθλήματα. \n" -"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα." +"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα.\n" #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" @@ -1039,7 +1043,7 @@ msgstr "Supernatural" msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." msgstr "" "Συνήθως συνεπάγεται εκπληκτικές και ανεξήγητες δυνάμεις ή γεγονότα \n" -"τα οποία αψηφούν τους νόμους της φυσικής." +"τα οποία αψηφούν τους νόμους της φυσικής.\n" #: tmainform.ckfiltertragedy.caption msgid "Tragedy" From 23b373ae8a24c4535d0dc8eafea4f36f13650652 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Feb 2017 08:29:49 +0800 Subject: [PATCH 1519/2794] remove ineffective codes, most website are down. --- .../PornComix/chapter_page_number.inc | 95 ------------------- .../PornComix/directory_page_number.inc | 37 -------- baseunits/includes/PornComix/image_url.inc | 64 ------------- .../includes/PornComix/manga_information.inc | 72 -------------- .../includes/PornComix/names_and_links.inc | 52 ---------- baseunits/uBaseUnit.pas | 60 ++---------- baseunits/uData.pas | 33 ------- baseunits/uDownloadsManager.pas | 22 ----- config/mangalist.ini | 2 +- 9 files changed, 11 insertions(+), 426 deletions(-) delete mode 100644 baseunits/includes/PornComix/chapter_page_number.inc delete mode 100644 baseunits/includes/PornComix/directory_page_number.inc delete mode 100644 baseunits/includes/PornComix/image_url.inc delete mode 100644 baseunits/includes/PornComix/manga_information.inc delete mode 100644 baseunits/includes/PornComix/names_and_links.inc diff --git a/baseunits/includes/PornComix/chapter_page_number.inc b/baseunits/includes/PornComix/chapter_page_number.inc deleted file mode 100644 index 4103ecc4a..000000000 --- a/baseunits/includes/PornComix/chapter_page_number.inc +++ /dev/null @@ -1,95 +0,0 @@ - function GetPornComixPageNumber(MangaID: Cardinal): Boolean; - var - i: LongInt; - s: String; - l: TStringList; - regx: TRegExpr; - isGetImageURL: Boolean = False; - RepeatGet: Boolean = True; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MangaID, URL)); - while RepeatGet do - begin - RepeatGet := False; - l.Clear; - parse.Clear; - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - Task.Container.PageNumber := 0; - Task.Container.PageLinks.Clear; - Task.Container.PageContainerLinks.Clear; - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - isGetImageURL := False; - regx.Expression := '^^(.*)/img-(\w+)\..*$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<div', parse[i]) <> 0) and (Pos('class="single-post', parse[i]) <> 0) then - isGetImageURL := True; - if isGetImageURL and (Pos('</div', parse[i]) <> 0) then - Break; - if isGetImageURL and - (Pos('<a', parse[i]) <> 0) and - ((Pos('target="_blank', parse[i]) <> 0) or - (Pos('rel="nofollow', parse[i]) <> 0)) then - begin - Inc(Task.Container.PageNumber); - s := GetVal(parse[i], 'href'); - if (Pos('<img', parse[i + 1]) <> 0) and - (Pos('/upload/small/', parse[i + 1]) <> 0) then - begin - s := GetVal(parse[i + 1], 'src'); - s := StringReplace(s, '/small/', '/big/', [rfIgnoreCase]); - Task.Container.PageLinks.Add(s); - Task.Container.PageContainerLinks.Add('W'); - end - else if (Pos('imagetwist.', s) <> 0) or - (Pos('imgmega.', s) <> 0) or - (Pos('imgchili.', s) <> 0) then - begin - Task.Container.PageContainerLinks.Add(s); - Task.Container.PageLinks.Add('W'); - end - else if regx.Exec(s) then - begin - s := regx.Replace(s, '$1/dlimg.php?id=$2', True); - Task.Container.PageLinks.Add(s); - Task.Container.PageContainerLinks.Add('W'); - end - else if (Pos('/category/', s) = 0) and - ((Pos(WebsiteRoots[PORNCOMIX_ID, 1], s) <> 0) or - (Pos(WebsiteRoots[XXCOMICS_ID, 1], s) <> 0) or - (Pos(WebsiteRoots[XXCOMICSMT_ID, 1], s) <> 0) or - (Pos(WebsiteRoots[XXCOMICS3D_ID, 1], s) <> 0) or - (Pos(WebsiteRoots[PORNCOMIXRE_ID, 1], s) <> 0) or - (Pos(WebsiteRoots[PORNCOMIXIC_ID, 1], s) <> 0) or - (Pos(WebsiteRoots[PORNXXXCOMICS_ID, 1], s) <> 0) or - (Pos('.xxcomics.', s) <> 0) or - (Pos('.porncomix.', s) <> 0)) then - begin - RepeatGet := True; - if Assigned(FHTTP) then - FHTTP.Cookies.Clear; - Break; - end - else - Dec(Task.Container.PageNumber); - end; - end; - finally - regx.Free; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/PornComix/directory_page_number.inc b/baseunits/includes/PornComix/directory_page_number.inc deleted file mode 100644 index ebbf92c36..000000000 --- a/baseunits/includes/PornComix/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetPornComixDirectoryPageNumber(MangaID: Cardinal): Byte; - var - i, p: LongInt; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[MangaID, 1]; - if MangaID = PORNCOMIXRE_ID then - s := s + '/online/'; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - for i := 0 to parse.Count - 1 do - if (Pos('<a', parse[i]) > 0) and (Pos('/page/', parse[i]) > 0) then - begin - p := StrToIntDef(ReplaceRegExpr('^.*/(\d+)/$', GetVal(parse[i], 'href'), '$1', True), 0); - if APage < p then - APage := p; - end; - Source.Free; - end; diff --git a/baseunits/includes/PornComix/image_url.inc b/baseunits/includes/PornComix/image_url.inc deleted file mode 100644 index cd9cf70e2..000000000 --- a/baseunits/includes/PornComix/image_url.inc +++ /dev/null @@ -1,64 +0,0 @@ - function GetPornComixImageURL: Boolean; - var - i: LongInt; - s, surl: String; - l: TStringList; - begin - surl := Task.Container.PageContainerLinks[WorkId]; - if not ((Pos('imagetwist.', surl) <> 0) or - (Pos('imgmega.', surl) <> 0) or - (Pos('imgchili.', surl) <> 0)) then - Exit(False); - l := TStringList.Create; - Result := GetPage(TObject(l), DecodeUrl(surl), Task.Container.manager.retryConnect); - - //broken source - if l.Count > 0 then - if (Pos('imgmega.', surl) <> 0) or - (Pos('imagetwist.', surl) <> 0) then - begin - for i := 0 to l.Count - 1 do - if (Pos('<img', l[i]) <> 0) and (Pos('class="pic', l[i]) <> 0) then - begin - s := l[i]; - Break; - end; - if s <> '' then - l.Text := s; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - // imgmega, imgaetwist - if (Pos('imgmega.', surl) <> 0) or - (Pos('imagetwist.', surl) <> 0) then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) <> 0) and (Pos('class="pic', parse[i]) <> 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end - else - // imgchili - if Pos('imgchili.', surl) <> 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) <> 0) and (Pos('id="show_image', parse[i]) <> 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/PornComix/manga_information.inc b/baseunits/includes/PornComix/manga_information.inc deleted file mode 100644 index fa983a4f6..000000000 --- a/baseunits/includes/PornComix/manga_information.inc +++ /dev/null @@ -1,72 +0,0 @@ - function GetPornComixInfoFromURL(MangaID: Cardinal): Byte; - var - i: LongInt; - isExtractCover: Boolean = False; - isExtractGenres: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MangaID, 0]; - mangaInfo.url := FillMangaSiteHost(MangaID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - // using parser - if parse.Count = 0 then - Exit; - - mangaInfo.coverLink := ''; - - for i := 0 to parse.Count - 1 do - begin - //cover - if Pos('class="single-post', parse[i]) <> 0 then - isExtractCover := True; - if isExtractCover and (Pos('<img', parse[i]) <> 0) and - (Pos('alt="download comic"', parse[i]) = 0) then - begin - mangaInfo.coverLink := GetVal(parse[i], 'src'); - isExtractCover := False; - end; - - //title - if (mangaInfo.title = '') and (Pos('class="posts', parse[i]) <> 0) then - if (Pos('<h2' , parse[i + 2]) <> 0) and - (Pos('class="post-title', parse[i + 2]) <> 0) then - mangaInfo.title := CommonStringFilter(parse[i + 3]); - - //genres/tags - if (Pos('class="video-tags', parse[i]) <> 0) then - isExtractGenres := True; - if isExtractGenres and (Pos('</div', parse[i]) <> 0) then - isExtractGenres := False; - if isExtractGenres and - (Pos('<a', parse[i]) <> 0) and (Pos('/tag/', parse[i]) <> 0) then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]) - end; - end; - if mangaInfo.title = '' then - mangaInfo.title := 'Untitled_' + IntToStr(Random(99999)); - mangaInfo.status := '0'; - - //single chapter - mangaInfo.chapterLinks.Add(AURL); - mangaInfo.chapterName.Add(mangaInfo.title); - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/PornComix/names_and_links.inc b/baseunits/includes/PornComix/names_and_links.inc deleted file mode 100644 index bf9a66f4b..000000000 --- a/baseunits/includes/PornComix/names_and_links.inc +++ /dev/null @@ -1,52 +0,0 @@ - function PornComixGetNamesAndLinks(MangaID: Cardinal): Byte; - var - i: LongInt; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[MangaID, 1] + '/'; - if MangaID = PORNCOMIXRE_ID then - s := s + 'online/'; - if AURL <> '0' then - s := s + 'page/' + IntToStr(StrToInt(AURL) + 1) + '/'; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - regx := TRegExpr.Create; - try - regx.Expression := '\w+\.\w+/.+$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('id="post-', parse[i]) <> 0) then - begin - s := GetVal(parse[i + 2], 'href'); - if regx.Exec(s) then - begin - ALinks.Add(s); - ANames.Add(CommonStringFilter(GetVal(parse[i + 2], 'title'))); - if ANames[ANames.Count - 1] = '' then - ANames[ANames.Count - 1] := 'Untitled_' + IntToStr(Random(99999)); - end; - end; - end; - finally - regx.Free; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7c5fd3183..fae74b4a6 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -280,19 +280,12 @@ interface UNIXMANGA_ID = 47; EXTREMEMANGAS_ID = 48; MANGAHOST_ID = 49; - PORNCOMIX_ID = 50; - PORNCOMIXRE_ID = 51; - PORNCOMIXIC_ID = 52; - XXCOMICS_ID = 53; - XXCOMICSMT_ID = 54; - XXCOMICS3D_ID = 55; - PORNXXXCOMICS_ID = 56; - MANGAKU_ID = 57; - MANGAAT_ID = 58; - READMANGATODAY_ID = 59; - DYNASTYSCANS_ID = 60; - - WebsiteRoots: array [0..60] of array [0..1] of String = ( + MANGAKU_ID = 50; + MANGAAT_ID = 51; + READMANGATODAY_ID = 52; + DYNASTYSCANS_ID = 53; + + WebsiteRoots: array [0..53] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -343,13 +336,6 @@ interface ('UnixManga', 'http://unixmanga.co'), ('ExtremeMangas', 'http://www.extrememangas.com'), ('MangaHost', 'http://br.mangahost.com'), - ('PornComix', 'http://porncomix.wf'), - ('PornComixRE', 'http://porncomix.re'), - ('PornComixIC', 'http://incest.porncomix.re'), - ('XXComics', 'http://gallery.xxcomics.net'), - ('XXComicsMT', 'http://milftoon.xxcomics.net'), - ('XXComics3D', 'http://3dincest.xxcomics.net'), - ('PornXXXComics', 'http://pornxxxcomics.com'), ('MangaKu', 'http://mangaku.web.id'), ('MangaAt', 'http://www.mangaat.com'), ('ReadMangaToday', 'http://www.readmanga.today'), @@ -1144,14 +1130,7 @@ function SitesWithSortedList(const website: String): Boolean; NINEMANGA_BR_ID, ONEMANGA_ID, MYREADINGMANGAINFO_ID, - NHENTAI_ID, - PORNCOMIX_ID, - XXCOMICS_ID, - XXCOMICSMT_ID, - XXCOMICS3D_ID, - PORNCOMIXRE_ID, - PORNCOMIXIC_ID, - PORNXXXCOMICS_ID + NHENTAI_ID ]); end; @@ -1168,14 +1147,7 @@ function SitesWithoutFavorites(const website: String): Boolean; Result := SitesMemberOf(website, [ FAKKU_ID, MYREADINGMANGAINFO_ID, - NHENTAI_ID, - PORNCOMIX_ID, - XXCOMICS_ID, - XXCOMICSMT_ID, - XXCOMICS3D_ID, - PORNCOMIXRE_ID, - PORNCOMIXIC_ID, - PORNXXXCOMICS_ID + NHENTAI_ID ]); end; @@ -1204,14 +1176,7 @@ function SitesWithoutReferer(const website: String): Boolean; Result := False; Result := SitesMemberOf(website, [ MEINMANGA_ID, - IKOMIK_ID, - PORNCOMIX_ID, - XXCOMICS_ID, - XXCOMICSMT_ID, - XXCOMICS3D_ID, - PORNCOMIXRE_ID, - PORNCOMIXIC_ID, - PORNXXXCOMICS_ID + IKOMIK_ID ]); end; @@ -1221,12 +1186,7 @@ function SitesWithSingleChapter(const website: String): Boolean; Result := SitesMemberOf(website, [ FAKKU_ID, MYREADINGMANGAINFO_ID, - NHENTAI_ID, - PORNCOMIX_ID, - XXCOMICS_ID, - XXCOMICSMT_ID, - XXCOMICS3D_ID, - PORNCOMIXRE_ID + NHENTAI_ID ]); end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 23685c64d..ebe5c9baf 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -808,8 +808,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/MangaHost/directory_page_number.inc} - {$I includes/PornComix/directory_page_number.inc} - {$I includes/MangaAt/directory_page_number.inc} {$I includes/ReadMangaToday/directory_page_number.inc} @@ -904,15 +902,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if WebsiteID = MANGAHOST_ID then Result := GetMangaHostDirectoryPageNumber else - if (WebsiteID = PORNCOMIX_ID) or - (WebsiteID = XXCOMICS_ID) or - (WebsiteID = XXCOMICSMT_ID) or - (WebsiteID = XXCOMICS3D_ID) or - (WebsiteID = PORNCOMIXRE_ID) or - (WebsiteID = PORNCOMIXIC_ID) or - (WebsiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixDirectoryPageNumber(GetMangaSiteID(AWebsite)) - else if WebsiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber else @@ -1023,8 +1012,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/MangaHost/names_and_links.inc} - {$I includes/PornComix/names_and_links.inc} - {$I includes/MangaKu/names_and_links.inc} {$I includes/MangaAt/names_and_links.inc} @@ -1174,15 +1161,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if WebsiteID = MANGAHOST_ID then Result := MangaHostGetNamesAndLinks else - if (WebsiteID = PORNCOMIX_ID) or - (WebsiteID = XXCOMICS_ID) or - (WebsiteID = XXCOMICSMT_ID) or - (WebsiteID = XXCOMICS3D_ID) or - (WebsiteID = PORNCOMIXRE_ID) or - (WebsiteID = PORNCOMIXIC_ID) or - (WebsiteID = PORNXXXCOMICS_ID) then - Result := PornComixGetNamesAndLinks(GetMangaSiteID(AWebsite)) - else if WebsiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks else @@ -1298,8 +1276,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/MangaHost/manga_information.inc} - {$I includes/PornComix/manga_information.inc} - {$I includes/MangaKu/manga_information.inc} {$I includes/MangaAt/manga_information.inc} @@ -1460,15 +1436,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if WebsiteID = MANGAHOST_ID then Result := GetMangaHostInfoFromURL else - if (WebsiteID = PORNCOMIX_ID) or - (WebsiteID = XXCOMICS_ID) or - (WebsiteID = XXCOMICSMT_ID) or - (WebsiteID = XXCOMICS3D_ID) or - (WebsiteID = PORNCOMIXRE_ID) or - (WebsiteID = PORNCOMIXIC_ID) or - (WebsiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixInfoFromURL(GetMangaSiteID(AWebsite)) - else if WebsiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8a8e02089..9662ad869 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -458,8 +458,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaHost/chapter_page_number.inc} - {$I includes/PornComix/chapter_page_number.inc} - {$I includes/MangaKu/chapter_page_number.inc} {$I includes/MangaAt/chapter_page_number.inc} @@ -563,15 +561,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostPageNumber else - if (Task.Container.MangaSiteID = PORNCOMIX_ID) or - (Task.Container.MangaSiteID = XXCOMICS_ID) or - (Task.Container.MangaSiteID = XXCOMICSMT_ID) or - (Task.Container.MangaSiteID = XXCOMICS3D_ID) or - (Task.Container.MangaSiteID = PORNCOMIXRE_ID) or - (Task.Container.MangaSiteID = PORNCOMIXIC_ID) or - (Task.Container.MangaSiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixPageNumber(Task.Container.MangaSiteID) - else if Task.Container.MangaSiteID = MANGAKU_ID then Result := GetMangaKuPageNumber else @@ -664,8 +653,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaHost/image_url.inc} - {$I includes/PornComix/image_url.inc} - {$I includes/MangaAt/image_url.inc} begin @@ -789,15 +776,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostImageURL else - if (Task.Container.MangaSiteID = PORNCOMIX_ID) or - (Task.Container.MangaSiteID = XXCOMICS_ID) or - (Task.Container.MangaSiteID = XXCOMICSMT_ID) or - (Task.Container.MangaSiteID = XXCOMICS3D_ID) or - (Task.Container.MangaSiteID = PORNCOMIXRE_ID) or - (Task.Container.MangaSiteID = PORNCOMIXIC_ID) or - (Task.Container.MangaSiteID = PORNXXXCOMICS_ID) then - Result := GetPornComixImageURL - else if Task.Container.MangaSiteID = MANGAAT_ID then Result := GetMangaAtImageURL; end; diff --git a/config/mangalist.ini b/config/mangalist.ini index 9d3dd413a..877ccd870 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -20,4 +20,4 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,PornComix,PornComixRE,PornComixIC,PornXXXComics,ReadHentaiManga,Tsumino,XXComics,XXComicsMT,XXComics3D,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU From 6b75c56e913720aa7d587894d3f665b53d8607b8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Feb 2017 09:14:20 +0800 Subject: [PATCH 1520/2794] added adult website --- baseunits/ModuleList.inc | 1 + baseunits/modules/WPAdultSiteSkins.pas | 155 +++++++++++++++++++++++++ config/mangalist.ini | 1 + 3 files changed, 157 insertions(+) create mode 100644 baseunits/modules/WPAdultSiteSkins.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index eb0312719..5640205ea 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -55,6 +55,7 @@ uses JapScan, MangaGo, GoodManga, + WPAdultSiteSkins, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas new file mode 100644 index 000000000..e3e286685 --- /dev/null +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -0,0 +1,155 @@ +unit WPAdultSiteSkins; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//div[@class="paginator"]/span[starts-with(.,"Page") and contains(.," of ")]/normalize-space(substring-after(.," of "))'),1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL; + if AURL <> '0' then + s += '/page/' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFtitleAll('//div[@class="posts"]/div[starts-with(@id,"post-")]/a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//div[@class="single-post"]//img[starts-with(@class,"attachment-") and not(@data-lazy-src)]/@src'); + if coverLink = '' then coverLink := XPathString('//div[@class="single-post"]/p/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="posts"]/h2[@class="post-title"][1]'); + chapterLinks.Add(url); + chapterName.Add(title); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + XPathStringAll('//div[@class="single-post"]//dl[@class="gallery-item"]/dt/a/@href', PageContainerLinks); + if PageContainerLinks.Count = 0 then + for v in XPath('//div[@class="single-post"]/p/img/@src') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)) + else + PageNumber := PageContainerLinks.Count; + finally + Free; + end; + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if GET(MaybeFillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkId])) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + PageLinks[DownloadThread.WorkId] := + MaybeFillHost(Module.RootURL, XPathString('//div[@class="attachment-image"]//img/@src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; + function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; + begin + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + end; +begin + AddWebsiteModule('PornComix', 'http://www.porncomix.info'); + AddWebsiteModule('Comic-XXX', 'http://comics-xxx.com'); + AddWebsiteModule('FreeAdultComix', 'http://freeadultcomix.com'); + AddWebsiteModule('AsianHotties', 'http://tits.asianhotties.me'); +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index 877ccd870..1f038a864 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -21,3 +21,4 @@ Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU +Adult=Comic-XXX,FreeAdultComix,PornComix From 3a917eeef9aa3de3c182ea0a4f5f47c512ed281a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Feb 2017 00:07:20 +0800 Subject: [PATCH 1521/2794] wpadultsiteskins, fix cover and some --- baseunits/modules/WPAdultSiteSkins.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas index e3e286685..84dd80933 100644 --- a/baseunits/modules/WPAdultSiteSkins.pas +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -64,7 +64,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with TXQueryEngineHTML.Create(Document) do try coverLink := XPathString('//div[@class="single-post"]//img[starts-with(@class,"attachment-") and not(@data-lazy-src)]/@src'); - if coverLink = '' then coverLink := XPathString('//div[@class="single-post"]/p/img/@src'); + if coverLink = '' then coverLink := XPathString('//div[@class="single-post"]/p//img[not(@data-lazy-src)]/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); if title = '' then title := XPathString('//div[@class="posts"]/h2[@class="post-title"][1]'); chapterLinks.Add(url); @@ -93,8 +93,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with TXQueryEngineHTML.Create(Document) do try XPathStringAll('//div[@class="single-post"]//dl[@class="gallery-item"]/dt/a/@href', PageContainerLinks); + XPathStringAll('//div[@class="single-post"]/p//a[./img]/@href', PageContainerLinks); if PageContainerLinks.Count = 0 then - for v in XPath('//div[@class="single-post"]/p/img/@src') do + for v in XPath('//div[@class="single-post"]/p//img[not(@data-lazy-src)]/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)) else PageNumber := PageContainerLinks.Count; @@ -111,6 +112,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if DownloadThread.WorkId >= PageContainerLinks.Count then Exit; if GET(MaybeFillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkId])) then begin Result := True; From 2f0afb71fb42e38a728d8945834efaf966448277 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Feb 2017 00:12:56 +0800 Subject: [PATCH 1522/2794] fixed error when removing running task --- baseunits/uDownloadsManager.pas | 37 +++++++++++++++++++++---------- mangadownloader/forms/frmMain.pas | 35 +++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9662ad869..4fd25b3b5 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -83,7 +83,9 @@ TTaskThread = class(THTTPThread) FCurrentMaxFileNameLength: Integer; {$ENDIF} FCurrentCustomFileName: String; + FIsForDelete: Boolean; procedure SetCurrentWorkingDir(AValue: String); + procedure SetIsForDelete(AValue: Boolean); protected procedure CheckOut; procedure Execute; override; @@ -107,6 +109,7 @@ TTaskThread = class(THTTPThread) property CurrentMaxFileNameLength: Integer read FCurrentMaxFileNameLength; // current custom filename with only %FILENAME% left intact property CurrentCustomFileName: String read FCurrentCustomFileName write FCurrentCustomFileName; + property IsForDelete: Boolean read FIsForDelete write SetIsForDelete; end; { TTaskContainer } @@ -178,7 +181,8 @@ TDownloadManager = class procedure DecStatusCount(const Status: TDownloadStatusType); procedure IncStatusCount(const Status: TDownloadStatusType); public - CS_Task: TRTLCriticalSection; + CS_Task, + CS_ItemsActiveTask: TRTLCriticalSection; Items, ItemsActiveTask: TTaskContainers; isRunningBackup, isFinishTaskAccessed, isRunningBackupDownloadedChaptersList, @@ -788,6 +792,7 @@ constructor TTaskThread.Create; inherited Create(True); Threads := TDownloadThreads.Create; FCheckAndActiveTaskFlag := True; + FIsForDelete := False; httpCookies := ''; FCurrentWorkingDir := ''; FCurrentCustomFileName := ''; @@ -986,6 +991,12 @@ procedure TTaskThread.SetCurrentWorkingDir(AValue: String); {$ENDIF} end; +procedure TTaskThread.SetIsForDelete(AValue: Boolean); +begin + if FIsForDelete = AValue then Exit; + FIsForDelete := AValue; +end; + procedure TTaskThread.CheckOut; var currentMaxThread: Integer; @@ -1356,17 +1367,17 @@ procedure TTaskThread.DoTerminate; UnlockCreateConnection; end; while Threads.Count > 0 do - Sleep(100); + Sleep(32); end; Modules.DecActiveTaskCount(Container.ModuleId); with Container do begin - Container.ReadCount := 0; - DownloadInfo.TransferRate := ''; - Manager.RemoveItemsActiveTask(Container); ThreadState := False; + Manager.RemoveItemsActiveTask(Container); Task := nil; - if not Manager.isReadyForExit then + if not (IsForDelete or Manager.isReadyForExit) then begin + Container.ReadCount := 0; + DownloadInfo.TransferRate := ''; if Status <> STATUS_STOP then begin if (WorkCounter >= PageLinks.Count) and @@ -1479,21 +1490,21 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); procedure TDownloadManager.AddItemsActiveTask(const Item: TTaskContainer); begin - EnterCriticalsection(CS_Task); + EnterCriticalsection(CS_ItemsActiveTask); try ItemsActiveTask.Add(Item); finally - LeaveCriticalsection(CS_Task); + LeaveCriticalsection(CS_ItemsActiveTask); end; end; procedure TDownloadManager.RemoveItemsActiveTask(const Item: TTaskContainer); begin - EnterCriticalsection(CS_Task); + EnterCriticalsection(CS_ItemsActiveTask); try ItemsActiveTask.Remove(Item); finally - LeaveCriticalsection(CS_Task); + LeaveCriticalsection(CS_ItemsActiveTask); end; end; @@ -1513,7 +1524,7 @@ function TDownloadManager.GetTransferRate: Integer; begin Result := 0; if ItemsActiveTask.Count = 0 then Exit; - EnterCriticalSection(CS_Task); + EnterCriticalSection(CS_ItemsActiveTask); try for i := 0 to ItemsActiveTask.Count - 1 do with ItemsActiveTask[i] do @@ -1528,7 +1539,7 @@ function TDownloadManager.GetTransferRate: Integer; end; end; finally - LeaveCriticalSection(CS_Task); + LeaveCriticalSection(CS_ItemsActiveTask); end; end; @@ -1573,6 +1584,7 @@ constructor TDownloadManager.Create; begin inherited Create; InitCriticalSection(CS_Task); + InitCriticalSection(CS_ItemsActiveTask); ForceDirectoriesUTF8(WORK_FOLDER); DownloadManagerFile := TIniFileRun.Create(WORK_FILE); DownloadedChapters := TDownloadedChaptersDB.Create; @@ -1607,6 +1619,7 @@ destructor TDownloadManager.Destroy; DownloadManagerFile.Free; ItemsActiveTask.Free; DownloadedChapters.Free; + DoneCriticalsection(CS_ItemsActiveTask); DoneCriticalsection(CS_Task); DoneCriticalsection(CS_StatusCount); inherited Destroy; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3c79666a2..23d48a884 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1713,12 +1713,30 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if MessageDlg('', RS_DlgRemoveTask, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then Exit; - EnterCriticalSection(DLManager.CS_Task); + vtDownload.BeginUpdate; try + EnterCriticalSection(DLManager.CS_Task); + // stop selected nodes xNode := vtDownload.GetPreviousSelected(nil); - while Assigned(xNode) do begin - DLManager.StopTask(xNode^.Index, False, True); - with DLManager.Items[xNode^.Index] do begin + while Assigned(xNode) do + begin + with DLManager.Items[xNode^.Index] do + if ThreadState then + begin + Task.IsForDelete := True; + Task.Terminate; + end; + xNode := vtDownload.GetPreviousSelected(xNode); + end; + // cleaning the data + xNode := vtDownload.GetPreviousSelected(nil); + while Assigned(xNode) do + begin + Exclude(xNode^.States, vsSelected); + with DLManager.Items[xNode^.Index] do + begin + if ThreadState then + Task.WaitFor; if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) and (ChapterName.Count > 0) then begin for i := 0 to ChapterName.Count - 1 do begin @@ -1753,7 +1771,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); finally FavoriteManager.LockRelease; end; - DLManager.Items[xNode^.Index].Free; + Free; DLManager.Items.Delete(xNode^.Index); end; xNode := vtDownload.GetPreviousSelected(xNode); @@ -1761,9 +1779,12 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); finally LeaveCriticalSection(DLManager.CS_Task); end; - vtDownload.ClearSelection; - DLManager.CheckAndActiveTask; + if vtDownload.RootNodeCount <> DLManager.Items.Count then + vtDownload.RootNodeCount := DLManager.Items.Count; + vtDownload.EndUpdate; UpdateVtDownload; + DLManager.CheckAndActiveTask(); + Exit; end; procedure TMainForm.miDownloadMergeCompletedClick(Sender: TObject); From a58fcf5111bc3021e4d674c2c62d2c43a25eb46a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Feb 2017 01:12:29 +0800 Subject: [PATCH 1523/2794] wpadultsiteskins, added imagehoster --- baseunits/modules/ImageHoster.pas | 35 ++++++++++++++++++++++++++ baseunits/modules/WPAdultSiteSkins.pas | 18 +++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 baseunits/modules/ImageHoster.pas diff --git a/baseunits/modules/ImageHoster.pas b/baseunits/modules/ImageHoster.pas new file mode 100644 index 000000000..c3e20aa6e --- /dev/null +++ b/baseunits/modules/ImageHoster.pas @@ -0,0 +1,35 @@ +unit ImageHoster; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, httpsendthread, XQueryEngineHTML; + +function GetImageHoster(const AHTTP: THTTPSendThread; const AURL: String): String; + +implementation + +function GetImageHoster(const AHTTP: THTTPSendThread; const AURL: String): String; +var + u: String; +begin + Result := ''; + u := Trim(LowerCase(AURL)); + if u = '' then Exit; + if Pos('imagetwist.com', u) <> 0 then + begin + AHTTP.GET(AURL); + AHTTP.GET(AURL); + with TXQueryEngineHTML.Create(AHTTP.Document) do + try + Result := XPathString('//img[@class="pic img img-responsive"]/@src'); + finally + Free; + end; + end; +end; + +end. + diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas index 84dd80933..3df7e0855 100644 --- a/baseunits/modules/WPAdultSiteSkins.pas +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML, httpsendthread, synautil, ImageHoster; implementation @@ -93,7 +93,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with TXQueryEngineHTML.Create(Document) do try XPathStringAll('//div[@class="single-post"]//dl[@class="gallery-item"]/dt/a/@href', PageContainerLinks); - XPathStringAll('//div[@class="single-post"]/p//a[./img]/@href', PageContainerLinks); + XPathStringAll('//div[@class="single-post"]/p//a[./img[not(data-lazy-src)]]/@href', PageContainerLinks); if PageContainerLinks.Count = 0 then for v in XPath('//div[@class="single-post"]/p//img[not(@data-lazy-src)]/@src') do PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)) @@ -108,23 +108,31 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if DownloadThread.WorkId >= PageContainerLinks.Count then Exit; + s := ImageHoster.GetImageHoster(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkId])); + if s = '' then if GET(MaybeFillHost(Module.RootURL, PageContainerLinks[DownloadThread.WorkId])) then begin - Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.WorkId] := - MaybeFillHost(Module.RootURL, XPathString('//div[@class="attachment-image"]//img/@src')); + s := MaybeFillHost(Module.RootURL, XPathString('//div[@class="attachment-image"]//img/@src')); finally Free; end; end; + if s <> '' then + begin + Result := True; + PageLinks[DownloadThread.WorkId] := s; + end; end; + end; procedure RegisterModule; From 1493889829e1ddc6baaaa7322fdc3cfe162ff51a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Feb 2017 13:49:31 +0800 Subject: [PATCH 1524/2794] frmmain, remove task --- mangadownloader/forms/frmMain.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 23d48a884..37b58de23 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1779,8 +1779,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); finally LeaveCriticalSection(DLManager.CS_Task); end; - if vtDownload.RootNodeCount <> DLManager.Items.Count then - vtDownload.RootNodeCount := DLManager.Items.Count; + vtDownload.RootNodeCount := DLManager.Items.Count; vtDownload.EndUpdate; UpdateVtDownload; DLManager.CheckAndActiveTask(); From 52b25a5d4372ff840236ba38c5dde119e76f54ac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Feb 2017 09:56:19 +0800 Subject: [PATCH 1525/2794] added spanish translations by Mariolr93. closed #482. --- mangadownloader/languages/fmd.es.po | 2311 +++++++++++++++++ .../languages/updater.el_GR.po | 0 updater/languages/updater.es.po | 104 + .../languages/updater.pt_BR.po | 0 4 files changed, 2415 insertions(+) create mode 100644 mangadownloader/languages/fmd.es.po rename {mangadownloader => updater}/languages/updater.el_GR.po (100%) create mode 100644 updater/languages/updater.es.po rename {mangadownloader => updater}/languages/updater.pt_BR.po (100%) diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po new file mode 100644 index 000000000..c0d757b53 --- /dev/null +++ b/mangadownloader/languages/fmd.es.po @@ -0,0 +1,2311 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: FMD Español v2\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.11\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Last-Translator: Mariolr\n" +"Language: es_419\n" + +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Mostrar todos los idiomas" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Mostrar Grupo de Scanlation" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Descargar imagen original (require una cuenta ExHentai)" + +#: ehentai.rs_settingsimagesize +msgid "Image size:" +msgstr "Tamaño de imagen:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Estás seguro que deseas eliminar esta cuenta?" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Revisando" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "Inválido" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Desconocido" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "OK" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Nombre de usuario o contraseña no puede estar vacio!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "Importar completado." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "Lista de manga sin importar" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Todas las descargas" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&OK" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "Cancelar" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Revisando..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "No se puede conectar con el servidor" + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "" +"Cannot get manga info. Please check your internet connection and try it " +"again." +msgstr "" +"No se puede obtener la información del manga. Por favor revisa tu conexión a " +"internet e inténtalo de nuevo." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Cuenta de Descarga:" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "Debes escoger al menos 1 sitio web de manga!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Estás seguro que quieres salir?" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Estás seguro de que quieres eliminar los favoritos?" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Estás seguro de que quieres eliminar todas las tareas terminadas?" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Estás seguro de querer eliminar este(os) ítem(s)?" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Estás seguro de desear eliminar la(s) tarea(s)?" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Dividir descarga" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "" +"Este título ya se encuentra en la lista de descarga\n" +"Deseas descargarlo de todos modos?\n" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Ingresar Nuevo Capitulo?" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Ingresar Nueva Ruta de Guardado :" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Actualizador está Ejecutandose!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Quieres Descargar la Lista de Manga del Servidor?" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "URL no Soportada!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "" +"Descargar Todo\n" +"Agregar a Favoritos\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "" +"Completado\n" +"En Curso\n" +"<Nada>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader está ya ejecutandose!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "" +"Hay un Problema con estos Datos!\n" +"Quitarlo y Volviendolo a Agregar Podría Resolver el Problema.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "Historial" + +#: frmmain.rs_import +msgid "Import" +msgstr "Importar" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Artista(s):" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Autor(es):" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Género(s):" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Estado:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Sinopsis:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Título:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Sitio Web:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "En Progreso" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Auto Revisar Capítulos Cada %d Minutos" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "" +"%s : Ruta al Manga\n" +"%s : Nombre del Capítulo\n" +"\n" +"Ejemplo : \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Cargando ..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Modo: Mostrar Todo (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Modo: Filtrado(%d)" + +#: frmmain.rs_modesearching +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Modo: Buscando..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "Un Mes" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "Una Semana" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "" +"Nada\n" +"Salir\n" +"Apagar\n" +"Hibernar\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Seleccionado: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Software" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Ruta al Software (e.g. C:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Hoy" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Entrada no valida!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Ayer" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "FMD Saldrá en %d segundos." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "Sistema Hibernará en %d segundos." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "Sistema se Apagará en %d segundos." + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Quitar Marca de Agua" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Guardar como PNG" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Agregar" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Eliminar" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Editar" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Actualizar" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Sitio Web" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Usuario" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Estado" + +#: taccountsetform.btcancel.caption +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Cancelar" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "Ok" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Mostar Contraseña" + +#: taccountsetform.edpassword.texthint +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Contraseña" + +#: taccountsetform.edusername.texthint +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Usuario" + +#: taccountsetform.label1.caption +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Sitio Web" + +#: taccountsetform.label2.caption +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Usuario" + +#: taccountsetform.label3.caption +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Contraseña" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "FormadeColorPersonalizada" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Lista Básica" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Lista de Capítulos" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Lista de Favoritos" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Lista de Manga" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Agregar a Favoritos" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "&Cerrar" + +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Descargar Todo" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Limpiar" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Permanecer Encima" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Limite de Registro" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Copiar" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Cancelar" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&OK" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga Downloader" + +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Ruta al Software (e.g. C:\\MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Software:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Abortar Actualizar Lista" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Agregar a Favoritos" + +#: tmainform.btchecklatestversion.caption +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Revisar Última Version" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Limpiar Archivo de Registro" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "Descargar" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Dividir Descarga" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Revisar si hay Capitulo Nuevo" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Importar Lista" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Filtro" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Reiniciar Valor" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Abrir Registro" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Aplicar" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Leer Online" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Quitar Filtro" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Quitar Filtro" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Actualizar Lista de Manga" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Visitar mi blog" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "Agregar a Descargas como Tarea Detenida" + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<nada>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Buscar Solo Manga Nuevo" + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Descarga Automática al Terminar de Revisar" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Auto Revisar si hay Nuevo Capítulo en un Intervalo" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Remover Automáticamente Manga Completado de Favoritos" + +#: tmainform.cboptionautocheckfavstartup.caption +msgid "Auto check for new chapter at startup" +msgstr "Revisar Automáticamente Nuevos Capítulos al Iniciar" + +#: tmainform.cboptionautochecklatestversion.caption +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Revisar Automáticamente la Última Versión" + +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Abrir Favoritos al Iniciar" + +#: tmainform.cboptionchangeunicodecharacter.caption +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Replace all unicode character with" +msgstr "Reemplazar todo Carácter Unicode con" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "" +"Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Capítulo" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Volumen" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Habilitar Carga de Cover (Portada)" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Generar Automáticamente Folder de Capítulo" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgid "Auto generate folder based on manga's name" +msgstr "Auto Generar Folder Basado en Nombre del Manga" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Habilitar Búsqueda en Directo (Lento en Lista Larga)" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Minimizar a Bandeja" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "Permitir Solo Ejecutar un FMD " + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Remover Nombre del Manga del Capitulo" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Borrar Tarea/Favorito" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Descargar Lista de Manga si está Vacía" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "Mostrar Barra de Herramientas de Descargas" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "Salir de FMD" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "" +"Don't load manga information when updating list (filter will be not work!)" +msgstr "" +"No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro " +"no Funcionará)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "" +"Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Usar Proxy" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Buscar en Todos Los Sitios de Manga" + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Para más Sitios de Mangas, Ve a Opciones->Sitios Manga" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Regular Expresión" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "Mostrar Drop Box" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Habilitar Registro" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Acción" + +#: tmainform.ckfilteraction.hint +msgid "" +"A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "" +"Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de " +"rápido movimiento." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Adulto" + +#: tmainform.ckfilteradult.hint +msgid "" +"Contains content that is suitable only for adults. Titles in this category " +"may include prolonged scenes of intense violence and/or graphic sexual " +"content and nudity." +msgstr "" +"Contiene contenido que es apropiado solo para adultos. Los títulos en esta " +"categoría pueden incluir prolongadas escenas de intensa violencia y/o " +"contenido sexual gráfico o desnudez." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Aventura" + +#: tmainform.ckfilteradventure.hint +msgid "" +"If a character in the story goes on a trip or along that line, your best bet " +"is that it is an adventure manga. Otherwise, it's up to your personal " +"prejudice on this case." +msgstr "" +"Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor " +"apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio " +"personal en este caso." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Comedia" + +#: tmainform.ckfiltercomedy.hint +msgid "" +"A dramatic work that is light and often humorous or satirical in tone and " +"that usually contains a happy resolution of the thematic conflict." +msgstr "" +"Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o " +"satírico y que usualmente contiene una feliz resolución del conflicto " +"temático." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Doujinshi" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Trabajos de Fans inspirados en manga/anime oficiales." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Drama" + +#: tmainform.ckfilterdrama.hint +msgid "" +"A work meant to bring on an emotional response, such as instilling sadness " +"or tension." +msgstr "" +"Un trabajo que pretende traer una respuesta emocional, tales como inculcar " +"la tristeza o tensión." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Ecchi" + +#: tmainform.ckfilterechi.hint +msgid "" +"Possibly the line between hentai and non-hentai, ecchi usually refers to " +"fanservice put in to attract a certain group of fans." +msgstr "" +"Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se " +"refiere a fanservice puesto para atraer un cierto grupo de fans." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Fantasía" + +#: tmainform.ckfilterfantasy.hint +msgid "" +"Anything that involves, but not limited to, magic, dream world, and fairy " +"tales." +msgstr "" +"Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y " +"cuentos de hadas." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Transgénero" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "" +"Chicas vistiendo como chicos, chicos vistiendo como chicas.\n" +"Chicos convirtiéndose en chicas, chicas convirtiéndose en chicos.\n" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Harem" + +#: tmainform.ckfilterharem.hint +msgid "" +"A series involving one male character and many female characters (usually " +"attracted to the male character). A Reverse Harem is when the genders are " +"reversed." +msgstr "" +"Una serie que envuelve un personaje masculino y muchos personajes femeninos " +"(generalmente atraídos por el personaje masculino). Un Harem inverso es " +"cuando los sexos se invierten." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "Historico" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Tiene que ver con viejos o antiguos tiempos." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Horror" + +#: tmainform.ckfilterhorror.hint +msgid "" +"A painful emotion of fear, dread, and abhorrence; a shuddering with terror " +"and detestation; the feeling inspired by something frightful and shocking." +msgstr "" +"Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de " +"terror y odio; el sentimiento inspirado por algo terrible e impactante." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Josei" + +#: tmainform.ckfilterjosei.hint +msgid "" +"Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. " +"Unlike shoujo the romance is more realistic and less idealized. The " +"storytelling is more explicit and mature." +msgstr "" +"Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino " +"equivalente al seinen. A diferencia de shoujo el romance es más realista y " +"menos idealizado. La narración es más explícita y madura." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Lolicon" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Representa una atracción sexual a chicas jóvenes o menores de edad." + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Artes Marciales" + +#: tmainform.ckfiltermartialarts.hint +msgid "" +"As the name suggests, anything martial arts related. Any of several arts of " +"combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, " +"fencing, and so on and so forth." +msgstr "" +"Como su nombre indica, cualquier cosa relacionada artes marciales. " +"Cualquiera de los diversos artes de combate o de autodefensa, como el " +"aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Maduro" + +#: tmainform.ckfiltermature.hint +msgid "" +"Contains subject matter which may be too extreme for people under the age of " +"17. Titles in this category may contain intense violence, blood and gore, " +"sexual content and/or strong language." +msgstr "" +"Contiene temas que pueden ser demasiado extremos para las personas menores " +"de 17. Los títulos de esta categoría pueden contener violencia intensa, " +"sangre y gore, contenido sexual y/o lenguaje fuerte." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Mecha" + +#: tmainform.ckfiltermecha.hint +msgid "" +"A work involving and usually concentrating on all types of large robotic " +"machines." +msgstr "" +"Un trabajo que involucra y por lo general se concentra en todos los tipos de " +"grandes máquinas robóticas." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Misterio" + +#: tmainform.ckfiltermystery.hint +msgid "" +"Usually an unexplained event occurs, and the main protagonist attempts to " +"find out what caused it." +msgstr "" +"Por lo general, se produce un acontecimiento inexplicable, y el protagonista " +"intenta averiguar cuál fue la causa." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Psicológico" + +#: tmainform.ckfilterpsychological.hint +msgid "" +"Usually deals with the philosophy of a state of mind, in most cases " +"detailing abnormal psychology." +msgstr "" +"Por lo general lidia con la filosofía de un estado de la mente, en la " +"mayoría de los casos que detallan la psicología anormal." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Romance" + +#: tmainform.ckfilterromance.hint +msgid "" +"Any love related story. We will define love as between man and woman in this " +"case. Other than that, it is up to your own imagination of what love is." +msgstr "" +"Cualquier historia relacionada con el amor. Vamos a definir el amor como " +"entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu " +"propia imaginación de lo que es el amor." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "Vida Escolar" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "" +"Tener un escenario importante de la historia ocupado con algún tipo de " +"escuela." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Sci-Fi (Ciencia Ficción)" + +#: tmainform.ckfilterscifi.hint +msgid "" +"Short for science fiction, these works involve twists on technology and " +"other science related phenomena which are contrary or stretches of the " +"modern day scientific world." +msgstr "" +"Abreviatura de ciencia ficción, estos trabajos implican giros en la " +"tecnología y otros fenómenos relacionados con la ciencia y que sean " +"contrarias o tramos del mundo científico de hoy en día." + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Seinen" + +#: tmainform.ckfilterseinen.hint +msgid "" +"From Google: Seinen means 'young Man'. Manga and anime that specifically " +"targets young adult males around the ages of 18 to 25 are seinen titles. The " +"stories in seinen works appeal to university students and those in the " +"working world. Typically the story lines deal with the issues of adulthood." +msgstr "" +"De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige " +"específicamente a los varones adultos jóvenes en torno a las edades de 18 a " +"25 años son títulos seinen. Las historias en las obras seinen apelan a los " +"estudiantes universitarios y los que están en el mundo laboral. Por lo " +"general las líneas de la historia se ocupan de los problemas de la edad " +"adulta." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Shotacon" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "" +"Representa una atracción sexual hacia los niños jóvenes o menores de edad." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Shoujo" + +#: tmainform.ckfiltershoujo.hint +msgid "" +"A work intended and primarily written for females. Usually involves a lot of " +"romance and strong character development." +msgstr "" +"Un trabajo destinado y dirigido principalmente a las mujeres. Por lo " +"general, implica mucho romance y fuerte desarrollo de los personajes." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Shoujo Ai" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "" +"Often synonymous with yuri, this can be thought of as somewhat less extreme. " +"\"Girl''s Love\", so to speak." +msgstr "" +"A menudo sinónimo de yuri, esto puede ser considerado como algo menos " +"extremo. \"Amor de Chicas\", por así decirlo." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Shounen" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "" +"A work intended and primarily written for males. These works usually involve " +"fighting and/or violence." +msgstr "" +"Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos " +"involucran generalmente la lucha y/o violencia." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Shounen Ai" + +#: tmainform.ckfiltershounenai.hint +msgid "" +"Often synonymous with yaoi, this can be thought of as somewhat less extreme. " +"\"Boy''s Love\", so to speak" +msgstr "" +"A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. " +"\"Amor de Chicos\", por así decirlo" + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Recuentos de la Vida" + +#: tmainform.ckfiltersliceoflife.hint +msgid "" +"As the name suggests, this genre represents day-to-day tribulations of one/" +"many character(s). These challenges/events could technically happen in real " +"life and are often -if not all the time- set in the present timeline in a " +"world that mirrors our own." +msgstr "" +"Como su nombre indica, este género representa el día a día tribulaciones de " +"uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente " +"en la vida real y no son a menudo -si todo el tiempo-, establecido en la " +"presente línea de tiempo en un mundo que refleja al nuestro." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Smut (Atrevido)" + +#: tmainform.ckfiltersmut.hint +msgid "" +"Deals with series that are considered profane or offensive, particularly " +"with regards to sexual content." +msgstr "" +"Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo " +"que respecta a contenido sexual." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Deportes" + +#: tmainform.ckfiltersports.hint +msgid "" +"As the name suggests, anything sports related. Baseball, basketball, hockey, " +"soccer, golf, and racing just to name a few." +msgstr "" +"Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, " +"baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos " +"pocos." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Sobrenatural" + +#: tmainform.ckfiltersupernatural.hint +msgid "" +"Usually entails amazing and unexplained powers or events which defy the laws " +"of physics." +msgstr "" +"Por lo general, implica sorprendentes e inexplicables poderes y eventos que " +"desafían las leyes de la física." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Tragedia" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Contiene eventos que resultan en una gran pérdida y desgracia." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Yaoi" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Este trabajo involucra generalmente relaciones íntimas entre hombres." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Yuri" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Este trabajo involucra generalmente relaciones íntimas entre mujeres." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Ingresa géneros personalizados, separados por coma." + +#: tmainform.eddownloadssearch.texthint +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Buscar Descargas..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Buscar Favoritos..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Artista" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Autor" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Filtro" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Parte de la Sinopsis" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Título" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Buscar Título..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgid "Custom rename" +msgstr "Nombre Personalizado" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Ruta de Descarga por Defecto" + +#: tmainform.edoptionexternalparams.texthint +msgctxt "tmainform.edoptionexternalparams.texthint" +msgid "External program parameters" +msgstr "Parametros de Programa Externos" + +#: tmainform.edoptionexternalpath.texthint +msgctxt "tmainform.edoptionexternalpath.texthint" +msgid "External program path" +msgstr "Ruta de Programa Externa" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Nombre Personalizado" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr "Proxy Host/IP" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Nombre Personalizado" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "Contraseña de Proxy" + +#: tmainform.edoptionport.texthint +msgid "Proxy Port" +msgstr "Puerto de Proxy" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "Usuario de Proxy" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Guardar en" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "Ingresar URL Aquí" + +#: tmainform.edwebsitessearch.texthint +msgctxt "tmainform.edwebsitessearch.texthint" +msgid "Search website..." +msgstr "Buscar Sitio Web..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Mostrar Dialogo de Confirmación para" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "Drop Box" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Programa Externo" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Favoritos" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Configuración de Proxy" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Renombrando" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Escoger la Ruta de Descarga por Defecto:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Opacidad" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Artista" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Autor" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Géneros Personalizados" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "" +"Géneros:\n" +"- Marcado: Incluir este Género.\n" +"- Desmarcado: Excluir este Género.\n" +"- En Gris: No Importa.\n" +"\n" +"Géneros Personalizados:\n" +"- Separar Múltiples Géneros con ','.\n" +"- Excluir un Género poniendo '!' o '-' al Inicio del Género.\n" +"- Ejemplo: Aventura,!Ecchi,Comedia.\n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Estado" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Sinopsis" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Título" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Archivo de Registro:" + +#: tmainform.lbmode.caption +msgid "Mode: Show all (0)" +msgstr "Modo: Mostrar Todo (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgid "Auto check for new chapter every %d minutes" +msgstr "Auto Revisar Capítulos Cada %d Minutos" + +#: tmainform.lboptionchaptercustomrename.caption +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Nombre del Capitulo:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Nombre del Sitio Web\n" +"%MANGA% : Título del Manga\n" +"%CHAPTER% : Título del Capítulo\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"%NUMBERING% : Numeración\n" +"\n" +"Nota:\n" +"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o " +"%NUMBERING%.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Tiempo de Conexión Expiró (Segundos)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Abrir Manga Usando un Programa Externo:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Parámetros:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "tmainform.lboptionexternalparamshint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Nombre del Archivo:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nombre del Sitio Web\n" +"%MANGA% : Título del Manga\n" +"%CHAPTER% : Título del Capítulo\n" +"%FILENAME% : Nombre del Archivo\n" +"\n" +"Nota:\n" +"El Nombre del Archivo debe tener al menos %FILENAME%\n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Host" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Idioma:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "Después de Finalizar la Descarga:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Nombre de la Carpeta del Manga:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nombre del Sitio Web\n" +"%MANGA% : Título del Manga\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"\n" +"Nota:\n" +"El Nombre del la Carpeta del Manga debe tener al menos %MANGA%.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Numero de Tareas de Descargas al Mismo Tiempo (Max: 8)" + +#: tmainform.lboptionmaxretry.caption +msgid "" +"Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "" +"Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre " +"reintenta)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Numero de Archivos Descargados por Tarea al Mismo Tiempo (Max: 32)" + +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "Nuevo Manga Basado en su Tiempo de Actualización (Días)" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Contraseña" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "Nivel de Compresión PDF" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (Sin Pérdida), Más Bajo = DCTEncode (Con Pérdida)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Puerto" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Tipo" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Renombrar Dígitos" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Usuario" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Guardar en:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Eliminar" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Copiar" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Cotar" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Pegar" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Pegar e Ir" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Selecionar Todo" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Deshacer" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Abortar" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Marcar Todo" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Marcar Selecionado" + +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Filtro" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "Ocultar Capitulos Descargados" + +#: tmainform.michapterlisthighlight.caption +msgid "Highlight downloaded chapters" +msgstr "Resaltar Capitulos Descargados" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Desmarcar Todo" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Desmarcar Seleccionado" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Eliminar" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Eliminar Todas las Tareas Completadas" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Solo Tarea" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Tarea + Datos" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Tarea + Datos + Favorito" + +#: tmainform.midownloaddisable.caption +msgid "Disable" +msgstr "Deshabilitar" + +#: tmainform.midownloadenable.caption +msgid "Enable" +msgstr "Habilitar" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Combinar Tareas Completadas" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Abrir Carpeta" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Abrir ..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Reanudar" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Detener" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Ver Información del Manga" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Cambiar \"Capitulo Actual\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Cambiar \"Guardar En\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Revisar si hay Capitulo Nuevo" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Eliminar" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Descargar Todo" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Abrir Carpeta" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Abrir ..." + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Detener Revisar si hay Nuevo Capitulo" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Ver Información del Manga" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Resaltar Manga Nuevo" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Agregar a Favoritos" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Eliminar" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Descargar Todo" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Ver Información del Manga" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "Después de Finalizar la Descarga" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Salir" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Salir" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Hibernar" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Nada" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Apagar" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Restaurar" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Reanudar Todo" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Mostrar Drop Box" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Detener Todo" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Descargar Todas las Listas desde el Servidor Inmediatamente" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Marcar Todo" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Todo Indeterminado" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Desmarcar Todo" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Actualizar Todas las Listas Inmediatamente" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Descargar la Lista de Manga desde el Servidor" + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Actualizar Lista de Manga" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Tener Todos los Géneros Marcados" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Tener Uno de los Géneros Marcado" + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Modo" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "Guardar Capitulos Descargados Como" + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (Sin Pérdida), Más Bajo = DCTEncode (Con Pérdida)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Eliminar Todas las Tareas Completadas" + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Reanudar Todo" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Detener Todo" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Desplegar Todo" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Expandir Todo" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "Sobre" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "Sobre FMD" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Cuentas" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Historial de Cambios" + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Conexiones" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Color Personalizado" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "Diálogos" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr "Descargas" + +#: tmainform.tsdownloadfilter.caption +msgid ">>" +msgstr ">>" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Favoritos" + +#: tmainform.tsfilter.caption +msgctxt "tmainform.tsfilter.caption" +msgid "Filter" +msgstr "Filtro" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "General" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Información del Manga" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Registro" + +#: tmainform.tsmangalist.caption +msgid "Manga List" +msgstr "Lista de Manga" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Misceláneo" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Opciones" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Guardar en" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Actualizaciones" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Ver" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Avanzado" + +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Opciones" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Sitios Web" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" +msgid "Websites" +msgstr "Sitios Web" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Manga" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Estado" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "Progreso" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Ratio de Transferencia" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Sitio Web" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Guardar en" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Agregado" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Título" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Capítulo Actual" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Sitio Web" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Guardar en" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "&Cancelar" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "&Descargar" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "&Agregar a Cola" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "&Abortar" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "&Ahora" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "&Después" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "&Actualizar" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "" +"¡Nueva Versión Encontrada! ¿Quieres Actualizar Ahora?\n" +"FMD se Cerrará para Terminar la Actualización.\n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Agregar" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Editar" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Eliminar" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Numero de Pagina del Directorio" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Descargas" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Maximos Hilos por Tarea" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Numero de Hilos" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Actualizar Lista" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "Agente de Usuario" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Sitio Web" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "" +"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Sitio Web" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "" +"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Valor" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0]." +"text" +msgid "Website" +msgstr "Sitio Web" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1]." +"text" +msgid "Value" +msgstr "Valor" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Sitio Web" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Valor" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Sitio Web" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "Agente de Usuario" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Seleccionar un Sitio Web" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Comprimiendo..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Deshabilitado" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "Descargando" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Fallido" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Falló en Crear Directorio" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Fallido, Intenta Reanudar Esta Tarea!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Completado" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Preparando" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Detenido" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Esperando..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "&Agregar a Cola" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "&Cancelar" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Revisar si hay Capitulo Nuevo" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "&Descargar" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "&Remover" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "Encontrado %d Manga Completado" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "Revisar Favoritos está Ejecutándose!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d Manga(s) Tiene Nuevo(s) Capitulo(s)" + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "%s <%s> Tienen %d Nuevo(s) Capitulo(s)." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "Manga Completado será Removido:" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "Encontrado %d Nuevo Capitulo de %d Manga(s):" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Cargando: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Revisar si hay Nueva Versión" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "Versión Instalada" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Última Versión" + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Nueva Versión Encontrada!" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "%s Tiene %d Nuevo(s) Manga(s)" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Obteniendo Directorio" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Obteniendo Información" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Obteniendo Lista Para" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Indexando Nuevo(s) Título(s)" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Buscando Nuevo(s) Título(s)" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Buscando Nuevo(s) Título(s) desde Otro Directorio" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Preparando" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Removiendo Duplicado de los Datos Actuales" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Removiendo Duplicado de Datos Locales" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Removiendo Duplicado de Nuevo(s) Título(s)" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Guardando Datos" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Sincronizando Datos" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Actualizando Lista" diff --git a/mangadownloader/languages/updater.el_GR.po b/updater/languages/updater.el_GR.po similarity index 100% rename from mangadownloader/languages/updater.el_GR.po rename to updater/languages/updater.el_GR.po diff --git a/updater/languages/updater.es.po b/updater/languages/updater.es.po new file mode 100644 index 000000000..f640aea5b --- /dev/null +++ b/updater/languages/updater.es.po @@ -0,0 +1,104 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: updater.es\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Mariolr\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"X-Generator: Poedit 1.8.11\n" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Tamaño del Archivo" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Esperando..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Ratio de Transferencia" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Ayuda" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "No se Puede Extraer Archivo porque 7za.exe no se Encontró!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "Un Error Ocurrió Cuando se Trató de Descargar el Archivo." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "Descargando [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Error al Guardar Archivo, Revisa tu Antivirus!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Error al Descargar Archivo!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Error al Cargar la Página!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Archivo no Encontrado!" + +#: umain.rs_finished +msgid "Finished." +msgstr "Terminado." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "URL no válida!" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Cargando Página..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Redirigido..." + +#: umain.rs_response +msgid "Response" +msgstr "Respuesta" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "Reintentando Descargar [%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Reintentando Cargar Página [%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Guardando Archivo... " + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Error de Respuesta del Servidor!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(Desconocido)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Extrayendo Archivo [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Esperando Aplicación Principal que se Cierre..." diff --git a/mangadownloader/languages/updater.pt_BR.po b/updater/languages/updater.pt_BR.po similarity index 100% rename from mangadownloader/languages/updater.pt_BR.po rename to updater/languages/updater.pt_BR.po From fb9b1ffff26dbbd572184b9d82b9fa8d9d149604 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Feb 2017 13:48:04 +0800 Subject: [PATCH 1526/2794] fixed save and load drop box --- mangadownloader/forms/frmDropTarget.lfm | 1 + mangadownloader/forms/frmDropTarget.pas | 2 +- mangadownloader/forms/frmMain.pas | 11 ++++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mangadownloader/forms/frmDropTarget.lfm b/mangadownloader/forms/frmDropTarget.lfm index c84a7f8ff..03e202be9 100644 --- a/mangadownloader/forms/frmDropTarget.lfm +++ b/mangadownloader/forms/frmDropTarget.lfm @@ -18,6 +18,7 @@ object FormDropTarget: TFormDropTarget OnMouseMove = FormMouseMove OnMouseUp = FormMouseUp OnShow = FormShow + LCLVersion = '1.7' Visible = False object shBorder: TShape Left = 0 diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 45a8f7629..9b057709e 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -256,7 +256,7 @@ procedure TFormDropTarget.FormClose(Sender: TObject; FHeight := Height; FLeft := Left; FTop := Top; - MainForm.SaveDropTargetFormInformation(True); + MainForm.SaveDropTargetFormInformation; CloseAction := caFree; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 37b58de23..d56a81a6d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -695,7 +695,7 @@ TMainForm = class(TForm) // drop target procedure ShowDropTarget(const AShow: Boolean); - procedure SaveDropTargetFormInformation(const isClose: Boolean = False); + procedure SaveDropTargetFormInformation; // load language from file procedure CollectLanguagesFromFiles; @@ -4684,7 +4684,8 @@ procedure TMainForm.SaveOptions; // view WriteBool('view', 'ShowDownloadsToolbar', cbOptionShowDownloadToolbar.Checked); WriteBool('view', 'LoadMangaCover', cbOptionEnableLoadCover.Checked); - SaveDropTargetFormInformation; + if not (isExiting and Assigned(FormDropTarget)) then + SaveDropTargetFormInformation; // connections WriteInteger('connections', 'NumberOfTasks', seOptionMaxParallel.Value); @@ -5285,6 +5286,7 @@ procedure TMainForm.SaveFormInformation; procedure TMainForm.ShowDropTarget(const AShow: Boolean); begin + ckDropTarget.Checked := AShow; configfile.WriteBool('droptarget', 'Show', AShow); if AShow then begin @@ -5301,12 +5303,11 @@ procedure TMainForm.ShowDropTarget(const AShow: Boolean); end; end; -procedure TMainForm.SaveDropTargetFormInformation(const isClose: Boolean); +procedure TMainForm.SaveDropTargetFormInformation; begin with configfile do begin - if isClose then - WriteBool('droptarget', 'Show', False); + WriteBool('droptarget', 'Show', ckDropTarget.Checked); WriteInteger('droptarget', 'Mode', rgDropTargetMode.ItemIndex); WriteInteger('droptarget', 'Opacity', frmDropTarget.FAlphaBlendValue); WriteInteger('droptarget', 'Width', frmDropTarget.FWidth); From ca36242cf0a542a75a6514790cf315471f959f95 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Feb 2017 11:51:08 +0800 Subject: [PATCH 1527/2794] ehentai max conn were capped to 2 --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index e5abb97a1..d54976ca7 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -418,7 +418,7 @@ procedure RegisterModule; Website := AWebsite; RootURL := ARootURL; MaxTaskLimit := 1; - MaxConnectionLimit := 4; + MaxConnectionLimit := 2; SortedList := True; DynamicPageLink := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; From 5b4bb31a34870bf6746c716856f0b7724461db3f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Feb 2017 12:44:55 +0800 Subject: [PATCH 1528/2794] added option to show delete all completed task in toolbar --- mangadownloader/forms/frmMain.lfm | 23 +- mangadownloader/forms/frmMain.lrj | 2 + mangadownloader/forms/frmMain.pas | 7 +- mangadownloader/languages/fmd.el_GR.po | 8 + mangadownloader/languages/fmd.en.po | 8 + mangadownloader/languages/fmd.es.po | 301 +++++++------------------ mangadownloader/languages/fmd.id_ID.po | 8 + mangadownloader/languages/fmd.pl_PL.po | 8 + mangadownloader/languages/fmd.po | 8 + mangadownloader/languages/fmd.pt_BR.po | 94 ++++++-- mangadownloader/md.lpi | 2 +- 11 files changed, 224 insertions(+), 245 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0a60d6f77..c75fe1b21 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -15,7 +15,6 @@ object MainForm: TMainForm Position = poScreenCenter ShowHint = True LCLVersion = '1.7' - Visible = False object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -38,13 +37,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 4 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -249,7 +248,7 @@ object MainForm: TMainForm ImageIndex = 7 OnClick = tbDownloadStopAllClick end - object ToolButton1: TToolButton + object tbSeparator1: TToolButton Left = 153 Height = 25 Top = 0 @@ -2179,10 +2178,10 @@ object MainForm: TMainForm Height = 415 Top = 8 Width = 539 - ActivePage = tsGeneral + ActivePage = tsView Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 1 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -2531,13 +2530,23 @@ object MainForm: TMainForm object cbOptionEnableLoadCover: TCheckBox Left = 4 Height = 19 - Top = 200 + Top = 223 Width = 523 Align = alTop Caption = 'Enable load manga cover' ParentFont = False TabOrder = 2 end + object cbOptionShowDownloadToolbarDeleteAll: TCheckBox + Left = 4 + Height = 19 + Top = 200 + Width = 523 + Align = alTop + Caption = 'Show "Delete all completed tasks" in downloads toolbar' + ParentFont = False + TabOrder = 3 + end end object tsConnections: TTabSheet Caption = 'Connections' diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 179644a1a..98e15a905 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -1,4 +1,5 @@ {"version":1,"strings":[ +{"hash":57972706,"name":"tmainform.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Free Manga Downloader"}, {"hash":240327891,"name":"tmainform.tsdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, {"hash":5473489,"name":"tmainform.vtdownload.header.columns[0].text","sourcebytes":[77,97,110,103,97],"value":"Manga"}, {"hash":95062979,"name":"tmainform.vtdownload.header.columns[1].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, @@ -151,6 +152,7 @@ {"hash":107454697,"name":"tmainform.lbdroptargetopacity.caption","sourcebytes":[79,112,97,99,105,116,121],"value":"Opacity"}, {"hash":345509,"name":"tmainform.rgdroptargetmode.caption","sourcebytes":[77,111,100,101],"value":"Mode"}, {"hash":117603058,"name":"tmainform.cboptionenableloadcover.caption","sourcebytes":[69,110,97,98,108,101,32,108,111,97,100,32,109,97,110,103,97,32,99,111,118,101,114],"value":"Enable load manga cover"}, +{"hash":150918338,"name":"tmainform.cboptionshowdownloadtoolbardeleteall.caption","sourcebytes":[83,104,111,119,32,34,68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115,34,32,105,110,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show \"Delete all completed tasks\" in downloads toolbar"}, {"hash":199270675,"name":"tmainform.tsconnections.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,115],"value":"Connections"}, {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d56a81a6d..97488c59a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -57,6 +57,7 @@ TMainForm = class(TForm) cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadMangalistDialog: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; + cbOptionShowDownloadToolbarDeleteAll: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; cbOptionDigitVolume: TCheckBox; cbOptionDigitChapter: TCheckBox; @@ -353,7 +354,7 @@ TMainForm = class(TForm) ToolBarDownload: TToolBar; tbDownloadResumeAll: TToolButton; tbDownloadStopAll: TToolButton; - ToolButton1: TToolButton; + tbSeparator1: TToolButton; tbDownloadDeleteCompleted: TToolButton; tvDownloadFilter: TTreeView; tsDownloadFilter: TTabSheet; @@ -4544,6 +4545,7 @@ procedure TMainForm.LoadOptions; // view cbOptionShowDownloadToolbar.Checked := ReadBool('view', 'ShowDownloadsToolbar', True); + cbOptionShowDownloadToolbarDeleteAll.Checked := ReadBool('view', 'ShowDownloadsToolbarDeleteAll', False); cbOptionEnableLoadCover.Checked := ReadBool('view', 'LoadMangaCover', True); ckDropTarget.Checked := ReadBool('droptarget', 'Show', False); frmDropTarget.FWidth := ReadInteger('droptarget', 'Width', frmDropTarget.FWidth); @@ -4683,6 +4685,7 @@ procedure TMainForm.SaveOptions; // view WriteBool('view', 'ShowDownloadsToolbar', cbOptionShowDownloadToolbar.Checked); + WriteBool('view', 'ShowDownloadsToolbarDeleteAll', cbOptionShowDownloadToolbarDeleteAll.Checked); WriteBool('view', 'LoadMangaCover', cbOptionEnableLoadCover.Checked); if not (isExiting and Assigned(FormDropTarget)) then SaveDropTargetFormInformation; @@ -4822,6 +4825,8 @@ procedure TMainForm.ApplyOptions; //view ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; + tbDownloadDeleteCompleted.Visible := cbOptionShowDownloadToolbarDeleteAll.Checked; + tbSeparator1.Visible := tbDownloadDeleteCompleted.Visible; ShowDropTarget(ckDropTarget.Checked); //connection diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index a680e6102..4334db5b9 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -571,6 +571,10 @@ msgstr "Ενημέρωση λίστας manga" msgid "Visit my blog" msgstr "Επίσκεψη στο blog μου" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Προσθήκη στη λίστα λήψης ως διακοπείσα εργασία" @@ -675,6 +679,10 @@ msgstr "Λήψη λίστας manga εάν είναι κενή" msgid "Show downloads toolbar" msgstr "Εμφάνιση εργαλειοθήκης λήψεων" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Έξοδος του FMD" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 001ee2137..c19171cd8 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -567,6 +567,10 @@ msgstr "Update manga list" msgid "Visit my blog" msgstr "Visit my blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Add to download list as stopped task" @@ -671,6 +675,10 @@ msgstr "Download manga list if empty" msgid "Show downloads toolbar" msgstr "Show downloads toolbar" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "Show \"Delete all completed tasks\" in downloads toolbar" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Exit FMD" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index c0d757b53..94ec2f035 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -101,12 +101,8 @@ msgid "Cannot connect to the server." msgstr "No se puede conectar con el servidor" #: frmmain.rs_dlgcannotgetmangainfo -msgid "" -"Cannot get manga info. Please check your internet connection and try it " -"again." -msgstr "" -"No se puede obtener la información del manga. Por favor revisa tu conexión a " -"internet e inténtalo de nuevo." +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "No se puede obtener la información del manga. Por favor revisa tu conexión a internet e inténtalo de nuevo." #: frmmain.rs_dlgdownloadcount msgid "Download count:" @@ -562,6 +558,10 @@ msgstr "Actualizar Lista de Manga" msgid "Visit my blog" msgstr "Visitar mi blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Agregar a Descargas como Tarea Detenida" @@ -608,8 +608,7 @@ msgstr "Reemplazar todo Carácter Unicode con" #: tmainform.cboptionchangeunicodecharacter.hint msgid "Enable this if you have problem with unicode character in path." -msgstr "" -"Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" +msgstr "Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -664,21 +663,21 @@ msgstr "Descargar Lista de Manga si está Vacía" msgid "Show downloads toolbar" msgstr "Mostrar Barra de Herramientas de Descargas" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Salir de FMD" #: tmainform.cboptionupdatelistnomangainfo.caption -msgid "" -"Don't load manga information when updating list (filter will be not work!)" -msgstr "" -"No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro " -"no Funcionará)" +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro no Funcionará)" #: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption msgid "Remove duplicate local data when updating manga list" -msgstr "" -"Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" +msgstr "Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" #: tmainform.cboptionuseproxy.caption msgid "Use proxy" @@ -710,52 +709,32 @@ msgid "Action" msgstr "Acción" #: tmainform.ckfilteraction.hint -msgid "" -"A work typically depicting fighting, violence, chaos, and fast paced motion." -msgstr "" -"Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de " -"rápido movimiento." +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de rápido movimiento." #: tmainform.ckfilteradult.caption msgid "Adult" msgstr "Adulto" #: tmainform.ckfilteradult.hint -msgid "" -"Contains content that is suitable only for adults. Titles in this category " -"may include prolonged scenes of intense violence and/or graphic sexual " -"content and nudity." -msgstr "" -"Contiene contenido que es apropiado solo para adultos. Los títulos en esta " -"categoría pueden incluir prolongadas escenas de intensa violencia y/o " -"contenido sexual gráfico o desnudez." +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Contiene contenido que es apropiado solo para adultos. Los títulos en esta categoría pueden incluir prolongadas escenas de intensa violencia y/o contenido sexual gráfico o desnudez." #: tmainform.ckfilteradventure.caption msgid "Adventure" msgstr "Aventura" #: tmainform.ckfilteradventure.hint -msgid "" -"If a character in the story goes on a trip or along that line, your best bet " -"is that it is an adventure manga. Otherwise, it's up to your personal " -"prejudice on this case." -msgstr "" -"Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor " -"apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio " -"personal en este caso." +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio personal en este caso." #: tmainform.ckfiltercomedy.caption msgid "Comedy" msgstr "Comedia" #: tmainform.ckfiltercomedy.hint -msgid "" -"A dramatic work that is light and often humorous or satirical in tone and " -"that usually contains a happy resolution of the thematic conflict." -msgstr "" -"Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o " -"satírico y que usualmente contiene una feliz resolución del conflicto " -"temático." +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o satírico y que usualmente contiene una feliz resolución del conflicto temático." #: tmainform.ckfilterdoujinshi.caption msgid "Doujinshi" @@ -770,36 +749,24 @@ msgid "Drama" msgstr "Drama" #: tmainform.ckfilterdrama.hint -msgid "" -"A work meant to bring on an emotional response, such as instilling sadness " -"or tension." -msgstr "" -"Un trabajo que pretende traer una respuesta emocional, tales como inculcar " -"la tristeza o tensión." +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Un trabajo que pretende traer una respuesta emocional, tales como inculcar la tristeza o tensión." #: tmainform.ckfilterechi.caption msgid "Ecchi" msgstr "Ecchi" #: tmainform.ckfilterechi.hint -msgid "" -"Possibly the line between hentai and non-hentai, ecchi usually refers to " -"fanservice put in to attract a certain group of fans." -msgstr "" -"Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se " -"refiere a fanservice puesto para atraer un cierto grupo de fans." +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se refiere a fanservice puesto para atraer un cierto grupo de fans." #: tmainform.ckfilterfantasy.caption msgid "Fantasy" msgstr "Fantasía" #: tmainform.ckfilterfantasy.hint -msgid "" -"Anything that involves, but not limited to, magic, dream world, and fairy " -"tales." -msgstr "" -"Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y " -"cuentos de hadas." +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y cuentos de hadas." #: tmainform.ckfiltergenderbender.caption msgid "Gender Bender" @@ -818,14 +785,8 @@ msgid "Harem" msgstr "Harem" #: tmainform.ckfilterharem.hint -msgid "" -"A series involving one male character and many female characters (usually " -"attracted to the male character). A Reverse Harem is when the genders are " -"reversed." -msgstr "" -"Una serie que envuelve un personaje masculino y muchos personajes femeninos " -"(generalmente atraídos por el personaje masculino). Un Harem inverso es " -"cuando los sexos se invierten." +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "Una serie que envuelve un personaje masculino y muchos personajes femeninos (generalmente atraídos por el personaje masculino). Un Harem inverso es cuando los sexos se invierten." #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -850,26 +811,16 @@ msgid "Horror" msgstr "Horror" #: tmainform.ckfilterhorror.hint -msgid "" -"A painful emotion of fear, dread, and abhorrence; a shuddering with terror " -"and detestation; the feeling inspired by something frightful and shocking." -msgstr "" -"Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de " -"terror y odio; el sentimiento inspirado por algo terrible e impactante." +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de terror y odio; el sentimiento inspirado por algo terrible e impactante." #: tmainform.ckfilterjosei.caption msgid "Josei" msgstr "Josei" #: tmainform.ckfilterjosei.hint -msgid "" -"Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. " -"Unlike shoujo the romance is more realistic and less idealized. The " -"storytelling is more explicit and mature." -msgstr "" -"Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino " -"equivalente al seinen. A diferencia de shoujo el romance es más realista y " -"menos idealizado. La narración es más explícita y madura." +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino equivalente al seinen. A diferencia de shoujo el romance es más realista y menos idealizado. La narración es más explícita y madura." #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -884,40 +835,24 @@ msgid "Martial Arts" msgstr "Artes Marciales" #: tmainform.ckfiltermartialarts.hint -msgid "" -"As the name suggests, anything martial arts related. Any of several arts of " -"combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, " -"fencing, and so on and so forth." -msgstr "" -"Como su nombre indica, cualquier cosa relacionada artes marciales. " -"Cualquiera de los diversos artes de combate o de autodefensa, como el " -"aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "Como su nombre indica, cualquier cosa relacionada artes marciales. Cualquiera de los diversos artes de combate o de autodefensa, como el aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." #: tmainform.ckfiltermature.caption msgid "Mature" msgstr "Maduro" #: tmainform.ckfiltermature.hint -msgid "" -"Contains subject matter which may be too extreme for people under the age of " -"17. Titles in this category may contain intense violence, blood and gore, " -"sexual content and/or strong language." -msgstr "" -"Contiene temas que pueden ser demasiado extremos para las personas menores " -"de 17. Los títulos de esta categoría pueden contener violencia intensa, " -"sangre y gore, contenido sexual y/o lenguaje fuerte." +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "Contiene temas que pueden ser demasiado extremos para las personas menores de 17. Los títulos de esta categoría pueden contener violencia intensa, sangre y gore, contenido sexual y/o lenguaje fuerte." #: tmainform.ckfiltermecha.caption msgid "Mecha" msgstr "Mecha" #: tmainform.ckfiltermecha.hint -msgid "" -"A work involving and usually concentrating on all types of large robotic " -"machines." -msgstr "" -"Un trabajo que involucra y por lo general se concentra en todos los tipos de " -"grandes máquinas robóticas." +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Un trabajo que involucra y por lo general se concentra en todos los tipos de grandes máquinas robóticas." #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -934,37 +869,24 @@ msgid "Mystery" msgstr "Misterio" #: tmainform.ckfiltermystery.hint -msgid "" -"Usually an unexplained event occurs, and the main protagonist attempts to " -"find out what caused it." -msgstr "" -"Por lo general, se produce un acontecimiento inexplicable, y el protagonista " -"intenta averiguar cuál fue la causa." +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Por lo general, se produce un acontecimiento inexplicable, y el protagonista intenta averiguar cuál fue la causa." #: tmainform.ckfilterpsychological.caption msgid "Psychological" msgstr "Psicológico" #: tmainform.ckfilterpsychological.hint -msgid "" -"Usually deals with the philosophy of a state of mind, in most cases " -"detailing abnormal psychology." -msgstr "" -"Por lo general lidia con la filosofía de un estado de la mente, en la " -"mayoría de los casos que detallan la psicología anormal." +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Por lo general lidia con la filosofía de un estado de la mente, en la mayoría de los casos que detallan la psicología anormal." #: tmainform.ckfilterromance.caption msgid "Romance" msgstr "Romance" #: tmainform.ckfilterromance.hint -msgid "" -"Any love related story. We will define love as between man and woman in this " -"case. Other than that, it is up to your own imagination of what love is." -msgstr "" -"Cualquier historia relacionada con el amor. Vamos a definir el amor como " -"entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu " -"propia imaginación de lo que es el amor." +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Cualquier historia relacionada con el amor. Vamos a definir el amor como entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu propia imaginación de lo que es el amor." #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -972,41 +894,23 @@ msgstr "Vida Escolar" #: tmainform.ckfilterschoollife.hint msgid "Having a major setting of the story deal with some type of school." -msgstr "" -"Tener un escenario importante de la historia ocupado con algún tipo de " -"escuela." +msgstr "Tener un escenario importante de la historia ocupado con algún tipo de escuela." #: tmainform.ckfilterscifi.caption msgid "Sci-Fi" msgstr "Sci-Fi (Ciencia Ficción)" #: tmainform.ckfilterscifi.hint -msgid "" -"Short for science fiction, these works involve twists on technology and " -"other science related phenomena which are contrary or stretches of the " -"modern day scientific world." -msgstr "" -"Abreviatura de ciencia ficción, estos trabajos implican giros en la " -"tecnología y otros fenómenos relacionados con la ciencia y que sean " -"contrarias o tramos del mundo científico de hoy en día." +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Abreviatura de ciencia ficción, estos trabajos implican giros en la tecnología y otros fenómenos relacionados con la ciencia y que sean contrarias o tramos del mundo científico de hoy en día." #: tmainform.ckfilterseinen.caption msgid "Seinen" msgstr "Seinen" #: tmainform.ckfilterseinen.hint -msgid "" -"From Google: Seinen means 'young Man'. Manga and anime that specifically " -"targets young adult males around the ages of 18 to 25 are seinen titles. The " -"stories in seinen works appeal to university students and those in the " -"working world. Typically the story lines deal with the issues of adulthood." -msgstr "" -"De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige " -"específicamente a los varones adultos jóvenes en torno a las edades de 18 a " -"25 años son títulos seinen. Las historias en las obras seinen apelan a los " -"estudiantes universitarios y los que están en el mundo laboral. Por lo " -"general las líneas de la historia se ocupan de los problemas de la edad " -"adulta." +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige específicamente a los varones adultos jóvenes en torno a las edades de 18 a 25 años son títulos seinen. Las historias en las obras seinen apelan a los estudiantes universitarios y los que están en el mundo laboral. Por lo general las líneas de la historia se ocupan de los problemas de la edad adulta." #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -1014,20 +918,15 @@ msgstr "Shotacon" #: tmainform.ckfiltershotacon.hint msgid "Representing a sexual attraction to young or under-age boys." -msgstr "" -"Representa una atracción sexual hacia los niños jóvenes o menores de edad." +msgstr "Representa una atracción sexual hacia los niños jóvenes o menores de edad." #: tmainform.ckfiltershoujo.caption msgid "Shoujo" msgstr "Shoujo" #: tmainform.ckfiltershoujo.hint -msgid "" -"A work intended and primarily written for females. Usually involves a lot of " -"romance and strong character development." -msgstr "" -"Un trabajo destinado y dirigido principalmente a las mujeres. Por lo " -"general, implica mucho romance y fuerte desarrollo de los personajes." +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Un trabajo destinado y dirigido principalmente a las mujeres. Por lo general, implica mucho romance y fuerte desarrollo de los personajes." #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -1035,12 +934,8 @@ msgstr "Shoujo Ai" #: tmainform.ckfiltershoujoai.hint msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" -msgid "" -"Often synonymous with yuri, this can be thought of as somewhat less extreme. " -"\"Girl''s Love\", so to speak." -msgstr "" -"A menudo sinónimo de yuri, esto puede ser considerado como algo menos " -"extremo. \"Amor de Chicas\", por así decirlo." +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "A menudo sinónimo de yuri, esto puede ser considerado como algo menos extremo. \"Amor de Chicas\", por así decirlo." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -1048,77 +943,48 @@ msgstr "Shounen" #: tmainform.ckfiltershounen.hint msgctxt "tmainform.ckfiltershounen.hint" -msgid "" -"A work intended and primarily written for males. These works usually involve " -"fighting and/or violence." -msgstr "" -"Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos " -"involucran generalmente la lucha y/o violencia." +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos involucran generalmente la lucha y/o violencia." #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" msgstr "Shounen Ai" #: tmainform.ckfiltershounenai.hint -msgid "" -"Often synonymous with yaoi, this can be thought of as somewhat less extreme. " -"\"Boy''s Love\", so to speak" -msgstr "" -"A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. " -"\"Amor de Chicos\", por así decirlo" +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. \"Amor de Chicos\", por así decirlo" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" msgstr "Recuentos de la Vida" #: tmainform.ckfiltersliceoflife.hint -msgid "" -"As the name suggests, this genre represents day-to-day tribulations of one/" -"many character(s). These challenges/events could technically happen in real " -"life and are often -if not all the time- set in the present timeline in a " -"world that mirrors our own." -msgstr "" -"Como su nombre indica, este género representa el día a día tribulaciones de " -"uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente " -"en la vida real y no son a menudo -si todo el tiempo-, establecido en la " -"presente línea de tiempo en un mundo que refleja al nuestro." +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "Como su nombre indica, este género representa el día a día tribulaciones de uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente en la vida real y no son a menudo -si todo el tiempo-, establecido en la presente línea de tiempo en un mundo que refleja al nuestro." #: tmainform.ckfiltersmut.caption msgid "Smut" msgstr "Smut (Atrevido)" #: tmainform.ckfiltersmut.hint -msgid "" -"Deals with series that are considered profane or offensive, particularly " -"with regards to sexual content." -msgstr "" -"Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo " -"que respecta a contenido sexual." +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo que respecta a contenido sexual." #: tmainform.ckfiltersports.caption msgid "Sports" msgstr "Deportes" #: tmainform.ckfiltersports.hint -msgid "" -"As the name suggests, anything sports related. Baseball, basketball, hockey, " -"soccer, golf, and racing just to name a few." -msgstr "" -"Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, " -"baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos " -"pocos." +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos pocos." #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" msgstr "Sobrenatural" #: tmainform.ckfiltersupernatural.hint -msgid "" -"Usually entails amazing and unexplained powers or events which defy the laws " -"of physics." -msgstr "" -"Por lo general, implica sorprendentes e inexplicables poderes y eventos que " -"desafían las leyes de la física." +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Por lo general, implica sorprendentes e inexplicables poderes y eventos que desafían las leyes de la física." #: tmainform.ckfiltertragedy.caption msgid "Tragedy" @@ -1388,8 +1254,7 @@ msgstr "" "%NUMBERING% : Numeración\n" "\n" "Nota:\n" -"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o " -"%NUMBERING%.\n" +"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1480,11 +1345,8 @@ msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Numero de Tareas de Descargas al Mismo Tiempo (Max: 8)" #: tmainform.lboptionmaxretry.caption -msgid "" -"Number of retry times if tasks have download problems (-1 = always retry)" -msgstr "" -"Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre " -"reintenta)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre reintenta)" #: tmainform.lboptionmaxthread.caption msgid "Number of downloaded files per task at the same time (Max: 32)" @@ -2092,40 +1954,32 @@ msgid "Cookies" msgstr "Cookies" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text -msgctxt "" -"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text -msgctxt "" -"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0]." -"text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1]." -"text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" msgid "Value" msgstr "Valor" @@ -2309,3 +2163,4 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index c0c5e4f2d..aca471444 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -558,6 +558,10 @@ msgstr "Perbarui daftar komik" msgid "Visit my blog" msgstr "Kunjungi blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Tambahkan ke daftar unduhan tanpa dimulai" @@ -659,6 +663,10 @@ msgstr "Unduh daftar komik jika kosong" msgid "Show downloads toolbar" msgstr "Tampilkan toolbar unduhan" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "Tampilkan \"Hapus semua unduhan selesai\" di toolbar unduhan" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Tutup FMD" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 319089225..bbd27c88e 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -567,6 +567,10 @@ msgstr "Aktualizuj listę mang" msgid "Visit my blog" msgstr "Odwiedź mój blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Dodaj do listy pobieranych jako zatrzymane zadanie." @@ -671,6 +675,10 @@ msgstr "Pobierz listę mang jeżeli jest pusta" msgid "Show downloads toolbar" msgstr "Pokaż pasek pobierania" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Wyjdź z FMD" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 82054847f..7e25045d2 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -523,6 +523,10 @@ msgstr "" msgid "Visit my blog" msgstr "" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "" @@ -624,6 +628,10 @@ msgstr "" msgid "Show downloads toolbar" msgstr "" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 738772b9b..febf95875 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -38,7 +38,14 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -135,7 +142,9 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim" +msgstr "" +"Este título já está na lista de download.\n" +"Você quer baixá-lo mesmo assim\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -161,14 +170,19 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "Baixar tudo\nAdicionar aos favoritos\n" +msgstr "" +"Baixar tudo\n" +"Adicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "<none>\n" -msgstr "Completo\nEm Andamento\n<vazio>\n" +msgstr "" +"Completo\n" +"Em Andamento\n" +"<vazio>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -178,7 +192,9 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "" +"Há um problema com estes dados!\n" +"Removendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -232,7 +248,11 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" +msgstr "" +"%s : Caminho para o mangá\n" +"%s : Nome do capítulo\n" +"\n" +"Examplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -266,7 +286,11 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "Nada\nSair\nDesligar\nHibernar\n" +msgstr "" +"Nada\n" +"Sair\n" +"Desligar\n" +"Hibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -543,6 +567,10 @@ msgstr "Atualizar lista de mangá" msgid "Visit my blog" msgstr "Visite meu blog" +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "" + #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" msgstr "Adicionar download de lista como uma tarefa parada" @@ -647,6 +675,10 @@ msgstr "Baixar lista de mangá se vazia" msgid "Show downloads toolbar" msgstr "Exibir Barra de Ferramentas de Downloads" +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Sair do FMD" @@ -756,7 +788,9 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\r\nRapazes se transformando em garotas, garotas se transformando em caras" +msgstr "" +"Meninas vestindo-se como caras, caras vestir-se como meninas.r\n" +"Rapazes se transformando em garotas, garotas se transformando em caras\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1167,7 +1201,16 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "Géneros:\r\n- Marcado: Inclua este gênero.\r\n- Desmarcado: exclua esse gênero.\r\n- Cinzento: Não importa.\r\n\r\nGéneros Personalizados:\r\n- Separar vários gêneros com ','.\r\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\r\n- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "" +"Géneros:r\n" +"- Marcado: Inclua este gênero.r\n" +"- Desmarcado: exclua esse gênero.r\n" +"- Cinzento: Não importa.r\n" +"r\n" +"Géneros Personalizados:r\n" +"- Separar vários gêneros com ','.r\n" +"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.r\n" +"- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1220,7 +1263,16 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Nome doWebsite\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do capítulo\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"%NUMBERING% : Número\n" +"\n" +"Nota:\n" +"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1257,7 +1309,14 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do Capítulo\n" +"%FILENAME% : Nome do arquivo\n" +"\n" +"Nota:\n" +"Nome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1290,7 +1349,14 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"\n" +"Nota:\n" +"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time (Max: 8)" @@ -1847,7 +1913,9 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" +msgstr "" +"Nova versão encontrada! Você quer atualizar agora?\n" +"FMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "twebsiteoptionadvancedform.menuitem1.caption" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2a5432929..2e591d403 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="89"/> + <RevisionNr Value="90"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> From 3bedc2667432f7f530894e98227a499611988094 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Feb 2017 12:55:01 +0800 Subject: [PATCH 1529/2794] Bump version 0.9.90.0 --- changelog.txt | 7 +++++-- update | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index d32de4ebd..af4f88b4a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,10 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.90.0 (--2017) +0.9.90.0 (16-02-2017) [+] Added Portuguese (Brazil) translation by Havokdan [+] Added Greek translation by geogeo_gr -Full changes: https://github.com/riderkick/FMD/compare/0.9.88.0...0.9.89.0 +[*] Fixed error when removing running download task +[*] Fixed shop drop box at startup +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.89.0...0.9.90.0 0.9.89.0 (06-02-2017) [*] E-Hentai: fixed root url diff --git a/update b/update index a577597f1..b4a1e6ccc 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.89.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.89.0/fmd_0.9.89.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.89.0/fmd_0.9.89.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.89.0/fmd_0.9.89.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.89.0/fmd_0.9.89.0_Win64.7z +VERSION=0.9.90.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.90.0/fmd_0.9.90.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.90.0/fmd_0.9.90.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.90.0/fmd_0.9.90.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.90.0/fmd_0.9.90.0_Win64.7z From 4c70517307f1cf9d072edf4274c7997709c59061 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Feb 2017 22:54:31 +0800 Subject: [PATCH 1530/2794] ehentai, fixed content warning --- baseunits/modules/EHentai.pas | 86 ++++++++++++++++------------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index d54976ca7..836d454bb 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -88,9 +88,12 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL, AWebsite: String Result := False; if Account.Enabled[accname] then begin AHTTP.FollowRedirection := False; - if AHTTP.Cookies.Count > 0 then ACookies := AHTTP.Cookies.Text - else ACookies := ''; - //AHTTP.Cookies.Text := Account.Cookies[accname]; + // force no warning + AHTTP.Cookies.Values['nw'] := '1'; + if AHTTP.Cookies.Count > 0 then + ACookies := AHTTP.Cookies.Text + else + ACookies := ''; AHTTP.Cookies.AddText(Account.Cookies[accname]); Result := AHTTP.GET(AURL); if Result and (AHTTP.ResultCode > 300) then begin @@ -161,54 +164,41 @@ function GetInfo(const MangaInfo: TMangaInformation; v: IXQValue; procedure ScanParse; - var - getOK: Boolean; begin - getOK := True; - // check content warning - if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then - begin - getOK := GETWithLogin(MangaInfo.FHTTP, MangaInfo.mangaInfo.url + '?nw=session', Module.Website); - if getOK then - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - end; - if getOK then - begin - with MangaInfo.mangaInfo do begin - //title - title := Query.XPathString('//*[@id="gn"]'); - //cover - coverLink := Query.XPathString('//*[@id="gd1"]/img/@src'); - //artists - artists := ''; - for v in Query.XPath('//a[starts-with(@id,"ta_artist")]') do - AddCommaString(artists, v.toString); - //genres - genres := ''; - for v in Query.XPath( - '//a[starts-with(@id,"ta_")and(not(starts-with(@id,"ta_artist")))]') do - AddCommaString(genres, v.toString); - //chapter - if title <> '' then begin - chapterLinks.Add(url); - chapterName.Add(title); - end; - //status - with TRegExpr.Create do - try - Expression := '(?i)[\[\(\{](wip|ongoing)[\]\)\}]'; + with MangaInfo.mangaInfo do begin + //title + title := Query.XPathString('//*[@id="gn"]'); + //cover + coverLink := Query.XPathString('//*[@id="gd1"]/img/@src'); + //artists + artists := ''; + for v in Query.XPath('//a[starts-with(@id,"ta_artist")]') do + AddCommaString(artists, v.toString); + //genres + genres := ''; + for v in Query.XPath( + '//a[starts-with(@id,"ta_")and(not(starts-with(@id,"ta_artist")))]') do + AddCommaString(genres, v.toString); + //chapter + if title <> '' then begin + chapterLinks.Add(url); + chapterName.Add(title); + end; + //status + with TRegExpr.Create do + try + Expression := '(?i)[\[\(\{](wip|ongoing)[\]\)\}]'; + if Exec(title) then + status := '1' + else + begin + Expression := '(?i)[\[\(\{]completed[\]\)\}]'; if Exec(title) then - status := '1' - else - begin - Expression := '(?i)[\[\(\{]completed[\]\)\}]'; - if Exec(title) then - status := '0'; - end; - finally - Free; + status := '0'; end; - end; + finally + Free; + end; end; end; From 19940969b395d811a83f5c3defc3ad6398cff13a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Feb 2017 23:09:09 +0800 Subject: [PATCH 1531/2794] Bump version 0.9.91.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index af4f88b4a..180d04a01 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.91.0 (16-02-2017) +[*] E-Hentai: fixed loading "Content Warning" +Full changes: https://github.com/riderkick/FMD/compare/0.9.90.0...0.9.91.0 + 0.9.90.0 (16-02-2017) [+] Added Portuguese (Brazil) translation by Havokdan [+] Added Greek translation by geogeo_gr diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2e591d403..5dc51a7f8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="90"/> + <RevisionNr Value="91"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index b4a1e6ccc..dda8b07ce 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.90.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.90.0/fmd_0.9.90.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.90.0/fmd_0.9.90.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.90.0/fmd_0.9.90.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.90.0/fmd_0.9.90.0_Win64.7z +VERSION=0.9.91.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.91.0/fmd_0.9.91.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.91.0/fmd_0.9.91.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.91.0/fmd_0.9.91.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.91.0/fmd_0.9.91.0_Win64.7z From 06289172758747ce47c45f93af7f83bd913239cb Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Fri, 17 Feb 2017 09:44:07 +0530 Subject: [PATCH 1532/2794] MangaDoor --- baseunits/modules/MangaDoor.pas | 123 ++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 baseunits/modules/MangaDoor.pas diff --git a/baseunits/modules/MangaDoor.pas b/baseunits/modules/MangaDoor.pas new file mode 100644 index 000000000..9bd2093e9 --- /dev/null +++ b/baseunits/modules/MangaDoor.pas @@ -0,0 +1,123 @@ +unit MangaDoor; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/changeMangaList?type=text'; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('//h6',v.toNode)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//*[@class="cover"]/img/@src'); + if coverLink <> '' then coverLink := coverLink; + if title = '' then title := XPathString('//h2[@class="widget-title"]'); + status := MangaInfoStatusIfPos( + XPathString('//dd[2]'), + 'Ongoing', + 'Complete'); + artists := XPathStringAll('//dd[2]/a'); + authors := XPathStringAll('//dd[3]'); + for v in XPath('//ul[@class="chapters"]/li/*/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + Cookies.Values['viewer'] := '1'; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//script[contains(.,"var pages = [")]'); + if s <> '' then + begin + s := '[' + GetBetween('var pages = [', '];', s) + ']'; + ParseHTML(s); + XPathStringAll('json(*)().page_image', PageLinks); + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaDoor'; + RootURL := 'http://mangadoor.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From 9ca4945e2b12ded4baea9a379d7cd063759deb73 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 06:43:31 +0800 Subject: [PATCH 1533/2794] added more imagehoster --- baseunits/modules/ImageHoster.pas | 32 ++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/ImageHoster.pas b/baseunits/modules/ImageHoster.pas index c3e20aa6e..8c7b347c9 100644 --- a/baseunits/modules/ImageHoster.pas +++ b/baseunits/modules/ImageHoster.pas @@ -11,23 +11,37 @@ function GetImageHoster(const AHTTP: THTTPSendThread; const AURL: String): Strin implementation +const + imghosts: array [0..2] of array [0..1] of string = ( + ('imagetwist.com', '//img[@class="pic img img-responsive"]/@src'), + ('imgchili.net', '//img[@id="show_image"]/@src'), + ('imgbox.com', '//img[@id="img"]/@src ') + ); + function GetImageHoster(const AHTTP: THTTPSendThread; const AURL: String): String; var u: String; + i: Integer; begin Result := ''; u := Trim(LowerCase(AURL)); if u = '' then Exit; - if Pos('imagetwist.com', u) <> 0 then + + for i := Low(imghosts) to High(imghosts) do begin - AHTTP.GET(AURL); - AHTTP.GET(AURL); - with TXQueryEngineHTML.Create(AHTTP.Document) do - try - Result := XPathString('//img[@class="pic img img-responsive"]/@src'); - finally - Free; - end; + if Pos(imghosts[i, 0], u) <> 0 then + begin + AHTTP.GET(AURL); + if i = 0 then + AHTTP.GET(AURL); + with TXQueryEngineHTML.Create(AHTTP.Document) do + try + Result := XPathString(imghosts[i, 1]); + finally + Free; + end; + Break; + end; end; end; From e0b7cada037c26a36d35f0c1de0be1fe8291b8bd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 06:44:36 +0800 Subject: [PATCH 1534/2794] fixed resume download also restart finished download in multiselect --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 4fd25b3b5..ca6174929 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1865,7 +1865,7 @@ procedure TDownloadManager.SetTaskActive(const taskID: Integer); begin if not Items[taskID].Enabled then Exit; with Items[taskID] do - if not ThreadState then + if not (ThreadState or (Status in [STATUS_FINISH, STATUS_WAIT])) then begin Status := STATUS_WAIT; DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Waiting]); From 981be666320f1960d2610dac5af8db890f3e8222 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 07:19:51 +0800 Subject: [PATCH 1535/2794] fixed repaint manga info --- mangadownloader/forms/frmMain.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 97488c59a..fa75af943 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4464,11 +4464,11 @@ procedure TMainForm.ShowInformation(const title, website, link: String); pcMain.ActivePage := tsInformation; FilledSaveTo; + imCover.Picture.Assign(nil); + with rmInformation do begin - imCover.Picture.Assign(nil); Clear; - if (GetInfosThread <> nil) and ((GetInfosThread.MangaListPos > -1) or (GetInfosThread.MangaListPos = -2)) then begin @@ -4477,7 +4477,6 @@ procedure TMainForm.ShowInformation(const title, website, link: String); end else edURL.Text := mangaInfo.url; - AddTextToInfo(RS_InfoTitle, mangaInfo.title); AddTextToInfo(RS_InfoAuthors, mangaInfo.authors); AddTextToInfo(RS_InfoArtists, mangaInfo.artists); @@ -4487,7 +4486,9 @@ procedure TMainForm.ShowInformation(const title, website, link: String); AddTextToInfo(RS_InfoStatus, cbFilterStatus.Items[i]); AddTextToInfo(RS_InfoSummary, mangaInfo.summary); CaretPos := Point(0, 0); + Repaint; end; + SetLength(ChapterList, mangaInfo.chapterName.Count); for i := 0 to mangaInfo.chapterName.Count - 1 do begin From 3baf8b43d58993741195a9f2ce8df0dd2030ad84 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 07:26:16 +0800 Subject: [PATCH 1536/2794] wpadultsiteskins, preserve url --- baseunits/modules/WPAdultSiteSkins.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas index 3df7e0855..31d452b4d 100644 --- a/baseunits/modules/WPAdultSiteSkins.pas +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -58,7 +58,7 @@ function GetInfo(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + url := MaybeFillHost(Module.RootURL, AURL); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -87,7 +87,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do From 96b36e25870a5bcbb3c641bbb829856f32b26671 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 08:06:37 +0800 Subject: [PATCH 1537/2794] fixed repaint manga info --- mangadownloader/forms/frmMain.pas | 44 ++++++++++++++++--------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fa75af943..a133e6863 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4467,27 +4467,29 @@ procedure TMainForm.ShowInformation(const title, website, link: String); imCover.Picture.Assign(nil); with rmInformation do - begin - Clear; - if (GetInfosThread <> nil) and - ((GetInfosThread.MangaListPos > -1) or (GetInfosThread.MangaListPos = -2)) then - begin - mangaInfo.title := title; - mangaInfo.link := link; - end - else - edURL.Text := mangaInfo.url; - AddTextToInfo(RS_InfoTitle, mangaInfo.title); - AddTextToInfo(RS_InfoAuthors, mangaInfo.authors); - AddTextToInfo(RS_InfoArtists, mangaInfo.artists); - AddTextToInfo(RS_InfoGenres, mangaInfo.genres); - i := StrToIntDef(mangaInfo.status, -1); - if (i > -1) and (i < cbFilterStatus.Items.Count) then - AddTextToInfo(RS_InfoStatus, cbFilterStatus.Items[i]); - AddTextToInfo(RS_InfoSummary, mangaInfo.summary); - CaretPos := Point(0, 0); - Repaint; - end; + try + Lines.BeginUpdate; + Lines.Clear; + if (GetInfosThread <> nil) and + ((GetInfosThread.MangaListPos > -1) or (GetInfosThread.MangaListPos = -2)) then + begin + mangaInfo.title := title; + mangaInfo.link := link; + end + else + edURL.Text := mangaInfo.url; + AddTextToInfo(RS_InfoTitle, mangaInfo.title); + AddTextToInfo(RS_InfoAuthors, mangaInfo.authors); + AddTextToInfo(RS_InfoArtists, mangaInfo.artists); + AddTextToInfo(RS_InfoGenres, mangaInfo.genres); + i := StrToIntDef(mangaInfo.status, -1); + if (i > -1) and (i < cbFilterStatus.Items.Count) then + AddTextToInfo(RS_InfoStatus, cbFilterStatus.Items[i]); + AddTextToInfo(RS_InfoSummary, mangaInfo.summary); + CaretPos := Point(0, 0); + finally + Lines.EndUpdate; + end; SetLength(ChapterList, mangaInfo.chapterName.Count); for i := 0 to mangaInfo.chapterName.Count - 1 do From 4e5a62aa1303ac6ea39b8be152a53a961da8e9f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 09:37:31 +0800 Subject: [PATCH 1538/2794] added mymangareadercms, merge komikid, mangadenizi, mangadoor here --- 3rd/BESENPkg.lpk | 1 + baseunits/ModuleList.inc | 7 +- baseunits/modules/MangaDenizi.pas | 142 ------------------ baseunits/modules/MangaDoor.pas | 123 --------------- .../{Komikid.pas => myMangaReaderCMS.pas} | 64 ++++---- 5 files changed, 37 insertions(+), 300 deletions(-) delete mode 100644 baseunits/modules/MangaDenizi.pas delete mode 100644 baseunits/modules/MangaDoor.pas rename baseunits/modules/{Komikid.pas => myMangaReaderCMS.pas} (50%) diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk index 4e9d56eec..3660bde79 100644 --- a/3rd/BESENPkg.lpk +++ b/3rd/BESENPkg.lpk @@ -20,6 +20,7 @@ <Linking> <Debugging> <GenerateDebugInfo Value="False"/> + <TrashVariables Value="True"/> </Debugging> </Linking> </CompilerOptions> diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 5640205ea..4e8f0bb46 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,7 +1,9 @@ uses FoOlSlide, - Batoto, WPManga, + myMangaReaderCMS, + WPAdultSiteSkins, + Batoto, MangaFox, Mangacan, PecintaKomik, @@ -36,7 +38,6 @@ uses MangaEden, HeyMangaXyz, WebtoonTr, - MangaDenizi, MangaSaurus, GMangaMe, SekaiManga, @@ -47,7 +48,6 @@ uses MangaPark, MangaIndo, FunManga, - Komikid, MangaOnlineTo, MyMangaMe, ReadComics, @@ -55,7 +55,6 @@ uses JapScan, MangaGo, GoodManga, - WPAdultSiteSkins, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaDenizi.pas b/baseunits/modules/MangaDenizi.pas deleted file mode 100644 index a948dc506..000000000 --- a/baseunits/modules/MangaDenizi.pas +++ /dev/null @@ -1,142 +0,0 @@ -unit MangaDenizi; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurlstart = '/filterList?page='; - dirurlend = '&cat=&alpha=&sortBy=name&asc=true&author='; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurlstart + '1' + dirurlend) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := XPath('//ul[@class="pagination"]/li').Count - 2; - if Page < 1 then - Page := 1; - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurlstart + IncStr(AURL) + dirurlend) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//h5/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do - begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//div[@class="boxed"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h2[@class="widget-title"]'); - s := XPathString('//dl[@class="dl-horizontal"]/dd[1]'); - if Pos('Devam Ediyor', s) > 0 then - status := '1' - else if Pos('Tamamlandı', s) > 0 then - status := '0'; - authors := XPathString('//dl[@class="dl-horizontal"]/dd[2]/a[1]'); - artists := XPathString('//dl[@class="dl-horizontal"]/dd[2]/a[2]'); - genres := XPathStringAll('//dl[@class="dl-horizontal"]/dd[3]/a'); - summary := XPathString('//div[@class="well"]/p'); - for v in XPath('//ul[@class="chapters"]/li//a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//div[@id="all"]/img/@data-src') do - PageLinks.Add(v.toString); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaDenizi'; - RootURL := 'http://www.mangadenizi.com'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/baseunits/modules/MangaDoor.pas b/baseunits/modules/MangaDoor.pas deleted file mode 100644 index 9bd2093e9..000000000 --- a/baseunits/modules/MangaDoor.pas +++ /dev/null @@ -1,123 +0,0 @@ -unit MangaDoor; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/changeMangaList?type=text'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('//h6',v.toNode)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//*[@class="cover"]/img/@src'); - if coverLink <> '' then coverLink := coverLink; - if title = '' then title := XPathString('//h2[@class="widget-title"]'); - status := MangaInfoStatusIfPos( - XPathString('//dd[2]'), - 'Ongoing', - 'Complete'); - artists := XPathStringAll('//dd[2]/a'); - authors := XPathStringAll('//dd[3]'); - for v in XPath('//ul[@class="chapters"]/li/*/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - Cookies.Values['viewer'] := '1'; - if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - s := XPathString('//script[contains(.,"var pages = [")]'); - if s <> '' then - begin - s := '[' + GetBetween('var pages = [', '];', s) + ']'; - ParseHTML(s); - XPathStringAll('json(*)().page_image', PageLinks); - end; - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaDoor'; - RootURL := 'http://mangadoor.com'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/baseunits/modules/Komikid.pas b/baseunits/modules/myMangaReaderCMS.pas similarity index 50% rename from baseunits/modules/Komikid.pas rename to baseunits/modules/myMangaReaderCMS.pas index f17c48a56..353b11864 100644 --- a/baseunits/modules/Komikid.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -1,4 +1,4 @@ -unit Komikid; +unit myMangaReaderCMS; {$mode objfpc}{$H+} @@ -10,26 +10,18 @@ interface implementation -const - dirurl = '/changeMangaList?type=text'; - function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/changeMangaList?type=text') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//ul[@class="manga-list"]/li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; + XPathHREFAll('//li/a', ALinks, ANames); finally Free; end; @@ -50,20 +42,21 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="content"]//img/@src')); - if title = '' then title := XPathString('//div[@class="content"]//h5'); - authors := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Author")]/following-sibling::dd[1]/*'); - artists := XPathString('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Artist")]/following-sibling::dd[1]'); - genres := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Categories")]/following-sibling::dd[1]/*'); - status := MangaInfoStatusIfPos(XPathString( - '//dl[@class="dl-horizontal"]/dt[starts-with(.,"Status")]/following-sibling::dd[1]'), - 'Ongoing', - 'Completed'); - summary := XPathString('//*[@class="well"]/p'); + coverLink := XPathString('//div[@class="boxed"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//h2[@class="widget-title"]'); + if Module.Website = 'MangaDenizi' then + status := MangaInfoStatusIfPos(XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') + else + status := MangaInfoStatusIfPos(XPathString('//dt[.=("Status","Estado")]/following-sibling::dd[1]')); + authors := XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)")]/following-sibling::dd[1]/string-join(*,", ")'); + artists := XPathStringAll('//dt[.="Artist(s)"]/following-sibling::dd[1]/string-join(*,", ")'); + genres := XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías")]/following-sibling::dd[1]/string-join(*,", ")'); + summary := XPathString('//div[@class="well"]/p'); for v in XPath('//ul[@class="chapters"]/li/h5') do begin chapterLinks.Add(XPathString('a/@href', v)); - chapterName.Add(XPathString('a||": "||em', v)); + chapterName.Add(XPathString('normalize-space(.)', v)); end; InvertStrings([chapterLinks, chapterName]); finally @@ -87,7 +80,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - XPathStringAll('//*[@id="all"]/img/@data-src', PageLinks); + XPathStringAll('//div[@id="all"]/img/@data-src', PageLinks); finally Free; end; @@ -96,15 +89,24 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; procedure RegisterModule; -begin - with AddModule do + + function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; begin - Website := 'Komikid'; - RootURL := 'http://www.komikid.com'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; end; + +begin + AddWebsiteModule('Komikid', 'http://www.komikid.com'); + AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); + AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); end; initialization From 03e4660cb110e3e3312ec6a1ad948b09da325af9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 09:41:10 +0800 Subject: [PATCH 1539/2794] added mangadoor to spanish. closed #375. --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 1f038a864..4c37ba79f 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -15,7 +15,7 @@ Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU -Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,NineManga_ES,SekaiManga,SubManga,Tumangaonline +Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineManga_ES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr From 676a9d845a79173652e42d58b42f5bd036efca95 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 12:12:27 +0800 Subject: [PATCH 1540/2794] added function stringin and textin --- baseunits/uBaseUnit.pas | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fae74b4a6..5933b1b1f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -751,6 +751,8 @@ procedure AddCommaString(var Dest: String; S: String); function StringOfString(c: String; l: Integer): String; function IncStr(const S: String; N: Integer = 1): String; overload; function IncStr(const I: Integer; N: Integer = 1): String; overload; inline; +function StringIn(const AText: String; const AValues: array of String): Boolean; +function TextIn(const AText: String; const AValues: array of String): Boolean; //get heaader value from THTTPSend.Headers function GetHeaderValue(const AHeaders: TStrings; HName: String): String; @@ -1877,6 +1879,26 @@ function IncStr(const I: Integer; N: Integer): String; Result := IntToStr(I + N); end; +function StringIn(const AText: String; const AValues: array of String): Boolean; +var + i: Integer; +begin + for i := Low(AValues) to High(AValues) do + if AValues[i] = AText then + Exit(True); + Result := False; +end; + +function TextIn(const AText: String; const AValues: array of String): Boolean; +var + i: Integer; +begin + for i := Low(AValues) to High(AValues) do + if SameText(AValues[i], AText) then + Exit(True); + Result := False; +end; + function GetHeaderValue(const AHeaders: TStrings; HName: String): String; var i, p: Integer; From 1b48b4745fe9dd7846c67c8857a36bd7df262420 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 18 Feb 2017 12:58:39 +0800 Subject: [PATCH 1541/2794] gmangame, fixed manga list. #414 --- baseunits/modules/GMangaMe.pas | 39 +++------------------------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/baseunits/modules/GMangaMe.pas b/baseunits/modules/GMangaMe.pas index 94398c155..b66316038 100644 --- a/baseunits/modules/GMangaMe.pas +++ b/baseunits/modules/GMangaMe.pas @@ -10,55 +10,23 @@ interface implementation -const - dirurl = '/mangas'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - s := XPathString('//ul[starts-with(@class,"pagination")]/li[last()-1]/a/@href'); - if Pos('page=', s) <> 0 then - begin - s := SeparateRight(s, 'page='); - Page := StrToIntDef(s, 1); - end; - finally - Free; - end; - end; -end; - function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if AURL <> '0' then - s := s + '?&page=' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then + if MangaInfo.FHTTP.GET(Module.RootURL + '/mangas') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//dd[@class="small-dd"]/a') do + for v in XPath('//div[@class="row"]//a[./div[@class="manga-cover-container"]]') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + ANames.Add(XPathString('div/span[@class="info-item info-title"]', v)); end; finally Free; @@ -160,7 +128,6 @@ procedure RegisterModule; begin Website := 'GManga'; RootURL := 'http://gmanga.me'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From 99ab8d7c64c0da2b746a5a1527fc8b253762bb0b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 21 Feb 2017 12:33:07 +0800 Subject: [PATCH 1542/2794] rewrite wpmanga, added hentairead. closed #450 --- baseunits/modules/WPManga.pas | 275 +++++++++++------------------- config/mangalist.ini | 4 +- mangadownloader/forms/frmMain.lfm | 8 +- 3 files changed, 110 insertions(+), 177 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index ea288dfb5..126f719c0 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -6,190 +6,121 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, synacode, RegExpr; implementation -const - dirURL = '/manga-list/all/any/last-added/'; - dirURLreadhentaimanga = '/hentai-manga-list/all/any/last-added/'; - dirURLmangahen = '/manga_list/all/any/last-added/'; - -function GetDirURL(const AWebsite: String): String; +function GetDirURL(const AModule: TModuleContainer): String; begin - if AWebsite = 'ReadHentaiManga' then - Result := dirURLreadhentaimanga - else - if AWebsite = 'MangaHen' then - Result := dirURLmangahen - else - Result := dirURL; + with AModule do + if StringIn(Website, ['MangaSpy', 'MangaIce']) then + Result := 'manga_list' + else + if Website = 'ReadHentaiManga' then + Result := 'hentai-manga-list' + else if Website = 'HentaiRead' then + Result := 'hentai-list' + else + Result := 'manga-list'; + Result := '/' + Result + '/all/any/last-added/'; end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; -var - s: String; begin Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - with MangaInfo.FHTTP do begin - if Module.Website = 'Manga-Joy' then - AllowServerErrorResponse := True; - if GET(Module.RootURL + GetDirURL(Module.Website)) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - s := XPathString('//*[@class="pgg"]/li[last()]/a/@href'); - s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); - Page := StrToIntDef(s, 1); - finally - Free; - end; - end; + if MangaInfo.FHTTP.GET(Module.RootURL + GetDirURL(Module)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)/.*$', + XPathString('//ul[@class="pgg"]/li[last()]/a/@href'), '$1', True), 1); + finally + Free; + end; end; end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - with MangaInfo.FHTTP do begin - if Module.Website = 'Manga-Joy' then - AllowServerErrorResponse := True; - if GET(Module.RootURL + GetDirURL(Module.Website) + IncStr(AURL) + '/') then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - if Module.Website = 'ReadHentaiManga' then - for v in XPath('//*[@id="content"]//*[@id="center"]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toNode.getAttribute('title')); - end - else if (Module.Website = 'EyeOnManga') or - (Module.Website = 'MangaBoom') then - for v in XPath('//*[@id="sct_content"]//h2/a[1]') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end - else if (Module.Website = 'MangaJoy') then - for v in XPath('//*[@id="sct_manga_list"]//*[@class="det"]/h2/a[1]') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end - else - for v in XPath('//*[@id="sct_content"]//div[@class="det"]/a[1]') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; + if MangaInfo.FHTTP.GET(Module.RootURL + GetDirURL(Module) + IncStr(AURL) + '/') then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + if StringIn(Module.Website, ['MangaSpy', 'MangaIce']) then + XPathHREFAll('//*[contains(@id,"content")]//*[@class="det"]/a', ALinks, ANames) + else + XPathHREFtitleAll('//*[contains(@id,"content")]//a[./img]', ALinks, ANames); + finally + Free; + end; end; end; -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; v: IXQValue; s: String; - i, pagecount: Integer; - - procedure scanchapters; - var - t: String; - begin - with MangaInfo.mangaInfo, query, TRegExpr.Create do - for v in XPath('//ul[contains(@class,"lst")]/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - t := v.toNode.getAttribute('title'); - if t = '' then - t := XPathString('*[@class="val"]', v.toNode); - if t = '' then - t := XPathString('text()[1]', v.toNode); - chapterName.Add(t); - end; - end; - - function getwpmangavalue(aname: String): String; - begin - Result := query.XPathString('//*[contains(@class,"mng_det")]//p[starts-with(.,"' + - aname + '")]'); - if Result <> '' then Result := Trim(TrimChar(SeparateRight(Result, aname), [':', ' '])); - if Result = '-' then - Result := ''; - end; - - procedure scaninfo; - begin - with MangaInfo.mangaInfo, query do begin - authors := getwpmangavalue('Author'); - artists := getwpmangavalue('Artist'); - genres := ''; - AddCommaString(genres, getwpmangavalue('Category')); - AddCommaString(genres, getwpmangavalue('Genres')); - status := MangaInfoStatusIfPos(getwpmangavalue('Status'), 'Ongoing', 'Completed'); - summary := getwpmangavalue('Summary'); - if summary = '' then - begin - summary := XPathString('//*[contains(@class,"mng_det")]//p'); - if (summary <> '') and - ((Pos('name:', LowerCase(summary)) <> 0) or - (Pos('alternative name', LowerCase(summary)) = 1)) then - summary := ''; - end; - scanchapters; - end; - end; - begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - website := Module.Website; - url := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if Module.Website = 'Manga-Joy' then - AllowServerErrorResponse := True; - if GET(MangaInfo.mangaInfo.url) then begin + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - coverLink := query.XPathString('//img[starts-with(@class,"cvr")]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - title := query.XPathString('//*[@itemprop="itemreviewed"]'); - scaninfo; - s := query.XPathString('//*[@class="pgg"]/li[last()]/a/@href'); - if s <> '' then begin - s := ReplaceRegExpr('^.*\/(\d+)/.*$', s, '$1', True); - pagecount := StrToIntDef(s, 1); - if pagecount > 1 then - for i := 2 to pagecount do + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[starts-with(@class,"cvr")]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + title := XPathString('//*[@itemprop="itemreviewed"]'); + authors := XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Author")]/substring-after(.," ")'); + artists := XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Artist")]/substring-after(.," ")'); + status := MangaInfoStatusIfPos(XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Status")]/substring-after(.," ")')); + if StringIn(Module.Website, ['ReadHentaiManga', 'HentaiRead']) then + genres := XPathString('string-join(//*[contains(@class,"mng_det")]//*[self::p or self::li]//a,", ")') + else + genres := XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Category")]/string-join((./*[position()>1]),", ")'); + if Module.Website = 'HentaiRead' then + begin + chapterLinks.Add(XPathString('//a[@class="lst"]/@href')); + chapterName.Add(title); + end + else + begin + while True do begin - if MangaInfo.FHTTP.Thread.IsTerminated then Break; - if GET(url + 'chapter-list/' + IntToStr(i) + '/') then begin - query.ParseHTML(StreamToString(Document)); - scanchapters; + for v in XPath('//a[@class="lst"]') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + s := v.toNode.getAttribute('title'); + if s = '' then + s := XPathString('*[@class="val"]', v.toNode); + if s = '' then + s := XPathString('text()[1]', v.toNode); + chapterName.Add(s); end; + if Thread.IsTerminated then Break; + s := XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href'); + if s <> '' then + Break + else if GET(MaybeFillHost(Module.RootURL, s)) then + ParseHTML(Document) + else + Break; end; + InvertStrings([chapterLinks, chapterName]); + end; + finally + Free; end; - if Module.Website <> 'EyeOnManga' then - InvertStrings([chapterLinks, chapterName]); - { add missing chapter number } - //if (Module.Website = 'EyeOnManga') and - // (chapterName.Count > 0) then - // for i := 0 to chapterName.Count - 1 do - // chapterName[i] := 'Ch.' + IncStr(i) + ' ' + chapterName[i]; - finally - query.Free; - end; end; end; end; @@ -210,23 +141,24 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1') then begin Result := True; //multi page - s := StreamToString(Document); - if Pos('var imglist = ', s) > 0 then - begin - s := GetBetween('var imglist = ', '];', s); - if s <> '' then - begin - s := s + ']'; - s := RemoveBreaks(s); - with TXQueryEngineHTML.Create(s) do - try - for v in XPath('json(*)()("url")') do - PageLinks.Add(v.toString); - finally - Free; - end; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//script[contains(.,"imglist")]/substring-after(substring-before(.,"]"),"[")'); + if s <> '' then + s := '[' + s + ']' + else + begin + s := XPathString('//script[contains(.,"img_lst")]/substring-after(substring-before(.,"'')"),"(''")'); + if s <> '' then + s := DecodeURL(s); + end; + ParseHTML(s); + XPathStringAll('json(*)()("url")', PageLinks); + if PageLinks.Count = 0 then + XPathStringAll('json(*)()', PageLinks); + finally + Free; end; - end; //single page if PageLinks.Count = 0 then with TXQueryEngineHTML.Create(Document) do @@ -287,14 +219,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; procedure RegisterModule; - procedure AddWebsiteModule(AWebsite, ARootURL: String); + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - with AddModule do + Result := AddModule; + with Result do begin Website := AWebsite; RootURL := ARootURL; SortedList := True; - InformationAvailable := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; @@ -308,9 +240,10 @@ procedure RegisterModule; AddWebsiteModule('Authrone', 'http://www.authrone.com'); AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); - AddWebsiteModule('MangaHen', 'http://www.mangahen.com'); + AddWebsiteModule('MangaSpy', 'http://www.mangaspy.com'); AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); AddWebsiteModule('MangaCow', 'http://mngcow.co'); + AddWebsiteModule('HentaiRead', 'http://hentairead.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 4c37ba79f..30759e8c0 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHen,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga @@ -20,5 +20,5 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index c75fe1b21..9b5b55961 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,13 +37,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 4 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -2178,10 +2178,10 @@ object MainForm: TMainForm Height = 415 Top = 8 Width = 539 - ActivePage = tsView + ActivePage = tsGeneral Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 1 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' From 391f8f5f7a7df06dcfda87c4f9c7116ba0671b8f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 21 Feb 2017 13:00:54 +0800 Subject: [PATCH 1543/2794] Bump version 0.9.92.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 180d04a01..aabc39fed 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.92.0 (21-02-2017) +[+] Added MangaDoor[ES] +[+] Added HentaiRead[H] +[*] Replace MangaHen with MangaSpy +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.91.0...0.9.92.0 + 0.9.91.0 (16-02-2017) [*] E-Hentai: fixed loading "Content Warning" Full changes: https://github.com/riderkick/FMD/compare/0.9.90.0...0.9.91.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5dc51a7f8..61fcc6dee 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="91"/> + <RevisionNr Value="92"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index dda8b07ce..5d306b5e9 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.91.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.91.0/fmd_0.9.91.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.91.0/fmd_0.9.91.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.91.0/fmd_0.9.91.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.91.0/fmd_0.9.91.0_Win64.7z +VERSION=0.9.92.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.92.0/fmd_0.9.92.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.92.0/fmd_0.9.92.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.92.0/fmd_0.9.92.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.92.0/fmd_0.9.92.0_Win64.7z From 568321469f2acd0eb8d2c20057bdb411aeff56ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Feb 2017 10:51:43 +0800 Subject: [PATCH 1544/2794] wpmanga, fixed memory leak. closed #489 --- baseunits/modules/WPManga.pas | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 126f719c0..b86c5908c 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -108,10 +108,9 @@ function GetInfo(const MangaInfo: TMangaInformation; chapterName.Add(s); end; if Thread.IsTerminated then Break; - s := XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href'); - if s <> '' then - Break - else if GET(MaybeFillHost(Module.RootURL, s)) then + s := Trim(XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href')); + if s = '' then Break; + if GET(MaybeFillHost(Module.RootURL, s)) then ParseHTML(Document) else Break; From 5a2f5fec864719e08d4ccd109c87d604188f5b2b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Feb 2017 11:00:33 +0800 Subject: [PATCH 1545/2794] Bump version 0.9.93.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index aabc39fed..cd0c0c9ae 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.93.0 (22-02-2017) +[*] WPManga: Fixed memory leak +Full changes: https://github.com/riderkick/FMD/compare/0.9.92.0...0.9.93.0 + 0.9.92.0 (21-02-2017) [+] Added MangaDoor[ES] [+] Added HentaiRead[H] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 61fcc6dee..6d8b700a8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="92"/> + <RevisionNr Value="93"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5d306b5e9..914b3206d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.92.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.92.0/fmd_0.9.92.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.92.0/fmd_0.9.92.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.92.0/fmd_0.9.92.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.92.0/fmd_0.9.92.0_Win64.7z +VERSION=0.9.93.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.93.0/fmd_0.9.93.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.93.0/fmd_0.9.93.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.93.0/fmd_0.9.93.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.93.0/fmd_0.9.93.0_Win64.7z From f050aa184919789e0a6c892ba8c9f85e7311e963 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 10:35:37 +0800 Subject: [PATCH 1546/2794] downloads/favorites sort only with left click --- mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.pas | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 9b5b55961..0435d4fc2 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -252,7 +252,6 @@ object MainForm: TMainForm Left = 153 Height = 25 Top = 0 - Width = 5 Style = tbsDivider Visible = False end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a133e6863..fd349b5be 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3856,6 +3856,7 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ); begin + if Button <> mbLeft then Exit; if DLManager.Count < 2 then Exit; if (Column = 2) or (Column = 3) then Exit; if DLManager.SortColumn = Column then @@ -4036,6 +4037,7 @@ procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ); begin + if Button <> mbLeft then Exit; if FavoriteManager.isRunning then Exit; if FavoriteManager.Count < 2 then Exit; if Column = 0 then Exit; From 86d51e87a3e5558399c83289939786dea9f9a6b2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 11:52:42 +0800 Subject: [PATCH 1547/2794] added favoritesdb and updated sqlitedata --- baseunits/FavoritesDB.pas | 90 +++++++++++++++++++++++++++++++++++++++ baseunits/SQLiteData.pas | 22 +++++++--- 2 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 baseunits/FavoritesDB.pas diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas new file mode 100644 index 000000000..2375a35d3 --- /dev/null +++ b/baseunits/FavoritesDB.pas @@ -0,0 +1,90 @@ +unit FavoritesDB; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, SQLiteData; + +type + + { TFavoritesDB } + + TFavoritesDB = class(TSQliteData) + private + public + constructor Create; + function Add(const AWebsiteLink: string; const AOrder: Integer; + const AWebsite, ALink, ATitle, ASaveTo, ACurrentChapter, ADownloadedChapterList: string): Boolean; + procedure Delete(const AWebsiteLink: string); + end; + +implementation + +{ TFavoritesDB } + +constructor TFavoritesDB.Create; +begin + inherited Create; + TableName := 'favorites'; + CreateParams := + '"websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY,' + + '"order" INTEGER', + '"website" TEXT', + '"link" TEXT', + '"title" TEXT', + '"saveto" TEXT', + '"currentchapter" TEXT', + '"downloadedchapterlist" TEXT'; + SelectParams := + 'SELECT * FROM "favorites" ORDER BY "order"'); + { + CREATE TABLE "favorites" ( + "websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY, + "order" TEXT, + "website" TEXT, + "link" TEXT, + "title" TEXT, + "saveto" TEXT, + "currentchapter" TEXT, + "downloadedchapterlist" TEXT + ); + } +end; + +function TFavoritesDB.Add(const AWebsiteLink: string; const AOrder: Integer; + const AWebsite, ALink, ATitle, ASaveTo, ACurrentChapter, ADownloadedChapterList: string): Boolean; +begin + Result := False; + if AWebsiteLink = '' then Exit; + if not Connection.Connected then Exit; + try + Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" ('+ + '"websitelink", "order", "website", "link", "title", "saveto", "currentchapter", "downloadedchapterlist")'+ + ' VALUES ("' + + AWebsiteLink + '","' + + IntToStr(AOrder) + '","' + + AWebsite + '","' + + ALink + '","' + + ATitle + '","' + + ASaveTo + '","' + + ACurrentChapter + '","' + + ADownloadedChapterList + '")'); + Result := True; + except + end; +end; + +procedure TFavoritesDB.Delete(const AWebsiteLink: string); +begin + if AWebsiteLink = '' then Exit; + if not Connection.Connected then Exit; + try + Connection.ExecuteDirect('DELETE FROM "favorites" WHERE "AWebsiteLink"="' + AWebsiteLink + '"'); + except + end; +end; + +end. + diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 98d2bdef7..68107b9d1 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -29,12 +29,14 @@ TSQliteData = class FFilename: String; FTableName: String; FCreateParams: String; + FSelectParams: String; FRecordCount: Integer; procedure DoOnError(E: Exception); function GetAutoApplyUpdates: Boolean; procedure SetAutoApplyUpdates(AValue: Boolean); procedure SetCreateParams(AValue: String); procedure SetOnError(AValue: TExceptionEvent); + procedure SetSelectParams(AValue: String); protected function CreateDB: Boolean; virtual; function CreateDBTable: Boolean; virtual; @@ -53,12 +55,14 @@ TSQliteData = class procedure Close; procedure Refresh(RecheckDataCount: Boolean = False); procedure Save; - function Connected: Boolean; + function Connected: Boolean; inline; property Connection: TSQLite3ConnectionH read FConn; + property Transaction: TSQLTransaction read FTrans; property Table: TSQLQuery read FQuery; property Filename: String read FFilename write FFilename; property TableName: String read FTableName write FTableName; property CreateParams: String read FCreateParams write SetCreateParams; + property SelectParams: String read FSelectParams write SetSelectParams; property RecordCount: Integer read FRecordCount; property AutoApplyUpdates: Boolean read GetAutoApplyUpdates write SetAutoApplyUpdates; property OnError: TExceptionEvent read FOnError write SetOnError; @@ -95,8 +99,7 @@ procedure TSQliteData.SetAutoApplyUpdates(AValue: Boolean); procedure TSQliteData.SetCreateParams(AValue: String); begin if FCreateParams = AValue then Exit; - FCreateParams := Trim(AValue); - FCreateParams := TrimSet(FCreateParams, ['(', ')', ';']); + FCreateParams := TrimSet(Trim(AValue), ['(', ')', ';']); end; procedure TSQliteData.SetOnError(AValue: TExceptionEvent); @@ -105,12 +108,18 @@ procedure TSQliteData.SetOnError(AValue: TExceptionEvent); FOnError := AValue; end; +procedure TSQliteData.SetSelectParams(AValue: String); +begin + if FSelectParams = AValue then Exit; + FSelectParams := AValue; +end; + function TSQliteData.CreateDB: Boolean; begin Result := False; if FFilename = '' then Exit; if FileExistsUTF8(ffilename) then DeleteFileUTF8(FFilename); - CreateDBTable; + Result := CreateDBTable; end; function TSQliteData.CreateDBTable: Boolean; @@ -151,7 +160,10 @@ function TSQliteData.OpenDBTable: Boolean; if InternalOpenDB = False then Exit; try if FQuery.Active then FQuery.Close; - FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrd(FTableName); + if FSelectParams <> '' then + FQuery.SQL.Text := FSelectParams + else + FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrd(FTableName); FQuery.Open; GetRecordCount; except From a3958bcbbe2d2a97fcd788019aadb79703e32b89 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 14:59:14 +0800 Subject: [PATCH 1548/2794] update and fixed sqlitedata --- baseunits/SQLiteData.pas | 143 +++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 68107b9d1..8550fb70a 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -38,10 +38,8 @@ TSQliteData = class procedure SetOnError(AValue: TExceptionEvent); procedure SetSelectParams(AValue: String); protected + function OpenDB: Boolean; virtual; function CreateDB: Boolean; virtual; - function CreateDBTable: Boolean; virtual; - function InternalOpenDB: Boolean; virtual; - function OpenDBTable: Boolean; virtual; function ConvertNewTableIF: Boolean; virtual; procedure DoConvertNewTable; procedure GetRecordCount; virtual; @@ -51,9 +49,13 @@ TSQliteData = class public constructor Create; destructor Destroy; override; - function Open: Boolean; + function Open(const AOpenTable: Boolean = True): Boolean; + function OpenTable: Boolean; virtual; procedure Close; + procedure CloseTable; procedure Refresh(RecheckDataCount: Boolean = False); + procedure Commit; virtual; + procedure CommitRetaining; virtual; procedure Save; function Connected: Boolean; inline; property Connection: TSQLite3ConnectionH read FConn; @@ -68,9 +70,11 @@ TSQliteData = class property OnError: TExceptionEvent read FOnError write SetOnError; end; + function QuotedStrd(const S: string): string; inline; + implementation -function QuotedStrd(const S: String): String; +function QuotedStrd(const S: string): string; begin Result := AnsiQuotedStr(S, '"'); end; @@ -114,33 +118,7 @@ procedure TSQliteData.SetSelectParams(AValue: String); FSelectParams := AValue; end; -function TSQliteData.CreateDB: Boolean; -begin - Result := False; - if FFilename = '' then Exit; - if FileExistsUTF8(ffilename) then DeleteFileUTF8(FFilename); - Result := CreateDBTable; -end; - -function TSQliteData.CreateDBTable: Boolean; -begin - Result := False; - if FTableName = '' then Exit; - if FCreateParams = '' then Exit; - if InternalOpenDB = False then Exit; - try - FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); - FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + - '(' + FCreateParams + ')'); - FTrans.Commit; - Result := OpenDBTable; - except - on E: Exception do - DoOnError(E); - end; -end; - -function TSQliteData.InternalOpenDB: Boolean; +function TSQliteData.OpenDB: Boolean; begin Result := False; if FFilename = '' then Exit; @@ -148,30 +126,25 @@ function TSQliteData.InternalOpenDB: Boolean; FConn.DatabaseName := FFilename; FConn.Connected := True; FTrans.Active := True; - Result := FConn.Connected; - finally - Result := FConn.Connected; + except end; + Result := FConn.Connected; end; -function TSQliteData.OpenDBTable: Boolean; +function TSQliteData.CreateDB: Boolean; begin Result := False; - if InternalOpenDB = False then Exit; + if (FTableName = '') or (FCreateParams = '') then Exit; + if not FConn.Connected then + if not OpenDB then Exit; try - if FQuery.Active then FQuery.Close; - if FSelectParams <> '' then - FQuery.SQL.Text := FSelectParams - else - FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrd(FTableName); - FQuery.Open; - GetRecordCount; + FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + + '(' + FCreateParams + ')'); + FTrans.Commit; + Result := True; except - on E: Exception do - DoOnError(E); end; - Result := FQuery.Active; - if Result then DoConvertNewTable; end; function TSQliteData.ConvertNewTableIF: Boolean; @@ -208,7 +181,8 @@ procedure TSQliteData.DoConvertNewTable; procedure TSQliteData.GetRecordCount; begin - if FQuery.Active then begin + if FQuery.Active then + begin FQuery.Last; FRecordCount := FQuery.RecordCount; FQuery.Refresh; @@ -231,7 +205,7 @@ procedure TSQliteData.Vacuum; var qactive: Boolean; begin - if FConn.Connected = False then Exit; + if not FConn.Connected then Exit; try qactive := FQuery.Active; if FQuery.Active then FQuery.Close; @@ -274,15 +248,36 @@ destructor TSQliteData.Destroy; inherited Destroy; end; -function TSQliteData.Open: Boolean; +function TSQliteData.Open(const AOpenTable: Boolean): Boolean; begin Result := False; - if FFilename = '' then Exit; - if FCreateParams = '' then Exit; - if not FileExistsUTF8(FFilename) then - Result := CreateDBTable + if (FFilename = '') or (FCreateParams = '') then Exit; + if FileExistsUTF8(FFilename) then + Result := OpenDB else - Result := OpenDBTable; + Result := CreateDB; + if Result and AOpenTable then + Result := OpenTable; +end; + +function TSQliteData.OpenTable: Boolean; +begin + Result := False; + if not FConn.Connected then Exit; + try + if FQuery.Active then FQuery.Close; + if FSelectParams <> '' then + FQuery.SQL.Text := FSelectParams + else + FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrd(FTableName); + FQuery.Open; + GetRecordCount; + except + on E: Exception do + DoOnError(E); + end; + Result := FQuery.Active; + if Result then DoConvertNewTable; end; procedure TSQliteData.Close; @@ -291,9 +286,21 @@ procedure TSQliteData.Close; try Save; Vacuum; - FQuery.Close; + CloseTable; FTrans.Active := False; FConn.Close; + except + on E: Exception do + DoOnError(E); + end; +end; + +procedure TSQliteData.CloseTable; +begin + if not FConn.Connected then Exit; + if not FQuery.Active then Exit; + try + FQuery.Close; FRecordCount := 0; except on E: Exception do @@ -312,11 +319,31 @@ procedure TSQliteData.Refresh(RecheckDataCount: Boolean); GetRecordCount; end; +procedure TSQliteData.Commit; +begin + if not FConn.Connected then Exit; + try + Transaction.Commit; + except + Transaction.Rollback; + end; +end; + +procedure TSQliteData.CommitRetaining; +begin + if not FConn.Connected then Exit; + try + Transaction.CommitRetaining; + except + Transaction.RollbackRetaining; + end; +end; + procedure TSQliteData.Save; var qactive: Boolean; begin - if FConn.Connected = False then Exit; + if not FConn.Connected then Exit; try qactive := FQuery.Active; if FQuery.Active then From 30a18662802b54c8e7421c489604945fd6557ab7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 14:59:46 +0800 Subject: [PATCH 1549/2794] added favorites db file location --- baseunits/FMDOptions.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 6b9a36838..0cde198c4 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -57,6 +57,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) DOWNLOADEDCHAPTERS_FILE, DOWNLOADEDCHAPTERSDB_FILE, FAVORITES_FILE, + FAVORITESDB_FILE, CONFIG_FOLDER, CONFIG_FILE, CONFIG_ADVANCED, @@ -281,6 +282,7 @@ procedure SetAppDataDirectory(const ADir: String); DOWNLOADEDCHAPTERS_FILE := WORK_FOLDER + 'downloadedchapters.ini'; DOWNLOADEDCHAPTERSDB_FILE := WORK_FOLDER + 'downloadedchapters.db'; FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; + FAVORITESDB_FILE := WORK_FOLDER + 'favorites.db'; SetIniFiles; end; From 828f915b875a630a71f40a77cff8e31a8e086fa3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 15:00:40 +0800 Subject: [PATCH 1550/2794] updated complete favoritesdb, convert ini file to db at first --- baseunits/FavoritesDB.pas | 84 +++++++++++++------ baseunits/uFavoritesManager.pas | 144 +++++++++++++++++++------------- 2 files changed, 143 insertions(+), 85 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index 2375a35d3..dfcb24772 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -13,76 +13,108 @@ interface TFavoritesDB = class(TSQliteData) private + FCommitCount: Integer; + FAutoCommitCount: Integer; + procedure SetAutoCommitCount(AValue: Integer); public - constructor Create; - function Add(const AWebsiteLink: string; const AOrder: Integer; - const AWebsite, ALink, ATitle, ASaveTo, ACurrentChapter, ADownloadedChapterList: string): Boolean; - procedure Delete(const AWebsiteLink: string); + constructor Create(const AFilename: String); + function Add(const AOrder: Integer; const AWebsite, ALink, + ATitle, ACurrentChapter, ADownloadedChapterList, ASaveTo: String): Boolean; + procedure Delete(const AWebsite, ALink: String); + procedure Commit; override; + property AutoCommitCount: Integer read FAutoCommitCount write SetAutoCommitCount; end; implementation { TFavoritesDB } -constructor TFavoritesDB.Create; +procedure TFavoritesDB.SetAutoCommitCount(AValue: Integer); +begin + if FAutoCommitCount = AValue then Exit; + FAutoCommitCount := AValue; +end; + +constructor TFavoritesDB.Create(const AFilename: String); begin inherited Create; + FCommitCount := 0; + FAutoCommitCount := 500; + Filename := AFilename; TableName := 'favorites'; CreateParams := + '"order" INTEGER,' + '"websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY,' + - '"order" INTEGER', - '"website" TEXT', - '"link" TEXT', - '"title" TEXT', - '"saveto" TEXT', - '"currentchapter" TEXT', - '"downloadedchapterlist" TEXT'; + '"website" TEXT,' + + '"link" TEXT,' + + '"title" TEXT,' + + '"currentchapter" TEXT,' + + '"downloadedchapterlist" TEXT,' + + '"saveto" TEXT'; SelectParams := - 'SELECT * FROM "favorites" ORDER BY "order"'); + 'SELECT * FROM "favorites" ORDER BY "order"'; { CREATE TABLE "favorites" ( - "websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY, "order" TEXT, + "websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY, "website" TEXT, "link" TEXT, "title" TEXT, - "saveto" TEXT, "currentchapter" TEXT, - "downloadedchapterlist" TEXT + "downloadedchapterlist" TEXT, + "saveto" TEXT ); } end; -function TFavoritesDB.Add(const AWebsiteLink: string; const AOrder: Integer; - const AWebsite, ALink, ATitle, ASaveTo, ACurrentChapter, ADownloadedChapterList: string): Boolean; +function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, + ACurrentChapter, ADownloadedChapterList, ASaveTo: String): Boolean; begin Result := False; - if AWebsiteLink = '' then Exit; + if (AWebsite = '') or (ALink = '') then Exit; if not Connection.Connected then Exit; try Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" ('+ - '"websitelink", "order", "website", "link", "title", "saveto", "currentchapter", "downloadedchapterlist")'+ + '"order","websitelink","website","link","title","currentchapter","downloadedchapterlist","saveto")'+ ' VALUES ("' + - AWebsiteLink + '","' + IntToStr(AOrder) + '","' + + AWebsite + ALink + '","' + AWebsite + '","' + ALink + '","' + ATitle + '","' + - ASaveTo + '","' + ACurrentChapter + '","' + - ADownloadedChapterList + '")'); + ADownloadedChapterList + '","' + + ASaveTo + '")'); Result := True; + Inc(FCommitCount); + if FCommitCount >= FAutoCommitCount then + Commit; + except + end; +end; + +procedure TFavoritesDB.Delete(const AWebsite, ALink: String); +begin + if (AWebsite = '') or (ALink = '') then Exit; + if not Connection.Connected then Exit; + try + Connection.ExecuteDirect( + 'DELETE FROM "favorites" WHERE "websitelink"="' + AWebsite + ALink + '"'); + Inc(FCommitCount); + if FCommitCount >= FAutoCommitCount then + Commit; except end; end; -procedure TFavoritesDB.Delete(const AWebsiteLink: string); +procedure TFavoritesDB.Commit; begin - if AWebsiteLink = '' then Exit; if not Connection.Connected then Exit; try - Connection.ExecuteDirect('DELETE FROM "favorites" WHERE "AWebsiteLink"="' + AWebsiteLink + '"'); + Transaction.Commit; + FCommitCount := 0; except + Transaction.Rollback; end; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 881617a67..975ac0e45 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -13,7 +13,7 @@ interface uses Classes, SysUtils, fgl, Dialogs, IniFiles, lazutf8classes, LazFileUtils, uBaseUnit, uData, uDownloadsManager, WebsiteModules, - FMDOptions, httpsendthread, SimpleException; + FMDOptions, httpsendthread, FavoritesDB, SimpleException; type TFavoriteManager = class; @@ -85,13 +85,14 @@ TFavoriteContainer = class TFavoriteManager = class private CS_Favorites: TRTLCriticalSection; + FFavoritesDB: TFavoritesDB; FSortColumn: Integer; FSortDirection, FIsAuto, FIsRunning: Boolean; function GetFavoritesCount: Integer; inline; function GetFavorite(const Index: Integer): TFavoriteContainer; + function ConvertToDB: Boolean; public Items: TFavoriteContainers; - favoritesFile: TIniFileRun; taskthread: TFavoriteTask; DLManager: TDownloadManager; OnUpdateFavorite: procedure of object; @@ -106,21 +107,21 @@ TFavoriteManager = class // Show notification form after checking completed procedure ShowResult; - // Return true if a manga exist in FFavorites + // Return true if a manga exist in favorites function IsMangaExist(const ATitle, AWebsite: String): Boolean; function IsMangaExistURL(const AWebsite, AURL: String): Boolean; // Add new manga to the list procedure Add(const ATitle, ACurrentChapter, ADownloadedChapterList, AWebsite, ASaveTo, ALink: String); - // Merge manga information with a title that already exist in FFavorites + // Merge manga information with a title that already exist in favorites procedure AddMerge(const ATitle, ACurrentChapter, ADownloadedChapterList, AWebsite, ASaveTo, ALink: String); - // Merge a FFavorites.ini with another FFavorites.ini + // Merge a favorites.ini with another favorites.ini procedure MergeWith(const APath: String); // Remove a manga from FFavorites procedure Remove(const Pos: Integer; const isBackup: Boolean = True); - // Restore information from FFavorites.ini + // Restore information from favorites.db procedure Restore; - // Backup to FFavorites.ini + // Backup to favorites.db procedure Backup; // Add FFavorites downloadedchapterlist procedure AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); @@ -484,21 +485,55 @@ function TFavoriteManager.GetFavorite(const Index: Integer): TFavoriteContainer; Result := Items[Index]; end; +function TFavoriteManager.ConvertToDB: Boolean; +var + i: Integer; + s: String; +begin + Result := False; + if not FileExistsUTF8(FAVORITES_FILE) then Exit; + with TIniFile.Create(FAVORITES_FILE) do + try + i := ReadInteger('general', 'NumberOfFavorites', 0); + if i = 0 then Exit; + for i := 0 to i - 1 do + begin + s := IntToStr(i); + FFavoritesDB.Add( + i, + ReadString(s, 'Website', ''), + ReadString(s, 'Link', ''), + ReadString(s, 'Title', ''), + ReadString(s, 'CurrentChapter', ''), + ReadString(s, 'DownloadedChapterList', ''), + ReadString(s, 'SaveTo', '') + ); + end; + FFavoritesDB.Commit; + Result := True; + finally + Free; + end; + if Result then + DeleteFileUTF8(FAVORITES_FILE); +end; + constructor TFavoriteManager.Create; begin inherited Create; ForceDirectoriesUTF8(WORK_FOLDER); InitCriticalSection(CS_Favorites); isRunning := False; - favoritesFile := TIniFileRun.Create(FAVORITES_FILE); - Items := TFavoriteContainers.Create; + Items := TFavoriteContainers.Create;; + FFavoritesDB := TFavoritesDB.Create(FAVORITESDB_FILE); + FFavoritesDB.Open(False); + ConvertToDB; Restore; end; destructor TFavoriteManager.Destroy; begin Backup; - favoritesFile.Free; if Items.Count > 0 then begin StopChekForNewChapter; while Items.Count > 0 do begin @@ -507,6 +542,7 @@ destructor TFavoriteManager.Destroy; end; end; Items.Free; + FFavoritesDB.Free; DoneCriticalsection(CS_Favorites); inherited Destroy; end; @@ -912,6 +948,8 @@ procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); begin EnterCriticalsection(CS_Favorites); try + with Items[Pos].FavoriteInfo do + FFavoritesDB.Delete(Website, Link); Items[Pos].Free; Items.Delete(Pos); if isBackup then @@ -923,65 +961,53 @@ procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); end; procedure TFavoriteManager.Restore; -var - i, c: Integer; - s: TStringList; begin - c := favoritesFile.ReadInteger('general', 'NumberOfFavorites', 0); - if c = 0 then Exit; - s := TStringList.Create; - try - s.Sorted := True; - s.Duplicates := dupIgnore; - for i := 0 to c - 1 do begin - Items.Add(TFavoriteContainer.Create); - with Items.Last do begin - Manager := Self; - with favoritesFile, FavoriteInfo do begin - currentChapter := ReadString(IntToStr(i), 'CurrentChapter', '0'); - Title := ReadString(IntToStr(i), 'Title', ''); - Website := ReadString(IntToStr(i), 'Website', ''); - SaveTo := ReadString(IntToStr(i), 'SaveTo', ''); - Link := ReadString(IntToStr(i), 'Link', ''); - Website := Website; - Status := STATUS_IDLE; - - downloadedChapterList := ReadString(IntToStr(i), 'DownloadedChapterList', ''); - // remove duplicate - GetParams(s, DownloadedChapterList); - DownloadedChapterList := SetParams(s); - s.Clear; + if not FFavoritesDB.Connection.Connected then Exit; + if FFavoritesDB.OpenTable then + try + with FFavoritesDB.Table do + begin + First; + while not EOF do + begin + Items.Add(TFavoriteContainer.Create); + with Items.Last, FavoriteInfo do + begin + Manager := Self; + Status := STATUS_IDLE; + Website := Fields[2].AsString; + Link := Fields[3].AsString; + Title := Fields[4].AsString; + CurrentChapter := Fields[5].AsString; + DownloadedChapterList := Fields[6].AsString; + SaveTo := Fields[7].AsString; + end; + Next; end; end; + finally + FFavoritesDB.CloseTable; end; - finally - s.Free; - end; end; procedure TFavoriteManager.Backup; var i: Integer; begin - with favoritesFile do begin - // delete old info - if ReadInteger('general', 'NumberOfFavorites', 0) > 0 then - for i := 0 to ReadInteger('general', 'NumberOfFavorites', 0) - 1 do - EraseSection(IntToStr(i)); - - WriteInteger('general', 'NumberOfFavorites', Items.Count); - if Items.Count > 0 then - for i := 0 to Items.Count - 1 do - with Items[i].FavoriteInfo do begin - WriteString(IntToStr(i), 'Title', Title); - WriteString(IntToStr(i), 'CurrentChapter', currentChapter); - WriteString(IntToStr(i), 'DownloadedChapterList', downloadedChapterList); - WriteString(IntToStr(i), 'Website', Website); - WriteString(IntToStr(i), 'SaveTo', SaveTo); - WriteString(IntToStr(i), 'Link', Link); - end; - UpdateFile; - end; + if not FFavoritesDB.Connection.Connected then Exit; + if Items.Count > 0 then + for i := 0 to Items.Count - 1 do + with Items[i].FavoriteInfo do + FFavoritesDB.Add( + i, + Website, + Link, + Title, + CurrentChapter, + DownloadedChapterList, + SaveTo + ); + FFavoritesDB.Commit; end; procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); From a3fb2266ba0d4d48cc2d644c73b72a7d6c2b905a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 15:41:45 +0800 Subject: [PATCH 1551/2794] added getparams --- baseunits/uBaseUnit.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5933b1b1f..d7adca60a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -775,6 +775,7 @@ procedure GetParams(var output: TCardinalList; input: String); overload; procedure GetParams(var output: TList; input: String); overload; function ExtractParam(const output: TStrings; input, sep: String; WhiteSp: Boolean = True): Integer; +function GetParams(const input: String): String; overload; function RemoveDuplicateNumbersInString(const AString: String): String; // Set param from input @@ -2334,6 +2335,11 @@ function ExtractParam(const output: TStrings; input, sep: String; output.Add(input); end; +function GetParams(const input: String): String; +begin + Result := StringReplace(input, SEPERATOR, LineEnding, [rfReplaceAll]); +end; + function RemoveDuplicateNumbersInString(const AString: String): String; var i, j: Integer; From c5eea76023a506db05a19277fd833ebf00923cfe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Feb 2017 15:42:42 +0800 Subject: [PATCH 1552/2794] fixed favoritesdb downloadedchapterlist --- baseunits/uFavoritesManager.pas | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 975ac0e45..2ca81b3cc 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -233,7 +233,7 @@ procedure TFavoriteThread.Execute; try DLChapters := TStringList.Create; DLChapters.Sorted := False; - GetParams(DLChapters, FavoriteInfo.DownloadedChapterList); + DLChapters.Text := FavoriteInfo.DownloadedChapterList; DLChapters.Sorted := True; for i := 0 to NewMangaInfo.chapterLinks.Count - 1 do if DLChapters.IndexOf(NewMangaInfo.chapterLinks[i]) = -1 then @@ -505,7 +505,7 @@ function TFavoriteManager.ConvertToDB: Boolean; ReadString(s, 'Link', ''), ReadString(s, 'Title', ''), ReadString(s, 'CurrentChapter', ''), - ReadString(s, 'DownloadedChapterList', ''), + GetParams(ReadString(s, 'DownloadedChapterList', '')), ReadString(s, 'SaveTo', '') ); end; @@ -778,7 +778,7 @@ procedure TFavoriteManager.ShowResult; end; end; // add to downloaded chapter list - FavoriteInfo.downloadedChapterList += SetParams(NewMangaInfo.chapterLinks); + FavoriteInfo.downloadedChapterList := NewMangaInfo.chapterLinks.Text; // add to downloaded chapter list in downloadmanager DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := NewMangaInfo.chapterLinks.Text; @@ -1014,15 +1014,13 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, ALink, AV var st: TStringList; begin - if (AWebsite <> '') and (ALink <> '') and (AValue <> '') then - begin - st := TStringList.Create; - try - GetParams(st, AValue); - AddToDownloadedChaptersList(AWebsite, ALink, st); - finally - St.Free; - end; + if (AWebsite = '') or (ALink = '') or (AValue = '') then Exit; + st := TStringList.Create; + try + st.Text := AValue; + AddToDownloadedChaptersList(AWebsite, ALink, st); + finally + st.Free; end; end; @@ -1047,7 +1045,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St if SameText(AWebsite, Website) and SameText(Alink, Link) then begin p := i; - GetParams(dlCh, downloadedChapterList); + dlCh.Text := DownloadedChapterList; Break; end; @@ -1069,7 +1067,7 @@ procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: St //merge the links with Items[p].FavoriteInfo do begin - downloadedChapterList := downloadedChapterList + SetParams(ch); + DownloadedChapterList += ch.Text; currentChapter := IntToStr(dlCh.Count + ch.Count); end; MainForm.UpdateVtFavorites; From 4a77c09f6092d05a45f81d669e3519903bd4f6ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 24 Feb 2017 06:36:35 +0800 Subject: [PATCH 1553/2794] added option to show/hide balloon hint --- baseunits/FMDOptions.pas | 8 +++- baseunits/uDownloadsManager.pas | 55 +++++++++++++++----------- mangadownloader/forms/frmMain.lfm | 30 +++++++++----- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 4 ++ mangadownloader/languages/fmd.el_GR.po | 4 ++ mangadownloader/languages/fmd.en.po | 9 +++-- mangadownloader/languages/fmd.es.po | 4 ++ mangadownloader/languages/fmd.id_ID.po | 9 +++-- mangadownloader/languages/fmd.pl_PL.po | 4 ++ mangadownloader/languages/fmd.po | 4 ++ mangadownloader/languages/fmd.pt_BR.po | 4 ++ mangadownloader/md.lpi | 4 +- 13 files changed, 96 insertions(+), 44 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 0cde198c4..6d5390be5 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -91,6 +91,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionLetFMDDo: TFMDDo = DO_NOTHING; + // saveto OptionChangeUnicodeCharacter: Boolean = False; OptionChangeUnicodeCharacterStr: String = '_'; OptionGenerateMangaFolder: Boolean = False; @@ -105,13 +106,14 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionConvertDigitChapterLength: Integer; OptionPDFQuality: Cardinal = 95; - OptionUpdateListNoMangaInfo: Boolean = False; - OptionUpdateListRemoveDuplicateLocalData: Boolean = False; OptionMaxThreads: Integer = 1; + // view OptionEnableLoadCover: Boolean = False; + OptionShowBalloonHint: Boolean = True; + // updates OptionAutoCheckLatestVersion: Boolean = True; OptionAutoCheckFavStartup: Boolean = True; OptionAutoCheckFavInterval: Boolean = True; @@ -119,6 +121,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionNewMangaTime: Cardinal = 1; OptionAutoCheckFavDownload: Boolean = False; OptionAutoCheckFavRemoveCompletedManga: Boolean = False; + OptionUpdateListNoMangaInfo: Boolean = False; + OptionUpdateListRemoveDuplicateLocalData: Boolean = False; OptionHTTPUseGzip: Boolean = True; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ca6174929..bbd4f9357 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -86,6 +86,7 @@ TTaskThread = class(THTTPThread) FIsForDelete: Boolean; procedure SetCurrentWorkingDir(AValue: String); procedure SetIsForDelete(AValue: Boolean); + procedure SyncShowBallonHint; protected procedure CheckOut; procedure Execute; override; @@ -93,7 +94,7 @@ TTaskThread = class(THTTPThread) procedure Compress; procedure SyncStop; // show notification when download completed - procedure SyncShowBaloon; + procedure ShowBalloonHint; public //additional parameter httpCookies: String; @@ -870,28 +871,10 @@ procedure TTaskThread.SyncStop; Container.Manager.CheckAndActiveTask(FCheckAndActiveTaskFlag); end; -procedure TTaskThread.SyncShowBaloon; +procedure TTaskThread.ShowBalloonHint; begin - with MainForm.TrayIcon, Container.DownloadInfo do - begin - if Container.Status = STATUS_FAILED then - begin - BalloonFlags := bfError; - BalloonHint := QuotedStrd(Title); - if Status = '' then - BalloonHint := BalloonHint + ' - ' + RS_Failed - else - BalloonHint := BalloonHint + LineEnding + Status; - end - else - if Container.Status = STATUS_FINISH then - begin - BalloonFlags := bfInfo; - BalloonHint := - '"' + Container.DownloadInfo.title + '" - ' + RS_Finish; - end; - ShowBalloonHint; - end; + if OptionShowBalloonHint then + Synchronize(SyncShowBallonHint); end; function TDownloadThread.DownloadImage: Boolean; @@ -997,6 +980,30 @@ procedure TTaskThread.SetIsForDelete(AValue: Boolean); FIsForDelete := AValue; end; +procedure TTaskThread.SyncShowBallonHint; +begin + with MainForm.TrayIcon, Container.DownloadInfo do + begin + if Container.Status = STATUS_FAILED then + begin + BalloonFlags := bfError; + BalloonHint := QuotedStrd(Title); + if Status = '' then + BalloonHint := BalloonHint + ' - ' + RS_Failed + else + BalloonHint := BalloonHint + LineEnding + Status; + end + else + if Container.Status = STATUS_FINISH then + begin + BalloonFlags := bfInfo; + BalloonHint := + '"' + Container.DownloadInfo.title + '" - ' + RS_Finish; + end; + ShowBalloonHint; + end; +end; + procedure TTaskThread.CheckOut; var currentMaxThread: Integer; @@ -1159,7 +1166,7 @@ procedure TTaskThread.Execute; Container.CurrentDownloadChapterPtr, Container.ChapterLinks.Count, RS_FailedToCreateDir]); - SyncShowBaloon; + ShowBalloonHint; Exit; end; @@ -1346,7 +1353,7 @@ procedure TTaskThread.Execute; Container.DownloadInfo.Status := Format('[%d/%d] %s',[Container.ChapterLinks.Count,Container.ChapterLinks.Count,RS_Finish]); Container.DownloadInfo.Progress := ''; end; - Synchronize(SyncShowBaloon); + ShowBalloonHint; except on E: Exception do MainForm.ExceptionHandler(Self, E); diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0435d4fc2..7b62b407c 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2546,6 +2546,16 @@ object MainForm: TMainForm ParentFont = False TabOrder = 3 end + object cbOptionShowBalloonHint: TCheckBox + Left = 4 + Height = 19 + Top = 246 + Width = 523 + Align = alTop + Caption = 'Show balloon hint' + ParentFont = False + TabOrder = 4 + end end object tsConnections: TTabSheet Caption = 'Connections' @@ -6850,8 +6860,8 @@ object MainForm: TMainForm object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - Left = 240 - Top = 184 + Left = 560 + Top = 472 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( @@ -6956,28 +6966,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - Left = 336 - Top = 128 + Left = 656 + Top = 416 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - Left = 240 - Top = 256 + Left = 440 + Top = 472 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - Left = 336 - Top = 184 + Left = 656 + Top = 472 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - Left = 376 - Top = 256 + Left = 480 + Top = 472 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 98e15a905..c3b0f807e 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -153,6 +153,7 @@ {"hash":345509,"name":"tmainform.rgdroptargetmode.caption","sourcebytes":[77,111,100,101],"value":"Mode"}, {"hash":117603058,"name":"tmainform.cboptionenableloadcover.caption","sourcebytes":[69,110,97,98,108,101,32,108,111,97,100,32,109,97,110,103,97,32,99,111,118,101,114],"value":"Enable load manga cover"}, {"hash":150918338,"name":"tmainform.cboptionshowdownloadtoolbardeleteall.caption","sourcebytes":[83,104,111,119,32,34,68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115,34,32,105,110,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show \"Delete all completed tasks\" in downloads toolbar"}, +{"hash":81333124,"name":"tmainform.cboptionshowballoonhint.caption","sourcebytes":[83,104,111,119,32,98,97,108,108,111,111,110,32,104,105,110,116],"value":"Show balloon hint"}, {"hash":199270675,"name":"tmainform.tsconnections.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,115],"value":"Connections"}, {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fd349b5be..7c6bca374 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -53,6 +53,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionAutoOpenFavStartup: TCheckBox; cbOptionEnableLoadCover: TCheckBox; + cbOptionShowBalloonHint: TCheckBox; cbOptionGenerateChapterFolder: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadMangalistDialog: TCheckBox; @@ -4552,6 +4553,7 @@ procedure TMainForm.LoadOptions; cbOptionShowDownloadToolbar.Checked := ReadBool('view', 'ShowDownloadsToolbar', True); cbOptionShowDownloadToolbarDeleteAll.Checked := ReadBool('view', 'ShowDownloadsToolbarDeleteAll', False); cbOptionEnableLoadCover.Checked := ReadBool('view', 'LoadMangaCover', True); + cbOptionShowBalloonHint.Checked := ReadBool('view', 'ShowBalloonHint', OptionShowBalloonHint); ckDropTarget.Checked := ReadBool('droptarget', 'Show', False); frmDropTarget.FWidth := ReadInteger('droptarget', 'Width', frmDropTarget.FWidth); frmDropTarget.FHeight := ReadInteger('droptarget', 'Heigth', frmDropTarget.FHeight); @@ -4692,6 +4694,7 @@ procedure TMainForm.SaveOptions; WriteBool('view', 'ShowDownloadsToolbar', cbOptionShowDownloadToolbar.Checked); WriteBool('view', 'ShowDownloadsToolbarDeleteAll', cbOptionShowDownloadToolbarDeleteAll.Checked); WriteBool('view', 'LoadMangaCover', cbOptionEnableLoadCover.Checked); + WriteBool('view', 'ShowBalloonHint', cbOptionShowBalloonHint.Checked); if not (isExiting and Assigned(FormDropTarget)) then SaveDropTargetFormInformation; @@ -4833,6 +4836,7 @@ procedure TMainForm.ApplyOptions; tbDownloadDeleteCompleted.Visible := cbOptionShowDownloadToolbarDeleteAll.Checked; tbSeparator1.Visible := tbDownloadDeleteCompleted.Visible; ShowDropTarget(ckDropTarget.Checked); + OptionShowBalloonHint := cbOptionShowBalloonHint.Checked; //connection DLManager.maxDLTasks := seOptionMaxParallel.Value; diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 4334db5b9..c4d8ee96f 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -667,6 +667,10 @@ msgstr "HTTP" msgid "Remove manga name from chapter" msgstr "Αφαίρεση ονόματος manga από το κεφάλαιο" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Διαγραφή εργασίας / αγαπημένου" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index c19171cd8..6a93d7c5b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_US\n" -"X-Generator: Poedit 1.8.8\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: batoto.rs_showalllang @@ -569,7 +569,7 @@ msgstr "Visit my blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -663,6 +663,10 @@ msgstr "HTTP" msgid "Remove manga name from chapter" msgstr "Remove manga name from chapter" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "Show balloon hint" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Delete task/favorite" @@ -2183,4 +2187,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 94ec2f035..4b9689a8d 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -651,6 +651,10 @@ msgstr "HTTP" msgid "Remove manga name from chapter" msgstr "Remover Nombre del Manga del Capitulo" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Borrar Tarea/Favorito" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index aca471444..9f7bac136 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.8.8\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=1; plural=0;\n" #: batoto.rs_showalllang @@ -560,7 +560,7 @@ msgstr "Kunjungi blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -651,6 +651,10 @@ msgstr "HTTP" msgid "Remove manga name from chapter" msgstr "Hapus nama komik dari bab" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "Tampilkan balon pemberitahuan" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Hapus unduhan/kesukaan" @@ -2163,4 +2167,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index bbd27c88e..2c0328d8a 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -663,6 +663,10 @@ msgstr "HTTP" msgid "Remove manga name from chapter" msgstr "Usuń nazwę mangi z rozdziału" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Usuń zadanie/ulubione" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 7e25045d2..ebc1e6709 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -616,6 +616,10 @@ msgstr "" msgid "Remove manga name from chapter" msgstr "" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index febf95875..9cf9e59c9 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -663,6 +663,10 @@ msgstr "HTTP" msgid "Remove manga name from chapter" msgstr "Remover nome do mangá do capítulo" +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "" + #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" msgstr "Apagar tarefa/favorito" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6d8b700a8..701ba6c1b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -41,7 +41,7 @@ <TargetCPU Value="x86_64"/> <TargetOS Value="win64"/> <Optimizations> - <OptimizationLevel Value="3"/> + <OptimizationLevel Value="4"/> <VariablesInRegisters Value="True"/> </Optimizations> </CodeGeneration> @@ -330,7 +330,7 @@ <TargetCPU Value="i386"/> <TargetOS Value="win32"/> <Optimizations> - <OptimizationLevel Value="3"/> + <OptimizationLevel Value="4"/> <VariablesInRegisters Value="True"/> </Optimizations> </CodeGeneration> From bb04535d41727e0764a6d96bbc556207d66e5ae2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Feb 2017 08:34:54 +0800 Subject: [PATCH 1554/2794] favoritesdb, pk first --- baseunits/FavoritesDB.pas | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index dfcb24772..a1e1565ee 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -43,8 +43,8 @@ constructor TFavoritesDB.Create(const AFilename: String); Filename := AFilename; TableName := 'favorites'; CreateParams := - '"order" INTEGER,' + '"websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY,' + + '"order" INTEGER,' + '"website" TEXT,' + '"link" TEXT,' + '"title" TEXT,' + @@ -53,18 +53,6 @@ constructor TFavoritesDB.Create(const AFilename: String); '"saveto" TEXT'; SelectParams := 'SELECT * FROM "favorites" ORDER BY "order"'; - { - CREATE TABLE "favorites" ( - "order" TEXT, - "websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY, - "website" TEXT, - "link" TEXT, - "title" TEXT, - "currentchapter" TEXT, - "downloadedchapterlist" TEXT, - "saveto" TEXT - ); - } end; function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, @@ -75,10 +63,10 @@ function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, if not Connection.Connected then Exit; try Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" ('+ - '"order","websitelink","website","link","title","currentchapter","downloadedchapterlist","saveto")'+ + '"websitelink","order","website","link","title","currentchapter","downloadedchapterlist","saveto")'+ ' VALUES ("' + - IntToStr(AOrder) + '","' + AWebsite + ALink + '","' + + IntToStr(AOrder) + '","' + AWebsite + '","' + ALink + '","' + ATitle + '","' + From 5632fd1fc0f6773eef494a396736934085249544 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Feb 2017 09:44:12 +0800 Subject: [PATCH 1555/2794] favoritesdb, use lowercase websitelink --- baseunits/FavoritesDB.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index a1e1565ee..05c195b65 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -65,7 +65,7 @@ function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" ('+ '"websitelink","order","website","link","title","currentchapter","downloadedchapterlist","saveto")'+ ' VALUES ("' + - AWebsite + ALink + '","' + + LowerCase(AWebsite + ALink) + '","' + IntToStr(AOrder) + '","' + AWebsite + '","' + ALink + '","' + @@ -87,7 +87,7 @@ procedure TFavoritesDB.Delete(const AWebsite, ALink: String); if not Connection.Connected then Exit; try Connection.ExecuteDirect( - 'DELETE FROM "favorites" WHERE "websitelink"="' + AWebsite + ALink + '"'); + 'DELETE FROM "favorites" WHERE "websitelink"="' + LowerCase(AWebsite + ALink) + '"'); Inc(FCommitCount); if FCommitCount >= FAutoCommitCount then Commit; From 5175fca4109a2ec2426973666891055d3997eb15 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Feb 2017 09:59:05 +0800 Subject: [PATCH 1556/2794] added method mergecaseinsensitive --- baseunits/uBaseUnit.pas | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d7adca60a..48363ec6d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -710,6 +710,8 @@ procedure InvertStrings(const St: TStringList); overload; procedure InvertStrings(const Sts: array of TStringList); overload; procedure TrimStrings(TheStrings: TStrings); procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Integer = 0); +function MergeCaseInsensitive(Strs: array of String): String; overload; +function MergeCaseInsensitive(Strs: array of TStrings): String; overload; procedure CleanHTMLComments(const Str: TStringList); function FixHTMLTagQuote(const s: String): String; @@ -1807,6 +1809,44 @@ procedure RemoveDuplicateStrings(Strs: array of TStringList; RemIndex: Integer); end; end; +function MergeCaseInsensitive(Strs: array of String): String; +var + s: TStringList; + i: Integer; +begin + if Length(Strs) = 0 then Exit; + s := TStringList.Create; + try + s.CaseSensitive := False; + s.Duplicates := dupIgnore; + s.Sorted := True; + for i := Low(Strs) to High(Strs) do + s.AddText(Strs[i]); + Result := s.Text; + finally + s.Free; + end; +end; + +function MergeCaseInsensitive(Strs: array of TStrings): String; +var + s: TStringList; + i: Integer; +begin + if Length(Strs) = 0 then Exit; + s := TStringList.Create; + try + s.CaseSensitive := False; + s.sorted := True; + s.Duplicates := dupIgnore; + for i := Low(Strs) to High(Strs) do + s.AddText(Strs[i].Text); + Result := s.Text; + finally + s.Free; + end; +end; + procedure CleanHTMLComments(const Str: TStringList); var i: Integer; From 617e2250e8b49d8fabdfcff2ea99149499636768 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Feb 2017 10:28:17 +0800 Subject: [PATCH 1557/2794] fixed various issue with downloadedchapterlist --- baseunits/DownloadedChaptersDB.pas | 88 ++++++++++++++++++------------ baseunits/uData.pas | 3 +- baseunits/uFavoritesManager.pas | 86 ++++++----------------------- baseunits/uGetMangaInfosThread.pas | 3 +- baseunits/uSilentThread.pas | 12 +--- mangadownloader/forms/frmMain.pas | 14 ++--- 6 files changed, 78 insertions(+), 128 deletions(-) diff --git a/baseunits/DownloadedChaptersDB.pas b/baseunits/DownloadedChaptersDB.pas index a517d744b..20a6ee73d 100644 --- a/baseunits/DownloadedChaptersDB.pas +++ b/baseunits/DownloadedChaptersDB.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, SQLiteData, LazFileUtils; + Classes, SysUtils, SQLiteData, uBaseUnit, LazFileUtils; type @@ -66,46 +66,62 @@ procedure TDownloadedChaptersDB.SetChapters(const AWebsiteLink: String; AValue: try if Locate('websitelink', LowerCase(AWebsiteLink), []) then begin - c := CleanStr(AValue); - s := Fields[1].AsString; - if c = s then Exit; - dc := TStringList.Create; - ds := TStringList.Create; - try - dc.AddText(c); - ds.Sorted := True; - ds.Duplicates := dupIgnore; - ds.AddText(s); - for i := 0 to dc.Count - 1 do - begin - dc[i] := Trim(dc[i]); - if dc[i] <> '' then - ds.Add(dc[i]); - end; - Edit; - try - Fields[1].AsString := ds.Text; - Post; - except - CancelUpdates; - end; - finally - dc.Free; - ds.Free; - end; + Edit; + Fields[1].AsString := MergeCaseInsensitive([Fields[1].AsString, AValue]); end else begin Append; - try - Fields[0].AsString := LowerCase(AWebsiteLink); - Fields[1].AsString := CleanStr(AValue); - Post; - IncRecordCount; - except - CancelUpdates; - end; + Fields[0].AsString := LowerCase(AWebsiteLink); + Fields[1].AsString := AValue; end; + try + Post; + except + CancelUpdates; + end; + + // c := AValue; + // s := Fields[1].AsString; + // if c = s then Exit; + // dc := TStringList.Create; + // ds := TStringList.Create; + // try + // dc.AddText(c); + // ds.CaseSensitive := False; + // ds.Duplicates := dupIgnore; + // ds.Sorted := True; + // ds.AddText(s); + // for i := 0 to dc.Count - 1 do + // begin + // dc[i] := Trim(dc[i]); + // if dc[i] <> '' then + // ds.Add(dc[i]); + // end; + // Edit; + // try + // Fields[1].AsString := ds.Text; + // Post; + // except + // CancelUpdates; + // end; + // finally + // dc.Free; + // ds.Free; + // end; + //end + //else + //begin + // Append; + // try + // Fields[0].AsString := LowerCase(AWebsiteLink); + // Fields[1].AsString := AValue; + // Post; + // IncRecordCount; + // except + // CancelUpdates; + // end; + //end; finally LeaveCriticalsection(locklocate); end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index ebe5c9baf..1c5b2d211 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1456,7 +1456,8 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR end; with mangaInfo do begin - if mangaInfo.link = '' then mangaInfo.link := RemoveHostFromURL(mangaInfo.url); + if link = '' then + link := RemoveHostFromURL(mangaInfo.url); // cleanup info coverLink := CleanURL(coverLink); diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 2ca81b3cc..2374f043e 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -124,9 +124,7 @@ TFavoriteManager = class // Backup to favorites.db procedure Backup; // Add FFavorites downloadedchapterlist - procedure AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); - overload; - procedure AddToDownloadedChaptersList(const AWebsite, Alink: String; AValue: TStrings); overload; + procedure AddToDownloadedChaptersList(const AWebsite, ALink: String; const AValue: TStrings); // sorting procedure Sort(const AColumn: Integer); // critical section @@ -776,13 +774,11 @@ procedure TFavoriteManager.ShowResult; DownloadInfo.Status := Format('[%d/%d] %s',[0,ChapterLinks.Count,RS_Stopped]); Status := STATUS_STOP; end; + // add to downloaded chapter list + FavoriteInfo.downloadedChapterList := MergeCaseInsensitive([FavoriteInfo.DownloadedChapterList, chapterLinks.Text]); + // add to downloaded chapter list in downloadmanager + DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := chapterLinks.Text; end; - // add to downloaded chapter list - FavoriteInfo.downloadedChapterList := NewMangaInfo.chapterLinks.Text; - // add to downloaded chapter list in downloadmanager - DLManager.DownloadedChapters.Chapters[FavoriteInfo.Website + FavoriteInfo.Link] := - NewMangaInfo.chapterLinks.Text; - // free unused objects FreeAndNil(NewMangaInfo); FreeAndNil(NewMangaInfoChaptersPos); @@ -1010,73 +1006,23 @@ procedure TFavoriteManager.Backup; FFavoritesDB.Commit; end; -procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, ALink, AValue: String); +procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, + ALink: String; const AValue: TStrings); var - st: TStringList; + i: Integer; begin - if (AWebsite = '') or (ALink = '') or (AValue = '') then Exit; - st := TStringList.Create; + if (Items.Count = 0) or (AWebsite = '') or (ALink = '') or (AValue.Count = 0) then Exit; try - st.Text := AValue; - AddToDownloadedChaptersList(AWebsite, ALink, st); - finally - st.Free; - end; -end; - -procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, Alink: String; AValue: TStrings); -var - i, p, q: Integer; - Ch, dlCh: TStringList; -begin - if Count = 0 then - Exit; - if (AWebsite <> '') and (Alink <> '') and (AValue.Count > 0) then - begin - Ch := TStringList.Create; - dlCh := TStringList.Create; EnterCriticalsection(CS_Favorites); - try - p := -1; - //locate the link - if Items.Count > 1 then - for i := 0 to Items.Count - 1 do - with Items[i].FavoriteInfo do - if SameText(AWebsite, Website) and SameText(Alink, Link) then - begin - p := i; - dlCh.Text := DownloadedChapterList; - Break; - end; - - //if found the FavoriteItem - if p > -1 then - begin - //remove if links found on downloadedchapterlist - Ch.Assign(AValue); - if dlCh.Count > 0 then + for i := 0 to Items.Count - 1 do + with Items[i].FavoriteInfo do + if SameText(AWebsite, Website) and SameText(ALink, Link) then begin - dlCh.Sorted := True; - i := 0; - while i < Ch.Count do - if dlCh.Find(Ch[i], q) then - Ch.Delete(i) - else - Inc(i); - end; - - //merge the links - with Items[p].FavoriteInfo do begin - DownloadedChapterList += ch.Text; - currentChapter := IntToStr(dlCh.Count + ch.Count); + DownloadedChapterList := MergeCaseInsensitive([DownloadedChapterList, AValue.Text]); + Break; end; - MainForm.UpdateVtFavorites; - end; - finally - LeaveCriticalsection(CS_Favorites); - end; - dlCh.Free; - Ch.Free; + finally + LeaveCriticalsection(CS_Favorites); end; end; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 84fa23398..8359014bd 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -86,7 +86,6 @@ procedure TGetMangaInfosThread.DoGetInfos; FInfo.mangaInfo.genres := MainForm.dataProcess.Value[filterPos, DATA_PARAM_GENRES]; FNumChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); end; - FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolder; FInfo.isRemoveUnicode := OptionChangeUnicodeCharacter; @@ -223,7 +222,7 @@ procedure TGetMangaInfosThread.MainThreadShowInfos; dataProcess.Refresh; vtMangaList.EndUpdate; end; - ShowInformation(FTitle, FWebsite, FLink); + ShowInformation(mangaInfo.title, mangaInfo.website, mangaInfo.link); end; except on E: Exception do diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 83a577d4d..7600128bb 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -443,8 +443,7 @@ destructor TSilentThread.Destroy; procedure TSilentAddToFavThread.MainThreadAfterChecking; var - s, s2: String; - i: Integer; + s: String; begin try with MainForm do @@ -469,17 +468,12 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; '', OptionChangeUnicodeCharacter, OptionChangeUnicodeCharacterStr); - s2 := ''; - if (Info.mangaInfo.numChapter > 0) then - begin - for i := 0 to Info.mangaInfo.numChapter - 1 do - s2 := s2 + Info.mangaInfo.chapterLinks.Strings[i] + SEPERATOR; - end; + if Trim(title) = '' then title := Info.mangaInfo.title; FavoriteManager.Add(title, IntToStr(Info.mangaInfo.numChapter), - s2, + info.mangaInfo.chapterLinks.Text, website, CorrectPathSys(s), URL); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7c6bca374..bb99dd898 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2073,7 +2073,8 @@ procedure TMainForm.btDownloadClick(Sender: TObject); end; Website:=mangaInfo.website; DownloadInfo.Website:=mangaInfo.website; - DownloadInfo.Link:=mangaInfo.url; + DownloadInfo.Link:=mangaInfo.link; + SendLog('addedlink='+DownloadInfo.Link); DownloadInfo.Title:=mangaInfo.title; DownloadInfo.DateTime:=Now; DownloadInfo.SaveTo:=s; @@ -2094,8 +2095,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); procedure TMainForm.btAddToFavoritesClick(Sender: TObject); var - s, s2: String; - i: Integer; + s: String; begin if mangaInfo.title <> '' then begin @@ -2113,13 +2113,7 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); OptionChangeUnicodeCharacter, OptionChangeUnicodeCharacterStr); - // downloaded chapters - s2 := ''; - if mangaInfo.numChapter > 0 then - for i := 0 to mangaInfo.numChapter - 1 do - s2 := s2 + mangaInfo.chapterLinks.Strings[i] + SEPERATOR; - - FavoriteManager.Add(mangaInfo.title, IntToStr(mangaInfo.numChapter), s2, + FavoriteManager.Add(mangaInfo.title, IntToStr(mangaInfo.numChapter), mangaInfo.chapterLinks.Text, mangaInfo.website, CleanAndExpandDirectory(s), mangaInfo.link); vtFavorites.NodeDataSize := SizeOf(TFavoriteInfo); UpdateVtFavorites; From adbec0ca272e7ec143f330ed4419a0e947e73ed3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Feb 2017 11:57:29 +0800 Subject: [PATCH 1558/2794] dbdataprocess, pk first --- baseunits/DBDataProcess.pas | 50 ++++++++++++++++++------------------- baseunits/uBaseUnit.pas | 4 +-- baseunits/uUpdateThread.pas | 10 ++++---- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index da029a883..697970f93 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -85,7 +85,7 @@ TDBDataProcess = class(TObject) function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter, JDN: Integer): Boolean; overload; function AddData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; - NumChapter: Integer; JDN: TDateTime): Boolean; overload; + NumChapter: Integer; JDN: TDateTime): Boolean; overload; inline; function UpdateData(Const Title, Link, Authors, Artists, Genres, Status, Summary: String; NumChapter: Integer; AWebsite: String = ''): Boolean; function DeleteData(const RecIndex: Integer): Boolean; @@ -111,22 +111,21 @@ TDBDataProcess = class(TObject) end; const - DBDataProcessParam = 'title,link,authors,artists,genres,status,summary,numchapter,jdn'; + DBDataProcessParam = '"link","title","authors","artists","genres","status","summary","numchapter","jdn"'; DBDataProcessParams: array [0..8] of ShortString = - ('title', 'link', 'authors', 'artists', 'genres', 'status', + ('link', 'title', 'authors', 'artists', 'genres', 'status', 'summary', 'numchapter', 'jdn'); DBTempFieldWebsiteIndex = Length(DBDataProcessParams); - DBDataProccesCreateParam = '('#13#10 + - '"title" TEXT,'#13#10 + - '"link" TEXT NOT NULL PRIMARY KEY,'#13#10 + - '"authors" TEXT,'#13#10 + - '"artists" TEXT,'#13#10 + - '"genres" TEXT,'#13#10 + - '"status" TEXT,'#13#10 + - '"summary" TEXT,'#13#10 + - '"numchapter" INTEGER,'#13#10 + - '"jdn" INTEGER'#13#10 + - ');'; + DBDataProccesCreateParam = + '"link" TEXT NOT NULL PRIMARY KEY,' + + '"title" TEXT,' + + '"authors" TEXT,' + + '"artists" TEXT,' + + '"genres" TEXT,' + + '"status" TEXT,' + + '"summary" TEXT,' + + '"numchapter" INTEGER,' + + '"jdn" INTEGER'; function DBDataFilePath(const AWebsite: String): String; procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); @@ -308,8 +307,8 @@ procedure TDBDataProcess.CreateTable; if FConn.Connected then begin FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); - FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + - DBDataProccesCreateParam); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + ' (' + + DBDataProccesCreateParam + ');'); FTrans.Commit; end; end; @@ -317,7 +316,8 @@ procedure TDBDataProcess.CreateTable; procedure TDBDataProcess.ConvertNewTable; begin if FQuery.Active = False then Exit; - if (FieldTypeNames[FQuery.FieldByName('title').DataType] <> Fieldtypenames[ftMemo]) or + if (FQuery.Fields[0].FieldName <> 'link') or + (FieldTypeNames[FQuery.FieldByName('title').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[FQuery.FieldByName('link').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[FQuery.FieldByName('authors').DataType] <> Fieldtypenames[ftMemo]) or (FieldTypeNames[FQuery.FieldByName('artists').DataType] <> Fieldtypenames[ftMemo]) or @@ -328,8 +328,8 @@ procedure TDBDataProcess.ConvertNewTable; FQuery.Close; with fconn do begin ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+FTableName)); - ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+FTableName)+#13#10+DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+FTableName)+' SELECT * FROM '+QuotedStrd(FTableName)); + ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+FTableName)+ ' (' + DBDataProccesCreateParam + ')'); + ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+FTableName)+' ('+DBDataProcessParam+') SELECT ' + DBDataProcessParam + ' FROM '+QuotedStrd(FTableName)); ExecuteDirect('DROP TABLE '+QuotedStrd(FTableName)); ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+FTableName)+' RENAME TO '+QuotedStrd(FTableName)); end; @@ -793,8 +793,8 @@ function TDBDataProcess.AddData(const Title, Link, Authors, Artists, Genres, try FConn.ExecuteDirect( 'INSERT INTO '+QuotedStrd(FTableName)+' ('+DBDataProcessParam+') VALUES ('+ - QuotedStr(Title)+', '+ QuotedStr(Link)+', '+ + QuotedStr(Title)+', '+ QuotedStr(Authors)+', '+ QuotedStr(Artists)+', '+ QuotedStr(Genres)+', '+ @@ -1089,6 +1089,7 @@ function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList end; end; Result := FFiltered; + Result := FFiltered; end; end; @@ -1142,13 +1143,10 @@ procedure TDBDataProcess.Sort; with FConn do try ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName + '_ordered')); - ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + - DBDataProccesCreateParam); - ExecuteDirect('INSERT INTO '+QuotedStrd(FTableName + '_ordered') + - ' SELECT * FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); + ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName + '_ordered') + ' (' + DBDataProccesCreateParam +')'); + ExecuteDirect('INSERT INTO '+QuotedStrd(FTableName + '_ordered') + ' (' + DBDataProcessParam + ') SELECT '+ DBDataProcessParam +' FROM ' + QuotedStrd(FTableName) + ' ORDER BY "title" COLLATE NATCMP'); ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + - 'RENAME TO ' + QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrd(FTableName + '_ordered') + ' RENAME TO ' + QuotedStrd(FTableName)); FTrans.Commit; VacuumTable; except diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 48363ec6d..f95c560f5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -31,8 +31,8 @@ interface UTF8BOM = #$EF#$BB#$BF; - DATA_PARAM_TITLE = 0; - DATA_PARAM_LINK = 1; + DATA_PARAM_LINK = 0; + DATA_PARAM_TITLE = 1; DATA_PARAM_AUTHORS = 2; DATA_PARAM_ARTISTS = 3; DATA_PARAM_GENRES = 4; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 5a53fccd3..62aa4a84e 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -477,8 +477,8 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; Modules.IncActiveConnectionCount(ModuleId); i:=threads.Add(TUpdateListThread.Create); if cs=CS_INFO then begin - TUpdateListThread(threads[i]).title:=tempDataProcess.Value[workPtr,0]; - TUpdateListThread(threads[i]).link:=tempDataProcess.Value[workPtr,1]; + TUpdateListThread(threads[i]).title:=tempDataProcess.Value[workPtr,DATA_PARAM_TITLE]; + TUpdateListThread(threads[i]).link:=tempDataProcess.Value[workPtr,DATA_PARAM_LINK]; end; TUpdateListThread(threads[i]).checkStyle:=cs; TUpdateListThread(threads[i]).manager:=Self; @@ -508,7 +508,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; CS_DIRECTORY_PAGE_2: s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; CS_INFO: - s := Format('%s | %s "%s"', [s, RS_GettingInfo, tempDataProcess.Value[workPtr-1,0]]); + s := Format('%s | %s "%s"', [s, RS_GettingInfo, tempDataProcess.Value[workPtr-1,DATA_PARAM_TITLE]]); end; FStatus := s; MainForm.ulWorkPtr := workPtr + 1; @@ -660,8 +660,8 @@ procedure TUpdateListManagerThread.Execute; for k:=0 to tempDataProcess.RecordCount-1 do begin mainDataProcess.AddData( - tempDataProcess.Value[k,0], - tempDataProcess.Value[k,1], + tempDataProcess.Value[k,DATA_PARAM_TITLE], + tempDataProcess.Value[k,DATA_PARAM_LINK], '', '', '', From 760efff5abfd6bc1ff712e883c9857b09994bb27 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Feb 2017 12:00:12 +0800 Subject: [PATCH 1559/2794] sqlitedata, add autovacuum --- baseunits/SQLiteData.pas | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 8550fb70a..944db355a 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -22,6 +22,7 @@ TSQLite3ConnectionH = class(TSQLite3Connection) TSQliteData = class private + FAutoVacuum: Boolean; FConn: TSQLite3ConnectionH; FOnError: TExceptionEvent; FTrans: TSQLTransaction; @@ -34,6 +35,7 @@ TSQliteData = class procedure DoOnError(E: Exception); function GetAutoApplyUpdates: Boolean; procedure SetAutoApplyUpdates(AValue: Boolean); + procedure SetAutoVacuum(AValue: Boolean); procedure SetCreateParams(AValue: String); procedure SetOnError(AValue: TExceptionEvent); procedure SetSelectParams(AValue: String); @@ -67,6 +69,7 @@ TSQliteData = class property SelectParams: String read FSelectParams write SetSelectParams; property RecordCount: Integer read FRecordCount; property AutoApplyUpdates: Boolean read GetAutoApplyUpdates write SetAutoApplyUpdates; + property AutoVacuum: Boolean read FAutoVacuum write SetAutoVacuum; property OnError: TExceptionEvent read FOnError write SetOnError; end; @@ -100,6 +103,12 @@ procedure TSQliteData.SetAutoApplyUpdates(AValue: Boolean); FQuery.Options := FQuery.Options - [sqoAutoApplyUpdates]; end; +procedure TSQliteData.SetAutoVacuum(AValue: Boolean); +begin + if FAutoVacuum = AValue then Exit; + FAutoVacuum := AValue; +end; + procedure TSQliteData.SetCreateParams(AValue: String); begin if FCreateParams = AValue then Exit; @@ -233,6 +242,7 @@ constructor TSQliteData.Create; FQuery.DataBase := FTrans.DataBase; FQuery.Transaction := FTrans; AutoApplyUpdates := True; + FAutoVacuum := True; FRecordCount := 0; FFilename := ''; FTableName := 'maintable'; @@ -285,7 +295,8 @@ procedure TSQliteData.Close; if not FConn.Connected then Exit; try Save; - Vacuum; + if FAutoVacuum then + Vacuum; CloseTable; FTrans.Active := False; FConn.Close; From bd9470441d712ebaa2c6cce5b7759f92402e5b4d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Feb 2017 13:38:10 +0800 Subject: [PATCH 1560/2794] hentai2read, fixed download and mangainfo. closed #492. --- baseunits/modules/Hentai2Read.pas | 62 ++++++------------------------- 1 file changed, 11 insertions(+), 51 deletions(-) diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index d82e659fa..df6ab8a06 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -10,7 +10,7 @@ interface const dirurl = '/hentai-list/all/any/last-added/'; - cdnurl = 'http://hentaicdn.com'; + cdnurl = 'http://static.hentaicdn.com/hentai'; implementation @@ -66,7 +66,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then @@ -80,26 +79,12 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; with TXQueryEngineHTML.Create(Document) do try coverLink := MaybeFillHost(cdnurl, XPathString('//img[@class="img-responsive border-black-op"]/@src')); - title := XPathString('//title/substring-before(.," Hentai - Read ")'); - authors := XPathStringAll( - '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Author")]/*[position()>1]', - ['-']); - artists := XPathStringAll( - '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Artist")]/*[position()>1]', - ['-']); - genres := XPathStringAll( - '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Parody") or starts-with(.,"Category") or starts-with(.,"Content") or starts-with(.,"Language")]/*[position()>1]', ['-']); - s := XPathString('//ul[@class="list list-simple-mini"]/li[starts-with(.,"Status")]'); - if s <> '' then - begin - s := LowerCase(s); - if Pos('ongoing', s) > 0 then - status := '1' - else if Pos('completed', s) > 0 then - status := '0'; - end; - summary := XPathStringAll( - '//ul[@class="list list-simple-mini"]/li[starts-with(.,"Storyline")]/*[position()>1]'); + title := XPathString('//h3[@class="block-title"]/a/text()'); + status := MangaInfoStatusIfPos(XPathString('//ul[contains(@class,"list-simple-mini")]/li[starts-with(.,"Status")]')); + authors := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li[starts-with(.,"Author")]/a'); + artists := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li[starts-with(.,"Artist")]/a'); + genres := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li/a'); + summary := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li[starts-with(.,"Storyline")]/*[position()>1]'); for v in XPath('//ul[starts-with(@class,"nav-chapters")]/li/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); @@ -117,9 +102,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String const Module: TModuleContainer): Boolean; var v: IXQValue; - Source: TStringList; - i: Integer; - s: String; begin Result := False; if DownloadThread = nil then @@ -131,35 +113,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - Source := TStringList.Create; - try - Source.LoadFromStream(Document); - if Source.Count > 0 then - for i := 0 to Source.Count - 1 do - if Pos('var rff_imageList', Source[i]) > 0 then - begin - s := SeparateRight(Source[i], '='); - if s <> '' then - begin - s := Trim(TrimRightChar(s, [';'])); - with TXQueryEngineHTML.Create(s) do - try - for v in XPath('json(*)()') do - PageLinks.Add(cdnurl + '/hentai' + v.toString); - finally - Free; - end; - end; - Break; - end; - finally - Source.Free; - end; if PageLinks.Count = 0 then with TXQueryEngineHTML.Create(Document) do try - PageNumber := XPath( - '(//ul[@class="dropdown-menu text-center list-inline"])[1]/li').Count; + for v in XPath('json(//script[contains(.,"images'' :")]/substring-before(substring-after(.,"images'' : "),"]")||"]")()') do + PageLinks.Add(cdnurl + v.toString); + if PageLinks.Count = 0 then + PageNumber := XPath('(//ul[@class="dropdown-menu text-center list-inline"])[1]/li').Count; finally Free; end; From c0e6310a422db6ec3757f885fae93b2354ccc6d7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Feb 2017 14:22:43 +0800 Subject: [PATCH 1561/2794] some changes in sqlitedata and update favoritesdb, downloadedchaptersdb --- 3rd/BESENPkg.lpk | 1 - baseunits/DownloadedChaptersDB.pas | 48 ++---------------------------- baseunits/FavoritesDB.pas | 10 +++---- baseunits/SQLiteData.pas | 20 ++++++++----- 4 files changed, 20 insertions(+), 59 deletions(-) diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk index 3660bde79..4e9d56eec 100644 --- a/3rd/BESENPkg.lpk +++ b/3rd/BESENPkg.lpk @@ -20,7 +20,6 @@ <Linking> <Debugging> <GenerateDebugInfo Value="False"/> - <TrashVariables Value="True"/> </Debugging> </Linking> </CompilerOptions> diff --git a/baseunits/DownloadedChaptersDB.pas b/baseunits/DownloadedChaptersDB.pas index 20a6ee73d..6349a7c1d 100644 --- a/baseunits/DownloadedChaptersDB.pas +++ b/baseunits/DownloadedChaptersDB.pas @@ -53,10 +53,6 @@ function TDownloadedChaptersDB.GetChapters(const AWebsiteLink: String): String; end; procedure TDownloadedChaptersDB.SetChapters(const AWebsiteLink: String; AValue: String); -var - dc, ds: TStringList; - c, s: String; - i: Integer; begin if AWebsiteLink = '' then Exit; if AValue = '' then Exit; @@ -80,48 +76,6 @@ procedure TDownloadedChaptersDB.SetChapters(const AWebsiteLink: String; AValue: except CancelUpdates; end; - - // c := AValue; - // s := Fields[1].AsString; - // if c = s then Exit; - // dc := TStringList.Create; - // ds := TStringList.Create; - // try - // dc.AddText(c); - // ds.CaseSensitive := False; - // ds.Duplicates := dupIgnore; - // ds.Sorted := True; - // ds.AddText(s); - // for i := 0 to dc.Count - 1 do - // begin - // dc[i] := Trim(dc[i]); - // if dc[i] <> '' then - // ds.Add(dc[i]); - // end; - // Edit; - // try - // Fields[1].AsString := ds.Text; - // Post; - // except - // CancelUpdates; - // end; - // finally - // dc.Free; - // ds.Free; - // end; - //end - //else - //begin - // Append; - // try - // Fields[0].AsString := LowerCase(AWebsiteLink); - // Fields[1].AsString := AValue; - // Post; - // IncRecordCount; - // except - // CancelUpdates; - // end; - //end; finally LeaveCriticalsection(locklocate); end; @@ -136,6 +90,8 @@ constructor TDownloadedChaptersDB.Create; CreateParams := 'websitelink VARCHAR(3000) NOT NULL PRIMARY KEY,' + 'chapters TEXT'; + FieldsParams := '"websitelink","chapters"'; + SelectParams := 'SELECT ' + FieldsParams + ' FROM "' + TableName + '"'; end; destructor TDownloadedChaptersDB.Destroy; diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index 05c195b65..f7759be4d 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -51,8 +51,8 @@ constructor TFavoritesDB.Create(const AFilename: String); '"currentchapter" TEXT,' + '"downloadedchapterlist" TEXT,' + '"saveto" TEXT'; - SelectParams := - 'SELECT * FROM "favorites" ORDER BY "order"'; + FieldsParams := '"websitelink","order","website","link","title","currentchapter","downloadedchapterlist","saveto"'; + SelectParams := 'SELECT ' + FieldsParams + ' FROM "'+TableName+'" ORDER BY "order"'; end; function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, @@ -62,9 +62,9 @@ function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, if (AWebsite = '') or (ALink = '') then Exit; if not Connection.Connected then Exit; try - Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" ('+ - '"websitelink","order","website","link","title","currentchapter","downloadedchapterlist","saveto")'+ - ' VALUES ("' + + Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" (' + + FieldsParams + + ') VALUES ("' + LowerCase(AWebsite + ALink) + '","' + IntToStr(AOrder) + '","' + AWebsite + '","' + diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 944db355a..b2ade98b4 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -24,6 +24,7 @@ TSQliteData = class private FAutoVacuum: Boolean; FConn: TSQLite3ConnectionH; + FFieldsParams: String; FOnError: TExceptionEvent; FTrans: TSQLTransaction; FQuery: TSQLQuery; @@ -37,6 +38,7 @@ TSQliteData = class procedure SetAutoApplyUpdates(AValue: Boolean); procedure SetAutoVacuum(AValue: Boolean); procedure SetCreateParams(AValue: String); + procedure SetFieldsParams(AValue: String); procedure SetOnError(AValue: TExceptionEvent); procedure SetSelectParams(AValue: String); protected @@ -67,6 +69,7 @@ TSQliteData = class property TableName: String read FTableName write FTableName; property CreateParams: String read FCreateParams write SetCreateParams; property SelectParams: String read FSelectParams write SetSelectParams; + property FieldsParams: String read FFieldsParams write SetFieldsParams; property RecordCount: Integer read FRecordCount; property AutoApplyUpdates: Boolean read GetAutoApplyUpdates write SetAutoApplyUpdates; property AutoVacuum: Boolean read FAutoVacuum write SetAutoVacuum; @@ -115,6 +118,12 @@ procedure TSQliteData.SetCreateParams(AValue: String); FCreateParams := TrimSet(Trim(AValue), ['(', ')', ';']); end; +procedure TSQliteData.SetFieldsParams(AValue: String); +begin + if FFieldsParams = AValue then Exit; + FFieldsParams := AValue; +end; + procedure TSQliteData.SetOnError(AValue: TExceptionEvent); begin if FOnError = AValue then Exit; @@ -148,8 +157,7 @@ function TSQliteData.CreateDB: Boolean; if not OpenDB then Exit; try FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); - FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + #13#10 + - '(' + FCreateParams + ')'); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + ' (' + FCreateParams + ')'); FTrans.Commit; Result := True; except @@ -173,12 +181,10 @@ procedure TSQliteData.DoConvertNewTable; with FConn do begin ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd('temp' + FTableName)); - ExecuteDirect('CREATE TABLE ' + QuotedStrd('temp' + FTableName) + #13#10 + FCreateParams); - ExecuteDirect('INSERT INTO ' + QuotedStrd('temp' + FTableName) + ' SELECT * FROM ' + - QuotedStrd(FTableName)); + ExecuteDirect('CREATE TABLE ' + QuotedStrd('temp' + FTableName) + ' (' + (FCreateParams) + ')'); + ExecuteDirect('INSERT INTO ' + QuotedStrd('temp' + FTableName) + ' (' + FieldsParams + ') SELECT ' + FieldsParams + ' FROM ' + QuotedStrd(FTableName)); ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE ' + QuotedStrd('temp' + FTableName) + ' RENAME TO ' + - QuotedStrd(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrd('temp' + FTableName) + ' RENAME TO ' + QuotedStrd(FTableName)); end; FTrans.Commit; if qactive <> FQuery.Active then From 8f2535ad8357f70f368f7aa6522d8725bf17fb6b Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Mon, 27 Feb 2017 16:51:29 +0530 Subject: [PATCH 1562/2794] Added HelveticaScans --- baseunits/modules/FoOlSlide.pas | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 771343dfb..f2508a5f8 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -21,6 +21,7 @@ implementation dirurlslide = '/slide/directory/'; dirurlslideU = '/Slide/directory/'; dirurlonline = '/online/directory/'; + dirurlhelvetica = '/r/directory/'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; @@ -59,6 +60,9 @@ function GetDirURL(const AWebsite: String): String; if (AWebsite = 'Pzykosis666HFansub') or (AWebsite = 'SeinagiFansub') then Result := dirurlonline + else + if(AWebsite = 'HelveticaScans') then + Result := dirurlhelvetica else Result := dirurl; end; @@ -265,6 +269,7 @@ procedure RegisterModule; AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com'); AddWebsiteModule('KireiCake', 'https://reader.kireicake.com'); + AddWebsiteModule('HelveticaScans', 'http://helveticascans.com'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); From b3bcc6c00bead9fecbe8d0a5bda4a2ae1b6fdb53 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 09:16:53 +0800 Subject: [PATCH 1563/2794] added helveticascans to sen-sc --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 30759e8c0..bd8486e6a 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics Italian=MangaEden_IT,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik From 7f2188a447f3779c8c9582259fb9a5171585b09a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 15:41:41 +0800 Subject: [PATCH 1564/2794] sqlitedata, cleanup --- baseunits/SQLiteData.pas | 43 ++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index b2ade98b4..9d02c353f 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -53,8 +53,8 @@ TSQliteData = class public constructor Create; destructor Destroy; override; - function Open(const AOpenTable: Boolean = True): Boolean; - function OpenTable: Boolean; virtual; + function Open(const AOpenTable: Boolean = True; const AGetRecordCount: Boolean = True): Boolean; + function OpenTable(const AGetRecordCount: Boolean = True): Boolean; virtual; procedure Close; procedure CloseTable; procedure Refresh(RecheckDataCount: Boolean = False); @@ -76,15 +76,8 @@ TSQliteData = class property OnError: TExceptionEvent read FOnError write SetOnError; end; - function QuotedStrd(const S: string): string; inline; - implementation -function QuotedStrd(const S: string): string; -begin - Result := AnsiQuotedStr(S, '"'); -end; - { TSQliteData } procedure TSQliteData.DoOnError(E: Exception); @@ -156,8 +149,8 @@ function TSQliteData.CreateDB: Boolean; if not FConn.Connected then if not OpenDB then Exit; try - FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd(FTableName)); - FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrd(FTableName) + ' (' + FCreateParams + ')'); + FConn.ExecuteDirect('DROP TABLE IF EXISTS "' + FTableName + '"'); + FConn.ExecuteDirect('CREATE TABLE "' + FTableName + '" (' + FCreateParams + ')'); FTrans.Commit; Result := True; except @@ -180,11 +173,11 @@ procedure TSQliteData.DoConvertNewTable; if FQuery.Active then FQuery.Close; with FConn do begin - ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrd('temp' + FTableName)); - ExecuteDirect('CREATE TABLE ' + QuotedStrd('temp' + FTableName) + ' (' + (FCreateParams) + ')'); - ExecuteDirect('INSERT INTO ' + QuotedStrd('temp' + FTableName) + ' (' + FieldsParams + ') SELECT ' + FieldsParams + ' FROM ' + QuotedStrd(FTableName)); - ExecuteDirect('DROP TABLE ' + QuotedStrd(FTableName)); - ExecuteDirect('ALTER TABLE ' + QuotedStrd('temp' + FTableName) + ' RENAME TO ' + QuotedStrd(FTableName)); + ExecuteDirect('DROP TABLE IF EXISTS "temp' + FTableName + '"'); + ExecuteDirect('CREATE TABLE "temp' + FTableName + '" (' + FCreateParams + ')'); + ExecuteDirect('INSERT INTO "temp' + FTableName + '" (' + FieldsParams + ') SELECT ' + FieldsParams + ' FROM "' + FTableName + '"'); + ExecuteDirect('DROP TABLE "' + FTableName + '"'); + ExecuteDirect('ALTER TABLE "temp' + FTableName + '" RENAME TO "' + FTableName + '"'); end; FTrans.Commit; if qactive <> FQuery.Active then @@ -264,7 +257,8 @@ destructor TSQliteData.Destroy; inherited Destroy; end; -function TSQliteData.Open(const AOpenTable: Boolean): Boolean; +function TSQliteData.Open(const AOpenTable: Boolean; + const AGetRecordCount: Boolean): Boolean; begin Result := False; if (FFilename = '') or (FCreateParams = '') then Exit; @@ -273,10 +267,10 @@ function TSQliteData.Open(const AOpenTable: Boolean): Boolean; else Result := CreateDB; if Result and AOpenTable then - Result := OpenTable; + Result := OpenTable(AGetRecordCount); end; -function TSQliteData.OpenTable: Boolean; +function TSQliteData.OpenTable(const AGetRecordCount: Boolean): Boolean; begin Result := False; if not FConn.Connected then Exit; @@ -285,9 +279,12 @@ function TSQliteData.OpenTable: Boolean; if FSelectParams <> '' then FQuery.SQL.Text := FSelectParams else - FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrd(FTableName); + FQuery.SQL.Text := 'SELECT * FROM "' + FTableName + '"'; FQuery.Open; - GetRecordCount; + if AGetRecordCount then + GetRecordCount + else + FRecordCount := FQuery.RecordCount; except on E: Exception do DoOnError(E); @@ -333,7 +330,9 @@ procedure TSQliteData.Refresh(RecheckDataCount: Boolean); else FQuery.Open; if RecheckDataCount then - GetRecordCount; + GetRecordCount + else + FRecordCount := FQuery.RecordCount; end; procedure TSQliteData.Commit; From d30e86cf107e7f6cd82a119cb43759fb63ae57dc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 15:42:59 +0800 Subject: [PATCH 1565/2794] favoritesdb, retrieve records one by one --- baseunits/FavoritesDB.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index f7759be4d..07e4eff42 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -42,6 +42,7 @@ constructor TFavoritesDB.Create(const AFilename: String); FAutoCommitCount := 500; Filename := AFilename; TableName := 'favorites'; + Table.PacketRecords := 1; CreateParams := '"websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY,' + '"order" INTEGER,' + From 5a9e1ef657e90517661d8394c8d18715609872d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 15:44:46 +0800 Subject: [PATCH 1566/2794] favoritesmanager, cleanup after sqlitedata --- baseunits/uFavoritesManager.pas | 39 +++++++++++++++------------------ 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 2374f043e..3eef75833 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -513,7 +513,7 @@ function TFavoriteManager.ConvertToDB: Boolean; Free; end; if Result then - DeleteFileUTF8(FAVORITES_FILE); + Result := DeleteFileUTF8(FAVORITES_FILE); end; constructor TFavoriteManager.Create; @@ -524,7 +524,7 @@ constructor TFavoriteManager.Create; isRunning := False; Items := TFavoriteContainers.Create;; FFavoritesDB := TFavoritesDB.Create(FAVORITESDB_FILE); - FFavoritesDB.Open(False); + FFavoritesDB.Open(False, False); ConvertToDB; Restore; end; @@ -959,27 +959,24 @@ procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); procedure TFavoriteManager.Restore; begin if not FFavoritesDB.Connection.Connected then Exit; - if FFavoritesDB.OpenTable then + if FFavoritesDB.OpenTable(False) then try - with FFavoritesDB.Table do + FFavoritesDB.Table.First; + while not FFavoritesDB.Table.EOF do begin - First; - while not EOF do - begin - Items.Add(TFavoriteContainer.Create); - with Items.Last, FavoriteInfo do - begin - Manager := Self; - Status := STATUS_IDLE; - Website := Fields[2].AsString; - Link := Fields[3].AsString; - Title := Fields[4].AsString; - CurrentChapter := Fields[5].AsString; - DownloadedChapterList := Fields[6].AsString; - SaveTo := Fields[7].AsString; - end; - Next; - end; + Items.Add(TFavoriteContainer.Create); + with Items.Last, FavoriteInfo, FFavoritesDB.Table do + begin + Manager := Self; + Status := STATUS_IDLE; + Website := Fields[2].AsString; + Link := Fields[3].AsString; + Title := Fields[4].AsString; + CurrentChapter := Fields[5].AsString; + DownloadedChapterList := Fields[6].AsString; + SaveTo := Fields[7].AsString; + end; + FFavoritesDB.Table.Next; end; finally FFavoritesDB.CloseTable; From d87714c58f41dbfa578e76ec1daa00c7c7732deb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 15:45:58 +0800 Subject: [PATCH 1567/2794] added downloadsdb to store downloads list --- baseunits/DownloadsDB.pas | 176 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 baseunits/DownloadsDB.pas diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas new file mode 100644 index 000000000..8d3c5ffbd --- /dev/null +++ b/baseunits/DownloadsDB.pas @@ -0,0 +1,176 @@ +unit DownloadsDB; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, SQLiteData, uBaseUnit; + +type + + { TDownloadsDB } + + TDownloadsDB = class(TSQliteData) + private + FCommitCount: Integer; + FAutoCommitCount: Integer; + procedure SetAutoCommitCount(AValue: Integer); + public + constructor Create(const AFilename: String); + function Add(var Adlid: Integer; + const Aenabled: Boolean; + const Aorder, Ataskstatus, Achapterptr, Anumberofpages, Acurrentpage: Integer; + const Awebsite, Alink, Atitle, Astatus, Aprogress, Asaveto: String; + const Adatetime: TDateTime; + const Achapterslinks, Achaptersnames, Apagelinks, Apagecontainerlinks, Afilenames, Acustomfilenames, + Afailedchapterslinks, Afailedchaptersnames: String): Boolean; + procedure Delete(const ADlId: Integer); + procedure Commit; override; + property AutoCommitCount: Integer read FAutoCommitCount write SetAutoCommitCount; + end; + +implementation + +{ TDownloadsDB } + +procedure TDownloadsDB.SetAutoCommitCount(AValue: Integer); +begin + if FAutoCommitCount = AValue then Exit; + FAutoCommitCount := AValue; +end; + +constructor TDownloadsDB.Create(const AFilename: String); +begin + inherited Create; + FCommitCount := 0; + FAutoCommitCount := 300; + Filename := AFilename; + TableName := 'downloads'; + Table.PacketRecords := 1; + CreateParams := + '"dlid" INTEGER PRIMARY KEY,' + + '"enabled" BOOLEAN,' + + '"order" INTEGER,' + + '"taskstatus" INTEGER,' + + '"chapterptr" INTEGER,' + + '"numberofpages" INTEGER,' + + '"currentpage" INTEGER,' + + '"website" TEXT,' + + '"link" TEXT,' + + '"title" TEXT,' + + '"status" TEXT,' + + '"progress" TEXT,' + + '"saveto" TEXT,' + + '"datetime" DATETIME,' + + '"chapterslinks" TEXT,' + + '"chaptersnames" TEXT,' + + '"pagelinks" TEXT,' + + '"pagecontainerlinks" TEXT,' + + '"filenames" TEXT,' + + '"customfilenames" TEXT,' + + '"failedchapterlinks" TEXT,' + + '"failedchapternames" TEXT'; + FieldsParams := '"dlid","enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","failedchapterlinks","failedchapternames"'; + SelectParams := 'SELECT ' + FieldsParams + ' FROM "'+TableName+'" ORDER BY "order"'; +end; + +function TDownloadsDB.Add(var Adlid: Integer; + const Aenabled: Boolean; + const Aorder, Ataskstatus, Achapterptr, Anumberofpages, Acurrentpage: Integer; + const Awebsite, Alink, Atitle, Astatus, Aprogress, Asaveto: String; + const Adatetime: TDateTime; + const Achapterslinks, Achaptersnames, Apagelinks, Apagecontainerlinks, Afilenames, Acustomfilenames, + Afailedchapterslinks, Afailedchaptersnames: String): Boolean; +begin + Result := False; + if (AWebsite = '') or (ALink = '') then Exit; + if not Connection.Connected then Exit; + try + if Adlid <> -1 then + Connection.ExecuteDirect('UPDATE "downloads" SET ' + + '"enabled"="' + BoolToStr(Aenabled, '1', '0') + '",' + + '"order"="' + IntToStr(Aorder) + '",' + + '"taskstatus"="' + IntToStr(Ataskstatus) + '",' + + '"chapterptr"="' + IntToStr(Achapterptr) + '",' + + '"numberofpages"="' + IntToStr(Anumberofpages) + '",' + + '"currentpage"="' + IntToStr(Acurrentpage) + '",' + + '"website"="' + Awebsite + '",' + + '"link"="' + Alink + '",' + + '"title"="' + Atitle + '",' + + '"status"="' + Astatus + '",' + + '"progress"="' + Aprogress + '",' + + '"saveto"="' + Asaveto + '",' + + '"datetime"="' + FormatDateTime('yyyy-mm-dd hh:mm:ss', Adatetime) + '",' + + '"chapterslinks"="' + Achapterslinks + '",' + + '"chaptersnames"="' + Achaptersnames + '",' + + '"pagelinks"="' + Apagelinks + '",' + + '"pagecontainerlinks"="' + Apagecontainerlinks + '",' + + '"filenames"="' + Afilenames + '",' + + '"customfilenames"="' + Acustomfilenames + '",' + + '"failedchapterlinks"="' + Afailedchapterslinks + '",' + + '"failedchapternames"="' + Afailedchaptersnames + '"' + + ' WHERE "dlid"="' + IntToStr(Adlid) + '"') + else + with Table do + begin + Append; + Fields[1].AsBoolean := Aenabled; + Fields[2].AsInteger := Aorder; + Fields[3].AsInteger := Ataskstatus; + Fields[4].AsInteger := Achapterptr; + Fields[5].AsInteger := Anumberofpages; + Fields[6].AsInteger := Acurrentpage; + Fields[7].AsString := Awebsite; + Fields[8].AsString := Alink; + Fields[9].AsString := Atitle; + Fields[10].AsString := Astatus; + Fields[11].AsString := Aprogress; + Fields[12].AsString := Asaveto; + Fields[13].AsDateTime := Adatetime; + Fields[14].AsString := Achapterslinks; + Fields[15].AsString := Achaptersnames; + Fields[16].AsString := Apagelinks; + Fields[17].AsString := Apagecontainerlinks; + Fields[18].AsString := Afilenames; + Fields[19].AsString := Acustomfilenames; + Fields[20].AsString := Afailedchapterslinks; + Fields[21].AsString := Afailedchaptersnames; + Post; + Adlid := Fields[0].AsInteger; + end; + Result := True; + Inc(FCommitCount); + if FCommitCount >= FAutoCommitCount then + Commit; + except + end; +end; + +procedure TDownloadsDB.Delete(const ADlId: Integer); +begin + if ADlId = -1 then Exit; + if not Connection.Connected then Exit; + try + Connection.ExecuteDirect( + 'DELETE FROM "downloads" WHERE "dlid"="' + IntToStr(ADlId) + '"'); + Inc(FCommitCount); + if FCommitCount >= FAutoCommitCount then + Commit; + except + end; +end; + +procedure TDownloadsDB.Commit; +begin + if not Connection.Connected then Exit; + try + Transaction.Commit; + FCommitCount := 0; + except + Transaction.Rollback; + end; +end; + +end. + From 741592e2a1659b6b7b82eff7d56d8303d7cfc6a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 15:46:27 +0800 Subject: [PATCH 1568/2794] added downloadsdb file location --- baseunits/FMDOptions.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 6d5390be5..af30afa9d 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -54,6 +54,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) DEFAULT_PATH, WORK_FOLDER, WORK_FILE, + WORK_FILEDB, DOWNLOADEDCHAPTERS_FILE, DOWNLOADEDCHAPTERSDB_FILE, FAVORITES_FILE, @@ -283,6 +284,7 @@ procedure SetAppDataDirectory(const ADir: String); WORK_FOLDER := APPDATA_DIRECTORY + 'works' + PathDelim; WORK_FILE := WORK_FOLDER + 'works.ini'; + WORK_FILEDB := WORK_FOLDER + 'downloads.db'; DOWNLOADEDCHAPTERS_FILE := WORK_FOLDER + 'downloadedchapters.ini'; DOWNLOADEDCHAPTERSDB_FILE := WORK_FOLDER + 'downloadedchapters.db'; FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; From 39730de361d3ea68cb65d116a7958995de1ab403 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 15:47:12 +0800 Subject: [PATCH 1569/2794] downloadsmanager, used downloadsdb, convert works.ini to downloads.db --- baseunits/uDownloadsManager.pas | 242 +++++++++++++++----------------- 1 file changed, 116 insertions(+), 126 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index bbd4f9357..3bec02201 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -15,9 +15,10 @@ interface uses - LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, Classes, SysUtils, - ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, uMisc, - DownloadedChaptersDB, FMDOptions, httpsendthread, dateutils, strutils; + LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, IniFiles, Classes, + SysUtils, ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, + uMisc, DownloadedChaptersDB, FMDOptions, httpsendthread, DownloadsDB, + dateutils, strutils; type TDownloadStatusType = ( @@ -124,6 +125,7 @@ TTaskContainer = class procedure SetStatus(AValue: TDownloadStatusType); procedure SetWebsite(AValue: String); public + DlId: Integer; // critical section CS_Container: TRTLCriticalSection; // read count for transfer rate @@ -171,10 +173,11 @@ TDownloadManager = class private FSortDirection: Boolean; FSortColumn: Integer; - DownloadManagerFile: TIniFileRun; + FDownloadsDB: TDownloadsDB; procedure AddItemsActiveTask(const Item: TTaskContainer); procedure RemoveItemsActiveTask(const Item: TTaskContainer); function GetTask(const TaskId: Integer): TTaskContainer; + function ConvertToDB: Boolean; protected function GetTaskCount: Integer; inline; function GetTransferRate: Integer; @@ -1446,6 +1449,7 @@ procedure TTaskContainer.SetEnabled(AValue: Boolean); constructor TTaskContainer.Create; begin inherited Create; + DlId := -1; InitCriticalSection(CS_Container); ThreadState := False; ChapterLinks := TStringList.Create; @@ -1593,7 +1597,6 @@ constructor TDownloadManager.Create; InitCriticalSection(CS_Task); InitCriticalSection(CS_ItemsActiveTask); ForceDirectoriesUTF8(WORK_FOLDER); - DownloadManagerFile := TIniFileRun.Create(WORK_FILE); DownloadedChapters := TDownloadedChaptersDB.Create; DownloadedChapters.Filename := DOWNLOADEDCHAPTERSDB_FILE; DownloadedChapters.OnError := MainForm.ExceptionHandler; @@ -1613,6 +1616,8 @@ constructor TDownloadManager.Create; for ds := Low(StatusCount) to High(StatusCount) do StatusCount[ds] := 0; DisabledCount := 0; + FDownloadsDB := TDownloadsDB.Create(WORK_FILEDB); + FDownloadsDB.Open(True, False); end; destructor TDownloadManager.Destroy; @@ -1623,160 +1628,145 @@ destructor TDownloadManager.Destroy; Items.Remove(Items.Last); end; Items.Free; - DownloadManagerFile.Free; ItemsActiveTask.Free; DownloadedChapters.Free; + FDownloadsDB.Free; DoneCriticalsection(CS_ItemsActiveTask); DoneCriticalsection(CS_Task); DoneCriticalsection(CS_StatusCount); inherited Destroy; end; -procedure TDownloadManager.Restore; +function TDownloadManager.ConvertToDB: Boolean; var - tid, s: String; - tmp, i, j: Integer; + i, d: Integer; + s: String; begin - EnterCriticalSection(CS_Task); + Result := False; + if not FileExistsUTF8(WORK_FILE) then Exit; + with TIniFile.Create(WORK_FILE) do try - while Items.Count > 0 do + i := ReadInteger('general', 'NumberOfTasks', 0); + if i = 0 then Exit; + for i := 0 to i - 1 do begin - Items.Last.Free; - Items.Remove(Items.Last); + d := -1; + s := 'task' + IntToStr(i); + FDownloadsDB.Add(d, + ReadBool(s, 'Enabled', True), + i, + ReadInteger(s, 'TaskStatus', 0), + ReadInteger(s, 'ChapterPtr', 0), + ReadInteger(s, 'NumberOfPages', 0), + ReadInteger(s, 'CurrentPage', 0), + ReadString(s, 'Website', ''), + ReadString(s, 'Link', ''), + ReadString(s, 'Title', ''), + ReadString(s, 'Status', ''), + ReadString(s, 'Progress', ''), + ReadString(s, 'SaveTo', ''), + StrToFloatDef(ReadString(s, 'DateTime', ''), Now, FMDFormatSettings), + ReadString(s, 'ChapterLinks', ''), + ReadString(s, 'ChapterName', ''), + ReadString(s, 'PageLinks', ''), + ReadString(s, 'PageContainerLinks', ''), + ReadString(s, 'Filenames', ''), + ReadString(s, 'CustomFileName', DEFAULT_FILENAME_CUSTOMRENAME), + ReadString(s, 'FailedChapterLinks', ''), + ReadString(s, 'FailedChapterName', '')); end; + FDownloadsDB.Commit; + FDownloadsDB.Refresh(False); + Result := True; + finally + Free; + end; + if Result then + Result := DeleteFileUTF8(WORK_FILE); +end; - tmp := DownloadManagerFile.ReadInteger('general', 'NumberOfTasks', 0); - if tmp = 0 then - Exit; - for i := 0 to tmp - 1 do +procedure TDownloadManager.Restore; +begin + if not FDownloadsDB.Connected then Exit; + if not FDownloadsDB.Table.Active then Exit; + ConvertToDB; + if FDownloadsDB.RecordCount = 0 then Exit; + try + EnterCriticalsection(CS_Task); + FDownloadsDB.Table.First; + while not FDownloadsDB.Table.EOF do begin - // restore download task from file Items.Add(TTaskContainer.Create); - with DownloadManagerFile, Items.Last do + with Items.Last, FDownloadsDB.Table do begin - tid := 'task' + IntToStr(i); Manager := Self; - DownloadInfo.Website := ReadString(tid, 'Website', 'NULL'); - DownloadInfo.Link := ReadString(tid, 'Link', ''); - DownloadInfo.Title := ReadString(tid, 'Title', 'NULL'); - DownloadInfo.SaveTo := ReadString(tid, 'SaveTo', 'NULL'); - DownloadInfo.Status := ReadString(tid, 'Status', 'NULL'); - DownloadInfo.Progress := ReadString(tid, 'Progress', 'NULL'); - Enabled := ReadBool(tid, 'Enabled', True); - if Pos('/', DownloadInfo.Progress) > 0 then - begin - DownCounter := StrToIntDef(ExtractWord(1, DownloadInfo.Progress, ['/']), 0); - PageNumber := StrToIntDef(ExtractWord(2, DownloadInfo.Progress, ['/']), 0); - end; - CustomFileName := ReadString(tid, 'CustomFileName', DEFAULT_FILENAME_CUSTOMRENAME); - s := ReadString(tid, 'ChapterLinks', ''); - if s <> '' then GetParams(ChapterLinks, s); - s := ReadString(tid, 'ChapterName', ''); - if s <> '' then GetParams(ChapterName, s); - s := ReadString(tid, 'FailedChapterLinks', ''); - if s <> '' then GetParams(FailedChapterLinks, s); - s := ReadString(tid, 'FailedChapterName', ''); - if s <> '' then GetParams(FailedChapterName, s); - s := ReadString(tid, 'PageLinks', ''); - if s <> '' then GetParams(PageLinks, s); - s := ReadString(tid, 'PageContainerLinks', ''); - if s <> '' then GetParams(PageContainerLinks, s); - s := ReadString(tid, 'Filenames', ''); - if s <> '' then GetParams(FileNames, s); - j := ReadInteger(tid, 'TaskStatus', -1); - if j >= 0 then - Status := TDownloadStatusType(j) - else - begin - s := ReadString(tid, 'TaskStatus', 'STATUS_STOP'); - Status := TDownloadStatusType(GetEnumValue(TypeInfo(TDownloadStatusType), s)); - if Status = STATUS_COMPRESS then - Status := STATUS_WAIT; - end; - CurrentDownloadChapterPtr := ReadInteger(tid, 'ChapterPtr', 0); - PageNumber := ReadInteger(tid, 'NumberOfPages', 0); - CurrentPageNumber := ReadInteger(tid, 'CurrentPage', 0); - if Status = STATUS_COMPRESS then - DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Waiting]); - s := ReadString(tid, 'DateTime', ''); - //for old config - if (Pos('/', s) > 0) or (Pos('\', s) > 0) then - DownloadInfo.dateTime := StrToDateDef(s, Now) - else - begin - s := StringReplace(s, ',', FMDFormatSettings.DecimalSeparator, [rfReplaceAll]); - s := StringReplace(s, '.', FMDFormatSettings.DecimalSeparator, [rfReplaceAll]); - DownloadInfo.dateTime := StrToFloatDef(s, Now, FMDFormatSettings); - end; - if DownloadInfo.dateTime > Now then DownloadInfo.dateTime := Now; - - Website := DownloadInfo.Website; - ThreadState := False; - - //validating - if (CurrentDownloadChapterPtr > 0) and (CurrentDownloadChapterPtr >= ChapterLinks.Count) then - CurrentDownloadChapterPtr := ChapterLinks.Count - 1; + DlId := Fields[0].AsInteger; + Enabled := Fields[1].AsBoolean; + Status := TDownloadStatusType(Fields[3].AsInteger); + CurrentDownloadChapterPtr := Fields[4].AsInteger; + PageNumber := Fields[5].AsInteger; + CurrentPageNumber := Fields[6].AsInteger; + Website := Fields[7].AsString; + DownloadInfo.Website := Fields[7].AsString; + DownloadInfo.Link := Fields[8].AsString; + DownloadInfo.Title := Fields[9].AsString; + DownloadInfo.Status := Fields[10].AsString; + DownloadInfo.Progress := Fields[11].AsString; + DownloadInfo.SaveTo := Fields[12].AsString; + DownloadInfo.DateTime := Fields[13].AsDateTime; + ChapterLinks.Text := Fields[14].AsString; + ChapterName.Text := Fields[15].AsString; + PageLinks.Text := Fields[16].AsString; + PageContainerLinks.Text := Fields[17].AsString; + FileNames.Text := Fields[18].AsString; + CustomFileName := Fields[19].AsString; + FailedChapterLinks.Text := Fields[20].AsString; + FailedChapterName.Text := Fields[21].AsString; end; + FDownloadsDB.Table.Next; end; finally - LeaveCriticalSection(CS_Task); + LeaveCriticalsection(CS_Task); end; end; procedure TDownloadManager.Backup; var i: Integer; - tid: String; begin - if isRunningBackup then - Exit; - + if isRunningBackup then Exit; + if Items.Count = 0 then Exit; + if not FDownloadsDB.Connected then Exit; isRunningBackup := True; EnterCriticalSection(CS_Task); - with DownloadManagerFile do try - // Erase all sections - for i := 0 to ReadInteger('general', 'NumberOfTasks', 0) do - EraseSection('task' + IntToStr(i)); - EraseSection('general'); - - // backup - if Items.Count > 0 then - begin - WriteInteger('general', 'NumberOfTasks', Items.Count); - for i := 0 to Items.Count - 1 do + for i := 0 to Items.Count - 1 do + with Items[i] do begin - tid := 'task' + IntToStr(i); - with Items[i] do begin - WriteString(tid, 'Website', DownloadInfo.Website); - WriteString(tid, 'Link', DownloadInfo.Link); - WriteString(tid, 'Title', DownloadInfo.Title); - WriteString(tid, 'SaveTo', DownloadInfo.SaveTo); - WriteString(tid, 'Status', DownloadInfo.Status); - WriteString(tid, 'Progress', DownloadInfo.Progress); - WriteBool(tid, 'Enabled', Enabled); - WriteString(tid, 'DateTime', FloatToStr(DownloadInfo.dateTime, FMDFormatSettings)); - WriteString(tid, 'CustomFileName', CustomFileName); - WriteString(tid, 'ChapterLinks', SetParams(ChapterLinks)); - WriteString(tid, 'ChapterName', SetParams(ChapterName)); - if FailedChapterLinks.Count > 0 then - WriteString(tid, 'FailedChapterLinks', SetParams(FailedChapterLinks)); - if FailedChapterName.Count > 0 then - WriteString(tid, 'FailedChapterName', SetParams(FailedChapterName)); - if PageLinks.Count > 0 then - WriteString(tid, 'PageLinks', SetParams(PageLinks)); - if PageContainerLinks.Count > 0 then - WriteString(tid, 'PageContainerLinks', SetParams(PageContainerLinks)); - if FileNames.Count > 0 then - WriteString(tid, 'Filenames', SetParams(FileNames)); - WriteString(tid, 'TaskStatus', GetEnumName(TypeInfo(TDownloadStatusType), Integer(Status))); - WriteInteger(tid, 'ChapterPtr', CurrentDownloadChapterPtr); - WriteInteger(tid, 'NumberOfPages', PageNumber); - WriteInteger(tid, 'CurrentPage', CurrentPageNumber); - end; + FDownloadsDB.Add(DlId, + Enabled, + i, + Integer(Status), + CurrentDownloadChapterPtr, + PageNumber, + CurrentPageNumber, + Website, + DownloadInfo.Link, + DownloadInfo.Title, + DownloadInfo.Status, + DownloadInfo.Progress, + DownloadInfo.SaveTo, + DownloadInfo.DateTime, + ChapterLinks.Text, + ChapterName.Text, + PageLinks.Text, + PageContainerLinks.Text, + FileNames.Text, + CustomFileName, + FailedChapterLinks.Text, + FailedChapterName.Text); end; - end; - UpdateFile; + FDownloadsDB.Commit; finally LeaveCriticalSection(CS_Task); end; From 7ced290e4a6988b7a91ba5ac79aa336543ca9726 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 16:45:08 +0800 Subject: [PATCH 1570/2794] fixed delete favorite from db --- baseunits/uFavoritesManager.pas | 20 ++++++++++++-------- mangadownloader/forms/frmMain.pas | 5 ++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 3eef75833..d20d38270 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -117,6 +117,8 @@ TFavoriteManager = class ASaveTo, ALink: String); // Merge a favorites.ini with another favorites.ini procedure MergeWith(const APath: String); + // Free then delete favorite without any check, use with caution + procedure FreeAndDelete(const Pos: Integer); // Remove a manga from FFavorites procedure Remove(const Pos: Integer; const isBackup: Boolean = True); // Restore information from favorites.db @@ -691,10 +693,7 @@ procedure TFavoriteManager.ShowResult; if Assigned(NewMangaInfo) and (NewMangaInfoChaptersPos.Count = 0) and (NewMangaInfo.status = MangaInfo_StatusCompleted) then - begin - Items[i].Free; - Items.Delete(i); - end + FreeAndDelete(i) else Inc(i); end; @@ -938,16 +937,21 @@ procedure TFavoriteManager.MergeWith(const APath: String); isRunning := False; end; +procedure TFavoriteManager.FreeAndDelete(const Pos: Integer); +begin + with Items[Pos].FavoriteInfo do + FFavoritesDB.Delete(Website, Link); + Items[Pos].Free; + Items.Delete(Pos); +end; + procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); begin if (not isRunning) and (Pos < Items.Count) then begin EnterCriticalsection(CS_Favorites); try - with Items[Pos].FavoriteInfo do - FFavoritesDB.Delete(Website, Link); - Items[Pos].Free; - Items.Delete(Pos); + FreeAndDelete(Pos); if isBackup then Backup; finally diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bb99dd898..a68cb6b43 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1764,9 +1764,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if SameText(DLManager[xNode^.Index].DownloadInfo.Link, FavoriteManager[i].FavoriteInfo.Link) and SameText(DLManager[xNode^.Index].DownloadInfo.Website, FavoriteManager[i].FavoriteInfo.Website) then begin - FavoriteManager.Items[i].Free; - FavoriteManager.Items.Delete(i); - UpdateVtFavorites; + FavoriteManager.FreeAndDelete(i); Break; end; end; @@ -1783,6 +1781,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); end; vtDownload.RootNodeCount := DLManager.Items.Count; vtDownload.EndUpdate; + UpdateVtFavorites; UpdateVtDownload; DLManager.CheckAndActiveTask(); Exit; From 27924aed1dc9ec70c68674d9a3021797fe4d4857 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 16:49:55 +0800 Subject: [PATCH 1571/2794] fixed remove download from db --- baseunits/uDownloadsManager.pas | 23 ++++++++++++++--------- mangadownloader/forms/frmMain.pas | 3 +-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 3bec02201..8d1ab83ea 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -240,8 +240,10 @@ TDownloadManager = class procedure StopAllTasks; // Stop all download task inside a task before terminate the program. procedure StopAllDownloadTasksForExit; + // Free then delete task without any check, use with caution + procedure FreeAndDelete(const TaskId: Integer); // Remove a task from list. - procedure RemoveTask(const taskID: Integer); + procedure RemoveTask(const TaskID: Integer); // Remove all finished tasks. procedure RemoveAllFinishedTasks; // check status of task @@ -1986,17 +1988,23 @@ procedure TDownloadManager.StopAllDownloadTasksForExit; end; end; -procedure TDownloadManager.RemoveTask(const taskID: Integer); +procedure TDownloadManager.FreeAndDelete(const TaskId: Integer); +begin + FDownloadsDB.Delete(Items[TaskID].DlId); + Items[TaskID].Free; + Items.Delete(taskID); +end; + +procedure TDownloadManager.RemoveTask(const TaskID: Integer); begin EnterCriticalSection(CS_Task); try - with Items[taskID] do + with Items[TaskID] do if ThreadState then begin Task.Terminate; Task.WaitFor; end; - Items[taskID].Free; - Items.Delete(taskID); + FreeAndDelete(TaskID); finally LeaveCriticalSection(CS_Task); end; @@ -2012,10 +2020,7 @@ procedure TDownloadManager.RemoveAllFinishedTasks; try for i := Items.Count - 1 downto 0 do if Items[i].Status = STATUS_FINISH then - begin - Items[i].Free; - Items.Delete(i) - end; + FreeAndDelete(i); finally LeaveCriticalsection(CS_Task); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a68cb6b43..43c04d332 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1771,8 +1771,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); finally FavoriteManager.LockRelease; end; - Free; - DLManager.Items.Delete(xNode^.Index); + DLManager.FreeAndDelete(xNode^.Index); end; xNode := vtDownload.GetPreviousSelected(xNode); end; From 1d00a43e57b2a4e9b906dcce7c1b98c39e79f490 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 16:57:29 +0800 Subject: [PATCH 1572/2794] Bump version 0.9.94.0 --- changelog.txt | 10 ++++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index cd0c0c9ae..c1cd92ea8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,16 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.94.0 (28-02-2017) +[!+] Favorites and Downloads now saved in SQLite database file + WARNING: Please backup your favorites.ini and works.ini before update +[*] Sorted downloads and favorites only allowed with left click +[*] Fixed various issue with downloaded chapter list +[*] Hentai2Read: fixed download +[+] Added HelveticaScans[EN-SC] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.93.0...0.9.94.0 + 0.9.93.0 (22-02-2017) [*] WPManga: Fixed memory leak Full changes: https://github.com/riderkick/FMD/compare/0.9.92.0...0.9.93.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 701ba6c1b..88108c5c4 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="93"/> + <RevisionNr Value="94"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 914b3206d..8539ac0d9 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.93.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.93.0/fmd_0.9.93.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.93.0/fmd_0.9.93.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.93.0/fmd_0.9.93.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.93.0/fmd_0.9.93.0_Win64.7z +VERSION=0.9.94.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.94.0/fmd_0.9.94.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.94.0/fmd_0.9.94.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.94.0/fmd_0.9.94.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.94.0/fmd_0.9.94.0_Win64.7z From 4fe218b3c107ec0fa0eb26fe7f755df98e4fed45 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 22:27:59 +0800 Subject: [PATCH 1573/2794] httpsendthread, don't need to synchronize on terminate --- baseunits/httpsendthread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 5473f5186..bef0b9116 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -16,7 +16,7 @@ THTTPThread = class(TThread) private FOnCustomTerminate: TNotifyEvent; function GetTerminated: Boolean; - procedure CallOnCustomTerminate; + procedure CallOnCustomTerminate; inline; public constructor Create(CreateSuspended: Boolean = True); procedure Terminate; @@ -276,7 +276,7 @@ procedure THTTPThread.Terminate; begin inherited Terminate; if Assigned(FOnCustomTerminate) then - Synchronize(@CallOnCustomTerminate); + FOnCustomTerminate(Self); end; { THTTPSendThread } From 8f672a55a8e8483306683e4fc7c08c0d114d501e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 22:29:05 +0800 Subject: [PATCH 1574/2794] move isexiting to baseunit. it is a global flag that can be read from all --- baseunits/uBaseUnit.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f95c560f5..d616814d5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -482,6 +482,7 @@ interface Revision: Cardinal; currentJDN: Integer; + isExiting: Boolean = False; type TArrayOfString = array of String; From a8890ae15600b759a05e6dd5fa75d218f49add75 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 22:29:47 +0800 Subject: [PATCH 1575/2794] fixed closenow, write more log --- mangadownloader/forms/frmMain.pas | 33 ++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 43c04d332..0416269a0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -618,7 +618,7 @@ TMainForm = class(TForm) ulTotalPtr, ulWorkPtr: Integer; optionMangaSiteSelectionNodes: array of PVirtualNode; LastSearchStr, LastSearchWeb: String; - isStartup, isExiting, isRunDownloadFilter, isUpdating, isPendingExitCounter, + isStartup, isRunDownloadFilter, isUpdating, isPendingExitCounter, isNormalExit: Boolean; FavoriteManager: TFavoriteManager; dataProcess: TDBDataProcess; @@ -1078,7 +1078,6 @@ procedure TMainForm.FormCreate(Sender: TObject); btAbortUpdateList.Parent := sbUpdateList; isRunDownloadFilter := False; isUpdating := False; - isExiting := False; isGetMangaInfos := False; isPendingExitCounter:=False; isNormalExit:=False; @@ -1271,14 +1270,29 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin + isExiting := True; {$ifdef windows} if Assigned(PrevWndProc) then windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(PrevWndProc)); {$endif} - Logger.Send(Self.ClassName+'.CloseNow, terminating all threads and waitfor'); - FavoriteManager.StopChekForNewChapter(True); - SilentThreadManager.StopAll(True); - DLManager.StopAllDownloadTasksForExit; + if FavoriteManager.isRunning then + begin + Logger.Send(Self.ClassName+'.CloseNow, terminating check favorites threads'); + FavoriteManager.StopChekForNewChapter(True); + Logger.Send(Self.ClassName+'.CloseNow, check favorites threads terminated'); + end; + if SilentThreadManager.Count > 0 then + begin + Logger.Send(Self.ClassName+'.CloseNow, terminating silentthreads'); + SilentThreadManager.StopAll(True); + Logger.Send(Self.ClassName+'.CloseNow, silentthreads terminated'); + end; + if DLManager.ItemsActiveTask.Count > 0 then + begin + Logger.Send(Self.ClassName+'.CloseNow, terminating downloads threads'); + DLManager.StopAllDownloadTasksForExit; + Logger.Send(Self.ClassName+'.CloseNow, downlads threads terminated'); + end; //Terminating all threads and wait for it if Assigned(CheckUpdateThread) then begin @@ -1324,11 +1338,12 @@ procedure TMainForm.CloseNow; tmAnimateMangaInfo.Enabled := False; tmExitCommand.Enabled := False; - Logger.Send(Self.ClassName+'.CloseNow, backup all data to file'); //Backup data + Logger.Send(Self.ClassName+'.CloseNow, backup downloads'); DLManager.Backup; - isExiting := True; + Logger.Send(Self.ClassName+'.CloseNow, backup favorites'); FavoriteManager.Backup; + Logger.Send(Self.ClassName+'.CloseNow, backup all data to file'); SaveOptions; SaveFormInformation; @@ -3432,7 +3447,7 @@ procedure TMainForm.pmSbMainPopup(Sender: TObject); begin if Assigned(SilentThreadManager) then begin - if SilentThreadManager.ItemCount = 0 then + if SilentThreadManager.Count = 0 then Abort; end else From d7a77224afa751d7f4380f9dd5937325688111e7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 22:30:38 +0800 Subject: [PATCH 1576/2794] fixed terminating silentthreads --- baseunits/uSilentThread.pas | 159 ++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 81 deletions(-) diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 7600128bb..e0d6dc8ac 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -45,7 +45,6 @@ TSilentThread = class(THTTPThread) title, website, URL: String; ModuleId: Integer; procedure MainThreadAfterChecking; virtual; - procedure DoTerminate; override; procedure Execute; override; public Manager: TSilentThreadManager; @@ -79,9 +78,11 @@ TSilentThreadManagerThread = class(THTTPThread) TSilentThreadManager = class private + FCS_META: TRTLCriticalSection; + FCS_THREADS: TRTLCriticalSection; FLockAdd: Boolean; FManagerThread: TSilentThreadManagerThread; - function GetItemCount: Integer; + function GetCount: Integer; procedure StartManagerThread; procedure Checkout(Index: Integer); public @@ -93,7 +94,7 @@ TSilentThreadManager = class procedure UpdateLoadStatus; procedure BeginAdd; procedure EndAdd; - property ItemCount: Integer read GetItemCount; + property Count: Integer read GetCount; constructor Create; destructor Destroy; override; end; @@ -121,17 +122,8 @@ procedure TSilentThreadManagerThread.Checkout; begin if Terminated then Break; with MetaDatas[i] do - if (Threads.Count < OptionMaxThreads) and - Modules.CanCreateConnection(ModuleId) then - begin - LockCreateConnection; - try - if Modules.CanCreateConnection(ModuleId) then - Manager.Checkout(i); - finally - UnlockCreateConnection; - end; - end + if (Threads.Count < OptionMaxThreads) and Modules.CanCreateConnection(ModuleId) then + Manager.Checkout(i) else Inc(i); end; @@ -160,7 +152,7 @@ destructor TSilentThreadManagerThread.Destroy; { TSilentThreadManager } -function TSilentThreadManager.GetItemCount: Integer; +function TSilentThreadManager.GetCount: Integer; begin Result := MetaDatas.Count + Threads.Count; end; @@ -181,12 +173,17 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; if not ((AType = MD_AddToFavorites) and (MainForm.FavoriteManager.IsMangaExist(AManga, AWebsite))) then begin - MetaDatas.Add(TSilentThreadMetaData.Create( - AType, AWebsite, AManga, AURL, ASavePath)); - if not FLockAdd then - begin - StartManagerThread; - UpdateLoadStatus; + EnterCriticalsection(FCS_META); + try + MetaDatas.Add(TSilentThreadMetaData.Create( + AType, AWebsite, AManga, AURL, ASavePath)); + if not FLockAdd then + begin + StartManagerThread; + UpdateLoadStatus; + end; + finally + LeaveCriticalsection(FCS_META); end; end; end; @@ -195,21 +192,26 @@ procedure TSilentThreadManager.Checkout(Index: Integer); begin if (Index < 0) or (Index >= MetaDatas.Count) then Exit; Modules.IncActiveConnectionCount(MetaDatas[Index].ModuleId); - case MetaDatas[Index].MetaDataType of - MD_DownloadAll: Threads.Add(TSilentThread.Create); - MD_AddToFavorites: Threads.Add(TSilentAddToFavThread.Create); - end; - with Threads.Last do - begin - Manager := Self; - website := MetaDatas[Index].Website; - title := MetaDatas[Index].Title; - URL := MetaDatas[Index].URL; - SavePath := MetaDatas[Index].SaveTo; - ModuleId := MetaDatas[Index].ModuleId; - Start; - MetaDatas[Index].Free; - MetaDatas.Delete(Index); + EnterCriticalsection(FCS_THREADS); + try + case MetaDatas[Index].MetaDataType of + MD_DownloadAll: Threads.Add(TSilentThread.Create); + MD_AddToFavorites: Threads.Add(TSilentAddToFavThread.Create); + end; + with Threads.Last do + begin + Manager := Self; + website := MetaDatas[Index].Website; + title := MetaDatas[Index].Title; + URL := MetaDatas[Index].URL; + SavePath := MetaDatas[Index].SaveTo; + ModuleId := MetaDatas[Index].ModuleId; + Start; + MetaDatas[Index].Free; + MetaDatas.Delete(Index); + end; + finally + LeaveCriticalsection(FCS_THREADS); end; end; @@ -217,33 +219,42 @@ procedure TSilentThreadManager.StopAll(WaitFor: Boolean); var i: Integer; begin - if MetaDatas.Count or Threads.Count > 0 then - begin - while MetaDatas.Count > 0 do - begin - MetaDatas.Last.Free; - MetaDatas.Remove(MetaDatas.Last); - end; - if Assigned(FManagerThread) then + if Count = 0 then Exit; + EnterCriticalsection(FCS_META); + try + if MetaDatas.Count > 0 then begin - FManagerThread.Terminate; - if WaitFor then - FManagerThread.WaitFor; + for i := 0 to MetaDatas.Count - 1 do + MetaDatas[i].Free; + MetaDatas.Clear; end; + finally + LeaveCriticalsection(FCS_META); + end; + if Assigned(FManagerThread) then + begin + FManagerThread.Terminate; + if WaitFor then + FManagerThread.WaitFor; + end; + EnterCriticalsection(FCS_THREADS); + try if Threads.Count > 0 then for i := 0 to Threads.Count - 1 do Threads[i].Terminate; - if WaitFor then - while ItemCount > 0 do - Sleep(100); + finally + LeaveCriticalsection(FCS_THREADS); end; + if WaitFor then + while Threads.Count < 0 do + sleep(32); end; procedure TSilentThreadManager.UpdateLoadStatus; begin - if ItemCount > 0 then + if Count > 0 then MainForm.sbMain.Panels[1].Text := - Format(RS_SilentThreadLoadStatus, [Threads.Count, ItemCount]) + Format(RS_SilentThreadLoadStatus, [Threads.Count, Count]) else MainForm.sbMain.Panels[1].Text := ''; end; @@ -266,30 +277,20 @@ procedure TSilentThreadManager.EndAdd; constructor TSilentThreadManager.Create; begin inherited Create; + InitCriticalSection(FCS_META); + InitCriticalSection(FCS_THREADS); + FLockAdd := False; MetaDatas := TSilentThreadMetaDatas.Create; Threads := TSilentThreads.Create; - FLockAdd := False; end; destructor TSilentThreadManager.Destroy; -var - i: Integer; begin - if ItemCount > 0 then - begin - while MetaDatas.Count > 0 do - begin - MetaDatas.Last.Free; - MetaDatas.Remove(MetaDatas.Last); - end; - if Threads.Count > 0 then - for i := 0 to Threads.Count - 1 do - Threads[i].Terminate; - while ItemCount > 0 do - Sleep(100); - end; + StopAll(True); MetaDatas.Free; Threads.Free; + DoneCriticalsection(FCS_THREADS); + DoneCriticalsection(FCS_META); inherited Destroy; end; @@ -396,19 +397,6 @@ procedure TSilentThread.MainThreadAfterChecking; end; end; -procedure TSilentThread.DoTerminate; -begin - LockCreateConnection; - try - Modules.DecActiveConnectionCount(ModuleId); - Manager.Threads.Remove(Self); - finally - UnlockCreateConnection; - end; - Synchronize(Manager.UpdateLoadStatus); - inherited DoTerminate; -end; - procedure TSilentThread.Execute; begin Synchronize(Manager.UpdateLoadStatus); @@ -435,7 +423,16 @@ constructor TSilentThread.Create; destructor TSilentThread.Destroy; begin + EnterCriticalsection(Manager.FCS_THREADS); + try + Modules.DecActiveConnectionCount(ModuleId); + Manager.Threads.Remove(Self); + finally + LeaveCriticalsection(Manager.FCS_THREADS); + end; Info.Free; + if not isExiting then + Synchronize(Manager.UpdateLoadStatus); inherited Destroy; end; From a23fc96c0530c33262fbb2eb550cef5064f05a7c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 22:32:45 +0800 Subject: [PATCH 1577/2794] fixed terminating favorites thread/check new chapters --- baseunits/uFavoritesManager.pas | 207 +++++++++++++++----------------- 1 file changed, 97 insertions(+), 110 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index d20d38270..24cdc4318 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -23,15 +23,17 @@ TfavoriteContainer = class; { TFavoriteThread } TFavoriteThread = class(THTTPThread) + private + FMangaInformation: TMangaInformation; protected procedure SyncStatus; procedure Execute; override; - procedure DoTerminate; override; public WorkId: Cardinal; Task: TFavoriteTask; Container: TfavoriteContainer; constructor Create; + destructor Destroy; override; end; TFavoriteThreads = TFPGList<TFavoriteThread>; @@ -48,7 +50,6 @@ TFavoriteTask = class(THTTPThread) procedure SyncUpdateBtnCaption; procedure Checkout; procedure Execute; override; - procedure DoTerminate; override; public CS_Threads: TRTLCriticalSection; Manager: TFavoriteManager; @@ -93,7 +94,7 @@ TFavoriteManager = class function ConvertToDB: Boolean; public Items: TFavoriteContainers; - taskthread: TFavoriteTask; + TaskThread: TFavoriteTask; DLManager: TDownloadManager; OnUpdateFavorite: procedure of object; OnUpdateDownload: procedure of object; @@ -209,24 +210,14 @@ procedure TFavoriteThread.Execute; with Container do try // get new manga info - with TMangaInformation.Create(Self) do - try - isGetByUpdater := False; - mangaInfo.title := FavoriteInfo.Title; - GetInfoFromURL(FavoriteInfo.Website, FavoriteInfo.Link, DefaultRetryCount); - if not Terminated then - begin - NewMangaInfoChaptersPos := TCardinalList.Create; - NewMangaInfo := mangaInfo; - mangaInfo := nil; - end; - finally - Free; - end; - - // check for new chapters - if (not Terminated) and Assigned(NewMangaInfo) then + FMangaInformation.isGetByUpdater := False; + FMangaInformation.mangaInfo.title := FavoriteInfo.Title; + FMangaInformation.GetInfoFromURL(FavoriteInfo.Website, FavoriteInfo.Link, DefaultRetryCount); + if not Terminated then begin + NewMangaInfo := FMangaInformation.mangaInfo; + FMangaInformation.mangaInfo := nil; + NewMangaInfoChaptersPos := TCardinalList.Create; // update current chapters count immedietly FavoriteInfo.CurrentChapter := IntToStr(NewMangaInfo.chapterLinks.Count); if NewMangaInfo.chapterLinks.Count > 0 then @@ -256,42 +247,39 @@ procedure TFavoriteThread.Execute; end; end; -procedure TFavoriteThread.DoTerminate; +constructor TFavoriteThread.Create; begin - EnterCriticalsection(Container.Manager.CS_Favorites); - try - if Terminated then - begin - Container.Status := STATUS_IDLE; - // free unused objects - if Assigned(Container.NewMangaInfo) then - begin - FreeAndNil(Container.NewMangaInfo); - FreeAndNil(Container.NewMangaInfoChaptersPos); - end; - end - else - Container.Status := STATUS_CHECKED; - Container.Thread := nil; + inherited Create(True); + FMangaInformation := TMangaInformation.Create(Self); +end; - EnterCriticalsection(Task.CS_Threads); - try - Modules.DecActiveConnectionCount(Container.ModuleId); - Task.Threads.Remove(Self); - finally - LeaveCriticalsection(Task.CS_Threads); +destructor TFavoriteThread.Destroy; +begin + if Terminated then + begin + Container.Status := STATUS_IDLE; + // free unused objects + if Assigned(Container.NewMangaInfo) then + begin + FreeAndNil(Container.NewMangaInfo); + FreeAndNil(Container.NewMangaInfoChaptersPos); end; + end + else + Container.Status := STATUS_CHECKED; + Container.Thread := nil; + + EnterCriticalsection(Task.CS_Threads); + try + Modules.DecActiveConnectionCount(Container.ModuleId); + Task.Threads.Remove(Self); finally - LeaveCriticalsection(Container.Manager.CS_Favorites); + LeaveCriticalsection(Task.CS_Threads); end; + FMangaInformation.Free; if not Terminated then Synchronize(SyncStatus); - inherited DoTerminate; -end; - -constructor TFavoriteThread.Create; -begin - inherited Create(True); + inherited Destroy; end; { TFavoriteTask } @@ -316,13 +304,6 @@ procedure TFavoriteTask.SyncFinishChecking; btFavoritesCheckNewChapter.Caption := RS_BtnCheckFavorites; vtFavorites.Repaint; end; - try - EnterCriticalsection(Manager.CS_Favorites); - Manager.isRunning := False; - Manager.taskthread := nil; - finally - LeaveCriticalsection(Manager.CS_Favorites); - end; end; procedure TFavoriteTask.SyncUpdateBtnCaption; @@ -404,7 +385,20 @@ procedure TFavoriteTask.Execute; end; end; -procedure TFavoriteTask.DoTerminate; +procedure TFavoriteTask.UpdateBtnCaption(Cap: String); +begin + FBtnCaption := Cap; + Synchronize(SyncUpdateBtnCaption); +end; + +constructor TFavoriteTask.Create; +begin + inherited Create(True); + InitCriticalSection(CS_Threads); + Threads := TFavoriteThreads.Create; +end; + +destructor TFavoriteTask.Destroy; var i: Integer; begin @@ -427,10 +421,7 @@ procedure TFavoriteTask.DoTerminate; LeaveCriticalsection(CS_Threads); end; while Threads.Count > 0 do - Sleep(100); - - // reset the ui - Synchronize(SyncFinishChecking); + Sleep(32); if (not Terminated) and (not isDlgCounter) then Synchronize(Manager.ShowResult) @@ -441,35 +432,29 @@ procedure TFavoriteTask.DoTerminate; try for i := 0 to Manager.Items.Count - 1 do with Manager.Items[i] do + begin if Assigned(NewMangaInfo) then - begin FreeAndNil(NewMangaInfo); + if Assigned(NewMangaInfoChaptersPos) then FreeAndNil(NewMangaInfoChaptersPos); - end; + end; finally LeaveCriticalsection(Manager.CS_Favorites); end; end; - inherited DoTerminate; -end; - -procedure TFavoriteTask.UpdateBtnCaption(Cap: String); -begin - FBtnCaption := Cap; - Synchronize(SyncUpdateBtnCaption); -end; -constructor TFavoriteTask.Create; -begin - inherited Create(True); - InitCriticalSection(CS_Threads); - Threads := TFavoriteThreads.Create; -end; - -destructor TFavoriteTask.Destroy; -begin Threads.Free; - DoneCriticalsection(CS_Threads); + try + EnterCriticalsection(Manager.CS_Favorites); + Manager.isRunning := False; + Manager.TaskThread := nil; + finally + LeaveCriticalsection(Manager.CS_Favorites); + end; + + // reset the ui + if not isExiting then + Synchronize(SyncFinishChecking); inherited Destroy; end; @@ -532,14 +517,15 @@ constructor TFavoriteManager.Create; end; destructor TFavoriteManager.Destroy; +var + i: Integer; begin Backup; - if Items.Count > 0 then begin + if Items.Count > 0 then + begin StopChekForNewChapter; - while Items.Count > 0 do begin - Items.Last.Free; - Items.Remove(Items.Last); - end; + for i := 0 to Items.Count - 1 do + Items[i].Free; end; Items.Free; FFavoritesDB.Free; @@ -559,8 +545,8 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); if Status = STATUS_IDLE then begin Status := STATUS_CHECK; - if Assigned(taskthread) then - taskthread.FPendingCount := InterLockedIncrement(taskthread.FPendingCount); + if Assigned(TaskThread) then + TaskThread.FPendingCount := InterLockedIncrement(TaskThread.FPendingCount); end; end else @@ -581,11 +567,11 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); LeaveCriticalsection(CS_Favorites); end; end; - if taskthread = nil then + if TaskThread = nil then begin - taskthread := TFavoriteTask.Create; - taskthread.Manager := Self; - taskthread.Start; + TaskThread := TFavoriteTask.Create; + TaskThread.Manager := Self; + TaskThread.Start; end; except on E: Exception do @@ -595,26 +581,27 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); procedure TFavoriteManager.StopChekForNewChapter(WaitFor: Boolean; FavoriteIndex: Integer); begin - if isRunning then - if FavoriteIndex > -1 then - begin - with Items[FavoriteIndex] do begin - if Thread <> nil then - begin - Thread.Terminate; - if WaitFor then - Thread.WaitFor; - end; - if Status <> STATUS_IDLE then - Status := STATUS_IDLE; + if not isRunning then Exit; + if FavoriteIndex > -1 then + begin + with Items[FavoriteIndex] do begin + if Thread <> nil then + begin + Thread.Terminate; + if WaitFor then + Thread.WaitFor; end; - end - else - begin - taskthread.Terminate; - if WaitFor then - taskthread.WaitFor; + if Status <> STATUS_IDLE then + Status := STATUS_IDLE; end; + end + else + if Assigned(TaskThread) then + begin + TaskThread.Terminate; + if WaitFor then + TaskThread.WaitFor; + end; end; procedure TFavoriteManager.ShowResult; From 41b142be4290e9a51edc68fec7b272eb59527172 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 22:33:29 +0800 Subject: [PATCH 1578/2794] fixed terminating downloads threads --- baseunits/uDownloadsManager.pas | 126 +++++++++++++++----------------- 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8d1ab83ea..582b5337f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -63,7 +63,6 @@ TDownloadThread = class(THTTPThread) const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; procedure Execute; override; - procedure DoTerminate; override; public FHTTP: THTTPSendThread; Task: TTaskThread; @@ -78,6 +77,7 @@ TDownloadThread = class(THTTPThread) TTaskThread = class(THTTPThread) private + FCS_THREADS: TRTLCriticalSection; FCheckAndActiveTaskFlag: Boolean; FCurrentWorkingDir: String; {$IFDEF Windows} @@ -91,7 +91,6 @@ TTaskThread = class(THTTPThread) protected procedure CheckOut; procedure Execute; override; - procedure DoTerminate; override; procedure Compress; procedure SyncStop; // show notification when download completed @@ -312,6 +311,13 @@ constructor TDownloadThread.Create; destructor TDownloadThread.Destroy; begin + EnterCriticalsection(Task.FCS_THREADS); + try + Modules.DecActiveConnectionCount(Task.Container.ModuleId); + Task.Threads.Remove(Self); + finally + LeaveCriticalsection(Task.FCS_THREADS); + end; FHTTP.Free; inherited Destroy; end; @@ -394,18 +400,6 @@ procedure TDownloadThread.Execute; end; end; -procedure TDownloadThread.DoTerminate; -begin - LockCreateConnection; - try - Modules.DecActiveConnectionCount(Task.Container.ModuleId); - Task.Threads.Remove(Self); - finally - UnlockCreateConnection; - end; - inherited DoTerminate; -end; - function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; var Parser: THTMLParser; @@ -796,6 +790,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; constructor TTaskThread.Create; begin inherited Create(True); + InitCriticalSection(FCS_THREADS); Threads := TDownloadThreads.Create; FCheckAndActiveTaskFlag := True; FIsForDelete := False; @@ -806,8 +801,56 @@ constructor TTaskThread.Create; end; destructor TTaskThread.Destroy; +var + i: Integer; begin + EnterCriticalsection(FCS_THREADS); + try + if Threads.Count > 0 then + for i := 0 to Threads.Count - 1 do + Threads[i].Terminate; + finally + LeaveCriticalsection(FCS_THREADS); + end; + while Threads.Count > 0 do + Sleep(32); + + Modules.DecActiveTaskCount(Container.ModuleId); + with Container do + begin + ThreadState := False; + Manager.RemoveItemsActiveTask(Container); + Task := nil; + if not (IsForDelete or Manager.isReadyForExit) then + begin + Container.ReadCount := 0; + DownloadInfo.TransferRate := ''; + if Status <> STATUS_STOP then + begin + if (WorkCounter >= PageLinks.Count) and + (CurrentDownloadChapterPtr >= ChapterLinks.Count) and + (FailedChapterLinks.Count = 0) then + begin + Status := STATUS_FINISH; + DownloadInfo.Status := Format('[%d/%d] %s',[Container.ChapterLinks.Count,Container.ChapterLinks.Count,RS_Finish]); + DownloadInfo.Progress := ''; + end + else + if not (Status in [STATUS_FAILED, STATUS_PROBLEM]) then + begin + Status := STATUS_STOP; + DownloadInfo.Status := + Format('[%d/%d] %s', [CurrentDownloadChapterPtr + 1, + ChapterLinks.Count, RS_Stopped]); + FCheckAndActiveTaskFlag := False; + end; + if not isExiting then + Synchronize(SyncStop); + end; + end; + end; Threads.Free; + DoneCriticalsection(FCS_THREADS); inherited Destroy; end; @@ -1061,7 +1104,7 @@ procedure TTaskThread.CheckOut; if (not Terminated) and (Threads.Count < currentMaxThread) then begin - LockCreateConnection; + EnterCriticalsection(FCS_THREADS); try if Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxThread then Exit; Modules.IncActiveConnectionCount(Container.ModuleId); @@ -1077,7 +1120,7 @@ procedure TTaskThread.CheckOut; if Flag = CS_GETPAGELINK then Container.CurrentPageNumber := InterLockedIncrement(Container.CurrentPageNumber); finally - UnlockCreateConnection; + LeaveCriticalsection(FCS_THREADS); end; end; end; @@ -1365,57 +1408,6 @@ procedure TTaskThread.Execute; end; end; -procedure TTaskThread.DoTerminate; -var - i: Integer; -begin - if Threads.Count > 0 then - begin - LockCreateConnection; - try - for i := 0 to Threads.Count - 1 do - TDownloadThread(Threads[i]).Terminate; - finally - UnlockCreateConnection; - end; - while Threads.Count > 0 do - Sleep(32); - end; - Modules.DecActiveTaskCount(Container.ModuleId); - with Container do begin - ThreadState := False; - Manager.RemoveItemsActiveTask(Container); - Task := nil; - if not (IsForDelete or Manager.isReadyForExit) then - begin - Container.ReadCount := 0; - DownloadInfo.TransferRate := ''; - if Status <> STATUS_STOP then - begin - if (WorkCounter >= PageLinks.Count) and - (CurrentDownloadChapterPtr >= ChapterLinks.Count) and - (FailedChapterLinks.Count = 0) then - begin - Status := STATUS_FINISH; - DownloadInfo.Status := Format('[%d/%d] %s',[Container.ChapterLinks.Count,Container.ChapterLinks.Count,RS_Finish]); - DownloadInfo.Progress := ''; - end - else - if not (Status in [STATUS_FAILED, STATUS_PROBLEM]) then - begin - Status := STATUS_STOP; - DownloadInfo.Status := - Format('[%d/%d] %s', [CurrentDownloadChapterPtr + 1, - ChapterLinks.Count, RS_Stopped]); - FCheckAndActiveTaskFlag := False; - end; - Synchronize(SyncStop); - end; - end; - end; - inherited DoTerminate; -end; - { TTaskContainer } procedure TTaskContainer.SetWebsite(AValue: String); From 8b5f23a800d982960fc9bd0f822cc8d63493e8fd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 23:09:37 +0800 Subject: [PATCH 1579/2794] fixed terminating getinfosthread --- baseunits/uGetMangaInfosThread.pas | 43 ++++++++++-------------------- mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 15 insertions(+), 30 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 8359014bd..7c6b09c9f 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -34,9 +34,7 @@ TGetMangaInfosThread = class(THTTPThread) // Flush this thread, means that the result will not be shown. FIsFlushed: Boolean; - procedure DoTerminate; override; procedure Execute; override; - procedure DoGetInfos; procedure MainThreadSyncInfos; procedure MainThreadShowInfos; @@ -58,7 +56,13 @@ implementation uses frmMain, WebsiteModules; -procedure TGetMangaInfosThread.DoGetInfos; +procedure TGetMangaInfosThread.MainThreadSyncInfos; +begin + FInfo.SyncInfoToData(MainForm.DataProcess); + MainForm.dataProcess.Commit; +end; + +procedure TGetMangaInfosThread.Execute; function GetMangaInfo: Boolean; var @@ -139,15 +143,17 @@ procedure TGetMangaInfosThread.DoGetInfos; end; begin + MainForm.isGetMangaInfos := True; try if not GetMangaInfo then begin - if not Self.Terminated then + if not (Terminated or isExiting) then Synchronize(MainThreadShowCannotGetInfo); end else begin - Synchronize(MainThreadShowInfos); + if not (Terminated or isExiting) then + Synchronize(MainThreadShowInfos); FCover.Clear; // If there's cover then we will load it to the TPicture component. if OptionEnableLoadCover and (Trim(FInfo.mangaInfo.coverLink) <> '') then @@ -162,7 +168,8 @@ procedure TGetMangaInfosThread.DoGetInfos; end else FIsHasMangaCover := False; - Synchronize(MainThreadShowCover); + if not (Terminated or isExiting) then + Synchronize(MainThreadShowCover); end; except on E: Exception do @@ -170,29 +177,6 @@ procedure TGetMangaInfosThread.DoGetInfos; end; end; -procedure TGetMangaInfosThread.MainThreadSyncInfos; -begin - FInfo.SyncInfoToData(MainForm.DataProcess); - MainForm.dataProcess.Commit; -end; - -procedure TGetMangaInfosThread.DoTerminate; -begin - Modules.DecActiveConnectionCount(FInfo.ModuleId); - inherited DoTerminate; -end; - -procedure TGetMangaInfosThread.Execute; -begin - MainForm.isGetMangaInfos := True; - try - DoGetInfos; - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); - end; -end; - procedure TGetMangaInfosThread.MainThreadShowCannotGetInfo; begin if IsFlushed then @@ -263,6 +247,7 @@ constructor TGetMangaInfosThread.Create; destructor TGetMangaInfosThread.Destroy; begin + Modules.DecActiveConnectionCount(FInfo.ModuleId); FInfo.Free; FCover := nil; if not IsFlushed then diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0416269a0..638dd59e6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1315,7 +1315,7 @@ procedure TMainForm.CloseNow; OpenDBThread.WaitFor; Logger.Send(Self.ClassName+'.CloseNow, OpenDBThread terminated'); end; - if isGetMangaInfos then + if isGetMangaInfos and Assigned(GetInfosThread) then begin Logger.Send(Self.ClassName+'.CloseNow, terminating GetInfosThread'); GetInfosThread.IsFlushed := True; From fe8fda6df18109306f7a4a3174b71782ead71b1b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 23:29:12 +0800 Subject: [PATCH 1580/2794] frmmain, terminate and wait for prev getmangainfosthread before creating the new one --- mangadownloader/forms/frmMain.pas | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 638dd59e6..10851db14 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -632,9 +632,8 @@ TMainForm = class(TForm) gifWaiting: TAnimatedGif; gifWaitingRect: TRect; - // doing stuff like get manga info, compress, ... + // get manga info GetInfosThread: TGetMangaInfosThread; - isGetMangaInfos: Boolean; // check update CheckUpdateThread: TCheckUpdateThread; @@ -1078,7 +1077,6 @@ procedure TMainForm.FormCreate(Sender: TObject); btAbortUpdateList.Parent := sbUpdateList; isRunDownloadFilter := False; isUpdating := False; - isGetMangaInfos := False; isPendingExitCounter:=False; isNormalExit:=False; DoAfterFMD := DO_NOTHING; @@ -1315,10 +1313,9 @@ procedure TMainForm.CloseNow; OpenDBThread.WaitFor; Logger.Send(Self.ClassName+'.CloseNow, OpenDBThread terminated'); end; - if isGetMangaInfos and Assigned(GetInfosThread) then + if Assigned(GetInfosThread) then begin Logger.Send(Self.ClassName+'.CloseNow, terminating GetInfosThread'); - GetInfosThread.IsFlushed := True; GetInfosThread.Terminate; GetInfosThread.WaitFor; Logger.Send(Self.ClassName+'.CloseNow, GetInfosThread terminated'); @@ -4420,8 +4417,15 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; i: Integer; begin if (AURL = '') or (AWebsite = '') then Exit; - TURL := Trim(AURL); + // terminate exisiting getmangainfo thread + if Assigned(GetInfosThread) then + begin + GetInfosThread.Terminate; + GetInfosThread.WaitFor; + end; + + TURL := Trim(AURL); // fix url i := Modules.LocateModule(AWebsite); if i > -1 then @@ -4429,12 +4433,6 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; else TURL := FillMangaSiteHost(AWebsite, TURL); - // terminate exisiting getmangainfo thread - if isGetMangaInfos then - begin - GetInfosThread.IsFlushed := True; - GetInfosThread.Terminate; - end; // set the UI pcMain.ActivePage := tsInformation; @@ -4459,6 +4457,8 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; btAddToFavorites.Enabled := not FavoriteManager.IsMangaExist(ATitle, AWebsite); // start the thread + while Assigned(GetInfosThread) do + Sleep(32); GetInfosThread := TGetMangaInfosThread.Create; GetInfosThread.MangaListPos := AMangaListPos; GetInfosThread.Title := ATitle; From 016fbc4df3209b721e839f0ce03f8d12434a86d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 23:31:41 +0800 Subject: [PATCH 1581/2794] fixed terminating getmangainfosthread --- baseunits/uGetMangaInfosThread.pas | 85 ++++++++++-------------------- 1 file changed, 29 insertions(+), 56 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 7c6b09c9f..3310f3e91 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -30,12 +30,9 @@ TGetMangaInfosThread = class(THTTPThread) FInfo: TMangaInformation; FNumChapter: Cardinal; // Return TRUE if we can load manga cover. - FIsHasMangaCover, + FIsHasMangaCover: Boolean; // Flush this thread, means that the result will not be shown. - FIsFlushed: Boolean; - procedure Execute; override; - procedure MainThreadSyncInfos; procedure MainThreadShowInfos; procedure MainThreadShowCover; @@ -43,11 +40,9 @@ TGetMangaInfosThread = class(THTTPThread) public constructor Create; destructor Destroy; override; - property Title: String read FTitle write FTitle; property Website: String read FWebsite write FWebsite; property Link: String read FLink write FLink; - property IsFlushed: Boolean read FIsFlushed write FIsFlushed; property MangaListPos: Integer read FMangaListPos write FMangaListPos; end; @@ -105,7 +100,7 @@ procedure TGetMangaInfosThread.Execute; infob := FInfo.GetInfoFromURL(Website, Link, 0); - if Self.Terminated then Exit; + if Terminated or isExiting then Exit; if infob <> NO_ERROR then Exit; //set back if title changed @@ -132,7 +127,8 @@ procedure TGetMangaInfosThread.Execute; MainForm.DataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; end; - Synchronize(MainThreadSyncInfos); + if not (Terminated or isExiting) then + Synchronize(MainThreadSyncInfos); end; end; Result := True; @@ -143,7 +139,6 @@ procedure TGetMangaInfosThread.Execute; end; begin - MainForm.isGetMangaInfos := True; try if not GetMangaInfo then begin @@ -179,67 +174,46 @@ procedure TGetMangaInfosThread.Execute; procedure TGetMangaInfosThread.MainThreadShowCannotGetInfo; begin - if IsFlushed then - Exit; - try - MessageDlg('', RS_DlgCannotGetMangaInfo, - mtInformation, [mbYes], 0); - MainForm.rmInformation.Clear; - MainForm.tmAnimateMangaInfo.Enabled := False; - MainForm.pbWait.Visible := False; - MainForm.imCover.Picture.Assign(nil); - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); - end; + MessageDlg('', RS_DlgCannotGetMangaInfo, + mtInformation, [mbYes], 0); + MainForm.rmInformation.Clear; + MainForm.tmAnimateMangaInfo.Enabled := False; + MainForm.pbWait.Visible := False; + MainForm.imCover.Picture.Assign(nil); end; procedure TGetMangaInfosThread.MainThreadShowInfos; begin - if IsFlushed then Exit; - try - TransferMangaInfo(MainForm.mangaInfo, FInfo.mangaInfo); - with MainForm do begin - if (FMangaListPos > -1) and dataProcess.WebsiteLoaded(Website) then - begin - vtMangaList.BeginUpdate; - dataProcess.Refresh; - vtMangaList.EndUpdate; - end; - ShowInformation(mangaInfo.title, mangaInfo.website, mangaInfo.link); - end; - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); + TransferMangaInfo(MainForm.mangaInfo, FInfo.mangaInfo); + with MainForm do begin + if (FMangaListPos > -1) and dataProcess.WebsiteLoaded(Website) then + begin + vtMangaList.BeginUpdate; + dataProcess.Refresh; + vtMangaList.EndUpdate; + end; + ShowInformation(mangaInfo.title, mangaInfo.website, mangaInfo.link); end; end; procedure TGetMangaInfosThread.MainThreadShowCover; begin - if IsFlushed then - Exit; - try - MainForm.tmAnimateMangaInfo.Enabled := False; - MainForm.pbWait.Visible := False; - if FIsHasMangaCover then - begin - try - MainForm.imCover.Picture.Assign(FCover); - except - on E: Exception do ; - end; - FCover.Clear; + MainForm.tmAnimateMangaInfo.Enabled := False; + MainForm.pbWait.Visible := False; + if FIsHasMangaCover then + begin + try + MainForm.imCover.Picture.Assign(FCover); + except + on E: Exception do ; end; - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); + FCover.Clear; end; end; constructor TGetMangaInfosThread.Create; begin inherited Create(True); - FIsFlushed := False; FInfo := TMangaInformation.Create(Self); FCover := MainForm.mangaCover; FMangaListPos := -1; @@ -250,8 +224,7 @@ destructor TGetMangaInfosThread.Destroy; Modules.DecActiveConnectionCount(FInfo.ModuleId); FInfo.Free; FCover := nil; - if not IsFlushed then - MainForm.isGetMangaInfos := False; + MainForm.GetInfosThread := nil; inherited Destroy; end; From 76d7f8db151bd26137ceadc67e21c0d0ed18ef53 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 23:49:43 +0800 Subject: [PATCH 1582/2794] httpsendthread, some hint --- baseunits/httpsendthread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index bef0b9116..21794596e 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -128,6 +128,7 @@ procedure cleanuri(var u:string); Delete(URL,1,p); end; p:=poschar(':',URL); + q:=0; if (p<>0) and (p<Length(URL)) and (URL[P+1] in ['0'..'9']) then begin for q:=p+1 to Length(URL) do From 4bebad3aa38a937b1b687cb3123a5c09638388c0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 28 Feb 2017 23:50:33 +0800 Subject: [PATCH 1583/2794] updater, cleanup and fix some issue --- updater/languages/updater.el_GR.po | 4 +++ updater/languages/updater.en.po | 4 +++ updater/languages/updater.es.po | 5 +++ updater/languages/updater.id_ID.po | 4 +++ updater/languages/updater.pl_PL.po | 5 +++ updater/languages/updater.po | 4 +++ updater/languages/updater.pt_BR.po | 4 +++ updater/uMain.lfm | 7 ++-- updater/uMain.lrj | 1 + updater/uMain.pas | 55 ++++++++++++++---------------- 10 files changed, 60 insertions(+), 33 deletions(-) diff --git a/updater/languages/updater.el_GR.po b/updater/languages/updater.el_GR.po index 2761840df..e5245f73b 100644 --- a/updater/languages/updater.el_GR.po +++ b/updater/languages/updater.el_GR.po @@ -15,6 +15,10 @@ msgstr "" "X-Poedit-Country: GREECE\n" "X-Poedit-SourceCharset: UTF-8\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Μέγεθος αρχείου" diff --git a/updater/languages/updater.en.po b/updater/languages/updater.en.po index 18c436bfa..78bab6e03 100644 --- a/updater/languages/updater.en.po +++ b/updater/languages/updater.en.po @@ -11,6 +11,10 @@ msgstr "" "Language: en\n" "X-Generator: Poedit 1.8.8\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "File size" diff --git a/updater/languages/updater.es.po b/updater/languages/updater.es.po index f640aea5b..1c70b0363 100644 --- a/updater/languages/updater.es.po +++ b/updater/languages/updater.es.po @@ -11,6 +11,10 @@ msgstr "" "Language: es\n" "X-Generator: Poedit 1.8.11\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Tamaño del Archivo" @@ -102,3 +106,4 @@ msgstr "Extrayendo Archivo [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Esperando Aplicación Principal que se Cierre..." + diff --git a/updater/languages/updater.id_ID.po b/updater/languages/updater.id_ID.po index 924bc1912..157337cd2 100644 --- a/updater/languages/updater.id_ID.po +++ b/updater/languages/updater.id_ID.po @@ -11,6 +11,10 @@ msgstr "" "Language: id_ID\n" "X-Generator: Poedit 1.8.8\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Ukuran" diff --git a/updater/languages/updater.pl_PL.po b/updater/languages/updater.pl_PL.po index febb2a8da..5e6230c1e 100644 --- a/updater/languages/updater.pl_PL.po +++ b/updater/languages/updater.pl_PL.po @@ -12,6 +12,10 @@ msgstr "" "X-Generator: Poedit 1.7.4\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Rozmiar pliku" @@ -103,3 +107,4 @@ msgstr "Rozpakowanie pliku [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Oczekiwanie aż główna aplikacja się zamknie..." + diff --git a/updater/languages/updater.po b/updater/languages/updater.po index 00ea74156..56c7490de 100644 --- a/updater/languages/updater.po +++ b/updater/languages/updater.po @@ -1,6 +1,10 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "" diff --git a/updater/languages/updater.pt_BR.po b/updater/languages/updater.pt_BR.po index c69e7d3ba..6807f784f 100644 --- a/updater/languages/updater.pt_BR.po +++ b/updater/languages/updater.pt_BR.po @@ -11,6 +11,10 @@ msgstr "" "Language: pt-BR\n" "X-Generator: Poedit 1.8.8\n" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Tamanho do arquivo" diff --git a/updater/uMain.lfm b/updater/uMain.lfm index 2f5f24a4f..1676c8923 100644 --- a/updater/uMain.lfm +++ b/updater/uMain.lfm @@ -14,7 +14,6 @@ object frmMain: TfrmMain OnShow = FormShow Position = poOwnerFormCenter LCLVersion = '1.7' - Visible = False object pbDownload: TProgressBar Left = 8 Height = 20 @@ -36,7 +35,7 @@ object frmMain: TfrmMain Left = 8 Height = 15 Top = 52 - Width = 66 + Width = 65 Caption = 'Transfer rate' ParentColor = False end @@ -68,7 +67,7 @@ object frmMain: TfrmMain object itMonitor: TIdleTimer Enabled = False OnTimer = itMonitorTimer - left = 168 - top = 8 + Left = 168 + Top = 8 end end diff --git a/updater/uMain.lrj b/updater/uMain.lrj index f906dfa05..8a7917a17 100644 --- a/updater/uMain.lrj +++ b/updater/uMain.lrj @@ -1,4 +1,5 @@ {"version":1,"strings":[ +{"hash":193843458,"name":"tfrmmain.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114,32,45,32,85,112,100,97,116,101,114],"value":"Free Manga Downloader - Updater"}, {"hash":131060021,"name":"tfrmmain.lbtransferrate.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,114,97,116,101],"value":"Transfer rate"}, {"hash":41414149,"name":"tfrmmain.lbfilesize.caption","sourcebytes":[70,105,108,101,32,115,105,122,101],"value":"File size"}, {"hash":184637710,"name":"tfrmmain.lbstatus.caption","sourcebytes":[87,97,105,116,105,110,103,46,46,46],"value":"Waiting..."} diff --git a/updater/uMain.pas b/updater/uMain.pas index 414b2347b..025548f39 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -58,7 +58,6 @@ TDownloadThread = class(THTTPThread) procedure UpdateStatus(AStatus: String); procedure ShowErrorMessage(AMessage: String); procedure Execute; override; - procedure OnThreadTerminate(Sender: TObject); public URL: String; FileName: String; @@ -91,12 +90,15 @@ procedure IncReadCount(const ACount: Int64); ProxyUser: String; ProxyPass: String; + const Symbols: array [0..10] of Char = ('\', '/', ':', '*', '?', '"', '<', '>', '|', #9, ';'); UA_CURL = 'curl/7.42.1'; + CONFIG_FILE = 'config/config.ini'; + resourcestring RS_InvalidURL = 'Invalid URL!'; RS_Response = 'Response'; @@ -510,11 +512,6 @@ procedure TDownloadThread.Execute; HTTPHeaders.Free; end; -procedure TDownloadThread.OnThreadTerminate(Sender: TObject); -begin - FHTTP.Sock.AbortSocket; -end; - { TfrmMain } procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -528,8 +525,6 @@ procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); end; procedure TfrmMain.FormCreate(Sender: TObject); -var - config: TIniFile; begin Randomize; SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; @@ -537,27 +532,29 @@ procedure TfrmMain.FormCreate(Sender: TObject); SimpleTranslator.CollectLanguagesFiles; InitCriticalSection(CS_ReadCount); //load proxy config from fmd - config := TIniFile.Create('config/config.ini'); - try - if config.ReadBool('connections', 'UseProxy', False) then - begin - ProxyType := config.ReadString('connections', 'ProxyType', 'HTTP'); - ProxyHost := config.ReadString('connections', 'Host', ''); - ProxyPort := config.ReadString('connections', 'Port', ''); - ProxyUser := config.ReadString('connections', 'User', ''); - ProxyPass := config.ReadString('connections', 'Pass', ''); - end - else - begin - ProxyType := ''; - ProxyHost := ''; - ProxyPort := ''; - ProxyUser := ''; - ProxyPass := ''; + if not FileExistsUTF8(CONFIG_FILE) then Exit; + with TIniFile.Create(CONFIG_FILE) do + try + SimpleTranslator.SetLang(ReadString('languages', 'Selected', 'en'), 'updater'); + if ReadBool('connections', 'UseProxy', False) then + begin + ProxyType := ReadString('connections', 'ProxyType', 'HTTP'); + ProxyHost := ReadString('connections', 'Host', ''); + ProxyPort := ReadString('connections', 'Port', ''); + ProxyUser := ReadString('connections', 'User', ''); + ProxyPass := ReadString('connections', 'Pass', ''); + end + else + begin + ProxyType := ''; + ProxyHost := ''; + ProxyPort := ''; + ProxyUser := ''; + ProxyPass := ''; + end; + finally + Free; end; - finally - FreeAndNil(config); - end; end; procedure TfrmMain.FormDestroy(Sender: TObject); @@ -600,7 +597,7 @@ procedure TfrmMain.FormShow(Sender: TObject); else if s = '-l' then _LaunchApp := ParamStrUTF8(i + 1) else if (LowerCase(s) = '--lang') then - SimpleTranslator.SetLang(ParamStrUTF8(i + 1)); + SimpleTranslator.SetLang(ParamStrUTF8(i + 1), 'updater'); end; end; end; From f647d4a6cf1b07b02f64bb4e0e1b0eced9935ca0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Mar 2017 00:01:03 +0800 Subject: [PATCH 1584/2794] updater, fixed layout with translations --- updater/uMain.lfm | 30 ++++++++++++++++++++---------- updater/updater.lpi | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/updater/uMain.lfm b/updater/uMain.lfm index 1676c8923..8dc2c55ed 100644 --- a/updater/uMain.lfm +++ b/updater/uMain.lfm @@ -24,11 +24,17 @@ object frmMain: TfrmMain TabOrder = 0 end object lbTransferRateValue: TLabel - Left = 96 - Height = 1 + AnchorSideLeft.Control = lbTransferRate + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = lbTransferRate + AnchorSideBottom.Side = asrBottom + Left = 83 + Height = 15 Top = 52 - Width = 229 - Anchors = [akTop, akLeft, akRight] + Width = 242 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoSize = False + BorderSpacing.Left = 10 ParentColor = False end object lbTransferRate: TLabel @@ -40,11 +46,15 @@ object frmMain: TfrmMain ParentColor = False end object lbFileSizeValue: TLabel - Left = 96 - Height = 1 + AnchorSideLeft.Control = lbTransferRateValue + AnchorSideBottom.Control = lbFileSize + AnchorSideBottom.Side = asrBottom + Left = 83 + Height = 15 Top = 34 - Width = 229 - Anchors = [akTop, akLeft, akRight] + Width = 242 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoSize = False ParentColor = False end object lbFileSize: TLabel @@ -67,7 +77,7 @@ object frmMain: TfrmMain object itMonitor: TIdleTimer Enabled = False OnTimer = itMonitorTimer - Left = 168 - Top = 8 + Left = 264 + Top = 16 end end diff --git a/updater/updater.lpi b/updater/updater.lpi index 05706fc64..1aaf21ad5 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="9"/> + <Version Value="10"/> <PathDelim Value="\"/> <General> <SessionStorage Value="InProjectDir"/> From 9cdb90a2452ac29eb83d7639a8cc42580f18437b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Mar 2017 00:28:14 +0800 Subject: [PATCH 1585/2794] updater, added exception handler --- updater/uMain.pas | 20 +++++++++++++- updater/updater.lpi | 64 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 025548f39..14794c94c 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -12,7 +12,7 @@ interface Classes, SysUtils, zipper, FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls, RegExpr, IniFiles, blcksock, ssl_openssl, ssl_openssl_lib, synacode, httpsendthread, uMisc, - SimpleTranslator; + SimpleTranslator, SimpleException; type @@ -507,6 +507,8 @@ procedure TDownloadThread.Execute; if (not Self.Terminated) and _UpdApp and (_LaunchApp <> '') then RunExternalProcess(_LaunchApp, [''], True, False); except + on E: Exception do + ExceptionHandle(Self, E); end; regx.Free; HTTPHeaders.Free; @@ -516,17 +518,24 @@ procedure TDownloadThread.Execute; procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin + try if isDownload then begin dl.Terminate; dl.WaitFor; end; CloseAction := caFree; + except + on E: Exception do + ExceptionHandle(Self, E); + end; end; procedure TfrmMain.FormCreate(Sender: TObject); begin Randomize; + InitSimpleExceptionHandler; + try SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; SimpleTranslator.LangAppName := 'updater'; SimpleTranslator.CollectLanguagesFiles; @@ -555,6 +564,10 @@ procedure TfrmMain.FormCreate(Sender: TObject); finally Free; end; + except + on E: Exception do + ExceptionHandle(Self, E); + end; end; procedure TfrmMain.FormDestroy(Sender: TObject); @@ -568,6 +581,7 @@ procedure TfrmMain.FormShow(Sender: TObject); i: Integer; sh: Boolean = False; begin + try if Paramcount > 0 then begin for i := 1 to Paramcount do @@ -633,6 +647,10 @@ procedure TfrmMain.FormShow(Sender: TObject); Self.Close; end; end; + except + on E: Exception do + ExceptionHandle(Self, E); + end; end; procedure TfrmMain.itMonitorTimer(Sender: TObject); diff --git a/updater/updater.lpi b/updater/updater.lpi index 1aaf21ad5..66d7d0869 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -22,7 +22,7 @@ <Attributes pvaPrivateBuild="True"/> <StringTable FileDescription="Updater for Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="updater.exe" ProductName="Updater" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> - <BuildModes Count="2"> + <BuildModes Count="4"> <Item1 Name="Win32" Default="True"/> <Item2 Name="Win64"> <CompilerOptions> @@ -33,7 +33,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> - <OtherUnitFiles Value="..\baseunits"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\SimpleException"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -57,6 +57,64 @@ </Linking> </CompilerOptions> </Item2> + <Item3 Name="Win32 Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\bin\updater"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\SimpleException"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="i386"/> + <TargetOS Value="win32"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + </Item3> + <Item4 Name="Win64 Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\bin\updater"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\SimpleException"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + </Item4> </BuildModes> <PublishOptions> <Version Value="2"/> @@ -107,7 +165,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir)"/> - <OtherUnitFiles Value="..\baseunits"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\SimpleException"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From e61d6ed1d72853a50e530850ef4c45845966714d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Mar 2017 00:32:57 +0800 Subject: [PATCH 1586/2794] updater, increase version number --- updater/updater.lpi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/updater.lpi b/updater/updater.lpi index 66d7d0869..09b25fd42 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MajorVersionNr Value="2"/> - <MinorVersionNr Value="4"/> + <MinorVersionNr Value="5"/> <Attributes pvaPrivateBuild="True"/> <StringTable FileDescription="Updater for Free Manga Downloader" LegalCopyright="©2015 FMD Project Team" OriginalFilename="updater.exe" ProductName="Updater" ProductVersion="$BuildMode()" PrivateBuild="Cholif"/> </VersionInfo> From 22aa60f0a590c649e393de324d40b67f6f1064ef Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Mar 2017 02:45:51 +0800 Subject: [PATCH 1587/2794] enclose terminate getinfo in try except --- baseunits/uGetMangaInfosThread.pas | 25 ++++++++++++------------- mangadownloader/forms/frmMain.pas | 28 ++++++++++++---------------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 3310f3e91..4195042e5 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -147,22 +147,20 @@ procedure TGetMangaInfosThread.Execute; end else begin - if not (Terminated or isExiting) then - Synchronize(MainThreadShowInfos); + if Terminated or isExiting then Exit; + Synchronize(MainThreadShowInfos); FCover.Clear; // If there's cover then we will load it to the TPicture component. if OptionEnableLoadCover and (Trim(FInfo.mangaInfo.coverLink) <> '') then - begin - FInfo.FHTTP.Document.Clear; - FIsHasMangaCover := FInfo.FHTTP.GET(FInfo.mangaInfo.coverLink); - if FIsHasMangaCover then - try + try + FInfo.FHTTP.Document.Clear; + if FInfo.FHTTP.GET(FInfo.mangaInfo.coverLink) then + begin FCover.LoadFromStream(FInfo.FHTTP.Document); - except + FIsHasMangaCover := True; end; - end - else - FIsHasMangaCover := False; + except + end; if not (Terminated or isExiting) then Synchronize(MainThreadShowCover); end; @@ -216,15 +214,16 @@ constructor TGetMangaInfosThread.Create; inherited Create(True); FInfo := TMangaInformation.Create(Self); FCover := MainForm.mangaCover; + FIsHasMangaCover := False; FMangaListPos := -1; end; destructor TGetMangaInfosThread.Destroy; begin Modules.DecActiveConnectionCount(FInfo.ModuleId); - FInfo.Free; - FCover := nil; MainForm.GetInfosThread := nil; + FCover := nil; + FInfo.Free; inherited Destroy; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 10851db14..1f8949de7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1316,8 +1316,11 @@ procedure TMainForm.CloseNow; if Assigned(GetInfosThread) then begin Logger.Send(Self.ClassName+'.CloseNow, terminating GetInfosThread'); - GetInfosThread.Terminate; - GetInfosThread.WaitFor; + try + GetInfosThread.Terminate; + GetInfosThread.WaitFor; + except + end; Logger.Send(Self.ClassName+'.CloseNow, GetInfosThread terminated'); end; if isUpdating then @@ -4420,10 +4423,12 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; // terminate exisiting getmangainfo thread if Assigned(GetInfosThread) then - begin - GetInfosThread.Terminate; - GetInfosThread.WaitFor; - end; + try + { TODO -oriderkick : Access violation on terminate } + GetInfosThread.Terminate; + GetInfosThread.WaitFor; + except + end; TURL := Trim(AURL); // fix url @@ -4457,8 +4462,6 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; btAddToFavorites.Enabled := not FavoriteManager.IsMangaExist(ATitle, AWebsite); // start the thread - while Assigned(GetInfosThread) do - Sleep(32); GetInfosThread := TGetMangaInfosThread.Create; GetInfosThread.MangaListPos := AMangaListPos; GetInfosThread.Title := ATitle; @@ -4480,14 +4483,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); try Lines.BeginUpdate; Lines.Clear; - if (GetInfosThread <> nil) and - ((GetInfosThread.MangaListPos > -1) or (GetInfosThread.MangaListPos = -2)) then - begin - mangaInfo.title := title; - mangaInfo.link := link; - end - else - edURL.Text := mangaInfo.url; + edURL.Text := mangaInfo.url; AddTextToInfo(RS_InfoTitle, mangaInfo.title); AddTextToInfo(RS_InfoAuthors, mangaInfo.authors); AddTextToInfo(RS_InfoArtists, mangaInfo.artists); From a9f20c0066f537c91c728f4b27ea5663e09ab0c8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Mar 2017 02:48:06 +0800 Subject: [PATCH 1588/2794] some hint --- mangadownloader/forms/frmMain.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 1f8949de7..b650a624c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4424,7 +4424,9 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; // terminate exisiting getmangainfo thread if Assigned(GetInfosThread) then try - { TODO -oriderkick : Access violation on terminate } + { TODO -oriderkick : Access violation on terminate + if terminating thread while starting download cover + } GetInfosThread.Terminate; GetInfosThread.WaitFor; except From ea3e6017c7c43489d8c9718719da73153d677710 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 1 Mar 2017 02:51:31 +0800 Subject: [PATCH 1589/2794] Bump version 0.9.95.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index c1cd92ea8..46844b132 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.95.0 (29-02-2017) +[*] Fixed various issue when terminating threads/closing app +[*] Fixed updater +Full changes: https://github.com/riderkick/FMD/compare/0.9.94.0...0.9.95.0 + 0.9.94.0 (28-02-2017) [!+] Favorites and Downloads now saved in SQLite database file WARNING: Please backup your favorites.ini and works.ini before update diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 88108c5c4..61cfa19ea 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="94"/> + <RevisionNr Value="95"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 8539ac0d9..10388066a 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.94.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.94.0/fmd_0.9.94.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.94.0/fmd_0.9.94.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.94.0/fmd_0.9.94.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.94.0/fmd_0.9.94.0_Win64.7z +VERSION=0.9.95.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.95.0/fmd_0.9.95.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.95.0/fmd_0.9.95.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.95.0/fmd_0.9.95.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.95.0/fmd_0.9.95.0_Win64.7z From cd368c6599c1f958e017d0701665565fb5fcbf7e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 06:52:01 +0800 Subject: [PATCH 1590/2794] inline getparams --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d616814d5..9a1177055 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -778,7 +778,7 @@ procedure GetParams(var output: TCardinalList; input: String); overload; procedure GetParams(var output: TList; input: String); overload; function ExtractParam(const output: TStrings; input, sep: String; WhiteSp: Boolean = True): Integer; -function GetParams(const input: String): String; overload; +function GetParams(const input: String): String; overload; inline; function RemoveDuplicateNumbersInString(const AString: String): String; // Set param from input From bcbe2e5264d3d70783f83d38fc90cb68b179048b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 06:52:40 +0800 Subject: [PATCH 1591/2794] downloadsmanager, fixed convert to db --- baseunits/uDownloadsManager.pas | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 582b5337f..e696a238c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1660,14 +1660,14 @@ function TDownloadManager.ConvertToDB: Boolean; ReadString(s, 'Progress', ''), ReadString(s, 'SaveTo', ''), StrToFloatDef(ReadString(s, 'DateTime', ''), Now, FMDFormatSettings), - ReadString(s, 'ChapterLinks', ''), - ReadString(s, 'ChapterName', ''), - ReadString(s, 'PageLinks', ''), - ReadString(s, 'PageContainerLinks', ''), - ReadString(s, 'Filenames', ''), + GetParams(ReadString(s, 'ChapterLinks', '')), + GetParams(ReadString(s, 'ChapterName', '')), + GetParams(ReadString(s, 'PageLinks', '')), + GetParams(ReadString(s, 'PageContainerLinks', '')), + GetParams(ReadString(s, 'Filenames', '')), ReadString(s, 'CustomFileName', DEFAULT_FILENAME_CUSTOMRENAME), - ReadString(s, 'FailedChapterLinks', ''), - ReadString(s, 'FailedChapterName', '')); + GetParams(ReadString(s, 'FailedChapterLinks', '')), + GetParams(ReadString(s, 'FailedChapterName', ''))); end; FDownloadsDB.Commit; FDownloadsDB.Refresh(False); From 6baf12bb39a650f06f00213ef3af4ae56bf232b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 07:47:14 +0800 Subject: [PATCH 1592/2794] downloadsmanager, restore downcounter --- baseunits/uDownloadsManager.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index e696a238c..a4225c208 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1706,6 +1706,8 @@ procedure TDownloadManager.Restore; DownloadInfo.Title := Fields[9].AsString; DownloadInfo.Status := Fields[10].AsString; DownloadInfo.Progress := Fields[11].AsString; + if Pos('/', DownloadInfo.Progress) <> 0 then + DownCounter := StrToIntDef(Trim(ExtractWord(1, DownloadInfo.Progress, ['/'])), 0); DownloadInfo.SaveTo := Fields[12].AsString; DownloadInfo.DateTime := Fields[13].AsDateTime; ChapterLinks.Text := Fields[14].AsString; From 8586660a6ed572c736bb56b6cd4625b476d4276f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 08:47:35 +0800 Subject: [PATCH 1593/2794] added submodule internetttools --- .gitmodules | 5 +++++ 3rd/internettools | 1 + 2 files changed, 6 insertions(+) create mode 160000 3rd/internettools diff --git a/.gitmodules b/.gitmodules index f172a31e5..48a34d132 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,8 @@ [submodule "3rd/BESEN"] path = 3rd/BESEN url = https://github.com/BeRo1985/besen.git + ignore = dirty +[submodule "3rd/internettools"] + path = 3rd/internettools + url = https://github.com/benibela/internettools + ignore = dirty diff --git a/3rd/internettools b/3rd/internettools new file mode 160000 index 000000000..4ee1c88cf --- /dev/null +++ b/3rd/internettools @@ -0,0 +1 @@ +Subproject commit 4ee1c88cfb263f36946f3f67a1329b5d225d48d7 From f4d8ad80b6c03fab53f1c3771662c8a34cdbd6fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 08:57:59 +0800 Subject: [PATCH 1594/2794] changed besen output dir --- 3rd/BESENPkg.lpk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk index 4e9d56eec..1921be4fd 100644 --- a/3rd/BESENPkg.lpk +++ b/3rd/BESENPkg.lpk @@ -9,7 +9,7 @@ <SearchPaths> <IncludeFiles Value="BESEN\src"/> <OtherUnitFiles Value="BESEN\src"/> - <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + <UnitOutputDirectory Value="BESEN\lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> <SmartLinkUnit Value="True"/> From 479c0510b0649b558dc9c8b8135ffc558c5b1dde Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 08:59:21 +0800 Subject: [PATCH 1595/2794] added besen and internettools search path --- mangadownloader/md.lpi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 61cfa19ea..39d663184 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -33,7 +33,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -76,7 +76,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -117,7 +117,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -155,7 +155,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -322,7 +322,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 131a0a27fd84cfa3463ddabdb5129a70d603ff3f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 13:30:16 +0800 Subject: [PATCH 1596/2794] added option to sort chapter list in mangainfo, closed #458 --- baseunits/uBaseUnit.pas | 1 + mangadownloader/forms/frmMain.lfm | 21 +++++- mangadownloader/forms/frmMain.lrj | 2 + mangadownloader/forms/frmMain.pas | 92 +++++++++++++++++++++++--- mangadownloader/languages/fmd.el_GR.po | 8 +++ mangadownloader/languages/fmd.en.po | 8 +++ mangadownloader/languages/fmd.es.po | 8 +++ mangadownloader/languages/fmd.id_ID.po | 8 +++ mangadownloader/languages/fmd.pl_PL.po | 8 +++ mangadownloader/languages/fmd.po | 8 +++ mangadownloader/languages/fmd.pt_BR.po | 8 +++ 11 files changed, 160 insertions(+), 12 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9a1177055..bc4ead16e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -511,6 +511,7 @@ TSingleItem = record PChapterStateItem = ^TChapterStateItem; TChapterStateItem = record + Index: Integer; Title, Link: String; Downloaded: Boolean; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 7b62b407c..1f665ada5 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,13 +37,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsDownload + ActivePage = tsInformation Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 0 + TabIndex = 1 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -515,7 +515,7 @@ object MainForm: TMainForm TextMargin = 0 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnBeforeCellPaint = clbChapterListBeforeCellPaint OnGetText = clbChapterListGetText @@ -4885,6 +4885,21 @@ object MainForm: TMainForm Caption = 'Filter' OnClick = miChapterListFilterClick end + object MenuItem11: TMenuItem + Caption = '-' + end + object miChapterListAscending: TMenuItem + Caption = 'Ascending' + RadioItem = True + ShowAlwaysCheckable = True + OnClick = miChapterListAscendingClick + end + object miChapterListDescending: TMenuItem + Caption = 'Descending' + RadioItem = True + ShowAlwaysCheckable = True + OnClick = miChapterListAscendingClick + end end object pmFavorites: TPopupMenu Images = IconList diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index c3b0f807e..b67f46544 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -264,6 +264,8 @@ {"hash":15962307,"name":"tmainform.michapterlisthighlight.caption","sourcebytes":[72,105,103,104,108,105,103,104,116,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115],"value":"Highlight downloaded chapters"}, {"hash":112147507,"name":"tmainform.michapterlisthidedownloaded.caption","sourcebytes":[72,105,100,101,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115],"value":"Hide downloaded chapters"}, {"hash":80755394,"name":"tmainform.michapterlistfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":163899607,"name":"tmainform.michapterlistascending.caption","sourcebytes":[65,115,99,101,110,100,105,110,103],"value":"Ascending"}, +{"hash":163579095,"name":"tmainform.michapterlistdescending.caption","sourcebytes":[68,101,115,99,101,110,100,105,110,103],"value":"Descending"}, {"hash":165778738,"name":"tmainform.mifavoriteschecknewchapter.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Check for new chapter"}, {"hash":222540418,"name":"tmainform.mifavoritesstopchecknewchapter.caption","sourcebytes":[83,116,111,112,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Stop check for new chapter"}, {"hash":27371647,"name":"tmainform.mifavoritesviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b650a624c..d01a4e1be 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -86,6 +86,9 @@ TMainForm = class(TForm) lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; MenuItem10: TMenuItem; + MenuItem11: TMenuItem; + miChapterListDescending: TMenuItem; + miChapterListAscending: TMenuItem; miMangaListDelete: TMenuItem; miDownloadDeleteTaskDataFavorite: TMenuItem; miTrayExit: TMenuItem; @@ -446,6 +449,7 @@ TMainForm = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormWindowStateChange(Sender: TObject); + procedure miChapterListAscendingClick(Sender: TObject); procedure tmAnimateMangaInfoTimer(Sender: TObject); procedure tmCheckFavoritesTimer(Sender: TObject); procedure tmExitCommandTimer(Sender: TObject); @@ -1420,6 +1424,61 @@ procedure TMainForm.FormWindowStateChange(Sender: TObject); PrevWindowState := WindowState; end; +procedure TMainForm.miChapterListAscendingClick(Sender: TObject); +var + i, j, f: Integer; + t: TChapterStateItem; + Node, FNode: PVirtualNode; + c: array of TCheckState; +begin + if not (Sender is TMenuItem) then Exit; + if TMenuItem(Sender).Checked then Exit; + TMenuItem(Sender).Checked := True; + configfile.WriteBool('general', 'SortChapterListAscending', miChapterListAscending.Checked); + if Length(ChapterList) <> 0 then + begin + // invert chapterlist + for i := Low(ChapterList) to (High(ChapterList) div 2) do + begin + j := High(ChapterList) - i; + t := ChapterList[i]; + ChapterList[i] := ChapterList[j]; + ChapterList[j] := t; + end; + // rearrange checked state and focused + if (clbChapterList.CheckedCount <> 0 ) or (clbChapterList.SelectedCount <> 0) then + begin + FNode := nil; + if Assigned(clbChapterList.FocusedNode) then + f := clbChapterList.FocusedNode^.Index + else + f := -1; + SetLength(c, clbChapterList.RootNodeCount); + Node := clbChapterList.GetFirst(); + while Assigned(Node) do + begin + c[Node^.Index] := Node^.CheckState; + Node := clbChapterList.GetNext(Node); + end; + i := Low(c); + Node := clbChapterList.GetLast(); + while Assigned(Node) do + begin + if i = f then + FNode := Node; + Node^.CheckState := c[i]; + Inc(i); + Node := clbChapterList.GetPrevious(Node); + end; + SetLength(c, 0); + if Assigned(FNode) then + clbChapterList.FocusedNode := FNode + end; + clbChapterList.ClearSelection; + clbChapterList.Repaint; + end; +end; + procedure TMainForm.tmAnimateMangaInfoTimer(Sender: TObject); begin gifWaiting.Update(pbWait.Canvas, gifWaitingRect); @@ -2009,14 +2068,14 @@ procedure TMainForm.btDownloadClick(Sender: TObject); begin if (vsVisible in node^.States) then begin - links.Add(mangaInfo.chapterLinks[node^.Index]); + links.Add(ChapterList[node^.Index].Link); s:=CustomRename(OptionChapterCustomRename, mangaInfo.website, mangaInfo.title, mangaInfo.authors, mangaInfo.artists, - mangaInfo.chapterName[node^.Index], - Format('%.4d',[node^.Index+1]), + ChapterList[node^.Index].Title, + Format('%.4d',[ChapterList[node^.Index].Index]), OptionChangeUnicodeCharacter, OptionChangeUnicodeCharacterStr); names.Add(s); @@ -2403,7 +2462,7 @@ procedure TMainForm.clbChapterListGetText(Sender: TBaseVirtualTree; if Length(ChapterList)=1 then CellText:=ChapterList[Node^.Index].Title else - CellText:=Format('%.4d - %s',[Node^.Index+1,ChapterList[Node^.Index].Title]); + CellText:=Format('%.4d - %s',[ChapterList[Node^.Index].Index, ChapterList[Node^.Index].Title]); end; procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; @@ -4474,7 +4533,7 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; procedure TMainForm.ShowInformation(const title, website, link: String); var - i: Integer; + i, j: Integer; begin pcMain.ActivePage := tsInformation; FilledSaveTo; @@ -4500,12 +4559,25 @@ procedure TMainForm.ShowInformation(const title, website, link: String); end; SetLength(ChapterList, mangaInfo.chapterName.Count); - for i := 0 to mangaInfo.chapterName.Count - 1 do + if Length(ChapterList) <> 0 then begin - ChapterList[i].Title := mangaInfo.chapterName[i]; - ChapterList[i].Link := mangaInfo.chapterLinks[i]; - ChapterList[i].Downloaded := False; + if miChapterListAscending.Checked then + j := 0 + else + j := High(ChapterList); + for i := low(ChapterList) to High(ChapterList) do + begin + ChapterList[i].Index := j + 1; + ChapterList[i].Title := mangaInfo.chapterName[j]; + ChapterList[i].Link := mangaInfo.chapterLinks[j]; + ChapterList[i].Downloaded := False; + if miChapterListAscending.Checked then + Inc(j) + else + Dec(j); + end; end; + miChapterListHighlightClick(nil); UpdateVtChapter; miChapterListHideDownloadedClick(nil); @@ -4553,6 +4625,8 @@ procedure TMainForm.LoadOptions; cbAddAsStopped.Checked := ReadBool('general', 'AddAsStopped', False); miHighLightNewManga.Checked := ReadBool('general', 'HighlightNewManga', True); miChapterListHighlight.Checked := ReadBool('general', 'HighlightDownloadedChapters', True); + miChapterListAscending.Checked := ReadBool('general', 'SortChapterListAscending', True); + miChapterListDescending.Checked := not miChapterListAscending.Checked; // view cbOptionShowDownloadToolbar.Checked := ReadBool('view', 'ShowDownloadsToolbar', True); diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index c4d8ee96f..a93d7cd1a 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1508,6 +1508,10 @@ msgstr "Αναίρεση" msgid "Abort" msgstr "Ματαίωση" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1517,6 +1521,10 @@ msgstr "Σήμανση όλων" msgid "Check selected" msgstr "Σήμανση επιλεγμένων" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "" + #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" msgid "Filter" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6a93d7c5b..d56ad6bc9 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1453,6 +1453,10 @@ msgstr "Undo" msgid "Abort" msgstr "Abort" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "Ascending" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1462,6 +1466,10 @@ msgstr "Check all" msgid "Check selected" msgstr "Check selected" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "Descending" + #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" msgid "Filter" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 4b9689a8d..baf120ca7 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1434,6 +1434,10 @@ msgstr "Deshacer" msgid "Abort" msgstr "Abortar" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1443,6 +1447,10 @@ msgstr "Marcar Todo" msgid "Check selected" msgstr "Marcar Selecionado" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "" + #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" msgid "Filter" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 9f7bac136..e00730db2 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1434,6 +1434,10 @@ msgstr "Urungkan" msgid "Abort" msgstr "Batalkan" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "Menaik" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1443,6 +1447,10 @@ msgstr "Centang semua" msgid "Check selected" msgstr "Centang yang dipilih" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "Menurun" + #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" msgid "Filter" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 2c0328d8a..5e5e8b54e 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1454,6 +1454,10 @@ msgstr "Cofnij" msgid "Abort" msgstr "Anuluj" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1463,6 +1467,10 @@ msgstr "Zaznacz wszystkie" msgid "Check selected" msgstr "Zaznacz wybrane" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "" + #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" msgid "Filter" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index ebc1e6709..1fdd1685e 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1365,6 +1365,10 @@ msgstr "" msgid "Abort" msgstr "" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1374,6 +1378,10 @@ msgstr "" msgid "Check selected" msgstr "" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "" + #: tmainform.michapterlistfilter.caption msgctxt "TMAINFORM.MICHAPTERLISTFILTER.CAPTION" msgid "Filter" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 9cf9e59c9..0bc987471 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1453,6 +1453,10 @@ msgstr "Desfazer" msgid "Abort" msgstr "Abortar" +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "" + #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" msgid "Check all" @@ -1462,6 +1466,10 @@ msgstr "Marca tudo" msgid "Check selected" msgstr "Marcar selecionado" +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "" + #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" msgid "Filter" From 85f2f63053828f75e344b4277627238e9746efb6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:01:40 +0800 Subject: [PATCH 1597/2794] improved spliturl and added includeprotocol, includeport parameters --- baseunits/httpsendthread.pas | 80 +++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 21794596e..b98760478 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -66,7 +66,8 @@ procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); function MaybeEncodeURL(const AValue: String): String; -procedure SplitURL(URL: String; out Host, Path: String); +procedure SplitURL(const AURL: String; var AHost, APath: String; + const AIncludeProtocol: Boolean = True; const AIncludePort: Boolean = True); const UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; @@ -103,7 +104,8 @@ function poschar(const c:char;const s:string;const offset:cardinal=1):integer; Result:=0; end; -procedure SplitURL(URL: String; out Host, Path: String); +procedure SplitURL(const AURL: String; var AHost, APath: String; + const AIncludeProtocol: Boolean; const AIncludePort: Boolean); procedure cleanuri(var u:string); begin @@ -112,57 +114,67 @@ procedure cleanuri(var u:string); end; var - prot,port: String; + iurl,prot,port: String; p,q: Integer; begin - Host:=''; - Path:=''; - URL:=Trim(URL); - if URL='' then Exit; + AHost:=''; + APath:=''; + iurl:=Trim(AURL); + if iurl='' then Exit; prot:=''; port:=''; - p:=poschar(':',URL); - if (p<>0) and (p<Length(URL)) and (URL[P+1]='/') then + p:=poschar(':',iurl); + if (p<>0) and (p<Length(iurl)) and (iurl[P+1]='/') then begin - prot:=Copy(URL,1,p-1); - Delete(URL,1,p); + prot:=Copy(iurl,1,p-1); + Delete(iurl,1,p); end; - p:=poschar(':',URL); + p:=poschar(':',iurl); q:=0; - if (p<>0) and (p<Length(URL)) and (URL[P+1] in ['0'..'9']) then + if (p<>0) and (p<Length(iurl)) and (iurl[P+1] in ['0'..'9']) then begin - for q:=p+1 to Length(URL) do - if not (URL[q] in ['0'..'9']) then Break; - if q=Length(URL) then Inc(q); - port:=Copy(URL,p+1,q-p-1); - delete(URL,p,q-p); + for q:=p+1 to Length(iurl) do + if not (iurl[q] in ['0'..'9']) then Break; + if q=Length(iurl) then Inc(q); + port:=Copy(iurl,p+1,q-p-1); + delete(iurl,p,q-p); end; - cleanuri(URL); - p:=poschar('.',URL); - if (p<>0) and (p>poschar('/',URL)) then p:=0; - if (p<>0) and (p<Length(URL)) then + cleanuri(iurl); + p:=poschar('.',iurl); + q:=poschar('/',iurl); + if (q<>0) and (p<>0) and (p>q) then p:=0; + if (p<>0) and (p<Length(iurl)) then begin - p:=poschar('/',URL,p); + p:=poschar('/',iurl,p); if p<>0 then begin - Host:=Copy(URL,1,p-1); - Delete(URL,1,p-1); - cleanuri(URL); + AHost:=Copy(iurl,1,p-1); + Delete(iurl,1,p-1); + cleanuri(iurl); end else begin - Host:=URL; - URL:=''; + AHost:=iurl; + iurl:=''; end; end; - if Host<>'' then + if (AHost='') and (iurl<>'') and ((prot<>'') or (port<>'')) then begin - if prot<>'' then Host:=prot+'://'+Host - else Host:='http://'+Host; - if port<>'' then Host:=Host+':'+port; + AHost:=iurl; + iurl:=''; end; - if URL='' then Exit; - Path:='/'+URL; + if AHost<>'' then + begin + if AIncludeProtocol then + begin + if prot<>'' then AHost:=prot+'://'+AHost + else AHost:='http://'+AHost; + end; + if AIncludePort and (port<>'') then + AHost:=AHost+':'+port; + end; + if iurl<>'' then + APath:='/'+iurl; end; function KeyVal(const AKey, AValue: String): TKeyValuePair; From 2ef9d11335ee310f954d33f514d47210ddad97b5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:02:29 +0800 Subject: [PATCH 1598/2794] websitemodules, improved locatemodule --- baseunits/WebsiteModules.pas | 42 ++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index fe41aa19b..c16447104 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -380,34 +380,28 @@ function TWebsiteModules.LocateModule(const AWebsite: String): Integer; end; function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; + + function PosModule(const s: String): Integer; + var + i: Integer; + begin + for i := 0 to FModuleList.Count - 1 do + if Pos(s, LowerCase(TModuleContainer(FModuleList[i]).RootURL)) <> 0 then + Exit(i); + Result := -1; + end; var - i: Integer; - h: String; + h, p: String; begin Result := -1; - if FModuleList.Count > 0 then + if FModuleList.Count = 0 then Exit; + h := LowerCase(AHost); + Result := PosModule(h); + if Result = -1 then begin - h := LowerCase(AHost); - for i := 0 to FModuleList.Count - 1 do - if Pos(h, LowerCase(TModuleContainer(FModuleList[i]).RootURL)) <> 0 then - begin - Result := i; - Break; - end; - if Result = -1 then - with TRegExpr.Create do - try - Expression := REGEX_HOST; - for i := 0 to FModuleList.Count - 1 do - if Pos(LowerCase(Replace(TModuleContainer(FModuleList[i]).RootURL, - '$2', True)), h) <> 0 then - begin - Result := i; - Break; - end; - finally - Free; - end; + SplitURL(h, h, p, False, False); + if h = '' then Exit; + Result := PosModule(h); end; end; From 2ebb92b98f0d1300529d8677a461a6984fbe7eda Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:03:08 +0800 Subject: [PATCH 1599/2794] websitemodules, added locatemangaid and corrected some codes --- baseunits/uBaseUnit.pas | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bc4ead16e..a962d1353 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -632,6 +632,7 @@ function CorrectFilePath(const APath: String): String; function CorrectURL(const URL: String): String; procedure CheckPath(const S: String); +function LocateMangaSiteID(const URL: String): Integer; function GetMangaSiteID(const Name: String): Integer; function GetMangaSiteName(const ID: Cardinal): String; function GetMangaSiteRoot(const Website: String): String; overload; @@ -1061,14 +1062,40 @@ procedure CheckPath(const S: String); end; end; +function LocateMangaSiteID(const URL: String): Integer; + + function PosMangaSite(const s: String): Integer; + var + i: Integer; + begin + for i := Low(WebsiteRoots) to High(WebsiteRoots) do + if Pos(s, LowerCase(WebsiteRoots[i, 1])) <> 0 then + Exit(i); + Result := -1; + end; + +var + h, p: String; +begin + Result := -1; + h := LowerCase(URL); + Result := PosMangaSite(h); + if Result = -1 then + begin + SplitURL(h, h, p, False, False); + if h = '' then Exit; + Result := PosMangaSite(h); + end; +end; + function GetMangaSiteID(const Name: String): Integer; var i: Integer; begin - Result := High(WebsiteRoots) + 1; for i := Low(WebsiteRoots) to High(WebsiteRoots) do if SameText(Name, WebsiteRoots[i, 0]) then Exit(i); + Result := -1; end; function GetMangaSiteName(const ID: Cardinal): String; @@ -1081,10 +1108,10 @@ function GetMangaSiteRoot(const Website: String): String; var i: Integer; begin - Result := ''; for i := Low(WebsiteRoots) to High(WebsiteRoots) do if Website = WebsiteRoots[i, 0] then Exit(WebsiteRoots[i, 1]); + Result := ''; end; function GetMangaSiteRoot(const MangaID: Cardinal): String; From 2b36c79bf2004321730219b5100e4877ce9e9f3b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:08:52 +0800 Subject: [PATCH 1600/2794] fixed parse url and locate website --- mangadownloader/forms/frmMain.pas | 53 ++++++++++--------------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d01a4e1be..8ac0bdd8b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5194,11 +5194,9 @@ procedure TMainForm.edSaveToButtonClick(Sender: TObject); procedure TMainForm.edURLButtonClick(Sender: TObject); var i: Integer; - webid: Cardinal; website, host, link: String; - regx: TRegExpr; begin btDownload.Enabled := False; btDownloadSplit.Enabled := btDownload.Enabled; @@ -5206,51 +5204,32 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); btReadOnline.Enabled := False; website := ''; - host := ''; - link := ''; - edURL.Text := FixURL(edURL.Text); - - regx := TRegExpr.Create; - try - regx.Expression := '^https?\://'; - if not (regx.Exec(edURL.Text)) then - edURL.Text := 'http://' + edURL.Text; + SplitURL(edURL.Text, host, link); - regx.Expression := REGEX_HOST; - if regx.Exec(edURL.Text) then + if (host <> '') and (link <> '') then + begin + host := LowerCase(host); + i := Modules.LocateModuleByHost(host); + if i <> -1 then begin - host := regx.Replace(edURL.Text, '$2', True); - link := regx.Replace(edURL.Text, '$4', True); - end; - - if (host <> '') and (link <> '') then + website := Modules.Module[i].Website; + edURL.Text := FillHost(Modules.Module[i].RootURL, link); + end + else begin - host := LowerCase(host); - i := Modules.LocateModuleByHost(host); - if i > -1 then + i := LocateMangaSiteID(host); + if i <> -1 then begin - website := Modules.Module[i].Website; - edURL.Text := FillHost(Modules.Module[i].RootURL, link); - end - else - begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(host, WebsiteRoots[i, 1]) > 0 then - begin - webid := i; - website := WebsiteRoots[i, 0]; - Break; - end; - if website <> '' then - edURL.Text := FillMangaSiteHost(webid, link); + website := WebsiteRoots[i, 0]; + edURL.Text := FillMangaSiteHost(i, link); end; end; - finally - regx.Free; end; if (website = '') or (link = '') then begin + tmAnimateMangaInfo.Enabled := False; + pbWait.Visible := False; MessageDlg('', RS_DlgURLNotSupport, mtInformation, [mbYes], 0); Exit; end; From 14ee1fb5c8b78545170899693284622d3f86ff7d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:16:01 +0800 Subject: [PATCH 1601/2794] clenup obsolete data --- baseunits/uBaseUnit.pas | 4 ---- 1 file changed, 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a962d1353..3f55a0371 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -347,8 +347,6 @@ interface ANIMEA_BROWSER = '/browse.html?page='; ANIMEA_SKIP = '?skip=1'; - OURMANGA_BROWSER = '/directory/'; - MANGA24H_BROWSER = '/manga/update/page/'; VNSHARING_BROWSER = '/DanhSach'; @@ -359,8 +357,6 @@ interface TRUYEN18_ROOT = 'http://www.truyen18.org'; TRUYEN18_BROWSER = '/moi-dang/danhsach'; - MANGATRADERS_BROWSER = '/directory/'; - TRUYENTRANHTUAN_BROWSER = '/danh-sach-truyen'; TURKCRAFT_BROWSER = '/'; From 0ab60db54b10e4e165b0bf0d6706348e6b0cc0bd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:25:51 +0800 Subject: [PATCH 1602/2794] chapterlist, auto scroll to the last if in ascending sort --- mangadownloader/forms/frmMain.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8ac0bdd8b..abc77a413 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4582,6 +4582,8 @@ procedure TMainForm.ShowInformation(const title, website, link: String); UpdateVtChapter; miChapterListHideDownloadedClick(nil); edFilterMangaInfoChaptersChange(nil); + if (clbChapterList.RootNodeCount <>) 0 and miChapterListAscending.Checked then + clbChapterList.FocusedNode := clbChapterList.GetLast(); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); btDownloadSplit.Enabled := btDownload.Enabled; From 9eabdc0db9b3637f0ea5621f929a4d20be377688 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 22:47:35 +0800 Subject: [PATCH 1603/2794] chapterlist, auto scroll to the last if in ascending sort --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index abc77a413..35a589177 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4582,7 +4582,7 @@ procedure TMainForm.ShowInformation(const title, website, link: String); UpdateVtChapter; miChapterListHideDownloadedClick(nil); edFilterMangaInfoChaptersChange(nil); - if (clbChapterList.RootNodeCount <>) 0 and miChapterListAscending.Checked then + if (clbChapterList.RootNodeCount <> 0) and miChapterListAscending.Checked then clbChapterList.FocusedNode := clbChapterList.GetLast(); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); From 13b0e42ace5a9c20da4000190b182d3d055cf49f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 23:26:56 +0800 Subject: [PATCH 1604/2794] fixed convert taskstatus to db, #500 --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a4225c208..28f8bbc29 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1649,7 +1649,7 @@ function TDownloadManager.ConvertToDB: Boolean; FDownloadsDB.Add(d, ReadBool(s, 'Enabled', True), i, - ReadInteger(s, 'TaskStatus', 0), + GetEnumValue(TypeInfo(TDownloadStatusType), ReadString(s, 'TaskStatus', GetEnumName(TypeInfo(TDownloadStatusType), 0))), ReadInteger(s, 'ChapterPtr', 0), ReadInteger(s, 'NumberOfPages', 0), ReadInteger(s, 'CurrentPage', 0), From c7eef78464d66653d9c595afb966dc9e32d8d09d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 2 Mar 2017 23:38:09 +0800 Subject: [PATCH 1605/2794] Bump version 0.9.96.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 46844b132..8bf4de1ad 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.96.0 (02-03-2017) +[+] Added option to sort chapter list in mangainfo +[*] Auto scroll chapter list to the bottom if sort is ascending +[*] Fixed convert old downloads data before 0.9.94.0 +[*] Various changes and bug fixed +Full changes: https://github.com/riderkick/FMD/compare/0.9.95.0...0.9.96.0 + 0.9.95.0 (29-02-2017) [*] Fixed various issue when terminating threads/closing app [*] Fixed updater diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 39d663184..ae901cd65 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="95"/> + <RevisionNr Value="96"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 10388066a..a005ec044 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.95.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.95.0/fmd_0.9.95.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.95.0/fmd_0.9.95.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.95.0/fmd_0.9.95.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.95.0/fmd_0.9.95.0_Win64.7z +VERSION=0.9.96.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.96.0/fmd_0.9.96.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.96.0/fmd_0.9.96.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.96.0/fmd_0.9.96.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.96.0/fmd_0.9.96.0_Win64.7z From ca1ff6a743ced9fd78a07c7628fc92a98975daf7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 13:01:47 +0800 Subject: [PATCH 1606/2794] cf, fixed break on thread terminate --- baseunits/httpsendthread.pas | 5 +++-- baseunits/modules/Cloudflare.pas | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index b98760478..91b21f706 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -468,9 +468,10 @@ function THTTPSendThread.GetCookies: String; function THTTPSendThread.ThreadTerminated: Boolean; begin - Result := False; if Assigned(FOwner) then - Result := FOwner.IsTerminated; + Result := FOwner.IsTerminated + else + Result := False; end; procedure THTTPSendThread.RemoveCookie(const CookieName: String); diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 4592bf9b3..c9e1cfdd7 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -123,8 +123,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B if st < MIN_WAIT_TIME then st := MIN_WAIT_TIME; sc := 0; while sc < st do begin - if AHTTP.ThreadTerminated then - Break; + if AHTTP.ThreadTerminated then Break; Inc(sc, 500); Sleep(500); end; @@ -140,6 +139,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B AHTTP.RetryCount := 0; end; if Result then Break; + if AHTTP.ThreadTerminated then Break; if (maxretry > -1) and (maxretry <= counter) then Break; AHTTP.Reset; AHTTP.GET(AURL); From baf2ad33abc6cd90408554067a2904539d2cd051 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 13:02:12 +0800 Subject: [PATCH 1607/2794] downloadsdb, added field id const --- baseunits/DownloadsDB.pas | 68 ++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas index 8d3c5ffbd..1fc8a4fc6 100644 --- a/baseunits/DownloadsDB.pas +++ b/baseunits/DownloadsDB.pas @@ -30,6 +30,30 @@ TDownloadsDB = class(TSQliteData) property AutoCommitCount: Integer read FAutoCommitCount write SetAutoCommitCount; end; +const + f_dlid = 0; + f_enabled = 1; + f_order = 2; + f_taskstatus = 3; + f_chapterptr = 4; + f_numberofpages = 5; + f_currentpage = 6; + f_website = 7; + f_link = 8; + f_title = 9; + f_status = 10; + f_progress = 11; + f_saveto = 12; + f_datetime = 13; + f_chapterslinks = 14; + f_chaptersnames = 15; + f_pagelinks = 16; + f_pagecontainerlinks = 17; + f_filenames = 18; + f_customfilenames = 19; + f_failedchapterlinks = 20; + f_failedchapternames = 21; + implementation { TDownloadsDB } @@ -115,29 +139,29 @@ function TDownloadsDB.Add(var Adlid: Integer; with Table do begin Append; - Fields[1].AsBoolean := Aenabled; - Fields[2].AsInteger := Aorder; - Fields[3].AsInteger := Ataskstatus; - Fields[4].AsInteger := Achapterptr; - Fields[5].AsInteger := Anumberofpages; - Fields[6].AsInteger := Acurrentpage; - Fields[7].AsString := Awebsite; - Fields[8].AsString := Alink; - Fields[9].AsString := Atitle; - Fields[10].AsString := Astatus; - Fields[11].AsString := Aprogress; - Fields[12].AsString := Asaveto; - Fields[13].AsDateTime := Adatetime; - Fields[14].AsString := Achapterslinks; - Fields[15].AsString := Achaptersnames; - Fields[16].AsString := Apagelinks; - Fields[17].AsString := Apagecontainerlinks; - Fields[18].AsString := Afilenames; - Fields[19].AsString := Acustomfilenames; - Fields[20].AsString := Afailedchapterslinks; - Fields[21].AsString := Afailedchaptersnames; + Fields[f_enabled ].AsBoolean := Aenabled; + Fields[f_order ].AsInteger := Aorder; + Fields[f_taskstatus ].AsInteger := Ataskstatus; + Fields[f_chapterptr ].AsInteger := Achapterptr; + Fields[f_numberofpages ].AsInteger := Anumberofpages; + Fields[f_currentpage ].AsInteger := Acurrentpage; + Fields[f_website ].AsString := Awebsite; + Fields[f_link ].AsString := Alink; + Fields[f_title ].AsString := Atitle; + Fields[f_status ].AsString := Astatus; + Fields[f_progress ].AsString := Aprogress; + Fields[f_saveto ].AsString := Asaveto; + Fields[f_datetime ].AsDateTime := Adatetime; + Fields[f_chapterslinks ].AsString := Achapterslinks; + Fields[f_chaptersnames ].AsString := Achaptersnames; + Fields[f_pagelinks ].AsString := Apagelinks; + Fields[f_pagecontainerlinks].AsString := Apagecontainerlinks; + Fields[f_filenames ].AsString := Afilenames; + Fields[f_customfilenames ].AsString := Acustomfilenames; + Fields[f_failedchapterlinks].AsString := Afailedchapterslinks; + Fields[f_failedchapternames].AsString := Afailedchaptersnames; Post; - Adlid := Fields[0].AsInteger; + Adlid := Fields[f_dlid].AsInteger; end; Result := True; Inc(FCommitCount); From 322afb5848d565615a00df46dc3dabec6b5b6954 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 13:02:39 +0800 Subject: [PATCH 1608/2794] downloadsmanager, use fields id on downloadsdb --- baseunits/uDownloadsManager.pas | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 28f8bbc29..79cd8a2b8 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1694,30 +1694,30 @@ procedure TDownloadManager.Restore; with Items.Last, FDownloadsDB.Table do begin Manager := Self; - DlId := Fields[0].AsInteger; - Enabled := Fields[1].AsBoolean; - Status := TDownloadStatusType(Fields[3].AsInteger); - CurrentDownloadChapterPtr := Fields[4].AsInteger; - PageNumber := Fields[5].AsInteger; - CurrentPageNumber := Fields[6].AsInteger; - Website := Fields[7].AsString; - DownloadInfo.Website := Fields[7].AsString; - DownloadInfo.Link := Fields[8].AsString; - DownloadInfo.Title := Fields[9].AsString; - DownloadInfo.Status := Fields[10].AsString; - DownloadInfo.Progress := Fields[11].AsString; + DlId := Fields[f_dlid].AsInteger; + Enabled := Fields[f_enabled].AsBoolean; + Status := TDownloadStatusType(Fields[f_taskstatus].AsInteger); + CurrentDownloadChapterPtr := Fields[f_chapterptr].AsInteger; + PageNumber := Fields[f_numberofpages].AsInteger; + CurrentPageNumber := Fields[f_currentpage].AsInteger; + Website := Fields[f_website].AsString; + DownloadInfo.Website := Website; + DownloadInfo.Link := Fields[f_link].AsString; + DownloadInfo.Title := Fields[f_title].AsString; + DownloadInfo.Status := Fields[f_status].AsString; + DownloadInfo.Progress := Fields[f_progress].AsString; if Pos('/', DownloadInfo.Progress) <> 0 then DownCounter := StrToIntDef(Trim(ExtractWord(1, DownloadInfo.Progress, ['/'])), 0); - DownloadInfo.SaveTo := Fields[12].AsString; - DownloadInfo.DateTime := Fields[13].AsDateTime; - ChapterLinks.Text := Fields[14].AsString; - ChapterName.Text := Fields[15].AsString; - PageLinks.Text := Fields[16].AsString; - PageContainerLinks.Text := Fields[17].AsString; - FileNames.Text := Fields[18].AsString; - CustomFileName := Fields[19].AsString; - FailedChapterLinks.Text := Fields[20].AsString; - FailedChapterName.Text := Fields[21].AsString; + DownloadInfo.SaveTo := Fields[f_saveto].AsString; + DownloadInfo.DateTime := Fields[f_datetime].AsDateTime; + ChapterLinks.Text := Fields[f_chapterslinks].AsString; + ChapterName.Text := Fields[f_chaptersnames].AsString; + PageLinks.Text := Fields[f_pagelinks].AsString; + PageContainerLinks.Text := Fields[f_pagecontainerlinks].AsString; + FileNames.Text := Fields[f_filenames].AsString; + CustomFileName := Fields[f_customfilenames].AsString; + FailedChapterLinks.Text := Fields[f_failedchapterlinks].AsString; + FailedChapterName.Text := Fields[f_failedchapternames].AsString; end; FDownloadsDB.Table.Next; end; From f5f57530d2ad95044a9116878014577a73c54e55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 13:47:22 +0800 Subject: [PATCH 1609/2794] baseunit, added sendlogexception --- baseunits/uBaseUnit.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3f55a0371..384c83edf 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -862,6 +862,7 @@ procedure fmdHibernate; // logger procedure SendLog(const AText: String); overload; inline; procedure SendLog(const AText, AValue: String); overload; inline; +procedure SendLogException(const AText: String; AException: Exception); inline; implementation @@ -4209,6 +4210,11 @@ procedure SendLog(const AText, AValue: String); Logger.Send(AText, AValue); end; +procedure SendLogException(const AText: String; AException: Exception); +begin + Logger.SendException(AText, AException); +end; + function HeaderByName(const AHeaders: TStrings; const AHeaderName: String): String; var i, p: Integer; From e1496bb235aa24904234e4725bb537fef346f4a9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 14:22:31 +0800 Subject: [PATCH 1610/2794] baseunit, rename quotedstrd and direct inline --- baseunits/uBaseUnit.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 384c83edf..5ec9ee11f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -699,8 +699,8 @@ function TitleCase(const S: string): string; function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; function StreamToString(const Stream: TStream): String; inline; function GetRightValue(const Name, s: String): String; -function QuotedStrd(const S: String): String; overload; inline; -function QuotedStrd(const S: Integer): String; overload; inline; +function QuotedStrD(const S: String): String; overload; inline; +function QuotedStrD(const S: Integer): String; overload; inline; function BracketStr(const S: String): String; inline; function RandomString(SLength: Integer; ONumber: Boolean = False; OSymbol: Boolean = False; OSpace: Boolean = False): String; @@ -1502,14 +1502,14 @@ function GetRightValue(const Name, s: String): String; Result := Trim(Copy(s, i + Length(Name), Length(s))); end; -function QuotedStrd(const S: String): String; +function QuotedStrD(const S: String): String; begin Result := AnsiQuotedStr(S, '"'); end; -function QuotedStrd(const S: Integer): String; +function QuotedStrD(const S: Integer): String; begin - Result := QuotedStrd(IntToStr(S)); + Result := AnsiQuotedStr(IntToStr(S), '"'); end; function BracketStr(const S: String): String; From aa48c3bb82f624cfb7b3e812c367ded5d33a9117 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 14:26:53 +0800 Subject: [PATCH 1611/2794] baseunit, added overload of quotedstr with integer param --- baseunits/uBaseUnit.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5ec9ee11f..e1a42bfd6 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -699,6 +699,7 @@ function TitleCase(const S: string): string; function StringReplaceBrackets(const S, OldPattern, NewPattern: String; Flags: TReplaceFlags): String; function StreamToString(const Stream: TStream): String; inline; function GetRightValue(const Name, s: String): String; +function QuotedStr(const S: Integer): String; overload; inline; function QuotedStrD(const S: String): String; overload; inline; function QuotedStrD(const S: Integer): String; overload; inline; function BracketStr(const S: String): String; inline; @@ -1502,6 +1503,11 @@ function GetRightValue(const Name, s: String): String; Result := Trim(Copy(s, i + Length(Name), Length(s))); end; +function QuotedStr(const S: Integer): String; +begin + Result := AnsiQuotedStr(IntToStr(S), ''''); +end; + function QuotedStrD(const S: String): String; begin Result := AnsiQuotedStr(S, '"'); From 0051a99a10be66cdc5e87209acd504141a1d4ef6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 14:42:06 +0800 Subject: [PATCH 1612/2794] sqlitedata, added overload of quotedstr with param boolean and tdatetime --- baseunits/SQLiteData.pas | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 9d02c353f..06c4ab516 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -76,8 +76,21 @@ TSQliteData = class property OnError: TExceptionEvent read FOnError write SetOnError; end; +function QuotedStr(const S: Boolean): String; overload; inline; +function QuotedStr(const S: TDateTime): String; overload; inline; + implementation +function QuotedStr(const S: Boolean): String; +begin + Result := AnsiQuotedStr(BoolToStr(S, '1', '0'), ''''); +end; + +function QuotedStr(const S: TDateTime): String; +begin + Result := AnsiQuotedStr(FormatDateTime('yyyy-mm-dd hh:mm:ss', S), ''''); +end; + { TSQliteData } procedure TSQliteData.DoOnError(E: Exception); From d24af86e7c4900881fd5b61302780c513d3d5bcf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 14:48:59 +0800 Subject: [PATCH 1613/2794] sqlitedata, added overload of quotedstr --- baseunits/SQLiteData.pas | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 06c4ab516..6d96f213e 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -76,11 +76,19 @@ TSQliteData = class property OnError: TExceptionEvent read FOnError write SetOnError; end; +function QuotedStr(const S: Integer): String; overload; inline; function QuotedStr(const S: Boolean): String; overload; inline; function QuotedStr(const S: TDateTime): String; overload; inline; +function QuotedStrD(const S: String): String; overload; inline; +function QuotedStrD(const S: Integer): String; overload; inline; implementation +function QuotedStr(const S: Integer): String; +begin + Result := AnsiQuotedStr(IntToStr(S), ''''); +end; + function QuotedStr(const S: Boolean): String; begin Result := AnsiQuotedStr(BoolToStr(S, '1', '0'), ''''); @@ -91,6 +99,16 @@ function QuotedStr(const S: TDateTime): String; Result := AnsiQuotedStr(FormatDateTime('yyyy-mm-dd hh:mm:ss', S), ''''); end; +function QuotedStrD(const S: String): String; +begin + Result := AnsiQuotedStr(S, '"'); +end; + +function QuotedStrD(const S: Integer): String; +begin + Result := AnsiQuotedStr(IntToStr(S), '"'); +end; + { TSQliteData } procedure TSQliteData.DoOnError(E: Exception); From 741de489fee988658a27aab6efe7344b57096fce Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 15:06:56 +0800 Subject: [PATCH 1614/2794] downloadedchaptersdb, escape quote --- baseunits/DownloadedChaptersDB.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/DownloadedChaptersDB.pas b/baseunits/DownloadedChaptersDB.pas index 6349a7c1d..84be7898b 100644 --- a/baseunits/DownloadedChaptersDB.pas +++ b/baseunits/DownloadedChaptersDB.pas @@ -88,10 +88,10 @@ constructor TDownloadedChaptersDB.Create; AutoApplyUpdates := True; TableName := 'downloadedchapters'; CreateParams := - 'websitelink VARCHAR(3000) NOT NULL PRIMARY KEY,' + - 'chapters TEXT'; + '"websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY,' + + '"chapters" TEXT'; FieldsParams := '"websitelink","chapters"'; - SelectParams := 'SELECT ' + FieldsParams + ' FROM "' + TableName + '"'; + SelectParams := 'SELECT ' + FieldsParams + ' FROM ' + QuotedStrD(TableName); end; destructor TDownloadedChaptersDB.Destroy; @@ -128,7 +128,7 @@ function TDownloadedChaptersDB.ImportFromIni(const AFilename: String): Boolean; i := 0; while i < dc.Count - 2 do begin - Chapters[dc[i]] := StringReplace(dc[i + 1], '!%~', LineEnding, [rfReplaceAll]); + Chapters[dc[i]] := GetParams(dc[i + 1]); Inc(i, 2); end; Result := True; From 59bca28945fbf5854f4de24c22b18d16c539c4fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 15:08:23 +0800 Subject: [PATCH 1615/2794] sqlitedata, fixed escape quote --- baseunits/SQLiteData.pas | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 6d96f213e..25efb72c0 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -180,8 +180,8 @@ function TSQliteData.CreateDB: Boolean; if not FConn.Connected then if not OpenDB then Exit; try - FConn.ExecuteDirect('DROP TABLE IF EXISTS "' + FTableName + '"'); - FConn.ExecuteDirect('CREATE TABLE "' + FTableName + '" (' + FCreateParams + ')'); + FConn.ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrD(FTableName)); + FConn.ExecuteDirect('CREATE TABLE ' + QuotedStrD(FTableName) + ' (' + FCreateParams + ')'); FTrans.Commit; Result := True; except @@ -204,11 +204,11 @@ procedure TSQliteData.DoConvertNewTable; if FQuery.Active then FQuery.Close; with FConn do begin - ExecuteDirect('DROP TABLE IF EXISTS "temp' + FTableName + '"'); - ExecuteDirect('CREATE TABLE "temp' + FTableName + '" (' + FCreateParams + ')'); - ExecuteDirect('INSERT INTO "temp' + FTableName + '" (' + FieldsParams + ') SELECT ' + FieldsParams + ' FROM "' + FTableName + '"'); - ExecuteDirect('DROP TABLE "' + FTableName + '"'); - ExecuteDirect('ALTER TABLE "temp' + FTableName + '" RENAME TO "' + FTableName + '"'); + ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrD('temp' + FTableName)); + ExecuteDirect('CREATE TABLE ' + QuotedStrD('temp' + FTableName) + ' (' + FCreateParams + ')'); + ExecuteDirect('INSERT INTO ' + QuotedStrD('temp' + FTableName) + ' (' + FieldsParams + ') SELECT ' + FieldsParams + ' FROM "' + FTableName + '"'); + ExecuteDirect('DROP TABLE ' + QuotedStrD(FTableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrD('temp' + FTableName) + ' RENAME TO ' + QuotedStrD(FTableName)); end; FTrans.Commit; if qactive <> FQuery.Active then @@ -310,7 +310,7 @@ function TSQliteData.OpenTable(const AGetRecordCount: Boolean): Boolean; if FSelectParams <> '' then FQuery.SQL.Text := FSelectParams else - FQuery.SQL.Text := 'SELECT * FROM "' + FTableName + '"'; + FQuery.SQL.Text := 'SELECT * FROM ' + QuotedStrD(FTableName); FQuery.Open; if AGetRecordCount then GetRecordCount From 26897024eff24bbaaf5b9cb95a419514256ed08d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 15:09:25 +0800 Subject: [PATCH 1616/2794] favoritesdb, added more log on error --- baseunits/FavoritesDB.pas | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index 07e4eff42..91d2b515f 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, SQLiteData; + Classes, SysUtils, SQLiteData, uBaseUnit; type @@ -79,6 +79,8 @@ function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, if FCommitCount >= FAutoCommitCount then Commit; except + on E: Exception do + SendLogException(ClassName + '.Add failed!', E); end; end; @@ -93,6 +95,8 @@ procedure TFavoritesDB.Delete(const AWebsite, ALink: String); if FCommitCount >= FAutoCommitCount then Commit; except + on E: Exception do + SendLogException(ClassName + '.Delete failed!', E); end; end; @@ -103,7 +107,11 @@ procedure TFavoritesDB.Commit; Transaction.Commit; FCommitCount := 0; except - Transaction.Rollback; + on E: Exception do + begin + Transaction.Rollback; + SendLogException(ClassName + '.Commit failed! Rollback!', E); + end; end; end; From 9c1a7634ff55c8b6cf65f76ab16f03199d1f3f71 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 15:10:17 +0800 Subject: [PATCH 1617/2794] downloadsdb, fixed update data, escape quote. closed #500 --- baseunits/DownloadsDB.pas | 58 ++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas index 1fc8a4fc6..c2070422d 100644 --- a/baseunits/DownloadsDB.pas +++ b/baseunits/DownloadsDB.pas @@ -96,7 +96,7 @@ constructor TDownloadsDB.Create(const AFilename: String); '"failedchapterlinks" TEXT,' + '"failedchapternames" TEXT'; FieldsParams := '"dlid","enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","failedchapterlinks","failedchapternames"'; - SelectParams := 'SELECT ' + FieldsParams + ' FROM "'+TableName+'" ORDER BY "order"'; + SelectParams := 'SELECT ' + FieldsParams + ' FROM '+QuotedStrD(TableName)+' ORDER BY "order"'; end; function TDownloadsDB.Add(var Adlid: Integer; @@ -113,28 +113,28 @@ function TDownloadsDB.Add(var Adlid: Integer; try if Adlid <> -1 then Connection.ExecuteDirect('UPDATE "downloads" SET ' + - '"enabled"="' + BoolToStr(Aenabled, '1', '0') + '",' + - '"order"="' + IntToStr(Aorder) + '",' + - '"taskstatus"="' + IntToStr(Ataskstatus) + '",' + - '"chapterptr"="' + IntToStr(Achapterptr) + '",' + - '"numberofpages"="' + IntToStr(Anumberofpages) + '",' + - '"currentpage"="' + IntToStr(Acurrentpage) + '",' + - '"website"="' + Awebsite + '",' + - '"link"="' + Alink + '",' + - '"title"="' + Atitle + '",' + - '"status"="' + Astatus + '",' + - '"progress"="' + Aprogress + '",' + - '"saveto"="' + Asaveto + '",' + - '"datetime"="' + FormatDateTime('yyyy-mm-dd hh:mm:ss', Adatetime) + '",' + - '"chapterslinks"="' + Achapterslinks + '",' + - '"chaptersnames"="' + Achaptersnames + '",' + - '"pagelinks"="' + Apagelinks + '",' + - '"pagecontainerlinks"="' + Apagecontainerlinks + '",' + - '"filenames"="' + Afilenames + '",' + - '"customfilenames"="' + Acustomfilenames + '",' + - '"failedchapterlinks"="' + Afailedchapterslinks + '",' + - '"failedchapternames"="' + Afailedchaptersnames + '"' + - ' WHERE "dlid"="' + IntToStr(Adlid) + '"') + '"enabled"=' + QuotedStr(Aenabled) + ', ' + + '"order"=' + QuotedStr(Aorder) + ', ' + + '"taskstatus"=' + QuotedStr(Ataskstatus) + ',' + + '"chapterptr"=' + QuotedStr(Achapterptr) + ',' + + '"numberofpages"=' + QuotedStr(Anumberofpages) + ',' + + '"currentpage"=' + QuotedStr(Acurrentpage) + ',' + + '"website"=' + QuotedStr(Awebsite) + ', ' + + '"link"=' + QuotedStr(Alink) + ', ' + + '"title"=' + QuotedStr(Atitle) + ', ' + + '"status"=' + QuotedStr(Astatus) + ', ' + + '"progress"=' + QuotedStr(Aprogress) + ', ' + + '"saveto"=' + QuotedStr(Asaveto) + ', ' + + '"datetime"=' + QuotedStr(Adatetime) + ', ' + + '"chapterslinks"=' + QuotedStr(Achapterslinks) + ', ' + + '"chaptersnames"=' + QuotedStr(Achaptersnames) + ', ' + + '"pagelinks"=' + QuotedStr(Apagelinks) + ', ' + + '"pagecontainerlinks"=' + QuotedStr(Apagecontainerlinks) + ', ' + + '"filenames"=' + QuotedStr(Afilenames) + ', ' + + '"customfilenames"=' + QuotedStr(Acustomfilenames) + ', ' + + '"failedchapterlinks"=' + QuotedStr(Afailedchapterslinks) + ', ' + + '"failedchapternames"=' + QuotedStr(Afailedchaptersnames) + + ' WHERE "dlid"=' + QuotedStr(Adlid)) else with Table do begin @@ -168,6 +168,8 @@ function TDownloadsDB.Add(var Adlid: Integer; if FCommitCount >= FAutoCommitCount then Commit; except + on E: Exception do + SendLogException(ClassName + '.Add failed!', E); end; end; @@ -177,11 +179,13 @@ procedure TDownloadsDB.Delete(const ADlId: Integer); if not Connection.Connected then Exit; try Connection.ExecuteDirect( - 'DELETE FROM "downloads" WHERE "dlid"="' + IntToStr(ADlId) + '"'); + 'DELETE FROM "downloads" WHERE "dlid"=' + QuotedStr(ADlId)); Inc(FCommitCount); if FCommitCount >= FAutoCommitCount then Commit; except + on E: Exception do + SendLogException(ClassName + '.Delete failed!', E); end; end; @@ -192,7 +196,11 @@ procedure TDownloadsDB.Commit; Transaction.Commit; FCommitCount := 0; except - Transaction.Rollback; + on E: Exception do + begin + Transaction.Rollback; + SendLogException(ClassName + '.Commit failed! Rollback!', E); + end; end; end; From 52590253d089470d91aec428d6539ce70931620e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 3 Mar 2017 15:27:26 +0800 Subject: [PATCH 1618/2794] Bump version 0.9.97.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8bf4de1ad..6f1a7e7f1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.97.0 (03-03-2017) +[*] Fixed save and restore downloads +[*] Various changes and bug fixed +Full changes: https://github.com/riderkick/FMD/compare/0.9.96.0...0.9.97.0 + 0.9.96.0 (02-03-2017) [+] Added option to sort chapter list in mangainfo [*] Auto scroll chapter list to the bottom if sort is ascending diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ae901cd65..3249cb242 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="96"/> + <RevisionNr Value="97"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index a005ec044..9051b48b8 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.96.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.96.0/fmd_0.9.96.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.96.0/fmd_0.9.96.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.96.0/fmd_0.9.96.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.96.0/fmd_0.9.96.0_Win64.7z +VERSION=0.9.97.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.97.0/fmd_0.9.97.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.97.0/fmd_0.9.97.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.97.0/fmd_0.9.97.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.97.0/fmd_0.9.97.0_Win64.7z From 16e97cbb0272487c02ea720fd0d2245561413155 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 08:56:06 +0800 Subject: [PATCH 1619/2794] fixed addedlink, link always truncated, #505 --- mangadownloader/forms/frmMain.pas | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 35a589177..d587e46be 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2146,7 +2146,6 @@ procedure TMainForm.btDownloadClick(Sender: TObject); Website:=mangaInfo.website; DownloadInfo.Website:=mangaInfo.website; DownloadInfo.Link:=mangaInfo.link; - SendLog('addedlink='+DownloadInfo.Link); DownloadInfo.Title:=mangaInfo.title; DownloadInfo.DateTime:=Now; DownloadInfo.SaveTo:=s; @@ -4475,7 +4474,6 @@ procedure TMainForm.FilledSaveTo; procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; const AMangaListPos: Integer); var - TURL: String; i: Integer; begin if (AURL = '') or (AWebsite = '') then Exit; @@ -4491,18 +4489,13 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; except end; - TURL := Trim(AURL); - // fix url + // set the UI i := Modules.LocateModule(AWebsite); - if i > -1 then - TURL := FillHost(Modules.Module[i].RootURL, TURL) + if i <> -1 then + edURL.Text := FillHost(Modules.Module[i].RootURL, AURL) else - TURL := FillMangaSiteHost(AWebsite, TURL); - - - // set the UI + edURL.Text := FillMangaSiteHost(AWebsite, AURL); pcMain.ActivePage := tsInformation; - edURL.Text := TURL; imCover.Picture.Assign(nil); rmInformation.Clear; rmInformation.Lines.Add(RS_Loading); @@ -4527,7 +4520,7 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; GetInfosThread.MangaListPos := AMangaListPos; GetInfosThread.Title := ATitle; GetInfosThread.Website := AWebsite; - GetInfosThread.Link := TURL; + GetInfosThread.Link := AURL; GetInfosThread.Start; end; @@ -5213,18 +5206,12 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); host := LowerCase(host); i := Modules.LocateModuleByHost(host); if i <> -1 then - begin - website := Modules.Module[i].Website; - edURL.Text := FillHost(Modules.Module[i].RootURL, link); - end + website := Modules.Module[i].Website else begin i := LocateMangaSiteID(host); if i <> -1 then - begin website := WebsiteRoots[i, 0]; - edURL.Text := FillMangaSiteHost(i, link); - end; end; end; From 36ebdb6ccb97ca29ab7094aec4949e7a64050bf7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 19:53:15 +0800 Subject: [PATCH 1620/2794] downloadsmanager, added ttaskcontainer.savetodb --- baseunits/uDownloadsManager.pas | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 79cd8a2b8..2aacb95e6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -157,6 +157,7 @@ TTaskContainer = class constructor Create; destructor Destroy; override; procedure IncReadCount(const ACount: Integer); + procedure SaveToDB; public Visible: Boolean; property Website: String read FWebsite write SetWebsite; @@ -1491,6 +1492,32 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); end; end; +procedure TTaskContainer.SaveToDB; +begin + Manager.FDownloadsDB.Add(DlId, + Enabled, + Manager.Items.IndexOf(Self), + Integer(Status), + CurrentDownloadChapterPtr, + PageNumber, + CurrentPageNumber, + Website, + DownloadInfo.Link, + DownloadInfo.Title, + DownloadInfo.Status, + DownloadInfo.Progress, + DownloadInfo.SaveTo, + DownloadInfo.DateTime, + ChapterLinks.Text, + ChapterName.Text, + PageLinks.Text, + PageContainerLinks.Text, + FileNames.Text, + CustomFileName, + FailedChapterLinks.Text, + FailedChapterName.Text); +end; + { TDownloadManager } procedure TDownloadManager.AddItemsActiveTask(const Item: TTaskContainer); From 10e0d3e1f85ea88d215546bb71ec0fdbde7b83a5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 19:55:16 +0800 Subject: [PATCH 1621/2794] downloadsdb, commit previous query if it is a new data. #505 --- baseunits/DownloadsDB.pas | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas index c2070422d..60379000a 100644 --- a/baseunits/DownloadsDB.pas +++ b/baseunits/DownloadsDB.pas @@ -112,6 +112,7 @@ function TDownloadsDB.Add(var Adlid: Integer; if not Connection.Connected then Exit; try if Adlid <> -1 then + begin Connection.ExecuteDirect('UPDATE "downloads" SET ' + '"enabled"=' + QuotedStr(Aenabled) + ', ' + '"order"=' + QuotedStr(Aorder) + ', ' + @@ -134,10 +135,17 @@ function TDownloadsDB.Add(var Adlid: Integer; '"customfilenames"=' + QuotedStr(Acustomfilenames) + ', ' + '"failedchapterlinks"=' + QuotedStr(Afailedchapterslinks) + ', ' + '"failedchapternames"=' + QuotedStr(Afailedchaptersnames) + - ' WHERE "dlid"=' + QuotedStr(Adlid)) + ' WHERE "dlid"=' + QuotedStr(Adlid)); + Inc(FCommitCount); + if FCommitCount >= FAutoCommitCount then + Commit; + Result := True; + end else with Table do begin + if FCommitCount <> 0 then + Commit; Append; Fields[f_enabled ].AsBoolean := Aenabled; Fields[f_order ].AsInteger := Aorder; @@ -162,11 +170,8 @@ function TDownloadsDB.Add(var Adlid: Integer; Fields[f_failedchapternames].AsString := Afailedchaptersnames; Post; Adlid := Fields[f_dlid].AsInteger; + Result := Adlid <> -1; end; - Result := True; - Inc(FCommitCount); - if FCommitCount >= FAutoCommitCount then - Commit; except on E: Exception do SendLogException(ClassName + '.Add failed!', E); @@ -194,7 +199,8 @@ procedure TDownloadsDB.Commit; if not Connection.Connected then Exit; try Transaction.Commit; - FCommitCount := 0; + if FCommitCount <> 0 then + FCommitCount := 0; except on E: Exception do begin From 99cf54191b34c310db11179962ea432dd682d005 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 20:18:45 +0800 Subject: [PATCH 1622/2794] baseunit, added sendlogerror and sendlogwarning --- baseunits/uBaseUnit.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e1a42bfd6..5018b42e5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -863,6 +863,8 @@ procedure fmdHibernate; // logger procedure SendLog(const AText: String); overload; inline; procedure SendLog(const AText, AValue: String); overload; inline; +procedure SendLogError(const AText: String); overload; inline; +procedure SendLogWarning(const AText: String); overload; inline; procedure SendLogException(const AText: String; AException: Exception); inline; implementation @@ -4216,6 +4218,16 @@ procedure SendLog(const AText, AValue: String); Logger.Send(AText, AValue); end; +procedure SendLogError(const AText: String); +begin + Logger.SendError(AText); +end; + +procedure SendLogWarning(const AText: String); +begin + Logger.SendWarning(AText); +end; + procedure SendLogException(const AText: String; AException: Exception); begin Logger.SendException(AText, AException); From 4335b57f47c3f72bd4e995caa3bf0460a10970f9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 20:19:21 +0800 Subject: [PATCH 1623/2794] downloadsdb, added log if add new data seems to be failed --- baseunits/DownloadsDB.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas index 60379000a..511161eda 100644 --- a/baseunits/DownloadsDB.pas +++ b/baseunits/DownloadsDB.pas @@ -171,6 +171,9 @@ function TDownloadsDB.Add(var Adlid: Integer; Post; Adlid := Fields[f_dlid].AsInteger; Result := Adlid <> -1; + if not Result then + SendLogWarning(ClassName + '.Add seems to be failed! ' + + Format('id=%d; ord=%d; title=%s; website=%s', [Adlid, Aorder, Atitle, Awebsite])); end; except on E: Exception do From 94e59ce4dd9966532ebfc6ec2e64a78edb73f33a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 21:02:10 +0800 Subject: [PATCH 1624/2794] sqlitedata, make open,close,closetable,refresh,save as virtual --- baseunits/SQLiteData.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/SQLiteData.pas b/baseunits/SQLiteData.pas index 25efb72c0..1f6efaec8 100644 --- a/baseunits/SQLiteData.pas +++ b/baseunits/SQLiteData.pas @@ -53,14 +53,14 @@ TSQliteData = class public constructor Create; destructor Destroy; override; - function Open(const AOpenTable: Boolean = True; const AGetRecordCount: Boolean = True): Boolean; + function Open(const AOpenTable: Boolean = True; const AGetRecordCount: Boolean = True): Boolean; virtual; function OpenTable(const AGetRecordCount: Boolean = True): Boolean; virtual; - procedure Close; - procedure CloseTable; - procedure Refresh(RecheckDataCount: Boolean = False); + procedure Close; virtual; + procedure CloseTable; virtual; + procedure Refresh(RecheckDataCount: Boolean = False); virtual; procedure Commit; virtual; procedure CommitRetaining; virtual; - procedure Save; + procedure Save; virtual; function Connected: Boolean; inline; property Connection: TSQLite3ConnectionH read FConn; property Transaction: TSQLTransaction read FTrans; From 8db24bc35eb41f349c879d15b2cf220258ede5cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 21:43:33 +0800 Subject: [PATCH 1625/2794] faviritesdb, added close, and commit on close --- baseunits/FavoritesDB.pas | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index 91d2b515f..ede97c833 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -22,6 +22,8 @@ TFavoritesDB = class(TSQliteData) ATitle, ACurrentChapter, ADownloadedChapterList, ASaveTo: String): Boolean; procedure Delete(const AWebsite, ALink: String); procedure Commit; override; + function Open: Boolean; + procedure Close; override; property AutoCommitCount: Integer read FAutoCommitCount write SetAutoCommitCount; end; @@ -102,6 +104,7 @@ procedure TFavoritesDB.Delete(const AWebsite, ALink: String); procedure TFavoritesDB.Commit; begin + if FCommitCount = 0 then Exit; if not Connection.Connected then Exit; try Transaction.Commit; @@ -115,5 +118,16 @@ procedure TFavoritesDB.Commit; end; end; +function TFavoritesDB.Open: Boolean; +begin + Result := inherited Open(False, False); +end; + +procedure TFavoritesDB.Close; +begin + Commit; + inherited Close; +end; + end. From 64e25cdfcf242823b987e21e614e41a60d2e1dcb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 21:44:19 +0800 Subject: [PATCH 1626/2794] favoritesmanager, check for record count before restore --- baseunits/uFavoritesManager.pas | 40 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 24cdc4318..1d859e89b 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -511,7 +511,7 @@ constructor TFavoriteManager.Create; isRunning := False; Items := TFavoriteContainers.Create;; FFavoritesDB := TFavoritesDB.Create(FAVORITESDB_FILE); - FFavoritesDB.Open(False, False); + FFavoritesDB.Open; ConvertToDB; Restore; end; @@ -952,22 +952,28 @@ procedure TFavoriteManager.Restore; if not FFavoritesDB.Connection.Connected then Exit; if FFavoritesDB.OpenTable(False) then try - FFavoritesDB.Table.First; - while not FFavoritesDB.Table.EOF do - begin - Items.Add(TFavoriteContainer.Create); - with Items.Last, FavoriteInfo, FFavoritesDB.Table do - begin - Manager := Self; - Status := STATUS_IDLE; - Website := Fields[2].AsString; - Link := Fields[3].AsString; - Title := Fields[4].AsString; - CurrentChapter := Fields[5].AsString; - DownloadedChapterList := Fields[6].AsString; - SaveTo := Fields[7].AsString; - end; - FFavoritesDB.Table.Next; + if FFavoritesDB.Table.RecordCount = 0 then Exit; + EnterCriticalsection(CS_Favorites); + try + FFavoritesDB.Table.First; + while not FFavoritesDB.Table.EOF do + begin + Items.Add(TFavoriteContainer.Create); + with Items.Last, FavoriteInfo, FFavoritesDB.Table do + begin + Manager := Self; + Status := STATUS_IDLE; + Website := Fields[2].AsString; + Link := Fields[3].AsString; + Title := Fields[4].AsString; + CurrentChapter := Fields[5].AsString; + DownloadedChapterList := Fields[6].AsString; + SaveTo := Fields[7].AsString; + end; + FFavoritesDB.Table.Next; + end; + finally + LeaveCriticalsection(CS_Favorites); end; finally FFavoritesDB.CloseTable; From 69a7604b03c4a0c70a82a0ddad508dcb26df43b2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 21:46:02 +0800 Subject: [PATCH 1627/2794] favoritesmanager, don't need to backup on destroy, let mainthread handle --- baseunits/uFavoritesManager.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 1d859e89b..4dcafbb32 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -520,7 +520,6 @@ destructor TFavoriteManager.Destroy; var i: Integer; begin - Backup; if Items.Count > 0 then begin StopChekForNewChapter; From b879362f2cc71ccf928646511fd97c18c3c35151 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 22:08:24 +0800 Subject: [PATCH 1628/2794] favoritesdb, commit onclose if there is uncommitted data --- baseunits/FavoritesDB.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index ede97c833..9da8e12a8 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -104,7 +104,6 @@ procedure TFavoritesDB.Delete(const AWebsite, ALink: String); procedure TFavoritesDB.Commit; begin - if FCommitCount = 0 then Exit; if not Connection.Connected then Exit; try Transaction.Commit; @@ -125,7 +124,8 @@ function TFavoritesDB.Open: Boolean; procedure TFavoritesDB.Close; begin - Commit; + if FCommitCount <> 0 then + Commit; inherited Close; end; From bd985a40b370b56af75fe8da3ba19df868fe4367 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 22:29:02 +0800 Subject: [PATCH 1629/2794] downloadsdb, insert new data directly with transaction. #505 --- baseunits/DownloadsDB.pas | 92 ++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas index 511161eda..7d08985e6 100644 --- a/baseunits/DownloadsDB.pas +++ b/baseunits/DownloadsDB.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, SQLiteData, uBaseUnit; + Classes, SysUtils, SQLiteData, uBaseUnit, sqlite3dyn; type @@ -18,6 +18,7 @@ TDownloadsDB = class(TSQliteData) procedure SetAutoCommitCount(AValue: Integer); public constructor Create(const AFilename: String); + function Open: Boolean; function Add(var Adlid: Integer; const Aenabled: Boolean; const Aorder, Ataskstatus, Achapterptr, Anumberofpages, Acurrentpage: Integer; @@ -27,6 +28,7 @@ TDownloadsDB = class(TSQliteData) Afailedchapterslinks, Afailedchaptersnames: String): Boolean; procedure Delete(const ADlId: Integer); procedure Commit; override; + procedure Close; override; property AutoCommitCount: Integer read FAutoCommitCount write SetAutoCommitCount; end; @@ -99,6 +101,11 @@ constructor TDownloadsDB.Create(const AFilename: String); SelectParams := 'SELECT ' + FieldsParams + ' FROM '+QuotedStrD(TableName)+' ORDER BY "order"'; end; +function TDownloadsDB.Open: Boolean; +begin + Result := inherited Open(False, False); +end; + function TDownloadsDB.Add(var Adlid: Integer; const Aenabled: Boolean; const Aorder, Ataskstatus, Achapterptr, Anumberofpages, Acurrentpage: Integer; @@ -108,11 +115,37 @@ function TDownloadsDB.Add(var Adlid: Integer; Afailedchapterslinks, Afailedchaptersnames: String): Boolean; begin Result := False; - if (AWebsite = '') or (ALink = '') then Exit; if not Connection.Connected then Exit; try - if Adlid <> -1 then + if Adlid = -1 then begin + Connection.ExecuteDirect('INSERT INTO "downloads" ("enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","failedchapterlinks","failedchapternames")' + + ' VALUES (' + + QuotedStr(Aenabled) + ', ' + + QuotedStr(Aorder) + ', ' + + QuotedStr(Ataskstatus) + ',' + + QuotedStr(Achapterptr) + ',' + + QuotedStr(Anumberofpages) + ',' + + QuotedStr(Acurrentpage) + ',' + + QuotedStr(Awebsite) + ', ' + + QuotedStr(Alink) + ', ' + + QuotedStr(Atitle) + ', ' + + QuotedStr(Astatus) + ', ' + + QuotedStr(Aprogress) + ', ' + + QuotedStr(Asaveto) + ', ' + + QuotedStr(Adatetime) + ', ' + + QuotedStr(Achapterslinks) + ', ' + + QuotedStr(Achaptersnames) + ', ' + + QuotedStr(Apagelinks) + ', ' + + QuotedStr(Apagecontainerlinks) + ', ' + + QuotedStr(Afilenames) + ', ' + + QuotedStr(Acustomfilenames) + ', ' + + QuotedStr(Afailedchapterslinks) + ', ' + + QuotedStr(Afailedchaptersnames) + + ')'); + Adlid := Connection.GetInsertID; + end + else Connection.ExecuteDirect('UPDATE "downloads" SET ' + '"enabled"=' + QuotedStr(Aenabled) + ', ' + '"order"=' + QuotedStr(Aorder) + ', ' + @@ -136,45 +169,10 @@ function TDownloadsDB.Add(var Adlid: Integer; '"failedchapterlinks"=' + QuotedStr(Afailedchapterslinks) + ', ' + '"failedchapternames"=' + QuotedStr(Afailedchaptersnames) + ' WHERE "dlid"=' + QuotedStr(Adlid)); - Inc(FCommitCount); - if FCommitCount >= FAutoCommitCount then - Commit; - Result := True; - end - else - with Table do - begin - if FCommitCount <> 0 then - Commit; - Append; - Fields[f_enabled ].AsBoolean := Aenabled; - Fields[f_order ].AsInteger := Aorder; - Fields[f_taskstatus ].AsInteger := Ataskstatus; - Fields[f_chapterptr ].AsInteger := Achapterptr; - Fields[f_numberofpages ].AsInteger := Anumberofpages; - Fields[f_currentpage ].AsInteger := Acurrentpage; - Fields[f_website ].AsString := Awebsite; - Fields[f_link ].AsString := Alink; - Fields[f_title ].AsString := Atitle; - Fields[f_status ].AsString := Astatus; - Fields[f_progress ].AsString := Aprogress; - Fields[f_saveto ].AsString := Asaveto; - Fields[f_datetime ].AsDateTime := Adatetime; - Fields[f_chapterslinks ].AsString := Achapterslinks; - Fields[f_chaptersnames ].AsString := Achaptersnames; - Fields[f_pagelinks ].AsString := Apagelinks; - Fields[f_pagecontainerlinks].AsString := Apagecontainerlinks; - Fields[f_filenames ].AsString := Afilenames; - Fields[f_customfilenames ].AsString := Acustomfilenames; - Fields[f_failedchapterlinks].AsString := Afailedchapterslinks; - Fields[f_failedchapternames].AsString := Afailedchaptersnames; - Post; - Adlid := Fields[f_dlid].AsInteger; - Result := Adlid <> -1; - if not Result then - SendLogWarning(ClassName + '.Add seems to be failed! ' + - Format('id=%d; ord=%d; title=%s; website=%s', [Adlid, Aorder, Atitle, Awebsite])); - end; + Inc(FCommitCount); + if FCommitCount >= FAutoCommitCount then + Commit; + Result := True; except on E: Exception do SendLogException(ClassName + '.Add failed!', E); @@ -202,8 +200,7 @@ procedure TDownloadsDB.Commit; if not Connection.Connected then Exit; try Transaction.Commit; - if FCommitCount <> 0 then - FCommitCount := 0; + FCommitCount := 0; except on E: Exception do begin @@ -213,5 +210,12 @@ procedure TDownloadsDB.Commit; end; end; +procedure TDownloadsDB.Close; +begin + if FCommitCount <> 0 then + Commit; + inherited Close; +end; + end. From 0b13bcaf1545d041cd3bdf37efede49b8e28e11c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 22:31:24 +0800 Subject: [PATCH 1630/2794] downloadsmanager. added order as savetodb parameter for faster and added check on restore. #505 --- baseunits/uDownloadsManager.pas | 96 ++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 2aacb95e6..c3a099502 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -157,7 +157,7 @@ TTaskContainer = class constructor Create; destructor Destroy; override; procedure IncReadCount(const ACount: Integer); - procedure SaveToDB; + procedure SaveToDB(const AOrder: Integer = -1); public Visible: Boolean; property Website: String read FWebsite write SetWebsite; @@ -1492,11 +1492,17 @@ procedure TTaskContainer.IncReadCount(const ACount: Integer); end; end; -procedure TTaskContainer.SaveToDB; +procedure TTaskContainer.SaveToDB(const AOrder: Integer); +var + i: Integer; begin + if AOrder = -1 then + i := Manager.Items.IndexOf(Self) + else + i := AOrder; Manager.FDownloadsDB.Add(DlId, Enabled, - Manager.Items.IndexOf(Self), + i, Integer(Status), CurrentDownloadChapterPtr, PageNumber, @@ -1638,7 +1644,7 @@ constructor TDownloadManager.Create; StatusCount[ds] := 0; DisabledCount := 0; FDownloadsDB := TDownloadsDB.Create(WORK_FILEDB); - FDownloadsDB.Open(True, False); + FDownloadsDB.Open; end; destructor TDownloadManager.Destroy; @@ -1708,49 +1714,53 @@ function TDownloadManager.ConvertToDB: Boolean; procedure TDownloadManager.Restore; begin - if not FDownloadsDB.Connected then Exit; - if not FDownloadsDB.Table.Active then Exit; + if not FDownloadsDB.Connection.Connected then Exit; ConvertToDB; - if FDownloadsDB.RecordCount = 0 then Exit; + if FDownloadsDB.OpenTable(False) then try + if FDownloadsDB.RecordCount = 0 then Exit; EnterCriticalsection(CS_Task); - FDownloadsDB.Table.First; - while not FDownloadsDB.Table.EOF do - begin - Items.Add(TTaskContainer.Create); - with Items.Last, FDownloadsDB.Table do - begin - Manager := Self; - DlId := Fields[f_dlid].AsInteger; - Enabled := Fields[f_enabled].AsBoolean; - Status := TDownloadStatusType(Fields[f_taskstatus].AsInteger); - CurrentDownloadChapterPtr := Fields[f_chapterptr].AsInteger; - PageNumber := Fields[f_numberofpages].AsInteger; - CurrentPageNumber := Fields[f_currentpage].AsInteger; - Website := Fields[f_website].AsString; - DownloadInfo.Website := Website; - DownloadInfo.Link := Fields[f_link].AsString; - DownloadInfo.Title := Fields[f_title].AsString; - DownloadInfo.Status := Fields[f_status].AsString; - DownloadInfo.Progress := Fields[f_progress].AsString; - if Pos('/', DownloadInfo.Progress) <> 0 then - DownCounter := StrToIntDef(Trim(ExtractWord(1, DownloadInfo.Progress, ['/'])), 0); - DownloadInfo.SaveTo := Fields[f_saveto].AsString; - DownloadInfo.DateTime := Fields[f_datetime].AsDateTime; - ChapterLinks.Text := Fields[f_chapterslinks].AsString; - ChapterName.Text := Fields[f_chaptersnames].AsString; - PageLinks.Text := Fields[f_pagelinks].AsString; - PageContainerLinks.Text := Fields[f_pagecontainerlinks].AsString; - FileNames.Text := Fields[f_filenames].AsString; - CustomFileName := Fields[f_customfilenames].AsString; - FailedChapterLinks.Text := Fields[f_failedchapterlinks].AsString; - FailedChapterName.Text := Fields[f_failedchapternames].AsString; + try + FDownloadsDB.Table.First; + while not FDownloadsDB.Table.EOF do + begin + Items.Add(TTaskContainer.Create); + with Items.Last, FDownloadsDB.Table do + begin + Manager := Self; + DlId := Fields[f_dlid].AsInteger; + Enabled := Fields[f_enabled].AsBoolean; + Status := TDownloadStatusType(Fields[f_taskstatus].AsInteger); + CurrentDownloadChapterPtr := Fields[f_chapterptr].AsInteger; + PageNumber := Fields[f_numberofpages].AsInteger; + CurrentPageNumber := Fields[f_currentpage].AsInteger; + Website := Fields[f_website].AsString; + DownloadInfo.Website := Website; + DownloadInfo.Link := Fields[f_link].AsString; + DownloadInfo.Title := Fields[f_title].AsString; + DownloadInfo.Status := Fields[f_status].AsString; + DownloadInfo.Progress := Fields[f_progress].AsString; + if Pos('/', DownloadInfo.Progress) <> 0 then + DownCounter := StrToIntDef(Trim(ExtractWord(1, DownloadInfo.Progress, ['/'])), 0); + DownloadInfo.SaveTo := Fields[f_saveto].AsString; + DownloadInfo.DateTime := Fields[f_datetime].AsDateTime; + ChapterLinks.Text := Fields[f_chapterslinks].AsString; + ChapterName.Text := Fields[f_chaptersnames].AsString; + PageLinks.Text := Fields[f_pagelinks].AsString; + PageContainerLinks.Text := Fields[f_pagecontainerlinks].AsString; + FileNames.Text := Fields[f_filenames].AsString; + CustomFileName := Fields[f_customfilenames].AsString; + FailedChapterLinks.Text := Fields[f_failedchapterlinks].AsString; + FailedChapterName.Text := Fields[f_failedchapternames].AsString; + end; + FDownloadsDB.Table.Next; + end; + finally + LeaveCriticalsection(CS_Task); end; - FDownloadsDB.Table.Next; + finally + FDownloadsDB.CloseTable; end; - finally - LeaveCriticalsection(CS_Task); - end; end; procedure TDownloadManager.Backup; @@ -1759,7 +1769,7 @@ procedure TDownloadManager.Backup; begin if isRunningBackup then Exit; if Items.Count = 0 then Exit; - if not FDownloadsDB.Connected then Exit; + if not FDownloadsDB.Connection.Connected then Exit; isRunningBackup := True; EnterCriticalSection(CS_Task); try From 9e5ceec0d40450b9bc73b13ef92aebdc379f558d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 22:37:09 +0800 Subject: [PATCH 1631/2794] frmmain, savetodb on new task. #505 --- mangadownloader/forms/frmMain.lfm | 4 ++-- mangadownloader/forms/frmMain.pas | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 1f665ada5..0974fe09a 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,13 +37,13 @@ object MainForm: TMainForm Height = 520 Top = 11 Width = 566 - ActivePage = tsInformation + ActivePage = tsDownload Align = alClient BorderSpacing.Top = 3 BorderSpacing.Right = 4 BorderSpacing.Bottom = 3 ParentFont = False - TabIndex = 1 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d587e46be..6478d3abe 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2056,7 +2056,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); links,names:TStrings; node:PVirtualNode; s:String; - c,p,r,i,j,k,l:Integer; + c,p,r,i,j,k,l, newdl:Integer; begin if clbChapterList.CheckedCount = 0 then Exit; @@ -2125,7 +2125,8 @@ procedure TMainForm.btDownloadClick(Sender: TObject); l:=links.Count-k else l:=p; - with DLManager[DLManager.AddTask] do + newdl := DLManager.AddTask; + with DLManager[newdl] do begin for j:=1 to l do begin @@ -2150,6 +2151,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); DownloadInfo.DateTime:=Now; DownloadInfo.SaveTo:=s; CurrentDownloadChapterPtr:=0; + SaveToDB(newdl); end; end; DLManager.DownloadedChapters.Chapters[mangaInfo.website+mangaInfo.link]:=links.Text; From 3d6d931e6c81c72d82478260f18d1bc95446e975 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 22:37:41 +0800 Subject: [PATCH 1632/2794] favoritesmanager, savetodb on auto new task. #505 --- baseunits/uFavoritesManager.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 4dcafbb32..b1d763ff4 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -612,6 +612,7 @@ procedure TFavoriteManager.ShowResult; LNCResult: TNewChapterResult = ncrCancel; newChapterListStr: String = ''; removeListStr: String = ''; + newdl: LongInt; begin if isDlgCounter then Exit; if (Self.DLManager = nil) and Assigned(MainForm.DLManager) then @@ -723,8 +724,8 @@ procedure TFavoriteManager.ShowResult; (NewMangaInfoChaptersPos.Count > 0) then try EnterCriticalSection(DLManager.CS_Task); - DLManager.Items.Add(TTaskContainer.Create); - with DLManager.Items.Last do + newdl := DLManager.Items.Add(TTaskContainer.Create); + with DLManager.Items[newdl] do begin Manager := DLManager; CurrentDownloadChapterPtr := 0; @@ -759,6 +760,7 @@ procedure TFavoriteManager.ShowResult; DownloadInfo.Status := Format('[%d/%d] %s',[0,ChapterLinks.Count,RS_Stopped]); Status := STATUS_STOP; end; + SaveToDB(newdl); // add to downloaded chapter list FavoriteInfo.downloadedChapterList := MergeCaseInsensitive([FavoriteInfo.DownloadedChapterList, chapterLinks.Text]); // add to downloaded chapter list in downloadmanager From effcad0bc940bf56a24dfb1d06279bab7a98eb94 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 4 Mar 2017 22:38:09 +0800 Subject: [PATCH 1633/2794] silentthread, savetodb on auto new task. #505 --- baseunits/uSilentThread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index e0d6dc8ac..8405e6e57 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -378,6 +378,7 @@ procedure TSilentThread.MainThreadAfterChecking; OptionChangeUnicodeCharacterStr); end; DLManager.Items[p].downloadInfo.SaveTo := FSavePath; + DLManager.Items[p].SaveToDB(p); UpdateVtDownload; DLManager.CheckAndActiveTask(False); From 70ed4e72f9e4faecb30eb95772e59d40be296eaa Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sun, 5 Mar 2017 00:12:53 +0530 Subject: [PATCH 1634/2794] added Mangazuki Added Mangazuki gonna touch up later on chapter list and verification. To do : 1. Fix Series Title 2. Check if it works correctly or not. --- baseunits/modules/MangaZuki.pas | 134 ++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 baseunits/modules/MangaZuki.pas diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas new file mode 100644 index 000000000..309e97f37 --- /dev/null +++ b/baseunits/modules/MangaZuki.pas @@ -0,0 +1,134 @@ +unit MangaZuki; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/series'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(SeparateRight( + XPathString('//ul[@class="pagination pagination-separated"]/li[last()]/a/@href'), '?page'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then + s += '?page=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="col-lg-3 col-sm-6"]//div[@class="caption"]//a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@class="img-circle"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="media-body"]/h1'); + summary := XPathString('//div[@class="media-body"]/h1/small'); + for v in XPath('//table[@id="chapter-list"]//tr/td/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(v.toString); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//div [@class="content-wrapper"]//img') do + PageLinks.Add(v.toNode.getAttribute('src')); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaZuki'; + RootURL := 'https://mangazuki.co'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From e0d83441aad0d89ce05bed55d6bc8199cf6292d4 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sun, 5 Mar 2017 00:41:18 +0530 Subject: [PATCH 1635/2794] Fixed MangaZuki fatal error. --- baseunits/modules/MangaZuki.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 309e97f37..9e7b39d92 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -94,6 +94,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var s: String; + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; From 084cfbd6939f26d9e86e6fa9d942cf74574c8219 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 5 Mar 2017 10:23:45 +0800 Subject: [PATCH 1636/2794] frmmain, cleanup --- mangadownloader/forms/frmMain.lfm | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0974fe09a..d5544e8a4 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4476,7 +4476,6 @@ object MainForm: TMainForm Align = alClient AutoExpand = True DefaultItemHeight = 18 - ExpandSignSize = 16 Images = IconList ReadOnly = True TabOrder = 0 From da9a7f457a1d59eb87efece7ea8b33c4e9a74860 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 14:40:32 +0800 Subject: [PATCH 1637/2794] favoritesdb, escape quotes. closed #511 --- baseunits/FavoritesDB.pas | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index 9da8e12a8..e4bb35dd4 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -55,7 +55,7 @@ constructor TFavoritesDB.Create(const AFilename: String); '"downloadedchapterlist" TEXT,' + '"saveto" TEXT'; FieldsParams := '"websitelink","order","website","link","title","currentchapter","downloadedchapterlist","saveto"'; - SelectParams := 'SELECT ' + FieldsParams + ' FROM "'+TableName+'" ORDER BY "order"'; + SelectParams := 'SELECT ' + FieldsParams + ' FROM ' + QuotedStrD(TableName) + ' ORDER BY "order"'; end; function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, @@ -67,15 +67,15 @@ function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, try Connection.ExecuteDirect('INSERT OR REPLACE INTO "favorites" (' + FieldsParams + - ') VALUES ("' + - LowerCase(AWebsite + ALink) + '","' + - IntToStr(AOrder) + '","' + - AWebsite + '","' + - ALink + '","' + - ATitle + '","' + - ACurrentChapter + '","' + - ADownloadedChapterList + '","' + - ASaveTo + '")'); + ') VALUES (' + + QuotedStr(LowerCase(AWebsite + ALink)) + ', ' + + QuotedStr(AOrder) + ', ' + + QuotedStr(AWebsite) + ', ' + + QuotedStr(ALink) + ', ' + + QuotedStr(ATitle) + ', ' + + QuotedStr(ACurrentChapter) + ', ' + + QuotedStr(ADownloadedChapterList) + ', ' + + QuotedStr(ASaveTo) + ')'); Result := True; Inc(FCommitCount); if FCommitCount >= FAutoCommitCount then @@ -92,7 +92,7 @@ procedure TFavoritesDB.Delete(const AWebsite, ALink: String); if not Connection.Connected then Exit; try Connection.ExecuteDirect( - 'DELETE FROM "favorites" WHERE "websitelink"="' + LowerCase(AWebsite + ALink) + '"'); + 'DELETE FROM "favorites" WHERE "websitelink"="\' + QuotedStr(LowerCase(AWebsite + ALink))); Inc(FCommitCount); if FCommitCount >= FAutoCommitCount then Commit; From dd0d1a16db20306c0a06cbc7f7b4da1f3bd7c542 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 15:10:02 +0800 Subject: [PATCH 1638/2794] frmmain, use integer, fpc alias --- mangadownloader/forms/frmMain.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6478d3abe..67998f3f4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4274,7 +4274,7 @@ procedure TMainForm.tvDownloadFilterRefresh(const ResourceChanged: Boolean); procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); var - ACurrentJDN: LongInt; + ACurrentJDN: Integer; procedure ShowTasks(S: TDownloadStatusTypes = []); var @@ -4297,9 +4297,9 @@ procedure TMainForm.vtDownloadUpdateFilters(const RefreshTree: Boolean); end; end; - procedure ShowTasksOnCertainDays(const L, H: LongInt); + procedure ShowTasksOnCertainDays(const L, H: Integer); var - jdn: LongInt; + jdn: Integer; xNode: PVirtualNode; begin xNode := vtDownload.GetFirst(); From a5ea490a4dcdc4b072066a99937c4e3bab0621e7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 15:21:53 +0800 Subject: [PATCH 1639/2794] favoritesmanager, savetodb on add, cleanup backup method --- baseunits/uFavoritesManager.pas | 51 ++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index b1d763ff4..935f23d2e 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -75,6 +75,7 @@ TFavoriteContainer = class Status: TFavoriteStatusType; constructor Create; destructor Destroy; override; + procedure SaveToDB(const AOrder: Integer = -1); property ModuleId: Integer read FModuleId; property Website: String read FWebsite write SetWebsite; end; @@ -191,6 +192,26 @@ destructor TFavoriteContainer.Destroy; inherited Destroy; end; +procedure TFavoriteContainer.SaveToDB(const AOrder: Integer); +var + i: Integer; +begin + if AOrder = -1 then + i := Manager.Items.IndexOf(Self) + else + i := AOrder; + with FavoriteInfo do + Manager.FFavoritesDB.Add( + i, + Website, + Link, + Title, + CurrentChapter, + DownloadedChapterList, + SaveTo + ); +end; + { TFavoriteThread } procedure TFavoriteThread.SyncStatus; @@ -830,12 +851,14 @@ function TFavoriteManager.IsMangaExistURL(const AWebsite, AURL: String): Boolean procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapterList, AWebsite, ASaveTo, ALink: String); +var + newfv: Integer; begin if IsMangaExist(ATitle, AWebsite) then Exit; EnterCriticalsection(CS_Favorites); try - Items.Add(TFavoriteContainer.Create); - with Items.Last do begin + newfv := Items.Add(TFavoriteContainer.Create); + with Items[newfv] do begin Manager := Self; Website := AWebsite; with FavoriteInfo do begin @@ -846,12 +869,10 @@ procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapter DownloadedChapterList := ADownloadedChapterList; end; Status := STATUS_IDLE; + SaveToDB(newfv); end; if not isRunning then - begin Sort(SortColumn); - Backup; - end; finally LeaveCriticalsection(CS_Favorites); end; @@ -987,18 +1008,14 @@ procedure TFavoriteManager.Backup; begin if not FFavoritesDB.Connection.Connected then Exit; if Items.Count > 0 then - for i := 0 to Items.Count - 1 do - with Items[i].FavoriteInfo do - FFavoritesDB.Add( - i, - Website, - Link, - Title, - CurrentChapter, - DownloadedChapterList, - SaveTo - ); - FFavoritesDB.Commit; + try + EnterCriticalsection(CS_Favorites); + for i := 0 to Items.Count - 1 do + Items[i].SaveToDB(i); + FFavoritesDB.Commit; + finally + LeaveCriticalsection(CS_Favorites); + end; end; procedure TFavoriteManager.AddToDownloadedChaptersList(const AWebsite, From efff371408a4a3af151360dc5690f3e50a0dc624 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 15:22:16 +0800 Subject: [PATCH 1640/2794] downloadsmanager, cleanup backup method --- baseunits/uDownloadsManager.pas | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c3a099502..ff6bfa44a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1770,35 +1770,11 @@ procedure TDownloadManager.Backup; if isRunningBackup then Exit; if Items.Count = 0 then Exit; if not FDownloadsDB.Connection.Connected then Exit; - isRunningBackup := True; - EnterCriticalSection(CS_Task); try + EnterCriticalSection(CS_Task); + isRunningBackup := True; for i := 0 to Items.Count - 1 do - with Items[i] do - begin - FDownloadsDB.Add(DlId, - Enabled, - i, - Integer(Status), - CurrentDownloadChapterPtr, - PageNumber, - CurrentPageNumber, - Website, - DownloadInfo.Link, - DownloadInfo.Title, - DownloadInfo.Status, - DownloadInfo.Progress, - DownloadInfo.SaveTo, - DownloadInfo.DateTime, - ChapterLinks.Text, - ChapterName.Text, - PageLinks.Text, - PageContainerLinks.Text, - FileNames.Text, - CustomFileName, - FailedChapterLinks.Text, - FailedChapterName.Text); - end; + Items[i].SaveToDB(i); FDownloadsDB.Commit; finally LeaveCriticalSection(CS_Task); From f0f7faa26f68fb2aec8b81ea70b5cb7075d45b1c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 15:26:10 +0800 Subject: [PATCH 1641/2794] favoritesmanager, fixed delete --- baseunits/FavoritesDB.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index e4bb35dd4..e16623b29 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -92,7 +92,7 @@ procedure TFavoritesDB.Delete(const AWebsite, ALink: String); if not Connection.Connected then Exit; try Connection.ExecuteDirect( - 'DELETE FROM "favorites" WHERE "websitelink"="\' + QuotedStr(LowerCase(AWebsite + ALink))); + 'DELETE FROM "favorites" WHERE "websitelink"=' + QuotedStr(LowerCase(AWebsite + ALink))); Inc(FCommitCount); if FCommitCount >= FAutoCommitCount then Commit; From 7e1222c0a0906d4fa06f8459ddbcb6eba4567ec7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 16:11:01 +0800 Subject: [PATCH 1642/2794] favoritesdb, added field enabled --- baseunits/FavoritesDB.pas | 47 +++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/baseunits/FavoritesDB.pas b/baseunits/FavoritesDB.pas index e16623b29..c46555ea5 100644 --- a/baseunits/FavoritesDB.pas +++ b/baseunits/FavoritesDB.pas @@ -13,13 +13,17 @@ interface TFavoritesDB = class(TSQliteData) private + FNFEnabled: Boolean; FCommitCount: Integer; FAutoCommitCount: Integer; procedure SetAutoCommitCount(AValue: Integer); + protected + function ConvertNewTableIF: Boolean; override; public constructor Create(const AFilename: String); - function Add(const AOrder: Integer; const AWebsite, ALink, - ATitle, ACurrentChapter, ADownloadedChapterList, ASaveTo: String): Boolean; + function Add(const AOrder: Integer; + const AEnabled: Boolean; + const AWebsite, ALink, ATitle, ACurrentChapter, ADownloadedChapterList, ASaveTo: String): Boolean; procedure Delete(const AWebsite, ALink: String); procedure Commit; override; function Open: Boolean; @@ -27,6 +31,17 @@ TFavoritesDB = class(TSQliteData) property AutoCommitCount: Integer read FAutoCommitCount write SetAutoCommitCount; end; +const + f_websitelink = 0; + f_order = 1; + f_enabled = 2; + f_website = 3; + f_link = 4; + f_title = 5; + f_currentchapter = 6; + f_downloadedchapterlist = 7; + f_saveto = 8; + implementation { TFavoritesDB } @@ -37,9 +52,16 @@ procedure TFavoritesDB.SetAutoCommitCount(AValue: Integer); FAutoCommitCount := AValue; end; +function TFavoritesDB.ConvertNewTableIF: Boolean; +begin + Result := Table.Fields.Count < 9; + FNFEnabled := Table.Fields.Count = 8; +end; + constructor TFavoritesDB.Create(const AFilename: String); begin inherited Create; + FNFEnabled := False; FCommitCount := 0; FAutoCommitCount := 500; Filename := AFilename; @@ -48,18 +70,20 @@ constructor TFavoritesDB.Create(const AFilename: String); CreateParams := '"websitelink" VARCHAR(3000) NOT NULL PRIMARY KEY,' + '"order" INTEGER,' + + '"enabled" BOOLEAN,' + '"website" TEXT,' + '"link" TEXT,' + '"title" TEXT,' + '"currentchapter" TEXT,' + '"downloadedchapterlist" TEXT,' + '"saveto" TEXT'; - FieldsParams := '"websitelink","order","website","link","title","currentchapter","downloadedchapterlist","saveto"'; - SelectParams := 'SELECT ' + FieldsParams + ' FROM ' + QuotedStrD(TableName) + ' ORDER BY "order"'; + FieldsParams := '"websitelink","order","enabled","website","link","title","currentchapter","downloadedchapterlist","saveto"'; + SelectParams := 'SELECT * FROM ' + QuotedStrD(TableName) + ' ORDER BY "order"'; end; -function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, - ACurrentChapter, ADownloadedChapterList, ASaveTo: String): Boolean; +function TFavoritesDB.Add(const AOrder: Integer; const AEnabled: Boolean; + const AWebsite, ALink, ATitle, ACurrentChapter, ADownloadedChapterList, + ASaveTo: String): Boolean; begin Result := False; if (AWebsite = '') or (ALink = '') then Exit; @@ -70,6 +94,7 @@ function TFavoritesDB.Add(const AOrder: Integer; const AWebsite, ALink, ATitle, ') VALUES (' + QuotedStr(LowerCase(AWebsite + ALink)) + ', ' + QuotedStr(AOrder) + ', ' + + QuotedStr(AEnabled) + ', ' + QuotedStr(AWebsite) + ', ' + QuotedStr(ALink) + ', ' + QuotedStr(ATitle) + ', ' + @@ -119,7 +144,15 @@ procedure TFavoritesDB.Commit; function TFavoritesDB.Open: Boolean; begin - Result := inherited Open(False, False); + Result := inherited Open(True, False); + if FNFEnabled then + try + Connection.ExecuteDirect('UPDATE "favorites" SET "enabled"=''1'''); + Transaction.Commit; + finally + FNFEnabled := False; + end; + CloseTable; end; procedure TFavoritesDB.Close; From cdd908e20775a3c18690d809d4ad4a4d6525615a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 16:18:10 +0800 Subject: [PATCH 1643/2794] favoritesmanager,added enabled field to tfavoritecontainer #510 --- baseunits/uDownloadsManager.pas | 2 +- baseunits/uFavoritesManager.pas | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ff6bfa44a..8a19c6ce0 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1501,7 +1501,7 @@ procedure TTaskContainer.SaveToDB(const AOrder: Integer); else i := AOrder; Manager.FDownloadsDB.Add(DlId, - Enabled, + FEnabled, i, Integer(Status), CurrentDownloadChapterPtr, diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 935f23d2e..b9e21656a 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -63,8 +63,10 @@ TFavoriteTask = class(THTTPThread) TFavoriteContainer = class private + FEnabled: Boolean; FModuleId: Integer; FWebsite: String; + procedure SetEnabled(AValue: Boolean); procedure SetWebsite(AValue: String); public FavoriteInfo: TFavoriteInfo; @@ -78,6 +80,7 @@ TFavoriteContainer = class procedure SaveToDB(const AOrder: Integer = -1); property ModuleId: Integer read FModuleId; property Website: String read FWebsite write SetWebsite; + property Enabled: Boolean read FEnabled write SetEnabled; end; TFavoriteContainers = TFPGList<TFavoriteContainer>; @@ -171,9 +174,16 @@ procedure TFavoriteContainer.SetWebsite(AValue: String); FModuleId := Modules.LocateModule(FavoriteInfo.Website); end; +procedure TFavoriteContainer.SetEnabled(AValue: Boolean); +begin + if FEnabled = AValue then Exit; + FEnabled := AValue; +end; + constructor TFavoriteContainer.Create; begin FModuleId := -1; + FEnabled := True; end; destructor TFavoriteContainer.Destroy; @@ -203,6 +213,7 @@ procedure TFavoriteContainer.SaveToDB(const AOrder: Integer); with FavoriteInfo do Manager.FFavoritesDB.Add( i, + FEnabled, Website, Link, Title, @@ -507,6 +518,7 @@ function TFavoriteManager.ConvertToDB: Boolean; s := IntToStr(i); FFavoritesDB.Add( i, + True, ReadString(s, 'Website', ''), ReadString(s, 'Link', ''), ReadString(s, 'Title', ''), @@ -983,14 +995,15 @@ procedure TFavoriteManager.Restore; Items.Add(TFavoriteContainer.Create); with Items.Last, FavoriteInfo, FFavoritesDB.Table do begin - Manager := Self; - Status := STATUS_IDLE; - Website := Fields[2].AsString; - Link := Fields[3].AsString; - Title := Fields[4].AsString; - CurrentChapter := Fields[5].AsString; - DownloadedChapterList := Fields[6].AsString; - SaveTo := Fields[7].AsString; + Manager := Self; + Status := STATUS_IDLE; + Enabled := Fields[f_enabled].AsBoolean; + Website := Fields[f_website].AsString; + Link := Fields[f_link].AsString; + Title := Fields[f_title].AsString; + CurrentChapter := Fields[f_currentchapter].AsString; + DownloadedChapterList := Fields[f_downloadedchapterlist].AsString; + SaveTo := Fields[f_saveto].AsString; end; FFavoritesDB.Table.Next; end; From b51aad5e58090944ccb41528db48e7630d2efbdf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 16:53:53 +0800 Subject: [PATCH 1644/2794] frmmain, added enable disable menu for favorites #510 --- mangadownloader/forms/frmMain.lfm | 11 +- mangadownloader/forms/frmMain.lrj | 2 + mangadownloader/forms/frmMain.pas | 149 ++++++++++++++----------- mangadownloader/languages/fmd.el_GR.po | 14 +++ mangadownloader/languages/fmd.en.po | 12 ++ mangadownloader/languages/fmd.es.po | 14 +++ mangadownloader/languages/fmd.id_ID.po | 12 ++ mangadownloader/languages/fmd.pl_PL.po | 14 +++ mangadownloader/languages/fmd.po | 12 ++ mangadownloader/languages/fmd.pt_BR.po | 14 +++ 10 files changed, 190 insertions(+), 64 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index d5544e8a4..59ad616ed 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -1975,6 +1975,7 @@ object MainForm: TMainForm OnDragDrop = vtFavoritesDragDrop OnFocusChanged = vtDownloadFocusChanged OnGetText = vtFavoritesGetText + OnPaintText = vtFavoritesPaintText OnGetImageIndex = vtFavoritesGetImageIndex OnGetHint = vtFavoritesGetHint OnHeaderClick = vtFavoritesHeaderClick @@ -4606,7 +4607,7 @@ object MainForm: TMainForm object miDownloadDisable: TMenuItem Caption = 'Disable' ShowAlwaysCheckable = True - OnClick = miDownloadDisableClick + OnClick = miDownloadEnableClick end object miDownloadDelete: TMenuItem Caption = 'Delete' @@ -4987,6 +4988,14 @@ object MainForm: TMainForm ImageIndex = 7 OnClick = miFavoritesStopCheckNewChapterClick end + object miFavoritesEnable: TMenuItem + Caption = 'Enable' + OnClick = miFavoritesEnableClick + end + object miFavoritesDisable: TMenuItem + Caption = 'Disable' + OnClick = miFavoritesEnableClick + end object miFavoritesViewInfos: TMenuItem Caption = 'View manga info' Bitmap.Data = { diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index b67f46544..861e0704e 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -268,6 +268,8 @@ {"hash":163579095,"name":"tmainform.michapterlistdescending.caption","sourcebytes":[68,101,115,99,101,110,100,105,110,103],"value":"Descending"}, {"hash":165778738,"name":"tmainform.mifavoriteschecknewchapter.caption","sourcebytes":[67,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Check for new chapter"}, {"hash":222540418,"name":"tmainform.mifavoritesstopchecknewchapter.caption","sourcebytes":[83,116,111,112,32,99,104,101,99,107,32,102,111,114,32,110,101,119,32,99,104,97,112,116,101,114],"value":"Stop check for new chapter"}, +{"hash":79984933,"name":"tmainform.mifavoritesenable.caption","sourcebytes":[69,110,97,98,108,101],"value":"Enable"}, +{"hash":185170277,"name":"tmainform.mifavoritesdisable.caption","sourcebytes":[68,105,115,97,98,108,101],"value":"Disable"}, {"hash":27371647,"name":"tmainform.mifavoritesviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, {"hash":29393692,"name":"tmainform.mifavoritesdownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, {"hash":78392485,"name":"tmainform.mifavoritesdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 67998f3f4..ff96645be 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -87,6 +87,8 @@ TMainForm = class(TForm) lbOptionMangaCustomRename: TLabel; MenuItem10: TMenuItem; MenuItem11: TMenuItem; + miFavoritesEnable: TMenuItem; + miFavoritesDisable: TMenuItem; miChapterListDescending: TMenuItem; miChapterListAscending: TMenuItem; miMangaListDelete: TMenuItem; @@ -450,6 +452,7 @@ TMainForm = class(TForm) procedure FormShow(Sender: TObject); procedure FormWindowStateChange(Sender: TObject); procedure miChapterListAscendingClick(Sender: TObject); + procedure miFavoritesEnableClick(Sender: TObject); procedure tmAnimateMangaInfoTimer(Sender: TObject); procedure tmCheckFavoritesTimer(Sender: TObject); procedure tmExitCommandTimer(Sender: TObject); @@ -467,7 +470,6 @@ TMainForm = class(TForm) procedure miAbortSilentThreadClick(Sender: TObject); procedure miChapterListFilterClick(Sender: TObject); procedure miChapterListHideDownloadedClick(Sender: TObject); - procedure miDownloadDisableClick(Sender: TObject); procedure miDownloadEnableClick(Sender: TObject); procedure miDownloadViewMangaInfoClick(Sender: TObject); procedure miChapterListHighlightClick(Sender: TObject); @@ -584,6 +586,9 @@ TMainForm = class(TForm) Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure vtFavoritesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure vtFavoritesPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); procedure vtMangaListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtMangaListColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState); @@ -1479,6 +1484,22 @@ procedure TMainForm.miChapterListAscendingClick(Sender: TObject); end; end; +procedure TMainForm.miFavoritesEnableClick(Sender: TObject); +var + Node: PVirtualNode; +begin + if vtFavorites.SelectedCount = 0 then Exit; + Node := vtFavorites.GetFirstSelected(); + while Assigned(Node) do + begin + if Sender = miFavoritesDisable then + FavoriteManager.StopChekForNewChapter(False, Node^.Index); + FavoriteManager[Node^.Index].Enabled := (Sender = miFavoritesEnable); + Node := vtFavorites.GetNextSelected(Node); + end; + UpdateVtFavorites; +end; + procedure TMainForm.tmAnimateMangaInfoTimer(Sender: TObject); begin gifWaiting.Update(pbWait.Canvas, gifWaitingRect); @@ -1725,21 +1746,6 @@ procedure TMainForm.miChapterListHideDownloadedClick(Sender: TObject); FilterChapterList(edFilterMangaInfoChapters.Text, miChapterListHideDownloaded.Checked); end; -procedure TMainForm.miDownloadDisableClick(Sender: TObject); -var - Node: PVirtualNode; -begin - if vtDownload.SelectedCount = 0 then Exit; - Node := vtDownload.GetFirstSelected(); - while Assigned(Node) do - begin - DLManager.DisableTask(Node^.Index); - Node := vtDownload.GetNextSelected(Node); - end; - UpdateVtDownload; - DLManager.CheckAndActiveTask(); -end; - procedure TMainForm.miDownloadEnableClick(Sender: TObject); var Node: PVirtualNode; @@ -1748,7 +1754,10 @@ procedure TMainForm.miDownloadEnableClick(Sender: TObject); Node := vtDownload.GetFirstSelected(); while Assigned(Node) do begin - DLManager.EnableTask(Node^.Index); + if Sender = miDownloadEnable then + DLManager.EnableTask(Node^.Index) + else + DLManager.DisableTask(Node^.Index); Node := vtDownload.GetNextSelected(Node); end; UpdateVtDownload; @@ -3410,34 +3419,39 @@ procedure TMainForm.pmEditURLPopup(Sender: TObject); end; procedure TMainForm.pmFavoritesPopup(Sender: TObject); +var + iCheck, + iStop, + iEnable, + iDisable: Boolean; - function SelectedStatusPresent(Stats: TFavoriteStatusTypes): Boolean; + procedure ScanFavs; var - xNode: PVirtualNode; + Node: PVirtualNode; begin - Result := False; - with FavoriteManager do + iCheck := False; + iStop := False; + iEnable := False; + iDisable := False; + Node := vtFavorites.GetFirstSelected(); + while Assigned(Node) do begin - if vtFavorites.SelectedCount > 0 then + if FavoriteManager[Node^.Index].Enabled then begin - Lock; - try - xNode := vtFavorites.GetFirstSelected; - repeat - if Assigned(xNode) then - begin - if FavoriteManager.Items[xNode^.Index].Status in Stats then - begin - Result := True; - Break; - end; - xNode := vtFavorites.GetNextSelected(xNode); - end; - until xNode = nil; - finally - LockRelease; + if not iDisable then + iDisable := True; + case FavoriteManager[Node^.Index].Status of + STATUS_IDLE : if not iCheck then iCheck := True; + STATUS_CHECK, + STATUS_CHECKING, + STATUS_CHECKED : if not iStop then iStop := True; end; - end; + end + else if not iEnable then + iEnable := True; + if iEnable and iDisable and iCheck and iStop then + Break; + Node := vtFavorites.GetNextSelected(Node); end; end; @@ -3446,37 +3460,38 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); begin miFavoritesViewInfos.Enabled := False; miFavoritesDownloadAll.Enabled := False; + miFavoritesEnable.Enabled := False; + miFavoritesDisable.Enabled := False; miFavoritesDelete.Enabled := False; miFavoritesChangeSaveTo.Enabled := False; miFavoritesOpenFolder.Enabled := False; miFavoritesOpenWith.Enabled := False; end else - if vtFavorites.SelectedCount = 1 then - begin - miFavoritesCheckNewChapter.Visible := SelectedStatusPresent([STATUS_IDLE]); - miFavoritesStopCheckNewChapter.Visible := - SelectedStatusPresent([STATUS_CHECK, STATUS_CHECKING]); - miFavoritesViewInfos.Enabled := True; - miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager.Items[ - vtFavorites.FocusedNode^.Index].FavoriteInfo.Link) <> ''); - miFavoritesDelete.Enabled := True; - miFavoritesChangeSaveTo.Enabled := True; - miFavoritesOpenFolder.Enabled := - DirectoryExistsUTF8(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); - miFavoritesOpenWith.Enabled := miFavoritesOpenFolder.Enabled; - end - else begin - miFavoritesCheckNewChapter.Visible := SelectedStatusPresent([STATUS_IDLE]); - miFavoritesStopCheckNewChapter.Visible := - SelectedStatusPresent([STATUS_CHECK, STATUS_CHECKING]); - miFavoritesViewInfos.Enabled := False; - miFavoritesDownloadAll.Enabled := True; - miFavoritesDelete.Enabled := True; - miFavoritesChangeSaveTo.Enabled := False; - miFavoritesOpenFolder.Enabled := False; - miFavoritesOpenWith.Enabled := False; + ScanFavs; + miFavoritesCheckNewChapter.Visible := iCheck; + miFavoritesStopCheckNewChapter.Visible := iStop; + miFavoritesEnable.Visible := iEnable; + miFavoritesDisable.Visible := iDisable; + if vtFavorites.SelectedCount = 1 then + begin + miFavoritesViewInfos.Enabled := True; + miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager[vtFavorites.FocusedNode^.Index].FavoriteInfo.Link) <> ''); + miFavoritesDelete.Enabled := True; + miFavoritesChangeSaveTo.Enabled := True; + miFavoritesOpenFolder.Enabled := DirectoryExistsUTF8(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); + miFavoritesOpenWith.Enabled := miFavoritesOpenFolder.Enabled; + end + else + begin + miFavoritesViewInfos.Enabled := False; + miFavoritesDownloadAll.Enabled := True; + miFavoritesDelete.Enabled := True; + miFavoritesChangeSaveTo.Enabled := False; + miFavoritesOpenFolder.Enabled := False; + miFavoritesOpenWith.Enabled := False; + end; end; if FavoriteManager.isRunning then begin @@ -4124,6 +4139,14 @@ procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; end; end; +procedure TMainForm.vtFavoritesPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + if not FavoriteManager[Node^.Index].Enabled then + TargetCanvas.Font.Color := TVirtualStringTree(Sender).Colors.DisabledColor; +end; + procedure TMainForm.vtMangaListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); begin //if (NOT isUpdating) then diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index a93d7cd1a..6723d89e0 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1571,10 +1571,12 @@ msgid "Task + Data + Favorite" msgstr "Εργασία + Δεδομένα + Αγαπημένο" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "Απενεργοποίηση" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "Ενεργοποίηση" @@ -1623,11 +1625,23 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "Διαγραφή" +#: tmainform.mifavoritesdisable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Απενεργοποίηση" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "Λήψη όλων" +#: tmainform.mifavoritesenable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Ενεργοποίηση" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d56ad6bc9..f254c3df3 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1516,10 +1516,12 @@ msgid "Task + Data + Favorite" msgstr "Task + Data + Favorite" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "Disable" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "Enable" @@ -1568,11 +1570,21 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "Delete" +#: tmainform.mifavoritesdisable.caption +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Disable" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "Download all" +#: tmainform.mifavoritesenable.caption +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Enable" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index baf120ca7..52cede1d6 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1496,10 +1496,12 @@ msgid "Task + Data + Favorite" msgstr "Tarea + Datos + Favorito" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "Deshabilitar" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "Habilitar" @@ -1548,11 +1550,23 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "Eliminar" +#: tmainform.mifavoritesdisable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Deshabilitar" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "Descargar Todo" +#: tmainform.mifavoritesenable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Habilitar" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index e00730db2..3f4ccf167 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1496,10 +1496,12 @@ msgid "Task + Data + Favorite" msgstr "Daftar, data dan kesukaan" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "Matikan" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "Nyalakan" @@ -1548,11 +1550,21 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "Hapus" +#: tmainform.mifavoritesdisable.caption +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Matikan" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "Unduh semua" +#: tmainform.mifavoritesenable.caption +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Nyalakan" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 5e5e8b54e..0c3d0a606 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1517,10 +1517,12 @@ msgid "Task + Data + Favorite" msgstr "Zadania + Data + Ulubione" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "Wyłącz" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "Włącz" @@ -1569,11 +1571,23 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "Usuń" +#: tmainform.mifavoritesdisable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Wyłącz" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "Pobierz wszystko" +#: tmainform.mifavoritesenable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Włącz" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 1fdd1685e..c7fb8cde1 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1427,10 +1427,12 @@ msgid "Task + Data + Favorite" msgstr "" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "" @@ -1479,11 +1481,21 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "" +#: tmainform.mifavoritesdisable.caption +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "" +#: tmainform.mifavoritesenable.caption +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 0bc987471..c72664567 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1516,10 +1516,12 @@ msgid "Task + Data + Favorite" msgstr "Tarefa + Dados + Favorito" #: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" msgid "Disable" msgstr "Desabilitar" #: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" msgid "Enable" msgstr "Habilitar" @@ -1568,11 +1570,23 @@ msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" msgid "Delete" msgstr "Apagar" +#: tmainform.mifavoritesdisable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Desabilitar" + #: tmainform.mifavoritesdownloadall.caption msgctxt "tmainform.mifavoritesdownloadall.caption" msgid "Download all" msgstr "Baixar tudo" +#: tmainform.mifavoritesenable.caption +#, fuzzy +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Habilitar" + #: tmainform.mifavoritesopenfolder.caption msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" msgid "Open Folder" From c466b55794b55c0deea77bb2b796d8eec4881a25 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 16:59:55 +0800 Subject: [PATCH 1645/2794] favoritesmanager, skip disable items for check #510 --- baseunits/uFavoritesManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index b9e21656a..5cdf79d5b 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -593,7 +593,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); try for i := 0 to Items.Count - 1 do with Items[i] do - if (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then + if FEnabled and (Status = STATUS_IDLE) and (Trim(FavoriteInfo.Link) <> '') then Status := STATUS_CHECK; finally LeaveCriticalsection(CS_Favorites); From a17ca9eb9315f779ae158dafd2266ba1cd3e1ef4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 17:16:24 +0800 Subject: [PATCH 1646/2794] fixed stop individual favorites check --- baseunits/uFavoritesManager.pas | 4 ++-- mangadownloader/forms/frmMain.pas | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 5cdf79d5b..aa13697c0 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -364,8 +364,8 @@ procedure TFavoriteTask.Checkout; try Modules.IncActiveConnectionCount(ModuleId); Status := STATUS_CHECKING; - Threads.Add(TFavoriteThread.Create); - Thread := Threads.Last; + Thread := TFavoriteThread.Create; + Threads.Add(Thread); Thread.Task := Self; Thread.Container := Manager.Items[i]; Thread.WorkId := i; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ff96645be..b590e22a2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1948,18 +1948,14 @@ procedure TMainForm.miFavoritesStopCheckNewChapterClick(Sender: TObject); var xNode: PVirtualNode; begin - if vtFavorites.SelectedCount > 0 then + if vtFavorites.SelectedCount = 0 then Exit; + xNode := vtFavorites.GetFirstSelected; + while Assigned(xNode) do begin - xNode := vtFavorites.GetFirstSelected; - repeat - if Assigned(xNode) then - begin - FavoriteManager.StopChekForNewChapter(False, xNode^.Index); - xNode := vtFavorites.GetNextSelected(xNode); - end; - until xNode = nil; - vtFavorites.Repaint; + FavoriteManager.StopChekForNewChapter(False, xNode^.Index); + xNode := vtFavorites.GetNextSelected(xNode); end; + UpdateVtFavorites; end; procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); From 309a07ec0d32a907df45d82d31d3efdd05e95597 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 6 Mar 2017 17:32:49 +0800 Subject: [PATCH 1647/2794] Bump version 0.9.98.0 --- changelog.txt | 10 ++++++++-- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6f1a7e7f1..0ecdd7123 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,16 +4,22 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.98.0 (06-03-2017) +[*] Fixed various issue with downloads and favorites +[*] Added enable/disable favorites +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.97.0...0.9.98.0 + 0.9.97.0 (03-03-2017) [*] Fixed save and restore downloads -[*] Various changes and bug fixed +[*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.96.0...0.9.97.0 0.9.96.0 (02-03-2017) [+] Added option to sort chapter list in mangainfo [*] Auto scroll chapter list to the bottom if sort is ascending [*] Fixed convert old downloads data before 0.9.94.0 -[*] Various changes and bug fixed +[*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.95.0...0.9.96.0 0.9.95.0 (29-02-2017) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 3249cb242..defad684f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="97"/> + <RevisionNr Value="98"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 9051b48b8..8024d63f1 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.97.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.97.0/fmd_0.9.97.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.97.0/fmd_0.9.97.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.97.0/fmd_0.9.97.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.97.0/fmd_0.9.97.0_Win64.7z +VERSION=0.9.98.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.98.0/fmd_0.9.98.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.98.0/fmd_0.9.98.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.98.0/fmd_0.9.98.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.98.0/fmd_0.9.98.0_Win64.7z From 5813a93044e51d5cc48e58760434bf10f181b989 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 14:55:37 +0800 Subject: [PATCH 1648/2794] favorites, change the enabled property instead of visible --- mangadownloader/forms/frmMain.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b590e22a2..a61a299cb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3466,10 +3466,10 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); else begin ScanFavs; - miFavoritesCheckNewChapter.Visible := iCheck; - miFavoritesStopCheckNewChapter.Visible := iStop; - miFavoritesEnable.Visible := iEnable; - miFavoritesDisable.Visible := iDisable; + miFavoritesCheckNewChapter.Enabled := iCheck; + miFavoritesStopCheckNewChapter.Enabled := iStop; + miFavoritesEnable.Enabled := iEnable; + miFavoritesDisable.Enabled := iDisable; if vtFavorites.SelectedCount = 1 then begin miFavoritesViewInfos.Enabled := True; From be7fa72373225a54963b3d8ec2ee909c644d4a9b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 15:29:28 +0800 Subject: [PATCH 1649/2794] move logger to program initialization --- mangadownloader/forms/frmMain.pas | 9 ++++----- mangadownloader/md.lpr | 32 ++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a61a299cb..84cda8330 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -785,6 +785,9 @@ TSearchDBThread = class(TThread) IsDlgCounter: Boolean = False; FUpdateURL: String; + // file logger + FileLogger: TFileChannel; + const CL_HLBlueMarks = $FDC594; CL_HLGreenMarks = $B8FFB8; @@ -893,9 +896,6 @@ implementation // ... UpdateStatusTextStyle: TTextStyle; - // file logger - FileLogger: TFileChannel; - {$ifdef windows} PrevWndProc: windows.WNDPROC; @@ -1081,8 +1081,6 @@ procedure TMainForm.FormCreate(Sender: TObject); PrevWndProc := windows.WNDPROC(windows.GetWindowLongPtr(Self.Handle, GWL_WNDPROC)); windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)); {$endif} - Logger.Enabled := False; - InitSimpleExceptionHandler; btAbortUpdateList.Parent := sbUpdateList; isRunDownloadFilter := False; isUpdating := False; @@ -4978,6 +4976,7 @@ procedure TMainForm.ApplyOptions; //misc frmCustomColor.Apply; SimpleException.SetLogFileName(edLogFileName.Text); + if ckEnableLogging.Checked and (not Logger.Enabled) then begin Logger.Enabled := True; diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index ce56b6a10..ec7804ee6 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -12,12 +12,15 @@ cthreads, {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, - uBaseUnit, frmMain; + Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, + SimpleException, Classes, windows, sysutils, frmMain, MultiLog, FileChannel; var CheckInstance: Boolean = True; AllowedToRun: Boolean = True; + EnableLogging: Boolean = False; + LogFileName: String = ''; + s: TStringList; {$R *.res} @@ -25,6 +28,13 @@ with TIniFile.Create(CONFIG_FILE) do try CheckInstance := ReadBool('general', 'OneInstanceOnly', True); + EnableLogging := ReadBool('logger', 'Enabled', False); + if EnableLogging then + begin + LogFileName := ReadString('logger', 'LogFileName', ''); + if LogFileName = '' then + LogFileName := ChangeFileExt(Application.ExeName, '.log'); + end; finally Free; end; @@ -52,9 +62,25 @@ DeleteFileUTF8(ChangeFileExt(Application.ExeName, '.trc')); SetHeapTraceOutput(ChangeFileExt(Application.ExeName, '.trc')); {$ENDIF DEBUGLEAKS} - sqlite3dyn.SQLiteDefaultLibrary := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; Application.Title := 'Free Manga Downloader'; RequireDerivedFormResource := True; + Logger.Enabled := False; + InitSimpleExceptionHandler; + if EnableLogging then + begin + Logger.Enabled := True; + frmMain.FileLogger := TFileChannel.Create(LogFileName, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); + Logger.Channels.Add(FileLogger); + Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); + s := TStringList.Create; + try + s.AddText(SimpleException.GetApplicationInfo); + Logger.Send('Application info', s); + finally + s.Free; + end; + end; + sqlite3dyn.SQLiteDefaultLibrary := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; Application.Initialize; Application.CreateForm(TMainForm, MainForm); Application.Run; From 526ecf5ac6b5559b5a056637c93f172d2af48d75 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 15:48:00 +0800 Subject: [PATCH 1650/2794] updated spanish translations by Mariolr93. closed #515 --- mangadownloader/languages/fmd.es.po | 315 +++++++++++++++++++++------- 1 file changed, 234 insertions(+), 81 deletions(-) diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 52cede1d6..43f79b299 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1,13 +1,13 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: FMD Español v2\n" +"Project-Id-Version: FMD Español 2.0.1\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" -"Language-Team: \n" +"Language-Team: Mariolr\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.11\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Last-Translator: Mariolr\n" "Language: es_419\n" @@ -101,8 +101,12 @@ msgid "Cannot connect to the server." msgstr "No se puede conectar con el servidor" #: frmmain.rs_dlgcannotgetmangainfo -msgid "Cannot get manga info. Please check your internet connection and try it again." -msgstr "No se puede obtener la información del manga. Por favor revisa tu conexión a internet e inténtalo de nuevo." +msgid "" +"Cannot get manga info. Please check your internet connection and try it " +"again." +msgstr "" +"No se puede obtener la información del manga. Por favor revisa tu conexión a " +"internet e inténtalo de nuevo." #: frmmain.rs_dlgdownloadcount msgid "Download count:" @@ -447,7 +451,7 @@ msgstr "Limpiar" #: tformlogger.ckstayontop.caption msgid "Stay on top" -msgstr "Permanecer Encima" +msgstr "Siempre Visible" #: tformlogger.lbloglimit.caption msgid "Log limit" @@ -507,7 +511,7 @@ msgstr "Descargar" #: tmainform.btdownloadsplit.hint msgctxt "tmainform.btdownloadsplit.hint" msgid "Split download" -msgstr "Dividir Descarga" +msgstr "Dividir descarga" #: tmainform.btfavoriteschecknewchapter.caption msgctxt "tmainform.btfavoriteschecknewchapter.caption" @@ -560,7 +564,7 @@ msgstr "Visitar mi blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -608,7 +612,8 @@ msgstr "Reemplazar todo Carácter Unicode con" #: tmainform.cboptionchangeunicodecharacter.hint msgid "Enable this if you have problem with unicode character in path." -msgstr "Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" +msgstr "" +"Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -653,7 +658,7 @@ msgstr "Remover Nombre del Manga del Capitulo" #: tmainform.cboptionshowballoonhint.caption msgid "Show balloon hint" -msgstr "" +msgstr "Mostrar Globo de Sugerencia" #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" @@ -670,18 +675,24 @@ msgstr "Mostrar Barra de Herramientas de Descargas" #: tmainform.cboptionshowdownloadtoolbardeleteall.caption msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "" +"Mostrar \"Eliminar Todas las Tareas Completadas\" en la Barra de " +"Herramientas de Descargas" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Salir de FMD" #: tmainform.cboptionupdatelistnomangainfo.caption -msgid "Don't load manga information when updating list (filter will be not work!)" -msgstr "No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro no Funcionará)" +msgid "" +"Don't load manga information when updating list (filter will be not work!)" +msgstr "" +"No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro " +"no Funcionará)" #: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption msgid "Remove duplicate local data when updating manga list" -msgstr "Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" +msgstr "" +"Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" #: tmainform.cboptionuseproxy.caption msgid "Use proxy" @@ -713,32 +724,52 @@ msgid "Action" msgstr "Acción" #: tmainform.ckfilteraction.hint -msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." -msgstr "Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de rápido movimiento." +msgid "" +"A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "" +"Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de " +"rápido movimiento." #: tmainform.ckfilteradult.caption msgid "Adult" msgstr "Adulto" #: tmainform.ckfilteradult.hint -msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." -msgstr "Contiene contenido que es apropiado solo para adultos. Los títulos en esta categoría pueden incluir prolongadas escenas de intensa violencia y/o contenido sexual gráfico o desnudez." +msgid "" +"Contains content that is suitable only for adults. Titles in this category " +"may include prolonged scenes of intense violence and/or graphic sexual " +"content and nudity." +msgstr "" +"Contiene contenido que es apropiado solo para adultos. Los títulos en esta " +"categoría pueden incluir prolongadas escenas de intensa violencia y/o " +"contenido sexual gráfico o desnudez." #: tmainform.ckfilteradventure.caption msgid "Adventure" msgstr "Aventura" #: tmainform.ckfilteradventure.hint -msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." -msgstr "Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio personal en este caso." +msgid "" +"If a character in the story goes on a trip or along that line, your best bet " +"is that it is an adventure manga. Otherwise, it's up to your personal " +"prejudice on this case." +msgstr "" +"Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor " +"apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio " +"personal en este caso." #: tmainform.ckfiltercomedy.caption msgid "Comedy" msgstr "Comedia" #: tmainform.ckfiltercomedy.hint -msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." -msgstr "Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o satírico y que usualmente contiene una feliz resolución del conflicto temático." +msgid "" +"A dramatic work that is light and often humorous or satirical in tone and " +"that usually contains a happy resolution of the thematic conflict." +msgstr "" +"Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o " +"satírico y que usualmente contiene una feliz resolución del conflicto " +"temático." #: tmainform.ckfilterdoujinshi.caption msgid "Doujinshi" @@ -753,24 +784,36 @@ msgid "Drama" msgstr "Drama" #: tmainform.ckfilterdrama.hint -msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." -msgstr "Un trabajo que pretende traer una respuesta emocional, tales como inculcar la tristeza o tensión." +msgid "" +"A work meant to bring on an emotional response, such as instilling sadness " +"or tension." +msgstr "" +"Un trabajo que pretende traer una respuesta emocional, tales como inculcar " +"la tristeza o tensión." #: tmainform.ckfilterechi.caption msgid "Ecchi" msgstr "Ecchi" #: tmainform.ckfilterechi.hint -msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." -msgstr "Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se refiere a fanservice puesto para atraer un cierto grupo de fans." +msgid "" +"Possibly the line between hentai and non-hentai, ecchi usually refers to " +"fanservice put in to attract a certain group of fans." +msgstr "" +"Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se " +"refiere a fanservice puesto para atraer un cierto grupo de fans." #: tmainform.ckfilterfantasy.caption msgid "Fantasy" msgstr "Fantasía" #: tmainform.ckfilterfantasy.hint -msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." -msgstr "Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y cuentos de hadas." +msgid "" +"Anything that involves, but not limited to, magic, dream world, and fairy " +"tales." +msgstr "" +"Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y " +"cuentos de hadas." #: tmainform.ckfiltergenderbender.caption msgid "Gender Bender" @@ -789,8 +832,14 @@ msgid "Harem" msgstr "Harem" #: tmainform.ckfilterharem.hint -msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." -msgstr "Una serie que envuelve un personaje masculino y muchos personajes femeninos (generalmente atraídos por el personaje masculino). Un Harem inverso es cuando los sexos se invierten." +msgid "" +"A series involving one male character and many female characters (usually " +"attracted to the male character). A Reverse Harem is when the genders are " +"reversed." +msgstr "" +"Una serie que envuelve un personaje masculino y muchos personajes femeninos " +"(generalmente atraídos por el personaje masculino). Un Harem inverso es " +"cuando los sexos se invierten." #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -815,16 +864,26 @@ msgid "Horror" msgstr "Horror" #: tmainform.ckfilterhorror.hint -msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." -msgstr "Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de terror y odio; el sentimiento inspirado por algo terrible e impactante." +msgid "" +"A painful emotion of fear, dread, and abhorrence; a shuddering with terror " +"and detestation; the feeling inspired by something frightful and shocking." +msgstr "" +"Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de " +"terror y odio; el sentimiento inspirado por algo terrible e impactante." #: tmainform.ckfilterjosei.caption msgid "Josei" msgstr "Josei" #: tmainform.ckfilterjosei.hint -msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." -msgstr "Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino equivalente al seinen. A diferencia de shoujo el romance es más realista y menos idealizado. La narración es más explícita y madura." +msgid "" +"Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. " +"Unlike shoujo the romance is more realistic and less idealized. The " +"storytelling is more explicit and mature." +msgstr "" +"Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino " +"equivalente al seinen. A diferencia de shoujo el romance es más realista y " +"menos idealizado. La narración es más explícita y madura." #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -839,24 +898,40 @@ msgid "Martial Arts" msgstr "Artes Marciales" #: tmainform.ckfiltermartialarts.hint -msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." -msgstr "Como su nombre indica, cualquier cosa relacionada artes marciales. Cualquiera de los diversos artes de combate o de autodefensa, como el aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." +msgid "" +"As the name suggests, anything martial arts related. Any of several arts of " +"combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, " +"fencing, and so on and so forth." +msgstr "" +"Como su nombre indica, cualquier cosa relacionada artes marciales. " +"Cualquiera de los diversos artes de combate o de autodefensa, como el " +"aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." #: tmainform.ckfiltermature.caption msgid "Mature" msgstr "Maduro" #: tmainform.ckfiltermature.hint -msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." -msgstr "Contiene temas que pueden ser demasiado extremos para las personas menores de 17. Los títulos de esta categoría pueden contener violencia intensa, sangre y gore, contenido sexual y/o lenguaje fuerte." +msgid "" +"Contains subject matter which may be too extreme for people under the age of " +"17. Titles in this category may contain intense violence, blood and gore, " +"sexual content and/or strong language." +msgstr "" +"Contiene temas que pueden ser demasiado extremos para las personas menores " +"de 17. Los títulos de esta categoría pueden contener violencia intensa, " +"sangre y gore, contenido sexual y/o lenguaje fuerte." #: tmainform.ckfiltermecha.caption msgid "Mecha" msgstr "Mecha" #: tmainform.ckfiltermecha.hint -msgid "A work involving and usually concentrating on all types of large robotic machines." -msgstr "Un trabajo que involucra y por lo general se concentra en todos los tipos de grandes máquinas robóticas." +msgid "" +"A work involving and usually concentrating on all types of large robotic " +"machines." +msgstr "" +"Un trabajo que involucra y por lo general se concentra en todos los tipos de " +"grandes máquinas robóticas." #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -873,24 +948,37 @@ msgid "Mystery" msgstr "Misterio" #: tmainform.ckfiltermystery.hint -msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." -msgstr "Por lo general, se produce un acontecimiento inexplicable, y el protagonista intenta averiguar cuál fue la causa." +msgid "" +"Usually an unexplained event occurs, and the main protagonist attempts to " +"find out what caused it." +msgstr "" +"Por lo general, se produce un acontecimiento inexplicable, y el protagonista " +"intenta averiguar cuál fue la causa." #: tmainform.ckfilterpsychological.caption msgid "Psychological" msgstr "Psicológico" #: tmainform.ckfilterpsychological.hint -msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." -msgstr "Por lo general lidia con la filosofía de un estado de la mente, en la mayoría de los casos que detallan la psicología anormal." +msgid "" +"Usually deals with the philosophy of a state of mind, in most cases " +"detailing abnormal psychology." +msgstr "" +"Por lo general lidia con la filosofía de un estado de la mente, en la " +"mayoría de los casos que detallan la psicología anormal." #: tmainform.ckfilterromance.caption msgid "Romance" msgstr "Romance" #: tmainform.ckfilterromance.hint -msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." -msgstr "Cualquier historia relacionada con el amor. Vamos a definir el amor como entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu propia imaginación de lo que es el amor." +msgid "" +"Any love related story. We will define love as between man and woman in this " +"case. Other than that, it is up to your own imagination of what love is." +msgstr "" +"Cualquier historia relacionada con el amor. Vamos a definir el amor como " +"entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu " +"propia imaginación de lo que es el amor." #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -898,23 +986,41 @@ msgstr "Vida Escolar" #: tmainform.ckfilterschoollife.hint msgid "Having a major setting of the story deal with some type of school." -msgstr "Tener un escenario importante de la historia ocupado con algún tipo de escuela." +msgstr "" +"Tener un escenario importante de la historia ocupado con algún tipo de " +"escuela." #: tmainform.ckfilterscifi.caption msgid "Sci-Fi" msgstr "Sci-Fi (Ciencia Ficción)" #: tmainform.ckfilterscifi.hint -msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." -msgstr "Abreviatura de ciencia ficción, estos trabajos implican giros en la tecnología y otros fenómenos relacionados con la ciencia y que sean contrarias o tramos del mundo científico de hoy en día." +msgid "" +"Short for science fiction, these works involve twists on technology and " +"other science related phenomena which are contrary or stretches of the " +"modern day scientific world." +msgstr "" +"Abreviatura de ciencia ficción, estos trabajos implican giros en la " +"tecnología y otros fenómenos relacionados con la ciencia y que sean " +"contrarias o tramos del mundo científico de hoy en día." #: tmainform.ckfilterseinen.caption msgid "Seinen" msgstr "Seinen" #: tmainform.ckfilterseinen.hint -msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." -msgstr "De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige específicamente a los varones adultos jóvenes en torno a las edades de 18 a 25 años son títulos seinen. Las historias en las obras seinen apelan a los estudiantes universitarios y los que están en el mundo laboral. Por lo general las líneas de la historia se ocupan de los problemas de la edad adulta." +msgid "" +"From Google: Seinen means 'young Man'. Manga and anime that specifically " +"targets young adult males around the ages of 18 to 25 are seinen titles. The " +"stories in seinen works appeal to university students and those in the " +"working world. Typically the story lines deal with the issues of adulthood." +msgstr "" +"De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige " +"específicamente a los varones adultos jóvenes en torno a las edades de 18 a " +"25 años son títulos seinen. Las historias en las obras seinen apelan a los " +"estudiantes universitarios y los que están en el mundo laboral. Por lo " +"general las líneas de la historia se ocupan de los problemas de la edad " +"adulta." #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -922,15 +1028,20 @@ msgstr "Shotacon" #: tmainform.ckfiltershotacon.hint msgid "Representing a sexual attraction to young or under-age boys." -msgstr "Representa una atracción sexual hacia los niños jóvenes o menores de edad." +msgstr "" +"Representa una atracción sexual hacia los niños jóvenes o menores de edad." #: tmainform.ckfiltershoujo.caption msgid "Shoujo" msgstr "Shoujo" #: tmainform.ckfiltershoujo.hint -msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." -msgstr "Un trabajo destinado y dirigido principalmente a las mujeres. Por lo general, implica mucho romance y fuerte desarrollo de los personajes." +msgid "" +"A work intended and primarily written for females. Usually involves a lot of " +"romance and strong character development." +msgstr "" +"Un trabajo destinado y dirigido principalmente a las mujeres. Por lo " +"general, implica mucho romance y fuerte desarrollo de los personajes." #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -938,8 +1049,12 @@ msgstr "Shoujo Ai" #: tmainform.ckfiltershoujoai.hint msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" -msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." -msgstr "A menudo sinónimo de yuri, esto puede ser considerado como algo menos extremo. \"Amor de Chicas\", por así decirlo." +msgid "" +"Often synonymous with yuri, this can be thought of as somewhat less extreme. " +"\"Girl''s Love\", so to speak." +msgstr "" +"A menudo sinónimo de yuri, esto puede ser considerado como algo menos " +"extremo. \"Amor de Chicas\", por así decirlo." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -947,48 +1062,77 @@ msgstr "Shounen" #: tmainform.ckfiltershounen.hint msgctxt "tmainform.ckfiltershounen.hint" -msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." -msgstr "Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos involucran generalmente la lucha y/o violencia." +msgid "" +"A work intended and primarily written for males. These works usually involve " +"fighting and/or violence." +msgstr "" +"Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos " +"involucran generalmente la lucha y/o violencia." #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" msgstr "Shounen Ai" #: tmainform.ckfiltershounenai.hint -msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" -msgstr "A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. \"Amor de Chicos\", por así decirlo" +msgid "" +"Often synonymous with yaoi, this can be thought of as somewhat less extreme. " +"\"Boy''s Love\", so to speak" +msgstr "" +"A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. " +"\"Amor de Chicos\", por así decirlo" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" msgstr "Recuentos de la Vida" #: tmainform.ckfiltersliceoflife.hint -msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." -msgstr "Como su nombre indica, este género representa el día a día tribulaciones de uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente en la vida real y no son a menudo -si todo el tiempo-, establecido en la presente línea de tiempo en un mundo que refleja al nuestro." +msgid "" +"As the name suggests, this genre represents day-to-day tribulations of one/" +"many character(s). These challenges/events could technically happen in real " +"life and are often -if not all the time- set in the present timeline in a " +"world that mirrors our own." +msgstr "" +"Como su nombre indica, este género representa el día a día tribulaciones de " +"uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente " +"en la vida real y no son a menudo -si todo el tiempo-, establecido en la " +"presente línea de tiempo en un mundo que refleja al nuestro." #: tmainform.ckfiltersmut.caption msgid "Smut" msgstr "Smut (Atrevido)" #: tmainform.ckfiltersmut.hint -msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." -msgstr "Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo que respecta a contenido sexual." +msgid "" +"Deals with series that are considered profane or offensive, particularly " +"with regards to sexual content." +msgstr "" +"Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo " +"que respecta a contenido sexual." #: tmainform.ckfiltersports.caption msgid "Sports" msgstr "Deportes" #: tmainform.ckfiltersports.hint -msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." -msgstr "Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos pocos." +msgid "" +"As the name suggests, anything sports related. Baseball, basketball, hockey, " +"soccer, golf, and racing just to name a few." +msgstr "" +"Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, " +"baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos " +"pocos." #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" msgstr "Sobrenatural" #: tmainform.ckfiltersupernatural.hint -msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." -msgstr "Por lo general, implica sorprendentes e inexplicables poderes y eventos que desafían las leyes de la física." +msgid "" +"Usually entails amazing and unexplained powers or events which defy the laws " +"of physics." +msgstr "" +"Por lo general, implica sorprendentes e inexplicables poderes y eventos que " +"desafían las leyes de la física." #: tmainform.ckfiltertragedy.caption msgid "Tragedy" @@ -1258,7 +1402,8 @@ msgstr "" "%NUMBERING% : Numeración\n" "\n" "Nota:\n" -"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o %NUMBERING%.\n" +"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o " +"%NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1349,8 +1494,11 @@ msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Numero de Tareas de Descargas al Mismo Tiempo (Max: 8)" #: tmainform.lboptionmaxretry.caption -msgid "Number of retry times if tasks have download problems (-1 = always retry)" -msgstr "Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre reintenta)" +msgid "" +"Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "" +"Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre " +"reintenta)" #: tmainform.lboptionmaxthread.caption msgid "Number of downloaded files per task at the same time (Max: 32)" @@ -1436,7 +1584,7 @@ msgstr "Abortar" #: tmainform.michapterlistascending.caption msgid "Ascending" -msgstr "" +msgstr "Ascendente" #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" @@ -1449,7 +1597,7 @@ msgstr "Marcar Selecionado" #: tmainform.michapterlistdescending.caption msgid "Descending" -msgstr "" +msgstr "Descendente" #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" @@ -1551,7 +1699,6 @@ msgid "Delete" msgstr "Eliminar" #: tmainform.mifavoritesdisable.caption -#, fuzzy msgctxt "tmainform.mifavoritesdisable.caption" msgid "Disable" msgstr "Deshabilitar" @@ -1562,7 +1709,6 @@ msgid "Download all" msgstr "Descargar Todo" #: tmainform.mifavoritesenable.caption -#, fuzzy msgctxt "tmainform.mifavoritesenable.caption" msgid "Enable" msgstr "Habilitar" @@ -1980,32 +2126,40 @@ msgid "Cookies" msgstr "Cookies" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgctxt "" +"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgctxt "" +"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0]." +"text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1]." +"text" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgctxt "" +"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" msgid "Value" msgstr "Valor" @@ -2189,4 +2343,3 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" - From b9c2f15cb04f6ca610691fabb2efc180e5c4c115 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 21:04:08 +0800 Subject: [PATCH 1651/2794] fixed spliturl. #513 --- baseunits/httpsendthread.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 91b21f706..a58f1f413 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -123,6 +123,14 @@ procedure cleanuri(var u:string); if iurl='' then Exit; prot:=''; port:=''; + if iurl[1] = '/' then + if Length(iurl) = 1 then Exit + else + if iurl[2] <> '/' then + begin + APath := iurl; + Exit; + end; p:=poschar(':',iurl); if (p<>0) and (p<Length(iurl)) and (iurl[P+1]='/') then begin From cfaabd1c57bd052d41360759553980f736977eba Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 21:10:10 +0800 Subject: [PATCH 1652/2794] removed hugemanga and manaesta, website is dead. #513 --- .../HugeManga/chapter_page_number.inc | 34 ------ baseunits/includes/HugeManga/image_url.inc | 32 ----- .../includes/HugeManga/manga_information.inc | 74 ----------- .../includes/HugeManga/names_and_links.inc | 38 ------ baseunits/includes/MangaEsta/image_url.inc | 43 ------- .../includes/MangaEsta/manga_information.inc | 115 ------------------ .../includes/MangaEsta/names_and_links.inc | 39 ------ baseunits/uBaseUnit.pas | 91 +++++++------- baseunits/uData.pas | 20 --- baseunits/uDownloadsManager.pas | 15 --- config/mangalist.ini | 2 +- 11 files changed, 42 insertions(+), 461 deletions(-) delete mode 100644 baseunits/includes/HugeManga/chapter_page_number.inc delete mode 100644 baseunits/includes/HugeManga/image_url.inc delete mode 100644 baseunits/includes/HugeManga/manga_information.inc delete mode 100644 baseunits/includes/HugeManga/names_and_links.inc delete mode 100644 baseunits/includes/MangaEsta/image_url.inc delete mode 100644 baseunits/includes/MangaEsta/manga_information.inc delete mode 100644 baseunits/includes/MangaEsta/names_and_links.inc diff --git a/baseunits/includes/HugeManga/chapter_page_number.inc b/baseunits/includes/HugeManga/chapter_page_number.inc deleted file mode 100644 index fe6f07355..000000000 --- a/baseunits/includes/HugeManga/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetHugeMangaPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.pageNumber := 0; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('</option>', parse[i]) > 0) then - begin - s := parse[i - 2]; - Task.Container.pageNumber := - StrToInt(GetVal(s, 'value')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/HugeManga/image_url.inc b/baseunits/includes/HugeManga/image_url.inc deleted file mode 100644 index 0dfe4565f..000000000 --- a/baseunits/includes/HugeManga/image_url.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetHugeMangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(HUGEMANGA_ID, URL) + '/' + IntToStr(WorkId + 1)); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := - EncodeURL(WebsiteRoots[HUGEMANGA_ID, 1] + HUGEMANGA_BROWSER + - GetVal(parse[i], 'src')); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/HugeManga/manga_information.inc b/baseunits/includes/HugeManga/manga_information.inc deleted file mode 100644 index a4257581a..000000000 --- a/baseunits/includes/HugeManga/manga_information.inc +++ /dev/null @@ -1,74 +0,0 @@ - function GetHugeMangaInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[HUGEMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(HUGEMANGA_ID, HUGEMANGA_BROWSER + AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i + 1], 'indonesia online - ', - ' - Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := '/' + AURL + '/' + GetVal(parse[i], 'value'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/HugeManga/names_and_links.inc b/baseunits/includes/HugeManga/names_and_links.inc deleted file mode 100644 index 45f089769..000000000 --- a/baseunits/includes/HugeManga/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function HugeMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[HUGEMANGA_ID, 1] + - HUGEMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('option value="', parse[i]) > 0) and - (Pos('value="0"', parse[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse[i + 1]); - ANames.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i], 'value'); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MangaEsta/image_url.inc b/baseunits/includes/MangaEsta/image_url.inc deleted file mode 100644 index fe5e28bf4..000000000 --- a/baseunits/includes/MangaEsta/image_url.inc +++ /dev/null @@ -1,43 +0,0 @@ - function GetMangaEstaImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAESTA_ID, URL); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('addpage(''', parse[i]) > 0 then - begin - s := parse[i]; - s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); - repeat - j := Pos('addpage(''', s); - if Pos('googleusercontent', s) > 0 then - Task.Container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ''','))) - else - Task.Container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ');'))); - Delete(s, Pos('addpage(''', s), 16); - j := Pos('addpage(''', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaEsta/manga_information.inc b/baseunits/includes/MangaEsta/manga_information.inc deleted file mode 100644 index 28156456d..000000000 --- a/baseunits/includes/MangaEsta/manga_information.inc +++ /dev/null @@ -1,115 +0,0 @@ - function GetMangaEstaInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAESTA_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAESTA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('imageanchor="1"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'href')); - - // get title - if (Pos('Nama :', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft(TrimRight(HTMLEntitiesFilter(parse[i + 2]))); - - if (not isExtractChapter) and (Pos('ONLINE INDONESIAN', parse[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('href="http://www.mangaesta.net/', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MANGAESTA_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class=''comments''', parse[i]) > 0) then - isExtractChapter := False; - - // get summary - if (Pos('Sinopsis :', parse[i]) <> 0) then - begin - j := i + 6; - while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 8 < parse.Count) and (Pos('Author :', parse[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - - // get artists - if (i + 1 < parse.Count) and (Pos('Artist :', parse[i]) <> 0) then - mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - - // get genres - if (Pos('Genre :', parse[i]) <> 0) then - begin - mangaInfo.genres := StringReplace( - StringFilter(TrimLeft(TrimRight(parse[i + 2]))), ' |', ',', [rfReplaceAll]); - mangaInfo.genres := StringReplace(mangaInfo.genres, '|', ',', [rfReplaceAll]); - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status :', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaEsta/names_and_links.inc b/baseunits/includes/MangaEsta/names_and_links.inc deleted file mode 100644 index 9f0fe0930..000000000 --- a/baseunits/includes/MangaEsta/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function MangaEstaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAESTA_ID, 1] + - MANGAESTA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="gallery-icon"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft( - TrimRight(GetVal(parse[i + 3], 'title')))); - ANames.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetVal(parse[i + 2], 'href'), - WebsiteRoots[MANGAESTA_ID, 1], '', []); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5018b42e5..93f8b6ceb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -243,49 +243,47 @@ interface BLOGTRUYEN_ID = 10; ESMANGAHERE_ID = 11; ANIMEEXTREMIST_ID = 12; - HUGEMANGA_ID = 13; - S2SCAN_ID = 14; - IMANHUA_ID = 15; - MABUNS_ID = 16; - MANGAESTA_ID = 17; - CENTRALDEMANGAS_ID = 18; - EGSCANS_ID = 19; - MANGAAR_ID = 20; - MANGAAE_ID = 21; - ANIMESTORY_ID = 22; - LECTUREENLIGNE_ID = 23; - SCANMANGA_ID = 24; - DM5_ID = 25; - KIVMANGA_ID = 26; - MEINMANGA_ID = 27; - MANGASPROJECT_ID = 28; - MANGAREADER_POR_ID = 29; - NINEMANGA_ID = 30; - NINEMANGA_ES_ID = 31; - NINEMANGA_CN_ID = 32; - NINEMANGA_RU_ID = 33; - NINEMANGA_DE_ID = 34; - NINEMANGA_IT_ID = 35; - NINEMANGA_BR_ID = 36; - JAPANSHIN_ID = 37; - CENTRUMMANGI_PL_ID = 38; - MANGALIB_PL_ID = 39; - ONEMANGA_ID = 40; - MANGATOWN_ID = 41; - MANGAOKU_ID = 42; - MYREADINGMANGAINFO_ID = 43; - IKOMIK_ID = 44; - NHENTAI_ID = 45; - MANGAMINT_ID = 46; - UNIXMANGA_ID = 47; - EXTREMEMANGAS_ID = 48; - MANGAHOST_ID = 49; - MANGAKU_ID = 50; - MANGAAT_ID = 51; - READMANGATODAY_ID = 52; - DYNASTYSCANS_ID = 53; - - WebsiteRoots: array [0..53] of array [0..1] of String = ( + S2SCAN_ID = 13; + IMANHUA_ID = 14; + MABUNS_ID = 15; + CENTRALDEMANGAS_ID = 16; + EGSCANS_ID = 17; + MANGAAR_ID = 18; + MANGAAE_ID = 19; + ANIMESTORY_ID = 20; + LECTUREENLIGNE_ID = 21; + SCANMANGA_ID = 22; + DM5_ID = 23; + KIVMANGA_ID = 24; + MEINMANGA_ID = 25; + MANGASPROJECT_ID = 26; + MANGAREADER_POR_ID = 27; + NINEMANGA_ID = 28; + NINEMANGA_ES_ID = 29; + NINEMANGA_CN_ID = 30; + NINEMANGA_RU_ID = 31; + NINEMANGA_DE_ID = 32; + NINEMANGA_IT_ID = 33; + NINEMANGA_BR_ID = 34; + JAPANSHIN_ID = 35; + CENTRUMMANGI_PL_ID = 36; + MANGALIB_PL_ID = 37; + ONEMANGA_ID = 38; + MANGATOWN_ID = 39; + MANGAOKU_ID = 40; + MYREADINGMANGAINFO_ID = 41; + IKOMIK_ID = 42; + NHENTAI_ID = 43; + MANGAMINT_ID = 44; + UNIXMANGA_ID = 45; + EXTREMEMANGAS_ID = 46; + MANGAHOST_ID = 47; + MANGAKU_ID = 48; + MANGAAT_ID = 49; + READMANGATODAY_ID = 50; + DYNASTYSCANS_ID = 51; + + WebsiteRoots: array [0..51] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -299,11 +297,9 @@ interface ('BlogTruyen', 'http://blogtruyen.com'), ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), - ('HugeManga', 'http://hugemanga.com'), ('S2Scans', 'http://reader.s2smanga.com'), ('imanhua', 'http://www.imanhua.com'), ('Mabuns', 'http://www.mabuns.web.id'), - ('MangaEsta', 'http://www.mangaesta.net'), ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), ('MangaAr', 'http://manga-ar.net'), @@ -374,14 +370,10 @@ interface ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; - HUGEMANGA_BROWSER = '/'; - IMANHUA_BROWSER = '/all.html'; MABUNS_BROWSER = '/p/mabuns-manga-list.html'; - MANGAESTA_BROWSER = '/p/manga-list.html'; - CENTRALDEMANGAS_BROWSER = '/mangas/list/*'; EGSCANS_BROWSER = '/'; @@ -1198,7 +1190,6 @@ function SitesWithoutInformation(const website: String): Boolean; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, TURKCRAFT_ID, - HUGEMANGA_ID, KIVMANGA_ID, MANGAOKU_ID, UNIXMANGA_ID diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1c5b2d211..12362f3da 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -946,10 +946,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/Mabuns/names_and_links.inc} - {$I includes/MangaEsta/names_and_links.inc} - - {$I includes/HugeManga/names_and_links.inc} - {$I includes/AnimeStory/names_and_links.inc} {$I includes/LectureEnLigne/names_and_links.inc} @@ -1074,12 +1070,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if WebsiteID = MABUNS_ID then Result := MabunsGetNamesAndLinks else - if WebsiteID = MANGAESTA_ID then - Result := MangaEstaGetNamesAndLinks - else - if WebsiteID = HUGEMANGA_ID then - Result := HugeMangaGetNamesAndLinks - else if WebsiteID = ANIMESTORY_ID then Result := AnimeStoryGetNamesAndLinks else @@ -1220,10 +1210,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/Mabuns/manga_information.inc} - {$I includes/MangaEsta/manga_information.inc} - - {$I includes/HugeManga/manga_information.inc} - {$I includes/AnimeStory/manga_information.inc} {$I includes/LectureEnLigne/manga_information.inc} @@ -1349,12 +1335,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if WebsiteID = MABUNS_ID then Result := GetMabunsInfoFromURL else - if WebsiteID = MANGAESTA_ID then - Result := GetMangaEstaInfoFromURL - else - if WebsiteID = HUGEMANGA_ID then - Result := GetHugeMangaInfoFromURL - else if WebsiteID = ANIMESTORY_ID then Result := GetAnimeStoryInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8a19c6ce0..3e01e5cb3 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -415,8 +415,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/EsMangaHere/chapter_page_number.inc} - {$I includes/HugeManga/chapter_page_number.inc} - {$I includes/Kivmanga/chapter_page_number.inc} {$I includes/MangaAe/chapter_page_number.inc} @@ -500,9 +498,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistPageNumber else - if Task.Container.MangaSiteID = HUGEMANGA_ID then - Result := GetHugeMangaPageNumber - else if Task.Container.MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryPageNumber else @@ -602,8 +597,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Fakku/image_url.inc} - {$I includes/HugeManga/image_url.inc} - {$I includes/Kivmanga/image_url.inc} {$I includes/Mabuns/image_url.inc} @@ -614,8 +607,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaAr/image_url.inc} - {$I includes/MangaEsta/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -697,12 +688,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MABUNS_ID then Result := GetMabunsImageURL else - if Task.Container.MangaSiteID = MANGAESTA_ID then - Result := GetMangaEstaImageURL - else - if Task.Container.MangaSiteID = HUGEMANGA_ID then - Result := GetHugeMangaImageURL - else if Task.Container.MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index bd8486e6a..8173570fd 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE -Indonesian=HugeManga,Komikid,Mabuns,Mangacan,MangaEsta,MangaIndo,MangaKu,PecintaKomik +Indonesian=Komikid,Mabuns,Mangacan,MangaIndo,MangaKu,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas From 2b8928a28f82c23a0b120a5cb5ef48cbbb21ee5a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 21:57:25 +0800 Subject: [PATCH 1653/2794] baseunit, overload sendlog with tstrings --- baseunits/uBaseUnit.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 93f8b6ceb..825fa4987 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -855,6 +855,7 @@ procedure fmdHibernate; // logger procedure SendLog(const AText: String); overload; inline; procedure SendLog(const AText, AValue: String); overload; inline; +procedure SendLog(const AText: String; AValue: TStrings); overload; inline; procedure SendLogError(const AText: String); overload; inline; procedure SendLogWarning(const AText: String); overload; inline; procedure SendLogException(const AText: String; AException: Exception); inline; @@ -4209,6 +4210,11 @@ procedure SendLog(const AText, AValue: String); Logger.Send(AText, AValue); end; +procedure SendLog(const AText: String; AValue: TStrings); +begin + Logger.Send(AText, AValue); +end; + procedure SendLogError(const AText: String); begin Logger.SendError(AText); From 550975cd2b32cc39a2fe33b55dd574211db7ee6c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 23:03:45 +0800 Subject: [PATCH 1654/2794] baseunit, overload sendlog with variant type --- baseunits/uBaseUnit.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 825fa4987..890e79914 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -18,10 +18,10 @@ interface {$else} UTF8Process, {$endif} - SysUtils, Classes, Graphics, lazutf8classes, LazFileUtils, - LConvEncoding, strutils, dateutils, base64, fpjson, jsonparser, jsonscanner, - FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, - MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, + SysUtils, Classes, Graphics, lazutf8classes, LazFileUtils, LConvEncoding, + strutils, dateutils, variants, base64, fpjson, jsonparser, jsonscanner, + FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, + synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit; const @@ -855,6 +855,7 @@ procedure fmdHibernate; // logger procedure SendLog(const AText: String); overload; inline; procedure SendLog(const AText, AValue: String); overload; inline; +procedure SendLog(const AText: String; const AValue: Variant); overload; inline; procedure SendLog(const AText: String; AValue: TStrings); overload; inline; procedure SendLogError(const AText: String); overload; inline; procedure SendLogWarning(const AText: String); overload; inline; @@ -4210,6 +4211,11 @@ procedure SendLog(const AText, AValue: String); Logger.Send(AText, AValue); end; +procedure SendLog(const AText: String; const AValue: Variant); +begin + Logger.Send(AText, VarToStr(AValue)); +end; + procedure SendLog(const AText: String; AValue: TStrings); begin Logger.Send(AText, AValue); From 1ab56bba1a0359d204bd76668aae093a6eb4a4df Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 23:05:08 +0800 Subject: [PATCH 1655/2794] httpsendthread, improved spliturl --- baseunits/httpsendthread.pas | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index a58f1f413..ad51d1ad2 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -136,8 +136,8 @@ procedure cleanuri(var u:string); begin prot:=Copy(iurl,1,p-1); Delete(iurl,1,p); + p:=poschar(':',iurl); end; - p:=poschar(':',iurl); q:=0; if (p<>0) and (p<Length(iurl)) and (iurl[P+1] in ['0'..'9']) then begin @@ -150,22 +150,23 @@ procedure cleanuri(var u:string); cleanuri(iurl); p:=poschar('.',iurl); q:=poschar('/',iurl); - if (q<>0) and (p<>0) and (p>q) then p:=0; if (p<>0) and (p<Length(iurl)) then - begin - p:=poschar('/',iurl,p); - if p<>0 then + if p<q then begin - AHost:=Copy(iurl,1,p-1); - Delete(iurl,1,p-1); + AHost:=Copy(iurl,1,q-1); + Delete(iurl,1,q-1); cleanuri(iurl); end else + if q=0 then begin - AHost:=iurl; - iurl:=''; + q:=poschar('.',iurl,p+1); + if (q<>0) and (q<Length(iurl)) then + begin + AHost:=iurl; + iurl:=''; + end; end; - end; if (AHost='') and (iurl<>'') and ((prot<>'') or (port<>'')) then begin AHost:=iurl; From 95667338ffdb4712bdc3e0444a514c6d01829d11 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 23:08:43 +0800 Subject: [PATCH 1656/2794] rewrite mangacan. closed #513 --- baseunits/modules/Mangacan.pas | 180 ++++++++------------------------- 1 file changed, 40 insertions(+), 140 deletions(-) diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index a5e98cd13..33bd5fdbe 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -6,171 +6,74 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - httpsendthread, HTMLUtil, synautil; + XQueryEngineHTML, httpsendthread; implementation -const - dirURL = '/daftar-komik-manga-bahasa-indonesia.html'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - Page := 1; -end; - function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - Parse: TStringList; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'a') and (Pos('baca-komik-', Parse[i]) <> 0) then - begin - ALinks.Add(GetVal(Parse[i], 'href')); - ANames.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - begin Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Parse := TStringList.Create; - try - if MangaInfo.GetPage(TObject(Parse), Module.RootURL + dirURL, 3) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/daftar-komik-manga-bahasa-indonesia.html') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFAll('//*[@class="series_col"]//li/a', ALinks, ANames); + finally + Free; end; - end; - finally - Parse.Free; end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - Parse: TStringList; - info: TMangaInfo; - - procedure ScanChapters(const StartIndex: Integer); - var - i: Integer; - s: String = ''; - begin - for i := StartIndex to Parse.Count - 1 do - begin - if GetTagName(Parse[i]) = '/table' then - Break - else - if GetTagName(parse[i]) = 'a' then - begin - s := GetVal(Parse[i], 'href'); - if (Length(s) > 7) and (RightStr(s, 7) = '-1.html') then - s := SeparateLeft(s, '-1.html') + '.html'; - info.chapterLinks.Add(s); - info.chapterName.Add(CommonStringFilter(Parse[i + 1])); - end; - end; - - //invert chapters - if info.chapterLinks.Count > 0 then - InvertStrings([info.chapterLinks, info.chapterName]); - end; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - begin - //title - if info.title = '' then - if Pos(' Indonesia|Baca ', Parse[i]) <> 0 then - info.title := CommonStringFilter(SeparateLeft(Parse[i], ' Indonesia|Baca ')); - - //chapters - if (GetTagName(Parse[i]) = 'table') and - (GetVal(Parse[i], 'class') = 'updates') then - begin - ScanChapters(i); - Break; - end; - end; - end; - begin Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, AURL); - Parse := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Parse)) then - begin - Result := INFORMATION_NOT_FOUND; - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := NO_ERROR; - ScanParse; - end; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + if title = '' then title := XPathString('//h1/substring-before(.," Indonesia|Baca")'); + XPathHREFAll('//table[@class="updates"]//td/a', chapterLinks, chapterName); + if chapterLinks.Count <> 0 then + chapterLinks.Text := StringReplace(chapterLinks.Text, '-1.htm', '.htm', [rfIgnoreCase, rfReplaceAll]); + InvertStrings([chapterLinks,chapterName]); + finally + Free; + end; end; - finally - Parse.Free; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - Parse: TStringList; - Container: TTaskContainer; - - procedure ScanParse; - var - i: Integer; - begin - for i := 0 to Parse.Count - 1 do - if (GetTagName(Parse[i]) = 'img') and - (GetVal(Parse[i], 'class') = 'picture') then - Container.PageLinks.Add(MaybeFillHost(Module.RootURL, GetVal(Parse[i], 'src'))); - end; - + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.Task.Container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Parse := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Parse), - FillHost(Module.RootURL, AURL), - Container.Manager.retryConnect) then + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then begin - ParseHTML(Parse.Text, Parse); - if Parse.Count > 0 then - begin - Result := True; - ScanParse; + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//*[@id="imgholder"]//img/@src') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toString)); + finally + Free; end; end; - finally - Parse.Free; end; end; @@ -179,10 +82,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Mangacan'; - RootURL := 'http://mangacanblog.com'; - SortedList := False; - InformationAvailable := False; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + RootURL := 'http://www.mangacanblog.com'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From 40e877ef6daa1a52628dedb141e65f544870847b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 7 Mar 2017 23:24:22 +0800 Subject: [PATCH 1657/2794] updatethread, fixed threads --- baseunits/uUpdateThread.pas | 79 +++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 62aa4a84e..16beba8af 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -27,7 +27,6 @@ TUpdateListThread = class(THTTPThread) manager: TUpdateListManagerThread; procedure Execute; override; - procedure DoTerminate; override; public title, link: String; constructor Create; @@ -59,7 +58,9 @@ TUpdateListManagerThread = class(THTTPThread) procedure GetInfo(const limit: Integer; const cs: TCheckStyleType); procedure DoTerminate; override; public - CS_AddInfoToData, CS_AddNamesAndLinks: TRTLCriticalSection; + CS_Threads, + CS_AddInfoToData, + CS_AddNamesAndLinks: TRTLCriticalSection; isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; mainDataProcess: TDBDataProcess; tempDataProcess: TDBDataProcess; @@ -69,7 +70,7 @@ TUpdateListManagerThread = class(THTTPThread) workPtr, directoryCount, // for fakku's doujinshi only directoryCount2, numberOfThreads, websitePtr: Integer; - threads: TFPList; + Threads: TFPList; SortedList, NoMangaInfo: Boolean; constructor Create; destructor Destroy; override; @@ -106,6 +107,13 @@ constructor TUpdateListThread.Create; destructor TUpdateListThread.Destroy; begin + Modules.DecActiveConnectionCount(manager.ModuleId); + EnterCriticalsection(manager.CS_Threads); + try + manager.Threads.Remove(Self); + finally + LeaveCriticalsection(manager.CS_Threads); + end; if Assigned(Info) then Info.Free; inherited Destroy; @@ -250,18 +258,6 @@ procedure TUpdateListThread.Execute; end; end; -procedure TUpdateListThread.DoTerminate; -begin - LockCreateConnection; - try - Modules.DecActiveConnectionCount(manager.ModuleId); - manager.threads.Remove(Self); - finally - UnlockCreateConnection - end; - inherited DoTerminate; -end; - { TUpdateListManagerThread } procedure TUpdateListManagerThread.MainThreadStatusRepaint; @@ -331,6 +327,7 @@ procedure TUpdateListManagerThread.ExtractFile; constructor TUpdateListManagerThread.Create; begin inherited Create(True); + InitCriticalSection(CS_Threads); InitCriticalSection(CS_AddInfoToData); InitCriticalSection(CS_AddNamesAndLinks); FreeOnTerminate := True; @@ -340,7 +337,7 @@ constructor TUpdateListManagerThread.Create; mainDataProcess := TDBDataProcess.Create; tempDataProcess := TDBDataProcess.Create; - threads := TFPList.Create; + Threads := TFPList.Create; SortedList := False; NoMangaInfo := False; ModuleId := -1; @@ -360,10 +357,11 @@ destructor TUpdateListManagerThread.Destroy; DeleteDBDataProcess(twebsitetemp); mainDataProcess.Free; tempDataProcess.Free; - threads.Free; + Threads.Free; MainForm.isUpdating := False; DoneCriticalsection(CS_AddInfoToData); DoneCriticalsection(CS_AddNamesAndLinks); + DoneCriticalsection(CS_Threads); inherited Destroy; end; @@ -423,7 +421,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; procedure WaitForThreads; begin - while (not Terminated) and (threads.Count > 0) do + while (not Terminated) and (Threads.Count > 0) do Sleep(SOCKHEARTBEATRATE); end; @@ -466,27 +464,27 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE) else - while (not Terminated) and (threads.Count >= numberOfThreads) do + while (not Terminated) and (Threads.Count >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE); - if (not Terminated) and (threads.Count < numberOfThreads) then + if (not Terminated) and (Threads.Count < numberOfThreads) then begin - LockCreateConnection; + EnterCriticalsection(CS_Threads); try if Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads then Exit; Modules.IncActiveConnectionCount(ModuleId); - i:=threads.Add(TUpdateListThread.Create); + i:=Threads.Add(TUpdateListThread.Create); if cs=CS_INFO then begin - TUpdateListThread(threads[i]).title:=tempDataProcess.Value[workPtr,DATA_PARAM_TITLE]; - TUpdateListThread(threads[i]).link:=tempDataProcess.Value[workPtr,DATA_PARAM_LINK]; + TUpdateListThread(Threads[i]).title:=tempDataProcess.Value[workPtr,DATA_PARAM_TITLE]; + TUpdateListThread(Threads[i]).link:=tempDataProcess.Value[workPtr,DATA_PARAM_LINK]; end; - TUpdateListThread(threads[i]).checkStyle:=cs; - TUpdateListThread(threads[i]).manager:=Self; - TUpdateListThread(threads[i]).workPtr:=Self.workPtr; - TUpdateListThread(threads[i]).Start; + TUpdateListThread(Threads[i]).checkStyle:=cs; + TUpdateListThread(Threads[i]).manager:=Self; + TUpdateListThread(Threads[i]).workPtr:=Self.workPtr; + TUpdateListThread(Threads[i]).Start; Inc(workPtr); s := RS_UpdatingList + Format(' [%d/%d] %s | [T:%d] [%d/%d]', - [websitePtr, websites.Count, website, threads.Count, workPtr, limit]); + [websitePtr, websites.Count, website, Threads.Count, workPtr, limit]); case cs of CS_DIRECTORY_COUNT: @@ -514,7 +512,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; MainForm.ulWorkPtr := workPtr + 1; Synchronize(MainThreadShowGetting); finally - UnlockCreateConnection; + LeaveCriticalsection(CS_Threads); end; end; end; @@ -529,18 +527,16 @@ procedure TUpdateListManagerThread.DoTerminate; var i: Integer; begin - if threads.Count > 0 then - begin - LockCreateConnection; - try - for i := 0 to threads.Count - 1 do - TUpdateListThread(threads[i]).Terminate; - finally - UnlockCreateConnection; - end; - while threads.Count > 0 do - Sleep(SOCKHEARTBEATRATE); + EnterCriticalsection(CS_Threads); + try + if Threads.Count > 0 then + for i := 0 to Threads.Count - 1 do + TUpdateListThread(Threads[i]).Terminate; + finally + LeaveCriticalsection(CS_Threads); end; + while Threads.Count > 0 do + Sleep(SOCKHEARTBEATRATE); inherited DoTerminate; end; @@ -647,7 +643,6 @@ procedure TUpdateListManagerThread.Execute; Synchronize(MainThreadShowGetting); tempDataProcess.OpenTable('', True); - // get manga info if tempDataProcess.RecordCount>0 then begin From 8669c493ce348312e6011e70cb147b31f3a1ebe4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Mar 2017 00:26:10 +0800 Subject: [PATCH 1658/2794] baseunit, maybefillhost ignore if path invalid --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 890e79914..bd996bafd 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1254,7 +1254,7 @@ function MaybeFillHost(const Host, URL: String): String; H,P: String; begin SplitURL(URL,H,P); - if H='' then Result:=RemoveURLDelim(Host)+P + if (H='') and (P<>'') then Result:=RemoveURLDelim(Host)+P else Result:=URL; end; From 91561447537683a1a78b89b8953a552ad8c434fc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Mar 2017 00:32:43 +0800 Subject: [PATCH 1659/2794] mangazuki, fixed all. closed #510, closed #514 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaZuki.pas | 261 +++++++++++++++----------------- 2 files changed, 127 insertions(+), 135 deletions(-) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 4e8f0bb46..e85f06728 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -55,6 +55,7 @@ uses JapScan, MangaGo, GoodManga, + MangaZuki, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 9e7b39d92..4362a3a04 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -1,135 +1,126 @@ -unit MangaZuki; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/series'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := StrToIntDef(SeparateRight( - XPathString('//ul[@class="pagination pagination-separated"]/li[last()]/a/@href'), '?page'), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if AURL <> '0' then - s += '?page=' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="col-lg-3 col-sm-6"]//div[@class="caption"]//a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//img[@class="img-circle"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@class="media-body"]/h1'); - summary := XPathString('//div[@class="media-body"]/h1/small'); - for v in XPath('//table[@id="chapter-list"]//tr/td/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//div [@class="content-wrapper"]//img') do - PageLinks.Add(v.toNode.getAttribute('src')); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaZuki'; - RootURL := 'https://mangazuki.co'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. +unit MangaZuki; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/series'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('(//ul[contains(@class,"pagination")]//a)[last()]/replace(@href,"^.*page=(\d+)\??.*$","$1")'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '?page=' + IncStr(AURL)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFAll('//*[@class="row"]//*[@class="caption"]//a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//*[@class="profile-thumb"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="media-body"]/h1/text()'); + summary := XPathString('//h6[text()="Synopsis"]/following-sibling::p'); + while True do + begin + for v in XPath('//ul[contains(@class,"media-list")]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('.//h6/text()', v)); + end; + s := XPathString('//ul[contains(@class,"pagination")]/li[@class="next"]/a/@href'); + if s = '' then Break; + if GET(MaybeFillHost(Module.RootURL, s)) then + ParseHTML(Document) + else Break; + if ThreadTerminated then Break; + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//*[@class="content-wrapper"]/*[@class="row"]/img') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toNode.getAttribute('src'))); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaZuki'; + RootURL := 'https://mangazuki.co'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. From b2dd4fd8b497dac5a3d186305710f7b8fd688a36 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Mar 2017 00:40:39 +0800 Subject: [PATCH 1660/2794] added mangazuki to en-sc --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 8173570fd..50cf778d5 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics Italian=MangaEden_IT,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake +English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=Komikid,Mabuns,Mangacan,MangaIndo,MangaKu,PecintaKomik From f3abf1e58a8427a7793792f76f046e984bbfba00 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Mar 2017 00:50:02 +0800 Subject: [PATCH 1661/2794] Bump version 0.9.99.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0ecdd7123..2fca8ae4c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.99.0 (08-03-2017) +[+] Added MangaZuki[EN-SC] +[-] HugeManga and MangaEsta were removed because the website is dead +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.98.0...0.9.99.0 + 0.9.98.0 (06-03-2017) [*] Fixed various issue with downloads and favorites [*] Added enable/disable favorites diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index defad684f..4c9b50d4a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="98"/> + <RevisionNr Value="99"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 8024d63f1..a853f30e8 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.98.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.98.0/fmd_0.9.98.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.98.0/fmd_0.9.98.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.98.0/fmd_0.9.98.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.98.0/fmd_0.9.98.0_Win64.7z +VERSION=0.9.99.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.99.0/fmd_0.9.99.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.99.0/fmd_0.9.99.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.99.0/fmd_0.9.99.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.99.0/fmd_0.9.99.0_Win64.7z From 8d5bce16f465890df618fe55113dad9c55f49c2e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 8 Mar 2017 13:31:05 +0800 Subject: [PATCH 1662/2794] downloadsmager, don't need to use table. insert and update using execute direct. closed #517 --- baseunits/uDownloadsManager.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 3e01e5cb3..23845a48b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1688,7 +1688,6 @@ function TDownloadManager.ConvertToDB: Boolean; GetParams(ReadString(s, 'FailedChapterName', ''))); end; FDownloadsDB.Commit; - FDownloadsDB.Refresh(False); Result := True; finally Free; From 7f93d7dac34ddb86a45d97dafa4a7f82b9bdfc0d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 00:11:24 +0800 Subject: [PATCH 1663/2794] Bump version 0.9.100.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2fca8ae4c..56998b09e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.100.0 (08-03-2017) +[*] Minor bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.99.0...0.9.100.0 + 0.9.99.0 (08-03-2017) [+] Added MangaZuki[EN-SC] [-] HugeManga and MangaEsta were removed because the website is dead diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 4c9b50d4a..932528441 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="99"/> + <RevisionNr Value="100"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index a853f30e8..6e74110e8 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.99.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.99.0/fmd_0.9.99.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.99.0/fmd_0.9.99.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.99.0/fmd_0.9.99.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.99.0/fmd_0.9.99.0_Win64.7z +VERSION=0.9.100.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.100.0/fmd_0.9.100.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.100.0/fmd_0.9.100.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.100.0/fmd_0.9.100.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.100.0/fmd_0.9.100.0_Win64.7z From 5e24dbec0a979a4b511b41957dd2ab9723d8b903 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 12:00:59 +0800 Subject: [PATCH 1664/2794] websitemodules, module as default property --- baseunits/WebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index c16447104..c5beaed3c 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -195,7 +195,7 @@ TWebsiteModules = class procedure LockModules; procedure UnlockModules; - property Module[const ModuleId: Integer]: TModuleContainer read GetModule; + property Module[const ModuleId: Integer]: TModuleContainer read GetModule; default; property Count: Integer read GetCount; property Website[const ModuleId: Integer]: String read GetWebsite; From c963a144238a166c4d987f122f69970846a01c1d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 12:16:54 +0800 Subject: [PATCH 1665/2794] batoto, removed task and connection limit. #519 --- baseunits/modules/Batoto.pas | 2 -- 1 file changed, 2 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index f7b7fe00e..5ab038c73 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -313,8 +313,6 @@ procedure RegisterModule; begin Website := modulename; RootURL := urlroot; - MaxTaskLimit := 1; - MaxConnectionLimit := 1; AccountSupport := True; SortedList := True; InformationAvailable := True; From d3105605e22d7e32fc10022a426ae89e91153e84 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 13:47:20 +0800 Subject: [PATCH 1666/2794] baseunit, overload fillhost with tstrings --- baseunits/uBaseUnit.pas | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index bd996bafd..2be191609 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -643,7 +643,8 @@ function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overlo function FillMangaSiteHost(const Website, URL: String): String; overload; // modify url -function FillHost(const Host, URL: String): String; +function FillHost(const Host, URL: String): String; overload; +function FillHost(const Host: String; const URLs: TStrings): String; overload; function MaybeFillHost(const Host, URL: String): String; function GetHostURL(URL: String): String; function RemoveHostFromURL(URL: String): String; @@ -1249,6 +1250,18 @@ function FillHost(const Host, URL: String): String; Result:=RemoveURLDelim(Host)+P; end; +function FillHost(const Host: String; const URLs: TStrings): String; +var + i: Integer; + H,P: String; +begin + for i:=0 to URLs.Count-1 do + begin + SplitURL(URLs[i],H,P); + URLs[i]:=RemoveURLDelim(Host)+P; + end; +end; + function MaybeFillHost(const Host, URL: String): String; var H,P: String; From 14c7330c2af2ae3a8e4ffd7f54b1b71058d8347f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 13:48:18 +0800 Subject: [PATCH 1667/2794] batoto, added option to select the server. #519 --- baseunits/modules/Batoto.pas | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 5ab038c73..4b54c69d1 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -25,10 +25,27 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; locklogin: TRTLCriticalSection; showalllang: Boolean = False; showscangroup: Boolean = False; + serverselection: Integer = 0; + +const + serverselectionvalue : array [0..4] of String = ( + 'img', + 'img3', + 'img4', + 'cdn', + 'cdn2' + ); resourcestring RS_ShowAllLang = 'Show all language'; RS_ShowScanGroup = 'Show scanlation group'; + RS_ServerSelection = 'Server selection:'; + RS_ServerSelectionItems = + 'Auto' + LineEnding + + 'Image Server EU' + LineEnding + + 'Image Server NA' + LineEnding + + 'CDN (default)' + LineEnding + + 'CDN2 (testing)'; function Login(const AHTTP: THTTPSendThread): Boolean; var @@ -295,6 +312,8 @@ function GetImageURL(const DownloadThread: TDownloadThread; IntToStr(DownloadThread.WorkId + 1); Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; Cookies.Text := Account.Cookies['Batoto']; + if serverselection <> 0 then + Cookies.Values['server_selection'] := serverselectionvalue[serverselection]; if GET(rurl) then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -325,6 +344,7 @@ procedure RegisterModule; OnLogin := @Login; AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); + AddOptionComboBox(@serverselection,'ServerSelection', @RS_ServerSelection, @RS_ServerSelectionItems); end; end; From 4ddb76b389537b96b1a1232292fcb9a4f2da9ab6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 14:03:21 +0800 Subject: [PATCH 1668/2794] websitemodules, change beforedownloadimage par aurl to var, should be able to change this value --- baseunits/WebsiteModules.pas | 10 +++++----- baseunits/modules/Comico.pas | 2 +- baseunits/modules/GameofScanlation.pas | 2 +- baseunits/modules/RawSenManga.pas | 2 +- baseunits/modules/Webtoons.pas | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index c5beaed3c..0e0b786c4 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -41,7 +41,7 @@ TModuleContainer = class; const AURL: String; const Module: TModuleContainer): Boolean; TOnBeforeDownloadImage = function(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; + var AURL: String; const Module: TModuleContainer): Boolean; TOnDownloadImage = function(const DownloadThread: TDownloadThread; const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; @@ -177,9 +177,9 @@ TWebsiteModules = class const AURL, AWebsite: String): Boolean; overload; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const ModuleId: Integer): Boolean; overload; + var AURL: String; const ModuleId: Integer): Boolean; overload; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - const AURL, AWebsite: String): Boolean; overload; + var AURL, AWebsite: String): Boolean; overload; function DownloadImage(const DownloadThread: TDownloadThread; const AURL, APath, AName: String; const ModuleId: Integer): Boolean; overload; @@ -553,7 +553,7 @@ function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; end; function TWebsiteModules.BeforeDownloadImage( - const DownloadThread: TDownloadThread; const AURL: String; + const DownloadThread: TDownloadThread; var AURL: String; const ModuleId: Integer): Boolean; begin Result := False; @@ -564,7 +564,7 @@ function TWebsiteModules.BeforeDownloadImage( end; function TWebsiteModules.BeforeDownloadImage( - const DownloadThread: TDownloadThread; const AURL, AWebsite: String): Boolean; + const DownloadThread: TDownloadThread; var AURL, AWebsite: String): Boolean; begin Result := BeforeDownloadImage(DownloadThread, AURL, LocateModule(AWebsite)); end; diff --git a/baseunits/modules/Comico.pas b/baseunits/modules/Comico.pas index a5040091a..ac462b603 100644 --- a/baseunits/modules/Comico.pas +++ b/baseunits/modules/Comico.pas @@ -156,7 +156,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; + var AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 0fa3780c6..f47f0208d 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -129,7 +129,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; + var AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 600e8612c..d997df6e4 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -171,7 +171,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; end; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; + var AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index c69ed6c08..2bcf9eac3 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -126,7 +126,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; + var AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; From 2a7c2e04f21458dfae97806044cdd8560c33a131 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 14:16:52 +0800 Subject: [PATCH 1669/2794] cleanups --- mangadownloader/md.lpr | 3 --- 1 file changed, 3 deletions(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index ec7804ee6..8299143f8 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -5,9 +5,6 @@ {$DEFINE MANGADOWNLOADER} uses - {$IFDEF DEBUGLEAKS} - SysUtils, - {$ENDIF} {$IFDEF UNIX} {$IFDEF UseCThreads} cthreads, {$ENDIF} {$ENDIF} From 17129de8930981671292382e946f6d958e8968cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 14:18:35 +0800 Subject: [PATCH 1670/2794] downloadmanagers,fixed downloadimage, fixed beforedownloadimage --- baseunits/uDownloadsManager.pas | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 23845a48b..a33185925 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -943,34 +943,30 @@ function TDownloadThread.DownloadImage: Boolean; FHTTP.Clear; - // call beforedownloadimage if available - if Modules.ModuleAvailable(Task.Container.ModuleId, MMBeforeDownloadImage) then - Result := Modules.BeforeDownloadImage(Self, workURL, Task.Container.ModuleId); - // prepare filename workFilename := Task.GetFileName(WorkId); // download image savedFilename := ''; + + if Modules.ModuleAvailable(Task.Container.ModuleId, MMDownloadImage) and + (Task.Container.PageNumber = Task.Container.PageContainerLinks.Count) and + (WorkId < Task.Container.PageContainerLinks.Count) then + workURL := Task.Container.PageContainerLinks[WorkId]; + + // call beforedownloadimage if available + if Modules.ModuleAvailable(Task.Container.ModuleId, MMBeforeDownloadImage) then + Result := Modules.BeforeDownloadImage(Self, workURL, Task.Container.ModuleId); + if Result then begin if Modules.ModuleAvailable(Task.Container.ModuleId, MMDownloadImage) then - begin - workURL := ''; - if (Task.Container.PageNumber = Task.Container.PageContainerLinks.Count) - and (WorkId < Task.Container.PageContainerLinks.Count) then - workURL := Task.Container.PageContainerLinks[WorkId] - else if WorkId < Task.Container.PageLinks.Count then - workURL := Task.Container.PageLinks[WorkId]; - - if workURL <> '' then Result := Modules.DownloadImage( Self, workURL, Task.CurrentWorkingDir, workFilename, - Task.Container.ModuleId); - end + Task.Container.ModuleId) else if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL From f2bea66050e6397511ae9528f77ae1cb52a7d761 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 14:22:54 +0800 Subject: [PATCH 1671/2794] batoto, replace image url before download, so the option will be applied while the download already running --- baseunits/modules/Batoto.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 4b54c69d1..96d7f2692 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -326,6 +326,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; end; end; +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + var AURL: String; const Module: TModuleContainer): Boolean; +begin + AURL := FillHost('http://' + serverselectionvalue[serverselection] + '.bato.to', AURL); + Result := True; +end; + procedure RegisterModule; begin with AddModule do @@ -341,6 +348,7 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; + OnBeforeDownloadImage := @BeforeDownloadImage; OnLogin := @Login; AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); From 67c67fa256df463187f9ffc5cff14f2c4429fdaf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 14:31:23 +0800 Subject: [PATCH 1672/2794] mangasee, change the domain. #522 --- baseunits/modules/MangaLife.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 678cdb720..46ef3f452 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -241,7 +241,7 @@ procedure RegisterModule; begin AddWebsiteModule('MangaLife', 'http://mangalife.org'); - AddWebsiteModule('MangaSee', 'http://mangaseeonline.net'); + AddWebsiteModule('MangaSee', 'http://mangaseeonline.us'); MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.biz'); MMangaTraders.AccountSupport := True; MMangaTraders.OnLogin := @MangaTradersLogin; From 3b91419d7f3ff7d5e95445c15bdfe98b2f597e70 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 9 Mar 2017 14:56:39 +0800 Subject: [PATCH 1673/2794] changed the proxy port field with spinedit, fixed layout --- mangadownloader/forms/frmMain.lfm | 126 +++++++---- mangadownloader/forms/frmMain.lrj | 1 - mangadownloader/languages/fmd.el_GR.po | 4 - mangadownloader/languages/fmd.en.po | 5 +- mangadownloader/languages/fmd.es.po | 301 ++++++------------------- mangadownloader/languages/fmd.id_ID.po | 5 +- mangadownloader/languages/fmd.pl_PL.po | 4 - mangadownloader/languages/fmd.po | 4 - mangadownloader/languages/fmd.pt_BR.po | 4 - 9 files changed, 149 insertions(+), 305 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 59ad616ed..b757b001d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2599,35 +2599,42 @@ object MainForm: TMainForm Left = 4 Height = 105 Top = 155 - Width = 402 + Width = 426 AutoSize = True Caption = 'Proxy config' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 4 + ChildSizing.HorizontalSpacing = 12 + ChildSizing.VerticalSpacing = 12 ClientHeight = 85 - ClientWidth = 398 + ClientWidth = 422 Enabled = False ParentFont = False TabOrder = 1 object lbOptionHost: TLabel + AnchorSideLeft.Control = lbOptionProxyType + AnchorSideTop.Control = lbOptionProxyType + AnchorSideTop.Side = asrBottom Left = 4 - Height = 23 - Top = 4 + Height = 15 + Top = 35 Width = 25 Caption = 'Host' ParentColor = False ParentFont = False end object edOptionHost: TEdit - Left = 33 + AnchorSideLeft.Control = cbOptionProxyType + AnchorSideTop.Control = lbOptionHost + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = cbOptionProxyType + AnchorSideRight.Side = asrBottom + Left = 41 Height = 23 - Top = 4 + Top = 31 Width = 150 - Constraints.MinWidth = 150 + Anchors = [akTop, akLeft, akRight] + AutoSize = False Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Default' @@ -2636,86 +2643,88 @@ object MainForm: TMainForm TextHint = 'Proxy host/IP' end object lbOptionUser: TLabel + AnchorSideLeft.Control = cbOptionProxyType AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 187 - Height = 23 - Top = 4 + AnchorSideTop.Control = lbOptionHost + Left = 203 + Height = 15 + Top = 35 Width = 53 Caption = 'Username' ParentColor = False end object edOptionUser: TEdit + AnchorSideLeft.Control = lbOptionUser AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 244 + AnchorSideTop.Control = lbOptionUser + AnchorSideTop.Side = asrCenter + Left = 268 Height = 23 - Top = 4 + Top = 31 Width = 150 - Constraints.MinWidth = 150 Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Default' ParentFont = False - TabOrder = 2 + TabOrder = 1 TextHint = 'Proxy username' end object lbOptionPort: TLabel + AnchorSideLeft.Control = lbOptionHost + AnchorSideTop.Control = lbOptionHost + AnchorSideTop.Side = asrBottom Left = 4 - Height = 23 - Top = 31 - Width = 25 + Height = 15 + Top = 62 + Width = 22 Caption = 'Port' ParentColor = False end - object edOptionPort: TEdit - Left = 33 - Height = 23 - Top = 31 - Width = 150 - Font.CharSet = ANSI_CHARSET - Font.Height = -12 - Font.Name = 'Default' - ParentFont = False - TabOrder = 1 - TextHint = 'Proxy Port' - end object lbOptionPass: TLabel - AnchorSideLeft.Side = asrBottom + AnchorSideLeft.Control = lbOptionUser + AnchorSideTop.Control = lbOptionUser AnchorSideTop.Side = asrBottom - Left = 187 - Height = 23 - Top = 31 - Width = 53 + Left = 203 + Height = 15 + Top = 62 + Width = 50 Caption = 'Password' ParentColor = False end object edOptionPass: TEdit - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 244 + AnchorSideLeft.Control = edOptionUser + AnchorSideTop.Control = lbOptionPass + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = edOptionUser + AnchorSideRight.Side = asrBottom + Left = 268 Height = 23 - Top = 31 + Top = 58 Width = 150 + Anchors = [akTop, akLeft, akRight] Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Default' ParentFont = False - TabOrder = 3 + TabOrder = 2 TextHint = 'Proxy password' end object lbOptionProxyType: TLabel Left = 4 - Height = 23 - Top = 58 + Height = 15 + Top = 8 Width = 25 Caption = 'Type' ParentColor = False end object cbOptionProxyType: TComboBox - Left = 33 + AnchorSideLeft.Control = lbOptionProxyType + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbOptionProxyType + AnchorSideTop.Side = asrCenter + Left = 41 Height = 23 - Top = 58 + Top = 4 Width = 150 ItemHeight = 15 ItemIndex = 0 @@ -2725,9 +2734,26 @@ object MainForm: TMainForm 'SOCKS5' ) Style = csDropDownList - TabOrder = 4 + TabOrder = 3 Text = 'HTTP' end + object edOptionPort: TSpinEdit + AnchorSideLeft.Control = edOptionHost + AnchorSideTop.Control = lbOptionPort + AnchorSideTop.Side = asrCenter + Left = 41 + Height = 23 + Top = 58 + Width = 67 + Font.CharSet = ANSI_CHARSET + Font.Height = -12 + Font.Name = 'Default' + MaxValue = 999999 + MinValue = 1 + ParentFont = False + TabOrder = 4 + Value = 8080 + end end object seOptionMaxParallel: TSpinEdit Left = 4 diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 861e0704e..f388bb3b8 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -162,7 +162,6 @@ {"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, {"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, -{"hash":263204852,"name":"tmainform.edoptionport.texthint","sourcebytes":[80,114,111,120,121,32,80,111,114,116],"value":"Proxy Port"}, {"hash":145417188,"name":"tmainform.lboptionpass.caption","sourcebytes":[80,97,115,115,119,111,114,100],"value":"Password"}, {"hash":29717652,"name":"tmainform.edoptionpass.texthint","sourcebytes":[80,114,111,120,121,32,112,97,115,115,119,111,114,100],"value":"Proxy password"}, {"hash":376933,"name":"tmainform.lboptionproxytype.caption","sourcebytes":[84,121,112,101],"value":"Type"}, diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 6723d89e0..ae4ea3220 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1174,10 +1174,6 @@ msgstr "Προσαρμ. μετονομασία" msgid "Proxy password" msgstr "Κωδικός μεσολαβητή" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "Θύρα μεσολαβητή" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "Όνομα χρήστη μεσολαβητή" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index f254c3df3..9660662b0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1119,10 +1119,6 @@ msgstr "Custom rename" msgid "Proxy password" msgstr "Proxy password" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "Proxy Port" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "Proxy username" @@ -2207,3 +2203,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 43f79b299..140261b8d 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -101,12 +101,8 @@ msgid "Cannot connect to the server." msgstr "No se puede conectar con el servidor" #: frmmain.rs_dlgcannotgetmangainfo -msgid "" -"Cannot get manga info. Please check your internet connection and try it " -"again." -msgstr "" -"No se puede obtener la información del manga. Por favor revisa tu conexión a " -"internet e inténtalo de nuevo." +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "No se puede obtener la información del manga. Por favor revisa tu conexión a internet e inténtalo de nuevo." #: frmmain.rs_dlgdownloadcount msgid "Download count:" @@ -612,8 +608,7 @@ msgstr "Reemplazar todo Carácter Unicode con" #: tmainform.cboptionchangeunicodecharacter.hint msgid "Enable this if you have problem with unicode character in path." -msgstr "" -"Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" +msgstr "Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -674,25 +669,19 @@ msgstr "Mostrar Barra de Herramientas de Descargas" #: tmainform.cboptionshowdownloadtoolbardeleteall.caption msgid "Show \"Delete all completed tasks\" in downloads toolbar" -msgstr "" -"Mostrar \"Eliminar Todas las Tareas Completadas\" en la Barra de " -"Herramientas de Descargas" +msgstr "Mostrar \"Eliminar Todas las Tareas Completadas\" en la Barra de Herramientas de Descargas" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Salir de FMD" #: tmainform.cboptionupdatelistnomangainfo.caption -msgid "" -"Don't load manga information when updating list (filter will be not work!)" -msgstr "" -"No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro " -"no Funcionará)" +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "No Cargar la Información del Manga Cuando se Actualice la Lista (El Filtro no Funcionará)" #: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption msgid "Remove duplicate local data when updating manga list" -msgstr "" -"Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" +msgstr "Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Manga" #: tmainform.cboptionuseproxy.caption msgid "Use proxy" @@ -724,52 +713,32 @@ msgid "Action" msgstr "Acción" #: tmainform.ckfilteraction.hint -msgid "" -"A work typically depicting fighting, violence, chaos, and fast paced motion." -msgstr "" -"Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de " -"rápido movimiento." +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Un trabajo que típicamente demuestra peleas, violencia, caos, y ritmo de rápido movimiento." #: tmainform.ckfilteradult.caption msgid "Adult" msgstr "Adulto" #: tmainform.ckfilteradult.hint -msgid "" -"Contains content that is suitable only for adults. Titles in this category " -"may include prolonged scenes of intense violence and/or graphic sexual " -"content and nudity." -msgstr "" -"Contiene contenido que es apropiado solo para adultos. Los títulos en esta " -"categoría pueden incluir prolongadas escenas de intensa violencia y/o " -"contenido sexual gráfico o desnudez." +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Contiene contenido que es apropiado solo para adultos. Los títulos en esta categoría pueden incluir prolongadas escenas de intensa violencia y/o contenido sexual gráfico o desnudez." #: tmainform.ckfilteradventure.caption msgid "Adventure" msgstr "Aventura" #: tmainform.ckfilteradventure.hint -msgid "" -"If a character in the story goes on a trip or along that line, your best bet " -"is that it is an adventure manga. Otherwise, it's up to your personal " -"prejudice on this case." -msgstr "" -"Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor " -"apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio " -"personal en este caso." +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Si un personaje en la historia va en un viaje o siguiendo esa línea, mejor apuesta a que es un manga de aventura. De otro modo, es a tu prejuicio personal en este caso." #: tmainform.ckfiltercomedy.caption msgid "Comedy" msgstr "Comedia" #: tmainform.ckfiltercomedy.hint -msgid "" -"A dramatic work that is light and often humorous or satirical in tone and " -"that usually contains a happy resolution of the thematic conflict." -msgstr "" -"Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o " -"satírico y que usualmente contiene una feliz resolución del conflicto " -"temático." +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Un trabajo dramático que es iluminado y muy seguido en un tono humorístico o satírico y que usualmente contiene una feliz resolución del conflicto temático." #: tmainform.ckfilterdoujinshi.caption msgid "Doujinshi" @@ -784,36 +753,24 @@ msgid "Drama" msgstr "Drama" #: tmainform.ckfilterdrama.hint -msgid "" -"A work meant to bring on an emotional response, such as instilling sadness " -"or tension." -msgstr "" -"Un trabajo que pretende traer una respuesta emocional, tales como inculcar " -"la tristeza o tensión." +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Un trabajo que pretende traer una respuesta emocional, tales como inculcar la tristeza o tensión." #: tmainform.ckfilterechi.caption msgid "Ecchi" msgstr "Ecchi" #: tmainform.ckfilterechi.hint -msgid "" -"Possibly the line between hentai and non-hentai, ecchi usually refers to " -"fanservice put in to attract a certain group of fans." -msgstr "" -"Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se " -"refiere a fanservice puesto para atraer un cierto grupo de fans." +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Posiblemente la línea entre lo hentai y no-hentai, ecchi usualmente se refiere a fanservice puesto para atraer un cierto grupo de fans." #: tmainform.ckfilterfantasy.caption msgid "Fantasy" msgstr "Fantasía" #: tmainform.ckfilterfantasy.hint -msgid "" -"Anything that involves, but not limited to, magic, dream world, and fairy " -"tales." -msgstr "" -"Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y " -"cuentos de hadas." +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y cuentos de hadas." #: tmainform.ckfiltergenderbender.caption msgid "Gender Bender" @@ -832,14 +789,8 @@ msgid "Harem" msgstr "Harem" #: tmainform.ckfilterharem.hint -msgid "" -"A series involving one male character and many female characters (usually " -"attracted to the male character). A Reverse Harem is when the genders are " -"reversed." -msgstr "" -"Una serie que envuelve un personaje masculino y muchos personajes femeninos " -"(generalmente atraídos por el personaje masculino). Un Harem inverso es " -"cuando los sexos se invierten." +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "Una serie que envuelve un personaje masculino y muchos personajes femeninos (generalmente atraídos por el personaje masculino). Un Harem inverso es cuando los sexos se invierten." #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -864,26 +815,16 @@ msgid "Horror" msgstr "Horror" #: tmainform.ckfilterhorror.hint -msgid "" -"A painful emotion of fear, dread, and abhorrence; a shuddering with terror " -"and detestation; the feeling inspired by something frightful and shocking." -msgstr "" -"Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de " -"terror y odio; el sentimiento inspirado por algo terrible e impactante." +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Una dolorosa emoción de miedo, temor y repugnancia; un estremecimiento de terror y odio; el sentimiento inspirado por algo terrible e impactante." #: tmainform.ckfilterjosei.caption msgid "Josei" msgstr "Josei" #: tmainform.ckfilterjosei.hint -msgid "" -"Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. " -"Unlike shoujo the romance is more realistic and less idealized. The " -"storytelling is more explicit and mature." -msgstr "" -"Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino " -"equivalente al seinen. A diferencia de shoujo el romance es más realista y " -"menos idealizado. La narración es más explícita y madura." +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Literalmente \"mujer\". Dirigido a las mujeres de 18-30. Femenino equivalente al seinen. A diferencia de shoujo el romance es más realista y menos idealizado. La narración es más explícita y madura." #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -898,40 +839,24 @@ msgid "Martial Arts" msgstr "Artes Marciales" #: tmainform.ckfiltermartialarts.hint -msgid "" -"As the name suggests, anything martial arts related. Any of several arts of " -"combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, " -"fencing, and so on and so forth." -msgstr "" -"Como su nombre indica, cualquier cosa relacionada artes marciales. " -"Cualquiera de los diversos artes de combate o de autodefensa, como el " -"aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "Como su nombre indica, cualquier cosa relacionada artes marciales. Cualquiera de los diversos artes de combate o de autodefensa, como el aikido, karate, judo, o el taekwondo, kendo, la esgrima, y así sucesivamente." #: tmainform.ckfiltermature.caption msgid "Mature" msgstr "Maduro" #: tmainform.ckfiltermature.hint -msgid "" -"Contains subject matter which may be too extreme for people under the age of " -"17. Titles in this category may contain intense violence, blood and gore, " -"sexual content and/or strong language." -msgstr "" -"Contiene temas que pueden ser demasiado extremos para las personas menores " -"de 17. Los títulos de esta categoría pueden contener violencia intensa, " -"sangre y gore, contenido sexual y/o lenguaje fuerte." +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "Contiene temas que pueden ser demasiado extremos para las personas menores de 17. Los títulos de esta categoría pueden contener violencia intensa, sangre y gore, contenido sexual y/o lenguaje fuerte." #: tmainform.ckfiltermecha.caption msgid "Mecha" msgstr "Mecha" #: tmainform.ckfiltermecha.hint -msgid "" -"A work involving and usually concentrating on all types of large robotic " -"machines." -msgstr "" -"Un trabajo que involucra y por lo general se concentra en todos los tipos de " -"grandes máquinas robóticas." +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Un trabajo que involucra y por lo general se concentra en todos los tipos de grandes máquinas robóticas." #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -948,37 +873,24 @@ msgid "Mystery" msgstr "Misterio" #: tmainform.ckfiltermystery.hint -msgid "" -"Usually an unexplained event occurs, and the main protagonist attempts to " -"find out what caused it." -msgstr "" -"Por lo general, se produce un acontecimiento inexplicable, y el protagonista " -"intenta averiguar cuál fue la causa." +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Por lo general, se produce un acontecimiento inexplicable, y el protagonista intenta averiguar cuál fue la causa." #: tmainform.ckfilterpsychological.caption msgid "Psychological" msgstr "Psicológico" #: tmainform.ckfilterpsychological.hint -msgid "" -"Usually deals with the philosophy of a state of mind, in most cases " -"detailing abnormal psychology." -msgstr "" -"Por lo general lidia con la filosofía de un estado de la mente, en la " -"mayoría de los casos que detallan la psicología anormal." +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Por lo general lidia con la filosofía de un estado de la mente, en la mayoría de los casos que detallan la psicología anormal." #: tmainform.ckfilterromance.caption msgid "Romance" msgstr "Romance" #: tmainform.ckfilterromance.hint -msgid "" -"Any love related story. We will define love as between man and woman in this " -"case. Other than that, it is up to your own imagination of what love is." -msgstr "" -"Cualquier historia relacionada con el amor. Vamos a definir el amor como " -"entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu " -"propia imaginación de lo que es el amor." +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Cualquier historia relacionada con el amor. Vamos a definir el amor como entre el hombre y la mujer en este caso. Aparte de eso, le corresponde tu propia imaginación de lo que es el amor." #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -986,41 +898,23 @@ msgstr "Vida Escolar" #: tmainform.ckfilterschoollife.hint msgid "Having a major setting of the story deal with some type of school." -msgstr "" -"Tener un escenario importante de la historia ocupado con algún tipo de " -"escuela." +msgstr "Tener un escenario importante de la historia ocupado con algún tipo de escuela." #: tmainform.ckfilterscifi.caption msgid "Sci-Fi" msgstr "Sci-Fi (Ciencia Ficción)" #: tmainform.ckfilterscifi.hint -msgid "" -"Short for science fiction, these works involve twists on technology and " -"other science related phenomena which are contrary or stretches of the " -"modern day scientific world." -msgstr "" -"Abreviatura de ciencia ficción, estos trabajos implican giros en la " -"tecnología y otros fenómenos relacionados con la ciencia y que sean " -"contrarias o tramos del mundo científico de hoy en día." +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Abreviatura de ciencia ficción, estos trabajos implican giros en la tecnología y otros fenómenos relacionados con la ciencia y que sean contrarias o tramos del mundo científico de hoy en día." #: tmainform.ckfilterseinen.caption msgid "Seinen" msgstr "Seinen" #: tmainform.ckfilterseinen.hint -msgid "" -"From Google: Seinen means 'young Man'. Manga and anime that specifically " -"targets young adult males around the ages of 18 to 25 are seinen titles. The " -"stories in seinen works appeal to university students and those in the " -"working world. Typically the story lines deal with the issues of adulthood." -msgstr "" -"De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige " -"específicamente a los varones adultos jóvenes en torno a las edades de 18 a " -"25 años son títulos seinen. Las historias en las obras seinen apelan a los " -"estudiantes universitarios y los que están en el mundo laboral. Por lo " -"general las líneas de la historia se ocupan de los problemas de la edad " -"adulta." +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "De Google: Seinen significa 'hombre joven'. Manga y anime que se dirige específicamente a los varones adultos jóvenes en torno a las edades de 18 a 25 años son títulos seinen. Las historias en las obras seinen apelan a los estudiantes universitarios y los que están en el mundo laboral. Por lo general las líneas de la historia se ocupan de los problemas de la edad adulta." #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -1028,20 +922,15 @@ msgstr "Shotacon" #: tmainform.ckfiltershotacon.hint msgid "Representing a sexual attraction to young or under-age boys." -msgstr "" -"Representa una atracción sexual hacia los niños jóvenes o menores de edad." +msgstr "Representa una atracción sexual hacia los niños jóvenes o menores de edad." #: tmainform.ckfiltershoujo.caption msgid "Shoujo" msgstr "Shoujo" #: tmainform.ckfiltershoujo.hint -msgid "" -"A work intended and primarily written for females. Usually involves a lot of " -"romance and strong character development." -msgstr "" -"Un trabajo destinado y dirigido principalmente a las mujeres. Por lo " -"general, implica mucho romance y fuerte desarrollo de los personajes." +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Un trabajo destinado y dirigido principalmente a las mujeres. Por lo general, implica mucho romance y fuerte desarrollo de los personajes." #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -1049,12 +938,8 @@ msgstr "Shoujo Ai" #: tmainform.ckfiltershoujoai.hint msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" -msgid "" -"Often synonymous with yuri, this can be thought of as somewhat less extreme. " -"\"Girl''s Love\", so to speak." -msgstr "" -"A menudo sinónimo de yuri, esto puede ser considerado como algo menos " -"extremo. \"Amor de Chicas\", por así decirlo." +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "A menudo sinónimo de yuri, esto puede ser considerado como algo menos extremo. \"Amor de Chicas\", por así decirlo." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -1062,77 +947,48 @@ msgstr "Shounen" #: tmainform.ckfiltershounen.hint msgctxt "tmainform.ckfiltershounen.hint" -msgid "" -"A work intended and primarily written for males. These works usually involve " -"fighting and/or violence." -msgstr "" -"Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos " -"involucran generalmente la lucha y/o violencia." +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Un trabajo destinado y dirigido principalmente a los varones. Estas trabajos involucran generalmente la lucha y/o violencia." #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" msgstr "Shounen Ai" #: tmainform.ckfiltershounenai.hint -msgid "" -"Often synonymous with yaoi, this can be thought of as somewhat less extreme. " -"\"Boy''s Love\", so to speak" -msgstr "" -"A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. " -"\"Amor de Chicos\", por así decirlo" +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. \"Amor de Chicos\", por así decirlo" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" msgstr "Recuentos de la Vida" #: tmainform.ckfiltersliceoflife.hint -msgid "" -"As the name suggests, this genre represents day-to-day tribulations of one/" -"many character(s). These challenges/events could technically happen in real " -"life and are often -if not all the time- set in the present timeline in a " -"world that mirrors our own." -msgstr "" -"Como su nombre indica, este género representa el día a día tribulaciones de " -"uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente " -"en la vida real y no son a menudo -si todo el tiempo-, establecido en la " -"presente línea de tiempo en un mundo que refleja al nuestro." +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "Como su nombre indica, este género representa el día a día tribulaciones de uno/muchos personaje(s). Estos desafíos/eventos podrían ocurrir técnicamente en la vida real y no son a menudo -si todo el tiempo-, establecido en la presente línea de tiempo en un mundo que refleja al nuestro." #: tmainform.ckfiltersmut.caption msgid "Smut" msgstr "Smut (Atrevido)" #: tmainform.ckfiltersmut.hint -msgid "" -"Deals with series that are considered profane or offensive, particularly " -"with regards to sexual content." -msgstr "" -"Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo " -"que respecta a contenido sexual." +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Se ocupa de series que se consideran profanas u ofensivas, sobre todo en lo que respecta a contenido sexual." #: tmainform.ckfiltersports.caption msgid "Sports" msgstr "Deportes" #: tmainform.ckfiltersports.hint -msgid "" -"As the name suggests, anything sports related. Baseball, basketball, hockey, " -"soccer, golf, and racing just to name a few." -msgstr "" -"Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, " -"baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos " -"pocos." +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "Como su nombre sugiere, cualquier cosa relacionado con el deporte. Béisbol, baloncesto, hockey, fútbol, golf, y las carreras sólo para nombrar unos pocos." #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" msgstr "Sobrenatural" #: tmainform.ckfiltersupernatural.hint -msgid "" -"Usually entails amazing and unexplained powers or events which defy the laws " -"of physics." -msgstr "" -"Por lo general, implica sorprendentes e inexplicables poderes y eventos que " -"desafían las leyes de la física." +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Por lo general, implica sorprendentes e inexplicables poderes y eventos que desafían las leyes de la física." #: tmainform.ckfiltertragedy.caption msgid "Tragedy" @@ -1248,10 +1104,6 @@ msgstr "Nombre Personalizado" msgid "Proxy password" msgstr "Contraseña de Proxy" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "Puerto de Proxy" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "Usuario de Proxy" @@ -1402,8 +1254,7 @@ msgstr "" "%NUMBERING% : Numeración\n" "\n" "Nota:\n" -"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o " -"%NUMBERING%.\n" +"El Nombre de la Carpeta del Capítulo debe tener al menos %CHAPTER% o %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1494,11 +1345,8 @@ msgid "Number of downloaded tasks at the same time (Max: 8)" msgstr "Numero de Tareas de Descargas al Mismo Tiempo (Max: 8)" #: tmainform.lboptionmaxretry.caption -msgid "" -"Number of retry times if tasks have download problems (-1 = always retry)" -msgstr "" -"Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre " -"reintenta)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre reintenta)" #: tmainform.lboptionmaxthread.caption msgid "Number of downloaded files per task at the same time (Max: 32)" @@ -2126,40 +1974,32 @@ msgid "Cookies" msgstr "Cookies" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text -msgctxt "" -"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text -msgctxt "" -"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0]." -"text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1]." -"text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" msgid "Website" msgstr "Sitio Web" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text -msgctxt "" -"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" msgid "Value" msgstr "Valor" @@ -2343,3 +2183,4 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 3f4ccf167..eb7b9019a 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1104,10 +1104,6 @@ msgstr "Ubah nama kustom" msgid "Proxy password" msgstr "Kata kunci" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "Port" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "Nama user" @@ -2187,3 +2183,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 0c3d0a606..44b360dda 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1119,10 +1119,6 @@ msgstr "Zmień nazwę" msgid "Proxy password" msgstr "hasło proxy" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "Port proxy" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "nazwa użytkownika Proxy" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c7fb8cde1..fd9a7ca0a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1067,10 +1067,6 @@ msgstr "" msgid "Proxy password" msgstr "" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index c72664567..8123c1b7b 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1119,10 +1119,6 @@ msgstr "Renomear personalizado" msgid "Proxy password" msgstr "Senha do proxy" -#: tmainform.edoptionport.texthint -msgid "Proxy Port" -msgstr "Porta proxy" - #: tmainform.edoptionuser.texthint msgid "Proxy username" msgstr "Nome de usuário Proxy" From 26b04df57c63c25c655d07d5efa58e6bc464945b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 12:33:12 +0800 Subject: [PATCH 1674/2794] frmmain, changed default property of openfavoritesatstartup to false --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 84cda8330..f06b45a0e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4698,7 +4698,7 @@ procedure TMainForm.LoadOptions; cbOptionAutoCheckLatestVersion.Checked := ReadBool('update', 'AutoCheckLatestVersion', True); cbOptionAutoCheckFavStartup.Checked := ReadBool('update', 'AutoCheckFavStartup', True); cbOptionAutoCheckFavStartupChange(cbOptionAutoCheckFavStartup); - cbOptionAutoOpenFavStartup.Checked := ReadBool('update', 'AutoOpenFavStartup', True); + cbOptionAutoOpenFavStartup.Checked := ReadBool('update', 'AutoOpenFavStartup', False); cbOptionAutoCheckFavInterval.Checked := ReadBool('update', 'AutoCheckFavInterval', True); seOptionAutoCheckFavIntervalMinutes.Value := ReadInteger('update', 'AutoCheckFavIntervalMinutes', 60); lbOptionAutoCheckFavIntervalMinutes.Caption := Format(RS_LblAutoCheckNewChapterMinute, [seOptionAutoCheckFavIntervalMinutes.Value]); From ce8dc0ba2811edb4d6b31d02463011921725b70f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 12:52:34 +0800 Subject: [PATCH 1675/2794] xqueryenginehtml, added helper xpathhrefall and xpathhreftitleall --- baseunits/XQueryEngineHTML.pas | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 0dedcbaad..b28cb151f 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -66,6 +66,8 @@ TXQueryEngineHTML = class function XPathString(const Expression, HTMLString: String): String; overload; function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; +procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); +procedure XPathHREFtitleAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATitles: TStrings); implementation @@ -118,6 +120,28 @@ function XPathString(const Expression: String; const HTMLStream: TStream): Strin Result := XPathString(Expression, StreamToString(HTMLStream)); end; +procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; + const ALinks, ATexts: TStrings); +begin + with TXQueryEngineHTML.Create(HTMLStream) do + try + XPathHREFAll(Expression, ALinks, ATexts); + finally + Free; + end; +end; + +procedure XPathHREFtitleAll(const Expression: String; + const HTMLStream: TStream; const ALinks, ATitles: TStrings); +begin + with TXQueryEngineHTML.Create(HTMLStream) do + try + XPathHREFtitleAll(Expression, ALinks, ATitles); + finally + Free; + end; +end; + { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; From 96a23a40ca25490ace0757faad2a495c880564df Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 13:12:28 +0800 Subject: [PATCH 1676/2794] xqueryenginehtml, added helper xpathstringall --- baseunits/XQueryEngineHTML.pas | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index b28cb151f..a6db6d735 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -66,6 +66,7 @@ TXQueryEngineHTML = class function XPathString(const Expression, HTMLString: String): String; overload; function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; +procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; const TheStrings: TStrings); procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); procedure XPathHREFtitleAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATitles: TStrings); @@ -120,6 +121,16 @@ function XPathString(const Expression: String; const HTMLStream: TStream): Strin Result := XPathString(Expression, StreamToString(HTMLStream)); end; +procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; + const TheStrings: TStrings); +begin + with TXQueryEngineHTML.Create(HTMLStream) do + try + XPathStringAll(Expression, TheStrings); + finally + end; +end; + procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); begin From d5b5294987aa62993489d4909ce434f4c82a02e6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 13:16:50 +0800 Subject: [PATCH 1677/2794] mangaindo, rewrite all. #523 --- baseunits/modules/MangaIndo.pas | 77 ++++++--------------------------- 1 file changed, 13 insertions(+), 64 deletions(-) diff --git a/baseunits/modules/MangaIndo.pas b/baseunits/modules/MangaIndo.pas index 908853c91..d83c9c026 100644 --- a/baseunits/modules/MangaIndo.pas +++ b/baseunits/modules/MangaIndo.pas @@ -6,55 +6,24 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML; implementation -const - dirurl = '/manga-list2/'; - function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list/') then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="entry-content"]/div/ul/li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; + XPathHREFAll('//li[@class="manga-list"]/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - p: LongInt; - i: Integer; - - procedure ScanChapters; - var - v: IXQValue; - begin - with MangaInfo.mangaInfo, query do - for v in XPath('//ul[@class="lcp_catlist"]/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - end; - begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -63,31 +32,16 @@ function GetInfo(const MangaInfo: TMangaInformation; url := MaybeFillHost(Module.RootURL, AURL); if GET(url) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create(Document); - with query do + with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@id="main"]//img/@src')); - if title = '' then title := XPathString('//div[@class="title"]/h2'); - artists := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Artist:")]'),':')); - authors := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Author:")]'),':')); - genres := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Genre:")]'),':')); - status := MangaInfoStatusIfPos(XPathString( - '//div[@id="main"]//div[@class="entry-content"]/p/text()[starts-with(.,"Episode:")]'), - 'Ongoing', - 'Completed'); - summary := Trim(SeparateRight(XPathString('//div[@id="main"]//div[@class="entry-content"]/p[starts-with(.,"Synopsis:")]'), ':')); - ScanChapters; - p := StrToIntDef(XPathString('(//ul[@class="lcp_paginator"]/li/a[.!=">>"])[last()]') , 1); - if p > 1 then - for i := 2 to p do - begin - if Thread.IsTerminated then Break; - if GET(AppendURLDelim(url) + '?lcp_page0=' + IntToStr(i)) then - begin - ParseHTML(Document); - ScanChapters; - end; - end; + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@id="m-cover"]/img/@src')); + if title = '' then title := XPathString('//*[@class="title"]/h2'); + authors := XPathString('//*[@id="m-author"]'); + artists := XPathString('//*[@id="m-artist"]'); + genres := XPathString('//*[@id="m-genre"]/string-join(a," ")'); + status := MangaInfoStatusIfPos(XPathString('//*[@id="m-status"]')); + summary := XPathString('//*[@id="m-synopsis"]'); + XPathHREFAll('//ul[@class="lcp_catlist"]/li/a', chapterLinks, chapterName); InvertStrings([chapterLinks, chapterName]); finally Free; @@ -108,12 +62,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('//div[@id="main"]//div[@class="entry-content"]//img/@src', PageLinks); - finally - Free; - end; + XPathStringAll('//*[@class="entry-content"]//img/@src', Document, PageLinks); end; end; end; From 79cb498b0d16b5c6c8fee64b503b055a0fc642cd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 13:22:22 +0800 Subject: [PATCH 1678/2794] mabuns removed. website is dead. closed #526 --- baseunits/includes/Mabuns/image_url.inc | 43 --------- .../includes/Mabuns/manga_information.inc | 91 ------------------- baseunits/includes/Mabuns/names_and_links.inc | 37 -------- baseunits/uBaseUnit.pas | 80 ++++++++-------- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 5 - config/mangalist.ini | 2 +- 7 files changed, 39 insertions(+), 229 deletions(-) delete mode 100644 baseunits/includes/Mabuns/image_url.inc delete mode 100644 baseunits/includes/Mabuns/manga_information.inc delete mode 100644 baseunits/includes/Mabuns/names_and_links.inc diff --git a/baseunits/includes/Mabuns/image_url.inc b/baseunits/includes/Mabuns/image_url.inc deleted file mode 100644 index 10e3391af..000000000 --- a/baseunits/includes/Mabuns/image_url.inc +++ /dev/null @@ -1,43 +0,0 @@ - function GetMabunsImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MABUNS_ID, URL); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('addpage(''', parse[i]) > 0 then - begin - s := parse[i]; - s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); - repeat - j := Pos('addpage(''', s); - if Pos('googleusercontent', s) > 0 then - Task.Container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ''','))) - else - Task.Container.PageLinks.Add( - EncodeUrl(GetString(s, 'addpage(''', ');'))); - Delete(s, Pos('addpage(''', s), 16); - j := Pos('addpage(''', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Mabuns/manga_information.inc b/baseunits/includes/Mabuns/manga_information.inc deleted file mode 100644 index 1312df2e1..000000000 --- a/baseunits/includes/Mabuns/manga_information.inc +++ /dev/null @@ -1,91 +0,0 @@ - function GetMabunsInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MABUNS_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MABUNS_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('rel="image_src"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'href')); - - // get title - if (Pos('Judul :', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - TrimRight(HTMLEntitiesFilter(StringFilter(GetString(parse[i] + '~!@', - 'Judul :', '~!@'))))); - - if (not isExtractChapter) and (Pos('Baca Online:', parse[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('<a href', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MABUNS_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('</table>', parse[i]) > 0) then - isExtractChapter := False; - - // get authors - if (i + 8 < parse.Count) and (Pos('Author :', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft( - TrimRight(GetString(parse[i] + '~!@', 'Author :', '~!@'))); - - // get artists - if (i + 1 < parse.Count) and (Pos('Artist :', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft( - TrimRight(GetString(parse[i] + '~!@', 'Artist :', '~!@'))); - - // get genres - if (Pos('Genre :', parse[i]) <> 0) then - begin - mangaInfo.genres := TrimLeft( - TrimRight(GetString(parse[i] + '~!@', 'Genre :', '~!@'))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Mabuns/names_and_links.inc b/baseunits/includes/Mabuns/names_and_links.inc deleted file mode 100644 index 847753490..000000000 --- a/baseunits/includes/Mabuns/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function MabunsGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MABUNS_ID, 1] + MABUNS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="manga"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); - ANames.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetVal(parse[i + 6], 'href'), - WebsiteRoots[MABUNS_ID, 1], '', []); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2be191609..50567a43b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -245,45 +245,44 @@ interface ANIMEEXTREMIST_ID = 12; S2SCAN_ID = 13; IMANHUA_ID = 14; - MABUNS_ID = 15; - CENTRALDEMANGAS_ID = 16; - EGSCANS_ID = 17; - MANGAAR_ID = 18; - MANGAAE_ID = 19; - ANIMESTORY_ID = 20; - LECTUREENLIGNE_ID = 21; - SCANMANGA_ID = 22; - DM5_ID = 23; - KIVMANGA_ID = 24; - MEINMANGA_ID = 25; - MANGASPROJECT_ID = 26; - MANGAREADER_POR_ID = 27; - NINEMANGA_ID = 28; - NINEMANGA_ES_ID = 29; - NINEMANGA_CN_ID = 30; - NINEMANGA_RU_ID = 31; - NINEMANGA_DE_ID = 32; - NINEMANGA_IT_ID = 33; - NINEMANGA_BR_ID = 34; - JAPANSHIN_ID = 35; - CENTRUMMANGI_PL_ID = 36; - MANGALIB_PL_ID = 37; - ONEMANGA_ID = 38; - MANGATOWN_ID = 39; - MANGAOKU_ID = 40; - MYREADINGMANGAINFO_ID = 41; - IKOMIK_ID = 42; - NHENTAI_ID = 43; - MANGAMINT_ID = 44; - UNIXMANGA_ID = 45; - EXTREMEMANGAS_ID = 46; - MANGAHOST_ID = 47; - MANGAKU_ID = 48; - MANGAAT_ID = 49; - READMANGATODAY_ID = 50; - DYNASTYSCANS_ID = 51; - - WebsiteRoots: array [0..51] of array [0..1] of String = ( + CENTRALDEMANGAS_ID = 15; + EGSCANS_ID = 16; + MANGAAR_ID = 17; + MANGAAE_ID = 18; + ANIMESTORY_ID = 19; + LECTUREENLIGNE_ID = 20; + SCANMANGA_ID = 21; + DM5_ID = 22; + KIVMANGA_ID = 23; + MEINMANGA_ID = 24; + MANGASPROJECT_ID = 25; + MANGAREADER_POR_ID = 26; + NINEMANGA_ID = 27; + NINEMANGA_ES_ID = 28; + NINEMANGA_CN_ID = 29; + NINEMANGA_RU_ID = 30; + NINEMANGA_DE_ID = 31; + NINEMANGA_IT_ID = 32; + NINEMANGA_BR_ID = 33; + JAPANSHIN_ID = 34; + CENTRUMMANGI_PL_ID = 35; + MANGALIB_PL_ID = 36; + ONEMANGA_ID = 37; + MANGATOWN_ID = 38; + MANGAOKU_ID = 39; + MYREADINGMANGAINFO_ID = 40; + IKOMIK_ID = 41; + NHENTAI_ID = 42; + MANGAMINT_ID = 43; + UNIXMANGA_ID = 44; + EXTREMEMANGAS_ID = 45; + MANGAHOST_ID = 46; + MANGAKU_ID = 47; + MANGAAT_ID = 48; + READMANGATODAY_ID = 49; + DYNASTYSCANS_ID = 50; + + WebsiteRoots: array [0..50] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -299,7 +298,6 @@ interface ('AnimExtremist', 'http://www.animextremist.com'), ('S2Scans', 'http://reader.s2smanga.com'), ('imanhua', 'http://www.imanhua.com'), - ('Mabuns', 'http://www.mabuns.web.id'), ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), ('MangaAr', 'http://manga-ar.net'), @@ -372,8 +370,6 @@ interface IMANHUA_BROWSER = '/all.html'; - MABUNS_BROWSER = '/p/mabuns-manga-list.html'; - CENTRALDEMANGAS_BROWSER = '/mangas/list/*'; EGSCANS_BROWSER = '/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 12362f3da..154a2f935 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -944,8 +944,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/TruyenTranhTuan/names_and_links.inc} - {$I includes/Mabuns/names_and_links.inc} - {$I includes/AnimeStory/names_and_links.inc} {$I includes/LectureEnLigne/names_and_links.inc} @@ -1067,9 +1065,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if WebsiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else - if WebsiteID = MABUNS_ID then - Result := MabunsGetNamesAndLinks - else if WebsiteID = ANIMESTORY_ID then Result := AnimeStoryGetNamesAndLinks else @@ -1208,8 +1203,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/TruyenTranhTuan/manga_information.inc} - {$I includes/Mabuns/manga_information.inc} - {$I includes/AnimeStory/manga_information.inc} {$I includes/LectureEnLigne/manga_information.inc} @@ -1332,9 +1325,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if WebsiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else - if WebsiteID = MABUNS_ID then - Result := GetMabunsInfoFromURL - else if WebsiteID = ANIMESTORY_ID then Result := GetAnimeStoryInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a33185925..87a3c5f8a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -599,8 +599,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Kivmanga/image_url.inc} - {$I includes/Mabuns/image_url.inc} - {$I includes/Manga24h/image_url.inc} {$I includes/MangaAe/image_url.inc} @@ -685,9 +683,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else - if Task.Container.MangaSiteID = MABUNS_ID then - Result := GetMabunsImageURL - else if Task.Container.MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 50cf778d5..2b265c9a1 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE -Indonesian=Komikid,Mabuns,Mangacan,MangaIndo,MangaKu,PecintaKomik +Indonesian=Komikid,Mangacan,MangaIndo,MangaKu,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas From 08d8109ad41c9116be7a092ed849170edd4cc55f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 13:31:08 +0800 Subject: [PATCH 1679/2794] added mangaid. #523 --- baseunits/modules/myMangaReaderCMS.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index 353b11864..f93f91e9f 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -107,6 +107,7 @@ procedure RegisterModule; AddWebsiteModule('Komikid', 'http://www.komikid.com'); AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); + AddWebsiteModule('MangaID', 'http://mangaid.co'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 2b265c9a1..bf0723858 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE -Indonesian=Komikid,Mangacan,MangaIndo,MangaKu,PecintaKomik +Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas From d2c29ec5065ab9a2c12254a68c947751ce0d698c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 14:08:22 +0800 Subject: [PATCH 1680/2794] added mangashiro. closed #523 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaShiro.pas | 84 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaShiro.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e85f06728..29c9b2bd9 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -56,6 +56,7 @@ uses MangaGo, GoodManga, MangaZuki, + MangaShiro, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas new file mode 100644 index 000000000..5b44b6b4a --- /dev/null +++ b/baseunits/modules/MangaShiro.pas @@ -0,0 +1,84 @@ +unit MangaShiro; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/daftar-manga/') then + begin + Result := NO_ERROR; + XPathHREFAll('//*[@class="azindex"]//li/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="imganime"]//img/substring-before(substring-after(@style,"(''"),"'')")')); + if title = '' then title := XPathString('//*[@class="infos9" and starts-with(.,"Judul")]/text()'); + authors := XPathString('//*[@class="infos9" and starts-with(.,"Produser")]/text()'); + genres := XPathString('//*[@class="infos9" and starts-with(.,"Genre")]/text()'); + status := MangaInfoStatusIfPos(XPathString('//*[@class="infos9" and starts-with(.,"Status")]/text()')); + summary := XPathString('//*[@class="deskripsi"]/string-join(text(),"")'); + XPathHREFtitleAll('//*[@class="chapter-list"]//li[@class="anilist"]/div[2]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + XPathStringAll('//*[@class="readmanga"]//img/@src', Document, PageLinks); + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaShiro'; + RootURL := 'http://mangashiro.net'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index bf0723858..62b3b09c9 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE -Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,PecintaKomik +Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas From 0eb43e08ba0a5b2a3b55ac712374d37333f7cd16 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 14:28:29 +0800 Subject: [PATCH 1681/2794] update translations --- baseunits/modules/Batoto.pas | 2 +- mangadownloader/languages/fmd.el_GR.po | 20 ++++++++++++++------ mangadownloader/languages/fmd.en.po | 20 ++++++++++++++++++-- mangadownloader/languages/fmd.es.po | 13 +++++++++++++ mangadownloader/languages/fmd.id_ID.po | 19 ++++++++++++++++++- mangadownloader/languages/fmd.pl_PL.po | 18 ++++++++++++++---- mangadownloader/languages/fmd.po | 13 +++++++++++++ mangadownloader/languages/fmd.pt_BR.po | 20 +++++++++++++++----- 8 files changed, 106 insertions(+), 19 deletions(-) diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 96d7f2692..c8419d8be 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -39,7 +39,7 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; resourcestring RS_ShowAllLang = 'Show all language'; RS_ShowScanGroup = 'Show scanlation group'; - RS_ServerSelection = 'Server selection:'; + RS_ServerSelection = 'Image server:'; RS_ServerSelectionItems = 'Auto' + LineEnding + 'Image Server EU' + LineEnding + diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index ae4ea3220..e07e1972c 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -9,13 +9,24 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_US\n" -"X-Generator: Poedit 1.8.8\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Greek\n" -"X-Poedit-Country: GREECE\n" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Bookmarks: -1,-1,-1,-1,-1,-1,-1,29,-1,-1\n" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" + #: batoto.rs_showalllang msgid "Show all language" msgstr "Εμφάνιση όλων των γλωσσών" @@ -1286,7 +1297,6 @@ msgid "Log file:" msgstr "Αρχείο καταγραφής:" #: tmainform.lbmode.caption -#| msgid "Mode: Show All (0)" msgid "Mode: Show all (0)" msgstr "Λειτ.: Εμφάνιση όλων (0)" @@ -1622,7 +1632,6 @@ msgid "Delete" msgstr "Διαγραφή" #: tmainform.mifavoritesdisable.caption -#, fuzzy msgctxt "tmainform.mifavoritesdisable.caption" msgid "Disable" msgstr "Απενεργοποίηση" @@ -1633,7 +1642,6 @@ msgid "Download all" msgstr "Λήψη όλων" #: tmainform.mifavoritesenable.caption -#, fuzzy msgctxt "tmainform.mifavoritesenable.caption" msgid "Enable" msgstr "Ενεργοποίηση" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 9660662b0..aad197a77 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -12,6 +12,24 @@ msgstr "" "X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "Image server:" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" + #: batoto.rs_showalllang msgid "Show all language" msgstr "Show all language" @@ -1231,7 +1249,6 @@ msgid "Log file:" msgstr "Log file:" #: tmainform.lbmode.caption -#| msgid "Mode: Show All (0)" msgid "Mode: Show all (0)" msgstr "Mode: Show all (0)" @@ -2203,4 +2220,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 140261b8d..d1a9d010d 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -12,6 +12,19 @@ msgstr "" "Last-Translator: Mariolr\n" "Language: es_419\n" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" + #: batoto.rs_showalllang msgid "Show all language" msgstr "Mostrar todos los idiomas" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index eb7b9019a..659a9b735 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -12,6 +12,24 @@ msgstr "" "X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=1; plural=0;\n" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "Server gambar:" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" +"Otomatis\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" + #: batoto.rs_showalllang msgid "Show all language" msgstr "Tampilkan semua bahasa" @@ -2183,4 +2201,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 44b360dda..8e650a661 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -9,9 +9,22 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl_PL\n" -"X-Generator: Poedit 1.7.4\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" + #: batoto.rs_showalllang msgid "Show all language" msgstr "Pokaż wszystkie języki" @@ -1231,7 +1244,6 @@ msgid "Log file:" msgstr "Plik logów:" #: tmainform.lbmode.caption -#| msgid "Mode: Show All (0)" msgid "Mode: Show all (0)" msgstr "Tryb: Pokaż wszystko (0)" @@ -1568,7 +1580,6 @@ msgid "Delete" msgstr "Usuń" #: tmainform.mifavoritesdisable.caption -#, fuzzy msgctxt "tmainform.mifavoritesdisable.caption" msgid "Disable" msgstr "Wyłącz" @@ -1579,7 +1590,6 @@ msgid "Download all" msgstr "Pobierz wszystko" #: tmainform.mifavoritesenable.caption -#, fuzzy msgctxt "tmainform.mifavoritesenable.caption" msgid "Enable" msgstr "Włącz" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index fd9a7ca0a..c6e2c275e 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1,6 +1,19 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" + #: batoto.rs_showalllang msgid "Show all language" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 8123c1b7b..6fe141a6b 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -8,10 +8,23 @@ msgstr "" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt-BR\n" -"X-Generator: Poedit 1.8.8\n" +"Language: pt_BR\n" +"X-Generator: Poedit 1.8.12\n" "Plural-Forms: \n" +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" + #: batoto.rs_showalllang msgid "Show all language" msgstr "Exibir todos os idiomas" @@ -1231,7 +1244,6 @@ msgid "Log file:" msgstr "Arquivo de registro:" #: tmainform.lbmode.caption -#| msgid "Mode: Show All (0)" msgid "Mode: Show all (0)" msgstr "Modo: Exibir Tudo (0)" @@ -1567,7 +1579,6 @@ msgid "Delete" msgstr "Apagar" #: tmainform.mifavoritesdisable.caption -#, fuzzy msgctxt "tmainform.mifavoritesdisable.caption" msgid "Disable" msgstr "Desabilitar" @@ -1578,7 +1589,6 @@ msgid "Download all" msgstr "Baixar tudo" #: tmainform.mifavoritesenable.caption -#, fuzzy msgctxt "tmainform.mifavoritesenable.caption" msgid "Enable" msgstr "Habilitar" From de13af05cb5200124946b7bcef57ca1629337e54 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 10 Mar 2017 14:30:04 +0800 Subject: [PATCH 1682/2794] Bump version 0.9.101.0 --- changelog.txt | 9 +++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 56998b09e..b38bc8a78 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.101.0 (10-03-2017) +[+] Batoto: added option to select the image server to download +[*] MangaIndo: rewrite all codes +[+] Added MangaID[ID] +[+] Added MangaShiro[ID] +[-] Mabuns: removed +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.100.0...0.9.101.0 + 0.9.100.0 (08-03-2017) [*] Minor bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.99.0...0.9.100.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 932528441..23744d159 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="100"/> + <RevisionNr Value="101"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 6e74110e8..15e41701a 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.100.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.100.0/fmd_0.9.100.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.100.0/fmd_0.9.100.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.100.0/fmd_0.9.100.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.100.0/fmd_0.9.100.0_Win64.7z +VERSION=0.9.101.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.101.0/fmd_0.9.101.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.101.0/fmd_0.9.101.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.101.0/fmd_0.9.101.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.101.0/fmd_0.9.101.0_Win64.7z From 48cca5ef3729b58c45e0860101c23e556a27a22c Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sat, 11 Mar 2017 18:27:25 +0530 Subject: [PATCH 1683/2794] Update Hentaichan domain --- baseunits/modules/MangaChanRU.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 805d6bf90..4ce72d916 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -160,7 +160,7 @@ procedure RegisterModule; begin AddWebsiteModule('MangaChanRU', 'http://mangachan.me'); - AddWebsiteModule('HentaiChanRU', 'http://hentaichan.me'); + AddWebsiteModule('HentaiChanRU', 'http://henchan.me'); AddWebsiteModule('YaoiChanRU', 'http://yaoichan.me'); end; From a58e6af023e96c8f51d37c0d4070f44ff5a25721 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 12 Mar 2017 16:43:13 +0800 Subject: [PATCH 1684/2794] mangago, fixed image src. #529 --- baseunits/modules/MangaGo.pas | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 68f0c0052..2d5e02f33 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -31,12 +31,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + '1/') then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := XPath('//div[@class="pagination"]//ol/li//select/option').Count; - finally - Free; - end; + Page := StrToIntDef(XPathString('count(//div[@class="pagination"]//ol/li//select/option)', MangaInfo.FHTTP.Document), 1); end; end; @@ -48,12 +43,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + IncStr(AURL) + '/') then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - XPathHREFtitleAll('//div[@class="directory_left"]//li/h3/a', ALinks, ANames); - finally - Free; - end; + XPathHREFtitleAll('//div[@class="directory_left"]//li/h3/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; @@ -99,16 +89,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - s := XPathString('//script[contains(.,"imgsrcs = new Array")]', Document); + s := XPathString('//script[contains(.,"imgsrcs")]/substring-before(substring-after(substring-before(.,"imgsrcs"),"''"),"''")', Document); if s <> '' then - begin - s := GetString(s, 'new Array(', ');'); - s := StringReplace(s, ''',''', LineEnding, [rfReplaceAll]); - s := StringReplace(s, '''', '', [rfReplaceAll]); - s := StringReplace(s, '","', LineEnding, [rfReplaceAll]); - s := StringReplace(s, '"', '', [rfReplaceAll]); - PageLinks.Text := s; - end; + PageLinks.CommaText := s end; end; end; From 7cc9686c65413ec778129292636b9b36861f913a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 13 Mar 2017 12:43:49 +0800 Subject: [PATCH 1685/2794] readmangatoday, rewrite all. closed #527 --- baseunits/ModuleList.inc | 1 + .../ReadMangaToday/chapter_page_number.inc | 26 ---- .../ReadMangaToday/directory_page_number.inc | 6 - .../ReadMangaToday/manga_information.inc | 115 ------------------ .../ReadMangaToday/names_and_links.inc | 30 ----- baseunits/modules/ReadMangaToday.pas | 107 ++++++++++++++++ baseunits/uBaseUnit.pas | 6 +- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 5 - 9 files changed, 110 insertions(+), 201 deletions(-) delete mode 100644 baseunits/includes/ReadMangaToday/chapter_page_number.inc delete mode 100644 baseunits/includes/ReadMangaToday/directory_page_number.inc delete mode 100644 baseunits/includes/ReadMangaToday/manga_information.inc delete mode 100644 baseunits/includes/ReadMangaToday/names_and_links.inc create mode 100644 baseunits/modules/ReadMangaToday.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 29c9b2bd9..601a18425 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -57,6 +57,7 @@ uses GoodManga, MangaZuki, MangaShiro, + ReadMangaToday, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/ReadMangaToday/chapter_page_number.inc b/baseunits/includes/ReadMangaToday/chapter_page_number.inc deleted file mode 100644 index 911a5378b..000000000 --- a/baseunits/includes/ReadMangaToday/chapter_page_number.inc +++ /dev/null @@ -1,26 +0,0 @@ - function GetReadMangaTodayPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(READMANGATODAY_ID, URL)+'/all-pages'); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - - ParseHTML(l.Text, parse); - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count-1 do - if (GetTagName(parse[i]) = 'img') and - (Pos('img-responsive-', parse[i]) <> 0) then - Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); - Task.Container.PageNumber := Task.Container.PageLinks.Count; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/ReadMangaToday/directory_page_number.inc b/baseunits/includes/ReadMangaToday/directory_page_number.inc deleted file mode 100644 index a8a11a837..000000000 --- a/baseunits/includes/ReadMangaToday/directory_page_number.inc +++ /dev/null @@ -1,6 +0,0 @@ - function GetReadMangaTodayDirectoryPageNumber: Byte; - begin - Source.Free; - APage := Length(ALPHA_LIST); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/ReadMangaToday/manga_information.inc b/baseunits/includes/ReadMangaToday/manga_information.inc deleted file mode 100644 index d38d3ca05..000000000 --- a/baseunits/includes/ReadMangaToday/manga_information.inc +++ /dev/null @@ -1,115 +0,0 @@ - function GetReadMangaTodayInfoFromURL: Byte; - var - s: String; - i, j: Integer; - begin - mangaInfo.website := WebsiteRoots[READMANGATODAY_ID, 0]; - mangaInfo.url := FillMangaSiteHost(READMANGATODAY_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count-1 do - begin - //title - if mangaInfo.title = '' then - if GetTagName(parse[i]) = 'h1' then - mangaInfo.title := CommonStringFilter(parse[i+1]); - - //cover - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'class') = 'img-responsive') then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - if GetTagName(parse[i]) = 'dt' then - begin - //genre - if Pos('Categories:', parse[i+1]) > 0 then - begin - mangaInfo.genres := ''; - for j := i+2 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/dd' then - Break - else - if GetTagName(parse[j]) = 'a' then - if mangaInfo.genres = '' then - mangaInfo.genres := GetVal(parse[j], 'title') - else - mangaInfo.genres := mangaInfo.genres + ', ' + GetVal(parse[j], 'title'); - end; - end; - - //status - if Pos('Status:', parse[i+1]) > 0 then - begin - s := LowerCase(Trim(parse[i+6])); - if s = 'ongoing' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - end; - - //summary - if GetVal(parse[i], 'class') = 'list-group-item movie-detail' then - begin - mangaInfo.summary := ''; - for j := i + 1 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/li' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := mangaInfo.summary + LineEnding + CommonStringFilter(parse[j]); - end; - mangaInfo.summary := Trim(mangaInfo.summary); - end; - - //author - if Trim(parse[i]) = 'Author' then - for j := i downto 0 do - if GetTagName(parse[j]) = 'a' then - begin - mangaInfo.authors := CommonStringFilter(parse[j+1]); - Break; - end; - - //artist - if Trim(parse[i]) = 'Artist' then - for j := i downto 0 do - if GetTagName(parse[j]) = 'a' then - begin - mangaInfo.artists := CommonStringFilter(parse[j+1]); - Break; - end; - - //chapters - if (GetTagName(parse[i]) = 'ul') and - (GetVal(parse[i], 'class') = 'chp_lst') then - for j := i+1 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/ul' then - Break - else - if GetTagName(parse[j]) = 'a' then - mangaInfo.chapterLinks.Add(GetVal(parse[j], 'href')) - else - if GetVal(parse[j], 'class') = 'icon-arrow-2' then - mangaInfo.chapterName.Add(Trim(parse[j+2])); - end; - end; - Result := NO_ERROR; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 1 then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - end; diff --git a/baseunits/includes/ReadMangaToday/names_and_links.inc b/baseunits/includes/ReadMangaToday/names_and_links.inc deleted file mode 100644 index 986dad5fb..000000000 --- a/baseunits/includes/ReadMangaToday/names_and_links.inc +++ /dev/null @@ -1,30 +0,0 @@ - function ReadMangaTodayGetNamesAndLinks: Byte; - var - i: Integer; - s: string; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[READMANGATODAY_ID, 1] + '/manga-list'; - i := StrToIntDef(AURL, 0); - if i > 0 then - s := s + '/' + ALPHA_LIST[i+1]; - if not GetPage(TObject(Source), s, 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'span') and - (GetVal(parse[i], 'class') = 'manga-item') then - begin - ALinks.Add(GetVal(parse[i+4], 'href')); - ANames.Add(CommonStringFilter(parse[i+5])); - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/modules/ReadMangaToday.pas b/baseunits/modules/ReadMangaToday.pas new file mode 100644 index 000000000..1483e6ea1 --- /dev/null +++ b/baseunits/modules/ReadMangaToday.pas @@ -0,0 +1,107 @@ +unit ReadMangaToday; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +const + dirurls = ' abcdefghijklmnopqrstuvwxyz'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NO_ERROR; + Page := Length(dirurls); +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list/' + dirurls[StrToIntDef(AURL, 0) + 1]) then + begin + Result := NO_ERROR; + XPathHREFAll('//*[@class="manga-item"]//a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="panel-body"]//img/@src')); + if title = '' then title := XPathString('//h1'); + authors := XPathString('//li[.="Author"]/preceding-sibling::li'); + artists := XPathString('//li[.="Artist"]/preceding-sibling::li'); + genres := XPathString('//*[@class="dl-horizontal"]/dt[starts-with(.,"Categories")]/following-sibling::dd[1]/string-join(*,", ")'); + status := MangaInfoStatusIfPos(XPathString('//*[@class="dl-horizontal"]/dt[starts-with(.,"Status")]/following-sibling::dd[1]')); + summary := XPathString('//*[contains(@class,"movie-detail")]'); + for v in XPath('//ul[@class="chp_lst"]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('span[1]', v)); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + s := MaybeFillHost(Module.RootURL, AURL); + if Pos('/all-pages', LowerCase(s)) = 0 then + s := AppendURLDelim(s) + 'all-pages'; + if GET(s) then + begin + Result := True; + XPathStringAll('//*[contains(@class,"content-list")]//img/@src', Document, PageLinks); + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'ReadMangaToday'; + RootURL := 'http://www.readmanga.today'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 50567a43b..08fc0c022 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -279,10 +279,9 @@ interface MANGAHOST_ID = 46; MANGAKU_ID = 47; MANGAAT_ID = 48; - READMANGATODAY_ID = 49; - DYNASTYSCANS_ID = 50; + DYNASTYSCANS_ID = 49; - WebsiteRoots: array [0..50] of array [0..1] of String = ( + WebsiteRoots: array [0..49] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -332,7 +331,6 @@ interface ('MangaHost', 'http://br.mangahost.com'), ('MangaKu', 'http://mangaku.web.id'), ('MangaAt', 'http://www.mangaat.com'), - ('ReadMangaToday', 'http://www.readmanga.today'), ('Dynasty-Scans', 'http://dynasty-scans.com') ); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 154a2f935..9cfa2a9cc 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -810,8 +810,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/MangaAt/directory_page_number.inc} - {$I includes/ReadMangaToday/directory_page_number.inc} - {$I includes/Dynasty-Scans/directory_page_number.inc} begin @@ -905,9 +903,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if WebsiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber else - if WebsiteID = READMANGATODAY_ID then - Result := GetReadMangaTodayDirectoryPageNumber - else if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansDirectoryPageNumber else @@ -1010,8 +1005,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/MangaAt/names_and_links.inc} - {$I includes/ReadMangaToday/names_and_links.inc} - {$I includes/Dynasty-Scans/names_and_links.inc} begin @@ -1152,9 +1145,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if WebsiteID = MANGAAT_ID then Result := MangaAtGetNamesAndLinks else - if WebsiteID = READMANGATODAY_ID then - Result := ReadMangaTodayGetNamesAndLinks - else if WebsiteID = DYNASTYSCANS_ID then Result := DynastyScansGetNamesAndLinks else @@ -1259,8 +1249,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/MangaAt/manga_information.inc} - {$I includes/ReadMangaToday/manga_information.inc} - {$I includes/Dynasty-Scans/manga_information.inc} begin @@ -1412,9 +1400,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if WebsiteID = MANGAAT_ID then Result := GetMangaAtInfoFromURL else - if WebsiteID = READMANGATODAY_ID then - Result := GetReadMangaTodayInfoFromURL - else if WebsiteID = DYNASTYSCANS_ID then Result := GetDynastyScansInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 87a3c5f8a..dcd52dabb 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -465,8 +465,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaAt/chapter_page_number.inc} - {$I includes/ReadMangaToday/chapter_page_number.inc} - {$I includes/Dynasty-Scans/chapter_page_number.inc} begin @@ -567,9 +565,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAAT_ID then Result := GetMangaAtPageNumber else - if Task.Container.MangaSiteID = READMANGATODAY_ID then - Result := GetReadMangaTodayPageNumber - else if Task.Container.MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansPageNumber; end; From 540683c75f3d85f09385509c0d97bce68bb36b1e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 13 Mar 2017 13:17:34 +0800 Subject: [PATCH 1686/2794] Bump version 0.9.102.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index b38bc8a78..b647fa1b2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.102.0 (13-03-2017) +[*] MangaGo: fixed download +[*] ReadMangaToday: rewrite all codes +Full changes: https://github.com/riderkick/FMD/compare/0.9.101.0...0.9.102.0 + 0.9.101.0 (10-03-2017) [+] Batoto: added option to select the image server to download [*] MangaIndo: rewrite all codes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 23744d159..d05c92073 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="101"/> + <RevisionNr Value="102"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 15e41701a..6639c7fd7 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.101.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.101.0/fmd_0.9.101.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.101.0/fmd_0.9.101.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.101.0/fmd_0.9.101.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.101.0/fmd_0.9.101.0_Win64.7z +VERSION=0.9.102.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.102.0/fmd_0.9.102.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.102.0/fmd_0.9.102.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.102.0/fmd_0.9.102.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.102.0/fmd_0.9.102.0_Win64.7z From 7aba49227e1b3288787cc2f0ab66a99dcb88b44a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Mar 2017 06:32:08 +0800 Subject: [PATCH 1687/2794] unionmangas, rule out banner images. closed #528 --- baseunits/modules/UnionMangas.pas | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index c6b3c94cd..a8a7fa286 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -106,9 +106,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; @@ -117,15 +114,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - for v in query.XPath( - '//div[@id="image"]/div/img[@class="real img-responsive"][@id!="imagem-forum"]/@data-lazy') do - PageLinks.Add(v.toString); - finally - query.Free; - end; + XPathStringAll('//*[@id="image"]//img[contains(@data-lazy,"/leitor/")]/@data-lazy', Document, PageLinks); end; end; end; From a964d80b4ab3e7c2d01b194d8aebd2e9a5d28d18 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Mar 2017 06:59:56 +0800 Subject: [PATCH 1688/2794] unionmangas, cleanups rewrite --- baseunits/modules/UnionMangas.pas | 71 ++++++++----------------------- 1 file changed, 17 insertions(+), 54 deletions(-) diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index a8a7fa286..a38a16edd 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -15,26 +15,12 @@ implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - s: String; begin Result := NET_PROBLEM; - Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s := query.XPathString('//*[@class="pagination"]/li[last()]/a/@href'); - if s <> '' then begin - s := ReplaceRegExpr('^.*/(\d+)/?\*?$', s, '$1', True); - Page := StrToIntDef(s, 1); - end; - finally - query.Free; - end; + Page := StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()]/a/substring-before(substring-after(@href,"a-z/"),"/")', MangaInfo.FHTTP.Document), 1); end; end; @@ -42,8 +28,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; - v: IXQValue; s: String; begin Result := NET_PROBLEM; @@ -52,54 +36,33 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if AURL <> '0' then s += '/a-z/' + IncStr(AURL) + '/*'; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//div[@class="row"]/div/a[2]') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - query.Free; - end; + XPathHREFAll('//*[@class="row"]/div/a[2]', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; - s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL, AURL)) then begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink := query.XPathString('//img[@class="img-thumbnail"]/@src'); - if title = '' then title := query.XPathString('//div/h2'); - for v in query.XPath('//h4') do begin - s := v.toString; - if Pos('Gênero(s):', s) = 1 then genres := SeparateRight(s, ':') else - if Pos('Autor:', s) = 1 then authors := SeparateRight(s, ':') else - if Pos('Artista:', s) = 1 then artists := SeparateRight(s, ':') else - if Pos('Status:', s) = 1 then begin - if Pos('Ativo', s) > 0 then status := '1' else status := '0'; - end; - end; - summary := query.XPathString('//div/div[@class="panel-body"]'); - for v in query.XPath('//div[@class="row lancamento-linha"]/div[1]/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@class="img-thumbnail"]/@src')); + title := XPathString('//title/substring-before(.," - Union Mangás")'); + genres := XPathString('//h4[starts-with(./label,"Gênero")]/substring-after(.,":")'); + authors := XPathString('//h4[starts-with(./label,"Autor")]/substring-after(.,":")'); + artists := XPathString('//h4[starts-with(./label,"Artista")]/substring-after(.,":")'); + status := MangaInfoStatusIfPos(XPathString('//h4[starts-with(./label,"Status")]/substring-after(.,":")'), 'Ativo', 'Completo'); + summary := XPathString('//*[@class="panel-body"]'); + XPathHREFAll('//*[contains(@class,"lancamento-linha")]/div[1]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; end; - InvertStrings([chapterLinks, chapterName]); - finally - query.Free; - end; end; end; end; From 51966b8529eeb0884a8b7c122ef7f776f006e221 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Mar 2017 10:20:21 +0800 Subject: [PATCH 1689/2794] added mangaonlinebr. closed #533 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaOnlineBR.pas | 118 ++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaOnlineBR.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 601a18425..ebe16bece 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -58,6 +58,7 @@ uses MangaZuki, MangaShiro, ReadMangaToday, + MangaOnlineBR, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaOnlineBR.pas b/baseunits/modules/MangaOnlineBR.pas new file mode 100644 index 000000000..fa791741f --- /dev/null +++ b/baseunits/modules/MangaOnlineBR.pas @@ -0,0 +1,118 @@ +unit MangaOnlineBR; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, synacode, RegExpr; + +implementation + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/lista-titulos.php') then + begin + Result := NO_ERROR; + XPathHREFAll('//*[@class="manga"]/p/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v, x: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@id="page-mangas"]//*[@class="image"]/img/@src')); + title := XPathString('//h1'); + authors := XPathString('//*[@class="texto-left"]/ul/li[starts-with(.,"História")]/substring-after(.,":")'); + artists := XPathString('//*[@class="texto-left"]/ul/li[starts-with(.,"Ilustração")]/substring-after(.,":")'); + genres := XPathString('string-join(//*[@class="generos"]/a,", ")'); + status := MangaInfoStatusIfPos(XPathString('//*[@class="texto-left"]/ul/li[starts-with(.,"Status")]'), 'Em Publicação', ''); + summary := XPathString('//p[.="Sinopse"]/following-sibling::p'); + for v in XPath('//*[@id="volumes-capitulos"]//*[@class="texto"]') do + begin + s := XPathString('p[1]', v); + for x in XPath('p[2]//a', v) do + begin + chapterLinks.Add(x.toNode.getAttribute('href')); + chapterName.Add(s + ' Capitulo ' + x.toString); + end; + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + a, c: String; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + a := ''; + c := ''; + with TRegExpr.Create('(?i)/([^/]+)/capitulo/(\d+)') do + try + if Exec(AURL) then + begin + a := Match[1]; + c := Match[2]; + end; + finally + Free; + end; + if (a = '') or (c ='') then Exit; + if GET(Module.RootURL + '/capitulo.php?act=getImg&anime=' + EncodeURLElement(a) + '&capitulo=' + c + '&src=1&view=2') then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//*[@id="imgAvancadoVisualizacao"]/img') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toNode.getAttribute('src'))); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaOnlineBR'; + RootURL := 'http://mangaonline.com.br'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 62b3b09c9..2ac5659a3 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -12,7 +12,7 @@ German=MeinManga,NineManga_DE Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL -Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaREADER_POR,NineManga_BR,UnionMangas +Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineManga_BR,UnionMangas Raw=MangaMint,RawSenManga,RawYoManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineManga_ES,SekaiManga,SubManga,Tumangaonline From 9d48b8bf0ae394e8d97e158bb8730472ab1b46aa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 15 Mar 2017 10:31:11 +0800 Subject: [PATCH 1690/2794] Bump version 0.9.103.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index b647fa1b2..dde4a61aa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.103.0 (15-03-2017) +[+] Added MangaOnlineBR +[*] UnionMangas: exclude banner +Full changes: https://github.com/riderkick/FMD/compare/0.9.102.0...0.9.103.0 + 0.9.102.0 (13-03-2017) [*] MangaGo: fixed download [*] ReadMangaToday: rewrite all codes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index d05c92073..87a401a34 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="102"/> + <RevisionNr Value="103"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 6639c7fd7..27c6e7d84 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.102.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.102.0/fmd_0.9.102.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.102.0/fmd_0.9.102.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.102.0/fmd_0.9.102.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.102.0/fmd_0.9.102.0_Win64.7z +VERSION=0.9.103.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.103.0/fmd_0.9.103.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.103.0/fmd_0.9.103.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.103.0/fmd_0.9.103.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.103.0/fmd_0.9.103.0_Win64.7z From 3a914db9246ac10d9d80ab720164d5e9de515e41 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Mar 2017 20:54:33 +0800 Subject: [PATCH 1691/2794] fixed memory leak in xpathstringall --- baseunits/XQueryEngineHTML.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index a6db6d735..81b4086b2 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -128,6 +128,7 @@ procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; try XPathStringAll(Expression, TheStrings); finally + Free; end; end; From 42805b31dddad80881eba0b307ad09de480a1333 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Mar 2017 21:04:19 +0800 Subject: [PATCH 1692/2794] xqueryenginehtml, added xpathcount --- baseunits/XQueryEngineHTML.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 81b4086b2..0f20f3609 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -66,6 +66,7 @@ TXQueryEngineHTML = class function XPathString(const Expression, HTMLString: String): String; overload; function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; +function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; overload; procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; const TheStrings: TStrings); procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); procedure XPathHREFtitleAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATitles: TStrings); @@ -121,6 +122,17 @@ function XPathString(const Expression: String; const HTMLStream: TStream): Strin Result := XPathString(Expression, StreamToString(HTMLStream)); end; +function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; +begin + Result := 0; + with TXQueryEngineHTML.Create(HTMLStream) do + try + Result := XPath(Expression).Count; + finally + Free; + end; +end; + procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; const TheStrings: TStrings); begin From 8e40a14b5dbb72418a65321d64e417f27a11f8d1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Mar 2017 21:04:40 +0800 Subject: [PATCH 1693/2794] mangafox, cleanups --- baseunits/modules/MangaFox.pas | 63 ++++++---------------------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index a63cb4417..afae63539 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -20,23 +20,13 @@ implementation function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/manga/') then begin + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga/') then + begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="manga_list"]/ul/li/a[starts-with(@class,"series_preview manga")]') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; + XPathHREFAll('//*[@class="manga_list"]/ul/li/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; @@ -48,19 +38,13 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := FillHost(Module.RootURL, AURL); + url := MaybeFillHost(Module.RootURL, AURL); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//div[@class="cover"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@class="cover"]/img/@alt'); - if title = '' then begin - title := XPathString('//meta[@property="og:title"]/@content'); - if RightStr(title, 6) = ' Manga' then - SetLength(title, Length(title) - 6); - end; + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); + if title = '' then title := XPathString('//title/substring-before(.," Manga - Read")'); authors := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[2]'); artists := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[3]'); genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); @@ -82,8 +66,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - v: IXQValue; - i: Integer; s: String; begin Result := False; @@ -91,26 +73,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; - s := ChapterLinks[CurrentDownloadChapterPtr]; - if RightStr(s, 6) = '1.html' then begin - SetLength(s, Length(s) - 6); - ChapterLinks[CurrentDownloadChapterPtr] := s; - end; - if GET(AppendURLDelim(FillHost(Module.RootURL, s)) + '1.html') then begin + if GET(MaybeFillHost(Module.RootURL, AURL) + '1.html') then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - v := XPath('//select[@onchange="change_page(this)"]/option'); - for i := v.Count downto 1 do begin - s := v.get(i).toNode.getAttribute('value'); - if s <> '0' then begin - PageNumber := StrToIntDef(s, 0); - Break; - end; - end; - finally - Free; - end; + PageNumber := XPathCount('//*[@id="top_bar"]//select[@onchange="change_page(this)"]/option[@value!="0"]', Document); end; end; end; @@ -121,17 +86,9 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(DownloadThread.WorkId) + '.html') then - begin + if GET(MaybeFillHost(Module.RootURL, AURL) + IncStr(DownloadThread.WorkId) + '.html') then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := - XPathString('//div[@class="read_img"]//img[@id="image"]/@src'); - finally - Free; - end; + PageLinks[DownloadThread.WorkId] := XPathString('//div[@class="read_img"]//img[@id="image"]/@src', Document); end; end; end; From 0cbea45189778f24f14ddf2ef8041353d298bc3b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Mar 2017 21:44:43 +0800 Subject: [PATCH 1694/2794] added hentaifox. closed #535 --- baseunits/ModuleList.inc | 1 + baseunits/modules/HentaiFox.pas | 107 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/HentaiFox.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ebe16bece..c2d0df339 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -59,6 +59,7 @@ uses MangaShiro, ReadMangaToday, MangaOnlineBR, + HentaiFox, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/HentaiFox.pas b/baseunits/modules/HentaiFox.pas new file mode 100644 index 000000000..c9b586239 --- /dev/null +++ b/baseunits/modules/HentaiFox.pas @@ -0,0 +1,107 @@ +unit HentaiFox; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, RegExpr; + +implementation + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL) then + begin + Result := NO_ERROR; + Page := StrToIntDef(XPathString('//*[@class="pagination"]/a[last()-1]', MangaInfo.FHTTP.Document), 1); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/pag/' + IncStr(AURL) + '/') then + begin + Result := NO_ERROR; + XPathHREFAll('//*[@class="galleries_overview"]//*[contains(@class,"item")]/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); + if title = '' then title := XPathString('//*[@class="info"]/h1'); + artists := XPathString('//*[@class="info"]/span[starts-with(.,"Artist")]/substring-after(.,": ")'); + genres := XPathString('//*[@class="info"]/string-join(./span/a,", ")'); + chapterLinks.Add(url); + chapterName.Add(title); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; + i: Integer; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + XPathStringAll('//*[@class="gallery"]//img/@data-src', Document, PageLinks); + if PageLinks.Count <> 0 then + begin + for i := 0 to PageLinks.Count - 1 do + begin + if LeftStr(PageLinks[i], 2) = '//' then + PageLinks[i] := 'https:' + PageLinks[i]; + end; + PageLinks.Text := ReplaceRegExpr('(?i)(/\d+)t\.', PageLinks.Text, '$1.', True); + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'HentaiFox'; + RootURL := 'https://hentaifox.com'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 2ac5659a3..cca6b6c3e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -20,5 +20,5 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From 662804215363159e7d19021f3fcc8225f226b674 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 16 Mar 2017 21:58:06 +0800 Subject: [PATCH 1695/2794] Bump version 0.9.104.0 --- changelog.txt | 7 ++++++- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index dde4a61aa..b4e26d6b5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,8 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.104.0 (16-03-2017) +[+] Added HentaiFox[H] +[*] Fixed memory leak +Full changes: https://github.com/riderkick/FMD/compare/0.9.103.0...0.9.104.0 + 0.9.103.0 (15-03-2017) -[+] Added MangaOnlineBR +[+] Added MangaOnlineBR[PT] [*] UnionMangas: exclude banner Full changes: https://github.com/riderkick/FMD/compare/0.9.102.0...0.9.103.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 87a401a34..15422697b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="103"/> + <RevisionNr Value="104"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 27c6e7d84..fb9df080e 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.103.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.103.0/fmd_0.9.103.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.103.0/fmd_0.9.103.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.103.0/fmd_0.9.103.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.103.0/fmd_0.9.103.0_Win64.7z +VERSION=0.9.104.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.104.0/fmd_0.9.104.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.104.0/fmd_0.9.104.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.104.0/fmd_0.9.104.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.104.0/fmd_0.9.104.0_Win64.7z From 02841e75fef010d782137b6310171b686d0e5de4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Mar 2017 03:20:25 +0800 Subject: [PATCH 1696/2794] store preferred filename for submodule besen and internettools --- 3rd/internettools | 2 +- mangadownloader/md.lpi | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 4ee1c88cf..eda74eed7 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 4ee1c88cfb263f36946f3f67a1329b5d225d48d7 +Subproject commit eda74eed78593411a219ad75e3617132172ecceb diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 15422697b..fd3dd880a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -200,6 +200,7 @@ <RequiredPackages Count="8"> <Item1> <PackageName Value="BESENPkg"/> + <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> </Item1> <Item2> <PackageName Value="multiloglaz"/> @@ -209,6 +210,7 @@ </Item3> <Item4> <PackageName Value="internettools"/> + <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item4> <Item5> <PackageName Value="TAChartLazarusPkg"/> From 1d5e0c132dc038f51c7d1202ebfefe9b1a588daa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 20 Mar 2017 06:58:01 +0800 Subject: [PATCH 1697/2794] downloadsmanager, mangasiteid use integer --- baseunits/uDownloadsManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index dcd52dabb..766d64734 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -141,7 +141,7 @@ TTaskContainer = class WorkCounter, DownCounter, PageNumber: Integer; - MangaSiteID: Cardinal; + MangaSiteID: Integer; ModuleId: Integer; //Status: TDownloadStatusType; ThreadState: Boolean; From 21193dc4a66707928981103e35f192ed64e74e47 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Wed, 22 Mar 2017 10:32:43 +0530 Subject: [PATCH 1698/2794] Fallen Angels Scans --- baseunits/modules/myMangaReaderCMS.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index f93f91e9f..d66c421e0 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -108,6 +108,7 @@ procedure RegisterModule; AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); AddWebsiteModule('MangaID', 'http://mangaid.co'); + AddWebsiteModule'FallenAngelsScans','http://manga.fascans.com'); end; initialization From 22ff19b14015f87a93488a0417332f2249fea67b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:10:12 +0800 Subject: [PATCH 1699/2794] added basethread - rename thttpthread with tbasethread and separate it from httpsenthread unit - tbasethread had objectlist that will be freed on destroy, xqueryengine need to be separated from its calculation so the cache can be cleared on thread destroy - xqueryenginehtml should be adapted to this and check the currentthread, if not mainthread then it will added the txqueryengine to objectlist to be freed later on destroy --- baseunits/BaseThread.pas | 73 ++++++++++++++++++++++++++++++++++++ baseunits/httpsendthread.pas | 49 +++--------------------- 2 files changed, 78 insertions(+), 44 deletions(-) create mode 100644 baseunits/BaseThread.pas diff --git a/baseunits/BaseThread.pas b/baseunits/BaseThread.pas new file mode 100644 index 000000000..f2a25dc33 --- /dev/null +++ b/baseunits/BaseThread.pas @@ -0,0 +1,73 @@ +unit BaseThread; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils; + +type + + { TBaseThread } + + TBaseThread = class(TThread) + private + FObjectList: TFPList; + FOnCustomTerminate: TNotifyEvent; + function GetTerminated: Boolean; + procedure CallOnCustomTerminate; inline; + public + constructor Create(CreateSuspended: Boolean = True); + destructor Destroy; override; + procedure Terminate; + property IsTerminated: Boolean read GetTerminated; + property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; + property ObjectList: TFPList read FObjectList; // Object to be freed on Destroy + end; + +implementation + +{ TBaseThread } + +function TBaseThread.GetTerminated: Boolean; +begin + Result := Self.Terminated; +end; + +procedure TBaseThread.CallOnCustomTerminate; +begin + FOnCustomTerminate(Self); +end; + +constructor TBaseThread.Create(CreateSuspended: Boolean); +begin + inherited Create(CreateSuspended); + FreeOnTerminate := True; + FObjectList := TFPList.Create; +end; + +destructor TBaseThread.Destroy; +var + i: Integer; +begin + if FObjectList.Count <> 0 then + for i := 0 to FObjectList.Count - 1 do + if Assigned(FObjectList[i]) then + try + TObject(FObjectList[i]).Free; + except + end; + FObjectList.Free; + inherited Destroy; +end; + +procedure TBaseThread.Terminate; +begin + inherited Terminate; + if Assigned(FOnCustomTerminate) then + FOnCustomTerminate(Self); +end; + +end. + diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index ad51d1ad2..d1454d151 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,29 +6,15 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - GZIPUtils; + GZIPUtils, BaseThread; type - { THTTPThread } - - THTTPThread = class(TThread) - private - FOnCustomTerminate: TNotifyEvent; - function GetTerminated: Boolean; - procedure CallOnCustomTerminate; inline; - public - constructor Create(CreateSuspended: Boolean = True); - procedure Terminate; - property IsTerminated: Boolean read GetTerminated; - property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; - end; - { THTTPSendThread } THTTPSendThread = class(THTTPSend) private - FOwner: THTTPThread; + FOwner: TBaseThread; FRetryCount: Integer; FGZip: Boolean; FFollowRedirection: Boolean; @@ -36,7 +22,7 @@ THTTPSendThread = class(THTTPSend) procedure SetTimeout(AValue: Integer); procedure OnOwnerTerminate(Sender: TObject); public - constructor Create(AOwner: THTTPThread = nil); + constructor Create(AOwner: TBaseThread = nil); destructor Destroy; override; function HTTPRequest(const Method, URL: String; const Response: TObject = nil): Boolean; function HEAD(const URL: String; const Response: TObject = nil): Boolean; @@ -53,7 +39,7 @@ THTTPSendThread = class(THTTPSend) property GZip: Boolean read FGZip write FGZip; property FollowRedirection: Boolean read FFollowRedirection write FFollowRedirection; property AllowServerErrorResponse: Boolean read FAllowServerErrorResponse write FAllowServerErrorResponse; - property Thread: THTTPThread read FOwner; + property Thread: TBaseThread read FOwner; end; TKeyValuePair = array[0..1] of String; @@ -276,31 +262,6 @@ function MaybeEncodeURL(const AValue: String): String; Result := EncodeURL(Result); end; -{ THTTPThread } - -function THTTPThread.GetTerminated: Boolean; -begin - Result := Self.Terminated; -end; - -procedure THTTPThread.CallOnCustomTerminate; -begin - FOnCustomTerminate(Self); -end; - -constructor THTTPThread.Create(CreateSuspended: Boolean); -begin - inherited Create(CreateSuspended); - FreeOnTerminate := True; -end; - -procedure THTTPThread.Terminate; -begin - inherited Terminate; - if Assigned(FOnCustomTerminate) then - FOnCustomTerminate(Self); -end; - { THTTPSendThread } procedure THTTPSendThread.SetTimeout(AValue: Integer); @@ -317,7 +278,7 @@ procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); Sock.AbortSocket; end; -constructor THTTPSendThread.Create(AOwner: THTTPThread); +constructor THTTPSendThread.Create(AOwner: TBaseThread); begin inherited Create; KeepAlive := True; From 6d985c5a9f75c6c6ca41dc62802e5cd4db4c1946 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:19:51 +0800 Subject: [PATCH 1700/2794] mangafox, cleanups --- baseunits/modules/MangaFox.pas | 2 -- 1 file changed, 2 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index afae63539..a8fc4e02a 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -65,8 +65,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; begin Result := False; if DownloadThread = nil then Exit; From 96f7d0771facb18574dce6edcf907a6a88690016 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:24:33 +0800 Subject: [PATCH 1701/2794] replaced thttpthread withtbasethread --- baseunits/CheckUpdate.pas | 5 +++-- baseunits/uData.pas | 6 +++--- baseunits/uDownloadsManager.pas | 6 +++--- baseunits/uFavoritesManager.pas | 6 +++--- baseunits/uGetMangaInfosThread.pas | 5 +++-- baseunits/uSilentThread.pas | 6 +++--- baseunits/uUpdateThread.pas | 7 ++++--- mangadownloader/forms/frmAccountManager.pas | 4 ++-- updater/uMain.pas | 4 ++-- 9 files changed, 26 insertions(+), 23 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 7dc60d3db..189086fd4 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -10,11 +10,12 @@ interface uses - Classes, SysUtils, Forms, Controls, uBaseUnit, FMDOptions, httpsendthread; + Classes, SysUtils, Forms, Controls, uBaseUnit, FMDOptions, httpsendthread, + BaseThread; type - TCheckUpdateThread = class(THTTPThread) + TCheckUpdateThread = class(TBaseThread) private FHTTP: THTTPSendThread; fNewVersionNumber, fUpdateURL, fChangelog: String; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9cfa2a9cc..7becd3fa6 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -15,7 +15,7 @@ interface uses Classes, SysUtils, uBaseUnit, DBDataProcess, FMDOptions, httpsendthread, - LazFileUtils, strutils, RegExpr, httpsend, MultiLog; + BaseThread, LazFileUtils, strutils, RegExpr, httpsend, MultiLog; type @@ -89,7 +89,7 @@ TMangaInformation = class(TObject) procedure OnTag(NoCaseTag, ActualTag: String); procedure OnText(AText: String); - constructor Create(AOwnerThread: THTTPThread = nil; ACreateInfo: Boolean = True); + constructor Create(AOwnerThread: TBaseThread = nil; ACreateInfo: Boolean = True); destructor Destroy; override; procedure ClearInfo; function GetDirectoryPage(var APage: Integer; const AWebsite: String): Byte; @@ -713,7 +713,7 @@ procedure TDataProcess.Sort; { TMangaInformation } -constructor TMangaInformation.Create(AOwnerThread: THTTPThread; ACreateInfo: Boolean); +constructor TMangaInformation.Create(AOwnerThread: TBaseThread; ACreateInfo: Boolean); begin inherited Create; FHTTP := THTTPSendThread.Create(AOwnerThread); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 766d64734..fdf0a1e22 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -18,7 +18,7 @@ interface LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, IniFiles, Classes, SysUtils, ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, uMisc, DownloadedChaptersDB, FMDOptions, httpsendthread, DownloadsDB, - dateutils, strutils; + BaseThread, dateutils, strutils; type TDownloadStatusType = ( @@ -40,7 +40,7 @@ TTaskThread = class; { TDownloadThread } - TDownloadThread = class(THTTPThread) + TDownloadThread = class(TBaseThread) private parse: TStringList; public @@ -75,7 +75,7 @@ TDownloadThread = class(THTTPThread) { TTaskThread } - TTaskThread = class(THTTPThread) + TTaskThread = class(TBaseThread) private FCS_THREADS: TRTLCriticalSection; FCheckAndActiveTaskFlag: Boolean; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index aa13697c0..c06f7afd0 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -13,7 +13,7 @@ interface uses Classes, SysUtils, fgl, Dialogs, IniFiles, lazutf8classes, LazFileUtils, uBaseUnit, uData, uDownloadsManager, WebsiteModules, - FMDOptions, httpsendthread, FavoritesDB, SimpleException; + FMDOptions, httpsendthread, FavoritesDB, BaseThread, SimpleException; type TFavoriteManager = class; @@ -22,7 +22,7 @@ TfavoriteContainer = class; { TFavoriteThread } - TFavoriteThread = class(THTTPThread) + TFavoriteThread = class(TBaseThread) private FMangaInformation: TMangaInformation; protected @@ -40,7 +40,7 @@ TFavoriteThread = class(THTTPThread) { TFavoriteTask } - TFavoriteTask = class(THTTPThread) + TFavoriteTask = class(TBaseThread) private FBtnCaption: String; FPendingCount: Integer; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 4195042e5..fb96b740f 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -16,13 +16,14 @@ interface uses - SysUtils, Graphics, Dialogs, uBaseUnit, uData, httpsendthread, FMDOptions; + SysUtils, Graphics, Dialogs, uBaseUnit, uData, httpsendthread, FMDOptions, + BaseThread; type { TGetMangaInfosThread } - TGetMangaInfosThread = class(THTTPThread) + TGetMangaInfosThread = class(TBaseThread) protected FMangaListPos: Integer; FCover: TPicture; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 8405e6e57..e99638954 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -16,7 +16,7 @@ interface uses SysUtils, fgl, uBaseUnit, uData, uDownloadsManager, - WebsiteModules, FMDOptions, httpsendthread, LazFileUtils; + WebsiteModules, FMDOptions, httpsendthread, BaseThread, LazFileUtils; type @@ -36,7 +36,7 @@ TSilentThreadManager = class; { TSilentThread } - TSilentThread = class(THTTPThread) + TSilentThread = class(TBaseThread) protected FSavePath: String; Info: TMangaInformation; @@ -62,7 +62,7 @@ TSilentAddToFavThread = class(TSilentThread) { TSilentThreadManagerThread } - TSilentThreadManagerThread = class(THTTPThread) + TSilentThreadManagerThread = class(TBaseThread) protected procedure Checkout; procedure Execute; override; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 16beba8af..e2ca539ae 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -12,14 +12,15 @@ interface uses Classes, SysUtils, typinfo, uData, LazFileUtils, uBaseUnit, uMisc, - WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread, MultiLog; + WebsiteModules, DBDataProcess, SimpleTranslator, FMDOptions, httpsendthread, + BaseThread, MultiLog; type TUpdateListManagerThread = class; { TUpdateListThread } - TUpdateListThread = class(THTTPThread) + TUpdateListThread = class(TBaseThread) protected Info: TMangaInformation; checkStyle: TCheckStyleType; @@ -35,7 +36,7 @@ TUpdateListThread = class(THTTPThread) { TUpdateListManagerThread } - TUpdateListManagerThread = class(THTTPThread) + TUpdateListManagerThread = class(TBaseThread) private FStatus: String; FCommitCount: Integer; diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 4b4280870..722da7787 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, - FMDOptions, HTTPSendThread, frmAccountSet, SimpleException; + FMDOptions, HTTPSendThread, BaseThread, frmAccountSet, SimpleException; type @@ -58,7 +58,7 @@ TAccountCheck = class; { TAccountCheckThread } - TAccountCheckThread = class(THTTPThread) + TAccountCheckThread = class(TBaseThread) private fwebsite: String; fhttp: THTTPSendThread; diff --git a/updater/uMain.pas b/updater/uMain.pas index 14794c94c..5cd4cabb3 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -11,7 +11,7 @@ interface {$endif} Classes, SysUtils, zipper, FileUtil, LazFileUtils, LazUTF8, LazUTF8Classes, Forms, Dialogs, ComCtrls, StdCtrls, ExtCtrls, RegExpr, IniFiles, blcksock, - ssl_openssl, ssl_openssl_lib, synacode, httpsendthread, uMisc, + ssl_openssl, ssl_openssl_lib, synacode, httpsendthread, uMisc, BaseThread, SimpleTranslator, SimpleException; type @@ -39,7 +39,7 @@ TfrmMain = class(TForm) { TDownloadThread } - TDownloadThread = class(THTTPThread) + TDownloadThread = class(TBaseThread) private FTotalSize, FCurrentSize: Integer; FHTTP: THTTPSendThread; From 6bf612747205b708b92af1cf955b245c03f958c4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:28:06 +0800 Subject: [PATCH 1702/2794] typo --- baseunits/modules/myMangaReaderCMS.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index d66c421e0..958fa96e0 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -108,7 +108,7 @@ procedure RegisterModule; AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); AddWebsiteModule('MangaID', 'http://mangaid.co'); - AddWebsiteModule'FallenAngelsScans','http://manga.fascans.com'); + AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); end; initialization From 6912c92be74d3c867fa75e5fa381453c7fd07b1a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:34:42 +0800 Subject: [PATCH 1703/2794] debugleak with more checks --- mangadownloader/md.lpi | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index fd3dd880a..1b7edab25 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -79,7 +79,17 @@ <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> <TargetCPU Value="i386"/> <TargetOS Value="win32"/> <Optimizations> @@ -120,7 +130,17 @@ <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> <TargetCPU Value="x86_64"/> <TargetOS Value="win64"/> <Optimizations> @@ -158,7 +178,18 @@ <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> <TargetCPU Value="i386"/> <TargetOS Value="win32"/> <Optimizations> From f5852f1a1be1ba92bb1fc82268c4d8ea72e8a67e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:36:37 +0800 Subject: [PATCH 1704/2794] xqueryenginehtml use tbasethread to free the engine instead. should be cleanup the memory leak --- baseunits/XQueryEngineHTML.pas | 140 ++++++++++++++++++++++++++------- 1 file changed, 113 insertions(+), 27 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 0f20f3609..d150be4db 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, xquery, xquery_json, simplehtmltreeparser; + Classes, SysUtils, xquery, xquery_json, simplehtmltreeparser, BaseThread; type @@ -13,10 +13,15 @@ interface TXQueryEngineHTML = class private + FIsMainThread: Boolean; FEngine: TXQueryEngine; FTreeParser: TTreeParser; function Eval(const Expression: String; const isCSS: Boolean = False; const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): IXQValue; + function EvalString(const Expression: String; const isCSS: Boolean = False; + const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): String; + function EvalCount(const Expression: String; const isCSS: Boolean = False; + const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): Integer; function EvalStringAll(const Expression: String; const isCSS: Boolean; const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; function EvalStringAll(const Expression: String; const isCSS: Boolean; @@ -35,6 +40,8 @@ TXQueryEngineHTML = class function XPath(const Expression: String; const ContextItem: IXQValue): IXQValue; inline; function XPathString(const Expression: String; const Tree: TTreeNode = nil): String; inline; function XPathString(const Expression: String; const ContextItem: IXQValue): String; inline; + function XPathCount(const Expression: String; const Tree: TTreeNode = nil): Integer; inline; + function XPathCount(const Expression: String; const ContextItem: IXQValue): Integer; inline; function XPathStringAll(const Expression: String; const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; inline; function XPathStringAll(const Expression: String; const Exc: array of String; @@ -66,7 +73,7 @@ TXQueryEngineHTML = class function XPathString(const Expression, HTMLString: String): String; overload; function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; -function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; overload; +function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; const TheStrings: TStrings); procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); procedure XPathHREFtitleAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATitles: TStrings); @@ -111,7 +118,7 @@ function XPathString(const Expression, HTMLString: String): String; Result := ''; with TXQueryEngineHTML.Create(HTMLString) do try - Result := XPath(Expression).toString; + Result := XPathString(Expression); finally Free; end; @@ -127,7 +134,7 @@ function XPathCount(const Expression: String; const HTMLStream: TStream): Intege Result := 0; with TXQueryEngineHTML.Create(HTMLStream) do try - Result := XPath(Expression).Count; + Result := XPathCount(Expression); finally Free; end; @@ -198,41 +205,95 @@ function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; end; end; +function TXQueryEngineHTML.EvalString(const Expression: String; + const isCSS: Boolean; const ContextItem: IXQValue; const Tree: TTreeNode + ): String; +var + v: IXQValue; +begin + v := Eval(Expression, isCSS, ContextItem, Tree); + Result := v.toString; + v := nil; +end; + +function TXQueryEngineHTML.EvalCount(const Expression: String; + const isCSS: Boolean; const ContextItem: IXQValue; const Tree: TTreeNode + ): Integer; +var + v: IXQValue; +begin + v := Eval(Expression, isCSS, ContextItem, Tree); + Result := v.Count; + v := nil; +end; + function TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; const Separator: String; const ContextItem: IXQValue): String; var - v: IXQValue; + v, x: IXQValue; + i: Integer; begin Result := ''; - for v in Eval(Expression, isCSS, ContextItem) do - AddSeparatorString(Result, v.toString, Separator); + v := Eval(Expression, isCSS, ContextItem); + for i := 1 to v.Count do + begin + x := v.get(i); + AddSeparatorString(Result, x.toString, Separator); + end; + x := nil; + v := nil; end; function TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; const Exc: array of String; const Separator: String; const ContextItem: IXQValue ): String; var - v: IXQValue; + v, x: IXQValue; + i: Integer; begin Result := ''; - for v in Eval(Expression, isCSS, ContextItem) do - if StringInArray(Trim(v.toString), Exc) = False then - AddSeparatorString(Result, v.toString, Separator); + v := Eval(Expression, isCSS, ContextItem); + for i := 1 to v.Count do + begin + x := v.get(i); + if not StringInArray(Trim(x.toString), Exc) then + AddSeparatorString(Result, x.toString, Separator); + end; + x := nil; + v := nil; end; procedure TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; const TheStrings: TStrings; ContextItem: IXQValue); var - v: IXQValue; + v, x: IXQValue; + i: Integer; begin - for v in Eval(Expression, isCSS, ContextItem) do - TheStrings.Add(v.toString); + v := Eval(Expression, isCSS, ContextItem); + for i := 1 to v.Count do + begin + x := v.get(i); + TheStrings.Add(x.toString); + end; + x := nil; + v := nil; end; constructor TXQueryEngineHTML.Create(const HTML: String); +var + ct: TThread; begin + FIsMainThread := GetThreadID = MainThreadID; FEngine := TXQueryEngine.Create; FTreeParser := TTreeParser.Create; + if not FIsMainThread then + begin + ct := TThread.CurrentThread; + if ct is TBaseThread then + TBaseThread(ct).ObjectList.Add(FEngine) + else + FIsMainThread := True; + end; with FTreeParser do begin parsingModel := pmHTML; @@ -257,7 +318,10 @@ constructor TXQueryEngineHTML.Create(const HTMLStream: TStream); destructor TXQueryEngineHTML.Destroy; begin - FEngine.Free; + if FIsMainThread then + FEngine.Free + else + FEngine := nil; FTreeParser.Free; inherited Destroy; end; @@ -286,13 +350,25 @@ function TXQueryEngineHTML.XPath(const Expression: String; const ContextItem: IX function TXQueryEngineHTML.XPathString(const Expression: String; const Tree: TTreeNode): String; begin - Result := Eval(Expression, False, nil, Tree).toString; + Result := EvalString(Expression, False, nil, Tree); end; function TXQueryEngineHTML.XPathString(const Expression: String; const ContextItem: IXQValue): String; begin - Result := Eval(Expression, False, ContextItem).toString; + Result := EvalString(Expression, False, ContextItem); +end; + +function TXQueryEngineHTML.XPathCount(const Expression: String; + const Tree: TTreeNode): Integer; +begin + Result := EvalCount(Expression, False, nil, Tree); +end; + +function TXQueryEngineHTML.XPathCount(const Expression: String; + const ContextItem: IXQValue): Integer; +begin + Result := EvalCount(Expression, False, ContextItem); end; function TXQueryEngineHTML.XPathStringAll(const Expression: String; @@ -317,25 +393,35 @@ procedure TXQueryEngineHTML.XPathStringAll(const Expression: String; procedure TXQueryEngineHTML.XPathHREFAll(const Expression: String; const ALinks, ATexts: TStrings; const ContextItem: IXQValue); var - v: IXQValue; + v, x: IXQValue; + i: Integer; begin - for v in Eval(Expression, False, ContextItem) do + v := Eval(Expression, False, ContextItem); + for i := 1 to v.Count do begin - ALinks.Add(v.toNode.getAttribute('href')); - ATexts.Add(v.toString); + x := v.get(i); + ALinks.Add(x.toNode.getAttribute('href')); + ATexts.Add(x.toString); end; + x := nil; + v := nil; end; procedure TXQueryEngineHTML.XPathHREFtitleAll(const Expression: String; const ALinks, ATitles: TStrings; const ContextItem: IXQValue); var - v: IXQValue; + v, x: IXQValue; + i: Integer; begin - for v in Eval(Expression, False, ContextItem) do + v := Eval(Expression, False, ContextItem); + for i := 1 to v.Count do begin - ALinks.Add(v.toNode.getAttribute('href')); - ATitles.Add(v.toNode.getAttribute('title')); + x := v.get(i); + ALinks.Add(x.toNode.getAttribute('href')); + ATitles.Add(x.toNode.getAttribute('title')); end; + x := nil; + v := nil; end; function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; @@ -351,13 +437,13 @@ function TXQueryEngineHTML.CSS(const Expression: String; const ContextItem: IXQV function TXQueryEngineHTML.CSSString(const Expression: String; const Tree: TTreeNode): String; begin - Result := Eval(Expression, True, nil, Tree).toString; + Result := EvalString(Expression, True, nil, Tree); end; function TXQueryEngineHTML.CSSString(const Expression: String; const ContextItem: IXQValue): String; begin - Result := Eval(Expression, True, ContextItem).toString; + Result := EvalString(Expression, True, ContextItem); end; function TXQueryEngineHTML.CSSStringAll(const Expression: String; From c8191061e9be2f6fae412cc376dc5ea461d01c06 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:42:26 +0800 Subject: [PATCH 1705/2794] added fallenangelsscan to mangalist --- config/mangalist.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index cca6b6c3e..305788013 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics Italian=MangaEden_IT,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake +English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik From ba547077d24cf001b10d3c249f7411fc3a5b47c1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 21:53:00 +0800 Subject: [PATCH 1706/2794] udata, change all websiteid with mangasiteid, an integer --- baseunits/uData.pas | 256 ++++++++++++++++++++++---------------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 7becd3fa6..363ca732b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -768,7 +768,7 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: p: Integer; Source: TStringList; Parser: THTMLParser; - WebsiteID: Cardinal; + MangaSiteID: Integer; {$I includes/AnimeA/directory_page_number.inc} @@ -835,75 +835,75 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: Result := Modules.GetDirectoryPageNumber(Self, APage, ModuleId) else begin - WebsiteID := GetMangaSiteID(AWebsite); + MangaSiteID := GetMangaSiteID(AWebsite); Source := TStringList.Create; - if WebsiteID = ANIMEA_ID then + if MangaSiteID = ANIMEA_ID then Result := GetAnimeADirectoryPageNumber else - if WebsiteID = MANGA24H_ID then + if MangaSiteID = MANGA24H_ID then Result := GetManga24hDirectoryPageNumber else - if WebsiteID = VNSHARING_ID then + if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if WebsiteID = FAKKU_ID then + if MangaSiteID = FAKKU_ID then Result := GetFakkuDirectoryPageNumber else - if WebsiteID = BLOGTRUYEN_ID then + if MangaSiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenDirectoryPageNumber else - if WebsiteID = S2SCAN_ID then + if MangaSiteID = S2SCAN_ID then Result := GetS2ScanDirectoryPageNumber else - if WebsiteID = LECTUREENLIGNE_ID then + if MangaSiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLigneDirectoryPageNumber else - if WebsiteID = MANGAAE_ID then + if MangaSiteID = MANGAAE_ID then Result := GetMangaAeDirectoryPageNumber else - if WebsiteID = CENTRALDEMANGAS_ID then + if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasDirectoryPageNumber else - if WebsiteID = DM5_ID then + if MangaSiteID = DM5_ID then Result := GetDM5DirectoryPageNumber else - if (WebsiteID = NINEMANGA_ID) or - (WebsiteID = NINEMANGA_ES_ID) or - (WebsiteID = NINEMANGA_CN_ID) or - (WebsiteID = NINEMANGA_RU_ID) or - (WebsiteID = NINEMANGA_DE_ID) or - (WebsiteID = NINEMANGA_IT_ID) or - (WebsiteID = NINEMANGA_BR_ID) then + if (MangaSiteID = NINEMANGA_ID) or + (MangaSiteID = NINEMANGA_ES_ID) or + (MangaSiteID = NINEMANGA_CN_ID) or + (MangaSiteID = NINEMANGA_RU_ID) or + (MangaSiteID = NINEMANGA_DE_ID) or + (MangaSiteID = NINEMANGA_IT_ID) or + (MangaSiteID = NINEMANGA_BR_ID) then Result := GetNineMangaDirectoryPageNumber else - if WebsiteID = JAPANSHIN_ID then + if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinDirectoryPageNumber else - if WebsiteID = ONEMANGA_ID then + if MangaSiteID = ONEMANGA_ID then Result := GetOneMangaDirectoryPageNumber else - if WebsiteID = MANGATOWN_ID then + if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownDirectoryPageNumber else - if WebsiteID = MYREADINGMANGAINFO_ID then + if MangaSiteID = MYREADINGMANGAINFO_ID then Result := GetMyReadingMangaInfoDirectoryPageNumber else - if WebsiteID = IKOMIK_ID then + if MangaSiteID = IKOMIK_ID then Result := GetIKomikDirectoryPageNumber else - if WebsiteID = NHENTAI_ID then + if MangaSiteID = NHENTAI_ID then Result := GetNHentaiDirectoryPageNumber else - if WebsiteID = MANGAMINT_ID then + if MangaSiteID = MANGAMINT_ID then Result := GetMangaMintDirectoryPageNumber else - if WebsiteID = MANGAHOST_ID then + if MangaSiteID = MANGAHOST_ID then Result := GetMangaHostDirectoryPageNumber else - if WebsiteID = MANGAAT_ID then + if MangaSiteID = MANGAAT_ID then Result := GetMangaAtDirectoryPageNumber else - if WebsiteID = DYNASTYSCANS_ID then + if MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansDirectoryPageNumber else begin @@ -923,7 +923,7 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; var Source: TStringList; Parser: THTMLParser; - WebsiteID: Cardinal; + MangaSiteID: Integer; {$I includes/AnimeA/names_and_links.inc} @@ -1017,135 +1017,135 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; Result := Modules.GetNameAndLink(Self, ANames, ALinks, AURL, ModuleId) else begin - WebsiteID := GetMangaSiteID(AWebsite); + MangaSiteID := GetMangaSiteID(AWebsite); Source := TStringList.Create; - if WebsiteID = ANIMEA_ID then + if MangaSiteID = ANIMEA_ID then Result := AnimeAGetNamesAndLinks else - if WebsiteID = MANGA24H_ID then + if MangaSiteID = MANGA24H_ID then Result := Manga24hGetNamesAndLinks else - if WebsiteID = VNSHARING_ID then + if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else - if WebsiteID = FAKKU_ID then + if MangaSiteID = FAKKU_ID then Result := FakkuGetNamesAndLinks else - if WebsiteID = STARKANA_ID then + if MangaSiteID = STARKANA_ID then Result := StarkanaGetNamesAndLinks else - if WebsiteID = EATMANGA_ID then + if MangaSiteID = EATMANGA_ID then Result := EatMangaGetNamesAndLinks else - if WebsiteID = S2SCAN_ID then + if MangaSiteID = S2SCAN_ID then Result := S2ScanGetNamesAndLinks else - if WebsiteID = EGSCANS_ID then + if MangaSiteID = EGSCANS_ID then Result := EGScansGetNamesAndLinks else - if WebsiteID = MEINMANGA_ID then + if MangaSiteID = MEINMANGA_ID then Result := MeinMangaGetNamesAndLinks else - if WebsiteID = BLOGTRUYEN_ID then + if MangaSiteID = BLOGTRUYEN_ID then Result := BlogTruyenGetNamesAndLinks else - if WebsiteID = TRUYENTRANHTUAN_ID then + if MangaSiteID = TRUYENTRANHTUAN_ID then Result := TruyenTranhTuanGetNamesAndLinks else - if WebsiteID = ESMANGAHERE_ID then + if MangaSiteID = ESMANGAHERE_ID then Result := EsMangaHereGetNamesAndLinks else - if WebsiteID = ANIMEEXTREMIST_ID then + if MangaSiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else - if WebsiteID = ANIMESTORY_ID then + if MangaSiteID = ANIMESTORY_ID then Result := AnimeStoryGetNamesAndLinks else - if WebsiteID = LECTUREENLIGNE_ID then + if MangaSiteID = LECTUREENLIGNE_ID then Result := LectureEnLigneGetNamesAndLinks else - if WebsiteID = SCANMANGA_ID then + if MangaSiteID = SCANMANGA_ID then Result := ScanMangaGetNamesAndLinks else - if WebsiteID = MANGAAR_ID then + if MangaSiteID = MANGAAR_ID then Result := MangaArGetNamesAndLinks else - if WebsiteID = MANGAAE_ID then + if MangaSiteID = MANGAAE_ID then Result := MangaAeGetNamesAndLinks else - if WebsiteID = CENTRALDEMANGAS_ID then + if MangaSiteID = CENTRALDEMANGAS_ID then Result := CentralDeMangasGetNamesAndLinks else - if WebsiteID = IMANHUA_ID then + if MangaSiteID = IMANHUA_ID then Result := imanhuaGetNamesAndLinks else - if WebsiteID = TURKCRAFT_ID then + if MangaSiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else - if WebsiteID = KIVMANGA_ID then + if MangaSiteID = KIVMANGA_ID then Result := KivmangaGetNamesAndLinks else - if WebsiteID = MANGASPROJECT_ID then + if MangaSiteID = MANGASPROJECT_ID then Result := MangasPROJECTGetNamesAndLinks else - if WebsiteID = MANGAREADER_POR_ID then + if MangaSiteID = MANGAREADER_POR_ID then Result := MangaREADER_PORGetNamesAndLinks else - if (WebsiteID = NINEMANGA_ID) or - (WebsiteID = NINEMANGA_ES_ID) or - (WebsiteID = NINEMANGA_CN_ID) or - (WebsiteID = NINEMANGA_RU_ID) or - (WebsiteID = NINEMANGA_DE_ID) or - (WebsiteID = NINEMANGA_IT_ID) or - (WebsiteID = NINEMANGA_BR_ID) then + if (MangaSiteID = NINEMANGA_ID) or + (MangaSiteID = NINEMANGA_ES_ID) or + (MangaSiteID = NINEMANGA_CN_ID) or + (MangaSiteID = NINEMANGA_RU_ID) or + (MangaSiteID = NINEMANGA_DE_ID) or + (MangaSiteID = NINEMANGA_IT_ID) or + (MangaSiteID = NINEMANGA_BR_ID) then Result := NineMangaGetNamesAndLinks else - if WebsiteID = JAPANSHIN_ID then + if MangaSiteID = JAPANSHIN_ID then Result := JapanShinGetNamesAndLinks else - if WebsiteID = CENTRUMMANGI_PL_ID then + if MangaSiteID = CENTRUMMANGI_PL_ID then Result := CentrumMangi_PLGetNamesAndLinks else - if WebsiteID = MANGALIB_PL_ID then + if MangaSiteID = MANGALIB_PL_ID then Result := MangaLib_PLGetNamesAndLinks else - if WebsiteID = ONEMANGA_ID then + if MangaSiteID = ONEMANGA_ID then Result := OneMangaGetNamesAndLinks else - if WebsiteID = MANGATOWN_ID then + if MangaSiteID = MANGATOWN_ID then Result := MangaTownGetNamesAndLinks else - if WebsiteID = MANGAOKU_ID then + if MangaSiteID = MANGAOKU_ID then Result := MangaOkuGetNamesAndLinks else - if WebsiteID = MYREADINGMANGAINFO_ID then + if MangaSiteID = MYREADINGMANGAINFO_ID then Result := MyReadingMangaInfoNamesAndLinks else - if WebsiteID = IKOMIK_ID then + if MangaSiteID = IKOMIK_ID then Result := IKomikNamesAndLinks else - if WebsiteID = NHENTAI_ID then + if MangaSiteID = NHENTAI_ID then Result := NHentaiNamesAndLinks else - if WebsiteID = MANGAMINT_ID then + if MangaSiteID = MANGAMINT_ID then Result := MangaMintGetNamesAndLinks else - if WebsiteID = UNIXMANGA_ID then + if MangaSiteID = UNIXMANGA_ID then Result := UnixMangaNamesAndLinks else - if WebsiteID = EXTREMEMANGAS_ID then + if MangaSiteID = EXTREMEMANGAS_ID then Result := ExtremeMangasNamesAndLinks else - if WebsiteID = MANGAHOST_ID then + if MangaSiteID = MANGAHOST_ID then Result := MangaHostGetNamesAndLinks else - if WebsiteID = MANGAKU_ID then + if MangaSiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks else - if WebsiteID = MANGAAT_ID then + if MangaSiteID = MANGAAT_ID then Result := MangaAtGetNamesAndLinks else - if WebsiteID = DYNASTYSCANS_ID then + if MangaSiteID = DYNASTYSCANS_ID then Result := DynastyScansGetNamesAndLinks else begin @@ -1166,7 +1166,7 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR del: Boolean; Source: TStringList; Parser: THTMLParser; - WebsiteID: Cardinal; + MangaSiteID: Integer; {$I includes/AnimeA/manga_information.inc} @@ -1272,135 +1272,135 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR end else begin - WebsiteID := GetMangaSiteID(AWebsite); - if WebsiteID > High(WebsiteRoots) then + MangaSiteID := GetMangaSiteID(AWebsite); + if MangaSiteID > High(WebsiteRoots) then Exit(INFORMATION_NOT_FOUND); - mangaInfo.url := FillMangaSiteHost(WebsiteID, AURL); + mangaInfo.url := FillMangaSiteHost(MangaSiteID, AURL); Source := TStringList.Create; - if WebsiteID = ANIMEA_ID then + if MangaSiteID = ANIMEA_ID then Result := GetAnimeAInfoFromURL else - if WebsiteID = MANGA24H_ID then + if MangaSiteID = MANGA24H_ID then Result := GetManga24hInfoFromURL else - if WebsiteID = VNSHARING_ID then + if MangaSiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else - if WebsiteID = FAKKU_ID then + if MangaSiteID = FAKKU_ID then Result := GetFakkuInfoFromURL else - if WebsiteID = STARKANA_ID then + if MangaSiteID = STARKANA_ID then Result := GetStarkanaInfoFromURL else - if WebsiteID = EATMANGA_ID then + if MangaSiteID = EATMANGA_ID then Result := GetEatMangaInfoFromURL else - if WebsiteID = S2SCAN_ID then + if MangaSiteID = S2SCAN_ID then Result := GetS2scanInfoFromURL else - if WebsiteID = EGSCANS_ID then + if MangaSiteID = EGSCANS_ID then Result := GetEGScansInfoFromURL else - if WebsiteID = TRUYENTRANHTUAN_ID then + if MangaSiteID = TRUYENTRANHTUAN_ID then Result := GetTruyenTranhTuanInfoFromURL else - if WebsiteID = MEINMANGA_ID then + if MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaInfoFromURL else - if WebsiteID = ESMANGAHERE_ID then + if MangaSiteID = ESMANGAHERE_ID then Result := GetEsMangaHereInfoFromURL else - if WebsiteID = ANIMEEXTREMIST_ID then + if MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else - if WebsiteID = ANIMESTORY_ID then + if MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryInfoFromURL else - if WebsiteID = LECTUREENLIGNE_ID then + if MangaSiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLigneInfoFromURL else - if WebsiteID = SCANMANGA_ID then + if MangaSiteID = SCANMANGA_ID then Result := GetScanMangaInfoFromURL else - if WebsiteID = TURKCRAFT_ID then + if MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftInfoFromURL else - if WebsiteID = MANGAAR_ID then + if MangaSiteID = MANGAAR_ID then Result := GetMangaArInfoFromURL else - if WebsiteID = MANGAAE_ID then + if MangaSiteID = MANGAAE_ID then Result := GetMangaAeInfoFromURL else - if WebsiteID = CENTRALDEMANGAS_ID then + if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else - if WebsiteID = BLOGTRUYEN_ID then + if MangaSiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenInfoFromURL else - if WebsiteID = KIVMANGA_ID then + if MangaSiteID = KIVMANGA_ID then Result := GetKivmangaInfoFromURL else - if WebsiteID = MANGASPROJECT_ID then + if MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTInfoFromURL else - if WebsiteID = MANGAREADER_POR_ID then + if MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORInfoFromURL else - if (WebsiteID = NINEMANGA_ID) or - (WebsiteID = NINEMANGA_ES_ID) or - (WebsiteID = NINEMANGA_CN_ID) or - (WebsiteID = NINEMANGA_RU_ID) or - (WebsiteID = NINEMANGA_DE_ID) or - (WebsiteID = NINEMANGA_IT_ID) or - (WebsiteID = NINEMANGA_BR_ID) then + if (MangaSiteID = NINEMANGA_ID) or + (MangaSiteID = NINEMANGA_ES_ID) or + (MangaSiteID = NINEMANGA_CN_ID) or + (MangaSiteID = NINEMANGA_RU_ID) or + (MangaSiteID = NINEMANGA_DE_ID) or + (MangaSiteID = NINEMANGA_IT_ID) or + (MangaSiteID = NINEMANGA_BR_ID) then Result := GetNineMangaInfoFromURL else - if WebsiteID = JAPANSHIN_ID then + if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinInfoFromURL else - if WebsiteID = CENTRUMMANGI_PL_ID then + if MangaSiteID = CENTRUMMANGI_PL_ID then Result := GetCentrumMangi_PLInfoFromURL else - if WebsiteID = MANGALIB_PL_ID then + if MangaSiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLInfoFromURL else - if WebsiteID = ONEMANGA_ID then + if MangaSiteID = ONEMANGA_ID then Result := GetOneMangaInfoFromURL else - if WebsiteID = MANGATOWN_ID then + if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownInfoFromURL else - if WebsiteID = MANGAOKU_ID then + if MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuInfoFromURL else - if WebsiteID = MYREADINGMANGAINFO_ID then + if MangaSiteID = MYREADINGMANGAINFO_ID then Result := GetMyReadingMangaInfoInfoFromURL else - if WebsiteID = IKOMIK_ID then + if MangaSiteID = IKOMIK_ID then Result := GetIKomikInfoFromURL else - if WebsiteID = NHENTAI_ID then + if MangaSiteID = NHENTAI_ID then Result := GetNHentaiInfoFromURL else - if WebsiteID = MANGAMINT_ID then + if MangaSiteID = MANGAMINT_ID then Result := GetMangaMintInfoFromURL else - if WebsiteID = UNIXMANGA_ID then + if MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaInfoFromURL else - if WebsiteID = EXTREMEMANGAS_ID then + if MangaSiteID = EXTREMEMANGAS_ID then Result := GetExtremeMangasInfoFromURL else - if WebsiteID = MANGAHOST_ID then + if MangaSiteID = MANGAHOST_ID then Result := GetMangaHostInfoFromURL else - if WebsiteID = MANGAKU_ID then + if MangaSiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL else - if WebsiteID = MANGAAT_ID then + if MangaSiteID = MANGAAT_ID then Result := GetMangaAtInfoFromURL else - if WebsiteID = DYNASTYSCANS_ID then + if MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansInfoFromURL else begin From df8e23956109104b07753832bf49e282a2af0671 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 22 Mar 2017 22:10:50 +0800 Subject: [PATCH 1707/2794] mymangareadercms, fixed chapterlist --- baseunits/modules/myMangaReaderCMS.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index 958fa96e0..d14bf8a59 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -53,7 +53,7 @@ function GetInfo(const MangaInfo: TMangaInformation; artists := XPathStringAll('//dt[.="Artist(s)"]/following-sibling::dd[1]/string-join(*,", ")'); genres := XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías")]/following-sibling::dd[1]/string-join(*,", ")'); summary := XPathString('//div[@class="well"]/p'); - for v in XPath('//ul[@class="chapters"]/li/h5') do + for v in XPath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') do begin chapterLinks.Add(XPathString('a/@href', v)); chapterName.Add(XPathString('normalize-space(.)', v)); From 6abb2608939b45f6b6e0d7256e4e50037f248c38 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Mar 2017 00:16:10 +0800 Subject: [PATCH 1708/2794] Bump version 0.9.105.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index b4e26d6b5..1766729e0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.105.0 (22-03-2017) +[*] Fixed memory leak +[+] Added FallenAngelsScan[EN-SC] +Full changes: https://github.com/riderkick/FMD/compare/0.9.104.0...0.9.105.0 + 0.9.104.0 (16-03-2017) [+] Added HentaiFox[H] [*] Fixed memory leak diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1b7edab25..273b3b849 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="104"/> + <RevisionNr Value="105"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index fb9df080e..26a6ae40c 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.104.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.104.0/fmd_0.9.104.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.104.0/fmd_0.9.104.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.104.0/fmd_0.9.104.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.104.0/fmd_0.9.104.0_Win64.7z +VERSION=0.9.105.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.105.0/fmd_0.9.105.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.105.0/fmd_0.9.105.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.105.0/fmd_0.9.105.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.105.0/fmd_0.9.105.0_Win64.7z From e65b3e320a51bf6fe60e5dbc07432df90005f6d4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Mar 2017 16:26:18 +0800 Subject: [PATCH 1709/2794] added requirement dcpcrypt. #538 --- mangadownloader/md.lpi | 25 ++++++++++++++----------- readme.txt | 1 + 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 273b3b849..817236d0a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -228,33 +228,36 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="8"> + <RequiredPackages Count="9"> <Item1> - <PackageName Value="BESENPkg"/> - <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> + <PackageName Value="dcpcrypt"/> </Item1> <Item2> - <PackageName Value="multiloglaz"/> + <PackageName Value="BESENPkg"/> + <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> </Item2> <Item3> - <PackageName Value="laz_synapse"/> + <PackageName Value="multiloglaz"/> </Item3> <Item4> - <PackageName Value="internettools"/> - <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> + <PackageName Value="laz_synapse"/> </Item4> <Item5> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="internettools"/> + <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item5> <Item6> - <PackageName Value="richmemopackage"/> + <PackageName Value="TAChartLazarusPkg"/> </Item6> <Item7> - <PackageName Value="virtualtreeview_package"/> + <PackageName Value="richmemopackage"/> </Item7> <Item8> - <PackageName Value="LCL"/> + <PackageName Value="virtualtreeview_package"/> </Item8> + <Item9> + <PackageName Value="LCL"/> + </Item9> </RequiredPackages> <Units Count="13"> <Unit0> diff --git a/readme.txt b/readme.txt index 7a708a645..96662b853 100644 --- a/readme.txt +++ b/readme.txt @@ -27,6 +27,7 @@ In order to build FMD from the source code, you must install the latest version - InternetTools, https://github.com/benibela/internettools - BESEN, https://github.com/BeRo1985/besen - MultiLog, https://github.com/blikblum/multilog + - DCPCypt, https://sourceforge.net/projects/lazarus-ccr/ After everything is installed, open the file md.lpi by using Lazarus IDE, select Run->Build to build the source code. If everything is ok, the binary file should be in FMD_source_code_folder/bin From 22d6b42c15babc94fccc538c8df7aa84f02ef5c4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Mar 2017 16:28:12 +0800 Subject: [PATCH 1710/2794] added basecrypto unit. All crypography work should be placed here #538 --- baseunits/BaseCrypto.pas | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 baseunits/BaseCrypto.pas diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas new file mode 100644 index 000000000..1a58be5a3 --- /dev/null +++ b/baseunits/BaseCrypto.pas @@ -0,0 +1,73 @@ +unit BaseCrypto; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, base64, DCPrijndael, DCPsha256; + +function Pkcs7AddPad(const s: String): String; +function Pkcs7RemovePad(const s: String): String; +function AESEncrpytCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; +function AESDecryptCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; + +implementation + +// Pkcs7 padding described in RFC 5652 https://tools.ietf.org/html/rfc5652#section-6.3 +function Pkcs7AddPad(const s: String): String; +var + l: Integer; +begin + Result:=s; + l:=16-(Length(s) and 15); + if l>0 then + result += StringOfChar(Char(l),l); +end; + +function Pkcs7RemovePad(const s: String): String; +begin + Result:=s; + SetLength(Result,Length(Result)-Ord(Result[Length(Result)])); +end; + +function AESEncrpytCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; +var + i: String; +begin + Result:=''; + with TDCP_rijndael.Create(nil) do + try + InitStr(key,TDCP_sha256); + SetIV(IV); + i:=Pkcs7AddPad(s); + SetLength(Result,Length(i)); + EncryptCBC(i[1],Result[1],Length(i)); + Burn; + Result:=EncodeStringBase64(Result); + finally + Free; + end; +end; + +function AESDecryptCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; +var + i: String; +begin + Result:=''; + with TDCP_rijndael.Create(nil) do + try + InitStr(key,TDCP_sha256); + SetIV(IV); + i:=DecodeStringBase64(s); + SetLength(Result,Length(i)); + DecryptCBC(i[1],Result[1],Length(i)); + Burn; + Result:=Pkcs7RemovePad(Result); + finally + Free; + end; +end; + +end. + From ba1b9f913e6b572c2315e371f72b0b69800b1b9e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Mar 2017 16:30:04 +0800 Subject: [PATCH 1711/2794] kissmanga, fixed decrypt image url. closed #538 --- baseunits/modules/KissManga.pas | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 8efd05043..5c573d80c 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Cloudflare, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, BaseCrypto, Cloudflare, RegExpr, synautil; implementation @@ -14,6 +14,9 @@ implementation kissmangadirurl = '/MangaList/Newest'; readcomiconlinedirurl = '/ComicList/Newest'; + kissmangaiv: array[0..15] of byte = ($a5, $e8, $e2, $e9, $c2, $72, $1b, $e0, $a8, $4a, $d6, $60, $c4, $72, $c1, $f3); + kissmangakey='mshsdf832nsdbash20asdmnasdbasd612basd'; + var kissmangacookies: String = ''; kissmangalockget: TRTLCriticalSection; @@ -156,11 +159,14 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if source.Count > 0 then for i := 0 to source.Count - 1 do begin if Pos('lstImages.push', source[i]) > 0 then - PageLinks.Add(GetBetween('.push("', '");', source[i])); + PageLinks.Add(GetBetween('("', '")', source[i])); end; finally source.Free; end; + if (PageLinks.Count <> 0) and (Module.Website = 'KissManga') then + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], kissmangakey, kissmangaiv); end; end; end; From 09f3d52f3d1cce5d879cc28ef978df94c6ce1eff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Mar 2017 17:22:15 +0800 Subject: [PATCH 1712/2794] heymanga, fixed download and cover. closed #547 --- baseunits/modules/HeyMangaXyz.pas | 34 ++++++++++--------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index c64a6664a..ab3072005 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -22,12 +22,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - page := XPath('//div/a[@class="btn btn-sm btn-icon"]').Count; - finally - Free; - end; + Page := XPathCount('//div/a[@class="btn btn-sm btn-icon"]', MangaInfo.FHTTP.Document); end; end; @@ -42,16 +37,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="row"]/div/div/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; + XPathHREFAll('//div[@class="row"]/div/div/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; @@ -72,6 +58,8 @@ function GetInfo(const MangaInfo: TMangaInformation; try coverLink := XPathString('//div[@class="mangas"]/div[@class="manga"]/img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if (coverLink <> '') and (LeftStr(coverLink, 2) = '//') then + coverLink := 'https:' + coverLink; if title = '' then title := SeparateRight(XPathString('//ul[@class="lead"]/li[starts-with(.,"Name: ")]'), ': '); s := XPathString('//ul[@class="lead"]/li[starts-with(.,"Status: ")]'); if Pos('Ongoing', s) > 0 then @@ -138,6 +126,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -146,12 +136,10 @@ function GetImageURL(const DownloadThread: TDownloadThread; if GET(FillHost(Module.RootURL, AURL) + IncStr(DownloadThread.WorkId)) then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := XPathString('//img[@id="img-content"]/@src'); - finally - Free; - end; + s := XPathString('//img[@id="img-content"]/@src', Document); + if LeftStr(s, 2) = '//' then + s := 'https:' + s; + PageLinks[DownloadThread.WorkId] := s; end; end; end; @@ -161,7 +149,7 @@ procedure RegisterModule; with AddModule do begin Website := 'HeyManga'; - RootURL := 'http://www.heymanga.xyz'; + RootURL := 'https://www.heymanga.me'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 0459b90bae851f1b263e2be9d1027a09379c62d7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 23 Mar 2017 17:28:01 +0800 Subject: [PATCH 1713/2794] Bump version 0.9.106.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1766729e0..457960f86 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.106.0 (23-03-2017) +[*] KissManga: fixed download +[*] HeyManga: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.105.0...0.9.106.0 + 0.9.105.0 (22-03-2017) [*] Fixed memory leak [+] Added FallenAngelsScan[EN-SC] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 817236d0a..031e90616 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="105"/> + <RevisionNr Value="106"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 26a6ae40c..cfc441763 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.105.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.105.0/fmd_0.9.105.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.105.0/fmd_0.9.105.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.105.0/fmd_0.9.105.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.105.0/fmd_0.9.105.0_Win64.7z +VERSION=0.9.106.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.106.0/fmd_0.9.106.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.106.0/fmd_0.9.106.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.106.0/fmd_0.9.106.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.106.0/fmd_0.9.106.0_Win64.7z From adf16bc32c1127bde0600ea122bcaad4162f1acb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 25 Mar 2017 13:33:40 +0800 Subject: [PATCH 1714/2794] changed spliturl var with const pstring, and changed the usage in all unit accordingly --- baseunits/WebsiteModules.pas | 4 +-- baseunits/httpsendthread.pas | 55 +++++++++++++++++-------------- baseunits/uBaseUnit.pas | 51 ++++++++++------------------ mangadownloader/forms/frmMain.pas | 2 +- 4 files changed, 50 insertions(+), 62 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 0e0b786c4..29c60eb6e 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -391,7 +391,7 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; Result := -1; end; var - h, p: String; + h: String; begin Result := -1; if FModuleList.Count = 0 then Exit; @@ -399,7 +399,7 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; Result := PosModule(h); if Result = -1 then begin - SplitURL(h, h, p, False, False); + SplitURL(h, @h, nil, False, False); if h = '' then Exit; Result := PosModule(h); end; diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index d1454d151..1cd7529da 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -52,7 +52,7 @@ procedure SetDefaultTimeoutAndApply(const ATimeout: Integer); procedure SetDefaultRetryCountAndApply(const ARetryCount: Integer); function MaybeEncodeURL(const AValue: String): String; -procedure SplitURL(const AURL: String; var AHost, APath: String; +procedure SplitURL(const AURL: String; const AHost, APath: PString; const AIncludeProtocol: Boolean = True; const AIncludePort: Boolean = True); const @@ -90,7 +90,7 @@ function poschar(const c:char;const s:string;const offset:cardinal=1):integer; Result:=0; end; -procedure SplitURL(const AURL: String; var AHost, APath: String; +procedure SplitURL(const AURL: String; const AHost, APath: PString; const AIncludeProtocol: Boolean; const AIncludePort: Boolean); procedure cleanuri(var u:string); @@ -100,27 +100,30 @@ procedure cleanuri(var u:string); end; var - iurl,prot,port: String; + iurl,ihost,ipath,iproto,iport: String; p,q: Integer; begin - AHost:=''; - APath:=''; + if (AHost=nil) and (APath=nil) then Exit; + if Assigned(AHost) then AHost^:=''; + if Assigned(APath) then APath^:=''; iurl:=Trim(AURL); if iurl='' then Exit; - prot:=''; - port:=''; - if iurl[1] = '/' then - if Length(iurl) = 1 then Exit + ihost:=''; + ipath:=''; + iproto:=''; + iport:=''; + if iurl[1]='/' then + if Length(iurl)=1 then Exit else - if iurl[2] <> '/' then + if iurl[2]<>'/' then begin - APath := iurl; + if Assigned(APath) then APath^:=iurl; Exit; end; p:=poschar(':',iurl); if (p<>0) and (p<Length(iurl)) and (iurl[P+1]='/') then begin - prot:=Copy(iurl,1,p-1); + iproto:=Copy(iurl,1,p-1); Delete(iurl,1,p); p:=poschar(':',iurl); end; @@ -130,7 +133,7 @@ procedure cleanuri(var u:string); for q:=p+1 to Length(iurl) do if not (iurl[q] in ['0'..'9']) then Break; if q=Length(iurl) then Inc(q); - port:=Copy(iurl,p+1,q-p-1); + iport:=Copy(iurl,p+1,q-p-1); delete(iurl,p,q-p); end; cleanuri(iurl); @@ -139,7 +142,7 @@ procedure cleanuri(var u:string); if (p<>0) and (p<Length(iurl)) then if p<q then begin - AHost:=Copy(iurl,1,q-1); + ihost:=Copy(iurl,1,q-1); Delete(iurl,1,q-1); cleanuri(iurl); end @@ -149,27 +152,29 @@ procedure cleanuri(var u:string); q:=poschar('.',iurl,p+1); if (q<>0) and (q<Length(iurl)) then begin - AHost:=iurl; + ihost:=iurl; iurl:=''; end; end; - if (AHost='') and (iurl<>'') and ((prot<>'') or (port<>'')) then + if (ihost='') and (iurl<>'') and ((iproto<>'') or (iport<>'')) then begin - AHost:=iurl; + ihost:=iurl; iurl:=''; end; - if AHost<>'' then + if ihost<>'' then begin if AIncludeProtocol then begin - if prot<>'' then AHost:=prot+'://'+AHost - else AHost:='http://'+AHost; + if iproto<>'' then ihost:=iproto+'://'+ihost + else ihost:='http://'+ihost; end; - if AIncludePort and (port<>'') then - AHost:=AHost+':'+port; + if AIncludePort and (iport<>'') then + ihost:=ihost+':'+iport; end; if iurl<>'' then - APath:='/'+iurl; + ipath:='/'+iurl; + if Assigned(AHost) then AHost^:=ihost; + if Assigned(APath) then APath^:=ipath; end; function KeyVal(const AKey, AValue: String): TKeyValuePair; @@ -355,10 +360,10 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: s := Trim(Headers.Values['Location']); if s<>'' then begin - SplitURL(s,h,p); + SplitURL(s,@h,@p); s:=p; if h='' then - SplitURL(rurl,h,p); + SplitURL(rurl,@h,@p); rurl:=h+s; end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 08fc0c022..df8b1a8d1 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -1064,14 +1064,14 @@ function LocateMangaSiteID(const URL: String): Integer; end; var - h, p: String; + h: String; begin Result := -1; h := LowerCase(URL); Result := PosMangaSite(h); if Result = -1 then begin - SplitURL(h, h, p, False, False); + SplitURL(h, @h, nil, False, False); if h = '' then Exit; Result := PosMangaSite(h); end; @@ -1238,80 +1238,63 @@ function FillMangaSiteHost(const Website, URL: String): String; function FillHost(const Host, URL: String): String; var - H,P: String; + P: String; begin - SplitURL(URL,H,P); + SplitURL(URL,nil,@P); Result:=RemoveURLDelim(Host)+P; end; function FillHost(const Host: String; const URLs: TStrings): String; var i: Integer; - H,P: String; begin + if (URLs=nil) or (URLs.Count=0) then Exit; for i:=0 to URLs.Count-1 do - begin - SplitURL(URLs[i],H,P); - URLs[i]:=RemoveURLDelim(Host)+P; - end; + URLs[i]:=FillHost(Host,URLs[i]); end; function MaybeFillHost(const Host, URL: String): String; var H,P: String; begin - SplitURL(URL,H,P); + SplitURL(URL,@H,@P); if (H='') and (P<>'') then Result:=RemoveURLDelim(Host)+P else Result:=URL; end; function GetHostURL(URL: String): String; var - H,P: String; + H: String; begin - SplitURL(URL,H,P); + SplitURL(URL,@H,nil); Result:=H; end; function RemoveHostFromURL(URL: String): String; -var - H,P: String; begin - SplitURL(URL,H,P); - Result:=P; + SplitURL(URL,nil,@Result); end; procedure RemoveHostFromURLs(const URLs: TStringList); var i: Integer; - H,P: String; begin - if URLs=nil then Exit; - if URLs.Count=0 then Exit; + if (URLs=nil) or (URLs.Count=0) then Exit; for i:=0 to URLs.Count-1 do - begin - SplitURL(URLs[i],H,P); - URLs[i]:=P; - end; + URLs[i]:=RemoveHostFromURL(URLs[i]); end; procedure RemoveHostFromURLsPair(const URLs, Names: TStringList); var i: Integer; - H,P: String; begin - if (URLs= nil) or (Names=nil) then Exit; - if (URLs.Count<>Names.Count) then Exit; - if URLs.Count=0 then Exit; + if (URLs=nil) or (Names=nil) or (URLs.Count<>Names.Count) or (URLs.Count=0) then Exit; i:=0; while i<URLs.Count do begin - SplitURL(URLs[i],H,P); - if P<>'' then - begin - URLs[i]:=P; - Inc(i); - end + URLs[i]:=RemoveHostFromURL(URLs[i]); + if URLs[i]<>'' then + Inc(i) else begin URLs.Delete(i); @@ -1324,7 +1307,7 @@ function EncodeCriticalURLElements(const URL: String): String; var H,P: String; begin - SplitURL(URL,H,P); + SplitURL(URL,@H,@P); Result:=H+EncodeTriplet(P,'%',URLSpecialChar+URLFullSpecialChar-['/']); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f06b45a0e..632016724 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5219,7 +5219,7 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); btReadOnline.Enabled := False; website := ''; - SplitURL(edURL.Text, host, link); + SplitURL(edURL.Text, @host, @link); if (host <> '') and (link <> '') then begin From 9e5521a6bca007769be83fc29b850e403a881c0c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 25 Mar 2017 15:35:16 +0800 Subject: [PATCH 1715/2794] basecrypto, changed aes to accept iv of hexstr, added hextobytes and bytestohex #538 --- baseunits/BaseCrypto.pas | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas index 1a58be5a3..bc8c671a9 100644 --- a/baseunits/BaseCrypto.pas +++ b/baseunits/BaseCrypto.pas @@ -7,13 +7,34 @@ interface uses Classes, SysUtils, base64, DCPrijndael, DCPsha256; +procedure HexToBytes(const h: String; var o :TBytes); +function BytesToHex(const h: TBytes): String; function Pkcs7AddPad(const s: String): String; function Pkcs7RemovePad(const s: String): String; -function AESEncrpytCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; -function AESDecryptCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; +function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; +function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; implementation +procedure HexToBytes(const h: String; var o :TBytes); +var + i, l: Integer; +begin + l:=Length(h) div 2; + SetLength(o,l); + for i:=Low(o) to High(o) do + o[i]:=Byte(StrToInt('$'+Copy(h,(i*2)+1,2))); +end; + +function BytesToHex(const h: TBytes): String; +var + i: Integer; +begin + Result:=''; + for i:=Low(h) to High(h) do + Result+=hexStr(h[i],2); +end; + // Pkcs7 padding described in RFC 5652 https://tools.ietf.org/html/rfc5652#section-6.3 function Pkcs7AddPad(const s: String): String; var @@ -31,15 +52,17 @@ function Pkcs7RemovePad(const s: String): String; SetLength(Result,Length(Result)-Ord(Result[Length(Result)])); end; -function AESEncrpytCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; +function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; var i: String; + ivb: TBytes; begin Result:=''; with TDCP_rijndael.Create(nil) do try InitStr(key,TDCP_sha256); - SetIV(IV); + HexToBytes(iv,ivb); + SetIV(ivb[0]); i:=Pkcs7AddPad(s); SetLength(Result,Length(i)); EncryptCBC(i[1],Result[1],Length(i)); @@ -50,15 +73,17 @@ function AESEncrpytCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; end; end; -function AESDecryptCBCSHA256Base64Pkcs7(const s, key: String; const IV): string; +function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; var i: String; + ivb: TBytes; begin Result:=''; with TDCP_rijndael.Create(nil) do try InitStr(key,TDCP_sha256); - SetIV(IV); + HexToBytes(iv,ivb); + SetIV(ivb[0]); i:=DecodeStringBase64(s); SetLength(Result,Length(i)); DecryptCBC(i[1],Result[1],Length(i)); From 858b48df1604b3b17edca10950c91f366329b5d9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 25 Mar 2017 15:35:57 +0800 Subject: [PATCH 1716/2794] kissmanga, added option for custom key and iv #538 --- baseunits/modules/KissManga.pas | 21 +++++++++++++++------ mangadownloader/languages/fmd.el_GR.po | 8 ++++++++ mangadownloader/languages/fmd.en.po | 8 ++++++++ mangadownloader/languages/fmd.es.po | 8 ++++++++ mangadownloader/languages/fmd.id_ID.po | 8 ++++++++ mangadownloader/languages/fmd.pl_PL.po | 8 ++++++++ mangadownloader/languages/fmd.po | 8 ++++++++ mangadownloader/languages/fmd.pt_BR.po | 8 ++++++++ 8 files changed, 71 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 5c573d80c..405bcb2df 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -14,15 +14,19 @@ implementation kissmangadirurl = '/MangaList/Newest'; readcomiconlinedirurl = '/ComicList/Newest'; - kissmangaiv: array[0..15] of byte = ($a5, $e8, $e2, $e9, $c2, $72, $1b, $e0, $a8, $4a, $d6, $60, $c4, $72, $c1, $f3); - kissmangakey='mshsdf832nsdbash20asdmnasdbasd612basd'; - var kissmangacookies: String = ''; kissmangalockget: TRTLCriticalSection; readcomiconlinecookies: String = ''; readcomiconlinelockget: TRTLCriticalSection; + kissmangaiv: String ='a5e8e2e9c2721be0a84ad660c472c1f3'; + kissmangakey: String ='mshsdf832nsdbash20asdmnasdbasd612basd'; + +resourcestring + RS_KissManga_Key = 'Key:'; + RS_KissManga_InitVector = 'Initialization Vector:'; + function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin @@ -173,9 +177,10 @@ function GetPageNumber(const DownloadThread: TDownloadThread; procedure RegisterModule; - procedure AddWebsiteModule(AWebsite, ARootURL: String); + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - with AddModule do + Result := AddModule; + with Result do begin Website := AWebsite; RootURL := ARootURL; @@ -188,7 +193,11 @@ procedure RegisterModule; end; begin - AddWebsiteModule('KissManga', 'http://kissmanga.com'); + with AddWebsiteModule('KissManga', 'http://kissmanga.com') do + begin + AddOptionEdit(@kissmangakey,'Key',@RS_KissManga_Key); + AddOptionEdit(@kissmangaiv,'IV',@RS_KissManga_InitVector); + end; AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.to'); end; diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index e07e1972c..67db3ae84 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -344,6 +344,14 @@ msgstr "Το σύστημα θα αδρανοποιηθεί σε %d δευτερ msgid "System will shutdown in %d second." msgstr "Το σύστημα θα τερματιστεί σε %d δευτερόλεπτα." +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Αφαίρεση υδατογραφήματος" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index aad197a77..184a8cece 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -347,6 +347,14 @@ msgstr "System will hibernate in %d second." msgid "System will shutdown in %d second." msgstr "System will shutdown in %d second." +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "Initialization Vector:" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "Key:" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Remove watermark" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index d1a9d010d..7d3fd400a 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -340,6 +340,14 @@ msgstr "Sistema Hibernará en %d segundos." msgid "System will shutdown in %d second." msgstr "Sistema se Apagará en %d segundos." +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Quitar Marca de Agua" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 659a9b735..d7b2062f4 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -345,6 +345,14 @@ msgstr "Komputer akan dihibernasi dalam %d detik" msgid "System will shutdown in %d second." msgstr "Komputer akan dimatikan dalam %d detik" +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "Initialization Vector:" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "Key:" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Hapus watermark" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 8e650a661..ec52fd0d0 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -342,6 +342,14 @@ msgstr "System zahibernuje się za %d sekund." msgid "System will shutdown in %d second." msgstr "System wyłączy się za %d sekund." +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Usuń znak wodny" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c6e2c275e..aa8c2193d 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -305,6 +305,14 @@ msgstr "" msgid "System will shutdown in %d second." msgstr "" +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 6fe141a6b..bc6bbf874 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -342,6 +342,14 @@ msgstr "Sistema irá hibernar em %d segundos." msgid "System will shutdown in %d second." msgstr "Sistema irá desligar em %d segundos." +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Remover a marca d'água" From 848631351e4ad48219344ac83e6c1b57ec05b71e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 25 Mar 2017 17:34:34 +0800 Subject: [PATCH 1717/2794] overrides packages compiler options to disable debug info and use optimization --- mangadownloader/md.lpi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 031e90616..a07c2379d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -215,6 +215,9 @@ </Other> </CompilerOptions> </Item5> + <SharedMatrixOptions Count="1"> + <Item1 ID="931960419235" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz,laz_synase,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win32 Debug Leaks" Value="-O3 -g- -CX -XX -Xs"/> + </SharedMatrixOptions> </BuildModes> <PublishOptions> <Version Value="2"/> From 2de6190036b56993b5f3ecebabb641a981dd8247 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 25 Mar 2017 17:49:23 +0800 Subject: [PATCH 1718/2794] Bump version 0.9.107.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 457960f86..5f42a410e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.107.0 (25-03-2017) +[*] KissManga: added option to add custom key and iv #538 +Full changes: https://github.com/riderkick/FMD/compare/0.9.106.0...0.9.107.0 + 0.9.106.0 (23-03-2017) [*] KissManga: fixed download [*] HeyManga: fixed download diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index a07c2379d..e63b40f35 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="106"/> + <RevisionNr Value="107"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index cfc441763..398b83520 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.106.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.106.0/fmd_0.9.106.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.106.0/fmd_0.9.106.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.106.0/fmd_0.9.106.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.106.0/fmd_0.9.106.0_Win64.7z +VERSION=0.9.107.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.107.0/fmd_0.9.107.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.107.0/fmd_0.9.107.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.107.0/fmd_0.9.107.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.107.0/fmd_0.9.107.0_Win64.7z From fb3f12a6a40352f424e953f1280b217dcc84406f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Mar 2017 13:16:39 +0800 Subject: [PATCH 1719/2794] basecrypto, added jshextostr and hide exception on aes encrypt/decrypt --- baseunits/BaseCrypto.pas | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas index bc8c671a9..67ec073d6 100644 --- a/baseunits/BaseCrypto.pas +++ b/baseunits/BaseCrypto.pas @@ -7,8 +7,11 @@ interface uses Classes, SysUtils, base64, DCPrijndael, DCPsha256; +function HexToStr(const h: String): String; procedure HexToBytes(const h: String; var o :TBytes); function BytesToHex(const h: TBytes): String; +function JSHexToStr(const h: String): String; + function Pkcs7AddPad(const s: String): String; function Pkcs7RemovePad(const s: String): String; function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; @@ -16,6 +19,15 @@ function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; implementation +function HexToStr(const h: String): String; +var + i: Integer; +begin + SetLength(Result,Length(h) div 2); + for i:=1 to Length(Result) do + Result[i]:=Char(StrToInt('$'+Copy(h,(i*2)-1,2))); +end; + procedure HexToBytes(const h: String; var o :TBytes); var i, l: Integer; @@ -35,6 +47,11 @@ function BytesToHex(const h: TBytes): String; Result+=hexStr(h[i],2); end; +function JSHexToStr(const h: String): String; +begin + Result := HexToStr(StringReplace(h, '\x', '', [rfIgnoreCase, rfReplaceAll])); +end; + // Pkcs7 padding described in RFC 5652 https://tools.ietf.org/html/rfc5652#section-6.3 function Pkcs7AddPad(const s: String): String; var @@ -59,6 +76,7 @@ function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; begin Result:=''; with TDCP_rijndael.Create(nil) do + begin try InitStr(key,TDCP_sha256); HexToBytes(iv,ivb); @@ -68,9 +86,10 @@ function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; EncryptCBC(i[1],Result[1],Length(i)); Burn; Result:=EncodeStringBase64(Result); - finally - Free; + except end; + Free; + end; end; function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; @@ -80,6 +99,7 @@ function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; begin Result:=''; with TDCP_rijndael.Create(nil) do + begin try InitStr(key,TDCP_sha256); HexToBytes(iv,ivb); @@ -89,9 +109,10 @@ function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; DecryptCBC(i[1],Result[1],Length(i)); Burn; Result:=Pkcs7RemovePad(Result); - finally - Free; + except end; + Free; + end; end; end. From 596088c9bf0aeef6ac1e73e868abb29734424cda Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Mar 2017 13:17:32 +0800 Subject: [PATCH 1720/2794] cf, changed minwaittime and sleep time --- baseunits/modules/Cloudflare.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index c9e1cfdd7..2e6682b67 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -16,7 +16,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; overl implementation const - MIN_WAIT_TIME = 5000; + MIN_WAIT_TIME = 4000; function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; begin @@ -124,8 +124,8 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B sc := 0; while sc < st do begin if AHTTP.ThreadTerminated then Break; - Inc(sc, 500); - Sleep(500); + Inc(sc, 250); + Sleep(250); end; AHTTP.FollowRedirection := False; if AHTTP.HTTPRequest(m, FillHost(h, u)) then From ab8c793de8c676729de48c828ae3b27125f2ff6f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Mar 2017 13:28:11 +0800 Subject: [PATCH 1721/2794] kissmanga, attempt to read key and iv, fallback to predefined if failed #538 --- baseunits/modules/KissManga.pas | 111 ++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 405bcb2df..3fa66ff31 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -155,10 +155,10 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then begin - Result := True; - source := TStringList.Create; + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then try + Result := True; + source := TStringList.Create; source.LoadFromStream(Document); if source.Count > 0 then for i := 0 to source.Count - 1 do begin @@ -168,10 +168,106 @@ function GetPageNumber(const DownloadThread: TDownloadThread; finally source.Free; end; - if (PageLinks.Count <> 0) and (Module.Website = 'KissManga') then - for i := 0 to PageLinks.Count - 1 do - PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], kissmangakey, kissmangaiv); - end; + end; +end; + +function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + source: TStringList; + i, chkop, ivp: Integer; + chkos, chko1, chko2, key, iv, s: String; + chkoa: Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then + try + Result := True; + chkop := -1; + ivp := -1; + chkos := ''; + chko1 := ''; + chko2 := ''; + key := ''; + iv := ''; + s := ''; + chkoa := False; + source := TStringList.Create; + source.LoadFromStream(Document); + if source.Count <> 0 then + for i := 0 to source.Count - 1 do + begin + if Pos('lstImages.push', source[i]) <> 0 then + PageLinks.Add(GetBetween('("', '")', source[i])) + else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then + chko2 += GetBetween('["', '"]', source[i]); + end; + if PageLinks.Count <> 0 then + begin + if GETWithCookie(DownloadThread.FHTTP, Module.RootURL + '/Scripts/lo.js', Module) then + begin + source.Text := StringReplace(StreamToString(Document), ';', LineEnding, [rfReplaceAll]); + if source.Count <> 0 then + begin + for i := 0 to source.Count - 1 do + if (Pos('boxzq', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then + ivp := StrToIntDef(GetBetween('[',']', source[i]), -1) + else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then + begin + chkos := GetBetween('=','[',source[i]); + chkop := StrToIntDef(GetBetween('[',']', source[i]), -1); + chkoa := Pos('chko+', StringReplace(source[i], ' ', '', [rfReplaceAll])) <> 0; + Break; + end; + if (chkos <> '') and (chkop <> -1) then + begin + for i := 0 to source.Count - 1 do + if Pos(chkos, source[i]) <> 0 then + begin + s := GetBetween('[', ']',source[i]); + Break; + end; + if s <> '' then + begin + source.CommaText := s; + if chkop < source.Count then + chko1 := source[chkop]; + if (ivp <> -1) and (ivp < source.Count) then + iv := JSHexToStr(source[ivp]); + end; + end; + end; + end; + if (chko1 <> '') or (chko2 <> '') then + begin + if chkoa then + chko2 := chko1 + chko2; + if chko2 = '' then + chko2 := chko1; + key := JSHexToStr(chko2); + if iv = '' then + iv := kissmangaiv; + s := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[0], key, iv); + if Pos('://', s) = 0 then + begin + key := kissmangakey; + iv := kissmangaiv; + end; + end; + s := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[0], key, iv); + if Pos('://', s) = 0 then + PageLinks.Clear; + if PageLinks.Count <> 0 then + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], key, iv); + end; + finally + source.Free; + end; end; end; @@ -195,6 +291,7 @@ procedure RegisterModule; begin with AddWebsiteModule('KissManga', 'http://kissmanga.com') do begin + OnGetPageNumber := @KissMangaGetPageNumber; AddOptionEdit(@kissmangakey,'Key',@RS_KissManga_Key); AddOptionEdit(@kissmangaiv,'IV',@RS_KissManga_InitVector); end; From 7a95d368ae1ed70db40f00301bca1036c9be0d99 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Mar 2017 13:41:47 +0800 Subject: [PATCH 1722/2794] updated user-agent string --- baseunits/httpsendthread.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 1cd7529da..87ccae07a 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -60,9 +60,10 @@ procedure SplitURL(const AURL: String; const AHost, APath: PString; UserAgentCURL = 'curl/7.52.1'; UserAgentGooglebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; UserAgentMSIE = 'Mozilla/5.0 (Windows NT 10.0; Win64; Trident/7.0; rv:11.0) like Gecko'; - UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0'; - UserAgentChrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'; - UserAgentOpera = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 OPR/42.0.2393.94'; + UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0'; + UserAgentChrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'; + UserAgentVivaldi = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.111 Safari/537.36 Vivaldi/1.8.770.44'; + UserAgentOpera = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 OPR/44.0.2510.857'; UserAgentEdge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393'; var From e281b2923cb5b4946249f23d207b20dd4d50d592 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Mar 2017 19:05:06 +0800 Subject: [PATCH 1723/2794] kissmanga, fixed wrong line of condition and cleanup unused #538 --- baseunits/modules/KissManga.pas | 60 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 3fa66ff31..9409994b2 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -198,50 +198,49 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; chkoa := False; source := TStringList.Create; source.LoadFromStream(Document); - if source.Count <> 0 then - for i := 0 to source.Count - 1 do + for i := 0 to source.Count - 1 do + begin + if Pos('lstImages.push', source[i]) <> 0 then + PageLinks.Add(GetBetween('("', '")', source[i])) + else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then begin - if Pos('lstImages.push', source[i]) <> 0 then - PageLinks.Add(GetBetween('("', '")', source[i])) - else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then - chko2 += GetBetween('["', '"]', source[i]); + chko2 += GetBetween('["', '"]', source[i]); + chkoa := Pos('chko+', StringReplace(source[i], ' ', '', [rfReplaceAll])) <> 0; end; + end; if PageLinks.Count <> 0 then begin if GETWithCookie(DownloadThread.FHTTP, Module.RootURL + '/Scripts/lo.js', Module) then begin source.Text := StringReplace(StreamToString(Document), ';', LineEnding, [rfReplaceAll]); - if source.Count <> 0 then + for i := 0 to source.Count - 1 do + if (Pos('boxzq', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then + ivp := StrToIntDef(GetBetween('[',']', source[i]), -1) + else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then + begin + chkos := GetBetween('=','[',source[i]); + chkop := StrToIntDef(GetBetween('[',']', source[i]), -1); + Break; + end; + if (chkos <> '') and (chkop <> -1) then begin for i := 0 to source.Count - 1 do - if (Pos('boxzq', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then - ivp := StrToIntDef(GetBetween('[',']', source[i]), -1) - else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then + if Pos(chkos, source[i]) <> 0 then begin - chkos := GetBetween('=','[',source[i]); - chkop := StrToIntDef(GetBetween('[',']', source[i]), -1); - chkoa := Pos('chko+', StringReplace(source[i], ' ', '', [rfReplaceAll])) <> 0; + s := GetBetween('[', ']',source[i]); Break; end; - if (chkos <> '') and (chkop <> -1) then + if s <> '' then begin - for i := 0 to source.Count - 1 do - if Pos(chkos, source[i]) <> 0 then - begin - s := GetBetween('[', ']',source[i]); - Break; - end; - if s <> '' then - begin - source.CommaText := s; - if chkop < source.Count then - chko1 := source[chkop]; - if (ivp <> -1) and (ivp < source.Count) then - iv := JSHexToStr(source[ivp]); - end; + source.CommaText := s; + if chkop < source.Count then + chko1 := source[chkop]; + if (ivp <> -1) and (ivp < source.Count) then + iv := JSHexToStr(source[ivp]); end; end; end; + if (chko1 <> '') or (chko2 <> '') then begin if chkoa then @@ -261,9 +260,8 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; s := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[0], key, iv); if Pos('://', s) = 0 then PageLinks.Clear; - if PageLinks.Count <> 0 then - for i := 0 to PageLinks.Count - 1 do - PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], key, iv); + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], key, iv); end; finally source.Free; From 9bc0d8c83fd59c19c82c9bc91aa6923d6d95bd92 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 26 Mar 2017 19:16:27 +0800 Subject: [PATCH 1724/2794] md, only overrides runtime packagages that not part of ide --- mangadownloader/md.lpi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e63b40f35..2a6044e96 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -216,7 +216,7 @@ </CompilerOptions> </Item5> <SharedMatrixOptions Count="1"> - <Item1 ID="931960419235" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz,laz_synase,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win32 Debug Leaks" Value="-O3 -g- -CX -XX -Xs"/> + <Item1 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win32 Debug Leaks" Value="-O3 -g- -CX -XX -Xs"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From 84b2675ed7e3294804257f22473391def23d57a5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Mar 2017 08:15:22 +0800 Subject: [PATCH 1725/2794] luscious, rewrite all closed #554 --- baseunits/modules/Luscious.pas | 196 ++++++++++----------------------- 1 file changed, 57 insertions(+), 139 deletions(-) diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 674265a95..fd8179622 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -6,183 +6,102 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; + XQueryEngineHTML, RegExpr; implementation -uses - synautil, RegExpr; - const - dirURL = '/c/-/albums/t/manga/sorted/new/page/'; + dirurl = '/c/-/albums/frontpage/0/t/manga/sorted/new/page/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin - Page := 100; - Result := NO_ERROR; + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '/') then + begin + Result := NO_ERROR; + Page := StrToIntDef(TrimChar(XPathString('//*[@class="pagination"]/*[@class="last"]/a/@href/substring-after(.,"/new/page")', MangaInfo.FHTTP.Document), ['/']), 1); + end; end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - Source: TStringList; - Query: TXQueryEngineHTML; - v: IXQValue; begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), - Module.RootURL + dirURL + IncStr(AURL) + '/', 3) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); - try - for v in Query.XPath('//*[@id="albums_wrapper"]//*[@class="caption"]//a') do begin - ALinks.Add(TrimLeftChar(v.toNode.getAttribute('href'), ['.'])); - ANames.Add(v.toString); - end; - finally - Query.Free; - end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; + if MangaInfo.FHTTP.GET(Module.RootURL + '/page/' + IncStr(AURL) + '/') then + begin + Result := NO_ERROR; + XPathHREFtitleAll('//*[@id="albums_wrapper"]//*[@class="item_cover"]/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - Source: TStringList; - Query: TXQueryEngineHTML; - info: TMangaInfo; - v: IXQValue; - s: String; - regx: TRegExpr; begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := AppendURLDelim(FillHost(Module.RootURL, AURL)); - Source := TStringList.Create; - regx := TRegExpr.Create; - try - regx.ModifierI := True; - regx.Expression := '/page/\d+/?$'; - if regx.Exec(info.url) then - info.url := regx.Replace(info.url, '/', False); - if RightStr(info.url, 5) <> 'view/' then info.url += 'view/'; - if Pos('/pictures/album/', info.url) > 0 then - info.url := StringReplace(info.url, '/pictures/album/', '/albums/', []); - if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Query := TXQueryEngineHTML.Create(Source.Text); + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try - with info do begin - coverLink := Query.XPathString('//*[@class="album_cover_item"]//img/@src'); - if coverLink <> '' then - coverLink := TrimLeftChar(coverLink, ['/']); - title := Query.XPathString('//*[@class="album_cover"]/h2'); - genres := ''; - for v in Query.XPath('//*[@id="tag_section"]//li') do begin - s := v.toString; - if LeftStr(s, 7) = 'author:' then - authors := SeparateRight(s, ':') - else if LeftStr(s, 7) = 'artist:' then - artists := SeparateRight(s, ':') - else - AddCommaString(genres, s); - end; - //section, languge - for v in Query.XPath('//*[@class="content_info"]//p/*') do - AddCommaString(genres, v.toString); - //chapter - s := info.url; - if RightStr(s, 5) = 'view/' then SetLength(s, Length(s) - 5); - chapterLinks.Add(s); - chapterName.Add(title); - end; + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="album_cover_item"]//img/@src')); + if title = '' then title := XPathString('//*[@class="album_cover"]/h2'); + artists := XPathString('//*[@id="tag_section"]/ol/li/a[starts-with(.,"Artist")]/text()[last()]'); + genres := XPathString('//*[@id="tag_section"]/ol/string-join(li/a/text()[last()],", ")'); + chapterLinks.Add(url); + chapterName.Add(title); finally - Query.Free; + Free; end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - regx.Free; - Source.Free; + end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - Source: TStringList; - Query: TXQueryEngineHTML; - Container: TTaskContainer; - v: IXQValue; - rurl: String; - p: Integer; - nextpage: Boolean; - regx: TRegExpr; - s: String; + n: String; + i: Integer; begin Result := False; if DownloadThread = nil then Exit; - Container := DownloadThread.Task.Container; - with Container do begin + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin PageLinks.Clear; PageNumber := 0; - rurl := AppendURLDelim(FillHost(Module.RootURL, AURL)); - Source := TStringList.Create; - regx := TRegExpr.Create; - try - regx.ModifierI := True; - regx.Expression := '/page/\d+/?$'; - if regx.Exec(rurl) then rurl := regx.Replace(rurl, '/', False); - if RightStr(rurl, 5) = 'view/' then SetLength(rurl, Length(rurl) - 5); - if RightStr(rurl, 5) <> 'page/' then rurl += 'page/'; - if Pos('/albums/', rurl) > 0 then - rurl := StringReplace(rurl, '/albums/', '/pictures/album/', []); - Query := TXQueryEngineHTML.Create; - try - regx.Expression := '\.\d+x\d+(\.\w+)$'; - p := 1; - nextpage := True; - while nextpage do begin - nextpage := False; - if GetPage(DownloadThread.FHTTP, TObject(Source), rurl + IntToStr(p) + '/', - Manager.retryConnect) then + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + while True do begin - Result := True; - Query.ParseHTML(Source.Text); - for v in Query.XPath('//*[@class="picture_page"]//img/@src') do begin - s := TrimLeftChar(v.toString, ['/']); - if regx.Exec(s) then s := regx.Replace(s, '$1', True); - Container.PageLinks.Add(s); - end; - if Query.XPathString('//*[@id="next_page"]//a/@href') <> '' then begin - Inc(p); - nextpage := True; + XPathStringAll('//*[@class="picture_page"]//img/@data-src', PageLinks); + n := XPathString('//*[@class="pagination"]/a/@href'); + if n = '' then Break; + if GET(MaybeFillHost(Module.RootURL, n)) then + ParseHTML(Document) + else + begin + PageLinks.Clear; + Break; end; end; + if PageLinks.Count <> 0 then + with TRegExpr.Create('\.\d+x\d+(\.\w+)') do + try + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := Replace(PageLinks[i], '$1', True); + finally + Free; + end; + finally + Free; end; - finally - Query.Free; - end; - finally - regx.Free; - Source.Free; end; end; end; @@ -192,9 +111,8 @@ procedure RegisterModule; with AddModule do begin Website := 'Luscious'; - RootURL := 'http://luscious.net/'; + RootURL := 'https://luscious.net'; SortedList := True; - FavoriteAvailable := False; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 046d09b0469705f41065b33e12fa67ac70a82443 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Mar 2017 08:22:51 +0800 Subject: [PATCH 1726/2794] luscious, fixed update list --- baseunits/modules/Luscious.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index fd8179622..82d86693d 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -17,7 +17,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '/') then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1/') then begin Result := NO_ERROR; Page := StrToIntDef(TrimChar(XPathString('//*[@class="pagination"]/*[@class="last"]/a/@href/substring-after(.,"/new/page")', MangaInfo.FHTTP.Document), ['/']), 1); @@ -29,7 +29,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/page/' + IncStr(AURL) + '/') then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL) + '/') then begin Result := NO_ERROR; XPathHREFtitleAll('//*[@id="albums_wrapper"]//*[@class="item_cover"]/a', MangaInfo.FHTTP.Document, ALinks, ANames); From 4637fa646f7f35ce0c503e11c06cd7330a74a831 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Mar 2017 08:34:44 +0800 Subject: [PATCH 1727/2794] xqueryenginehtml, use trim on batch --- baseunits/XQueryEngineHTML.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index d150be4db..9caf3f8a7 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -273,7 +273,7 @@ procedure TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: for i := 1 to v.Count do begin x := v.get(i); - TheStrings.Add(x.toString); + TheStrings.Add(Trim(x.toString)); end; x := nil; v := nil; @@ -401,7 +401,7 @@ procedure TXQueryEngineHTML.XPathHREFAll(const Expression: String; begin x := v.get(i); ALinks.Add(x.toNode.getAttribute('href')); - ATexts.Add(x.toString); + ATexts.Add(Trim(x.toString)); end; x := nil; v := nil; From e06b2a235d6f8fb77448cce9d658e4d69ad2b49c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Mar 2017 09:28:18 +0800 Subject: [PATCH 1728/2794] added pururin closed #556 --- baseunits/ModuleList.inc | 22 +++---- baseunits/modules/Pururin.pas | 105 ++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 baseunits/modules/Pururin.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index c2d0df339..325bd3793 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -2,21 +2,14 @@ uses FoOlSlide, WPManga, myMangaReaderCMS, - WPAdultSiteSkins, Batoto, MangaFox, Mangacan, PecintaKomik, - EHentai, - Doujinmoeus, MangaReader, MangaStream, MangaLife, - Luscious, MangaHere, - EightMuses, - HitomiLa, - HentaiCafe, MangaTr, Madokami, RawSenManga, @@ -33,7 +26,6 @@ uses Tsumino, SubManga, MangaBackup, - Hentai2Read, Tumangaonline, MangaEden, HeyMangaXyz, @@ -59,10 +51,20 @@ uses MangaShiro, ReadMangaToday, MangaOnlineBR, - HentaiFox, // Raw Official SundayWebEvery, TonarinoYoungJump, YoungAceUp, NewType, - Comico; + Comico, + // Adult + WPAdultSiteSkins, + EHentai, + Doujinmoeus, + Luscious, + EightMuses, + HitomiLa, + HentaiCafe, + Hentai2Read, + HentaiFox, + Pururin; diff --git a/baseunits/modules/Pururin.pas b/baseunits/modules/Pururin.pas new file mode 100644 index 000000000..c9be627f2 --- /dev/null +++ b/baseunits/modules/Pururin.pas @@ -0,0 +1,105 @@ +unit Pururin; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, RegExpr; + +implementation + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL) then + begin + Result := NO_ERROR; + Page := StrToIntDef(XPathString('//*[contains(@class,"pager")]/a[last()]', MangaInfo.FHTTP.Document), 1); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/browse/search/1/' + IncStr(AURL) + '.html') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//*[@class="gallery-list"]/li//a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('.//*[@class="title"]//h2/text()[1]', v)); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="gallery-cover"]//img/@src')); + if title = '' then title := XPathString('//*[@class="gallery-info"]/h1'); + artists := XPathString('//*[@class="table-info"]//tr/td[starts-with(.,"Artist")]/following-sibling::td[1]/string-join(.//a,", ")'); + genres := XPathString('//*[@class="table-info"]/string-join(.//tr/td//a,", ")'); + XPathHREFAll('//*[@class="table-data"]//tr/td[2]/a', chapterLinks, chapterName); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + XPathStringAll('json(//script[contains(.,"chapter_page")]/substring-before(substring-after(.,"= "),";"))//chapter_image', Document, PageLinks); + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Pururin'; + RootURL := 'https://pururin.us'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 305788013..684a8a115 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -20,5 +20,5 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,ReadHentaiManga,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From b643b36bce637dfd30a06d0e71b15bf3e9f95665 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Mar 2017 09:43:28 +0800 Subject: [PATCH 1729/2794] overrides ide packages too --- mangadownloader/md.lpi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2a6044e96..7ed7d2050 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -215,8 +215,9 @@ </Other> </CompilerOptions> </Item5> - <SharedMatrixOptions Count="1"> - <Item1 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win32 Debug Leaks" Value="-O3 -g- -CX -XX -Xs"/> + <SharedMatrixOptions Count="2"> + <Item1 ID="284095981400" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-O3 -g- -CX -XX -Xs"/> + <Item2 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win32 Debug Leaks,Win64,Win32" Value="-O3 -g- -CX -XX -Xs"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From f6856bc30a4e8fb763134c40c4f5ff51cc192194 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Mar 2017 09:56:50 +0800 Subject: [PATCH 1730/2794] Bump version 0.9.108.0 --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5f42a410e..914be8d56 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.108.0 (27-03-2017) +[*] KissManga: fixed download +[*] Luscious: rewrite all +[+] Added Pururin[H] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.107.0...0.9.108.0 + 0.9.107.0 (25-03-2017) [*] KissManga: added option to add custom key and iv #538 Full changes: https://github.com/riderkick/FMD/compare/0.9.106.0...0.9.107.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 7ed7d2050..ddb0b49f4 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="107"/> + <RevisionNr Value="108"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 398b83520..5ed7ca700 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.107.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.107.0/fmd_0.9.107.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.107.0/fmd_0.9.107.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.107.0/fmd_0.9.107.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.107.0/fmd_0.9.107.0_Win64.7z +VERSION=0.9.108.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.108.0/fmd_0.9.108.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.108.0/fmd_0.9.108.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.108.0/fmd_0.9.108.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.108.0/fmd_0.9.108.0_Win64.7z From bd6e4136800ee391398f1a22b14cf1a5d7ef1eb4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Mar 2017 15:28:22 +0800 Subject: [PATCH 1731/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index eda74eed7..aa1bd131e 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit eda74eed78593411a219ad75e3617132172ecceb +Subproject commit aa1bd131e6eaeaf72526aaf40908ab7134525480 From 8f07778108b7017804453ff339256f53b7851f17 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 29 Mar 2017 15:37:22 +0800 Subject: [PATCH 1732/2794] xqueryenginehtml, free engine immedietly following internettools changes --- baseunits/XQueryEngineHTML.pas | 102 ++++++++------------------------- 1 file changed, 24 insertions(+), 78 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 9caf3f8a7..65d9cc372 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, xquery, xquery_json, simplehtmltreeparser, BaseThread; + Classes, SysUtils, xquery, xquery_json, simplehtmltreeparser; type @@ -13,15 +13,14 @@ interface TXQueryEngineHTML = class private - FIsMainThread: Boolean; FEngine: TXQueryEngine; FTreeParser: TTreeParser; function Eval(const Expression: String; const isCSS: Boolean = False; const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): IXQValue; function EvalString(const Expression: String; const isCSS: Boolean = False; - const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): String; + const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): String; inline; function EvalCount(const Expression: String; const isCSS: Boolean = False; - const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): Integer; + const ContextItem: IXQValue = nil; const Tree: TTreeNode = nil): Integer; inline; function EvalStringAll(const Expression: String; const isCSS: Boolean; const Separator: String = ', '; const ContextItem: IXQValue = nil): String; overload; function EvalStringAll(const Expression: String; const isCSS: Boolean; @@ -208,92 +207,52 @@ function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; function TXQueryEngineHTML.EvalString(const Expression: String; const isCSS: Boolean; const ContextItem: IXQValue; const Tree: TTreeNode ): String; -var - v: IXQValue; begin - v := Eval(Expression, isCSS, ContextItem, Tree); - Result := v.toString; - v := nil; + Result := Eval(Expression, isCSS, ContextItem, Tree).toString; end; function TXQueryEngineHTML.EvalCount(const Expression: String; const isCSS: Boolean; const ContextItem: IXQValue; const Tree: TTreeNode ): Integer; -var - v: IXQValue; begin - v := Eval(Expression, isCSS, ContextItem, Tree); - Result := v.Count; - v := nil; + Result := Eval(Expression, isCSS, ContextItem, Tree).Count; end; function TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; const Separator: String; const ContextItem: IXQValue): String; var - v, x: IXQValue; - i: Integer; + v: IXQValue; begin Result := ''; - v := Eval(Expression, isCSS, ContextItem); - for i := 1 to v.Count do - begin - x := v.get(i); - AddSeparatorString(Result, x.toString, Separator); - end; - x := nil; - v := nil; + for v in Eval(Expression, isCSS, ContextItem) do + AddSeparatorString(Result, v.toString, Separator); end; function TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; const Exc: array of String; const Separator: String; const ContextItem: IXQValue ): String; var - v, x: IXQValue; - i: Integer; + v: IXQValue; begin Result := ''; - v := Eval(Expression, isCSS, ContextItem); - for i := 1 to v.Count do - begin - x := v.get(i); - if not StringInArray(Trim(x.toString), Exc) then - AddSeparatorString(Result, x.toString, Separator); - end; - x := nil; - v := nil; + for v in Eval(Expression, isCSS, ContextItem) do + if not StringInArray(Trim(v.toString), Exc) then + AddSeparatorString(Result, v.toString, Separator); end; procedure TXQueryEngineHTML.EvalStringAll(const Expression: String; const isCSS: Boolean; const TheStrings: TStrings; ContextItem: IXQValue); var - v, x: IXQValue; - i: Integer; + v: IXQValue; begin - v := Eval(Expression, isCSS, ContextItem); - for i := 1 to v.Count do - begin - x := v.get(i); - TheStrings.Add(Trim(x.toString)); - end; - x := nil; - v := nil; + for v in Eval(Expression, isCSS, ContextItem) do + TheStrings.Add(Trim(v.toString)); end; constructor TXQueryEngineHTML.Create(const HTML: String); -var - ct: TThread; begin - FIsMainThread := GetThreadID = MainThreadID; FEngine := TXQueryEngine.Create; FTreeParser := TTreeParser.Create; - if not FIsMainThread then - begin - ct := TThread.CurrentThread; - if ct is TBaseThread then - TBaseThread(ct).ObjectList.Add(FEngine) - else - FIsMainThread := True; - end; with FTreeParser do begin parsingModel := pmHTML; @@ -318,10 +277,7 @@ constructor TXQueryEngineHTML.Create(const HTMLStream: TStream); destructor TXQueryEngineHTML.Destroy; begin - if FIsMainThread then - FEngine.Free - else - FEngine := nil; + FEngine.Free; FTreeParser.Free; inherited Destroy; end; @@ -393,35 +349,25 @@ procedure TXQueryEngineHTML.XPathStringAll(const Expression: String; procedure TXQueryEngineHTML.XPathHREFAll(const Expression: String; const ALinks, ATexts: TStrings; const ContextItem: IXQValue); var - v, x: IXQValue; - i: Integer; + v: IXQValue; begin - v := Eval(Expression, False, ContextItem); - for i := 1 to v.Count do + for v in Eval(Expression, False, ContextItem) do begin - x := v.get(i); - ALinks.Add(x.toNode.getAttribute('href')); - ATexts.Add(Trim(x.toString)); + ALinks.Add(v.toNode.getAttribute('href')); + ATexts.Add(Trim(v.toString)); end; - x := nil; - v := nil; end; procedure TXQueryEngineHTML.XPathHREFtitleAll(const Expression: String; const ALinks, ATitles: TStrings; const ContextItem: IXQValue); var - v, x: IXQValue; - i: Integer; + v: IXQValue; begin - v := Eval(Expression, False, ContextItem); - for i := 1 to v.Count do + for v in Eval(Expression, False, ContextItem) do begin - x := v.get(i); - ALinks.Add(x.toNode.getAttribute('href')); - ATitles.Add(x.toNode.getAttribute('title')); + ALinks.Add(v.toNode.getAttribute('href')); + ATitles.Add(v.toNode.getAttribute('title')); end; - x := nil; - v := nil; end; function TXQueryEngineHTML.CSS(const Expression: String; const Tree: TTreeNode): IXQValue; From 395565808a0460778f2a7b090033d8e58a6d80bf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Mar 2017 10:51:44 +0800 Subject: [PATCH 1733/2794] kissmanga, fixed get key and iv closed #557 --- baseunits/modules/KissManga.pas | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 9409994b2..b1cfc7105 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -178,6 +178,13 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; i, chkop, ivp: Integer; chkos, chko1, chko2, key, iv, s: String; chkoa: Boolean; + + function testkeyiv: Boolean; + begin + if DownloadThread.Task.Container.PageLinks.Count=0 then Exit(False); + Result:=Pos('://',AESDecryptCBCSHA256Base64Pkcs7(DownloadThread.Task.Container.PageLinks[0],key,iv))<>0; + end; + begin Result := False; if DownloadThread = nil then Exit; @@ -204,7 +211,7 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; PageLinks.Add(GetBetween('("', '")', source[i])) else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then begin - chko2 += GetBetween('["', '"]', source[i]); + chko2 := GetBetween('["', '"]', source[i]); chkoa := Pos('chko+', StringReplace(source[i], ' ', '', [rfReplaceAll])) <> 0; end; end; @@ -243,25 +250,31 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; if (chko1 <> '') or (chko2 <> '') then begin + chko1 := JSHexToStr(chko1); + chko2 := JSHexToStr(chko2); if chkoa then chko2 := chko1 + chko2; if chko2 = '' then chko2 := chko1; - key := JSHexToStr(chko2); + key := chko2; if iv = '' then iv := kissmangaiv; - s := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[0], key, iv); - if Pos('://', s) = 0 then + if not testkeyiv then begin key := kissmangakey; iv := kissmangaiv; + if not testkeyiv then + PageLinks.Clear; end; + end + else + if not testkeyiv then + PageLinks.Clear; + if PageLinks.Count <> 0 then + begin + for i := 0 to PageLinks.Count - 1 do + PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], key, iv); end; - s := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[0], key, iv); - if Pos('://', s) = 0 then - PageLinks.Clear; - for i := 0 to PageLinks.Count - 1 do - PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], key, iv); end; finally source.Free; From c18560eb223ef71230cb447ccb89b0cbf4c5ba22 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 30 Mar 2017 11:02:30 +0800 Subject: [PATCH 1734/2794] Bump version 0.9.109.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 914be8d56..0ad8909ff 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.109.0 (30-03-2017) +[*] KissManga: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.108.0...0.9.109.0 + 0.9.108.0 (27-03-2017) [*] KissManga: fixed download [*] Luscious: rewrite all diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ddb0b49f4..afc079058 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="108"/> + <RevisionNr Value="109"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5ed7ca700..fa67dca1b 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.108.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.108.0/fmd_0.9.108.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.108.0/fmd_0.9.108.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.108.0/fmd_0.9.108.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.108.0/fmd_0.9.108.0_Win64.7z +VERSION=0.9.109.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.109.0/fmd_0.9.109.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.109.0/fmd_0.9.109.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.109.0/fmd_0.9.109.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.109.0/fmd_0.9.109.0_Win64.7z From 186eddeca685fb1aa6e710a83c67da331402ada0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 May 2017 17:23:10 +0800 Subject: [PATCH 1735/2794] httpsendthread, get cookie expires after every request --- baseunits/httpsendthread.pas | 70 +++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 87ccae07a..761d29ae7 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,7 +6,39 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - GZIPUtils, BaseThread; + GZIPUtils, BaseThread, dateutils; + +const + + HTTPFormatSettings :TFormatSettings = ( + CurrencyFormat :1; + NegCurrFormat :5; + ThousandSeparator :','; + DecimalSeparator :'.'; + CurrencyDecimals :2; + DateSeparator :'/'; + TimeSeparator :':'; + ListSeparator :','; + CurrencyString :'$'; + ShortDateFormat :'m/d/y'; + LongDateFormat :'dd" "mmmm" "yyyy'; + TimeAMString :'AM'; + TimePMString :'PM'; + ShortTimeFormat :'hh:nn'; + LongTimeFormat :'hh:nn:ss'; + ShortMonthNames :('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); + LongMonthNames :('January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', 'October', + 'November', 'December'); + ShortDayNames :('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); + LongDayNames :('Sunday', 'Monday', 'Tuesday', 'Wednesday', + 'Thursday', 'Friday', 'Saturday'); + TwoDigitYearCenturyWindow :50; + ); + + // https://tools.ietf.org/html/rfc2616#section-3.3.1 + HTTPCookieExpiresFormat = 'ddd, dd-mmm-yy hh:nn:ss'; type @@ -19,11 +51,15 @@ THTTPSendThread = class(THTTPSend) FGZip: Boolean; FFollowRedirection: Boolean; FAllowServerErrorResponse: Boolean; + FCookiesExpires: TDateTime; procedure SetTimeout(AValue: Integer); procedure OnOwnerTerminate(Sender: TObject); + protected + procedure ParseCookiesExpires; public constructor Create(AOwner: TBaseThread = nil); destructor Destroy; override; + function HTTPMethod(const Method, URL: string): Boolean; function HTTPRequest(const Method, URL: String; const Response: TObject = nil): Boolean; function HEAD(const URL: String; const Response: TObject = nil): Boolean; function GET(const URL: String; const Response: TObject = nil): Boolean; @@ -40,6 +76,7 @@ THTTPSendThread = class(THTTPSend) property FollowRedirection: Boolean read FFollowRedirection write FFollowRedirection; property AllowServerErrorResponse: Boolean read FAllowServerErrorResponse write FAllowServerErrorResponse; property Thread: TBaseThread read FOwner; + property CookiesExpires: TDateTime read FCookiesExpires; end; TKeyValuePair = array[0..1] of String; @@ -284,6 +321,30 @@ procedure THTTPSendThread.OnOwnerTerminate(Sender: TObject); Sock.AbortSocket; end; +procedure THTTPSendThread.ParseCookiesExpires; +var + i, p: Integer; + c: TDateTime; + s: String; +begin + FCookiesExpires := 0.0; + for i := 0 to FHeaders.Count-1 do + if Pos('set-cookie', LowerCase(FHeaders[i])) = 1 then + begin + s := SeparateRight(FHeaders[i], ':'); + p := Pos('expires', lowercase(s)); + if p <> 0 then + begin + s := Copy(s, p, Length(s)); + s := SeparateLeft(SeparateRight(s,'='),';'); + s := Trim(SeparateLeft(s, 'GMT')); + c := ScanDateTime(HTTPCookieExpiresFormat, s, HTTPFormatSettings); + if (FCookiesExpires = 0.0) or (c < FCookiesExpires) then + FCookiesExpires := c; + end; + end; +end; + constructor THTTPSendThread.Create(AOwner: TBaseThread); begin inherited Create; @@ -324,6 +385,13 @@ destructor THTTPSendThread.Destroy; inherited Destroy; end; +function THTTPSendThread.HTTPMethod(const Method, URL: string): Boolean; +begin + FCookiesExpires := 0.0; + Result := inherited HTTPMethod(Method, URL); + ParseCookiesExpires; +end; + function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: TObject): Boolean; function CheckTerminate: Boolean; From 5f8eb36509becf53f81da59a7569fa85039c6e0b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 May 2017 17:24:09 +0800 Subject: [PATCH 1736/2794] cf, check cookie expires before request --- baseunits/modules/Cloudflare.pas | 85 ++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 2e6682b67..87bf5adef 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -5,13 +5,24 @@ interface uses - Classes, SysUtils, uBaseUnit, XQueryEngineHTML, httpsendthread, BESEN, BESENValue, - RegExpr; + Classes, SysUtils, uBaseUnit, XQueryEngineHTML, httpsendthread, synautil, + BESEN, BESENValue, RegExpr, dateutils; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; - var CS: TRTLCriticalSection): Boolean; overload; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String): Boolean; overload; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; overload; +type + + { TCFProps } + + TCFProps = class + public + Cookies: String; + Expires: TDateTime; + CS: TRTLCriticalSection; + constructor Create; + destructor Destroy; override; + procedure Reset; + end; + +function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: TCFProps): Boolean; implementation @@ -97,7 +108,7 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; Result := True; end; -function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): Boolean; +function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String; var Expires: TDateTime): Boolean; var m, u, h: String; st, sc, counter, maxretry: Integer; @@ -129,9 +140,15 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B end; AHTTP.FollowRedirection := False; if AHTTP.HTTPRequest(m, FillHost(h, u)) then + begin Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; + if Result then + begin + Cookie := AHTTP.GetCookies; + Expires := AHTTP.CookiesExpires; + end; + end; AHTTP.FollowRedirection := True; - if Result then Cookie := AHTTP.GetCookies; end; if AHTTP.RetryCount <> 0 then begin @@ -147,52 +164,56 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String): B AHTTP.RetryCount := maxretry; end; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String; - var CS: TRTLCriticalSection): Boolean; +function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: TCFProps): Boolean; begin Result := False; if AHTTP = nil then Exit; - AHTTP.Cookies.Text := Cookie; + if (CFProps.Expires <> 0.0) and (Now > CFProps.Expires) then + CFProps.Reset; + AHTTP.Cookies.Text := CFProps.Cookies; AHTTP.AllowServerErrorResponse := True; Result := AHTTP.GET(AURL); if AntiBotActive(AHTTP) then begin - if TryEnterCriticalsection(CS) > 0 then + if TryEnterCriticalsection(CFProps.CS) > 0 then try - Result := CFJS(AHTTP, AURL, Cookie); + Result := CFJS(AHTTP, AURL, CFProps.Cookies, CFProps.Expires); + // reduce the expires by 1 hour, usually it is 24 hours or 16 hours + // in case of the different between local and server time + if Result then + CFProps.Expires := IncHour(CFProps.Expires, -1); finally - LeaveCriticalsection(CS); + LeaveCriticalsection(CFProps.CS); end else try - EnterCriticalsection(CS); - AHTTP.Cookies.Text := Cookie; + EnterCriticalsection(CFProps.CS); + AHTTP.Cookies.Text := CFProps.Cookies; finally - LeaveCriticalsection(CS); + LeaveCriticalsection(CFProps.CS); end; if not AHTTP.ThreadTerminated then Result := AHTTP.GET(AURL); end; end; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String; var Cookie: String): Boolean; +{ TCFProps } + +constructor TCFProps.Create; begin - Result := False; - if AHTTP = nil then Exit; - AHTTP.Cookies.Text := Cookie; - AHTTP.AllowServerErrorResponse := True; - Result := AHTTP.GET(AURL); - if AntiBotActive(AHTTP) then begin - Result := CFJS(AHTTP, AURL, Cookie); - Result := AHTTP.GET(AURL); - end; + Reset; + InitCriticalSection(CS); end; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String): Boolean; -var - Cookie: String; +destructor TCFProps.Destroy; +begin + DoneCriticalsection(CS); + inherited Destroy; +end; + +procedure TCFProps.Reset; begin - Cookie := ''; - Result := GETCF(AHTTP, AURL, Cookie); + Cookies := ''; + Expires := 0.0; end; end. From 64925089417c70b96442612d0466ab0be62d9505 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 May 2017 17:25:33 +0800 Subject: [PATCH 1737/2794] fix cf expires --- baseunits/modules/FoOlSlide.pas | 9 ++++----- baseunits/modules/GameofScanlation.pas | 13 ++++++------- baseunits/modules/KissManga.pas | 18 ++++++++---------- baseunits/modules/MangaGo.pas | 9 ++++----- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index f2508a5f8..4deb14884 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -11,8 +11,7 @@ interface implementation var - yomangalockget: TRTLCriticalSection; - yomangacookies: String; + yomangacf: TCFProps; const dirurl = '/directory/'; @@ -27,7 +26,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin if Module.Website = 'YoManga' then - Result := Cloudflare.GETCF(AHTTP, AURL, yomangacookies, yomangalockget) + Result := Cloudflare.GETCF(AHTTP, AURL, yomangacf) else if ((Module.Website = 'SeinagiAdultoFansub') or (Module.Website = 'TripleSevenScan')) @@ -289,10 +288,10 @@ procedure RegisterModule; end; initialization - InitCriticalSection(yomangalockget); + yomangacf := TCFProps.Create; RegisterModule; finalization - DoneCriticalsection(yomangalockget); + yomangacf.Free; end. diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index f47f0208d..d0fdfeafd 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -13,12 +13,11 @@ implementation const dirurl = '/projects/'; var - goscookies: String = ''; - goslockget: TRTLCriticalSection; + goscf: TCFProps; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; begin - Result := Cloudflare.GETCF(AHTTP, AURL, goscookies, goslockget); + Result := Cloudflare.GETCF(AHTTP, AURL, goscf); end; function GetNameAndLink(const MangaInfo: TMangaInformation; @@ -136,8 +135,8 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do if CurrentDownloadChapterPtr < ChapterLinks.Count then begin Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); - Cookies.Text := goscookies; - if (goscookies = '') or (HEAD(AURL) and (ResultCode = 503)) then + Cookies.Text := goscf.Cookies; + if (goscf.Cookies = '') or (HEAD(AURL) and (ResultCode = 503)) then Result := GETWithCookie(DownloadThread.FHTTP, Module.RootURL) else Result := True; @@ -158,10 +157,10 @@ procedure RegisterModule; end; initialization - InitCriticalSection(goslockget); + goscf := TCFProps.Create; RegisterModule; finalization - DoneCriticalsection(goslockget); + goscf.Free; end. diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index b1cfc7105..9e4555c6e 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -15,10 +15,8 @@ implementation readcomiconlinedirurl = '/ComicList/Newest'; var - kissmangacookies: String = ''; - kissmangalockget: TRTLCriticalSection; - readcomiconlinecookies: String = ''; - readcomiconlinelockget: TRTLCriticalSection; + kissmangacf: TCFProps; + readcomiconlinecf: TCFProps; kissmangaiv: String ='a5e8e2e9c2721be0a84ad660c472c1f3'; kissmangakey: String ='mshsdf832nsdbash20asdmnasdbasd612basd'; @@ -31,9 +29,9 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin if Module.Website = 'KissManga' then - Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacookies, kissmangalockget) + Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacf) else if Module.Website = 'ReadComicOnline' then - Result := Cloudflare.GETCF(AHTTP, AURL, readcomiconlinecookies, readcomiconlinelockget); + Result := Cloudflare.GETCF(AHTTP, AURL, readcomiconlinecf); end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; @@ -310,12 +308,12 @@ procedure RegisterModule; end; initialization - InitCriticalSection(kissmangalockget); - InitCriticalSection(readcomiconlinelockget); + kissmangacf := TCFProps.Create; + readcomiconlinecf := TCFProps.Create; RegisterModule; finalization - DoneCriticalsection(kissmangalockget); - DoneCriticalsection(readcomiconlinelockget); + kissmangacf.Free; + readcomiconlinecf.Free; end. diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 2d5e02f33..efeb377ca 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -11,15 +11,14 @@ interface implementation var - cookies: String; - lockget: TRTLCriticalSection; + mangagocf: TCFProps; const dirurl= '/list/directory/all/'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; begin - Result := Cloudflare.GETCF(AHTTP, AURL, cookies, lockget) + Result := Cloudflare.GETCF(AHTTP, AURL, mangagocf) end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; @@ -110,10 +109,10 @@ procedure RegisterModule; end; initialization - InitCriticalSection(lockget); + mangagocf := TCFProps.Create; RegisterModule; finalization - DoneCriticalsection(lockget); + mangagocf.Free; end. From 48f5b424f0e19bad2efd639902b67af3e53f5992 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 May 2017 18:12:56 +0800 Subject: [PATCH 1738/2794] kissmanga, test all combination posiibilities of key and iv closed #568 closed #569 closed #577 closed #580 --- baseunits/modules/KissManga.pas | 41 +++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 9e4555c6e..034444ad4 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -174,13 +174,19 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; var source: TStringList; i, chkop, ivp: Integer; - chkos, chko1, chko2, key, iv, s: String; + chkos, chko1, chko2, civ, key, iv: String; chkoa: Boolean; + s: String; - function testkeyiv: Boolean; + function testkeyiv(const akey, aiv: string): Boolean; begin if DownloadThread.Task.Container.PageLinks.Count=0 then Exit(False); - Result:=Pos('://',AESDecryptCBCSHA256Base64Pkcs7(DownloadThread.Task.Container.PageLinks[0],key,iv))<>0; + Result:=Pos('://',AESDecryptCBCSHA256Base64Pkcs7(DownloadThread.Task.Container.PageLinks[0],akey,aiv))<>0; + if Result then + begin + key := akey; + iv := aiv; + end; end; begin @@ -197,6 +203,7 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; chkos := ''; chko1 := ''; chko2 := ''; + civ := ''; key := ''; iv := ''; s := ''; @@ -241,32 +248,26 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; if chkop < source.Count then chko1 := source[chkop]; if (ivp <> -1) and (ivp < source.Count) then - iv := JSHexToStr(source[ivp]); + civ := JSHexToStr(source[ivp]); end; end; end; - if (chko1 <> '') or (chko2 <> '') then begin chko1 := JSHexToStr(chko1); chko2 := JSHexToStr(chko2); - if chkoa then - chko2 := chko1 + chko2; - if chko2 = '' then - chko2 := chko1; - key := chko2; - if iv = '' then - iv := kissmangaiv; - if not testkeyiv then - begin - key := kissmangakey; - iv := kissmangaiv; - if not testkeyiv then - PageLinks.Clear; - end; + if civ = '' then + civ := kissmangaiv; + // test all possibilities + if not testkeyiv(chko1, civ) then + if not testkeyiv(chko2, civ) then + if not testkeyiv(chko1+chko2, civ) then + if not testkeyiv(chko2+chko1, civ) then + if not testkeyiv(kissmangakey, kissmangaiv) then + PageLinks.Clear; end else - if not testkeyiv then + if not testkeyiv(kissmangakey, kissmangaiv) then PageLinks.Clear; if PageLinks.Count <> 0 then begin From f3e023cbd983b8665ccead7f1acee88a9144946d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 May 2017 18:39:11 +0800 Subject: [PATCH 1739/2794] httpsendthread, enclose parse expires in try except --- baseunits/httpsendthread.pas | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 761d29ae7..cdde768bd 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -338,9 +338,13 @@ procedure THTTPSendThread.ParseCookiesExpires; s := Copy(s, p, Length(s)); s := SeparateLeft(SeparateRight(s,'='),';'); s := Trim(SeparateLeft(s, 'GMT')); - c := ScanDateTime(HTTPCookieExpiresFormat, s, HTTPFormatSettings); - if (FCookiesExpires = 0.0) or (c < FCookiesExpires) then - FCookiesExpires := c; + c := 0.0; + try + c := ScanDateTime(HTTPCookieExpiresFormat, s, HTTPFormatSettings); + if (FCookiesExpires = 0.0) or (c < FCookiesExpires) then + FCookiesExpires := c; + except + end; end; end; end; From 5e62962440f1e1ce054393214f7215d486a648ca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 May 2017 18:42:18 +0800 Subject: [PATCH 1740/2794] Bump version 0.9.110.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 6 +++--- update | 10 +++++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0ad8909ff..c83801180 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.110.0 (02-05-2017) +[*] CF: fixed expired cookies +[*] KissManga: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.109.0...0.9.110.0 + 0.9.109.0 (30-03-2017) [*] KissManga: fixed download Full changes: https://github.com/riderkick/FMD/compare/0.9.108.0...0.9.109.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index afc079058..0d4ed9882 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="109"/> + <RevisionNr Value="110"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> @@ -216,8 +216,8 @@ </CompilerOptions> </Item5> <SharedMatrixOptions Count="2"> - <Item1 ID="284095981400" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-O3 -g- -CX -XX -Xs"/> - <Item2 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win32 Debug Leaks,Win64,Win32" Value="-O3 -g- -CX -XX -Xs"/> + <Item1 ID="284095981400" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz" Value="-O3 -g- -CX -XX -Xs"/> + <Item2 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-O3 -g- -CX -XX -Xs"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> diff --git a/update b/update index fa67dca1b..b8009a0c7 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.109.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.109.0/fmd_0.9.109.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.109.0/fmd_0.9.109.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.109.0/fmd_0.9.109.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.109.0/fmd_0.9.109.0_Win64.7z +VERSION=0.9.110.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.110.0/fmd_0.9.110.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.110.0/fmd_0.9.110.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.110.0/fmd_0.9.110.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.110.0/fmd_0.9.110.0_Win64.7z From 9906716f2009fed31cbdfb45c93d92d08fdfcdac Mon Sep 17 00:00:00 2001 From: GhostWriterTNCS <ghostwriter.tncs@gmail.com> Date: Fri, 12 May 2017 19:29:12 +0200 Subject: [PATCH 1741/2794] Added tapas.io --- baseunits/ModuleList.inc | 1 + baseunits/modules/Tapas.pas | 210 ++++++++++++++++++++++++++++++++++++ config/mangalist.ini | 1 + 3 files changed, 212 insertions(+) create mode 100644 baseunits/modules/Tapas.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 325bd3793..fcb38e204 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -51,6 +51,7 @@ uses MangaShiro, ReadMangaToday, MangaOnlineBR, + Tapas, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas new file mode 100644 index 000000000..469010b8d --- /dev/null +++ b/baseunits/modules/Tapas.pas @@ -0,0 +1,210 @@ +unit Tapas; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, Cloudflare, synautil, RegExpr; + +implementation + +const + dirurl = '/comics?sortType=TITLE&browse=ALL'; + +var + tapascf: TCFProps; + +function Split(const str: string; const separator: string): TStringList; +var + strline, strfield: string; + list: TStringList; +begin + strline := str; + list := TStringList.Create; + repeat + if Pos(separator, strline) > 0 then + begin + strfield := Copy(strline, 1, Pos(separator, strline) - 1); + strline := Copy(strline, Pos(separator, strline) + 1, +Length(strline) - pos(separator,strline)); + end + else + begin + strfield := strline; + strline := ''; + end; + list.Add(strfield); + until strline = ''; + Result := list; +end; + +function SubString(const str: string; const delimFrom: string; const delimTo: + string): string; +var + s: string; +begin + s := copy(str, Pos(delimFrom, str) + Length(delimFrom)); + Result := copy(s, 0, Pos(delimTo, s) - 1); +end; + +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): + Boolean; +begin + Result := Cloudflare.GETCF(AHTTP, AURL, tapascf) +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if MangaInfo.FHTTP.GET(s) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//div[@class="global-pagination-wrap"]/a[last()-1]'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := Module.RootURL + dirurl; + if AURL <> '0' then + s := s + '?pageNumber=' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[@class="content-list-wrap"]//li//a[@class="preferred title"]') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s: String; + caps: TStringList; + cap: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL)) then begin + Result := NO_ERROR; + with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + coverLink := XPathString('//a[@id="series-thumb"]/img/@src'); + if coverLink = '' then + begin + s := SubString(XPathString('//body'), '<div class="inner has-thumb">', '</div>'); + coverLink := SubString(s, '<img src="', '"'); + end; + + if title = '' then + begin + title := XPathString('//a[@class="series-header-title"]/text()'); + end; + genres := XPathString('//div[@class="tags"]'); + authors := XPathString('//a[@class="name"]/span/text()'); + summary := XPathString('//span[@id="series-desc-body"]'); + summary := StringReplace(summary, + ' ', '', [rfReplaceAll]); + + s := XPathString('//body'); + s := SubString(s, 'var _data', '}],'); + caps := TStringList.Create; + caps := Split(s, '},{'); + for cap in caps do begin + chapterLinks.Add('https://tapas.io/episode/' + SubString(cap, '"id":', ',')); + chapterName.Add(SubString(cap, '"title":"', '","thumbUrl":"')); + end; + finally + Free; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(FillHost(Module.RootURL, AURL)) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + with TRegExpr.Create do + try + Expression := '[\?\&]type=q\d+'; + for v in XPath('//img[@class="art-image"]/@src') do + PageLinks.Add(Replace(v.toString, '', False)); + finally + Free; + end; + finally + Free; + end; + end; + end; +end; + +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + var AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container do + if CurrentDownloadChapterPtr < ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer'] := + ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + Result := True; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Tapas'; + RootURL := 'https://tapas.io'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; + end; +end; + +initialization + tapascf := TCFProps.Create; + RegisterModule; + +finalization + tapascf.Free; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 684a8a115..aa4e8ed76 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -20,5 +20,6 @@ Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFans Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing +Webcomics=Tapas H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From fee7da90117244931c418e746a7087a702018342 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sun, 14 May 2017 21:07:50 +0530 Subject: [PATCH 1742/2794] NeoProject Scanlation changed domain --- baseunits/modules/FoOlSlide.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 4deb14884..301e8150d 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -277,7 +277,7 @@ procedure RegisterModule; AddWebsiteModule('MangaWorksFansub', 'http://lector.mangaworksfansub.net'); AddWebsiteModule('MasterPieceScans', 'http://reader.manga2me.net'); AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com'); - AddWebsiteModule('NeoProjectScan', 'http://npscan.scans-es.com'); + AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net'); AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com'); AddWebsiteModule('R15TeamScanlation', 'http://www.r15team.com'); AddWebsiteModule('SantosScan', 'http://santosfansub.com'); From bd1165a845532542686b15b841fc1132da42624b Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sat, 20 May 2017 13:16:12 +0530 Subject: [PATCH 1743/2794] Update MangaKoi Domain --- baseunits/modules/MangaKoi.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaKoi.pas index 60a88af06..9fc0e5009 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaKoi.pas @@ -158,7 +158,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaKoi'; - RootURL := 'http://www.mangakoi.com'; + RootURL := 'http://www.mangahome.com'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From f9ac5dc18184129b6785f405e884477a2792d001 Mon Sep 17 00:00:00 2001 From: Brandan White <kavin-90@users.noreply.github.com> Date: Sat, 20 May 2017 13:22:12 +0530 Subject: [PATCH 1744/2794] Update domain --- baseunits/modules/UnionMangas.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index a38a16edd..48e1c0579 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -87,7 +87,7 @@ procedure RegisterModule; with AddModule do begin Website := 'UnionMangas'; - RootURL := 'http://unionmangas.com.br'; + RootURL := 'http://unionmangas.net'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From af558beba8544d3a26ae028493278055840957a4 Mon Sep 17 00:00:00 2001 From: Supree Ariyadech <supree.ari@gec.co.th> Date: Mon, 22 May 2017 01:02:40 +0700 Subject: [PATCH 1745/2794] Update HeyManga --- baseunits/modules/HeyMangaXyz.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index ab3072005..e124d20ea 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -114,7 +114,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - PageNumber := XPath('//select[@id="page_list"]/option').Count - 1; + PageNumber := XPath('//select[@id="fuzetsu_list"]/option').Count - 1; for v in XPath('//picture/img') do PageLinks.Add(v.toNode.getAttribute('src')); finally From 3e85dd3f72a79190d28622a5e254616fb1f4dd22 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 May 2017 13:19:03 +0800 Subject: [PATCH 1746/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index aa1bd131e..fbc5f691f 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit aa1bd131e6eaeaf72526aaf40908ab7134525480 +Subproject commit fbc5f691f459aebd54909bb48ec8eb2e0cbf3df2 From c5f5a9a3fc5032705496f63cbf8ea2b12fa7230a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 May 2017 14:28:45 +0800 Subject: [PATCH 1747/2794] httpsendthread, fix get cookie expires --- baseunits/httpsendthread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index cdde768bd..7d291a7c4 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -340,7 +340,7 @@ procedure THTTPSendThread.ParseCookiesExpires; s := Trim(SeparateLeft(s, 'GMT')); c := 0.0; try - c := ScanDateTime(HTTPCookieExpiresFormat, s, HTTPFormatSettings); + c := UniversalTimeToLocal(ScanDateTime(HTTPCookieExpiresFormat, s, HTTPFormatSettings)); if (FCookiesExpires = 0.0) or (c < FCookiesExpires) then FCookiesExpires := c; except From 7d6f82f242e7996cc4fdac0b6fa202ac2f153900 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 May 2017 14:29:33 +0800 Subject: [PATCH 1748/2794] cf, reduce cookie expires by 5 minutes --- baseunits/modules/Cloudflare.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 87bf5adef..e053b7802 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -177,10 +177,10 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: if TryEnterCriticalsection(CFProps.CS) > 0 then try Result := CFJS(AHTTP, AURL, CFProps.Cookies, CFProps.Expires); - // reduce the expires by 1 hour, usually it is 24 hours or 16 hours + // reduce the expires by 5 minutes, usually it is 24 hours or 16 hours // in case of the different between local and server time if Result then - CFProps.Expires := IncHour(CFProps.Expires, -1); + CFProps.Expires := IncMinute(CFProps.Expires, -5); finally LeaveCriticalsection(CFProps.CS); end From 825450e2b2c529d57fc4af878159ae911ccdb632 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 May 2017 15:47:17 +0800 Subject: [PATCH 1749/2794] fixed tumangaonline --- baseunits/modules/Tumangaonline.pas | 37 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index df5b0485b..158c8a3d9 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, Cloudflare, synautil, RegExpr; implementation @@ -17,7 +17,16 @@ implementation dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage='; perpage = '1000'; mangaurl = '/biblioteca/mangas/'; - imgurl = 'http://img1.tumangaonline.com'; + imgurl = 'https://img1.tumangaonline.com'; + +var + tumangacf: TCFProps; + +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): + Boolean; +begin + Result := Cloudflare.GETCF(AHTTP, AURL, tumangacf); +end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; @@ -25,7 +34,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1&page=1') then + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + '1&page=1') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -45,7 +54,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -76,7 +85,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; url := FillHost(Module.RootURL, AURL); mangaid := RegExprGetMatch('/mangas/(\d+)/', url, 1); if mangaid = '' then Exit; - if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + apiurlmangas + '/' + mangaid) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -133,7 +142,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then + if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -149,21 +158,35 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String end; end; +function DownloadImageWithCookie(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + if GETWithCookie(DownloadThread.FHTTP, AURL) then + result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; +end; + procedure RegisterModule; begin with AddModule do begin Website := 'Tumangaonline'; - RootURL := 'http://www.tumangaonline.com'; + RootURL := 'https://www.tumangaonline.com'; MaxTaskLimit := 1; MaxConnectionLimit := 1; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImageWithCookie; end; end; initialization + tumangacf := TCFProps.Create; RegisterModule; +finalization + tumangacf.Free; + end. From e21400ea9131f7e3b6afa9659417c04e27c6671e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 May 2017 16:35:13 +0800 Subject: [PATCH 1750/2794] tapas, fix and cleanup --- baseunits/modules/Tapas.pas | 69 ++++++------------------------------- 1 file changed, 11 insertions(+), 58 deletions(-) diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index 469010b8d..9526bc311 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Cloudflare, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, Cloudflare, RegExpr; implementation @@ -16,39 +16,6 @@ implementation var tapascf: TCFProps; -function Split(const str: string; const separator: string): TStringList; -var - strline, strfield: string; - list: TStringList; -begin - strline := str; - list := TStringList.Create; - repeat - if Pos(separator, strline) > 0 then - begin - strfield := Copy(strline, 1, Pos(separator, strline) - 1); - strline := Copy(strline, Pos(separator, strline) + 1, -Length(strline) - pos(separator,strline)); - end - else - begin - strfield := strline; - strline := ''; - end; - list.Add(strfield); - until strline = ''; - Result := list; -end; - -function SubString(const str: string; const delimFrom: string; const delimTo: - string): string; -var - s: string; -begin - s := copy(str, Pos(delimFrom, str) + Length(delimFrom)); - Result := copy(s, 0, Pos(delimTo, s) - 1); -end; - function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; begin @@ -103,9 +70,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - s: String; - caps: TStringList; - cap: String; + v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -114,29 +79,17 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try coverLink := XPathString('//a[@id="series-thumb"]/img/@src'); - if coverLink = '' then - begin - s := SubString(XPathString('//body'), '<div class="inner has-thumb">', '</div>'); - coverLink := SubString(s, '<img src="', '"'); - end; - - if title = '' then - begin - title := XPathString('//a[@class="series-header-title"]/text()'); - end; - genres := XPathString('//div[@class="tags"]'); + if coverLink = '' then coverLink := XPathString('//script[contains(.,"has-thumb")]/substring-before(substring-after(.,"src="""),"""")'); + if title = '' then title := XPathString('//a[@class="series-header-title"]/text()'); + genres := XPathString('//div[@class="tags"]/string-join(./*,", ")'); authors := XPathString('//a[@class="name"]/span/text()'); summary := XPathString('//span[@id="series-desc-body"]'); - summary := StringReplace(summary, - ' ', '', [rfReplaceAll]); - - s := XPathString('//body'); - s := SubString(s, 'var _data', '}],'); - caps := TStringList.Create; - caps := Split(s, '},{'); - for cap in caps do begin - chapterLinks.Add('https://tapas.io/episode/' + SubString(cap, '"id":', ',')); - chapterName.Add(SubString(cap, '"title":"', '","thumbUrl":"')); + while Pos(' ', summary) <> 0 do + summary := StringReplace(summary, ' ', ' ', [rfReplaceAll]); + for v in XPath('json(//script[contains(.,"var _data")]/concat(substring-before(substring-after(.,"episodeList :"),"]"),"]"))()') do + begin + chapterLinks.Add(Module.RootURL + '/episode/' + XPathString('./id', v)); + chapterName.Add(XPathString('./title', v)); end; finally Free; From 4aa7c4b41f8e8a0463349013a918ba25ebeced8e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 May 2017 17:26:16 +0800 Subject: [PATCH 1751/2794] Bump version 0.9.111.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 4 ++-- update | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index c83801180..0df4b1e5a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.111.0 (23-05-2017) +[*] Added Tapas +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.110.0...0.9.111.0 + 0.9.110.0 (02-05-2017) [*] CF: fixed expired cookies [*] KissManga: fixed download diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0d4ed9882..ca9e5d951 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,9 +18,9 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="110"/> + <RevisionNr Value="111"/> <Attributes pvaPrivateBuild="True"/> - <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2016" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> + <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> <BuildModes Count="5"> <Item1 Name="Win32" Default="True"/> diff --git a/update b/update index b8009a0c7..f5b0ecc7e 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.110.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.110.0/fmd_0.9.110.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.110.0/fmd_0.9.110.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.110.0/fmd_0.9.110.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.110.0/fmd_0.9.110.0_Win64.7z +VERSION=0.9.111.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.111.0/fmd_0.9.111.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.111.0/fmd_0.9.111.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.111.0/fmd_0.9.111.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.111.0/fmd_0.9.111.0_Win64.7z From 0a3bd5e112279137a0197f05d64e5ffd16924b93 Mon Sep 17 00:00:00 2001 From: Ghost Writer <ghostwriter.tncs@gmail.com> Date: Tue, 23 May 2017 14:32:11 +0200 Subject: [PATCH 1752/2794] Tapas manga list issue Hi! Thank you for merging my pull request. Testing the new release, I've found this stupid mistake, sorry ^.^" Bye! --- baseunits/modules/Tapas.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index 9526bc311..9ce4330db 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -52,7 +52,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks if MangaInfo = nil then Exit(UNKNOWN_ERROR); s := Module.RootURL + dirurl; if AURL <> '0' then - s := s + '?pageNumber=' + IncStr(AURL); + s := s + '&pageNumber=' + IncStr(AURL); if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do From 855c24de6281d9ca43940ac37d7c5b4be4cd6b64 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 24 May 2017 14:59:44 +0800 Subject: [PATCH 1753/2794] update changelog --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index 0df4b1e5a..394390523 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,7 @@ Changelog: 0.9.111.0 (23-05-2017) [*] Added Tapas +[*] Tumangaonline: fixed all [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.110.0...0.9.111.0 From 57b20385a32300481499063d87aae0062ffc18bc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 May 2017 16:14:58 +0800 Subject: [PATCH 1754/2794] hitomi, fixed download --- baseunits/modules/HitomiLa.pas | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index fec34217d..ebf803df3 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -100,6 +100,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var v: IXQValue; + galleryid: Integer; + subdomain: String; begin Result := False; if DownloadThread = nil then Exit; @@ -112,7 +114,19 @@ function GetPageNumber(const DownloadThread: TDownloadThread; try for v in XPath('//div[@class="img-url"]') do PageLinks.Add(FillURLProtocol('https://', v.toString)); - PageNumber := PageLinks.Count + PageNumber := PageLinks.Count; + // https://ltn.hitomi.la/reader.js + if PageLinks.Count <> 0 then + begin + galleryid := -1; + subdomain := ''; + galleryid := StrToIntDef(ReplaceRegExpr('(?i)^.*reader/(\d+).*$', AURL, '$1', True), -1); + if galleryid <> -1 then + begin + subdomain := 'https://' + Char(97 + (galleryid mod 2)) + 'a.hitomi.la'; + FillHost(subdomain, PageLinks); + end; + end; finally Free; end; From 7a7aaf889ba100fb0a6005ec99a182687b04f67f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 May 2017 17:10:07 +0800 Subject: [PATCH 1755/2794] mangago, fixed download close #570 close #573 --- baseunits/modules/MangaGo.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index efeb377ca..f48302b0d 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -88,7 +88,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - s := XPathString('//script[contains(.,"imgsrcs")]/substring-before(substring-after(substring-before(.,"imgsrcs"),"''"),"''")', Document); + s := XPathString('//script[contains(.,"imgsrcs")]/substring-before(substring-after(substring-before(.,"imgsrcs"),"= ''"),"''")', Document); if s <> '' then PageLinks.CommaText := s end; From b231c48072bec462a643df3a29ffe12d26a080e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 May 2017 18:07:24 +0800 Subject: [PATCH 1756/2794] Bump version 0.9.112.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 394390523..83042e9f7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,9 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.112.0 (29-05-2017) +[*] HitomiLa: fixed download +[*] MangaGo: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.111.0...0.9.112.0 + 0.9.111.0 (23-05-2017) [*] Added Tapas [*] Tumangaonline: fixed all +[*] NeoProjectScan: fixed domain [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.110.0...0.9.111.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ca9e5d951..38bc51a76 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="111"/> + <RevisionNr Value="112"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index f5b0ecc7e..07d4d2493 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.111.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.111.0/fmd_0.9.111.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.111.0/fmd_0.9.111.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.111.0/fmd_0.9.111.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.111.0/fmd_0.9.111.0_Win64.7z +VERSION=0.9.112.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.112.0/fmd_0.9.112.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.112.0/fmd_0.9.112.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.112.0/fmd_0.9.112.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.112.0/fmd_0.9.112.0_Win64.7z From 42f48556dbe8062112154191e5f5410daa689c87 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Jun 2017 17:31:58 +0800 Subject: [PATCH 1757/2794] pururin, fixed all --- baseunits/modules/Pururin.pas | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/Pururin.pas b/baseunits/modules/Pururin.pas index c9be627f2..054d2d3a8 100644 --- a/baseunits/modules/Pururin.pas +++ b/baseunits/modules/Pururin.pas @@ -17,7 +17,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if MangaInfo.FHTTP.GET(Module.RootURL) then begin Result := NO_ERROR; - Page := StrToIntDef(XPathString('//*[contains(@class,"pager")]/a[last()]', MangaInfo.FHTTP.Document), 1); + Page := StrToIntDef(XPathString('//*[@class="pagination"]/li[last()-1]', MangaInfo.FHTTP.Document), 1); end; end; @@ -28,15 +28,15 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/browse/search/1/' + IncStr(AURL) + '.html') then + if MangaInfo.FHTTP.GET(Module.RootURL + '/browse/newest?page=' + IncStr(AURL)) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//*[@class="gallery-list"]/li//a') do + for v in XPath('//*[@class="gallery-listing"]/*[@class="row"]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('.//*[@class="title"]//h2/text()[1]', v)); + ANames.Add(XPathString('.//*[@class="title"]/text()[1]', v)); end; finally Free; @@ -56,11 +56,12 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="gallery-cover"]//img/@src')); - if title = '' then title := XPathString('//*[@class="gallery-info"]/h1'); - artists := XPathString('//*[@class="table-info"]//tr/td[starts-with(.,"Artist")]/following-sibling::td[1]/string-join(.//a,", ")'); - genres := XPathString('//*[@class="table-info"]/string-join(.//tr/td//a,", ")'); - XPathHREFAll('//*[@class="table-data"]//tr/td[2]/a', chapterLinks, chapterName); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]//img/@src')); + if title = '' then title := XPathString('//*[@class="gallery-info"]//*[@class="title"]'); + artists := XPathString('//*[@class="gallery-info"]//*[@class="table"]//tr/td[starts-with(.,"Artist")]/following-sibling::td[1]/string-join(.//a,", ")'); + genres := XPathString('//*[@class="gallery-info"]//*[@class="table"]/string-join(.//tr/td//a,", ")'); + chapterLinks.Add(XPathString('//a[@class="read-more"]/@href')); + chapterName.Add(title); finally Free; end; @@ -80,7 +81,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('json(//script[contains(.,"chapter_page")]/substring-before(substring-after(.,"= "),";"))//chapter_image', Document, PageLinks); + XPathStringAll('json(//script[contains(.,"var chapters")]/substring-before(substring-after(.,"= "),";"))//image', Document, PageLinks); end; end; end; @@ -90,7 +91,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Pururin'; - RootURL := 'https://pururin.us'; + RootURL := 'https://www.pururin.us'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; From d3e72190ae175c1de1635a33c233a225e92868fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Jun 2017 19:27:17 +0800 Subject: [PATCH 1758/2794] changed layout, downloads, mangainfo, filter merged accordingly --- mangadownloader/forms/frmMain.lfm | 4451 ++++++++++++------------ mangadownloader/forms/frmMain.lrj | 15 +- mangadownloader/forms/frmMain.pas | 45 +- mangadownloader/languages/fmd.el_GR.po | 23 +- mangadownloader/languages/fmd.en.po | 22 +- mangadownloader/languages/fmd.es.po | 25 +- mangadownloader/languages/fmd.id_ID.po | 24 +- mangadownloader/languages/fmd.pl_PL.po | 23 +- mangadownloader/languages/fmd.po | 20 +- mangadownloader/languages/fmd.pt_BR.po | 23 +- 10 files changed, 2350 insertions(+), 2321 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index b757b001d..3e5e91d87 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.7' + LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar Left = 0 Height = 30 @@ -33,732 +33,533 @@ object MainForm: TMainForm OnDrawPanel = sbUpdateListDrawPanel end object pcMain: TPageControl - Left = 201 - Height = 520 - Top = 11 - Width = 566 + Left = 2 + Height = 526 + Top = 8 + Width = 769 ActivePage = tsDownload Align = alClient - BorderSpacing.Top = 3 - BorderSpacing.Right = 4 - BorderSpacing.Bottom = 3 ParentFont = False TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet Caption = 'Downloads' - ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 492 - ClientWidth = 558 - object vtDownload: TVirtualStringTree - AnchorSideTop.Side = asrBottom - Left = 4 - Height = 456 - Top = 31 - Width = 549 - Anchors = [akTop, akLeft, akRight, akBottom] - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - DragOperations = [doMove] - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Manga' - Width = 100 - end - item - Position = 1 - Text = 'Status' - Width = 200 - end - item - Position = 2 - Text = 'Progress' - Width = 55 - end - item - Position = 3 - Text = 'Transfer rate' - end - item - Position = 4 - Text = 'Website' - Width = 65 - end - item - Position = 5 - Text = 'Save to' - Width = 150 - end - item - Position = 6 - Text = 'Added' - Width = 80 - end> - Header.DefaultHeight = 17 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] - HintMode = hmHintAndDefault - Images = IconDL - Margin = 2 - ParentFont = False - ParentShowHint = False - PopupMenu = pmDownload - ShowHint = True - TabOrder = 0 - TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnColumnDblClick = vtDownloadColumnDblClick - OnDragAllowed = vtDownloadDragAllowed - OnDragOver = vtDownloadDragOver - OnDragDrop = vtDownloadDragDrop - OnDrawText = vtDownloadDrawText - OnFocusChanged = vtDownloadFocusChanged - OnGetText = vtDownloadGetText - OnPaintText = vtDownloadPaintText - OnGetImageIndex = vtDownloadGetImageIndex - OnGetHint = vtDownloadGetHint - OnHeaderClick = vtDownloadHeaderClick - OnKeyAction = vtDownloadKeyAction - OnKeyDown = vtDownloadKeyDown - OnKeyUp = vtDownloadKeyUp - end - object pnDownloadToolbar: TPanel - AnchorSideLeft.Control = edDownloadsSearch - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrCenter - Left = 158 - Height = 24 - Top = 3 - Width = 395 - Anchors = [akTop, akLeft, akRight] - BevelOuter = bvNone - ClientHeight = 24 - ClientWidth = 395 - TabOrder = 1 - object TransferRateGraph: TChart - Left = 321 - Height = 24 - Top = 0 - Width = 74 - AllowZoom = False - AxisList = < - item - Minors = <> - Title.LabelFont.Orientation = 900 - end - item - Alignment = calBottom - Minors = <> - end> - AxisVisible = False - BackColor = clDefault - Extent.UseXMin = True - Extent.UseYMin = True - Extent.XMin = 1 - Extent.YMin = 1 - Foot.Brush.Color = clBtnFace - Foot.Font.Color = clBlue - Frame.Color = clGreen - Frame.Visible = False - Legend.Alignment = laCenterRight - Legend.BackgroundBrush.Style = bsClear - Legend.Frame.Visible = False - Legend.MarginX = 0 - Legend.MarginY = 0 - Legend.Spacing = 0 - Legend.SymbolWidth = 0 - Legend.UseSidebar = False - Legend.Visible = True - Margins.Left = 0 - Margins.Top = 0 - Margins.Right = 0 - Margins.Bottom = 0 - MarginsExternal.Left = 0 - MarginsExternal.Top = 0 - MarginsExternal.Right = 0 - MarginsExternal.Bottom = 0 - Title.Brush.Color = clBtnFace - Title.Font.Color = clBlue - Title.Text.Strings = ( - 'TAChart' - ) - Toolset = TransferRateToolset - Align = alClient - Visible = False - object TransferRateGraphArea: TAreaSeries - Transparency = 125 - AreaBrush.Color = 8453888 - AreaContourPen.Color = 5481984 - AreaLinesPen.Style = psClear - Source = TransferRateGraphList - end - end - object pnDownloadToolbarLeft: TPanel + ClientHeight = 498 + ClientWidth = 761 + object psDownloads: TPairSplitter + Left = 0 + Height = 490 + Top = 4 + Width = 761 + Align = alClient + Position = 200 + object pssDownloadsFilter: TPairSplitterSide + Cursor = crArrow Left = 0 - Height = 24 + Height = 490 Top = 0 - Width = 321 - Align = alLeft - AutoSize = True - BevelOuter = bvNone - ClientHeight = 24 - ClientWidth = 321 - TabOrder = 1 - object ToolBarDownload: TToolBar + Width = 200 + ClientWidth = 200 + ClientHeight = 490 + object tvDownloadFilter: TTreeView Left = 0 - Height = 24 + Height = 490 Top = 0 - Width = 321 + Width = 200 Align = alClient - AutoSize = True - ButtonHeight = 25 - EdgeBorders = [] + AutoExpand = True Images = IconList - List = True - ParentFont = False - ShowCaptions = True + ReadOnly = True TabOrder = 0 - TabStop = True - Transparent = True - object tbDownloadResumeAll: TToolButton - Left = 1 - Top = 0 - AutoSize = True - Caption = 'Resume All' - ImageIndex = 12 - OnClick = tbDownloadResumeAllClick - end - object tbDownloadStopAll: TToolButton - Left = 86 - Top = 0 - AutoSize = True - Caption = 'Stop All' - ImageIndex = 7 - OnClick = tbDownloadStopAllClick - end - object tbSeparator1: TToolButton - Left = 153 - Height = 25 - Top = 0 - Style = tbsDivider - Visible = False - end - object tbDownloadDeleteCompleted: TToolButton - Left = 158 - Top = 0 - AutoSize = True - Caption = 'Delete all completed tasks' - ImageIndex = 9 - OnClick = tbDownloadDeleteCompletedClick - Visible = False - end + OnSelectionChanged = tvDownloadFilterSelectionChanged + Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end end - end - object edDownloadsSearch: TEditButton - Left = 4 - Height = 23 - Top = 4 - Width = 150 - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 - 00070000000E00000014000000190000001A0000001900000017000000150000 - 00120000000E0000000B00000008000000050000000200000001000000020000 - 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 - 305D0000001C000000160000000F0000000A0000000400000001000000000000 - 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 - 5ACA00224248000D170000000000000000000000000000000000000000000000 - 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 - ABFF003763C600356046002D4E00010101000000000000000000013048000021 - 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA - C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B - 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 - C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B - 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 - CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E - 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA - D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D - 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 - 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 - 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 - D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 - 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 - 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 - 94000162930001619200016293000162930001639400000000240000006788CC - DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 - 940001629300016192000162930001629300016394000000000001334C390165 - 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 - 940001629300016192000162930001629300016394000000000001334C000165 - 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - MaxLength = 0 - NumGlyphs = 1 - OnButtonClick = edDownloadsSearchButtonClick - OnChange = edDownloadsSearchChange - PasswordChar = #0 - TabOrder = 2 - TextHint = 'Search downloads...' - end - end - object tsInformation: TTabSheet - Caption = 'Manga Info' - ClientHeight = 492 - ClientWidth = 558 - object sbInformation: TScrollBox - Left = 0 - Height = 492 - Top = 0 - Width = 558 - HorzScrollBar.Page = 316 - VertScrollBar.Page = 417 - Align = alClient - BorderStyle = bsNone - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 8 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 492 - ClientWidth = 558 - TabOrder = 0 - object pnInfomation: TPanel - Left = 4 - Height = 248 - Top = 8 - Width = 550 - Align = alTop - BevelOuter = bvNone + object pssDownloads: TPairSplitterSide + Cursor = crArrow + Left = 205 + Height = 490 + Top = 0 + Width = 556 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 248 - ClientWidth = 550 - ParentFont = False - TabOrder = 0 - object rmInformation: TRichMemo - AnchorSideLeft.Control = pnThumbContainer - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edURL + ClientWidth = 556 + ClientHeight = 490 + object vtDownload: TVirtualStringTree + AnchorSideTop.Control = edDownloadsSearch AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = edURL - AnchorSideRight.Side = asrBottom - Left = 158 - Height = 219 + Left = 0 + Height = 463 Top = 27 - Width = 392 + Width = 556 + Align = alBottom Anchors = [akTop, akLeft, akRight, akBottom] - HideSelection = False - ReadOnly = True - ScrollBars = ssAutoVertical + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + DragOperations = [doMove] + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Manga' + Width = 100 + end + item + Position = 1 + Text = 'Status' + Width = 200 + end + item + Position = 2 + Text = 'Progress' + Width = 55 + end + item + Position = 3 + Text = 'Transfer rate' + end + item + Position = 4 + Text = 'Website' + Width = 65 + end + item + Position = 5 + Text = 'Save to' + Width = 150 + end + item + Position = 6 + Text = 'Added' + Width = 80 + end> + Header.DefaultHeight = 17 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] + HintMode = hmHintAndDefault + Images = IconDL + Margin = 2 + ParentFont = False + ParentShowHint = False + PopupMenu = pmDownload + ShowHint = True TabOrder = 0 - ZoomFactor = 1 - end - object btDonate: TImage - Cursor = crHandPoint - Left = -54 - Height = 21 - Top = 14 - Width = 75 - Anchors = [akTop, akRight] - OnClick = btDonateClick - Stretch = True - Visible = False + TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnColumnDblClick = vtDownloadColumnDblClick + OnDragAllowed = vtDownloadDragAllowed + OnDragOver = vtDownloadDragOver + OnDragDrop = vtDownloadDragDrop + OnDrawText = vtDownloadDrawText + OnFocusChanged = vtDownloadFocusChanged + OnGetText = vtDownloadGetText + OnPaintText = vtDownloadPaintText + OnGetImageIndex = vtDownloadGetImageIndex + OnGetHint = vtDownloadGetHint + OnHeaderClick = vtDownloadHeaderClick + OnKeyAction = vtDownloadKeyAction + OnKeyDown = vtDownloadKeyDown + OnKeyUp = vtDownloadKeyUp end - object pnThumbContainer: TPanel - AnchorSideLeft.Control = edURL - AnchorSideTop.Control = edURL - AnchorSideTop.Side = asrBottom - Left = 0 - Height = 216 - Top = 27 - Width = 154 + object pnDownloadToolbar: TPanel + AnchorSideLeft.Control = edDownloadsSearch + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edDownloadsSearch + AnchorSideTop.Side = asrCenter + Left = 154 + Height = 24 + Top = -1 + Width = 457 + Anchors = [akTop, akLeft, akRight] BevelOuter = bvNone - BorderStyle = bsSingle - ClientHeight = 212 - ClientWidth = 150 - Color = clWhite - ParentColor = False + ClientHeight = 24 + ClientWidth = 457 TabOrder = 1 - object imCover: TImage - Left = 0 - Height = 212 + object TransferRateGraph: TChart + Left = 321 + Height = 24 Top = 0 - Width = 150 - AntialiasingMode = amOn + Width = 136 + AllowZoom = False + AxisList = < + item + Minors = <> + Title.LabelFont.Orientation = 900 + end + item + Alignment = calBottom + Minors = <> + end> + AxisVisible = False + BackColor = clDefault + Extent.UseXMin = True + Extent.UseYMin = True + Extent.XMin = 1 + Extent.YMin = 1 + Foot.Brush.Color = clBtnFace + Foot.Font.Color = clBlue + Frame.Color = clGreen + Frame.Visible = False + Legend.Alignment = laCenterRight + Legend.BackgroundBrush.Style = bsClear + Legend.Frame.Visible = False + Legend.MarginX = 0 + Legend.MarginY = 0 + Legend.Spacing = 0 + Legend.SymbolWidth = 0 + Legend.UseSidebar = False + Legend.Visible = True + Margins.Left = 0 + Margins.Top = 0 + Margins.Right = 0 + Margins.Bottom = 0 + MarginsExternal.Left = 0 + MarginsExternal.Top = 0 + MarginsExternal.Right = 0 + MarginsExternal.Bottom = 0 + Title.Brush.Color = clBtnFace + Title.Font.Color = clBlue + Title.Text.Strings = ( + 'TAChart' + ) + Toolset = TransferRateToolset Align = alClient - Center = True - Proportional = True - Stretch = True + Visible = False + object TransferRateGraphArea: TAreaSeries + Transparency = 125 + AreaBrush.Color = 8453888 + AreaContourPen.Color = 5481984 + AreaLinesPen.Style = psClear + Source = TransferRateGraphList + end end - object pbWait: TPaintBox + object pnDownloadToolbarLeft: TPanel Left = 0 - Height = 212 + Height = 24 Top = 0 - Width = 150 - Align = alClient + Width = 321 + Align = alLeft + AutoSize = True + BevelOuter = bvNone + ClientHeight = 24 + ClientWidth = 321 + TabOrder = 1 + object ToolBarDownload: TToolBar + Left = 0 + Height = 24 + Top = 0 + Width = 321 + Align = alClient + AutoSize = True + ButtonHeight = 25 + ButtonWidth = 23 + EdgeBorders = [] + Images = IconList + List = True + ParentFont = False + ShowCaptions = True + TabOrder = 0 + TabStop = True + Transparent = True + object tbDownloadResumeAll: TToolButton + Left = 1 + Top = 0 + AutoSize = True + Caption = 'Resume All' + ImageIndex = 12 + OnClick = tbDownloadResumeAllClick + end + object tbDownloadStopAll: TToolButton + Left = 86 + Top = 0 + AutoSize = True + Caption = 'Stop All' + ImageIndex = 7 + OnClick = tbDownloadStopAllClick + end + object tbSeparator1: TToolButton + Left = 153 + Height = 25 + Top = 0 + Style = tbsDivider + Visible = False + end + object tbDownloadDeleteCompleted: TToolButton + Left = 158 + Top = 0 + AutoSize = True + Caption = 'Delete all completed tasks' + ImageIndex = 9 + OnClick = tbDownloadDeleteCompletedClick + Visible = False + end + end end end - object edURL: TEditButton + object edDownloadsSearch: TEditButton Left = 0 Height = 23 Top = 0 - Width = 550 - Align = alTop - ButtonWidth = 30 + Width = 150 + ButtonWidth = 23 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0001000000070000000E000000150000001A0000001A0000001A0000001A0000 - 001A0000001A000000160000000F0000000800000002FFFFFF00FFFFFF000000 - 00020000000E0000001C0000002A000000330000003300000033733A02A66332 - 0274000000330000002B0000001D0000000F00000003FFFFFF00FFFFFF000000 - 00000000000000000000000000000000000000000000281502009D5206CC9D52 - 06CC763E055C29160300000000000000000000000000FFFFFF00FFFFFF005933 - 0B0058320A0058320A0058320A0058320A0058320A00A3580B00A3580BCCFFBA - 18FFA3580BCCA4590C5C7F470C002C19050000000000FFFFFF00FFFFFF00B166 - 1600AF641400AF641400AF641400AF641400AF641400AE631300AA5F10CCFFB9 - 12FFFFBC1EFFAA5F10CCAB60115CB1661600B96E1C00FFFFFF00FFFFFF00B267 - 1799B16616CCB16616CCB16616CCB16616CCB16616CCB16616CCB16616CCF7B5 - 25FFF5AB0EFFF7BA32FFB16616CCB267175CB96E1C00FFFFFF00FFFFFF00B96E - 1CCCF7CD81FFF4C276FFF3C071FFEEB85BFFE8B049FFE7AE45FFE6AD43FFE3A5 - 35FFE19E29FFE19E29FFEBB54DFFB96E1CCCBA6F1D5CFFFFFF00FFFFFF00C277 - 22CCF5C77BFFEEB266FFEEB266FFEEB266FFEAAE60FFE1A453FFD89B49FFD396 - 44FFD09341FFD09341FFD39644FFE8B868FFC27722CCFFFFFF00FFFFFF00CA7F - 28CCFAD589FFF6C97DFFF6C87CFFF5C77BFFF5C77BFFF5C67AFFF5C579FFF2BC - 70FFEFB468FFEFB468FFF8CF83FFCA7F28CCC97E275CFFFFFF00FFFFFF00D186 - 2D99D2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCF8CD - 81FFF4BE72FFFCD98DFFD2872ECCD1862D5CCA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00D3882F00D3882F00D58A3100D98E33CCFCD5 - 89FFFEE094FFD98E33CCD88D335CD2872E00CA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00D3882F00D78C3200E0953800E09538CCFFE4 - 98FFE09538CCDF94385CD98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00D88D3300E59A3C00E59A3C00E59A3CCCE59A - 3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 - 2E00D3882F00D3882F00D3882F00E89D3F00E89D3F00E89D3F00E99E4099E99E - 405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } MaxLength = 0 NumGlyphs = 1 - OnButtonClick = edURLButtonClick - OnKeyPress = edURLKeyPress + OnButtonClick = edDownloadsSearchButtonClick + OnChange = edDownloadsSearchChange PasswordChar = #0 - PopupMenu = pmEditURL TabOrder = 2 - TextHint = 'Input URL here' + TextHint = 'Search downloads...' end end - object spInfos: TSplitter - Cursor = crVSplit - Left = 4 - Height = 5 - Top = 260 - Width = 550 - Align = alTop - ResizeAnchor = akTop - end - object pnChapterList: TPanel - Left = 4 - Height = 215 - Top = 269 - Width = 550 - Align = alClient - BevelOuter = bvNone + end + end + object tsInformation: TTabSheet + Caption = 'Manga Info' + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 498 + ClientWidth = 761 + object psInfo: TPairSplitter + Left = 0 + Height = 490 + Top = 4 + Width = 761 + Align = alClient + Position = 200 + object pssInfoList: TPairSplitterSide + Cursor = crArrow + Left = 0 + Height = 490 + Top = 0 + Width = 200 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 215 - ClientWidth = 550 - TabOrder = 2 - object clbChapterList: TVirtualStringTree - AnchorSideLeft.Control = edFilterMangaInfoChapters - AnchorSideTop.Control = edFilterMangaInfoChapters - AnchorSideRight.Control = btChecks - AnchorSideBottom.Control = btDownload + ClientWidth = 200 + ClientHeight = 490 + object vtMangaList: TVirtualStringTree + AnchorSideTop.Control = lbMode + AnchorSideTop.Side = asrBottom Left = 0 - Height = 125 - Top = 0 - Width = 520 + Height = 409 + Top = 81 + Width = 200 + Align = alBottom Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Top = 8 Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight Colors.SelectionRectangleBorderColor = clHotLight Colors.UnfocusedSelectionBorderColor = clBtnShadow DefaultText = 'Node' + DragOperations = [] Header.AutoSizeIndex = 0 Header.Columns = <> Header.DefaultHeight = 17 Header.Height = 23 Header.MainColumn = -1 - Margin = 2 - ParentFont = False - PopupMenu = pmChapterList + HintMode = hmHint + Margin = 0 + ParentShowHint = False + PopupMenu = pmMangaList + ShowHint = True TabOrder = 0 - TextMargin = 0 + TextMargin = 3 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnBeforeCellPaint = clbChapterListBeforeCellPaint - OnGetText = clbChapterListGetText - OnInitNode = clbChapterListInitNode + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] + OnBeforeCellPaint = vtMangaListBeforeCellPaint + OnChange = vtMangaListChange + OnColumnDblClick = vtMangaListColumnDblClick + OnGetCursor = vtMangaListGetCursor + OnGetText = vtMangaListGetText + OnGetHint = vtMangaListGetHint end - object btDownload: TBitBtn - AnchorSideLeft.Control = btAddToFavorites - AnchorSideTop.Control = btDownloadSplit - AnchorSideRight.Control = btDownloadSplit - AnchorSideBottom.Control = btReadOnline - Left = 420 - Height = 26 - Top = 129 - Width = 100 - Anchors = [akLeft, akRight, akBottom] - AutoSize = True - Caption = 'Download' + object btAbortUpdateList: TSpeedButton + Left = 104 + Height = 22 + Hint = 'Abort update list' + Top = 104 + Width = 23 + Flat = True Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 + 0004000000170000002B00001A430000448000005AAB00005DC400005DC40000 + 5AAB0000448000001A430000002D0000001800000004FFFFFF00FFFFFF000000 + 000000001F000000534D020274BF08089DE30E0EC4F51111D4FD1111D4FD0E0E + C4F508089DE3020274BF0000534D00001F0000000000FFFFFF00FFFFFF000000 + 830000007F4D040488CD1212C4F61212B6FF1111D1FF1111D1FF1111D1FF1111 + D1FF1111B6FF0F0FC2F6030388CD00007F4D00008300FFFFFF00FFFFFF000000 + 851A03038ABF1818C1F61212B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 + B2FFEEEEEEFF1111B2FF0F0FBCF6020289BF0000851AFFFFFF00FFFFFF000000 + 896C1616AAE21616C1FFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA + EAFFEEEEEEFFEEEEEEFF1111BEFF0909A1E30000896CFFFFFF00FFFFFF000000 + 8DA72E2EC0F51212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 + E6FFEAEAEAFF1111B4FF1111B4FF1212AFF500008DA7FFFFFF00FFFFFF000000 + 92C44444CDFD2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 + E2FF1111AAFF1111AAFF1111AAFF1818AFFD000092C4FFFFFF00FFFFFF000000 + 96C44949D1FD3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC + DCFF11119EFF1111A1FF1111A1FF1D1DACFD000096C4FFFFFF00FFFFFF000000 + 9AA74747D3F53737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB + DBFFDDDDDDFF11119BFF1616A0FF2727B4F500009AA7FFFFFF00FFFFFF000000 + 9E6C3232C6E34949D1FFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF + FFFFFFFFFFFFFFFFFFFF4747CFFF2A2ABDE300009E6CFFFFFF00FFFFFF000000 + A11A0808A8BF5656E2F65151D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F + D7FFFFFFFFFF5050D8FF4F4FDCF60707A7BF0000A11AFFFFFF00FFFFFF000000 + A2000000A54D1010B1CD5B5BE8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B + E3FF5F5FE7FF5858E4F60F0FB0CD0000A54D0000A200FFFFFF00FFFFFF000000 + A2000000A5000000A84D0909AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5B + E9F53636CFE30909AEBF0000A84D0000A5000000A200FFFFFF00FFFFFF000000 + A2000000A5000000A8000000A91A0000AA6C0000AAA60000AAC40000AAC40000 + AAA60000AA6C0000A91A0000A8000000A5000000A200FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btDownloadClick - TabOrder = 1 + OnClick = btAbortUpdateListClick + ShowCaption = False + ShowHint = True + ParentShowHint = False end - object cbAddAsStopped: TCheckBox - AnchorSideLeft.Control = edSaveTo - AnchorSideTop.Control = btAddToFavorites - AnchorSideRight.Control = edSaveTo - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = btAddToFavorites - AnchorSideBottom.Side = asrBottom + object cbSelectManga: TComboBox + AnchorSideRight.Control = btUpdateList Left = 0 - Height = 19 - Top = 189 - Width = 416 + Height = 23 + Hint = 'For more manga sites, please go to Options->Manga sites' + Top = 0 + Width = 171 Anchors = [akTop, akLeft, akRight] - Caption = 'Add to download list as stopped task' - OnChange = cbAddAsStoppedChange - ParentFont = False - TabOrder = 3 - end - object btReadOnline: TBitBtn - AnchorSideLeft.Control = btAddToFavorites - AnchorSideTop.Control = btDownload - AnchorSideRight.Control = btChecks - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = btAddToFavorites - Left = 420 - Height = 26 - Top = 159 - Width = 130 - Anchors = [akLeft, akRight, akBottom] - AutoSize = True - Caption = 'Read online' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0A0A0A660C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C - 0C770C0C0C770C0C0C776C3A07C94E2A06970000002C00000012000000090000 - 00161F1F1F74EBEBEBFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 - E6FFE6E6E6FFE6E6E6FFB47839FF99560FE3723F0A6E00000009000000002A2A - 2A0036363671E8E8E8FFB4B4B4FFBDBDBDFFC5C5C5FFBDBDBDFFBF9261FFBD81 - 40FFBD8140FFBD8140FFBF8342FFFFC538FFB56A18CCB76C195C343434004545 - 45004545456FEAEAEAFFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFC68A46FFFFE3 - 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC4B4B4B004B4B - 4B004B4B4B6EECECECFF8E8E8EFFA5A5A5FFA5A5A5FF8E8E8EFFD2A56FFFD599 - 53FFCF934CFFCD914AFFD79B55FFFFE597FFD2872ECCD0852D5C515151005151 - 51005151516DEEEEEEFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 - E8FFD5D5D5FFD5D5D5FFE3A75CFFD18E3AE2DE93375CD2872E00575757005757 - 57005757576CF0F0F0FFBFBFBFFFC7C7C7FFD0D0D0FFC7C7C7FFD8D8D8FFEAEA - EAFFBFBFBFFFC7C7C7FFEABD85FF9E794BA29C764800957043005D5D5D005D5D - 5D005D5D5D6BF2F2F2FFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFEDED - EDFFDBDBDBFFDBDBDBFFF2F2F2FF5D5D5D6B5D5D5D005D5D5D00626262006262 - 62006262626BF5F5F5FF919191FFC4C4C4FFAAAAAAFFAAAAAAFF919191FFF1F1 - F1FFBBBBBBFFCCCCCCFFF5F5F5FF6262626B6262620062626200676767006767 - 67006767676AF7F7F7FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 - F4FFF4F4F4FFF4F4F4FFF7F7F7FF6767676A67676700676767006C6C6C006C6C - 6C006C6C6C69F9F9F9FF03599DFF0961A5FF1A77BBFF2587CBFF1976BAFF2587 - CBFF1570B4FF055CA0FFF9F9F9FF6C6C6C696C6C6C006C6C6C00717171007171 - 710071717168FBFBFBFF03599DFFC2D8E9FF89B9DBFF90C3E5FFB6CFE0FF2587 - CBFF1570B4FF055CA0FFFBFBFBFF717171687171710071717100757575007575 - 750075757568FDFDFDFF03599DFF126CB0FF2484C8FF3096DAFF3196DAFF2587 - CBFF1570B4FF055CA0FFFDFDFDFF757575687575750075757500797979007979 - 790079797967FEFEFEFF02579BFF0961A5FF126DB1FF1876BAFF1976BAFF136E - B2FF0B63A7FF03599DFFFEFEFEFF7979796779797900797979007D7D7D007D7D - 7D007D7D7D67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFF7D7D7D677D7D7D007D7D7D007F7F7F007F7F - 7F008080804D8080806680808066808080668080806680808066808080668080 - 80668080806680808066808080668080804D7F7F7F007F7F7F00 - } - OnClick = btReadOnlineClick - TabOrder = 2 + ItemHeight = 15 + ItemIndex = 0 + Items.Strings = ( + '' + ) + OnChange = cbSelectMangaChange + ParentShowHint = False + ShowHint = True + Sorted = True + Style = csDropDownList + TabOrder = 1 end - object btChecks: TSpeedButton - AnchorSideLeft.Control = clbChapterList + object btUpdateList: TSpeedButton AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = clbChapterList - Left = 524 - Height = 26 + AnchorSideTop.Control = cbSelectManga + AnchorSideRight.Control = vtMangaList + AnchorSideRight.Side = asrBottom + Left = 175 + Height = 23 + Hint = 'Update manga list' Top = 0 - Width = 26 + Width = 25 Anchors = [akTop, akRight] Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000090000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000900000012010E - 0033024A0083025D00BC025D00CC025D00CC025D00CC025D00CC025D00CC025D - 00CC025D00CC025D00CC025D00BC024A0083010E003300000012021D0000066D - 0073129208DD20CC10F922D911FF22D911FF22D911FF22D911FF22D911FF22D9 - 11FF22D911FF22D911FF1FCC0FF9109207DD066D0073021D00000A7D00000A7D - 00BA25CA15F922D111FF22D111FF22D111FF22B611FF22D111FF22D111FF22D1 - 11FF22D111FF22D111FF22D111FF20C80FF90A7D00BA0A7D00000C8400000C84 - 00CC2BCC1AFF22C811FF22C811FF22B211FFE6E6E6FF22B211FF22C811FF22C8 - 11FF22C811FF22C811FF22C811FF22C811FF0C8400CC0C8400000D8900000D89 - 00CC31C620FF22BE11FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE - 11FF22BE11FF22BE11FF22BE11FF23BE12FF0D8900CC0D8900000E8D00000E8D - 00CC41C330FF23AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 - 11FF22B411FF22B411FF22B411FF25B514FF0E8D00CC0E8D00000F9200000F92 - 00CC52C941FFA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 - E6FF22A311FF22AA11FF22AA11FF28AF17FF0F9200CC0F920000109600001096 - 00CC55CC44FF3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 - E2FFE6E6E6FF229E11FF22A111FF2CAA1BFF109600CC10960000119A0000119A - 00CC5AD149FF47BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 - E2FFE3E3E3FFE7E7E7FF269E15FF39B128FF119A00CC119A0000129E0000129E - 00CC60D74FFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB - 33FFFFFFFFFFA7E29EFF4EC53DFF58CF47FF129E00CC129E000013A2000013A2 - 00CC67DE56FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE - 46FF4AC139FF51C840FF57CE46FF60D74FFF13A200CC13A2000014A5000014A5 - 00BA64DE53F95FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD6 - 4EFF5FD64EFF5FD64EFF5FD64EFF60DA4FF914A500BA14A5000014A8000014A8 - 007337C124DD66E054F96EE55DFF6EE55DFF6EE55DFF6EE55DFF6DE45CFF6DE4 - 5CFF6DE45CFF6DE45CFF64DF53F936BF23DD14A8007314A8000014A8000015A9 - 000C15AA007315AA00BA15AA00CC15AA00CC15AA00CC15AA00CC15AA00CC15AA - 00CC15AA00CC15AA00CC15AA00BA15AA007315A9000C14A80000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + 20000000000000040000640000006400000000000000000000000000001F0000 + 0084000000E4733100C5733100C5733100C5733100C5733100C5733100C57331 + 00C5582500A00000002200000000000000000000000000000000000000100101 + 01D1606060FFCA9764FFC69360FFC69360FFC69360FFC69360FFC69360FFCA97 + 64FF803A00BE0000002B0000001A000000110000000000000000010101000101 + 01C8646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFFBE8B58FFCA97 + 64FF9C5E28F7733100C5582500A0000000220000000000000000010101000101 + 01C3696969FFCF9C69FFBF8C59FFC69360FFC69360FFC69360FFBF8C59FFCF9C + 69FFAD713AFFCA9764FF803A00BE0000001A0000001A00000011010101000101 + 01BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFBF8C59FFD4A1 + 6EFFB0733BFFCA9764FF9C5E28F7733100C5582500A000000022010101000101 + 01BA737373FFD9A673FFBF8C59FFD09D6AFFD09D6AFFD09D6AFFBF8C59FFD9A6 + 73FFB4783EFFCF9C69FFAD713AFFCA9764FF853D00B623100000010101000101 + 01B5787878FFDEAB78FFBE8B58FFE1AE7BFFE1AE7BFFE1AE7BFFBE8B58FFDEAB + 78FFB87B40FFD4A16EFFB0733BFFCA9764FF8E4200B08E420000010101000101 + 01B27C7C7CFFE2AF7CFFBC8956FFBC8956FFBC8956FFBC8956FFBC8956FFE2AF + 7CFFBB7E42FFD9A673FFB4783EFFCF9C69FF934600AC93460000010101000101 + 01AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 + 84FFBD8043FFDEAB78FFB87B40FFD4A16EFF984900A898490000010101000101 + 01AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFBF8144FFE2AF7CFFBB7E42FFD9A673FF9C4C00A49C4C0000040404000404 + 048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFB + FAFFB4A484FFEAB784FFBD8043FFDEAB78FFA04F00A1A04F0000040404000404 + 04460404048AA16A33EEAA7744FFC28548FFC28548FFC28548FFC28548FFC285 + 48FFC28548FFCC9966FFBF8144FFE2AF7CFFA451009EA4510000040404000404 + 0400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEA + E5FFF3F3F1FFFBFBFAFFB4A484FFEAB784FFA753009CA7530000040404000404 + 040004040400040404460404048AA16A33EEAA7744FFC28548FFC28548FFC285 + 48FFC28548FFC28548FFC28548FFCC9966FFAA55009AAA550000040404000404 + 04000404040004040400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6 + CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFBFAFF55552B6655552B00000000000202 + 0200040404000404040004040400040404460404048AAA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550099AA550073AA550000 } - OnClick = btChecksClick + OnClick = btUpdateListClick + ShowCaption = False end - object btAddToFavorites: TBitBtn - AnchorSideLeft.Control = btDownload - AnchorSideTop.Control = btReadOnline + object edMangaListSearch: TEdit + AnchorSideLeft.Control = cbSelectManga + AnchorSideTop.Control = cbSelectManga AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = btChecks + AnchorSideRight.Control = cbSelectManga AnchorSideRight.Side = asrBottom - Left = 420 - Height = 26 - Top = 189 - Width = 130 - Anchors = [akRight, akBottom] - AutoSize = True - Caption = 'Add to favorites' - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000050000 - 001E0000003200009CC9000054630000002E0000002B00000026000000220000 - 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 - 000F000000190000A8C50000A8C500006D580000001600000013000000110000 - 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 - 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D - 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 - BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 - 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 - C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C - 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 - C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 - 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 - C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 - CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 - C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 - FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 - C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 - F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 - C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A - F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 - C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C - F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 - C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E - FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 - 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 - DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 - 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 - E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 - 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 - E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 - 0000000000000000990000002B00000000000000000001016E000101DE000101 - E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 - } - OnClick = btAddToFavoritesClick - TabOrder = 4 - end - object lbSaveTo: TLabel - AnchorSideLeft.Control = clbChapterList - AnchorSideTop.Control = btDownload - AnchorSideBottom.Control = edSaveTo Left = 0 - Height = 15 - Top = 140 - Width = 41 - Anchors = [akLeft, akBottom] - Caption = 'Save to:' - ParentColor = False - ParentFont = False + Height = 23 + Top = 27 + Width = 171 + Anchors = [akTop, akLeft, akRight] + OnChange = edMangaListSearchChange + OnKeyDown = edMangaListSearchKeyDown + TabOrder = 2 + TextHint = 'Search title...' end - object edFilterMangaInfoChapters: TEditButton - Left = 0 + object btMangaListSearchClear: TSpeedButton + AnchorSideLeft.Control = edMangaListSearch + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edMangaListSearch + AnchorSideTop.Side = asrCenter + Left = 175 Height = 23 - Top = 0 - Width = 250 - ButtonWidth = 23 + Top = 27 + Width = 25 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF @@ -795,1131 +596,1697 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - MaxLength = 0 - NumGlyphs = 1 - OnButtonClick = edFilterMangaInfoChaptersButtonClick - OnChange = edFilterMangaInfoChaptersChange - PasswordChar = #0 - TabOrder = 5 - TextHint = 'Filter' - Visible = False + OnClick = btMangaListSearchClearClick + ShowCaption = False end - object edSaveTo: TEditButton - AnchorSideLeft.Control = lbSaveTo - AnchorSideTop.Control = btReadOnline - AnchorSideRight.Control = btReadOnline - AnchorSideBottom.Control = cbAddAsStopped + object lbMode: TLabel + AnchorSideLeft.Control = edMangaListSearch + AnchorSideTop.Control = edMangaListSearch + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = edMangaListSearch + AnchorSideRight.Side = asrBottom Left = 0 - Height = 23 - Top = 159 - Width = 416 + Height = 15 + Top = 58 + Width = 171 Anchors = [akTop, akLeft, akRight] - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 - 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 - 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 - 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 - 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 - 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 - 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC - DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 - 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 - D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 - AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA - D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 - B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC - DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 - B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD - DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B - B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE - DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D - BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 - DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F - BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 - E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 - C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 - E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 - C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA - FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 - C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC - FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 - CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 - FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 - CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 - CC810088CC810088CC810088CC810088CC610087CB000087CB00 - } - MaxLength = 0 - NumGlyphs = 1 - OnButtonClick = edSaveToButtonClick + BorderSpacing.Top = 8 + Caption = 'Mode: Show all (0)' + Font.Style = [fsBold] + ParentColor = False ParentFont = False - PasswordChar = #0 - TabOrder = 6 - TextHint = 'Save to' end - object btDownloadSplit: TSpeedButton - AnchorSideLeft.Control = btDownload + object btRemoveFilter: TSpeedButton + AnchorSideLeft.Control = lbMode AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = btDownload - AnchorSideRight.Control = btChecks - AnchorSideRight.Side = asrBottom - AnchorSideBottom.Control = btReadOnline - Left = 524 - Height = 26 - Hint = 'Split download' - Top = 129 - Width = 26 - Anchors = [akTop, akRight, akBottom] + AnchorSideTop.Control = lbMode + AnchorSideTop.Side = asrCenter + Left = 175 + Height = 23 + Top = 54 + Width = 25 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 000800000010000000170000001A00000016000000120000000E0000000E0000 - 0012000000160000001A000000180000001000000008FFFFFF00FFFFFF000000 - 00100000001F64330270984D02CC64330270000000230000001B0000001C0000 - 002364330270984D02CC643302710000002000000010FFFFFF00FFFFFF002815 - 0200753D045C9C5105CCFFB811FF9C5105CC753D045C2815020028150200753D - 045C9C5105CCFFB508FF9C5105CC753D045C28150200FFFFFF00FFFFFF00A257 - 0A5CA15609CCFFB917FFFFB201FFFFB814FFA15609CCA1560948A1560948A156 - 09CCFFB60DFFFFB201FFFFB50BFFA15609CCA2570A5CFFFFFF00FFFFFF00BF74 - 1599BF7415CCBF7415CCFBC23EFFBF7415CCBF7415CCBF741566BF741566BF74 - 15CCBF7415CCFABA27FFBF7415CCBF7415CCBF741599FFFFFF00FFFFFF00BF74 - 1500BB701500AD6212C9F2BC49FDB36A18D0B2671320BF741500BF741500B267 - 1320B36916D0F0B435FDAD6212C9BB701500BF741500FFFFFF00FFFFFF00BA6F - 1700B4691700B46917B4E3AA46F4C6842DDBB56A185EB56A1800B56A1800B56A - 185EC58128DBE1A53BF6B46917B9B4691700BA6F1700FFFFFF00FFFFFF00BA6F - 1C00BA6F1C00BA6F1C86D59A45E6DAA24CEFBA6F1CB8BE731F0ABE731F0ABA6F - 1CB8D89D45EFD3963FE8BA6F1C8CBA6F1C00BA6F1C00FFFFFF00FFFFFF00C075 - 2000C0752000C176213CC7802CD2EDC577FECD8C39D9C1772271C1772270CC89 - 37D9E7BB6DFFC8822ED4C0762148BF752000BF752000FFFFFF00FFFFFF00C77C - 2500C77C2500C77C2502C97E27A1DCA452E6E9BE70F6C97E27C6C97E27C6E6B8 - 6AF6DAA050E9C97E27ACC77C2505C77C2500C77C2500FFFFFF00FFFFFF00CC81 - 2900CC812900CC812900CF842C2CD18831CDF2C679FBDC9D49DBDB9B47DCE6B8 - 6BFCD28932CFCE832C36CD822B00CD822B00CD822B00FFFFFF00FFFFFF00D489 - 3000D4893000D4893000D4893000D68B3190E9B461E6EEB86AF4EEB869F4EAB3 - 61E7D68B3197D3882F00D2872F00D2872F00D2872F00FFFFFF00FFFFFF00DA8F - 3400DA8F3400DA8F3400DA8F3400DB903547E4A44DD8F6C679FEF5C679FEE4A4 - 4DD8DB903549DA8F3400DA8F3400DA8F3400DA8F3400FFFFFF00FFFFFF00E196 - 3900E1963900E1963900E1963900E1963917E39B3FCFFCD488FFFCD387FFE39C - 40CFE1963918E1963900E1963900E1963900E1963900FFFFFF00FFFFFF00E69B - 3D00E69B3D00E69B3D00E69B3D00E69B3D04E69B3DCCFFE094FFFFDF93FFE69B - 3DCCE69B3D04E69B3D00E69B3D00E69B3D00E69B3D00FFFFFF00FFFFFF003A27 - 1000AE752E00E79C3D00E79C3D00E79C3D00E99E4099E99E40CCE99E40CCE99E - 4099E79C3D00E79C3D00E79C3D00AE752E003A271000FFFFFF00 + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000080000000000005A000000770000008000000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A000000110000000400005A00000077000000770000008000000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578040426000000 + 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 + 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 + A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 + A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C + 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 250027275200101090000000AA000000AA000000AA000000A700363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535004343430035355F00121291000000AA000000A700363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A43434300464646004646460035355F0023237700363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } - OnClick = btDownloadSplitClick + OnClick = btRemoveFilterClick + ShowCaption = False end end - end - end - object tsFilter: TTabSheet - Caption = 'Filter' - ClientHeight = 492 - ClientWidth = 558 - object sbFilter: TScrollBox - Left = 0 - Height = 492 - Top = 0 - Width = 558 - HorzScrollBar.Page = 488 - VertScrollBar.Page = 416 - Align = alClient - BorderStyle = bsNone - ClientHeight = 492 - ClientWidth = 558 - TabOrder = 0 - object pnCustomGenre: TPanel - Left = 8 - Height = 23 - Top = 196 - Width = 542 - Align = alTop - AutoSize = True - BorderSpacing.Around = 8 - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ChildSizing.ControlsPerLine = 3 - ClientHeight = 23 - ClientWidth = 542 - TabOrder = 2 - object lbFilterCustomGenres: TLabel + object pssInfo: TPairSplitterSide + Cursor = crArrow + Left = 205 + Height = 490 + Top = 0 + Width = 556 + ClientWidth = 556 + ClientHeight = 490 + object pcInfo: TPageControl Left = 0 - Height = 23 - Top = 0 - Width = 93 - Align = alLeft - Caption = 'Custom Genres' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edCustomGenres: TEdit - Left = 97 - Height = 23 + Height = 490 Top = 0 - Width = 428 + Width = 556 + ActivePage = tsInfoManga Align = alClient - BorderSpacing.Left = 4 - ParentFont = False - TabOrder = 0 - TextHint = 'Input custom genres, separated by comma' - end - object lbFilterHint: TLabel - AnchorSideLeft.Control = edCustomGenres - AnchorSideLeft.Side = asrBottom - Left = 529 - Height = 23 - Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' - Top = 0 - Width = 13 - Align = alRight - BorderSpacing.Left = 4 - Caption = '[?]' - Font.Color = clBlue - ParentColor = False - ParentFont = False - ParentShowHint = False - ShowHint = True - end - end - object pnFilter: TPanel - Left = 8 - Height = 136 - Top = 237 - Width = 542 - Align = alTop - BorderSpacing.Top = 10 - BorderSpacing.Around = 8 - BevelOuter = bvNone - ClientHeight = 136 - ClientWidth = 542 - ParentFont = False - TabOrder = 1 - object Panel1: TPanel - Left = 0 - Height = 136 - Top = 0 - Width = 299 - Align = alLeft - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ChildSizing.EnlargeHorizontal = crsScaleChilds - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 2 - ClientHeight = 136 - ClientWidth = 299 + TabIndex = 0 TabOrder = 0 - object lbFilterTitle: TLabel - Left = 0 - Height = 23 - Top = 0 - Width = 110 - Caption = 'Title' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edFilterTitle: TEdit - Left = 114 - Height = 23 - Top = 0 - Width = 185 - TabOrder = 0 - TextHint = 'Title' - end - object lbFilterAuthors: TLabel - Left = 0 - Height = 23 - Top = 27 - Width = 110 - Caption = 'Author' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edFilterAuthors: TEdit - Left = 114 - Height = 23 - Top = 27 - Width = 185 - TabOrder = 2 - TextHint = 'Author' - end - object lbFilterArtists: TLabel - Left = 0 - Height = 23 - Top = 54 - Width = 110 - Caption = 'Artist' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edFilterArtists: TEdit - Left = 114 - Height = 23 - Top = 54 - Width = 185 - TabOrder = 1 - TextHint = 'Artist' - end - object lbFilterStatus: TLabel - Left = 0 - Height = 23 - Top = 81 - Width = 110 - Caption = 'Status' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object cbFilterStatus: TComboBox - Left = 114 - Height = 23 - Top = 81 - Width = 185 - ItemHeight = 15 - ItemIndex = 2 - Items.Strings = ( - 'Completed' - 'Ongoing' - '<none>' - ) - Style = csDropDownList - TabOrder = 3 - Text = '<none>' - end - object lbFilterSummary: TLabel - Left = 0 - Height = 23 - Top = 108 - Width = 110 - Caption = 'Summary' - Font.Height = -13 - Font.Style = [fsBold] - ParentBidiMode = False - ParentColor = False - ParentFont = False - end - object edFilterSummary: TEdit - Left = 114 - Height = 23 - Top = 108 - Width = 185 - TabOrder = 4 - TextHint = 'Part of summary' - end - end - object Panel2: TPanel - Left = 303 - Height = 136 - Top = 0 - Width = 239 - Align = alClient - AutoSize = True - BorderSpacing.Left = 4 - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ClientHeight = 136 - ClientWidth = 239 - TabOrder = 1 - object rbOne: TRadioButton - Left = 0 - Height = 19 - Top = 0 - Width = 169 - Caption = 'Have one of genres checked' - ParentFont = False - TabOrder = 0 + object tsInfoManga: TTabSheet + Caption = 'Info' + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 462 + ClientWidth = 548 + object sbInformation: TScrollBox + Left = 0 + Height = 454 + Top = 4 + Width = 548 + HorzScrollBar.Page = 308 + VertScrollBar.Page = 401 + Align = alClient + Anchors = [akRight, akBottom] + BorderStyle = bsNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 454 + ClientWidth = 548 + TabOrder = 0 + object pnInfomation: TPanel + Left = 0 + Height = 248 + Top = 0 + Width = 548 + Align = alTop + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 248 + ClientWidth = 548 + ParentFont = False + TabOrder = 0 + object edURL: TEditButton + Left = 0 + Height = 23 + Top = 0 + Width = 548 + Align = alTop + ButtonWidth = 30 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0001000000070000000E000000150000001A0000001A0000001A0000001A0000 + 001A0000001A000000160000000F0000000800000002FFFFFF00FFFFFF000000 + 00020000000E0000001C0000002A000000330000003300000033733A02A66332 + 0274000000330000002B0000001D0000000F00000003FFFFFF00FFFFFF000000 + 00000000000000000000000000000000000000000000281502009D5206CC9D52 + 06CC763E055C29160300000000000000000000000000FFFFFF00FFFFFF005933 + 0B0058320A0058320A0058320A0058320A0058320A00A3580B00A3580BCCFFBA + 18FFA3580BCCA4590C5C7F470C002C19050000000000FFFFFF00FFFFFF00B166 + 1600AF641400AF641400AF641400AF641400AF641400AE631300AA5F10CCFFB9 + 12FFFFBC1EFFAA5F10CCAB60115CB1661600B96E1C00FFFFFF00FFFFFF00B267 + 1799B16616CCB16616CCB16616CCB16616CCB16616CCB16616CCB16616CCF7B5 + 25FFF5AB0EFFF7BA32FFB16616CCB267175CB96E1C00FFFFFF00FFFFFF00B96E + 1CCCF7CD81FFF4C276FFF3C071FFEEB85BFFE8B049FFE7AE45FFE6AD43FFE3A5 + 35FFE19E29FFE19E29FFEBB54DFFB96E1CCCBA6F1D5CFFFFFF00FFFFFF00C277 + 22CCF5C77BFFEEB266FFEEB266FFEEB266FFEAAE60FFE1A453FFD89B49FFD396 + 44FFD09341FFD09341FFD39644FFE8B868FFC27722CCFFFFFF00FFFFFF00CA7F + 28CCFAD589FFF6C97DFFF6C87CFFF5C77BFFF5C77BFFF5C67AFFF5C579FFF2BC + 70FFEFB468FFEFB468FFF8CF83FFCA7F28CCC97E275CFFFFFF00FFFFFF00D186 + 2D99D2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCD2872ECCF8CD + 81FFF4BE72FFFCD98DFFD2872ECCD1862D5CCA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00D3882F00D3882F00D58A3100D98E33CCFCD5 + 89FFFEE094FFD98E33CCD88D335CD2872E00CA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00D3882F00D78C3200E0953800E09538CCFFE4 + 98FFE09538CCDF94385CD98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00D88D3300E59A3C00E59A3C00E59A3CCCE59A + 3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00D287 + 2E00D3882F00D3882F00D3882F00E89D3F00E89D3F00E89D3F00E99E4099E99E + 405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edURLButtonClick + OnKeyPress = edURLKeyPress + PasswordChar = #0 + PopupMenu = pmEditURL + TabOrder = 2 + TextHint = 'Input URL here' + end + object rmInformation: TRichMemo + AnchorSideLeft.Control = pnThumbContainer + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edURL + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = edURL + AnchorSideRight.Side = asrBottom + Left = 158 + Height = 219 + Top = 27 + Width = 390 + Anchors = [akTop, akLeft, akRight, akBottom] + HideSelection = False + ReadOnly = True + ScrollBars = ssAutoVertical + TabOrder = 0 + ZoomFactor = 1 + end + object btDonate: TImage + Cursor = crHandPoint + Left = -56 + Height = 21 + Top = 14 + Width = 75 + Anchors = [akTop, akRight] + OnClick = btDonateClick + Stretch = True + Visible = False + end + object pnThumbContainer: TPanel + AnchorSideLeft.Control = edURL + AnchorSideTop.Control = edURL + AnchorSideTop.Side = asrBottom + Left = 0 + Height = 216 + Top = 27 + Width = 154 + BevelOuter = bvNone + BorderStyle = bsSingle + ClientHeight = 212 + ClientWidth = 150 + Color = clWhite + ParentColor = False + TabOrder = 1 + object imCover: TImage + Left = 0 + Height = 212 + Top = 0 + Width = 150 + AntialiasingMode = amOn + Align = alClient + Center = True + Proportional = True + Stretch = True + end + object pbWait: TPaintBox + Left = 0 + Height = 212 + Top = 0 + Width = 150 + Align = alClient + end + end + end + object spInfos: TSplitter + Cursor = crVSplit + Left = 0 + Height = 5 + Top = 252 + Width = 548 + Align = alTop + ResizeAnchor = akTop + end + object pnChapterList: TPanel + Left = 0 + Height = 193 + Top = 261 + Width = 548 + Align = alClient + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 193 + ClientWidth = 548 + TabOrder = 2 + object clbChapterList: TVirtualStringTree + AnchorSideLeft.Control = edFilterMangaInfoChapters + AnchorSideTop.Control = edFilterMangaInfoChapters + AnchorSideRight.Control = btChecks + AnchorSideBottom.Control = btDownload + Left = 0 + Height = 103 + Top = 0 + Width = 518 + Anchors = [akTop, akLeft, akRight, akBottom] + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.Height = 23 + Header.MainColumn = -1 + Margin = 2 + ParentFont = False + PopupMenu = pmChapterList + TabOrder = 0 + TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnBeforeCellPaint = clbChapterListBeforeCellPaint + OnGetText = clbChapterListGetText + OnInitNode = clbChapterListInitNode + end + object btDownload: TBitBtn + AnchorSideLeft.Control = btAddToFavorites + AnchorSideTop.Control = btDownloadSplit + AnchorSideRight.Control = btDownloadSplit + AnchorSideBottom.Control = btReadOnline + Left = 418 + Height = 26 + Top = 107 + Width = 100 + Anchors = [akLeft, akRight, akBottom] + AutoSize = True + Caption = 'Download' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } + OnClick = btDownloadClick + TabOrder = 1 + end + object cbAddAsStopped: TCheckBox + AnchorSideLeft.Control = edSaveTo + AnchorSideTop.Control = btAddToFavorites + AnchorSideRight.Control = edSaveTo + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btAddToFavorites + AnchorSideBottom.Side = asrBottom + Left = 0 + Height = 19 + Top = 167 + Width = 414 + Anchors = [akTop, akLeft, akRight] + Caption = 'Add to download list as stopped task' + OnChange = cbAddAsStoppedChange + ParentFont = False + TabOrder = 3 + end + object btReadOnline: TBitBtn + AnchorSideLeft.Control = btAddToFavorites + AnchorSideTop.Control = btDownload + AnchorSideRight.Control = btChecks + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btAddToFavorites + Left = 418 + Height = 26 + Top = 137 + Width = 130 + Anchors = [akLeft, akRight, akBottom] + AutoSize = True + Caption = 'Read online' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0A0A0A660C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C0C770C0C + 0C770C0C0C770C0C0C776C3A07C94E2A06970000002C00000012000000090000 + 00161F1F1F74EBEBEBFFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6 + E6FFE6E6E6FFE6E6E6FFB47839FF99560FE3723F0A6E00000009000000002A2A + 2A0036363671E8E8E8FFB4B4B4FFBDBDBDFFC5C5C5FFBDBDBDFFBF9261FFBD81 + 40FFBD8140FFBD8140FFBF8342FFFFC538FFB56A18CCB76C195C343434004545 + 45004545456FEAEAEAFFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFC68A46FFFFE3 + 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC4B4B4B004B4B + 4B004B4B4B6EECECECFF8E8E8EFFA5A5A5FFA5A5A5FF8E8E8EFFD2A56FFFD599 + 53FFCF934CFFCD914AFFD79B55FFFFE597FFD2872ECCD0852D5C515151005151 + 51005151516DEEEEEEFFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8E8FFE8E8 + E8FFD5D5D5FFD5D5D5FFE3A75CFFD18E3AE2DE93375CD2872E00575757005757 + 57005757576CF0F0F0FFBFBFBFFFC7C7C7FFD0D0D0FFC7C7C7FFD8D8D8FFEAEA + EAFFBFBFBFFFC7C7C7FFEABD85FF9E794BA29C764800957043005D5D5D005D5D + 5D005D5D5D6BF2F2F2FFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFDBDBDBFFEDED + EDFFDBDBDBFFDBDBDBFFF2F2F2FF5D5D5D6B5D5D5D005D5D5D00626262006262 + 62006262626BF5F5F5FF919191FFC4C4C4FFAAAAAAFFAAAAAAFF919191FFF1F1 + F1FFBBBBBBFFCCCCCCFFF5F5F5FF6262626B6262620062626200676767006767 + 67006767676AF7F7F7FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 + F4FFF4F4F4FFF4F4F4FFF7F7F7FF6767676A67676700676767006C6C6C006C6C + 6C006C6C6C69F9F9F9FF03599DFF0961A5FF1A77BBFF2587CBFF1976BAFF2587 + CBFF1570B4FF055CA0FFF9F9F9FF6C6C6C696C6C6C006C6C6C00717171007171 + 710071717168FBFBFBFF03599DFFC2D8E9FF89B9DBFF90C3E5FFB6CFE0FF2587 + CBFF1570B4FF055CA0FFFBFBFBFF717171687171710071717100757575007575 + 750075757568FDFDFDFF03599DFF126CB0FF2484C8FF3096DAFF3196DAFF2587 + CBFF1570B4FF055CA0FFFDFDFDFF757575687575750075757500797979007979 + 790079797967FEFEFEFF02579BFF0961A5FF126DB1FF1876BAFF1976BAFF136E + B2FF0B63A7FF03599DFFFEFEFEFF7979796779797900797979007D7D7D007D7D + 7D007D7D7D67FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + FFFFFFFFFFFFFFFFFFFFFFFFFFFF7D7D7D677D7D7D007D7D7D007F7F7F007F7F + 7F008080804D8080806680808066808080668080806680808066808080668080 + 80668080806680808066808080668080804D7F7F7F007F7F7F00 + } + OnClick = btReadOnlineClick + TabOrder = 2 + end + object btChecks: TSpeedButton + AnchorSideLeft.Control = clbChapterList + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = clbChapterList + Left = 522 + Height = 26 + Top = 0 + Width = 26 + Anchors = [akTop, akRight] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000090000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000900000012010E + 0033024A0083025D00BC025D00CC025D00CC025D00CC025D00CC025D00CC025D + 00CC025D00CC025D00CC025D00BC024A0083010E003300000012021D0000066D + 0073129208DD20CC10F922D911FF22D911FF22D911FF22D911FF22D911FF22D9 + 11FF22D911FF22D911FF1FCC0FF9109207DD066D0073021D00000A7D00000A7D + 00BA25CA15F922D111FF22D111FF22D111FF22B611FF22D111FF22D111FF22D1 + 11FF22D111FF22D111FF22D111FF20C80FF90A7D00BA0A7D00000C8400000C84 + 00CC2BCC1AFF22C811FF22C811FF22B211FFE6E6E6FF22B211FF22C811FF22C8 + 11FF22C811FF22C811FF22C811FF22C811FF0C8400CC0C8400000D8900000D89 + 00CC31C620FF22BE11FF22AD11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE + 11FF22BE11FF22BE11FF22BE11FF23BE12FF0D8900CC0D8900000E8D00000E8D + 00CC41C330FF23AE12FFD5D5D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A8 + 11FF22B411FF22B411FF22B411FF25B514FF0E8D00CC0E8D00000F9200000F92 + 00CC52C941FFA9D7A2FFD5D5D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6 + E6FF22A311FF22AA11FF22AA11FF28AF17FF0F9200CC0F920000109600001096 + 00CC55CC44FF3CB32BFFF8F8F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2 + E2FFE6E6E6FF229E11FF22A111FF2CAA1BFF109600CC10960000119A0000119A + 00CC5AD149FF47BE36FF3EB52DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2 + E2FFE3E3E3FFE7E7E7FF269E15FF39B128FF119A00CC119A0000129E0000129E + 00CC60D74FFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB + 33FFFFFFFFFFA7E29EFF4EC53DFF58CF47FF129E00CC129E000013A2000013A2 + 00CC67DE56FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF57CE + 46FF4AC139FF51C840FF57CE46FF60D74FFF13A200CC13A2000014A5000014A5 + 00BA64DE53F95FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD64EFF5FD6 + 4EFF5FD64EFF5FD64EFF5FD64EFF60DA4FF914A500BA14A5000014A8000014A8 + 007337C124DD66E054F96EE55DFF6EE55DFF6EE55DFF6EE55DFF6DE45CFF6DE4 + 5CFF6DE45CFF6DE45CFF64DF53F936BF23DD14A8007314A8000014A8000015A9 + 000C15AA007315AA00BA15AA00CC15AA00CC15AA00CC15AA00CC15AA00CC15AA + 00CC15AA00CC15AA00CC15AA00BA15AA007315A9000C14A80000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btChecksClick + end + object btAddToFavorites: TBitBtn + AnchorSideLeft.Control = btDownload + AnchorSideTop.Control = btReadOnline + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btChecks + AnchorSideRight.Side = asrBottom + Left = 418 + Height = 26 + Top = 167 + Width = 130 + Anchors = [akRight, akBottom] + AutoSize = True + Caption = 'Add to favorites' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000050000 + 001E0000003200009CC9000054630000002E0000002B00000026000000220000 + 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 + 000F000000190000A8C50000A8C500006D580000001600000013000000110000 + 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 + 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D + 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 + BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 + 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 + C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C + 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 + C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 + 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 + C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 + CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 + C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 + FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 + C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 + F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A + F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C + F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E + FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 + 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 + DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 + 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 + E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 + 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 + E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 + 0000000000000000990000002B00000000000000000001016E000101DE000101 + E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 + } + OnClick = btAddToFavoritesClick + TabOrder = 4 + end + object lbSaveTo: TLabel + AnchorSideLeft.Control = clbChapterList + AnchorSideTop.Control = btDownload + AnchorSideBottom.Control = edSaveTo + Left = 0 + Height = 15 + Top = 118 + Width = 41 + Anchors = [akLeft, akBottom] + Caption = 'Save to:' + ParentColor = False + ParentFont = False + end + object edFilterMangaInfoChapters: TEditButton + Left = 0 + Height = 23 + Top = 0 + Width = 250 + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edFilterMangaInfoChaptersButtonClick + OnChange = edFilterMangaInfoChaptersChange + PasswordChar = #0 + TabOrder = 5 + TextHint = 'Filter' + Visible = False + end + object edSaveTo: TEditButton + AnchorSideLeft.Control = lbSaveTo + AnchorSideTop.Control = btReadOnline + AnchorSideRight.Control = btReadOnline + AnchorSideBottom.Control = cbAddAsStopped + Left = 0 + Height = 23 + Top = 137 + Width = 414 + Anchors = [akTop, akLeft, akRight] + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edSaveToButtonClick + ParentFont = False + PasswordChar = #0 + TabOrder = 6 + TextHint = 'Save to' + end + object btDownloadSplit: TSpeedButton + AnchorSideLeft.Control = btDownload + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btDownload + AnchorSideRight.Control = btChecks + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btReadOnline + Left = 522 + Height = 26 + Hint = 'Split download' + Top = 107 + Width = 26 + Anchors = [akTop, akRight, akBottom] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 000800000010000000170000001A00000016000000120000000E0000000E0000 + 0012000000160000001A000000180000001000000008FFFFFF00FFFFFF000000 + 00100000001F64330270984D02CC64330270000000230000001B0000001C0000 + 002364330270984D02CC643302710000002000000010FFFFFF00FFFFFF002815 + 0200753D045C9C5105CCFFB811FF9C5105CC753D045C2815020028150200753D + 045C9C5105CCFFB508FF9C5105CC753D045C28150200FFFFFF00FFFFFF00A257 + 0A5CA15609CCFFB917FFFFB201FFFFB814FFA15609CCA1560948A1560948A156 + 09CCFFB60DFFFFB201FFFFB50BFFA15609CCA2570A5CFFFFFF00FFFFFF00BF74 + 1599BF7415CCBF7415CCFBC23EFFBF7415CCBF7415CCBF741566BF741566BF74 + 15CCBF7415CCFABA27FFBF7415CCBF7415CCBF741599FFFFFF00FFFFFF00BF74 + 1500BB701500AD6212C9F2BC49FDB36A18D0B2671320BF741500BF741500B267 + 1320B36916D0F0B435FDAD6212C9BB701500BF741500FFFFFF00FFFFFF00BA6F + 1700B4691700B46917B4E3AA46F4C6842DDBB56A185EB56A1800B56A1800B56A + 185EC58128DBE1A53BF6B46917B9B4691700BA6F1700FFFFFF00FFFFFF00BA6F + 1C00BA6F1C00BA6F1C86D59A45E6DAA24CEFBA6F1CB8BE731F0ABE731F0ABA6F + 1CB8D89D45EFD3963FE8BA6F1C8CBA6F1C00BA6F1C00FFFFFF00FFFFFF00C075 + 2000C0752000C176213CC7802CD2EDC577FECD8C39D9C1772271C1772270CC89 + 37D9E7BB6DFFC8822ED4C0762148BF752000BF752000FFFFFF00FFFFFF00C77C + 2500C77C2500C77C2502C97E27A1DCA452E6E9BE70F6C97E27C6C97E27C6E6B8 + 6AF6DAA050E9C97E27ACC77C2505C77C2500C77C2500FFFFFF00FFFFFF00CC81 + 2900CC812900CC812900CF842C2CD18831CDF2C679FBDC9D49DBDB9B47DCE6B8 + 6BFCD28932CFCE832C36CD822B00CD822B00CD822B00FFFFFF00FFFFFF00D489 + 3000D4893000D4893000D4893000D68B3190E9B461E6EEB86AF4EEB869F4EAB3 + 61E7D68B3197D3882F00D2872F00D2872F00D2872F00FFFFFF00FFFFFF00DA8F + 3400DA8F3400DA8F3400DA8F3400DB903547E4A44DD8F6C679FEF5C679FEE4A4 + 4DD8DB903549DA8F3400DA8F3400DA8F3400DA8F3400FFFFFF00FFFFFF00E196 + 3900E1963900E1963900E1963900E1963917E39B3FCFFCD488FFFCD387FFE39C + 40CFE1963918E1963900E1963900E1963900E1963900FFFFFF00FFFFFF00E69B + 3D00E69B3D00E69B3D00E69B3D00E69B3D04E69B3DCCFFE094FFFFDF93FFE69B + 3DCCE69B3D04E69B3D00E69B3D00E69B3D00E69B3D00FFFFFF00FFFFFF003A27 + 1000AE752E00E79C3D00E79C3D00E79C3D00E99E4099E99E40CCE99E40CCE99E + 4099E79C3D00E79C3D00E79C3D00AE752E003A271000FFFFFF00 + } + OnClick = btDownloadSplitClick + end + end + end + end + object tsinfoFilterAdv: TTabSheet + Caption = 'Filter' + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 456 + ClientWidth = 544 + object sbFilter: TScrollBox + Left = 0 + Height = 448 + Top = 4 + Width = 544 + HorzScrollBar.Page = 488 + VertScrollBar.Page = 416 + Align = alClient + BorderStyle = bsNone + ClientHeight = 448 + ClientWidth = 544 + TabOrder = 0 + object pnCustomGenre: TPanel + Left = 8 + Height = 23 + Top = 196 + Width = 528 + Align = alTop + AutoSize = True + BorderSpacing.Around = 8 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.ControlsPerLine = 3 + ClientHeight = 23 + ClientWidth = 528 + TabOrder = 2 + object lbFilterCustomGenres: TLabel + Left = 0 + Height = 23 + Top = 0 + Width = 93 + Align = alLeft + Caption = 'Custom Genres' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edCustomGenres: TEdit + Left = 97 + Height = 23 + Top = 0 + Width = 414 + Align = alClient + BorderSpacing.Left = 4 + ParentFont = False + TabOrder = 0 + TextHint = 'Input custom genres, separated by comma' + end + object lbFilterHint: TLabel + AnchorSideLeft.Control = edCustomGenres + AnchorSideLeft.Side = asrBottom + Left = 515 + Height = 23 + Hint = 'Genres:'#13#10'- Checked: Include this genre.'#13#10'- Unchecked: Exclude this genre.'#13#10'- Grayed: Doesn''t matter.'#13#10#13#10'Custom Genres:'#13#10'- Separate multiple genres with '',''.'#13#10'- Exclude a genre by placing ''!'' or ''-'' at the beginning of a genre.'#13#10'- Example: Adventure,!Ecchi,Comedy.' + Top = 0 + Width = 13 + Align = alRight + BorderSpacing.Left = 4 + Caption = '[?]' + Font.Color = clBlue + ParentColor = False + ParentFont = False + ParentShowHint = False + ShowHint = True + end + end + object pnFilter: TPanel + Left = 8 + Height = 136 + Top = 237 + Width = 528 + Align = alTop + BorderSpacing.Top = 10 + BorderSpacing.Around = 8 + BevelOuter = bvNone + ClientHeight = 136 + ClientWidth = 528 + ParentFont = False + TabOrder = 1 + object Panel1: TPanel + Left = 0 + Height = 136 + Top = 0 + Width = 299 + Align = alLeft + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.EnlargeHorizontal = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 2 + ClientHeight = 136 + ClientWidth = 299 + TabOrder = 0 + object lbFilterTitle: TLabel + Left = 0 + Height = 23 + Top = 0 + Width = 110 + Caption = 'Title' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterTitle: TEdit + Left = 114 + Height = 23 + Top = 0 + Width = 185 + TabOrder = 0 + TextHint = 'Title' + end + object lbFilterAuthors: TLabel + Left = 0 + Height = 23 + Top = 27 + Width = 110 + Caption = 'Author' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterAuthors: TEdit + Left = 114 + Height = 23 + Top = 27 + Width = 185 + TabOrder = 2 + TextHint = 'Author' + end + object lbFilterArtists: TLabel + Left = 0 + Height = 23 + Top = 54 + Width = 110 + Caption = 'Artist' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterArtists: TEdit + Left = 114 + Height = 23 + Top = 54 + Width = 185 + TabOrder = 1 + TextHint = 'Artist' + end + object lbFilterStatus: TLabel + Left = 0 + Height = 23 + Top = 81 + Width = 110 + Caption = 'Status' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object cbFilterStatus: TComboBox + Left = 114 + Height = 23 + Top = 81 + Width = 185 + ItemHeight = 15 + ItemIndex = 2 + Items.Strings = ( + 'Completed' + 'Ongoing' + '<none>' + ) + Style = csDropDownList + TabOrder = 3 + Text = '<none>' + end + object lbFilterSummary: TLabel + Left = 0 + Height = 23 + Top = 108 + Width = 110 + Caption = 'Summary' + Font.Height = -13 + Font.Style = [fsBold] + ParentBidiMode = False + ParentColor = False + ParentFont = False + end + object edFilterSummary: TEdit + Left = 114 + Height = 23 + Top = 108 + Width = 185 + TabOrder = 4 + TextHint = 'Part of summary' + end + end + object Panel2: TPanel + Left = 303 + Height = 136 + Top = 0 + Width = 225 + Align = alClient + AutoSize = True + BorderSpacing.Left = 4 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ClientHeight = 136 + ClientWidth = 225 + TabOrder = 1 + object rbOne: TRadioButton + Left = 0 + Height = 19 + Top = 0 + Width = 169 + Caption = 'Have one of genres checked' + ParentFont = False + TabOrder = 0 + end + object rbAll: TRadioButton + Left = 0 + Height = 19 + Top = 23 + Width = 169 + Caption = 'Have all genre checked' + Checked = True + ParentFont = False + TabOrder = 1 + TabStop = True + end + object cbOnlyNew: TCheckBox + Left = 0 + Height = 19 + Top = 46 + Width = 169 + Caption = 'Search only new manga' + ParentFont = False + TabOrder = 2 + end + object cbSearchFromAllSites: TCheckBox + Left = 0 + Height = 19 + Top = 69 + Width = 169 + Caption = 'Search in all manga sites' + TabOrder = 3 + end + object cbUseRegExpr: TCheckBox + Left = 0 + Height = 19 + Top = 92 + Width = 169 + Caption = 'Regular Expression' + TabOrder = 4 + end + end + end + object pnGenres: TPanel + Left = 8 + Height = 180 + Top = 8 + Width = 528 + Align = alTop + AutoSize = True + BorderSpacing.Around = 8 + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.Layout = cclTopToBottomThenLeftToRight + ChildSizing.ControlsPerLine = 8 + ClientHeight = 180 + ClientWidth = 528 + PopupMenu = pmFilterGenreAll + TabOrder = 0 + object ckFilterAction: TCheckBox + Left = 0 + Height = 19 + Hint = 'A work typically depicting fighting, violence, chaos, and fast paced motion.' + Top = 0 + Width = 91 + AllowGrayed = True + Caption = 'Action' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 0 + end + object ckFilterAdult: TCheckBox + Left = 0 + Height = 19 + Hint = 'Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity.' + Top = 23 + Width = 91 + AllowGrayed = True + Caption = 'Adult' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 1 + end + object ckFilterAdventure: TCheckBox + Left = 0 + Height = 19 + Hint = 'If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it''s up to your personal prejudice on this case.' + Top = 46 + Width = 91 + AllowGrayed = True + Caption = 'Adventure' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 2 + end + object ckFilterComedy: TCheckBox + Left = 0 + Height = 19 + Hint = 'A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict.' + Top = 69 + Width = 91 + AllowGrayed = True + Caption = 'Comedy' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 3 + end + object ckFilterDoujinshi: TCheckBox + Left = 0 + Height = 19 + Hint = 'Fan based work inpspired by official manga/anime.' + Top = 92 + Width = 91 + AllowGrayed = True + Caption = 'Doujinshi' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 4 + end + object ckFilterDrama: TCheckBox + Left = 0 + Height = 19 + Hint = 'A work meant to bring on an emotional response, such as instilling sadness or tension.' + Top = 115 + Width = 91 + AllowGrayed = True + Caption = 'Drama' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 5 + end + object ckFilterEchi: TCheckBox + Left = 0 + Height = 19 + Hint = 'Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans.' + Top = 138 + Width = 91 + AllowGrayed = True + Caption = 'Ecchi' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 6 + end + object ckFilterFantasy: TCheckBox + Left = 0 + Height = 19 + Hint = 'Anything that involves, but not limited to, magic, dream world, and fairy tales.' + Top = 161 + Width = 91 + AllowGrayed = True + Caption = 'Fantasy' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 7 + end + object ckFilterGenderBender: TCheckBox + Left = 95 + Height = 19 + Hint = 'Girls dressing up as guys, guys dressing up as girls.'#13#10'Guys turning into girls, girls turning into guys.' + Top = 0 + Width = 114 + AllowGrayed = True + Caption = 'Gender Bender' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 8 + end + object ckFilterHarem: TCheckBox + Left = 95 + Height = 19 + Hint = 'A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed.' + Top = 23 + Width = 114 + AllowGrayed = True + Caption = 'Harem' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 9 + end + object ckFilterHentai: TCheckBox + Left = 95 + Height = 19 + Hint = 'Hentai' + Top = 46 + Width = 114 + AllowGrayed = True + Caption = 'Hentai' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 10 + end + object ckFilterHistorical: TCheckBox + Left = 95 + Height = 19 + Hint = 'Having to do with old or ancient times.' + Top = 69 + Width = 114 + AllowGrayed = True + Caption = 'Historical' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 11 + end + object ckFilterHorror: TCheckBox + Left = 95 + Height = 19 + Hint = 'A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking.' + Top = 92 + Width = 114 + AllowGrayed = True + Caption = 'Horror' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 12 + end + object ckFilterJosei: TCheckBox + Left = 95 + Height = 19 + Hint = 'Literally "Woman". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature.' + Top = 115 + Width = 114 + AllowGrayed = True + Caption = 'Josei' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 13 + end + object ckFilterLolicon: TCheckBox + Left = 95 + Height = 19 + Hint = 'Representing a sexual attraction to young or under-age girls.' + Top = 138 + Width = 114 + AllowGrayed = True + Caption = 'Lolicon' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 14 + end + object ckFilterMartialArts: TCheckBox + Left = 95 + Height = 19 + Hint = 'As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth.' + Top = 161 + Width = 114 + AllowGrayed = True + Caption = 'Martial Arts' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 15 + end + object ckFilterMature: TCheckBox + Left = 213 + Height = 19 + Hint = 'Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language.' + Top = 0 + Width = 109 + AllowGrayed = True + Caption = 'Mature' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 16 + end + object ckFilterMecha: TCheckBox + Left = 213 + Height = 19 + Hint = 'A work involving and usually concentrating on all types of large robotic machines.' + Top = 23 + Width = 109 + AllowGrayed = True + Caption = 'Mecha' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 17 + end + object ckFilterMusical: TCheckBox + Left = 213 + Height = 19 + Hint = 'Musical' + Top = 46 + Width = 109 + AllowGrayed = True + Caption = 'Musical' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 18 + end + object ckFilterMystery: TCheckBox + Left = 213 + Height = 19 + Hint = 'Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it.' + Top = 69 + Width = 109 + AllowGrayed = True + Caption = 'Mystery' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 19 + end + object ckFilterPsychological: TCheckBox + Left = 213 + Height = 19 + Hint = 'Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology.' + Top = 92 + Width = 109 + AllowGrayed = True + Caption = 'Psychological' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 20 + end + object ckFilterRomance: TCheckBox + Left = 213 + Height = 19 + Hint = 'Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is.' + Top = 115 + Width = 109 + AllowGrayed = True + Caption = 'Romance' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 21 + end + object ckFilterSchoolLife: TCheckBox + Left = 213 + Height = 19 + Hint = 'Having a major setting of the story deal with some type of school.' + Top = 138 + Width = 109 + AllowGrayed = True + Caption = 'School Life' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 22 + end + object ckFilterSciFi: TCheckBox + Left = 213 + Height = 19 + Hint = 'Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world.' + Top = 161 + Width = 109 + AllowGrayed = True + Caption = 'Sci-Fi' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 23 + end + object ckFilterSeinen: TCheckBox + Left = 326 + Height = 19 + Hint = 'From Google: Seinen means ''young Man''. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood.' + Top = 0 + Width = 97 + AllowGrayed = True + Caption = 'Seinen' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 24 + end + object ckFilterShotacon: TCheckBox + Left = 326 + Height = 19 + Hint = 'Representing a sexual attraction to young or under-age boys.' + Top = 23 + Width = 97 + AllowGrayed = True + Caption = 'Shotacon' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 25 + end + object ckFilterShoujo: TCheckBox + Left = 326 + Height = 19 + Hint = 'A work intended and primarily written for females. Usually involves a lot of romance and strong character development.' + Top = 46 + Width = 97 + AllowGrayed = True + Caption = 'Shoujo' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 26 + end + object ckFilterShoujoAi: TCheckBox + Left = 326 + Height = 19 + Hint = 'Often synonymous with yuri, this can be thought of as somewhat less extreme. "Girl''''s Love", so to speak.' + Top = 69 + Width = 97 + AllowGrayed = True + Caption = 'Shoujo Ai' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 27 + end + object ckFilterShounen: TCheckBox + Left = 326 + Height = 19 + Hint = 'A work intended and primarily written for males. These works usually involve fighting and/or violence.' + Top = 92 + Width = 97 + AllowGrayed = True + Caption = 'Shounen' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 28 + end + object ckFilterShounenAi: TCheckBox + Left = 326 + Height = 19 + Hint = 'Often synonymous with yaoi, this can be thought of as somewhat less extreme. "Boy''''s Love", so to speak' + Top = 115 + Width = 97 + AllowGrayed = True + Caption = 'Shounen Ai' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 29 + end + object ckFilterSliceofLife: TCheckBox + Left = 326 + Height = 19 + Hint = 'As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own.' + Top = 138 + Width = 97 + AllowGrayed = True + Caption = 'Slice of Life' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 30 + end + object ckFilterSmut: TCheckBox + Left = 326 + Height = 19 + Hint = 'Deals with series that are considered profane or offensive, particularly with regards to sexual content.' + Top = 161 + Width = 97 + HelpType = htKeyword + AllowGrayed = True + Caption = 'Smut' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 31 + end + object ckFilterSports: TCheckBox + Left = 427 + Height = 19 + Hint = 'As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few.' + Top = 0 + Width = 101 + AllowGrayed = True + Caption = 'Sports' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 32 + end + object ckFilterSupernatural: TCheckBox + Left = 427 + Height = 19 + Hint = 'Usually entails amazing and unexplained powers or events which defy the laws of physics.' + Top = 23 + Width = 101 + AllowGrayed = True + Caption = 'Supernatural' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 33 + end + object ckFilterTragedy: TCheckBox + Left = 427 + Height = 19 + Hint = 'Contains events resulting in great loss and misfortune.' + Top = 46 + Width = 101 + AllowGrayed = True + Caption = 'Tragedy' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 34 + end + object ckFilterYaoi: TCheckBox + Left = 427 + Height = 19 + Hint = 'This work usually involves intimate relationships between men.' + Top = 69 + Width = 101 + AllowGrayed = True + Caption = 'Yaoi' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 35 + end + object ckFilterYuri: TCheckBox + Left = 427 + Height = 19 + Hint = 'This work usually involves intimate relationships between women.' + Top = 92 + Width = 101 + AllowGrayed = True + Caption = 'Yuri' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 36 + end + object ckFilterWeebtons: TCheckBox + Left = 427 + Height = 19 + Hint = 'Weebtoons' + Top = 115 + Width = 101 + AllowGrayed = True + Caption = 'Weebtoons' + ParentFont = False + ParentShowHint = False + PopupMenu = pmFilterGenreAll + ShowHint = True + TabOrder = 37 + end + end + object Panel3: TPanel + Left = 0 + Height = 35 + Top = 381 + Width = 544 + Align = alTop + AutoSize = True + BevelOuter = bvNone + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 3 + ClientHeight = 35 + ClientWidth = 544 + TabOrder = 3 + object btFilter: TBitBtn + Left = 4 + Height = 27 + Top = 4 + Width = 78 + Caption = 'Filter' + Font.Height = -13 + Font.Style = [fsBold] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000089C5106999C51065CA75C0D00B56A1800000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A0000001100000004A75C0DCCA75C0DCCA95E0E5CB56A1800000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578B76C1999B56A + 18CCB56A18CCB56A18CCB56A18CCFFC538FFB56A18CCB76C195C000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097EC37923CCFFE3 + 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87D0852D99D287 + 2ECCD2872ECCD2872ECCD2872ECCFFE597FFD2872ECCD0852D5C000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B89714C1F00D58A + 3100D58A3100D98E3400DF9438CCDF9438CCDE93375CD2872E001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B8912121200A870 + 2D00D58A3100E69B3D00E79C3E99E79C3E5CDF943800D2872E00363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 25005C4A3300E69B3D00E89D3F00E89D3F00DF943800D2872E00363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535006B594100E89D3F00E89D3F00DF943800D2872E00363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A434343006F5D450097724300936D3F008C673A00363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btFilterClick + ParentFont = False + TabOrder = 1 + end + object btRemoveFilterLarge: TBitBtn + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Side = asrBottom + Left = 86 + Height = 27 + Hint = 'Remove filter' + Top = 4 + Width = 129 + Caption = 'Remove filter' + Font.Height = -13 + Font.Style = [fsBold] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00050000001E000000320000003300000082000000830101014E000000330000 + 003300000022000000080000000000005A000000770000008000000000000000 + 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 + 001A000000110000000400005A00000077000000770000008000000000000000 + 000000000000000000000202020002020272C4B5B5FF05050578040426000000 + 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 + 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 + 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 + 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 + A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 + 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 + A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 + 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C + 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C + 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 + 250027275200101090000000AA000000AA000000AA000000A700363636002C2C + 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 + 252D353535004343430035355F00121291000000AA000000A700363636002C2C + 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 + 257E3535352A43434300464646004646460035355F0023237700363636002C2C + 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD + CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C + 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA + CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C + 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD + ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA + EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 + D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C + 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 + 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btRemoveFilterClick + ParentFont = False + ParentShowHint = False + ShowHint = True + TabOrder = 0 + end + object btFilterReset: TBitBtn + Left = 219 + Height = 27 + Top = 4 + Width = 116 + Caption = 'Reset value' + Font.Height = -13 + Font.Style = [fsBold] + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000050000001E000000320000003300000082000000830101014E0000 + 003300000033000000220000000800000000FFFFFF00FFFFFF00FFFFFF000000 + 0000000000030000000F000000190000001A00000078D1C2C2FF0303037A0000 + 001A0000001A000000110000000400000000FFFFFF00FFFFFF00FFFFFF000000 + 00000000000000000000000000000202020002020272C4B5B5FF050505780505 + 050000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 + 00000000000000000000010101000101010001010174C4B5B5FF0909097E0A0A + 0A0008080800000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 + 0000000000000000000000000000000000000000007AC4B5B5FF0B0B0B870D0D + 0D000D0D0D000A0A0A000000000000000000FFFFFF00FFFFFF00FFFFFF000000 + 0000000000000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D + 0D000D0D0D000D0D0D000A0A0A0007070700FFFFFF00FFFFFF00FFFFFF001B1B + 1B00161616000404040000000000000000000000007BC4B5B5FF0B0B0B891212 + 12001919190021212100282828002A2A2A00FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717 + 172F25252500353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF1717 + 17852525252D353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7 + C7FF2525257E3535352A4343430046464600FFFFFF00FFFFFF00FFFFFF003636 + 36002C2C2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBC + BCFFDFCDCDFF353535774343432846464600FFFFFF00FFFFFF00FFFFFF004B4B + 4B002C2C2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5 + B5FFDCCACAFFEBDADAFF4343436F4E4E4E00FFFFFF00FFFFFF00FFFFFF004F4F + 4F662C2C2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C + 9CFFB6ADADFFC5BCBCFF4343436F4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F + 4F66EAEAEAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4 + C4FFE4D2D2FFF0DFDFFFF9E8E8FF4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F + 4F4D2C2C2C6608080866000000660000006A0000007B020202890B0B0B891717 + 17852525257E353535774343436F4F4F4F4FFFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btFilterResetClick + ParentFont = False + TabOrder = 2 + end + end + end end - object rbAll: TRadioButton - Left = 0 - Height = 19 - Top = 23 - Width = 169 - Caption = 'Have all genre checked' - Checked = True - ParentFont = False - TabOrder = 1 - TabStop = True - end - object cbOnlyNew: TCheckBox - Left = 0 - Height = 19 - Top = 46 - Width = 169 - Caption = 'Search only new manga' - ParentFont = False - TabOrder = 2 - end - object cbSearchFromAllSites: TCheckBox - Left = 0 - Height = 19 - Top = 69 - Width = 169 - Caption = 'Search in all manga sites' - TabOrder = 3 - end - object cbUseRegExpr: TCheckBox - Left = 0 - Height = 19 - Top = 92 - Width = 169 - Caption = 'Regular Expression' - TabOrder = 4 - end - end - end - object pnGenres: TPanel - Left = 8 - Height = 180 - Top = 8 - Width = 542 - Align = alTop - AutoSize = True - BorderSpacing.Around = 8 - BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.Layout = cclTopToBottomThenLeftToRight - ChildSizing.ControlsPerLine = 8 - ClientHeight = 180 - ClientWidth = 542 - PopupMenu = pmFilterGenreAll - TabOrder = 0 - object ckFilterAction: TCheckBox - Left = 0 - Height = 19 - Hint = 'A work typically depicting fighting, violence, chaos, and fast paced motion.' - Top = 0 - Width = 94 - AllowGrayed = True - Caption = 'Action' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 0 - end - object ckFilterAdult: TCheckBox - Left = 0 - Height = 19 - Hint = 'Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity.' - Top = 23 - Width = 94 - AllowGrayed = True - Caption = 'Adult' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 1 - end - object ckFilterAdventure: TCheckBox - Left = 0 - Height = 19 - Hint = 'If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it''s up to your personal prejudice on this case.' - Top = 46 - Width = 94 - AllowGrayed = True - Caption = 'Adventure' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 2 - end - object ckFilterComedy: TCheckBox - Left = 0 - Height = 19 - Hint = 'A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict.' - Top = 69 - Width = 94 - AllowGrayed = True - Caption = 'Comedy' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 3 - end - object ckFilterDoujinshi: TCheckBox - Left = 0 - Height = 19 - Hint = 'Fan based work inpspired by official manga/anime.' - Top = 92 - Width = 94 - AllowGrayed = True - Caption = 'Doujinshi' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 4 - end - object ckFilterDrama: TCheckBox - Left = 0 - Height = 19 - Hint = 'A work meant to bring on an emotional response, such as instilling sadness or tension.' - Top = 115 - Width = 94 - AllowGrayed = True - Caption = 'Drama' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 5 - end - object ckFilterEchi: TCheckBox - Left = 0 - Height = 19 - Hint = 'Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans.' - Top = 138 - Width = 94 - AllowGrayed = True - Caption = 'Ecchi' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 6 - end - object ckFilterFantasy: TCheckBox - Left = 0 - Height = 19 - Hint = 'Anything that involves, but not limited to, magic, dream world, and fairy tales.' - Top = 161 - Width = 94 - AllowGrayed = True - Caption = 'Fantasy' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 7 - end - object ckFilterGenderBender: TCheckBox - Left = 98 - Height = 19 - Hint = 'Girls dressing up as guys, guys dressing up as girls.'#13#10'Guys turning into girls, girls turning into guys.' - Top = 0 - Width = 117 - AllowGrayed = True - Caption = 'Gender Bender' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 8 - end - object ckFilterHarem: TCheckBox - Left = 98 - Height = 19 - Hint = 'A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed.' - Top = 23 - Width = 117 - AllowGrayed = True - Caption = 'Harem' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 9 - end - object ckFilterHentai: TCheckBox - Left = 98 - Height = 19 - Hint = 'Hentai' - Top = 46 - Width = 117 - AllowGrayed = True - Caption = 'Hentai' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 10 - end - object ckFilterHistorical: TCheckBox - Left = 98 - Height = 19 - Hint = 'Having to do with old or ancient times.' - Top = 69 - Width = 117 - AllowGrayed = True - Caption = 'Historical' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 11 - end - object ckFilterHorror: TCheckBox - Left = 98 - Height = 19 - Hint = 'A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking.' - Top = 92 - Width = 117 - AllowGrayed = True - Caption = 'Horror' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 12 - end - object ckFilterJosei: TCheckBox - Left = 98 - Height = 19 - Hint = 'Literally "Woman". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature.' - Top = 115 - Width = 117 - AllowGrayed = True - Caption = 'Josei' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 13 - end - object ckFilterLolicon: TCheckBox - Left = 98 - Height = 19 - Hint = 'Representing a sexual attraction to young or under-age girls.' - Top = 138 - Width = 117 - AllowGrayed = True - Caption = 'Lolicon' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 14 - end - object ckFilterMartialArts: TCheckBox - Left = 98 - Height = 19 - Hint = 'As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth.' - Top = 161 - Width = 117 - AllowGrayed = True - Caption = 'Martial Arts' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 15 - end - object ckFilterMature: TCheckBox - Left = 219 - Height = 19 - Hint = 'Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language.' - Top = 0 - Width = 112 - AllowGrayed = True - Caption = 'Mature' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 16 - end - object ckFilterMecha: TCheckBox - Left = 219 - Height = 19 - Hint = 'A work involving and usually concentrating on all types of large robotic machines.' - Top = 23 - Width = 112 - AllowGrayed = True - Caption = 'Mecha' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 17 - end - object ckFilterMusical: TCheckBox - Left = 219 - Height = 19 - Hint = 'Musical' - Top = 46 - Width = 112 - AllowGrayed = True - Caption = 'Musical' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 18 - end - object ckFilterMystery: TCheckBox - Left = 219 - Height = 19 - Hint = 'Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it.' - Top = 69 - Width = 112 - AllowGrayed = True - Caption = 'Mystery' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 19 - end - object ckFilterPsychological: TCheckBox - Left = 219 - Height = 19 - Hint = 'Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology.' - Top = 92 - Width = 112 - AllowGrayed = True - Caption = 'Psychological' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 20 - end - object ckFilterRomance: TCheckBox - Left = 219 - Height = 19 - Hint = 'Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is.' - Top = 115 - Width = 112 - AllowGrayed = True - Caption = 'Romance' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 21 - end - object ckFilterSchoolLife: TCheckBox - Left = 219 - Height = 19 - Hint = 'Having a major setting of the story deal with some type of school.' - Top = 138 - Width = 112 - AllowGrayed = True - Caption = 'School Life' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 22 - end - object ckFilterSciFi: TCheckBox - Left = 219 - Height = 19 - Hint = 'Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world.' - Top = 161 - Width = 112 - AllowGrayed = True - Caption = 'Sci-Fi' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 23 - end - object ckFilterSeinen: TCheckBox - Left = 335 - Height = 19 - Hint = 'From Google: Seinen means ''young Man''. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood.' - Top = 0 - Width = 100 - AllowGrayed = True - Caption = 'Seinen' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 24 - end - object ckFilterShotacon: TCheckBox - Left = 335 - Height = 19 - Hint = 'Representing a sexual attraction to young or under-age boys.' - Top = 23 - Width = 100 - AllowGrayed = True - Caption = 'Shotacon' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 25 - end - object ckFilterShoujo: TCheckBox - Left = 335 - Height = 19 - Hint = 'A work intended and primarily written for females. Usually involves a lot of romance and strong character development.' - Top = 46 - Width = 100 - AllowGrayed = True - Caption = 'Shoujo' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 26 - end - object ckFilterShoujoAi: TCheckBox - Left = 335 - Height = 19 - Hint = 'Often synonymous with yuri, this can be thought of as somewhat less extreme. "Girl''''s Love", so to speak.' - Top = 69 - Width = 100 - AllowGrayed = True - Caption = 'Shoujo Ai' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 27 - end - object ckFilterShounen: TCheckBox - Left = 335 - Height = 19 - Hint = 'A work intended and primarily written for males. These works usually involve fighting and/or violence.' - Top = 92 - Width = 100 - AllowGrayed = True - Caption = 'Shounen' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 28 - end - object ckFilterShounenAi: TCheckBox - Left = 335 - Height = 19 - Hint = 'Often synonymous with yaoi, this can be thought of as somewhat less extreme. "Boy''''s Love", so to speak' - Top = 115 - Width = 100 - AllowGrayed = True - Caption = 'Shounen Ai' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 29 - end - object ckFilterSliceofLife: TCheckBox - Left = 335 - Height = 19 - Hint = 'As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own.' - Top = 138 - Width = 100 - AllowGrayed = True - Caption = 'Slice of Life' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 30 - end - object ckFilterSmut: TCheckBox - Left = 335 - Height = 19 - Hint = 'Deals with series that are considered profane or offensive, particularly with regards to sexual content.' - Top = 161 - Width = 100 - HelpType = htKeyword - AllowGrayed = True - Caption = 'Smut' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 31 - end - object ckFilterSports: TCheckBox - Left = 439 - Height = 19 - Hint = 'As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few.' - Top = 0 - Width = 103 - AllowGrayed = True - Caption = 'Sports' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 32 - end - object ckFilterSupernatural: TCheckBox - Left = 439 - Height = 19 - Hint = 'Usually entails amazing and unexplained powers or events which defy the laws of physics.' - Top = 23 - Width = 103 - AllowGrayed = True - Caption = 'Supernatural' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 33 - end - object ckFilterTragedy: TCheckBox - Left = 439 - Height = 19 - Hint = 'Contains events resulting in great loss and misfortune.' - Top = 46 - Width = 103 - AllowGrayed = True - Caption = 'Tragedy' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 34 - end - object ckFilterYaoi: TCheckBox - Left = 439 - Height = 19 - Hint = 'This work usually involves intimate relationships between men.' - Top = 69 - Width = 103 - AllowGrayed = True - Caption = 'Yaoi' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 35 - end - object ckFilterYuri: TCheckBox - Left = 439 - Height = 19 - Hint = 'This work usually involves intimate relationships between women.' - Top = 92 - Width = 103 - AllowGrayed = True - Caption = 'Yuri' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 36 - end - object ckFilterWeebtons: TCheckBox - Left = 439 - Height = 19 - Hint = 'Weebtoons' - Top = 115 - Width = 103 - AllowGrayed = True - Caption = 'Weebtoons' - ParentFont = False - ParentShowHint = False - PopupMenu = pmFilterGenreAll - ShowHint = True - TabOrder = 37 - end - end - object Panel3: TPanel - Left = 0 - Height = 35 - Top = 381 - Width = 558 - Align = alTop - AutoSize = True - BevelOuter = bvNone - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 3 - ClientHeight = 35 - ClientWidth = 558 - TabOrder = 3 - object btFilter: TBitBtn - Left = 4 - Height = 27 - Top = 4 - Width = 78 - Caption = 'Filter' - Font.Height = -13 - Font.Style = [fsBold] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000089C5106999C51065CA75C0D00B56A1800000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A0000001100000004A75C0DCCA75C0DCCA95E0E5CB56A1800000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578B76C1999B56A - 18CCB56A18CCB56A18CCB56A18CCFFC538FFB56A18CCB76C195C000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097EC37923CCFFE3 - 92FFFFD56AFFFFD15DFFFFD15DFFFFD15DFFFFD873FFC37923CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87D0852D99D287 - 2ECCD2872ECCD2872ECCD2872ECCFFE597FFD2872ECCD0852D5C000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B89714C1F00D58A - 3100D58A3100D98E3400DF9438CCDF9438CCDE93375CD2872E001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B8912121200A870 - 2D00D58A3100E69B3D00E79C3E99E79C3E5CDF943800D2872E00363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 25005C4A3300E69B3D00E89D3F00E89D3F00DF943800D2872E00363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535006B594100E89D3F00E89D3F00DF943800D2872E00363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A434343006F5D450097724300936D3F008C673A00363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btFilterClick - ParentFont = False - TabOrder = 1 - end - object btRemoveFilterLarge: TBitBtn - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Side = asrBottom - Left = 86 - Height = 27 - Hint = 'Remove filter' - Top = 4 - Width = 129 - Caption = 'Remove filter' - Font.Height = -13 - Font.Style = [fsBold] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000080000000000005A000000770000008000000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A000000110000000400005A00000077000000770000008000000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578040426000000 - 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 - 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 - A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 - A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C - 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 250027275200101090000000AA000000AA000000AA000000A700363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535004343430035355F00121291000000AA000000A700363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A43434300464646004646460035355F0023237700363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btRemoveFilterClick - ParentFont = False - ParentShowHint = False - ShowHint = True - TabOrder = 0 - end - object btFilterReset: TBitBtn - Left = 219 - Height = 27 - Top = 4 - Width = 116 - Caption = 'Reset value' - Font.Height = -13 - Font.Style = [fsBold] - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000050000001E000000320000003300000082000000830101014E0000 - 003300000033000000220000000800000000FFFFFF00FFFFFF00FFFFFF000000 - 0000000000030000000F000000190000001A00000078D1C2C2FF0303037A0000 - 001A0000001A000000110000000400000000FFFFFF00FFFFFF00FFFFFF000000 - 00000000000000000000000000000202020002020272C4B5B5FF050505780505 - 050000000000000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 00000000000000000000010101000101010001010174C4B5B5FF0909097E0A0A - 0A0008080800000000000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000007AC4B5B5FF0B0B0B870D0D - 0D000D0D0D000A0A0A000000000000000000FFFFFF00FFFFFF00FFFFFF000000 - 0000000000000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D - 0D000D0D0D000D0D0D000A0A0A0007070700FFFFFF00FFFFFF00FFFFFF001B1B - 1B00161616000404040000000000000000000000007BC4B5B5FF0B0B0B891212 - 12001919190021212100282828002A2A2A00FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717 - 172F25252500353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF1717 - 17852525252D353535004343430046464600FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7 - C7FF2525257E3535352A4343430046464600FFFFFF00FFFFFF00FFFFFF003636 - 36002C2C2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBC - BCFFDFCDCDFF353535774343432846464600FFFFFF00FFFFFF00FFFFFF004B4B - 4B002C2C2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5 - B5FFDCCACAFFEBDADAFF4343436F4E4E4E00FFFFFF00FFFFFF00FFFFFF004F4F - 4F662C2C2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C - 9CFFB6ADADFFC5BCBCFF4343436F4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F - 4F66EAEAEAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4 - C4FFE4D2D2FFF0DFDFFFF9E8E8FF4F4F4F69FFFFFF00FFFFFF00FFFFFF004F4F - 4F4D2C2C2C6608080866000000660000006A0000007B020202890B0B0B891717 - 17852525257E353535774343436F4F4F4F4FFFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btFilterResetClick - ParentFont = False - TabOrder = 2 end end end end object tsFavorites: TTabSheet Caption = 'Favorites' - ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 492 - ClientWidth = 558 + ClientHeight = 498 + ClientWidth = 761 object vtFavorites: TVirtualStringTree AnchorSideTop.Side = asrBottom - Left = 4 - Height = 374 + Left = 0 + Height = 463 Top = 31 - Width = 549 + Width = 761 + Align = alBottom Anchors = [akTop, akLeft, akRight, akBottom] Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight @@ -1981,11 +2348,15 @@ object MainForm: TMainForm OnHeaderClick = vtFavoritesHeaderClick end object btFavoritesImport: TBitBtn - Left = 33 - Height = 24 - Top = 458 - Width = 491 - Anchors = [akLeft, akRight, akBottom] + AnchorSideTop.Control = edFavoritesSearch + AnchorSideRight.Control = vtFavorites + AnchorSideRight.Side = asrBottom + Left = 661 + Height = 26 + Top = 4 + Width = 100 + Anchors = [akTop, akRight] + AutoSize = True Caption = 'Import list' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -2028,11 +2399,17 @@ object MainForm: TMainForm TabOrder = 2 end object btCancelFavoritesCheck: TSpeedButton - Left = 490 - Height = 40 - Top = 412 - Width = 34 - Anchors = [akRight, akBottom] + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btFavoritesCheckNewChapter + AnchorSideRight.Control = btFavoritesImport + AnchorSideBottom.Control = btFavoritesCheckNewChapter + AnchorSideBottom.Side = asrBottom + Left = 641 + Height = 26 + Top = 4 + Width = 20 + Anchors = [akTop, akRight, akBottom] + AutoSize = True Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000090000 @@ -2073,11 +2450,15 @@ object MainForm: TMainForm OnClick = btCancelFavoritesCheckClick end object btFavoritesCheckNewChapter: TBitBtn - Left = 33 - Height = 40 - Top = 412 - Width = 491 - Anchors = [akLeft, akRight, akBottom] + AnchorSideLeft.Control = btCancelFavoritesCheck + AnchorSideTop.Control = edFavoritesSearch + AnchorSideRight.Control = btCancelFavoritesCheck + Left = 476 + Height = 26 + Top = 4 + Width = 165 + Anchors = [akTop, akRight] + AutoSize = True Caption = 'Check for new chapter' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -2119,7 +2500,7 @@ object MainForm: TMainForm TabOrder = 1 end object edFavoritesSearch: TEditButton - Left = 4 + Left = 0 Height = 23 Top = 4 Width = 150 @@ -2171,14 +2552,16 @@ object MainForm: TMainForm end object tsOption: TTabSheet Caption = 'Options' - ClientHeight = 492 - ClientWidth = 558 - object pnOptions: TPageControl - Left = 8 - Height = 415 - Top = 8 - Width = 539 + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 498 + ClientWidth = 761 + object pcOptions: TPageControl + Left = 0 + Height = 420 + Top = 4 + Width = 761 ActivePage = tsGeneral + Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False TabIndex = 0 @@ -2189,8 +2572,8 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime AnchorSideTop.Control = seOptionNewMangaTime @@ -2235,7 +2618,7 @@ object MainForm: TMainForm Left = 4 Height = 118 Top = 244 - Width = 520 + Width = 742 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 20 Caption = 'External program' @@ -2244,14 +2627,14 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 98 - ClientWidth = 516 + ClientWidth = 738 ParentFont = False TabOrder = 1 object lbOptionExternal: TLabel Left = 4 Height = 15 Top = 4 - Width = 508 + Width = 730 Align = alTop Caption = 'Open manga by using external program:' ParentColor = False @@ -2260,7 +2643,7 @@ object MainForm: TMainForm Left = 4 Height = 15 Top = 50 - Width = 508 + Width = 730 Align = alTop Caption = 'Parameters:' ParentColor = False @@ -2272,7 +2655,7 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 69 - Width = 481 + Width = 703 Anchors = [akTop, akLeft, akRight] TabOrder = 0 TextHint = 'External program parameters' @@ -2282,7 +2665,7 @@ object MainForm: TMainForm AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edOptionExternalParams AnchorSideTop.Side = asrCenter - Left = 489 + Left = 711 Height = 15 Top = 73 Width = 13 @@ -2297,7 +2680,7 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 23 - Width = 508 + Width = 730 Align = alTop ButtonWidth = 23 Glyph.Data = { @@ -2348,7 +2731,7 @@ object MainForm: TMainForm Left = 4 Height = 15 Top = 8 - Width = 523 + Width = 745 Align = alTop Caption = 'Language:' ParentColor = False @@ -2434,13 +2817,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object cbOptionShowDownloadToolbar: TCheckBox Left = 4 Height = 19 Top = 177 - Width = 523 + Width = 745 Align = alTop Caption = 'Show downloads toolbar' ParentFont = False @@ -2450,7 +2833,7 @@ object MainForm: TMainForm Left = 4 Height = 165 Top = 8 - Width = 523 + Width = 745 Align = alTop AutoSize = True Caption = 'Drop Box' @@ -2459,13 +2842,13 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 145 - ClientWidth = 519 + ClientWidth = 741 TabOrder = 1 object ckDropTarget: TCheckBox Left = 4 Height = 19 Top = 4 - Width = 511 + Width = 733 Align = alTop Caption = 'Show Drop Box' ParentFont = False @@ -2531,7 +2914,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 223 - Width = 523 + Width = 745 Align = alTop Caption = 'Enable load manga cover' ParentFont = False @@ -2541,7 +2924,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 200 - Width = 523 + Width = 745 Align = alTop Caption = 'Show "Delete all completed tasks" in downloads toolbar' ParentFont = False @@ -2551,7 +2934,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 246 - Width = 523 + Width = 745 Align = alTop Caption = 'Show balloon hint' ParentFont = False @@ -2560,13 +2943,13 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object sbDownloadConnections: TScrollBox Left = 0 - Height = 387 + Height = 392 Top = 0 - Width = 531 + Width = 753 HorzScrollBar.Page = 455 VertScrollBar.Page = 268 Align = alClient @@ -2575,8 +2958,8 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 TabOrder = 0 object cbOptionUseProxy: TCheckBox AnchorSideLeft.Control = seOptionConnectionTimeout @@ -2875,23 +3258,23 @@ object MainForm: TMainForm end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object sbSaveTo: TScrollBox Left = 0 - Height = 387 + Height = 392 Top = 0 - Width = 531 + Width = 753 HorzScrollBar.Page = 198 - VertScrollBar.Page = 387 + VertScrollBar.Page = 392 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 514 + ClientHeight = 392 + ClientWidth = 736 TabOrder = 0 object rgOptionCompress: TRadioGroup AnchorSideLeft.Control = lbDefaultDownloadPath @@ -2902,7 +3285,7 @@ object MainForm: TMainForm Left = 4 Height = 60 Top = 54 - Width = 506 + Width = 728 Anchors = [akTop, akLeft, akRight] AutoFill = True BorderSpacing.Top = 4 @@ -2916,7 +3299,7 @@ object MainForm: TMainForm ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 4 ClientHeight = 40 - ClientWidth = 502 + ClientWidth = 724 Columns = 4 ItemIndex = 0 Items.Strings = ( @@ -2938,7 +3321,7 @@ object MainForm: TMainForm Left = 4 Height = 302 Top = 145 - Width = 506 + Width = 728 Anchors = [akTop, akLeft, akRight] AutoSize = True BorderSpacing.Top = 4 @@ -2948,7 +3331,7 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 282 - ClientWidth = 502 + ClientWidth = 724 ParentFont = False TabOrder = 3 object cbOptionChangeUnicodeCharacter: TCheckBox @@ -3204,7 +3587,7 @@ object MainForm: TMainForm Left = 4 Height = 15 Top = 8 - Width = 506 + Width = 728 Align = alTop Caption = 'Choose the default download path:' ParentColor = False @@ -3214,7 +3597,7 @@ object MainForm: TMainForm Left = 4 Height = 0 Top = 54 - Width = 506 + Width = 728 Align = alTop AutoSize = True BevelOuter = bvNone @@ -3277,7 +3660,7 @@ object MainForm: TMainForm Left = 4 Height = 23 Top = 27 - Width = 506 + Width = 728 Align = alTop ButtonWidth = 23 Glyph.Data = { @@ -3332,13 +3715,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object cbOptionAutoCheckLatestVersion: TCheckBox Left = 4 Height = 19 Top = 8 - Width = 523 + Width = 745 Align = alTop Caption = 'Auto check for latest version ' ParentFont = False @@ -3348,7 +3731,7 @@ object MainForm: TMainForm Left = 4 Height = 166 Top = 31 - Width = 523 + Width = 745 Align = alTop AutoSize = True Caption = 'Favorites' @@ -3357,14 +3740,14 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 146 - ClientWidth = 519 + ClientWidth = 741 ParentFont = False TabOrder = 1 object cbOptionAutoCheckFavStartup: TCheckBox Left = 4 Height = 19 Top = 4 - Width = 511 + Width = 733 Align = alTop Caption = 'Auto check for new chapter at startup' OnChange = cbOptionAutoCheckFavStartupChange @@ -3424,7 +3807,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 50 - Width = 511 + Width = 733 Align = alTop Caption = 'Auto check for new chapter in an interval' OnChange = cbOptionAutoCheckFavIntervalChange @@ -3435,7 +3818,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 27 - Width = 511 + Width = 733 Align = alTop Caption = 'Open Favorites at startup' ParentFont = False @@ -3446,7 +3829,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 201 - Width = 523 + Width = 745 Align = alTop Caption = 'Don''t load manga information when updating list (filter will be not work!)' ParentFont = False @@ -3456,7 +3839,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 224 - Width = 523 + Width = 745 Align = alTop Caption = 'Remove duplicate local data when updating manga list' ParentFont = False @@ -3470,13 +3853,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object gbDialogs: TGroupBox Left = 4 Height = 93 Top = 8 - Width = 523 + Width = 745 Align = alTop AutoSize = True Caption = 'Show dialog confirmation for' @@ -3485,13 +3868,13 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 73 - ClientWidth = 519 + ClientWidth = 741 TabOrder = 0 object cbOptionShowQuitDialog: TCheckBox Left = 4 Height = 19 Top = 4 - Width = 511 + Width = 733 Align = alTop Caption = 'Exit FMD' ParentFont = False @@ -3501,7 +3884,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 27 - Width = 511 + Width = 733 Align = alTop Caption = 'Delete task/favorite' ParentFont = False @@ -3511,7 +3894,7 @@ object MainForm: TMainForm Left = 4 Height = 19 Top = 50 - Width = 511 + Width = 733 Align = alTop Caption = 'Download manga list if empty' ParentFont = False @@ -3525,26 +3908,26 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object pcWebsiteOptions: TPageControl Left = 4 - Height = 371 + Height = 376 Top = 8 - Width = 523 + Width = 745 ActivePage = tsWebsiteSelection Align = alClient TabIndex = 0 TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' - ClientHeight = 343 - ClientWidth = 515 + ClientHeight = 348 + ClientWidth = 737 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 0 - Height = 308 + Height = 313 Top = 35 - Width = 515 + Width = 737 Align = alClient Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight @@ -3573,7 +3956,7 @@ object MainForm: TMainForm Left = 2 Height = 23 Top = 6 - Width = 509 + Width = 731 Align = alTop BorderSpacing.Top = 4 BorderSpacing.Right = 2 @@ -3583,10 +3966,10 @@ object MainForm: TMainForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ClientHeight = 23 - ClientWidth = 509 + ClientWidth = 731 TabOrder = 1 object pnlWebsitesToolRight: TPanel - Left = 339 + Left = 561 Height = 23 Top = 0 Width = 170 @@ -3721,13 +4104,13 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 387 - ClientWidth = 531 + ClientHeight = 392 + ClientWidth = 753 object pcMisc: TPageControl Left = 4 - Height = 371 + Height = 376 Top = 8 - Width = 523 + Width = 745 ActivePage = tsCustomColor Align = alClient TabIndex = 0 @@ -3921,7 +4304,7 @@ object MainForm: TMainForm object btOptionApply: TBitBtn Left = 8 Height = 45 - Top = 434 + Top = 440 Width = 125 Anchors = [akLeft, akBottom] AutoSize = True @@ -3970,14 +4353,13 @@ object MainForm: TMainForm end object tsAbout: TTabSheet Caption = 'About' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 8 - ClientHeight = 492 - ClientWidth = 558 + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 498 + ClientWidth = 761 object btCheckLatestVersion: TBitBtn - Left = 25 + Left = 0 Height = 40 - Top = 441 + Top = 447 Width = 208 Anchors = [akLeft, akBottom] Caption = 'Check for latest version' @@ -4021,11 +4403,14 @@ object MainForm: TMainForm TabOrder = 0 end object btAbortCheckLatestVersion: TSpeedButton - Left = 193 + AnchorSideLeft.Control = btCheckLatestVersion + AnchorSideLeft.Side = asrBottom + Left = 212 Height = 40 - Top = 441 + Top = 447 Width = 40 Anchors = [akLeft, akBottom] + BorderSpacing.Left = 4 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000090000 @@ -4066,11 +4451,15 @@ object MainForm: TMainForm OnClick = btAbortCheckLatestVersionClick end object btVisitMyBlog: TBitBtn - Left = 249 + AnchorSideLeft.Control = btAbortCheckLatestVersion + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btAbortCheckLatestVersion + Left = 256 Height = 40 - Top = 441 + Top = 447 Width = 208 - Anchors = [akLeft, akBottom] + Anchors = [akTop, akLeft, akBottom] + BorderSpacing.Left = 4 Caption = 'Visit my blog' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -4110,12 +4499,13 @@ object MainForm: TMainForm } OnClick = btVisitMyBlogClick TabOrder = 1 + Visible = False end object pcAbout: TPageControl - Left = 4 - Height = 422 - Top = 8 - Width = 550 + Left = 0 + Height = 432 + Top = 4 + Width = 761 ActivePage = tsAboutText Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] @@ -4123,17 +4513,15 @@ object MainForm: TMainForm TabOrder = 2 object tsAboutText: TTabSheet Caption = 'About FMD' - ClientHeight = 394 - ClientWidth = 542 + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 404 + ClientWidth = 753 object rmAbout: TRichMemo - Left = 2 - Height = 388 + Left = 0 + Height = 396 Top = 4 - Width = 536 + Width = 753 Align = alClient - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Around = 2 Color = clWhite Font.Style = [fsBold] HideSelection = False @@ -4146,18 +4534,15 @@ object MainForm: TMainForm end object tsChangelogText: TTabSheet Caption = 'Changelog' - ClientHeight = 388 - ClientWidth = 594 + ChildSizing.TopBottomSpacing = 4 + ClientHeight = 404 + ClientWidth = 753 object mmChangelog: TMemo - Left = 2 - Height = 380 + Left = 0 + Height = 396 Top = 4 - Width = 588 + Width = 753 Align = alClient - BorderSpacing.Top = 2 - BorderSpacing.Right = 2 - BorderSpacing.Bottom = 2 - BorderSpacing.Around = 2 Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Courier New' @@ -4181,336 +4566,6 @@ object MainForm: TMainForm TabOrder = 1 Visible = False end - object pcLeft: TPageControl - Left = 4 - Height = 518 - Top = 12 - Width = 195 - ActivePage = tsMangaList - Align = alLeft - BorderSpacing.Left = 4 - BorderSpacing.Top = 4 - BorderSpacing.Bottom = 4 - Images = IconList - TabIndex = 0 - TabOrder = 4 - object tsMangaList: TTabSheet - Caption = 'Manga List' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 490 - ClientWidth = 187 - object vtMangaList: TVirtualStringTree - AnchorSideLeft.Control = lbMode - AnchorSideTop.Control = lbMode - AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = btRemoveFilter - AnchorSideRight.Side = asrBottom - Left = 4 - Height = 401 - Top = 85 - Width = 179 - Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Top = 8 - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - DragOperations = [] - Header.AutoSizeIndex = 0 - Header.Columns = <> - Header.DefaultHeight = 17 - Header.Height = 23 - Header.MainColumn = -1 - HintMode = hmHint - Margin = 0 - ParentShowHint = False - PopupMenu = pmMangaList - ShowHint = True - TabOrder = 0 - TextMargin = 3 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] - OnBeforeCellPaint = vtMangaListBeforeCellPaint - OnChange = vtMangaListChange - OnColumnDblClick = vtMangaListColumnDblClick - OnGetCursor = vtMangaListGetCursor - OnGetText = vtMangaListGetText - OnGetHint = vtMangaListGetHint - end - object btAbortUpdateList: TSpeedButton - Left = 104 - Height = 22 - Hint = 'Abort update list' - Top = 104 - Width = 23 - Flat = True - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 00020000000C000000160000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A000000170000000C00000002FFFFFF00FFFFFF000000 - 0004000000170000002B00001A430000448000005AAB00005DC400005DC40000 - 5AAB0000448000001A430000002D0000001800000004FFFFFF00FFFFFF000000 - 000000001F000000534D020274BF08089DE30E0EC4F51111D4FD1111D4FD0E0E - C4F508089DE3020274BF0000534D00001F0000000000FFFFFF00FFFFFF000000 - 830000007F4D040488CD1212C4F61212B6FF1111D1FF1111D1FF1111D1FF1111 - D1FF1111B6FF0F0FC2F6030388CD00007F4D00008300FFFFFF00FFFFFF000000 - 851A03038ABF1818C1F61212B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111 - B2FFEEEEEEFF1111B2FF0F0FBCF6020289BF0000851AFFFFFF00FFFFFF000000 - 896C1616AAE21616C1FFD1D1D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEA - EAFFEEEEEEFFEEEEEEFF1111BEFF0909A1E30000896CFFFFFF00FFFFFF000000 - 8DA72E2EC0F51212B4FF1111B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6 - E6FFEAEAEAFF1111B4FF1111B4FF1212AFF500008DA7FFFFFF00FFFFFF000000 - 92C44444CDFD2626B5FF1414ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2 - E2FF1111AAFF1111AAFF1111AAFF1818AFFD000092C4FFFFFF00FFFFFF000000 - 96C44949D1FD3333BBFF2E2EB8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDC - DCFF11119EFF1111A1FF1111A1FF1D1DACFD000096C4FFFFFF00FFFFFF000000 - 9AA74747D3F53737BFFF2323ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDB - DBFFDDDDDDFF11119BFF1616A0FF2727B4F500009AA7FFFFFF00FFFFFF000000 - 9E6C3232C6E34949D1FFFFFFFFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFF - FFFFFFFFFFFFFFFFFFFF4747CFFF2A2ABDE300009E6CFFFFFF00FFFFFF000000 - A11A0808A8BF5656E2F65151D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4F - D7FFFFFFFFFF5050D8FF4F4FDCF60707A7BF0000A11AFFFFFF00FFFFFF000000 - A2000000A54D1010B1CD5B5BE8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5B - E3FF5F5FE7FF5858E4F60F0FB0CD0000A54D0000A200FFFFFF00FFFFFF000000 - A2000000A5000000A84D0909AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5B - E9F53636CFE30909AEBF0000A84D0000A5000000A200FFFFFF00FFFFFF000000 - A2000000A5000000A8000000A91A0000AA6C0000AAA60000AAC40000AAC40000 - AAA60000AA6C0000A91A0000A8000000A5000000A200FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btAbortUpdateListClick - ShowCaption = False - ShowHint = True - ParentShowHint = False - end - object cbSelectManga: TComboBox - Left = 4 - Height = 23 - Hint = 'For more manga sites, please go to Options->Manga sites' - Top = 4 - Width = 150 - Anchors = [akTop, akLeft, akRight] - ItemHeight = 15 - ItemIndex = 0 - Items.Strings = ( - '' - ) - OnChange = cbSelectMangaChange - ParentShowHint = False - ShowHint = True - Sorted = True - Style = csDropDownList - TabOrder = 1 - end - object btUpdateList: TSpeedButton - AnchorSideLeft.Control = cbSelectManga - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = cbSelectManga - AnchorSideTop.Side = asrCenter - Left = 158 - Height = 23 - Hint = 'Update manga list' - Top = 4 - Width = 25 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 20000000000000040000640000006400000000000000000000000000001F0000 - 0084000000E4733100C5733100C5733100C5733100C5733100C5733100C57331 - 00C5582500A00000002200000000000000000000000000000000000000100101 - 01D1606060FFCA9764FFC69360FFC69360FFC69360FFC69360FFC69360FFCA97 - 64FF803A00BE0000002B0000001A000000110000000000000000010101000101 - 01C8646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFFBE8B58FFCA97 - 64FF9C5E28F7733100C5582500A0000000220000000000000000010101000101 - 01C3696969FFCF9C69FFBF8C59FFC69360FFC69360FFC69360FFBF8C59FFCF9C - 69FFAD713AFFCA9764FF803A00BE0000001A0000001A00000011010101000101 - 01BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFBF8C59FFD4A1 - 6EFFB0733BFFCA9764FF9C5E28F7733100C5582500A000000022010101000101 - 01BA737373FFD9A673FFBF8C59FFD09D6AFFD09D6AFFD09D6AFFBF8C59FFD9A6 - 73FFB4783EFFCF9C69FFAD713AFFCA9764FF853D00B623100000010101000101 - 01B5787878FFDEAB78FFBE8B58FFE1AE7BFFE1AE7BFFE1AE7BFFBE8B58FFDEAB - 78FFB87B40FFD4A16EFFB0733BFFCA9764FF8E4200B08E420000010101000101 - 01B27C7C7CFFE2AF7CFFBC8956FFBC8956FFBC8956FFBC8956FFBC8956FFE2AF - 7CFFBB7E42FFD9A673FFB4783EFFCF9C69FF934600AC93460000010101000101 - 01AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B27FFFEAB7 - 84FFBD8043FFDEAB78FFB87B40FFD4A16EFF984900A898490000010101000101 - 01AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFBF8144FFE2AF7CFFBB7E42FFD9A673FF9C4C00A49C4C0000040404000404 - 048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFB - FAFFB4A484FFEAB784FFBD8043FFDEAB78FFA04F00A1A04F0000040404000404 - 04460404048AA16A33EEAA7744FFC28548FFC28548FFC28548FFC28548FFC285 - 48FFC28548FFCC9966FFBF8144FFE2AF7CFFA451009EA4510000040404000404 - 0400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6CBFFE0E0D8FFEAEA - E5FFF3F3F1FFFBFBFAFFB4A484FFEAB784FFA753009CA7530000040404000404 - 040004040400040404460404048AA16A33EEAA7744FFC28548FFC28548FFC285 - 48FFC28548FFC28548FFC28548FFCC9966FFAA55009AAA550000040404000404 - 04000404040004040400040404000404048ABDBDACFFC3C3B4FFCCCCBEFFD6D6 - CBFFE0E0D8FFEAEAE5FFF3F3F1FFFBFBFAFF55552B6655552B00000000000202 - 0200040404000404040004040400040404460404048AAA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550099AA550073AA550000 - } - OnClick = btUpdateListClick - ShowCaption = False - end - object edMangaListSearch: TEdit - AnchorSideLeft.Control = cbSelectManga - AnchorSideTop.Control = cbSelectManga - AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = cbSelectManga - AnchorSideRight.Side = asrBottom - Left = 4 - Height = 23 - Top = 31 - Width = 150 - Anchors = [akTop, akLeft, akRight] - OnChange = edMangaListSearchChange - OnKeyDown = edMangaListSearchKeyDown - TabOrder = 2 - TextHint = 'Search title...' - end - object btMangaListSearchClear: TSpeedButton - AnchorSideLeft.Control = edMangaListSearch - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edMangaListSearch - AnchorSideTop.Side = asrCenter - Left = 158 - Height = 23 - Top = 31 - Width = 25 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 - 00070000000E00000014000000190000001A0000001900000017000000150000 - 00120000000E0000000B00000008000000050000000200000001000000020000 - 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 - 305D0000001C000000160000000F0000000A0000000400000001000000000000 - 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 - 5ACA00224248000D170000000000000000000000000000000000000000000000 - 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 - ABFF003763C600356046002D4E00010101000000000000000000013048000021 - 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA - C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B - 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 - C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B - 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 - CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E - 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA - D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D - 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 - 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 - 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 - D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 - 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 - 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 - 94000162930001619200016293000162930001639400000000240000006788CC - DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 - 940001629300016192000162930001629300016394000000000001334C390165 - 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 - 940001629300016192000162930001629300016394000000000001334C000165 - 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btMangaListSearchClearClick - ShowCaption = False - end - object lbMode: TLabel - AnchorSideLeft.Control = edMangaListSearch - AnchorSideTop.Control = edMangaListSearch - AnchorSideTop.Side = asrBottom - AnchorSideRight.Control = edMangaListSearch - AnchorSideRight.Side = asrBottom - Left = 4 - Height = 15 - Top = 62 - Width = 150 - Anchors = [akTop, akLeft, akRight] - BorderSpacing.Top = 8 - Caption = 'Mode: Show all (0)' - Font.Style = [fsBold] - ParentColor = False - ParentFont = False - end - object btRemoveFilter: TSpeedButton - AnchorSideLeft.Control = lbMode - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = lbMode - AnchorSideTop.Side = asrCenter - Left = 158 - Height = 23 - Top = 58 - Width = 25 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00050000001E000000320000003300000082000000830101014E000000330000 - 003300000022000000080000000000005A000000770000008000000000000000 - 00030000000F000000190000001A00000078D1C2C2FF0303037A0000001A0000 - 001A000000110000000400005A00000077000000770000008000000000000000 - 000000000000000000000202020002020272C4B5B5FF05050578040426000000 - 8499000080CC000080CC000080CC000080CC000080CC00008499000000000000 - 000000000000010101000101010001010174C4B5B5FF0909097E060651000000 - 98CC5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF5E5EF7FF000098CC000000000000 - 00000000000000000000000000000000007AC4B5B5FF0B0B0B87070759000000 - A6990000A7CC0000A7CC0000A7CC0000A7CC0000A7CC0000A699000000000000 - 00000000000000000000000000000000007BC4B5B5FF0B0B0B890D0D0D000000 - A7000000AA000000AA000000AA000000AA000000AA000000A7001B1B1B001616 - 16000404040000000000000000000000007BC4B5B5FF0B0B0B89121212000C0C - 61000000AA000000AA000000AA000000AA000000AA000000A700363636002C2C - 2C000808080000000000000000260000007BC4B5B5FF0B0B0B891717172F2525 - 250027275200101090000000AA000000AA000000AA000000A700363636002C2C - 2C0008080800000000240000006AC7C6C6FFAFA4A4FFC4B2B2FF171717852525 - 252D353535004343430035355F00121291000000AA000000A700363636002C2C - 2C000808082400000066CBCBCBFFC1C0C0FFAEA1A1FFBEACACFFD8C7C7FF2525 - 257E3535352A43434300464646004646460035355F0023237700363636002C2C - 2C2408080866D1D1D1FFC3C3C3FFBBBABAFFAC9E9EFFB8A6A6FFCEBCBCFFDFCD - CDFF3535357743434328464646004646460046464600464646004B4B4B002C2C - 2C66E2E2E2FFCFCFCFFFBDBDBDFFB7B5B5FFAB9C9CFFB4A2A2FFC7B5B5FFDCCA - CAFFEBDADAFF4343436F4E4E4E005151510051515100515151004F4F4F662C2C - 2C66C1C1C1FFB4B4B4FFA9A9A9FF9D9C9CFF918A8AFF978E8EFFA59C9CFFB6AD - ADFFC5BCBCFF4343436F4F4F4F695151510051515100515151004F4F4F66EAEA - EAFFE6E6E6FFDEDEDEFFD5D5D5FFCECACAFFC4B5B5FFC9B8B8FFD6C4C4FFE4D2 - D2FFF0DFDFFFF9E8E8FF4F4F4F695151510051515100515151004F4F4F4D2C2C - 2C6608080866000000660000006A0000007B020202890B0B0B89171717852525 - 257E353535774343436F4F4F4F4F515151005151510051515100FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btRemoveFilterClick - ShowCaption = False - end - end - object tsDownloadFilter: TTabSheet - Caption = '>>' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 4 - ClientHeight = 490 - ClientWidth = 187 - ImageIndex = 4 - object tvDownloadFilter: TTreeView - Left = 4 - Height = 482 - Top = 4 - Width = 179 - Align = alClient - AutoExpand = True - DefaultItemHeight = 18 - Images = IconList - ReadOnly = True - TabOrder = 0 - OnSelectionChanged = tvDownloadFilterSelectionChanged - Options = [tvoAutoExpand, tvoAutoItemHeight, tvoHideSelection, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] - end - end - end object sbMain: TStatusBar Left = 0 Height = 23 @@ -4527,7 +4582,7 @@ object MainForm: TMainForm SimplePanel = False end object spMainSplitter: TSplitter - Left = 199 + Left = 0 Height = 526 Top = 8 Width = 2 diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index f388bb3b8..3ce4a0465 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -13,6 +13,12 @@ {"hash":235571507,"name":"tmainform.tbdownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, {"hash":173363182,"name":"tmainform.eddownloadssearch.texthint","sourcebytes":[83,101,97,114,99,104,32,100,111,119,110,108,111,97,100,115,46,46,46],"value":"Search downloads..."}, {"hash":221371535,"name":"tmainform.tsinformation.caption","sourcebytes":[77,97,110,103,97,32,73,110,102,111],"value":"Manga Info"}, +{"hash":206498996,"name":"tmainform.btabortupdatelist.hint","sourcebytes":[65,98,111,114,116,32,117,112,100,97,116,101,32,108,105,115,116],"value":"Abort update list"}, +{"hash":158194067,"name":"tmainform.cbselectmanga.hint","sourcebytes":[70,111,114,32,109,111,114,101,32,109,97,110,103,97,32,115,105,116,101,115,44,32,112,108,101,97,115,101,32,103,111,32,116,111,32,79,112,116,105,111,110,115,45,62,77,97,110,103,97,32,115,105,116,101,115],"value":"For more manga sites, please go to Options->Manga sites"}, +{"hash":119443044,"name":"tmainform.btupdatelist.hint","sourcebytes":[85,112,100,97,116,101,32,109,97,110,103,97,32,108,105,115,116],"value":"Update manga list"}, +{"hash":138125102,"name":"tmainform.edmangalistsearch.texthint","sourcebytes":[83,101,97,114,99,104,32,116,105,116,108,101,46,46,46],"value":"Search title..."}, +{"hash":150137481,"name":"tmainform.lbmode.caption","sourcebytes":[77,111,100,101,58,32,83,104,111,119,32,97,108,108,32,40,48,41],"value":"Mode: Show all (0)"}, +{"hash":328911,"name":"tmainform.tsinfomanga.caption","sourcebytes":[73,110,102,111],"value":"Info"}, {"hash":60460069,"name":"tmainform.edurl.texthint","sourcebytes":[73,110,112,117,116,32,85,82,76,32,104,101,114,101],"value":"Input URL here"}, {"hash":115683780,"name":"tmainform.btdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100],"value":"Download"}, {"hash":70044827,"name":"tmainform.cbaddasstopped.caption","sourcebytes":[65,100,100,32,116,111,32,100,111,119,110,108,111,97,100,32,108,105,115,116,32,97,115,32,115,116,111,112,112,101,100,32,116,97,115,107],"value":"Add to download list as stopped task"}, @@ -22,7 +28,7 @@ {"hash":80755394,"name":"tmainform.edfiltermangainfochapters.texthint","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, {"hash":160200703,"name":"tmainform.edsaveto.texthint","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":32855652,"name":"tmainform.btdownloadsplit.hint","sourcebytes":[83,112,108,105,116,32,100,111,119,110,108,111,97,100],"value":"Split download"}, -{"hash":80755394,"name":"tmainform.tsfilter.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, +{"hash":80755394,"name":"tmainform.tsinfofilteradv.caption","sourcebytes":[70,105,108,116,101,114],"value":"Filter"}, {"hash":236121459,"name":"tmainform.lbfiltercustomgenres.caption","sourcebytes":[67,117,115,116,111,109,32,71,101,110,114,101,115],"value":"Custom Genres"}, {"hash":58090881,"name":"tmainform.edcustomgenres.texthint","sourcebytes":[73,110,112,117,116,32,99,117,115,116,111,109,32,103,101,110,114,101,115,44,32,115,101,112,97,114,97,116,101,100,32,98,121,32,99,111,109,109,97],"value":"Input custom genres, separated by comma"}, {"hash":255353502,"name":"tmainform.lbfilterhint.hint","sourcebytes":[71,101,110,114,101,115,58,13,10,45,32,67,104,101,99,107,101,100,58,32,73,110,99,108,117,100,101,32,116,104,105,115,32,103,101,110,114,101,46,13,10,45,32,85,110,99,104,101,99,107,101,100,58,32,69,120,99,108,117,100,101,32,116,104,105,115,32,103,101,110,114,101,46,13,10,45,32,71,114,97,121,101,100,58,32,68,111,101,115,110,39,116,32,109,97,116,116,101,114,46,13,10,13,10,67,117,115,116,111,109,32,71,101,110,114,101,115,58,13,10,45,32,83,101,112,97,114,97,116,101,32,109,117,108,116,105,112,108,101,32,103,101,110,114,101,115,32,119,105,116,104,32,39,44,39,46,13,10,45,32,69,120,99,108,117,100,101,32,97,32,103,101,110,114,101,32,98,121,32,112,108,97,99,105,110,103,32,39,33,39,32,111,114,32,39,45,39,32,97,116,32,116,104,101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,97,32,103,101,110,114,101,46,13,10,45,32,69,120,97,109,112,108,101,58,32,65,100,118,101,110,116,117,114,101,44,33,69,99,99,104,105,44,67,111,109,101,100,121,46],"value":"Genres:\r\n- Checked: Include this genre.\r\n- Unchecked: Exclude this genre.\r\n- Grayed: Doesn't matter.\r\n\r\nCustom Genres:\r\n- Separate multiple genres with ','.\r\n- Exclude a genre by placing '!' or '-' at the beginning of a genre.\r\n- Example: Adventure,!Ecchi,Comedy."}, @@ -236,13 +242,6 @@ {"hash":163353879,"name":"tmainform.btvisitmyblog.caption","sourcebytes":[86,105,115,105,116,32,109,121,32,98,108,111,103],"value":"Visit my blog"}, {"hash":113643140,"name":"tmainform.tsabouttext.caption","sourcebytes":[65,98,111,117,116,32,70,77,68],"value":"About FMD"}, {"hash":139332791,"name":"tmainform.tschangelogtext.caption","sourcebytes":[67,104,97,110,103,101,108,111,103],"value":"Changelog"}, -{"hash":221391076,"name":"tmainform.tsmangalist.caption","sourcebytes":[77,97,110,103,97,32,76,105,115,116],"value":"Manga List"}, -{"hash":206498996,"name":"tmainform.btabortupdatelist.hint","sourcebytes":[65,98,111,114,116,32,117,112,100,97,116,101,32,108,105,115,116],"value":"Abort update list"}, -{"hash":158194067,"name":"tmainform.cbselectmanga.hint","sourcebytes":[70,111,114,32,109,111,114,101,32,109,97,110,103,97,32,115,105,116,101,115,44,32,112,108,101,97,115,101,32,103,111,32,116,111,32,79,112,116,105,111,110,115,45,62,77,97,110,103,97,32,115,105,116,101,115],"value":"For more manga sites, please go to Options->Manga sites"}, -{"hash":119443044,"name":"tmainform.btupdatelist.hint","sourcebytes":[85,112,100,97,116,101,32,109,97,110,103,97,32,108,105,115,116],"value":"Update manga list"}, -{"hash":138125102,"name":"tmainform.edmangalistsearch.texthint","sourcebytes":[83,101,97,114,99,104,32,116,105,116,108,101,46,46,46],"value":"Search title..."}, -{"hash":150137481,"name":"tmainform.lbmode.caption","sourcebytes":[77,111,100,101,58,32,83,104,111,119,32,97,108,108,32,40,48,41],"value":"Mode: Show all (0)"}, -{"hash":1054,"name":"tmainform.tsdownloadfilter.caption","sourcebytes":[62,62],"value":">>"}, {"hash":371552,"name":"tmainform.midownloadstop.caption","sourcebytes":[83,116,111,112],"value":"Stop"}, {"hash":93105205,"name":"tmainform.midownloadresume.caption","sourcebytes":[82,101,115,117,109,101],"value":"Resume"}, {"hash":79984933,"name":"tmainform.midownloadenable.caption","sourcebytes":[69,110,97,98,108,101],"value":"Enable"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 632016724..0afb460f4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -16,15 +16,16 @@ interface {$else} FakeActiveX, {$endif} - Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, - ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, - types, LCLIntf, DefaultTranslator, EditBtn, MultiLog, FileChannel, FileUtil, - LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, - uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, - uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, - frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, CheckUpdate, accountmanagerdb, - DBDataProcess, MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, - SimpleException; + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, + ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, + simpleipc, lclproc, types, LCLIntf, DefaultTranslator, EditBtn, PairSplitter, + MultiLog, FileChannel, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, + TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, + uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, + frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, + frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, CheckUpdate, + accountmanagerdb, DBDataProcess, MangaFoxWatermark, SimpleTranslator, + FMDOptions, httpsendthread, SimpleException; type @@ -114,6 +115,13 @@ TMainForm = class(TForm) miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; + pcInfo: TPageControl; + psInfo: TPairSplitter; + pssInfoList: TPairSplitterSide; + pssInfo: TPairSplitterSide; + psDownloads: TPairSplitter; + pssDownloadsFilter: TPairSplitterSide; + pssDownloads: TPairSplitterSide; pcMisc: TPageControl; pcWebsiteOptions: TPageControl; Panel1: TPanel; @@ -127,6 +135,8 @@ TMainForm = class(TForm) sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; btDownloadSplit: TSpeedButton; + tsInfoManga: TTabSheet; + tsinfoFilterAdv: TTabSheet; tsCustomColor: TTabSheet; tsLog: TTabSheet; tmAnimateMangaInfo: TTimer; @@ -314,10 +324,9 @@ TMainForm = class(TForm) miDownloadResume: TMenuItem; miDownloadDelete: TMenuItem; miChapterListUncheckAll: TMenuItem; - pcLeft: TPageControl; pbWait: TPaintBox; pmChapterList: TPopupMenu; - pnOptions: TPageControl; + pcOptions: TPageControl; pnChapterList: TPanel; pnFilter: TPanel; pnGenres: TPanel; @@ -363,8 +372,6 @@ TMainForm = class(TForm) tbSeparator1: TToolButton; tbDownloadDeleteCompleted: TToolButton; tvDownloadFilter: TTreeView; - tsDownloadFilter: TTabSheet; - tsMangaList: TTabSheet; tsMisc: TTabSheet; tsUpdate: TTabSheet; tsAbout: TTabSheet; @@ -376,7 +383,6 @@ TMainForm = class(TForm) tsSaveTo: TTabSheet; tsConnections: TTabSheet; tsOption: TTabSheet; - tsFilter: TTabSheet; tsInformation: TTabSheet; tsDownload: TTabSheet; clbChapterList: TVirtualStringTree; @@ -1018,7 +1024,7 @@ procedure TOpenDBThread.SyncOpenStart; begin with MainForm do begin - ChangeAllCursor(tsMangaList, crHourGlass); + ChangeAllCursor(pssInfoList, crHourGlass); SetControlEnabled(False); lbMode.Caption := RS_Loading; vtMangaList.Clear; @@ -1039,7 +1045,7 @@ procedure TOpenDBThread.SyncOpenFinish; vtMangaList.BeginUpdate; vtMangaList.RootNodeCount := dataProcess.RecordCount; vtMangaList.EndUpdate; - ChangeAllCursor(tsMangaList, crDefault); + ChangeAllCursor(pssInfoList, crDefault); end; end; @@ -5289,8 +5295,8 @@ procedure TMainForm.LoadFormInformation; begin with configfile do begin - pcLeft.Width := ReadInteger('form', 'MainSplitter', 195); - sbMain.Panels[0].Width := pcLeft.Width + 4; + psDownloads.Position := ReadInteger('form', 'DownloadsSplitter', psDownloads.Position); + psInfo.Position := ReadInteger('form', 'MangaInfoSplitter', psInfo.Position); if cbOptionAutoCheckFavStartup.Checked and cbOptionAutoOpenFavStartup.Checked then pcMain.ActivePage := tsFavorites @@ -5336,7 +5342,8 @@ procedure TMainForm.SaveFormInformation; begin with configfile do begin - WriteInteger('form', 'MainSplitter', pcLeft.Width); + WriteInteger('form', 'DownloadsSplitter', psDownloads.Position); + WriteInteger('form', 'MangaInfoSplitter', psInfo.Position); WriteInteger('form', 'pcMainPageIndex', pcMain.PageIndex); WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); WriteBool('form', 'MainFormMaximized', (WindowState = wsMaximized)); diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 67db3ae84..04f73d9cb 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1844,24 +1844,24 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Λήψεις" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr ">>" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "Αγαπημένα" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" -msgid "Filter" -msgstr "Φίλτρο" - #: tmainform.tsgeneral.caption msgid "General" msgstr "Γενικές" +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Φίλτρο" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "" + #: tmainform.tsinformation.caption msgid "Manga Info" msgstr "Πληροφορίες manga" @@ -1870,10 +1870,6 @@ msgstr "Πληροφορίες manga" msgid "Log" msgstr "Αρχείο καταγραφής" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "Λίστα Manga" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "Διάφορα" @@ -2276,4 +2272,3 @@ msgstr "Συγχρονισμός δεδομένων" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Ενημέρωση λίστας" - diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 184a8cece..55a53471b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1796,24 +1796,24 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Downloads" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr ">>" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "Favorites" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" -msgid "Filter" -msgstr "Filter" - #: tmainform.tsgeneral.caption msgid "General" msgstr "General" +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Filter" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "Info" + #: tmainform.tsinformation.caption msgid "Manga Info" msgstr "Manga Info" @@ -1822,10 +1822,6 @@ msgstr "Manga Info" msgid "Log" msgstr "Log" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "Manga List" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "Misc" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 7d3fd400a..a3ee936d3 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -581,7 +581,7 @@ msgstr "Visitar mi blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" +msgstr "" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -1772,24 +1772,24 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Descargas" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr ">>" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "Favoritos" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" -msgid "Filter" -msgstr "Filtro" - #: tmainform.tsgeneral.caption msgid "General" msgstr "General" +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Filtro" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "" + #: tmainform.tsinformation.caption msgid "Manga Info" msgstr "Información del Manga" @@ -1798,10 +1798,6 @@ msgstr "Información del Manga" msgid "Log" msgstr "Registro" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "Lista de Manga" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "Misceláneo" @@ -2204,4 +2200,3 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" - diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index d7b2062f4..30f502733 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -586,7 +586,7 @@ msgstr "Kunjungi blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "Free Manga Downloader" +msgstr "" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -1777,24 +1777,24 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Unduhan" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr ">>" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "Kesukaan" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" -msgid "Filter" -msgstr "Saring" - #: tmainform.tsgeneral.caption msgid "General" msgstr "Umum" +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Saring" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "Info" + #: tmainform.tsinformation.caption msgid "Manga Info" msgstr "Informasi Komik" @@ -1803,10 +1803,6 @@ msgstr "Informasi Komik" msgid "Log" msgstr "Log" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "Daftar Komik" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "Lain-lain" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index ec52fd0d0..1357eae75 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1793,24 +1793,24 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "Pobrane" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr ">>" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "Ulubione" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" -msgid "Filter" -msgstr "Filtr" - #: tmainform.tsgeneral.caption msgid "General" msgstr "Główne" +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Filtr" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "" + #: tmainform.tsinformation.caption msgid "Manga Info" msgstr "Informacje o mandze" @@ -1819,10 +1819,6 @@ msgstr "Informacje o mandze" msgid "Log" msgstr "Log" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "Lista Mang" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "Różne" @@ -2225,4 +2221,3 @@ msgstr "Synchronizacja danych" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Aktualizacja listy" - diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index aa8c2193d..64d4776d0 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1703,22 +1703,22 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr "" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr "" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "" + +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" msgid "Filter" msgstr "" -#: tmainform.tsgeneral.caption -msgid "General" +#: tmainform.tsinfomanga.caption +msgid "Info" msgstr "" #: tmainform.tsinformation.caption @@ -1729,10 +1729,6 @@ msgstr "" msgid "Log" msgstr "" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index bc6bbf874..bc3cd6b48 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1791,24 +1791,24 @@ msgctxt "tmainform.tsdownload.caption" msgid "Downloads" msgstr ">>" -#: tmainform.tsdownloadfilter.caption -msgid ">>" -msgstr ">>" - #: tmainform.tsfavorites.caption msgctxt "tmainform.tsfavorites.caption" msgid "Favorites" msgstr "Favoritos" -#: tmainform.tsfilter.caption -msgctxt "tmainform.tsfilter.caption" -msgid "Filter" -msgstr "Filtros" - #: tmainform.tsgeneral.caption msgid "General" msgstr "Geral" +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Filtros" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "" + #: tmainform.tsinformation.caption msgid "Manga Info" msgstr "Info do Mangá" @@ -1817,10 +1817,6 @@ msgstr "Info do Mangá" msgid "Log" msgstr "Registro" -#: tmainform.tsmangalist.caption -msgid "Manga List" -msgstr "Lista de Mangás" - #: tmainform.tsmisc.caption msgid "Misc" msgstr "Misc" @@ -2223,4 +2219,3 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" - From 62624ac794430bf12afef349a88746408fc92b7d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Jun 2017 19:32:12 +0800 Subject: [PATCH 1759/2794] fixed status bar anchor --- mangadownloader/forms/frmMain.lfm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 3e5e91d87..c3265d987 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -16,9 +16,10 @@ object MainForm: TMainForm ShowHint = True LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar + AnchorSideBottom.Control = sbMain Left = 0 Height = 30 - Top = 557 + Top = 534 Width = 771 AutoSize = False Panels = < @@ -4569,7 +4570,7 @@ object MainForm: TMainForm object sbMain: TStatusBar Left = 0 Height = 23 - Top = 534 + Top = 564 Width = 771 Panels = < item From 6c99d6fdc145f6aa1be8b6c283de86940d4779ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Jun 2017 19:38:45 +0800 Subject: [PATCH 1760/2794] Bump version 0.9.113.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 6 +++++- update | 10 +++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 83042e9f7..7738a23ce 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.113.0 (08-07-2017) +[*] Pururin: fixed all +[*] Layout changes +Full changes: https://github.com/riderkick/FMD/compare/0.9.112.0...0.9.113.0 + 0.9.112.0 (29-05-2017) [*] HitomiLa: fixed download [*] MangaGo: fixed download diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 38bc51a76..c9510441a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -9,6 +9,10 @@ <Title Value="Free Manga Downloader"/> <ResourceType Value="res"/> <UseXPManifest Value="True"/> + <XPManifest> + <TextName Value="fmd.free"/> + <TextDesc Value="Free Manga Downloader"/> + </XPManifest> <Icon Value="0"/> </General> <i18n> @@ -18,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="112"/> + <RevisionNr Value="113"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 07d4d2493..d6bd47bb4 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.112.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.112.0/fmd_0.9.112.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.112.0/fmd_0.9.112.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.112.0/fmd_0.9.112.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.112.0/fmd_0.9.112.0_Win64.7z +VERSION=0.9.113.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.113.0/fmd_0.9.113.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.113.0/fmd_0.9.113.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.113.0/fmd_0.9.113.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.113.0/fmd_0.9.113.0_Win64.7z From d9ed0ffce4bbf72df289c09620ff99e769edca39 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Jun 2017 13:58:43 +0800 Subject: [PATCH 1761/2794] fixed downloads toolbar layout fixed #609 --- mangadownloader/forms/frmMain.lfm | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index c3265d987..3087fc190 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -174,21 +174,26 @@ object MainForm: TMainForm AnchorSideLeft.Control = edDownloadsSearch AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edDownloadsSearch - AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = vtDownload + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = edDownloadsSearch + AnchorSideBottom.Side = asrBottom Left = 154 - Height = 24 - Top = -1 - Width = 457 + Height = 25 + Top = 0 + Width = 402 Anchors = [akTop, akLeft, akRight] BevelOuter = bvNone - ClientHeight = 24 - ClientWidth = 457 + ClientHeight = 25 + ClientWidth = 402 TabOrder = 1 object TransferRateGraph: TChart + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Side = asrBottom Left = 321 - Height = 24 + Height = 25 Top = 0 - Width = 136 + Width = 81 AllowZoom = False AxisList = < item @@ -214,7 +219,7 @@ object MainForm: TMainForm Legend.Frame.Visible = False Legend.MarginX = 0 Legend.MarginY = 0 - Legend.Spacing = 0 + Legend.Spacing = 2 Legend.SymbolWidth = 0 Legend.UseSidebar = False Legend.Visible = True @@ -244,21 +249,20 @@ object MainForm: TMainForm end object pnDownloadToolbarLeft: TPanel Left = 0 - Height = 24 + Height = 25 Top = 0 Width = 321 Align = alLeft AutoSize = True BevelOuter = bvNone - ClientHeight = 24 + ClientHeight = 25 ClientWidth = 321 TabOrder = 1 object ToolBarDownload: TToolBar Left = 0 - Height = 24 + Height = 25 Top = 0 Width = 321 - Align = alClient AutoSize = True ButtonHeight = 25 ButtonWidth = 23 From eb9b963ce3370ef240eaf97729d76516b6d167c9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Jun 2017 23:28:24 +0800 Subject: [PATCH 1762/2794] eatmanga, rewrite all fixed #610 --- baseunits/ModuleList.inc | 1 + .../includes/EatManga/chapter_page_number.inc | 43 ------- baseunits/includes/EatManga/image_url.inc | 36 ------ .../includes/EatManga/manga_information.inc | 110 ------------------ .../includes/EatManga/names_and_links.inc | 38 ------ baseunits/modules/EatManga.pas | 91 +++++++++++++++ baseunits/uBaseUnit.pas | 91 +++++++-------- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 10 -- 9 files changed, 135 insertions(+), 295 deletions(-) delete mode 100644 baseunits/includes/EatManga/chapter_page_number.inc delete mode 100644 baseunits/includes/EatManga/image_url.inc delete mode 100644 baseunits/includes/EatManga/manga_information.inc delete mode 100644 baseunits/includes/EatManga/names_and_links.inc create mode 100644 baseunits/modules/EatManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index fcb38e204..352e14403 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -52,6 +52,7 @@ uses ReadMangaToday, MangaOnlineBR, Tapas, + EatManga, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/EatManga/chapter_page_number.inc b/baseunits/includes/EatManga/chapter_page_number.inc deleted file mode 100644 index 8f7129c5d..000000000 --- a/baseunits/includes/EatManga/chapter_page_number.inc +++ /dev/null @@ -1,43 +0,0 @@ - function GetEatMangaPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - try - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL)), - Task.Container.manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'id') = 'pages') then - isGetPageNumber := True; - if isGetPageNumber then - begin - if GetTagName(parse[i]) = '/select' then - Break - else if GetTagName(parse[i]) = 'option' then - Inc(Task.Container.PageNumber); - end; - end; - end; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/EatManga/image_url.inc b/baseunits/includes/EatManga/image_url.inc deleted file mode 100644 index f5a54ed91..000000000 --- a/baseunits/includes/EatManga/image_url.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetEatMangaImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(EATMANGA_ID, URL) + 'page-' + IntToStr(WorkId + 1)), - Task.Container.Manager.retryConnect); - - parse := TStringList.Create; - try - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = 'eatmanga_image') then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/EatManga/manga_information.inc b/baseunits/includes/EatManga/manga_information.inc deleted file mode 100644 index eb4ecf948..000000000 --- a/baseunits/includes/EatManga/manga_information.inc +++ /dev/null @@ -1,110 +0,0 @@ - function GetEatMangaInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[EATMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(EATMANGA_ID, AURL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse[i]) = 'img') and - (Pos('border="0" align="center"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); - - // get summary - if (Pos(' manga about ?', parse[i]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - end; - - // get title - if (Pos(', Read ', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft(StringFilter(GetString(parse[i], - ', Read ', ' English Scan Online'))); - - // get chapter name and links - if (Pos('<th class="title">', parse[i]) > 0) and - (Pos('/upcoming/', parse[i + 1]) = 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse[i + 1], 'href="', '"'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 2]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Author:', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Artist:', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse[i + 4]); - - // get genres - if (Pos('Genre:', parse[i]) <> 0) then - begin - mangaInfo.genres := ''; - s := parse[i + 4]; - if s[1] <> '<' then - mangaInfo.genres := s; - end; - - // get status - if (i + 4 < parse.Count) and (Pos('Chapters:', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/EatManga/names_and_links.inc b/baseunits/includes/EatManga/names_and_links.inc deleted file mode 100644 index 31f7f4275..000000000 --- a/baseunits/includes/EatManga/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function EatMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[EATMANGA_ID, 1] + - EATMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos(' Online">', parse[i]) > 0) and - (Pos('<th>', parse[i - 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - ANames.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i], 'href="'); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/modules/EatManga.pas b/baseunits/modules/EatManga.pas new file mode 100644 index 000000000..db9d03f0a --- /dev/null +++ b/baseunits/modules/EatManga.pas @@ -0,0 +1,91 @@ +unit EatManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/Manga-Scan/') then + begin + Result := NO_ERROR; + XPathHREFAll('//li[@class="item-dr"]/div[1]/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + XPathHREFAll('//ul[@id="updates"]/li[not(./div[2]/span[starts-with(.,"in ")])]/div[1]/a', Document, chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + a, c: String; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + PageNumber := XPathCount('//select[@id="pages"]/option', Document); + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if GET(AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)) + 'page-' + IncStr(DownloadThread.WorkId)) then + begin + Result := True; + PageLinks[DownloadThread.WorkId] := XPathString('//img[contains(@id,"eatmanga_image")]/@src', Document); + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'EatManga'; + RootURL := 'http://eatmanga.me'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index df8b1a8d1..9ecd2aab3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -238,50 +238,49 @@ interface TRUYEN18_ID = 5; TRUYENTRANHTUAN_ID = 6; TURKCRAFT_ID = 7; - EATMANGA_ID = 8; - STARKANA_ID = 9; - BLOGTRUYEN_ID = 10; - ESMANGAHERE_ID = 11; - ANIMEEXTREMIST_ID = 12; - S2SCAN_ID = 13; - IMANHUA_ID = 14; - CENTRALDEMANGAS_ID = 15; - EGSCANS_ID = 16; - MANGAAR_ID = 17; - MANGAAE_ID = 18; - ANIMESTORY_ID = 19; - LECTUREENLIGNE_ID = 20; - SCANMANGA_ID = 21; - DM5_ID = 22; - KIVMANGA_ID = 23; - MEINMANGA_ID = 24; - MANGASPROJECT_ID = 25; - MANGAREADER_POR_ID = 26; - NINEMANGA_ID = 27; - NINEMANGA_ES_ID = 28; - NINEMANGA_CN_ID = 29; - NINEMANGA_RU_ID = 30; - NINEMANGA_DE_ID = 31; - NINEMANGA_IT_ID = 32; - NINEMANGA_BR_ID = 33; - JAPANSHIN_ID = 34; - CENTRUMMANGI_PL_ID = 35; - MANGALIB_PL_ID = 36; - ONEMANGA_ID = 37; - MANGATOWN_ID = 38; - MANGAOKU_ID = 39; - MYREADINGMANGAINFO_ID = 40; - IKOMIK_ID = 41; - NHENTAI_ID = 42; - MANGAMINT_ID = 43; - UNIXMANGA_ID = 44; - EXTREMEMANGAS_ID = 45; - MANGAHOST_ID = 46; - MANGAKU_ID = 47; - MANGAAT_ID = 48; - DYNASTYSCANS_ID = 49; - - WebsiteRoots: array [0..49] of array [0..1] of String = ( + STARKANA_ID = 8; + BLOGTRUYEN_ID = 9; + ESMANGAHERE_ID = 10; + ANIMEEXTREMIST_ID = 11; + S2SCAN_ID = 12; + IMANHUA_ID = 13; + CENTRALDEMANGAS_ID = 14; + EGSCANS_ID = 15; + MANGAAR_ID = 16; + MANGAAE_ID = 17; + ANIMESTORY_ID = 18; + LECTUREENLIGNE_ID = 19; + SCANMANGA_ID = 20; + DM5_ID = 21; + KIVMANGA_ID = 22; + MEINMANGA_ID = 23; + MANGASPROJECT_ID = 24; + MANGAREADER_POR_ID = 25; + NINEMANGA_ID = 26; + NINEMANGA_ES_ID = 27; + NINEMANGA_CN_ID = 28; + NINEMANGA_RU_ID = 29; + NINEMANGA_DE_ID = 30; + NINEMANGA_IT_ID = 31; + NINEMANGA_BR_ID = 32; + JAPANSHIN_ID = 33; + CENTRUMMANGI_PL_ID = 34; + MANGALIB_PL_ID = 35; + ONEMANGA_ID = 36; + MANGATOWN_ID = 37; + MANGAOKU_ID = 38; + MYREADINGMANGAINFO_ID = 39; + IKOMIK_ID = 40; + NHENTAI_ID = 41; + MANGAMINT_ID = 42; + UNIXMANGA_ID = 43; + EXTREMEMANGAS_ID = 44; + MANGAHOST_ID = 45; + MANGAKU_ID = 46; + MANGAAT_ID = 47; + DYNASTYSCANS_ID = 48; + + WebsiteRoots: array [0..48] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -290,7 +289,6 @@ interface ('Truyen18', 'http://www.truyen18.org'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), - ('EatManga', 'http://eatmanga.com'), ('Starkana', 'http://starkana.jp'), ('BlogTruyen', 'http://blogtruyen.com'), ('ESMangaHere', 'http://es.mangahere.co'), @@ -353,9 +351,6 @@ interface TURKCRAFT_BROWSER = '/'; - EATMANGA_BROWSER = '/Manga-Scan/'; - EATMANGA_maxDLTask: Cardinal = 1; - STARKANA_BROWSER = '/manga/list'; BLOGTRUYEN_BROWSER = '/danhsach/tatca'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 363ca732b..be07b1399 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -957,8 +957,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/Starkana/names_and_links.inc} - {$I includes/EatManga/names_and_links.inc} - {$I includes/S2Scans/names_and_links.inc} {$I includes/EGScans/names_and_links.inc} @@ -1034,9 +1032,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = STARKANA_ID then Result := StarkanaGetNamesAndLinks else - if MangaSiteID = EATMANGA_ID then - Result := EatMangaGetNamesAndLinks - else if MangaSiteID = S2SCAN_ID then Result := S2ScanGetNamesAndLinks else @@ -1185,8 +1180,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/Starkana/manga_information.inc} - {$I includes/EatManga/manga_information.inc} - {$I includes/S2Scans/manga_information.inc} {$I includes/EGScans/manga_information.inc} @@ -1292,9 +1285,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = STARKANA_ID then Result := GetStarkanaInfoFromURL else - if MangaSiteID = EATMANGA_ID then - Result := GetEatMangaInfoFromURL - else if MangaSiteID = S2SCAN_ID then Result := GetS2scanInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index fdf0a1e22..a0dfb0028 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -409,8 +409,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/chapter_page_number.inc} - {$I includes/EatManga/chapter_page_number.inc} - {$I includes/EGScans/chapter_page_number.inc} {$I includes/EsMangaHere/chapter_page_number.inc} @@ -481,9 +479,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaPageNumber else - if Task.Container.MangaSiteID = EATMANGA_ID then - Result := GetEatMangaPageNumber - else if Task.Container.MangaSiteID = S2SCAN_ID then Result := GetS2scanPageNumber else @@ -584,8 +579,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/CentralDeMangas/image_url.inc} - {$I includes/EatManga/image_url.inc} - {$I includes/EGScans/image_url.inc} {$I includes/EsMangaHere/image_url.inc} @@ -666,9 +659,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaImageURL else - if Task.Container.MangaSiteID = EATMANGA_ID then - Result := GetEatMangaImageURL - else if Task.Container.MangaSiteID = EGSCANS_ID then Result := GetEGScansImageURL else From 37315e3c81300208a9c16fe9e52a2135e3616fc1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Jun 2017 23:38:43 +0800 Subject: [PATCH 1763/2794] Bump version 0.9.114.0 --- changelog.txt | 7 ++++++- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7738a23ce..4e119f12f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.113.0 (08-07-2017) +0.9.114.0 (10-06-2017) +[*] EatManga: fixed all +[*] Fixed layout +Full changes: https://github.com/riderkick/FMD/compare/0.9.113.0...0.9.114.0 + +0.9.113.0 (08-06-2017) [*] Pururin: fixed all [*] Layout changes Full changes: https://github.com/riderkick/FMD/compare/0.9.112.0...0.9.113.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c9510441a..b1b16231c 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="113"/> + <RevisionNr Value="114"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index d6bd47bb4..df216d36d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.113.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.113.0/fmd_0.9.113.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.113.0/fmd_0.9.113.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.113.0/fmd_0.9.113.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.113.0/fmd_0.9.113.0_Win64.7z +VERSION=0.9.114.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.114.0/fmd_0.9.114.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.114.0/fmd_0.9.114.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.114.0/fmd_0.9.114.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.114.0/fmd_0.9.114.0_Win64.7z From 28037c5f4d898824a9c3289583e36497d6314ca8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 14:28:48 +0800 Subject: [PATCH 1764/2794] eatmanga, fixed title and cleanup --- baseunits/modules/EatManga.pas | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/EatManga.pas b/baseunits/modules/EatManga.pas index db9d03f0a..5aae56fac 100644 --- a/baseunits/modules/EatManga.pas +++ b/baseunits/modules/EatManga.pas @@ -32,17 +32,19 @@ function GetInfo(const MangaInfo: TMangaInformation; url := MaybeFillHost(Module.RootURL, AURL); if GET(url) then begin Result := NO_ERROR; - XPathHREFAll('//ul[@id="updates"]/li[not(./div[2]/span[starts-with(.,"in ")])]/div[1]/a', Document, chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); + with TXQueryEngineHTML.Create(Document) do try + if title = '' then title := XPathString('//title/substring-before(.," Manga Releases - Read ")'); + XPathHREFAll('//ul[@id="updates"]/li[not(./div[2]/span[starts-with(.,"in ")])]/div[1]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - a, c: String; - v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; From 4107b1dd3268eb29d95f29ea17ec105e5780466d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 14:29:52 +0800 Subject: [PATCH 1765/2794] added taadd --- baseunits/ModuleList.inc | 1 + baseunits/modules/Taadd.pas | 102 ++++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Taadd.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 352e14403..fe79d14ed 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -53,6 +53,7 @@ uses MangaOnlineBR, Tapas, EatManga, + Taadd, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/Taadd.pas b/baseunits/modules/Taadd.pas new file mode 100644 index 000000000..ff584352d --- /dev/null +++ b/baseunits/modules/Taadd.pas @@ -0,0 +1,102 @@ +unit Taadd; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/list/New-Book/') then + begin + Result := NO_ERROR; + XPathHREFtitleAll('//*[@class="clistChr"]/ul/li/div/h2/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + s := url; + if Pos('waring=1', s) = 0 then s += '?waring=1'; + if GET(s) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//table//td/a/img/@src'); + if title = '' then title := XPathString('//title/substring-before(.," - Read ")'); + authors := XPathString('//table//table//td[starts-with(.,"Author:")]/string-join(./a,", ")'); + genres := XPathString('//table//table//td[starts-with(.,"Categories:")]/string-join(./a,", ")'); + status := MangaInfoStatusIfPos(XPathString('//table//table//td[starts-with(.,"Status:")]/a'),'Updated','Completed'); + summary := XPathString('//table//table//td[contains(.," Manga Summary ")]/substring-after(.,"Manga Summary ")'); + XPathHREFAll('//*[@class="chapter_list"]/table//tr/td[1]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + PageNumber := StrToIntDef(XPathString('//select[@id="page"]/count(./option)', Document),0); + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if GET(AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)) + 'page-' + IncStr(DownloadThread.WorkId)) then + begin + Result := True; + PageLinks[DownloadThread.WorkId] := XPathString('//img[@id="comicpic"]/@src', Document); + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Taadd'; + RootURL := 'http://www.taadd.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index aa4e8ed76..d1a1341c3 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineManga_IT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 8c8062bb87e015acad0798231de515d62c6031a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 15:35:25 +0800 Subject: [PATCH 1766/2794] updatethread, added property currentdirectorypagenumber to update for ucertain max number --- baseunits/uUpdateThread.pas | 43 ++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e2ca539ae..6f739be69 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -43,6 +43,9 @@ TUpdateListManagerThread = class(TBaseThread) FThreadAborted, FThreadEndNormally, FIsPreListAvailable: Boolean; + FCurrentGetInfoLimit: Integer; + FCS_CurrentGetInfoLimit: TRTLCriticalSection; + procedure SetCurrentDirectoryPageNumber(AValue: Integer); protected procedure Execute; override; {$IFNDEF DOWNLOADER} @@ -76,6 +79,7 @@ TUpdateListManagerThread = class(TBaseThread) constructor Create; destructor Destroy; override; procedure CheckCommit(const CommitCount: Integer = 32); + property CurrentDirectoryPageNumber: Integer read FCurrentGetInfoLimit write SetCurrentDirectoryPageNumber; end; resourcestring @@ -331,6 +335,7 @@ constructor TUpdateListManagerThread.Create; InitCriticalSection(CS_Threads); InitCriticalSection(CS_AddInfoToData); InitCriticalSection(CS_AddNamesAndLinks); + InitCriticalSection(FCS_CurrentGetInfoLimit); FreeOnTerminate := True; websites := TStringList.Create; @@ -360,6 +365,7 @@ destructor TUpdateListManagerThread.Destroy; tempDataProcess.Free; Threads.Free; MainForm.isUpdating := False; + DoneCriticalsection(FCS_CurrentGetInfoLimit); DoneCriticalsection(CS_AddInfoToData); DoneCriticalsection(CS_AddNamesAndLinks); DoneCriticalsection(CS_Threads); @@ -430,9 +436,11 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; mt, i: Integer; s: String; begin - MainForm.ulTotalPtr := limit; try - while (not Terminated) and (workPtr < limit) do begin + FCurrentGetInfoLimit := limit; + while (not Terminated) and (workPtr < FCurrentGetInfoLimit) do begin + if MainForm.ulTotalPtr <> FCurrentGetInfoLimit then + MainForm.ulTotalPtr := FCurrentGetInfoLimit; mt := advancedfile.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then begin @@ -457,7 +465,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; (isFinishSearchingForNewManga) then begin WaitForThreads; - workPtr := limit; + workPtr := FCurrentGetInfoLimit; Exit; end; @@ -485,12 +493,12 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; TUpdateListThread(Threads[i]).Start; Inc(workPtr); s := RS_UpdatingList + Format(' [%d/%d] %s | [T:%d] [%d/%d]', - [websitePtr, websites.Count, website, Threads.Count, workPtr, limit]); + [websitePtr, websites.Count, website, Threads.Count, workPtr, FCurrentGetInfoLimit]); case cs of CS_DIRECTORY_COUNT: begin - if limit = 1 then + if FCurrentGetInfoLimit = 1 then s := RS_UpdatingList + Format(' [%d/%d] ', [websitePtr, websites.Count]) + website + ' | ' + RS_GettingDirectory + '...' else @@ -541,6 +549,17 @@ procedure TUpdateListManagerThread.DoTerminate; inherited DoTerminate; end; +procedure TUpdateListManagerThread.SetCurrentDirectoryPageNumber(AValue: Integer); +begin + if FCurrentGetInfoLimit = AValue then Exit; + try + EnterCriticalsection(FCS_CurrentGetInfoLimit); + FCurrentGetInfoLimit := AValue; + finally + LeaveCriticalsection(FCS_CurrentGetInfoLimit); + end; +end; + procedure TUpdateListManagerThread.Execute; var j, k: Integer; @@ -614,12 +633,16 @@ procedure TUpdateListManagerThread.Execute; if ModuleId <> -1 then begin with Modules.Module[ModuleId] do - for j := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do begin - workPtr := 0; - isFinishSearchingForNewManga := False; - CurrentDirectoryIndex := j; - GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); + j := Low(TotalDirectoryPage); + while j < High(TotalDirectoryPage) do + begin + workPtr := 0; + isFinishSearchingForNewManga := False; + CurrentDirectoryIndex := j; + GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); + Inc(j); + end; end; end else From 3c954d95de19745bbd5a4da75cfe5ae74dfb583e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 15:45:34 +0800 Subject: [PATCH 1767/2794] moved all global variable to fmdvars unit --- baseunits/CheckUpdate.pas | 6 +- baseunits/FMDVars.pas | 64 ++++++++++++++++++++ baseunits/modules/Taadd.pas | 1 + baseunits/uBaseUnit.pas | 3 +- baseunits/uDownloadsManager.pas | 4 +- baseunits/uFavoritesManager.pas | 6 +- baseunits/uGetMangaInfosThread.pas | 44 ++++++-------- baseunits/uSilentThread.pas | 4 +- baseunits/uUpdateDBThread.pas | 10 +-- baseunits/uUpdateThread.pas | 22 +++---- mangadownloader/forms/frmImportFavorites.pas | 6 +- mangadownloader/forms/frmMain.pas | 55 +++++------------ mangadownloader/md.lpr | 5 +- 13 files changed, 135 insertions(+), 95 deletions(-) create mode 100644 baseunits/FMDVars.pas diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 189086fd4..80b64c5a1 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -38,7 +38,7 @@ TCheckUpdateThread = class(TBaseThread) implementation uses - frmMain, frmUpdateDialog; + frmMain, frmUpdateDialog, FMDVars; { TCheckUpdateThread } @@ -61,7 +61,7 @@ procedure TCheckUpdateThread.MainThreadUpdate; end; if ShowModal = mrYes then begin - frmMain.FUpdateURL := fUpdateURL; + FUpdateURL := fUpdateURL; DoAfterFMD := DO_UPDATE; MainForm.tmExitCommand.Enabled := True; end @@ -137,7 +137,7 @@ constructor TCheckUpdateThread.Create; destructor TCheckUpdateThread.Destroy; begin FHTTP.Free; - MainForm.CheckUpdateThread := nil; + CheckUpdateThread := nil; inherited Destroy; end; diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas new file mode 100644 index 000000000..5a239c2e8 --- /dev/null +++ b/baseunits/FMDVars.pas @@ -0,0 +1,64 @@ +unit FMDVars; + +{$mode objfpc}{$H+} + +interface + +uses + frmMain, uDownloadsManager, uFavoritesManager, uUpdateThread, DBDataProcess, + uUpdateDBThread, uSilentThread, uBaseUnit, uGetMangaInfosThread, CheckUpdate, + FMDOptions, FileChannel, simpleipc; + +var + FormMain: TMainForm; + + isStartup, + isRunDownloadFilter, + isUpdating, + isPendingExitCounter, + isNormalExit: Boolean; + + //Instance + FMDInstance: TSimpleIPCServer; + + // update fmd through main thread + DoAfterFMD: TFMDDo; + IsDlgCounter: Boolean = False; + FUpdateURL: String; + + // file logger + FileLogger: TFileChannel; + + // status in status bar update + ulTotalPtr, + ulWorkPtr: Integer; + + // download manager + DLManager: TDownloadManager; + + // favorite manager + FavoriteManager: TFavoriteManager; + + // main dataprocess for manga list + dataProcess: TDBDataProcess; + + // update manga list thread manager + updateList: TUpdateListManagerThread; + + // updateDB thread + updateDB: TUpdateDBThread; + + // silent thread for download all or add to favorite + SilentThreadManager: TSilentThreadManager; + + // get manga info + mangaInfo: TMangaInfo; + GetInfosThread: TGetMangaInfosThread; + + // check update thread + CheckUpdateThread: TCheckUpdateThread; + +implementation + +end. + diff --git a/baseunits/modules/Taadd.pas b/baseunits/modules/Taadd.pas index ff584352d..3ba8463ef 100644 --- a/baseunits/modules/Taadd.pas +++ b/baseunits/modules/Taadd.pas @@ -93,6 +93,7 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; + TotalDirectory := Length(ALPHA_LIST_UP); end; end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9ecd2aab3..795b85f62 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -332,7 +332,8 @@ interface ('Dynasty-Scans', 'http://dynasty-scans.com') ); - ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; + ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; + ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; ANIMEA_BROWSER = '/browse.html?page='; ANIMEA_SKIP = '?skip=1'; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a0dfb0028..7ab2036e7 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -276,7 +276,7 @@ TDownloadManager = class implementation uses - frmMain, WebsiteModules; + frmMain, WebsiteModules, FMDVars; function IntToStr(Value: Cardinal): String; begin @@ -1817,7 +1817,7 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); MainForm.tmRefreshDownloadsInfo.Enabled := False; MainForm.UpdateVtDownload; if isCheckForFMDDo and (OptionLetFMDDo <> DO_NOTHING) then begin - frmMain.DoAfterFMD := OptionLetFMDDo; + DoAfterFMD := OptionLetFMDDo; MainForm.DoExitWaitCounter; end; end; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index c06f7afd0..c6ed6d830 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -162,7 +162,7 @@ TFavoriteManager = class implementation uses - frmMain, frmNewChapter; + frmMain, frmNewChapter, FMDVars; { TFavoriteContainer } @@ -648,8 +648,8 @@ procedure TFavoriteManager.ShowResult; newdl: LongInt; begin if isDlgCounter then Exit; - if (Self.DLManager = nil) and Assigned(MainForm.DLManager) then - Self.DLManager := MainForm.DLManager; + if (Self.DLManager = nil) and Assigned(DLManager) then + Self.DLManager := DLManager; if Self.DLManager = nil then Exit; EnterCriticalsection(CS_Favorites); diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index fb96b740f..c7fe8e9d2 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -16,7 +16,7 @@ interface uses - SysUtils, Graphics, Dialogs, uBaseUnit, uData, httpsendthread, FMDOptions, + SysUtils, Graphics, Dialogs, uBaseUnit, uData, FMDOptions, BaseThread; type @@ -50,12 +50,12 @@ TGetMangaInfosThread = class(TBaseThread) implementation uses - frmMain, WebsiteModules; + frmMain, WebsiteModules, FMDVars; procedure TGetMangaInfosThread.MainThreadSyncInfos; begin - FInfo.SyncInfoToData(MainForm.DataProcess); - MainForm.dataProcess.Commit; + FInfo.SyncInfoToData(DataProcess); + dataProcess.Commit; end; procedure TGetMangaInfosThread.Execute; @@ -76,15 +76,15 @@ procedure TGetMangaInfosThread.Execute; begin filterPos := FMangaListPos; if FInfo.mangaInfo.title = '' then - FInfo.mangaInfo.title := MainForm.dataProcess.Value[filterPos, DATA_PARAM_TITLE]; - FInfo.mangaInfo.link := MainForm.dataProcess.Value[filterPos, DATA_PARAM_LINK]; - FInfo.mangaInfo.authors := MainForm.dataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; - FInfo.mangaInfo.artists := MainForm.dataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; - FInfo.mangaInfo.status := MainForm.dataProcess.Value[filterPos, DATA_PARAM_STATUS]; - FInfo.mangaInfo.summary := MainForm.dataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; - FInfo.mangaInfo.numChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); - FInfo.mangaInfo.genres := MainForm.dataProcess.Value[filterPos, DATA_PARAM_GENRES]; - FNumChapter := StrToIntDef(MainForm.dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); + FInfo.mangaInfo.title := dataProcess.Value[filterPos, DATA_PARAM_TITLE]; + FInfo.mangaInfo.link := dataProcess.Value[filterPos, DATA_PARAM_LINK]; + FInfo.mangaInfo.authors := dataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; + FInfo.mangaInfo.artists := dataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; + FInfo.mangaInfo.status := dataProcess.Value[filterPos, DATA_PARAM_STATUS]; + FInfo.mangaInfo.summary := dataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; + FInfo.mangaInfo.numChapter := StrToIntDef(dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); + FInfo.mangaInfo.genres := dataProcess.Value[filterPos, DATA_PARAM_GENRES]; + FNumChapter := StrToIntDef(dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); end; FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolder; FInfo.isRemoveUnicode := OptionChangeUnicodeCharacter; @@ -110,22 +110,18 @@ procedure TGetMangaInfosThread.Execute; if FMangaListPos >= 0 then begin - if MainForm.dataProcess.WebsiteLoaded(Website) then + if dataProcess.WebsiteLoaded(Website) then begin if SitesWithoutInformation(website) then begin if FInfo.mangaInfo.authors = '' then - FInfo.mangaInfo.authors := - MainForm.DataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; + FInfo.mangaInfo.authors := DataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; if FInfo.mangaInfo.artists = '' then - FInfo.mangaInfo.artists := - MainForm.DataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; + FInfo.mangaInfo.artists := DataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; if FInfo.mangaInfo.genres = '' then - FInfo.mangaInfo.genres := - MainForm.DataProcess.Value[filterPos, DATA_PARAM_GENRES]; + FInfo.mangaInfo.genres := DataProcess.Value[filterPos, DATA_PARAM_GENRES]; if FInfo.mangaInfo.summary = '' then - FInfo.mangaInfo.summary := - MainForm.DataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; + FInfo.mangaInfo.summary := DataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; end; if not (Terminated or isExiting) then @@ -183,7 +179,7 @@ procedure TGetMangaInfosThread.MainThreadShowCannotGetInfo; procedure TGetMangaInfosThread.MainThreadShowInfos; begin - TransferMangaInfo(MainForm.mangaInfo, FInfo.mangaInfo); + TransferMangaInfo(mangaInfo, FInfo.mangaInfo); with MainForm do begin if (FMangaListPos > -1) and dataProcess.WebsiteLoaded(Website) then begin @@ -222,7 +218,7 @@ constructor TGetMangaInfosThread.Create; destructor TGetMangaInfosThread.Destroy; begin Modules.DecActiveConnectionCount(FInfo.ModuleId); - MainForm.GetInfosThread := nil; + GetInfosThread := nil; FCover := nil; FInfo.Free; inherited Destroy; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index e99638954..16fa92d11 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -105,7 +105,7 @@ TSilentThreadManager = class implementation uses - frmMain; + frmMain, FMDVars; { TSilentThreadManagerThread } @@ -171,7 +171,7 @@ procedure TSilentThreadManager.Add(AType: TMetaDataType; AWebsite, AManga, AURL: String; ASavePath: String = ''); begin if not ((AType = MD_AddToFavorites) and - (MainForm.FavoriteManager.IsMangaExist(AManga, AWebsite))) then + (FavoriteManager.IsMangaExist(AManga, AWebsite))) then begin EnterCriticalsection(FCS_META); try diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas index 2e67bb744..1daa19ff8 100644 --- a/baseunits/uUpdateDBThread.pas +++ b/baseunits/uUpdateDBThread.pas @@ -36,7 +36,7 @@ TUpdateDBThread = class(TThread) implementation uses - frmMain, Dialogs, ComCtrls; + frmMain, FMDVars, Dialogs, ComCtrls; procedure TUpdateDBThread.MainThreadRefreshList; begin @@ -45,14 +45,14 @@ procedure TUpdateDBThread.MainThreadRefreshList; begin MainForm.edMangaListSearch.Clear; MainForm.vtMangaList.Clear; - MainForm.dataProcess.Close; + dataProcess.Close; ExtractFile; MainForm.OpenDataDB(websiteName); end else begin - if MainForm.dataProcess.WebsiteLoaded(websiteName) then - MainForm.dataProcess.RemoveFilter; + if dataProcess.WebsiteLoaded(websiteName) then + dataProcess.RemoveFilter; ExtractFile; end; except @@ -121,7 +121,7 @@ procedure TUpdateDBThread.MainThreadShowEndGetting; MainForm.sbUpdateList.Panels[0].Text := ''; MainForm.sbUpdateList.Hide; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; - MainForm.isUpdating := False; + isUpdating := False; end; procedure TUpdateDBThread.MainThreadCannotConnectToServer; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 6f739be69..8ff63e864 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -101,7 +101,7 @@ TUpdateListManagerThread = class(TBaseThread) implementation uses - frmMain, Dialogs, ComCtrls; + frmMain, FMDVars, Dialogs, ComCtrls; { TUpdateListThread } @@ -292,8 +292,8 @@ procedure TUpdateListManagerThread.MainThreadEndGetting; mainForm.sbUpdateList.Panels[0].Style := psText; MainForm.sbUpdateList.Hide; MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; - MainForm.isUpdating:=False; - if MainForm.isPendingExitCounter then + isUpdating:=False; + if isPendingExitCounter then MainForm.DoExitWaitCounter; end; @@ -364,7 +364,7 @@ destructor TUpdateListManagerThread.Destroy; mainDataProcess.Free; tempDataProcess.Free; Threads.Free; - MainForm.isUpdating := False; + isUpdating := False; DoneCriticalsection(FCS_CurrentGetInfoLimit); DoneCriticalsection(CS_AddInfoToData); DoneCriticalsection(CS_AddNamesAndLinks); @@ -439,8 +439,8 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; try FCurrentGetInfoLimit := limit; while (not Terminated) and (workPtr < FCurrentGetInfoLimit) do begin - if MainForm.ulTotalPtr <> FCurrentGetInfoLimit then - MainForm.ulTotalPtr := FCurrentGetInfoLimit; + if ulTotalPtr <> FCurrentGetInfoLimit then + ulTotalPtr := FCurrentGetInfoLimit; mt := advancedfile.ReadInteger('UpdateListNumberOfThreads', website, -1); if mt > 0 then begin @@ -518,7 +518,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; s := Format('%s | %s "%s"', [s, RS_GettingInfo, tempDataProcess.Value[workPtr-1,DATA_PARAM_TITLE]]); end; FStatus := s; - MainForm.ulWorkPtr := workPtr + 1; + ulWorkPtr := workPtr + 1; Synchronize(MainThreadShowGetting); finally LeaveCriticalsection(CS_Threads); @@ -602,12 +602,12 @@ procedure TUpdateListManagerThread.Execute; try DeleteDBDataProcess(twebsite); DeleteDBDataProcess(twebsitetemp); - if (MainForm.dataProcess.Website = website) and - (MainForm.dataProcess.Connected) then - MainForm.dataProcess.Backup(twebsite) + if (dataProcess.Website = website) and + (dataProcess.Connected) then + dataProcess.Backup(twebsite) else begin - if MainForm.dataProcess.WebsiteLoaded(website) then + if dataProcess.WebsiteLoaded(website) then Synchronize(MainThreadRemoveFilter); CopyDBDataProcess(website, twebsite); end; diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index 585e19475..e5474ad36 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -43,7 +43,7 @@ TImportFavorites = class(TForm) implementation uses - frmMain, uSilentThread; + frmMain, uSilentThread, FMDVars; {$R *.lfm} @@ -111,7 +111,7 @@ procedure TImportFavorites.DMDHandle; if webs <> '' then begin - MainForm.SilentThreadManager.Add( + SilentThreadManager.Add( MD_AddToFavorites, webs, mangaList[i], @@ -151,7 +151,7 @@ procedure TImportFavorites.DMDHandle; procedure TImportFavorites.FMDHandle; begin - MainForm.FavoriteManager.MergeWith(CleanAndExpandDirectory(edPath.Text) + 'works/favorites.ini'); + FavoriteManager.MergeWith(CleanAndExpandDirectory(edPath.Text) + 'works/favorites.ini'); MessageDlg('', RS_ImportCompleted, mtConfirmation, [mbYes], 0) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0afb460f4..b2a0e6d74 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -630,29 +630,16 @@ TMainForm = class(TForm) procedure FMDInstanceReceiveMsg(Sender: TObject); procedure ClearChapterListState; public - ulTotalPtr, ulWorkPtr: Integer; optionMangaSiteSelectionNodes: array of PVirtualNode; LastSearchStr, LastSearchWeb: String; - isStartup, isRunDownloadFilter, isUpdating, isPendingExitCounter, - isNormalExit: Boolean; - FavoriteManager: TFavoriteManager; - dataProcess: TDBDataProcess; - mangaInfo: TMangaInfo; + + // state of chapterlist in mangainfo ChapterList: array of TChapterStateItem; - DLManager: TDownloadManager; - updateDB: TUpdateDBThread; - updateList: TUpdateListManagerThread; - SilentThreadManager: TSilentThreadManager; + // animation gif gifWaiting: TAnimatedGif; gifWaitingRect: TRect; - // get manga info - GetInfosThread: TGetMangaInfosThread; - - // check update - CheckUpdateThread: TCheckUpdateThread; - // generate >> nodes procedure GeneratetvDownloadFilterNodes; @@ -781,19 +768,8 @@ TSearchDBThread = class(TThread) procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); var - //Instance - FMDInstance: TSimpleIPCServer; - MainForm: TMainForm; - // update fmd through main thread - DoAfterFMD: TFMDDo; - IsDlgCounter: Boolean = False; - FUpdateURL: String; - - // file logger - FileLogger: TFileChannel; - const CL_HLBlueMarks = $FDC594; CL_HLGreenMarks = $B8FFB8; @@ -889,8 +865,8 @@ implementation {$R *.lfm} uses - frmImportFavorites, frmShutdownCounter, WebsiteModules, RegExpr, Clipbrd, - LazFileUtils, LazUTF8; + frmImportFavorites, frmShutdownCounter, WebsiteModules, FMDVars, RegExpr, + Clipbrd, LazFileUtils, LazUTF8; var // thread for open db @@ -970,13 +946,13 @@ procedure TSearchDBThread.SyncAfterSearch; procedure TSearchDBThread.Execute; begin - if MainForm.dataProcess <> nil then + if dataProcess <> nil then begin Synchronize(@SyncBeforeSearch); while FNewSearch do begin FNewSearch := False; - MainForm.dataProcess.Search(FSearchStr); + dataProcess.Search(FSearchStr); end; if not Terminated then Synchronize(@SyncAfterSearch); @@ -1051,14 +1027,14 @@ procedure TOpenDBThread.SyncOpenFinish; procedure TOpenDBThread.Execute; begin - if (FWebsite <> '') and (MainForm.dataProcess <> nil) then + if (FWebsite <> '') and (dataProcess <> nil) then begin Synchronize(@SyncOpenStart); - if MainForm.dataProcess <> nil then + if dataProcess <> nil then begin - MainForm.dataProcess.Open(FWebsite); - if MainForm.edMangaListSearch.Text <> '' then - MainForm.dataProcess.Search(MainForm.edMangaListSearch.Text); + dataProcess.Open(FWebsite); + if FormMain.edMangaListSearch.Text <> '' then + dataProcess.Search(MainForm.edMangaListSearch.Text); end; if not Terminated then Synchronize(@SyncOpenFinish); @@ -1083,6 +1059,7 @@ destructor TOpenDBThread.Destroy; procedure TMainForm.FormCreate(Sender: TObject); begin Randomize; + FormMain := Self; {$ifdef windows} PrevWndProc := windows.WNDPROC(windows.GetWindowLongPtr(Self.Handle, GWL_WNDPROC)); windows.SetWindowLongPtr(Self.Handle, GWL_WNDPROC, PtrInt(@WndCallback)); @@ -1126,7 +1103,7 @@ procedure TMainForm.FormCreate(Sender: TObject); // favorites FavoriteManager := TFavoriteManager.Create; - FavoriteManager.DLManager := Self.DLManager; + FavoriteManager.DLManager := DLManager; FavoriteManager.OnUpdateFavorite := @UpdateVtFavorites; FavoriteManager.OnUpdateDownload := @UpdateVtDownload; @@ -1669,8 +1646,8 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); btCheckLatestVersionClick(btCheckLatestVersion); if OptionAutoCheckFavStartup then begin - MainForm.FavoriteManager.isAuto := True; - MainForm.FavoriteManager.CheckForNewChapter; + FavoriteManager.isAuto := True; + FavoriteManager.CheckForNewChapter; end; DLManager.CheckAndActiveTaskAtStartup; end; diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 8299143f8..fc54c1528 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -10,7 +10,8 @@ {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, - SimpleException, Classes, windows, sysutils, frmMain, MultiLog, FileChannel; + FMDVars, SimpleException, Classes, windows, sysutils, frmMain, MultiLog, + FileChannel; var CheckInstance: Boolean = True; @@ -66,7 +67,7 @@ if EnableLogging then begin Logger.Enabled := True; - frmMain.FileLogger := TFileChannel.Create(LogFileName, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); + FileLogger := TFileChannel.Create(LogFileName, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); Logger.Channels.Add(FileLogger); Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); s := TStringList.Create; From 158df0fea5cda7725d04f192cb5bef1276bd6901 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 17:20:43 +0800 Subject: [PATCH 1768/2794] tadd, fixed update list with uncertain last directory page --- baseunits/modules/Taadd.pas | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/Taadd.pas b/baseunits/modules/Taadd.pas index 3ba8463ef..34ba7eb58 100644 --- a/baseunits/modules/Taadd.pas +++ b/baseunits/modules/Taadd.pas @@ -10,15 +10,35 @@ interface implementation +uses FMDVars; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; +var + s: String; + v: IXQValue; + i, x: Integer; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/list/New-Book/') then + if Module.CurrentDirectoryIndex = 0 then + s := '0-9' + else + s := ALPHA_LIST_UP[Module.CurrentDirectoryIndex + 1]; + if MangaInfo.FHTTP.GET(Module.RootURL + '/category/' + s + '_views_'+ IncStr(AURL) + '.html') then begin Result := NO_ERROR; - XPathHREFtitleAll('//*[@class="clistChr"]/ul/li/div/h2/a', MangaInfo.FHTTP.Document, ALinks, ANames); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try + i := 1; + for v in XPath('//*[@class="clistChr"]//span[@class="pagetor"]//text()') do begin + x := StrToIntDef(v.toString, 1); + if x > i then i := x; + end; + updateList.CurrentDirectoryPageNumber := i; + XPathHREFtitleAll('//*[@class="clistChr"]/ul/li/div/h2/a', ALinks, ANames); + finally + Free; + end; end; end; From a7b1fceb7b117e524caeeef29df3865b79b4a780 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 17:21:23 +0800 Subject: [PATCH 1769/2794] updatethread, fixed getinfo with new limit --- baseunits/uUpdateThread.pas | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 8ff63e864..e2e0914f7 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -433,12 +433,13 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end; var - mt, i: Integer; + mt, i, plimit: Integer; s: String; begin try FCurrentGetInfoLimit := limit; - while (not Terminated) and (workPtr < FCurrentGetInfoLimit) do begin + while workPtr < FCurrentGetInfoLimit do begin + if Terminated then Break; if ulTotalPtr <> FCurrentGetInfoLimit then ulTotalPtr := FCurrentGetInfoLimit; mt := advancedfile.ReadInteger('UpdateListNumberOfThreads', website, -1); @@ -476,7 +477,8 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; while (not Terminated) and (Threads.Count >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE); - if (not Terminated) and (Threads.Count < numberOfThreads) then + if Terminated then Break; + if Threads.Count < numberOfThreads then begin EnterCriticalsection(CS_Threads); try @@ -524,6 +526,18 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; LeaveCriticalsection(CS_Threads); end; end; + // wait for threads and new data + if workPtr >= FCurrentGetInfoLimit then + begin + plimit := FCurrentGetInfoLimit; + while Threads.Count > 0 do + begin + if Terminated then Break; + // if limit changed, break and continue the loop with new limit + if FCurrentGetInfoLimit <> plimit then Break; + Sleep(SOCKHEARTBEATRATE); + end; + end; end; except on E: Exception do @@ -635,7 +649,7 @@ procedure TUpdateListManagerThread.Execute; with Modules.Module[ModuleId] do begin j := Low(TotalDirectoryPage); - while j < High(TotalDirectoryPage) do + while j <= High(TotalDirectoryPage) do begin workPtr := 0; isFinishSearchingForNewManga := False; From d3e102baa39ebd5f5176cf69c64807dbe6717413 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 17:28:29 +0800 Subject: [PATCH 1770/2794] yomanga, removed due to website is down closed #563 --- baseunits/modules/FoOlSlide.pas | 29 +---------------------------- config/mangalist.ini | 4 ++-- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 301e8150d..8fa92a2e4 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -10,9 +10,6 @@ interface implementation -var - yomangacf: TCFProps; - const dirurl = '/directory/'; dirurlreader = '/reader/directory/'; @@ -25,9 +22,6 @@ implementation function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - if Module.Website = 'YoManga' then - Result := Cloudflare.GETCF(AHTTP, AURL, yomangacf) - else if ((Module.Website = 'SeinagiAdultoFansub') or (Module.Website = 'TripleSevenScan')) and (Pos(dirurl, AURL) = 0)then @@ -38,8 +32,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; function GetDirURL(const AWebsite: String): String; begin - if (AWebsite = 'YoManga') or - (AWebsite = 'GoManga') or + if (AWebsite = 'GoManga') or (AWebsite = 'Jaiminisbox') or (AWebsite = 'TripleSevenScan') then Result := dirurlreader @@ -226,15 +219,6 @@ function GetImageURL(const DownloadThread: TDownloadThread; end; end; -function DownloadImageWithCookie(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - if GETWithCookie(DownloadThread.FHTTP, AURL, Module) then - SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName); -end; - procedure RegisterModule; function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; @@ -256,13 +240,6 @@ procedure RegisterModule; AddWebsiteModule('PowerManga', 'http://read.powermanga.org'); AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); - with AddWebsiteModule('YoManga', 'http://yomanga.co') do - begin - MaxTaskLimit := 1; - MaxConnectionLimit := 4; - OnDownloadImage := @DownloadImageWithCookie; - end; - AddWebsiteModule('RawYoManga', 'http://raws.yomanga.co'); AddWebsiteModule('GoManga', 'http://gomanga.co'); AddWebsiteModule('OneTimeScans', 'http://otscans.com'); AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); @@ -288,10 +265,6 @@ procedure RegisterModule; end; initialization - yomangacf := TCFProps.Create; RegisterModule; -finalization - yomangacf.Free; - end. diff --git a/config/mangalist.ini b/config/mangalist.ini index d1a1341c3..e0e8cff7e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,14 +6,14 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineManga_IT -English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,YoManga,Jaiminisbox,PowerManga,KireiCake +English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineManga_DE Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineManga_BR,UnionMangas -Raw=MangaMint,RawSenManga,RawYoManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType +Raw=MangaMint,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineManga_ES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub From 1ec7a80c8787fee6710f69ae61aceaa43e2e3c35 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 17:48:29 +0800 Subject: [PATCH 1771/2794] removed fakku, not free anymore. cleanup old codes --- .../includes/Fakku/directory_page_number.inc | 37 ------ baseunits/includes/Fakku/image_url.inc | 64 --------- .../includes/Fakku/manga_information.inc | 101 -------------- baseunits/includes/Fakku/names_and_links.inc | 48 ------- baseunits/uBaseUnit.pas | 123 +++++++----------- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 5 - baseunits/uUpdateThread.pas | 55 +------- config/mangalist.ini | 2 +- 9 files changed, 58 insertions(+), 392 deletions(-) delete mode 100644 baseunits/includes/Fakku/directory_page_number.inc delete mode 100644 baseunits/includes/Fakku/image_url.inc delete mode 100644 baseunits/includes/Fakku/manga_information.inc delete mode 100644 baseunits/includes/Fakku/names_and_links.inc diff --git a/baseunits/includes/Fakku/directory_page_number.inc b/baseunits/includes/Fakku/directory_page_number.inc deleted file mode 100644 index 6f30a509f..000000000 --- a/baseunits/includes/Fakku/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetFakkuDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'a') and - (GetVal(parse[i], 'title') = - 'Last Page') then - begin - s := TrimRight(TrimLeft(GetString(parse[i], '/page/', '"'))); - APage := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Fakku/image_url.inc b/baseunits/includes/Fakku/image_url.inc deleted file mode 100644 index d2043ffa9..000000000 --- a/baseunits/includes/Fakku/image_url.inc +++ /dev/null @@ -1,64 +0,0 @@ - function GetFakkuImageURL: Boolean; - var - i, totalPages: Cardinal; - l: TStringList; - imgURL, imgExt, s: String; - - begin - totalPages := 0; - Task.Container.PageLinks.Clear; - l := TStringList.Create; - s := FillMangaSiteHost(FAKKU_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - - if l.Count > 0 then - begin - //Get total pages - for i := 0 to l.Count - 1 do - begin - if (Pos('window.params.thumbs = ', l[i]) > 0) then - begin - s := GetString(l[i], '= [', '];'); - with TStringList.Create do - try - DelimitedText := s; - totalPages := Count; - finally - Free; - end; - Break; - end; - end; - - if totalPages = 0 then - Result := False; - - //Get imgurl - for i := 0 to l.Count - 1 do - begin - if (Pos('return ''', l[i]) > 0) then - begin - imgURL := GetString(l[i], 'return ''', ''' +'); - imgExt := GetString(l[i], 'x + ''', ''';'); - Break; - end; - end; - - //Build image links - if imgExt = '' then - imgExt := '.jpg'; - - if imgURL <> '' then - begin - imgURL := TrimLeftChar(imgURL, ['/', '\', ':']); - for i := 1 to totalPages do - begin - s := IntToStr(i); - while Length(s) < 3 do - s := '0' + s; - Task.Container.PageLinks.Add(imgURL + s + imgExt); - end; - end; - end; - l.Free; - end; diff --git a/baseunits/includes/Fakku/manga_information.inc b/baseunits/includes/Fakku/manga_information.inc deleted file mode 100644 index 3839da21a..000000000 --- a/baseunits/includes/Fakku/manga_information.inc +++ /dev/null @@ -1,101 +0,0 @@ - function GetFakkuInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = False; - i: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(FAKKU_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[FAKKU_ID, 0]; - if parse.Count = 0 then - Exit; - - mangaInfo.status := '0'; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - for i := 0 to parse.Count - 1 do - begin - // get manga title - if GetVal(parse[i], 'property') = 'og:title' then - mangaInfo.title := CommonStringFilter(GetVal(parse[i], 'content')); - - // get cover - if (Pos('<img ', parse[i]) > 0) and (Pos('class="cover"', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'src'); - if ExecRegExpr('^//', s) then - mangaInfo.coverLink := 'https:' + s - else - mangaInfo.coverLink := s - end; - - // get read/chapter - if GetVal(parse[i], 'class') = 'button green' then - begin - Inc(mangaInfo.numChapter); - if mangaInfo.title = '' then - mangaInfo.title := 'Unknown'; - mangaInfo.chapterName.Add(mangaInfo.title); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - end; - - // get series/authors - if (Pos('div class="left"', parse[i]) > 0) and - (Pos('Series', parse[i + 1]) > 0) then - begin - mangaInfo.authors := parse[i + 6]; - mangaInfo.genres := mangaInfo.authors; - end; - - // get artists - if (Pos('div class="left"', parse[i]) > 0) and - (Pos('Artist', parse[i + 1]) > 0) then - begin - mangaInfo.artists := parse[i + 6]; - mangaInfo.genres := mangaInfo.genres + ', ' + mangaInfo.artists; - end; - - // get language - if (Pos('div class="left"', parse[i]) > 0) and - (Pos('Language', parse[i + 1]) > 0) then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 7]); - - // get descriptions - if (Pos('div class="left"', parse[i]) > 0) and - (Pos('Description', parse[i + 1]) > 0) then - isExtractSummary := True; - - if isExtractSummary then - begin - if (Pos('</div>', parse[i + 5]) > 0) then - isExtractSummary := False - else if (not (Pos('<', parse[i + 5]) > 0)) then - mangaInfo.summary := Trim(mangaInfo.summary) + ' ' + Trim(parse[i + 5]); - end; - - // get genres - if (Pos('"/tags/', parse[i]) > 0) then - begin - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - end; - end; - - //last correction - mangaInfo.summary := BreaksString(StringFilter(mangaInfo.summary)); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Fakku/names_and_links.inc b/baseunits/includes/Fakku/names_and_links.inc deleted file mode 100644 index 582fb222e..000000000 --- a/baseunits/includes/Fakku/names_and_links.inc +++ /dev/null @@ -1,48 +0,0 @@ - function FakkuGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - i := StrToInt(AURL); - if i = 0 then - begin - if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + FAKKU_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - end - else - begin - if not GetPage(TObject(Source), WebsiteRoots[FAKKU_ID, 1] + - FAKKU_BROWSER + '/page/' + IntToStr(i + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="content-title"', parse[i]) > 0 then - begin - Result := NO_ERROR; - ANames.Add(Trim(GetVal(parse[i], 'title'))); - ALinks.Add(StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[FAKKU_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 795b85f62..eaf9bec47 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -234,58 +234,56 @@ interface OURMANGA_ID = 1; MANGA24H_ID = 2; VNSHARING_ID = 3; - FAKKU_ID = 4; - TRUYEN18_ID = 5; - TRUYENTRANHTUAN_ID = 6; - TURKCRAFT_ID = 7; - STARKANA_ID = 8; - BLOGTRUYEN_ID = 9; - ESMANGAHERE_ID = 10; - ANIMEEXTREMIST_ID = 11; - S2SCAN_ID = 12; - IMANHUA_ID = 13; - CENTRALDEMANGAS_ID = 14; - EGSCANS_ID = 15; - MANGAAR_ID = 16; - MANGAAE_ID = 17; - ANIMESTORY_ID = 18; - LECTUREENLIGNE_ID = 19; - SCANMANGA_ID = 20; - DM5_ID = 21; - KIVMANGA_ID = 22; - MEINMANGA_ID = 23; - MANGASPROJECT_ID = 24; - MANGAREADER_POR_ID = 25; - NINEMANGA_ID = 26; - NINEMANGA_ES_ID = 27; - NINEMANGA_CN_ID = 28; - NINEMANGA_RU_ID = 29; - NINEMANGA_DE_ID = 30; - NINEMANGA_IT_ID = 31; - NINEMANGA_BR_ID = 32; - JAPANSHIN_ID = 33; - CENTRUMMANGI_PL_ID = 34; - MANGALIB_PL_ID = 35; - ONEMANGA_ID = 36; - MANGATOWN_ID = 37; - MANGAOKU_ID = 38; - MYREADINGMANGAINFO_ID = 39; - IKOMIK_ID = 40; - NHENTAI_ID = 41; - MANGAMINT_ID = 42; - UNIXMANGA_ID = 43; - EXTREMEMANGAS_ID = 44; - MANGAHOST_ID = 45; - MANGAKU_ID = 46; - MANGAAT_ID = 47; - DYNASTYSCANS_ID = 48; - - WebsiteRoots: array [0..48] of array [0..1] of String = ( + TRUYEN18_ID = 4; + TRUYENTRANHTUAN_ID = 5; + TURKCRAFT_ID = 6; + STARKANA_ID = 7; + BLOGTRUYEN_ID = 8; + ESMANGAHERE_ID = 9; + ANIMEEXTREMIST_ID = 10; + S2SCAN_ID = 11; + IMANHUA_ID = 12; + CENTRALDEMANGAS_ID = 13; + EGSCANS_ID = 14; + MANGAAR_ID = 15; + MANGAAE_ID = 16; + ANIMESTORY_ID = 17; + LECTUREENLIGNE_ID = 18; + SCANMANGA_ID = 19; + DM5_ID = 20; + KIVMANGA_ID = 21; + MEINMANGA_ID = 22; + MANGASPROJECT_ID = 23; + MANGAREADER_POR_ID = 24; + NINEMANGA_ID = 25; + NINEMANGA_ES_ID = 26; + NINEMANGA_CN_ID = 27; + NINEMANGA_RU_ID = 28; + NINEMANGA_DE_ID = 29; + NINEMANGA_IT_ID = 30; + NINEMANGA_BR_ID = 31; + JAPANSHIN_ID = 32; + CENTRUMMANGI_PL_ID = 33; + MANGALIB_PL_ID = 34; + ONEMANGA_ID = 35; + MANGATOWN_ID = 36; + MANGAOKU_ID = 37; + MYREADINGMANGAINFO_ID = 38; + IKOMIK_ID = 39; + NHENTAI_ID = 40; + MANGAMINT_ID = 41; + UNIXMANGA_ID = 42; + EXTREMEMANGAS_ID = 43; + MANGAHOST_ID = 44; + MANGAKU_ID = 45; + MANGAAT_ID = 46; + DYNASTYSCANS_ID = 47; + + WebsiteRoots: array [0..47] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), - ('Fakku', 'https://www.fakku.net'), ('Truyen18', 'http://www.truyen18.org'), ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), @@ -342,9 +340,6 @@ interface VNSHARING_BROWSER = '/DanhSach'; - FAKKU_BROWSER_1 = '/manga/newest'; - FAKKU_BROWSER_2 = '/doujinshi/newest'; - TRUYEN18_ROOT = 'http://www.truyen18.org'; TRUYEN18_BROWSER = '/moi-dang/danhsach'; @@ -450,8 +445,6 @@ interface // Sites var BROWSER_INVERT: Boolean = False; - FAKKU_BROWSER: String = '/manga/newest'; - MANGALIB_PL_COOKIES: String; //------------------------------------------ @@ -464,8 +457,7 @@ interface type TArrayOfString = array of String; - TCheckStyleType = (CS_DIRECTORY_COUNT, CS_DIRECTORY_PAGE, - CS_DIRECTORY_PAGE_2, CS_INFO); + TCheckStyleType = (CS_DIRECTORY_COUNT, CS_DIRECTORY_PAGE, CS_INFO); TFlagType = (CS_GETPAGENUMBER, CS_GETPAGELINK, CS_DOWNLOAD); TFavoriteStatusType = (STATUS_IDLE, STATUS_CHECK, STATUS_CHECKING, STATUS_CHECKED); @@ -1139,7 +1131,6 @@ function SitesWithSortedList(const website: String): Boolean; Exit; end; Result := SitesMemberOf(website, [ - FAKKU_ID, NINEMANGA_ID, NINEMANGA_ES_ID, NINEMANGA_CN_ID, @@ -1164,7 +1155,6 @@ function SitesWithoutFavorites(const website: String): Boolean; Exit; end; Result := SitesMemberOf(website, [ - FAKKU_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID ]); @@ -1202,7 +1192,6 @@ function SitesWithSingleChapter(const website: String): Boolean; begin Result := False; Result := SitesMemberOf(website, [ - FAKKU_ID, MYREADINGMANGAINFO_ID, NHENTAI_ID ]); @@ -2219,15 +2208,7 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh // numbering/index if (Pos(CR_NUMBERING, Result) = 0) and (Pos(CR_CHAPTER, Result) = 0) then Result := ANumbering + Result; - if AWebsite = WebsiteRoots[FAKKU_ID, 0] then - begin - if Pos('%NUMBERING% - ', Result) > 0 then - Result := StringReplaceBrackets(Result, CR_NUMBERING + ' - ', '', [rfReplaceAll]) - else - Result := StringReplaceBrackets(Result, CR_NUMBERING, '', [rfReplaceAll]); - end - else - Result := StringReplaceBrackets(Result, CR_NUMBERING, ANumbering, [rfReplaceAll]); + Result := StringReplaceBrackets(Result, CR_NUMBERING, ANumbering, [rfReplaceAll]); // pad number fchapter := Trim(AChapter); @@ -2246,12 +2227,8 @@ function CustomRename(const AString, AWebsite, AMangaName, AAuthor, AArtist, ACh Result := StringReplaceBrackets(Result, CR_CHAPTER, fchapter, [rfReplaceAll]); - if Result = '' then begin - if AWebsite = WebsiteRoots[FAKKU_ID, 0] then - Result := fchapter - else - Result := ANumbering; - end; + if Result = '' then + Result := ANumbering; end; Result := StringReplaceBrackets(Result, CR_WEBSITE, FixStringLocal(AWebsite), [rfReplaceAll]); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index be07b1399..5411b178f 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -776,8 +776,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/VnSharing/directory_page_number.inc} - {$I includes/Fakku/directory_page_number.inc} - {$I includes/BlogTruyen/directory_page_number.inc} {$I includes/S2Scans/directory_page_number.inc} @@ -846,9 +844,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if MangaSiteID = FAKKU_ID then - Result := GetFakkuDirectoryPageNumber - else if MangaSiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenDirectoryPageNumber else @@ -935,8 +930,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/VnSharing/names_and_links.inc} - {$I includes/Fakku/names_and_links.inc} - {$I includes/TruyenTranhTuan/names_and_links.inc} {$I includes/AnimeStory/names_and_links.inc} @@ -1026,9 +1019,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else - if MangaSiteID = FAKKU_ID then - Result := FakkuGetNamesAndLinks - else if MangaSiteID = STARKANA_ID then Result := StarkanaGetNamesAndLinks else @@ -1176,8 +1166,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/VnSharing/manga_information.inc} - {$I includes/Fakku/manga_information.inc} - {$I includes/Starkana/manga_information.inc} {$I includes/S2Scans/manga_information.inc} @@ -1279,9 +1267,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else - if MangaSiteID = FAKKU_ID then - Result := GetFakkuInfoFromURL - else if MangaSiteID = STARKANA_ID then Result := GetStarkanaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 7ab2036e7..c70522d5c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -583,8 +583,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/EsMangaHere/image_url.inc} - {$I includes/Fakku/image_url.inc} - {$I includes/Kivmanga/image_url.inc} {$I includes/Manga24h/image_url.inc} @@ -653,9 +651,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else - if Task.Container.MangaSiteID = FAKKU_ID then - Result := GetFakkuImageURL - else if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaImageURL else diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e2e0914f7..653d49571 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -71,9 +71,10 @@ TUpdateListManagerThread = class(TBaseThread) websites: TStringList; website, twebsite, twebsitetemp: String; ModuleId: Integer; - workPtr, directoryCount, - // for fakku's doujinshi only - directoryCount2, numberOfThreads, websitePtr: Integer; + directoryCount, + workPtr, + websitePtr, + numberOfThreads: Integer; Threads: TFPList; SortedList, NoMangaInfo: Boolean; constructor Create; @@ -149,21 +150,12 @@ procedure TUpdateListThread.Execute; info.GetDirectoryPage(TotalDirectoryPage[i], manager.website); end; end - else - if manager.website = WebsiteRoots[FAKKU_ID, 0] then - begin - FAKKU_BROWSER := FAKKU_BROWSER_1; - info.GetDirectoryPage(manager.directoryCount, manager.website); - - FAKKU_BROWSER := FAKKU_BROWSER_2; - info.GetDirectoryPage(manager.directoryCount2, manager.website); - end else info.GetDirectoryPage(manager.directoryCount, manager.website); end; //get names and links - CS_DIRECTORY_PAGE, CS_DIRECTORY_PAGE_2: + CS_DIRECTORY_PAGE: begin names := TStringList.Create; links := TStringList.Create; @@ -176,26 +168,8 @@ procedure TUpdateListThread.Execute; else if checkStyle = CS_DIRECTORY_PAGE then workPtr := manager.directoryCount - workPtr - 1 - else - if checkStyle = CS_DIRECTORY_PAGE_2 then - workPtr := manager.directoryCount2 - workPtr - 1; end; - if manager.website = WebsiteRoots[FAKKU_ID, 0] then - begin - if checkStyle = CS_DIRECTORY_PAGE then - begin - FAKKU_BROWSER := FAKKU_BROWSER_1; - Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); - end - else - if checkStyle = CS_DIRECTORY_PAGE_2 then - begin - FAKKU_BROWSER := FAKKU_BROWSER_2; - Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); - end; - end - else - Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); + Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); //if website has sorted list by latest added //we will stop at first found against current db @@ -462,7 +436,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; numberOfThreads := 1; //default // Finish searching for new series - if (cs in [CS_DIRECTORY_PAGE, CS_DIRECTORY_PAGE_2]) and + if (cs = CS_DIRECTORY_PAGE) and (isFinishSearchingForNewManga) then begin WaitForThreads; @@ -514,8 +488,6 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; s += Format(' %d/%d', [CurrentDirectoryIndex + 1, TotalDirectory]); s += '...'; end; - CS_DIRECTORY_PAGE_2: - s := s + ' | ' + RS_LookingForNewTitleFromAnotherDirectory + '...'; CS_INFO: s := Format('%s | %s "%s"', [s, RS_GettingInfo, tempDataProcess.Value[workPtr-1,DATA_PARAM_TITLE]]); end; @@ -632,7 +604,6 @@ procedure TUpdateListManagerThread.Execute; // get directory page count directoryCount := 0; - directoryCount2 := 0; workPtr := 0; GetInfo(1, CS_DIRECTORY_COUNT); if Terminated then Break; @@ -659,18 +630,6 @@ procedure TUpdateListManagerThread.Execute; end; end; end - else - if website = WebsiteRoots[FAKKU_ID, 0] then - begin - if directoryCount = 0 then - directoryCount := 1; - GetInfo(directoryCount, CS_DIRECTORY_PAGE); - workPtr := 0; - isFinishSearchingForNewManga := False; - if directoryCount2 = 0 then - directoryCount2 := 1; - GetInfo(directoryCount2, CS_DIRECTORY_PAGE_2); - end else GetInfo(directoryCount, CS_DIRECTORY_PAGE); diff --git a/config/mangalist.ini b/config/mangalist.ini index e0e8cff7e..619a6cc60 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -21,5 +21,5 @@ Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing Webcomics=Tapas -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Fakku,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From 2a2fa53e9dd22e86943c5bccec27ac50c3eed5b0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Jun 2017 18:01:17 +0800 Subject: [PATCH 1772/2794] Bump version 0.9.115.0 --- changelog.txt | 8 +++++++- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4e119f12f..33dc380f7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.115.0 (11-06-2017) +[+] Added Taadd[EN] +[-] Fakku: removed, not free anymore +[-] Yomanga: removed, website down +Full changes: https://github.com/riderkick/FMD/compare/0.9.114.0...0.9.115.0 + 0.9.114.0 (10-06-2017) [*] EatManga: fixed all [*] Fixed layout @@ -20,7 +26,7 @@ Full changes: https://github.com/riderkick/FMD/compare/0.9.112.0...0.9.113.0 Full changes: https://github.com/riderkick/FMD/compare/0.9.111.0...0.9.112.0 0.9.111.0 (23-05-2017) -[*] Added Tapas +[+] Added Tapas [*] Tumangaonline: fixed all [*] NeoProjectScan: fixed domain [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b1b16231c..db7db311e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="114"/> + <RevisionNr Value="115"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index df216d36d..5acc1cc71 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.114.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.114.0/fmd_0.9.114.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.114.0/fmd_0.9.114.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.114.0/fmd_0.9.114.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.114.0/fmd_0.9.114.0_Win64.7z +VERSION=0.9.115.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.115.0/fmd_0.9.115.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.115.0/fmd_0.9.115.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.115.0/fmd_0.9.115.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.115.0/fmd_0.9.115.0_Win64.7z From daa027308dfcadc94e57118bc01aad426d160226 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Jun 2017 13:38:11 +0800 Subject: [PATCH 1773/2794] updatethread, fixed currentlimit --- baseunits/uUpdateThread.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 653d49571..0886ab710 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -306,17 +306,16 @@ procedure TUpdateListManagerThread.ExtractFile; constructor TUpdateListManagerThread.Create; begin inherited Create(True); + FreeOnTerminate := True; + InitCriticalSection(CS_Threads); InitCriticalSection(CS_AddInfoToData); InitCriticalSection(CS_AddNamesAndLinks); InitCriticalSection(FCS_CurrentGetInfoLimit); - FreeOnTerminate := True; websites := TStringList.Create; - mainDataProcess := TDBDataProcess.Create; tempDataProcess := TDBDataProcess.Create; - Threads := TFPList.Create; SortedList := False; NoMangaInfo := False; @@ -324,6 +323,7 @@ constructor TUpdateListManagerThread.Create; FThreadEndNormally:=False; FThreadAborted:=False; FIsPreListAvailable:=False; + FCurrentGetInfoLimit := 1; end; destructor TUpdateListManagerThread.Destroy; @@ -537,7 +537,7 @@ procedure TUpdateListManagerThread.DoTerminate; procedure TUpdateListManagerThread.SetCurrentDirectoryPageNumber(AValue: Integer); begin - if FCurrentGetInfoLimit = AValue then Exit; + if AValue < FCurrentGetInfoLimit then Exit; try EnterCriticalsection(FCS_CurrentGetInfoLimit); FCurrentGetInfoLimit := AValue; From 33bcf30b803b8c8e24c76d07404e3f031041af6a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Jun 2017 14:33:44 +0800 Subject: [PATCH 1774/2794] myreadingmanga, rewrite all fixed #612 --- baseunits/ModuleList.inc | 3 +- .../chapter_page_number.inc | 48 ------- .../directory_page_number.inc | 46 ------- .../MyReadingMangaInfo/manga_information.inc | 127 ------------------ .../MyReadingMangaInfo/names_and_links.inc | 38 ------ baseunits/modules/MyReadingManga.pas | 118 ++++++++++++++++ baseunits/uBaseUnit.pas | 27 ++-- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 5 - config/mangalist.ini | 2 +- 10 files changed, 132 insertions(+), 297 deletions(-) delete mode 100644 baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc delete mode 100644 baseunits/includes/MyReadingMangaInfo/directory_page_number.inc delete mode 100644 baseunits/includes/MyReadingMangaInfo/manga_information.inc delete mode 100644 baseunits/includes/MyReadingMangaInfo/names_and_links.inc create mode 100644 baseunits/modules/MyReadingManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index fe79d14ed..3eba80899 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -70,4 +70,5 @@ uses HentaiCafe, Hentai2Read, HentaiFox, - Pururin; + Pururin, + MyReadingManga; diff --git a/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc b/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc deleted file mode 100644 index fbd6bf3cb..000000000 --- a/baseunits/includes/MyReadingMangaInfo/chapter_page_number.inc +++ /dev/null @@ -1,48 +0,0 @@ - function GetMyReadingMangaInfoPageNumber: Boolean; - var - i: Integer; - //j: Integer; - l: TStringList; - s: String; - isExtractImg: Boolean = False; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MYREADINGMANGAINFO_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - //if (Pos('class="separator"', parse[i]) > 0) and - // (Pos('style="clear: both; text-align: center;"', parse[i]) > 0) then - // for j := i + 1 to parse.Count - 1 do - // if (Pos('<img', parse[j]) > 0) then - // begin - // Task.Container.PageLinks.Add(GetVal(parse[j], 'src')); - // Break; - // end; - if isExtractImg and (Pos('<footer', parse[i]) > 0) and - (Pos('class="entry-footer"', parse[i]) > 0) then - begin - isExtractImg := False; - Break; - end; - if (Pos('<div', parse[i]) > 0) and - (Pos('class="entry-content"', parse[i]) > 0) then - isExtractImg := True; - if isExtractImg and (Pos('<img', parse[i]) > 0) then - Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); - end; - Task.Container.PageNumber := Task.Container.PageLinks.Count; - end; - parse.Free; - end; diff --git a/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc b/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc deleted file mode 100644 index 52ae35e61..000000000 --- a/baseunits/includes/MyReadingMangaInfo/directory_page_number.inc +++ /dev/null @@ -1,46 +0,0 @@ - function GetMyReadingMangaInfoDirectoryPageNumber: Byte; - var - i, j: Cardinal; - isGetLastPage: Boolean = False; - begin - APage := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MYREADINGMANGAINFO_ID, 1] + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="pagination-omission"', parse[i]) > 0 then - begin - j := i + 1; - while j < parse.Count - 1 do - begin - if (Pos('<a', parse[j]) > 0) and (Pos('/page/', parse[j]) > 0) then - begin - Result := NO_ERROR; - APage := StrToIntDef(Trim(parse[j + 1]), 1); - isGetLastPage := True; - Break; - end; - if isGetLastPage then - Break; - Inc(j); - end; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MyReadingMangaInfo/manga_information.inc b/baseunits/includes/MyReadingMangaInfo/manga_information.inc deleted file mode 100644 index 2f386cd32..000000000 --- a/baseunits/includes/MyReadingMangaInfo/manga_information.inc +++ /dev/null @@ -1,127 +0,0 @@ - function GetMyReadingMangaInfoInfoFromURL: Byte; - var - s: String; - i, j: Integer; - isCategories: Boolean = False; - isTags: Boolean = False; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MYREADINGMANGAINFO_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MYREADINGMANGAINFO_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //title - if (GetTagName(parse[i]) = 'h1') and - (GetVal(parse[i], 'class') = 'entry-title') then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //author - if (Pos('<strong>', parse[i]) <> 0) and (Pos('Author:', parse[i + 1]) <> 0) then - begin - s := StringReplace(parse[i + 1], 'Author:', '', []); - s := StringReplace(s, #194#160, '', [rfReplaceAll]); //space - mangaInfo.authors := Trim(s); - end; - - //genres - if (Pos('class="entry-categories"', parse[i]) > 0) and (isCategories = False) then - begin - j := i + 2; - s := ''; - while (j < parse.Count - 1) do - begin - if (Pos('</span', parse[j]) > 0) then - Break; - if (Pos('<', parse[j]) = 0) then - s := s + parse[j]; - Inc(j); - end; - s := StringFilter(Trim(s)); - if (mangaInfo.genres <> '') and (s <> '') then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(s) - else - if s <> '' then - mangaInfo.genres := Trim(s); - isCategories := True; - end; - if (Pos('class="entry-tags"', parse[i]) > 0) and (isTags = False) then - begin - j := i + 2; - s := ''; - while (j < parse.Count - 1) do - begin - if (Pos('</span', parse[j]) > 0) then - Break; - if (Pos('<', parse[j]) = 0) then - s := s + parse[j]; - Inc(j); - end; - s := StringFilter(Trim(s)); - if (mangaInfo.genres <> '') and (s <> '') then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(s) - else - if s <> '' then - mangaInfo.genres := Trim(s); - isTags := True; - end; - if (i + 1 < parse.Count - 1) then - if (Pos('Pairing:', parse[i]) > 0) and (Pos('</strong', parse[i + 1]) > 0) then - begin - s := StringReplace(parse[i], 'Pairing:', '', []); - s := StringReplace(s, #194#160, #32, [rfReplaceAll]); - if (mangaInfo.genres <> '') and (s <> '') then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(s) - else - if s <> '' then - mangaInfo.genres := Trim(s); - end; - - //chapters - if Pos('class="entry-pagination pagination', parse[i]) <> 0 then - isExtractChapters := True; - if isExtractChapters and (Pos('</div', parse[i]) <> 0) then - isExtractChapters := False; - if isExtractChapters and (Pos('<a', parse[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(RemoveHostFromURL(GetVal(parse[i], 'href'))); - mangaInfo.chapterName.Add(mangaInfo.title + ' Ch. ' + IntToStr(mangaInfo.numChapter + 1)); - end; - end; - - //chapter 1 - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Insert(0, AURL); - if mangaInfo.numChapter = 1 then - mangaInfo.chapterName.Insert(0, mangaInfo.title) - else - mangaInfo.chapterName.Insert(0, mangaInfo.title + ' Ch. 1'); - - //no status = completed - mangaInfo.status := '0'; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MyReadingMangaInfo/names_and_links.inc b/baseunits/includes/MyReadingMangaInfo/names_and_links.inc deleted file mode 100644 index d9918b055..000000000 --- a/baseunits/includes/MyReadingMangaInfo/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function MyReadingMangaInfoNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MYREADINGMANGAINFO_ID, 1] + - '/page/' + IntToStr(StrToInt(AURL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="entry-title"', parse[i]) > 0 then - begin - Result := NO_ERROR; - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2])))); - ANames.Add(s); - s := GetVal(parse[i + 1], 'href'); - s := StringReplace(s, WebsiteRoots[MYREADINGMANGAINFO_ID, 1], '', [rfIgnoreCase]); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/modules/MyReadingManga.pas b/baseunits/modules/MyReadingManga.pas new file mode 100644 index 000000000..23b0b4674 --- /dev/null +++ b/baseunits/modules/MyReadingManga.pas @@ -0,0 +1,118 @@ +unit MyReadingManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +uses Cloudflare, httpsendthread; + +var + myreadingmangacf: TCFProps; + +function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +begin + Result := Cloudflare.GETCF(AHTTP, AURL, myreadingmangacf) +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL) then begin + Result := NO_ERROR; + Page := StrToIntDef(XPathString('//*[contains(@class,"archive-pagination")]/ul/li[last()-1]', MangaInfo.FHTTP.Document), 1); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + '/page/' + IncStr(AURL) + '/') then + begin + Result := NO_ERROR; + XPathHREFAll('//h2[@class="entry-title"]/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GETWithCookie(MangaInfo.FHTTP, url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + title := XPathString('//*[contains(@class,"entry-content")]/h2'); + if title = '' then title := Trim(XPathString('//*[contains(@class,"entry-content")]/p[starts-with(.,"Title")]/substring-after(.,":")')); + if title = '' then title := XPathString('//*[contains(@class,"entry-content")]/p[1]/strong'); + if title = '' then title := XPathString('//h1[@class="entry-title"]'); + genres := XPathString('//header[@class="entry-header"]/string-join(./p[position()>1]//a,", ")'); + authors := Trim(XPathString('//*[contains(@class,"entry-content")]/p[starts-with(.,"Author")]/substring-after(.,":")')); + chapterLinks.Add(url); + chapterName.Add(title); + for v in XPath('//*[contains(@class,"entry-pagination")]/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(title + ' - ' + v.toString); + end; + if chapterName.Count > 1 then + chapterName[0] := chapterName[0] + ' - 1'; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + XPathStringAll('//*[contains(@class,"entry-content")]/div/img/@src', Document, PageLinks); + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MyReadingManga'; + RootURL := 'https://myreadingmanga.info'; + SortedList := True; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + myreadingmangacf := TCFProps.Create; + RegisterModule; + +finalization + myreadingmangacf.Free; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index eaf9bec47..ee8741a70 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -268,18 +268,17 @@ interface ONEMANGA_ID = 35; MANGATOWN_ID = 36; MANGAOKU_ID = 37; - MYREADINGMANGAINFO_ID = 38; - IKOMIK_ID = 39; - NHENTAI_ID = 40; - MANGAMINT_ID = 41; - UNIXMANGA_ID = 42; - EXTREMEMANGAS_ID = 43; - MANGAHOST_ID = 44; - MANGAKU_ID = 45; - MANGAAT_ID = 46; - DYNASTYSCANS_ID = 47; - - WebsiteRoots: array [0..47] of array [0..1] of String = ( + IKOMIK_ID = 38; + NHENTAI_ID = 39; + MANGAMINT_ID = 40; + UNIXMANGA_ID = 41; + EXTREMEMANGAS_ID = 42; + MANGAHOST_ID = 43; + MANGAKU_ID = 44; + MANGAAT_ID = 45; + DYNASTYSCANS_ID = 46; + + WebsiteRoots: array [0..46] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -318,7 +317,6 @@ interface ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), ('MangaOku', 'http://www.mangaoku.net'), - ('MyReadingMangaInfo', 'https://myreadingmanga.info'), ('I-Komik', 'http://www.i-komik.com'), ('NHentai', 'http://nhentai.net'), ('MangaMint', 'http://www.mangamint.com'), @@ -1139,7 +1137,6 @@ function SitesWithSortedList(const website: String): Boolean; NINEMANGA_IT_ID, NINEMANGA_BR_ID, ONEMANGA_ID, - MYREADINGMANGAINFO_ID, NHENTAI_ID ]); end; @@ -1155,7 +1152,6 @@ function SitesWithoutFavorites(const website: String): Boolean; Exit; end; Result := SitesMemberOf(website, [ - MYREADINGMANGAINFO_ID, NHENTAI_ID ]); end; @@ -1192,7 +1188,6 @@ function SitesWithSingleChapter(const website: String): Boolean; begin Result := False; Result := SitesMemberOf(website, [ - MYREADINGMANGAINFO_ID, NHENTAI_ID ]); end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5411b178f..6309433b2 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -796,8 +796,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/MangaTown/directory_page_number.inc} - {$I includes/MyReadingMangaInfo/directory_page_number.inc} - {$I includes/IKomik/directory_page_number.inc} {$I includes/NHentai/directory_page_number.inc} @@ -880,9 +878,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownDirectoryPageNumber else - if MangaSiteID = MYREADINGMANGAINFO_ID then - Result := GetMyReadingMangaInfoDirectoryPageNumber - else if MangaSiteID = IKOMIK_ID then Result := GetIKomikDirectoryPageNumber else @@ -978,8 +973,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/MangaOku/names_and_links.inc} - {$I includes/MyReadingMangaInfo/names_and_links.inc} - {$I includes/IKomik/names_and_links.inc} {$I includes/NHentai/names_and_links.inc} @@ -1103,9 +1096,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = MANGAOKU_ID then Result := MangaOkuGetNamesAndLinks else - if MangaSiteID = MYREADINGMANGAINFO_ID then - Result := MyReadingMangaInfoNamesAndLinks - else if MangaSiteID = IKOMIK_ID then Result := IKomikNamesAndLinks else @@ -1212,8 +1202,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/MangaOku/manga_information.inc} - {$I includes/MyReadingMangaInfo/manga_information.inc} - {$I includes/IKomik/manga_information.inc} {$I includes/NHentai/manga_information.inc} @@ -1348,9 +1336,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuInfoFromURL else - if MangaSiteID = MYREADINGMANGAINFO_ID then - Result := GetMyReadingMangaInfoInfoFromURL - else if MangaSiteID = IKOMIK_ID then Result := GetIKomikInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c70522d5c..e4fa30f62 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -445,8 +445,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaOku/chapter_page_number.inc} - {$I includes/MyReadingMangaInfo/chapter_page_number.inc} - {$I includes/IKomik/chapter_page_number.inc} {$I includes/NHentai/chapter_page_number.inc} @@ -533,9 +531,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuPageNumber else - if Task.Container.MangaSiteID = MYREADINGMANGAINFO_ID then - Result := GetMyReadingMangaInfoPageNumber - else if Task.Container.MangaSiteID = IKOMIK_ID then Result := GetIKomikPageNumber else diff --git a/config/mangalist.ini b/config/mangalist.ini index 619a6cc60..0038a5d57 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -21,5 +21,5 @@ Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing Webcomics=Tapas -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingMangaInfo,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From ac03c552c497e162c1e164e8b9a736c7d8fcf6f3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Jun 2017 16:01:12 +0800 Subject: [PATCH 1775/2794] ninemanga, rewrite all fixed #503 --- baseunits/ModuleList.inc | 1 + .../NineManga/chapter_page_number.inc | 39 ------ .../NineManga/directory_page_number.inc | 29 ---- baseunits/includes/NineManga/image_url.inc | 42 ------ .../includes/NineManga/manga_information.inc | 125 ----------------- .../includes/NineManga/names_and_links.inc | 38 ------ baseunits/modules/NineManga.pas | 129 ++++++++++++++++++ baseunits/uBaseUnit.pas | 58 +++----- baseunits/uData.pas | 33 ----- baseunits/uDownloadsManager.pas | 22 --- config/mangalist.ini | 10 +- 11 files changed, 152 insertions(+), 374 deletions(-) delete mode 100644 baseunits/includes/NineManga/chapter_page_number.inc delete mode 100644 baseunits/includes/NineManga/directory_page_number.inc delete mode 100644 baseunits/includes/NineManga/image_url.inc delete mode 100644 baseunits/includes/NineManga/manga_information.inc delete mode 100644 baseunits/includes/NineManga/names_and_links.inc create mode 100644 baseunits/modules/NineManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 3eba80899..3a733437b 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -54,6 +54,7 @@ uses Tapas, EatManga, Taadd, + NineManga, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/NineManga/chapter_page_number.inc b/baseunits/includes/NineManga/chapter_page_number.inc deleted file mode 100644 index c4b17aa3f..000000000 --- a/baseunits/includes/NineManga/chapter_page_number.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetNineMangaPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - isExtractPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - - Result := GetPage(TObject(l), - FillMangaSiteHost(Task.Container.MangaSiteID, URL), - Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and - (Pos('name="page"', parse[i]) > 0) and - (Pos('id="page"', parse[i]) > 0) then - isExtractPageNumber := True; - if isExtractPageNumber and (Pos('</select', parse[i]) > 0) then - begin - isExtractPageNumber := False; - Break; - end; - if isExtractPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/NineManga/directory_page_number.inc b/baseunits/includes/NineManga/directory_page_number.inc deleted file mode 100644 index 2eb74041a..000000000 --- a/baseunits/includes/NineManga/directory_page_number.inc +++ /dev/null @@ -1,29 +0,0 @@ - function GetNineMangaDirectoryPageNumber: Byte; - var - SiteID: Cardinal; - p: Integer; - begin - Source.Free; - Result := 0; - BROWSER_INVERT := True; - //I can't get manga directory total pages. Its not available on any page - //The only option to get total pages is just checking manually with browser :( - p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', AWebsite, -1); - if p > 0 then - APage := p - else - begin - SiteID := GetMangaSiteID(AWebsite); - case SiteID of - NINEMANGA_ID: APage := 520; //latest check = 513 (01-11-2014) - NINEMANGA_ES_ID: APage := 596; - NINEMANGA_CN_ID: APage := 778; - NINEMANGA_RU_ID: APage := 205; - NINEMANGA_BR_ID: APage := 56; - NINEMANGA_IT_ID: APage := 50; - NINEMANGA_DE_ID: APage := 30; - else - APage := 500; //not checked yet = 500 default - end; - end; - end; diff --git a/baseunits/includes/NineManga/image_url.inc b/baseunits/includes/NineManga/image_url.inc deleted file mode 100644 index 9aa383532..000000000 --- a/baseunits/includes/NineManga/image_url.inc +++ /dev/null @@ -1,42 +0,0 @@ - function GetNineMangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(Task.Container.MangaSiteID, URL); - s := StringReplace(s, '.html', '', []); - s := StringReplace(s, '.htm', '', []); - s := s + '-' + IntToStr(WorkId + 1) + '.html'; - - Result := GetPage(TObject(l), - s, - Task.container.Manager.retryConnect); - if Self.Terminated then - begin - l.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and - (Pos('class="manga_pic', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := - GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/NineManga/manga_information.inc b/baseunits/includes/NineManga/manga_information.inc deleted file mode 100644 index 38030251c..000000000 --- a/baseunits/includes/NineManga/manga_information.inc +++ /dev/null @@ -1,125 +0,0 @@ - function GetNineMangaInfoFromURL: Byte; - var - isExtractGenres: Boolean = False; - i, j, SiteID: Cardinal; - s: String; - begin - SiteID := GetMangaSiteID(AWebsite); - mangaInfo.website := WebsiteRoots[SiteID, 0]; - mangaInfo.url := StringReplace(FillMangaSiteHost(SiteID, AURL), '?waring=1', '', - [rfIgnoreCase, rfReplaceAll]); - - if not GetPage(TObject(Source), mangaInfo.url + '?waring=1', AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.numChapter := 0; - - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - //manga title - if {(mangaInfo.title = '') and} - (Pos('itemprop="name"', parse[i]) > 0) then - begin - mangaInfo.title := HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))); - mangaInfo.title := ReplaceRegExpr('\sManga$', mangaInfo.title, '', False); - end; - - //coverlink - if Pos('itemprop="image"', parse[i]) > 0 then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //genres - if Pos('itemprop="genre"', parse[i]) > 0 then - isExtractGenres := True; - if isExtractGenres and (Pos('</li>', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('href="', parse[i]) > 0) then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - - //author - if Pos('itemprop="author"', parse[i]) > 0 then - mangaInfo.authors := Trim(parse[i + 1]); - - //status - if Pos('class="red" href="/category/', parse[i]) > 0 then - if Pos('/category/updated', parse[i]) > 0 then - mangaInfo.status := '1' //ongoing - else - if Pos('/category/completed', parse[i]) > 0 then - mangaInfo.status := '0'; //completed - - //summary - if Pos('itemprop="description"', parse[i]) > 0 then - //mangaInfo.summary:= mangaInfo.summary+#13#10+Trim(parse[i+5]); - mangaInfo.summary := HTMLEntitiesFilter(StringFilter(Trim(parse[i + 5]))); - - ////chapter name and links - //if Pos('class="chapter_list_', parse[i]) > 0 then - //begin - // Inc(mangaInfo.numChapter); - // mangaInfo.chapterLinks.Add( - // StringReplace(GetVal(parse[i], 'href'), - // WebsiteRoots[SiteID, 1], '', [rfIgnoreCase])); - // mangaInfo.chapterName.Add(HTMLEntitiesFilter( - // StringFilter(Trim(parse[i + 1])))); - //end; - end; - - // chapter list direct - if Source.Count > 1 then - begin - for i := 0 to Source.Count - 1 do - begin - if (Pos('<a ', Source[i]) > 0) and - (Pos('class="chapter_list_', Source[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(Source[i], 'href'), WebsiteRoots[SiteID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(ReplaceRegExpr('^.*\>(.*)\<\/a.*$', Source[i], '$1', True)); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(s)))); - end; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/includes/NineManga/names_and_links.inc b/baseunits/includes/NineManga/names_and_links.inc deleted file mode 100644 index aea72cbf8..000000000 --- a/baseunits/includes/NineManga/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function NineMangaGetNamesAndLinks: Byte; - var - SiteID, i: Cardinal; - - begin - Result := INFORMATION_NOT_FOUND; - SiteID := GetMangaSiteID(AWebsite); - if not GetPage(TObject(Source), WebsiteRoots[SiteID, 1] + - NINEMANGA_BROWSER + '&page=' + IntToStr(StrToIntDef(AURL, 0) + 1) + '.html', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="bookname"', parse[i]) > 0) then - begin - Result := NO_ERROR; - ALinks.Add( - StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[SiteID, 1], '', [rfReplaceAll])); - ANames.Add(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - end; - end; - Source.Free; - end; diff --git a/baseunits/modules/NineManga.pas b/baseunits/modules/NineManga.pas new file mode 100644 index 000000000..7fc345641 --- /dev/null +++ b/baseunits/modules/NineManga.pas @@ -0,0 +1,129 @@ +unit NineManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +uses FMDVars; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + i, x: Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/category/index_' + IncStr(AURL) + '.html') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try + i := 1; + for v in XPath('//ul[@class="pagelist"]/li') do begin + x := StrToIntDef(v.toString, 1); + if x > i then i := x; + end; + updateList.CurrentDirectoryPageNumber := i; + XPathHREFAll('//dl[@class="bookinfo"]//dd/a[@class="bookname"]', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + s := url; + if Pos('waring=1', s) = 0 then s += '?waring=1'; + if GET(s) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//*[@class="bookface"]/img/@src'); + if title = '' then title := XPathString('//*[@class="manga"]/*[@class="ttline"]/h1/substring-before(.," Manga")'); + authors := XPathString('//ul[@class="message"]/li[starts-with(.,"Author")]/string-join(a,", ")'); + genres := XPathString('//ul[@class="message"]/li[starts-with(.,"Genre")]/string-join(a,", ")'); + status := MangaInfoStatusIfPos(XPathString('//ul[@class="message"]/li[starts-with(.,"Status")]')); + summary := Trim(XPathString('//*[@class="bookintro"]/p[starts-with(.,"Summary")]/substring-after(.,":")')); + XPathHREFAll('//*[@class="chapterbox"]//li/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + PageNumber := XPathCount('(//select[@id="page"])[1]/option', Document); + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + if GET(AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)) + 'page-' + IncStr(DownloadThread.WorkId)) then + begin + Result := True; + PageLinks[DownloadThread.WorkId] := XPathString('//img[contains(@class,"manga_pic")]/@src', Document); + end; + end; +end; + +procedure RegisterModule; + + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + begin + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; + end; + +begin + AddWebsiteModule('NineManga', 'http://www.ninemanga.com'); + AddWebsiteModule('NineMangaES', 'http://es.ninemanga.com'); + AddWebsiteModule('NineMangaRU', 'http://ru.ninemanga.com'); + AddWebsiteModule('NineMangaDE', 'http://de.ninemanga.com'); + AddWebsiteModule('NineMangaIT', 'http://it.ninemanga.com'); + AddWebsiteModule('NineMangaBR', 'http://br.ninemanga.com'); +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ee8741a70..dc3047479 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -255,30 +255,23 @@ interface MEINMANGA_ID = 22; MANGASPROJECT_ID = 23; MANGAREADER_POR_ID = 24; - NINEMANGA_ID = 25; - NINEMANGA_ES_ID = 26; - NINEMANGA_CN_ID = 27; - NINEMANGA_RU_ID = 28; - NINEMANGA_DE_ID = 29; - NINEMANGA_IT_ID = 30; - NINEMANGA_BR_ID = 31; - JAPANSHIN_ID = 32; - CENTRUMMANGI_PL_ID = 33; - MANGALIB_PL_ID = 34; - ONEMANGA_ID = 35; - MANGATOWN_ID = 36; - MANGAOKU_ID = 37; - IKOMIK_ID = 38; - NHENTAI_ID = 39; - MANGAMINT_ID = 40; - UNIXMANGA_ID = 41; - EXTREMEMANGAS_ID = 42; - MANGAHOST_ID = 43; - MANGAKU_ID = 44; - MANGAAT_ID = 45; - DYNASTYSCANS_ID = 46; - - WebsiteRoots: array [0..46] of array [0..1] of String = ( + JAPANSHIN_ID = 25; + CENTRUMMANGI_PL_ID = 26; + MANGALIB_PL_ID = 27; + ONEMANGA_ID = 28; + MANGATOWN_ID = 29; + MANGAOKU_ID = 30; + IKOMIK_ID = 31; + NHENTAI_ID = 32; + MANGAMINT_ID = 33; + UNIXMANGA_ID = 34; + EXTREMEMANGAS_ID = 35; + MANGAHOST_ID = 36; + MANGAKU_ID = 37; + MANGAAT_ID = 38; + DYNASTYSCANS_ID = 39; + + WebsiteRoots: array [0..39] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -304,13 +297,6 @@ interface ('MeinManga', 'http://www.meinmanga.com/'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), - ('NineManga', 'http://www.ninemanga.com'), - ('NineManga_ES', 'http://es.ninemanga.com'), - ('NineManga_CN', 'http://cn.ninemanga.com'), - ('NineManga_RU', 'http://ru.ninemanga.com'), - ('NineManga_DE', 'http://de.ninemanga.com'), - ('NineManga_IT', 'http://it.ninemanga.com'), - ('NineManga_BR', 'http://br.ninemanga.com'), ('Japan-Shin', 'http://www.japan-shin.com'), ('Centrum-Mangi_PL', 'http://centrum-mangi.pl'), ('Manga-Lib_PL', 'http://www.manga-lib.pl/index.php'), @@ -381,9 +367,6 @@ interface MANGAREADER_POR_BROWSER = '/AJAX/listaMangas/all'; - NINEMANGA_BROWSER = - '/search/?name_sel=contain&wd=&author_sel=contain&author=&artist_sel=contain&artist=&category_id=&out_category_id=&completed_series=either'; - JAPANSHIN_BROWSER = '/lectureenligne/reader/list/'; CENTRUMMANGI_PL_BROWSER = '/spis/'; @@ -1129,13 +1112,6 @@ function SitesWithSortedList(const website: String): Boolean; Exit; end; Result := SitesMemberOf(website, [ - NINEMANGA_ID, - NINEMANGA_ES_ID, - NINEMANGA_CN_ID, - NINEMANGA_RU_ID, - NINEMANGA_DE_ID, - NINEMANGA_IT_ID, - NINEMANGA_BR_ID, ONEMANGA_ID, NHENTAI_ID ]); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 6309433b2..3048902ee 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -788,8 +788,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/DM5/directory_page_number.inc} - {$I includes/NineManga/directory_page_number.inc} - {$I includes/JapanShin/directory_page_number.inc} {$I includes/OneManga/directory_page_number.inc} @@ -860,15 +858,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = DM5_ID then Result := GetDM5DirectoryPageNumber else - if (MangaSiteID = NINEMANGA_ID) or - (MangaSiteID = NINEMANGA_ES_ID) or - (MangaSiteID = NINEMANGA_CN_ID) or - (MangaSiteID = NINEMANGA_RU_ID) or - (MangaSiteID = NINEMANGA_DE_ID) or - (MangaSiteID = NINEMANGA_IT_ID) or - (MangaSiteID = NINEMANGA_BR_ID) then - Result := GetNineMangaDirectoryPageNumber - else if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinDirectoryPageNumber else @@ -959,8 +948,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/MangaREADER_POR/names_and_links.inc} - {$I includes/NineManga/names_and_links.inc} - {$I includes/JapanShin/names_and_links.inc} {$I includes/CentrumMangi_PL/names_and_links.inc} @@ -1069,15 +1056,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = MANGAREADER_POR_ID then Result := MangaREADER_PORGetNamesAndLinks else - if (MangaSiteID = NINEMANGA_ID) or - (MangaSiteID = NINEMANGA_ES_ID) or - (MangaSiteID = NINEMANGA_CN_ID) or - (MangaSiteID = NINEMANGA_RU_ID) or - (MangaSiteID = NINEMANGA_DE_ID) or - (MangaSiteID = NINEMANGA_IT_ID) or - (MangaSiteID = NINEMANGA_BR_ID) then - Result := NineMangaGetNamesAndLinks - else if MangaSiteID = JAPANSHIN_ID then Result := JapanShinGetNamesAndLinks else @@ -1188,8 +1166,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/MangaREADER_POR/manga_information.inc} - {$I includes/NineManga/manga_information.inc} - {$I includes/JapanShin/manga_information.inc} {$I includes/CentrumMangi_PL/manga_information.inc} @@ -1309,15 +1285,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORInfoFromURL else - if (MangaSiteID = NINEMANGA_ID) or - (MangaSiteID = NINEMANGA_ES_ID) or - (MangaSiteID = NINEMANGA_CN_ID) or - (MangaSiteID = NINEMANGA_RU_ID) or - (MangaSiteID = NINEMANGA_DE_ID) or - (MangaSiteID = NINEMANGA_IT_ID) or - (MangaSiteID = NINEMANGA_BR_ID) then - Result := GetNineMangaInfoFromURL - else if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index e4fa30f62..c987c0ad0 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -429,8 +429,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/AnimeA/chapter_page_number.inc} - {$I includes/NineManga/chapter_page_number.inc} - {$I includes/LectureEnLigne/chapter_page_number.inc} {$I includes/JapanShin/chapter_page_number.inc} @@ -501,15 +499,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else - if (Task.Container.MangaSiteID = NINEMANGA_ID) or - (Task.Container.MangaSiteID = NINEMANGA_ES_ID) or - (Task.Container.MangaSiteID = NINEMANGA_CN_ID) or - (Task.Container.MangaSiteID = NINEMANGA_RU_ID) or - (Task.Container.MangaSiteID = NINEMANGA_DE_ID) or - (Task.Container.MangaSiteID = NINEMANGA_IT_ID) or - (Task.Container.MangaSiteID = NINEMANGA_BR_ID) then - Result := GetNineMangaPageNumber - else if Task.Container.MangaSiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLignePageNumber else @@ -602,8 +591,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/AnimeA/image_url.inc} - {$I includes/NineManga/image_url.inc} - {$I includes/LectureEnLigne/image_url.inc} {$I includes/JapanShin/image_url.inc} @@ -691,15 +678,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORImageURL else - if (Task.Container.MangaSiteID = NINEMANGA_ID) or - (Task.Container.MangaSiteID = NINEMANGA_ES_ID) or - (Task.Container.MangaSiteID = NINEMANGA_CN_ID) or - (Task.Container.MangaSiteID = NINEMANGA_RU_ID) or - (Task.Container.MangaSiteID = NINEMANGA_DE_ID) or - (Task.Container.MangaSiteID = NINEMANGA_IT_ID) or - (Task.Container.MangaSiteID = NINEMANGA_BR_ID) then - Result := GetNineMangaImageURL - else if Task.Container.MangaSiteID = LECTUREENLIGNE_ID then Result := GeLectureEnligneImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 0038a5d57..25853fe72 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,17 +5,17 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd -Italian=MangaEden_IT,NineManga_IT +Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga -German=MeinManga,NineManga_DE +German=MeinManga,NineMangaDE Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL -Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineManga_BR,UnionMangas +Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas Raw=MangaMint,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType -Russian=MangaChanRU,MintMangaRU,NineManga_RU,ReadMangaRU -Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineManga_ES,SekaiManga,SubManga,Tumangaonline +Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU +Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr From bf410cc01fd95624d287949b32ca6377dfe93328 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Jun 2017 16:16:09 +0800 Subject: [PATCH 1776/2794] Bump version 0.9.116.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 33dc380f7..64e94925f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.116.0 (12-06-2017) +[*] NineManga: fixed all +[*] MyReadingManga: fixed all +Full changes: https://github.com/riderkick/FMD/compare/0.9.115.0...0.9.116.0 + 0.9.115.0 (11-06-2017) [+] Added Taadd[EN] [-] Fakku: removed, not free anymore diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index db7db311e..b39e66609 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="115"/> + <RevisionNr Value="116"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 5acc1cc71..b5fb0d9c7 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.115.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.115.0/fmd_0.9.115.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.115.0/fmd_0.9.115.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.115.0/fmd_0.9.115.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.115.0/fmd_0.9.115.0_Win64.7z +VERSION=0.9.116.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.116.0/fmd_0.9.116.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.116.0/fmd_0.9.116.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.116.0/fmd_0.9.116.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.116.0/fmd_0.9.116.0_Win64.7z From 92aa94c9860902643e496a0b4bc7f4502275c42f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Jun 2017 16:41:34 +0800 Subject: [PATCH 1777/2794] fixed update url --- baseunits/CheckUpdate.pas | 2 +- baseunits/FMDVars.pas | 2 +- mangadownloader/forms/frmMain.pas | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 80b64c5a1..b12bdabfe 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -61,7 +61,7 @@ procedure TCheckUpdateThread.MainThreadUpdate; end; if ShowModal = mrYes then begin - FUpdateURL := fUpdateURL; + UpdateURL := fUpdateURL; DoAfterFMD := DO_UPDATE; MainForm.tmExitCommand.Enabled := True; end diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas index 5a239c2e8..c90bf07e5 100644 --- a/baseunits/FMDVars.pas +++ b/baseunits/FMDVars.pas @@ -24,7 +24,7 @@ interface // update fmd through main thread DoAfterFMD: TFMDDo; IsDlgCounter: Boolean = False; - FUpdateURL: String; + UpdateURL: String; // file logger FileLogger: TFileChannel; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b2a0e6d74..3b4a1c2dd 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1079,12 +1079,12 @@ procedure TMainForm.FormCreate(Sender: TObject); LoadAbout; // remove old updater - if FileExistsUTF8(FMD_DIRECTORY + 'old_updater.exe') then + if FileExistsUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) then begin - if FileExistsUTF8(FMD_DIRECTORY + 'updater.exe') then - DeleteFileUTF8(FMD_DIRECTORY + 'old_updater.exe') + if FileExistsUTF8(FMD_DIRECTORY + UPDATER_EXE) then + DeleteFileUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) else - RenameFileUTF8(FMD_DIRECTORY + 'old_updater.exe', FMD_DIRECTORY + 'updater.exe'); + RenameFileUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE, FMD_DIRECTORY + UPDATER_EXE); end; // TrayIcon @@ -1604,7 +1604,7 @@ procedure TMainForm.tmExitCommandTimer(Sender: TObject); begin Self.CloseNow; RunExternalProcess(FMD_DIRECTORY + 'old_' + UPDATER_EXE, - ['-x', '-r', '3', '-a', FUpdateURL, '-l', Application.ExeName, + ['-x', '-r', '3', '-a', UpdateURL, '-l', Application.ExeName, '--lang', SimpleTranslator.LastSelected], True, False); Self.Close; end; From f37459be5aaa74972663d9be68ce5f90e939a198 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Jun 2017 16:52:12 +0800 Subject: [PATCH 1778/2794] Bump version 0.9.117.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 64e94925f..509df5e5a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.117.0 (12-06-2017) +[*] Fixed empty update url, you may need to download this version manually +Full changes: https://github.com/riderkick/FMD/compare/0.9.116.0...0.9.117.0 + 0.9.116.0 (12-06-2017) [*] NineManga: fixed all [*] MyReadingManga: fixed all diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b39e66609..547afa586 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="116"/> + <RevisionNr Value="117"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index b5fb0d9c7..bc93942c7 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.116.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.116.0/fmd_0.9.116.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.116.0/fmd_0.9.116.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.116.0/fmd_0.9.116.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.116.0/fmd_0.9.116.0_Win64.7z +VERSION=0.9.117.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.117.0/fmd_0.9.117.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.117.0/fmd_0.9.117.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.117.0/fmd_0.9.117.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.117.0/fmd_0.9.117.0_Win64.7z From 3978bb051a260b6f8a2fc3347c766a787e0abbd4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 15:16:42 +0800 Subject: [PATCH 1779/2794] accountmanagerdb, cancel on edit error --- baseunits/accountmanagerdb.pas | 38 +++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas index 19293d897..fd5626684 100644 --- a/baseunits/accountmanagerdb.pas +++ b/baseunits/accountmanagerdb.pas @@ -204,7 +204,7 @@ procedure TAccountManager.SetCookies(AName: string; AValue: string); procedure TAccountManager.SetStatus(AName: string; AValue: TAccountStatus); begin - SetValueInteger(AName, 'status', Integer(AValue)); + SetValueString(AName, 'status', IntToStr(Integer(AValue))); end; function TAccountManager.CreateDB: Boolean; @@ -364,7 +364,11 @@ procedure TAccountManager.SetValueStr(const RecIndex, FieldIndex: Integer; fquery.Fields[FieldIndex].AsString := encode(AValue) else fquery.Fields[FieldIndex].AsString := decode(AValue); - fquery.Post; + try + fquery.Post; + except + fquery.Cancel; + end; finally LeaveCriticalsection(locklocate); end; @@ -380,7 +384,11 @@ procedure TAccountManager.SetValueBool(const RecIndex, FieldIndex: Integer; fquery.RecNo := RecIndex + 1; fquery.Edit; fquery.Fields[FieldIndex].AsBoolean := AValue; - fquery.Post; + try + fquery.Post; + except + fquery.Cancel; + end; finally LeaveCriticalsection(locklocate); end; @@ -396,7 +404,11 @@ procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex: Integer; fquery.RecNo := RecIndex + 1; fquery.Edit; fquery.Fields[FieldIndex].AsInteger := AValue; - fquery.Post; + try + fquery.Post; + except + fquery.Cancel; + end; finally LeaveCriticalsection(locklocate); end; @@ -410,7 +422,11 @@ procedure TAccountManager.SetValueString(const AName, AField, AValue: string); if fquery.Locate('aname', AName, []) then begin fquery.Edit; fquery.FieldByName(AField).AsString := AValue; - fquery.Post; + try + fquery.Post; + except + fquery.Cancel; + end; end; finally LeaveCriticalsection(locklocate); @@ -426,7 +442,11 @@ procedure TAccountManager.SetValueBoolean(const AName, AField: string; if fquery.Locate('aname', AName, []) then begin fquery.Edit; fquery.FieldByName(AField).AsBoolean := AValue; - fquery.Post; + try + fquery.Post; + except + fquery.Cancel; + end; end; finally LeaveCriticalsection(locklocate); @@ -442,7 +462,11 @@ procedure TAccountManager.SetValueInteger(const AName, AField: string; if fquery.Locate('aname', AName, []) then begin fquery.Edit; fquery.FieldByName(AField).AsInteger := AValue; - fquery.Post; + try + fquery.Post; + except + fquery.Cancel; + end; end; finally LeaveCriticalsection(locklocate); From 0fbc198cc990cf268b3d1fcaa79ad7c3165d441c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 15:35:47 +0800 Subject: [PATCH 1780/2794] updated useragent --- baseunits/httpsendthread.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 7d291a7c4..64f46e0f1 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -97,10 +97,10 @@ procedure SplitURL(const AURL: String; const AHost, APath: PString; UserAgentCURL = 'curl/7.52.1'; UserAgentGooglebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; UserAgentMSIE = 'Mozilla/5.0 (Windows NT 10.0; Win64; Trident/7.0; rv:11.0) like Gecko'; - UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0'; + UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0'; UserAgentChrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'; - UserAgentVivaldi = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.111 Safari/537.36 Vivaldi/1.8.770.44'; - UserAgentOpera = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36 OPR/44.0.2510.857'; + UserAgentVivaldi = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.90 Safari/537.36 Vivaldi/1.91.867.3'; + UserAgentOpera = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.888'; UserAgentEdge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393'; var From d667a176f4815aa75749e6bd652767980616a47b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 15:38:09 +0800 Subject: [PATCH 1781/2794] madokami, fixed login and getinfo closed #585 #615 #613 --- baseunits/modules/Madokami.pas | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 2f2b69b9c..d325fa2c5 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -30,6 +30,7 @@ implementation ); var + madokamiauth: String = ''; locklogin: TRTLCriticalSection; function Login(const AHTTP: THTTPSendThread): Boolean; @@ -42,10 +43,9 @@ function Login(const AHTTP: THTTPSendThread): Boolean; Account.Status[modulename] := asChecking; AHTTP.Reset; AHTTP.Cookies.Clear; - AHTTP.Headers.Values['Authorization'] := - ' Basic ' + Base64Encode(Account.Username[modulename] + - ':' + Account.Password[modulename]); - if AHTTP.GET(urlroot + '/login') then begin + madokamiauth := 'Authorization: Basic ' + Base64Encode(Account.Username[modulename] + ':' + Account.Password[modulename]); + AHTTP.Headers.Add(madokamiauth); + if AHTTP.GET(urlroot) then begin //Result := AHTTP.Cookies.Values['laravel_session'] <> ''; Result := (AHTTP.ResultCode < 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ''); if Result then begin @@ -73,10 +73,21 @@ function Login(const AHTTP: THTTPSendThread): Boolean; AHTTP.Reset; end; +procedure SetAuth(const AHTTP: THTTPSendThread); +begin + AHTTP.Cookies.Text := Account.Cookies[modulename]; + if AHTTP.Cookies.Count <> 0 then + begin + if madokamiauth = '' then + madokamiauth := 'Authorization: Basic ' + Base64Encode(Account.Username[modulename] + ':' + Account.Password[modulename]); + AHTTP.Headers.Add(madokamiauth); + end; +end; + function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; begin Result := False; - AHTTP.Cookies.Text := Account.Cookies[modulename]; + SetAuth(AHTTP); AHTTP.FollowRedirection := False; Result := AHTTP.GET(AURL); if (AHTTP.ResultCode > 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ' Basic') then @@ -132,7 +143,7 @@ function GetInfo(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin + if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try From b486830ac71796336646e3e559d48904f807641a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 16:27:50 +0800 Subject: [PATCH 1782/2794] udata, tmangainformation, added ownerthread --- baseunits/uData.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 3048902ee..bb19fe1b3 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -77,6 +77,8 @@ TDataProcess = class(TObject) { TMangaInformation } TMangaInformation = class(TObject) + private + FOwner: TBaseThread; public isGetByUpdater: Boolean; mangaInfo: TMangaInfo; @@ -108,6 +110,7 @@ TMangaInformation = class(TObject) procedure AddInfoToData(const ATitle, ALink: String; const ADataProcess: TDBDataProcess); overload; //wrapper function GetPage(var AOutput: TObject; AURL: String; const AReconnect: Integer = 0): Boolean; inline; + property Thread: TBaseThread read FOwner; end; var @@ -716,6 +719,7 @@ procedure TDataProcess.Sort; constructor TMangaInformation.Create(AOwnerThread: TBaseThread; ACreateInfo: Boolean); begin inherited Create; + FOwner := AOwnerThread; FHTTP := THTTPSendThread.Create(AOwnerThread); FHTTP.Headers.NameValueSeparator := ':'; parse := TStringList.Create; From 441c2bab70fce24d171ae275145b8edb052d9f58 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 16:44:27 +0800 Subject: [PATCH 1783/2794] madokami, fixed update list #615 --- baseunits/modules/Madokami.pas | 94 +++++++++++++++++++++++++--------- 1 file changed, 71 insertions(+), 23 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index d325fa2c5..678810f6c 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -10,23 +10,23 @@ interface implementation +uses FMDVars; + const modulename = 'Madokami'; urlroot = 'https://manga.madokami.al'; - madokamidirlist: array [0..12] of String = ( - '/Manga/%23%20-%20F', - '/Manga/G%20-%20M', - '/Manga/N%20-%20Z', + madokamilist = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'; + madokamiotherlist: array [0..9] of String = ( '/Manga/_Autouploads/AutoUploaded%20from%20Assorted%20Sources', '/Manga/_Autouploads/ComicWalker', + '/Manga/Oneshots', '/Manga/Non-English/Bahasa%20Indonesia', '/Manga/Non-English/Brazilian%20Portuguese', + '/Manga/Non-English/Deutsch', '/Manga/Non-English/Fran%C3%A7ais', '/Manga/Non-English/Italian', '/Manga/Non-English/Russian', - '/Manga/Non-English/Spanish', - '/Manga/_Doujinshi', - '/Raws' + '/Manga/Non-English/Spanish' ); var @@ -101,37 +101,84 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; - Page := Length(madokamidirlist); + if Module.CurrentDirectoryIndex = 0 then + Page := Length(madokamilist) + else + Page := Length(madokamiotherlist); end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; + + procedure GetList; + var + v: IXQValue; + s: String; + begin + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try + for v in XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do + begin + s := v.toString; + if Length(s) > 1 then + begin + if s[Length(s)] = '/' then + SetLength(s, Length(s) - 1); + if LowerCase(LeftStr(s, 4)) = '.txt' then + s := ''; + end; + if s <> '' then + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(s); + end; + end; + finally + Free; + end; + end; + var - v: IXQValue; - currentdir: Integer; - s: String; + currentdir, i, j: Integer; + u: String; + l1, l2: TStringList; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); currentdir := StrToIntDef(AURL, 0); - if currentdir > Length(madokamidirlist) then Exit; - if MangaInfo.FHTTP.GET(Module.RootURL + madokamidirlist[currentdir]) then begin + u := Module.RootURL; + if Module.CurrentDirectoryIndex = 0 then begin + Inc(currentdir); + u += '/Manga/' + madokamilist[currentdir] + end + else + u += madokamiotherlist[currentdir]; + if GETWithLogin(MangaInfo.FHTTP, u) then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + if Module.CurrentDirectoryIndex = 0 then begin + l1 := TStringList.Create; + l2 := TStringList.Create; try - for v in XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - s := v.toString; - if Length(s) > 1 then - if s[Length(s)] = '/' then - SetLength(s, Length(s) - 1); - ANames.Add(s); + XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, l1); + for i := 0 to l1.Count - 1 do begin + if MangaInfo.Thread.IsTerminated then Break; + if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l1[i])) then begin + XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, l2); + for j := 0 to l2.Count - 1 do begin + if MangaInfo.Thread.IsTerminated then Break; + if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l2[j])) then begin + GetList; + end; + end; + end; end; finally - Free; + l1.Free; + l2.Free; end; + end + else + GetList; end; end; @@ -228,6 +275,7 @@ procedure RegisterModule; AccountSupport := True; MaxTaskLimit := 1; MaxConnectionLimit := 4; + TotalDirectory := 2; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From beaa0b4114ec79a3245114cb255a4b30f031827f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 16:50:15 +0800 Subject: [PATCH 1784/2794] replace mangakoi with mangahome closed #615 --- baseunits/ModuleList.inc | 2 +- baseunits/modules/{MangaKoi.pas => MangaHome.pas} | 4 ++-- config/mangalist.ini | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename baseunits/modules/{MangaKoi.pas => MangaHome.pas} (99%) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 3a733437b..34b3c7a26 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -16,7 +16,7 @@ uses KissManga, UnionMangas, MangaStreamTo, - MangaKoi, + MangaHome, GameofScanlation, Hakihome, MangaChanRU, diff --git a/baseunits/modules/MangaKoi.pas b/baseunits/modules/MangaHome.pas similarity index 99% rename from baseunits/modules/MangaKoi.pas rename to baseunits/modules/MangaHome.pas index 9fc0e5009..871dc2e29 100644 --- a/baseunits/modules/MangaKoi.pas +++ b/baseunits/modules/MangaHome.pas @@ -1,4 +1,4 @@ -unit MangaKoi; +unit MangaHome; {$mode objfpc}{$H+} @@ -157,7 +157,7 @@ procedure RegisterModule; begin with AddModule do begin - Website := 'MangaKoi'; + Website := 'MangaHome'; RootURL := 'http://www.mangahome.com'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/config/mangalist.ini b/config/mangalist.ini index 25853fe72..9bfadb38a 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaIce,MangaInn,MangaKoi,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 3e81463959f620130cd05947dafa7cd4ead9a021 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 19:11:31 +0800 Subject: [PATCH 1785/2794] mangamint removed, added mangatail and mangasail #closed #548 --- baseunits/ModuleList.inc | 1 + .../MangaMint/chapter_page_number.inc | 44 ------ .../MangaMint/directory_page_number.inc | 34 ----- baseunits/includes/MangaMint/image_url.inc | 44 ------ .../includes/MangaMint/manga_information.inc | 141 ------------------ .../includes/MangaMint/names_and_links.inc | 56 ------- baseunits/modules/MangaTail.pas | 133 +++++++++++++++++ baseunits/uBaseUnit.pas | 18 +-- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 10 -- changelog.txt | 9 ++ config/mangalist.ini | 4 +- 12 files changed, 153 insertions(+), 356 deletions(-) delete mode 100644 baseunits/includes/MangaMint/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaMint/directory_page_number.inc delete mode 100644 baseunits/includes/MangaMint/image_url.inc delete mode 100644 baseunits/includes/MangaMint/manga_information.inc delete mode 100644 baseunits/includes/MangaMint/names_and_links.inc create mode 100644 baseunits/modules/MangaTail.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 34b3c7a26..fa46163ad 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -55,6 +55,7 @@ uses EatManga, Taadd, NineManga, + MangaTail, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/MangaMint/chapter_page_number.inc b/baseunits/includes/MangaMint/chapter_page_number.inc deleted file mode 100644 index 212c8febb..000000000 --- a/baseunits/includes/MangaMint/chapter_page_number.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetMangaMintPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isExtractPage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - try - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(MANGAMINT_ID, URL)), - Task.Container.manager.retryConnect); - - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and (GetVal(parse[i], 'name') = 'manga_page') then - isExtractPage := True; - if isExtractPage then - begin - if GetTagName(parse[i]) = '/select' then - Break - else - if GetTagName(parse[i]) = 'option' then - Inc(Task.Container.PageNumber); - end; - end; - end; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/MangaMint/directory_page_number.inc b/baseunits/includes/MangaMint/directory_page_number.inc deleted file mode 100644 index 5221ac47d..000000000 --- a/baseunits/includes/MangaMint/directory_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetMangaMintDirectoryPageNumber: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAMINT_ID, 1] + - '/directory', 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - for i := parse.Count - 1 downto 0 do - if (GetTagName(parse[i]) = 'li') and (GetVal(parse[i], 'class') = 'pager-last last') then - begin - APage := StrToIntDef( - ReplaceRegExpr('^.*\?page=(\d+)$', GetVal(parse[i + 1], 'href'), '$1', True), 1); - Break; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaMint/image_url.inc b/baseunits/includes/MangaMint/image_url.inc deleted file mode 100644 index ddd07fa39..000000000 --- a/baseunits/includes/MangaMint/image_url.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetMangaMintImageURL: Boolean; - var - s: String; - i: Integer; - l: TStringList; - isExtractImage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - try - s := FillMangaSiteHost(MANGAMINT_ID, URL); - if WorkId > 0 then - s := s + '?page=' + IntToStr(WorkId); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'id') = 'images') then - isExtractImage := True; - if isExtractImage and (GetTagName(parse[i]) = 'img') then - begin - if Pos('src =', parse[i]) > 0 then - parse[i] := StringReplace(parse[i], 'src =', 'src=', []); - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/MangaMint/manga_information.inc b/baseunits/includes/MangaMint/manga_information.inc deleted file mode 100644 index 790c371a9..000000000 --- a/baseunits/includes/MangaMint/manga_information.inc +++ /dev/null @@ -1,141 +0,0 @@ - function GetMangaMintInfoFromURL: Byte; - var - i, j, p: Integer; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAMINT_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAMINT_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - - - if parse.Count > 0 then - begin - p := 0; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if GetTagName(parse[i]) = 'h2' then - mangaInfo.title := CommonStringFilter( - ReplaceRegExpr('\sManga$', Trim(parse[i + 1]), '', False)); - - //cover - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'class') = 'imagefield imagefield-field_image2') then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - if GetVal(parse[i], 'class') = 'field-label' then - begin - //status - if Pos('Status:', parse[i + 1]) > 0 then - begin - if (LowerCase(Trim(parse[i + 7])) = 'complete') then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end; - - //author - if Pos('Author:', parse[i + 1]) > 0 then - mangaInfo.authors := CommonStringFilter(parse[i + 7]); - - //artits - if Pos('Artist:', parse[i + 1]) > 0 then - mangaInfo.artists := CommonStringFilter(parse[i + 7]); - - //genre - if Pos('Type:', parse[i + 1]) > 0 then - mangaInfo.genres := Trim(parse[i + 7]); - end; - - //summary - if GetTagName(parse[i]) = '/fieldset' then - if GetTagName(parse[i + 2]) = 'p' then - mangaInfo.summary := CommonStringFilter(parse[i + 3]); - - //chapters - if (GetTagName(parse[i]) = 'thead') then - isExtractChapters := True; - if isExtractChapters then - begin - if GetTagName(parse[i]) = '/tbody' then - isExtractChapters := False - else - if GetTagName(parse[i]) = 'a' then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - - //morechapterspage - if (p = 0) and - (GetTagName(parse[i]) = 'li') and (GetVal(parse[i], 'class') = 'pager-last last') then - if GetTagName(parse[i + 1]) = 'a' then - p := StrToIntDef(ReplaceRegExpr('^.*\?page=(\d+)$', GetVal(parse[i + 1], 'href'), '$1', True), 0); - end; - Result := NO_ERROR; - end; - - //fetch chapters pages - if p > 0 then - for j := 1 to p do - begin - isExtractChapters := False; - Source.Clear; - if GetPage(TObject(Source), mangaInfo.url + '?page=' + IntToStr(j), AReconnect) then - begin - parse.Clear; - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'thead') then - isExtractChapters := True; - if isExtractChapters then - begin - if GetTagName(parse[i]) = '/tbody' then - isExtractChapters := False - else - if GetTagName(parse[i]) = 'a' then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - end; - finally - Parser.Free; - end; - Result := NO_ERROR; - end - else - Result := NET_PROBLEM; - end; - - //invert chapters - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Source.Free; - end; diff --git a/baseunits/includes/MangaMint/names_and_links.inc b/baseunits/includes/MangaMint/names_and_links.inc deleted file mode 100644 index a5052069a..000000000 --- a/baseunits/includes/MangaMint/names_and_links.inc +++ /dev/null @@ -1,56 +0,0 @@ - function MangaMintGetNamesAndLinks: Byte; - var - i: Integer; - isExtractNames: Boolean = False; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAMINT_ID, 1] + - '/directory?page=' + IntToStr(StrToInt(AURL) + 1), 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(Source.Text); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '\sManga$'; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'table') and (GetVal(parse[i], 'class') = 'sticky-enabled') then - isExtractNames := True; - if isExtractNames then - begin - if GetTagName(parse[i]) = '/table' then - Break - else - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'cover') then - if GetTagName(parse[i + 1]) = 'img' then - begin - ALinks.Add(GetVal(parse[i], 'href')); - ANames.Add(CommonStringFilter( - regx.Replace(Trim(GetVal(parse[i + 1], 'title')), '', False))); - end; - end; - end; - finally - regx.Free; - end; - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/modules/MangaTail.pas b/baseunits/modules/MangaTail.pas new file mode 100644 index 000000000..484508ef9 --- /dev/null +++ b/baseunits/modules/MangaTail.pas @@ -0,0 +1,133 @@ +unit MangaTail; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +uses FMDVars; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; + v: IXQValue; + i, x: Integer; +begin + Result := NET_PROBLEM; + s := Module.RootURL + '/directory'; + if AURL <> '0' then + s += '?page=' + AURL; + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try + i := 1; + for v in XPath('//ul[@class="pagination"]/li') do begin + x := StrToIntDef(v.toString, 1); + if x > i then i := x; + end; + updateList.CurrentDirectoryPageNumber := i - 1; + XPathHREFAll('//table[contains(@class,"directory_list")]//tr/td[1]/a', ALinks, ANames); + for i := 0 to ANames.Count - 1 do + begin + s := ANames[i]; + if RightStr(s, 6) = ' Manga' then + begin + SetLength(s, Length(s) - 6); + ANames[i] := s; + end; + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//*[@class="bookface"]/img/@src'); + if title = '' then begin + title := XPathString('//h1'); + if RightStr(title, 6) = ' Manga' then + SetLength(title, Length(title) - 6); + end; + status := MangaInfoStatusIfPos(XPathString('//*[contains(@class,"field-status")]')); + XPathHREFAll('//table[contains(@class,"chlist")]//tr/td[1]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + s := XPathStringAll('//iframe[contains(.,"field-name")]/substring-after(substring-before(.,"""}}"),":en"":""")', LineEnding); + if s <> '' then begin + s := StringReplace(s, '\n', LineEnding, [rfReplaceAll]); + s := StringReplace(s, '\', '', [rfReplaceAll]); + ParseHTML(s); + coverLink := XPathString('//img/@src'); + authors := XPathString('//*[contains(@class,"author")]/*[@class="field-items"]/string-join(.//text(),", ")'); + artists := XPathString('//*[contains(@class,"artist")]/*[@class="field-items"]/string-join(.//text(),", ")'); + genres := XPathString('//*[contains(@class,"genres")]/*[@class="field-items"]/string-join(.//text(),", ")'); + summary := XPathString('//*[contains(@class,"summary")]/*[@class="field-items"]//text()'); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL + '?page=all')) then + begin + Result := True; + XPathStringAll('//*[@id="images"]//img[not(contains(@src,"adsense"))]/@src', Document, PageLinks); + end; + end; +end; + +procedure RegisterModule; + + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + begin + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; + end; + +begin + AddWebsiteModule('MangaTail', 'http://www.mangatail.com'); + AddWebsiteModule('MangaSail', 'http://www.mangasail.com'); +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index dc3047479..fa349d419 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -263,15 +263,14 @@ interface MANGAOKU_ID = 30; IKOMIK_ID = 31; NHENTAI_ID = 32; - MANGAMINT_ID = 33; - UNIXMANGA_ID = 34; - EXTREMEMANGAS_ID = 35; - MANGAHOST_ID = 36; - MANGAKU_ID = 37; - MANGAAT_ID = 38; - DYNASTYSCANS_ID = 39; - - WebsiteRoots: array [0..39] of array [0..1] of String = ( + UNIXMANGA_ID = 33; + EXTREMEMANGAS_ID = 34; + MANGAHOST_ID = 35; + MANGAKU_ID = 36; + MANGAAT_ID = 37; + DYNASTYSCANS_ID = 38; + + WebsiteRoots: array [0..38] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), @@ -305,7 +304,6 @@ interface ('MangaOku', 'http://www.mangaoku.net'), ('I-Komik', 'http://www.i-komik.com'), ('NHentai', 'http://nhentai.net'), - ('MangaMint', 'http://www.mangamint.com'), ('UnixManga', 'http://unixmanga.co'), ('ExtremeMangas', 'http://www.extrememangas.com'), ('MangaHost', 'http://br.mangahost.com'), diff --git a/baseunits/uData.pas b/baseunits/uData.pas index bb19fe1b3..b828ee86e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -802,8 +802,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/NHentai/directory_page_number.inc} - {$I includes/MangaMint/directory_page_number.inc} - {$I includes/MangaHost/directory_page_number.inc} {$I includes/MangaAt/directory_page_number.inc} @@ -877,9 +875,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = NHENTAI_ID then Result := GetNHentaiDirectoryPageNumber else - if MangaSiteID = MANGAMINT_ID then - Result := GetMangaMintDirectoryPageNumber - else if MangaSiteID = MANGAHOST_ID then Result := GetMangaHostDirectoryPageNumber else @@ -968,8 +963,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/NHentai/names_and_links.inc} - {$I includes/MangaMint/names_and_links.inc} - {$I includes/UnixManga/names_and_links.inc} {$I includes/ExtremeMangas/names_and_links.inc} @@ -1084,9 +1077,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = NHENTAI_ID then Result := NHentaiNamesAndLinks else - if MangaSiteID = MANGAMINT_ID then - Result := MangaMintGetNamesAndLinks - else if MangaSiteID = UNIXMANGA_ID then Result := UnixMangaNamesAndLinks else @@ -1186,8 +1176,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/NHentai/manga_information.inc} - {$I includes/MangaMint/manga_information.inc} - {$I includes/UnixManga/manga_information.inc} {$I includes/ExtremeMangas/manga_information.inc} @@ -1313,9 +1301,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = NHENTAI_ID then Result := GetNHentaiInfoFromURL else - if MangaSiteID = MANGAMINT_ID then - Result := GetMangaMintInfoFromURL - else if MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c987c0ad0..b4379666f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -447,8 +447,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/NHentai/chapter_page_number.inc} - {$I includes/MangaMint/chapter_page_number.inc} - {$I includes/UnixManga/chapter_page_number.inc} {$I includes/ExtremeMangas/chapter_page_number.inc} @@ -526,9 +524,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiPageNumber else - if Task.Container.MangaSiteID = MANGAMINT_ID then - Result := GetMangaMintPageNumber - else if Task.Container.MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaPageNumber else @@ -609,8 +604,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/NHentai/image_url.inc} - {$I includes/MangaMint/image_url.inc} - {$I includes/UnixManga/image_url.inc} {$I includes/MangaHost/image_url.inc} @@ -705,9 +698,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiImageURL else - if Task.Container.MangaSiteID = MANGAMINT_ID then - Result := GetMangaMintImageURL - else if Task.Container.MangaSiteID = UNIXMANGA_ID then Result := GetUnixMangaImageURL else diff --git a/changelog.txt b/changelog.txt index 509df5e5a..8e75f41c1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.117.0 (future) +[*] Madokami: fixed +[-] MangaKoi: removed +[+] Added MangaHome[EN] +[-] MangaMint: removed +[+] Added MangaTail[EN] +[+] Added MangaSail[EN] +Full changes: https://github.com/riderkick/FMD/compare/0.9.118.0...0.9.118.0 + 0.9.117.0 (12-06-2017) [*] Fixed empty update url, you may need to download this version manually Full changes: https://github.com/riderkick/FMD/compare/0.9.116.0...0.9.117.0 diff --git a/config/mangalist.ini b/config/mangalist.ini index 9bfadb38a..1a11e9d58 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga @@ -13,7 +13,7 @@ Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas -Raw=MangaMint,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType +Raw=RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub From aac94173aaa72ab048dfa3047b7521d7052ea21c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 19:58:24 +0800 Subject: [PATCH 1786/2794] added option to minimize on start closed #574 --- changelog.txt | 1 + mangadownloader/forms/frmMain.lfm | 48 ++++++++++++++++---------- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 7 ++++ mangadownloader/languages/fmd.el_GR.po | 5 +++ mangadownloader/languages/fmd.en.po | 4 +++ mangadownloader/languages/fmd.es.po | 5 +++ mangadownloader/languages/fmd.id_ID.po | 6 +++- mangadownloader/languages/fmd.pl_PL.po | 5 +++ mangadownloader/languages/fmd.po | 4 +++ mangadownloader/languages/fmd.pt_BR.po | 5 +++ 11 files changed, 72 insertions(+), 19 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8e75f41c1..63cd70b0b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -11,6 +11,7 @@ Changelog: [-] MangaMint: removed [+] Added MangaTail[EN] [+] Added MangaSail[EN] +[+] Added option to minimize on start Full changes: https://github.com/riderkick/FMD/compare/0.9.118.0...0.9.118.0 0.9.117.0 (12-06-2017) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 3087fc190..ff3ecb3ce 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -38,10 +38,10 @@ object MainForm: TMainForm Height = 526 Top = 8 Width = 769 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient ParentFont = False - TabIndex = 0 + TabIndex = 3 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -2581,13 +2581,12 @@ object MainForm: TMainForm ClientWidth = 753 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime - AnchorSideTop.Control = seOptionNewMangaTime + AnchorSideTop.Control = cbOptionMinimizeOnStart AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 159 + Top = 182 Width = 106 - BorderSpacing.Top = 20 Caption = 'Minimize to tray' ParentFont = False TabOrder = 0 @@ -2598,7 +2597,7 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 182 + Top = 205 Width = 177 Caption = 'Permit only one FMD running' ParentFont = False @@ -2610,7 +2609,7 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 205 + Top = 228 Width = 210 Caption = 'Enable live search (slow on long list)' ParentFont = False @@ -2622,7 +2621,7 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 118 - Top = 244 + Top = 267 Width = 742 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 20 @@ -2815,6 +2814,19 @@ object MainForm: TMainForm ParentColor = False ParentFont = False end + object cbOptionMinimizeOnStart: TCheckBox + AnchorSideLeft.Control = seOptionNewMangaTime + AnchorSideTop.Control = seOptionNewMangaTime + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 19 + Top = 159 + Width = 112 + BorderSpacing.Top = 20 + Caption = 'Minimize on start' + ParentFont = False + TabOrder = 7 + end end object tsView: TTabSheet Caption = 'View' @@ -5309,8 +5321,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - Left = 128 - Top = 272 + Left = 382 + Top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5461,8 +5473,8 @@ object MainForm: TMainForm end object pmUpdate: TPopupMenu ParentBidiMode = False - Left = 128 - Top = 144 + Left = 382 + Top = 110 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5484,8 +5496,8 @@ object MainForm: TMainForm end end object IconList: TImageList - Left = 24 - Top = 136 + Left = 278 + Top = 102 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6227,8 +6239,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - Left = 24 - Top = 184 + Left = 278 + Top = 150 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6524,8 +6536,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - Left = 27 - Top = 268 + Left = 328 + Top = 238 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 3ce4a0465..799bf663e 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -151,6 +151,7 @@ {"hash":82521866,"name":"tmainform.lboptionlanguage.caption","sourcebytes":[76,97,110,103,117,97,103,101,58],"value":"Language:"}, {"hash":93623386,"name":"tmainform.lboptionletfmddo.caption","sourcebytes":[65,102,116,101,114,32,100,111,119,110,108,111,97,100,32,102,105,110,105,115,104,58],"value":"After download finish:"}, {"hash":160062057,"name":"tmainform.lboptionnewmangatime.caption","sourcebytes":[78,101,119,32,109,97,110,103,97,32,98,97,115,101,100,32,111,110,32,32,105,116,39,115,32,117,112,100,97,116,101,32,116,105,109,101,32,40,100,97,121,115,41],"value":"New manga based on it's update time (days)"}, +{"hash":69131508,"name":"tmainform.cboptionminimizeonstart.caption","sourcebytes":[77,105,110,105,109,105,122,101,32,111,110,32,115,116,97,114,116],"value":"Minimize on start"}, {"hash":380871,"name":"tmainform.tsview.caption","sourcebytes":[86,105,101,119],"value":"View"}, {"hash":126054082,"name":"tmainform.cboptionshowdownloadtoolbar.caption","sourcebytes":[83,104,111,119,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show downloads toolbar"}, {"hash":157437400,"name":"tmainform.gbdroptarget.caption","sourcebytes":[68,114,111,112,32,66,111,120],"value":"Drop Box"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3b4a1c2dd..ae8cb0085 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -54,6 +54,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionAutoOpenFavStartup: TCheckBox; cbOptionEnableLoadCover: TCheckBox; + cbOptionMinimizeOnStart: TCheckBox; cbOptionShowBalloonHint: TCheckBox; cbOptionGenerateChapterFolder: TCheckBox; cbOptionRemoveMangaNameFromChapter: TCheckBox; @@ -1234,6 +1235,10 @@ procedure TMainForm.FormCreate(Sender: TObject); LoadOptions; ApplyOptions; + // minimize on start + if cbOptionMinimizeOnStart.Checked then + Application.ShowMainForm := False; + // hint ShowHint := True; Application.HintPause := 500; @@ -4614,6 +4619,7 @@ procedure TMainForm.LoadOptions; // general cbOptionOneInstanceOnly.Checked := ReadBool('general', 'OneInstanceOnly', True); cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); + cbOptionMinimizeOnStart.Checked := ReadBool('general', 'MinimizeOnStart', False); cbOptionMinimizeToTray.Checked := ReadBool('general', 'MinimizeToTray', False); cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); edOptionExternalPath.Text := ReadString('general', 'ExternalProgramPath', ''); @@ -4757,6 +4763,7 @@ procedure TMainForm.SaveOptions; WriteBool('general', 'OneInstanceOnly', cbOptionOneInstanceOnly.Checked); if cbLanguages.ItemIndex > -1 then WriteString('languages', 'Selected', AvailableLanguages.Names[cbLanguages.ItemIndex]); + WriteBool('general', 'MinimizeOnStart', cbOptionMinimizeOnStart.Checked); WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); WriteString('general', 'ExternalProgramPath', edOptionExternalPath.Text); diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 04f73d9cb..13064966e 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -670,6 +670,10 @@ msgstr "Αυτόματη δημιουργία φακέλου βάσει του msgid "Enable live search (slow on long list)" msgstr "Ενεργοποίηση ζωντανής αναζήτησης (αργή σε μεγάλη λίστα)" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Ελαχιστοποίηση στην περιοχή ειδοποιήσεωνMinimize to tray" @@ -2272,3 +2276,4 @@ msgstr "Συγχρονισμός δεδομένων" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Ενημέρωση λίστας" + diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 55a53471b..b56da1e6f 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -673,6 +673,10 @@ msgstr "Auto generate folder based on manga's name" msgid "Enable live search (slow on long list)" msgstr "Enable live search (slow on long list)" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "Minimize on start" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Minimize to tray" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index a3ee936d3..e472d9c76 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -656,6 +656,10 @@ msgstr "Auto Generar Folder Basado en Nombre del Manga" msgid "Enable live search (slow on long list)" msgstr "Habilitar Búsqueda en Directo (Lento en Lista Larga)" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Minimizar a Bandeja" @@ -2200,3 +2204,4 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 30f502733..9ecaeee1d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -586,7 +586,7 @@ msgstr "Kunjungi blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -661,6 +661,10 @@ msgstr "Buat otomatis folder berdasarkan nama komik" msgid "Enable live search (slow on long list)" msgstr "Aktifkan pencarian langsung (lambat dengan daftar yang panjang)" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "Kecilkan ke penampan saat dimulai" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Perkecil ke penampan" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 1357eae75..886d88959 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -668,6 +668,10 @@ msgstr "Automatyczne generowanie folderu używając nazwy mangi" msgid "Enable live search (slow on long list)" msgstr "Włącz wyszukiwanie na żywo (wolne w przypadku długiej lisy)" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Zminimalizuj do zasobnika" @@ -2221,3 +2225,4 @@ msgstr "Synchronizacja danych" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Aktualizacja listy" + diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 64d4776d0..3a9425793 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -621,6 +621,10 @@ msgstr "" msgid "Enable live search (slow on long list)" msgstr "" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index bc3cd6b48..17b6cd0e6 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -668,6 +668,10 @@ msgstr "Auto-gerar pasta com o nome do mangá" msgid "Enable live search (slow on long list)" msgstr "Habilitar buscar em tempo real (lento em lista longas)" +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "" + #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" msgstr "Minimizar para bandeja" @@ -2219,3 +2223,4 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" + From c4df447378f22c199e92fe9a6dce6b1137bc654c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 20:00:38 +0800 Subject: [PATCH 1787/2794] formmain, default downloads --- mangadownloader/forms/frmMain.lfm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index ff3ecb3ce..ae3ba7557 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -38,10 +38,10 @@ object MainForm: TMainForm Height = 526 Top = 8 Width = 769 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient ParentFont = False - TabIndex = 3 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet From c5a90c169cfb466a7b330a4bb2d8c089c97f5381 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 20:35:49 +0800 Subject: [PATCH 1788/2794] manga-tr, fixed chapter list fixed #399 --- baseunits/modules/MangaTr.pas | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index 2c2991d23..9121180c4 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -82,7 +82,18 @@ function GetInfo(const MangaInfo: TMangaInformation; summary := XPathString('//div[@class="well"]/p'); v := XPath('//table[4]/tbody/tr/td/a'); if v.Count = 0 then v := XPath('//table[3]/tbody/tr/td/a'); - if v.Count > 0 then + if v.Count = 0 then begin + s := XPathString('//*[@slug]/@slug'); + if s <> '' then begin + MangaInfo.FHTTP.Reset; + MangaInfo.FHTTP.Headers.Add('X-Requested-With: XMLHttpRequest'); + if MangaInfo.FHTTP.GET(Module.RootURL+'/cek/fetch_pages_manga.php?manga_cek='+s) then begin + ParseHTML(MangaInfo.FHTTP.Document); + v := XPath('//tr/td[1]/a'); + end; + end; + end; + if v.Count <> 0 then begin for i := 1 to v.Count do begin chapterLinks.Add(v.get(i).toNode.getAttribute('href')); From 2c18e35dc9e6add8c41992226051ddb098c0330c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 21:50:55 +0800 Subject: [PATCH 1789/2794] gmanga, fixed all closed #414 --- baseunits/modules/GMangaMe.pas | 62 ++++++++++------------------------ changelog.txt | 6 ++-- 2 files changed, 21 insertions(+), 47 deletions(-) diff --git a/baseunits/modules/GMangaMe.pas b/baseunits/modules/GMangaMe.pas index b66316038..00b2e47ea 100644 --- a/baseunits/modules/GMangaMe.pas +++ b/baseunits/modules/GMangaMe.pas @@ -37,8 +37,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - v, x: IXQValue; - s, t: String; + v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -49,27 +48,19 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//div/img[starts-with(@class,"img-responsive")]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@class="section-title en-text-center"]'); - summary := XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dd[contains(@class,"summary")]'); - authors := XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dt[.="المؤلفون"]/following-sibling::dd[1]'); - artists := XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dt[.="الرسامون"]/following-sibling::dd[1]'); - genres := XPathStringAll('//div/dl[starts-with(@class,"dl-horizontal")]/dt[.="التصنيف"]/following-sibling::dd[1]/span'); - status := MangaInfoStatusIfPos(XPathString('//div/dl[starts-with(@class,"dl-horizontal")]/dt[ends-with(.,"الـمانهوا")]/following-sibling::dd[1]'), + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div/img[starts-with(@class,"img-responsive")]/@src')); + if title = '' then title := XPathString('//div[@class="content-div"]/h2'); + summary := XPathString('//div[@class="content-div"]/div[@class="summary"]/text()'); + authors := XPathString('//label[starts-with(.,"المؤلفون")]/following-sibling::*'); + artists := XPathString('//label[starts-with(.,"الرسامون")]/following-sibling::*'); + genres := XPathStringAll('//label[starts-with(.,"التصنيفات")]/following-sibling::*//a'); + status := MangaInfoStatusIfPos(XPathString('//label[starts-with(.,"حالة القصة")]/following-sibling::*'), 'مستمرة', 'منتهية'); - for v in XPath('//table[1]/tbody/tr') do + for v in XPath('//tr/td[./a[@class="chapter-link"]]') do begin - s := XPathString('td/div[@class="c_edit"]', v.toNode); - for x in XPath('td/span[@dir="ltr"]/a', v.toNode) do - begin - chapterLinks.Add(x.toNode.getAttribute('href')); - t := x.toString; - if t <> '' then - t := ' [' + t + ']'; - chapterName.Add(s + t); - end; + chapterLinks.Add(XPathString('./a/@href', v)); + chapterName.Add(XPathString('../td[1]', v)); end; InvertStrings([chapterLinks, chapterName]); finally @@ -82,10 +73,7 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - source: TStringList; - i: Integer; - images: String; - v: IXQValue; + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -96,28 +84,12 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - images := ''; - source := TStringList.Create; - try - source.LoadFromStream(Document); - if source.Count > 0 then - for i := 0 to source.Count - 1 do - if Pos('chapterImgs = [', source[i]) <> 0 then - begin - images := SeparateRight(source[i], '['); - Break; - end; - finally - source.Free; + s := XPathString('//script[contains(.,"var release_pages")]/substring-before(substring-after(substring-after(.,"var release_pages"), "(["), "]")', Document); + if s <> '' then + begin + s := StringReplace(s, '"', '', [rfReplaceAll]); + PageLinks.CommaText := s; end; - if images <> '' then - with TXQueryEngineHTML.Create('[' + images) do - try - for v in XPath('json(*)()') do - PageLinks.Add(v.toString); - finally - Free; - end; end; end; end; diff --git a/changelog.txt b/changelog.txt index 63cd70b0b..dbec9f9e4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,14 +5,16 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.117.0 (future) -[*] Madokami: fixed +[*] Madokami: fixed all [-] MangaKoi: removed [+] Added MangaHome[EN] [-] MangaMint: removed [+] Added MangaTail[EN] [+] Added MangaSail[EN] [+] Added option to minimize on start -Full changes: https://github.com/riderkick/FMD/compare/0.9.118.0...0.9.118.0 +[*] Manga-Tr: fixed all +[*] GManga: fixed all +Full changes: https://github.com/riderkick/FMD/compare/0.9.117.0...0.9.118.0 0.9.117.0 (12-06-2017) [*] Fixed empty update url, you may need to download this version manually From 6dc3260675a9fbd1fb6faa83340fab1b40324527 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 22:30:42 +0800 Subject: [PATCH 1790/2794] truyentranhtuan, rewrite all #491 --- baseunits/ModuleList.inc | 1 + .../includes/TruyenTranhTuan/image_url.inc | 39 ------ .../TruyenTranhTuan/manga_information.inc | 120 ------------------ .../TruyenTranhTuan/names_and_links.inc | 38 ------ baseunits/modules/TruyenTranhTuan.pas | 109 ++++++++++++++++ baseunits/uBaseUnit.pas | 74 +++++------ baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 5 - 8 files changed, 145 insertions(+), 251 deletions(-) delete mode 100644 baseunits/includes/TruyenTranhTuan/image_url.inc delete mode 100644 baseunits/includes/TruyenTranhTuan/manga_information.inc delete mode 100644 baseunits/includes/TruyenTranhTuan/names_and_links.inc create mode 100644 baseunits/modules/TruyenTranhTuan.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index fa46163ad..0f41706f0 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -56,6 +56,7 @@ uses Taadd, NineManga, MangaTail, + TruyenTranhTuan, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/TruyenTranhTuan/image_url.inc b/baseunits/includes/TruyenTranhTuan/image_url.inc deleted file mode 100644 index 302c7af5a..000000000 --- a/baseunits/includes/TruyenTranhTuan/image_url.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetTruyenTranhTuanImageURL: Boolean; - var - s, s2: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(TRUYENTRANHTUAN_ID, URL), - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('var slides_page = ["', parse[i]) > 0 then - begin - s := parse[i]; - repeat - j := Pos('"/manga/', s); - s2 := EncodeUrl(WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + '/manga/' + - GetString(s, '"/manga/', '"')); - Task.Container.PageLinks.Add(s2); - Delete(s, Pos('"/manga/', s), 10); - j := Pos('"/manga/', s); - until j = 0; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/TruyenTranhTuan/manga_information.inc b/baseunits/includes/TruyenTranhTuan/manga_information.inc deleted file mode 100644 index ef7fbcd65..000000000 --- a/baseunits/includes/TruyenTranhTuan/manga_information.inc +++ /dev/null @@ -1,120 +0,0 @@ - function GetTruyenTranhTuanInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(TRUYENTRANHTUAN_ID, AURL);// + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[TRUYENTRANHTUAN_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse[i]) = 'meta') and - (Pos('property="og:image"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'content')); - - // get summary - if (Pos('id="manga-summary"', parse[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := Trim(StringFilter(GetString('~!@' + parse[i + 1], - '~!@', ' - Truyện tranh online - truyentranhtuan.com'))); - - // get chapter name and links - if (Pos('class="chapter-name"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetString(parse[i + 2], 'href="', '"'); - s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse[i + 3])); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - // get authors - if (i + 1 < parse.Count) and (Pos('Tác giả:', parse[i]) <> 0) then - mangaInfo.authors := Trim(parse[i + 2]); - - // get artists - //if (i+1<parse.Count) AND (Pos('/search/artist/', parse[i])<>0) then - // mangaInfo.artists:= TrimLeft(parse[i+1]); - - // get genres - if (Pos('Thể loại:', parse[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if Pos('<a href=', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse[i + 1])) + ', '; - if Pos('</span>', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 5 < parse.Count) and (Pos('Chương mới nhất', parse[i]) <> 0) then - begin - if Pos('dang-tien-hanh', parse[i + 1]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/TruyenTranhTuan/names_and_links.inc b/baseunits/includes/TruyenTranhTuan/names_and_links.inc deleted file mode 100644 index 3ecbe4455..000000000 --- a/baseunits/includes/TruyenTranhTuan/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function TruyenTranhTuanGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[TRUYENTRANHTUAN_ID, 1] + - TRUYENTRANHTUAN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('class="manga"', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - ANames.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i + 1], 'href'); - s := StringReplace(s, WebsiteRoots[TRUYENTRANHTUAN_ID, 1], '', []); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/modules/TruyenTranhTuan.pas b/baseunits/modules/TruyenTranhTuan.pas new file mode 100644 index 000000000..4c8cdd9ea --- /dev/null +++ b/baseunits/modules/TruyenTranhTuan.pas @@ -0,0 +1,109 @@ +unit TruyenTranhTuan; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +uses FMDVars; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + i, x: Integer; + s: String; +begin + Result := NET_PROBLEM; + s := Module.RootURL; + if AURL <> '0' then + s += '/page/' + IncStr(AURL); + if MangaInfo.FHTTP.GET(s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try + i := 1; + for v in XPath('//*[@id="page-nav"]//li') do begin + x := StrToIntDef(v.toString, 1); + if x > i then i := x; + end; + updateList.CurrentDirectoryPageNumber := i; + XPathHREFAll('//*[@id="story-list"]/div/span[1]/a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//*[@class="manga-cover"]/img/@src'); + if title = '' then title := XPathString('//h1[@itemprop="name"]'); + authors := XPathString('//p[@class="misc-infor" and starts-with(.,"Tác giả")]/string-join(./a,", ")'); + genres := XPathString('//p[@class="misc-infor" and starts-with(.,"Thể loại")]/string-join(./a,", ")'); + summary := XPathString('//*[@id="manga-summary"]/p'); + XPathHREFAll('//*[@id="manga-chapter"]//*[@class="chapter-name"]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + s := XPathString('//script[contains(.,"var slides_page_path")]/substring-before(substring-after(substring-after(.,"var slides_page_path"),"["),"]")', Document); + if s = '' then + s := XPathString('//script[contains(.,"var slides_page_url_path")]/substring-before(substring-after(substring-after(.,"var slides_page_url_path"),"["),"]")', Document); + if s <> '' then begin + s := StringReplace(s, '"', '', [rfReplaceAll]); + PageLinks.CommaText := s; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'TruyenTranhTuan'; + RootURL := 'http://truyentranhtuan.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fa349d419..9087faf09 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -235,48 +235,46 @@ interface MANGA24H_ID = 2; VNSHARING_ID = 3; TRUYEN18_ID = 4; - TRUYENTRANHTUAN_ID = 5; - TURKCRAFT_ID = 6; - STARKANA_ID = 7; - BLOGTRUYEN_ID = 8; - ESMANGAHERE_ID = 9; - ANIMEEXTREMIST_ID = 10; - S2SCAN_ID = 11; - IMANHUA_ID = 12; - CENTRALDEMANGAS_ID = 13; - EGSCANS_ID = 14; - MANGAAR_ID = 15; - MANGAAE_ID = 16; - ANIMESTORY_ID = 17; - LECTUREENLIGNE_ID = 18; - SCANMANGA_ID = 19; - DM5_ID = 20; - KIVMANGA_ID = 21; - MEINMANGA_ID = 22; - MANGASPROJECT_ID = 23; - MANGAREADER_POR_ID = 24; - JAPANSHIN_ID = 25; - CENTRUMMANGI_PL_ID = 26; - MANGALIB_PL_ID = 27; - ONEMANGA_ID = 28; - MANGATOWN_ID = 29; - MANGAOKU_ID = 30; - IKOMIK_ID = 31; - NHENTAI_ID = 32; - UNIXMANGA_ID = 33; - EXTREMEMANGAS_ID = 34; - MANGAHOST_ID = 35; - MANGAKU_ID = 36; - MANGAAT_ID = 37; - DYNASTYSCANS_ID = 38; - - WebsiteRoots: array [0..38] of array [0..1] of String = ( + TURKCRAFT_ID = 5; + STARKANA_ID = 6; + BLOGTRUYEN_ID = 7; + ESMANGAHERE_ID = 8; + ANIMEEXTREMIST_ID = 9; + S2SCAN_ID = 10; + IMANHUA_ID = 11; + CENTRALDEMANGAS_ID = 12; + EGSCANS_ID = 13; + MANGAAR_ID = 14; + MANGAAE_ID = 15; + ANIMESTORY_ID = 16; + LECTUREENLIGNE_ID = 17; + SCANMANGA_ID = 18; + DM5_ID = 19; + KIVMANGA_ID = 20; + MEINMANGA_ID = 21; + MANGASPROJECT_ID = 22; + MANGAREADER_POR_ID = 23; + JAPANSHIN_ID = 24; + CENTRUMMANGI_PL_ID = 25; + MANGALIB_PL_ID = 26; + ONEMANGA_ID = 27; + MANGATOWN_ID = 28; + MANGAOKU_ID = 29; + IKOMIK_ID = 30; + NHENTAI_ID = 31; + UNIXMANGA_ID = 32; + EXTREMEMANGAS_ID = 33; + MANGAHOST_ID = 34; + MANGAKU_ID = 35; + MANGAAT_ID = 36; + DYNASTYSCANS_ID = 37; + + WebsiteRoots: array [0..37] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Truyen18', 'http://www.truyen18.org'), - ('TruyenTranhTuan', 'http://truyentranhtuan.com'), ('Turkcraft', 'http://turkcraft.com'), ('Starkana', 'http://starkana.jp'), ('BlogTruyen', 'http://blogtruyen.com'), @@ -325,8 +323,6 @@ interface TRUYEN18_ROOT = 'http://www.truyen18.org'; TRUYEN18_BROWSER = '/moi-dang/danhsach'; - TRUYENTRANHTUAN_BROWSER = '/danh-sach-truyen'; - TURKCRAFT_BROWSER = '/'; STARKANA_BROWSER = '/manga/list'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b828ee86e..b3ba1f355 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -913,8 +913,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/VnSharing/names_and_links.inc} - {$I includes/TruyenTranhTuan/names_and_links.inc} - {$I includes/AnimeStory/names_and_links.inc} {$I includes/LectureEnLigne/names_and_links.inc} @@ -1011,9 +1009,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = BLOGTRUYEN_ID then Result := BlogTruyenGetNamesAndLinks else - if MangaSiteID = TRUYENTRANHTUAN_ID then - Result := TruyenTranhTuanGetNamesAndLinks - else if MangaSiteID = ESMANGAHERE_ID then Result := EsMangaHereGetNamesAndLinks else @@ -1134,8 +1129,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/EGScans/manga_information.inc} - {$I includes/TruyenTranhTuan/manga_information.inc} - {$I includes/AnimeStory/manga_information.inc} {$I includes/LectureEnLigne/manga_information.inc} @@ -1232,9 +1225,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = EGSCANS_ID then Result := GetEGScansInfoFromURL else - if MangaSiteID = TRUYENTRANHTUAN_ID then - Result := GetTruyenTranhTuanInfoFromURL - else if MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b4379666f..252f41b61 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -578,8 +578,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Starkana/image_url.inc} - {$I includes/TruyenTranhTuan/image_url.inc} - {$I includes/Turkcraft/image_url.inc} {$I includes/VnSharing/image_url.inc} @@ -656,9 +654,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else - if Task.Container.MangaSiteID = TRUYENTRANHTUAN_ID then - Result := GetTruyenTranhTuanImageURL - else if Task.Container.MangaSiteID = BLOGTRUYEN_ID then Result := GetBlogTruyenImageURL else From ff8d23131aea0fd368e6ea136ddb5993af840704 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 22:35:53 +0800 Subject: [PATCH 1791/2794] manga24h, removed #491 --- .../Manga24h/directory_page_number.inc | 36 ----- baseunits/includes/Manga24h/image_url.inc | 31 ---- .../includes/Manga24h/manga_information.inc | 136 ------------------ .../includes/Manga24h/names_and_links.inc | 38 ----- baseunits/uBaseUnit.pas | 78 +++++----- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 5 - changelog.txt | 1 + 8 files changed, 38 insertions(+), 302 deletions(-) delete mode 100644 baseunits/includes/Manga24h/directory_page_number.inc delete mode 100644 baseunits/includes/Manga24h/image_url.inc delete mode 100644 baseunits/includes/Manga24h/manga_information.inc delete mode 100644 baseunits/includes/Manga24h/names_and_links.inc diff --git a/baseunits/includes/Manga24h/directory_page_number.inc b/baseunits/includes/Manga24h/directory_page_number.inc deleted file mode 100644 index 5edda3a3c..000000000 --- a/baseunits/includes/Manga24h/directory_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetManga24hDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + - MANGA24H_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('Pages (', parse[i]) > 0) then - begin - s := GetString(parse[i], 'Pages (', ')'); - APage := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Manga24h/image_url.inc b/baseunits/includes/Manga24h/image_url.inc deleted file mode 100644 index 5861afb8c..000000000 --- a/baseunits/includes/Manga24h/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetManga24hImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(MANGA24H_ID, URL), - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'img') and - (Pos('style="border:3px', parse[i]) <> 0) then - // (GetVal(parse[i], 'class') = 'm_picture') then - begin - Task.Container.PageLinks.Add(GetVal(parse[i], 'src')); - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Manga24h/manga_information.inc b/baseunits/includes/Manga24h/manga_information.inc deleted file mode 100644 index 2b4cb903a..000000000 --- a/baseunits/includes/Manga24h/manga_information.inc +++ /dev/null @@ -1,136 +0,0 @@ - function GetManga24hInfoFromURL: Byte; - var - // patchURL, - s: String; - i, j: Cardinal; - isExtractChapters: Boolean = False; - isExtractSummary: Boolean = False; - begin - // patchURL:= UTF8ToANSI(AURL); - // Insert('comics/', patchURL, 10); - mangaInfo.url := FillMangaSiteHost(MANGA24H_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGA24H_ID, 0]; - mangaInfo.summary := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover link - if (Pos('class="img-rounded', parse[i]) > 0) then - begin - mangaInfo.coverLink := EncodeURL(GetVal(parse[i], 'src')); - s := mangaInfo.coverLink; - end; - - // get summary - if (Pos('"clearfix"', parse[i]) > 0) and - (Pos('<p>', parse[i + 3]) > 0) then - begin - j := i + 5; - mangaInfo.summary := ''; - while (Pos('$(document).ready(function()', parse[j]) = 0) and - (j < parse.Count - 1) do - begin - s := parse[j]; - if (Length(s) > 0) and (s[1] <> '<') then - begin - parse[j] := StringFilter(HTMLEntitiesFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + - StringFilter(TrimRight(TrimLeft(parse[j]))); - end; - Inc(j); - end; - end; - - if (Pos('<tbody>', parse[i]) <> 0) and (not isExtractSummary) then - isExtractChapters := True; - - if (Pos('</tbody>', parse[i]) <> 0) and (isExtractSummary) then - isExtractChapters := False; - - - // get chapter name and links - if (isExtractChapters) and - (Pos('<td>', parse[i]) <> 0) and - (GetVal(parse[i + 1], 'href') <> '') and - (Pos('</a>', parse[i + 3]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - CorrectURL('/' + StringReplace(GetVal(parse[i + 1], 'href'), WebsiteRoots[MANGA24H_ID, 1], - '', [rfReplaceAll]))); - parse[i + 2] := HTMLEntitiesFilter(parse[i + 2]); - parse[i + 2] := StringReplace(parse[i + 2], #10, '', [rfReplaceAll]); - parse[i + 2] := StringReplace(parse[i + 2], #13, '', [rfReplaceAll]); - parse[i + 2] := TrimLeft(parse[i + 2]); - mangaInfo.chapterName.Add( - StringFilter(TrimRight(RemoveSymbols(parse[i + 2])))); - end; - - // get title - if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - StringFilter(GetString('~!@' + parse[i + 1], '~!@', ' - Truyen Tranh Online'))); - - // get authors - if (Pos('Tác giả :', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(StringFilter(parse[i + 3])); - - // get artists - if (Pos('Họa sỹ :', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(StringFilter(parse[i + 3])); - - // get genres - if (Pos('Thể loại :', parse[i]) <> 0) then - begin - mangaInfo.genres := ''; - for j := 0 to 37 do - if Pos(LowerCase(defaultGenres[j]), LowerCase(parse[i + 4])) <> 0 then - mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); - end; - - // get status - if (Pos('Tình Trạng:', parse[i]) <> 0) then - begin - if Pos('Hoàn Thành', parse[i + 4]) <> 0 then - mangaInfo.status := '0' // ongoing - else - mangaInfo.status := '1'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Manga24h/names_and_links.inc b/baseunits/includes/Manga24h/names_and_links.inc deleted file mode 100644 index 82b47cdbc..000000000 --- a/baseunits/includes/Manga24h/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function Manga24hGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGA24H_ID, 1] + - MANGA24H_BROWSER + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 3 do - begin - if (Pos('<b>', parse[i]) <> 0) and - (Pos('</b>', parse[i + 2]) <> 0) and - (GetVal(parse[i - 1], 'href') <> '') then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - ANames.Add(s); - ALinks.Add('/' + StringReplace(GetVal(parse[i - 1], 'href'), WebsiteRoots[MANGA24H_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 9087faf09..5f0e52ef7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -232,47 +232,45 @@ interface ANIMEA_ID = 0; OURMANGA_ID = 1; - MANGA24H_ID = 2; - VNSHARING_ID = 3; - TRUYEN18_ID = 4; - TURKCRAFT_ID = 5; - STARKANA_ID = 6; - BLOGTRUYEN_ID = 7; - ESMANGAHERE_ID = 8; - ANIMEEXTREMIST_ID = 9; - S2SCAN_ID = 10; - IMANHUA_ID = 11; - CENTRALDEMANGAS_ID = 12; - EGSCANS_ID = 13; - MANGAAR_ID = 14; - MANGAAE_ID = 15; - ANIMESTORY_ID = 16; - LECTUREENLIGNE_ID = 17; - SCANMANGA_ID = 18; - DM5_ID = 19; - KIVMANGA_ID = 20; - MEINMANGA_ID = 21; - MANGASPROJECT_ID = 22; - MANGAREADER_POR_ID = 23; - JAPANSHIN_ID = 24; - CENTRUMMANGI_PL_ID = 25; - MANGALIB_PL_ID = 26; - ONEMANGA_ID = 27; - MANGATOWN_ID = 28; - MANGAOKU_ID = 29; - IKOMIK_ID = 30; - NHENTAI_ID = 31; - UNIXMANGA_ID = 32; - EXTREMEMANGAS_ID = 33; - MANGAHOST_ID = 34; - MANGAKU_ID = 35; - MANGAAT_ID = 36; - DYNASTYSCANS_ID = 37; - - WebsiteRoots: array [0..37] of array [0..1] of String = ( + VNSHARING_ID = 2; + TRUYEN18_ID = 3; + TURKCRAFT_ID = 4; + STARKANA_ID = 5; + BLOGTRUYEN_ID = 6; + ESMANGAHERE_ID = 7; + ANIMEEXTREMIST_ID = 8; + S2SCAN_ID = 9; + IMANHUA_ID = 10; + CENTRALDEMANGAS_ID = 11; + EGSCANS_ID = 12; + MANGAAR_ID = 13; + MANGAAE_ID = 14; + ANIMESTORY_ID = 15; + LECTUREENLIGNE_ID = 16; + SCANMANGA_ID = 17; + DM5_ID = 18; + KIVMANGA_ID = 19; + MEINMANGA_ID = 20; + MANGASPROJECT_ID = 21; + MANGAREADER_POR_ID = 22; + JAPANSHIN_ID = 23; + CENTRUMMANGI_PL_ID = 24; + MANGALIB_PL_ID = 25; + ONEMANGA_ID = 26; + MANGATOWN_ID = 27; + MANGAOKU_ID = 28; + IKOMIK_ID = 29; + NHENTAI_ID = 30; + UNIXMANGA_ID = 31; + EXTREMEMANGAS_ID = 32; + MANGAHOST_ID = 33; + MANGAKU_ID = 34; + MANGAAT_ID = 35; + DYNASTYSCANS_ID = 36; + + WebsiteRoots: array [0..36] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), - ('Manga24h', 'http://manga24h.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Truyen18', 'http://www.truyen18.org'), ('Turkcraft', 'http://turkcraft.com'), @@ -316,8 +314,6 @@ interface ANIMEA_BROWSER = '/browse.html?page='; ANIMEA_SKIP = '?skip=1'; - MANGA24H_BROWSER = '/manga/update/page/'; - VNSHARING_BROWSER = '/DanhSach'; TRUYEN18_ROOT = 'http://www.truyen18.org'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b3ba1f355..762b12ed9 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -776,8 +776,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/AnimeA/directory_page_number.inc} - {$I includes/Manga24h/directory_page_number.inc} - {$I includes/VnSharing/directory_page_number.inc} {$I includes/BlogTruyen/directory_page_number.inc} @@ -836,9 +834,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = ANIMEA_ID then Result := GetAnimeADirectoryPageNumber else - if MangaSiteID = MANGA24H_ID then - Result := GetManga24hDirectoryPageNumber - else if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else @@ -909,8 +904,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/AnimExtremist/names_and_links.inc} - {$I includes/Manga24h/names_and_links.inc} - {$I includes/VnSharing/names_and_links.inc} {$I includes/AnimeStory/names_and_links.inc} @@ -988,9 +981,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = ANIMEA_ID then Result := AnimeAGetNamesAndLinks else - if MangaSiteID = MANGA24H_ID then - Result := Manga24hGetNamesAndLinks - else if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else @@ -1119,8 +1109,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/AnimExtremist/manga_information.inc} - {$I includes/Manga24h/manga_information.inc} - {$I includes/VnSharing/manga_information.inc} {$I includes/Starkana/manga_information.inc} @@ -1210,9 +1198,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = ANIMEA_ID then Result := GetAnimeAInfoFromURL else - if MangaSiteID = MANGA24H_ID then - Result := GetManga24hInfoFromURL - else if MangaSiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 252f41b61..8e023a259 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -564,8 +564,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Kivmanga/image_url.inc} - {$I includes/Manga24h/image_url.inc} - {$I includes/MangaAe/image_url.inc} {$I includes/MangaAr/image_url.inc} @@ -618,9 +616,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMEA_ID then Result := GetAnimeAImageURL else - if Task.Container.MangaSiteID = MANGA24H_ID then - Result := GetManga24hImageURL - else if Task.Container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else diff --git a/changelog.txt b/changelog.txt index dbec9f9e4..6a3b2822d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -14,6 +14,7 @@ Changelog: [+] Added option to minimize on start [*] Manga-Tr: fixed all [*] GManga: fixed all +[*] TruyenTranhTuan: fixed all Full changes: https://github.com/riderkick/FMD/compare/0.9.117.0...0.9.118.0 0.9.117.0 (12-06-2017) From 5fd90beaf0527a8bd41ec1689d80d1cfc605db31 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 22:39:11 +0800 Subject: [PATCH 1792/2794] manga24h, removed --- changelog.txt | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 6a3b2822d..a268ebf55 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,7 @@ Changelog: [*] Manga-Tr: fixed all [*] GManga: fixed all [*] TruyenTranhTuan: fixed all +[-] Manga24H: removed Full changes: https://github.com/riderkick/FMD/compare/0.9.117.0...0.9.118.0 0.9.117.0 (12-06-2017) diff --git a/config/mangalist.ini b/config/mangalist.ini index 1a11e9d58..afc75e683 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -19,7 +19,7 @@ Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiMa Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr -Vietnamese=AcademyVN,BlogTruyen,Manga24h,TruyenTranhTuan,VnSharing +Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing Webcomics=Tapas H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From c9981c4c4992f0a0a70e8eddb237383fc04142fd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Jun 2017 23:03:29 +0800 Subject: [PATCH 1793/2794] httpsendthread, added xhr request --- baseunits/httpsendthread.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 64f46e0f1..0da6216f8 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -64,6 +64,7 @@ THTTPSendThread = class(THTTPSend) function HEAD(const URL: String; const Response: TObject = nil): Boolean; function GET(const URL: String; const Response: TObject = nil): Boolean; function POST(const URL: String; const POSTData: String = ''; const Response: TObject = nil): Boolean; + function XHR(const URL: String; const Response: TObject = nil): Boolean; function GetCookies: String; function ThreadTerminated: Boolean; procedure RemoveCookie(const CookieName: String); @@ -502,6 +503,14 @@ function THTTPSendThread.POST(const URL: String; const POSTData: String; const R Result := HTTPRequest('POST', URL, Response); end; +function THTTPSendThread.XHR(const URL: String; const Response: TObject + ): Boolean; +begin + if Pos('HTTP/', Headers.Text) = 1 then Reset; + Headers.Add('X-Requested-With: XMLHttpRequest'); + Result := GET(URL, Response); +end; + function THTTPSendThread.GetCookies: String; var i: Integer; From 6a9d9cfb95b689de54fcde9fdc00c8f3389afe52 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Jun 2017 00:19:26 +0800 Subject: [PATCH 1794/2794] blogtruyen, rewrite all closed #491 --- baseunits/ModuleList.inc | 1 + .../BlogTruyen/directory_page_number.inc | 36 ----- baseunits/includes/BlogTruyen/image_url.inc | 34 ----- .../includes/BlogTruyen/manga_information.inc | 128 ---------------- .../includes/BlogTruyen/names_and_links.inc | 39 ----- baseunits/modules/Blogtruyen.pas | 143 ++++++++++++++++++ baseunits/uBaseUnit.pas | 70 ++++----- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 5 - changelog.txt | 1 + 10 files changed, 177 insertions(+), 295 deletions(-) delete mode 100644 baseunits/includes/BlogTruyen/directory_page_number.inc delete mode 100644 baseunits/includes/BlogTruyen/image_url.inc delete mode 100644 baseunits/includes/BlogTruyen/manga_information.inc delete mode 100644 baseunits/includes/BlogTruyen/names_and_links.inc create mode 100644 baseunits/modules/Blogtruyen.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 0f41706f0..df698cc89 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -57,6 +57,7 @@ uses NineManga, MangaTail, TruyenTranhTuan, + BlogTruyen, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/BlogTruyen/directory_page_number.inc b/baseunits/includes/BlogTruyen/directory_page_number.inc deleted file mode 100644 index 962083e37..000000000 --- a/baseunits/includes/BlogTruyen/directory_page_number.inc +++ /dev/null @@ -1,36 +0,0 @@ - function GetBlogTruyenDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[BLOGTRUYEN_ID, 1] + - BLOGTRUYEN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('[cuối]', parse[i]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse[i - 1], 'LoadPage(', ')'))); - APage := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/BlogTruyen/image_url.inc b/baseunits/includes/BlogTruyen/image_url.inc deleted file mode 100644 index 73b03c232..000000000 --- a/baseunits/includes/BlogTruyen/image_url.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetBlogTruyenImageURL: Boolean; - var - isExtrackLink: Boolean = False; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(BLOGTRUYEN_ID, URL), - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if not (isExtrackLink) and (Pos('id="content"', parse[i]) > 0) then - isExtrackLink := True; - if (isExtrackLink) and (GetTagName(parse[i]) = 'img') then - Task.Container.PageLinks.Add( - EncodeUrl(GetVal(parse[i], 'src'))) - else - if (isExtrackLink) and (Pos('</article>', parse[i]) > 0) then - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/BlogTruyen/manga_information.inc b/baseunits/includes/BlogTruyen/manga_information.inc deleted file mode 100644 index c31c662bd..000000000 --- a/baseunits/includes/BlogTruyen/manga_information.inc +++ /dev/null @@ -1,128 +0,0 @@ - function GetBlogTruyenInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = True; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[BLOGTRUYEN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(BLOGTRUYEN_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('div class="thumbnail"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); - - // get summary - if (Pos('class="content"', parse[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 1; - while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - Break; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if (Pos('class="entry-title"', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 3]))); - - // get chapter name and links - if (isExtractChapter) and - (Pos('class="publishedDate"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i - 5], 'href'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse[i - 4])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class="al-c social-button"', parse[i]) > 0) then - isExtractChapter := False; - - // get authors - if (i + 2 < parse.Count) and (Pos('Tác giả:', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(TrimRight(parse[i + 2])); - - // get artists - //if (i+1<parse.Count) AND (Pos('/search/artist/', parse[i])<>0) then - // mangaInfo.artists:= TrimLeft(parse[i+1]); - - // get genres - if (not isExtractGenres) and (Pos('class="category"', parse[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - s := TrimLeft(TrimRight(parse[i])); - if Pos('Đăng bởi:', s) <> 0 then - isExtractGenres := False - else - if (s <> '') and (s[1] <> '<') and - (Pos('class="category"', parse[i - 2]) <> 0) then - mangaInfo.genres := mangaInfo.genres + s + ', '; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Trạng thái:', parse[i]) <> 0) then - begin - if (Pos('Đang tiến hành', parse[i + 2]) <> 0) or - (Pos('Tạm ngưng', parse[i + 2]) <> 0) then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/BlogTruyen/names_and_links.inc b/baseunits/includes/BlogTruyen/names_and_links.inc deleted file mode 100644 index 9a0a616a6..000000000 --- a/baseunits/includes/BlogTruyen/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function BlogTruyenGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - stream: TStringStream; - begin - Result := INFORMATION_NOT_FOUND; - stream := TStringStream.Create(''); - s := WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER; - s := BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(AURL) + 1); - while not HttpPostURL(WebsiteRoots[BLOGTRUYEN_ID, 1] + BLOGTRUYEN_JS_BROWSER, - BLOGTRUYEN_POST_FORM + IntToStr(StrToInt(AURL) + 1), stream) do - Sleep(32); - Source.Text := stream.DataString; - stream.Free; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="tiptip', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft( - TrimRight(GetString(parse[i + 2], 'title="truyện tranh ', '">')))); - ANames.Add(HTMLEntitiesFilter(s)); - ALinks.Add(GetVal(parse[i + 2], 'href="')); - end; - end; - Source.Free; - end; diff --git a/baseunits/modules/Blogtruyen.pas b/baseunits/modules/Blogtruyen.pas new file mode 100644 index 000000000..31dfb4601 --- /dev/null +++ b/baseunits/modules/Blogtruyen.pas @@ -0,0 +1,143 @@ +unit BlogTruyen; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +uses RegExpr, synacode; + +const + dirurl = '/ajax/Search/AjaxLoadListManga?key=tatca&orderBy=1&p='; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.XHR(Module.RootURL + dirurl + '1') then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//*[@class="paging"]/span[last()]/a/@href/substring-before(substring-after(.,"("),")")'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.XHR(Module.RootURL + dirurl + IncStr(AURL)) then + begin + Result := NO_ERROR; + XPathHREFAll('//*[@class="list"]//span/a', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//*[@class="thumbnail"]/img/@src'); + if title = '' then title := XPathString('//title/substring-before(.," | BlogTruyen")'); + authors := XPathString('//*[@class="description"]/p[starts-with(.,"Tác giả")]/string-join(.//a,", ")'); + genres := XPathString('//*[@class="description"]/p[starts-with(.,"Thể loại")]/string-join(.//a,", ")'); + summary := XPathString('//*[@class="detail"]/*[@class="content"]'); + XPathHREFAll('//*[@id="list-chapters"]//span[@class="title"]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + i: Integer; + image: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + XPathStringAll('//article[@id="content"]/img[not(contains(@src,"credit"))]/@src', Document, PageLinks); + // http://blogtruyen.com/scripts/image-url-filter.js?ver=1 + with TRegExpr.Create do try + ModifierI := True; + for i := 0 to PageLinks.Count - 1 do + begin + image := PageLinks[i]; + image := DecodeURL(image); + Expression := '^.+(&|\?)url='; + image := Replace(image, '', True); + Expression := '(https?:\/\/)lh(\d)(\.bp\.blogspot\.com)'; + image := Replace(image, '$1$2$3', True); + Expression := '(https?:\/\/)lh\d\.(googleusercontent|ggpht)\.com'; + image := Replace(image, '$1\4.bp.blogspot.com', True); + Expression := '\?.+$'; + image := Replace(image, '', False); + if Pos('blogspot.com', image) <> 0 then begin + Expression := '\/([^\/]+\-)?(Ic42)(\-[^\/]+)?\/'; + image := Replace(image, '/$2/', True); + Expression := '\/(((s|w|h)\d+|(w|h)\d+\-(w|h)\d+))?\-?(c|d|g)?\/([^\/]+$)'; + image := Replace(image, '/$1', True); + image += '?imgmax=0'; + end; + if Pos('i.imgur.com', image) <> 0 then begin + Expression := '(\/)(\w{5}|\w{7})(s|b|t|m|l|h)(\.(jpe?g|png|gif))$'; + image := Replace(image, '$1$2$4', True); + end; + if (Pos('i.imgur.com', image) <> 0) or (Pos('manga.truyentranh8.', image) <> 0) then begin + image := 'http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?container=focus&url=' + image; + end; + image := image.Replace('https://', 'http://'); + PageLinks[i] := image; + end; + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'BlogTruyen'; + RootURL := 'http://blogtruyen.com'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5f0e52ef7..582b46e7a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -236,46 +236,44 @@ interface TRUYEN18_ID = 3; TURKCRAFT_ID = 4; STARKANA_ID = 5; - BLOGTRUYEN_ID = 6; - ESMANGAHERE_ID = 7; - ANIMEEXTREMIST_ID = 8; - S2SCAN_ID = 9; - IMANHUA_ID = 10; - CENTRALDEMANGAS_ID = 11; - EGSCANS_ID = 12; - MANGAAR_ID = 13; - MANGAAE_ID = 14; - ANIMESTORY_ID = 15; - LECTUREENLIGNE_ID = 16; - SCANMANGA_ID = 17; - DM5_ID = 18; - KIVMANGA_ID = 19; - MEINMANGA_ID = 20; - MANGASPROJECT_ID = 21; - MANGAREADER_POR_ID = 22; - JAPANSHIN_ID = 23; - CENTRUMMANGI_PL_ID = 24; - MANGALIB_PL_ID = 25; - ONEMANGA_ID = 26; - MANGATOWN_ID = 27; - MANGAOKU_ID = 28; - IKOMIK_ID = 29; - NHENTAI_ID = 30; - UNIXMANGA_ID = 31; - EXTREMEMANGAS_ID = 32; - MANGAHOST_ID = 33; - MANGAKU_ID = 34; - MANGAAT_ID = 35; - DYNASTYSCANS_ID = 36; - - WebsiteRoots: array [0..36] of array [0..1] of String = ( + ESMANGAHERE_ID = 6; + ANIMEEXTREMIST_ID = 7; + S2SCAN_ID = 8; + IMANHUA_ID = 9; + CENTRALDEMANGAS_ID = 10; + EGSCANS_ID = 11; + MANGAAR_ID = 12; + MANGAAE_ID = 13; + ANIMESTORY_ID = 14; + LECTUREENLIGNE_ID = 15; + SCANMANGA_ID = 16; + DM5_ID = 17; + KIVMANGA_ID = 18; + MEINMANGA_ID = 19; + MANGASPROJECT_ID = 20; + MANGAREADER_POR_ID = 21; + JAPANSHIN_ID = 22; + CENTRUMMANGI_PL_ID = 23; + MANGALIB_PL_ID = 24; + ONEMANGA_ID = 25; + MANGATOWN_ID = 26; + MANGAOKU_ID = 27; + IKOMIK_ID = 28; + NHENTAI_ID = 29; + UNIXMANGA_ID = 30; + EXTREMEMANGAS_ID = 31; + MANGAHOST_ID = 32; + MANGAKU_ID = 33; + MANGAAT_ID = 34; + DYNASTYSCANS_ID = 35; + + WebsiteRoots: array [0..35] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Truyen18', 'http://www.truyen18.org'), ('Turkcraft', 'http://turkcraft.com'), ('Starkana', 'http://starkana.jp'), - ('BlogTruyen', 'http://blogtruyen.com'), ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), ('S2Scans', 'http://reader.s2smanga.com'), @@ -323,10 +321,6 @@ interface STARKANA_BROWSER = '/manga/list'; - BLOGTRUYEN_BROWSER = '/danhsach/tatca'; - BLOGTRUYEN_JS_BROWSER = '/ListStory/GetListStory/'; - BLOGTRUYEN_POST_FORM = 'Url=tatca&OrderBy=1&PageIndex='; - ESMANGAHERE_BROWSER = '/mangalist/'; ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 762b12ed9..52946586a 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -778,8 +778,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/VnSharing/directory_page_number.inc} - {$I includes/BlogTruyen/directory_page_number.inc} - {$I includes/S2Scans/directory_page_number.inc} {$I includes/LectureEnLigne/directory_page_number.inc} @@ -837,9 +835,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if MangaSiteID = BLOGTRUYEN_ID then - Result := GetBlogTruyenDirectoryPageNumber - else if MangaSiteID = S2SCAN_ID then Result := GetS2ScanDirectoryPageNumber else @@ -928,8 +923,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/EGScans/names_and_links.inc} - {$I includes/BlogTruyen/names_and_links.inc} - {$I includes/Kivmanga/names_and_links.inc} {$I includes/MeinManga/names_and_links.inc} @@ -996,9 +989,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = MEINMANGA_ID then Result := MeinMangaGetNamesAndLinks else - if MangaSiteID = BLOGTRUYEN_ID then - Result := BlogTruyenGetNamesAndLinks - else if MangaSiteID = ESMANGAHERE_ID then Result := EsMangaHereGetNamesAndLinks else @@ -1131,8 +1121,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/CentralDeMangas/manga_information.inc} - {$I includes/BlogTruyen/manga_information.inc} - {$I includes/MeinManga/manga_information.inc} {$I includes/KivManga/manga_information.inc} @@ -1240,9 +1228,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else - if MangaSiteID = BLOGTRUYEN_ID then - Result := GetBlogTruyenInfoFromURL - else if MangaSiteID = KIVMANGA_ID then Result := GetKivmangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8e023a259..c19e548da 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -554,8 +554,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/image_url.inc} - {$I includes/BlogTruyen/image_url.inc} - {$I includes/CentralDeMangas/image_url.inc} {$I includes/EGScans/image_url.inc} @@ -649,9 +647,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else - if Task.Container.MangaSiteID = BLOGTRUYEN_ID then - Result := GetBlogTruyenImageURL - else if Task.Container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaImageURL else diff --git a/changelog.txt b/changelog.txt index a268ebf55..9a9948854 100644 --- a/changelog.txt +++ b/changelog.txt @@ -16,6 +16,7 @@ Changelog: [*] GManga: fixed all [*] TruyenTranhTuan: fixed all [-] Manga24H: removed +[*] BlogTruyen: fixed all Full changes: https://github.com/riderkick/FMD/compare/0.9.117.0...0.9.118.0 0.9.117.0 (12-06-2017) From 7a1c79c67256ed17bb1ceca8cf4dd4d97031aa70 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Jun 2017 00:57:24 +0800 Subject: [PATCH 1795/2794] kumanga, fixed all #499 --- baseunits/modules/KuManga.pas | 70 ++++++++++++----------------------- changelog.txt | 3 +- 2 files changed, 25 insertions(+), 48 deletions(-) diff --git a/baseunits/modules/KuManga.pas b/baseunits/modules/KuManga.pas index d98b906b8..6b4555864 100644 --- a/baseunits/modules/KuManga.pas +++ b/baseunits/modules/KuManga.pas @@ -64,8 +64,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -76,20 +74,15 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//div[@class="row"]/img/@src'); + coverLink := XPathString('//div[@class="row"]//img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h2'); - summary := XPathString('//div[@id="info"]/div[1]/div[1]/div[1]/div[2]'); - genres := XPathStringAll('//div[@id="info"]/div[1]/div[1]/div[1]/div[3]/a'); - authors := XPathString('//div[@id="info"]/div[1]/div[2]/div[1]/div[2]/p[2]/a'); - status := MangaInfoStatusIfPos( - XPathString('//div[@id="info"]/div[1]/div[2]/div[1]/div[2]/p[3]/span'), 'Activo', 'Completo'); - for v in XPath('//div[@id="info"]/div[2]//table/tbody/tr/td/a') do - begin - chapterLinks.Add(StringReplace(v.toNode.getAttribute('href'), - '/c/', '/leer/', [rfIgnoreCase])); - chapterName.Add(v.toString); - end; + if title = '' then title := XPathString('//h1'); + summary := XPathString('//*[@class="infom"]/div/div[1]/p'); + authors := XPathString('//*[@class="infom"]/div/div[2]//p[contains(.,"Autor") and not(contains(.,"No Disponible"))]/substring-after(normalize-space(.),": ")'); + artists := XPathString('//*[@class="infom"]/div/div[2]//p[contains(.,"Artist") and not(contains(.,"No Disponible"))]/substring-after(normalize-space(.),": ")'); + status := MangaInfoStatusIfPos(XPathString('//*[@class="infom"]/div/div[2]//p[contains(.,"Estado")]'), 'Activo', 'Finalizado'); + genres := XPathString('//*[@class="panel-footer" and contains(.,"Géneros")]/string-join(.//a,", ")'); + XPathHREFAll('//table//tr/td/a', chapterLinks, chapterName); InvertStrings([chapterLinks, chapterName]); finally Free; @@ -101,9 +94,8 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - source: TStringList; - i, p: Integer; - s: String; + pages: Integer; + pageFormat, pageFormat2: String; begin Result := False; if DownloadThread = nil then Exit; @@ -111,38 +103,22 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then + if GET(MaybeFillHost(Module.RootURL, AURL.Replace('/c/','/leer/'))) then begin Result := True; - source := TStringList.Create; - try - source.LoadFromStream(Document); - if source.Count > 0 then - for i := 0 to source.Count - 1 do - if Pos('konekomangareader(''setup'',{', source[i]) <> 0 then - begin - s := GetBetween('.konekomangareader(''setup'',{', '});', source[i]); - Break; - end; + with TXQueryEngineHTML.Create(Document) do try + pageFormat := XPathString('//script[contains(.,"konekomangareader")]/substring-before(substring-after(substring-after(.,"setup"),","),");")'); + if pageFormat <> '' then begin + ParseHTML(pageFormat); + pages := StrToIntDef(XPathString('json(*)//pages'), 0); + pageFormat := XPathString('substring-before(json(*)//pageFormat,"{pnumber}")'); + pageFormat2 := XPathString('substring-after(json(*)//pageFormat,"{pnumber}")'); + if pageFormat <> '' then + for pages := 1 to pages do + PageLinks.Add(pageFormat + IntToStr(pages) + pageFormat2); + end; finally - source.Free; - end; - if s <> '' then - begin - s := '{' + s + '}'; - with TXQueryEngineHTML.Create(s) do - try - p := StrToIntDef(XPathString('json(*).pages'), 0); - if p > 0 then - begin - s := XPathString('json(*).pageFormat'); - if Pos('{pnumber}', s) <> 0 then - for i := 1 to p do - PageLinks.Add(StringReplace(s, '{pnumber}', IntToStr(i), [rfReplaceAll])); - end; - finally - Free; - end; + Free; end; end; end; diff --git a/changelog.txt b/changelog.txt index 9a9948854..59bf4e3c0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.117.0 (future) +0.9.118.0 (future) [*] Madokami: fixed all [-] MangaKoi: removed [+] Added MangaHome[EN] @@ -17,6 +17,7 @@ Changelog: [*] TruyenTranhTuan: fixed all [-] Manga24H: removed [*] BlogTruyen: fixed all +[*] KuManga: fixed all Full changes: https://github.com/riderkick/FMD/compare/0.9.117.0...0.9.118.0 0.9.117.0 (12-06-2017) From d9006ab73675825b2a0b92491393fe3c11bbceaf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Jun 2017 01:31:36 +0800 Subject: [PATCH 1796/2794] baseunit, added overload of maybefillhost --- baseunits/uBaseUnit.pas | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 582b46e7a..90c120f22 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -591,8 +591,9 @@ function FillMangaSiteHost(const Website, URL: String): String; overload; // modify url function FillHost(const Host, URL: String): String; overload; -function FillHost(const Host: String; const URLs: TStrings): String; overload; -function MaybeFillHost(const Host, URL: String): String; +procedure FillHost(const Host: String; const URLs: TStrings); overload; +function MaybeFillHost(const Host, URL: String): String; overload; +procedure MaybeFillHost(const Host: String; const URLs: TStrings); overload; function GetHostURL(URL: String): String; function RemoveHostFromURL(URL: String): String; procedure RemoveHostFromURLs(const URLs: TStringList); @@ -1184,7 +1185,7 @@ function FillHost(const Host, URL: String): String; Result:=RemoveURLDelim(Host)+P; end; -function FillHost(const Host: String; const URLs: TStrings): String; +procedure FillHost(const Host: String; const URLs: TStrings); var i: Integer; begin @@ -1202,6 +1203,15 @@ function MaybeFillHost(const Host, URL: String): String; else Result:=URL; end; +procedure MaybeFillHost(const Host: String; const URLs: TStrings); +var + i: Integer; +begin + if (URLs=nil) or (URLs.Count=0) then Exit; + for i:=0 to URLs.Count-1 do + URLs[i]:=MaybeFillHost(Host,URLs[i]); +end; + function GetHostURL(URL: String): String; var H: String; From bf16b5199e75969974658e3eb7acc1e7898a4719 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Jun 2017 01:32:12 +0800 Subject: [PATCH 1797/2794] leomanga, fixed all fixed #499 --- baseunits/modules/LeoManga.pas | 31 ++++++++++--------------------- changelog.txt | 1 + 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/baseunits/modules/LeoManga.pas b/baseunits/modules/LeoManga.pas index 020a790f5..4aa80931b 100644 --- a/baseunits/modules/LeoManga.pas +++ b/baseunits/modules/LeoManga.pas @@ -74,7 +74,7 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@class="manga-picture"]/@src')); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[contains(@class,"manga-picture")]/@data-original')); if title = '' then begin title := XPathString('//*[@id="page-manga"]/h1'); @@ -82,9 +82,9 @@ function GetInfo(const MangaInfo: TMangaInformation; SetLength(title, Length(title) - 6); end; summary := XPathString('//*[@id="page-manga"]/h2[.="Sinopsis"]/following-sibling::p/text()'); - authors := XPathStringAll('//*[@id="page-manga"]/div[@class="row"]/div/strong[.="Autor:"]/following-sibling::a'); - genres := XPathStringAll('//*[@id="page-manga"]/div[@class="row"]/div/strong[.="Géneros:"]/following-sibling::a'); - for v in XPath('//ul[@class="list-unstyled caps-list"]/li') do + authors := XPathString('//*[@id="page-manga"]/div[@class="row"]/div[starts-with(.,"Autor")]/substring-after(normalize-space(.),": ")'); + genres := XPathString('//*[@id="page-manga"]/div[@class="row"]/div[starts-with(.,"Géneros")]/substring-after(normalize-space(.),": ")'); + for v in XPath('//ul[contains(@class,"caps-list")]/li') do begin s := Trim(XPathString('div[1]/h3/text()[2]', v.toNode)); for x in XPath('div[2]/ul/li/a', v.toNode) do @@ -107,8 +107,7 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - s, p: String; - i: Integer; + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -121,22 +120,12 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - s := XPathString('//a[contains(@class,"btn")][.="Online"]/@href'); + s := XPathString('//a[contains(@class,"cap-option")]/@href'); if s = '' then Exit; - if GET(MaybeFillHost(Module.RootURL, s)) then - begin + if GET(MaybeFillHost(Module.RootURL, s)) then begin ParseHTML(Document); - s := XPathString('//*[@id="read-chapter"]/@name'); - if s <> '' then - s := AppendURLDelim(MaybeFillHost(Module.RootURL, s)); - p := XPathString('//*[@id="read-chapter"]/@pos'); - if p <> '' then - begin - ExtractStrings([';'],[], PChar(p), PageLinks, False); - if (s <> '') and (PageLinks.Count > 0) then - for i := 0 to PageLinks.Count - 1 do - PageLinks[i] := s + PageLinks[i]; - end; + XPathStringAll('//*[@id="cascade-images"]//img/@src', PageLinks); + MaybeFillHost(Module.RootURL, PageLinks); end; finally Free; @@ -150,7 +139,7 @@ procedure RegisterModule; with AddModule do begin Website := 'LeoManga'; - RootURL := 'http://www.leomanga.com'; + RootURL := 'http://leomanga.com'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/changelog.txt b/changelog.txt index 59bf4e3c0..7e62d7cd6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -18,6 +18,7 @@ Changelog: [-] Manga24H: removed [*] BlogTruyen: fixed all [*] KuManga: fixed all +[*] LeoManga: fixed all Full changes: https://github.com/riderkick/FMD/compare/0.9.117.0...0.9.118.0 0.9.117.0 (12-06-2017) From 6a7c9f1ef057b59e308bdbbc7e7d88fdce44d9db Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Jun 2017 01:44:48 +0800 Subject: [PATCH 1798/2794] Bump version 0.9.118.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7e62d7cd6..ce8a94db8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.118.0 (future) +0.9.118.0 (14-06-2017) [*] Madokami: fixed all [-] MangaKoi: removed [+] Added MangaHome[EN] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 547afa586..52b7db7d9 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="117"/> + <RevisionNr Value="118"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index bc93942c7..fd109c8d0 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.117.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.117.0/fmd_0.9.117.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.117.0/fmd_0.9.117.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.117.0/fmd_0.9.117.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.117.0/fmd_0.9.117.0_Win64.7z +VERSION=0.9.118.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.118.0/fmd_0.9.118.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.118.0/fmd_0.9.118.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.118.0/fmd_0.9.118.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.118.0/fmd_0.9.118.0_Win64.7z From ad956cd8bf3f6af94b4fb9c18c8233161e774291 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Jun 2017 21:19:11 +0800 Subject: [PATCH 1799/2794] baseunit, added overload base64 decode encode with tstream --- baseunits/uBaseUnit.pas | 63 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 90c120f22..d5d33ddc1 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -618,8 +618,10 @@ function ConvertCharsetToUTF8(S: String): String; overload; procedure ConvertCharsetToUTF8(S: TStrings); overload; // encode/decode -function Base64Encode(const s: String): String; -function Base64Decode(const s: String): String; +function Base64Encode(const s: String): String; overload; +function Base64Decode(const s: String): String; overload; +function Base64Encode(const TheStream: TStream): Boolean ; overload; +function Base64Decode(const TheStream: TStream): Boolean ; overload; // StringUtils function PadZero(const S: String; ATotalWidth: Integer = 3; @@ -1939,6 +1941,63 @@ function Base64Decode(const s: String): String; Result := DecodeStringBase64(s); end; +function Base64Encode(const TheStream: TStream): Boolean; +var + OutStream: TMemoryStream; + Encoder: TBase64EncodingStream; +begin + Result := False; + if TheStream = nil then Exit; + if TheStream.Size = 0 then Exit; + OutStream := TMemoryStream.Create; + try + Encoder := TBase64EncodingStream.Create(OutStream); + try + TheStream.Position := 0; + Encoder.CopyFrom(TheStream, TheStream.Size); + Encoder.Flush; + TheStream.Position := 0; + TheStream.Size := 0; + OutStream.Position := 0; + TheStream.CopyFrom(OutStream, OutStream.Size); + Result := True; + finally + Encoder.Free; + end; + finally + OutStream.Free; + end; +end; + +function Base64Decode(const TheStream: TStream): Boolean; +var + Decoder: TBase64DecodingStream; + InStream: TMemoryStream; +begin + Result := False; + if TheStream = nil then Exit; + if TheStream.Size = 0 then Exit; + InStream := TMemoryStream.Create; + try + TheStream.Position := 0; + InStream.CopyFrom(TheStream, TheStream.Size); + try + InStream.Position := 0; + Decoder := TBase64DecodingStream.Create(InStream); + if Decoder.Size > 0 then begin + TheStream.Position := 0; + TheStream.Size := 0; + TheStream.CopyFrom(Decoder, Decoder.Size); + Result := True; + end; + except + end; + Decoder.Free; + finally + InStream.Free; + end; +end; + function PadZero(const S: String; ATotalWidth: Integer; PadAll: Boolean; StripZero: Boolean): String; function PadN(const SN: String): String; From 6fdde9a5b48ccc71f9fa910655dab52dca4a8b55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Jun 2017 21:28:31 +0800 Subject: [PATCH 1800/2794] added shogakukan closed #623 --- baseunits/ModuleList.inc | 1 + baseunits/modules/Shogakukan.pas | 99 ++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 baseunits/modules/Shogakukan.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index df698cc89..a9711da00 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -64,6 +64,7 @@ uses YoungAceUp, NewType, Comico, + Shogakukan, // Adult WPAdultSiteSkins, EHentai, diff --git a/baseunits/modules/Shogakukan.pas b/baseunits/modules/Shogakukan.pas new file mode 100644 index 000000000..681094aeb --- /dev/null +++ b/baseunits/modules/Shogakukan.pas @@ -0,0 +1,99 @@ +unit Shogakukan; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML; + +implementation + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//meta[@property="og:image"]/@content'); + if title = '' then title := XPathString('//title/substring-before(.," | ")'); + chapterLinks.Add(url); + chapterName.Add(title); + finally + Free; + end; + end; + end; +end; + + +function TaskStart(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; +begin + Result := True; + if Task = nil then Exit; + Task.PageLinks.Clear; + Task.PageLinks.Clear; + Task.PageNumber := 0; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do try + XPathStringAll('//*[@id="book_data_area"]/input[@data-key="imageCodes"]/@value', PageLinks); + PageContainerLinks.Add(XPathString('//*[@id="book_data_area"]/input[@data-key="isbn"]/@value')); + PageContainerLinks.Add(XPathString('//*[@id="book_data_area"]/input[@data-key="vsid"]/@value')); + finally + Free; + end; + end; + end; +end; + +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread, DownloadThread.FHTTP, DownloadThread.Task.Container do begin + if WorkId = 0 then + Headers.Add('Referer: ' + Module.RootURL + '/' + PageContainerLinks[1]) + else + Headers.Add('Referer: ' + Module.RootURL + '/' + PageContainerLinks[1] + '?page=' + IntToStr(WorkId)); + if POST(Module.RootURL + '/imgDeliver?gcode=' + PageContainerLinks[0], + 'base64=1&vsid=' + PageContainerLinks[1] + '&trgCode=' + PageLinks[WorkId]) then + if Base64Decode(Document) then + Result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Shogakukan'; + RootURL := 'https://shogakukan.tameshiyo.me'; + OnGetInfo := @GetInfo; + OnTaskStart := @TaskStart; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + end; +end; + +initialization + RegisterModule; + +end. From 8c80b570b7b0417291d876e887e4f9ef6da4b42f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Jun 2017 21:33:17 +0800 Subject: [PATCH 1801/2794] baseunit, added parse googleresulturls --- baseunits/uBaseUnit.pas | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d5d33ddc1..693b5612e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -729,6 +729,10 @@ function SetParams(const input: array of String): String; overload; procedure CustomGenres(var output: TStringList; input: String); +//parse google result urls +function GoogleResultURL(const AURL: String): String; +procedure GoogleResultURLs(const AURLs: TStrings); + // deal with sourceforge URL. function SourceForgeURL(URL: String): String; // Get HTML source code from a URL. @@ -2879,6 +2883,28 @@ function SFDirectLinkURL(URL: String; Document: TMemoryStream): String; Result := URL; end; +function GoogleResultURL(const AURL: String): String; +begin + Result := AURL; + if Pos('google.', LowerCase(AURL)) = 0 then Exit; + Result := DecodeURL(ReplaceRegExpr('(?i)^.*google\..*\&url=([^\&]+)\&?.*$', AURL, '$1', True)); +end; + +procedure GoogleResultURLs(const AURLs: TStrings); +var + i: Integer; +begin + if AURLs.Count = 0 then Exit; + if Pos('google.', LowerCase(AURLs.Text)) = 0 then Exit; + with TRegExpr.Create('(?i)^.*google\..*\&url=([^\&]+)\&?.*$') do try + for i := 0 to AURLs.Count - 1 do + if Pos('google.', LowerCase(AURLs[i])) <> 0 then + AURLs[i] := DecodeURL(Replace(AURLs[i], '$1', True)); + finally + Free; + end; +end; + function SourceForgeURL(URL: String): String; // Detects sourceforge download and tries to deal with // redirection, and extracting direct download link. From a91bf822b507ccb81550ccc08375cc3becb99c68 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Jun 2017 21:33:34 +0800 Subject: [PATCH 1802/2794] frmmain, parse google urls on drop --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ae8cb0085..e8888165f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4387,6 +4387,7 @@ procedure TMainForm.AddSilentThread(URL: string; MetaDataType: TMetaDataType); URls.Text := URL; if URls.Count > 0 then begin + GoogleResultURLs(URls); SilentThreadManager.BeginAdd; with TRegExpr.Create do try From f71e97fa141e2f267f9992ab259c7bee3c4f4754 Mon Sep 17 00:00:00 2001 From: Denis K <tokcdk@gmail.com> Date: Thu, 22 Jun 2017 16:43:31 +0500 Subject: [PATCH 1803/2794] Added russian localization files --- mangadownloader/languages/fmd.ru_RU.po | 2210 ++++++++++++++++++++ mangadownloader/languages/updater.ru_RU.po | 108 + 2 files changed, 2318 insertions(+) create mode 100644 mangadownloader/languages/fmd.ru_RU.po create mode 100644 mangadownloader/languages/updater.ru_RU.po diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po new file mode 100644 index 000000000..2f117407d --- /dev/null +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -0,0 +1,2210 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: 0.9.118.0\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Tokc.D.K. <tokcdk@gmail.com>\n" +"Language-Team: TokcDK\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru_RU\n" +"X-Generator: Poedit 2.0.2\n" + +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "Сервер изображения:" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" +"Авто\n" +"Сервер изображения EU\n" +"Сервер изображения NA\n" +"CDN (по умолч.)\n" +"CDN2 (тестовый)\n" + +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Показать все языки" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Показать группу сканирования" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Загрузить оригинальное изображение(треб. аккаунт ExHentai)" + +#: ehentai.rs_settingsimagesize +msgid "Image size:" +msgstr "Размер изображения:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Авто\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Оригинал\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Хотите удалить этот аккаунт?" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Проверка" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "Неверный" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Неизвестный" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "OK" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Имя пользователя и пароль не могут быть пустыми!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "Импорт завершен." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "Список неимпортированной манги" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Все загрузки" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&OK" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "Отмена" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Проверка..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "Не удалось подключиться к серверу." + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "Не удалось получить информацию о манге. Проверьте интернет-подключение и попробуйте снова." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Количество загрузок:" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "Нужно выбрать минимум один сайт манги!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Хотите выйти?" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Хотите удалить это избранное?" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Хотите удалить все завершенные задачи?" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Хотите удалить это?" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Хотите удалить эти задачи?" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Разделить загрузку" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "" +"Это название уже в списке загрузки.\n" +"Все равно хотите загрузить?\n" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Введите новую главу:" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Введите новый путь сохранения:" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Обновление запущено!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Хотите загрузить список манги с сервера?" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "Ссылка не поддерживается!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "" +"Загрузить все\n" +"Добавить в избранное\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "" +"Завершено\n" +"Постоянный\n" +"<none>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Бесплатный Manga Downloader уже запущен!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "" +"Есть проблема с этими данными!\n" +"Удаление и повторное добавление этих данных могут решить проблему.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "История" + +#: frmmain.rs_import +msgid "Import" +msgstr "Импорт" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Артисты:" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Автор:" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Жанр:" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Статус:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Описание:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Название:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Сайт:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "В процессе" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Автоматическая проверка новой главы каждые %d минут" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "" +"%s : Путь к манге\n" +"%s : Имя файла главы\n" +"\n" +"Пример : \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Загрузка..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Режим: Показать все (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Режим: Отфильтрованные (%d)" + +#: frmmain.rs_modesearching +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Режим: Поиск..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "За месяц" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "За неделю" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "" +"Ничего\n" +"Выход\n" +"Выключить\n" +"Сон\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Выбрано: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Программа" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Путь к программе (например, C:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Cегодня" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Неверный ввод!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Вчера" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "Программа закроется через %d секунд." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "Система перейдет в спящий режим через %d секунд." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "Система выключится через %d секунд." + +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "Вектор инициализации:" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "Ключ:" + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Удалить водяные знаки" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Сохранить как PNG" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Добавить" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Удалить" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Изменить" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Обновить" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" +msgid "Website" +msgstr "Сайт" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[2].TEXT" +msgid "Username" +msgstr "Имя пользователя" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[3].TEXT" +msgid "Status" +msgstr "Статус" + +#: taccountsetform.btcancel.caption +msgctxt "TACCOUNTSETFORM.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Отмена" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "OK" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Показать пароль" + +#: taccountsetform.edpassword.texthint +msgctxt "TACCOUNTSETFORM.EDPASSWORD.TEXTHINT" +msgid "Password" +msgstr "Пароль" + +#: taccountsetform.edusername.texthint +msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" +msgid "Username" +msgstr "Имя пользователя" + +#: taccountsetform.label1.caption +msgctxt "TACCOUNTSETFORM.LABEL1.CAPTION" +msgid "Website" +msgstr "Сайт" + +#: taccountsetform.label2.caption +msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" +msgid "Username" +msgstr "Имя пользователя" + +#: taccountsetform.label3.caption +msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" +msgid "Password" +msgstr "Пароль" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Основной список" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Список глав" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Список избранного" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Список манги" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" +msgid "Add to favorites" +msgstr "Добавить в избранное" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "И Закрыть" + +#: tformdroptarget.midownloadall.caption +msgctxt "TFORMDROPTARGET.MIDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Загрузить все" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Очистить" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Пребывание на вершине" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Лимит лога" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Скопировать" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Отмена" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&OK" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga Downloader" + +#: timportfavorites.edpath.texthint +msgctxt "TIMPORTFAVORITES.EDPATH.TEXTHINT" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Путь к программному обеспечению (например, C: \\ MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Программное обеспечение:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Прервать обновление списка" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Добавить в избранное" + +#: tmainform.btchecklatestversion.caption +msgctxt "TMAINFORM.BTCHECKLATESTVERSION.CAPTION" +msgid "Check for latest version" +msgstr "Проверка последней версии" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Очистить файл лога" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "Загрузить" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Разделить загрузку" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Проверить на новую глава" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Импорт списка" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Фильтр" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Сбросить том" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Открыть лог" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Принять" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Читать онлайн" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Удалить фильтр" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Удалить фильтр" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Обновить список манги" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Посетите мой блог" + +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "Добавить в список загрузки как остановленное задание" + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<none>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Искать только новую мангу" + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVDOWNLOAD.CAPTION" +msgid "Automatic download after finish checking" +msgstr "Автоматическая загрузка после завершения проверки" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Автоматическая проверка новой главы в интервале" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVREMOVECOMPLETEDMANGA.CAPTION" +msgid "Automatic remove completed manga from Favorites" +msgstr "Автоматически удалять завершенную мангу из Избранного" + +#: tmainform.cboptionautocheckfavstartup.caption +msgid "Auto check for new chapter at startup" +msgstr "Автоматическая проверка новой главы при запуске" + +#: tmainform.cboptionautochecklatestversion.caption +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" +msgid "Auto check for latest version " +msgstr "Автоматическая проверка последней версии " + +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Открыть избранное при запуске" + +#: tmainform.cboptionchangeunicodecharacter.caption +msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" +msgid "Replace all unicode character with" +msgstr "Заменить все символы Юникода на" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Включите, если возникли проблемы с Unicode-символами в пути." + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Глава" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Том" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Включить загрузку обложки манги" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Авто-создание папки главы" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "TMAINFORM.CBOPTIONGENERATEMANGAFOLDER.CAPTION" +msgid "Auto generate folder based on manga's name" +msgstr "Авто-создание папки на основе имени манги" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Включить живой поиск (медленно при длинном списке)" + +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "Минимизировать при запуске" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Свернуть в трей" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "Разрешить только один экземпляр программы" + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Удалить имя манги из главы" + +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "Показывать подсказки" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Удаление задачи/избранного" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Загрузка списка манги, если он пустой" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "Показать панель загрузок" + +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "Показать \"Удалить все завершенные задачи\" в панели загрузки" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "Выход из программы" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "Не загружать информацию о манге при обновлении списка (фильтр не будет работать!)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "Удалять повторяющиеся локальные данные при обновлении списка манги" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Использовать прокси" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Поиск по всем сайтам манги" + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Для получения дополнительных сайтов с мангой откройте Настройки->Сайты с мангой" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Регулярное выражение (regexp)" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "Показать Дропбокс" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Включить логирование" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Экшен" + +#: tmainform.ckfilteraction.hint +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Работа, обычно изображающая бой, насилие, хаос и быстрое движение." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Взрослое" + +#: tmainform.ckfilteradult.hint +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Содержит контент, который подходит только для взрослых. Работы этой категории могут содержать длительные сцены интенсивного насилия и/или графический сексуальный контент и наготу." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Приключения" + +#: tmainform.ckfilteradventure.hint +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Если персонаж в истории отправляется в путешествие или что-то в этом роде, тогда наверняка это приключенческая манга. В противном случае, это зависит от ваших личных предубеждений по этой теме." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Юмор" + +#: tmainform.ckfiltercomedy.hint +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Драматическая работа, легкая и часто юмористическая или сатирическая по тону и, обычно, содержащая счастливое разрешение тематического конфликта." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Додзинси" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Фанатская работа, вдохновленная официальной мангой/аниме." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Драма" + +#: tmainform.ckfilterdrama.hint +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Работа, призванная вызвать эмоциональный отклик, например, внушить печаль или напряжение." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Этти" + +#: tmainform.ckfilterechi.hint +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Возможно, середина между хентаем и не хентаем, этти обычно относится к фансервису, с целью привлечь определенную группу фанатов." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Фентези" + +#: tmainform.ckfilterfantasy.hint +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Все, что включает в себя, помимо прочего, магию, воображаемый мир и сказки." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Смена пола" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "" +"Девушки наряжаются как парни, парни наряжаются как девушки.\n" +"Парни превращаются в девушек, девушки превращаются в парней.\n" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Гарем" + +#: tmainform.ckfilterharem.hint +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "В сериях учавствует один главный мужской персонаж и многих женских персонажей (как правило, испытывающих влечение к мужскому персонажу). Реверсивный гарем - это когда пол меняются на противоположный." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Хентай" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Хентай" + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "История" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Имеет отношение к старым или древним временам." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Ужасы" + +#: tmainform.ckfilterhorror.hint +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Мучительное чувство ужаса, страха и отвращения; Содрогание от ужаса и ненависти; Чувство, вдохновленное чем-то страшным и шокирующим." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Дзёсэй" + +#: tmainform.ckfilterjosei.hint +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Буквально «Женщина». Нацелено на женщин 18-30 лет. Женский эквивалент сёнен. В отличие от сёдзе роман более реалистичен и менее идеализирован. Рассказ историй более ясный и зрелый." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Лоликон" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Представление сексуального влечения к молодым или несовершеннолетним девочкам." + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Боевые Искусства" + +#: tmainform.ckfiltermartialarts.hint +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "Как следует из названия, все, что связано с боевыми искусствами. Любое из нескольких исскуств боя или самозащиты, таких как айкидо, каратэ, дзюдо, таэквондо, кендо, фехтование и т.д.и т.п." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Зрелые" + +#: tmainform.ckfiltermature.hint +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "Содержит субъекта, который может быть слишком экстремальным для людей в возрасте до 17 лет. Работы в этой категории могут содержать много насилия, крови, сексуального контента и/или резких слов." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Меха" + +#: tmainform.ckfiltermecha.hint +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Работа, включающая и обычно концентрирующаяся на всех типах крупных роботизированных машин." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Мюзикл" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Музыка" + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Мистика" + +#: tmainform.ckfiltermystery.hint +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Обычно происходит необъяснимое событие и главный герой пытается выяснить, что вызвало его." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Психология" + +#: tmainform.ckfilterpsychological.hint +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Обычно речь идет о философии состояния ума, в большинстве случаев подробно описывающей аномальную психологию." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Романтика" + +#: tmainform.ckfilterromance.hint +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Любая история, связанная с любовью. В этом случае мы определяем любовь между мужчиной и женщиной. Кроме этого, это зависит от вашего представления, что такое любовь." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "Школьная жизнь" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "В основном сеттинге истории события происходят в какой-либо школе." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Скайфай" + +#: tmainform.ckfilterscifi.hint +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Это сокращение от научной фантастики, эти работы связаны с поворотами в технологиях и других, связанных с наукой явлениях, которые являются противоречиями или отрезками современного научного мира." + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Сейнэн" + +#: tmainform.ckfilterseinen.hint +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "Из Google: Сейнэн означает «молодой человек». аниме и манга, рассчитанные на особую целевую аудиторию — молодых мужчин от 18 лет и старше. Истории в Сейнэн рассчитаны на привлечение студентов университетов и тех, кто работают. Как правило, сюжетные линии посвящены проблемам взрослой жизни." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Шота" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "Представление сексуального влечения к молодым или несовершеннолетним мальчикам." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Сёдзе" + +#: tmainform.ckfiltershoujo.hint +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Работа, нацеленная и предназначенная в основном для женщин. Обычно включает в себя много романтики и сильного развития персонажа." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Сёдзе-ай" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "Часто синонимом Юри, это можно считать несколько менее экстремальным. «Девичья любовь», так сказать." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Сёнэн" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Работа, нацеленная и предназначенная в основном для мужчин. Обычно эти работы связаны с борьбой и/или насилием." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Сёнэн-ай" + +#: tmainform.ckfiltershounenai.hint +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "Часто синонимом яоя, это можно считать несколько менее экстремальным. «Мужская любовь», так сказать" + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Повседневность" + +#: tmainform.ckfiltersliceoflife.hint +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "Wiki: Жанр, повествующий о жизни простых обывателей. Так называют любое реалистическое описание или представление событий и ситуаций из повседневной жизни. Акцент делается на чувствах и поведении персонажей." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Смат (Непристойность)" + +#: tmainform.ckfiltersmut.hint +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Жанр сетевого текста, в котором описывается только секс между героями. Имеет дело с сериями, которые считаются неприличными или оскорбительными, особенно в отношении сексуального контента." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Спорт" + +#: tmainform.ckfiltersports.hint +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "Как следует из названия, все, что связано со спортом. Бейсбол, баскетбол, хоккей, футбол, гольф и гонки- некоторые из них." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Сверхъестественное" + +#: tmainform.ckfiltersupernatural.hint +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Обычно подразумевает удивительные и необъяснимые силы или события, которые бросают вызов законам физики." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Трагедия" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Содержит события, приводящие к большим потерям и неудачам." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Вебкомиксы" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Вебкомиксы" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Яой" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Обычно связано с интимными отношениями между мужчинами." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Юри" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Обычно связано с интимными отношениями между женщинами." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Ввод пользовательских жанров, разделенных запятой" + +#: tmainform.eddownloadssearch.texthint +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Поиск загрузок..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Поиск избранного..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Артист" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Автор" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "TMAINFORM.EDFILTERMANGAINFOCHAPTERS.TEXTHINT" +msgid "Filter" +msgstr "Фильтр" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Часть Описание" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Название" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Поиск названия..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "TMAINFORM.EDOPTIONCHAPTERCUSTOMRENAME.TEXTHINT" +msgid "Custom rename" +msgstr "Пользовательское переименование" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Путь загрузки по умолчанию:" + +#: tmainform.edoptionexternalparams.texthint +msgctxt "TMAINFORM.EDOPTIONEXTERNALPARAMS.TEXTHINT" +msgid "External program parameters" +msgstr "Параметры внешней программы" + +#: tmainform.edoptionexternalpath.texthint +msgctxt "TMAINFORM.EDOPTIONEXTERNALPATH.TEXTHINT" +msgid "External program path" +msgstr "Путь к внешней программе" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "TMAINFORM.EDOPTIONFILENAMECUSTOMRENAME.TEXTHINT" +msgid "Custom rename" +msgstr "Пользовательское переименование" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr "Прокси-сервер / IP-адрес" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "TMAINFORM.EDOPTIONMANGACUSTOMRENAME.TEXTHINT" +msgid "Custom rename" +msgstr "Пользовательское переименование" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "Пароль прокси" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "Имя пользователя прокси" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Сохранить в" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "Ввести адрес сюда" + +#: tmainform.edwebsitessearch.texthint +msgctxt "TMAINFORM.EDWEBSITESSEARCH.TEXTHINT" +msgid "Search website..." +msgstr "Поиск сайта..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Показать диалог подтверждения когда" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "Дропбокс" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Внешняя программа" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Избранное" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Конфигурация прокси-сервера" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Переименовать" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Выберите путь загрузки по умолчанию:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Прозрачность" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Артист" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Автор" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Пользовательские жанры" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "" +"Жанры:\n" +"- Отмечено: Включить этот жанр.\n" +"- не отмечено: Исключить этот жанр.\n" +"- Серое: Не имеет значения.\n" +" \n" +"Свои жанры:\n" +"- Разделяйте несколько жанров с помощью ','.\n" +"- Исключите жанр, поставив '!' или '-' в начале жанра.\n" +"- Пример: Приключение,!Этти, Комедия.\n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Статус" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Описание" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Название" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Файл лога:" + +#: tmainform.lbmode.caption +msgid "Mode: Show all (0)" +msgstr "Режим: Показать все (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "TMAINFORM.LBOPTIONAUTOCHECKFAVINTERVALMINUTES.CAPTION" +msgid "Auto check for new chapter every %d minutes" +msgstr "Автоматическая проверка новой главы каждые %d минут" + +#: tmainform.lboptionchaptercustomrename.caption +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAME.CAPTION" +msgid "Chapter name:" +msgstr "Название главы:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.CAPTION" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.HINT" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Название сайта\n" +"%MANGA%: Название манги\n" +"%CHAPTER%: Название главы\n" +"%AUTHOR%: Автор\n" +"%ARTIST%: Артист\n" +"%NUMBERING% : Нумерация\n" +"\n" +"Примечание:\n" +"Имя папки главы должно содержать как минимум %CHAPTER% или %NUMBERING%.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Время ожидания подключения (в секундах)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Открыть мангу, используя внешнюю программу:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Параметры боксмода:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "TMAINFORM.LBOPTIONEXTERNALPARAMSHINT.CAPTION" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Имя файла:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "TMAINFORM.LBOPTIONFILENAMECUSTOMRENAMEHINT.CAPTION" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE%: Название сайта\n" +"%MANGA%: Название манги\n" +"%CHAPTER%: Название главы\n" +"%FILENAME%: Имя файла\n" +"\n" +"Примечание:\n" +"Имя файла должно содержать как минимум %FILENAME%\n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Сервер" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Язык:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "После завершения загрузки:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAME.CAPTION" +msgid "Manga folder name:" +msgstr "Имя каталога манги:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAMEHINT.CAPTION" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE%: Название сайта\n" +"%MANGA%: Название манги\n" +"%AUTHOR%: Автор\n" +"%ARTIST%: Артист \n" +"\n" +"Примечание:\n" +"Имя папки манги должно содержать как минимум %MANGA%.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Количество загружаемых задач одновременно (максимум: 8)" + +#: tmainform.lboptionmaxretry.caption +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Количество повторных попыток, если задачи имеют проблемы с загрузкой (-1 = всегда повторять)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Количество загружаемых файлов за одну задачу одновременно (максимум: 32)" + +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "Новая манга основана на времени ее обновления (дней)" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Пароль" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "Уровень сжатия PDF" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (без потерь), lower = DCTEncode (с потерями)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "TMAINFORM.LBOPTIONPDFQUALITYHINT.CAPTION" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Порт" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Тип" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Переименовать цифры" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Имя пользователя" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Сохранить в:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Удалить" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Скопировать" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Вырезать" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Вставить" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Вставить и пойти" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Выбрать все" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Отменить" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Отменить" + +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "Восходящий" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Отметить все" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Отметить выделенные" + +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "Нисходящий" + +#: tmainform.michapterlistfilter.caption +msgctxt "TMAINFORM.MICHAPTERLISTFILTER.CAPTION" +msgid "Filter" +msgstr "Фильтр" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "Скрыть загруженные главы" + +#: tmainform.michapterlisthighlight.caption +msgid "Highlight downloaded chapters" +msgstr "Подсветить загруженные главы" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Снять отметку со всех" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Снять отметку с выделенных" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Удалить" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Удалить все выполненные задачи" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Только задание" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Задача + Данные" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Задача + Данные + Избранное" + +#: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" +msgid "Disable" +msgstr "Отключить" + +#: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" +msgid "Enable" +msgstr "Включить" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Объединить завершенные задачи" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Открыть папку" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Открыть..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Продолжить" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Остановить" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Информация о манге" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Изменить \"Текущая глава\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Изменить \"Сохранить в\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "TMAINFORM.MIFAVORITESCHECKNEWCHAPTER.CAPTION" +msgid "Check for new chapter" +msgstr "Проверить на новые главы" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Удалить" + +#: tmainform.mifavoritesdisable.caption +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Отключить" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Загрузить все" + +#: tmainform.mifavoritesenable.caption +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Включить" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Открыть папку" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Открыть..." + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Не проверять на новые главы" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Информация о манге" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Подсветить новую мангу" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Добавить в избранное" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Удалить" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Загрузить все" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Информация о манге" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "После завершения загрузки:" + +#: tmainform.mitrayexit.caption +msgctxt "TMAINFORM.MITRAYEXIT.CAPTION" +msgid "Exit" +msgstr "Выход" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Выход" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Hibernate" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Бесплатно" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Неисправность" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Восстановить" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Продолжить все" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "TMAINFORM.MITRAYSHOWDROPBOX.CAPTION" +msgid "Show Drop Box" +msgstr "Показать Drop Box" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Остановить все" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Загрузите все списки с сервера одновременно" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "TMAINFORM.MNFILTERGENREALLCHECK.CAPTION" +msgid "Check all" +msgstr "Отметить все" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Определить все" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "TMAINFORM.MNFILTERGENREALLUNCHECK.CAPTION" +msgid "Uncheck all" +msgstr "Снить выделение со всех" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Обновление всех списков одновременно" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Загрузить список манги с сервера" + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Обновить список манги" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Содержит все отмеченные жанры" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Содержит один из отмеченных жанров" + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Режим" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "Сохранить загруженные главы как" + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (без потерь), lower = DCTEncode (с потерями)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Удалить все выполненные задачи" + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Продолжить все" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Остановить все" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Свернуть все" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Раскрыть все" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "О программе" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "О программе" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Учётные записи" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Журнал изменений" + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Соединение" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Пользовательские цвета" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "Диалоги" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr "Загрузки" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Избранное" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "Основные" + +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Фильтр" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "Информация" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Информация о манге" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Лог" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Разное" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Настройки" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Сохранение" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Обновления" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Вид" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Расширенные" + +#: tmainform.tswebsiteoptions.caption +msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" +msgid "Options" +msgstr "Настройки" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Веб-сайты" + +#: tmainform.tswebsiteselection.caption +msgctxt "TMAINFORM.TSWEBSITESELECTION.CAPTION" +msgid "Websites" +msgstr "Веб-сайты" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Манга" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Статус" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "Прогресс" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Скоростъ передачи данных" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Сайт" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Сохранить в" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Добавлена" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Название" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Текущая глава" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Сайт" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Сохранить в" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "Отмена" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "Загрузить" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "Добавить в очередь" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "Прервать" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "Сейчас" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "Позже" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "Обновить" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "" +"Найдена новая версия! Хотите обновить сейчас? \n" +"FMD будет закрыт для завершения обновления. \n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM1.CAPTION" +msgid "Add" +msgstr "Добавить" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM2.CAPTION" +msgid "Edit" +msgstr "Правка" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM4.CAPTION" +msgid "Delete" +msgstr "Удалить" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Куки" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Номер страницы папки" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "TWEBSITEOPTIONADVANCEDFORM.TSDOWNLOADS.CAPTION" +msgid "Downloads" +msgstr "Загрузки" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Максимальное количество потоков на задание" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Количество потоков" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Обновление списка" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "Сайт" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[1].TEXT" +msgid "Cookies" +msgstr "Файлы Cookie" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTDOWNLOADMAXTHREADSPERTASK.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "Сайт" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Значение" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "Сайт" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[1].TEXT" +msgid "Value" +msgstr "Значение" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "Сайт" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[1].TEXT" +msgid "Value" +msgstr "Значение" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[0].TEXT" +msgid "Website" +msgstr "Сайт" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[1].TEXT" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Выбрать сайт" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Сжатие..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Отключено" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "Загрузка" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Неудачно" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Не удалось создать каталог!" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Не удалось, попробуйте возобновить эту задачу!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Завершено" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Подготовка" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Остановлено" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Ожидание..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "Добавить в очередь" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "Отмена" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Проверить на новые главы" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "Загрузить" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "Удалить" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "Найдено %d завершенной манги" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "Проверка избранного запущена!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d manga (s) имеют новую главу (главы)" + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "%s <%s> имеет %d новых глав." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "Завершенная манга будет удалена::" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "Найдено %d новая глава из %d manga (s):" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Загрузка: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Проверить новую версию" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "Установленная версия" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Последняя версия " + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Найдена новая версия!" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "%s имеет %d новой манги" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Получение каталога" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Получение информации" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Получение списка для" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Индексация новых названий" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Поиск новых названий" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Поиск новых названий из другого каталога" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Подготовка" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Удаление дубликатов из текущих данных" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Удаление дубликатов из локальных данных" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Удаление дубликатов из новых названий" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Сохранение данных" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Синхронизацияе данных" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Обновление списка" diff --git a/mangadownloader/languages/updater.ru_RU.po b/mangadownloader/languages/updater.ru_RU.po new file mode 100644 index 000000000..56e9a646c --- /dev/null +++ b/mangadownloader/languages/updater.ru_RU.po @@ -0,0 +1,108 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: 0.9.118.0\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Tokc.D.K. <tokcdk@gmail.com>\n" +"Language-Team: TokcDK\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru_RU\n" +"X-Generator: Poedit 2.0.2\n" + +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "Free Manga Downloader - Обновление" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Размер файла" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Ожидание..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Скорость передачи" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Помощь" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "Не удалось извлечь файл, т.к. 7za.exe не найден!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "При загрузке файла произошла ошибка." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "Загружается [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Ошбка сохранения файла, проверьте свой антивирус!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Не удалось загрузить файл!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Не удалось загрузить страницу!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Файл не найден!" + +#: umain.rs_finished +msgid "Finished." +msgstr "Завершено." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "Неверный адрес!" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Загрузка страницы..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Перенаправлено..." + +#: umain.rs_response +msgid "Response" +msgstr "Ответ" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "Попытка загрузки[%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Попытка загрузки страницы[%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Сохранение файла... " + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Ошибка ответа сервера!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(неизвестно)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Распаковка файла [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Ожидание закрытия основного приложения..." From e38f1a40aee8b7edc707993911ad80609e2024c8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 27 Jun 2017 08:25:58 +0800 Subject: [PATCH 1804/2794] mangasee, fixed download fixed #641 --- baseunits/modules/MangaLife.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 46ef3f452..06bdf1619 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -215,7 +215,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - XPathStringAll('//*[@class="image-container"]//img/@src', PageLinks); + XPathStringAll('//*[contains(@class,"image-container")]//img/@src', PageLinks); finally Free; end; From 6a7d1c54018bb705fcc63e71d555b5d24931c2a2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 30 Jun 2017 03:51:29 +0800 Subject: [PATCH 1805/2794] myreadingmanga, fixed download fixed #640 --- baseunits/modules/MyReadingManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MyReadingManga.pas b/baseunits/modules/MyReadingManga.pas index 23b0b4674..7e1af3d93 100644 --- a/baseunits/modules/MyReadingManga.pas +++ b/baseunits/modules/MyReadingManga.pas @@ -89,7 +89,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('//*[contains(@class,"entry-content")]/div/img/@src', Document, PageLinks); + XPathStringAll('//*[contains(@class,"entry-content")]//div//img/@src', Document, PageLinks); end; end; end; From 349a1e1c64dc7e067b32473cbcc36335053bb71e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 1 Jul 2017 09:03:35 +0800 Subject: [PATCH 1806/2794] websitemodules, added beforeupdatelist, afterupdatelist --- baseunits/WebsiteModules.pas | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 29c60eb6e..3caad405e 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -26,6 +26,8 @@ interface TModuleContainer = class; + TOnBeforeUpdateList = function(const Module: TModuleContainer): Boolean; + TOnAfterUpdateList = function(const Module: TModuleContainer): Boolean; TOnGetDirectoryPageNumber = function(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; TOnGetNameAndLink = function(const MangaInfo: TMangaInformation; @@ -88,6 +90,8 @@ TModuleContainer = class TotalDirectoryPage: array of Integer; CurrentDirectoryIndex: Integer; OptionList: array of TWebsiteOptionItem; + OnBeforeUpdateList: TOnBeforeUpdateList; + OnAfterUpdateList: TOnAfterUpdateList; OnGetDirectoryPageNumber: TOnGetDirectoryPageNumber; OnGetNameAndLink: TOnGetNameAndLink; OnGetInfo: TOnGetInfo; @@ -144,6 +148,8 @@ TWebsiteModules = class function ModuleAvailable(const AWebsite: String; var OutIndex: Integer): Boolean; overload; + function BeforeUpdateList(const ModuleId: Integer): Boolean; + function AfterUpdateList(const ModuleId: Integer): Boolean; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer): Integer; overload; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; @@ -452,6 +458,24 @@ function TWebsiteModules.ModuleAvailable(const AWebsite: String; Result := OutIndex > -1; end; +function TWebsiteModules.BeforeUpdateList(const ModuleId: Integer): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnBeforeUpdateList) then + Result := OnBeforeUpdateList(TModuleContainer(FModuleList[ModuleId])); +end; + +function TWebsiteModules.AfterUpdateList(const ModuleId: Integer): Boolean; +begin + Result := False; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnAfterUpdateList) then + Result := OnAfterUpdateList(TModuleContainer(FModuleList[ModuleId])); +end; + function TWebsiteModules.GetDirectoryPageNumber( const MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer ): Integer; From 614ebddfd2e7279a710f26ac923f167ec011e259 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 1 Jul 2017 09:04:26 +0800 Subject: [PATCH 1807/2794] updatethread, integrate beforeupdatelist, afterupdatelist --- baseunits/uUpdateThread.pas | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 0886ab710..b8252d262 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -23,12 +23,11 @@ TUpdateListManagerThread = class; TUpdateListThread = class(TBaseThread) protected Info: TMangaInformation; - checkStyle: TCheckStyleType; - workPtr: Integer; - manager: TUpdateListManagerThread; - procedure Execute; override; public + checkStyle: TCheckStyleType; + manager: TUpdateListManagerThread; + workPtr: Integer; title, link: String; constructor Create; destructor Destroy; override; @@ -141,15 +140,8 @@ procedure TUpdateListThread.Execute; case CheckStyle of CS_DIRECTORY_COUNT: begin - if manager.ModuleId > -1 then - begin - with Modules.Module[manager.ModuleId] do - for i := Low(TotalDirectoryPage) to High(TotalDirectoryPage) do - begin - CurrentDirectoryIndex := i; - info.GetDirectoryPage(TotalDirectoryPage[i], manager.website); - end; - end + if manager.ModuleId <> -1 then + info.GetDirectoryPage(Modules[manager.ModuleId].TotalDirectoryPage[workPtr], manager.website) else info.GetDirectoryPage(manager.directoryCount, manager.website); end; @@ -605,8 +597,18 @@ procedure TUpdateListManagerThread.Execute; // get directory page count directoryCount := 0; workPtr := 0; - GetInfo(1, CS_DIRECTORY_COUNT); - if Terminated then Break; + if ModuleId <> -1 then begin + Modules.BeforeUpdateList(ModuleId); + GetInfo(Modules[ModuleId].TotalDirectory, CS_DIRECTORY_COUNT); + end + else + GetInfo(1, CS_DIRECTORY_COUNT); + + if Terminated then begin + if ModuleId <> -1 then + Modules.AfterUpdateList(ModuleId); + Break; + end; mainDataProcess.OpenTable('',True); FIsPreListAvailable:=mainDataProcess.RecordCount>0; @@ -627,12 +629,15 @@ procedure TUpdateListManagerThread.Execute; CurrentDirectoryIndex := j; GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); Inc(j); + if Terminated then Break; end; end; end else GetInfo(directoryCount, CS_DIRECTORY_PAGE); + if ModuleId <> -1 then + Modules.BeforeUpdateList(ModuleId); if Terminated then Break; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', From 40b61d77f2dee52ede3d81d09318867db6469e2f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 1 Jul 2017 09:05:15 +0800 Subject: [PATCH 1808/2794] madokami, fixed update list --- baseunits/modules/Madokami.pas | 81 ++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 678810f6c..b0f1d7acd 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -32,6 +32,7 @@ implementation var madokamiauth: String = ''; locklogin: TRTLCriticalSection; + madokamiulist: array of TStrings; function Login(const AHTTP: THTTPSendThread): Boolean; begin @@ -97,14 +98,49 @@ function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; end; end; +procedure ClearMadokamiUlist; +var + i: Integer; +begin + if Length(madokamiulist) <> 0 then begin + for i := Low(madokamiulist) to High(madokamiulist) do + FreeAndNil(madokamiulist[i]); + SetLength(madokamiulist, 0); + end; +end; + +function BeforeUpdateList(const Module: TModuleContainer): Boolean; +var + i: Integer; +begin + Result := True; + ClearMadokamiUlist; + SetLength(madokamiulist, Length(madokamilist)); + for i := Low(madokamiulist) to High(madokamiulist) do + madokamiulist[i] := TStringList.Create; +end; + +function AfterUpdateList(const Module: TModuleContainer): Boolean; +begin + Result := True; + ClearMadokamiUlist; +end; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const Module: TModuleContainer): Integer; +var + workPtr: Integer; begin Result := NO_ERROR; - if Module.CurrentDirectoryIndex = 0 then - Page := Length(madokamilist) + workPtr := TUpdateListThread(MangaInfo.Thread).workPtr; + if workPtr < Length(madokamilist) then begin + if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/Manga/' + madokamilist[workPtr+1]) then begin + XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, madokamiulist[workPtr]); + Page := madokamiulist[workPtr].Count; + end; + end else - Page := Length(madokamiotherlist); + Page := 1; end; function GetNameAndLink(const MangaInfo: TMangaInformation; @@ -139,42 +175,30 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; end; var - currentdir, i, j: Integer; + workPtr, i: Integer; u: String; - l1, l2: TStringList; + l1: TStrings; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - currentdir := StrToIntDef(AURL, 0); - u := Module.RootURL; - if Module.CurrentDirectoryIndex = 0 then begin - Inc(currentdir); - u += '/Manga/' + madokamilist[currentdir] - end + workPtr := StrToIntDef(AURL, 0); + if Module.CurrentDirectoryIndex < Length(madokamilist) then + u := MaybeFillHost(Module.RootURL, madokamiulist[Module.CurrentDirectoryIndex][workPtr]) else - u += madokamiotherlist[currentdir]; + u := Module.RootURL + madokamiotherlist[Module.CurrentDirectoryIndex-Length(madokamilist)]; if GETWithLogin(MangaInfo.FHTTP, u) then begin Result := NO_ERROR; - if Module.CurrentDirectoryIndex = 0 then begin + if Module.CurrentDirectoryIndex < Length(madokamilist) then begin l1 := TStringList.Create; - l2 := TStringList.Create; try XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, l1); for i := 0 to l1.Count - 1 do begin if MangaInfo.Thread.IsTerminated then Break; - if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l1[i])) then begin - XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, l2); - for j := 0 to l2.Count - 1 do begin - if MangaInfo.Thread.IsTerminated then Break; - if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l2[j])) then begin - GetList; - end; - end; - end; + if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l1[i])) then + GetList; end; finally l1.Free; - l2.Free; end; end else @@ -273,9 +297,11 @@ procedure RegisterModule; Website := modulename; RootURL := urlroot; AccountSupport := True; - MaxTaskLimit := 1; - MaxConnectionLimit := 4; - TotalDirectory := 2; + //MaxTaskLimit := 1; + //MaxConnectionLimit := 4; + TotalDirectory := Length(madokamilist) + Length(madokamiotherlist); + OnBeforeUpdateList := @BeforeUpdateList; + OnAfterUpdateList := @AfterUpdateList; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; @@ -290,6 +316,7 @@ initialization RegisterModule; finalization + ClearMadokamiUlist; DoneCriticalsection(locklogin); end. From a859175e3af4f72f82eef2003ab1fcdccccff8c6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 1 Jul 2017 09:27:37 +0800 Subject: [PATCH 1809/2794] websitemodules, changed getdirectorypagenumber parameter --- baseunits/WebsiteModules.pas | 22 +++++++++++----------- baseunits/modules/AcademyVN.pas | 2 +- baseunits/modules/Batoto.pas | 4 ++-- baseunits/modules/Blogtruyen.pas | 2 +- baseunits/modules/Doujinmoeus.pas | 2 +- baseunits/modules/EHentai.pas | 2 +- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/modules/FunManga.pas | 2 +- baseunits/modules/Hakihome.pas | 2 +- baseunits/modules/Hentai2Read.pas | 2 +- baseunits/modules/HentaiCafe.pas | 2 +- baseunits/modules/HentaiFox.pas | 2 +- baseunits/modules/HeyMangaXyz.pas | 2 +- baseunits/modules/HitomiLa.pas | 2 +- baseunits/modules/KissManga.pas | 2 +- baseunits/modules/KuManga.pas | 2 +- baseunits/modules/LeoManga.pas | 2 +- baseunits/modules/Luscious.pas | 2 +- baseunits/modules/Madokami.pas | 11 ++++------- baseunits/modules/MangaBackup.pas | 2 +- baseunits/modules/MangaChanRU.pas | 2 +- baseunits/modules/MangaEden.pas | 2 +- baseunits/modules/MangaGo.pas | 2 +- baseunits/modules/MangaHome.pas | 2 +- baseunits/modules/MangaLife.pas | 2 +- baseunits/modules/MangaPark.pas | 2 +- baseunits/modules/MangaReader.pas | 2 +- baseunits/modules/MangaSaurus.pas | 2 +- baseunits/modules/MangaStream.pas | 2 +- baseunits/modules/MangaZuki.pas | 2 +- baseunits/modules/MintMangaRU.pas | 2 +- baseunits/modules/MyMangaMe.pas | 2 +- baseunits/modules/MyReadingManga.pas | 2 +- baseunits/modules/Pururin.pas | 2 +- baseunits/modules/ReadMangaToday.pas | 2 +- baseunits/modules/Seemh.pas | 2 +- baseunits/modules/SenManga.pas | 2 +- baseunits/modules/Submanga.pas | 2 +- baseunits/modules/Tapas.pas | 2 +- baseunits/modules/Tsumino.pas | 2 +- baseunits/modules/Tumangaonline.pas | 2 +- baseunits/modules/UnionMangas.pas | 2 +- baseunits/modules/WPAdultSiteSkins.pas | 2 +- baseunits/modules/WPManga.pas | 2 +- baseunits/modules/WebtoonTr.pas | 11 +++++++++-- baseunits/uData.pas | 4 ++-- 46 files changed, 69 insertions(+), 65 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 3caad405e..85fdaf323 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -29,7 +29,7 @@ TModuleContainer = class; TOnBeforeUpdateList = function(const Module: TModuleContainer): Boolean; TOnAfterUpdateList = function(const Module: TModuleContainer): Boolean; TOnGetDirectoryPageNumber = function(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; TOnGetNameAndLink = function(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; @@ -151,9 +151,9 @@ TWebsiteModules = class function BeforeUpdateList(const ModuleId: Integer): Boolean; function AfterUpdateList(const ModuleId: Integer): Boolean; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const ModuleId: Integer): Integer; overload; + var Page: Integer; const WorkPtr: Integer; const ModuleId: Integer): Integer; overload; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const AWebsite: String): Integer; overload; + var Page: Integer; const WorkPtr: Integer; const AWebsite: String): Integer; overload; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; @@ -477,22 +477,22 @@ function TWebsiteModules.AfterUpdateList(const ModuleId: Integer): Boolean; end; function TWebsiteModules.GetDirectoryPageNumber( - const MangaInfo: TMangaInformation; var Page: Integer; const ModuleId: Integer - ): Integer; + const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; + const ModuleId: Integer): Integer; begin Page := 1; Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber) then - Result := TModuleContainer(FModuleList[ModuleId]).OnGetDirectoryPageNumber( - MangaInfo, Page, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnGetDirectoryPageNumber) then + Result := OnGetDirectoryPageNumber(MangaInfo, Page, WorkPtr,TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.GetDirectoryPageNumber( - const MangaInfo: TMangaInformation; var Page: Integer; const AWebsite: String - ): Integer; + const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; + const AWebsite: String): Integer; begin - Result := GetDirectoryPageNumber(MangaInfo, Page, LocateModule(AWebsite)); + Result := GetDirectoryPageNumber(MangaInfo, Page, WorkPtr, LocateModule(AWebsite)); end; function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 5f127eeb2..2cc46fd5b 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -14,7 +14,7 @@ implementation dirurl = '/manga/all'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index c8419d8be..49e614601 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -152,14 +152,14 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String): Boolean end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[WorkPtr] + dirparam + IntToStr(perpage)) then begin Result := NO_ERROR; diff --git a/baseunits/modules/Blogtruyen.pas b/baseunits/modules/Blogtruyen.pas index 31dfb4601..5dc1bd734 100644 --- a/baseunits/modules/Blogtruyen.pas +++ b/baseunits/modules/Blogtruyen.pas @@ -15,7 +15,7 @@ implementation const dirurl = '/ajax/Search/AjaxLoadListManga?key=tatca&orderBy=1&p='; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index 61c4ec5c9..c0e40a512 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -13,7 +13,7 @@ implementation simplehtmltreeparser, xquery; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Page := 100; Result := NO_ERROR; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 836d454bb..1cf5253de 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -110,7 +110,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL, AWebsite: String end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 8fa92a2e4..4198373f7 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -60,7 +60,7 @@ function GetDirURL(const AWebsite: String): String; end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var v: IXQValue; p: Integer; diff --git a/baseunits/modules/FunManga.pas b/baseunits/modules/FunManga.pas index 4b84bb660..f28b785fc 100644 --- a/baseunits/modules/FunManga.pas +++ b/baseunits/modules/FunManga.pas @@ -15,7 +15,7 @@ implementation diralpha = '#abcdefghijklmnopqrstuvwxyz'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := Length(diralpha); diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index c75170140..8791ece4a 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -14,7 +14,7 @@ implementation dirurl = '/listmangahentai.html'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; s: String; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index df6ab8a06..13b3975a4 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -15,7 +15,7 @@ interface implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index 0a24f26b4..fa1089542 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -14,7 +14,7 @@ implementation synautil; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin diff --git a/baseunits/modules/HentaiFox.pas b/baseunits/modules/HentaiFox.pas index c9b586239..f28a26fe2 100644 --- a/baseunits/modules/HentaiFox.pas +++ b/baseunits/modules/HentaiFox.pas @@ -11,7 +11,7 @@ interface implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; if MangaInfo.FHTTP.GET(Module.RootURL) then diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index e124d20ea..843ea27d4 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -14,7 +14,7 @@ implementation dirurl = '/manga-series/new/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index ebf803df3..5098ea854 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -11,7 +11,7 @@ interface implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var source: TStringList; i: Integer; diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 034444ad4..aa5b23e21 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -35,7 +35,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; begin diff --git a/baseunits/modules/KuManga.pas b/baseunits/modules/KuManga.pas index 6b4555864..799499c9a 100644 --- a/baseunits/modules/KuManga.pas +++ b/baseunits/modules/KuManga.pas @@ -17,7 +17,7 @@ implementation dirperpage + '&page='; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; begin diff --git a/baseunits/modules/LeoManga.pas b/baseunits/modules/LeoManga.pas index 4aa80931b..3db55fc48 100644 --- a/baseunits/modules/LeoManga.pas +++ b/baseunits/modules/LeoManga.pas @@ -14,7 +14,7 @@ implementation dirurl = '/directorio-manga?orden=alfabetico'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 82d86693d..64f4b7f3a 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -14,7 +14,7 @@ implementation dirurl = '/c/-/albums/frontpage/0/t/manga/sorted/new/page/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1/') then diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index b0f1d7acd..4f0ed1f2e 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -127,16 +127,13 @@ function AfterUpdateList(const Module: TModuleContainer): Boolean; end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; -var - workPtr: Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; - workPtr := TUpdateListThread(MangaInfo.Thread).workPtr; if workPtr < Length(madokamilist) then begin - if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/Manga/' + madokamilist[workPtr+1]) then begin - XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, madokamiulist[workPtr]); - Page := madokamiulist[workPtr].Count; + if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/Manga/' + madokamilist[WorkPtr+1]) then begin + XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, madokamiulist[WorkPtr]); + Page := madokamiulist[WorkPtr].Count; end; end else diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index 7d6ddb63f..87c2c6cab 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -11,7 +11,7 @@ interface implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 4ce72d916..aca759e03 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -15,7 +15,7 @@ implementation perpage = 20; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; begin diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index c6ffa16dd..23df79cd2 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -17,7 +17,7 @@ implementation MMangaEden, MMangaEdenIT, MPervEden, MPervEdenIT: TModuleContainer; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index f48302b0d..f7a317d6c 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -22,7 +22,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolea end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/MangaHome.pas b/baseunits/modules/MangaHome.pas index 871dc2e29..2b5350aa7 100644 --- a/baseunits/modules/MangaHome.pas +++ b/baseunits/modules/MangaHome.pas @@ -14,7 +14,7 @@ implementation dirurl = '/directory'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 06bdf1619..7685c6317 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -84,7 +84,7 @@ function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String): Bool end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; if Module = MMangaTraders then diff --git a/baseunits/modules/MangaPark.pas b/baseunits/modules/MangaPark.pas index a9ba99fcc..b34c4d2e1 100644 --- a/baseunits/modules/MangaPark.pas +++ b/baseunits/modules/MangaPark.pas @@ -14,7 +14,7 @@ implementation dirurl = '/search?orderby=add'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 8b1dad06d..840859943 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -17,7 +17,7 @@ implementation dirurl = '/alphabetical'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := 1; diff --git a/baseunits/modules/MangaSaurus.pas b/baseunits/modules/MangaSaurus.pas index f65462e01..d52ad1268 100644 --- a/baseunits/modules/MangaSaurus.pas +++ b/baseunits/modules/MangaSaurus.pas @@ -15,7 +15,7 @@ implementation domainImage = 'http://img.mangasaurus.com'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; begin diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 5ba67b6a0..8b5e39944 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -16,7 +16,7 @@ implementation readURL = 'http://readms.com'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Page := 1; Result := NO_ERROR; diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 4362a3a04..1cd9904e2 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -14,7 +14,7 @@ implementation dirurl = '/series'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index a0647cafb..2bac355ef 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -15,7 +15,7 @@ implementation perpage = 70; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; begin diff --git a/baseunits/modules/MyMangaMe.pas b/baseunits/modules/MyMangaMe.pas index 49cd14840..0836590a1 100644 --- a/baseunits/modules/MyMangaMe.pas +++ b/baseunits/modules/MyMangaMe.pas @@ -14,7 +14,7 @@ implementation dirurl = '/manga-directory/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/MyReadingManga.pas b/baseunits/modules/MyReadingManga.pas index 7e1af3d93..05a16d50b 100644 --- a/baseunits/modules/MyReadingManga.pas +++ b/baseunits/modules/MyReadingManga.pas @@ -20,7 +20,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolea Result := Cloudflare.GETCF(AHTTP, AURL, myreadingmangacf) end; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; diff --git a/baseunits/modules/Pururin.pas b/baseunits/modules/Pururin.pas index 054d2d3a8..19abe05cb 100644 --- a/baseunits/modules/Pururin.pas +++ b/baseunits/modules/Pururin.pas @@ -11,7 +11,7 @@ interface implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; if MangaInfo.FHTTP.GET(Module.RootURL) then diff --git a/baseunits/modules/ReadMangaToday.pas b/baseunits/modules/ReadMangaToday.pas index 1483e6ea1..4ab04735f 100644 --- a/baseunits/modules/ReadMangaToday.pas +++ b/baseunits/modules/ReadMangaToday.pas @@ -14,7 +14,7 @@ implementation dirurls = ' abcdefghijklmnopqrstuvwxyz'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; Page := Length(dirurls); diff --git a/baseunits/modules/Seemh.pas b/baseunits/modules/Seemh.pas index 43d748e6b..4e038ea85 100644 --- a/baseunits/modules/Seemh.pas +++ b/baseunits/modules/Seemh.pas @@ -14,7 +14,7 @@ implementation dirurl='/list/'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var query: TXQueryEngineHTML; begin diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas index 27f528b24..193dd919f 100644 --- a/baseunits/modules/SenManga.pas +++ b/baseunits/modules/SenManga.pas @@ -14,7 +14,7 @@ implementation dirurl = '/directory'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index a85300a54..897c20592 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -14,7 +14,7 @@ implementation dirurl = '/series'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index 9ce4330db..ea00757b7 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -22,7 +22,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Result := Cloudflare.GETCF(AHTTP, AURL, tapascf) end; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; var s: String; diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index b261c4291..c704cb84a 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -18,7 +18,7 @@ implementation dirurldataend = '&RawSearch=&SortOptions=Newest&PageMinimum=1&PageMaximum=10000&RateMinimum=0&RateMaximum=5'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 158c8a3d9..638178618 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -28,7 +28,7 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Result := Cloudflare.GETCF(AHTTP, AURL, tumangacf); end; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 48e1c0579..b2609563e 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -14,7 +14,7 @@ implementation dirurl = '/mangas'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas index 31d452b4d..aff7ed295 100644 --- a/baseunits/modules/WPAdultSiteSkins.pas +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -11,7 +11,7 @@ interface implementation function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const Module: TModuleContainer): Integer; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index b86c5908c..5c84a41b7 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -25,7 +25,7 @@ function GetDirURL(const AModule: TModuleContainer): String; Result := '/' + Result + '/all/any/last-added/'; end; -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Page := 1; diff --git a/baseunits/modules/WebtoonTr.pas b/baseunits/modules/WebtoonTr.pas index 689bcb722..d5f50f3cf 100644 --- a/baseunits/modules/WebtoonTr.pas +++ b/baseunits/modules/WebtoonTr.pas @@ -17,6 +17,13 @@ implementation '/ero-listesi' ); +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := Length(dirurls); +end; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; @@ -25,7 +32,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[StrToIntDef(AURL, 0)]) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -110,7 +117,7 @@ procedure RegisterModule; begin Website := 'WebtoonTr'; RootURL := 'http://webtoontr.com'; - TotalDirectory := Length(dirurls); + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 52946586a..99340ac2b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -120,7 +120,7 @@ implementation uses Dialogs, fpJSON, JSONParser, jsonscanner, FastHTMLParser, HTMLUtil, - SynaCode, frmMain, WebsiteModules; + SynaCode, frmMain, WebsiteModules, uUpdateThread; // ----- TDataProcess ----- @@ -824,7 +824,7 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if ModuleId < 0 then ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then - Result := Modules.GetDirectoryPageNumber(Self, APage, ModuleId) + Result := Modules.GetDirectoryPageNumber(Self, APage, TUpdateListThread(Thread).workPtr, ModuleId) else begin MangaSiteID := GetMangaSiteID(AWebsite); From 5462783329bcf151f9dbf79dae81e2f8229b46e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 1 Jul 2017 09:42:26 +0800 Subject: [PATCH 1810/2794] moved updater.ru to updater languages --- .../languages/updater.ru_RU.po | 216 +++++++++--------- 1 file changed, 108 insertions(+), 108 deletions(-) rename {mangadownloader => updater}/languages/updater.ru_RU.po (96%) diff --git a/mangadownloader/languages/updater.ru_RU.po b/updater/languages/updater.ru_RU.po similarity index 96% rename from mangadownloader/languages/updater.ru_RU.po rename to updater/languages/updater.ru_RU.po index 56e9a646c..3c1c05184 100644 --- a/mangadownloader/languages/updater.ru_RU.po +++ b/updater/languages/updater.ru_RU.po @@ -1,108 +1,108 @@ -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: 0.9.118.0\n" -"POT-Creation-Date: \n" -"PO-Revision-Date: \n" -"Last-Translator: Tokc.D.K. <tokcdk@gmail.com>\n" -"Language-Team: TokcDK\n" -"MIME-Version: 1.0\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: ru_RU\n" -"X-Generator: Poedit 2.0.2\n" - -#: tfrmmain.caption -msgid "Free Manga Downloader - Updater" -msgstr "Free Manga Downloader - Обновление" - -#: tfrmmain.lbfilesize.caption -msgid "File size" -msgstr "Размер файла" - -#: tfrmmain.lbstatus.caption -msgid "Waiting..." -msgstr "Ожидание..." - -#: tfrmmain.lbtransferrate.caption -msgid "Transfer rate" -msgstr "Скорость передачи" - -#: tfrmmessage.caption -msgid "Help" -msgstr "Помощь" - -#: umain.rs_7znotfound -msgid "Can't extract file because 7za.exe not found!" -msgstr "Не удалось извлечь файл, т.к. 7za.exe не найден!" - -#: umain.rs_anerroroccured -msgid "An error occured when trying to download file." -msgstr "При загрузке файла произошла ошибка." - -#: umain.rs_downloading -msgid "Downloading [%s]..." -msgstr "Загружается [%s]..." - -#: umain.rs_errorcheckantivirus -msgid "Error saving file, check your AntiVirus!" -msgstr "Ошбка сохранения файла, проверьте свой антивирус!" - -#: umain.rs_faileddownloadpage -msgid "Failed downloading file!" -msgstr "Не удалось загрузить файл!" - -#: umain.rs_failedloadpage -msgid "Failed loading page!" -msgstr "Не удалось загрузить страницу!" - -#: umain.rs_filenotfound -msgid "File not found!" -msgstr "Файл не найден!" - -#: umain.rs_finished -msgid "Finished." -msgstr "Завершено." - -#: umain.rs_invalidurl -msgid "Invalid URL!" -msgstr "Неверный адрес!" - -#: umain.rs_loadingpage -msgid "Loading page..." -msgstr "Загрузка страницы..." - -#: umain.rs_redirected -msgid "Redirected..." -msgstr "Перенаправлено..." - -#: umain.rs_response -msgid "Response" -msgstr "Ответ" - -#: umain.rs_retrydownloading -msgid "Retry downloading[%d] [%s]..." -msgstr "Попытка загрузки[%d] [%s]..." - -#: umain.rs_retryloadpage -msgid "Retry loading page[%d]..." -msgstr "Попытка загрузки страницы[%d]..." - -#: umain.rs_savefile -msgid "Saving file... " -msgstr "Сохранение файла... " - -#: umain.rs_servererror -msgid "Server response error!" -msgstr "Ошибка ответа сервера!" - -#: umain.rs_unknown -msgid "(unknown)" -msgstr "(неизвестно)" - -#: umain.rs_unpackfile -msgid "Unpacking file [%s]..." -msgstr "Распаковка файла [%s]..." - -#: umain.rs_waitmainapp -msgid "Waiting main app to close..." -msgstr "Ожидание закрытия основного приложения..." +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: 0.9.118.0\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Tokc.D.K. <tokcdk@gmail.com>\n" +"Language-Team: TokcDK\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ru_RU\n" +"X-Generator: Poedit 2.0.2\n" + +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "Free Manga Downloader - Обновление" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Размер файла" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Ожидание..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Скорость передачи" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Помощь" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "Не удалось извлечь файл, т.к. 7za.exe не найден!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "При загрузке файла произошла ошибка." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "Загружается [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Ошбка сохранения файла, проверьте свой антивирус!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Не удалось загрузить файл!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Не удалось загрузить страницу!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Файл не найден!" + +#: umain.rs_finished +msgid "Finished." +msgstr "Завершено." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "Неверный адрес!" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Загрузка страницы..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Перенаправлено..." + +#: umain.rs_response +msgid "Response" +msgstr "Ответ" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "Попытка загрузки[%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Попытка загрузки страницы[%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Сохранение файла... " + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Ошибка ответа сервера!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(неизвестно)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Распаковка файла [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Ожидание закрытия основного приложения..." From d63c0983d2591fd0170477726d03c23d509dc267 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 4 Jul 2017 01:47:46 +0800 Subject: [PATCH 1811/2794] cleanup --- baseunits/WebsiteModules.pas | 3 --- 1 file changed, 3 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 85fdaf323..686d4c6e7 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -236,9 +236,6 @@ implementation {$I ModuleList.inc} -const - REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - var CS_Connection: TRTLCriticalSection; From 55c2b64d7df6d9a49bf9a09b085733fa1248795e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 4 Jul 2017 01:48:48 +0800 Subject: [PATCH 1812/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index fbc5f691f..a1fe1291e 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit fbc5f691f459aebd54909bb48ec8eb2e0cbf3df2 +Subproject commit a1fe1291e3cf46686ce3df80162ec1ca29b3a36e From 8c443726f2e93f802ec0e5c6366b42091978778c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 4 Jul 2017 01:50:00 +0800 Subject: [PATCH 1813/2794] tonarinoyoungjump, fixed get chapterlist and cleanup #606 --- baseunits/modules/TonarinoYoungJump.pas | 47 ++++++------------------- 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonarinoYoungJump.pas index c28c06ddd..f1152c7df 100644 --- a/baseunits/modules/TonarinoYoungJump.pas +++ b/baseunits/modules/TonarinoYoungJump.pas @@ -4,42 +4,26 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr, Dialogs; + XQueryEngineHTML; implementation -const - dirurl = '/comics/'; - function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + if MangaInfo.FHTTP.GET(Module.RootURL + '/comics/') then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//ul[@class="manga-list__list"]/li/h4/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; + XPathHREFAll('//ul[@class="manga-list__list"]/li/h4/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - s, n: String; v: IXQValue; - i: Integer; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -56,11 +40,12 @@ function GetInfo(const MangaInfo: TMangaInformation; summary := XPathString('//*[@class="single-story"]/p'); { there is no chapter list? assuming the first chapter link in manga info is always the last chapters } - for v in XPath('//a[@class="single"]') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end + for v in XPath('//li/a[contains(@class,"single")]') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('./text()[1]', v)); + end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -70,9 +55,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - ViewerURL: String; begin Result := False; if DownloadThread = nil then Exit; @@ -80,17 +62,10 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - ViewerURL := 'http://viewer.tonarinoyj.jp'; - if GET(FillHost(ViewerURL, AURL)) then + if GET(MaybeFillHost('http://viewer.tonarinoyj.jp', AURL)) then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//img[@class="js-page-image"]') do - PageLinks.Add(v.toNode.getAttribute('src')); - finally - Free; - end; + XPathStringAll('//img[@class="js-page-image"]/@src', Document, PageLinks); end; end; end; From 629f778a912015188d40eddec515017beef9934c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 11 Jul 2017 05:56:48 +0800 Subject: [PATCH 1814/2794] mangazuki, reverse chapter list fixed #655 --- baseunits/modules/MangaZuki.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 1cd9904e2..0b9f84b7b 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -78,6 +78,7 @@ function GetInfo(const MangaInfo: TMangaInformation; else Break; if ThreadTerminated then Break; end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; From 36c6f7e25cb44123008ffe9710ace5c6c3ac543d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 11 Jul 2017 06:08:25 +0800 Subject: [PATCH 1815/2794] magafox, remove last invalid page fixed #652 --- baseunits/modules/MangaFox.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index a8fc4e02a..b846d3464 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -80,13 +80,23 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin if GET(MaybeFillHost(Module.RootURL, AURL) + IncStr(DownloadThread.WorkId) + '.html') then begin Result := True; - PageLinks[DownloadThread.WorkId] := XPathString('//div[@class="read_img"]//img[@id="image"]/@src', Document); + s := XPathString('//div[@class="read_img"]//img[@id="image"]/@src', Document); + PageLinks[DownloadThread.WorkId] := s; + // remove invalid last invalid page + if (DownloadThread.WorkId = PageLinks.Count - 1) and + (RightStr(LowerCase(RemovePathDelim(s)), 10) = 'compressed') then + begin + PageLinks.Delete(DownloadThread.WorkId); + PageNumber := PageLinks.Count; + end; end; end; end; From 9659a50502da864df65c4efe4e1c9cba44f13121 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 11 Jul 2017 16:47:33 +0800 Subject: [PATCH 1816/2794] update internettools --- 3rd/internettools | 2 +- mangadownloader/md.lpi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/3rd/internettools b/3rd/internettools index a1fe1291e..78d746c1f 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit a1fe1291e3cf46686ce3df80162ec1ca29b3a36e +Subproject commit 78d746c1f3a65279444e6b70a88a09ed6a3a7b4e diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 52b7db7d9..2c2ac1e07 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -221,7 +221,7 @@ </Item5> <SharedMatrixOptions Count="2"> <Item1 ID="284095981400" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz" Value="-O3 -g- -CX -XX -Xs"/> - <Item2 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-O3 -g- -CX -XX -Xs"/> + <Item2 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks" Value="-O3 -g- -CX -XX -Xs"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From 10099d9e3a319a1cc05f2e38fff90c46c530f8b7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 18 Jul 2017 16:19:59 +0800 Subject: [PATCH 1817/2794] cf, remove previous cookies if bot active --- baseunits/modules/Cloudflare.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index e053b7802..1ce85fe79 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -176,6 +176,8 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: if AntiBotActive(AHTTP) then begin if TryEnterCriticalsection(CFProps.CS) > 0 then try + CFProps.Cookies := ''; + AHTTP.Cookies.Clear; Result := CFJS(AHTTP, AURL, CFProps.Cookies, CFProps.Expires); // reduce the expires by 5 minutes, usually it is 24 hours or 16 hours // in case of the different between local and server time From e7c9c532256c400360704ec1be6ce8030365edcc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Jul 2017 00:41:50 +0800 Subject: [PATCH 1818/2794] cleanup transfer rate graph --- mangadownloader/forms/frmMain.pas | 37 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e8888165f..7b64debb0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1228,6 +1228,15 @@ procedure TMainForm.FormCreate(Sender: TObject); // load mangafox template MangaFoxWatermark.SetTemplateDirectory(MANGAFOXTEMPLATE_FOLDER); + // hint + ShowHint := True; + Application.HintPause := 500; + Application.HintHidePause := 3000; + + // transfer rate graph + TransferRateGraphList.DataPoints.NameValueSeparator := '|'; + TransferRateGraph.Visible := False; + // load configfile isStartup := False; CollectLanguagesFromFiles; @@ -1238,11 +1247,6 @@ procedure TMainForm.FormCreate(Sender: TObject); // minimize on start if cbOptionMinimizeOnStart.Checked then Application.ShowMainForm := False; - - // hint - ShowHint := True; - Application.HintPause := 500; - Application.HintHidePause := 3000; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -1622,9 +1626,11 @@ procedure TMainForm.tmRefreshDownloadsInfoStartTimer(Sender: TObject); begin if Assigned(DLManager) then begin - TransferRateGraphInit(round(TransferRateGraph.Width/4)); + TransferRateGraphInit(round(TransferRateGraph.Width/4)+1); TransferRateGraph.Visible := True; - end; + end + else + tmRefreshDownloadsInfo.Enabled := False; end; procedure TMainForm.tmRefreshDownloadsInfoStopTimer(Sender: TObject); @@ -5553,13 +5559,9 @@ procedure TMainForm.TransferRateGraphInit(xCount: Integer); i: Integer; begin TransferRateGraphList.Clear; - TransferRateGraphList.DataPoints.NameValueSeparator := '|'; TransferRateGraphArea.Legend.Format := FormatByteSize(0, True); - if xCount=0 then - TransferRateGraphInit - else - for i:=1 to xCount do - TransferRateGraphList.DataPoints.Add(IntToStr(i)+'|0|?|'); + for i:=1 to xCount do + TransferRateGraphList.DataPoints.Add(IntToStr(i)+'|0|?|'); end; procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); @@ -5569,12 +5571,9 @@ procedure TMainForm.TransferRateGraphAddItem(TransferRate: Integer); TransferRateGraphArea.Legend.Format := FormatByteSize(TransferRate, True); with TransferRateGraphList.DataPoints do begin - if Count=0 then - TransferRateGraphInit; - for i := 0 to Count - 1 do - if i < Count - 1 then - Strings[i] := Format('%d|%s', [i+1, ValueFromIndex[i+1]]); - Strings[Count-1] := Format('%d|%d|?|',[Count,TransferRate]); + for i := 0 to Count - 2 do + Strings[i] := IntToStr(i+1)+'|'+ValueFromIndex[i+1]; + Strings[Count-1] := IntToStr(Count)+'|'+IntToStr(TransferRate)+'|?|'; end; end; From 3a1bcd031423b421935c32587f200ba3c86c35f7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Jul 2017 02:51:27 +0800 Subject: [PATCH 1819/2794] update greek translations by geogeo-gr --- mangadownloader/languages/fmd.el_GR.po | 75 ++++++++++++++------------ updater/languages/updater.el_GR.po | 6 ++- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 13064966e..ff0f15f25 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: Free Manga Downloader 0.9.85\n" +"Project-Id-Version: Free Manga Downloader 0.9.118\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: geogeo.gr <geogeo.gr@gmail.com>\n" @@ -13,10 +13,12 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-Bookmarks: -1,-1,-1,-1,-1,-1,-1,29,-1,-1\n" +"X-Poedit-Language: Greek\n" +"X-Poedit-Country: GREECE\n" #: batoto.rs_serverselection msgid "Image server:" -msgstr "" +msgstr "Διακομιστής εικόνων:" #: batoto.rs_serverselectionitems msgid "" @@ -26,6 +28,11 @@ msgid "" "CDN (default)\n" "CDN2 (testing)\n" msgstr "" +"Αυτόματα\n" +"Διακομιστής εικόνων EU\n" +"Διακομιστής εικόνων NA\n" +"CDN (προεπιλογή)\n" +"CDN2 (δοκιμαστικά)\n" #: batoto.rs_showalllang msgid "Show all language" @@ -60,7 +67,7 @@ msgstr "" "1280x\n" "1600x\n" "2400x\n" -"Αρχική\n" +"Αρχικό\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -346,11 +353,11 @@ msgstr "Το σύστημα θα τερματιστεί σε %d δευτερόλ #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" -msgstr "" +msgstr "Διάνυσμα προετοιμασίας:" #: kissmanga.rs_kissmanga_key msgid "Key:" -msgstr "" +msgstr "Κλειδί:" #: mangafox.rs_removewatermark msgid "Remove watermark" @@ -592,7 +599,7 @@ msgstr "Επίσκεψη στο blog μου" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -633,7 +640,7 @@ msgstr "Αυτόματος έλεγχος για την τελευταία έκ #: tmainform.cboptionautoopenfavstartup.caption msgid "Open Favorites at startup" -msgstr "" +msgstr "Άνοιγμα αγαπημένων στην έναρξη" #: tmainform.cboptionchangeunicodecharacter.caption #| msgid "Change all all character to" @@ -672,7 +679,7 @@ msgstr "Ενεργοποίηση ζωντανής αναζήτησης (αργή #: tmainform.cboptionminimizeonstart.caption msgid "Minimize on start" -msgstr "" +msgstr "Ελαχιστοποίηση στην έναρξη" #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" @@ -692,7 +699,7 @@ msgstr "Αφαίρεση ονόματος manga από το κεφάλαιο" #: tmainform.cboptionshowballoonhint.caption msgid "Show balloon hint" -msgstr "" +msgstr "Εμφάνιση αναδυόμενων παραθύρων συμβουλών" #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" @@ -708,7 +715,7 @@ msgstr "Εμφάνιση εργαλειοθήκης λήψεων" #: tmainform.cboptionshowdownloadtoolbardeleteall.caption msgid "Show \"Delete all completed tasks\" in downloads toolbar" -msgstr "" +msgstr "Εμφάνιση \"Διαγραφή όλων των ολοκληρωμένων εργασιών\" στην εργαλειοθήκη λήψεων" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -764,7 +771,7 @@ msgid "Contains content that is suitable only for adults. Titles in this categor msgstr "" "Περιέχει περιεχόμενο που είναι κατάλληλο μόνο για ενήλικες.\n" " Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν σκηνές παρατεταμένης έντονης \n" -"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό.\n" +"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό." #: tmainform.ckfilteradventure.caption msgid "Adventure" @@ -775,7 +782,7 @@ msgid "If a character in the story goes on a trip or along that line, your best msgstr "" "Αν ένας χαρακτήρας στην ιστορία πηγαίνει σε ταξίδι ή κατά μήκος αυτής της γραμμής, \n" "το πιθανότερο είναι ότι πρόκειται για μια περιπέτεια manga. Ειδάλλως, είναι στο χέρι σας\n" -" να αποφασίσετε γι αυτή την περίπτωση.\n" +" να αποφασίσετε γι αυτή την περίπτωση." #: tmainform.ckfiltercomedy.caption msgid "Comedy" @@ -809,7 +816,7 @@ msgstr "Ecchi" msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." msgstr "" "Ενδεχομένως η γραμμή μεταξύ Hentai και μη-Hentai, το Ecchi συνήθως αναφέρεται \n" -"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών.\n" +"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών." #: tmainform.ckfilterfantasy.caption msgid "Fantasy" @@ -840,7 +847,7 @@ msgid "A series involving one male character and many female characters (usually msgstr "" "Μια σειρά που περιλαμβάνει έναν αρσενικό χαρακτήρα και πολλούς γυναικείους \n" "(συνήθως έλκονται από τον αρσενικό χαρακτήρα). \n" -"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται.\n" +"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται." #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -868,7 +875,7 @@ msgstr "Horror" msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." msgstr "" "Ένα οδυνηρό συναίσθημα φόβου, τρόμου και αποστροφής. Ένα ανατριχιαστικό με τρόμο \n" -"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό.\n" +"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό." #: tmainform.ckfilterjosei.caption msgid "Josei" @@ -879,7 +886,7 @@ msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Un msgstr "" "Κυριολεκτικά «Γυναίκα». Απευθύνεται σε γυναίκες 18-30. Ισοδύναμο με το θηλυκό. \n" "Σε αντίθεση με το Shoujo το ειδύλλιο είναι πιο ρεαλιστικό και λιγότερο εξιδανικευμένο. \n" -"Η αφήγηση είναι πιο σαφής και ώριμη.\n" +"Η αφήγηση είναι πιο σαφής και ώριμη." #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -898,7 +905,7 @@ msgid "As the name suggests, anything martial arts related. Any of several arts msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με πολεμικές τέχνες. \n" "Οποιεσδήποτε από τις διάφορες τέχνες μάχης ή αυτοάμυνας, όπως αϊκίντο, \n" -"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά.\n" +"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά." #: tmainform.ckfiltermature.caption msgid "Mature" @@ -909,7 +916,7 @@ msgid "Contains subject matter which may be too extreme for people under the age msgstr "" "Περιέχει θέμα το οποίο μπορεί να είναι πολύ ακραίο για άτομα κάτω των 17 ετών. \n" "Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν έντονη βία, έντονη αιματοχυσία, \n" -"σεξουαλικό περιεχόμενο και σκληρή γλώσσα.\n" +"σεξουαλικό περιεχόμενο και σκληρή γλώσσα." #: tmainform.ckfiltermecha.caption msgid "Mecha" @@ -919,7 +926,7 @@ msgstr "Mecha" msgid "A work involving and usually concentrating on all types of large robotic machines." msgstr "" "Ένα έργο που περιλαμβάνει και συνήθως επικεντρώνεται σε όλους \n" -"τους τύπους των μεγάλων ρομποτικών μηχανημάτων.\n" +"τους τύπους των μεγάλων ρομποτικών μηχανημάτων." #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -939,7 +946,7 @@ msgstr "Mystery" msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." msgstr "" "Συνήθως συμβαίνει κάποιο ανεξήγητο γεγονός και ο κεντρικός \n" -"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε.\n" +"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε." #: tmainform.ckfilterpsychological.caption msgid "Psychological" @@ -949,7 +956,7 @@ msgstr "Psychological" msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." msgstr "" "Συνήθως ασχολείται με τη φιλοσοφία μιας κατάστασης του μυαλού. \n" -"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση.\n" +"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση." #: tmainform.ckfilterromance.caption msgid "Romance" @@ -959,7 +966,7 @@ msgstr "Romance" msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." msgstr "" "Οποιαδήποτε ιστορία σχετική με αγάπη. Εμείς θεωρούμε την αγάπη μεταξύ άνδρα και γυναίκας. \n" -"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι.\n" +"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι." #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -977,7 +984,7 @@ msgstr "Sci-Fi" msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." msgstr "" "Τα έργα αυτά αφορούν ανατροπές στην τεχνολογία και σε άλλα φαινόμενα σχετικά με την επιστήμη \n" -"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου.\n" +"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου." #: tmainform.ckfilterseinen.caption msgid "Seinen" @@ -988,7 +995,7 @@ msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically msgstr "" "Seinen σημαίνει «νέος άνθρωπος». Τα manga και anime που στοχεύουν ειδικά σε νεαρά ενήλικα αρσενικά,\n" " ηλικίας μεταξύ 18 και 25 ετών. Οι ιστορίες αυτές εμφανίζουν φοιτητές Πανεπιστημίου και άτομα από τον \n" -"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής.\n" +"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής." #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -1006,7 +1013,7 @@ msgstr "Shoujo" msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." msgstr "" "Ένα έργο που προορίζεται και είναι κυρίως γραμμένο για γυναίκες. \n" -"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα.\n" +"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα." #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -1017,7 +1024,7 @@ msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." msgstr "" "Συχνά συνώνυμη με το Yuri. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας κοριτσιών».\n" +"Μπορείτε να το πείτε και «Έρωτας κοριτσιών»." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -1028,7 +1035,7 @@ msgctxt "tmainform.ckfiltershounen.hint" msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." msgstr "" "Ένα έργο που προορίζεται και είναι γραμμένο κυρίως για άνδρες. \n" -"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία.\n" +"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία." #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" @@ -1038,7 +1045,7 @@ msgstr "Shounen Ai" msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" msgstr "" "Συχνά συνώνυμη με το Yaoi. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας αγοριών».\n" +"Μπορείτε να το πείτε και «Έρωτας αγοριών»." #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" @@ -1050,7 +1057,7 @@ msgstr "" "Όπως υποδηλώνει το όνομα, το είδος αυτό αντιπροσωπεύει καθημερινές δοκιμασίες \n" "από έναν ή περισσότερους χαρακτήρες. Αυτές οι προκλήσεις / εκδηλώσεις θα μπορούσαν \n" "τεχνικά να συμβούν στην πραγματική ζωή και εμφανίζονται συχνά, αν όχι συνεχώς, σε \n" -"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές.\n" +"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές." #: tmainform.ckfiltersmut.caption msgid "Smut" @@ -1068,7 +1075,7 @@ msgstr "Sports" msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με αθλήματα. \n" -"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα.\n" +"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα." #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" @@ -1078,7 +1085,7 @@ msgstr "Supernatural" msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." msgstr "" "Συνήθως συνεπάγεται εκπληκτικές και ανεξήγητες δυνάμεις ή γεγονότα \n" -"τα οποία αψηφούν τους νόμους της φυσικής.\n" +"τα οποία αψηφούν τους νόμους της φυσικής." #: tmainform.ckfiltertragedy.caption msgid "Tragedy" @@ -1528,7 +1535,7 @@ msgstr "Ματαίωση" #: tmainform.michapterlistascending.caption msgid "Ascending" -msgstr "" +msgstr "Αύξουσα" #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" @@ -1541,7 +1548,7 @@ msgstr "Σήμανση επιλεγμένων" #: tmainform.michapterlistdescending.caption msgid "Descending" -msgstr "" +msgstr "Φθίνουσα" #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" @@ -1864,7 +1871,7 @@ msgstr "Φίλτρο" #: tmainform.tsinfomanga.caption msgid "Info" -msgstr "" +msgstr "Πληροφορίες" #: tmainform.tsinformation.caption msgid "Manga Info" diff --git a/updater/languages/updater.el_GR.po b/updater/languages/updater.el_GR.po index e5245f73b..e7c351344 100644 --- a/updater/languages/updater.el_GR.po +++ b/updater/languages/updater.el_GR.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: Free Manga Downloader 0.9.85\n" +"Project-Id-Version: Free Manga Downloader 0.9.118\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: geogeo.gr <geogeo.gr@gmail.com>\n" @@ -19,6 +19,10 @@ msgstr "" msgid "Free Manga Downloader - Updater" msgstr "" +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "Free Manga Downloader - Ενημέρωση" + #: tfrmmain.lbfilesize.caption msgid "File size" msgstr "Μέγεθος αρχείου" From 20773d45301a65fdeec626c4a178da9635622855 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Jul 2017 03:14:47 +0800 Subject: [PATCH 1820/2794] Bump version 0.9.119.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index ce8a94db8..2f3559fd0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.119.0 (21-07-2017) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.118.0...0.9.119.0 + 0.9.118.0 (14-06-2017) [*] Madokami: fixed all [-] MangaKoi: removed diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 2c2ac1e07..c21dfb311 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="118"/> + <RevisionNr Value="119"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index fd109c8d0..21c4b84a9 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.118.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.118.0/fmd_0.9.118.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.118.0/fmd_0.9.118.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.118.0/fmd_0.9.118.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.118.0/fmd_0.9.118.0_Win64.7z +VERSION=0.9.119.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.119.0/fmd_0.9.119.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.119.0/fmd_0.9.119.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.119.0/fmd_0.9.119.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.119.0/fmd_0.9.119.0_Win64.7z From 2d83fdf5fdee0b1a3c6f64137d3c791c7e7946f8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Jul 2017 14:08:45 +0800 Subject: [PATCH 1821/2794] update changelog --- changelog.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/changelog.txt b/changelog.txt index 2f3559fd0..5397f025d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,14 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.119.0 (21-07-2017) +[+] Added shogakukan +[+] Added Russian translation by TokcDK +[*] Mangasee: fixed download +[*] MyReadingManga: fixed download +[*] Madokami: fixed update list +[*] TonariYoungJump: fixed chapter list +[*] Mangazuki: fixed chapter list +[*] Update Greek translation by geogeo-gr [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.118.0...0.9.119.0 From 9234c5e221a84b1a013923296b21224c1386837c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 21 Jul 2017 14:09:18 +0800 Subject: [PATCH 1822/2794] added german translation from novellis --- mangadownloader/languages/fmd.de.po | 2230 +++++++++++++++++++++++++++ 1 file changed, 2230 insertions(+) create mode 100644 mangadownloader/languages/fmd.de.po diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po new file mode 100644 index 000000000..949b7f71e --- /dev/null +++ b/mangadownloader/languages/fmd.de.po @@ -0,0 +1,2230 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: DE\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: Novellis\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de\n" +"X-Generator: Poedit 2.0.2\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "Bilder-Server:" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" +"Auto\n" +"Bilder-Server EU\n" +"Bilder-Server NA\n" +"CDN (Standard)\n" +"CDN2 (testing)\n" + +#: batoto.rs_showalllang +msgid "Show all language" +msgstr "Zeige alle Sprachen" + +#: batoto.rs_showscangroup +msgid "Show scanlation group" +msgstr "Zeige Scanlation Group" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Download Originalbilder (benötigt ExHentai account)" + +#: ehentai.rs_settingsimagesize +#| msgid "Image size" +msgid "Image size:" +msgstr "Bildgröße" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Bist du dir sicher, dass du den Account löschen willst?" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Prüfen" + +#: frmaccountmanager.rs_invalid +msgid "Invalid" +msgstr "Ungültig" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Unbekannt" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "OK" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Benutzername oder Passwort kann nicht leer sein!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "Importierung abgeschlossen." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "Liste von nicht importierten Manga" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Alle Downloads" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&OK" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "Abbrechen" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Prüfe..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "Keine Verbindung zum Server." + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "Keine Manga-Informationen abrufbar. Bitte prüfen Sie ihre Internetverbindung und versuchen Sie es erneut." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "Download zähler:" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "Wählen Sie zumindest eine Manga-Webseite aus!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Sind Sie sicher, dass Sie beenden wollen?" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Sind Sie sicher, dass Sie die Favoriten löschen wollen?" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Sind Sie sicher, dass Sie alle abgeschlossenen Aufgaben löschen wollen?" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Sind Sie sicher, dass Sie dieses Items löschen wollen?" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Sind Sie sicher, dass Sie alle Aufgaben löschen wollen?" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Download aufteilen" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "" +"Dieser Titel ist bereits in der Downloadliste.\n" +"Wollen Sie ihn dennoch laden?\n" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Tippe neues Kapitel ein:" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Tippe neuen Speicherpfad ein:" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Aktualisierung läuft!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Möchten Sie die Mangaliste vom Server laden?" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "URL wird nicht unterstützt!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "" +"Lade alle\n" +"Zu den Favoriten hinzufügen\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "" +"Abgeschlossen\n" +"Fortlaufend\n" +"<none>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader läuft bereits!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "" +"Es gibt ein Problem mit dieser Datei!\n" +"Entfernen und wieder hinzufügen dieser Datei könnte das Problem beheben.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "Verlauf" + +#: frmmain.rs_import +msgid "Import" +msgstr "Import" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Artist(en):" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Autor(en):" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Genre(s):" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Status:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Zusammenfassung:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Titel:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Webseite:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "Im Gange" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Automatisch nach neuen Kapitel alle %d Minuten suchen" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "" +"%s : Pfad zum Manga\n" +"%s : Kapitel Dateiname\n" +"\n" +"Beispiel : \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Lade ..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Modus: Zeig alle (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Mode: Gefiltert (%d)" + +#: frmmain.rs_modesearching +#| msgid "Searching..." +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Mode: Suche..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "Ein Monat" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "Eine Woche" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "" +"Nichts\n" +"Verlassen\n" +"Herunterfahren\n" +"Ruhezustand\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Ausgewählt: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Software" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Pfad zur Software (z.B. C:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Heute" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Fehlerhafte Eingabe!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Gestern" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "FMD wird beendet in %d Sekunden." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "System wird in den Ruhemodus versetzt in %d Sekunden." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "System wird heruntergefahren in %d Sekunden." + +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "Initialisierungs Vektor:" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "Schlüssel:" + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Entferne Wasserzeichen" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "Speichern als PNG" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Hinzufügen" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Löschen" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Bearbeiten" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Aktualisieren" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Webseite" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Benutzername" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Status" + +#: taccountsetform.btcancel.caption +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "Abbrechen" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "Ok" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Passwort anzeigen" + +#: taccountsetform.edpassword.texthint +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Passwort" + +#: taccountsetform.edusername.texthint +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Benutzername" + +#: taccountsetform.label1.caption +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Webseite" + +#: taccountsetform.label2.caption +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Benutzername" + +#: taccountsetform.label3.caption +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Passwort" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "CustomColorForm" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Basisliste " + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Kapitelliste" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Favoritenliste" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Mangaliste" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Zu den Favoriten hinzufügen" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "&schließen" + +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Alles laden" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Sauber" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Oben bleiben" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Protokolllimit" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Kopieren" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "Abbrechen" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&OK" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga Downloader" + +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Pfad zur Software (z.B. C:\\MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Software:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Aktualisierungsliste abbrechen" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Zu den Favoriten hinzufügen" + +#: tmainform.btchecklatestversion.caption +#| msgid "Check for new version" +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Auf neuste Version prüfen" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Protokolldatei löschen" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "Download" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Download aufteilen" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Auf neues Kapitel überprüfen" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Importiere Liste" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Filter" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Wert zurücksetzen" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Öffne Protokoll" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Anwenden" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Online lesen" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Entferne Filter" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Entferne Filter" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Aktualisiere Manga-Liste" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Besuche meinen Blog" + +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "Zur Downloadliste als angehaltene Aufgabe hinzufügen" + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<none>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Nur nach neuen Manga suchen." + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Automatisch runterladen nach abgeschlossener Aktualisierung" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Automatisches auf neue Kapitel in einem Zeitabstand" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Automatisches Entfernen abgeschlosser Manga aus den Favoriten" + +#: tmainform.cboptionautocheckfavstartup.caption +#| msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" +msgstr "Automatisch auf neue Kapitel beim Start prüfen" + +#: tmainform.cboptionautochecklatestversion.caption +#| msgid "Check for new version " +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Automatisch auf neuste Version prüfen " + +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Öffne Favoriten beim Start" + +#: tmainform.cboptionchangeunicodecharacter.caption +#| msgid "Change all all character to" +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Replace all unicode character with" +msgstr "Ersetze alle Unicode Zeichen mit" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Aktiviere dies, falls du Probleme mit Unicode Zeichen in diesem Pfad hast" + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Kapitel" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Band" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Aktiviere Manga-Cover laden" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Automatischen Kapitel-Ordner erzeugen" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgid "Auto generate folder based on manga's name" +msgstr "Auto generate folder based on manga's name" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Aktiviere live search (langsam bei langen Listen)" + +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "Minimieren beim Start" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Minimieren in die Ablage" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "FMD nur einmal ausführen lassen" + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Entferne Manga-Name aus dem Kapitel" + +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "Show balloon hint" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Lösche Aufgabe/Favorite" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Lade Manga-Liste falls leer" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "Zeige Download-Symbolleiste" + +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "Zeige \"Lösche alle abgeschlossenen Aufgaben\" in Download-Symbolleiste" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "FMD beenden" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "Lade keine Manga-Informationen, wenn die Liste sich aktualisiert (Filter wird nicht funktionieren!)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "Remove duplicate local data when updating manga list" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Benutze proxy" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Suche in allen Manga-Seiten" + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Für mehr Manga-Seiten, bitte geh in die Optionen->Manga-Seiten" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Regular Expression" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "Show Drop Box" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Aufzeichnung aktivieren" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Action" + +#: tmainform.ckfilteraction.hint +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Ein Werk, das typischwerise Kampf, Gewalt, Chaos und schnelle Bewegungen darstellt." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Erwachsen" + +#: tmainform.ckfilteradult.hint +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Enthält Inhalte, die nur für Erwachsene geeignet sind. Titel in dieser Kategorie können eine ausgedehnte Szenen intensiver Gewalt und / oder grafisch-sexuelle Inhalte und Nacktheit beinhalten." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Abenteuer" + +#: tmainform.ckfilteradventure.hint +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Wenn ein Charakter in der Geschichte auf einer Reise geht oder entlang dieser Richtung, kannst du darauf wetten, dass es ein Abenteuer-Manga ist. Ansonsten obliegt es ganz deiner persönlichen Einschätzung auf diesen Fall." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Komödie" + +#: tmainform.ckfiltercomedy.hint +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Ein dramatisches Werk, das leicht und oft witzig oder satirisch im Ton ist, und dass in der Regel eine glückliche Auflösung des thematischen Konflikts enthält." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Doujinshi" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Fan basierte Arbeit, inspiriert von offiziellen Manga / Anime." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Drama" + +#: tmainform.ckfilterdrama.hint +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Eine Arbeit, die eine emotionale Reaktion, wie intesiven Schwermut oder Spannung, auslösen will." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Ecchi" + +#: tmainform.ckfilterechi.hint +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Möglicherweise die dünne Linie zwischen Hentai und nicht-Hentai. Ecchi baut auf Fanservice, um bestimmte Gruppe von Fans zu gewinnen." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Fantasie" + +#: tmainform.ckfilterfantasy.hint +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Alles was, aber nicht ausschließlich, Magie, Traumwelt, und Märchen behandelt." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Transvestit (Gender Bender)" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "" +"Mädchen verkleiden sich als Jungs, Jungs verkleiden sich als Mädchen.\n" +"Jungs verwandeln sich in Mädchen, Mädchen verwandeln sich in Jungs.\n" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Harem" + +#: tmainform.ckfilterharem.hint +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "Eine Serie, die sich um einen männlichen Charakter und viele weiblichen Charaktere (die in der Regel sich zu dem männlichen Charakter hingezogen fühlen) dreht. Ein \"Reverse Harem\" ist es wiederum, wenn die Geschlechter vertauscht sind." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "Historisch" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Handelt von alten oder antiken Zeiten." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Horror" + +#: tmainform.ckfilterhorror.hint +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Ein schmerzhaftes Gefühl der Angst, Furcht und Verachtung; ein Schauern mit Terror und Verabscheuung; das Gefühl, inspiriert von etwas schrecklichem und schockierendem." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Josei" + +#: tmainform.ckfilterjosei.hint +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Buchstäblich übersetzt „Frau“. Zielt auf Frauen zwischen 18-30 ab. Weibliches Äquivalent zu Seinen. Im Gegensatz zu Shoujo ist die Romantik realistischer und weniger idealisiert. Das Geschichtenerzählung ist expliziter und reifer." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Lolicon" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Stellvertretend für eine sexuelle Anziehung zu jungen oder minderjährigen Mädchen." + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Kampfsport" + +#: tmainform.ckfiltermartialarts.hint +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "Wie der Name schon sagt, alles was mit Kampfkunst zutun hat. Behandelt verschiedene Arten von Kampfsport oder Selbstverteidigung, wie Aikido, Karate, Judo oder Taekwondo, Kendo, Fechten, und so weiter und so fort." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Erwachsen" + +#: tmainform.ckfiltermature.hint +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "Behandelt Themen, die für Menschen unter dem Alter von 17 vielleicht zu extrem sind. Titel in dieser Kategorie enthalten möglicherweise intensive Gewalt, Blut und Gore, sexuellen Inhalt und / oder Kraftausdrücke." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Mecha" + +#: tmainform.ckfiltermecha.hint +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Ein Werk, das in der Regel alle Arten von großen Robotermaschinen behandelt und normalerweise darauf konzentriert." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Musical" + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Mystery" + +#: tmainform.ckfiltermystery.hint +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Üblicherweise tritt ein unerklärliche Ereignis ein, und die Hauptfigur versucht, herauszufinden, was es verursacht hat." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Psychologisch" + +#: tmainform.ckfilterpsychological.hint +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Normalerweise befasst es sich mit der Philosophie des Geisteszustandes, in den meisten Fällen schildert es abnorme Psychologie." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Romantik" + +#: tmainform.ckfilterromance.hint +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Jede Liebe behandelnde Geschichte. Wir werden in diesem Fall Liebe als etwas zwischen Mann und Frau definieren. Ansonsten obliegt es deiner Vorstellung, was du als Liebe definierst." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "Schulleben" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "Ein umfangreicher Teil des Schauplatzes der Geschichte befaßt sich mit irgendeiner Art von Schule." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Sci-Fi" + +#: tmainform.ckfilterscifi.hint +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Abkürzung für Science Fiction. Diese Werke bauen auf Wendungen in technischen und anderen wissenschaftlich verwandten Phänomenen, welche Gegensätze oder Erweiterungen der monderen wissenschaftlichen Welt sind." + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Seinen" + +#: tmainform.ckfilterseinen.hint +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "Von Google: Sein bedeutet wörtlich ‚junger Mann‘. Manga und Anime, die speziell auf junge, erwachsene Männer im Alter von 18 bis 25 abzielt. Die Geschichten in Seinen-Werken appellieren an Studenten und diejenigen in der Arbeitswelt. Normalerweise beschäftigen sich die Geschichten mit den Problem des Erwachsenseins." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Shotacon" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "Stellvertretend für eine sexuelle Anziehung zu jungen oder minderjährigen Jungs." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Shoujo" + +#: tmainform.ckfiltershoujo.hint +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Eine Arbeit bestimmt und in erster Linie für Frauen geschrieben. Normalerweise bedeutet das eine Menge Romantik und starke Charakter-Entwicklung." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Shoujo Ai" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "Oft gleichbedeutend mit \"Yuri\". Es kann als etwas weniger extrem betrachtet werden. „Girl' Love“, sozusagen." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Shounen" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Eine Arbeit bestimmt und in erster Linie für Männer geschrieben. Normalerweise bedeutet das Kämpfe und/oder Gewalt." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Shounen Ai" + +#: tmainform.ckfiltershounenai.hint +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "Oft gleichbedeutend mit \"Yaoi\". Es kann als etwas weniger extrem betrachtet werden. „Boy's Love“, sozusagen." + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Alltag/Ein Stück aus dem Leben" + +#: tmainform.ckfiltersliceoflife.hint +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "Wie der Name schon sagt, stellt dieses Genre die Tag-zu-Tag Sorgen eines/vieler Charakters/Charaktere dar. Diese Herausforderungen/Ereignisse könnten eigentlich im wirklichen Leben passieren und sind oft -Wenn nicht immer- in der gegenwärtigen Zeit, in einer uns gespiegelten Welt, angesiedelt." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Schweinekram" + +#: tmainform.ckfiltersmut.hint +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Behandelt Serien, die als Profan oder Beleidigend betracht werden können, insbesondere im Hinblick auf sexuelle Inhalte." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Sport" + +#: tmainform.ckfiltersports.hint +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "Genre Sport = Sport. Welche eine Überraschung. Handelt von allem, was irgendwie Sport-Verwandt ist. Baseball, Basketball, Hockey, Fußball, Golf und Rennsport um nur einige zu nennen." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Übernatürlich" + +#: tmainform.ckfiltersupernatural.hint +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Handelt normalerweise von erstaunlichen und unerklärlichen Kräften oder Ereignissen, die den Gesetzen der Physik trotzen." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Tragik" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Behandelt Ereignisse, die in großen Verlust und Unglück resultieren." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Weebtoons" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Yaoi" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Diese Arbeit beinhaltet in der Regel intime Beziehungen zwischen Männern." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Yuri" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Diese Arbeit beinhaltet in der Regel intime Beziehungen zwischen Frauen." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Eingabe individueller Genres, durch Komma getrennt" + +#: tmainform.eddownloadssearch.texthint +#| msgid "Search favorites..." +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "Downloads durchsuchen..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Favoriten durchsuchen..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Artist" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Autor" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Filter" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Zusammenfassungsteil" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Titel" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Suche Titel..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgid "Custom rename" +msgstr "Benutzerdefinierte Umbenennung" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Standarddownloadpfad" + +#: tmainform.edoptionexternalparams.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalparams.texthint" +msgid "External program parameters" +msgstr "Externe Programmparameter" + +#: tmainform.edoptionexternalpath.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalpath.texthint" +msgid "External program path" +msgstr "Externer Programmpfad" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Benutzerdefinierte Umbenennung" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr "Proxy host/IP" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Benutzerdefinierte Umbenennung" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "Proxy passwort" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "Proxy Benutzername" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Speichern unter" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "URL hier einfügen" + +#: tmainform.edwebsitessearch.texthint +#| msgid "Search..." +msgctxt "tmainform.edwebsitessearch.texthint" +msgid "Search website..." +msgstr "Durchsuche webseite..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Zeige Dialogbestätigungen für" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "Drop Box" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Externes Programm" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Favoriten" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Proxy Einstellung" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Umbenennung" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Wähle den Standarddownloadpfad:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Opazität" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Artist" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Autor" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Eigene Genres" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "" +"Genres:\n" +"- Ausgewählt: Dieses Genre einschließe\n" +"- Abgewählt: Dieses Genre ausschließen.\n" +"- Grau: Egal.\n" +"\n" +"Eigene Genres:\n" +"- Separiere mehrere Genres mit ','.\n" +"- Schließe ein Genre aus mit '!' oder '-' am Anfang eines Genre.\n" +"- Beispiel: Abenteuer, !Ecchi, Komödie.\n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Status" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Zusammenfassung" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Titel" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Protokolldatei:" + +#: tmainform.lbmode.caption +msgid "Mode: Show all (0)" +msgstr "Modus: Zeig alle (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgid "Auto check for new chapter every %d minutes" +msgstr "Automatisch nach neuen Kapitel alle %d Minuten suchen" + +#: tmainform.lboptionchaptercustomrename.caption +#| msgid "Chapter folder name:" +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Kapitelname:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Webseite name\n" +"%MANGA% : Manga Titel\n" +"%CHAPTER% : Kapitelname\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Nummerierung\n" +"\n" +"Hinweis:\n" +"Kapitelordner muss mindest %CHAPTER% oder %NUMBERING% haben.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Verbindungsunterbrechung (sekunden)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Öffne Manga durch Nutzung eines externen Programmes:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Parameter:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "tmainform.lboptionexternalparamshint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Dateiname:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga Titel\n" +"%CHAPTER% : Kapitelname\n" +"%FILENAME% : Dateiname\n" +"\n" +"Note:\n" +"Der Dateiname muss mindest %FILENAME% haben. \n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Host" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Sprache:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "Nachdem der Download abgeschlossen ist:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Manga Ordnername:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Webseite name\n" +"%MANGA% : Manga Titel\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga Ordnername muss mindest %MANGA% haben.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Anzahl von Downloads zur selben Zeit (Max: 8)" + +#: tmainform.lboptionmaxretry.caption +#| msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "Anzahl der erneuten Versuche, falls der Download Probleme hat (-1 =immer wiederholen)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Anzahl der Download-Dateien je Aufgabe zur selben Zeit (Max: 32)" + +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "Neuer Manga basierend auf seiner Aktualisierungszeit (täglich)" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Passwort" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "PDF Komprimierungsstufe" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (Verlustfrei), Niedriger = DCTEncode (verlustbehaftet)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Port" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Type" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Rename digits" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Benutzername" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Speichern unter:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Löschen" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Kopieren" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Schneiden" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Einfügen" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Einfügen und los" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Alles auswählen" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Öffnen" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Abbrechen" + +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "Aufsteigend" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Alles auswählen" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Prüfen ausgewählt" + +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "Absteigend" + +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Filter" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "Verstecke geladene Kapitel" + +#: tmainform.michapterlisthighlight.caption +#| msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" +msgstr "Hebe geladene Kapitel hervor" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Alles abwählen" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Uncheck selected" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Löschen" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Lösche alle abgeschlossenen Aufgaben" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Nur Aufgaben" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Aufgaben + Daten" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Aufgaben + Daten + Favoriten" + +#: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" +msgid "Disable" +msgstr "Deaktiviere" + +#: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" +msgid "Enable" +msgstr "Aktiviere" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Verschmelze abgeschlossene Aufgaben" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Öffne Ordner" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Öffne ..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Fortsetzen" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Stop" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Zeige Manga-Information" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Ändere \"Derzeitiges Kapitel\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Ändere \"Speichern unter\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Nach neuen Kapitel suchen" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Löschen" + +#: tmainform.mifavoritesdisable.caption +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Deaktiviere" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Alles laden" + +#: tmainform.mifavoritesenable.caption +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Aktiviere" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Öffne Ordner" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Öffne ..." + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Nach neuen Kapitel suchen anhalten" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Zeige Manga-Informationen" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Neue Manga hervorheben" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Zu den Favoriten hinzufügen" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Löschen" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Alles laden" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Zeige Manga-Informationen" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "After download finish" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Beenden" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Beenden" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Hibernate" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Nichts" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Herunterfahren" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Wiederherstellen" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Alle fortsetzen" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "Show Drop Box" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Alle anhalten" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Lade alle Listen aufeinmal vom Server" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Check all" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Indeterminate all" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Uncheck all" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Aktualisiere alle Listen gleichzeitig" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Download manga list from server" + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Aktualisiere Manga-Liste" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Have all genre checked" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Have one of genres checked" + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Modus" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "Speichere geladene Kapitel als" + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Lösche alle abgeschlossenen Aufgaben" + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Alle fortsetzen" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Alle anhalten" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Collapse All" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Expand All" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "Über" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "Über FMD" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Accounts" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Änderungsprotokoll " + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Verbindungen" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Custom color" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "Dialog" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr "Downloads" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Favoriten" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "Allgemeines" + +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Filter" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "Info" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Manga Info" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Protokoll" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Sonstiges" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Optionen" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Speichern unter" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Updates" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Anzeige" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Erweitert" + +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Optionen" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Webseiten" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" +msgid "Websites" +msgstr "Webseiten" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Manga" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Status" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "Fortschritt" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Tranferrate" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Webseite" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Speichern unter" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Hinzugefügt" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Titel" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Aktuelles Kapitel" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Webseite" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Speichern unter" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "&Abbrechen" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "&Download" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "&zur Warteschlage hinzufügen" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "&Abbrechen" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "&Jetzt" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "&Später" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "&Aktualisiere" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "" +"Neue Version gefunden! Möchten Sie jetzt aktualisieren?\n" +"FMD wird geschlossen um die Aktualisierung abzuschließen.\n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Hinzufügen" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Ändern" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Löschen" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Directory page number" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "Downloads" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Max threads je Aufgabe" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "Anzahl von threads" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Aktualisiere Liste" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Webseite" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Cookies" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Webseite" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Value" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Webseite" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Value" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Webseite" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Value" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Webseite" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Wähle eine Webseite" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Compressing..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Deaktiviert" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "Downloading" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Gescheitert" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Gescheitert einen Ordner zu erstellen!" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Gescheitert, versuch die Aufgabe zu wiederholen!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Abgeschlossen" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Preparing" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Angehalten" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Warte..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "&zur Warteschlage hinzufügen" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "&Abbrechen" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Nach neuen Kapitel suchen" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "&Download" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "&Entfernen" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "%d abgeschlossenen Manga gefunden" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "Favoriten-Überprüfung läuft!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d manga(s) hat neue(s) Kapitel" + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "%s <%s> hat %d neue Kapitel." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "Abgeschlossene Manga werden entfernt:" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "Found %d new chapter from %d manga(s):" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Lade: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Prüfe auf neue Version" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "Installierte Version" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Aktuellste Version " + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Neue Version gefunden!" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "%s hat %d neue Manga" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Getting directory" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Getting info" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Getting list for" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Indexierung neuer Titel" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Schaue nach neuen Titel(n)" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Schaue nach neuen Titel(n) aus einem anderen Verzeichnis" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Vorbereitung" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Entfernen von Duplikaten aus aktuellen Daten" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Entfernen von Duplikaten aus lokalen Daten" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Entfernen von Duplikaten aus den neuen Titeln" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Speichere Daten" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Synchronisiere Daten" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Aktualisiere Liste" From 6b0b35fdb8ec757e9cdbda92c6a38663da67419b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 22 Jul 2017 03:10:30 +0800 Subject: [PATCH 1823/2794] httpsendthread, added getproxy --- baseunits/httpsendthread.pas | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 0da6216f8..d55968629 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -69,6 +69,7 @@ THTTPSendThread = class(THTTPSend) function ThreadTerminated: Boolean; procedure RemoveCookie(const CookieName: String); procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); + procedure GetProxy(var ProxyType, Host, Port, User, Pass: String); procedure SetNoProxy; procedure Reset; property Timeout: Integer read FTimeout write SetTimeout; @@ -580,6 +581,39 @@ procedure THTTPSendThread.SetProxy(const ProxyType, Host, Port, User, Pass: Stri end; end; +procedure THTTPSendThread.GetProxy(var ProxyType, Host, Port, User, Pass: String); +begin + if ProxyHost <> '' then + begin + ProxyType := 'HTTP'; + Host := ProxyHost; + Port := ProxyPass; + User := ProxyUser; + Pass := ProxyPass; + end + else + if Sock.SocksIP <> '' then + with Sock do + begin + if SocksType = ST_Socks5 then + ProxyType := 'SOCKS5' + else + ProxyType := 'SOCKS4'; + Host := SocksIP; + Port := SocksPort; + User := SocksUsername; + Pass := SocksPassword; + end + else + begin + ProxyType := ''; + Host := ''; + Port := ''; + User := ''; + Pass := ''; + end; +end; + procedure THTTPSendThread.SetNoProxy; begin SetProxy('', '', '', '', ''); From 9a40d1800a642d9d61064665b214cb3f5ab8dd3f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 22 Jul 2017 03:18:46 +0800 Subject: [PATCH 1824/2794] httpsendthread, added getproxy --- baseunits/httpsendthread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index d55968629..76115bced 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -587,7 +587,7 @@ procedure THTTPSendThread.GetProxy(var ProxyType, Host, Port, User, Pass: String begin ProxyType := 'HTTP'; Host := ProxyHost; - Port := ProxyPass; + Port := ProxyPort; User := ProxyUser; Pass := ProxyPass; end From 2b43b51a367a290e16914ba918549ddf8dd0d170 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 22 Jul 2017 04:22:02 +0800 Subject: [PATCH 1825/2794] httpsendthread, add setdefaultproxy, beforehttpmethod, afterhttpmethod --- baseunits/httpsendthread.pas | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 76115bced..d7a1d7c37 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -42,6 +42,10 @@ interface type + THTTPSendThread = class; + + THTTPMethodEvent = procedure(const AHTTP: THTTPSendThread; var Method, URL: String); + { THTTPSendThread } THTTPSendThread = class(THTTPSend) @@ -71,6 +75,7 @@ THTTPSendThread = class(THTTPSend) procedure SetProxy(const ProxyType, Host, Port, User, Pass: String); procedure GetProxy(var ProxyType, Host, Port, User, Pass: String); procedure SetNoProxy; + procedure SetDefaultProxy; procedure Reset; property Timeout: Integer read FTimeout write SetTimeout; property RetryCount: Integer read FRetryCount write FRetryCount; @@ -79,6 +84,9 @@ THTTPSendThread = class(THTTPSend) property AllowServerErrorResponse: Boolean read FAllowServerErrorResponse write FAllowServerErrorResponse; property Thread: TBaseThread read FOwner; property CookiesExpires: TDateTime read FCookiesExpires; + public + BeforeHTTPMethod: THTTPMethodEvent; + AfterHTTPMethod: THTTPMethodEvent; end; TKeyValuePair = array[0..1] of String; @@ -372,6 +380,8 @@ constructor THTTPSendThread.Create(AOwner: TBaseThread); FOwner := AOwner; FOwner.OnCustomTerminate := @OnOwnerTerminate; end; + BeforeHTTPMethod := nil; + AfterHTTPMethod := nil; EnterCriticalsection(CS_ALLHTTPSendThread); try ALLHTTPSendThread.Add(Self); @@ -392,10 +402,18 @@ destructor THTTPSendThread.Destroy; end; function THTTPSendThread.HTTPMethod(const Method, URL: string): Boolean; +var + amethod, aurl: String; begin + amethod:=Method; + aurl:=URL; + if Assigned(BeforeHTTPMethod) then + BeforeHTTPMethod(Self, amethod, aurl); FCookiesExpires := 0.0; - Result := inherited HTTPMethod(Method, URL); + Result := inherited HTTPMethod(amethod, aurl); ParseCookiesExpires; + if Assigned(BeforeHTTPMethod) then + BeforeHTTPMethod(Self, amethod, aurl); end; function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: TObject): Boolean; @@ -619,6 +637,11 @@ procedure THTTPSendThread.SetNoProxy; SetProxy('', '', '', '', ''); end; +procedure THTTPSendThread.SetDefaultProxy; +begin + SetProxy(DefaultProxyType, DefaultProxyHost, DefaultProxyPort, DefaultProxyUser, DefaultProxyPass); +end; + procedure THTTPSendThread.Reset; begin Clear; From bee0e5a073b3741137844aa25fd64780cbd217a9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 22 Jul 2017 04:22:34 +0800 Subject: [PATCH 1826/2794] added googledcp --- baseunits/modules/GoogleDCP.pas | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 baseunits/modules/GoogleDCP.pas diff --git a/baseunits/modules/GoogleDCP.pas b/baseunits/modules/GoogleDCP.pas new file mode 100644 index 000000000..97bde9415 --- /dev/null +++ b/baseunits/modules/GoogleDCP.pas @@ -0,0 +1,57 @@ +unit GoogleDCP; + +{$mode objfpc}{$H+} + +interface + +uses + SysUtils, httpsendthread, synautil, synacode, dateutils; + +procedure SetGoogleDCP(const AHTTP: THTTPSendThread); +procedure RemoveGoogleDCP(const AHTTP: THTTPSendThread); + +implementation + +const + proxyhost='proxy.googlezip.net'; + authkey='ac4500dd3b7579186c1b0620614fdb1f7d61f944'; + +function randint: String; +begin + Result:=IntToStr(Random(999999999)); +end; + +procedure BeforeHTTPMethod(const AHTTP: THTTPSendThread; var Method, URL: String); +var + timestamp: String; +begin + if (Method='GET') and (LowerCase(Copy(URL,1,7))='http://') then + begin + AHTTP.SetProxy('HTTP',proxyhost,'80','',''); + timestamp:=IntToStr(DateTimeToUnix(Now)); + AHTTP.Headers.Add('Chrome-Proxy: ps='+timestamp+'-'+randint+'-'+randint+'-'+randint+', sid='+StrToHex(MD5(timestamp+authkey+timestamp))+', c=win, b=3029, p=110'); + end; +end; + +procedure AfterHTTPMethod(const AHTTP: THTTPSendThread; var Method, URL: String); +begin + if AHTTP.ProxyHost = proxyhost then + AHTTP.SetDefaultProxy; +end; + +procedure SetGoogleDCP(const AHTTP: THTTPSendThread); +begin + AHTTP.BeforeHTTPMethod := @BeforeHTTPMethod; + AHTTP.AfterHTTPMethod := @AfterHTTPMethod; +end; + +procedure RemoveGoogleDCP(const AHTTP: THTTPSendThread); +begin + if AHTTP.BeforeHTTPMethod=@BeforeHTTPMethod then + AHTTP.BeforeHTTPMethod:=nil; + if AHTTP.AfterHTTPMethod=@AfterHTTPMethod then + AHTTP.AfterHTTPMethod:=nil; +end; + +end. + From b6c208166242a6530b8e18699ba20122e8fb79f3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 22 Jul 2017 04:23:20 +0800 Subject: [PATCH 1827/2794] kissmanga, added usegoogledcp --- baseunits/modules/KissManga.pas | 22 +++++++----- mangadownloader/languages/fmd.de.po | 5 +++ mangadownloader/languages/fmd.el_GR.po | 46 ++++++++++++++------------ mangadownloader/languages/fmd.en.po | 5 +++ mangadownloader/languages/fmd.es.po | 4 +++ mangadownloader/languages/fmd.id_ID.po | 5 +++ mangadownloader/languages/fmd.pl_PL.po | 4 +++ mangadownloader/languages/fmd.po | 4 +++ mangadownloader/languages/fmd.pt_BR.po | 4 +++ mangadownloader/languages/fmd.ru_RU.po | 5 +++ 10 files changed, 75 insertions(+), 29 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index aa5b23e21..d2b976118 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -6,7 +6,8 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, BaseCrypto, Cloudflare, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, BaseCrypto, Cloudflare, GoogleDCP, RegExpr, + synautil; implementation @@ -20,16 +21,25 @@ implementation kissmangaiv: String ='a5e8e2e9c2721be0a84ad660c472c1f3'; kissmangakey: String ='mshsdf832nsdbash20asdmnasdbasd612basd'; + kissmangausegoogledcp: Boolean = True; resourcestring RS_KissManga_Key = 'Key:'; RS_KissManga_InitVector = 'Initialization Vector:'; + RS_KissManga_UseGoogleDCP = 'Use Google DCP'; function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - if Module.Website = 'KissManga' then - Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacf) + if Module.Website = 'KissManga' then begin + if kissmangausegoogledcp then + begin + SetGoogleDCP(AHTTP); + Result := AHTTP.GET(AURL); + end + else + Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacf); + end else if Module.Website = 'ReadComicOnline' then Result := Cloudflare.GETCF(AHTTP, AURL, readcomiconlinecf); end; @@ -175,7 +185,6 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; source: TStringList; i, chkop, ivp: Integer; chkos, chko1, chko2, civ, key, iv: String; - chkoa: Boolean; s: String; function testkeyiv(const akey, aiv: string): Boolean; @@ -207,7 +216,6 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; key := ''; iv := ''; s := ''; - chkoa := False; source := TStringList.Create; source.LoadFromStream(Document); for i := 0 to source.Count - 1 do @@ -215,10 +223,7 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; if Pos('lstImages.push', source[i]) <> 0 then PageLinks.Add(GetBetween('("', '")', source[i])) else if (Pos('chko', source[i]) <> 0) and (Pos('=', source[i]) <> 0) then - begin chko2 := GetBetween('["', '"]', source[i]); - chkoa := Pos('chko+', StringReplace(source[i], ' ', '', [rfReplaceAll])) <> 0; - end; end; if PageLinks.Count <> 0 then begin @@ -304,6 +309,7 @@ procedure RegisterModule; OnGetPageNumber := @KissMangaGetPageNumber; AddOptionEdit(@kissmangakey,'Key',@RS_KissManga_Key); AddOptionEdit(@kissmangaiv,'IV',@RS_KissManga_InitVector); + AddOptionCheckBox(@kissmangausegoogledcp,'UseGoogleDCP',@RS_KissManga_UseGoogleDCP); end; AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.to'); end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 949b7f71e..3b0149ca2 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -355,6 +355,10 @@ msgstr "Initialisierungs Vektor:" msgid "Key:" msgstr "Schlüssel:" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Entferne Wasserzeichen" @@ -2228,3 +2232,4 @@ msgstr "Synchronisiere Daten" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Aktualisiere Liste" + diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index ff0f15f25..d6af477f7 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -359,6 +359,10 @@ msgstr "Διάνυσμα προετοιμασίας:" msgid "Key:" msgstr "Κλειδί:" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Αφαίρεση υδατογραφήματος" @@ -771,7 +775,7 @@ msgid "Contains content that is suitable only for adults. Titles in this categor msgstr "" "Περιέχει περιεχόμενο που είναι κατάλληλο μόνο για ενήλικες.\n" " Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν σκηνές παρατεταμένης έντονης \n" -"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό." +"βίας ή/και γραφικά με σεξουαλικό περιεχόμενο και γυμνό.\n" #: tmainform.ckfilteradventure.caption msgid "Adventure" @@ -782,7 +786,7 @@ msgid "If a character in the story goes on a trip or along that line, your best msgstr "" "Αν ένας χαρακτήρας στην ιστορία πηγαίνει σε ταξίδι ή κατά μήκος αυτής της γραμμής, \n" "το πιθανότερο είναι ότι πρόκειται για μια περιπέτεια manga. Ειδάλλως, είναι στο χέρι σας\n" -" να αποφασίσετε γι αυτή την περίπτωση." +" να αποφασίσετε γι αυτή την περίπτωση.\n" #: tmainform.ckfiltercomedy.caption msgid "Comedy" @@ -816,7 +820,7 @@ msgstr "Ecchi" msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." msgstr "" "Ενδεχομένως η γραμμή μεταξύ Hentai και μη-Hentai, το Ecchi συνήθως αναφέρεται \n" -"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών." +"σε υπηρεσία οπαδών που θέλει να προσελκύσει μια συγκεκριμένη ομάδα οπαδών.\n" #: tmainform.ckfilterfantasy.caption msgid "Fantasy" @@ -847,7 +851,7 @@ msgid "A series involving one male character and many female characters (usually msgstr "" "Μια σειρά που περιλαμβάνει έναν αρσενικό χαρακτήρα και πολλούς γυναικείους \n" "(συνήθως έλκονται από τον αρσενικό χαρακτήρα). \n" -"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται." +"Το Reverse Harem είναι όταν τα φύλα αντιστρέφονται.\n" #: tmainform.ckfilterhentai.caption msgctxt "tmainform.ckfilterhentai.caption" @@ -875,7 +879,7 @@ msgstr "Horror" msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." msgstr "" "Ένα οδυνηρό συναίσθημα φόβου, τρόμου και αποστροφής. Ένα ανατριχιαστικό με τρόμο \n" -"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό." +"και αποστροφή. Το αίσθημα που είναι εμπνευσμένο από κάτι τρομακτικό και συγκλονιστικό.\n" #: tmainform.ckfilterjosei.caption msgid "Josei" @@ -886,7 +890,7 @@ msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Un msgstr "" "Κυριολεκτικά «Γυναίκα». Απευθύνεται σε γυναίκες 18-30. Ισοδύναμο με το θηλυκό. \n" "Σε αντίθεση με το Shoujo το ειδύλλιο είναι πιο ρεαλιστικό και λιγότερο εξιδανικευμένο. \n" -"Η αφήγηση είναι πιο σαφής και ώριμη." +"Η αφήγηση είναι πιο σαφής και ώριμη.\n" #: tmainform.ckfilterlolicon.caption msgid "Lolicon" @@ -905,7 +909,7 @@ msgid "As the name suggests, anything martial arts related. Any of several arts msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με πολεμικές τέχνες. \n" "Οποιεσδήποτε από τις διάφορες τέχνες μάχης ή αυτοάμυνας, όπως αϊκίντο, \n" -"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά." +"καράτε, τζούντο, τάε κβον ντο ή κέντο κ.ά.\n" #: tmainform.ckfiltermature.caption msgid "Mature" @@ -916,7 +920,7 @@ msgid "Contains subject matter which may be too extreme for people under the age msgstr "" "Περιέχει θέμα το οποίο μπορεί να είναι πολύ ακραίο για άτομα κάτω των 17 ετών. \n" "Οι τίτλοι σε αυτή την κατηγορία μπορεί να περιέχουν έντονη βία, έντονη αιματοχυσία, \n" -"σεξουαλικό περιεχόμενο και σκληρή γλώσσα." +"σεξουαλικό περιεχόμενο και σκληρή γλώσσα.\n" #: tmainform.ckfiltermecha.caption msgid "Mecha" @@ -926,7 +930,7 @@ msgstr "Mecha" msgid "A work involving and usually concentrating on all types of large robotic machines." msgstr "" "Ένα έργο που περιλαμβάνει και συνήθως επικεντρώνεται σε όλους \n" -"τους τύπους των μεγάλων ρομποτικών μηχανημάτων." +"τους τύπους των μεγάλων ρομποτικών μηχανημάτων.\n" #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -946,7 +950,7 @@ msgstr "Mystery" msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." msgstr "" "Συνήθως συμβαίνει κάποιο ανεξήγητο γεγονός και ο κεντρικός \n" -"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε." +"πρωταγωνιστής προσπαθεί να ανακαλύψει τι το προκάλεσε.\n" #: tmainform.ckfilterpsychological.caption msgid "Psychological" @@ -956,7 +960,7 @@ msgstr "Psychological" msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." msgstr "" "Συνήθως ασχολείται με τη φιλοσοφία μιας κατάστασης του μυαλού. \n" -"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση." +"Στις περισσότερες περιπτώσεις σε μια ανώμαλη ψυχολογική κατάσταση.\n" #: tmainform.ckfilterromance.caption msgid "Romance" @@ -966,7 +970,7 @@ msgstr "Romance" msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." msgstr "" "Οποιαδήποτε ιστορία σχετική με αγάπη. Εμείς θεωρούμε την αγάπη μεταξύ άνδρα και γυναίκας. \n" -"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι." +"Εκτός από αυτήν, είναι θέμα της φαντασίας σας ποια αγάπη μπορεί να είναι.\n" #: tmainform.ckfilterschoollife.caption msgid "School Life" @@ -984,7 +988,7 @@ msgstr "Sci-Fi" msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." msgstr "" "Τα έργα αυτά αφορούν ανατροπές στην τεχνολογία και σε άλλα φαινόμενα σχετικά με την επιστήμη \n" -"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου." +"που είναι αντίθετα ή παραποιιημένα τμήματα του σύγχρονου επιστημονικού κόσμου.\n" #: tmainform.ckfilterseinen.caption msgid "Seinen" @@ -995,7 +999,7 @@ msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically msgstr "" "Seinen σημαίνει «νέος άνθρωπος». Τα manga και anime που στοχεύουν ειδικά σε νεαρά ενήλικα αρσενικά,\n" " ηλικίας μεταξύ 18 και 25 ετών. Οι ιστορίες αυτές εμφανίζουν φοιτητές Πανεπιστημίου και άτομα από τον \n" -"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής." +"κόσμο της εργασίας. Σε γενικές γραμμές οι ιστορίες αυτές ασχολούνται με θέματα της ενήλικης ζωής.\n" #: tmainform.ckfiltershotacon.caption msgid "Shotacon" @@ -1013,7 +1017,7 @@ msgstr "Shoujo" msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." msgstr "" "Ένα έργο που προορίζεται και είναι κυρίως γραμμένο για γυναίκες. \n" -"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα." +"Συνήθως περιλαμβάνει ειδύλλια και ανάπτυξη ισχυρού χαρακτήρα.\n" #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -1024,7 +1028,7 @@ msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." msgstr "" "Συχνά συνώνυμη με το Yuri. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας κοριτσιών»." +"Μπορείτε να το πείτε και «Έρωτας κοριτσιών».\n" #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -1035,7 +1039,7 @@ msgctxt "tmainform.ckfiltershounen.hint" msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." msgstr "" "Ένα έργο που προορίζεται και είναι γραμμένο κυρίως για άνδρες. \n" -"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία." +"Τα έργα αυτά αφορούν συνήθως σκηνές μάχης ή/και βία.\n" #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" @@ -1045,7 +1049,7 @@ msgstr "Shounen Ai" msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" msgstr "" "Συχνά συνώνυμη με το Yaoi. Αυτό μπορεί να θεωρηθεί ως κάπως λιγότερο ακραίο. \n" -"Μπορείτε να το πείτε και «Έρωτας αγοριών»." +"Μπορείτε να το πείτε και «Έρωτας αγοριών».\n" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" @@ -1057,7 +1061,7 @@ msgstr "" "Όπως υποδηλώνει το όνομα, το είδος αυτό αντιπροσωπεύει καθημερινές δοκιμασίες \n" "από έναν ή περισσότερους χαρακτήρες. Αυτές οι προκλήσεις / εκδηλώσεις θα μπορούσαν \n" "τεχνικά να συμβούν στην πραγματική ζωή και εμφανίζονται συχνά, αν όχι συνεχώς, σε \n" -"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές." +"έναν κόσμο που αντικατοπτρίζει τις δικές μας ζωές.\n" #: tmainform.ckfiltersmut.caption msgid "Smut" @@ -1075,7 +1079,7 @@ msgstr "Sports" msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." msgstr "" "Όπως υποδηλώνει το όνομα, οτιδήποτε σχετικό με αθλήματα. \n" -"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα." +"Για παράδειγμα μπέιζμπολ, μπάσκετ, χόκεϊ, ποδόσφαιρο, γκολφ και μηχανοκίνητα.\n" #: tmainform.ckfiltersupernatural.caption msgid "Supernatural" @@ -1085,7 +1089,7 @@ msgstr "Supernatural" msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." msgstr "" "Συνήθως συνεπάγεται εκπληκτικές και ανεξήγητες δυνάμεις ή γεγονότα \n" -"τα οποία αψηφούν τους νόμους της φυσικής." +"τα οποία αψηφούν τους νόμους της φυσικής.\n" #: tmainform.ckfiltertragedy.caption msgid "Tragedy" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index b56da1e6f..8fd1cc233 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -355,6 +355,10 @@ msgstr "Initialization Vector:" msgid "Key:" msgstr "Key:" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Remove watermark" @@ -2228,3 +2232,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index e472d9c76..8ed62213f 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -348,6 +348,10 @@ msgstr "" msgid "Key:" msgstr "" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Quitar Marca de Agua" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 9ecaeee1d..7a7d27e3d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -353,6 +353,10 @@ msgstr "Initialization Vector:" msgid "Key:" msgstr "Key:" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Hapus watermark" @@ -2209,3 +2213,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 886d88959..1ea0ef454 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -350,6 +350,10 @@ msgstr "" msgid "Key:" msgstr "" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Usuń znak wodny" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 3a9425793..43657d547 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -313,6 +313,10 @@ msgstr "" msgid "Key:" msgstr "" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 17b6cd0e6..8c999c356 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -350,6 +350,10 @@ msgstr "" msgid "Key:" msgstr "" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Remover a marca d'água" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 2f117407d..58a93e12d 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -352,6 +352,10 @@ msgstr "Вектор инициализации:" msgid "Key:" msgstr "Ключ:" +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Удалить водяные знаки" @@ -2208,3 +2212,4 @@ msgstr "Синхронизацияе данных" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Обновление списка" + From 7121186b5046d0fefdd71a8d76899026fdb6b3f0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 22 Jul 2017 04:28:17 +0800 Subject: [PATCH 1828/2794] change build mode options --- mangadownloader/md.lpi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c21dfb311..9ca997eaa 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -48,6 +48,7 @@ <OptimizationLevel Value="4"/> <VariablesInRegisters Value="True"/> </Optimizations> + <SmallerCode Value="True"/> </CodeGeneration> <Linking> <Debugging> @@ -377,6 +378,7 @@ <OptimizationLevel Value="4"/> <VariablesInRegisters Value="True"/> </Optimizations> + <SmallerCode Value="True"/> </CodeGeneration> <Linking> <Debugging> From e9c8765def16827ced33cb8bb6fed323ede1fb27 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 23 Jul 2017 09:43:38 +0800 Subject: [PATCH 1829/2794] mangafox, added watermark template closed #680 --- extras/mangafoxtemplate/728x86-2.png | Bin 0 -> 4313 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 extras/mangafoxtemplate/728x86-2.png diff --git a/extras/mangafoxtemplate/728x86-2.png b/extras/mangafoxtemplate/728x86-2.png new file mode 100644 index 0000000000000000000000000000000000000000..82c9163de5afa28b645c7100faa89a154a866bc3 GIT binary patch literal 4313 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 SJ$T;^fDQf(uEokP?SBAM%zID( literal 0 HcmV?d00001 From 3f651a222eb9998dc420b8f42ee82dbf76f28420 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 23 Jul 2017 21:43:46 +0800 Subject: [PATCH 1830/2794] madokami, auth failed if redirected to login page closed #681 --- baseunits/modules/Madokami.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 4f0ed1f2e..ce39b1b33 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -91,7 +91,8 @@ function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; SetAuth(AHTTP); AHTTP.FollowRedirection := False; Result := AHTTP.GET(AURL); - if (AHTTP.ResultCode > 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ' Basic') then + if ((AHTTP.ResultCode > 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ' Basic')) or + (Pos('/login',AHTTP.Headers.Values['Location']) <> 0) then begin if Login(AHTTP) then Result := AHTTP.GET(AURL); From e8c2fabdca35d6a6e0c76c5e821cbb697c7aa5c3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 23 Jul 2017 21:44:30 +0800 Subject: [PATCH 1831/2794] mangago, fixed download closed #682 --- baseunits/modules/MangaGo.pas | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index f7a317d6c..71d49ea8f 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -76,8 +76,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -88,9 +86,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - s := XPathString('//script[contains(.,"imgsrcs")]/substring-before(substring-after(substring-before(.,"imgsrcs"),"= ''"),"''")', Document); - if s <> '' then - PageLinks.CommaText := s + PageLinks.CommaText := XPathString('//script[contains(.,"imgsrcs")]/replace(substring-before(substring-after(.,"("),")"),"''","")', Document); end; end; end; From 9eb14b9ca9ef7a800df075d0eea7fc7a26c572ca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 23 Jul 2017 21:55:30 +0800 Subject: [PATCH 1832/2794] fixed slow mangalist live search --- mangadownloader/forms/frmMain.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7b64debb0..78173bb07 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -928,7 +928,7 @@ procedure TSearchDBThread.SyncBeforeSearch; begin vtMangaList.Cursor := crHourGlass; lbMode.Caption := RS_ModeSearching; - vtMangaList.BeginUpdate; + vtMangaList.RootNodeCount := 0; end; end; @@ -937,7 +937,6 @@ procedure TSearchDBThread.SyncAfterSearch; with MainForm do begin vtMangaList.RootNodeCount := dataProcess.RecordCount; - vtMangaList.EndUpdate; UpdateVtMangaListFilterStatus; LastSearchWeb := dataProcess.Website; LastSearchStr := UpCase(FSearchStr); From 567039035eb5ad24b784190d0cd4ff7688a900c9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 24 Jul 2017 10:43:42 +0800 Subject: [PATCH 1833/2794] updater, change build mode options --- updater/updater.lpi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/updater/updater.lpi b/updater/updater.lpi index 09b25fd42..38fb9946c 100644 --- a/updater/updater.lpi +++ b/updater/updater.lpi @@ -41,12 +41,14 @@ <TargetCPU Value="x86_64"/> <TargetOS Value="win64"/> <Optimizations> - <OptimizationLevel Value="3"/> + <OptimizationLevel Value="4"/> </Optimizations> + <SmallerCode Value="True"/> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> + <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> @@ -173,12 +175,14 @@ <TargetCPU Value="i386"/> <TargetOS Value="win32"/> <Optimizations> - <OptimizationLevel Value="3"/> + <OptimizationLevel Value="4"/> </Optimizations> + <SmallerCode Value="True"/> </CodeGeneration> <Linking> <Debugging> <GenerateDebugInfo Value="False"/> + <StripSymbols Value="True"/> </Debugging> <LinkSmart Value="True"/> <Options> From a36f9f3ad4dd0e950403e01eddee4d188a679e16 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 24 Jul 2017 21:49:35 +0800 Subject: [PATCH 1834/2794] httpsendthread, fixed redirection --- baseunits/httpsendthread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index d7a1d7c37..7a30d9a22 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -445,9 +445,9 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: Headers.Assign(HTTPHeader); end; - // redirection ' + // redirection, only 301, 302, 303 if FFollowRedirection then - while (ResultCode > 300) and (ResultCode < 400) do begin + while (ResultCode > 300) and (ResultCode < 304) do begin if CheckTerminate then Exit; HTTPHeader.Values['Referer'] := ' ' + rurl; s := Trim(Headers.Values['Location']); From e7ecb4c542443cb0d099e2100ed0b8bdc3e7bfc0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 16:10:21 +0800 Subject: [PATCH 1835/2794] added support for relative path #672 --- baseunits/FMDOptions.pas | 2 +- baseunits/uBaseUnit.pas | 4 ++-- baseunits/uDownloadsManager.pas | 11 +++++------ baseunits/uSilentThread.pas | 3 +-- mangadownloader/forms/frmMain.pas | 15 ++++++--------- 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index af30afa9d..f9052a55c 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -272,7 +272,7 @@ procedure SetAppDataDirectory(const ADir: String); begin APPDATA_DIRECTORY := CleanAndExpandDirectory(ADir); - DEFAULT_PATH := APPDATA_DIRECTORY + 'downloads' + PathDelim; + DEFAULT_PATH := 'downloads' + PathDelim; CONFIG_FOLDER := APPDATA_DIRECTORY + 'config' + PathDelim; CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 693b5612e..0aceafdb9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -4047,7 +4047,7 @@ function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String; procedure TFavoriteInfo.SetSaveTo(AValue: String); begin if FSaveTo = AValue then Exit; - FSaveTo := CorrectPathSys(AValue); + FSaveTo := AValue; end; { TDownloadInfo } @@ -4055,7 +4055,7 @@ procedure TFavoriteInfo.SetSaveTo(AValue: String); procedure TDownloadInfo.SetSaveTo(AValue: String); begin if FSaveTo = AValue then Exit; - FSaveTo := CorrectPathSys(AValue); + FSaveTo := AValue; end; { THTMLForm } diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index c19e548da..9bb2a6f65 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -806,11 +806,10 @@ procedure TTaskThread.Compress; end; uPacker.CompressionQuality := OptionPDFQuality; uPacker.Path := CurrentWorkingDir; - uPacker.FileName := Container.DownloadInfo.SaveTo + - Container.ChapterName[Container.CurrentDownloadChapterPtr]; + uPacker.FileName := RemovePathDelim(uPacker.Path); for i := 0 to Container.PageLinks.Count - 1 do begin - s := FindImageFile(CurrentWorkingDir + GetFileName(i)); + s := FindImageFile(uPacker.Path + GetFileName(i)); if s <> '' then uPacker.FileList.Add(s); end; @@ -1107,10 +1106,10 @@ procedure TTaskThread.Execute; //check path if OptionGenerateChapterFolder then - CurrentWorkingDir := Container.DownloadInfo.SaveTo + - Container.ChapterName[Container.CurrentDownloadChapterPtr] + CurrentWorkingDir := CleanAndExpandDirectory(Container.DownloadInfo.SaveTo) + + AppendPathDelim(Container.ChapterName[Container.CurrentDownloadChapterPtr]) else - CurrentWorkingDir := Container.DownloadInfo.SaveTo; + CurrentWorkingDir := CleanAndExpandDirectory(Container.DownloadInfo.SaveTo); if not ForceDirectoriesUTF8(CurrentWorkingDir) then begin Logger.SendError(Format('Failed to create dir(%d) = %s', [Length(CurrentWorkingDir), CurrentWorkingDir])); diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 16fa92d11..57f21c5a5 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -466,14 +466,13 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; '', OptionChangeUnicodeCharacter, OptionChangeUnicodeCharacterStr); - if Trim(title) = '' then title := Info.mangaInfo.title; FavoriteManager.Add(title, IntToStr(Info.mangaInfo.numChapter), info.mangaInfo.chapterLinks.Text, website, - CorrectPathSys(s), + s, URL); UpdateVtFavorites; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 78173bb07..67689852b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2183,7 +2183,7 @@ procedure TMainForm.btAddToFavoritesClick(Sender: TObject); OptionChangeUnicodeCharacterStr); FavoriteManager.Add(mangaInfo.title, IntToStr(mangaInfo.numChapter), mangaInfo.chapterLinks.Text, - mangaInfo.website, CleanAndExpandDirectory(s), mangaInfo.link); + mangaInfo.website, s, mangaInfo.link); vtFavorites.NodeDataSize := SizeOf(TFavoriteInfo); UpdateVtFavorites; btAddToFavorites.Enabled := False; @@ -3267,14 +3267,14 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then - OpenDocument(ChompPathDelim( + OpenDocument(CleanAndExpandFilename( FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); end; procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); begin if Assigned(vtDownload.FocusedNode) then - OpenDocument(ChompPathDelim( + OpenDocument(CleanAndExpandFilename( DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo)); end; @@ -4479,9 +4479,7 @@ procedure TMainForm.FilledSaveTo; edSaveTo.Text := Trim(configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH)); if edSaveTo.Text = '' then edSaveTo.Text := DEFAULT_PATH; - end - else - edSaveTo.Text := CleanAndExpandDirectory(edSaveTo.Text); + end; end; procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; @@ -4802,7 +4800,6 @@ procedure TMainForm.SaveOptions; // saveto if Trim(edOptionDefaultPath.Text) = '' then edOptionDefaultPath.Text := DEFAULT_PATH; - edOptionDefaultPath.Text := CleanAndExpandDirectory(edOptionDefaultPath.Text); WriteString('saveto', 'SaveTo', edOptionDefaultPath.Text); WriteBool('saveto', 'ChangeUnicodeCharacter', cbOptionChangeUnicodeCharacter.Checked); WriteString('saveto', 'ChangeUnicodeCharacterStr', edOptionChangeUnicodeCharacterStr.Text); @@ -5172,7 +5169,7 @@ procedure TMainForm.edOptionDefaultPathButtonClick(Sender: TObject); try InitialDir := edOptionDefaultPath.Text; if Execute then - edOptionDefaultPath.Text := CleanAndExpandDirectory(FileName); + edOptionDefaultPath.Text := FileName; finally Free; end; @@ -5196,7 +5193,7 @@ procedure TMainForm.edSaveToButtonClick(Sender: TObject); try InitialDir := edSaveTo.Text; if Execute then - edSaveTo.Text := CleanAndExpandDirectory(FileName); + edSaveTo.Text := FileName; finally Free; end; From c7a4a81e75b6ce3b64ce56e96e7a63c21c86454d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 16:36:19 +0800 Subject: [PATCH 1836/2794] added selectdirectoryform for common change save to --- mangadownloader/forms/frmSelectDirectory.lfm | 112 +++++++++++++++++++ mangadownloader/forms/frmSelectDirectory.lrj | 4 + mangadownloader/forms/frmSelectDirectory.pas | 32 ++++++ mangadownloader/languages/fmd.de.po | 11 ++ mangadownloader/languages/fmd.el_GR.po | 11 ++ mangadownloader/languages/fmd.en.po | 11 ++ mangadownloader/languages/fmd.es.po | 11 ++ mangadownloader/languages/fmd.id_ID.po | 11 ++ mangadownloader/languages/fmd.pl_PL.po | 11 ++ mangadownloader/languages/fmd.po | 10 ++ mangadownloader/languages/fmd.pt_BR.po | 11 ++ mangadownloader/languages/fmd.ru_RU.po | 11 ++ mangadownloader/md.lpi | 8 +- 13 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 mangadownloader/forms/frmSelectDirectory.lfm create mode 100644 mangadownloader/forms/frmSelectDirectory.lrj create mode 100644 mangadownloader/forms/frmSelectDirectory.pas diff --git a/mangadownloader/forms/frmSelectDirectory.lfm b/mangadownloader/forms/frmSelectDirectory.lfm new file mode 100644 index 000000000..a9c5a2ef5 --- /dev/null +++ b/mangadownloader/forms/frmSelectDirectory.lfm @@ -0,0 +1,112 @@ +object SelectDirectoryForm: TSelectDirectoryForm + Left = 445 + Height = 70 + Top = 322 + Width = 320 + BorderIcons = [biSystemMenu] + Caption = 'Select directory' + ChildSizing.VerticalSpacing = 6 + ClientHeight = 70 + ClientWidth = 320 + Position = poMainFormCenter + LCLVersion = '1.9.0.0' + object dePath: TDirectoryEdit + Left = 8 + Height = 23 + Top = 8 + Width = 304 + ShowHidden = False + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 0000002E45000064970000629300005E8E30005C8C7C00598792000000070028 + 3C00005B8900005B8900005B8900002E45000000000000000000000000000000 + 0000002E450000659950006497991C7AA9C052A5CDE0005B89C10000001A0028 + 3C07005B8900005B8900005B8900002E45000000000000000000000000110000 + 002400466A983590BDF269B8DDFA82CBECFF85CEEEFF005C8BEF005079C40050 + 79C4005D8CBE005D8CBE005D8CBE00466A980000002400000011000000090000 + 0012006699B288D0EFFF7FCAE9FF7FCAE9FF87D0EFFF267DA9FF7FBCDBFF7FBC + DBFF8DD1F3FF8DD1F3FF90D4F5FF006699B20042634D00000009000000000054 + 7E00006FA7A48AD3F0FF82CDEBFF82CDEBFF8AD3F0FF267EABFF7CB9D8FF7CB9 + D8FF8ACEF0FF8ACEF0FF8FD3F4FFF4B62EFF006FA7A400547E00005782000073 + AC000073AC9E8ED6F2FF87D0EDFF87D0EDFF8ED6F2FF2882AFFF7DBAD8FF7DBA + D8FF8BCFF1FF8BCFF1FF91D5F5FFFEC941FF0073AC9E0073AC000076B0000076 + B0000076B09B92DAF4FF8BD4F0FF8BD4F0FF92DAF4FF2B85B3FF7FBCDAFF7FBC + DAFF8DD1F3FF8DD1F3FF93D7F6FFEBEBDDFF0076B09B0076B0000078B4000078 + B4000078B49797DEF6FF90D8F2FF90D8F2FF97DEF6FF2D89B7FF80BDDCFF80BD + DCFF8FD3F5FF8FD3F5FF95D9F8FFF5F5EEFF0078B4970078B400007BB800007B + B800007BB8949BE1F7FF94DBF4FF94DBF4FF9BE1F7FF308DBCFF81BEDDFF81BE + DDFF90D4F6FF90D4F6FF97DBF9FFFEFEFDFF007BB894007BB800007DBB00007D + BB00007DBB909EE5F9FF98DFF6FF98DFF6FF9EE5F9FF3290C0FF83C0DFFF83C0 + DFFF92D6F8FF92D6F8FF99DDFAFF007DBB90007DBB33007CBA00007FBF00007F + BF00007FBF8DA3E8FBFF9DE3F9FF9DE3F9FFA3E8FBFF3594C5FF85C2E1FF85C2 + E1FF94D8FAFF94D8FAFF9BDFFCFF007FBF8D007FBE00007EBD000082C2000082 + C2000082C28AA6EBFCFFA1E6FBFFA1E6FBFFA6EBFCFF3C9DCFFF87C4E2FF87C4 + E2FF96DAFCFF96DAFCFF9EE2FDFF0082C28A0082C2000082C2000084C5000084 + C5000084C587A9EEFDFFA4E9FCFFA4E9FCFFAAEFFDFF42A1D1FF90D1F1FF96DA + FBFF97DBFDFF97DBFDFF9FE3FEFF0084C5870084C5000084C5000085C8000085 + C8000085C885ADF1FFFFABEFFEFF95E2F8FF6EC9EDFF48A9D9FF98DCFEFF98DC + FEFF98DCFEFF98DCFEFFA1E5FFFF0085C8850085C8000085C8000087CA000087 + CA000087CA8388DCF4FF60C0E9FF5FBFEAFF80D3F4FF9CE3FDFFA2E6FFFFA2E6 + FFFFA2E6FFFFA2E6FFFFA6EAFFFF0087CA830087CA000087CA000087CB000087 + CB000088CC610088CC810088CC810088CC810088CC810088CC810088CC810088 + CC810088CC810088CC810088CC810088CC610087CB000087CB00 + } + NumGlyphs = 1 + Anchors = [akTop, akLeft, akRight] + MaxLength = 0 + TabOrder = 0 + end + object btOK: TBitBtn + AnchorSideTop.Control = dePath + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = dePath + AnchorSideRight.Side = asrBottom + Left = 250 + Height = 26 + Top = 37 + Width = 62 + Anchors = [akTop, akRight] + AutoSize = True + Caption = 'OK' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 00010000000800000010000000170000001A0000001900000017000000150000 + 00110000000D0000000A000000060000000300000001FFFFFF00FFFFFF000000 + 00020000000F0000001F0000002D02330066025F00CC012B0055000000290000 + 00220000001A000000130000000C0000000600000001FFFFFF00FFFFFF000000 + 0000000000000320000006570048077200CC16A60AE8087601C406570029021E + 00000000000000000000000000000000000000000000FFFFFF00FFFFFF000747 + 00000A6500000B8300480B8200CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85 + 001B0745000000000000000000000000000000000000FFFFFF00FFFFFF000E8D + 00000D8800480D8700CC43CA33F629C318FF39CC28FF28C217FF1EAA0FEA0D87 + 00AE0D8A00100F8F0000084A00000000000000000000FFFFFF00FFFFFF000E8E + 00480E8D00CC5FD94FF933BC22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA2 + 0FE40E8D009E0F8F00081094000010950000084B0000FFFFFF00FFFFFF000F92 + 00CC6DE55CFA59D048FF69E158FC0F9200CC0F92006D139504CB34B423F832B2 + 21FF1F9F0FDF0F92008C109400021095000010950000FFFFFF00FFFFFF001196 + 0048119700CC73EA62FD119700CC119600480F9300001196004C189D08D33DB6 + 2CFB37AF26FE1FA00EDA1197007B11980000129B0000FFFFFF00FFFFFF001197 + 0000129B0048129B00CC129B0048119700000F93000011970000129B006924AA + 13D857CF46FE55CD44FD21A710D6129C006313A00000FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000113A0 + 008533B820DE61D850FF5CD54BFA1EA80CD213A1004CFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000614A3009E43C631E56BE25AFF70E95FFB14A300CCFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000014A5001014A700B077EE66FF14A700CC14A70048FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000013A2000014A5000014A5000014A6 + 000015A8000015A9001F15AA00CC15AA004814A70000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + ModalResult = 1 + TabOrder = 1 + end +end diff --git a/mangadownloader/forms/frmSelectDirectory.lrj b/mangadownloader/forms/frmSelectDirectory.lrj new file mode 100644 index 000000000..57a2ded3c --- /dev/null +++ b/mangadownloader/forms/frmSelectDirectory.lrj @@ -0,0 +1,4 @@ +{"version":1,"strings":[ +{"hash":51995065,"name":"tselectdirectoryform.caption","sourcebytes":[83,101,108,101,99,116,32,100,105,114,101,99,116,111,114,121],"value":"Select directory"}, +{"hash":1339,"name":"tselectdirectoryform.btok.caption","sourcebytes":[79,75],"value":"OK"} +]} diff --git a/mangadownloader/forms/frmSelectDirectory.pas b/mangadownloader/forms/frmSelectDirectory.pas new file mode 100644 index 000000000..b4b7aa598 --- /dev/null +++ b/mangadownloader/forms/frmSelectDirectory.pas @@ -0,0 +1,32 @@ +unit frmSelectDirectory; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, EditBtn, + Buttons; + +type + + { TSelectDirectoryForm } + + TSelectDirectoryForm = class(TForm) + btOK: TBitBtn; + dePath: TDirectoryEdit; + private + + public + + end; + +var + SelectDirectoryForm: TSelectDirectoryForm; + +implementation + +{$R *.lfm} + +end. + diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 3b0149ca2..e329752e6 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -82,6 +82,7 @@ msgid "Unknown" msgstr "Unbekannt" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1942,6 +1943,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&zur Warteschlage hinzufügen" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Abbrechen" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index d6af477f7..08cd19a86 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -86,6 +86,7 @@ msgid "Unknown" msgstr "Άγνωστο" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "Εντάξει" @@ -1997,6 +1998,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Προσθήκη στην ουρά" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "Εντάξει" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Ματαίωση" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8fd1cc233..ff1053d45 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -82,6 +82,7 @@ msgid "Unknown" msgstr "Unknown" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1942,6 +1943,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Add to queue" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Abort" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 8ed62213f..7e20b84d1 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -76,6 +76,7 @@ msgid "Unknown" msgstr "Desconocido" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1918,6 +1919,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Agregar a Cola" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Abortar" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 7a7d27e3d..1bbb0b819 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -81,6 +81,7 @@ msgid "Unknown" msgstr "Tidak diketahui" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1923,6 +1924,16 @@ msgctxt "tnewchapter.btqueue.caption" msgid "&Add to queue" msgstr "&Tambahkan ke antrian" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Batalkan" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 1ea0ef454..03f853a69 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -77,6 +77,7 @@ msgid "Unknown" msgstr "Nieznane" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1939,6 +1940,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Dodaj do kolejki" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&O" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 43657d547..c2ca7a5bc 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -58,6 +58,7 @@ msgid "Unknown" msgstr "" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "" @@ -1849,6 +1850,15 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "" +#: tselectdirectoryform.btok.caption +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 8c999c356..78257b851 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -77,6 +77,7 @@ msgid "Unknown" msgstr "Desconhecido" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1937,6 +1938,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Adic. à fila" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Abortar" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 58a93e12d..4a703b6be 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -80,6 +80,7 @@ msgid "Unknown" msgstr "Неизвестный" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "OK" @@ -1922,6 +1923,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "Добавить в очередь" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "OK" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "Прервать" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9ca997eaa..0453bb99e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -268,7 +268,7 @@ <PackageName Value="LCL"/> </Item9> </RequiredPackages> - <Units Count="13"> + <Units Count="14"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -357,6 +357,12 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit12> + <Unit13> + <Filename Value="forms\frmSelectDirectory.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="SelectDirectoryForm"/> + <ResourceBaseClass Value="Form"/> + </Unit13> </Units> </ProjectOptions> <CompilerOptions> From c73f48bc8e7d7401f8e305b9a14bde26072b6685 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 16:36:51 +0800 Subject: [PATCH 1837/2794] favorites, change save to use select directory form to be able to add relative path --- mangadownloader/forms/frmMain.lfm | 92 +++++++++++++++---------------- mangadownloader/forms/frmMain.lrj | 14 ++--- mangadownloader/forms/frmMain.pas | 19 +++---- 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index ae3ba7557..0a2b1d8a6 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4606,14 +4606,14 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - Left = 80 - Top = 408 + left = 80 + top = 408 end object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - Left = 592 - Top = 184 + left = 592 + top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -4943,8 +4943,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - Left = 592 - Top = 224 + left = 592 + top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -5002,8 +5002,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - Left = 520 - Top = 212 + left = 520 + top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -5321,8 +5321,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - Left = 382 - Top = 238 + left = 382 + top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5468,13 +5468,13 @@ object MainForm: TMainForm PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - Left = 288 - Top = 432 + left = 288 + top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False - Left = 382 - Top = 110 + left = 382 + top = 110 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5496,8 +5496,8 @@ object MainForm: TMainForm end end object IconList: TImageList - Left = 278 - Top = 102 + left = 278 + top = 102 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6239,8 +6239,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - Left = 278 - Top = 150 + left = 278 + top = 150 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6536,8 +6536,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - Left = 328 - Top = 238 + left = 328 + top = 238 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6831,8 +6831,8 @@ object MainForm: TMainForm } end object IconSmall: TImageList - Left = 27 - Top = 328 + left = 27 + top = 328 Bitmap = { 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6935,8 +6935,8 @@ object MainForm: TMainForm end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup - Left = 592 - Top = 136 + left = 592 + top = 136 object medURLUndo: TMenuItem Caption = 'Undo' OnClick = medURLUndoClick @@ -6975,38 +6975,38 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - Left = 80 - Top = 448 + left = 80 + top = 448 end object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - Left = 560 - Top = 472 + left = 560 + top = 472 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - Left = 504 - Top = 120 + left = 504 + top = 120 end object TransferRateToolset: TChartToolset - Left = 464 - Top = 120 + left = 464 + top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - Left = 152 - Top = 376 + left = 152 + top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick end end object pmFilterGenreAll: TPopupMenu - Left = 520 - Top = 168 + left = 520 + top = 168 object mnFilterGenreAllCheck: TMenuItem Caption = 'Check all' OnClick = mnFilterGenreAllCheckClick @@ -7022,8 +7022,8 @@ object MainForm: TMainForm end object pmTray: TPopupMenu OnPopup = pmTrayPopup - Left = 341 - Top = 432 + left = 341 + top = 432 object miTrayResumeAll: TMenuItem Caption = 'Resume all' OnClick = tbDownloadResumeAllClick @@ -7087,28 +7087,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - Left = 656 - Top = 416 + left = 656 + top = 416 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - Left = 440 - Top = 472 + left = 440 + top = 472 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - Left = 656 - Top = 472 + left = 656 + top = 472 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - Left = 480 - Top = 472 + left = 480 + top = 472 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 799bf663e..ed6a06ff6 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -50,13 +50,13 @@ {"hash":84262158,"name":"tmainform.cbuseregexpr.caption","sourcebytes":[82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110],"value":"Regular Expression"}, {"hash":111905342,"name":"tmainform.ckfilteraction.hint","sourcebytes":[65,32,119,111,114,107,32,116,121,112,105,99,97,108,108,121,32,100,101,112,105,99,116,105,110,103,32,102,105,103,104,116,105,110,103,44,32,118,105,111,108,101,110,99,101,44,32,99,104,97,111,115,44,32,97,110,100,32,102,97,115,116,32,112,97,99,101,100,32,109,111,116,105,111,110,46],"value":"A work typically depicting fighting, violence, chaos, and fast paced motion."}, {"hash":75149406,"name":"tmainform.ckfilteraction.caption","sourcebytes":[65,99,116,105,111,110],"value":"Action"}, -{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity."}, +{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and\/or graphic sexual content and nudity."}, {"hash":4701236,"name":"tmainform.ckfilteradult.caption","sourcebytes":[65,100,117,108,116],"value":"Adult"}, {"hash":267284606,"name":"tmainform.ckfilteradventure.hint","sourcebytes":[73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,111,114,121,32,103,111,101,115,32,111,110,32,97,32,116,114,105,112,32,111,114,32,97,108,111,110,103,32,116,104,97,116,32,108,105,110,101,44,32,121,111,117,114,32,98,101,115,116,32,98,101,116,32,105,115,32,116,104,97,116,32,105,116,32,105,115,32,97,110,32,97,100,118,101,110,116,117,114,101,32,109,97,110,103,97,46,32,79,116,104,101,114,119,105,115,101,44,32,105,116,39,115,32,117,112,32,116,111,32,121,111,117,114,32,112,101,114,115,111,110,97,108,32,112,114,101,106,117,100,105,99,101,32,111,110,32,116,104,105,115,32,99,97,115,101,46],"value":"If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case."}, {"hash":214301493,"name":"tmainform.ckfilteradventure.caption","sourcebytes":[65,100,118,101,110,116,117,114,101],"value":"Adventure"}, {"hash":11846766,"name":"tmainform.ckfiltercomedy.hint","sourcebytes":[65,32,100,114,97,109,97,116,105,99,32,119,111,114,107,32,116,104,97,116,32,105,115,32,108,105,103,104,116,32,97,110,100,32,111,102,116,101,110,32,104,117,109,111,114,111,117,115,32,111,114,32,115,97,116,105,114,105,99,97,108,32,105,110,32,116,111,110,101,32,97,110,100,32,116,104,97,116,32,117,115,117,97,108,108,121,32,99,111,110,116,97,105,110,115,32,97,32,104,97,112,112,121,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,104,101,109,97,116,105,99,32,99,111,110,102,108,105,99,116,46],"value":"A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict."}, {"hash":78003129,"name":"tmainform.ckfiltercomedy.caption","sourcebytes":[67,111,109,101,100,121],"value":"Comedy"}, -{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga/anime."}, +{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga\/anime."}, {"hash":202379913,"name":"tmainform.ckfilterdoujinshi.caption","sourcebytes":[68,111,117,106,105,110,115,104,105],"value":"Doujinshi"}, {"hash":221112350,"name":"tmainform.ckfilterdrama.hint","sourcebytes":[65,32,119,111,114,107,32,109,101,97,110,116,32,116,111,32,98,114,105,110,103,32,111,110,32,97,110,32,101,109,111,116,105,111,110,97,108,32,114,101,115,112,111,110,115,101,44,32,115,117,99,104,32,97,115,32,105,110,115,116,105,108,108,105,110,103,32,115,97,100,110,101,115,115,32,111,114,32,116,101,110,115,105,111,110,46],"value":"A work meant to bring on an emotional response, such as instilling sadness or tension."}, {"hash":4950065,"name":"tmainform.ckfilterdrama.caption","sourcebytes":[68,114,97,109,97],"value":"Drama"}, @@ -80,7 +80,7 @@ {"hash":56818190,"name":"tmainform.ckfilterlolicon.caption","sourcebytes":[76,111,108,105,99,111,110],"value":"Lolicon"}, {"hash":104001182,"name":"tmainform.ckfiltermartialarts.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,109,97,114,116,105,97,108,32,97,114,116,115,32,114,101,108,97,116,101,100,46,32,65,110,121,32,111,102,32,115,101,118,101,114,97,108,32,97,114,116,115,32,111,102,32,99,111,109,98,97,116,32,111,114,32,115,101,108,102,45,100,101,102,101,110,115,101,44,32,115,117,99,104,32,97,115,32,97,105,107,105,100,111,44,32,107,97,114,97,116,101,44,32,106,117,100,111,44,32,111,114,32,116,97,101,107,119,111,110,100,111,44,32,107,101,110,100,111,44,32,102,101,110,99,105,110,103,44,32,97,110,100,32,115,111,32,111,110,32,97,110,100,32,115,111,32,102,111,114,116,104,46],"value":"As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth."}, {"hash":47977283,"name":"tmainform.ckfiltermartialarts.caption","sourcebytes":[77,97,114,116,105,97,108,32,65,114,116,115],"value":"Martial Arts"}, -{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language."}, +{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and\/or strong language."}, {"hash":87604357,"name":"tmainform.ckfiltermature.caption","sourcebytes":[77,97,116,117,114,101],"value":"Mature"}, {"hash":187133582,"name":"tmainform.ckfiltermecha.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,118,111,108,118,105,110,103,32,97,110,100,32,117,115,117,97,108,108,121,32,99,111,110,99,101,110,116,114,97,116,105,110,103,32,111,110,32,97,108,108,32,116,121,112,101,115,32,111,102,32,108,97,114,103,101,32,114,111,98,111,116,105,99,32,109,97,99,104,105,110,101,115,46],"value":"A work involving and usually concentrating on all types of large robotic machines."}, {"hash":5487073,"name":"tmainform.ckfiltermecha.caption","sourcebytes":[77,101,99,104,97],"value":"Mecha"}, @@ -104,11 +104,11 @@ {"hash":94333967,"name":"tmainform.ckfiltershoujo.caption","sourcebytes":[83,104,111,117,106,111],"value":"Shoujo"}, {"hash":171132846,"name":"tmainform.ckfiltershoujoai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,117,114,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,71,105,114,108,39,39,115,32,76,111,118,101,34,44,32,115,111,32,116,111,32,115,112,101,97,107,46],"value":"Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak."}, {"hash":113331593,"name":"tmainform.ckfiltershoujoai.caption","sourcebytes":[83,104,111,117,106,111,32,65,105],"value":"Shoujo Ai"}, -{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and/or violence."}, +{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and\/or violence."}, {"hash":167167214,"name":"tmainform.ckfiltershounen.caption","sourcebytes":[83,104,111,117,110,101,110],"value":"Shounen"}, {"hash":19597467,"name":"tmainform.ckfiltershounenai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,97,111,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,66,111,121,39,39,115,32,76,111,118,101,34,194,157,44,32,115,111,32,116,111,32,115,112,101,97,107],"value":"Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\"\u009D, so to speak"}, {"hash":206543641,"name":"tmainform.ckfiltershounenai.caption","sourcebytes":[83,104,111,117,110,101,110,32,65,105],"value":"Shounen Ai"}, -{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, +{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one\/many character(s). These challenges\/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, {"hash":262977669,"name":"tmainform.ckfiltersliceoflife.caption","sourcebytes":[83,108,105,99,101,32,111,102,32,76,105,102,101],"value":"Slice of Life"}, {"hash":68245006,"name":"tmainform.ckfiltersmut.hint","sourcebytes":[68,101,97,108,115,32,119,105,116,104,32,115,101,114,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,112,114,111,102,97,110,101,32,111,114,32,111,102,102,101,110,115,105,118,101,44,32,112,97,114,116,105,99,117,108,97,114,108,121,32,119,105,116,104,32,114,101,103,97,114,100,115,32,116,111,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,46],"value":"Deals with series that are considered profane or offensive, particularly with regards to sexual content."}, {"hash":369860,"name":"tmainform.ckfiltersmut.caption","sourcebytes":[83,109,117,116],"value":"Smut"}, @@ -165,7 +165,7 @@ {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, {"hash":325284,"name":"tmainform.lboptionhost.caption","sourcebytes":[72,111,115,116],"value":"Host"}, -{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host/IP"}, +{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host\/IP"}, {"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, {"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, @@ -220,7 +220,7 @@ {"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, {"hash":263412434,"name":"tmainform.gbdialogs.caption","sourcebytes":[83,104,111,119,32,100,105,97,108,111,103,32,99,111,110,102,105,114,109,97,116,105,111,110,32,102,111,114],"value":"Show dialog confirmation for"}, {"hash":252071892,"name":"tmainform.cboptionshowquitdialog.caption","sourcebytes":[69,120,105,116,32,70,77,68],"value":"Exit FMD"}, -{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task/favorite"}, +{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task\/favorite"}, {"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, {"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, {"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 67689852b..71b1939e4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -866,8 +866,8 @@ implementation {$R *.lfm} uses - frmImportFavorites, frmShutdownCounter, WebsiteModules, FMDVars, RegExpr, - Clipbrd, LazFileUtils, LazUTF8; + frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, + FMDVars, RegExpr, Clipbrd, LazFileUtils, LazUTF8; var // thread for open db @@ -2876,14 +2876,13 @@ procedure TMainForm.miFavoritesChangeSaveToClick(Sender: TObject); if not Assigned(vtFavorites.FocusedNode) then Exit; s := ''; - with TSelectDirectoryDialog.Create(Self) do - try - InitialDir := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo; - if Execute then - s := FileName; - finally - Free; - end; + with TSelectDirectoryForm.Create(Self) do try + dePath.Directory := FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo; + if ShowModal = mrOK then + s := dePath.Directory; + finally + Free; + end; if s <> '' then begin From 44bcaa9010d91633bcb25fe2b4d8fe081458f3b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 17:09:14 +0800 Subject: [PATCH 1838/2794] move some task/connection limit const to fmdoptions increase limit for win32 to 16, 64 increase limit for win64 to 64, 256 --- baseunits/FMDOptions.pas | 18 ++++++++++++++++-- baseunits/WebsiteModules.pas | 3 --- mangadownloader/forms/frmMain.lfm | 8 ++++---- mangadownloader/forms/frmMain.lrj | 4 ++-- mangadownloader/languages/fmd.de.po | 8 ++++++-- mangadownloader/languages/fmd.el_GR.po | 8 ++++++-- mangadownloader/languages/fmd.en.po | 18 +++++++++--------- mangadownloader/languages/fmd.es.po | 8 ++++++-- mangadownloader/languages/fmd.id_ID.po | 12 +++++------- mangadownloader/languages/fmd.pl_PL.po | 8 ++++++-- mangadownloader/languages/fmd.po | 4 ++-- mangadownloader/languages/fmd.pt_BR.po | 8 ++++++-- mangadownloader/languages/fmd.ru_RU.po | 8 ++++++-- 13 files changed, 74 insertions(+), 41 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index f9052a55c..b96b6187b 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -34,8 +34,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) EXPARAM_CHAPTER = '%CHAPTER%'; DEFAULT_EXPARAM = '"' + EXPARAM_PATH + EXPARAM_CHAPTER + '"'; - SOCKHEARTBEATRATE = 400; - DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; @@ -47,6 +45,22 @@ TIniFileRun = class(IniFiles.TMemIniFile) ZIP_EXE = '7za.exe'; RUN_EXE = '.run'; + + SOCKHEARTBEATRATE = 500; + {$IFDEF WINDOWS} + {$IFDEF WIN32} + MAX_TASKLIMIT = 16; + MAX_CONNECTIONPERHOSTLIMIT = 64; + {$ENDIF} + {$IFDEF WIN64} + MAX_TASKLIMIT = 64; + MAX_CONNECTIONPERHOSTLIMIT = 256; + {$ENDIF} + {$ELSE} + MAX_TASKLIMIT = 8; + MAX_CONNECTIONPERHOSTLIMIT = 32; + {$ENDIF} + var FMD_VERSION_NUMBER, FMD_DIRECTORY, diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 686d4c6e7..e9a0e6287 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -19,9 +19,6 @@ interface NET_PROBLEM = 1; INFORMATION_NOT_FOUND = 2; - MAX_TASKLIMIT = 8; - MAX_CONNECTIONPERHOSTLIMIT = 32; - type TModuleContainer = class; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0a2b1d8a6..f37246285 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3175,8 +3175,8 @@ object MainForm: TMainForm Left = 60 Height = 15 Top = 12 - Width = 292 - Caption = 'Number of downloaded tasks at the same time (Max: 8)' + Width = 247 + Caption = 'Number of downloaded tasks at the same time' ParentColor = False ParentFont = False end @@ -3206,8 +3206,8 @@ object MainForm: TMainForm Left = 60 Height = 15 Top = 39 - Width = 337 - Caption = 'Number of downloaded files per task at the same time (Max: 32)' + Width = 286 + Caption = 'Number of downloaded files per task at the same time' ParentColor = False ParentFont = False end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index ed6a06ff6..f67155a24 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -173,8 +173,8 @@ {"hash":29717652,"name":"tmainform.edoptionpass.texthint","sourcebytes":[80,114,111,120,121,32,112,97,115,115,119,111,114,100],"value":"Proxy password"}, {"hash":376933,"name":"tmainform.lboptionproxytype.caption","sourcebytes":[84,121,112,101],"value":"Type"}, {"hash":317840,"name":"tmainform.cboptionproxytype.text","sourcebytes":[72,84,84,80],"value":"HTTP"}, -{"hash":119412009,"name":"tmainform.lboptionmaxparallel.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,116,97,115,107,115,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,40,77,97,120,58,32,56,41],"value":"Number of downloaded tasks at the same time (Max: 8)"}, -{"hash":12948617,"name":"tmainform.lboptionmaxthread.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,102,105,108,101,115,32,112,101,114,32,116,97,115,107,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101,32,40,77,97,120,58,32,51,50,41],"value":"Number of downloaded files per task at the same time (Max: 32)"}, +{"hash":172706133,"name":"tmainform.lboptionmaxparallel.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,116,97,115,107,115,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101],"value":"Number of downloaded tasks at the same time"}, +{"hash":244185205,"name":"tmainform.lboptionmaxthread.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,102,105,108,101,115,32,112,101,114,32,116,97,115,107,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101],"value":"Number of downloaded files per task at the same time"}, {"hash":34874153,"name":"tmainform.lboptionmaxretry.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,114,101,116,114,121,32,116,105,109,101,115,32,105,102,32,116,97,115,107,115,32,104,97,118,101,32,100,111,119,110,108,111,97,100,32,112,114,111,98,108,101,109,115,32,40,45,49,32,61,32,97,108,119,97,121,115,32,114,101,116,114,121,41],"value":"Number of retry times if tasks have download problems (-1 = always retry)"}, {"hash":161967481,"name":"tmainform.lboptionconnectiontimeout.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,32,116,105,109,101,111,117,116,32,40,115,101,99,111,110,100,115,41],"value":"Connection timeout (seconds)"}, {"hash":160200703,"name":"tmainform.tssaveto.caption","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index e329752e6..a4912711d 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -1393,7 +1393,9 @@ msgstr "" "Manga Ordnername muss mindest %MANGA% haben.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Anzahl von Downloads zur selben Zeit (Max: 8)" #: tmainform.lboptionmaxretry.caption @@ -1402,7 +1404,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Anzahl der erneuten Versuche, falls der Download Probleme hat (-1 =immer wiederholen)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Anzahl der Download-Dateien je Aufgabe zur selben Zeit (Max: 32)" #: tmainform.lboptionnewmangatime.caption diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 08cd19a86..83372b052 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1448,7 +1448,9 @@ msgstr "" "Το όνομα φακέλου Manga πρέπει να έχει τουλάχιστον %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Αριθμός ταυτόχρονων εργασιών λήψης (Μέγ.: 8)" #: tmainform.lboptionmaxretry.caption @@ -1457,7 +1459,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Αριθμός επαναλήψεων αν οι εργασίες έχουν προβλήματα λήψης (-1 = συνεχής επανάληψη)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Αριθμός ταυτόχρονα ληφθέντων αρχείων ανά εργασία (Μέγ: 32)" #: tmainform.lboptionnewmangatime.caption diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index ff1053d45..8c4777d5b 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: en_US\n" -"X-Generator: Poedit 1.8.12\n" +"X-Generator: Poedit 2.0.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: batoto.rs_serverselection @@ -358,7 +358,7 @@ msgstr "Key:" #: kissmanga.rs_kissmanga_usegoogledcp msgid "Use Google DCP" -msgstr "" +msgstr "Use Google DCP" #: mangafox.rs_removewatermark msgid "Remove watermark" @@ -1393,8 +1393,9 @@ msgstr "" "Manga folder name must have at least %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" -msgstr "Number of downloaded tasks at the same time (Max: 8)" +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" +msgstr "Number of downloaded tasks at the same time" #: tmainform.lboptionmaxretry.caption #| msgid "Number of retry times if tasks have download problems (0 = always retry)" @@ -1402,8 +1403,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Number of retry times if tasks have download problems (-1 = always retry)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" -msgstr "Number of downloaded files per task at the same time (Max: 32)" +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" +msgstr "Number of downloaded files per task at the same time" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -1944,14 +1946,13 @@ msgid "&Add to queue" msgstr "&Add to queue" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" #: tselectdirectoryform.caption msgid "Select directory" -msgstr "" +msgstr "Select directory" #: tshutdowncounterform.btabort.caption msgid "&Abort" @@ -2243,4 +2244,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 7e20b84d1..fcd91f2df 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1371,7 +1371,9 @@ msgstr "" "El Nombre del la Carpeta del Manga debe tener al menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Numero de Tareas de Descargas al Mismo Tiempo (Max: 8)" #: tmainform.lboptionmaxretry.caption @@ -1379,7 +1381,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre reintenta)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Numero de Archivos Descargados por Tarea al Mismo Tiempo (Max: 32)" #: tmainform.lboptionnewmangatime.caption diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1bbb0b819..1dfd01a2c 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" "Language: id_ID\n" -"X-Generator: Poedit 1.8.12\n" +"X-Generator: Poedit 2.0.1\n" "Plural-Forms: nplurals=1; plural=0;\n" #: batoto.rs_serverselection @@ -1376,16 +1376,16 @@ msgstr "" "Nama folder komik setidaknya harus meiliki %MANGA%\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" -msgstr "Jumlah unduhan aktif pada waktu yang sama (Max: 8)" +msgid "Number of downloaded tasks at the same time" +msgstr "Jumlah unduhan aktif pada waktu yang sama" #: tmainform.lboptionmaxretry.caption msgid "Number of retry times if tasks have download problems (-1 = always retry)" msgstr "Jumlah pengulangan jika unduhan memiliki masalah (-1 = selalu coba lagi)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" -msgstr "Jumlah koneksi per unduhan pada waktu yang sama (Max: 32)" +msgid "Number of downloaded files per task at the same time" +msgstr "Jumlah koneksi per unduhan pada waktu yang sama" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -1925,7 +1925,6 @@ msgid "&Add to queue" msgstr "&Tambahkan ke antrian" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" @@ -2224,4 +2223,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 03f853a69..7f2e354e9 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1388,7 +1388,9 @@ msgstr "" "Nazwa folderu z mangą musi mieć przynajmniej %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Ilość pobierań w tym samym czasie (max: 8)" #: tmainform.lboptionmaxretry.caption @@ -1397,7 +1399,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Ilość prób pobierania po nieudanym pobraniu (-1 = zawsze próbuj)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Liczba pobieranych plików na zadanie w tym samym czasie (Max: 32)" # WTF does that mean? diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c2ca7a5bc..54f7a5d93 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1302,7 +1302,7 @@ msgid "" msgstr "" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "" #: tmainform.lboptionmaxretry.caption @@ -1310,7 +1310,7 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "" #: tmainform.lboptionnewmangatime.caption diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 78257b851..b4dd0b680 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1388,7 +1388,9 @@ msgstr "" "Nome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Número de tarefas de download ao mesmo tempo (Máx: 8)" #: tmainform.lboptionmaxretry.caption @@ -1397,7 +1399,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Número de tentativas de repetição se as tarefas tiverem problemas de download (-1 = sempre tentar novamente)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Número de arquivos baixados por tarefa ao mesmo tempo (Máx: 32)" #: tmainform.lboptionnewmangatime.caption diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 4a703b6be..22e9b2264 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -1375,7 +1375,9 @@ msgstr "" "Имя папки манги должно содержать как минимум %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Количество загружаемых задач одновременно (максимум: 8)" #: tmainform.lboptionmaxretry.caption @@ -1383,7 +1385,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Количество повторных попыток, если задачи имеют проблемы с загрузкой (-1 = всегда повторять)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Количество загружаемых файлов за одну задачу одновременно (максимум: 32)" #: tmainform.lboptionnewmangatime.caption From 32264f464b699183fa9ddb5ebcbc0da1abad9db8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 17:27:55 +0800 Subject: [PATCH 1839/2794] future changelog --- changelog.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.txt b/changelog.txt index 5397f025d..f9b647513 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.120.0 (future) +[*] Added support for relative path +[*] Increased task/connection limit for win32 to 16/64 and win64 to 64/256 +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.119.0...0.9.120.0 + 0.9.119.0 (21-07-2017) [+] Added shogakukan [+] Added Russian translation by TokcDK From b34be8a41b570a094996750112a0000fb4a6d459 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 17:29:15 +0800 Subject: [PATCH 1840/2794] madokami, exclude txt zip rar from update list --- baseunits/modules/Madokami.pas | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index ce39b1b33..feae1e8d9 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -146,30 +146,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; procedure GetList; - var - v: IXQValue; - s: String; begin - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//table[@id="index-table"]/tbody/tr/td[1]/a') do - begin - s := v.toString; - if Length(s) > 1 then - begin - if s[Length(s)] = '/' then - SetLength(s, Length(s) - 1); - if LowerCase(LeftStr(s, 4)) = '.txt' then - s := ''; - end; - if s <> '' then - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(s); - end; - end; - finally - Free; - end; + XPathHREFAll('//table[@id="index-table"]/tbody/tr/td[1]/a[not(ends-with(.,".txt") or ends-with(.,".zip") or ends-with(.,".rar"))]', MangaInfo.FHTTP.Document, ALinks, ANames); end; var From 7302839a7f6742337b2ce54d3720711801e3600c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 26 Jul 2017 18:21:11 +0800 Subject: [PATCH 1841/2794] Bump version 0.9.120.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index f9b647513..31a4def16 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.120.0 (future) +0.9.120.0 (26-07.2017) [*] Added support for relative path [*] Increased task/connection limit for win32 to 16/64 and win64 to 64/256 [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0453bb99e..949158fcf 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="119"/> + <RevisionNr Value="120"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 21c4b84a9..df3f0bcb4 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.119.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.119.0/fmd_0.9.119.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.119.0/fmd_0.9.119.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.119.0/fmd_0.9.119.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.119.0/fmd_0.9.119.0_Win64.7z +VERSION=0.9.120.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.120.0/fmd_0.9.120.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.120.0/fmd_0.9.120.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.120.0/fmd_0.9.120.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.120.0/fmd_0.9.120.0_Win64.7z From 2f98d9de91bee37f013903f4f8b6420640569ab6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 27 Jul 2017 04:38:05 +0800 Subject: [PATCH 1842/2794] mangago, fixed download #682 --- baseunits/modules/MangaGo.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 71d49ea8f..f675360b5 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -76,6 +76,8 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; begin Result := False; if DownloadThread = nil then Exit; @@ -86,7 +88,15 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - PageLinks.CommaText := XPathString('//script[contains(.,"imgsrcs")]/replace(substring-before(substring-after(.,"("),")"),"''","")', Document); + s := XPathString('//script[contains(.,"imgsrcs")]', Document); + if s <> '' then begin + if Pos('imgsrcs = new Array', s) <> 0 then + s := GetString(s, '(', ')') + else + s := GetString(s, ' = ''', ''';'); + s:=StringReplace(s, '''', '', [rfReplaceAll]); + PageLinks.CommaText := s; + end; end; end; end; From 822cfc9a3d52fec8e3b2bb1be8174c4deb709434 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 27 Jul 2017 18:15:03 +0800 Subject: [PATCH 1843/2794] fixed delete task/favorite download --- mangadownloader/forms/frmMain.pas | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 71b1939e4..a8b8cf2e8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1781,7 +1781,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); var xNode: PVirtualNode; i: Integer; - f: String; + f, d: String; begin if vtDownload.SelectedCount = 0 then Exit; if DLManager.Count = 0 then Exit; @@ -1814,9 +1814,14 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if ThreadState then Task.WaitFor; if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) - and (ChapterName.Count > 0) then begin + and (ChapterName.Count > 0) then + begin + d := CleanAndExpandDirectory(DownloadInfo.SaveTo); for i := 0 to ChapterName.Count - 1 do begin - f := CorrectPathSys(DownloadInfo.SaveTo + ChapterName[i]); + f := CorrectPathSys(d + ChapterName[i]); + if DirectoryExistsUTF8(f) then + DeleteDirectory(f, False); + f := RemovePathDelim(f); if FileExistsUTF8(f + '.zip') then DeleteFileUTF8(f + '.zip') else if FileExistsUTF8(f + '.cbz') then @@ -1826,7 +1831,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); else if DirectoryExistsUTF8(f) then DeleteDirectory(f, False); end; - RemoveDirUTF8(DownloadInfo.SaveTo); + RemoveDirUTF8(d); end; if (Sender = miDownloadDeleteTaskDataFavorite) and (FavoriteManager.Items.Count <> 0) and From 8615e197628038c8c0f140e6f3ec46d1fc6dcc49 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 28 Jul 2017 16:19:24 +0800 Subject: [PATCH 1844/2794] fixed packer filename with chapter fixed #687 --- baseunits/uDownloadsManager.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9bb2a6f65..6d6991ba1 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -706,7 +706,9 @@ constructor TTaskThread.Create; httpCookies := ''; FCurrentWorkingDir := ''; FCurrentCustomFileName := ''; + {$IFDEF WINDOWS} FCurrentMaxFileNameLength := 0; + {$ENDIF} end; destructor TTaskThread.Destroy; @@ -806,7 +808,8 @@ procedure TTaskThread.Compress; end; uPacker.CompressionQuality := OptionPDFQuality; uPacker.Path := CurrentWorkingDir; - uPacker.FileName := RemovePathDelim(uPacker.Path); + uPacker.FileName := RemovePathDelim(CorrectPathSys(AppendPathDelim(Container.DownloadInfo.SaveTo) + + Container.ChapterName[Container.CurrentDownloadChapterPtr])); for i := 0 to Container.PageLinks.Count - 1 do begin s := FindImageFile(uPacker.Path + GetFileName(i)); @@ -1106,10 +1109,10 @@ procedure TTaskThread.Execute; //check path if OptionGenerateChapterFolder then - CurrentWorkingDir := CleanAndExpandDirectory(Container.DownloadInfo.SaveTo) + + CurrentWorkingDir := AppendPathDelim(Container.DownloadInfo.SaveTo) + AppendPathDelim(Container.ChapterName[Container.CurrentDownloadChapterPtr]) else - CurrentWorkingDir := CleanAndExpandDirectory(Container.DownloadInfo.SaveTo); + CurrentWorkingDir := Container.DownloadInfo.SaveTo; if not ForceDirectoriesUTF8(CurrentWorkingDir) then begin Logger.SendError(Format('Failed to create dir(%d) = %s', [Length(CurrentWorkingDir), CurrentWorkingDir])); From 63f3976e978f34462f92d149cdfbe9277f666066 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 28 Jul 2017 16:59:12 +0800 Subject: [PATCH 1845/2794] Bump version 0.9.121.0 --- changelog.txt | 5 +++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 31a4def16..56bca45f3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,11 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.121.0 (28-07.2017) +[*] Mangago: fixed download +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.120.0...0.9.121.0 + 0.9.120.0 (26-07.2017) [*] Added support for relative path [*] Increased task/connection limit for win32 to 16/64 and win64 to 64/256 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 949158fcf..351bf94aa 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="120"/> + <RevisionNr Value="121"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index df3f0bcb4..4c959fca6 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.120.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.120.0/fmd_0.9.120.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.120.0/fmd_0.9.120.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.120.0/fmd_0.9.120.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.120.0/fmd_0.9.120.0_Win64.7z +VERSION=0.9.121.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.121.0/fmd_0.9.121.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.121.0/fmd_0.9.121.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.121.0/fmd_0.9.121.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.121.0/fmd_0.9.121.0_Win64.7z From 79bbeb5a0dc43580f63f4725139e4f6e0a4b299f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 29 Jul 2017 23:12:02 +0800 Subject: [PATCH 1846/2794] added more status info on failed to create dir --- baseunits/uDownloadsManager.pas | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 6d6991ba1..e195c795a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -93,6 +93,7 @@ TTaskThread = class(TBaseThread) procedure Execute; override; procedure Compress; procedure SyncStop; + procedure StatusFailedToCreateDir; // show notification when download completed procedure ShowBalloonHint; public @@ -830,6 +831,16 @@ procedure TTaskThread.SyncStop; Container.Manager.CheckAndActiveTask(FCheckAndActiveTaskFlag); end; +procedure TTaskThread.StatusFailedToCreateDir; +begin + Logger.SendError(Format('Failed to create dir(%d) = %s', [Length(CurrentWorkingDir), CurrentWorkingDir])); + Container.Status := STATUS_FAILED; + Container.DownloadInfo.Status := Format('[%d/%d] %s (%d) %s', [ + Container.CurrentDownloadChapterPtr, + Container.ChapterLinks.Count, + RS_FailedToCreateDir, Length(CurrentWorkingDir), LineEnding + CurrentWorkingDir]); +end; + procedure TTaskThread.ShowBalloonHint; begin if OptionShowBalloonHint then @@ -850,11 +861,7 @@ function TDownloadThread.DownloadImage: Boolean; // check download path if not ForceDirectoriesUTF8(Task.CurrentWorkingDir) then begin - Task.Container.Status := STATUS_FAILED; - Task.Container.DownloadInfo.Status := Format('[%d/%d] %s', [ - Task.Container.CurrentDownloadChapterPtr, - Task.Container.ChapterLinks.Count, - RS_FailedToCreateDir]); + Task.StatusFailedToCreateDir; Result := False; Exit; end; @@ -1115,12 +1122,7 @@ procedure TTaskThread.Execute; CurrentWorkingDir := Container.DownloadInfo.SaveTo; if not ForceDirectoriesUTF8(CurrentWorkingDir) then begin - Logger.SendError(Format('Failed to create dir(%d) = %s', [Length(CurrentWorkingDir), CurrentWorkingDir])); - Container.Status := STATUS_FAILED; - Container.DownloadInfo.Status := Format('[%d/%d] %s', [ - Container.CurrentDownloadChapterPtr, - Container.ChapterLinks.Count, - RS_FailedToCreateDir]); + StatusFailedToCreateDir; ShowBalloonHint; Exit; end; From 17f0db05adc8763d8ece47a9bdac8e53f287e122 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 29 Jul 2017 23:39:01 +0800 Subject: [PATCH 1847/2794] cloudflare, added getcf helper for thttpsendthread --- baseunits/modules/Cloudflare.pas | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 1ce85fe79..f5755bd59 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -22,6 +22,12 @@ TCFProps = class procedure Reset; end; + { THTTPSendThreadHelper } + + THTTPSendThreadHelper = class helper for THTTPSendThread + function GETCF(const AURL: String; const CFProps: TCFProps): Boolean; + end; + function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: TCFProps): Boolean; implementation @@ -218,4 +224,11 @@ procedure TCFProps.Reset; Expires := 0.0; end; +{ THTTPSendThreadHelper } + +function THTTPSendThreadHelper.GETCF(const AURL: String; const CFProps: TCFProps): Boolean; +begin + Cloudflare.GETCF(Self, AURL, CFProps); +end; + end. From e635af6590b2610b62b880364906ff2e89970a61 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 30 Jul 2017 00:41:52 +0800 Subject: [PATCH 1848/2794] mangaae, rewrite all fixed #675 --- baseunits/ModuleList.inc | 1 + .../includes/MangaAe/chapter_page_number.inc | 39 ------ .../MangaAe/directory_page_number.inc | 37 ------ baseunits/includes/MangaAe/image_url.inc | 35 ----- .../includes/MangaAe/manga_information.inc | 117 ----------------- .../includes/MangaAe/names_and_links.inc | 50 ------- baseunits/modules/MangaAe.pas | 124 ++++++++++++++++++ baseunits/uBaseUnit.pas | 52 ++++---- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 10 -- 10 files changed, 149 insertions(+), 331 deletions(-) delete mode 100644 baseunits/includes/MangaAe/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaAe/directory_page_number.inc delete mode 100644 baseunits/includes/MangaAe/image_url.inc delete mode 100644 baseunits/includes/MangaAe/manga_information.inc delete mode 100644 baseunits/includes/MangaAe/names_and_links.inc create mode 100644 baseunits/modules/MangaAe.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a9711da00..715c85d4f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -58,6 +58,7 @@ uses MangaTail, TruyenTranhTuan, BlogTruyen, + MangaAe, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/includes/MangaAe/chapter_page_number.inc b/baseunits/includes/MangaAe/chapter_page_number.inc deleted file mode 100644 index 2f6874076..000000000 --- a/baseunits/includes/MangaAe/chapter_page_number.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetMangaAePageNumber: Boolean; - var - s: String; - i, p: LongInt; - l: TStringList; - isExtractPage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - Task.container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) <> 0) and (Pos('class="active"', parse[i]) <> 0) then - isExtractPage := True; - if isExtractPage and (Pos('</div', parse[i]) <> 0) then - Break; - if isExtractPage and - (Pos('<a', parse[i]) <> 0) and (Pos(URL, parse[i]) <> 0) then - begin - p := StrToIntDef(Trim(parse[i + 1]), 0); - if p > Task.Container.PageNumber then - Task.Container.PageNumber := p; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaAe/directory_page_number.inc b/baseunits/includes/MangaAe/directory_page_number.inc deleted file mode 100644 index d9b161bf8..000000000 --- a/baseunits/includes/MangaAe/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetMangaAeDirectoryPageNumber: Byte; - var - i, p: LongInt; - isExtractPage: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + MANGAAE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - APage := 1; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (Pos('<div', parse[i]) <> 0 ) and (Pos('class="pagination', parse[i]) <> 0) then - isExtractPage := True; - if isExtractPage and (Pos('</div', parse[i]) <> 0) then - Break; - if isExtractPage and (Pos('<a', parse[i]) <> 0) then - begin - s := ReplaceRegExpr('^.*/page\:(\d+)$', GetVal(parse[i], 'href'), '$1', True); - p := StrToIntDef(s, 0); - if p > APage then - APage := p; - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/includes/MangaAe/image_url.inc b/baseunits/includes/MangaAe/image_url.inc deleted file mode 100644 index 599f984d2..000000000 --- a/baseunits/includes/MangaAe/image_url.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetMangaAeImageURL: Boolean; - var - s: String; - i: LongInt; - l: TStringList; - isImageURL: Boolean = False; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAE_ID, URL) + '/' + IntToStr(WorkId + 1)); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('id="showchaptercontainer', parse[i]) <> 0) then - isImageURL := True; - if isImageURL and (Pos('<img', parse[i]) <> 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaAe/manga_information.inc b/baseunits/includes/MangaAe/manga_information.inc deleted file mode 100644 index 00a229e02..000000000 --- a/baseunits/includes/MangaAe/manga_information.inc +++ /dev/null @@ -1,117 +0,0 @@ - function GetMangaAeInfoFromURL: Byte; - var - i: LongInt; - regx: TRegExpr; - isExtractChapter: Boolean = False; - isExtractGenres : Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAAE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAAE_ID, AURL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.genres := ''; - - regx := TRegExpr.Create; - try - regx.Expression := '/1/?$'; - for i := 0 to parse.Count - 1 do - begin - // cover - if (Pos('<img', parse[i]) <> 0) and (Pos('class="manga-cover', parse[i]) <> 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // title - if (mangaInfo.title = '') and (Pos('class="EnglishName', parse[i]) <> 0) then - begin - parse[i] := Trim(parse[i + 1]); - if Length(parse[i]) > 2 then - begin - if (parse[i][1] = '(') and (parse[i][Length(parse[i])] = ')') then - parse[i] := Copy(parse[i], 2, Length(parse[i]) - 2); - end; - mangaInfo.title := Trim(parse[i]); - end; - - // author - if (Pos('class="manga-details-author', parse[i]) <> 0) then - if (Pos('<', parse[i + 21]) = 0) then - mangaInfo.authors := Trim(parse[i + 21]); - - // status - if (i + 4 < parse.Count) and - (Pos('الحالة :', parse[i]) <> 0) and - (Pos('</h3', parse[i + 1]) <> 0) then - begin - if (Pos('مستمرة', parse[i + 4]) <> 0) then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - // genres - if Pos('التصنيف:', parse[i]) <> 0 then - isExtractGenres := True; - if isExtractChapter and (Pos('</ul', parse[i]) <> 0) then - isExtractGenres := False; - if isExtractGenres and - (Pos('<a', parse[i]) <> 0) and (Pos('/manga/cats', parse[i]) <> 0) then - begin - if mangaInfo.genres <> '' then - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]) - else - mangaInfo.genres := Trim(parse[i + 1]); - end; - - // summary - if (Pos('نبذة عن المانجا', parse[i]) <> 0) and (Pos('</h3', parse[i + 1]) <> 0) then - if Pos('<', parse[i + 4]) = 0 then - mangaInfo.summary := CommonStringFilter(parse[i + 4]); - - //chapters - if (Pos('<ul', parse[i]) <> 0) and (Pos('class="new-manga-chapters', parse[i]) <> 0) then - isExtractChapter := True; - if isExtractChapter and (Pos('</ul', parse[i]) <> 0) then - isExtractChapter := False; - if isExtractChapter and - (Pos('<a', parse[i]) <> 0) and (Pos('class="chapter', parse[i]) <> 0) then - begin - parse[i] := GetVal(parse[i], 'href'); - if regx.Exec(parse[i]) then - parse[i] := regx.Replace(parse[i], '', False); - mangaInfo.chapterLinks.Add(parse[i]); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - finally - regx.Free; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaAe/names_and_links.inc b/baseunits/includes/MangaAe/names_and_links.inc deleted file mode 100644 index 999b12294..000000000 --- a/baseunits/includes/MangaAe/names_and_links.inc +++ /dev/null @@ -1,50 +0,0 @@ - function MangaAeGetNamesAndLinks: Byte; - var - i: LongInt; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAE_ID, 1] + - MANGAAE_BROWSER + 'page:' + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - if parse.Count > 0 then - begin - regx := TRegExpr.Create; - try - regx.Expression := '[^/]*\w+\.\w+(\:\d+)?/.+'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) <> 0) and (Pos('class="manga"', parse[i]) <> 0) then - begin - s := GetVal(parse[i], 'href'); - if regx.Exec(s) then - begin - ALinks.Add(s); - ANames.Add(CommonStringFilter(parse[i + 1])); - end; - end; - end; - finally - regx.Free; - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/modules/MangaAe.pas b/baseunits/modules/MangaAe.pas new file mode 100644 index 000000000..0cd8f5884 --- /dev/null +++ b/baseunits/modules/MangaAe.pas @@ -0,0 +1,124 @@ +unit MangaAe; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, Cloudflare; + +implementation + +var + cf: TCFProps; + +const + dirurl = '/manga'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GETCF(Module.RootURL + dirurl, cf) then begin + Result := NO_ERROR; + Page := XPathCount('//div[@class="pagination"]/a', MangaInfo.FHTTP.Document); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GETCF(Module.RootURL + dirurl + '/page:' + IncStr(AURL), cf) then + begin + Result := NO_ERROR; + XPathHREFAll('//div[@id="mangadirectory"]/div[@class="mangacontainer"]/a[2]', MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GETCF(url, cf) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do try + coverLink := XPathString('//img[@class="manga-cover"]/resolve-uri(@src)'); + if title = '' then title := TrimChar(XPathString('//h1[@class="EnglishName"]'), ['(', ')']); + authors := XPathString('//div[@class="manga-details-author"]/h4[1]'); + genres := XPathString('//div[@class="manga-details-extended"]/ul/string-join(./li/a,", ")'); + summary := XPathString('//div[@class="manga-details-extended"]/h4[last()]'); + status := MangaInfoStatusIfPos(XPathString('//div[@class="manga-details-extended"]/h4[2]'), + 'مستمرة', + 'مكتملة'); + XPathHREFAll('//ul[@class="new-manga-chapters"]/li/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + u: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + u := RemoveURLDelim(MaybeFillHost(Module.RootURL, AURL)); + if RightStr(u, 2) = '/1' then Delete(u, Length(u)-2, 2); + u += '/0/full'; + if GETCF(u, cf) then + begin + Result := True; + XPathStringAll('//*[@id="showchaptercontainer"]//img/resolve-uri(@src)', Document, PageLinks); + end; + end; +end; + +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; +begin + if DownloadThread.FHTTP.GETCF(AURL, cf) then begin + Result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; + end + else + Result := False; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaAe'; + RootURL := 'https://www.manga.ae'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + end; +end; + +initialization + cf := TCFProps.Create; + RegisterModule; + +finalization + cf.Free; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 0aceafdb9..60bba9e7c 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -243,31 +243,30 @@ interface CENTRALDEMANGAS_ID = 10; EGSCANS_ID = 11; MANGAAR_ID = 12; - MANGAAE_ID = 13; - ANIMESTORY_ID = 14; - LECTUREENLIGNE_ID = 15; - SCANMANGA_ID = 16; - DM5_ID = 17; - KIVMANGA_ID = 18; - MEINMANGA_ID = 19; - MANGASPROJECT_ID = 20; - MANGAREADER_POR_ID = 21; - JAPANSHIN_ID = 22; - CENTRUMMANGI_PL_ID = 23; - MANGALIB_PL_ID = 24; - ONEMANGA_ID = 25; - MANGATOWN_ID = 26; - MANGAOKU_ID = 27; - IKOMIK_ID = 28; - NHENTAI_ID = 29; - UNIXMANGA_ID = 30; - EXTREMEMANGAS_ID = 31; - MANGAHOST_ID = 32; - MANGAKU_ID = 33; - MANGAAT_ID = 34; - DYNASTYSCANS_ID = 35; - - WebsiteRoots: array [0..35] of array [0..1] of String = ( + ANIMESTORY_ID = 13; + LECTUREENLIGNE_ID = 14; + SCANMANGA_ID = 15; + DM5_ID = 16; + KIVMANGA_ID = 17; + MEINMANGA_ID = 18; + MANGASPROJECT_ID = 19; + MANGAREADER_POR_ID = 20; + JAPANSHIN_ID = 21; + CENTRUMMANGI_PL_ID = 22; + MANGALIB_PL_ID = 23; + ONEMANGA_ID = 24; + MANGATOWN_ID = 25; + MANGAOKU_ID = 26; + IKOMIK_ID = 27; + NHENTAI_ID = 28; + UNIXMANGA_ID = 29; + EXTREMEMANGAS_ID = 30; + MANGAHOST_ID = 31; + MANGAKU_ID = 32; + MANGAAT_ID = 33; + DYNASTYSCANS_ID = 34; + + WebsiteRoots: array [0..34] of array [0..1] of String = ( ('AnimeA', 'http://manga.animea.net'), ('OurManga', 'http://www.ourmanga.com'), ('VnSharing', 'http://truyen.vnsharing.net'), @@ -281,7 +280,6 @@ interface ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), ('MangaAr', 'http://manga-ar.net'), - ('MangaAe', 'http://www.manga.ae'), ('AnimeStory', 'http://www.anime-story.com'), ('Lecture-En-Ligne', 'http://www.lecture-en-ligne.com'), ('ScanManga', 'http://www.scan-manga.com'), @@ -333,8 +331,6 @@ interface MANGAAR_BROWSER = '/manga/'; - MANGAAE_BROWSER = '/manga/'; - ANIMESTORY_BROWSER = '/mangas/'; LECTUREENLIGNE_BROWSER = '/index.php?page=liste&ordre=titre'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 99340ac2b..c8ced1c7b 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -782,8 +782,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/LectureEnLigne/directory_page_number.inc} - {$I includes/MangaAe/directory_page_number.inc} - {$I includes/CentralDeMangas/directory_page_number.inc} {$I includes/DM5/directory_page_number.inc} @@ -841,9 +839,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = LECTUREENLIGNE_ID then Result := GetLectureEnLigneDirectoryPageNumber else - if MangaSiteID = MANGAAE_ID then - Result := GetMangaAeDirectoryPageNumber - else if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasDirectoryPageNumber else @@ -909,8 +904,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/MangaAr/names_and_links.inc} - {$I includes/MangaAe/names_and_links.inc} - {$I includes/CentralDeMangas/names_and_links.inc} {$I includes/Imanhua/names_and_links.inc} @@ -1007,9 +1000,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = MANGAAR_ID then Result := MangaArGetNamesAndLinks else - if MangaSiteID = MANGAAE_ID then - Result := MangaAeGetNamesAndLinks - else if MangaSiteID = CENTRALDEMANGAS_ID then Result := CentralDeMangasGetNamesAndLinks else @@ -1117,8 +1107,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/MangaAr/manga_information.inc} - {$I includes/MangaAe/manga_information.inc} - {$I includes/CentralDeMangas/manga_information.inc} {$I includes/MeinManga/manga_information.inc} @@ -1222,9 +1210,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = MANGAAR_ID then Result := GetMangaArInfoFromURL else - if MangaSiteID = MANGAAE_ID then - Result := GetMangaAeInfoFromURL - else if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index e195c795a..1732f4571 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -416,8 +416,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Kivmanga/chapter_page_number.inc} - {$I includes/MangaAe/chapter_page_number.inc} - {$I includes/MangaAr/chapter_page_number.inc} {$I includes/MeinManga/chapter_page_number.inc} @@ -492,9 +490,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftPageNumber else - if Task.Container.MangaSiteID = MANGAAE_ID then - Result := GetMangaAePageNumber - else if Task.Container.MangaSiteID = KIVMANGA_ID then Result := GetKivmangaPageNumber else @@ -563,8 +558,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Kivmanga/image_url.inc} - {$I includes/MangaAe/image_url.inc} - {$I includes/MangaAr/image_url.inc} {$I includes/MangaREADER_POR/image_url.inc} @@ -642,9 +635,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAAR_ID then Result := GetMangaArImageURL else - if Task.Container.MangaSiteID = MANGAAE_ID then - Result := GetMangaAeImageURL - else if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else From 193c025448aa28be8b9770f167fdbc354963c6b6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 30 Jul 2017 01:00:29 +0800 Subject: [PATCH 1849/2794] httpsendthread, break too many redirect --- baseunits/httpsendthread.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 7a30d9a22..0be0590ea 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -54,6 +54,7 @@ THTTPSendThread = class(THTTPSend) FRetryCount: Integer; FGZip: Boolean; FFollowRedirection: Boolean; + FMaxRedirect: Integer; FAllowServerErrorResponse: Boolean; FCookiesExpires: TDateTime; procedure SetTimeout(AValue: Integer); @@ -84,6 +85,7 @@ THTTPSendThread = class(THTTPSend) property AllowServerErrorResponse: Boolean read FAllowServerErrorResponse write FAllowServerErrorResponse; property Thread: TBaseThread read FOwner; property CookiesExpires: TDateTime read FCookiesExpires; + property MaxRedirect: Integer read FMaxRedirect write FMaxRedirect; public BeforeHTTPMethod: THTTPMethodEvent; AfterHTTPMethod: THTTPMethodEvent; @@ -372,6 +374,7 @@ constructor THTTPSendThread.Create(AOwner: TBaseThread); FFollowRedirection := True; FAllowServerErrorResponse := False; FRetryCount := DefaultRetryCount; + FMaxRedirect := 5; SetTimeout(DefaultTimeout); SetProxy(DefaultProxyType, DefaultProxyHost, DefaultProxyPort, DefaultProxyUser, DefaultProxyPass); Reset; @@ -426,6 +429,7 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: var counter: Integer = 0; + redirectcounter: Integer = 0; rurl, s, h, p: String; HTTPHeader: TStringList; mstream: TMemoryStream; @@ -449,6 +453,9 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: if FFollowRedirection then while (ResultCode > 300) and (ResultCode < 304) do begin if CheckTerminate then Exit; + // break too many redirect + if redirectcounter >= FMaxRedirect then Exit + else Inc(redirectcounter); HTTPHeader.Values['Referer'] := ' ' + rurl; s := Trim(Headers.Values['Location']); if s<>'' then From c7434f2a66f2c44217d04efc68ae79bd0c3e93f1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 30 Jul 2017 03:47:51 +0800 Subject: [PATCH 1850/2794] changed log filename with relative path --- mangadownloader/forms/frmMain.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a8b8cf2e8..e3a033bc2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2564,7 +2564,7 @@ procedure TMainForm.edLogFileNameButtonClick(Sender: TObject); begin with TOpenDialog.Create(nil) do try - InitialDir := ExtractFileDir(edLogFileName.Text); + InitialDir := ExtractFileDir(ExpandFileName(edLogFileName.Text)); if Execute then edLogFileName.Text := FileName; finally @@ -4716,7 +4716,7 @@ procedure TMainForm.LoadOptions; ckEnableLogging.Checked := ReadBool('logger', 'Enabled', False); edLogFileName.Text := ReadString('logger', 'LogFileName', ''); if edLogFileName.Text = '' then - edLogFileName.Text := ChangeFileExt(Application.ExeName, '.log'); + edLogFileName.Text := ChangeFileExt(ExtractFileNameOnly(Application.ExeName), '.log'); // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4847,7 +4847,7 @@ procedure TMainForm.SaveOptions; frmCustomColor.SaveToIniFile(configfile); WriteBool('logger', 'Enabled', ckEnableLogging.Checked); if edLogFileName.Text = '' then - edLogFileName.Text := ChangeFileExt(Application.ExeName, '.log'); + edLogFileName.Text := ChangeFileExt(ExtractFileNameOnly(Application.ExeName), '.log'); WriteString('logger', 'LogFileName', edLogFileName.Text); finally UpdateFile; From 3858c0ebbb861d94362e2d34dc2ff1895314890f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 30 Jul 2017 06:58:52 +0800 Subject: [PATCH 1851/2794] changed compiler options --- 3rd/BESENPkg.lpk | 14 +++----------- mangadownloader/md.lpi | 25 ++++++++++++------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk index 1921be4fd..b6a92340f 100644 --- a/3rd/BESENPkg.lpk +++ b/3rd/BESENPkg.lpk @@ -11,17 +11,9 @@ <OtherUnitFiles Value="BESEN\src"/> <UnitOutputDirectory Value="BESEN\lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> - <CodeGeneration> - <SmartLinkUnit Value="True"/> - <Optimizations> - <OptimizationLevel Value="3"/> - </Optimizations> - </CodeGeneration> - <Linking> - <Debugging> - <GenerateDebugInfo Value="False"/> - </Debugging> - </Linking> + <Other> + <CustomOptions Value="-CX -Os4 -Xs -XX -g-"/> + </Other> </CompilerOptions> <Files Count="97"> <Item1> diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 351bf94aa..fca934fab 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -36,8 +36,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -80,8 +80,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -131,8 +131,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -179,8 +179,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -220,9 +220,8 @@ </Other> </CompilerOptions> </Item5> - <SharedMatrixOptions Count="2"> - <Item1 ID="284095981400" Targets="FCL,LazUtils,LCLBase,LCL,TAChartLazarusPkg,richmemopackage,virtualtreeview_package,multiloglaz" Value="-O3 -g- -CX -XX -Xs"/> - <Item2 ID="931960419235" Targets="laz_synapse,BESENPkg,internettools,dcpcrypt" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks" Value="-O3 -g- -CX -XX -Xs"/> + <SharedMatrixOptions Count="1"> + <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-CX -Os4 -Xs -XX -g-"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> @@ -372,8 +371,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\BlogTruyen;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EatManga;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Fakku;..\baseunits\includes\Hentai2Read;..\baseunits\includes\HugeManga;..\baseunits\includes\Kivmanga;..\baseunits\includes\Komikid;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\Mabuns;..\baseunits\includes\Manga24h;..\baseunits\includes\MangaAe;..\baseunits\includes\MangaAr;..\baseunits\includes\Mangacow;..\baseunits\includes\MangaEden;..\baseunits\includes\MangaEsta;..\baseunits\includes\MangaFrame;..\baseunits\includes\MangaGo;..\baseunits\includes\MangaInn;..\baseunits\includes\MangaPark;..\baseunits\includes\MangaTraders;..\baseunits\includes\MangaVadisi;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\SenManga;..\baseunits\includes\Starkana;..\baseunits\includes\SubManga;..\baseunits\includes\TruyenTranhTuan;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\3rd\BESEN\src;..\3rd\internettools;..\3rd\internettools\data;..\3rd\internettools\internet;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From cfd07a6d4acab376ec42d87dba7e65d4d63f7c92 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 30 Jul 2017 07:20:32 +0800 Subject: [PATCH 1852/2794] fixed various path issue fixed #688 --- baseunits/uBaseUnit.pas | 8 ++++---- baseunits/uDownloadsManager.pas | 6 +++--- baseunits/uPacker.pas | 2 +- mangadownloader/forms/frmMain.pas | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 60bba9e7c..e7349eb25 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -933,7 +933,7 @@ function IsDirectoryEmpty(const ADir: String): Boolean; searchRec: TSearchRec; begin try - Result := (FindFirstUTF8(CleanAndExpandDirectory(ADir) + '*.*', + Result := (FindFirstUTF8(CorrectPathSys(ADir) + '*.*', faAnyFile{$ifdef unix} or faSymLink{$endif unix}, searchRec) = 0) and (FindNextUTF8(searchRec) = 0) and (FindNextUTF8(searchRec) <> 0); @@ -3330,7 +3330,7 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag Result := ''; if Stream = nil then Exit; if Stream.Size = 0 then Exit; - p := CleanAndExpandDirectory(Path); + p := CorrectPathSys(Path); if ForceDirectoriesUTF8(p) then begin f := GetImageStreamExt(Stream); if f = '' then Exit; @@ -3433,7 +3433,7 @@ function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; // Check to see if a file with similar name was already exist. If so then we // skip the download process. if Trim(URL) = 'D' then Exit(True); - s := CleanAndExpandDirectory(Path) + Name; + s := CorrectPathSys(Path) + Name; if ImageFileExist(s) then Exit(True); @@ -3676,7 +3676,7 @@ function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; con begin Result := False; if not DirectoryExistsUTF8(Directory) then Exit; - D := CleanAndExpandDirectory(Directory); + D := CorrectPathSys(Directory); AImgName1 := D + ImgName1; AImgName2 := D + ImgName2; if not (FileExistsUTF8(AImgName1) and FileExistsUTF8(AImgName2)) then Exit; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 1732f4571..46d602cef 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -799,7 +799,7 @@ procedure TTaskThread.Compress; end; uPacker.CompressionQuality := OptionPDFQuality; uPacker.Path := CurrentWorkingDir; - uPacker.FileName := RemovePathDelim(CorrectPathSys(AppendPathDelim(Container.DownloadInfo.SaveTo) + + uPacker.FileName := RemovePathDelim(CorrectPathSys(CorrectPathSys(Container.DownloadInfo.SaveTo) + Container.ChapterName[Container.CurrentDownloadChapterPtr])); for i := 0 to Container.PageLinks.Count - 1 do begin @@ -1106,8 +1106,8 @@ procedure TTaskThread.Execute; //check path if OptionGenerateChapterFolder then - CurrentWorkingDir := AppendPathDelim(Container.DownloadInfo.SaveTo) + - AppendPathDelim(Container.ChapterName[Container.CurrentDownloadChapterPtr]) + CurrentWorkingDir := CorrectPathSys(Container.DownloadInfo.SaveTo) + + Container.ChapterName[Container.CurrentDownloadChapterPtr] else CurrentWorkingDir := Container.DownloadInfo.SaveTo; if not ForceDirectoriesUTF8(CurrentWorkingDir) then diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 775bef597..979d13953 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -115,7 +115,7 @@ function TPacker.Execute: Boolean; i: Integer; begin Result := False; - Path := CleanAndExpandDirectory(Path); + Path := CorrectPathSys(Path); if FFileList.Count = 0 then begin diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e3a033bc2..2fee53a52 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1816,7 +1816,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); if (Sender = miDownloadDeleteTaskData) or (Sender = miDownloadDeleteTaskDataFavorite) and (ChapterName.Count > 0) then begin - d := CleanAndExpandDirectory(DownloadInfo.SaveTo); + d := CorrectPathSys(DownloadInfo.SaveTo); for i := 0 to ChapterName.Count - 1 do begin f := CorrectPathSys(d + ChapterName[i]); if DirectoryExistsUTF8(f) then @@ -3271,14 +3271,14 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then - OpenDocument(CleanAndExpandFilename( + OpenDocument(CorrectPathSys( FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo)); end; procedure TMainForm.miDownloadOpenFolderClick(Sender: TObject); begin if Assigned(vtDownload.FocusedNode) then - OpenDocument(CleanAndExpandFilename( + OpenDocument(CorrectPathSys( DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo.SaveTo)); end; From a3e20c784a1c167b9e6f9a6e46d6186e3b2e31b7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 30 Jul 2017 12:18:07 +0800 Subject: [PATCH 1853/2794] added compiler info in about and log --- baseunits/SimpleException/SimpleException.pas | 11 +- mangadownloader/forms/frmMain.lfm | 115 ++++++++++-------- mangadownloader/forms/frmMain.lrj | 14 +-- mangadownloader/forms/frmMain.pas | 35 +++++- mangadownloader/languages/fmd.en.po | 1 + mangadownloader/languages/fmd.id_ID.po | 1 + 6 files changed, 110 insertions(+), 67 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 02db6ed63..1e4c70de5 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -35,8 +35,7 @@ interface uses - Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, LCLVersion, - SimpleExceptionForm, + Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, SimpleExceptionForm, {$IFDEF WINDOWS} Windows, win32proc, {$ENDIF} @@ -117,6 +116,8 @@ procedure DoneSimpleExceptionHandler; implementation +uses InterfaceBase, LCLVersion{$IF FPC_FULLVERSION >= 30101}, LCLPlatformDef{$ENDIF}; + {$IFDEF MULTILOG} type @@ -535,9 +536,11 @@ constructor TSimpleException.Create(const FileName: String); 'Product Version : ' + AProductVersion + LineEnding; FApplicationInfo := FApplicationInfo + 'Host Machine : ' + GetOSVer + LineEnding + - 'Target CPU_OS : ' + {$i %FPCTARGETCPU%} +'_' + {$i %FPCTARGETOS%} +LineEnding + - 'FPC Version : ' + {$i %FPCVERSION%} +LineEnding + + 'FPC Version : ' + {$I %FPCVERSION%} + LineEnding + 'LCL Version : ' + LCLVersion.lcl_version + LineEnding + + 'WidgetSet : ' + LCLPlatformDirNames[WidgetSet.LCLPlatform] + LineEnding + + 'Target CPU-OS : ' + {$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%} + LineEnding + + 'Build Time : ' + {$I %DATE%} + ' ' + {$I %TIME%} + LineEnding + 'Path : ' + ParamStrUTF8(0) + LineEnding + 'Process ID : ' + IntToStr(GetProcessID) + LineEnding + 'MainThread ID : ' + IntToStr(MainThreadID); diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f37246285..7aee18661 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4084,12 +4084,12 @@ object MainForm: TMainForm object tsWebsiteOptions: TTabSheet Caption = 'Options' ClientHeight = 348 - ClientWidth = 515 + ClientWidth = 737 object sbWebsiteOptions: TScrollBox Left = 0 Height = 348 Top = 0 - Width = 515 + Width = 737 HorzScrollBar.Increment = 1 HorzScrollBar.Page = 1 HorzScrollBar.Smooth = True @@ -4530,7 +4530,6 @@ object MainForm: TMainForm TabOrder = 2 object tsAboutText: TTabSheet Caption = 'About FMD' - ChildSizing.TopBottomSpacing = 4 ClientHeight = 404 ClientWidth = 753 object rmAbout: TRichMemo @@ -4539,6 +4538,8 @@ object MainForm: TMainForm Top = 4 Width = 753 Align = alClient + BorderSpacing.Top = 4 + BorderSpacing.Bottom = 4 Color = clWhite Font.Style = [fsBold] HideSelection = False @@ -4548,10 +4549,22 @@ object MainForm: TMainForm TabOrder = 0 ZoomFactor = 1 end + object pnAboutComp: TPanel + Left = 0 + Height = 0 + Top = 404 + Width = 753 + Align = alBottom + AutoSize = True + BevelOuter = bvNone + ChildSizing.HorizontalSpacing = 8 + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 2 + TabOrder = 1 + end end object tsChangelogText: TTabSheet Caption = 'Changelog' - ChildSizing.TopBottomSpacing = 4 ClientHeight = 404 ClientWidth = 753 object mmChangelog: TMemo @@ -4560,6 +4573,8 @@ object MainForm: TMainForm Top = 4 Width = 753 Align = alClient + BorderSpacing.Top = 4 + BorderSpacing.Bottom = 4 Font.CharSet = ANSI_CHARSET Font.Height = -12 Font.Name = 'Courier New' @@ -4606,14 +4621,14 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - left = 80 - top = 408 + Left = 96 + Top = 251 end object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - left = 592 - top = 184 + Left = 592 + Top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -4943,8 +4958,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - left = 592 - top = 224 + Left = 592 + Top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -5002,8 +5017,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - left = 520 - top = 212 + Left = 520 + Top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -5321,8 +5336,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - left = 382 - top = 238 + Left = 382 + Top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5468,13 +5483,13 @@ object MainForm: TMainForm PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - left = 288 - top = 432 + Left = 288 + Top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False - left = 382 - top = 110 + Left = 382 + Top = 110 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5496,8 +5511,8 @@ object MainForm: TMainForm end end object IconList: TImageList - left = 278 - top = 102 + Left = 278 + Top = 102 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6239,8 +6254,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - left = 278 - top = 150 + Left = 278 + Top = 150 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6536,8 +6551,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - left = 328 - top = 238 + Left = 328 + Top = 238 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6831,8 +6846,8 @@ object MainForm: TMainForm } end object IconSmall: TImageList - left = 27 - top = 328 + Left = 27 + Top = 328 Bitmap = { 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6935,8 +6950,8 @@ object MainForm: TMainForm end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup - left = 592 - top = 136 + Left = 592 + Top = 136 object medURLUndo: TMenuItem Caption = 'Undo' OnClick = medURLUndoClick @@ -6975,38 +6990,38 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - left = 80 - top = 448 + Left = 96 + Top = 312 end object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - left = 560 - top = 472 + Left = 560 + Top = 472 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - left = 504 - top = 120 + Left = 504 + Top = 120 end object TransferRateToolset: TChartToolset - left = 464 - top = 120 + Left = 464 + Top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - left = 152 - top = 376 + Left = 152 + Top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick end end object pmFilterGenreAll: TPopupMenu - left = 520 - top = 168 + Left = 520 + Top = 168 object mnFilterGenreAllCheck: TMenuItem Caption = 'Check all' OnClick = mnFilterGenreAllCheckClick @@ -7022,8 +7037,8 @@ object MainForm: TMainForm end object pmTray: TPopupMenu OnPopup = pmTrayPopup - left = 341 - top = 432 + Left = 341 + Top = 432 object miTrayResumeAll: TMenuItem Caption = 'Resume all' OnClick = tbDownloadResumeAllClick @@ -7087,28 +7102,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - left = 656 - top = 416 + Left = 656 + Top = 416 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - left = 440 - top = 472 + Left = 440 + Top = 472 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - left = 656 - top = 472 + Left = 656 + Top = 472 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - left = 480 - top = 472 + Left = 480 + Top = 472 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index f67155a24..a350a41c8 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -50,13 +50,13 @@ {"hash":84262158,"name":"tmainform.cbuseregexpr.caption","sourcebytes":[82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110],"value":"Regular Expression"}, {"hash":111905342,"name":"tmainform.ckfilteraction.hint","sourcebytes":[65,32,119,111,114,107,32,116,121,112,105,99,97,108,108,121,32,100,101,112,105,99,116,105,110,103,32,102,105,103,104,116,105,110,103,44,32,118,105,111,108,101,110,99,101,44,32,99,104,97,111,115,44,32,97,110,100,32,102,97,115,116,32,112,97,99,101,100,32,109,111,116,105,111,110,46],"value":"A work typically depicting fighting, violence, chaos, and fast paced motion."}, {"hash":75149406,"name":"tmainform.ckfilteraction.caption","sourcebytes":[65,99,116,105,111,110],"value":"Action"}, -{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and\/or graphic sexual content and nudity."}, +{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity."}, {"hash":4701236,"name":"tmainform.ckfilteradult.caption","sourcebytes":[65,100,117,108,116],"value":"Adult"}, {"hash":267284606,"name":"tmainform.ckfilteradventure.hint","sourcebytes":[73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,111,114,121,32,103,111,101,115,32,111,110,32,97,32,116,114,105,112,32,111,114,32,97,108,111,110,103,32,116,104,97,116,32,108,105,110,101,44,32,121,111,117,114,32,98,101,115,116,32,98,101,116,32,105,115,32,116,104,97,116,32,105,116,32,105,115,32,97,110,32,97,100,118,101,110,116,117,114,101,32,109,97,110,103,97,46,32,79,116,104,101,114,119,105,115,101,44,32,105,116,39,115,32,117,112,32,116,111,32,121,111,117,114,32,112,101,114,115,111,110,97,108,32,112,114,101,106,117,100,105,99,101,32,111,110,32,116,104,105,115,32,99,97,115,101,46],"value":"If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case."}, {"hash":214301493,"name":"tmainform.ckfilteradventure.caption","sourcebytes":[65,100,118,101,110,116,117,114,101],"value":"Adventure"}, {"hash":11846766,"name":"tmainform.ckfiltercomedy.hint","sourcebytes":[65,32,100,114,97,109,97,116,105,99,32,119,111,114,107,32,116,104,97,116,32,105,115,32,108,105,103,104,116,32,97,110,100,32,111,102,116,101,110,32,104,117,109,111,114,111,117,115,32,111,114,32,115,97,116,105,114,105,99,97,108,32,105,110,32,116,111,110,101,32,97,110,100,32,116,104,97,116,32,117,115,117,97,108,108,121,32,99,111,110,116,97,105,110,115,32,97,32,104,97,112,112,121,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,104,101,109,97,116,105,99,32,99,111,110,102,108,105,99,116,46],"value":"A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict."}, {"hash":78003129,"name":"tmainform.ckfiltercomedy.caption","sourcebytes":[67,111,109,101,100,121],"value":"Comedy"}, -{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga\/anime."}, +{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga/anime."}, {"hash":202379913,"name":"tmainform.ckfilterdoujinshi.caption","sourcebytes":[68,111,117,106,105,110,115,104,105],"value":"Doujinshi"}, {"hash":221112350,"name":"tmainform.ckfilterdrama.hint","sourcebytes":[65,32,119,111,114,107,32,109,101,97,110,116,32,116,111,32,98,114,105,110,103,32,111,110,32,97,110,32,101,109,111,116,105,111,110,97,108,32,114,101,115,112,111,110,115,101,44,32,115,117,99,104,32,97,115,32,105,110,115,116,105,108,108,105,110,103,32,115,97,100,110,101,115,115,32,111,114,32,116,101,110,115,105,111,110,46],"value":"A work meant to bring on an emotional response, such as instilling sadness or tension."}, {"hash":4950065,"name":"tmainform.ckfilterdrama.caption","sourcebytes":[68,114,97,109,97],"value":"Drama"}, @@ -80,7 +80,7 @@ {"hash":56818190,"name":"tmainform.ckfilterlolicon.caption","sourcebytes":[76,111,108,105,99,111,110],"value":"Lolicon"}, {"hash":104001182,"name":"tmainform.ckfiltermartialarts.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,109,97,114,116,105,97,108,32,97,114,116,115,32,114,101,108,97,116,101,100,46,32,65,110,121,32,111,102,32,115,101,118,101,114,97,108,32,97,114,116,115,32,111,102,32,99,111,109,98,97,116,32,111,114,32,115,101,108,102,45,100,101,102,101,110,115,101,44,32,115,117,99,104,32,97,115,32,97,105,107,105,100,111,44,32,107,97,114,97,116,101,44,32,106,117,100,111,44,32,111,114,32,116,97,101,107,119,111,110,100,111,44,32,107,101,110,100,111,44,32,102,101,110,99,105,110,103,44,32,97,110,100,32,115,111,32,111,110,32,97,110,100,32,115,111,32,102,111,114,116,104,46],"value":"As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth."}, {"hash":47977283,"name":"tmainform.ckfiltermartialarts.caption","sourcebytes":[77,97,114,116,105,97,108,32,65,114,116,115],"value":"Martial Arts"}, -{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and\/or strong language."}, +{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language."}, {"hash":87604357,"name":"tmainform.ckfiltermature.caption","sourcebytes":[77,97,116,117,114,101],"value":"Mature"}, {"hash":187133582,"name":"tmainform.ckfiltermecha.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,118,111,108,118,105,110,103,32,97,110,100,32,117,115,117,97,108,108,121,32,99,111,110,99,101,110,116,114,97,116,105,110,103,32,111,110,32,97,108,108,32,116,121,112,101,115,32,111,102,32,108,97,114,103,101,32,114,111,98,111,116,105,99,32,109,97,99,104,105,110,101,115,46],"value":"A work involving and usually concentrating on all types of large robotic machines."}, {"hash":5487073,"name":"tmainform.ckfiltermecha.caption","sourcebytes":[77,101,99,104,97],"value":"Mecha"}, @@ -104,11 +104,11 @@ {"hash":94333967,"name":"tmainform.ckfiltershoujo.caption","sourcebytes":[83,104,111,117,106,111],"value":"Shoujo"}, {"hash":171132846,"name":"tmainform.ckfiltershoujoai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,117,114,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,71,105,114,108,39,39,115,32,76,111,118,101,34,44,32,115,111,32,116,111,32,115,112,101,97,107,46],"value":"Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak."}, {"hash":113331593,"name":"tmainform.ckfiltershoujoai.caption","sourcebytes":[83,104,111,117,106,111,32,65,105],"value":"Shoujo Ai"}, -{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and\/or violence."}, +{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and/or violence."}, {"hash":167167214,"name":"tmainform.ckfiltershounen.caption","sourcebytes":[83,104,111,117,110,101,110],"value":"Shounen"}, {"hash":19597467,"name":"tmainform.ckfiltershounenai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,97,111,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,66,111,121,39,39,115,32,76,111,118,101,34,194,157,44,32,115,111,32,116,111,32,115,112,101,97,107],"value":"Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\"\u009D, so to speak"}, {"hash":206543641,"name":"tmainform.ckfiltershounenai.caption","sourcebytes":[83,104,111,117,110,101,110,32,65,105],"value":"Shounen Ai"}, -{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one\/many character(s). These challenges\/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, +{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, {"hash":262977669,"name":"tmainform.ckfiltersliceoflife.caption","sourcebytes":[83,108,105,99,101,32,111,102,32,76,105,102,101],"value":"Slice of Life"}, {"hash":68245006,"name":"tmainform.ckfiltersmut.hint","sourcebytes":[68,101,97,108,115,32,119,105,116,104,32,115,101,114,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,112,114,111,102,97,110,101,32,111,114,32,111,102,102,101,110,115,105,118,101,44,32,112,97,114,116,105,99,117,108,97,114,108,121,32,119,105,116,104,32,114,101,103,97,114,100,115,32,116,111,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,46],"value":"Deals with series that are considered profane or offensive, particularly with regards to sexual content."}, {"hash":369860,"name":"tmainform.ckfiltersmut.caption","sourcebytes":[83,109,117,116],"value":"Smut"}, @@ -165,7 +165,7 @@ {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, {"hash":325284,"name":"tmainform.lboptionhost.caption","sourcebytes":[72,111,115,116],"value":"Host"}, -{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host\/IP"}, +{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host/IP"}, {"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, {"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, @@ -220,7 +220,7 @@ {"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, {"hash":263412434,"name":"tmainform.gbdialogs.caption","sourcebytes":[83,104,111,119,32,100,105,97,108,111,103,32,99,111,110,102,105,114,109,97,116,105,111,110,32,102,111,114],"value":"Show dialog confirmation for"}, {"hash":252071892,"name":"tmainform.cboptionshowquitdialog.caption","sourcebytes":[69,120,105,116,32,70,77,68],"value":"Exit FMD"}, -{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task\/favorite"}, +{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task/favorite"}, {"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, {"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, {"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2fee53a52..141a1b0e0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,10 +22,9 @@ interface MultiLog, FileChannel, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, - frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, - frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, CheckUpdate, - accountmanagerdb, DBDataProcess, MangaFoxWatermark, SimpleTranslator, - FMDOptions, httpsendthread, SimpleException; + frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, frmWebsiteOptionAdvanced, + frmCustomColor, frmLogger, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, + SimpleTranslator, FMDOptions, httpsendthread, SimpleException; type @@ -116,6 +115,7 @@ TMainForm = class(TForm) miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; + pnAboutComp: TPanel; pcInfo: TPageControl; psInfo: TPairSplitter; pssInfoList: TPairSplitterSide; @@ -867,7 +867,8 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, - FMDVars, RegExpr, Clipbrd, LazFileUtils, LazUTF8; + FMDVars, RegExpr, Clipbrd, InterfaceBase, LazFileUtils, + LazUTF8{$IF FPC_FULLVERSION >= 30101}, LCLPlatformDef{$ENDIF}; var // thread for open db @@ -1969,6 +1970,21 @@ procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); end; procedure TMainForm.LoadAbout; + + procedure addaboutcomp(const ACaption, AValue: String); + + function addaboutcomplbl(const ACaption: String): TLabel; + begin + Result := TLabel.Create(Self); + Result.Parent := pnAboutComp; + Result.Caption := ACaption; + end; + + begin + addaboutcomplbl(ACaption); + addaboutcomplbl(AValue).Font.Style := [fsBold]; + end; + var i: Integer; fs: TFileStreamUTF8; @@ -2006,7 +2022,14 @@ procedure TMainForm.LoadAbout; end; end; // load changelog.txt - if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); + if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); + + // compiler info + addaboutcomp('FPC Version', {$I %FPCVERSION%}); + addaboutcomp('LCL Version', LCLVersion); + addaboutcomp('WidgetSet', LCLPlatformDirNames[WidgetSet.LCLPlatform]); + addaboutcomp('Target CPU-OS', {$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%}); + addaboutcomp('Build Time', {$I %DATE%} + ' ' + {$I %TIME%}); end; procedure TMainForm.GeneratetvDownloadFilterNodes; diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8c4777d5b..9ee27b5d5 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -2244,3 +2244,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1dfd01a2c..1dc1aee43 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -2223,3 +2223,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + From b2aa947664e3274e84cabc8ba7fc854a7dd6c8df Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 00:31:02 +0800 Subject: [PATCH 1854/2794] changed about info layout to 1 line --- mangadownloader/forms/frmMain.lfm | 4 ++-- mangadownloader/forms/frmMain.pas | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 7aee18661..6e2f75ba0 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4557,9 +4557,9 @@ object MainForm: TMainForm Align = alBottom AutoSize = True BevelOuter = bvNone - ChildSizing.HorizontalSpacing = 8 + ChildSizing.HorizontalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 2 + ChildSizing.ControlsPerLine = 10 TabOrder = 1 end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 141a1b0e0..bf92c7f22 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1981,8 +1981,12 @@ procedure TMainForm.LoadAbout; end; begin - addaboutcomplbl(ACaption); - addaboutcomplbl(AValue).Font.Style := [fsBold]; + addaboutcomplbl(ACaption + ':'); + with addaboutcomplbl(AValue) do + begin + Font.Style := [fsBold]; + BorderSpacing.Right := 16; + end; end; var From b16a7510c0bb4d76f57e2ea2233eff67b1c14f98 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 02:36:55 +0800 Subject: [PATCH 1855/2794] moved build info to simpleexception --- baseunits/SimpleException/SimpleException.pas | 154 ++++++++++++------ mangadownloader/forms/frmMain.pas | 13 +- 2 files changed, 107 insertions(+), 60 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 1e4c70de5..32a99c293 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -91,6 +91,13 @@ TSimpleException = class destructor Destroy; override; end; +function GetOSVer: String; +function GetFPCVersion: String; +function GetLCLVersion: String; +function GetWidgetSetName: String; +function GetTargetCPU_OS: String; +function GetBuildTime: String; + function GetApplicationInfo: String; function AddIgnoredException(const EClassName: String): Boolean; function RemoveIgnoredClass(const EClassName: String): Boolean; @@ -143,6 +150,95 @@ procedure SetMaxStackCount(const ACount: Integer); MainExceptionHandler.MaxStackCount := ACount; end; +function GetOSVer: String; +{$IFDEF WINDOWS} +var + wdir: array [0..MAX_PATH] of Char; + + function WinLater: String; + begin + if (Win32MajorVersion = 6) and (Win32MinorVersion = 3) then + Result := 'Windows 8.1' + else if (Win32MajorVersion = 10) and (Win32MinorVersion = 0) then + Result := 'Windows 10' + else + Result := Format('Windows %d.%d', [Win32MajorVersion, Win32MinorVersion]); + end; + +{$ENDIF} +begin + {$IFDEF LCLcarbon} + Result := 'Mac OS X 10.'; + {$ENDIF} + {$IFDEF Linux} + Result := 'Linux Kernel '; + {$ENDIF} + {$IFDEF UNIX} + Result := 'Unix '; + {$ENDIF} + {$IFDEF WINDOWS} + case WindowsVersion of + wv95: Result := 'Windows 95'; + wvNT4: Result := 'Windows NT v.4'; + wv98: Result := 'Windows 98'; + wvMe: Result := 'Windows ME'; + wv2000: Result := 'Windows 2000'; + wvXP: Result := 'Windows XP'; + wvServer2003: Result := 'Windows Server 2003'; + wvVista: Result := 'Windows Vista'; + wv7: Result := 'Windows 7'; + wv8: Result := 'Windows 8'; + else + Result := WinLater; + end; + FillChar({%H-}wdir, SizeOf(wdir), 0); + GetWindowsDirectory(PChar(wdir), MAX_PATH); + if DirectoryExists(wdir + '\SysWOW64') then + Result := Result + ' 64-bit'; + {$ENDIF} +end; + +function GetFPCVersion: String; +begin + Result := {$I %FPCVERSION%}; +end; + +function GetLCLVersion: String; +begin + Result := LCLVersion.lcl_version; +end; + +function GetWidgetSetName: String; +begin + case WidgetSet.LCLPlatform of + lpGtk : Result := 'GTK'; + lpGtk2 : Result := 'GTK2'; + lpGtk3 : Result := 'GTK3'; + lpWin32 : Result := 'Win32/Win64'; + lpWinCE : Result := 'WinCE'; + lpCarbon : Result := 'Carbon'; + lpQT : Result := 'Qt'; + lpfpGUI : Result := 'fpGUI'; + lpNoGUI : Result := 'NoGUI'; + lpCocoa : Result := 'Cocoa'; + lpCustomDrawn : Result := 'Custom Drawn'; + {$IF FPC_FULLVERSION >= 30101} + lpQt5 : Result := 'Qt5'; + lpMUI : Result := 'MUI'; + {$ENDIF} + end; +end; + +function GetTargetCPU_OS: String; +begin + Result := {$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%}; +end; + +function GetBuildTime: String; +begin + Result := {$I %DATE%} + ' ' + {$I %TIME%}; +end; + function GetApplicationInfo: String; begin Result := ''; @@ -233,54 +329,6 @@ procedure TSimpleException.SetLogFileName(const AValue: String); FLogFileName := AValue; end; -function GetOSVer: String; -{$IFDEF WINDOWS} -var - wdir: array [0..MAX_PATH] of Char; - - function WinLater: String; - begin - if (Win32MajorVersion = 6) and (Win32MinorVersion = 3) then - Result := 'Windows 8.1' - else if (Win32MajorVersion = 10) and (Win32MinorVersion = 0) then - Result := 'Windows 10' - else - Result := Format('Windows %d.%d', [Win32MajorVersion, Win32MinorVersion]); - end; - -{$ENDIF} -begin - {$IFDEF LCLcarbon} - Result := 'Mac OS X 10.'; - {$ENDIF} - {$IFDEF Linux} - Result := 'Linux Kernel '; - {$ENDIF} - {$IFDEF UNIX} - Result := 'Unix '; - {$ENDIF} - {$IFDEF WINDOWS} - case WindowsVersion of - wv95: Result := 'Windows 95'; - wvNT4: Result := 'Windows NT v.4'; - wv98: Result := 'Windows 98'; - wvMe: Result := 'Windows ME'; - wv2000: Result := 'Windows 2000'; - wvXP: Result := 'Windows XP'; - wvServer2003: Result := 'Windows Server 2003'; - wvVista: Result := 'Windows Vista'; - wv7: Result := 'Windows 7'; - wv8: Result := 'Windows 8'; - else - Result := WinLater; - end; - FillChar({%H-}wdir, SizeOf(wdir), 0); - GetWindowsDirectory(PChar(wdir), MAX_PATH); - if DirectoryExists(wdir + '\SysWOW64') then - Result := Result + ' 64-bit'; - {$ENDIF} -end; - procedure TSimpleException.ExceptionHandler; begin if Assigned(FLastException) then @@ -536,11 +584,11 @@ constructor TSimpleException.Create(const FileName: String); 'Product Version : ' + AProductVersion + LineEnding; FApplicationInfo := FApplicationInfo + 'Host Machine : ' + GetOSVer + LineEnding + - 'FPC Version : ' + {$I %FPCVERSION%} + LineEnding + - 'LCL Version : ' + LCLVersion.lcl_version + LineEnding + - 'WidgetSet : ' + LCLPlatformDirNames[WidgetSet.LCLPlatform] + LineEnding + - 'Target CPU-OS : ' + {$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%} + LineEnding + - 'Build Time : ' + {$I %DATE%} + ' ' + {$I %TIME%} + LineEnding + + 'FPC Version : ' + GetFPCVersion + LineEnding + + 'LCL Version : ' + GetLCLVersion + LineEnding + + 'WidgetSet : ' + GetWidgetSetName + LineEnding + + 'Target CPU-OS : ' + GetTargetCPU_OS + LineEnding + + 'Build Time : ' + GetBuildTime + LineEnding + 'Path : ' + ParamStrUTF8(0) + LineEnding + 'Process ID : ' + IntToStr(GetProcessID) + LineEnding + 'MainThread ID : ' + IntToStr(MainThreadID); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bf92c7f22..324f3f5dd 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -867,8 +867,7 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, - FMDVars, RegExpr, Clipbrd, InterfaceBase, LazFileUtils, - LazUTF8{$IF FPC_FULLVERSION >= 30101}, LCLPlatformDef{$ENDIF}; + FMDVars, RegExpr, Clipbrd, LazFileUtils, LazUTF8; var // thread for open db @@ -2029,11 +2028,11 @@ procedure TMainForm.LoadAbout; if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); // compiler info - addaboutcomp('FPC Version', {$I %FPCVERSION%}); - addaboutcomp('LCL Version', LCLVersion); - addaboutcomp('WidgetSet', LCLPlatformDirNames[WidgetSet.LCLPlatform]); - addaboutcomp('Target CPU-OS', {$I %FPCTARGETCPU%} + '-' + {$I %FPCTARGETOS%}); - addaboutcomp('Build Time', {$I %DATE%} + ' ' + {$I %TIME%}); + addaboutcomp('FPC Version', GetFPCVersion); + addaboutcomp('LCL Version', GetLCLVersion); + addaboutcomp('WidgetSet', GetWidgetSetName); + addaboutcomp('Target CPU-OS', GetTargetCPU_OS); + addaboutcomp('Build Time', GetBuildTime); end; procedure TMainForm.GeneratetvDownloadFilterNodes; From dd749aa8b4ec631cdc247da2c9d04b490023e71e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 16:55:19 +0800 Subject: [PATCH 1856/2794] changed submodules shallow true --- .gitmodules | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitmodules b/.gitmodules index 48a34d132..f5e264382 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,7 +2,9 @@ path = 3rd/BESEN url = https://github.com/BeRo1985/besen.git ignore = dirty + shallow = true [submodule "3rd/internettools"] path = 3rd/internettools url = https://github.com/benibela/internettools ignore = dirty + shallow = true From 368651931e94602a8b620ca8f7edbc7e0d3c306a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 16:56:03 +0800 Subject: [PATCH 1857/2794] besen, changed compiler options --- 3rd/BESENPkg.lpk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk index b6a92340f..762fd4398 100644 --- a/3rd/BESENPkg.lpk +++ b/3rd/BESENPkg.lpk @@ -12,7 +12,7 @@ <UnitOutputDirectory Value="BESEN\lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Other> - <CustomOptions Value="-CX -Os4 -Xs -XX -g-"/> + <CustomOptions Value="-CX -O3 -Xs -XX -g-"/> </Other> </CompilerOptions> <Files Count="97"> From eba71bb90750ffca400eee02ac6775051411cb38 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 16:57:11 +0800 Subject: [PATCH 1858/2794] internettools, added package without flre --- 3rd/internettools.lpk | 135 ++++++++++++++++++++++++++++++++++++++++++ 3rd/internettools.pas | 22 +++++++ 2 files changed, 157 insertions(+) create mode 100644 3rd/internettools.lpk create mode 100644 3rd/internettools.pas diff --git a/3rd/internettools.lpk b/3rd/internettools.lpk new file mode 100644 index 000000000..89bebeba8 --- /dev/null +++ b/3rd/internettools.lpk @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <Package Version="4"> + <Name Value="internettools"/> + <Type Value="RunAndDesignTime"/> + <CompilerOptions> + <Version Value="11"/> + <SearchPaths> + <IncludeFiles Value="internettools/data;internettools/lazarus/dialogs;internettools/import/synapse"/> + <OtherUnitFiles Value="internettools/data;internettools/internet;internettools/import/regexpr/source;internettools/lazarus/dialogs;internettools/import/synapse;internettools/system;internettools/import/flre/src"/> + <UnitOutputDirectory Value="internettools/lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Other> + <CustomOptions Value="-CX -O3 -Xs -XX -g- +-uUSE_FLRE_WITH_CACHE +-uUSE_BBFLRE_UNICODE +-dUSE_SOROKINS_REGEX +-dUSE_BBFULL_UNICODE"/> + </Other> + </CompilerOptions> + <Files Count="25"> + <Item1> + <Filename Value="internettools/data/bbutils.pas"/> + <UnitName Value="bbutils"/> + </Item1> + <Item2> + <Filename Value="internettools/data/extendedhtmlparser.pas"/> + <UnitName Value="extendedhtmlparser"/> + </Item2> + <Item3> + <Filename Value="internettools/internet/simpleinternet.pas"/> + <UnitName Value="simpleinternet"/> + </Item3> + <Item4> + <Filename Value="internettools/internet/internetaccess.pas"/> + <UnitName Value="internetaccess"/> + </Item4> + <Item5> + <Filename Value="internettools/data/disableRangeOverflowChecks.inc"/> + <Type Value="Include"/> + </Item5> + <Item6> + <Filename Value="internettools/data/simplehtmlparser.pas"/> + <UnitName Value="simplehtmlparser"/> + </Item6> + <Item7> + <Filename Value="internettools/data/simplehtmltreeparser.pas"/> + <UnitName Value="simplehtmltreeparser"/> + </Item7> + <Item8> + <Filename Value="internettools/data/simplexmlparser.pas"/> + <UnitName Value="simplexmlparser"/> + </Item8> + <Item9> + <Filename Value="internettools/data/restoreRangeOverflowChecks.inc"/> + <Type Value="Include"/> + </Item9> + <Item10> + <Filename Value="internettools/data/xquery.pas"/> + <UnitName Value="xquery"/> + </Item10> + <Item11> + <Filename Value="internettools/data/xquery_functions_generated.inc"/> + <Type Value="Include"/> + </Item11> + <Item12> + <Filename Value="internettools/data/xquery_functions_generated_template.inc"/> + <Type Value="Include"/> + </Item12> + <Item13> + <Filename Value="internettools/data/xquery_terms.inc"/> + <Type Value="Include"/> + </Item13> + <Item14> + <Filename Value="internettools/data/xquery_types.inc"/> + <Type Value="Include"/> + </Item14> + <Item15> + <Filename Value="internettools/internet/synapseinternetaccess.pas"/> + <UnitName Value="synapseinternetaccess"/> + </Item15> + <Item16> + <Filename Value="internettools/internet/w32internetaccess.pas"/> + <UnitName Value="w32internetaccess"/> + </Item16> + <Item17> + <Filename Value="internettools/data/simplexmltreeparserfpdom.pas"/> + <UnitName Value="simplexmltreeparserfpdom"/> + </Item17> + <Item18> + <Filename Value="internettools/data/xquery_json.pas"/> + <UnitName Value="xquery_json"/> + </Item18> + <Item19> + <Filename Value="internettools/internet/mockinternetaccess.pas"/> + <UnitName Value="mockinternetaccess"/> + </Item19> + <Item20> + <Filename Value="internettools/data/xquery_schemas.inc"/> + <Type Value="Include"/> + </Item20> + <Item21> + <Filename Value="internettools/data/xquery__regex.pas"/> + <UnitName Value="xquery__regex"/> + </Item21> + <Item22> + <Filename Value="internettools/data/xquery__parse.pas"/> + <UnitName Value="xquery__parse"/> + </Item22> + <Item23> + <Filename Value="internettools/data/xquery_module_math.pas"/> + <UnitName Value="xquery_module_math"/> + </Item23> + <Item24> + <Filename Value="internettools/data/xquery__functions.pas"/> + <UnitName Value="xquery__functions"/> + </Item24> + <Item25> + <Filename Value="internettools/internettoolsconfig.inc"/> + <Type Value="Binary"/> + </Item25> + </Files> + <RequiredPkgs Count="1"> + <Item1> + <PackageName Value="FCL"/> + </Item1> + </RequiredPkgs> + <UsageOptions> + <UnitPath Value="$(PkgOutDir)"/> + </UsageOptions> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + </Package> +</CONFIG> diff --git a/3rd/internettools.pas b/3rd/internettools.pas new file mode 100644 index 000000000..65f7cbce1 --- /dev/null +++ b/3rd/internettools.pas @@ -0,0 +1,22 @@ +{ This file was automatically created by Lazarus. Do not edit! + This source is only used to compile and install the package. + } + +unit internettools; + +interface + +uses + bbutils, extendedhtmlparser, simpleinternet, internetaccess, simplehtmlparser, simplehtmltreeparser, simplexmlparser, xquery, + synapseinternetaccess, w32internetaccess, simplexmltreeparserfpdom, xquery_json, mockinternetaccess, xquery__regex, xquery__parse, + xquery_module_math, xquery__functions, LazarusPackageIntf; + +implementation + +procedure Register; +begin +end; + +initialization + RegisterPackage('internettools', @Register); +end. From b1a4238eaa6ce61e172f97bd6483c2da01b364fa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 17:00:23 +0800 Subject: [PATCH 1859/2794] updated project options changed internettools package without flre changed custom options to use -O3 --- mangadownloader/md.lpi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index fca934fab..8444c36f9 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -221,7 +221,7 @@ </CompilerOptions> </Item5> <SharedMatrixOptions Count="1"> - <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-CX -Os4 -Xs -XX -g-"/> + <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-CX -O3 -Xs -XX -g-"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> @@ -252,7 +252,7 @@ </Item4> <Item5> <PackageName Value="internettools"/> - <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> + <DefaultFilename Value="..\3rd\internettools.lpk" Prefer="True"/> </Item5> <Item6> <PackageName Value="TAChartLazarusPkg"/> From 5d9a92bb72eb3f267095becf583ee8b5ad49d217 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 17:01:14 +0800 Subject: [PATCH 1860/2794] tumangaonline, fixed get manhwa fixed #690 --- baseunits/modules/Tumangaonline.pas | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 638178618..01d4b8cf5 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -83,7 +83,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := FillHost(Module.RootURL, AURL); - mangaid := RegExprGetMatch('/mangas/(\d+)/', url, 1); + mangaid := RegExprGetMatch('/\w+/(\d+)/\w+', url, 1); if mangaid = '' then Exit; if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + apiurlmangas + '/' + mangaid) then begin @@ -93,11 +93,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; coverLink := XPathString('json(*).imageUrl'); if coverLink <> '' then coverLink := MaybeFillHost(imgurl, coverLink); if title = '' then title := XPathString('json(*).nombre'); - s := XPathString('json(*).estado'); - if Pos('Activo', s) <> 0 then - status := '1' - else if Pos('Finalizado', s) <> 0 then - status := '0'; + status := MangaInfoStatusIfPos(XPathString('json(*).estado'), 'Activo', 'Finalizado'); summary := XPathString('json(*).info.sinopsis'); genres := XPathStringAll('json(*).generos().genero'); AddCommaString(genres, XPathStringAll('json(*).categorias().categoria')); From 9a3c93efde1f11495692e0119de59dabe29ef00c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 17:19:40 +0800 Subject: [PATCH 1861/2794] added build mode win64 debug leaks --- mangadownloader/md.lpi | 55 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8444c36f9..f7fb42bd8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -9,10 +9,6 @@ <Title Value="Free Manga Downloader"/> <ResourceType Value="res"/> <UseXPManifest Value="True"/> - <XPManifest> - <TextName Value="fmd.free"/> - <TextDesc Value="Free Manga Downloader"/> - </XPManifest> <Icon Value="0"/> </General> <i18n> @@ -26,7 +22,7 @@ <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> - <BuildModes Count="5"> + <BuildModes Count="6"> <Item1 Name="Win32" Default="True"/> <Item2 Name="Win64"> <CompilerOptions> @@ -220,6 +216,55 @@ </Other> </CompilerOptions> </Item5> + <Item6 Name="Win64 Debug Leaks"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\bin\fmd"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + <Optimizations> + <VariablesInRegisters Value="True"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + <UseHeaptrc Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + </Linking> + <Other> + <CustomOptions Value="-dMANGADOWNLOADER +-dDOWNLOADER +-dSELFUPDATE +-dDEBUGLEAKS +-dMULTILOG"/> + <ExecuteAfter> + <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> + </ExecuteAfter> + </Other> + </CompilerOptions> + </Item6> <SharedMatrixOptions Count="1"> <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-CX -O3 -Xs -XX -g-"/> </SharedMatrixOptions> From 3ad9d18f5269a8b7879a275ed55752f08b66b018 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 31 Jul 2017 17:30:07 +0800 Subject: [PATCH 1862/2794] mangainn, changed domain and fixed info fixed #691 --- baseunits/modules/MangaInn.pas | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas index e75c7a5f0..56d3d0942 100644 --- a/baseunits/modules/MangaInn.pas +++ b/baseunits/modules/MangaInn.pas @@ -50,13 +50,10 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@itemprop="image"]/@src')); - if title = '' then - begin - title := XPathString('//title'); - if Pos(' - Read ', title) <> 0 then - title := Trim(GetBetween(' - Read ', ' Online For Free', title)); - end; + coverLink := XPathString('//img[@itemprop="image"]/resolve-uri(@src)'); + title := XPathString('//title'); + if Pos(' - Read ', title) <> 0 then + title := Trim(GetBetween(' - Read ', ' Online For Free', title)); status := MangaInfoStatusIfPos( XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Status")]/following-sibling::*[1]'), 'Ongoing', @@ -65,10 +62,10 @@ function GetInfo(const MangaInfo: TMangaInformation; artists := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Artist(s)")]/following-sibling::*[1]'); genres := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Genre(s)")]/following-sibling::*[1]'); summary := Trim(XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Summary")]/following-sibling::*')); - for v in XPath('//tr/td[1]/span/a') do + for v in XPath('//div[@class="content"]/div[@class="divThickBorder"][3]/table//td[1]/span/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); + chapterName.Add(Trim(title + ' : ' + XPathString('./text()', v))); end; finally Free; @@ -130,7 +127,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaInn'; - RootURL := 'http://www.mangainn.me'; + RootURL := 'http://www.mangainn.net'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From f2c25b7eecd88aa736e231e3e36f19526ce7298b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 1 Aug 2017 22:03:24 +0800 Subject: [PATCH 1863/2794] set all timeout, partially revert 2dd9710103abe521205a72c414dbc6d25c0acbeb --- baseunits/httpsendthread.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 0be0590ea..1dca3e4e6 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -323,6 +323,7 @@ procedure THTTPSendThread.SetTimeout(AValue: Integer); begin if FTimeout = AValue then Exit; FTimeout := AValue; + Sock.ConnectionTimeout := FTimeout; Sock.SocksTimeout := FTimeout; Sock.SetTimeout(FTimeout); end; From 562a168d10cca28a3322cdfa59d9e7eafa2eb5e1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 2 Aug 2017 04:45:14 +0800 Subject: [PATCH 1864/2794] fixed compile with lcl <= 1.8.0 --- baseunits/SimpleException/SimpleException.pas | 18 +++++++++--------- mangadownloader/md.lpi | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 32a99c293..e33aae2f6 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -35,21 +35,21 @@ interface uses - Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, SimpleExceptionForm, + Classes, SysUtils, LazFileUtils, LazUTF8, Forms, Controls, SimpleExceptionForm {$IFDEF WINDOWS} - Windows, win32proc, + , Windows, win32proc {$ENDIF} {$IFDEF LINUX} - elfreader, + , elfreader {$ENDIF} {$IF DEFINED(DARWIN) OR DEFINED(MACOS)} - machoreader, + , machoreader {$ENDIF} - fileinfo + , fileinfo {$IFDEF MULTILOG} - ,MultiLog + , MultiLog {$ENDIF} - ; + , LCLVersion; type @@ -123,7 +123,7 @@ procedure DoneSimpleExceptionHandler; implementation -uses InterfaceBase, LCLVersion{$IF FPC_FULLVERSION >= 30101}, LCLPlatformDef{$ENDIF}; +uses InterfaceBase {$IF LCL_FULLVERSION >= 1080000}, LCLPlatformDef{$ENDIF}; {$IFDEF MULTILOG} type @@ -222,7 +222,7 @@ function GetWidgetSetName: String; lpNoGUI : Result := 'NoGUI'; lpCocoa : Result := 'Cocoa'; lpCustomDrawn : Result := 'Custom Drawn'; - {$IF FPC_FULLVERSION >= 30101} + {$IF LCL_FULLVERSION >= 1080000} lpQt5 : Result := 'Qt5'; lpMUI : Result := 'MUI'; {$ENDIF} diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f7fb42bd8..b119b792f 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -266,7 +266,7 @@ </CompilerOptions> </Item6> <SharedMatrixOptions Count="1"> - <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-CX -O3 -Xs -XX -g-"/> + <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From 8c6b6215f0aa25588366dc03aa903ea4fd4baede Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 2 Aug 2017 05:59:35 +0800 Subject: [PATCH 1865/2794] Bump version 0.9.122.0 --- changelog.txt | 11 +++++++++-- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index 56bca45f3..9ae38cc41 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,12 +4,19 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.121.0 (28-07.2017) +0.9.122.0 (02-08-2017) +[*] MangaAe: fixed all +[*] Tumangaonline: fixed load manhwa +[*] MangaIn: fixed all +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.121.0...0.9.122.0 + +0.9.121.0 (28-07-2017) [*] Mangago: fixed download [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.120.0...0.9.121.0 -0.9.120.0 (26-07.2017) +0.9.120.0 (26-07-2017) [*] Added support for relative path [*] Increased task/connection limit for win32 to 16/64 and win64 to 64/256 [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b119b792f..8626c96c8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="121"/> + <RevisionNr Value="122"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 4c959fca6..b862e5e69 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.121.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.121.0/fmd_0.9.121.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.121.0/fmd_0.9.121.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.121.0/fmd_0.9.121.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.121.0/fmd_0.9.121.0_Win64.7z +VERSION=0.9.122.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.122.0/fmd_0.9.122.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.122.0/fmd_0.9.122.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.122.0/fmd_0.9.122.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.122.0/fmd_0.9.122.0_Win64.7z From 6dc9ca7bb06c85570d892c790e65d34f27fb1dde Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 9 Aug 2017 16:09:40 +0800 Subject: [PATCH 1866/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 78d746c1f..5b8ec6520 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 78d746c1f3a65279444e6b70a88a09ed6a3a7b4e +Subproject commit 5b8ec652081d7b342f6245ad77bfdced2204703d From 6466de3e2893f914ea0d1cce6d0f780d82268fed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 11 Aug 2017 15:39:44 +0800 Subject: [PATCH 1867/2794] changed downloads db failedchapters with chapterstatus --- baseunits/DownloadsDB.pas | 53 ++++++++++++++++++---------- baseunits/uDownloadsManager.pas | 61 ++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 46 deletions(-) diff --git a/baseunits/DownloadsDB.pas b/baseunits/DownloadsDB.pas index 7d08985e6..ef35063a3 100644 --- a/baseunits/DownloadsDB.pas +++ b/baseunits/DownloadsDB.pas @@ -25,7 +25,7 @@ TDownloadsDB = class(TSQliteData) const Awebsite, Alink, Atitle, Astatus, Aprogress, Asaveto: String; const Adatetime: TDateTime; const Achapterslinks, Achaptersnames, Apagelinks, Apagecontainerlinks, Afilenames, Acustomfilenames, - Afailedchapterslinks, Afailedchaptersnames: String): Boolean; + Achaptersstatus: String): Boolean; procedure Delete(const ADlId: Integer); procedure Commit; override; procedure Close; override; @@ -53,8 +53,7 @@ TDownloadsDB = class(TSQliteData) f_pagecontainerlinks = 17; f_filenames = 18; f_customfilenames = 19; - f_failedchapterlinks = 20; - f_failedchapternames = 21; + f_chaptersstatus = 20; implementation @@ -95,31 +94,51 @@ constructor TDownloadsDB.Create(const AFilename: String); '"pagecontainerlinks" TEXT,' + '"filenames" TEXT,' + '"customfilenames" TEXT,' + - '"failedchapterlinks" TEXT,' + - '"failedchapternames" TEXT'; - FieldsParams := '"dlid","enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","failedchapterlinks","failedchapternames"'; + '"chaptersstatus" TEXT'; + FieldsParams := '"dlid","enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","chaptersstatus"'; SelectParams := 'SELECT ' + FieldsParams + ' FROM '+QuotedStrD(TableName)+' ORDER BY "order"'; end; function TDownloadsDB.Open: Boolean; begin Result := inherited Open(False, False); + Table.SQL.Text := 'SELECT * FROM ' + QuotedStrD(TableName); + Table.Open; + if Table.Active then + begin + // convert table, replace failedchapterlink, failedchaptername with chaptersstatus + if (Table.Fields.Count = 22) and (Table.Fields[20].FieldName = 'failedchapterlinks') then + begin + Table.Close; + with Connection do + begin + ExecuteDirect('DROP TABLE IF EXISTS ' + QuotedStrD('temp' + TableName)); + ExecuteDirect('CREATE TABLE ' + QuotedStrD('temp' + TableName) + ' (' + CreateParams + ')'); + ExecuteDirect('INSERT INTO ' + QuotedStrD('temp' + TableName) + ' (' + FieldsParams + ') SELECT ' + + '"dlid","enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks"||"failedchapterlinks","chaptersnames"||"failedchapternames","pagelinks","pagecontainerlinks","filenames","customfilenames",""' + + ' FROM "' + TableName + '"'); + ExecuteDirect('DROP TABLE ' + QuotedStrD(TableName)); + ExecuteDirect('ALTER TABLE ' + QuotedStrD('temp' + TableName) + ' RENAME TO ' + QuotedStrD(TableName)); + Transaction.Commit; + end; + end; + end; + CloseTable; end; -function TDownloadsDB.Add(var Adlid: Integer; - const Aenabled: Boolean; - const Aorder, Ataskstatus, Achapterptr, Anumberofpages, Acurrentpage: Integer; - const Awebsite, Alink, Atitle, Astatus, Aprogress, Asaveto: String; - const Adatetime: TDateTime; - const Achapterslinks, Achaptersnames, Apagelinks, Apagecontainerlinks, Afilenames, Acustomfilenames, - Afailedchapterslinks, Afailedchaptersnames: String): Boolean; +function TDownloadsDB.Add(var Adlid: Integer; const Aenabled: Boolean; + const Aorder, Ataskstatus, Achapterptr, Anumberofpages, + Acurrentpage: Integer; const Awebsite, Alink, Atitle, Astatus, Aprogress, + Asaveto: String; const Adatetime: TDateTime; const Achapterslinks, + Achaptersnames, Apagelinks, Apagecontainerlinks, Afilenames, + Acustomfilenames, Achaptersstatus: String): Boolean; begin Result := False; if not Connection.Connected then Exit; try if Adlid = -1 then begin - Connection.ExecuteDirect('INSERT INTO "downloads" ("enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","failedchapterlinks","failedchapternames")' + + Connection.ExecuteDirect('INSERT INTO "downloads" ("enabled","order","taskstatus","chapterptr","numberofpages","currentpage","website","link","title","status","progress","saveto","datetime","chapterslinks","chaptersnames","pagelinks","pagecontainerlinks","filenames","customfilenames","chaptersstatus")' + ' VALUES (' + QuotedStr(Aenabled) + ', ' + QuotedStr(Aorder) + ', ' + @@ -140,8 +159,7 @@ function TDownloadsDB.Add(var Adlid: Integer; QuotedStr(Apagecontainerlinks) + ', ' + QuotedStr(Afilenames) + ', ' + QuotedStr(Acustomfilenames) + ', ' + - QuotedStr(Afailedchapterslinks) + ', ' + - QuotedStr(Afailedchaptersnames) + + QuotedStr(Achaptersstatus) + ')'); Adlid := Connection.GetInsertID; end @@ -166,8 +184,7 @@ function TDownloadsDB.Add(var Adlid: Integer; '"pagecontainerlinks"=' + QuotedStr(Apagecontainerlinks) + ', ' + '"filenames"=' + QuotedStr(Afilenames) + ', ' + '"customfilenames"=' + QuotedStr(Acustomfilenames) + ', ' + - '"failedchapterlinks"=' + QuotedStr(Afailedchapterslinks) + ', ' + - '"failedchapternames"=' + QuotedStr(Afailedchaptersnames) + + '"chaptersstatus"=' + QuotedStr(Achaptersstatus) + ' WHERE "dlid"=' + QuotedStr(Adlid)); Inc(FCommitCount); if FCommitCount >= FAutoCommitCount then diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 46d602cef..7ce8b488f 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -94,6 +94,7 @@ TTaskThread = class(TBaseThread) procedure Compress; procedure SyncStop; procedure StatusFailedToCreateDir; + function FailedChaptersExist: Boolean; // show notification when download completed procedure ShowBalloonHint; public @@ -148,8 +149,7 @@ TTaskContainer = class ThreadState: Boolean; ChapterName, ChapterLinks, - FailedChapterName, - FailedChapterLinks, + ChaptersStatus, PageContainerLinks, PageLinks: TStringList; FileNames: TStringList; @@ -731,7 +731,7 @@ destructor TTaskThread.Destroy; begin if (WorkCounter >= PageLinks.Count) and (CurrentDownloadChapterPtr >= ChapterLinks.Count) and - (FailedChapterLinks.Count = 0) then + (not FailedChaptersExist) then begin Status := STATUS_FINISH; DownloadInfo.Status := Format('[%d/%d] %s',[Container.ChapterLinks.Count,Container.ChapterLinks.Count,RS_Finish]); @@ -831,6 +831,15 @@ procedure TTaskThread.StatusFailedToCreateDir; RS_FailedToCreateDir, Length(CurrentWorkingDir), LineEnding + CurrentWorkingDir]); end; +function TTaskThread.FailedChaptersExist: Boolean; +var + i: Integer; +begin + for i := 0 to Container.ChaptersStatus.Count - 1 do + if Container.ChaptersStatus[i] = 'F' then Exit(True); + Result := False; +end; + procedure TTaskThread.ShowBalloonHint; begin if OptionShowBalloonHint then @@ -1099,8 +1108,17 @@ procedure TTaskThread.Execute; if Trim(Container.CustomFileName) = '' then Container.CustomFileName := DEFAULT_FILENAME_CUSTOMRENAME; + while Container.ChaptersStatus.Count < Container.ChapterLinks.Count do + Container.ChaptersStatus.Add('P'); + if Container.CurrentDownloadChapterPtr > 1 then + for j := 0 to Container.CurrentDownloadChapterPtr - 1 do + Container.ChaptersStatus[j] := 'D'; + while Container.CurrentDownloadChapterPtr < Container.ChapterLinks.Count do begin + while Container.ChaptersStatus[Container.CurrentDownloadChapterPtr] = 'D' do + Inc(Container.CurrentDownloadChapterPtr); + WaitForThreads; if Terminated then Exit; @@ -1264,13 +1282,10 @@ procedure TTaskThread.Execute; Container.Status := STATUS_FAILED; end; - if (Container.Status = STATUS_FAILED) and - (not FindStrLinear(Container.FailedChapterLinks, - Container.ChapterName[Container.CurrentDownloadChapterPtr])) then - begin - Container.FailedChapterName.Add(Container.ChapterName[Container.CurrentDownloadChapterPtr]); - Container.FailedChapterLinks.Add(Container.ChapterLinks[Container.CurrentDownloadChapterPtr]); - end; + if Container.Status = STATUS_FAILED then + Container.ChaptersStatus[Container.CurrentDownloadChapterPtr] := 'F' + else + Container.ChaptersStatus[Container.CurrentDownloadChapterPtr] := 'D'; Container.CurrentPageNumber := 0; Container.PageLinks.Clear; @@ -1279,7 +1294,7 @@ procedure TTaskThread.Execute; InterLockedIncrement(Container.CurrentDownloadChapterPtr); end; - if Container.FailedChapterLinks.Count > 0 then + if FailedChaptersExist then begin Container.Status := STATUS_FAILED; Container.DownloadInfo.Status := Format('[%d/%d] %s', [ @@ -1288,11 +1303,6 @@ procedure TTaskThread.Execute; RS_FailedTryResumeTask]); Container.DownloadInfo.Progress := ''; Container.CurrentDownloadChapterPtr := 0; - - Container.ChapterName.Assign(Container.FailedChapterName); - Container.ChapterLinks.Assign(Container.FailedChapterLinks); - Container.FailedChapterName.Clear; - Container.FailedChapterLinks.Clear; end else begin @@ -1347,8 +1357,7 @@ constructor TTaskContainer.Create; ThreadState := False; ChapterLinks := TStringList.Create; ChapterName := TStringList.Create; - FailedChapterName := TStringList.Create; - FailedChapterLinks := TStringList.Create; + ChaptersStatus := TStringList.Create; PageLinks := TStringList.Create; PageContainerLinks := TStringList.Create; FileNames := TStringList.Create; @@ -1372,8 +1381,7 @@ destructor TTaskContainer.Destroy; PageLinks.Free; ChapterName.Free; ChapterLinks.Free; - FailedChapterName.Free; - FailedChapterLinks.Free; + ChaptersStatus.Free; DoneCriticalsection(CS_Container); if Assigned(Manager) then Manager.DecStatusCount(Status); @@ -1418,8 +1426,7 @@ procedure TTaskContainer.SaveToDB(const AOrder: Integer); PageContainerLinks.Text, FileNames.Text, CustomFileName, - FailedChapterLinks.Text, - FailedChapterName.Text); + ChaptersStatus.Text); end; { TDownloadManager } @@ -1591,14 +1598,13 @@ function TDownloadManager.ConvertToDB: Boolean; ReadString(s, 'Progress', ''), ReadString(s, 'SaveTo', ''), StrToFloatDef(ReadString(s, 'DateTime', ''), Now, FMDFormatSettings), - GetParams(ReadString(s, 'ChapterLinks', '')), - GetParams(ReadString(s, 'ChapterName', '')), + GetParams(ReadString(s, 'ChapterLinks', '') + ReadString(s, 'FailedChapterLinks', '')), + GetParams(ReadString(s, 'ChapterName', '') + ReadString(s, 'FailedChapterName', '')), GetParams(ReadString(s, 'PageLinks', '')), GetParams(ReadString(s, 'PageContainerLinks', '')), GetParams(ReadString(s, 'Filenames', '')), ReadString(s, 'CustomFileName', DEFAULT_FILENAME_CUSTOMRENAME), - GetParams(ReadString(s, 'FailedChapterLinks', '')), - GetParams(ReadString(s, 'FailedChapterName', ''))); + ''); end; FDownloadsDB.Commit; Result := True; @@ -1647,8 +1653,7 @@ procedure TDownloadManager.Restore; PageContainerLinks.Text := Fields[f_pagecontainerlinks].AsString; FileNames.Text := Fields[f_filenames].AsString; CustomFileName := Fields[f_customfilenames].AsString; - FailedChapterLinks.Text := Fields[f_failedchapterlinks].AsString; - FailedChapterName.Text := Fields[f_failedchapternames].AsString; + ChaptersStatus.Text := Fields[f_chaptersstatus].AsString; end; FDownloadsDB.Table.Next; end; From 50b46577bff1b30cb209cba0d7784074d77f7b91 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 11 Aug 2017 22:27:20 +0800 Subject: [PATCH 1868/2794] added more info when task failed --- baseunits/uDownloadsManager.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 7ce8b488f..6db8dbb1c 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1057,6 +1057,7 @@ procedure TTaskThread.Execute; function CheckForFinish: Boolean; var i, c: Integer; + sf: String; begin if Container.PageLinks.Count > 0 then Result := True @@ -1067,18 +1068,20 @@ procedure TTaskThread.Execute; end; c := 0; + sf := ''; for i := 0 to Container.PageLinks.Count - 1 do - begin if Trim(Container.PageLinks[i]) <> 'D' then + begin Inc(c); - end; + sf += Container.PageLinks[i] + LineEnding; + end; if c > 0 then begin Logger.SendWarning(Format('%s, checkforfinish failed=%d/%d "%s" > "%s"', [Self.ClassName, c, Container.PageLinks.Count, Container.DownloadInfo.Title, - Container.ChapterName[Container.CurrentDownloadChapterPtr]])); + Container.ChapterLinks[Container.CurrentDownloadChapterPtr]]) + LineEnding + Trim(sf)); Result := False; end; end; From d94cf7cb8f25bef897f0a111c3f4b671888493fd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 11 Aug 2017 23:32:40 +0800 Subject: [PATCH 1869/2794] added option auto retry failed task count and more failed handles - auto retry failed task with retry count option - set status failed if compress failed - cleanup dlmanager var, move to fmdoptions --- baseunits/FMDOptions.pas | 5 + baseunits/uDownloadsManager.pas | 61 +++++++----- mangadownloader/forms/frmMain.lfm | 132 +++++++++++++++---------- mangadownloader/forms/frmMain.lrj | 15 +-- mangadownloader/forms/frmMain.pas | 32 ++++-- mangadownloader/languages/fmd.de.po | 4 + mangadownloader/languages/fmd.el_GR.po | 4 + mangadownloader/languages/fmd.en.po | 5 +- mangadownloader/languages/fmd.es.po | 4 + mangadownloader/languages/fmd.id_ID.po | 9 +- mangadownloader/languages/fmd.pl_PL.po | 4 + mangadownloader/languages/fmd.po | 4 + mangadownloader/languages/fmd.pt_BR.po | 4 + mangadownloader/languages/fmd.ru_RU.po | 4 + 14 files changed, 191 insertions(+), 96 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index b96b6187b..b0c1773cc 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -122,7 +122,12 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionPDFQuality: Cardinal = 95; + // connections + OptionMaxParallel: Integer = 1; OptionMaxThreads: Integer = 1; + OptionMaxRetry: Integer = 5; + OptionConnectionTimeout: Integer = 30; + OptionRetryFailedTask: Integer = 1; // view OptionEnableLoadCover: Boolean = False; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 6db8dbb1c..9bb9b6c10 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -91,9 +91,10 @@ TTaskThread = class(TBaseThread) protected procedure CheckOut; procedure Execute; override; - procedure Compress; + function Compress: Boolean; procedure SyncStop; procedure StatusFailedToCreateDir; + function FirstFailedChapters: Integer; function FailedChaptersExist: Boolean; // show notification when download completed procedure ShowBalloonHint; @@ -197,13 +198,9 @@ TDownloadManager = class CS_StatusCount: TRTLCriticalSection; StatusCount: array [TDownloadStatusType] of Integer; // disabled count - DisabledCount: Integer; - - compress, retryConnect, - // max. active tasks - maxDLTasks, - // max. download threads per task - maxDLThreadsPerTask: Integer; + DisabledCount, + CompressType, + RetryConnect: Integer; //downloaded chapter list database DownloadedChapters: TDownloadedChaptersDB; @@ -779,20 +776,21 @@ function TTaskThread.GetFileName(const AWorkId: Integer): String; {$ENDIF} end; -procedure TTaskThread.Compress; +function TTaskThread.Compress: Boolean; var uPacker: TPacker; i: Integer; s: String; begin - if (Container.Manager.compress >= 1) then + Result := True; + if (Container.Manager.CompressType >= 1) then begin Container.DownloadInfo.Status := Format('[%d/%d] %s', [Container.CurrentDownloadChapterPtr + 1, Container.ChapterLinks.Count, RS_Compressing]); uPacker := TPacker.Create; try - case Container.Manager.compress of + case Container.Manager.CompressType of 1: uPacker.Format := pfZIP; 2: uPacker.Format := pfCBZ; 3: uPacker.Format := pfPDF; @@ -807,7 +805,7 @@ procedure TTaskThread.Compress; if s <> '' then uPacker.FileList.Add(s); end; - uPacker.Execute; + Result := uPacker.Execute; except on E: Exception do MainForm.ExceptionHandler(Self, E); @@ -831,13 +829,18 @@ procedure TTaskThread.StatusFailedToCreateDir; RS_FailedToCreateDir, Length(CurrentWorkingDir), LineEnding + CurrentWorkingDir]); end; -function TTaskThread.FailedChaptersExist: Boolean; +function TTaskThread.FirstFailedChapters: Integer; var i: Integer; begin for i := 0 to Container.ChaptersStatus.Count - 1 do - if Container.ChaptersStatus[i] = 'F' then Exit(True); - Result := False; + if Container.ChaptersStatus[i] = 'F' then Exit(i); + Result := -1; +end; + +function TTaskThread.FailedChaptersExist: Boolean; +begin + Result := FirstFailedChapters <> -1; end; procedure TTaskThread.ShowBalloonHint; @@ -909,7 +912,7 @@ function TDownloadThread.DownloadImage: Boolean; Task.CurrentWorkingDir, workFilename, savedFilename, - Task.Container.Manager.retryConnect); + Task.Container.Manager.RetryConnect); end; if Terminated then Exit(False); if Result then @@ -987,9 +990,9 @@ procedure TTaskThread.CheckOut; if Modules.MaxConnectionLimit[Container.ModuleId] > 0 then currentMaxThread := Modules.MaxConnectionLimit[Container.ModuleId] else - currentMaxThread := Container.Manager.maxDLThreadsPerTask; - if currentMaxThread > Container.Manager.maxDLThreadsPerTask then - currentMaxThread := Container.Manager.maxDLThreadsPerTask; + currentMaxThread := OptionMaxThreads; + if currentMaxThread > OptionMaxThreads then + currentMaxThread := OptionMaxThreads; end; if Container.PageLinks.Count > 0 then @@ -1095,6 +1098,7 @@ procedure TTaskThread.Execute; var j: Integer; DynamicPageLink: Boolean; + FailedRetryCount: Integer = 0; begin Container.ThreadState := True; Container.DownloadInfo.TransferRate := FormatByteSize(Container.ReadCount, true); @@ -1271,7 +1275,8 @@ procedure TTaskThread.Execute; begin Container.Status := STATUS_COMPRESS; Container.DownloadInfo.Progress := ''; - Compress; + if not Compress then + Container.Status := STATUS_FAILED; end else Container.Status := STATUS_FAILED; @@ -1295,6 +1300,16 @@ procedure TTaskThread.Execute; Container.PageContainerLinks.Clear; Container.CurrentDownloadChapterPtr := InterLockedIncrement(Container.CurrentDownloadChapterPtr); + + if (Container.CurrentDownloadChapterPtr = Container.ChapterLinks.Count) and + (FailedRetryCount < OptionRetryFailedTask) then + begin + Container.CurrentDownloadChapterPtr := FirstFailedChapters; + if container.CurrentDownloadChapterPtr <> -1 then + Inc(FailedRetryCount) + else + Container.CurrentDownloadChapterPtr := Container.ChapterLinks.Count; + end; end; if FailedChaptersExist then @@ -1736,10 +1751,10 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); if Items[i].ThreadState then Inc(tcount); - if tcount < maxDLTasks then + if tcount < OptionMaxParallel then for i := 0 to Items.Count - 1 do with Items[i] do - if (tcount < maxDLTasks) and + if (tcount < OptionMaxParallel) and (Status = STATUS_WAIT) and Modules.CanCreateTask(ModuleId) then begin @@ -1792,7 +1807,7 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; for i := 0 to Items.Count - 1 do with Items[i] do if Status in [STATUS_DOWNLOAD, STATUS_PREPARE] then - if (tcount < maxDLTasks) and + if (tcount < OptionMaxParallel) and Modules.CanCreateTask(ModuleId) then begin Inc(tcount); diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 6e2f75ba0..6fd7d5d58 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,6 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -2968,7 +2967,7 @@ object MainForm: TMainForm Top = 0 Width = 753 HorzScrollBar.Page = 455 - VertScrollBar.Page = 268 + VertScrollBar.Page = 295 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 @@ -2979,12 +2978,12 @@ object MainForm: TMainForm ClientWidth = 753 TabOrder = 0 object cbOptionUseProxy: TCheckBox - AnchorSideLeft.Control = seOptionConnectionTimeout - AnchorSideTop.Control = seOptionConnectionTimeout + AnchorSideLeft.Control = seOptionRetryFailedTask + AnchorSideTop.Control = seOptionRetryFailedTask AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 132 + Top = 159 Width = 71 BorderSpacing.Top = 20 Caption = 'Use proxy' @@ -2998,7 +2997,7 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 105 - Top = 155 + Top = 182 Width = 426 AutoSize = True Caption = 'Proxy config' @@ -3271,6 +3270,35 @@ object MainForm: TMainForm ParentColor = False ParentFont = False end + object lbOptionRetryFailedTask: TLabel + AnchorSideLeft.Control = seOptionRetryFailedTask + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = seOptionRetryFailedTask + AnchorSideTop.Side = asrCenter + Left = 60 + Height = 15 + Top = 120 + Width = 183 + Caption = 'Number of retry times if task failed' + ParentColor = False + ParentFont = False + end + object seOptionRetryFailedTask: TSpinEdit + AnchorSideLeft.Control = seOptionConnectionTimeout + AnchorSideTop.Control = seOptionConnectionTimeout + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = seOptionMaxRetry + AnchorSideRight.Side = asrBottom + Left = 4 + Height = 23 + Top = 116 + Width = 52 + Anchors = [akTop, akLeft, akRight] + ParentFont = False + ParentShowHint = False + TabOrder = 6 + Value = 1 + end end end object tsSaveTo: TTabSheet @@ -4621,14 +4649,14 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - Left = 96 - Top = 251 + left = 96 + top = 251 end object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - Left = 592 - Top = 184 + left = 592 + top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -4958,8 +4986,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - Left = 592 - Top = 224 + left = 592 + top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -5017,8 +5045,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - Left = 520 - Top = 212 + left = 520 + top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -5336,8 +5364,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - Left = 382 - Top = 238 + left = 382 + top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5483,13 +5511,13 @@ object MainForm: TMainForm PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - Left = 288 - Top = 432 + left = 288 + top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False - Left = 382 - Top = 110 + left = 382 + top = 110 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5511,8 +5539,8 @@ object MainForm: TMainForm end end object IconList: TImageList - Left = 278 - Top = 102 + left = 278 + top = 102 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6254,8 +6282,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - Left = 278 - Top = 150 + left = 278 + top = 150 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6551,8 +6579,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - Left = 328 - Top = 238 + left = 328 + top = 238 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6846,8 +6874,8 @@ object MainForm: TMainForm } end object IconSmall: TImageList - Left = 27 - Top = 328 + left = 27 + top = 328 Bitmap = { 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6950,8 +6978,8 @@ object MainForm: TMainForm end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup - Left = 592 - Top = 136 + left = 592 + top = 136 object medURLUndo: TMenuItem Caption = 'Undo' OnClick = medURLUndoClick @@ -6990,38 +7018,38 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - Left = 96 - Top = 312 + left = 96 + top = 312 end object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - Left = 560 - Top = 472 + left = 560 + top = 472 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - Left = 504 - Top = 120 + left = 504 + top = 120 end object TransferRateToolset: TChartToolset - Left = 464 - Top = 120 + left = 464 + top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - Left = 152 - Top = 376 + left = 152 + top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick end end object pmFilterGenreAll: TPopupMenu - Left = 520 - Top = 168 + left = 520 + top = 168 object mnFilterGenreAllCheck: TMenuItem Caption = 'Check all' OnClick = mnFilterGenreAllCheckClick @@ -7037,8 +7065,8 @@ object MainForm: TMainForm end object pmTray: TPopupMenu OnPopup = pmTrayPopup - Left = 341 - Top = 432 + left = 341 + top = 432 object miTrayResumeAll: TMenuItem Caption = 'Resume all' OnClick = tbDownloadResumeAllClick @@ -7102,28 +7130,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - Left = 656 - Top = 416 + left = 656 + top = 416 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - Left = 440 - Top = 472 + left = 440 + top = 472 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - Left = 656 - Top = 472 + left = 656 + top = 472 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - Left = 480 - Top = 472 + left = 480 + top = 472 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index a350a41c8..b7459b14d 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -50,13 +50,13 @@ {"hash":84262158,"name":"tmainform.cbuseregexpr.caption","sourcebytes":[82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110],"value":"Regular Expression"}, {"hash":111905342,"name":"tmainform.ckfilteraction.hint","sourcebytes":[65,32,119,111,114,107,32,116,121,112,105,99,97,108,108,121,32,100,101,112,105,99,116,105,110,103,32,102,105,103,104,116,105,110,103,44,32,118,105,111,108,101,110,99,101,44,32,99,104,97,111,115,44,32,97,110,100,32,102,97,115,116,32,112,97,99,101,100,32,109,111,116,105,111,110,46],"value":"A work typically depicting fighting, violence, chaos, and fast paced motion."}, {"hash":75149406,"name":"tmainform.ckfilteraction.caption","sourcebytes":[65,99,116,105,111,110],"value":"Action"}, -{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity."}, +{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and\/or graphic sexual content and nudity."}, {"hash":4701236,"name":"tmainform.ckfilteradult.caption","sourcebytes":[65,100,117,108,116],"value":"Adult"}, {"hash":267284606,"name":"tmainform.ckfilteradventure.hint","sourcebytes":[73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,111,114,121,32,103,111,101,115,32,111,110,32,97,32,116,114,105,112,32,111,114,32,97,108,111,110,103,32,116,104,97,116,32,108,105,110,101,44,32,121,111,117,114,32,98,101,115,116,32,98,101,116,32,105,115,32,116,104,97,116,32,105,116,32,105,115,32,97,110,32,97,100,118,101,110,116,117,114,101,32,109,97,110,103,97,46,32,79,116,104,101,114,119,105,115,101,44,32,105,116,39,115,32,117,112,32,116,111,32,121,111,117,114,32,112,101,114,115,111,110,97,108,32,112,114,101,106,117,100,105,99,101,32,111,110,32,116,104,105,115,32,99,97,115,101,46],"value":"If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case."}, {"hash":214301493,"name":"tmainform.ckfilteradventure.caption","sourcebytes":[65,100,118,101,110,116,117,114,101],"value":"Adventure"}, {"hash":11846766,"name":"tmainform.ckfiltercomedy.hint","sourcebytes":[65,32,100,114,97,109,97,116,105,99,32,119,111,114,107,32,116,104,97,116,32,105,115,32,108,105,103,104,116,32,97,110,100,32,111,102,116,101,110,32,104,117,109,111,114,111,117,115,32,111,114,32,115,97,116,105,114,105,99,97,108,32,105,110,32,116,111,110,101,32,97,110,100,32,116,104,97,116,32,117,115,117,97,108,108,121,32,99,111,110,116,97,105,110,115,32,97,32,104,97,112,112,121,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,104,101,109,97,116,105,99,32,99,111,110,102,108,105,99,116,46],"value":"A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict."}, {"hash":78003129,"name":"tmainform.ckfiltercomedy.caption","sourcebytes":[67,111,109,101,100,121],"value":"Comedy"}, -{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga/anime."}, +{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga\/anime."}, {"hash":202379913,"name":"tmainform.ckfilterdoujinshi.caption","sourcebytes":[68,111,117,106,105,110,115,104,105],"value":"Doujinshi"}, {"hash":221112350,"name":"tmainform.ckfilterdrama.hint","sourcebytes":[65,32,119,111,114,107,32,109,101,97,110,116,32,116,111,32,98,114,105,110,103,32,111,110,32,97,110,32,101,109,111,116,105,111,110,97,108,32,114,101,115,112,111,110,115,101,44,32,115,117,99,104,32,97,115,32,105,110,115,116,105,108,108,105,110,103,32,115,97,100,110,101,115,115,32,111,114,32,116,101,110,115,105,111,110,46],"value":"A work meant to bring on an emotional response, such as instilling sadness or tension."}, {"hash":4950065,"name":"tmainform.ckfilterdrama.caption","sourcebytes":[68,114,97,109,97],"value":"Drama"}, @@ -80,7 +80,7 @@ {"hash":56818190,"name":"tmainform.ckfilterlolicon.caption","sourcebytes":[76,111,108,105,99,111,110],"value":"Lolicon"}, {"hash":104001182,"name":"tmainform.ckfiltermartialarts.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,109,97,114,116,105,97,108,32,97,114,116,115,32,114,101,108,97,116,101,100,46,32,65,110,121,32,111,102,32,115,101,118,101,114,97,108,32,97,114,116,115,32,111,102,32,99,111,109,98,97,116,32,111,114,32,115,101,108,102,45,100,101,102,101,110,115,101,44,32,115,117,99,104,32,97,115,32,97,105,107,105,100,111,44,32,107,97,114,97,116,101,44,32,106,117,100,111,44,32,111,114,32,116,97,101,107,119,111,110,100,111,44,32,107,101,110,100,111,44,32,102,101,110,99,105,110,103,44,32,97,110,100,32,115,111,32,111,110,32,97,110,100,32,115,111,32,102,111,114,116,104,46],"value":"As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth."}, {"hash":47977283,"name":"tmainform.ckfiltermartialarts.caption","sourcebytes":[77,97,114,116,105,97,108,32,65,114,116,115],"value":"Martial Arts"}, -{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language."}, +{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and\/or strong language."}, {"hash":87604357,"name":"tmainform.ckfiltermature.caption","sourcebytes":[77,97,116,117,114,101],"value":"Mature"}, {"hash":187133582,"name":"tmainform.ckfiltermecha.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,118,111,108,118,105,110,103,32,97,110,100,32,117,115,117,97,108,108,121,32,99,111,110,99,101,110,116,114,97,116,105,110,103,32,111,110,32,97,108,108,32,116,121,112,101,115,32,111,102,32,108,97,114,103,101,32,114,111,98,111,116,105,99,32,109,97,99,104,105,110,101,115,46],"value":"A work involving and usually concentrating on all types of large robotic machines."}, {"hash":5487073,"name":"tmainform.ckfiltermecha.caption","sourcebytes":[77,101,99,104,97],"value":"Mecha"}, @@ -104,11 +104,11 @@ {"hash":94333967,"name":"tmainform.ckfiltershoujo.caption","sourcebytes":[83,104,111,117,106,111],"value":"Shoujo"}, {"hash":171132846,"name":"tmainform.ckfiltershoujoai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,117,114,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,71,105,114,108,39,39,115,32,76,111,118,101,34,44,32,115,111,32,116,111,32,115,112,101,97,107,46],"value":"Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak."}, {"hash":113331593,"name":"tmainform.ckfiltershoujoai.caption","sourcebytes":[83,104,111,117,106,111,32,65,105],"value":"Shoujo Ai"}, -{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and/or violence."}, +{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and\/or violence."}, {"hash":167167214,"name":"tmainform.ckfiltershounen.caption","sourcebytes":[83,104,111,117,110,101,110],"value":"Shounen"}, {"hash":19597467,"name":"tmainform.ckfiltershounenai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,97,111,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,66,111,121,39,39,115,32,76,111,118,101,34,194,157,44,32,115,111,32,116,111,32,115,112,101,97,107],"value":"Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\"\u009D, so to speak"}, {"hash":206543641,"name":"tmainform.ckfiltershounenai.caption","sourcebytes":[83,104,111,117,110,101,110,32,65,105],"value":"Shounen Ai"}, -{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, +{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one\/many character(s). These challenges\/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, {"hash":262977669,"name":"tmainform.ckfiltersliceoflife.caption","sourcebytes":[83,108,105,99,101,32,111,102,32,76,105,102,101],"value":"Slice of Life"}, {"hash":68245006,"name":"tmainform.ckfiltersmut.hint","sourcebytes":[68,101,97,108,115,32,119,105,116,104,32,115,101,114,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,112,114,111,102,97,110,101,32,111,114,32,111,102,102,101,110,115,105,118,101,44,32,112,97,114,116,105,99,117,108,97,114,108,121,32,119,105,116,104,32,114,101,103,97,114,100,115,32,116,111,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,46],"value":"Deals with series that are considered profane or offensive, particularly with regards to sexual content."}, {"hash":369860,"name":"tmainform.ckfiltersmut.caption","sourcebytes":[83,109,117,116],"value":"Smut"}, @@ -165,7 +165,7 @@ {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, {"hash":325284,"name":"tmainform.lboptionhost.caption","sourcebytes":[72,111,115,116],"value":"Host"}, -{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host/IP"}, +{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host\/IP"}, {"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, {"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, @@ -177,6 +177,7 @@ {"hash":244185205,"name":"tmainform.lboptionmaxthread.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,100,111,119,110,108,111,97,100,101,100,32,102,105,108,101,115,32,112,101,114,32,116,97,115,107,32,97,116,32,116,104,101,32,115,97,109,101,32,116,105,109,101],"value":"Number of downloaded files per task at the same time"}, {"hash":34874153,"name":"tmainform.lboptionmaxretry.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,114,101,116,114,121,32,116,105,109,101,115,32,105,102,32,116,97,115,107,115,32,104,97,118,101,32,100,111,119,110,108,111,97,100,32,112,114,111,98,108,101,109,115,32,40,45,49,32,61,32,97,108,119,97,121,115,32,114,101,116,114,121,41],"value":"Number of retry times if tasks have download problems (-1 = always retry)"}, {"hash":161967481,"name":"tmainform.lboptionconnectiontimeout.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,32,116,105,109,101,111,117,116,32,40,115,101,99,111,110,100,115,41],"value":"Connection timeout (seconds)"}, +{"hash":225523060,"name":"tmainform.lboptionretryfailedtask.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,114,101,116,114,121,32,116,105,109,101,115,32,105,102,32,116,97,115,107,32,102,97,105,108,101,100],"value":"Number of retry times if task failed"}, {"hash":160200703,"name":"tmainform.tssaveto.caption","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":96652067,"name":"tmainform.rgoptioncompress.caption","sourcebytes":[83,97,118,101,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115,32,97,115],"value":"Save downloaded chapters as"}, {"hash":206060487,"name":"tmainform.gboptionrenaming.caption","sourcebytes":[82,101,110,97,109,105,110,103],"value":"Renaming"}, @@ -220,7 +221,7 @@ {"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, {"hash":263412434,"name":"tmainform.gbdialogs.caption","sourcebytes":[83,104,111,119,32,100,105,97,108,111,103,32,99,111,110,102,105,114,109,97,116,105,111,110,32,102,111,114],"value":"Show dialog confirmation for"}, {"hash":252071892,"name":"tmainform.cboptionshowquitdialog.caption","sourcebytes":[69,120,105,116,32,70,77,68],"value":"Exit FMD"}, -{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task/favorite"}, +{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task\/favorite"}, {"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, {"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, {"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 324f3f5dd..0a6174a94 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -82,6 +82,7 @@ TMainForm = class(TForm) edURL: TEditButton; edWebsitesSearch: TEditButton; lbLogFileName: TLabel; + lbOptionRetryFailedTask: TLabel; lbOptionFilenameCustomRenameHint: TLabel; lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; @@ -136,6 +137,7 @@ TMainForm = class(TForm) sbSaveTo: TScrollBox; sbWebsiteOptions: TScrollBox; btDownloadSplit: TSpeedButton; + seOptionRetryFailedTask: TSpinEdit; tsInfoManga: TTabSheet; tsinfoFilterAdv: TTabSheet; tsCustomColor: TTabSheet; @@ -4679,10 +4681,13 @@ procedure TMainForm.LoadOptions; tbDropTargetOpacity.Position := ReadInteger('droptarget', 'Opacity', 255); // connection - seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', 1); - seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', 1); - seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', 5);; - seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', 30); + seOptionMaxParallel.Value := ReadInteger('connections', 'NumberOfTasks', OptionMaxParallel); + seOptionMaxThread.Value := ReadInteger('connections', 'NumberOfThreadsPerTask', OptionMaxThreads); + seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', OptionMaxRetry);; + seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', OptionConnectionTimeout); + seOptionRetryFailedTask.Value := ReadInteger('connections', 'NumberOfAutoRetryFailedTask', OptionRetryFailedTask); + + // proxy cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); cbOptionProxyType.Text := ReadString('connections', 'ProxyType', 'HTTP'); edOptionHost.Text := ReadString('connections', 'Host', ''); @@ -4820,6 +4825,9 @@ procedure TMainForm.SaveOptions; WriteInteger('connections', 'NumberOfThreadsPerTask', seOptionMaxThread.Value); WriteInteger('connections', 'Retry', seOptionMaxRetry.Value); WriteInteger('connections', 'ConnectionTimeout', seOptionConnectionTimeout.Value); + WriteInteger('connections', 'NumberOfAutoRetryFailedTask', seOptionRetryFailedTask.Value); + + // proxy WriteBool('connections', 'UseProxy', cbOptionUseProxy.Checked); WriteString('connections', 'ProxyType', cbOptionProxyType.Text); WriteString('connections', 'Host', edOptionHost.Text); @@ -4955,12 +4963,16 @@ procedure TMainForm.ApplyOptions; OptionShowBalloonHint := cbOptionShowBalloonHint.Checked; //connection - DLManager.maxDLTasks := seOptionMaxParallel.Value; - DLManager.maxDLThreadsPerTask := seOptionMaxThread.Value; - DLManager.retryConnect := seOptionMaxRetry.Value; + OptionMaxParallel := seOptionMaxParallel.Value; OptionMaxThreads := seOptionMaxThread.Value; - SetDefaultTimeoutAndApply(seOptionConnectionTimeout.Value * 1000); - SetDefaultRetryCountAndApply(seOptionMaxRetry.Value); + OptionMaxRetry := seOptionMaxRetry.Value; + DLManager.RetryConnect := OptionMaxRetry; + SetDefaultRetryCountAndApply(OptionMaxRetry); + OptionConnectionTimeout := seOptionConnectionTimeout.Value; + SetDefaultTimeoutAndApply(OptionConnectionTimeout * 1000); + OptionRetryFailedTask := seOptionRetryFailedTask.Value; + + // proxy if cbOptionUseProxy.Checked then SetDefaultProxyAndApply(cbOptionProxyType.Text, edOptionHost.Text, edOptionPort.Text, edOptionUser.Text, edOptionPass.Text) @@ -4969,7 +4981,7 @@ procedure TMainForm.ApplyOptions; //saveto OptionPDFQuality := seOptionPDFQuality.Value; - DLManager.compress := rgOptionCompress.ItemIndex; + DLManager.CompressType := rgOptionCompress.ItemIndex; OptionChangeUnicodeCharacter := cbOptionChangeUnicodeCharacter.Checked; OptionChangeUnicodeCharacterStr := edOptionChangeUnicodeCharacterStr.Text; OptionRemoveMangaNameFromChapter := cbOptionRemoveMangaNameFromChapter.Checked; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index a4912711d..61319d055 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -1444,6 +1444,10 @@ msgstr "Type" msgid "Rename digits" msgstr "Rename digits" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 83372b052..55e73149d 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1499,6 +1499,10 @@ msgstr "Τύπος" msgid "Rename digits" msgstr "Μετονομασία ψηφίων" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 9ee27b5d5..dd93ac321 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1442,6 +1442,10 @@ msgstr "Type" msgid "Rename digits" msgstr "Rename digits" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "Number of retry times if task failed" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" @@ -2244,4 +2248,3 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" - diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index fcd91f2df..3f216b666 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1421,6 +1421,10 @@ msgstr "Tipo" msgid "Rename digits" msgstr "Renombrar Dígitos" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1dc1aee43..9f4185af5 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -356,7 +356,7 @@ msgstr "Key:" #: kissmanga.rs_kissmanga_usegoogledcp msgid "Use Google DCP" -msgstr "" +msgstr "Gunakan Google DCP" #: mangafox.rs_removewatermark msgid "Remove watermark" @@ -1422,6 +1422,10 @@ msgstr "Tipe" msgid "Rename digits" msgstr "Ganti nama digit" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "Jumlah pengulangan pada tugas unduhan yang memiliki masalah" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" @@ -1931,7 +1935,7 @@ msgstr "OK" #: tselectdirectoryform.caption msgid "Select directory" -msgstr "" +msgstr "Pilih direktori" #: tshutdowncounterform.btabort.caption msgid "&Abort" @@ -2223,4 +2227,3 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" - diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 7f2e354e9..118857734 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1440,6 +1440,10 @@ msgstr "Typ" msgid "Rename digits" msgstr "Zmiana nazwy cyfry" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 54f7a5d93..d9bcd4b3d 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1348,6 +1348,10 @@ msgstr "" msgid "Rename digits" msgstr "" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index b4dd0b680..4db81a7e5 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1439,6 +1439,10 @@ msgstr "Tipo" msgid "Rename digits" msgstr "Renomear dígitos" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 22e9b2264..a5a214d76 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -1425,6 +1425,10 @@ msgstr "Тип" msgid "Rename digits" msgstr "Переименовать цифры" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" From 3eb343e897aef1cb49c8003d9c774afb695246c0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 11 Aug 2017 23:44:09 +0800 Subject: [PATCH 1870/2794] updated spanish translations by Mariolr93 closed #699 --- mangadownloader/languages/fmd.es.po | 36 +++++++++++++---------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 3f216b666..a206ce5e9 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1,13 +1,13 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: FMD Español 2.0.1\n" +"Project-Id-Version: FMD Español 2.0.2\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Language-Team: Mariolr\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.12\n" +"X-Generator: Poedit 2.0.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Last-Translator: Mariolr\n" "Language: es_419\n" @@ -24,6 +24,11 @@ msgid "" "CDN (default)\n" "CDN2 (testing)\n" msgstr "" +"Auto\n" +"Imagen de Servidor EU\n" +"Imagen de Servidor NA\n" +"CDN (Por Defecto)\n" +"CDN2 (Pruebando)\n" #: batoto.rs_showalllang msgid "Show all language" @@ -343,15 +348,15 @@ msgstr "Sistema se Apagará en %d segundos." #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" -msgstr "" +msgstr "Inicialización del Vector:" #: kissmanga.rs_kissmanga_key msgid "Key:" -msgstr "" +msgstr "Llave:" #: kissmanga.rs_kissmanga_usegoogledcp msgid "Use Google DCP" -msgstr "" +msgstr "Usar Google DCP" #: mangafox.rs_removewatermark msgid "Remove watermark" @@ -586,7 +591,7 @@ msgstr "Visitar mi blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -663,7 +668,7 @@ msgstr "Habilitar Búsqueda en Directo (Lento en Lista Larga)" #: tmainform.cboptionminimizeonstart.caption msgid "Minimize on start" -msgstr "" +msgstr "Minimizar al Iniciar" #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" @@ -1371,20 +1376,16 @@ msgstr "" "El Nombre del la Carpeta del Manga debe tener al menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" -msgstr "Numero de Tareas de Descargas al Mismo Tiempo (Max: 8)" +msgstr "Numero de Tareas de Descargas al Mismo Tiempo" #: tmainform.lboptionmaxretry.caption msgid "Number of retry times if tasks have download problems (-1 = always retry)" msgstr "Numero de Reintentos si la Tarea Tiene Problemas de Descarga (-1 = siempre reintenta)" #: tmainform.lboptionmaxthread.caption -#, fuzzy -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" -msgstr "Numero de Archivos Descargados por Tarea al Mismo Tiempo (Max: 32)" +msgstr "Numero de Archivos Descargados por Tarea al Mismo Tiempo" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -1421,10 +1422,6 @@ msgstr "Tipo" msgid "Rename digits" msgstr "Renombrar Dígitos" -#: tmainform.lboptionretryfailedtask.caption -msgid "Number of retry times if task failed" -msgstr "" - #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" @@ -1805,7 +1802,7 @@ msgstr "Filtro" #: tmainform.tsinfomanga.caption msgid "Info" -msgstr "" +msgstr "Información" #: tmainform.tsinformation.caption msgid "Manga Info" @@ -1928,14 +1925,13 @@ msgid "&Add to queue" msgstr "&Agregar a Cola" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" #: tselectdirectoryform.caption msgid "Select directory" -msgstr "" +msgstr "Seleccionar Directorio" #: tshutdowncounterform.btabort.caption msgid "&Abort" From af51e83e5b327340703151b85d4ef86e14930e50 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 13 Aug 2017 15:19:03 +0800 Subject: [PATCH 1871/2794] mangainn, fixed chapter name fixed #701 --- baseunits/modules/MangaInn.pas | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas index 56d3d0942..49bf8eec6 100644 --- a/baseunits/modules/MangaInn.pas +++ b/baseunits/modules/MangaInn.pas @@ -6,13 +6,10 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML, synautil; implementation -const - dirurl = '/MangaList'; - function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; @@ -20,7 +17,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + if MangaInfo.FHTTP.GET(Module.RootURL + '/MangaList') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -38,8 +35,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -62,11 +57,7 @@ function GetInfo(const MangaInfo: TMangaInformation; artists := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Artist(s)")]/following-sibling::*[1]'); genres := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Genre(s)")]/following-sibling::*[1]'); summary := Trim(XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Summary")]/following-sibling::*')); - for v in XPath('//div[@class="content"]/div[@class="divThickBorder"][3]/table//td[1]/span/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(Trim(title + ' : ' + XPathString('./text()', v))); - end; + XPathHREFAll('//div[@class="content"]/div[@class="divThickBorder"][3]/table//td[1]/span/a', chapterLinks, chapterName); finally Free; end; From 737766a1e39364129b0631c60054f586f67d0655 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 13 Aug 2017 15:42:08 +0800 Subject: [PATCH 1872/2794] Bump version 0.9.123.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9ae38cc41..1ee7ad1a9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.123.0 (13-08-2017) +[+] Added option for auto retry failed task +[*] MangaInn: fixed chapter name +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.123.0...0.9.123.0 + 0.9.122.0 (02-08-2017) [*] MangaAe: fixed all [*] Tumangaonline: fixed load manhwa diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8626c96c8..6d903e753 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="122"/> + <RevisionNr Value="123"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index b862e5e69..1249866e6 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.122.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.122.0/fmd_0.9.122.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.122.0/fmd_0.9.122.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.122.0/fmd_0.9.122.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.122.0/fmd_0.9.122.0_Win64.7z +VERSION=0.9.123.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.123.0/fmd_0.9.123.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.123.0/fmd_0.9.123.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.123.0/fmd_0.9.123.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.123.0/fmd_0.9.123.0_Win64.7z From f59d81836a9e2882db44b1e303f3b85df918f63f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Aug 2017 02:26:05 +0800 Subject: [PATCH 1873/2794] logger, check accesible of log file fixed loop on io error #700 --- baseunits/SimpleException/SimpleException.pas | 100 +++++++++++++++--- mangadownloader/forms/frmMain.pas | 16 ++- mangadownloader/md.lpr | 11 +- 3 files changed, 104 insertions(+), 23 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index e33aae2f6..e00e6fdc8 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -57,7 +57,10 @@ interface TSimpleException = class private + FLogFileHandle: TextFile; FLogFileName: String; + FLogFileOK: Boolean; + FLogFileStatus: String; FLastSender: TObject; FLastException: Exception; FApplicationInfo, @@ -81,6 +84,8 @@ TSimpleException = class IgnoredExceptionList: TStringList; property ApplicationInfo: String read FApplicationInfo; property LogFileName: String read FLogFileName write SetLogFileName; + property LogFileOK: Boolean read FLogFileOK; + property LogFileStatus: String read FLogFileStatus; property MaxStackCount: Integer read FMaxStackCount write SetMaxStackCount; property LastSender: TObject read FLastSender; property LastException: Exception read FLastException; @@ -91,6 +96,7 @@ TSimpleException = class destructor Destroy; override; end; +function GetIOResultStr(const AIOResult: Word): String; function GetOSVer: String; function GetFPCVersion: String; function GetLCLVersion: String; @@ -150,6 +156,43 @@ procedure SetMaxStackCount(const ACount: Integer); MainExceptionHandler.MaxStackCount := ACount; end; +function GetIOResultStr(const AIOResult: Word): String; +begin + Result := IntToStr(AIOResult) + ': '; + case AIOResult of + 0 : Result := Result + 'OK.'; + 2 : Result := Result + 'File not found.'; + 3 : Result := Result + 'Path not found.'; + 4 : Result := Result + 'Too many open files.'; + 5 : Result := Result + 'Access denied.'; + 6 : Result := Result + 'Invalid file handle.'; + 12 : Result := Result + 'Invalid file-access mode.'; + 15 : Result := Result + 'Invalid disk number.'; + 16 : Result := Result + 'Cannot remove current directory.'; + 17 : Result := Result + 'Cannot rename across volumes.'; + 100: Result := Result + 'Error when reading from disk.'; + 101: Result := Result + 'Error when writing to disk.'; + 102: Result := Result + 'File not assigned.'; + 103: Result := Result + 'File not open.'; + 104: Result := Result + 'File not opened for input.'; + 105: Result := Result + 'File not opened for output.'; + 106: Result := Result + 'Invalid number.'; + 150: Result := Result + 'Disk is write protected.'; + 151: Result := Result + 'Unknown device.'; + 152: Result := Result + 'Drive not ready.'; + 153: Result := Result + 'Unknown command.'; + 154: Result := Result + 'CRC check failed.'; + 155: Result := Result + 'Invalid drive specified..'; + 156: Result := Result + 'Seek error on disk.'; + 157: Result := Result + 'Invalid media type.'; + 158: Result := Result + 'Sector not found.'; + 159: Result := Result + 'Printer out of paper.'; + 160: Result := Result + 'Error when writing to device.'; + 161: Result := Result + 'Error when reading from device.'; + 162: Result := Result + 'Hardware failure.'; + end; +end; + function GetOSVer: String; {$IFDEF WINDOWS} var @@ -324,9 +367,29 @@ procedure TSimpleException.SetMaxStackCount(AMaxStackCount: Integer); end; procedure TSimpleException.SetLogFileName(const AValue: String); +var + ir: Word; + fe: Boolean; begin if FLogFileName = AValue then Exit; FLogFileName := AValue; + AssignFile(FLogFileHandle, FLogFileName); + fe := FileExistsUTF8(FLogFileName); + if fe then + {$I-} + Append(FLogFileHandle) + else + Rewrite(FLogFileHandle); + {$I+} + ir := IOResult; + if ir = 0 then + begin + CloseFile(FLogFileHandle); + if not fe then + Erase(FLogFileHandle); + end; + FLogFileOK := ir = 0; + FLogFileStatus := GetIOResultStr(ir); end; procedure TSimpleException.ExceptionHandler; @@ -468,20 +531,26 @@ procedure TSimpleException.CreateExceptionReport; procedure TSimpleException.SaveLogToFile(const LogMsg: String); var - f: TextFile; + ir: Word; begin - if LogFileName <> '' then + if FLogFileName = '' then Exit; + if FileExistsUTF8(FLogFileName) then + {$I-} + Append(FLogFileHandle) + else + Rewrite(FLogFileHandle); + {$I+} + ir := IOResult; + if ir = 0 then begin - AssignFile(f, LogFileName); - try - if FileExistsUTF8(LogFileName) then - Append(f) - else - Rewrite(f); - WriteLn(f, LogMsg); - finally - CloseFile(f); - end; + WriteLn(FLogFileHandle, LogMsg); + CloseFile(FLogFileHandle); + end + else + begin + FLastReport := 'Failed to write exception message to "' + (FLogFileName) + '"' + LineEnding + + ' ' + GetIOResultStr(ir) + LineEnding + + FLastReport; end; end; @@ -550,10 +619,11 @@ constructor TSimpleException.Create(const FileName: String); AFileVersion, AProductVersion: String; begin inherited Create; + FLogFileName := ''; + FLogFileOK := False; + FLogFileStatus := ''; if Trim(FileName) <> '' then - LogFileName := FileName - else - LogFileName := ChangeFileExt(Application.ExeName, '.log'); + LogFileName := FileName; InitCriticalSection(FSimpleCriticalSection); IgnoredExceptionList := TStringList.Create; FMaxStackCount := 20; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 0a6174a94..a1d4db77b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5015,8 +5015,13 @@ procedure TMainForm.ApplyOptions; if ckEnableLogging.Checked and (not Logger.Enabled) then begin Logger.Enabled := True; - FileLogger := TFileChannel.Create(edLogFileName.Text, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); - Logger.Channels.Add(FileLogger); + if MainExceptionHandler.LogFileOK then + begin + FileLogger := TFileChannel.Create(edLogFileName.Text, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); + Logger.Channels.Add(FileLogger); + end + else + Logger.SendError('Log file error ' + MainExceptionHandler.LogFileStatus + '"' + edLogFileName.Text + '"'); Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); St := TStringList.Create; try @@ -5030,8 +5035,11 @@ procedure TMainForm.ApplyOptions; if (not ckEnableLogging.Checked) and (Logger.Enabled) then begin Logger.Enabled := False; - Logger.Channels.Remove(FileLogger); - FreeAndNil(FileLogger); + if Assigned(FileLogger) then + begin + Logger.Channels.Remove(FileLogger); + FreeAndNil(FileLogger); + end; end; //languages diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index fc54c1528..585616ac5 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -63,13 +63,16 @@ Application.Title := 'Free Manga Downloader'; RequireDerivedFormResource := True; Logger.Enabled := False; - InitSimpleExceptionHandler; + InitSimpleExceptionHandler(LogFileName); if EnableLogging then begin Logger.Enabled := True; - FileLogger := TFileChannel.Create(LogFileName, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); - Logger.Channels.Add(FileLogger); - Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); + if MainExceptionHandler.LogFileOK then + begin + FileLogger := TFileChannel.Create(LogFileName, [fcoShowHeader, fcoShowPrefix, fcoShowTime]); + Logger.Channels.Add(FileLogger); + Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); + end; s := TStringList.Create; try s.AddText(SimpleException.GetApplicationInfo); From d03ecac118fe5c6204e169f5b89b80ea2b4d9351 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 14 Aug 2017 03:08:53 +0800 Subject: [PATCH 1874/2794] added logger helper for strings --- baseunits/SimpleException/SimpleException.pas | 26 ++++++++++++------- mangadownloader/forms/frmMain.pas | 9 +------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index e00e6fdc8..64d2fa402 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -118,6 +118,17 @@ procedure DoneSimpleExceptionHandler; var MainExceptionHandler: TSimpleException; +{$IFDEF MULTILOG} +type + { TLoggerException } + + TLoggerException = class helper for TLogger + public + procedure SendExceptionStr(const AText: String; AExceptionStr: String); + procedure SendStrings(const AText: String; AValue: String); + end; +{$ENDIF} + resourcestring SExceptionDialogTitle = 'Exception Info'; SExceptionCaption = 'An error occured during program execution:'; @@ -132,23 +143,18 @@ implementation uses InterfaceBase {$IF LCL_FULLVERSION >= 1080000}, LCLPlatformDef{$ENDIF}; {$IFDEF MULTILOG} -type - - { TLoggerException } - - TLoggerException = class helper for TLogger - public - procedure SendExceptionStr(const AText: String; AExceptionStr: String); - end; - { TLoggerException } procedure TLoggerException.SendExceptionStr(const AText: String; AExceptionStr: String); begin SendBuffer(ltException, AText, AExceptionStr[1], Length(AExceptionStr)); end; -{$ENDIF} +procedure TLoggerException.SendStrings(const AText: String; AValue: String); +begin + SendBuffer(ltStrings, AText, AValue[1], Length(AValue)); +end; +{$ENDIF} procedure SetMaxStackCount(const ACount: Integer); begin diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a1d4db77b..a78184a95 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4895,7 +4895,6 @@ procedure TMainForm.ApplyOptions; i: Integer; isStillHaveCurrentWebsite: Boolean = False; data: PSingleItem; - St: TStringList; begin try // general @@ -5023,13 +5022,7 @@ procedure TMainForm.ApplyOptions; else Logger.SendError('Log file error ' + MainExceptionHandler.LogFileStatus + '"' + edLogFileName.Text + '"'); Logger.Send(QuotedStrd(Application.Title)+' started with [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); - St := TStringList.Create; - try - St.AddText(SimpleException.GetApplicationInfo); - Logger.Send('Application info', St); - finally - St.Free; - end; + Logger.SendStrings('Application info', SimpleException.GetApplicationInfo); end else if (not ckEnableLogging.Checked) and (Logger.Enabled) then From b41d75f17ab93b136a7a03b393804e83d2f282c9 Mon Sep 17 00:00:00 2001 From: Havokdan <havokdan@yahoo.com.br> Date: Sun, 13 Aug 2017 21:39:57 -0300 Subject: [PATCH 1875/2794] Update for PT-BR Update of the Brazilian Portuguese translation, I hope I did it the right way, I do not know very well how to use Github. --- mangadownloader/languages/fmd.pt_BR.po | 126 ++++++------------------- 1 file changed, 31 insertions(+), 95 deletions(-) diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 4db81a7e5..4b09952db 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -8,13 +8,13 @@ msgstr "" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -"Language: pt_BR\n" -"X-Generator: Poedit 1.8.12\n" +"Language: pt-BR\n" +"X-Generator: Poedit 2.0.1\n" "Plural-Forms: \n" #: batoto.rs_serverselection msgid "Image server:" -msgstr "" +msgstr "Servidor da imagem:" #: batoto.rs_serverselectionitems msgid "" @@ -23,7 +23,7 @@ msgid "" "Image Server NA\n" "CDN (default)\n" "CDN2 (testing)\n" -msgstr "" +msgstr "Auto\nServidor da Imagem EU\nServidor da Imagem NA\nCDN (padrão)\nCDN2 (testando)\n" #: batoto.rs_showalllang msgid "Show all language" @@ -51,14 +51,7 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "" -"Auto\n" -"780x\n" -"980x\n" -"1280x\n" -"1600x\n" -"2400x\n" -"Original\n" +msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -156,9 +149,7 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "" -"Este título já está na lista de download.\n" -"Você quer baixá-lo mesmo assim\n" +msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -184,19 +175,14 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "" -"Baixar tudo\n" -"Adicionar aos favoritos\n" +msgstr "Baixar tudo\nAdicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "<none>\n" -msgstr "" -"Completo\n" -"Em Andamento\n" -"<vazio>\n" +msgstr "Completo\nEm Andamento\n<vazio>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -206,9 +192,7 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "" -"Há um problema com estes dados!\n" -"Removendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -262,11 +246,7 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "" -"%s : Caminho para o mangá\n" -"%s : Nome do capítulo\n" -"\n" -"Examplo : \"%s%s\"\n" +msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -300,11 +280,7 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "" -"Nada\n" -"Sair\n" -"Desligar\n" -"Hibernar\n" +msgstr "Nada\nSair\nDesligar\nHibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -345,15 +321,15 @@ msgstr "Sistema irá desligar em %d segundos." #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" -msgstr "" +msgstr "Vetor de Inicialização:" #: kissmanga.rs_kissmanga_key msgid "Key:" -msgstr "" +msgstr "Chave:" #: kissmanga.rs_kissmanga_usegoogledcp msgid "Use Google DCP" -msgstr "" +msgstr "Usar Google DCP" #: mangafox.rs_removewatermark msgid "Remove watermark" @@ -595,7 +571,7 @@ msgstr "Visite meu blog" #: tmainform.caption msgid "Free Manga Downloader" -msgstr "" +msgstr "Free Manga Downloader" #: tmainform.cbaddasstopped.caption msgid "Add to download list as stopped task" @@ -675,7 +651,7 @@ msgstr "Habilitar buscar em tempo real (lento em lista longas)" #: tmainform.cboptionminimizeonstart.caption msgid "Minimize on start" -msgstr "" +msgstr "Minimizar ao iniciar" #: tmainform.cboptionminimizetotray.caption msgid "Minimize to tray" @@ -695,7 +671,7 @@ msgstr "Remover nome do mangá do capítulo" #: tmainform.cboptionshowballoonhint.caption msgid "Show balloon hint" -msgstr "" +msgstr "Exibir dicas em balões" #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" @@ -711,7 +687,7 @@ msgstr "Exibir Barra de Ferramentas de Downloads" #: tmainform.cboptionshowdownloadtoolbardeleteall.caption msgid "Show \"Delete all completed tasks\" in downloads toolbar" -msgstr "" +msgstr "Exibir \"Apagar todas tarefas concluídas\" na barra de ferramentas" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -822,9 +798,7 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "" -"Meninas vestindo-se como caras, caras vestir-se como meninas.r\n" -"Rapazes se transformando em garotas, garotas se transformando em caras\n" +msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1231,16 +1205,7 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "" -"Géneros:r\n" -"- Marcado: Inclua este gênero.r\n" -"- Desmarcado: exclua esse gênero.r\n" -"- Cinzento: Não importa.r\n" -"r\n" -"Géneros Personalizados:r\n" -"- Separar vários gêneros com ','.r\n" -"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.r\n" -"- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1292,16 +1257,7 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "" -"%WEBSITE% : Nome doWebsite\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do capítulo\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"%NUMBERING% : Número\n" -"\n" -"Nota:\n" -"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1338,14 +1294,7 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do Capítulo\n" -"%FILENAME% : Nome do arquivo\n" -"\n" -"Nota:\n" -"Nome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1378,20 +1327,12 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"\n" -"Nota:\n" -"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy #| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" -msgstr "Número de tarefas de download ao mesmo tempo (Máx: 8)" +msgstr "Número de tarefas baixadas ao mesmo tempo" #: tmainform.lboptionmaxretry.caption #| msgid "Number of retry times if tasks have download problems (0 = always retry)" @@ -1399,10 +1340,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Número de tentativas de repetição se as tarefas tiverem problemas de download (-1 = sempre tentar novamente)" #: tmainform.lboptionmaxthread.caption -#, fuzzy #| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" -msgstr "Número de arquivos baixados por tarefa ao mesmo tempo (Máx: 32)" +msgstr "Número de arquivos baixados por tarefa ao mesmo tempo" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -1441,7 +1381,7 @@ msgstr "Renomear dígitos" #: tmainform.lboptionretryfailedtask.caption msgid "Number of retry times if task failed" -msgstr "" +msgstr "Número de tentativas se a tarefa falhar" #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" @@ -1488,7 +1428,7 @@ msgstr "Abortar" #: tmainform.michapterlistascending.caption msgid "Ascending" -msgstr "" +msgstr "Ascendente" #: tmainform.michapterlistcheckall.caption msgctxt "tmainform.michapterlistcheckall.caption" @@ -1501,7 +1441,7 @@ msgstr "Marcar selecionado" #: tmainform.michapterlistdescending.caption msgid "Descending" -msgstr "" +msgstr "Descendente" #: tmainform.michapterlistfilter.caption msgctxt "tmainform.michapterlistfilter.caption" @@ -1824,7 +1764,7 @@ msgstr "Filtros" #: tmainform.tsinfomanga.caption msgid "Info" -msgstr "" +msgstr "Info" #: tmainform.tsinformation.caption msgid "Manga Info" @@ -1947,14 +1887,13 @@ msgid "&Add to queue" msgstr "&Adic. à fila" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" #: tselectdirectoryform.caption msgid "Select directory" -msgstr "" +msgstr "Selecionar Diretório" #: tshutdowncounterform.btabort.caption msgid "&Abort" @@ -1976,9 +1915,7 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "" -"Nova versão encontrada! Você quer atualizar agora?\n" -"FMD irá fechar para terminar a atualização.\n" +msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "twebsiteoptionadvancedform.menuitem1.caption" @@ -2246,4 +2183,3 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" - From c8a76def3d0c5690ccb9459c57beba5409a8ffd8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Aug 2017 06:10:11 +0800 Subject: [PATCH 1876/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 5b8ec6520..f415cd42b 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 5b8ec652081d7b342f6245ad77bfdced2204703d +Subproject commit f415cd42bab72b863cc8697a123b3b835a9f7e69 From dd0205f8d855582cacf2b2e2daf91483364bd23c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Aug 2017 06:11:20 +0800 Subject: [PATCH 1877/2794] mangafox, don't include new tag in chapter's title fixed #704 --- baseunits/modules/MangaFox.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index b846d3464..5b6f0a834 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -53,7 +53,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; for v in XPath('//ul[@class="chlist"]/li/div/*[self::h3 or self::h4]') do begin chapterLinks.Add(StringReplace(XPathString('a/@href', v), '1.html', '', [rfReplaceAll])); - chapterName.Add(XPathString('string-join(*/text()," ")', v)); + chapterName.Add(XPathString('string-join(.//*[not(contains(@class,"newch"))]/text()," ")', v)); end; InvertStrings([chapterLinks, chapterName]); finally From d679b3c31b8cc7ab89066c02720c84d3d6d26f55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 15 Aug 2017 06:27:13 +0800 Subject: [PATCH 1878/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index f415cd42b..99970038f 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit f415cd42bab72b863cc8697a123b3b835a9f7e69 +Subproject commit 99970038fdf92aa01763fb35d5dc6b9061295046 From 0954250ed6bcb59ef4cec9bc8319eb9db2e6acb2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Aug 2017 03:50:24 +0800 Subject: [PATCH 1879/2794] mangashiro, fixed all fixed #705 --- baseunits/modules/MangaShiro.pas | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas index 5b44b6b4a..e234d186b 100644 --- a/baseunits/modules/MangaShiro.pas +++ b/baseunits/modules/MangaShiro.pas @@ -18,7 +18,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if MangaInfo.FHTTP.GET(Module.RootURL + '/daftar-manga/') then begin Result := NO_ERROR; - XPathHREFAll('//*[@class="azindex"]//li/a', MangaInfo.FHTTP.Document, ALinks, ANames); + XPathHREFAll('//*[@class="soralist"]//a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; @@ -34,13 +34,13 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="imganime"]//img/substring-before(substring-after(@style,"(''"),"'')")')); - if title = '' then title := XPathString('//*[@class="infos9" and starts-with(.,"Judul")]/text()'); - authors := XPathString('//*[@class="infos9" and starts-with(.,"Produser")]/text()'); - genres := XPathString('//*[@class="infos9" and starts-with(.,"Genre")]/text()'); - status := MangaInfoStatusIfPos(XPathString('//*[@class="infos9" and starts-with(.,"Status")]/text()')); - summary := XPathString('//*[@class="deskripsi"]/string-join(text(),"")'); - XPathHREFtitleAll('//*[@class="chapter-list"]//li[@class="anilist"]/div[2]/a', chapterLinks, chapterName); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="imgdesc"]/img/@src')); + if title = '' then title := XPathString('//h1[@itemprop="name"]'); + authors := XPathString('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")'); + genres := XPathString('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")'); + status := MangaInfoStatusIfPos(XPathString('//div[@class="listinfo"]//li[starts-with(.,"Status")]')); + summary := XPathString('//*[@class="desc"]/string-join(.//text(),"")'); + XPathHREFAll('//div[@class="cl"]//li/span[1]/a', chapterLinks, chapterName); InvertStrings([chapterLinks, chapterName]); finally Free; @@ -61,7 +61,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('//*[@class="readmanga"]//img/@src', Document, PageLinks); + XPathStringAll('//*[@id="readerarea"]//img/@src', Document, PageLinks); end; end; end; From 56eeef14f7957f00639565c291d377a32c76c817 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 16 Aug 2017 04:02:39 +0800 Subject: [PATCH 1880/2794] Bump version 0.9.124.0 --- changelog.txt | 12 ++++++++++-- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index 1ee7ad1a9..a09ff05bb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,16 +4,24 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.124.0 (16-08-2017) +[*] MangaShiro: fixed all +[*] MangaFox: remove "new" from chapter's title +[*] Update Portuguese (Brazil) translation by Havokdan +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.123.0...0.9.124.0 + 0.9.123.0 (13-08-2017) [+] Added option for auto retry failed task [*] MangaInn: fixed chapter name +[*] Update Spanish translation by Mariolr39 [*] Various changes and bug fixes -Full changes: https://github.com/riderkick/FMD/compare/0.9.123.0...0.9.123.0 +Full changes: https://github.com/riderkick/FMD/compare/0.9.122.0...0.9.123.0 0.9.122.0 (02-08-2017) [*] MangaAe: fixed all [*] Tumangaonline: fixed load manhwa -[*] MangaIn: fixed all +[*] MangaInn: fixed all [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.121.0...0.9.122.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6d903e753..3e976ce7c 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="123"/> + <RevisionNr Value="124"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 1249866e6..9306debca 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.123.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.123.0/fmd_0.9.123.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.123.0/fmd_0.9.123.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.123.0/fmd_0.9.123.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.123.0/fmd_0.9.123.0_Win64.7z +VERSION=0.9.124.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.124.0/fmd_0.9.124.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.124.0/fmd_0.9.124.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.124.0/fmd_0.9.124.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.124.0/fmd_0.9.124.0_Win64.7z From a62838189071a11f5f1b811091a2b712ad75ef19 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 17 Aug 2017 08:10:29 +0800 Subject: [PATCH 1881/2794] heymanga, handle download directly, try onerror.src #696 --- baseunits/modules/HeyMangaXyz.pas | 62 +++++++++++++------------------ 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index 843ea27d4..9c2ba18d1 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -29,8 +29,6 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -100,47 +98,37 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do - begin + with DownloadThread, DownloadThread.Task.Container do begin PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL) + '1') then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('//select[@id="fuzetsu_list"]/option').Count - 1; - for v in XPath('//picture/img') do - PageLinks.Add(v.toNode.getAttribute('src')); - finally - Free; - end; - end; + Result := FHTTP.GET(FillHost(Module.RootURL, AURL) + '1'); + if not Result then Exit; + XPathStringAll('//select[@id="fuzetsu_list"]/option[@value]/concat('+ QuotedStr(AURL) +',@value)', FHTTP.Document, PageLinks); end; end; -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + + function downloadandsave(u: String): Boolean; + begin + if u = '' then Exit(False); + if LeftStr(u, 2) = '//' then u := 'https:' + u; + Result := DownloadThread.FHTTP.GET(u); + if Result then + Result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; + end; + begin Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - if GET(FillHost(Module.RootURL, AURL) + IncStr(DownloadThread.WorkId)) then - begin - Result := True; - s := XPathString('//img[@id="img-content"]/@src', Document); - if LeftStr(s, 2) = '//' then - s := 'https:' + s; - PageLinks[DownloadThread.WorkId] := s; - end; + if not DownloadThread.FHTTP.GET(FillHost(Module.RootURL, AURL)) then Exit; + with TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document) do + try + Result := downloadandsave(XPathString('//img[@id="img-content"]/@src')); + if (Result = False) and (DownloadThread.IsTerminated = False) then + Result := downloadandsave(XPathString('//img[@id="img-content"]/@onerror/substring-before(substring-after(.,"''"),"''")')); + finally + Free; end; end; @@ -154,7 +142,7 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; + OnDownloadImage := @DownloadImage; end; end; From dbac1186148cdd281aca9552cad5680ea29574e0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 19 Aug 2017 17:56:41 +0800 Subject: [PATCH 1882/2794] always check for log file --- baseunits/SimpleException/SimpleException.pas | 2 +- mangadownloader/forms/frmMain.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index 64d2fa402..f59ebeb90 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -377,7 +377,7 @@ procedure TSimpleException.SetLogFileName(const AValue: String); ir: Word; fe: Boolean; begin - if FLogFileName = AValue then Exit; + // always check for log file in case something changed at runtime (permission/disk removed) FLogFileName := AValue; AssignFile(FLogFileHandle, FLogFileName); fe := FileExistsUTF8(FLogFileName); diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a78184a95..ca5e533d6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5027,12 +5027,12 @@ procedure TMainForm.ApplyOptions; else if (not ckEnableLogging.Checked) and (Logger.Enabled) then begin - Logger.Enabled := False; if Assigned(FileLogger) then begin Logger.Channels.Remove(FileLogger); FreeAndNil(FileLogger); end; + Logger.Enabled := False; end; //languages From 0d019cce47c7c3034d496ac15b2dd19dd8782fa9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 20 Aug 2017 15:19:09 +0800 Subject: [PATCH 1883/2794] downloadsmanager, fixed faied chapters always marked finish --- baseunits/uDownloadsManager.pas | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 9bb9b6c10..150dc75e9 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1115,11 +1115,10 @@ procedure TTaskThread.Execute; if Trim(Container.CustomFileName) = '' then Container.CustomFileName := DEFAULT_FILENAME_CUSTOMRENAME; + while container.ChaptersStatus.Count < Container.CurrentDownloadChapterPtr - 1 do + Container.ChaptersStatus.Add('D'); while Container.ChaptersStatus.Count < Container.ChapterLinks.Count do Container.ChaptersStatus.Add('P'); - if Container.CurrentDownloadChapterPtr > 1 then - for j := 0 to Container.CurrentDownloadChapterPtr - 1 do - Container.ChaptersStatus[j] := 'D'; while Container.CurrentDownloadChapterPtr < Container.ChapterLinks.Count do begin From bf5d02b76709ebeb11497174bab2c58f97309e0a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 20 Aug 2017 15:55:38 +0800 Subject: [PATCH 1884/2794] added options to always start task from failed chapters --- baseunits/FMDOptions.pas | 1 + baseunits/uDownloadsManager.pas | 3 + mangadownloader/forms/frmMain.lfm | 42 +++++++---- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 4 ++ mangadownloader/languages/fmd.de.po | 5 ++ mangadownloader/languages/fmd.el_GR.po | 5 ++ mangadownloader/languages/fmd.en.po | 6 ++ mangadownloader/languages/fmd.es.po | 9 +++ mangadownloader/languages/fmd.id_ID.po | 5 ++ mangadownloader/languages/fmd.pl_PL.po | 5 ++ mangadownloader/languages/fmd.po | 5 ++ mangadownloader/languages/fmd.pt_BR.po | 99 ++++++++++++++++++++++---- mangadownloader/languages/fmd.ru_RU.po | 5 ++ 14 files changed, 166 insertions(+), 29 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index b0c1773cc..8612958fd 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -128,6 +128,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionMaxRetry: Integer = 5; OptionConnectionTimeout: Integer = 30; OptionRetryFailedTask: Integer = 1; + OptionAlwaysStartTaskFromFailedChapters: Boolean = False; // view OptionEnableLoadCover: Boolean = False; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 150dc75e9..6757b84a9 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1120,6 +1120,9 @@ procedure TTaskThread.Execute; while Container.ChaptersStatus.Count < Container.ChapterLinks.Count do Container.ChaptersStatus.Add('P'); + if OptionAlwaysStartTaskFromFailedChapters and (Container.CurrentDownloadChapterPtr <> 0) then + Container.CurrentDownloadChapterPtr := 0; + while Container.CurrentDownloadChapterPtr < Container.ChapterLinks.Count do begin while Container.ChaptersStatus[Container.CurrentDownloadChapterPtr] = 'D' do diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 6fd7d5d58..140b1fcde 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2561,7 +2561,7 @@ object MainForm: TMainForm ClientWidth = 761 object pcOptions: TPageControl Left = 0 - Height = 420 + Height = 400 Top = 4 Width = 761 ActivePage = tsGeneral @@ -2576,7 +2576,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 object cbOptionMinimizeToTray: TCheckBox AnchorSideLeft.Control = seOptionNewMangaTime @@ -2833,7 +2833,7 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 object cbOptionShowDownloadToolbar: TCheckBox Left = 4 @@ -2959,31 +2959,31 @@ object MainForm: TMainForm end object tsConnections: TTabSheet Caption = 'Connections' - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 object sbDownloadConnections: TScrollBox Left = 0 - Height = 392 + Height = 372 Top = 0 Width = 753 HorzScrollBar.Page = 455 - VertScrollBar.Page = 295 + VertScrollBar.Page = 334 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 TabOrder = 0 object cbOptionUseProxy: TCheckBox - AnchorSideLeft.Control = seOptionRetryFailedTask - AnchorSideTop.Control = seOptionRetryFailedTask + AnchorSideLeft.Control = ckOptionsAlwaysStartTaskFromFailedChapters + AnchorSideTop.Control = ckOptionsAlwaysStartTaskFromFailedChapters AnchorSideTop.Side = asrBottom Left = 4 Height = 19 - Top = 159 + Top = 198 Width = 71 BorderSpacing.Top = 20 Caption = 'Use proxy' @@ -2997,7 +2997,7 @@ object MainForm: TMainForm AnchorSideTop.Side = asrBottom Left = 4 Height = 105 - Top = 182 + Top = 221 Width = 426 AutoSize = True Caption = 'Proxy config' @@ -3299,26 +3299,38 @@ object MainForm: TMainForm TabOrder = 6 Value = 1 end + object ckOptionsAlwaysStartTaskFromFailedChapters: TCheckBox + AnchorSideLeft.Control = seOptionRetryFailedTask + AnchorSideTop.Control = seOptionRetryFailedTask + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 19 + Top = 159 + Width = 216 + BorderSpacing.Top = 20 + Caption = 'Always start task from failed chapters' + TabOrder = 7 + end end end object tsSaveTo: TTabSheet Caption = 'Save to' - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 object sbSaveTo: TScrollBox Left = 0 - Height = 392 + Height = 372 Top = 0 Width = 753 HorzScrollBar.Page = 198 - VertScrollBar.Page = 392 + VertScrollBar.Page = 372 Align = alClient BorderStyle = bsNone ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 736 TabOrder = 0 object rgOptionCompress: TRadioGroup diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index b7459b14d..5eba8c9fa 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -178,6 +178,7 @@ {"hash":34874153,"name":"tmainform.lboptionmaxretry.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,114,101,116,114,121,32,116,105,109,101,115,32,105,102,32,116,97,115,107,115,32,104,97,118,101,32,100,111,119,110,108,111,97,100,32,112,114,111,98,108,101,109,115,32,40,45,49,32,61,32,97,108,119,97,121,115,32,114,101,116,114,121,41],"value":"Number of retry times if tasks have download problems (-1 = always retry)"}, {"hash":161967481,"name":"tmainform.lboptionconnectiontimeout.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,32,116,105,109,101,111,117,116,32,40,115,101,99,111,110,100,115,41],"value":"Connection timeout (seconds)"}, {"hash":225523060,"name":"tmainform.lboptionretryfailedtask.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,114,101,116,114,121,32,116,105,109,101,115,32,105,102,32,116,97,115,107,32,102,97,105,108,101,100],"value":"Number of retry times if task failed"}, +{"hash":168552227,"name":"tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption","sourcebytes":[65,108,119,97,121,115,32,115,116,97,114,116,32,116,97,115,107,32,102,114,111,109,32,102,97,105,108,101,100,32,99,104,97,112,116,101,114,115],"value":"Always start task from failed chapters"}, {"hash":160200703,"name":"tmainform.tssaveto.caption","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":96652067,"name":"tmainform.rgoptioncompress.caption","sourcebytes":[83,97,118,101,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,115,32,97,115],"value":"Save downloaded chapters as"}, {"hash":206060487,"name":"tmainform.gboptionrenaming.caption","sourcebytes":[82,101,110,97,109,105,110,103],"value":"Renaming"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ca5e533d6..132d2d773 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -68,6 +68,7 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + ckOptionsAlwaysStartTaskFromFailedChapters: TCheckBox; ckEnableLogging: TCheckBox; edDownloadsSearch: TEditButton; edFavoritesSearch: TEditButton; @@ -4686,6 +4687,7 @@ procedure TMainForm.LoadOptions; seOptionMaxRetry.Value := ReadInteger('connections', 'Retry', OptionMaxRetry);; seOptionConnectionTimeout.Value := ReadInteger('connections', 'ConnectionTimeout', OptionConnectionTimeout); seOptionRetryFailedTask.Value := ReadInteger('connections', 'NumberOfAutoRetryFailedTask', OptionRetryFailedTask); + ckOptionsAlwaysStartTaskFromFailedChapters.Checked := ReadBool('connections', 'AlwaysStartFromFailedChapters', OptionAlwaysStartTaskFromFailedChapters); // proxy cbOptionUseProxy.Checked := ReadBool('connections', 'UseProxy', False); @@ -4826,6 +4828,7 @@ procedure TMainForm.SaveOptions; WriteInteger('connections', 'Retry', seOptionMaxRetry.Value); WriteInteger('connections', 'ConnectionTimeout', seOptionConnectionTimeout.Value); WriteInteger('connections', 'NumberOfAutoRetryFailedTask', seOptionRetryFailedTask.Value); + WriteBool('connections', 'AlwaysRetruFailedChaptersOnStart', ckOptionsAlwaysStartTaskFromFailedChapters.Checked); // proxy WriteBool('connections', 'UseProxy', cbOptionUseProxy.Checked); @@ -4970,6 +4973,7 @@ procedure TMainForm.ApplyOptions; OptionConnectionTimeout := seOptionConnectionTimeout.Value; SetDefaultTimeoutAndApply(OptionConnectionTimeout * 1000); OptionRetryFailedTask := seOptionRetryFailedTask.Value; + OptionAlwaysStartTaskFromFailedChapters := ckOptionsAlwaysStartTaskFromFailedChapters.Checked; // proxy if cbOptionUseProxy.Checked then diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 61319d055..575115054 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -1071,6 +1071,11 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Diese Arbeit beinhaltet in der Regel intime Beziehungen zwischen Frauen." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Eingabe individueller Genres, durch Komma getrennt" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 55e73149d..04a60cf8d 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1126,6 +1126,11 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Το έργο αυτό συνήθως περιλαμβάνει στενές σχέσεις μεταξύ γυναικών." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Εισαγωγή προσαρμοσμένων ειδών, χωρισμένα με κόμμα" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index dd93ac321..e629f181f 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1071,6 +1071,12 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "This work usually involves intimate relationships between women." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +#| msgid "Always start from failed chapters when task start" +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "Always start task from failed chapters" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Input custom genres, separated by comma" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index a206ce5e9..a20538e0e 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1059,6 +1059,11 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Este trabajo involucra generalmente relaciones íntimas entre mujeres." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Ingresa géneros personalizados, separados por coma." @@ -1422,6 +1427,10 @@ msgstr "Tipo" msgid "Rename digits" msgstr "Renombrar Dígitos" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 9f4185af5..0e4e1aea1 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1059,6 +1059,11 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Biasanya melibatkan hubungan yang intim antara sesama perempuan." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "Selalu mulai undudah dari bab yang gagal" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Masukan genre pilihan, dipisahkan dengan koma" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 118857734..16b95caf9 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1066,6 +1066,11 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Dzieło to obejmuje zazwyczaj intymne relacje między kobietami." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Lista gatunków oddzielone przecinkami" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index d9bcd4b3d..0c770d22c 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1017,6 +1017,11 @@ msgstr "" msgid "This work usually involves intimate relationships between women." msgstr "" +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 4b09952db..d0c67aeef 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -23,7 +23,12 @@ msgid "" "Image Server NA\n" "CDN (default)\n" "CDN2 (testing)\n" -msgstr "Auto\nServidor da Imagem EU\nServidor da Imagem NA\nCDN (padrão)\nCDN2 (testando)\n" +msgstr "" +"Auto\n" +"Servidor da Imagem EU\n" +"Servidor da Imagem NA\n" +"CDN (padrão)\n" +"CDN2 (testando)\n" #: batoto.rs_showalllang msgid "Show all language" @@ -51,7 +56,14 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -149,7 +161,9 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" +msgstr "" +"Este título já está na lista de download.\n" +"Você quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -175,14 +189,19 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "Baixar tudo\nAdicionar aos favoritos\n" +msgstr "" +"Baixar tudo\n" +"Adicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "<none>\n" -msgstr "Completo\nEm Andamento\n<vazio>\n" +msgstr "" +"Completo\n" +"Em Andamento\n" +"<vazio>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -192,7 +211,9 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "" +"Há um problema com estes dados!\n" +"Removendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -246,7 +267,11 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" +msgstr "" +"%s : Caminho para o mangá\n" +"%s : Nome do capítulo\n" +"\n" +"Examplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -280,7 +305,11 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "Nada\nSair\nDesligar\nHibernar\n" +msgstr "" +"Nada\n" +"Sair\n" +"Desligar\n" +"Hibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -798,7 +827,9 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" +msgstr "" +"Meninas vestindo-se como caras, caras vestir-se como meninas.\n" +"Rapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1040,6 +1071,11 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Este trabalho geralmente envolve relações íntimas entre as mulheres." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Entrar gêneros personalizados, separados por vírgula" @@ -1205,7 +1241,16 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "" +"Géneros:\n" +"- Marcado: Inclua este gênero.\n" +"- Desmarcado: exclua esse gênero.\n" +"- Cinzento: Não importa.\n" +"\n" +"Géneros Personalizados:\n" +"- Separar vários gêneros com ','.\n" +"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n" +"- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1257,7 +1302,16 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Nome doWebsite\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do capítulo\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"%NUMBERING% : Número\n" +"\n" +"Nota:\n" +"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1294,7 +1348,14 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do Capítulo\n" +"%FILENAME% : Nome do arquivo\n" +"\n" +"Nota:\n" +"Nome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1327,7 +1388,14 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"\n" +"Nota:\n" +"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption #| msgid "Number of downloaded tasks at the same time (Max: 8)" @@ -1915,7 +1983,9 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" +msgstr "" +"Nova versão encontrada! Você quer atualizar agora?\n" +"FMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "twebsiteoptionadvancedform.menuitem1.caption" @@ -2183,3 +2253,4 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" + diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index a5a214d76..20c3d9c7c 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -1058,6 +1058,11 @@ msgstr "Юри" msgid "This work usually involves intimate relationships between women." msgstr "Обычно связано с интимными отношениями между женщинами." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Ввод пользовательских жанров, разделенных запятой" From 27aab9ef9f9090392fca71d390df18dcb8fcd064 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 20 Aug 2017 16:06:10 +0800 Subject: [PATCH 1885/2794] changed optionsalwaysstarttaskfromfailedchapters default to true --- baseunits/FMDOptions.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 8612958fd..f53886454 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -128,7 +128,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionMaxRetry: Integer = 5; OptionConnectionTimeout: Integer = 30; OptionRetryFailedTask: Integer = 1; - OptionAlwaysStartTaskFromFailedChapters: Boolean = False; + OptionAlwaysStartTaskFromFailedChapters: Boolean = True; // view OptionEnableLoadCover: Boolean = False; From 2a045e2b1fcfb10f357a6099f730b1346c6b6aa8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Aug 2017 03:43:35 +0800 Subject: [PATCH 1886/2794] downloadsmanager, added general exception info --- baseunits/uDownloadsManager.pas | 39 +++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 6757b84a9..90a526ed8 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -98,6 +98,8 @@ TTaskThread = class(TBaseThread) function FailedChaptersExist: Boolean; // show notification when download completed procedure ShowBalloonHint; + // general exception info + function GetExceptionInfo: String; public //additional parameter httpCookies: String; @@ -385,15 +387,7 @@ procedure TDownloadThread.Execute; except on E: Exception do begin - E.Message := E.Message + LineEnding + - ' In TDownloadThread.Execute : ' + GetEnumName(TypeInfo(TFlagType), Integer(Task.Flag)) + - LineEnding + - ' Website : ' + Task.Container.DownloadInfo.Website + LineEnding + - ' URL : ' + FillMangaSiteHost(Task.Container.MangaSiteID, - Task.Container.ChapterLinks[Task.Container.CurrentDownloadChapterPtr]) + LineEnding + - ' Title : ' + Task.Container.DownloadInfo.title + LineEnding + - ' Chapter : ' + Task.Container.ChapterName[Task.Container.CurrentDownloadChapterPtr] + - LineEnding; + E.Message := E.Message + LineEnding + ' In TDownloadThread.Execute' + LineEnding + Task.GetExceptionInfo; MainForm.ExceptionHandler(Self, E); end; end; @@ -808,7 +802,10 @@ function TTaskThread.Compress: Boolean; Result := uPacker.Execute; except on E: Exception do + begin + E.Message := E.Message + LineEnding + ' In TTaskThread.Compress' + LineEnding + GetExceptionInfo; MainForm.ExceptionHandler(Self, E); + end; end; uPacker.Free; end; @@ -849,6 +846,16 @@ procedure TTaskThread.ShowBalloonHint; Synchronize(SyncShowBallonHint); end; +function TTaskThread.GetExceptionInfo: String; +begin + Result := + ' Flag : ' + GetEnumName(TypeInfo(TFlagType), Integer(Flag)) + LineEnding + + ' Website : ' + Container.DownloadInfo.Website + LineEnding + + ' Title : ' + Container.DownloadInfo.title + LineEnding + + ' Chapterlink : ' + Container.ChapterLinks[Container.CurrentDownloadChapterPtr] + LineEnding + + ' Chaptername : ' + Container.ChapterName[Container.CurrentDownloadChapterPtr] + LineEnding; +end; + function TDownloadThread.DownloadImage: Boolean; var workFilename, @@ -976,6 +983,7 @@ procedure TTaskThread.CheckOut; begin if Terminated then Exit; + try //load advanced config if any mt := advancedfile.ReadInteger('DownloadMaxThreadsPerTask', Container.DownloadInfo.Website, -1); @@ -1019,9 +1027,8 @@ procedure TTaskThread.CheckOut; Sleep(SOCKHEARTBEATRATE); if (not Terminated) and (Threads.Count < currentMaxThread) then - begin - EnterCriticalsection(FCS_THREADS); try + EnterCriticalsection(FCS_THREADS); if Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxThread then Exit; Modules.IncActiveConnectionCount(Container.ModuleId); Threads.Add(TDownloadThread.Create); @@ -1038,6 +1045,13 @@ procedure TTaskThread.CheckOut; finally LeaveCriticalsection(FCS_THREADS); end; + + except + on E: Exception do + begin + E.Message := E.Message + LineEnding + ' In TTaskThread.Checkout' + LineEnding + GetExceptionInfo; + MainForm.ExceptionHandler(Self, E); + end; end; end; @@ -1333,7 +1347,10 @@ procedure TTaskThread.Execute; ShowBalloonHint; except on E: Exception do + begin + E.Message := E.Message + LineEnding + ' In TTaskThread.Execute' + LineEnding + GetExceptionInfo; MainForm.ExceptionHandler(Self, E); + end; end; end; From 217b8145653850c3762c47bd0fc70286cd52332d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Aug 2017 03:55:37 +0800 Subject: [PATCH 1887/2794] favorites tools buttons layout --- mangadownloader/forms/frmMain.lfm | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 140b1fcde..cc72a022f 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2353,11 +2353,12 @@ object MainForm: TMainForm end object btFavoritesImport: TBitBtn AnchorSideTop.Control = edFavoritesSearch + AnchorSideTop.Side = asrCenter AnchorSideRight.Control = vtFavorites AnchorSideRight.Side = asrBottom Left = 661 Height = 26 - Top = 4 + Top = 2 Width = 100 Anchors = [akTop, akRight] AutoSize = True @@ -2403,16 +2404,16 @@ object MainForm: TMainForm TabOrder = 2 end object btCancelFavoritesCheck: TSpeedButton + AnchorSideLeft.Control = btFavoritesCheckNewChapter AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btFavoritesCheckNewChapter - AnchorSideRight.Control = btFavoritesImport AnchorSideBottom.Control = btFavoritesCheckNewChapter AnchorSideBottom.Side = asrBottom - Left = 641 + Left = 321 Height = 26 - Top = 4 + Top = 2 Width = 20 - Anchors = [akTop, akRight, akBottom] + Anchors = [akTop, akLeft, akBottom] AutoSize = True Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -2454,15 +2455,17 @@ object MainForm: TMainForm OnClick = btCancelFavoritesCheckClick end object btFavoritesCheckNewChapter: TBitBtn - AnchorSideLeft.Control = btCancelFavoritesCheck + AnchorSideLeft.Control = edFavoritesSearch + AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = edFavoritesSearch + AnchorSideTop.Side = asrCenter AnchorSideRight.Control = btCancelFavoritesCheck - Left = 476 + Left = 156 Height = 26 - Top = 4 + Top = 2 Width = 165 - Anchors = [akTop, akRight] AutoSize = True + BorderSpacing.Left = 6 Caption = 'Check for new chapter' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 From ca4e9ea2beeab174587b8755855986c603341889 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 21 Aug 2017 05:13:04 +0800 Subject: [PATCH 1888/2794] exception dialog layout with anchors --- .../SimpleException/SimpleExceptionForm.lfm | 817 +++++++++--------- .../SimpleException/SimpleExceptionForm.pas | 45 +- 2 files changed, 424 insertions(+), 438 deletions(-) diff --git a/baseunits/SimpleException/SimpleExceptionForm.lfm b/baseunits/SimpleException/SimpleExceptionForm.lfm index 569da4fbc..6446cceeb 100644 --- a/baseunits/SimpleException/SimpleExceptionForm.lfm +++ b/baseunits/SimpleException/SimpleExceptionForm.lfm @@ -1,435 +1,416 @@ object SimpleExceptionForm: TSimpleExceptionForm Left = 410 - Height = 226 + Height = 250 Top = 270 - Width = 483 + Width = 580 HorzScrollBar.Page = 445 HorzScrollBar.Range = 445 VertScrollBar.Page = 121 VertScrollBar.Range = 121 BorderIcons = [biSystemMenu] Caption = 'SimpleExceptionForm' - ClientHeight = 226 - ClientWidth = 483 + ClientHeight = 250 + ClientWidth = 580 FormStyle = fsSystemStayOnTop OnClose = FormClose OnCreate = FormCreate OnShow = FormShow Position = poDesktopCenter - LCLVersion = '1.5' object PanelTop: TPanel Left = 0 - Height = 60 + Height = 54 Top = 0 - Width = 483 - Align = alTop + Width = 217 AutoSize = True BevelOuter = bvNone - ClientHeight = 60 - ClientWidth = 483 + ClientHeight = 54 + ClientWidth = 217 Color = clWindow ParentColor = False TabOrder = 0 - object PanelExceptionIcon: TPanel - Left = 0 - Height = 60 - Top = 0 - Width = 60 - Align = alLeft - BevelOuter = bvNone - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ClientHeight = 60 - ClientWidth = 60 - TabOrder = 0 - object IconException: TImage - Left = 6 - Height = 48 - Top = 6 - Width = 48 - AntialiasingMode = amOn - Align = alTop - Center = True - Picture.Data = { - 1754506F727461626C654E6574776F726B47726170686963BA24000089504E47 - 0D0A1A0A0000000D49484452000000300000003008060000005702F987000000 - 097048597300000B1300000B1301009A9C18000000206348524D00007A250000 - 80830000F9FF000080E9000075300000EA6000003A980000176F925FC5460000 - 2440494441547801003024CFDB01FFFFFF000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000400000000ED6C4E00000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000100000003E0000003E00 - 00002E0000001E000000160000000B00000000000000F5000000EA000000E200 - 0000D2000000C3000000C1000000F00000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000001394B2000400000000FFFF00000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000007000000540000005C000000450000000300000000 - 0000000000000000000000000000000000000000000000060000001100000027 - 0000004500000073000000FD000000BC000000A3000000AC000000F900000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000200000000FF00FF00FF00FF00FF00FF - 00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF - 00FF00FF09FF00FF72FF00FFDDFF00FFA4FF00FF48FF00FF03FF00FF00FF00FF - 00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF - 00FF00FF00FF00FF00FF00FF03FF00FF47FF00FFA4FF00FFDEFF00FF72FF00FF - 09FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF - 00FF00FF00FF00FF00FF00FF00000000000400000000FFFF0000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 004900000093000000230000000000000000000000000000000003121500051A - 1F00030F1200020A0B00010709000103040000000000FFFDFC00FFF9F700FEF6 - F500FDF1EE00FBE6E100FDEEEB0000000000000000000000001A0000008D0000 - 006A0000006D000000B700000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000400000000FFFFFF000000000000 - 0000000000000000000000000000000000000000000000000000080000008E00 - 000069000000000000000000000000020A0D0007262C00061D23000104050000 - 0000000000000000000000000000000000000000000000010406000104060002 - 0B0F0004151A0007242C00FFFDFC00FAE2DC00F9DBD400FEF5F3000000000000 - 000023000000B60000009700000072000000F800000000000000000000000000 - 000000000000000000000000000000000000000400000000FFFFFF0000000000 - 000000000000000000000000000000000000000000000017000000B400000034 - 0000000000000000020809000A303900051A1E000000000000000000FFF6F300 - FEF1EE00FFF2EF00FFFAF80000FCFB0000FDFD00000000000003030000040500 - 01060800010E1100020F1200010A0B000721260007212600FBE6E200F6D0C700 - FEF8F7000000000000000069000000370000004A000000E90000000000000000 - 00000000000000000000000000000000000000000400000000FEFFFF00000000 - 000000000000000000000000000000000000000022000000B900000024000000 - 0000000000072228000A2B330001050600FFFF0000FEEBE700FDE6E000FFF5F3 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000ECE80000000000010B0D00031A20000215190004191E000D1418 - 00F6D5CD00F9DED8000000000000000032000000C400000046000000DF000000 - 0000000000000000000000000000000000000000000400000000FFFF00000000 - 00000000000000000000000000000000001C000000BD00000020000000000000 - 00000C343C00071F240000000000FEEEEA00FCDED800FFF9F700000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000FFF4F200FEDAD20001E1DB00042228000212 - 15000B30380004111500F4CCC3000000000000000024000000BE0000003D0000 - 00E400000000000000000000000000000000000000000400000000FEFFFF0000 - 00000000000000000000000000000A000000B20000002000000000000000000E - 394300061A1E00FFFF0000FCDAD200FDEBE70000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000FFF8F600FAD6CE0003 - 15190004252C00061E23000C040500F2C7BD000000000000000020000000B200 - 00003C000000F6000000000000000000000000000000000400000000FFFFFF00 - 000000000000000000000000000000900000003100000000000000000F3A4400 - 06191D00FFFBFA00FBD9D200FEEFEC0000000000000000000000000000000000 - 000000000000000011859E000000000000000000000000000000000000000000 - 0000000000000000EF7B62000000000000000000000000000000000000000000 - FCE9E600FEFAFA0005272E0006191D000E394300F1C6BC000000000000000031 - 0000009100000065000000000000000000000000000000000200000000FEFFFF - 00FEFFFF00FEFFFF00FEFFFF4AFEFFFF65FEFFFF00FEFFFF000C343D0005181C - 00FEFAF800FAD6CE00FDEEEA00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE - 00FFFFFE00FFFFFE000000000000000000000000000000000000000000000000 - 000000000000000000FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE - 00FFFFFE00FDEEEA00FAD6CE00FEFAF80005181C000C343D00FEFFFF00FEFFFF - 00FEFFFF64FEFFFF4AFEFFFF00FEFFFF00FEFFFF00000000000200000000FFFF - FF00FFFFFF00FFFFFF08FFFFFF92FFFFFF00FFFFFF0009232900081E2300FFFE - FE00FAD8D100FDF0ED00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000 - 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FDF0ED00FAD8D100FFFEFE00081E230009242A00FFFF - FF00FFFFFF00FFFFFF93FFFFFF08FFFFFF00FFFFFF00000000000200000000FE - FFFF00FEFFFF00FEFFFF69FEFFFF23FEFFFF00000709000A2A3100FFFFFF00FA - D9D100FDEEEB00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FF - FEFE00FFFEFE00FFFEFE00000000000000000000000000000000000000000000 - 0000000000000000000000FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FF - FEFE00FFFEFE00FFFEFE00FFFEFE00FDEEEB00FAD9D100FFFFFF000A29300000 - 080900FEFFFF00FEFFFF22FEFFFF69FEFFFF00FEFFFF00000000000200000000 - FEFEFF00FEFEFF07FEFEFF74FEFEFF00FEFEFF000D30370001040500FDECE800 - FCE8E500FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00 - FFFEFF00FFFEFF00FFFEFF000000000000000000000000000000000000000000 - 000000000000000000000000FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00 - FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FCE8E500FDECE80001040500 - 0D2F3700FEFEFF00FEFEFF00FEFEFF75FEFEFF08FEFEFF000000000002000000 - 00FEFFFF00FEFFFF54FEFFFF1AFEFFFF00010A0C00071A1F00FFFFFF00F8DBD4 - 00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE - 00FEFFFE00FEFFFE00FEFFFE0000000000000000000000000000000000000000 - 00000000000000000000000000FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE - 00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00F8DBD400FFFFFF - 00071A1F00020B0C00FEFFFF00FEFFFF19FEFFFF53FEFFFF0000000000020000 - 0000FFFFFF00FFFFFF5DFFFFFF00FFFFFF000C262C0000FFFF00FCE8E400FEF6 - F600FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFE - FF00FFFEFF00FFFEFF00FFFEFF00000000000000000000000000000000000000 - 0000000000000000000000000000FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFE - FF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FEF6F600FCE8 - E40000FFFF000B252C00FFFFFF00FFFFFF00FFFFFF5DFFFFFF00000000000200 - 000000FEFFFF10FEFFFF44FEFFFF00FEFFFF00091E2300FFFFFF00FAE2DD00FF - FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF - FFFE00FFFFFE00FFFFFE00FFFFFE00FFFCFB0000000000000000000000000000 - 0000000000000000000000FFFBFA00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF - FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FA - E2DD00FFFFFF00091E2300FEFFFF00FEFFFF00FEFFFF44FEFFFF100000000002 - 00000000FEFEFF3FFEFEFF03FEFEFF000511150001030300FEF5F200FDF2EF00 - FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00 - FFFEFE00FFFEFE00FFFEFE00FFFEFE00FEF1EE00000000000000000000000000 - 000000000000000000000000FEF2EF00FFFEFE00FFFEFE00FFFEFE00FFFEFE00 - FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00 - FDF2EF00FEF5F2000103030005111500FEFEFF00FEFEFF03FEFEFF3F00000000 - 0200000000FEFFFF3CFEFFFF00FEFFFF00081B1F00FFFF0000FBEDEC00FEFEFF - 00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF - 00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FDF2F0000000000000000000000000 - 00000000000000000000000000FDF2F000FEFEFF00FEFEFF00FEFEFF00FEFEFF - 00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF - 00FEFEFF00FBEDEC00FFFF0000081B1F00FEFFFF00FEFFFF00FEFFFF3D000000 - 000400000000FEFFFF290000000000000000040D0E00FF00FE00FDF1ED00FFFF - FE00000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000FDF1EE0000000000000000000000 - 0000000000000000000000000000FDF1EE00FFFFFE0000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000FDF1ED00FF1C1F00040E0F00FEFFFF0000000000000000290000 - 00000400000000FEFEFF250000000000000000040C0D0000FFFF00FDF5F300FF - FEFE000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000FCF1EF00000000000000000000 - 000000000000000000000000000000FCF0EE00FFFEFE00000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000FDF5F30000FFFF00040B0C00FEFEFF00000000000000002400 - 0000000400000000FEFFFF18000000000000000002070900FFFFFF00FEF7F700 - FFFEFE0000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000FDF1EF000000000000000000 - 00000000000000000000000000000000FDF2F000FFFEFE000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000FEF9F900FFFFFF0002060700FEFFFF000000000000000014 - 000000000400000000FEFFFE0E000000000000000001030500FFFE0000FDFBFB - 00FFFEFF00000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000000000FCEFED0000000000000000 - 0000000000000000000000000000000000FCEFED00FEFEFF0000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000FFFBFB00FFFE000000020500FEFFFE0000000000000000 - 0C000000000400000000FEFEFF000000000000000000FF00FF0000000000FFFF - FE00FFFFFE000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000FCF0ED00000000000000 - 000000000000000000000000000000000000FCF1EE00FFFFFE00000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000FFFE00FF00FF00FF00FF00FEFEFF00000000000000 - 0000000000000400000000FFFFFFF20000000E00000000FEFAFA000205050000 - 020200FFFEFE0000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000FCF1EF000000000000 - 00000000000000000000000000000000000000FCF0EE00FFFEFE000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000101020000FFFF00FEFBFA00FFFFFF000000000000 - 0000F4000000000400000000FEFFFFE80000000E00000000FBF7F50006040F00 - 00050700FEF5F500000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000000000000000FAEEEB0000000000 - 0000000000000000000000000000000000000000FAEEEB00FEFEFF0000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000002040500FFFFFF00FCF8F700FEFFFF0000000000 - 000000EC000000000400000000FEFEFFDB0000002600000000F9F2F100050C0E - 0001080A00FFFEEC000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000000000FCF1EF0000FEFE - 000002020000000000000000000000000000FEFE00FCF1EF0000FEFE00000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000001080A00FFFFFF00F9F2F100FEFEFF00000000 - 00000000DC000000000200000000FEFFFFD8FEFFFF00FEFFFF00F9F0EF0000FF - FF00030E1100FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE - FE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFCFC00FCF3 - F00000000000000000000000000000000000FCF3F100FFFCFC00FFFEFE00FFFE - FE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE - FE00FFFEFE00FFFEFE00FFFEFE00030E110000FFFF00F9F0EF00FEFFFF00FEFF - FF00FEFFFFD7000000000200000000FEFFFFC3FEFFFF00FEFFFF00F1E2DE00FF - FFFF0004131500FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF - FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FC - EFED0000000000000000000000000000000000FCEFEC00FFFFFE00FFFFFE00FF - FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF - FFFE00FFFFFE00FFFFFE00FFFFFE0004131500FFFFFF00F1E2DE00FEFFFF00FE - FFFF00FEFFFFC3000000000400000000FEFFFFC1000000FD00000003F4EBE900 - FDFBFB00020B0D00020C0F00FCF2F00000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - E79C8D00020A0C00000000000000000000000000FEF6F400FEFEFF0000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000040E1000020B0D00FDFBFB00F4EBE90000000000 - 000000FD000000C2000000000400000000FEFEFFF0000000BC00000047000000 - 00EFDEDA001225290007212600FBCFC800000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00F6DCD700000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000007212600FFFFFF00EFDEDB00FEFEFF00000000 - 00000000BD000000EF000000000400000000FEFFFF00000000A3000000470000 - 0000E9D5D20012242800071A1E00F5D7D100FEF7F50000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000134A56000205050000000000000000000000000000000000EDBAB000FEF7 - F500000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000002090B00071A1E0000FFFF00E9D5D100FEFFFF000000 - 0000000000A300000000000000000400000000FFFFFF00000000AD0000008B00 - 000019F9F3F100F0E2DF000F1D20000B2B3100F2CAC300000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000016556100030A0C0000000000000000000000000000000000EFC3BB00FD - F5F4000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000B2B3100FFFFFF00F1E3E000F9F3F1000000000000 - 0000E7000000AC00000000000000000200000000FEFFFF00FEFFFFF8FEFFFF8B - FEFFFF00FEFFFF00E3CAC500FCFAF90005171A0005191C00FEFFFE00FEFFFE00 - FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00 - FEFFFE00000000000000000000000000000000000000000000000000FFFFFE00 - FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00 - FEFFFE00FEFFFE0005191C0005171A00FCFBF900E3CAC500FEFFFF00FEFFFF00 - FEFFFF8CFEFFFFF8FEFFFF00000000000200000000FEFEFF00FEFEFF00FEFEFF - 97FEFEFFDEFEFEFF00F9F5F500E7D0CD0000FE00000D30380005121600FFFEFF - 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF - 00FFFEFF00000000000000000000000000000000000000000000000000FFFEFF - 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF - 00FFFEFF00051216000D30380000FE0000E7D0CE00F9F5F500FEFEFF00FEFEFF - DEFEFEFF96FEFEFF00FEFEFF00000000000200000000FEFFFF00FEFFFF00FEFF - FFF8FEFFFF6DFEFFFF00FEFFFF00E8D7D300EDDEDB00000102000D3239000411 - 1400FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE - FE00FFFEFE00000000000000000000000000000000000000000000000000FFFF - FF00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE - FE00041114000D32390000010200EDDEDB00E8D6D200FEFFFF00FEFFFF00FEFF - FF6EFEFFFFF8FEFFFF00FEFFFF00000000000200000000FFFFFF00FFFFFF00FF - FFFF00FFFFFFB6FFFFFF9DFFFFFF00FFFFFF00DEC4BE00F1E5E100020708000F - 363E0005161900FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF - FFFF00FFFFFF00000000000000000000000000000000000000000000000000FF - FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0005 - 1619000F363E0002070800F1E5E100DEC4BE00FFFFFF00FFFFFF00FFFFFF9FFF - FFFFB5FFFFFF00FFFFFF00FFFFFF000000000001FFFFFF00AF412B0000000000 - 00000000000000000000000A000000C500000030000000000000000025414600 - 101C1F00FFFEFE00F2CFC700F8E3DF0000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000000000000000081D2100 - 0E31390001020200F0E4E100DBBFBA000000000000000000000000D00000003B - 000000F600000000000000000000000051BFD5000200000000FFFFFF00FFFFFF - 00FFFFFF00FFFFFF00FFFFFFF6FFFFFF4DFFFFFFE1FFFFFF00FFFFFF00DABEB9 - 00EBDDDA00000101000E323A000F363F0002080A00FFFEFF00FFFEFF00FFFEFF - 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF - 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF0002080A000F363F000E323A - 0000010100EBDDDA00DABEB900FFFFFF00FFFFFF00FFFFFFE1FFFFFF4DFFFFFF - F6FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000400000000FEFFFF000000 - 0000000000000000000000000000000000E400000042000000BB000000220000 - 0000DDC4BF00F5ECEB001C30340007191C0007191C00F7E3DF00F6DBD600FBF0 - EE00000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000051012000A252A00091D210000000000FCFA - F900E4D0CC00E9D8D5000000000000000000000000DE00000045000000E40000 - 0000000000000000000000000000000000000000000001FFFFFF00AB3E280000 - 000000000000000000000000000000000000000000000000000018000000B500 - 000032000000000000000005090A0021373C00111E20000000000000000000FC - F3F100FAEAE800FBEEEB00FDF7F600FEF8F700FEFCFB00000000000204050002 - 08090003090A000512150006161800040D0F000000000000000000EFE2E000DF - C9C400FBF7F6000000000000000000000000CE0000004B000000E80000000000 - 0000000000000000000000000000000000000055C2D80001FFFFFF00A93D2800 - 0000000000000000000000000000000000000000000000000000000000000008 - 0000009100000066000000000000000000000000080D0E001A2B2E0015242600 - 0203040000000000000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000FEFDFC00EBDCDA00E6D5D200F8F3F200 - 0000000000000000000000000000009900000070000000F80000000000000000 - 000000000000000000000000000000000000000057C3D80001FFFFFF00A83C27 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000004A0000009200000023000000000000000000000000000000 - 000D151700131F2100090F1000080D0E00050909000304050000000000FDFCFB - 00FBF7F700F8F3F200F7F1F000EDE1DF00F3EBE9000000000000000000000000 - 0000000000000000DD0000006D000000B7000000000000000000000000000000 - 00000000000000000000000000000000000000000058C4D9000400000000FFFF - FF00000000000000000000000000000000000000000000000000000000000000 - 000000000000000000B6000000BF000000690000007400000019000000000000 - 0000F2EAE800F2EAE80000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00E70000008C00000097000000F7000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000000000000400000000FF - FFFF000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000F70000008E00000095000000540000005F00 - 0000420000000300000000000000000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000FD000000BE000000A100 - 0000AC000000F900000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000400000000 - FF00000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000F9000000A5000000A5 - 000000110000003F0000003B0000002A00000022000000170000000C00000000 - 000000F4000000E9000000DE000000D6000000C5000000C1000000EF00000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000001FFFFFF - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000010000 - FFFF99B3ED4DB34E9B390000000049454E44AE426082 - } - Proportional = True - Transparent = True - end + object IconException: TImage + AnchorSideLeft.Control = PanelTop + AnchorSideTop.Control = PanelTop + Left = 6 + Height = 48 + Top = 6 + Width = 48 + AntialiasingMode = amOn + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + Center = True + Picture.Data = { + 1754506F727461626C654E6574776F726B47726170686963BA24000089504E47 + 0D0A1A0A0000000D49484452000000300000003008060000005702F987000000 + 097048597300000B1300000B1301009A9C18000000206348524D00007A250000 + 80830000F9FF000080E9000075300000EA6000003A980000176F925FC5460000 + 2440494441547801003024CFDB01FFFFFF000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000400000000ED6C4E00000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000100000003E0000003E00 + 00002E0000001E000000160000000B00000000000000F5000000EA000000E200 + 0000D2000000C3000000C1000000F00000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000001394B2000400000000FFFF00000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000007000000540000005C000000450000000300000000 + 0000000000000000000000000000000000000000000000060000001100000027 + 0000004500000073000000FD000000BC000000A3000000AC000000F900000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000200000000FF00FF00FF00FF00FF00FF + 00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF + 00FF00FF09FF00FF72FF00FFDDFF00FFA4FF00FF48FF00FF03FF00FF00FF00FF + 00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF + 00FF00FF00FF00FF00FF00FF03FF00FF47FF00FFA4FF00FFDEFF00FF72FF00FF + 09FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF + 00FF00FF00FF00FF00FF00FF00000000000400000000FFFF0000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 004900000093000000230000000000000000000000000000000003121500051A + 1F00030F1200020A0B00010709000103040000000000FFFDFC00FFF9F700FEF6 + F500FDF1EE00FBE6E100FDEEEB0000000000000000000000001A0000008D0000 + 006A0000006D000000B700000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000400000000FFFFFF000000000000 + 0000000000000000000000000000000000000000000000000000080000008E00 + 000069000000000000000000000000020A0D0007262C00061D23000104050000 + 0000000000000000000000000000000000000000000000010406000104060002 + 0B0F0004151A0007242C00FFFDFC00FAE2DC00F9DBD400FEF5F3000000000000 + 000023000000B60000009700000072000000F800000000000000000000000000 + 000000000000000000000000000000000000000400000000FFFFFF0000000000 + 000000000000000000000000000000000000000000000017000000B400000034 + 0000000000000000020809000A303900051A1E000000000000000000FFF6F300 + FEF1EE00FFF2EF00FFFAF80000FCFB0000FDFD00000000000003030000040500 + 01060800010E1100020F1200010A0B000721260007212600FBE6E200F6D0C700 + FEF8F7000000000000000069000000370000004A000000E90000000000000000 + 00000000000000000000000000000000000000000400000000FEFFFF00000000 + 000000000000000000000000000000000000000022000000B900000024000000 + 0000000000072228000A2B330001050600FFFF0000FEEBE700FDE6E000FFF5F3 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000ECE80000000000010B0D00031A20000215190004191E000D1418 + 00F6D5CD00F9DED8000000000000000032000000C400000046000000DF000000 + 0000000000000000000000000000000000000000000400000000FFFF00000000 + 00000000000000000000000000000000001C000000BD00000020000000000000 + 00000C343C00071F240000000000FEEEEA00FCDED800FFF9F700000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000FFF4F200FEDAD20001E1DB00042228000212 + 15000B30380004111500F4CCC3000000000000000024000000BE0000003D0000 + 00E400000000000000000000000000000000000000000400000000FEFFFF0000 + 00000000000000000000000000000A000000B20000002000000000000000000E + 394300061A1E00FFFF0000FCDAD200FDEBE70000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000FFF8F600FAD6CE0003 + 15190004252C00061E23000C040500F2C7BD000000000000000020000000B200 + 00003C000000F6000000000000000000000000000000000400000000FFFFFF00 + 000000000000000000000000000000900000003100000000000000000F3A4400 + 06191D00FFFBFA00FBD9D200FEEFEC0000000000000000000000000000000000 + 000000000000000011859E000000000000000000000000000000000000000000 + 0000000000000000EF7B62000000000000000000000000000000000000000000 + FCE9E600FEFAFA0005272E0006191D000E394300F1C6BC000000000000000031 + 0000009100000065000000000000000000000000000000000200000000FEFFFF + 00FEFFFF00FEFFFF00FEFFFF4AFEFFFF65FEFFFF00FEFFFF000C343D0005181C + 00FEFAF800FAD6CE00FDEEEA00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE + 00FFFFFE00FFFFFE000000000000000000000000000000000000000000000000 + 000000000000000000FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE + 00FFFFFE00FDEEEA00FAD6CE00FEFAF80005181C000C343D00FEFFFF00FEFFFF + 00FEFFFF64FEFFFF4AFEFFFF00FEFFFF00FEFFFF00000000000200000000FFFF + FF00FFFFFF00FFFFFF08FFFFFF92FFFFFF00FFFFFF0009232900081E2300FFFE + FE00FAD8D100FDF0ED00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF0000000000000000000000000000000000000000000000 + 00000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FDF0ED00FAD8D100FFFEFE00081E230009242A00FFFF + FF00FFFFFF00FFFFFF93FFFFFF08FFFFFF00FFFFFF00000000000200000000FE + FFFF00FEFFFF00FEFFFF69FEFFFF23FEFFFF00000709000A2A3100FFFFFF00FA + D9D100FDEEEB00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FF + FEFE00FFFEFE00FFFEFE00000000000000000000000000000000000000000000 + 0000000000000000000000FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FF + FEFE00FFFEFE00FFFEFE00FFFEFE00FDEEEB00FAD9D100FFFFFF000A29300000 + 080900FEFFFF00FEFFFF22FEFFFF69FEFFFF00FEFFFF00000000000200000000 + FEFEFF00FEFEFF07FEFEFF74FEFEFF00FEFEFF000D30370001040500FDECE800 + FCE8E500FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00 + FFFEFF00FFFEFF00FFFEFF000000000000000000000000000000000000000000 + 000000000000000000000000FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00 + FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FCE8E500FDECE80001040500 + 0D2F3700FEFEFF00FEFEFF00FEFEFF75FEFEFF08FEFEFF000000000002000000 + 00FEFFFF00FEFFFF54FEFFFF1AFEFFFF00010A0C00071A1F00FFFFFF00F8DBD4 + 00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE + 00FEFFFE00FEFFFE00FEFFFE0000000000000000000000000000000000000000 + 00000000000000000000000000FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE + 00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00F8DBD400FFFFFF + 00071A1F00020B0C00FEFFFF00FEFFFF19FEFFFF53FEFFFF0000000000020000 + 0000FFFFFF00FFFFFF5DFFFFFF00FFFFFF000C262C0000FFFF00FCE8E400FEF6 + F600FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFE + FF00FFFEFF00FFFEFF00FFFEFF00000000000000000000000000000000000000 + 0000000000000000000000000000FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFE + FF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FEF6F600FCE8 + E40000FFFF000B252C00FFFFFF00FFFFFF00FFFFFF5DFFFFFF00000000000200 + 000000FEFFFF10FEFFFF44FEFFFF00FEFFFF00091E2300FFFFFF00FAE2DD00FF + FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF + FFFE00FFFFFE00FFFFFE00FFFFFE00FFFCFB0000000000000000000000000000 + 0000000000000000000000FFFBFA00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF + FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FA + E2DD00FFFFFF00091E2300FEFFFF00FEFFFF00FEFFFF44FEFFFF100000000002 + 00000000FEFEFF3FFEFEFF03FEFEFF000511150001030300FEF5F200FDF2EF00 + FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00 + FFFEFE00FFFEFE00FFFEFE00FFFEFE00FEF1EE00000000000000000000000000 + 000000000000000000000000FEF2EF00FFFEFE00FFFEFE00FFFEFE00FFFEFE00 + FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00 + FDF2EF00FEF5F2000103030005111500FEFEFF00FEFEFF03FEFEFF3F00000000 + 0200000000FEFFFF3CFEFFFF00FEFFFF00081B1F00FFFF0000FBEDEC00FEFEFF + 00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF + 00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FDF2F0000000000000000000000000 + 00000000000000000000000000FDF2F000FEFEFF00FEFEFF00FEFEFF00FEFEFF + 00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF00FEFEFF + 00FEFEFF00FBEDEC00FFFF0000081B1F00FEFFFF00FEFFFF00FEFFFF3D000000 + 000400000000FEFFFF290000000000000000040D0E00FF00FE00FDF1ED00FFFF + FE00000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000FDF1EE0000000000000000000000 + 0000000000000000000000000000FDF1EE00FFFFFE0000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000FDF1ED00FF1C1F00040E0F00FEFFFF0000000000000000290000 + 00000400000000FEFEFF250000000000000000040C0D0000FFFF00FDF5F300FF + FEFE000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000FCF1EF00000000000000000000 + 000000000000000000000000000000FCF0EE00FFFEFE00000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000FDF5F30000FFFF00040B0C00FEFEFF00000000000000002400 + 0000000400000000FEFFFF18000000000000000002070900FFFFFF00FEF7F700 + FFFEFE0000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000FDF1EF000000000000000000 + 00000000000000000000000000000000FDF2F000FFFEFE000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000FEF9F900FFFFFF0002060700FEFFFF000000000000000014 + 000000000400000000FEFFFE0E000000000000000001030500FFFE0000FDFBFB + 00FFFEFF00000000000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000FCEFED0000000000000000 + 0000000000000000000000000000000000FCEFED00FEFEFF0000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000FFFBFB00FFFE000000020500FEFFFE0000000000000000 + 0C000000000400000000FEFEFF000000000000000000FF00FF0000000000FFFF + FE00FFFFFE000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FCF0ED00000000000000 + 000000000000000000000000000000000000FCF1EE00FFFFFE00000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000FFFE00FF00FF00FF00FF00FEFEFF00000000000000 + 0000000000000400000000FFFFFFF20000000E00000000FEFAFA000205050000 + 020200FFFEFE0000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000FCF1EF000000000000 + 00000000000000000000000000000000000000FCF0EE00FFFEFE000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000101020000FFFF00FEFBFA00FFFFFF000000000000 + 0000F4000000000400000000FEFFFFE80000000E00000000FBF7F50006040F00 + 00050700FEF5F500000000000000000000000000000000000000000000000000 + 000000000000000000000000000000000000000000000000FAEEEB0000000000 + 0000000000000000000000000000000000000000FAEEEB00FEFEFF0000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000002040500FFFFFF00FCF8F700FEFFFF0000000000 + 000000EC000000000400000000FEFEFFDB0000002600000000F9F2F100050C0E + 0001080A00FFFEEC000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000FCF1EF0000FEFE + 000002020000000000000000000000000000FEFE00FCF1EF0000FEFE00000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000001080A00FFFFFF00F9F2F100FEFEFF00000000 + 00000000DC000000000200000000FEFFFFD8FEFFFF00FEFFFF00F9F0EF0000FF + FF00030E1100FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE + FE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFCFC00FCF3 + F00000000000000000000000000000000000FCF3F100FFFCFC00FFFEFE00FFFE + FE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE + FE00FFFEFE00FFFEFE00FFFEFE00030E110000FFFF00F9F0EF00FEFFFF00FEFF + FF00FEFFFFD7000000000200000000FEFFFFC3FEFFFF00FEFFFF00F1E2DE00FF + FFFF0004131500FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF + FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FC + EFED0000000000000000000000000000000000FCEFEC00FFFFFE00FFFFFE00FF + FFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FFFFFE00FF + FFFE00FFFFFE00FFFFFE00FFFFFE0004131500FFFFFF00F1E2DE00FEFFFF00FE + FFFF00FEFFFFC3000000000400000000FEFFFFC1000000FD00000003F4EBE900 + FDFBFB00020B0D00020C0F00FCF2F00000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + E79C8D00020A0C00000000000000000000000000FEF6F400FEFEFF0000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 000000000000000000000000040E1000020B0D00FDFBFB00F4EBE90000000000 + 000000FD000000C2000000000400000000FEFEFFF0000000BC00000047000000 + 00EFDEDA001225290007212600FBCFC800000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00F6DCD700000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000007212600FFFFFF00EFDEDB00FEFEFF00000000 + 00000000BD000000EF000000000400000000FEFFFF00000000A3000000470000 + 0000E9D5D20012242800071A1E00F5D7D100FEF7F50000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000134A56000205050000000000000000000000000000000000EDBAB000FEF7 + F500000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000002090B00071A1E0000FFFF00E9D5D100FEFFFF000000 + 0000000000A300000000000000000400000000FFFFFF00000000AD0000008B00 + 000019F9F3F100F0E2DF000F1D20000B2B3100F2CAC300000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000016556100030A0C0000000000000000000000000000000000EFC3BB00FD + F5F4000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000B2B3100FFFFFF00F1E3E000F9F3F1000000000000 + 0000E7000000AC00000000000000000200000000FEFFFF00FEFFFFF8FEFFFF8B + FEFFFF00FEFFFF00E3CAC500FCFAF90005171A0005191C00FEFFFE00FEFFFE00 + FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00 + FEFFFE00000000000000000000000000000000000000000000000000FFFFFE00 + FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00FEFFFE00 + FEFFFE00FEFFFE0005191C0005171A00FCFBF900E3CAC500FEFFFF00FEFFFF00 + FEFFFF8CFEFFFFF8FEFFFF00000000000200000000FEFEFF00FEFEFF00FEFEFF + 97FEFEFFDEFEFEFF00F9F5F500E7D0CD0000FE00000D30380005121600FFFEFF + 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF + 00FFFEFF00000000000000000000000000000000000000000000000000FFFEFF + 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF + 00FFFEFF00051216000D30380000FE0000E7D0CE00F9F5F500FEFEFF00FEFEFF + DEFEFEFF96FEFEFF00FEFEFF00000000000200000000FEFFFF00FEFFFF00FEFF + FFF8FEFFFF6DFEFFFF00FEFFFF00E8D7D300EDDEDB00000102000D3239000411 + 1400FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE + FE00FFFEFE00000000000000000000000000000000000000000000000000FFFF + FF00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFEFE00FFFE + FE00041114000D32390000010200EDDEDB00E8D6D200FEFFFF00FEFFFF00FEFF + FF6EFEFFFFF8FEFFFF00FEFFFF00000000000200000000FFFFFF00FFFFFF00FF + FFFF00FFFFFFB6FFFFFF9DFFFFFF00FFFFFF00DEC4BE00F1E5E100020708000F + 363E0005161900FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FF + FFFF00FFFFFF00000000000000000000000000000000000000000000000000FF + FFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0005 + 1619000F363E0002070800F1E5E100DEC4BE00FFFFFF00FFFFFF00FFFFFF9FFF + FFFFB5FFFFFF00FFFFFF00FFFFFF000000000001FFFFFF00AF412B0000000000 + 00000000000000000000000A000000C500000030000000000000000025414600 + 101C1F00FFFEFE00F2CFC700F8E3DF0000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000000081D2100 + 0E31390001020200F0E4E100DBBFBA000000000000000000000000D00000003B + 000000F600000000000000000000000051BFD5000200000000FFFFFF00FFFFFF + 00FFFFFF00FFFFFF00FFFFFFF6FFFFFF4DFFFFFFE1FFFFFF00FFFFFF00DABEB9 + 00EBDDDA00000101000E323A000F363F0002080A00FFFEFF00FFFEFF00FFFEFF + 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF + 00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF0002080A000F363F000E323A + 0000010100EBDDDA00DABEB900FFFFFF00FFFFFF00FFFFFFE1FFFFFF4DFFFFFF + F6FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000400000000FEFFFF000000 + 0000000000000000000000000000000000E400000042000000BB000000220000 + 0000DDC4BF00F5ECEB001C30340007191C0007191C00F7E3DF00F6DBD600FBF0 + EE00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000051012000A252A00091D210000000000FCFA + F900E4D0CC00E9D8D5000000000000000000000000DE00000045000000E40000 + 0000000000000000000000000000000000000000000001FFFFFF00AB3E280000 + 000000000000000000000000000000000000000000000000000018000000B500 + 000032000000000000000005090A0021373C00111E20000000000000000000FC + F3F100FAEAE800FBEEEB00FDF7F600FEF8F700FEFCFB00000000000204050002 + 08090003090A000512150006161800040D0F000000000000000000EFE2E000DF + C9C400FBF7F6000000000000000000000000CE0000004B000000E80000000000 + 0000000000000000000000000000000000000055C2D80001FFFFFF00A93D2800 + 0000000000000000000000000000000000000000000000000000000000000008 + 0000009100000066000000000000000000000000080D0E001A2B2E0015242600 + 0203040000000000000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000FEFDFC00EBDCDA00E6D5D200F8F3F200 + 0000000000000000000000000000009900000070000000F80000000000000000 + 000000000000000000000000000000000000000057C3D80001FFFFFF00A83C27 + 0000000000000000000000000000000000000000000000000000000000000000 + 00000000000000004A0000009200000023000000000000000000000000000000 + 000D151700131F2100090F1000080D0E00050909000304050000000000FDFCFB + 00FBF7F700F8F3F200F7F1F000EDE1DF00F3EBE9000000000000000000000000 + 0000000000000000DD0000006D000000B7000000000000000000000000000000 + 00000000000000000000000000000000000000000058C4D9000400000000FFFF + FF00000000000000000000000000000000000000000000000000000000000000 + 000000000000000000B6000000BF000000690000007400000019000000000000 + 0000F2EAE800F2EAE80000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 00E70000008C00000097000000F7000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000000000000400000000FF + FFFF000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000F70000008E00000095000000540000005F00 + 0000420000000300000000000000000000000000000000000000000000000000 + 00000000000000000000000000000000000000000000FD000000BE000000A100 + 0000AC000000F900000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000400000000 + FF00000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000F9000000A5000000A5 + 000000110000003F0000003B0000002A00000022000000170000000C00000000 + 000000F4000000E9000000DE000000D6000000C5000000C1000000EF00000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000001FFFFFF + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000000000 + 0000000000000000000000000000000000000000000000000000000000010000 + FFFF99B3ED4DB34E9B390000000049454E44AE426082 + } + Proportional = True + Transparent = True end - object PanelMessage: TPanel + object LabelExceptionCaption: TLabel + AnchorSideLeft.Control = IconException + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = IconException Left = 60 - Height = 60 - Top = 0 - Width = 423 - Align = alClient - BevelOuter = bvNone - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ClientHeight = 60 - ClientWidth = 423 - TabOrder = 1 - object LabelExceptionCaption: TLabel - Left = 6 - Height = 21 - Top = 6 - Width = 411 - Align = alTop - Caption = 'LabelExceptionCaption' - Font.Height = -16 - ParentColor = False - ParentFont = False - end - object LabelExceptionMessage: TLabel - Left = 12 - Height = 21 - Top = 33 - Width = 405 - Align = alClient - BorderSpacing.Left = 6 - BorderSpacing.Around = 6 - Caption = 'LabelExceptionMessage' - Font.Height = -13 - ParentColor = False - ParentFont = False - WordWrap = True - end + Height = 21 + Top = 6 + Width = 157 + BorderSpacing.Left = 6 + Caption = 'LabelExceptionCaption' + Font.Height = -16 + ParentColor = False + ParentFont = False end - object PanelButton: TPanel - Left = 483 - Height = 60 - Top = 0 - Width = 0 - Align = alRight - AutoSize = True - BevelOuter = bvNone - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - TabOrder = 2 + object LabelExceptionMessage: TLabel + AnchorSideLeft.Control = LabelExceptionCaption + AnchorSideTop.Control = LabelExceptionCaption + AnchorSideTop.Side = asrBottom + Left = 66 + Height = 15 + Top = 27 + Width = 147 + BorderSpacing.Left = 6 + Caption = 'LabelExceptionMessage' + Font.Height = -12 + Font.Name = 'Courier New' + ParentColor = False + ParentFont = False + WordWrap = True end end object PanelBottom: TPanel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = PanelTop + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom Left = 0 - Height = 37 - Top = 62 - Width = 483 - Align = alTop + Height = 195 + Top = 55 + Width = 580 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoSize = True + BorderSpacing.Top = 1 BevelOuter = bvNone ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 - ClientHeight = 37 - ClientWidth = 483 + ClientHeight = 195 + ClientWidth = 580 + ParentColor = False TabOrder = 1 object CheckBoxIgnoreException: TCheckBox + AnchorSideTop.Control = ButtonDetails + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = ButtonDetails Left = 6 - Height = 25 - Top = 6 + Height = 19 + Top = 10 Width = 157 - Align = alLeft - BorderSpacing.Left = 4 Caption = 'CheckBoxIgnoreException' TabOrder = 1 end object ButtonDetails: TBitBtn - Left = 93 - Height = 25 + AnchorSideTop.Control = ButtonTerminate + AnchorSideRight.Control = ButtonTerminate + Left = 191 + Height = 26 Top = 6 Width = 117 - Align = alRight + Anchors = [akTop, akRight] AutoSize = True Caption = '&ButtonDetails' Kind = bkHelp @@ -437,11 +418,13 @@ object SimpleExceptionForm: TSimpleExceptionForm TabOrder = 0 end object ButtonTerminate: TBitBtn - Left = 210 - Height = 25 + AnchorSideTop.Control = ButtonContinue + AnchorSideRight.Control = ButtonContinue + Left = 308 + Height = 26 Top = 6 Width = 136 - Align = alRight + Anchors = [akTop, akRight] AutoSize = True Caption = '&ButtonTerminate' Kind = bkAbort @@ -450,11 +433,11 @@ object SimpleExceptionForm: TSimpleExceptionForm TabOrder = 2 end object ButtonContinue: TBitBtn - Left = 346 - Height = 25 + Left = 444 + Height = 26 Top = 6 Width = 131 - Align = alRight + Anchors = [akTop, akRight] AutoSize = True Caption = '&ButtonContinue' Kind = bkYes @@ -462,25 +445,20 @@ object SimpleExceptionForm: TSimpleExceptionForm OnClick = ButtonContinueClick TabOrder = 3 end - end - object PanelCenter: TPanel - Left = 0 - Height = 127 - Top = 99 - Width = 483 - Align = alClient - BevelOuter = bvNone - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ClientHeight = 127 - ClientWidth = 483 - TabOrder = 2 object MemoExceptionLog: TMemo + AnchorSideLeft.Control = PanelBottom + AnchorSideTop.Control = ButtonDetails + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = PanelBottom + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = PanelBottom + AnchorSideBottom.Side = asrBottom Left = 6 - Height = 115 - Top = 6 - Width = 471 - Align = alClient + Height = 151 + Top = 38 + Width = 568 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 Font.Height = -12 Font.Name = 'Courier New' Lines.Strings = ( @@ -489,16 +467,21 @@ object SimpleExceptionForm: TSimpleExceptionForm ParentFont = False ReadOnly = True ScrollBars = ssAutoBoth - TabOrder = 0 + TabOrder = 4 WordWrap = False end end object BevelPannelBottom: TShape + AnchorSideLeft.Control = PanelTop + AnchorSideTop.Control = PanelTop + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = PanelTop + AnchorSideRight.Side = asrBottom Left = 0 Height = 2 - Top = 60 - Width = 483 - Align = alTop + Top = 54 + Width = 217 + Anchors = [akTop, akLeft, akRight] Brush.Color = clBtnShadow Pen.Color = clBtnShadow Pen.Style = psClear diff --git a/baseunits/SimpleException/SimpleExceptionForm.pas b/baseunits/SimpleException/SimpleExceptionForm.pas index 8f24825b9..0702eb2e7 100644 --- a/baseunits/SimpleException/SimpleExceptionForm.pas +++ b/baseunits/SimpleException/SimpleExceptionForm.pas @@ -28,7 +28,7 @@ interface {$ifdef windows} windows, {$endif} - Forms, Controls, StdCtrls, ExtCtrls, Buttons; + Forms, Controls, StdCtrls, ExtCtrls, Buttons, Classes; type @@ -43,10 +43,6 @@ TSimpleExceptionForm = class(TForm) LabelExceptionMessage: TLabel; LabelExceptionCaption: TLabel; MemoExceptionLog: TMemo; - PanelButton : TPanel; - PanelCenter: TPanel; - PanelMessage: TPanel; - PanelExceptionIcon: TPanel; PanelBottom: TPanel; PanelTop: TPanel; BevelPannelBottom: TShape; @@ -58,6 +54,8 @@ TSimpleExceptionForm = class(TForm) procedure FormShow(Sender: TObject); private { private declarations } + normalheight, + expandedheight: Integer; public { public declarations } end; @@ -72,10 +70,14 @@ implementation procedure TSimpleExceptionForm.ButtonDetailsClick(Sender: TObject); begin - if ClientHeight <= PanelCenter.Top + PanelCenter.ChildSizing.TopBottomSpacing then - ClientHeight := PanelTop.Height + PanelBottom.Height + 200 + if ClientHeight <= normalheight then + ClientHeight := expandedheight else - ClientHeight := PanelTop.Height + PanelBottom.Height; + ClientHeight := normalheight; + //if ClientHeight <= PanelCenter.Top + PanelCenter.ChildSizing.TopBottomSpacing then + // ClientHeight := PanelTop.Height + PanelBottom.Height + 200 + //else + // ClientHeight := PanelTop.Height + PanelBottom.Height; end; procedure TSimpleExceptionForm.ButtonTerminateClick(Sender: TObject); @@ -90,26 +92,27 @@ procedure TSimpleExceptionForm.ButtonTerminateClick(Sender: TObject); procedure TSimpleExceptionForm.FormCreate(Sender: TObject); begin Icon.Assign(Application.Icon); -end; - -procedure TSimpleExceptionForm.FormShow(Sender: TObject); -begin + IconException.Visible := IconException.Picture.Graphic <> nil; Caption := SExceptionDialogTitle; - if IconException.Picture.Graphic <> nil then - PanelExceptionIcon.Show - else - PanelExceptionIcon.Hide; LabelExceptionCaption.Caption := SExceptionCaption; ButtonDetails.Caption := TCaption(SButtonDetails); ButtonTerminate.Caption := TCaption(SButtonTerminate); ButtonContinue.Caption := TCaption(SButtonContinue); CheckBoxIgnoreException.Caption := SCheckBoxIgnoreException; CheckBoxIgnoreException.Checked := False; - ClientHeight := PanelTop.Height + PanelBottom.Height; - ClientWidth := CheckBoxIgnoreException.Width + ButtonDetails.Width + - ButtonTerminate.Width + ButtonContinue.Width + - (PanelBottom.ChildSizing.LeftRightSpacing * 3); - Position := poDesktopCenter; +end; + +procedure TSimpleExceptionForm.FormShow(Sender: TObject); +begin + normalheight := min(PanelTop.Height + ButtonDetails.Height + (6 * 2), Screen.Height); + expandedheight := normalheight + 300; + Constraints.MinWidth := CheckBoxIgnoreException.Width + ButtonDetails.Width + ButtonTerminate.Width + ButtonContinue.Width + (6 * 5); + Constraints.MinHeight := normalheight; + ClientWidth := min(max(PanelTop.Width, Constraints.MinWidth), Screen.Width); + ClientHeight := normalheight; + PanelTop.AutoSize := False; + PanelTop.Width := ClientWidth; + PanelTop.Anchors := [akLeft, akRight, akTop]; Position := poMainFormCenter; end; From 4c8c6300127c36a0ad0c43d88a87d0ccbd43ff9a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 22 Aug 2017 21:03:50 +0800 Subject: [PATCH 1889/2794] cleanup --- baseunits/SimpleException/SimpleExceptionForm.pas | 4 ---- 1 file changed, 4 deletions(-) diff --git a/baseunits/SimpleException/SimpleExceptionForm.pas b/baseunits/SimpleException/SimpleExceptionForm.pas index 0702eb2e7..f77e4749a 100644 --- a/baseunits/SimpleException/SimpleExceptionForm.pas +++ b/baseunits/SimpleException/SimpleExceptionForm.pas @@ -74,10 +74,6 @@ procedure TSimpleExceptionForm.ButtonDetailsClick(Sender: TObject); ClientHeight := expandedheight else ClientHeight := normalheight; - //if ClientHeight <= PanelCenter.Top + PanelCenter.ChildSizing.TopBottomSpacing then - // ClientHeight := PanelTop.Height + PanelBottom.Height + 200 - //else - // ClientHeight := PanelTop.Height + PanelBottom.Height; end; procedure TSimpleExceptionForm.ButtonTerminateClick(Sender: TObject); From 8f80f32e2052a02f64f5aef8d64a700852929608 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 02:19:08 +0800 Subject: [PATCH 1890/2794] update internettools --- .gitmodules | 2 +- 3rd/internettools | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index f5e264382..ab2cc44b0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,6 +5,6 @@ shallow = true [submodule "3rd/internettools"] path = 3rd/internettools - url = https://github.com/benibela/internettools + url = https://github.com/benibela/internettools.git ignore = dirty shallow = true diff --git a/3rd/internettools b/3rd/internettools index 99970038f..74bcaf987 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 99970038fdf92aa01763fb35d5dc6b9061295046 +Subproject commit 74bcaf987eedd99e3337d963c409c785292f2d15 From e4667c2e8e51c7e07d19b86c2fb62c1951b3032a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 02:38:18 +0800 Subject: [PATCH 1891/2794] simpleexceptionform, fixed layout --- baseunits/SimpleException/SimpleExceptionForm.lfm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/baseunits/SimpleException/SimpleExceptionForm.lfm b/baseunits/SimpleException/SimpleExceptionForm.lfm index 6446cceeb..087c04269 100644 --- a/baseunits/SimpleException/SimpleExceptionForm.lfm +++ b/baseunits/SimpleException/SimpleExceptionForm.lfm @@ -393,6 +393,7 @@ object SimpleExceptionForm: TSimpleExceptionForm ParentColor = False TabOrder = 1 object CheckBoxIgnoreException: TCheckBox + AnchorSideLeft.Control = PanelBottom AnchorSideTop.Control = ButtonDetails AnchorSideTop.Side = asrCenter AnchorSideRight.Control = ButtonDetails @@ -406,7 +407,7 @@ object SimpleExceptionForm: TSimpleExceptionForm object ButtonDetails: TBitBtn AnchorSideTop.Control = ButtonTerminate AnchorSideRight.Control = ButtonTerminate - Left = 191 + Left = 190 Height = 26 Top = 6 Width = 117 @@ -420,7 +421,7 @@ object SimpleExceptionForm: TSimpleExceptionForm object ButtonTerminate: TBitBtn AnchorSideTop.Control = ButtonContinue AnchorSideRight.Control = ButtonContinue - Left = 308 + Left = 307 Height = 26 Top = 6 Width = 136 @@ -433,7 +434,10 @@ object SimpleExceptionForm: TSimpleExceptionForm TabOrder = 2 end object ButtonContinue: TBitBtn - Left = 444 + AnchorSideTop.Control = PanelBottom + AnchorSideRight.Control = PanelBottom + AnchorSideRight.Side = asrBottom + Left = 443 Height = 26 Top = 6 Width = 131 @@ -458,7 +462,7 @@ object SimpleExceptionForm: TSimpleExceptionForm Top = 38 Width = 568 Anchors = [akTop, akLeft, akRight, akBottom] - BorderSpacing.Around = 6 + BorderSpacing.Top = 6 Font.Height = -12 Font.Name = 'Courier New' Lines.Strings = ( From b8fdfe0d101fb8c0e11381ef1c665a80bb94c05a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 03:41:54 +0800 Subject: [PATCH 1892/2794] change project/compiler options --- 3rd/BESENPkg.lpk | 14 ++++- 3rd/internettools.lpk | 135 ----------------------------------------- 3rd/internettools.pas | 22 ------- mangadownloader/md.lpi | 29 ++++----- 4 files changed, 24 insertions(+), 176 deletions(-) delete mode 100644 3rd/internettools.lpk delete mode 100644 3rd/internettools.pas diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk index 762fd4398..1921be4fd 100644 --- a/3rd/BESENPkg.lpk +++ b/3rd/BESENPkg.lpk @@ -11,9 +11,17 @@ <OtherUnitFiles Value="BESEN\src"/> <UnitOutputDirectory Value="BESEN\lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> - <Other> - <CustomOptions Value="-CX -O3 -Xs -XX -g-"/> - </Other> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + </Linking> </CompilerOptions> <Files Count="97"> <Item1> diff --git a/3rd/internettools.lpk b/3rd/internettools.lpk deleted file mode 100644 index 89bebeba8..000000000 --- a/3rd/internettools.lpk +++ /dev/null @@ -1,135 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<CONFIG> - <Package Version="4"> - <Name Value="internettools"/> - <Type Value="RunAndDesignTime"/> - <CompilerOptions> - <Version Value="11"/> - <SearchPaths> - <IncludeFiles Value="internettools/data;internettools/lazarus/dialogs;internettools/import/synapse"/> - <OtherUnitFiles Value="internettools/data;internettools/internet;internettools/import/regexpr/source;internettools/lazarus/dialogs;internettools/import/synapse;internettools/system;internettools/import/flre/src"/> - <UnitOutputDirectory Value="internettools/lib/$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Other> - <CustomOptions Value="-CX -O3 -Xs -XX -g- --uUSE_FLRE_WITH_CACHE --uUSE_BBFLRE_UNICODE --dUSE_SOROKINS_REGEX --dUSE_BBFULL_UNICODE"/> - </Other> - </CompilerOptions> - <Files Count="25"> - <Item1> - <Filename Value="internettools/data/bbutils.pas"/> - <UnitName Value="bbutils"/> - </Item1> - <Item2> - <Filename Value="internettools/data/extendedhtmlparser.pas"/> - <UnitName Value="extendedhtmlparser"/> - </Item2> - <Item3> - <Filename Value="internettools/internet/simpleinternet.pas"/> - <UnitName Value="simpleinternet"/> - </Item3> - <Item4> - <Filename Value="internettools/internet/internetaccess.pas"/> - <UnitName Value="internetaccess"/> - </Item4> - <Item5> - <Filename Value="internettools/data/disableRangeOverflowChecks.inc"/> - <Type Value="Include"/> - </Item5> - <Item6> - <Filename Value="internettools/data/simplehtmlparser.pas"/> - <UnitName Value="simplehtmlparser"/> - </Item6> - <Item7> - <Filename Value="internettools/data/simplehtmltreeparser.pas"/> - <UnitName Value="simplehtmltreeparser"/> - </Item7> - <Item8> - <Filename Value="internettools/data/simplexmlparser.pas"/> - <UnitName Value="simplexmlparser"/> - </Item8> - <Item9> - <Filename Value="internettools/data/restoreRangeOverflowChecks.inc"/> - <Type Value="Include"/> - </Item9> - <Item10> - <Filename Value="internettools/data/xquery.pas"/> - <UnitName Value="xquery"/> - </Item10> - <Item11> - <Filename Value="internettools/data/xquery_functions_generated.inc"/> - <Type Value="Include"/> - </Item11> - <Item12> - <Filename Value="internettools/data/xquery_functions_generated_template.inc"/> - <Type Value="Include"/> - </Item12> - <Item13> - <Filename Value="internettools/data/xquery_terms.inc"/> - <Type Value="Include"/> - </Item13> - <Item14> - <Filename Value="internettools/data/xquery_types.inc"/> - <Type Value="Include"/> - </Item14> - <Item15> - <Filename Value="internettools/internet/synapseinternetaccess.pas"/> - <UnitName Value="synapseinternetaccess"/> - </Item15> - <Item16> - <Filename Value="internettools/internet/w32internetaccess.pas"/> - <UnitName Value="w32internetaccess"/> - </Item16> - <Item17> - <Filename Value="internettools/data/simplexmltreeparserfpdom.pas"/> - <UnitName Value="simplexmltreeparserfpdom"/> - </Item17> - <Item18> - <Filename Value="internettools/data/xquery_json.pas"/> - <UnitName Value="xquery_json"/> - </Item18> - <Item19> - <Filename Value="internettools/internet/mockinternetaccess.pas"/> - <UnitName Value="mockinternetaccess"/> - </Item19> - <Item20> - <Filename Value="internettools/data/xquery_schemas.inc"/> - <Type Value="Include"/> - </Item20> - <Item21> - <Filename Value="internettools/data/xquery__regex.pas"/> - <UnitName Value="xquery__regex"/> - </Item21> - <Item22> - <Filename Value="internettools/data/xquery__parse.pas"/> - <UnitName Value="xquery__parse"/> - </Item22> - <Item23> - <Filename Value="internettools/data/xquery_module_math.pas"/> - <UnitName Value="xquery_module_math"/> - </Item23> - <Item24> - <Filename Value="internettools/data/xquery__functions.pas"/> - <UnitName Value="xquery__functions"/> - </Item24> - <Item25> - <Filename Value="internettools/internettoolsconfig.inc"/> - <Type Value="Binary"/> - </Item25> - </Files> - <RequiredPkgs Count="1"> - <Item1> - <PackageName Value="FCL"/> - </Item1> - </RequiredPkgs> - <UsageOptions> - <UnitPath Value="$(PkgOutDir)"/> - </UsageOptions> - <PublishOptions> - <Version Value="2"/> - </PublishOptions> - </Package> -</CONFIG> diff --git a/3rd/internettools.pas b/3rd/internettools.pas deleted file mode 100644 index 65f7cbce1..000000000 --- a/3rd/internettools.pas +++ /dev/null @@ -1,22 +0,0 @@ -{ This file was automatically created by Lazarus. Do not edit! - This source is only used to compile and install the package. - } - -unit internettools; - -interface - -uses - bbutils, extendedhtmlparser, simpleinternet, internetaccess, simplehtmlparser, simplehtmltreeparser, simplexmlparser, xquery, - synapseinternetaccess, w32internetaccess, simplexmltreeparserfpdom, xquery_json, mockinternetaccess, xquery__regex, xquery__parse, - xquery_module_math, xquery__functions, LazarusPackageIntf; - -implementation - -procedure Register; -begin -end; - -initialization - RegisterPackage('internettools', @Register); -end. diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 3e976ce7c..c42c93e31 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -99,7 +99,6 @@ </CodeGeneration> <Linking> <Debugging> - <DebugInfoType Value="dsDwarf3"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> @@ -150,7 +149,6 @@ </CodeGeneration> <Linking> <Debugging> - <DebugInfoType Value="dsDwarf3"/> <UseExternalDbgSyms Value="True"/> </Debugging> <Options> @@ -199,7 +197,6 @@ </CodeGeneration> <Linking> <Debugging> - <DebugInfoType Value="dsDwarf3"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> @@ -248,7 +245,6 @@ </CodeGeneration> <Linking> <Debugging> - <DebugInfoType Value="dsDwarf3"/> <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> @@ -265,8 +261,9 @@ </Other> </CompilerOptions> </Item6> - <SharedMatrixOptions Count="1"> + <SharedMatrixOptions Count="2"> <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> + <Item2 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> @@ -283,33 +280,33 @@ </RunParams> <RequiredPackages Count="9"> <Item1> - <PackageName Value="dcpcrypt"/> + <PackageName Value="LCL"/> </Item1> <Item2> - <PackageName Value="BESENPkg"/> - <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> + <PackageName Value="TAChartLazarusPkg"/> </Item2> <Item3> - <PackageName Value="multiloglaz"/> + <PackageName Value="richmemopackage"/> </Item3> <Item4> - <PackageName Value="laz_synapse"/> + <PackageName Value="virtualtreeview_package"/> </Item4> <Item5> - <PackageName Value="internettools"/> - <DefaultFilename Value="..\3rd\internettools.lpk" Prefer="True"/> + <PackageName Value="multiloglaz"/> </Item5> <Item6> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="laz_synapse"/> </Item6> <Item7> - <PackageName Value="richmemopackage"/> + <PackageName Value="dcpcrypt"/> </Item7> <Item8> - <PackageName Value="virtualtreeview_package"/> + <PackageName Value="BESENPkg"/> + <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> </Item8> <Item9> - <PackageName Value="LCL"/> + <PackageName Value="internettools"/> + <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item9> </RequiredPackages> <Units Count="14"> From d17445ec01a822e28d9c0f7b9e74edcc00609952 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 04:00:21 +0800 Subject: [PATCH 1893/2794] fixed merge completed task if empty fixed #714 --- mangadownloader/forms/frmMain.lfm | 93 ++++++++++++++++--------------- mangadownloader/forms/frmMain.lrj | 14 ++--- mangadownloader/forms/frmMain.pas | 6 +- 3 files changed, 57 insertions(+), 56 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index cc72a022f..63d05dd4c 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,6 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True + LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -4664,14 +4665,14 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - left = 96 - top = 251 + Left = 96 + Top = 251 end object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - left = 592 - top = 184 + Left = 592 + Top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -5001,8 +5002,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - left = 592 - top = 224 + Left = 592 + Top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -5060,8 +5061,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - left = 520 - top = 212 + Left = 520 + Top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -5379,8 +5380,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - left = 382 - top = 238 + Left = 382 + Top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5526,13 +5527,13 @@ object MainForm: TMainForm PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - left = 288 - top = 432 + Left = 288 + Top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False - left = 382 - top = 110 + Left = 382 + Top = 110 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5554,8 +5555,8 @@ object MainForm: TMainForm end end object IconList: TImageList - left = 278 - top = 102 + Left = 278 + Top = 102 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6297,8 +6298,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - left = 278 - top = 150 + Left = 278 + Top = 150 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6594,8 +6595,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - left = 328 - top = 238 + Left = 328 + Top = 238 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6889,8 +6890,8 @@ object MainForm: TMainForm } end object IconSmall: TImageList - left = 27 - top = 328 + Left = 27 + Top = 328 Bitmap = { 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6993,8 +6994,8 @@ object MainForm: TMainForm end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup - left = 592 - top = 136 + Left = 592 + Top = 136 object medURLUndo: TMenuItem Caption = 'Undo' OnClick = medURLUndoClick @@ -7033,38 +7034,38 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - left = 96 - top = 312 + Left = 96 + Top = 312 end object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - left = 560 - top = 472 + Left = 560 + Top = 472 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - left = 504 - top = 120 + Left = 504 + Top = 120 end object TransferRateToolset: TChartToolset - left = 464 - top = 120 + Left = 464 + Top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - left = 152 - top = 376 + Left = 152 + Top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick end end object pmFilterGenreAll: TPopupMenu - left = 520 - top = 168 + Left = 520 + Top = 168 object mnFilterGenreAllCheck: TMenuItem Caption = 'Check all' OnClick = mnFilterGenreAllCheckClick @@ -7080,8 +7081,8 @@ object MainForm: TMainForm end object pmTray: TPopupMenu OnPopup = pmTrayPopup - left = 341 - top = 432 + Left = 341 + Top = 432 object miTrayResumeAll: TMenuItem Caption = 'Resume all' OnClick = tbDownloadResumeAllClick @@ -7145,28 +7146,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - left = 656 - top = 416 + Left = 656 + Top = 416 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - left = 440 - top = 472 + Left = 440 + Top = 472 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - left = 656 - top = 472 + Left = 656 + Top = 472 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - left = 480 - top = 472 + Left = 480 + Top = 472 end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 5eba8c9fa..4b5d16190 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -50,13 +50,13 @@ {"hash":84262158,"name":"tmainform.cbuseregexpr.caption","sourcebytes":[82,101,103,117,108,97,114,32,69,120,112,114,101,115,115,105,111,110],"value":"Regular Expression"}, {"hash":111905342,"name":"tmainform.ckfilteraction.hint","sourcebytes":[65,32,119,111,114,107,32,116,121,112,105,99,97,108,108,121,32,100,101,112,105,99,116,105,110,103,32,102,105,103,104,116,105,110,103,44,32,118,105,111,108,101,110,99,101,44,32,99,104,97,111,115,44,32,97,110,100,32,102,97,115,116,32,112,97,99,101,100,32,109,111,116,105,111,110,46],"value":"A work typically depicting fighting, violence, chaos, and fast paced motion."}, {"hash":75149406,"name":"tmainform.ckfilteraction.caption","sourcebytes":[65,99,116,105,111,110],"value":"Action"}, -{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and\/or graphic sexual content and nudity."}, +{"hash":258619502,"name":"tmainform.ckfilteradult.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,99,111,110,116,101,110,116,32,116,104,97,116,32,105,115,32,115,117,105,116,97,98,108,101,32,111,110,108,121,32,102,111,114,32,97,100,117,108,116,115,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,105,110,99,108,117,100,101,32,112,114,111,108,111,110,103,101,100,32,115,99,101,110,101,115,32,111,102,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,32,97,110,100,47,111,114,32,103,114,97,112,104,105,99,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,32,110,117,100,105,116,121,46],"value":"Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity."}, {"hash":4701236,"name":"tmainform.ckfilteradult.caption","sourcebytes":[65,100,117,108,116],"value":"Adult"}, {"hash":267284606,"name":"tmainform.ckfilteradventure.hint","sourcebytes":[73,102,32,97,32,99,104,97,114,97,99,116,101,114,32,105,110,32,116,104,101,32,115,116,111,114,121,32,103,111,101,115,32,111,110,32,97,32,116,114,105,112,32,111,114,32,97,108,111,110,103,32,116,104,97,116,32,108,105,110,101,44,32,121,111,117,114,32,98,101,115,116,32,98,101,116,32,105,115,32,116,104,97,116,32,105,116,32,105,115,32,97,110,32,97,100,118,101,110,116,117,114,101,32,109,97,110,103,97,46,32,79,116,104,101,114,119,105,115,101,44,32,105,116,39,115,32,117,112,32,116,111,32,121,111,117,114,32,112,101,114,115,111,110,97,108,32,112,114,101,106,117,100,105,99,101,32,111,110,32,116,104,105,115,32,99,97,115,101,46],"value":"If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case."}, {"hash":214301493,"name":"tmainform.ckfilteradventure.caption","sourcebytes":[65,100,118,101,110,116,117,114,101],"value":"Adventure"}, {"hash":11846766,"name":"tmainform.ckfiltercomedy.hint","sourcebytes":[65,32,100,114,97,109,97,116,105,99,32,119,111,114,107,32,116,104,97,116,32,105,115,32,108,105,103,104,116,32,97,110,100,32,111,102,116,101,110,32,104,117,109,111,114,111,117,115,32,111,114,32,115,97,116,105,114,105,99,97,108,32,105,110,32,116,111,110,101,32,97,110,100,32,116,104,97,116,32,117,115,117,97,108,108,121,32,99,111,110,116,97,105,110,115,32,97,32,104,97,112,112,121,32,114,101,115,111,108,117,116,105,111,110,32,111,102,32,116,104,101,32,116,104,101,109,97,116,105,99,32,99,111,110,102,108,105,99,116,46],"value":"A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict."}, {"hash":78003129,"name":"tmainform.ckfiltercomedy.caption","sourcebytes":[67,111,109,101,100,121],"value":"Comedy"}, -{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga\/anime."}, +{"hash":163738830,"name":"tmainform.ckfilterdoujinshi.hint","sourcebytes":[70,97,110,32,98,97,115,101,100,32,119,111,114,107,32,105,110,112,115,112,105,114,101,100,32,98,121,32,111,102,102,105,99,105,97,108,32,109,97,110,103,97,47,97,110,105,109,101,46],"value":"Fan based work inpspired by official manga/anime."}, {"hash":202379913,"name":"tmainform.ckfilterdoujinshi.caption","sourcebytes":[68,111,117,106,105,110,115,104,105],"value":"Doujinshi"}, {"hash":221112350,"name":"tmainform.ckfilterdrama.hint","sourcebytes":[65,32,119,111,114,107,32,109,101,97,110,116,32,116,111,32,98,114,105,110,103,32,111,110,32,97,110,32,101,109,111,116,105,111,110,97,108,32,114,101,115,112,111,110,115,101,44,32,115,117,99,104,32,97,115,32,105,110,115,116,105,108,108,105,110,103,32,115,97,100,110,101,115,115,32,111,114,32,116,101,110,115,105,111,110,46],"value":"A work meant to bring on an emotional response, such as instilling sadness or tension."}, {"hash":4950065,"name":"tmainform.ckfilterdrama.caption","sourcebytes":[68,114,97,109,97],"value":"Drama"}, @@ -80,7 +80,7 @@ {"hash":56818190,"name":"tmainform.ckfilterlolicon.caption","sourcebytes":[76,111,108,105,99,111,110],"value":"Lolicon"}, {"hash":104001182,"name":"tmainform.ckfiltermartialarts.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,97,110,121,116,104,105,110,103,32,109,97,114,116,105,97,108,32,97,114,116,115,32,114,101,108,97,116,101,100,46,32,65,110,121,32,111,102,32,115,101,118,101,114,97,108,32,97,114,116,115,32,111,102,32,99,111,109,98,97,116,32,111,114,32,115,101,108,102,45,100,101,102,101,110,115,101,44,32,115,117,99,104,32,97,115,32,97,105,107,105,100,111,44,32,107,97,114,97,116,101,44,32,106,117,100,111,44,32,111,114,32,116,97,101,107,119,111,110,100,111,44,32,107,101,110,100,111,44,32,102,101,110,99,105,110,103,44,32,97,110,100,32,115,111,32,111,110,32,97,110,100,32,115,111,32,102,111,114,116,104,46],"value":"As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth."}, {"hash":47977283,"name":"tmainform.ckfiltermartialarts.caption","sourcebytes":[77,97,114,116,105,97,108,32,65,114,116,115],"value":"Martial Arts"}, -{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and\/or strong language."}, +{"hash":190246206,"name":"tmainform.ckfiltermature.hint","sourcebytes":[67,111,110,116,97,105,110,115,32,115,117,98,106,101,99,116,32,109,97,116,116,101,114,32,119,104,105,99,104,32,109,97,121,32,98,101,32,116,111,111,32,101,120,116,114,101,109,101,32,102,111,114,32,112,101,111,112,108,101,32,117,110,100,101,114,32,116,104,101,32,97,103,101,32,111,102,32,49,55,46,32,84,105,116,108,101,115,32,105,110,32,116,104,105,115,32,99,97,116,101,103,111,114,121,32,109,97,121,32,99,111,110,116,97,105,110,32,105,110,116,101,110,115,101,32,118,105,111,108,101,110,99,101,44,32,98,108,111,111,100,32,97,110,100,32,103,111,114,101,44,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,32,97,110,100,47,111,114,32,115,116,114,111,110,103,32,108,97,110,103,117,97,103,101,46],"value":"Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language."}, {"hash":87604357,"name":"tmainform.ckfiltermature.caption","sourcebytes":[77,97,116,117,114,101],"value":"Mature"}, {"hash":187133582,"name":"tmainform.ckfiltermecha.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,118,111,108,118,105,110,103,32,97,110,100,32,117,115,117,97,108,108,121,32,99,111,110,99,101,110,116,114,97,116,105,110,103,32,111,110,32,97,108,108,32,116,121,112,101,115,32,111,102,32,108,97,114,103,101,32,114,111,98,111,116,105,99,32,109,97,99,104,105,110,101,115,46],"value":"A work involving and usually concentrating on all types of large robotic machines."}, {"hash":5487073,"name":"tmainform.ckfiltermecha.caption","sourcebytes":[77,101,99,104,97],"value":"Mecha"}, @@ -104,11 +104,11 @@ {"hash":94333967,"name":"tmainform.ckfiltershoujo.caption","sourcebytes":[83,104,111,117,106,111],"value":"Shoujo"}, {"hash":171132846,"name":"tmainform.ckfiltershoujoai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,117,114,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,71,105,114,108,39,39,115,32,76,111,118,101,34,44,32,115,111,32,116,111,32,115,112,101,97,107,46],"value":"Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak."}, {"hash":113331593,"name":"tmainform.ckfiltershoujoai.caption","sourcebytes":[83,104,111,117,106,111,32,65,105],"value":"Shoujo Ai"}, -{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and\/or violence."}, +{"hash":215064270,"name":"tmainform.ckfiltershounen.hint","sourcebytes":[65,32,119,111,114,107,32,105,110,116,101,110,100,101,100,32,97,110,100,32,112,114,105,109,97,114,105,108,121,32,119,114,105,116,116,101,110,32,102,111,114,32,109,97,108,101,115,46,32,84,104,101,115,101,32,119,111,114,107,115,32,117,115,117,97,108,108,121,32,105,110,118,111,108,118,101,32,102,105,103,104,116,105,110,103,32,97,110,100,47,111,114,32,118,105,111,108,101,110,99,101,46],"value":"A work intended and primarily written for males. These works usually involve fighting and/or violence."}, {"hash":167167214,"name":"tmainform.ckfiltershounen.caption","sourcebytes":[83,104,111,117,110,101,110],"value":"Shounen"}, {"hash":19597467,"name":"tmainform.ckfiltershounenai.hint","sourcebytes":[79,102,116,101,110,32,115,121,110,111,110,121,109,111,117,115,32,119,105,116,104,32,121,97,111,105,44,32,116,104,105,115,32,99,97,110,32,98,101,32,116,104,111,117,103,104,116,32,111,102,32,97,115,32,115,111,109,101,119,104,97,116,32,108,101,115,115,32,101,120,116,114,101,109,101,46,32,34,66,111,121,39,39,115,32,76,111,118,101,34,194,157,44,32,115,111,32,116,111,32,115,112,101,97,107],"value":"Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\"\u009D, so to speak"}, {"hash":206543641,"name":"tmainform.ckfiltershounenai.caption","sourcebytes":[83,104,111,117,110,101,110,32,65,105],"value":"Shounen Ai"}, -{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one\/many character(s). These challenges\/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, +{"hash":250633278,"name":"tmainform.ckfiltersliceoflife.hint","sourcebytes":[65,115,32,116,104,101,32,110,97,109,101,32,115,117,103,103,101,115,116,115,44,32,116,104,105,115,32,103,101,110,114,101,32,114,101,112,114,101,115,101,110,116,115,32,100,97,121,45,116,111,45,100,97,121,32,116,114,105,98,117,108,97,116,105,111,110,115,32,111,102,32,111,110,101,47,109,97,110,121,32,99,104,97,114,97,99,116,101,114,40,115,41,46,32,84,104,101,115,101,32,99,104,97,108,108,101,110,103,101,115,47,101,118,101,110,116,115,32,99,111,117,108,100,32,116,101,99,104,110,105,99,97,108,108,121,32,104,97,112,112,101,110,32,105,110,32,114,101,97,108,32,108,105,102,101,32,97,110,100,32,97,114,101,32,111,102,116,101,110,32,45,105,102,32,110,111,116,32,97,108,108,32,116,104,101,32,116,105,109,101,45,32,115,101,116,32,105,110,32,116,104,101,32,112,114,101,115,101,110,116,32,116,105,109,101,108,105,110,101,32,105,110,32,97,32,119,111,114,108,100,32,116,104,97,116,32,109,105,114,114,111,114,115,32,111,117,114,32,111,119,110,46],"value":"As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own."}, {"hash":262977669,"name":"tmainform.ckfiltersliceoflife.caption","sourcebytes":[83,108,105,99,101,32,111,102,32,76,105,102,101],"value":"Slice of Life"}, {"hash":68245006,"name":"tmainform.ckfiltersmut.hint","sourcebytes":[68,101,97,108,115,32,119,105,116,104,32,115,101,114,105,101,115,32,116,104,97,116,32,97,114,101,32,99,111,110,115,105,100,101,114,101,100,32,112,114,111,102,97,110,101,32,111,114,32,111,102,102,101,110,115,105,118,101,44,32,112,97,114,116,105,99,117,108,97,114,108,121,32,119,105,116,104,32,114,101,103,97,114,100,115,32,116,111,32,115,101,120,117,97,108,32,99,111,110,116,101,110,116,46],"value":"Deals with series that are considered profane or offensive, particularly with regards to sexual content."}, {"hash":369860,"name":"tmainform.ckfiltersmut.caption","sourcebytes":[83,109,117,116],"value":"Smut"}, @@ -165,7 +165,7 @@ {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, {"hash":325284,"name":"tmainform.lboptionhost.caption","sourcebytes":[72,111,115,116],"value":"Host"}, -{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host\/IP"}, +{"hash":184330448,"name":"tmainform.edoptionhost.texthint","sourcebytes":[80,114,111,120,121,32,104,111,115,116,47,73,80],"value":"Proxy host/IP"}, {"hash":164185077,"name":"tmainform.lboptionuser.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":11073157,"name":"tmainform.edoptionuser.texthint","sourcebytes":[80,114,111,120,121,32,117,115,101,114,110,97,109,101],"value":"Proxy username"}, {"hash":358036,"name":"tmainform.lboptionport.caption","sourcebytes":[80,111,114,116],"value":"Port"}, @@ -222,7 +222,7 @@ {"hash":184038819,"name":"tmainform.tsdialogs.caption","sourcebytes":[68,105,97,108,111,103,115],"value":"Dialogs"}, {"hash":263412434,"name":"tmainform.gbdialogs.caption","sourcebytes":[83,104,111,119,32,100,105,97,108,111,103,32,99,111,110,102,105,114,109,97,116,105,111,110,32,102,111,114],"value":"Show dialog confirmation for"}, {"hash":252071892,"name":"tmainform.cboptionshowquitdialog.caption","sourcebytes":[69,120,105,116,32,70,77,68],"value":"Exit FMD"}, -{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task\/favorite"}, +{"hash":242423477,"name":"tmainform.cboptionshowdeletetaskdialog.caption","sourcebytes":[68,101,108,101,116,101,32,116,97,115,107,47,102,97,118,111,114,105,116,101],"value":"Delete task/favorite"}, {"hash":221590857,"name":"tmainform.cboptionshowdownloadmangalistdialog.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,109,97,110,103,97,32,108,105,115,116,32,105,102,32,101,109,112,116,121],"value":"Download manga list if empty"}, {"hash":194645779,"name":"tmainform.tswebsites.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, {"hash":194645779,"name":"tmainform.tswebsiteselection.caption","sourcebytes":[87,101,98,115,105,116,101,115],"value":"Websites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 132d2d773..d2de2eb53 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1870,7 +1870,7 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); procedure TMainForm.miDownloadMergeCompletedClick(Sender: TObject); var - i, j: Cardinal; + i, j: Integer; ic, jc: TTaskContainer; // merge all finished tasks that have same manga name, website and directory begin @@ -3392,8 +3392,8 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); end; begin - miDownloadDeleteCompleted.Enabled := True; - miDownloadMergeCompleted.Enabled := True; + miDownloadDeleteCompleted.Enabled := DLManager.Count > 0; + miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; with DLManager do begin if vtDownload.SelectedCount = 0 then begin From 1fab8e4e07052547361a2e3abdd560a6443ac826 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 04:10:26 +0800 Subject: [PATCH 1894/2794] mangago, fixed title fixed #707 --- baseunits/modules/MangaGo.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index f675360b5..e552b7300 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -61,6 +61,7 @@ function GetInfo(const MangaInfo: TMangaInformation; try coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="left cover"]/img/@src')); title := XPathString('//h1'); + if RightStr(title, 6) = ' manga' then SetLength(title, Length(title) - 6); status := MangaInfoStatusIfPos(XPathString('//div[@class="manga_right"]//td/label[.="Status:"]/following-sibling::*/text()')); authors := XPathString('//div[@class="manga_right"]//td/label[.="Author:"]/string-join(following-sibling::*/text(),", ")'); genres := XPathString('//div[@class="manga_right"]//td/label[.="Genre(s):"]/string-join(following-sibling::*/text(),", ")'); From d8e3e53cbef4a22de1777f06496a91a47c0ff31c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 04:14:17 +0800 Subject: [PATCH 1895/2794] mangazuki, fixed title fixed #708 --- baseunits/modules/MangaZuki.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 0b9f84b7b..c16728584 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -62,7 +62,7 @@ function GetInfo(const MangaInfo: TMangaInformation; try coverLink := XPathString('//*[@class="profile-thumb"]/img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@class="media-body"]/h1/text()'); + if title = '' then title := XPathString('//div[@class="media-body"]/h2/text()'); summary := XPathString('//h6[text()="Synopsis"]/following-sibling::p'); while True do begin From ee393f7e6dd1cd9acacc695b46108aefa0a877c2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 04:54:19 +0800 Subject: [PATCH 1896/2794] added saveimage with thttpsendthread --- baseunits/uBaseUnit.pas | 20 ++++++++++++++++++++ baseunits/uDownloadsManager.pas | 9 +-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index e7349eb25..3bad2dffe 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -758,6 +758,8 @@ function SaveImage(const AHTTP: THTTPSend; URL: String; function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; +function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String; var ASavedFileName: String): Boolean; overload; +function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; overload; // check file exist with known extensions. AFilename is a filename without extensions function ImageFileExist(const AFileName: String): Boolean; @@ -3608,6 +3610,24 @@ function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Result := SaveImage(nil, mangaSiteID, URL, Path, Name, SavedFilename, Reconnect); end; +function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, + AFileName: String; var ASavedFileName: String): Boolean; +begin + Result := False; + if AHTTP.GET(AURL) then + begin + ASavedFileName := SaveImageStreamToFile(AHTTP, APath, AFileName); + Result := ASavedFileName <> ''; + end; +end; + +function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; +begin + Result := False; + if AHTTP.GET(AURL) then + Result := SaveImageStreamToFile(AHTTP, APath, AFileName) <> ''; +end; + function ImageFileExist(const AFileName: String): Boolean; begin Result := FindImageFile(AFileName) <> ''; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 90a526ed8..deb4d0849 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -912,14 +912,7 @@ function TDownloadThread.DownloadImage: Boolean; if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL else - Result := uBaseUnit.SaveImage( - FHTTP, - Task.Container.MangaSiteID, - workURL, - Task.CurrentWorkingDir, - workFilename, - savedFilename, - Task.Container.Manager.RetryConnect); + Result := uBaseUnit.SaveImage(FHTTP, workURL, Task.CurrentWorkingDir, workFilename, savedFilename); end; if Terminated then Exit(False); if Result then From 49c35c9615a58611a4b68c7210040e1e94eb45eb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 05:08:31 +0800 Subject: [PATCH 1897/2794] changed saveimage to downloadandsaveimage --- baseunits/uBaseUnit.pas | 8 ++++---- baseunits/uDownloadsManager.pas | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3bad2dffe..f0db3eca7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -758,8 +758,8 @@ function SaveImage(const AHTTP: THTTPSend; URL: String; function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; inline; -function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String; var ASavedFileName: String): Boolean; overload; -function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; overload; +function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String; var ASavedFileName: String): Boolean; overload; +function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; overload; // check file exist with known extensions. AFilename is a filename without extensions function ImageFileExist(const AFileName: String): Boolean; @@ -3610,7 +3610,7 @@ function SaveImage(const mangaSiteID: Integer; URL: String; const Path, Result := SaveImage(nil, mangaSiteID, URL, Path, Name, SavedFilename, Reconnect); end; -function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, +function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String; var ASavedFileName: String): Boolean; begin Result := False; @@ -3621,7 +3621,7 @@ function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, end; end; -function SaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; +function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; begin Result := False; if AHTTP.GET(AURL) then diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index deb4d0849..700169d1e 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -912,7 +912,7 @@ function TDownloadThread.DownloadImage: Boolean; if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL else - Result := uBaseUnit.SaveImage(FHTTP, workURL, Task.CurrentWorkingDir, workFilename, savedFilename); + Result := uBaseUnit.DownloadAndSaveImage(FHTTP, workURL, Task.CurrentWorkingDir, workFilename, savedFilename); end; if Terminated then Exit(False); if Result then From 9c23b58c447e609f7c6c152053b0fac63fb035d5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 23 Aug 2017 05:22:52 +0800 Subject: [PATCH 1898/2794] japscan, fixed download fixed #694 --- baseunits/modules/JapScan.pas | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas index d66fd0af4..35759732c 100644 --- a/baseunits/modules/JapScan.pas +++ b/baseunits/modules/JapScan.pas @@ -83,24 +83,22 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - v := XPath('//img[@id="image"]'); - dataimg := v.toNode.getAttribute('data-img'); - imgurl := v.toNode.getAttribute('src'); - if Pos(dataimg, imgurl) <> 0 then - begin - imgurl := StringReplace(imgurl, dataimg, '', []); - for v in XPath('//select[@id="pages"]/option/@data-img') do - PageLinks.Add(imgurl + v.toString); - end; - finally - Free; - end; + XPathStringAll('//select[@id="pages"]/option/@data-img', Document, PageLinks); end; end; end; +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + with DownloadThread, DownloadThread.FHTTP, DownloadThread.Task.Container do + begin + if GET(AppendURLDelim(FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr])) + IncStr(WorkId) + '.html') then + Result := DownloadAndSaveImage(FHTTP, XPathString('//img[@id="image"]/@src', Document), APath, AName); + end; +end; + procedure RegisterModule; begin with AddModule do @@ -110,6 +108,7 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; end; end; From 5aae6c039170b80449b22f61cfaf539e75eb671f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 24 Aug 2017 02:16:08 +0800 Subject: [PATCH 1899/2794] change sort ui even when no sort performed closed #714 --- mangadownloader/forms/frmMain.pas | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d2de2eb53..9ba3b2c83 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3960,14 +3960,14 @@ procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; ); begin if Button <> mbLeft then Exit; - if DLManager.Count < 2 then Exit; if (Column = 2) or (Column = 3) then Exit; if DLManager.SortColumn = Column then DLManager.SortDirection := not DLManager.SortDirection; DLManager.SortColumn := Column; vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); vtDownload.Header.SortColumn := Column; - DLManager.Sort(Column); + if DLManager.Count > 1 then + DLManager.Sort(Column); UpdateVtDownload; end; @@ -4142,21 +4142,18 @@ procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; begin if Button <> mbLeft then Exit; if FavoriteManager.isRunning then Exit; - if FavoriteManager.Count < 2 then Exit; if Column = 0 then Exit; FavoriteManager.isRunning := True; - try - if FavoriteManager.SortColumn = Column then - FavoriteManager.sortDirection := not FavoriteManager.sortDirection - else - FavoriteManager.SortColumn := Column; - vtFavorites.Header.SortColumn := Column; - vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); + if FavoriteManager.SortColumn = Column then + FavoriteManager.sortDirection := not FavoriteManager.sortDirection + else + FavoriteManager.SortColumn := Column; + vtFavorites.Header.SortColumn := Column; + vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); + if FavoriteManager.Count > 1 then FavoriteManager.Sort(Column); - finally - UpdateVtFavorites; - FavoriteManager.isRunning := False; - end; + UpdateVtFavorites; + FavoriteManager.isRunning := False; end; procedure TMainForm.vtFavoritesPaintText(Sender: TBaseVirtualTree; From 791d1e3c0536a44d649dca3be623cb04cfa45d71 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 26 Aug 2017 19:54:59 +0800 Subject: [PATCH 1900/2794] Bump version 0.9.125.0 --- changelog.txt | 10 ++++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index a09ff05bb..6b12856c2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,16 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.125.0 (26-08-2017) +[*] Japscan: fixed download +[*] MangaZuki: fixed title +[*] MangaGo: fixed title +[*] HeyManga: fixed download +[*] Fixed failed chapter(s) always marked as finished +[+] Added option to always start task from failed chapter if any +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.124.0...0.9.125.0 + 0.9.124.0 (16-08-2017) [*] MangaShiro: fixed all [*] MangaFox: remove "new" from chapter's title diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index c42c93e31..72e886264 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="124"/> + <RevisionNr Value="125"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 9306debca..2db7f3483 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.124.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.124.0/fmd_0.9.124.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.124.0/fmd_0.9.124.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.124.0/fmd_0.9.124.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.124.0/fmd_0.9.124.0_Win64.7z +VERSION=0.9.125.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.125.0/fmd_0.9.125.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.125.0/fmd_0.9.125.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.125.0/fmd_0.9.125.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.125.0/fmd_0.9.125.0_Win64.7z From 8926e56dc3f12b9bbd4b4e4eb6b543780908bd0e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Aug 2017 05:14:21 +0800 Subject: [PATCH 1901/2794] added class helper sendwarningstrings for multilog --- baseunits/SimpleException/SimpleException.pas | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/baseunits/SimpleException/SimpleException.pas b/baseunits/SimpleException/SimpleException.pas index f59ebeb90..4518ba882 100644 --- a/baseunits/SimpleException/SimpleException.pas +++ b/baseunits/SimpleException/SimpleException.pas @@ -126,6 +126,7 @@ TLoggerException = class helper for TLogger public procedure SendExceptionStr(const AText: String; AExceptionStr: String); procedure SendStrings(const AText: String; AValue: String); + procedure SendWarningStrings(const AText: String; AValue: String); end; {$ENDIF} @@ -154,6 +155,13 @@ procedure TLoggerException.SendStrings(const AText: String; AValue: String); begin SendBuffer(ltStrings, AText, AValue[1], Length(AValue)); end; + +procedure TLoggerException.SendWarningStrings(const AText: String; + AValue: String); +begin + SendBuffer(ltWarning, AText, AValue[1], Length(AValue)); +end; + {$ENDIF} procedure SetMaxStackCount(const ACount: Integer); From aa1fe6d8d5c6a4696575bcd9b6c0d11abc82245c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Aug 2017 05:14:53 +0800 Subject: [PATCH 1902/2794] upacker publish property savedfilename and ext --- baseunits/uPacker.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 979d13953..9555cf238 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -33,6 +33,8 @@ TPacker = class CompressionQuality: Cardinal; function Execute: Boolean; property FileList: TStringList read FFileList; + property SavedFileName: String read FSavedFileName; + property Ext: String read FExt; public constructor Create; destructor Destroy; override; @@ -161,6 +163,11 @@ function TPacker.Execute: Boolean; constructor TPacker.Create; begin FFileList := TStringList.Create; + FSavedFileName := ''; + FExt := ''; + Path := ''; + FileName := ''; + Format := pfZIP; end; destructor TPacker.Destroy; From 55310eb61d2347924993759a10714f9b8b0a12fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Aug 2017 05:15:16 +0800 Subject: [PATCH 1903/2794] downloadsmanager, added more log message on failed --- baseunits/uDownloadsManager.pas | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 700169d1e..f7a749c65 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -276,7 +276,7 @@ TDownloadManager = class implementation uses - frmMain, WebsiteModules, FMDVars; + frmMain, WebsiteModules, FMDVars, SimpleException; function IntToStr(Value: Cardinal): String; begin @@ -800,6 +800,8 @@ function TTaskThread.Compress: Boolean; uPacker.FileList.Add(s); end; Result := uPacker.Execute; + if not Result then + Logger.SendWarning(Self.ClassName+', failed to compress. '+uPacker.SavedFileName); except on E: Exception do begin @@ -1254,7 +1256,7 @@ procedure TTaskThread.Execute; // If Container doesn't have any image, we will skip the loop. Otherwise // download them Container.PageNumber := Container.PageLinks.Count; - if (Container.PageLinks.Count > 0) then + if Container.PageLinks.Count > 0 then begin Flag := CS_DOWNLOAD; Container.WorkCounter := 0; @@ -1288,15 +1290,25 @@ procedure TTaskThread.Execute; Container.Status := STATUS_FAILED; end else + begin Container.Status := STATUS_FAILED; + Logger.SendWarningStrings(Format('%s, download failed. "%s" "%s" "%s"', + [Self.ClassName, + Container.DownloadInfo.Title, + Container.ChapterName[Container.CurrentDownloadChapterPtr], + Container.ChapterLinks[Container.CurrentDownloadChapterPtr] + ]), Container.PageLinks.Text); + end; end - else begin - Logger.SendWarning(Format('%s, failed download image PageLinks=%d "%s" > "%s"', - [Self.ClassName, - Container.PageLinks.Count, - Container.DownloadInfo.Title, - Container.ChapterName[Container.CurrentDownloadChapterPtr]])); + else + begin Container.Status := STATUS_FAILED; + Logger.SendWarning(Format('%s, pagelinks is empty. "%s" "%s" "%s"', + [Self.ClassName, + Container.DownloadInfo.Title, + Container.ChapterName[Container.CurrentDownloadChapterPtr], + Container.ChapterLinks[Container.CurrentDownloadChapterPtr] + ])); end; if Container.Status = STATUS_FAILED then From 5957b148fe12c0682a249fa4db7d2492348c237b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 27 Aug 2017 05:33:31 +0800 Subject: [PATCH 1904/2794] madoami, prevent range error on getnameandlink #718 --- baseunits/modules/Madokami.pas | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index feae1e8d9..c3bb4ff81 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -158,10 +158,15 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); workPtr := StrToIntDef(AURL, 0); + u := ''; if Module.CurrentDirectoryIndex < Length(madokamilist) then - u := MaybeFillHost(Module.RootURL, madokamiulist[Module.CurrentDirectoryIndex][workPtr]) + begin + if workPtr < madokamiulist[Module.CurrentDirectoryIndex].Count then + u := MaybeFillHost(Module.RootURL, madokamiulist[Module.CurrentDirectoryIndex][workPtr]); + end else u := Module.RootURL + madokamiotherlist[Module.CurrentDirectoryIndex-Length(madokamilist)]; + if u = '' then Exit; if GETWithLogin(MangaInfo.FHTTP, u) then begin Result := NO_ERROR; if Module.CurrentDirectoryIndex < Length(madokamilist) then begin From 598d2127098e778a8409456f86b4a5d74cf1f06b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Aug 2017 04:24:51 +0800 Subject: [PATCH 1905/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 74bcaf987..beb66b2a9 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 74bcaf987eedd99e3337d963c409c785292f2d15 +Subproject commit beb66b2a97d3ab59b5442b7b8d3645c9bde87d41 From 1fed03a8ab74c656b5a4210b3a444f3f35d10e28 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Aug 2017 04:26:48 +0800 Subject: [PATCH 1906/2794] httpsendthread.httprequest cleanup url fixed #720 --- baseunits/httpsendthread.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 1dca3e4e6..dd212a2fa 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, httpsend, synautil, synacode, ssl_openssl, blcksock, - GZIPUtils, BaseThread, dateutils; + GZIPUtils, BaseThread, dateutils, strutils; const @@ -436,7 +436,9 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: mstream: TMemoryStream; begin Result := False; - rurl := MaybeEncodeURL(URL); + rurl := TrimRight(TrimLeftSet(URL, [':', '/', #0..' '])); + if rurl = '' then Exit; + rurl := MaybeEncodeURL(rurl); if Pos('HTTP/', Headers.Text) = 1 then Reset; HTTPHeader := TStringList.Create; HTTPHeader.Assign(Headers); From 34a3ea5ca2d55195631ba48edeabed7cd321c208 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Aug 2017 04:49:44 +0800 Subject: [PATCH 1907/2794] madokami, prevent update list if there is no account fixed #718 --- baseunits/modules/Madokami.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index c3bb4ff81..88870a042 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -33,6 +33,7 @@ implementation madokamiauth: String = ''; locklogin: TRTLCriticalSection; madokamiulist: array of TStrings; + accountexist: Boolean = False; function Login(const AHTTP: THTTPSendThread): Boolean; begin @@ -115,6 +116,8 @@ function BeforeUpdateList(const Module: TModuleContainer): Boolean; i: Integer; begin Result := True; + accountexist := Account.Username[modulename] <> ''; + if not accountexist then Exit; ClearMadokamiUlist; SetLength(madokamiulist, Length(madokamilist)); for i := Low(madokamiulist) to High(madokamiulist) do @@ -124,6 +127,7 @@ function BeforeUpdateList(const Module: TModuleContainer): Boolean; function AfterUpdateList(const Module: TModuleContainer): Boolean; begin Result := True; + if not accountexist then Exit; ClearMadokamiUlist; end; @@ -131,6 +135,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NO_ERROR; + if not accountexist then Exit; if workPtr < Length(madokamilist) then begin if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/Manga/' + madokamilist[WorkPtr+1]) then begin XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, madokamiulist[WorkPtr]); @@ -156,6 +161,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; l1: TStrings; begin Result := NET_PROBLEM; + if not accountexist then Exit; if MangaInfo = nil then Exit(UNKNOWN_ERROR); workPtr := StrToIntDef(AURL, 0); u := ''; From 9090d528074d46d78fff4e916851b0c8ed099fb2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Aug 2017 04:57:44 +0800 Subject: [PATCH 1908/2794] Bump version 0.9.126.0 --- changelog.txt | 6 ++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6b12856c2..470033cd6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.126.0 (29-08-2017) +[*] Madokami: fixed update list +[*] Fixed download issue with some website +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.125.0...0.9.126.0 + 0.9.125.0 (26-08-2017) [*] Japscan: fixed download [*] MangaZuki: fixed title diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 72e886264..fb7b36e55 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="125"/> + <RevisionNr Value="126"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 2db7f3483..d0cc291d9 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.125.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.125.0/fmd_0.9.125.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.125.0/fmd_0.9.125.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.125.0/fmd_0.9.125.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.125.0/fmd_0.9.125.0_Win64.7z +VERSION=0.9.126.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.126.0/fmd_0.9.126.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.126.0/fmd_0.9.126.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.126.0/fmd_0.9.126.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.126.0/fmd_0.9.126.0_Win64.7z From 34505928d4aa943cc41106d2959e940797036a0f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 29 Aug 2017 05:18:37 +0800 Subject: [PATCH 1909/2794] mangafox, remove last invalid page --- baseunits/modules/MangaFox.pas | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 5b6f0a834..8f65d710a 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -90,12 +90,16 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; Result := True; s := XPathString('//div[@class="read_img"]//img[@id="image"]/@src', Document); PageLinks[DownloadThread.WorkId] := s; - // remove invalid last invalid page - if (DownloadThread.WorkId = PageLinks.Count - 1) and - (RightStr(LowerCase(RemovePathDelim(s)), 10) = 'compressed') then + // remove invalid last page + if DownloadThread.WorkId = PageLinks.Count - 1 then begin - PageLinks.Delete(DownloadThread.WorkId); - PageNumber := PageLinks.Count; + s := LowerCase(RemovePathDelim(s)); + if (RightStr(s, 10) = 'compressed') or + (Pos('/compressed?', s) <> 0) then + begin + PageLinks.Delete(DownloadThread.WorkId); + PageNumber := PageLinks.Count; + end; end; end; end; From a389c248ebe178f0bef7943857c52eee15e6d6f7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Nov 2017 18:06:16 +0800 Subject: [PATCH 1910/2794] fix check update --- baseunits/CheckUpdate.pas | 43 +++++++++++++++------------------------ baseunits/FMDOptions.pas | 2 +- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index b12bdabfe..7f03e54c1 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -93,38 +93,27 @@ procedure TCheckUpdateThread.SyncEndUpdate; end; procedure TCheckUpdateThread.Execute; -var - l: TStringList; - updateFound: Boolean = False; begin + fNewVersionNumber := ''; + fUpdateURL := ''; + fChangelog := ''; Synchronize(@SyncStartUpdate); - l := TStringList.Create; - try - fNewVersionNumber := FMD_VERSION_NUMBER; - fUpdateURL := ''; - if not Terminated and - GetPage(FHTTP, TObject(l), UPDATE_URL + 'update', 3) then - if l.Count > 1 then - begin - l.NameValueSeparator := '='; - if Trim(l.Values['VERSION']) <> FMD_VERSION_NUMBER then - begin - fNewVersionNumber := Trim(l.Values['VERSION']); - fUpdateURL := Trim(l.Values[UpperCase(FMD_TARGETOS)]); - if fUpdateURL <> '' then - updateFound := True; - FHTTP.Clear; - l.Clear; - if not Terminated and - GetPage(FHTTP, TObject(l), UPDATE_URL + 'changelog.txt', 3) then - fChangelog := l.Text; - end; - end; + if not Terminated and FHTTP.Get(UPDATE_URL + 'update') then + with TStringList.Create do try + LoadFromStream(FHTTP.Document); + if Count <> 0 then begin + NameValueSeparator := '='; + fNewVersionNumber := Trim(Values['VERSION']); + if fNewVersionNumber <> FMD_VERSION_NUMBER then + fUpdateURL := Trim(Values[UpperCase(FMD_TARGETOS)]); + end; finally - l.Free; + Free; end; + if not Terminated and (fUpdateURL <> '') and FHTTP.Get(UPDATE_URL + 'changelog.txt') then + fChangelog := StreamToString(FHTTP.Document); Synchronize(@SyncEndUpdate); - if not Terminated and updateFound and (not isDlgCounter) then + if not Terminated and (fUpdateURL <> '') and (not isDlgCounter) then Synchronize(@MainThreadUpdate); end; diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index f53886454..83c038cfb 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -340,7 +340,7 @@ function GetCurrentBinVersion: String; {$ENDIF} for i := 0 to AppVerInfo.Count - 1 do AppVerInfo.Strings[i] := LowerCase(AppVerInfo.Names[i]) + '=' + AppVerInfo.ValueFromIndex[i]; - Result := AppVerInfo.Values['fileversion']; + Result := Trim(AppVerInfo.Values['fileversion']); end; except end; From 079af2231162d270a4d183c52c34a81a5cb21b83 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 11 Nov 2017 18:11:29 +0800 Subject: [PATCH 1911/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index beb66b2a9..4c45e99b3 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit beb66b2a97d3ab59b5442b7b8d3645c9bde87d41 +Subproject commit 4c45e99b30e3749c8b69ece7e74d6fa3501ddb9c From f4fb27bc05b285f336f14719aa8cdc67b56c00be Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 17 Nov 2017 05:43:26 +0800 Subject: [PATCH 1912/2794] mangahere, exclude and remove featured page --- baseunits/modules/MangaHere.pas | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index bf312589f..e2aae3501 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -90,7 +90,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - PageNumber := XPath('(//span[@class="right"]/select)[1]/option').Count; + PageNumber := XPath('(//span[@class="right"]/select)[1]/option[not(.="Featured")]').Count; PageLinks.Add(XPathString(imagepath)); finally Free; @@ -108,6 +108,12 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread, FHTTP, Task.Container do begin + if (WorkId = PageLinks.Count - 1) and (Pos('/featured.', AURL) <> 0) then + begin + PageLinks.Delete(WorkId); + Exit; + end; + s := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); if WorkId > 0 then s := s + IncStr(WorkId) + '.html'; From 1077cadd1232faffa1a7f25fd69e02d33537774c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 17 Nov 2017 06:40:49 +0800 Subject: [PATCH 1913/2794] change ubaseunit, udata and downloadmanager mode to objofc --- .../AnimExtremist/chapter_page_number.inc | 4 +- .../includes/AnimExtremist/image_url.inc | 4 +- .../AnimExtremist/manga_information.inc | 4 +- .../AnimExtremist/names_and_links.inc | 4 +- .../includes/AnimeA/chapter_page_number.inc | 4 +- .../includes/AnimeA/directory_page_number.inc | 6 +-- baseunits/includes/AnimeA/image_url.inc | 4 +- .../includes/AnimeA/manga_information.inc | 4 +- .../AnimeStory/chapter_page_number.inc | 4 +- baseunits/includes/AnimeStory/image_url.inc | 4 +- .../includes/AnimeStory/manga_information.inc | 4 +- .../includes/AnimeStory/names_and_links.inc | 4 +- .../CentralDeMangas/directory_page_number.inc | 4 +- .../includes/CentralDeMangas/image_url.inc | 4 +- .../CentralDeMangas/manga_information.inc | 4 +- .../CentralDeMangas/names_and_links.inc | 4 +- .../CentrumMangi_PL/chapter_page_number.inc | 4 +- .../includes/CentrumMangi_PL/image_url.inc | 4 +- .../CentrumMangi_PL/manga_information.inc | 4 +- .../CentrumMangi_PL/names_and_links.inc | 4 +- .../includes/DM5/directory_page_number.inc | 4 +- .../includes/EGScans/chapter_page_number.inc | 4 +- baseunits/includes/EGScans/image_url.inc | 4 +- .../includes/EGScans/manga_information.inc | 4 +- .../includes/EGScans/names_and_links.inc | 4 +- .../EsMangaHere/chapter_page_number.inc | 4 +- baseunits/includes/EsMangaHere/image_url.inc | 4 +- .../EsMangaHere/manga_information.inc | 4 +- .../includes/EsMangaHere/names_and_links.inc | 4 +- .../ExtremeMangas/chapter_page_number.inc | 4 +- .../ExtremeMangas/manga_information.inc | 4 +- .../ExtremeMangas/names_and_links.inc | 4 +- .../includes/IKomik/chapter_page_number.inc | 4 +- .../includes/IKomik/directory_page_number.inc | 4 +- baseunits/includes/IKomik/image_url.inc | 4 +- .../includes/IKomik/manga_information.inc | 4 +- baseunits/includes/IKomik/names_and_links.inc | 4 +- .../includes/Imanhua/names_and_links.inc | 4 +- .../JapanShin/chapter_page_number.inc | 4 +- .../JapanShin/directory_page_number.inc | 4 +- baseunits/includes/JapanShin/image_url.inc | 4 +- .../includes/JapanShin/manga_information.inc | 4 +- .../includes/JapanShin/names_and_links.inc | 4 +- .../includes/Kivmanga/chapter_page_number.inc | 4 +- baseunits/includes/Kivmanga/image_url.inc | 4 +- .../includes/Kivmanga/manga_information.inc | 4 +- .../includes/Kivmanga/names_and_links.inc | 4 +- .../LectureEnLigne/chapter_page_number.inc | 4 +- .../LectureEnLigne/directory_page_number.inc | 4 +- .../includes/LectureEnLigne/image_url.inc | 4 +- .../LectureEnLigne/manga_information.inc | 4 +- .../LectureEnLigne/names_and_links.inc | 4 +- baseunits/includes/MangaAr/image_url.inc | 4 +- .../includes/MangaAr/manga_information.inc | 4 +- .../includes/MangaAr/names_and_links.inc | 4 +- .../includes/MangaAt/chapter_page_number.inc | 4 +- .../MangaAt/directory_page_number.inc | 4 +- baseunits/includes/MangaAt/image_url.inc | 4 +- .../includes/MangaAt/manga_information.inc | 4 +- .../includes/MangaAt/names_and_links.inc | 4 +- .../MangaHost/chapter_page_number.inc | 4 +- .../MangaHost/directory_page_number.inc | 4 +- baseunits/includes/MangaHost/image_url.inc | 4 +- .../includes/MangaHost/manga_information.inc | 4 +- .../includes/MangaHost/names_and_links.inc | 4 +- .../includes/MangaKu/chapter_page_number.inc | 4 +- .../includes/MangaKu/manga_information.inc | 4 +- .../includes/MangaKu/names_and_links.inc | 4 +- .../MangaLib_PL/chapter_page_number.inc | 4 +- baseunits/includes/MangaLib_PL/image_url.inc | 4 +- .../MangaLib_PL/manga_information.inc | 4 +- .../includes/MangaLib_PL/names_and_links.inc | 4 +- .../includes/MangaOku/chapter_page_number.inc | 4 +- baseunits/includes/MangaOku/image_url.inc | 4 +- .../includes/MangaOku/manga_information.inc | 4 +- .../includes/MangaOku/names_and_links.inc | 4 +- .../includes/MangaREADER_POR/image_url.inc | 4 +- .../MangaREADER_POR/manga_information.inc | 8 ++-- .../MangaTown/chapter_page_number.inc | 4 +- .../MangaTown/directory_page_number.inc | 4 +- baseunits/includes/MangaTown/image_url.inc | 4 +- .../includes/MangaTown/manga_information.inc | 4 +- .../includes/MangaTown/names_and_links.inc | 4 +- .../includes/MangasPROJECT/image_url.inc | 4 +- .../MangasPROJECT/manga_information.inc | 8 ++-- .../MeinManga/chapter_page_number.inc | 4 +- baseunits/includes/MeinManga/image_url.inc | 4 +- .../includes/MeinManga/manga_information.inc | 8 ++-- .../includes/MeinManga/names_and_links.inc | 4 +- .../includes/NHentai/chapter_page_number.inc | 4 +- .../NHentai/directory_page_number.inc | 4 +- baseunits/includes/NHentai/image_url.inc | 4 +- .../includes/NHentai/manga_information.inc | 4 +- .../includes/NHentai/names_and_links.inc | 4 +- .../includes/OneManga/chapter_page_number.inc | 4 +- .../OneManga/directory_page_number.inc | 4 +- baseunits/includes/OneManga/image_url.inc | 4 +- .../includes/OneManga/manga_information.inc | 4 +- .../includes/OneManga/names_and_links.inc | 4 +- .../S2Scans/directory_page_number.inc | 4 +- .../includes/S2Scans/manga_information.inc | 4 +- .../includes/S2Scans/names_and_links.inc | 4 +- .../includes/ScanManga/manga_information.inc | 4 +- .../includes/ScanManga/names_and_links.inc | 4 +- .../includes/Starkana/chapter_page_number.inc | 4 +- baseunits/includes/Starkana/image_url.inc | 4 +- .../includes/Starkana/manga_information.inc | 4 +- .../includes/Starkana/names_and_links.inc | 4 +- .../Turkcraft/chapter_page_number.inc | 4 +- baseunits/includes/Turkcraft/image_url.inc | 4 +- .../includes/Turkcraft/manga_information.inc | 4 +- .../includes/Turkcraft/names_and_links.inc | 4 +- .../UnixManga/chapter_page_number.inc | 4 +- baseunits/includes/UnixManga/image_url.inc | 4 +- .../includes/UnixManga/manga_information.inc | 4 +- .../includes/UnixManga/names_and_links.inc | 4 +- .../VnSharing/directory_page_number.inc | 4 +- baseunits/includes/VnSharing/image_url.inc | 4 +- .../includes/VnSharing/manga_information.inc | 4 +- .../includes/VnSharing/names_and_links.inc | 4 +- baseunits/uBaseUnit.pas | 38 ++++--------------- baseunits/uData.pas | 32 ++++++++-------- baseunits/uDownloadsManager.pas | 16 ++++---- 123 files changed, 278 insertions(+), 302 deletions(-) diff --git a/baseunits/includes/AnimExtremist/chapter_page_number.inc b/baseunits/includes/AnimExtremist/chapter_page_number.inc index 9e5bc20f8..7c63df939 100644 --- a/baseunits/includes/AnimExtremist/chapter_page_number.inc +++ b/baseunits/includes/AnimExtremist/chapter_page_number.inc @@ -10,8 +10,8 @@ '.html', '', []) + '-1.html', Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/AnimExtremist/image_url.inc b/baseunits/includes/AnimExtremist/image_url.inc index d4cefdfb4..3a4bd6ac2 100644 --- a/baseunits/includes/AnimExtremist/image_url.inc +++ b/baseunits/includes/AnimExtremist/image_url.inc @@ -12,8 +12,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/AnimExtremist/manga_information.inc b/baseunits/includes/AnimExtremist/manga_information.inc index 8249e04af..fd7cd1f1a 100644 --- a/baseunits/includes/AnimExtremist/manga_information.inc +++ b/baseunits/includes/AnimExtremist/manga_information.inc @@ -13,8 +13,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/AnimExtremist/names_and_links.inc b/baseunits/includes/AnimExtremist/names_and_links.inc index d4e4d37eb..8833dde6b 100644 --- a/baseunits/includes/AnimExtremist/names_and_links.inc +++ b/baseunits/includes/AnimExtremist/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/AnimeA/chapter_page_number.inc b/baseunits/includes/AnimeA/chapter_page_number.inc index 69b3bc0cf..775f37a1d 100644 --- a/baseunits/includes/AnimeA/chapter_page_number.inc +++ b/baseunits/includes/AnimeA/chapter_page_number.inc @@ -12,8 +12,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/AnimeA/directory_page_number.inc b/baseunits/includes/AnimeA/directory_page_number.inc index 4efe91a29..bc5f8e299 100644 --- a/baseunits/includes/AnimeA/directory_page_number.inc +++ b/baseunits/includes/AnimeA/directory_page_number.inc @@ -11,8 +11,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then @@ -34,4 +34,4 @@ end; end; Source.Free; - end; \ No newline at end of file + end; diff --git a/baseunits/includes/AnimeA/image_url.inc b/baseunits/includes/AnimeA/image_url.inc index 9a80149cd..333c9bc5a 100644 --- a/baseunits/includes/AnimeA/image_url.inc +++ b/baseunits/includes/AnimeA/image_url.inc @@ -12,8 +12,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/AnimeA/manga_information.inc b/baseunits/includes/AnimeA/manga_information.inc index b63cd4808..9930a9d16 100644 --- a/baseunits/includes/AnimeA/manga_information.inc +++ b/baseunits/includes/AnimeA/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/AnimeStory/chapter_page_number.inc b/baseunits/includes/AnimeStory/chapter_page_number.inc index 12f23eba4..bdc601d9e 100644 --- a/baseunits/includes/AnimeStory/chapter_page_number.inc +++ b/baseunits/includes/AnimeStory/chapter_page_number.inc @@ -11,8 +11,8 @@ s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/AnimeStory/image_url.inc b/baseunits/includes/AnimeStory/image_url.inc index 01dd08137..a85230e9d 100644 --- a/baseunits/includes/AnimeStory/image_url.inc +++ b/baseunits/includes/AnimeStory/image_url.inc @@ -11,8 +11,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/AnimeStory/manga_information.inc b/baseunits/includes/AnimeStory/manga_information.inc index 78693e1da..7a1766fed 100644 --- a/baseunits/includes/AnimeStory/manga_information.inc +++ b/baseunits/includes/AnimeStory/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/AnimeStory/names_and_links.inc b/baseunits/includes/AnimeStory/names_and_links.inc index 1595e7108..93250f303 100644 --- a/baseunits/includes/AnimeStory/names_and_links.inc +++ b/baseunits/includes/AnimeStory/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/CentralDeMangas/directory_page_number.inc b/baseunits/includes/CentralDeMangas/directory_page_number.inc index 6696ea991..2c0ea5d56 100644 --- a/baseunits/includes/CentralDeMangas/directory_page_number.inc +++ b/baseunits/includes/CentralDeMangas/directory_page_number.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/CentralDeMangas/image_url.inc b/baseunits/includes/CentralDeMangas/image_url.inc index 71d79d249..01da6bafa 100644 --- a/baseunits/includes/CentralDeMangas/image_url.inc +++ b/baseunits/includes/CentralDeMangas/image_url.inc @@ -12,8 +12,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/CentralDeMangas/manga_information.inc b/baseunits/includes/CentralDeMangas/manga_information.inc index 7ccc22421..2a4331ac4 100644 --- a/baseunits/includes/CentralDeMangas/manga_information.inc +++ b/baseunits/includes/CentralDeMangas/manga_information.inc @@ -18,8 +18,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/CentralDeMangas/names_and_links.inc b/baseunits/includes/CentralDeMangas/names_and_links.inc index e31fd2d60..9764a5efd 100644 --- a/baseunits/includes/CentralDeMangas/names_and_links.inc +++ b/baseunits/includes/CentralDeMangas/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc index d9b3b82a5..7deb8fc25 100644 --- a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc +++ b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc @@ -12,8 +12,8 @@ s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/CentrumMangi_PL/image_url.inc b/baseunits/includes/CentrumMangi_PL/image_url.inc index 4db99d04c..4b2ff1cca 100644 --- a/baseunits/includes/CentrumMangi_PL/image_url.inc +++ b/baseunits/includes/CentrumMangi_PL/image_url.inc @@ -12,8 +12,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/CentrumMangi_PL/manga_information.inc b/baseunits/includes/CentrumMangi_PL/manga_information.inc index e0e5894ce..d92097669 100644 --- a/baseunits/includes/CentrumMangi_PL/manga_information.inc +++ b/baseunits/includes/CentrumMangi_PL/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/CentrumMangi_PL/names_and_links.inc b/baseunits/includes/CentrumMangi_PL/names_and_links.inc index 0b7023efb..ca7ed7971 100644 --- a/baseunits/includes/CentrumMangi_PL/names_and_links.inc +++ b/baseunits/includes/CentrumMangi_PL/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/DM5/directory_page_number.inc b/baseunits/includes/DM5/directory_page_number.inc index deef3fbef..ab21ca8c0 100644 --- a/baseunits/includes/DM5/directory_page_number.inc +++ b/baseunits/includes/DM5/directory_page_number.inc @@ -11,8 +11,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/EGScans/chapter_page_number.inc b/baseunits/includes/EGScans/chapter_page_number.inc index 230f60225..1bb4d924f 100644 --- a/baseunits/includes/EGScans/chapter_page_number.inc +++ b/baseunits/includes/EGScans/chapter_page_number.inc @@ -11,8 +11,8 @@ s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/EGScans/image_url.inc b/baseunits/includes/EGScans/image_url.inc index 4c498cff8..4fd7e57f2 100644 --- a/baseunits/includes/EGScans/image_url.inc +++ b/baseunits/includes/EGScans/image_url.inc @@ -11,8 +11,8 @@ Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/EGScans/manga_information.inc b/baseunits/includes/EGScans/manga_information.inc index 6fd781efc..4df5c0812 100644 --- a/baseunits/includes/EGScans/manga_information.inc +++ b/baseunits/includes/EGScans/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/EGScans/names_and_links.inc b/baseunits/includes/EGScans/names_and_links.inc index d192b7201..5d64bc4b1 100644 --- a/baseunits/includes/EGScans/names_and_links.inc +++ b/baseunits/includes/EGScans/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/EsMangaHere/chapter_page_number.inc b/baseunits/includes/EsMangaHere/chapter_page_number.inc index 96ad34a75..ce5f886f7 100644 --- a/baseunits/includes/EsMangaHere/chapter_page_number.inc +++ b/baseunits/includes/EsMangaHere/chapter_page_number.inc @@ -9,8 +9,8 @@ FillMangaSiteHost(ESMANGAHERE_ID, URL), Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/EsMangaHere/image_url.inc b/baseunits/includes/EsMangaHere/image_url.inc index 30866d459..fcf9796a9 100644 --- a/baseunits/includes/EsMangaHere/image_url.inc +++ b/baseunits/includes/EsMangaHere/image_url.inc @@ -16,8 +16,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/EsMangaHere/manga_information.inc b/baseunits/includes/EsMangaHere/manga_information.inc index edeb728a8..220021eaa 100644 --- a/baseunits/includes/EsMangaHere/manga_information.inc +++ b/baseunits/includes/EsMangaHere/manga_information.inc @@ -14,8 +14,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/EsMangaHere/names_and_links.inc b/baseunits/includes/EsMangaHere/names_and_links.inc index 162d68096..62c83a6d4 100644 --- a/baseunits/includes/EsMangaHere/names_and_links.inc +++ b/baseunits/includes/EsMangaHere/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/ExtremeMangas/chapter_page_number.inc b/baseunits/includes/ExtremeMangas/chapter_page_number.inc index 09d61c74b..e1918ed1c 100644 --- a/baseunits/includes/ExtremeMangas/chapter_page_number.inc +++ b/baseunits/includes/ExtremeMangas/chapter_page_number.inc @@ -13,8 +13,8 @@ l.Text := FixHTMLTagQuote(l.Text); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/ExtremeMangas/manga_information.inc b/baseunits/includes/ExtremeMangas/manga_information.inc index 5de28eb36..a39a2c8c9 100644 --- a/baseunits/includes/ExtremeMangas/manga_information.inc +++ b/baseunits/includes/ExtremeMangas/manga_information.inc @@ -19,8 +19,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/ExtremeMangas/names_and_links.inc b/baseunits/includes/ExtremeMangas/names_and_links.inc index 1fb089359..d45e714df 100644 --- a/baseunits/includes/ExtremeMangas/names_and_links.inc +++ b/baseunits/includes/ExtremeMangas/names_and_links.inc @@ -17,8 +17,8 @@ Source.Text := FixHTMLTagQuote(Source.Text); parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/IKomik/chapter_page_number.inc b/baseunits/includes/IKomik/chapter_page_number.inc index 14dedb111..33b3bf20f 100644 --- a/baseunits/includes/IKomik/chapter_page_number.inc +++ b/baseunits/includes/IKomik/chapter_page_number.inc @@ -12,8 +12,8 @@ Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/IKomik/directory_page_number.inc b/baseunits/includes/IKomik/directory_page_number.inc index 35f0197f6..803bcc794 100644 --- a/baseunits/includes/IKomik/directory_page_number.inc +++ b/baseunits/includes/IKomik/directory_page_number.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/IKomik/image_url.inc b/baseunits/includes/IKomik/image_url.inc index 2e4a5f6e2..1192ef5b5 100644 --- a/baseunits/includes/IKomik/image_url.inc +++ b/baseunits/includes/IKomik/image_url.inc @@ -21,8 +21,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/IKomik/manga_information.inc b/baseunits/includes/IKomik/manga_information.inc index 2b3677760..b1a0fe870 100644 --- a/baseunits/includes/IKomik/manga_information.inc +++ b/baseunits/includes/IKomik/manga_information.inc @@ -15,8 +15,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/IKomik/names_and_links.inc b/baseunits/includes/IKomik/names_and_links.inc index 4d57b2b69..b2ce7d193 100644 --- a/baseunits/includes/IKomik/names_and_links.inc +++ b/baseunits/includes/IKomik/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/Imanhua/names_and_links.inc b/baseunits/includes/Imanhua/names_and_links.inc index ad2ba6c6a..b371af83c 100644 --- a/baseunits/includes/Imanhua/names_and_links.inc +++ b/baseunits/includes/Imanhua/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/JapanShin/chapter_page_number.inc b/baseunits/includes/JapanShin/chapter_page_number.inc index 4fe9f0d09..37da789c1 100644 --- a/baseunits/includes/JapanShin/chapter_page_number.inc +++ b/baseunits/includes/JapanShin/chapter_page_number.inc @@ -9,8 +9,8 @@ FillMangaSiteHost(JAPANSHIN_ID, URL), Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/JapanShin/directory_page_number.inc b/baseunits/includes/JapanShin/directory_page_number.inc index 7a5574d12..af4644cf8 100644 --- a/baseunits/includes/JapanShin/directory_page_number.inc +++ b/baseunits/includes/JapanShin/directory_page_number.inc @@ -14,8 +14,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/JapanShin/image_url.inc b/baseunits/includes/JapanShin/image_url.inc index 8809fe75f..323927b74 100644 --- a/baseunits/includes/JapanShin/image_url.inc +++ b/baseunits/includes/JapanShin/image_url.inc @@ -16,8 +16,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/JapanShin/manga_information.inc b/baseunits/includes/JapanShin/manga_information.inc index 8fd573350..a61208c4f 100644 --- a/baseunits/includes/JapanShin/manga_information.inc +++ b/baseunits/includes/JapanShin/manga_information.inc @@ -14,8 +14,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/JapanShin/names_and_links.inc b/baseunits/includes/JapanShin/names_and_links.inc index b7a17c870..994880ee5 100644 --- a/baseunits/includes/JapanShin/names_and_links.inc +++ b/baseunits/includes/JapanShin/names_and_links.inc @@ -15,8 +15,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/Kivmanga/chapter_page_number.inc b/baseunits/includes/Kivmanga/chapter_page_number.inc index 17a86cfa4..67f6fd11d 100644 --- a/baseunits/includes/Kivmanga/chapter_page_number.inc +++ b/baseunits/includes/Kivmanga/chapter_page_number.inc @@ -11,8 +11,8 @@ s, Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/Kivmanga/image_url.inc b/baseunits/includes/Kivmanga/image_url.inc index 58e69968f..eef9068be 100644 --- a/baseunits/includes/Kivmanga/image_url.inc +++ b/baseunits/includes/Kivmanga/image_url.inc @@ -11,8 +11,8 @@ Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/Kivmanga/manga_information.inc b/baseunits/includes/Kivmanga/manga_information.inc index 67585832e..6f43af877 100644 --- a/baseunits/includes/Kivmanga/manga_information.inc +++ b/baseunits/includes/Kivmanga/manga_information.inc @@ -15,8 +15,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/Kivmanga/names_and_links.inc b/baseunits/includes/Kivmanga/names_and_links.inc index 5e9b425af..48a6655db 100644 --- a/baseunits/includes/Kivmanga/names_and_links.inc +++ b/baseunits/includes/Kivmanga/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/LectureEnLigne/chapter_page_number.inc b/baseunits/includes/LectureEnLigne/chapter_page_number.inc index 650161365..9b35ab332 100644 --- a/baseunits/includes/LectureEnLigne/chapter_page_number.inc +++ b/baseunits/includes/LectureEnLigne/chapter_page_number.inc @@ -16,8 +16,8 @@ Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/LectureEnLigne/directory_page_number.inc b/baseunits/includes/LectureEnLigne/directory_page_number.inc index ef7233f21..8f79eea7d 100644 --- a/baseunits/includes/LectureEnLigne/directory_page_number.inc +++ b/baseunits/includes/LectureEnLigne/directory_page_number.inc @@ -14,8 +14,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/LectureEnLigne/image_url.inc b/baseunits/includes/LectureEnLigne/image_url.inc index dc4792b24..3628e31e0 100644 --- a/baseunits/includes/LectureEnLigne/image_url.inc +++ b/baseunits/includes/LectureEnLigne/image_url.inc @@ -14,8 +14,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/LectureEnLigne/manga_information.inc b/baseunits/includes/LectureEnLigne/manga_information.inc index 32918aef6..d0352ac18 100644 --- a/baseunits/includes/LectureEnLigne/manga_information.inc +++ b/baseunits/includes/LectureEnLigne/manga_information.inc @@ -14,8 +14,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/LectureEnLigne/names_and_links.inc b/baseunits/includes/LectureEnLigne/names_and_links.inc index a9ba9deb4..f49147983 100644 --- a/baseunits/includes/LectureEnLigne/names_and_links.inc +++ b/baseunits/includes/LectureEnLigne/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/MangaAr/image_url.inc b/baseunits/includes/MangaAr/image_url.inc index 0984bee47..e1c29e1b0 100644 --- a/baseunits/includes/MangaAr/image_url.inc +++ b/baseunits/includes/MangaAr/image_url.inc @@ -12,8 +12,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MangaAr/manga_information.inc b/baseunits/includes/MangaAr/manga_information.inc index 475aeeb34..3ba8396d9 100644 --- a/baseunits/includes/MangaAr/manga_information.inc +++ b/baseunits/includes/MangaAr/manga_information.inc @@ -14,8 +14,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MangaAr/names_and_links.inc b/baseunits/includes/MangaAr/names_and_links.inc index 7c7e75814..56d762db2 100644 --- a/baseunits/includes/MangaAr/names_and_links.inc +++ b/baseunits/includes/MangaAr/names_and_links.inc @@ -14,8 +14,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/MangaAt/chapter_page_number.inc b/baseunits/includes/MangaAt/chapter_page_number.inc index 68de629f3..a983de6bc 100644 --- a/baseunits/includes/MangaAt/chapter_page_number.inc +++ b/baseunits/includes/MangaAt/chapter_page_number.inc @@ -14,8 +14,8 @@ Parser := THTMLParser.Create(l.Text); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MangaAt/directory_page_number.inc b/baseunits/includes/MangaAt/directory_page_number.inc index a51086249..4444cf63a 100644 --- a/baseunits/includes/MangaAt/directory_page_number.inc +++ b/baseunits/includes/MangaAt/directory_page_number.inc @@ -16,8 +16,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MangaAt/image_url.inc b/baseunits/includes/MangaAt/image_url.inc index 4c6b58c26..99969dfa0 100644 --- a/baseunits/includes/MangaAt/image_url.inc +++ b/baseunits/includes/MangaAt/image_url.inc @@ -14,8 +14,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MangaAt/manga_information.inc b/baseunits/includes/MangaAt/manga_information.inc index b1935a676..e23eece09 100644 --- a/baseunits/includes/MangaAt/manga_information.inc +++ b/baseunits/includes/MangaAt/manga_information.inc @@ -16,8 +16,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MangaAt/names_and_links.inc b/baseunits/includes/MangaAt/names_and_links.inc index cba90e1d2..5daccdbed 100644 --- a/baseunits/includes/MangaAt/names_and_links.inc +++ b/baseunits/includes/MangaAt/names_and_links.inc @@ -14,8 +14,8 @@ parse.Clear; Parser := THTMLParser.Create(FixHTMLTagQuote(Source.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; finally Parser.Exec; end; diff --git a/baseunits/includes/MangaHost/chapter_page_number.inc b/baseunits/includes/MangaHost/chapter_page_number.inc index e1f534e2c..4f5721188 100644 --- a/baseunits/includes/MangaHost/chapter_page_number.inc +++ b/baseunits/includes/MangaHost/chapter_page_number.inc @@ -10,8 +10,8 @@ DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL)), Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/MangaHost/directory_page_number.inc b/baseunits/includes/MangaHost/directory_page_number.inc index 259a977fc..96547ef97 100644 --- a/baseunits/includes/MangaHost/directory_page_number.inc +++ b/baseunits/includes/MangaHost/directory_page_number.inc @@ -13,8 +13,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/MangaHost/image_url.inc b/baseunits/includes/MangaHost/image_url.inc index c7991d2b6..77f26a5e4 100644 --- a/baseunits/includes/MangaHost/image_url.inc +++ b/baseunits/includes/MangaHost/image_url.inc @@ -9,8 +9,8 @@ Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MangaHost/manga_information.inc b/baseunits/includes/MangaHost/manga_information.inc index e27df622d..f96daa526 100644 --- a/baseunits/includes/MangaHost/manga_information.inc +++ b/baseunits/includes/MangaHost/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/MangaHost/names_and_links.inc b/baseunits/includes/MangaHost/names_and_links.inc index fcf6ac062..41f996584 100644 --- a/baseunits/includes/MangaHost/names_and_links.inc +++ b/baseunits/includes/MangaHost/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/MangaKu/chapter_page_number.inc b/baseunits/includes/MangaKu/chapter_page_number.inc index e85f55850..0ab37f7f1 100644 --- a/baseunits/includes/MangaKu/chapter_page_number.inc +++ b/baseunits/includes/MangaKu/chapter_page_number.inc @@ -13,8 +13,8 @@ Parser := THTMLParser.Create(l.Text); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MangaKu/manga_information.inc b/baseunits/includes/MangaKu/manga_information.inc index 2a9e722c0..58ecc6339 100644 --- a/baseunits/includes/MangaKu/manga_information.inc +++ b/baseunits/includes/MangaKu/manga_information.inc @@ -23,8 +23,8 @@ parse.Clear; Parser := THTMLParser.Create(s); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MangaKu/names_and_links.inc b/baseunits/includes/MangaKu/names_and_links.inc index cc4376c2b..8a1069402 100644 --- a/baseunits/includes/MangaKu/names_and_links.inc +++ b/baseunits/includes/MangaKu/names_and_links.inc @@ -18,8 +18,8 @@ parse.Clear; Parser := THTMLParser.Create(s); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; finally Parser.Exec; end; diff --git a/baseunits/includes/MangaLib_PL/chapter_page_number.inc b/baseunits/includes/MangaLib_PL/chapter_page_number.inc index 6dbfb70fe..5728b425f 100644 --- a/baseunits/includes/MangaLib_PL/chapter_page_number.inc +++ b/baseunits/includes/MangaLib_PL/chapter_page_number.inc @@ -43,8 +43,8 @@ end; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Task.Container.PageNumber := 0; diff --git a/baseunits/includes/MangaLib_PL/image_url.inc b/baseunits/includes/MangaLib_PL/image_url.inc index 7d444fb24..684cbde99 100644 --- a/baseunits/includes/MangaLib_PL/image_url.inc +++ b/baseunits/includes/MangaLib_PL/image_url.inc @@ -43,8 +43,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/MangaLib_PL/manga_information.inc b/baseunits/includes/MangaLib_PL/manga_information.inc index f46a36c7b..6a686adfb 100644 --- a/baseunits/includes/MangaLib_PL/manga_information.inc +++ b/baseunits/includes/MangaLib_PL/manga_information.inc @@ -52,8 +52,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MangaLib_PL/names_and_links.inc b/baseunits/includes/MangaLib_PL/names_and_links.inc index 8ac8d572d..ee71c4dad 100644 --- a/baseunits/includes/MangaLib_PL/names_and_links.inc +++ b/baseunits/includes/MangaLib_PL/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/MangaOku/chapter_page_number.inc b/baseunits/includes/MangaOku/chapter_page_number.inc index c037ef663..83fe65492 100644 --- a/baseunits/includes/MangaOku/chapter_page_number.inc +++ b/baseunits/includes/MangaOku/chapter_page_number.inc @@ -12,8 +12,8 @@ Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/MangaOku/image_url.inc b/baseunits/includes/MangaOku/image_url.inc index cf91dc0a8..9147dfc26 100644 --- a/baseunits/includes/MangaOku/image_url.inc +++ b/baseunits/includes/MangaOku/image_url.inc @@ -21,8 +21,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/MangaOku/manga_information.inc b/baseunits/includes/MangaOku/manga_information.inc index 8ecbb0843..453ee4411 100644 --- a/baseunits/includes/MangaOku/manga_information.inc +++ b/baseunits/includes/MangaOku/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/MangaOku/names_and_links.inc b/baseunits/includes/MangaOku/names_and_links.inc index 033486caa..92f7e4c16 100644 --- a/baseunits/includes/MangaOku/names_and_links.inc +++ b/baseunits/includes/MangaOku/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/MangaREADER_POR/image_url.inc b/baseunits/includes/MangaREADER_POR/image_url.inc index 9ea605f2c..cb8ed0ed1 100644 --- a/baseunits/includes/MangaREADER_POR/image_url.inc +++ b/baseunits/includes/MangaREADER_POR/image_url.inc @@ -11,8 +11,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MangaREADER_POR/manga_information.inc b/baseunits/includes/MangaREADER_POR/manga_information.inc index b6216cdb8..37c00716a 100644 --- a/baseunits/includes/MangaREADER_POR/manga_information.inc +++ b/baseunits/includes/MangaREADER_POR/manga_information.inc @@ -46,8 +46,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; @@ -161,8 +161,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; isExtractChapter := False; diff --git a/baseunits/includes/MangaTown/chapter_page_number.inc b/baseunits/includes/MangaTown/chapter_page_number.inc index c583f1ca3..80776d70d 100644 --- a/baseunits/includes/MangaTown/chapter_page_number.inc +++ b/baseunits/includes/MangaTown/chapter_page_number.inc @@ -11,8 +11,8 @@ s := FillMangaSiteHost(MANGATOWN_ID, URL); Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/MangaTown/directory_page_number.inc b/baseunits/includes/MangaTown/directory_page_number.inc index 4fc852e92..9d711acf2 100644 --- a/baseunits/includes/MangaTown/directory_page_number.inc +++ b/baseunits/includes/MangaTown/directory_page_number.inc @@ -14,8 +14,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index c2451f013..f6f2d979d 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -19,8 +19,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/MangaTown/manga_information.inc b/baseunits/includes/MangaTown/manga_information.inc index 8bef7e3ec..fc23f972c 100644 --- a/baseunits/includes/MangaTown/manga_information.inc +++ b/baseunits/includes/MangaTown/manga_information.inc @@ -17,8 +17,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/MangaTown/names_and_links.inc b/baseunits/includes/MangaTown/names_and_links.inc index 51ad361d7..625d04846 100644 --- a/baseunits/includes/MangaTown/names_and_links.inc +++ b/baseunits/includes/MangaTown/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/MangasPROJECT/image_url.inc b/baseunits/includes/MangasPROJECT/image_url.inc index 9f6b65b13..94f75aaff 100644 --- a/baseunits/includes/MangasPROJECT/image_url.inc +++ b/baseunits/includes/MangasPROJECT/image_url.inc @@ -11,8 +11,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MangasPROJECT/manga_information.inc b/baseunits/includes/MangasPROJECT/manga_information.inc index c058f461e..059e01695 100644 --- a/baseunits/includes/MangasPROJECT/manga_information.inc +++ b/baseunits/includes/MangasPROJECT/manga_information.inc @@ -45,8 +45,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; @@ -148,8 +148,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; isExtractChapter := False; diff --git a/baseunits/includes/MeinManga/chapter_page_number.inc b/baseunits/includes/MeinManga/chapter_page_number.inc index 3941df5f1..de0ee9c06 100644 --- a/baseunits/includes/MeinManga/chapter_page_number.inc +++ b/baseunits/includes/MeinManga/chapter_page_number.inc @@ -11,8 +11,8 @@ s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc index 8ef95e219..fecf331cc 100644 --- a/baseunits/includes/MeinManga/image_url.inc +++ b/baseunits/includes/MeinManga/image_url.inc @@ -40,8 +40,8 @@ parse := TStringList.Create; try Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; finally Parser.Free; diff --git a/baseunits/includes/MeinManga/manga_information.inc b/baseunits/includes/MeinManga/manga_information.inc index 969e76f07..b536323b0 100644 --- a/baseunits/includes/MeinManga/manga_information.inc +++ b/baseunits/includes/MeinManga/manga_information.inc @@ -30,8 +30,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; @@ -138,8 +138,8 @@ parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/MeinManga/names_and_links.inc b/baseunits/includes/MeinManga/names_and_links.inc index 80c318543..22d309c39 100644 --- a/baseunits/includes/MeinManga/names_and_links.inc +++ b/baseunits/includes/MeinManga/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/NHentai/chapter_page_number.inc b/baseunits/includes/NHentai/chapter_page_number.inc index 1999aa2c6..b939426e5 100644 --- a/baseunits/includes/NHentai/chapter_page_number.inc +++ b/baseunits/includes/NHentai/chapter_page_number.inc @@ -14,8 +14,8 @@ Result := GetPage(TObject(l), s + '1/', Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/NHentai/directory_page_number.inc b/baseunits/includes/NHentai/directory_page_number.inc index 18a884353..0429fe96a 100644 --- a/baseunits/includes/NHentai/directory_page_number.inc +++ b/baseunits/includes/NHentai/directory_page_number.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/NHentai/image_url.inc b/baseunits/includes/NHentai/image_url.inc index ed1773217..6b88a9f06 100644 --- a/baseunits/includes/NHentai/image_url.inc +++ b/baseunits/includes/NHentai/image_url.inc @@ -21,8 +21,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/NHentai/manga_information.inc b/baseunits/includes/NHentai/manga_information.inc index f0ade6e0e..d0051cf2c 100644 --- a/baseunits/includes/NHentai/manga_information.inc +++ b/baseunits/includes/NHentai/manga_information.inc @@ -14,8 +14,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/NHentai/names_and_links.inc b/baseunits/includes/NHentai/names_and_links.inc index 0813d27fd..3f552da28 100644 --- a/baseunits/includes/NHentai/names_and_links.inc +++ b/baseunits/includes/NHentai/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/OneManga/chapter_page_number.inc b/baseunits/includes/OneManga/chapter_page_number.inc index 91a663ef1..e4a5c60b8 100644 --- a/baseunits/includes/OneManga/chapter_page_number.inc +++ b/baseunits/includes/OneManga/chapter_page_number.inc @@ -12,8 +12,8 @@ s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Task.Container.PageNumber := 0; diff --git a/baseunits/includes/OneManga/directory_page_number.inc b/baseunits/includes/OneManga/directory_page_number.inc index a8e5ef780..798b8c6f6 100644 --- a/baseunits/includes/OneManga/directory_page_number.inc +++ b/baseunits/includes/OneManga/directory_page_number.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/OneManga/image_url.inc b/baseunits/includes/OneManga/image_url.inc index fa4dcfc4e..76eec9de2 100644 --- a/baseunits/includes/OneManga/image_url.inc +++ b/baseunits/includes/OneManga/image_url.inc @@ -12,8 +12,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/OneManga/manga_information.inc b/baseunits/includes/OneManga/manga_information.inc index bdcc3111e..391928808 100644 --- a/baseunits/includes/OneManga/manga_information.inc +++ b/baseunits/includes/OneManga/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/OneManga/names_and_links.inc b/baseunits/includes/OneManga/names_and_links.inc index 80880006f..a2c8b45c6 100644 --- a/baseunits/includes/OneManga/names_and_links.inc +++ b/baseunits/includes/OneManga/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/S2Scans/directory_page_number.inc b/baseunits/includes/S2Scans/directory_page_number.inc index c13a8096d..58e7a012d 100644 --- a/baseunits/includes/S2Scans/directory_page_number.inc +++ b/baseunits/includes/S2Scans/directory_page_number.inc @@ -12,8 +12,8 @@ Parser := THTMLParser.Create(PChar(Source.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; parse.Clear; Parser.Exec; finally diff --git a/baseunits/includes/S2Scans/manga_information.inc b/baseunits/includes/S2Scans/manga_information.inc index 28776041e..4e4a24670 100644 --- a/baseunits/includes/S2Scans/manga_information.inc +++ b/baseunits/includes/S2Scans/manga_information.inc @@ -15,8 +15,8 @@ // parsing the HTML source Parser := THTMLParser.Create(PChar(Source.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; parse.Clear; Parser.Exec; finally diff --git a/baseunits/includes/S2Scans/names_and_links.inc b/baseunits/includes/S2Scans/names_and_links.inc index 6c5143afb..0fd6e0270 100644 --- a/baseunits/includes/S2Scans/names_and_links.inc +++ b/baseunits/includes/S2Scans/names_and_links.inc @@ -13,8 +13,8 @@ Parser := THTMLParser.Create(PChar(Source.Text)); try - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; parse.Clear; Parser.Exec; finally diff --git a/baseunits/includes/ScanManga/manga_information.inc b/baseunits/includes/ScanManga/manga_information.inc index a958cae80..031e29163 100644 --- a/baseunits/includes/ScanManga/manga_information.inc +++ b/baseunits/includes/ScanManga/manga_information.inc @@ -14,8 +14,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/ScanManga/names_and_links.inc b/baseunits/includes/ScanManga/names_and_links.inc index 8f776a6bb..a9a9b45b8 100644 --- a/baseunits/includes/ScanManga/names_and_links.inc +++ b/baseunits/includes/ScanManga/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/Starkana/chapter_page_number.inc b/baseunits/includes/Starkana/chapter_page_number.inc index d28fa0b10..d8be79919 100644 --- a/baseunits/includes/Starkana/chapter_page_number.inc +++ b/baseunits/includes/Starkana/chapter_page_number.inc @@ -10,8 +10,8 @@ DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL)), Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/Starkana/image_url.inc b/baseunits/includes/Starkana/image_url.inc index c2abe9f53..18bf6e1c2 100644 --- a/baseunits/includes/Starkana/image_url.inc +++ b/baseunits/includes/Starkana/image_url.inc @@ -9,8 +9,8 @@ Task.Container.manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/Starkana/manga_information.inc b/baseunits/includes/Starkana/manga_information.inc index 59894ec08..feecb9061 100644 --- a/baseunits/includes/Starkana/manga_information.inc +++ b/baseunits/includes/Starkana/manga_information.inc @@ -15,8 +15,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/Starkana/names_and_links.inc b/baseunits/includes/Starkana/names_and_links.inc index d891d14ea..2f50e32e2 100644 --- a/baseunits/includes/Starkana/names_and_links.inc +++ b/baseunits/includes/Starkana/names_and_links.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/Turkcraft/chapter_page_number.inc b/baseunits/includes/Turkcraft/chapter_page_number.inc index 60864e8ac..de9341377 100644 --- a/baseunits/includes/Turkcraft/chapter_page_number.inc +++ b/baseunits/includes/Turkcraft/chapter_page_number.inc @@ -11,8 +11,8 @@ s, Task.Container.manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/Turkcraft/image_url.inc b/baseunits/includes/Turkcraft/image_url.inc index c1e95913f..a9d9c68f4 100644 --- a/baseunits/includes/Turkcraft/image_url.inc +++ b/baseunits/includes/Turkcraft/image_url.inc @@ -11,8 +11,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/Turkcraft/manga_information.inc b/baseunits/includes/Turkcraft/manga_information.inc index b37e80665..64b6faafc 100644 --- a/baseunits/includes/Turkcraft/manga_information.inc +++ b/baseunits/includes/Turkcraft/manga_information.inc @@ -15,8 +15,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/Turkcraft/names_and_links.inc b/baseunits/includes/Turkcraft/names_and_links.inc index 84b1f7b22..94e48aada 100644 --- a/baseunits/includes/Turkcraft/names_and_links.inc +++ b/baseunits/includes/Turkcraft/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/UnixManga/chapter_page_number.inc b/baseunits/includes/UnixManga/chapter_page_number.inc index 1241d57f0..bc63ba9ff 100644 --- a/baseunits/includes/UnixManga/chapter_page_number.inc +++ b/baseunits/includes/UnixManga/chapter_page_number.inc @@ -11,8 +11,8 @@ Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/UnixManga/image_url.inc b/baseunits/includes/UnixManga/image_url.inc index f6c942aac..7d515809c 100644 --- a/baseunits/includes/UnixManga/image_url.inc +++ b/baseunits/includes/UnixManga/image_url.inc @@ -17,8 +17,8 @@ parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; l.Free; diff --git a/baseunits/includes/UnixManga/manga_information.inc b/baseunits/includes/UnixManga/manga_information.inc index 8e027f1b4..b09834b8e 100644 --- a/baseunits/includes/UnixManga/manga_information.inc +++ b/baseunits/includes/UnixManga/manga_information.inc @@ -15,8 +15,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/UnixManga/names_and_links.inc b/baseunits/includes/UnixManga/names_and_links.inc index 6ab1e652f..46d944a6d 100644 --- a/baseunits/includes/UnixManga/names_and_links.inc +++ b/baseunits/includes/UnixManga/names_and_links.inc @@ -13,8 +13,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; Source.Free; diff --git a/baseunits/includes/VnSharing/directory_page_number.inc b/baseunits/includes/VnSharing/directory_page_number.inc index 41ebe10fb..ff0330f20 100644 --- a/baseunits/includes/VnSharing/directory_page_number.inc +++ b/baseunits/includes/VnSharing/directory_page_number.inc @@ -12,8 +12,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/includes/VnSharing/image_url.inc b/baseunits/includes/VnSharing/image_url.inc index 3ebecbbd4..29e550d29 100644 --- a/baseunits/includes/VnSharing/image_url.inc +++ b/baseunits/includes/VnSharing/image_url.inc @@ -10,8 +10,8 @@ Task.Container.Manager.retryConnect); parse := TStringList.Create; Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count > 0 then diff --git a/baseunits/includes/VnSharing/manga_information.inc b/baseunits/includes/VnSharing/manga_information.inc index dc0af4fe4..cb66b8ebf 100644 --- a/baseunits/includes/VnSharing/manga_information.inc +++ b/baseunits/includes/VnSharing/manga_information.inc @@ -16,8 +16,8 @@ // parsing the HTML source parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; diff --git a/baseunits/includes/VnSharing/names_and_links.inc b/baseunits/includes/VnSharing/names_and_links.inc index fe4f469bb..dd611a68c 100644 --- a/baseunits/includes/VnSharing/names_and_links.inc +++ b/baseunits/includes/VnSharing/names_and_links.inc @@ -15,8 +15,8 @@ end; parse.Clear; Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := OnTag; - Parser.OnFoundText := OnText; + Parser.OnFoundTag := @OnTag; + Parser.OnFoundText := @OnText; Parser.Exec; Parser.Free; if parse.Count = 0 then diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f0db3eca7..b0ac33ee3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -6,7 +6,7 @@ unit uBaseUnit; -{$mode delphi} +{$mode objfpc}{$H+} {$MACRO ON} {$DEFINE DOWNLOADER} @@ -476,19 +476,15 @@ TMangaInfo = class { TDownloadInfo } TDownloadInfo = record - private - FSaveTo: String; - procedure SetSaveTo(AValue: String); - public Website, Link, Title, + SaveTo, Status, Progress, TransferRate: String; DateTime: TDateTime; iProgress: Integer; - property SaveTo: String read FSaveTo write SetSaveTo; end; PFavoriteInfo = ^TFavoriteInfo; @@ -496,21 +492,17 @@ TDownloadInfo = record { TFavoriteInfo } TFavoriteInfo = record - private - FSaveTo: String; - procedure SetSaveTo(AValue: String); - public Website, Title, Link, + SaveTo, Numbering, DownloadedChapterList, CurrentChapter: String; - property SaveTo: String read FSaveTo write SetSaveTo; end; - TCardinalList = TFPGList<Cardinal>; - TByteList = TFPGList<Byte>; + TCardinalList = specialize TFPGList<Cardinal>; + TByteList = specialize TFPGList<Byte>; TDownloadPageThread = class(TThread) protected @@ -4058,22 +4050,6 @@ function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String; Result := MangaInfo_StatusCompleted; end; -{ TFavoriteInfo } - -procedure TFavoriteInfo.SetSaveTo(AValue: String); -begin - if FSaveTo = AValue then Exit; - FSaveTo := AValue; -end; - -{ TDownloadInfo } - -procedure TDownloadInfo.SetSaveTo(AValue: String); -begin - if FSaveTo = AValue then Exit; - FSaveTo := AValue; -end; - { THTMLForm } constructor THTMLForm.Create; @@ -4150,8 +4126,8 @@ function TParseHTML.Exec(const Raw: String): String; Output.BeginUpdate; parser := THTMLParser.Create(PChar(FRaw)); try - parser.OnFoundTag := FoundTag; - parser.OnFoundText := FoundText; + parser.OnFoundTag := @FoundTag; + parser.OnFoundText := @FoundText; parser.Exec; finally parser.Free; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c8ced1c7b..9356d72ac 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -6,7 +6,7 @@ unit uData; -{$mode delphi} +{$mode objfpc}{$H+} {$DEFINE DOWNLOADER} // This unit contains all necessary functions for data processing @@ -48,9 +48,9 @@ TDataProcess = class(TObject) // it's for faster filter procedure BreakDataToParts(const i: Cardinal); - function LoadFromFile(const website: String): Boolean; + function LoadFromFile(const awebsite: String): Boolean; function LoadFromAllFiles(const websiteList: TStringList): Boolean; - procedure SaveToFile(const website: String); overload; + procedure SaveToFile(const awebsite: String); overload; procedure SaveToFile; overload; function CanFilter(const checkedGenres, uncheckedGenres: TStringList; @@ -243,13 +243,13 @@ procedure TDataProcess.BreakDataToParts(const i: Cardinal); end; end; -function TDataProcess.LoadFromFile(const website: String): Boolean; +function TDataProcess.LoadFromFile(const awebsite: String): Boolean; var id, i: Cardinal; l: TStringList; - Filename: String; + afilename: String; begin - Filename := DATA_FOLDER + website; + afilename := DATA_FOLDER + awebsite; Data.Clear; searchPos.Clear; @@ -265,14 +265,14 @@ function TDataProcess.LoadFromFile(const website: String): Boolean; summary.Clear; jdn.Clear; - if not FileExistsUTF8(Filename + DATA_EXT) then + if not FileExistsUTF8(afilename + DATA_EXT) then Exit(False); l := TStringList.Create; try - Self.Filename := Filename; + Self.Filename := afilename; - Data.LoadFromFile(Filename + DATA_EXT); - id := GetMangaSiteID(website); + Data.LoadFromFile(afilename + DATA_EXT); + id := GetMangaSiteID(awebsite); if Data.Count > 0 then begin @@ -311,7 +311,7 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; var id, j, i: Cardinal; l: TStringList; - Filename: String; + afilename: String; begin if websiteList.Count = 0 then Exit(False); @@ -333,12 +333,12 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; try for i := 0 to websiteList.Count - 1 do begin - Filename := DATA_FOLDER + websiteList.Strings[i]; + afilename := DATA_FOLDER + websiteList.Strings[i]; id := GetMangaSiteID(websiteList.Strings[i]); - if not FileExistsUTF8(Filename + DATA_EXT) then + if not FileExistsUTF8(afilename + DATA_EXT) then continue; l.Clear; - l.LoadFromFile(Filename + DATA_EXT); + l.LoadFromFile(afilename + DATA_EXT); if l.Count <> 0 then begin @@ -379,13 +379,13 @@ function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; Result := True; end; -procedure TDataProcess.SaveToFile(const website: String); +procedure TDataProcess.SaveToFile(const awebsite: String); begin if Data.Count = 0 then Exit; //QuickSortData(Data); ForceDirectoriesUTF8(DATA_FOLDER); - Data.SaveToFile(DATA_FOLDER + website + DATA_EXT); + Data.SaveToFile(DATA_FOLDER + awebsite + DATA_EXT); end; procedure TDataProcess.SaveToFile; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index f7a749c65..be43e83a6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -6,7 +6,7 @@ unit uDownloadsManager; -{$mode delphi} +{$mode objfpc}{$H+} {$IF FPC_FULLVERSION >= 20701} {$DEFINE FPC271} @@ -71,7 +71,7 @@ TDownloadThread = class(TBaseThread) destructor Destroy; override; end; - TDownloadThreads = TFPGList<TDownloadThread>; + TDownloadThreads = specialize TFPGList<TDownloadThread>; { TTaskThread } @@ -169,7 +169,7 @@ TTaskContainer = class property Enabled: Boolean read FEnabled write SetEnabled; end; - TTaskContainers = TFPGList<TTaskContainer>; + TTaskContainers = specialize TFPGList<TTaskContainer>; { TDownloadManager } @@ -307,7 +307,7 @@ constructor TDownloadThread.Create; inherited Create(True); FHTTP := THTTPSendThread.Create(Self); FHTTP.Headers.NameValueSeparator := ':'; - FHTTP.Sock.OnStatus := SockOnStatus; + FHTTP.Sock.OnStatus := @SockOnStatus; end; destructor TDownloadThread.Destroy; @@ -738,7 +738,7 @@ destructor TTaskThread.Destroy; FCheckAndActiveTaskFlag := False; end; if not isExiting then - Synchronize(SyncStop); + Synchronize(@SyncStop); end; end; end; @@ -845,7 +845,7 @@ function TTaskThread.FailedChaptersExist: Boolean; procedure TTaskThread.ShowBalloonHint; begin if OptionShowBalloonHint then - Synchronize(SyncShowBallonHint); + Synchronize(@SyncShowBallonHint); end; function TTaskThread.GetExceptionInfo: String; @@ -1573,7 +1573,7 @@ constructor TDownloadManager.Create; ForceDirectoriesUTF8(WORK_FOLDER); DownloadedChapters := TDownloadedChaptersDB.Create; DownloadedChapters.Filename := DOWNLOADEDCHAPTERSDB_FILE; - DownloadedChapters.OnError := MainForm.ExceptionHandler; + DownloadedChapters.OnError := @MainForm.ExceptionHandler; DownloadedChapters.Open; if FileExistsUTF8(DOWNLOADEDCHAPTERS_FILE) then if DownloadedChapters.ImportFromIni(DOWNLOADEDCHAPTERS_FILE) then @@ -2066,7 +2066,7 @@ procedure TDownloadManager.Sort(const AColumn: Integer); EnterCriticalSection(CS_Task); try SortColumn := AColumn; - Items.Sort(CompareTaskContainer); + Items.Sort(@CompareTaskContainer); finally LeaveCriticalSection(CS_Task); end; From db7e45d932be8cf656a29df1f5bf79f746e0d0d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 19 Nov 2017 02:54:59 +0800 Subject: [PATCH 1914/2794] Bump version 0.9.127.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 470033cd6..e6c14200f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.127.0 (19-11-2017) +[*] MangaFox, MangaHere: exclude ads page +Full changes: https://github.com/riderkick/FMD/compare/0.9.126.0...0.9.127.0 + 0.9.126.0 (29-08-2017) [*] Madokami: fixed update list [*] Fixed download issue with some website diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index fb7b36e55..d02956cf9 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="126"/> + <RevisionNr Value="127"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index d0cc291d9..e6ccc0340 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.126.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.126.0/fmd_0.9.126.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.126.0/fmd_0.9.126.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.126.0/fmd_0.9.126.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.126.0/fmd_0.9.126.0_Win64.7z +VERSION=0.9.127.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.127.0/fmd_0.9.127.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.127.0/fmd_0.9.127.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.127.0/fmd_0.9.127.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.127.0/fmd_0.9.127.0_Win64.7z From d0ff6eb9d256cb25e44cb2d0d272c6d98e4567a3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Nov 2017 11:05:05 +0800 Subject: [PATCH 1915/2794] update besen --- 3rd/BESEN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/BESEN b/3rd/BESEN index bed9b6ccf..4d55f34fb 160000 --- a/3rd/BESEN +++ b/3rd/BESEN @@ -1 +1 @@ -Subproject commit bed9b6ccf3d2986dc80e698c94dd0a63f02ba28f +Subproject commit 4d55f34fb3b0e9aa7e18ca0b18dd40d813d4d23c From 17612429cce57e85189f298c0524b9d461a54c3b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 27 Nov 2017 11:05:22 +0800 Subject: [PATCH 1916/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 4c45e99b3..8cad542f8 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 4c45e99b30e3749c8b69ece7e74d6fa3501ddb9c +Subproject commit 8cad542f87c95fb70f4b462a1150e821a5c608d4 From 304a09d5e9b8d3f623f812b29221340f0ff1911f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Dec 2017 05:33:33 +0800 Subject: [PATCH 1917/2794] update basecrypto --- baseunits/BaseCrypto.pas | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas index 67ec073d6..8c1f87d1f 100644 --- a/baseunits/BaseCrypto.pas +++ b/baseunits/BaseCrypto.pas @@ -9,8 +9,10 @@ interface function HexToStr(const h: String): String; procedure HexToBytes(const h: String; var o :TBytes); -function BytesToHex(const h: TBytes): String; +function BytesToHex(const b: TBytes): String; +function BytesToString(const b: TBytes): String; function JSHexToStr(const h: String): String; +function StrToHexStr(const s: String): String; function Pkcs7AddPad(const s: String): String; function Pkcs7RemovePad(const s: String): String; @@ -38,13 +40,22 @@ procedure HexToBytes(const h: String; var o :TBytes); o[i]:=Byte(StrToInt('$'+Copy(h,(i*2)+1,2))); end; -function BytesToHex(const h: TBytes): String; +function BytesToHex(const b: TBytes): String; var i: Integer; begin Result:=''; - for i:=Low(h) to High(h) do - Result+=hexStr(h[i],2); + for i:=Low(b) to High(b) do + Result+=IntToHex(b[i],2); +end; + +function BytesToString(const b: TBytes): String; +var + i: Integer; +begin + Result:=''; + for i:=Low(b) to High(b) do + Result+=Char(b[i]); end; function JSHexToStr(const h: String): String; @@ -52,6 +63,12 @@ function JSHexToStr(const h: String): String; Result := HexToStr(StringReplace(h, '\x', '', [rfIgnoreCase, rfReplaceAll])); end; +function StrToHexStr(const s: String): String; +begin + SetLength(Result, Length(s) * 2); + BinToHex(@s[1],@Result[1],Length(s)); +end; + // Pkcs7 padding described in RFC 5652 https://tools.ietf.org/html/rfc5652#section-6.3 function Pkcs7AddPad(const s: String): String; var @@ -94,7 +111,7 @@ function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; var - i: String; + data: String; ivb: TBytes; begin Result:=''; @@ -104,9 +121,9 @@ function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; InitStr(key,TDCP_sha256); HexToBytes(iv,ivb); SetIV(ivb[0]); - i:=DecodeStringBase64(s); - SetLength(Result,Length(i)); - DecryptCBC(i[1],Result[1],Length(i)); + data:=DecodeStringBase64(s); + SetLength(Result,Length(data)); + DecryptCBC(data[1],Result[1],Length(data)); Burn; Result:=Pkcs7RemovePad(Result); except From 60c90421a2541396918465ef1bb553251a0c9bf7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Dec 2017 05:33:49 +0800 Subject: [PATCH 1918/2794] update mangafox domain --- baseunits/modules/MangaFox.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 8f65d710a..23cd1fc2c 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -117,7 +117,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaFox'; - RootURL := 'http://mangafox.me'; + RootURL := 'http://mangafox.la'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From 4defb418964cdc00abe8e4685834e70003a4a521 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 15 Dec 2017 05:42:14 +0800 Subject: [PATCH 1919/2794] Bump version 0.9.128.0 --- changelog.txt | 3 +++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index e6c14200f..8341122d8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,9 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.128.0 (15-12-2017) +Full changes: https://github.com/riderkick/FMD/compare/0.9.127.0...0.9.128.0 + 0.9.127.0 (19-11-2017) [*] MangaFox, MangaHere: exclude ads page Full changes: https://github.com/riderkick/FMD/compare/0.9.126.0...0.9.127.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index d02956cf9..83cf25d97 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="127"/> + <RevisionNr Value="128"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index e6ccc0340..0db3e2ac3 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.127.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.127.0/fmd_0.9.127.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.127.0/fmd_0.9.127.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.127.0/fmd_0.9.127.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.127.0/fmd_0.9.127.0_Win64.7z +VERSION=0.9.128.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.128.0/fmd_0.9.128.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.128.0/fmd_0.9.128.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.128.0/fmd_0.9.128.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.128.0/fmd_0.9.128.0_Win64.7z From 85df2404a0997e3c72a9c9b8e6a0a056e0632db5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 22 Dec 2017 02:22:03 +0800 Subject: [PATCH 1920/2794] Fix all caps titles for MangaHere --- baseunits/modules/MangaHere.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index e2aae3501..228e1d18f 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -54,7 +54,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with TXQueryEngineHTML.Create(Document) do try coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="manga_detail"]//img[@class="img"]/@src')); - if title = '' then title := XPathString('//h1[@class="title"]'); + if title = '' then title := XPathString('//meta[@property="og:title"]/@content'); authors := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Author")]'), ':'); artists := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Artist")]'), ':'); genres := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Genre")]'), ':'); From 9d213de8dac3dcabe70ddd59365b1dd8791e434f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 22 Dec 2017 02:22:44 +0800 Subject: [PATCH 1921/2794] update mangahere domain --- baseunits/modules/MangaHere.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 228e1d18f..c9ebce29b 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -135,7 +135,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaHere'; - RootURL := 'http://www.mangahere.co'; + RootURL := 'http://www.mangahere.cc'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From b21802b0fd353952fb0a1880cb5be012ea53d88b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 23 Dec 2017 05:46:38 +0800 Subject: [PATCH 1922/2794] eightmuses, fixed download --- baseunits/modules/EightMuses.pas | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/EightMuses.pas b/baseunits/modules/EightMuses.pas index df33f8bb8..5d6486cd1 100644 --- a/baseunits/modules/EightMuses.pas +++ b/baseunits/modules/EightMuses.pas @@ -51,7 +51,10 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; end else begin chapterLinks.Add(url); - chapterName.Add(title + ' - ' + s); + if s <> '' then + chapterName.Add(title + ' - ' + s) + else + chapterName.Add(title); end; finally Free; @@ -82,8 +85,10 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String s := v.toString; if s <> '' then begin - s := StringReplace(s, '/th/', '/fu/', [rfIgnoreCase]); + s := StringReplace(s, '/th/', '/fm/', [rfIgnoreCase]); s := MaybeFillHost(Module.RootURL, s); + if Pos('//', s) = 1 then + s := 'https:' + s; PageLinks.Add(s); end; end; From ed4b58bf5cd0f81a3eb9cb3faa994d337c38dd61 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 30 Dec 2017 07:08:03 +0800 Subject: [PATCH 1923/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 8cad542f8..e3c04bba8 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 8cad542f87c95fb70f4b462a1150e821a5c608d4 +Subproject commit e3c04bba823f294834675ad9c9095552c72194f8 From 4b0e53833a130335e9b65c194555204e8a4baa9d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 31 Dec 2017 06:05:14 +0800 Subject: [PATCH 1924/2794] httpsendthread, added lasturl property --- baseunits/httpsendthread.pas | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index dd212a2fa..f4b2695b6 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -50,6 +50,7 @@ THTTPSendThread = class; THTTPSendThread = class(THTTPSend) private + FURL: String; FOwner: TBaseThread; FRetryCount: Integer; FGZip: Boolean; @@ -89,6 +90,7 @@ THTTPSendThread = class(THTTPSend) public BeforeHTTPMethod: THTTPMethodEvent; AfterHTTPMethod: THTTPMethodEvent; + property LastURL: String read FURL; end; TKeyValuePair = array[0..1] of String; @@ -431,20 +433,20 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: var counter: Integer = 0; redirectcounter: Integer = 0; - rurl, s, h, p: String; + s, h, p: String; HTTPHeader: TStringList; mstream: TMemoryStream; begin Result := False; - rurl := TrimRight(TrimLeftSet(URL, [':', '/', #0..' '])); - if rurl = '' then Exit; - rurl := MaybeEncodeURL(rurl); + FURL := TrimRight(TrimLeftSet(URL, [':', '/', #0..' '])); + if FURL = '' then Exit; + FURL := MaybeEncodeURL(FURL); if Pos('HTTP/', Headers.Text) = 1 then Reset; HTTPHeader := TStringList.Create; HTTPHeader.Assign(Headers); try // first request - while (not HTTPMethod(Method, rurl)) or + while (not HTTPMethod(Method, FURL)) or ((not FAllowServerErrorResponse) and (ResultCode > 500)) do begin if CheckTerminate then Exit; if (FRetryCount > -1) and (FRetryCount <= counter) then Exit; @@ -459,21 +461,21 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: // break too many redirect if redirectcounter >= FMaxRedirect then Exit else Inc(redirectcounter); - HTTPHeader.Values['Referer'] := ' ' + rurl; + HTTPHeader.Values['Referer'] := ' ' + FURL; s := Trim(Headers.Values['Location']); if s<>'' then begin SplitURL(s,@h,@p); s:=p; if h='' then - SplitURL(rurl,@h,@p); - rurl:=h+s; + SplitURL(FURL,@h,@p); + FURL:=h+s; end; Clear; Headers.Assign(HTTPHeader); counter := 0; - while (not HTTPMethod('GET', rurl)) or + while (not HTTPMethod('GET', FURL)) or ((not FAllowServerErrorResponse) and (ResultCode > 500)) do begin if checkTerminate then Exit; if (FRetryCount > -1) and (FRetryCount <= counter) then Exit; From 574247ad5c0c9d0c6dcb9506fa1a29d72cb6188e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 31 Dec 2017 06:07:10 +0800 Subject: [PATCH 1925/2794] mangago, fixed download fixed #813 --- baseunits/modules/MangaGo.pas | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index e552b7300..e50b740ef 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -78,7 +78,7 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - s: String; + s, rurl: String; begin Result := False; if DownloadThread = nil then Exit; @@ -86,7 +86,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then + rurl := MaybeFillHost(Module.RootURL, AURL); + if GETWithCookie(DownloadThread.FHTTP, rurl) then begin Result := True; s := XPathString('//script[contains(.,"imgsrcs")]', Document); @@ -97,11 +98,23 @@ function GetPageNumber(const DownloadThread: TDownloadThread; s := GetString(s, ' = ''', ''';'); s:=StringReplace(s, '''', '', [rfReplaceAll]); PageLinks.CommaText := s; + if LastURL <> rurl then + PageContainerLinks.Text := LastURL; end; end; end; end; +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + var AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := True; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container do + if PageContainerLinks.Count <> 0 then + DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + PageContainerLinks[0]; +end; + procedure RegisterModule; begin with AddModule do @@ -112,6 +125,7 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; end; end; From a04ee6bde797efa3b37e86ef61d1327aaf08a2b3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 1 Jan 2018 22:49:43 +0800 Subject: [PATCH 1926/2794] kissmanga, added more log info --- baseunits/modules/KissManga.pas | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index d2b976118..7ce8c4435 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -273,13 +273,18 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; end else if not testkeyiv(kissmangakey, kissmangaiv) then + begin + SendLog('KissManga, failed to decrypt. chko1='+chko1+'; chko2= '+chko2+'; iv='+civ+'; '+AURL, PageLinks); PageLinks.Clear; + end; if PageLinks.Count <> 0 then begin for i := 0 to PageLinks.Count - 1 do PageLinks[i] := AESDecryptCBCSHA256Base64Pkcs7(PageLinks[i], key, iv); end; - end; + end + else + SendLogError('KissManga, image list empty. '+AURL); finally source.Free; end; From a70f83672fbf71a3e0cfeb41dc2ba1b989aa8288 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 2 Jan 2018 05:24:53 +0800 Subject: [PATCH 1927/2794] Bump version 0.9.129.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 11 ++++++----- update | 10 +++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8341122d8..0f0e9339d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.129.0 (02-01-2018) +[*] MangaGo: fixed download +Full changes: https://github.com/riderkick/FMD/compare/0.9.128.0...0.9.129.0 + 0.9.128.0 (15-12-2017) Full changes: https://github.com/riderkick/FMD/compare/0.9.127.0...0.9.128.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 83cf25d97..cdec25c1b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="10"/> + <Version Value="11"/> <PathDelim Value="\"/> <General> <SessionStorage Value="InProjectDir"/> @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="128"/> + <RevisionNr Value="129"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> @@ -274,9 +274,10 @@ <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> - <local> - <FormatVersion Value="1"/> - </local> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"/> + </Modes> </RunParams> <RequiredPackages Count="9"> <Item1> diff --git a/update b/update index 0db3e2ac3..950d13d96 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.128.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.128.0/fmd_0.9.128.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.128.0/fmd_0.9.128.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.128.0/fmd_0.9.128.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.128.0/fmd_0.9.128.0_Win64.7z +VERSION=0.9.129.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.129.0/fmd_0.9.129.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.129.0/fmd_0.9.129.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.129.0/fmd_0.9.129.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.129.0/fmd_0.9.129.0_Win64.7z From d95805a9146c23a363a9779993e98dbb4d755fcb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 7 Jan 2018 08:10:49 +0800 Subject: [PATCH 1928/2794] license file --- COPYING.GPL.txt => license.txt | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) rename COPYING.GPL.txt => license.txt (96%) diff --git a/COPYING.GPL.txt b/license.txt similarity index 96% rename from COPYING.GPL.txt rename to license.txt index c79e32906..d159169d1 100644 --- a/COPYING.GPL.txt +++ b/license.txt @@ -1,9 +1,8 @@ - GNU GENERAL PUBLIC LICENSE Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -16,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -56,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION @@ -111,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -169,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -226,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -279,8 +278,8 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -292,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> + Copyright (C) <year> <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -304,16 +303,16 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. From c475e9f04a839f9e93b9b8c136b66116dcff8e6e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 9 Jan 2018 21:16:13 +0300 Subject: [PATCH 1929/2794] Fix MangaInn module --- baseunits/modules/MangaInn.pas | 88 ++++++++++++++++------------------ 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas index 49bf8eec6..4685266fc 100644 --- a/baseunits/modules/MangaInn.pas +++ b/baseunits/modules/MangaInn.pas @@ -15,26 +15,32 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; var v: IXQValue; + s: String; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/MangaList') then + for s in ['a'..'z', '#'] do begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//*[@class="mangalistItems"]/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list/' + s) then + begin + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//ul[contains(@class, "manga-list")]/li/a') do + begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(v.toString); + end; + finally + Free; end; - finally - Free; - end; + end; end; + Result := NO_ERROR; end; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -45,19 +51,24 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//img[@itemprop="image"]/resolve-uri(@src)'); + coverLink := XPathString('//div[contains(@class, "manga-info")]//img[@class="img-responsive mobile-img"]/resolve-uri(@src)'); title := XPathString('//title'); if Pos(' - Read ', title) <> 0 then - title := Trim(GetBetween(' - Read ', ' Online For Free', title)); + title := Trim(GetBetween('- Read ', ' Online at', title)); status := MangaInfoStatusIfPos( - XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Status")]/following-sibling::*[1]'), + XPathString('//dt[starts-with(.,"Status")]/following-sibling::dd[1]'), 'Ongoing', 'Complete'); - authors := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Author(s)")]/following-sibling::*[1]'); - artists := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Artist(s)")]/following-sibling::*[1]'); - genres := XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Genre(s)")]/following-sibling::*[1]'); - summary := Trim(XPathString('//*[@class="RedHeadLabel"][starts-with(.,"Summary")]/following-sibling::*')); - XPathHREFAll('//div[@class="content"]/div[@class="divThickBorder"][3]/table//td[1]/span/a', chapterLinks, chapterName); + authors := XPathString('//dt[starts-with(.,"Author")]/following-sibling::dd[1]'); + artists := XPathString('//dt[starts-with(.,"Artist")]/following-sibling::dd[1]'); + genres := XPathStringAll('//dt[starts-with(.,"Categories")]/following-sibling::dd[1]/a'); + summary := Trim(XPathString('//div[contains(@class, "manga-info")]//div[contains(@class, "note")]')); + for v in XPath('//div[@id="chapter_list"]/ul/li/a') do + begin + chapterLinks.Add(v.toNode().getAttribute('href')); + chapterName.Add(XPathString('span[1]', v)); + end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -67,29 +78,6 @@ function GetInfo(const MangaInfo: TMangaInformation; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('//select[@id="cmbpages"]/option').Count; - PageLinks.Add(XPathString('//*[@id="divimgPage"]/img/@src')); - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; var s: String; begin @@ -97,15 +85,20 @@ function GetImageURL(const DownloadThread: TDownloadThread; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := MaybeFillHost(Module.RootURL, AURL); - if DownloadThread.WorkId > 0 then - s += '/page_' + IntToStr(DownloadThread.WorkId + 1); - if GET(s) then + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL + '/all-pages')) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try - PageLinks[DownloadThread.WorkId] := XPathString('//*[@id="divimgPage"]/img/@src'); + s := XPathString('//script[contains(.,"var images = [")]'); + if s <> '' then + begin + s := '[' + GetBetween('var images = [', '];', s) + ']'; + ParseHTML(s); + XPathStringAll('json(*)().url', PageLinks); + end; finally Free; end; @@ -122,7 +115,6 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; end; end; From 62b8c032dbd8e66f50456397ac8c95458fdcf987 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 10 Jan 2018 09:16:45 +0300 Subject: [PATCH 1930/2794] Fix NineManga parsing --- baseunits/modules/NineManga.pas | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/NineManga.pas b/baseunits/modules/NineManga.pas index 7fc345641..d54e97384 100644 --- a/baseunits/modules/NineManga.pas +++ b/baseunits/modules/NineManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, RegExpr; implementation @@ -86,11 +86,16 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; begin Result := False; if DownloadThread = nil then Exit; + s := AURL; + s := ReplaceRegExpr('\.html?$', s, '', False); + s := s + '-' + IncStr(DownloadThread.WorkId) + '.html'; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)) + 'page-' + IncStr(DownloadThread.WorkId)) then + if GET(MaybeFillHost(Module.RootURL, s)) then begin Result := True; PageLinks[DownloadThread.WorkId] := XPathString('//img[contains(@class,"manga_pic")]/@src', Document); From 3d0a85ca35606b8a6ba58ba260f665a775208a7c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 10 Jan 2018 14:50:27 +0300 Subject: [PATCH 1931/2794] Fix NineManga cookies and headers --- baseunits/modules/NineManga.pas | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/NineManga.pas b/baseunits/modules/NineManga.pas index d54e97384..fc16c363d 100644 --- a/baseunits/modules/NineManga.pas +++ b/baseunits/modules/NineManga.pas @@ -12,6 +12,9 @@ implementation uses FMDVars; +var + cookie: String; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; @@ -48,7 +51,6 @@ function GetInfo(const MangaInfo: TMangaInformation; begin url := MaybeFillHost(Module.RootURL, AURL); s := url; - if Pos('waring=1', s) = 0 then s += '?waring=1'; if GET(s) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try @@ -87,17 +89,33 @@ function GetPageNumber(const DownloadThread: TDownloadThread; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - s: String; + s, ref: String; begin Result := False; if DownloadThread = nil then Exit; + s := AURL; s := ReplaceRegExpr('\.html?$', s, '', False); + if DownloadThread.WorkId = 0 then + ref := AURL + else + ref := s + '-' + IntToStr(DownloadThread.WorkId) + '.html'; s := s + '-' + IncStr(DownloadThread.WorkId) + '.html'; + ref := MaybeFillHost(module.RootURL, ref); + + if cookie = '' then + begin + if DownloadThread.FHTTP.GET(Module.RootURL) then + cookie := DownloadThread.FHTTP.Cookies.Text; + end; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + Cookies.Text := cookie; + Headers.Values['Referer'] := ref; if GET(MaybeFillHost(Module.RootURL, s)) then begin Result := True; + cookie := Cookies.Text; PageLinks[DownloadThread.WorkId] := XPathString('//img[contains(@class,"manga_pic")]/@src', Document); end; end; @@ -129,6 +147,7 @@ procedure RegisterModule; end; initialization + cookie := ''; RegisterModule; end. From d56fe84a56653836fbb0fb9923922da2ac84381b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 10 Jan 2018 16:19:15 +0300 Subject: [PATCH 1932/2794] fix --- baseunits/modules/NineManga.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/modules/NineManga.pas b/baseunits/modules/NineManga.pas index fc16c363d..a7a6747e0 100644 --- a/baseunits/modules/NineManga.pas +++ b/baseunits/modules/NineManga.pas @@ -115,7 +115,6 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; if GET(MaybeFillHost(Module.RootURL, s)) then begin Result := True; - cookie := Cookies.Text; PageLinks[DownloadThread.WorkId] := XPathString('//img[contains(@class,"manga_pic")]/@src', Document); end; end; From 57d7cb7da1fe0dc79a9bacd0d775106438469368 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 13 Jan 2018 01:41:50 +0800 Subject: [PATCH 1933/2794] mainform, disable dialog on auto save options --- mangadownloader/forms/frmMain.lfm | 93 +++++++++++++++---------------- mangadownloader/forms/frmMain.pas | 8 +-- 2 files changed, 50 insertions(+), 51 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 63d05dd4c..cc72a022f 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,6 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -4665,14 +4664,14 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - Left = 96 - Top = 251 + left = 96 + top = 251 end object pmDownload: TPopupMenu Images = IconList OnPopup = pmDownloadPopup - Left = 592 - Top = 184 + left = 592 + top = 184 object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False @@ -5002,8 +5001,8 @@ object MainForm: TMainForm end end object pmChapterList: TPopupMenu - Left = 592 - Top = 224 + left = 592 + top = 224 object miChapterListCheckSelected: TMenuItem Caption = 'Check selected' OnClick = miChapterListCheckSelectedClick @@ -5061,8 +5060,8 @@ object MainForm: TMainForm object pmFavorites: TPopupMenu Images = IconList OnPopup = pmFavoritesPopup - Left = 520 - Top = 212 + left = 520 + top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' Bitmap.Data = { @@ -5380,8 +5379,8 @@ object MainForm: TMainForm object pmMangaList: TPopupMenu Images = IconList OnPopup = pmMangaListPopup - Left = 382 - Top = 238 + left = 382 + top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' Bitmap.Data = { @@ -5527,13 +5526,13 @@ object MainForm: TMainForm PopUpMenu = pmTray Hint = 'Free Manga Downloader' OnDblClick = TrayIconDblClick - Left = 288 - Top = 432 + left = 288 + top = 432 end object pmUpdate: TPopupMenu ParentBidiMode = False - Left = 382 - Top = 110 + left = 382 + top = 110 object mnUpdateList: TMenuItem Caption = 'Update manga list' OnClick = mnUpdateListClick @@ -5555,8 +5554,8 @@ object MainForm: TMainForm end end object IconList: TImageList - Left = 278 - Top = 102 + left = 278 + top = 102 Bitmap = { 4C691700000010000000100000004F4F4F005050500052525200535353005454 54155555553E555555555555556355555563555555555555553E545454155353 @@ -6298,8 +6297,8 @@ object MainForm: TMainForm } end object IconDL: TImageList - Left = 278 - Top = 150 + left = 278 + top = 150 Bitmap = { 4C69090000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6595,8 +6594,8 @@ object MainForm: TMainForm object IconMed: TImageList Height = 48 Width = 48 - Left = 328 - Top = 238 + left = 328 + top = 238 Bitmap = { 4C69010000003000000030000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6890,8 +6889,8 @@ object MainForm: TMainForm } end object IconSmall: TImageList - Left = 27 - Top = 328 + left = 27 + top = 328 Bitmap = { 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF @@ -6994,8 +6993,8 @@ object MainForm: TMainForm end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup - Left = 592 - Top = 136 + left = 592 + top = 136 object medURLUndo: TMenuItem Caption = 'Undo' OnClick = medURLUndoClick @@ -7034,38 +7033,38 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - Left = 96 - Top = 312 + left = 96 + top = 312 end object tmExitCommand: TTimer Enabled = False OnTimer = tmExitCommandTimer - Left = 560 - Top = 472 + left = 560 + top = 472 end object TransferRateGraphList: TListChartSource DataPoints.Strings = ( '1|0|?|' ) - Left = 504 - Top = 120 + left = 504 + top = 120 end object TransferRateToolset: TChartToolset - Left = 464 - Top = 120 + left = 464 + top = 120 end object pmSbMain: TPopupMenu OnPopup = pmSbMainPopup - Left = 152 - Top = 376 + left = 152 + top = 376 object miAbortSilentThread: TMenuItem Caption = 'Abort' OnClick = miAbortSilentThreadClick end end object pmFilterGenreAll: TPopupMenu - Left = 520 - Top = 168 + left = 520 + top = 168 object mnFilterGenreAllCheck: TMenuItem Caption = 'Check all' OnClick = mnFilterGenreAllCheckClick @@ -7081,8 +7080,8 @@ object MainForm: TMainForm end object pmTray: TPopupMenu OnPopup = pmTrayPopup - Left = 341 - Top = 432 + left = 341 + top = 432 object miTrayResumeAll: TMenuItem Caption = 'Resume all' OnClick = tbDownloadResumeAllClick @@ -7146,28 +7145,28 @@ object MainForm: TMainForm Enabled = False Interval = 48 OnTimer = tmAnimateMangaInfoTimer - Left = 656 - Top = 416 + left = 656 + top = 416 end object tmRefreshDownloadsInfo: TTimer Enabled = False OnTimer = tmRefreshDownloadsInfoTimer OnStartTimer = tmRefreshDownloadsInfoStartTimer OnStopTimer = tmRefreshDownloadsInfoStopTimer - Left = 440 - Top = 472 + left = 440 + top = 472 end object tmBackup: TTimer Interval = 120000 OnTimer = tmBackupTimer - Left = 656 - Top = 472 + left = 656 + top = 472 end object tmCheckFavorites: TTimer Enabled = False Interval = 600000 OnTimer = tmCheckFavoritesTimer - Left = 480 - Top = 472 + left = 480 + top = 472 end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9ba3b2c83..120584d0c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -683,7 +683,7 @@ TMainForm = class(TForm) // Load config from config.ini procedure LoadOptions; - procedure SaveOptions; + procedure SaveOptions(const AShowDialog: Boolean = False); procedure ApplyOptions; // Load config from mangalist.ini @@ -4185,7 +4185,7 @@ procedure TMainForm.vtMangaListColumnDblClick(Sender: TBaseVirtualTree; procedure TMainForm.btOptionApplyClick(Sender: TObject); begin - SaveOptions; + SaveOptions(True); ApplyOptions; if not Self.Focused then Self.SetFocus; end; @@ -4778,14 +4778,14 @@ procedure TMainForm.LoadOptions; end; end; -procedure TMainForm.SaveOptions; +procedure TMainForm.SaveOptions(const AShowDialog: Boolean); var s: String; begin if Length(optionMangaSiteSelectionNodes) > 0 then begin s := SaveMangaOptions; - if s = '' then + if (s = '') and AShowDialog then begin MessageDlg('', RS_DlgMangaListSelect, mtConfirmation, [mbYes], 0); From 6b76d5c719ea2b17fc9c5e6dedd04a767902467f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 11 Jan 2018 07:29:31 +0300 Subject: [PATCH 1934/2794] Fix crash when clicking on deleted row (fixes #762) --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 120584d0c..8d2716e93 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3395,7 +3395,7 @@ procedure TMainForm.pmDownloadPopup(Sender: TObject); miDownloadDeleteCompleted.Enabled := DLManager.Count > 0; miDownloadMergeCompleted.Enabled := miDownloadDeleteCompleted.Enabled; with DLManager do begin - if vtDownload.SelectedCount = 0 then + if (vtDownload.SelectedCount = 0) or (vtDownload.FocusedNode = nil) then begin miDownloadStop.Enabled := False; miDownloadResume.Enabled := False; From 76b4c106e24faa6d39712c428e2f8fee3f1a7957 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 11 Jan 2018 07:43:05 +0300 Subject: [PATCH 1935/2794] Changed mangalife.org to mangalife.us (fixes #771) --- baseunits/modules/MangaLife.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 7685c6317..6004d18ab 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -240,7 +240,7 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaLife', 'http://mangalife.org'); + AddWebsiteModule('MangaLife', 'http://mangalife.us'); AddWebsiteModule('MangaSee', 'http://mangaseeonline.us'); MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.biz'); MMangaTraders.AccountSupport := True; From a04b93b03495c3c19ee40c39a9204a5ca931fd0b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 13 Jan 2018 05:19:11 +0300 Subject: [PATCH 1936/2794] fix mangaid (fixes #803, #767, #724, #648) --- baseunits/modules/myMangaReaderCMS.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index d14bf8a59..25ff64bb2 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -81,6 +81,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with TXQueryEngineHTML.Create(Document) do try XPathStringAll('//div[@id="all"]/img/@data-src', PageLinks); + if PageLinks.Count = 0 then + XPathStringAll('//div[@id="all"]/img/@src', PageLinks); finally Free; end; From 3a2c19cf072f2264344f93a9a9b84e38bdad749c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 13 Jan 2018 05:32:34 +0300 Subject: [PATCH 1937/2794] Add subapics.com (#651) --- baseunits/modules/MangaShiro.pas | 28 ++++++++++++++++++++-------- config/mangalist.ini | 2 +- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas index e234d186b..283611d6d 100644 --- a/baseunits/modules/MangaShiro.pas +++ b/baseunits/modules/MangaShiro.pas @@ -13,9 +13,13 @@ implementation function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; +var + dirurl: String; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/daftar-manga/') then + dirurl := '/daftar-manga/'; + if Module.Website = 'Subapics' then dirurl := '/manga-list/'; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; XPathHREFAll('//*[@class="soralist"]//a', MangaInfo.FHTTP.Document, ALinks, ANames); @@ -67,15 +71,23 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; procedure RegisterModule; -begin - with AddModule do + + function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; begin - Website := 'MangaShiro'; - RootURL := 'http://mangashiro.net'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; end; + +begin + AddWebsiteModule('MangaShiro', 'http://mangashiro.net'); + AddWebsiteModule('Subapics', 'http://subapics.com/'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index afc75e683..8e2862f58 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineMangaDE -Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik +Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik,Subapics Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas From 429c93415fa83328d068d4ac04a6f0ac7b2b7879 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 13 Jan 2018 05:36:47 +0300 Subject: [PATCH 1938/2794] Add mangadesu.net (fixes #651) --- baseunits/modules/myMangaReaderCMS.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index 25ff64bb2..287f8db58 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -111,6 +111,7 @@ procedure RegisterModule; AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); AddWebsiteModule('MangaID', 'http://mangaid.co'); AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); + AddWebsiteModule('MangaDesu','http://mangadesu.net/'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 8e2862f58..75e814f2b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineMangaDE -Indonesian=Komikid,Mangacan,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik,Subapics +Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik,Subapics Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas From dc1f3387504db90abde2953a5dfe592d7c3f238d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 13 Jan 2018 08:41:42 +0300 Subject: [PATCH 1939/2794] Add mangakita.net (fixes #643) --- baseunits/modules/MangaShiro.pas | 7 ++++--- config/mangalist.ini | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas index 283611d6d..65d80d951 100644 --- a/baseunits/modules/MangaShiro.pas +++ b/baseunits/modules/MangaShiro.pas @@ -17,8 +17,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; dirurl: String; begin Result := NET_PROBLEM; - dirurl := '/daftar-manga/'; - if Module.Website = 'Subapics' then dirurl := '/manga-list/'; + dirurl := '/manga-list/'; + if Module.Website = 'MangaShiro' then dirurl := '/daftar-manga/'; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; @@ -87,7 +87,8 @@ procedure RegisterModule; begin AddWebsiteModule('MangaShiro', 'http://mangashiro.net'); - AddWebsiteModule('Subapics', 'http://subapics.com/'); + AddWebsiteModule('Subapics', 'http://subapics.com'); + AddWebsiteModule('MangaKita', 'http://www.mangakita.net'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 75e814f2b..f9150f982 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineMangaDE -Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKu,MangaShiro,PecintaKomik,Subapics +Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas From ea39fb20ad58ded19383c6ea285af1f4835e1ace Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 13 Jan 2018 09:03:31 +0300 Subject: [PATCH 1940/2794] Fix madokami chapter title issue (fixes #725) --- baseunits/modules/Madokami.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 88870a042..593405139 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -222,7 +222,7 @@ function GetInfo(const MangaInfo: TMangaInformation; if chapterName.Count > 0 then with TRegExpr.Create do try - Expression := '\.\w+'; + Expression := '\.\w+\s*$'; for i := 0 to chapterName.Count - 1 do chapterName[i] := Replace(chapterName[i], '', False); finally From c0092c70673d7d21f947c246ac0eb3caeb41229c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 13 Jan 2018 15:16:48 +0300 Subject: [PATCH 1941/2794] Rewrite MangaInn.GetNameAndLink --- baseunits/modules/MangaInn.pas | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas index 4685266fc..64f2439c5 100644 --- a/baseunits/modules/MangaInn.pas +++ b/baseunits/modules/MangaInn.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, synautil; + XQueryEngineHTML, synautil, FMDVars; implementation @@ -14,27 +14,21 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - v: IXQValue; s: String; begin Result := NET_PROBLEM; - for s in ['a'..'z', '#'] do + s := ALPHA_LIST[Module.CurrentDirectoryIndex + 1]; + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list/' + s) then begin - if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list/' + s) then - begin - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//ul[contains(@class, "manga-list")]/li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + updateList.CurrentDirectoryPageNumber := 1; + XPathHREFAll('//ul[contains(@class, "manga-list")]/li/a', ALinks, ANames); + finally + Free; + end; end; - Result := NO_ERROR; end; function GetInfo(const MangaInfo: TMangaInformation; @@ -115,6 +109,7 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + TotalDirectory := Length(ALPHA_LIST); end; end; From 0c3801acc11248743046f7d8ee9c1368190693bb Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 14 Jan 2018 08:11:49 +0300 Subject: [PATCH 1942/2794] jaiminisbox, fix download (refs #800) --- baseunits/modules/FoOlSlide.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 4198373f7..5692433a9 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -180,6 +180,10 @@ function GetPageNumber(const DownloadThread: TDownloadThread; s := XPathString('//script[contains(.,"var pages")]'); if s <> '' then begin s := GetBetween('var pages = ', ';', s); + if Pos('atob("', s) > 0 then begin + s := GetBetween('atob("', '")', s); + s := Base64Decode(s); + end; try ParseHTML(s); for v in XPath('json(*)()("url")') do From d7d670a30b3dccb36a39f480744a03b43d1819c8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 15 Jan 2018 06:55:08 +0300 Subject: [PATCH 1943/2794] readmangatoday, change domain (fixes #839) --- baseunits/modules/ReadMangaToday.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/ReadMangaToday.pas b/baseunits/modules/ReadMangaToday.pas index 4ab04735f..46683e28a 100644 --- a/baseunits/modules/ReadMangaToday.pas +++ b/baseunits/modules/ReadMangaToday.pas @@ -93,7 +93,7 @@ procedure RegisterModule; with AddModule do begin Website := 'ReadMangaToday'; - RootURL := 'http://www.readmanga.today'; + RootURL := 'https://www.readmng.com'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 863a367e81aec75a2bcbc2d34dbe79356c2b72e4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 11 Jan 2018 13:29:15 +0300 Subject: [PATCH 1944/2794] mangapark, fix title (fixes #738) --- baseunits/modules/MangaPark.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaPark.pas b/baseunits/modules/MangaPark.pas index b34c4d2e1..fd3e0d6ad 100644 --- a/baseunits/modules/MangaPark.pas +++ b/baseunits/modules/MangaPark.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML, httpsendthread, synautil, strutils; implementation @@ -76,7 +76,9 @@ function GetInfo(const MangaInfo: TMangaInformation; with TXQueryEngineHTML.Create(Document) do try coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); - if title = '' then title := XPathString('//*[@class="content"]//h1'); + if title = '' then title := Trim(XPathString('//*[@class="content"]//h1')); + if AnsiEndsStr(' Manga', title) then title := LeftStr(title, Length(title) - 6) + else if AnsiEndsStr(' Manhwa', title) then title := LeftStr(title, Length(title) - 7); authors := XPathStringAll('//table[@class="attr"]//tr/th[.="Author(s)"]/following-sibling::td/a'); artists := XPathStringAll('//table[@class="attr"]//tr/th[.="Artist(s)"]/following-sibling::td/a'); genres := XPathStringAll('//table[@class="attr"]//tr/th[.="Genre(s)"]/following-sibling::td/a'); From d9323f64b9dce839945950d54e92d3e11b01f50f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 16 Jan 2018 21:27:32 +0300 Subject: [PATCH 1945/2794] tsumino, fix update list (fixed #841) --- baseunits/modules/Tsumino.pas | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index c704cb84a..93f0629c6 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -11,11 +11,9 @@ interface implementation const - //dirurl = '/Browse/Index/1/'; - // '/?pageNumber=532&RawSearch=&SortOptions=Newest&PageMinimum=1&PageMaximum=10000&RateMinimum=0&RateMaximum=5' - dirurl = '/Browse/Query'; - dirurldata = 'pageNumber='; - dirurldataend = '&RawSearch=&SortOptions=Newest&PageMinimum=1&PageMaximum=10000&RateMinimum=0&RateMaximum=5'; + dirurl = '/Books/Operate'; + dirurldata = 'PageNumber='; + dirurldataend = '&Text=&Sort=Newest&List=0&Length=0&MinimumRating=0&ExcludeList=0&CompletelyExcludeHated=false'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; @@ -35,7 +33,6 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; var v: IXQValue; - s: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -45,14 +42,9 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - s := XPathString('json(*)("Data")'); - if s <> '' then - begin - ParseHTML(s); - for v in XPath('//div[@class="overlay"]/a/@href') do - ALinks.Add(v.toString); - for v in XPath('//div[@class="overlay"]/div[@class="overlay-data"]/div[@class="overlay-title"]') do - ANames.Add(v.toString); + for v in XPath('json(*)("Data")().Entry') do begin + ANames.Add(v.getProperty('Title').toString()); + ALinks.Add(Module.RootURL + '/Book/Info/' + v.getProperty('Id').toString()); end; finally Free; From cb3fbec39fe7cd40ac2b298be31e782caf6b9454 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 15 Jan 2018 11:57:55 +0300 Subject: [PATCH 1946/2794] kumanga, fix chapter list, download (fixes #722) --- baseunits/modules/KuManga.pas | 46 ++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/KuManga.pas b/baseunits/modules/KuManga.pas index 799499c9a..ba0e1d42e 100644 --- a/baseunits/modules/KuManga.pas +++ b/baseunits/modules/KuManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML, httpsendthread, synautil, URIParser; implementation @@ -64,15 +64,22 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; +var + lastPage, i, totalChapters, perPage: Integer; + s: String; + tmp: TStringList; + uri: TURI; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do + with MangaInfo.mangaInfo do begin url := FillHost(Module.RootURL, AURL); - if GET(url) then begin + if MangaInfo.FHTTP.GET(url) then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do + tmp := TStringList.Create; + lastPage := 0; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try coverLink := XPathString('//div[@class="row"]//img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); @@ -82,11 +89,37 @@ function GetInfo(const MangaInfo: TMangaInformation; artists := XPathString('//*[@class="infom"]/div/div[2]//p[contains(.,"Artist") and not(contains(.,"No Disponible"))]/substring-after(normalize-space(.),": ")'); status := MangaInfoStatusIfPos(XPathString('//*[@class="infom"]/div/div[2]//p[contains(.,"Estado")]'), 'Activo', 'Finalizado'); genres := XPathString('//*[@class="panel-footer" and contains(.,"Géneros")]/string-join(.//a,", ")'); - XPathHREFAll('//table//tr/td/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); + XPathHREFAll('//table[contains(@class, "table")]//h4[@class="title"]/a', chapterLinks, chapterName); + + s := XPathString('//script[contains(., "php_pagination")]'); + if s <> '' then begin + s := GetBetween('php_pagination(', ');', s); + tmp.Delimiter := ','; + tmp.DelimitedText := s; + totalChapters := StrToIntDef(tmp[4], 0); + perPage := StrToIntDef(tmp[5], 1); + lastPage := Math.ceil(float(totalChapters) / float(perPage)); + end; finally + tmp.Free; Free; end; + + for i := 2 to lastPage do begin + uri := ParseURI(url); + uri.Path := uri.Path + 'p/' + IntToStr(i); + s := EncodeURI(uri); + if MangaInfo.FHTTP.GET(s) then begin + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFAll('//table[contains(@class, "table")]//h4[@class="title"]/a', chapterLinks, chapterName); + finally + Free; + end; + end; + end; + + InvertStrings([chapterLinks, chapterName]); end; end; end; @@ -109,6 +142,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with TXQueryEngineHTML.Create(Document) do try pageFormat := XPathString('//script[contains(.,"konekomangareader")]/substring-before(substring-after(substring-after(.,"setup"),","),");")'); if pageFormat <> '' then begin + pageFormat := ReplaceString(pageFormat, ':remote', ':''remote'''); ParseHTML(pageFormat); pages := StrToIntDef(XPathString('json(*)//pages'), 0); pageFormat := XPathString('substring-before(json(*)//pageFormat,"{pnumber}")'); From b4feda3f224f2d162f16f574829ee4e986dc0c18 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 17 Jan 2018 09:58:34 +0300 Subject: [PATCH 1947/2794] rawsenmanga, fixed all --- baseunits/modules/RawSenManga.pas | 81 +++++++++++++------------------ 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index d997df6e4..c22894751 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -6,10 +6,13 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, RegExpr, synautil, URIParser; implementation +var + cookie: String; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; @@ -18,14 +21,11 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/Manga/?order=text-version') then begin + if MangaInfo.FHTTP.GET(Module.RootURL + '/directory/text_version') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//table//tr/td[2]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; + XPathHREFAll('//table//tr/td[2]/a', ALinks, ANames); finally Free; end; @@ -35,9 +35,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - v: IXQValue; - i: Integer; - s, cl, m: String; + cl, m: String; cu: Boolean; begin Result := NET_PROBLEM; @@ -64,38 +62,15 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//img[@class="series-cover"]/@src'); + coverLink := XPathString('//div[@class="thumbnail"]/img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h1[@itemprop="name"]'); - v := XPath('//div[@class="series_desc"]/*'); - if v.Count > 0 then begin - i := 0; - while i < v.Count - 2 do begin - s := v.get(i).toString; - if Pos('Categorize in:', s) = 1 then genres := v.get(i + 1).toString else - if Pos('Author:', s) = 1 then authors := v.get(i + 1).toString else - if Pos('Artist:', s) = 1 then artists := Trim(SeparateRight(v.get(i).toString, ':')) else - if Pos('Status:', s) = 1 then if Pos('ongoing', LowerCase(v.get(i).toString)) > 0 then - status := '1' else status := '0'; - Inc(i); - end; - end; - summary := XPathString('//div[@class="series_desc"]//div[@itemprop="description"]'); - if not cu then - for v in XPath('//*[@id="content"]/*[@id="post"]//tr[@class="even" or @class="odd"]/td[2]/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end - else if cl <> '' then - if GET(FillHost(Module.RootURL, cl)) then - begin - ParseHTML(Document); - for v in XPath('//select[@name="chapter"]/option') do begin - chapterLinks.Add(m + v.toNode.getAttribute('value')); - chapterName.Add(v.toString); - end; - end; + if title = '' then title := XPathString('//h1[@class="title"]'); + genres := XPathStringAll('//ul[@class="series-info"]/li[contains(., "Categories")]/a'); + authors := XPathStringAll('//ul[@class="series-info"]/li[contains(., "Author")]/a'); + artists := XPathStringAll('//ul[@class="series-info"]/li[contains(., "Artist")]/a'); + status := MangaInfoStatusIfPos(XPathString('//ul[@class="series-info"]/li[contains(., "Status")]/a')); + summary := XPathString('//*[@itemprop="description"]'); + XPathHREFAll('//div[@class="title" and contains(., "Chapters")]/following-sibling::div/div/a', chapterLinks, chapterName); InvertStrings([chapterLinks, chapterName]); finally Free; @@ -108,6 +83,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var s: String; + uri: TURI; begin Result := False; if DownloadThread = nil then Exit; @@ -128,18 +104,23 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, s + '/1')) then begin Result := True; + cookie := Cookies.Text; with TXQueryEngineHTML.Create(Document) do try PageNumber := XPath('//select[@name="page"]/option').Count; if PageNumber > 0 then begin s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); - if ((Pos('/raw-viewer.php?', LowerCase(s)) > 0) and (LowerCase(RightStr(s, 7)) = '&page=1')) or - ((Pos('/viewer/', AnsiLowerCase(s)) > 0) and (RightStr(s, 2) = '/1')) then - begin - SetLength(s, Length(s) - 1); - while PageLinks.Count < PageNumber do - PageLinks.Add(s + IncStr(PageLinks.Count)); - end; + uri := ParseURI(s); + if (Pos('/raw-viewer.php', LowerCase(uri.Path)) > 0) and (Pos('page=1', LowerCase(uri.Params)) > 0) then + while PageLinks.Count < PageNumber do begin + uri.Params := ReplaceString(uri.Params, 'page=1', 'page=' + IncStr(PageLinks.Count)); + PageLinks.Add(EncodeURI(uri)); + end + else if (Pos('/viewer/', LowerCase(uri.Path)) > 0) and (uri.Document = '1') then + while PageLinks.Count < PageNumber do begin + uri.Document := IncStr(PageLinks.Count); + PageLinks.Add(EncodeURI(uri)); + end; end; finally Free; @@ -152,11 +133,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var s: String; + uri: TURI; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(FillHost(Module.RootURL, AURL) + '/' + IncStr(DownloadThread.WorkId)) then begin + uri := ParseURI(FillHost(Module.RootURL, AURL)); + uri.Document := IncStr(DownloadThread.WorkId); + if GET(EncodeURI(uri)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try @@ -179,6 +163,7 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; if CurrentDownloadChapterPtr < ChapterLinks.Count then begin DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + DownloadThread.FHTTP.Cookies.Text := cookie; Result := True; end; end; From 78d6f7acf9dbda0dc330638b1f250c09e51aecc2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Jan 2018 00:00:55 +0800 Subject: [PATCH 1948/2794] fix fmd path fixes #825 --- baseunits/FMDOptions.pas | 4 ++-- baseunits/SimpleTranslator.pas | 7 ++++--- mangadownloader/forms/frmMain.pas | 2 +- mangadownloader/md.lpr | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 83c038cfb..1129029c9 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -355,8 +355,8 @@ procedure doInitialization; FMD_VERSION_NUMBER := GetCurrentBinVersion; AvailableWebsite := TStringList.Create; AvailableWebsite.Sorted := True; - SetFMDdirectory(GetCurrentDirUTF8); - SetAppDataDirectory(GetCurrentDirUTF8); + SetFMDdirectory(ExtractFilePath(Application.ExeName)); + SetAppDataDirectory(FMD_DIRECTORY); end; procedure doFinalization; diff --git a/baseunits/SimpleTranslator.pas b/baseunits/SimpleTranslator.pas index bd7cec87a..cd9bd514e 100644 --- a/baseunits/SimpleTranslator.pas +++ b/baseunits/SimpleTranslator.pas @@ -556,7 +556,7 @@ procedure CollectLanguagesFiles(const appname: string; const dir: string; tdir := LangDir else begin - tdir := CleanAndExpandDirectory(GetCurrentDirUTF8); + tdir := ExtractFilePath(Application.ExeName); lauto := True; end; end; @@ -647,7 +647,7 @@ function TranslateLCL(Lang: string): Boolean; procedure FindLCLFile; var i: Integer; - s: string; + l, s: string; begin if LangDir <> '' then begin @@ -665,9 +665,10 @@ function TranslateLCL(Lang: string): Boolean; end; if lcllangpath = '' then begin + l := ExtractFilePath(Application.ExeName); for i := Low(ldir) to High(ldir) do begin - lcllangdir := GetCurrentDirUTF8 + PathDelim + ldir[i]; + lcllangdir := l + ldir[i]; s := lcllangdir + 'lclstrconsts.' + lcllang; if FileExistsUTF8(s + '.po') then begin diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8d2716e93..196eee99a 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5441,7 +5441,7 @@ procedure TMainForm.CollectLanguagesFromFiles; i: Integer; begin cbLanguages.Items.Clear; - SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; + SimpleTranslator.LangDir := FMD_DIRECTORY + 'languages'; SimpleTranslator.LangAppName := 'fmd'; SimpleTranslator.CollectLanguagesFiles; if SimpleTranslator.AvailableLanguages.Count > 0 then diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 585616ac5..b9cf6e5d1 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -81,7 +81,8 @@ s.Free; end; end; - sqlite3dyn.SQLiteDefaultLibrary := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'sqlite3.dll'; + if FileExists(FMD_DIRECTORY + 'sqlite3.dll') then + sqlite3dyn.SQLiteDefaultLibrary := FMD_DIRECTORY + 'sqlite3.dll'; Application.Initialize; Application.CreateForm(TMainForm, MainForm); Application.Run; From 9473f98a96b33c1fecb79493387c8099dc008ae6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Jan 2018 01:33:57 +0800 Subject: [PATCH 1949/2794] fixed sort column with vtv5 --- mangadownloader/forms/frmCustomColor.pas | 2 ++ mangadownloader/forms/frmMain.pas | 30 +++++++++++++++++++ .../forms/frmWebsiteOptionAdvanced.pas | 16 +++++++++- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index fe3658753..875d6a74d 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -486,7 +486,9 @@ procedure TVTApplyList.InstallCustomColors(Index: Integer); Color := clWindow; LineStyle:=lsDotted; Header.Options:=Header.Options+[hoHotTrack]; + {$if VTMajorVersion < 5} TreeOptions.PaintOptions:=TreeOptions.PaintOptions+[toUseExplorerTheme,toHotTrack]; + {$endif} // save original event PaintText := OnPaintText; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 196eee99a..54dd8ac1f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -566,8 +566,12 @@ TMainForm = class(TForm) var Ghosted: Boolean; var ImageIndex: Integer); procedure vtDownloadGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + {$if VTMajorVersion < 5} procedure vtDownloadHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + {$else} + procedure vtDownloadHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + {$endif} procedure vtDownloadKeyAction(Sender: TBaseVirtualTree; var CharCode: Word; var Shift: TShiftState; var DoDefault: Boolean); procedure vtDownloadKeyDown(Sender : TObject; var Key : Word; @@ -594,8 +598,12 @@ TMainForm = class(TForm) var Ghosted: Boolean; var ImageIndex: Integer); procedure vtFavoritesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + {$if VTMajorVersion < 5} procedure vtFavoritesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + {$else} + procedure vtFavoritesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + {$endif} procedure vtFavoritesPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); @@ -3955,10 +3963,21 @@ procedure TMainForm.vtDownloadGetText(Sender: TBaseVirtualTree; end; end; +{$if VTMajorVersion < 5} procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ); +{$else} +procedure TMainForm.vtDownloadHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +var + Column: TColumnIndex; + Button: TMouseButton; +{$endif} begin + {$if VTMajorVersion >= 5} + Column := HitInfo.Column; + Button := HitInfo.Button; + {$endif} if Button <> mbLeft then Exit; if (Column = 2) or (Column = 3) then Exit; if DLManager.SortColumn = Column then @@ -4136,10 +4155,21 @@ procedure TMainForm.vtFavoritesGetText(Sender: TBaseVirtualTree; end; end; +{$if VTMajorVersion < 5} procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ); +{$else} +procedure TMainForm.vtFavoritesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +var + Column: TColumnIndex; + Button: TMouseButton; +{$endif} begin + {$if VTMajorVersion >= 5} + Column := HitInfo.Column; + Button := HitInfo.Button; + {$endif} if Button <> mbLeft then Exit; if FavoriteManager.isRunning then Exit; if Column = 0 then Exit; diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 9eee0976c..138ebec89 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -55,8 +55,12 @@ TWebsiteOptionAdvancedForm = class(TForm) var NodeDataSize: Integer); procedure vtCookiesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + {$if VTMajorVersion < 5} procedure vtCookiesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + {$else} + procedure vtCookiesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + {$endif} procedure vtCookiesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure vtCookiesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; const NewText: String); @@ -183,9 +187,19 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesGetText(Sender: TBaseVirtualTree; end; end; +{$if VTMajorVersion < 5} procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; - Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer + ); +{$else} +procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +var + Column: TColumnIndex; +{$endif} begin + {$if VTMajorVersion >= 5} + Column := HitInfo.Column; + {$endif} Sender.SortColumn := Column; if Sender.SortDirection = sdAscending then Sender.SortDirection := sdDescending From 7738999a228be9528a009ee6c3ec7d22cd25a59d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Jan 2018 03:05:15 +0800 Subject: [PATCH 1950/2794] initial add transfer favorites --- mangadownloader/forms/frmMain.lfm | 4 + mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 25 +- .../forms/frmTransferFavorites.lfm | 231 ++++++++++++++++++ .../forms/frmTransferFavorites.lrj | 12 + .../forms/frmTransferFavorites.pas | 110 +++++++++ mangadownloader/languages/fmd.de.po | 66 +++++ mangadownloader/languages/fmd.el_GR.po | 66 +++++ mangadownloader/languages/fmd.en.po | 67 +++++ mangadownloader/languages/fmd.es.po | 66 +++++ mangadownloader/languages/fmd.id_ID.po | 67 +++++ mangadownloader/languages/fmd.pl_PL.po | 66 +++++ mangadownloader/languages/fmd.po | 60 +++++ mangadownloader/languages/fmd.pt_BR.po | 66 +++++ mangadownloader/languages/fmd.ru_RU.po | 66 +++++ mangadownloader/md.lpi | 9 +- 16 files changed, 980 insertions(+), 2 deletions(-) create mode 100644 mangadownloader/forms/frmTransferFavorites.lfm create mode 100644 mangadownloader/forms/frmTransferFavorites.lrj create mode 100644 mangadownloader/forms/frmTransferFavorites.pas diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index cc72a022f..20813250a 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -5235,6 +5235,10 @@ object MainForm: TMainForm ImageIndex = 1 OnClick = miFavoritesDownloadAllClick end + object miTransferWebsite: TMenuItem + Caption = 'Transfer website' + OnClick = miTransferWebsiteClick + end object MenuItem7: TMenuItem Caption = '-' end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 4b5d16190..347a89980 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -273,6 +273,7 @@ {"hash":185170277,"name":"tmainform.mifavoritesdisable.caption","sourcebytes":[68,105,115,97,98,108,101],"value":"Disable"}, {"hash":27371647,"name":"tmainform.mifavoritesviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, {"hash":29393692,"name":"tmainform.mifavoritesdownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, +{"hash":136379477,"name":"tmainform.mitransferwebsite.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,119,101,98,115,105,116,101],"value":"Transfer website"}, {"hash":78392485,"name":"tmainform.mifavoritesdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":94036626,"name":"tmainform.mifavoriteschangecurrentchapter.caption","sourcebytes":[67,104,97,110,103,101,32,34,67,117,114,114,101,110,116,32,99,104,97,112,116,101,114,34],"value":"Change \"Current chapter\""}, {"hash":202687490,"name":"tmainform.mifavoriteschangesaveto.caption","sourcebytes":[67,104,97,110,103,101,32,34,83,97,118,101,32,116,111,34],"value":"Change \"Save to\""}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 54dd8ac1f..98c265825 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, frmWebsiteOptionAdvanced, - frmCustomColor, frmLogger, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, + frmCustomColor, frmLogger, frmTransferFavorites, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, SimpleException; type @@ -90,6 +90,7 @@ TMainForm = class(TForm) lbOptionMangaCustomRename: TLabel; MenuItem10: TMenuItem; MenuItem11: TMenuItem; + miTransferWebsite: TMenuItem; miFavoritesEnable: TMenuItem; miFavoritesDisable: TMenuItem; miChapterListDescending: TMenuItem; @@ -463,6 +464,7 @@ TMainForm = class(TForm) procedure FormWindowStateChange(Sender: TObject); procedure miChapterListAscendingClick(Sender: TObject); procedure miFavoritesEnableClick(Sender: TObject); + procedure miTransferWebsiteClick(Sender: TObject); procedure tmAnimateMangaInfoTimer(Sender: TObject); procedure tmCheckFavoritesTimer(Sender: TObject); procedure tmExitCommandTimer(Sender: TObject); @@ -1500,6 +1502,24 @@ procedure TMainForm.miFavoritesEnableClick(Sender: TObject); UpdateVtFavorites; end; +procedure TMainForm.miTransferWebsiteClick(Sender: TObject); +var + Node: PVirtualNode; +begin + with TTransferFavoritesForm.Create(nil) do + try + Node := vtFavorites.GetFirstSelected(); + while Assigned(Node) do + begin + Favs.Add(FavoriteManager.Items[Node^.Index]); + Node := vtFavorites.GetNextSelected(Node); + end; + ShowModal; + finally + Free; + end; +end; + procedure TMainForm.tmAnimateMangaInfoTimer(Sender: TObject); begin gifWaiting.Update(pbWait.Canvas, gifWaitingRect); @@ -3494,6 +3514,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesChangeSaveTo.Enabled := False; miFavoritesOpenFolder.Enabled := False; miFavoritesOpenWith.Enabled := False; + miTransferWebsite.Enabled := False; end else begin @@ -3502,6 +3523,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesStopCheckNewChapter.Enabled := iStop; miFavoritesEnable.Enabled := iEnable; miFavoritesDisable.Enabled := iDisable; + miTransferWebsite.Enabled := True; if vtFavorites.SelectedCount = 1 then begin miFavoritesViewInfos.Enabled := True; @@ -3525,6 +3547,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); begin miFavoritesDelete.Enabled := False; miFavoritesChangeSaveTo.Enabled := False; + miTransferWebsite.Enabled := False; end; end; diff --git a/mangadownloader/forms/frmTransferFavorites.lfm b/mangadownloader/forms/frmTransferFavorites.lfm new file mode 100644 index 000000000..a6d008863 --- /dev/null +++ b/mangadownloader/forms/frmTransferFavorites.lfm @@ -0,0 +1,231 @@ +object TransferFavoritesForm: TTransferFavoritesForm + Left = 299 + Height = 320 + Top = 250 + Width = 491 + Caption = 'Transfer Favorites' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.TopBottomSpacing = 6 + ChildSizing.HorizontalSpacing = 4 + ChildSizing.VerticalSpacing = 4 + ClientHeight = 320 + ClientWidth = 491 + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + Position = poMainFormCenter + object cbWebsites: TComboBox + AnchorSideLeft.Control = lbTransferTo + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbTransferTo + AnchorSideTop.Side = asrCenter + Left = 66 + Height = 23 + Top = 8 + Width = 164 + AutoComplete = True + AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchAscending] + ItemHeight = 15 + OnChange = cbWebsitesChange + TabOrder = 0 + end + object lbTransferTo: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Left = 6 + Height = 15 + Top = 12 + Width = 56 + BorderSpacing.Top = 12 + Caption = 'Transfer to' + ParentColor = False + end + object vtFavs: TVirtualStringTree + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = rbAll + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btOK + Left = 6 + Height = 203 + Top = 81 + Width = 479 + Anchors = [akTop, akLeft, akRight, akBottom] + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Width = 20 + end + item + Position = 1 + Text = 'Title' + Width = 300 + end + item + Position = 2 + Text = 'Website' + Width = 150 + end> + Header.DefaultHeight = 17 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + TabOrder = 1 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect] + WantTabs = True + OnGetText = vtFavsGetText + end + object btOK: TBitBtn + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 423 + Height = 26 + Top = 288 + Width = 62 + Anchors = [akRight, akBottom] + AutoSize = True + Caption = 'OK' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 00010000000800000010000000170000001A0000001900000017000000150000 + 00110000000D0000000A000000060000000300000001FFFFFF00FFFFFF000000 + 00020000000F0000001F0000002D02330066025F00CC012B0055000000290000 + 00220000001A000000130000000C0000000600000001FFFFFF00FFFFFF000000 + 0000000000000320000006570048077200CC16A60AE8087601C406570029021E + 00000000000000000000000000000000000000000000FFFFFF00FFFFFF000747 + 00000A6500000B8300480B8200CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85 + 001B0745000000000000000000000000000000000000FFFFFF00FFFFFF000E8D + 00000D8800480D8700CC43CA33F629C318FF39CC28FF28C217FF1EAA0FEA0D87 + 00AE0D8A00100F8F0000084A00000000000000000000FFFFFF00FFFFFF000E8E + 00480E8D00CC5FD94FF933BC22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA2 + 0FE40E8D009E0F8F00081094000010950000084B0000FFFFFF00FFFFFF000F92 + 00CC6DE55CFA59D048FF69E158FC0F9200CC0F92006D139504CB34B423F832B2 + 21FF1F9F0FDF0F92008C109400021095000010950000FFFFFF00FFFFFF001196 + 0048119700CC73EA62FD119700CC119600480F9300001196004C189D08D33DB6 + 2CFB37AF26FE1FA00EDA1197007B11980000129B0000FFFFFF00FFFFFF001197 + 0000129B0048129B00CC129B0048119700000F93000011970000129B006924AA + 13D857CF46FE55CD44FD21A710D6129C006313A00000FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000113A0 + 008533B820DE61D850FF5CD54BFA1EA80CD213A1004CFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000614A3009E43C631E56BE25AFF70E95FFB14A300CCFFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000011990000129F0000129F000013A2 + 000014A5001014A700B077EE66FF14A700CC14A70048FFFFFF00FFFFFF001197 + 0000129B0000129C0000129B00001197000013A2000014A5000014A5000014A6 + 000015A8000015A9001F15AA00CC15AA004814A70000FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btOKClick + TabOrder = 2 + end + object btCancel: TBitBtn + AnchorSideTop.Control = btOK + AnchorSideRight.Control = btOK + Left = 337 + Height = 26 + Top = 288 + Width = 82 + Anchors = [akTop, akRight] + AutoSize = True + Caption = 'Cancel' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000013000000190000001900000016000000120000000F0000000E0000 + 0011000000150000001900000019000000140000000EFFFFFF00FFFFFF000000 + 001C000000260000346400005FCC00003561000000240000001D0000001B0000 + 00210000366000005FCC00003464000000270000001CFFFFFF00FFFFFF000000 + 1E0000005748000072CC1111D8FF000072CC0000574800002000000020000000 + 5748000072CC1111D8FF000072CC0000574800001E00FFFFFF00FFFFFF000000 + 8200000082CC1111D0FF1111D0FF1111D0FF000082CC00008348000083480000 + 82CC1111D0FF1111D0FF1111D0FF000082CC00008200FFFFFF00FFFFFF000000 + 860000008748000087CC1111C4FF1111C4FF1111C4FF000087CC000087CC1111 + C4FF1111C4FF1111C4FF000087CC0000874800008600FFFFFF00FFFFFF000000 + 86000000870000008C4800008DCC1111B8FF1111B8FF1111B8FF1111B8FF1111 + B8FF1111B8FF00008DCC00008C480000870000008600FFFFFF00FFFFFF000000 + 86000000870000008D0000009148000092CC1515AFFF1111ACFF1111ACFF1111 + ACFF000092CC0000914800008D000000870000008600FFFFFF00FFFFFF000000 + A1000000A00000009B0000009848000097CC2525B4FF1111A2FF1111A2FF1414 + A5FF000097CC0000984800009B000000A0000000A100FFFFFF00FFFFFF000000 + A1000000A00000009C4800009BCC5353DBFF2E2EB7FF3D3DC6FF3131BAFF1515 + 9FFF1E1EA8FF00009BCC00009C480000A0000000A100FFFFFF00FFFFFF000000 + A1000000A1480000A0CC6767EFFF3636BEFF5E5EE6FF0000A0CC0000A0CC4F4F + D7FF3636BEFF4545CDFF0000A0CC0000A1480000A100FFFFFF00FFFFFF000000 + A3000000A3CC7676FEFF4C4CD4FF7272FAFF0000A3CC0000A3480000A3480000 + A3CC6262EAFF4C4CD4FF5C5CE4FF0000A3CC0000A300FFFFFF00FFFFFF000000 + A6000000A7480000A7CC7777FFFF0000A7CC0000A7480000A3000000A3000000 + A7480000A7CC7070F8FF0000A7CC0000A7480000A600FFFFFF00FFFFFF000000 + A6000000A7000000AA480000AACC0000AA480000A7000000A3000000A3000000 + A7000000AA480000AACC0000AA480000A7000000A600FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btCancelClick + TabOrder = 3 + end + object rbAll: TRadioButton + AnchorSideLeft.Control = ckClearDownloadedChapters + AnchorSideTop.Control = ckClearDownloadedChapters + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 19 + Top = 58 + Width = 34 + Caption = 'All' + Checked = True + TabOrder = 6 + TabStop = True + end + object rbValid: TRadioButton + AnchorSideLeft.Control = rbAll + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = rbAll + Left = 48 + Height = 19 + Top = 58 + Width = 46 + BorderSpacing.Left = 8 + Caption = 'Valid' + TabOrder = 4 + end + object rbInvalid: TRadioButton + AnchorSideLeft.Control = rbValid + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = rbValid + Left = 102 + Height = 19 + Top = 58 + Width = 55 + BorderSpacing.Left = 8 + Caption = 'Invalid' + TabOrder = 5 + end + object ckClearDownloadedChapters: TCheckBox + AnchorSideLeft.Control = lbTransferTo + AnchorSideTop.Control = lbTransferTo + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 19 + Top = 35 + Width = 299 + BorderSpacing.Top = 8 + Caption = 'Clear downloaded chapter list and reload from server' + Checked = True + State = cbChecked + TabOrder = 7 + end +end diff --git a/mangadownloader/forms/frmTransferFavorites.lrj b/mangadownloader/forms/frmTransferFavorites.lrj new file mode 100644 index 000000000..f2fd03e3f --- /dev/null +++ b/mangadownloader/forms/frmTransferFavorites.lrj @@ -0,0 +1,12 @@ +{"version":1,"strings":[ +{"hash":102089683,"name":"ttransferfavoritesform.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,70,97,118,111,114,105,116,101,115],"value":"Transfer Favorites"}, +{"hash":160944127,"name":"ttransferfavoritesform.lbtransferto.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,116,111],"value":"Transfer to"}, +{"hash":5966629,"name":"ttransferfavoritesform.vtfavs.header.columns[1].text","sourcebytes":[84,105,116,108,101],"value":"Title"}, +{"hash":230269173,"name":"ttransferfavoritesform.vtfavs.header.columns[2].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":1339,"name":"ttransferfavoritesform.btok.caption","sourcebytes":[79,75],"value":"OK"}, +{"hash":77089212,"name":"ttransferfavoritesform.btcancel.caption","sourcebytes":[67,97,110,99,101,108],"value":"Cancel"}, +{"hash":18476,"name":"ttransferfavoritesform.rball.caption","sourcebytes":[65,108,108],"value":"All"}, +{"hash":6062836,"name":"ttransferfavoritesform.rbvalid.caption","sourcebytes":[86,97,108,105,100],"value":"Valid"}, +{"hash":6062756,"name":"ttransferfavoritesform.rbinvalid.caption","sourcebytes":[73,110,118,97,108,105,100],"value":"Invalid"}, +{"hash":231329170,"name":"ttransferfavoritesform.ckcleardownloadedchapters.caption","sourcebytes":[67,108,101,97,114,32,100,111,119,110,108,111,97,100,101,100,32,99,104,97,112,116,101,114,32,108,105,115,116,32,97,110,100,32,114,101,108,111,97,100,32,102,114,111,109,32,115,101,114,118,101,114],"value":"Clear downloaded chapter list and reload from server"} +]} diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas new file mode 100644 index 000000000..3a63019d1 --- /dev/null +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -0,0 +1,110 @@ +unit frmTransferFavorites; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, Menus, + VirtualTrees, uFavoritesManager, DBDataProcess; + +type + + { TTransferFavoritesForm } + + TTransferFavoritesForm = class(TForm) + btOK: TBitBtn; + btCancel: TBitBtn; + cbWebsites: TComboBox; + ckClearDownloadedChapters: TCheckBox; + lbTransferTo: TLabel; + rbAll: TRadioButton; + rbValid: TRadioButton; + rbInvalid: TRadioButton; + vtFavs: TVirtualStringTree; + procedure btCancelClick(Sender: TObject); + procedure btOKClick(Sender: TObject); + procedure cbWebsitesChange(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure vtFavsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String + ); + private + procedure SearchDBForMatchTitle; + public + Favs: TFavoriteContainers; + DB: TDBDataProcess; + end; + +var + TransferFavoritesForm: TTransferFavoritesForm; + +implementation + +uses + FMDVars, FMDOptions, frmCustomColor; + +{$R *.lfm} + +{ TTransferFavoritesForm } + +procedure TTransferFavoritesForm.FormCreate(Sender: TObject); +begin + Favs := TFavoriteContainers.Create; + DB := TDBDataProcess.Create; + AddVT(vtFavs); + cbWebsites.Items.Text := FormMain.cbSelectManga.Items.Text; +end; + +procedure TTransferFavoritesForm.btOKClick(Sender: TObject); +begin + Close; +end; + +procedure TTransferFavoritesForm.cbWebsitesChange(Sender: TObject); +begin + if not FileExists(DATA_FOLDER + cbWebsites.Text + DBDATA_EXT) then + Exit; + if DB.Open(cbWebsites.Text) then + SearchDBForMatchTitle; +end; + +procedure TTransferFavoritesForm.btCancelClick(Sender: TObject); +begin + Close; +end; + +procedure TTransferFavoritesForm.FormDestroy(Sender: TObject); +begin + Favs.Free; + DB.Free; +end; + +procedure TTransferFavoritesForm.FormShow(Sender: TObject); +begin + vtFavs.RootNodeCount := Favs.Count; +end; + +procedure TTransferFavoritesForm.vtFavsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +begin + case Column of + 1: CellText := Favs.Items[Node^.Index].FavoriteInfo.Title; + 2: CellText := Favs.Items[Node^.Index].FavoriteInfo.Website; + end; +end; + +procedure TTransferFavoritesForm.SearchDBForMatchTitle; +var + i: Integer; +begin + if DB.RecordCount = 0 then Exit; + for i := 0 to Favs.Count - 1 do + begin + //if DB.Table.Locate('title', Favs.Items[i].FavoriteInfo.Title); + end; +end; + +end. + diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 575115054..33421545c 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -74,6 +74,7 @@ msgid "Checking" msgstr "Prüfen" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Ungültig" @@ -466,6 +467,15 @@ msgstr "Favoritenliste" msgid "Manga list" msgstr "Mangaliste" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1669,6 +1679,10 @@ msgstr "Alles laden" msgid "View manga infos" msgstr "Zeige Manga-Informationen" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "After download finish" @@ -1974,6 +1988,58 @@ msgstr "&Abbrechen" msgid "&Now" msgstr "&Jetzt" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Abbrechen" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Ungültig" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Webseite" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Webseite" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Später" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 04a60cf8d..dc5cb74bf 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -78,6 +78,7 @@ msgid "Checking" msgstr "Έλεγχος" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Μη έγκυρο" @@ -470,6 +471,15 @@ msgstr "Λίστα αγαπημένων" msgid "Manga list" msgstr "Λίστα Manga" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1724,6 +1734,10 @@ msgstr "Λήψη όλων" msgid "View manga infos" msgstr "Προβολή πρηροφοριών manga" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Μετά την ολοκλήρωση της λήψης" @@ -2029,6 +2043,58 @@ msgstr "&Ματαίωση" msgid "&Now" msgstr "&Τώρα" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Άκυρο" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "Εντάξει" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Μη έγκυρο" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Ιστότοπος" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Ιστότοπος" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Αργότερα" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index e629f181f..e29dc602c 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -74,6 +74,7 @@ msgid "Checking" msgstr "Checking" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Invalid" @@ -466,6 +467,15 @@ msgstr "Favorite list" msgid "Manga list" msgstr "Manga list" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1668,6 +1678,10 @@ msgstr "Download all" msgid "View manga infos" msgstr "View manga infos" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "After download finish" @@ -1972,6 +1986,58 @@ msgstr "&Abort" msgid "&Now" msgstr "&Now" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Cancel" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Invalid" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Website" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Website" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Later" @@ -2254,3 +2320,4 @@ msgstr "Synchronizing data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Updating list" + diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index a20538e0e..aeee99beb 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -73,6 +73,7 @@ msgid "Checking" msgstr "Revisando" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Inválido" @@ -458,6 +459,15 @@ msgstr "Lista de Favoritos" msgid "Manga list" msgstr "Lista de Manga" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1646,6 +1656,10 @@ msgstr "Descargar Todo" msgid "View manga infos" msgstr "Ver Información del Manga" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Después de Finalizar la Descarga" @@ -1950,6 +1964,58 @@ msgstr "&Abortar" msgid "&Now" msgstr "&Ahora" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Cancelar" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Inválido" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Sitio Web" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Sitio Web" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Después" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 0e4e1aea1..7a5015458 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -73,6 +73,7 @@ msgid "Checking" msgstr "Memeriksa" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Tidak valid" @@ -458,6 +459,15 @@ msgstr "Daftar kesukaan" msgid "Manga list" msgstr "Daftar komik" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1646,6 +1656,10 @@ msgstr "Unduh semua" msgid "View manga infos" msgstr "Lihat informasi komik" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Setelah download selesai" @@ -1950,6 +1964,58 @@ msgstr "&Batalkan" msgid "&Now" msgstr "&Sekarang" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Batal" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Tidak valid" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Situs web" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Situs web" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Nanti saja" @@ -2232,3 +2298,4 @@ msgstr "Sinkronisasi data" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Memperbarui daftar" + diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 16b95caf9..3b240cc64 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -69,6 +69,7 @@ msgid "Checking" msgstr "Sprawdzanie" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Niepoprawnie" @@ -461,6 +462,15 @@ msgstr "Lista ulubionych" msgid "Manga list" msgstr "Lista mang" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1665,6 +1675,10 @@ msgstr "Pobierz wszystko" msgid "View manga infos" msgstr "Zobacz informacje o mandze" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Po pobieraniu zakończ" @@ -1971,6 +1985,58 @@ msgstr "&O" msgid "&Now" msgstr "&Teraz" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Anuluj" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Niepoprawnie" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Strona WWW" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Strona WWW" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&później" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 0c770d22c..bc483cce8 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -50,6 +50,7 @@ msgid "Checking" msgstr "" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "" @@ -418,6 +419,15 @@ msgstr "" msgid "Manga list" msgstr "" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" @@ -1572,6 +1582,10 @@ msgstr "" msgid "View manga infos" msgstr "" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "" @@ -1876,6 +1890,52 @@ msgstr "" msgid "&Now" msgstr "" +#: ttransferfavoritesform.btcancel.caption +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "" + +#: ttransferfavoritesform.btok.caption +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index d0c67aeef..bf86f04d3 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -74,6 +74,7 @@ msgid "Checking" msgstr "Checando" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Inválido" @@ -466,6 +467,15 @@ msgstr "Lista de favoritos" msgid "Manga list" msgstr "Lista de mangás" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1667,6 +1677,10 @@ msgstr "Baixar tudo" msgid "View manga infos" msgstr "Exibir infos do mangá" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Depois do download terminar" @@ -1971,6 +1985,58 @@ msgstr "&Abortar" msgid "&Now" msgstr "&Agora" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Cancelar" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Inválido" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Website" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Website" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "&Depois" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 20c3d9c7c..bc395ae94 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -72,6 +72,7 @@ msgid "Checking" msgstr "Проверка" #: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" msgid "Invalid" msgstr "Неверный" @@ -457,6 +458,15 @@ msgstr "Список избранного" msgid "Manga list" msgstr "Список манги" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" @@ -1649,6 +1659,10 @@ msgstr "Загрузить все" msgid "View manga infos" msgstr "Информация о манге" +#: tmainform.mitransferwebsite.caption +msgid "Transfer website" +msgstr "" + #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "После завершения загрузки:" @@ -1954,6 +1968,58 @@ msgstr "Прервать" msgid "&Now" msgstr "Сейчас" +#: ttransferfavoritesform.btcancel.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "Отмена" + +#: ttransferfavoritesform.btok.caption +#, fuzzy +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "OK" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "" + +#: ttransferfavoritesform.rball.caption +msgid "All" +msgstr "" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Неверный" + +#: ttransferfavoritesform.rbvalid.caption +msgid "Valid" +msgstr "" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +#, fuzzy +#| msgid "Website" +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Сайт" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +#, fuzzy +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Сайт" + #: tupdatedialogform.btnlater.caption msgid "&Later" msgstr "Позже" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index cdec25c1b..d50697ef3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -310,7 +310,7 @@ <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item9> </RequiredPackages> - <Units Count="14"> + <Units Count="15"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -405,6 +405,13 @@ <ComponentName Value="SelectDirectoryForm"/> <ResourceBaseClass Value="Form"/> </Unit13> + <Unit14> + <Filename Value="forms\frmTransferFavorites.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="TransferFavoritesForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit14> </Units> </ProjectOptions> <CompilerOptions> From 5713c420c3f8fda8ac4b11e9aef956bd9ab6862a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 18 Jan 2018 10:18:50 +0800 Subject: [PATCH 1951/2794] transferfavorites, implement find match title #826 --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 2 +- .../forms/frmTransferFavorites.lfm | 142 ++++++++++- .../forms/frmTransferFavorites.pas | 238 ++++++++++++++++-- mangadownloader/languages/fmd.de.po | 18 ++ mangadownloader/languages/fmd.el_GR.po | 18 ++ mangadownloader/languages/fmd.en.po | 18 ++ mangadownloader/languages/fmd.es.po | 18 ++ mangadownloader/languages/fmd.id_ID.po | 18 ++ mangadownloader/languages/fmd.pl_PL.po | 18 ++ mangadownloader/languages/fmd.po | 17 ++ mangadownloader/languages/fmd.pt_BR.po | 18 ++ mangadownloader/languages/fmd.ru_RU.po | 18 ++ 13 files changed, 508 insertions(+), 36 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 20813250a..db9deaf73 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,6 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True + LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 98c265825..9608248f7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1511,7 +1511,7 @@ procedure TMainForm.miTransferWebsiteClick(Sender: TObject); Node := vtFavorites.GetFirstSelected(); while Assigned(Node) do begin - Favs.Add(FavoriteManager.Items[Node^.Index]); + AddFav(FavoriteManager.Items[Node^.Index]); Node := vtFavorites.GetNextSelected(Node); end; ShowModal; diff --git a/mangadownloader/forms/frmTransferFavorites.lfm b/mangadownloader/forms/frmTransferFavorites.lfm index a6d008863..d4d5ef0f0 100644 --- a/mangadownloader/forms/frmTransferFavorites.lfm +++ b/mangadownloader/forms/frmTransferFavorites.lfm @@ -1,17 +1,16 @@ object TransferFavoritesForm: TTransferFavoritesForm Left = 299 - Height = 320 + Height = 490 Top = 250 - Width = 491 + Width = 490 Caption = 'Transfer Favorites' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 320 - ClientWidth = 491 + ClientHeight = 490 + ClientWidth = 490 OnCreate = FormCreate - OnDestroy = FormDestroy OnShow = FormShow Position = poMainFormCenter object cbWebsites: TComboBox @@ -48,11 +47,10 @@ object TransferFavoritesForm: TTransferFavoritesForm AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = btOK Left = 6 - Height = 203 + Height = 373 Top = 81 - Width = 479 + Width = 478 Anchors = [akTop, akLeft, akRight, akBottom] - DefaultText = 'Node' Header.AutoSizeIndex = 0 Header.Columns = < item @@ -71,20 +69,24 @@ object TransferFavoritesForm: TTransferFavoritesForm end> Header.DefaultHeight = 17 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + Images = imgsState TabOrder = 1 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect] WantTabs = True + OnFreeNode = vtFavsFreeNode OnGetText = vtFavsGetText + OnGetImageIndex = vtFavsGetImageIndex + OnGetNodeDataSize = vtFavsGetNodeDataSize end object btOK: TBitBtn AnchorSideRight.Control = Owner AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = Owner AnchorSideBottom.Side = asrBottom - Left = 423 + Left = 422 Height = 26 - Top = 288 + Top = 458 Width = 62 Anchors = [akRight, akBottom] AutoSize = True @@ -131,9 +133,9 @@ object TransferFavoritesForm: TTransferFavoritesForm object btCancel: TBitBtn AnchorSideTop.Control = btOK AnchorSideRight.Control = btOK - Left = 337 + Left = 336 Height = 26 - Top = 288 + Top = 458 Width = 82 Anchors = [akTop, akRight] AutoSize = True @@ -187,6 +189,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Width = 34 Caption = 'All' Checked = True + OnChange = rbAllChange TabOrder = 6 TabStop = True end @@ -200,6 +203,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Width = 46 BorderSpacing.Left = 8 Caption = 'Valid' + OnChange = rbAllChange TabOrder = 4 end object rbInvalid: TRadioButton @@ -212,6 +216,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Width = 55 BorderSpacing.Left = 8 Caption = 'Invalid' + OnChange = rbAllChange TabOrder = 5 end object ckClearDownloadedChapters: TCheckBox @@ -228,4 +233,117 @@ object TransferFavoritesForm: TTransferFavoritesForm State = cbChecked TabOrder = 7 end + object imgState: TImage + AnchorSideLeft.Control = cbWebsites + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cbWebsites + AnchorSideTop.Side = asrCenter + Left = 234 + Height = 16 + Top = 11 + Width = 16 + end + object imgsState: TImageList + left = 326 + top = 32 + Bitmap = { + 4C690300000010000000100000001975BA001975BA001770B7900B56A4C60142 + 96CC003F94CC002A80CC00166BCC021C70CB072D7DC80D4390C51259A3C1176C + B290186FB500186FB500FFFFFF0098763200987632009876325BF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29876 + 325B9876320098763200FFFFFF0097753100977531009775315CF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29775 + 315C9775310097753100FFFFFF0096743000967430009674305DF5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD29674 + 305D9674300096743000FFFFFF0095732F0095732F0095732F5FF8F0E9DCCCCB + C3CE86BBD4FAB0D2E2FC629FBEF95492B0F95391AFF9C7C6BDCEF7EEE5DC9573 + 2F5F95732F0095732F00FFFFFF0094722E0094722E0094722E3094722E60F1E3 + D5D2DCDBD6D2B4D4E3FA69A3BFF65C96B1F6C4C3BBCEF1E2D3D394722E609472 + 2E3094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D319371 + 2D62F7EDE4D7E8EBEAE391B5C5E2D1CDC4C9F1E3D5D293712D6293712D319472 + 2E0094722E0094722E00FFFFFF0094722E0094722E0094722E0093712D00916F + 2B32916F2B63F9F2ECDBF0E1D1BDF4E7DBD1916F2B63916F2B3293712D009472 + 2E0094722E0094722E00FFFFFF008C6A26008C6A26008D6B27008E6C2800906E + 2A33906E2A65F9F2ECDBF0E1D1BDF4E7DBD1906E2A65906E2A338E6C28008D6B + 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27008E6C28348E6C + 2867F7EDE4D7F9F2ECDBF0E1D1BDEDDAC8BEF1E3D5D28E6C28678E6C28348D6B + 27008C6A26008C6A2600FFFFFF008C6A26008C6A26008D6B27358D6B2769F1E3 + D5D2F3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFF1E2D3D38D6B27698D6B + 27358C6A26008C6A2600FFFFFF008B6925008B6925008B69256AF8F0E9DCEAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F7EEE5DC8B69 + 256A8B6925008B692500FFFFFF00674E1B00896723008967236CF5EAE0D276AF + CBF68CBDD5F7B4D4E3FA69A3BFF65C96B1F65B95B0F66BA4BFF6F3E7DBD28967 + 236C89672300674E1B00FFFFFF0000000000654B180085631F70F5EAE0D299BB + C7E3ABCAD6E7CADEE6EF91B5C5E287AAB8E386A8B5E391B3BFE3F3E7DBD28563 + 1F70654B180000000000FFFFFF000000000A000000177F5D1977F5EAE0D2EAD4 + BFBFF3E5D8C8F9F2ECDBF0E1D1BDEDDAC8BEEAD5C0BFE9D3BDC0F3E7DBD27F5D + 1977000000170000000AFFFFFF00000000000000002D002C6CA600277CCC0016 + 6BCC001569CC000955CC000041CC000546CC001155CC001F68CC002E7CCC002B + 69A60000002E00000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0013A2000014A5000014A8000015A9 + 001A15AA006C15AA00A615AA00C415AA00C415AA00A615AA006C15A9001A14A8 + 000014A5000013A20000FFFFFF00FFFFFF0013A2000014A5000014A8004D1BAD + 08BF42C82FE35FDC4EF56BE35AFD6BE359FD5FDB4EF541C72EE31BAD07BF14A8 + 004D14A5000013A20000FFFFFF00FFFFFF0013A2000014A5004D21AF0ECD5FDA + 4EF663DA52FF5FD64EFF5FD64EFF5FD64EFF5FD64EFF62D951FF5DD94BF620AE + 0DCD14A5004D13A20000FFFFFF00FFFFFF0013A1001A1AA707BF5CD74BF658CF + 47FF57CE46FF57CE46FF57CE46FF57CE46FF57CE46FF4AC139FF52C941FF57D2 + 45F619A606BF13A1001AFFFFFF00FFFFFF00129E006C3DBF2CE354CB43FF4EC5 + 3DFF4EC53DFF4EC53DFF4EC53DFF4EC53DFF44BB33FFFFFFFFFFA7E29EFF52C9 + 41FF36B925E3129E006CFFFFFF00FFFFFF00119A00A751CB40F547BE36FF3EB5 + 2DFF47BE36FF41B930FF37AF26FF2DA41CFFE2E2E2FFE3E3E3FFE7E7E7FF269E + 15FF34B023F5119A00A7FFFFFF00FFFFFF00109600C453CB42FD3CB32BFFF8F8 + F8FF2DA81CFF23A212FF229F11FFDEDEDEFFE2E2E2FFE6E6E6FF229E11FF22A1 + 11FF2CAA1BFD109600C4FFFFFF00FFFFFF000F9200C450C83FFDA9D7A2FFD5D5 + D5FFEBEBEBFF22A511FFDEDEDEFFE2E2E2FFE6E6E6FF22A311FF22AA11FF22AA + 11FF28AE17FD0F9200C4FFFFFF00FFFFFF000E8D00A73BBD2BF523AE12FFD5D5 + D5FFDADADAFFDEDEDEFFE2E2E2FFE6E6E6FF22A811FF22B411FF22B411FF22B4 + 11FF21AF11F50E8D00A7FFFFFF00FFFFFF000D89006C22A813E326C015FF22AD + 11FFDEDEDEFFE2E2E2FFE6E6E6FF22AD11FF22BE11FF22BE11FF22BE11FF22BE + 11FF17A109E30D89006CFFFFFF00FFFFFF000C85001A0F8A03BF27C017F623C8 + 12FF22B211FFE6E6E6FF22B211FF22C811FF22C811FF22C811FF22C811FF1FBC + 0FF60D8902BF0C85001AFFFFFF00FFFFFF000B8300000B7F004D0E8804CD21C4 + 11F623D112FF22B611FF22D111FF22D111FF22D111FF22D111FF1EC20FF60D88 + 03CD0B7F004D0B830000FFFFFF00FFFFFF0000000000031F00000553004D0874 + 02BF139D08E31DC40EF521D411FD21D411FD1DC40EF5139D08E3087402BF0553 + 004D031F000000000000FFFFFF00FFFFFF0000000004000000170000002B011A + 004302440080025A00AB025D00C4025D00C4025A00AB02440080011A00430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 + A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 + A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 + AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 + A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B + E8F65F5FE7FF5B5BE3FF5B5BE3FF5B5BE3FF5B5BE3FF5F5FE7FF5858E4F60F0F + B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 + D9FFFFFFFFFF4F4FD7FF4F4FD7FF4F4FD7FF4F4FD7FFFFFFFFFF5050D8FF4F4F + DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FFFFFF + FFFFFFFFFFFFFFFFFFFF4242CAFF4242CAFFFFFFFFFFFFFFFFFFFFFFFFFF4747 + CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF2323 + ABFFFFFFFFFFF7F7F7FFE8E8E8FFDEDEDEFFDBDBDBFFDDDDDDFF11119BFF1616 + A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E + B8FF13139FFFCECECEFFD1D1D1FFD6D6D6FFDCDCDCFF11119EFF1111A1FF1111 + A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 + ABFF1111AAFFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FF1111AAFF1111AAFF1111 + AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 + B4FFD1D1D1FFD6D6D6FFDCDCDCFFE2E2E2FFE6E6E6FFEAEAEAFF1111B4FF1111 + B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FFD1D1 + D1FFD6D6D6FFDCDCDCFF1111ADFF1111ADFFEAEAEAFFEEEEEEFFEEEEEEFF1111 + BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 + B2FFDCDCDCFF1111B2FF1111C8FF1111C8FF1111B2FFEEEEEEFF1111B2FF0F0F + BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 + C4F61212B6FF1111D1FF1111D1FF1111D1FF1111D1FF1111B6FF0F0FC2F60303 + 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 + 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 + 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 + 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00 + } + end end diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas index 3a63019d1..a0422ac4f 100644 --- a/mangadownloader/forms/frmTransferFavorites.pas +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, Menus, + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Buttons, Menus, ExtCtrls, VirtualTrees, uFavoritesManager, DBDataProcess; type @@ -17,6 +17,8 @@ TTransferFavoritesForm = class(TForm) btCancel: TBitBtn; cbWebsites: TComboBox; ckClearDownloadedChapters: TCheckBox; + imgState: TImage; + imgsState: TImageList; lbTransferTo: TLabel; rbAll: TRadioButton; rbValid: TRadioButton; @@ -26,35 +28,168 @@ TTransferFavoritesForm = class(TForm) procedure btOKClick(Sender: TObject); procedure cbWebsitesChange(Sender: TObject); procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); + procedure rbAllChange(Sender: TObject); + procedure vtFavsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vtFavsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure vtFavsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); procedure vtFavsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String ); private - procedure SearchDBForMatchTitle; + FAllCount, + FValidCount, + FInvalidCount: Integer; + FLastFilter: Integer; + procedure UpdateFilterCount; + procedure FilterState(const AState: Integer = 0); + procedure FindMatchTitle; public - Favs: TFavoriteContainers; - DB: TDBDataProcess; + procedure AddFav(const AFav: TFavoriteContainer); + end; + + TFavsContainer = record + Fav: TFavoriteContainer; + NewLink: String; + State: Integer; + end; + + PFavContainer = ^TFavsContainer; + + { TFindMatchDBThread } + + TFindMatchDBThread = class(TThread) + private + FWebsite: String; + procedure SyncBegin; + procedure SyncEnd; + protected + procedure Execute; override; + public + Owner: TTransferFavoritesForm; + constructor Create(AWebsite: String); end; var TransferFavoritesForm: TTransferFavoritesForm; +resourcestring + RS_ALL = 'All'; + RS_Valid = 'Valid'; + RS_Invalid = 'Invalid'; + implementation uses - FMDVars, FMDOptions, frmCustomColor; + FMDVars, FMDOptions, db, frmCustomColor; {$R *.lfm} +{ TFindMatchDBThread } + +procedure TFindMatchDBThread.SyncBegin; +begin + Owner.imgState.Visible := True; + Owner.imgsState.GetBitmap(0,Owner.imgState.Picture.Bitmap); + Owner.cbWebsites.Enabled := False; + Owner.vtFavs.Enabled := False; +end; + +procedure TFindMatchDBThread.SyncEnd; +begin + Owner.imgsState.GetBitmap(1,Owner.imgState.Picture.Bitmap); + Owner.cbWebsites.Enabled := True; + Owner.vtFavs.Enabled := True; + Owner.cbWebsites.SetFocus; + + Owner.UpdateFilterCount; + + if Owner.FLastFilter <> 0 then + begin + Owner.FLastFilter := -1; + Owner.rbAllChange(nil); + end; +end; + +procedure TFindMatchDBThread.Execute; +var + db: TDBDataProcess; + node: PVirtualNode; + data: PFavContainer; +begin + Synchronize(@SyncBegin); + Owner.FValidCount := 0; + Owner.FInvalidCount := 0; + db := TDBDataProcess.Create; + try + if db.Connect(FWebsite) then + begin + db.Table.ReadOnly := True; + node := Owner.vtFavs.GetFirst(); + while Assigned(node) do + begin + data := Owner.vtFavs.GetNodeData(node); + try + db.Table.SQL.Text := 'SELECT link FROM ' + AnsiQuotedStr(db.TableName, '"') + + ' WHERE title LIKE '+AnsiQuotedStr(data^.Fav.FavoriteInfo.Title, '"') + ' COLLATE NOCASE;'; + db.Table.Open; + if db.Table.RecNo > 0 then + begin + Inc(Owner.FValidCount); + data^.NewLink := db.Table.Fields[0].AsString; + data^.State := 1; + end + else + begin + Inc(Owner.FInvalidCount); + data^.NewLink := ''; + data^.State := 2; + end; + db.Table.Close; + except + end; + node := Owner.vtFavs.GetNext(node); + end; + end; + db.Connection.Connected := False; + finally + db.Free; + end; + Synchronize(@SyncEnd); +end; + +constructor TFindMatchDBThread.Create(AWebsite: String); +begin + inherited Create(True); + FreeOnTerminate := True; + FWebsite := AWebsite; +end; + { TTransferFavoritesForm } procedure TTransferFavoritesForm.FormCreate(Sender: TObject); begin - Favs := TFavoriteContainers.Create; - DB := TDBDataProcess.Create; - AddVT(vtFavs); + frmCustomColor.AddVT(vtFavs); cbWebsites.Items.Text := FormMain.cbSelectManga.Items.Text; + FLastFilter := 0; + FAllCount := 0; + FValidCount := 0; + FInvalidCount := 0; +end; + +procedure TTransferFavoritesForm.FormShow(Sender: TObject); +begin + UpdateFilterCount; +end; + +procedure TTransferFavoritesForm.rbAllChange(Sender: TObject); +begin + if rbAll.Checked then + FilterState(0) + else if rbValid.Checked then + FilterState(1) + else if rbInvalid.Checked then + FilterState(2); end; procedure TTransferFavoritesForm.btOKClick(Sender: TObject); @@ -66,8 +201,7 @@ procedure TTransferFavoritesForm.cbWebsitesChange(Sender: TObject); begin if not FileExists(DATA_FOLDER + cbWebsites.Text + DBDATA_EXT) then Exit; - if DB.Open(cbWebsites.Text) then - SearchDBForMatchTitle; + FindMatchTitle; end; procedure TTransferFavoritesForm.btCancelClick(Sender: TObject); @@ -75,36 +209,94 @@ procedure TTransferFavoritesForm.btCancelClick(Sender: TObject); Close; end; -procedure TTransferFavoritesForm.FormDestroy(Sender: TObject); +procedure TTransferFavoritesForm.vtFavsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + Data: PFavContainer; begin - Favs.Free; - DB.Free; + Data := Sender.GetNodeData(Node); + if Assigned(Data) then + Finalize(Data^); end; -procedure TTransferFavoritesForm.FormShow(Sender: TObject); +procedure TTransferFavoritesForm.vtFavsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; + Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + Data: PFavContainer; +begin + if Column <> 0 then Exit; + Data := Sender.GetNodeData(Node); + ImageIndex := Data^.State; +end; + +procedure TTransferFavoritesForm.vtFavsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); begin - vtFavs.RootNodeCount := Favs.Count; + NodeDataSize := SizeOf(TFavsContainer); end; procedure TTransferFavoritesForm.vtFavsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + Data: PFavContainer; begin + Data := Sender.GetNodeData(Node); case Column of - 1: CellText := Favs.Items[Node^.Index].FavoriteInfo.Title; - 2: CellText := Favs.Items[Node^.Index].FavoriteInfo.Website; + 1: CellText := Data^.Fav.FavoriteInfo.Title; + 2: CellText := Data^.Fav.FavoriteInfo.Website; end; end; -procedure TTransferFavoritesForm.SearchDBForMatchTitle; +procedure TTransferFavoritesForm.UpdateFilterCount; +begin + rbAll.Caption := RS_ALL + '(' + IntToStr(FAllCount) + ')'; + rbValid.Caption := RS_Valid + '(' + IntToStr(FValidCount) + ')'; + rbInvalid.Caption := RS_Invalid + '(' + IntToStr(FInvalidCount) + ')'; +end; + +procedure TTransferFavoritesForm.FilterState(const AState: Integer); var - i: Integer; + Node: PVirtualNode; + Data: PFavContainer; begin - if DB.RecordCount = 0 then Exit; - for i := 0 to Favs.Count - 1 do + if FLastFilter = AState then Exit; + try + vtFavs.BeginUpdate; + Node := vtFavs.GetFirst(); + while Assigned(Node) do + begin + Data := vtFavs.GetNodeData(Node); + if AState = 0 then + vtFavs.IsVisible[Node] := True + else + vtFavs.IsVisible[Node] := Data^.State = AState; + Node := vtFavs.GetNext(Node); + end; + finally + vtFavs.EndUpdate; + end; + FLastFilter := AState; +end; + +procedure TTransferFavoritesForm.FindMatchTitle; +begin + with TFindMatchDBThread.Create(cbWebsites.Text) do begin - //if DB.Table.Locate('title', Favs.Items[i].FavoriteInfo.Title); + Owner := Self; + Start; end; end; +procedure TTransferFavoritesForm.AddFav(const AFav: TFavoriteContainer); +var + Node: PVirtualNode; + Data: PFavContainer; +begin + Node := vtFavs.AddChild(nil); + Data := vtFavs.GetNodeData(Node); + Data^.Fav := AFav; + Data^.NewLink := ''; + Data^.State := 0; + Inc(FAllCount); +end; + end. diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 33421545c..eee3d37b5 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -349,6 +349,22 @@ msgstr "System wird in den Ruhemodus versetzt in %d Sekunden." msgid "System will shutdown in %d second." msgstr "System wird heruntergefahren in %d Sekunden." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Ungültig" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Initialisierungs Vektor:" @@ -2014,6 +2030,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2024,6 +2041,7 @@ msgid "Invalid" msgstr "Ungültig" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index dc5cb74bf..5d78e247a 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -353,6 +353,22 @@ msgstr "Το σύστημα θα αδρανοποιηθεί σε %d δευτερ msgid "System will shutdown in %d second." msgstr "Το σύστημα θα τερματιστεί σε %d δευτερόλεπτα." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Μη έγκυρο" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Διάνυσμα προετοιμασίας:" @@ -2069,6 +2085,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2079,6 +2096,7 @@ msgid "Invalid" msgstr "Μη έγκυρο" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index e29dc602c..d24329e18 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -349,6 +349,22 @@ msgstr "System will hibernate in %d second." msgid "System will shutdown in %d second." msgstr "System will shutdown in %d second." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Invalid" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Initialization Vector:" @@ -2012,6 +2028,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2022,6 +2039,7 @@ msgid "Invalid" msgstr "Invalid" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index aeee99beb..bc31ec097 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -347,6 +347,22 @@ msgstr "Sistema Hibernará en %d segundos." msgid "System will shutdown in %d second." msgstr "Sistema se Apagará en %d segundos." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Inválido" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Inicialización del Vector:" @@ -1990,6 +2006,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2000,6 +2017,7 @@ msgid "Invalid" msgstr "Inválido" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 7a5015458..3d3ce4030 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -347,6 +347,22 @@ msgstr "Komputer akan dihibernasi dalam %d detik" msgid "System will shutdown in %d second." msgstr "Komputer akan dimatikan dalam %d detik" +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Tidak valid" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Initialization Vector:" @@ -1990,6 +2006,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2000,6 +2017,7 @@ msgid "Invalid" msgstr "Tidak valid" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 3b240cc64..7040ea765 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -344,6 +344,22 @@ msgstr "System zahibernuje się za %d sekund." msgid "System will shutdown in %d second." msgstr "System wyłączy się za %d sekund." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Niepoprawnie" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "" @@ -2011,6 +2027,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2021,6 +2038,7 @@ msgid "Invalid" msgstr "Niepoprawnie" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index bc483cce8..2bd9dc28c 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -307,6 +307,21 @@ msgstr "" msgid "System will shutdown in %d second." msgstr "" +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "" @@ -1914,6 +1929,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -1923,6 +1939,7 @@ msgid "Invalid" msgstr "" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index bf86f04d3..4a82a838f 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -349,6 +349,22 @@ msgstr "Sistema irá hibernar em %d segundos." msgid "System will shutdown in %d second." msgstr "Sistema irá desligar em %d segundos." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Inválido" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Vetor de Inicialização:" @@ -2011,6 +2027,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2021,6 +2038,7 @@ msgid "Invalid" msgstr "Inválido" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index bc395ae94..077736c03 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -346,6 +346,22 @@ msgstr "Система перейдет в спящий режим через %d msgid "System will shutdown in %d second." msgstr "Система выключится через %d секунд." +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "" + +#: frmtransferfavorites.rs_invalid +#, fuzzy +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Неверный" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "" + #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" msgstr "Вектор инициализации:" @@ -1994,6 +2010,7 @@ msgid "Transfer to" msgstr "" #: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "" @@ -2004,6 +2021,7 @@ msgid "Invalid" msgstr "Неверный" #: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" msgstr "" From 75f80e6c5f1a856a364229bbf1e62c27dc5deb75 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 18 Jan 2018 15:49:53 +0300 Subject: [PATCH 1952/2794] Add WhiteoutScans #637 --- baseunits/modules/FoOlSlide.pas | 4 ++-- config/mangalist.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 5692433a9..cf60d1d3f 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -242,14 +242,14 @@ procedure RegisterModule; begin AddWebsiteModule('PowerManga', 'http://read.powermanga.org'); - AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); AddWebsiteModule('GoManga', 'http://gomanga.co'); AddWebsiteModule('OneTimeScans', 'http://otscans.com'); AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com'); AddWebsiteModule('KireiCake', 'https://reader.kireicake.com'); - AddWebsiteModule('HelveticaScans', 'http://helveticascans.com'); + AddWebsiteModule('HelveticaScans', 'http://helveticascans.com'); + AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index f9150f982..18d7de8b5 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake +English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineMangaDE Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From 6cd37ec77d83ebb8957f29cb9c0ee3ec53d4bf03 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 18 Jan 2018 16:12:56 +0300 Subject: [PATCH 1953/2794] Add Doki fixes #721 --- baseunits/modules/FoOlSlide.pas | 7 +++++-- config/mangalist.ini | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index cf60d1d3f..e94d741f2 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -23,7 +23,8 @@ function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin if ((Module.Website = 'SeinagiAdultoFansub') or - (Module.Website = 'TripleSevenScan')) + (Module.Website = 'TripleSevenScan') or + (Module.Website = 'DokiFansubs')) and (Pos(dirurl, AURL) = 0)then Result := AHTTP.POST(AURL, 'adult=true') else @@ -34,7 +35,8 @@ function GetDirURL(const AWebsite: String): String; begin if (AWebsite = 'GoManga') or (AWebsite = 'Jaiminisbox') or - (AWebsite = 'TripleSevenScan') then + (AWebsite = 'TripleSevenScan') or + (AWebsite = 'DokiFansubs') then Result := dirurlreader else if AWebsite = 'OneTimeScans' then @@ -250,6 +252,7 @@ procedure RegisterModule; AddWebsiteModule('KireiCake', 'https://reader.kireicake.com'); AddWebsiteModule('HelveticaScans', 'http://helveticascans.com'); AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com'); + AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index 18d7de8b5..c97e8861d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans +English-Scanlation=DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineMangaDE Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From 5d303ab5302df50afa3ede3936e2a7980516f720 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Jan 2018 14:42:25 +0800 Subject: [PATCH 1954/2794] favoritesdb, fix restore website --- baseunits/uFavoritesManager.pas | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index c6ed6d830..7ff91ae73 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -982,6 +982,8 @@ procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); end; procedure TFavoriteManager.Restore; +var + t: TFavoriteContainer; begin if not FFavoritesDB.Connection.Connected then Exit; if FFavoritesDB.OpenTable(False) then @@ -992,19 +994,21 @@ procedure TFavoriteManager.Restore; FFavoritesDB.Table.First; while not FFavoritesDB.Table.EOF do begin - Items.Add(TFavoriteContainer.Create); - with Items.Last, FavoriteInfo, FFavoritesDB.Table do + t := TFavoriteContainer.Create; + with t, FavoriteInfo, FFavoritesDB.Table do begin Manager := Self; Status := STATUS_IDLE; Enabled := Fields[f_enabled].AsBoolean; Website := Fields[f_website].AsString; + t.Website := Website; Link := Fields[f_link].AsString; Title := Fields[f_title].AsString; CurrentChapter := Fields[f_currentchapter].AsString; DownloadedChapterList := Fields[f_downloadedchapterlist].AsString; SaveTo := Fields[f_saveto].AsString; end; + Items.Add(t); FFavoritesDB.Table.Next; end; finally From 865941d491c40aadc93a495a7d59c5ade665a363 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Jan 2018 14:42:47 +0800 Subject: [PATCH 1955/2794] transferfavorites, ignore same website --- .../forms/frmTransferFavorites.pas | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas index a0422ac4f..e41c5415d 100644 --- a/mangadownloader/forms/frmTransferFavorites.pas +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -116,6 +116,20 @@ procedure TFindMatchDBThread.Execute; db: TDBDataProcess; node: PVirtualNode; data: PFavContainer; + + procedure setvalid(const nl: String = ''); + begin + Inc(Owner.FValidCount); + data^.NewLink := nl; + data^.State := 1; + end; + procedure setinvalid; + begin + Inc(Owner.FInvalidCount); + data^.NewLink := ''; + data^.State := 2; + end; + begin Synchronize(@SyncBegin); Owner.FValidCount := 0; @@ -129,24 +143,23 @@ procedure TFindMatchDBThread.Execute; while Assigned(node) do begin data := Owner.vtFavs.GetNodeData(node); - try - db.Table.SQL.Text := 'SELECT link FROM ' + AnsiQuotedStr(db.TableName, '"') + - ' WHERE title LIKE '+AnsiQuotedStr(data^.Fav.FavoriteInfo.Title, '"') + ' COLLATE NOCASE;'; - db.Table.Open; - if db.Table.RecNo > 0 then - begin - Inc(Owner.FValidCount); - data^.NewLink := db.Table.Fields[0].AsString; - data^.State := 1; - end - else - begin - Inc(Owner.FInvalidCount); - data^.NewLink := ''; - data^.State := 2; + writeln(data^.Fav.Website+' <-> '+db.Website); + if data^.Fav.Website = db.Website then + setvalid + else + begin + try + db.Table.SQL.Text := 'SELECT link FROM ' + AnsiQuotedStr(db.TableName, '"') + + ' WHERE title LIKE '+AnsiQuotedStr(data^.Fav.FavoriteInfo.Title, '"') + ' COLLATE NOCASE;'; + db.Table.Open; + writeln('locate>'); + if db.Table.RecNo > 0 then + setvalid(db.Table.Fields[0].AsString) + else + setinvalid; + except end; db.Table.Close; - except end; node := Owner.vtFavs.GetNext(node); end; From 71f745c6ddd74e231258c1acc68985626f93d733 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Jan 2018 15:05:40 +0800 Subject: [PATCH 1956/2794] favoritemanager, add overload of remove favorite --- baseunits/uFavoritesManager.pas | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 7ff91ae73..5ef760820 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -123,9 +123,11 @@ TFavoriteManager = class // Merge a favorites.ini with another favorites.ini procedure MergeWith(const APath: String); // Free then delete favorite without any check, use with caution - procedure FreeAndDelete(const Pos: Integer); + procedure FreeAndDelete(const Pos: Integer); overload; + procedure FreeAndDelete(const T: TFavoriteContainer); overload; // Remove a manga from FFavorites - procedure Remove(const Pos: Integer; const isBackup: Boolean = True); + procedure Remove(const Pos: Integer; const isBackup: Boolean = True); overload; + procedure Remove(const T: TFavoriteContainer; const isBackup: Boolean = True); overload; // Restore information from favorites.db procedure Restore; // Backup to favorites.db @@ -966,6 +968,14 @@ procedure TFavoriteManager.FreeAndDelete(const Pos: Integer); Items.Delete(Pos); end; +procedure TFavoriteManager.FreeAndDelete(const T: TFavoriteContainer); +begin + with T.FavoriteInfo do + FFavoritesDB.Delete(Website, Link); + T.Free; + Items.Remove(T); +end; + procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); begin if (not isRunning) and (Pos < Items.Count) then @@ -981,6 +991,21 @@ procedure TFavoriteManager.Remove(const Pos: Integer; const isBackup: Boolean); end; end; +procedure TFavoriteManager.Remove(const T: TFavoriteContainer; const isBackup: Boolean); +begin + if not isRunning then + begin + EnterCriticalsection(CS_Favorites); + try + FreeAndDelete(T); + if isBackup then + Backup; + finally + LeaveCriticalsection(CS_Favorites); + end; + end; +end; + procedure TFavoriteManager.Restore; var t: TFavoriteContainer; From ccd6d766ac032b76e3da22f3f5183fe101eb0d43 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Jan 2018 15:07:34 +0800 Subject: [PATCH 1957/2794] transferfavorite, add and delete old favorites on transter --- mangadownloader/forms/frmMain.pas | 3 +- .../forms/frmTransferFavorites.pas | 36 ++++++++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9608248f7..61c2fa8df 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1514,7 +1514,8 @@ procedure TMainForm.miTransferWebsiteClick(Sender: TObject); AddFav(FavoriteManager.Items[Node^.Index]); Node := vtFavorites.GetNextSelected(Node); end; - ShowModal; + if ShowModal = mrOK then + UpdateVtFavorites; finally Free; end; diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas index e41c5415d..63ca050bb 100644 --- a/mangadownloader/forms/frmTransferFavorites.pas +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -143,7 +143,6 @@ procedure TFindMatchDBThread.Execute; while Assigned(node) do begin data := Owner.vtFavs.GetNodeData(node); - writeln(data^.Fav.Website+' <-> '+db.Website); if data^.Fav.Website = db.Website then setvalid else @@ -152,7 +151,6 @@ procedure TFindMatchDBThread.Execute; db.Table.SQL.Text := 'SELECT link FROM ' + AnsiQuotedStr(db.TableName, '"') + ' WHERE title LIKE '+AnsiQuotedStr(data^.Fav.FavoriteInfo.Title, '"') + ' COLLATE NOCASE;'; db.Table.Open; - writeln('locate>'); if db.Table.RecNo > 0 then setvalid(db.Table.Fields[0].AsString) else @@ -206,8 +204,38 @@ procedure TTransferFavoritesForm.rbAllChange(Sender: TObject); end; procedure TTransferFavoritesForm.btOKClick(Sender: TObject); +var + Node: PVirtualNode; + Data: PFavContainer; + dc: String; begin - Close; + Node := vtFavs.GetFirst(); + while Assigned(Node) do + begin + Data := vtFavs.GetNodeData(Node); + // add new item and remove the old one + if Data^.NewLink <> '' then + begin + with Data^.Fav.FavoriteInfo do + begin + if ckClearDownloadedChapters.Checked then + dc := '' + else + dc := DownloadedChapterList; + FavoriteManager.Add( + Title, + CurrentChapter, + dc, + cbWebsites. + Text, + SaveTo, + Data^.NewLink); + end; + FavoriteManager.Remove(Data^.Fav, False); + end; + Node := vtFavs.GetNext(Node); + end; + ModalResult := mrOK; end; procedure TTransferFavoritesForm.cbWebsitesChange(Sender: TObject); @@ -219,7 +247,7 @@ procedure TTransferFavoritesForm.cbWebsitesChange(Sender: TObject); procedure TTransferFavoritesForm.btCancelClick(Sender: TObject); begin - Close; + ModalResult := mrCancel; end; procedure TTransferFavoritesForm.vtFavsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); From f8c38647a3aea30aec768d1647410ea4baf6630b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Jan 2018 16:00:50 +0800 Subject: [PATCH 1958/2794] transferfavorite, get new downloadedchapterlist #826 --- baseunits/uFavoritesManager.pas | 11 ++++++ mangadownloader/forms/frmMain.pas | 35 +++++++++++++++---- .../forms/frmTransferFavorites.pas | 7 +++- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 5ef760820..095e9610b 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -69,6 +69,7 @@ TFavoriteContainer = class procedure SetEnabled(AValue: Boolean); procedure SetWebsite(AValue: String); public + Tag: Integer; FavoriteInfo: TFavoriteInfo; NewMangaInfo: TMangaInfo; NewMangaInfoChaptersPos: TCardinalList; @@ -186,6 +187,7 @@ constructor TFavoriteContainer.Create; begin FModuleId := -1; FEnabled := True; + Tag := 0; end; destructor TFavoriteContainer.Destroy; @@ -255,6 +257,14 @@ procedure TFavoriteThread.Execute; // update current chapters count immedietly FavoriteInfo.CurrentChapter := IntToStr(NewMangaInfo.chapterLinks.Count); if NewMangaInfo.chapterLinks.Count > 0 then + begin + // tag 100 for transfer favorite, add all chapter to downloaded chapter list + if Container.Tag = 100 then + begin + FavoriteInfo.DownloadedChapterList := NewMangaInfo.chapterLinks.Text; + Container.Tag := 0; + end + else try DLChapters := TStringList.Create; DLChapters.Sorted := False; @@ -266,6 +276,7 @@ procedure TFavoriteThread.Execute; finally DLChapters.Free; end; + end; // free unneeded objects if (NewMangaInfoChaptersPos.Count = 0) and diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 61c2fa8df..9e9fdc55f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1505,17 +1505,40 @@ procedure TMainForm.miFavoritesEnableClick(Sender: TObject); procedure TMainForm.miTransferWebsiteClick(Sender: TObject); var Node: PVirtualNode; + sm, i: Integer; + Data: PFavContainer; begin with TTransferFavoritesForm.Create(nil) do try - Node := vtFavorites.GetFirstSelected(); - while Assigned(Node) do - begin - AddFav(FavoriteManager.Items[Node^.Index]); - Node := vtFavorites.GetNextSelected(Node); + FavoriteManager.isRunning := True; + sm := mrNone; + try + Node := vtFavorites.GetFirstSelected(); + while Assigned(Node) do + begin + AddFav(FavoriteManager.Items[Node^.Index]); + Node := vtFavorites.GetNextSelected(Node); + end; + sm := ShowModal; + finally + FavoriteManager.isRunning := False; end; - if ShowModal = mrOK then + if sm = mrOK then + begin UpdateVtFavorites; + i := 0; + Node := vtFavs.GetFirst(); + while Assigned(Node) do + begin + Data := vtFavs.GetNodeData(Node); + for i := i to FavoriteManager.Count - 1 do + begin + if Data^.Fav = FavoriteManager.Items[i] then + FavoriteManager.CheckForNewChapter(i); + end; + Node := vtFavs.GetNext(Node); + end; + end; finally Free; end; diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas index 63ca050bb..2b43847e6 100644 --- a/mangadownloader/forms/frmTransferFavorites.pas +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -208,6 +208,7 @@ procedure TTransferFavoritesForm.btOKClick(Sender: TObject); Node: PVirtualNode; Data: PFavContainer; dc: String; + t: TFavoriteContainer; begin Node := vtFavs.GetFirst(); while Assigned(Node) do @@ -231,7 +232,11 @@ procedure TTransferFavoritesForm.btOKClick(Sender: TObject); SaveTo, Data^.NewLink); end; - FavoriteManager.Remove(Data^.Fav, False); + t := FavoriteManager.Items.Last; + FavoriteManager.FreeAndDelete(Data^.Fav); + Data^.Fav := t; + if ckClearDownloadedChapters.Checked then + t.Tag := 100; // get new chapterlist end; Node := vtFavs.GetNext(Node); end; From 9c0cf3e8f23b5fee4ea817614d6686e34330af58 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 20 Jan 2018 21:35:22 +0800 Subject: [PATCH 1959/2794] auto check favorites, stop timer and start again aftar check favorites finished fixed #837 --- baseunits/uFavoritesManager.pas | 2 ++ mangadownloader/forms/frmMain.pas | 1 + 2 files changed, 3 insertions(+) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 095e9610b..c41048323 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -348,6 +348,8 @@ procedure TFavoriteTask.SyncFinishChecking; btCancelFavoritesCheck.Width + 6; btFavoritesCheckNewChapter.Caption := RS_BtnCheckFavorites; vtFavorites.Repaint; + if OptionAutoCheckFavInterval and (not tmCheckFavorites.Enabled) then + tmCheckFavorites.Enabled := True; end; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9e9fdc55f..740be48a6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1552,6 +1552,7 @@ procedure TMainForm.tmAnimateMangaInfoTimer(Sender: TObject); procedure TMainForm.tmCheckFavoritesTimer(Sender: TObject); begin if IsDlgCounter then Exit; + tmCheckFavorites.Enabled := False; if OptionAutoCheckLatestVersion then btCheckLatestVersionClick(btCheckLatestVersion); FavoriteManager.isAuto := True; From 4abc1f638a08ed258d92c4c4eb8997ae03a8fb55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 21 Jan 2018 00:50:34 +0800 Subject: [PATCH 1960/2794] favorites, added rename favorite title #826 --- mangadownloader/forms/frmMain.lfm | 9 ++++--- mangadownloader/forms/frmMain.lrj | 3 ++- mangadownloader/forms/frmMain.pas | 36 +++++++++++++++++++++----- mangadownloader/languages/fmd.de.po | 13 +++++++--- mangadownloader/languages/fmd.el_GR.po | 13 +++++++--- mangadownloader/languages/fmd.en.po | 13 +++++++--- mangadownloader/languages/fmd.es.po | 13 +++++++--- mangadownloader/languages/fmd.id_ID.po | 13 +++++++--- mangadownloader/languages/fmd.pl_PL.po | 13 +++++++--- mangadownloader/languages/fmd.po | 13 +++++++--- mangadownloader/languages/fmd.pt_BR.po | 13 +++++++--- mangadownloader/languages/fmd.ru_RU.po | 13 +++++++--- 12 files changed, 119 insertions(+), 46 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index db9deaf73..8aa214eea 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,7 +14,6 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -5236,9 +5235,13 @@ object MainForm: TMainForm ImageIndex = 1 OnClick = miFavoritesDownloadAllClick end - object miTransferWebsite: TMenuItem + object miFavoritesRename: TMenuItem + Caption = 'Rename' + OnClick = miFavoritesRenameClick + end + object miFavoritesTransferWebsite: TMenuItem Caption = 'Transfer website' - OnClick = miTransferWebsiteClick + OnClick = miFavoritesTransferWebsiteClick end object MenuItem7: TMenuItem Caption = '-' diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 347a89980..db84609c3 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -273,7 +273,8 @@ {"hash":185170277,"name":"tmainform.mifavoritesdisable.caption","sourcebytes":[68,105,115,97,98,108,101],"value":"Disable"}, {"hash":27371647,"name":"tmainform.mifavoritesviewinfos.caption","sourcebytes":[86,105,101,119,32,109,97,110,103,97,32,105,110,102,111],"value":"View manga info"}, {"hash":29393692,"name":"tmainform.mifavoritesdownloadall.caption","sourcebytes":[68,111,119,110,108,111,97,100,32,97,108,108],"value":"Download all"}, -{"hash":136379477,"name":"tmainform.mitransferwebsite.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,119,101,98,115,105,116,101],"value":"Transfer website"}, +{"hash":93079605,"name":"tmainform.mifavoritesrename.caption","sourcebytes":[82,101,110,97,109,101],"value":"Rename"}, +{"hash":136379477,"name":"tmainform.mifavoritestransferwebsite.caption","sourcebytes":[84,114,97,110,115,102,101,114,32,119,101,98,115,105,116,101],"value":"Transfer website"}, {"hash":78392485,"name":"tmainform.mifavoritesdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, {"hash":94036626,"name":"tmainform.mifavoriteschangecurrentchapter.caption","sourcebytes":[67,104,97,110,103,101,32,34,67,117,114,114,101,110,116,32,99,104,97,112,116,101,114,34],"value":"Change \"Current chapter\""}, {"hash":202687490,"name":"tmainform.mifavoriteschangesaveto.caption","sourcebytes":[67,104,97,110,103,101,32,34,83,97,118,101,32,116,111,34],"value":"Change \"Save to\""}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 740be48a6..629d8a4e3 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -90,7 +90,8 @@ TMainForm = class(TForm) lbOptionMangaCustomRename: TLabel; MenuItem10: TMenuItem; MenuItem11: TMenuItem; - miTransferWebsite: TMenuItem; + miFavoritesRename: TMenuItem; + miFavoritesTransferWebsite: TMenuItem; miFavoritesEnable: TMenuItem; miFavoritesDisable: TMenuItem; miChapterListDescending: TMenuItem; @@ -464,7 +465,8 @@ TMainForm = class(TForm) procedure FormWindowStateChange(Sender: TObject); procedure miChapterListAscendingClick(Sender: TObject); procedure miFavoritesEnableClick(Sender: TObject); - procedure miTransferWebsiteClick(Sender: TObject); + procedure miFavoritesRenameClick(Sender: TObject); + procedure miFavoritesTransferWebsiteClick(Sender: TObject); procedure tmAnimateMangaInfoTimer(Sender: TObject); procedure tmCheckFavoritesTimer(Sender: TObject); procedure tmExitCommandTimer(Sender: TObject); @@ -1502,7 +1504,26 @@ procedure TMainForm.miFavoritesEnableClick(Sender: TObject); UpdateVtFavorites; end; -procedure TMainForm.miTransferWebsiteClick(Sender: TObject); +procedure TMainForm.miFavoritesRenameClick(Sender: TObject); +var + node: PVirtualNode; + t: TFavoriteContainer; + tt: String; +begin + node := vtFavorites.GetFirstSelected(); + if Assigned(node) then + begin + t := FavoriteManager.Items[node^.Index]; + tt := t.FavoriteInfo.Title; + if InputQuery('', RS_InfoTitle, tt) then + begin + t.FavoriteInfo.Title := tt; + t.SaveToDB(); + end; + end; +end; + +procedure TMainForm.miFavoritesTransferWebsiteClick(Sender: TObject); var Node: PVirtualNode; sm, i: Integer; @@ -3539,7 +3560,8 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesChangeSaveTo.Enabled := False; miFavoritesOpenFolder.Enabled := False; miFavoritesOpenWith.Enabled := False; - miTransferWebsite.Enabled := False; + miFavoritesTransferWebsite.Enabled := False; + miFavoritesRename.Enabled := False; end else begin @@ -3548,7 +3570,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesStopCheckNewChapter.Enabled := iStop; miFavoritesEnable.Enabled := iEnable; miFavoritesDisable.Enabled := iDisable; - miTransferWebsite.Enabled := True; + miFavoritesTransferWebsite.Enabled := True; if vtFavorites.SelectedCount = 1 then begin miFavoritesViewInfos.Enabled := True; @@ -3557,6 +3579,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesChangeSaveTo.Enabled := True; miFavoritesOpenFolder.Enabled := DirectoryExistsUTF8(FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo.SaveTo); miFavoritesOpenWith.Enabled := miFavoritesOpenFolder.Enabled; + miFavoritesRename.Enabled := True; end else begin @@ -3566,13 +3589,14 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesChangeSaveTo.Enabled := False; miFavoritesOpenFolder.Enabled := False; miFavoritesOpenWith.Enabled := False; + miFavoritesRename.Enabled := False; end; end; if FavoriteManager.isRunning then begin miFavoritesDelete.Enabled := False; miFavoritesChangeSaveTo.Enabled := False; - miTransferWebsite.Enabled := False; + miFavoritesTransferWebsite.Enabled := False; end; end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index eee3d37b5..81f2b3b43 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -1664,10 +1664,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Öffne ..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Nach neuen Kapitel suchen anhalten" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1695,10 +1704,6 @@ msgstr "Alles laden" msgid "View manga infos" msgstr "Zeige Manga-Informationen" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "After download finish" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 5d78e247a..2eb38265c 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1719,10 +1719,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Άνοιγμα..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Διακοπή ελέγχου για νέα κεφάλαια" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1750,10 +1759,6 @@ msgstr "Λήψη όλων" msgid "View manga infos" msgstr "Προβολή πρηροφοριών manga" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Μετά την ολοκλήρωση της λήψης" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d24329e18..d25a830e3 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1663,10 +1663,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Open ..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Stop check for new chapter" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1694,10 +1703,6 @@ msgstr "Download all" msgid "View manga infos" msgstr "View manga infos" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "After download finish" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index bc31ec097..399af1203 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1641,10 +1641,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Abrir ..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Detener Revisar si hay Nuevo Capitulo" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1672,10 +1681,6 @@ msgstr "Descargar Todo" msgid "View manga infos" msgstr "Ver Información del Manga" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Después de Finalizar la Descarga" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 3d3ce4030..41d260ffd 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1641,10 +1641,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Buka ..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Berhenti periksa bab baru" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1672,10 +1681,6 @@ msgstr "Unduh semua" msgid "View manga infos" msgstr "Lihat informasi komik" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Setelah download selesai" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 7040ea765..a6eed446b 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1660,10 +1660,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Otwórz... " +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Zatrzymaj sprawdzanie nowych rozdziałów" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1691,10 +1700,6 @@ msgstr "Pobierz wszystko" msgid "View manga infos" msgstr "Zobacz informacje o mandze" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Po pobieraniu zakończ" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 2bd9dc28c..c2e472b54 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1566,10 +1566,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "" +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1597,10 +1606,6 @@ msgstr "" msgid "View manga infos" msgstr "" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 4a82a838f..b799f721d 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1662,10 +1662,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Abrir ..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Parar de checar por novos capítulos" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1693,10 +1702,6 @@ msgstr "Baixar tudo" msgid "View manga infos" msgstr "Exibir infos do mangá" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "Depois do download terminar" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 077736c03..08976baa9 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -1644,10 +1644,19 @@ msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" msgid "Open ..." msgstr "Открыть..." +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "" + #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" msgstr "Не проверять на новые главы" +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "" + #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" msgid "View manga info" @@ -1675,10 +1684,6 @@ msgstr "Загрузить все" msgid "View manga infos" msgstr "Информация о манге" -#: tmainform.mitransferwebsite.caption -msgid "Transfer website" -msgstr "" - #: tmainform.mitrayafterdownloadfinish.caption msgid "After download finish" msgstr "После завершения загрузки:" From 69d21fa5ee45a5bec61136fb5a10c97a5b860ff1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 22 Jan 2018 09:02:17 +0300 Subject: [PATCH 1961/2794] senmanga, fix all fixes #854 --- baseunits/modules/SenManga.pas | 93 ++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 21 deletions(-) diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas index 193dd919f..2a7008961 100644 --- a/baseunits/modules/SenManga.pas +++ b/baseunits/modules/SenManga.pas @@ -6,13 +6,16 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + XQueryEngineHTML, httpsendthread, synautil, URIParser; implementation const dirurl = '/directory'; +var + cookie: String; + function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin @@ -74,20 +77,15 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//*[@class="cover"]/img/@src'); + coverLink := XPathString('//div[@class="thumbnail"]/img/@src'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//*[@class="info"]/h1[@class="title"]'); - status := MangaInfoStatusIfPos( - XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), - 'Ongoing', - 'Complete'); - artists := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Artist:")]/following-sibling::*[@class="desc"][1]/a'); - authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); - for v in XPath('//table[@id="chapter-list"]//tr/td/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; + if title = '' then title := XPathString('//h1[@class="title"]'); + genres := XPathStringAll('//ul[@class="series-info"]/li[contains(., "Categories")]/a'); + authors := XPathStringAll('//ul[@class="series-info"]/li[contains(., "Author")]/a'); + artists := XPathStringAll('//ul[@class="series-info"]/li[contains(., "Artist")]/a'); + status := MangaInfoStatusIfPos(XPathString('//ul[@class="series-info"]/li[contains(., "Status")]/a')); + summary := XPathString('//*[@itemprop="description"]'); + XPathHREFAll('//div[@class="title" and contains(., "Chapters")]/following-sibling::div/div/a', chapterLinks, chapterName); finally Free; end; @@ -99,6 +97,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var s: String; + uri: TURI; begin Result := False; if DownloadThread = nil then Exit; @@ -106,18 +105,26 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - Cookies.Values['viewer'] := '1'; if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then begin Result := True; + cookie := Cookies.Text; with TXQueryEngineHTML.Create(Document) do try - s := XPathString('//script[contains(.,"var imglist = [")]'); - if s <> '' then - begin - s := '[' + GetBetween('var imglist = [', '];', s) + ']'; - ParseHTML(s); - XPathStringAll('json(*)().url', PageLinks); + PageNumber := XPath('//select[@name="page"]/option').Count; + if PageNumber > 0 then begin + s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); + uri := ParseURI(s); + if (Pos('/raw-viewer.php', LowerCase(uri.Path)) > 0) and (Pos('page=1', LowerCase(uri.Params)) > 0) then + while PageLinks.Count < PageNumber do begin + uri.Params := ReplaceString(uri.Params, 'page=1', 'page=' + IncStr(PageLinks.Count)); + PageLinks.Add(EncodeURI(uri)); + end + else if (Pos('/viewer/', LowerCase(uri.Path)) > 0) and (uri.Document = '1') then + while PageLinks.Count < PageNumber do begin + uri.Document := IncStr(PageLinks.Count); + PageLinks.Add(EncodeURI(uri)); + end; end; finally Free; @@ -126,16 +133,59 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + var AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container do + if CurrentDownloadChapterPtr < ChapterLinks.Count then begin + DownloadThread.FHTTP.Headers.Values['Referer'] := + ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); + DownloadThread.FHTTP.Cookies.Text := cookie; + Result := True; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; + uri: TURI; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + uri := ParseURI(FillHost(Module.RootURL, AURL)); + uri.Document := IncStr(DownloadThread.WorkId); + if GET(EncodeURI(uri)) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="picture"]/@src')); + if s <> '' then + PageLinks[DownloadThread.WorkId] := s; + finally + Free; + end; + end; + end; +end; + procedure RegisterModule; begin with AddModule do begin Website := 'SenManga'; RootURL := 'http://www.senmanga.com'; + MaxTaskLimit := 1; + MaxConnectionLimit := 4; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; + OnGetImageURL := @GetImageURL; end; end; @@ -143,3 +193,4 @@ initialization RegisterModule; end. + From 9a80f89f4988c3a91e3cb1159b6b95eaea567dbf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 Jan 2018 07:18:55 +0800 Subject: [PATCH 1962/2794] baseunit, added tbasemangainfo --- baseunits/uBaseUnit.pas | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index b0ac33ee3..5485d84c9 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -448,6 +448,18 @@ TChapterStateItem = record Downloaded: Boolean; end; + PBaseMangaInfo = ^TBaseMangaInfo; + + TBaseMangaInfo = record + title, + authors, + artists, + genres, + status, + summary: String; + numChapter: Integer; + end; + PMangaInfo = ^TMangaInfo; { TMangaInfo } @@ -791,6 +803,10 @@ procedure TransferMangaInfo(var dest: TMangaInfo; const Source: TMangaInfo); function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String = 'Ongoing'; const CompletedStr: String = 'Complete'): String; +procedure GetBaseMangaInfo(const M: TMangaInfo; var B: TBaseMangaInfo); +// fill empty manga info +procedure FillBaseMangaInfo(const M: TMangaInfo; var B: TBaseMangaInfo); + // cross platform funcs function fmdGetTempPath: String; @@ -4050,6 +4066,28 @@ function MangaInfoStatusIfPos(const SearchStr: String; const OngoingStr: String; Result := MangaInfo_StatusCompleted; end; +procedure GetBaseMangaInfo(const M: TMangaInfo; var B: TBaseMangaInfo); +begin + B.title := M.title; + B.authors := M.authors; + B.artists := M.artists; + B.genres := M.genres; + B.status := M.status; + B.summary := M.summary; + B.numChapter := M.numChapter; +end; + +procedure FillBaseMangaInfo(const M: TMangaInfo; var B: TBaseMangaInfo); +begin + if Trim(M.title) = '' then M.title := B.title; + if Trim(M.authors) = '' then M.authors := B.authors; + if Trim(M.artists) = '' then M.artists := B.artists; + if Trim(M.genres) = '' then M.genres := B.genres; + if Trim(M.status) = '' then M.status := B.status; + if Trim(M.summary) = '' then M.summary := B.summary; + if M.numChapter = 0 then M.numChapter := B.numChapter; +end; + { THTMLForm } constructor THTMLForm.Create; From 77852b2c1fba180fa692ae354603be3cb9067d9a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 Jan 2018 07:19:38 +0800 Subject: [PATCH 1963/2794] mangainfo, backup and restore mangainfo on get (fixed #857) --- baseunits/uData.pas | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 9356d72ac..73f3e31c2 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -1079,6 +1079,7 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR Source: TStringList; Parser: THTMLParser; MangaSiteID: Integer; + bmangaInfo: TBaseMangaInfo; {$I includes/AnimeA/manga_information.inc} @@ -1152,6 +1153,8 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, AWebsite); + GetBaseMangaInfo(mangaInfo, bmangaInfo); + mangaInfo.website := AWebsite; mangaInfo.coverLink := ''; mangaInfo.numChapter := 0; @@ -1289,14 +1292,15 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR summary := CleanMultilinedString(FixWhiteSpace(summary)); // fix info - if title = '' then - title := 'N/A'; if (LeftStr(authors, 1) = '<') or (authors = '-') or (authors = ':') then authors := ''; if (LeftStr(artists, 1) = '<') or (artists = '-') or (artists = ':') then artists := ''; if (summary = '-') or (summary = ':') then summary := ''; + if title = '' then + title := 'N/A'; + FillBaseMangaInfo(mangaInfo, bmangaInfo); // cleanup chapters if chapterLinks.Count > 0 then begin From 6302ee8d23102f864851ab63207b481ac8a3dcbf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 Jan 2018 07:44:10 +0800 Subject: [PATCH 1964/2794] update future changelog --- changelog.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/changelog.txt b/changelog.txt index 0f0e9339d..4116a12f9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,27 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.130.0 (-2018) +[+] Added transfer favorites +[+] Added rename favorites +[+] Added Subapics [ID] +[+] Added MangaDesu [ID] +[+] Added MangaKita [ID] +[+] Added Whiteoutscans [EN-SC] +[+] Added DokiFansubs [EN-SC] +[*] NineManga: fixed all +[*] MangaInn: fixed all +[*] MangaLife: fixed domain +[*] MangaId: fixed download +[*] Madokami: fixed chapter title +[*] Jaiminisbox: fixed downoad +[*] MangaPark: fixed title +[*] Tsumanga: fixed update list +[*] Kumanga: fixed all +[*] RawSenManga: fixed all +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.129.0...0.9.130.0 + 0.9.129.0 (02-01-2018) [*] MangaGo: fixed download Full changes: https://github.com/riderkick/FMD/compare/0.9.128.0...0.9.129.0 From c96d60145ca3c20e0ed90ca773c05b0115f94e37 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 Jan 2018 08:13:49 +0800 Subject: [PATCH 1965/2794] added sqlite and openssl client version to about --- mangadownloader/forms/frmMain.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 629d8a4e3..d5af8b681 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -882,7 +882,7 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, - FMDVars, RegExpr, Clipbrd, LazFileUtils, LazUTF8; + FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8; var // thread for open db @@ -2110,6 +2110,10 @@ procedure TMainForm.LoadAbout; addaboutcomp('WidgetSet', GetWidgetSetName); addaboutcomp('Target CPU-OS', GetTargetCPU_OS); addaboutcomp('Build Time', GetBuildTime); + if SQLiteLibraryHandle = 0 then InitializeSqlite(); + if SQLiteLibraryHandle <> 0 then try addaboutcomp('SQLite Version', sqlite3_version()); except end; + if SSLLibHandle = 0 then InitSSLInterface; + if SSLLibHandle <> 0 then try addaboutcomp('OpenSSL Version', SSLeayversion(0)); except end; end; procedure TMainForm.GeneratetvDownloadFilterNodes; From d11951f8e1c5a9f60487d153157db419c8bc2205 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 23 Jan 2018 05:55:20 +0300 Subject: [PATCH 1966/2794] senmanga, fix update list --- baseunits/modules/SenManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas index 2a7008961..33bf1e147 100644 --- a/baseunits/modules/SenManga.pas +++ b/baseunits/modules/SenManga.pas @@ -52,7 +52,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//*[@id="search-results"]/*[@class="media_box"]/*[@class="media-body"]/a') do + for v in XPath('//*[@id="search-results"]/*[contains(@class, "media_box")]/*[contains(@class, "media-body")]/a') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); From 75719b3376636de556d54b6b1c20537b2134a685 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 23 Jan 2018 07:03:12 +0300 Subject: [PATCH 1967/2794] ninemanga, fix invalid chapter links --- baseunits/modules/NineManga.pas | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/NineManga.pas b/baseunits/modules/NineManga.pas index a7a6747e0..b2cde7277 100644 --- a/baseunits/modules/NineManga.pas +++ b/baseunits/modules/NineManga.pas @@ -42,16 +42,30 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; -var - s: String; + + function GetWithWarning(var url: String; const MangaInfo: TMangaInformation): Boolean; + var + w: String; + begin + Result := False; + if MangaInfo.FHTTP.GET(url) then begin + w := XPathString('//script[contains(., ''is_warning = "1"'')]', MangaInfo.FHTTP.Document); + if (w = '') or (Pos('waring=1', url) > 0) then + Result := True + else begin + url += '?waring=1'; + Result := MangaInfo.FHTTP.GET(url); + end; + end; + end; + begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := MaybeFillHost(Module.RootURL, AURL); - s := url; - if GET(s) then begin + if GetWithWarning(url, MangaInfo) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try coverLink := XPathString('//*[@class="bookface"]/img/@src'); From 884778b5b7f61e8f562aaac3af5724f07b7f2e29 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 Jan 2018 12:33:23 +0800 Subject: [PATCH 1968/2794] fixed path issue --- baseunits/FMDOptions.pas | 4 ++++ baseunits/extras/MangaFoxWatermark.pas | 22 +++++++++++----------- baseunits/uBaseUnit.pas | 6 +++--- mangadownloader/forms/frmMain.pas | 4 ++-- mangadownloader/md.lpr | 16 ++++++++-------- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 1129029c9..e968a89ae 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -64,6 +64,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) var FMD_VERSION_NUMBER, FMD_DIRECTORY, + FMD_EXENAME, APPDATA_DIRECTORY, DEFAULT_PATH, WORK_FOLDER, @@ -85,6 +86,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) IMAGE_FOLDER, LANGUAGE_FILE, CHANGELOG_FILE, + DEFAULT_LOG_FILE, README_FILE, EXTRAS_FOLDER, MANGAFOXTEMPLATE_FOLDER: String; @@ -274,6 +276,7 @@ procedure SetIniFiles; procedure SetFMDdirectory(const ADir: String); begin FMD_DIRECTORY := CleanAndExpandDirectory(ADir); + FMD_EXENAME := ExtractFileNameOnly(Application.ExeName); CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; @@ -286,6 +289,7 @@ procedure SetFMDdirectory(const ADir: String); README_FILE := FMD_DIRECTORY + 'readme.rtf'; EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; + DEFAULT_LOG_FILE := FMD_DIRECTORY + FMD_EXENAME + '.log'; end; procedure SetAppDataDirectory(const ADir: String); diff --git a/baseunits/extras/MangaFoxWatermark.pas b/baseunits/extras/MangaFoxWatermark.pas index b340c0915..d09df90bf 100644 --- a/baseunits/extras/MangaFoxWatermark.pas +++ b/baseunits/extras/MangaFoxWatermark.pas @@ -73,9 +73,9 @@ TWatermarkRemover = class MinWhiteBorder: Integer; constructor Create; destructor Destroy; override; - function LoadTemplate(const Directory: String = ''): Integer; + function LoadTemplate(const ADirectory: String = ''): Integer; procedure ClearTemplate; - function RemoveWatermark(const FileName: String; const SaveAsPNG: Boolean = False): Boolean; + function RemoveWatermark(const AFileName: String; const SaveAsPNG: Boolean = False): Boolean; property TemplateDirectory: String read FTemplateDirectory write FTemplateDirectory; property TemplateCount: Integer read GetTemplateCount; property Template[const Index: Integer]: POneBitImage read GetTemplate; @@ -290,7 +290,7 @@ destructor TWatermarkRemover.Destroy; DoneCriticalsection(FCS_RemoveWatermark); end; -function TWatermarkRemover.LoadTemplate(const Directory: String): Integer; +function TWatermarkRemover.LoadTemplate(const ADirectory: String): Integer; var Files: TStrings; D: String; @@ -298,8 +298,8 @@ function TWatermarkRemover.LoadTemplate(const Directory: String): Integer; begin Result := 0; FCleared := False; - if (Directory <> '') and (Directory <> FTemplateDirectory) then - FTemplateDirectory := Directory; + if (ADirectory <> '') and (ADirectory <> FTemplateDirectory) then + FTemplateDirectory := ADirectory; if FTemplateDirectory = '' then Exit; D := CleanAndExpandDirectory(FTemplateDirectory); if not DirectoryExistsUTF8(D) then Exit; @@ -355,7 +355,7 @@ function CalculatePSNR(const Image1, Image2: TOneBitImage): Single; Result := 10 * log10(sqr(255) / MSE); end; -function TWatermarkRemover.RemoveWatermark(const FileName: String; +function TWatermarkRemover.RemoveWatermark(const AFileName: String; const SaveAsPNG: Boolean): Boolean; var Handler: TImageHandlerRec; @@ -380,14 +380,14 @@ function TWatermarkRemover.RemoveWatermark(const FileName: String; LoadTemplate; end; if TemplateCount = 0 then Exit; - Handler := GetImageHandlerByFile(FileName); + Handler := GetImageHandlerByFile(AFileName); if Handler.Ext = '' then Exit; Image := TFPMemoryImage.Create(0, 0); try GrayScale := False; try Reader := Handler.ReaderClass.Create; - FileStream := TFileStreamUTF8.Create(FileName, fmOpenRead or fmShareDenyWrite); + FileStream := TFileStreamUTF8.Create(AFileName, fmOpenRead or fmShareDenyWrite); Image.LoadFromStream(FileStream, Reader); if Reader is TFPReaderJPEG then GrayScale := TFPReaderJPEG(Reader).GrayScale; @@ -450,9 +450,9 @@ function TWatermarkRemover.RemoveWatermark(const FileName: String; Handler.WriterClass := TFPWriterPNG; Handler.WExt := 'png'; end; - NewFileName := ExtractFileNameWithoutExt(FileName) + '.' + Handler.WExt; - if FileExistsUTF8(FileName) then - DeleteFileUTF8(FileName); + NewFileName := ExtractFileNameWithoutExt(AFileName) + '.' + Handler.WExt; + if FileExistsUTF8(AFileName) then + DeleteFileUTF8(AFileName); if FileExistsUTF8(NewFileName) then DeleteFileUTF8(NewFileName); if not FileExistsUTF8(NewFileName) then diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5485d84c9..83af45097 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -18,7 +18,7 @@ interface {$else} UTF8Process, {$endif} - SysUtils, Classes, Graphics, lazutf8classes, LazFileUtils, LConvEncoding, + SysUtils, Classes, Graphics, lazutf8classes, LazFileUtils, LConvEncoding, LazUtils, strutils, dateutils, variants, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, @@ -1851,7 +1851,7 @@ function CorrectPathSys(const Path: String): String; begin Result := FixWhiteSpace(Path); {$IFDEF WINDOWS} - Result := RemovePathDelim(CleanAndExpandFilename(GetForcedPathDelims(Result))); + Result := RemovePathDelim(ExpandFileNameUTF8(TrimFilename(GetForcedPathDelims(Result)), FMD_DIRECTORY)); Result := TrimRightChar(Result, ['.']); s := UTF8Decode(Result); if Length(s) > MAX_PATHDIR then @@ -1860,7 +1860,7 @@ function CorrectPathSys(const Path: String): String; Result := UTF8Encode(s); end; {$ELSE} - Result := CleanAndExpandFilename(GetForcedPathDelims(Path)); + Result := ExpandFileNameUTF8(TrimFilename(Path), FMD_DIRECTORY); {$ENDIF} Result := AppendPathDelim(Trim(Result)); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d5af8b681..e65e0a564 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4852,7 +4852,7 @@ procedure TMainForm.LoadOptions; ckEnableLogging.Checked := ReadBool('logger', 'Enabled', False); edLogFileName.Text := ReadString('logger', 'LogFileName', ''); if edLogFileName.Text = '' then - edLogFileName.Text := ChangeFileExt(ExtractFileNameOnly(Application.ExeName), '.log'); + edLogFileName.Text := DEFAULT_LOG_FILE; // websites if Length(optionMangaSiteSelectionNodes) > 0 then @@ -4987,7 +4987,7 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); frmCustomColor.SaveToIniFile(configfile); WriteBool('logger', 'Enabled', ckEnableLogging.Checked); if edLogFileName.Text = '' then - edLogFileName.Text := ChangeFileExt(ExtractFileNameOnly(Application.ExeName), '.log'); + edLogFileName.Text := DEFAULT_LOG_FILE; WriteString('logger', 'LogFileName', edLogFileName.Text); finally UpdateFile; diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index b9cf6e5d1..6d8957291 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -19,6 +19,9 @@ EnableLogging: Boolean = False; LogFileName: String = ''; s: TStringList; + {$IFDEF DEBUGLEAKS} + trcfile: String; + {$ENDIF DEBUGLEAKS} {$R *.res} @@ -28,11 +31,7 @@ CheckInstance := ReadBool('general', 'OneInstanceOnly', True); EnableLogging := ReadBool('logger', 'Enabled', False); if EnableLogging then - begin - LogFileName := ReadString('logger', 'LogFileName', ''); - if LogFileName = '' then - LogFileName := ChangeFileExt(Application.ExeName, '.log'); - end; + LogFileName := ExpandFileNameUTF8(ReadString('logger', 'LogFileName', DEFAULT_LOG_FILE), FMD_DIRECTORY); finally Free; end; @@ -56,9 +55,10 @@ if AllowedToRun then begin {$IFDEF DEBUGLEAKS} - if FileExistsUTF8(ChangeFileExt(Application.ExeName, '.trc')) then - DeleteFileUTF8(ChangeFileExt(Application.ExeName, '.trc')); - SetHeapTraceOutput(ChangeFileExt(Application.ExeName, '.trc')); + trcfile := FMD_DIRECTORY + FMD_EXENAME + '.trc'; + if FileExistsUTF8(trcfile) then + DeleteFileUTF8(trcfile); + SetHeapTraceOutput(trcfile); {$ENDIF DEBUGLEAKS} Application.Title := 'Free Manga Downloader'; RequireDerivedFormResource := True; From b8b532aad5693b7f25360cf6983ed0d12b337955 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 23 Jan 2018 17:39:34 +0800 Subject: [PATCH 1969/2794] Bump version 0.9.130.0 --- changelog.txt | 3 ++- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4116a12f9..24d8c7cad 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.130.0 (-2018) +0.9.130.0 (23-01-2018) [+] Added transfer favorites [+] Added rename favorites [+] Added Subapics [ID] @@ -22,6 +22,7 @@ Changelog: [*] Tsumanga: fixed update list [*] Kumanga: fixed all [*] RawSenManga: fixed all +[*] SenManga: fixed all [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.129.0...0.9.130.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index d50697ef3..635d03731 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -18,7 +18,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="129"/> + <RevisionNr Value="130"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 950d13d96..9c5743977 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.129.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.129.0/fmd_0.9.129.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.129.0/fmd_0.9.129.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.129.0/fmd_0.9.129.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.129.0/fmd_0.9.129.0_Win64.7z +VERSION=0.9.130.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.130.0/fmd_0.9.130.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.130.0/fmd_0.9.130.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.130.0/fmd_0.9.130.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.130.0/fmd_0.9.130.0_Win64.7z From b08241677d227a95e7ce5ef6c62bdbcf7b3e371d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 23 Jan 2018 15:18:01 +0300 Subject: [PATCH 1970/2794] update russian localization --- mangadownloader/languages/fmd.ru_RU.po | 49 +++++--------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 08976baa9..751ba76ec 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -349,18 +349,17 @@ msgstr "Система выключится через %d секунд." #: frmtransferfavorites.rs_all msgctxt "frmtransferfavorites.rs_all" msgid "All" -msgstr "" +msgstr "Все" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" -msgstr "Неверный" +msgstr "Нельзя перенести" #: frmtransferfavorites.rs_valid msgctxt "frmtransferfavorites.rs_valid" msgid "Valid" -msgstr "" +msgstr "Можно перенести" #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" @@ -474,15 +473,6 @@ msgstr "Список избранного" msgid "Manga list" msgstr "Список манги" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" @@ -1646,7 +1636,7 @@ msgstr "Открыть..." #: tmainform.mifavoritesrename.caption msgid "Rename" -msgstr "" +msgstr "Переименовать" #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" @@ -1655,7 +1645,7 @@ msgstr "Не проверять на новые главы" #: tmainform.mifavoritestransferwebsite.caption msgctxt "tmainform.mifavoritestransferwebsite.caption" msgid "Transfer website" -msgstr "" +msgstr "Перенести на другой сайт" #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" @@ -1990,55 +1980,34 @@ msgid "&Now" msgstr "Сейчас" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Отмена" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" #: ttransferfavoritesform.caption msgid "Transfer Favorites" -msgstr "" +msgstr "Перенос на другой сайт" #: ttransferfavoritesform.ckcleardownloadedchapters.caption msgid "Clear downloaded chapter list and reload from server" -msgstr "" +msgstr "Очистить скачанные главы и заново загрузить с сервера" #: ttransferfavoritesform.lbtransferto.caption msgctxt "ttransferfavoritesform.lbtransferto.caption" msgid "Transfer to" -msgstr "" - -#: ttransferfavoritesform.rball.caption -msgctxt "ttransferfavoritesform.rball.caption" -msgid "All" -msgstr "" - -#: ttransferfavoritesform.rbinvalid.caption -#, fuzzy -msgctxt "ttransferfavoritesform.rbinvalid.caption" -msgid "Invalid" -msgstr "Неверный" - -#: ttransferfavoritesform.rbvalid.caption -msgctxt "ttransferfavoritesform.rbvalid.caption" -msgid "Valid" -msgstr "" +msgstr "Перенести на" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Сайт" +msgstr "Название" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Сайт" From 8670ecd38c74ba5e567080cca903f00b2913d172 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 23 Jan 2018 15:35:28 +0300 Subject: [PATCH 1971/2794] change domain fixes #737 --- baseunits/modules/MangaChanRU.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index aca759e03..b70e08a42 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -160,7 +160,7 @@ procedure RegisterModule; begin AddWebsiteModule('MangaChanRU', 'http://mangachan.me'); - AddWebsiteModule('HentaiChanRU', 'http://henchan.me'); + AddWebsiteModule('HentaiChanRU', 'http://hentai-chan.me/'); AddWebsiteModule('YaoiChanRU', 'http://yaoichan.me'); end; From ddaaa50566d44941b13cd82defe6219f98ce2a7b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 23 Jan 2018 16:02:42 +0300 Subject: [PATCH 1972/2794] update en localization --- mangadownloader/languages/fmd.en.po | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d25a830e3..543bc1ab0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -352,10 +352,9 @@ msgstr "System will shutdown in %d second." #: frmtransferfavorites.rs_all msgctxt "frmtransferfavorites.rs_all" msgid "All" -msgstr "" +msgstr "All" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" msgstr "Invalid" @@ -363,7 +362,7 @@ msgstr "Invalid" #: frmtransferfavorites.rs_valid msgctxt "frmtransferfavorites.rs_valid" msgid "Valid" -msgstr "" +msgstr "Valid" #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" @@ -483,15 +482,6 @@ msgstr "Favorite list" msgid "Manga list" msgstr "Manga list" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1665,7 +1655,7 @@ msgstr "Open ..." #: tmainform.mifavoritesrename.caption msgid "Rename" -msgstr "" +msgstr "Rename" #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" @@ -1674,7 +1664,7 @@ msgstr "Stop check for new chapter" #: tmainform.mifavoritestransferwebsite.caption msgctxt "tmainform.mifavoritestransferwebsite.caption" msgid "Transfer website" -msgstr "" +msgstr "Transfer website" #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" @@ -2021,24 +2011,23 @@ msgstr "OK" #: ttransferfavoritesform.caption msgid "Transfer Favorites" -msgstr "" +msgstr "Transfer Favorites" #: ttransferfavoritesform.ckcleardownloadedchapters.caption msgid "Clear downloaded chapter list and reload from server" -msgstr "" +msgstr "Clear downloaded chapter list and reload from server" #: ttransferfavoritesform.lbtransferto.caption msgctxt "ttransferfavoritesform.lbtransferto.caption" msgid "Transfer to" -msgstr "" +msgstr "Transfer to" #: ttransferfavoritesform.rball.caption msgctxt "ttransferfavoritesform.rball.caption" msgid "All" -msgstr "" +msgstr "All" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" msgstr "Invalid" @@ -2046,7 +2035,7 @@ msgstr "Invalid" #: ttransferfavoritesform.rbvalid.caption msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" -msgstr "" +msgstr "Valid" #: ttransferfavoritesform.vtfavs.header.columns[1].text #, fuzzy From d3c3a60233c0102cec29752c8689c0b25a97db64 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 23 Jan 2018 16:43:33 +0300 Subject: [PATCH 1973/2794] mangatown, remove featured page fixes #778 --- baseunits/includes/MangaTown/chapter_page_number.inc | 3 ++- baseunits/includes/MangaTown/image_url.inc | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/baseunits/includes/MangaTown/chapter_page_number.inc b/baseunits/includes/MangaTown/chapter_page_number.inc index 80776d70d..6fe3fc2f6 100644 --- a/baseunits/includes/MangaTown/chapter_page_number.inc +++ b/baseunits/includes/MangaTown/chapter_page_number.inc @@ -30,7 +30,8 @@ Break; end; if isExtractPage and - (Pos('<option', parse[i]) > 0) then + (Pos('<option', parse[i]) > 0) and + (Pos('featured', parse[i]) = 0) then begin Inc(Task.Container.PageNumber); end; diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc index f6f2d979d..141a1e977 100644 --- a/baseunits/includes/MangaTown/image_url.inc +++ b/baseunits/includes/MangaTown/image_url.inc @@ -4,6 +4,12 @@ l: TStringList; s: String; begin + if (WorkId = Task.Container.PageLinks.Count - 1) and (Pos('/featured.', URL) <> 0) then + begin + Task.Container.PageLinks.Delete(WorkId); + Exit; + end; + l := TStringList.Create; s := AppendURLDelim(FillMangaSiteHost(MANGATOWN_ID, URL)); if WorkId > 0 then From 95e26237c5fec98a90b5bb4f3c7639b5d7591909 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 24 Jan 2018 07:05:39 +0300 Subject: [PATCH 1974/2794] enable high dpi support fixes #865 --- mangadownloader/forms/frmAccountSet.lfm | 1 + mangadownloader/forms/frmMain.lfm | 12 +++++++++--- mangadownloader/forms/frmMain.pas | 8 ++++++++ mangadownloader/forms/frmWebsiteSelection.lfm | 2 +- mangadownloader/md.lpi | 4 ++++ mangadownloader/md.lpr | 1 + 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmAccountSet.lfm b/mangadownloader/forms/frmAccountSet.lfm index 37ca9af35..1dc066d5e 100644 --- a/mangadownloader/forms/frmAccountSet.lfm +++ b/mangadownloader/forms/frmAccountSet.lfm @@ -3,6 +3,7 @@ object AccountSetForm: TAccountSetForm Height = 234 Top = 229 Width = 269 + BorderStyle = bsDialog ActiveControl = cbWebsiteName Caption = 'Account' ChildSizing.LeftRightSpacing = 8 diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 8aa214eea..ea0101f08 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2285,6 +2285,7 @@ object MainForm: TMainForm ClientHeight = 498 ClientWidth = 761 object vtFavorites: TVirtualStringTree + AnchorSideTop.Control = edFavoritesSearch AnchorSideTop.Side = asrBottom Left = 0 Height = 463 @@ -2292,6 +2293,7 @@ object MainForm: TMainForm Width = 761 Align = alBottom Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Top = 3 Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight Colors.SelectionRectangleBorderColor = clHotLight @@ -4417,11 +4419,14 @@ object MainForm: TMainForm ClientHeight = 498 ClientWidth = 761 object btCheckLatestVersion: TBitBtn + AnchorSideTop.Control = pcAbout + AnchorSideTop.Side = asrBottom Left = 0 Height = 40 Top = 447 Width = 208 - Anchors = [akLeft, akBottom] + BorderSpacing.Top = 3 + Anchors = [akTop, akLeft, akBottom] Caption = 'Check for latest version' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -4465,11 +4470,12 @@ object MainForm: TMainForm object btAbortCheckLatestVersion: TSpeedButton AnchorSideLeft.Control = btCheckLatestVersion AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btCheckLatestVersion Left = 212 Height = 40 Top = 447 Width = 40 - Anchors = [akLeft, akBottom] + Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 @@ -4513,7 +4519,7 @@ object MainForm: TMainForm object btVisitMyBlog: TBitBtn AnchorSideLeft.Control = btAbortCheckLatestVersion AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = btAbortCheckLatestVersion + AnchorSideTop.Control = btCheckLatestVersion Left = 256 Height = 40 Top = 447 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e65e0a564..9dddd534c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1196,6 +1196,8 @@ procedure TMainForm.FormCreate(Sender: TObject); ChildSizing.LeftRightSpacing := 0; ChildSizing.TopBottomSpacing := 0; Show; + if Screen.PixelsPerInch > 96 then + AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); end; WebsiteOptionCustomForm := TCustomOptionForm.Create(Self); @@ -1205,6 +1207,8 @@ procedure TMainForm.FormCreate(Sender: TObject); BorderStyle := bsNone; Align := alClient; Show; + if Screen.PixelsPerInch > 96 then + AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); end; WebsiteOptionAdvancedForm := TWebsiteOptionAdvancedForm.Create(Self); @@ -1214,6 +1218,8 @@ procedure TMainForm.FormCreate(Sender: TObject); BorderStyle := bsNone; Align := alClient; Show; + if Screen.PixelsPerInch > 96 then + AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); end; CustomColorForm := TCustomColorForm.Create(Self); @@ -1223,6 +1229,8 @@ procedure TMainForm.FormCreate(Sender: TObject); BorderStyle := bsNone; Align := alClient; Show; + if Screen.PixelsPerInch > 96 then + AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); AddVT(Self.vtMangaList); AddVT(Self.clbChapterList); AddVT(Self.vtDownload); diff --git a/mangadownloader/forms/frmWebsiteSelection.lfm b/mangadownloader/forms/frmWebsiteSelection.lfm index 0a3dcb07e..d7c0eebe1 100644 --- a/mangadownloader/forms/frmWebsiteSelection.lfm +++ b/mangadownloader/forms/frmWebsiteSelection.lfm @@ -3,7 +3,7 @@ object WebsiteSelectionForm: TWebsiteSelectionForm Height = 75 Top = 182 Width = 310 - BorderStyle = bsSizeToolWin + BorderStyle = bsDialog Caption = 'Select a website' ChildSizing.LeftRightSpacing = 10 ChildSizing.TopBottomSpacing = 10 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 635d03731..587c3c8de 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -7,8 +7,12 @@ <SessionStorage Value="InProjectDir"/> <MainUnit Value="0"/> <Title Value="Free Manga Downloader"/> + <Scaled Value="True"/> <ResourceType Value="res"/> <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> <Icon Value="0"/> </General> <i18n> diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 6d8957291..e8db1967a 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -26,6 +26,7 @@ {$R *.res} begin + Application.Scaled := True; with TIniFile.Create(CONFIG_FILE) do try CheckInstance := ReadBool('general', 'OneInstanceOnly', True); From 03bf6874cd338ff99a3221996b3ce3bd6235531f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 24 Jan 2018 07:37:05 +0300 Subject: [PATCH 1975/2794] add mangahub support fixes #765 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaHubRU.pas | 127 +++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaHubRU.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 715c85d4f..2c36a6692 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -21,6 +21,7 @@ uses Hakihome, MangaChanRU, MintMangaRU, + MangaHubRU, AcademyVN, Webtoons, Tsumino, diff --git a/baseunits/modules/MangaHubRU.pas b/baseunits/modules/MangaHubRU.pas new file mode 100644 index 000000000..6113915db --- /dev/null +++ b/baseunits/modules/MangaHubRU.pas @@ -0,0 +1,127 @@ +unit MangaHubRU; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr; + +implementation + +const + dirurl = '/explore?search[sort]=date'; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + query: TXQueryEngineHTML; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then + begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(Document); + try + if title = '' then title := query.XPathString('//div[@class="b-group-head__desc"]/h1'); + coverLink := MaybeFillHost(Module.RootURL, query.XPathString('//div[@class="manga-section-image__img"]/img/@src')); + authors := query.XPathString('//a[@itemprop="author"]'); + summary:= query.XPathString('//div[@itemprop="description"]'); + genres := query.XPathStringAll('//div[@class="b-dtl-desc__labels"]/a'); + query.XPathHREFAll('//div[@class="b-ovf-table"]/div[@class="b-ovf-table__elem"]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + query.Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//div[contains(@class, "b-reader__full")]/@data-js-scans'); + s := ReplaceString(s, '\/', '/'); + if s <> '' then begin + ParseHTML(s); + for v in XPath('json(*)()("src")') do begin + s := ReplaceString(v.toString, '\/', '/'); + PageLinks.Add(MaybeFillHost(Module.RootURL, s)); + end; + end; + finally + Free; + end; + end; +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('//div[@class="pagination"]/ul/li[last()-1]/a'); + Page := StrToIntDef(s, 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '&page=' + IncStr(AURL)) then begin + Result := NO_ERROR; + XPathHREFAll('//div[@class="list-element__name"]/a', + MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaHubRU'; + RootURL := 'https://mangahub.ru'; + SortedList := True; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + end; +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index c97e8861d..73833a27f 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,7 +14,7 @@ Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas Raw=RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType -Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU +Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom From 165b43d927d64c1bc9ebe005d0b38e4cf218372e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 24 Jan 2018 08:59:07 +0300 Subject: [PATCH 1976/2794] add mangadex support fixes #845 --- baseunits/ModuleList.inc | 1 + baseunits/modules/Mangadex.pas | 171 +++++++++++++++++++++++++ config/mangalist.ini | 2 +- mangadownloader/languages/fmd.de.po | 12 ++ mangadownloader/languages/fmd.el_GR.po | 12 ++ mangadownloader/languages/fmd.en.po | 12 ++ mangadownloader/languages/fmd.es.po | 12 ++ mangadownloader/languages/fmd.id_ID.po | 12 ++ mangadownloader/languages/fmd.pl_PL.po | 12 ++ mangadownloader/languages/fmd.po | 12 ++ mangadownloader/languages/fmd.pt_BR.po | 12 ++ mangadownloader/languages/fmd.ru_RU.po | 12 ++ 12 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Mangadex.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 2c36a6692..191674f60 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -60,6 +60,7 @@ uses TruyenTranhTuan, BlogTruyen, MangaAe, + Mangadex, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas new file mode 100644 index 000000000..f117e37ea --- /dev/null +++ b/baseunits/modules/Mangadex.pas @@ -0,0 +1,171 @@ +unit Mangadex; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr, URIParser, FMDVars; + +implementation + +const + PerPage = 100; + +var + showalllang: Boolean = False; + showscangroup: Boolean = False; + +resourcestring + RS_ShowAllLang = 'Show all language'; + RS_ShowScanGroup = 'Show scanlation group'; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s, lang, group: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + Cookies.Values['mangadex_h_toggle'] := '1'; + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + if title = '' then title := XPathString('//h3[@class="panel-title"]/text()'); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@alt="Manga image"]/@src')); + authors := XPathString('//th[contains(., "Author")]/following-sibling::td/a'); + artists := XPathString('//th[contains(., "Artist")]/following-sibling::td/a'); + genres := XPathStringAll('//th[contains(., "Genres")]/following-sibling::td/span'); + summary := XPathString('//th[contains(., "Description")]/following-sibling::td'); + status := MangaInfoStatusIfPos(XPathString('//th[contains(., "Status")]/following-sibling::td')); + if showalllang then + s := '//div[contains(@class, "tab-content")]//table/tbody/tr/td[1]/a' + else + s := '//div[contains(@class, "tab-content")]//table/tbody/tr[td[2]/img/@title="English"]/td[1]/a'; + for v in XPath(s) do begin + chapterLinks.Add(v.toNode().getAttribute('href')); + s := v.toString(); + if showalllang then begin + lang := XPathString('parent::td/parent::tr/td[2]/img/@title', v); + if lang <> '' then s := s + ' [' + lang + ']'; + end; + if showscangroup then begin + group := XPathString('parent::td/parent::tr/td[3]/a', v); + if group <> '' then s := s + ' [' + group + ']'; + end; + chapterName.Add(s); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + uri: TURI; + s: String; + i: Integer; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + Cookies.Values['mangadex_h_toggle'] := '1'; + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="current_page"]/@src')); + PageNumber:= XPathCount('//select[@id="jump_page"]/option'); + uri := ParseURI(s); + for i := 1 to PageNumber do begin + uri.Document := IntToStr(i) + ExtractFileExt(uri.Document); + PageLinks.Add(EncodeURI(uri)); + end; + finally + Free; + end; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + s := IntToStr(StrToInt(AURL) * PerPage); + MangaInfo.FHTTP.Cookies.Values['mangadex_h_toggle'] := '1'; + // FIXME: /titles shows titles in alphabetical order rather than last updated + // maybe it will be changed in future + if MangaInfo.FHTTP.GET(Module.RootURL + '/titles/' + s) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + updateList.CurrentDirectoryPageNumber := 1; + XPathHREFAll('//table/tbody/tr/td[2]/a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.FHTTP.Cookies.Values['mangadex_h_toggle'] := '1'; + // FIXME: /titles shows titles in alphabetical order rather than last updated + // maybe it will be changed in future + if MangaInfo.FHTTP.GET(Module.RootURL + '/titles') then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + s := XPathString('//li[@class="paging"]/a[contains(span/@title, "last")]/@href'); + if s <> '' then begin + s := ReplaceRegExpr('^.+\/(\d+)$', s, '$1', True); + Page := (StrToIntDef(s, 0) div PerPage) + 1; + end; + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do begin + Website := 'Mangadex'; + RootURL := 'https://mangadex.com'; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); + AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); + end; +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index 73833a27f..ad3ebd4ac 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 81f2b3b43..ea8390fd1 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -31,10 +31,12 @@ msgstr "" "CDN2 (testing)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Zeige alle Sprachen" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Zeige Scanlation Group" @@ -377,6 +379,16 @@ msgstr "Schlüssel:" msgid "Use Google DCP" msgstr "" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Zeige alle Sprachen" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Zeige Scanlation Group" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Entferne Wasserzeichen" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 2eb38265c..7a7c0f86e 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -35,10 +35,12 @@ msgstr "" "CDN2 (δοκιμαστικά)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Εμφάνιση όλων των γλωσσών" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Εμφάνιση ομάδας scanlation" @@ -381,6 +383,16 @@ msgstr "Κλειδί:" msgid "Use Google DCP" msgstr "" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Εμφάνιση όλων των γλωσσών" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Εμφάνιση ομάδας scanlation" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Αφαίρεση υδατογραφήματος" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 543bc1ab0..5fb9363f0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -31,10 +31,12 @@ msgstr "" "CDN2 (testing)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Show all language" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Show scanlation group" @@ -376,6 +378,16 @@ msgstr "Key:" msgid "Use Google DCP" msgstr "Use Google DCP" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Show all language" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Show scanlation group" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Remove watermark" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 399af1203..a2db5982f 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -31,10 +31,12 @@ msgstr "" "CDN2 (Pruebando)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Mostrar todos los idiomas" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Mostrar Grupo de Scanlation" @@ -375,6 +377,16 @@ msgstr "Llave:" msgid "Use Google DCP" msgstr "Usar Google DCP" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Mostrar todos los idiomas" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Mostrar Grupo de Scanlation" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Quitar Marca de Agua" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 41d260ffd..e95082ad6 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -31,10 +31,12 @@ msgstr "" "CDN2 (testing)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Tampilkan semua bahasa" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Tampilkan nama grup scan" @@ -375,6 +377,16 @@ msgstr "Key:" msgid "Use Google DCP" msgstr "Gunakan Google DCP" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Tampilkan semua bahasa" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Tampilkan nama grup scan" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Hapus watermark" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index a6eed446b..77836a7ae 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -26,10 +26,12 @@ msgid "" msgstr "" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Pokaż wszystkie języki" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Pokaż grupę skanlacja" @@ -372,6 +374,16 @@ msgstr "" msgid "Use Google DCP" msgstr "" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Pokaż wszystkie języki" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Pokaż grupę skanlacja" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Usuń znak wodny" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c2e472b54..c9efc0fa3 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -15,10 +15,12 @@ msgid "" msgstr "" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "" @@ -334,6 +336,16 @@ msgstr "" msgid "Use Google DCP" msgstr "" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index b799f721d..a3d72810d 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -31,10 +31,12 @@ msgstr "" "CDN2 (testando)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Exibir todos os idiomas" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Exibir grupo de scans" @@ -377,6 +379,16 @@ msgstr "Chave:" msgid "Use Google DCP" msgstr "Usar Google DCP" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Exibir todos os idiomas" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Exibir grupo de scans" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Remover a marca d'água" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 751ba76ec..d0b60ebaa 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -30,10 +30,12 @@ msgstr "" "CDN2 (тестовый)\n" #: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" msgid "Show all language" msgstr "Показать все языки" #: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" msgid "Show scanlation group" msgstr "Показать группу сканирования" @@ -373,6 +375,16 @@ msgstr "Ключ:" msgid "Use Google DCP" msgstr "" +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Показать все языки" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Показать группу сканирования" + #: mangafox.rs_removewatermark msgid "Remove watermark" msgstr "Удалить водяные знаки" From 6ab162c285371d2ca91d25fc5c93706cb8dcb7b2 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Wed, 24 Jan 2018 18:28:09 +0300 Subject: [PATCH 1977/2794] Turkish translation Translated FMD into Turkish language. --- mangadownloader/languages/fmd.tr.po | 2320 +++++++++++++++++++++++++++ updater/languages/updater.tr_TR.po | 108 ++ 2 files changed, 2428 insertions(+) create mode 100644 mangadownloader/languages/fmd.tr.po create mode 100644 updater/languages/updater.tr_TR.po diff --git a/mangadownloader/languages/fmd.tr.po b/mangadownloader/languages/fmd.tr.po new file mode 100644 index 000000000..53ac884a4 --- /dev/null +++ b/mangadownloader/languages/fmd.tr.po @@ -0,0 +1,2320 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: Tmp341 <tmp341@gmail.com>\n" +"Language-Team: Tmp341\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: tr\n" +"X-Generator: Poedit 2.0.6\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-SourceCharset: UTF-8\n" + +#: batoto.rs_serverselection +msgid "Image server:" +msgstr "Resim sunucusu:" + +#: batoto.rs_serverselectionitems +msgid "" +"Auto\n" +"Image Server EU\n" +"Image Server NA\n" +"CDN (default)\n" +"CDN2 (testing)\n" +msgstr "" +"Otomatik\n" +"Resim Sunucusu AB\n" +"Resim Sunucusu KA\n" +"CDN (varsayılan)\n" +"CDN2 (test)\n" + +#: batoto.rs_showalllang +msgctxt "batoto.rs_showalllang" +msgid "Show all language" +msgstr "Tüm dilleri göster" + +#: batoto.rs_showscangroup +msgctxt "batoto.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Scanlation grubunu göster" + +#: ehentai.rs_downloadoriginalimage +msgid "Download original image(require ExHentai account)" +msgstr "Orijinal resmi indir(ExHentai hesabı gerektirir)" + +#: ehentai.rs_settingsimagesize +#| msgid "Image size" +msgid "Image size:" +msgstr "Resim boyutu:" + +#: ehentai.rs_settingsimagesizeitems +msgid "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" +msgstr "" +"Oto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Orjinal\n" + +#: frmaccountmanager.rs_accountdeleteconfirmation +msgid "Are you sure you want to delete this account?" +msgstr "Bu hesabı silmek istediğinizden emin misiniz?" + +#: frmaccountmanager.rs_checking +msgid "Checking" +msgstr "Kontrol ediliyor" + +#: frmaccountmanager.rs_invalid +msgctxt "frmaccountmanager.rs_invalid" +msgid "Invalid" +msgstr "Geçersiz" + +#: frmaccountmanager.rs_unknown +msgid "Unknown" +msgstr "Bilinmeyen" + +#: frmaccountmanager.rs_valid +msgid "OK" +msgstr "Tamam" + +#: frmaccountset.rs_cantbeempty +msgid "Username or password can't be empty!" +msgstr "Kullanıcı adı veya şifre boş olamaz!" + +#: frmimportfavorites.rs_importcompleted +msgid "Import completed." +msgstr "İçe aktarma tamamlandı." + +#: frmimportfavorites.rs_listunimportedcaption +msgid "List of unimported manga" +msgstr "İçe aktarılmayan manga listesi" + +#: frmmain.rs_alldownloads +msgid "All downloads" +msgstr "Tüm indirmeler" + +#: frmmain.rs_btnok +msgctxt "frmmain.rs_btnok" +msgid "&OK" +msgstr "&Tamam" + +#: frmmain.rs_cancel +msgctxt "frmmain.rs_cancel" +msgid "Cancel" +msgstr "İptal" + +#: frmmain.rs_checking +msgid "Checking..." +msgstr "Kontrol ediliyor..." + +#: frmmain.rs_dlgcannotconnecttoserver +msgid "Cannot connect to the server." +msgstr "Sunucuya bağlanılamıyor." + +#: frmmain.rs_dlgcannotgetmangainfo +msgid "Cannot get manga info. Please check your internet connection and try it again." +msgstr "Manga bilgisi alınamıyor. Lütfen internet bağlantınızı kontrol edip tekrar deneyin." + +#: frmmain.rs_dlgdownloadcount +msgid "Download count:" +msgstr "İndirme sayısı:" + +#: frmmain.rs_dlgmangalistselect +msgid "You must choose at least 1 manga website!" +msgstr "En az 1 manga sitesi seçmelisin!" + +#: frmmain.rs_dlgquit +msgid "Are you sure you want to exit?" +msgstr "Çıkmak istediğine emin misin?" + +#: frmmain.rs_dlgremovefavorite +msgid "Are you sure you want to delete the favorite(s)?" +msgstr "Favori(leri) silmek istediğine emin misin?" + +#: frmmain.rs_dlgremovefinishtasks +msgid "Are you sure you want to delete all finished tasks?" +msgstr "Tamamlanmış indirmeleri silmek istediğine emin misin?" + +#: frmmain.rs_dlgremoveitem +msgid "Are you sure you want to delete this item(s)?" +msgstr "Bu kalemleri silmek istediğine emin misin?" + +#: frmmain.rs_dlgremovetask +msgid "Are you sure you want to delete the task(s)?" +msgstr "Görev(leri) silmek istediğine emin misin?" + +#: frmmain.rs_dlgsplitdownload +msgctxt "frmmain.rs_dlgsplitdownload" +msgid "Split download" +msgstr "Bölünmüş indirme" + +#: frmmain.rs_dlgtitleexistindllist +msgid "" +"This title are already in download list.\n" +"Do you want to download it anyway?\n" +msgstr "" +"Bu başlık zaten indirme listesinde.\n" +"Yine de indirmek istiyor musun?\n" + +#: frmmain.rs_dlgtypeinnewchapter +msgid "Type in new chapter:" +msgstr "Yeni bölüm gir:" + +#: frmmain.rs_dlgtypeinnewsavepath +msgid "Type in new save path:" +msgstr "Yeni kayıt yolu gir:" + +#: frmmain.rs_dlgupdaterisrunning +msgid "Updater is running!" +msgstr "Güncelleyici çalışıyor!" + +#: frmmain.rs_dlgupdaterwanttoupdatedb +msgid "Do you want to download manga list from the server?" +msgstr "Manga listesini sunucudan indirmek istiyor musun?" + +#: frmmain.rs_dlgurlnotsupport +msgid "URL not supported!" +msgstr "URL desteklenmiyor!" + +#: frmmain.rs_droptargetmodeitems +msgid "" +"Download all\n" +"Add to favorites\n" +msgstr "" +"Tümünü indir\n" +"Favorilere ekle\n" + +#: frmmain.rs_filterstatusitems +msgid "" +"Completed\n" +"Ongoing\n" +"<none>\n" +msgstr "" +"Tamamlanmış\n" +"Devam eden\n" +"<hiçbiri>\n" + +#: frmmain.rs_fmdalreadyrunning +msgid "Free Manga Downloader already running!" +msgstr "Free Manga Downloader zaten çalışıyor!" + +#: frmmain.rs_hintfavoriteproblem +msgid "" +"There is a problem with this data!\n" +"Removing and re-adding this data may fix the problem.\n" +msgstr "" +"Bu veriyle ilgili bir sorun var!\n" +"Silip tekrardan eklemek bu soruna çözüm olabilir.\n" + +#: frmmain.rs_history +msgid "History" +msgstr "Geçmiş" + +#: frmmain.rs_import +msgid "Import" +msgstr "İçe aktar" + +#: frmmain.rs_infoartists +msgid "Artist(s):" +msgstr "Çizer(ler):" + +#: frmmain.rs_infoauthors +msgid "Author(s):" +msgstr "Yazar(lar):" + +#: frmmain.rs_infogenres +msgid "Genre(s):" +msgstr "Tür(ler):" + +#: frmmain.rs_infostatus +msgid "Status:" +msgstr "Durum:" + +#: frmmain.rs_infosummary +msgid "Summary:" +msgstr "Özet:" + +#: frmmain.rs_infotitle +msgid "Title:" +msgstr "Başlık:" + +#: frmmain.rs_infowebsite +msgctxt "frmmain.rs_infowebsite" +msgid "Website:" +msgstr "Site:" + +#: frmmain.rs_inprogress +msgid "In progress" +msgstr "Devam ediyor" + +#: frmmain.rs_lblautochecknewchapterminute +msgctxt "frmmain.rs_lblautochecknewchapterminute" +msgid "Auto check for new chapter every %d minutes" +msgstr "Yeni bölümleri her %d dakikada bir kontrol et" + +#: frmmain.rs_lbloptionexternalparamshint +msgid "" +"%s : Path to the manga\n" +"%s : Chapter filename\n" +"\n" +"Example : \"%s%s\"\n" +msgstr "" +"%s : Manga yolu\n" +"%s : Bölüm dosya adı\n" +"\n" +"Örnek : \"%s%s\"\n" + +#: frmmain.rs_loading +msgid "Loading ..." +msgstr "Yükleniyor ..." + +#: frmmain.rs_modeall +msgid "Mode: Show all (%d)" +msgstr "Mod: Tümünü göster (%d)" + +#: frmmain.rs_modefiltered +msgid "Mode: Filtered (%d)" +msgstr "Mod: Filtrelenmiş (%d)" + +#: frmmain.rs_modesearching +#| msgid "Searching..." +msgctxt "frmmain.rs_modesearching" +msgid "Mode: Searching..." +msgstr "Mod: Aranıyor..." + +#: frmmain.rs_onemonth +msgid "One month" +msgstr "Bir ay" + +#: frmmain.rs_oneweek +msgid "One week" +msgstr "Bir hafta" + +#: frmmain.rs_optionfmddoitems +msgid "" +"Nothing\n" +"Exit\n" +"Shutdown\n" +"Hibernate\n" +msgstr "" +"Hiçbiri\n" +"Çıkış\n" +"Kapat\n" +"Uyku\n" + +#: frmmain.rs_selected +msgid "Selected: %d" +msgstr "Seçildi: %d" + +#: frmmain.rs_software +msgid "Software" +msgstr "Yazılım" + +#: frmmain.rs_softwarepath +msgctxt "frmmain.rs_softwarepath" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Yazılım yolu (mesela c:\\MangaDownloader)" + +#: frmmain.rs_today +msgid "Today" +msgstr "Bugün" + +#: frmmain.rs_wronginput +msgid "Invalid input!" +msgstr "Geçersiz giriş!" + +#: frmmain.rs_yesterday +msgid "Yesterday" +msgstr "Dün" + +#: frmshutdowncounter.rs_lblmessageexit +msgid "FMD will exit in %d second." +msgstr "FMD %d saniye içinde kapanacak." + +#: frmshutdowncounter.rs_lblmessagehibernate +msgid "System will hibernate in %d second." +msgstr "Sistem %d saniye içinde uykuya geçecek." + +#: frmshutdowncounter.rs_lblmessageshutdown +msgid "System will shutdown in %d second." +msgstr "Sistem %d saniye içinde kapanacak." + +#: frmtransferfavorites.rs_all +msgctxt "frmtransferfavorites.rs_all" +msgid "All" +msgstr "Tümü" + +#: frmtransferfavorites.rs_invalid +msgctxt "frmtransferfavorites.rs_invalid" +msgid "Invalid" +msgstr "Geçersiz" + +#: frmtransferfavorites.rs_valid +msgctxt "frmtransferfavorites.rs_valid" +msgid "Valid" +msgstr "Geçerli" + +#: kissmanga.rs_kissmanga_initvector +msgid "Initialization Vector:" +msgstr "Başlatma Vektörü:" + +#: kissmanga.rs_kissmanga_key +msgid "Key:" +msgstr "Anahtar:" + +#: kissmanga.rs_kissmanga_usegoogledcp +msgid "Use Google DCP" +msgstr "Google DCP kullan" + +#: mangadex.rs_showalllang +msgctxt "mangadex.rs_showalllang" +msgid "Show all language" +msgstr "Tüm dilleri göster" + +#: mangadex.rs_showscangroup +msgctxt "mangadex.rs_showscangroup" +msgid "Show scanlation group" +msgstr "Scanlation grubunu göster" + +#: mangafox.rs_removewatermark +msgid "Remove watermark" +msgstr "Filigranı kaldır" + +#: mangafox.rs_saveaspng +msgid "Save as PNG" +msgstr "PNG olarak kaydet" + +#: taccountmanagerform.btadd.caption +msgctxt "taccountmanagerform.btadd.caption" +msgid "Add" +msgstr "Ekle" + +#: taccountmanagerform.btdelete.caption +msgctxt "taccountmanagerform.btdelete.caption" +msgid "Delete" +msgstr "Sil" + +#: taccountmanagerform.btedit.caption +msgctxt "taccountmanagerform.btedit.caption" +msgid "Edit" +msgstr "Düzenle" + +#: taccountmanagerform.btrefresh.caption +msgid "Refresh" +msgstr "Yenile" + +#: taccountmanagerform.vtaccountlist.header.columns[1].text +#| msgid "Username" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgid "Website" +msgstr "Site" + +#: taccountmanagerform.vtaccountlist.header.columns[2].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgid "Username" +msgstr "Kullanıcı Adı" + +#: taccountmanagerform.vtaccountlist.header.columns[3].text +#| msgid "Status" +msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgid "Status" +msgstr "Durum" + +#: taccountsetform.btcancel.caption +msgctxt "taccountsetform.btcancel.caption" +msgid "Cancel" +msgstr "İptal" + +#: taccountsetform.btok.caption +msgid "Ok" +msgstr "Tamam" + +#: taccountsetform.ckshowpassword.caption +msgid "Show password" +msgstr "Şifreyi göster" + +#: taccountsetform.edpassword.texthint +msgctxt "taccountsetform.edpassword.texthint" +msgid "Password" +msgstr "Şifre" + +#: taccountsetform.edusername.texthint +#| msgid "Status" +msgctxt "taccountsetform.edusername.texthint" +msgid "Username" +msgstr "Kullanıcı Adı" + +#: taccountsetform.label1.caption +#| msgid "Username" +msgctxt "taccountsetform.label1.caption" +msgid "Website" +msgstr "Site" + +#: taccountsetform.label2.caption +#| msgid "Status" +msgctxt "taccountsetform.label2.caption" +msgid "Username" +msgstr "Kullanıcı Adı" + +#: taccountsetform.label3.caption +msgctxt "taccountsetform.label3.caption" +msgid "Password" +msgstr "Şifre" + +#: tcustomcolorform.caption +msgid "CustomColorForm" +msgstr "KişiselRenkFromu" + +#: tcustomcolorform.tsbasiclist.caption +msgid "Basic list" +msgstr "Basit Liste" + +#: tcustomcolorform.tschapterlist.caption +msgid "Chapter list" +msgstr "Bölüm Listesi" + +#: tcustomcolorform.tsfavoritelist.caption +msgid "Favorite list" +msgstr "Favori Listesi" + +#: tcustomcolorform.tsmangalist.caption +msgid "Manga list" +msgstr "Manga Listesi" + +#: tformdroptarget.miaddtofavorites.caption +msgctxt "tformdroptarget.miaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Favorilere ekle" + +#: tformdroptarget.miclose.caption +msgid "&Close" +msgstr "&Kapat" + +#: tformdroptarget.midownloadall.caption +msgctxt "tformdroptarget.midownloadall.caption" +msgid "Download all" +msgstr "Tümünü İndir" + +#: tformlogger.btnclearlog.caption +msgid "Clear" +msgstr "Temizle" + +#: tformlogger.ckstayontop.caption +msgid "Stay on top" +msgstr "Üstte kal" + +#: tformlogger.lbloglimit.caption +msgid "Log limit" +msgstr "Günlük limiti" + +#: tformlogger.micopy.caption +msgctxt "tformlogger.micopy.caption" +msgid "Copy" +msgstr "Kopyala" + +#: timportfavorites.btcancel.caption +msgctxt "TIMPORTFAVORITES.BTCANCEL.CAPTION" +msgid "Cancel" +msgstr "İptal" + +#: timportfavorites.btimport.caption +msgctxt "timportfavorites.btimport.caption" +msgid "&OK" +msgstr "&Tamam" + +#: timportfavorites.cbsoftware.text +msgid "Domdomsoft Manga Downloader" +msgstr "Domdomsoft Manga İndirici" + +#: timportfavorites.edpath.texthint +msgctxt "timportfavorites.edpath.texthint" +msgid "Path to the software (e.g. C:\\MangaDownloader)" +msgstr "Yazılım yolu (mesela c:\\MangaDownloader)" + +#: timportfavorites.lbselectsoftware.caption +msgid "Software:" +msgstr "Yazılım:" + +#: tmainform.btabortupdatelist.hint +msgid "Abort update list" +msgstr "Liste güncellemeyi iptal et" + +#: tmainform.btaddtofavorites.caption +msgctxt "tmainform.btaddtofavorites.caption" +msgid "Add to favorites" +msgstr "Favorilere ekle" + +#: tmainform.btchecklatestversion.caption +#| msgid "Check for new version" +msgctxt "tmainform.btchecklatestversion.caption" +msgid "Check for latest version" +msgstr "Son sürümü kontrol et" + +#: tmainform.btclearlogfile.caption +msgid "Clear log file" +msgstr "Günlük dosyasını temizle" + +#: tmainform.btdownload.caption +msgctxt "tmainform.btdownload.caption" +msgid "Download" +msgstr "İndir" + +#: tmainform.btdownloadsplit.hint +msgctxt "tmainform.btdownloadsplit.hint" +msgid "Split download" +msgstr "Bölünmüş indirme" + +#: tmainform.btfavoriteschecknewchapter.caption +msgctxt "tmainform.btfavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Yeni bölümü kontrol et" + +#: tmainform.btfavoritesimport.caption +msgid "Import list" +msgstr "Listeyi içe aktar" + +#: tmainform.btfilter.caption +msgctxt "TMAINFORM.BTFILTER.CAPTION" +msgid "Filter" +msgstr "Filtre" + +#: tmainform.btfilterreset.caption +msgid "Reset value" +msgstr "Değeri sıfırla" + +#: tmainform.btopenlog.caption +msgid "Open log" +msgstr "Günlüğü aç" + +#: tmainform.btoptionapply.caption +msgid "Apply" +msgstr "Uygula" + +#: tmainform.btreadonline.caption +msgid "Read online" +msgstr "Çevrimiçi oku" + +#: tmainform.btremovefilterlarge.caption +msgctxt "TMAINFORM.BTREMOVEFILTERLARGE.CAPTION" +msgid "Remove filter" +msgstr "Filtreyi kaldır" + +#: tmainform.btremovefilterlarge.hint +msgctxt "tmainform.btremovefilterlarge.hint" +msgid "Remove filter" +msgstr "Filtreyi kaldır" + +#: tmainform.btupdatelist.hint +msgctxt "tmainform.btupdatelist.hint" +msgid "Update manga list" +msgstr "Manga listesini güncelle" + +#: tmainform.btvisitmyblog.caption +msgid "Visit my blog" +msgstr "Blogumu ziyaret et" + +#: tmainform.caption +msgid "Free Manga Downloader" +msgstr "Free Manga Downloader" + +#: tmainform.cbaddasstopped.caption +msgid "Add to download list as stopped task" +msgstr "İndirme listesine durdurulmuş görev olarak ekle" + +#: tmainform.cbfilterstatus.text +msgid "<none>" +msgstr "<hiçbiri>" + +#: tmainform.cbonlynew.caption +msgid "Search only new manga" +msgstr "Sadece yeni manga ara" + +#: tmainform.cboptionautocheckfavdownload.caption +msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgid "Automatic download after finish checking" +msgstr "Kontrol bittikten sonra oto indir" + +#: tmainform.cboptionautocheckfavinterval.caption +msgid "Auto check for new chapter in an interval" +msgstr "Beklerken yeni bölümleri oto kontrol et" + +#: tmainform.cboptionautocheckfavremovecompletedmanga.caption +msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgid "Automatic remove completed manga from Favorites" +msgstr "Tamamlanmış mangayı Favorilerden oto kaldır" + +#: tmainform.cboptionautocheckfavstartup.caption +#| msgid "Automatic check for new chapter at startup" +msgid "Auto check for new chapter at startup" +msgstr "Başlangıça yeni bölümleri oto kontrol et" + +#: tmainform.cboptionautochecklatestversion.caption +#| msgid "Check for new version " +msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgid "Auto check for latest version " +msgstr "Son sürümü oto kontrol et " + +#: tmainform.cboptionautoopenfavstartup.caption +msgid "Open Favorites at startup" +msgstr "Başlangıçta Favorileri aç" + +#: tmainform.cboptionchangeunicodecharacter.caption +#| msgid "Change all all character to" +msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgid "Replace all unicode character with" +msgstr "Tüm Unicode karakteri şununla değiştir" + +#: tmainform.cboptionchangeunicodecharacter.hint +msgid "Enable this if you have problem with unicode character in path." +msgstr "Yolda Unicode karakter varsa bunu açın." + +#: tmainform.cboptiondigitchapter.caption +msgid "Chapter" +msgstr "Bölüm" + +#: tmainform.cboptiondigitvolume.caption +msgid "Volume" +msgstr "Cilt" + +#: tmainform.cboptionenableloadcover.caption +msgid "Enable load manga cover" +msgstr "Manga afişini yüklemeyi aç" + +#: tmainform.cboptiongeneratechapterfolder.caption +msgid "Auto generate chapter folder" +msgstr "Bölüm klasörünü oto oluştur" + +#: tmainform.cboptiongeneratemangafolder.caption +msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgid "Auto generate folder based on manga's name" +msgstr "Klasörü manga adına göre oto oluştur" + +#: tmainform.cboptionlivesearch.caption +msgid "Enable live search (slow on long list)" +msgstr "Canlı taramayı etkinleştir (kalabalık listelerde yavaş)" + +#: tmainform.cboptionminimizeonstart.caption +msgid "Minimize on start" +msgstr "Başlangıça küçült" + +#: tmainform.cboptionminimizetotray.caption +msgid "Minimize to tray" +msgstr "Görev çubuğuna küçült" + +#: tmainform.cboptiononeinstanceonly.caption +msgid "Permit only one FMD running" +msgstr "Sadece bir FMD çalıştırmaya izin ver" + +#: tmainform.cboptionproxytype.text +msgid "HTTP" +msgstr "HTTP" + +#: tmainform.cboptionremovemanganamefromchapter.caption +msgid "Remove manga name from chapter" +msgstr "Manga ismini bölümden kaldır" + +#: tmainform.cboptionshowballoonhint.caption +msgid "Show balloon hint" +msgstr "Yardım balonlarını göster" + +#: tmainform.cboptionshowdeletetaskdialog.caption +msgid "Delete task/favorite" +msgstr "Görevi/favoriyi sil" + +#: tmainform.cboptionshowdownloadmangalistdialog.caption +msgid "Download manga list if empty" +msgstr "Boşsa manga listesini indir" + +#: tmainform.cboptionshowdownloadtoolbar.caption +msgid "Show downloads toolbar" +msgstr "İndirmeler araç çubuğunu göster" + +#: tmainform.cboptionshowdownloadtoolbardeleteall.caption +msgid "Show \"Delete all completed tasks\" in downloads toolbar" +msgstr "\"Tüm tamamlanmış görevleri sili\" indirmeler araç çubuğunda göster" + +#: tmainform.cboptionshowquitdialog.caption +msgid "Exit FMD" +msgstr "FMD'den çık" + +#: tmainform.cboptionupdatelistnomangainfo.caption +msgid "Don't load manga information when updating list (filter will be not work!)" +msgstr "Listeyi güncellerken manga bilgisini yükleme (filtre çalışmayabilir)" + +#: tmainform.cboptionupdatelistremoveduplicatelocaldata.caption +msgid "Remove duplicate local data when updating manga list" +msgstr "Manga listesini güncellerken çift yerel veriyi kaldır" + +#: tmainform.cboptionuseproxy.caption +msgid "Use proxy" +msgstr "Proxy kullan" + +#: tmainform.cbsearchfromallsites.caption +msgid "Search in all manga sites" +msgstr "Tüm manga sitelerinde ara" + +#: tmainform.cbselectmanga.hint +msgid "For more manga sites, please go to Options->Manga sites" +msgstr "Daha fazla manga sitesi için, lütfen Ayarlar->Manga siteleri'ne gidin" + +#: tmainform.cbuseregexpr.caption +msgid "Regular Expression" +msgstr "Düzenli İfadeler" + +#: tmainform.ckdroptarget.caption +msgctxt "tmainform.ckdroptarget.caption" +msgid "Show Drop Box" +msgstr "İndirme Kutusunu Göster" + +#: tmainform.ckenablelogging.caption +msgid "Enable logging" +msgstr "Günlüklemeyi Aç" + +#: tmainform.ckfilteraction.caption +msgid "Action" +msgstr "Aksiyon" + +#: tmainform.ckfilteraction.hint +msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." +msgstr "Dövüş, şiddet, kaos ve olayların hızla geliştiği bir çalışma." + +#: tmainform.ckfilteradult.caption +msgid "Adult" +msgstr "Yetişkin" + +#: tmainform.ckfilteradult.hint +msgid "Contains content that is suitable only for adults. Titles in this category may include prolonged scenes of intense violence and/or graphic sexual content and nudity." +msgstr "Sadece yetişkenlere uygun içerik barındırır. Bu kategorideki içerikler, uzun süreli yoğun şiddet ve/veya cinsel içerik ve çıplaklık içerebilir." + +#: tmainform.ckfilteradventure.caption +msgid "Adventure" +msgstr "Macera" + +#: tmainform.ckfilteradventure.hint +msgid "If a character in the story goes on a trip or along that line, your best bet is that it is an adventure manga. Otherwise, it's up to your personal prejudice on this case." +msgstr "Eğer hikayedeki bir karakter bir geziye ya da ona benzer bir şeye giderse, en yüksek ihtimalle o bir macera mangasıdır. Aksi halde, bu durumda sizin kişisel yargınıza kalmış." + +#: tmainform.ckfiltercomedy.caption +msgid "Comedy" +msgstr "Komedi" + +#: tmainform.ckfiltercomedy.hint +msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." +msgstr "Hafif ve çoğu zaman gülünç olan ya da tonlamasında yergi içeren ve çoğunlukla tematik çatışmanın mutlu bir şekilde çözülmesini içeren dramatik bir çalışma." + +#: tmainform.ckfilterdoujinshi.caption +msgid "Doujinshi" +msgstr "Doujinshi" + +#: tmainform.ckfilterdoujinshi.hint +msgid "Fan based work inpspired by official manga/anime." +msgstr "Resmi bir mangadan/animeden esinlenerek yapılmış hayran temelli çalışma." + +#: tmainform.ckfilterdrama.caption +msgid "Drama" +msgstr "Dram" + +#: tmainform.ckfilterdrama.hint +msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." +msgstr "Keder vererek ya da gererek duyguları etkilemek üzere yapılmış bir çalışma." + +#: tmainform.ckfilterechi.caption +msgid "Ecchi" +msgstr "Ecchi" + +#: tmainform.ckfilterechi.hint +msgid "Possibly the line between hentai and non-hentai, ecchi usually refers to fanservice put in to attract a certain group of fans." +msgstr "Hentai ile hentai-olmayan içerik arasında bir çizgi olan ecchi, çoğunlukla belli bir grup hayranı etkilemek üzere hazırlanmış bir hayran hizmetidir." + +#: tmainform.ckfilterfantasy.caption +msgid "Fantasy" +msgstr "Fantastik" + +#: tmainform.ckfilterfantasy.hint +msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." +msgstr "Sihir, hayal dünyası ve masalları içeren fakat bunlarla sınırlı olmayan çalışmaların tamamı." + +#: tmainform.ckfiltergenderbender.caption +msgid "Gender Bender" +msgstr "Gender Bender" + +#: tmainform.ckfiltergenderbender.hint +msgid "" +"Girls dressing up as guys, guys dressing up as girls.\n" +"Guys turning into girls, girls turning into guys.\n" +msgstr "" +"Kızlar erkek gibi giyinebilir, erkekler kız gibi giyinebilir.\n" +"Erkekler kıza dönüşebilir, kızlar erkeğe dönüşebilir.\n" + +#: tmainform.ckfilterharem.caption +msgid "Harem" +msgstr "Harem" + +#: tmainform.ckfilterharem.hint +msgid "A series involving one male character and many female characters (usually attracted to the male character). A Reverse Harem is when the genders are reversed." +msgstr "Bir erkek karakter ve birden çok kız/kadın karakter içeren (çoğunlukla bu kızlar/kadınlar erkek karaktere sevgi, aşk ile bağlıdırlar) çalışmalar. Reverse Haremde ise cinsiyetler tam tersidir." + +#: tmainform.ckfilterhentai.caption +msgctxt "tmainform.ckfilterhentai.caption" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhentai.hint +msgctxt "TMAINFORM.CKFILTERHENTAI.HINT" +msgid "Hentai" +msgstr "Hentai" + +#: tmainform.ckfilterhistorical.caption +msgid "Historical" +msgstr "Tarihi" + +#: tmainform.ckfilterhistorical.hint +msgid "Having to do with old or ancient times." +msgstr "Eski ya da antik çağlarda gerçekleşen olaylar." + +#: tmainform.ckfilterhorror.caption +msgid "Horror" +msgstr "Korku" + +#: tmainform.ckfilterhorror.hint +msgid "A painful emotion of fear, dread, and abhorrence; a shuddering with terror and detestation; the feeling inspired by something frightful and shocking." +msgstr "Korku, dehşet ve nefret; korkutmayla sarsıcı ve iğrenme; korkunç ve şok edici bir şeyden etkilenme hissi." + +#: tmainform.ckfilterjosei.caption +msgid "Josei" +msgstr "Josei" + +#: tmainform.ckfilterjosei.hint +msgid "Literally \"Woman\". Targets women 18-30. Female equivalent to seinen. Unlike shoujo the romance is more realistic and less idealized. The storytelling is more explicit and mature." +msgstr "Bayan. 18-30 yaş arası bayanlara yönelik içerik. Seinen'in kadın versiyonu. Aşklar gerçekçidir. Hikaye, Shoujo’ya göre daha olgun içerikler barındırır." + +#: tmainform.ckfilterlolicon.caption +msgid "Lolicon" +msgstr "Lolicon" + +#: tmainform.ckfilterlolicon.hint +msgid "Representing a sexual attraction to young or under-age girls." +msgstr "Genç veya çoğunlukla yaşı küçük kızlara karşı cinsel anlamda ilgi barındıran içerikler." + +#: tmainform.ckfiltermartialarts.caption +msgid "Martial Arts" +msgstr "Dövüş Sanatları" + +#: tmainform.ckfiltermartialarts.hint +msgid "As the name suggests, anything martial arts related. Any of several arts of combat or self-defense, such as aikido, karate, judo, or taekwondo, kendo, fencing, and so on and so forth." +msgstr "İsimden de anlaşılacağı gibi, dövüş sanatlarını içeren her şey. Birkaç tane dövüş ya da savunma sanatı; aikido, karate, judo ya da taekwondo, kendo, eskrim vb." + +#: tmainform.ckfiltermature.caption +msgid "Mature" +msgstr "Olgun" + +#: tmainform.ckfiltermature.hint +msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." +msgstr "17 yaşın altındaki kişiler için aşırı gelebilecek şeyler içerir. Bu kategorideki başlıklar aşırı şiddet, kan ve gore, seksüel içerik ve/veya ağır sözler içerebilir." + +#: tmainform.ckfiltermecha.caption +msgid "Mecha" +msgstr "Mekanik" + +#: tmainform.ckfiltermecha.hint +msgid "A work involving and usually concentrating on all types of large robotic machines." +msgstr "Büyük robotik makineler içeren ve çoğunlukla bunlara odaklı çalışmalar." + +#: tmainform.ckfiltermusical.caption +msgctxt "tmainform.ckfiltermusical.caption" +msgid "Musical" +msgstr "Müzikal" + +#: tmainform.ckfiltermusical.hint +msgctxt "tmainform.ckfiltermusical.hint" +msgid "Musical" +msgstr "Müzikal" + +#: tmainform.ckfiltermystery.caption +msgid "Mystery" +msgstr "Gizem" + +#: tmainform.ckfiltermystery.hint +msgid "Usually an unexplained event occurs, and the main protagonist attempts to find out what caused it." +msgstr "Genellikle, açıklanmayan bir olay gerçekleşir ve ana karakter buna neyin sebep olduğunu bulmaya çalışır." + +#: tmainform.ckfilterpsychological.caption +msgid "Psychological" +msgstr "Psikolojik" + +#: tmainform.ckfilterpsychological.hint +msgid "Usually deals with the philosophy of a state of mind, in most cases detailing abnormal psychology." +msgstr "Genel olarak ruhsal durum felsefesi kullanır, çoğu durumda anormal psikoloji detaycılığıyla akıl oyunları oynar." + +#: tmainform.ckfilterromance.caption +msgid "Romance" +msgstr "Romantizm" + +#: tmainform.ckfilterromance.hint +msgid "Any love related story. We will define love as between man and woman in this case. Other than that, it is up to your own imagination of what love is." +msgstr "Aşk içeren herhangi bir hikaye. Buradaki aşk, kadın ve erkek arasındadır. Bunun dışında, aşkın ne olduğu sizin hayal gücünüze bağlıdır." + +#: tmainform.ckfilterschoollife.caption +msgid "School Life" +msgstr "Okul Hayatı" + +#: tmainform.ckfilterschoollife.hint +msgid "Having a major setting of the story deal with some type of school." +msgstr "Hikayenin çoğu, bir çeşit okulda geçer." + +#: tmainform.ckfilterscifi.caption +msgid "Sci-Fi" +msgstr "Bilim Kurgu" + +#: tmainform.ckfilterscifi.hint +msgid "Short for science fiction, these works involve twists on technology and other science related phenomena which are contrary or stretches of the modern day scientific world." +msgstr "Bu çalışmalar teknolojide ilerlemeler içerir ve günümüz dünyasındaki bilimsel gerçekliklerden farklı ya da fenomen olan içerikler barındırır." + +#: tmainform.ckfilterseinen.caption +msgid "Seinen" +msgstr "Seinen" + +#: tmainform.ckfilterseinen.hint +msgid "From Google: Seinen means 'young Man'. Manga and anime that specifically targets young adult males around the ages of 18 to 25 are seinen titles. The stories in seinen works appeal to university students and those in the working world. Typically the story lines deal with the issues of adulthood." +msgstr "Google: Seinen \"Genç Adam\" demek. 18-25 yaş arası genç yetişkinlere yönelik manga ve animeler. Seinen, üniversite öğrencileri ya da iş hayatındaki kişilerin yaşamlarını barındırır. Hikaye, yetişkinlik sorunlarını işler." + +#: tmainform.ckfiltershotacon.caption +msgid "Shotacon" +msgstr "Shotacon" + +#: tmainform.ckfiltershotacon.hint +msgid "Representing a sexual attraction to young or under-age boys." +msgstr "Genç yada küçük yaştaki erkek çocuklarına karşı cinsel anlamda ilgi barındıran içerikler." + +#: tmainform.ckfiltershoujo.caption +msgid "Shoujo" +msgstr "Shoujo" + +#: tmainform.ckfiltershoujo.hint +msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." +msgstr "Öncelikli olarak bayanlar için yazılmış çalışmalar. Bunlar çoğunlukla çok fazla romantizm ve güçlü derecede karakter gelişimi barındırır." + +#: tmainform.ckfiltershoujoai.caption +msgid "Shoujo Ai" +msgstr "Shoujo Ai" + +#: tmainform.ckfiltershoujoai.hint +msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" +msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." +msgstr "Yuri ile benzer görülse de, bu biraz daha az aşırılık barındırır. \"Kız Çocuklarının Aşkı\", denebilir." + +#: tmainform.ckfiltershounen.caption +msgid "Shounen" +msgstr "Shounen" + +#: tmainform.ckfiltershounen.hint +msgctxt "tmainform.ckfiltershounen.hint" +msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." +msgstr "Öncelikli olarak erkekler için yazılmış çalışmalar. Bunlar çoğunlukla kavga ve/veya şiddet içerir." + +#: tmainform.ckfiltershounenai.caption +msgid "Shounen Ai" +msgstr "Shounen Ai" + +#: tmainform.ckfiltershounenai.hint +msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" +msgstr "Yaoi ile benzer görülse de, bu biraz daha az aşırılık barındırır. \"Erkek Çocuklarının Aşkı\", denebilir" + +#: tmainform.ckfiltersliceoflife.caption +msgid "Slice of Life" +msgstr "Hayattan Bir Kesit" + +#: tmainform.ckfiltersliceoflife.hint +msgid "As the name suggests, this genre represents day-to-day tribulations of one/many character(s). These challenges/events could technically happen in real life and are often -if not all the time- set in the present timeline in a world that mirrors our own." +msgstr "İsimden de anlaşılacağı gibi, bu tür bir/birden fazla karakterin günbegün yaşamını yansıtır. Bu zorluklar/olaylar teknik olarak günlük hayatta yaşanabilir ve çoğunlukla -her zaman olmasa bile- günümüz zaman diliminin yansıması olan bir dünyada geçer." + +#: tmainform.ckfiltersmut.caption +msgid "Smut" +msgstr "Smut" + +#: tmainform.ckfiltersmut.hint +msgid "Deals with series that are considered profane or offensive, particularly with regards to sexual content." +msgstr "Özellikle cinsel içerik açısından, küstahça veya saldırgan sayılan özellikler barındıran seriler." + +#: tmainform.ckfiltersports.caption +msgid "Sports" +msgstr "Spor" + +#: tmainform.ckfiltersports.hint +msgid "As the name suggests, anything sports related. Baseball, basketball, hockey, soccer, golf, and racing just to name a few." +msgstr "İsimden de anlaşılacağı gibi, spor içerikli. Beyzbol, hokey, futbol, golf ve yarış sadece birkaçı." + +#: tmainform.ckfiltersupernatural.caption +msgid "Supernatural" +msgstr "Doğaüstü" + +#: tmainform.ckfiltersupernatural.hint +msgid "Usually entails amazing and unexplained powers or events which defy the laws of physics." +msgstr "Gerçek olmayan güçler yada olaylar barındıran, fizik kurallarını ihlal eden içerikler." + +#: tmainform.ckfiltertragedy.caption +msgid "Tragedy" +msgstr "Trajedi" + +#: tmainform.ckfiltertragedy.hint +msgid "Contains events resulting in great loss and misfortune." +msgstr "Büyük kayıpların ya da talihsizliklerin olduğu olaylar içerir." + +#: tmainform.ckfilterweebtons.caption +msgctxt "tmainform.ckfilterweebtons.caption" +msgid "Weebtoons" +msgstr "Webtoonlar" + +#: tmainform.ckfilterweebtons.hint +msgctxt "tmainform.ckfilterweebtons.hint" +msgid "Weebtoons" +msgstr "Webtoonlar" + +#: tmainform.ckfilteryaoi.caption +msgid "Yaoi" +msgstr "Yaoi" + +#: tmainform.ckfilteryaoi.hint +msgid "This work usually involves intimate relationships between men." +msgstr "Bu çalışmalar genellikle erkekler arası yakın ilişki barındırır." + +#: tmainform.ckfilteryuri.caption +msgid "Yuri" +msgstr "Yuri" + +#: tmainform.ckfilteryuri.hint +msgid "This work usually involves intimate relationships between women." +msgstr "Bu çalışmalar genellikle kadınlar arası yakın ilişki barındırır." + +#: tmainform.edcustomgenres.texthint +msgid "Input custom genres, separated by comma" +msgstr "Kişisel demogrofi ekle, virgülle ayrılmış" + +#: tmainform.eddownloadssearch.texthint +#| msgid "Search favorites..." +msgctxt "tmainform.eddownloadssearch.texthint" +msgid "Search downloads..." +msgstr "İndirmeleri ara..." + +#: tmainform.edfavoritessearch.texthint +msgctxt "tmainform.edfavoritessearch.texthint" +msgid "Search favorites..." +msgstr "Favorileri ara..." + +#: tmainform.edfilterartists.texthint +msgctxt "tmainform.edfilterartists.texthint" +msgid "Artist" +msgstr "Çizer" + +#: tmainform.edfilterauthors.texthint +msgctxt "tmainform.edfilterauthors.texthint" +msgid "Author" +msgstr "Yazar" + +#: tmainform.edfiltermangainfochapters.texthint +msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgid "Filter" +msgstr "Filtre" + +#: tmainform.edfiltersummary.texthint +msgid "Part of summary" +msgstr "Özetin bir kısmı" + +#: tmainform.edfiltertitle.texthint +msgctxt "TMAINFORM.EDFILTERTITLE.TEXTHINT" +msgid "Title" +msgstr "Başlık" + +#: tmainform.edmangalistsearch.texthint +msgctxt "tmainform.edmangalistsearch.texthint" +msgid "Search title..." +msgstr "Başlık ara..." + +#: tmainform.edoptionchaptercustomrename.texthint +msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgid "Custom rename" +msgstr "Kişisel yeniden adlandırma" + +#: tmainform.edoptiondefaultpath.texthint +msgid "Default download path" +msgstr "Varsayılan indirme yolu" + +#: tmainform.edoptionexternalparams.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalparams.texthint" +msgid "External program parameters" +msgstr "Harici program parametreleri" + +#: tmainform.edoptionexternalpath.texthint +#| msgid "External program parameters" +msgctxt "tmainform.edoptionexternalpath.texthint" +msgid "External program path" +msgstr "Harici program yolu" + +#: tmainform.edoptionfilenamecustomrename.texthint +msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgid "Custom rename" +msgstr "Kişisel yeniden adlandırma" + +#: tmainform.edoptionhost.texthint +msgid "Proxy host/IP" +msgstr "Vekil sunucu/IP" + +#: tmainform.edoptionmangacustomrename.texthint +msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgid "Custom rename" +msgstr "Kişisel yeniden adlandırma" + +#: tmainform.edoptionpass.texthint +msgid "Proxy password" +msgstr "Vekil şifre" + +#: tmainform.edoptionuser.texthint +msgid "Proxy username" +msgstr "Vekil kullanıcı adı" + +#: tmainform.edsaveto.texthint +msgctxt "TMAINFORM.EDSAVETO.TEXTHINT" +msgid "Save to" +msgstr "Şuraya kaydet" + +#: tmainform.edurl.texthint +msgid "Input URL here" +msgstr "Buraya URL ekle" + +#: tmainform.edwebsitessearch.texthint +#| msgid "Search..." +msgctxt "tmainform.edwebsitessearch.texthint" +msgid "Search website..." +msgstr "Websitesi ara..." + +#: tmainform.gbdialogs.caption +msgid "Show dialog confirmation for" +msgstr "Şunun için doğrulama diyaloğu göster" + +#: tmainform.gbdroptarget.caption +msgid "Drop Box" +msgstr "İndirme kutusu" + +#: tmainform.gboptionexternal.caption +msgid "External program" +msgstr "Harici program" + +#: tmainform.gboptionfavorites.caption +msgctxt "TMAINFORM.GBOPTIONFAVORITES.CAPTION" +msgid "Favorites" +msgstr "Favoriler" + +#: tmainform.gboptionproxy.caption +msgid "Proxy config" +msgstr "Vekil ayarları" + +#: tmainform.gboptionrenaming.caption +msgid "Renaming" +msgstr "Yeniden adlandırılıyor" + +#: tmainform.lbdefaultdownloadpath.caption +msgid "Choose the default download path:" +msgstr "Varsayılan indirme yolunu seç:" + +#: tmainform.lbdroptargetopacity.caption +msgid "Opacity" +msgstr "Şeffaflık" + +#: tmainform.lbfilterartists.caption +msgctxt "tmainform.lbfilterartists.caption" +msgid "Artist" +msgstr "Çizer" + +#: tmainform.lbfilterauthors.caption +msgctxt "tmainform.lbfilterauthors.caption" +msgid "Author" +msgstr "Yazar" + +#: tmainform.lbfiltercustomgenres.caption +msgid "Custom Genres" +msgstr "Kişisel Türler" + +#: tmainform.lbfilterhint.caption +msgctxt "tmainform.lbfilterhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lbfilterhint.hint +msgid "" +"Genres:\n" +"- Checked: Include this genre.\n" +"- Unchecked: Exclude this genre.\n" +"- Grayed: Doesn't matter.\n" +"\n" +"Custom Genres:\n" +"- Separate multiple genres with ','.\n" +"- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" +"- Example: Adventure,!Ecchi,Comedy.\n" +msgstr "" +"Türler:\n" +"- Seçili: Bu türü dahil et.\n" +"- Seçilmemiş: Bu türü dahil etme.\n" +"- Gri: Farketmez.\n" +"\n" +"Kişisel türler:\n" +"- Birden fazla türü ',' ile ayır.\n" +"- Başına '!' ya da '-' ekleyerek bir türü hariç tutun.\n" +"- Örnek: Macera,!Ecchi,Komedi.\n" + +#: tmainform.lbfilterstatus.caption +msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" +msgid "Status" +msgstr "Durum" + +#: tmainform.lbfiltersummary.caption +msgid "Summary" +msgstr "Özet" + +#: tmainform.lbfiltertitle.caption +msgctxt "tmainform.lbfiltertitle.caption" +msgid "Title" +msgstr "Başlık" + +#: tmainform.lblogfilename.caption +msgid "Log file:" +msgstr "Günlük dosyası:" + +#: tmainform.lbmode.caption +msgid "Mode: Show all (0)" +msgstr "Mod: Tümünü göster (0)" + +#: tmainform.lboptionautocheckfavintervalminutes.caption +msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgid "Auto check for new chapter every %d minutes" +msgstr "Her %d dakikada bir yeni bölüm kontrolü yap" + +#: tmainform.lboptionchaptercustomrename.caption +#| msgid "Chapter folder name:" +msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgid "Chapter name:" +msgstr "Bölüm adı:" + +#: tmainform.lboptionchaptercustomrenamehint.caption +msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionchaptercustomrenamehint.hint +msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"%NUMBERING% : Numbering\n" +"\n" +"Note:\n" +"Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Website adı\n" +"%MANGA% : Manga başlığı\n" +"%CHAPTER% : Bölüm başlığı\n" +"%AUTHOR% : Yazar\n" +"%ARTIST% : Çizer\n" +"%NUMBERING% : Numaralama\n" +"\n" +"Not:\n" +"Bölüm klasörü en azından %CHAPTER% ya da %NUMBERING% içermelidir.\n" + +#: tmainform.lboptionconnectiontimeout.caption +msgid "Connection timeout (seconds)" +msgstr "Bağlantı zaman aşımı (saniye)" + +#: tmainform.lboptionexternal.caption +msgid "Open manga by using external program:" +msgstr "Mangayı harici program ile aç:" + +#: tmainform.lboptionexternalparams.caption +msgid "Parameters:" +msgstr "Parametreler:" + +#: tmainform.lboptionexternalparamshint.caption +msgctxt "tmainform.lboptionexternalparamshint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrename.caption +msgid "Filename:" +msgstr "Dosya adı:" + +#: tmainform.lboptionfilenamecustomrenamehint.caption +msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionfilenamecustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%CHAPTER% : Chapter title\n" +"%FILENAME% : Filename\n" +"\n" +"Note:\n" +"Filename must have at least %FILENAME%\n" +msgstr "" +"%WEBSITE% : Website adı\n" +"%MANGA% : Manga başlığı\n" +"%CHAPTER% : Bölüm başlığı\n" +"%FILENAME% : Dosya adı\n" +"\n" +"Not:\n" +"Dosya adı en azından %FILENAME% içermeldir\n" + +#: tmainform.lboptionhost.caption +msgid "Host" +msgstr "Sunucu" + +#: tmainform.lboptionlanguage.caption +msgid "Language:" +msgstr "Dil:" + +#: tmainform.lboptionletfmddo.caption +msgid "After download finish:" +msgstr "İndirme bittikten sonra:" + +#: tmainform.lboptionmangacustomrename.caption +msgctxt "tmainform.lboptionmangacustomrename.caption" +msgid "Manga folder name:" +msgstr "Manga klasörü adı:" + +#: tmainform.lboptionmangacustomrenamehint.caption +msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionmangacustomrenamehint.hint +msgid "" +"%WEBSITE% : Website name\n" +"%MANGA% : Manga title\n" +"%AUTHOR% : Author\n" +"%ARTIST% : Artist\n" +"\n" +"Note:\n" +"Manga folder name must have at least %MANGA%.\n" +msgstr "" +"%WEBSITE% : Website adı\n" +"%MANGA% : Manga başlığı\n" +"%AUTHOR% : Yazar\n" +"%ARTIST% : Çizer\n" +"\n" +"Not:\n" +"Manga klasörü adı en azından %MANGA% içermelidir.\n" + +#: tmainform.lboptionmaxparallel.caption +msgid "Number of downloaded tasks at the same time (Max: 8)" +msgstr "Eşzamanlı indirilen görev sayısı (Maks: 8)" + +#: tmainform.lboptionmaxretry.caption +#| msgid "Number of retry times if tasks have download problems (0 = always retry)" +msgid "Number of retry times if tasks have download problems (-1 = always retry)" +msgstr "İndirmede sorun varsa tekrar deneme sayısı (-1 = sürekli yeniden dene)" + +#: tmainform.lboptionmaxthread.caption +msgid "Number of downloaded files per task at the same time (Max: 32)" +msgstr "Tek görev başına aynı anda indirilmiş dosya sayısı (Maks: 32)" + +#: tmainform.lboptionnewmangatime.caption +msgid "New manga based on it's update time (days)" +msgstr "Güncelleme süresine (günler) göre yeni manga" + +#: tmainform.lboptionpass.caption +msgctxt "tmainform.lboptionpass.caption" +msgid "Password" +msgstr "Şifre" + +#: tmainform.lboptionpdfquality.caption +msgid "PDF compression level" +msgstr "PDF sıkıştırma seviyesi" + +#: tmainform.lboptionpdfquality.hint +msgctxt "TMAINFORM.LBOPTIONPDFQUALITY.HINT" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (kayıpsız), düşük = DCTEncode (kayıplı)" + +#: tmainform.lboptionpdfqualityhint.caption +msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgid "[?]" +msgstr "[?]" + +#: tmainform.lboptionport.caption +msgid "Port" +msgstr "Port" + +#: tmainform.lboptionproxytype.caption +msgid "Type" +msgstr "Tip" + +#: tmainform.lboptionrenamedigits.caption +msgid "Rename digits" +msgstr "Basamakları yeniden adlandır" + +#: tmainform.lboptionuser.caption +msgctxt "tmainform.lboptionuser.caption" +msgid "Username" +msgstr "Kullanıcı adı" + +#: tmainform.lbsaveto.caption +msgid "Save to:" +msgstr "Şuraya kaydet:" + +#: tmainform.medturldelete.caption +msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" +msgid "Delete" +msgstr "Sil" + +#: tmainform.medurlcopy.caption +msgctxt "tmainform.medurlcopy.caption" +msgid "Copy" +msgstr "Kopyala" + +#: tmainform.medurlcut.caption +msgid "Cut" +msgstr "Kes" + +#: tmainform.medurlpaste.caption +msgid "Paste" +msgstr "Yapıştır" + +#: tmainform.medurlpasteandgo.caption +msgid "Paste and go" +msgstr "Yapıştır ve git" + +#: tmainform.medurlselectall.caption +msgid "Select all" +msgstr "Tümünü seç" + +#: tmainform.medurlundo.caption +msgid "Undo" +msgstr "Geri al" + +#: tmainform.miabortsilentthread.caption +msgid "Abort" +msgstr "Durdur" + +#: tmainform.michapterlistascending.caption +msgid "Ascending" +msgstr "Artan" + +#: tmainform.michapterlistcheckall.caption +msgctxt "tmainform.michapterlistcheckall.caption" +msgid "Check all" +msgstr "Tümünü işaretle" + +#: tmainform.michapterlistcheckselected.caption +msgid "Check selected" +msgstr "Seçilileri işaretle" + +#: tmainform.michapterlistdescending.caption +msgid "Descending" +msgstr "Azalan" + +#: tmainform.michapterlistfilter.caption +msgctxt "tmainform.michapterlistfilter.caption" +msgid "Filter" +msgstr "Filtre" + +#: tmainform.michapterlisthidedownloaded.caption +msgid "Hide downloaded chapters" +msgstr "İndirilmiş bölümleri gizle" + +#: tmainform.michapterlisthighlight.caption +#| msgid "Highlight download chapters" +msgid "Highlight downloaded chapters" +msgstr "İndirilmiş bölümleri vurgula" + +#: tmainform.michapterlistuncheckall.caption +msgctxt "tmainform.michapterlistuncheckall.caption" +msgid "Uncheck all" +msgstr "Tüm seçimleri kaldır" + +#: tmainform.michapterlistuncheckselected.caption +msgid "Uncheck selected" +msgstr "Seçilmişin işaretini kaldır" + +#: tmainform.midownloaddelete.caption +msgctxt "tmainform.midownloaddelete.caption" +msgid "Delete" +msgstr "Sil" + +#: tmainform.midownloaddeletecompleted.caption +msgctxt "TMAINFORM.MIDOWNLOADDELETECOMPLETED.CAPTION" +msgid "Delete all completed tasks" +msgstr "Tüm tamamlanmış görevleri sil" + +#: tmainform.midownloaddeletetask.caption +msgid "Task only" +msgstr "Sadece görev" + +#: tmainform.midownloaddeletetaskdata.caption +msgid "Task + Data" +msgstr "Görev + Veri" + +#: tmainform.midownloaddeletetaskdatafavorite.caption +msgid "Task + Data + Favorite" +msgstr "Görev + Veri + Favori" + +#: tmainform.midownloaddisable.caption +msgctxt "tmainform.midownloaddisable.caption" +msgid "Disable" +msgstr "Pasifleştir" + +#: tmainform.midownloadenable.caption +msgctxt "tmainform.midownloadenable.caption" +msgid "Enable" +msgstr "Aktifleştir" + +#: tmainform.midownloadmergecompleted.caption +msgid "Merge completed tasks" +msgstr "Tamamlanmış görevleri birleştir" + +#: tmainform.midownloadopenfolder.caption +msgctxt "tmainform.midownloadopenfolder.caption" +msgid "Open Folder" +msgstr "Klasörü Aç" + +#: tmainform.midownloadopenwith.caption +msgctxt "tmainform.midownloadopenwith.caption" +msgid "Open ..." +msgstr "Aç ..." + +#: tmainform.midownloadresume.caption +msgid "Resume" +msgstr "Devam et" + +#: tmainform.midownloadstop.caption +msgid "Stop" +msgstr "Dur" + +#: tmainform.midownloadviewmangainfo.caption +msgctxt "tmainform.midownloadviewmangainfo.caption" +msgid "View manga info" +msgstr "Manga bilgisini göster" + +#: tmainform.mifavoriteschangecurrentchapter.caption +msgid "Change \"Current chapter\"" +msgstr "Değiştir \"Şu anki bölüm\"" + +#: tmainform.mifavoriteschangesaveto.caption +msgid "Change \"Save to\"" +msgstr "Değiştir \"Şuraya kaydet\"" + +#: tmainform.mifavoriteschecknewchapter.caption +msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgid "Check for new chapter" +msgstr "Yeni bölüm kontrolü yap" + +#: tmainform.mifavoritesdelete.caption +msgctxt "TMAINFORM.MIFAVORITESDELETE.CAPTION" +msgid "Delete" +msgstr "Sil" + +#: tmainform.mifavoritesdisable.caption +msgctxt "tmainform.mifavoritesdisable.caption" +msgid "Disable" +msgstr "Pasifleştir" + +#: tmainform.mifavoritesdownloadall.caption +msgctxt "tmainform.mifavoritesdownloadall.caption" +msgid "Download all" +msgstr "Tümünü indir" + +#: tmainform.mifavoritesenable.caption +msgctxt "tmainform.mifavoritesenable.caption" +msgid "Enable" +msgstr "Aktifleştir" + +#: tmainform.mifavoritesopenfolder.caption +msgctxt "TMAINFORM.MIFAVORITESOPENFOLDER.CAPTION" +msgid "Open Folder" +msgstr "Klasörü Aç" + +#: tmainform.mifavoritesopenwith.caption +msgctxt "TMAINFORM.MIFAVORITESOPENWITH.CAPTION" +msgid "Open ..." +msgstr "Aç ..." + +#: tmainform.mifavoritesrename.caption +msgid "Rename" +msgstr "Yeniden adlandır" + +#: tmainform.mifavoritesstopchecknewchapter.caption +msgid "Stop check for new chapter" +msgstr "Yeni bölüm aramayı durdur" + +#: tmainform.mifavoritestransferwebsite.caption +msgctxt "tmainform.mifavoritestransferwebsite.caption" +msgid "Transfer website" +msgstr "Website değiştir" + +#: tmainform.mifavoritesviewinfos.caption +msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" +msgid "View manga info" +msgstr "Manga bilgisini göster" + +#: tmainform.mihighlightnewmanga.caption +msgid "Highlight new manga" +msgstr "Yeni mangayı vurgula" + +#: tmainform.mimangalistaddtofavorites.caption +msgid "Add to Favorites" +msgstr "Favorilere Ekle" + +#: tmainform.mimangalistdelete.caption +msgctxt "tmainform.mimangalistdelete.caption" +msgid "Delete" +msgstr "Sil" + +#: tmainform.mimangalistdownloadall.caption +msgctxt "TMAINFORM.MIMANGALISTDOWNLOADALL.CAPTION" +msgid "Download all" +msgstr "Tümünü indir" + +#: tmainform.mimangalistviewinfos.caption +msgid "View manga infos" +msgstr "Manga bilgilerini göster" + +#: tmainform.mitrayafterdownloadfinish.caption +msgid "After download finish" +msgstr "İndirme bittikten sonra" + +#: tmainform.mitrayexit.caption +msgctxt "tmainform.mitrayexit.caption" +msgid "Exit" +msgstr "Çık" + +#: tmainform.mitrayfinishexit.caption +msgctxt "tmainform.mitrayfinishexit.caption" +msgid "Exit" +msgstr "Çık" + +#: tmainform.mitrayfinishhibernate.caption +msgid "Hibernate" +msgstr "Uyut" + +#: tmainform.mitrayfinishnothing.caption +msgid "Nothing" +msgstr "Hiçbir şey" + +#: tmainform.mitrayfinishshutdown.caption +msgid "Shutdown" +msgstr "Kapat" + +#: tmainform.mitrayrestore.caption +msgid "Restore" +msgstr "Geri getir" + +#: tmainform.mitrayresumeall.caption +msgid "Resume all" +msgstr "Tamamına devam et" + +#: tmainform.mitrayshowdropbox.caption +msgctxt "tmainform.mitrayshowdropbox.caption" +msgid "Show Drop Box" +msgstr "İndirme Kutusunu göster" + +#: tmainform.mitraystopall.caption +msgid "Stop all" +msgstr "Tümünü durdur" + +#: tmainform.mndownload1click.caption +msgid "Download all lists from server at once" +msgstr "Tüm listeleri tek seferde sunucudan indir" + +#: tmainform.mnfiltergenreallcheck.caption +msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgid "Check all" +msgstr "Tümünü seç" + +#: tmainform.mnfiltergenreallindeterminate.caption +msgid "Indeterminate all" +msgstr "Tümünü belirsiz yap" + +#: tmainform.mnfiltergenrealluncheck.caption +msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgid "Uncheck all" +msgstr "Tüm seçimleri kaldır" + +#: tmainform.mnupdate1click.caption +msgid "Update all lists at once" +msgstr "Tüm listeleri güncelle" + +#: tmainform.mnupdatedownfromserver.caption +msgid "Download manga list from server" +msgstr "Manga listesini sunucudan indir" + +#: tmainform.mnupdatelist.caption +msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" +msgid "Update manga list" +msgstr "Manga listesini güncelle" + +#: tmainform.rball.caption +msgid "Have all genre checked" +msgstr "Tüm türleri seç" + +#: tmainform.rbone.caption +msgid "Have one of genres checked" +msgstr "Türlerden birini seç" + +#: tmainform.rgdroptargetmode.caption +msgid "Mode" +msgstr "Mod" + +#: tmainform.rgoptioncompress.caption +msgid "Save downloaded chapters as" +msgstr "İndirilmiş bölümleri şöyle kaydet" + +#: tmainform.seoptionpdfquality.hint +msgctxt "tmainform.seoptionpdfquality.hint" +msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" +msgstr "100 = FlateEncode (kayıpsız), düşük = DCTEncode (kayıplı)" + +#: tmainform.tbdownloaddeletecompleted.caption +msgctxt "tmainform.tbdownloaddeletecompleted.caption" +msgid "Delete all completed tasks" +msgstr "Tamamlanmış tüm görevleri sil" + +#: tmainform.tbdownloadresumeall.caption +msgid "Resume All" +msgstr "Tümüne Devam Et" + +#: tmainform.tbdownloadstopall.caption +msgid "Stop All" +msgstr "Tümünü Durdur" + +#: tmainform.tbwebsitescollapseall.caption +msgid "Collapse All" +msgstr "Tümünü Daralt" + +#: tmainform.tbwebsitesexpandall.caption +msgid "Expand All" +msgstr "Tümünü Genişlet" + +#: tmainform.tsabout.caption +msgid "About" +msgstr "Hakkında" + +#: tmainform.tsabouttext.caption +msgid "About FMD" +msgstr "FMD Hakkında" + +#: tmainform.tsaccounts.caption +msgid "Accounts" +msgstr "Hesaplar" + +#: tmainform.tschangelogtext.caption +msgid "Changelog" +msgstr "Değişim kaydı" + +#: tmainform.tsconnections.caption +msgid "Connections" +msgstr "Bağlantılar" + +#: tmainform.tscustomcolor.caption +msgid "Custom color" +msgstr "Kişisel renk" + +#: tmainform.tsdialogs.caption +msgid "Dialogs" +msgstr "İletişim kutuları" + +#: tmainform.tsdownload.caption +msgctxt "tmainform.tsdownload.caption" +msgid "Downloads" +msgstr "İndirmeler" + +#: tmainform.tsfavorites.caption +msgctxt "tmainform.tsfavorites.caption" +msgid "Favorites" +msgstr "Favoriler" + +#: tmainform.tsgeneral.caption +msgid "General" +msgstr "Genel" + +#: tmainform.tsinfofilteradv.caption +msgctxt "tmainform.tsinfofilteradv.caption" +msgid "Filter" +msgstr "Filtre" + +#: tmainform.tsinfomanga.caption +msgid "Info" +msgstr "Bilgi" + +#: tmainform.tsinformation.caption +msgid "Manga Info" +msgstr "Manga Bilgisi" + +#: tmainform.tslog.caption +msgid "Log" +msgstr "Günlük" + +#: tmainform.tsmisc.caption +msgid "Misc" +msgstr "Çeşitli" + +#: tmainform.tsoption.caption +msgctxt "tmainform.tsoption.caption" +msgid "Options" +msgstr "Ayarlar" + +#: tmainform.tssaveto.caption +msgctxt "TMAINFORM.TSSAVETO.CAPTION" +msgid "Save to" +msgstr "Şuraya kaydet" + +#: tmainform.tsupdate.caption +msgid "Updates" +msgstr "Güncellemeler" + +#: tmainform.tsview.caption +msgid "View" +msgstr "Görünüm" + +#: tmainform.tswebsiteadvanced.caption +msgid "Advanced" +msgstr "Gelişmiş" + +#: tmainform.tswebsiteoptions.caption +msgctxt "tmainform.tswebsiteoptions.caption" +msgid "Options" +msgstr "Ayarlar" + +#: tmainform.tswebsites.caption +msgctxt "tmainform.tswebsites.caption" +msgid "Websites" +msgstr "Websiteleri" + +#: tmainform.tswebsiteselection.caption +msgctxt "tmainform.tswebsiteselection.caption" +msgid "Websites" +msgstr "Websiteleri" + +#: tmainform.vtdownload.header.columns[0].text +msgid "Manga" +msgstr "Manga" + +#: tmainform.vtdownload.header.columns[1].text +msgctxt "tmainform.vtdownload.header.columns[1].text" +msgid "Status" +msgstr "Durum" + +#: tmainform.vtdownload.header.columns[2].text +msgid "Progress" +msgstr "İlerleme" + +#: tmainform.vtdownload.header.columns[3].text +msgctxt "tmainform.vtdownload.header.columns[3].text" +msgid "Transfer rate" +msgstr "Transfer oranı" + +#: tmainform.vtdownload.header.columns[4].text +msgctxt "tmainform.vtdownload.header.columns[4].text" +msgid "Website" +msgstr "Website" + +#: tmainform.vtdownload.header.columns[5].text +msgctxt "tmainform.vtdownload.header.columns[5].text" +msgid "Save to" +msgstr "Şuraya kaydet" + +#: tmainform.vtdownload.header.columns[6].text +msgctxt "TMAINFORM.VTDOWNLOAD.HEADER.COLUMNS[6].TEXT" +msgid "Added" +msgstr "Eklenme Tarihi" + +#: tmainform.vtfavorites.header.columns[0].text +msgid "#" +msgstr "#" + +#: tmainform.vtfavorites.header.columns[1].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[1].TEXT" +msgid "Title" +msgstr "Başlık" + +#: tmainform.vtfavorites.header.columns[2].text +msgid "Current chapter" +msgstr "Şu anki bölüm" + +#: tmainform.vtfavorites.header.columns[3].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" +msgid "Website" +msgstr "Website" + +#: tmainform.vtfavorites.header.columns[4].text +msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" +msgid "Save to" +msgstr "Şuraya kaydet" + +#: tnewchapter.btcancel.caption +msgctxt "TNEWCHAPTER.BTCANCEL.CAPTION" +msgid "&Cancel" +msgstr "&İptal" + +#: tnewchapter.btdownload.caption +msgctxt "TNEWCHAPTER.BTDOWNLOAD.CAPTION" +msgid "&Download" +msgstr "&İndir" + +#: tnewchapter.btqueue.caption +msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" +msgid "&Add to queue" +msgstr "&Sıraya ekle" + +#: tshutdowncounterform.btabort.caption +msgid "&Abort" +msgstr "&Durdur" + +#: tshutdowncounterform.btnow.caption +msgid "&Now" +msgstr "&Şimdi" + +#: ttransferfavoritesform.btcancel.caption +msgctxt "ttransferfavoritesform.btcancel.caption" +msgid "Cancel" +msgstr "İptal" + +#: ttransferfavoritesform.btok.caption +msgctxt "ttransferfavoritesform.btok.caption" +msgid "OK" +msgstr "Tamam" + +#: ttransferfavoritesform.caption +msgid "Transfer Favorites" +msgstr "Favorileri Transfer Et" + +#: ttransferfavoritesform.ckcleardownloadedchapters.caption +msgid "Clear downloaded chapter list and reload from server" +msgstr "İndirilmiş bölüm listesini temizle ve sunucudan yeniden yükle" + +#: ttransferfavoritesform.lbtransferto.caption +msgctxt "ttransferfavoritesform.lbtransferto.caption" +msgid "Transfer to" +msgstr "Şuraya Transfer Et" + +#: ttransferfavoritesform.rball.caption +msgctxt "ttransferfavoritesform.rball.caption" +msgid "All" +msgstr "Tümü" + +#: ttransferfavoritesform.rbinvalid.caption +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Geçersiz" + +#: ttransferfavoritesform.rbvalid.caption +msgctxt "ttransferfavoritesform.rbvalid.caption" +msgid "Valid" +msgstr "Geçerli" + +#: ttransferfavoritesform.vtfavs.header.columns[1].text +msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" +msgid "Title" +msgstr "Başlık" + +#: ttransferfavoritesform.vtfavs.header.columns[2].text +msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" +msgid "Website" +msgstr "Website" + +#: tupdatedialogform.btnlater.caption +msgid "&Later" +msgstr "&Sonra" + +#: tupdatedialogform.btnupdate.caption +msgid "&Update" +msgstr "&Güncelle" + +#: tupdatedialogform.lbmessage.caption +msgid "" +"New version found! Do you want to update now?\n" +"FMD will be closed to finish the update.\n" +msgstr "" +"Yeni sürüm bulundu! Şimdi güncellemek ister misiniz?\n" +"FMD, güncelleme için kapatılacak.\n" + +#: twebsiteoptionadvancedform.menuitem1.caption +msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgid "Add" +msgstr "Ekle" + +#: twebsiteoptionadvancedform.menuitem2.caption +msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgid "Edit" +msgstr "Düzenle" + +#: twebsiteoptionadvancedform.menuitem4.caption +msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgid "Delete" +msgstr "Sil" + +#: twebsiteoptionadvancedform.tscookies.caption +msgctxt "twebsiteoptionadvancedform.tscookies.caption" +msgid "Cookies" +msgstr "Çerezler" + +#: twebsiteoptionadvancedform.tsdirectorypagenumber.caption +msgid "Directory page number" +msgstr "Dizin sayfa numarası" + +#: twebsiteoptionadvancedform.tsdownloads.caption +msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgid "Downloads" +msgstr "İndirmeler" + +#: twebsiteoptionadvancedform.tsmaxthreadspertask.caption +msgid "Max threads per task" +msgstr "Her bir görev için maksimum iş parçacığı" + +#: twebsiteoptionadvancedform.tsnumberofthreads.caption +msgid "Number of threads" +msgstr "İş parçacığı sayısı" + +#: twebsiteoptionadvancedform.tsupdatelist.caption +msgid "Update List" +msgstr "Listeyi Güncelle" + +#: twebsiteoptionadvancedform.tsuseragent.caption +msgctxt "twebsiteoptionadvancedform.tsuseragent.caption" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtcookies.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgid "Cookies" +msgstr "Çerezler" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" +msgid "Value" +msgstr "Değer" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgid "Value" +msgstr "Değer" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgid "Value" +msgstr "Değer" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgid "Website" +msgstr "Website" + +#: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text +msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgid "User Agent" +msgstr "User Agent" + +#: twebsiteselectionform.caption +msgid "Select a website" +msgstr "Bir websitesi seç" + +#: udownloadsmanager.rs_compressing +msgid "Compressing..." +msgstr "Sıkıştırılıyor..." + +#: udownloadsmanager.rs_disabled +msgid "Disabled" +msgstr "Pasifleştirilmiş" + +#: udownloadsmanager.rs_downloading +msgid "Downloading" +msgstr "İndiriliyor" + +#: udownloadsmanager.rs_failed +msgid "Failed" +msgstr "Başarısız oldu" + +#: udownloadsmanager.rs_failedtocreatedir +msgid "Failed to create directory!" +msgstr "Dizin oluşturma başarısız oldu!" + +#: udownloadsmanager.rs_failedtryresumetask +msgid "Failed, try resuming this task!" +msgstr "Başarısız, görevi devam ettirmeyi deneyin!" + +#: udownloadsmanager.rs_finish +msgid "Completed" +msgstr "Tamamlandı" + +#: udownloadsmanager.rs_preparing +msgctxt "udownloadsmanager.rs_preparing" +msgid "Preparing" +msgstr "Hazırlanıyor" + +#: udownloadsmanager.rs_stopped +msgid "Stopped" +msgstr "Durduruldu" + +#: udownloadsmanager.rs_waiting +msgid "Waiting..." +msgstr "Bekliyor..." + +#: ufavoritesmanager.rs_btnaddtoqueue +msgctxt "ufavoritesmanager.rs_btnaddtoqueue" +msgid "&Add to queue" +msgstr "&Sıraya ekle" + +#: ufavoritesmanager.rs_btncancel +msgctxt "ufavoritesmanager.rs_btncancel" +msgid "&Cancel" +msgstr "&İptal Et" + +#: ufavoritesmanager.rs_btncheckfavorites +msgctxt "ufavoritesmanager.rs_btncheckfavorites" +msgid "Check for new chapter" +msgstr "Yeni bölüme bak" + +#: ufavoritesmanager.rs_btndownload +msgctxt "ufavoritesmanager.rs_btndownload" +msgid "&Download" +msgstr "&İndir" + +#: ufavoritesmanager.rs_btnremove +msgid "&Remove" +msgstr "&Kaldır" + +#: ufavoritesmanager.rs_dlgcompletedmangacaption +msgid "Found %d completed manga" +msgstr "%d tamamlanmış manga bulundu" + +#: ufavoritesmanager.rs_dlgfavoritescheckisrunning +msgid "Favorites check is running!" +msgstr "Favorilerin kontrolü devam ediyor!" + +#: ufavoritesmanager.rs_dlgnewchaptercaption +msgid "%d manga(s) have new chapter(s)" +msgstr "%d manganın yeni bölümü var" + +#: ufavoritesmanager.rs_favoritehasnewchapter +msgid "%s <%s> has %d new chapter(s)." +msgstr "%s <%s> %d yeni bölümü var." + +#: ufavoritesmanager.rs_lblmangawillberemoved +msgid "Completed manga will be removed:" +msgstr "Tamamlanmış manga kaldırılacak:" + +#: ufavoritesmanager.rs_lblnewchapterfound +msgid "Found %d new chapter from %d manga(s):" +msgstr "%d yeni bölüm bulundu %d manga(larından)sından:" + +#: usilentthread.rs_silentthreadloadstatus +msgid "Loading: %d/%d" +msgstr "Yükleniyor: %d/%d" + +#: usubthread.rs_btncheckupdates +msgctxt "usubthread.rs_btncheckupdates" +msgid "Check for new version" +msgstr "Yeni sürümü kontrol et" + +#: usubthread.rs_currentversion +msgid "Installed Version" +msgstr "İndirilmiş Sürüm" + +#: usubthread.rs_latestversion +msgid "Latest Version " +msgstr "Son Sürüm " + +#: usubthread.rs_newversionfound +msgid "New Version found!" +msgstr "Yeni Sürüm bulundu!" + +#: uupdatethread.rs_dlghasnewmanga +msgid "%s has %d new manga(s)" +msgstr "%s için %d yeni manga bulundu" + +#: uupdatethread.rs_gettingdirectory +msgid "Getting directory" +msgstr "Dizin alınıyor" + +#: uupdatethread.rs_gettinginfo +msgid "Getting info" +msgstr "Bilgi alınıyor" + +#: uupdatethread.rs_gettinglistfor +msgid "Getting list for" +msgstr "Şunun için liste alınıyor" + +#: uupdatethread.rs_indexingnewtitle +msgid "Indexing new title(s)" +msgstr "Yeni başlık(lar) indeksleniyor" + +#: uupdatethread.rs_lookingfornewtitle +msgid "Looking for new title(s)" +msgstr "Yeni başlık(lar) aranıyor" + +#: uupdatethread.rs_lookingfornewtitlefromanotherdirectory +msgid "Looking for new title(s) from another directory" +msgstr "Başka bir dizinden yeni başlık(lar) aranıyor" + +#: uupdatethread.rs_preparing +msgctxt "uupdatethread.rs_preparing" +msgid "Preparing" +msgstr "Hazırlanıyor" + +#: uupdatethread.rs_removingduplicatefromcurrentdata +msgid "Removing duplicate from current data" +msgstr "Şu anki veriden çiftler kaldırılıyor" + +#: uupdatethread.rs_removingduplicatefromlocaldata +msgid "Removing duplicate from local data" +msgstr "Yerel veriden çiftler kaldırılıyor" + +#: uupdatethread.rs_removingduplicatefromnewtitle +msgid "Removing duplicate from new title(s)" +msgstr "Başlıktan çiftler kaldırılıyor" + +#: uupdatethread.rs_savingdata +msgid "Saving data" +msgstr "Veri kaydediliyor" + +#: uupdatethread.rs_synchronizingdata +msgid "Synchronizing data" +msgstr "Veri eşitleniyor" + +#: uupdatethread.rs_updatinglist +msgid "Updating list" +msgstr "Liste güncelleniyor" diff --git a/updater/languages/updater.tr_TR.po b/updater/languages/updater.tr_TR.po new file mode 100644 index 000000000..e508439f9 --- /dev/null +++ b/updater/languages/updater.tr_TR.po @@ -0,0 +1,108 @@ +msgid "" +msgstr "" +"Content-Type: text/plain; charset=UTF-8\n" +"Project-Id-Version: The Free Manga Downloader\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: Tmp341\n" +"MIME-Version: 1.0\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: tr\n" +"X-Generator: Poedit 2.0.3\n" + +#: tfrmmain.caption +msgid "Free Manga Downloader - Updater" +msgstr "Free Manga Downloader - Güncelleyici" + +#: tfrmmain.lbfilesize.caption +msgid "File size" +msgstr "Dosya boyutu" + +#: tfrmmain.lbstatus.caption +msgid "Waiting..." +msgstr "Bekliyor..." + +#: tfrmmain.lbtransferrate.caption +msgid "Transfer rate" +msgstr "Transfer oranı" + +#: tfrmmessage.caption +msgid "Help" +msgstr "Yardım" + +#: umain.rs_7znotfound +msgid "Can't extract file because 7za.exe not found!" +msgstr "Çıkarılamıyor, çünkü 7za.exe bulunamadı!" + +#: umain.rs_anerroroccured +msgid "An error occured when trying to download file." +msgstr "Dosyayı indirmeye çalışırken bir hata ile karşılaşıldı." + +#: umain.rs_downloading +msgid "Downloading [%s]..." +msgstr "İndiriliyor [%s]..." + +#: umain.rs_errorcheckantivirus +msgid "Error saving file, check your AntiVirus!" +msgstr "Dosya kaydedilirken hata, AntiVirus programınızı kontrol edin!" + +#: umain.rs_faileddownloadpage +msgid "Failed downloading file!" +msgstr "Dosyayı indirme başarısız!" + +#: umain.rs_failedloadpage +msgid "Failed loading page!" +msgstr "Sayfayı yükleme başarısız!" + +#: umain.rs_filenotfound +msgid "File not found!" +msgstr "Dosya bulunamadı!" + +#: umain.rs_finished +msgid "Finished." +msgstr "Tamamlandı." + +#: umain.rs_invalidurl +msgid "Invalid URL!" +msgstr "Geçersiz URL!" + +#: umain.rs_loadingpage +msgid "Loading page..." +msgstr "Sayfa yükleniyor..." + +#: umain.rs_redirected +msgid "Redirected..." +msgstr "Yeniden yönlendirildi..." + +#: umain.rs_response +msgid "Response" +msgstr "Cevap" + +#: umain.rs_retrydownloading +msgid "Retry downloading[%d] [%s]..." +msgstr "İndirmeyi tekrar dene[%d] [%s]..." + +#: umain.rs_retryloadpage +msgid "Retry loading page[%d]..." +msgstr "Sayfayı yüklemeyi yeniden dene[%d]..." + +#: umain.rs_savefile +msgid "Saving file... " +msgstr "Dosya kaydediliyor... " + +#: umain.rs_servererror +msgid "Server response error!" +msgstr "Sunucudan cevap alınamadı!" + +#: umain.rs_unknown +msgid "(unknown)" +msgstr "(bilinmeyen)" + +#: umain.rs_unpackfile +msgid "Unpacking file [%s]..." +msgstr "Dosya çıkartılıyor [%s]..." + +#: umain.rs_waitmainapp +msgid "Waiting main app to close..." +msgstr "Uygulamanın kapanması bekleniyor..." From 623d2dd6c5baacff7aeb0b9b3d74a0142c47e23f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 25 Jan 2018 10:39:52 +0300 Subject: [PATCH 1978/2794] add webp decoder --- baseunits/webp.pas | 154 ++++++++++++++++++++++++++++++ mangadownloader/forms/frmMain.pas | 5 +- 2 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 baseunits/webp.pas diff --git a/baseunits/webp.pas b/baseunits/webp.pas new file mode 100644 index 000000000..a270860f2 --- /dev/null +++ b/baseunits/webp.pas @@ -0,0 +1,154 @@ +unit webp; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Windows, MemBitmap, Dynlibs; + +var + WebPLibHandle: TLibHandle = 0; + DLLWebPName: String = 'libwebp.dll'; + +function IsWebPModuleLoaded: Boolean; +procedure InitWebPModule; +procedure DestroyWebPModule; +function WebPToMemBitmap(webp: TMemoryStream): TMemBitmap; +function WebPGetVersion: String; + +implementation + +uses + FMDOptions, SyncObjs; + +type + TWebPGetInfo = function (data: LPVOID; data_size: UInt32; width, height: pInt32): Int32; cdecl; + TWebPDecodeBGRAInto = function (data: LPVOID; data_size: UInt32; output: LPVOID; output_size: UInt32; stride: Int32): pInt32; cdecl; + TWebPGetDecoderVersion = function (): Int32; cdecl; + +var + pWebPGetInfo: TWebPGetInfo = nil; + pWebPDecodeBGRAInto: TWebPDecodeBGRAInto = nil; + pWebPGetDecoderVersion: TWebPGetDecoderVersion = nil; + webpCS: TCriticalSection; + webpLibLoaded: Boolean = False; + +resourcestring + SErrLoadFailed = 'Can not load WebP codec library "%s". Check your installation.'; + +function IsWebPModuleLoaded: Boolean; +begin + Result := webpLibLoaded; +end; + +procedure InitWebPModule; +begin + if IsWebPModuleLoaded then Exit; + webpCS.Enter; + try + if not IsWebPModuleLoaded then begin + WebPLibHandle := LoadLibrary(PChar(DLLWebPName)); + if WebPLibHandle <> 0 then begin + pWebPGetInfo := TWebPGetInfo(GetProcAddress(WebPLibHandle, 'WebPGetInfo')); + pWebPDecodeBGRAInto := TWebPDecodeBGRAInto(GetProcAddress(WebPLibHandle, 'WebPDecodeBGRAInto')); + pWebPGetDecoderVersion := TWebPGetDecoderVersion(GetProcAddress(WebPLibHandle, 'WebPGetDecoderVersion')); + webpLibLoaded := True; + end else + raise EInOutError.CreateFmt(SErrLoadFailed, [DLLWebPName]); + end; + finally + webpCS.Leave; + end; +end; + +procedure DestroyWebPModule; +begin + webpCS.Enter; + try + if IsWebPModuleLoaded then begin + if WebPLibHandle <> 0 then begin + pWebPGetInfo := nil; + pWebPDecodeBGRAInto := nil; + pWebPGetDecoderVersion := nil; + FreeLibrary(WebPLibHandle); + WebPLibHandle := 0; + end; + webpLibLoaded := False; + end; + finally + webpCS.Leave; + end; +end; + +function WebPGetInfo(data: LPVOID; data_size: UInt32; width, height: pInt32): Int32; +begin + if IsWebPModuleLoaded and Assigned(pWebPGetInfo) then + Result := pWebPGetInfo(data, data_size, width, height) + else + Result := 0; +end; + +function WebPDecodeBGRAInto(data: LPVOID; data_size: UInt32; output: LPVOID; output_size: UInt32; stride: Int32): pInt32; +begin + if IsWebPModuleLoaded and Assigned(pWebPDecodeBGRAInto) then + Result := pWebPDecodeBGRAInto(data, data_size, output, output_size, stride) + else + Result := nil; +end; + +function WebPGetDecoderVersion: Int32; +begin + if IsWebPModuleLoaded and Assigned(pWebPGetDecoderVersion) then + Result := pWebPGetDecoderVersion() + else + Result := 0; +end; + +function WebPGetVersion: String; +var + ver: Int32; +begin + Result := ''; + ver := WebPGetDecoderVersion; + if ver > 0 then begin + Result += chr(((ver shr 16) and $ff) + $30) + '.'; + Result += chr(((ver shr 8) and $ff) + $30) + '.'; + Result += chr(( ver and $ff) + $30); + end; +end; + +function WebPToMemBitmap(webp: TMemoryStream): TMemBitmap; +var + e, width, height, stride: Integer; + scan: pInt32; + r: TMemBitmap; +begin + Result := nil; + if webp = nil then Exit; + + e := WebPGetInfo(webp.Memory, webp.Size, @width, @height); + if e = 0 then Exit; + + r := TMemBitmap.Create(width, height); + stride := (r.ScanLine[1] - r.ScanLine[0]) * SizeOf(TMemPixel); + scan := WebPDecodeBGRAInto(webp.Memory, webp.Size, + r.ScanLine[0], stride * height, stride); + + if scan <> PLONG(r.ScanLine[0]) then begin + r.Free; + Exit; + end; + + Result := r; +end; + +initialization + webpCS := TCriticalSection.Create; + +finalization + DestroyWebPModule; + webpCS.Free; + +end. + diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9dddd534c..43be47821 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -882,7 +882,8 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, - FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8; + FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8, + webp; var // thread for open db @@ -2122,6 +2123,8 @@ procedure TMainForm.LoadAbout; if SQLiteLibraryHandle <> 0 then try addaboutcomp('SQLite Version', sqlite3_version()); except end; if SSLLibHandle = 0 then InitSSLInterface; if SSLLibHandle <> 0 then try addaboutcomp('OpenSSL Version', SSLeayversion(0)); except end; + if WebPLibHandle = 0 then InitWebPModule; + if WebPLibHandle <> 0 then try addaboutcomp('WebP Version', WebPGetVersion); except end; end; procedure TMainForm.GeneratetvDownloadFilterNodes; From a4544c994182528c8ac40bdacc9a8a1e139c7256 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 17 Jan 2018 07:33:57 +0300 Subject: [PATCH 1979/2794] Add atelierdunoir (fixes #842) --- baseunits/modules/FoOlSlide.pas | 19 +++++++++++++------ config/mangalist.ini | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index e94d741f2..53091849e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -36,7 +36,8 @@ function GetDirURL(const AWebsite: String): String; if (AWebsite = 'GoManga') or (AWebsite = 'Jaiminisbox') or (AWebsite = 'TripleSevenScan') or - (AWebsite = 'DokiFansubs') then + (AWebsite = 'DokiFansubs') or + (AWebsite = 'AtelierDuNoir') then Result := dirurlreader else if AWebsite = 'OneTimeScans' then @@ -113,10 +114,13 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//div[@class="list series"]/div/div[@class="title"]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; + if Module.Website = 'AtelierDuNoir' then + for v in XPath('//div[@class="caption"]') do begin + ALinks.Add(XPathString('div/a/@href', v)); + ANames.Add(XPathString('h4', v)); + end + else + XPathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', ALinks, ANames); finally Free; end; @@ -139,7 +143,9 @@ function GetInfo(const MangaInfo: TMangaInformation; with TXQueryEngineHTML.Create(Document) do try coverLink := XPathString('//div[@class="thumbnail"]/img/@src'); - if title = '' then title := XPathString('//h1[@class="title"]'); + if title = '' then + if Module.Website = 'AtelierDuNoir' then title := XPathString('//div[@class="section-headline"]//h3') + else title := XPathString('//h1[@class="title"]'); authors := TrimLeftChar(XPathString( '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), [':', ' ']); artists := TrimLeftChar(XPathString( @@ -253,6 +259,7 @@ procedure RegisterModule; AddWebsiteModule('HelveticaScans', 'http://helveticascans.com'); AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com'); AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com'); + AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index ad3ebd4ac..4b49f055d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans +English-Scanlation=AtelierDuNoir,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MeinManga,NineMangaDE Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From 7899437506c3ec01b6d84a3b1d694a6eeb2a5a9c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Jan 2018 19:15:58 +0800 Subject: [PATCH 1980/2794] rename turkish file --- mangadownloader/languages/{fmd.tr.po => fmd.tr_TR.po} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mangadownloader/languages/{fmd.tr.po => fmd.tr_TR.po} (100%) diff --git a/mangadownloader/languages/fmd.tr.po b/mangadownloader/languages/fmd.tr_TR.po similarity index 100% rename from mangadownloader/languages/fmd.tr.po rename to mangadownloader/languages/fmd.tr_TR.po From 71281d8e01ac6deae22eb75ce5b17b573375b67a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 25 Jan 2018 19:49:01 +0800 Subject: [PATCH 1981/2794] set library name at runtime --- mangadownloader/md.lpr | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index e8db1967a..83d79b8f8 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -10,8 +10,8 @@ {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, - FMDVars, SimpleException, Classes, windows, sysutils, frmMain, MultiLog, - FileChannel; + FMDVars, webp, SimpleException, Classes, windows, sysutils, frmMain, MultiLog, + FileChannel, ssl_openssl_lib; var CheckInstance: Boolean = True; @@ -82,8 +82,16 @@ s.Free; end; end; - if FileExists(FMD_DIRECTORY + 'sqlite3.dll') then - sqlite3dyn.SQLiteDefaultLibrary := FMD_DIRECTORY + 'sqlite3.dll'; + + if FileExists(FMD_DIRECTORY + Sqlite3Lib) then + SQLiteDefaultLibrary := FMD_DIRECTORY + Sqlite3Lib; + if FileExists(FMD_DIRECTORY + DLLSSLName) then + DLLSSLName := FMD_DIRECTORY + DLLSSLName; + if FileExists(FMD_DIRECTORY + DLLUtilName) then + DLLUtilName := FMD_DIRECTORY + DLLUtilName; + if FileExists(FMD_DIRECTORY + DLLWebPName) then + DLLWebPName := FMD_DIRECTORY + DLLWebPName; + Application.Initialize; Application.CreateForm(TMainForm, MainForm); Application.Run; From 18633b05800d5cc834337fb954126f1035c43aca Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 25 Jan 2018 20:03:35 +0300 Subject: [PATCH 1982/2794] Add manga-tube [DE] #667 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaTube.pas | 136 ++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaTube.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 191674f60..d9cb80beb 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -61,6 +61,7 @@ uses BlogTruyen, MangaAe, Mangadex, + MangaTube, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaTube.pas b/baseunits/modules/MangaTube.pas new file mode 100644 index 000000000..75ec85048 --- /dev/null +++ b/baseunits/modules/MangaTube.pas @@ -0,0 +1,136 @@ +unit MangaTube; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, synautil; + +implementation + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if MangaInfo.FHTTP.GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + if title = '' then title := XPathString('//h1[@class="series-title"]'); + coverLink := XPathString('//div[contains(@class, "cover")]//img/@data-original'); + coverLink := MaybeFillHost(Module.RootURL, coverLink); + summary := XPathString('//h4[text()="Beschreibung"]/following-sibling::p'); + if summary = '' then summary := XPathString('//h4[text()="Beschreibung"]/following-sibling::text()[1]'); + genres := XPathStringAll('//ul[contains(@class, "genre-list")]/li/a'); + authors := XPathStringAll('//ul[contains(@class, "series-details")]/li[contains(., "Autor")]/a'); + artists := XPathStringAll('//ul[contains(@class, "series-details")]/li[contains(., "Artist")]/a'); + status := Trim(XPathString('//ul[contains(@class, "series-details")]/li[contains(., "Status (Offiziell):")]/text()')); + status := MangaInfoStatusIfPos(status, 'laufend', 'abgeschlossen'); + for v in XPath('//ul[contains(@class, "chapter-list")]/li/a[contains(@href, "read/")]') do + begin + chapterLinks.Add(v.toNode().getAttribute('href')); + chapterName.Add(XPathString('concat(b, " ", span[1])', v)); + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + imgpath, s: String; + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//script[contains(., "img_path: ")]'); + imgpath := GetBetween('img_path: ''', ''',', s); + s := GetBetween('pages: ', '}],', s) + '}]'; + ParseHTML(s); + for v in XPath('json(*)().file_name') do begin + s := v.toString; + PageLinks.Add(imgpath + s); + end; + finally + Free; + end; + end; + end; +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +var + s:string; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/series/?filter=alphabetic') then + begin + Result := NO_ERROR; + Page := StrToIntDef(XPathString('//div[@id="series_list"]/@data-series-pages', MangaInfo.FHTTP.Document), 0); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + data: String; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + data := 'action=load_series_list_entries¶meter%5Bpage%5D=' + IncStr(AURL) + + '¶meter%5Bletter%5D=¶meter%5Bsortby%5D=alphabetic¶meter%5Border%5D=asc'; + if MangaInfo.FHTTP.POST(Module.RootURL + '/ajax', data) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathStringAll('json(*).success().manga_title', ANames); + for v in XPath('json(*).success().manga_slug') do + ALinks.Add(Module.RootURL + '/series/' + v.toString()); + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaTube'; + RootURL := 'https://manga-tube.me'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 4b49f055d..a7c5545d6 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -8,7 +8,7 @@ English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,He Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga -German=MeinManga,NineMangaDE +German=MangaTube,MeinManga,NineMangaDE Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL From 62cfa957f9e97bf6a9ad58cb3b99e9d6716271a4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 25 Jan 2018 20:17:52 +0300 Subject: [PATCH 1983/2794] Add wiemanga [DE] #667 --- baseunits/ModuleList.inc | 1 + baseunits/modules/WieManga.pas | 127 +++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/WieManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index d9cb80beb..91703abd6 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -62,6 +62,7 @@ uses MangaAe, Mangadex, MangaTube, + WieManga, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/WieManga.pas b/baseunits/modules/WieManga.pas new file mode 100644 index 000000000..1e5cbe96b --- /dev/null +++ b/baseunits/modules/WieManga.pas @@ -0,0 +1,127 @@ +unit WieManga; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, MangaFoxWatermark, FMDVars; + +implementation + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if MangaInfo.FHTTP.GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + title := XPathString('//div[@class="bookmessagebox"]/h1/substring-before(., " Manga")'); + coverLink := XPathString('//div[@class="bookfrontpage"]/a/img/@src'); + summary := XPathString('//h4[text()="Beschreibung"]/following-sibling::text()'); + genres := XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Genre")]/a'); + authors := XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Autor")]/a'); + artists := XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Zeichner")]/a'); + status := MangaInfoStatusIfPos(XPathString('//div[@class="bookmessgae"]//dd[contains(span/text(), "Status")]/a'), 'ongoing', 'finished'); + XPathHREFAll('//div[@class="chapterlist"]/table//td[@class="col1"]/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + url: String; +begin + Result := False; + if DownloadThread = nil then Exit; + url := MaybeFillHost(Module.RootURL, AURL); + url := TrimRightChar(url, ['/']) + '-1.html'; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(url) then begin + Result := True; + PageNumber := XPathCount('(//select[@id="page"])[1]/option', Document); + end; + end; +end; + +function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + baseurl, url, s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + baseurl := MaybeFillHost(Module.RootURL, AURL); + url := TrimRightChar(baseurl, ['/']) + '-' + IncStr(DownloadThread.WorkId) + '.html'; + with DownloadThread.Task.Container, DownloadThread.FHTTP do begin + Headers.Values['Referer'] := baseurl; + if GET(url) then begin + Result := True; + s := XPathString('//img[@id="comicpic"]/@src', Document); + PageLinks[DownloadThread.WorkId] := s; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; + v: IXQValue; + i, x: Integer; +begin + Result := NET_PROBLEM; + if Module.CurrentDirectoryIndex = 0 then + s := '0-9' + else + s := ALPHA_LIST_UP[Module.CurrentDirectoryIndex + 1]; + if MangaInfo.FHTTP.GET(Module.RootURL + '/category/' + s + '_'+ IncStr(AURL) + '.html') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try + i := 1; + for v in XPath('//*[@class="booklist"]//span[@class="pagetor"]//text()') do begin + x := StrToIntDef(v.toString, 1); + if x > i then i := x; + end; + updateList.CurrentDirectoryPageNumber := i; + XPathHREFtitleAll('//*[@class="booklist"]/table//dl/dd/a[1]', ALinks, ANames); + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'WieManga'; + RootURL := 'https://www.wiemanga.com'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + TotalDirectory := Length(ALPHA_LIST_UP); + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index a7c5545d6..6022a4d79 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -8,7 +8,7 @@ English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,He Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga -German=MangaTube,MeinManga,NineMangaDE +German=MangaTube,MeinManga,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL From bffb092f23acd3c8d1b693ace62bb86de6b630b1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 25 Jan 2018 20:28:41 +0300 Subject: [PATCH 1984/2794] Add mangaf [AR] fixes #739 --- baseunits/ModuleList.inc | 1 + baseunits/modules/Mangaf.pas | 120 +++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Mangaf.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 91703abd6..745d0c814 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -63,6 +63,7 @@ uses Mangadex, MangaTube, WieManga, + Mangaf, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/Mangaf.pas b/baseunits/modules/Mangaf.pas new file mode 100644 index 000000000..0025e562b --- /dev/null +++ b/baseunits/modules/Mangaf.pas @@ -0,0 +1,120 @@ +unit Mangaf; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, FMDVars; + +implementation + +const + dirurl: String = '/api/v1/explore/state/'; + dirstates: array[0..2] of String = ('stopped', 'ongoing', 'completed'); + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + s, p: String; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + s := dirstates[Module.CurrentDirectoryIndex]; + p := IncStr(AURL); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + s + '?page=' + p) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + if AURL = '0' then begin + s := XPathString('json(*).last_page'); + updateList.CurrentDirectoryPageNumber := StrToIntDef(XPathString('json(*).last_page'), 0); + end; + for v in XPath('json(*).data()') do begin + s := v.getProperty('slug').toString; + p := v.getProperty('name').toString; + ALinks.Add(Module.RootURL + '/m/' + v.getProperty('slug').toString); + ANames.Add(v.getProperty('name').toString); + end; + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + v := XPath('//div[@id="content"]/noscript/div[@class="container"]'); + if title = '' then title := XPathString('h2', v); + coverLink := XPathString('img/@src', v); + authors := XPathString('dl[dt="الكاتب"]/dd', v); + artists := XPathString('dl[dt="الراسم"]/dd', v); + genres := XPathStringAll('dl[dt="التصنيفات"]/dd/a', ', ', v); + status := MangaInfoStatusIfPos(XPathString('dl[dt="الحالة"]/dd', v), + 'مستمرة', + 'مكتملة'); + summary := XPathString('dl[dt="القصة"]/dd', v); + XPathHREFAll('div[@class="Chapters"]/ul/li/a', chapterLinks, chapterName, v); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//noscript/div[@class="container"]/ul/li/img/@src') do + PageLinks.Add(v.toString()); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Mangaf'; + RootURL := 'http://mangaf.co/'; + TotalDirectory := 3; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index 6022a4d79..7a9c38689 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] -Arabic=GManga,MangaAe,MangaAr,MangaAt +Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans From 36e22fecd90de25edd0acad872b74224f3592322 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 25 Jan 2018 20:40:49 +0300 Subject: [PATCH 1985/2794] Add ChampionScans [EN-Scanlation] --- baseunits/modules/FoOlSlide.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 53091849e..c2e031d6e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -260,6 +260,7 @@ procedure RegisterModule; AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com'); AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com'); AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org'); + AddWebsiteModule('ChampionScans', 'http://reader.championscans.com'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index 7a9c38689..0613b3847 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans +English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MangaTube,MeinManga,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From 4b429415f7a1c9fd5d28011949df49a42122b406 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 25 Jan 2018 21:32:16 +0300 Subject: [PATCH 1986/2794] Add LHTranslation [EN-Scanlation] --- baseunits/ModuleList.inc | 1 + baseunits/modules/LHTranslation.pas | 102 ++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/LHTranslation.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 745d0c814..58fc5e207 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -64,6 +64,7 @@ uses MangaTube, WieManga, Mangaf, + LHTranslation, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/LHTranslation.pas b/baseunits/modules/LHTranslation.pas new file mode 100644 index 000000000..b65f90d93 --- /dev/null +++ b/baseunits/modules/LHTranslation.pas @@ -0,0 +1,102 @@ +unit LHTranslation; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + readerUrl = 'http://read.lhtranslation.com'; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + if title = '' then title := XPathString('//h1[@class="postsby"]/substring-after(.,":")'); + title := Trim(title); + coverLink := XPathString('(//div[@class="featured-thumbnail"])[1]/img/@src'); + // FIXME: no genres, summary, etc + // some chapters are not available for online reading + for v in XPath('//h2[@class="title"]/a') do begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(Trim(ReplaceString(v.toString, title, ''))); + end; + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + s: String; +begin + Result := False; + if DownloadThread = nil then Exit; + s := '/read-' + ReplaceString(AURL, '/', '') + '.html'; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(readerUrl, s)) then begin + Result := True; + XPathStringAll('//img[@class="chapter-img"]/@src', Document, PageLinks); + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//select[@id="cat"]/option[@value!="-1"]') do begin + ALinks.Add(Module.RootURL + '/?cat=' + v.toNode.getAttribute('value')); + ANames.Add(v.toString); + end; + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'LHTranslation'; + RootURL := 'http://lhtranslation.com'; + TotalDirectory := 1; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index 0613b3847..bac51f6d7 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans +English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MangaTube,MeinManga,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From 6c868919f90ed2afcc95293c35ae3cfd1c6da49a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 26 Jan 2018 06:16:51 +0300 Subject: [PATCH 1987/2794] unionmangas, fix download fixes #871 --- baseunits/modules/UnionMangas.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index b2609563e..624124c60 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -77,7 +77,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('//*[@id="image"]//img[contains(@data-lazy,"/leitor/")]/@data-lazy', Document, PageLinks); + XPathStringAll('//img[contains(@class, "")]/@src', Document, PageLinks); end; end; end; From 0958fcac605f3c91729048240aefcad07ef7a4c9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 26 Jan 2018 06:26:53 +0300 Subject: [PATCH 1988/2794] mangadex, fix update list --- baseunits/modules/Mangadex.pas | 49 +++++++++++----------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index f117e37ea..9c3fba63a 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -104,46 +104,29 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - s: String; + s, p: String; begin Result := NET_PROBLEM; - s := IntToStr(StrToInt(AURL) * PerPage); + if Module.CurrentDirectoryIndex = 0 then + s := '~' + else + s := ALPHA_LIST_UP[Module.CurrentDirectoryIndex + 1]; + p := IntToStr(StrToInt(AURL) * PerPage); MangaInfo.FHTTP.Cookies.Values['mangadex_h_toggle'] := '1'; - // FIXME: /titles shows titles in alphabetical order rather than last updated - // maybe it will be changed in future - if MangaInfo.FHTTP.GET(Module.RootURL + '/titles/' + s) then + if MangaInfo.FHTTP.GET(Module.RootURL + '/titles/' + s + '/' + p) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - updateList.CurrentDirectoryPageNumber := 1; - XPathHREFAll('//table/tbody/tr/td[2]/a', ALinks, ANames); - finally - Free; - end; - end; -end; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - MangaInfo.FHTTP.Cookies.Values['mangadex_h_toggle'] := '1'; - // FIXME: /titles shows titles in alphabetical order rather than last updated - // maybe it will be changed in future - if MangaInfo.FHTTP.GET(Module.RootURL + '/titles') then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - s := XPathString('//li[@class="paging"]/a[contains(span/@title, "last")]/@href'); - if s <> '' then begin - s := ReplaceRegExpr('^.+\/(\d+)$', s, '$1', True); - Page := (StrToIntDef(s, 0) div PerPage) + 1; + if AURL = '0' then begin + updateList.CurrentDirectoryPageNumber := 1; + s := XPathString('//li[@class="paging"]/a[contains(span/@title, "last")]/@href'); + if s <> '' then begin + s := ReplaceRegExpr('^.+\/(\d+)$', s, '$1', True); + updateList.CurrentDirectoryPageNumber := (StrToIntDef(s, 0) div PerPage) + 1; + end; end; + XPathHREFAll('//table/tbody/tr/td[2]/a', ALinks, ANames); finally Free; end; @@ -155,10 +138,10 @@ procedure RegisterModule; with AddModule do begin Website := 'Mangadex'; RootURL := 'https://mangadex.com'; + TotalDirectory := Length(ALPHA_LIST_UP); OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnGetNameAndLink := @GetNameAndLink; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); end; From ca1c2e0dfeb79fc3aa33923727aefa47fff73ed4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 26 Jan 2018 06:29:19 +0300 Subject: [PATCH 1989/2794] update changelog.txt --- changelog.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/changelog.txt b/changelog.txt index 24d8c7cad..8dee95532 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,25 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.131.0 (xx-xx-2018) +[+] Added LHTranslation [EN-SC] +[+] Added ChampionScans [EN-SC] +[+] Added Mangaf [AR] +[+] Added WieManga [DE] +[+] Added MangaTube [DE] +[+] Added AtelierDuNoir [EN-SC] +[+] Added MangaDex [EN] +[+] Added MangaHub [RU] +[+] Added Turkish translation by Tmp341 +[+] Added WebP codec library (libwebp) +[+] Enabled high DPI awareness +[*] MangaTown, exclude ads page +[*] MangaChan, fix domain +[*] UnionMangas, fix download +[*] Update localization [EN, RU] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.130.0...0.9.131.0 + 0.9.130.0 (23-01-2018) [+] Added transfer favorites [+] Added rename favorites From 56258412dd2e60ac20fcb67f2a6a4735009b7d0c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 26 Jan 2018 11:54:40 +0300 Subject: [PATCH 1990/2794] fix typo --- baseunits/modules/UnionMangas.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 624124c60..0a7f2fd4d 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -77,7 +77,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('//img[contains(@class, "")]/@src', Document, PageLinks); + XPathStringAll('//img[contains(@class, "img-manga")]/@src', Document, PageLinks); end; end; end; From 0b73cc3d34921032f75537c865b2a5ae75b1c89b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 26 Jan 2018 16:19:18 +0300 Subject: [PATCH 1991/2794] Add mangarock fixes #786 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaRock.pas | 230 ++++++++++++++++++++++++++++++++ baseunits/uBaseUnit.pas | 36 ++++- changelog.txt | 1 + config/mangalist.ini | 2 +- 5 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 baseunits/modules/MangaRock.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 58fc5e207..570eb925a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -65,6 +65,7 @@ uses WieManga, Mangaf, LHTranslation, + MangaRock, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas new file mode 100644 index 000000000..4ffd59cad --- /dev/null +++ b/baseunits/modules/MangaRock.pas @@ -0,0 +1,230 @@ +unit MangaRock; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, webp, MemBitmap, Math, xquery; + +implementation + +var + mangaList: TStringList; + +const + ModuleApiUrl: String = 'https://api.mangarockhd.com'; + DirRequest: String = '{"status":"all","genres":{},"rank":"all","order":"name"}'; + PerPage = 100; + +function DecryptImage(const imageData: TStream): TMemoryStream; +var + n, i: Integer; + tmp: TMemoryStream; +begin + n := imageData.Size + 7; + tmp := TMemoryStream.Create; + + // RIFF header + tmp.WriteByte(82); + tmp.WriteByte(73); + tmp.WriteByte(70); + tmp.WriteByte(70); + + // image size + tmp.WriteByte(n and $FF); + tmp.WriteByte((n shr 8) and $FF); + tmp.WriteByte((n shr 16) and $FF); + tmp.WriteByte((n shr 24) and $FF); + + // WEBPVP8 header + tmp.WriteByte(87); + tmp.WriteByte(69); + tmp.WriteByte(66); + tmp.WriteByte(80); + tmp.WriteByte(86); + tmp.WriteByte(80); + tmp.WriteByte(56); + + for i := 0 to imageData.Size - 1 do + tmp.WriteByte(imageData.ReadByte xor 101); + + tmp.Seek(0, TSeekOrigin.soBeginning); + Result := tmp; +end; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + mangaId, name: String; + query: TXQueryEngineHTML; + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + mangaId := TrimRightChar(SeparateRight(AURL, 'manga/'), ['/']); + if MangaInfo.FHTTP.GET(ModuleApiUrl + '/query/web400/info?oid=' + mangaId) then + begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document); + with MangaInfo.mangaInfo do + begin + title := query.XPathString('json(*).data.name'); + coverLink := query.XPathString('json(*).data.thumbnail'); + summary := query.XPathString('json(*).data.description'); + + genres := ''; + for v in query.XPath('json(*).data.rich_categories().name') do + AddCommaString(genres, v.toString()); + + authors := ''; + artists := ''; + for v in query.XPath('json(*).data.authors()') do + begin + name := v.getProperty('name').toString(); + if CompareText(v.getProperty('role').toString(), 'art') = 0 then + AddCommaString(artists, name) + else + AddCommaString(authors, name) + end; + + status := MangaInfoStatusIfPos(query.XPathString('json(*).data.completed'), 'false', 'true'); + + for v in query.XPath('json(*).data.chapters()') do + begin + chapterName.Add(v.getProperty('name').toString()); + chapterLinks.Add(v.getProperty('oid').toString()); + end; + end; + query.Free; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + chapterId: String; +begin + Result := False; + if DownloadThread = nil then Exit; + DownloadThread.Task.Container.PageLinks.Clear; + DownloadThread.Task.Container.PageNumber := 0; + chapterId := TrimLeftChar(AURL, ['/']); + if DownloadThread.FHTTP.GET(ModuleApiUrl + '/query/web400/pages?oid=' + chapterId) then + begin + Result := True; + XPathStringAll('json(*).data()', + DownloadThread.FHTTP.Document, + DownloadThread.Task.Container.PageLinks); + end; +end; + +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; +var + decoded: TMemoryStream; + img: TMemBitmap; +begin + decoded := nil; + img := nil; + Result := False; + if DownloadThread = nil then Exit; + if DownloadThread.FHTTP.GET(AURL) then + begin + try + decoded := DecryptImage(DownloadThread.FHTTP.Document); + img := WebPToMemBitmap(decoded); + Result := SaveImageAsPngFile(img, APath, AName) <> ''; + finally + img.Free; + decoded.Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; + const AURL: String; const Module: TModuleContainer): Integer; +var + index, i, ubound: Integer; + request: String; + query: TXQueryEngineHTML; + v: TXQProperty; + name, link: string; + obj: IXQValue; +begin + Result := NET_PROBLEM; + if (MangaInfo = nil) or (mangaList = nil) then Exit(UNKNOWN_ERROR); + + index := StrToInt(AURL); + ubound := Min((index + 1) * PerPage - 1, mangaList.Count - 1); + request := '"' + mangaList[index * PerPage] + '"'; + for i := index * PerPage + 1 to ubound do + request := request + ',"' + mangaList[i] + '"'; + request := '[' + request + ']'; + + MangaInfo.FHTTP.MimeType := 'application/json'; + if MangaInfo.FHTTP.POST(ModuleApiUrl + '/meta', request) then + begin + Result := NO_ERROR; + query := TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document); + for i := index * PerPage + 1 to ubound do + begin + name := query.XPathString('json(*).data("' + mangaList[i] + '").name'); + ANames.Add(name); + ALinks.Add(Module.RootURL + '/manga/' + mangaList[i]); + end; + query.Free; + end; + + if ubound = mangaList.Count - 1 then + begin + mangaList.Free; + mangaList := nil; + end; +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.FHTTP.MimeType := 'application/json'; + if MangaInfo.FHTTP.POST(ModuleApiUrl + '/query/web400/mrs_filter', DirRequest) then + begin + Result := NO_ERROR; + mangaList := TStringList.Create; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathStringAll('json(*).data()', mangaList); + Page := mangaList.Count div PerPage; + if mangaList.Count mod PerPage <> 0 then + Inc(Page); + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'MangaRock'; + RootURL := 'https://mangarock.com'; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + OnGetNameAndLink := @GetNameAndLink; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + end; +end; + +initialization + RegisterModule; + +finalization + mangaList.Free; + +end. + diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 83af45097..ad198a35f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -22,7 +22,8 @@ interface strutils, dateutils, variants, base64, fpjson, jsonparser, jsonscanner, FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, - simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit; + simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit, + MemBitmap, FPWritePNG; const JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); @@ -749,6 +750,8 @@ function GetURLFromBitly(const URL: String): String; function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; overload; function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String; overload; +function SaveImageAsPngFile(image: TMemBitmap; Path, FileName: String): String; + // detect and save image from base64 string function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; @@ -3410,6 +3413,37 @@ function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; end; end; +function SaveImageAsPngFile(image: TMemBitmap; Path, FileName: String): String; +var + p, f: String; + fs: TFileStreamUTF8; + writer: TFPWriterPNG; +begin + Result := ''; + if image = nil then Exit; + p := CorrectPathSys(Path); + if ForceDirectoriesUTF8(p) then begin + f := p + FileName + '.png'; + if FileExistsUTF8(f) then DeleteFileUTF8(f); + try + fs := TFileStreamUTF8.Create(f, fmCreate); + writer := TFPWriterPNG.Create; + writer.Indexed := false; + writer.UseAlpha := image.HasTransparentPixels; + try + image.SaveToStream(fs, writer); + finally + writer.Free; + fs.Free; + end; + except + on E: Exception do + Logger.SendException('SaveImageAsPngFile Failed! ' + f, E); + end; + end; + if FileExistsUTF8(f) then Result := f; +end; + function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; diff --git a/changelog.txt b/changelog.txt index 8dee95532..4186a37ff 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,7 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.131.0 (xx-xx-2018) +[+] Added Mangarock [EN] [+] Added LHTranslation [EN-SC] [+] Added ChampionScans [EN-SC] [+] Added Mangaf [AR] diff --git a/config/mangalist.ini b/config/mangalist.ini index bac51f6d7..75ac56d50 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 13aca521fb19b88669ddb8af82b722eb5cbfc564 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 27 Jan 2018 00:57:08 +0800 Subject: [PATCH 1992/2794] remove vt from vtlist on destroy (fixed #872) --- mangadownloader/forms/frmAccountManager.pas | 4 ++- mangadownloader/forms/frmCustomColor.pas | 21 ++++++++++++++- mangadownloader/forms/frmMain.lfm | 4 +-- mangadownloader/forms/frmMain.pas | 12 ++++----- .../forms/frmTransferFavorites.lfm | 2 ++ .../forms/frmTransferFavorites.pas | 6 +++++ .../forms/frmWebsiteOptionAdvanced.lfm | 3 +-- .../forms/frmWebsiteOptionAdvanced.pas | 27 ++++++++++++++----- 8 files changed, 61 insertions(+), 18 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 722da7787..5f8b2a5cd 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -98,7 +98,7 @@ TAccountCheck = class implementation -uses frmMain; +uses frmMain, frmCustomColor; var Websites, WebsitesAvailable: TStringlist; @@ -340,10 +340,12 @@ procedure TAccountManagerForm.FormCreate(Sender: TObject); Websites.Sorted := True; end; LoadForm; + AddVT(vtAccountList); end; procedure TAccountManagerForm.FormDestroy(Sender: TObject); begin + RemoveVT(vtAccountList); if Assigned(Websites) then Websites.Free; if Assigned(WebsitesAvailable) then WebsitesAvailable.Free; if Assigned(AccountThreadList) then AccountThreadList.Free; diff --git a/mangadownloader/forms/frmCustomColor.pas b/mangadownloader/forms/frmCustomColor.pas index 875d6a74d..84356c2b2 100644 --- a/mangadownloader/forms/frmCustomColor.pas +++ b/mangadownloader/forms/frmCustomColor.pas @@ -110,11 +110,13 @@ TVTApplyList = class destructor Destroy; override; function IndexOf(const AVT: VirtualTrees.TVirtualStringTree): Integer; procedure Add(const AVT: VirtualTrees.TVirtualStringTree); + procedure Remove(const AVT: VirtualTrees.TVirtualStringTree); property Items[Index: Integer]: VirtualTrees.TVirtualStringTree read GetItems write SetItems; default; property Count: Integer read FCount; end; -procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); +procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); inline; +procedure RemoveVT(const AVT: VirtualTrees.TVirtualStringTree); inline; procedure Apply; procedure LoadFromIniFile(const IniFile: TIniFile); procedure SaveToIniFile(const IniFile: TIniFile); @@ -245,6 +247,11 @@ procedure AddVT(const AVT: VirtualTrees.TVirtualStringTree); VTApplyList.Add(AVT); end; +procedure RemoveVT(const AVT: VirtualTrees.TVirtualStringTree); +begin + VTApplyList.Remove(AVT); +end; + procedure ApplyToFMDOptions; begin //basiclist @@ -545,6 +552,18 @@ procedure TVTApplyList.Add(const AVT: VirtualTrees.TVirtualStringTree); end; end; +procedure TVTApplyList.Remove(const AVT: VirtualTrees.TVirtualStringTree); +var + i: Integer; +begin + i := IndexOf(AVT); + if i = -1 then Exit; + Dec(FCount); + if i <> FCount then + FVTList[i] := FVTList[FCount]; + SetLength(FVTList, FCount); +end; + { TVirtualStringTree } procedure TVirtualStringTree.SetCI(AValue: TColorItems); diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index ea0101f08..d638c4c1a 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4420,13 +4420,13 @@ object MainForm: TMainForm ClientWidth = 761 object btCheckLatestVersion: TBitBtn AnchorSideTop.Control = pcAbout - AnchorSideTop.Side = asrBottom + AnchorSideTop.Side = asrBottom Left = 0 Height = 40 Top = 447 Width = 208 - BorderSpacing.Top = 3 Anchors = [akTop, akLeft, akBottom] + BorderSpacing.Top = 3 Caption = 'Check for latest version' Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 43be47821..896a9d025 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1237,12 +1237,6 @@ procedure TMainForm.FormCreate(Sender: TObject); AddVT(Self.vtDownload); AddVT(Self.vtFavorites); AddVT(Self.vtOptionMangaSiteSelection); - AddVT(AccountManagerForm.vtAccountList); - AddVT(WebsiteOptionAdvancedForm.vtCookies); - AddVT(WebsiteOptionAdvancedForm.vtUserAgent); - AddVT(WebsiteOptionAdvancedForm.vtDownloadMaxThreadsPerTask); - AddVT(WebsiteOptionAdvancedForm.vtUpdateListDirectoryPageNumber); - AddVT(WebsiteOptionAdvancedForm.vtUpdateListNumberOfThreads); end; // logger @@ -1389,6 +1383,12 @@ procedure TMainForm.CloseNow; procedure TMainForm.FormDestroy(Sender: TObject); begin Logger.Send(Self.ClassName+'.FormDestroy, freeing all objects'); + RemoveVT(vtMangaList); + RemoveVT(clbChapterList); + RemoveVT(vtDownload); + RemoveVT(vtFavorites); + RemoveVT(vtOptionMangaSiteSelection); + SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); diff --git a/mangadownloader/forms/frmTransferFavorites.lfm b/mangadownloader/forms/frmTransferFavorites.lfm index d4d5ef0f0..d1dc65f0c 100644 --- a/mangadownloader/forms/frmTransferFavorites.lfm +++ b/mangadownloader/forms/frmTransferFavorites.lfm @@ -11,6 +11,7 @@ object TransferFavoritesForm: TTransferFavoritesForm ClientHeight = 490 ClientWidth = 490 OnCreate = FormCreate + OnDestroy = FormDestroy OnShow = FormShow Position = poMainFormCenter object cbWebsites: TComboBox @@ -68,6 +69,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Width = 150 end> Header.DefaultHeight = 17 + Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] Images = imgsState TabOrder = 1 diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas index 2b43847e6..331eeccb8 100644 --- a/mangadownloader/forms/frmTransferFavorites.pas +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -28,6 +28,7 @@ TTransferFavoritesForm = class(TForm) procedure btOKClick(Sender: TObject); procedure cbWebsitesChange(Sender: TObject); procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); procedure rbAllChange(Sender: TObject); procedure vtFavsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); @@ -188,6 +189,11 @@ procedure TTransferFavoritesForm.FormCreate(Sender: TObject); FInvalidCount := 0; end; +procedure TTransferFavoritesForm.FormDestroy(Sender: TObject); +begin + frmCustomColor.RemoveVT(vtFavs); +end; + procedure TTransferFavoritesForm.FormShow(Sender: TObject); begin UpdateFilterCount; diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index 638ebd961..321c6d16c 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -6,8 +6,7 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ClientHeight = 307 ClientWidth = 510 OnCreate = FormCreate - LCLVersion = '1.7' - Visible = False + OnDestroy = FormDestroy object pcAdvanced: TPageControl Left = 0 Height = 307 diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 138ebec89..95b331f7d 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -41,6 +41,7 @@ TWebsiteOptionAdvancedForm = class(TForm) vtUpdateListNumberOfThreads: TVirtualStringTree; vtUserAgent: TVirtualStringTree; procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); procedure MenuItem1Click(Sender: TObject); procedure MenuItem2Click(Sender: TObject); procedure MenuItem4Click(Sender: TObject); @@ -66,8 +67,8 @@ TWebsiteOptionAdvancedForm = class(TForm) Column: TColumnIndex; const NewText: String); private { private declarations } - procedure LoadFromFileToVT(const AVT: TVirtualStringTree; const ASection: String); - procedure GetWebsite(const AVT: TVirtualStringTree; const S: TStrings); + procedure LoadFromFileToVT(const AVT: VirtualTrees.TVirtualStringTree; const ASection: String); + procedure GetWebsite(const AVT: VirtualTrees.TVirtualStringTree; const S: TStrings); public { public declarations } end; @@ -77,12 +78,19 @@ TWebsiteOptionAdvancedForm = class(TForm) implementation +uses frmCustomColor; + {$R *.lfm} { TWebsiteOptionAdvancedForm } procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); begin + AddVT(vtCookies); + AddVT(vtUserAgent); + AddVT(vtDownloadMaxThreadsPerTask); + AddVT(vtUpdateListDirectoryPageNumber); + AddVT(vtUpdateListNumberOfThreads); LoadFromFileToVT(vtCookies, 'Cookies'); LoadFromFileToVT(vtUserAgent, 'UserAgent'); LoadFromFileToVT(vtDownloadMaxThreadsPerTask, 'DownloadMaxThreadsPerTask'); @@ -90,6 +98,15 @@ procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); LoadFromFileToVT(vtUpdateListNumberOfThreads, 'UpdateListNumberOfThreads'); end; +procedure TWebsiteOptionAdvancedForm.FormDestroy(Sender: TObject); +begin + RemoveVT(vtCookies); + RemoveVT(vtUserAgent); + RemoveVT(vtDownloadMaxThreadsPerTask); + RemoveVT(vtUpdateListDirectoryPageNumber); + RemoveVT(vtUpdateListNumberOfThreads); +end; + procedure TWebsiteOptionAdvancedForm.MenuItem1Click(Sender: TObject); var Data: PNameValue; @@ -231,8 +248,7 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesNewText(Sender: TBaseVirtualTree; end; end; -procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: TVirtualStringTree; - const ASection: String); +procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: VirtualTrees.TVirtualStringTree; const ASection: String); var s: TStringList; i: Integer; @@ -270,8 +286,7 @@ procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: TVirtualStringT end; end; -procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: TVirtualStringTree; - const S: TStrings); +procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtualStringTree; const S: TStrings); var Data: PNameValue; Node: PVirtualNode; From 9c928fef8139ba0394ecf5fd712200f67805d2bb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 27 Jan 2018 02:10:37 +0800 Subject: [PATCH 1993/2794] ctrl+shift+v on mangainfo url text to paste and go (fixed #873) --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index d638c4c1a..e8a1f22c0 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -765,6 +765,7 @@ object MainForm: TMainForm MaxLength = 0 NumGlyphs = 1 OnButtonClick = edURLButtonClick + OnKeyDown = edURLKeyDown OnKeyPress = edURLKeyPress PasswordChar = #0 PopupMenu = pmEditURL diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 896a9d025..27111474e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -445,6 +445,7 @@ TMainForm = class(TForm) procedure edOptionExternalPathButtonClick(Sender: TObject); procedure edSaveToButtonClick(Sender: TObject); procedure edURLButtonClick(Sender: TObject); + procedure edURLKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure edURLKeyPress(Sender: TObject; var Key: Char); procedure edWebsitesSearchButtonClick(Sender: TObject); procedure edWebsitesSearchChange(Sender: TObject); @@ -1768,7 +1769,8 @@ procedure TMainForm.medURLPasteClick(Sender: TObject); procedure TMainForm.medURLPasteandgoClick(Sender: TObject); begin - edURL.Text := Clipboard.AsText; + edURL.Clear; + edURL.PasteFromClipboard; edURLButtonClick(edURL); end; @@ -5400,6 +5402,15 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); ViewMangaInfo(link, website, ''); end; +procedure TMainForm.edURLKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + if (ssCtrl in Shift) and (ssShift in Shift) and (Key = VK_V) then + begin + Key := 0; + medURLPasteandgoClick(medURLPasteandgo); + end; +end; + procedure TMainForm.UpdateVtChapter; begin if clbChapterList.RootNodeCount = Length(ChapterList) then From e38ded4da006d5d4a3b0aba90208e558a5d4be96 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 27 Jan 2018 02:24:26 +0800 Subject: [PATCH 1994/2794] ctrl+shift+c on mangainfo url text copy all text --- mangadownloader/forms/frmMain.pas | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 27111474e..a92840e43 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5404,10 +5404,14 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); procedure TMainForm.edURLKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin - if (ssCtrl in Shift) and (ssShift in Shift) and (Key = VK_V) then + if (ssCtrl in Shift) and (ssShift in Shift) then begin + if Key = VK_V then + medURLPasteandgoClick(medURLPasteandgo) + else + if Key = VK_C then + Clipboard.AsText := edURL.Text; Key := 0; - medURLPasteandgoClick(medURLPasteandgo); end; end; From d65412190466e690c32512259eb7ef92e412bec5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 27 Jan 2018 03:33:19 +0800 Subject: [PATCH 1995/2794] Bump version 0.9.131.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4186a37ff..f223f5813 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.131.0 (xx-xx-2018) +0.9.131.0 (27-01-2018) [+] Added Mangarock [EN] [+] Added LHTranslation [EN-SC] [+] Added ChampionScans [EN-SC] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 587c3c8de..9f68ccc78 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="130"/> + <RevisionNr Value="131"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 9c5743977..f6abaa750 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.130.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.130.0/fmd_0.9.130.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.130.0/fmd_0.9.130.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.130.0/fmd_0.9.130.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.130.0/fmd_0.9.130.0_Win64.7z +VERSION=0.9.131.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.131.0/fmd_0.9.131.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.131.0/fmd_0.9.131.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.131.0/fmd_0.9.131.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.131.0/fmd_0.9.131.0_Win64.7z From 6b3bac96a521ba79dee475eeaec4e6d2d89bb91d Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Sat, 27 Jan 2018 10:46:37 +0300 Subject: [PATCH 1996/2794] Update fmd.tr_TR.po * At Line 63, changed translation to much more understandable phrase. * At Line 371, added it's English short form, so people can find what it is. * At Lines 648, 652, 657, 662, 668, 678, 698 and 703, changed translations to much more accurate phrases. * At Line 747, changed translation to much more understandable phrase. * At Line 1227, changed translation to much more accurate phrase. * At Line 1385, only 4 character shows. Going back to general "host" word. * At "Options\Connections" tab, seems like "Number of retry times if task failed" and "Always start task from failed chapters" options are hardcoded or haven't included inside Language files. * At Line 1438, changed translation to much more understandable phrase. * At "Options\Save to\Save downloaded chapters as", "None" option looks hardcoded. * At Line 1905, removed unnecessary character. * At Options\Misc\Custom color", color options look hardcoded. --- mangadownloader/languages/fmd.tr_TR.po | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 53ac884a4..f3fa02fb9 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -60,7 +60,7 @@ msgid "" "2400x\n" "Original\n" msgstr "" -"Oto\n" +"Otomatik\n" "780x\n" "980x\n" "1280x\n" @@ -368,7 +368,7 @@ msgstr "Geçerli" #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" -msgstr "Başlatma Vektörü:" +msgstr "Başlatma Vektörü (IV):" #: kissmanga.rs_kissmanga_key msgid "Key:" @@ -645,27 +645,27 @@ msgstr "Sadece yeni manga ara" #: tmainform.cboptionautocheckfavdownload.caption msgctxt "tmainform.cboptionautocheckfavdownload.caption" msgid "Automatic download after finish checking" -msgstr "Kontrol bittikten sonra oto indir" +msgstr "Kontrol bittikten sonra otomatik indir" #: tmainform.cboptionautocheckfavinterval.caption msgid "Auto check for new chapter in an interval" -msgstr "Beklerken yeni bölümleri oto kontrol et" +msgstr "Beklerken yeni bölümleri otomatik kontrol et" #: tmainform.cboptionautocheckfavremovecompletedmanga.caption msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" msgid "Automatic remove completed manga from Favorites" -msgstr "Tamamlanmış mangayı Favorilerden oto kaldır" +msgstr "Tamamlanmış mangayı Favorilerden otomatik kaldır" #: tmainform.cboptionautocheckfavstartup.caption #| msgid "Automatic check for new chapter at startup" msgid "Auto check for new chapter at startup" -msgstr "Başlangıça yeni bölümleri oto kontrol et" +msgstr "Başlangıça yeni bölümleri otomatik kontrol et" #: tmainform.cboptionautochecklatestversion.caption #| msgid "Check for new version " msgctxt "tmainform.cboptionautochecklatestversion.caption" msgid "Auto check for latest version " -msgstr "Son sürümü oto kontrol et " +msgstr "Son sürümü otomatik kontrol et " #: tmainform.cboptionautoopenfavstartup.caption msgid "Open Favorites at startup" @@ -675,7 +675,7 @@ msgstr "Başlangıçta Favorileri aç" #| msgid "Change all all character to" msgctxt "tmainform.cboptionchangeunicodecharacter.caption" msgid "Replace all unicode character with" -msgstr "Tüm Unicode karakteri şununla değiştir" +msgstr "Tüm Unicode karakterleri şununla değiştir" #: tmainform.cboptionchangeunicodecharacter.hint msgid "Enable this if you have problem with unicode character in path." @@ -695,12 +695,12 @@ msgstr "Manga afişini yüklemeyi aç" #: tmainform.cboptiongeneratechapterfolder.caption msgid "Auto generate chapter folder" -msgstr "Bölüm klasörünü oto oluştur" +msgstr "Bölüm klasörünü otomatik oluştur" #: tmainform.cboptiongeneratemangafolder.caption msgctxt "tmainform.cboptiongeneratemangafolder.caption" msgid "Auto generate folder based on manga's name" -msgstr "Klasörü manga adına göre oto oluştur" +msgstr "Klasörü manga adına göre otomatik oluştur" #: tmainform.cboptionlivesearch.caption msgid "Enable live search (slow on long list)" @@ -744,7 +744,7 @@ msgstr "İndirmeler araç çubuğunu göster" #: tmainform.cboptionshowdownloadtoolbardeleteall.caption msgid "Show \"Delete all completed tasks\" in downloads toolbar" -msgstr "\"Tüm tamamlanmış görevleri sili\" indirmeler araç çubuğunda göster" +msgstr "\"Tüm tamamlanmış görevleri sil\" seçeneğini indirmeler araç çubuğunda göster" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -1224,7 +1224,7 @@ msgstr "Vekil ayarları" #: tmainform.gboptionrenaming.caption msgid "Renaming" -msgstr "Yeniden adlandırılıyor" +msgstr "Yeniden adlandırma" #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" @@ -1382,7 +1382,7 @@ msgstr "" #: tmainform.lboptionhost.caption msgid "Host" -msgstr "Sunucu" +msgstr "Host" #: tmainform.lboptionlanguage.caption msgid "Language:" @@ -1435,7 +1435,7 @@ msgstr "Tek görev başına aynı anda indirilmiş dosya sayısı (Maks: 32)" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" -msgstr "Güncelleme süresine (günler) göre yeni manga" +msgstr "Manga güncelleme süresine göre yeni manga (gün bazlı)" #: tmainform.lboptionpass.caption msgctxt "tmainform.lboptionpass.caption" @@ -1902,7 +1902,7 @@ msgstr "Ayarlar" #: tmainform.tswebsites.caption msgctxt "tmainform.tswebsites.caption" msgid "Websites" -msgstr "Websiteleri" +msgstr "Websiteler" #: tmainform.tswebsiteselection.caption msgctxt "tmainform.tswebsiteselection.caption" From 4d4654131a4b2d6e115de0bb13d07badf2c82075 Mon Sep 17 00:00:00 2001 From: Havokdan <havokdan@yahoo.com.br> Date: Sat, 27 Jan 2018 06:14:29 -0300 Subject: [PATCH 1997/2794] Update fmd.pt_BR.po --- mangadownloader/languages/fmd.pt_BR.po | 127 +++++-------------------- 1 file changed, 26 insertions(+), 101 deletions(-) diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index a3d72810d..d3f7584cf 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -23,12 +23,7 @@ msgid "" "Image Server NA\n" "CDN (default)\n" "CDN2 (testing)\n" -msgstr "" -"Auto\n" -"Servidor da Imagem EU\n" -"Servidor da Imagem NA\n" -"CDN (padrão)\n" -"CDN2 (testando)\n" +msgstr "Auto\nServidor da Imagem EU\nServidor da Imagem NA\nCDN (padrão)\nCDN2 (testando)\n" #: batoto.rs_showalllang msgctxt "batoto.rs_showalllang" @@ -58,14 +53,7 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "" -"Auto\n" -"780x\n" -"980x\n" -"1280x\n" -"1600x\n" -"2400x\n" -"Original\n" +msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -164,9 +152,7 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "" -"Este título já está na lista de download.\n" -"Você quer baixá-lo mesmo assim?\n" +msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -192,19 +178,14 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "" -"Baixar tudo\n" -"Adicionar aos favoritos\n" +msgstr "Baixar tudo\nAdicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "<none>\n" -msgstr "" -"Completo\n" -"Em Andamento\n" -"<vazio>\n" +msgstr "Completo\nEm Andamento\n<vazio>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -214,9 +195,7 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "" -"Há um problema com estes dados!\n" -"Removendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -270,11 +249,7 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "" -"%s : Caminho para o mangá\n" -"%s : Nome do capítulo\n" -"\n" -"Examplo : \"%s%s\"\n" +msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -308,11 +283,7 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "" -"Nada\n" -"Sair\n" -"Desligar\n" -"Hibernar\n" +msgstr "Nada\nSair\nDesligar\nHibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -354,10 +325,9 @@ msgstr "Sistema irá desligar em %d segundos." #: frmtransferfavorites.rs_all msgctxt "frmtransferfavorites.rs_all" msgid "All" -msgstr "" +msgstr "Todos" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" msgstr "Inválido" @@ -365,7 +335,7 @@ msgstr "Inválido" #: frmtransferfavorites.rs_valid msgctxt "frmtransferfavorites.rs_valid" msgid "Valid" -msgstr "" +msgstr "Válido" #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" @@ -495,15 +465,6 @@ msgstr "Lista de favoritos" msgid "Manga list" msgstr "Lista de mangás" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -865,9 +826,7 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "" -"Meninas vestindo-se como caras, caras vestir-se como meninas.\n" -"Rapazes se transformando em garotas, garotas se transformando em caras.\n" +msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1110,9 +1069,10 @@ msgid "This work usually involves intimate relationships between women." msgstr "Este trabalho geralmente envolve relações íntimas entre as mulheres." #: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +#| msgid "Always start from failed chapters when task start" msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" -msgstr "" +msgstr "Sempre iniciar tarefa dos capítulos que falharam" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1279,16 +1239,7 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "" -"Géneros:\n" -"- Marcado: Inclua este gênero.\n" -"- Desmarcado: exclua esse gênero.\n" -"- Cinzento: Não importa.\n" -"\n" -"Géneros Personalizados:\n" -"- Separar vários gêneros com ','.\n" -"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n" -"- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1340,16 +1291,7 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "" -"%WEBSITE% : Nome doWebsite\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do capítulo\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"%NUMBERING% : Número\n" -"\n" -"Nota:\n" -"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1386,14 +1328,7 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do Capítulo\n" -"%FILENAME% : Nome do arquivo\n" -"\n" -"Nota:\n" -"Nome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1426,14 +1361,7 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"\n" -"Nota:\n" -"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption #| msgid "Number of downloaded tasks at the same time (Max: 8)" @@ -1676,7 +1604,7 @@ msgstr "Abrir ..." #: tmainform.mifavoritesrename.caption msgid "Rename" -msgstr "" +msgstr "Renomear" #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" @@ -1685,7 +1613,7 @@ msgstr "Parar de checar por novos capítulos" #: tmainform.mifavoritestransferwebsite.caption msgctxt "tmainform.mifavoritestransferwebsite.caption" msgid "Transfer website" -msgstr "" +msgstr "Transferir website" #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" @@ -2032,24 +1960,23 @@ msgstr "OK" #: ttransferfavoritesform.caption msgid "Transfer Favorites" -msgstr "" +msgstr "Transferir Favoritos" #: ttransferfavoritesform.ckcleardownloadedchapters.caption msgid "Clear downloaded chapter list and reload from server" -msgstr "" +msgstr "Limpar lista de capítulos baixados e recarregar do servidor" #: ttransferfavoritesform.lbtransferto.caption msgctxt "ttransferfavoritesform.lbtransferto.caption" msgid "Transfer to" -msgstr "" +msgstr "Transferir para" #: ttransferfavoritesform.rball.caption msgctxt "ttransferfavoritesform.rball.caption" msgid "All" -msgstr "" +msgstr "Todos" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" msgstr "Inválido" @@ -2057,14 +1984,14 @@ msgstr "Inválido" #: ttransferfavoritesform.rbvalid.caption msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" -msgstr "" +msgstr "Válido" #: ttransferfavoritesform.vtfavs.header.columns[1].text #, fuzzy #| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Website" +msgstr "Título" #: ttransferfavoritesform.vtfavs.header.columns[2].text #, fuzzy @@ -2084,9 +2011,7 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "" -"Nova versão encontrada! Você quer atualizar agora?\n" -"FMD irá fechar para terminar a atualização.\n" +msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "twebsiteoptionadvancedform.menuitem1.caption" From 54120e2c3fa6c4e44951809b44947057decdeb34 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 27 Jan 2018 19:16:36 +0300 Subject: [PATCH 1998/2794] LHTranslation, fix chapters order fixes #883 --- baseunits/modules/LHTranslation.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/LHTranslation.pas b/baseunits/modules/LHTranslation.pas index b65f90d93..3f801af32 100644 --- a/baseunits/modules/LHTranslation.pas +++ b/baseunits/modules/LHTranslation.pas @@ -35,6 +35,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(Trim(ReplaceString(v.toString, title, ''))); end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; From 4cf730d2e946b35c825b1eccdf6571b955d791db Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Jan 2018 02:25:59 +0800 Subject: [PATCH 1999/2794] add save to compress type resourcestring --- mangadownloader/forms/frmMain.pas | 7 +- mangadownloader/languages/fmd.de.po | 8 ++ mangadownloader/languages/fmd.el_GR.po | 8 ++ mangadownloader/languages/fmd.en.po | 18 ++++ mangadownloader/languages/fmd.es.po | 8 ++ mangadownloader/languages/fmd.id_ID.po | 8 ++ mangadownloader/languages/fmd.pl_PL.po | 8 ++ mangadownloader/languages/fmd.po | 8 ++ mangadownloader/languages/fmd.pt_BR.po | 111 +++++++++++++++++++++---- mangadownloader/languages/fmd.ru_RU.po | 36 ++++++++ mangadownloader/languages/fmd.tr_TR.po | 46 +++++++++- 11 files changed, 249 insertions(+), 17 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a92840e43..837316e5f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -824,6 +824,7 @@ TSearchDBThread = class(TThread) RS_FilterStatusItems = 'Completed'#13#10'Ongoing'#13#10'<none>'; RS_OptionFMDDoItems = 'Nothing'#13#10'Exit'#13#10'Shutdown'#13#10'Hibernate'; RS_DropTargetModeItems = 'Download all'#13#10'Add to favorites'; + RS_OptionCompress = 'None'#13#10'ZIP'#13#10'CBZ'#13#10'PDF'; RS_HintFavoriteProblem = 'There is a problem with this data!'#13#10 + 'Removing and re-adding this data may fix the problem.'; @@ -5592,7 +5593,8 @@ procedure TMainForm.ApplyLanguage; idxFilterStatus, idxOptionLetFMDDo, idxOptionProxyType, - idxDropTargetMode: Integer; + idxDropTargetMode, + idxOptionCompress: Integer; begin if AvailableLanguages.Count = 0 then Exit; if cbLanguages.ItemIndex < 0 then Exit; @@ -5608,6 +5610,7 @@ procedure TMainForm.ApplyLanguage; idxOptionLetFMDDo := cbOptionLetFMDDo.ItemIndex; idxOptionProxyType := cbOptionProxyType.ItemIndex; idxDropTargetMode := rgDropTargetMode.ItemIndex; + idxOptionCompress := rgOptionCompress.ItemIndex; if SimpleTranslator.SetLangByIndex(cbLanguages.ItemIndex) then begin // assign new value @@ -5618,6 +5621,7 @@ procedure TMainForm.ApplyLanguage; cbFilterStatus.Items.Text := RS_FilterStatusItems; cbOptionLetFMDDo.Items.Text := RS_OptionFMDDoItems; rgDropTargetMode.Items.Text := RS_DropTargetModeItems; + rgOptionCompress.Items.Text := RS_OptionCompress; // restore ItemIndex cbSelectManga.ItemIndex:=idxSelectManga; @@ -5626,6 +5630,7 @@ procedure TMainForm.ApplyLanguage; cbOptionLetFMDDo.ItemIndex := idxOptionLetFMDDo; cbOptionProxyType.ItemIndex := idxOptionProxyType; rgDropTargetMode.ItemIndex := idxDropTargetMode; + rgOptionCompress.ItemIndex := idxOptionCompress; Self.Repaint; vtMangaList.Repaint; tvDownloadFilterRefresh(True); diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index ea8390fd1..9b3655d7b 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -302,6 +302,14 @@ msgstr "Ein Monat" msgid "One week" msgstr "Eine Woche" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 7a7c0f86e..79797a96a 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -306,6 +306,14 @@ msgstr "Ένας μήνας" msgid "One week" msgstr "Μια εβδομάδα" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 5fb9363f0..48f2aaf00 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -302,6 +302,14 @@ msgstr "One month" msgid "One week" msgstr "One week" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" @@ -494,6 +502,16 @@ msgstr "Favorite list" msgid "Manga list" msgstr "Manga list" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +#, fuzzy +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "Transfer to" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index a2db5982f..2923a0bb2 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -300,6 +300,14 @@ msgstr "Un Mes" msgid "One week" msgstr "Una Semana" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index e95082ad6..fb1eed228 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -300,6 +300,14 @@ msgstr "Satu bulan" msgid "One week" msgstr "Satu minggu" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 77836a7ae..6fd05909e 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -297,6 +297,14 @@ msgstr "Miesiąc temu" msgid "One week" msgstr "Tydzień temu" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c9efc0fa3..2e8d66277 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -264,6 +264,14 @@ msgstr "" msgid "One week" msgstr "" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index d3f7584cf..a2d69c4c4 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -23,7 +23,12 @@ msgid "" "Image Server NA\n" "CDN (default)\n" "CDN2 (testing)\n" -msgstr "Auto\nServidor da Imagem EU\nServidor da Imagem NA\nCDN (padrão)\nCDN2 (testando)\n" +msgstr "" +"Auto\n" +"Servidor da Imagem EU\n" +"Servidor da Imagem NA\n" +"CDN (padrão)\n" +"CDN2 (testando)\n" #: batoto.rs_showalllang msgctxt "batoto.rs_showalllang" @@ -53,7 +58,14 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -152,7 +164,9 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" +msgstr "" +"Este título já está na lista de download.\n" +"Você quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -178,14 +192,19 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "Baixar tudo\nAdicionar aos favoritos\n" +msgstr "" +"Baixar tudo\n" +"Adicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "<none>\n" -msgstr "Completo\nEm Andamento\n<vazio>\n" +msgstr "" +"Completo\n" +"Em Andamento\n" +"<vazio>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -195,7 +214,9 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "" +"Há um problema com estes dados!\n" +"Removendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -249,7 +270,11 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" +msgstr "" +"%s : Caminho para o mangá\n" +"%s : Nome do capítulo\n" +"\n" +"Examplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -277,13 +302,25 @@ msgstr "Um mês" msgid "One week" msgstr "Uma semana" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "Nada\nSair\nDesligar\nHibernar\n" +msgstr "" +"Nada\n" +"Sair\n" +"Desligar\n" +"Hibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -465,6 +502,16 @@ msgstr "Lista de favoritos" msgid "Manga list" msgstr "Lista de mangás" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +#, fuzzy +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "Transferir para" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -826,7 +873,9 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" +msgstr "" +"Meninas vestindo-se como caras, caras vestir-se como meninas.\n" +"Rapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1239,7 +1288,16 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "" +"Géneros:\n" +"- Marcado: Inclua este gênero.\n" +"- Desmarcado: exclua esse gênero.\n" +"- Cinzento: Não importa.\n" +"\n" +"Géneros Personalizados:\n" +"- Separar vários gêneros com ','.\n" +"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n" +"- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1291,7 +1349,16 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Nome doWebsite\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do capítulo\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"%NUMBERING% : Número\n" +"\n" +"Nota:\n" +"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1328,7 +1395,14 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do Capítulo\n" +"%FILENAME% : Nome do arquivo\n" +"\n" +"Nota:\n" +"Nome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1361,7 +1435,14 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"\n" +"Nota:\n" +"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption #| msgid "Number of downloaded tasks at the same time (Max: 8)" @@ -2011,7 +2092,9 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" +msgstr "" +"Nova versão encontrada! Você quer atualizar agora?\n" +"FMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "twebsiteoptionadvancedform.menuitem1.caption" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index d0b60ebaa..2588d4f6e 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -299,6 +299,14 @@ msgstr "За месяц" msgid "One week" msgstr "За неделю" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" @@ -485,6 +493,16 @@ msgstr "Список избранного" msgid "Manga list" msgstr "Список манги" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +#, fuzzy +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "Перенести на" + #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" @@ -2014,6 +2032,24 @@ msgctxt "ttransferfavoritesform.lbtransferto.caption" msgid "Transfer to" msgstr "Перенести на" +#: ttransferfavoritesform.rball.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rball.caption" +msgid "All" +msgstr "Все" + +#: ttransferfavoritesform.rbinvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbinvalid.caption" +msgid "Invalid" +msgstr "Нельзя перенести" + +#: ttransferfavoritesform.rbvalid.caption +#, fuzzy +msgctxt "ttransferfavoritesform.rbvalid.caption" +msgid "Valid" +msgstr "Можно перенести" + #: ttransferfavoritesform.vtfavs.header.columns[1].text msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index f3fa02fb9..1a3d73c4f 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -86,6 +86,7 @@ msgid "Unknown" msgstr "Bilinmeyen" #: frmaccountmanager.rs_valid +msgctxt "frmaccountmanager.rs_valid" msgid "OK" msgstr "Tamam" @@ -302,6 +303,14 @@ msgstr "Bir ay" msgid "One week" msgstr "Bir hafta" +#: frmmain.rs_optioncompress +msgid "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +msgstr "" + #: frmmain.rs_optionfmddoitems msgid "" "Nothing\n" @@ -494,6 +503,16 @@ msgstr "Favori Listesi" msgid "Manga list" msgstr "Manga Listesi" +#: tform1.caption +msgid "Form1" +msgstr "" + +#: tform1.lbtransferto.caption +#, fuzzy +msgctxt "tform1.lbtransferto.caption" +msgid "Transfer to" +msgstr "Şuraya Transfer Et" + #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" @@ -1099,6 +1118,10 @@ msgstr "Yuri" msgid "This work usually involves intimate relationships between women." msgstr "Bu çalışmalar genellikle kadınlar arası yakın ilişki barındırır." +#: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption +msgid "Always start task from failed chapters" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Kişisel demogrofi ekle, virgülle ayrılmış" @@ -1421,7 +1444,9 @@ msgstr "" "Manga klasörü adı en azından %MANGA% içermelidir.\n" #: tmainform.lboptionmaxparallel.caption -msgid "Number of downloaded tasks at the same time (Max: 8)" +#, fuzzy +#| msgid "Number of downloaded tasks at the same time (Max: 8)" +msgid "Number of downloaded tasks at the same time" msgstr "Eşzamanlı indirilen görev sayısı (Maks: 8)" #: tmainform.lboptionmaxretry.caption @@ -1430,7 +1455,9 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "İndirmede sorun varsa tekrar deneme sayısı (-1 = sürekli yeniden dene)" #: tmainform.lboptionmaxthread.caption -msgid "Number of downloaded files per task at the same time (Max: 32)" +#, fuzzy +#| msgid "Number of downloaded files per task at the same time (Max: 32)" +msgid "Number of downloaded files per task at the same time" msgstr "Tek görev başına aynı anda indirilmiş dosya sayısı (Maks: 32)" #: tmainform.lboptionnewmangatime.caption @@ -1468,6 +1495,10 @@ msgstr "Tip" msgid "Rename digits" msgstr "Basamakları yeniden adlandır" +#: tmainform.lboptionretryfailedtask.caption +msgid "Number of retry times if task failed" +msgstr "" + #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" msgid "Username" @@ -1980,6 +2011,16 @@ msgctxt "TNEWCHAPTER.BTQUEUE.CAPTION" msgid "&Add to queue" msgstr "&Sıraya ekle" +#: tselectdirectoryform.btok.caption +#, fuzzy +msgctxt "tselectdirectoryform.btok.caption" +msgid "OK" +msgstr "Tamam" + +#: tselectdirectoryform.caption +msgid "Select directory" +msgstr "" + #: tshutdowncounterform.btabort.caption msgid "&Abort" msgstr "&Durdur" @@ -2318,3 +2359,4 @@ msgstr "Veri eşitleniyor" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Liste güncelleniyor" + From 3695af5ee61e179f36ddfb826052b349275838a3 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Sat, 27 Jan 2018 23:57:12 +0300 Subject: [PATCH 2000/2794] Update fmd.tr_TR.po Translated latest changes. Left line 501 as it is, because i don't know what it's purpose. --- mangadownloader/languages/fmd.tr_TR.po | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 1a3d73c4f..efae235c5 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -310,6 +310,10 @@ msgid "" "CBZ\n" "PDF\n" msgstr "" +"Hiçbiri\n" +"ZIP\n" +"CBZ\n" +"PDF\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -505,7 +509,7 @@ msgstr "Manga Listesi" #: tform1.caption msgid "Form1" -msgstr "" +msgstr "Form1" #: tform1.lbtransferto.caption #, fuzzy @@ -1120,7 +1124,7 @@ msgstr "Bu çalışmalar genellikle kadınlar arası yakın ilişki barındırı #: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption msgid "Always start task from failed chapters" -msgstr "" +msgstr "Görevi her zaman başarısız bölümlerden başlat" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1497,7 +1501,7 @@ msgstr "Basamakları yeniden adlandır" #: tmainform.lboptionretryfailedtask.caption msgid "Number of retry times if task failed" -msgstr "" +msgstr "Görev başarısız olunca yeniden deneme sayısı" #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" @@ -2019,7 +2023,7 @@ msgstr "Tamam" #: tselectdirectoryform.caption msgid "Select directory" -msgstr "" +msgstr "Yolu seç" #: tshutdowncounterform.btabort.caption msgid "&Abort" @@ -2359,4 +2363,3 @@ msgstr "Veri eşitleniyor" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Liste güncelleniyor" - From d383cdb9327345b866c960ba17676177740bf6ae Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 27 Jan 2018 20:55:22 +0300 Subject: [PATCH 2001/2794] mangadex, fix download #884 --- baseunits/modules/Mangadex.pas | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index 9c3fba63a..f7a587fbf 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr, URIParser, FMDVars; + XQueryEngineHTML, httpsendthread, synautil, RegExpr, FMDVars; implementation @@ -72,9 +72,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - uri: TURI; - s: String; - i: Integer; + s, dataurl, server, pages: String; + v: IXQValue; begin Result := False; if DownloadThread = nil then Exit; @@ -86,13 +85,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String Result := True; with TXQueryEngineHTML.Create(Document) do try - s := MaybeFillHost(Module.RootURL, XPathString('//img[@id="current_page"]/@src')); - PageNumber:= XPathCount('//select[@id="jump_page"]/option'); - uri := ParseURI(s); - for i := 1 to PageNumber do begin - uri.Document := IntToStr(i) + ExtractFileExt(uri.Document); - PageLinks.Add(EncodeURI(uri)); - end; + s := XPathString('//script[contains(., "var page_array")]'); + dataurl := GetBetween('var dataurl = ''', ''';', s); + server := GetBetween('var server = ''', ''';', s); + pages := '[' + GetBetween('var page_array = [', '];', s) + ']'; + ParseHTML(pages); + for v in XPath('json(*)()') do + PageLinks.Add(MaybeFillHost(Module.RootURL, server + dataurl + '/' + v.toString)); finally Free; end; From dd681372014c1c748b08eea930a9c227822f9203 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Jan 2018 12:29:09 +0800 Subject: [PATCH 2002/2794] cleanup po files --- mangadownloader/languages/fmd.de.po | 9 --------- mangadownloader/languages/fmd.el_GR.po | 9 --------- mangadownloader/languages/fmd.en.po | 10 ---------- mangadownloader/languages/fmd.es.po | 9 --------- mangadownloader/languages/fmd.id_ID.po | 9 --------- mangadownloader/languages/fmd.pl_PL.po | 9 --------- mangadownloader/languages/fmd.po | 9 --------- mangadownloader/languages/fmd.pt_BR.po | 10 ---------- mangadownloader/languages/fmd.ru_RU.po | 10 ---------- mangadownloader/languages/fmd.tr_TR.po | 10 ---------- 10 files changed, 94 deletions(-) diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 9b3655d7b..f9e691f55 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -503,15 +503,6 @@ msgstr "Favoritenliste" msgid "Manga list" msgstr "Mangaliste" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 79797a96a..39eba0a1c 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -507,15 +507,6 @@ msgstr "Λίστα αγαπημένων" msgid "Manga list" msgstr "Λίστα Manga" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 48f2aaf00..86bd1c226 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -502,16 +502,6 @@ msgstr "Favorite list" msgid "Manga list" msgstr "Manga list" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -#, fuzzy -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "Transfer to" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 2923a0bb2..c28437197 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -495,15 +495,6 @@ msgstr "Lista de Favoritos" msgid "Manga list" msgstr "Lista de Manga" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index fb1eed228..b1496a637 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -495,15 +495,6 @@ msgstr "Daftar kesukaan" msgid "Manga list" msgstr "Daftar komik" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 6fd05909e..88d1788f5 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -498,15 +498,6 @@ msgstr "Lista ulubionych" msgid "Manga list" msgstr "Lista mang" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 2e8d66277..86ea4398c 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -454,15 +454,6 @@ msgstr "" msgid "Manga list" msgstr "" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "" - #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index a2d69c4c4..674f01ad0 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -502,16 +502,6 @@ msgstr "Lista de favoritos" msgid "Manga list" msgstr "Lista de mangás" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -#, fuzzy -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "Transferir para" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 2588d4f6e..0d55b6e26 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -493,16 +493,6 @@ msgstr "Список избранного" msgid "Manga list" msgstr "Список манги" -#: tform1.caption -msgid "Form1" -msgstr "" - -#: tform1.lbtransferto.caption -#, fuzzy -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "Перенести на" - #: tformdroptarget.miaddtofavorites.caption msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index efae235c5..3272ed424 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -507,16 +507,6 @@ msgstr "Favori Listesi" msgid "Manga list" msgstr "Manga Listesi" -#: tform1.caption -msgid "Form1" -msgstr "Form1" - -#: tform1.lbtransferto.caption -#, fuzzy -msgctxt "tform1.lbtransferto.caption" -msgid "Transfer to" -msgstr "Şuraya Transfer Et" - #: tformdroptarget.miaddtofavorites.caption msgctxt "tformdroptarget.miaddtofavorites.caption" msgid "Add to favorites" From e34c7044b2d5e8c318192d656c820514b6e58c82 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Jan 2018 15:02:32 +0800 Subject: [PATCH 2003/2794] fixed menu popup on advanced website option (fixed #889) --- .../forms/frmWebsiteOptionAdvanced.pas | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 95b331f7d..38f41c37c 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -112,12 +112,12 @@ procedure TWebsiteOptionAdvancedForm.MenuItem1Click(Sender: TObject); Data: PNameValue; Node: PVirtualNode; begin - if Screen.ActiveControl is TVirtualStringTree then + if Screen.ActiveControl is VirtualTrees.TVirtualStringTree then with TWebsiteSelectionForm.Create(Self) do try - GetWebsite(TVirtualStringTree(Screen.ActiveControl), cbWebsites.Items); + GetWebsite(VirtualTrees.TVirtualStringTree(Screen.ActiveControl), cbWebsites.Items); if (ShowModal = mrOk) and (cbWebsites.Text <> '') then - with TVirtualStringTree(Screen.ActiveControl) do + with VirtualTrees.TVirtualStringTree(Screen.ActiveControl) do begin Node := AddChild(nil); Data := GetNodeData(Node); @@ -132,8 +132,8 @@ procedure TWebsiteOptionAdvancedForm.MenuItem1Click(Sender: TObject); procedure TWebsiteOptionAdvancedForm.MenuItem2Click(Sender: TObject); begin - if Screen.ActiveControl is TVirtualStringTree then - with TVirtualStringTree(Screen.ActiveControl) do + if Screen.ActiveControl is VirtualTrees.TVirtualStringTree then + with VirtualTrees.TVirtualStringTree(Screen.ActiveControl) do EditNode(FocusedNode, 1); end; @@ -141,8 +141,8 @@ procedure TWebsiteOptionAdvancedForm.MenuItem4Click(Sender: TObject); var Data: PNameValue; begin - if Screen.ActiveControl is TVirtualStringTree then - with TVirtualStringTree(Screen.ActiveControl) do + if Screen.ActiveControl is VirtualTrees.TVirtualStringTree then + with VirtualTrees.TVirtualStringTree(Screen.ActiveControl) do begin Data := GetNodeData(FocusedNode); advancedfile.DeleteKey(DefaultText, Data^.Name); @@ -228,8 +228,8 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; Hit procedure TWebsiteOptionAdvancedForm.vtCookiesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin - if not (Sender is TVirtualStringTree) then Exit; - with TVirtualStringTree(Sender) do + if not (Sender is VirtualTrees.TVirtualStringTree) then Exit; + with VirtualTrees.TVirtualStringTree(Sender) do if (Key = VK_RETURN) and (FocusedColumn <> 0) then EditNode(FocusedNode, FocusedColumn); end; @@ -244,7 +244,7 @@ procedure TWebsiteOptionAdvancedForm.vtCookiesNewText(Sender: TBaseVirtualTree; if Data^.Value <> NewText then begin Data^.Value := NewText; - advancedfile.WriteString(TVirtualStringTree(Sender).DefaultText, Data^.Name, NewText); + advancedfile.WriteString(VirtualTrees.TVirtualStringTree(Sender).DefaultText, Data^.Name, NewText); end; end; From c050a54fccd2dd5deb8f89d7c496a251988addaf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 28 Jan 2018 15:52:34 +0800 Subject: [PATCH 2004/2794] set hint timeout on mangalist to 5 minutes (fixed #888) --- mangadownloader/forms/frmMain.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 837316e5f..bf52dc5a7 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2337,7 +2337,10 @@ procedure TMainForm.appPropertiesMainShowHint(var HintStr: String; var CanShow: Boolean; var HintInfo: THintInfo); begin if HintInfo.HintControl = vtMangaList then + begin HintInfo.HintMaxWidth := 500; + HintInfo.HideTimeout := 300000; + end; if HintInfo.HintControl = sbUpdateList then if isUpdating then HintStr := Trim(updateList.websites.Text) From e4ebba633230a932a57b930b7ebea0990bc90d51 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 28 Jan 2018 12:25:38 +0300 Subject: [PATCH 2005/2794] UnionMangas, remove ad pages fixes #886 --- baseunits/modules/UnionMangas.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index 0a7f2fd4d..f76cec866 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -77,7 +77,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('//img[contains(@class, "img-manga")]/@src', Document, PageLinks); + XPathStringAll('//img[contains(@class, "img-manga") and contains(@src, "/leitor/")]/@src', Document, PageLinks); end; end; end; From b1069a444912129d68f11c19adfff71b3f09fc64 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 28 Jan 2018 13:19:36 +0300 Subject: [PATCH 2006/2794] readmangame, fix download fixes #887 --- baseunits/modules/MintMangaRU.pas | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index 2bac355ef..da25424e8 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -154,6 +154,14 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; +function BeforeDownloadImage(const DownloadThread: TDownloadThread; + var AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := True; + if DownloadThread = nil then Exit; + DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + Module.RootURL; +end; + procedure RegisterModule; function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; @@ -167,6 +175,7 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + OnBeforeDownloadImage := @BeforeDownloadImage; end; end; From 46b98d3f075622e0cd8a8230c7e1c540e2feca89 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 06:10:12 +0800 Subject: [PATCH 2007/2794] websitemodules, add onsaveimage event, change ondownloadimage params --- baseunits/WebsiteModules.pas | 60 +++++++++++++++++++++++---------- baseunits/uDownloadsManager.pas | 25 ++++++++++++-- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index e9a0e6287..a5c3fb059 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -43,7 +43,10 @@ TModuleContainer = class; var AURL: String; const Module: TModuleContainer): Boolean; TOnDownloadImage = function(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; + + TOnSaveImage = function(const AHTTP: THTTPSendThread; + const APath, AName: String; const Module: TModuleContainer): String; TOnAfterImageSaved = function(const AFilename: String; const Module: TModuleContainer): Boolean; @@ -51,7 +54,7 @@ TModuleContainer = class; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, - MMDownloadImage, MMAfterImageSaved, MMLogin); + MMDownloadImage, MMSaveImage, MMAfterImageSaved, MMLogin); TWebsiteOptionType = (woCheckBox, woEdit, woSpinEdit, woComboBox); @@ -97,6 +100,7 @@ TModuleContainer = class OnGetImageURL: TOnGetImageURL; OnBeforeDownloadImage: TOnBeforeDownloadImage; OnDownloadImage: TOnDownloadImage; + OnSaveImage: TOnSaveImage; OnAfterImageSaved: TOnAfterImageSaved; OnLogin: TOnLogin; constructor Create; @@ -150,50 +154,55 @@ TWebsiteModules = class function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const ModuleId: Integer): Integer; overload; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const AWebsite: String): Integer; overload; + var Page: Integer; const WorkPtr: Integer; const AWebsite: String): Integer; overload; inline; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const ModuleId: Integer): Integer; overload; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; - const AURL, AWebsite: String): Integer; overload; + const AURL, AWebsite: String): Integer; overload; inline; function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const ModuleId: Integer): Integer; overload; function GetInfo(const MangaInfo: TMangaInformation; - const AURL, AWebsite: String): Integer; overload; + const AURL, AWebsite: String): Integer; overload; inline; function TaskStart(const Task: TTaskContainer; const ModuleId: Integer): Boolean; overload; function TaskStart(const Task: TTaskContainer; - const AWebsite: String): Boolean; overload; + const AWebsite: String): Boolean; overload; inline; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; overload; function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL, AWebsite: String): Boolean; overload; + const AURL, AWebsite: String): Boolean; overload; inline; function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; overload; function GetImageURL(const DownloadThread: TDownloadThread; - const AURL, AWebsite: String): Boolean; overload; + const AURL, AWebsite: String): Boolean; overload; inline; function BeforeDownloadImage(const DownloadThread: TDownloadThread; var AURL: String; const ModuleId: Integer): Boolean; overload; function BeforeDownloadImage(const DownloadThread: TDownloadThread; - var AURL, AWebsite: String): Boolean; overload; + var AURL, AWebsite: String): Boolean; overload; inline; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const ModuleId: Integer): Boolean; overload; + const AURL: String; const ModuleId: Integer): Boolean; overload; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName, AWebsite: String): Boolean; overload; + const AURL, AWebsite: String): Boolean; overload; inline; + + function SaveImage(const AHTTP: THTTPSendThread; + const APath, AName: String; const ModuleId: Integer): String; overload; + function SaveImage(const AHTTP: THTTPSendThread; + const APath, AName, AWebsite: String): String; overload; inline; function AfterImageSaved(const AFilename: String; const ModuleId: Integer): Boolean; overload; - function AfterImageSaved(const AFilename, AWebsite: String): Boolean; overload; + function AfterImageSaved(const AFilename, AWebsite: String): Boolean; overload; inline; function Login(const AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; overload; - function Login(const AHTTP: THTTPSendThread; const AWebsite: String): Boolean; overload; + function Login(const AHTTP: THTTPSendThread; const AWebsite: String): Boolean; overload; inline; procedure LockModules; procedure UnlockModules; @@ -588,19 +597,35 @@ function TWebsiteModules.BeforeDownloadImage( end; function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const ModuleId: Integer): Boolean; + const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnDownloadImage) then Result := TModuleContainer(FModuleList[ModuleId]).OnDownloadImage( - DownloadThread, AURL, APath, AName, TModuleContainer(FModuleList[ModuleId])); + DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName, AWebsite: String): Boolean; + const AURL, AWebsite: String): Boolean; begin - Result := DownloadImage(DownloadThread, AURL, APath, AName, LocateModule(AWebsite)); + Result := DownloadImage(DownloadThread, AURL, LocateModule(AWebsite)); +end; + +function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; + const APath, AName: String; const ModuleId: Integer): String; +begin + Result := ''; + if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if Assigned(TModuleContainer(FModuleList[ModuleId]).OnSaveImage) then + Result := TModuleContainer(FModuleList[ModuleId]).OnSaveImage( + AHTTP, APath, AName, TModuleContainer(FModuleList[ModuleId])); +end; + +function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; + const APath, AName, AWebsite: String): String; +begin + Result := SaveImage(AHTTP, APath, AName, LocateModule(AWebsite)); end; function TWebsiteModules.AfterImageSaved(const AFilename: String; @@ -611,7 +636,6 @@ function TWebsiteModules.AfterImageSaved(const AFilename: String; if Assigned(TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved) then Result := TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved(AFilename, TModuleContainer(FModuleList[ModuleId])); - end; function TWebsiteModules.AfterImageSaved(const AFilename, AWebsite: String diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index be43e83a6..629f475c8 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -897,12 +897,13 @@ function TDownloadThread.DownloadImage: Boolean; (WorkId < Task.Container.PageContainerLinks.Count) then workURL := Task.Container.PageContainerLinks[WorkId]; - // call beforedownloadimage if available + // OnBeforeDownloadImage if Modules.ModuleAvailable(Task.Container.ModuleId, MMBeforeDownloadImage) then Result := Modules.BeforeDownloadImage(Self, workURL, Task.Container.ModuleId); if Result then begin + // OnDownloadImage if Modules.ModuleAvailable(Task.Container.ModuleId, MMDownloadImage) then Result := Modules.DownloadImage( Self, @@ -914,13 +915,31 @@ function TDownloadThread.DownloadImage: Boolean; if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL else - Result := uBaseUnit.DownloadAndSaveImage(FHTTP, workURL, Task.CurrentWorkingDir, workFilename, savedFilename); + Result := FHTTP.GET(workURL); end; + + if Result then + begin + savedFilename := FindImageFile(Task.CurrentWorkingDir + workFilename); + Result := savedFilename <> ''; + if not Result then + begin + if Modules.ModuleAvailable(Task.Container.ModuleId, MMSaveImage) then + savedFilename := Modules.SaveImage(FHTTP, Task.CurrentWorkingDir, workFilename, Task.Container.ModuleId) + else + savedFilename := SaveImageStreamToFile(FHTTP, Task.CurrentWorkingDir, workFilename); + Result := savedFilename <> ''; + end; + end; + + if Result then + Result := FileExistsUTF8(savedFilename); + if Terminated then Exit(False); if Result then begin Task.Container.PageLinks[WorkId] := 'D'; - + // OnAfterImageSaved if Modules.ModuleAvailable(Task.Container.ModuleId, MMAfterImageSaved) then Modules.AfterImageSaved(savedFilename, Task.Container.ModuleId); end; From a26b09c9a26992434573e9ef13209461e4ce967b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 06:23:05 +0800 Subject: [PATCH 2008/2794] fix call ondownloadimage --- baseunits/uDownloadsManager.pas | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 629f475c8..ec48e31b9 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -905,12 +905,7 @@ function TDownloadThread.DownloadImage: Boolean; begin // OnDownloadImage if Modules.ModuleAvailable(Task.Container.ModuleId, MMDownloadImage) then - Result := Modules.DownloadImage( - Self, - workURL, - Task.CurrentWorkingDir, - workFilename, - Task.Container.ModuleId) + Result := Modules.DownloadImage(Self, workURL, Task.Container.ModuleId) else if Task.Container.MangaSiteID = MEINMANGA_ID then Result := GetMeinMangaImageURL From 504eed120ab38c2d1e81e0da15496057f21c6ab1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 06:23:48 +0800 Subject: [PATCH 2009/2794] fix modules following websitemodules changes --- baseunits/modules/EHentai.pas | 4 ++-- baseunits/modules/HeyMangaXyz.pas | 4 +--- baseunits/modules/JapScan.pas | 4 ++-- baseunits/modules/Madokami.pas | 6 ++---- baseunits/modules/MangaAe.pas | 8 ++------ baseunits/modules/MangaRock.pas | 4 ++-- baseunits/modules/Shogakukan.pas | 5 ++--- baseunits/modules/Tumangaonline.pas | 5 ++--- 8 files changed, 15 insertions(+), 25 deletions(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 1cf5253de..414b7a3cd 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -301,7 +301,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; iurl: String; @@ -326,7 +326,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then - Result := SaveImage(DownloadThread.FHTTP, iurl, APath, AName); + Result := GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website); if DownloadThread.IsTerminated then Break; if rcount >= reconnect then Break; if not Result then begin diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index 9c2ba18d1..802854015 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -108,15 +108,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; function downloadandsave(u: String): Boolean; begin if u = '' then Exit(False); if LeftStr(u, 2) = '//' then u := 'https:' + u; Result := DownloadThread.FHTTP.GET(u); - if Result then - Result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; end; begin diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas index 35759732c..fee35f8a1 100644 --- a/baseunits/modules/JapScan.pas +++ b/baseunits/modules/JapScan.pas @@ -89,13 +89,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; with DownloadThread, DownloadThread.FHTTP, DownloadThread.Task.Container do begin if GET(AppendURLDelim(FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr])) + IncStr(WorkId) + '.html') then - Result := DownloadAndSaveImage(FHTTP, XPathString('//img[@id="image"]/@src', Document), APath, AName); + Result := GET(XPathString('//img[@id="image"]/@src', Document)); end; end; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 593405139..16f034050 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -268,13 +268,11 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; - if GETWithLogin(DownloadThread.FHTTP, AURL) then begin - SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName); - end; + Result := GETWithLogin(DownloadThread.FHTTP, AURL); end; procedure RegisterModule; diff --git a/baseunits/modules/MangaAe.pas b/baseunits/modules/MangaAe.pas index 0cd8f5884..0f6f602fa 100644 --- a/baseunits/modules/MangaAe.pas +++ b/baseunits/modules/MangaAe.pas @@ -91,13 +91,9 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; begin - if DownloadThread.FHTTP.GETCF(AURL, cf) then begin - Result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; - end - else - Result := False; + Result := DownloadThread.FHTTP.GETCF(AURL, cf); end; procedure RegisterModule; diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas index 4ffd59cad..1f5b72687 100644 --- a/baseunits/modules/MangaRock.pas +++ b/baseunits/modules/MangaRock.pas @@ -121,7 +121,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; var decoded: TMemoryStream; img: TMemBitmap; @@ -135,7 +135,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; try decoded := DecryptImage(DownloadThread.FHTTP.Document); img := WebPToMemBitmap(decoded); - Result := SaveImageAsPngFile(img, APath, AName) <> ''; + //Result := SaveImageAsPngFile(img, APath, AName) <> ''; finally img.Free; decoded.Free; diff --git a/baseunits/modules/Shogakukan.pas b/baseunits/modules/Shogakukan.pas index 681094aeb..0f26916e9 100644 --- a/baseunits/modules/Shogakukan.pas +++ b/baseunits/modules/Shogakukan.pas @@ -64,7 +64,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; function DownloadImage(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; @@ -75,8 +75,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; Headers.Add('Referer: ' + Module.RootURL + '/' + PageContainerLinks[1] + '?page=' + IntToStr(WorkId)); if POST(Module.RootURL + '/imgDeliver?gcode=' + PageContainerLinks[0], 'base64=1&vsid=' + PageContainerLinks[1] + '&trgCode=' + PageLinks[WorkId]) then - if Base64Decode(Document) then - Result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; + Result := Base64Decode(Document); end; end; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 01d4b8cf5..a487c6b8e 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -155,12 +155,11 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String end; function DownloadImageWithCookie(const DownloadThread: TDownloadThread; - const AURL, APath, AName: String; const Module: TModuleContainer): Boolean; + const AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; if DownloadThread = nil then Exit; - if GETWithCookie(DownloadThread.FHTTP, AURL) then - result := SaveImageStreamToFile(DownloadThread.FHTTP, APath, AName) <> ''; + Result := GETWithCookie(DownloadThread.FHTTP, AURL); end; procedure RegisterModule; From ed720be02713922a4e85c7608cae3888b3f5b73f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 08:33:07 +0800 Subject: [PATCH 2010/2794] check and convert webp on saveimagestreamtofile add convert webp to png add convert webp to jpg --- baseunits/modules/MangaRock.pas | 24 +++--- baseunits/uBaseUnit.pas | 131 +++++++++++++++++++++++--------- 2 files changed, 106 insertions(+), 49 deletions(-) diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas index 1f5b72687..4a5381e20 100644 --- a/baseunits/modules/MangaRock.pas +++ b/baseunits/modules/MangaRock.pas @@ -124,23 +124,21 @@ function DownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var decoded: TMemoryStream; - img: TMemBitmap; begin decoded := nil; - img := nil; Result := False; if DownloadThread = nil then Exit; - if DownloadThread.FHTTP.GET(AURL) then - begin - try - decoded := DecryptImage(DownloadThread.FHTTP.Document); - img := WebPToMemBitmap(decoded); - //Result := SaveImageAsPngFile(img, APath, AName) <> ''; - finally - img.Free; - decoded.Free; - end; - end; + with DownloadThread.FHTTP do + if GET(AURL) then + try + decoded := DecryptImage(Document); + Document.Size := decoded.Size; + Document.Position := 0; + decoded.SaveToStream(Document); + Result := True; + finally + decoded.Free; + end; end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ad198a35f..47ce7656b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -746,11 +746,18 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0) // Get url from a bitly url. function GetURLFromBitly(const URL: String): String; +// convert webp +function WebPToPNGStream(const AStream: TMemoryStream): Boolean; +function WebPToJpegStream(const AStream: TMemoryStream): Boolean; + +// check and convert known file + +function ConvertKnownImageFormat(const AStream: TMemoryStream): Boolean; + // try to save tmemorystream to file, return the saved filename if success, otherwise return empty string function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; overload; function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String; overload; -function SaveImageAsPngFile(image: TMemBitmap; Path, FileName: String): String; // detect and save image from base64 string function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; @@ -828,7 +835,7 @@ procedure SendLogException(const AText: String; AException: Exception); inline; implementation uses - {$IFDEF DOWNLOADER}WebsiteModules;{$ENDIF} + {$IFDEF DOWNLOADER}WebsiteModules, webp, FPWriteJPEG;{$ENDIF} {$IFDEF WINDOWS} // thanks Leledumbo for the code @@ -3334,8 +3341,85 @@ function GetURLFromBitly(const URL: String): String; httpSource.Free; end; -function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt - ): String; +function WebPToPNGStream(const AStream: TMemoryStream): Boolean; +var + mem: TMemBitmap; + writer: TFPWriterPNG; +begin + Result := False; + mem := nil; + try + mem := WebPToMemBitmap(AStream); + if Assigned(mem) then + try + writer := TFPWriterPNG.create; + writer.Indexed := False; + writer.UseAlpha := mem.HasTransparentPixels; + mem.SaveToStream(AStream, writer); + Result := True; + finally + writer.Free; + end; + finally + if Assigned(mem) then + mem.Free; + end; +end; + +function WebPToJpegStream(const AStream: TMemoryStream): Boolean; +var + mem: TMemBitmap; + writer: TFPWriterJPEG; +begin + Result := False; + mem := nil; + try + mem := WebPToMemBitmap(AStream); + if Assigned(mem) then + try + writer := TFPWriterJPEG.create; + writer.CompressionQuality := 80; + mem.SaveToStream(AStream, writer); + Result := True; + finally + writer.Free; + end; + finally + if Assigned(mem) then + mem.Free; + end; +end; + +function IsWebPStream(const AStream: TMemoryStream): Boolean; +var + hdr: array[0..3] of Char; +begin + Result := False; + AStream.Position := 0; + if AStream.Read(hdr, 4) = 4 then + begin + if hdr = 'RIFF' then + begin + AStream.Seek(4, soFromCurrent); + if AStream.Read(hdr, 4) = 4 then + begin + if hdr = 'WEBP' then + Result := True; + end; + end; + end; +end; + +function ConvertKnownImageFormat(const AStream: TMemoryStream): Boolean; +begin + Result := False; + // webp + if IsWebPStream(AStream) then + Result := WebPToPNGStream(AStream); + //Result := WebPToJpegStream(AStream); +end; + +function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt): String; var p, f: String; fs: TFileStreamUTF8; @@ -3346,13 +3430,19 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag p := CorrectPathSys(Path); if ForceDirectoriesUTF8(p) then begin f := GetImageStreamExt(Stream); + if f = '' then + begin + if ConvertKnownImageFormat(Stream) then + f := GetImageStreamExt(Stream); + end; if f = '' then Exit; f := p + FileName + '.' + f; if FileExistsUTF8(f) then DeleteFileUTF8(f); try fs := TFileStreamUTF8.Create(f, fmCreate); try - Stream.SaveToStream(fs); + Stream.Position := 0; + fs.CopyFrom(Stream, Stream.Size); finally fs.Free; end; @@ -3413,37 +3503,6 @@ function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; end; end; -function SaveImageAsPngFile(image: TMemBitmap; Path, FileName: String): String; -var - p, f: String; - fs: TFileStreamUTF8; - writer: TFPWriterPNG; -begin - Result := ''; - if image = nil then Exit; - p := CorrectPathSys(Path); - if ForceDirectoriesUTF8(p) then begin - f := p + FileName + '.png'; - if FileExistsUTF8(f) then DeleteFileUTF8(f); - try - fs := TFileStreamUTF8.Create(f, fmCreate); - writer := TFPWriterPNG.Create; - writer.Indexed := false; - writer.UseAlpha := image.HasTransparentPixels; - try - image.SaveToStream(fs, writer); - finally - writer.Free; - fs.Free; - end; - except - on E: Exception do - Logger.SendException('SaveImageAsPngFile Failed! ' + f, E); - end; - end; - if FileExistsUTF8(f) then Result := f; -end; - function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; const Path, Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; From 6bea6cf7d20b9924ea02056c439128f4a148645b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 15:34:29 +0800 Subject: [PATCH 2011/2794] transferfavorite, fix check new favorites --- mangadownloader/forms/frmMain.pas | 17 +++---- .../forms/frmTransferFavorites.lfm | 10 ++-- .../forms/frmTransferFavorites.pas | 51 ++++++++++--------- 3 files changed, 43 insertions(+), 35 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index bf52dc5a7..e2e4612fb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1537,7 +1537,7 @@ procedure TMainForm.miFavoritesRenameClick(Sender: TObject); procedure TMainForm.miFavoritesTransferWebsiteClick(Sender: TObject); var Node: PVirtualNode; - sm, i: Integer; + sm: Integer; Data: PFavContainer; begin with TTransferFavoritesForm.Create(nil) do @@ -1558,17 +1558,16 @@ procedure TMainForm.miFavoritesTransferWebsiteClick(Sender: TObject); if sm = mrOK then begin UpdateVtFavorites; - i := 0; - Node := vtFavs.GetFirst(); - while Assigned(Node) do + if ckClearDownloadedChapters.Checked then begin - Data := vtFavs.GetNodeData(Node); - for i := i to FavoriteManager.Count - 1 do + Node := vtFavs.GetFirst(); + while Assigned(Node) do begin - if Data^.Fav = FavoriteManager.Items[i] then - FavoriteManager.CheckForNewChapter(i); + Data := vtFavs.GetNodeData(Node); + if Data^.NewLink <> '' then + FavoriteManager.CheckForNewChapter(FavoriteManager.Items.IndexOf(Data^.Fav)); + Node := vtFavs.GetNext(Node); end; - Node := vtFavs.GetNext(Node); end; end; finally diff --git a/mangadownloader/forms/frmTransferFavorites.lfm b/mangadownloader/forms/frmTransferFavorites.lfm index d1dc65f0c..5e2cd3e59 100644 --- a/mangadownloader/forms/frmTransferFavorites.lfm +++ b/mangadownloader/forms/frmTransferFavorites.lfm @@ -25,8 +25,9 @@ object TransferFavoritesForm: TTransferFavoritesForm Width = 164 AutoComplete = True AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchAscending] + AutoDropDown = True ItemHeight = 15 - OnChange = cbWebsitesChange + OnEditingDone = cbWebsitesEditingDone TabOrder = 0 end object lbTransferTo: TLabel @@ -246,8 +247,8 @@ object TransferFavoritesForm: TTransferFavoritesForm Width = 16 end object imgsState: TImageList - left = 326 - top = 32 + Left = 326 + Top = 32 Bitmap = { 4C690300000010000000100000001975BA001975BA001770B7900B56A4C60142 96CC003F94CC002A80CC00166BCC021C70CB072D7DC80D4390C51259A3C1176C @@ -347,5 +348,8 @@ object TransferFavoritesForm: TTransferFavoritesForm 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 00170000000C00000002FFFFFF00 } + BitmapAdv = { + 4C6900000000 + } end end diff --git a/mangadownloader/forms/frmTransferFavorites.pas b/mangadownloader/forms/frmTransferFavorites.pas index 331eeccb8..10c3f5e45 100644 --- a/mangadownloader/forms/frmTransferFavorites.pas +++ b/mangadownloader/forms/frmTransferFavorites.pas @@ -26,7 +26,7 @@ TTransferFavoritesForm = class(TForm) vtFavs: TVirtualStringTree; procedure btCancelClick(Sender: TObject); procedure btOKClick(Sender: TObject); - procedure cbWebsitesChange(Sender: TObject); + procedure cbWebsitesEditingDone(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure FormShow(Sender: TObject); @@ -40,8 +40,9 @@ TTransferFavoritesForm = class(TForm) private FAllCount, FValidCount, - FInvalidCount: Integer; - FLastFilter: Integer; + FInvalidCount, + FLastFilter, + FLastWebsiteSelect: Integer; procedure UpdateFilterCount; procedure FilterState(const AState: Integer = 0); procedure FindMatchTitle; @@ -118,19 +119,6 @@ procedure TFindMatchDBThread.Execute; node: PVirtualNode; data: PFavContainer; - procedure setvalid(const nl: String = ''); - begin - Inc(Owner.FValidCount); - data^.NewLink := nl; - data^.State := 1; - end; - procedure setinvalid; - begin - Inc(Owner.FInvalidCount); - data^.NewLink := ''; - data^.State := 2; - end; - begin Synchronize(@SyncBegin); Owner.FValidCount := 0; @@ -145,7 +133,10 @@ procedure TFindMatchDBThread.Execute; begin data := Owner.vtFavs.GetNodeData(node); if data^.Fav.Website = db.Website then - setvalid + begin + data^.NewLink := ''; + data^.State := 0; + end else begin try @@ -153,9 +144,17 @@ procedure TFindMatchDBThread.Execute; ' WHERE title LIKE '+AnsiQuotedStr(data^.Fav.FavoriteInfo.Title, '"') + ' COLLATE NOCASE;'; db.Table.Open; if db.Table.RecNo > 0 then - setvalid(db.Table.Fields[0].AsString) + begin + data^.NewLink := db.Table.Fields[0].AsString; + data^.State := 1; + Inc(Owner.FValidCount); + end else - setinvalid; + begin + data^.NewLink := ''; + data^.State := 2; + Inc(Owner.FInvalidCount); + end; except end; db.Table.Close; @@ -187,6 +186,7 @@ procedure TTransferFavoritesForm.FormCreate(Sender: TObject); FAllCount := 0; FValidCount := 0; FInvalidCount := 0; + FLastWebsiteSelect := -1; end; procedure TTransferFavoritesForm.FormDestroy(Sender: TObject); @@ -249,10 +249,8 @@ procedure TTransferFavoritesForm.btOKClick(Sender: TObject); ModalResult := mrOK; end; -procedure TTransferFavoritesForm.cbWebsitesChange(Sender: TObject); +procedure TTransferFavoritesForm.cbWebsitesEditingDone(Sender: TObject); begin - if not FileExists(DATA_FOLDER + cbWebsites.Text + DBDATA_EXT) then - Exit; FindMatchTitle; end; @@ -277,7 +275,10 @@ procedure TTransferFavoritesForm.vtFavsGetImageIndex(Sender: TBaseVirtualTree; N begin if Column <> 0 then Exit; Data := Sender.GetNodeData(Node); - ImageIndex := Data^.State; + if Data^.State = 0 then + ImageIndex := -1 + else + ImageIndex := Data^.State; end; procedure TTransferFavoritesForm.vtFavsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); @@ -330,6 +331,10 @@ procedure TTransferFavoritesForm.FilterState(const AState: Integer); procedure TTransferFavoritesForm.FindMatchTitle; begin + if FLastWebsiteSelect = cbWebsites.ItemIndex then Exit; + FLastWebsiteSelect := cbWebsites.ItemIndex; + if not FileExists(DATA_FOLDER + cbWebsites.Text + DBDATA_EXT) then + Exit; with TFindMatchDBThread.Create(cbWebsites.Text) do begin Owner := Self; From 3aa840669d8717554218b5b8635f67846798ac80 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 15:52:46 +0800 Subject: [PATCH 2012/2794] update changelog --- changelog.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.txt b/changelog.txt index f223f5813..0dcc6d756 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.132.0 (--2018) +[*] LHTranslation, fix chapter order +[*] Mangadex, fix download +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.131.0...0.9.132.0 + 0.9.131.0 (27-01-2018) [+] Added Mangarock [EN] [+] Added LHTranslation [EN-SC] From 7299dea0a454aa6490bacdab2bc6723cc2f70b58 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 29 Jan 2018 15:57:39 +0800 Subject: [PATCH 2013/2794] Bump version 0.9.132.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0dcc6d756..4e96267ed 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.132.0 (--2018) +0.9.132.0 (29-01-2018) [*] LHTranslation, fix chapter order [*] Mangadex, fix download [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9f68ccc78..eddf6adc3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="131"/> + <RevisionNr Value="132"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index f6abaa750..c6726ac50 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.131.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.131.0/fmd_0.9.131.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.131.0/fmd_0.9.131.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.131.0/fmd_0.9.131.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.131.0/fmd_0.9.131.0_Win64.7z +VERSION=0.9.132.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.132.0/fmd_0.9.132.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.132.0/fmd_0.9.132.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.132.0/fmd_0.9.132.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.132.0/fmd_0.9.132.0_Win64.7z From 4c369d8c380277adfb9b723dc46ec8000b8afb28 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Mon, 29 Jan 2018 14:21:11 +0300 Subject: [PATCH 2014/2794] Fixed missed translation Fixed missed translation --- mangadownloader/languages/fmd.tr_TR.po | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 3272ed424..ca9d2eabf 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -1438,8 +1438,6 @@ msgstr "" "Manga klasörü adı en azından %MANGA% içermelidir.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" msgstr "Eşzamanlı indirilen görev sayısı (Maks: 8)" @@ -1449,8 +1447,6 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "İndirmede sorun varsa tekrar deneme sayısı (-1 = sürekli yeniden dene)" #: tmainform.lboptionmaxthread.caption -#, fuzzy -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" msgstr "Tek görev başına aynı anda indirilmiş dosya sayısı (Maks: 32)" @@ -1932,7 +1928,7 @@ msgstr "Websiteler" #: tmainform.tswebsiteselection.caption msgctxt "tmainform.tswebsiteselection.caption" msgid "Websites" -msgstr "Websiteleri" +msgstr "Websiteler" #: tmainform.vtdownload.header.columns[0].text msgid "Manga" @@ -2006,7 +2002,6 @@ msgid "&Add to queue" msgstr "&Sıraya ekle" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "Tamam" From 1bb9e6bda829cb12a231a6d1b5a0757b473beada Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 29 Jan 2018 15:33:33 +0300 Subject: [PATCH 2015/2794] Add MangaDeep [EN] #794 --- baseunits/modules/WPManga.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 5c84a41b7..4c0c31be2 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -243,6 +243,7 @@ procedure RegisterModule; AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); AddWebsiteModule('MangaCow', 'http://mngcow.co'); AddWebsiteModule('HentaiRead', 'http://hentairead.com'); + AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 75ac56d50..3c729208b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 250f12c4eabbbf56e8be924ae13d968a8e2d2be3 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 29 Jan 2018 15:35:57 +0300 Subject: [PATCH 2016/2794] Remove MangaSpy, MangaIce #891 --- baseunits/modules/WPManga.pas | 2 -- config/mangalist.ini | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 4c0c31be2..0cadf2df3 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -239,8 +239,6 @@ procedure RegisterModule; AddWebsiteModule('Authrone', 'http://www.authrone.com'); AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); - AddWebsiteModule('MangaSpy', 'http://www.mangaspy.com'); - AddWebsiteModule('MangaIce', 'http://www.mangaice.com'); AddWebsiteModule('MangaCow', 'http://mngcow.co'); AddWebsiteModule('HentaiRead', 'http://hentairead.com'); AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index 3c729208b..24ca83c3c 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaIce,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaSpy,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 007e8347b62b413e8c4391f04af50704aa6b999e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 29 Jan 2018 15:57:18 +0300 Subject: [PATCH 2017/2794] remove trailing slashes --- baseunits/modules/MangaChanRU.pas | 2 +- baseunits/modules/Mangaf.pas | 2 +- baseunits/modules/myMangaReaderCMS.pas | 2 +- baseunits/uBaseUnit.pas | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index b70e08a42..3c8009878 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -160,7 +160,7 @@ procedure RegisterModule; begin AddWebsiteModule('MangaChanRU', 'http://mangachan.me'); - AddWebsiteModule('HentaiChanRU', 'http://hentai-chan.me/'); + AddWebsiteModule('HentaiChanRU', 'http://hentai-chan.me'); AddWebsiteModule('YaoiChanRU', 'http://yaoichan.me'); end; diff --git a/baseunits/modules/Mangaf.pas b/baseunits/modules/Mangaf.pas index 0025e562b..9fb95f221 100644 --- a/baseunits/modules/Mangaf.pas +++ b/baseunits/modules/Mangaf.pas @@ -105,7 +105,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Mangaf'; - RootURL := 'http://mangaf.co/'; + RootURL := 'http://mangaf.co'; TotalDirectory := 3; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index 287f8db58..7ceb6db02 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -111,7 +111,7 @@ procedure RegisterModule; AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); AddWebsiteModule('MangaID', 'http://mangaid.co'); AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); - AddWebsiteModule('MangaDesu','http://mangadesu.net/'); + AddWebsiteModule('MangaDesu','http://mangadesu.net'); end; initialization diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 47ce7656b..f8f9e7ebf 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -286,7 +286,7 @@ interface ('ScanManga', 'http://www.scan-manga.com'), ('DM5', 'http://www.dm5.com'), ('KivManga', 'http://www.kivmanga.com'), - ('MeinManga', 'http://www.meinmanga.com/'), + ('MeinManga', 'http://www.meinmanga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), ('Japan-Shin', 'http://www.japan-shin.com'), From ae0cd2bc83317e60254e0fde4bbf18134a2f8d51 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 05:39:13 +0800 Subject: [PATCH 2018/2794] load mangalist in virtual show website name in title on filter all #884 --- baseunits/DBDataProcess.pas | 13 +- baseunits/FMDOptions.pas | 3 +- baseunits/uBaseUnit.pas | 4 +- mangadownloader/forms/frmMain.lfm | 16 +- mangadownloader/forms/frmMain.pas | 238 +++++++++++++++++------------- 5 files changed, 162 insertions(+), 112 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 697970f93..8e777487a 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -64,11 +64,11 @@ TDBDataProcess = class(TObject) function Search(ATitle: String): Boolean; function CanFilter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const {%H-}minusDay: Cardinal; + const {%H-}minusDay: Integer; const haveAllChecked, searchNewManga: Boolean): Boolean; function Filter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; + const minusDay: Integer; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; function WebsiteLoaded(const AWebsite: String): Boolean; function LinkExist(ALink: String): Boolean; @@ -459,10 +459,7 @@ function TDBDataProcess.InternalOpen(const FilePath: String): Boolean; function TDBDataProcess.GetWebsiteName(RecIndex: Integer): String; begin Result:=FWebsite; - if FQuery.Active=False then Exit; - if DBTempFieldWebsiteIndex>=FQuery.Fields.Count then Exit; - if (RecIndex<0) or (RecIndex>FRecordCount) then Exit; - if FAttachedSites.Count>0 then + if FAllSitesAttached then try FQuery.RecNo:=RecIndex+1; Result:=FQuery.Fields[DBTempFieldWebsiteIndex].AsString; @@ -944,7 +941,7 @@ function TDBDataProcess.Search(ATitle: String): Boolean; function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; + const minusDay: Integer; const haveAllChecked, searchNewManga: Boolean): Boolean; begin Result := False; if not FQuery.Active then @@ -965,7 +962,7 @@ function TDBDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringL function TDBDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; + const minusDay: Integer; const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean): Boolean; var tsql: String; diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index e968a89ae..b222f637f 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -141,7 +141,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionAutoCheckFavStartup: Boolean = True; OptionAutoCheckFavInterval: Boolean = True; OptionAutoCheckFavIntervalMinutes: Cardinal = 60; - OptionNewMangaTime: Cardinal = 1; + OptionNewMangaTime: Integer = 1; + OptionJDNNewMangaTime: Integer = MaxInt; OptionAutoCheckFavDownload: Boolean = False; OptionAutoCheckFavRemoveCompletedManga: Boolean = False; OptionUpdateListNoMangaInfo: Boolean = False; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f8f9e7ebf..823ce2b52 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -26,9 +26,7 @@ interface MemBitmap, FPWritePNG; const - JPG_HEADER: array[0..2] of Byte = ($FF, $D8, $FF); - GIF_HEADER: array[0..2] of Byte = ($47, $49, $46); - PNG_HEADER: array[0..2] of Byte = ($89, $50, $4E); + LineEnding2 = LineEnding + LineEnding; UTF8BOM = #$EF#$BB#$BF; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e8a1f22c0..a9cdd29f9 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -417,9 +417,11 @@ object MainForm: TMainForm OnBeforeCellPaint = vtMangaListBeforeCellPaint OnChange = vtMangaListChange OnColumnDblClick = vtMangaListColumnDblClick - OnGetCursor = vtMangaListGetCursor + OnFreeNode = vtMangaListFreeNode OnGetText = vtMangaListGetText OnGetHint = vtMangaListGetHint + OnGetNodeDataSize = vtMangaListGetNodeDataSize + OnInitNode = vtMangaListInitNode end object btAbortUpdateList: TSpeedButton Left = 104 @@ -6310,6 +6312,9 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } + BitmapAdv = { + 4C6900000000 + } end object IconDL: TImageList left = 278 @@ -6605,6 +6610,9 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } + BitmapAdv = { + 4C6900000000 + } end object IconMed: TImageList Height = 48 @@ -6902,6 +6910,9 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } + BitmapAdv = { + 4C6900000000 + } end object IconSmall: TImageList left = 27 @@ -7005,6 +7016,9 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } + BitmapAdv = { + 4C6900000000 + } end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e2e4612fb..92bad080d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -618,14 +618,17 @@ TMainForm = class(TForm) procedure vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure vtMangaListGetCursor(Sender: TBaseVirtualTree; - var ACursor: TCursor); + procedure vtMangaListFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); + procedure vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); procedure vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); procedure tmBackupTimer(Sender: TObject); + procedure vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); procedure vtOptionMangaSiteSelectionFocusChanged(Sender : TBaseVirtualTree; @@ -782,6 +785,22 @@ TSearchDBThread = class(TThread) procedure NewSearch(const ASearchStr: String); end; + PMangaInfoData = ^TMangaInfoData; + + TMangaInfoData = record + website, + link, + title, + titleformat, + authors, + artists, + genres, + status, + summary: String; + numchapter, + jdn: Integer; + end; + procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); var @@ -1036,9 +1055,7 @@ procedure TOpenDBThread.SyncOpenFinish; else lbMode.Caption := Format(RS_ModeAll, [dataProcess.RecordCount]); SetControlEnabled(True); - vtMangaList.BeginUpdate; vtMangaList.RootNodeCount := dataProcess.RecordCount; - vtMangaList.EndUpdate; ChangeAllCursor(pssInfoList, crDefault); end; end; @@ -1055,7 +1072,7 @@ procedure TOpenDBThread.Execute; dataProcess.Search(MainForm.edMangaListSearch.Text); end; if not Terminated then - Synchronize(@SyncOpenFinish); + Synchronize(@SyncOpenFinish); end; end; @@ -2917,22 +2934,17 @@ procedure TMainForm.btFilterResetClick(Sender: TObject); procedure TMainForm.miMangaListAddToFavoritesClick(Sender: TObject); var - i: Cardinal; xNode: PVirtualNode; + data: PMangaInfoData; begin if vtMangaList.SelectedCount = 0 then Exit; SilentThreadManager.BeginAdd; try xNode := vtMangaList.GetFirstSelected; - for i := 0 to vtMangaList.SelectedCount - 1 do + while Assigned(xNode) do begin - if vtMangaList.Selected[xNode] then - begin - SilentThreadManager.Add(MD_AddToFavorites, - dataProcess.WebsiteName[xNode^.Index], - DataProcess.Value[xNode^.Index, DATA_PARAM_TITLE], - DataProcess.Value[xNode^.Index, DATA_PARAM_LINK]); - end; + data := vtMangaList.GetNodeData(xNode); + SilentThreadManager.Add(MD_AddToFavorites, data^.website, data^.title, data^.link); xNode := vtMangaList.GetNextSelected(xNode); end; finally @@ -3311,9 +3323,10 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); var xNode: PVirtualNode; AllowedToCreate, YesAll, NoAll : Boolean; - i, j: Integer; + i: Integer; mResult: TModalResult; mBtns: TMsgDlgButtons; + data: PMangaInfoData; begin if vtMangaList.SelectedCount = 0 then Exit; @@ -3327,52 +3340,46 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); mBtns := [mbYes, mbNo, mbYesToAll, mbNoToAll]; xNode := vtMangaList.GetFirstSelected; - for i := 0 to vtMangaList.SelectedCount - 1 do + while Assigned(xNode) do begin - if vtMangaList.Selected[xNode] then - begin - AllowedToCreate := True; - if DLManager.Count > 0 then - for j := 0 to DLManager.Count - 1 do - if dataProcess.Value[xNode^.Index, DATA_PARAM_TITLE] = - DLManager.Items[j].DownloadInfo.title then + data := vtMangaList.GetNodeData(xNode); + AllowedToCreate := True; + if DLManager.Count > 0 then + for i := 0 to DLManager.Count - 1 do + if data^.title = DLManager.Items[i].DownloadInfo.title then + begin + if YesAll then + AllowedToCreate := True + else if NoAll then + AllowedToCreate := False + else begin - if YesAll then - AllowedToCreate := True - else if NoAll then - AllowedToCreate := False - else - begin - pcMain.ActivePage := tsDownload; - mResult := MessageDlg('', DLManager.Items[j].DownloadInfo.title + - LineEnding + LineEnding + RS_DlgTitleExistInDLlist, mtConfirmation, - mBtns, 0); - case mResult of - mrYes : AllowedToCreate := True; - mrNo : AllowedToCreate := False; - mrYesToAll : - begin - YesAll := True; - NoAll := False; - AllowedToCreate := True; - end; - mrNoToAll : - begin - YesAll := False; - NoAll := True; - AllowedToCreate := False; - end; - end; + pcMain.ActivePage := tsDownload; + mResult := MessageDlg('', DLManager.Items[i].DownloadInfo.title + + LineEnding + LineEnding + RS_DlgTitleExistInDLlist, mtConfirmation, + mBtns, 0); + case mResult of + mrYes : AllowedToCreate := True; + mrNo : AllowedToCreate := False; + mrYesToAll : + begin + YesAll := True; + NoAll := False; + AllowedToCreate := True; + end; + mrNoToAll : + begin + YesAll := False; + NoAll := True; + AllowedToCreate := False; + end; end; - Break; end; + Break; + end; - if AllowedToCreate then - SilentThreadManager.Add(MD_DownloadAll, - dataProcess.WebsiteName[xNode^.Index], - dataProcess.Value[xNode^.Index, DATA_PARAM_TITLE], - dataProcess.Value[xNode^.Index, DATA_PARAM_LINK]); - end; + if AllowedToCreate then + SilentThreadManager.Add(MD_DownloadAll, data^.website, data^.title, data^.link); xNode := vtMangaList.GetNextSelected(xNode); end; except @@ -3383,12 +3390,14 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); end; procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); +var + data: PMangaInfoData; begin if Assigned(vtMangaList.FocusedNode) then - ViewMangaInfo(DataProcess.Value[vtMangaList.FocusedNode^.Index, DATA_PARAM_LINK], - DataProcess.WebsiteName[vtMangaList.FocusedNode^.Index], - DataProcess.Value[vtMangaList.FocusedNode^.Index, DATA_PARAM_TITLE], - vtMangaList.FocusedNode^.Index); + begin + data := vtMangaList.GetNodeData(vtMangaList.FocusedNode); + ViewMangaInfo(data^.link, data^.website, data^.title, vtMangaList.FocusedNode^.Index); + end; end; procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); @@ -4317,76 +4326,83 @@ procedure TMainForm.btOptionApplyClick(Sender: TObject); procedure TMainForm.vtMangaListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + data: PMangaInfoData; begin if CellPaintMode <> cpmPaint then Exit; - if Node^.Index>=dataProcess.RecordCount then Exit; with TargetCanvas do begin Brush.Color := clNone; - if dataProcess.Value[Node^.Index, DATA_PARAM_STATUS] = MangaInfo_StatusCompleted then + data := Sender.GetNodeData(Node); + if data^.status = MangaInfo_StatusCompleted then Brush.Color := CL_MNCompletedManga; - if miHighlightNewManga.Checked and - (dataProcess.ValueInt[Node^.Index, DATA_PARAM_JDN] > (currentJDN - OptionNewMangaTime)) then + if miHighlightNewManga.Checked and (data^.jdn > OptionJDNNewMangaTime) then + begin + if Brush.Color <> clNone then + Brush.Color := Brush.Color + CL_MNNewManga + else Brush.Color := CL_MNNewManga; - + end; if Brush.Color <> clNone then FillRect(CellRect); end; end; -procedure TMainForm.vtMangaListGetCursor(Sender: TBaseVirtualTree; - var ACursor: TCursor); +procedure TMainForm.vtMangaListFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + data: PMangaInfoData; begin - ACursor := Sender.Cursor; + data := Sender.GetNodeData(Node); + Finalize(data^); end; procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); var - LPos: Integer; - s: String; + data: PMangaInfoData; begin - s := ''; - LPos := Node^.Index; - with dataProcess do + data := Sender.GetNodeData(Node); + with data^ do begin - if FilterAllSites then - s := s + RS_InfoWebsite + LineEnding + - dataProcess.WebsiteName[LPos] + LineEnding + LineEnding; - if Trim(Value[LPos, DATA_PARAM_TITLE]) <> '' then - s := s + RS_InfoTitle + LineEnding + Value[LPos, DATA_PARAM_TITLE]; - if Trim(Value[LPos, DATA_PARAM_AUTHORS]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoAuthors + LineEnding + - Value[LPos, DATA_PARAM_AUTHORS]; - if Trim(Value[LPos, DATA_PARAM_ARTISTS]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoArtists + LineEnding + - Value[LPos, DATA_PARAM_ARTISTS]; - if Trim(Value[LPos, DATA_PARAM_GENRES]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoGenres + LineEnding + - Value[LPos, DATA_PARAM_GENRES]; - if Trim(Value[LPos, DATA_PARAM_STATUS]) <> '' then + if dataProcess.FilterAllSites then + HintText += RS_InfoWebsite + LineEnding + website + LineEnding2; + HintText += RS_InfoTitle + LineEnding + title; + if authors <> '' then + HintText += LineEnding2 + RS_InfoAuthors + LineEnding + authors; + if artists <> '' then + HintText += LineEnding2 + RS_InfoArtists + LineEnding + artists; + if genres <> '' then + HintText += LineEnding2 + RS_InfoGenres + LineEnding + genres; + if status <> '' then begin - s := s + LineEnding + LineEnding + RS_InfoStatus + LineEnding; - if Value[LPos, DATA_PARAM_STATUS] = '0' then - s := s + cbFilterStatus.Items[0] + HintText += LineEnding2 + RS_InfoStatus + LineEnding; + if status = '0' then + HintText += cbFilterStatus.Items[0]; + if status = '1' then + HintText += cbFilterStatus.Items[1] else - s := s + cbFilterStatus.Items[1]; + HintText += status; end; - if Trim(Value[LPos, DATA_PARAM_SUMMARY]) <> '' then - s := s + LineEnding + LineEnding + RS_InfoSummary + LineEnding + - StringBreaks(dataProcess.Value[LPos, DATA_PARAM_SUMMARY]); + if summary <> '' then + HintText += LineEnding2 + RS_InfoSummary + LineEnding + summary; end; - HintText := s; +end; + +procedure TMainForm.vtMangaListGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TMangaInfoData); end; procedure TMainForm.vtMangaListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + data: PMangaInfoData; begin - if Assigned(Node) then - CellText := Format('%s (%d)', [dataProcess.Value[Node^.Index, DATA_PARAM_TITLE], - dataProcess.ValueInt[Node^.Index, DATA_PARAM_NUMCHAPTER]]); + data := Sender.GetNodeData(Node); + CellText := data^.titleformat; end; procedure TMainForm.InitCheckboxes; @@ -5123,6 +5139,7 @@ procedure TMainForm.ApplyOptions; OptionAutoCheckFavInterval := cbOptionAutoCheckFavInterval.Checked; OptionAutoCheckFavIntervalMinutes := seOptionAutoCheckFavIntervalMinutes.Value; OptionNewMangaTime := seOptionNewMangaTime.Value; + OptionJDNNewMangaTime := currentJDN - OptionNewMangaTime; OptionAutoCheckFavDownload := cbOptionAutoCheckFavDownload.Checked; OptionAutoCheckFavRemoveCompletedManga := cbOptionAutoCheckFavRemoveCompletedManga.Checked; OptionUpdateListNoMangaInfo := cbOptionUpdateListNoMangaInfo.Checked; @@ -5779,6 +5796,29 @@ procedure TMainForm.tmBackupTimer(Sender: TObject); FavoriteManager.Backup; end; +procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + data: PMangaInfoData; +begin + data := Sender.GetNodeData(Node); + with data^ do + begin + link := dataProcess.Value[Node^.Index, DATA_PARAM_LINK]; + title := dataProcess.Value[Node^.Index, DATA_PARAM_TITLE]; + authors := dataProcess.Value[Node^.Index, DATA_PARAM_AUTHORS]; + artists := dataProcess.Value[Node^.Index, DATA_PARAM_ARTISTS]; + genres := dataProcess.Value[Node^.Index, DATA_PARAM_GENRES]; + status := dataProcess.Value[Node^.Index, DATA_PARAM_STATUS]; + numchapter := dataProcess.ValueInt[Node^.Index, DATA_PARAM_NUMCHAPTER]; + jdn := dataProcess.ValueInt[Node^.Index, DATA_PARAM_JDN]; + website := dataProcess.WebsiteName[Node^.Index]; + titleformat := title + ' (' + IntToStr(numchapter) + ')'; + if dataProcess.FilterAllSites then + titleformat += ' [' + website + ']'; + end; +end; + procedure TMainForm.vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; Node : PVirtualNode); begin From b2fc9436ff537d4614a49569612a623507ceac72 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 06:05:44 +0800 Subject: [PATCH 2019/2794] fix update mangalist after getmangainfo --- baseunits/uGetMangaInfosThread.pas | 45 +++++++++++++++--------------- mangadownloader/forms/frmMain.pas | 11 ++++---- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index c7fe8e9d2..178110f07 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -17,7 +17,7 @@ interface uses SysUtils, Graphics, Dialogs, uBaseUnit, uData, FMDOptions, - BaseThread; + BaseThread, VirtualTrees; type @@ -25,7 +25,7 @@ interface TGetMangaInfosThread = class(TBaseThread) protected - FMangaListPos: Integer; + FMangaListNode: PVirtualNode; FCover: TPicture; FTitle, FWebsite, FLink: String; FInfo: TMangaInformation; @@ -44,7 +44,7 @@ TGetMangaInfosThread = class(TBaseThread) property Title: String read FTitle write FTitle; property Website: String read FWebsite write FWebsite; property Link: String read FLink write FLink; - property MangaListPos: Integer read FMangaListPos write FMangaListPos; + property MangaListNode: PVirtualNode read FMangaListNode write FMangaListNode; end; implementation @@ -62,8 +62,8 @@ procedure TGetMangaInfosThread.Execute; function GetMangaInfo: Boolean; var - filterPos: Cardinal; infob: byte; + data: PMangaInfoData; begin Result := False; try @@ -71,20 +71,20 @@ procedure TGetMangaInfosThread.Execute; FInfo.mangaInfo.link := Link; FInfo.mangaInfo.title := Title; FInfo.ModuleId := Modules.LocateModule(Website); - if (FMangaListPos >= 0) and (MainForm.cbSelectManga.ItemIndex<>-1) and + data := MainForm.vtMangaList.GetNodeData(FMangaListNode); + if Assigned(FMangaListNode) and (MainForm.cbSelectManga.ItemIndex<>-1) and (website = MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex]) then begin - filterPos := FMangaListPos; if FInfo.mangaInfo.title = '' then - FInfo.mangaInfo.title := dataProcess.Value[filterPos, DATA_PARAM_TITLE]; - FInfo.mangaInfo.link := dataProcess.Value[filterPos, DATA_PARAM_LINK]; - FInfo.mangaInfo.authors := dataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; - FInfo.mangaInfo.artists := dataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; - FInfo.mangaInfo.status := dataProcess.Value[filterPos, DATA_PARAM_STATUS]; - FInfo.mangaInfo.summary := dataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; - FInfo.mangaInfo.numChapter := StrToIntDef(dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); - FInfo.mangaInfo.genres := dataProcess.Value[filterPos, DATA_PARAM_GENRES]; - FNumChapter := StrToIntDef(dataProcess.Value[filterPos, DATA_PARAM_NUMCHAPTER], 0); + FInfo.mangaInfo.title := data^.title; + FInfo.mangaInfo.link := data^.link; + FInfo.mangaInfo.authors := data^.authors; + FInfo.mangaInfo.artists := data^.artists; + FInfo.mangaInfo.status := data^.status; + FInfo.mangaInfo.summary := data^.summary; + FInfo.mangaInfo.numChapter := data^.numchapter; + FInfo.mangaInfo.genres := data^.genres; + FNumChapter := data^.numchapter; end; FInfo.isGenerateFolderChapterName := OptionGenerateMangaFolder; FInfo.isRemoveUnicode := OptionChangeUnicodeCharacter; @@ -108,20 +108,20 @@ procedure TGetMangaInfosThread.Execute; if (FInfo.mangaInfo.title <> '') and (FInfo.mangaInfo.title <> FTitle) then FTitle := FInfo.mangaInfo.title; - if FMangaListPos >= 0 then + if Assigned(data) then begin if dataProcess.WebsiteLoaded(Website) then begin if SitesWithoutInformation(website) then begin if FInfo.mangaInfo.authors = '' then - FInfo.mangaInfo.authors := DataProcess.Value[filterPos, DATA_PARAM_AUTHORS]; + FInfo.mangaInfo.authors := data^.authors; if FInfo.mangaInfo.artists = '' then - FInfo.mangaInfo.artists := DataProcess.Value[filterPos, DATA_PARAM_ARTISTS]; + FInfo.mangaInfo.artists := data^.artists; if FInfo.mangaInfo.genres = '' then - FInfo.mangaInfo.genres := DataProcess.Value[filterPos, DATA_PARAM_GENRES]; + FInfo.mangaInfo.genres := data^.genres; if FInfo.mangaInfo.summary = '' then - FInfo.mangaInfo.summary := DataProcess.Value[filterPos, DATA_PARAM_SUMMARY]; + FInfo.mangaInfo.summary := data^.summary; end; if not (Terminated or isExiting) then @@ -181,10 +181,11 @@ procedure TGetMangaInfosThread.MainThreadShowInfos; begin TransferMangaInfo(mangaInfo, FInfo.mangaInfo); with MainForm do begin - if (FMangaListPos > -1) and dataProcess.WebsiteLoaded(Website) then + if Assigned(FMangaListNode) and dataProcess.WebsiteLoaded(Website) then begin vtMangaList.BeginUpdate; dataProcess.Refresh; + vtMangaList.ReinitNode(FMangaListNode, False); vtMangaList.EndUpdate; end; ShowInformation(mangaInfo.title, mangaInfo.website, mangaInfo.link); @@ -212,7 +213,7 @@ constructor TGetMangaInfosThread.Create; FInfo := TMangaInformation.Create(Self); FCover := MainForm.mangaCover; FIsHasMangaCover := False; - FMangaListPos := -1; + FMangaListNode := nil; end; destructor TGetMangaInfosThread.Destroy; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 92bad080d..6be30827b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -689,7 +689,7 @@ TMainForm = class(TForm) // View manga information procedure ViewMangaInfo(const AURL, AWebsite, ATitle: String; - const AMangaListPos: Integer = -1); + const AMangaListNode: PVirtualNode = nil); // Show manga information procedure ShowInformation(const title, website, link: String); @@ -3396,7 +3396,7 @@ procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); if Assigned(vtMangaList.FocusedNode) then begin data := vtMangaList.GetNodeData(vtMangaList.FocusedNode); - ViewMangaInfo(data^.link, data^.website, data^.title, vtMangaList.FocusedNode^.Index); + ViewMangaInfo(data^.link, data^.website, data^.title, vtMangaList.FocusedNode); end; end; @@ -4378,7 +4378,8 @@ procedure TMainForm.vtMangaListGetHint(Sender: TBaseVirtualTree; begin HintText += LineEnding2 + RS_InfoStatus + LineEnding; if status = '0' then - HintText += cbFilterStatus.Items[0]; + HintText += cbFilterStatus.Items[0] + else if status = '1' then HintText += cbFilterStatus.Items[1] else @@ -4651,7 +4652,7 @@ procedure TMainForm.FilledSaveTo; end; procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; - const AMangaListPos: Integer); + const AMangaListNode: PVirtualNode); var i: Integer; begin @@ -4696,7 +4697,7 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; // start the thread GetInfosThread := TGetMangaInfosThread.Create; - GetInfosThread.MangaListPos := AMangaListPos; + GetInfosThread.MangaListNode := AMangaListNode; GetInfosThread.Title := ATitle; GetInfosThread.Website := AWebsite; GetInfosThread.Link := AURL; From 5d752eea2c9661223b3221fe3cf2375e1ece62f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 13:50:52 +0800 Subject: [PATCH 2020/2794] cleanup form --- mangadownloader/forms/frmMain.lfm | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index a9cdd29f9..32ddf419e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -6312,9 +6312,6 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } - BitmapAdv = { - 4C6900000000 - } end object IconDL: TImageList left = 278 @@ -6610,9 +6607,6 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } - BitmapAdv = { - 4C6900000000 - } end object IconMed: TImageList Height = 48 @@ -6910,9 +6904,6 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } - BitmapAdv = { - 4C6900000000 - } end object IconSmall: TImageList left = 27 @@ -7016,9 +7007,6 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00 } - BitmapAdv = { - 4C6900000000 - } end object pmEditURL: TPopupMenu OnPopup = pmEditURLPopup From 41bdc17ced9da14a4e3ea980aa5def5bb386bedf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 17:34:43 +0800 Subject: [PATCH 2021/2794] kissmanga, add log when testkey failed --- baseunits/modules/KissManga.pas | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 7ce8c4435..9f4ef1f4b 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -198,6 +198,13 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; end; end; + procedure testkeyivlast; + begin + if testkeyiv(kissmangakey, kissmangaiv) then Exit; + SendLog('KissManga, failed to decrypt. chko1='+chko1+'; chko2= '+chko2+'; iv='+civ+'; '+ AURL, DownloadThread.Task.Container.PageLinks); + DownloadThread.Task.Container.PageLinks.Clear; + end; + begin Result := False; if DownloadThread = nil then Exit; @@ -268,15 +275,10 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; if not testkeyiv(chko2, civ) then if not testkeyiv(chko1+chko2, civ) then if not testkeyiv(chko2+chko1, civ) then - if not testkeyiv(kissmangakey, kissmangaiv) then - PageLinks.Clear; + testkeyivlast; end else - if not testkeyiv(kissmangakey, kissmangaiv) then - begin - SendLog('KissManga, failed to decrypt. chko1='+chko1+'; chko2= '+chko2+'; iv='+civ+'; '+AURL, PageLinks); - PageLinks.Clear; - end; + testkeyivlast; if PageLinks.Count <> 0 then begin for i := 0 to PageLinks.Count - 1 do From 54ef3f77bbf6f98aa187132c710a50b6db602c84 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 17:38:19 +0800 Subject: [PATCH 2022/2794] added internettools and besen src path to project search path due to bug in lazarus, internettools and besen need to be compiled twice. add components src path to project search path so fpc can find required source to recompile. --- mangadownloader/md.lpi | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index eddf6adc3..8264edb1b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -177,8 +177,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;..\3rd\BESEN\src;..\3rd\internettools\data;..\3rd\internettools\internet;..\3rd\internettools\system;..\3rd\internettools\import\flre\src;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -210,7 +210,19 @@ -dDOWNLOADER -dSELFUPDATE -dDEBUGLEAKS --dMULTILOG"/> +-dMULTILOG +-uUSE_BBFLRE_UNICODE +-dUSE_SOROKINS_REGEX +-dUSE_BBFULL_UNICODE"/> + <OtherDefines Count="7"> + <Define0 Value="MANGADOWNLOADER"/> + <Define1 Value="DOWNLOADER"/> + <Define2 Value="SELFUPDATE"/> + <Define3 Value="DEBUGLEAKS"/> + <Define4 Value="MULTILOG"/> + <Define5 Value="USE_SOROKINS_REGEX"/> + <Define6 Value="USE_BBFULL_UNICODE"/> + </OtherDefines> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> From d47e7aeef00155abba5e4ef02f5eae0e48365559 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 14 Jan 2018 09:23:25 +0300 Subject: [PATCH 2023/2794] mangazuki, fix all --- baseunits/modules/MangaZuki.pas | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index c16728584..22174b5a2 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -11,7 +11,7 @@ interface implementation const - dirurl = '/series'; + dirurl = '/manga-list'; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; @@ -22,7 +22,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - Page := StrToIntDef(XPathString('(//ul[contains(@class,"pagination")]//a)[last()]/replace(@href,"^.*page=(\d+)\??.*$","$1")'), 1); + Page := StrToIntDef(XPathString('(//ul[contains(@class,"pagination")]//a)[last()-1]/replace(@href,"^.*page=(\d+)$","$1")'), 1); finally Free; end; @@ -39,7 +39,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - XPathHREFAll('//*[@class="row"]//*[@class="caption"]//a', ALinks, ANames); + XPathHREFAll('//*[@class="row"]//a[@class="chart-title"]', ALinks, ANames); finally Free; end; @@ -60,24 +60,11 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//*[@class="profile-thumb"]/img/@src'); + coverLink := XPathString('//meta[@itemprop="photo"]/@content'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@class="media-body"]/h2/text()'); - summary := XPathString('//h6[text()="Synopsis"]/following-sibling::p'); - while True do - begin - for v in XPath('//ul[contains(@class,"media-list")]/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathString('.//h6/text()', v)); - end; - s := XPathString('//ul[contains(@class,"pagination")]/li[@class="next"]/a/@href'); - if s = '' then Break; - if GET(MaybeFillHost(Module.RootURL, s)) then - ParseHTML(Document) - else Break; - if ThreadTerminated then Break; - end; + if title = '' then title := XPathString('//div[@class="container"]/div[@class="row"]/div/h2'); + summary := XPathString('//h5[text()="Summary"]/following-sibling::*'); + XPathHREFAll('//ul[@class="chapters"]/li/h3/a', chapterLinks, chapterName); InvertStrings([chapterLinks, chapterName]); finally Free; @@ -99,8 +86,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Result := True; with TXQueryEngineHTML.Create(Document) do try - for v in XPath('//*[@class="content-wrapper"]/*[@class="row"]/img') do - PageLinks.Add(MaybeFillHost(Module.RootURL, v.toNode.getAttribute('src'))); + for v in XPath('//div[@id="all"]/img/@data-src') do + PageLinks.Add(MaybeFillHost(Module.RootURL, Trim(v.toString))); finally Free; end; From f52e094b52e473a47158d82a2ef26eaf830c6733 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 11:32:09 +0300 Subject: [PATCH 2024/2794] add MangaZukiRaws --- baseunits/modules/MangaZuki.pas | 23 +++++++++++++++-------- config/mangalist.ini | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 22174b5a2..1780f20a6 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -96,16 +96,23 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; procedure RegisterModule; -begin - with AddModule do + + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; begin - Website := 'MangaZuki'; - RootURL := 'https://mangazuki.co'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; + Result := AddModule; + with Result do begin + Website := AWebsite; + RootURL := ARootURL; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; end; + +begin + AddWebsiteModule('MangaZuki', 'https://mangazuki.co'); + AddWebsiteModule('MangaZukiRaws', 'https://raws.mangazuki.co'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 24ca83c3c..ffddf82da 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -13,7 +13,7 @@ Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaS Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas -Raw=RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType +Raw=RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub From 9699792c71f4d27c2fab4ede86f5d1168e006e00 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 10:43:09 +0300 Subject: [PATCH 2025/2794] Add PsychoPlay [EN-SC] --- baseunits/ModuleList.inc | 1 + baseunits/modules/PsychoPlay.pas | 127 +++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/PsychoPlay.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 570eb925a..b51a3c849 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -66,6 +66,7 @@ uses Mangaf, LHTranslation, MangaRock, + PsychoPlay, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/PsychoPlay.pas b/baseunits/modules/PsychoPlay.pas new file mode 100644 index 000000000..ed48cc2f6 --- /dev/null +++ b/baseunits/modules/PsychoPlay.pas @@ -0,0 +1,127 @@ +unit PsychoPlay; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/series'; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('(//ul[contains(@class,"pagination")]//a)[last()]/replace(@href,"^.*page=(\d+)\??.*$","$1")'), 1); + finally + Free; + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '?page=' + IncStr(AURL)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + XPathHREFAll('//*[@class="row"]//*[@class="caption"]//a', ALinks, ANames); + finally + Free; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//*[@class="profile-thumb"]/img/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := XPathString('//div[@class="media-body"]/h2/text()'); + summary := XPathString('//h6[text()="Synopsis"]/following-sibling::p'); + while True do + begin + for v in XPath('//ul[contains(@class,"media-list")]/li/a') do + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('.//h6/text()', v)); + end; + s := XPathString('//ul[contains(@class,"pagination")]/li[@class="next"]/a/@href'); + if s = '' then Break; + if GET(MaybeFillHost(Module.RootURL, s)) then + ParseHTML(Document) + else Break; + if ThreadTerminated then Break; + end; + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v: IXQValue; +begin + Result := False; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('//*[@class="content-wrapper"]/*[@class="row"]/img') do + PageLinks.Add(MaybeFillHost(Module.RootURL, v.toNode.getAttribute('src'))); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'PsychoPlay'; + RootURL := 'https://psychoplay.co'; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + end; +end; + +initialization + RegisterModule; + +end. diff --git a/config/mangalist.ini b/config/mangalist.ini index ffddf82da..904c3d747 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans +English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MangaTube,MeinManga,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From 9a279970115cd0b9b86be194c4c30020b3df151f Mon Sep 17 00:00:00 2001 From: TokcDK <tokcdk@gmail.com> Date: Tue, 30 Jan 2018 16:34:37 +0500 Subject: [PATCH 2026/2794] Updated Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 65 ++++++++++++-------------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 0d55b6e26..32077d330 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -201,8 +201,8 @@ msgid "" "<none>\n" msgstr "" "Завершено\n" -"Постоянный\n" -"<none>\n" +"Онгоинг\n" +"<нет>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -306,6 +306,10 @@ msgid "" "CBZ\n" "PDF\n" msgstr "" +"Как есть\n" +"ZIP\n" +"CBZ\n" +"PDF\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -381,7 +385,7 @@ msgstr "Ключ:" #: kissmanga.rs_kissmanga_usegoogledcp msgid "Use Google DCP" -msgstr "" +msgstr "Использовать Google DCP" #: mangadex.rs_showalllang msgctxt "mangadex.rs_showalllang" @@ -541,11 +545,11 @@ msgstr "Domdomsoft Manga Downloader" #: timportfavorites.edpath.texthint msgctxt "TIMPORTFAVORITES.EDPATH.TEXTHINT" msgid "Path to the software (e.g. C:\\MangaDownloader)" -msgstr "Путь к программному обеспечению (например, C: \\ MangaDownloader)" +msgstr "Путь к программе (пример: C:\\MangaDownloader)" #: timportfavorites.lbselectsoftware.caption msgid "Software:" -msgstr "Программное обеспечение:" +msgstr "Программа:" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -634,7 +638,7 @@ msgstr "Добавить в список загрузки как останов #: tmainform.cbfilterstatus.text msgid "<none>" -msgstr "<none>" +msgstr "<нет>" #: tmainform.cbonlynew.caption msgid "Search only new manga" @@ -784,7 +788,7 @@ msgstr "Экшен" #: tmainform.ckfilteraction.hint msgid "A work typically depicting fighting, violence, chaos, and fast paced motion." -msgstr "Работа, обычно изображающая бой, насилие, хаос и быстрое движение." +msgstr "Работы жанра обычно изображают бой, насилие, хаос и быстрое движение." #: tmainform.ckfilteradult.caption msgid "Adult" @@ -808,7 +812,7 @@ msgstr "Юмор" #: tmainform.ckfiltercomedy.hint msgid "A dramatic work that is light and often humorous or satirical in tone and that usually contains a happy resolution of the thematic conflict." -msgstr "Драматическая работа, легкая и часто юмористическая или сатирическая по тону и, обычно, содержащая счастливое разрешение тематического конфликта." +msgstr "Драматическая работа, легкая и часто юмористическая или сатирическая по тону и, обычно, содержит счастливое разрешение тематического конфликта." #: tmainform.ckfilterdoujinshi.caption msgid "Doujinshi" @@ -816,7 +820,7 @@ msgstr "Додзинси" #: tmainform.ckfilterdoujinshi.hint msgid "Fan based work inpspired by official manga/anime." -msgstr "Фанатская работа, вдохновленная официальной мангой/аниме." +msgstr "Фанатские работы, вдохновленные официальной мангой/аниме." #: tmainform.ckfilterdrama.caption msgid "Drama" @@ -824,7 +828,7 @@ msgstr "Драма" #: tmainform.ckfilterdrama.hint msgid "A work meant to bring on an emotional response, such as instilling sadness or tension." -msgstr "Работа, призванная вызвать эмоциональный отклик, например, внушить печаль или напряжение." +msgstr "Работы жанра призванны вызвать эмоциональный отклик, например, внушить печаль или напряжение." #: tmainform.ckfilterechi.caption msgid "Ecchi" @@ -918,7 +922,7 @@ msgstr "Зрелые" #: tmainform.ckfiltermature.hint msgid "Contains subject matter which may be too extreme for people under the age of 17. Titles in this category may contain intense violence, blood and gore, sexual content and/or strong language." -msgstr "Содержит субъекта, который может быть слишком экстремальным для людей в возрасте до 17 лет. Работы в этой категории могут содержать много насилия, крови, сексуального контента и/или резких слов." +msgstr "Содержит материаллы, которые могут быть слишком экстремальными для несовершеннолетних. Работы в этой категории могут содержать много насилия, крови, сексуального контента и/или резких слов." #: tmainform.ckfiltermecha.caption msgid "Mecha" @@ -926,7 +930,7 @@ msgstr "Меха" #: tmainform.ckfiltermecha.hint msgid "A work involving and usually concentrating on all types of large robotic machines." -msgstr "Работа, включающая и обычно концентрирующаяся на всех типах крупных роботизированных машин." +msgstr "Работы жанра, включают и обычно концентрируются на всех типах крупных роботизированных машин." #: tmainform.ckfiltermusical.caption msgctxt "tmainform.ckfiltermusical.caption" @@ -1000,7 +1004,7 @@ msgstr "Сёдзе" #: tmainform.ckfiltershoujo.hint msgid "A work intended and primarily written for females. Usually involves a lot of romance and strong character development." -msgstr "Работа, нацеленная и предназначенная в основном для женщин. Обычно включает в себя много романтики и сильного развития персонажа." +msgstr "Работы жанра нацелены и предназначены, в основном, для женщин. Обычно включает в себя много романтики и сильного развития персонажа." #: tmainform.ckfiltershoujoai.caption msgid "Shoujo Ai" @@ -1009,7 +1013,7 @@ msgstr "Сёдзе-ай" #: tmainform.ckfiltershoujoai.hint msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." -msgstr "Часто синонимом Юри, это можно считать несколько менее экстремальным. «Девичья любовь», так сказать." +msgstr "Часто ассоциируется с Юри, можно считать несколько менее экстремальным. «Девичья любовь», так сказать." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -1018,7 +1022,7 @@ msgstr "Сёнэн" #: tmainform.ckfiltershounen.hint msgctxt "tmainform.ckfiltershounen.hint" msgid "A work intended and primarily written for males. These works usually involve fighting and/or violence." -msgstr "Работа, нацеленная и предназначенная в основном для мужчин. Обычно эти работы связаны с борьбой и/или насилием." +msgstr "Работы жанра нацелены и предназначены, в основном, для мужчин. Обычно связано с борьбой и/или насилием." #: tmainform.ckfiltershounenai.caption msgid "Shounen Ai" @@ -1026,7 +1030,7 @@ msgstr "Сёнэн-ай" #: tmainform.ckfiltershounenai.hint msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" -msgstr "Часто синонимом яоя, это можно считать несколько менее экстремальным. «Мужская любовь», так сказать" +msgstr "Часто ассоциируется с Яоем, можно считать несколько менее экстремальным. «Мужская любовь», так сказать" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" @@ -1097,7 +1101,7 @@ msgstr "Обычно связано с интимными отношениями #: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" -msgstr "" +msgstr "Всегда запускать задачу с неудавшихся частей" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1111,7 +1115,7 @@ msgstr "Поиск загрузок..." #: tmainform.edfavoritessearch.texthint msgctxt "tmainform.edfavoritessearch.texthint" msgid "Search favorites..." -msgstr "Поиск избранного..." +msgstr "Поиск в избранном..." #: tmainform.edfilterartists.texthint msgctxt "tmainform.edfilterartists.texthint" @@ -1416,20 +1420,16 @@ msgstr "" "Имя папки манги должно содержать как минимум %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" -msgstr "Количество загружаемых задач одновременно (максимум: 8)" +msgstr "Количество одновременно загружаемых задач" #: tmainform.lboptionmaxretry.caption msgid "Number of retry times if tasks have download problems (-1 = always retry)" msgstr "Количество повторных попыток, если задачи имеют проблемы с загрузкой (-1 = всегда повторять)" #: tmainform.lboptionmaxthread.caption -#, fuzzy -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" -msgstr "Количество загружаемых файлов за одну задачу одновременно (максимум: 32)" +msgstr "Количество одновременно загружаемых файлов на одну задачу" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -1468,7 +1468,7 @@ msgstr "Переименовать цифры" #: tmainform.lboptionretryfailedtask.caption msgid "Number of retry times if task failed" -msgstr "" +msgstr "Количество попыток при ошибке в задаче" #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" @@ -1926,7 +1926,7 @@ msgstr "Прогресс" #: tmainform.vtdownload.header.columns[3].text msgctxt "tmainform.vtdownload.header.columns[3].text" msgid "Transfer rate" -msgstr "Скоростъ передачи данных" +msgstr "Скоростъ загрузки" #: tmainform.vtdownload.header.columns[4].text msgctxt "tmainform.vtdownload.header.columns[4].text" @@ -1982,14 +1982,13 @@ msgid "&Add to queue" msgstr "Добавить в очередь" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" #: tselectdirectoryform.caption msgid "Select directory" -msgstr "" +msgstr "Выбрать папку" #: tshutdowncounterform.btabort.caption msgid "&Abort" @@ -2023,22 +2022,19 @@ msgid "Transfer to" msgstr "Перенести на" #: ttransferfavoritesform.rball.caption -#, fuzzy msgctxt "ttransferfavoritesform.rball.caption" msgid "All" msgstr "Все" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" -msgstr "Нельзя перенести" +msgstr "Неподтвержденное" #: ttransferfavoritesform.rbvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" -msgstr "Можно перенести" +msgstr "Подтвержденное" #: ttransferfavoritesform.vtfavs.header.columns[1].text msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" @@ -2278,7 +2274,7 @@ msgstr "Найдена новая версия!" #: uupdatethread.rs_dlghasnewmanga msgid "%s has %d new manga(s)" -msgstr "%s имеет %d новой манги" +msgstr "%s имеет %d новых частей манги" #: uupdatethread.rs_gettingdirectory msgid "Getting directory" @@ -2332,4 +2328,3 @@ msgstr "Синхронизацияе данных" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Обновление списка" - From b72fb294055677abefaedada20a78eb2f701b447 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 15:15:38 +0300 Subject: [PATCH 2027/2794] mangafox, change domain #894 --- baseunits/modules/MangaFox.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 23cd1fc2c..38c749ac0 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -117,7 +117,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaFox'; - RootURL := 'http://mangafox.la'; + RootURL := 'http://fanfox.net'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From 4058a67ad67630ba2a7edefbe8851f29dedbfaed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 21:43:05 +0800 Subject: [PATCH 2028/2794] dbdataprocess, cache current rectno and use next prior on getvalue --- baseunits/DBDataProcess.pas | 38 +++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 8e777487a..3530be024 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -35,7 +35,9 @@ TDBDataProcess = class(TObject) FSQLSelect: String; FFilterSQL: String; FLinks: TStringList; + FRecNo: Integer; function GetLinkCount: Integer; + procedure ResetRecNo(Dataset: TDataSet); protected procedure CreateTable; procedure ConvertNewTable; @@ -302,6 +304,11 @@ function TDBDataProcess.GetLinkCount: Integer; Result := 0; end; +procedure TDBDataProcess.ResetRecNo(Dataset: TDataSet); +begin + FRecNo := 0; +end; + procedure TDBDataProcess.CreateTable; begin if FConn.Connected then @@ -478,7 +485,17 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; Result:=''; if FQuery.Active=False then Exit; try - FQuery.RecNo:=RecIndex+1; + if FRecNo<>RecIndex then + begin + if FRecNo=RecIndex+1 then + FQuery.Prior + else + if FRecNo=RecIndex-1 then + FQuery.Next + else + FQuery.RecNo:=RecIndex+1; + FRecNo:=RecIndex; + end; Result:=FQuery.Fields[FieldIndex].AsString; except end; @@ -491,7 +508,17 @@ function TDBDataProcess.GetValueInt(RecIndex, FieldIndex: Integer): Integer; if not (FieldIndex in [DATA_PARAM_NUMCHAPTER,DATA_PARAM_JDN]) then Exit; try - FQuery.RecNo:=RecIndex+1; + if FRecNo<>RecIndex then + begin + if FRecNo=RecIndex+1 then + FQuery.Prior + else + if FRecNo=RecIndex-1 then + FQuery.Next + else + FQuery.RecNo:=RecIndex+1; + FRecNo:=RecIndex; + end; Result:=FQuery.Fields[FieldIndex].AsInteger; except end; @@ -601,6 +628,13 @@ constructor TDBDataProcess.Create; FFilterApplied := False; FFilterSQL := ''; FAllSitesAttached := False; + + ResetRecNo(nil); + FQuery.AfterOpen := @ResetRecNo; + FQuery.AfterInsert := @ResetRecNo; + FQuery.AfterDelete := @ResetRecNo; + FQuery.AfterEdit := @ResetRecNo; + FQuery.AfterRefresh := @ResetRecNo; end; destructor TDBDataProcess.Destroy; From 3ade68bf3534f358aadca40f08f70a3d1540a2aa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 21:54:25 +0800 Subject: [PATCH 2029/2794] fix delete mangalist --- mangadownloader/forms/frmMain.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6be30827b..206d871a1 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3303,15 +3303,17 @@ procedure TMainForm.miMangaListDeleteClick(Sender: TObject); while Assigned(Node) do begin if dataProcess.DeleteData(Node^.Index) then + begin Inc(DeleteCount); - Node := vtMangaList.GetPreviousSelected(Node); + vtMangaList.DeleteNode(Node); + end; + Node := vtMangaList.GetPreviousSelected(nil); end; dataProcess.Table.ApplyUpdates; dataProcess.Table.SQLTransaction.CommitRetaining; if DeleteCount <> 0 then begin vtMangaList.ClearSelection; - vtMangaList.RootNodeCount := dataProcess.RecordCount; UpdateVtMangaListFilterStatus; end; finally From ca2abd25475a3748f0057fbb3c9e222dc91ef30e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 30 Jan 2018 22:06:58 +0800 Subject: [PATCH 2030/2794] dbdataprocess, deletedata use cached recno --- baseunits/DBDataProcess.pas | 42 +++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 3530be024..923bff411 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -38,6 +38,7 @@ TDBDataProcess = class(TObject) FRecNo: Integer; function GetLinkCount: Integer; procedure ResetRecNo(Dataset: TDataSet); + procedure GoToRecNo(const ARecIndex: Integer); protected procedure CreateTable; procedure ConvertNewTable; @@ -309,6 +310,21 @@ procedure TDBDataProcess.ResetRecNo(Dataset: TDataSet); FRecNo := 0; end; +procedure TDBDataProcess.GoToRecNo(const ARecIndex: Integer); +begin + if FRecNo<>ARecIndex then + begin + if FRecNo=ARecIndex+1 then + FQuery.Prior + else + if FRecNo=ARecIndex-1 then + FQuery.Next + else + FQuery.RecNo:=ARecIndex+1; + FRecNo:=ARecIndex; + end; +end; + procedure TDBDataProcess.CreateTable; begin if FConn.Connected then @@ -485,17 +501,7 @@ function TDBDataProcess.GetValue(RecIndex, FieldIndex: Integer): String; Result:=''; if FQuery.Active=False then Exit; try - if FRecNo<>RecIndex then - begin - if FRecNo=RecIndex+1 then - FQuery.Prior - else - if FRecNo=RecIndex-1 then - FQuery.Next - else - FQuery.RecNo:=RecIndex+1; - FRecNo:=RecIndex; - end; + GoToRecNo(RecIndex); Result:=FQuery.Fields[FieldIndex].AsString; except end; @@ -508,17 +514,7 @@ function TDBDataProcess.GetValueInt(RecIndex, FieldIndex: Integer): Integer; if not (FieldIndex in [DATA_PARAM_NUMCHAPTER,DATA_PARAM_JDN]) then Exit; try - if FRecNo<>RecIndex then - begin - if FRecNo=RecIndex+1 then - FQuery.Prior - else - if FRecNo=RecIndex-1 then - FQuery.Next - else - FQuery.RecNo:=RecIndex+1; - FRecNo:=RecIndex; - end; + GoToRecNo(RecIndex); Result:=FQuery.Fields[FieldIndex].AsInteger; except end; @@ -877,7 +873,7 @@ function TDBDataProcess.DeleteData(const RecIndex: Integer): Boolean; begin Result := False; try - FQuery.RecNo := RecIndex + 1; + GoToRecNo(RecIndex); FQuery.Delete; Dec(FRecordCount); Result := True; From bd783b195119127cf46c5f06f6c2fa821c4fcfff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 07:39:45 +0800 Subject: [PATCH 2031/2794] cf, simple check --- baseunits/modules/Cloudflare.pas | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index f5755bd59..5b974073e 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -36,16 +36,15 @@ implementation MIN_WAIT_TIME = 4000; function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; +var + s: String; begin Result := False; if AHTTP = nil then Exit; if AHTTP.ResultCode < 500 then Exit; - with TXQueryEngineHTML.Create(AHTTP.Document) do - try - Result := XPathString('//input[@name="jschl_vc"]/@value') <> ''; - finally - Free; - end; + s := StreamToString(AHTTP.Document); + Result := Pos('name="jschl_vc"',s) <> 0; + s := ''; end; function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; From cc80fbcfea07e2ee4a39cb7713a6857f1236b9cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 08:03:43 +0800 Subject: [PATCH 2032/2794] cf, check only text/html --- baseunits/modules/Cloudflare.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 5b974073e..a0a536cef 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -42,6 +42,7 @@ function AntiBotActive(const AHTTP: THTTPSendThread): Boolean; Result := False; if AHTTP = nil then Exit; if AHTTP.ResultCode < 500 then Exit; + if Pos('text/html', AHTTP.Headers.Values['Content-Type']) = 0 then Exit; s := StreamToString(AHTTP.Document); Result := Pos('name="jschl_vc"',s) <> 0; s := ''; From 3130ca31dbad491313a60be5a51a68d14d206146 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 10:39:30 +0800 Subject: [PATCH 2033/2794] httpsentthread, added onhttprequest --- baseunits/httpsendthread.pas | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index f4b2695b6..2a98227a2 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -46,6 +46,8 @@ THTTPSendThread = class; THTTPMethodEvent = procedure(const AHTTP: THTTPSendThread; var Method, URL: String); + THTTPRequestEvent = function(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject = nil): Boolean of object; + { THTTPSendThread } THTTPSendThread = class(THTTPSend) @@ -62,6 +64,7 @@ THTTPSendThread = class(THTTPSend) procedure OnOwnerTerminate(Sender: TObject); protected procedure ParseCookiesExpires; + function InternalHTTPRequest(const Method, URL: String; const Response: TObject = nil): Boolean; public constructor Create(AOwner: TBaseThread = nil); destructor Destroy; override; @@ -90,6 +93,7 @@ THTTPSendThread = class(THTTPSend) public BeforeHTTPMethod: THTTPMethodEvent; AfterHTTPMethod: THTTPMethodEvent; + OnHTTPRequest: THTTPRequestEvent; property LastURL: String read FURL; end; @@ -364,6 +368,15 @@ procedure THTTPSendThread.ParseCookiesExpires; end; end; +function THTTPSendThread.InternalHTTPRequest(const Method, URL: String; + const Response: TObject): Boolean; +begin + if Assigned(OnHTTPRequest) then + Result := OnHTTPRequest(Self, Method, URL, Response) + else + Result := HTTPRequest(Method, URL, Response); +end; + constructor THTTPSendThread.Create(AOwner: TBaseThread); begin inherited Create; @@ -388,6 +401,7 @@ constructor THTTPSendThread.Create(AOwner: TBaseThread); end; BeforeHTTPMethod := nil; AfterHTTPMethod := nil; + OnHTTPRequest := nil; EnterCriticalsection(CS_ALLHTTPSendThread); try ALLHTTPSendThread.Add(Self); @@ -515,12 +529,12 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: function THTTPSendThread.HEAD(const URL: String; const Response: TObject): Boolean; begin - Result := HTTPRequest('HEAD', URL, Response); + Result := InternalHTTPRequest('HEAD', URL, Response); end; function THTTPSendThread.GET(const URL: String; const Response: TObject): Boolean; begin - Result := HTTPRequest('GET', URL, Response); + Result := InternalHTTPRequest('GET', URL, Response); end; function THTTPSendThread.POST(const URL: String; const POSTData: String; const Response: TObject): Boolean; @@ -531,7 +545,7 @@ function THTTPSendThread.POST(const URL: String; const POSTData: String; const R end; if (MimeType = 'text/html') or (MimeType = '') then MimeType := 'application/x-www-form-urlencoded'; - Result := HTTPRequest('POST', URL, Response); + Result := InternalHTTPRequest('POST', URL, Response); end; function THTTPSendThread.XHR(const URL: String; const Response: TObject From bc4b357cc282f8954251b8e8008e6d39117052d4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 10:40:41 +0800 Subject: [PATCH 2034/2794] cf, replace cookies with tstringlist --- baseunits/modules/Cloudflare.pas | 47 ++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index a0a536cef..765a527a6 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -14,12 +14,13 @@ interface TCFProps = class public - Cookies: String; + Cookies: TStringList; Expires: TDateTime; CS: TRTLCriticalSection; constructor Create; destructor Destroy; override; procedure Reset; + procedure AddCookiesTo(const ACookies: TStringList); end; { THTTPSendThreadHelper } @@ -114,14 +115,13 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; Result := True; end; -function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String; var Expires: TDateTime): Boolean; +function CFJS(const AHTTP: THTTPSendThread; AURL: String; const Cookies: TStringList; var Expires: TDateTime): Boolean; var m, u, h: String; st, sc, counter, maxretry: Integer; begin Result := False; if AHTTP = nil then Exit; - if Cookie <> '' then AHTTP.Cookies.Text := Cookie; counter := 0; maxretry := AHTTP.RetryCount; AHTTP.RetryCount := 0; @@ -150,7 +150,8 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String; va Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; if Result then begin - Cookie := AHTTP.GetCookies; + Cookies.Clear; + Cookies.AddStrings(AHTTP.Cookies); Expires := AHTTP.CookiesExpires; end; end; @@ -165,7 +166,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Cookie: String; va if AHTTP.ThreadTerminated then Break; if (maxretry > -1) and (maxretry <= counter) then Break; AHTTP.Reset; - AHTTP.GET(AURL); + AHTTP.HTTPRequest('GET', AURL); end; AHTTP.RetryCount := maxretry; end; @@ -176,14 +177,14 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: if AHTTP = nil then Exit; if (CFProps.Expires <> 0.0) and (Now > CFProps.Expires) then CFProps.Reset; - AHTTP.Cookies.Text := CFProps.Cookies; + CFProps.AddCookiesTo(CFProps.Cookies); AHTTP.AllowServerErrorResponse := True; - Result := AHTTP.GET(AURL); + Result := AHTTP.HTTPRequest('GET', AURL); if AntiBotActive(AHTTP) then begin if TryEnterCriticalsection(CFProps.CS) > 0 then try - CFProps.Cookies := ''; - AHTTP.Cookies.Clear; + CFProps.Reset; + //AHTTP.Cookies.Clear; Result := CFJS(AHTTP, AURL, CFProps.Cookies, CFProps.Expires); // reduce the expires by 5 minutes, usually it is 24 hours or 16 hours // in case of the different between local and server time @@ -195,12 +196,12 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: else try EnterCriticalsection(CFProps.CS); - AHTTP.Cookies.Text := CFProps.Cookies; + CFProps.AddCookiesTo(AHTTP.Cookies); finally LeaveCriticalsection(CFProps.CS); end; if not AHTTP.ThreadTerminated then - Result := AHTTP.GET(AURL); + Result := AHTTP.HTTPRequest('GET', AURL); end; end; @@ -208,27 +209,43 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: constructor TCFProps.Create; begin - Reset; InitCriticalSection(CS); + Cookies := TStringList.Create; + Reset; end; destructor TCFProps.Destroy; begin + Cookies.Free; DoneCriticalsection(CS); inherited Destroy; end; procedure TCFProps.Reset; begin - Cookies := ''; - Expires := 0.0; + if TryEnterCriticalsection(CS) <> 0 then + try + Cookies.Clear; + Expires := 0.0; + finally + LeaveCriticalsection(CS); + end; +end; + +procedure TCFProps.AddCookiesTo(const ACookies: TStringList); +var + i: Integer; +begin + if Cookies.Count <> 0 then + for i := 0 to Cookies.Count - 1 do + ACookies.Values[Cookies.Names[i]] := Cookies.ValueFromIndex[i]; end; { THTTPSendThreadHelper } function THTTPSendThreadHelper.GETCF(const AURL: String; const CFProps: TCFProps): Boolean; begin - Cloudflare.GETCF(Self, AURL, CFProps); + Result := Cloudflare.GETCF(Self, AURL, CFProps); end; end. From 33d2a7236ae411a5a96ea9b43356acf98894166f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 10:42:30 +0800 Subject: [PATCH 2035/2794] websitemodules, add cf check for all default is true for now to test the performance --- baseunits/WebsiteModules.pas | 51 +++++++++++++++++++++++--- baseunits/modules/FoOlSlide.pas | 2 +- baseunits/modules/GameofScanlation.pas | 24 ++---------- baseunits/modules/KissManga.pas | 23 ++---------- baseunits/modules/MangaAe.pas | 24 +++--------- baseunits/modules/MangaGo.pas | 22 +++-------- baseunits/modules/MyReadingManga.pas | 22 +++-------- baseunits/modules/Tapas.pas | 17 +-------- baseunits/modules/Tumangaonline.pas | 32 +++------------- 9 files changed, 77 insertions(+), 140 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index a5c3fb059..5ad1b8f83 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -10,8 +10,8 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager, FMDOptions, httpsendthread, - RegExpr; + Classes, SysUtils, uData, uDownloadsManager, FMDOptions, httpsendthread, LazLogger, + Cloudflare, RegExpr; const MODULE_NOT_FOUND = -1; @@ -72,6 +72,11 @@ TModuleContainer = class private FID: Integer; FTotalDirectory: Integer; + FCloudflareCF: TCFProps; + FCloudflareEnabled: Boolean; + procedure SetCloudflareEnabled(AValue: Boolean); + procedure CheckCloudflareEnabled(const AHTTP: THTTPSendThread); + function CloudflareHTTPRequest(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject = nil): Boolean; procedure SetTotalDirectory(AValue: Integer); procedure AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; const AName: String; const ACaption: PString); @@ -116,6 +121,7 @@ TModuleContainer = class const ACaption: PString); procedure AddOptionComboBox(const ABindValue: PInteger; const AName: String; const ACaption, AItems: PString); + property CloudflareEnabled: Boolean read FCloudflareEnabled write SetCloudflareEnabled; end; { TWebsiteModules } @@ -267,6 +273,32 @@ function CleanOptionName(const S: String): String; Inc(i); end; +procedure TModuleContainer.SetCloudflareEnabled(AValue: Boolean); +begin + if FCloudflareEnabled = AValue then Exit; + FCloudflareEnabled := AValue; + if FCloudflareEnabled then + FCloudflareCF := TCFProps.Create + else + begin + FCloudflareCF.Free; + FCloudflareCF := nil; + end; +end; + +procedure TModuleContainer.CheckCloudflareEnabled(const AHTTP: THTTPSendThread); +begin + if FCloudflareEnabled then + if AHTTP.OnHTTPRequest <> @CloudflareHTTPRequest then + AHTTP.OnHTTPRequest := @CloudflareHTTPRequest; +end; + +function TModuleContainer.CloudflareHTTPRequest(const AHTTP: THTTPSendThread; + const Method, URL: String; const Response: TObject): Boolean; +begin + Result := Cloudflare.GETCF(AHTTP, URL, FCloudflareCF); +end; + procedure TModuleContainer.SetTotalDirectory(AValue: Integer); var i: Integer; @@ -293,12 +325,15 @@ constructor TModuleContainer.Create; DynamicPageLink := False; TotalDirectory := 1; CurrentDirectoryIndex := 0; + CloudflareEnabled := True; end; destructor TModuleContainer.Destroy; begin SetLength(TotalDirectoryPage, 0); SetLength(OptionList,0); + if Assigned(FCloudflareCF) then + FCloudflareCF.Free; inherited Destroy; end; @@ -488,7 +523,10 @@ function TWebsiteModules.GetDirectoryPageNumber( if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnGetDirectoryPageNumber) then + begin + CheckCloudflareEnabled(MangaInfo.FHTTP); Result := OnGetDirectoryPageNumber(MangaInfo, Page, WorkPtr,TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.GetDirectoryPageNumber( @@ -520,9 +558,12 @@ function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; begin Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetInfo) then - Result := TModuleContainer(FModuleList[ModuleId]).OnGetInfo( - MangaInfo, AURL, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnGetInfo) then + begin + CheckCloudflareEnabled(MangaInfo.FHTTP); + Result := OnGetInfo(MangaInfo, AURL, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index c2e031d6e..0bdb5635b 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Cloudflare, RegExpr, synautil; + XQueryEngineHTML, httpsendthread, RegExpr, synautil; implementation diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index d0fdfeafd..0ad865ab3 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -6,19 +6,12 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil, Cloudflare; + XQueryEngineHTML, httpsendthread, RegExpr, synautil; implementation const dirurl = '/projects/'; -var - goscf: TCFProps; - -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; -begin - Result := Cloudflare.GETCF(AHTTP, AURL, goscf); -end; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; @@ -28,7 +21,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -63,7 +56,7 @@ function GetInfo(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin url := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if GETWithCookie(MangaInfo.FHTTP, url) then begin + if MangaInfo.FHTTP.GET(url) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create(Document); try @@ -106,7 +99,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; s := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); s := AppendURLDelim(FillHost(Module.RootURL, s)) + '?chapter_view=fullstrip'; - if GETWithCookie(DownloadThread.FHTTP, s) then begin + if DownloadThread.FHTTP.GET(s) then begin Result := True; with TXQueryEngineHTML.Create(Document) do try @@ -135,11 +128,6 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container, DownloadThread.FHTTP do if CurrentDownloadChapterPtr < ChapterLinks.Count then begin Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); - Cookies.Text := goscf.Cookies; - if (goscf.Cookies = '') or (HEAD(AURL) and (ResultCode = 503)) then - Result := GETWithCookie(DownloadThread.FHTTP, Module.RootURL) - else - Result := True; end; end; @@ -157,10 +145,6 @@ procedure RegisterModule; end; initialization - goscf := TCFProps.Create; RegisterModule; -finalization - goscf.Free; - end. diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 9f4ef1f4b..6b6c1c087 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, BaseCrypto, Cloudflare, GoogleDCP, RegExpr, + XQueryEngineHTML, httpsendthread, BaseCrypto, GoogleDCP, RegExpr, synautil; implementation @@ -16,9 +16,6 @@ implementation readcomiconlinedirurl = '/ComicList/Newest'; var - kissmangacf: TCFProps; - readcomiconlinecf: TCFProps; - kissmangaiv: String ='a5e8e2e9c2721be0a84ad660c472c1f3'; kissmangakey: String ='mshsdf832nsdbash20asdmnasdbasd612basd'; kissmangausegoogledcp: Boolean = True; @@ -31,17 +28,9 @@ implementation function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; begin - if Module.Website = 'KissManga' then begin - if kissmangausegoogledcp then - begin - SetGoogleDCP(AHTTP); - Result := AHTTP.GET(AURL); - end - else - Result := Cloudflare.GETCF(AHTTP, AURL, kissmangacf); - end - else if Module.Website = 'ReadComicOnline' then - Result := Cloudflare.GETCF(AHTTP, AURL, readcomiconlinecf); + if (Module.Website = 'KissManga') and kissmangausegoogledcp then + SetGoogleDCP(AHTTP); + Result := AHTTP.GET(AURL); end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; @@ -322,12 +311,8 @@ procedure RegisterModule; end; initialization - kissmangacf := TCFProps.Create; - readcomiconlinecf := TCFProps.Create; RegisterModule; finalization - kissmangacf.Free; - readcomiconlinecf.Free; end. diff --git a/baseunits/modules/MangaAe.pas b/baseunits/modules/MangaAe.pas index 0f6f602fa..87165b517 100644 --- a/baseunits/modules/MangaAe.pas +++ b/baseunits/modules/MangaAe.pas @@ -6,13 +6,10 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, Cloudflare; + XQueryEngineHTML; implementation -var - cf: TCFProps; - const dirurl = '/manga'; @@ -22,7 +19,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GETCF(Module.RootURL + dirurl, cf) then begin + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin Result := NO_ERROR; Page := XPathCount('//div[@class="pagination"]/a', MangaInfo.FHTTP.Document); end; @@ -33,7 +30,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GETCF(Module.RootURL + dirurl + '/page:' + IncStr(AURL), cf) then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '/page:' + IncStr(AURL)) then begin Result := NO_ERROR; XPathHREFAll('//div[@id="mangadirectory"]/div[@class="mangacontainer"]/a[2]', MangaInfo.FHTTP.Document, ALinks, ANames); @@ -48,7 +45,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := MaybeFillHost(Module.RootURL, AURL); - if GETCF(url, cf) then begin + if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try coverLink := XPathString('//img[@class="manga-cover"]/resolve-uri(@src)'); @@ -82,7 +79,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; u := RemoveURLDelim(MaybeFillHost(Module.RootURL, AURL)); if RightStr(u, 2) = '/1' then Delete(u, Length(u)-2, 2); u += '/0/full'; - if GETCF(u, cf) then + if GET(u) then begin Result := True; XPathStringAll('//*[@id="showchaptercontainer"]//img/resolve-uri(@src)', Document, PageLinks); @@ -90,12 +87,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; -function DownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := DownloadThread.FHTTP.GETCF(AURL, cf); -end; - procedure RegisterModule; begin with AddModule do @@ -106,15 +97,10 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; - OnDownloadImage := @DownloadImage; end; end; initialization - cf := TCFProps.Create; RegisterModule; -finalization - cf.Free; - end. diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index e50b740ef..7004d6395 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -6,28 +6,20 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Cloudflare; + XQueryEngineHTML, httpsendthread; implementation -var - mangagocf: TCFProps; - const dirurl= '/list/directory/all/'; -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; -begin - Result := Cloudflare.GETCF(AHTTP, AURL, mangagocf) -end; - function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + '1/') then + if Mangainfo.FHTTP.GET(Module.RootURL + dirurl + '1/') then begin Result := NO_ERROR; Page := StrToIntDef(XPathString('count(//div[@class="pagination"]//ol/li//select/option)', MangaInfo.FHTTP.Document), 1); @@ -39,7 +31,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + IncStr(AURL) + '/') then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL) + '/') then begin Result := NO_ERROR; XPathHREFtitleAll('//div[@class="directory_left"]//li/h3/a', MangaInfo.FHTTP.Document, ALinks, ANames); @@ -54,7 +46,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := MaybeFillHost(Module.RootURL, AURL); - if GETWithCookie(MangaInfo.FHTTP, url) then + if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -87,7 +79,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageLinks.Clear; PageNumber := 0; rurl := MaybeFillHost(Module.RootURL, AURL); - if GETWithCookie(DownloadThread.FHTTP, rurl) then + if GET(rurl) then begin Result := True; s := XPathString('//script[contains(.,"imgsrcs")]', Document); @@ -130,10 +122,6 @@ procedure RegisterModule; end; initialization - mangagocf := TCFProps.Create; RegisterModule; -finalization - mangagocf.Free; - end. diff --git a/baseunits/modules/MyReadingManga.pas b/baseunits/modules/MyReadingManga.pas index 05a16d50b..10a0e084c 100644 --- a/baseunits/modules/MyReadingManga.pas +++ b/baseunits/modules/MyReadingManga.pas @@ -10,21 +10,13 @@ interface implementation -uses Cloudflare, httpsendthread; - -var - myreadingmangacf: TCFProps; - -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): Boolean; -begin - Result := Cloudflare.GETCF(AHTTP, AURL, myreadingmangacf) -end; +uses httpsendthread; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL) then begin + if MangaInfo.FHTTP.GET(Module.RootURL) then begin Result := NO_ERROR; Page := StrToIntDef(XPathString('//*[contains(@class,"archive-pagination")]/ul/li[last()-1]', MangaInfo.FHTTP.Document), 1); end; @@ -35,7 +27,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + '/page/' + IncStr(AURL) + '/') then + if MangaInfo.FHTTP.GET(Module.RootURL + '/page/' + IncStr(AURL) + '/') then begin Result := NO_ERROR; XPathHREFAll('//h2[@class="entry-title"]/a', MangaInfo.FHTTP.Document, ALinks, ANames); @@ -52,7 +44,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := MaybeFillHost(Module.RootURL, AURL); - if GETWithCookie(MangaInfo.FHTTP, url) then begin + if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try title := XPathString('//*[contains(@class,"entry-content")]/h2'); @@ -86,7 +78,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; XPathStringAll('//*[contains(@class,"entry-content")]//div//img/@src', Document, PageLinks); @@ -109,10 +101,6 @@ procedure RegisterModule; end; initialization - myreadingmangacf := TCFProps.Create; RegisterModule; -finalization - myreadingmangacf.Free; - end. diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index ea00757b7..df2964358 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -6,21 +6,12 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Cloudflare, RegExpr; + XQueryEngineHTML, httpsendthread, RegExpr; implementation const dirurl = '/comics?sortType=TITLE&browse=ALL'; - -var - tapascf: TCFProps; - -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): - Boolean; -begin - Result := Cloudflare.GETCF(AHTTP, AURL, tapascf) -end; function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; @@ -74,7 +65,7 @@ function GetInfo(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, FillHost(Module.RootURL, AURL)) then begin + if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -154,10 +145,6 @@ procedure RegisterModule; end; initialization - tapascf := TCFProps.Create; RegisterModule; -finalization - tapascf.Free; - end. diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index a487c6b8e..e0c20ee90 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, Cloudflare, synautil, RegExpr; + XQueryEngineHTML, httpsendthread, synautil, RegExpr; implementation @@ -19,22 +19,13 @@ implementation mangaurl = '/biblioteca/mangas/'; imgurl = 'https://img1.tumangaonline.com'; -var - tumangacf: TCFProps; - -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String): - Boolean; -begin - Result := Cloudflare.GETCF(AHTTP, AURL, tumangacf); -end; - function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + '1&page=1') then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1&page=1') then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -54,7 +45,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -85,7 +76,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; url := FillHost(Module.RootURL, AURL); mangaid := RegExprGetMatch('/\w+/(\d+)/\w+', url, 1); if mangaid = '' then Exit; - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + apiurlmangas + '/' + mangaid) then + if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do @@ -138,7 +129,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin PageLinks.Clear; PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then + if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; with TXQueryEngineHTML.Create(Document) do @@ -154,14 +145,6 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String end; end; -function DownloadImageWithCookie(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - Result := GETWithCookie(DownloadThread.FHTTP, AURL); -end; - procedure RegisterModule; begin with AddModule do begin @@ -173,15 +156,10 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; - OnDownloadImage := @DownloadImageWithCookie; end; end; initialization - tumangacf := TCFProps.Create; RegisterModule; -finalization - tumangacf.Free; - end. From eeca711eb1911147700bfd781fa6d3981a29d9c7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 14:22:21 +0800 Subject: [PATCH 2036/2794] websitemodules, check for cf on all event --- baseunits/WebsiteModules.pas | 62 ++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 5ad1b8f83..da7a72e15 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -542,9 +542,12 @@ function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := MODULE_NOT_FOUND; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink) then - Result := TModuleContainer(FModuleList[ModuleId]).OnGetNameAndLink( - MangaInfo, ANames, ALinks, AURL, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnGetNameAndLink) then + begin + CheckCloudflareEnabled(MangaInfo.FHTTP); + Result := OnGetNameAndLink(MangaInfo, ANames, ALinks, AURL, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; @@ -593,9 +596,12 @@ function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetPageNumber) then - Result := TModuleContainer(FModuleList[ModuleId]).OnGetPageNumber( - DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnGetPageNumber) then + begin + CheckCloudflareEnabled(DownloadThread.FHTTP); + Result := OnGetPageNumber(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; @@ -609,9 +615,12 @@ function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnGetImageURL) then - Result := TModuleContainer(FModuleList[ModuleId]).OnGetImageURL( - DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnGetImageURL) then + begin + CheckCloudflareEnabled(DownloadThread.FHTTP); + Result := OnGetImageURL(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; @@ -626,9 +635,12 @@ function TWebsiteModules.BeforeDownloadImage( begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnBeforeDownloadImage) then - Result := TModuleContainer(FModuleList[ModuleId]).OnBeforeDownloadImage( - DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnBeforeDownloadImage) then + begin + CheckCloudflareEnabled(DownloadThread.FHTTP); + Result := OnBeforeDownloadImage(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.BeforeDownloadImage( @@ -642,9 +654,12 @@ function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnDownloadImage) then - Result := TModuleContainer(FModuleList[ModuleId]).OnDownloadImage( - DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnDownloadImage) then + begin + CheckCloudflareEnabled(DownloadThread.FHTTP); + Result := OnDownloadImage(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; @@ -658,9 +673,12 @@ function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; begin Result := ''; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnSaveImage) then - Result := TModuleContainer(FModuleList[ModuleId]).OnSaveImage( - AHTTP, APath, AName, TModuleContainer(FModuleList[ModuleId])); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnSaveImage) then + begin + CheckCloudflareEnabled(AHTTP); + Result := OnSaveImage(AHTTP, APath, AName, TModuleContainer(FModuleList[ModuleId])); + end; end; function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; @@ -690,8 +708,12 @@ function TWebsiteModules.Login(const AHTTP: THTTPSendThread; begin Result := False; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnLogin) then - Result := TModuleContainer(FModuleList[ModuleId]).OnLogin(AHTTP); + with TModuleContainer(FModuleList[ModuleId]) do + if Assigned(OnLogin) then + begin + CheckCloudflareEnabled(AHTTP); + Result := OnLogin(AHTTP); + end; end; function TWebsiteModules.Login(const AHTTP: THTTPSendThread; From 441a00c327943b2c5c02387a7fd1998b8405c84c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 14:29:14 +0800 Subject: [PATCH 2037/2794] mangago, set referer to download cover image --- baseunits/modules/MangaGo.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 7004d6395..405beecfd 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -63,6 +63,8 @@ function GetInfo(const MangaInfo: TMangaInformation; finally Free; end; + Reset; + Headers.Values['Referer'] := url; end; end; end; From 5223d9656a34d16890638acf8cfef382fc2565f6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 15:07:10 +0800 Subject: [PATCH 2038/2794] cf, only cache clearance cookie --- baseunits/modules/Cloudflare.pas | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 765a527a6..bdb6e6caa 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -14,7 +14,7 @@ interface TCFProps = class public - Cookies: TStringList; + cf_clearance: string; Expires: TDateTime; CS: TRTLCriticalSection; constructor Create; @@ -115,7 +115,7 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; Result := True; end; -function CFJS(const AHTTP: THTTPSendThread; AURL: String; const Cookies: TStringList; var Expires: TDateTime): Boolean; +function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Acf_clearance: String; var AExpires: TDateTime): Boolean; var m, u, h: String; st, sc, counter, maxretry: Integer; @@ -147,13 +147,10 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; const Cookies: TString AHTTP.FollowRedirection := False; if AHTTP.HTTPRequest(m, FillHost(h, u)) then begin - Result := AHTTP.Cookies.Values['cf_clearance'] <> ''; + Acf_clearance := AHTTP.Cookies.Values['cf_clearance']; + Result := Acf_clearance <> ''; if Result then - begin - Cookies.Clear; - Cookies.AddStrings(AHTTP.Cookies); - Expires := AHTTP.CookiesExpires; - end; + AExpires := AHTTP.CookiesExpires; end; AHTTP.FollowRedirection := True; end; @@ -177,7 +174,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: if AHTTP = nil then Exit; if (CFProps.Expires <> 0.0) and (Now > CFProps.Expires) then CFProps.Reset; - CFProps.AddCookiesTo(CFProps.Cookies); + CFProps.AddCookiesTo(AHTTP.Cookies); AHTTP.AllowServerErrorResponse := True; Result := AHTTP.HTTPRequest('GET', AURL); if AntiBotActive(AHTTP) then begin @@ -185,7 +182,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: try CFProps.Reset; //AHTTP.Cookies.Clear; - Result := CFJS(AHTTP, AURL, CFProps.Cookies, CFProps.Expires); + Result := CFJS(AHTTP, AURL, CFProps.cf_clearance, CFProps.Expires); // reduce the expires by 5 minutes, usually it is 24 hours or 16 hours // in case of the different between local and server time if Result then @@ -210,13 +207,11 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: constructor TCFProps.Create; begin InitCriticalSection(CS); - Cookies := TStringList.Create; Reset; end; destructor TCFProps.Destroy; begin - Cookies.Free; DoneCriticalsection(CS); inherited Destroy; end; @@ -225,7 +220,7 @@ procedure TCFProps.Reset; begin if TryEnterCriticalsection(CS) <> 0 then try - Cookies.Clear; + cf_clearance := ''; Expires := 0.0; finally LeaveCriticalsection(CS); @@ -233,12 +228,9 @@ procedure TCFProps.Reset; end; procedure TCFProps.AddCookiesTo(const ACookies: TStringList); -var - i: Integer; begin - if Cookies.Count <> 0 then - for i := 0 to Cookies.Count - 1 do - ACookies.Values[Cookies.Names[i]] := Cookies.ValueFromIndex[i]; + if cf_clearance <> '' then + ACookies.Values['cf_clearance'] := cf_clearance; end; { THTTPSendThreadHelper } From cce1979fdab41b0caa675898eb8b6fcb9c8eb4ca Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 31 Jan 2018 15:50:04 +0800 Subject: [PATCH 2039/2794] websitemodules, add preparehttp --- baseunits/WebsiteModules.pas | 33 ++++++--------------------------- baseunits/uData.pas | 12 +++++++++++- baseunits/uDownloadsManager.pas | 13 ++++++++++++- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index da7a72e15..10b5c74ae 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -122,6 +122,7 @@ TModuleContainer = class procedure AddOptionComboBox(const ABindValue: PInteger; const AName: String; const ACaption, AItems: PString); property CloudflareEnabled: Boolean read FCloudflareEnabled write SetCloudflareEnabled; + procedure PrepareHTTP(const AHTTP: THTTPSendThread); end; { TWebsiteModules } @@ -363,6 +364,11 @@ procedure TModuleContainer.AddOptionComboBox(const ABindValue: PInteger; Items := AItems; end; +procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); +begin + CheckCloudflareEnabled(AHTTP); +end; + procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; const AName: String; const ACaption: PString); begin @@ -523,10 +529,7 @@ function TWebsiteModules.GetDirectoryPageNumber( if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnGetDirectoryPageNumber) then - begin - CheckCloudflareEnabled(MangaInfo.FHTTP); Result := OnGetDirectoryPageNumber(MangaInfo, Page, WorkPtr,TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.GetDirectoryPageNumber( @@ -544,10 +547,7 @@ function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnGetNameAndLink) then - begin - CheckCloudflareEnabled(MangaInfo.FHTTP); Result := OnGetNameAndLink(MangaInfo, ANames, ALinks, AURL, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; @@ -563,10 +563,7 @@ function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnGetInfo) then - begin - CheckCloudflareEnabled(MangaInfo.FHTTP); Result := OnGetInfo(MangaInfo, AURL, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; @@ -598,10 +595,7 @@ function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnGetPageNumber) then - begin - CheckCloudflareEnabled(DownloadThread.FHTTP); Result := OnGetPageNumber(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; @@ -617,10 +611,7 @@ function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnGetImageURL) then - begin - CheckCloudflareEnabled(DownloadThread.FHTTP); Result := OnGetImageURL(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; @@ -637,10 +628,7 @@ function TWebsiteModules.BeforeDownloadImage( if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnBeforeDownloadImage) then - begin - CheckCloudflareEnabled(DownloadThread.FHTTP); Result := OnBeforeDownloadImage(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.BeforeDownloadImage( @@ -656,10 +644,7 @@ function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnDownloadImage) then - begin - CheckCloudflareEnabled(DownloadThread.FHTTP); Result := OnDownloadImage(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; @@ -675,10 +660,7 @@ function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnSaveImage) then - begin - CheckCloudflareEnabled(AHTTP); Result := OnSaveImage(AHTTP, APath, AName, TModuleContainer(FModuleList[ModuleId])); - end; end; function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; @@ -710,10 +692,7 @@ function TWebsiteModules.Login(const AHTTP: THTTPSendThread; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnLogin) then - begin - CheckCloudflareEnabled(AHTTP); Result := OnLogin(AHTTP); - end; end; function TWebsiteModules.Login(const AHTTP: THTTPSendThread; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 73f3e31c2..8a1fca584 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -79,6 +79,8 @@ TDataProcess = class(TObject) TMangaInformation = class(TObject) private FOwner: TBaseThread; + FModuleId: Integer; + procedure SetModuleId(AValue: Integer); public isGetByUpdater: Boolean; mangaInfo: TMangaInfo; @@ -87,7 +89,6 @@ TMangaInformation = class(TObject) isRemoveUnicode: Boolean; RemoveHostFromChapterLinks: Boolean; FHTTP: THTTPSendThread; - ModuleId: Integer; procedure OnTag(NoCaseTag, ActualTag: String); procedure OnText(AText: String); @@ -111,6 +112,7 @@ TMangaInformation = class(TObject) //wrapper function GetPage(var AOutput: TObject; AURL: String; const AReconnect: Integer = 0): Boolean; inline; property Thread: TBaseThread read FOwner; + property ModuleId: Integer read FModuleId write SetModuleId; end; var @@ -756,6 +758,14 @@ procedure TMangaInformation.ClearInfo; mangaInfo.chapterLinks.Clear; end; +procedure TMangaInformation.SetModuleId(AValue: Integer); +begin + if FModuleId = AValue then Exit; + FModuleId := AValue; + if (FModuleId <> -1) and Assigned(FHTTP) then + WebsiteModules.Modules[FModuleId].PrepareHTTP(FHTTP); +end; + procedure TMangaInformation.OnTag(NoCaseTag, ActualTag: String); begin parse.Add(ActualTag); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index ec48e31b9..5af5e1470 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -43,6 +43,8 @@ TTaskThread = class; TDownloadThread = class(TBaseThread) private parse: TStringList; + FTask: TTaskThread; + procedure SetTask(AValue: TTaskThread); public // Get download link from URL function GetLinkPageFromURL(const URL: String): Boolean; @@ -65,10 +67,10 @@ TDownloadThread = class(TBaseThread) procedure Execute; override; public FHTTP: THTTPSendThread; - Task: TTaskThread; WorkId: Integer; constructor Create; destructor Destroy; override; + property Task: TTaskThread read FTask write SetTask; end; TDownloadThreads = specialize TFPGList<TDownloadThread>; @@ -285,6 +287,15 @@ function IntToStr(Value: Cardinal): String; { TDownloadThread } +procedure TDownloadThread.SetTask(AValue: TTaskThread); +begin + if FTask = AValue then Exit; + FTask := AValue; + with FTask.Container do + if ModuleId<>-1 then + WebsiteModules.Modules[ModuleId].PrepareHTTP(FHTTP); +end; + procedure TDownloadThread.OnTag(NoCaseTag, ActualTag: String); begin parse.Add(ActualTag); From 546b357321c4f387f60f1e071d6298b196216cfb Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 31 Jan 2018 16:14:36 +0300 Subject: [PATCH 2040/2794] mangaae, fix download --- baseunits/modules/MangaAe.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaAe.pas b/baseunits/modules/MangaAe.pas index 87165b517..2156fdfbf 100644 --- a/baseunits/modules/MangaAe.pas +++ b/baseunits/modules/MangaAe.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; + XQueryEngineHTML, strutils; implementation @@ -77,7 +77,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageLinks.Clear; PageNumber := 0; u := RemoveURLDelim(MaybeFillHost(Module.RootURL, AURL)); - if RightStr(u, 2) = '/1' then Delete(u, Length(u)-2, 2); + if AnsiEndsStr('/1', u) then u := AnsiLeftStr(u, Length(u)-2); u += '/0/full'; if GET(u) then begin From de451be5e151a3a5ecfb832d8ca0b6f3d8003ebf Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 31 Jan 2018 18:56:24 +0300 Subject: [PATCH 2041/2794] mangago, fix all --- baseunits/BaseCrypto.pas | 42 +++++++- baseunits/modules/MangaGo.pas | 187 ++++++++++++++++++++++++++++++---- 2 files changed, 210 insertions(+), 19 deletions(-) diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas index 8c1f87d1f..3138cc4cb 100644 --- a/baseunits/BaseCrypto.pas +++ b/baseunits/BaseCrypto.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, base64, DCPrijndael, DCPsha256; + Classes, SysUtils, base64, DCPrijndael, DCPsha256, DCPmd5, Math; function HexToStr(const h: String): String; procedure HexToBytes(const h: String; var o :TBytes); @@ -18,6 +18,7 @@ function Pkcs7AddPad(const s: String): String; function Pkcs7RemovePad(const s: String): String; function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; +function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; implementation @@ -132,5 +133,44 @@ function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; end; end; +function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; +var + keyHash: array[0 .. 15] of Byte; + ivBytes: array[0 .. 15] of Byte; + keyBytes: array[0 .. 31] of Byte; + i: Integer; + data: String; +begin + Result := ''; + + with TDCP_md5.Create(nil) do + begin + Init; + UpdateStr(key); + Final(keyHash); + end; + + data := LowerCase(StrToHexStr(BytesToString(keyHash))); + for i := 0 to 31 do + keyBytes[i] := Byte(data[i + 1]); + + FillChar(ivBytes, 16, 0); + for i := 0 to Min(16, Length(iv)) - 1 do + ivBytes[i] := Byte(iv[i + 1]); + + with TDCP_rijndael.Create(nil) do + begin + try + Init(keyBytes, 32*8, @ivBytes[0]); + data := DecodeStringBase64(s); + SetLength(Result,Length(data)); + DecryptCBC(data[1],Result[1],Length(data)); + Burn; + finally + Free; + end; + end; +end; + end. diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 405beecfd..a5c812c0f 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -6,10 +6,14 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; + XQueryEngineHTML, httpsendthread, BaseCrypto, synautil, Graphics, + Interfaces, Math, RegExpr, strutils; implementation +var + deskeys: TStringList; + const dirurl= '/list/directory/all/'; @@ -19,6 +23,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.FHTTP.Headers.Values['Referer'] := Module.RootURL; if Mangainfo.FHTTP.GET(Module.RootURL + dirurl + '1/') then begin Result := NO_ERROR; @@ -29,8 +34,13 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; +var + ref: String; begin Result := NET_PROBLEM; + if AURL = '0' then ref := Module.RootURL + else ref := Module.RootURL + dirurl + AURL + '/'; + MangaInfo.FHTTP.Headers.Values['Referer'] := ref; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL) + '/') then begin Result := NO_ERROR; @@ -69,10 +79,56 @@ function GetInfo(const MangaInfo: TMangaInformation; end; end; +function DecryptScript(script: String): String; +var + rg: TRegExpr; + c: Char; + s: String; +begin + Result := Copy(script, 1, Length(script)); + rg := TRegExpr.Create('\\x[\da-f]{1,2}'); + try + if rg.Exec(script) then begin + s := SeparateRight(rg.Match[0], '\x'); + c := Chr(Byte(Hex2Dec(s) and $ff)); + Result := ReplaceString(Result, rg.Match[0], c); + while rg.ExecNext do begin + s := SeparateRight(rg.Match[0], '\x'); + c := Chr(Byte(Hex2Dec(s) and $ff)); + Result := ReplaceString(Result, rg.Match[0], c); + end; + end; + finally + rg.Free; + end; +end; + +function GetKey(script: String): String; +var + rg: TRegExpr; +begin + Result := ''; + rg := TRegExpr.Create('body\s+ready\s+(\S+)'); + try + if rg.Exec(script) then + Result := '@' + rg.Match[1] + '!'; + finally + rg.Free; + end; +end; + +function GetIV(script: String): String; +begin + Result := GetKey(script); +end; + function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var - s, rurl: String; + s, rurl, script: String; + i: Integer; + a: TStringArray; + t: TStringList; begin Result := False; if DownloadThread = nil then Exit; @@ -81,21 +137,37 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageLinks.Clear; PageNumber := 0; rurl := MaybeFillHost(Module.RootURL, AURL); - if GET(rurl) then - begin - Result := True; - s := XPathString('//script[contains(.,"imgsrcs")]', Document); - if s <> '' then begin - if Pos('imgsrcs = new Array', s) <> 0 then - s := GetString(s, '(', ')') - else - s := GetString(s, ' = ''', ''';'); - s:=StringReplace(s, '''', '', [rfReplaceAll]); - PageLinks.CommaText := s; - if LastURL <> rurl then - PageContainerLinks.Text := LastURL; + if not GET(rurl) then Exit; + + Result := True; + s := XPathString('//script[contains(.,"imgsrcs")]', Document); + if s = '' then Exit; + + if Pos('imgsrcs = new Array', s) <> 0 then + s := GetString(s, '(', ')') + else + s := GetString(s, ' = ''', ''';'); + s := StringReplace(s, '''', '', [rfReplaceAll]); + + if Pos(s, ',') = 0 then begin + script := XPathString('//script[contains(@src, "chapter.js")]/@src', Document); + Reset; + Headers.Values['Referer'] := rurl; + if GET(script) then begin + t := TStringList.Create; + try + t.LoadFromStream(Document); + script := DecryptScript(t.Text); + s := AESDecryptCBCMD5Base64ZerosPadding(s, GetKey(script), GetIV(script)); + finally + t.Free; + end; end; end; + + a := s.Split([',']); + for i := 0 to Length(a) - 1 do + PageLinks.Add(SeparateRight(a[i], '//')); end; end; @@ -104,9 +176,73 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; begin Result := True; if DownloadThread = nil then Exit; - with DownloadThread.Task.Container do - if PageContainerLinks.Count <> 0 then - DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + PageContainerLinks[0]; + DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + Module.RootURL; +end; + +function DeScramble(AURL: String; image: TPicture): TPicture; +var + tmp: String = '18a72a69a64a13a1a43a3aa42a23a66a26a19a51a54a78a34a17a31a35a15a58a29a61a48a73a74a44a52a60a24a63a20a32a7a45a53a75a55a62a59a41a76a68a2a36a21a10a38a33a71a40a67a22a4a50a80a65a27a37a47a70a14a28a16a6a56a30a57a5a11a79a9a77a46a39a25a49a8a12'; + a: TStringArray; + i, size, heightnum, aint: Integer; + sw, h, j, y, rxpos, py, canvasx: float; + r: TPicture; + rect1, rect2: TRect; +begin + for i := 0 to deskeys.Count - 1 do + if Pos(deskeys.Names[i], AURL) > 0 then begin + tmp := deskeys.Values[deskeys.Names[i]]; + Break; + end; + + a := tmp.Split(['a']); + r := TPicture.Create; + r.Bitmap.SetSize(image.Width, image.Height); + + size := 9; + heightnum := 9; + sw := float(image.Width) / size; + h := float(image.Height) / heightnum; + for i := 0 to size * heightnum - 1 do begin + aint := StrToIntDef(a[i], 0); + j := Floor(float(aint) / float(heightnum)); + y := j * h; + rxpos := (aint - j * size) * sw; + j := Floor(float(i) / float(size)); + py := j * h; + canvasX := (i - j * size) * sw; + rect1 := Rect(Trunc(rxpos), Trunc(y), Trunc(rxpos) + Trunc(sw), Trunc(y) + Trunc(h)); + rect2 := Rect(Trunc(canvasX), Trunc(py), Trunc(canvasX) + Trunc(sw), Trunc(py) + Trunc(h)) ; + r.Bitmap.Canvas.CopyRect(rect1, image.Bitmap.Canvas, rect2); + end; + + Result := r; +end; + +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + image, r: TPicture; +begin + Result := False; + if DownloadThread = nil then Exit; + if DownloadThread.FHTTP.GET(AURL) then begin + if Pos('cspiclink', LowerCase(AURL)) = 0 then begin + Result := True; + Exit; + end; + image := TPicture.Create; + r := nil; + try + image.LoadFromStream(DownloadThread.FHTTP.Document); + r := DeScramble(AURL, image); + DownloadThread.FHTTP.Document.Position := 0; + r.SaveToStreamWithFileExt(DownloadThread.FHTTP.Document, 'jpg'); + Result := True; + finally + r.Free; + image.Free; + end; + end; end; procedure RegisterModule; @@ -120,10 +256,25 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnBeforeDownloadImage := @BeforeDownloadImage; + OnDownloadImage := @DownloadImage; end; end; initialization + deskeys := TStringList.Create; + deskeys.Values['60a2b0ed56cd458c4633d04b1b76b7e9'] := '18a72a69a64a13a1a43a3aa42a23a66a26a19a51a54a78a34a17a31a35a15a58a29a61a48a73a74a44a52a60a24a63a20a32a7a45a53a75a55a62a59a41a76a68a2a36a21a10a38a33a71a40a67a22a4a50a80a65a27a37a47a70a14a28a16a6a56a30a57a5a11a79a9a77a46a39a25a49a8a12'; + deskeys.Values['400df5e8817565e28b2e141c533ed7db'] := '61a74a10a45a3a37a72a22a57a39a25a56a52a29a70a60a67a41a63a55a27a28a43a18a5a9a8a40a17a48a44a79a38a47a32a73a4a6a13a34a33a49a2a42a50a76a54a36a35a14a58a7a69a46a16a30a21a11aa51a53a77a26a31a1a19a20a80a24a62a68a59a66a75a12a64a78a71a15a65a23'; + deskeys.Values['84ba0d8098f405b14f4dbbcc04c93bac'] := '61a26a35a16a55a10a72a37a2a60a66a65a33a44a7a28a70a62a32a56a30a40a58a15a74a47aa36a78a75a11a6a77a67a39a23a9a31a64a59a13a24a80a14a38a45a21a63a19a51a17a34a50a46a5a29a73a8a57a69a48a68a49a71a41a12a52a18a79a76a54a42a22a4a1a3a53a20a25a43a27'; + deskeys.Values['56665708741979f716e5bd64bf733c33'] := '23a7a41a48a57a27a69a36a76a62a40a75a26a2a51a6a10a65a43a24a1aa20a71a28a30a13a38a79a78a72a14a49a55a56a58a25a70a12a80a3a66a11a39a42a17a15a54a45a34a74a31a8a61a46a73a63a22a64a19a77a50a9a59a37a68a52a18a32a16a33a60a67a21a44a53a5a35a4a29a47'; + deskeys.Values['a67e15ed870fe4aab0a502478a5c720f'] := '8a12a59a52a24a13a37a21a55a56a41a71a65a43a40a66a11a79a67a44a33a20a72a2a31a42a29a34a58a60a27a48a28a15a35a51a76a80a0a63a69a53a39a46a64a50a75a1a57a9a62a74a18a16a73a14a17a6a19a61a23a38a10a3a32a26a36a54a4a30a45a47a70a22a7a68a49a77a5a25a78'; + deskeys.Values['b6a2f75185754b691e4dfe50f84db57c'] := '47a63a76a58a37a4a56a21a1a48a62a2a36a44a34a42a23a9a60a72a11a74a70a20a77a16a15a35a69a0a55a46a24a6a32a75a68a43a41a78a31a71a52a33a67a25a80a30a5a28a40a65a39a14a29a64a3a53a49a59a12a66a38a27a79a45a18a22a8a61a50a17a51a10a26a13a57a19a7a54a73'; + deskeys.Values['db99689c5a26a09d126c7089aedc0d86'] := '57a31a46a61a55a41a26a2a39a24a75a4a45a13a23a51a15a8a64a37a72a34a12a3a79a42a80a17a62a49a19a77a48a68a78a65a14a10a29a16a20a76a38a36a54a30a53a40a33a21a44a22a32a5a1a7a70a67a58a0a71a74a43a66a6a63a35a56a73a9a27a25a59a47a52a11a50a18a28a60a69'; + deskeys.Values['37abcb7424ce8df47ccb1d2dd9144b49'] := '67a45a39a72a35a38a61a11a51a60a13a22a31a25a75a30a74a43a69a50a6a26a16a49a77a68a59a64a17a56a18a1a10a54a44a62a53a80a5a23a48a32a29a79a24a70a28a58a71a3a52a42a55a9a14a36a73a34a2a27a57a0a21a41a33a37a76a8a40a65a7a20a12a19a47a4a78a15a63a66a46'; + deskeys.Values['874b83ba76a7e783d13abc2dabc08d76'] := '26a59a42a43a4a20a61a28a12a64a37a52a2a77a34a13a46a74a70a0a44a29a73a66a55a38a69a67a62a9a63a6a54a79a21a33a8a58a40a47a71a49a22a50a57a78a56a25a17a15a36a16a48a32a5a10a14a80a24a72a76a45a3a53a23a41a60a11a65a19a27a51a68a35a31a1a75a39a30a7a18'; + deskeys.Values['d320d2647d70c068b89853e1a269c609'] := '77a38a53a40a16a3a20a18a63a9a24a64a50a61a45a59a27a37a8a34a11a55a79a13a47a68a12a22a46a33a1a69a52a54a31a23a62a43a0a2a35a28a57a36a51a78a70a5a32a75a41a30a4a80a19a21a42a71a49a10a56a74a17a7a25a6a14a73a29a44a48a39a60a58a15a66a67a72a65a76a26'; RegisterModule; +finalization + deskeys.Free(); + end. From fe01504526f27ad3428375aa8530a9813d281720 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 31 Jan 2018 19:15:32 +0300 Subject: [PATCH 2042/2794] tumangaonline, fix all --- baseunits/modules/Tumangaonline.pas | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index e0c20ee90..1218b27a5 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -25,6 +25,8 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: In Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.FHTTP.Headers.Values['Referer'] := Module.RootURL; + MangaInfo.FHTTP.Headers.Values['Cache-Mode'] := 'no-cache'; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1&page=1') then begin Result := NO_ERROR; @@ -45,6 +47,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); + MangaInfo.FHTTP.Headers.Values['Referer'] := Module.RootURL; + MangaInfo.FHTTP.Headers.Values['Cache-Mode'] := 'no-cache'; if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then begin Result := NO_ERROR; @@ -76,6 +80,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; url := FillHost(Module.RootURL, AURL); mangaid := RegExprGetMatch('/\w+/(\d+)/\w+', url, 1); if mangaid = '' then Exit; + Headers.Values['Referer'] := url; + Headers.Values['Cache-Mode'] := 'no-cache'; if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then begin Result := NO_ERROR; @@ -91,21 +97,32 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; artists := XPathStringAll('json(*).artistas().artista'); authors := XPathStringAll('json(*).autores().autor'); purl := Module.RootURL + apiurlmangas + '/' + mangaid + '/capitulos?tomo=-1&page='; + Reset; + Headers.Values['Referer'] := url; + Headers.Values['Cache-Mode'] := 'no-cache'; if GET(purl + '1') then begin ParseHTML(Document); p := StrToIntDef(XPathString('json(*).last_page'), 1); for i := 1 to p do begin - if i > 1 then + if i > 1 then begin + Reset; + Headers.Values['Referer'] := url; + Headers.Values['Cache-Mode'] := 'no-cache'; if GET(purl + IntToStr(i)) then ParseHTML(Document) else Break; + end; for v in XPath('json(*).data()') do begin chapterLinks.Add(apiurlimagenes + XPathString('"?idManga="||tomo/idManga||"&idScanlation="||subidas/idScan||"&numeroCapitulo="||numCapitulo||"&visto=true"', v)); - chapterName.Add(XPathString('string-join((numCapitulo,nombre)," ")', v)); + s := v.getProperty('nombre').toString; + if s = 'null' then s := ''; + if s <> '' then s := ' ' + s; + s := v.getProperty('numCapitulo').toString + s; + chapterName.Add(s); end; end; InvertStrings([chapterLinks, chapterName]); @@ -129,6 +146,8 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String begin PageLinks.Clear; PageNumber := 0; + Headers.Values['Referer'] := Module.RootURL; + Headers.Values['Cache-Mode'] := 'no-cache'; if GET(FillHost(Module.RootURL, AURL)) then begin Result := True; From 533824a50d45fcd6291efdd0358bedd0c69c4344 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 31 Jan 2018 19:48:00 +0300 Subject: [PATCH 2043/2794] tapas, show locked chapters --- baseunits/modules/Tapas.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index df2964358..0326430f7 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -62,6 +62,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + locked: String; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -80,7 +81,9 @@ function GetInfo(const MangaInfo: TMangaInformation; for v in XPath('json(//script[contains(.,"var _data")]/concat(substring-before(substring-after(.,"episodeList :"),"]"),"]"))()') do begin chapterLinks.Add(Module.RootURL + '/episode/' + XPathString('./id', v)); - chapterName.Add(XPathString('./title', v)); + locked := ''; + if XPathString('./locked', v) = 'true' then locked := ' [locked]'; + chapterName.Add(XPathString('./title', v) + locked); end; finally Free; From 33bf283413fb4532b931e37e247b4bee8284b97b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 31 Jan 2018 20:27:33 +0300 Subject: [PATCH 2044/2794] funmanga, fix domain --- baseunits/modules/FunManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/FunManga.pas b/baseunits/modules/FunManga.pas index f28b785fc..e8a6fa564 100644 --- a/baseunits/modules/FunManga.pas +++ b/baseunits/modules/FunManga.pas @@ -117,7 +117,7 @@ procedure RegisterModule; with AddModule do begin Website := 'FunManga'; - RootURL := 'http://funmanga.com'; + RootURL := 'http://www.funmanga.com'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From 2fccb820b81a3eb84e4d6bc80f7e8283567dde85 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 31 Jan 2018 20:44:20 +0300 Subject: [PATCH 2045/2794] CF, fix POST requests --- baseunits/WebsiteModules.pas | 2 +- baseunits/modules/Cloudflare.pas | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 10b5c74ae..61ccaebca 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -297,7 +297,7 @@ procedure TModuleContainer.CheckCloudflareEnabled(const AHTTP: THTTPSendThread); function TModuleContainer.CloudflareHTTPRequest(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject): Boolean; begin - Result := Cloudflare.GETCF(AHTTP, URL, FCloudflareCF); + Result := Cloudflare.GETCF(AHTTP, Method, URL, FCloudflareCF); end; procedure TModuleContainer.SetTotalDirectory(AValue: Integer); diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index bdb6e6caa..3f7d7bf42 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -29,7 +29,7 @@ THTTPSendThreadHelper = class helper for THTTPSendThread function GETCF(const AURL: String; const CFProps: TCFProps): Boolean; end; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: TCFProps): Boolean; +function GETCF(const AHTTP: THTTPSendThread; const Method, AURL: String; const CFProps: TCFProps): Boolean; implementation @@ -168,7 +168,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Acf_clearance: Str AHTTP.RetryCount := maxretry; end; -function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: TCFProps): Boolean; +function GETCF(const AHTTP: THTTPSendThread; const Method, AURL: String; const CFProps: TCFProps): Boolean; begin Result := False; if AHTTP = nil then Exit; @@ -176,7 +176,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: CFProps.Reset; CFProps.AddCookiesTo(AHTTP.Cookies); AHTTP.AllowServerErrorResponse := True; - Result := AHTTP.HTTPRequest('GET', AURL); + Result := AHTTP.HTTPRequest(Method, AURL); if AntiBotActive(AHTTP) then begin if TryEnterCriticalsection(CFProps.CS) > 0 then try @@ -198,7 +198,7 @@ function GETCF(const AHTTP: THTTPSendThread; const AURL: String; const CFProps: LeaveCriticalsection(CFProps.CS); end; if not AHTTP.ThreadTerminated then - Result := AHTTP.HTTPRequest('GET', AURL); + Result := AHTTP.HTTPRequest(Method, AURL); end; end; @@ -237,7 +237,7 @@ procedure TCFProps.AddCookiesTo(const ACookies: TStringList); function THTTPSendThreadHelper.GETCF(const AURL: String; const CFProps: TCFProps): Boolean; begin - Result := Cloudflare.GETCF(Self, AURL, CFProps); + Result := Cloudflare.GETCF(Self, 'GET', AURL, CFProps); end; end. From c4ba4fa9b526d9944ba7dc82bd7c29599667213e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Feb 2018 08:08:28 +0300 Subject: [PATCH 2046/2794] comico, fix all --- baseunits/modules/Comico.pas | 100 ++++++++++++++--------------------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/baseunits/modules/Comico.pas b/baseunits/modules/Comico.pas index ac462b603..e4a5cef1c 100644 --- a/baseunits/modules/Comico.pas +++ b/baseunits/modules/Comico.pas @@ -11,7 +11,10 @@ interface implementation const + apiUrl = 'http://www.comico.jp/api'; + getChaptersApiUrl = apiUrl + '/getArticleList.nhn'; dirurl = '/official'; + dirpages: array[0..7] of String = ('mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', 'finish'); // Get Series Name function GetNameAndLink(const MangaInfo: TMangaInformation; @@ -23,22 +26,23 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; + s := Module.RootURL + dirurl + '/' + dirpages[Module.CurrentDirectoryIndex]; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//p[@itemprop="name"]/a') do + for v in XPath('//ul[contains(@class, "resizeTitleList")]/li/a') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + ANames.Add(XPathString('div/p[1]/text()', v)); end; finally Free; end; end; end; + // Get Chapter List function GetChapterPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const AURL: String; const Module: TModuleContainer): Integer; @@ -66,24 +70,8 @@ function GetChapterPageNumber(const MangaInfo: TMangaInformation; var Page: Inte function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - query: TXQueryEngineHTML; - p, i: Integer; - new_url: String; - - procedure getchapters; - var - v: IXQValue; - begin - for v in query.XPath('//a[@class="m-thumb-episode__inner"]') do begin - MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); - MangaInfo.mangaInfo.chapterName.Add(v.toString); - end; - end; - - procedure getp; - begin - p := StrToIntDef(SeparateRight(query.XPathString('//ul[@class="m-pager__list"]/li[last()]/a/@href'), '&page='), 1); - end; + s: String; + v: IXQValue; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -92,48 +80,47 @@ function GetInfo(const MangaInfo: TMangaInformation; url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); if GET(url) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create(Document); - with query do + with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//*[@class="m-title-hero m-title-hero__line o-mt-30"]@style/@background-image'); + coverLink := XPathString('//meta[@property="og:image"]/@content'); if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h1[@class="m-title-hero__title--manga"]'); - status := MangaInfoStatusIfPos( - XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), - 'Ongoing', - 'Complete'); - artists := XPathStringAll('//a[itemprop="author"]/a'); - authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); - summary := XPathString('//div[@class="m-title-hero__description"]'); - getchapters; - getp; - if p > 1 then begin - i := 2; - while (i <= p) and (Thread.IsTerminated = False) do begin - new_url := url + '&page=' + IntToStr(i); - if GET(new_url) then begin - ParseHTML(Document); - getchapters; - getp; - end; - Inc(i); - end; + if title = '' then begin + title := XPathString('//meta[@property="og:title"]/@content'); + title := Trim(SeparateLeft(title, '|')); end; - InvertStrings([chapterLinks, chapterName]); - Reset; - Headers.Values['Referer'] := ' ' + url; + status := XPathString('//div[contains(@class, "meta")]/p[1]'); + if status = '完結作品' then status := '0' + else status := '1'; + authors := XPathStringAll('//*[contains(@class, "author")]/a'); + summary := XPathString('//meta[@property="og:description"]/@content'); + genres := XPathStringAll('//div[contains(@class, "meta")]/p[2]/a'); finally - query.Free; + Free; end; + + s := RegExprGetMatch('titleNo\=\d+', url, 0); + Reset; + if POST(getChaptersApiUrl, s) then + with TXQueryEngineHTML.Create(Document) do + try + for v in XPath('json(*).result.list()') do begin + chapterLinks.Add(v.getProperty('articleDetailUrl').toString); + s := v.getProperty('freeFlg').toString; + if s = 'N' then s += ' [unavailable]' + else s := ''; + chapterName.Add(v.getProperty('subtitle').toString + s); + end; + finally + Free; + end; + Reset; + Headers.Values['Referer'] := ' ' + url; end; end; end; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - ViewerURL: String; begin Result := False; if DownloadThread = nil then Exit; @@ -144,13 +131,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then begin Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//img[@itemprop="primaryImageOfPage"]') do - PageLinks.Add(v.toNode.getAttribute('src')); - finally - Free; - end; + XPathStringAll('//img[contains(@class, "comic-image")]/@src', Document, PageLinks); end; end; end; @@ -178,6 +159,7 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnBeforeDownloadImage := @BeforeDownloadImage; + TotalDirectory := Length(dirpages); end; end; From 43443787931405a5c644f67370d6c3cb9f3ce8b4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Feb 2018 11:16:18 +0300 Subject: [PATCH 2047/2794] fix 'check version' button for high dpi screen --- mangadownloader/forms/frmMain.lfm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 32ddf419e..e37640f38 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4422,13 +4422,12 @@ object MainForm: TMainForm ClientHeight = 498 ClientWidth = 761 object btCheckLatestVersion: TBitBtn - AnchorSideTop.Control = pcAbout - AnchorSideTop.Side = asrBottom + AnchorSideTop.Side = asrTop Left = 0 Height = 40 - Top = 447 + Top = 452 Width = 208 - Anchors = [akTop, akLeft, akBottom] + Anchors = [akLeft, akBottom] BorderSpacing.Top = 3 Caption = 'Check for latest version' Glyph.Data = { From 12d694383fa8a0b646205eea09e5daf1ab1a65d8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Feb 2018 19:54:40 +0300 Subject: [PATCH 2048/2794] webtoons, fix cover image --- baseunits/modules/Webtoons.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index 2bcf9eac3..25dcac8d3 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -67,8 +67,7 @@ function GetInfo(const MangaInfo: TMangaInformation; query := TXQueryEngineHTML.Create(Document); with query do try - coverLink := XPathString('//div[@class="detail_header type_white"]/span[@class="thmb"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + coverLink := XPathString('//meta[@name="twitter:image"]/@content'); if title = '' then title := XPathString('//div[@class="info"]/h1/text()'); authors := XPathString('//div[@class="info"]/a/text()'); genres := XPathString('//div[@class="info"]/h2'); From e2aed0bbd34e8a7f49d4a2ae609f5139c9e483e8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 2 Feb 2018 11:56:02 +0300 Subject: [PATCH 2049/2794] add WorldThree fixes #901 --- baseunits/modules/FoOlSlide.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 0bdb5635b..5890ed5af 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -261,6 +261,7 @@ procedure RegisterModule; AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com'); AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org'); AddWebsiteModule('ChampionScans', 'http://reader.championscans.com'); + AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org'); //es-san AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); diff --git a/config/mangalist.ini b/config/mangalist.ini index 904c3d747..62d63f221 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans +English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MangaTube,MeinManga,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics From e6661797102d9e33f4668552764eedda7c04dd2a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 2 Feb 2018 12:27:45 +0300 Subject: [PATCH 2050/2794] fix 'emailprotected' in titles --- baseunits/modules/FoOlSlide.pas | 2 ++ baseunits/modules/Mangadex.pas | 2 ++ 2 files changed, 4 insertions(+) diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas index 5890ed5af..d4175737e 100644 --- a/baseunits/modules/FoOlSlide.pas +++ b/baseunits/modules/FoOlSlide.pas @@ -146,6 +146,8 @@ function GetInfo(const MangaInfo: TMangaInformation; if title = '' then if Module.Website = 'AtelierDuNoir' then title := XPathString('//div[@class="section-headline"]//h3') else title := XPathString('//h1[@class="title"]'); + if Pos('emailprotected', title) > 0 then + title := Trim(SeparateLeft(XPathString('//title'), '::')); authors := TrimLeftChar(XPathString( '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), [':', ' ']); artists := TrimLeftChar(XPathString( diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index f7a587fbf..049dc766f 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -38,6 +38,8 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; with TXQueryEngineHTML.Create(Document) do try if title = '' then title := XPathString('//h3[@class="panel-title"]/text()'); + if Pos('emailprotected', title) > 0 then + title := Trim(ReplaceString(XPathString('//title'), '(Manga) - MangaDex', '')); coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@alt="Manga image"]/@src')); authors := XPathString('//th[contains(., "Author")]/following-sibling::td/a'); artists := XPathString('//th[contains(., "Artist")]/following-sibling::td/a'); From 46585dfc6efed14398cb773655224fa3ebafe7b1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 2 Feb 2018 14:44:33 +0300 Subject: [PATCH 2051/2794] update changelog --- changelog.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/changelog.txt b/changelog.txt index 4e96267ed..6c6bcb3a1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,24 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.133.0 (xx-xx-2018) +[+] Added WorldThree [EN-SC] +[+] Added PsychoPlay [EN-SC] +[+] Added MangaZukiRaws [Raws] +[+] Added MangaDeep [EN] +[-] Removed MangaSpy +[-] Removed MangaIce +[*] MangaZuki: fixed all +[*] Comico: fixed all +[*] MangaGo: fixed all +[*] Tumangaonline: fixed all +[*] MangaAe: fixed download +[*] Cloudflare check added to all network events +[*] Update Russian localization (by TokcDK) +[*] Update Turkish localization (by Tmp341) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.132.0...0.9.133.0 + 0.9.132.0 (29-01-2018) [*] LHTranslation, fix chapter order [*] Mangadex, fix download From d9107605e25147d818853ec88552db1e0ffef572 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Feb 2018 10:37:26 +0300 Subject: [PATCH 2052/2794] fix js --- baseunits/JSUnpack.pas | 90 +++++++++++++++++++++++++++++++++++ baseunits/modules/MangaGo.pas | 65 +++++++++++++++++++++++-- 2 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 baseunits/JSUnpack.pas diff --git a/baseunits/JSUnpack.pas b/baseunits/JSUnpack.pas new file mode 100644 index 000000000..c62fafd54 --- /dev/null +++ b/baseunits/JSUnpack.pas @@ -0,0 +1,90 @@ +unit JSUnpack; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fgl, RegExpr, math; + +type + TStringMap = specialize TFPGMap<String, String>; + TJSUnpack36 = class + FDict: TStringMap; + function Encode36(code: Integer): String; + function GetIdentifier(c, a: Integer): String; + function Replace(ARegExpr : TRegExpr): String; + public + constructor Create; + destructor Destroy; override; + function Unpack(text: String; a, c: Integer; words: TStringArray): String; + end; + +implementation + +const + lookup36 = '0123456789abcdefghijklmnopqrstuvwxyz'; + +function TJSUnpack36.Encode36(code: Integer): String; +var + digit: Integer; + i: Integer = 0; +begin + Result := ''; + repeat + digit := (code div Trunc(power(36, i))) mod 36; + Result := Char(lookup36[digit + 1]) + Result; + code -= digit * Trunc(power(36, i)); + Inc(i); + until code <= 0; +end; + +constructor TJSUnpack36.Create; +begin + inherited; + FDict := TStringMap.Create; +end; + +destructor TJSUnpack36.Destroy; +begin + FDict.Free; + inherited; +end; + +function TJSUnpack36.GetIdentifier(c, a: Integer): String; +begin + if c < a then Result := '' + else Result := GetIdentifier(c div a, a); + c := c mod a; + if c > 35 then Result += Chr(Byte(c + 29)) + else Result += Encode36(c); +end; + +function TJSUnpack36.Replace(ARegExpr : TRegExpr): String; +var + s: String; +begin + Result := ARegExpr.Match[0]; + if FDict.TryGetData(ARegExpr.Match[0], s) and (s <> '') then + Result := s; +end; + +function TJSUnpack36.Unpack(text: String; a, c: Integer; words: TStringArray): String; +var + rg: TRegExpr; +begin + FDict.Clear; + rg := TRegExpr.Create('\b\w+\b'); + try + while c <> 0 do begin + Dec(c); + FDict.Add(GetIdentifier(c, a), words[c]); + end; + Result := rg.Replace(text, @Replace); + finally + rg.Free; + end; +end; + +end. + diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index a5c812c0f..a1acf488a 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, XQueryEngineHTML, httpsendthread, BaseCrypto, synautil, Graphics, - Interfaces, Math, RegExpr, strutils; + Interfaces, Math, RegExpr, strutils, JSUnpack; implementation @@ -79,7 +79,7 @@ function GetInfo(const MangaInfo: TMangaInformation; end; end; -function DecryptScript(script: String): String; +function ReplaceHex(script: String): String; var rg: TRegExpr; c: Char; @@ -103,12 +103,71 @@ function DecryptScript(script: String): String; end; end; +function GetScriptText(script: String): String; +begin + Result := SeparateRight(script, '('''); + Result := SeparateLeft(Result, ''','); +end; + +function GetA(script: String): Integer; +var s: String; +begin + s := SeparateRight(script, ''','); + s := SeparateLeft(s, ','); + Result := StrToIntDef(s, 1); +end; + +function GetC(script: String): Integer; +var s: String; +begin + s := SeparateRight(script, ''','); + s := SeparateRight(s, ','); + s := SeparateLeft(s, ','); + Result := StrToIntDef(s, 1); +end; + +function GetWords(script: String): String; +var s: String; +begin + s := SeparateRight(script, '('''); + s := SeparateRight(s, ',"'); + Result := SeparateLeft(s, '"'); +end; + +function GetSeparator(script: String): String; +var + s: String; +begin + s := ReplaceHex(script); + s := s.Substring(RPos('split', s)); + Result := GetBetween('(', ')', s); + Result := ReplaceString(Result, '''', ''); + Result := ReplaceString(Result, '"', ''); +end; + +function DecryptScript(script: String): String; +var + u: TJSUnpack36; + words, sep, text: String; +begin + Result := ''; + u := TJSUnpack36.Create; + try + text := ReplaceHex(GetScriptText(script)); + words := ReplaceHex(GetWords(script)); + sep := GetSeparator(script); + Result := u.Unpack(text, GetA(script), GetC(script), words.Split(sep)); + finally + u.Free; + end; +end; + function GetKey(script: String): String; var rg: TRegExpr; begin Result := ''; - rg := TRegExpr.Create('body\s+ready\s+(\S+)'); + rg := TRegExpr.Create('\=\s*["'']@(.+?)!["'']'); try if rg.Exec(script) then Result := '@' + rg.Match[1] + '!'; From a082bfa89461f20ba56056233b4214bb2cb4d7ab Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 4 Feb 2018 09:35:03 +0300 Subject: [PATCH 2053/2794] check whether the updated item should be removed from filtered rows --- baseunits/DBDataProcess.pas | 7 +++++-- baseunits/uGetMangaInfosThread.pas | 12 +++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 923bff411..8f51a0b4d 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -799,8 +799,11 @@ procedure TDBDataProcess.Refresh(RecheckDataCount: Boolean); begin if FConn.Connected then begin - if FQuery.Active then - FQuery.Refresh + if FQuery.Active then begin + if RecheckDataCount then + GetRecordCount; + FQuery.Refresh; + end else if Trim(FQuery.SQL.Text) <> '' then begin diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 178110f07..fad4c093f 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -178,14 +178,24 @@ procedure TGetMangaInfosThread.MainThreadShowCannotGetInfo; end; procedure TGetMangaInfosThread.MainThreadShowInfos; +var node: PVirtualNode; begin TransferMangaInfo(mangaInfo, FInfo.mangaInfo); with MainForm do begin if Assigned(FMangaListNode) and dataProcess.WebsiteLoaded(Website) then begin vtMangaList.BeginUpdate; - dataProcess.Refresh; + dataProcess.Refresh(dataProcess.Filtered); vtMangaList.ReinitNode(FMangaListNode, False); + if dataProcess.Filtered then begin + node := vtMangaList.GetNextVisible(FMangaListNode, False); + while Assigned(node) do begin + vtMangaList.ReinitNode(node, False); + node := vtMangaList.GetNextVisible(node, False); + end; + vtMangaList.RootNodeCount := dataProcess.RecordCount; + MainForm.UpdateVtMangaListFilterStatus; + end; vtMangaList.EndUpdate; end; ShowInformation(mangaInfo.title, mangaInfo.website, mangaInfo.link); From 9934ab5d8c765eeee2c109418c762cc73f8f43d6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 4 Feb 2018 10:11:18 +0300 Subject: [PATCH 2054/2794] fix pages count --- baseunits/modules/MangaGo.pas | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index a1acf488a..0f9f40134 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -185,7 +185,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var s, rurl, script: String; - i: Integer; + i, cnt: Integer; a: TStringArray; t: TStringList; begin @@ -199,9 +199,15 @@ function GetPageNumber(const DownloadThread: TDownloadThread; if not GET(rurl) then Exit; Result := True; - s := XPathString('//script[contains(.,"imgsrcs")]', Document); - if s = '' then Exit; + with TXQueryEngineHTML.Create(Document) do + try + cnt := XPathCount('//ul[@id="dropdown-menu-page"]/li/a'); + s := XPathString('//script[contains(.,"imgsrcs")]'); + finally + Free; + end; + if s = '' then Exit; if Pos('imgsrcs = new Array', s) <> 0 then s := GetString(s, '(', ')') else @@ -225,7 +231,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; a := s.Split([',']); - for i := 0 to Length(a) - 1 do + for i := 0 to cnt - 1 do PageLinks.Add(SeparateRight(a[i], '//')); end; end; From cd6c88eb43b4fc7d39c38325ef8b4ccb0eec091b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 5 Feb 2018 07:55:14 +0300 Subject: [PATCH 2055/2794] mangarock, fix update list fixes #907 --- baseunits/modules/MangaRock.pas | 51 ++++++++++++++------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas index 4a5381e20..018008ae5 100644 --- a/baseunits/modules/MangaRock.pas +++ b/baseunits/modules/MangaRock.pas @@ -11,12 +11,12 @@ interface implementation var - mangaList: TStringList; + mangaList: TStringList = nil; const ModuleApiUrl: String = 'https://api.mangarockhd.com'; DirRequest: String = '{"status":"all","genres":{},"rank":"all","order":"name"}'; - PerPage = 100; + PerPage = 500; function DecryptImage(const imageData: TStream): TMemoryStream; var @@ -144,41 +144,33 @@ function DownloadImage(const DownloadThread: TDownloadThread; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; var - index, i, ubound: Integer; - request: String; - query: TXQueryEngineHTML; - v: TXQProperty; - name, link: string; - obj: IXQValue; + offset, i, ubound: Integer; + request, name: String; begin Result := NET_PROBLEM; if (MangaInfo = nil) or (mangaList = nil) then Exit(UNKNOWN_ERROR); - index := StrToInt(AURL); - ubound := Min((index + 1) * PerPage - 1, mangaList.Count - 1); - request := '"' + mangaList[index * PerPage] + '"'; - for i := index * PerPage + 1 to ubound do - request := request + ',"' + mangaList[i] + '"'; - request := '[' + request + ']'; + offset := StrToInt(AURL) * PerPage; + ubound := Min(offset + PerPage - 1, mangaList.Count - 1); + request := '["' + mangaList[offset] + '"'; + for i := offset + 1 to ubound do + request += ',"' + mangaList[i] + '"'; + request += ']'; MangaInfo.FHTTP.MimeType := 'application/json'; if MangaInfo.FHTTP.POST(ModuleApiUrl + '/meta', request) then begin Result := NO_ERROR; - query := TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document); - for i := index * PerPage + 1 to ubound do - begin - name := query.XPathString('json(*).data("' + mangaList[i] + '").name'); - ANames.Add(name); - ALinks.Add(Module.RootURL + '/manga/' + mangaList[i]); - end; - query.Free; - end; - - if ubound = mangaList.Count - 1 then - begin - mangaList.Free; - mangaList := nil; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for i := offset to ubound do begin + name := XPathString('json(*).data("' + mangaList[i] + '").name'); + ANames.Add(name); + ALinks.Add(Module.RootURL + '/manga/' + mangaList[i]); + end; + finally + Free; + end; end; end; @@ -191,7 +183,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if MangaInfo.FHTTP.POST(ModuleApiUrl + '/query/web400/mrs_filter', DirRequest) then begin Result := NO_ERROR; - mangaList := TStringList.Create; + mangaList.Clear; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try XPathStringAll('json(*).data()', mangaList); @@ -219,6 +211,7 @@ procedure RegisterModule; end; initialization + mangaList := TStringList.Create; RegisterModule; finalization From f7470c322466f87df54d55614e0739fd88c3651a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 5 Feb 2018 21:01:44 +0800 Subject: [PATCH 2056/2794] websitemodules, add mising module on login event --- baseunits/WebsiteModules.pas | 6 ++++-- baseunits/modules/Batoto.pas | 8 ++++---- baseunits/modules/EHentai.pas | 24 ++++++++++++------------ baseunits/modules/Madokami.pas | 18 +++++++++--------- baseunits/modules/MangaLife.pas | 8 ++++---- 5 files changed, 33 insertions(+), 31 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 61ccaebca..458b6aff1 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -50,7 +50,7 @@ TModuleContainer = class; TOnAfterImageSaved = function(const AFilename: String; const Module: TModuleContainer): Boolean; - TOnLogin = function(const AHTTP: THTTPSendThread): Boolean; + TOnLogin = function(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; TModuleMethod = (MMGetDirectoryPageNumber, MMGetNameAndLink, MMGetInfo, MMTaskStart, MMGetPageNumber, MMGetImageURL, MMBeforeDownloadImage, @@ -81,6 +81,8 @@ TModuleContainer = class procedure AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; const AName: String; const ACaption: PString); public + Tag: Integer; + TagPtr: Pointer; Website: String; RootURL: String; MaxTaskLimit: Integer; @@ -692,7 +694,7 @@ function TWebsiteModules.Login(const AHTTP: THTTPSendThread; if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnLogin) then - Result := OnLogin(AHTTP); + Result := OnLogin(AHTTP, TModuleContainer(FModuleList[ModuleId])); end; function TWebsiteModules.Login(const AHTTP: THTTPSendThread; diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas index 49e614601..823ed5d9c 100644 --- a/baseunits/modules/Batoto.pas +++ b/baseunits/modules/Batoto.pas @@ -47,7 +47,7 @@ dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; 'CDN (default)' + LineEnding + 'CDN2 (testing)'; -function Login(const AHTTP: THTTPSendThread): Boolean; +function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; var query: TXQueryEngineHTML; loginform: THTMLForm; @@ -121,7 +121,7 @@ function Login(const AHTTP: THTTPSendThread): Boolean; end; end; -function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; var s: String; begin @@ -138,7 +138,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String): Boolean s := StreamToString(AHTTP.Document); Result := (Pos('class=''logged_in''', s) > 0) or (Pos('class="logged_in"', s) > 0); if not Result then begin - Result := Login(AHTTP); + Result := Login(AHTTP, Module); if Result then Result := AHTTP.GET(AURL) else @@ -212,7 +212,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo do begin website := modulename; url := FillHost(urlroot, AURL); - if GETWithLogin(MangaInfo.FHTTP, url) then begin + if GETWithLogin(MangaInfo.FHTTP, url, Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 414b7a3cd..84a32478f 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -40,7 +40,7 @@ implementation '2400x' + LineEnding + 'Original'; -function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; +function ExHentaiLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; var s: String; begin @@ -81,7 +81,7 @@ function ExHentaiLogin(const AHTTP: THTTPSendThread): Boolean; end; end; -function GETWithLogin(const AHTTP: THTTPSendThread; const AURL, AWebsite: String): Boolean; +function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; var ACookies: String; begin @@ -97,7 +97,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL, AWebsite: String AHTTP.Cookies.AddText(Account.Cookies[accname]); Result := AHTTP.GET(AURL); if Result and (AHTTP.ResultCode > 300) then begin - Result := ExHentaiLogin(AHTTP); + Result := ExHentaiLogin(AHTTP, Module); if Result then begin if ACookies <> '' then AHTTP.Cookies.AddText(ACookies); @@ -117,7 +117,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; Page := 1; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/?' + dirURL, Module.Website) then begin + if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/?' + dirURL, Module) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try @@ -141,7 +141,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if MangaInfo = nil then Exit(UNKNOWN_ERROR); if AURL = '0' then rurl := Module.RootURL + '/?' + dirURL else rurl := Module.RootURL + '/?page=' + IncStr(AURL) + '&' + dirURL; - if GETWithLogin(MangaInfo.FHTTP, rurl, Module.Website) then begin + if GETWithLogin(MangaInfo.FHTTP, rurl, Module) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create; try @@ -209,7 +209,7 @@ function GetInfo(const MangaInfo: TMangaInformation; website := Module.Website; url := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); url := AppendURLDelim(FillHost(Module.RootURL, url)); - if GETWithLogin(MangaInfo.FHTTP, url, Module.Website) then begin + if GETWithLogin(MangaInfo.FHTTP, url, Module) then begin Result := NO_ERROR; // if there is only 1 line, it's banned message! //if Source.Count = 1 then @@ -261,14 +261,14 @@ function GetPageNumber(const DownloadThread: TDownloadThread; PageNumber := 0; rurl := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); rurl := AppendURLDelim(FillHost(Module.RootURL, rurl)); - if GETWithLogin(DownloadThread.FHTTP, rurl, Module.Website) then begin + if GETWithLogin(DownloadThread.FHTTP, rurl, Module) then begin Result := True; query := TXQueryEngineHTML.Create; try getOK := True; //check content warning if Pos('Content Warning', query.XPathString('//div/h1')) > 0 then - getOK := GETWithLogin(DownloadThread.FHTTP, rurl + '?nw=session', Module.Website); + getOK := GETWithLogin(DownloadThread.FHTTP, rurl + '?nw=session', Module); if getOK then begin GetImageLink; //get page count @@ -278,7 +278,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; for i := 1 to p do begin if DownloadThread.IsTerminated then Break; - if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module.Website) then + if GETWithLogin(DownloadThread.FHTTP, rurl + '?p=' + IntToStr(i), Module) then GetImageLink; end; end; @@ -326,7 +326,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; if iurl = '' then iurl := query.XPathString('//a/img/@src[not(contains(.,"ehgt.org/"))]'); if iurl <> '' then - Result := GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website); + Result := GETWithLogin(DownloadThread.FHTTP, iurl, Module); if DownloadThread.IsTerminated then Break; if rcount >= reconnect then Break; if not Result then begin @@ -376,7 +376,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; nls := nls + '&nl=' + nl; iurl := iurl + nls; end; - if not GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then Break; + if not GETWithLogin(DownloadThread.FHTTP, iurl, Module) then Break; Inc(rcount); end; end; @@ -389,7 +389,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; iurl := FillHost(Module.RootURL, AURL); if settingsimagesize <= High(settingsimagesizestr) then DownloadThread.FHTTP.Cookies.Values['uconfig'] := settingsimagesizestr[settingsimagesize]; - if GETWithLogin(DownloadThread.FHTTP, iurl, Module.Website) then begin + if GETWithLogin(DownloadThread.FHTTP, iurl, Module) then begin query := TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document); try Result := DoDownloadImage; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 16f034050..fe84c460c 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -35,7 +35,7 @@ implementation madokamiulist: array of TStrings; accountexist: Boolean = False; -function Login(const AHTTP: THTTPSendThread): Boolean; +function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; begin Result := False; if Account.Enabled[modulename] = False then Exit; @@ -86,7 +86,7 @@ procedure SetAuth(const AHTTP: THTTPSendThread); end; end; -function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; +function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; SetAuth(AHTTP); @@ -95,7 +95,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String): Boolean; if ((AHTTP.ResultCode > 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ' Basic')) or (Pos('/login',AHTTP.Headers.Values['Location']) <> 0) then begin - if Login(AHTTP) then + if Login(AHTTP, Module) then Result := AHTTP.GET(AURL); end; end; @@ -137,7 +137,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NO_ERROR; if not accountexist then Exit; if workPtr < Length(madokamilist) then begin - if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/Manga/' + madokamilist[WorkPtr+1]) then begin + if GETWithLogin(MangaInfo.FHTTP, Module.RootURL + '/Manga/' + madokamilist[WorkPtr+1], Module) then begin XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, madokamiulist[WorkPtr]); Page := madokamiulist[WorkPtr].Count; end; @@ -173,7 +173,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; else u := Module.RootURL + madokamiotherlist[Module.CurrentDirectoryIndex-Length(madokamilist)]; if u = '' then Exit; - if GETWithLogin(MangaInfo.FHTTP, u) then begin + if GETWithLogin(MangaInfo.FHTTP, u, Module) then begin Result := NO_ERROR; if Module.CurrentDirectoryIndex < Length(madokamilist) then begin l1 := TStringList.Create; @@ -181,7 +181,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; XPathStringAll('//table[@id="index-table"]/tbody/tr/td[1]/a/@href', MangaInfo.FHTTP.Document, l1); for i := 0 to l1.Count - 1 do begin if MangaInfo.Thread.IsTerminated then Break; - if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l1[i])) then + if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, l1[i]), Module) then GetList; end; finally @@ -201,7 +201,7 @@ function GetInfo(const MangaInfo: TMangaInformation; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, AURL)) then begin + if GETWithLogin(MangaInfo.FHTTP, MaybeFillHost(Module.RootURL, AURL), Module) then begin Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try @@ -245,7 +245,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; - if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL)) then begin + if GETWithLogin(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then begin Result := True; with TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document) do try @@ -272,7 +272,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; begin Result := False; if DownloadThread = nil then Exit; - Result := GETWithLogin(DownloadThread.FHTTP, AURL); + Result := GETWithLogin(DownloadThread.FHTTP, AURL, Module); end; procedure RegisterModule; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 6004d18ab..015371c4c 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -22,7 +22,7 @@ implementation MangaTradersLockLogin: TRTLCriticalSection; MangaTradersOnLogin: Boolean; -function MangaTradersLogin(const AHTTP: THTTPSendThread): Boolean; +function MangaTradersLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; var s: String; begin @@ -66,7 +66,7 @@ function MangaTradersLogin(const AHTTP: THTTPSendThread): Boolean; end; end; -function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; var accstat: TAccountStatus; begin @@ -78,7 +78,7 @@ function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String): Bool AHTTP.Cookies.AddText(Account.Cookies[MMangaTraders.Website]) else if accstat in [asChecking, asUnknown] then - Result := MangaTradersLogin(AHTTP); + Result := MangaTradersLogin(AHTTP, Module); end; Result := AHTTP.GET(AURL); end; @@ -145,7 +145,7 @@ function GetInfo(const MangaInfo: TMangaInformation; begin url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); if Module = MMangaTraders then - r := GETMangaTraders(MangaInfo.FHTTP, url) + r := GETMangaTraders(MangaInfo.FHTTP, url, Module) else r := GET(url); if r then begin From f395dbfe2c10eb8fe10cdcd8b524f63d17209439 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 5 Feb 2018 21:20:36 +0800 Subject: [PATCH 2057/2794] websitemodules, locate from the last --- baseunits/WebsiteModules.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 458b6aff1..e37effa0d 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -399,7 +399,7 @@ destructor TWebsiteModules.Destroy; i: Integer; begin if FModuleList.Count > 0 then - for i := 0 to FModuleList.Count - 1 do + for i := FModuleList.Count - 1 downto 0 do TModuleContainer(FModuleList[i]).Free; FModuleList.Free; DoneCriticalsection(FCSModules); @@ -423,7 +423,7 @@ function TWebsiteModules.LocateModule(const AWebsite: String): Integer; begin Result := -1; if FModuleList.Count > 0 then - for i := 0 to FModuleList.Count - 1 do + for i := FModuleList.Count - 1 downto 0 do if SameText(TModuleContainer(FModuleList[i]).Website, AWebsite) then begin Result := i; @@ -437,7 +437,7 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; var i: Integer; begin - for i := 0 to FModuleList.Count - 1 do + for i := FModuleList.Count - 1 downto 0 do if Pos(s, LowerCase(TModuleContainer(FModuleList[i]).RootURL)) <> 0 then Exit(i); Result := -1; From 3a8c3653222680a018c4dfb44daf783d28d3c197 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 01:08:04 +0800 Subject: [PATCH 2058/2794] cleanup project options, move some to additional and override --- mangadownloader/md.lpi | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8264edb1b..45ac8a7dd 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -36,8 +36,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -80,8 +80,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -130,8 +130,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -178,7 +178,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;..\3rd\BESEN\src;..\3rd\internettools\data;..\3rd\internettools\internet;..\3rd\internettools\system;..\3rd\internettools\import\flre\src;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -210,19 +210,7 @@ -dDOWNLOADER -dSELFUPDATE -dDEBUGLEAKS --dMULTILOG --uUSE_BBFLRE_UNICODE --dUSE_SOROKINS_REGEX --dUSE_BBFULL_UNICODE"/> - <OtherDefines Count="7"> - <Define0 Value="MANGADOWNLOADER"/> - <Define1 Value="DOWNLOADER"/> - <Define2 Value="SELFUPDATE"/> - <Define3 Value="DEBUGLEAKS"/> - <Define4 Value="MULTILOG"/> - <Define5 Value="USE_SOROKINS_REGEX"/> - <Define6 Value="USE_BBFULL_UNICODE"/> - </OtherDefines> +-dMULTILOG"/> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> @@ -238,7 +226,7 @@ </Target> <SearchPaths> <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -437,8 +425,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 1822924d8061a052a7498ee02fb4abacf81d5393 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 01:13:58 +0800 Subject: [PATCH 2059/2794] add lua files --- baseunits/FMDOptions.pas | 4 +- baseunits/lua/LuaBase.pas | 84 +++ baseunits/lua/LuaBaseUnit.pas | 66 ++ baseunits/lua/LuaClass.pas | 576 +++++++++++++++++ baseunits/lua/LuaDownloadTask.pas | 30 + baseunits/lua/LuaHTTPSend.pas | 97 +++ baseunits/lua/LuaIXQValue.pas | 88 +++ baseunits/lua/LuaMangaInfo.pas | 41 ++ baseunits/lua/LuaRegex.pas | 40 ++ baseunits/lua/LuaStrings.pas | 175 ++++++ baseunits/lua/LuaStringsStorage.pas | 186 ++++++ baseunits/lua/LuaUtils.pas | 180 ++++++ baseunits/lua/LuaWebsiteModules.pas | 571 +++++++++++++++++ baseunits/lua/lua53.pas | 920 ++++++++++++++++++++++++++++ baseunits/lua/luaXQuery.pas | 156 +++++ mangadownloader/forms/frmMain.pas | 12 +- 16 files changed, 3224 insertions(+), 2 deletions(-) create mode 100644 baseunits/lua/LuaBase.pas create mode 100644 baseunits/lua/LuaBaseUnit.pas create mode 100644 baseunits/lua/LuaClass.pas create mode 100644 baseunits/lua/LuaDownloadTask.pas create mode 100644 baseunits/lua/LuaHTTPSend.pas create mode 100644 baseunits/lua/LuaIXQValue.pas create mode 100644 baseunits/lua/LuaMangaInfo.pas create mode 100644 baseunits/lua/LuaRegex.pas create mode 100644 baseunits/lua/LuaStrings.pas create mode 100644 baseunits/lua/LuaStringsStorage.pas create mode 100644 baseunits/lua/LuaUtils.pas create mode 100644 baseunits/lua/LuaWebsiteModules.pas create mode 100644 baseunits/lua/lua53.pas create mode 100644 baseunits/lua/luaXQuery.pas diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index b222f637f..7ae1f7f83 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -89,7 +89,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) DEFAULT_LOG_FILE, README_FILE, EXTRAS_FOLDER, - MANGAFOXTEMPLATE_FOLDER: String; + MANGAFOXTEMPLATE_FOLDER, + LUA_WEBSITEMODULE_FOLDER: String; // ini files revisionfile, @@ -279,6 +280,7 @@ procedure SetFMDdirectory(const ADir: String); FMD_DIRECTORY := CleanAndExpandDirectory(ADir); FMD_EXENAME := ExtractFileNameOnly(Application.ExeName); + LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules'; CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas new file mode 100644 index 000000000..fd785057c --- /dev/null +++ b/baseunits/lua/LuaBase.pas @@ -0,0 +1,84 @@ +unit LuaBase; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Lua53; + +procedure LuaBaseRegister(L: Plua_State); +procedure luaPushObject(L: Plua_State; Obj: TObject; Name: String; + AutoFree: Boolean = False); inline; + +function LuaDoFile(AFilename: String; AFuncName: String = ''): Plua_State; +function LuaNewBaseState: Plua_State; +function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; + +implementation + +uses + LuaClass, luaStrings, LuaBaseUnit, LuaRegex, MultiLog; + +function luabase_print(L: Plua_State): Integer; cdecl; +var + i: Integer; +begin + Result := 0; + for i := 1 to lua_gettop(L) do + Logger.Send(lua_tostring(L, i)); +end; + +procedure LuaBaseRegister(L: Plua_State); +begin + lua_register(L, 'print', @luabase_print); + luaRegexRegister(L); + luaBaseUnitRegister(L); + luaClassRegisterAll(L); +end; + +procedure luaPushObject(L: Plua_State; Obj: TObject; Name: String; AutoFree: Boolean); +begin + luaClassPushObject(L, Obj, Name, AutoFree); +end; + +function LuaDoFile(AFilename: String; AFuncName: String): Plua_State; +begin + Result := nil; + if not FileExists(AFilename) then + Exit; + Result := luaL_newstate; + try + luaL_openlibs(Result); + LuaBaseRegister(Result); + if luaL_dofile(Result, PChar(AFilename)) <> 0 then + raise Exception.Create(''); + LuaCallFunction(Result, AFuncName); + except + Logger.SendError('LuaDoFile.Error ' + lua_tostring(Result, -1)); + end; +end; + +function LuaNewBaseState: Plua_State; +begin + Result := nil; + Result := luaL_newstate; + try + luaL_openlibs(Result); + LuaBaseRegister(Result); + except + Logger.SendError(lua_tostring(Result, -1)); + end; +end; + +function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; +begin + Result := False; + if lua_getglobal(L, PChar(AFuncName)) = 0 then + raise Exception.Create('No function name ' + QuotedStr(AFuncName)); + if lua_pcall(L, 0, -1, 0) <> 0 then + raise Exception.Create(''); + Result := True; +end; + +end. diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas new file mode 100644 index 000000000..061cf64da --- /dev/null +++ b/baseunits/lua/LuaBaseUnit.pas @@ -0,0 +1,66 @@ +unit LuaBaseUnit; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, uBaseUnit; + +procedure luaBaseUnitRegister(L: Plua_State); + +implementation + +uses + LuaUtils, MultiLog; + +function lua_pos(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, Pos(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +function lua_trim(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, Trim(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_maybefillhost(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, MaybeFillHost(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +function lua_invertstrings(L: Plua_State): Integer; cdecl; +var + i: Integer; +begin + Result := 0; + for i := 1 to lua_gettop(L) do + InvertStrings(TStringList(PPointer(lua_touserdata(L, i))^)); +end; + +function lua_mangainfostatusifpos(L: Plua_State): Integer; cdecl; +begin + case lua_gettop(L) of + 3: lua_pushstring(L, MangaInfoStatusIfPos(lua_tostring(L, 1), + lua_tostring(L, 2), lua_tostring(L, 3))); + 2: lua_pushstring(L, MangaInfoStatusIfPos(lua_tostring(L, 1), lua_tostring(L, 2))); + 1: lua_pushstring(L, MangaInfoStatusIfPos(lua_tostring(L, 1))); + else + Exit(0); + end; + Result := 1; +end; + +procedure luaBaseUnitRegister(L: Plua_State); +begin + luaPushFunctionGlobal(L, 'Pos', @lua_pos); + luaPushFunctionGlobal(L, 'Trim', @lua_trim); + luaPushFunctionGlobal(L, 'MaybeFillHost', @lua_maybefillhost); + luaPushFunctionGlobal(L, 'InvertStrings', @lua_invertstrings); + luaPushFunctionGlobal(L, 'MangaInfoStatusIfPos', @lua_mangainfostatusifpos); +end; + +end. diff --git a/baseunits/lua/LuaClass.pas b/baseunits/lua/LuaClass.pas new file mode 100644 index 000000000..e8a2dfe04 --- /dev/null +++ b/baseunits/lua/LuaClass.pas @@ -0,0 +1,576 @@ +unit LuaClass; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +type + PObject = ^TObject; + + luaL_Reg_prop = packed record + name: PAnsiChar; + funcget: lua_CFunction; + funcset: lua_CFunction; + end; + PluaL_Reg_prop = ^luaL_Reg_prop; + + TluaClassAddMetaTable = procedure(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + TLuaClassRegisterLib = procedure(L: Plua_State); + +procedure luaClassNewLib(L: Plua_State; n: PAnsiChar; lr: PluaL_Reg); + +procedure luaClassRegisterAll(L: Plua_State); + +procedure luaClassRegister(C: TClass; AddMetaTable: TluaClassAddMetaTable; + AddLib: TLuaClassRegisterLib = nil); + +function luaNewUserData(L: Plua_State; Obj: Pointer): Integer; +procedure luaClassNewUserData(L: Plua_State; Obj: Pointer; + var MetaTable, UserData: Integer; AutoFree: Boolean = False); + +function luaClassGetClosure(L: Plua_State): Pointer; +function luaClassGetObject(L: Plua_State): Pointer; inline; + +procedure luaClassPushUserData(L: Plua_State; Obj: Pointer; Name: String; + AutoFree: Boolean; AddMetaTable: TluaClassAddMetaTable); +procedure luaClassPushObject(L: Plua_State; Obj: TObject; Name: String; + AutoFree: Boolean = False; AddMetaTable: TluaClassAddMetaTable = nil); + +procedure luaClassAddFunction(L: Plua_State; MetaTable, UserData: Integer; + Name: PAnsiChar; Func: lua_CFunction); overload; inline; +procedure luaClassAddFunction(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg); overload; +procedure luaClassAddProperty(L: Plua_State; MetaTable, UserData: Integer; + Name: PAnsiChar; FuncGet, FuncSet: lua_CFunction); overload; +procedure luaClassAddProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg_prop); overload; +procedure luaClassAddArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + Name: PAnsiChar; FuncGet, FuncSet: lua_CFunction); overload; +procedure luaClassAddArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg_prop); overload; +procedure luaClassAddDefaultArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncGet, FuncSet: lua_CFunction); overload; +procedure luaClassAddDefaultArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg_prop); overload; inline; +procedure luaClassAddStringProperty(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer); overload; +procedure luaClassAddIntegerProperty(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer); overload; +procedure luaClassAddBooleanProperty(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer); overload; +procedure luaClassAddObject(L: Plua_State; Obj: TObject; MetaTable: Integer; + Name: String; AddMetaTable: TluaClassAddMetaTable = nil); + +implementation + +uses LuaUtils; + +type + + { TluaClassList } + + TluaClassList = class + FClassList, FAddMetaTableList, FClassLibList: TFPList; + public + constructor Create; + destructor Destroy; override; + procedure Add(C: TClass; AddMetaTable: TluaClassAddMetaTable; + AddLib: TLuaClassRegisterLib); + function FindAddMetaTable(C: TClass): TluaClassAddMetaTable; + property Libs: TFPList read FClassLibList; + end; + +var + classlist: TluaClassList; + +function __index(L: Plua_State): Integer; cdecl; +begin + Result := 0; + if lua_gettop(L) < 2 then + Exit; + + lua_getmetatable(L, 1); // 1 should be userdata + lua_pushstring(L, AnsiLowerCase(lua_tostring(L, 2))); // 2 should be the key + lua_rawget(L, -2); // get metatable[key] + + if lua_istable(L, -1) then + begin + lua_getfield(L, -1, '__get'); + if lua_iscfunction(L, -1) then + begin + lua_pushvalue(L, 1); // push userdata + lua_call(L, 1, 1); + end; + end + else + if lua_isnil(L, -1) then + begin + lua_pop(L, 1); + lua_getfield(L, -1, '__defaultget'); // default get[] from metatable + if lua_iscfunction(L, -1) then + begin + lua_pushvalue(L, 1); // userdata + lua_pushvalue(L, 2); // key + lua_call(L, 2, 1); + end + else + if lua_isnil(L, -1) then // no default get + lua_pop(L, 1); + end; + Result := 1; +end; + +function __newindex(L: Plua_State): Integer; cdecl; +begin + if lua_gettop(L) < 2 then + Exit(0); + + lua_getmetatable(L, 1); + lua_pushstring(L, AnsiLowerCase(lua_tostring(L, 2))); + lua_rawget(L, -2); + + if lua_istable(L, -1) then + begin + lua_getfield(L, -1, '__set'); + if lua_iscfunction(L, -1) then + begin + lua_pushvalue(L, 1); // userdata + lua_pushvalue(L, 3); // data + lua_call(L, 2, 0); + end; + end + else + if lua_isnil(L, -1) then + begin + lua_pop(L, 1); + lua_getfield(L, -1, '__defaultset'); // default get from metatable + if lua_iscfunction(L, -1) then + begin + lua_pushvalue(L, 1); // userdata + lua_pushvalue(L, 2); // key + lua_pushvalue(L, 3); // data + lua_call(L, 3, 1); + end + else + if lua_isnil(L, -1) then // no default get + lua_pop(L, 1); + end; + Result := 1; +end; + +function __indexarray(L: Plua_State): Integer; cdecl; +begin + Result := 1; + + if lua_tostring(L, 2) = '__get' then + begin + lua_pushvalue(L, 1); + Exit; + end; + + lua_pushvalue(L, lua_upvalueindex(2)); // cfunc + lua_pushvalue(L, lua_upvalueindex(1)); // userdata + lua_pushvalue(L, 2); + lua_call(L, 2, 1); +end; + +function __newindexarray(L: Plua_State): Integer; cdecl; +begin + Result := 1; + + if lua_tostring(L, 2) = '__set' then + begin + lua_pushvalue(L, 1); + Exit; + end; + lua_pushvalue(L, lua_upvalueindex(2)); // cfunc + lua_pushvalue(L, lua_upvalueindex(1)); // userdata + lua_pushvalue(L, 2); + lua_pushvalue(L, 3); + lua_call(L, 3, 0); +end; + +function __gc(L: Plua_State): Integer; cdecl; +var + autodestroy: Boolean; +begin + Result := 0; + if not lua_isuserdata(L, 1) then + Exit; + + autodestroy := False; + lua_getmetatable(L, 1); + lua_getfield(L, -1, '__autodestroy'); + if lua_isboolean(L, -1) then + autodestroy := lua_toboolean(L, -1); + if not autodestroy then + Exit; + + lua_getfield(L, -2, 'destroy'); + if lua_iscfunction(L, -1) then + begin + lua_pushvalue(L, 1); + lua_call(L, 1, 0); + end + else + try + PObject(lua_touserdata(L, 1))^.Free; + except + end; +end; + +function __self(L: Plua_State): Integer; cdecl; +begin + lua_pushlightuserdata(L, PPointer(luaClassGetObject(L))^); + Result := 1; +end; + +function firstUpcase(s: String): String; +begin + Result := s; + if Result <> '' then + Result[1] := AnsiUpperCase(Result[1])[1]; +end; + +procedure luaClassNewLib(L: Plua_State; n: PAnsiChar; lr: PluaL_Reg); +var + t: Integer; +begin + lua_newtable(L); + t := lua_gettop(L); + while lr^.name <> nil do + begin + luaAddCFunctionToTable(L, t, PAnsiChar(LowerCase(lr^.name)), lr^.func); + luaAddCFunctionToTable(L, t, PAnsiChar(firstUpcase(lr^.name)), lr^.func); + Inc(lr); + end; + if n <> '' then + lua_setglobal(L, n); +end; + +procedure luaClassRegisterAll(L: Plua_State); +var + i: Integer; +begin + for i := 0 to classlist.Libs.Count - 1 do + if classlist.Libs[i] <> nil then + TLuaClassRegisterLib(classlist.Libs[i])(L); +end; + +procedure luaClassRegister(C: TClass; AddMetaTable: TluaClassAddMetaTable; + AddLib: TLuaClassRegisterLib); +begin + classlist.Add(C, AddMetaTable, AddLib); +end; + +function luaNewUserData(L: Plua_State; Obj: Pointer): Integer; +begin + PPointer(lua_newuserdata(L, SizeOf(PPointer)))^ := Obj; + Result := lua_gettop(L); +end; + +procedure luaClassNewUserData(L: Plua_State; Obj: Pointer; + var MetaTable, UserData: Integer; AutoFree: Boolean); +begin + UserData := luaNewUserData(L, Obj); + lua_newtable(L); + MetaTable := lua_gettop(L); + luaClassAddFunction(L, MetaTable, UserData, 'self', @__self); + luaAddCFunctionToTable(L, MetaTable, '__index', @__index); + luaAddCFunctionToTable(L, MetaTable, '__newindex', @__newindex); + luaAddCFunctionToTable(L, MetaTable, '__gc', @__gc); + luaAddBooleanToTable(L, MetaTable, '__autodestroy', AutoFree); +end; + +function luaClassGetClosure(L: Plua_State): Pointer; +begin + Result := nil; + if lua_isuserdata(L, lua_upvalueindex(1)) then + Result := lua_touserdata(L, lua_upvalueindex(1)) + else + if lua_gettop(L) > 0 then + if lua_isuserdata(L, 1) then + begin + Result := lua_touserdata(L, 1); + lua_remove(L, 1); + end; +end; + +function luaClassGetObject(L: Plua_State): Pointer; +begin + Result := PPointer(luaClassGetClosure(L))^; +end; + +procedure luaClassPushUserData(L: Plua_State; Obj: Pointer; Name: String; + AutoFree: Boolean; AddMetaTable: TluaClassAddMetaTable); +var + m, u: Integer; +begin + if Obj = nil then + Exit; + luaClassNewUserData(L, Obj, m, u, AutoFree); + AddMetaTable(L, Obj, m, u); + lua_setmetatable(L, u); + if Name <> '' then + lua_setglobal(L, PAnsiChar(Name)); +end; + +procedure luaClassPushObject(L: Plua_State; Obj: TObject; Name: String; + AutoFree: Boolean; AddMetaTable: TluaClassAddMetaTable); +begin + if Obj = nil then + Exit; + if AddMetaTable = nil then + AddMetaTable := classlist.FindAddMetaTable(Obj.ClassType); + if AddMetaTable = nil then + Exit; + luaClassPushUserData(L, Obj, Name, AutoFree, AddMetaTable); +end; + +procedure luaClassAddFunction(L: Plua_State; MetaTable, UserData: Integer; + Name: PAnsiChar; Func: lua_CFunction); +begin + luaAddCClosureToTable(L, MetaTable, UserData, PAnsiChar(AnsiLowerCase(Name)), Func); +end; + +procedure luaClassAddFunction(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg); +var + p: PluaL_Reg; +begin + p := FuncArr; + while p^.name <> nil do + begin + luaClassAddFunction(L, MetaTable, UserData, p^.name, p^.func); + Inc(p); + end; +end; + +procedure luaClassAddProperty(L: Plua_State; MetaTable, UserData: Integer; + Name: PAnsiChar; FuncGet, FuncSet: lua_CFunction); +var + t: Integer; +begin + lua_pushstring(L, PAnsiChar(LowerCase(Name))); + lua_newtable(L); + t := lua_gettop(L); + + if FuncGet <> nil then + luaAddCClosureToTable(L, t, UserData, '__get', FuncGet); + if FuncSet <> nil then + luaAddCClosureToTable(L, t, UserData, '__set', FuncSet); + + lua_rawset(L, MetaTable); +end; + +procedure luaClassAddProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg_prop); +var + p: PluaL_Reg_prop; +begin + p := FuncArr; + while p^.name <> nil do + begin + luaClassAddProperty(L, MetaTable, UserData, p^.name, p^.funcget, p^.funcset); + Inc(p); + end; +end; + +procedure luaClassAddArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + Name: PAnsiChar; FuncGet, FuncSet: lua_CFunction); +var + t, m: Integer; +begin + lua_pushstring(L, PAnsiChar(AnsiLowerCase(Name))); + lua_newtable(L); + t := lua_gettop(L); + + lua_newtable(L); + m := lua_gettop(L); + + lua_pushstring(L, '__index'); + lua_pushvalue(L, UserData); + lua_pushcfunction(L, FuncGet); + lua_pushcclosure(L, @__indexarray, 2); + lua_rawset(L, m); + + if FuncSet <> nil then + begin + lua_pushstring(L, '__newindex'); + lua_pushvalue(L, UserData); + lua_pushcfunction(L, FuncSet); + lua_pushcclosure(L, @__newindexarray, 2); + lua_rawset(L, m); + end; + + lua_setmetatable(L, t); + lua_rawset(L, MetaTable); +end; + +procedure luaClassAddArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg_prop); +var + p: PluaL_Reg_prop; +begin + p := FuncArr; + while p^.name <> nil do + begin + luaClassAddArrayProperty(L, MetaTable, UserData, p^.name, p^.funcget, p^.funcset); + Inc(p); + end; +end; + +procedure luaClassAddDefaultArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncGet, FuncSet: lua_CFunction); +begin + if FuncGet <> nil then + luaAddCClosureToTable(L, MetaTable, UserData, '__defaultget', FuncGet); + if FuncSet <> nil then + luaAddCClosureToTable(L, MetaTable, UserData, '__defaultset', FuncSet); +end; + +procedure luaClassAddDefaultArrayProperty(L: Plua_State; MetaTable, UserData: Integer; + FuncArr: PluaL_Reg_prop); +begin + luaClassAddDefaultArrayProperty(L, MetaTable, UserData, FuncArr^.funcget, + FuncArr^.funcset); +end; + +function luaclass_string_get(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, String(luaClassGetClosure(L)^)); + Result := 1; +end; + +function luaclass_string_set(L: Plua_State): Integer; cdecl; +begin + Result := 0; + String(luaClassGetClosure(L)^) := lua_tostring(L, -1); +end; + +function luaclass_int_get(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, Integer(luaClassGetClosure(L)^)); + Result := 1; +end; + +function luaclass_int_set(L: Plua_State): Integer; cdecl; +begin + Result := 0; + Integer(luaClassGetClosure(L)^) := lua_tointeger(L, -1); +end; + +function luaclass_bool_get(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, Boolean(luaClassGetClosure(L)^)); + Result := 1; +end; + +function luaclass_bool_set(L: Plua_State): Integer; cdecl; +begin + Result := 0; + Boolean(luaClassGetClosure(L)^) := lua_toboolean(L, -1); +end; + +procedure luaClassAddVariable(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer; FuncGet, FuncSet: lua_CFunction); +var + t: Integer; +begin + lua_pushstring(L, PAnsiChar(LowerCase(Name))); + lua_newtable(L); + t := lua_gettop(L); + + luaAddCClosureToTable(L, t, P, '__get', FuncGet); + luaAddCClosureToTable(L, t, P, '__set', FuncSet); + + lua_rawset(L, MetaTable); +end; + +procedure luaClassAddStringProperty(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer); +begin + luaClassAddVariable(L, MetaTable, Name, P, @luaclass_string_get, @luaclass_string_set); +end; + +procedure luaClassAddIntegerProperty(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer); +begin + luaClassAddVariable(L, MetaTable, Name, P, @luaclass_int_get, @luaclass_int_set); +end; + +procedure luaClassAddBooleanProperty(L: Plua_State; MetaTable: Integer; + Name: PAnsiChar; P: Pointer); +begin + luaClassAddVariable(L, MetaTable, Name, P, @luaclass_bool_get, @luaclass_bool_set); +end; + +procedure luaClassAddObject(L: Plua_State; Obj: TObject; MetaTable: Integer; + Name: String; AddMetaTable: TluaClassAddMetaTable); +var + m, u: Integer; +begin + if AddMetaTable = nil then + AddMetaTable := classlist.FindAddMetaTable(Obj.ClassType); + if AddMetaTable = nil then + Exit; + lua_pushstring(L, PAnsiChar(AnsiLowerCase(Name))); + luaClassNewUserData(L, Obj, m, u, False); + AddMetaTable(L, Obj, m, u); + lua_setmetatable(L, u); + lua_rawset(L, MetaTable); +end; + +{ TluaClassList } + +constructor TluaClassList.Create; +begin + FClassList := TFPList.Create; + FAddMetaTableList := TFPList.Create; + FClassLibList := TFPList.Create; +end; + +destructor TluaClassList.Destroy; +begin + FClassList.Free; + FAddMetaTableList.Free; + FClassLibList.Free; + inherited Destroy; +end; + +procedure TluaClassList.Add(C: TClass; AddMetaTable: TluaClassAddMetaTable; + AddLib: TLuaClassRegisterLib); +begin + FClassList.Add(C); + FAddMetaTableList.Add(AddMetaTable); + FClassLibList.Add(AddLib); +end; + +function TluaClassList.FindAddMetaTable(C: TClass): TluaClassAddMetaTable; +var + i, p: Integer; +begin + Result := nil; + p := FClassList.IndexOf(C); + if p = -1 then + for i := 0 to FClassList.Count - 1 do + if C.InheritsFrom(TClass(FClassList[i])) then + begin + p := i; + Break; + end; + if p <> -1 then + Result := TluaClassAddMetaTable(FAddMetaTableList[p]); +end; + +initialization + classlist := TluaClassList.Create; + +finalization + classlist.Free; + +end. diff --git a/baseunits/lua/LuaDownloadTask.pas b/baseunits/lua/LuaDownloadTask.pas new file mode 100644 index 000000000..82409af1b --- /dev/null +++ b/baseunits/lua/LuaDownloadTask.pas @@ -0,0 +1,30 @@ +unit LuaDownloadTask; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +implementation + +uses + LuaClass, uDownloadsManager; + +procedure luaDownloadTaskMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + with TTaskContainer(Obj) do + begin + luaClassAddObject(L, ChapterName, MetaTable, 'chapterName'); + luaClassAddObject(L, ChapterLinks, MetaTable, 'chapterLinks'); + luaClassAddObject(L, PageContainerLinks, MetaTable, 'chapterLinks'); + end; +end; + +initialization + luaClassRegister(TTaskContainer, @luaDownloadTaskMetaTable); + +end. + diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas new file mode 100644 index 000000000..0d98c9687 --- /dev/null +++ b/baseunits/lua/LuaHTTPSend.pas @@ -0,0 +1,97 @@ +unit LuaHTTPSend; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +implementation + +uses + uBaseUnit, httpsendthread, LuaClass; + +type + TUserData = THTTPSendThread; + +function http_get(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, TUserData(luaClassGetObject(L)).GET(lua_tostring(L, 1))); + Result := 1; +end; + +function http_post(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, TUserData(luaClassGetObject(L)).POST(lua_tostring(L, 1), + lua_tostring(L, 2))); + Result := 1; +end; + +function http_head(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, TUserData(luaClassGetObject(L)).head(lua_tostring(L, 1))); + Result := 1; +end; + +function http_xhr(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, TUserData(luaClassGetObject(L)).XHR(lua_tostring(L, 1))); + Result := 1; +end; + +function http_reset(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Reset; +end; + +function http_getcookies(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).GetCookies; +end; + +function http_threadterminated(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, TUserData(luaClassGetObject(L)).ThreadTerminated); + Result := 1; +end; + +function http_document(L: Plua_State): Integer; cdecl; +begin + lua_pushlightuserdata(L, TUserData(luaClassGetObject(L)).Document); + Result := 1; +end; + +const + methods: packed array [0..6] of luaL_Reg = ( + (name: 'GET'; func: @http_get), + (name: 'POST'; func: @http_post), + (name: 'HEAD'; func: @http_head), + (name: 'XHR'; func: @http_xhr), + (name: 'Reset'; func: @http_reset), + (name: 'GetCookies'; func: @http_getcookies), + (name: nil; func: nil) + ); + props: packed array[0..2] of luaL_Reg_prop = ( + (name: 'Document'; funcget: @http_document; funcset: nil), + (name: 'ThreadTerminated'; funcget: @http_threadterminated; funcset: nil), + (name: nil; funcget: nil; funcset: nil) + ); + +procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + with TUserData(Obj) do + begin + luaClassAddFunction(L, MetaTable, UserData, methods); + luaClassAddProperty(L, MetaTable, UserData, props); + luaClassAddObject(L, Headers, MetaTable, 'Headers'); + luaClassAddObject(L, Cookies, MetaTable, 'Cookies'); + end; +end; + +initialization + luaClassRegister(THTTPSendThread, @luaHTTPSendThreadAddMetaTable); + +end. diff --git a/baseunits/lua/LuaIXQValue.pas b/baseunits/lua/LuaIXQValue.pas new file mode 100644 index 000000000..486393fb4 --- /dev/null +++ b/baseunits/lua/LuaIXQValue.pas @@ -0,0 +1,88 @@ +unit LuaIXQValue; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, xquery; + +type + { TLuaIXQValue } + + TLuaIXQValue = class + public + FIXQValue: IXQValue; + constructor Create(const AIX: IXQValue); + end; + +procedure luaIXQValuePush(L: Plua_State; Obj: TLuaIXQValue); inline; + +implementation + +uses + LuaClass; + +type + TUserData = TLuaIXQValue; + +{ TLuaIXQValue } + +constructor TLuaIXQValue.Create(const AIX: IXQValue); +begin + FIXQValue := AIX; +end; + +function ixqvalue_tostring(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).FIXQValue.toString); + Result := 1; +end; + +function ixqvalue_getattribute(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).FIXQValue.toNode.getAttribute( + lua_tostring(L, 1))); + Result := 1; +end; + +function ixqvalue_count(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).FIXQValue.Count); + Result := 1; +end; + +function ixqvalue_get(L: Plua_State): Integer; cdecl; +begin + luaIXQValuePush(L, TUserData.Create(TUserData(luaClassGetObject(L)).FIXQValue.get(lua_tointeger(L, 1)))); + Result := 1; +end; + +const + methods: packed array [0..2] of luaL_Reg = ( + (name: 'GetAttribute'; func: @ixqvalue_getattribute), + (name: 'Get'; func: @ixqvalue_get), + (name: nil; func: nil) + ); + props: packed array [0..2] of luaL_Reg_prop = ( + (name: 'Count'; funcget: @ixqvalue_count; funcset: nil), + (name: 'ToString'; funcget: @ixqvalue_tostring; funcset: nil), + (name: nil; funcget: nil; funcset: nil) + ); + +procedure luaIXQValueAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + luaClassAddFunction(L, MetaTable, UserData, methods); + luaClassAddProperty(L, MetaTable, UserData, props); +end; + +procedure luaIXQValuePush(L: Plua_State; Obj: TLuaIXQValue); +begin + luaClassPushObject(L, Obj, '', True, @luaIXQValueAddMetaTable); +end; + +initialization + luaClassRegister(TLuaIXQValue, @luaIXQValueAddMetaTable); + +end. diff --git a/baseunits/lua/LuaMangaInfo.pas b/baseunits/lua/LuaMangaInfo.pas new file mode 100644 index 000000000..ca25d2cc2 --- /dev/null +++ b/baseunits/lua/LuaMangaInfo.pas @@ -0,0 +1,41 @@ +unit LuaMangaInfo; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +implementation + +uses + uBaseUnit, LuaClass; + +procedure luaMangaInfoAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + with TMangaInfo(Obj) do + begin + luaClassAddStringProperty(L, MetaTable, 'url', @url); + luaClassAddStringProperty(L, MetaTable, 'title', @title); + luaClassAddStringProperty(L, MetaTable, 'link', @link); + luaClassAddStringProperty(L, MetaTable, 'website', @website); + luaClassAddStringProperty(L, MetaTable, 'coverLink', @coverLink); + luaClassAddStringProperty(L, MetaTable, 'authors', @authors); + luaClassAddStringProperty(L, MetaTable, 'artists', @artists); + luaClassAddStringProperty(L, MetaTable, 'genres', @genres); + luaClassAddStringProperty(L, MetaTable, 'status', @status); + luaClassAddStringProperty(L, MetaTable, 'summary', @summary); + luaClassAddStringProperty(L, MetaTable, 'summary', @summary); + luaClassAddIntegerProperty(L, MetaTable, 'numChapter', @numChapter); + luaClassAddObject(L, chapterName, MetaTable, 'chapterNames'); + luaClassAddObject(L, chapterLinks, MetaTable, 'chapterLinks'); + end; +end; + +initialization + luaClassRegister(TMangaInfo, @luaMangaInfoAddMetaTable); + +end. + diff --git a/baseunits/lua/LuaRegex.pas b/baseunits/lua/LuaRegex.pas new file mode 100644 index 000000000..7295a8cdb --- /dev/null +++ b/baseunits/lua/LuaRegex.pas @@ -0,0 +1,40 @@ +unit LuaRegex; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, RegExpr; + +procedure luaRegexRegister(L: Plua_State); + +implementation + +function re_exec(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, ExecRegExpr(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +function re_replace(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, ReplaceRegExpr(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), True)); + Result := 1; +end; + +const + methods: packed array [0..2] of luaL_Reg = ( + (name: 'Exec'; func: @re_exec), + (name: 'Replace'; func: @re_replace), + (name: nil; func: nil) + ); + +procedure luaRegexRegister(L: Plua_State); +begin + lua_newtable(L); + luaL_setfuncs(L, @methods, 0); + lua_setglobal(L, 'RegExpr'); +end; + +end. diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas new file mode 100644 index 000000000..b0cc01377 --- /dev/null +++ b/baseunits/lua/LuaStrings.pas @@ -0,0 +1,175 @@ +unit luaStrings; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +procedure luaStringsPush(L: Plua_State; Obj: TStrings; Name: String = ''; + AutoFree: Boolean = False); inline; + +implementation + +uses LuaClass; + +type + TUserData = TStrings; + +function strings_create(L: Plua_State): Integer; cdecl; +begin + luaStringsPush(L, TStringList.Create, '', True); + Result := 1; +end; + +function strings_loadfromfile(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).LoadFromFile(lua_tostring(L, 1)); +end; + +function strings_settext(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Text := lua_tostring(L, 1); +end; + +function strings_gettext(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).Text); + Result := 1; +end; + +function strings_setcommatext(L: Plua_State): Integer; cdecl; +begin + TUserData(luaClassGetObject(L)).CommaText := lua_tostring(L, 1); + Result := 0; +end; + +function strings_getcommatext(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).CommaText); + Result := 1; +end; + +function strings_add(L: Plua_State): Integer; cdecl; +begin + TUserData(luaClassGetObject(L)).Add(lua_tostring(L, 1)); + Result := 0; +end; + +function strings_addtext(L: Plua_State): Integer; cdecl; +begin + TUserData(luaClassGetObject(L)).AddText(lua_tostring(L, 1)); + Result := 0; +end; + +function strings_get(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, PAnsiChar( + TUserData(luaClassGetObject(L)).Strings[lua_tointeger(L, 1)])); + Result := 1; +end; + +function strings_set(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Strings[lua_tointeger(L, 1)] := lua_tostring(L, 2); +end; + +function strings_namevalueseparatorget(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, PAnsiChar( + String(TUserData(luaClassGetObject(L)).NameValueSeparator))); + Result := 1; +end; + +function strings_namevalueseparatorset(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).NameValueSeparator := String(lua_tostring(L, 1))[1]; +end; + +function strings_valuesget(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, PAnsiChar( + TUserData(luaClassGetObject(L)).Values[lua_tostring(L, 1)])); + Result := 1; +end; + +function strings_valuesset(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Values[lua_tostring(L, 1)] := lua_tostring(L, 2); +end; + +function strings_getcount(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).Count); + Result := 1; +end; + +function strings_sort(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TStringList(TUserData(luaClassGetObject(L))).Sort; +end; + +const + constructs: packed array [0..4] of luaL_Reg = ( + (name: 'New'; func: @strings_create), + (name: 'Create'; func: @strings_create), + (name: 'new'; func: @strings_create), + (name: 'create'; func: @strings_create), + (name: nil; func: nil) + ); + methods: packed array [0..9] of luaL_Reg = ( + (name: 'LoadFromFile'; func: @strings_loadfromfile), + (name: 'SetText'; func: @strings_settext), + (name: 'GetText'; func: @strings_gettext), + (name: 'Add'; func: @strings_add), + (name: 'AddText'; func: @strings_addtext), + (name: 'Get'; func: @strings_get), + (name: 'Set'; func: @strings_set), + (name: 'GetCount'; func: @strings_getcount), + (name: 'Sort'; func: @strings_sort), + (name: nil; func: nil) + ); + props: packed array[0..4] of lual_Reg_prop = ( + (name: 'Text'; funcget: @strings_gettext; funcset: @strings_settext), + (name: 'CommaText'; funcget: @strings_getcommatext; funcset: @strings_setcommatext), + (name: 'Count'; funcget: @strings_getcount; funcset: nil), + (name: 'NameValueSeparator'; funcget: @strings_namevalueseparatorget; + funcset: @strings_namevalueseparatorset), + (name: nil; funcget: nil; funcset: nil) + ); + arrprops: packed array[0..2] of lual_Reg_prop = ( + (name: 'Strings'; funcget: @strings_get; funcset: @strings_set), + (name: 'Values'; funcget: @strings_valuesget; funcset: @strings_valuesset), + (name: nil; funcget: nil; funcset: nil) + ); + +procedure luaStringsAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + luaClassAddFunction(L, MetaTable, UserData, methods); + luaClassAddProperty(L, MetaTable, UserData, props); + luaClassAddArrayProperty(L, MetaTable, UserData, arrprops); + luaClassAddDefaultArrayProperty(L, MetaTable, UserData, @strings_get, @strings_set); +end; + +procedure luaStringsPush(L: Plua_State; Obj: TStrings; Name: String; AutoFree: Boolean); +begin + luaClassPushObject(L, Obj, Name, AutoFree, @luaStringsAddMetaTable); +end; + +procedure luaStringsRegister(L: Plua_State); +begin + luaClassNewLib(L, PAnsiChar(String(TUserData.ClassName)), constructs); +end; + +initialization + luaClassRegister(TUserData, @luaStringsAddMetaTable, @luaStringsRegister); + +end. diff --git a/baseunits/lua/LuaStringsStorage.pas b/baseunits/lua/LuaStringsStorage.pas new file mode 100644 index 000000000..858179d1e --- /dev/null +++ b/baseunits/lua/LuaStringsStorage.pas @@ -0,0 +1,186 @@ +unit LuaStringsStorage; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +type + + { TStringsStorage } + + TStringsStorage = class + private + FStrings: TStringList; + FCS: TRTLCriticalSection; + function GetValues(const AName: String): String; + procedure SetValues(const AName: String; AValue: String); + function GetText: String; + procedure SetText(AValue: String); + public + Tag: Integer; + Enable: Boolean; + Status: String; + constructor Create; + destructor Destroy; override; + procedure Remove(const AName: String); + property Values[const AName: String]: String read GetValues write SetValues; default; + property Text: String read GetText write SetText; + end; + +procedure luaStringsStoragePush(L: Plua_State; Obj: TStringsStorage; + Name: PAnsiChar = nil; AutoFree: Boolean = False); inline; + +implementation + +uses LuaClass; + +{ TStringsStorage } + +function TStringsStorage.GetValues(const AName: String): String; +begin + Result := FStrings.Values[AName]; +end; + +function TStringsStorage.GetText: String; +begin + Result := FStrings.Text; +end; + +procedure TStringsStorage.SetText(AValue: String); +begin + FStrings.Text := AValue; +end; + +procedure TStringsStorage.SetValues(const AName: String; AValue: String); +begin + EnterCriticalsection(FCS); + try + FStrings.Values[AName] := AValue; + finally + LeaveCriticalsection(FCS); + end; +end; + +constructor TStringsStorage.Create; +begin + FStrings := TStringList.Create; + InitCriticalSection(FCS); + Tag := 0; + Enable := True; + Status := 'my status of ' + Self.ClassName; +end; + +destructor TStringsStorage.Destroy; +begin + FStrings.Free; + DoneCriticalsection(FCS); + inherited Destroy; +end; + +procedure TStringsStorage.Remove(const AName: String); +var + i: Integer; +begin + i := FStrings.IndexOfName(AName); + if (i < 0) or (i >= FStrings.Count) then + Exit; + EnterCriticalsection(FCS); + try + FStrings.Delete(i); + finally + LeaveCriticalsection(FCS); + end; +end; + +type + TUserData = TStringsStorage; + +function strings_create(L: Plua_State): Integer; cdecl; +begin + luaStringsStoragePush(L, TStringsStorage.Create, nil, True); + Result := 1; +end; + +function strings_destroy(L: Plua_State): Integer; cdecl; +begin + TUserData(luaClassGetObject(L)).Free; + Result := 0; +end; + +function strings_getvalue(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).GetValues(lua_tostring(L, 1))); + Result := 1; +end; + +function strings_setvalue(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).SetValues(lua_tostring(L, 1), lua_tostring(L, 2)); +end; + +function strings_remove(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Remove(lua_tostring(L, 1)); +end; + +function strings_gettext(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).Text); + Result := 1; +end; + +function strings_settext(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Text := lua_tostring(L, 1); +end; + +const + constructs: packed array [0..4] of luaL_Reg = ( + (name: 'New'; func: @strings_create), + (name: 'Create'; func: @strings_Create), + (name: 'new'; func: @strings_create), + (name: 'create'; func: @strings_create), + (name: nil; func: nil) + ); + methods: packed array [0..3] of luaL_Reg = ( + (name: 'Remove'; func: @strings_remove), + (name: 'Free'; func: @strings_destroy), + (name: 'Destroy'; func: @strings_destroy), + (name: nil; func: nil) + ); + +procedure luaStringsStorageAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + luaClassAddFunction(L, MetaTable, UserData, methods); + luaClassAddDefaultArrayProperty(L, MetaTable, UserData, @strings_getvalue, + @strings_setvalue); + luaClassAddProperty(L, MetaTable, UserData, 'Text', @strings_gettext, + @strings_settext); + luaClassAddIntegerProperty(L, MetaTable, 'Tag', @TUserData(Obj).Tag); + luaClassAddBooleanProperty(L, MetaTable, 'Enable', @TUserData(Obj).Enable); + luaClassAddStringProperty(L, MetaTable, 'Status', @TUserData(Obj).Status); +end; + +procedure luaStringsStoragePush(L: Plua_State; Obj: TStringsStorage; + Name: PAnsiChar; AutoFree: Boolean); +begin + luaClassPushObject(L, Obj, Name, AutoFree, @luaStringsStorageAddMetaTable); +end; + +procedure luaStringsStorageRegister(L: Plua_State); +begin + luaClassNewLib(L, PAnsiChar(String(TUserData.ClassName)), constructs); +end; + +initialization + luaClassRegister(TUserData, @luaStringsStorageAddMetaTable, + @luaStringsStorageRegister); + +end. diff --git a/baseunits/lua/LuaUtils.pas b/baseunits/lua/LuaUtils.pas new file mode 100644 index 000000000..083100a43 --- /dev/null +++ b/baseunits/lua/LuaUtils.pas @@ -0,0 +1,180 @@ +unit LuaUtils; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +procedure luaAddCFunctionToTable(L: Plua_State; Table: Integer; + Name: PAnsiChar; Func: lua_CFunction); +procedure luaAddCClosureToTable(L: Plua_State; Table, Value: Integer; + Name: PAnsiChar; Func: lua_CFunction); overload; +procedure luaAddCClosureToTable(L: Plua_State; Table: Integer; + Value: Pointer; Name: PAnsiChar; Func: lua_CFunction); overload; +procedure luaAddStringToTable(L: Plua_State; Table: Integer; Name, Value: PAnsiChar); +procedure luaAddIntegerToTable(L: Plua_State; Table: Integer; + Name: PAnsiChar; Value: lua_Integer); +procedure luaAddBooleanToTable(L: Plua_State; Table: Integer; + Name: PAnsiChar; Value: Boolean); + +procedure luaPushFunctionGlobal(L: Plua_State; Name: PAnsiChar; Func: lua_CFunction); + +procedure luaPushStringGlobal(L: Plua_State; Name: PAnsiChar; S: String); +procedure luaPushIntegerGlobal(L: Plua_State; Name: PAnsiChar; I: Integer); +procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); + +function LuaToString(L: Plua_State; Idx: Integer): String; +function LuaStackToString(L: Plua_State): String; + +procedure luaL_newlib(L: Plua_State; n: PAnsiChar; lr: PluaL_Reg); overload; inline; + +// deprecated since 5.2 +procedure luaL_openlib(L: Plua_State; n: PansiChar; lr: PluaL_Reg; + {%H-}nup: Integer); inline; +procedure luaL_register(L: Plua_State; n: PAnsiChar; lr: PluaL_Reg); inline; + +implementation + +procedure luaAddCFunctionToTable(L: Plua_State; Table: Integer; + Name: PAnsiChar; Func: lua_CFunction); +begin + lua_pushstring(L, Name); + lua_pushcfunction(L, Func); + lua_rawset(L, Table); +end; + +procedure luaAddCClosureToTable(L: Plua_State; Table, Value: Integer; + Name: PAnsiChar; Func: lua_CFunction); +begin + lua_pushstring(L, Name); + lua_pushvalue(L, Value); + lua_pushcclosure(L, Func, 1); + lua_rawset(L, Table); +end; + +procedure luaAddCClosureToTable(L: Plua_State; Table: Integer; + Value: Pointer; Name: PAnsiChar; Func: lua_CFunction); +begin + lua_pushstring(L, Name); + lua_pushlightuserdata(L, Value); + lua_pushcclosure(L, Func, 1); + lua_rawset(L, Table); +end; + +procedure luaAddStringToTable(L: Plua_State; Table: Integer; Name, Value: PAnsiChar); +begin + lua_pushstring(L, Name); + lua_pushstring(L, Value); + lua_rawset(L, Table); +end; + +procedure luaAddIntegerToTable(L: Plua_State; Table: Integer; + Name: PAnsiChar; Value: lua_Integer); +begin + lua_pushstring(L, Name); + lua_pushinteger(L, Value); + lua_rawset(L, Table); +end; + +procedure luaAddBooleanToTable(L: Plua_State; Table: Integer; + Name: PAnsiChar; Value: Boolean); +begin + lua_pushstring(L, Name); + lua_pushboolean(L, Value); + lua_rawset(L, Table); +end; + +procedure luaPushFunctionGlobal(L: Plua_State; Name: PAnsiChar; Func: lua_CFunction); +begin + lua_pushcfunction(L, Func); + lua_setglobal(L, Name); +end; + +procedure luaPushStringGlobal(L: Plua_State; Name: PAnsiChar; S: String); +begin + lua_pushstring(L, S); + lua_setglobal(L, Name); +end; + +procedure luaPushIntegerGlobal(L: Plua_State; Name: PAnsiChar; I: Integer); +begin + lua_pushinteger(L, I); + lua_setglobal(L, Name); +end; + +procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); +begin + lua_pushboolean(L, B); + lua_setglobal(L, Name); +end; + +function LuaToString(L: Plua_State; Idx: Integer): String; +begin + if lua_isuserdata(L, Idx) then + Result := 'userdata: ' + hexStr(lua_touserdata(L, Idx)) + else + if lua_isstring(L, Idx) then + Result := 'string: ' + lua_tostring(L, Idx) + else + if lua_isinteger(L, Idx) then + Result := 'integer: ' + IntToStr(lua_tointeger(L, Idx)) + else + if lua_iscfunction(L, Idx) then + Result := 'cfunc: ' + hexStr(lua_topointer(L, Idx)) + else + if lua_isfunction(L, Idx) then + Result := 'func: ' + hexStr(lua_topointer(L, Idx)) + else + if lua_isnoneornil(L, Idx) then + Result := 'nil' + else + if lua_isboolean(L, Idx) then + Result := 'boolean: ' + BoolToStr(lua_toboolean(L, Idx), True) + else + if lua_isnumber(L, Idx) then + Result := 'number: ' + FloatToStr(lua_tonumber(L, Idx)) + else + if lua_istable(L, Idx) then + Result := 'table: ' + hexStr(lua_topointer(L, Idx)) + else + if lua_islightuserdata(L, Idx) then + Result := 'ligthuserdata: ' + hexStr(lua_topointer(L, Idx)) + else + Result := 'unknown: ' + hexStr(lua_topointer(L, Idx)); +end; + +function LuaStackToString(L: Plua_State): String; +var + i: Integer; +begin + Result := ''; + i := lua_gettop(L); + if i = 0 then + Exit; + for i := 1 to i do + Result := Result + IntToStr(i) + '=' + LuaToString(L, i) + LineEnding; + SetLength(Result, Length(Result) - Length(LineEnding)); +end; + +procedure luaL_newlib(L: Plua_State; n: PAnsiChar; lr: PluaL_Reg); +begin + luaL_newlib(L, lr); + if n <> '' then + lua_setglobal(L, n); +end; + +procedure luaL_openlib(L: Plua_State; n: PansiChar; lr: PluaL_Reg; nup: Integer); +begin + luaL_setfuncs(L, lr, 0); + if n <> '' then + lua_setglobal(L, n); +end; + +procedure luaL_register(L: Plua_State; n: PAnsiChar; lr: PluaL_Reg); +begin + luaL_openlib(L, n, lr, 0); +end; + +end. diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas new file mode 100644 index 000000000..a56b0d57d --- /dev/null +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -0,0 +1,571 @@ +unit LuaWebsiteModules; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, LuaStringsStorage, WebsiteModules, uData, + uDownloadsManager, xquery, httpsendthread; + +type + + { TLuaWebsiteModuleContainer } + + TLuaWebsiteModuleContainer = class + private + FModule: TModuleContainer; + public + OnBeforeUpdateList: String; + OnAfterUpdateList: String; + OnGetDirectoryPageNumber: String; + OnGetNameAndLink: String; + OnGetInfo: String; + OnTaskStart: String; + OnGetPageNumber: String; + OnGetImageURL: String; + OnBeforeDownloadImage: String; + OnDownloadImage: String; + OnSaveImage: String; + OnAfterImageSaved: String; + OnLogin: String; + Storage: TStringsStorage; + Filename: String; + LastUpdated: String; + constructor Create; + destructor Destroy; override; + procedure luaPushMe(L: Plua_State); + end; + +procedure ScanLuaWebsiteModulesFile; + +implementation + +uses + FMDOptions, FileUtil, MultiLog, LuaClass, LuaBase, LuaMangaInfo, LuaHTTPSend, + LuaXQuery, LuaUtils, LuaDownloadTask; + +var + luawebsitemodulelist: TFPList; + +function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnBeforeUpdateList) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoAfterUpdateList(const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnAfterUpdateList) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoGetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +var + l: Plua_State; +begin + Result := NO_ERROR; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushIntegerGlobal(l, 'page', Page); + luaPushIntegerGlobal(l, 'workptr', WorkPtr); + luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); + luaPushObject(l, MangaInfo.FHTTP, 'http'); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnGetDirectoryPageNumber) then + begin + Result := lua_tointeger(l, -1); + if lua_getglobal(l, 'page') <> 0 then + Page := lua_tointeger(l, -1); + end; + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoGetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + l: Plua_State; +begin + Result := NO_ERROR; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); + luaPushObject(l, MangaInfo.FHTTP, 'http'); + luaPushStringGlobal(L, 'url', AURL); + luaPushObject(l, ANames, 'names'); + luaPushObject(l, ANames, 'links'); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnGetNameAndLink) then + Result := lua_tointeger(L, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoGetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + l: Plua_State; +begin + Result := NO_ERROR; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushStringGlobal(l, 'url', AURL); + luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); + luaPushObject(l, MangaInfo.FHTTP, 'http'); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + LuaCallFunction(l, OnGetInfo); + except + Logger.SendError(lua_tostring(L, -1)); + end; + lua_close(l); + end; +end; + +function DoTaskStart(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, Task, 'task'); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnTaskStart) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoGetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushStringGlobal(l, 'url', AURL); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnGetPageNumber) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoGetImageURL(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushStringGlobal(l, 'url', AURL); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnGetImageURL) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoBeforeDownloadImage(const DownloadThread: TDownloadThread; + var AURL: String; const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushStringGlobal(l, 'url', AURL); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnBeforeDownloadImage) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoDownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushStringGlobal(l, 'url', AURL); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnDownloadImage) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoSaveImage(const AHTTP: THTTPSendThread; const APath, AName: String; + const Module: TModuleContainer): String; +var + l: Plua_State; +begin + Result := ''; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, AHTTP, 'http'); + luaPushStringGlobal(l, 'path', APath); + luaPushStringGlobal(l, 'name', AName); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnSaveImage) then + Result := lua_tostring(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoAfterImageSaved(const AFilename: String; const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushStringGlobal(l, 'filename', AFilename); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnAfterImageSaved) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function DoLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; +var + l: Plua_State; +begin + Result := False; + with TLuaWebsiteModuleContainer(Module.TagPtr) do + begin + l := LuaNewBaseState; + try + luaPushMe(l); + luaPushObject(l, AHTTP, 'http'); + + if luaL_dofile(l, PChar(Filename)) <> 0 then + raise Exception.Create(''); + if LuaCallFunction(l, OnTaskStart) then + Result := lua_toboolean(l, -1); + except + Logger.SendError(lua_tostring(l, -1)); + end; + lua_close(l); + end; +end; + +function LoadLuaToWebsiteModules(AFilename: String): Boolean; +var + l: Plua_State; + m: Pointer; + i: Integer; + + procedure setcurrent; + begin + with TLuaWebsiteModuleContainer(m) do + begin + Filename := AFilename; + if OnBeforeUpdateList <> '' then + FModule.OnBeforeUpdateList := @DoBeforeUpdateList; + if OnAfterUpdateList <> '' then + FModule.OnAfterUpdateList := @DoAfterUpdateList; + if OnGetDirectoryPageNumber <> '' then + FModule.OnGetDirectoryPageNumber := @DoGetDirectoryPageNumber; + if OnGetNameAndLink <> '' then + FModule.OnGetNameAndLink := @DoGetNameAndLink; + if OnGetInfo <> '' then + FModule.OnGetInfo := @DoGetInfo; + if OnTaskStart <> '' then + FModule.OnTaskStart := @DoTaskStart; + if OnGetPageNumber <> '' then + FModule.OnGetPageNumber := @DoGetPageNumber; + if OnGetImageURL <> '' then + FModule.OnGetImageURL := @DoGetImageURL; + if OnBeforeDownloadImage <> '' then + FModule.OnBeforeDownloadImage := @DoBeforeDownloadImage; + if OnDownloadImage <> '' then + FModule.OnDownloadImage := @DoDownloadImage; + if OnSaveImage <> '' then + FModule.OnSaveImage := @DoSaveImage; + if OnAfterImageSaved <> '' then + FModule.OnAfterImageSaved := @DoAfterImageSaved; + if OnLogin <> '' then + FModule.OnLogin := @DoLogin; + + Logger.EnterMethod('lualoadmodule' + IntToStr(i), ' '); + Logger.Send('File', Filename); + Logger.Send('Website', FModule.Website); + Logger.Send('RootURL', FModule.RootURL); + Logger.Send('LastUpdated', LastUpdated); + Logger.ExitMethod('lualoadmodule' + IntToStr(i), ' '); + end; + end; + +begin + Result := False; + Logger.Send('Load lua website module', AFilename); + try + l := LuaDoFile(AFilename, 'Init'); + except + Logger.SendError('Error load lua website module'); + end; + if Assigned(l) then + begin + logger.Send('Read returned data from lua website module'); + Result := True; + try + for i := 1 to lua_gettop(L) do + if lua_isuserdata(L, i) then + begin + m := lua_touserdata(L, i); + if TObject(m) is TLuaWebsiteModuleContainer then + setcurrent + else + begin + m := PPointer(m)^; + if TObject(m) is TLuaWebsiteModuleContainer then + setcurrent; + end; + end + else + Logger.SendWarning('Lua module doesn''t return any data!'); + finally + lua_close(l); + end; + end; +end; + +procedure ScanLuaWebsiteModulesFile; +var + d: String; + f: TStringList; + i: Integer; +begin + d := LUA_WEBSITEMODULE_FOLDER; + try + f := FindAllFiles(d, '*.lua', False, faAnyFile); + if f.Count > 0 then + for i := 0 to f.Count - 1 do + LoadLuaToWebsiteModules(f[i]); + finally + f.Free; + end; +end; + + +{ TLuaWebsiteModuleContainer } + +constructor TLuaWebsiteModuleContainer.Create; +begin + luawebsitemodulelist.Add(Self); + FModule := Modules.AddModule; + FModule.TagPtr := Self; + Storage := TStringsStorage.Create; +end; + +destructor TLuaWebsiteModuleContainer.Destroy; +begin + Storage.Free; + inherited Destroy; +end; + +procedure TLuaWebsiteModuleContainer.luaPushMe(L: Plua_State); +begin + luaPushObject(L, Self, 'module'); + luaPushIntegerGlobal(L, 'no_error', NO_ERROR); + luaPushIntegerGlobal(L, 'net_problem', NET_PROBLEM); + luaPushIntegerGlobal(L, 'information_not_found', INFORMATION_NOT_FOUND); +end; + +procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + with TLuaWebsiteModuleContainer(Obj) do + begin + luaClassAddStringProperty(L, MetaTable, 'Website', @FModule.Website); + luaClassAddStringProperty(L, MetaTable, 'RootURL', @FModule.RootURL); + luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @FModule.MaxTaskLimit); + luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', + @FModule.MaxConnectionLimit); + luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', + @FModule.ActiveTaskCount); + luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', + @FModule.ActiveConnectionCount); + luaClassAddBooleanProperty(L, MetaTable, 'AccountSupport', @FModule.AccountSupport); + luaClassAddBooleanProperty(L, MetaTable, 'SortedList', @FModule.SortedList); + luaClassAddBooleanProperty(L, MetaTable, 'InformationAvailable', + @FModule.InformationAvailable); + luaClassAddBooleanProperty(L, MetaTable, 'FavoriteAvailable', + @FModule.FavoriteAvailable); + luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', + @FModule.DynamicPageLink); + luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', + @FModule.CloudflareEnabled); + luaClassAddStringProperty(L, MetaTable, 'OnBeforeUpdateList', @OnBeforeUpdateList); + luaClassAddStringProperty(L, MetaTable, 'OnAfterUpdateList', @OnAfterUpdateList); + luaClassAddStringProperty(L, MetaTable, 'OnGetDirectoryPageNumber', + @OnGetDirectoryPageNumber); + luaClassAddStringProperty(L, MetaTable, 'OnGetNameAndLink', @OnGetNameAndLink); + luaClassAddStringProperty(L, MetaTable, 'OnGetInfo', @OnGetInfo); + luaClassAddStringProperty(L, MetaTable, 'OnTaskStart', @OnTaskStart); + luaClassAddStringProperty(L, MetaTable, 'OnGetPageNumber', @OnGetPageNumber); + luaClassAddStringProperty(L, MetaTable, 'OnGetImageURL', @OnGetImageURL); + luaClassAddStringProperty(L, MetaTable, 'OnBeforeDownloadImage', + @OnBeforeDownloadImage); + luaClassAddStringProperty(L, MetaTable, 'OnDownloadImage', @OnDownloadImage); + luaClassAddStringProperty(L, MetaTable, 'OnSaveImage', @OnSaveImage); + luaClassAddStringProperty(L, MetaTable, 'OnAfterImageSaved', @OnAfterImageSaved); + luaClassAddStringProperty(L, MetaTable, 'OnLogin', @OnLogin); + luaClassAddStringProperty(L, MetaTable, 'LastUpdated', @LastUpdated); + luaClassAddObject(L, Storage, MetaTable, 'Storage'); + end; +end; + +function _create(L: Plua_State): Integer; cdecl; +begin + luaClassPushObject(L, TLuaWebsiteModuleContainer.Create, '', False, + @luaWebsiteModuleAddMetaTable); + Result := 1; +end; + +procedure luaWebsiteModuleRegister(L: Plua_State); +begin + lua_register(L, 'NewModule', @_create); +end; + +procedure dofinalization; +var + i: Integer; +begin + for i := 0 to luawebsitemodulelist.Count - 1 do + TObject(luawebsitemodulelist[i]).Free; + luawebsitemodulelist.Free; +end; + +initialization + luawebsitemodulelist := TFPList.Create; + luaClassRegister(TLuaWebsiteModuleContainer, @luaWebsiteModuleAddMetaTable, + @luaWebsiteModuleRegister); + +finalization + dofinalization; + +end. diff --git a/baseunits/lua/lua53.pas b/baseunits/lua/lua53.pas new file mode 100644 index 000000000..417ec796a --- /dev/null +++ b/baseunits/lua/lua53.pas @@ -0,0 +1,920 @@ +(****************************************************************************** + * * + * File: lua53.pas * + * * + * Authors: TeCGraf (C headers + actual Lua libraries) * + * Lavergne Thomas (original translation to Pascal) * + * Bram Kuijvenhoven (update to Lua 5.1.1 for FreePascal) * + * Egor Skriptunoff (update to Lua 5.2.1 for FreePascal) * + * Vladimir Klimov (Delphi compatibility) * + * Malcome@Japan (update to Lua 5.3.0 for FreePascal) * + * * + * Description: Basic Lua library * + * Lua auxiliary library * + * Standard Lua libraries * + * This is 3-in-1 replacement for FPC modules lua.pas,lauxlib.pas,lualib.pas * + * * + ******************************************************************************) + +(* +** $Id: lua.h,v 1.325 2014/12/26 17:24:27 roberto Exp $ +** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $ +** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ +** Lua - A Scripting Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*) +(* +** Translated to pascal by Lavergne Thomas +** Notes : +** - Pointers type was prefixed with 'P' +** - lua_upvalueindex constant was transformed to function +** - Some compatibility function was isolated because with it you must have +** lualib. +** - LUA_VERSION was suffixed by '_' for avoiding name collision. +** Bug reports : +** - thomas.lavergne@laposte.net +** In french or in english +*) +(* +** Updated to Lua 5.1.1 by Bram Kuijvenhoven (bram at kuijvenhoven dot net), +** Hexis BV (http://www.hexis.nl), the Netherlands +** Notes: +** - Only tested with FPC (FreePascal Compiler) +** - Using LuaBinaries styled DLL/SO names, which include version names +** - LUA_YIELD was suffixed by '_' for avoiding name collision +*) +(* +** Updated to Lua 5.2.1 by Egor Skriptunoff +** Notes: +** - Only tested with FPC (FreePascal Compiler) +** - Functions dealing with luaL_Reg were overloaded to accept pointer +** or open array parameter. In any case, do not forget to terminate +** your array with "sentinel". +** - All floating-point exceptions were forcibly disabled in Windows +** to overcome well-known bug +** Bug reports: +** - egor.skriptunoff at gmail.com +** In russian or in english +*) +(* +** Delphi compatibility by Vladimir Klimov +** Notes: +** - fixed luaL_error syntax +** - PChar replaced with PAnsiChar, String with AnsiString due to since +** D2009 both PChar and String are unicode +** Bug reports: +** - wintarif@narod.ru +** russian or english +*) +(* +** Updated to Lua 5.3.0 by Malcome@Japan +** Notes: +** - Only tested with FPC (FreePascal Compiler) +** - Needs Delphi with Int64 supported. +*) + + +//-------------------------- +// What was not translated: +//-------------------------- +// macro +// #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +// Generic Buffer manipulation functions and macros were not translated. +// They are not required in Pascal programs due to powerful String type. +// luaL_addchar, luaL_addsize, luaL_buffinit, luaL_prepbuffsize, +// luaL_addlstring, luaL_addstring, luaL_addvalue, luaL_pushresult, +// luaL_pushresultsize, luaL_buffinitsize, luaL_prepbuffer + +// Functions defined with LUA_COMPAT_MODULE are deprecated. +// They were translated but commented intentionally. +// Uncomment them if you really need. +// luaL_pushmodule, luaL_openlib, luaL_register + + +{$IFDEF FPC}{$MODE OBJFPC}{$H+}{$ENDIF} + +unit lua53; + +interface + +const +{$IFDEF MSWINDOWS} + LUA_LIB_NAME = 'lua53.dll'; +{$ELSE} + LUA_LIB_NAME = 'liblua53.so'; +{$ENDIF} + +const + LUA_VERSION_MAJOR = '5'; + LUA_VERSION_MINOR = '3'; + LUA_VERSION_NUM = 503; + LUA_VERSION_RELEASE = '0'; + LUA_VERSION_ = 'Lua 5.3'; // LUA_VERSION was suffixed by '_' for avoiding name collision + LUA_RELEASE = 'Lua 5.3.0'; + LUA_COPYRIGHT = 'Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio'; + LUA_AUTHORS = 'R. Ierusalimschy, L. H. de Figueiredo, W. Celes'; + LUA_SIGNATURE = #27'Lua'; // mark for precompiled code '<esc>Lua' + LUA_MULTRET = -1; // option for multiple returns in 'lua_pcall' and 'lua_call' + + // pseudo-indices + LUA_REGISTRYINDEX = -1001000; + +function lua_upvalueindex(I: Integer): Integer; inline; + +// thread status +const + LUA_OK = 0; + LUA_YIELD_ = 1; // LUA_YIELD was suffixed by '_' for avoiding name collision + LUA_ERRRUN = 2; + LUA_ERRSYNTAX = 3; + LUA_ERRMEM = 4; + LUA_ERRGCMM = 5; + LUA_ERRERR = 6; + LUA_ERRFILE = LUA_ERRERR + 1; // extra error code for `luaL_load' + +type + // Type of Numbers in Lua +{$IFDEF FPC} + lua_Integer = Int64; + lua_Unsigned = UInt64; +{$ELSE} // Delphi + {$IF CompilerVersion < 18} + lua_Integer = Int64; + lua_Unsigned = Int64; + {$ELSE} + lua_Integer = Int64; + lua_Unsigned = UInt64; + {$IFEND} +{$ENDIF} + + Plua_Integer = ^lua_Integer; + Plua_Unsigned = ^lua_Unsigned; + + lua_Number = Double; + Plua_Number = ^lua_Number; + + size_t = Cardinal; + Psize_t = ^size_t; + + Plua_State = Pointer; + + // type for continuation-function contexts + lua_KContext = Pointer; + + lua_CFunction = function(L: Plua_State): Integer; cdecl; + + // Type for continuation functions + lua_KFunction = function(L: Plua_State; status: Integer; ctx: lua_KContext): Integer; cdecl; + + // functions that read/write blocks when loading/dumping Lua chunks + lua_Reader = function(L: Plua_State; ud: Pointer; sz: Psize_t): PAnsiChar; cdecl; + lua_Writer = function(L: Plua_State; const p: Pointer; sz: size_t; ud: Pointer): Integer; cdecl; + + // prototype for memory-allocation functions + lua_Alloc = function(ud, ptr: Pointer; osize, nsize: size_t): Pointer; cdecl; + +const + // basic types + LUA_TNONE = -1; + LUA_TNIL = 0; + LUA_TBOOLEAN = 1; + LUA_TLIGHTUSERDATA = 2; + LUA_TNUMBER = 3; + LUA_TSTRING = 4; + LUA_TTABLE = 5; + LUA_TFUNCTION = 6; + LUA_TUSERDATA = 7; + LUA_TTHREAD = 8; + LUA_NUMTAGS = 9; + + // minimum Lua stack available to a C function + LUA_MINSTACK = 20; + + // predefined values in the registry */ + LUA_RIDX_MAINTHREAD = 1; + LUA_RIDX_GLOBALS = 2; + LUA_RIDX_LAST = LUA_RIDX_GLOBALS; + +// state manipulation +function lua_newstate(f: lua_Alloc; ud: Pointer): Plua_state; cdecl; +procedure lua_close(L: Plua_State); cdecl; +function lua_newthread(L: Plua_State): Plua_State; cdecl; +function lua_atpanic(L: Plua_State; panicf: lua_CFunction): lua_CFunction; cdecl; +function lua_version(L: Plua_State): Plua_Number; cdecl; + +// basic stack manipulation +function lua_absindex(L: Plua_State; idx: Integer): Integer; cdecl; +function lua_gettop(L: Plua_State): Integer; cdecl; +procedure lua_settop(L: Plua_State; idx: Integer); cdecl; +procedure lua_pushvalue(L: Plua_State; Idx: Integer); cdecl; +procedure lua_rotate(L: Plua_State; idx, n: Integer); cdecl; +procedure lua_remove(L: Plua_State; idx: Integer); inline; +procedure lua_insert(L: Plua_State; idx: Integer); inline; +procedure lua_replace(L: Plua_State; idx: Integer); inline; +procedure lua_copy(L: Plua_State; fromidx, toidx: Integer); cdecl; +function lua_checkstack(L: Plua_State; n: Integer): LongBool; cdecl; + +procedure lua_xmove(from, to_: Plua_State; n: Integer); cdecl; + +// access functions (stack -> C) +function lua_isnumber(L: Plua_State; idx: Integer): LongBool; cdecl; +function lua_isstring(L: Plua_State; idx: Integer): LongBool; cdecl; +function lua_iscfunction(L: Plua_State; idx: Integer): LongBool; cdecl; +function lua_isinteger(L: Plua_State; idx: Integer): LongBool; cdecl; +function lua_isuserdata(L: Plua_State; idx: Integer): LongBool; cdecl; +function lua_type(L: Plua_State; idx: Integer): Integer; cdecl; +function lua_typename(L: Plua_State; tp: Integer): PAnsiChar; cdecl; +function lua_tonumberx(L: Plua_State; idx: Integer; isnum: PLongBool): lua_Number; cdecl; +function lua_tointegerx(L: Plua_State; idx: Integer; isnum: PLongBool): lua_Integer; cdecl; +function lua_toboolean(L: Plua_State; idx: Integer): LongBool; cdecl; +function lua_tolstring(L: Plua_State; idx: Integer; len: Psize_t): PAnsiChar; cdecl; +function lua_rawlen(L: Plua_State; idx: Integer): size_t; cdecl; +function lua_tocfunction(L: Plua_State; idx: Integer): lua_CFunction; cdecl; +function lua_touserdata(L: Plua_State; idx: Integer): Pointer; cdecl; +function lua_tothread(L: Plua_State; idx: Integer): Plua_State; cdecl; +function lua_topointer(L: Plua_State; idx: Integer): Pointer; cdecl; + +// Arithmetic functions +const + LUA_OPADD = 0; (* ORDER TM, ORDER OP *) + LUA_OPSUB = 1; + LUA_OPMUL = 2; + LUA_OPMOD = 3; + LUA_OPPOW = 4; + LUA_OPDIV = 5; + LUA_OPIDIV = 6; + LUA_OPBAND = 7; + LUA_OPBOR = 8; + LUA_OPBXOR = 9; + LUA_OPSHL = 10; + LUA_OPSHR = 11; + LUA_OPUNM = 12; + LUA_OPBNOT = 13; + +procedure lua_arith(L: Plua_State; op: Integer); cdecl; + +// Comparison functions +const + LUA_OPEQ = 0; + LUA_OPLT = 1; + LUA_OPLE = 2; + +function lua_rawequal(L: Plua_State; idx1, idx2: Integer): LongBool; cdecl; +function lua_compare(L: Plua_State; idx1, idx2, op: Integer): LongBool; cdecl; + +// push functions (C -> stack) +procedure lua_pushnil(L: Plua_State); cdecl; +procedure lua_pushnumber(L: Plua_State; n: lua_Number); cdecl; +procedure lua_pushinteger(L: Plua_State; n: lua_Integer); cdecl; +procedure lua_pushlstring(L: Plua_State; const s: PAnsiChar; len: size_t); cdecl; +procedure lua_pushstring(L: Plua_State; const s: PAnsiChar); cdecl; overload; +procedure lua_pushstring(L: Plua_State; const s: AnsiString); inline; overload; // added for Pascal +function lua_pushvfstring(L: Plua_State; const fmt: PAnsiChar; argp: Pointer): PAnsiChar; cdecl; +function lua_pushfstring(L: Plua_State; const fmt: PAnsiChar): PAnsiChar; cdecl; varargs; +procedure lua_pushcclosure(L: Plua_State; fn: lua_CFunction; n: Integer); cdecl; +procedure lua_pushboolean(L: Plua_State; b: LongBool); cdecl; +procedure lua_pushlightuserdata(L: Plua_State; p: Pointer); cdecl; +procedure lua_pushthread(L: Plua_State); cdecl; + +// get functions (Lua -> stack) +function lua_getglobal(L: Plua_State; const name: PAnsiChar): Integer; cdecl; +function lua_gettable(L: Plua_State; idx: Integer): Integer; cdecl; +function lua_getfield(L: Plua_state; idx: Integer; k: PAnsiChar): Integer; cdecl; +function lua_geti(L: Plua_State; idx: Integer; n: lua_Integer): Integer cdecl; +function lua_rawget(L: Plua_State; idx: Integer): Integer; cdecl; +function lua_rawgeti(L: Plua_State; idx, n: Integer): Integer; cdecl; +function lua_rawgetp(L: Plua_State; idx: Integer; p: Pointer): Integer; cdecl; + +procedure lua_createtable(L: Plua_State; narr, nrec: Integer); cdecl; +function lua_newuserdata(L: Plua_State; sz: size_t): Pointer; cdecl; +function lua_getmetatable(L: Plua_State; objindex: Integer): Integer; cdecl; +function lua_getuservalue(L: Plua_State; idx: Integer): Integer; cdecl; + +// set functions (stack -> Lua) +procedure lua_setglobal(L: Plua_State; const name: PAnsiChar); cdecl; +procedure lua_settable(L: Plua_State; idx: Integer); cdecl; +procedure lua_setfield(L: Plua_State; idx: Integer; k: PAnsiChar); cdecl; +procedure lua_seti(L: Plua_State; idx: Integer; n: lua_Integer); cdecl; +procedure lua_rawset(L: Plua_State; idx: Integer); cdecl; +procedure lua_rawseti(L: Plua_State; idx: Integer; n: lua_Integer); cdecl; +procedure lua_rawsetp(L: Plua_State; idx: Integer; p: Pointer); cdecl; +function lua_setmetatable(L: Plua_State; objindex: Integer): Integer; cdecl; +procedure lua_setuservalue(L: Plua_State; idx: Integer); cdecl; + +// 'load' and 'call' functions (load and run Lua code) +procedure lua_callk(L: Plua_State; nargs, nresults: Integer; ctx: lua_KContext; k: lua_KFunction); cdecl; +procedure lua_call(L: Plua_State; nargs, nresults: Integer); inline; +function lua_pcallk(L: Plua_State; nargs, nresults, errfunc: Integer; ctx: lua_KContext; k: lua_KFunction): Integer; cdecl; +function lua_pcall(L: Plua_State; nargs, nresults, errf: Integer): Integer; inline; +function lua_load(L: Plua_State; reader: lua_Reader; dt: Pointer; const chunkname, mode: PAnsiChar): Integer; cdecl; +function lua_dump(L: Plua_State; writer: lua_Writer; data: Pointer; strip: Integer): Integer; cdecl; + +// coroutine functions +function lua_yieldk(L: Plua_State; nresults: Integer; ctx: lua_KContext; k: lua_KFunction): Integer; cdecl; +function lua_yield(L: Plua_State; nresults: Integer): Integer; inline; +function lua_resume(L, from: Plua_State; narg: Integer): Integer; cdecl; +function lua_status(L: Plua_State): Integer; cdecl; +function lua_isyieldable(L: Plua_State): LongBool; cdecl; + +// garbage-collection function and options +const + LUA_GCSTOP = 0; + LUA_GCRESTART = 1; + LUA_GCCOLLECT = 2; + LUA_GCCOUNT = 3; + LUA_GCCOUNTB = 4; + LUA_GCSTEP = 5; + LUA_GCSETPAUSE = 6; + LUA_GCSETSTEPMUL = 7; + LUA_GCISRUNNING = 9; + +function lua_gc(L: Plua_State; what, data: Integer): Integer; cdecl; + +// miscellaneous functions +function lua_error(L: Plua_State): Integer; cdecl; + +function lua_next(L: Plua_State; idx: Integer): Integer; cdecl; + +procedure lua_concat(L: Plua_State; n: Integer); cdecl; +procedure lua_len(L: Plua_State; idx: Integer); cdecl; + +function lua_stringtonumber(L: Plua_State; const s: PAnsiChar): size_t; cdecl; + +function lua_getallocf(L: Plua_State; ud: PPointer): lua_Alloc; cdecl; +procedure lua_setallocf(L: Plua_State; f: lua_Alloc; ud: Pointer); cdecl; + +// some useful macros +function lua_getextraspace(L: Plua_State): Pointer; inline; +function lua_tonumber(L: Plua_State; idx: Integer): lua_Number; inline; +function lua_tointeger(L: Plua_State; idx: Integer): lua_Integer; inline; +procedure lua_pop(L: Plua_State; n: Integer); inline; +procedure lua_newtable(L: Plua_state); inline; +procedure lua_register(L: Plua_State; const n: PAnsiChar; f: lua_CFunction); inline; +procedure lua_pushcfunction(L: Plua_State; f: lua_CFunction); inline; +function lua_isfunction(L: Plua_State; n: Integer): Boolean; inline; +function lua_istable(L: Plua_State; n: Integer): Boolean; inline; +function lua_islightuserdata(L: Plua_State; n: Integer): Boolean; inline; +function lua_isnil(L: Plua_State; n: Integer): Boolean; inline; +function lua_isboolean(L: Plua_State; n: Integer): Boolean; inline; +function lua_isthread(L: Plua_State; n: Integer): Boolean; inline; +function lua_isnone(L: Plua_State; n: Integer): Boolean; inline; +function lua_isnoneornil(L: Plua_State; n: Integer): Boolean; inline; +procedure lua_pushliteral(L: Plua_State; s: PAnsiChar); inline; +procedure lua_pushglobaltable(L: Plua_State); inline; +function lua_tostring(L: Plua_State; i: Integer): PAnsiChar; inline; + +// Debug API +const + // Event codes + LUA_HOOKCALL = 0; + LUA_HOOKRET = 1; + LUA_HOOKLINE = 2; + LUA_HOOKCOUNT = 3; + LUA_HOOKTAILCALL = 4; + + // Event masks + LUA_MASKCALL = 1 shl Ord(LUA_HOOKCALL); + LUA_MASKRET = 1 shl Ord(LUA_HOOKRET); + LUA_MASKLINE = 1 shl Ord(LUA_HOOKLINE); + LUA_MASKCOUNT = 1 shl Ord(LUA_HOOKCOUNT); + + LUA_IDSIZE = 60; + +type + lua_Debug = packed record (* activation record *) + event: Integer; + name: PAnsiChar; (* (n) *) + namewhat: PAnsiChar; (* (n) `global', `local', `field', `method' *) + what: PAnsiChar; (* (S) `Lua', `C', `main', `tail'*) + source: PAnsiChar; (* (S) *) + currentline: Integer; (* (l) *) + linedefined: Integer; (* (S) *) + lastlinedefined: Integer; (* (S) *) + nups: Byte; (* (u) number of upvalues *) + nparams: Byte; (* (u) number of parameters *) + isvararg: ByteBool; (* (u) *) + istailcall: ByteBool; (* (t) *) + short_src: packed array[0..LUA_IDSIZE - 1] of AnsiChar; (* (S) *) + (* private part *) + i_ci: Pointer; (* active function *) // ptr to struct CallInfo + end; + Plua_Debug = ^lua_Debug; + + // Functions to be called by the debugger in specific events + lua_Hook = procedure(L: Plua_State; ar: Plua_Debug); cdecl; + +function lua_getstack(L: Plua_State; level: Integer; ar: Plua_Debug): Integer; cdecl; +function lua_getinfo(L: Plua_State; const what: PAnsiChar; ar: Plua_Debug): Integer; cdecl; +function lua_getlocal(L: Plua_State; const ar: Plua_Debug; n: Integer): PAnsiChar; cdecl; +function lua_setlocal(L: Plua_State; const ar: Plua_Debug; n: Integer): PAnsiChar; cdecl; +function lua_getupvalue(L: Plua_State; funcindex, n: Integer): PAnsiChar; cdecl; +function lua_setupvalue(L: Plua_State; funcindex, n: Integer): PAnsiChar; cdecl; +function lua_upvalueid(L: Plua_State; funcindex, n: Integer): Pointer; cdecl; +procedure lua_upvaluejoin(L: Plua_State; funcindex1, n1, funcindex2, n2: Integer); cdecl; +procedure lua_sethook(L: Plua_State; func: lua_Hook; mask: Integer; count: Integer); cdecl; +function lua_gethook(L: Plua_State): lua_Hook; cdecl; +function lua_gethookmask(L: Plua_State): Integer; cdecl; +function lua_gethookcount(L: Plua_State): Integer; cdecl; + +// pre-defined references +const + LUA_NOREF = -2; + LUA_REFNIL = -1; + + LUAL_NUMSIZES = sizeof(lua_Integer)*16 + sizeof(lua_Number); + +type + luaL_Reg = packed record + name: PAnsiChar; + func: lua_CFunction; + end; + PluaL_Reg = ^luaL_Reg; + +procedure luaL_checkversion_(L: Plua_State; ver: lua_Number; sz: size_t); cdecl; +procedure luaL_checkversion(L: Plua_State); inline; +function luaL_getmetafield(L: Plua_State; obj: Integer; const e: PAnsiChar): Integer; cdecl; +function luaL_callmeta(L: Plua_State; obj: Integer; const e: PAnsiChar): Integer; cdecl; +function luaL_tolstring(L: Plua_State; idx: Integer; len: Psize_t): PAnsiChar; cdecl; +function luaL_argerror(L: Plua_State; arg: Integer; const extramsg: PAnsiChar): Integer; cdecl; +function luaL_checklstring(L: Plua_State; arg: Integer; l_: Psize_t): PAnsiChar; cdecl; +function luaL_optlstring(L: Plua_State; arg: Integer; const def: PAnsiChar; l_: Psize_t): PAnsiChar; cdecl; +function luaL_checknumber(L: Plua_State; arg: Integer): lua_Number; cdecl; +function luaL_optnumber(L: Plua_State; arg: Integer; def: lua_Number): lua_Number; cdecl; +function luaL_checkinteger(L: Plua_State; arg: Integer): lua_Integer; cdecl; +function luaL_optinteger(L: Plua_State; arg: Integer; def: lua_Integer): lua_Integer; cdecl; +procedure luaL_checkstack(L: Plua_State; sz: Integer; const msg: PAnsiChar); cdecl; +procedure luaL_checktype(L: Plua_State; arg, t: Integer); cdecl; +procedure luaL_checkany(L: Plua_State; arg: Integer); cdecl; +function luaL_newmetatable(L: Plua_State; const tname: PAnsiChar): Integer; cdecl; +procedure luaL_setmetatable(L: Plua_State; const tname: PAnsiChar); cdecl; +function luaL_testudata(L: Plua_State; ud: Integer; const tname: PAnsiChar): Pointer; cdecl; +function luaL_checkudata(L: Plua_State; ud: Integer; const tname: PAnsiChar): Pointer; cdecl; +procedure luaL_where(L: Plua_State; lvl: Integer); cdecl; +function luaL_error(L: Plua_State; const fmt: PAnsiChar): Integer; cdecl; varargs; +function luaL_checkoption(L: Plua_State; arg: Integer; def: PAnsiChar; lst: PPAnsiChar): Integer; cdecl; +function luaL_fileresult(L: Plua_State; stat: Integer; const fname: PAnsiChar): Integer; cdecl; +function luaL_execresult(L: Plua_State; stat: Integer): Integer; cdecl; +function luaL_ref(L: Plua_State; t: Integer): Integer; cdecl; +procedure luaL_unref(L: Plua_State; t, ref: Integer); cdecl; +function luaL_loadfilex(L: Plua_State; const filename, mode: PAnsiChar): Integer; cdecl; +function luaL_loadfile(L: Plua_State; const filename: PAnsiChar): Integer; inline; +function luaL_loadbufferx(L: Plua_State; const buff: PAnsiChar; sz: size_t; const name, mode: PAnsiChar): Integer; cdecl; +function luaL_loadstring(L: Plua_State; const s: PAnsiChar): Integer; cdecl; +function luaL_newstate: Plua_State; cdecl; +function luaL_len(L: Plua_State; idx: Integer): lua_Integer; cdecl; +function luaL_gsub(L: Plua_State; const s, p, r: PAnsiChar): PAnsiChar; cdecl; +procedure luaL_setfuncs(L: Plua_State; lr: array of luaL_Reg; nup: Integer); inline; overload; +procedure luaL_setfuncs(L: Plua_State; lr: PluaL_Reg; nup: Integer); cdecl; overload; +function luaL_getsubtable(L: Plua_State; idx: Integer; const fname: PAnsiChar): Integer; cdecl; +procedure luaL_traceback(L, L1: Plua_State; msg: PAnsiChar; level: Integer); cdecl; +procedure luaL_requiref(L: Plua_State; const modname: PAnsiChar; openf: lua_CFunction; glb: LongBool); cdecl; + +// some useful macros +procedure luaL_newlibtable(L: Plua_State; lr: array of luaL_Reg); inline; overload; +procedure luaL_newlibtable(L: Plua_State; lr: PluaL_Reg); inline; overload; +procedure luaL_newlib(L: Plua_State; lr: array of luaL_Reg); inline; overload; +procedure luaL_newlib(L: Plua_State; lr: PluaL_Reg); inline; overload; +procedure luaL_argcheck(L: Plua_State; cond: Boolean; arg: Integer; extramsg: PAnsiChar); inline; +function luaL_checkstring(L: Plua_State; n: Integer): PAnsiChar; inline; +function luaL_optstring(L: Plua_State; n: Integer; d: PAnsiChar): PAnsiChar; inline; +function luaL_typename(L: Plua_State; i: Integer): PAnsiChar; inline; +function luaL_dofile(L: Plua_State; const filename: PAnsiChar): Integer; inline; +function luaL_dostring(L: Plua_State; const str: PAnsiChar): Integer; inline; +procedure luaL_getmetatable(L: Plua_State; tname: PAnsiChar); inline; +function luaL_loadbuffer(L: Plua_State; const buff: PAnsiChar; size: size_t; const name: PAnsiChar): Integer; inline; + +const + LUA_COLIBNAME = 'coroutine'; + LUA_TABLIBNAME = 'table'; + LUA_IOLIBNAME = 'io'; + LUA_OSLIBNAME = 'os'; + LUA_STRLIBNAME = 'string'; + LUA_UTF8LIBNAME = 'utf8'; + LUA_BITLIBNAME = 'bit32'; + LUA_MATHLIBNAME = 'math'; + LUA_DBLIBNAME = 'debug'; + LUA_LOADLIBNAME = 'package'; + +function luaopen_base(L: Plua_State): Integer; cdecl; +function luaopen_coroutine(L: Plua_State): Integer; cdecl; +function luaopen_table(L: Plua_State): Integer; cdecl; +function luaopen_io(L: Plua_State): Integer; cdecl; +function luaopen_os(L: Plua_State): Integer; cdecl; +function luaopen_string(L: Plua_State): Integer; cdecl; +function luaopen_utf8(L: Plua_State): Integer; cdecl; +function luaopen_bit32(L: Plua_State): Integer; cdecl; +function luaopen_math(L: Plua_State): Integer; cdecl; +function luaopen_debug(L: Plua_State): Integer; cdecl; +function luaopen_package(L: Plua_State): Integer; cdecl; + +// open all previous libraries +procedure luaL_openlibs(L: Plua_State); cdecl; + +implementation + +function lua_upvalueindex(I: Integer): Integer; +begin + Result := LUA_REGISTRYINDEX - i; +end; + +function lua_newstate(f: lua_Alloc; ud: Pointer): Plua_State; cdecl; external LUA_LIB_NAME; +procedure lua_close(L: Plua_State); cdecl; external LUA_LIB_NAME; +function lua_newthread(L: Plua_State): Plua_State; cdecl; external LUA_LIB_NAME; +function lua_atpanic(L: Plua_State; panicf: lua_CFunction): lua_CFunction; cdecl; external LUA_LIB_NAME; +function lua_version(L: Plua_State): Plua_Number; cdecl; external LUA_LIB_NAME; +function lua_absindex(L: Plua_State; idx: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_gettop(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +procedure lua_settop(L: Plua_State; idx: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_pushvalue(L: Plua_State; Idx: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_rotate(L: Plua_State; idx, n: Integer); cdecl; external LUA_LIB_NAME; + +procedure lua_remove(L: Plua_State; idx: Integer); +begin + lua_rotate(L, idx, -1); + lua_pop(L, 1); +end; + +procedure lua_insert(L: Plua_State; idx: Integer); +begin + lua_rotate(L, idx, 1); +end; + +procedure lua_replace(L: Plua_State; idx: Integer); +begin + lua_copy(L, -1, idx); + lua_pop(L, 1); +end; + +procedure lua_copy(L: Plua_State; fromidx, toidx: Integer); cdecl; external LUA_LIB_NAME; +function lua_checkstack(L: Plua_State; n: Integer): LongBool; cdecl; external LUA_LIB_NAME; +procedure lua_xmove(from, to_: Plua_State; n: Integer); cdecl; external LUA_LIB_NAME; +function lua_isnumber(L: Plua_State; idx: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_isstring(L: Plua_State; idx: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_iscfunction(L: Plua_State; idx: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_isinteger(L: Plua_State; idx: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_isuserdata(L: Plua_State; idx: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_type(L: Plua_State; idx: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_typename(L: Plua_State; tp: Integer): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_tonumberx(L: Plua_State; idx: Integer; isnum: PLongBool): lua_Number; cdecl; external LUA_LIB_NAME; +function lua_tointegerx(L: Plua_State; idx: Integer; isnum: PLongBool): lua_Integer; cdecl; external LUA_LIB_NAME; +procedure lua_arith(L: Plua_State; op: Integer); cdecl; external LUA_LIB_NAME; +function lua_rawequal(L: Plua_State; idx1, idx2: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_compare(L: Plua_State; idx1, idx2, op: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_toboolean(L: Plua_State; idx: Integer): LongBool; cdecl; external LUA_LIB_NAME; +function lua_tolstring(L: Plua_State; idx: Integer; len: Psize_t): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_rawlen(L: Plua_State; idx: Integer): size_t; cdecl; external LUA_LIB_NAME; +function lua_tocfunction(L: Plua_State; idx: Integer): lua_CFunction; cdecl; external LUA_LIB_NAME; +function lua_touserdata(L: Plua_State; idx: Integer): Pointer; cdecl; external LUA_LIB_NAME; +function lua_tothread(L: Plua_State; idx: Integer): Plua_State; cdecl; external LUA_LIB_NAME; +function lua_topointer(L: Plua_State; idx: Integer): Pointer; cdecl; external LUA_LIB_NAME; +procedure lua_pushnil(L: Plua_State); cdecl; external LUA_LIB_NAME; +procedure lua_pushnumber(L: Plua_State; n: lua_Number); cdecl; external LUA_LIB_NAME; +procedure lua_pushinteger(L: Plua_State; n: lua_Integer); cdecl; external LUA_LIB_NAME; +procedure lua_pushlstring(L: Plua_State; const s: PAnsiChar; len: size_t); cdecl; external LUA_LIB_NAME; +procedure lua_pushstring(L: Plua_State; const s: PAnsiChar); cdecl; external LUA_LIB_NAME; + +procedure lua_pushstring(L: Plua_State; const s: AnsiString); +begin + lua_pushlstring(L, PAnsiChar(s), Length(s)); +end; + +function lua_pushvfstring(L: Plua_State; const fmt: PAnsiChar; argp: Pointer): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_pushfstring(L: Plua_State; const fmt: PAnsiChar): PAnsiChar; cdecl; varargs; external LUA_LIB_NAME; +procedure lua_pushcclosure(L: Plua_State; fn: lua_CFunction; n: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_pushboolean(L: Plua_State; b: LongBool); cdecl; external LUA_LIB_NAME; +procedure lua_pushlightuserdata(L: Plua_State; p: Pointer); cdecl; external LUA_LIB_NAME; +procedure lua_pushthread(L: Plua_State); cdecl; external LUA_LIB_NAME; +function lua_getglobal(L: Plua_State; const name: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function lua_gettable(L: Plua_State; idx: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_getfield(L: Plua_state; idx: Integer; k: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function lua_geti(L: Plua_State; idx: Integer; n: lua_Integer): Integer cdecl; external LUA_LIB_NAME; +function lua_rawget(L: Plua_State; idx: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_rawgeti(L: Plua_State; idx, n: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_rawgetp(L: Plua_State; idx: Integer; p: Pointer): Integer; cdecl; external LUA_LIB_NAME; +procedure lua_createtable(L: Plua_State; narr, nrec: Integer); cdecl; external LUA_LIB_NAME; +function lua_newuserdata(L: Plua_State; sz: size_t): Pointer; cdecl; external LUA_LIB_NAME; +function lua_getmetatable(L: Plua_State; objindex: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_getuservalue(L: Plua_State; idx: Integer): Integer; cdecl; external LUA_LIB_NAME; +procedure lua_setglobal(L: Plua_State; const name: PAnsiChar); cdecl; external LUA_LIB_NAME; +procedure lua_settable(L: Plua_State; idx: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_setfield(L: Plua_State; idx: Integer; k: PAnsiChar); cdecl; external LUA_LIB_NAME; +procedure lua_seti(L: Plua_State; idx: Integer; n: lua_Integer); cdecl; external LUA_LIB_NAME; +procedure lua_rawset(L: Plua_State; idx: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_rawseti(L: Plua_State; idx: Integer; n: lua_Integer); cdecl; external LUA_LIB_NAME; +procedure lua_rawsetp(L: Plua_State; idx: Integer; p: Pointer); cdecl; external LUA_LIB_NAME; +function lua_setmetatable(L: Plua_State; objindex: Integer): Integer; cdecl; external LUA_LIB_NAME; +procedure lua_setuservalue(L: Plua_State; idx: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_callk(L: Plua_State; nargs, nresults: Integer; ctx: lua_KContext; k: lua_KFunction); cdecl; external LUA_LIB_NAME; +function lua_pcallk(L: Plua_State; nargs, nresults, errfunc: Integer; ctx: lua_KContext; k: lua_KFunction): Integer; cdecl; external LUA_LIB_NAME; +function lua_load(L: Plua_State; reader: lua_Reader; dt: Pointer; const chunkname, mode: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function lua_dump(L: Plua_State; writer: lua_Writer; data: Pointer; strip: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_yieldk(L: Plua_State; nresults: Integer; ctx: lua_KContext; k: lua_KFunction): Integer; cdecl; external LUA_LIB_NAME; + +procedure lua_call(L: Plua_State; nargs, nresults: Integer); +begin + lua_callk(L, nargs, nresults, nil, nil); +end; + +function lua_pcall(L: Plua_State; nargs, nresults, errf: Integer): Integer; +begin + Result := lua_pcallk(L, nargs, nresults, errf, nil, nil); +end; + +function lua_yield(L: Plua_State; nresults: Integer): Integer; +begin + Result := lua_yieldk(L, nresults, nil, nil); +end; + +function lua_resume(L, from: Plua_State; narg: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_status(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function lua_isyieldable(L: Plua_State): LongBool; cdecl; external LUA_LIB_NAME; +function lua_gc(L: Plua_State; what, data: Integer): Integer; cdecl; external LUA_LIB_NAME; +function lua_error(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function lua_next(L: Plua_State; idx: Integer): Integer; cdecl; external LUA_LIB_NAME; +procedure lua_concat(L: Plua_State; n: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_len(L: Plua_State; idx: Integer); cdecl; external LUA_LIB_NAME; +function lua_stringtonumber(L: Plua_State; const s: PAnsiChar): size_t; cdecl; external LUA_LIB_NAME; +function lua_getallocf(L: Plua_State; ud: PPointer): lua_Alloc; cdecl; external LUA_LIB_NAME; +procedure lua_setallocf(L: Plua_State; f: lua_Alloc; ud: Pointer); cdecl; external LUA_LIB_NAME; + +function lua_getextraspace(L: Plua_State): Pointer; +const + LUA_EXTRASPACE = sizeof(Pointer); +begin + Result := L - LUA_EXTRASPACE; +end; + +function lua_tonumber(L: Plua_State; idx: Integer): lua_Number; +begin + Result := lua_tonumberx(L, idx, nil); +end; + +function lua_tointeger(L: Plua_State; idx: Integer): lua_Integer; +begin + Result := lua_tointegerx(L, idx, nil); +end; + +procedure lua_pop(L: Plua_State; n: Integer); +begin + lua_settop(L, - n - 1); +end; + +procedure lua_newtable(L: Plua_State); +begin + lua_createtable(L, 0, 0); +end; + +procedure lua_register(L: Plua_State; const n: PAnsiChar; f: lua_CFunction); +begin + lua_pushcfunction(L, f); + lua_setglobal(L, n); +end; + +procedure lua_pushcfunction(L: Plua_State; f: lua_CFunction); +begin + lua_pushcclosure(L, f, 0); +end; + +function lua_isfunction(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TFUNCTION; +end; + +function lua_istable(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TTABLE; +end; + +function lua_islightuserdata(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TLIGHTUSERDATA; +end; + +function lua_isnil(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TNIL; +end; + +function lua_isboolean(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TBOOLEAN; +end; + +function lua_isthread(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TTHREAD; +end; + +function lua_isnone(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) = LUA_TNONE; +end; + +function lua_isnoneornil(L: Plua_State; n: Integer): Boolean; +begin + Result := lua_type(L, n) <= 0; +end; + +procedure lua_pushliteral(L: Plua_State; s: PAnsiChar); +begin + lua_pushlstring(L, s, Length(s)); +end; + +procedure lua_pushglobaltable(L: Plua_State); +begin + lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); +end; + +function lua_tostring(L: Plua_State; i: Integer): PAnsiChar; +begin + Result := lua_tolstring(L, i, nil); +end; + +function lua_getstack(L: Plua_State; level: Integer; ar: Plua_Debug): Integer; cdecl; external LUA_LIB_NAME; +function lua_getinfo(L: Plua_State; const what: PAnsiChar; ar: Plua_Debug): Integer; cdecl; external LUA_LIB_NAME; +function lua_getlocal(L: Plua_State; const ar: Plua_Debug; n: Integer): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_setlocal(L: Plua_State; const ar: Plua_Debug; n: Integer): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_getupvalue(L: Plua_State; funcindex, n: Integer): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_setupvalue(L: Plua_State; funcindex, n: Integer): PAnsiChar; cdecl; external LUA_LIB_NAME; +function lua_upvalueid(L: Plua_State; funcindex, n: Integer): Pointer; cdecl; external LUA_LIB_NAME; +procedure lua_upvaluejoin(L: Plua_State; funcindex1, n1, funcindex2, n2: Integer); cdecl; external LUA_LIB_NAME; +procedure lua_sethook(L: Plua_State; func: lua_Hook; mask: Integer; count: Integer); cdecl; external LUA_LIB_NAME; +function lua_gethook(L: Plua_State): lua_Hook; cdecl; external LUA_LIB_NAME; +function lua_gethookmask(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function lua_gethookcount(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; + +procedure luaL_checkversion_(L: Plua_State; ver: lua_Number; sz: size_t); cdecl; external LUA_LIB_NAME; + +procedure luaL_checkversion(L: Plua_State); +begin + luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES); +end; + +procedure luaL_traceback(L, L1: Plua_State; msg: PAnsiChar; level: Integer); cdecl; external LUA_LIB_NAME; +function luaL_argerror(L: Plua_State; arg: Integer; const extramsg: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +procedure luaL_where(L: Plua_State; lvl: Integer); cdecl; external LUA_LIB_NAME; +function luaL_newmetatable(L: Plua_State; const tname: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +procedure luaL_setmetatable(L: Plua_State; const tname: PAnsiChar); cdecl; external LUA_LIB_NAME; +function luaL_testudata(L: Plua_State; ud: Integer; const tname: PAnsiChar): Pointer; cdecl; external LUA_LIB_NAME; +function luaL_checkudata(L: Plua_State; ud: Integer; const tname: PAnsiChar): Pointer; cdecl; external LUA_LIB_NAME; +function luaL_error(L: Plua_State; const fmt: PAnsiChar): Integer; cdecl; varargs; external LUA_LIB_NAME; +function luaL_checkoption(L: Plua_State; arg: Integer; def: PAnsiChar; lst: PPAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +procedure luaL_checkstack(L: Plua_State; sz: Integer; const msg: PAnsiChar); cdecl; external LUA_LIB_NAME; +procedure luaL_checktype(L: Plua_State; arg, t: Integer); cdecl; external LUA_LIB_NAME; +procedure luaL_checkany(L: Plua_State; arg: Integer); cdecl; external LUA_LIB_NAME; +function luaL_checklstring(L: Plua_State; arg: Integer; l_: Psize_t): PAnsiChar; cdecl; external LUA_LIB_NAME; +function luaL_optlstring(L: Plua_State; arg: Integer; const def: PAnsiChar; l_: Psize_t): PAnsiChar; cdecl; external LUA_LIB_NAME; +function luaL_checknumber(L: Plua_State; arg: Integer): lua_Number; cdecl; external LUA_LIB_NAME; +function luaL_optnumber(L: Plua_State; arg: Integer; def: lua_Number): lua_Number; cdecl; external LUA_LIB_NAME; +function luaL_checkinteger(L: Plua_State; arg: Integer): lua_Integer; cdecl; external LUA_LIB_NAME; +function luaL_optinteger(L: Plua_State; arg: Integer; def: lua_Integer): lua_Integer; cdecl; external LUA_LIB_NAME; + +procedure luaL_argcheck(L: Plua_State; cond: Boolean; arg: Integer; extramsg: PAnsiChar); +begin + if not cond then + luaL_argerror(L, arg, extramsg); +end; + +function luaL_checkstring(L: Plua_State; n: Integer): PAnsiChar; +begin + Result := luaL_checklstring(L, n, nil); +end; + +function luaL_optstring(L: Plua_State; n: Integer; d: PAnsiChar): PAnsiChar; +begin + Result := luaL_optlstring(L, n, d, nil); +end; + +function luaL_typename(L: Plua_State; i: Integer): PAnsiChar; +begin + Result := lua_typename(L, lua_type(L, i)); +end; + +function luaL_dofile(L: Plua_State; const filename: PAnsiChar): Integer; +begin + Result := luaL_loadfile(L, filename); + if Result = 0 then + Result := lua_pcall(L, 0, LUA_MULTRET, 0); +end; + +function luaL_dostring(L: Plua_State; const str: PAnsiChar): Integer; +begin + Result := luaL_loadstring(L, str); + if Result = 0 then + Result := lua_pcall(L, 0, LUA_MULTRET, 0); +end; + +procedure luaL_getmetatable(L: Plua_State; tname: PAnsiChar); +begin + lua_getfield(L, LUA_REGISTRYINDEX, tname); +end; + +function luaL_fileresult(L: Plua_State; stat: Integer; const fname: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function luaL_execresult(L: Plua_State; stat: Integer): Integer; cdecl; external LUA_LIB_NAME; +function luaL_ref(L: Plua_State; t: Integer): Integer; cdecl; external LUA_LIB_NAME; +procedure luaL_unref(L: Plua_State; t, ref: Integer); cdecl; external LUA_LIB_NAME; +function luaL_loadfilex(L: Plua_State; const filename, mode: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function luaL_loadbufferx(L: Plua_State; const buff: PAnsiChar; sz: size_t; const name, mode: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; + +function luaL_loadfile(L: Plua_State; const filename: PAnsiChar): Integer; +begin + Result := luaL_loadfilex(L, filename, nil); +end; + +function luaL_loadbuffer(L: Plua_State; const buff: PAnsiChar; size: size_t; const name: PAnsiChar): Integer; +begin + Result := luaL_loadbufferx(L, buff, size, name, nil); +end; + +function luaL_loadstring(L: Plua_State; const s: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function luaL_getmetafield(L: Plua_State; obj: Integer; const e: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function luaL_callmeta(L: Plua_State; obj: Integer; const e: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function luaL_tolstring(L: Plua_State; idx: Integer; len: Psize_t): PAnsiChar; cdecl; external LUA_LIB_NAME; +procedure luaL_requiref(L: Plua_State; const modname: PAnsiChar; openf: lua_CFunction; glb: LongBool); cdecl; external LUA_LIB_NAME; +procedure luaL_setfuncs(L: Plua_State; lr: PluaL_Reg; nup: Integer); cdecl; external LUA_LIB_NAME; + +procedure luaL_setfuncs(L: Plua_State; lr: array of luaL_Reg; nup: Integer); +begin + luaL_setfuncs(L, @lr, nup); +end; + +procedure luaL_newlibtable(L: Plua_State; lr: array of luaL_Reg); +begin + lua_createtable(L, 0, High(lr)); +end; + +procedure luaL_newlibtable(L: Plua_State; lr: PluaL_Reg); +var + n: Integer; +begin + n := 0; + while lr^.name <> nil do begin + inc(n); + inc(lr); + end; + lua_createtable(L, 0, n); +end; + +procedure luaL_newlib(L: Plua_State; lr: array of luaL_Reg); +begin + luaL_checkversion(L); + luaL_newlibtable(L, lr); + luaL_setfuncs(L, @lr, 0); +end; + +procedure luaL_newlib(L: Plua_State; lr: PluaL_Reg); +begin + luaL_checkversion(L); + luaL_newlibtable(L, lr); + luaL_setfuncs(L, lr, 0); +end; + +function luaL_gsub(L: Plua_State; const s, p, r: PAnsiChar): PAnsiChar; cdecl; external LUA_LIB_NAME; +function luaL_getsubtable(L: Plua_State; idx: Integer; const fname: PAnsiChar): Integer; cdecl; external LUA_LIB_NAME; +function luaL_newstate: Plua_State; cdecl; external LUA_LIB_NAME; +function luaL_len(L: Plua_State; idx: Integer): lua_Integer; cdecl; external LUA_LIB_NAME; + +function luaopen_base(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_coroutine(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_table(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_io(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_os(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_string(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_utf8(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_bit32(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_math(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_debug(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +function luaopen_package(L: Plua_State): Integer; cdecl; external LUA_LIB_NAME; +procedure luaL_openlibs(L: Plua_State); cdecl; external LUA_LIB_NAME; + +initialization +{$IFDEF MSWINDOWS} + Set8087CW($133F); // disable all floating-point exceptions +{$ENDIF} + +(****************************************************************************** +* Copyright (C) 1994-2015 Lua.org, PUC-Rio. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************) + +end. diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas new file mode 100644 index 000000000..b5702e306 --- /dev/null +++ b/baseunits/lua/luaXQuery.pas @@ -0,0 +1,156 @@ +unit LuaXQuery; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, XQueryEngineHTML, xquery; + +procedure luaXQueryPush(L: Plua_State; Obj: TXQueryEngineHTML; + Name: String = ''; AutoFree: Boolean = False); inline; + +implementation + +uses + LuaClass, LuaIXQValue, LuaUtils; + +type + TUserData = TXQueryEngineHTML; + +function xquery_create(L: Plua_State): Integer; cdecl; +begin + if lua_gettop(L) = 1 then + begin + if lua_isstring(L, 1) then + luaXQueryPush(L, TXQueryEngineHTML.Create(lua_tostring(L, 1)), '', True) + else + if lua_isuserdata(L, 1) then + luaXQueryPush(L, TXQueryEngineHTML.Create(TStream(lua_touserdata(L, 1))), + '', True); + end + else + luaXQueryPush(L, TXQueryEngineHTML.Create, '', True); + Result := 1; +end; + +function xquery_parsehtml(L: Plua_State): Integer; cdecl; +var + u: TUserData; +begin + Result := 0; + u := TUserData(luaClassGetObject(L)); + if lua_isstring(L, 1) then + u.ParseHTML(lua_tostring(L, 1)) + else + if lua_isuserdata(L, 1) then + u.ParseHTML(lua_tostring(L, 1)); +end; + +function xquery_xpath(L: Plua_State): Integer; cdecl; +var + u: TUserData; + x: IXQValue; +begin + u := TUserData(luaClassGetObject(L)); + if lua_gettop(L) = 2 then + x := u.XPath(lua_tostring(L, 1), IXQValue(PPointer(lua_touserdata(L, 2))^)) + else + x := u.XPath(lua_tostring(L, 1)); + luaIXQValuePush(L, TLuaIXQValue.Create(x)); + Result := 1; +end; + +function xquery_xpathstring(L: Plua_State): Integer; cdecl; +var + u: TUserData; +begin + u := TUserData(luaClassGetObject(L)); + if lua_gettop(L) = 2 then + lua_pushstring(L, u.XPathString(lua_tostring(L, 1), + TLuaIXQValue(PPointer(lua_touserdata(L, 2))^).FIXQValue)) + else + lua_pushstring(L, u.XPathString(lua_tostring(L, 1))); + Result := 1; +end; + +function xquery_xpathstringall(L: Plua_State): Integer; cdecl; +var + u: TUserData; +begin + u := TUserData(luaClassGetObject(L)); + case lua_gettop(L) of + 2: u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^)); + 3: u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + IXQValue(PPointer(lua_touserdata(L, 2))^)); + end; + Result := 0; +end; + +function xquery_xpathhrefall(L: Plua_State): Integer; cdecl; +var + u: TUserData; +begin + u := TUserData(luaClassGetObject(L)); + case lua_gettop(L) of + 3: u.XPathHREFAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + TStrings(PPointer(lua_touserdata(L, 3))^)); + 4: u.XPathHREFAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + TStrings(PPointer(lua_touserdata(L, 3))^), + IXQValue(PPointer(lua_touserdata(L, 4))^)) + end; + Result := 0; +end; + +function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; +var + u: TUserData; +begin + u := TUserData(luaClassGetObject(L)); + case lua_gettop(L) of + 3: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + TStrings(PPointer(lua_touserdata(L, 3))^)); + 4: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + TStrings(PPointer(lua_touserdata(L, 3))^), + IXQValue(PPointer(lua_touserdata(L, 4))^)) + end; + Result := 0; +end; + +const + constructs: packed array [0..2] of luaL_Reg = ( + (name: 'New'; func: @xquery_create), + (name: 'Create'; func: @xquery_create), + (name: nil; func: nil) + ); + methods: packed array [0..6] of luaL_Reg = ( + (name: 'ParseHTML'; func: @xquery_parsehtml), + (name: 'XPath'; func: @xquery_xpath), + (name: 'XPathString'; func: @xquery_xpathstring), + (name: 'XpathStringAll'; func: @xquery_xpathstringall), + (name: 'XpathHREFAll'; func: @xquery_xpathhrefall), + (name: 'XpathHREFTitle'; func: @xquery_xpathhreftitleall), + (name: nil; func: nil) + ); + +procedure luaXQueryAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + luaClassAddFunction(L, MetaTable, UserData, methods); +end; + +procedure luaXQueryPush(L: Plua_State; Obj: TXQueryEngineHTML; + Name: String; AutoFree: Boolean); +begin + luaClassPushObject(L, Obj, Name, AutoFree, @luaXQueryAddMetaTable); +end; + +procedure luaXQueryRegister(L: Plua_State); +begin + luaClassNewLib(L, 'TXQuery', constructs); +end; + +initialization + luaClassRegister(TXQueryEngineHTML, @luaXQueryAddMetaTable, @luaXQueryRegister); + +end. diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 206d871a1..f88461b93 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -904,7 +904,11 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8, - webp; + webp + {$ifdef USE_LUA_MODULE} + ,LuaWebsiteModules + {$endif} + ; var // thread for open db @@ -1754,6 +1758,12 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); if not isStartup then begin isStartup := True; + + {$ifdef USE_LUA_MODULE} + //load lua modules + ScanLuaWebsiteModulesFile; + {$endif} + if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if OptionAutoCheckLatestVersion then From 852f5b308f7081c299bd4944f4921e681b1343ec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 08:47:31 +0800 Subject: [PATCH 2060/2794] viewmangainfo, retrieve saveto field from its sender if sender is favoritelist/downloadlist = use favoritest/downloadlist saveto and ignore generate manga name options if sender is mangalist/manually typed url = use last user picked saveto/default save to and use generate manga name options except if manga already exist in favoritelist, then sender replaced with favoritelist and its saveto closed #893 --- baseunits/uFavoritesManager.pas | 34 +++++++---- baseunits/uGetMangaInfosThread.pas | 2 +- baseunits/uSilentThread.pas | 4 +- mangadownloader/forms/frmMain.pas | 94 +++++++++++++++++------------- 4 files changed, 78 insertions(+), 56 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index c41048323..c6a4d3f4f 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -114,8 +114,10 @@ TFavoriteManager = class // Show notification form after checking completed procedure ShowResult; // Return true if a manga exist in favorites - function IsMangaExist(const ATitle, AWebsite: String): Boolean; - function IsMangaExistURL(const AWebsite, AURL: String): Boolean; + function LocateManga(const ATitle, AWebsite: String): TFavoriteContainer; + function IsMangaExist(const ATitle, AWebsite: String): Boolean; inline; + function LocateMangaByLink(const AWebsite, ALink: String): TFavoriteContainer; + function IsMangaExistLink(const AWebsite, ALink: String): Boolean; inline; // Add new manga to the list procedure Add(const ATitle, ACurrentChapter, ADownloadedChapterList, AWebsite, ASaveTo, ALink: String); // Merge manga information with a title that already exist in favorites @@ -852,28 +854,38 @@ procedure TFavoriteManager.ShowResult; end; end; -function TFavoriteManager.IsMangaExist(const ATitle, AWebsite: String): Boolean; +function TFavoriteManager.LocateManga(const ATitle, AWebsite: String): TFavoriteContainer; var i: Integer; begin - Result := False; - if Items.Count > 0 then + Result := nil; + if Items.Count <> 0 then for i := 0 to Items.Count - 1 do with Items[i].FavoriteInfo do if SameText(ATitle, Title) and SameText(AWebsite, Website) then - Exit(True); + Exit(Items[i]); +end; + +function TFavoriteManager.IsMangaExist(const ATitle, AWebsite: String): Boolean; +begin + Result := LocateManga(ATitle, AWebsite) <> nil; end; -function TFavoriteManager.IsMangaExistURL(const AWebsite, AURL: String): Boolean; +function TFavoriteManager.LocateMangaByLink(const AWebsite, ALink: String): TFavoriteContainer; var i: Integer; begin - Result := False; - if Items.Count > 0 then + Result := nil; + if Items.Count <> 0 then for i := 0 to Items.Count - 1 do with Items[i].FavoriteInfo do - if SameText(AWebsite, Website) and SameText(AURL, Link) then - Exit(True); + if SameText(AWebsite, Website) and SameText(ALink, Link) then + Exit(Items[i]); +end; + +function TFavoriteManager.IsMangaExistLink(const AWebsite, ALink: String): Boolean; +begin + Result := LocateMangaByLink(AWebsite, ALink) <> nil; end; procedure TFavoriteManager.Add(const ATitle, ACurrentChapter, ADownloadedChapterList, diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index fad4c093f..41ab0bfba 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -198,7 +198,7 @@ procedure TGetMangaInfosThread.MainThreadShowInfos; end; vtMangaList.EndUpdate; end; - ShowInformation(mangaInfo.title, mangaInfo.website, mangaInfo.link); + ShowInformation; end; end; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 57f21c5a5..47014bb28 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -362,7 +362,7 @@ procedure TSilentThread.MainThreadAfterChecking; if FSavePath = '' then begin - FilledSaveTo; + FillSaveTo; FSavePath := edSaveTo.Text; // save to if OptionGenerateMangaFolder then @@ -450,7 +450,7 @@ procedure TSilentAddToFavThread.MainThreadAfterChecking; title := Info.mangaInfo.title; if FSavePath = '' then begin - FilledSaveTo; + FillSaveTo; s := edSaveTo.Text; end else diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f88461b93..ef3675db8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -651,7 +651,10 @@ TMainForm = class(TForm) procedure ClearChapterListState; public optionMangaSiteSelectionNodes: array of PVirtualNode; - LastSearchStr, LastSearchWeb: String; + LastSearchStr: String; + LastSearchWeb: String; + LastUserPickedSaveTo: String; + LastViewMangaInfoSender: TObject; // state of chapterlist in mangainfo ChapterList: array of TChapterStateItem; @@ -685,14 +688,14 @@ TMainForm = class(TForm) procedure AddTextToInfo(const ATitle, AValue: String); // fill edSaveTo with default path - procedure FilledSaveTo; + procedure FillSaveTo; // View manga information - procedure ViewMangaInfo(const AURL, AWebsite, ATitle: String; - const AMangaListNode: PVirtualNode = nil); + procedure ViewMangaInfo(const ALink, AWebsite, ATitle, ASaveTo: String; + const ASender: TObject; const AMangaListNode: PVirtualNode = nil); // Show manga information - procedure ShowInformation(const title, website, link: String); + procedure ShowInformation; // get manga list from server procedure RunGetList; @@ -1873,7 +1876,7 @@ procedure TMainForm.miDownloadViewMangaInfoClick(Sender: TObject); begin if Assigned(vtDownload.FocusedNode) then with DLManager.Items[vtDownload.FocusedNode^.Index].DownloadInfo do - ViewMangaInfo(Link, Website, Title); + ViewMangaInfo(Link, Website, Title, SaveTo, miDownloadViewMangaInfo); end; procedure TMainForm.miChapterListHighlightClick(Sender: TObject); @@ -2073,7 +2076,7 @@ procedure TMainForm.miFavoritesViewInfosClick(Sender: TObject); begin if Assigned(vtFavorites.FocusedNode) then with FavoriteManager.Items[vtFavorites.FocusedNode^.Index].FavoriteInfo do - ViewMangaInfo(Link, Website, Title); + ViewMangaInfo(Link, Website, Title, SaveTo, miFavoritesViewInfos); end; procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); @@ -2236,7 +2239,10 @@ procedure TMainForm.btDownloadClick(Sender: TObject); if links.Count<>0 then begin s:=edSaveTo.Text; - if OptionGenerateMangaFolder then + if OptionGenerateMangaFolder and + not((LastViewMangaInfoSender = miDownloadViewMangaInfo) or + (LastViewMangaInfoSender = miFavoritesViewInfos)) // ignore custom saveto options + then s:=AppendPathDelim(s)+CustomRename( OptionMangaCustomRename, mangaInfo.website, @@ -3402,14 +3408,10 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); end; procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); -var - data: PMangaInfoData; begin if Assigned(vtMangaList.FocusedNode) then - begin - data := vtMangaList.GetNodeData(vtMangaList.FocusedNode); - ViewMangaInfo(data^.link, data^.website, data^.title, vtMangaList.FocusedNode); - end; + with PMangaInfoData(vtMangaList.GetNodeData(vtMangaList.FocusedNode))^ do + ViewMangaInfo(link, website, title, '', miMangaListViewInfos, vtMangaList.FocusedNode); end; procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); @@ -4653,29 +4655,27 @@ procedure TMainForm.AddTextToInfo(const ATitle, AValue: String); end; end; -procedure TMainForm.FilledSaveTo; +procedure TMainForm.FillSaveTo; begin - if Trim(edSaveTo.Text) = '' then - begin - edSaveTo.Text := Trim(configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH)); - if edSaveTo.Text = '' then - edSaveTo.Text := DEFAULT_PATH; - end; + if Trim(edSaveTo.Text) <> '' then Exit; + if LastUserPickedSaveTo = '' then + LastUserPickedSaveTo := Trim(configfile.ReadString('saveto', 'SaveTo', DEFAULT_PATH)); + if LastUserPickedSaveTo = '' then + LastUserPickedSaveTo := DEFAULT_PATH; + edSaveTo.Text := LastUserPickedSaveTo; end; -procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; - const AMangaListNode: PVirtualNode); +procedure TMainForm.ViewMangaInfo(const ALink, AWebsite, ATitle, ASaveTo: String; + const ASender: TObject; const AMangaListNode: PVirtualNode); var i: Integer; + fav: TFavoriteContainer; begin - if (AURL = '') or (AWebsite = '') then Exit; + if (ALink = '') or (AWebsite = '') then Exit; // terminate exisiting getmangainfo thread if Assigned(GetInfosThread) then try - { TODO -oriderkick : Access violation on terminate - if terminating thread while starting download cover - } GetInfosThread.Terminate; GetInfosThread.WaitFor; except @@ -4684,9 +4684,9 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; // set the UI i := Modules.LocateModule(AWebsite); if i <> -1 then - edURL.Text := FillHost(Modules.Module[i].RootURL, AURL) + edURL.Text := FillHost(Modules.Module[i].RootURL, ALink) else - edURL.Text := FillMangaSiteHost(AWebsite, AURL); + edURL.Text := FillMangaSiteHost(AWebsite, ALink); pcMain.ActivePage := tsInformation; imCover.Picture.Assign(nil); rmInformation.Clear; @@ -4700,28 +4700,43 @@ procedure TMainForm.ViewMangaInfo(const AURL, AWebsite, ATitle: String; btDownload.Enabled := False; btDownloadSplit.Enabled := btDownload.Enabled; btReadOnline.Enabled := True; + + // set saveto + edSaveTo.Text := ASaveTo; + LastViewMangaInfoSender := ASender; + if edSaveTo.Text = '' then + FillSaveTo; + DisableAddToFavorites(AWebsite); //check if manga already in FavoriteManager list - if btAddToFavorites.Enabled and - (ATitle <> '') and - (FavoriteManager.Count > 0) then - btAddToFavorites.Enabled := not FavoriteManager.IsMangaExist(ATitle, AWebsite); + if btAddToFavorites.Enabled and not(LastViewMangaInfoSender = miFavoritesViewInfos) then + begin + fav := FavoriteManager.LocateMangaByLink(AWebsite, ALink); + if fav <> nil then + begin + btAddToFavorites.Enabled := False; + if LastViewMangaInfoSender <> miDownloadViewMangaInfo then + begin + edSaveTo.Text := fav.FavoriteInfo.SaveTo; + LastViewMangaInfoSender := miFavoritesViewInfos; + end; + end; + end; // start the thread GetInfosThread := TGetMangaInfosThread.Create; GetInfosThread.MangaListNode := AMangaListNode; GetInfosThread.Title := ATitle; GetInfosThread.Website := AWebsite; - GetInfosThread.Link := AURL; + GetInfosThread.Link := ALink; GetInfosThread.Start; end; -procedure TMainForm.ShowInformation(const title, website, link: String); +procedure TMainForm.ShowInformation; var i, j: Integer; begin pcMain.ActivePage := tsInformation; - FilledSaveTo; imCover.Picture.Assign(nil); @@ -4773,11 +4788,6 @@ procedure TMainForm.ShowInformation(const title, website, link: String); btDownload.Enabled := (clbChapterList.RootNodeCount > 0); btDownloadSplit.Enabled := btDownload.Enabled; btReadOnline.Enabled := (mangaInfo.link <> ''); - DisableAddToFavorites(website); - - //check if manga already in FavoriteManager list - if btAddToFavorites.Enabled and (FavoriteManager.Count > 0) then - btAddToFavorites.Enabled := not FavoriteManager.IsMangaExist(mangaInfo.title, website); end; procedure TMainForm.RunGetList; @@ -5432,7 +5442,7 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); Exit; end; - ViewMangaInfo(link, website, ''); + ViewMangaInfo(link, website, '', '', edURL); end; procedure TMainForm.edURLKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); From 918e8df4b3cca76de34f42c04ac5b1be2e3a3422 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 10:17:00 +0800 Subject: [PATCH 2061/2794] added left download toolbar to move items and added option to show/hide #856 --- mangadownloader/forms/frmMain.lfm | 1293 ++++++++++-------------- mangadownloader/forms/frmMain.lrj | 14 +- mangadownloader/forms/frmMain.pas | 43 + mangadownloader/languages/fmd.de.po | 24 + mangadownloader/languages/fmd.el_GR.po | 24 + mangadownloader/languages/fmd.en.po | 180 ++-- mangadownloader/languages/fmd.es.po | 24 + mangadownloader/languages/fmd.id_ID.po | 24 + mangadownloader/languages/fmd.pl_PL.po | 24 + mangadownloader/languages/fmd.po | 24 + mangadownloader/languages/fmd.pt_BR.po | 24 + mangadownloader/languages/fmd.ru_RU.po | 25 + mangadownloader/languages/fmd.tr_TR.po | 25 + 13 files changed, 882 insertions(+), 866 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index e37640f38..70e0e78f6 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -7,6 +7,7 @@ object MainForm: TMainForm Caption = 'Free Manga Downloader' ClientHeight = 587 ClientWidth = 771 + Color = clWindow OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy @@ -14,6 +15,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True + LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -84,124 +86,42 @@ object MainForm: TMainForm Top = 0 Width = 556 ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 ClientWidth = 556 ClientHeight = 490 - object vtDownload: TVirtualStringTree - AnchorSideTop.Control = edDownloadsSearch - AnchorSideTop.Side = asrBottom - Left = 0 - Height = 463 - Top = 27 - Width = 556 - Align = alBottom - Anchors = [akTop, akLeft, akRight, akBottom] - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - DragOperations = [doMove] - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Manga' - Width = 100 - end - item - Position = 1 - Text = 'Status' - Width = 200 - end - item - Position = 2 - Text = 'Progress' - Width = 55 - end - item - Position = 3 - Text = 'Transfer rate' - end - item - Position = 4 - Text = 'Website' - Width = 65 - end - item - Position = 5 - Text = 'Save to' - Width = 150 - end - item - Position = 6 - Text = 'Added' - Width = 80 - end> - Header.DefaultHeight = 17 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] - HintMode = hmHintAndDefault - Images = IconDL - Margin = 2 - ParentFont = False - ParentShowHint = False - PopupMenu = pmDownload - ShowHint = True - TabOrder = 0 - TextMargin = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnColumnDblClick = vtDownloadColumnDblClick - OnDragAllowed = vtDownloadDragAllowed - OnDragOver = vtDownloadDragOver - OnDragDrop = vtDownloadDragDrop - OnDrawText = vtDownloadDrawText - OnFocusChanged = vtDownloadFocusChanged - OnGetText = vtDownloadGetText - OnPaintText = vtDownloadPaintText - OnGetImageIndex = vtDownloadGetImageIndex - OnGetHint = vtDownloadGetHint - OnHeaderClick = vtDownloadHeaderClick - OnKeyAction = vtDownloadKeyAction - OnKeyDown = vtDownloadKeyDown - OnKeyUp = vtDownloadKeyUp - end object pnDownloadToolbar: TPanel - AnchorSideLeft.Control = edDownloadsSearch - AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = edDownloadsSearch - AnchorSideRight.Control = vtDownload - AnchorSideRight.Side = asrBottom AnchorSideBottom.Control = edDownloadsSearch AnchorSideBottom.Side = asrBottom - Left = 154 - Height = 25 + Left = 0 + Height = 26 Top = 0 - Width = 402 - Anchors = [akTop, akLeft, akRight] + Width = 556 + Align = alTop BevelOuter = bvNone - ClientHeight = 25 - ClientWidth = 402 - TabOrder = 1 + ClientHeight = 26 + ClientWidth = 556 + TabOrder = 0 object TransferRateGraph: TChart + AnchorSideLeft.Control = pnDownloadToolbarLeft + AnchorSideLeft.Side = asrBottom AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom - Left = 321 + Left = 475 Height = 25 - Top = 0 + Top = 1 Width = 81 AllowZoom = False AxisList = < item + Marks.LabelBrush.Style = bsClear Minors = <> Title.LabelFont.Orientation = 900 + Title.LabelBrush.Style = bsClear end item Alignment = calBottom + Marks.LabelBrush.Style = bsClear Minors = <> + Title.LabelBrush.Style = bsClear end> AxisVisible = False BackColor = clDefault @@ -236,7 +156,6 @@ object MainForm: TMainForm 'TAChart' ) Toolset = TransferRateToolset - Align = alClient Visible = False object TransferRateGraphArea: TAreaSeries Transparency = 125 @@ -247,12 +166,16 @@ object MainForm: TMainForm end end object pnDownloadToolbarLeft: TPanel - Left = 0 + AnchorSideLeft.Control = edDownloadsSearch + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edDownloadsSearch + AnchorSideTop.Side = asrCenter + Left = 150 Height = 25 Top = 0 Width = 321 - Align = alLeft AutoSize = True + BorderSpacing.Right = 4 BevelOuter = bvNone ClientHeight = 25 ClientWidth = 321 @@ -307,56 +230,198 @@ object MainForm: TMainForm end end end + object edDownloadsSearch: TEditButton + Left = 0 + Height = 23 + Top = 1 + Width = 150 + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edDownloadsSearchButtonClick + OnChange = edDownloadsSearchChange + PasswordChar = #0 + TabOrder = 2 + TextHint = 'Search downloads...' + end end - object edDownloadsSearch: TEditButton + object pnDownloadList: TPanel + AnchorSideLeft.Side = asrBottom Left = 0 - Height = 23 - Top = 0 - Width = 150 - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 - 00070000000E00000014000000190000001A0000001900000017000000150000 - 00120000000E0000000B00000008000000050000000200000001000000020000 - 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 - 305D0000001C000000160000000F0000000A0000000400000001000000000000 - 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 - 5ACA00224248000D170000000000000000000000000000000000000000000000 - 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 - ABFF003763C600356046002D4E00010101000000000000000000013048000021 - 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA - C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B - 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 - C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B - 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 - CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E - 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA - D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D - 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 - 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 - 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 - D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 - 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 - 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 - 94000162930001619200016293000162930001639400000000240000006788CC - DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 - 940001629300016192000162930001629300016394000000000001334C390165 - 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 - 940001629300016192000162930001629300016394000000000001334C000165 - 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - MaxLength = 0 - NumGlyphs = 1 - OnButtonClick = edDownloadsSearchButtonClick - OnChange = edDownloadsSearchChange - PasswordChar = #0 - TabOrder = 2 - TextHint = 'Search downloads...' + Height = 464 + Top = 26 + Width = 556 + Align = alClient + Anchors = [akTop, akLeft, akRight] + Caption = 'pnDownloadList' + ClientHeight = 464 + ClientWidth = 556 + TabOrder = 1 + object ToolBarDownloadLeft: TToolBar + Left = 1 + Height = 462 + Top = 1 + Width = 25 + Align = alLeft + AutoSize = True + BorderSpacing.Right = 4 + ButtonHeight = 24 + ButtonWidth = 24 + Color = clWindow + EdgeBorders = [] + EdgeInner = esNone + EdgeOuter = esNone + Images = IconDLLeft + ParentColor = False + TabOrder = 0 + object tbmiDownloadMoveTop: TToolButton + Left = 1 + Hint = 'Move selected item(s) to top' + Top = 0 + AutoSize = True + ImageIndex = 0 + OnClick = tbmiDownloadMoveTopClick + end + object tbmiDownloadMoveUp: TToolButton + Left = 1 + Hint = 'Move selected item(s) up' + Top = 28 + AutoSize = True + ImageIndex = 1 + OnClick = tbmiDownloadMoveUpClick + end + object tbmiDownloadMoveDown: TToolButton + Left = 1 + Hint = 'Move selected item(s) down' + Top = 56 + AutoSize = True + ImageIndex = 2 + OnClick = tbmiDownloadMoveDownClick + end + object tbmiDownloadMoveBottom: TToolButton + Left = 1 + Hint = 'Move selected item(s) to bottom' + Top = 84 + AutoSize = True + ImageIndex = 3 + OnClick = tbmiDownloadMoveBottomClick + end + end + object vtDownload: TVirtualStringTree + Left = 30 + Height = 462 + Top = 1 + Width = 525 + Align = alClient + Colors.DropTargetBorderColor = clHotLight + Colors.FocusedSelectionBorderColor = clHotLight + Colors.SelectionRectangleBorderColor = clHotLight + Colors.UnfocusedSelectionBorderColor = clBtnShadow + DefaultText = 'Node' + DragOperations = [doMove] + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Manga' + Width = 100 + end + item + Position = 1 + Text = 'Status' + Width = 200 + end + item + Position = 2 + Text = 'Progress' + Width = 55 + end + item + Position = 3 + Text = 'Transfer rate' + end + item + Position = 4 + Text = 'Website' + Width = 65 + end + item + Position = 5 + Text = 'Save to' + Width = 150 + end + item + Position = 6 + Text = 'Added' + Width = 80 + end> + Header.DefaultHeight = 17 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible] + HintMode = hmHintAndDefault + Images = IconDL + Margin = 2 + ParentFont = False + ParentShowHint = False + PopupMenu = pmDownload + ShowHint = True + TabOrder = 1 + TextMargin = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnColumnDblClick = vtDownloadColumnDblClick + OnDragAllowed = vtDownloadDragAllowed + OnDragOver = vtDownloadDragOver + OnDragDrop = vtDownloadDragDrop + OnDrawText = vtDownloadDrawText + OnFocusChanged = vtDownloadFocusChanged + OnGetText = vtDownloadGetText + OnPaintText = vtDownloadPaintText + OnGetImageIndex = vtDownloadGetImageIndex + OnGetHint = vtDownloadGetHint + OnHeaderClick = vtDownloadHeaderClick + OnKeyAction = vtDownloadKeyAction + OnKeyDown = vtDownloadKeyDown + OnKeyUp = vtDownloadKeyUp + end end end end @@ -2291,8 +2356,8 @@ object MainForm: TMainForm AnchorSideTop.Control = edFavoritesSearch AnchorSideTop.Side = asrBottom Left = 0 - Height = 463 - Top = 31 + Height = 464 + Top = 30 Width = 761 Align = alBottom Anchors = [akTop, akLeft, akRight, akBottom] @@ -2937,7 +3002,7 @@ object MainForm: TMainForm object cbOptionEnableLoadCover: TCheckBox Left = 4 Height = 19 - Top = 223 + Top = 246 Width = 745 Align = alTop Caption = 'Enable load manga cover' @@ -2957,13 +3022,23 @@ object MainForm: TMainForm object cbOptionShowBalloonHint: TCheckBox Left = 4 Height = 19 - Top = 246 + Top = 269 Width = 745 Align = alTop Caption = 'Show balloon hint' ParentFont = False TabOrder = 4 end + object cbOptionShowDownloadToolbarLeft: TCheckBox + Left = 4 + Height = 19 + Top = 223 + Width = 745 + Align = alTop + Caption = 'Show left downloads toolbar' + ParentFont = False + TabOrder = 5 + end end object tsConnections: TTabSheet Caption = 'Connections' @@ -4422,7 +4497,6 @@ object MainForm: TMainForm ClientHeight = 498 ClientWidth = 761 object btCheckLatestVersion: TBitBtn - AnchorSideTop.Side = asrTop Left = 0 Height = 40 Top = 452 @@ -4672,8 +4746,8 @@ object MainForm: TMainForm OnMoved = spMainSplitterMoved end object dlgSaveTo: TSelectDirectoryDialog - left = 96 - top = 251 + left = 272 + top = 336 end object pmDownload: TPopupMenu Images = IconList @@ -4683,84 +4757,12 @@ object MainForm: TMainForm object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 - 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 - 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF - FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 - C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 - C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 - C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 - C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A - C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B - C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B - D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 - DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 - E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 7 OnClick = miDownloadStopClick end object miDownloadResume: TMenuItem Caption = 'Resume' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 - 000000000001000000070000000E000000150000001A0000001A0000001A0000 - 001A0000001A0000001A000000160000000F0000000800000002000000000000 - 0000000000020000000E0000001C0000002A000000330000003300000033733A - 02A663320274000000330000002B0000001D0000000F00000003000000000000 - 0000000000000000000000000000000000000000000000000000281502009D52 - 06CC9D5206CC763E055C29160300000000000000000000000000B0651400A85D - 0E00A85D0E00553008007F470C00A85D0E007F470C00A85D0E00A65B0D00A358 - 0BCCFFB914FFA3580BCCA4590C5C7F470C002C19050000000000B4691700AA5F - 1000AA5F10CCAB601100AB601199AA5F10CCAB601199AA5F10CCAB601199AA5F - 10CCFFB810FFFFBB1BFFAA5F10CCAB60115CB1661600B96E1C00B76C1A00AF64 - 1400AF641400B3681700B16616CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B4 - 24FFF5AF18FFF5AB0EFFF7B92EFFB16616CCB267175CB96E1C00B96E1CCCBA6F - 1D00BA6F1D99B96E1CCCB96E1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA96 - 27F5E19E29FFE19E29FFE19E29FFEAB349FFB96E1CCCBA6F1D5CBF742000C378 - 2300C27722CCF8D084FFC27722CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D396 - 44FFD09341FFD09341FFD39644FFD89B49FFECBB6CFFC27722CCCB802999CA7F - 28CCCA7F28CCCA7F28CCCA7F28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE - 61FAEEB266FFEEB266FFEEB266FFF7CC80FFCA7F28CCC97E275CD2872ECCFBD9 - 8DFFD2872ECCD0852C00D2872ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C9 - 7DFFF4C175FFF2B96DFFFAD68AFFD2872ECCD1862D5CCA7F2800D88D3399D98E - 33CCD88D3399D78C3200D88D3399D98E33CCD88D3399D98E33CCD98E33CCD98E - 33CCFBD488FFFEDF93FFD98E33CCD88D335CD2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DA8F3400DC913600E095 - 38CCFFE498FFE09538CCDF94385CD98E3300D2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DD923700E59A3C00E59A - 3CCCE59A3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300E89D3F00E89D3F00E99E - 4099E99E405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 12 OnClick = miDownloadResumeClick end @@ -4776,42 +4778,6 @@ object MainForm: TMainForm object miDownloadDelete: TMenuItem Caption = 'Delete' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 9 object miDownloadDeleteTask: TMenuItem Caption = 'Task only' @@ -4839,42 +4805,6 @@ object MainForm: TMainForm object miDownloadMergeCompleted: TMenuItem Caption = 'Merge completed tasks' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 - 000200000005000000090000000D0000001100000015000000180000001A0000 - 001A0000001A0000001A0000001A000000170000000F00000005000000000000 - 00040000000A0000001100000019000000220000002A00000030000000330000 - 003300000033733B03A6633303740000002E0000001D0000000A532E0700522D - 0600522D0600522D0600522D0600522D0600522D0600522D0600522D0600522D - 0600522D06009F5408CC9F5408CC783F065C2917030000000000A75C0E99A65B - 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B - 0DCCA65B0DCCA65B0DCCFFB508FFA65B0DCCA75C0E5C824A0E00AF6414CCF9C6 - 60FFFFBE23FFFFBD1FFFFFBC1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB7 - 0FFFFFB70DFFFFB60BFFFFB200FFFFB609FFAF6414CCAF641448B96E1BCCF6CB - 7FFFF8C051FFF9BD36FFF8B92CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B5 - 23FFF7B523FFF7B421FFF5AB0EFFF6B11BFFB96E1BCCB96E1B48C1762199C277 - 22CCC27722CCC27722CCD5973FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C - 26CFC27722CCC27722CCE6A93CFFC27722CCC176215CBB701C00C2772200C479 - 2400CC812A2BD38E38CEF0BF71FBE0A856FFDCA04CE4CC8129AACB80283FC97E - 270FC77C2600CC8129CCCC8129CCCB80285CC2772200BB701C00CD822A00D58A - 3000D58A307BEBB865E8F7C579FFF0C070EFD58A30AAD0852D13CC812900C97E - 2700D2872E00D4892F99D4892F5CCC812900C2772200BB701C00DD923600DD92 - 3600DD9236AAF8D081F6FCD185FFE7A951D9DC91363FDB903500CC812900C97E - 2700D2872E00D58A3000D58A3000CC812900C2772200BB701C00E4993B00E499 - 3B00E4993BC5FEDF92FDFFDF93FFE69E42CFE4993B0FE4993B00E4993B00D085 - 2D00D2872E00D58A3000D58A3000CC812900C2772200BB701C00E89D3E00E89D - 3E00E99E3F99E99E3FCCE99E3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C - 3200D2872E00D58A3000D58A3000CC812900C2772200BB701C00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 10 OnClick = miDownloadMergeCompletedClick end @@ -4884,126 +4814,18 @@ object MainForm: TMainForm object miDownloadViewMangaInfo: TMenuItem Caption = 'View manga info' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000030000 - 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B - 0B7A090909650505054200000032000000270000001300000003000000020000 - 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA - DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 - 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 - 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F - 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 - 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 - 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 - 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA - AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 - 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF - CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 - 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC - CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B - 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF - CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 - 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC - DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 - 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF - BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 - 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C - 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F - 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E - 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E - 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 - 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C - 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 - 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA - EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 - 50005252520053535300545454155555553E5555555555555563555555635555 - 55555555553E545454155353530052525200505050004F4F4F00 - } ImageIndex = 0 OnClick = miDownloadViewMangaInfoClick end object miDownloadOpenFolder: TMenuItem Caption = 'Open Folder' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 4 OnClick = miDownloadOpenFolderClick end object miDownloadOpenWith: TMenuItem Caption = 'Open ...' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00000000000000000000000000100000001A0000001000000000000000000000 - 00000000000000000000000000000000000000000000000000001007000F220E - 00352A110048000000620000008F000000ED0000008F000000622A110048200D - 003A130800300703002A050200290502002906030023020100095322009A8550 - 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 - 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 - B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 - B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF - FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 - EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B - A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 - DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 - D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE - FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 - F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF - E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F - 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F - 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D - } ImageIndex = 11 OnClick = miDownloadOpenWithClick end @@ -5072,83 +4894,11 @@ object MainForm: TMainForm top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 002C00000087000000E7702E00C7702E00C7702E00C72C6662E8157882F21578 - 82F2157882F2157882F2157882F2107B87EA008398D00066779A000000090000 - 0016000000DB606060FFCA9764FFC5925FFFC5925FFF4C9590FF32C6D1FF29DB - E9FF28DAE9FF79EDF5FF28DAE9FF28DAE9FF1CC7D8EA0198AF9F000000000101 - 0100010101CE626262FFC89562FFBD8A57FFBF8C59FF95906EFF3CA8ACFF42D9 - E0FF33D5DDFF000000FF33D5DDFF34D5DDFF0DACC1C7019EB63A010101000101 - 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5CFF509B94FF67D1 - D7FF46D3D7FF75B4B5FF40D0D2FF40C3C6F901A4BC9801A2BA01010101000101 - 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFF919778FF56B6 - BAFF7CE4F1FF000000FF68D8E7FF38A6ABEE01A8C04301A7BF00010101000101 - 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC59563FF4FA3 - 9FFF90E3E9FF555555FF88E1E9FF2E8E8ADE01ABC40401ABC400010101000101 - 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FF8F9F - 83FF6BC5C6FFABF5FCFF6CC7C8FF636E48C38F4F0D008F4F0D00010101000101 - 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFC99D - 6CFF50ACA8FFA2E5E7FF53AFABFF94500AA89B4B00009B4B0000010101000101 - 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F - 6CFF84A791FF3FA6A6FF8CAF99FF9E4D00A39E4D00009E4D0000010101000101 - 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 - 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 - 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 - 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 - 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 - 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 - 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 - 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 - 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 - 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 - E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 - 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550073AA550000AA550000 - } ImageIndex = 21 OnClick = miFavoritesCheckNewChapterClick end object miFavoritesStopCheckNewChapter: TMenuItem Caption = 'Stop check for new chapter' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 - 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 - 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF - FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 - C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 - C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 - C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 - C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A - C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B - C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B - D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 - DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 - E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 7 OnClick = miFavoritesStopCheckNewChapterClick end @@ -5162,84 +4912,12 @@ object MainForm: TMainForm end object miFavoritesViewInfos: TMenuItem Caption = 'View manga info' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0001000000050000000A0000000E0000001120140D214936273544312233160C - 061E000000110000000F0000000B000000060000000200000000B87E51000503 - 02000000000200000004301C0F0C91745D62BBA087C4CFB59EE6CFB7A2E3BBA4 - 91BC9278645C321E0F0D000000040000000200000000000000007B55391F825F - 44305E423304421A0005A9896D7CDABC9DF4F1D3B5FFF4DBC1FFEBD5C0FDE0CC - BAF6D2BEAEF0B0978389734B2E0B8562470000000000000000007B573C2AAD8A - 69CAB6916D9D9E7D617DD7B696F1F0D0ADFFF0D4B6FFD5BCA4DFAB8F796E9778 - 6137AE958058B09784BB92725A760600000178523500000000001E000005B48E - 69A8DEAF7DFFDBB58CFDECC9A3FEEFD0AEFFD6BBA1E69C7D6643FFFADF004422 - 1100A281650086654C187F5A3F88775134307852350000000000B69372009D78 - 5961D8AC7BFDEBC295FFEDCAA5FFEED1B1FFC8AE95D99E7F674E805D410DC5B0 - 9E0077513400754F3100744D3019765033407A54370178523500845F4300805C - 4025C9A37BE2EDC69CFFEECDA9FFEFD2B3FFE8CFB6FFCAB29DE891725987693F - 20120600000178563D1697775D3D8A674C3F5D33140277513400754E31002400 - 0005B39272AAD9B895FBCFB193DCC1A58BAFAF927A799A7B63599A7B6356AF92 - 7A71C1A58BA4CEB194D3D9B897F6B99778B34720060776503300775134000000 - 000089664A4098785D4A7F5D441E3B1B0B046339190C8F6F5679C9B19CE3E7CF - B7FFEFD3B5FFEFCEABFFEDC89EFFCEA880E68763462B8A66480078523500653C - 1E0076503339744D301E754F32007751340096765D007E5A3E099E7F6745C7AD - 95D1EED1B2FFEECCA7FFEBC498FFDBAE7EFEA27D5D66C39F7C00000000007852 - 350077503324805C40888A6A511EB3947800371A0D00EFD6BC009B7D663AD5BA - A1DFF0D1B0FFEDCBA5FEDEB890FDDFB17EFFB8916BAA27060005000000007852 - 3500FFFFFF0094745C67B29A87BEB39A875E9B7D6638AD927B6AD6BDA6DAF0D4 - B8FFF1D1AEFFDBBA9AF3A5836783BA95709FB38F6ECC7E5A3F2A000000000000 - 0000815D4200663D1D07B096827CD3BFAFEEE1CDBCF7EBD5C1FDF4DBC2FFF1D4 - B6FFDCBEA0F5AE8E72814F280E0665493905866449347C573A21000000000000 - 000000000000704A2F00532A0E04A3877049C5AD99ABD5BDA8D8D6BCA4DDC7AA - 91B9A5856C59603C230776533900785235007852350078523500000000000000 - 000000000000000000000000000089542E004F2B15077C583E1D826046216341 - 290CFFFFFF000901000000000000000000000000000000000000 - } ImageIndex = 0 SubMenuImages = IconList OnClick = miFavoritesViewInfosClick end object miFavoritesDownloadAll: TMenuItem Caption = 'Download all' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 - } ImageIndex = 1 OnClick = miFavoritesDownloadAllClick end @@ -5256,42 +4934,6 @@ object MainForm: TMainForm end object miFavoritesDelete: TMenuItem Caption = 'Delete' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 9 SubMenuImages = IconList OnClick = miFavoritesDeleteClick @@ -5310,84 +4952,12 @@ object MainForm: TMainForm end object miFavoritesOpenFolder: TMenuItem Caption = 'Open Folder' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00478BE6FF5191E5FF5191E5FF5191E5FF5191E5FF5191E5FF5191E5FF5191 - E5FF5191E5FF5191E5FF5191E5FF478BE6FFFFFFFF00FFFFFF00FFFFFF002784 - F7FF429BFFFF469DFFFF469DFFFF469DFFFF469DFFFF469DFFFF469DFFFF469D - FFFF469DFFFF469DFFFF469DFFFF429BFFFF2784F7FFFFFFFF00FFFFFF002479 - FFFF387AFFFF377BFFFF377BFFFF377BFFFF377BFFFF377BFFFF377BFFFF377B - FFFF377BFFFF377BFFFF377BFFFF387AFFFF2479FFFFFFFFFF00FFFFFF002173 - FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF3B87 - FFFF3B87FFFF3B87FFFF3B87FFFF3B87FFFF2172FFFFFFFFFF00FFFFFF002279 - FFFF3D8DFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8CFFFF3B8C - FFFF3B8CFFFF3B8CFFFF3B8CFFFF3D8DFFFF2279FFFFFFFFFF00FFFFFF002482 - FFFF3E95FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94FFFF3D94 - FFFF3D94FFFF3D94FFFF3D94FFFF3E95FFFF2482FFFFFFFFFF00FFFFFF002488 - FFFF3E9BFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9AFFFF3D9A - FFFF3D9AFFFF3D9AFFFF3D9AFFFF3E9BFFFF2488FFFFFFFFFF00FFFFFF002690 - FFFF40A2FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1FFFF3FA1 - FFFF3FA1FFFF3FA1FFFF3FA1FFFF40A2FFFF2690FFFFFFFFFF00FFFFFF002697 - FFFF40A9FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8FFFF3FA8 - FFFF3FA8FFFF3FA8FFFF3FA7FFFF40A8FFFF2697FFFFFFFFFF00FFFFFF0029A0 - FFFF42B0FFFF41AFFFFF41AFFFFF41AFFFFF41B0FFFF41B0FFFF41AFFFFF41B0 - FFFF41B0FFFF41B0FFFF41B1FFFF43B2FFFF26A2FFFFFFFFFF00FFFFFF002AA6 - FFFF42B6FFFF41B5FFFF41B5FFFF41B6FFFF41B7FFFF45BAFFFF3EBBFFFF3FBD - FFFF3FBEFFFF3FBEFFFF3FBEFFFF3BBEFFFF2BA8FFFFFFFFFF00FFFFFF002BAD - FFFF43BDFFFF43BCFFFF43BCFFFF42BCFFFF45C1FFFF2CB1FFFF73CDFFFF6DCC - FFFF6DCCFFFF6DCCFFFF6DCCFFFF61C9FFFFFFFFFF00FFFFFF00FFFFFF002BB4 - FFFF44C2FFFF43BFFFFF43BFFFFF43C1FFFF46C6FFFF1CB0FFFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002ABC - FFFF47D0FFFF47CEFFFF47CEFFFF49CFFFFF3FCBFFFF2BB8FFFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002EC9FFFF3BCCFFFF3BCCFFFF38CCFFFF45CCFFFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 4 SubMenuImages = IconList OnClick = miFavoritesOpenFolderClick end object miFavoritesOpenWith: TMenuItem Caption = 'Open ...' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00000000000000000000000000100000001A0000001000000000000000000000 - 00000000000000000000000000000000000000000000000000001007000F220E - 00352A110048000000620000008F000000ED0000008F000000622A110048200D - 003A130800300703002A050200290502002906030023020100095322009A8550 - 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 - 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 - B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 - B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF - FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 - EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B - A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 - DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 - D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE - FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 - F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF - E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F - 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F - 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D - } ImageIndex = 11 OnClick = miFavoritesOpenWithClick end @@ -5399,126 +4969,18 @@ object MainForm: TMainForm top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 - 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 - 0000000000040000001B481F1546B24C3399E96443D4EE6644F5EE6644F5E964 - 43D4B24C3399471F15470000001F0000000600000000FFFFFF00FFFFFF007432 - 210077332200B34D3360EF6F4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1 - C9FFF4A18EFFEF6E4EEBB34D33603C1A110000000000FFFFFF00FFFFFF00E863 - 4100EE664460EF7659F9F7D4CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8 - E8FFF7E9E9FFF6D1CAFFEF7658F9EE664460E8634100FFFFFF00FFFFFF00E360 - 3E20E66A4AEBF3D3CDFFF0E5E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4 - E4FFEFE4E4FFEFE4E4FFEFCDC7FFE66A4AEBE3603E20FFFFFF00FFFFFF00D659 - 3787E59D8AFFEAE2E2FFE7DFDFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DF - DFFFE7DFDFFFE7DFDFFFE8E0E0FFE19784FFD6593787FFFFFF00FFFFFF00C550 - 2ED0EAD0C8FFE1DADAFFE0D9D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9 - D9FFE0D9D9FFE0D9D9FFE0D9D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00B748 - 26F5F4EEEDFFE7E5E5FFDAD6D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4 - D4FFD8D4D4FFD8D4D4FFD8D4D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00AD44 - 22F5F4EFEDFFEEEEEEFFEAEAEAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0 - D0FFD2D0D0FFD2D0D0FFD2D0D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00AB46 - 24D0EAD5CDFFF0F0F0FFF0F0F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1 - D1FFCECECEFFCECECEFFD2D1D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00B34F - 2D87D49D8AFFF5F5F5FFF3F3F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3 - F3FFF3F3F3FFF3F3F3FFF5F5F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00BF5C - 3A20C56747EBF2DFD9FFF8F8F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7 - F7FFF7F7F7FFF8F8F8FFF2DFD9FFC56747EBBF5C3A20FFFFFF00FFFFFF00C461 - 3F00CF6B4960D77F61F9F6E3DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB - FBFFFCFCFCFFF6E3DCFFD77F61F9CF6B4960C4613F00FFFFFF00FFFFFF00C461 - 3F00D16D4B00DF7A5860E38464EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4 - DDFFEFB7A4FFE38464EBDF7A5860D16D4B00C4613F00FFFFFF00FFFFFF00C461 - 3F00D16D4B00E17C5A00EA846220EC866487EC8664D0EC8664F5EC8664F5EC86 - 64D0EC866487EA846220E17C5A00D16D4B00C4613F00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 13 SubMenuImages = IconList OnClick = miMangaListViewInfosClick end object miMangaListDownloadAll: TMenuItem Caption = 'Download all' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000818181007F7F - 7FFF7C7C7CFF7A7A7AFF787878FF777777FF757575FF767676FFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00868686FFBFBF - BFFFBDBDBDFFBCBCBCFFBBBBBBFFBBBBBBFFBABABAFF81818100FFFFFF00FFFF - FF002A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF008A8A8AFFC0C0 - C0FFB0B0B0FFB0B0B0FFB0B0B0FFB1B1B1FFC0C0C0FF989898FFFFFFFF002A89 - 27FF3F993CFF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF008E8E8EFFC2C2 - C2FFD2D2D2FFD2D2D2FFD3D3D3FFD6D6D6FFCCCCCCFFD7D7D7FF2A8927FF419B - 3DFF61B45DFF419B3DFF2A8927FFFFFFFF00FFFFFF00FFFFFF00939393FFC4C4 - C4FFD2D2D2FFD3D3D3FFD6D6D6FFDDDDDDFFDDDDDDFF2A8927FF429C3FFF65B8 - 61FF65B861FF65B861FF429C3FFF2A8927FFFFFFFF00FFFFFF00979797FFC6C6 - C6FFD2D2D2FFD4D4D4FFDADADAFFE6E6E6FF2A8927FF449E41FF6ABB66FF69BB - 65FF69BB65FF69BB65FF6ABB66FF449E41FF2A8927FFFFFFFF009C9C9CFFC9C9 - C9FFC7C7C7FFCACACAFFD4D4D4FF2A8927FF5DAA5BFFA7D9A5FFA7D9A5FF8FCE - 8CFF6DBF69FF8FCE8CFFA7D9A5FFA7D9A5FF5DAA5BFF2A8927FFA0A0A0FFCBCB - CBFFC9C9C9FFCBCBCBFFD4D4D4FF2A8927FF2A8927FF2A8927FF2A8927FF5FAB - 5CFF72C36EFF5FAB5CFF2A8927FF2A8927FF2A8927FF2A8927FFA4A4A4FFCCCC - CCFFCBCBCBFFCCCCCCFFD1D1D1FFD7D7D7FFDCDCDCFFC9C9C9FFFFFFFF002A89 - 27FF76C772FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00A8A8A8FFCECE - CEFFB0B0B0FFB1B1B1FFB4B4B4FFB7B7B7FFCECECEFFB1B1B1FFFFFFFF002A89 - 27FF79CA75FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00ACACACFFD0D0 - D0FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFCACACAFFA7A7A7FFFFFFFF002A89 - 27FF7CCE79FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00AFAFAFFFD2D2 - D2FFB0B0B0FFB0B0B0FFB0B0B0FFB0B0B0FFCCCCCCFFABABABFFFFFFFF002A89 - 27FF7FD17BFF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B2B2B2FFD2D2 - D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFCDCDCDFFADADADFFFFFFFF002A89 - 27FFB3E5B1FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFD4D4 - D4FFD3D3D3FFD2D2D2FFD2D2D2FFD1D1D1FFD0D0D0FFAEAEAEFFFFFFFF002A89 - 27FF2A8927FF2A8927FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFD4D4 - D4FFD4D4D4FFD4D4D4FFD2D2D2FFD2D2D2FFD1D1D1FFAEAEAEFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FFB4B4 - B4FFB4B4B4FFB4B4B4FFB2B2B2FFB1B1B1FFAFAFAFFFAEAEAEFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 1 SubMenuImages = IconList OnClick = miMangaListDownloadAllClick end object miMangaListAddToFavorites: TMenuItem Caption = 'Add to Favorites' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF0058B754FF5AB856FFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF001DB31BFF04C302FF03C200FF1EB31EFFFFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF0041BB42FF08BF09FF1EB720FF1EB720FF06BE08FF42BB44FFFFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF0020B828FF08C313FF20B929FF1EBD28FF1EBB27FF20BA29FF08C313FF21B8 - 29FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0045C1 - 50FF0AC71CFF20BD2EFF1FBF2DFF1FC02FFF1FC02EFF1FBE2EFF20BE2EFF0AC6 - 1BFF43BF4FFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0003BF - 1CFF23C238FF21C337FF21C338FF21C338FF21C338FF21C437FF21C137FF23BF - 38FF0CCA25FF23BE37FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0027BF - 42FF11C331FF24CA42FF22C63FFF21C53FFF21C63FFF21C63FFF21C63FFF21C4 - 3EFF22C33FFF0CCE2FFF43C45BFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF0022C547FF11C73BFF26CE4DFF24CB49FF23CA49FF23C949FF23CA49FF23CA - 4AFF24CB4AFF26C74BFF10D23CFF22C346FFFFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF0023C84FFF14CD45FF27D152FF25CD50FF25CD50FF25CF51FF28D5 - 55FF14D045FF00C032FF16C644FF11D644FF4DCD6EFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF0025CB59FF16CE4EFF29D45DFF27D15AFF29D75FFF0AC8 - 45FF79E19AFFFFFFFF006FDC90FF18C34CFF11CC4AFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF0027CF60FF19D357FF2AD865FF21D35DFF2BC8 - 60FFFFFFFF00FFFFFF00FFFFFF004DD27AFF11C24DFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0028D168FF19D660FF20D465FF35BD - 69FFFFFFFF00FFFFFF00FFFFFF0056C880FF14C557FFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0029D46DFF1AD464FF11CF - 5CFF9BCEAFFFFFFFFF0091CFAAFF1BC960FF19C75EFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0029D674FF15D5 - 69FF04E765FF00EC63FF07E767FF19DE6FFF1FD16BFFFFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0075E7 - A8FF5CE79AFF60ED9FFF5FE89CFF5AE598FFFFFFFF00FFFFFF00 - } ImageIndex = 2 SubMenuImages = IconList OnClick = miMangaListAddToFavoritesClick @@ -7185,4 +6647,301 @@ object MainForm: TMainForm left = 480 top = 472 end + object IconDLLeft: TImageList + Height = 24 + Width = 24 + left = 272 + top = 232 + Bitmap = { + 4C69040000001800000018000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000003522 + 0C00A1692500DA8F3400DE933700E1963A00E59A3C00E89D3E00EA9F4066EA9F + 4066E89D3E00E59A3C00E1963A00DE933700DA8F3400A169250035220C000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009A622000D186 + 2D00D68B3100DA8F3400DE933700E1963A00E59A3C00E89D3E66E89D3ECCE89D + 3ECCE89D3E66E59A3C00E1963A00DE933700DA8F3400D68B3100D1862D009A62 + 2000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00D186 + 2D00D68B3100DA8F3400DE933700E1963A00E59A3C66E59A3CCCFFE599FFFFE4 + 98FFE59A3CCCE59A3C66E1963A00DE933700DA8F3400D68B3100D1862D00CD82 + 2A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00D186 + 2D00D68B3100DA8F3400DE933700E1963A66E1963ACCFFE498FFFCD185FFFCD1 + 85FFFFE397FFE1963ACCE1963A66DE933700DA8F3400D68B3100D1862D00CD82 + 2A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00D186 + 2D00D68B3100DA8F3400DE933766DE9337CCFFE397FFF8CA7EFFF6C276FFF6C2 + 76FFF8C97DFFFEE195FFDE9337CCDE933766DA8F3400D68B3100D1862D00CD82 + 2A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00D186 + 2D00D68B3100DA8F3466DA8F34CCFEE195FFF4C276FFF1B86CFFF1B86CFFF1B8 + 6CFFF1B86CFFF4C175FFFDDD91FFDA8F34CCDA8F3466D68B3100D1862D00CD82 + 2A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00D186 + 2D00D68B3166D68B31CCFDE094FFF2BE72FFEEB367FFEEB367FFEEB367FFEEB3 + 67FFEEB367FFEEB367FFF2BC70FFFBD88CFFD68B31CCD68B3166D1862D00CD82 + 2A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00D186 + 2D66D1862DCCFDDE92FFF2BD71FFEEB266FFECB064FFE3A75BFFD99D51FFD498 + 4CFFCF9347FFCD9145FFCD9145FFD7A155FFF1CC80FFD1862DCCD1862D66CD82 + 2A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CC812A66CD82 + 2ACCFCDD91FFF9D185FFF4C579FFECBD71FFE1B266FFCC9044FFCC9044FFCC90 + 44FFCC9044FFD59E52FFDDAC60FFDCAB5FFFE4B86CFFEBC478FFCD822ACCCC81 + 2A66FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C97E2799C87D + 26CCC87D26CCC87D26CCC87D26CCC87D26CCF1CD81FFCC9044FFCC9044FFCC90 + 44FFCC9044FFDCAB5FFFC87D26CCC87D26CCC87D26CCC87D26CCC87D26CCC97E + 2799FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600C77C + 2500C77C2500C77C2500C67B2500C37823CCEFC97CFFCD9142FFCD9142FFCD91 + 42FFCD9142FFDCA95BFFC37823CCC3792300C77C2500C77C2500C77C2500C87D + 2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600C77C + 2500C77C2500C57A2400BE741F00BE741FCCEEC675FFD3943CFFD3943CFFD394 + 3CFFD3943CFFDEA954FFBF7521CDBE741F03C0762100C77C2500C77C2500C87D + 2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600C77C + 2500C4792300BA6F1C00BA6F1C00BA6F1CCBEEC36CFFD99834FFD99834FFD998 + 34FFD99834FFE2AA4BFFBE7521D0BA6F1C0DBA6F1C00BD721E00C77C2500C87D + 2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600C378 + 2200B56A1800B56A1800B56A1800B56A18BDECBC5DFBE09F2CFFE09D2AFFE09D + 2AFFE09D2AFFE6AA3EFFBF7823D4B56A181EB56A1800B56A1800BA6F1B00C87D + 2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BC711D00B065 + 1500B0651500B0651500B0651500B065159EE4AD49F3E9A82AFFE7A220FFE7A2 + 20FFE7A220FFEBAB2FFFC37E25DAB0651536B0651500B0651500B0651500B065 + 1500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00AC611100AC61 + 1100AC611100AC611100AC611100AC611168CE8D2CE3F2B330FFEFA716FFEFA7 + 16FFEFA716FFF0AC1FFFCD8A26E2AB601156AA5F1000AA5F1000AA5F1000AA5F + 1000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00A85D0F00A85D + 0F00A85D0F00A85D0F00A85D0F00A85D0F20AF6613C8F3B635FBF6AE10FFF6AC + 0DFFF6AC0DFFF6AE10FFE2A027F0A75C0E8CA75C0E00A75C0E00A75C0E00A75C + 0E00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 0000000000007C440900A4590C00A4590C00A3580B73C8831BE0FCB81EFFFBB0 + 06FFFBB006FFFBB006FFF6B31EFBA95F0CBDA2570A0BA2570A00A2570A00A257 + 0A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 00000000000000000000291603007A420800A1560A0FA05508A2D28D17E7FEB8 + 12FFFFB301FFFFB201FFFFB70FFFC37B10DEA055084B9F5407007E4105005C2E + 0200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 00000000000000000000000000000000000028160300773E05169C5106A2C57D + 0FE0F7B012FBFFB405FFFFB404FFEEA712F6A15607AF9B5005106F3803005C2E + 0200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 00000000000100000004000000070000000B0000000F0000001327140125793E + 0382A25806C9C8800CE3E9A00CF3F8B00EFBCF860BE6994E04916F3803265C2E + 0200FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000000000001000000070000000D000000150000001E000000260000002D0000 + 0032311901476633027D8F4802A5964B02BE974C02CB974C02CC7139029F4C26 + 0100FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 00000000000100000004000000070000000B0000000F00000013000000170000 + 00190000001A0000001A0000001A0000001A0000001A0000001A000000100000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 000036230D00A46C2800DE933700E1963A00E59A3C00E89D3E00EA9F4066EA9F + 4066E89D3E00E59A3C00E1963A00DE933700A46C280036230D00000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D00D68B3100DA8F3400DE933700E1963A00E59A3C00E89D3E66E89D3ECCE89D + 3ECCE89D3E66E59A3C00E1963A00DE933700DA8F3400D68B3100D1862D00CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D00D68B3100DA8F3400DE933700E1963A00E59A3C66E59A3CCCFFE599FFFFE4 + 98FFE59A3CCCE59A3C66E1963A00DE933700DA8F3400D68B3100D1862D00CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D00D68B3100DA8F3400DE933700E1963A66E1963ACCFFE498FFFCD286FFFCD2 + 86FFFFE397FFE1963ACCE1963A66DE933700DA8F3400D68B3100D1862D00CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D00D68B3100DA8F3400DE933766DE9337CCFFE397FFF9CC80FFF7C478FFF7C4 + 78FFF9CB7FFFFEE195FFDE9337CCDE933766DA8F3400D68B3100D1862D00CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D00D68B3100DA8F3466DA8F34CCFEE296FFF6C579FFF3BC70FFF3BC70FFF3BC + 70FFF3BC70FFF6C478FFFDDD91FFDA8F34CCDA8F3466D68B3100D1862D00CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D00D68B3166D68B31CCFDE094FFF3BF73FFF0B569FFF0B569FFF0B569FFF0B5 + 69FFF0B569FFF0B569FFF3BE72FFFBD98DFFD68B31CCD68B3166D1862D00CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CD822A00D186 + 2D66D1862DCCFDDE92FFF2BD71FFEEB266FFEEB266FFEEB266FFEEB266FFEEB2 + 66FFEEB266FFEEB266FFEEB266FFF1BB6FFFFAD589FFD1862DCCD1862D66CD82 + 2A00C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2600CC812A66CD82 + 2ACCFCDD91FFF2BD71FFEEB266FFEEB266FFECB064FFE3A75BFFD99D51FFD498 + 4CFFCF9347FFCD9145FFCD9145FFCF9347FFD9A256FFF0C97DFFCD822ACCCC81 + 2A66C87D2600FFFFFF00FFFFFF00FFFFFF00FFFFFF00C87D2666C87D26CCFCDB + 8FFFF8D084FFF5C67AFFF3C478FFEABB6FFFE0B064FFCC9044FFCC9044FFCC90 + 44FFCC9044FFD49D51FFDBAA5EFFDBA95DFFDBA85CFFE2B367FFE8BE72FFC87D + 26CCC87D2666FFFFFF00FFFFFF00FFFFFF00FFFFFF00C4792499C37823CCC378 + 23CCC37823CCC37823CCC37823CCC37823CCEEC97DFFCC9044FFCC9044FFCC90 + 44FFCC9044FFDBA95DFFC37823CCC37823CCC37823CCC37823CCC37823CCC378 + 23CCC4792499FFFFFF00FFFFFF00FFFFFF00FFFFFF00C3782300C2772200C277 + 2200C2772200C2772200C1762100BE741FCCECC577FFCF9241FFCF9241FFCF92 + 41FFCF9241FFDBA758FFBE741FCCC1762100C2772200C2772200C2772200C277 + 2200C3782300FFFFFF00FFFFFF00FFFFFF00FFFFFF00C3782300C2772200C277 + 2200C2772200C0752100BA6F1C00BA6F1CCCEDC26FFFD49539FFD49539FFD495 + 39FFD49539FFDEA850FFBA6F1CCCBA6F1C00C0752100C2772200C2772200C277 + 2200C3782300FFFFFF00FFFFFF00FFFFFF00FFFFFF00C3782300C2772200C277 + 2200BF742000B56A1800B56A1800B56A18CCEEC165FFDB9A30FFDB9A30FFDB9A + 30FFDB9A30FFE3AA46FFB56A18CCB56A1800B56A1800BF742000C2772200C277 + 2200C3782300FFFFFF00FFFFFF00FFFFFF00FFFFFF00C3782300C2772200BE73 + 1F00B0651500B0651500B0651500B06515CCF0BF5AFFE3A025FFE3A025FFE3A0 + 25FFE3A025FFE9AC3AFFB06515CCB0651500B0651500B0651500BE731F00C277 + 2200C3782300FFFFFF00FFFFFF00FFFFFF00FFFFFF00C3782300BC711E00AC61 + 1100AC611100AC611100AC611100AC6111CCF3BF4EFFEBA51AFFEBA51AFFEBA5 + 1AFFEBA51AFFEFB02EFFAC6111CCAC611100AC611100AC611100AC611100BC71 + 1E00C3782300FFFFFF00FFFFFF00FFFFFF00FFFFFF00B56A1800A75C0E00A75C + 0E00A75C0E00A75C0E00A75C0E00A75C0ECCF7BF40FFF3AA10FFF3AA10FFF3AA + 10FFF3AA10FFF5B322FFA75C0ECCA75C0E00A75C0E00A75C0E00A75C0E00A75C + 0E00B56A1800FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 00007B430800A3580B00A3580B00A3580BCCFBBF34FFFAAE07FFFAAE07FFFAAE + 07FFFAAE07FFFBB518FFA3580BCCA3580B00A3580B007B430800000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 00000000000078400700A0550800A05508CCFFBF29FFFEB201FFFEB201FFFEB2 + 01FFFEB201FFFEB710FFA05508CCA05508007840070000000000000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 00000000000000000000763D05009C5106CCFFBE22FFFFB200FFFFB200FFFFB2 + 00FFFFB200FFFFB60CFF9C5106CC763D05000000000000000000000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 0001000000060000000C00000012994E04CCFFBC1CFFFFB60DFFFFB60CFFFFB6 + 0BFFFFB60AFFFFB70FFF994E04CC000000130000000C00000006000000010000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 00020000000B0000001800000024713902A5974C02CC974C02CC974C02CC974C + 02CC974C02CC974C02CC713902A500000025000000180000000B000000020000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 0001000000060000000C00000012000000180000001A0000001A0000001A0000 + 001A0000001A0000001A00000018000000130000000C00000006000000010000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E99E3F00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00EA9F4099EA9F40CCEA9F40CCEA9F40CCEA9F + 40CCEA9F40CCEA9F40CCEA9F4099E99E3F00E99E3F00E99E3F00E99E3F00E99E + 3F00E99E3F00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E89D3E00E89D3E00E89D + 3E00E89D3E00E89D3E00E89D3E00E89D3ECCFFE599FFFFE599FFFFE599FFFFE4 + 98FFFFE498FFFFE498FFE89D3ECCE89D3E00E89D3E00E89D3E00E89D3E00E89D + 3E00E89D3E00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E59A3C00E59A3C00E59A + 3C00E59A3C00E59A3C00E59A3C00E59A3CCCFFE498FFFBCB7FFFFBCB7FFFFBCB + 7FFFFBCB7FFFFDD78BFFE59A3CCCE59A3C00E59A3C00E59A3C00E59A3C00E59A + 3C00E59A3C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E1963A00E1963A00E196 + 3A00E1963A00E1963A00E1963A00E1963ACCFFE397FFF6C276FFF6C276FFF6C2 + 76FFF6C276FFFAD185FFE1963ACCE1963A00E1963A00E1963A00E1963A00E196 + 3A00E1963A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00DE933700DE933700DE93 + 3700DE933700DE933700DE933700DE9337CCFEE195FFF1B86CFFF1B86CFFF1B8 + 6CFFF1B86CFFF7CB7FFFDE9337CCDE933700DE933700DE933700DE933700DE93 + 3700DE933700FFFFFF00FFFFFF00FFFFFF00FFFFFF00CD822A00DA8F3400DA8F + 3400DA8F3400DA8F3400DA8F3400DA8F34CCFDDE92FFEEB367FFEEB367FFEEB3 + 67FFEEB367FFF5C77BFFDA8F34CCDA8F3400DA8F3400DA8F3400DA8F3400DA8F + 3400CD822A00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE741F00C57B2500D68B + 3100D68B3100D68B3100D68B3100D68B31CCFCDC90FFEEB266FFEEB266FFEEB2 + 66FFEEB266FFF4C579FFD68B31CCD68B3100D68B3100D68B3100D68B3100C57B + 2500BE741F00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE741F00BF752000C47A + 2400D1862D00D1862D00D1862D00D1862DCCFBD98DFFE3A75BFFD99D51FFD498 + 4CFFCF9347FFDEAD61FFD1862DCCD1862D00D1862D00D1862D00C47A2400BF75 + 2000BE741F00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE741F00BF752000BF75 + 2000C3792300CD822A00CD822A00CD822ACCF1CE82FFCC9044FFCC9044FFCC90 + 44FFCC9044FFDCAB5FFFCD822ACCCD822A00CD822A00C3792300BF752000BF75 + 2000BE741F00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE741F00BF752000BF75 + 2000BF752000C2782200C87D2600C87D26CCEEC97DFFCC9044FFCC9044FFCC90 + 44FFCC9044FFDBA95DFFC87D26CCC87D2600C2782200BF752000BF752000BF75 + 2000BE741F00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE741F00BF752000BF75 + 2000BF752000BF752000C1762100C37823CCECC577FFCF9241FFCF9241FFCF92 + 41FFCF9241FFDBA758FFC37823CCC1762100BF752000BF752000BF752000BF75 + 2000BE741F00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE731F99BE741FCCBE74 + 1FCCBE741FCCBE741FCCBE741FCCBE741FCCEDC26FFFD49539FFD49539FFD495 + 39FFD49539FFDEA850FFBE741FCCBE741FCCBE741FCCBE741FCCBE741FCCBE74 + 1FCCBE731F99FFFFFF00FFFFFF00FFFFFF00FFFFFF00BB701C66BA6F1CCCF1C7 + 6FFFF0C66DFFF0C56BFFEFC369FFEEC267FFEEC165FFDB9A30FFDB9A30FFDB9A + 30FFDB9A30FFE3AA46FFEAB95AFFE9B758FFE8B656FFE8B554FFE7B353FFBA6F + 1CCCBB701C66FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00B66B1966B56A + 18CCF2C462FFE3A025FFE3A025FFE3A025FFE3A025FFE3A025FFE3A025FFE3A0 + 25FFE3A025FFE3A025FFE3A025FFE3A025FFE3A025FFECB548FFB56A18CCB66B + 1966BA6F1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00B56A1800B166 + 1566B06515CCF4C354FFEBA51AFFEBA51AFFEBA51AFFEBA51AFFEBA51AFFEBA5 + 1AFFEBA51AFFEBA51AFFEBA51AFFEBA51AFFF1B73DFFB06515CCB1661566B56A + 1800BA6F1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00B56A1800B065 + 1500AD621266AC6111CCF8C145FFF3AA10FFF3AA10FFF3AA10FFF3AA10FFF3AA + 10FFF3AA10FFF3AA10FFF3AA10FFF6B931FFAC6111CCAD621266B0651500B56A + 1800BA6F1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00B56A1800B065 + 1500AC611100A85D0F66A75C0ECCFBC036FFFAAE07FFFAAE07FFFAAE07FFFAAE + 07FFFAAE07FFFAAE07FFFBBA27FFA75C0ECCA85D0F66AC611100B0651500B56A + 1800BA6F1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00B56A1800B065 + 1500AC611100A75C0E00A4590B66A3580BCCFFBF29FFFEB201FFFEB201FFFEB2 + 01FFFEB201FFFEBC1FFFA3580BCCA4590B66A75C0E00AC611100B0651500B56A + 1800BA6F1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF005D380E005B350C005833 + 0B0056310900542E0700A3580B00A0550966A05508CCFFBD20FFFFB200FFFFB2 + 00FFFFBB1AFFA05508CCA0550966A3580B00542E070000000000000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 0000000000000000000000000000502B04009D5206669C5106CCFFBB19FFFFBA + 17FF9C5106CC9D520666502B0400000000000000000000000000000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 000000000000000000040000000B00000013000000196E390377994E04CC994E + 04CC6E39037700000019000000140000000C0000000500000001000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 00000000000000000008000000160000002600000032000000336734027B6734 + 027B000000330000003200000028000000180000000900000001000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000000000 + 000000000000000000040000000B00000013000000190000001A0000001A0000 + 001A0000001A00000019000000140000000C0000000500000001000000000000 + 000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E99E3F00EA9F + 4099EA9F40CCEA9F40CBEA9F40BDEA9F409EEA9F4068E99E3F20E89D3E00E69B + 3D00E3983B00E0953800DF943700DF943700704A1C0000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E89D3E00E89D + 3E1DE89D3E90F4C36EE6FEE093FBFAD181F3F3BE67E3EAA447C8E89D3E73E69B + 3D0FE3983B00E0953800DF943700DF943700DF943700DF943700704A1C00704A + 1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E89D3E00E89D + 3E00E69B3D10E69D40AFFBD889F6FDD88CFFFCCF83FFFCD285FBF0B761E0E59A + 3CA2E3983B16E0953800DF943700DF943700DF943700DF943700DF943700DF94 + 3700FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00E89D3E00E59A + 3C00E2973A00E2973A4BEDB35DDEFDDE92FFF8C579FFF8C579FFF9CA7EFFF1BB + 67E7E1963AA2E095380FDF943700DF943700DF943700DF943700DF943700DF94 + 3700FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00DF943700DF94 + 3700DF943700DF94370BE0983DBDFCDD8FFBF6C276FFF4BD71FFF4BD71FFF6C3 + 77FFEBB15BE0DE933773DD923600DD923600DD923600DD923600DD923600DD92 + 3600FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00DA8F3400DA8F + 3400DA8F3400DA8F3400DA8F348CF4C978F0F6C77BFFF0B66AFFF0B66AFFF0B6 + 6AFFF4C376FBDE973DC8DA8F3420D98E3300D98E3300D98E3300D98E3300D98E + 3300FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D78C3100D78C + 3100D78C3100D78C3100D78C3156E7B05BE2F7CA7EFFEEB266FFEEB266FFEEB2 + 66FFF0B66AFFE7AD59E3D68B3168D68B3100D68B3100D68B3100D68B3100D68B + 3100FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00D1862D00D186 + 2D00D1862D00D1862D00D1862D36DE9F4ADAF8CE82FFEEB266FFEEB266FFEEB2 + 66FFEEB266FFEEBB6CF3D1862D9ED1862D00D1862D00D1862D00D1862D00C67B + 2500FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00C97E + 2700CD822A00CD822A00CD822A1ED5913BD4F8D084FFE3A75BFFD99D51FFD498 + 4CFFCF9347FFDDAB5FFBCD822ABDCD822A00CD822A00CD822A00C0752000BA6F + 1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00BB70 + 1C00C57A2400C87D2600C87D260DCB832DD0EDC77BFFCC9044FFCC9044FFCC90 + 44FFCC9044FFDBA85CFFC87D26CBC87D2600C87D2600BF741F00BB701C00BA6F + 1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00BB70 + 1C00BB701C00C2772200C3782303C47A25CDECC478FFCC9044FFCC9044FFCC90 + 44FFCC9044FFDAA75BFFC37823CCC3782300BE731E00BB701C00BB701C00BA6F + 1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BA6F1C00BB70 + 1C00BB701C00BB701C00BD721E00BE741FCCEAC171FFD0933FFFD0933FFFD093 + 3FFFD0933FFFDBA654FFBE741FCCBC721D00BB701C00BB701C00BB701C00BA6F + 1C00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B96E1C99BA6F + 1CCCBA6F1CCCBA6F1CCCBA6F1CCCBA6F1CCCEBBF69FFD79737FFD79737FFD797 + 37FFD79737FFDFA74BFFBA6F1CCCBA6F1CCCBA6F1CCCBA6F1CCCBA6F1CCCB96E + 1C99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B66B1966B56A + 18CCF0C365FFEFC263FFEFC061FFEEBF5FFFEDBE5DFFDF9D2BFFDF9D2BFFDF9D + 2BFFDF9D2BFFE5AA3FFFEAB652FFEAB550FFE9B44EFFE9B34DFFB56A18CCB66B + 1966FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B56A1800B166 + 1566B06515CCF2C157FFE8A31FFFE8A31FFFE8A31FFFE8A31FFFE8A31FFFE8A3 + 1FFFE8A31FFFE8A31FFFE8A31FFFE8A31FFFEEB541FFB06515CCB1661566B56A + 1800FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B56A1800B065 + 1500AD621266AC6111CCF6C048FFF0A814FFF0A814FFF0A814FFF0A814FFF0A8 + 14FFF0A814FFF0A814FFF0A814FFF4B735FFAC6111CCAD621266B0651500B56A + 1800FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B56A1800B065 + 1500AC611100A85D0F66A75C0ECCFABF38FFF8AD0AFFF8AD0AFFF8AD0AFFF8AD + 0AFFF8AD0AFFF8AD0AFFF9B929FFA75C0ECCA85D0F66AC611100B0651500B56A + 1800FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B56A1800B065 + 1500AC611100A75C0E00A4590B66A3580BCCFEBF2AFFFEB102FFFEB102FFFEB1 + 02FFFEB102FFFEBB1FFFA3580BCCA4590B66A75C0E00AC611100B0651500B56A + 1800FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF005B350C005833 + 0B0056310900542E0700A3580B00A0550966A05508CCFFBD20FFFFB200FFFFB2 + 00FFFFBB1AFFA05508CCA0550966A3580B00542E070000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 0000000000000000000000000000502B04009D5206669C5106CCFFBB19FFFFBA + 17FF9C5106CC9D520666502B0400000000000000000000000000000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000000000000000000040000000B00000013000000196E390377994E04CC994E + 04CC6E39037700000019000000140000000C0000000500000001000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 00000000000000000008000000160000002600000032000000336734027B6734 + 027B000000330000003200000028000000180000000900000001000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000000000000000000040000000B00000013000000190000001A0000001A0000 + 001A0000001A00000019000000140000000C0000000500000001000000000000 + 0000FFFFFF00FFFFFF00FFFFFF00 + } + end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index db84609c3..93413daee 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -1,6 +1,15 @@ {"version":1,"strings":[ {"hash":57972706,"name":"tmainform.caption","sourcebytes":[70,114,101,101,32,77,97,110,103,97,32,68,111,119,110,108,111,97,100,101,114],"value":"Free Manga Downloader"}, {"hash":240327891,"name":"tmainform.tsdownload.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, +{"hash":204655756,"name":"tmainform.tbdownloadresumeall.caption","sourcebytes":[82,101,115,117,109,101,32,65,108,108],"value":"Resume All"}, +{"hash":190989196,"name":"tmainform.tbdownloadstopall.caption","sourcebytes":[83,116,111,112,32,65,108,108],"value":"Stop All"}, +{"hash":235571507,"name":"tmainform.tbdownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, +{"hash":173363182,"name":"tmainform.eddownloadssearch.texthint","sourcebytes":[83,101,97,114,99,104,32,100,111,119,110,108,111,97,100,115,46,46,46],"value":"Search downloads..."}, +{"hash":131060932,"name":"tmainform.pndownloadlist.caption","sourcebytes":[112,110,68,111,119,110,108,111,97,100,76,105,115,116],"value":"pnDownloadList"}, +{"hash":14216608,"name":"tmainform.tbmidownloadmovetop.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,116,111,32,116,111,112],"value":"Move selected item(s) to top"}, +{"hash":160874656,"name":"tmainform.tbmidownloadmoveup.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,117,112],"value":"Move selected item(s) up"}, +{"hash":113368910,"name":"tmainform.tbmidownloadmovedown.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,100,111,119,110],"value":"Move selected item(s) down"}, +{"hash":268089565,"name":"tmainform.tbmidownloadmovebottom.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,116,111,32,98,111,116,116,111,109],"value":"Move selected item(s) to bottom"}, {"hash":5473489,"name":"tmainform.vtdownload.header.columns[0].text","sourcebytes":[77,97,110,103,97],"value":"Manga"}, {"hash":95062979,"name":"tmainform.vtdownload.header.columns[1].text","sourcebytes":[83,116,97,116,117,115],"value":"Status"}, {"hash":157190611,"name":"tmainform.vtdownload.header.columns[2].text","sourcebytes":[80,114,111,103,114,101,115,115],"value":"Progress"}, @@ -8,10 +17,6 @@ {"hash":230269173,"name":"tmainform.vtdownload.header.columns[4].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, {"hash":160200703,"name":"tmainform.vtdownload.header.columns[5].text","sourcebytes":[83,97,118,101,32,116,111],"value":"Save to"}, {"hash":4696756,"name":"tmainform.vtdownload.header.columns[6].text","sourcebytes":[65,100,100,101,100],"value":"Added"}, -{"hash":204655756,"name":"tmainform.tbdownloadresumeall.caption","sourcebytes":[82,101,115,117,109,101,32,65,108,108],"value":"Resume All"}, -{"hash":190989196,"name":"tmainform.tbdownloadstopall.caption","sourcebytes":[83,116,111,112,32,65,108,108],"value":"Stop All"}, -{"hash":235571507,"name":"tmainform.tbdownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, -{"hash":173363182,"name":"tmainform.eddownloadssearch.texthint","sourcebytes":[83,101,97,114,99,104,32,100,111,119,110,108,111,97,100,115,46,46,46],"value":"Search downloads..."}, {"hash":221371535,"name":"tmainform.tsinformation.caption","sourcebytes":[77,97,110,103,97,32,73,110,102,111],"value":"Manga Info"}, {"hash":206498996,"name":"tmainform.btabortupdatelist.hint","sourcebytes":[65,98,111,114,116,32,117,112,100,97,116,101,32,108,105,115,116],"value":"Abort update list"}, {"hash":158194067,"name":"tmainform.cbselectmanga.hint","sourcebytes":[70,111,114,32,109,111,114,101,32,109,97,110,103,97,32,115,105,116,101,115,44,32,112,108,101,97,115,101,32,103,111,32,116,111,32,79,112,116,105,111,110,115,45,62,77,97,110,103,97,32,115,105,116,101,115],"value":"For more manga sites, please go to Options->Manga sites"}, @@ -161,6 +166,7 @@ {"hash":117603058,"name":"tmainform.cboptionenableloadcover.caption","sourcebytes":[69,110,97,98,108,101,32,108,111,97,100,32,109,97,110,103,97,32,99,111,118,101,114],"value":"Enable load manga cover"}, {"hash":150918338,"name":"tmainform.cboptionshowdownloadtoolbardeleteall.caption","sourcebytes":[83,104,111,119,32,34,68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115,34,32,105,110,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show \"Delete all completed tasks\" in downloads toolbar"}, {"hash":81333124,"name":"tmainform.cboptionshowballoonhint.caption","sourcebytes":[83,104,111,119,32,98,97,108,108,111,111,110,32,104,105,110,116],"value":"Show balloon hint"}, +{"hash":185449858,"name":"tmainform.cboptionshowdownloadtoolbarleft.caption","sourcebytes":[83,104,111,119,32,108,101,102,116,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show left downloads toolbar"}, {"hash":199270675,"name":"tmainform.tsconnections.caption","sourcebytes":[67,111,110,110,101,99,116,105,111,110,115],"value":"Connections"}, {"hash":125299305,"name":"tmainform.cboptionuseproxy.caption","sourcebytes":[85,115,101,32,112,114,111,120,121],"value":"Use proxy"}, {"hash":66921287,"name":"tmainform.gboptionproxy.caption","sourcebytes":[80,114,111,120,121,32,99,111,110,102,105,103],"value":"Proxy config"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ef3675db8..68d4d11c6 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -59,6 +59,7 @@ TMainForm = class(TForm) cbOptionRemoveMangaNameFromChapter: TCheckBox; cbOptionShowDownloadMangalistDialog: TCheckBox; cbOptionShowDownloadToolbar: TCheckBox; + cbOptionShowDownloadToolbarLeft: TCheckBox; cbOptionShowDownloadToolbarDeleteAll: TCheckBox; cbOptionUpdateListNoMangaInfo: TCheckBox; cbOptionDigitVolume: TCheckBox; @@ -82,6 +83,7 @@ TMainForm = class(TForm) edSaveTo: TEditButton; edURL: TEditButton; edWebsitesSearch: TEditButton; + IconDLLeft: TImageList; lbLogFileName: TLabel; lbOptionRetryFailedTask: TLabel; lbOptionFilenameCustomRenameHint: TLabel; @@ -119,6 +121,7 @@ TMainForm = class(TForm) miChapterListHideDownloaded: TMenuItem; miAbortSilentThread: TMenuItem; mmChangelog: TMemo; + pnDownloadList: TPanel; pnAboutComp: TPanel; pcInfo: TPageControl; psInfo: TPairSplitter; @@ -141,6 +144,11 @@ TMainForm = class(TForm) sbWebsiteOptions: TScrollBox; btDownloadSplit: TSpeedButton; seOptionRetryFailedTask: TSpinEdit; + ToolBarDownloadLeft: TToolBar; + tbmiDownloadMoveTop: TToolButton; + tbmiDownloadMoveUp: TToolButton; + tbmiDownloadMoveDown: TToolButton; + tbmiDownloadMoveBottom: TToolButton; tsInfoManga: TTabSheet; tsinfoFilterAdv: TTabSheet; tsCustomColor: TTabSheet; @@ -468,6 +476,10 @@ TMainForm = class(TForm) procedure miFavoritesEnableClick(Sender: TObject); procedure miFavoritesRenameClick(Sender: TObject); procedure miFavoritesTransferWebsiteClick(Sender: TObject); + procedure tbmiDownloadMoveBottomClick(Sender: TObject); + procedure tbmiDownloadMoveDownClick(Sender: TObject); + procedure tbmiDownloadMoveTopClick(Sender: TObject); + procedure tbmiDownloadMoveUpClick(Sender: TObject); procedure tmAnimateMangaInfoTimer(Sender: TObject); procedure tmCheckFavoritesTimer(Sender: TObject); procedure tmExitCommandTimer(Sender: TObject); @@ -1599,6 +1611,34 @@ procedure TMainForm.miFavoritesTransferWebsiteClick(Sender: TObject); end; end; +procedure TMainForm.tbmiDownloadMoveTopClick(Sender: TObject); +begin + if vtDownload.SelectedCount = 0 then Exit; + vtDownloadMoveItems(0, dmAbove); +end; + +procedure TMainForm.tbmiDownloadMoveUpClick(Sender: TObject); +var + p: Cardinal; +begin + if vtDownload.SelectedCount = 0 then Exit; + p := vtDownload.GetFirstSelected()^.Index; + if p > 0 then + vtDownloadMoveItems(p - 1, dmAbove); +end; + +procedure TMainForm.tbmiDownloadMoveDownClick(Sender: TObject); +begin + if vtDownload.SelectedCount = 0 then Exit; + vtDownloadMoveItems(vtDownload.GetFirstSelected()^.Index, dmBelow); +end; + +procedure TMainForm.tbmiDownloadMoveBottomClick(Sender: TObject); +begin + if vtDownload.SelectedCount = 0 then Exit; + vtDownloadMoveItems(vtDownload.RootNodeCount - 1, dmBelow); +end; + procedure TMainForm.tmAnimateMangaInfoTimer(Sender: TObject); begin gifWaiting.Update(pbWait.Canvas, gifWaitingRect); @@ -4828,6 +4868,7 @@ procedure TMainForm.LoadOptions; // view cbOptionShowDownloadToolbar.Checked := ReadBool('view', 'ShowDownloadsToolbar', True); + cbOptionShowDownloadToolbarLeft.Checked := ReadBool('view', 'ShowDownloadsToolbarLeft', True); cbOptionShowDownloadToolbarDeleteAll.Checked := ReadBool('view', 'ShowDownloadsToolbarDeleteAll', False); cbOptionEnableLoadCover.Checked := ReadBool('view', 'LoadMangaCover', True); cbOptionShowBalloonHint.Checked := ReadBool('view', 'ShowBalloonHint', OptionShowBalloonHint); @@ -4974,6 +5015,7 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); // view WriteBool('view', 'ShowDownloadsToolbar', cbOptionShowDownloadToolbar.Checked); + WriteBool('view', 'ShowDownloadsToolbarLeft', cbOptionShowDownloadToolbarLeft.Checked); WriteBool('view', 'ShowDownloadsToolbarDeleteAll', cbOptionShowDownloadToolbarDeleteAll.Checked); WriteBool('view', 'LoadMangaCover', cbOptionEnableLoadCover.Checked); WriteBool('view', 'ShowBalloonHint', cbOptionShowBalloonHint.Checked); @@ -5117,6 +5159,7 @@ procedure TMainForm.ApplyOptions; //view ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; + ToolBarDownloadLeft.Visible := cbOptionShowDownloadToolbarLeft.Checked; tbDownloadDeleteCompleted.Visible := cbOptionShowDownloadToolbarDeleteAll.Checked; tbSeparator1.Visible := tbDownloadDeleteCompleted.Visible; ShowDropTarget(ckDropTarget.Checked); diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index f9e691f55..df2c6f842 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -755,6 +755,10 @@ msgstr "Zeige Download-Symbolleiste" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Zeige \"Lösche alle abgeschlossenen Aufgaben\" in Download-Symbolleiste" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "FMD beenden" @@ -1789,6 +1793,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Aktualisiere Manga-Liste" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Have all genre checked" @@ -1823,6 +1831,22 @@ msgstr "Alle fortsetzen" msgid "Stop All" msgstr "Alle anhalten" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Collapse All" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 39eba0a1c..186e4c942 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -759,6 +759,10 @@ msgstr "Εμφάνιση εργαλειοθήκης λήψεων" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Εμφάνιση \"Διαγραφή όλων των ολοκληρωμένων εργασιών\" στην εργαλειοθήκη λήψεων" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Έξοδος του FMD" @@ -1844,6 +1848,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Ενημέρωση λίστας manga" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Όλα τα είδη που έχουν σημανθεί" @@ -1878,6 +1886,22 @@ msgstr "Συνέχιση όλων" msgid "Stop All" msgstr "Διακοπή όλων" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Σύμπτυξη όλων" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 86bd1c226..7cbbafbbe 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1,16 +1,5 @@ msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: \n" -"POT-Creation-Date: \n" -"PO-Revision-Date: \n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: en_US\n" -"X-Generator: Poedit 2.0.1\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +msgstr "Content-Type: text/plain; charset=UTF-8" #: batoto.rs_serverselection msgid "Image server:" @@ -45,7 +34,6 @@ msgid "Download original image(require ExHentai account)" msgstr "Download original image(require ExHentai account)" #: ehentai.rs_settingsimagesize -#| msgid "Image size" msgid "Image size:" msgstr "Image size:" @@ -289,7 +277,6 @@ msgid "Mode: Filtered (%d)" msgstr "Mode: Filtered (%d)" #: frmmain.rs_modesearching -#| msgid "Searching..." msgctxt "frmmain.rs_modesearching" msgid "Mode: Searching..." msgstr "Mode: Searching..." @@ -309,6 +296,10 @@ msgid "" "CBZ\n" "PDF\n" msgstr "" +"None\n" +"ZIP\n" +"CBZ\n" +"PDF\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -424,25 +415,22 @@ msgid "Refresh" msgstr "Refresh" #: taccountmanagerform.vtaccountlist.header.columns[1].text -#| msgid "Username" -msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" msgstr "Website" #: taccountmanagerform.vtaccountlist.header.columns[2].text -#| msgid "Status" -msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[2].TEXT" msgid "Username" msgstr "Username" #: taccountmanagerform.vtaccountlist.header.columns[3].text -#| msgid "Status" -msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[3].TEXT" msgid "Status" msgstr "Status" #: taccountsetform.btcancel.caption -msgctxt "taccountsetform.btcancel.caption" +msgctxt "TACCOUNTSETFORM.BTCANCEL.CAPTION" msgid "Cancel" msgstr "Cancel" @@ -455,30 +443,27 @@ msgid "Show password" msgstr "Show password" #: taccountsetform.edpassword.texthint -msgctxt "taccountsetform.edpassword.texthint" +msgctxt "TACCOUNTSETFORM.EDPASSWORD.TEXTHINT" msgid "Password" msgstr "Password" #: taccountsetform.edusername.texthint -#| msgid "Status" -msgctxt "taccountsetform.edusername.texthint" +msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" msgid "Username" msgstr "Username" #: taccountsetform.label1.caption -#| msgid "Username" -msgctxt "taccountsetform.label1.caption" +msgctxt "TACCOUNTSETFORM.LABEL1.CAPTION" msgid "Website" msgstr "Website" #: taccountsetform.label2.caption -#| msgid "Status" -msgctxt "taccountsetform.label2.caption" +msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" msgid "Username" msgstr "Username" #: taccountsetform.label3.caption -msgctxt "taccountsetform.label3.caption" +msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" msgid "Password" msgstr "Password" @@ -503,7 +488,7 @@ msgid "Manga list" msgstr "Manga list" #: tformdroptarget.miaddtofavorites.caption -msgctxt "tformdroptarget.miaddtofavorites.caption" +msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" msgstr "Add to favorites" @@ -512,7 +497,7 @@ msgid "&Close" msgstr "&Close" #: tformdroptarget.midownloadall.caption -msgctxt "tformdroptarget.midownloadall.caption" +msgctxt "TFORMDROPTARGET.MIDOWNLOADALL.CAPTION" msgid "Download all" msgstr "Download all" @@ -548,7 +533,7 @@ msgid "Domdomsoft Manga Downloader" msgstr "Domdomsoft Manga Downloader" #: timportfavorites.edpath.texthint -msgctxt "timportfavorites.edpath.texthint" +msgctxt "TIMPORTFAVORITES.EDPATH.TEXTHINT" msgid "Path to the software (e.g. C:\\MangaDownloader)" msgstr "Path to the software (e.g. C:\\MangaDownloader)" @@ -566,8 +551,7 @@ msgid "Add to favorites" msgstr "Add to favorites" #: tmainform.btchecklatestversion.caption -#| msgid "Check for new version" -msgctxt "tmainform.btchecklatestversion.caption" +msgctxt "TMAINFORM.BTCHECKLATESTVERSION.CAPTION" msgid "Check for latest version" msgstr "Check for latest version" @@ -651,7 +635,7 @@ msgid "Search only new manga" msgstr "Search only new manga" #: tmainform.cboptionautocheckfavdownload.caption -msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVDOWNLOAD.CAPTION" msgid "Automatic download after finish checking" msgstr "Automatic download after finish checking" @@ -660,18 +644,16 @@ msgid "Auto check for new chapter in an interval" msgstr "Auto check for new chapter in an interval" #: tmainform.cboptionautocheckfavremovecompletedmanga.caption -msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVREMOVECOMPLETEDMANGA.CAPTION" msgid "Automatic remove completed manga from Favorites" msgstr "Automatic remove completed manga from Favorites" #: tmainform.cboptionautocheckfavstartup.caption -#| msgid "Automatic check for new chapter at startup" msgid "Auto check for new chapter at startup" msgstr "Auto check for new chapter at startup" #: tmainform.cboptionautochecklatestversion.caption -#| msgid "Check for new version " -msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" msgid "Auto check for latest version " msgstr "Auto check for latest version " @@ -680,8 +662,7 @@ msgid "Open Favorites at startup" msgstr "Open Favorites at startup" #: tmainform.cboptionchangeunicodecharacter.caption -#| msgid "Change all all character to" -msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" msgid "Replace all unicode character with" msgstr "Replace all unicode character with" @@ -706,7 +687,7 @@ msgid "Auto generate chapter folder" msgstr "Auto generate chapter folder" #: tmainform.cboptiongeneratemangafolder.caption -msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgctxt "TMAINFORM.CBOPTIONGENERATEMANGAFOLDER.CAPTION" msgid "Auto generate folder based on manga's name" msgstr "Auto generate folder based on manga's name" @@ -754,6 +735,10 @@ msgstr "Show downloads toolbar" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Show \"Delete all completed tasks\" in downloads toolbar" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "Show left downloads toolbar" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Exit FMD" @@ -1108,7 +1093,6 @@ msgid "This work usually involves intimate relationships between women." msgstr "This work usually involves intimate relationships between women." #: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption -#| msgid "Always start from failed chapters when task start" msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "Always start task from failed chapters" @@ -1118,7 +1102,6 @@ msgid "Input custom genres, separated by comma" msgstr "Input custom genres, separated by comma" #: tmainform.eddownloadssearch.texthint -#| msgid "Search favorites..." msgctxt "tmainform.eddownloadssearch.texthint" msgid "Search downloads..." msgstr "Search downloads..." @@ -1139,7 +1122,7 @@ msgid "Author" msgstr "Author" #: tmainform.edfiltermangainfochapters.texthint -msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgctxt "TMAINFORM.EDFILTERMANGAINFOCHAPTERS.TEXTHINT" msgid "Filter" msgstr "Filter" @@ -1158,7 +1141,7 @@ msgid "Search title..." msgstr "Search title..." #: tmainform.edoptionchaptercustomrename.texthint -msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgctxt "TMAINFORM.EDOPTIONCHAPTERCUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "Custom rename" @@ -1167,19 +1150,17 @@ msgid "Default download path" msgstr "Default download path" #: tmainform.edoptionexternalparams.texthint -#| msgid "External program parameters" -msgctxt "tmainform.edoptionexternalparams.texthint" +msgctxt "TMAINFORM.EDOPTIONEXTERNALPARAMS.TEXTHINT" msgid "External program parameters" msgstr "External program parameters" #: tmainform.edoptionexternalpath.texthint -#| msgid "External program parameters" -msgctxt "tmainform.edoptionexternalpath.texthint" +msgctxt "TMAINFORM.EDOPTIONEXTERNALPATH.TEXTHINT" msgid "External program path" msgstr "External program path" #: tmainform.edoptionfilenamecustomrename.texthint -msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgctxt "TMAINFORM.EDOPTIONFILENAMECUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "Custom rename" @@ -1188,7 +1169,7 @@ msgid "Proxy host/IP" msgstr "Proxy host/IP" #: tmainform.edoptionmangacustomrename.texthint -msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgctxt "TMAINFORM.EDOPTIONMANGACUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "Custom rename" @@ -1210,8 +1191,7 @@ msgid "Input URL here" msgstr "Input URL here" #: tmainform.edwebsitessearch.texthint -#| msgid "Search..." -msgctxt "tmainform.edwebsitessearch.texthint" +msgctxt "TMAINFORM.EDWEBSITESSEARCH.TEXTHINT" msgid "Search website..." msgstr "Search website..." @@ -1312,23 +1292,22 @@ msgid "Mode: Show all (0)" msgstr "Mode: Show all (0)" #: tmainform.lboptionautocheckfavintervalminutes.caption -msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgctxt "TMAINFORM.LBOPTIONAUTOCHECKFAVINTERVALMINUTES.CAPTION" msgid "Auto check for new chapter every %d minutes" msgstr "Auto check for new chapter every %d minutes" #: tmainform.lboptionchaptercustomrename.caption -#| msgid "Chapter folder name:" -msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAME.CAPTION" msgid "Chapter name:" msgstr "Chapter name:" #: tmainform.lboptionchaptercustomrenamehint.caption -msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "[?]" #: tmainform.lboptionchaptercustomrenamehint.hint -msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.HINT" msgid "" "%WEBSITE% : Website name\n" "%MANGA% : Manga title\n" @@ -1363,7 +1342,7 @@ msgid "Parameters:" msgstr "Parameters:" #: tmainform.lboptionexternalparamshint.caption -msgctxt "tmainform.lboptionexternalparamshint.caption" +msgctxt "TMAINFORM.LBOPTIONEXTERNALPARAMSHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1372,7 +1351,7 @@ msgid "Filename:" msgstr "Filename:" #: tmainform.lboptionfilenamecustomrenamehint.caption -msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgctxt "TMAINFORM.LBOPTIONFILENAMECUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1407,12 +1386,12 @@ msgid "After download finish:" msgstr "After download finish:" #: tmainform.lboptionmangacustomrename.caption -msgctxt "tmainform.lboptionmangacustomrename.caption" +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAME.CAPTION" msgid "Manga folder name:" msgstr "Manga folder name:" #: tmainform.lboptionmangacustomrenamehint.caption -msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1435,17 +1414,14 @@ msgstr "" "Manga folder name must have at least %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" msgstr "Number of downloaded tasks at the same time" #: tmainform.lboptionmaxretry.caption -#| msgid "Number of retry times if tasks have download problems (0 = always retry)" msgid "Number of retry times if tasks have download problems (-1 = always retry)" msgstr "Number of retry times if tasks have download problems (-1 = always retry)" #: tmainform.lboptionmaxthread.caption -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" msgstr "Number of downloaded files per task at the same time" @@ -1468,7 +1444,7 @@ msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" msgstr "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" #: tmainform.lboptionpdfqualityhint.caption -msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgctxt "TMAINFORM.LBOPTIONPDFQUALITYHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1549,7 +1525,7 @@ msgid "Descending" msgstr "Descending" #: tmainform.michapterlistfilter.caption -msgctxt "tmainform.michapterlistfilter.caption" +msgctxt "TMAINFORM.MICHAPTERLISTFILTER.CAPTION" msgid "Filter" msgstr "Filter" @@ -1558,7 +1534,6 @@ msgid "Hide downloaded chapters" msgstr "Hide downloaded chapters" #: tmainform.michapterlisthighlight.caption -#| msgid "Highlight download chapters" msgid "Highlight downloaded chapters" msgstr "Highlight downloaded chapters" @@ -1639,7 +1614,7 @@ msgid "Change \"Save to\"" msgstr "Change \"Save to\"" #: tmainform.mifavoriteschecknewchapter.caption -msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgctxt "TMAINFORM.MIFAVORITESCHECKNEWCHAPTER.CAPTION" msgid "Check for new chapter" msgstr "Check for new chapter" @@ -1718,7 +1693,7 @@ msgid "After download finish" msgstr "After download finish" #: tmainform.mitrayexit.caption -msgctxt "tmainform.mitrayexit.caption" +msgctxt "TMAINFORM.MITRAYEXIT.CAPTION" msgid "Exit" msgstr "Exit" @@ -1748,7 +1723,7 @@ msgid "Resume all" msgstr "Resume all" #: tmainform.mitrayshowdropbox.caption -msgctxt "tmainform.mitrayshowdropbox.caption" +msgctxt "TMAINFORM.MITRAYSHOWDROPBOX.CAPTION" msgid "Show Drop Box" msgstr "Show Drop Box" @@ -1761,7 +1736,7 @@ msgid "Download all lists from server at once" msgstr "Download all lists from server at once" #: tmainform.mnfiltergenreallcheck.caption -msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgctxt "TMAINFORM.MNFILTERGENREALLCHECK.CAPTION" msgid "Check all" msgstr "Check all" @@ -1770,7 +1745,7 @@ msgid "Indeterminate all" msgstr "Indeterminate all" #: tmainform.mnfiltergenrealluncheck.caption -msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgctxt "TMAINFORM.MNFILTERGENREALLUNCHECK.CAPTION" msgid "Uncheck all" msgstr "Uncheck all" @@ -1787,6 +1762,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Update manga list" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "pnDownloadList" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Have all genre checked" @@ -1821,6 +1800,22 @@ msgstr "Resume All" msgid "Stop All" msgstr "Stop All" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "Move selected item(s) to bottom" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "Move selected item(s) down" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "Move selected item(s) to top" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "Move selected item(s) up" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Collapse All" @@ -1915,7 +1910,7 @@ msgid "Advanced" msgstr "Advanced" #: tmainform.tswebsiteoptions.caption -msgctxt "tmainform.tswebsiteoptions.caption" +msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" msgid "Options" msgstr "Options" @@ -1925,7 +1920,7 @@ msgid "Websites" msgstr "Websites" #: tmainform.tswebsiteselection.caption -msgctxt "tmainform.tswebsiteselection.caption" +msgctxt "TMAINFORM.TSWEBSITESELECTION.CAPTION" msgid "Websites" msgstr "Websites" @@ -2018,13 +2013,11 @@ msgid "&Now" msgstr "&Now" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Cancel" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" @@ -2058,14 +2051,11 @@ msgid "Valid" msgstr "Valid" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Website" +msgstr "Title" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Website" @@ -2087,17 +2077,17 @@ msgstr "" "FMD will be closed to finish the update.\n" #: twebsiteoptionadvancedform.menuitem1.caption -msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM1.CAPTION" msgid "Add" msgstr "Add" #: twebsiteoptionadvancedform.menuitem2.caption -msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM2.CAPTION" msgid "Edit" msgstr "Edit" #: twebsiteoptionadvancedform.menuitem4.caption -msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM4.CAPTION" msgid "Delete" msgstr "Delete" @@ -2111,7 +2101,7 @@ msgid "Directory page number" msgstr "Directory page number" #: twebsiteoptionadvancedform.tsdownloads.caption -msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.TSDOWNLOADS.CAPTION" msgid "Downloads" msgstr "Downloads" @@ -2133,17 +2123,17 @@ msgid "User Agent" msgstr "User Agent" #: twebsiteoptionadvancedform.vtcookies.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtcookies.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[1].TEXT" msgid "Cookies" msgstr "Cookies" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTDOWNLOADMAXTHREADSPERTASK.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" @@ -2153,32 +2143,32 @@ msgid "Value" msgstr "Value" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[1].TEXT" msgid "Value" msgstr "Value" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[1].TEXT" msgid "Value" msgstr "Value" #: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[1].TEXT" msgid "User Agent" msgstr "User Agent" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index c28437197..ec5592f26 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -743,6 +743,10 @@ msgstr "Mostrar Barra de Herramientas de Descargas" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Mostrar \"Eliminar Todas las Tareas Completadas\" en la Barra de Herramientas de Descargas" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Salir de FMD" @@ -1766,6 +1770,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Actualizar Lista de Manga" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Tener Todos los Géneros Marcados" @@ -1800,6 +1808,22 @@ msgstr "Reanudar Todo" msgid "Stop All" msgstr "Detener Todo" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Desplegar Todo" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index b1496a637..1abf877fe 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -743,6 +743,10 @@ msgstr "Tampilkan toolbar unduhan" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Tampilkan \"Hapus semua unduhan selesai\" di toolbar unduhan" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Tutup FMD" @@ -1766,6 +1770,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Perbarui daftar komik" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Memiliki semua genre yang dicentang" @@ -1800,6 +1808,22 @@ msgstr "Lanjutkan semua" msgid "Stop All" msgstr "Hentikan semua" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Lipat semua" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 88d1788f5..cf9bd9493 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -750,6 +750,10 @@ msgstr "Pokaż pasek pobierania" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Wyjdź z FMD" @@ -1786,6 +1790,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Aktualizacja listy manga" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Miej wszystkie gatunki zaznaczone" @@ -1820,6 +1828,22 @@ msgstr "Wznów wszystkie" msgid "Stop All" msgstr "Zatrzymaj wszystkie" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Zwiń wszystkie" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 86ea4398c..3b33e1382 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -702,6 +702,10 @@ msgstr "" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "" @@ -1691,6 +1695,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "" @@ -1725,6 +1733,22 @@ msgstr "" msgid "Stop All" msgstr "" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 674f01ad0..5b170e2f4 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -754,6 +754,10 @@ msgstr "Exibir Barra de Ferramentas de Downloads" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Exibir \"Apagar todas tarefas concluídas\" na barra de ferramentas" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Sair do FMD" @@ -1787,6 +1791,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Atualizar lista de mangá" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Todos os gêneros marcados" @@ -1821,6 +1829,22 @@ msgstr "Resumir Tudo" msgid "Stop All" msgstr "Parar Tudo" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Agrupar Tudo" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 32077d330..9587087c9 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -745,6 +745,10 @@ msgstr "Показать панель загрузок" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "Показать \"Удалить все завершенные задачи\" в панели загрузки" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "Выход из программы" @@ -1768,6 +1772,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Обновить список манги" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Содержит все отмеченные жанры" @@ -1802,6 +1810,22 @@ msgstr "Продолжить все" msgid "Stop All" msgstr "Остановить все" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Свернуть все" @@ -2328,3 +2352,4 @@ msgstr "Синхронизацияе данных" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Обновление списка" + diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index ca9d2eabf..1ce9e8e3d 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -759,6 +759,10 @@ msgstr "İndirmeler araç çubuğunu göster" msgid "Show \"Delete all completed tasks\" in downloads toolbar" msgstr "\"Tüm tamamlanmış görevleri sil\" seçeneğini indirmeler araç çubuğunda göster" +#: tmainform.cboptionshowdownloadtoolbarleft.caption +msgid "Show left downloads toolbar" +msgstr "" + #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" msgstr "FMD'den çık" @@ -1788,6 +1792,10 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Manga listesini güncelle" +#: tmainform.pndownloadlist.caption +msgid "pnDownloadList" +msgstr "" + #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Tüm türleri seç" @@ -1822,6 +1830,22 @@ msgstr "Tümüne Devam Et" msgid "Stop All" msgstr "Tümünü Durdur" +#: tmainform.tbmidownloadmovebottom.hint +msgid "Move selected item(s) to bottom" +msgstr "" + +#: tmainform.tbmidownloadmovedown.hint +msgid "Move selected item(s) down" +msgstr "" + +#: tmainform.tbmidownloadmovetop.hint +msgid "Move selected item(s) to top" +msgstr "" + +#: tmainform.tbmidownloadmoveup.hint +msgid "Move selected item(s) up" +msgstr "" + #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" msgstr "Tümünü Daralt" @@ -2348,3 +2372,4 @@ msgstr "Veri eşitleniyor" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Liste güncelleniyor" + From ee6b6eef2a045c0cc769ce143feb1a0694988717 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 10:22:59 +0800 Subject: [PATCH 2062/2794] update changelog --- changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.txt b/changelog.txt index 6c6bcb3a1..1e67b8208 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,8 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.133.0 (xx-xx-2018) +[+] Added left download toolbar to move selected download(s) +[*] View manga info preserve saveto location from download or favorite [+] Added WorldThree [EN-SC] [+] Added PsychoPlay [EN-SC] [+] Added MangaZukiRaws [Raws] From c6d090507d0128d58ffa70e185ff28742f6aa3b0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 12:03:22 +0800 Subject: [PATCH 2063/2794] luaxquery fix get with ixqvalue param --- baseunits/lua/luaXQuery.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index b5702e306..f3a0d15d4 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -54,7 +54,7 @@ function xquery_xpath(L: Plua_State): Integer; cdecl; begin u := TUserData(luaClassGetObject(L)); if lua_gettop(L) = 2 then - x := u.XPath(lua_tostring(L, 1), IXQValue(PPointer(lua_touserdata(L, 2))^)) + x := u.XPath(lua_tostring(L, 1), TLuaIXQValue(PPointer(lua_touserdata(L, 2))^).FIXQValue) else x := u.XPath(lua_tostring(L, 1)); luaIXQValuePush(L, TLuaIXQValue.Create(x)); @@ -82,7 +82,7 @@ function xquery_xpathstringall(L: Plua_State): Integer; cdecl; case lua_gettop(L) of 2: u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^)); 3: u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), - IXQValue(PPointer(lua_touserdata(L, 2))^)); + TLuaIXQValue(PPointer(lua_touserdata(L, 2))^).FIXQValue); end; Result := 0; end; @@ -97,7 +97,7 @@ function xquery_xpathhrefall(L: Plua_State): Integer; cdecl; TStrings(PPointer(lua_touserdata(L, 3))^)); 4: u.XPathHREFAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), TStrings(PPointer(lua_touserdata(L, 3))^), - IXQValue(PPointer(lua_touserdata(L, 4))^)) + TLuaIXQValue(PPointer(lua_touserdata(L, 4))^).FIXQValue) end; Result := 0; end; @@ -112,7 +112,7 @@ function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; TStrings(PPointer(lua_touserdata(L, 3))^)); 4: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), TStrings(PPointer(lua_touserdata(L, 3))^), - IXQValue(PPointer(lua_touserdata(L, 4))^)) + TLuaIXQValue(PPointer(lua_touserdata(L, 4))^).FIXQValue) end; Result := 0; end; From 8b04e868c788a7219e7407702d7e8e6a15466e8f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 12:33:54 +0800 Subject: [PATCH 2064/2794] fix luaxquery xpathstringall --- baseunits/lua/LuaBaseUnit.pas | 2 +- baseunits/lua/LuaUtils.pas | 7 ++++ baseunits/lua/luaXQuery.pas | 71 +++++++++++++++++++++++++---------- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 061cf64da..a0a63deb0 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -38,7 +38,7 @@ function lua_invertstrings(L: Plua_State): Integer; cdecl; begin Result := 0; for i := 1 to lua_gettop(L) do - InvertStrings(TStringList(PPointer(lua_touserdata(L, i))^)); + InvertStrings(TStringList(luaGetUserData(L, i))); end; function lua_mangainfostatusifpos(L: Plua_State): Integer; cdecl; diff --git a/baseunits/lua/LuaUtils.pas b/baseunits/lua/LuaUtils.pas index 083100a43..d565b3aaa 100644 --- a/baseunits/lua/LuaUtils.pas +++ b/baseunits/lua/LuaUtils.pas @@ -25,6 +25,8 @@ procedure luaPushStringGlobal(L: Plua_State; Name: PAnsiChar; S: String); procedure luaPushIntegerGlobal(L: Plua_State; Name: PAnsiChar; I: Integer); procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); +function luaGetUserData(L: Plua_State; idx: Integer): Pointer; inline; + function LuaToString(L: Plua_State; Idx: Integer): String; function LuaStackToString(L: Plua_State): String; @@ -110,6 +112,11 @@ procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); lua_setglobal(L, Name); end; +function luaGetUserData(L: Plua_State; idx: Integer): Pointer; +begin + Result := PPointer(lua_touserdata(L, idx))^; +end; + function LuaToString(L: Plua_State; Idx: Integer): String; begin if lua_isuserdata(L, Idx) then diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index f3a0d15d4..74c9fffd5 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -7,8 +7,8 @@ interface uses Classes, SysUtils, lua53, XQueryEngineHTML, xquery; -procedure luaXQueryPush(L: Plua_State; Obj: TXQueryEngineHTML; - Name: String = ''; AutoFree: Boolean = False); inline; +procedure luaXQueryPush(L: Plua_State; Obj: TXQueryEngineHTML; Name: String = ''; + AutoFree: Boolean = False); inline; implementation @@ -54,7 +54,7 @@ function xquery_xpath(L: Plua_State): Integer; cdecl; begin u := TUserData(luaClassGetObject(L)); if lua_gettop(L) = 2 then - x := u.XPath(lua_tostring(L, 1), TLuaIXQValue(PPointer(lua_touserdata(L, 2))^).FIXQValue) + x := u.XPath(lua_tostring(L, 1), TLuaIXQValue(luaGetUserData(L, 2)).FIXQValue) else x := u.XPath(lua_tostring(L, 1)); luaIXQValuePush(L, TLuaIXQValue.Create(x)); @@ -68,7 +68,7 @@ function xquery_xpathstring(L: Plua_State): Integer; cdecl; u := TUserData(luaClassGetObject(L)); if lua_gettop(L) = 2 then lua_pushstring(L, u.XPathString(lua_tostring(L, 1), - TLuaIXQValue(PPointer(lua_touserdata(L, 2))^).FIXQValue)) + TLuaIXQValue(luaGetUserData(L, 2)).FIXQValue)) else lua_pushstring(L, u.XPathString(lua_tostring(L, 1))); Result := 1; @@ -77,14 +77,47 @@ function xquery_xpathstring(L: Plua_State): Integer; cdecl; function xquery_xpathstringall(L: Plua_State): Integer; cdecl; var u: TUserData; + t: Integer; begin u := TUserData(luaClassGetObject(L)); - case lua_gettop(L) of - 2: u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^)); - 3: u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), - TLuaIXQValue(PPointer(lua_touserdata(L, 2))^).FIXQValue); - end; - Result := 0; + t := lua_gettop(L); + if t > 1 then + if t = 2 then + begin + if lua_isstring(L, 2) then + begin + lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; + end + else + if lua_isuserdata(L, 2) then + begin + u.XPathStringAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2))); + Result := 0; + end; + end + else + if t = 3 then + begin + if lua_isstring(L, 2) then + begin + lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1), lua_tostring(L, 2), + TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue)); + Result := 1; + end + else + if lua_isuserdata(L, 2) then + begin + u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue); + Result := 0; + end; + end + else + begin + lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1))); + Result := 1; + end; end; function xquery_xpathhrefall(L: Plua_State): Integer; cdecl; @@ -93,11 +126,10 @@ function xquery_xpathhrefall(L: Plua_State): Integer; cdecl; begin u := TUserData(luaClassGetObject(L)); case lua_gettop(L) of - 3: u.XPathHREFAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), - TStrings(PPointer(lua_touserdata(L, 3))^)); - 4: u.XPathHREFAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), - TStrings(PPointer(lua_touserdata(L, 3))^), - TLuaIXQValue(PPointer(lua_touserdata(L, 4))^).FIXQValue) + 3: u.XPathHREFAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), + TStrings(luaGetUserData(L, 2))); + 4: u.XPathHREFAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), + TStrings(luaGetUserData(L, 3)), TLuaIXQValue(luaGetUserData(L, 4)).FIXQValue) end; Result := 0; end; @@ -110,9 +142,8 @@ function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; case lua_gettop(L) of 3: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), TStrings(PPointer(lua_touserdata(L, 3))^)); - 4: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), - TStrings(PPointer(lua_touserdata(L, 3))^), - TLuaIXQValue(PPointer(lua_touserdata(L, 4))^).FIXQValue) + 4: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), + TStrings(luaGetUserData(L, 3)), TLuaIXQValue(luaGetUserData(L, 4)).FIXQValue) end; Result := 0; end; @@ -139,8 +170,8 @@ procedure luaXQueryAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddFunction(L, MetaTable, UserData, methods); end; -procedure luaXQueryPush(L: Plua_State; Obj: TXQueryEngineHTML; - Name: String; AutoFree: Boolean); +procedure luaXQueryPush(L: Plua_State; Obj: TXQueryEngineHTML; Name: String; + AutoFree: Boolean); begin luaClassPushObject(L, Obj, Name, AutoFree, @luaXQueryAddMetaTable); end; From 9ee516cbbc45f1fe04126570a3da0e286b18b8e3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 12:38:03 +0800 Subject: [PATCH 2065/2794] fix luaxquery xpathstringall --- baseunits/lua/luaXQuery.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index 74c9fffd5..b3cb5d3d9 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -108,7 +108,7 @@ function xquery_xpathstringall(L: Plua_State): Integer; cdecl; else if lua_isuserdata(L, 2) then begin - u.XPathStringAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), + u.XPathStringAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue); Result := 0; end; @@ -140,8 +140,8 @@ function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; begin u := TUserData(luaClassGetObject(L)); case lua_gettop(L) of - 3: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(PPointer(lua_touserdata(L, 2))^), - TStrings(PPointer(lua_touserdata(L, 3))^)); + 3: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), + TStrings(luaGetUserData(L, 2))); 4: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), TStrings(luaGetUserData(L, 3)), TLuaIXQValue(luaGetUserData(L, 4)).FIXQValue) end; From 63c841b8f02628681135889f9880cea28c7d8485 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 13:51:07 +0800 Subject: [PATCH 2066/2794] luadownloadtask, publish needed object --- baseunits/lua/LuaDownloadTask.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/lua/LuaDownloadTask.pas b/baseunits/lua/LuaDownloadTask.pas index 82409af1b..6344caebb 100644 --- a/baseunits/lua/LuaDownloadTask.pas +++ b/baseunits/lua/LuaDownloadTask.pas @@ -17,9 +17,9 @@ procedure luaDownloadTaskMetaTable(L: Plua_State; Obj: Pointer; begin with TTaskContainer(Obj) do begin - luaClassAddObject(L, ChapterName, MetaTable, 'chapterName'); - luaClassAddObject(L, ChapterLinks, MetaTable, 'chapterLinks'); - luaClassAddObject(L, PageContainerLinks, MetaTable, 'chapterLinks'); + luaClassAddObject(L, PageLinks, MetaTable, 'PageLinks'); + luaClassAddObject(L, PageContainerLinks, MetaTable, 'PageContainerLinks'); + luaClassAddIntegerProperty(L, MetaTable, 'PageNumber', @PageNumber); end; end; From f6300b124fac27434236df3a8a11fb5f4cc34782 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 13:51:24 +0800 Subject: [PATCH 2067/2794] luastrings. public clear method --- baseunits/lua/LuaStrings.pas | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas index b0cc01377..c27698625 100644 --- a/baseunits/lua/LuaStrings.pas +++ b/baseunits/lua/LuaStrings.pas @@ -116,15 +116,19 @@ function strings_sort(L: Plua_State): Integer; cdecl; TStringList(TUserData(luaClassGetObject(L))).Sort; end; +function strings_clear(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Clear; +end; + const - constructs: packed array [0..4] of luaL_Reg = ( + constructs: packed array [0..2] of luaL_Reg = ( (name: 'New'; func: @strings_create), (name: 'Create'; func: @strings_create), - (name: 'new'; func: @strings_create), - (name: 'create'; func: @strings_create), (name: nil; func: nil) ); - methods: packed array [0..9] of luaL_Reg = ( + methods: packed array [0..10] of luaL_Reg = ( (name: 'LoadFromFile'; func: @strings_loadfromfile), (name: 'SetText'; func: @strings_settext), (name: 'GetText'; func: @strings_gettext), @@ -134,6 +138,7 @@ function strings_sort(L: Plua_State): Integer; cdecl; (name: 'Set'; func: @strings_set), (name: 'GetCount'; func: @strings_getcount), (name: 'Sort'; func: @strings_sort), + (name: 'Clear'; func: @strings_clear), (name: nil; func: nil) ); props: packed array[0..4] of lual_Reg_prop = ( From efd8ac799ea31c6569604850405a4b23b5db48ec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 13:51:45 +0800 Subject: [PATCH 2068/2794] luawebsitemodule, publish task object on taskstart even --- baseunits/lua/LuaWebsiteModules.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index a56b0d57d..182d17354 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -213,6 +213,7 @@ function DoGetPageNumber(const DownloadThread: TDownloadThread; luaPushMe(l); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); + luaPushObject(L, DownloadThread.Task.Container, 'task'); if luaL_dofile(l, PChar(Filename)) <> 0 then raise Exception.Create(''); From b73d091c8755bb80df029a6c32234a7885571327 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 13:52:14 +0800 Subject: [PATCH 2069/2794] main, restore downloads and favorites after all modules loaded --- baseunits/uFavoritesManager.pas | 1 - mangadownloader/forms/frmMain.pas | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index c6a4d3f4f..26be13731 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -563,7 +563,6 @@ constructor TFavoriteManager.Create; FFavoritesDB := TFavoritesDB.Create(FAVORITESDB_FILE); FFavoritesDB.Open; ConvertToDB; - Restore; end; destructor TFavoriteManager.Destroy; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 68d4d11c6..058a72a25 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1153,7 +1153,6 @@ procedure TMainForm.FormCreate(Sender: TObject); // downloadmanager DLManager := TDownloadManager.Create; - DLManager.Restore; // favorites FavoriteManager := TFavoriteManager.Create; @@ -1177,12 +1176,6 @@ procedure TMainForm.FormCreate(Sender: TObject); if cbFilterStatus.Items.Count > 2 then cbFilterStatus.ItemIndex := 2; - // show download list - UpdateVtDownload; - - // show favorite list - UpdateVtFavorites; - InitCheckboxes; pcMain.ActivePage := tsDownload; @@ -1453,7 +1446,7 @@ procedure TMainForm.FormShow(Sender: TObject); with TTimer.Create(nil) do begin OnTimer := @tmStartupTimer; - Interval := 1000; + Interval := 32; Enabled := True; end; end; @@ -1807,6 +1800,13 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); ScanLuaWebsiteModulesFile; {$endif} + //restore everything after all modules loaded + DLManager.Restore; + UpdateVtDownload; + + FavoriteManager.Restore; + UpdateVtFavorites; + if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if OptionAutoCheckLatestVersion then From aaca0953bdf8651c9be7b427539fe459d602b92a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 14:20:16 +0800 Subject: [PATCH 2070/2794] luaclass, refactor addobjectclass --- baseunits/lua/LuaClass.pas | 18 +++++++++--------- baseunits/lua/LuaDownloadTask.pas | 4 ++-- baseunits/lua/LuaHTTPSend.pas | 4 ++-- baseunits/lua/LuaMangaInfo.pas | 4 ++-- baseunits/lua/LuaWebsiteModules.pas | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/baseunits/lua/LuaClass.pas b/baseunits/lua/LuaClass.pas index e8a2dfe04..36f5151e9 100644 --- a/baseunits/lua/LuaClass.pas +++ b/baseunits/lua/LuaClass.pas @@ -29,8 +29,8 @@ procedure luaClassRegister(C: TClass; AddMetaTable: TluaClassAddMetaTable; AddLib: TLuaClassRegisterLib = nil); function luaNewUserData(L: Plua_State; Obj: Pointer): Integer; -procedure luaClassNewUserData(L: Plua_State; Obj: Pointer; - var MetaTable, UserData: Integer; AutoFree: Boolean = False); +procedure luaClassNewUserData(L: Plua_State; var MetaTable, UserData: Integer; + Obj: Pointer; AutoFree: Boolean = False); function luaClassGetClosure(L: Plua_State): Pointer; function luaClassGetObject(L: Plua_State): Pointer; inline; @@ -62,7 +62,7 @@ procedure luaClassAddIntegerProperty(L: Plua_State; MetaTable: Integer; Name: PAnsiChar; P: Pointer); overload; procedure luaClassAddBooleanProperty(L: Plua_State; MetaTable: Integer; Name: PAnsiChar; P: Pointer); overload; -procedure luaClassAddObject(L: Plua_State; Obj: TObject; MetaTable: Integer; +procedure luaClassAddObject(L: Plua_State; MetaTable: Integer; Obj: TObject; Name: String; AddMetaTable: TluaClassAddMetaTable = nil); implementation @@ -273,8 +273,8 @@ function luaNewUserData(L: Plua_State; Obj: Pointer): Integer; Result := lua_gettop(L); end; -procedure luaClassNewUserData(L: Plua_State; Obj: Pointer; - var MetaTable, UserData: Integer; AutoFree: Boolean); +procedure luaClassNewUserData(L: Plua_State; var MetaTable, UserData: Integer; + Obj: Pointer; AutoFree: Boolean); begin UserData := luaNewUserData(L, Obj); lua_newtable(L); @@ -312,7 +312,7 @@ procedure luaClassPushUserData(L: Plua_State; Obj: Pointer; Name: String; begin if Obj = nil then Exit; - luaClassNewUserData(L, Obj, m, u, AutoFree); + luaClassNewUserData(L, m, u, Obj, AutoFree); AddMetaTable(L, Obj, m, u); lua_setmetatable(L, u); if Name <> '' then @@ -509,8 +509,8 @@ procedure luaClassAddBooleanProperty(L: Plua_State; MetaTable: Integer; luaClassAddVariable(L, MetaTable, Name, P, @luaclass_bool_get, @luaclass_bool_set); end; -procedure luaClassAddObject(L: Plua_State; Obj: TObject; MetaTable: Integer; - Name: String; AddMetaTable: TluaClassAddMetaTable); +procedure luaClassAddObject(L: Plua_State; MetaTable: Integer; Obj: TObject; Name: String; + AddMetaTable: TluaClassAddMetaTable); var m, u: Integer; begin @@ -519,7 +519,7 @@ AddMetaTable := classlist.FindAddMetaTable(Obj.ClassType); if AddMetaTable = nil then Exit; lua_pushstring(L, PAnsiChar(AnsiLowerCase(Name))); - luaClassNewUserData(L, Obj, m, u, False); + luaClassNewUserData(L, m, u, Obj, False); AddMetaTable(L, Obj, m, u); lua_setmetatable(L, u); lua_rawset(L, MetaTable); diff --git a/baseunits/lua/LuaDownloadTask.pas b/baseunits/lua/LuaDownloadTask.pas index 6344caebb..081c14497 100644 --- a/baseunits/lua/LuaDownloadTask.pas +++ b/baseunits/lua/LuaDownloadTask.pas @@ -17,8 +17,8 @@ procedure luaDownloadTaskMetaTable(L: Plua_State; Obj: Pointer; begin with TTaskContainer(Obj) do begin - luaClassAddObject(L, PageLinks, MetaTable, 'PageLinks'); - luaClassAddObject(L, PageContainerLinks, MetaTable, 'PageContainerLinks'); + luaClassAddObject(L, MetaTable, PageLinks, 'PageLinks'); + luaClassAddObject(L, MetaTable, PageContainerLinks, 'PageContainerLinks'); luaClassAddIntegerProperty(L, MetaTable, 'PageNumber', @PageNumber); end; end; diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index 0d98c9687..d1b8b6c3c 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -86,8 +86,8 @@ procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, begin luaClassAddFunction(L, MetaTable, UserData, methods); luaClassAddProperty(L, MetaTable, UserData, props); - luaClassAddObject(L, Headers, MetaTable, 'Headers'); - luaClassAddObject(L, Cookies, MetaTable, 'Cookies'); + luaClassAddObject(L, MetaTable, Headers, 'Headers'); + luaClassAddObject(L, MetaTable, Cookies, 'Cookies'); end; end; diff --git a/baseunits/lua/LuaMangaInfo.pas b/baseunits/lua/LuaMangaInfo.pas index ca25d2cc2..5febdaf00 100644 --- a/baseunits/lua/LuaMangaInfo.pas +++ b/baseunits/lua/LuaMangaInfo.pas @@ -29,8 +29,8 @@ procedure luaMangaInfoAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'summary', @summary); luaClassAddStringProperty(L, MetaTable, 'summary', @summary); luaClassAddIntegerProperty(L, MetaTable, 'numChapter', @numChapter); - luaClassAddObject(L, chapterName, MetaTable, 'chapterNames'); - luaClassAddObject(L, chapterLinks, MetaTable, 'chapterLinks'); + luaClassAddObject(L, MetaTable, chapterName, 'chapterNames'); + luaClassAddObject(L, MetaTable, chapterLinks, 'chapterLinks'); end; end; diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 182d17354..b4bdb5821 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -536,7 +536,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'OnAfterImageSaved', @OnAfterImageSaved); luaClassAddStringProperty(L, MetaTable, 'OnLogin', @OnLogin); luaClassAddStringProperty(L, MetaTable, 'LastUpdated', @LastUpdated); - luaClassAddObject(L, Storage, MetaTable, 'Storage'); + luaClassAddObject(L, MetaTable, Storage, 'Storage'); end; end; From 0321dcbddb5a8a77977a86becc9fa73e3684b0ce Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 14:24:23 +0800 Subject: [PATCH 2071/2794] luawebsitemodules, publish task on variuos event --- baseunits/lua/LuaWebsiteModules.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index b4bdb5821..2d8857c90 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -211,9 +211,9 @@ function DoGetPageNumber(const DownloadThread: TDownloadThread; l := LuaNewBaseState; try luaPushMe(l); + luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); - luaPushObject(L, DownloadThread.Task.Container, 'task'); if luaL_dofile(l, PChar(Filename)) <> 0 then raise Exception.Create(''); @@ -237,6 +237,7 @@ function DoGetImageURL(const DownloadThread: TDownloadThread; const AURL: String l := LuaNewBaseState; try luaPushMe(l); + luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); @@ -262,6 +263,7 @@ function DoBeforeDownloadImage(const DownloadThread: TDownloadThread; l := LuaNewBaseState; try luaPushMe(l); + luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); @@ -287,6 +289,7 @@ function DoDownloadImage(const DownloadThread: TDownloadThread; l := LuaNewBaseState; try luaPushMe(l); + luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); From a6b8ceb3bddfb954e58795f3b01eb8aaf8e7968d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 6 Feb 2018 14:54:50 +0800 Subject: [PATCH 2072/2794] basecrypto, fix memory leaks --- baseunits/BaseCrypto.pas | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas index 3138cc4cb..7b1731ba1 100644 --- a/baseunits/BaseCrypto.pas +++ b/baseunits/BaseCrypto.pas @@ -144,11 +144,13 @@ function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; Result := ''; with TDCP_md5.Create(nil) do - begin - Init; - UpdateStr(key); - Final(keyHash); - end; + try + Init; + UpdateStr(key); + Final(keyHash); + finally + Free; + end; data := LowerCase(StrToHexStr(BytesToString(keyHash))); for i := 0 to 31 do @@ -159,7 +161,6 @@ function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; ivBytes[i] := Byte(iv[i + 1]); with TDCP_rijndael.Create(nil) do - begin try Init(keyBytes, 32*8, @ivBytes[0]); data := DecodeStringBase64(s); @@ -169,7 +170,6 @@ function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; finally Free; end; - end; end; end. From 98a3b44b032511f12e11904cb7b2fe82a9e33daa Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 6 Feb 2018 15:50:38 +0300 Subject: [PATCH 2073/2794] lua, fix typos --- baseunits/lua/LuaWebsiteModules.pas | 3 ++- baseunits/lua/luaXQuery.pas | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 2d8857c90..0a2fb6986 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -139,7 +139,7 @@ function DoGetNameAndLink(const MangaInfo: TMangaInformation; luaPushObject(l, MangaInfo.FHTTP, 'http'); luaPushStringGlobal(L, 'url', AURL); luaPushObject(l, ANames, 'names'); - luaPushObject(l, ANames, 'links'); + luaPushObject(l, ALinks, 'links'); if luaL_dofile(l, PChar(Filename)) <> 0 then raise Exception.Create(''); @@ -239,6 +239,7 @@ function DoGetImageURL(const DownloadThread: TDownloadThread; const AURL: String luaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushIntegerGlobal(l, 'workid', DownloadThread.WorkId); luaPushStringGlobal(l, 'url', AURL); if luaL_dofile(l, PChar(Filename)) <> 0 then diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index b3cb5d3d9..71fcc1d88 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -127,7 +127,7 @@ function xquery_xpathhrefall(L: Plua_State): Integer; cdecl; u := TUserData(luaClassGetObject(L)); case lua_gettop(L) of 3: u.XPathHREFAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), - TStrings(luaGetUserData(L, 2))); + TStrings(luaGetUserData(L, 3))); 4: u.XPathHREFAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), TStrings(luaGetUserData(L, 3)), TLuaIXQValue(luaGetUserData(L, 4)).FIXQValue) end; @@ -141,7 +141,7 @@ function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; u := TUserData(luaClassGetObject(L)); case lua_gettop(L) of 3: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), - TStrings(luaGetUserData(L, 2))); + TStrings(luaGetUserData(L, 3))); 4: u.XPathHREFtitleAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), TStrings(luaGetUserData(L, 3)), TLuaIXQValue(luaGetUserData(L, 4)).FIXQValue) end; From b5d632eaa6ef8cab6493a4ab15ff40034b12bb46 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 14:39:25 +0800 Subject: [PATCH 2074/2794] luabase, add luadumpfiletostream and lualoadfromstream to cache precompiled lua byte code --- baseunits/lua/LuaBase.pas | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index fd785057c..577132312 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -15,6 +15,10 @@ function LuaDoFile(AFilename: String; AFuncName: String = ''): Plua_State; function LuaNewBaseState: Plua_State; function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; +function LuaDumpFileToStream(L: Plua_State; AFilename: String; + AStripDebug: Boolean = True): TMemoryStream; +function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiChar): Integer; + implementation uses @@ -81,4 +85,55 @@ function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; Result := True; end; +function _luawriter(L: Plua_State; const p: Pointer; sz: size_t; ud: Pointer): Integer; cdecl; +begin + if TMemoryStream(ud).Write(p^, sz) <> sz then + Result := 1 + else + Result := 0; +end; + +function LuaDumpFileToStream(L: Plua_State; AFilename: String; + AStripDebug: Boolean): TMemoryStream; +var + strip: Integer; +begin + if not FileExists(AFilename) then + Exit; + Result := TMemoryStream.Create; + try + if luaL_loadfile(L, PChar(AFilename)) <> 0 then + raise Exception.Create(''); + if AStripDebug then + strip := 0 + else + strip := 1; + if lua_dump(L, @_luawriter, Result, strip) <> 0 then + raise Exception.Create(''); + except + Result.Free; + Result := nil; + Logger.SendError(lua_tostring(L, -1)); + end; +end; + +function _luareader(L: Plua_State; ud: Pointer; sz: Psize_t): PAnsiChar; cdecl; +var + m: TMemoryStream; +begin + m := TMemoryStream(ud); + if m.Size = 0 then + begin + Result := nil; + Exit; + end; + Result := PAnsiChar(m.Memory); + sz^ := m.Size; +end; + +function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiChar): Integer; +begin + Result := lua_load(L, @_luareader, AStream, AName, 'b'); +end; + end. From a667336a50f37eaff207b632f3eaea0986f8c817 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 14:57:43 +0800 Subject: [PATCH 2075/2794] luawebsitemodules, add container for lua modules execute cached precompiled byte code --- baseunits/lua/LuaWebsiteModules.pas | 365 ++++++++++++++++------------ 1 file changed, 214 insertions(+), 151 deletions(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 0a2fb6986..6d485a309 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -5,17 +5,19 @@ interface uses - Classes, SysUtils, lua53, LuaStringsStorage, WebsiteModules, uData, + Classes, SysUtils, fgl, lua53, LuaStringsStorage, WebsiteModules, uData, uDownloadsManager, xquery, httpsendthread; type - { TLuaWebsiteModuleContainer } + TLuaWebsiteModulesContainer = class; - TLuaWebsiteModuleContainer = class + { TLuaWebsiteModule } + + TLuaWebsiteModule = class private - FModule: TModuleContainer; public + Module: TModuleContainer; OnBeforeUpdateList: String; OnAfterUpdateList: String; OnGetDirectoryPageNumber: String; @@ -30,36 +32,63 @@ TLuaWebsiteModuleContainer = class OnAfterImageSaved: String; OnLogin: String; Storage: TStringsStorage; - Filename: String; LastUpdated: String; + Container: TLuaWebsiteModulesContainer; + constructor Create; + destructor Destroy; override; + + procedure LuaPushMe(L: Plua_State); + function LuaDoMe(L: Plua_State): Integer; + end; + + TLuaWebsiteModules = specialize TFPGList<TLuaWebsiteModule>; + + { TLuaWebsiteModulesContainer } + + TLuaWebsiteModulesContainer = class + public + Modules: TLuaWebsiteModules; + FileName: String; + ByteCode: TMemoryStream; + constructor Create; + destructor Destroy; override; + end; + + TLuaWebsiteModulesContainers = specialize TFPGList<TLuaWebsiteModulesContainer>; + + { TLuaWebsiteModulesManager } + + TLuaWebsiteModulesManager = class + public + Containers: TLuaWebsiteModulesContainers; + TempModuleList: TLuaWebsiteModules; constructor Create; destructor Destroy; override; - procedure luaPushMe(L: Plua_State); end; procedure ScanLuaWebsiteModulesFile; +var + LuaWebsiteModulesManager: TLuaWebsiteModulesManager; + implementation uses FMDOptions, FileUtil, MultiLog, LuaClass, LuaBase, LuaMangaInfo, LuaHTTPSend, LuaXQuery, LuaUtils, LuaDownloadTask; -var - luawebsitemodulelist: TFPList; - function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; var l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnBeforeUpdateList) then Result := lua_toboolean(l, -1); @@ -75,13 +104,13 @@ function DoAfterUpdateList(const Module: TModuleContainer): Boolean; l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnAfterUpdateList) then Result := lua_toboolean(l, -1); @@ -98,17 +127,17 @@ function DoGetDirectoryPageNumber(const MangaInfo: TMangaInformation; l: Plua_State; begin Result := NO_ERROR; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushIntegerGlobal(l, 'page', Page); luaPushIntegerGlobal(l, 'workptr', WorkPtr); luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); luaPushObject(l, MangaInfo.FHTTP, 'http'); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnGetDirectoryPageNumber) then begin @@ -130,18 +159,18 @@ function DoGetNameAndLink(const MangaInfo: TMangaInformation; l: Plua_State; begin Result := NO_ERROR; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); luaPushObject(l, MangaInfo.FHTTP, 'http'); luaPushStringGlobal(L, 'url', AURL); luaPushObject(l, ANames, 'names'); luaPushObject(l, ALinks, 'links'); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnGetNameAndLink) then Result := lua_tointeger(L, -1); @@ -158,16 +187,16 @@ function DoGetInfo(const MangaInfo: TMangaInformation; const AURL: String; l: Plua_State; begin Result := NO_ERROR; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushStringGlobal(l, 'url', AURL); luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); luaPushObject(l, MangaInfo.FHTTP, 'http'); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); LuaCallFunction(l, OnGetInfo); except @@ -182,14 +211,14 @@ function DoTaskStart(const Task: TTaskContainer; const Module: TModuleContainer) l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(l, Task, 'task'); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnTaskStart) then Result := lua_toboolean(l, -1); @@ -206,16 +235,16 @@ function DoGetPageNumber(const DownloadThread: TDownloadThread; l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnGetPageNumber) then Result := lua_toboolean(l, -1); @@ -232,17 +261,17 @@ function DoGetImageURL(const DownloadThread: TDownloadThread; const AURL: String l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushIntegerGlobal(l, 'workid', DownloadThread.WorkId); luaPushStringGlobal(l, 'url', AURL); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnGetImageURL) then Result := lua_toboolean(l, -1); @@ -259,16 +288,16 @@ function DoBeforeDownloadImage(const DownloadThread: TDownloadThread; l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnBeforeDownloadImage) then Result := lua_toboolean(l, -1); @@ -285,16 +314,16 @@ function DoDownloadImage(const DownloadThread: TDownloadThread; l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task'); luaPushObject(l, DownloadThread.FHTTP, 'http'); luaPushStringGlobal(l, 'url', AURL); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnDownloadImage) then Result := lua_toboolean(l, -1); @@ -311,16 +340,16 @@ function DoSaveImage(const AHTTP: THTTPSendThread; const APath, AName: String; l: Plua_State; begin Result := ''; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(l, AHTTP, 'http'); luaPushStringGlobal(l, 'path', APath); luaPushStringGlobal(l, 'name', AName); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnSaveImage) then Result := lua_tostring(l, -1); @@ -336,14 +365,14 @@ function DoAfterImageSaved(const AFilename: String; const Module: TModuleContain l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushStringGlobal(l, 'filename', AFilename); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnAfterImageSaved) then Result := lua_toboolean(l, -1); @@ -359,14 +388,14 @@ function DoLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): l: Plua_State; begin Result := False; - with TLuaWebsiteModuleContainer(Module.TagPtr) do + with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; try - luaPushMe(l); + LuaPushMe(l); luaPushObject(l, AHTTP, 'http'); - if luaL_dofile(l, PChar(Filename)) <> 0 then + if LuaDoMe(l) <> 0 then raise Exception.Create(''); if LuaCallFunction(l, OnTaskStart) then Result := lua_toboolean(l, -1); @@ -380,82 +409,79 @@ function DoLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): function LoadLuaToWebsiteModules(AFilename: String): Boolean; var l: Plua_State; - m: Pointer; + c: TLuaWebsiteModulesContainer; + m: TMemoryStream; i: Integer; - - procedure setcurrent; - begin - with TLuaWebsiteModuleContainer(m) do - begin - Filename := AFilename; - if OnBeforeUpdateList <> '' then - FModule.OnBeforeUpdateList := @DoBeforeUpdateList; - if OnAfterUpdateList <> '' then - FModule.OnAfterUpdateList := @DoAfterUpdateList; - if OnGetDirectoryPageNumber <> '' then - FModule.OnGetDirectoryPageNumber := @DoGetDirectoryPageNumber; - if OnGetNameAndLink <> '' then - FModule.OnGetNameAndLink := @DoGetNameAndLink; - if OnGetInfo <> '' then - FModule.OnGetInfo := @DoGetInfo; - if OnTaskStart <> '' then - FModule.OnTaskStart := @DoTaskStart; - if OnGetPageNumber <> '' then - FModule.OnGetPageNumber := @DoGetPageNumber; - if OnGetImageURL <> '' then - FModule.OnGetImageURL := @DoGetImageURL; - if OnBeforeDownloadImage <> '' then - FModule.OnBeforeDownloadImage := @DoBeforeDownloadImage; - if OnDownloadImage <> '' then - FModule.OnDownloadImage := @DoDownloadImage; - if OnSaveImage <> '' then - FModule.OnSaveImage := @DoSaveImage; - if OnAfterImageSaved <> '' then - FModule.OnAfterImageSaved := @DoAfterImageSaved; - if OnLogin <> '' then - FModule.OnLogin := @DoLogin; - - Logger.EnterMethod('lualoadmodule' + IntToStr(i), ' '); - Logger.Send('File', Filename); - Logger.Send('Website', FModule.Website); - Logger.Send('RootURL', FModule.RootURL); - Logger.Send('LastUpdated', LastUpdated); - Logger.ExitMethod('lualoadmodule' + IntToStr(i), ' '); - end; - end; - + s: String; begin Result := False; Logger.Send('Load lua website module', AFilename); try - l := LuaDoFile(AFilename, 'Init'); - except - Logger.SendError('Error load lua website module'); - end; - if Assigned(l) then - begin - logger.Send('Read returned data from lua website module'); - Result := True; + l := LuaNewBaseState; try - for i := 1 to lua_gettop(L) do - if lua_isuserdata(L, i) then - begin - m := lua_touserdata(L, i); - if TObject(m) is TLuaWebsiteModuleContainer then - setcurrent - else - begin - m := PPointer(m)^; - if TObject(m) is TLuaWebsiteModuleContainer then - setcurrent; - end; - end - else - Logger.SendWarning('Lua module doesn''t return any data!'); - finally - lua_close(l); + m := LuaDumpFileToStream(l, AFilename); + if m <> nil then + begin + if lua_pcall(l, 0, 0, 0) <> 0 then + raise Exception.Create(''); + LuaCallFunction(l, 'Init'); + end; + except + Logger.SendError('Error load lua website module. ' + lua_tostring(L, -1)); end; + finally + lua_close(l); end; + + if LuaWebsiteModulesManager.TempModuleList.Count <> 0 then + with LuaWebsiteModulesManager do + begin + c := TLuaWebsiteModulesContainer.Create; + c.FileName := AFilename; + c.ByteCode := m; + m := nil; + s := ''; + Containers.Add(c); + for i := 0 to TempModuleList.Count - 1 do + with TempModuleList[i] do + begin + s += Module.Website + ', '; + c.Modules.Add(TempModuleList[i]); + Container := c; + if OnBeforeUpdateList <> '' then + Module.OnBeforeUpdateList := @DoBeforeUpdateList; + if OnAfterUpdateList <> '' then + Module.OnAfterUpdateList := @DoAfterUpdateList; + if OnGetDirectoryPageNumber <> '' then + Module.OnGetDirectoryPageNumber := @DoGetDirectoryPageNumber; + if OnGetNameAndLink <> '' then + Module.OnGetNameAndLink := @DoGetNameAndLink; + if OnGetInfo <> '' then + Module.OnGetInfo := @DoGetInfo; + if OnTaskStart <> '' then + Module.OnTaskStart := @DoTaskStart; + if OnGetPageNumber <> '' then + Module.OnGetPageNumber := @DoGetPageNumber; + if OnGetImageURL <> '' then + Module.OnGetImageURL := @DoGetImageURL; + if OnBeforeDownloadImage <> '' then + Module.OnBeforeDownloadImage := @DoBeforeDownloadImage; + if OnDownloadImage <> '' then + Module.OnDownloadImage := @DoDownloadImage; + if OnSaveImage <> '' then + Module.OnSaveImage := @DoSaveImage; + if OnAfterImageSaved <> '' then + Module.OnAfterImageSaved := @DoAfterImageSaved; + if OnLogin <> '' then + Module.OnLogin := @DoLogin; + end; + TempModuleList.Clear; + SetLength(s, Length(s) - 2); + Logger.Send('Loaded modules from ' + ExtractFileName(AFilename), s); + s := ''; + end; + if m <> nil then + m.Free; end; procedure ScanLuaWebsiteModulesFile; @@ -475,24 +501,65 @@ procedure ScanLuaWebsiteModulesFile; end; end; +{ TLuaWebsiteModulesManager } + +constructor TLuaWebsiteModulesManager.Create; +begin + Containers := TLuaWebsiteModulesContainers.Create; + TempModuleList := TLuaWebsiteModules.Create; +end; + +destructor TLuaWebsiteModulesManager.Destroy; +var + i: Integer; +begin + for i := 0 to TempModuleList.Count - 1 do + TempModuleList[i].Free; + TempModuleList.Free; + for i := 0 to Containers.Count - 1 do + Containers[i].Free; + Containers.Free; + inherited Destroy; +end; + +{ TLuaWebsiteModulesContainer } + +constructor TLuaWebsiteModulesContainer.Create; +begin + Modules := TLuaWebsiteModules.Create; + ByteCode := nil; +end; + +destructor TLuaWebsiteModulesContainer.Destroy; +var + i: Integer; +begin + if Assigned(ByteCode) then + ByteCode.Free; + for i := 0 to Modules.Count - 1 do + Modules[i].Free; + Modules.Free; + inherited Destroy; +end; -{ TLuaWebsiteModuleContainer } -constructor TLuaWebsiteModuleContainer.Create; +{ TLuaWebsiteModule } + +constructor TLuaWebsiteModule.Create; begin - luawebsitemodulelist.Add(Self); - FModule := Modules.AddModule; - FModule.TagPtr := Self; + LuaWebsiteModulesManager.TempModuleList.Add(Self); Storage := TStringsStorage.Create; + Module := Modules.AddModule; + Module.TagPtr := Self; end; -destructor TLuaWebsiteModuleContainer.Destroy; +destructor TLuaWebsiteModule.Destroy; begin Storage.Free; inherited Destroy; end; -procedure TLuaWebsiteModuleContainer.luaPushMe(L: Plua_State); +procedure TLuaWebsiteModule.LuaPushMe(L: Plua_State); begin luaPushObject(L, Self, 'module'); luaPushIntegerGlobal(L, 'no_error', NO_ERROR); @@ -500,30 +567,35 @@ procedure TLuaWebsiteModuleContainer.luaPushMe(L: Plua_State); luaPushIntegerGlobal(L, 'information_not_found', INFORMATION_NOT_FOUND); end; +function TLuaWebsiteModule.LuaDoMe(L: Plua_State): Integer; +begin + Result := LuaLoadFromStream(L, Container.ByteCode, PChar(Container.FileName)); + if Result <> 0 then + Result := lua_pcall(L, 0, 0, 0); +end; + procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, UserData: Integer; AutoFree: Boolean = False); begin - with TLuaWebsiteModuleContainer(Obj) do + with TLuaWebsiteModule(Obj) do begin - luaClassAddStringProperty(L, MetaTable, 'Website', @FModule.Website); - luaClassAddStringProperty(L, MetaTable, 'RootURL', @FModule.RootURL); - luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @FModule.MaxTaskLimit); + luaClassAddStringProperty(L, MetaTable, 'Website', @Module.Website); + luaClassAddStringProperty(L, MetaTable, 'RootURL', @Module.RootURL); + luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.MaxTaskLimit); luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', - @FModule.MaxConnectionLimit); - luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', - @FModule.ActiveTaskCount); + @Module.MaxConnectionLimit); + luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', @Module.ActiveTaskCount); luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', - @FModule.ActiveConnectionCount); - luaClassAddBooleanProperty(L, MetaTable, 'AccountSupport', @FModule.AccountSupport); - luaClassAddBooleanProperty(L, MetaTable, 'SortedList', @FModule.SortedList); + @Module.ActiveConnectionCount); + luaClassAddBooleanProperty(L, MetaTable, 'AccountSupport', @Module.AccountSupport); + luaClassAddBooleanProperty(L, MetaTable, 'SortedList', @Module.SortedList); luaClassAddBooleanProperty(L, MetaTable, 'InformationAvailable', - @FModule.InformationAvailable); + @Module.InformationAvailable); luaClassAddBooleanProperty(L, MetaTable, 'FavoriteAvailable', - @FModule.FavoriteAvailable); + @Module.FavoriteAvailable); + luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', @Module.DynamicPageLink); luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', - @FModule.DynamicPageLink); - luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', - @FModule.CloudflareEnabled); + @Module.CloudflareEnabled); luaClassAddStringProperty(L, MetaTable, 'OnBeforeUpdateList', @OnBeforeUpdateList); luaClassAddStringProperty(L, MetaTable, 'OnAfterUpdateList', @OnAfterUpdateList); luaClassAddStringProperty(L, MetaTable, 'OnGetDirectoryPageNumber', @@ -546,7 +618,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; function _create(L: Plua_State): Integer; cdecl; begin - luaClassPushObject(L, TLuaWebsiteModuleContainer.Create, '', False, + luaClassPushObject(L, TLuaWebsiteModule.Create, '', False, @luaWebsiteModuleAddMetaTable); Result := 1; end; @@ -556,21 +628,12 @@ procedure luaWebsiteModuleRegister(L: Plua_State); lua_register(L, 'NewModule', @_create); end; -procedure dofinalization; -var - i: Integer; -begin - for i := 0 to luawebsitemodulelist.Count - 1 do - TObject(luawebsitemodulelist[i]).Free; - luawebsitemodulelist.Free; -end; - initialization - luawebsitemodulelist := TFPList.Create; - luaClassRegister(TLuaWebsiteModuleContainer, @luaWebsiteModuleAddMetaTable, + luaClassRegister(TLuaWebsiteModule, @luaWebsiteModuleAddMetaTable, @luaWebsiteModuleRegister); + LuaWebsiteModulesManager := TLuaWebsiteModulesManager.Create; finalization - dofinalization; + LuaWebsiteModulesManager.Free; end. From 3287a313c6d89cf84e1febc61133c371257c1edd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 14:58:11 +0800 Subject: [PATCH 2076/2794] added modules count to about status --- mangadownloader/forms/frmMain.pas | 56 ++++++++++++++++--------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 058a72a25..6fc1fab07 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -680,6 +680,7 @@ TMainForm = class(TForm) // load about information procedure LoadAbout; + procedure AddToAboutStatus(const ACaption, AValue: String); procedure CloseNow; @@ -1800,6 +1801,8 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); ScanLuaWebsiteModulesFile; {$endif} + AddToAboutStatus('Modules', IntToStr(Modules.Count)); + //restore everything after all modules loaded DLManager.Restore; UpdateVtDownload; @@ -2127,25 +2130,6 @@ procedure TMainForm.miHighlightNewMangaClick(Sender: TObject); end; procedure TMainForm.LoadAbout; - - procedure addaboutcomp(const ACaption, AValue: String); - - function addaboutcomplbl(const ACaption: String): TLabel; - begin - Result := TLabel.Create(Self); - Result.Parent := pnAboutComp; - Result.Caption := ACaption; - end; - - begin - addaboutcomplbl(ACaption + ':'); - with addaboutcomplbl(AValue) do - begin - Font.Style := [fsBold]; - BorderSpacing.Right := 16; - end; - end; - var i: Integer; fs: TFileStreamUTF8; @@ -2186,17 +2170,35 @@ procedure TMainForm.LoadAbout; if FileExistsUTF8(CHANGELOG_FILE) then mmChangelog.Lines.LoadFromFile(CHANGELOG_FILE); // compiler info - addaboutcomp('FPC Version', GetFPCVersion); - addaboutcomp('LCL Version', GetLCLVersion); - addaboutcomp('WidgetSet', GetWidgetSetName); - addaboutcomp('Target CPU-OS', GetTargetCPU_OS); - addaboutcomp('Build Time', GetBuildTime); + AddToAboutStatus('FPC Version', GetFPCVersion); + AddToAboutStatus('LCL Version', GetLCLVersion); + AddToAboutStatus('WidgetSet', GetWidgetSetName); + AddToAboutStatus('Target CPU-OS', GetTargetCPU_OS); + AddToAboutStatus('Build Time', GetBuildTime); if SQLiteLibraryHandle = 0 then InitializeSqlite(); - if SQLiteLibraryHandle <> 0 then try addaboutcomp('SQLite Version', sqlite3_version()); except end; + if SQLiteLibraryHandle <> 0 then try AddToAboutStatus('SQLite Version', sqlite3_version()); except end; if SSLLibHandle = 0 then InitSSLInterface; - if SSLLibHandle <> 0 then try addaboutcomp('OpenSSL Version', SSLeayversion(0)); except end; + if SSLLibHandle <> 0 then try AddToAboutStatus('OpenSSL Version', SSLeayversion(0)); except end; if WebPLibHandle = 0 then InitWebPModule; - if WebPLibHandle <> 0 then try addaboutcomp('WebP Version', WebPGetVersion); except end; + if WebPLibHandle <> 0 then try AddToAboutStatus('WebP Version', WebPGetVersion); except end; +end; + +procedure TMainForm.AddToAboutStatus(const ACaption, AValue: String); + + function addaboutcomplbl(const ACaption: String): TLabel; + begin + Result := TLabel.Create(Self); + Result.Parent := pnAboutComp; + Result.Caption := ACaption; + end; + +begin + addaboutcomplbl(ACaption + ':'); + with addaboutcomplbl(AValue) do + begin + Font.Style := [fsBold]; + BorderSpacing.Right := 16; + end; end; procedure TMainForm.GeneratetvDownloadFilterNodes; From 43e0ac96a9a79d88e96ef6a7305fd57aa6ac7277 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 15:26:36 +0800 Subject: [PATCH 2077/2794] add paramstr --lua-dofile to always load lua module from file --- baseunits/lua/LuaWebsiteModules.pas | 9 +++++++-- mangadownloader/md.lpi | 9 +++++++++ mangadownloader/md.lpr | 13 +++++++++++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 6d485a309..4069e7a6f 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -70,6 +70,7 @@ procedure ScanLuaWebsiteModulesFile; var LuaWebsiteModulesManager: TLuaWebsiteModulesManager; + AlwaysLoadLuaFromFile: Boolean = {$ifdef DEVBUILD}True{$else}False{$endif}; implementation @@ -569,9 +570,13 @@ procedure TLuaWebsiteModule.LuaPushMe(L: Plua_State); function TLuaWebsiteModule.LuaDoMe(L: Plua_State): Integer; begin - Result := LuaLoadFromStream(L, Container.ByteCode, PChar(Container.FileName)); - if Result <> 0 then + if AlwaysLoadLuaFromFile then + Result := luaL_loadfile(L, PChar(Container.FileName)) + else + Result := LuaLoadFromStream(L, Container.ByteCode, PChar(Container.FileName)); + if Result = 0 then Result := lua_pcall(L, 0, 0, 0); + writeln(LuaStackToString(L)); end; procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 45ac8a7dd..0d4cf8e36 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -211,6 +211,15 @@ -dSELFUPDATE -dDEBUGLEAKS -dMULTILOG"/> + <OtherDefines Count="7"> + <Define0 Value="MANGADOWNLOADER"/> + <Define1 Value="DOWNLOADER"/> + <Define2 Value="SELFUPDATE"/> + <Define3 Value="DEBUGLEAKS"/> + <Define4 Value="MULTILOG"/> + <Define5 Value="USE_SOROKINS_REGEX"/> + <Define6 Value="USE_BBFULL_UNICODE"/> + </OtherDefines> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 83d79b8f8..8158d6c53 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -9,8 +9,8 @@ cthreads, {$ENDIF} {$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, - FMDVars, webp, SimpleException, Classes, windows, sysutils, frmMain, MultiLog, + Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, FMDVars, webp, + LuaWebsiteModules, SimpleException, Classes, windows, sysutils, frmMain, MultiLog, FileChannel, ssl_openssl_lib; var @@ -22,10 +22,19 @@ {$IFDEF DEBUGLEAKS} trcfile: String; {$ENDIF DEBUGLEAKS} + i: Integer; + p: String; {$R *.res} begin + for i := 1 to ParamCount-1 do + begin + p := AnsiLowerCase(ParamStr(i)); + if p = '--lua-dofile' then + LuaWebsiteModules.AlwaysLoadLuaFromFile := True; + end; + Application.Scaled := True; with TIniFile.Create(CONFIG_FILE) do try From 13a1dfb3860e2b35139d0b2ad042d5583c0d0e49 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 15:48:29 +0800 Subject: [PATCH 2078/2794] luabaseunit, register more functions --- baseunits/lua/LuaBaseUnit.pas | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index a0a63deb0..01cc87c44 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -54,6 +54,42 @@ function lua_mangainfostatusifpos(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_appendurldelim(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, AppendURLDelim(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_removeurldelim(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, RemoveURLDelim(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_appendurldelimleft(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, AppendURLDelimLeft(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_removeurldelimleft(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, RemoveURLDelimLeft(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_encodebase64(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, Base64Decode(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_decodebase64(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, Base64Encode(lua_tostring(L, 1))); + Result := 1; +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -61,6 +97,12 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'MaybeFillHost', @lua_maybefillhost); luaPushFunctionGlobal(L, 'InvertStrings', @lua_invertstrings); luaPushFunctionGlobal(L, 'MangaInfoStatusIfPos', @lua_mangainfostatusifpos); + luaPushFunctionGlobal(L, 'AppendURLDelim', @lua_appendurldelim); + luaPushFunctionGlobal(L, 'AppendURLDelimleft', @lua_appendurldelimleft); + luaPushFunctionGlobal(L, 'RemoveURLDelim', @lua_removeurldelim); + luaPushFunctionGlobal(L, 'RemoveURLDelimLeft', @lua_removeurldelimleft); + luaPushFunctionGlobal(L, 'EncodeBase64', @lua_encodebase64); + luaPushFunctionGlobal(L, 'DecodeBase64', @lua_decodebase64); end; end. From 637884a2f31cd8b52589f348d0886cf2d0287ca7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 16:09:12 +0800 Subject: [PATCH 2079/2794] cleanup project options, move to additionals and overrides, enable lua for all target --- mangadownloader/md.lpi | 53 ++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0d4cf8e36..357b5297a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -64,12 +64,6 @@ </Win32> </Options> </Linking> - <Other> - <CustomOptions Value="-dMANGADOWNLOADER --dDOWNLOADER --dSELFUPDATE --dMULTILOG"/> - </Other> </CompilerOptions> </Item2> <Item3 Name="Win32 Debug"> @@ -115,10 +109,6 @@ <CompilerMessages> <IgnoredMessages idx4079="True"/> </CompilerMessages> - <CustomOptions Value="-dMANGADOWNLOADER --dDOWNLOADER --dSELFUPDATE --dMULTILOG"/> </Other> </CompilerOptions> </Item3> @@ -161,12 +151,6 @@ </Win32> </Options> </Linking> - <Other> - <CustomOptions Value="-dMANGADOWNLOADER --dDOWNLOADER --dSELFUPDATE --dMULTILOG"/> - </Other> </CompilerOptions> </Item4> <Item5 Name="Win32 Debug Leaks"> @@ -204,13 +188,13 @@ <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> </Linking> <Other> - <CustomOptions Value="-dMANGADOWNLOADER --dDOWNLOADER --dSELFUPDATE --dDEBUGLEAKS --dMULTILOG"/> <OtherDefines Count="7"> <Define0 Value="MANGADOWNLOADER"/> <Define1 Value="DOWNLOADER"/> @@ -261,22 +245,29 @@ <UseHeaptrc Value="True"/> <UseExternalDbgSyms Value="True"/> </Debugging> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> </Linking> <Other> - <CustomOptions Value="-dMANGADOWNLOADER --dDOWNLOADER --dSELFUPDATE --dDEBUGLEAKS --dMULTILOG"/> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> </Other> </CompilerOptions> </Item6> - <SharedMatrixOptions Count="2"> - <Item1 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> - <Item2 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <SharedMatrixOptions Count="9"> + <Item1 ID="465017374973" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> + <Item2 ID="534084266787" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -WC"/> + <Item3 ID="951904047630" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item4 ID="140379931701" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> + <Item5 ID="729045573668" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> + <Item6 ID="200657967120" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> + <Item7 ID="915259842272" Modes="Win32 Debug Leaks,Win64 Debug Leaks" Value="-dDEVBUILD"/> + <Item8 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> + <Item9 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> @@ -466,10 +457,6 @@ <CompilerMessages> <IgnoredMessages idx5028="True"/> </CompilerMessages> - <CustomOptions Value="-dMANGADOWNLOADER --dDOWNLOADER --dSELFUPDATE --dMULTILOG"/> </Other> </CompilerOptions> <Debugging> From c0847efaaac38495b7a6580a11203f03800ada5a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 16:15:25 +0800 Subject: [PATCH 2080/2794] replace foolslide module with lua script close #849 --- baseunits/ModuleList.inc | 1 - baseunits/modules/FoOlSlide.pas | 288 -------------------------------- lua/modules/FoOlSlide.lua | 213 +++++++++++++++++++++++ 3 files changed, 213 insertions(+), 289 deletions(-) delete mode 100644 baseunits/modules/FoOlSlide.pas create mode 100644 lua/modules/FoOlSlide.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index b51a3c849..dd0e6ecc3 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,5 +1,4 @@ uses - FoOlSlide, WPManga, myMangaReaderCMS, Batoto, diff --git a/baseunits/modules/FoOlSlide.pas b/baseunits/modules/FoOlSlide.pas deleted file mode 100644 index d4175737e..000000000 --- a/baseunits/modules/FoOlSlide.pas +++ /dev/null @@ -1,288 +0,0 @@ -unit FoOlSlide; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil; - -implementation - -const - dirurl = '/directory/'; - dirurlreader = '/reader/directory/'; - dirurlfoolslide = '/foolslide/directory/'; - dirurlslide = '/slide/directory/'; - dirurlslideU = '/Slide/directory/'; - dirurlonline = '/online/directory/'; - dirurlhelvetica = '/r/directory/'; - -function GETWithCookie(const AHTTP: THTTPSendThread; const AURL: String; - const Module: TModuleContainer): Boolean; -begin - if ((Module.Website = 'SeinagiAdultoFansub') or - (Module.Website = 'TripleSevenScan') or - (Module.Website = 'DokiFansubs')) - and (Pos(dirurl, AURL) = 0)then - Result := AHTTP.POST(AURL, 'adult=true') - else - Result := AHTTP.GET(AURL); -end; - -function GetDirURL(const AWebsite: String): String; -begin - if (AWebsite = 'GoManga') or - (AWebsite = 'Jaiminisbox') or - (AWebsite = 'TripleSevenScan') or - (AWebsite = 'DokiFansubs') or - (AWebsite = 'AtelierDuNoir') then - Result := dirurlreader - else - if AWebsite = 'OneTimeScans' then - Result := dirurlfoolslide - else - if (AWebsite = 'DejameProbar') or - (AWebsite = 'MenudoFansub') or - (AWebsite = 'NeoProjectScan') or - (AWebsite = 'SolitarioNoFansub') then - Result := dirurlslide - else - if AWebsite = 'SantosScan' then - Result := dirurlslideU - else - if (AWebsite = 'Pzykosis666HFansub') or - (AWebsite = 'SeinagiFansub') then - Result := dirurlonline - else - if(AWebsite = 'HelveticaScans') then - Result := dirurlhelvetica - else - Result := dirurl; -end; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - v: IXQValue; - p: Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if GETWithCookie(MangaInfo.FHTTP, Module.RootURL + GetDirURL(Module.Website), Module) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - with TRegExpr.Create do - try - Expression := '/(\d+)/$'; - for v in XPath('//*[@class="next"]/a/@href') do - begin - Exec(v.toString); - if SubExprMatchCount > 0 then - begin - p := StrToIntDef(Match[1], -1); - if p > Page then - Page := p; - end; - end; - finally - Free; - end; - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + GetDirURL(Module.Website); - if AURL <> '0' then s += IncStr(AURL) + '/'; - if GETWithCookie(MangaInfo.FHTTP, s, Module) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - if Module.Website = 'AtelierDuNoir' then - for v in XPath('//div[@class="caption"]') do begin - ALinks.Add(XPathString('div/a/@href', v)); - ANames.Add(XPathString('h4', v)); - end - else - XPathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', ALinks, ANames); - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do - begin - url := FillHost(Module.RootURL, AURL); - if GETWithCookie(MangaInfo.FHTTP, url, Module) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//div[@class="thumbnail"]/img/@src'); - if title = '' then - if Module.Website = 'AtelierDuNoir' then title := XPathString('//div[@class="section-headline"]//h3') - else title := XPathString('//h1[@class="title"]'); - if Pos('emailprotected', title) > 0 then - title := Trim(SeparateLeft(XPathString('//title'), '::')); - authors := TrimLeftChar(XPathString( - '//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), [':', ' ']); - artists := TrimLeftChar(XPathString( - '//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), [':', ' ']); - summary := TrimLeftChar(XPathString( - '//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), [':', ' ']); - for v in XPath('//div[@class="list"]//div[@class="title"]/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - if v.toNode.getAttribute('title') <> '' then - chapterName.Add(v.toNode.getAttribute('title')) - else chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do - begin - PageLinks.Clear; - PageNumber := 0; - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').Count; - s := XPathString('//script[contains(.,"var pages")]'); - if s <> '' then begin - s := GetBetween('var pages = ', ';', s); - if Pos('atob("', s) > 0 then begin - s := GetBetween('atob("', '")', s); - s := Base64Decode(s); - end; - try - ParseHTML(s); - for v in XPath('json(*)()("url")') do - PageLinks.Add(v.toString); - except - end; - end; - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - s := AURL; - if DownloadThread.WorkId > 0 then - s := AppendURLDelim(s) + 'page/' + IncStr(DownloadThread.WorkId); - if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, s), Module) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := XPathString('//div[@id="page"]//img/@src'); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; - begin - Result := AddModule; - with Result do - begin - Website := AWebsite; - RootURL := ARootURL; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; - end; - -begin - AddWebsiteModule('PowerManga', 'http://read.powermanga.org'); - AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com'); - AddWebsiteModule('GoManga', 'http://gomanga.co'); - AddWebsiteModule('OneTimeScans', 'http://otscans.com'); - AddWebsiteModule('SenseScans', 'http://reader.sensescans.com'); - AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com'); - AddWebsiteModule('KireiCake', 'https://reader.kireicake.com'); - AddWebsiteModule('HelveticaScans', 'http://helveticascans.com'); - AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com'); - AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com'); - AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org'); - AddWebsiteModule('ChampionScans', 'http://reader.championscans.com'); - AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org'); - - //es-san - AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com'); - AddWebsiteModule('DejameProbar', 'http://dejameprobar.es'); - AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com'); - AddWebsiteModule('MangaWorksFansub', 'http://lector.mangaworksfansub.net'); - AddWebsiteModule('MasterPieceScans', 'http://reader.manga2me.net'); - AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com'); - AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net'); - AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com'); - AddWebsiteModule('R15TeamScanlation', 'http://www.r15team.com'); - AddWebsiteModule('SantosScan', 'http://santosfansub.com'); - AddWebsiteModule('SeinagiFansub', 'http://seinagi.org'); - AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org'); - AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net'); - AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua new file mode 100644 index 000000000..2b567d1a9 --- /dev/null +++ b/lua/modules/FoOlSlide.lua @@ -0,0 +1,213 @@ +local dirurl = '/directory/' +local dirurlreader = '/reader/directory/' +local dirurlfoolslide = '/foolslide/directory/' +local dirurlslide = '/slide/directory/' +local dirurlslideU = '/Slide/directory/' +local dirurlonline = '/online/directory/' +local dirurlhelvetica = '/r/directory/' + +function getWithCookie(lurl) + local needCookie = { + ['SeinagiAdultoFansub'] = true, + ['TripleSevenScan'] = true, + ['DokiFansubs'] = true + } + if needCookie[module.website] and Pos(dirurl, lurl) then + return http.post(lurl, 'adult=true') + else + return http.get(lurl) + end +end + +function getdirurl(website) + local dirs = { + ['GoManga'] = dirurlreader, + ['Jaiminisbox'] = dirurlreader, + ['TripleSevenScan'] = dirurlreader, + ['DokiFansubs'] = dirurlreader, + ['AtelierDuNoir'] = dirurlreader, + ['OneTimeScans'] = dirurlfoolslide, + ['DejameProbar'] = dirurlslide, + ['MenudoFansub'] = dirurlslide, + ['NeoProjectScan'] = dirurlslide, + ['SolitarioNoFansub'] = dirurlslide, + ['SantosScan'] = dirurlslideU, + ['Pzykosis666HFansub'] = dirurlonline, + ['SeinagiFansub'] = dirurlonline, + ['HelveticaScans'] = dirurlhelvetica + } + if dirs[website] ~= nil then + return dirs[website] + else + return dirurl + end +end + +function getinfo() + local lurl = MaybeFillHost(module.rooturl, url) + local result = net_error + if http.get(lurl) then + x = TXQuery.Create(http.document) + mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail"]/img/@src') + if mangainfo.title == '' then + if module.website == 'AtelierDuNoir' then + mangainfo.title = x.xpathstring('//div[@class="section-headline"]//h3') + else + mangainfo.title = x.xpathstring('//h1[@class="title"]') + end + end + if Pos('emailprotected', mangainfo.title) > 0 then + mangainfo.title = Trim(SeparateLeft(x.xpathstring('//title'), '::')) + end + mangainfo.authors = string.gsub( + x.xpathstring('//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), + '^[%s:]*', '') + mangainfo.artists = string.gsub( + x.xpathstring('//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), + '^[%s:]*', '') + mangainfo.summary = string.gsub( + x.xpathstring('//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), + '^[%s:]*', '') + v = x.xpath('//div[@class="list"]//div[@class="title"]/a') + for i = 1, v.count do + v1 = v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + if v1.getattribute('title') ~= '' then + mangainfo.chapternames.add(v1.getattribute('title')) + else + mangainfo.chapternames.add(v1.ToString) + end + end + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + result = no_error + end + return result +end + +function taskstart() + task.pagelinks.clear() + task.pagenumber = 0 + return true +end + +function getpagenumber() + local result = false + if getWithCookie(MaybeFillHost(module.rooturl, url)) then + x = TXQuery.create(http.document) + task.pagenumber = x.xpath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').count + s = x.xpathstring('//script[contains(.,"var pages")]') + if s ~= '' then + s = GetBetween('var pages = ', ';', s) + if Pos('atob("', s) > 0 then + s = GetBetween('atob("', '")', s) + s = DecodeBase64(s) + end + x.parsehtml(s) + v = x.xpath('json(*)()("url")') + for i = 1, v.count do + task.pagelinks.add(v.get(i).ToString) + end + end + result = true + end + return result +end + +function getimageurl() + local result = false + local s = url + if workid > 0 then + s = AppendURLDelim(s) .. 'page/' .. (workid + 1) + end + if getWithCookie(MaybeFillHost(module.rooturl, s)) then + x = TXQuery.create(http.document) + task.pagelinks.set(workid, x.XPathString('//div[@id="page"]//img/@src')) + end + return result +end + +function getdirectorypagenumber() + local result = net_error + page = 1 + if getWithCookie(module.rooturl .. getdirurl(module.website)) then + result = no_error + x = TXQuery.create(http.document) + v = x.xpath('//*[@class="next"]/a/@href') + for i = 1, v.count do + local s = tonumber(string.match(v.get(i).tostring, '/(%d+)/$')) + if (s ~= nil) and (s > page) then + page = s + end + end + end + return result +end + +function getnameandlink() + local result = net_error + local s = module.rooturl .. getdirurl(module.website) + if url ~= '0' then + s = s .. (tonumber(url) + 1) .. '/' + end + if getWithCookie(s) then + result = no_error + x = TXQuery.create(http.document) + if module.website == 'AtelierDuNoir' then + v = x.xpath('//div[@class="caption"]') + for i = 1, v.count do + v1 = v.get(i) + links.add(x.xpathstring('div/a/@href', v1)) + names.add(x.xpathstring('h4', v1)) + end + else + x.XpathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', links, names) + end + end + return result +end + +function AddWebsiteModule(name, url) + local m = NewModule() + m.website = name + m.rooturl = url + m.lastupdated = 'february, 6 2018' + m.ongetinfo = 'getinfo' + m.OnTaskStart = 'taskstart' + m.OnGetPageNumber = 'getpagenumber' + m.OnGetImageURL = 'getimageurl' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + m.OnGetNameAndLink = 'getnameandlink' + return m +end + +function Init() + AddWebsiteModule('PowerManga', 'http://read.powermanga.org') + AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com') + AddWebsiteModule('GoManga', 'http://gomanga.co') + AddWebsiteModule('OneTimeScans', 'http://otscans.com') + AddWebsiteModule('SenseScans', 'http://reader.sensescans.com') + AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com') + AddWebsiteModule('KireiCake', 'https://reader.kireicake.com') + AddWebsiteModule('HelveticaScans', 'http://helveticascans.com') + AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com') + AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com') + AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org') + AddWebsiteModule('ChampionScans', 'http://reader.championscans.com') + AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org') + + -- es-sc + AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') + AddWebsiteModule('DejameProbar', 'http://dejameprobar.es') + AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com') + AddWebsiteModule('MangaWorksFansub', 'http://lector.mangaworksfansub.net') + AddWebsiteModule('MasterPieceScans', 'http://reader.manga2me.net') + AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com') + AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net') + AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com') + AddWebsiteModule('R15TeamScanlation', 'http://www.r15team.com') + AddWebsiteModule('SantosScan', 'http://santosfansub.com') + AddWebsiteModule('SeinagiFansub', 'http://seinagi.org') + AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org') + AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net') + AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') +end From d1ae3ba3da3d722d995312c26ee657f314718378 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 16:17:54 +0800 Subject: [PATCH 2081/2794] add imgur lua script (close #905) --- lua/modules/Imgur.lua | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lua/modules/Imgur.lua diff --git a/lua/modules/Imgur.lua b/lua/modules/Imgur.lua new file mode 100644 index 000000000..b7e287ee5 --- /dev/null +++ b/lua/modules/Imgur.lua @@ -0,0 +1,38 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1[@class="post-title"]') + mangainfo.chapterlinks.add(url) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_error + end +end + +function taskstart() + task.pagelinks.clear() + return true +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + x.xpathStringAll('//div[contains(@class,"post-image")]/a/img/concat("https:",@src)', task.pagelinks) + return true + else + return false + end + return true +end + +function Init() + m=NewModule() + m.website='Imgur' + m.rooturl='https://imgur.com' + m.lastupdated='February 6, 2018' + m.OnGetInfo='getinfo' + m.OnTaskStart='taskstart' + m.OnGetPageNumber='getpagenumber' +end From 5249da3384b0067623091ebd7566a28882ec0e40 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 16:23:34 +0800 Subject: [PATCH 2082/2794] update changelog --- changelog.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 1e67b8208..db6c25a1a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,12 +5,14 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.133.0 (xx-xx-2018) -[+] Added left download toolbar to move selected download(s) +[+] Added left download toolbar to move selected download(s). Options > View [*] View manga info preserve saveto location from download or favorite [+] Added WorldThree [EN-SC] [+] Added PsychoPlay [EN-SC] [+] Added MangaZukiRaws [Raws] [+] Added MangaDeep [EN] +[+] Added lua support to add website module at runtime +[+] Added Imgur [-] Removed MangaSpy [-] Removed MangaIce [*] MangaZuki: fixed all From a0076503559e9742e310ae09c97e4067a83a3fbd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 16:36:12 +0800 Subject: [PATCH 2083/2794] cleanup --- baseunits/lua/LuaWebsiteModules.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 4069e7a6f..15caadc03 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -576,7 +576,6 @@ function TLuaWebsiteModule.LuaDoMe(L: Plua_State): Integer; Result := LuaLoadFromStream(L, Container.ByteCode, PChar(Container.FileName)); if Result = 0 then Result := lua_pcall(L, 0, 0, 0); - writeln(LuaStackToString(L)); end; procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; From 549dbbbc2f5883e7fb32fc151f089b76ba6b2f08 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 16:36:35 +0800 Subject: [PATCH 2084/2794] luadumpfiletostream default stripdebug false --- baseunits/lua/LuaBase.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 577132312..da797c8b8 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -16,7 +16,7 @@ function LuaNewBaseState: Plua_State; function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; function LuaDumpFileToStream(L: Plua_State; AFilename: String; - AStripDebug: Boolean = True): TMemoryStream; + AStripDebug: Boolean = False): TMemoryStream; function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiChar): Integer; implementation From 46ffaa44c7ca816c88e4b1b57ffddfd01eaef311 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 17:09:35 +0800 Subject: [PATCH 2085/2794] add luasynautil --- baseunits/lua/LuaBase.pas | 3 ++- baseunits/lua/LuaSynaUtil.pas | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 baseunits/lua/LuaSynaUtil.pas diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index da797c8b8..1f0755bdd 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -22,7 +22,7 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh implementation uses - LuaClass, luaStrings, LuaBaseUnit, LuaRegex, MultiLog; + LuaClass, luaStrings, LuaBaseUnit, LuaRegex, LuaSynaUtil, MultiLog; function luabase_print(L: Plua_State): Integer; cdecl; var @@ -38,6 +38,7 @@ procedure LuaBaseRegister(L: Plua_State); lua_register(L, 'print', @luabase_print); luaRegexRegister(L); luaBaseUnitRegister(L); + luaSynaUtilRegister(L); luaClassRegisterAll(L); end; diff --git a/baseunits/lua/LuaSynaUtil.pas b/baseunits/lua/LuaSynaUtil.pas new file mode 100644 index 000000000..bacf97227 --- /dev/null +++ b/baseunits/lua/LuaSynaUtil.pas @@ -0,0 +1,43 @@ +unit LuaSynaUtil; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, synautil; + +procedure luaSynaUtilRegister(L: Plua_State); + +implementation + +uses + LuaUtils; + +function lua_getbetween(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, GetBetween(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3))); + Result := 1; +end; + +function lua_separateleft(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, SeparateLeft(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +function lua_separateright(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, SeparateRight(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +procedure luaSynaUtilRegister(L: Plua_State); +begin + luaPushFunctionGlobal(L, 'GetBetween', @lua_getbetween); + luaPushFunctionGlobal(L, 'SeparateLeft', @lua_separateleft); + luaPushFunctionGlobal(L, 'SeparateRight', @lua_separateright); +end; + +end. + From e4033f8cd5478d0b7e51563b12c9c63ddc758a3e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 17:18:30 +0800 Subject: [PATCH 2086/2794] cleanup project options --- mangadownloader/md.lpi | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 357b5297a..478810d98 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -24,7 +24,7 @@ <MinorVersionNr Value="9"/> <RevisionNr Value="132"/> <Attributes pvaPrivateBuild="True"/> - <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2017" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> + <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> <BuildModes Count="6"> <Item1 Name="Win32" Default="True"/> @@ -36,8 +36,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> @@ -74,8 +73,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -120,8 +118,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -161,8 +158,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -218,8 +214,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -258,16 +253,18 @@ </Other> </CompilerOptions> </Item6> - <SharedMatrixOptions Count="9"> - <Item1 ID="465017374973" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> - <Item2 ID="534084266787" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -WC"/> - <Item3 ID="951904047630" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> - <Item4 ID="140379931701" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> - <Item5 ID="729045573668" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> - <Item6 ID="200657967120" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> - <Item7 ID="915259842272" Modes="Win32 Debug Leaks,Win64 Debug Leaks" Value="-dDEVBUILD"/> - <Item8 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> - <Item9 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <SharedMatrixOptions Count="11"> + <Item1 ID="285210846225" Modes="Win32 Debug Leaks" Value="-Fu..\baseunits -Fu..\baseunits\animatedgifs -Fu..\baseunits\SimpleException -Fu..\baseunits\modules -Fu..\baseunits\extras -Fuforms"/> + <Item2 ID="787838556410" Modes="Win32 Debug Leaks" Value="-Fi..\baseunits\includes\AnimeA -Fi..\baseunits\includes\AnimeStory -Fi..\baseunits\includes\AnimExtremist -Fi..\baseunits\includes\CentralDeMangas -Fi..\baseunits\includes\EGScans -Fi..\baseunits\includes\EsMangaHere -Fi..\baseunits\includes\Kivmanga -Fi..\baseunits\includes\LectureEnLigne -Fi..\baseunits\includes\MangaAr -Fi..\baseunits\includes\S2scans -Fi..\baseunits\includes\ScanManga -Fi..\baseunits\includes\Starkana -Fi..\baseunits\includes\Turkcraft -Fi..\baseunits\includes\VnSharing -Fi..\baseunits\includes\MeinManga -Fi..\baseunits\includes\MangaREADER_POR -Fi..\baseunits\includes\MangasPROJECT"/> + <Item3 ID="465017374973" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> + <Item4 ID="534084266787" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -WC"/> + <Item5 ID="951904047630" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item6 ID="140379931701" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> + <Item7 ID="729045573668" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> + <Item8 ID="200657967120" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> + <Item9 ID="915259842272" Modes="Win32 Debug Leaks,Win64 Debug Leaks" Value="-dDEVBUILD"/> + <Item10 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> + <Item11 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> @@ -425,8 +422,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\3rd\BESEN\src;..\3rd\internettools\data"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\lua;..\baseunits\pcre;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <CodeGeneration> From 593ea25f6b21091c3e16c96b43cb0409fa76d717 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 17:40:34 +0800 Subject: [PATCH 2087/2794] add luasynacode --- baseunits/lua/LuaBase.pas | 5 +- baseunits/lua/LuaBaseUnit.pas | 2 - baseunits/lua/LuaSynaCode.pas | 134 ++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 baseunits/lua/LuaSynaCode.pas diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 1f0755bdd..42dd420f4 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -22,7 +22,7 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh implementation uses - LuaClass, luaStrings, LuaBaseUnit, LuaRegex, LuaSynaUtil, MultiLog; + LuaClass, luaStrings, LuaBaseUnit, LuaRegex, LuaSynaUtil, LuaSynaCode, MultiLog; function luabase_print(L: Plua_State): Integer; cdecl; var @@ -36,9 +36,12 @@ function luabase_print(L: Plua_State): Integer; cdecl; procedure LuaBaseRegister(L: Plua_State); begin lua_register(L, 'print', @luabase_print); + luaRegexRegister(L); luaBaseUnitRegister(L); luaSynaUtilRegister(L); + luaSynaCodeRegister(L); + luaClassRegisterAll(L); end; diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 01cc87c44..22faee366 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -101,8 +101,6 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'AppendURLDelimleft', @lua_appendurldelimleft); luaPushFunctionGlobal(L, 'RemoveURLDelim', @lua_removeurldelim); luaPushFunctionGlobal(L, 'RemoveURLDelimLeft', @lua_removeurldelimleft); - luaPushFunctionGlobal(L, 'EncodeBase64', @lua_encodebase64); - luaPushFunctionGlobal(L, 'DecodeBase64', @lua_decodebase64); end; end. diff --git a/baseunits/lua/LuaSynaCode.pas b/baseunits/lua/LuaSynaCode.pas new file mode 100644 index 000000000..e41284791 --- /dev/null +++ b/baseunits/lua/LuaSynaCode.pas @@ -0,0 +1,134 @@ +unit LuaSynaCode; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, synacode; + +procedure luaSynaCodeRegister(L: Plua_State); + +implementation + +uses + LuaUtils; + +function lua_decodeurl(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, DecodeURL(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_encodeurl(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, EncodeURL(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_decodeuu(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, DecodeUU(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_encodeuu(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, EncodeUU(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_encodeurlelement(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, EncodeURLElement(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_decodebase64(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, DecodeBase64(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_encodebase64(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, EncodeBase64(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_crc16(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, Crc16(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_crc32(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, Crc32(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_md4(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, MD4(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_md5(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, MD5(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_hmac_md5(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, HMAC_MD5(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +function lua_md5longhash(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, MD5LongHash(lua_tostring(L, 1), lua_tointeger(L, 2))); + Result := 1; +end; + +function lua_sha1(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, SHA1(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_hmac_sha1(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, HMAC_SHA1(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; +end; + +function lua_sha1longhash(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, SHA1LongHash(lua_tostring(L, 1), lua_tointeger(L, 2))); + Result := 1; +end; + +procedure luaSynaCodeRegister(L: Plua_State); +begin + luaPushFunctionGlobal(L, 'DecodeURL', @lua_decodeurl); + luaPushFunctionGlobal(L, 'EncodeURL', @lua_encodeurl); + luaPushFunctionGlobal(L, 'DecodeUU', @lua_decodeuu); + luaPushFunctionGlobal(L, 'EncodeUU', @lua_encodeuu); + luaPushFunctionGlobal(L, 'EncodeURLElement', @lua_encodeurlelement); + luaPushFunctionGlobal(L, 'DecodeBase64', @lua_decodebase64); + luaPushFunctionGlobal(L, 'EncodeBase64', @lua_encodebase64); + luaPushFunctionGlobal(L, 'CRC16', @lua_crc16); + luaPushFunctionGlobal(L, 'CRC32', @lua_crc32); + luaPushFunctionGlobal(L, 'MD4', @lua_md4); + luaPushFunctionGlobal(L, 'MD5', @lua_md5); + luaPushFunctionGlobal(L, 'HMAC_MD5', @lua_hmac_md5); + luaPushFunctionGlobal(L, 'MD5LongHash', @lua_md5longhash); + luaPushFunctionGlobal(L, 'SHA1', @lua_sha1); + luaPushFunctionGlobal(L, 'HMAC_SHA1', @lua_hmac_sha1); + luaPushFunctionGlobal(L, 'SHA1LongHash', @lua_sha1longhash); +end; + +end. + From f53e055aab9ee9173496feb7e6a7a4989550ea01 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 17:55:43 +0800 Subject: [PATCH 2088/2794] fix project options path --- mangadownloader/md.lpi | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 478810d98..5393c17ba 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -158,7 +158,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\lua"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;..\baseunits\lua;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -191,15 +192,6 @@ </Options> </Linking> <Other> - <OtherDefines Count="7"> - <Define0 Value="MANGADOWNLOADER"/> - <Define1 Value="DOWNLOADER"/> - <Define2 Value="SELFUPDATE"/> - <Define3 Value="DEBUGLEAKS"/> - <Define4 Value="MULTILOG"/> - <Define5 Value="USE_SOROKINS_REGEX"/> - <Define6 Value="USE_BBFULL_UNICODE"/> - </OtherDefines> <ExecuteAfter> <Command Value="cmd.exe /c copy /y languages\*.po ..\bin\languages\"/> </ExecuteAfter> @@ -214,7 +206,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT;..\baseunits\lua"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;..\baseunits\lua;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -253,18 +246,17 @@ </Other> </CompilerOptions> </Item6> - <SharedMatrixOptions Count="11"> - <Item1 ID="285210846225" Modes="Win32 Debug Leaks" Value="-Fu..\baseunits -Fu..\baseunits\animatedgifs -Fu..\baseunits\SimpleException -Fu..\baseunits\modules -Fu..\baseunits\extras -Fuforms"/> - <Item2 ID="787838556410" Modes="Win32 Debug Leaks" Value="-Fi..\baseunits\includes\AnimeA -Fi..\baseunits\includes\AnimeStory -Fi..\baseunits\includes\AnimExtremist -Fi..\baseunits\includes\CentralDeMangas -Fi..\baseunits\includes\EGScans -Fi..\baseunits\includes\EsMangaHere -Fi..\baseunits\includes\Kivmanga -Fi..\baseunits\includes\LectureEnLigne -Fi..\baseunits\includes\MangaAr -Fi..\baseunits\includes\S2scans -Fi..\baseunits\includes\ScanManga -Fi..\baseunits\includes\Starkana -Fi..\baseunits\includes\Turkcraft -Fi..\baseunits\includes\VnSharing -Fi..\baseunits\includes\MeinManga -Fi..\baseunits\includes\MangaREADER_POR -Fi..\baseunits\includes\MangasPROJECT"/> + <SharedMatrixOptions Count="10"> + <Item1 ID="285210846225" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-Fu..\baseunits -Fu..\baseunits\animatedgifs -Fu..\baseunits\SimpleException -Fu..\baseunits\modules -Fu..\baseunits\extras -Fuforms"/> + <Item2 ID="787838556410" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-Fi..\baseunits\includes\AnimeA -Fi..\baseunits\includes\AnimeStory -Fi..\baseunits\includes\AnimExtremist -Fi..\baseunits\includes\CentralDeMangas -Fi..\baseunits\includes\EGScans -Fi..\baseunits\includes\EsMangaHere -Fi..\baseunits\includes\Kivmanga -Fi..\baseunits\includes\LectureEnLigne -Fi..\baseunits\includes\MangaAr -Fi..\baseunits\includes\S2scans -Fi..\baseunits\includes\ScanManga -Fi..\baseunits\includes\Starkana -Fi..\baseunits\includes\Turkcraft -Fi..\baseunits\includes\VnSharing -Fi..\baseunits\includes\MeinManga -Fi..\baseunits\includes\MangaREADER_POR -Fi..\baseunits\includes\MangasPROJECT"/> <Item3 ID="465017374973" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> - <Item4 ID="534084266787" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -WC"/> - <Item5 ID="951904047630" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> - <Item6 ID="140379931701" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> - <Item7 ID="729045573668" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> - <Item8 ID="200657967120" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> - <Item9 ID="915259842272" Modes="Win32 Debug Leaks,Win64 Debug Leaks" Value="-dDEVBUILD"/> - <Item10 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> - <Item11 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item4 ID="729045573668" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> + <Item5 ID="200657967120" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> + <Item6 ID="534084266787" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -dDEVBUILD -WC"/> + <Item7 ID="951904047630" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item8 ID="140379931701" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> + <Item9 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> + <Item10 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From a41b1bfa59bde2c0ab7f1b0b4a05a3c9e8b226f3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 18:04:39 +0800 Subject: [PATCH 2089/2794] use decoderfcdatetime --- baseunits/httpsendthread.pas | 11 ++++------- baseunits/uBaseUnit.pas | 5 +---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 2a98227a2..ae6f59c09 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -357,15 +357,12 @@ procedure THTTPSendThread.ParseCookiesExpires; s := Copy(s, p, Length(s)); s := SeparateLeft(SeparateRight(s,'='),';'); s := Trim(SeparateLeft(s, 'GMT')); - c := 0.0; - try - c := UniversalTimeToLocal(ScanDateTime(HTTPCookieExpiresFormat, s, HTTPFormatSettings)); - if (FCookiesExpires = 0.0) or (c < FCookiesExpires) then - FCookiesExpires := c; - except - end; + c := DecodeRfcDateTime(s); + if (FCookiesExpires = 0.0) or (c < FCookiesExpires) then + FCookiesExpires := c; end; end; + write end; function THTTPSendThread.InternalHTTPRequest(const Method, URL: String; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 823ce2b52..865c6e0af 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3472,10 +3472,7 @@ function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String s := Trim(AHTTP.Headers.Values['last-modified']); lastmodified := 0; if s <> '' then - try - lastmodified := DateTimeToFileDate(ScanDateTime(HTTPDateTimeFormatStr, s, FMDFormatSettings)); - except - end; + lastmodified := DateTimeToFileDate(DecodeRfcDateTime(s)); Result := SaveImageStreamToFile(AHTTP.Document, Path, FileName, lastmodified); end; From 459c8eff21dcbbde66a00d373b6ad596392e09e8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 7 Feb 2018 18:29:36 +0800 Subject: [PATCH 2090/2794] Bump version 0.9.133.0 --- changelog.txt | 4 ++-- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index db6c25a1a..e324d9e21 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,14 +4,14 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.133.0 (xx-xx-2018) +0.9.133.0 (07-02-2018) [+] Added left download toolbar to move selected download(s). Options > View [*] View manga info preserve saveto location from download or favorite +[+] Added Lua support to add website module at runtime [+] Added WorldThree [EN-SC] [+] Added PsychoPlay [EN-SC] [+] Added MangaZukiRaws [Raws] [+] Added MangaDeep [EN] -[+] Added lua support to add website module at runtime [+] Added Imgur [-] Removed MangaSpy [-] Removed MangaIce diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5393c17ba..f80fc525e 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="132"/> + <RevisionNr Value="133"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index c6726ac50..1566ee663 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.132.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.132.0/fmd_0.9.132.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.132.0/fmd_0.9.132.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.132.0/fmd_0.9.132.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.132.0/fmd_0.9.132.0_Win64.7z +VERSION=0.9.133.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.133.0/fmd_0.9.133.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.133.0/fmd_0.9.133.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.133.0/fmd_0.9.133.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.133.0/fmd_0.9.133.0_Win64.7z From 04363626abd573d34fb3992fe9363794aaaf0a4e Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Wed, 7 Feb 2018 15:53:40 +0300 Subject: [PATCH 2091/2794] Update fmd.tr_TR.po Tried to translate line 1795, but i don't know if it is ok. What is that "pnDownloadList"? --- mangadownloader/languages/fmd.tr_TR.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 1ce9e8e3d..09ddde9f0 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -761,7 +761,7 @@ msgstr "\"Tüm tamamlanmış görevleri sil\" seçeneğini indirmeler araç çub #: tmainform.cboptionshowdownloadtoolbarleft.caption msgid "Show left downloads toolbar" -msgstr "" +msgstr "Sol indirmeler araç çubuğunu göster" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -1794,7 +1794,7 @@ msgstr "Manga listesini güncelle" #: tmainform.pndownloadlist.caption msgid "pnDownloadList" -msgstr "" +msgstr "pnİndirmeListesi" #: tmainform.rball.caption msgid "Have all genre checked" @@ -1832,19 +1832,19 @@ msgstr "Tümünü Durdur" #: tmainform.tbmidownloadmovebottom.hint msgid "Move selected item(s) to bottom" -msgstr "" +msgstr "Seçilen içerik(ler)i en alta taşı" #: tmainform.tbmidownloadmovedown.hint msgid "Move selected item(s) down" -msgstr "" +msgstr "Seçilen içerik(ler)i alta taşı" #: tmainform.tbmidownloadmovetop.hint msgid "Move selected item(s) to top" -msgstr "" +msgstr "Seçilen içerik(ler)i en üste taşı" #: tmainform.tbmidownloadmoveup.hint msgid "Move selected item(s) up" -msgstr "" +msgstr "Seçilen içerik(ler)i üste taşı" #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" From 9e4d6fa14fb831bde53141981b13071782c9ca3f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Feb 2018 19:24:24 +0300 Subject: [PATCH 2092/2794] cf, add Response parameter #914 --- baseunits/WebsiteModules.pas | 2 +- baseunits/modules/Cloudflare.pas | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index e37effa0d..c5fa5b39f 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -299,7 +299,7 @@ procedure TModuleContainer.CheckCloudflareEnabled(const AHTTP: THTTPSendThread); function TModuleContainer.CloudflareHTTPRequest(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject): Boolean; begin - Result := Cloudflare.GETCF(AHTTP, Method, URL, FCloudflareCF); + Result := Cloudflare.CFRequest(AHTTP, Method, URL, Response, FCloudflareCF); end; procedure TModuleContainer.SetTotalDirectory(AValue: Integer); diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 3f7d7bf42..c1a5e3039 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -29,7 +29,7 @@ THTTPSendThreadHelper = class helper for THTTPSendThread function GETCF(const AURL: String; const CFProps: TCFProps): Boolean; end; -function GETCF(const AHTTP: THTTPSendThread; const Method, AURL: String; const CFProps: TCFProps): Boolean; +function CFRequest(const AHTTP: THTTPSendThread; const Method, AURL: String; const Response: TObject; const CFProps: TCFProps): Boolean; implementation @@ -168,7 +168,7 @@ function CFJS(const AHTTP: THTTPSendThread; AURL: String; var Acf_clearance: Str AHTTP.RetryCount := maxretry; end; -function GETCF(const AHTTP: THTTPSendThread; const Method, AURL: String; const CFProps: TCFProps): Boolean; +function CFRequest(const AHTTP: THTTPSendThread; const Method, AURL: String; const Response: TObject; const CFProps: TCFProps): Boolean; begin Result := False; if AHTTP = nil then Exit; @@ -200,6 +200,12 @@ function GETCF(const AHTTP: THTTPSendThread; const Method, AURL: String; const C if not AHTTP.ThreadTerminated then Result := AHTTP.HTTPRequest(Method, AURL); end; + if Assigned(Response) then + if Response is TStringList then + TStringList(Response).LoadFromStream(AHTTP.Document) + else + if Response is TStream then + AHTTP.Document.SaveToStream(TStream(Response)); end; { TCFProps } @@ -237,7 +243,7 @@ procedure TCFProps.AddCookiesTo(const ACookies: TStringList); function THTTPSendThreadHelper.GETCF(const AURL: String; const CFProps: TCFProps): Boolean; begin - Result := Cloudflare.GETCF(Self, 'GET', AURL, CFProps); + Result := Cloudflare.CFRequest(Self, 'GET', AURL, nil, CFProps); end; end. From 9e531291f76038a1062a121dd295674b942fc6a4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Feb 2018 19:44:19 +0300 Subject: [PATCH 2093/2794] Add Lhscans [RAW] fixes #730 --- baseunits/ModuleList.inc | 1 + baseunits/modules/Lhscans.pas | 95 +++++++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Lhscans.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index dd0e6ecc3..4053b2cac 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -66,6 +66,7 @@ uses LHTranslation, MangaRock, PsychoPlay, + Lhscans, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/Lhscans.pas b/baseunits/modules/Lhscans.pas new file mode 100644 index 000000000..37dc77d2c --- /dev/null +++ b/baseunits/modules/Lhscans.pas @@ -0,0 +1,95 @@ +unit Lhscans; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//img[@class="thumbnail"]/@src'); + if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); + if title = '' then title := Trim(SeparateLeft(XPathString('//title'), '- Raw')); + authors := XPathString('//ul[@class="manga-info"]/li[contains(., "Author")]//a'); + genres := XPathStringAll('//ul[@class="manga-info"]/li[contains(., "Genre")]//a'); + status := MangaInfoStatusIfPos(XPathString('//ul[@class="manga-info"]/li[contains(., "Status")]//a')); + summary := XPathString('//h3[text()="Description"]/following-sibling::p'); + XPathHREFAll('//div[@id="tab-chapper"]//table/tbody/tr/td/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +begin + Result := False; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then + begin + Result := True; + XPathStringAll('//img[@class="chapter-img"]/@src', Document, PageLinks); + end; + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list.html?listType=allABC') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//span[@manga-slug]//a') do begin + ANames.Add(Trim(SeparateLeft(v.toString, '- Raw'))); + ALinks.Add(v.toNode.getAttribute('href')); + end; + finally + Free; + end; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'Lhscans'; + RootURL := 'http://lhscans.com'; + TotalDirectory := 1; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetNameAndLink := @GetNameAndLink; + end; +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index 62d63f221..c5771754a 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -13,7 +13,7 @@ Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaS Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas -Raw=RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws +Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub From 151599a3e3dadea0f296bf1d8c85273a5bf0936f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Feb 2018 19:56:45 +0300 Subject: [PATCH 2094/2794] mangastream, fix domain --- baseunits/modules/MangaStream.pas | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas index 8b5e39944..3c28177c0 100644 --- a/baseunits/modules/MangaStream.pas +++ b/baseunits/modules/MangaStream.pas @@ -12,9 +12,6 @@ implementation uses simplehtmltreeparser, xquery, RegExpr; -const - readURL = 'http://readms.com'; - function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; begin @@ -118,7 +115,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; Container.PageNumber := 0; Source := TStringList.Create; try - if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(readURL, AURL + '/1'), + if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(Module.RootURL, AURL + '/1'), Container.Manager.retryConnect) then if Source.Count > 0 then begin @@ -154,7 +151,7 @@ function GetImageURL(const DownloadThread: TDownloadThread; Source := TStringList.Create; try if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(readURL, AURL)) + + AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.WorkId), Manager.retryConnect) then if Source.Count > 0 then begin @@ -179,7 +176,7 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaStream'; - RootURL := 'http://mangastream.com'; + RootURL := 'https://readms.net'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; From d5a1141f54f6cb368b18e3d8a741c6ca07c682ea Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 8 Feb 2018 06:00:19 +0300 Subject: [PATCH 2095/2794] update russian localization --- mangadownloader/languages/fmd.ru_RU.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 9587087c9..31feb3286 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -747,7 +747,7 @@ msgstr "Показать \"Удалить все завершенные зада #: tmainform.cboptionshowdownloadtoolbarleft.caption msgid "Show left downloads toolbar" -msgstr "" +msgstr "Показать дополнительную панель загрузок" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -1774,7 +1774,7 @@ msgstr "Обновить список манги" #: tmainform.pndownloadlist.caption msgid "pnDownloadList" -msgstr "" +msgstr "pnDownloadList" #: tmainform.rball.caption msgid "Have all genre checked" @@ -1812,19 +1812,19 @@ msgstr "Остановить все" #: tmainform.tbmidownloadmovebottom.hint msgid "Move selected item(s) to bottom" -msgstr "" +msgstr "Переместить выбранные элементы в конец списка" #: tmainform.tbmidownloadmovedown.hint msgid "Move selected item(s) down" -msgstr "" +msgstr "Сдвинуть выбранные элементы вниз" #: tmainform.tbmidownloadmovetop.hint msgid "Move selected item(s) to top" -msgstr "" +msgstr "Переместить выбранные элементы в начало списка" #: tmainform.tbmidownloadmoveup.hint msgid "Move selected item(s) up" -msgstr "" +msgstr "Сдвинуть выбранные элементы вверх" #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" From 18faf92034f3d4e5e89f1b65d9c5d42131d4b302 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 8 Feb 2018 06:19:17 +0300 Subject: [PATCH 2096/2794] cf, cleanup --- baseunits/modules/Cloudflare.pas | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index c1a5e3039..24ea096ef 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -23,12 +23,6 @@ TCFProps = class procedure AddCookiesTo(const ACookies: TStringList); end; - { THTTPSendThreadHelper } - - THTTPSendThreadHelper = class helper for THTTPSendThread - function GETCF(const AURL: String; const CFProps: TCFProps): Boolean; - end; - function CFRequest(const AHTTP: THTTPSendThread; const Method, AURL: String; const Response: TObject; const CFProps: TCFProps): Boolean; implementation @@ -239,11 +233,4 @@ procedure TCFProps.AddCookiesTo(const ACookies: TStringList); ACookies.Values['cf_clearance'] := cf_clearance; end; -{ THTTPSendThreadHelper } - -function THTTPSendThreadHelper.GETCF(const AURL: String; const CFProps: TCFProps): Boolean; -begin - Result := Cloudflare.CFRequest(Self, 'GET', AURL, nil, CFProps); -end; - end. From 7ba2c832143b57aceab40aa281caec3d320e03a6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 11:26:10 +0800 Subject: [PATCH 2097/2794] add units path to dev build mode so lazarus can scan them --- mangadownloader/md.lpi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index f80fc525e..de52a11cf 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -73,7 +73,8 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)"/> + <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> + <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;..\baseunits\lua;forms"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> From aaa8b84301d1c8a1af6f258839aac5d2d217f9aa Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 11:27:14 +0800 Subject: [PATCH 2098/2794] luaregex, use original method name for easier converting existing module --- baseunits/lua/LuaRegex.pas | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/baseunits/lua/LuaRegex.pas b/baseunits/lua/LuaRegex.pas index 7295a8cdb..fbf2e9c62 100644 --- a/baseunits/lua/LuaRegex.pas +++ b/baseunits/lua/LuaRegex.pas @@ -11,6 +11,9 @@ procedure luaRegexRegister(L: Plua_State); implementation +uses + LuaUtils; + function re_exec(L: Plua_State): Integer; cdecl; begin lua_pushboolean(L, ExecRegExpr(lua_tostring(L, 1), lua_tostring(L, 2))); @@ -23,18 +26,10 @@ function re_replace(L: Plua_State): Integer; cdecl; Result := 1; end; -const - methods: packed array [0..2] of luaL_Reg = ( - (name: 'Exec'; func: @re_exec), - (name: 'Replace'; func: @re_replace), - (name: nil; func: nil) - ); - procedure luaRegexRegister(L: Plua_State); begin - lua_newtable(L); - luaL_setfuncs(L, @methods, 0); - lua_setglobal(L, 'RegExpr'); + luaPushFunctionGlobal(L, 'ExecRegExpr', @re_exec); + luaPushFunctionGlobal(L, 'ReplaceRegExpr', @re_replace); end; end. From d97bde9942148d14f0a43037f0fd068bff6448cf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 12:29:07 +0800 Subject: [PATCH 2099/2794] cleanup localizations --- mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.lrj | 1 - mangadownloader/languages/fmd.de.po | 4 ---- mangadownloader/languages/fmd.el_GR.po | 4 ---- mangadownloader/languages/fmd.en.po | 4 ---- mangadownloader/languages/fmd.es.po | 4 ---- mangadownloader/languages/fmd.id_ID.po | 4 ---- mangadownloader/languages/fmd.pl_PL.po | 4 ---- mangadownloader/languages/fmd.po | 4 ---- mangadownloader/languages/fmd.pt_BR.po | 4 ---- mangadownloader/languages/fmd.ru_RU.po | 4 ---- mangadownloader/languages/fmd.tr_TR.po | 4 ---- 12 files changed, 42 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 70e0e78f6..a084ff90d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -289,7 +289,6 @@ object MainForm: TMainForm Width = 556 Align = alClient Anchors = [akTop, akLeft, akRight] - Caption = 'pnDownloadList' ClientHeight = 464 ClientWidth = 556 TabOrder = 1 diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 93413daee..45643c6b3 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -5,7 +5,6 @@ {"hash":190989196,"name":"tmainform.tbdownloadstopall.caption","sourcebytes":[83,116,111,112,32,65,108,108],"value":"Stop All"}, {"hash":235571507,"name":"tmainform.tbdownloaddeletecompleted.caption","sourcebytes":[68,101,108,101,116,101,32,97,108,108,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115],"value":"Delete all completed tasks"}, {"hash":173363182,"name":"tmainform.eddownloadssearch.texthint","sourcebytes":[83,101,97,114,99,104,32,100,111,119,110,108,111,97,100,115,46,46,46],"value":"Search downloads..."}, -{"hash":131060932,"name":"tmainform.pndownloadlist.caption","sourcebytes":[112,110,68,111,119,110,108,111,97,100,76,105,115,116],"value":"pnDownloadList"}, {"hash":14216608,"name":"tmainform.tbmidownloadmovetop.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,116,111,32,116,111,112],"value":"Move selected item(s) to top"}, {"hash":160874656,"name":"tmainform.tbmidownloadmoveup.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,117,112],"value":"Move selected item(s) up"}, {"hash":113368910,"name":"tmainform.tbmidownloadmovedown.hint","sourcebytes":[77,111,118,101,32,115,101,108,101,99,116,101,100,32,105,116,101,109,40,115,41,32,100,111,119,110],"value":"Move selected item(s) down"}, diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index df2c6f842..25a3f8699 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -1793,10 +1793,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Aktualisiere Manga-Liste" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Have all genre checked" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 186e4c942..cf310eaf1 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -1848,10 +1848,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Ενημέρωση λίστας manga" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Όλα τα είδη που έχουν σημανθεί" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 7cbbafbbe..9a5df2977 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1762,10 +1762,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Update manga list" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "pnDownloadList" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Have all genre checked" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index ec5592f26..5f3bfcd0c 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1770,10 +1770,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Actualizar Lista de Manga" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Tener Todos los Géneros Marcados" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 1abf877fe..808be25f5 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1770,10 +1770,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Perbarui daftar komik" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Memiliki semua genre yang dicentang" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index cf9bd9493..3ef4d30ba 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -1790,10 +1790,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Aktualizacja listy manga" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Miej wszystkie gatunki zaznaczone" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 3b33e1382..3a4dab5b6 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1695,10 +1695,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 5b170e2f4..69b329237 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1791,10 +1791,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Atualizar lista de mangá" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Todos os gêneros marcados" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 31feb3286..e377ebe0b 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -1772,10 +1772,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Обновить список манги" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "pnDownloadList" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Содержит все отмеченные жанры" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 09ddde9f0..32d78663c 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -1792,10 +1792,6 @@ msgctxt "TMAINFORM.MNUPDATELIST.CAPTION" msgid "Update manga list" msgstr "Manga listesini güncelle" -#: tmainform.pndownloadlist.caption -msgid "pnDownloadList" -msgstr "pnİndirmeListesi" - #: tmainform.rball.caption msgid "Have all genre checked" msgstr "Tüm türleri seç" From e8ff0a2653422c5c90b855f19da60c3a44718f94 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 13:02:03 +0800 Subject: [PATCH 2100/2794] fix project options additional and overrides for current project --- mangadownloader/md.lpi | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index de52a11cf..faa5366ca 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -73,8 +73,7 @@ <Filename Value="..\bin\fmd"/> </Target> <SearchPaths> - <IncludeFiles Value="$(ProjOutDir);..\baseunits\includes\AnimeA;..\baseunits\includes\AnimeStory;..\baseunits\includes\AnimExtremist;..\baseunits\includes\CentralDeMangas;..\baseunits\includes\EGScans;..\baseunits\includes\EsMangaHere;..\baseunits\includes\Kivmanga;..\baseunits\includes\LectureEnLigne;..\baseunits\includes\MangaAr;..\baseunits\includes\S2scans;..\baseunits\includes\ScanManga;..\baseunits\includes\Starkana;..\baseunits\includes\Turkcraft;..\baseunits\includes\VnSharing;..\baseunits\includes\MeinManga;..\baseunits\includes\MangaREADER_POR;..\baseunits\includes\MangasPROJECT"/> - <OtherUnitFiles Value="..\baseunits;..\baseunits\animatedgifs;..\baseunits\SimpleException;..\baseunits\modules;..\baseunits\extras;..\baseunits\lua;forms"/> + <IncludeFiles Value="$(ProjOutDir)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> </SearchPaths> <Parsing> @@ -247,17 +246,18 @@ </Other> </CompilerOptions> </Item6> - <SharedMatrixOptions Count="10"> - <Item1 ID="285210846225" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-Fu..\baseunits -Fu..\baseunits\animatedgifs -Fu..\baseunits\SimpleException -Fu..\baseunits\modules -Fu..\baseunits\extras -Fuforms"/> - <Item2 ID="787838556410" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-Fi..\baseunits\includes\AnimeA -Fi..\baseunits\includes\AnimeStory -Fi..\baseunits\includes\AnimExtremist -Fi..\baseunits\includes\CentralDeMangas -Fi..\baseunits\includes\EGScans -Fi..\baseunits\includes\EsMangaHere -Fi..\baseunits\includes\Kivmanga -Fi..\baseunits\includes\LectureEnLigne -Fi..\baseunits\includes\MangaAr -Fi..\baseunits\includes\S2scans -Fi..\baseunits\includes\ScanManga -Fi..\baseunits\includes\Starkana -Fi..\baseunits\includes\Turkcraft -Fi..\baseunits\includes\VnSharing -Fi..\baseunits\includes\MeinManga -Fi..\baseunits\includes\MangaREADER_POR -Fi..\baseunits\includes\MangasPROJECT"/> - <Item3 ID="465017374973" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> - <Item4 ID="729045573668" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> - <Item5 ID="200657967120" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> - <Item6 ID="534084266787" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -dDEVBUILD -WC"/> - <Item7 ID="951904047630" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> - <Item8 ID="140379931701" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> - <Item9 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g-"/> - <Item10 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <SharedMatrixOptions Count="11"> + <Item1 ID="285210846225" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-Fu..\baseunits -Fu..\baseunits\animatedgifs -Fu..\baseunits\SimpleException -Fu..\baseunits\modules -Fu..\baseunits\extras -Fuforms"/> + <Item2 ID="787838556410" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-Fi..\baseunits\includes\AnimeA -Fi..\baseunits\includes\AnimeStory -Fi..\baseunits\includes\AnimExtremist -Fi..\baseunits\includes\CentralDeMangas -Fi..\baseunits\includes\EGScans -Fi..\baseunits\includes\EsMangaHere -Fi..\baseunits\includes\Kivmanga -Fi..\baseunits\includes\LectureEnLigne -Fi..\baseunits\includes\MangaAr -Fi..\baseunits\includes\S2scans -Fi..\baseunits\includes\ScanManga -Fi..\baseunits\includes\Starkana -Fi..\baseunits\includes\Turkcraft -Fi..\baseunits\includes\VnSharing -Fi..\baseunits\includes\MeinManga -Fi..\baseunits\includes\MangaREADER_POR -Fi..\baseunits\includes\MangasPROJECT"/> + <Item3 ID="465017374973" Targets="#project" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> + <Item4 ID="729045573668" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> + <Item5 ID="200657967120" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> + <Item6 ID="534084266787" Targets="#project" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -dDEVBUILD -WC"/> + <Item7 ID="951904047630" Targets="#project" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item8 ID="140379931701" Targets="#project" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> + <Item9 ID="403646715137" Targets="BESENPkg,internettools" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-CX -O3 -Xs -XX -g- -Os"/> + <Item10 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item11 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -Os"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From fe48cf5bed6fc1f99104b823c5f6f0a0692bece1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 14:36:32 +0800 Subject: [PATCH 2101/2794] luaclass, fix default array property --- baseunits/lua/LuaClass.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/lua/LuaClass.pas b/baseunits/lua/LuaClass.pas index 36f5151e9..b8d6f2552 100644 --- a/baseunits/lua/LuaClass.pas +++ b/baseunits/lua/LuaClass.pas @@ -113,9 +113,9 @@ function __index(L: Plua_State): Integer; cdecl; lua_getfield(L, -1, '__defaultget'); // default get[] from metatable if lua_iscfunction(L, -1) then begin - lua_pushvalue(L, 1); // userdata + //lua_pushvalue(L, 1); // userdata ; already in closure lua_pushvalue(L, 2); // key - lua_call(L, 2, 1); + lua_call(L, 1, 1); end else if lua_isnil(L, -1) then // no default get @@ -150,10 +150,10 @@ function __newindex(L: Plua_State): Integer; cdecl; lua_getfield(L, -1, '__defaultset'); // default get from metatable if lua_iscfunction(L, -1) then begin - lua_pushvalue(L, 1); // userdata + //lua_pushvalue(L, 1); // userdata ; already in closure lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // data - lua_call(L, 3, 1); + lua_call(L, 2, 1); end else if lua_isnil(L, -1) then // no default get From a1801f13e9c97623a0154487ccf82f6f06ca48e4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 14:59:24 +0800 Subject: [PATCH 2102/2794] luaclass, fix call property method --- baseunits/lua/LuaClass.pas | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/baseunits/lua/LuaClass.pas b/baseunits/lua/LuaClass.pas index b8d6f2552..a825de205 100644 --- a/baseunits/lua/LuaClass.pas +++ b/baseunits/lua/LuaClass.pas @@ -101,10 +101,7 @@ function __index(L: Plua_State): Integer; cdecl; begin lua_getfield(L, -1, '__get'); if lua_iscfunction(L, -1) then - begin - lua_pushvalue(L, 1); // push userdata - lua_call(L, 1, 1); - end; + lua_call(L, 0, 1); end else if lua_isnil(L, -1) then @@ -113,7 +110,6 @@ function __index(L: Plua_State): Integer; cdecl; lua_getfield(L, -1, '__defaultget'); // default get[] from metatable if lua_iscfunction(L, -1) then begin - //lua_pushvalue(L, 1); // userdata ; already in closure lua_pushvalue(L, 2); // key lua_call(L, 1, 1); end @@ -138,9 +134,8 @@ function __newindex(L: Plua_State): Integer; cdecl; lua_getfield(L, -1, '__set'); if lua_iscfunction(L, -1) then begin - lua_pushvalue(L, 1); // userdata lua_pushvalue(L, 3); // data - lua_call(L, 2, 0); + lua_call(L, 1, 0); end; end else @@ -150,7 +145,6 @@ function __newindex(L: Plua_State): Integer; cdecl; lua_getfield(L, -1, '__defaultset'); // default get from metatable if lua_iscfunction(L, -1) then begin - //lua_pushvalue(L, 1); // userdata ; already in closure lua_pushvalue(L, 2); // key lua_pushvalue(L, 3); // data lua_call(L, 2, 1); From 0f61ddc9bd56ec3fc87f3644474bfc21f4a17cd2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 15:24:53 +0800 Subject: [PATCH 2103/2794] replace mangastream module with lua script --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaStream.pas | 191 ------------------------------ lua/modules/MangaStream.lua | 53 +++++++++ 3 files changed, 53 insertions(+), 192 deletions(-) delete mode 100644 baseunits/modules/MangaStream.pas create mode 100644 lua/modules/MangaStream.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 4053b2cac..333bc038b 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -6,7 +6,6 @@ uses Mangacan, PecintaKomik, MangaReader, - MangaStream, MangaLife, MangaHere, MangaTr, diff --git a/baseunits/modules/MangaStream.pas b/baseunits/modules/MangaStream.pas deleted file mode 100644 index 3c28177c0..000000000 --- a/baseunits/modules/MangaStream.pas +++ /dev/null @@ -1,191 +0,0 @@ -unit MangaStream; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, httpsendthread; - -implementation - -uses - simplehtmltreeparser, xquery, RegExpr; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Page := 1; - Result := NO_ERROR; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - Source: TStringList; - Parser: TTreeParser; - v: IXQValue; -begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - Result := NET_PROBLEM; - Source := TStringList.Create; - try - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/manga', 3) then - if Source.Count > 0 then begin - Result := NO_ERROR; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - for v in SelectXPathIX('//table//tr/td[1]//a', Parser) do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end - finally - Parser.Free; - end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - info: TMangaInfo; - Source: TStringList; - Parser: TTreeParser; - v: IXQValue; - s: String; -begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - Result := NET_PROBLEM; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, AURL); - Source := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - with info do begin - //title - title := SelectXPathString('//h1', Parser); - //chapters - for v in SelectXPathIX('//table//td/a', Parser) do begin - s := v.toNode.getAttribute('href'); - if (Length(s) > 2) and (RightStr(s, 2) = '/1') then - SetLength(s, Length(s) - 2); - chapterLinks.Add(EncodeCriticalURLElements(s)); - chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks, chapterName]); - end; - finally - Parser.Free; - end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - Container: TTaskContainer; - Source: TStringList; - Parser: TTreeParser; - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.Task.Container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), FillHost(Module.RootURL, AURL + '/1'), - Container.Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - s := SelectXPathString( - '//div[@class="controls"]/div[2]/ul[@class="dropdown-menu"]/li[last()]/a', - Parser); - if s <> '' then begin - s := ReplaceRegExpr('^.*\((\d+)\).*$', s, '$1', True); - Container.PageNumber := StrToIntDef(s, 0); - end; - finally - Parser.Free; - end; - end; - finally - Source.Free; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - Source: TStringList; - Parser: TTreeParser; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container do begin - Source := TStringList.Create; - try - if GetPage(DownloadThread.FHTTP, TObject(Source), - AppendURLDelim(FillHost(Module.RootURL, AURL)) + - IncStr(DownloadThread.WorkId), Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - PageLinks[DownloadThread.WorkId] := - SelectXPathString('//img[@id="manga-page"]/@src', Parser); - finally - Parser.Free; - end; - end; - finally - Source.Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaStream'; - RootURL := 'https://readms.net'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/MangaStream.lua b/lua/modules/MangaStream.lua new file mode 100644 index 000000000..586cb054b --- /dev/null +++ b/lua/modules/MangaStream.lua @@ -0,0 +1,53 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//h1') + x.xpathhrefall('//table//td/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_error + end +end + +function GetPageNumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + task.pagenumber=tonumber(x.xpathstring('//div[contains(@class,"btn-reader-page")]/ul[@class="dropdown-menu"]/li[last()]/substring-before(substring-after(.,"("),")")')) + return true + else + return false + end +end + +function GetImageURL() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]=x.xpathstring('//img[@id="manga-page"]/@src') + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/manga') then + x=TXQuery.Create(http.Document) + x.xpathhrefall('//table//tr/td[1]//a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.website='MangaStream' + m.rooturl='https://readms.net' + m.lastupdated='February 8, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetimageurl='GetImageURL' + m.ongetnameandlink='GetNameAndLink' +end From 2529b11cccace13408d44d039271e1d768533bb7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 15:33:45 +0800 Subject: [PATCH 2104/2794] luasynautil, add replacestring --- baseunits/lua/LuaSynaUtil.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/baseunits/lua/LuaSynaUtil.pas b/baseunits/lua/LuaSynaUtil.pas index bacf97227..5e6917940 100644 --- a/baseunits/lua/LuaSynaUtil.pas +++ b/baseunits/lua/LuaSynaUtil.pas @@ -32,11 +32,18 @@ function lua_separateright(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_replacestring(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, ReplaceString(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3))); + Result := 1; +end; + procedure luaSynaUtilRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'GetBetween', @lua_getbetween); luaPushFunctionGlobal(L, 'SeparateLeft', @lua_separateleft); luaPushFunctionGlobal(L, 'SeparateRight', @lua_separateright); + luaPushFunctionGlobal(L, 'ReplaceString', @lua_replacestring); end; end. From f5932a1de0cb1cfe89ff71e6e5ced9cb669c7f0b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 15:57:05 +0800 Subject: [PATCH 2105/2794] luaxquery, typo --- baseunits/lua/luaXQuery.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index 71fcc1d88..1eea4b30e 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -160,7 +160,7 @@ function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; (name: 'XPathString'; func: @xquery_xpathstring), (name: 'XpathStringAll'; func: @xquery_xpathstringall), (name: 'XpathHREFAll'; func: @xquery_xpathhrefall), - (name: 'XpathHREFTitle'; func: @xquery_xpathhreftitleall), + (name: 'XpathHREFTitleAll'; func: @xquery_xpathhreftitleall), (name: nil; func: nil) ); From adcb8de2c184d5667b310981eee11a083ad891ec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 16:19:39 +0800 Subject: [PATCH 2106/2794] update firefox user-agent --- baseunits/httpsendthread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index ae6f59c09..858457efa 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -115,14 +115,14 @@ procedure SplitURL(const AURL: String; const AHost, APath: PString; UserAgentCURL = 'curl/7.52.1'; UserAgentGooglebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; UserAgentMSIE = 'Mozilla/5.0 (Windows NT 10.0; Win64; Trident/7.0; rv:11.0) like Gecko'; - UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0'; + UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'; UserAgentChrome = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36'; UserAgentVivaldi = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.90 Safari/537.36 Vivaldi/1.91.867.3'; UserAgentOpera = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 OPR/45.0.2552.888'; UserAgentEdge = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393'; var - DefaultUserAgent: String = UserAgentChrome; + DefaultUserAgent: String = UserAgentFirefox; DefaultRetryCount: Integer = 0; DefaultTimeout: Integer = 15000; DefaultProxyType: String = ''; From cda21ebe752ab4f8a2ef407186e54e7212438801 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 16:42:30 +0800 Subject: [PATCH 2107/2794] luaxquery, fix parsehtml with tstream --- baseunits/lua/luaXQuery.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index 1eea4b30e..28b326ed9 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -44,7 +44,7 @@ function xquery_parsehtml(L: Plua_State): Integer; cdecl; u.ParseHTML(lua_tostring(L, 1)) else if lua_isuserdata(L, 1) then - u.ParseHTML(lua_tostring(L, 1)); + u.ParseHTML(TStream(lua_touserdata(L, 1))); end; function xquery_xpath(L: Plua_State): Integer; cdecl; From dc96691128f8a94361de93e1529ce70b60a61b56 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 16:56:57 +0800 Subject: [PATCH 2108/2794] replace lhtranslation with lua script --- baseunits/ModuleList.inc | 1 - baseunits/modules/LHTranslation.pas | 103 ---------------------------- lua/modules/LHTranslation.lua | 52 ++++++++++++++ 3 files changed, 52 insertions(+), 104 deletions(-) delete mode 100644 baseunits/modules/LHTranslation.pas create mode 100644 lua/modules/LHTranslation.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 333bc038b..ff58fe00d 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -62,7 +62,6 @@ uses MangaTube, WieManga, Mangaf, - LHTranslation, MangaRock, PsychoPlay, Lhscans, diff --git a/baseunits/modules/LHTranslation.pas b/baseunits/modules/LHTranslation.pas deleted file mode 100644 index 3f801af32..000000000 --- a/baseunits/modules/LHTranslation.pas +++ /dev/null @@ -1,103 +0,0 @@ -unit LHTranslation; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - readerUrl = 'http://read.lhtranslation.com'; - -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - if title = '' then title := XPathString('//h1[@class="postsby"]/substring-after(.,":")'); - title := Trim(title); - coverLink := XPathString('(//div[@class="featured-thumbnail"])[1]/img/@src'); - // FIXME: no genres, summary, etc - // some chapters are not available for online reading - for v in XPath('//h2[@class="title"]/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(Trim(ReplaceString(v.toString, title, ''))); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - s := '/read-' + ReplaceString(AURL, '/', '') + '.html'; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(readerUrl, s)) then begin - Result := True; - XPathStringAll('//img[@class="chapter-img"]/@src', Document, PageLinks); - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//select[@id="cat"]/option[@value!="-1"]') do begin - ALinks.Add(Module.RootURL + '/?cat=' + v.toNode.getAttribute('value')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'LHTranslation'; - RootURL := 'http://lhtranslation.com'; - TotalDirectory := 1; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. - diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua new file mode 100644 index 000000000..0fb69b6d6 --- /dev/null +++ b/lua/modules/LHTranslation.lua @@ -0,0 +1,52 @@ +function GetInfo() + mangainfo.url = MaybeFillHost(module.RootURL, url) + if http.GET(mangainfo.url) then + x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//h1[@class="postsby"]/substring-after(.,":")') + end + mangainfo.title = Trim(mangainfo.title) + mangainfo.coverLink = x.XPathString('(//div[@class="featured-thumbnail"])[1]/img/@src') + x.xpathhreftitleall('//h2[@class="title"]/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_error + end +end + +function GetPageNumber() + if http.GET(MaybeFillHost(module.rooturl, url)) then + x=TXQuery.Create(http.document) + if http.get(x.xpathstring('//div[@class="commentmetadata"][1]/p/a/@href')) then + x.parsehtml(http.document) + x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) + return true + end + end + return false +end + +function GetNameAndLink() + if http.GET(module.rooturl) then + x=TXQuery.Create(http.document) + v=x.xpath('//select[@id="cat"]/option[@value!="-1"]') + for i=1,v.count do + v1=v.get(i) + links.add(module.rooturl..'/?cat='..v1.getattribute('value')) + names.add(v1.tostring) + end + return no_error + else + return net_error + end +end + +function Init() + m=NewModule() + m.Website = 'LHTranslation' + m.RootURL = 'http://lhtranslation.com' + m.OnGetNameAndLink = 'GetNameAndLink' + m.OnGetInfo = 'GetInfo' + m.OnGetPageNumber = 'GetPageNumber' +end From 2b1acc64126cc992579f4be910739f60ac53cab4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 8 Feb 2018 07:34:42 +0300 Subject: [PATCH 2109/2794] Add Mangakakalot/Manganelo [EN] fixes #776 --- baseunits/ModuleList.inc | 1 + baseunits/modules/Mangakakalot.pas | 137 +++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/Mangakakalot.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ff58fe00d..63d925260 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -64,6 +64,7 @@ uses Mangaf, MangaRock, PsychoPlay, + Mangakakalot, Lhscans, // Raw Official SundayWebEvery, diff --git a/baseunits/modules/Mangakakalot.pas b/baseunits/modules/Mangakakalot.pas new file mode 100644 index 000000000..a0710b6ee --- /dev/null +++ b/baseunits/modules/Mangakakalot.pas @@ -0,0 +1,137 @@ +unit Mangakakalot; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil; + +implementation + +const + dirurl = '/manga_list?type=newest&category=all&state=all&page='; + +function GetRedirectUrl(Document: TMemoryStream): String; +var s: String; +begin + Result := ''; + s := XPathString('//script[contains(., "window.location.assign")]', Document); + if s <> '' then + Result := GetBetween('("', '")', s); +end; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then begin + Result := NO_ERROR; + s := XPathString('//div[@class="group-page"]/a[contains(., "Last")]/@href', MangaInfo.FHTTP.Document); + Page := StrToInt(RegExprGetMatch('page\=(\d+)', s, 1)); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then begin + Result := NO_ERROR; + XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', + MangaInfo.FHTTP.Document, ALinks, ANames); + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; + const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + s := GetRedirectUrl(Document); + if s <> '' then begin + url := s; + if not GET(url) then Exit; + end; + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="manga-info-pic"]/img/@src')); + if title = '' then title := XPathString('//ul[@class="manga-info-text"]/li/h1'); + if (Pos('email', title) > 0) and (Pos('protected', title) > 0) then + title := Trim(XPathString('//title/substring-after(substring-before(., "Manga Online"), "Read")')); + authors := XPathStringAll('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a'); + genres := XPathStringAll('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a'); + status := MangaInfoStatusIfPos(XPathString('//ul[@class="manga-info-text"]/li[contains(., "Status")]')); + summary := XPathStringAll('//div[@id="noidungm"]/text()', ''); + XPathHREFAll('//div[@class="chapter-list"]/div[@class="row"]/span/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; + const Module: TModuleContainer): Boolean; +var s, url, path, host: String; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do begin + PageLinks.Clear; + PageNumber := 0; + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + s := GetRedirectUrl(Document); + if s <> '' then begin + SplitURL(s, @host, nil); + SplitURL(url, nil, @path); + if not GET(host + path) then Exit; + end; + Result := True; + XPathStringAll('//div[@id="vungdoc"]/img/@src', Document, PageLinks); + end; + end; +end; + +procedure RegisterModule; + + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + begin + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + end; + end; + +begin + AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com'); + AddWebsiteModule('Manganelo', 'http://manganelo.com'); +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index c5771754a..9e039e591 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 9766818b5eb598291fea48f72c29414ad74271fe Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 8 Feb 2018 09:01:09 +0300 Subject: [PATCH 2110/2794] remove batoto --- baseunits/ModuleList.inc | 1 - baseunits/modules/Batoto.pas | 366 ------------------------- config/mangalist.ini | 2 +- mangadownloader/languages/fmd.de.po | 28 -- mangadownloader/languages/fmd.el_GR.po | 28 -- mangadownloader/languages/fmd.en.po | 28 -- mangadownloader/languages/fmd.es.po | 28 -- mangadownloader/languages/fmd.id_ID.po | 28 -- mangadownloader/languages/fmd.pl_PL.po | 23 -- mangadownloader/languages/fmd.po | 23 -- mangadownloader/languages/fmd.pt_BR.po | 28 -- mangadownloader/languages/fmd.ru_RU.po | 28 -- mangadownloader/languages/fmd.tr_TR.po | 28 -- 13 files changed, 1 insertion(+), 638 deletions(-) delete mode 100644 baseunits/modules/Batoto.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 63d925260..bbc9f747f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,7 +1,6 @@ uses WPManga, myMangaReaderCMS, - Batoto, MangaFox, Mangacan, PecintaKomik, diff --git a/baseunits/modules/Batoto.pas b/baseunits/modules/Batoto.pas deleted file mode 100644 index 823ed5d9c..000000000 --- a/baseunits/modules/Batoto.pas +++ /dev/null @@ -1,366 +0,0 @@ -unit Batoto; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, httpsendthread, dateutils, - synautil, MultiLog; - -implementation - -const - modulename = 'Batoto'; - urlroot = 'http://bato.to'; - urllogin = 'https://bato.to/forums/index.php?app=core&module=global§ion=login&do=process'; - dirurls: array [0..1] of String = ( - '/comic/_/sp/', - '/comic/_/comics/'); - perpage = 50; - dirparam = '?sort_col=record_saved&sort_order=desc&per_page='; - -var - locklogin: TRTLCriticalSection; - showalllang: Boolean = False; - showscangroup: Boolean = False; - serverselection: Integer = 0; - -const - serverselectionvalue : array [0..4] of String = ( - 'img', - 'img3', - 'img4', - 'cdn', - 'cdn2' - ); - -resourcestring - RS_ShowAllLang = 'Show all language'; - RS_ShowScanGroup = 'Show scanlation group'; - RS_ServerSelection = 'Image server:'; - RS_ServerSelectionItems = - 'Auto' + LineEnding + - 'Image Server EU' + LineEnding + - 'Image Server NA' + LineEnding + - 'CDN (default)' + LineEnding + - 'CDN2 (testing)'; - -function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - loginform: THTMLForm; - key: String; -begin - Result := False; - if AHTTP = nil then Exit; - if Account.Enabled[modulename] = False then Exit; - if Account.Username[modulename] = '' then Exit; - - if TryEnterCriticalsection(locklogin) > 0 then - with AHTTP do begin - Account.Status[modulename] := asChecking; - Reset; - Cookies.Clear; - Logger.Send('Batoto, login: get login form'); - if GET(urlroot) then begin - loginform := THTMLForm.Create; - query := TXQueryEngineHTML.Create(Document); - try - key := query.XPathString('//input[@name="auth_key"]/@value'); - if key <> '' then begin - with loginform do begin - Put('auth_key', key); - Put('referer', 'https://bato.to/'); - Put('ips_username', Account.Username[modulename]); - Put('ips_password', Account.Password[modulename]); - Put('rememberMe', '1'); - end; - Clear; - Headers.Values['Referer'] := ' https://bato.to/'; - Logger.Send('Batoto, login: send authentification'); - if POST(urllogin, loginform.GetData) then begin - if ResultCode = 200 then begin - Result := Cookies.Values['pass_hash'] <> ''; - if Result then begin - Logger.Send('Batoto, login: success'); - Account.Cookies[modulename] := GetCookies; - Account.Status[modulename] := asValid; - end else begin - Logger.SendError('Batoto, login: failed, wrong user/password?'); - Account.Status[modulename] := asInvalid; - end; - Account.Save; - end - else - Logger.SendError('Batoto, login: failed, unexpected server reply: ' + - IntToStr(ResultCode) + ' ' + ResultString); - end - else - Logger.SendError('Batoto, login: connection failed'); - end; - finally - query.Free; - loginform.Free - end; - end; - if Account.Status[modulename] = asChecking then - Account.Status[modulename] := asUnknown; - LeaveCriticalsection(locklogin); - end - else - begin - EnterCriticalsection(locklogin); - try - if Result then - AHTTP.Cookies.Text := Account.Cookies[modulename]; - finally - LeaveCriticalsection(locklogin); - end; - end; -end; - -function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - AHTTP.Cookies.Text := Account.Cookies['Batoto']; - AHTTP.KeepAlive := False; - Result := AHTTP.GET(AURL); - if (AHTTP.ResultCode > 400) and (AHTTP.ResultCode < 500) then Exit; - if Result then begin - Result := True; - if Account.Enabled[modulename] = False then Exit; - if Account.Username[modulename] = '' then Exit; - if Account.Status[modulename] = asInvalid then Exit; - s := StreamToString(AHTTP.Document); - Result := (Pos('class=''logged_in''', s) > 0) or (Pos('class="logged_in"', s) > 0); - if not Result then begin - Result := Login(AHTTP, Module); - if Result then - Result := AHTTP.GET(AURL) - else - begin - Result := True; - AHTTP.Document.Clear; - WriteStrToStream(AHTTP.Document, s); - end; - end; - end; -end; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[WorkPtr] + - dirparam + IntToStr(perpage)) - then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s := Trim(XPathString('//ul[@class="ipsList_inline left pages"]/li/a')); - if s <> '' then - Page := StrToIntDef(Trim(SeparateRight(LowerCase(s), 'page 1 of ')), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurls[Module.CurrentDirectoryIndex] + dirparam + IntToStr(perpage); - if AURL <> '0' then s += '&st=' + IntToStr(StrToInt(AURL) * perpage); - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//table[@class="ipb_table topic_list hover_rows"]/tbody/tr/td/h4/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v, w: IXQValue; - s, t, l: String; - i: Integer; -begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - Result := NET_PROBLEM; - with MangaInfo.mangaInfo do begin - website := modulename; - url := FillHost(urlroot, AURL); - if GETWithLogin(MangaInfo.FHTTP, url, Module) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - coverLink := XPathString('//div[@class="ipsBox"]//img/@src'); - if title = '' then - title := XPathString('//h1[@class="ipsType_pagetitle"]'); - for v in XPath('//table[@class="ipb_table"]//tr') do begin - s := v.toString; - if Pos('Author:', s) > 0 then authors := GetRightValue('Author:', s) - else if Pos('Artist:', s) > 0 then artists := GetRightValue('Artist:', s) - else if Pos('Description:', s) > 0 then summary := GetRightValue('Description:', s) - else if Pos('Status:', s) > 0 then begin - if Pos('Ongoing', s) > 0 then status := '1' - else status := '0'; - end; - end; - v := XPath('//table[@class="ipb_table"]//tr[starts-with(*, "Genres:")]/td/a'); - if v.Count > 0 then begin - genres := ''; - for i := 1 to v.Count do AddCommaString(genres, v.get(i).toString); - end; - - if showalllang then - s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang")]' - else s := '//table[@class="ipb_table chapters_list"]//tr[starts-with(@class, "row lang_English")]'; - for v in XPath(s) do begin - w := XPath('td[1]/a', v.toNode); - chapterLinks.Add(w.toNode.getAttribute('href')); - t := w.toString; - if showalllang then begin - l := XPath('td[2]/div', v.toNode).toNode.getAttribute('title'); - if l <> '' then t += ' [' + l + ']'; - end; - if showscangroup then begin - l := XPath('td[3]', v.toNode).toString; - if l <> '' then t += ' [' + l + ']'; - end; - chapterName.Add(t); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end else Result := INFORMATION_NOT_FOUND; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - cid, s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - Headers.Values['Referer'] := ' ' + urlroot + '/reader'; - cid := SeparateRight(AURL, '/reader#'); - Cookies.Text := Account.Cookies['Batoto']; - if GET(urlroot + '/areader?id=' + cid + '&p=1') then begin - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageContainerLinks.Text := cid; - if XPathString('//select[@id="page_select"]') <> '' then begin - PageNumber := XPath('(//select[@id="page_select"])[1]/option/@value').Count; - if PageNumber > 0 then begin - s := XPathString('//div[@id="full_image"]//img/@src'); - if s <> '' then PageLinks.Add(s); - end; - end - else begin - // long-strip view - PageLinks.Clear; - for v in XPath('//div/img/@src') do - PageLinks.Add(v.toString); - end; - finally - Free; - end; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - rurl: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if PageContainerLinks.Text = '' then Exit; - rurl := urlroot + '/areader?id=' + PageContainerLinks[0] + '&p=' + - IntToStr(DownloadThread.WorkId + 1); - Headers.Values['Referer'] := ' ' + Module.RootURL + '/reader'; - Cookies.Text := Account.Cookies['Batoto']; - if serverselection <> 0 then - Cookies.Values['server_selection'] := serverselectionvalue[serverselection]; - if GET(rurl) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := XPathString('//div[@id="full_image"]//img/@src'); - finally - Free; - end; - end; - end; -end; - -function BeforeDownloadImage(const DownloadThread: TDownloadThread; - var AURL: String; const Module: TModuleContainer): Boolean; -begin - AURL := FillHost('http://' + serverselectionvalue[serverselection] + '.bato.to', AURL); - Result := True; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := modulename; - RootURL := urlroot; - AccountSupport := True; - SortedList := True; - InformationAvailable := True; - TotalDirectory := Length(dirurls); - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - OnBeforeDownloadImage := @BeforeDownloadImage; - OnLogin := @Login; - AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); - AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); - AddOptionComboBox(@serverselection,'ServerSelection', @RS_ServerSelection, @RS_ServerSelectionItems); - end; -end; - -initialization - InitCriticalSection(locklogin); - RegisterModule; - -finalization - DoneCriticalsection(locklogin); - -end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 9e039e591..b5f0dd2e6 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 25a3f8699..f4e47520d 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -12,34 +12,6 @@ msgstr "" "X-Generator: Poedit 2.0.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Bilder-Server:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Auto\n" -"Bilder-Server EU\n" -"Bilder-Server NA\n" -"CDN (Standard)\n" -"CDN2 (testing)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Zeige alle Sprachen" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Zeige Scanlation Group" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Download Originalbilder (benötigt ExHentai account)" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index cf310eaf1..c9abd6a34 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -16,34 +16,6 @@ msgstr "" "X-Poedit-Language: Greek\n" "X-Poedit-Country: GREECE\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Διακομιστής εικόνων:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Αυτόματα\n" -"Διακομιστής εικόνων EU\n" -"Διακομιστής εικόνων NA\n" -"CDN (προεπιλογή)\n" -"CDN2 (δοκιμαστικά)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Εμφάνιση όλων των γλωσσών" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Εμφάνιση ομάδας scanlation" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Λήψη αρχικής εικόνας (απαιτείται λογαριασμός ExHentai)" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 9a5df2977..698353153 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1,34 +1,6 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Image server:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Show all language" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Show scanlation group" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Download original image(require ExHentai account)" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 5f3bfcd0c..f7c818fdc 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -12,34 +12,6 @@ msgstr "" "Last-Translator: Mariolr\n" "Language: es_419\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Auto\n" -"Imagen de Servidor EU\n" -"Imagen de Servidor NA\n" -"CDN (Por Defecto)\n" -"CDN2 (Pruebando)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Mostrar todos los idiomas" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Mostrar Grupo de Scanlation" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Descargar imagen original (require una cuenta ExHentai)" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 808be25f5..3e703a7a2 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -12,34 +12,6 @@ msgstr "" "X-Generator: Poedit 2.0.1\n" "Plural-Forms: nplurals=1; plural=0;\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Server gambar:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Otomatis\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Tampilkan semua bahasa" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Tampilkan nama grup scan" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Unduh gambar asli(membutuhkan akun ExHentai)" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 3ef4d30ba..e01a237be 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -12,29 +12,6 @@ msgstr "" "X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Pokaż wszystkie języki" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Pokaż grupę skanlacja" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Pobierz oryginalny obraz (wymaga konta ExHentai)" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 3a4dab5b6..fcc5fe2c4 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1,29 +1,6 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 69b329237..059aa49dd 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -12,34 +12,6 @@ msgstr "" "X-Generator: Poedit 2.0.1\n" "Plural-Forms: \n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Servidor da imagem:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Auto\n" -"Servidor da Imagem EU\n" -"Servidor da Imagem NA\n" -"CDN (padrão)\n" -"CDN2 (testando)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Exibir todos os idiomas" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Exibir grupo de scans" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Baixar imagem original (exige uma conta ExHentai)" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index e377ebe0b..5c7171bca 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -11,34 +11,6 @@ msgstr "" "Language: ru_RU\n" "X-Generator: Poedit 2.0.2\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Сервер изображения:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Авто\n" -"Сервер изображения EU\n" -"Сервер изображения NA\n" -"CDN (по умолч.)\n" -"CDN2 (тестовый)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Показать все языки" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Показать группу сканирования" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Загрузить оригинальное изображение(треб. аккаунт ExHentai)" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 32d78663c..0842b7972 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -13,34 +13,6 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: batoto.rs_serverselection -msgid "Image server:" -msgstr "Resim sunucusu:" - -#: batoto.rs_serverselectionitems -msgid "" -"Auto\n" -"Image Server EU\n" -"Image Server NA\n" -"CDN (default)\n" -"CDN2 (testing)\n" -msgstr "" -"Otomatik\n" -"Resim Sunucusu AB\n" -"Resim Sunucusu KA\n" -"CDN (varsayılan)\n" -"CDN2 (test)\n" - -#: batoto.rs_showalllang -msgctxt "batoto.rs_showalllang" -msgid "Show all language" -msgstr "Tüm dilleri göster" - -#: batoto.rs_showscangroup -msgctxt "batoto.rs_showscangroup" -msgid "Show scanlation group" -msgstr "Scanlation grubunu göster" - #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Orijinal resmi indir(ExHentai hesabı gerektirir)" From 284cba9f2d00d6e99df0eb0d1b65d919e457c701 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 8 Feb 2018 09:04:25 +0300 Subject: [PATCH 2111/2794] Add MangaWindow, new Batoto [EN] fixes #899 --- baseunits/ModuleList.inc | 1 + baseunits/modules/MangaWindow.pas | 162 ++++++++++++++++++++++++++++++ config/mangalist.ini | 2 +- 3 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 baseunits/modules/MangaWindow.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index bbc9f747f..75fc7825a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -65,6 +65,7 @@ uses PsychoPlay, Mangakakalot, Lhscans, + MangaWindow, // Raw Official SundayWebEvery, TonarinoYoungJump, diff --git a/baseunits/modules/MangaWindow.pas b/baseunits/modules/MangaWindow.pas new file mode 100644 index 000000000..695844312 --- /dev/null +++ b/baseunits/modules/MangaWindow.pas @@ -0,0 +1,162 @@ +unit MangaWindow; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, httpsendthread, synautil, RegExpr; + +implementation + +const + dirurl = '/browse?sort=create&page='; + +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +var + s: String; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then begin + Result := NO_ERROR; + s := XPathString('(//ul[contains(@class, "pagination")])[1]/li[last()-1]', MangaInfo.FHTTP.Document); + Page := StrToIntDef(s, 1); + end; +end; + +function GetNameAndLink(const MangaInfo: TMangaInformation; + const ANames, ALinks: TStringList; const AURL: String; + const Module: TModuleContainer): Integer; +var + v: IXQValue; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@id="series-list"]/div/div') do begin + ALinks.Add(XPathString('a/@href', v)); + s := XPathString('span[contains(@class, "flag")]/@class', v); + if s <> '' then begin + s := RegExprGetMatch('flag_(\w+)\b', s, 1); + if s <> 'united_kingdom' then s := ' [' + UpperCase(s) + ']' + else s := ' [EN]'; + end; + s := XPathString('a', v) + s; + ANames.Add(s); + end; + finally + Free; + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + s: String; + v, obj: IXQValue; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.Task.Container, DownloadThread.FHTTP do + begin + PageLinks.Clear; + PageNumber := 0; + s := MaybeFillHost(Module.RootURL, AURL); + if GET(s) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + s := XPathString('//script[matches(., "var\s+images")]'); + s := RegExprGetMatch('var\s+images\s+\=\s+\{(.+?)\}', s, 1); + s := '{' + s + '}'; + ParseHTML(s); + obj := XPath('json(*)'); + for v in XPath('json(*)()') do + PageLinks.Add(obj.getProperty(v.toString).toString); + finally + Free; + end; + end; + end; +end; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + a: TStringArray; + i: Integer; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := MaybeFillHost(Module.RootURL, AURL); + if GET(url) then begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[contains(@class, "attr-cover")]/img/@src')); + if title = '' then begin + title := XPathString('//h3[@class="item-title"]'); + s := XPathString('//h3[@class="item-title"]/parent::*/span[contains(@class, "flag")]/@class'); + if s <> '' then begin + s := RegExprGetMatch('flag_(\w+)\b', s, 1); + if s <> 'united_kingdom' then s := ' [' + UpperCase(s) + ']' + else s := ' [EN]'; + title += s; + end; + end; + authors := XPathStringAll('//div[@class="attr-item" and contains(b, "Authors")]/span'); + genres := XPathStringAll('//div[@class="attr-item" and contains(b, "Genres")]/span'); + a := genres.Split('/'); + for i := Low(a) to High(a) do a[i] := Trim(a[i]); + genres := ''.Join(', ', a); + status := MangaInfoStatusIfPos(XPathString('//div[@class="attr-item" and contains(b, "Status")]/span')); + summary := XPathStringAll('//p[@class="summary-set"]/text()', ''); + XPathHREFAll('//div[contains(@class, "chapter-list")]/div[@class="main"]/div/a', chapterLinks, chapterName); + InvertStrings([chapterLinks, chapterName]); + finally + Free; + end; + end; + end; +end; + +procedure RegisterModule; + + function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + begin + Result := AddModule; + with Result do + begin + Website := AWebsite; + RootURL := ARootURL; + SortedList := True; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; + end; + end; + +begin + AddWebsiteModule('MangaWindow', 'https://mangawindow.net'); + AddWebsiteModule('Batoto', 'https://bato.to'); +end; + +initialization + RegisterModule; + +end. + diff --git a/config/mangalist.ini b/config/mangalist.ini index b5f0dd2e6..9c0d51c72 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From ea87ed89c0c733769580bf555bd45cd4073da6ba Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 19:05:45 +0800 Subject: [PATCH 2112/2794] rename luaregex to luaregexpr --- baseunits/lua/LuaBase.pas | 2 +- baseunits/lua/{LuaRegex.pas => LuaRegExpr.pas} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename baseunits/lua/{LuaRegex.pas => LuaRegExpr.pas} (97%) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 42dd420f4..754e426e0 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -22,7 +22,7 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh implementation uses - LuaClass, luaStrings, LuaBaseUnit, LuaRegex, LuaSynaUtil, LuaSynaCode, MultiLog; + LuaClass, luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog; function luabase_print(L: Plua_State): Integer; cdecl; var diff --git a/baseunits/lua/LuaRegex.pas b/baseunits/lua/LuaRegExpr.pas similarity index 97% rename from baseunits/lua/LuaRegex.pas rename to baseunits/lua/LuaRegExpr.pas index fbf2e9c62..a818b63b5 100644 --- a/baseunits/lua/LuaRegex.pas +++ b/baseunits/lua/LuaRegExpr.pas @@ -1,4 +1,4 @@ -unit LuaRegex; +unit LuaRegExpr; {$mode objfpc}{$H+} From 42a093dfb5e25d8860a1dcf2779982571481650a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 19:07:11 +0800 Subject: [PATCH 2113/2794] luabaseunit, register regexprgetmatch --- baseunits/lua/LuaBaseUnit.pas | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 22faee366..259c006a6 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -78,15 +78,9 @@ function lua_removeurldelimleft(L: Plua_State): Integer; cdecl; Result := 1; end; -function lua_encodebase64(L: Plua_State): Integer; cdecl; +function lua_regexprgetmatch(L: Plua_State): Integer; cdecl; begin - lua_pushstring(L, Base64Decode(lua_tostring(L, 1))); - Result := 1; -end; - -function lua_decodebase64(L: Plua_State): Integer; cdecl; -begin - lua_pushstring(L, Base64Encode(lua_tostring(L, 1))); + lua_pushstring(L, RegExprGetMatch(lua_tostring(L, 1), lua_tostring(L, 2), lua_tointeger(L, 3))); Result := 1; end; @@ -101,6 +95,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'AppendURLDelimleft', @lua_appendurldelimleft); luaPushFunctionGlobal(L, 'RemoveURLDelim', @lua_removeurldelim); luaPushFunctionGlobal(L, 'RemoveURLDelimLeft', @lua_removeurldelimleft); + luaPushFunctionGlobal(L, 'RegExprGetMatch', @lua_regexprgetmatch); end; end. From d6327033cb045c23b751a31557a2ed50bcbd395c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 19:08:25 +0800 Subject: [PATCH 2114/2794] luaregexpr, typo --- baseunits/lua/LuaBase.pas | 2 +- baseunits/lua/LuaRegExpr.pas | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 754e426e0..6d89d545f 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -37,8 +37,8 @@ procedure LuaBaseRegister(L: Plua_State); begin lua_register(L, 'print', @luabase_print); - luaRegexRegister(L); luaBaseUnitRegister(L); + luaRegExprRegister(L); luaSynaUtilRegister(L); luaSynaCodeRegister(L); diff --git a/baseunits/lua/LuaRegExpr.pas b/baseunits/lua/LuaRegExpr.pas index a818b63b5..ec3910ff8 100644 --- a/baseunits/lua/LuaRegExpr.pas +++ b/baseunits/lua/LuaRegExpr.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, lua53, RegExpr; -procedure luaRegexRegister(L: Plua_State); +procedure luaRegExprRegister(L: Plua_State); implementation @@ -26,7 +26,7 @@ function re_replace(L: Plua_State): Integer; cdecl; Result := 1; end; -procedure luaRegexRegister(L: Plua_State); +procedure luaRegExprRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'ExecRegExpr', @re_exec); luaPushFunctionGlobal(L, 'ReplaceRegExpr', @re_replace); From 4b8cf5b8d3c09e416f9b1d1dcf22136ad2cfa41e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 21:30:54 +0800 Subject: [PATCH 2115/2794] Bump version 0.9.134.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index e324d9e21..5b46529be 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.134.0 (08-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.133.0...0.9.134.0 + 0.9.133.0 (07-02-2018) [+] Added left download toolbar to move selected download(s). Options > View [*] View manga info preserve saveto location from download or favorite diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index faa5366ca..671390731 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="133"/> + <RevisionNr Value="134"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 1566ee663..01cd6e2b2 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.133.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.133.0/fmd_0.9.133.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.133.0/fmd_0.9.133.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.133.0/fmd_0.9.133.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.133.0/fmd_0.9.133.0_Win64.7z +VERSION=0.9.134.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.134.0/fmd_0.9.134.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.134.0/fmd_0.9.134.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.134.0/fmd_0.9.134.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.134.0/fmd_0.9.134.0_Win64.7z From 89c8237cc58c5b3b110c299551882dd366b9dbb6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:34:17 +0300 Subject: [PATCH 2116/2794] remove AnimeA --- baseunits/FMDOptions.pas | 2 +- .../includes/AnimeA/chapter_page_number.inc | 37 ------ .../includes/AnimeA/directory_page_number.inc | 37 ------ baseunits/includes/AnimeA/image_url.inc | 31 ----- .../includes/AnimeA/manga_information.inc | 110 ------------------ baseunits/includes/AnimeA/names_and_links.inc | 23 ---- baseunits/uBaseUnit.pas | 6 +- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 10 -- config/mangalist.ini | 4 +- 10 files changed, 4 insertions(+), 271 deletions(-) delete mode 100644 baseunits/includes/AnimeA/chapter_page_number.inc delete mode 100644 baseunits/includes/AnimeA/directory_page_number.inc delete mode 100644 baseunits/includes/AnimeA/image_url.inc delete mode 100644 baseunits/includes/AnimeA/manga_information.inc delete mode 100644 baseunits/includes/AnimeA/names_and_links.inc diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 7ae1f7f83..d9f400183 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -34,7 +34,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) EXPARAM_CHAPTER = '%CHAPTER%'; DEFAULT_EXPARAM = '"' + EXPARAM_PATH + EXPARAM_CHAPTER + '"'; - DEFAULT_LIST = 'AnimeA,MangaFox,MangaHere,MangaInn,MangaReader'; + DEFAULT_LIST = 'MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; DEFAULT_FILENAME_CUSTOMRENAME = '%FILENAME%'; diff --git a/baseunits/includes/AnimeA/chapter_page_number.inc b/baseunits/includes/AnimeA/chapter_page_number.inc deleted file mode 100644 index 775f37a1d..000000000 --- a/baseunits/includes/AnimeA/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetAnimeAPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - isPage: Boolean = False; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - Result := GetPage(TObject(l), FillMangaSiteHost(ANIMEA_ID, - StringReplace(URL, '.html', '', [])) + - '.html', Task.Container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and - (Pos('class="mangaselecter pageselect"', parse[i]) > 0) then - isPage := True; - if isPage and (Pos('</select', parse[i]) > 0) then - begin - isPage := False; - Break; - end; - if isPage and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/AnimeA/directory_page_number.inc b/baseunits/includes/AnimeA/directory_page_number.inc deleted file mode 100644 index bc5f8e299..000000000 --- a/baseunits/includes/AnimeA/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetAnimeADirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + ANIMEA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'a') and - (GetVal(parse[i], 'href') = - 'http://manga.animea.net/browse.html?page=1') and - (Pos('Next', parse[i + 1]) > 0) then - begin - APage := StrToInt(TrimRight(TrimLeft(parse[i - 4]))); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/AnimeA/image_url.inc b/baseunits/includes/AnimeA/image_url.inc deleted file mode 100644 index 333c9bc5a..000000000 --- a/baseunits/includes/AnimeA/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetAnimeAImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(ANIMEA_ID, - StringReplace(URL, '.html', '', []) + - '-page-' + IntToStr(WorkId + 1) + '.html'), - Task.Container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', parse[i]) > 0) and - (Pos('class="scanmr"', parse[i]) > 0) and - (Pos('id="scanmr"', parse[i])> 0) then - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/AnimeA/manga_information.inc b/baseunits/includes/AnimeA/manga_information.inc deleted file mode 100644 index 9930a9d16..000000000 --- a/baseunits/includes/AnimeA/manga_information.inc +++ /dev/null @@ -1,110 +0,0 @@ - function GetAnimeAInfoFromURL: Byte; - var - i, j: Cardinal; - isExtractGenres: Boolean = False; - s: String; - begin - mangaInfo.website := WebsiteRoots[ANIMEA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ANIMEA_ID, AURL + ANIMEA_SKIP); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i + 1], 'Manga - Read ', ' Manga Scans'); - - // get cover link - if Pos('class="cover_mp"', parse[i]) > 0 then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - // get authors - if (Pos('Author(s):', parse[i]) <> 0) then - mangaInfo.authors := TrimRight(TrimLeft(parse[i + 3])); - - // get artists - if (Pos('Artist(s):', parse[i]) <> 0) then - mangaInfo.artists := TrimRight(TrimLeft(parse[i + 2])); - - // get genres - if (Pos('Genre(s):', parse[i]) <> 0) then - begin - mangaInfo.genres := ''; - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if GetTagName(parse[i]) <> 'a' then - for j := 0 to 37 do - if Pos(LowerCase(defaultGenres[j]), LowerCase(parse[i])) <> 0 then - mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); - if Pos('</li>', parse[i]) > 0 then - isExtractGenres := False; - end; - - // get summary - if Pos('Upload a chapter', parse[i]) > 0 then - begin - j := i + 8; - mangaInfo.summary := ''; - while (j < parse.Count - 4) and (Pos('</p>', parse[j]) = 0) do - begin - mangaInfo.summary := StringFilter(mangaInfo.summary + parse[j]); - Inc(j); - end; - mangaInfo.summary := StringFilter(mangaInfo.summary); - end; - - // get status - if (Pos('Status:', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - // get chapter name and links - if (Pos('<a', parse[i]) > 0) and (Pos('id="ch_', parse[i]) > 0) and - (i + 3 < parse.Count - 1) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - s := ''; - if (parse[i + 3] <> '') and (Pos('<', parse[i + 3]) = 0) then - begin - s := Trim(TrimLeftChar(parse[i + 3], [':'])); - end; - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]) + ' ' + s))); - mangaInfo.chapterName.Add(s); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/AnimeA/names_and_links.inc b/baseunits/includes/AnimeA/names_and_links.inc deleted file mode 100644 index 7c8a33d5e..000000000 --- a/baseunits/includes/AnimeA/names_and_links.inc +++ /dev/null @@ -1,23 +0,0 @@ - function AnimeAGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMEA_ID, 1] + - ANIMEA_BROWSER + AURL, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - for i := 0 to Source.Count - 1 do - begin - if Pos('manga_img', Source[i]) <> 0 then - begin - Result := NO_ERROR; - ALinks.Add(GetString(Source[i], '"', '"')); - ANames.Add(GetString(Source[i], 'title="', ' Manga"')); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 865c6e0af..ba4035044 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -229,7 +229,6 @@ interface // common regex to split host/url REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - ANIMEA_ID = 0; OURMANGA_ID = 1; VNSHARING_ID = 2; TRUYEN18_ID = 3; @@ -266,7 +265,7 @@ interface DYNASTYSCANS_ID = 34; WebsiteRoots: array [0..34] of array [0..1] of String = ( - ('AnimeA', 'http://manga.animea.net'), + ('', ''), ('OurManga', 'http://www.ourmanga.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Truyen18', 'http://www.truyen18.org'), @@ -306,9 +305,6 @@ interface ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - ANIMEA_BROWSER = '/browse.html?page='; - ANIMEA_SKIP = '?skip=1'; - VNSHARING_BROWSER = '/DanhSach'; TRUYEN18_ROOT = 'http://www.truyen18.org'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 8a1fca584..cbb960251 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -784,8 +784,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: Parser: THTMLParser; MangaSiteID: Integer; - {$I includes/AnimeA/directory_page_number.inc} - {$I includes/VnSharing/directory_page_number.inc} {$I includes/S2Scans/directory_page_number.inc} @@ -837,9 +835,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: begin MangaSiteID := GetMangaSiteID(AWebsite); Source := TStringList.Create; - if MangaSiteID = ANIMEA_ID then - Result := GetAnimeADirectoryPageNumber - else if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else @@ -898,8 +893,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; Parser: THTMLParser; MangaSiteID: Integer; - {$I includes/AnimeA/names_and_links.inc} - {$I includes/EsMangaHere/names_and_links.inc} {$I includes/AnimExtremist/names_and_links.inc} @@ -974,9 +967,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; begin MangaSiteID := GetMangaSiteID(AWebsite); Source := TStringList.Create; - if MangaSiteID = ANIMEA_ID then - Result := AnimeAGetNamesAndLinks - else if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else @@ -1091,8 +1081,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR MangaSiteID: Integer; bmangaInfo: TBaseMangaInfo; - {$I includes/AnimeA/manga_information.inc} - // due to its weird designs, this will take a lot of work (and time) for it to // work property @@ -1184,9 +1172,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR Exit(INFORMATION_NOT_FOUND); mangaInfo.url := FillMangaSiteHost(MangaSiteID, AURL); Source := TStringList.Create; - if MangaSiteID = ANIMEA_ID then - Result := GetAnimeAInfoFromURL - else if MangaSiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 5af5e1470..8fc6fd590 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -428,8 +428,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Turkcraft/chapter_page_number.inc} - {$I includes/AnimeA/chapter_page_number.inc} - {$I includes/LectureEnLigne/chapter_page_number.inc} {$I includes/JapanShin/chapter_page_number.inc} @@ -468,9 +466,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := Modules.GetPageNumber(Self, URL, Task.Container.ModuleId) else begin - if Task.Container.MangaSiteID = ANIMEA_ID then - Result := GetAnimeAPageNumber - else if Task.Container.MangaSiteID = STARKANA_ID then Result := GetStarkanaPageNumber else @@ -574,8 +569,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/VnSharing/image_url.inc} - {$I includes/AnimeA/image_url.inc} - {$I includes/LectureEnLigne/image_url.inc} {$I includes/JapanShin/image_url.inc} @@ -607,9 +600,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; Result := Modules.GetImageURL(Self, URL, Task.Container.ModuleId) else begin - if Task.Container.MangaSiteID = ANIMEA_ID then - Result := GetAnimeAImageURL - else if Task.Container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 9c0d51c72..43c2802f9 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -1,10 +1,10 @@ [general] -DefaultSelect=AnimeA,MangaFox,MangaHere,MangaInn,MangaReader +DefaultSelect=MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf -English=AnimeA,Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga From 9bfc0751c1158a42f2d6be8770ebac3fb07db845 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:37:17 +0300 Subject: [PATCH 2117/2794] remove Centrum-Mangi_PL --- .../CentrumMangi_PL/chapter_page_number.inc | 37 ----- .../includes/CentrumMangi_PL/image_url.inc | 34 ----- .../CentrumMangi_PL/manga_information.inc | 127 ------------------ .../CentrumMangi_PL/names_and_links.inc | 52 ------- baseunits/uBaseUnit.pas | 5 +- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 10 -- 7 files changed, 1 insertion(+), 274 deletions(-) delete mode 100644 baseunits/includes/CentrumMangi_PL/chapter_page_number.inc delete mode 100644 baseunits/includes/CentrumMangi_PL/image_url.inc delete mode 100644 baseunits/includes/CentrumMangi_PL/manga_information.inc delete mode 100644 baseunits/includes/CentrumMangi_PL/names_and_links.inc diff --git a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc b/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc deleted file mode 100644 index 7deb8fc25..000000000 --- a/baseunits/includes/CentrumMangi_PL/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetCentrumMangi_PLPageNumber: Boolean; - var - s: String; - Count: Cardinal = 0; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(CENTRUMMANGI_PL_ID, URL)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('</select>', parse[i]) > 0) then - if Count > 0 then - begin - s := parse[i - 2]; - Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end - else - Inc(Count); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/CentrumMangi_PL/image_url.inc b/baseunits/includes/CentrumMangi_PL/image_url.inc deleted file mode 100644 index 4b2ff1cca..000000000 --- a/baseunits/includes/CentrumMangi_PL/image_url.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetCentrumMangi_PLImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(CENTRUMMANGI_PL_ID, '/' + - StringReplace(URL, '-1.html', '.html', [])); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - if (Pos('<img alt=', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'src'); - s := StringReplace(s, 'https://', 'http://', [rfReplaceAll]); - s := StringReplace(s, 'mangas/', WebsiteRoots[CENTRUMMANGI_PL_ID, 1] + - '/mangas/', [rfReplaceAll]); - Task.Container.PageLinks.Add(EncodeURL(s)); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/CentrumMangi_PL/manga_information.inc b/baseunits/includes/CentrumMangi_PL/manga_information.inc deleted file mode 100644 index d92097669..000000000 --- a/baseunits/includes/CentrumMangi_PL/manga_information.inc +++ /dev/null @@ -1,127 +0,0 @@ - function GetCentrumMangi_PLInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[CENTRUMMANGI_PL_ID, 0]; - mangaInfo.url := FillMangaSiteHost(CENTRUMMANGI_PL_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - //get infos - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - //get cover - if Pos('class="image"', parse[i]) > 0 then - if Pos('<img ', parse[i + 2]) > 0 then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - //get title - if Pos('Informacje ::', parse[i]) > 0 then - if Pos('<h2', parse[i - 1]) > 0 then - mangaInfo.title := - Trim(HTMLEntitiesFilter(StringFilter( - Trim(ReplaceRegExpr('Informacje\s\:\:\s', parse[i], '', False))))); - - //get author - if Pos('Autor:', parse[i]) > 0 then - if Pos('</strong', parse[i + 1]) > 0 then - mangaInfo.authors := - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2])))); - - //get summary - if Pos('Recenzja', parse[i]) > 0 then - if Pos('</h3', parse[i + 1]) > 0 then - mangaInfo.summary := - Trim(BreaksString(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 4]))))); - - //get status - if Pos('Status:', parse[i]) > 0 then - if Pos('</strong', parse[i + 1]) > 0 then - if Pos('Zlicencjonowana', parse[i + 4]) > 0 then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - - //get genres - if Pos('Gatunki:', parse[i]) > 0 then - if Pos('</strong', parse[i + 1]) > 0 then - isExtractGenres := True; - if isExtractGenres and - (Pos('</div', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres then - begin - if Pos('<a ', parse[i]) > 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))) - else - mangaInfo.genres := - Trim(mangaInfo.genres + ', ' + - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - - //get chapters - if Pos('class="chapter"', parse[i]) > 0 then - isExtractChapter := True; - if Pos('</tbody', parse[i]) > 0 then - isExtractChapter := False; - if isExtractChapter then - begin - if Pos('class="c"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i + 1], 'href'), - WebsiteRoots[CENTRUMMANGI_PL_ID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2])))); - mangaInfo.chapterName.Add(s); - end; - if (Pos('class="t"', parse[i]) > 0) and - (mangaInfo.chapterName.Count > 0) then - begin - s := mangaInfo.chapterName[mangaInfo.chapterName.Count - 1] + ' '; - mangaInfo.chapterName[mangaInfo.chapterName.Count - 1] := - Trim(s + (Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))))); - end; - end; - end; - end; - - // invert chapters - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/CentrumMangi_PL/names_and_links.inc b/baseunits/includes/CentrumMangi_PL/names_and_links.inc deleted file mode 100644 index ca7ed7971..000000000 --- a/baseunits/includes/CentrumMangi_PL/names_and_links.inc +++ /dev/null @@ -1,52 +0,0 @@ - function CentrumMangi_PLGetNamesAndLinks: Byte; - var - i: Cardinal; - //isExtractItem :boolean = True; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[CENTRUMMANGI_PL_ID, 1] + - CENTRUMMANGI_PL_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - //if (Pos('<div ', parse[i]) > 0) and - // (Pos('class="box-max"', parse[i]) > 0) then - // isExtractItem := True; - //if isExtractItem and - // (Pos('</table', parse[i]) > 0) then - // isExtractItem := False; - - if (Pos('<td style="width:45%;text-align: left;">', parse[i]) > 0) then - begin - Result := NO_ERROR; - ALinks.Add(StringReplace(GetVal(parse[i + 1], 'href'), - WebsiteRoots[CENTRUMMANGI_PL_ID, 1], '', [rfIgnoreCase])); - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 2])))); - end; - - //if isExtractItem then - //begin - // if (Pos('<a ', parse[i]) > 0) and - // (Pos('/spis/', parse[i]) = 0) then - // begin - // Result := NO_ERROR; - // ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[CENTRUMMANGI_PL_ID, 1], '', [rfIgnoreCase])); - // ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); - // end; - //end; - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index ba4035044..1c474cd23 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -250,7 +250,6 @@ interface MANGASPROJECT_ID = 19; MANGAREADER_POR_ID = 20; JAPANSHIN_ID = 21; - CENTRUMMANGI_PL_ID = 22; MANGALIB_PL_ID = 23; ONEMANGA_ID = 24; MANGATOWN_ID = 25; @@ -287,7 +286,7 @@ interface ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), ('Japan-Shin', 'http://www.japan-shin.com'), - ('Centrum-Mangi_PL', 'http://centrum-mangi.pl'), + ('', ''), ('Manga-Lib_PL', 'http://www.manga-lib.pl/index.php'), ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), @@ -344,8 +343,6 @@ interface JAPANSHIN_BROWSER = '/lectureenligne/reader/list/'; - CENTRUMMANGI_PL_BROWSER = '/spis/'; - MANGALIB_PL_BROWSER = '/manga/directory'; ONEMANGA_BROWSER = '/manga-list/all/any/last-added/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index cbb960251..0fbbfa115 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -929,8 +929,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/JapanShin/names_and_links.inc} - {$I includes/CentrumMangi_PL/names_and_links.inc} - {$I includes/MangaLib_PL/names_and_links.inc} {$I includes/OneManga/names_and_links.inc} @@ -1021,9 +1019,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = JAPANSHIN_ID then Result := JapanShinGetNamesAndLinks else - if MangaSiteID = CENTRUMMANGI_PL_ID then - Result := CentrumMangi_PLGetNamesAndLinks - else if MangaSiteID = MANGALIB_PL_ID then Result := MangaLib_PLGetNamesAndLinks else @@ -1118,8 +1113,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/JapanShin/manga_information.inc} - {$I includes/CentrumMangi_PL/manga_information.inc} - {$I includes/MangaLib_PL/manga_information.inc} {$I includes/OneManga/manga_information.inc} @@ -1223,9 +1216,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinInfoFromURL else - if MangaSiteID = CENTRUMMANGI_PL_ID then - Result := GetCentrumMangi_PLInfoFromURL - else if MangaSiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 8fc6fd590..888135013 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -432,8 +432,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/JapanShin/chapter_page_number.inc} - {$I includes/CentrumMangi_PL/chapter_page_number.inc} - {$I includes/MangaLib_PL/chapter_page_number.inc} {$I includes/OneManga/chapter_page_number.inc} @@ -496,9 +494,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinPageNumber else - if Task.Container.MangaSiteID = CENTRUMMANGI_PL_ID then - Result := GetCentrumMangi_PLPageNumber - else if Task.Container.MangaSiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLPageNumber else @@ -573,8 +568,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/JapanShin/image_url.inc} - {$I includes/CentrumMangi_PL/image_url.inc} - {$I includes/MangaLib_PL/image_url.inc} {$I includes/OneManga/image_url.inc} @@ -645,9 +638,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinImageURL else - if Task.Container.MangaSiteID = CENTRUMMANGI_PL_ID then - Result := GetCentrumMangi_PLImageURL - else if Task.Container.MangaSiteID = MANGALIB_PL_ID then Result := GetMangaLib_PLImageURL else From ff5fa37725db5d49f3bdb84dc56500e0dd5d5ed8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:40:56 +0300 Subject: [PATCH 2118/2794] remove DM5 --- .../includes/DM5/directory_page_number.inc | 34 ------------------- baseunits/uBaseUnit.pas | 5 +-- baseunits/uData.pas | 5 --- 3 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 baseunits/includes/DM5/directory_page_number.inc diff --git a/baseunits/includes/DM5/directory_page_number.inc b/baseunits/includes/DM5/directory_page_number.inc deleted file mode 100644 index ab21ca8c0..000000000 --- a/baseunits/includes/DM5/directory_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetDM5DirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; // - if not GetPage(TObject(Source), WebsiteRoots[DM5_ID, 1] + DM5_BROWSER + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('/mangas/list/*/', parse[i]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse[i], '/mangas/list/*/', '">'))); - APage := StrToInt(s); - Result := NO_ERROR; - Exit; - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1c474cd23..43c7249c7 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -244,7 +244,6 @@ interface ANIMESTORY_ID = 13; LECTUREENLIGNE_ID = 14; SCANMANGA_ID = 15; - DM5_ID = 16; KIVMANGA_ID = 17; MEINMANGA_ID = 18; MANGASPROJECT_ID = 19; @@ -280,7 +279,7 @@ interface ('AnimeStory', 'http://www.anime-story.com'), ('Lecture-En-Ligne', 'http://www.lecture-en-ligne.com'), ('ScanManga', 'http://www.scan-manga.com'), - ('DM5', 'http://www.dm5.com'), + ('', ''), ('KivManga', 'http://www.kivmanga.com'), ('MeinManga', 'http://www.meinmanga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), @@ -331,8 +330,6 @@ interface SCANMANGA_BROWSER = '/scanlation/liste_des_mangas.html'; - DM5_BROWSER = '/manhua-new'; - KIVMANGA_BROWSER = '/'; MEINMANGA_BROWSER = '/directory/all/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 0fbbfa115..d3d3ad0a9 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -792,8 +792,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/CentralDeMangas/directory_page_number.inc} - {$I includes/DM5/directory_page_number.inc} - {$I includes/JapanShin/directory_page_number.inc} {$I includes/OneManga/directory_page_number.inc} @@ -847,9 +845,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasDirectoryPageNumber else - if MangaSiteID = DM5_ID then - Result := GetDM5DirectoryPageNumber - else if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinDirectoryPageNumber else From 341f243d526d6b0554fb3dcd1fb6c6dd5ebc5c5a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:54:29 +0300 Subject: [PATCH 2119/2794] remove Imanhua --- .../includes/Imanhua/names_and_links.inc | 37 ------------------- baseunits/uBaseUnit.pas | 5 +-- baseunits/uData.pas | 5 --- 3 files changed, 1 insertion(+), 46 deletions(-) delete mode 100644 baseunits/includes/Imanhua/names_and_links.inc diff --git a/baseunits/includes/Imanhua/names_and_links.inc b/baseunits/includes/Imanhua/names_and_links.inc deleted file mode 100644 index b371af83c..000000000 --- a/baseunits/includes/Imanhua/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function imanhuaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; // - if not GetPage(TObject(Source), WebsiteRoots[IMANHUA_ID, 1] + IMANHUA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('href="/comic/', parse[i]) > 0) and - (Pos('/list_', parse[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse[i + 1]); - ANames.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i], 'href'); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 43c7249c7..059109eb4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -237,7 +237,6 @@ interface ESMANGAHERE_ID = 6; ANIMEEXTREMIST_ID = 7; S2SCAN_ID = 8; - IMANHUA_ID = 9; CENTRALDEMANGAS_ID = 10; EGSCANS_ID = 11; MANGAAR_ID = 12; @@ -272,7 +271,7 @@ interface ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), ('S2Scans', 'http://reader.s2smanga.com'), - ('imanhua', 'http://www.imanhua.com'), + ('', ''), ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), ('MangaAr', 'http://manga-ar.net'), @@ -316,8 +315,6 @@ interface ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; - IMANHUA_BROWSER = '/all.html'; - CENTRALDEMANGAS_BROWSER = '/mangas/list/*'; EGSCANS_BROWSER = '/'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d3d3ad0a9..c1815c653 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -904,8 +904,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/CentralDeMangas/names_and_links.inc} - {$I includes/Imanhua/names_and_links.inc} - {$I includes/Turkcraft/names_and_links.inc} {$I includes/Starkana/names_and_links.inc} @@ -996,9 +994,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = CENTRALDEMANGAS_ID then Result := CentralDeMangasGetNamesAndLinks else - if MangaSiteID = IMANHUA_ID then - Result := imanhuaGetNamesAndLinks - else if MangaSiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else From 11a6194b4a07a765944f029d8a52c995352d8f39 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:55:34 +0300 Subject: [PATCH 2120/2794] remove Manga-Lib_PL --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 059109eb4..3c8a6a60a 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -285,7 +285,7 @@ interface ('MangaREADER_POR', 'http://www.mangareader.com.br'), ('Japan-Shin', 'http://www.japan-shin.com'), ('', ''), - ('Manga-Lib_PL', 'http://www.manga-lib.pl/index.php'), + ('', ''), ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), ('MangaOku', 'http://www.mangaoku.net'), From 825acf77ebe528518fcda591e19c9fc37e0d236f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:57:45 +0300 Subject: [PATCH 2121/2794] remove MangaAr # Conflicts: # config/mangalist.ini --- .../includes/MangaAr/chapter_page_number.inc | 34 ----- baseunits/includes/MangaAr/image_url.inc | 48 ------- .../includes/MangaAr/manga_information.inc | 129 ------------------ .../includes/MangaAr/names_and_links.inc | 45 ------ baseunits/uBaseUnit.pas | 5 +- baseunits/uData.pas | 10 -- baseunits/uDownloadsManager.pas | 7 - config/mangalist.ini | 2 +- 8 files changed, 2 insertions(+), 278 deletions(-) delete mode 100644 baseunits/includes/MangaAr/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaAr/image_url.inc delete mode 100644 baseunits/includes/MangaAr/manga_information.inc delete mode 100644 baseunits/includes/MangaAr/names_and_links.inc diff --git a/baseunits/includes/MangaAr/chapter_page_number.inc b/baseunits/includes/MangaAr/chapter_page_number.inc deleted file mode 100644 index 3f2af60f3..000000000 --- a/baseunits/includes/MangaAr/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetMangaArPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - - if l.Count > 0 then - try - for i := 0 to l.Count - 1 do - if Pos('var pages = [', l[i]) > 0 then - begin - s := l[i]; - s := StringReplace(s, 'var pages =', '', [rfIgnoreCase]); - s := Trim(TrimChar(s, [';', ' '])); - Break; - end; - if s <> '' then - begin - Task.Container.PageLinks.Clear; - ParseJSONArray(s, 'url', Task.Container.PageLinks); - Task.Container.PageNumber := Task.Container.PageLinks.Count; - end; - finally - parse.Free; - l.Free; - end; - end; diff --git a/baseunits/includes/MangaAr/image_url.inc b/baseunits/includes/MangaAr/image_url.inc deleted file mode 100644 index e1c29e1b0..000000000 --- a/baseunits/includes/MangaAr/image_url.inc +++ /dev/null @@ -1,48 +0,0 @@ - function GetMangaArImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l, ts: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAAR_ID, URL) + '/1'; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - Task.Container.PageLinks.Clear; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('var pages =', parse[i]) > 0) then - begin - ts := TStringList.Create; - s := GetString(parse[i], '[{', '}];'); - s := StringReplace(s, '":', '",', [rfReplaceAll]); - s := StringReplace(s, '\', '', [rfReplaceAll]); - ts.DelimitedText := s; - for j := 0 to ts.Count - 1 do - begin - if (Pos('url', ts[j]) > 0) then - begin - s := ts[j + 1]; - s := 'http' + GetString(s, 'http', '?w='); //original resolution - Task.Container.PageLinks.Add(s); - end; - end; - ts.Free; - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaAr/manga_information.inc b/baseunits/includes/MangaAr/manga_information.inc deleted file mode 100644 index 3ba8396d9..000000000 --- a/baseunits/includes/MangaAr/manga_information.inc +++ /dev/null @@ -1,129 +0,0 @@ - function GetMangaArInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(MANGAAR_ID, AURL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MANGAAR_ID, 0]; - - mangaInfo.numChapter := 0; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class=" thumbnail"', parse[i]) > 0) then - mangaInfo.coverLink := - CorrectURL(GetVal(parse[i + 2], 'src')); - - // get summary - if (i + 4 < parse.Count) and (Pos('القصة', parse[i]) > 0) then - if (Pos('</span>', parse[i - 1]) > 0) and - (Pos('</dt>', parse[i + 1]) > 0) then - begin - mangaInfo.summary := ''; - j := i + 4; - while (j < parse.Count) and (not (Pos('</dd>', parse[j]) > 0)) do - begin - s := Trim(parse[j]); - s := HTMLEntitiesFilter(StringFilter(s)); - mangaInfo.summary := mangaInfo.summary + s; - Inc(j); - end; - mangaInfo.summary := StringReplace(mangaInfo.summary, '<p>', - '\r\n', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '</p>', '', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', - '\r\n', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', - '\r\n', [rfReplaceAll]); - mangaInfo.summary := StringReplace(mangaInfo.summary, '\r\n\r\n', - '\r\n', [rfReplaceAll]); - end; - - // get title - if (mangaInfo.title = '') and - (Pos('http-equiv="description" content="', parse[i]) <> 0) then - mangaInfo.title := Trim(GetVal(parse[i], 'content')); - - // get chapter name and links - if (Pos('class="tit ajaxify {title:', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse[i + 1])); - s := StringFilter(HTMLEntitiesFilter(s)); - mangaInfo.chapterName.Add(s); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('اسم المؤلف', parse[i]) > 0) then - if (Pos('</span>', parse[i - 1]) > 0) and - (Pos('</dt>', parse[i + 1]) > 0) then - mangaInfo.authors := Trim(parse[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('اسم الرسام', parse[i]) > 0) then - if (Pos('</span>', parse[i - 1]) > 0) and - (Pos('</dt>', parse[i + 1]) > 0) then - mangaInfo.artists := Trim(parse[i + 4]); - - // get genres - if (i + 4 < parse.Count) and (Pos('التصنيف', parse[i]) > 0) then - if (Pos('</span>', parse[i - 1]) > 0) and - (Pos('</dt>', parse[i + 1]) > 0) then - begin - mangaInfo.genres := Trim(parse[i + 4]); - mangaInfo.genres := StringReplace(mangaInfo.genres, sLineBreak, - '', [rfReplaceAll]); - mangaInfo.genres := StringReplace(mangaInfo.genres, ' ', '', [rfReplaceAll]); - mangaInfo.genres := StringReplace(mangaInfo.genres, ',', ', ', [rfReplaceAll]); - end; - - // get status - if (i + 4 < parse.Count) and (Pos('حالة الترجمة', parse[i]) > 0) then - if (Pos('</span>', parse[i - 1]) > 0) and - (Pos('</dt>', parse[i + 1]) > 0) then - begin - if Trim(parse[i + 4]) = 'مكتملة' then - mangaInfo.status := '1' // Ongoing - else - mangaInfo.status := '0'; // Completed - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaAr/names_and_links.inc b/baseunits/includes/MangaAr/names_and_links.inc deleted file mode 100644 index 56d762db2..000000000 --- a/baseunits/includes/MangaAr/names_and_links.inc +++ /dev/null @@ -1,45 +0,0 @@ - function MangaArGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - isExtractMangaList: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAR_ID, 1] + MANGAAR_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<tbody>', parse[i]) > 0) then - isExtractMangaList := True; - if (Pos('</tbody>', parse[i]) > 0) then - begin - isExtractMangaList := False; - Break; - end; - - if isExtractMangaList and (Pos('href=', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'href'); - s := StringReplace(s, WebsiteRoots[MANGAAR_ID, 1], '', []); - ALinks.Add(s); - s := Trim(StringFilter(parse[i + 1])); - s := HTMLEntitiesFilter(s); - ANames.Add(s); - end; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3c8a6a60a..f640bfb1b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -239,7 +239,6 @@ interface S2SCAN_ID = 8; CENTRALDEMANGAS_ID = 10; EGSCANS_ID = 11; - MANGAAR_ID = 12; ANIMESTORY_ID = 13; LECTUREENLIGNE_ID = 14; SCANMANGA_ID = 15; @@ -274,7 +273,7 @@ interface ('', ''), ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), - ('MangaAr', 'http://manga-ar.net'), + ('', ''), ('AnimeStory', 'http://www.anime-story.com'), ('Lecture-En-Ligne', 'http://www.lecture-en-ligne.com'), ('ScanManga', 'http://www.scan-manga.com'), @@ -319,8 +318,6 @@ interface EGSCANS_BROWSER = '/'; - MANGAAR_BROWSER = '/manga/'; - ANIMESTORY_BROWSER = '/mangas/'; LECTUREENLIGNE_BROWSER = '/index.php?page=liste&ordre=titre'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c1815c653..5a4236b2e 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -900,8 +900,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/ScanManga/names_and_links.inc} - {$I includes/MangaAr/names_and_links.inc} - {$I includes/CentralDeMangas/names_and_links.inc} {$I includes/Turkcraft/names_and_links.inc} @@ -988,9 +986,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = SCANMANGA_ID then Result := ScanMangaGetNamesAndLinks else - if MangaSiteID = MANGAAR_ID then - Result := MangaArGetNamesAndLinks - else if MangaSiteID = CENTRALDEMANGAS_ID then Result := CentralDeMangasGetNamesAndLinks else @@ -1089,8 +1084,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/Turkcraft/manga_information.inc} - {$I includes/MangaAr/manga_information.inc} - {$I includes/CentralDeMangas/manga_information.inc} {$I includes/MeinManga/manga_information.inc} @@ -1188,9 +1181,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftInfoFromURL else - if MangaSiteID = MANGAAR_ID then - Result := GetMangaArInfoFromURL - else if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 888135013..b85a92da0 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -418,8 +418,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/Kivmanga/chapter_page_number.inc} - {$I includes/MangaAr/chapter_page_number.inc} - {$I includes/MeinManga/chapter_page_number.inc} {$I includes/S2Scans/chapter_page_number.inc} @@ -550,8 +548,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Kivmanga/image_url.inc} - {$I includes/MangaAr/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -617,9 +613,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftImageURL else - if Task.Container.MangaSiteID = MANGAAR_ID then - Result := GetMangaArImageURL - else if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 43c2802f9..660450486 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] -Arabic=GManga,MangaAe,MangaAr,MangaAt,Mangaf +Arabic=GManga,MangaAe,MangaAt,Mangaf English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree From f312dd29901645dc8fce78d650205e291f414cf2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 30 Jan 2018 17:59:19 +0300 Subject: [PATCH 2122/2794] remove MangaAt # Conflicts: # config/mangalist.ini --- .../includes/MangaAt/chapter_page_number.inc | 40 ------- .../MangaAt/directory_page_number.inc | 47 -------- baseunits/includes/MangaAt/image_url.inc | 34 ------ .../includes/MangaAt/manga_information.inc | 108 ------------------ .../includes/MangaAt/names_and_links.inc | 37 ------ baseunits/uBaseUnit.pas | 3 +- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 12 +- config/mangalist.ini | 2 +- 9 files changed, 3 insertions(+), 295 deletions(-) delete mode 100644 baseunits/includes/MangaAt/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaAt/directory_page_number.inc delete mode 100644 baseunits/includes/MangaAt/image_url.inc delete mode 100644 baseunits/includes/MangaAt/manga_information.inc delete mode 100644 baseunits/includes/MangaAt/names_and_links.inc diff --git a/baseunits/includes/MangaAt/chapter_page_number.inc b/baseunits/includes/MangaAt/chapter_page_number.inc deleted file mode 100644 index a983de6bc..000000000 --- a/baseunits/includes/MangaAt/chapter_page_number.inc +++ /dev/null @@ -1,40 +0,0 @@ - function GetMangaAtPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - isExtractPage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAAT_ID, URL + '/1/')); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'active') then - isExtractPage := True; - if isExtractPage and (GetTagName(parse[i]) = 'a') then - if GetVal(parse[i], 'class') = 'chapter' then - Break - else - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaAt/directory_page_number.inc b/baseunits/includes/MangaAt/directory_page_number.inc deleted file mode 100644 index 4444cf63a..000000000 --- a/baseunits/includes/MangaAt/directory_page_number.inc +++ /dev/null @@ -1,47 +0,0 @@ - function GetMangaAtDirectoryPageNumber: Byte; - var - i, p: Integer; - s: String; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAT_ID, 1] + - '/manga', 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - APage := 0; - regx := TRegExpr.Create; - try - regx.Expression := '^.*/manga/page\:(\d+)$'; - regx.ModifierI := True; - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'a') and (Pos('/manga/page:', parse[i]) > 0 ) then - begin - s := GetVal(parse[i], 'href'); - s := regx.Replace(s, '$1', True); - p := StrToIntDef(s, 0); - if p > APage then - APage := p; - end; - finally - regx.Free; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MangaAt/image_url.inc b/baseunits/includes/MangaAt/image_url.inc deleted file mode 100644 index 99969dfa0..000000000 --- a/baseunits/includes/MangaAt/image_url.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetMangaAtImageURL: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAAT_ID, URL) + - '/' + IntToStr(WorkId + 1) + '/'; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if GetVal(parse[i], 'id') = 'showchaptercontainer' then - if (GetTagName(parse[i + 3]) = 'img') then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i + 3], 'src'); - Break; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaAt/manga_information.inc b/baseunits/includes/MangaAt/manga_information.inc deleted file mode 100644 index e23eece09..000000000 --- a/baseunits/includes/MangaAt/manga_information.inc +++ /dev/null @@ -1,108 +0,0 @@ - function GetMangaAtInfoFromURL: Byte; - var - s: String; - i, j: Integer; - begin - mangaInfo.website := WebsiteRoots[MANGAAT_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAAT_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if GetVal(parse[i], 'class') = 'EnglishName' then - begin - mangaInfo.title := CommonStringFilter(parse[i + 1]); - if Length(mangaInfo.title) > 2 then - if (mangaInfo.title[1] = '(') and - (mangaInfo.title[Length(mangaInfo.title)] = ')') then - begin - Delete(mangaInfo.title, 1, 1); - Delete(mangaInfo.title, Length(mangaInfo.title), 1); - end; - end; - - //cover - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'class') = 'manga-cover') then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - if GetTagName(parse[i]) = 'h3' then - begin - //genre - if Pos('التصنيف:', parse[i + 1]) > 0 then - begin - for j := i + 2 to parse.Count - 1 do - begin - if GetTagName(parse[j]) = '/ul' then - Break; - if Pos('<', parse[j]) = 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[j]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[j]); - end; - mangaInfo.genres := Trim(mangaInfo.genres); - end; - - //author - if Pos('اسم المؤلف بالأنجليزية', parse[i + 1]) > 0 then - mangaInfo.authors := CommonStringFilter(TrimLeftChar(parse[i + 5], [':'])); - - //status - if Pos('الحالة :', parse[i + 1]) > 0 then - begin - s := Trim(TrimLeftChar(parse[i + 5], [':'])); - if s = 'مستمرة' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - - //summary - if Pos('نبذة عن المانجا', parse[i + 1]) > 0 then - mangaInfo.summary := CommonStringFilter(parse[i + 5]); - end; - - //chapters - if (GetTagName(parse[i]) = 'a') and - (GetVal(parse[i], 'class') = 'chapter') then - begin - Inc(mangaInfo.numChapter); - s := GetVal(parse[i], 'href'); - if Length(s) > 3 then - if RightStr(s, 3) = '/1/' then - SetLength(s, Length(s) - 3); - mangaInfo.chapterLinks.Add(s); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - Result := NO_ERROR; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 0 then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - end; diff --git a/baseunits/includes/MangaAt/names_and_links.inc b/baseunits/includes/MangaAt/names_and_links.inc deleted file mode 100644 index 5daccdbed..000000000 --- a/baseunits/includes/MangaAt/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function MangaAtGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAAT_ID, 1] + - '/manga/page:' + IntToStr(StrToInt(AURL) + 1), 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(FixHTMLTagQuote(Source.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - finally - Parser.Exec; - end; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'a') and - (GetVal(parse[i], 'class') = 'manga') then - begin - ALinks.Add(GetVal(parse[i], 'href')); - ANames.Add(CommonStringFilter(parse[i + 1])); - end; - end; - - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f640bfb1b..8d26861a1 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -257,7 +257,6 @@ interface EXTREMEMANGAS_ID = 30; MANGAHOST_ID = 31; MANGAKU_ID = 32; - MANGAAT_ID = 33; DYNASTYSCANS_ID = 34; WebsiteRoots: array [0..34] of array [0..1] of String = ( @@ -294,7 +293,7 @@ interface ('ExtremeMangas', 'http://www.extrememangas.com'), ('MangaHost', 'http://br.mangahost.com'), ('MangaKu', 'http://mangaku.web.id'), - ('MangaAt', 'http://www.mangaat.com'), + ('', ''), ('Dynasty-Scans', 'http://dynasty-scans.com') ); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5a4236b2e..d269f1b86 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -804,8 +804,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/MangaHost/directory_page_number.inc} - {$I includes/MangaAt/directory_page_number.inc} - {$I includes/Dynasty-Scans/directory_page_number.inc} begin @@ -863,9 +861,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = MANGAHOST_ID then Result := GetMangaHostDirectoryPageNumber else - if MangaSiteID = MANGAAT_ID then - Result := GetMangaAtDirectoryPageNumber - else if MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansDirectoryPageNumber else @@ -940,8 +935,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/MangaKu/names_and_links.inc} - {$I includes/MangaAt/names_and_links.inc} - {$I includes/Dynasty-Scans/names_and_links.inc} begin @@ -1034,9 +1027,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = MANGAKU_ID then Result := MangaKuGetNamesAndLinks else - if MangaSiteID = MANGAAT_ID then - Result := MangaAtGetNamesAndLinks - else if MangaSiteID = DYNASTYSCANS_ID then Result := DynastyScansGetNamesAndLinks else @@ -1116,8 +1106,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/MangaKu/manga_information.inc} - {$I includes/MangaAt/manga_information.inc} - {$I includes/Dynasty-Scans/manga_information.inc} begin @@ -1226,9 +1214,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = MANGAKU_ID then Result := GetMangaKuInfoFromURL else - if MangaSiteID = MANGAAT_ID then - Result := GetMangaAtInfoFromURL - else if MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index b85a92da0..635097d22 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -450,8 +450,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/MangaKu/chapter_page_number.inc} - {$I includes/MangaAt/chapter_page_number.inc} - {$I includes/Dynasty-Scans/chapter_page_number.inc} begin @@ -522,9 +520,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGAKU_ID then Result := GetMangaKuPageNumber else - if Task.Container.MangaSiteID = MANGAAT_ID then - Result := GetMangaAtPageNumber - else if Task.Container.MangaSiteID = DYNASTYSCANS_ID then Result := GetDynastyScansPageNumber; end; @@ -580,8 +575,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/MangaHost/image_url.inc} - {$I includes/MangaAt/image_url.inc} - begin Result := False; if Task.Container.PageLinks[WorkId] <> 'W' then Exit; @@ -653,10 +646,7 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; Result := GetUnixMangaImageURL else if Task.Container.MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostImageURL - else - if Task.Container.MangaSiteID = MANGAAT_ID then - Result := GetMangaAtImageURL; + Result := GetMangaHostImageURL; end; end; diff --git a/config/mangalist.ini b/config/mangalist.ini index 660450486..921a34187 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,7 @@ DefaultSelect=MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] -Arabic=GManga,MangaAe,MangaAt,Mangaf +Arabic=GManga,MangaAe,Mangaf English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree From ec22658e38c9335d2b5d0931ab8192432f520ee7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 8 Feb 2018 22:04:20 +0800 Subject: [PATCH 2123/2794] fix transfer rate graph anchoring --- mangadownloader/forms/frmMain.lfm | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index a084ff90d..f1487c072 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -103,11 +103,14 @@ object MainForm: TMainForm object TransferRateGraph: TChart AnchorSideLeft.Control = pnDownloadToolbarLeft AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = edDownloadsSearch + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = pnDownloadToolbar AnchorSideRight.Side = asrBottom AnchorSideBottom.Side = asrBottom Left = 475 Height = 25 - Top = 1 + Top = 0 Width = 81 AllowZoom = False AxisList = < @@ -156,6 +159,7 @@ object MainForm: TMainForm 'TAChart' ) Toolset = TransferRateToolset + Anchors = [akTop, akLeft, akRight] Visible = False object TransferRateGraphArea: TAreaSeries Transparency = 125 @@ -289,13 +293,15 @@ object MainForm: TMainForm Width = 556 Align = alClient Anchors = [akTop, akLeft, akRight] + BevelOuter = bvNone ClientHeight = 464 ClientWidth = 556 + ParentBidiMode = False TabOrder = 1 object ToolBarDownloadLeft: TToolBar - Left = 1 - Height = 462 - Top = 1 + Left = 0 + Height = 464 + Top = 0 Width = 25 Align = alLeft AutoSize = True @@ -343,10 +349,10 @@ object MainForm: TMainForm end end object vtDownload: TVirtualStringTree - Left = 30 - Height = 462 - Top = 1 - Width = 525 + Left = 29 + Height = 464 + Top = 0 + Width = 527 Align = alClient Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight From 1a19d243df2888389f7da386c67d4933fbffd590 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 13:33:14 +0800 Subject: [PATCH 2124/2794] set png compression level to none when converting webp --- baseunits/uBaseUnit.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8d26861a1..7e6c004f0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -816,7 +816,7 @@ procedure SendLogException(const AText: String; AException: Exception); inline; implementation uses - {$IFDEF DOWNLOADER}WebsiteModules, webp, FPWriteJPEG;{$ENDIF} + {$IFDEF DOWNLOADER}WebsiteModules, webp, FPWriteJPEG, zstream;{$ENDIF} {$IFDEF WINDOWS} // thanks Leledumbo for the code @@ -3336,6 +3336,7 @@ function WebPToPNGStream(const AStream: TMemoryStream): Boolean; writer := TFPWriterPNG.create; writer.Indexed := False; writer.UseAlpha := mem.HasTransparentPixels; + writer.CompressionLevel := zstream.clnone; mem.SaveToStream(AStream, writer); Result := True; finally From ec2100a06e8dc92e9f8ac9910a8db8cf1046dfaf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 14:58:03 +0800 Subject: [PATCH 2125/2794] lua print with criticalsection --- baseunits/lua/LuaBase.pas | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 6d89d545f..3ac60c337 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -24,13 +24,21 @@ implementation uses LuaClass, luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog; +var + printcs: TRTLCriticalSection; + function luabase_print(L: Plua_State): Integer; cdecl; var i: Integer; begin Result := 0; - for i := 1 to lua_gettop(L) do - Logger.Send(lua_tostring(L, i)); + EnterCriticalsection(printcs); + try + for i := 1 to lua_gettop(L) do + Logger.Send(lua_tostring(L, i)); + finally + LeaveCriticalsection(printcs); + end; end; procedure LuaBaseRegister(L: Plua_State); @@ -140,4 +148,10 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh Result := lua_load(L, @_luareader, AStream, AName, 'b'); end; +initialization + InitCriticalSection(printcs); + +finalization + DoneCriticalsection(printcs); + end. From a3b37ad5320eb50acf128ef5c9aa7378e60b25d6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 15:18:27 +0800 Subject: [PATCH 2126/2794] fix mangastream (#922) --- lua/modules/MangaStream.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaStream.lua b/lua/modules/MangaStream.lua index 586cb054b..1228dff82 100644 --- a/lua/modules/MangaStream.lua +++ b/lua/modules/MangaStream.lua @@ -22,7 +22,7 @@ function GetPageNumber() end function GetImageURL() - if http.get(MaybeFillHost(module.rooturl,url)) then + if http.get(MaybeFillHost(module.rooturl,url):gsub('/1$','')..'/'..tostring(workid+1)) then x=TXQuery.Create(http.Document) task.pagelinks[workid]=x.xpathstring('//img[@id="manga-page"]/@src') return true From 5909e9d4df2c013a9ec3ca14badbb8a9baad09ba Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 11:16:06 +0300 Subject: [PATCH 2127/2794] set png compression level to clfastest --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 7e6c004f0..76f8b7c50 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3336,7 +3336,7 @@ function WebPToPNGStream(const AStream: TMemoryStream): Boolean; writer := TFPWriterPNG.create; writer.Indexed := False; writer.UseAlpha := mem.HasTransparentPixels; - writer.CompressionLevel := zstream.clnone; + writer.CompressionLevel := zstream.clfastest; mem.SaveToStream(AStream, writer); Result := True; finally From b894252ad5ce4da5f214342a9be363cd3dde116b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 17:42:36 +0800 Subject: [PATCH 2128/2794] add options webp convert (#919) --- baseunits/FMDOptions.pas | 4 + baseunits/uBaseUnit.pas | 32 +- mangadownloader/forms/frmMain.lfm | 736 ++++++++++++++++++++++++- mangadownloader/forms/frmMain.lrj | 6 + mangadownloader/forms/frmMain.pas | 29 +- mangadownloader/languages/fmd.de.po | 39 ++ mangadownloader/languages/fmd.el_GR.po | 39 ++ mangadownloader/languages/fmd.en.po | 39 ++ mangadownloader/languages/fmd.es.po | 39 ++ mangadownloader/languages/fmd.id_ID.po | 39 ++ mangadownloader/languages/fmd.pl_PL.po | 39 ++ mangadownloader/languages/fmd.po | 39 ++ mangadownloader/languages/fmd.pt_BR.po | 39 ++ mangadownloader/languages/fmd.ru_RU.po | 39 ++ mangadownloader/languages/fmd.tr_TR.po | 39 ++ 15 files changed, 1174 insertions(+), 23 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index d9f400183..803214db2 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -125,6 +125,10 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionPDFQuality: Cardinal = 95; + OptionWebPConvertTo: Integer = 1; + OptionWebPPNGLevel: Integer = 1; + OptionWebPJpegQuality: Integer = 80; + // connections OptionMaxParallel: Integer = 1; OptionMaxThreads: Integer = 1; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 76f8b7c50..4c27414af 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -23,7 +23,7 @@ interface FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit, - MemBitmap, FPWritePNG; + MemBitmap, FPWritePNG, zstream; const LineEnding2 = LineEnding + LineEnding; @@ -728,8 +728,8 @@ function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0) function GetURLFromBitly(const URL: String): String; // convert webp -function WebPToPNGStream(const AStream: TMemoryStream): Boolean; -function WebPToJpegStream(const AStream: TMemoryStream): Boolean; +function WebPToPNGStream(const AStream: TMemoryStream; const ALevel: Tcompressionlevel = clfastest): Boolean; +function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer = 80): Boolean; // check and convert known file @@ -816,7 +816,7 @@ procedure SendLogException(const AText: String; AException: Exception); inline; implementation uses - {$IFDEF DOWNLOADER}WebsiteModules, webp, FPWriteJPEG, zstream;{$ENDIF} + {$IFDEF DOWNLOADER}WebsiteModules, webp, FPWriteJPEG;{$ENDIF} {$IFDEF WINDOWS} // thanks Leledumbo for the code @@ -3322,7 +3322,8 @@ function GetURLFromBitly(const URL: String): String; httpSource.Free; end; -function WebPToPNGStream(const AStream: TMemoryStream): Boolean; +function WebPToPNGStream(const AStream: TMemoryStream; + const ALevel: Tcompressionlevel): Boolean; var mem: TMemBitmap; writer: TFPWriterPNG; @@ -3336,7 +3337,7 @@ function WebPToPNGStream(const AStream: TMemoryStream): Boolean; writer := TFPWriterPNG.create; writer.Indexed := False; writer.UseAlpha := mem.HasTransparentPixels; - writer.CompressionLevel := zstream.clfastest; + writer.CompressionLevel := ALevel; mem.SaveToStream(AStream, writer); Result := True; finally @@ -3348,7 +3349,8 @@ function WebPToPNGStream(const AStream: TMemoryStream): Boolean; end; end; -function WebPToJpegStream(const AStream: TMemoryStream): Boolean; +function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer + ): Boolean; var mem: TMemBitmap; writer: TFPWriterJPEG; @@ -3360,7 +3362,7 @@ function WebPToJpegStream(const AStream: TMemoryStream): Boolean; if Assigned(mem) then try writer := TFPWriterJPEG.create; - writer.CompressionQuality := 80; + writer.CompressionQuality := AQuality; mem.SaveToStream(AStream, writer); Result := True; finally @@ -3411,12 +3413,14 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag if Stream.Size = 0 then Exit; p := CorrectPathSys(Path); if ForceDirectoriesUTF8(p) then begin - f := GetImageStreamExt(Stream); - if f = '' then - begin - if ConvertKnownImageFormat(Stream) then - f := GetImageStreamExt(Stream); - end; + if IsWebPStream(Stream) then + case OptionWebPConvertTo of + 0: f := 'webp'; + 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionWebPPNGLevel)) then f := 'png'; + 2: if WebPToJpegStream(Stream, OptionWebPJpegQuality) then f := 'jpg'; + end + else + f := GetImageStreamExt(Stream); if f = '' then Exit; f := p + FileName + '.' + f; if FileExistsUTF8(f) then DeleteFileUTF8(f); diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f1487c072..785d6029e 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -8,6 +8,7 @@ object MainForm: TMainForm ClientHeight = 587 ClientWidth = 771 Color = clWindow + Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy @@ -15,7 +16,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.9.0.0' + LCLVersion = '1.8.0.6' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -115,16 +116,12 @@ object MainForm: TMainForm AllowZoom = False AxisList = < item - Marks.LabelBrush.Style = bsClear Minors = <> Title.LabelFont.Orientation = 900 - Title.LabelBrush.Style = bsClear end item Alignment = calBottom - Marks.LabelBrush.Style = bsClear Minors = <> - Title.LabelBrush.Style = bsClear end> AxisVisible = False BackColor = clDefault @@ -3459,13 +3456,13 @@ object MainForm: TMainForm end object gbOptionRenaming: TGroupBox AnchorSideLeft.Control = lbDefaultDownloadPath - AnchorSideTop.Control = seOptionPDFQuality + AnchorSideTop.Control = gbWebP AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lbDefaultDownloadPath AnchorSideRight.Side = asrBottom Left = 4 Height = 302 - Top = 145 + Top = 250 Width = 728 Anchors = [akTop, akLeft, akRight] AutoSize = True @@ -3852,6 +3849,113 @@ object MainForm: TMainForm TabOrder = 4 TextHint = 'Default download path' end + object gbWebP: TGroupBox + AnchorSideLeft.Control = lbDefaultDownloadPath + AnchorSideTop.Control = seOptionPDFQuality + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = sbSaveTo + AnchorSideRight.Side = asrBottom + Left = 4 + Height = 101 + Top = 145 + Width = 728 + Anchors = [akTop, akLeft, akRight] + AutoSize = True + Caption = 'WebP' + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 6 + ChildSizing.VerticalSpacing = 6 + ClientHeight = 81 + ClientWidth = 724 + TabOrder = 5 + object lbWebPConvertTo: TLabel + Left = 4 + Height = 15 + Top = 8 + Width = 72 + Caption = 'Save WebP to' + ParentColor = False + end + object cbWebPConvertTo: TComboBox + AnchorSideLeft.Control = lbWebPConvertTo + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbWebPConvertTo + AnchorSideTop.Side = asrCenter + Left = 82 + Height = 23 + Top = 4 + Width = 76 + ItemHeight = 15 + ItemIndex = 1 + Items.Strings = ( + 'WebP' + 'PNG' + 'Jpeg' + ) + Style = csDropDownList + TabOrder = 0 + Text = 'PNG' + end + object lbWebPPNGCompressionLevel: TLabel + AnchorSideLeft.Control = lbWebPConvertTo + AnchorSideTop.Control = cbWebPConvertTo + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 15 + Top = 33 + Width = 124 + Caption = 'PNG Compression level' + ParentColor = False + end + object cbWebPPNGCompressionLevel: TComboBox + AnchorSideLeft.Control = lbWebPPNGCompressionLevel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbWebPPNGCompressionLevel + AnchorSideTop.Side = asrCenter + AnchorSideRight.Side = asrBottom + Left = 134 + Height = 23 + Top = 29 + Width = 85 + ItemHeight = 15 + ItemIndex = 1 + Items.Strings = ( + 'None' + 'Fastest' + 'Default' + 'Maximum' + ) + Style = csDropDownList + TabOrder = 1 + Text = 'Fastest' + end + object lbWebPJpegQuality: TLabel + AnchorSideLeft.Control = lbWebPConvertTo + AnchorSideTop.Control = cbWebPPNGCompressionLevel + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 15 + Top = 58 + Width = 63 + Caption = 'Jpeg quality' + ParentColor = False + end + object seWebPJpegQuality: TSpinEdit + AnchorSideLeft.Control = lbWebPJpegQuality + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lbWebPJpegQuality + AnchorSideTop.Side = asrCenter + AnchorSideRight.Side = asrBottom + Left = 73 + Height = 23 + Top = 54 + Width = 47 + MinValue = 1 + TabOrder = 2 + Value = 80 + end + end end end object tsUpdate: TTabSheet @@ -4762,12 +4866,84 @@ object MainForm: TMainForm object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 7 OnClick = miDownloadStopClick end object miDownloadResume: TMenuItem Caption = 'Resume' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000000000001000000070000000E000000150000001A0000001A0000001A0000 + 001A0000001A0000001A000000160000000F0000000800000002000000000000 + 0000000000020000000E0000001C0000002A000000330000003300000033733A + 02A663320274000000330000002B0000001D0000000F00000003000000000000 + 0000000000000000000000000000000000000000000000000000281502009D52 + 06CC9D5206CC763E055C29160300000000000000000000000000B0651400A85D + 0E00A85D0E00553008007F470C00A85D0E007F470C00A85D0E00A65B0D00A358 + 0BCCFFB914FFA3580BCCA4590C5C7F470C002C19050000000000B4691700AA5F + 1000AA5F10CCAB601100AB601199AA5F10CCAB601199AA5F10CCAB601199AA5F + 10CCFFB810FFFFBB1BFFAA5F10CCAB60115CB1661600B96E1C00B76C1A00AF64 + 1400AF641400B3681700B16616CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B4 + 24FFF5AF18FFF5AB0EFFF7B92EFFB16616CCB267175CB96E1C00B96E1CCCBA6F + 1D00BA6F1D99B96E1CCCB96E1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA96 + 27F5E19E29FFE19E29FFE19E29FFEAB349FFB96E1CCCBA6F1D5CBF742000C378 + 2300C27722CCF8D084FFC27722CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D396 + 44FFD09341FFD09341FFD39644FFD89B49FFECBB6CFFC27722CCCB802999CA7F + 28CCCA7F28CCCA7F28CCCA7F28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE + 61FAEEB266FFEEB266FFEEB266FFF7CC80FFCA7F28CCC97E275CD2872ECCFBD9 + 8DFFD2872ECCD0852C00D2872ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C9 + 7DFFF4C175FFF2B96DFFFAD68AFFD2872ECCD1862D5CCA7F2800D88D3399D98E + 33CCD88D3399D78C3200D88D3399D98E33CCD88D3399D98E33CCD98E33CCD98E + 33CCFBD488FFFEDF93FFD98E33CCD88D335CD2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DA8F3400DC913600E095 + 38CCFFE498FFE09538CCDF94385CD98E3300D2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DD923700E59A3C00E59A + 3CCCE59A3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300E89D3F00E89D3F00E99E + 4099E99E405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 12 OnClick = miDownloadResumeClick end @@ -4783,6 +4959,42 @@ object MainForm: TMainForm object miDownloadDelete: TMenuItem Caption = 'Delete' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 9 object miDownloadDeleteTask: TMenuItem Caption = 'Task only' @@ -4810,6 +5022,42 @@ object MainForm: TMainForm object miDownloadMergeCompleted: TMenuItem Caption = 'Merge completed tasks' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000200000005000000090000000D0000001100000015000000180000001A0000 + 001A0000001A0000001A0000001A000000170000000F00000005000000000000 + 00040000000A0000001100000019000000220000002A00000030000000330000 + 003300000033733B03A6633303740000002E0000001D0000000A532E0700522D + 0600522D0600522D0600522D0600522D0600522D0600522D0600522D0600522D + 0600522D06009F5408CC9F5408CC783F065C2917030000000000A75C0E99A65B + 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B + 0DCCA65B0DCCA65B0DCCFFB508FFA65B0DCCA75C0E5C824A0E00AF6414CCF9C6 + 60FFFFBE23FFFFBD1FFFFFBC1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB7 + 0FFFFFB70DFFFFB60BFFFFB200FFFFB609FFAF6414CCAF641448B96E1BCCF6CB + 7FFFF8C051FFF9BD36FFF8B92CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B5 + 23FFF7B523FFF7B421FFF5AB0EFFF6B11BFFB96E1BCCB96E1B48C1762199C277 + 22CCC27722CCC27722CCD5973FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C + 26CFC27722CCC27722CCE6A93CFFC27722CCC176215CBB701C00C2772200C479 + 2400CC812A2BD38E38CEF0BF71FBE0A856FFDCA04CE4CC8129AACB80283FC97E + 270FC77C2600CC8129CCCC8129CCCB80285CC2772200BB701C00CD822A00D58A + 3000D58A307BEBB865E8F7C579FFF0C070EFD58A30AAD0852D13CC812900C97E + 2700D2872E00D4892F99D4892F5CCC812900C2772200BB701C00DD923600DD92 + 3600DD9236AAF8D081F6FCD185FFE7A951D9DC91363FDB903500CC812900C97E + 2700D2872E00D58A3000D58A3000CC812900C2772200BB701C00E4993B00E499 + 3B00E4993BC5FEDF92FDFFDF93FFE69E42CFE4993B0FE4993B00E4993B00D085 + 2D00D2872E00D58A3000D58A3000CC812900C2772200BB701C00E89D3E00E89D + 3E00E99E3F99E99E3FCCE99E3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C + 3200D2872E00D58A3000D58A3000CC812900C2772200BB701C00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 10 OnClick = miDownloadMergeCompletedClick end @@ -4819,18 +5067,126 @@ object MainForm: TMainForm object miDownloadViewMangaInfo: TMenuItem Caption = 'View manga info' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000030000 + 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B + 0B7A090909650505054200000032000000270000001300000003000000020000 + 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA + DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 + 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 + 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F + 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 + 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 + 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 + 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA + AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 + 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF + CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 + 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC + CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B + 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF + CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 + 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC + DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 + 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF + BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 + 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C + 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F + 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E + 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E + 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 + 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C + 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 + 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA + EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 + 50005252520053535300545454155555553E5555555555555563555555635555 + 55555555553E545454155353530052525200505050004F4F4F00 + } ImageIndex = 0 OnClick = miDownloadViewMangaInfoClick end object miDownloadOpenFolder: TMenuItem Caption = 'Open Folder' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 4 OnClick = miDownloadOpenFolderClick end object miDownloadOpenWith: TMenuItem Caption = 'Open ...' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000100000001A0000001000000000000000000000 + 00000000000000000000000000000000000000000000000000001007000F220E + 00352A110048000000620000008F000000ED0000008F000000622A110048200D + 003A130800300703002A050200290502002906030023020100095322009A8550 + 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 + 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 + B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 + B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF + FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 + EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B + A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 + DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 + D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE + FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 + F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF + E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F + 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F + 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D + } ImageIndex = 11 OnClick = miDownloadOpenWithClick end @@ -4899,11 +5255,83 @@ object MainForm: TMainForm top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 002C00000087000000E7702E00C7702E00C7702E00C7702E00C7702E00C7702E + 00C7702E00C72D5500E9175F00F4124A00C40000002C00000000000000090000 + 0016000000DB606060FFCA9764FFC5925FFFC5925FFFC5925FFFC5925FFFC592 + 5FFFC5925FFF318613FF2BDF1AFF1E7700F20000001600000009000000000101 + 0100010101CE626262FFC89562FFBD8A57FFBF8C59FFBF8C59FFBF8C59FF548D + 24FF318C12FF318C11FF3DE22CFF208100F00E8C00CC0E8D0099010101000101 + 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFF3394 + 12FF52E741FF52E741FF52E741FF52E741FF52E741FF109500CC010101000101 + 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFFC4915EFF5A98 + 26FF369B13FF359A12FF66EB55FF249000EF129D00CC129C0099010101000101 + 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC89562FFC895 + 62FFC89562FF369F12FF75EE64FF269700EE179E0000129D0000010101000101 + 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFCB98 + 65FFCB9865FF599D24FF3BA816FF448700DC6072000056730000010101000101 + 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFCF9C + 69FFCF9C69FFBF8C59FFD8A572FF9B4B00A59B4B00009B4B0000010101000101 + 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F + 6CFFD29F6CFFBE8B58FFDBA875FF9E4D00A39E4D00009E4D0000010101000101 + 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 + 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 + 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 + 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 + 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 + 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 + 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 + 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 + 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 + 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 + E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 + 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550073AA550000AA550000 + } ImageIndex = 21 OnClick = miFavoritesCheckNewChapterClick end object miFavoritesStopCheckNewChapter: TMenuItem Caption = 'Stop check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 7 OnClick = miFavoritesStopCheckNewChapterClick end @@ -4917,12 +5345,84 @@ object MainForm: TMainForm end object miFavoritesViewInfos: TMenuItem Caption = 'View manga info' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000030000 + 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B + 0B7A090909650505054200000032000000270000001300000003000000020000 + 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA + DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 + 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 + 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F + 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 + 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 + 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 + 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA + AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 + 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF + CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 + 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC + CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B + 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF + CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 + 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC + DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 + 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF + BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 + 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C + 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F + 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E + 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E + 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 + 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C + 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 + 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA + EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 + 50005252520053535300545454155555553E5555555555555563555555635555 + 55555555553E545454155353530052525200505050004F4F4F00 + } ImageIndex = 0 SubMenuImages = IconList OnClick = miFavoritesViewInfosClick end object miFavoritesDownloadAll: TMenuItem Caption = 'Download all' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } ImageIndex = 1 OnClick = miFavoritesDownloadAllClick end @@ -4939,6 +5439,42 @@ object MainForm: TMainForm end object miFavoritesDelete: TMenuItem Caption = 'Delete' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 9 SubMenuImages = IconList OnClick = miFavoritesDeleteClick @@ -4957,12 +5493,84 @@ object MainForm: TMainForm end object miFavoritesOpenFolder: TMenuItem Caption = 'Open Folder' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 4 SubMenuImages = IconList OnClick = miFavoritesOpenFolderClick end object miFavoritesOpenWith: TMenuItem Caption = 'Open ...' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000100000001A0000001000000000000000000000 + 00000000000000000000000000000000000000000000000000001007000F220E + 00352A110048000000620000008F000000ED0000008F000000622A110048200D + 003A130800300703002A050200290502002906030023020100095322009A8550 + 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 + 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 + B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 + B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF + FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 + EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B + A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 + DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 + D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE + FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 + F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF + E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F + 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F + 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D + } ImageIndex = 11 OnClick = miFavoritesOpenWithClick end @@ -4974,18 +5582,126 @@ object MainForm: TMainForm top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 + 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 + 0000000000040000001B481F1546B24C3399E96443D4EE6644F5EE6644F5E964 + 43D4B24C3399471F15470000001F0000000600000000FFFFFF00FFFFFF007432 + 210077332200B34D3360EF6F4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1 + C9FFF4A18EFFEF6E4EEBB34D33603C1A110000000000FFFFFF00FFFFFF00E863 + 4100EE664460EF7659F9F7D4CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8 + E8FFF7E9E9FFF6D1CAFFEF7658F9EE664460E8634100FFFFFF00FFFFFF00E360 + 3E20E66A4AEBF3D3CDFFF0E5E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4 + E4FFEFE4E4FFEFE4E4FFEFCDC7FFE66A4AEBE3603E20FFFFFF00FFFFFF00D659 + 3787E59D8AFFEAE2E2FFE7DFDFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DF + DFFFE7DFDFFFE7DFDFFFE8E0E0FFE19784FFD6593787FFFFFF00FFFFFF00C550 + 2ED0EAD0C8FFE1DADAFFE0D9D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9 + D9FFE0D9D9FFE0D9D9FFE0D9D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00B748 + 26F5F4EEEDFFE7E5E5FFDAD6D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4 + D4FFD8D4D4FFD8D4D4FFD8D4D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00AD44 + 22F5F4EFEDFFEEEEEEFFEAEAEAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0 + D0FFD2D0D0FFD2D0D0FFD2D0D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00AB46 + 24D0EAD5CDFFF0F0F0FFF0F0F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1 + D1FFCECECEFFCECECEFFD2D1D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00B34F + 2D87D49D8AFFF5F5F5FFF3F3F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3 + F3FFF3F3F3FFF3F3F3FFF5F5F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00BF5C + 3A20C56747EBF2DFD9FFF8F8F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7 + F7FFF7F7F7FFF8F8F8FFF2DFD9FFC56747EBBF5C3A20FFFFFF00FFFFFF00C461 + 3F00CF6B4960D77F61F9F6E3DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB + FBFFFCFCFCFFF6E3DCFFD77F61F9CF6B4960C4613F00FFFFFF00FFFFFF00C461 + 3F00D16D4B00DF7A5860E38464EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4 + DDFFEFB7A4FFE38464EBDF7A5860D16D4B00C4613F00FFFFFF00FFFFFF00C461 + 3F00D16D4B00E17C5A00EA846220EC866487EC8664D0EC8664F5EC8664F5EC86 + 64D0EC866487EA846220E17C5A00D16D4B00C4613F00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 13 SubMenuImages = IconList OnClick = miMangaListViewInfosClick end object miMangaListDownloadAll: TMenuItem Caption = 'Download all' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } ImageIndex = 1 SubMenuImages = IconList OnClick = miMangaListDownloadAllClick end object miMangaListAddToFavorites: TMenuItem Caption = 'Add to Favorites' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000050000 + 001E0000003200009CC9000054630000002E0000002B00000026000000220000 + 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 + 000F000000190000A8C50000A8C500006D580000001600000013000000110000 + 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 + 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D + 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 + BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 + 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 + C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C + 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 + C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 + 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 + C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 + CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 + C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 + FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 + C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 + F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A + F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C + F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E + FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 + 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 + DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 + 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 + E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 + 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 + E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 + 0000000000000000990000002B00000000000000000001016E000101DE000101 + E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 + } ImageIndex = 2 SubMenuImages = IconList OnClick = miMangaListAddToFavoritesClick @@ -6516,7 +7232,7 @@ object MainForm: TMainForm object appPropertiesMain: TApplicationProperties CaptureExceptions = False OnShowHint = appPropertiesMainShowHint - left = 96 + left = 392 top = 312 end object tmExitCommand: TTimer @@ -6949,4 +7665,8 @@ object MainForm: TMainForm 0000FFFFFF00FFFFFF00FFFFFF00 } end + object MainMenu1: TMainMenu + left = 224 + top = 323 + end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 45643c6b3..eff3e88b8 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -213,6 +213,12 @@ {"hash":265971401,"name":"tmainform.lboptionpdfquality.hint","sourcebytes":[49,48,48,32,61,32,70,108,97,116,101,69,110,99,111,100,101,32,40,108,111,115,115,108,101,115,115,41,44,32,108,111,119,101,114,32,61,32,68,67,84,69,110,99,111,100,101,32,40,108,111,115,115,121,41],"value":"100 = FlateEncode (lossless), lower = DCTEncode (lossy)"}, {"hash":13786124,"name":"tmainform.lboptionpdfquality.caption","sourcebytes":[80,68,70,32,99,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PDF compression level"}, {"hash":8726312,"name":"tmainform.edoptiondefaultpath.texthint","sourcebytes":[68,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104],"value":"Default download path"}, +{"hash":383856,"name":"tmainform.gbwebp.caption","sourcebytes":[87,101,98,80],"value":"WebP"}, +{"hash":137355519,"name":"tmainform.lbwebpconvertto.caption","sourcebytes":[83,97,118,101,32,87,101,98,80,32,116,111],"value":"Save WebP to"}, +{"hash":21799,"name":"tmainform.cbwebpconvertto.text","sourcebytes":[80,78,71],"value":"PNG"}, +{"hash":32654252,"name":"tmainform.lbwebppngcompressionlevel.caption","sourcebytes":[80,78,71,32,67,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PNG Compression level"}, +{"hash":210414820,"name":"tmainform.cbwebppngcompressionlevel.text","sourcebytes":[70,97,115,116,101,115,116],"value":"Fastest"}, +{"hash":228764105,"name":"tmainform.lbwebpjpegquality.caption","sourcebytes":[74,112,101,103,32,113,117,97,108,105,116,121],"value":"Jpeg quality"}, {"hash":208308883,"name":"tmainform.tsupdate.caption","sourcebytes":[85,112,100,97,116,101,115],"value":"Updates"}, {"hash":72408384,"name":"tmainform.cboptionautochecklatestversion.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,108,97,116,101,115,116,32,118,101,114,115,105,111,110,32],"value":"Auto check for latest version "}, {"hash":225003075,"name":"tmainform.gboptionfavorites.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6fc1fab07..7893e67f5 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -71,6 +71,8 @@ TMainForm = class(TForm) cbOptionOneInstanceOnly: TCheckBox; ckOptionsAlwaysStartTaskFromFailedChapters: TCheckBox; ckEnableLogging: TCheckBox; + cbWebPConvertTo: TComboBox; + cbWebPPNGCompressionLevel: TComboBox; edDownloadsSearch: TEditButton; edFavoritesSearch: TEditButton; edFilterMangaInfoChapters: TEditButton; @@ -83,13 +85,18 @@ TMainForm = class(TForm) edSaveTo: TEditButton; edURL: TEditButton; edWebsitesSearch: TEditButton; + gbWebP: TGroupBox; IconDLLeft: TImageList; + lbWebPPNGCompressionLevel: TLabel; + lbWebPJpegQuality: TLabel; + lbWebPConvertTo: TLabel; lbLogFileName: TLabel; lbOptionRetryFailedTask: TLabel; lbOptionFilenameCustomRenameHint: TLabel; lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; + MainMenu1: TMainMenu; MenuItem10: TMenuItem; MenuItem11: TMenuItem; miFavoritesRename: TMenuItem; @@ -144,6 +151,7 @@ TMainForm = class(TForm) sbWebsiteOptions: TScrollBox; btDownloadSplit: TSpeedButton; seOptionRetryFailedTask: TSpinEdit; + seWebPJpegQuality: TSpinEdit; ToolBarDownloadLeft: TToolBar; tbmiDownloadMoveTop: TToolButton; tbmiDownloadMoveUp: TToolButton; @@ -860,6 +868,8 @@ TMangaInfoData = record RS_OptionFMDDoItems = 'Nothing'#13#10'Exit'#13#10'Shutdown'#13#10'Hibernate'; RS_DropTargetModeItems = 'Download all'#13#10'Add to favorites'; RS_OptionCompress = 'None'#13#10'ZIP'#13#10'CBZ'#13#10'PDF'; + RS_WebPConvertTo = 'WebP'#13#10'PNG'#13#10'Jpeg'; + RS_WebPPNGLevel = 'None'#13#10'Fastest'#13#10'Default'#13#10'Maximum'; RS_HintFavoriteProblem = 'There is a problem with this data!'#13#10 + 'Removing and re-adding this data may fix the problem.'; @@ -4924,6 +4934,9 @@ procedure TMainForm.LoadOptions; edOptionFilenameCustomRename.Text := ReadString('saveto', 'FilenameCustomRename', DEFAULT_FILENAME_CUSTOMRENAME); if Trim(edOptionFilenameCustomRename.Text) = '' then edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; + cbWebPConvertTo.ItemIndex := ReadInteger('saveto', 'ConvertWebP', OptionWebPConvertTo); + cbWebPPNGCompressionLevel.ItemIndex := ReadInteger('saveto', 'WebPPNGLevel', OptionWebPPNGLevel); + seWebPJpegQuality.Value := ReadInteger('saveto', 'WebPJpegQuality', OptionWebPJpegQuality); // update cbOptionAutoCheckLatestVersion.Checked := ReadBool('update', 'AutoCheckLatestVersion', True); @@ -5064,6 +5077,9 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); if Trim(edOptionFilenameCustomRename.Text) = '' then edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; WriteString('saveto', 'FilenameCustomRename', edOptionFilenameCustomRename.Text); + WriteInteger('saveto', 'ConvertWebP', cbWebPConvertTo.ItemIndex); + WriteInteger('saveto', 'WebPPNGLevel', cbWebPPNGCompressionLevel.ItemIndex); + WriteInteger('saveto', 'WebPJpegQuality', seWebPJpegQuality.Value); // update WriteBool('update', 'AutoCheckLatestVersion', cbOptionAutoCheckLatestVersion.Checked); @@ -5200,6 +5216,9 @@ procedure TMainForm.ApplyOptions; OptionConvertDigitVolumeLength := seOptionDigitVolume.Value; OptionConvertDigitChapter := cbOptionDigitChapter.Checked; OptionConvertDigitChapterLength := seOptionDigitChapter.Value; + OptionWebPConvertTo := cbWebPConvertTo.ItemIndex; + OptionWebPPNGLevel := cbWebPPNGCompressionLevel.ItemIndex; + OptionWebPJpegQuality := seWebPJpegQuality.Value; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; @@ -5681,7 +5700,9 @@ procedure TMainForm.ApplyLanguage; idxOptionLetFMDDo, idxOptionProxyType, idxDropTargetMode, - idxOptionCompress: Integer; + idxOptionCompress, + idxOptionWebPConvertTo, + idxOptionWebPPNGLevel: Integer; begin if AvailableLanguages.Count = 0 then Exit; if cbLanguages.ItemIndex < 0 then Exit; @@ -5698,6 +5719,8 @@ procedure TMainForm.ApplyLanguage; idxOptionProxyType := cbOptionProxyType.ItemIndex; idxDropTargetMode := rgDropTargetMode.ItemIndex; idxOptionCompress := rgOptionCompress.ItemIndex; + idxOptionWebPConvertTo := cbWebPConvertTo.ItemIndex; + idxOptionWebPPNGLevel := cbWebPPNGCompressionLevel.ItemIndex; if SimpleTranslator.SetLangByIndex(cbLanguages.ItemIndex) then begin // assign new value @@ -5709,6 +5732,8 @@ procedure TMainForm.ApplyLanguage; cbOptionLetFMDDo.Items.Text := RS_OptionFMDDoItems; rgDropTargetMode.Items.Text := RS_DropTargetModeItems; rgOptionCompress.Items.Text := RS_OptionCompress; + cbWebPConvertTo.Items.Text := RS_WebPConvertTo; + cbWebPConvertTo.Items.Text := RS_WebPPNGLevel; // restore ItemIndex cbSelectManga.ItemIndex:=idxSelectManga; @@ -5718,6 +5743,8 @@ procedure TMainForm.ApplyLanguage; cbOptionProxyType.ItemIndex := idxOptionProxyType; rgDropTargetMode.ItemIndex := idxDropTargetMode; rgOptionCompress.ItemIndex := idxOptionCompress; + cbWebPConvertTo.ItemIndex := idxOptionWebPConvertTo; + cbWebPPNGCompressionLevel.ItemIndex := idxOptionWebPPNGLevel; Self.Repaint; vtMangaList.Repaint; tvDownloadFilterRefresh(True); diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index f4e47520d..a18deb6f5 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -311,6 +311,21 @@ msgstr "Pfad zur Software (z.B. C:\\MangaDownloader)" msgid "Today" msgstr "Heute" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Fehlerhafte Eingabe!" @@ -759,6 +774,14 @@ msgstr "Für mehr Manga-Seiten, bitte geh in die Optionen->Manga-Seiten" msgid "Regular Expression" msgstr "Regular Expression" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1216,6 +1239,10 @@ msgstr "Proxy Einstellung" msgid "Renaming" msgstr "Umbenennung" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Wähle den Standarddownloadpfad:" @@ -1475,6 +1502,18 @@ msgstr "Benutzername" msgid "Save to:" msgstr "Speichern unter:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index c9abd6a34..b153d4af9 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -315,6 +315,21 @@ msgstr "Διαδρομή του προγράμματος (π.χ. C:\\MangaDownlo msgid "Today" msgstr "Σήμερα" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Μη έγκυρη εισαγωγή!" @@ -763,6 +778,14 @@ msgstr "Για περισσότερους ιστότοπους manga, παρακ msgid "Regular Expression" msgstr "Κανονική έκφραση" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1271,6 +1294,10 @@ msgstr "Ρυθμίσεις διακομιστή μεσολάβησης" msgid "Renaming" msgstr "Μετονομασία" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Καθορίστε την προεπιλεγμένη διαδρομή λήψης:" @@ -1530,6 +1557,18 @@ msgstr "Όνομα χρήστη" msgid "Save to:" msgstr "Αποθήκευση σε:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 698353153..f7ea8fbe4 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -302,6 +302,21 @@ msgstr "Path to the software (e.g. C:\\MangaDownloader)" msgid "Today" msgstr "Today" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Invalid input!" @@ -739,6 +754,14 @@ msgstr "For more manga sites, please go to Options->Manga sites" msgid "Regular Expression" msgstr "Regular Expression" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1192,6 +1215,10 @@ msgstr "Proxy config" msgid "Renaming" msgstr "Renaming" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Choose the default download path:" @@ -1445,6 +1472,18 @@ msgstr "Username" msgid "Save to:" msgstr "Save to:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index f7c818fdc..c0e2d5fe9 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -309,6 +309,21 @@ msgstr "Ruta al Software (e.g. C:\\MangaDownloader)" msgid "Today" msgstr "Hoy" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Entrada no valida!" @@ -747,6 +762,14 @@ msgstr "Para más Sitios de Mangas, Ve a Opciones->Sitios Manga" msgid "Regular Expression" msgstr "Regular Expresión" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1200,6 +1223,10 @@ msgstr "Configuración de Proxy" msgid "Renaming" msgstr "Renombrando" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Escoger la Ruta de Descarga por Defecto:" @@ -1453,6 +1480,18 @@ msgstr "Usuario" msgid "Save to:" msgstr "Guardar en:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 3e703a7a2..65ce453c7 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -309,6 +309,21 @@ msgstr "Path ke perangkat lunak (misalnya C:\\MangaDownloader)" msgid "Today" msgstr "Hari ini" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Input salah!" @@ -747,6 +762,14 @@ msgstr "Untuk situs komik yang lain, silahkan pilih di Pengaturan->Situs komik" msgid "Regular Expression" msgstr "Regular Expression" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1200,6 +1223,10 @@ msgstr "Konfigurasi proxy" msgid "Renaming" msgstr "Mengubah nama" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Pilih lokasi pengunduhan bawaan:" @@ -1453,6 +1480,18 @@ msgstr "Nama user" msgid "Save to:" msgstr "Lokasi penyimpanan:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index e01a237be..c746c27e6 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -311,6 +311,21 @@ msgstr "Ścieżka do programu (np C:\\MangaDownloader)" msgid "Today" msgstr "Dzisiaj" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Nieprawidłowe wejście!" @@ -759,6 +774,14 @@ msgstr "Aby uzyskać więcej stron z mangami, przejdź do Opcje->Strony z mangam msgid "Regular Expression" msgstr "Wyrażenie regularne" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1216,6 +1239,10 @@ msgstr "Konfiguracja Proxy" msgid "Renaming" msgstr "Zmiana nazwy …" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Wybierz domyślną ścieżkę pobierania:" @@ -1476,6 +1503,18 @@ msgstr "Nazwa użytkownika" msgid "Save to:" msgstr "Zapisz do:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index fcc5fe2c4..48240c8ab 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -274,6 +274,21 @@ msgstr "" msgid "Today" msgstr "" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "" @@ -711,6 +726,14 @@ msgstr "" msgid "Regular Expression" msgstr "" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1162,6 +1185,10 @@ msgstr "" msgid "Renaming" msgstr "" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "" @@ -1383,6 +1410,18 @@ msgstr "" msgid "Save to:" msgstr "" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 059aa49dd..8be8b87b8 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -311,6 +311,21 @@ msgstr "Caminho para o software (e.g. C:\\MangaDownloader)" msgid "Today" msgstr "Hoje" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Entrada inválida!" @@ -758,6 +773,14 @@ msgstr "Para mais sites de mangá, por favor vá em Opções->Sites de Mangá" msgid "Regular Expression" msgstr "Expressão Regular" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1216,6 +1239,10 @@ msgstr "Config. do Proxy" msgid "Renaming" msgstr "Renomeando" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Escolha o caminho de download padrão:" @@ -1473,6 +1500,18 @@ msgstr "Nome de usuário" msgid "Save to:" msgstr "Salvar em:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 5c7171bca..4594b87f9 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -312,6 +312,21 @@ msgstr "Путь к программе (например, C:\\MangaDownloader)" msgid "Today" msgstr "Cегодня" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Неверный ввод!" @@ -749,6 +764,14 @@ msgstr "Для получения дополнительных сайтов с msgid "Regular Expression" msgstr "Регулярное выражение (regexp)" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1202,6 +1225,10 @@ msgstr "Конфигурация прокси-сервера" msgid "Renaming" msgstr "Переименовать" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Выберите путь загрузки по умолчанию:" @@ -1455,6 +1482,18 @@ msgstr "Имя пользователя" msgid "Save to:" msgstr "Сохранить в:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 0842b7972..2d4e738d1 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -316,6 +316,21 @@ msgstr "Yazılım yolu (mesela c:\\MangaDownloader)" msgid "Today" msgstr "Bugün" +#: frmmain.rs_webpconvertto +msgid "" +"WebP\n" +"PNG\n" +"Jpeg\n" +msgstr "" + +#: frmmain.rs_webppnglevel +msgid "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" +msgstr "" + #: frmmain.rs_wronginput msgid "Invalid input!" msgstr "Geçersiz giriş!" @@ -763,6 +778,14 @@ msgstr "Daha fazla manga sitesi için, lütfen Ayarlar->Manga siteleri'ne gidin" msgid "Regular Expression" msgstr "Düzenli İfadeler" +#: tmainform.cbwebpconvertto.text +msgid "PNG" +msgstr "" + +#: tmainform.cbwebppngcompressionlevel.text +msgid "Fastest" +msgstr "" + #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1219,6 +1242,10 @@ msgstr "Vekil ayarları" msgid "Renaming" msgstr "Yeniden adlandırma" +#: tmainform.gbwebp.caption +msgid "WebP" +msgstr "" + #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Varsayılan indirme yolunu seç:" @@ -1474,6 +1501,18 @@ msgstr "Kullanıcı adı" msgid "Save to:" msgstr "Şuraya kaydet:" +#: tmainform.lbwebpconvertto.caption +msgid "Save WebP to" +msgstr "" + +#: tmainform.lbwebpjpegquality.caption +msgid "Jpeg quality" +msgstr "" + +#: tmainform.lbwebppngcompressionlevel.caption +msgid "PNG Compression level" +msgstr "" + #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" msgid "Delete" From 500995aeb8251e6816eae5d09dfc791d3ec6f06a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 13:06:55 +0300 Subject: [PATCH 2129/2794] fix typo --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7893e67f5..c13fbacc0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5733,7 +5733,7 @@ procedure TMainForm.ApplyLanguage; rgDropTargetMode.Items.Text := RS_DropTargetModeItems; rgOptionCompress.Items.Text := RS_OptionCompress; cbWebPConvertTo.Items.Text := RS_WebPConvertTo; - cbWebPConvertTo.Items.Text := RS_WebPPNGLevel; + cbWebPPNGCompressionLevel.Items.Text := RS_WebPPNGLevel; // restore ItemIndex cbSelectManga.ItemIndex:=idxSelectManga; From 025f663d4b32dbf7537a3e49678c3ad88476e61c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 18:37:57 +0800 Subject: [PATCH 2130/2794] fix compress webp to zip/cbz (#919) --- baseunits/uBaseUnit.pas | 2 +- baseunits/uPacker.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4c27414af..838617d9b 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -360,7 +360,7 @@ interface MangaInfo_StatusOngoing = '1'; FMDSupportedOutputExt: array[0..2] of ShortString = ('.zip', '.cbz', '.pdf'); - FMDImageFileExt: array[0..2] of ShortString = ('.png', '.gif', '.jpg'); + FMDImageFileExt: array[0..3] of ShortString = ('.png', '.gif', '.jpg', '.webp'); {$ifdef windows} // MAX_PATH = 260 // MAX_PATH - 12 - 1 diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index 9555cf238..ed200cd79 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -125,7 +125,7 @@ function TPacker.Execute: Boolean; with TFileSearcher.Create do try OnFileFound := FileFound; - Search(Self.Path, '*.jpg;*.png;*.gif', False, False); + Search(Self.Path, '*.jpg;*.png;*.gif;*.webp', False, False); finally Free; end; From 9ef098e22a0ceaa5908489e5324ac64846e03b5d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 22:05:07 +0800 Subject: [PATCH 2131/2794] imginfos, add webp check stream and dimension (#919) --- baseunits/ImgInfos.pas | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/baseunits/ImgInfos.pas b/baseunits/ImgInfos.pas index c7c11baf4..e750d0d79 100644 --- a/baseunits/ImgInfos.pas +++ b/baseunits/ImgInfos.pas @@ -572,6 +572,45 @@ procedure TIFFGetImageSize(const Stream: TStream; out Width, Height: Integer); end; end; +function WEBPCheckImageStream(const Stream: TStream): Boolean; +var + Hdr: array[0..3] of Char = (#0, #0, #0, #0); +begin + Result := (Stream.Read(Hdr, 4) = 4) and (Hdr = 'RIFF') and + (Stream.Seek(4, soFromCurrent) = 8) and + (Stream.Read(Hdr, 4) = 4) and (Hdr = 'WEBP'); +end; + +procedure WEBPGetImageSize(const Stream: TStream; out Width, Height: Integer); +var + Hdr: array[0..3] of Byte = (0, 0, 0, 0); +begin + Width := 0; + Height := 0; + if (Stream.Seek(12, soFromBeginning) <> 12) or + (stream.Read(Hdr, 4) <> 4) then Exit; + // "VP8 " + if Hdr[3] = $20 then + begin + // https://tools.ietf.org/html/rfc6386#page-30 + // 7 byte + 3 byte signature 9D 01 2A + Stream.Seek(10, soFromCurrent); + Stream.Read(Width, 2); + Stream.Read(Height, 2); + end + else + // "VP8L" + if Hdr[3] = $4C then + begin + // https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification + // 4 byte + 1 byte signature 2F + Stream.Seek(5, soFromCurrent); + Stream.Read(Hdr, 4); + Width := (((Hdr[1] and $3F) shl 8) or Hdr[0]) + 1; + Height := (((Hdr[3] and $F) shl 10) or (Hdr[2] shl 2) or ((Hdr[1] and $C0) shr 6)) + 1; + end; +end; + initialization ImageHandlerMgr := TimageHandlerMgr.Create; ImageHandlerMgr.Add(TFPReaderJPEG, TFPWriterJPEG, @JPEGCheckImageStream, @JPEGGetImageSize, 'jpg'); @@ -579,6 +618,7 @@ initialization ImageHandlerMgr.Add(TFPReaderGif, TFPWriterPNG, @GIFCheckImageStream, @GIFGetImageSize, 'gif', 'png'); ImageHandlerMgr.Add(TFPReaderBMP, TFPWriterBMP, @BMPCheckImageStream, @BMPGetImageSize, 'bmp'); ImageHandlerMgr.Add(TFPReaderTiff, TFPWriterTiff, @TIFFCheckImageStream, @TIFFGetImageSize, 'tif'); + ImageHandlerMgr.Add(nil, nil, @WEBPCheckImageStream, @WEBPGetImageSize, 'webp'); finalization ImageHandlerMgr.Free; From d21e06f1063598a8a641fb0ef3dc2dd95caa4e25 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 9 Feb 2018 22:23:10 +0800 Subject: [PATCH 2132/2794] img2pdf add webp support (#919) convert to png --- baseunits/Img2Pdf.pas | 61 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index a7920f604..7ddd81ee9 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -34,7 +34,7 @@ interface uses - Classes, SysUtils, LazFileUtils, LazUTF8Classes, FPimage, ImgInfos, + Classes, SysUtils, LazFileUtils, LazUTF8Classes, FPimage, ImgInfos, MemBitmap, FPReadJPEG, FPWriteJPEG, FPReadPNG, JPEGLib, JdAPImin, JDataSrc, Jerror, zstream; @@ -98,6 +98,8 @@ TImg2PDF = class implementation +uses webp, FPWritePNG; + type { TFPReaderPNGInfo } @@ -229,9 +231,9 @@ procedure JPEGCompressToPageInfo(const PageInfo: TPageInfo); end; end; -procedure PNGToPageInfo(const PageInfo: TPageInfo); +procedure PNGToPageInfo(const PageInfo: TPageInfo; const AStream: TStream = nil); var - AFS: TFileStreamUTF8; + AFS: TStream; IMG: TFPCustomImage; RDR: TFPReaderPNGInfo; AMS: TMemoryStreamUTF8; @@ -242,13 +244,21 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); IMG := TFPMemoryImage.Create(0, 0); try try + if AStream = nil then + AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite) + else + AFS := AStream; RDR := TFPReaderPNGInfo.Create; - AFS := TFileStreamUTF8.Create(PageInfo.FileName, fmOpenRead or fmShareDenyWrite); - RDR.CheckContents(AFS); - if RDR.Header.ColorType = 3 then - IMG.UsePalette := True; - AFS.Position := 0; - IMG.LoadFromStream(AFS, RDR); + try + RDR.CheckContents(AFS); + if RDR.Header.ColorType = 3 then + IMG.UsePalette := True; + AFS.Position := 0; + IMG.LoadFromStream(AFS, RDR); + finally + if AStream = nil then + FreeAndNil(AFS); + end; PageInfo.Filter := 'FlateDecode'; PageInfo.BitsPerComponent := 8; @@ -329,13 +339,44 @@ procedure PNGToPageInfo(const PageInfo: TPageInfo); end; finally RDR.Free; - AFS.Free; end finally IMG.Free; end; end; +procedure WEBPToPageInfo(const PageInfo: TPageInfo); +var + AMS: TMemoryStreamUTF8; + MBM: TMemBitmap; + WRT: TFPWriterPNG; +begin + AMS := TMemoryStreamUTF8.Create; + try + AMS.LoadFromFile(PageInfo.FileName); + MBM := nil; + try + MBM := WebPToMemBitmap(AMS); + if Assigned(MBM) then + try + WRT := TFPWriterPNG.create; + WRT.Indexed := False; + WRT.UseAlpha := MBM.HasTransparentPixels; + WRT.CompressionLevel := clnone; + MBM.SaveToStream(AMS, WRT); + finally + WRT.Free; + end; + finally + if Assigned(MBM) then + MBM.Free; + end; + PNGToPageInfo(PageInfo, AMS); + finally + AMS.Free; + end; +end; + procedure ImageToPageInfo(const PageInfo: TPageInfo); var IMG: TFPCustomImage; From 1049ac6ed031e6c13470d758c5bb2b99b6f5b291 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 17:39:09 +0300 Subject: [PATCH 2133/2794] img2Pdf, fix load image data --- baseunits/Img2Pdf.pas | 3 +++ 1 file changed, 3 insertions(+) diff --git a/baseunits/Img2Pdf.pas b/baseunits/Img2Pdf.pas index 7ddd81ee9..63d8d1245 100644 --- a/baseunits/Img2Pdf.pas +++ b/baseunits/Img2Pdf.pas @@ -441,6 +441,9 @@ procedure TPageInfo.LoadImageData; else if Ext = 'png' then PNGToPageInfo(Self) + else + if Ext = 'webp' then + WEBPToPageInfo(Self) else ImageToPageInfo(Self); except From 9fa708d5fc089fc04ce31d6cceb2693fdb4a0b42 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 18:00:57 +0300 Subject: [PATCH 2134/2794] mainform, enlarge cbWebPPNGCompressionLevel combobox --- mangadownloader/forms/frmMain.lfm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 785d6029e..0be5641dc 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3917,7 +3917,7 @@ object MainForm: TMainForm Left = 134 Height = 23 Top = 29 - Width = 85 + Width = 100 ItemHeight = 15 ItemIndex = 1 Items.Strings = ( From 198f9f887acde1b3f1675650ab486386fbbb1921 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 18:01:58 +0300 Subject: [PATCH 2135/2794] update Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 4594b87f9..545a5cfc1 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -318,6 +318,9 @@ msgid "" "PNG\n" "Jpeg\n" msgstr "" +"WebP\n" +"PNG\n" +"Jpeg\n" #: frmmain.rs_webppnglevel msgid "" @@ -326,6 +329,10 @@ msgid "" "Default\n" "Maximum\n" msgstr "" +"Без компрессии\n" +"Скоростной\n" +"Средний\n" +"Максимальный\n" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -766,11 +773,11 @@ msgstr "Регулярное выражение (regexp)" #: tmainform.cbwebpconvertto.text msgid "PNG" -msgstr "" +msgstr "PNG" #: tmainform.cbwebppngcompressionlevel.text msgid "Fastest" -msgstr "" +msgstr "Скоростной" #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" @@ -1227,7 +1234,7 @@ msgstr "Переименовать" #: tmainform.gbwebp.caption msgid "WebP" -msgstr "" +msgstr "WebP" #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" @@ -1484,15 +1491,15 @@ msgstr "Сохранить в:" #: tmainform.lbwebpconvertto.caption msgid "Save WebP to" -msgstr "" +msgstr "Сохранить WebP как" #: tmainform.lbwebpjpegquality.caption msgid "Jpeg quality" -msgstr "" +msgstr "Качество Jpeg" #: tmainform.lbwebppngcompressionlevel.caption msgid "PNG Compression level" -msgstr "" +msgstr "Уровень компрессии PNG" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From c900066bf912725d3f9d5022cab46a1bc54ea4f3 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 18:08:31 +0300 Subject: [PATCH 2136/2794] update English localization --- mangadownloader/languages/fmd.en.po | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index f7ea8fbe4..d753e6838 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -308,6 +308,9 @@ msgid "" "PNG\n" "Jpeg\n" msgstr "" +"WebP\n" +"PNG\n" +"Jpeg\n" #: frmmain.rs_webppnglevel msgid "" @@ -316,6 +319,10 @@ msgid "" "Default\n" "Maximum\n" msgstr "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -756,11 +763,11 @@ msgstr "Regular Expression" #: tmainform.cbwebpconvertto.text msgid "PNG" -msgstr "" +msgstr "PNG" #: tmainform.cbwebppngcompressionlevel.text msgid "Fastest" -msgstr "" +msgstr "Fastest" #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" @@ -1217,7 +1224,7 @@ msgstr "Renaming" #: tmainform.gbwebp.caption msgid "WebP" -msgstr "" +msgstr "WebP" #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" @@ -1474,15 +1481,15 @@ msgstr "Save to:" #: tmainform.lbwebpconvertto.caption msgid "Save WebP to" -msgstr "" +msgstr "Save WebP to" #: tmainform.lbwebpjpegquality.caption msgid "Jpeg quality" -msgstr "" +msgstr "Jpeg quality" #: tmainform.lbwebppngcompressionlevel.caption msgid "PNG Compression level" -msgstr "" +msgstr "PNG Compression level" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From b080af2257c69ea5bf4bd1e964f8f9468a838023 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Feb 2018 00:04:03 +0800 Subject: [PATCH 2137/2794] updater, fix current dir (fix #923) --- updater/uMain.pas | 54 ++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index 5cd4cabb3..e869dab72 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -90,6 +90,12 @@ procedure IncReadCount(const ACount: Int64); ProxyUser: String; ProxyPass: String; + FMD_DIR: String; + CONFIG_DIR: String; + LANGUAGES_DIR: String; + CONFIG_FILE: String; + SZA: String; + OSZA: String; const Symbols: array [0..10] of Char = @@ -97,8 +103,6 @@ procedure IncReadCount(const ACount: Int64); UA_CURL = 'curl/7.42.1'; - CONFIG_FILE = 'config/config.ini'; - resourcestring RS_InvalidURL = 'Invalid URL!'; RS_Response = 'Response'; @@ -267,7 +271,7 @@ procedure TDownloadThread.Execute; sf: Boolean = False; regx: TRegExpr; i, ctry: Cardinal; - Sza, + csza, rurl, fname, sproject, @@ -428,7 +432,7 @@ procedure TDownloadThread.Execute; (FHTTP.ResultCode >= 100) and (FHTTP.ResultCode < 300) and (FCurrentSize >= FTotalSize) then begin - fname := DirPath + DirectorySeparator + FileName; + fname := DirPath + FileName; if FileExistsUTF8(fname) then DeleteFileUTF8(fname); @@ -453,54 +457,53 @@ procedure TDownloadThread.Execute; ssl_openssl_lib.DestroySSLInterface; UpdateStatus(Format(RS_UnpackFile, [fname])); - Sza := GetCurrentDirUTF8 + DirectorySeparator + '7za.exe'; if _UpdApp and - FileExistsUTF8(GetCurrentDirUTF8 + DirectorySeparator + '7za.exe') then + FileExistsUTF8(SZA) then begin st := TStringList.Create; try - FindAllFiles(st, GetCurrentDirUTF8, '*.dbg', False); + FindAllFiles(st, FMD_DIR, '*.dbg', False); if st.Count > 0 then for i := 0 to st.Count - 1 do DeleteFileUTF8(st[i]); finally st.Free; end; - CopyFile(GetCurrentDirUTF8 + DirectorySeparator + '7za.exe', - GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe'); - Sza := GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe'; + if FileExistsUTF8(OSZA) then + DeleteFileUTF8(OSZA); + CopyFile(SZA, OSZA); + csza := OSZA; end; if Pos('.zip', LowerCase(FileName)) <> 0 then begin UZip := TUnZipper.Create; UZip.OnStartFile := @UZipOnStartFile; try - UZip.FileName := DirPath + DirectorySeparator + FileName; + UZip.FileName := DirPath + FileName; UZip.OutputPath := Dirpath; UZip.Examine; UZip.UnZipAllFiles; finally UZip.Free; - DeleteFileUTF8(DirPath + DirectorySeparator + FileName); + DeleteFileUTF8(DirPath + FileName); end; end else begin - if FileExistsUTF8(Sza) then + if FileExistsUTF8(csza) then begin - RunExternalProcess(Sza, ['x', fname, '-o' + + RunExternalProcess(csza, ['x', fname, '-o' + AnsiQuotedStr(DirPath, '"'), '-aoa'], False, True); DeleteFileUTF8(fname); end else ShowErrorMessage(RS_7zNotFound); end; - if FileExistsUTF8(GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe') then - if FileExistsUTF8(GetCurrentDirUTF8 + DirectorySeparator + '7za.exe') then - DeleteFileUTF8(GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe') + if FileExistsUTF8(OSZA) then + if FileExistsUTF8(SZA) then + DeleteFileUTF8(OSZA) else - RenameFileUTF8(GetCurrentDirUTF8 + DirectorySeparator + 'old_7za.exe', - GetCurrentDirUTF8 + DirectorySeparator + '7za.exe'); + RenameFileUTF8(OSZA, SZA); end; end; UpdateStatus(RS_Finished); @@ -534,9 +537,16 @@ procedure TfrmMain.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TfrmMain.FormCreate(Sender: TObject); begin Randomize; + FMD_DIR := CleanAndExpandDirectory(ExtractFilePath(Application.ExeName)); + CONFIG_DIR := FMD_DIR + 'config'; + LANGUAGES_DIR := FMD_DIR + 'languages'; + CONFIG_FILE := CONFIG_DIR + PathDelim + 'config.ini'; + SZA := FMD_DIR + '7za.exe'; + SZA := FMD_DIR + 'old_7za.exe'; + InitSimpleExceptionHandler; try - SimpleTranslator.LangDir := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'languages'; + SimpleTranslator.LangDir := LANGUAGES_DIR; SimpleTranslator.LangAppName := 'updater'; SimpleTranslator.CollectLanguagesFiles; InitCriticalSection(CS_ReadCount); @@ -634,9 +644,9 @@ procedure TfrmMain.FormShow(Sender: TObject); dl.URL := _URL; dl.MaxRetry := _MaxRetry; if _UpdApp then - dl.DirPath := GetCurrentDirUTF8 + dl.DirPath := FMD_DIR else - dl.DirPath := CleanAndExpandDirectory(GetCurrentDirUTF8) + 'data'; + dl.DirPath := FMD_DIR + 'data' + PathDelim; dl.Extract := _Extract; dl.Start; itMonitor.Enabled := True; From 3f8bedd9707cad524d040934f3c6662cc21ad89e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Feb 2018 00:54:12 +0800 Subject: [PATCH 2138/2794] Bump version 0.9.135.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5b46529be..5df5752c2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.135.0 (10-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.134.0...0.9.135.0 + 0.9.134.0 (08-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.133.0...0.9.134.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 671390731..fe36f74d4 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="134"/> + <RevisionNr Value="135"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 01cd6e2b2..f2b35882d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.134.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.134.0/fmd_0.9.134.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.134.0/fmd_0.9.134.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.134.0/fmd_0.9.134.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.134.0/fmd_0.9.134.0_Win64.7z +VERSION=0.9.135.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.135.0/fmd_0.9.135.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.135.0/fmd_0.9.135.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.135.0/fmd_0.9.135.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.135.0/fmd_0.9.135.0_Win64.7z From 1b4fe414bbfb829cf1388f4fd2db90c2222f8edc Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:13:16 +0300 Subject: [PATCH 2139/2794] fix download --- baseunits/modules/MangaGo.pas | 90 +++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 0f9f40134..24ed32a0a 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -4,15 +4,17 @@ interface +implementation + uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, XQueryEngineHTML, httpsendthread, BaseCrypto, synautil, Graphics, - Interfaces, Math, RegExpr, strutils, JSUnpack; - -implementation + Interfaces, Math, RegExpr, strutils, JSUnpack, syncobjs; var - deskeys: TStringList; + initstr: String; + cs: TCriticalSection; + ks: TStringList; const dirurl= '/list/directory/all/'; @@ -68,7 +70,7 @@ function GetInfo(const MangaInfo: TMangaInformation; authors := XPathString('//div[@class="manga_right"]//td/label[.="Author:"]/string-join(following-sibling::*/text(),", ")'); genres := XPathString('//div[@class="manga_right"]//td/label[.="Genre(s):"]/string-join(following-sibling::*/text(),", ")'); summary := XPathString('//div[@class="manga_summary"]/string-join(text(),codepoints-to-string(10))'); - XPathHREFAll('//table[@id="chapter_table"]//td//a', chapterLinks, chapterName); + XPathHREFAll('//table[@id="chapter_table"]//td//a[not(@style)]', chapterLinks, chapterName); InvertStrings([chapterLinks, chapterName]); finally Free; @@ -181,6 +183,30 @@ function GetIV(script: String): String; Result := GetKey(script); end; +procedure FillK(script: String); +var + rg1, rg2: TRegExpr; +begin + if ks.Count > 0 then Exit; + cs.Enter; + rg1 := TRegExpr.Create('\[\s*["'']([0-9a-f]+)["'']\s*\]\s*\=\s*["'']([a\d]+)["'']'); + rg2 := TRegExpr.Create('\w\s*\=\s*["'']([a\d]+)["'']'); + try + if ks.Count > 0 then Exit; + if rg1.Exec(script) then begin + ks.Values[rg1.Match[1]] := rg1.Match[2]; + while rg1.ExecNext do + ks.Values[rg1.Match[1]] := rg1.Match[2]; + end; + if rg2.Exec(script) then + initstr := rg2.Match[1]; + finally + rg1.Free; + rg2.Free; + cs.Leave; + end; +end; + function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; var @@ -213,25 +239,25 @@ function GetPageNumber(const DownloadThread: TDownloadThread; else s := GetString(s, ' = ''', ''';'); s := StringReplace(s, '''', '', [rfReplaceAll]); + script := XPathString('//script[contains(@src, "chapter.js")]/@src', Document); - if Pos(s, ',') = 0 then begin - script := XPathString('//script[contains(@src, "chapter.js")]/@src', Document); - Reset; - Headers.Values['Referer'] := rurl; - if GET(script) then begin - t := TStringList.Create; - try - t.LoadFromStream(Document); - script := DecryptScript(t.Text); + Reset; + Headers.Values['Referer'] := rurl; + if GET(script) then begin + t := TStringList.Create; + try + t.LoadFromStream(Document); + script := DecryptScript(t.Text); + if Pos(',', s) = 0 then s := AESDecryptCBCMD5Base64ZerosPadding(s, GetKey(script), GetIV(script)); - finally - t.Free; - end; + FillK(script); + finally + t.Free; end; end; a := s.Split([',']); - for i := 0 to cnt - 1 do + for i := 0 to Math.min(cnt - 1, Length(a) - 1) do PageLinks.Add(SeparateRight(a[i], '//')); end; end; @@ -246,16 +272,17 @@ function BeforeDownloadImage(const DownloadThread: TDownloadThread; function DeScramble(AURL: String; image: TPicture): TPicture; var - tmp: String = '18a72a69a64a13a1a43a3aa42a23a66a26a19a51a54a78a34a17a31a35a15a58a29a61a48a73a74a44a52a60a24a63a20a32a7a45a53a75a55a62a59a41a76a68a2a36a21a10a38a33a71a40a67a22a4a50a80a65a27a37a47a70a14a28a16a6a56a30a57a5a11a79a9a77a46a39a25a49a8a12'; a: TStringArray; i, size, heightnum, aint: Integer; sw, h, j, y, rxpos, py, canvasx: float; r: TPicture; rect1, rect2: TRect; + tmp: String; begin - for i := 0 to deskeys.Count - 1 do - if Pos(deskeys.Names[i], AURL) > 0 then begin - tmp := deskeys.Values[deskeys.Names[i]]; + tmp := initstr; + for i := 0 to ks.Count - 1 do + if Pos(ks.Names[i], AURL) > 0 then begin + tmp := ks.Values[ks.Names[i]]; Break; end; @@ -291,7 +318,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; Result := False; if DownloadThread = nil then Exit; if DownloadThread.FHTTP.GET(AURL) then begin - if Pos('cspiclink', LowerCase(AURL)) = 0 then begin + if (Pos('mangapicgallery.com/r/cspiclink', LowerCase(AURL))) = 0 then begin Result := True; Exit; end; @@ -326,20 +353,13 @@ procedure RegisterModule; end; initialization - deskeys := TStringList.Create; - deskeys.Values['60a2b0ed56cd458c4633d04b1b76b7e9'] := '18a72a69a64a13a1a43a3aa42a23a66a26a19a51a54a78a34a17a31a35a15a58a29a61a48a73a74a44a52a60a24a63a20a32a7a45a53a75a55a62a59a41a76a68a2a36a21a10a38a33a71a40a67a22a4a50a80a65a27a37a47a70a14a28a16a6a56a30a57a5a11a79a9a77a46a39a25a49a8a12'; - deskeys.Values['400df5e8817565e28b2e141c533ed7db'] := '61a74a10a45a3a37a72a22a57a39a25a56a52a29a70a60a67a41a63a55a27a28a43a18a5a9a8a40a17a48a44a79a38a47a32a73a4a6a13a34a33a49a2a42a50a76a54a36a35a14a58a7a69a46a16a30a21a11aa51a53a77a26a31a1a19a20a80a24a62a68a59a66a75a12a64a78a71a15a65a23'; - deskeys.Values['84ba0d8098f405b14f4dbbcc04c93bac'] := '61a26a35a16a55a10a72a37a2a60a66a65a33a44a7a28a70a62a32a56a30a40a58a15a74a47aa36a78a75a11a6a77a67a39a23a9a31a64a59a13a24a80a14a38a45a21a63a19a51a17a34a50a46a5a29a73a8a57a69a48a68a49a71a41a12a52a18a79a76a54a42a22a4a1a3a53a20a25a43a27'; - deskeys.Values['56665708741979f716e5bd64bf733c33'] := '23a7a41a48a57a27a69a36a76a62a40a75a26a2a51a6a10a65a43a24a1aa20a71a28a30a13a38a79a78a72a14a49a55a56a58a25a70a12a80a3a66a11a39a42a17a15a54a45a34a74a31a8a61a46a73a63a22a64a19a77a50a9a59a37a68a52a18a32a16a33a60a67a21a44a53a5a35a4a29a47'; - deskeys.Values['a67e15ed870fe4aab0a502478a5c720f'] := '8a12a59a52a24a13a37a21a55a56a41a71a65a43a40a66a11a79a67a44a33a20a72a2a31a42a29a34a58a60a27a48a28a15a35a51a76a80a0a63a69a53a39a46a64a50a75a1a57a9a62a74a18a16a73a14a17a6a19a61a23a38a10a3a32a26a36a54a4a30a45a47a70a22a7a68a49a77a5a25a78'; - deskeys.Values['b6a2f75185754b691e4dfe50f84db57c'] := '47a63a76a58a37a4a56a21a1a48a62a2a36a44a34a42a23a9a60a72a11a74a70a20a77a16a15a35a69a0a55a46a24a6a32a75a68a43a41a78a31a71a52a33a67a25a80a30a5a28a40a65a39a14a29a64a3a53a49a59a12a66a38a27a79a45a18a22a8a61a50a17a51a10a26a13a57a19a7a54a73'; - deskeys.Values['db99689c5a26a09d126c7089aedc0d86'] := '57a31a46a61a55a41a26a2a39a24a75a4a45a13a23a51a15a8a64a37a72a34a12a3a79a42a80a17a62a49a19a77a48a68a78a65a14a10a29a16a20a76a38a36a54a30a53a40a33a21a44a22a32a5a1a7a70a67a58a0a71a74a43a66a6a63a35a56a73a9a27a25a59a47a52a11a50a18a28a60a69'; - deskeys.Values['37abcb7424ce8df47ccb1d2dd9144b49'] := '67a45a39a72a35a38a61a11a51a60a13a22a31a25a75a30a74a43a69a50a6a26a16a49a77a68a59a64a17a56a18a1a10a54a44a62a53a80a5a23a48a32a29a79a24a70a28a58a71a3a52a42a55a9a14a36a73a34a2a27a57a0a21a41a33a37a76a8a40a65a7a20a12a19a47a4a78a15a63a66a46'; - deskeys.Values['874b83ba76a7e783d13abc2dabc08d76'] := '26a59a42a43a4a20a61a28a12a64a37a52a2a77a34a13a46a74a70a0a44a29a73a66a55a38a69a67a62a9a63a6a54a79a21a33a8a58a40a47a71a49a22a50a57a78a56a25a17a15a36a16a48a32a5a10a14a80a24a72a76a45a3a53a23a41a60a11a65a19a27a51a68a35a31a1a75a39a30a7a18'; - deskeys.Values['d320d2647d70c068b89853e1a269c609'] := '77a38a53a40a16a3a20a18a63a9a24a64a50a61a45a59a27a37a8a34a11a55a79a13a47a68a12a22a46a33a1a69a52a54a31a23a62a43a0a2a35a28a57a36a51a78a70a5a32a75a41a30a4a80a19a21a42a71a49a10a56a74a17a7a25a6a14a73a29a44a48a39a60a58a15a66a67a72a65a76a26'; + cs := TCriticalSection.Create; + initstr := ''; + ks := TStringList.Create; RegisterModule; finalization - deskeys.Free(); + ks.Free; + cs.Free; end. From 11c3d8016e90ad3f6719f31e7a49b7e89b3222dc Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:18:20 +0300 Subject: [PATCH 2140/2794] baseunit, cleanup --- baseunits/uBaseUnit.pas | 46 ++++++----------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 838617d9b..5b1d067c8 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -731,10 +731,6 @@ function GetURLFromBitly(const URL: String): String; function WebPToPNGStream(const AStream: TMemoryStream; const ALevel: Tcompressionlevel = clfastest): Boolean; function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer = 80): Boolean; -// check and convert known file - -function ConvertKnownImageFormat(const AStream: TMemoryStream): Boolean; - // try to save tmemorystream to file, return the saved filename if success, otherwise return empty string function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; overload; function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String; overload; @@ -3374,35 +3370,6 @@ function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer end; end; -function IsWebPStream(const AStream: TMemoryStream): Boolean; -var - hdr: array[0..3] of Char; -begin - Result := False; - AStream.Position := 0; - if AStream.Read(hdr, 4) = 4 then - begin - if hdr = 'RIFF' then - begin - AStream.Seek(4, soFromCurrent); - if AStream.Read(hdr, 4) = 4 then - begin - if hdr = 'WEBP' then - Result := True; - end; - end; - end; -end; - -function ConvertKnownImageFormat(const AStream: TMemoryStream): Boolean; -begin - Result := False; - // webp - if IsWebPStream(AStream) then - Result := WebPToPNGStream(AStream); - //Result := WebPToJpegStream(AStream); -end; - function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt): String; var p, f: String; @@ -3413,14 +3380,13 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag if Stream.Size = 0 then Exit; p := CorrectPathSys(Path); if ForceDirectoriesUTF8(p) then begin - if IsWebPStream(Stream) then + f := GetImageStreamExt(Stream); + if f = 'webp' then case OptionWebPConvertTo of - 0: f := 'webp'; - 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionWebPPNGLevel)) then f := 'png'; - 2: if WebPToJpegStream(Stream, OptionWebPJpegQuality) then f := 'jpg'; - end - else - f := GetImageStreamExt(Stream); + 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionWebPPNGLevel)) then f := 'png' else f := ''; + 2: if WebPToJpegStream(Stream, OptionWebPJpegQuality) then f := 'jpg' else f := ''; + end; + if f = '' then Exit; f := p + FileName + '.' + f; if FileExistsUTF8(f) then DeleteFileUTF8(f); From 89c1b0e0c185a77629aef62cc87f203c2bfa068b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:40:29 +0300 Subject: [PATCH 2141/2794] remove MangaWorksFansub (not working) --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 921a34187..9f1a1e52f 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MangaWorksFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 2b567d1a9..6e0e8b459 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -199,7 +199,6 @@ function Init() AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') AddWebsiteModule('DejameProbar', 'http://dejameprobar.es') AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com') - AddWebsiteModule('MangaWorksFansub', 'http://lector.mangaworksfansub.net') AddWebsiteModule('MasterPieceScans', 'http://reader.manga2me.net') AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com') AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net') From b3d36cfdd532a1a6b39c8ad363aacf8e42d32a8c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:41:16 +0300 Subject: [PATCH 2142/2794] remove MasterPieceScans (not working) --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 9f1a1e52f..16badfc98 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MasterPieceScans,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 6e0e8b459..74a9866c9 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -199,7 +199,6 @@ function Init() AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') AddWebsiteModule('DejameProbar', 'http://dejameprobar.es') AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com') - AddWebsiteModule('MasterPieceScans', 'http://reader.manga2me.net') AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com') AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net') AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com') From db424dca0ffd32af9a8d41b1ae8b5267dad7a1c9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:41:55 +0300 Subject: [PATCH 2143/2794] remove R15TeamScanlation (not working) --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 16badfc98..6d7a5b83b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,R15TeamScanlation,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 74a9866c9..d3926a047 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -202,7 +202,6 @@ function Init() AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com') AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net') AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com') - AddWebsiteModule('R15TeamScanlation', 'http://www.r15team.com') AddWebsiteModule('SantosScan', 'http://santosfansub.com') AddWebsiteModule('SeinagiFansub', 'http://seinagi.org') AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org') From db543915696834391311b74ec8ee4beb48db2fa1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:47:09 +0300 Subject: [PATCH 2144/2794] foolslide, fix --- lua/modules/FoOlSlide.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index d3926a047..e01385169 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -46,7 +46,7 @@ end function getinfo() local lurl = MaybeFillHost(module.rooturl, url) local result = net_error - if http.get(lurl) then + if getWithCookie(lurl) then x = TXQuery.Create(http.document) mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail"]/img/@src') if mangainfo.title == '' then From 8f316318d740e406066155b6f2d102ab7f3ecfb8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:48:52 +0300 Subject: [PATCH 2145/2794] add RavensScans [SP-SC] #625 --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 6d7a5b83b..8ec5ca23d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index e01385169..f6b01484b 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -5,12 +5,14 @@ local dirurlslide = '/slide/directory/' local dirurlslideU = '/Slide/directory/' local dirurlonline = '/online/directory/' local dirurlhelvetica = '/r/directory/' +local dirurllector = '/lector/directory/' function getWithCookie(lurl) local needCookie = { ['SeinagiAdultoFansub'] = true, ['TripleSevenScan'] = true, - ['DokiFansubs'] = true + ['DokiFansubs'] = true, + ['RavensScans'] = true } if needCookie[module.website] and Pos(dirurl, lurl) then return http.post(lurl, 'adult=true') @@ -34,7 +36,8 @@ function getdirurl(website) ['SantosScan'] = dirurlslideU, ['Pzykosis666HFansub'] = dirurlonline, ['SeinagiFansub'] = dirurlonline, - ['HelveticaScans'] = dirurlhelvetica + ['HelveticaScans'] = dirurlhelvetica, + ['RavensScans'] = dirurllector } if dirs[website] ~= nil then return dirs[website] @@ -207,4 +210,5 @@ function Init() AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org') AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net') AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') + AddWebsiteModule('RavensScans', 'http://ravens-scans.com') end From 05c431907ba1005ee981b508b9ff401e679a6f16 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 20:53:00 +0300 Subject: [PATCH 2146/2794] add KirishimaFansub [SP-SC] #625 --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 8ec5ca23d..ca1fd3d2d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index f6b01484b..c4b4cc640 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -211,4 +211,5 @@ function Init() AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net') AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') AddWebsiteModule('RavensScans', 'http://ravens-scans.com') + AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com') end From 50bfe747470269630267780fc8eacf41c5f67f80 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 21:01:14 +0300 Subject: [PATCH 2147/2794] add NoraNoFansub [SP-SC] #625 --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index ca1fd3d2d..2c2d7db83 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,NoraNoFansub,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index c4b4cc640..cf699bc6d 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -37,7 +37,8 @@ function getdirurl(website) ['Pzykosis666HFansub'] = dirurlonline, ['SeinagiFansub'] = dirurlonline, ['HelveticaScans'] = dirurlhelvetica, - ['RavensScans'] = dirurllector + ['RavensScans'] = dirurllector, + ['NoraNoFansub'] = dirurllector } if dirs[website] ~= nil then return dirs[website] @@ -212,4 +213,5 @@ function Init() AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') AddWebsiteModule('RavensScans', 'http://ravens-scans.com') AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com') + AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com') end From c89267778848edd5577da92541aee915b0081a7b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 21:03:59 +0300 Subject: [PATCH 2148/2794] add YamiTenshiNoFansub [SP-SC] #625 --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 2c2d7db83..a85b323b2 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR, Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,NoraNoFansub,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub +Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,NoraNoFansub,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub,YamiTenshiNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index cf699bc6d..a647209fc 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -12,7 +12,8 @@ function getWithCookie(lurl) ['SeinagiAdultoFansub'] = true, ['TripleSevenScan'] = true, ['DokiFansubs'] = true, - ['RavensScans'] = true + ['RavensScans'] = true, + ['YamiTenshiNoFansub'] = true } if needCookie[module.website] and Pos(dirurl, lurl) then return http.post(lurl, 'adult=true') @@ -214,4 +215,5 @@ function Init() AddWebsiteModule('RavensScans', 'http://ravens-scans.com') AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com') AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com') + AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com') end From d4477794ac947a7c1bd6ad5e5edc12bb01299390 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Feb 2018 21:33:46 +0300 Subject: [PATCH 2149/2794] add Mangavy [ID] #874 --- baseunits/modules/MangaShiro.pas | 1 + config/mangalist.ini | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas index 65d80d951..dbd708fe8 100644 --- a/baseunits/modules/MangaShiro.pas +++ b/baseunits/modules/MangaShiro.pas @@ -89,6 +89,7 @@ procedure RegisterModule; AddWebsiteModule('MangaShiro', 'http://mangashiro.net'); AddWebsiteModule('Subapics', 'http://subapics.com'); AddWebsiteModule('MangaKita', 'http://www.mangakita.net'); + AddWebsiteModule('Mangavy', 'https://mangavy.com'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index a85b323b2..e9de5e2e6 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga German=MangaTube,MeinManga,NineMangaDE,WieManga -Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,PecintaKomik,Subapics +Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics Malaysian-Indonesian=I-Komik Polish=Manga-Lib_PL Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas From 59157e5c3358a789ab51283046c3e9dc52776587 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Fri, 9 Feb 2018 23:44:32 +0300 Subject: [PATCH 2150/2794] Update Turkish localization Translated latest WebP changes. --- mangadownloader/languages/fmd.tr_TR.po | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 2d4e738d1..5baefae5d 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: \n" +"Project-Id-Version: Free Manga Downloader 0.9.135\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: Tmp341 <tmp341@gmail.com>\n" @@ -322,6 +322,9 @@ msgid "" "PNG\n" "Jpeg\n" msgstr "" +"WebP\n" +"PNG\n" +"Jpeg\n" #: frmmain.rs_webppnglevel msgid "" @@ -330,6 +333,10 @@ msgid "" "Default\n" "Maximum\n" msgstr "" +"Hiçbiri\n" +"En hızlı\n" +"Varsayılan\n" +"Maksimum\n" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -780,11 +787,11 @@ msgstr "Düzenli İfadeler" #: tmainform.cbwebpconvertto.text msgid "PNG" -msgstr "" +msgstr "PNG" #: tmainform.cbwebppngcompressionlevel.text msgid "Fastest" -msgstr "" +msgstr "En hızlı" #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" @@ -1244,7 +1251,7 @@ msgstr "Yeniden adlandırma" #: tmainform.gbwebp.caption msgid "WebP" -msgstr "" +msgstr "WebP" #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" @@ -1503,15 +1510,15 @@ msgstr "Şuraya kaydet:" #: tmainform.lbwebpconvertto.caption msgid "Save WebP to" -msgstr "" +msgstr "WebP'yi şuraya kaydet" #: tmainform.lbwebpjpegquality.caption msgid "Jpeg quality" -msgstr "" +msgstr "JPEG kalitesi" #: tmainform.lbwebppngcompressionlevel.caption msgid "PNG Compression level" -msgstr "" +msgstr "PNG Sıkıştırma seviyesi" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From e1651151de12358c84840fb993e8e6d00dfa9d8f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Feb 2018 08:53:42 +0800 Subject: [PATCH 2151/2794] failed webp convert should keep it as(save to) webp --- baseunits/uBaseUnit.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 5b1d067c8..4ce6876e1 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3383,8 +3383,8 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag f := GetImageStreamExt(Stream); if f = 'webp' then case OptionWebPConvertTo of - 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionWebPPNGLevel)) then f := 'png' else f := ''; - 2: if WebPToJpegStream(Stream, OptionWebPJpegQuality) then f := 'jpg' else f := ''; + 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionWebPPNGLevel)) then f := 'png'; + 2: if WebPToJpegStream(Stream, OptionWebPJpegQuality) then f := 'jpg'; end; if f = '' then Exit; From da32b7495bf79d49e7daa58b9c1b5b161e91545f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Feb 2018 09:46:49 +0800 Subject: [PATCH 2152/2794] imginfos, webp get vp8x dimension and some check --- baseunits/ImgInfos.pas | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/baseunits/ImgInfos.pas b/baseunits/ImgInfos.pas index e750d0d79..13bff4399 100644 --- a/baseunits/ImgInfos.pas +++ b/baseunits/ImgInfos.pas @@ -589,14 +589,19 @@ procedure WEBPGetImageSize(const Stream: TStream; out Width, Height: Integer); Height := 0; if (Stream.Seek(12, soFromBeginning) <> 12) or (stream.Read(Hdr, 4) <> 4) then Exit; + if not ((Hdr[0] = $56) and (Hdr[1] = $50) and (Hdr[2] = $38)) then Exit; // "VP8 " if Hdr[3] = $20 then begin // https://tools.ietf.org/html/rfc6386#page-30 // 7 byte + 3 byte signature 9D 01 2A - Stream.Seek(10, soFromCurrent); + Stream.Seek(7, soFromCurrent); + Stream.Read(Hdr, 3); + if not ((Hdr[0] = $9D) and (Hdr[1] = $01) and (Hdr[2] = $2A)) then Exit; Stream.Read(Width, 2); Stream.Read(Height, 2); + Width := LEtoN(Width); + Height := LEtoN(Height); end else // "VP8L" @@ -604,10 +609,23 @@ procedure WEBPGetImageSize(const Stream: TStream; out Width, Height: Integer); begin // https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification // 4 byte + 1 byte signature 2F - Stream.Seek(5, soFromCurrent); + Stream.Seek(4, soFromCurrent); + Stream.Read(Hdr, 1); + if Hdr[0] <> $2F then Exit; Stream.Read(Hdr, 4); Width := (((Hdr[1] and $3F) shl 8) or Hdr[0]) + 1; Height := (((Hdr[3] and $F) shl 10) or (Hdr[2] shl 2) or ((Hdr[1] and $C0) shr 6)) + 1; + end + else + // "VP8X" + if Hdr[3] = $58 then + begin + // https://developers.google.com/speed/webp/docs/riff_container#extended_file_format + Stream.Seek(8, soFromCurrent); + Stream.Read(Width, 3); + Stream.Read(Height, 3); + Width := LEtoN(Width) + 1; + Height := LEtoN(Height) + 1; end; end; From 68390f60f4914d5777eb94d22e29210531dd7cdf Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 10 Feb 2018 10:15:21 +0800 Subject: [PATCH 2153/2794] cleanup unused codes --- .../MangaLib_PL/chapter_page_number.inc | 72 -------- baseunits/includes/MangaLib_PL/image_url.inc | 62 ------- .../MangaLib_PL/manga_information.inc | 162 ------------------ .../includes/MangaLib_PL/names_and_links.inc | 33 ---- baseunits/uBaseUnit.pas | 88 ++++------ baseunits/uData.pas | 14 +- baseunits/uDownloadsManager.pas | 10 -- 7 files changed, 32 insertions(+), 409 deletions(-) delete mode 100644 baseunits/includes/MangaLib_PL/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaLib_PL/image_url.inc delete mode 100644 baseunits/includes/MangaLib_PL/manga_information.inc delete mode 100644 baseunits/includes/MangaLib_PL/names_and_links.inc diff --git a/baseunits/includes/MangaLib_PL/chapter_page_number.inc b/baseunits/includes/MangaLib_PL/chapter_page_number.inc deleted file mode 100644 index 5728b425f..000000000 --- a/baseunits/includes/MangaLib_PL/chapter_page_number.inc +++ /dev/null @@ -1,72 +0,0 @@ - function GetMangaLib_PLPageNumber: Boolean; - var - s: String; - i: Cardinal = 0; - l: TStringList; - cf: Boolean = False; - isExtractPage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGALIB_PL_ID, URL)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - //check confirm - if l.Count > 0 then - begin - for i := 0 to l.Count - 1 do - begin - if (Pos('<form ', l[i]) > 0) and - (Pos('name="confirm_', l[i]) > 0) then - begin - if (Length(URL) > 1) and - (URL[1] = '/') then - s := Copy(URL, 2, Length(URL) - 1) - else - s := URL; - s := FillMangaSiteHost(MANGALIB_PL_ID, '/page/' + GetVal(l[i], 'name') + - '?backlink=' + s); - cf := True; - Break; - end; - end; - if cf then - begin - MANGALIB_PL_COOKIES := FHTTP.Cookies.Text; - l.Clear; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - end; - end; - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Task.Container.PageNumber := 0; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select ', parse[i]) > 0) and - (Pos('class="ch_page"', parse[i]) > 0) then - isExtractPage := True; - if isExtractPage and - (Pos('</select', parse[i]) > 0) then - begin - isExtractPage := False; - Break; - end; - if isExtractPage and - (Pos('<option ', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaLib_PL/image_url.inc b/baseunits/includes/MangaLib_PL/image_url.inc deleted file mode 100644 index 684cbde99..000000000 --- a/baseunits/includes/MangaLib_PL/image_url.inc +++ /dev/null @@ -1,62 +0,0 @@ - function GetMangaLib_PLImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - cf: Boolean = False; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGALIB_PL_ID, URL) + ',' + IntToStr(WorkId + 1); - - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - //check confirm - if l.Count > 0 then - begin - for i := 0 to l.Count - 1 do - begin - if (Pos('<form ', l[i]) > 0) and - (Pos('name="confirm_', l[i]) > 0) then - begin - if (Length(URL) > 1) and - (URL[1] = '/') then - s := Copy(URL, 2, Length(URL) - 1) - else - s := URL; - s := FillMangaSiteHost(MANGALIB_PL_ID, '/page/' + - GetVal(l[i], 'name') + '?backlink=' + s); - cf := True; - Break; - end; - end; - if cf then - begin - MANGALIB_PL_COOKIES := FHTTP.Cookies.Text; - l.Clear; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - end; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img ', parse[i]) > 0) and - (Pos('id="img_curr"', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaLib_PL/manga_information.inc b/baseunits/includes/MangaLib_PL/manga_information.inc deleted file mode 100644 index 6a686adfb..000000000 --- a/baseunits/includes/MangaLib_PL/manga_information.inc +++ /dev/null @@ -1,162 +0,0 @@ - function GetMangaLib_PLInfoFromURL: Byte; - var - s: String; - i, j: Cardinal; - cf: Boolean = False; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGALIB_PL_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGALIB_PL_ID, AURL); - s := mangaInfo.url; - - if not GetPage(TObject(Source), s, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //check confirm - if Source.Count > 0 then - begin - for i := 0 to Source.Count - 1 do - begin - if (Pos('<form ', Source[i]) > 0) and - (Pos('name="confirm_', Source[i]) > 0) then - begin - if (Length(AURL) > 1) and - (AURL[1] = '/') then - s := Copy(AURL, 2, Length(AURL) - 1) - else - s := AURL; - s := WebsiteRoots[MANGALIB_PL_ID, 1] + '/page/' + - GetVal(Source[i], 'name') + '?backlink=' + s; - cf := True; - Break; - end; - end; - if cf then - begin - MANGALIB_PL_COOKIES := FHTTP.Cookies.Text; - Source.Clear; - if not GetPage(TObject(Source), s, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - end; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - - //get infos - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - //get cover - if Pos('itemprop="image"', parse[i]) > 0 then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //get title - if (Pos('<strong', parse[i]) > 0) and - (Pos('itemprop="name"', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - - //get author - if (Pos('<td', parse[i]) > 0) and - (Pos('itemprop="author"', parse[i]) > 0) then - mangaInfo.authors := - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 4])))); - - //get artist - if (Pos('<td', parse[i]) > 0) and - (Pos('itemprop="illustrator"', parse[i]) > 0) then - mangaInfo.artists := - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 4])))); - - //get summary - if Pos('itemprop="description"', parse[i]) > 0 then - mangaInfo.summary := - Trim(BreaksString(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - - //get status - if Pos('Status:', parse[i]) > 0 then - if Pos('</th', parse[i + 1]) > 0 then - if Pos('trwa', parse[i + 4]) > 0 then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - - //get genres - if Pos('Kategorie:', parse[i]) > 0 then - if Pos('</th', parse[i + 1]) > 0 then - isExtractGenres := True; - if isExtractGenres and - (Pos('</tr', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres then - begin - if Pos('<a ', parse[i]) > 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))) - else - mangaInfo.genres := - Trim(mangaInfo.genres + ', ' + - Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - - //get chapters - if (Pos('<table ', parse[i]) > 0) and - (Pos('class="chapters_list"', parse[i]) > 0) then - isExtractChapter := True; - if Pos('</tbody', parse[i]) > 0 then - isExtractChapter := False; - if isExtractChapter then - begin - if (Pos('<a ', parse[i]) > 0) and - (Pos('/manga/online/', parse[i]) > 0) then - if Pos('<tr', parse[i - 3]) > 0 then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MANGALIB_PL_ID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(EncodeURL(s)); - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1])))); - mangaInfo.chapterName.Add(s); - end; - end; - end; - end; - - // invert chapters - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaLib_PL/names_and_links.inc b/baseunits/includes/MangaLib_PL/names_and_links.inc deleted file mode 100644 index ee71c4dad..000000000 --- a/baseunits/includes/MangaLib_PL/names_and_links.inc +++ /dev/null @@ -1,33 +0,0 @@ - function MangaLib_PLGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGALIB_PL_ID, 1] + - MANGALIB_PL_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('itemprop="name"', parse[i]) > 0) then - begin - Result := NO_ERROR; - ALinks.Add(StringReplace(GetVal(parse[i - 1], 'href'), - WebsiteRoots[MANGALIB_PL_ID, 1], '', [rfIgnoreCase])); - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); - end; - end; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 4ce6876e1..8d5e297fc 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -229,38 +229,36 @@ interface // common regex to split host/url REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - OURMANGA_ID = 1; - VNSHARING_ID = 2; - TRUYEN18_ID = 3; - TURKCRAFT_ID = 4; - STARKANA_ID = 5; - ESMANGAHERE_ID = 6; - ANIMEEXTREMIST_ID = 7; - S2SCAN_ID = 8; - CENTRALDEMANGAS_ID = 10; - EGSCANS_ID = 11; - ANIMESTORY_ID = 13; - LECTUREENLIGNE_ID = 14; - SCANMANGA_ID = 15; - KIVMANGA_ID = 17; - MEINMANGA_ID = 18; - MANGASPROJECT_ID = 19; - MANGAREADER_POR_ID = 20; - JAPANSHIN_ID = 21; - MANGALIB_PL_ID = 23; - ONEMANGA_ID = 24; - MANGATOWN_ID = 25; - MANGAOKU_ID = 26; - IKOMIK_ID = 27; - NHENTAI_ID = 28; - UNIXMANGA_ID = 29; - EXTREMEMANGAS_ID = 30; - MANGAHOST_ID = 31; - MANGAKU_ID = 32; - DYNASTYSCANS_ID = 34; - - WebsiteRoots: array [0..34] of array [0..1] of String = ( - ('', ''), + OURMANGA_ID = 0; + VNSHARING_ID = 1; + TRUYEN18_ID = 2; + TURKCRAFT_ID = 3; + STARKANA_ID = 4; + ESMANGAHERE_ID = 5; + ANIMEEXTREMIST_ID = 6; + S2SCAN_ID = 7; + CENTRALDEMANGAS_ID = 8; + EGSCANS_ID = 9; + ANIMESTORY_ID = 10; + LECTUREENLIGNE_ID = 11; + SCANMANGA_ID = 12; + KIVMANGA_ID = 13; + MEINMANGA_ID = 14; + MANGASPROJECT_ID = 15; + MANGAREADER_POR_ID = 16; + JAPANSHIN_ID = 17; + ONEMANGA_ID = 18; + MANGATOWN_ID = 19; + MANGAOKU_ID = 20; + IKOMIK_ID = 21; + NHENTAI_ID = 22; + UNIXMANGA_ID = 23; + EXTREMEMANGAS_ID = 24; + MANGAHOST_ID = 25; + MANGAKU_ID = 26; + DYNASTYSCANS_ID = 27; + + WebsiteRoots: array [0..27] of array [0..1] of String = ( ('OurManga', 'http://www.ourmanga.com'), ('VnSharing', 'http://truyen.vnsharing.net'), ('Truyen18', 'http://www.truyen18.org'), @@ -269,21 +267,16 @@ interface ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), ('S2Scans', 'http://reader.s2smanga.com'), - ('', ''), ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), - ('', ''), ('AnimeStory', 'http://www.anime-story.com'), ('Lecture-En-Ligne', 'http://www.lecture-en-ligne.com'), ('ScanManga', 'http://www.scan-manga.com'), - ('', ''), ('KivManga', 'http://www.kivmanga.com'), ('MeinManga', 'http://www.meinmanga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), ('Japan-Shin', 'http://www.japan-shin.com'), - ('', ''), - ('', ''), ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), ('MangaOku', 'http://www.mangaoku.net'), @@ -293,7 +286,6 @@ interface ('ExtremeMangas', 'http://www.extrememangas.com'), ('MangaHost', 'http://br.mangahost.com'), ('MangaKu', 'http://mangaku.web.id'), - ('', ''), ('Dynasty-Scans', 'http://dynasty-scans.com') ); @@ -388,8 +380,6 @@ interface // Sites var BROWSER_INVERT: Boolean = False; - MANGALIB_PL_COOKIES: String; - //------------------------------------------ Genre: array [0..37] of String; @@ -3173,24 +3163,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; if Pos(WebsiteRoots[MEINMANGA_ID, 1], URL) > 0 then HTTPHeader.Values['Accept-Charset'] := ' utf8' else - if Pos(WebsiteRoots[MANGALIB_PL_ID, 1], URL) > 0 then - begin - if MANGALIB_PL_COOKIES <> '' then - HTTP.Cookies.Text := MANGALIB_PL_COOKIES; - if (Pos('/page/confirm_', URL) > 0) then - begin - s := ReplaceRegExpr('^.*/confirm_(.+)\?backlink.*$', URL, '$1', True) + '=1'; - meth := 'POST'; - HTTP.Document.Clear; - HTTP.Document.Position := 0; - HTTP.Document.Write(PChar(s)^, Length(s)); - HTTP.Protocol := '1.1'; - HTTP.MimeType := 'application/x-www-form-urlencoded'; - HTTPHeader.Values['Referer'] := ' ' + URL; - HTTPHeader.Values['Accept'] := ' text/html'; - end; - end - else if (Pos('imgmega.com/', URL) > 0) then begin s := ReplaceRegExpr('^.*\w+\.\w+/(\w+)/.*$', URL, '$1', True); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index d269f1b86..b9a00ebfd 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -915,11 +915,9 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/JapanShin/names_and_links.inc} - {$I includes/MangaLib_PL/names_and_links.inc} - {$I includes/OneManga/names_and_links.inc} - {$I includes/MangaTown/names_and_links.inc} + {$I includes/MangaTown/names_and_links.inc} {$I includes/MangaOku/names_and_links.inc} @@ -997,9 +995,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = JAPANSHIN_ID then Result := JapanShinGetNamesAndLinks else - if MangaSiteID = MANGALIB_PL_ID then - Result := MangaLib_PLGetNamesAndLinks - else if MangaSiteID = ONEMANGA_ID then Result := OneMangaGetNamesAndLinks else @@ -1086,11 +1081,9 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/JapanShin/manga_information.inc} - {$I includes/MangaLib_PL/manga_information.inc} - {$I includes/OneManga/manga_information.inc} - {$I includes/MangaTown/manga_information.inc} + {$I includes/MangaTown/manga_information.inc} {$I includes/MangaOku/manga_information.inc} @@ -1184,9 +1177,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinInfoFromURL else - if MangaSiteID = MANGALIB_PL_ID then - Result := GetMangaLib_PLInfoFromURL - else if MangaSiteID = ONEMANGA_ID then Result := GetOneMangaInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 635097d22..fc122015d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -430,8 +430,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/JapanShin/chapter_page_number.inc} - {$I includes/MangaLib_PL/chapter_page_number.inc} - {$I includes/OneManga/chapter_page_number.inc} {$I includes/MangaTown/chapter_page_number.inc} @@ -490,9 +488,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinPageNumber else - if Task.Container.MangaSiteID = MANGALIB_PL_ID then - Result := GetMangaLib_PLPageNumber - else if Task.Container.MangaSiteID = ONEMANGA_ID then Result := GetOneMangaPageNumber else @@ -559,8 +554,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/JapanShin/image_url.inc} - {$I includes/MangaLib_PL/image_url.inc} - {$I includes/OneManga/image_url.inc} {$I includes/MangaTown/image_url.inc} @@ -624,9 +617,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = JAPANSHIN_ID then Result := GetJapanShinImageURL else - if Task.Container.MangaSiteID = MANGALIB_PL_ID then - Result := GetMangaLib_PLImageURL - else if Task.Container.MangaSiteID = ONEMANGA_ID then Result := GetOneMangaImageURL else From 911ac94e4c19e91e385026a8c801cff064d95511 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 10 Feb 2018 08:36:51 +0300 Subject: [PATCH 2154/2794] remove non-working sites OurManga Truyen18 Starkana ESMangaHere Lecture-En-Ligne KivManga MeinManga OneManga JapanShin I-Komik UnixManga ExtremeMangas --- .../includes/EGScans/names_and_links.inc | 3 - .../EsMangaHere/chapter_page_number.inc | 31 ---- baseunits/includes/EsMangaHere/image_url.inc | 37 ---- .../EsMangaHere/manga_information.inc | 119 ------------ .../includes/EsMangaHere/names_and_links.inc | 35 ---- .../ExtremeMangas/chapter_page_number.inc | 44 ----- .../ExtremeMangas/manga_information.inc | 83 --------- .../ExtremeMangas/names_and_links.inc | 51 ------ .../includes/IKomik/chapter_page_number.inc | 37 ---- .../includes/IKomik/directory_page_number.inc | 35 ---- baseunits/includes/IKomik/image_url.inc | 48 ----- .../includes/IKomik/manga_information.inc | 88 --------- baseunits/includes/IKomik/names_and_links.inc | 34 ---- .../includes/Kivmanga/chapter_page_number.inc | 33 ---- baseunits/includes/Kivmanga/image_url.inc | 32 ---- .../includes/Kivmanga/manga_information.inc | 78 -------- .../includes/Kivmanga/names_and_links.inc | 37 ---- .../LectureEnLigne/chapter_page_number.inc | 37 ---- .../LectureEnLigne/directory_page_number.inc | 43 ----- .../includes/LectureEnLigne/image_url.inc | 32 ---- .../LectureEnLigne/manga_information.inc | 111 ------------ .../LectureEnLigne/names_and_links.inc | 43 ----- .../MeinManga/chapter_page_number.inc | 37 ---- baseunits/includes/MeinManga/image_url.inc | 88 --------- .../includes/MeinManga/manga_information.inc | 169 ------------------ .../includes/MeinManga/names_and_links.inc | 39 ---- .../includes/OneManga/chapter_page_number.inc | 37 ---- .../OneManga/directory_page_number.inc | 34 ---- baseunits/includes/OneManga/image_url.inc | 30 ---- .../includes/OneManga/manga_information.inc | 97 ---------- .../includes/OneManga/names_and_links.inc | 36 ---- .../includes/S2Scans/chapter_page_number.inc | 30 ---- .../S2Scans/directory_page_number.inc | 33 ---- .../includes/S2Scans/manga_information.inc | 74 -------- .../includes/S2Scans/names_and_links.inc | 35 ---- .../includes/Starkana/chapter_page_number.inc | 32 ---- baseunits/includes/Starkana/image_url.inc | 29 --- .../includes/Starkana/manga_information.inc | 93 ---------- .../includes/Starkana/names_and_links.inc | 34 ---- .../UnixManga/chapter_page_number.inc | 32 ---- baseunits/includes/UnixManga/image_url.inc | 37 ---- .../includes/UnixManga/manga_information.inc | 52 ------ .../includes/UnixManga/names_and_links.inc | 33 ---- baseunits/uBaseUnit.pas | 97 ++-------- baseunits/uData.pas | 135 -------------- baseunits/uDownloadsManager.pas | 101 ----------- config/mangalist.ini | 14 +- 47 files changed, 25 insertions(+), 2494 deletions(-) delete mode 100644 baseunits/includes/EsMangaHere/chapter_page_number.inc delete mode 100644 baseunits/includes/EsMangaHere/image_url.inc delete mode 100644 baseunits/includes/EsMangaHere/manga_information.inc delete mode 100644 baseunits/includes/EsMangaHere/names_and_links.inc delete mode 100644 baseunits/includes/ExtremeMangas/chapter_page_number.inc delete mode 100644 baseunits/includes/ExtremeMangas/manga_information.inc delete mode 100644 baseunits/includes/ExtremeMangas/names_and_links.inc delete mode 100644 baseunits/includes/IKomik/chapter_page_number.inc delete mode 100644 baseunits/includes/IKomik/directory_page_number.inc delete mode 100644 baseunits/includes/IKomik/image_url.inc delete mode 100644 baseunits/includes/IKomik/manga_information.inc delete mode 100644 baseunits/includes/IKomik/names_and_links.inc delete mode 100644 baseunits/includes/Kivmanga/chapter_page_number.inc delete mode 100644 baseunits/includes/Kivmanga/image_url.inc delete mode 100644 baseunits/includes/Kivmanga/manga_information.inc delete mode 100644 baseunits/includes/Kivmanga/names_and_links.inc delete mode 100644 baseunits/includes/LectureEnLigne/chapter_page_number.inc delete mode 100644 baseunits/includes/LectureEnLigne/directory_page_number.inc delete mode 100644 baseunits/includes/LectureEnLigne/image_url.inc delete mode 100644 baseunits/includes/LectureEnLigne/manga_information.inc delete mode 100644 baseunits/includes/LectureEnLigne/names_and_links.inc delete mode 100644 baseunits/includes/MeinManga/chapter_page_number.inc delete mode 100644 baseunits/includes/MeinManga/image_url.inc delete mode 100644 baseunits/includes/MeinManga/manga_information.inc delete mode 100644 baseunits/includes/MeinManga/names_and_links.inc delete mode 100644 baseunits/includes/OneManga/chapter_page_number.inc delete mode 100644 baseunits/includes/OneManga/directory_page_number.inc delete mode 100644 baseunits/includes/OneManga/image_url.inc delete mode 100644 baseunits/includes/OneManga/manga_information.inc delete mode 100644 baseunits/includes/OneManga/names_and_links.inc delete mode 100644 baseunits/includes/S2Scans/chapter_page_number.inc delete mode 100644 baseunits/includes/S2Scans/directory_page_number.inc delete mode 100644 baseunits/includes/S2Scans/manga_information.inc delete mode 100644 baseunits/includes/S2Scans/names_and_links.inc delete mode 100644 baseunits/includes/Starkana/chapter_page_number.inc delete mode 100644 baseunits/includes/Starkana/image_url.inc delete mode 100644 baseunits/includes/Starkana/manga_information.inc delete mode 100644 baseunits/includes/Starkana/names_and_links.inc delete mode 100644 baseunits/includes/UnixManga/chapter_page_number.inc delete mode 100644 baseunits/includes/UnixManga/image_url.inc delete mode 100644 baseunits/includes/UnixManga/manga_information.inc delete mode 100644 baseunits/includes/UnixManga/names_and_links.inc diff --git a/baseunits/includes/EGScans/names_and_links.inc b/baseunits/includes/EGScans/names_and_links.inc index 5d64bc4b1..31a545ae1 100644 --- a/baseunits/includes/EGScans/names_and_links.inc +++ b/baseunits/includes/EGScans/names_and_links.inc @@ -30,9 +30,6 @@ Result := NO_ERROR; s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); ANames.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetVal(parse[i], - 'value="'), - WebsiteRoots[S2SCAN_ID, 1], '', []); ALinks.Add(s); end; if Pos('<select name="manga"', parse[i]) > 0 then diff --git a/baseunits/includes/EsMangaHere/chapter_page_number.inc b/baseunits/includes/EsMangaHere/chapter_page_number.inc deleted file mode 100644 index ce5f886f7..000000000 --- a/baseunits/includes/EsMangaHere/chapter_page_number.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetEsMangaHerePageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(ESMANGAHERE_ID, URL), - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := parse.Count - 1 downto 4 do - begin - if Pos('</select>', parse[i]) > 0 then - begin - Task.Container.PageNumber := - StrToInt(TrimLeft(TrimRight(parse[i - 3]))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/EsMangaHere/image_url.inc b/baseunits/includes/EsMangaHere/image_url.inc deleted file mode 100644 index fcf9796a9..000000000 --- a/baseunits/includes/EsMangaHere/image_url.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetEsMangaHereImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - if WorkId > 0 then - Result := GetPage(TObject(l), - FillMangaSiteHost(ESMANGAHERE_ID, URL) + - IntToStr(WorkId + 1) + '.html', - Task.Container.manager.retryConnect) - else - Result := GetPage(TObject(l), - WebsiteRoots[ESMANGAHERE_ID, 1] + URL, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="read_img"', parse[i]) <> 0) then - begin - Task.Container.PageLinks[WorkId] := - GetVal(parse[i + 6], 'src'); - parse.Free; - l.Free; - Exit; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/EsMangaHere/manga_information.inc b/baseunits/includes/EsMangaHere/manga_information.inc deleted file mode 100644 index 220021eaa..000000000 --- a/baseunits/includes/EsMangaHere/manga_information.inc +++ /dev/null @@ -1,119 +0,0 @@ - function GetEsMangaHereInfoFromURL: Byte; - var - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[ESMANGAHERE_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ESMANGAHERE_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i + 1], 'Manga - Leer ', - ' manga en Español'); - - // get cover link - if GetTagName(parse[i]) = 'img' then - if (GetVal(parse[i], 'class') = 'img') then - mangaInfo.coverLink := - GetVal(parse[i], 'src'); - - // get summary - if (Pos('id="show"', parse[i])) <> 0 then - begin - parse[i + 1] := StringFilter(parse[i + 1]); - parse[i + 1] := StringReplace(parse[i + 1], #10, '\n', [rfReplaceAll]); - parse[i + 1] := StringReplace(parse[i + 1], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse[i + 1]; - end; - - // get chapter name and links - if (GetTagName(parse[i]) = 'a') and - (GetVal(parse[i], 'class') = 'color_0077') and - (Pos('/manga/', GetVal(parse[i], - 'href')) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[ESMANGAHERE_ID, 1], '', [rfReplaceAll])); - parse[i + 1] := StringReplace(parse[i + 1], #10, '', [rfReplaceAll]); - parse[i + 1] := StringReplace(parse[i + 1], #13, '', [rfReplaceAll]); - parse[i + 1] := TrimLeft(parse[i + 1]); - parse[i + 1] := TrimRight(parse[i + 1]); - mangaInfo.chapterName.Add( - StringFilter(TrimRight(RemoveSymbols(parse[i + 1])))); - end; - - // get authors - if (Pos('Autor(s):', parse[i]) <> 0) then - mangaInfo.authors := parse[i + 3]; - - // get artists - if (Pos('Artist(s):', parse[i]) <> 0) then - mangaInfo.artists := parse[i + 3]; - - // get genres - if (Pos('Género(s):', parse[i]) <> 0) then - begin - mangaInfo.genres := ''; - for j := 0 to 37 do - if Pos(LowerCase(defaultGenres[j]), LowerCase(parse[i + 2])) <> 0 then - mangaInfo.genres := mangaInfo.genres + (defaultGenres[j] + ', '); - end; - - { // get status - if (Pos('Status:', parse[i])<>0) then - begin - if Pos('Ongoing', parse[i+2])<>0 then - mangaInfo.status:= '1' // ongoing - else - mangaInfo.status:= '0'; // completed - end; } - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterName.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterName.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - - // Delete 'latest' chapter because it isnt exist - { if (mangaInfo.status = '1') AND (mangainfo.ChapterName.Count > 0) then - begin - Dec(mangaInfo.numChapter); - mangainfo.ChapterName.Delete(mangainfo.ChapterName.Count-1); - mangainfo.chapterLinks.Delete(mangainfo.chapterLinks.Count-1); - end; } - Result := NO_ERROR; - end; diff --git a/baseunits/includes/EsMangaHere/names_and_links.inc b/baseunits/includes/EsMangaHere/names_and_links.inc deleted file mode 100644 index 62c83a6d4..000000000 --- a/baseunits/includes/EsMangaHere/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function EsMangaHereGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ESMANGAHERE_ID, 1] + - ESMANGAHERE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('manga_info', parse[i]) <> 0 then - begin - Result := NO_ERROR; - ANames.Add(StringFilter(GetString(parse[i], 'rel="', '" href'))); - ALinks.Add(StringReplace(GetString(parse[i], 'href="', '">'), - WebsiteRoots[ESMANGAHERE_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/ExtremeMangas/chapter_page_number.inc b/baseunits/includes/ExtremeMangas/chapter_page_number.inc deleted file mode 100644 index e1918ed1c..000000000 --- a/baseunits/includes/ExtremeMangas/chapter_page_number.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetExtremeMangasPageNumber: Boolean; - var - i, j: Integer; - l: TStringList; - s: String; - //isExtractPageNumber: Boolean = False; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(EXTREMEMANGAS_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - - l.Text := FixHTMLTagQuote(l.Text); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('addpage(', parse[i]) > 0) then - begin - l.Clear; - if ExtractStrings([','], [], PChar(Trim(parse[i])), l) > 0 then - for j := l.Count - 1 downto 0 do - if (Pos('addpage(', l[j]) = 0) or (Pos('/extrememangas.gif', l[j]) > 0) then - l.Delete(j) - else - l[j] := Trim(TrimChar(StringReplace(l[j], 'addpage(', '', [rfIgnoreCase]), [',', ''''])); - Task.Container.PageLinks.AddStrings(l); - Task.Container.PageNumber := Task.Container.PageLinks.Count; - Break; - end; - end; - - end; - l.Free; - parse.Free; - end; diff --git a/baseunits/includes/ExtremeMangas/manga_information.inc b/baseunits/includes/ExtremeMangas/manga_information.inc deleted file mode 100644 index a39a2c8c9..000000000 --- a/baseunits/includes/ExtremeMangas/manga_information.inc +++ /dev/null @@ -1,83 +0,0 @@ - function GetExtremeMangasInfoFromURL: Byte; - var - i: Integer; - isExtractChapters: Boolean = False; - regxp: TRegExpr; - begin - mangaInfo.website := WebsiteRoots[EXTREMEMANGAS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(EXTREMEMANGAS_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //replace ' with " - Source.Text := FixHTMLTagQuote(Source.Text); - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.coverLink := ''; - mangaInfo.title := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - mangaInfo.status := '1'; - - regxp := TRegExpr.Create; - regxp.ModifierI := True; - for i := 0 to parse.Count - 1 do - begin - //cover - if i + 1 < parse.Count - 1 then - if (Pos('imageanchor="1"', parse[i]) > 0) and (Pos('<img', parse[i + 1]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 1], 'src'); - - //title - if i + 3 < parse.Count - 1 then - if Pos('class="post-title entry-title"', parse[i]) > 0 then - begin - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 3])))); - regxp.Expression := '\smang..?s$'; mangaInfo.title := Trim(regxp.Replace(mangaInfo.title, '', False)); - end; - - //sinopsis - if i + 3 < parse.Count - 1 then - if (Pos('<img border="0"', parse[i]) > 0) and (Pos('<', parse[i + 3]) = 0) then - mangaInfo.summary := Trim(BreaksString(HTMLEntitiesFilter(StringFilter( - Trim(parse[i + 3]))))); - - //chapters - if Pos('class="post-body entry-content"', parse[i]) > 0 then - isExtractChapters := True; - if isExtractChapters and (Pos('class="post-footer"', parse[i]) > 0) then - isExtractChapters := False; - if (i + 1 < parse.Count - 1) then - if isExtractChapters and (Pos('<a', parse[i]) > 0) then - begin - regxp.Expression := '-\d+\.html?'; - if (regxp.Exec(parse[i])) then - begin - Inc(mangaInfo.numChapter); - s := Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[EXTREMEMANGAS_ID, 1], '', [rfIgnoreCase])); - regxp.Expression := '^https?://.*\.com/'; s := Trim(regxp.Replace(s, '', False)); - mangaInfo.chapterLinks.Add(s); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - end; - end; - regxp.Free; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/ExtremeMangas/names_and_links.inc b/baseunits/includes/ExtremeMangas/names_and_links.inc deleted file mode 100644 index d45e714df..000000000 --- a/baseunits/includes/ExtremeMangas/names_and_links.inc +++ /dev/null @@ -1,51 +0,0 @@ - function ExtremeMangasNamesAndLinks: Byte; - var - i: Integer; - s: String; - isExtractNames: Boolean = False; - regxp: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[EXTREMEMANGAS_ID, 1] + EXTREMEMANGAS_BROWSER; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Source.Text := FixHTMLTagQuote(Source.Text); - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - - regxp := TRegExpr.Create; - regxp.ModifierI := True; - regxp.Expression := '^https?://.*\.com/'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<div', parse[i]) > 0) and (Pos('id="content"', parse[i]) > 0) then - isExtractNames := True; - if isExtractNames and (Pos('<center', parse[i]) > 0) then - begin - isExtractNames := False; - Break; - end; - if i + 1 < parse.Count - 1 then - if isExtractNames and (Pos('<a', parse[i]) > 0) then - begin - Result := NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - s := Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[EXTREMEMANGAS_ID, 1], '', [rfIgnoreCase])); - s := Trim(regxp.Replace(s, '/', False)); - ALinks.Add(s); - end; - end; - regxp.Free; - end; diff --git a/baseunits/includes/IKomik/chapter_page_number.inc b/baseunits/includes/IKomik/chapter_page_number.inc deleted file mode 100644 index 33b3bf20f..000000000 --- a/baseunits/includes/IKomik/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetIKomikPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isExtractPage: Boolean = False; - s: String; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(IKOMIK_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('class="cbo_wp_manga_page"', parse[i]) > 0) then - isExtractPage := True; - if isExtractPage and (Pos('</select', parse[i]) > 0) then - begin - isExtractPage := False; - Break; - end; - if isExtractPage and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/IKomik/directory_page_number.inc b/baseunits/includes/IKomik/directory_page_number.inc deleted file mode 100644 index 803bcc794..000000000 --- a/baseunits/includes/IKomik/directory_page_number.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetIKomikDirectoryPageNumber: Byte; - var - i: Integer; - begin - APage := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[IKOMIK_ID, 1] + IKOMIK_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if i + 1 < parse.Count - 1 then - if (Pos('/page-', parse[i]) > 0) and (Pos('last', parse[i + 1]) > 0) then - begin - Result := NO_ERROR; - APage := StrToIntDef(ReplaceRegExpr('^.*\/page-(\d+)\/.*$', GetVal(parse[i], 'href'), '$1', True), 1); - Break; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/IKomik/image_url.inc b/baseunits/includes/IKomik/image_url.inc deleted file mode 100644 index 1192ef5b5..000000000 --- a/baseunits/includes/IKomik/image_url.inc +++ /dev/null @@ -1,48 +0,0 @@ - function GetIKomikImageURL: Boolean; - var - i, j: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(IKOMIK_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - s := s + IntToStr(QWord(WorkId) + 1); - Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<div', parse[i]) > 0) and (Pos('style="overflow', parse[i]) > 0) then - begin - for j := i + 1 to parse.Count - 1 do - begin - if Pos('<img', parse[j]) > 0 then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[j], 'src'); - Break; - end; - end; - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/IKomik/manga_information.inc b/baseunits/includes/IKomik/manga_information.inc deleted file mode 100644 index b1a0fe870..000000000 --- a/baseunits/includes/IKomik/manga_information.inc +++ /dev/null @@ -1,88 +0,0 @@ - function GetIKomikInfoFromURL: Byte; - var - s: String; - i: Integer; - begin - mangaInfo.website := WebsiteRoots[IKOMIK_ID, 0]; - mangaInfo.url := FillMangaSiteHost(IKOMIK_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //title - if (i + 1 < parse.Count - 1) then - if (Pos('<h1', parse[i]) > 0) and (Pos('class="title"', parse[i]) > 0) then - mangaInfo.title := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - - //cover - if (i + 2 < parse.Count - 1) then - if (Pos('class="cover_area"', parse[i]) > 0) and (Pos('<img', parse[i + 2]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - //authors - if (i + 2 < parse.Count - 1) then - if (Pos('Author', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - s := TrimLeftChar(parse[i + 2], [':']); - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(s)))); - mangaInfo.authors := s; - end; - - //category/genre - if (i + 2 < parse.Count - 1) then - if (Pos('Category', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - s := TrimLeftChar(parse[i + 2], [':']); - s := Trim(HTMLEntitiesFilter(StringFilter(Trim(s)))); - mangaInfo.genres := s; - end; - - //status - if (i + 2 < parse.Count - 1) then - if (Pos('Status', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - if Pos('Completed', parse[i + 2]) > 0 then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - end; - - //chapters - if (i + 1 < parse.Count - 1) then - if (Pos('class="list"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[IKOMIK_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - end; - - if mangaInfo.chapterName.Count > 1 then - begin - // invert chapter - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/IKomik/names_and_links.inc b/baseunits/includes/IKomik/names_and_links.inc deleted file mode 100644 index b2ce7d193..000000000 --- a/baseunits/includes/IKomik/names_and_links.inc +++ /dev/null @@ -1,34 +0,0 @@ - function IKomikNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[IKOMIK_ID, 1] + IKOMIK_BROWSER + - 'page-' + IntToStr(StrToInt(AURL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="list"', parse[i]) > 0) and (Pos('<a', parse[i]) > 0) then - begin - Result := NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[IKOMIK_ID, 1], '', [rfIgnoreCase])); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/Kivmanga/chapter_page_number.inc b/baseunits/includes/Kivmanga/chapter_page_number.inc deleted file mode 100644 index 67f6fd11d..000000000 --- a/baseunits/includes/Kivmanga/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetKivmangaPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Next Page"', parse[i]) > 0) then - begin - s := parse[i - 6]; - Task.container.PageNumber := StrToInt(GetString(s, '"', '"')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Kivmanga/image_url.inc b/baseunits/includes/Kivmanga/image_url.inc deleted file mode 100644 index eef9068be..000000000 --- a/baseunits/includes/Kivmanga/image_url.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetKivmangaImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(KIVMANGA_ID, URL) + '/' + IntToStr(WorkId + 1)); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse[i]) > 0) then - begin - s := WebsiteRoots[KIVMANGA_ID, 1] + KIVMANGA_BROWSER + - GetVal(parse[i], 'src'); - Task.Container.PageLinks[WorkId] := EncodeURL(s); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Kivmanga/manga_information.inc b/baseunits/includes/Kivmanga/manga_information.inc deleted file mode 100644 index 6f43af877..000000000 --- a/baseunits/includes/Kivmanga/manga_information.inc +++ /dev/null @@ -1,78 +0,0 @@ - function GetKivmangaInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(KIVMANGA_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.website := WebsiteRoots[KIVMANGA_ID, 0]; - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('<title>', parse[i]) > 0) then - mangaInfo.title := TrimLeft(TrimRight(GetString(parse[i + 1], - 'Read Free Manga Online - ', '-'))); - - if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := AURL + '/' + GetVal(parse[i], 'value'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - - if (isExtractChapter) and - (Pos('</select>', parse[i]) > 0) then - begin - isExtractChapter := False; - Break; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Kivmanga/names_and_links.inc b/baseunits/includes/Kivmanga/names_and_links.inc deleted file mode 100644 index 48a6655db..000000000 --- a/baseunits/includes/Kivmanga/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function KivmangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[KIVMANGA_ID, 1], 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('option value="', parse[i]) > 0) and - (Pos('value="0"', parse[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - ANames.Add(HTMLEntitiesFilter(s)); - s := '/' + GetVal(parse[i], 'value'); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/LectureEnLigne/chapter_page_number.inc b/baseunits/includes/LectureEnLigne/chapter_page_number.inc deleted file mode 100644 index 9b35ab332..000000000 --- a/baseunits/includes/LectureEnLigne/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetLectureEnLignePageNumber: Boolean; - var - s: string; - i: Integer; - l: TStringList; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(LECTUREENLIGNE_ID, URL)); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/1.html'; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'select') and - (GetVal(parse[i], 'class') = 'pages') then - isGetPageNumber := True; - if isGetPageNumber and (GetTagName(parse[i]) = '/select') then - Break; - if isGetPageNumber and (GetTagName(parse[i]) = 'option') then - Inc(Task.Container.PageNumber); - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/LectureEnLigne/directory_page_number.inc b/baseunits/includes/LectureEnLigne/directory_page_number.inc deleted file mode 100644 index 8f79eea7d..000000000 --- a/baseunits/includes/LectureEnLigne/directory_page_number.inc +++ /dev/null @@ -1,43 +0,0 @@ - function GetLectureEnLigneDirectoryPageNumber: Byte; - var - i, p: Cardinal; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + - LECTUREENLIGNE_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - APage := 0; - regx := TRegExpr.Create; - regx.Expression := '^.*\?page=liste.*ordre=.*p=(\d+)\".*$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('href="', parse[i]) > 0) and - (Pos('?page=liste', parse[i]) > 0) then - begin - Result := NO_ERROR; - p := StrToIntDef(regx.Replace(parse[i], '$1', True), 0); - if p > APage then - APage := p; - end; - end; - regx.Free; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/LectureEnLigne/image_url.inc b/baseunits/includes/LectureEnLigne/image_url.inc deleted file mode 100644 index 3628e31e0..000000000 --- a/baseunits/includes/LectureEnLigne/image_url.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GeLectureEnligneImageURL: Boolean; - var - s: string; - i: Integer; - l: TStringList; - begin - s := DecodeUrl(FillMangaSiteHost(LECTUREENLIGNE_ID, URL)); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - s := s + '/' + IntToStr(WorkId + 1) + '.html'; - l := TStringList.Create; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'id') = 'image') then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/LectureEnLigne/manga_information.inc b/baseunits/includes/LectureEnLigne/manga_information.inc deleted file mode 100644 index d0352ac18..000000000 --- a/baseunits/includes/LectureEnLigne/manga_information.inc +++ /dev/null @@ -1,111 +0,0 @@ - function GetLectureEnLigneInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Integer; - begin - mangaInfo.url := FillMangaSiteHost(LECTUREENLIGNE_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[LECTUREENLIGNE_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class="imagemanga"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(WebsiteRoots[LECTUREENLIGNE_ID, 1] + - '/' + GetVal(parse[i], 'src')); - - // get title - if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - TrimRight(HTMLEntitiesFilter(GetString('~!@' + parse[i + 1], - '~!@', ' - Lecture-en-ligne.com')))); - - // get chapter name and links - if (Pos('class="table"', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - '../..', '', []); - if Pos('.htm', s) > 0 then - s := ReplaceRegExpr('/\d+\.html?$', s, '', False); - mangaInfo.chapterLinks.Add(s); - j := i - 1; - while (Pos('<', parse[j]) > 0) or (Trim(parse[j]) = '') do - Dec(j); - s := RemoveSymbols(Trim(parse[j])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class=''comments''', parse[i]) > 0) then - isExtractChapter := False; - - // get summary - if (Pos('Résumé :', parse[i]) <> 0) and - (Pos('<p', parse[i - 1]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 3 < parse.Count) and (Pos('Auteur :', parse[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); - - // get artists - if (i + 3 < parse.Count) and (Pos('Dessinateur :', parse[i]) <> 0) then - mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); - - // get genres - if (i + 3 < parse.Count) and (Pos('Genres :', parse[i]) <> 0) then - mangaInfo.genres := StringFilter(TrimLeft(TrimRight(parse[i + 3]))); - - - // get status - if (i + 5 < parse.Count) and (Pos('Statut :', parse[i]) <> 0) then - begin - if (Pos('Terminé', parse[i + 3]) <> 0) or - (Pos('one shot', parse[i + 3]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/LectureEnLigne/names_and_links.inc b/baseunits/includes/LectureEnLigne/names_and_links.inc deleted file mode 100644 index f49147983..000000000 --- a/baseunits/includes/LectureEnLigne/names_and_links.inc +++ /dev/null @@ -1,43 +0,0 @@ - function LectureEnLigneGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[LECTUREENLIGNE_ID, 1] + - LECTUREENLIGNE_BROWSER + '&p=' + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - { - if (Pos('option value=', parse[i]) > 0) then - begin - Result:= NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i+1])))); - ALinks.Add(StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[LECTUREENLIGNE_ID,1], '', [])); - end; - } - if (Pos('class="infoImages"', parse[i]) > 0) and - (Pos('href="', parse[i]) > 0) then - begin - Result := NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1])))); - ALinks.Add('/' + GetVal(parse[i], 'href')); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/MeinManga/chapter_page_number.inc b/baseunits/includes/MeinManga/chapter_page_number.inc deleted file mode 100644 index de0ee9c06..000000000 --- a/baseunits/includes/MeinManga/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetMeinMangaPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MEINMANGA_ID, URL)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - Task.container.PageLinks.Clear; - for i := parse.Count - 1 downto 0 do - begin - if (Pos('</select>', parse[i]) > 0) then - begin - Task.Container.PageNumber := - StrToInt(TrimLeft(TrimRight(parse[i - 3]))); - Break; - end; - end; - if Task.Container.PageNumber > 0 then - for i := 0 to Task.Container.PageNumber - 1 do - Task.Container.pageLinks.Add(s + IntToStr(i + 1) + '.html'); - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MeinManga/image_url.inc b/baseunits/includes/MeinManga/image_url.inc deleted file mode 100644 index fecf331cc..000000000 --- a/baseunits/includes/MeinManga/image_url.inc +++ /dev/null @@ -1,88 +0,0 @@ - function GetMeinMangaImageURL: Boolean; - var - s, imageName: String; - prefix: Cardinal = 0; - i: Cardinal; - l: TStringList; - Parser: THTMLParser; - begin - s := Task.Container.DownloadInfo.SaveTo + - '/' + Task.Container.ChapterName[ - Task.Container.CurrentDownloadChapterPtr] + '/' + - Format('%.3d', [WorkId + 1]); - // Check to see if a file with similar name was already exist. If so then we - // skip the download process. - if (FileExistsUTF8(s + '.jpg')) or - (FileExistsUTF8(s + '.png')) or - (FileExistsUTF8(s + '.gif')) then - begin - Result := True; - Exit; - end; - - l := TStringList.Create; - - FHTTP.Headers.Values['Accept'] := ' image/png,image/*;q=0.8,*/*;q=0.5'; - FHTTP.Headers.Values['Accept-Encoding'] := ' gzip, deflate'; - FHTTP.Headers.Values['Accept-Language'] := ' en-US,en;q=0.5'; - - Result := GetPage(TObject(l), - Task.Container.PageLinks[WorkId], - Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - FHTTP.Free; - Exit; - end; - - parse := TStringList.Create; - try - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="pic_fragment"', parse[i]) > 0) then - begin - FHTTP.Clear; - - SaveImage( - Task.Container.MangaSiteID, - GetVal(parse[i], 'src'), - Task.CurrentWorkingDir, - Format('%.3d', [WorkId + 1]) + - '_' + IntToStr(prefix), - Task.Container.Manager.retryConnect); - - Inc(prefix); - - if Self.Terminated then - begin - l.Free; - parse.Free; - //HTTP.Free; - Exit; - end; - end; - end; - // If prefix = 2 then there're 2 separate images. We need to merge them into one ... - if prefix = 2 then - begin - imageName := Format('%.3d', [WorkId + 1]); - Merge2Image( - Task.CurrentWorkingDir, - imageName + '_' + IntToStr(prefix - 2) + '.jpg', - imageName + '_' + IntToStr(prefix - 1) + '.jpg', - imageName + '.jpg'); - end; // Merging. - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MeinManga/manga_information.inc b/baseunits/includes/MeinManga/manga_information.inc deleted file mode 100644 index b536323b0..000000000 --- a/baseunits/includes/MeinManga/manga_information.inc +++ /dev/null @@ -1,169 +0,0 @@ - function GetMeinMangaInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - i, j: Cardinal; - URLs: TStringList; - - procedure GetChapterTitleAndChapterURL; - begin - if (Pos('/default/images/book.jpg', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse[i + 2], 'href="', '">'), - WebsiteRoots[MEINMANGA_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(Trim(parse[i + 3])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - end; - - begin - mangaInfo.url := FillMangaSiteHost(MEINMANGA_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[MEINMANGA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - URLs := TStringList.Create; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (GetTagName(parse[i]) = 'img') and - (Pos('/pic/logo/', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); - - // get summary - if (Pos('Kurzbeschreibung', parse[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 6; - while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do - begin - s := parse[j]; - if (s[1] <> '<') then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get title - if (mangaInfo.title = '') and (Pos('class="chrname"', parse[i]) <> 0) then - mangaInfo.title := Trim(StringFilter(parse[i + 1])); - - // Get chapter title and AURL - GetChapterTitleAndChapterURL; - - // get authors - if (i + 4 < parse.Count) and - (Pos('Autor', parse[i]) <> 0) and - (Pos('valign="top"', parse[i - 1]) <> 0) then - mangaInfo.authors := Trim(parse[i + 4]); - - // get artists - if (i + 4 < parse.Count) and - (Pos('Zeichner', parse[i]) <> 0) and - (Pos('valign="top"', parse[i - 1]) <> 0) then - mangaInfo.artists := Trim(parse[i + 4]); - - // get genres - if (i + 4 < parse.Count) and - (Pos('Genre', parse[i]) <> 0) and - (Pos('valign="top"', parse[i - 1]) <> 0) then - mangaInfo.genres := Trim(parse[i + 4]); - - // get status - if (i + 4 < parse.Count) and - (Pos('Status', parse[i]) <> 0) and - (Pos('valign="top"', parse[i - 1]) <> 0) then - begin - if Pos('ongoing', parse[i + 4]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - - // Get number of page - if (URLs.Count = 0) and - (Pos('class="gotopage"', parse[i]) <> 0) and - (Pos('class="hover"', parse[i + 2]) <> 0) then - begin - j := i + 3; - while (j < parse.Count) and - ((Pos('class="next"', parse[j]) = 0) and - (Pos('</div>', parse[j]) = 0)) do - begin - if (Pos('<a', parse[j]) <> 0) then - begin - URLs.Add(GetString(parse[j], 'href="', '">')); - end; - Inc(j); - end; - end; - end; - - // Repeat until we get all chapter information - if URLs.Count > 0 then - begin - for j := 0 to URLs.Count - 1 do - begin - Source := TStringList.Create; - if not GetPage(TObject(Source), URLs[j], AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - GetChapterTitleAndChapterURL; - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - URLs.Free; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MeinManga/names_and_links.inc b/baseunits/includes/MeinManga/names_and_links.inc deleted file mode 100644 index 22d309c39..000000000 --- a/baseunits/includes/MeinManga/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function MeinMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MEINMANGA_ID, 1] + - MEINMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/manga/', parse[i]) > 0) and - (Pos('<img', parse[i - 2]) > 0) then - begin - Result := NO_ERROR; - s := GetVal(parse[i], 'href'); - ALinks.Add(s); - s := StringFilter(Trim(parse[i + 1])); - s := StringReplace(s, WebsiteRoots[MEINMANGA_ID, 1], '', []); - ANames.Add(HTMLEntitiesFilter(s)); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/OneManga/chapter_page_number.inc b/baseunits/includes/OneManga/chapter_page_number.inc deleted file mode 100644 index e4a5c60b8..000000000 --- a/baseunits/includes/OneManga/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetOneMangaPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - isGetPage: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(ONEMANGA_ID, URL); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Task.Container.PageNumber := 0; - if parse.Count > 0 then - for i := 1 to parse.Count - 1 do - begin - - if (Pos('<select ', parse[i]) > 0) and - (Pos('class="cbo_wpm_pag"', parse[i]) > 0) then - isGetPage := True; - if isGetPage and (Pos('</select', parse[i]) > 0) then - begin - isGetPage := False; - Break; - end; - if isGetPage and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/OneManga/directory_page_number.inc b/baseunits/includes/OneManga/directory_page_number.inc deleted file mode 100644 index 798b8c6f6..000000000 --- a/baseunits/includes/OneManga/directory_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetOneMangaDirectoryPageNumber: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ONEMANGA_ID, 1] + - ONEMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - if Pos('Last', parse[i]) > 0 then - if (Pos('<a ', parse[i - 1]) > 0) and (Pos('</a', parse[i + 1]) > 0) then - begin - APage := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)\/$', - GetVal(parse[i - 1], 'href'), '$1', True), 1); - Result := NO_ERROR; - Break; - end; - Source.Free; - end; diff --git a/baseunits/includes/OneManga/image_url.inc b/baseunits/includes/OneManga/image_url.inc deleted file mode 100644 index 76eec9de2..000000000 --- a/baseunits/includes/OneManga/image_url.inc +++ /dev/null @@ -1,30 +0,0 @@ - function GetOneMangaImageURL: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - s := FillMangaSiteHost(ONEMANGA_ID, URL); - s := s + IntToStr(WorkId + 1) + '/'; - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if (Pos('<img ', parse[i]) > 0) and - (Pos('class="manga-page"', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/OneManga/manga_information.inc b/baseunits/includes/OneManga/manga_information.inc deleted file mode 100644 index 391928808..000000000 --- a/baseunits/includes/OneManga/manga_information.inc +++ /dev/null @@ -1,97 +0,0 @@ - function GetOneMangaInfoFromURL: Byte; - var - i: Integer; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[ONEMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ONEMANGA_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.title := ''; - mangaInfo.authors := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - //get title - if (Pos('<h1 ', parse[i]) > 0) and (Pos('class="ttl"', parse[i]) > 0) then - mangaInfo.title := Trim(parse[i + 1]); - - //get cover - if (Pos('<img ', parse[i]) > 0) and (Pos('class="cvr"', parse[i]) > 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //get authors - if Pos('Author', parse[i]) > 0 then - if Pos('</b>', parse[i + 1]) > 0 then - mangaInfo.authors := Trim(RemoveSymbols(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 2]))))); - - //get summary - if Pos('class="det"', parse[i]) > 0 then - if Pos('<p>', parse[i + 2]) > 0 then - mangaInfo.summary := Trim(BreaksString(HTMLEntitiesFilter(StringFilter(parse[i + 3])))); - - //get genres - if Pos('Category', parse[i]) > 0 then - if Pos('</b>', parse[i + 1]) > 0 then - isExtractGenres := True; - if isExtractGenres and (Pos('</p>', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('<a ', parse[i]) > 0) then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(RemoveSymbols(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(RemoveSymbols(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - - //get status - if Pos('Status', parse[i]) > 0 then - if Pos('</b>', parse[i + 1]) > 0 then - begin - if Pos('Ongoing', parse[i + 2]) > 0 then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - - //get chapters name and link - if (Pos('<ul ', parse[i]) > 0) and (Pos('class="lst"', parse[i]) > 0) then - isExtractChapter := True; - if isExtractChapter and (Pos('</ul>', parse[i]) > 0) then - isExtractChapter := False; - if isExtractChapter and - ((Pos('<a ', parse[i]) > 0) and (Pos('class="lst"', parse[i]) > 0)) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[ONEMANGA_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(Trim(RemoveSymbols(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 3])))))); - end; - end; - - //invert chapter list - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/OneManga/names_and_links.inc b/baseunits/includes/OneManga/names_and_links.inc deleted file mode 100644 index a2c8b45c6..000000000 --- a/baseunits/includes/OneManga/names_and_links.inc +++ /dev/null @@ -1,36 +0,0 @@ - function OneMangaGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ONEMANGA_ID, 1] + - ONEMANGA_BROWSER + IntToStr(StrToInt(AURL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('class="det"', parse[i]) > 0 then - if Pos('<a ', parse[i + 2]) > 0 then - begin - Result := NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 3]))))); - ALinks.Add(StringReplace(GetVal(parse[i + 2], 'href'), - WebsiteRoots[ONEMANGA_ID, 1], '', [rfIgnoreCase])); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/S2Scans/chapter_page_number.inc b/baseunits/includes/S2Scans/chapter_page_number.inc deleted file mode 100644 index af8151ae3..000000000 --- a/baseunits/includes/S2Scans/chapter_page_number.inc +++ /dev/null @@ -1,30 +0,0 @@ - function GetS2scanPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - try - Result := GetPage(TObject(l), - FillMangaSiteHost(S2SCAN_ID, URL) + 'page/1', - Task.Container.Manager.retryConnect); - - if l.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to l.Count - 1 do - begin - if Pos('var pages = [', l[i]) > 0 then - begin - s := StringReplace(l[i], 'var pages = [', '[', []); - s := Trim(TrimChar(s, [';'])); - ParseJSONArray(s, 'url', Task.Container.PageLinks); - Break; - end; - end; - end; - finally - l.Free; - end; - end; diff --git a/baseunits/includes/S2Scans/directory_page_number.inc b/baseunits/includes/S2Scans/directory_page_number.inc deleted file mode 100644 index 58e7a012d..000000000 --- a/baseunits/includes/S2Scans/directory_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetS2ScanDirectoryPageNumber: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[S2SCAN_ID, 1] + '/directory/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if Pos('Last »»', parse[i]) > 0 then - if GetTagName(parse[i - 1]) = 'a' then - begin - APage := StrToIntDef(ReplaceRegExpr( - '^.*/(\d+)/$', GetVal(parse[i - 1], 'href'), '$1', True), 1); - Break; - end; - Source.Free; - end; diff --git a/baseunits/includes/S2Scans/manga_information.inc b/baseunits/includes/S2Scans/manga_information.inc deleted file mode 100644 index 4e4a24670..000000000 --- a/baseunits/includes/S2Scans/manga_information.inc +++ /dev/null @@ -1,74 +0,0 @@ - function GetS2scanInfoFromURL: Byte; - var - i: Integer; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[S2SCAN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(S2SCAN_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - Source.Free; - - //no status = ongoing - mangaInfo.status := '1'; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - //cover - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'thumbnail') then - if GetTagName(parse[i + 2]) = 'img' then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - //title - if mangaInfo.title = '' then - if (GetTagName(parse[i]) = 'h1') and (GetVal(parse[i], 'class') = 'title') then - mangaInfo.title := parse[i + 1]; - - if GetTagName(parse[i]) = 'b' then - begin - //author - if Trim(parse[i + 1]) = 'Author' then - mangaInfo.authors := TrimLeft(TrimLeftChar(parse[i + 3], [':'])); - //artist - if Trim(parse[i + 1]) = 'Artist' then - mangaInfo.artists := TrimLeft(TrimLeftChar(parse[i + 3], [':'])); - //author - if Trim(parse[i + 1]) = 'Synopsis' then - mangaInfo.summary := TrimLeft(TrimLeftChar(parse[i + 3], [':'])); - end; - - //chapters - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'list') then - isExtractChapter := True; - if isExtractChapter then - begin - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'title') then - if GetTagName(parse[i + 1]) = 'a' then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterName.Add(GetVal(parse[i + 1], 'title')); - mangaInfo.chapterLinks.Add(GetVal(parse[i + 1], 'href')); - end; - end; - end; - - // invert chapters - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/S2Scans/names_and_links.inc b/baseunits/includes/S2Scans/names_and_links.inc deleted file mode 100644 index 0fd6e0270..000000000 --- a/baseunits/includes/S2Scans/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function S2ScanGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[S2SCAN_ID, 1] + - '/directory/' + '/' + IntToStr(StrToInt(AURL)+1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - Parser := THTMLParser.Create(PChar(Source.Text)); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - parse.Clear; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'div') and (GetVal(parse[i], 'class') = 'group') then - if GetTagName(parse[i + 5]) = 'a' then - begin - ANames.Add(GetVal(parse[i + 5], 'title')); - ALinks.Add(GetVal(parse[i + 5], 'href')); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/Starkana/chapter_page_number.inc b/baseunits/includes/Starkana/chapter_page_number.inc deleted file mode 100644 index d8be79919..000000000 --- a/baseunits/includes/Starkana/chapter_page_number.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetStarkanaPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL)), - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('id="page_switch', parse[i]) > 0) then - isGetPageNumber := True; - if isGetPageNumber and (Pos('</select', parse[i]) > 0) then - Break; - if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Starkana/image_url.inc b/baseunits/includes/Starkana/image_url.inc deleted file mode 100644 index 18bf6e1c2..000000000 --- a/baseunits/includes/Starkana/image_url.inc +++ /dev/null @@ -1,29 +0,0 @@ - function GetStarkanaImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(STARKANA_ID, URL) + '/' + IntToStr(WorkId + 1)), - Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and (Pos('class="dyn', parse[i]) > 0) and - (Pos('style="cursor: pointer', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Starkana/manga_information.inc b/baseunits/includes/Starkana/manga_information.inc deleted file mode 100644 index feecb9061..000000000 --- a/baseunits/includes/Starkana/manga_information.inc +++ /dev/null @@ -1,93 +0,0 @@ - function GetStarkanaInfoFromURL: Byte; - var - i: Integer; - isExtractGenres: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[STARKANA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(STARKANA_ID, AURL) + '?mature_confirm=1'; - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - - mangaInfo.genres := ''; - - for i := 0 to parse.Count - 1 do - begin - //cover - if (Pos('<a', parse[i]) > 0) and (Pos('class="olol', parse[i]) > 0) then - if (Pos('<img', parse[i + 1]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 1], 'src'); - - //title - if Pos('Title(s):', parse[i]) > 0 then - mangaInfo.title := CommonStringFilter(parse[i + 5]); - - //author(s) - if Pos('Author(s):', parse[i]) > 0 then - mangaInfo.authors := CommonStringFilter(parse[i + 7]); - - //artist(s) - if Pos('Artist(s):', parse[i]) > 0 then - mangaInfo.artists := CommonStringFilter(parse[i + 7]); - - //status - if Pos('Status:', parse[i]) > 0 then - if (Trim(LowerCase(parse[i + 7])) = 'ongoing') then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - - //summary - if Pos('Summary:', parse[i]) > 0 then - if Pos('valign="top"', parse[i - 2]) > 0 then - mangaInfo.summary := BreaksString(CommonStringFilter(parse[i + 7])); - - //genres - if Pos('Genres:', parse[i]) > 0 then - isExtractGenres := True; - if isExtractGenres and (Pos('</tr', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('<', parse[i]) = 0) and - (Pos('Genres:', parse[i]) = 0) then - begin - parse[i] := Trim(parse[i]); - if parse[i] = ',' then - parse[i] := ', '; - mangaInfo.genres := mangaInfo.genres + parse[i]; - end; - - //chapter(s) - if Pos('class="download-link', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); // 1, 3, 7 - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[STARKANA_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(CommonStringFilter( - Trim(parse[i + 1]) + ' ' + Trim(parse[i + 3]) + ' ' + Trim(parse[i + 7]))); - end; - end; - - //invert chapter(s) - if mangaInfo.chapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterLinks); - InvertStrings(mangaInfo.chapterName); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Starkana/names_and_links.inc b/baseunits/includes/Starkana/names_and_links.inc deleted file mode 100644 index 2f50e32e2..000000000 --- a/baseunits/includes/Starkana/names_and_links.inc +++ /dev/null @@ -1,34 +0,0 @@ - function StarkanaGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[STARKANA_ID, 1] + - STARKANA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('style="float:right;', parse[i]) > 0) then - begin - ALinks.Add(GetVal(parse[i + 2], 'href')); - ANames.Add(CommonStringFilter(parse[i + 3])); - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/includes/UnixManga/chapter_page_number.inc b/baseunits/includes/UnixManga/chapter_page_number.inc deleted file mode 100644 index bc63ba9ff..000000000 --- a/baseunits/includes/UnixManga/chapter_page_number.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetUnixMangaPageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(UNIXMANGA_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - Task.Container.PageLinks.Clear; - Task.Container.PageContainerLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="td2"', parse[i]) > 0) and (Pos('<A', parse[i]) > 0) then - Task.Container.PageContainerLinks.Add(EncodeURL(GetVal(parse[i], 'HREF'))); - end; - Task.Container.PageNumber := Task.Container.PageContainerLinks.Count; - end; - parse.Free; - end; diff --git a/baseunits/includes/UnixManga/image_url.inc b/baseunits/includes/UnixManga/image_url.inc deleted file mode 100644 index 7d515809c..000000000 --- a/baseunits/includes/UnixManga/image_url.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetUnixMangaImageURL: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := Task.Container.PageContainerLinks[WorkId]; - Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('STYLE="border', parse[i]) > 0) and (Pos('<IMG', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := Trim(GetVal(parse[i], 'SRC')); - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/UnixManga/manga_information.inc b/baseunits/includes/UnixManga/manga_information.inc deleted file mode 100644 index b09834b8e..000000000 --- a/baseunits/includes/UnixManga/manga_information.inc +++ /dev/null @@ -1,52 +0,0 @@ - function GetUnixMangaInfoFromURL: Byte; - var - i: Integer; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[UNIXMANGA_ID, 0]; - mangaInfo.url := FillMangaSiteHost(UNIXMANGA_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - for i := 0 to parse.Count - 1 do - begin - //chapters - if (Pos('<table', parse[i]) > 0) and (Pos('class="snif"', parse[i]) > 0) then - isExtractChapters := True; - if isExtractChapters and (Pos('</table', parse[i]) > 0) then - isExtractChapters := False; - if (i + 1 < parse.Count - 1) then - if isExtractChapters and (Pos('/onlinereading/', parse[i]) > 0) and - (Pos('title=', parse[i]) > 0) and (Pos('<a ', parse[i]) > 0) and - (Pos('/index.php', parse[i]) = 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[UNIXMANGA_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - end; - end; - - // invert chapters - if mangaInfo.chapterName.Count > 1 then - begin - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/UnixManga/names_and_links.inc b/baseunits/includes/UnixManga/names_and_links.inc deleted file mode 100644 index 46d944a6d..000000000 --- a/baseunits/includes/UnixManga/names_and_links.inc +++ /dev/null @@ -1,33 +0,0 @@ - function UnixMangaNamesAndLinks: Byte; - var - i: Integer; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - s := WebsiteRoots[UNIXMANGA_ID, 1] + UNIXMANGA_BROWSER; - if not GetPage(TObject(Source), s, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/onlinereading/', parse[i]) > 0) and - (Pos('title=', parse[i]) > 0) and (Pos('<a ', parse[i]) > 0) then - begin - Result := NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - ALinks.Add(Trim(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[UNIXMANGA_ID, 1], '', [rfIgnoreCase]))); - end; - end; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8d5e297fc..3479bb3e8 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -229,61 +229,35 @@ interface // common regex to split host/url REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - OURMANGA_ID = 0; - VNSHARING_ID = 1; - TRUYEN18_ID = 2; - TURKCRAFT_ID = 3; - STARKANA_ID = 4; - ESMANGAHERE_ID = 5; - ANIMEEXTREMIST_ID = 6; - S2SCAN_ID = 7; - CENTRALDEMANGAS_ID = 8; - EGSCANS_ID = 9; - ANIMESTORY_ID = 10; - LECTUREENLIGNE_ID = 11; - SCANMANGA_ID = 12; - KIVMANGA_ID = 13; - MEINMANGA_ID = 14; - MANGASPROJECT_ID = 15; - MANGAREADER_POR_ID = 16; - JAPANSHIN_ID = 17; - ONEMANGA_ID = 18; - MANGATOWN_ID = 19; - MANGAOKU_ID = 20; - IKOMIK_ID = 21; - NHENTAI_ID = 22; - UNIXMANGA_ID = 23; - EXTREMEMANGAS_ID = 24; - MANGAHOST_ID = 25; - MANGAKU_ID = 26; - DYNASTYSCANS_ID = 27; - - WebsiteRoots: array [0..27] of array [0..1] of String = ( - ('OurManga', 'http://www.ourmanga.com'), + VNSHARING_ID = 0; + TURKCRAFT_ID = 1; + ANIMEEXTREMIST_ID = 2; + CENTRALDEMANGAS_ID = 3; + EGSCANS_ID = 4; + ANIMESTORY_ID = 5; + SCANMANGA_ID = 6; + MANGASPROJECT_ID = 7; + MANGAREADER_POR_ID = 8; + MANGATOWN_ID = 9; + MANGAOKU_ID = 10; + NHENTAI_ID = 11; + MANGAHOST_ID = 12; + MANGAKU_ID = 13; + DYNASTYSCANS_ID = 14; + + WebsiteRoots: array [0..14] of array [0..1] of String = ( ('VnSharing', 'http://truyen.vnsharing.net'), - ('Truyen18', 'http://www.truyen18.org'), ('Turkcraft', 'http://turkcraft.com'), - ('Starkana', 'http://starkana.jp'), - ('ESMangaHere', 'http://es.mangahere.co'), ('AnimExtremist', 'http://www.animextremist.com'), - ('S2Scans', 'http://reader.s2smanga.com'), ('CentralDeMangas', 'http://centraldemangas.com.br'), ('EGScans', 'http://read.egscans.com'), ('AnimeStory', 'http://www.anime-story.com'), - ('Lecture-En-Ligne', 'http://www.lecture-en-ligne.com'), ('ScanManga', 'http://www.scan-manga.com'), - ('KivManga', 'http://www.kivmanga.com'), - ('MeinManga', 'http://www.meinmanga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), - ('Japan-Shin', 'http://www.japan-shin.com'), - ('OneManga', 'http://www.onemanga2.com'), ('MangaTown', 'http://www.mangatown.com'), ('MangaOku', 'http://www.mangaoku.net'), - ('I-Komik', 'http://www.i-komik.com'), ('NHentai', 'http://nhentai.net'), - ('UnixManga', 'http://unixmanga.co'), - ('ExtremeMangas', 'http://www.extrememangas.com'), ('MangaHost', 'http://br.mangahost.com'), ('MangaKu', 'http://mangaku.web.id'), ('Dynasty-Scans', 'http://dynasty-scans.com') @@ -294,15 +268,8 @@ interface VNSHARING_BROWSER = '/DanhSach'; - TRUYEN18_ROOT = 'http://www.truyen18.org'; - TRUYEN18_BROWSER = '/moi-dang/danhsach'; - TURKCRAFT_BROWSER = '/'; - STARKANA_BROWSER = '/manga/list'; - - ESMANGAHERE_BROWSER = '/mangalist/'; - ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; CENTRALDEMANGAS_BROWSER = '/mangas/list/*'; @@ -311,34 +278,16 @@ interface ANIMESTORY_BROWSER = '/mangas/'; - LECTUREENLIGNE_BROWSER = '/index.php?page=liste&ordre=titre'; - SCANMANGA_BROWSER = '/scanlation/liste_des_mangas.html'; - KIVMANGA_BROWSER = '/'; - - MEINMANGA_BROWSER = '/directory/all/'; - MANGASPROJECT_BROWSER = '/AJAX/listaMangas/all'; MANGAREADER_POR_BROWSER = '/AJAX/listaMangas/all'; - JAPANSHIN_BROWSER = '/lectureenligne/reader/list/'; - - MANGALIB_PL_BROWSER = '/manga/directory'; - - ONEMANGA_BROWSER = '/manga-list/all/any/last-added/'; - MANGATOWN_BROWSER = '/directory/'; - IKOMIK_BROWSER = '/manga-directory/'; - UNIONMANGAS_BROWSER = '/mangas'; - UNIXMANGA_BROWSER = '/onlinereading/manga-lists.html'; - - EXTREMEMANGAS_BROWSER = '/2013/04/lista-de-mangas.html'; - MANGAHOST_BROWSER = '/mangas'; DYNASTYSCANS_BROWSER: array [0..3] of String = ( @@ -1086,7 +1035,6 @@ function SitesWithSortedList(const website: String): Boolean; Exit; end; Result := SitesMemberOf(website, [ - ONEMANGA_ID, NHENTAI_ID ]); end; @@ -1119,19 +1067,13 @@ function SitesWithoutInformation(const website: String): Boolean; Result := SitesMemberOf(website, [ MANGASPROJECT_ID, TURKCRAFT_ID, - KIVMANGA_ID, - MANGAOKU_ID, - UNIXMANGA_ID + MANGAOKU_ID ]); end; function SitesWithoutReferer(const website: String): Boolean; begin Result := False; - Result := SitesMemberOf(website, [ - MEINMANGA_ID, - IKOMIK_ID - ]); end; function SitesWithSingleChapter(const website: String): Boolean; @@ -3160,9 +3102,6 @@ function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; HTTPHeader.Delete(HTTPHeader.IndexOfName('Content-Type')); end; - if Pos(WebsiteRoots[MEINMANGA_ID, 1], URL) > 0 then - HTTPHeader.Values['Accept-Charset'] := ' utf8' - else if (Pos('imgmega.com/', URL) > 0) then begin s := ReplaceRegExpr('^.*\w+\.\w+/(\w+)/.*$', URL, '$1', True); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index b9a00ebfd..75cad9c36 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -786,20 +786,10 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/VnSharing/directory_page_number.inc} - {$I includes/S2Scans/directory_page_number.inc} - - {$I includes/LectureEnLigne/directory_page_number.inc} - {$I includes/CentralDeMangas/directory_page_number.inc} - {$I includes/JapanShin/directory_page_number.inc} - - {$I includes/OneManga/directory_page_number.inc} - {$I includes/MangaTown/directory_page_number.inc} - {$I includes/IKomik/directory_page_number.inc} - {$I includes/NHentai/directory_page_number.inc} {$I includes/MangaHost/directory_page_number.inc} @@ -834,27 +824,12 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if MangaSiteID = S2SCAN_ID then - Result := GetS2ScanDirectoryPageNumber - else - if MangaSiteID = LECTUREENLIGNE_ID then - Result := GetLectureEnLigneDirectoryPageNumber - else if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasDirectoryPageNumber else - if MangaSiteID = JAPANSHIN_ID then - Result := GetJapanShinDirectoryPageNumber - else - if MangaSiteID = ONEMANGA_ID then - Result := GetOneMangaDirectoryPageNumber - else if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownDirectoryPageNumber else - if MangaSiteID = IKOMIK_ID then - Result := GetIKomikDirectoryPageNumber - else if MangaSiteID = NHENTAI_ID then Result := GetNHentaiDirectoryPageNumber else @@ -883,52 +858,30 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; Parser: THTMLParser; MangaSiteID: Integer; - {$I includes/EsMangaHere/names_and_links.inc} - {$I includes/AnimExtremist/names_and_links.inc} {$I includes/VnSharing/names_and_links.inc} {$I includes/AnimeStory/names_and_links.inc} - {$I includes/LectureEnLigne/names_and_links.inc} - {$I includes/ScanManga/names_and_links.inc} {$I includes/CentralDeMangas/names_and_links.inc} {$I includes/Turkcraft/names_and_links.inc} - {$I includes/Starkana/names_and_links.inc} - - {$I includes/S2Scans/names_and_links.inc} - {$I includes/EGScans/names_and_links.inc} - {$I includes/Kivmanga/names_and_links.inc} - - {$I includes/MeinManga/names_and_links.inc} - {$I includes/MangasPROJECT/names_and_links.inc} {$I includes/MangaREADER_POR/names_and_links.inc} - {$I includes/JapanShin/names_and_links.inc} - - {$I includes/OneManga/names_and_links.inc} - {$I includes/MangaTown/names_and_links.inc} {$I includes/MangaOku/names_and_links.inc} - {$I includes/IKomik/names_and_links.inc} - {$I includes/NHentai/names_and_links.inc} - {$I includes/UnixManga/names_and_links.inc} - - {$I includes/ExtremeMangas/names_and_links.inc} - {$I includes/MangaHost/names_and_links.inc} {$I includes/MangaKu/names_and_links.inc} @@ -950,30 +903,15 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else - if MangaSiteID = STARKANA_ID then - Result := StarkanaGetNamesAndLinks - else - if MangaSiteID = S2SCAN_ID then - Result := S2ScanGetNamesAndLinks - else if MangaSiteID = EGSCANS_ID then Result := EGScansGetNamesAndLinks else - if MangaSiteID = MEINMANGA_ID then - Result := MeinMangaGetNamesAndLinks - else - if MangaSiteID = ESMANGAHERE_ID then - Result := EsMangaHereGetNamesAndLinks - else if MangaSiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else if MangaSiteID = ANIMESTORY_ID then Result := AnimeStoryGetNamesAndLinks else - if MangaSiteID = LECTUREENLIGNE_ID then - Result := LectureEnLigneGetNamesAndLinks - else if MangaSiteID = SCANMANGA_ID then Result := ScanMangaGetNamesAndLinks else @@ -983,39 +921,21 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else - if MangaSiteID = KIVMANGA_ID then - Result := KivmangaGetNamesAndLinks - else if MangaSiteID = MANGASPROJECT_ID then Result := MangasPROJECTGetNamesAndLinks else if MangaSiteID = MANGAREADER_POR_ID then Result := MangaREADER_PORGetNamesAndLinks else - if MangaSiteID = JAPANSHIN_ID then - Result := JapanShinGetNamesAndLinks - else - if MangaSiteID = ONEMANGA_ID then - Result := OneMangaGetNamesAndLinks - else if MangaSiteID = MANGATOWN_ID then Result := MangaTownGetNamesAndLinks else if MangaSiteID = MANGAOKU_ID then Result := MangaOkuGetNamesAndLinks else - if MangaSiteID = IKOMIK_ID then - Result := IKomikNamesAndLinks - else if MangaSiteID = NHENTAI_ID then Result := NHentaiNamesAndLinks else - if MangaSiteID = UNIXMANGA_ID then - Result := UnixMangaNamesAndLinks - else - if MangaSiteID = EXTREMEMANGAS_ID then - Result := ExtremeMangasNamesAndLinks - else if MangaSiteID = MANGAHOST_ID then Result := MangaHostGetNamesAndLinks else @@ -1049,52 +969,30 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR // due to its weird designs, this will take a lot of work (and time) for it to // work property - {$I includes/EsMangaHere/manga_information.inc} - {$I includes/AnimExtremist/manga_information.inc} {$I includes/VnSharing/manga_information.inc} - {$I includes/Starkana/manga_information.inc} - - {$I includes/S2Scans/manga_information.inc} - {$I includes/EGScans/manga_information.inc} {$I includes/AnimeStory/manga_information.inc} - {$I includes/LectureEnLigne/manga_information.inc} - {$I includes/ScanManga/manga_information.inc} {$I includes/Turkcraft/manga_information.inc} {$I includes/CentralDeMangas/manga_information.inc} - {$I includes/MeinManga/manga_information.inc} - - {$I includes/KivManga/manga_information.inc} - {$I includes/MangasPROJECT/manga_information.inc} {$I includes/MangaREADER_POR/manga_information.inc} - {$I includes/JapanShin/manga_information.inc} - - {$I includes/OneManga/manga_information.inc} - {$I includes/MangaTown/manga_information.inc} {$I includes/MangaOku/manga_information.inc} - {$I includes/IKomik/manga_information.inc} - {$I includes/NHentai/manga_information.inc} - {$I includes/UnixManga/manga_information.inc} - - {$I includes/ExtremeMangas/manga_information.inc} - {$I includes/MangaHost/manga_information.inc} {$I includes/MangaKu/manga_information.inc} @@ -1132,30 +1030,15 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else - if MangaSiteID = STARKANA_ID then - Result := GetStarkanaInfoFromURL - else - if MangaSiteID = S2SCAN_ID then - Result := GetS2scanInfoFromURL - else if MangaSiteID = EGSCANS_ID then Result := GetEGScansInfoFromURL else - if MangaSiteID = MEINMANGA_ID then - Result := GetMeinMangaInfoFromURL - else - if MangaSiteID = ESMANGAHERE_ID then - Result := GetEsMangaHereInfoFromURL - else if MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else if MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryInfoFromURL else - if MangaSiteID = LECTUREENLIGNE_ID then - Result := GetLectureEnLigneInfoFromURL - else if MangaSiteID = SCANMANGA_ID then Result := GetScanMangaInfoFromURL else @@ -1165,39 +1048,21 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasInfoFromURL else - if MangaSiteID = KIVMANGA_ID then - Result := GetKivmangaInfoFromURL - else if MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTInfoFromURL else if MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORInfoFromURL else - if MangaSiteID = JAPANSHIN_ID then - Result := GetJapanShinInfoFromURL - else - if MangaSiteID = ONEMANGA_ID then - Result := GetOneMangaInfoFromURL - else if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownInfoFromURL else if MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuInfoFromURL else - if MangaSiteID = IKOMIK_ID then - Result := GetIKomikInfoFromURL - else if MangaSiteID = NHENTAI_ID then Result := GetNHentaiInfoFromURL else - if MangaSiteID = UNIXMANGA_ID then - Result := GetUnixMangaInfoFromURL - else - if MangaSiteID = EXTREMEMANGAS_ID then - Result := GetExtremeMangasInfoFromURL - else if MangaSiteID = MANGAHOST_ID then Result := GetMangaHostInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index fc122015d..d49f9c97d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -414,36 +414,14 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/EGScans/chapter_page_number.inc} - {$I includes/EsMangaHere/chapter_page_number.inc} - - {$I includes/Kivmanga/chapter_page_number.inc} - - {$I includes/MeinManga/chapter_page_number.inc} - - {$I includes/S2Scans/chapter_page_number.inc} - - {$I includes/Starkana/chapter_page_number.inc} - {$I includes/Turkcraft/chapter_page_number.inc} - {$I includes/LectureEnLigne/chapter_page_number.inc} - - {$I includes/JapanShin/chapter_page_number.inc} - - {$I includes/OneManga/chapter_page_number.inc} - {$I includes/MangaTown/chapter_page_number.inc} {$I includes/MangaOku/chapter_page_number.inc} - {$I includes/IKomik/chapter_page_number.inc} - {$I includes/NHentai/chapter_page_number.inc} - {$I includes/UnixManga/chapter_page_number.inc} - - {$I includes/ExtremeMangas/chapter_page_number.inc} - {$I includes/MangaHost/chapter_page_number.inc} {$I includes/MangaKu/chapter_page_number.inc} @@ -458,18 +436,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; Result := Modules.GetPageNumber(Self, URL, Task.Container.ModuleId) else begin - if Task.Container.MangaSiteID = STARKANA_ID then - Result := GetStarkanaPageNumber - else - if Task.Container.MangaSiteID = S2SCAN_ID then - Result := GetS2scanPageNumber - else - if Task.Container.MangaSiteID = MEINMANGA_ID then - Result := GetMeinMangaPageNumber - else - if Task.Container.MangaSiteID = ESMANGAHERE_ID then - Result := GetEsMangaHerePageNumber - else if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistPageNumber else @@ -479,36 +445,15 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftPageNumber else - if Task.Container.MangaSiteID = KIVMANGA_ID then - Result := GetKivmangaPageNumber - else - if Task.Container.MangaSiteID = LECTUREENLIGNE_ID then - Result := GetLectureEnLignePageNumber - else - if Task.Container.MangaSiteID = JAPANSHIN_ID then - Result := GetJapanShinPageNumber - else - if Task.Container.MangaSiteID = ONEMANGA_ID then - Result := GetOneMangaPageNumber - else if Task.Container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownPageNumber else if Task.Container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuPageNumber else - if Task.Container.MangaSiteID = IKOMIK_ID then - Result := GetIKomikPageNumber - else if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiPageNumber else - if Task.Container.MangaSiteID = UNIXMANGA_ID then - Result := GetUnixMangaPageNumber - else - if Task.Container.MangaSiteID = EXTREMEMANGAS_ID then - Result := GetExtremeMangasPageNumber - else if Task.Container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostPageNumber else @@ -534,38 +479,22 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/EGScans/image_url.inc} - {$I includes/EsMangaHere/image_url.inc} - - {$I includes/Kivmanga/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} {$I includes/ScanManga/image_url.inc} - {$I includes/Starkana/image_url.inc} - {$I includes/Turkcraft/image_url.inc} {$I includes/VnSharing/image_url.inc} - {$I includes/LectureEnLigne/image_url.inc} - - {$I includes/JapanShin/image_url.inc} - - {$I includes/OneManga/image_url.inc} - {$I includes/MangaTown/image_url.inc} {$I includes/MangaOku/image_url.inc} - {$I includes/IKomik/image_url.inc} - {$I includes/NHentai/image_url.inc} - {$I includes/UnixManga/image_url.inc} - {$I includes/MangaHost/image_url.inc} begin @@ -578,15 +507,9 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else - if Task.Container.MangaSiteID = STARKANA_ID then - Result := GetStarkanaImageURL - else if Task.Container.MangaSiteID = EGSCANS_ID then Result := GetEGScansImageURL else - if Task.Container.MangaSiteID = ESMANGAHERE_ID then - Result := GetEsMangaHereImageURL - else if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else @@ -602,39 +525,21 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then Result := GetCentralDeMangasImageURL else - if Task.Container.MangaSiteID = KIVMANGA_ID then - Result := GetKivmangaImageURL - else if Task.Container.MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTImageURL else if Task.Container.MangaSiteID = MANGAREADER_POR_ID then Result := GetMangaREADER_PORImageURL else - if Task.Container.MangaSiteID = LECTUREENLIGNE_ID then - Result := GeLectureEnligneImageURL - else - if Task.Container.MangaSiteID = JAPANSHIN_ID then - Result := GetJapanShinImageURL - else - if Task.Container.MangaSiteID = ONEMANGA_ID then - Result := GetOneMangaImageURL - else if Task.Container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownImageURL else if Task.Container.MangaSiteID = MANGAOKU_ID then Result := GetMangaOkuImageURL else - if Task.Container.MangaSiteID = IKOMIK_ID then - Result := GetIKomikImageURL - else if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiImageURL else - if Task.Container.MangaSiteID = UNIXMANGA_ID then - Result := GetUnixMangaImageURL - else if Task.Container.MangaSiteID = MANGAHOST_ID then Result := GetMangaHostImageURL; end; @@ -827,9 +732,6 @@ function TDownloadThread.DownloadImage: Boolean; workFilename, workURL, savedFilename: String; - - {$I includes/MeinManga/image_url.inc} - begin Result := True; @@ -870,9 +772,6 @@ function TDownloadThread.DownloadImage: Boolean; // OnDownloadImage if Modules.ModuleAvailable(Task.Container.ModuleId, MMDownloadImage) then Result := Modules.DownloadImage(Self, workURL, Task.Container.ModuleId) - else - if Task.Container.MangaSiteID = MEINMANGA_ID then - Result := GetMeinMangaImageURL else Result := FHTTP.GET(workURL); end; diff --git a/config/mangalist.ini b/config/mangalist.ini index e9de5e2e6..e8bfd202b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,18 +4,18 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,Mangaf -English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,KivManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,OneManga,ReadMangaToday,ReadComicOnline,SenManga,UnixManga,Webtoons,ReadComics,Taadd +English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree -French=AnimeStory,Japan-Shin,Japscan,Lecture-En-Ligne,ScanManga -German=MangaTube,MeinManga,NineMangaDE,WieManga +French=AnimeStory,Japan-Shin,Japscan,ScanManga +German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics -Malaysian-Indonesian=I-Komik -Polish=Manga-Lib_PL -Portugues=CentralDeMangas,ExtremeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas +Malaysian-Indonesian= +Polish= +Portugues=CentralDeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU -Spanish=AnimExtremist,ESMangaHere,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline +Spanish=AnimExtremist,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,NoraNoFansub,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub,YamiTenshiNoFansub Thai=MangaBoom Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr From cb0ee64466bcb0b34dda9999fa84c0d3e3b66b92 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 10 Feb 2018 08:40:35 +0300 Subject: [PATCH 2155/2794] move S2Scans to lua module --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index a647209fc..48c1520cf 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -13,7 +13,8 @@ function getWithCookie(lurl) ['TripleSevenScan'] = true, ['DokiFansubs'] = true, ['RavensScans'] = true, - ['YamiTenshiNoFansub'] = true + ['YamiTenshiNoFansub'] = true, + ['S2Scans'] = true } if needCookie[module.website] and Pos(dirurl, lurl) then return http.post(lurl, 'adult=true') @@ -199,6 +200,7 @@ function Init() AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org') AddWebsiteModule('ChampionScans', 'http://reader.championscans.com') AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org') + AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com') -- es-sc AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') From 1f5599cd39892417264a250b9b30ec3a44ac11f7 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Sat, 10 Feb 2018 11:29:08 +0300 Subject: [PATCH 2156/2794] Update fmd.tr_TR.po 1. Line 1127, fixed typo, made more understandable. 2. Line 1496, made a little understandable. 3. Line 2310, removed confusion. --- mangadownloader/languages/fmd.tr_TR.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 5baefae5d..1cd2ad286 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -1124,7 +1124,7 @@ msgstr "Görevi her zaman başarısız bölümlerden başlat" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" -msgstr "Kişisel demogrofi ekle, virgülle ayrılmış" +msgstr "Kişisel tür ekle, virgülle ayırarak" #: tmainform.eddownloadssearch.texthint #| msgid "Search favorites..." @@ -1493,7 +1493,7 @@ msgstr "Tip" #: tmainform.lboptionrenamedigits.caption msgid "Rename digits" -msgstr "Basamakları yeniden adlandır" +msgstr "Yeniden adlandırma basamak sayısı" #: tmainform.lboptionretryfailedtask.caption msgid "Number of retry times if task failed" @@ -2307,7 +2307,7 @@ msgstr "Tamamlanmış manga kaldırılacak:" #: ufavoritesmanager.rs_lblnewchapterfound msgid "Found %d new chapter from %d manga(s):" -msgstr "%d yeni bölüm bulundu %d manga(larından)sından:" +msgstr "%d yeni bölüm bulundu %d mangadan:" #: usilentthread.rs_silentthreadloadstatus msgid "Loading: %d/%d" From f940c0ec6fcc98c7aaf8e7185d143ee62f825965 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 10 Feb 2018 13:34:34 +0300 Subject: [PATCH 2157/2794] EGScans, move to lua module --- .../includes/EGScans/chapter_page_number.inc | 34 --------- baseunits/includes/EGScans/image_url.inc | 31 -------- .../includes/EGScans/manga_information.inc | 68 ------------------ .../includes/EGScans/names_and_links.inc | 39 ---------- baseunits/uBaseUnit.pas | 28 ++++---- baseunits/uData.pas | 10 --- baseunits/uDownloadsManager.pas | 7 -- lua/modules/EGScans.lua | 72 +++++++++++++++++++ 8 files changed, 84 insertions(+), 205 deletions(-) delete mode 100644 baseunits/includes/EGScans/chapter_page_number.inc delete mode 100644 baseunits/includes/EGScans/image_url.inc delete mode 100644 baseunits/includes/EGScans/manga_information.inc delete mode 100644 baseunits/includes/EGScans/names_and_links.inc create mode 100644 lua/modules/EGScans.lua diff --git a/baseunits/includes/EGScans/chapter_page_number.inc b/baseunits/includes/EGScans/chapter_page_number.inc deleted file mode 100644 index 1bb4d924f..000000000 --- a/baseunits/includes/EGScans/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetEGScansPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('</span>', parse[i]) > 0) then - begin - s := parse[i - 4]; - Task.Container.PageNumber := - StrToInt(TrimLeft(TrimRight(GetString(s + ' ', 'of ', ' ')))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/EGScans/image_url.inc b/baseunits/includes/EGScans/image_url.inc deleted file mode 100644 index 4fd7e57f2..000000000 --- a/baseunits/includes/EGScans/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetEGScansImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(EGSCANS_ID, URL) + '/' + IntToStr(WorkId + 1)); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - if (Pos('<img ondragstart', parse[i]) > 0) then - begin - Task.Container.PageLinks.Add(WebsiteRoots[EGSCANS_ID, 1] + - '/' + EncodeURL(GetVal(parse[i], 'src'))); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/EGScans/manga_information.inc b/baseunits/includes/EGScans/manga_information.inc deleted file mode 100644 index 4df5c0812..000000000 --- a/baseunits/includes/EGScans/manga_information.inc +++ /dev/null @@ -1,68 +0,0 @@ - function GetEGScansInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i: Cardinal; - begin - mangaInfo.website := WebsiteRoots[EGSCANS_ID, 0]; - mangaInfo.url :=FillMangaSiteHost(EGSCANS_ID, '/' + AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (not isExtractChapter) and - (Pos('<span>', parse[i]) > 0) and - (Pos('Chapter', parse[i + 1]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('</span>', parse[i]) > 0) then - isExtractChapter := False; - - // get manga name - if (mangaInfo.title = '') and (Pos('content="Read ', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i], '~!@content="Read ', - ' Manga Online"'); - - { if (isExtractChapter) AND (Pos('</select>', parse[i])>0) then - break; } - - if (isExtractChapter) and - (Pos('<option value="', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := '/' + AURL + '/' + StringReplace(GetVal(parse[i], 'value'), WebsiteRoots[EGSCANS_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/EGScans/names_and_links.inc b/baseunits/includes/EGScans/names_and_links.inc deleted file mode 100644 index 31a545ae1..000000000 --- a/baseunits/includes/EGScans/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function EGScansGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[EGSCANS_ID, 1] + - EGSCANS_BROWSER + '/' + IntToStr(StrToInt(AURL) + 1) + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('<option value="', parse[i]) > 0) and - (Pos('="0"', parse[i]) = 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - ANames.Add(HTMLEntitiesFilter(s)); - ALinks.Add(s); - end; - if Pos('<select name="manga"', parse[i]) > 0 then - Break; - end; - Source.Free; - end; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 3479bb3e8..0c3faaaa5 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -233,24 +233,22 @@ interface TURKCRAFT_ID = 1; ANIMEEXTREMIST_ID = 2; CENTRALDEMANGAS_ID = 3; - EGSCANS_ID = 4; - ANIMESTORY_ID = 5; - SCANMANGA_ID = 6; - MANGASPROJECT_ID = 7; - MANGAREADER_POR_ID = 8; - MANGATOWN_ID = 9; - MANGAOKU_ID = 10; - NHENTAI_ID = 11; - MANGAHOST_ID = 12; - MANGAKU_ID = 13; - DYNASTYSCANS_ID = 14; - - WebsiteRoots: array [0..14] of array [0..1] of String = ( + ANIMESTORY_ID = 4; + SCANMANGA_ID = 5; + MANGASPROJECT_ID = 6; + MANGAREADER_POR_ID = 7; + MANGATOWN_ID = 8; + MANGAOKU_ID = 9; + NHENTAI_ID = 10; + MANGAHOST_ID = 11; + MANGAKU_ID = 12; + DYNASTYSCANS_ID = 13; + + WebsiteRoots: array [0..13] of array [0..1] of String = ( ('VnSharing', 'http://truyen.vnsharing.net'), ('Turkcraft', 'http://turkcraft.com'), ('AnimExtremist', 'http://www.animextremist.com'), ('CentralDeMangas', 'http://centraldemangas.com.br'), - ('EGScans', 'http://read.egscans.com'), ('AnimeStory', 'http://www.anime-story.com'), ('ScanManga', 'http://www.scan-manga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), @@ -274,8 +272,6 @@ interface CENTRALDEMANGAS_BROWSER = '/mangas/list/*'; - EGSCANS_BROWSER = '/'; - ANIMESTORY_BROWSER = '/mangas/'; SCANMANGA_BROWSER = '/scanlation/liste_des_mangas.html'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 75cad9c36..4a225c133 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -870,8 +870,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/Turkcraft/names_and_links.inc} - {$I includes/EGScans/names_and_links.inc} - {$I includes/MangasPROJECT/names_and_links.inc} {$I includes/MangaREADER_POR/names_and_links.inc} @@ -903,9 +901,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks else - if MangaSiteID = EGSCANS_ID then - Result := EGScansGetNamesAndLinks - else if MangaSiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else @@ -973,8 +968,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/VnSharing/manga_information.inc} - {$I includes/EGScans/manga_information.inc} - {$I includes/AnimeStory/manga_information.inc} {$I includes/ScanManga/manga_information.inc} @@ -1030,9 +1023,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = VNSHARING_ID then Result := GetVnSharingInfoFromURL else - if MangaSiteID = EGSCANS_ID then - Result := GetEGScansInfoFromURL - else if MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index d49f9c97d..6622fe7fc 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -412,8 +412,6 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/chapter_page_number.inc} - {$I includes/EGScans/chapter_page_number.inc} - {$I includes/Turkcraft/chapter_page_number.inc} {$I includes/MangaTown/chapter_page_number.inc} @@ -477,8 +475,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/CentralDeMangas/image_url.inc} - {$I includes/EGScans/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -507,9 +503,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = VNSHARING_ID then Result := GetVnSharingImageURL else - if Task.Container.MangaSiteID = EGSCANS_ID then - Result := GetEGScansImageURL - else if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else diff --git a/lua/modules/EGScans.lua b/lua/modules/EGScans.lua new file mode 100644 index 000000000..7a6628b48 --- /dev/null +++ b/lua/modules/EGScans.lua @@ -0,0 +1,72 @@ +function getinfo() + local lurl = MaybeFillHost(module.rooturl, url) + local result = net_error + if http.get(lurl) then + local x = TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//select[@name="manga"]/option[@selected]') + end + local v = x.xpath('//select[@name="chapter"]/option') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapternames.add(v1.ToString) + mangainfo.chapterlinks.add(url .. '/' .. v1.getattribute('value')) + end + result = no_error + end + return result +end + +function taskstart() + task.pagelinks.clear() + task.pagenumber = 0 + return true +end + +function getpagenumber() + local result = false + local s = url .. '&display=webtoon' + s = MaybeFillHost(module.rooturl, s) + if http.get(s) then + local x = TXQuery.create(http.document) + local v = x.xpath('//td/a/img[@class="picture"]/@src') + for i = 1, v.count do + local v1 = v.get(i) + task.pagelinks.add(MaybeFillHost(module.rooturl, v1.toString)) + end + result = true + end + return result +end + +function getdirectorypagenumber() + page = 1 + return no_error +end + +function getnameandlink() + local result = net_error + if http.get(module.rooturl) then + local x = TXQuery.create(http.document) + local v = x.xpath('//select[@name="manga"]/option[@value!="0"]') + for i = 1, v.count do + local v1 = v.get(i) + links.add(module.rooturl .. '/' .. v1.getattribute('value')) + names.add(v1.ToString) + end + result = no_error + end + return result +end + +function Init() + local m = NewModule() + m.website = 'EGScans' + m.rooturl = 'http://read.egscans.com' + m.lastupdated = 'february, 10 2018' + m.ongetinfo = 'getinfo' + m.OnTaskStart = 'taskstart' + m.OnGetPageNumber = 'getpagenumber' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + m.OnGetNameAndLink = 'getnameandlink' +end \ No newline at end of file From c2f378c913b7431ab7c060f9dde47939d048df4e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 10 Feb 2018 17:57:49 +0300 Subject: [PATCH 2158/2794] TonarinoYoungJump, fix all --- baseunits/modules/TonarinoYoungJump.pas | 132 +++++++++++++++++++++--- 1 file changed, 116 insertions(+), 16 deletions(-) diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonarinoYoungJump.pas index f1152c7df..48ad1405e 100644 --- a/baseunits/modules/TonarinoYoungJump.pas +++ b/baseunits/modules/TonarinoYoungJump.pas @@ -8,15 +8,31 @@ interface implementation +uses Graphics, Math, synautil; + +const + chapterListQuery = '/api/viewer/readable_products?current_readable_product_id=%s&number_since=%d&number_until=-1&read_more_num=50&type=episode'; + dirurls: array[0..2] of String = ('/series', '/series/finished', '/series/oneshot'); + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; begin Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/comics/') then + if MangaInfo.FHTTP.GET(Module.RootURL + dirurls[Module.CurrentDirectoryIndex]) then begin Result := NO_ERROR; - XPathHREFAll('//ul[@class="manga-list__list"]/li/h4/a', MangaInfo.FHTTP.Document, ALinks, ANames); + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + for v in XPath('//div[@class="series-items"]/ul/li/a') do begin + ALinks.Add(v.toNode.getAttribute('href')); + ANames.Add(XPathString('h4', v)); + end; + finally + Free; + end; end; end; @@ -24,31 +40,61 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; + lastChapter: Integer; + s, episode, priv: String; + node: TTreeNode; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); + url := MaybeFillHost(Module.RootURL, AURL); if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="fancybox a-alpha"]/img/@src')); - if title = '' then title := XPathString('//strong'); - summary := XPathString('//*[@class="single-story"]/p'); - { there is no chapter list? - assuming the first chapter link in manga info is always the last chapters } - for v in XPath('//li/a[contains(@class,"single")]') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathString('./text()[1]', v)); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="series-header-image-wrapper"]/img/@src')); + if title = '' then title := XPathString('//h1[@class="series-header-title"]'); + authors := XPathString('//h2[@class="series-header-author"]'); + summary := XPathString('//*[@class="series-header-description"]'); + lastChapter := XPathCount('//ul[contains(@class, "series-episode-list")]/li') + 1; + s := XPathString('//button[@class="js-read-more-button"]/@data-read-more-endpoint'); + if s <> '' then begin + s := RegExprGetMatch('number_since\=(\d+)\&', s, 1); + lastChapter += StrToIntDef(s, 0); end; - InvertStrings([chapterLinks, chapterName]); + episode := XPathString('//section[contains(@class, "viewer")]/@data-episode-id'); finally Free; end; + + while lastChapter > 1 do begin + if not GET(Module.RootURL + Format(chapterListQuery, [episode, lastChapter])) then Break; + if MangaInfo.Thread.IsTerminated then Break; + with TXQueryEngineHTML.Create(Document) do + try + node := XPath('json(*).html').toNode; + for v in XPath('//li', node) do begin + priv := ''; + if Pos('private', v.toNode.outerHTML()) > 0 then + priv := ' [private]'; + s := XPathString('a/@href', v); + if s <> '' then begin + chapterLinks.Add(ReplaceString(s, '\"', '')); + chapterName.Add(XPathString('a/div/h4', v) + priv); + end + else begin + chapterLinks.Add(url); + chapterName.Add(XPathString('div/h4', v) + priv); + end; + end; + finally + Free; + end; + lastChapter -= 50; + end; + InvertStrings([chapterLinks, chapterName]); end; end; end; @@ -62,10 +108,62 @@ function GetPageNumber(const DownloadThread: TDownloadThread; begin PageLinks.Clear; PageNumber := 0; - if GET(MaybeFillHost('http://viewer.tonarinoyj.jp', AURL)) then + if GET(MaybeFillHost(Module.RootURL, AURL)) then begin Result := True; - XPathStringAll('//img[@class="js-page-image"]/@src', Document, PageLinks); + XPathStringAll('//img[contains(@class, "js-page-image")]/@data-src', Document, PageLinks); + end; + end; +end; + +function DeScramble(AURL: String; image: TPicture): TPicture; +const + DIVIDE_NUM = 4; + MULTIPLE = 8; +var + cell_width, cell_height, e, sx, sy, dx, dy, a: Integer; + srcrect, destrect: TRect; + r: TPicture; +begin + Result := nil; + cell_width := Trunc(Real(image.Width) / Real(DIVIDE_NUM * MULTIPLE)) * MULTIPLE; + cell_height := Trunc(Real(image.Height) / Real(DIVIDE_NUM * MULTIPLE)) * MULTIPLE; + r := TPicture.Create; + r.Bitmap.SetSize(image.Width, image.Height); + for e := 0 to DIVIDE_NUM * DIVIDE_NUM - 1 do begin + sy := Trunc(Real(e) / Real(DIVIDE_NUM)) * cell_height; + sx := (e mod DIVIDE_NUM) * cell_width; + a := (e mod DIVIDE_NUM) * DIVIDE_NUM + Trunc(Real(e) / Real(DIVIDE_NUM)); + dx := (a mod DIVIDE_NUM) * cell_width; + dy := Trunc(Real(a) / Real(DIVIDE_NUM)) * cell_height; + srcrect := Rect(sx, sy, sx + cell_width, sy + cell_height); + destrect := Rect(dx, dy, dx + cell_width, dy + cell_height); + r.Bitmap.Canvas.CopyRect(destrect, image.Bitmap.Canvas, srcrect); + end; + Result := r; +end; + +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + image, r: TPicture; +begin + Result := False; + if DownloadThread = nil then Exit; + if DownloadThread.FHTTP.GET(AURL) then begin + image := TPicture.Create; + r := nil; + try + image.LoadFromStream(DownloadThread.FHTTP.Document); + r := DeScramble(AURL, image); + if r <> nil then begin + DownloadThread.FHTTP.Document.Clear; + r.SaveToStreamWithFileExt(DownloadThread.FHTTP.Document, 'jpg'); + Result := True; + end; + finally + r.Free; + image.Free; end; end; end; @@ -75,10 +173,12 @@ procedure RegisterModule; with AddModule do begin Website := 'TonarinoYoungJump'; - RootURL := 'http://www.tonarinoyj.jp'; + RootURL := 'https://tonarinoyj.jp'; + TotalDirectory := Length(dirurls); OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; end; end; From 0733ba7a67f45cf34a505a2b39b45435eb50446d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 11 Feb 2018 09:23:20 +0300 Subject: [PATCH 2159/2794] TonarinoYoungJump, fix --- baseunits/modules/TonarinoYoungJump.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonarinoYoungJump.pas index 48ad1405e..82e4d3ea8 100644 --- a/baseunits/modules/TonarinoYoungJump.pas +++ b/baseunits/modules/TonarinoYoungJump.pas @@ -64,7 +64,7 @@ function GetInfo(const MangaInfo: TMangaInformation; s := RegExprGetMatch('number_since\=(\d+)\&', s, 1); lastChapter += StrToIntDef(s, 0); end; - episode := XPathString('//section[contains(@class, "viewer")]/@data-episode-id'); + episode := RegExprGetMatch('episode\/(\d+)', AURL, 1); finally Free; end; From e951bacc5fd4c9e2683be94ca9fd687991f138e5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Feb 2018 15:14:15 +0800 Subject: [PATCH 2160/2794] basethread, remove unused objectlist --- baseunits/BaseThread.pas | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/baseunits/BaseThread.pas b/baseunits/BaseThread.pas index f2a25dc33..154315e06 100644 --- a/baseunits/BaseThread.pas +++ b/baseunits/BaseThread.pas @@ -13,7 +13,6 @@ interface TBaseThread = class(TThread) private - FObjectList: TFPList; FOnCustomTerminate: TNotifyEvent; function GetTerminated: Boolean; procedure CallOnCustomTerminate; inline; @@ -23,7 +22,6 @@ TBaseThread = class(TThread) procedure Terminate; property IsTerminated: Boolean read GetTerminated; property OnCustomTerminate: TNotifyEvent read FOnCustomTerminate write FOnCustomTerminate; - property ObjectList: TFPList read FObjectList; // Object to be freed on Destroy end; implementation @@ -44,21 +42,10 @@ constructor TBaseThread.Create(CreateSuspended: Boolean); begin inherited Create(CreateSuspended); FreeOnTerminate := True; - FObjectList := TFPList.Create; end; destructor TBaseThread.Destroy; -var - i: Integer; begin - if FObjectList.Count <> 0 then - for i := 0 to FObjectList.Count - 1 do - if Assigned(FObjectList[i]) then - try - TObject(FObjectList[i]).Free; - except - end; - FObjectList.Free; inherited Destroy; end; From a25e5351993a1ca02e21c33542d9ba9b1d2bf0e2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 11 Feb 2018 11:22:35 +0300 Subject: [PATCH 2161/2794] updatethread, ignore SortedList when UpdateListDirectoryPageNumber is set related to #910 #799 #763 #726 --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index b8252d262..611740850 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -173,7 +173,7 @@ procedure TUpdateListThread.Execute; for i:=0 to links.Count-1 do begin if manager.mainDataProcess.AddData(names[i],links[i],'','','','','',0,0) then manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0) - else if (manager.isFinishSearchingForNewManga=False) and manager.SortedList then + else if (manager.isFinishSearchingForNewManga=False) and manager.SortedList and (not BROWSER_INVERT) then manager.isFinishSearchingForNewManga:=True; end; manager.mainDataProcess.Rollback; From f35a37848e2faedf6b0d85771b7fa36151b59fa0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 11 Feb 2018 11:47:05 +0300 Subject: [PATCH 2162/2794] h2r, fix getinfo fixes #933 --- baseunits/modules/Hentai2Read.pas | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 13b3975a4..383bd43d9 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -9,7 +9,7 @@ interface XQueryEngineHTML, httpsendthread, synautil; const - dirurl = '/hentai-list/all/any/last-added/'; + dirurl = '/hentai-list/all/any/all/last-added'; cdnurl = 'http://static.hentaicdn.com/hentai'; implementation @@ -45,7 +45,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks Exit(UNKNOWN_ERROR); s := Module.RootURL + dirurl; if AURL <> '0' then - s := s + IncStr(AURL) + '/'; + s := s + '/' + IncStr(AURL) + '/'; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; @@ -85,7 +85,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; artists := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li[starts-with(.,"Artist")]/a'); genres := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li/a'); summary := XPathStringAll('//ul[contains(@class,"list-simple-mini")]/li[starts-with(.,"Storyline")]/*[position()>1]'); - for v in XPath('//ul[starts-with(@class,"nav-chapters")]/li/a') do + for v in XPath('//ul[contains(@class,"nav-chapters")]/li/div/a') do begin chapterLinks.Add(v.toNode.getAttribute('href')); chapterName.Add(XPathString('string-join(text()," ")', v.toNode)); @@ -119,7 +119,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String for v in XPath('json(//script[contains(.,"images'' :")]/substring-before(substring-after(.,"images'' : "),"]")||"]")()') do PageLinks.Add(cdnurl + v.toString); if PageLinks.Count = 0 then - PageNumber := XPath('(//ul[@class="dropdown-menu text-center list-inline"])[1]/li').Count; + PageNumber := XPath('(//li[contains(@class, "pageDropdown")])[1]/ul/li').Count; finally Free; end; From 182e730c82914caddbd79071f1a90aef452d6b57 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Feb 2018 20:49:55 +0800 Subject: [PATCH 2163/2794] mangadex, limit connections to 4 (#940) --- baseunits/modules/Mangadex.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index 049dc766f..68cdefb0e 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -139,6 +139,8 @@ procedure RegisterModule; with AddModule do begin Website := 'Mangadex'; RootURL := 'https://mangadex.com'; + MaxTaskLimit := 4; + MaxConnectionLimit := 4; TotalDirectory := Length(ALPHA_LIST_UP); OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; From d935f3cc9accc21edd32a1f2cf05f916f0cae475 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Feb 2018 23:00:33 +0800 Subject: [PATCH 2164/2794] added lua website modules updater auto update following main program auto check --- baseunits/FMDOptions.pas | 7 +- .../forms/frmLuaModulesUpdater.lfm | 397 ++++++++ .../forms/frmLuaModulesUpdater.lrj | 6 + .../forms/frmLuaModulesUpdater.pas | 930 ++++++++++++++++++ mangadownloader/forms/frmMain.lfm | 633 +----------- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 65 +- mangadownloader/languages/fmd.de.po | 45 + mangadownloader/languages/fmd.el_GR.po | 45 + mangadownloader/languages/fmd.en.po | 45 + mangadownloader/languages/fmd.es.po | 45 + mangadownloader/languages/fmd.id_ID.po | 45 + mangadownloader/languages/fmd.pl_PL.po | 45 + mangadownloader/languages/fmd.po | 44 + mangadownloader/languages/fmd.pt_BR.po | 45 + mangadownloader/languages/fmd.ru_RU.po | 45 + mangadownloader/languages/fmd.tr_TR.po | 45 + mangadownloader/md.lpi | 9 +- 18 files changed, 1861 insertions(+), 636 deletions(-) create mode 100644 mangadownloader/forms/frmLuaModulesUpdater.lfm create mode 100644 mangadownloader/forms/frmLuaModulesUpdater.lrj create mode 100644 mangadownloader/forms/frmLuaModulesUpdater.pas diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 803214db2..73ce684f6 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -90,7 +90,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) README_FILE, EXTRAS_FOLDER, MANGAFOXTEMPLATE_FOLDER, - LUA_WEBSITEMODULE_FOLDER: String; + LUA_WEBSITEMODULE_FOLDER, + LUA_WEBSITEMODULE_REPOS: String; // ini files revisionfile, @@ -284,7 +285,6 @@ procedure SetFMDdirectory(const ADir: String); FMD_DIRECTORY := CleanAndExpandDirectory(ADir); FMD_EXENAME := ExtractFileNameOnly(Application.ExeName); - LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules'; CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; @@ -297,6 +297,9 @@ procedure SetFMDdirectory(const ADir: String); EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; DEFAULT_LOG_FILE := FMD_DIRECTORY + FMD_EXENAME + '.log'; + + LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; + LUA_WEBSITEMODULE_REPOS := CONFIG_FOLDER + 'luamodules.json'; end; procedure SetAppDataDirectory(const ADir: String); diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lfm b/mangadownloader/forms/frmLuaModulesUpdater.lfm new file mode 100644 index 000000000..2ae4b92f8 --- /dev/null +++ b/mangadownloader/forms/frmLuaModulesUpdater.lfm @@ -0,0 +1,397 @@ +object LuaModulesUpdaterForm: TLuaModulesUpdaterForm + Left = 240 + Height = 394 + Top = 100 + Width = 580 + ChildSizing.LeftRightSpacing = 4 + ChildSizing.TopBottomSpacing = 4 + ChildSizing.HorizontalSpacing = 2 + ChildSizing.VerticalSpacing = 6 + ClientHeight = 394 + ClientWidth = 580 + OnCreate = FormCreate + OnDestroy = FormDestroy + LCLVersion = '1.9.0.0' + object vtLuaModulesRepos: TVirtualStringTree + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = btCheckUpdate + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 4 + Height = 354 + Top = 36 + Width = 572 + Anchors = [akTop, akLeft, akRight, akBottom] + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Filename' + Width = 150 + end + item + Position = 1 + Text = 'Last modified' + Width = 110 + end + item + Position = 2 + Text = 'Last message' + Width = 250 + end> + Header.DefaultHeight = 17 + Header.Height = 23 + Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] + HintMode = hmHint + Images = imStates + ParentShowHint = False + ShowHint = True + TabOrder = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnCompareNodes = vtLuaModulesReposCompareNodes + OnGetText = vtLuaModulesReposGetText + OnGetImageIndex = vtLuaModulesReposGetImageIndex + OnGetHint = vtLuaModulesReposGetHint + OnHeaderClick = vtLuaModulesReposHeaderClick + end + object btCheckUpdate: TBitBtn + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Left = 4 + Height = 26 + Top = 4 + Width = 119 + AutoSize = True + Caption = 'Check update' + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 20000000000000040000640000006400000000000000000000000000000E0000 + 0013000000170000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A000000150000000B00000002FFFFFF000000001C733A + 02A265330272000000332A1601436E380280934A02AB984D02CD984D02C29049 + 0291673502622111013A0000002A0000001500000003FFFFFF00281502009C51 + 05CC9C5105CC9C510585A35806BFC8841AE3EAA71FF5FCB920FFFCB920F1EAA6 + 1FCFC78219A6A3590978763D04222816020000000000FFFFFF00A2570A00A257 + 0ACCF9BF40FFA2570ACCF7B52AFFF6B01CFFF7B11EFFF8B527FFF8B527F1F7B1 + 1ED6F6B01CB4F8BA3490AB62105FA3580B19A65B0D00FFFFFF00A85D0E00A85D + 0ECCF2B339FFF3B844FFEEA824FFF2B339FFC37E23DCA85D0ECCA85D0EC1C27E + 22BAE7A937B2EFAB2A90F3B8436DAD631243A95E0F06FFFFFF00AF641400AF64 + 14CCECB149FFE6A334FFEEB752FFAF6414CCAF641494AD621200AA5F0F00AE63 + 134AAF641488E4A74491E8A83B6DCA88314EAF641419FFFFFF00B66B1900B66B + 19CCEBB861FFE7B057FFE7B057FFEEBF6AFFB66B19CCB76C1A5CB56A1800AF64 + 1400B56A1932C7843178E3A84E6CDCA24C54B66B1925FFFFFF00BC711D00BD72 + 1E99BE731FCCBE731FCCBE731FCCBE731FCCBE731FCCBD721E99C0752000C378 + 2300BD721E00BE731F33E5B06140E7B4663FBD721E20FFFFFF00C77C2600C67B + 2620E8B86F3FE6B46C40C57A2533C2782200BF752000C1762100C67B2699C57A + 25CCC57A25CCC57A25CCC57A25CCC57A25CCC67B2699FFFFFF00CD822A00CD82 + 2A25E6B16654E8B5706CD8984478CE832B32CF842C00CB802800CC81295CCD82 + 2ACCF3CD84FFECBD77FFECBD77FFF0C57EFFCD822ACCFFFFFF00D4893000D489 + 3019E2A7554EEDBC766DEEBE7491D4893088D58A314AD98E3300D3882F00D489 + 3094D48930CCF4CD84FFEAB772FFF1C67EFFD48930CCFFFFFF00D98E3300DA8F + 3406DD943A43F8D2896DF4C57D90F4C77AB2E5A852BADB9034C1DB9034CCE5A8 + 52DCF7CD85FFF2C27AFFF8D389FFF7CD85FFDB9034CCFFFFFF00DC913500DC91 + 3500E0953919E49E435FFCD88D90FACF85B4FBD086D6FCD489F1FCD489FFFBD0 + 86FFFACF85FFFBD389FFE19639CCFEDD92FFE19639CCFFFFFF00DC913500DC91 + 3500E1963900E59A3D22E79F4378F1B964A6FACF80CFFEDA8EF1FEDA8EFFFACF + 81F5F1BB65E3E79E42BFE59A3D85E59A3DCCE59A3DCCFFFFFF00DC913500DC91 + 3500E1963900E59A3D00E89D3F10E99E404DE99E408CE99E40C1E99E40CCE99E + 40A6E99E406CE89D3F1AE69B3D00E99E405CE99E4099FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btCheckUpdateClick + TabOrder = 1 + end + object btCheckUpdateTerminate: TSpeedButton + AnchorSideLeft.Control = btCheckUpdate + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btCheckUpdate + AnchorSideBottom.Control = btCheckUpdate + AnchorSideBottom.Side = asrBottom + Left = 125 + Height = 26 + Top = 4 + Width = 20 + Anchors = [akTop, akLeft, akBottom] + AutoSize = True + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000013000000190000001900000016000000120000000F0000000E0000 + 0011000000150000001900000019000000140000000EFFFFFF00FFFFFF000000 + 001C000000260000346400005FCC00003561000000240000001D0000001B0000 + 00210000366000005FCC00003464000000270000001CFFFFFF00FFFFFF000000 + 1E0000005748000072CC1111D8FF000072CC0000574800002000000020000000 + 5748000072CC1111D8FF000072CC0000574800001E00FFFFFF00FFFFFF000000 + 8200000082CC1111D0FF1111D0FF1111D0FF000082CC00008348000083480000 + 82CC1111D0FF1111D0FF1111D0FF000082CC00008200FFFFFF00FFFFFF000000 + 860000008748000087CC1111C4FF1111C4FF1111C4FF000087CC000087CC1111 + C4FF1111C4FF1111C4FF000087CC0000874800008600FFFFFF00FFFFFF000000 + 86000000870000008C4800008DCC1111B8FF1111B8FF1111B8FF1111B8FF1111 + B8FF1111B8FF00008DCC00008C480000870000008600FFFFFF00FFFFFF000000 + 86000000870000008D0000009148000092CC1515AFFF1111ACFF1111ACFF1111 + ACFF000092CC0000914800008D000000870000008600FFFFFF00FFFFFF000000 + A1000000A00000009B0000009848000097CC2525B4FF1111A2FF1111A2FF1414 + A5FF000097CC0000984800009B000000A0000000A100FFFFFF00FFFFFF000000 + A1000000A00000009C4800009BCC5353DBFF2E2EB7FF3D3DC6FF3131BAFF1515 + 9FFF1E1EA8FF00009BCC00009C480000A0000000A100FFFFFF00FFFFFF000000 + A1000000A1480000A0CC6767EFFF3636BEFF5E5EE6FF0000A0CC0000A0CC4F4F + D7FF3636BEFF4545CDFF0000A0CC0000A1480000A100FFFFFF00FFFFFF000000 + A3000000A3CC7676FEFF4C4CD4FF7272FAFF0000A3CC0000A3480000A3480000 + A3CC6262EAFF4C4CD4FF5C5CE4FF0000A3CC0000A300FFFFFF00FFFFFF000000 + A6000000A7480000A7CC7777FFFF0000A7CC0000A7480000A3000000A3000000 + A7480000A7CC7070F8FF0000A7CC0000A7480000A600FFFFFF00FFFFFF000000 + A6000000A7000000AA480000AACC0000AA480000A7000000A3000000A3000000 + A7000000AA480000AACC0000AA480000A7000000A600FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + OnClick = btCheckUpdateTerminateClick + end + object imStates: TImageList + left = 200 + top = 128 + Bitmap = { + 4C69070000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003B7F320015A9000015A9000015A9 + 000015A9000015AA009915AA00CC15AA00CC15AA009915A9000015A9000015A9 + 000015A90000094D0000FFFFFF00FFFFFF00119A0000129F000014A8000014A8 + 000014A8000014A800CC72E961FF71E860FF14A800CC14A8000014A8000014A8 + 0000129F0000119A0000FFFFFF00FFFFFF00119A0000119B0000129E000014A5 + 000014A5000014A500CC69E058FF69E058FF14A500CC14A5000014A50000129E + 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000129D + 000013A2000013A200CC62D951FF61D850FF13A200CC13A20000129D0000119B + 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000119B + 0000129C0000129E00CC5AD149FF59D048FF129E00CC129C0000119B0000119B + 0000119B0000119A0000FFFFFF00FFFFFF00119A0099119A00CC119A00CC119A + 00CC119A00CC119A00CC54CB43FF52C941FF119A00CC119A00CC119A00CC119A + 00CC119A00CC119A0099FFFFFF00FFFFFF00109600CC5ED54DFF55CC44FF54CB + 43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC63EFF4EC53DFF4DC43CFF4CC3 + 3BFF4EC53DFF109600CCFFFFFF00FFFFFF000F9200CC59D048FF50C73FFF50C7 + 3FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A920FF2CA51BFF2BA31AFF2DA5 + 1CFF33AB22FF0F9200CCFFFFFF00FFFFFF000E8E00990E8D00CC0E8D00CC0E8D + 00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D00CC0E8D00CC0E8D00CC0E8D + 00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8C + 00000E8B00000D8900CC29B618FF27B416FF0D8900CC0E8B00000E8C00000E8C + 00000E8C00000E8D0000FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8A + 00000C8400000C8400CC25C014FF24C013FF0C8400CC0C8400000E8A00000E8C + 00000E8C00000E8D0000FFFFFF00FFFFFF000747000000000000000000000320 + 00000A7D00000A7D00CC23CD12FF22CC11FF0A7D00CC0A7D0000032000000000 + 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 + 0000021D0000066D00CC22D811FF22D811FF066D00CC021D0000000000000000 + 00000000000000000000FFFFFF00FFFFFF0000000000000000040000001B0000 + 003000000033024700A6025D00CC025D00CC024700A600000033000000310000 + 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000 + 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000 + 00100000000300000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE000065D0000064 + CF000069D400006AD548006AD5CC006AD5CC006AD5660069D4000064CF000065 + D0000063CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE000065D01A0064 + CF000066D1000067D2CC38C1F8F938C7F8FD0067D2C90066D1000064CF000065 + D01A0063CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE660063CECC0063 + CEB30062CD4D0063CECC3AC8F8FF2FC0F1FD0063CEB30062CD4D0063CEB30063 + CECC0063CE66FFFFFF00FFFFFF00FFFFFF00FFFFFF00005FCACC39C2F5FF34B8 + F2F9117AD7D9005FCACC38C1F4FF2AAFE9F9005FCAB71079D6D932B6F0F936BF + F3FF005FCACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00005AC5CC27A4E3F92CAD + E7FF31B3ECFF1075D3D935B9F0FF249EE1F50F74D2D930B2EBFF2CADE7FF27A4 + E3F9005AC5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF000056C13E0055C0B31074 + CDE01A87D5EC2DAAE6FF2DA9E6FF28A3E1FF2DA9E6FF1A87D5EC1074CDE00055 + C0B30056C13EFFFFFF00FFFFFF00FFFFFF00FFFFFF000050BA000050BB000050 + BB480050BBCC1C8BD6F3249CDEFF249CDEFF1C8BD6F30050BBCC0050BB480050 + BB000050BA00FFFFFF00FFFFFF00FFFFFF00FFFFFF000049B33E004BB5B31474 + CCE01B87D6EC2099DDFF2099DDFF239EE1FF2099DDFF1884D3EC1070C9E0004B + B5B30049B33EFFFFFF00FFFFFF00FFFFFF00FFFFFF000045AFCC24A1E4F91C9D + E1FF1A9ADFFF075ABBD9158BD7F520A1E5FF075ABBD91A9ADFFF1B9BE0FF1C97 + DFF90045AFCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00003DA8CC139DE2FF1192 + DCF90554B6D9003DA8B71194DCF918A2E6FF003DA8CC0554B6D91192DCF9139D + E2FF003DA8CCFFFFFF00FFFFFF00FFFFFF00FFFFFF0000329D6600309BCC0030 + 9BB300339E4D00309BB30C9EE5FD0FA4E9FF00309BCC00339E4D00309BB30030 + 9BCC00329D66FFFFFF00FFFFFF00FFFFFF00FFFFFF0000184E0000154A1A0017 + 4C00000A250000248EC908A2E8FD0899E2F900248ECC000A250000174C000015 + 4A1A00184E00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000000D0000 + 00210000002700135E79002B91D1002B91D100104B6100000027000000230000 + 001000000001FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000080000 + 00160000001A0000001A0000001A0000001A0000001A0000001A000000170000 + 000A00000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000212121006565 + 65008B8B8B002502B0002502B2002502B3002602B5372602B47B2502B47C2502 + B3382502AF002402AC002302A800000000001D1D1D005C5C5C00808080008686 + 86008B8B8B002502B0002502B2002502B3382502B37CC9B8FDFFCAB9FEFF2502 + B17E2502AF392402AC002302A800525252007373730079797900808080008686 + 86008B8B8B002502B0002502B2392502B17EC6B5FCFFB6A5ECFFB8A7ECFFCAB9 + FEFF2402AD812402AC3B2302A8006C6C6C007373730079797900808080008686 + 86008B8B8B002502B0392502B07FC4B3FBFFB3A2EAFFB5A4EBFFB6A5ECFFB8A7 + ECFFCAB9FEFF2402A9862302A83D6C6C6C007373730079797900808080008686 + 86008A8A8A2F88888866C1B0F9FFB09FE9FFB2A1E9FFB3A2EAFFB5A4EBFFB6A5 + ECFF9887DCFFAA99EEFF2302A58A6C6C6C007373730079797900808080008585 + 852F83838366F8F8F8FFF5F5F5FFAE9DE8FFB09FE9FFB2A1E9FFB3A2EAFF9584 + D9FF9786DBFFA998EDFF2202A18D6C6C6C0073737300797979007F7F7F2F7D7D + 7D66F6F6F6FFF2F2F2FFF2F2F2FFF2F2F2FFAE9DE8FFB09FE9FF9281D6FF9483 + D8FFA695EAFF22029F9022029F416C6C6C00737373007878782F76767666F4F4 + F4FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFF8E7DD2FF907FD4FFA392 + E7FF21029D9221029C4221029E006C6C6C007272722F70707066F3F3F3FFECEC + ECFFECECECFFECECECFFECECECFFECECECFFCECECEFFD0D0D0FF9F8EE3FF2102 + 9B9521029A4321029C0021029E006B6B6B2F69696966F1F1F1FFE9E9E9FFE9E9 + E9FFE9E9E9FFE9E9E9FFE9E9E9FFCACACAFFCCCCCCFFDCDCDCFF363636662003 + 98452102990021029C0021029E0063636366F0F0F0FFE6E6E6FFE6E6E6FFE6E6 + E6FFE6E6E6FFE6E6E6FFC6C6C6FFC8C8C8FFD8D8D8FF272727662323232F2003 + 9700210299001902750011014F0058585866F0F0F0FFE3E3E3FFE3E3E3FFE3E3 + E3FFE3E3E3FFC2C2C2FFC4C4C4FFD4D4D4FF1A1A1A661616162F202020001803 + 71000801260000000000000000004848482F3D3D3D66F0F0F0FFE1E1E1FFE1E1 + E1FFBFBFBFFFC0C0C0FFD1D1D1FF0F0F0F660C0C0C2F0F0F0F00080808000000 + 0000000000000000000000000000101010001E1E1E2F20202066DFDFDFFFCECE + CEFFCECECEFFCECECEFF050505660202022F0202020000000000000000000000 + 00000000000000000000000000000000001100000026090909480A0A0A660505 + 05660202026601010166000000400000001E00000019000000130000000E0000 + 000000000005000000020000000000000000000000130000001A000000190000 + 00180000001600000014000000120000000F0000000D0000000A000000070000 + 0005000000030000000100000000000000000000000000000000000000002222 + 2200696969002502B0002502B2002502B3002602B5372602B47B2502B47C2502 + B3382502AF002402AC002302A80000000000000000001F1F1F00616161008686 + 86008B8B8B002502B0002502B2002502B3382502B37CC9B8FDFFCAB9FEFF2502 + B17E2502AF392402AC002302A8001C1C1C005757570079797900808080008686 + 86008B8B8B002502B0002502B2392502B17EC6B5FCFFB6A5ECFFB8A7ECFFCAB9 + FEFF2402AD812402AC3B2302A8006C6C6C007373730079797900808080008686 + 86008B8B8B002502B0392502B07FC4B3FBFFB3A2EAFFB5A4EBFFB6A5ECFFB8A7 + ECFFCAB9FEFF2402A9862302A83D6C6C6C007373730079797900808080008686 + 86008A8A8A2F88888866C1B0F9FFB09FE9FFB2A1E9FFB3A2EAFFB5A4EBFFB6A5 + ECFF9887DCFFAA99EEFF2302A58A6C6C6C007373730079797900808080008585 + 852F83838366F8F8F8FFF5F5F5FFAE9DE8FFB09FE9FFB2A1E9FFB3A2EAFF9584 + D9FF9786DBFFA998EDFF2202A18D6C6C6C0073737300797979007F7F7F2F7D7D + 7D66F6F6F6FFF2F2F2FFF2F2F2FFF2F2F2FFAE9DE8FFB09FE9FF9281D6FF9483 + D8FFA695EAFF22029F9022029F416C6C6C00737373007878782F76767666F4F4 + F4FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFF8E7DD2FF907FD4FFA392 + E7FF21029D9221029C4221029E006C6C6C007272722F70707066F3F3F3FFECEC + ECFFECECECFFECECECFFECECECFFECECECFFCECECEFFD0D0D0FF9F8EE3FF2102 + 9B9521029A4321029C0021029E006B6B6B2F69696966F1F1F1FFE9E9E9FFE9E9 + E9FFE9E9E9FFE9E9E9FFE9E9E9FFCACACAFFCCCCCCFFDCDCDCFF363636662003 + 984519029D000901A7000000A70063636366F0F0F0FFE6E6E6FFE6E6E6FFE6E6 + E6FFE6E6E6FFE6E6E6FFC6C6C6FFC8C8C8FFD8D8D8FF272727661A1A452F0801 + A5000000AA000000AA000000A70058585866F0F0F0FFE3E3E3FFE3E3E3FFE3E3 + E3FFE3E3E3FFC2C2C2FFC4C4C4FFD4D4D4FF0A0A7BC20202A1D50000A7CC0000 + A7CC0000A7CC0000A7CC0000A6994848482F3D3D3D66F0F0F0FFE1E1E1FFE1E1 + E1FFBFBFBFFFC0C0C0FFD1D1D1FF0F0F0F66010192D55E5EF7FF5E5EF7FF5E5E + F7FF5E5EF7FF5E5EF7FF000098CC101010001E1E1E2F20202066DFDFDFFFCECE + CEFFCECECEFFCECECEFF050505660202022F00006299000080CC000080CC0000 + 80CC000080CC000080CC000084990000001100000026090909480A0A0A660505 + 05660202026601010166000000400000001E00000019000000130000000E0000 + 000000000005000000020000400000000000000000130000001A000000190000 + 00180000001600000014000000120000000F0000000D0000000A000000070000 + 0005000000030000000100000000FFFFFF00E99E3F00E99E3F00E99E3F00EA9F + 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398 + 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B + 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398 + 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398 + 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297 + 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92 + 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91 + 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C + 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B + 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287 + 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287 + 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F + 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E + 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A + 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72 + 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73 + 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E + 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D + 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D + 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF + 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166 + 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3 + 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61 + 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A + 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60 + 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156 + 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000 + 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000 + 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000 + 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000 + 00320000003363320274974C02CC633202740000003300000033000000220000 + 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA + 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE + 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2 + 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B + 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5 + 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B + 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7 + 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197 + 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197 + 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1 + 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094 + 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC + 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094 + 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA + 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A + 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82 + 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000 + 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657 + 0048077200CC16A60AE8087601C406570029021E000000000000000000000000 + 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000 + 002D02330066025F00CC012B005500000029000000220000001A000000130000 + 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000 + 00170000001A000000190000001700000015000000110000000D0000000A0000 + 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000 + A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000 + A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909 + AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000 + A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B + E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F + B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151 + D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F + DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242 + CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747 + CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737 + BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616 + A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E + B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111 + A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414 + ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111 + AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111 + B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111 + B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111 + BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111 + BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212 + C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F + BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212 + C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303 + 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202 + 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000 + 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000 + 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000 + 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000 + 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 00170000000C00000002FFFFFF00 + } + end + object tmRepaintList: TTimer + Enabled = False + Interval = 500 + OnTimer = tmRepaintListTimer + left = 61 + top = 119 + end +end diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lrj b/mangadownloader/forms/frmLuaModulesUpdater.lrj new file mode 100644 index 000000000..56d0d4e88 --- /dev/null +++ b/mangadownloader/forms/frmLuaModulesUpdater.lrj @@ -0,0 +1,6 @@ +{"version":1,"strings":[ +{"hash":2901221,"name":"tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text","sourcebytes":[70,105,108,101,110,97,109,101],"value":"Filename"}, +{"hash":119908548,"name":"tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text","sourcebytes":[76,97,115,116,32,109,111,100,105,102,105,101,100],"value":"Last modified"}, +{"hash":115487141,"name":"tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text","sourcebytes":[76,97,115,116,32,109,101,115,115,97,103,101],"value":"Last message"}, +{"hash":56103285,"name":"tluamodulesupdaterform.btcheckupdate.caption","sourcebytes":[67,104,101,99,107,32,117,112,100,97,116,101],"value":"Check update"} +]} diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas new file mode 100644 index 000000000..98e660415 --- /dev/null +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -0,0 +1,930 @@ +unit frmLuaModulesUpdater; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, + Buttons, Menus, ExtCtrls, VirtualTrees, synautil, httpsendthread, BaseThread, + XQueryEngineHTML, fpjson, jsonparser, jsonscanner, dateutils; + +type + + TLuaModuleRepoFlag = (fNone, fNew, fUpdate, fDelete, fDeleted, fDownloading, + fDownloaded, fFailedDownload); + + PPLuaModuleRepo = ^PLuaModuleRepo; + PLuaModuleRepo = ^TLuaModuleRepo; + + { TLuaModuleRepo } + + TLuaModuleRepo = class + name: String; + sha: String; + size: Integer; + download_url: String; + last_modified: TDateTime; + last_message: String; + flag: TLuaModuleRepoFlag; + function Clone: TLuaModuleRepo; + function SyncTo(const t: TLuaModuleRepo): Boolean; + end; + + { TLuaModulesRepos } + + TLuaModulesRepos = class + private + function GetCount: Integer; inline; + function GetRepo(const AIndex: Integer): TLuaModuleRepo; inline; + public + Items: TStringList; + + constructor Create; + destructor Destroy; override; + + procedure Clear; inline; + function Add(const AName: String): TLuaModuleRepo; overload; + procedure Add(const I: TLuaModuleRepo); overload; + procedure LoadFromRemote(const AHTTP: THTTPSendThread); + procedure LoadFromRemoteHTML(const AHTTP: THTTPSendThread); + procedure LoadFromFile(const AFilename: String); + procedure SaveToFile(const AFilename: String); + procedure Sort; + function Clone: TLuaModulesRepos; + property Count: Integer read GetCount; + property Repo[const AIndex: Integer]: TLuaModuleRepo read GetRepo; default; + end; + + TCheckUpdateThread = class; + + { TLuaModulesUpdaterForm } + + TLuaModulesUpdaterForm = class(TForm) + btCheckUpdate: TBitBtn; + imStates: TImageList; + btCheckUpdateTerminate: TSpeedButton; + tmRepaintList: TTimer; + vtLuaModulesRepos: TVirtualStringTree; + procedure btCheckUpdateClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure btCheckUpdateTerminateClick(Sender: TObject); + procedure tmRepaintListTimer(Sender: TObject); + procedure vtLuaModulesReposCompareNodes(Sender: TBaseVirtualTree; + Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure vtLuaModulesReposGetHint(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; + var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: String); + procedure vtLuaModulesReposGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure vtLuaModulesReposGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); + {$if VTMajorVersion < 5} + procedure vtLuaModulesReposHeaderClick(Sender: TVTHeader; Column: TColumnIndex; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + {$else} + procedure vtLuaModulesReposHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + {$endif} + private + FListCS: TRTLCriticalSection; + FListDirty: Boolean; + public + Repos: TLuaModulesRepos; + ThreadCheck: TCheckUpdateThread; + procedure ListDirty; + procedure CheckUpdate; + procedure LoadLocalRepos; + procedure ReinitList(const ASort: Boolean = True); + procedure SortList; + end; + + { TDownloadThread } + + TDownloadThread = class(TBaseThread) + private + FOwner: TCheckUpdateThread; + FModule: TLuaModuleRepo; + FHTTP: THTTPSendThread; + protected + procedure Execute; override; + public + constructor Create(const Owner: TCheckUpdateThread; const T: TLuaModuleRepo); + destructor Destroy; override; + end; + + { TCheckUpdateThread } + + TCheckUpdateThread = class(TBaseThread) + private + FOwner: TLuaModulesUpdaterForm; + FHTTP: THTTPSendThread; + FReposUp: TLuaModulesRepos; + FRepos: TLuaModulesRepos; + FMainRepos: TLuaModulesRepos; + FThreads: TFPList; + FThreadsCS: TRTLCriticalSection; + procedure RemoveThread(const T: TDownloadThread); + procedure AddThread(const T: TDownloadThread); + protected + procedure SyncStartChecking; + procedure SyncFinishChecking; + procedure SyncStartDownload; + procedure SyncFinishDownload; + procedure SyncFinal; + function SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Boolean; + procedure Download; + procedure Execute; override; + public + constructor Create(const AOwner: TLuaModulesUpdaterForm); + destructor Destroy; override; + end; + +var + LuaModulesUpdaterForm: TLuaModulesUpdaterForm; + LuaModulesURLJSON: String = + 'https://api.github.com/repos/riderkick/FMD/contents/lua/modules'; + LuaModulesURLHTML: String = 'https://github.com/riderkick/FMD/file-list/master/lua/modules'; + +resourcestring + RS_CheckUpdate = 'Check update'; + RS_Checking = 'Checking...'; + RS_FinishChecking = 'Finish checking'; + RS_StartDownloading = 'Downloading...'; + RS_FinishDownload = 'Finish download'; + +implementation + +uses frmCustomColor, FMDOptions; + +const + // RFC 3339 - ISO 8601 + DateTimeFormatStrDecode = 'yyyy"-"mm"-"dd"T"hh":"nn":"ss'; + DateTimeFormatStrEncode = DateTimeFormatStrDecode + '"Z"'; + UnknownDateTime = 43101.0423726852; // 01/01/2018 01:01:01 + +function JSONToDateTime(const s: String): TDateTime; +begin + if Length(s) = 20 then + Result := ScanDateTime(DateTimeFormatStrDecode, s) + else + Result := UnknownDateTime; +end; + +function DateTimeToJSON(const d: TDateTime): String; +begin + Result := FormatDateTime(DateTimeFormatStrEncode, d); +end; + +{ TLuaModuleRepo } + +function TLuaModuleRepo.Clone: TLuaModuleRepo; +begin + Result := TLuaModuleRepo.Create; + Result.name := name; + Result.sha := sha; + Result.sha := sha; + Result.size := size; + Result.download_url := download_url; + Result.last_modified := last_modified; + Result.last_message := last_message; + Result.flag := flag; +end; + +function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean; +begin + Result := name = t.name; + if not Result then + Exit; + if sha <> t.sha then + begin + t.sha := sha; + t.last_modified := last_modified; + if t.last_message <> '' then + t.last_message := LineEnding + t.last_message; + t.last_message := last_message + t.last_message; + t.flag := fUpdate; + end; +end; + +{ TLuaModulesRepos } + +function TLuaModulesRepos.GetCount: Integer; +begin + Result := Items.Count; +end; + +function TLuaModulesRepos.GetRepo(const AIndex: Integer): TLuaModuleRepo; +begin + Result := TLuaModuleRepo(Items.Objects[AIndex]); +end; + +constructor TLuaModulesRepos.Create; +begin + Items := TStringList.Create; + Items.OwnsObjects := True; + Clear; +end; + +destructor TLuaModulesRepos.Destroy; +begin + Clear; + Items.Free; + inherited Destroy; +end; + +procedure TLuaModulesRepos.Clear; +begin + Items.Clear; +end; + +function TLuaModulesRepos.Add(const AName: String): TLuaModuleRepo; +begin + Result := TLuaModuleRepo.Create; + Result.name := AName; + Items.AddObject(AName, Result); +end; + +procedure TLuaModulesRepos.Add(const I: TLuaModuleRepo); +begin + Items.AddObject(I.name, I); +end; + +procedure TLuaModulesRepos.LoadFromRemote(const AHTTP: THTTPSendThread); +var + j: TJSONParser; + a: TJSONArray; + i: Integer; + o: TJSONObject; + m: TLuaModuleRepo; +begin + Clear; + + a := nil; + j := TJSONParser.Create(AHTTP.Document, [joUTF8]); + try + a := TJSONArray(j.Parse); + finally + j.Free; + end; + if a = nil then + Exit; + + try + for i := 0 to a.Count - 1 do + begin + o := TJSONObject(a.Items[i]); + m := Add(o.Get('name', '')); + m.sha := o.Get('sha', ''); + m.download_url := o.Get('download_url', ''); + m.size := o.Get('size', 0); + end; + finally + a.Free; + end; +end; + +procedure TLuaModulesRepos.LoadFromRemoteHTML(const AHTTP: THTTPSendThread); +var + v: IXQValue; + i: Integer; +begin + with TXQueryEngineHTML.Create(AHTTP.Document) do + try + v := XPath('//table[starts-with(@class,"files")]//tr[@class="js-navigation-item"]'); + if v.Count = Count then + for i := 1 to v.Count do + with Repo[i - 1] do + begin + last_message := XPathString('./td[@class="message"]/span/a/@title', v.get(i)); + last_modified := JSONToDateTime( + XPathString('./td[@class="age"]/span/time-ago/@datetime', v.get(i))); + end; + finally + Free; + end; + Sort; +end; + +procedure TLuaModulesRepos.LoadFromFile(const AFilename: String); +var + f: TFileStream; + j: TJSONParser; + a: TJSONArray; + o: TJSONObject; + i: Integer; + m: TLuaModuleRepo; +begin + if not FileExists(AFilename) then + Exit; + + a := nil; + f := TFileStream.Create(AFilename, fmOpenRead or fmShareDenyWrite); + try + j := TJSONParser.Create(f, [joUTF8]); + try + a := TJSONArray(j.Parse); + finally + j.Free; + end; + finally + f.Free; + end; + if a = nil then + Exit; + try + Self.Clear; + for i := 0 to a.Count - 1 do + begin + o := TJSONObject(a.Items[i]); + m := Add(o.Get('name', '')); + m.sha := o.Get('sha', ''); + m.download_url := o.Get('download_url', ''); + m.size := o.Get('asize', 0); + m.last_modified := JSONToDateTime(o.Get('last_modified', '')); + m.last_message := o.Get('last_message', ''); + m.flag := TLuaModuleRepoFlag(o.Get('flag', 0)); + if not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name) then + m.flag := fFailedDownload; + end; + finally + a.Free; + end; + Sort; +end; + +procedure TLuaModulesRepos.SaveToFile(const AFilename: String); +var + a: TJSONArray; + o: TJSONObject; + i: Integer; + m: TLuaModuleRepo; + f: TFileStream; + s: TJSONStringType; +begin + a := TJSONArray.Create; + try + for i := 0 to Items.Count - 1 do + begin + o := TJSONObject.Create; + m := Repo[i]; + o.Add('name', m.name); + o.Add('sha', m.sha); + o.Add('download_url', m.download_url); + o.Add('size', m.size); + o.Add('last_modified', DateTimeToJSON(m.last_modified)); + o.Add('last_message', m.last_message); + o.Add('flag', Integer(m.flag)); + a.Add(o); + end; + + if FileExists(AFilename) then + DeleteFile(AFilename); + f := TFileStream.Create(AFilename, fmCreate); + try + s := a.FormatJSON(); + f.WriteBuffer(s[1], Length(s)); + finally + f.Free; + end; + finally + a.Free; + end; +end; + +procedure TLuaModulesRepos.Sort; +begin + if Items.Count <> 0 then + Items.Sort; +end; + +function TLuaModulesRepos.Clone: TLuaModulesRepos; +var + i: Integer; +begin + Result := TLuaModulesRepos.Create; + for i := 0 to Items.Count - 1 do + Result.Items.AddObject(Items[i], Repo[i].Clone); +end; + +{ TDownloadThread } + +procedure TDownloadThread.Execute; +var + f: String; + c: Boolean; +begin + FModule.flag := fDownloading; + FOwner.FOwner.ListDirty; + if FHTTP.GET(FModule.download_url) then + begin + if ForceDirectories(LUA_WEBSITEMODULE_FOLDER) then + begin + f := LUA_WEBSITEMODULE_FOLDER + FModule.name; + c := True; + if FileExists(f) then + c := DeleteFile(f); + if c then + begin + FHTTP.Document.SaveToFile(f); + if FileExists(f) then + FModule.flag := fDownloaded; + end; + end; + end + else + FModule.flag := fFailedDownload; + FOwner.FOwner.ListDirty; +end; + +constructor TDownloadThread.Create(const Owner: TCheckUpdateThread; const T: TLuaModuleRepo); +begin + inherited Create(False); + FHTTP := THTTPSendThread.Create(Self); + FOwner := Owner; + FModule := T; + FOwner.AddThread(Self); +end; + +destructor TDownloadThread.Destroy; +begin + FOwner.RemoveThread(Self); + FHTTP.Free; + inherited Destroy; +end; + +{ TCheckUpdateThread } + +procedure TCheckUpdateThread.RemoveThread(const T: TDownloadThread); +begin + EnterCriticalsection(FThreadsCS); + try + FThreads.Remove(T); + finally + LeaveCriticalsection(FThreadsCS); + end; +end; + +procedure TCheckUpdateThread.AddThread(const T: TDownloadThread); +begin + EnterCriticalsection(FThreadsCS); + try + FThreads.Add(T); + finally + LeaveCriticalsection(FThreadsCS); + end; +end; + +procedure TCheckUpdateThread.SyncStartChecking; +begin + FOwner.btCheckUpdate.Caption := RS_Checking; + FOwner.btCheckUpdateTerminate.Show; + FOwner.tmRepaintList.Enabled := True; +end; + +procedure TCheckUpdateThread.SyncFinishChecking; +begin + FOwner.btCheckUpdate.Caption := RS_FinishChecking; + FOwner.vtLuaModulesRepos.BeginUpdate; + try + FMainRepos := FOwner.Repos; + FOwner.Repos := FRepos; + FOwner.ReinitList; + finally + FOwner.vtLuaModulesRepos.EndUpdate; + end; +end; + +procedure TCheckUpdateThread.SyncStartDownload; +begin + FOwner.btCheckUpdate.Caption := RS_StartDownloading; +end; + +procedure TCheckUpdateThread.SyncFinishDownload; +begin + FOwner.btCheckUpdate.Caption := RS_FinishDownload; +end; + +procedure TCheckUpdateThread.SyncFinal; +begin + FOwner.btCheckUpdateTerminate.Hide; + FOwner.btCheckUpdate.Caption := RS_CheckUpdate; + FOwner.ThreadCheck := nil; + FOwner.tmRepaintList.Enabled := False; + if FMainRepos <> nil then + try + FOwner.vtLuaModulesRepos.BeginUpdate; + FOwner.Repos := FMainRepos; + FOwner.ReinitList; + FMainRepos.SaveToFile(LUA_WEBSITEMODULE_REPOS); + finally + FOwner.vtLuaModulesRepos.EndUpdate; + end; +end; + +function TCheckUpdateThread.SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Boolean; +var + i, j, imax, jmax, k, inew, iupdate: Integer; + newfound: Boolean; + m, u: TLuaModuleRepo; +begin + i := 0; + j := 0; + inew := 0; + iupdate := 0; + imax := ARepos.Items.Count; + jmax := AReposUp.Items.Count; + while (i < imax) or (j < jmax) do + begin + if i < imax then + m := ARepos[i] + else + m := nil; + if j < jmax then + u := AReposUp[j] + else + u := nil; + + if (m <> nil) and (u <> nil) then + begin + if u.SyncTo(m) then // look for new update + begin + Inc(i); + Inc(j); + if m.flag = fUpdate then + Inc(iupdate); + end + else + begin // scan remote ARepos till end + newfound := False; + for k := j + 1 to jmax - 1 do + begin + if m.name = AReposUp[k].name then // j to k-1 is new + begin + newfound := True; + Break; + end; + end; + if newfound then // add new + begin + for k := j to k - 1 do + begin + m := AReposUp[k].Clone; + m.flag := fNew; + ARepos.Add(m); + Inc(inew); + end; + j := k + 1; + end + else // current is marked to delete + begin + m.flag := fDelete; + Inc(iupdate); + Inc(i); + end; + end; + end + else + if m = nil then // new found + begin + m := u.Clone; + m.flag := fNew; + ARepos.Add(m); + Inc(inew); + Inc(j); + end + else + begin // current is marked to delete + m.flag := fDelete; + Inc(iupdate); + Inc(i); + end; + end; + if inew <> 0 then + ARepos.Items.Sort; + Result := inew + iupdate <> 0; +end; + +procedure TCheckUpdateThread.Download; +var + i, imax: Integer; + m: TLuaModuleRepo; + f: String; +begin + Synchronize(@SyncStartDownload); + sleep(2000); + + i := 0; + imax := FRepos.Items.Count; + while i < imax do + begin + m := FRepos[i]; + if m.flag = fDelete then + begin + f := LUA_WEBSITEMODULE_FOLDER + m.name; + if FileExists(f) then + DeleteFile(f); + m.flag := fDeleted; + Inc(i); + end + else + if not (m.flag in [fNew, fUpdate, fFailedDownload]) then + Inc(i) + else + begin + while FThreads.Count >= OptionMaxThreads do + Sleep(SOCKHEARTBEATRATE); + if Terminated then + Break; + TDownloadThread.Create(Self, FRepos[i]); + Inc(i); + end; + end; + + while FThreads.Count <> 0 do + begin + if Terminated then + Break; + Sleep(SOCKHEARTBEATRATE); + end; + + EnterCriticalsection(FThreadsCS); + try + for i := 0 to FThreads.Count - 1 do + begin + TDownloadThread(FThreads[i]).Terminate; + end; + finally + LeaveCriticalsection(FThreadsCS); + end; + + while FThreads.Count <> 0 do + Sleep(SOCKHEARTBEATRATE); + Synchronize(@SyncFinishDownload); +end; + +procedure TCheckUpdateThread.Execute; +var + foundupdate: Boolean; + i, imax: Integer; + m: TLuaModuleRepo; + trepos: TLuaModulesRepos; +begin + Synchronize(@SyncStartChecking); + if FHTTP.GET(LuaModulesURLJSON) then + begin + FReposUp := TLuaModulesRepos.Create; + FReposUp.LoadFromRemote(FHTTP); + if FHTTP.GET(LuaModulesURLHTML) then + FReposUp.LoadFromRemoteHTML(FHTTP); + end; + + if not Terminated then + begin + // check + FRepos := FOwner.Repos.Clone; + foundupdate := SyncRepos(FRepos, FReposUp); + + // look for previously failed download + for i := 0 to FRepos.Items.Count - 1 do + if FRepos[i].flag = fFailedDownload then + begin + foundupdate := True; + break; + end; + + Synchronize(@SyncFinishChecking); + if foundupdate and (not Terminated) then + begin + Sleep(500); + if not Terminated then + begin + Download; + end; + end; + + // cleanup + i := 0; + imax := FRepos.Items.Count; + while i < imax do + begin + m := FRepos[i]; + if m.flag = fDeleted then + begin + FRepos.Items.Delete(i); + Dec(imax); + end + else + begin + if m.flag in [fNew, fUpdate, fFailedDownload] then + m.flag := fFailedDownload + else + m.flag := fNone; + Inc(i); + end; + end; + trepos := FMainRepos; + FMainRepos := FRepos; + FRepos := trepos; + end; + + if not Terminated then + Sleep(1000); + Synchronize(@SyncFinal); +end; + +constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); +begin + inherited Create(False); + InitCriticalSection(FThreadsCS); + FOwner := AOwner; + FHTTP := THTTPSendThread.Create(Self); + FThreads := TFPList.Create; +end; + +destructor TCheckUpdateThread.Destroy; +begin + if Assigned(FRepos) then + FRepos.Free; + if Assigned(FReposUp) then + FReposUp.Free; + FThreads.Free; + FHTTP.Free; + DoneCriticalsection(FThreadsCS); + inherited Destroy; +end; + +{$R *.lfm} + +{ TLuaModulesUpdaterForm } + +procedure TLuaModulesUpdaterForm.btCheckUpdateClick(Sender: TObject); +begin + if btCheckUpdate.Caption = RS_CheckUpdate then + CheckUpdate; +end; + +procedure TLuaModulesUpdaterForm.FormCreate(Sender: TObject); +begin + AddVT(vtLuaModulesRepos); + InitCriticalSection(FListCS); + Repos := TLuaModulesRepos.Create; + btCheckUpdate.Caption := RS_CheckUpdate; + btCheckUpdateTerminate.Hide; + vtLuaModulesRepos.NodeDataSize := SizeOf(TLuaModuleRepo); + LoadLocalRepos; +end; + +procedure TLuaModulesUpdaterForm.FormDestroy(Sender: TObject); +begin + if ThreadCheck <> nil then + begin + ThreadCheck.Terminate; + ThreadCheck.WaitFor; + end; + Repos.Free; + DoneCriticalsection(FListCS); + RemoveVT(vtLuaModulesRepos); +end; + +procedure TLuaModulesUpdaterForm.btCheckUpdateTerminateClick(Sender: TObject); +begin + ThreadCheck.Terminate; +end; + +procedure TLuaModulesUpdaterForm.tmRepaintListTimer(Sender: TObject); +begin + if FListDirty then + begin + vtLuaModulesRepos.Repaint; + EnterCriticalsection(FListCS); + try + FListDirty := False; + finally + LeaveCriticalsection(FListCS); + end; + end; +end; + +procedure TLuaModulesUpdaterForm.vtLuaModulesReposCompareNodes(Sender: TBaseVirtualTree; + Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +var + m1, m2: TLuaModuleRepo; +begin + m1 := PLuaModuleRepo(Sender.GetNodeData(Node1))^; + m2 := PLuaModuleRepo(Sender.GetNodeData(Node2))^; + case Column of + 0: Result := AnsiCompareStr(m1.name, m2.name); + 1: + begin + if m1.last_modified > m2.last_modified then + Result := 1 + else + Result := -1; + end; + 2: Result := AnsiCompareStr(m1.last_message, m2.last_message); + end; +end; + +procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetHint(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; + var HintText: String); +begin + with PLuaModuleRepo(Sender.GetNodeData(Node))^ do + begin + case Column of + 0: HintText := name; + 1: HintText := DateTimeToStr(last_modified); + 2: HintText := last_message; + end; + end; +end; + +procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); +begin + if Column <> 0 then + Exit; + ImageIndex := Integer(PLuaModuleRepo(Sender.GetNodeData(Node))^.flag) - 1; +end; + +procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +begin + with PLuaModuleRepo(Sender.GetNodeData(Node))^ do + begin + case Column of + 0: CellText := name; + 1: CellText := DateTimeToStr(last_modified); + 2: CellText := last_message; + end; + end; +end; + +{$if VTMajorVersion < 5} +procedure TLuaModulesUpdaterForm.vtLuaModulesReposHeaderClick(Sender: TVTHeader; + Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +{$else} +procedure TLuaModulesUpdaterForm.vtLuaModulesReposHeaderClick(Sender: TVTHeader; + HitInfo: TVTHeaderHitInfo); +var + Column: TColumnIndex; + Button: TMouseButton; +{$endif} +begin + {$if VTMajorVersion >= 5} + Column := HitInfo.Column; + Button := HitInfo.Button; + {$endif} + if Sender.SortColumn <> Column then + Sender.SortColumn := Column + else + if Sender.SortDirection = sdAscending then + Sender.SortDirection := sdDescending + else + Sender.SortDirection := sdAscending; + SortList; +end; + +procedure TLuaModulesUpdaterForm.ListDirty; +begin + if TryEnterCriticalsection(FListCS) <> 0 then + try + FListDirty := True; + finally + LeaveCriticalsection(FListCS); + end; +end; + +procedure TLuaModulesUpdaterForm.CheckUpdate; +begin + ThreadCheck := TCheckUpdateThread.Create(Self); +end; + +procedure TLuaModulesUpdaterForm.LoadLocalRepos; +begin + Repos.LoadFromFile(LUA_WEBSITEMODULE_REPOS); + ReinitList(False); +end; + +procedure TLuaModulesUpdaterForm.ReinitList(const ASort: Boolean); +var + i: Integer; +begin + vtLuaModulesRepos.Clear; + for i := 0 to Repos.Items.Count - 1 do + vtLuaModulesRepos.AddChild(nil, Repos[i]); + if ASort then + SortList; +end; + +procedure TLuaModulesUpdaterForm.SortList; +begin + with vtLuaModulesRepos do + Sort(nil, Header.SortColumn, Header.SortDirection, False); +end; + +end. diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 0be5641dc..603f0015d 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -16,7 +16,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.8.0.6' + LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -116,12 +116,16 @@ object MainForm: TMainForm AllowZoom = False AxisList = < item + Marks.LabelBrush.Style = bsClear Minors = <> Title.LabelFont.Orientation = 900 + Title.LabelBrush.Style = bsClear end item Alignment = calBottom + Marks.LabelBrush.Style = bsClear Minors = <> + Title.LabelBrush.Style = bsClear end> AxisVisible = False BackColor = clDefault @@ -4157,11 +4161,11 @@ object MainForm: TMainForm ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 object pcWebsiteOptions: TPageControl Left = 4 - Height = 376 + Height = 356 Top = 8 Width = 745 ActivePage = tsWebsiteSelection @@ -4170,11 +4174,11 @@ object MainForm: TMainForm TabOrder = 0 object tsWebsiteSelection: TTabSheet Caption = 'Websites' - ClientHeight = 348 + ClientHeight = 328 ClientWidth = 737 object vtOptionMangaSiteSelection: TVirtualStringTree Left = 0 - Height = 313 + Height = 293 Top = 35 Width = 737 Align = alClient @@ -4315,11 +4319,11 @@ object MainForm: TMainForm end object tsWebsiteOptions: TTabSheet Caption = 'Options' - ClientHeight = 348 + ClientHeight = 328 ClientWidth = 737 object sbWebsiteOptions: TScrollBox Left = 0 - Height = 348 + Height = 328 Top = 0 Width = 737 HorzScrollBar.Increment = 1 @@ -4340,6 +4344,9 @@ object MainForm: TMainForm ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 end + object tsWebsiteModules: TTabSheet + Caption = 'Modules' + end end end object tsAccounts: TTabSheet @@ -4866,84 +4873,12 @@ object MainForm: TMainForm object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 - 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 - 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF - FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 - C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 - C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 - C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 - C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A - C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B - C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B - D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 - DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 - E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 7 OnClick = miDownloadStopClick end object miDownloadResume: TMenuItem Caption = 'Resume' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 - 000000000001000000070000000E000000150000001A0000001A0000001A0000 - 001A0000001A0000001A000000160000000F0000000800000002000000000000 - 0000000000020000000E0000001C0000002A000000330000003300000033733A - 02A663320274000000330000002B0000001D0000000F00000003000000000000 - 0000000000000000000000000000000000000000000000000000281502009D52 - 06CC9D5206CC763E055C29160300000000000000000000000000B0651400A85D - 0E00A85D0E00553008007F470C00A85D0E007F470C00A85D0E00A65B0D00A358 - 0BCCFFB914FFA3580BCCA4590C5C7F470C002C19050000000000B4691700AA5F - 1000AA5F10CCAB601100AB601199AA5F10CCAB601199AA5F10CCAB601199AA5F - 10CCFFB810FFFFBB1BFFAA5F10CCAB60115CB1661600B96E1C00B76C1A00AF64 - 1400AF641400B3681700B16616CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B4 - 24FFF5AF18FFF5AB0EFFF7B92EFFB16616CCB267175CB96E1C00B96E1CCCBA6F - 1D00BA6F1D99B96E1CCCB96E1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA96 - 27F5E19E29FFE19E29FFE19E29FFEAB349FFB96E1CCCBA6F1D5CBF742000C378 - 2300C27722CCF8D084FFC27722CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D396 - 44FFD09341FFD09341FFD39644FFD89B49FFECBB6CFFC27722CCCB802999CA7F - 28CCCA7F28CCCA7F28CCCA7F28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE - 61FAEEB266FFEEB266FFEEB266FFF7CC80FFCA7F28CCC97E275CD2872ECCFBD9 - 8DFFD2872ECCD0852C00D2872ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C9 - 7DFFF4C175FFF2B96DFFFAD68AFFD2872ECCD1862D5CCA7F2800D88D3399D98E - 33CCD88D3399D78C3200D88D3399D98E33CCD88D3399D98E33CCD98E33CCD98E - 33CCFBD488FFFEDF93FFD98E33CCD88D335CD2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DA8F3400DC913600E095 - 38CCFFE498FFE09538CCDF94385CD98E3300D2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DD923700E59A3C00E59A - 3CCCE59A3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800D98E3300DA8F - 3400D98E3300D78C3200D98E3300DA8F3400D98E3300E89D3F00E89D3F00E99E - 4099E99E405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 12 OnClick = miDownloadResumeClick end @@ -4959,42 +4894,6 @@ object MainForm: TMainForm object miDownloadDelete: TMenuItem Caption = 'Delete' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 9 object miDownloadDeleteTask: TMenuItem Caption = 'Task only' @@ -5022,42 +4921,6 @@ object MainForm: TMainForm object miDownloadMergeCompleted: TMenuItem Caption = 'Merge completed tasks' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 - 000200000005000000090000000D0000001100000015000000180000001A0000 - 001A0000001A0000001A0000001A000000170000000F00000005000000000000 - 00040000000A0000001100000019000000220000002A00000030000000330000 - 003300000033733B03A6633303740000002E0000001D0000000A532E0700522D - 0600522D0600522D0600522D0600522D0600522D0600522D0600522D0600522D - 0600522D06009F5408CC9F5408CC783F065C2917030000000000A75C0E99A65B - 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B - 0DCCA65B0DCCA65B0DCCFFB508FFA65B0DCCA75C0E5C824A0E00AF6414CCF9C6 - 60FFFFBE23FFFFBD1FFFFFBC1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB7 - 0FFFFFB70DFFFFB60BFFFFB200FFFFB609FFAF6414CCAF641448B96E1BCCF6CB - 7FFFF8C051FFF9BD36FFF8B92CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B5 - 23FFF7B523FFF7B421FFF5AB0EFFF6B11BFFB96E1BCCB96E1B48C1762199C277 - 22CCC27722CCC27722CCD5973FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C - 26CFC27722CCC27722CCE6A93CFFC27722CCC176215CBB701C00C2772200C479 - 2400CC812A2BD38E38CEF0BF71FBE0A856FFDCA04CE4CC8129AACB80283FC97E - 270FC77C2600CC8129CCCC8129CCCB80285CC2772200BB701C00CD822A00D58A - 3000D58A307BEBB865E8F7C579FFF0C070EFD58A30AAD0852D13CC812900C97E - 2700D2872E00D4892F99D4892F5CCC812900C2772200BB701C00DD923600DD92 - 3600DD9236AAF8D081F6FCD185FFE7A951D9DC91363FDB903500CC812900C97E - 2700D2872E00D58A3000D58A3000CC812900C2772200BB701C00E4993B00E499 - 3B00E4993BC5FEDF92FDFFDF93FFE69E42CFE4993B0FE4993B00E4993B00D085 - 2D00D2872E00D58A3000D58A3000CC812900C2772200BB701C00E89D3E00E89D - 3E00E99E3F99E99E3FCCE99E3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C - 3200D2872E00D58A3000D58A3000CC812900C2772200BB701C00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 10 OnClick = miDownloadMergeCompletedClick end @@ -5067,126 +4930,18 @@ object MainForm: TMainForm object miDownloadViewMangaInfo: TMenuItem Caption = 'View manga info' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000030000 - 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B - 0B7A090909650505054200000032000000270000001300000003000000020000 - 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA - DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 - 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 - 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F - 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 - 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 - 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 - 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA - AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 - 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF - CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 - 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC - CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B - 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF - CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 - 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC - DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 - 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF - BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 - 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C - 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F - 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E - 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E - 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 - 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C - 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 - 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA - EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 - 50005252520053535300545454155555553E5555555555555563555555635555 - 55555555553E545454155353530052525200505050004F4F4F00 - } ImageIndex = 0 OnClick = miDownloadViewMangaInfoClick end object miDownloadOpenFolder: TMenuItem Caption = 'Open Folder' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 4 OnClick = miDownloadOpenFolderClick end object miDownloadOpenWith: TMenuItem Caption = 'Open ...' Enabled = False - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00000000000000000000000000100000001A0000001000000000000000000000 - 00000000000000000000000000000000000000000000000000001007000F220E - 00352A110048000000620000008F000000ED0000008F000000622A110048200D - 003A130800300703002A050200290502002906030023020100095322009A8550 - 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 - 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 - B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 - B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF - FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 - EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B - A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 - DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 - D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE - FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 - F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF - E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F - 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F - 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D - } ImageIndex = 11 OnClick = miDownloadOpenWithClick end @@ -5255,83 +5010,11 @@ object MainForm: TMainForm top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 002C00000087000000E7702E00C7702E00C7702E00C7702E00C7702E00C7702E - 00C7702E00C72D5500E9175F00F4124A00C40000002C00000000000000090000 - 0016000000DB606060FFCA9764FFC5925FFFC5925FFFC5925FFFC5925FFFC592 - 5FFFC5925FFF318613FF2BDF1AFF1E7700F20000001600000009000000000101 - 0100010101CE626262FFC89562FFBD8A57FFBF8C59FFBF8C59FFBF8C59FF548D - 24FF318C12FF318C11FF3DE22CFF208100F00E8C00CC0E8D0099010101000101 - 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFF3394 - 12FF52E741FF52E741FF52E741FF52E741FF52E741FF109500CC010101000101 - 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFFC4915EFF5A98 - 26FF369B13FF359A12FF66EB55FF249000EF129D00CC129C0099010101000101 - 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC89562FFC895 - 62FFC89562FF369F12FF75EE64FF269700EE179E0000129D0000010101000101 - 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFCB98 - 65FFCB9865FF599D24FF3BA816FF448700DC6072000056730000010101000101 - 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFCF9C - 69FFCF9C69FFBF8C59FFD8A572FF9B4B00A59B4B00009B4B0000010101000101 - 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F - 6CFFD29F6CFFBE8B58FFDBA875FF9E4D00A39E4D00009E4D0000010101000101 - 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 - 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 - 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 - 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 - 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 - 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 - 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 - 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 - 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 - 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 - 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 - E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 - 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 - 0099AA550099AA550099AA550099AA550073AA550000AA550000 - } ImageIndex = 21 OnClick = miFavoritesCheckNewChapterClick end object miFavoritesStopCheckNewChapter: TMenuItem Caption = 'Stop check for new chapter' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 - 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 - 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF - FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 - C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 - C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 - C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 - C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A - C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B - C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B - D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 - DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 - E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B - CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 7 OnClick = miFavoritesStopCheckNewChapterClick end @@ -5345,84 +5028,12 @@ object MainForm: TMainForm end object miFavoritesViewInfos: TMenuItem Caption = 'View manga info' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000030000 - 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B - 0B7A090909650505054200000032000000270000001300000003000000020000 - 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA - DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 - 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 - 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F - 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 - 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 - 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 - 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA - AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 - 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF - CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 - 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC - CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B - 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF - CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 - 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC - DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 - 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF - BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 - 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C - 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F - 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E - 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E - 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 - 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C - 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 - 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA - EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 - 50005252520053535300545454155555553E5555555555555563555555635555 - 55555555553E545454155353530052525200505050004F4F4F00 - } ImageIndex = 0 SubMenuImages = IconList OnClick = miFavoritesViewInfosClick end object miFavoritesDownloadAll: TMenuItem Caption = 'Download all' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 - } ImageIndex = 1 OnClick = miFavoritesDownloadAllClick end @@ -5439,42 +5050,6 @@ object MainForm: TMainForm end object miFavoritesDelete: TMenuItem Caption = 'Delete' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 9 SubMenuImages = IconList OnClick = miFavoritesDeleteClick @@ -5493,84 +5068,12 @@ object MainForm: TMainForm end object miFavoritesOpenFolder: TMenuItem Caption = 'Open Folder' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 - 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D - 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF - F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB - EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF - EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 - E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 - F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC - EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 - F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 - EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB - F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 - F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 - F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA - F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 - F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF - F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 - FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 - FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED - FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC - DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 - FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 - FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 - CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 - F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 - CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 - CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 4 SubMenuImages = IconList OnClick = miFavoritesOpenFolderClick end object miFavoritesOpenWith: TMenuItem Caption = 'Open ...' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000000000 - 00000000000000000000000000100000001A0000001000000000000000000000 - 00000000000000000000000000000000000000000000000000001007000F220E - 00352A110048000000620000008F000000ED0000008F000000622A110048200D - 003A130800300703002A050200290502002906030023020100095322009A8550 - 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 - 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 - B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 - B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF - FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 - EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B - A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 - DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 - D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE - FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE - ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE - FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 - E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 - F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF - E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F - 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F - 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D - } ImageIndex = 11 OnClick = miFavoritesOpenWithClick end @@ -5582,126 +5085,18 @@ object MainForm: TMainForm top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 - 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 - 0000000000040000001B481F1546B24C3399E96443D4EE6644F5EE6644F5E964 - 43D4B24C3399471F15470000001F0000000600000000FFFFFF00FFFFFF007432 - 210077332200B34D3360EF6F4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1 - C9FFF4A18EFFEF6E4EEBB34D33603C1A110000000000FFFFFF00FFFFFF00E863 - 4100EE664460EF7659F9F7D4CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8 - E8FFF7E9E9FFF6D1CAFFEF7658F9EE664460E8634100FFFFFF00FFFFFF00E360 - 3E20E66A4AEBF3D3CDFFF0E5E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4 - E4FFEFE4E4FFEFE4E4FFEFCDC7FFE66A4AEBE3603E20FFFFFF00FFFFFF00D659 - 3787E59D8AFFEAE2E2FFE7DFDFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DF - DFFFE7DFDFFFE7DFDFFFE8E0E0FFE19784FFD6593787FFFFFF00FFFFFF00C550 - 2ED0EAD0C8FFE1DADAFFE0D9D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9 - D9FFE0D9D9FFE0D9D9FFE0D9D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00B748 - 26F5F4EEEDFFE7E5E5FFDAD6D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4 - D4FFD8D4D4FFD8D4D4FFD8D4D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00AD44 - 22F5F4EFEDFFEEEEEEFFEAEAEAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0 - D0FFD2D0D0FFD2D0D0FFD2D0D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00AB46 - 24D0EAD5CDFFF0F0F0FFF0F0F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1 - D1FFCECECEFFCECECEFFD2D1D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00B34F - 2D87D49D8AFFF5F5F5FFF3F3F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3 - F3FFF3F3F3FFF3F3F3FFF5F5F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00BF5C - 3A20C56747EBF2DFD9FFF8F8F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7 - F7FFF7F7F7FFF8F8F8FFF2DFD9FFC56747EBBF5C3A20FFFFFF00FFFFFF00C461 - 3F00CF6B4960D77F61F9F6E3DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB - FBFFFCFCFCFFF6E3DCFFD77F61F9CF6B4960C4613F00FFFFFF00FFFFFF00C461 - 3F00D16D4B00DF7A5860E38464EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4 - DDFFEFB7A4FFE38464EBDF7A5860D16D4B00C4613F00FFFFFF00FFFFFF00C461 - 3F00D16D4B00E17C5A00EA846220EC866487EC8664D0EC8664F5EC8664F5EC86 - 64D0EC866487EA846220E17C5A00D16D4B00C4613F00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 13 SubMenuImages = IconList OnClick = miMangaListViewInfosClick end object miMangaListDownloadAll: TMenuItem Caption = 'Download all' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000120000 - 002C0D0D0D581212128512121285121212851212128512121285121212851212 - 12851212128512121285121212850D0D0D580000002C00000012000000090000 - 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 - C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B - 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 - 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 - 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD - DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D - 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 - B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F - 4F005151510D5454545A54545467545454675454546754545467545454675454 - 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F - 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 - 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F - 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 - 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F - 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 - 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F - 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 - 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F - 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD - 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 - 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 - 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 - 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 - 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E - 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 - 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 - 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E - 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E - 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 - } ImageIndex = 1 SubMenuImages = IconList OnClick = miMangaListDownloadAllClick end object miMangaListAddToFavorites: TMenuItem Caption = 'Add to Favorites' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000000000050000 - 001E0000003200009CC9000054630000002E0000002B00000026000000220000 - 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 - 000F000000190000A8C50000A8C500006D580000001600000013000000110000 - 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 - 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D - 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 - BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 - 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 - C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C - 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 - C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 - 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 - C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 - CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 - C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 - FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 - C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 - F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 - C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A - F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 - C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C - F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 - C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E - FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 - 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 - DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 - 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 - E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 - 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 - E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 - 0000000000000000990000002B00000000000000000001016E000101DE000101 - E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 - } ImageIndex = 2 SubMenuImages = IconList OnClick = miMangaListAddToFavoritesClick diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index eff3e88b8..a4e93d740 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -242,6 +242,7 @@ {"hash":32777246,"name":"tmainform.edwebsitessearch.texthint","sourcebytes":[83,101,97,114,99,104,32,119,101,98,115,105,116,101,46,46,46],"value":"Search website..."}, {"hash":108725763,"name":"tmainform.tswebsiteoptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, {"hash":197676484,"name":"tmainform.tswebsiteadvanced.caption","sourcebytes":[65,100,118,97,110,99,101,100],"value":"Advanced"}, +{"hash":73122451,"name":"tmainform.tswebsitemodules.caption","sourcebytes":[77,111,100,117,108,101,115],"value":"Modules"}, {"hash":161923523,"name":"tmainform.tsaccounts.caption","sourcebytes":[65,99,99,111,117,110,116,115],"value":"Accounts"}, {"hash":344211,"name":"tmainform.tsmisc.caption","sourcebytes":[77,105,115,99],"value":"Misc"}, {"hash":197593650,"name":"tmainform.tscustomcolor.caption","sourcebytes":[67,117,115,116,111,109,32,99,111,108,111,114],"value":"Custom color"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c13fbacc0..ce0ae46cf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -16,14 +16,14 @@ interface {$else} FakeActiveX, {$endif} - Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, - ExtCtrls, ComCtrls, Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, - simpleipc, lclproc, types, LCLIntf, DefaultTranslator, EditBtn, PairSplitter, - MultiLog, FileChannel, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, - TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, - uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, uGetMangaInfosThread, - frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, frmWebsiteOptionAdvanced, - frmCustomColor, frmLogger, frmTransferFavorites, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LCLType, ExtCtrls, ComCtrls, + Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, types, LCLIntf, + DefaultTranslator, EditBtn, PairSplitter, MultiLog, FileChannel, FileUtil, LazUTF8Classes, + TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, + uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, + uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, + frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, frmTransferFavorites, + frmLuaModulesUpdater, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, SimpleException; type @@ -152,6 +152,7 @@ TMainForm = class(TForm) btDownloadSplit: TSpeedButton; seOptionRetryFailedTask: TSpinEdit; seWebPJpegQuality: TSpinEdit; + tsWebsiteModules: TTabSheet; ToolBarDownloadLeft: TToolBar; tbmiDownloadMoveTop: TToolButton; tbmiDownloadMoveUp: TToolButton; @@ -1274,11 +1275,22 @@ procedure TMainForm.FormCreate(Sender: TObject); Show; if Screen.PixelsPerInch > 96 then AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); - AddVT(Self.vtMangaList); - AddVT(Self.clbChapterList); - AddVT(Self.vtDownload); - AddVT(Self.vtFavorites); - AddVT(Self.vtOptionMangaSiteSelection); + end; + AddVT(Self.vtMangaList); + AddVT(Self.clbChapterList); + AddVT(Self.vtDownload); + AddVT(Self.vtFavorites); + AddVT(Self.vtOptionMangaSiteSelection); + + LuaModulesUpdaterForm := TLuaModulesUpdaterForm.Create(Self); + with LuaModulesUpdaterForm do + begin + Parent := tsWebsiteModules; + BorderStyle := bsNone; + Align := alClient; + Show; + if Screen.PixelsPerInch > 96 then + AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); end; // logger @@ -1405,7 +1417,7 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; - Logger.Send(Self.ClassName+'.CloseNow, closing other forms'); + Logger.Send(Self.ClassName+'.CloseNow, closSaveFormInformationing other forms'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; @@ -1653,7 +1665,10 @@ procedure TMainForm.tmCheckFavoritesTimer(Sender: TObject); if IsDlgCounter then Exit; tmCheckFavorites.Enabled := False; if OptionAutoCheckLatestVersion then + begin btCheckLatestVersionClick(btCheckLatestVersion); + LuaModulesUpdaterForm.btCheckUpdateClick(LuaModulesUpdaterForm.btCheckUpdate); + end; FavoriteManager.isAuto := True; FavoriteManager.CheckForNewChapter; end; @@ -1823,7 +1838,10 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if OptionAutoCheckLatestVersion then + begin btCheckLatestVersionClick(btCheckLatestVersion); + LuaModulesUpdaterForm.btCheckUpdateClick(LuaModulesUpdaterForm.btCheckUpdate); + end; if OptionAutoCheckFavStartup then begin FavoriteManager.isAuto := True; @@ -5603,6 +5621,16 @@ procedure TMainForm.LoadFormInformation; DLManager.SortDirection := ReadBool('misc', 'SortDownloadDirection', False); vtDownload.Header.SortColumn := DLManager.SortColumn; vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); + + // lua website modules list + with LuaModulesUpdaterForm.vtLuaModulesRepos.Header do + begin + SortColumn := ReadInteger('websitemodules', 'SortColumn', SortColumn); + SortDirection := TSortDirection(ReadInteger('websitemodules', 'SortDirection', Integer(SortDirection))); + for i := 0 to Columns.Count - 1 do + Columns[i].Width := ReadInteger('websitemodules', 'Column' + IntToStr(i) + 'Width', Columns[i].Width); + LuaModulesUpdaterForm.SortList; + end; end; end; @@ -5639,6 +5667,15 @@ procedure TMainForm.SaveFormInformation; WriteInteger('misc', 'SortFavoritesColumn', vtFavorites.Header.SortColumn); WriteBool('misc', 'SortFavoritesDirection', FavoriteManager.sortDirection); + + // lua website modules list + with LuaModulesUpdaterForm.vtLuaModulesRepos.Header do + begin + WriteInteger('websitemodules', 'SortColumn', SortColumn); + WriteInteger('websitemodules', 'SortDirection', Integer(SortDirection)); + for i := 0 to Columns.Count - 1 do + WriteInteger('websitemodules', 'Column' + IntToStr(i) + 'Width', Columns[i].Width); + end; end; end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index a18deb6f5..f60b5098e 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -73,6 +73,29 @@ msgstr "Importierung abgeschlossen." msgid "List of unimported manga" msgstr "Liste von nicht importierten Manga" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Prüfe..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Alle Downloads" @@ -88,6 +111,7 @@ msgid "Cancel" msgstr "Abbrechen" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Prüfe..." @@ -544,6 +568,23 @@ msgstr "Pfad zur Software (z.B. C:\\MangaDownloader)" msgid "Software:" msgstr "Software:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Aktualisierungsliste abbrechen" @@ -1947,6 +1988,10 @@ msgstr "Anzeige" msgid "Advanced" msgstr "Erweitert" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index b153d4af9..9286ac7bb 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -77,6 +77,29 @@ msgstr "Η εισαγωγή ολοκληρώθηκε." msgid "List of unimported manga" msgstr "Λίστα μη εισηγμένων manga" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Έλεγχος..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Όλες οι λήψεις" @@ -92,6 +115,7 @@ msgid "Cancel" msgstr "Άκυρο" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Έλεγχος..." @@ -548,6 +572,23 @@ msgstr "Διαδρομή του προγράμματος (π.χ. C:\\MangaDownlo msgid "Software:" msgstr "Πρόγραμμα:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Ματαίωση ενημέρωσης λίστας" @@ -2002,6 +2043,10 @@ msgstr "Προβολή" msgid "Advanced" msgstr "Προηγμένες" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d753e6838..3ce754931 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -61,6 +61,29 @@ msgstr "Import completed." msgid "List of unimported manga" msgstr "List of unimported manga" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Checking..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "All downloads" @@ -76,6 +99,7 @@ msgid "Cancel" msgstr "Cancel" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Checking..." @@ -535,6 +559,23 @@ msgstr "Path to the software (e.g. C:\\MangaDownloader)" msgid "Software:" msgstr "Software:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Abort update list" @@ -1923,6 +1964,10 @@ msgstr "View" msgid "Advanced" msgstr "Advanced" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" msgid "Options" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index c0e2d5fe9..e7fa083da 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -72,6 +72,29 @@ msgstr "Importar completado." msgid "List of unimported manga" msgstr "Lista de manga sin importar" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Revisando..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Todas las descargas" @@ -87,6 +110,7 @@ msgid "Cancel" msgstr "Cancelar" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Revisando..." @@ -536,6 +560,23 @@ msgstr "Ruta al Software (e.g. C:\\MangaDownloader)" msgid "Software:" msgstr "Software:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Abortar Actualizar Lista" @@ -1924,6 +1965,10 @@ msgstr "Ver" msgid "Advanced" msgstr "Avanzado" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 65ce453c7..b66076c9e 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -72,6 +72,29 @@ msgstr "Selesai mengimpor." msgid "List of unimported manga" msgstr "Daftar komik yang tidak bisa di-impor" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Memeriksa..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Semua unduhan" @@ -87,6 +110,7 @@ msgid "Cancel" msgstr "Batal" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Memeriksa..." @@ -536,6 +560,23 @@ msgstr "Path ke perangkat lunak (misalnya C:\\MangaDownloader)" msgid "Software:" msgstr "Perangkat lunak:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Batalkan pembaruan daftar komik" @@ -1924,6 +1965,10 @@ msgstr "Tampilan" msgid "Advanced" msgstr "Lanjutan" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index c746c27e6..91d306172 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -73,6 +73,29 @@ msgstr "Importowanie zakończone." msgid "List of unimported manga" msgstr "Lista niezaimportowanych mang" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Sprawdzanie..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Wszystkie pobrania" @@ -88,6 +111,7 @@ msgid "Cancel" msgstr "Anuluj" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Sprawdzanie..." @@ -544,6 +568,23 @@ msgstr "Ścieżka do programu (np C:\\MangaDownloader)" msgid "Software:" msgstr "Oprogramowanie:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Przerwij aktualizacje list" @@ -1949,6 +1990,10 @@ msgstr "Wygląd" msgid "Advanced" msgstr "Zaawansowane" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 48240c8ab..dcd3d5943 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -54,6 +54,28 @@ msgstr "" msgid "List of unimported manga" msgstr "" +#: frmluamodulesupdater.rs_checking +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "" + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "" @@ -69,6 +91,7 @@ msgid "Cancel" msgstr "" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "" @@ -500,6 +523,23 @@ msgstr "" msgid "Software:" msgstr "" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "" @@ -1854,6 +1894,10 @@ msgstr "" msgid "Advanced" msgstr "" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" msgid "Options" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 8be8b87b8..8d987c268 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -73,6 +73,29 @@ msgstr "Importação concluída." msgid "List of unimported manga" msgstr "Lista de mangás não importados" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Checando..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Todos os downloads" @@ -88,6 +111,7 @@ msgid "Cancel" msgstr "Cancelar" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Checando..." @@ -543,6 +567,23 @@ msgstr "Caminho para o software (e.g. C:\\MangaDownloader)" msgid "Software:" msgstr "Software:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Abortar atualizações das lista" @@ -1945,6 +1986,10 @@ msgstr "Exibir" msgid "Advanced" msgstr "Avançado" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 545a5cfc1..3b1891af1 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -71,6 +71,29 @@ msgstr "Импорт завершен." msgid "List of unimported manga" msgstr "Список неимпортированной манги" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Проверка..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Все загрузки" @@ -86,6 +109,7 @@ msgid "Cancel" msgstr "Отмена" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Проверка..." @@ -545,6 +569,23 @@ msgstr "Путь к программе (пример: C:\\MangaDownloader)" msgid "Software:" msgstr "Программа:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Прервать обновление списка" @@ -1933,6 +1974,10 @@ msgstr "Вид" msgid "Advanced" msgstr "Расширенные" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" msgid "Options" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 1cd2ad286..d106955c5 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -74,6 +74,29 @@ msgstr "İçe aktarma tamamlandı." msgid "List of unimported manga" msgstr "İçe aktarılmayan manga listesi" +#: frmluamodulesupdater.rs_checking +#, fuzzy +msgctxt "frmluamodulesupdater.rs_checking" +msgid "Checking..." +msgstr "Kontrol ediliyor..." + +#: frmluamodulesupdater.rs_checkupdate +msgctxt "frmluamodulesupdater.rs_checkupdate" +msgid "Check update" +msgstr "" + +#: frmluamodulesupdater.rs_finishchecking +msgid "Finish checking" +msgstr "" + +#: frmluamodulesupdater.rs_finishdownload +msgid "Finish download" +msgstr "" + +#: frmluamodulesupdater.rs_startdownloading +msgid "Downloading..." +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Tüm indirmeler" @@ -89,6 +112,7 @@ msgid "Cancel" msgstr "İptal" #: frmmain.rs_checking +msgctxt "frmmain.rs_checking" msgid "Checking..." msgstr "Kontrol ediliyor..." @@ -555,6 +579,23 @@ msgstr "Yazılım yolu (mesela c:\\MangaDownloader)" msgid "Software:" msgstr "Yazılım:" +#: tluamodulesupdaterform.btcheckupdate.caption +msgctxt "tluamodulesupdaterform.btcheckupdate.caption" +msgid "Check update" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text +msgid "Filename" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text +msgid "Last modified" +msgstr "" + +#: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text +msgid "Last message" +msgstr "" + #: tmainform.btabortupdatelist.hint msgid "Abort update list" msgstr "Liste güncellemeyi iptal et" @@ -1953,6 +1994,10 @@ msgstr "Görünüm" msgid "Advanced" msgstr "Gelişmiş" +#: tmainform.tswebsitemodules.caption +msgid "Modules" +msgstr "" + #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" msgid "Options" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index fe36f74d4..e801e68f3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -304,7 +304,7 @@ <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item9> </RequiredPackages> - <Units Count="15"> + <Units Count="16"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -406,6 +406,13 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit14> + <Unit15> + <Filename Value="forms\frmLuaModulesUpdater.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="LuaModulesUpdaterForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit15> </Units> </ProjectOptions> <CompilerOptions> From d953376d394592b94702239cee697f2740179485 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Feb 2018 23:23:21 +0800 Subject: [PATCH 2165/2794] cleanup save/restore vt, save column, sort and position --- mangadownloader/forms/frmMain.pas | 93 ++++++++++++++----------------- 1 file changed, 43 insertions(+), 50 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ce0ae46cf..c0cf3048d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5578,8 +5578,23 @@ procedure TMainForm.UpdateVtMangaListFilterStatus; end; procedure TMainForm.LoadFormInformation; -var - i: Integer; + + procedure restorevt(const vt: VirtualTrees.TVirtualStringTree; const name: String); + var + i: Integer; + begin + with configfile, vt.Header do + begin + SortColumn := ReadInteger(name, 'SortColumn', SortColumn); + SortDirection := TSortDirection(ReadInteger(name, 'SortDirection', Integer(SortDirection))); + for i := 0 to Columns.Count - 1 do + begin + Columns[i].Width := ReadInteger(name, 'Column' + IntToStr(i) + 'Width', Columns[i].Width); + Columns[i].Position := ReadInteger(name, 'Column' + IntToStr(i) + 'Position', Columns[i].Position); + end; + end; + end; + begin with configfile do begin @@ -5602,41 +5617,38 @@ procedure TMainForm.LoadFormInformation; PrevWindowState := wsNormal; WindowState := PrevWindowState; - if vtDownload.Header.Columns.Count > 0 then - with vtDownload.Header.Columns do - for i := 0 to Count - 1 do - Items[i].Width := ReadInteger('form', 'vtDownload' + IntToStr(i) + 'Width', 50); + restorevt(vtDownload, 'vtDownload'); + DLManager.SortColumn := vtDownload.Header.SortColumn; + DLManager.SortDirection := Boolean(vtDownload.Header.SortDirection); - if vtFavorites.Header.Columns.Count > 0 then - with vtFavorites.Header.Columns do - for i := 0 to Count - 1 do - Items[i].Width := ReadInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', 50); + restorevt(vtFavorites, 'vtFavorites'); + FavoriteManager.SortColumn := vtFavorites.Header.SortColumn; + FavoriteManager.SortDirection := Boolean(vtFavorites.Header.SortDirection); - FavoriteManager.SortColumn := ReadInteger('misc', 'SortFavoritesColumn', 1); - FavoriteManager.sortDirection := ReadBool('misc', 'SortFavoritesDirection', False); - vtFavorites.Header.SortColumn := FavoriteManager.SortColumn; - vtFavorites.Header.SortDirection := TSortDirection(FavoriteManager.sortDirection); + // lua website modules list + restorevt(LuaModulesUpdaterForm.vtLuaModulesRepos, 'vtLuaModulesRepos'); + LuaModulesUpdaterForm.SortList; + end; +end; - DLManager.SortColumn := ReadInteger('misc', 'SortDownloadColumn', 0); - DLManager.SortDirection := ReadBool('misc', 'SortDownloadDirection', False); - vtDownload.Header.SortColumn := DLManager.SortColumn; - vtDownload.Header.SortDirection := TSortDirection(DLManager.SortDirection); +procedure TMainForm.SaveFormInformation; - // lua website modules list - with LuaModulesUpdaterForm.vtLuaModulesRepos.Header do + procedure savevt(const vt: VirtualTrees.TVirtualStringTree; const name: String); + var + i: Integer; + begin + with configfile, vt.Header do begin - SortColumn := ReadInteger('websitemodules', 'SortColumn', SortColumn); - SortDirection := TSortDirection(ReadInteger('websitemodules', 'SortDirection', Integer(SortDirection))); + WriteInteger(name, 'SortColumn', SortColumn); + WriteInteger(name, 'SortDirection', Integer(SortDirection)); for i := 0 to Columns.Count - 1 do - Columns[i].Width := ReadInteger('websitemodules', 'Column' + IntToStr(i) + 'Width', Columns[i].Width); - LuaModulesUpdaterForm.SortList; + begin + WriteInteger(name, 'Column' + IntToStr(i) + 'Width', Columns[i].Width); + WriteInteger(name, 'Column' + IntToStr(i) + 'Position', Columns[i].Position); + end; end; end; -end; -procedure TMainForm.SaveFormInformation; -var - i: Integer; begin with configfile do begin @@ -5652,30 +5664,11 @@ procedure TMainForm.SaveFormInformation; WriteInteger('form', 'MainFormWidth', Width); WriteInteger('form', 'MainFormHeight', Height); - if vtDownload.Header.Columns.Count > 0 then - with vtDownload.Header.Columns do - for i := 0 to Count - 1 do - WriteInteger('form', 'vtDownload' + IntToStr(i) + 'Width', Items[i].Width); - - if vtFavorites.Header.Columns.Count > 0 then - with vtFavorites.Header.Columns do - for i := 0 to Count - 1 do - WriteInteger('form', 'vtFavorites' + IntToStr(i) + 'Width', Items[i].Width); - - WriteInteger('misc', 'SortDownloadColumn', vtDownload.Header.SortColumn); - WriteBool('misc', 'SortDownloadDirection', DLManager.SortDirection); - - WriteInteger('misc', 'SortFavoritesColumn', vtFavorites.Header.SortColumn); - WriteBool('misc', 'SortFavoritesDirection', FavoriteManager.sortDirection); + savevt(vtDownload, 'vtDownload'); + savevt(vtFavorites, 'vtFavorites'); // lua website modules list - with LuaModulesUpdaterForm.vtLuaModulesRepos.Header do - begin - WriteInteger('websitemodules', 'SortColumn', SortColumn); - WriteInteger('websitemodules', 'SortDirection', Integer(SortDirection)); - for i := 0 to Columns.Count - 1 do - WriteInteger('websitemodules', 'Column' + IntToStr(i) + 'Width', Columns[i].Width); - end; + savevt(LuaModulesUpdaterForm.vtLuaModulesRepos, 'vtLuaModulesRepos'); end; end; From 4d2890a9331c9cc5bef46cf13e795f828d7d26e6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 11 Feb 2018 23:28:45 +0800 Subject: [PATCH 2166/2794] lua modules updater, check for missing files after check remote (#909) --- .../forms/frmLuaModulesUpdater.pas | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index 98e660415..a46f37e57 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -687,13 +687,26 @@ procedure TCheckUpdateThread.Execute; FRepos := FOwner.Repos.Clone; foundupdate := SyncRepos(FRepos, FReposUp); - // look for previously failed download + // look for missing local files for i := 0 to FRepos.Items.Count - 1 do - if FRepos[i].flag = fFailedDownload then + begin + m := FRepos[i]; + if not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name) then begin - foundupdate := True; - break; + m.flag := fFailedDownload; + if foundupdate <> True then + foundupdate := True; end; + end; + + // look for previously failed download + if not foundupdate then + for i := 0 to FRepos.Items.Count - 1 do + if FRepos[i].flag = fFailedDownload then + begin + foundupdate := True; + break; + end; Synchronize(@SyncFinishChecking); if foundupdate and (not Terminated) then From 88809bbc2858dcae249bd6b63c98460e854b40a8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 00:28:21 +0800 Subject: [PATCH 2167/2794] add restart current process method --- baseunits/FMDOptions.pas | 31 +++++++++++++++++++++++++++++++ mangadownloader/forms/frmMain.pas | 3 +++ 2 files changed, 34 insertions(+) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 73ce684f6..b6890fdc2 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -158,6 +158,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionRemoveMangaNameFromChapter: Boolean = False; + OptionRestartFMD: Boolean = False; + //custom color //basiclist CL_BSNormalText: TColor = clWindowText; @@ -185,8 +187,13 @@ TIniFileRun = class(IniFiles.TMemIniFile) procedure SetFMDdirectory(const ADir: String); procedure SetAppDataDirectory(const ADir: String); +procedure RestartFMD; +procedure DoRestartFMD; + implementation +uses FMDVars, UTF8Process; + { TIniFileRun } constructor TIniFileRun.Create(const AFileName: String; AEscapeLineFeeds: Boolean); @@ -327,6 +334,30 @@ procedure SetAppDataDirectory(const ADir: String); SetIniFiles; end; +procedure RestartFMD; +begin + OptionRestartFMD := True; + FormMain.Close; +end; + +procedure DoRestartFMD; +var + p: TProcessUTF8; + i: Integer; +begin + p := TProcessUTF8.Create(nil); + try + p.InheritHandles := False; + p.CurrentDirectory := ExtractFilePath(Application.ExeName); + p.Executable := Application.ExeName; + for i := 1 to ParamCount do + p.Parameters.Add(ParamStrUTF8(i)); + p.Execute; + finally + p.Free; + end; +end; + function GetCurrentBinVersion: String; var AppVerInfo: TStringList; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c0cf3048d..64b421880 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1459,6 +1459,9 @@ procedure TMainForm.FormDestroy(Sender: TObject); Logger.Send(QuotedStrd(Application.Title)+' exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']') else Logger.SendWarning(QuotedStrd(Application.Title)+' doesn''t exit normally [PID:'+IntToStr(GetProcessID)+'] [HANDLE:'+IntToStr(GetCurrentProcess)+']'); + + if OptionRestartFMD then + DoRestartFMD; end; procedure TMainForm.FormShow(Sender: TObject); From 1cf6ae099af5e4daddab7892e7525331bbdd3216 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 00:29:09 +0800 Subject: [PATCH 2168/2794] lua modules updater, add confirmation dialog to proceed and to restart (#909) --- .../forms/frmLuaModulesUpdater.pas | 29 ++++++++++++++++--- mangadownloader/languages/fmd.de.po | 16 ++++++++++ mangadownloader/languages/fmd.el_GR.po | 16 ++++++++++ mangadownloader/languages/fmd.en.po | 16 ++++++++++ mangadownloader/languages/fmd.es.po | 16 ++++++++++ mangadownloader/languages/fmd.id_ID.po | 16 ++++++++++ mangadownloader/languages/fmd.pl_PL.po | 16 ++++++++++ mangadownloader/languages/fmd.po | 16 ++++++++++ mangadownloader/languages/fmd.pt_BR.po | 16 ++++++++++ mangadownloader/languages/fmd.ru_RU.po | 16 ++++++++++ mangadownloader/languages/fmd.tr_TR.po | 16 ++++++++++ 11 files changed, 185 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index a46f37e57..e8981aeab 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -126,11 +126,14 @@ TCheckUpdateThread = class(TBaseThread) FMainRepos: TLuaModulesRepos; FThreads: TFPList; FThreadsCS: TRTLCriticalSection; + FDownloadedCount: Integer; + FProceed: Boolean; procedure RemoveThread(const T: TDownloadThread); procedure AddThread(const T: TDownloadThread); protected procedure SyncStartChecking; procedure SyncFinishChecking; + procedure SyncAskToProceed; procedure SyncStartDownload; procedure SyncFinishDownload; procedure SyncFinal; @@ -154,6 +157,10 @@ TCheckUpdateThread = class(TBaseThread) RS_FinishChecking = 'Finish checking'; RS_StartDownloading = 'Downloading...'; RS_FinishDownload = 'Finish download'; + RS_NewUpdateFoundTitle = 'Modules update found!'; + RS_NewUpdateFoundLostChanges = 'Modules update found, any local changes will be lost, procced?'; + RS_ModulesUpdatedTitle = 'Modules updated!'; + RS_ModulesUpdatedRestart = 'Modules updated, restart now?'; implementation @@ -430,7 +437,10 @@ procedure TDownloadThread.Execute; begin FHTTP.Document.SaveToFile(f); if FileExists(f) then + begin FModule.flag := fDownloaded; + FOwner.FDownloadedCount := InterLockedIncrement(FOwner.FDownloadedCount); + end; end; end; end @@ -497,6 +507,12 @@ procedure TCheckUpdateThread.SyncFinishChecking; end; end; +procedure TCheckUpdateThread.SyncAskToProceed; +begin + FProceed := MessageDlg(RS_NewUpdateFoundTitle, RS_NewUpdateFoundLostChanges, + mtConfirmation, mbYesNo, 0) = mrYes; +end; + procedure TCheckUpdateThread.SyncStartDownload; begin FOwner.btCheckUpdate.Caption := RS_StartDownloading; @@ -709,13 +725,12 @@ procedure TCheckUpdateThread.Execute; end; Synchronize(@SyncFinishChecking); + if foundupdate and (not Terminated) then begin - Sleep(500); - if not Terminated then - begin + Synchronize(@SyncAskToProceed); + if FProceed then Download; - end; end; // cleanup @@ -746,6 +761,11 @@ procedure TCheckUpdateThread.Execute; if not Terminated then Sleep(1000); Synchronize(@SyncFinal); + + if (FDownloadedCount <> 0) and + (MessageDlg(RS_ModulesUpdatedTitle, RS_ModulesUpdatedRestart, mtConfirmation, + mbYesNo, 0) = mrYes) then + RestartFMD; end; constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); @@ -755,6 +775,7 @@ constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); FOwner := AOwner; FHTTP := THTTPSendThread.Create(Self); FThreads := TFPList.Create; + FDownloadedCount := 0; end; destructor TCheckUpdateThread.Destroy; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index f60b5098e..e4fb6bdfe 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -92,6 +92,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 9286ac7bb..2e496c3e1 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -96,6 +96,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 3ce754931..96c874848 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -80,6 +80,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index e7fa083da..c9ade507d 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -91,6 +91,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index b66076c9e..f02edde99 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -91,6 +91,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 91d306172..aea5d0659 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -92,6 +92,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index dcd3d5943..bdbe8ab50 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -72,6 +72,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 8d987c268..eb621ecda 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -92,6 +92,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 3b1891af1..007ddd680 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -90,6 +90,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index d106955c5..5d1302699 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -93,6 +93,22 @@ msgstr "" msgid "Finish download" msgstr "" +#: frmluamodulesupdater.rs_modulesupdatedrestart +msgid "Modules updated, restart now?" +msgstr "" + +#: frmluamodulesupdater.rs_modulesupdatedtitle +msgid "Modules updated!" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundlostchanges +msgid "Modules update found, any local changes will be lost, procced?" +msgstr "" + +#: frmluamodulesupdater.rs_newupdatefoundtitle +msgid "Modules update found!" +msgstr "" + #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." msgstr "" From 3533a5303d116af81a0e35ff004cebd580b62027 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 01:13:14 +0800 Subject: [PATCH 2169/2794] lua modules updater, fix new status, and some typo --- .../forms/frmLuaModulesUpdater.pas | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index e8981aeab..e3f77d0bc 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -349,11 +349,12 @@ procedure TLuaModulesRepos.LoadFromFile(const AFilename: String); m := Add(o.Get('name', '')); m.sha := o.Get('sha', ''); m.download_url := o.Get('download_url', ''); - m.size := o.Get('asize', 0); + m.size := o.Get('size', 0); m.last_modified := JSONToDateTime(o.Get('last_modified', '')); m.last_message := o.Get('last_message', ''); m.flag := TLuaModuleRepoFlag(o.Get('flag', 0)); - if not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name) then + if (m.flag <> fFailedDownload) and + (not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name)) then m.flag := fFailedDownload; end; finally @@ -703,27 +704,21 @@ procedure TCheckUpdateThread.Execute; FRepos := FOwner.Repos.Clone; foundupdate := SyncRepos(FRepos, FReposUp); - // look for missing local files + // look for missing local files and previously failed download for i := 0 to FRepos.Items.Count - 1 do begin m := FRepos[i]; - if not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name) then + if m.flag = fFailedDownload then + foundupdate := True + else + if (not (m.flag in [fNew, fUpdate])) and + (not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name)) then begin m.flag := fFailedDownload; - if foundupdate <> True then - foundupdate := True; + foundupdate := True; end; end; - // look for previously failed download - if not foundupdate then - for i := 0 to FRepos.Items.Count - 1 do - if FRepos[i].flag = fFailedDownload then - begin - foundupdate := True; - break; - end; - Synchronize(@SyncFinishChecking); if foundupdate and (not Terminated) then From d2b8d1478dbdb0536b06f133ea86b980302bcd19 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 01:17:02 +0800 Subject: [PATCH 2170/2794] Bump version 0.9.136.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5df5752c2..79dca1a26 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.136.0 (12-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.135.0...0.9.136.0 + 0.9.135.0 (10-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.134.0...0.9.135.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e801e68f3..70ba9bdab 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="135"/> + <RevisionNr Value="136"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index f2b35882d..09a370e03 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.135.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.135.0/fmd_0.9.135.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.135.0/fmd_0.9.135.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.135.0/fmd_0.9.135.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.135.0/fmd_0.9.135.0_Win64.7z +VERSION=0.9.136.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.136.0/fmd_0.9.136.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.136.0/fmd_0.9.136.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.136.0/fmd_0.9.136.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.136.0/fmd_0.9.136.0_Win64.7z From 8a5ecec494656268a458b7242c569f0babd4dd7d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 02:33:08 +0800 Subject: [PATCH 2171/2794] update changelog --- changelog.txt | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 79dca1a26..93643a833 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,20 +5,47 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.136.0 (12-02-2018) +[+] Added website modules updater +[+] Added RavenScans [SP-SC] +[+] Added KirishimaFansub [SP-SC] +[+] Added NoraNoFansub [SP-SC] +[+] Added YamiTenshiNoFansub [SP-SC] +[+] Added Mangavy [ID] +[-] Removed MangaWorksFansub +[-] Removed MasterPieceScans +[-] Removed R15TeamScanlation +[*] TonarinoYoungJump: fixed all +[*] Hentai2Read: fixed info +[*] Mangadex: limit maximum connections to 4 +[*] Update Turkish localization [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.135.0...0.9.136.0 0.9.135.0 (10-02-2018) +[+] Added option to convert WebP to PNG/JPEG +[-] Removed AnimeA +[-] Removed CentrumMangi_PL +[-] Removed DM5 +[-] Removed Imanhua +[-] Removed MangaLib_PL +[-] Removed MangaAr +[-] Removed MangaAt +[*] MangaStream: fixed download +[*] Update Russian localization [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.134.0...0.9.135.0 0.9.134.0 (08-02-2018) +[+] Added Lhscans [RAW] +[+] Added Mangakakalot/Manganelo [EN] +[+] Added Mangawindow [EN] +[*] MangaStream: fixed domain +[*] Update Turkish localization [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.133.0...0.9.134.0 0.9.133.0 (07-02-2018) [+] Added left download toolbar to move selected download(s). Options > View -[*] View manga info preserve saveto location from download or favorite [+] Added Lua support to add website module at runtime [+] Added WorldThree [EN-SC] [+] Added PsychoPlay [EN-SC] @@ -27,6 +54,7 @@ Full changes: https://github.com/riderkick/FMD/compare/0.9.133.0...0.9.134.0 [+] Added Imgur [-] Removed MangaSpy [-] Removed MangaIce +[*] View manga info preserve saveto location from download or favorite [*] MangaZuki: fixed all [*] Comico: fixed all [*] MangaGo: fixed all From 2778def5f02b50d116fa192c04d2f4800e480a75 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Sun, 11 Feb 2018 22:26:15 +0300 Subject: [PATCH 2172/2794] Update fmd.tr_TR.po - Translated latest Module changes. - Line 1569 changed to more understandable sentence. --- mangadownloader/languages/fmd.tr_TR.po | 31 +++++++++++++------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 5d1302699..a87c3e9e2 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: Free Manga Downloader 0.9.135\n" +"Project-Id-Version: Free Manga Downloader 0.9.136\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: Tmp341 <tmp341@gmail.com>\n" @@ -75,7 +75,6 @@ msgid "List of unimported manga" msgstr "İçe aktarılmayan manga listesi" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Kontrol ediliyor..." @@ -83,35 +82,35 @@ msgstr "Kontrol ediliyor..." #: frmluamodulesupdater.rs_checkupdate msgctxt "frmluamodulesupdater.rs_checkupdate" msgid "Check update" -msgstr "" +msgstr "Güncellemelere bak" #: frmluamodulesupdater.rs_finishchecking msgid "Finish checking" -msgstr "" +msgstr "Kontrolü durdur" #: frmluamodulesupdater.rs_finishdownload msgid "Finish download" -msgstr "" +msgstr "İndirmeyi durdur" #: frmluamodulesupdater.rs_modulesupdatedrestart msgid "Modules updated, restart now?" -msgstr "" +msgstr "Modüller güncellendi, yeniden başlasın mı?" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "" +msgstr "Modüller güncellendi!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "Modules update found, any local changes will be lost, procced?" -msgstr "" +msgstr "Modül güncellemeleri bulundu, herhangi bir yerel değişim kaybolacaktır, devam edilsin mi?" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "" +msgstr "Modül güncellemeleri bulundu!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." -msgstr "" +msgstr "İndiriliyor..." #: frmmain.rs_alldownloads msgid "All downloads" @@ -598,19 +597,19 @@ msgstr "Yazılım:" #: tluamodulesupdaterform.btcheckupdate.caption msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" -msgstr "" +msgstr "Güncellemelere bak" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" -msgstr "" +msgstr "Dosya adı" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text msgid "Last modified" -msgstr "" +msgstr "Son değişim" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text msgid "Last message" -msgstr "" +msgstr "Son mesaj" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -1567,7 +1566,7 @@ msgstr "Şuraya kaydet:" #: tmainform.lbwebpconvertto.caption msgid "Save WebP to" -msgstr "WebP'yi şuraya kaydet" +msgstr "WebP'yi şöyle kaydet" #: tmainform.lbwebpjpegquality.caption msgid "Jpeg quality" @@ -2012,7 +2011,7 @@ msgstr "Gelişmiş" #: tmainform.tswebsitemodules.caption msgid "Modules" -msgstr "" +msgstr "Modüller" #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" From 64563bb9c4b88be25c7013f8a7a84ece27e3bf33 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 10:06:15 +0800 Subject: [PATCH 2173/2794] updater, fix typo (fix #945) --- updater/uMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/uMain.pas b/updater/uMain.pas index e869dab72..873142eaa 100644 --- a/updater/uMain.pas +++ b/updater/uMain.pas @@ -542,7 +542,7 @@ procedure TfrmMain.FormCreate(Sender: TObject); LANGUAGES_DIR := FMD_DIR + 'languages'; CONFIG_FILE := CONFIG_DIR + PathDelim + 'config.ini'; SZA := FMD_DIR + '7za.exe'; - SZA := FMD_DIR + 'old_7za.exe'; + OSZA := FMD_DIR + 'old_7za.exe'; InitSimpleExceptionHandler; try From 0b6d70429f30a37f5b2acc4f7e78b987633f05ee Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 10:16:56 +0800 Subject: [PATCH 2174/2794] update english localization --- mangadownloader/languages/fmd.en.po | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 96c874848..cde8d85b7 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -62,7 +62,6 @@ msgid "List of unimported manga" msgstr "List of unimported manga" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Checking..." @@ -70,35 +69,35 @@ msgstr "Checking..." #: frmluamodulesupdater.rs_checkupdate msgctxt "frmluamodulesupdater.rs_checkupdate" msgid "Check update" -msgstr "" +msgstr "Check update" #: frmluamodulesupdater.rs_finishchecking msgid "Finish checking" -msgstr "" +msgstr "Finish checking" #: frmluamodulesupdater.rs_finishdownload msgid "Finish download" -msgstr "" +msgstr "Finish download" #: frmluamodulesupdater.rs_modulesupdatedrestart msgid "Modules updated, restart now?" -msgstr "" +msgstr "Modules updated, restart now?" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "" +msgstr "Modules updated!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "Modules update found, any local changes will be lost, procced?" -msgstr "" +msgstr "Modules update found, any local changes will be lost, procced?" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "" +msgstr "Modules update found!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." -msgstr "" +msgstr "Downloading..." #: frmmain.rs_alldownloads msgid "All downloads" @@ -578,19 +577,19 @@ msgstr "Software:" #: tluamodulesupdaterform.btcheckupdate.caption msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" -msgstr "" +msgstr "Check update" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" -msgstr "" +msgstr "Filename" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text msgid "Last modified" -msgstr "" +msgstr "Last modified" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text msgid "Last message" -msgstr "" +msgstr "Last message" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -1982,7 +1981,7 @@ msgstr "Advanced" #: tmainform.tswebsitemodules.caption msgid "Modules" -msgstr "" +msgstr "Modules" #: tmainform.tswebsiteoptions.caption msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" From 40d22cdeb1e8dd7da21bcce9eba0d8d883fcb96e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 10:44:36 +0800 Subject: [PATCH 2175/2794] update Indonesian localization --- mangadownloader/languages/fmd.id_ID.po | 130 ++++++++++++------------- 1 file changed, 61 insertions(+), 69 deletions(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index f02edde99..6844d825d 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1,16 +1,5 @@ msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: \n" -"POT-Creation-Date: \n" -"PO-Revision-Date: \n" -"Last-Translator: \n" -"Language-Team: Cholif\n" -"MIME-Version: 1.0\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: id_ID\n" -"X-Generator: Poedit 2.0.1\n" -"Plural-Forms: nplurals=1; plural=0;\n" +msgstr "Content-Type: text/plain; charset=UTF-8" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" @@ -73,7 +62,6 @@ msgid "List of unimported manga" msgstr "Daftar komik yang tidak bisa di-impor" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Memeriksa..." @@ -81,35 +69,35 @@ msgstr "Memeriksa..." #: frmluamodulesupdater.rs_checkupdate msgctxt "frmluamodulesupdater.rs_checkupdate" msgid "Check update" -msgstr "" +msgstr "Periksa pembaruan" #: frmluamodulesupdater.rs_finishchecking msgid "Finish checking" -msgstr "" +msgstr "Selesai memeriksa" #: frmluamodulesupdater.rs_finishdownload msgid "Finish download" -msgstr "" +msgstr "Selesai mengunduh" #: frmluamodulesupdater.rs_modulesupdatedrestart msgid "Modules updated, restart now?" -msgstr "" +msgstr "Module diperbarui, memulai ulang sekarang?" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "" +msgstr "Modul diperbarui!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "Modules update found, any local changes will be lost, procced?" -msgstr "" +msgstr "Pembaruan modul ditemukan, ubahan lokal akan hilang, lanjutkan?" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "" +msgstr "Pembaruan modul ditemukan!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." -msgstr "" +msgstr "Mengunduh..." #: frmmain.rs_alldownloads msgid "All downloads" @@ -264,7 +252,7 @@ msgstr "Judul:" #: frmmain.rs_infowebsite msgctxt "frmmain.rs_infowebsite" msgid "Website:" -msgstr "Situs web:" +msgstr "Situs:" #: frmmain.rs_inprogress msgid "In progress" @@ -319,6 +307,10 @@ msgid "" "CBZ\n" "PDF\n" msgstr "" +"Tidak ada\n" +"ZIP\n" +"CBZ\n" +"PDF\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -355,6 +347,9 @@ msgid "" "PNG\n" "Jpeg\n" msgstr "" +"WebP\n" +"PNG\n" +"Jpeg\n" #: frmmain.rs_webppnglevel msgid "" @@ -363,6 +358,10 @@ msgid "" "Default\n" "Maximum\n" msgstr "" +"None\n" +"Fastest\n" +"Default\n" +"Maximum\n" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -387,10 +386,9 @@ msgstr "Komputer akan dimatikan dalam %d detik" #: frmtransferfavorites.rs_all msgctxt "frmtransferfavorites.rs_all" msgid "All" -msgstr "" +msgstr "Semua" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" msgstr "Tidak valid" @@ -398,7 +396,7 @@ msgstr "Tidak valid" #: frmtransferfavorites.rs_valid msgctxt "frmtransferfavorites.rs_valid" msgid "Valid" -msgstr "" +msgstr "Valid" #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" @@ -452,7 +450,7 @@ msgstr "Segarkan" #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: taccountmanagerform.vtaccountlist.header.columns[2].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" @@ -490,7 +488,7 @@ msgstr "Nama user" #: taccountsetform.label1.caption msgctxt "taccountsetform.label1.caption" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: taccountsetform.label2.caption msgctxt "taccountsetform.label2.caption" @@ -579,19 +577,19 @@ msgstr "Perangkat lunak:" #: tluamodulesupdaterform.btcheckupdate.caption msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" -msgstr "" +msgstr "Periksa pembaruan" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" -msgstr "" +msgstr "Nama" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text msgid "Last modified" -msgstr "" +msgstr "Terakhir diperbarui" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text msgid "Last message" -msgstr "" +msgstr "Pesan terakhir" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -789,7 +787,7 @@ msgstr "Tampilkan \"Hapus semua unduhan selesai\" di toolbar unduhan" #: tmainform.cboptionshowdownloadtoolbarleft.caption msgid "Show left downloads toolbar" -msgstr "" +msgstr "Tampilkan toolbar kiri" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -821,11 +819,11 @@ msgstr "Regular Expression" #: tmainform.cbwebpconvertto.text msgid "PNG" -msgstr "" +msgstr "PNG" #: tmainform.cbwebppngcompressionlevel.text msgid "Fastest" -msgstr "" +msgstr "Paling cepat" #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" @@ -1253,7 +1251,7 @@ msgstr "Masukkan URL disini" #: tmainform.edwebsitessearch.texthint msgctxt "tmainform.edwebsitessearch.texthint" msgid "Search website..." -msgstr "Cari situs web..." +msgstr "Cari situs..." #: tmainform.gbdialogs.caption msgid "Show dialog confirmation for" @@ -1282,7 +1280,7 @@ msgstr "Mengubah nama" #: tmainform.gbwebp.caption msgid "WebP" -msgstr "" +msgstr "WebP" #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" @@ -1539,15 +1537,15 @@ msgstr "Lokasi penyimpanan:" #: tmainform.lbwebpconvertto.caption msgid "Save WebP to" -msgstr "" +msgstr "Simpan WebP ke" #: tmainform.lbwebpjpegquality.caption msgid "Jpeg quality" -msgstr "" +msgstr "Kualitas Jpeg" #: tmainform.lbwebppngcompressionlevel.caption msgid "PNG Compression level" -msgstr "" +msgstr "Level kompresi PNG" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" @@ -1726,7 +1724,7 @@ msgstr "Buka ..." #: tmainform.mifavoritesrename.caption msgid "Rename" -msgstr "" +msgstr "Ubah nama" #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" @@ -1735,7 +1733,7 @@ msgstr "Berhenti periksa bab baru" #: tmainform.mifavoritestransferwebsite.caption msgctxt "tmainform.mifavoritestransferwebsite.caption" msgid "Transfer website" -msgstr "" +msgstr "Transfer website" #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" @@ -1874,19 +1872,19 @@ msgstr "Hentikan semua" #: tmainform.tbmidownloadmovebottom.hint msgid "Move selected item(s) to bottom" -msgstr "" +msgstr "Pindahkan item-item terpilih ke paling bawah" #: tmainform.tbmidownloadmovedown.hint msgid "Move selected item(s) down" -msgstr "" +msgstr "Pindahkan item-item terpilih ke bawah" #: tmainform.tbmidownloadmovetop.hint msgid "Move selected item(s) to top" -msgstr "" +msgstr "Pindahkan item-item terpilih ke paling atas" #: tmainform.tbmidownloadmoveup.hint msgid "Move selected item(s) up" -msgstr "" +msgstr "Pindahkan item-item terpilih ke atas" #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" @@ -1983,7 +1981,7 @@ msgstr "Lanjutan" #: tmainform.tswebsitemodules.caption msgid "Modules" -msgstr "" +msgstr "Modul" #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" @@ -1993,12 +1991,12 @@ msgstr "Pengaturan" #: tmainform.tswebsites.caption msgctxt "tmainform.tswebsites.caption" msgid "Websites" -msgstr "Situs web" +msgstr "Situs" #: tmainform.tswebsiteselection.caption msgctxt "tmainform.tswebsiteselection.caption" msgid "Websites" -msgstr "Situs web" +msgstr "Situs" #: tmainform.vtdownload.header.columns[0].text msgid "Manga" @@ -2021,7 +2019,7 @@ msgstr "Kecepatan" #: tmainform.vtdownload.header.columns[4].text msgctxt "tmainform.vtdownload.header.columns[4].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: tmainform.vtdownload.header.columns[5].text msgctxt "tmainform.vtdownload.header.columns[5].text" @@ -2049,7 +2047,7 @@ msgstr "Bab saat ini" #: tmainform.vtfavorites.header.columns[3].text msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[3].TEXT" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: tmainform.vtfavorites.header.columns[4].text msgctxt "TMAINFORM.VTFAVORITES.HEADER.COLUMNS[4].TEXT" @@ -2089,37 +2087,34 @@ msgid "&Now" msgstr "&Sekarang" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Batal" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" #: ttransferfavoritesform.caption msgid "Transfer Favorites" -msgstr "" +msgstr "Transfer kesukaan" #: ttransferfavoritesform.ckcleardownloadedchapters.caption msgid "Clear downloaded chapter list and reload from server" -msgstr "" +msgstr "Bersihkan daftr bab terunduh dan muat ulang dari server" #: ttransferfavoritesform.lbtransferto.caption msgctxt "ttransferfavoritesform.lbtransferto.caption" msgid "Transfer to" -msgstr "" +msgstr "Transfer ke" #: ttransferfavoritesform.rball.caption msgctxt "ttransferfavoritesform.rball.caption" msgid "All" -msgstr "" +msgstr "Semua" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" msgstr "Tidak valid" @@ -2127,20 +2122,17 @@ msgstr "Tidak valid" #: ttransferfavoritesform.rbvalid.caption msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" -msgstr "" +msgstr "Valid" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Situs web" +msgstr "Judul" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: tupdatedialogform.btnlater.caption msgid "&Later" @@ -2207,7 +2199,7 @@ msgstr "User Agent" #: twebsiteoptionadvancedform.vtcookies.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: twebsiteoptionadvancedform.vtcookies.header.columns[1].text msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" @@ -2217,7 +2209,7 @@ msgstr "Cookies" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text" @@ -2227,7 +2219,7 @@ msgstr "Nilai" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" @@ -2237,7 +2229,7 @@ msgstr "Nilai" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" @@ -2247,7 +2239,7 @@ msgstr "Nilai" #: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" msgid "Website" -msgstr "Situs web" +msgstr "Situs" #: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" @@ -2256,7 +2248,7 @@ msgstr "User Agent" #: twebsiteselectionform.caption msgid "Select a website" -msgstr "Pilih situs web" +msgstr "Pilih situs" #: udownloadsmanager.rs_compressing msgid "Compressing..." From 36325a63cdf338ebcd5fd063c4d512eb349107b9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 10:45:10 +0800 Subject: [PATCH 2176/2794] some cleanup --- mangadownloader/forms/frmLuaModulesUpdater.pas | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index e3f77d0bc..67d444e48 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -95,7 +95,6 @@ TLuaModulesUpdaterForm = class(TForm) Repos: TLuaModulesRepos; ThreadCheck: TCheckUpdateThread; procedure ListDirty; - procedure CheckUpdate; procedure LoadLocalRepos; procedure ReinitList(const ASort: Boolean = True); procedure SortList; @@ -791,8 +790,8 @@ destructor TCheckUpdateThread.Destroy; procedure TLuaModulesUpdaterForm.btCheckUpdateClick(Sender: TObject); begin - if btCheckUpdate.Caption = RS_CheckUpdate then - CheckUpdate; + if ThreadCheck = nil then + ThreadCheck := TCheckUpdateThread.Create(Self); end; procedure TLuaModulesUpdaterForm.FormCreate(Sender: TObject); @@ -928,11 +927,6 @@ procedure TLuaModulesUpdaterForm.ListDirty; end; end; -procedure TLuaModulesUpdaterForm.CheckUpdate; -begin - ThreadCheck := TCheckUpdateThread.Create(Self); -end; - procedure TLuaModulesUpdaterForm.LoadLocalRepos; begin Repos.LoadFromFile(LUA_WEBSITEMODULE_REPOS); From d7ccad78aa7fa733accb5c271ebc60305a4eef95 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 10:57:25 +0800 Subject: [PATCH 2177/2794] update changelog --- changelog.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changelog.txt b/changelog.txt index 93643a833..f9f21f3ac 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.137.0 (--2018) +[*] Fixed updater can't find 7za.exe, you need to download this release manually +[*] Update Turkish localization +[*] Update Indonesian localization +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.136.0...0.9.137.0 + 0.9.136.0 (12-02-2018) [+] Added website modules updater [+] Added RavenScans [SP-SC] From 2503ba6433d6f6054cde0d073a4fe3177e26f8e8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 11:21:28 +0800 Subject: [PATCH 2178/2794] mainform, mangainfo select manga accept user input to navigate --- mangadownloader/forms/frmMain.lfm | 6 ++-- mangadownloader/forms/frmMain.pas | 54 +++++++++++++++---------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 603f0015d..919af3b5c 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -550,16 +550,18 @@ object MainForm: TMainForm Top = 0 Width = 171 Anchors = [akTop, akLeft, akRight] + AutoComplete = True + AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchAscending] + AutoDropDown = True ItemHeight = 15 ItemIndex = 0 Items.Strings = ( '' ) - OnChange = cbSelectMangaChange + OnEditingDone = cbSelectMangaEditingDone ParentShowHint = False ShowHint = True Sorted = True - Style = csDropDownList TabOrder = 1 end object btUpdateList: TSpeedButton diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 64b421880..ad831f6ed 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -439,7 +439,7 @@ TMainForm = class(TForm) procedure cbOptionDigitChapterChange(Sender: TObject); procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderChange(Sender: TObject); - procedure cbSelectMangaChange(Sender: TObject); + procedure cbSelectMangaEditingDone(Sender: TObject); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -2568,6 +2568,31 @@ procedure TMainForm.cbOptionGenerateMangaFolderChange(Sender: TObject); lbOptionMangaCustomRenameHint.Enabled := edOptionMangaCustomRename.Enabled; end; +procedure TMainForm.cbSelectMangaEditingDone(Sender: TObject); +begin + if cbSelectManga.ItemIndex < 0 then + Exit; + if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then + begin + configfile.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); + currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; + vtMangaList.Clear; + if dataProcess = nil then + dataProcess := TDBDataProcess.Create + else + if dataProcess.Connected then + dataProcess.Close; + lbMode.Caption := Format(RS_ModeAll, [0]); + if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then + begin + OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); + end + else + if cbOptionShowDownloadMangalistDialog.Checked then + RunGetList; + end; +end; + procedure TMainForm.btReadOnlineClick(Sender: TObject); begin OpenURL(mangaInfo.url); @@ -2647,31 +2672,6 @@ procedure TMainForm.btChecksClick(Sender: TObject); clbChapterList.SetFocus; end; -procedure TMainForm.cbSelectMangaChange(Sender: TObject); -begin - if cbSelectManga.ItemIndex < 0 then - Exit; - configfile.WriteInteger('form', 'SelectManga', cbSelectManga.ItemIndex); - if currentWebsite <> cbSelectManga.Items[cbSelectManga.ItemIndex] then - begin - currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; - vtMangaList.Clear; - if dataProcess = nil then - dataProcess := TDBDataProcess.Create - else - if dataProcess.Connected then - dataProcess.Close; - lbMode.Caption := Format(RS_ModeAll, [0]); - if DataFileExist(cbSelectManga.Items[cbSelectManga.ItemIndex]) then - begin - OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); - end - else - if cbOptionShowDownloadMangalistDialog.Checked then - RunGetList; - end; -end; - procedure TMainForm.clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -5162,7 +5162,7 @@ procedure TMainForm.ApplyOptions; if cbSelectManga.Items.Count > 0 then begin cbSelectManga.ItemIndex := 0; - cbSelectMangaChange(cbSelectManga); + cbSelectMangaEditingDone(cbSelectManga); end else begin From 8acc8618a786ffd2866fdd12adad9f5361df2fc7 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 11 Feb 2018 19:31:09 +0300 Subject: [PATCH 2179/2794] update Russian localization --- changelog.txt | 1 + mangadownloader/languages/fmd.ru_RU.po | 27 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/changelog.txt b/changelog.txt index f9f21f3ac..c6fbfe097 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,7 @@ Changelog: [*] Fixed updater can't find 7za.exe, you need to download this release manually [*] Update Turkish localization [*] Update Indonesian localization +[*] Update Russian localization [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.136.0...0.9.137.0 diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 007ddd680..5139e1474 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -72,7 +72,6 @@ msgid "List of unimported manga" msgstr "Список неимпортированной манги" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Проверка..." @@ -80,35 +79,35 @@ msgstr "Проверка..." #: frmluamodulesupdater.rs_checkupdate msgctxt "frmluamodulesupdater.rs_checkupdate" msgid "Check update" -msgstr "" +msgstr "Проверить обновления" #: frmluamodulesupdater.rs_finishchecking msgid "Finish checking" -msgstr "" +msgstr "Проверено" #: frmluamodulesupdater.rs_finishdownload msgid "Finish download" -msgstr "" +msgstr "Скачано" #: frmluamodulesupdater.rs_modulesupdatedrestart msgid "Modules updated, restart now?" -msgstr "" +msgstr "Модули обновлены, перезапустить программу сейчас?" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "" +msgstr "Модули обновлены!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "Modules update found, any local changes will be lost, procced?" -msgstr "" +msgstr "Найдено обновление модулей, все локальные изменения модулей будут перезаписаны, продолжить?" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "" +msgstr "Найдено обновление модулей!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." -msgstr "" +msgstr "Скачивание..." #: frmmain.rs_alldownloads msgid "All downloads" @@ -588,19 +587,19 @@ msgstr "Программа:" #: tluamodulesupdaterform.btcheckupdate.caption msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" -msgstr "" +msgstr "Проверить обновления" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" -msgstr "" +msgstr "Файл" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text msgid "Last modified" -msgstr "" +msgstr "Изменен" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text msgid "Last message" -msgstr "" +msgstr "Описание изменения" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -1992,7 +1991,7 @@ msgstr "Расширенные" #: tmainform.tswebsitemodules.caption msgid "Modules" -msgstr "" +msgstr "Модули" #: tmainform.tswebsiteoptions.caption msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" From c417a69057aa400f289e5b3ba075af8e0efb08ac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 12:09:27 +0800 Subject: [PATCH 2180/2794] modulesupdater, add option to show warning and auto restart --- baseunits/FMDOptions.pas | 4 +++ .../forms/frmLuaModulesUpdater.lfm | 26 +++++++++++++++++++ .../forms/frmLuaModulesUpdater.lrj | 4 ++- .../forms/frmLuaModulesUpdater.pas | 11 +++++--- mangadownloader/forms/frmMain.pas | 12 +++++++++ mangadownloader/languages/fmd.de.po | 8 ++++++ mangadownloader/languages/fmd.el_GR.po | 8 ++++++ mangadownloader/languages/fmd.en.po | 8 ++++++ mangadownloader/languages/fmd.es.po | 8 ++++++ mangadownloader/languages/fmd.id_ID.po | 8 ++++++ mangadownloader/languages/fmd.pl_PL.po | 8 ++++++ mangadownloader/languages/fmd.po | 8 ++++++ mangadownloader/languages/fmd.pt_BR.po | 8 ++++++ mangadownloader/languages/fmd.ru_RU.po | 8 ++++++ mangadownloader/languages/fmd.tr_TR.po | 8 ++++++ 15 files changed, 132 insertions(+), 5 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index b6890fdc2..4ea1f0c11 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -154,6 +154,10 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionUpdateListNoMangaInfo: Boolean = False; OptionUpdateListRemoveDuplicateLocalData: Boolean = False; + // modules + OptionModulesUpdaterShowUpdateWarning: Boolean = True; + OptionModulesUpdaterAutoRestart: Boolean = False; + OptionHTTPUseGzip: Boolean = True; OptionRemoveMangaNameFromChapter: Boolean = False; diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lfm b/mangadownloader/forms/frmLuaModulesUpdater.lfm index 2ae4b92f8..74d498947 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.lfm +++ b/mangadownloader/forms/frmLuaModulesUpdater.lfm @@ -156,6 +156,32 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm } OnClick = btCheckUpdateTerminateClick end + object ckShowUpdateWarning: TCheckBox + AnchorSideLeft.Control = btCheckUpdateTerminate + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btCheckUpdate + AnchorSideTop.Side = asrCenter + Left = 155 + Height = 19 + Top = 8 + Width = 135 + BorderSpacing.Left = 10 + Caption = 'Show update warning' + Checked = True + State = cbChecked + TabOrder = 2 + end + object ckAutoRestart: TCheckBox + AnchorSideLeft.Control = ckShowUpdateWarning + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = ckShowUpdateWarning + Left = 292 + Height = 19 + Top = 8 + Width = 82 + Caption = 'Auto restart' + TabOrder = 3 + end object imStates: TImageList left = 200 top = 128 diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lrj b/mangadownloader/forms/frmLuaModulesUpdater.lrj index 56d0d4e88..bac00db9b 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.lrj +++ b/mangadownloader/forms/frmLuaModulesUpdater.lrj @@ -2,5 +2,7 @@ {"hash":2901221,"name":"tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text","sourcebytes":[70,105,108,101,110,97,109,101],"value":"Filename"}, {"hash":119908548,"name":"tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text","sourcebytes":[76,97,115,116,32,109,111,100,105,102,105,101,100],"value":"Last modified"}, {"hash":115487141,"name":"tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text","sourcebytes":[76,97,115,116,32,109,101,115,115,97,103,101],"value":"Last message"}, -{"hash":56103285,"name":"tluamodulesupdaterform.btcheckupdate.caption","sourcebytes":[67,104,101,99,107,32,117,112,100,97,116,101],"value":"Check update"} +{"hash":56103285,"name":"tluamodulesupdaterform.btcheckupdate.caption","sourcebytes":[67,104,101,99,107,32,117,112,100,97,116,101],"value":"Check update"}, +{"hash":47677607,"name":"tluamodulesupdaterform.ckshowupdatewarning.caption","sourcebytes":[83,104,111,119,32,117,112,100,97,116,101,32,119,97,114,110,105,110,103],"value":"Show update warning"}, +{"hash":205920740,"name":"tluamodulesupdaterform.ckautorestart.caption","sourcebytes":[65,117,116,111,32,114,101,115,116,97,114,116],"value":"Auto restart"} ]} diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index 67d444e48..a411411f8 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -62,6 +62,8 @@ TCheckUpdateThread = class; TLuaModulesUpdaterForm = class(TForm) btCheckUpdate: TBitBtn; + ckShowUpdateWarning: TCheckBox; + ckAutoRestart: TCheckBox; imStates: TImageList; btCheckUpdateTerminate: TSpeedButton; tmRepaintList: TTimer; @@ -509,8 +511,9 @@ procedure TCheckUpdateThread.SyncFinishChecking; procedure TCheckUpdateThread.SyncAskToProceed; begin - FProceed := MessageDlg(RS_NewUpdateFoundTitle, RS_NewUpdateFoundLostChanges, - mtConfirmation, mbYesNo, 0) = mrYes; + FProceed := (not OptionModulesUpdaterShowUpdateWarning) or + (MessageDlg(RS_NewUpdateFoundTitle, RS_NewUpdateFoundLostChanges, + mtWarning, mbYesNo, 0) = mrYes); end; procedure TCheckUpdateThread.SyncStartDownload; @@ -756,9 +759,9 @@ procedure TCheckUpdateThread.Execute; Sleep(1000); Synchronize(@SyncFinal); - if (FDownloadedCount <> 0) and + if (FDownloadedCount <> 0) and (OptionModulesUpdaterAutoRestart or (MessageDlg(RS_ModulesUpdatedTitle, RS_ModulesUpdatedRestart, mtConfirmation, - mbYesNo, 0) = mrYes) then + mbYesNo, 0) = mrYes)) then RestartFMD; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ad831f6ed..fe496b7b8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4974,6 +4974,10 @@ procedure TMainForm.LoadOptions; cbOptionUpdateListNoMangaInfo.Checked := ReadBool('update', 'UpdateListNoMangaInfo', False); cbOptionUpdateListRemoveDuplicateLocalData.Checked := ReadBool('update', 'UpdateListRemoveDuplicateLocalData', False); + // modules updater + LuaModulesUpdaterForm.ckShowUpdateWarning.Checked := ReadBool('modulesupdater', 'ShowUpdateWarning', OptionModulesUpdaterShowUpdateWarning); + LuaModulesUpdaterForm.ckAutoRestart.Checked := ReadBool('modulesupdater', 'AutoRestart', OptionModulesUpdaterAutoRestart); + // dialogs cbOptionShowQuitDialog.Checked := ReadBool('dialogs', 'ShowQuitDialog', True); cbOptionShowDeleteTaskDialog.Checked := ReadBool('dialogs', 'ShowDeleteDldTaskDialog', True); @@ -5114,6 +5118,10 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); WriteBool('update', 'UpdateListNoMangaInfo', cbOptionUpdateListNoMangaInfo.Checked); WriteBool('update', 'UpdateListRemoveDuplicateLocalData', cbOptionUpdateListRemoveDuplicateLocalData.Checked); + // modules updater + WriteBool('modulesupdater', 'ShowUpdateWarning', LuaModulesUpdaterForm.ckShowUpdateWarning.Checked); + WriteBool('modulesupdater', 'AutoRestart', LuaModulesUpdaterForm.ckAutoRestart.Checked); + // dialogs WriteBool('dialogs', 'ShowQuitDialog', cbOptionShowQuitDialog.Checked); WriteBool('dialogs', 'ShowDeleteDldTaskDialog', cbOptionShowDeleteTaskDialog.Checked); @@ -5255,6 +5263,10 @@ procedure TMainForm.ApplyOptions; tmCheckFavorites.Interval := OptionAutoCheckFavIntervalMinutes * 60000; tmCheckFavorites.Enabled := OptionAutoCheckFavInterval; + // modules updater + OptionModulesUpdaterShowUpdateWarning := LuaModulesUpdaterForm.ckShowUpdateWarning.Checked; + OptionModulesUpdaterAutoRestart := LuaModulesUpdaterForm.ckAutoRestart.Checked; + //misc frmCustomColor.Apply; SimpleException.SetLogFileName(edLogFileName.Text); diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index e4fb6bdfe..d096c694c 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -589,6 +589,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 2e496c3e1..a03bf5d78 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -593,6 +593,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index cde8d85b7..512e765ab 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -579,6 +579,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "Check update" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "Filename" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index c9ade507d..03c304256 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -581,6 +581,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 6844d825d..168041c64 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -579,6 +579,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "Periksa pembaruan" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "Nama" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index aea5d0659..eeb88c303 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -589,6 +589,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index bdbe8ab50..82a1291a1 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -544,6 +544,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index eb621ecda..eac43018c 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -588,6 +588,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 5139e1474..027233010 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -589,6 +589,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "Проверить обновления" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "Файл" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index a87c3e9e2..cf9175de4 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -599,6 +599,14 @@ msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" msgstr "Güncellemelere bak" +#: tluamodulesupdaterform.ckautorestart.caption +msgid "Auto restart" +msgstr "" + +#: tluamodulesupdaterform.ckshowupdatewarning.caption +msgid "Show update warning" +msgstr "" + #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" msgstr "Dosya adı" From 7c9ffc622654e73d201850f7e3bdac4c1deb5c82 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 12:10:27 +0800 Subject: [PATCH 2181/2794] update english localization --- mangadownloader/languages/fmd.en.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 512e765ab..2d62ff95d 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -581,11 +581,11 @@ msgstr "Check update" #: tluamodulesupdaterform.ckautorestart.caption msgid "Auto restart" -msgstr "" +msgstr "Auto restart" #: tluamodulesupdaterform.ckshowupdatewarning.caption msgid "Show update warning" -msgstr "" +msgstr "Show update warning" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" From eb41a0f917495baeca85523f069dc11d62f56521 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 12:12:05 +0800 Subject: [PATCH 2182/2794] update Indonesian localization --- mangadownloader/languages/fmd.id_ID.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 168041c64..3fcbb61f4 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -581,11 +581,11 @@ msgstr "Periksa pembaruan" #: tluamodulesupdaterform.ckautorestart.caption msgid "Auto restart" -msgstr "" +msgstr "Otomatis memuat ulang" #: tluamodulesupdaterform.ckshowupdatewarning.caption msgid "Show update warning" -msgstr "" +msgstr "Tampilkan peringatan pembaruan" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" From b4f3a030cba7d2c33151f72b6d1f9d151dd2ea1e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 12 Feb 2018 10:29:14 +0300 Subject: [PATCH 2183/2794] update Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 027233010..f6fb9ab5d 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -591,11 +591,11 @@ msgstr "Проверить обновления" #: tluamodulesupdaterform.ckautorestart.caption msgid "Auto restart" -msgstr "" +msgstr "Автоматически перезапускать программу" #: tluamodulesupdaterform.ckshowupdatewarning.caption msgid "Show update warning" -msgstr "" +msgstr "Показывать предупреждение" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" From f3f157d695ad0351e0e7b2e19ee3d67332ea6e5f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 12 Feb 2018 10:42:56 +0300 Subject: [PATCH 2184/2794] add ChibiManga [EN-SC] fixes #942 --- baseunits/modules/myMangaReaderCMS.pas | 1 + changelog.txt | 1 + config/mangalist.ini | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas index 7ceb6db02..1398094c5 100644 --- a/baseunits/modules/myMangaReaderCMS.pas +++ b/baseunits/modules/myMangaReaderCMS.pas @@ -112,6 +112,7 @@ procedure RegisterModule; AddWebsiteModule('MangaID', 'http://mangaid.co'); AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); AddWebsiteModule('MangaDesu','http://mangadesu.net'); + AddWebsiteModule('ChibiManga','http://www.cmreader.info'); end; initialization diff --git a/changelog.txt b/changelog.txt index c6fbfe097..2afeaa63c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,7 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.137.0 (--2018) +[+] Added ChibiManga [EN-SC] [*] Fixed updater can't find 7za.exe, you need to download this release manually [*] Update Turkish localization [*] Update Indonesian localization diff --git a/config/mangalist.ini b/config/mangalist.ini index e8bfd202b..f629da27d 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,Mangaf English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree +English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics From 3c7a57e993d4476ed78ad1b160ee3938f15085e5 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Mon, 12 Feb 2018 13:05:57 +0300 Subject: [PATCH 2185/2794] Update fmd.tr_TR.po - Modulesupdater changes translated. --- mangadownloader/languages/fmd.tr_TR.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index cf9175de4..31b41a9f5 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -601,11 +601,11 @@ msgstr "Güncellemelere bak" #: tluamodulesupdaterform.ckautorestart.caption msgid "Auto restart" -msgstr "" +msgstr "Otomatik yeniden başlat" #: tluamodulesupdaterform.ckshowupdatewarning.caption msgid "Show update warning" -msgstr "" +msgstr "Güncelleme uyarısını göster" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" From 109e27295c6574b8cb3f75baeafa13cc90626493 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 20:02:00 +0800 Subject: [PATCH 2186/2794] fix read params --- mangadownloader/md.lpr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 8158d6c53..a3be1fd33 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -28,7 +28,7 @@ {$R *.res} begin - for i := 1 to ParamCount-1 do + for i := 1 to ParamCount do begin p := AnsiLowerCase(ParamStr(i)); if p = '--lua-dofile' then From 16a8731250b75008122f469e456793633deea4a6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 20:20:37 +0800 Subject: [PATCH 2187/2794] luaxquery, fixed xpathstringall --- baseunits/lua/luaXQuery.pas | 72 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index 28b326ed9..6f0e99f5d 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -77,46 +77,42 @@ function xquery_xpathstring(L: Plua_State): Integer; cdecl; function xquery_xpathstringall(L: Plua_State): Integer; cdecl; var u: TUserData; - t: Integer; begin + Result := 0; u := TUserData(luaClassGetObject(L)); - t := lua_gettop(L); - if t > 1 then - if t = 2 then - begin - if lua_isstring(L, 2) then - begin - lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1), lua_tostring(L, 2))); - Result := 1; - end - else - if lua_isuserdata(L, 2) then - begin - u.XPathStringAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2))); - Result := 0; - end; - end - else - if t = 3 then - begin - if lua_isstring(L, 2) then - begin - lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1), lua_tostring(L, 2), - TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue)); - Result := 1; - end - else - if lua_isuserdata(L, 2) then - begin - u.XPathStringAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), - TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue); - Result := 0; - end; - end - else - begin - lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1))); - Result := 1; + case lua_gettop(L) of + 1: begin + lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1))); + Result := 1; + end; + 2: begin + if lua_isstring(L, 2) then + begin + lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1), lua_tostring(L, 2))); + Result := 1; + end + else + if lua_isuserdata(L, 2) then + begin + u.XPathStringAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2))); + Result := 0; + end; + end; + 3: begin + if lua_isstring(L, 2) then + begin + lua_pushstring(L, u.XPathStringAll(lua_tostring(L, 1), lua_tostring(L, 2), + TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue)); + Result := 1; + end + else + if lua_isuserdata(L, 2) then + begin + u.XPathStringAll(lua_tostring(L, 1), TStrings(luaGetUserData(L, 2)), + TLuaIXQValue(luaGetUserData(L, 3)).FIXQValue); + Result := 0; + end; + end; end; end; From 499a575684229f4c76786a688fdedce2004b6486 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 20:25:02 +0800 Subject: [PATCH 2188/2794] convert mymangareadercms to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/myMangaReaderCMS.pas | 121 ------------------------- lua/modules/myReaderMangaCMS.lua | 72 +++++++++++++++ 3 files changed, 72 insertions(+), 122 deletions(-) delete mode 100644 baseunits/modules/myMangaReaderCMS.pas create mode 100644 lua/modules/myReaderMangaCMS.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 75fc7825a..c1b647635 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,6 +1,5 @@ uses WPManga, - myMangaReaderCMS, MangaFox, Mangacan, PecintaKomik, diff --git a/baseunits/modules/myMangaReaderCMS.pas b/baseunits/modules/myMangaReaderCMS.pas deleted file mode 100644 index 1398094c5..000000000 --- a/baseunits/modules/myMangaReaderCMS.pas +++ /dev/null @@ -1,121 +0,0 @@ -unit myMangaReaderCMS; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/changeMangaList?type=text') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - XPathHREFAll('//li/a', ALinks, ANames); - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//div[@class="boxed"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h2[@class="widget-title"]'); - if Module.Website = 'MangaDenizi' then - status := MangaInfoStatusIfPos(XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') - else - status := MangaInfoStatusIfPos(XPathString('//dt[.=("Status","Estado")]/following-sibling::dd[1]')); - authors := XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)")]/following-sibling::dd[1]/string-join(*,", ")'); - artists := XPathStringAll('//dt[.="Artist(s)"]/following-sibling::dd[1]/string-join(*,", ")'); - genres := XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías")]/following-sibling::dd[1]/string-join(*,", ")'); - summary := XPathString('//div[@class="well"]/p'); - for v in XPath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') do - begin - chapterLinks.Add(XPathString('a/@href', v)); - chapterName.Add(XPathString('normalize-space(.)', v)); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('//div[@id="all"]/img/@data-src', PageLinks); - if PageLinks.Count = 0 then - XPathStringAll('//div[@id="all"]/img/@src', PageLinks); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; - begin - Result := AddModule; - with Result do - begin - Website := AWebsite; - RootURL := ARootURL; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; - end; - -begin - AddWebsiteModule('Komikid', 'http://www.komikid.com'); - AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); - AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); - AddWebsiteModule('MangaID', 'http://mangaid.co'); - AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); - AddWebsiteModule('MangaDesu','http://mangadesu.net'); - AddWebsiteModule('ChibiManga','http://www.cmreader.info'); -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua new file mode 100644 index 000000000..c7772909a --- /dev/null +++ b/lua/modules/myReaderMangaCMS.lua @@ -0,0 +1,72 @@ +function GetNameAndLink() + if http.GET(module.RootURL .. '/changeMangaList?type=text') then + x = TXQuery.Create(http.Document) + x.XPathHREFAll('//li/a', links, names) + return no_error + else + return net_problem + end +end + +function GetInfo(); + mangainfo.url = MaybeFillHost(module.RootURL, url) + if http.GET(mangainfo.url) then + x = TXQuery.Create(http.Document) + mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//h2[@class="widget-title"]') + end + if module.Website == 'MangaDenizi' then + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') + else + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.=("Status","Estado")]/following-sibling::dd[1]')) + end + mangainfo.authors = x.XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.artists = x.XPathStringAll('//dt[.="Artist(s)"]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.genres = x.XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.summary = x.XPathString('//div[@class="well"]/p') + v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') + for i = 1, v.Count do + mangainfo.chapterLinks.Add(x.XPathString('a/@href', v)) + mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v)) + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + if http.GET(MaybeFillHost(module.RootURL, url)) then + x = TXQuery.Create(http.Document) + x.XPathStringAll('//div[@id="all"]/img/@data-src', task.PageLinks) + if task.PageLinks.Count == 0 then + x.XPathStringAll('//div[@id="all"]/img/@src', task.PageLinks) + end + return true + else + return false + end +end + +function AddWebsiteModule(name, url) + local m = NewModule() + m.Website = name + m.RootURL = url + m.LastUpdated = 'February 12, 2018' + m.OnGetNameAndLink = 'GetNameAndLink' + m.OnGetInfo = 'GetInfo' + m.OnGetPageNumber = 'GetPageNumber' + return m +end + +function Init() + AddWebsiteModule('Komikid', 'http://www.komikid.com'); + AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); + AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); + AddWebsiteModule('MangaID', 'http://mangaid.co'); + AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); + AddWebsiteModule('MangaDesu','http://mangadesu.net'); + AddWebsiteModule('ChibiManga','http://www.cmreader.info'); +end From fc46fdfc27bff7dab7af7139f977958b0e1b47ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 20:34:51 +0800 Subject: [PATCH 2189/2794] myreadermangacms, fix get chapters --- lua/modules/myReaderMangaCMS.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index c7772909a..1297f85a3 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -27,8 +27,9 @@ function GetInfo(); mangainfo.summary = x.XPathString('//div[@class="well"]/p') v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') for i = 1, v.Count do - mangainfo.chapterLinks.Add(x.XPathString('a/@href', v)) - mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v)) + v2 = v.Get(i) + mangainfo.chapterLinks.Add(x.XPathString('a/@href', v2)) + mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v2)) end InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) return no_error From 1c602799f881b5a3b5542532b15ef930e4f71d28 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 12 Feb 2018 20:41:09 +0800 Subject: [PATCH 2190/2794] Bump version 0.9.137.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2afeaa63c..cada455a0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.137.0 (--2018) +0.9.137.0 (12-02-2018) [+] Added ChibiManga [EN-SC] [*] Fixed updater can't find 7za.exe, you need to download this release manually [*] Update Turkish localization diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 70ba9bdab..b48005712 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="136"/> + <RevisionNr Value="137"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 09a370e03..92d50a212 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.136.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.136.0/fmd_0.9.136.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.136.0/fmd_0.9.136.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.136.0/fmd_0.9.136.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.136.0/fmd_0.9.136.0_Win64.7z +VERSION=0.9.137.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.137.0/fmd_0.9.137.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.137.0/fmd_0.9.137.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.137.0/fmd_0.9.137.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.137.0/fmd_0.9.137.0_Win64.7z From 7e79cdd9d6ac1058034a3d725da2c5789e14668d Mon Sep 17 00:00:00 2001 From: Ghost Writer <ghostwriter.tncs@gmail.com> Date: Mon, 12 Feb 2018 16:19:38 +0100 Subject: [PATCH 2191/2794] Added option Delete completed tasks on close. Update frmMain.pas Update frmMain.pas --- mangadownloader/forms/frmMain.lfm | 8 ++++++++ mangadownloader/forms/frmMain.pas | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 919af3b5c..5d49b61cd 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2907,6 +2907,14 @@ object MainForm: TMainForm ParentFont = False TabOrder = 7 end + object cbOptionDeleteCompletedTasksOnClose: TCheckBox + Left = 346 + Height = 19 + Top = 159 + Width = 236 + Caption = 'Delete completed tasks on close' + TabOrder = 8 + end end object tsView: TTabSheet Caption = 'View' diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fe496b7b8..36ff88e16 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -52,6 +52,7 @@ TMainForm = class(TForm) cbOptionAutoCheckFavDownload: TCheckBox; cbOptionAutoCheckFavRemoveCompletedManga: TCheckBox; cbOptionAutoOpenFavStartup: TCheckBox; + cbOptionDeleteCompletedTasksOnClose: TCheckBox; cbOptionEnableLoadCover: TCheckBox; cbOptionMinimizeOnStart: TCheckBox; cbOptionShowBalloonHint: TCheckBox; @@ -1323,6 +1324,11 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin Logger.Send(Self.ClassName+'.FormClose'); + if cbOptionDeleteCompletedTasksOnClose.Checked then + begin + if DLManager.TaskStatusPresent([STATUS_FINISH]) then + miDownloadDeleteCompletedClick(miDownloadDeleteCompleted); + end; if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then @@ -4889,6 +4895,7 @@ procedure TMainForm.LoadOptions; cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); cbOptionMinimizeOnStart.Checked := ReadBool('general', 'MinimizeOnStart', False); cbOptionMinimizeToTray.Checked := ReadBool('general', 'MinimizeToTray', False); + cbOptionDeleteCompletedTasksOnClose.Checked := ReadBool('general', 'DeleteCompletedTasksOnClose', False); cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); edOptionExternalPath.Text := ReadString('general', 'ExternalProgramPath', ''); edOptionExternalParams.Text := ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); @@ -5045,6 +5052,7 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); WriteString('languages', 'Selected', AvailableLanguages.Names[cbLanguages.ItemIndex]); WriteBool('general', 'MinimizeOnStart', cbOptionMinimizeOnStart.Checked); WriteBool('general', 'MinimizeToTray', cbOptionMinimizeToTray.Checked); + WriteBool('general', 'DeleteCompletedTasksOnClose', cbOptionDeleteCompletedTasksOnClose.Checked); WriteInteger('general', 'LetFMDDo', cbOptionLetFMDDo.ItemIndex); WriteString('general', 'ExternalProgramPath', edOptionExternalPath.Text); WriteString('general', 'ExternalProgramParams', edOptionExternalParams.Text); From 2d9aa897fa722f2e45eeb294a39a530a4b5e204c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 12 Feb 2018 19:44:21 +0300 Subject: [PATCH 2192/2794] luaxquery, add XPathCount --- baseunits/lua/luaXQuery.pas | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index 6f0e99f5d..e722a9472 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -144,19 +144,33 @@ function xquery_xpathhreftitleall(L: Plua_State): Integer; cdecl; Result := 0; end; +function xquery_xpathcount(L: Plua_State): Integer; cdecl; +var + u: TUserData; +begin + u := TUserData(luaClassGetObject(L)); + if lua_gettop(L) = 2 then + lua_pushinteger(L, u.XPathCount(lua_tostring(L, 1), + TLuaIXQValue(luaGetUserData(L, 2)).FIXQValue)) + else + lua_pushinteger(L, u.XPathCount(lua_tostring(L, 1))); + Result := 1; +end; + const constructs: packed array [0..2] of luaL_Reg = ( (name: 'New'; func: @xquery_create), (name: 'Create'; func: @xquery_create), (name: nil; func: nil) ); - methods: packed array [0..6] of luaL_Reg = ( + methods: packed array [0..7] of luaL_Reg = ( (name: 'ParseHTML'; func: @xquery_parsehtml), (name: 'XPath'; func: @xquery_xpath), (name: 'XPathString'; func: @xquery_xpathstring), (name: 'XpathStringAll'; func: @xquery_xpathstringall), (name: 'XpathHREFAll'; func: @xquery_xpathhrefall), (name: 'XpathHREFTitleAll'; func: @xquery_xpathhreftitleall), + (name: 'XPathCount'; func: @xquery_xpathcount), (name: nil; func: nil) ); From b29d6618c0bcf6bae196b258cce9bbae80c91c8d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 12 Feb 2018 20:27:08 +0300 Subject: [PATCH 2193/2794] add NeuManga [ID] fixes #766 --- config/mangalist.ini | 2 +- lua/modules/NeuManga.lua | 67 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 lua/modules/NeuManga.lua diff --git a/config/mangalist.ini b/config/mangalist.ini index f629da27d..f76214a63 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,7 +9,7 @@ Italian=MangaEden_IT,NineMangaIT English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga -Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics +Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,NeuManga,PecintaKomik,Subapics Malaysian-Indonesian= Polish= Portugues=CentralDeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas diff --git a/lua/modules/NeuManga.lua b/lua/modules/NeuManga.lua new file mode 100644 index 000000000..181bf7fbe --- /dev/null +++ b/lua/modules/NeuManga.lua @@ -0,0 +1,67 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//h1[@class="manga1"]/text()') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[@class="imagemg"]/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//div[@class="info"]/span[contains(., "Status")]/a')) + mangainfo.authors = x.XPathStringAll('//div[@class="info"]/span[contains(., "Author")]/a') + mangainfo.artists = x.XPathStringAll('//div[@class="info"]/span[contains(., "Artist")]/a') + mangainfo.genres = x.XPathStringAll('//div[@class="info"]/span[contains(., "Genre")]/a') + mangainfo.summary = x.XPathStringAll('//div[@class="summary"]/text()', '') + v=x.xpath('//div[@id="scans"]/div[1]/div[@class="item-content"]/a') + for i=1, v.count do + v1=v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('href')) + mangainfo.chapternames.add(x.xpathstringall('text()', '', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_error + end +end + +function GetPageNumber() + http.cookies.values['age_confirmed'] = '1' + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + task.pagenumber=x.xpathcount('(//select[@class="page"])[1]/option') + return true + else + return false + end +end + +function GetImageURL() + s=url:gsub('%?.+$','')..'/'..tostring(workid+1) + http.cookies.values['age_confirmed'] = '1' + if http.get(MaybeFillHost(module.rooturl,s)) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]=x.xpathstring('//img[@class="imagechap"]/@src') + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/manga') then + x=TXQuery.Create(http.Document) + x.xpathhrefall('//div[@class="alplist"]/li/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.website='NeuManga' + m.rooturl='http://neumanga.tv' + m.lastupdated='February 12, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetimageurl='GetImageURL' + m.ongetnameandlink='GetNameAndLink' +end \ No newline at end of file From 122f37c3124b0162da79e47b80629d871285cc57 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 09:15:39 +0800 Subject: [PATCH 2194/2794] fix delete completed tasks on close --- baseunits/FMDOptions.pas | 2 ++ mangadownloader/forms/frmMain.lfm | 13 ++++++++----- mangadownloader/forms/frmMain.lrj | 1 + mangadownloader/forms/frmMain.pas | 11 +++++------ mangadownloader/languages/fmd.de.po | 4 ++++ mangadownloader/languages/fmd.el_GR.po | 4 ++++ mangadownloader/languages/fmd.en.po | 4 ++++ mangadownloader/languages/fmd.es.po | 4 ++++ mangadownloader/languages/fmd.id_ID.po | 4 ++++ mangadownloader/languages/fmd.pl_PL.po | 4 ++++ mangadownloader/languages/fmd.po | 4 ++++ mangadownloader/languages/fmd.pt_BR.po | 4 ++++ mangadownloader/languages/fmd.ru_RU.po | 4 ++++ mangadownloader/languages/fmd.tr_TR.po | 4 ++++ 14 files changed, 56 insertions(+), 11 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 4ea1f0c11..2f7a30897 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -108,7 +108,9 @@ TIniFileRun = class(IniFiles.TMemIniFile) // available website AvailableWebsite: TStringList; + // general OptionLetFMDDo: TFMDDo = DO_NOTHING; + OptionDeleteCompletedTasksOnClose: Boolean = False; // saveto OptionChangeUnicodeCharacter: Boolean = False; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 5d49b61cd..8b7602d47 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -2697,11 +2697,11 @@ object MainForm: TMainForm end object gbOptionExternal: TGroupBox AnchorSideLeft.Control = cbOptionLiveSearch - AnchorSideTop.Control = cbOptionLiveSearch + AnchorSideTop.Control = cbOptionDeleteCompletedTasksOnClose AnchorSideTop.Side = asrBottom Left = 4 Height = 118 - Top = 267 + Top = 290 Width = 742 Anchors = [akTop, akLeft, akRight] BorderSpacing.Top = 20 @@ -2908,10 +2908,13 @@ object MainForm: TMainForm TabOrder = 7 end object cbOptionDeleteCompletedTasksOnClose: TCheckBox - Left = 346 + AnchorSideLeft.Control = tsGeneral + AnchorSideTop.Control = cbOptionLiveSearch + AnchorSideTop.Side = asrBottom + Left = 4 Height = 19 - Top = 159 - Width = 236 + Top = 251 + Width = 189 Caption = 'Delete completed tasks on close' TabOrder = 8 end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index a4e93d740..df3477100 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -156,6 +156,7 @@ {"hash":93623386,"name":"tmainform.lboptionletfmddo.caption","sourcebytes":[65,102,116,101,114,32,100,111,119,110,108,111,97,100,32,102,105,110,105,115,104,58],"value":"After download finish:"}, {"hash":160062057,"name":"tmainform.lboptionnewmangatime.caption","sourcebytes":[78,101,119,32,109,97,110,103,97,32,98,97,115,101,100,32,111,110,32,32,105,116,39,115,32,117,112,100,97,116,101,32,116,105,109,101,32,40,100,97,121,115,41],"value":"New manga based on it's update time (days)"}, {"hash":69131508,"name":"tmainform.cboptionminimizeonstart.caption","sourcebytes":[77,105,110,105,109,105,122,101,32,111,110,32,115,116,97,114,116],"value":"Minimize on start"}, +{"hash":134851429,"name":"tmainform.cboptiondeletecompletedtasksonclose.caption","sourcebytes":[68,101,108,101,116,101,32,99,111,109,112,108,101,116,101,100,32,116,97,115,107,115,32,111,110,32,99,108,111,115,101],"value":"Delete completed tasks on close"}, {"hash":380871,"name":"tmainform.tsview.caption","sourcebytes":[86,105,101,119],"value":"View"}, {"hash":126054082,"name":"tmainform.cboptionshowdownloadtoolbar.caption","sourcebytes":[83,104,111,119,32,100,111,119,110,108,111,97,100,115,32,116,111,111,108,98,97,114],"value":"Show downloads toolbar"}, {"hash":157437400,"name":"tmainform.gbdroptarget.caption","sourcebytes":[68,114,111,112,32,66,111,120],"value":"Drop Box"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 36ff88e16..e7cedbfcd 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1324,11 +1324,6 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin Logger.Send(Self.ClassName+'.FormClose'); - if cbOptionDeleteCompletedTasksOnClose.Checked then - begin - if DLManager.TaskStatusPresent([STATUS_FINISH]) then - miDownloadDeleteCompletedClick(miDownloadDeleteCompleted); - end; if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then @@ -1344,6 +1339,9 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin + if OptionDeleteCompletedTasksOnClose then + miDownloadDeleteCompletedClick(miDownloadDeleteCompleted); + isExiting := True; {$ifdef windows} if Assigned(PrevWndProc) then @@ -4895,7 +4893,7 @@ procedure TMainForm.LoadOptions; cbOptionLiveSearch.Checked := ReadBool('general', 'LiveSearch', True); cbOptionMinimizeOnStart.Checked := ReadBool('general', 'MinimizeOnStart', False); cbOptionMinimizeToTray.Checked := ReadBool('general', 'MinimizeToTray', False); - cbOptionDeleteCompletedTasksOnClose.Checked := ReadBool('general', 'DeleteCompletedTasksOnClose', False); + cbOptionDeleteCompletedTasksOnClose.Checked := ReadBool('general', 'DeleteCompletedTasksOnClose', OptionDeleteCompletedTasksOnClose); cbOptionLetFMDDo.ItemIndex := ReadInteger('general', 'LetFMDDo', 0); edOptionExternalPath.Text := ReadString('general', 'ExternalProgramPath', ''); edOptionExternalParams.Text := ReadString('general', 'ExternalProgramParams', DEFAULT_EXPARAM); @@ -5211,6 +5209,7 @@ procedure TMainForm.ApplyOptions; end; OptionLetFMDDo := TFMDDo(cbOptionLetFMDDo.ItemIndex); OptionEnableLoadCover := cbOptionEnableLoadCover.Checked; + OptionDeleteCompletedTasksOnClose := cbOptionDeleteCompletedTasksOnClose.Checked; //view ToolBarDownload.Visible := cbOptionShowDownloadToolbar.Checked; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index d096c694c..4d212377f 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -742,6 +742,10 @@ msgstr "Ersetze alle Unicode Zeichen mit" msgid "Enable this if you have problem with unicode character in path." msgstr "Aktiviere dies, falls du Probleme mit Unicode Zeichen in diesem Pfad hast" +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Kapitel" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index a03bf5d78..9f46cc0e8 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -746,6 +746,10 @@ msgstr "Αλλαγή όλων των unicode χαρακτήρων με" msgid "Enable this if you have problem with unicode character in path." msgstr "Ενεργοποιήστε το αν έχετε πρόβλημα με χαρακτήρες unicode στη διαδρομή." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Κεφάλαιο" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 2d62ff95d..1bc726581 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -728,6 +728,10 @@ msgstr "Replace all unicode character with" msgid "Enable this if you have problem with unicode character in path." msgstr "Enable this if you have problem with unicode character in path." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Chapter" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 03c304256..e344cc0cf 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -730,6 +730,10 @@ msgstr "Reemplazar todo Carácter Unicode con" msgid "Enable this if you have problem with unicode character in path." msgstr "Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ruta" +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Capítulo" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 3fcbb61f4..ba6a2dcba 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -728,6 +728,10 @@ msgstr "Ubah semua simbol unicode menjadi" msgid "Enable this if you have problem with unicode character in path." msgstr "Aktifkan pilihan ini jika anda mengalami masalah dengan karakter unicode pada path." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Bab" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index eeb88c303..436130833 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -742,6 +742,10 @@ msgstr "Wymień wszystkie znaki Unicode" msgid "Enable this if you have problem with unicode character in path." msgstr "Włącz tę opcję, jeśli masz problem z znakami Unicode w ścieżce." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Rozdział" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 82a1291a1..8aae3a65c 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -693,6 +693,10 @@ msgstr "" msgid "Enable this if you have problem with unicode character in path." msgstr "" +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index eac43018c..5e8df4825 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -741,6 +741,10 @@ msgstr "Substituir todos caracteres unidcode com" msgid "Enable this if you have problem with unicode character in path." msgstr "Habilite isto se você tem problemas com caminhos com caracteres unicode." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Capítulo" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index f6fb9ab5d..b3309a902 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -738,6 +738,10 @@ msgstr "Заменить все символы Юникода на" msgid "Enable this if you have problem with unicode character in path." msgstr "Включите, если возникли проблемы с Unicode-символами в пути." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Глава" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 31b41a9f5..61f11eb33 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -752,6 +752,10 @@ msgstr "Tüm Unicode karakterleri şununla değiştir" msgid "Enable this if you have problem with unicode character in path." msgstr "Yolda Unicode karakter varsa bunu açın." +#: tmainform.cboptiondeletecompletedtasksonclose.caption +msgid "Delete completed tasks on close" +msgstr "" + #: tmainform.cboptiondigitchapter.caption msgid "Chapter" msgstr "Bölüm" From 296999a3ab7cf52e617bddf343d9e2ec3e050e3b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 09:21:48 +0800 Subject: [PATCH 2195/2794] newumanga, compatibility with fmd 0.9.137.0 --- lua/modules/NeuManga.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/NeuManga.lua b/lua/modules/NeuManga.lua index 181bf7fbe..7432ae71c 100644 --- a/lua/modules/NeuManga.lua +++ b/lua/modules/NeuManga.lua @@ -26,7 +26,7 @@ function GetPageNumber() http.cookies.values['age_confirmed'] = '1' if http.get(MaybeFillHost(module.rooturl,url)) then x=TXQuery.Create(http.Document) - task.pagenumber=x.xpathcount('(//select[@class="page"])[1]/option') + task.pagenumber=x.xpath('(//select[@class="page"])[1]/option').count return true else return false From 865c607f507998a300f5c51aca783242b764588d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 10:29:12 +0800 Subject: [PATCH 2196/2794] added option to save png as jpeg (#939) --- baseunits/FMDOptions.pas | 6 +- baseunits/uBaseUnit.pas | 44 ++++++++++++-- mangadownloader/forms/frmMain.lfm | 80 +++++++++++++++----------- mangadownloader/forms/frmMain.lrj | 13 +++-- mangadownloader/forms/frmMain.pas | 47 +++++++-------- mangadownloader/languages/fmd.de.po | 47 ++++++++------- mangadownloader/languages/fmd.el_GR.po | 47 ++++++++------- mangadownloader/languages/fmd.en.po | 57 +++++++++++------- mangadownloader/languages/fmd.es.po | 47 ++++++++------- mangadownloader/languages/fmd.id_ID.po | 57 +++++++++++------- mangadownloader/languages/fmd.pl_PL.po | 47 ++++++++------- mangadownloader/languages/fmd.po | 47 ++++++++------- mangadownloader/languages/fmd.pt_BR.po | 47 ++++++++------- mangadownloader/languages/fmd.ru_RU.po | 57 +++++++++++------- mangadownloader/languages/fmd.tr_TR.po | 57 +++++++++++------- 15 files changed, 425 insertions(+), 275 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 2f7a30897..4d47e3560 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -128,9 +128,9 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionPDFQuality: Cardinal = 95; - OptionWebPConvertTo: Integer = 1; - OptionWebPPNGLevel: Integer = 1; - OptionWebPJpegQuality: Integer = 80; + OptionWebPSaveAs: Integer = 1; + OptionPNGCompressionLevel: Integer = 1; + OptionJPEGQuality: Integer = 80; // connections OptionMaxParallel: Integer = 1; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 0c3faaaa5..d194f37b3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -664,7 +664,10 @@ function GetURLFromBitly(const URL: String): String; // convert webp function WebPToPNGStream(const AStream: TMemoryStream; const ALevel: Tcompressionlevel = clfastest): Boolean; -function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer = 80): Boolean; +function WebPToJPEGStream(const AStream: TMemoryStream; const AQuality: Integer = 80): Boolean; + +// convert png +function PNGToJPEGStream(const AStream: TMemoryStream; const AQuality: Integer = 80): Boolean; // try to save tmemorystream to file, return the saved filename if success, otherwise return empty string function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt = 0): String; overload; @@ -3252,7 +3255,7 @@ function WebPToPNGStream(const AStream: TMemoryStream; end; end; -function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer +function WebPToJPEGStream(const AStream: TMemoryStream; const AQuality: Integer ): Boolean; var mem: TMemBitmap; @@ -3277,6 +3280,30 @@ function WebPToJpegStream(const AStream: TMemoryStream; const AQuality: Integer end; end; +function PNGToJPEGStream(const AStream: TMemoryStream; const AQuality: Integer): Boolean; +var + img: TFPCustomImage; + writer: TFPWriterJPEG; +begin + Result := False; + img := TFPCustomImage.create(0,0); + try + writer := nil; + try + img.LoadFromStream(AStream); + writer := TFPWriterJPEG.create; + writer.CompressionQuality := AQuality; + img.SaveToStream(AStream, writer); + Result := True; + except + end; + if writer <> nil then + writer.Free; + finally + img.Free; + end; +end; + function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Age: LongInt): String; var p, f: String; @@ -3288,11 +3315,18 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag p := CorrectPathSys(Path); if ForceDirectoriesUTF8(p) then begin f := GetImageStreamExt(Stream); + if f = 'png' then + begin + if PNGToJPEGStream(Stream, OptionJPEGQuality) then f := 'jpg' + end + else if f = 'webp' then - case OptionWebPConvertTo of - 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionWebPPNGLevel)) then f := 'png'; - 2: if WebPToJpegStream(Stream, OptionWebPJpegQuality) then f := 'jpg'; + begin + case OptionWebPSaveAs of + 1: if WebPToPNGStream(Stream, Tcompressionlevel(OptionPNGCompressionLevel)) then f := 'png'; + 2: if WebPToJPEGStream(Stream, OptionJPEGQuality) then f := 'jpg'; end; + end; if f = '' then Exit; f := p + FileName + '.' + f; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 8b7602d47..2d71bd59b 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -16,7 +16,6 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True - LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -3473,13 +3472,13 @@ object MainForm: TMainForm end object gbOptionRenaming: TGroupBox AnchorSideLeft.Control = lbDefaultDownloadPath - AnchorSideTop.Control = gbWebP + AnchorSideTop.Control = gbImageConversion AnchorSideTop.Side = asrBottom AnchorSideRight.Control = lbDefaultDownloadPath AnchorSideRight.Side = asrBottom Left = 4 Height = 302 - Top = 250 + Top = 271 Width = 728 Anchors = [akTop, akLeft, akRight] AutoSize = True @@ -3866,74 +3865,77 @@ object MainForm: TMainForm TabOrder = 4 TextHint = 'Default download path' end - object gbWebP: TGroupBox + object gbImageConversion: TGroupBox AnchorSideLeft.Control = lbDefaultDownloadPath AnchorSideTop.Control = seOptionPDFQuality AnchorSideTop.Side = asrBottom AnchorSideRight.Control = sbSaveTo AnchorSideRight.Side = asrBottom Left = 4 - Height = 101 + Height = 122 Top = 145 Width = 728 Anchors = [akTop, akLeft, akRight] AutoSize = True - Caption = 'WebP' + Caption = 'Image Conversion' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 4 ChildSizing.HorizontalSpacing = 6 ChildSizing.VerticalSpacing = 6 - ClientHeight = 81 + ClientHeight = 102 ClientWidth = 724 TabOrder = 5 - object lbWebPConvertTo: TLabel + object lbWebPSaveAs: TLabel + AnchorSideLeft.Control = gbImageConversion + AnchorSideTop.Control = ckPNGSaveAsJPEG + AnchorSideTop.Side = asrBottom Left = 4 Height = 15 - Top = 8 + Top = 29 Width = 72 - Caption = 'Save WebP to' + Caption = 'Save WebP as' ParentColor = False end - object cbWebPConvertTo: TComboBox - AnchorSideLeft.Control = lbWebPConvertTo + object cbWebPSaveAs: TComboBox + AnchorSideLeft.Control = lbWebPSaveAs AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = lbWebPConvertTo + AnchorSideTop.Control = lbWebPSaveAs AnchorSideTop.Side = asrCenter Left = 82 Height = 23 - Top = 4 + Top = 25 Width = 76 ItemHeight = 15 ItemIndex = 1 Items.Strings = ( 'WebP' 'PNG' - 'Jpeg' + 'JPEG' ) Style = csDropDownList TabOrder = 0 Text = 'PNG' end - object lbWebPPNGCompressionLevel: TLabel - AnchorSideLeft.Control = lbWebPConvertTo - AnchorSideTop.Control = cbWebPConvertTo + object lbPNGCompressionLevel: TLabel + AnchorSideLeft.Control = lbWebPSaveAs + AnchorSideTop.Control = cbWebPSaveAs AnchorSideTop.Side = asrBottom Left = 4 Height = 15 - Top = 33 + Top = 54 Width = 124 Caption = 'PNG Compression level' ParentColor = False end - object cbWebPPNGCompressionLevel: TComboBox - AnchorSideLeft.Control = lbWebPPNGCompressionLevel + object cbPNGCompressionLevel: TComboBox + AnchorSideLeft.Control = lbPNGCompressionLevel AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = lbWebPPNGCompressionLevel + AnchorSideTop.Control = lbPNGCompressionLevel AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom Left = 134 Height = 23 - Top = 29 + Top = 50 Width = 100 ItemHeight = 15 ItemIndex = 1 @@ -3947,31 +3949,41 @@ object MainForm: TMainForm TabOrder = 1 Text = 'Fastest' end - object lbWebPJpegQuality: TLabel - AnchorSideLeft.Control = lbWebPConvertTo - AnchorSideTop.Control = cbWebPPNGCompressionLevel + object lbJPEGQuality: TLabel + AnchorSideLeft.Control = lbWebPSaveAs + AnchorSideTop.Control = cbPNGCompressionLevel AnchorSideTop.Side = asrBottom Left = 4 Height = 15 - Top = 58 - Width = 63 - Caption = 'Jpeg quality' + Top = 79 + Width = 64 + Caption = 'JPEG quality' ParentColor = False end - object seWebPJpegQuality: TSpinEdit - AnchorSideLeft.Control = lbWebPJpegQuality + object seJPEGQuality: TSpinEdit + AnchorSideLeft.Control = lbJPEGQuality AnchorSideLeft.Side = asrBottom - AnchorSideTop.Control = lbWebPJpegQuality + AnchorSideTop.Control = lbJPEGQuality AnchorSideTop.Side = asrCenter AnchorSideRight.Side = asrBottom - Left = 73 + Left = 74 Height = 23 - Top = 54 + Top = 75 Width = 47 MinValue = 1 TabOrder = 2 Value = 80 end + object ckPNGSaveAsJPEG: TCheckBox + AnchorSideLeft.Control = gbImageConversion + AnchorSideTop.Control = gbImageConversion + Left = 4 + Height = 19 + Top = 4 + Width = 113 + Caption = 'Save PNG as JPEG' + TabOrder = 3 + end end end end diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index df3477100..71d6a0b70 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -214,12 +214,13 @@ {"hash":265971401,"name":"tmainform.lboptionpdfquality.hint","sourcebytes":[49,48,48,32,61,32,70,108,97,116,101,69,110,99,111,100,101,32,40,108,111,115,115,108,101,115,115,41,44,32,108,111,119,101,114,32,61,32,68,67,84,69,110,99,111,100,101,32,40,108,111,115,115,121,41],"value":"100 = FlateEncode (lossless), lower = DCTEncode (lossy)"}, {"hash":13786124,"name":"tmainform.lboptionpdfquality.caption","sourcebytes":[80,68,70,32,99,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PDF compression level"}, {"hash":8726312,"name":"tmainform.edoptiondefaultpath.texthint","sourcebytes":[68,101,102,97,117,108,116,32,100,111,119,110,108,111,97,100,32,112,97,116,104],"value":"Default download path"}, -{"hash":383856,"name":"tmainform.gbwebp.caption","sourcebytes":[87,101,98,80],"value":"WebP"}, -{"hash":137355519,"name":"tmainform.lbwebpconvertto.caption","sourcebytes":[83,97,118,101,32,87,101,98,80,32,116,111],"value":"Save WebP to"}, -{"hash":21799,"name":"tmainform.cbwebpconvertto.text","sourcebytes":[80,78,71],"value":"PNG"}, -{"hash":32654252,"name":"tmainform.lbwebppngcompressionlevel.caption","sourcebytes":[80,78,71,32,67,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PNG Compression level"}, -{"hash":210414820,"name":"tmainform.cbwebppngcompressionlevel.text","sourcebytes":[70,97,115,116,101,115,116],"value":"Fastest"}, -{"hash":228764105,"name":"tmainform.lbwebpjpegquality.caption","sourcebytes":[74,112,101,103,32,113,117,97,108,105,116,121],"value":"Jpeg quality"}, +{"hash":28850558,"name":"tmainform.gbimageconversion.caption","sourcebytes":[73,109,97,103,101,32,67,111,110,118,101,114,115,105,111,110],"value":"Image Conversion"}, +{"hash":137355731,"name":"tmainform.lbwebpsaveas.caption","sourcebytes":[83,97,118,101,32,87,101,98,80,32,97,115],"value":"Save WebP as"}, +{"hash":21799,"name":"tmainform.cbwebpsaveas.text","sourcebytes":[80,78,71],"value":"PNG"}, +{"hash":32654252,"name":"tmainform.lbpngcompressionlevel.caption","sourcebytes":[80,78,71,32,67,111,109,112,114,101,115,115,105,111,110,32,108,101,118,101,108],"value":"PNG Compression level"}, +{"hash":210414820,"name":"tmainform.cbpngcompressionlevel.text","sourcebytes":[70,97,115,116,101,115,116],"value":"Fastest"}, +{"hash":205834697,"name":"tmainform.lbjpegquality.caption","sourcebytes":[74,80,69,71,32,113,117,97,108,105,116,121],"value":"JPEG quality"}, +{"hash":252069175,"name":"tmainform.ckpngsaveasjpeg.caption","sourcebytes":[83,97,118,101,32,80,78,71,32,97,115,32,74,80,69,71],"value":"Save PNG as JPEG"}, {"hash":208308883,"name":"tmainform.tsupdate.caption","sourcebytes":[85,112,100,97,116,101,115],"value":"Updates"}, {"hash":72408384,"name":"tmainform.cboptionautochecklatestversion.caption","sourcebytes":[65,117,116,111,32,99,104,101,99,107,32,102,111,114,32,108,97,116,101,115,116,32,118,101,114,115,105,111,110,32],"value":"Auto check for latest version "}, {"hash":225003075,"name":"tmainform.gboptionfavorites.caption","sourcebytes":[70,97,118,111,114,105,116,101,115],"value":"Favorites"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e7cedbfcd..5d78a9d14 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -70,10 +70,11 @@ TMainForm = class(TForm) cbUseRegExpr: TCheckBox; cbOptionProxyType: TComboBox; cbOptionOneInstanceOnly: TCheckBox; + ckPNGSaveAsJPEG: TCheckBox; ckOptionsAlwaysStartTaskFromFailedChapters: TCheckBox; ckEnableLogging: TCheckBox; - cbWebPConvertTo: TComboBox; - cbWebPPNGCompressionLevel: TComboBox; + cbWebPSaveAs: TComboBox; + cbPNGCompressionLevel: TComboBox; edDownloadsSearch: TEditButton; edFavoritesSearch: TEditButton; edFilterMangaInfoChapters: TEditButton; @@ -86,11 +87,11 @@ TMainForm = class(TForm) edSaveTo: TEditButton; edURL: TEditButton; edWebsitesSearch: TEditButton; - gbWebP: TGroupBox; + gbImageConversion: TGroupBox; IconDLLeft: TImageList; - lbWebPPNGCompressionLevel: TLabel; - lbWebPJpegQuality: TLabel; - lbWebPConvertTo: TLabel; + lbPNGCompressionLevel: TLabel; + lbJPEGQuality: TLabel; + lbWebPSaveAs: TLabel; lbLogFileName: TLabel; lbOptionRetryFailedTask: TLabel; lbOptionFilenameCustomRenameHint: TLabel; @@ -152,7 +153,7 @@ TMainForm = class(TForm) sbWebsiteOptions: TScrollBox; btDownloadSplit: TSpeedButton; seOptionRetryFailedTask: TSpinEdit; - seWebPJpegQuality: TSpinEdit; + seJPEGQuality: TSpinEdit; tsWebsiteModules: TTabSheet; ToolBarDownloadLeft: TToolBar; tbmiDownloadMoveTop: TToolButton; @@ -870,7 +871,7 @@ TMangaInfoData = record RS_OptionFMDDoItems = 'Nothing'#13#10'Exit'#13#10'Shutdown'#13#10'Hibernate'; RS_DropTargetModeItems = 'Download all'#13#10'Add to favorites'; RS_OptionCompress = 'None'#13#10'ZIP'#13#10'CBZ'#13#10'PDF'; - RS_WebPConvertTo = 'WebP'#13#10'PNG'#13#10'Jpeg'; + RS_WebPConvertTo = 'WebP'#13#10'PNG'#13#10'JPEG'; RS_WebPPNGLevel = 'None'#13#10'Fastest'#13#10'Default'#13#10'Maximum'; RS_HintFavoriteProblem = 'There is a problem with this data!'#13#10 @@ -4960,9 +4961,9 @@ procedure TMainForm.LoadOptions; edOptionFilenameCustomRename.Text := ReadString('saveto', 'FilenameCustomRename', DEFAULT_FILENAME_CUSTOMRENAME); if Trim(edOptionFilenameCustomRename.Text) = '' then edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; - cbWebPConvertTo.ItemIndex := ReadInteger('saveto', 'ConvertWebP', OptionWebPConvertTo); - cbWebPPNGCompressionLevel.ItemIndex := ReadInteger('saveto', 'WebPPNGLevel', OptionWebPPNGLevel); - seWebPJpegQuality.Value := ReadInteger('saveto', 'WebPJpegQuality', OptionWebPJpegQuality); + cbWebPSaveAs.ItemIndex := ReadInteger('saveto', 'ConvertWebP', OptionWebPSaveAs); + cbPNGCompressionLevel.ItemIndex := ReadInteger('saveto', 'PNGCompressionLevel', OptionPNGCompressionLevel); + seJPEGQuality.Value := ReadInteger('saveto', 'JPEGQuality', OptionJPEGQuality); // update cbOptionAutoCheckLatestVersion.Checked := ReadBool('update', 'AutoCheckLatestVersion', True); @@ -5108,9 +5109,9 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); if Trim(edOptionFilenameCustomRename.Text) = '' then edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; WriteString('saveto', 'FilenameCustomRename', edOptionFilenameCustomRename.Text); - WriteInteger('saveto', 'ConvertWebP', cbWebPConvertTo.ItemIndex); - WriteInteger('saveto', 'WebPPNGLevel', cbWebPPNGCompressionLevel.ItemIndex); - WriteInteger('saveto', 'WebPJpegQuality', seWebPJpegQuality.Value); + WriteInteger('saveto', 'ConvertWebP', cbWebPSaveAs.ItemIndex); + WriteInteger('saveto', 'WebPPNGLevel', cbPNGCompressionLevel.ItemIndex); + WriteInteger('saveto', 'WebPJpegQuality', seJPEGQuality.Value); // update WriteBool('update', 'AutoCheckLatestVersion', cbOptionAutoCheckLatestVersion.Checked); @@ -5252,9 +5253,9 @@ procedure TMainForm.ApplyOptions; OptionConvertDigitVolumeLength := seOptionDigitVolume.Value; OptionConvertDigitChapter := cbOptionDigitChapter.Checked; OptionConvertDigitChapterLength := seOptionDigitChapter.Value; - OptionWebPConvertTo := cbWebPConvertTo.ItemIndex; - OptionWebPPNGLevel := cbWebPPNGCompressionLevel.ItemIndex; - OptionWebPJpegQuality := seWebPJpegQuality.Value; + OptionWebPSaveAs := cbWebPSaveAs.ItemIndex; + OptionPNGCompressionLevel := cbPNGCompressionLevel.ItemIndex; + OptionJPEGQuality := seJPEGQuality.Value; //update OptionAutoCheckLatestVersion := cbOptionAutoCheckLatestVersion.Checked; @@ -5771,8 +5772,8 @@ procedure TMainForm.ApplyLanguage; idxOptionProxyType := cbOptionProxyType.ItemIndex; idxDropTargetMode := rgDropTargetMode.ItemIndex; idxOptionCompress := rgOptionCompress.ItemIndex; - idxOptionWebPConvertTo := cbWebPConvertTo.ItemIndex; - idxOptionWebPPNGLevel := cbWebPPNGCompressionLevel.ItemIndex; + idxOptionWebPConvertTo := cbWebPSaveAs.ItemIndex; + idxOptionWebPPNGLevel := cbPNGCompressionLevel.ItemIndex; if SimpleTranslator.SetLangByIndex(cbLanguages.ItemIndex) then begin // assign new value @@ -5784,8 +5785,8 @@ procedure TMainForm.ApplyLanguage; cbOptionLetFMDDo.Items.Text := RS_OptionFMDDoItems; rgDropTargetMode.Items.Text := RS_DropTargetModeItems; rgOptionCompress.Items.Text := RS_OptionCompress; - cbWebPConvertTo.Items.Text := RS_WebPConvertTo; - cbWebPPNGCompressionLevel.Items.Text := RS_WebPPNGLevel; + cbWebPSaveAs.Items.Text := RS_WebPConvertTo; + cbPNGCompressionLevel.Items.Text := RS_WebPPNGLevel; // restore ItemIndex cbSelectManga.ItemIndex:=idxSelectManga; @@ -5795,8 +5796,8 @@ procedure TMainForm.ApplyLanguage; cbOptionProxyType.ItemIndex := idxOptionProxyType; rgDropTargetMode.ItemIndex := idxDropTargetMode; rgOptionCompress.ItemIndex := idxOptionCompress; - cbWebPConvertTo.ItemIndex := idxOptionWebPConvertTo; - cbWebPPNGCompressionLevel.ItemIndex := idxOptionWebPPNGLevel; + cbWebPSaveAs.ItemIndex := idxOptionWebPConvertTo; + cbPNGCompressionLevel.ItemIndex := idxOptionWebPPNGLevel; Self.Repaint; vtMangaList.Repaint; tvDownloadFilterRefresh(True); diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 4d212377f..20ee9d987 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -355,7 +355,7 @@ msgstr "Heute" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" #: frmmain.rs_webppnglevel @@ -831,6 +831,11 @@ msgstr "Remove duplicate local data when updating manga list" msgid "Use proxy" msgstr "Benutze proxy" +#: tmainform.cbpngcompressionlevel.text +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Suche in allen Manga-Seiten" @@ -843,14 +848,11 @@ msgstr "Für mehr Manga-Seiten, bitte geh in die Optionen->Manga-Seiten" msgid "Regular Expression" msgstr "Regular Expression" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1181,6 +1183,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Eingabe individueller Genres, durch Komma getrennt" @@ -1291,6 +1297,10 @@ msgstr "Zeige Dialogbestätigungen für" msgid "Drop Box" msgstr "Drop Box" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Externes Programm" @@ -1308,10 +1318,6 @@ msgstr "Proxy Einstellung" msgid "Renaming" msgstr "Umbenennung" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Wähle den Standarddownloadpfad:" @@ -1375,6 +1381,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Titel" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Protokolldatei:" @@ -1567,20 +1577,17 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Benutzername" +#: tmainform.lbpngcompressionlevel.caption +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Speichern unter:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" msgstr "" #: tmainform.medturldelete.caption diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 9f46cc0e8..c178b42c0 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -359,7 +359,7 @@ msgstr "Σήμερα" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" #: frmmain.rs_webppnglevel @@ -835,6 +835,11 @@ msgstr "Κατάργηση διπλότυπων τοπικών δεδομένω msgid "Use proxy" msgstr "Χρήση διακομιστή μεσολάβησης" +#: tmainform.cbpngcompressionlevel.text +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Αναζήτηση σε όλους τους ιστότοπους manga" @@ -847,14 +852,11 @@ msgstr "Για περισσότερους ιστότοπους manga, παρακ msgid "Regular Expression" msgstr "Κανονική έκφραση" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1236,6 +1238,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Εισαγωγή προσαρμοσμένων ειδών, χωρισμένα με κόμμα" @@ -1346,6 +1352,10 @@ msgstr "Εμφάνιση παραθύρου επιβεβαίωσης όταν γ msgid "Drop Box" msgstr "Κουτί φύλαξης" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Εξωτερικό πρόγραμμα" @@ -1363,10 +1373,6 @@ msgstr "Ρυθμίσεις διακομιστή μεσολάβησης" msgid "Renaming" msgstr "Μετονομασία" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Καθορίστε την προεπιλεγμένη διαδρομή λήψης:" @@ -1430,6 +1436,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Τίτλος" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Αρχείο καταγραφής:" @@ -1622,20 +1632,17 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Όνομα χρήστη" +#: tmainform.lbpngcompressionlevel.caption +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Αποθήκευση σε:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" msgstr "" #: tmainform.medturldelete.caption diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 1bc726581..db859a67c 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -342,10 +342,15 @@ msgid "Today" msgstr "Today" #: frmmain.rs_webpconvertto +#, fuzzy +#| msgid "" +#| "WebP\n" +#| "PNG\n" +#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" "WebP\n" "PNG\n" @@ -817,6 +822,12 @@ msgstr "Remove duplicate local data when updating manga list" msgid "Use proxy" msgstr "Use proxy" +#: tmainform.cbpngcompressionlevel.text +#, fuzzy +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "Fastest" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Search in all manga sites" @@ -829,14 +840,12 @@ msgstr "For more manga sites, please go to Options->Manga sites" msgid "Regular Expression" msgstr "Regular Expression" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +#, fuzzy +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "Fastest" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1167,6 +1176,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "Always start task from failed chapters" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Input custom genres, separated by comma" @@ -1273,6 +1286,10 @@ msgstr "Show dialog confirmation for" msgid "Drop Box" msgstr "Drop Box" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "External program" @@ -1290,10 +1307,6 @@ msgstr "Proxy config" msgid "Renaming" msgstr "Renaming" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "WebP" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Choose the default download path:" @@ -1357,6 +1370,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Title" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Log file:" @@ -1543,21 +1560,19 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Username" +#: tmainform.lbpngcompressionlevel.caption +#, fuzzy +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "PNG Compression level" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Save to:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "Save WebP to" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "Jpeg quality" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" -msgstr "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" +msgstr "" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index e344cc0cf..8f8614062 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -353,7 +353,7 @@ msgstr "Hoy" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" #: frmmain.rs_webppnglevel @@ -819,6 +819,11 @@ msgstr "Remover los Datos Locales Duplicados Cuando se Actualiza la Lista de Man msgid "Use proxy" msgstr "Usar Proxy" +#: tmainform.cbpngcompressionlevel.text +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Buscar en Todos Los Sitios de Manga" @@ -831,14 +836,11 @@ msgstr "Para más Sitios de Mangas, Ve a Opciones->Sitios Manga" msgid "Regular Expression" msgstr "Regular Expresión" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1169,6 +1171,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Ingresa géneros personalizados, separados por coma." @@ -1275,6 +1281,10 @@ msgstr "Mostrar Dialogo de Confirmación para" msgid "Drop Box" msgstr "Drop Box" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Programa Externo" @@ -1292,10 +1302,6 @@ msgstr "Configuración de Proxy" msgid "Renaming" msgstr "Renombrando" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Escoger la Ruta de Descarga por Defecto:" @@ -1359,6 +1365,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Título" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Archivo de Registro:" @@ -1545,20 +1555,17 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Usuario" +#: tmainform.lbpngcompressionlevel.caption +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Guardar en:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" msgstr "" #: tmainform.medturldelete.caption diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index ba6a2dcba..74416be04 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -342,10 +342,15 @@ msgid "Today" msgstr "Hari ini" #: frmmain.rs_webpconvertto +#, fuzzy +#| msgid "" +#| "WebP\n" +#| "PNG\n" +#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" "WebP\n" "PNG\n" @@ -817,6 +822,12 @@ msgstr "Menghapus duplikat data lokal saat memperbarui daftar komik" msgid "Use proxy" msgstr "Gunakan proxy" +#: tmainform.cbpngcompressionlevel.text +#, fuzzy +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "Paling cepat" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Cari di semua situs komik" @@ -829,14 +840,12 @@ msgstr "Untuk situs komik yang lain, silahkan pilih di Pengaturan->Situs komik" msgid "Regular Expression" msgstr "Regular Expression" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +#, fuzzy +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "Paling cepat" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1167,6 +1176,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "Selalu mulai undudah dari bab yang gagal" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Masukan genre pilihan, dipisahkan dengan koma" @@ -1273,6 +1286,10 @@ msgstr "Tampilkan dialog konfirmasi untuk" msgid "Drop Box" msgstr "Kotak unduh" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Program eksternal" @@ -1290,10 +1307,6 @@ msgstr "Konfigurasi proxy" msgid "Renaming" msgstr "Mengubah nama" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "WebP" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Pilih lokasi pengunduhan bawaan:" @@ -1357,6 +1370,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Judul" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Berkas log:" @@ -1543,21 +1560,19 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Nama user" +#: tmainform.lbpngcompressionlevel.caption +#, fuzzy +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "Level kompresi PNG" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Lokasi penyimpanan:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "Simpan WebP ke" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "Kualitas Jpeg" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" -msgstr "Level kompresi PNG" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" +msgstr "" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 436130833..be44b7a11 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -355,7 +355,7 @@ msgstr "Dzisiaj" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" #: frmmain.rs_webppnglevel @@ -831,6 +831,11 @@ msgstr "Usuwanie zduplikowane lokalne dane podczas aktualizacji listy mang" msgid "Use proxy" msgstr "Użyj proxy" +#: tmainform.cbpngcompressionlevel.text +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Szukaj we wszystkich witrynach " @@ -843,14 +848,11 @@ msgstr "Aby uzyskać więcej stron z mangami, przejdź do Opcje->Strony z mangam msgid "Regular Expression" msgstr "Wyrażenie regularne" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1181,6 +1183,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Lista gatunków oddzielone przecinkami" @@ -1291,6 +1297,10 @@ msgstr "Pokaż potwierdzenie dialogowe" msgid "Drop Box" msgstr "Pole rozwijane" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Program zewnętrzny" @@ -1308,10 +1318,6 @@ msgstr "Konfiguracja Proxy" msgid "Renaming" msgstr "Zmiana nazwy …" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Wybierz domyślną ścieżkę pobierania:" @@ -1375,6 +1381,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Tytuł" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Plik logów:" @@ -1568,20 +1578,17 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Nazwa użytkownika" +#: tmainform.lbpngcompressionlevel.caption +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Zapisz do:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" msgstr "" #: tmainform.medturldelete.caption diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 8aae3a65c..860057312 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -317,7 +317,7 @@ msgstr "" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" #: frmmain.rs_webppnglevel @@ -782,6 +782,11 @@ msgstr "" msgid "Use proxy" msgstr "" +#: tmainform.cbpngcompressionlevel.text +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "" @@ -794,14 +799,11 @@ msgstr "" msgid "Regular Expression" msgstr "" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1130,6 +1132,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "" @@ -1236,6 +1242,10 @@ msgstr "" msgid "Drop Box" msgstr "" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "" @@ -1253,10 +1263,6 @@ msgstr "" msgid "Renaming" msgstr "" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "" @@ -1311,6 +1317,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "" @@ -1474,20 +1484,17 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "" -#: tmainform.lbsaveto.caption -msgid "Save to:" -msgstr "" - -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" +#: tmainform.lbpngcompressionlevel.caption +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" msgstr "" -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" +#: tmainform.lbsaveto.caption +msgid "Save to:" msgstr "" -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" msgstr "" #: tmainform.medturldelete.caption diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 5e8df4825..412ab1185 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -355,7 +355,7 @@ msgstr "Hoje" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" #: frmmain.rs_webppnglevel @@ -830,6 +830,11 @@ msgstr "Remover dados locais duplicados quando atualizando lista de mangás" msgid "Use proxy" msgstr "Usar proxy" +#: tmainform.cbpngcompressionlevel.text +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Buscar em todos sites de mangá" @@ -842,14 +847,11 @@ msgstr "Para mais sites de mangá, por favor vá em Opções->Sites de Mangá" msgid "Regular Expression" msgstr "Expressão Regular" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1181,6 +1183,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "Sempre iniciar tarefa dos capítulos que falharam" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Entrar gêneros personalizados, separados por vírgula" @@ -1291,6 +1297,10 @@ msgstr "Mostrar diálogo de confirmação para" msgid "Drop Box" msgstr "Caixa de Seleção" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Programa externo" @@ -1308,10 +1318,6 @@ msgstr "Config. do Proxy" msgid "Renaming" msgstr "Renomeando" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Escolha o caminho de download padrão:" @@ -1375,6 +1381,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Título" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Arquivo de registro:" @@ -1565,20 +1575,17 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Nome de usuário" +#: tmainform.lbpngcompressionlevel.caption +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Salvar em:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" msgstr "" #: tmainform.medturldelete.caption diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index b3309a902..e2ea6a0e7 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -352,10 +352,15 @@ msgid "Today" msgstr "Cегодня" #: frmmain.rs_webpconvertto +#, fuzzy +#| msgid "" +#| "WebP\n" +#| "PNG\n" +#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" "WebP\n" "PNG\n" @@ -827,6 +832,12 @@ msgstr "Удалять повторяющиеся локальные данны msgid "Use proxy" msgstr "Использовать прокси" +#: tmainform.cbpngcompressionlevel.text +#, fuzzy +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "Скоростной" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Поиск по всем сайтам манги" @@ -839,14 +850,12 @@ msgstr "Для получения дополнительных сайтов с msgid "Regular Expression" msgstr "Регулярное выражение (regexp)" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +#, fuzzy +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "Скоростной" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1177,6 +1186,10 @@ msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "Всегда запускать задачу с неудавшихся частей" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Ввод пользовательских жанров, разделенных запятой" @@ -1283,6 +1296,10 @@ msgstr "Показать диалог подтверждения когда" msgid "Drop Box" msgstr "Дропбокс" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Внешняя программа" @@ -1300,10 +1317,6 @@ msgstr "Конфигурация прокси-сервера" msgid "Renaming" msgstr "Переименовать" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "WebP" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Выберите путь загрузки по умолчанию:" @@ -1367,6 +1380,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Название" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Файл лога:" @@ -1553,21 +1570,19 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Имя пользователя" +#: tmainform.lbpngcompressionlevel.caption +#, fuzzy +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "Уровень компрессии PNG" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Сохранить в:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "Сохранить WebP как" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "Качество Jpeg" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" -msgstr "Уровень компрессии PNG" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" +msgstr "" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 61f11eb33..faa9a5687 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -356,10 +356,15 @@ msgid "Today" msgstr "Bugün" #: frmmain.rs_webpconvertto +#, fuzzy +#| msgid "" +#| "WebP\n" +#| "PNG\n" +#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" msgstr "" "WebP\n" "PNG\n" @@ -841,6 +846,12 @@ msgstr "Manga listesini güncellerken çift yerel veriyi kaldır" msgid "Use proxy" msgstr "Proxy kullan" +#: tmainform.cbpngcompressionlevel.text +#, fuzzy +msgctxt "tmainform.cbpngcompressionlevel.text" +msgid "Fastest" +msgstr "En hızlı" + #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" msgstr "Tüm manga sitelerinde ara" @@ -853,14 +864,12 @@ msgstr "Daha fazla manga sitesi için, lütfen Ayarlar->Manga siteleri'ne gidin" msgid "Regular Expression" msgstr "Düzenli İfadeler" -#: tmainform.cbwebpconvertto.text +#: tmainform.cbwebpsaveas.text +#, fuzzy +msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" -#: tmainform.cbwebppngcompressionlevel.text -msgid "Fastest" -msgstr "En hızlı" - #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" msgid "Show Drop Box" @@ -1190,6 +1199,10 @@ msgstr "Bu çalışmalar genellikle kadınlar arası yakın ilişki barındırı msgid "Always start task from failed chapters" msgstr "Görevi her zaman başarısız bölümlerden başlat" +#: tmainform.ckpngsaveasjpeg.caption +msgid "Save PNG as JPEG" +msgstr "" + #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Kişisel tür ekle, virgülle ayırarak" @@ -1300,6 +1313,10 @@ msgstr "Şunun için doğrulama diyaloğu göster" msgid "Drop Box" msgstr "İndirme kutusu" +#: tmainform.gbimageconversion.caption +msgid "Image Conversion" +msgstr "" + #: tmainform.gboptionexternal.caption msgid "External program" msgstr "Harici program" @@ -1317,10 +1334,6 @@ msgstr "Vekil ayarları" msgid "Renaming" msgstr "Yeniden adlandırma" -#: tmainform.gbwebp.caption -msgid "WebP" -msgstr "WebP" - #: tmainform.lbdefaultdownloadpath.caption msgid "Choose the default download path:" msgstr "Varsayılan indirme yolunu seç:" @@ -1384,6 +1397,10 @@ msgctxt "tmainform.lbfiltertitle.caption" msgid "Title" msgstr "Başlık" +#: tmainform.lbjpegquality.caption +msgid "JPEG quality" +msgstr "" + #: tmainform.lblogfilename.caption msgid "Log file:" msgstr "Günlük dosyası:" @@ -1572,21 +1589,19 @@ msgctxt "tmainform.lboptionuser.caption" msgid "Username" msgstr "Kullanıcı adı" +#: tmainform.lbpngcompressionlevel.caption +#, fuzzy +msgctxt "tmainform.lbpngcompressionlevel.caption" +msgid "PNG Compression level" +msgstr "PNG Sıkıştırma seviyesi" + #: tmainform.lbsaveto.caption msgid "Save to:" msgstr "Şuraya kaydet:" -#: tmainform.lbwebpconvertto.caption -msgid "Save WebP to" -msgstr "WebP'yi şöyle kaydet" - -#: tmainform.lbwebpjpegquality.caption -msgid "Jpeg quality" -msgstr "JPEG kalitesi" - -#: tmainform.lbwebppngcompressionlevel.caption -msgid "PNG Compression level" -msgstr "PNG Sıkıştırma seviyesi" +#: tmainform.lbwebpsaveas.caption +msgid "Save WebP as" +msgstr "" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From ea86f86cc9df2d856b73d22c76e3d71a39ea36c8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 10:31:37 +0800 Subject: [PATCH 2197/2794] update english localization --- mangadownloader/languages/fmd.en.po | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index db859a67c..d2ebefdd4 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -342,11 +342,6 @@ msgid "Today" msgstr "Today" #: frmmain.rs_webpconvertto -#, fuzzy -#| msgid "" -#| "WebP\n" -#| "PNG\n" -#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" @@ -354,7 +349,7 @@ msgid "" msgstr "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -735,7 +730,7 @@ msgstr "Enable this if you have problem with unicode character in path." #: tmainform.cboptiondeletecompletedtasksonclose.caption msgid "Delete completed tasks on close" -msgstr "" +msgstr "Delete completed tasks on close" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -823,7 +818,6 @@ msgid "Use proxy" msgstr "Use proxy" #: tmainform.cbpngcompressionlevel.text -#, fuzzy msgctxt "tmainform.cbpngcompressionlevel.text" msgid "Fastest" msgstr "Fastest" @@ -841,7 +835,6 @@ msgid "Regular Expression" msgstr "Regular Expression" #: tmainform.cbwebpsaveas.text -#, fuzzy msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" @@ -1178,7 +1171,7 @@ msgstr "Always start task from failed chapters" #: tmainform.ckpngsaveasjpeg.caption msgid "Save PNG as JPEG" -msgstr "" +msgstr "Save PNG as JPEG" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1288,7 +1281,7 @@ msgstr "Drop Box" #: tmainform.gbimageconversion.caption msgid "Image Conversion" -msgstr "" +msgstr "Image Conversion" #: tmainform.gboptionexternal.caption msgid "External program" @@ -1372,7 +1365,7 @@ msgstr "Title" #: tmainform.lbjpegquality.caption msgid "JPEG quality" -msgstr "" +msgstr "JPEG quality" #: tmainform.lblogfilename.caption msgid "Log file:" @@ -1561,7 +1554,6 @@ msgid "Username" msgstr "Username" #: tmainform.lbpngcompressionlevel.caption -#, fuzzy msgctxt "tmainform.lbpngcompressionlevel.caption" msgid "PNG Compression level" msgstr "PNG Compression level" @@ -1572,7 +1564,7 @@ msgstr "Save to:" #: tmainform.lbwebpsaveas.caption msgid "Save WebP as" -msgstr "" +msgstr "Save WebP as" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From 559e7ec2983c5b6b9550f26467dfe4bb3e6f97fc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 10:33:49 +0800 Subject: [PATCH 2198/2794] update Indonesian localization --- mangadownloader/languages/fmd.id_ID.po | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 74416be04..51db88199 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -342,11 +342,6 @@ msgid "Today" msgstr "Hari ini" #: frmmain.rs_webpconvertto -#, fuzzy -#| msgid "" -#| "WebP\n" -#| "PNG\n" -#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" @@ -354,7 +349,7 @@ msgid "" msgstr "" "WebP\n" "PNG\n" -"Jpeg\n" +"PNG\n" #: frmmain.rs_webppnglevel msgid "" @@ -735,7 +730,7 @@ msgstr "Aktifkan pilihan ini jika anda mengalami masalah dengan karakter unicode #: tmainform.cboptiondeletecompletedtasksonclose.caption msgid "Delete completed tasks on close" -msgstr "" +msgstr "Hapus unduhan yang selesai saat ditutup" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -823,7 +818,6 @@ msgid "Use proxy" msgstr "Gunakan proxy" #: tmainform.cbpngcompressionlevel.text -#, fuzzy msgctxt "tmainform.cbpngcompressionlevel.text" msgid "Fastest" msgstr "Paling cepat" @@ -841,7 +835,6 @@ msgid "Regular Expression" msgstr "Regular Expression" #: tmainform.cbwebpsaveas.text -#, fuzzy msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" @@ -1178,7 +1171,7 @@ msgstr "Selalu mulai undudah dari bab yang gagal" #: tmainform.ckpngsaveasjpeg.caption msgid "Save PNG as JPEG" -msgstr "" +msgstr "Simpan PNG sebagai JPEG" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1288,7 +1281,7 @@ msgstr "Kotak unduh" #: tmainform.gbimageconversion.caption msgid "Image Conversion" -msgstr "" +msgstr "Konversi gambar" #: tmainform.gboptionexternal.caption msgid "External program" @@ -1372,7 +1365,7 @@ msgstr "Judul" #: tmainform.lbjpegquality.caption msgid "JPEG quality" -msgstr "" +msgstr "Kualitas JPEG" #: tmainform.lblogfilename.caption msgid "Log file:" @@ -1561,7 +1554,6 @@ msgid "Username" msgstr "Nama user" #: tmainform.lbpngcompressionlevel.caption -#, fuzzy msgctxt "tmainform.lbpngcompressionlevel.caption" msgid "PNG Compression level" msgstr "Level kompresi PNG" @@ -1572,7 +1564,7 @@ msgstr "Lokasi penyimpanan:" #: tmainform.lbwebpsaveas.caption msgid "Save WebP as" -msgstr "" +msgstr "Simpan WebP sebagai" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From 00e1d5d5e426012c0168d3a2cd6453b6c542370a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 11:10:16 +0800 Subject: [PATCH 2199/2794] fix startup and some cleanup --- mangadownloader/forms/frmMain.lfm | 1 - mangadownloader/forms/frmMain.pas | 96 +++++++++++++------------------ 2 files changed, 41 insertions(+), 56 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 2d71bd59b..89f813cdd 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -12,7 +12,6 @@ object MainForm: TMainForm OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy - OnShow = FormShow OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5d78a9d14..3a6992e09 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -481,7 +481,6 @@ TMainForm = class(TForm) procedure cbOptionUseProxyChange(Sender: TObject); procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender: TObject); procedure FormWindowStateChange(Sender: TObject); procedure miChapterListAscendingClick(Sender: TObject); procedure miFavoritesEnableClick(Sender: TObject); @@ -933,11 +932,7 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8, - webp - {$ifdef USE_LUA_MODULE} - ,LuaWebsiteModules - {$endif} - ; + webp, LuaWebsiteModules; var // thread for open db @@ -1310,16 +1305,16 @@ procedure TMainForm.FormCreate(Sender: TObject); TransferRateGraphList.DataPoints.NameValueSeparator := '|'; TransferRateGraph.Visible := False; - // load configfile - isStartup := False; - CollectLanguagesFromFiles; - LoadMangaOptions; - LoadOptions; - ApplyOptions; - // minimize on start - if cbOptionMinimizeOnStart.Checked then - Application.ShowMainForm := False; + Application.ShowMainForm := False; + + isStartup := False; + with TTimer.Create(nil) do + begin + OnTimer := @tmStartupTimer; + Interval := 16; + Enabled := True; + end; end; procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); @@ -1469,20 +1464,6 @@ procedure TMainForm.FormDestroy(Sender: TObject); DoRestartFMD; end; -procedure TMainForm.FormShow(Sender: TObject); -begin - if not isStartup then - begin - LoadFormInformation; - with TTimer.Create(nil) do - begin - OnTimer := @tmStartupTimer; - Interval := 32; - Enabled := True; - end; - end; -end; - procedure TMainForm.cbOptionUseProxyChange(Sender: TObject); begin gbOptionProxy.Enabled := cbOptionUseProxy.Checked; @@ -1825,38 +1806,43 @@ procedure TMainForm.tmRefreshDownloadsInfoTimer(Sender: TObject); procedure TMainForm.tmStartupTimer(Sender: TObject); begin - if not isStartup then - begin - isStartup := True; + isStartup := True; - {$ifdef USE_LUA_MODULE} - //load lua modules - ScanLuaWebsiteModulesFile; - {$endif} + //load lua modules + ScanLuaWebsiteModulesFile; + AddToAboutStatus('Modules', IntToStr(Modules.Count)); - AddToAboutStatus('Modules', IntToStr(Modules.Count)); + // load configfile + LoadFormInformation; + CollectLanguagesFromFiles; + LoadMangaOptions; + LoadOptions; + ApplyOptions; - //restore everything after all modules loaded - DLManager.Restore; - UpdateVtDownload; + if not cbOptionMinimizeOnStart.Checked then + Self.Show; - FavoriteManager.Restore; - UpdateVtFavorites; + //restore everything after all modules loaded + DLManager.Restore; + UpdateVtDownload; - if cbSelectManga.ItemIndex > -1 then - OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); - if OptionAutoCheckLatestVersion then - begin - btCheckLatestVersionClick(btCheckLatestVersion); - LuaModulesUpdaterForm.btCheckUpdateClick(LuaModulesUpdaterForm.btCheckUpdate); - end; - if OptionAutoCheckFavStartup then - begin - FavoriteManager.isAuto := True; - FavoriteManager.CheckForNewChapter; - end; - DLManager.CheckAndActiveTaskAtStartup; + FavoriteManager.Restore; + UpdateVtFavorites; + + if cbSelectManga.ItemIndex > -1 then + OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); + if OptionAutoCheckLatestVersion then + begin + btCheckLatestVersionClick(btCheckLatestVersion); + LuaModulesUpdaterForm.btCheckUpdateClick(LuaModulesUpdaterForm.btCheckUpdate); end; + if OptionAutoCheckFavStartup then + begin + FavoriteManager.isAuto := True; + FavoriteManager.CheckForNewChapter; + end; + DLManager.CheckAndActiveTaskAtStartup; + if Sender is TTimer then TTimer(Sender).Free; end; From 4301f63f6121a8611896b7131e0a7675fd32cb52 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 11:22:27 +0800 Subject: [PATCH 2200/2794] websitemodules, add category this should be populated to websites selections --- baseunits/WebsiteModules.pas | 1 + baseunits/lua/LuaWebsiteModules.pas | 1 + mangadownloader/md.lpi | 15 +++++++-------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index c5fa5b39f..8b0e4e174 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -85,6 +85,7 @@ TModuleContainer = class TagPtr: Pointer; Website: String; RootURL: String; + Category: String; MaxTaskLimit: Integer; MaxConnectionLimit: Integer; ActiveTaskCount: Integer; diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 15caadc03..9baf04677 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -585,6 +585,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; begin luaClassAddStringProperty(L, MetaTable, 'Website', @Module.Website); luaClassAddStringProperty(L, MetaTable, 'RootURL', @Module.RootURL); + luaClassAddStringProperty(L, MetaTable, 'Category', @Module.Category); luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.MaxTaskLimit); luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', @Module.MaxConnectionLimit); diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b48005712..868f5c5d3 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -246,18 +246,17 @@ </Other> </CompilerOptions> </Item6> - <SharedMatrixOptions Count="11"> + <SharedMatrixOptions Count="10"> <Item1 ID="285210846225" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-Fu..\baseunits -Fu..\baseunits\animatedgifs -Fu..\baseunits\SimpleException -Fu..\baseunits\modules -Fu..\baseunits\extras -Fuforms"/> <Item2 ID="787838556410" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-Fi..\baseunits\includes\AnimeA -Fi..\baseunits\includes\AnimeStory -Fi..\baseunits\includes\AnimExtremist -Fi..\baseunits\includes\CentralDeMangas -Fi..\baseunits\includes\EGScans -Fi..\baseunits\includes\EsMangaHere -Fi..\baseunits\includes\Kivmanga -Fi..\baseunits\includes\LectureEnLigne -Fi..\baseunits\includes\MangaAr -Fi..\baseunits\includes\S2scans -Fi..\baseunits\includes\ScanManga -Fi..\baseunits\includes\Starkana -Fi..\baseunits\includes\Turkcraft -Fi..\baseunits\includes\VnSharing -Fi..\baseunits\includes\MeinManga -Fi..\baseunits\includes\MangaREADER_POR -Fi..\baseunits\includes\MangasPROJECT"/> <Item3 ID="465017374973" Targets="#project" Modes="Win32,Win64 Debug Leaks,Win32 Debug Leaks,Win64 Debug,Win32 Debug,Win64" Value="-dMANGADOWNLOADER -dDOWNLOADER -dSELFUPDATE -dMULTILOG"/> <Item4 ID="729045573668" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win32,Win64,Win32 Debug,Win64 Debug" Value="-Fu..\baseunits\lua -Fu..\baseunits\pcre"/> - <Item5 ID="200657967120" Targets="#project" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win64,Win32" Value="-dUSE_LUA_MODULE"/> - <Item6 ID="534084266787" Targets="#project" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -dDEVBUILD -WC"/> - <Item7 ID="951904047630" Targets="#project" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> - <Item8 ID="140379931701" Targets="#project" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> - <Item9 ID="403646715137" Targets="BESENPkg,internettools" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-CX -O3 -Xs -XX -g- -Os"/> - <Item10 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> - <Item11 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -Os"/> + <Item5 ID="534084266787" Targets="#project" Modes="Win64 Debug Leaks,Win32 Debug Leaks" Value="-dDEBUGLEAKS -dDEVBUILD -WC"/> + <Item6 ID="951904047630" Targets="#project" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item7 ID="140379931701" Targets="#project" Value="-Fi..\3rd\BESEN\src -Fi..\3rd\internettools\data -Fu..\3rd\BESEN\src -Fu..\3rd\internettools\data -Fu..\3rd\internettools\internet -Fu..\3rd\internettools\system -Fu..\3rd\internettools\import\flre\src"/> + <Item8 ID="403646715137" Targets="BESENPkg,internettools" Modes="Win32 Debug Leaks,Win64 Debug Leaks,Win64 Debug,Win32 Debug,Win32,Win64" Value="-CX -O3 -Xs -XX -g- -Os"/> + <Item9 ID="127282585717" Targets="internettools" Modes="Win32,Win64,Win32 Debug,Win64 Debug,Win64 Debug Leaks,Win32 Debug Leaks" Value="-uUSE_FLRE_WITH_CACHE -dUSE_SOROKINS_REGEX -uUSE_BBFLRE_UNICODE -dUSE_BBFULL_UNICODE"/> + <Item10 ID="939088584661" Targets="LazControls,TAChartLazarusPkg" Modes="Win64 Debug,Win32 Debug,Win64,Win32,Win32 Debug Leaks,Win64 Debug Leaks" Value="-CX -O3 -Xs -XX -g- -Os"/> </SharedMatrixOptions> </BuildModes> <PublishOptions> From e1c46f307848bde8c56a1eafe5c1314eaf97c0dc Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 07:48:35 +0300 Subject: [PATCH 2201/2794] update Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index e2ea6a0e7..933f72357 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -352,11 +352,6 @@ msgid "Today" msgstr "Cегодня" #: frmmain.rs_webpconvertto -#, fuzzy -#| msgid "" -#| "WebP\n" -#| "PNG\n" -#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" @@ -364,7 +359,7 @@ msgid "" msgstr "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -745,7 +740,7 @@ msgstr "Включите, если возникли проблемы с Unicode- #: tmainform.cboptiondeletecompletedtasksonclose.caption msgid "Delete completed tasks on close" -msgstr "" +msgstr "Удалить завершенные загрузки при выходе" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -833,7 +828,6 @@ msgid "Use proxy" msgstr "Использовать прокси" #: tmainform.cbpngcompressionlevel.text -#, fuzzy msgctxt "tmainform.cbpngcompressionlevel.text" msgid "Fastest" msgstr "Скоростной" @@ -851,7 +845,6 @@ msgid "Regular Expression" msgstr "Регулярное выражение (regexp)" #: tmainform.cbwebpsaveas.text -#, fuzzy msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" @@ -1188,7 +1181,7 @@ msgstr "Всегда запускать задачу с неудавшихся #: tmainform.ckpngsaveasjpeg.caption msgid "Save PNG as JPEG" -msgstr "" +msgstr "Сохранять PNG как JPEG" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1298,7 +1291,7 @@ msgstr "Дропбокс" #: tmainform.gbimageconversion.caption msgid "Image Conversion" -msgstr "" +msgstr "Конвертация изображений" #: tmainform.gboptionexternal.caption msgid "External program" @@ -1382,7 +1375,7 @@ msgstr "Название" #: tmainform.lbjpegquality.caption msgid "JPEG quality" -msgstr "" +msgstr "Качество JPEG" #: tmainform.lblogfilename.caption msgid "Log file:" @@ -1571,7 +1564,6 @@ msgid "Username" msgstr "Имя пользователя" #: tmainform.lbpngcompressionlevel.caption -#, fuzzy msgctxt "tmainform.lbpngcompressionlevel.caption" msgid "PNG Compression level" msgstr "Уровень компрессии PNG" @@ -1582,7 +1574,7 @@ msgstr "Сохранить в:" #: tmainform.lbwebpsaveas.caption msgid "Save WebP as" -msgstr "" +msgstr "Сохранять WebP как" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From 4af0a0697ce3e4600ed38ea60c74df7c2d86f9dd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 14:11:09 +0800 Subject: [PATCH 2202/2794] rewrite websites selection methods, also populate category from websitemodule --- baseunits/FMDOptions.pas | 53 +-- mangadownloader/forms/frmMain.lfm | 3 - mangadownloader/forms/frmMain.pas | 316 +++++++----------- .../forms/frmWebsiteOptionAdvanced.lfm | 109 +----- .../forms/frmWebsiteOptionAdvanced.pas | 6 +- 5 files changed, 137 insertions(+), 350 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 4d47e3560..dc42273f5 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -34,7 +34,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) EXPARAM_CHAPTER = '%CHAPTER%'; DEFAULT_EXPARAM = '"' + EXPARAM_PATH + EXPARAM_CHAPTER + '"'; - DEFAULT_LIST = 'MangaFox,MangaHere,MangaInn,MangaReader'; DEFAULT_MANGA_CUSTOMRENAME = '%MANGA%'; DEFAULT_CHAPTER_CUSTOMRENAME = '%CHAPTER%'; DEFAULT_FILENAME_CUSTOMRENAME = '%FILENAME%'; @@ -92,21 +91,21 @@ TIniFileRun = class(IniFiles.TMemIniFile) MANGAFOXTEMPLATE_FOLDER, LUA_WEBSITEMODULE_FOLDER, LUA_WEBSITEMODULE_REPOS: String; + DEFAULT_SELECTED_WEBSITES: String = 'MangaFox,MangaHere,MangaInn,MangaReader'; // ini files revisionfile, - updatesfile, - mangalistfile: TIniFile; + updatesfile: TIniFile; configfile, advancedfile: TIniFileRun; // db data download url - DBDownloadURL: String; + DBDownloadURL: String = 'https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download'; currentWebsite: String; // available website - AvailableWebsite: TStringList; + AvailableWebsites: TStringList; // general OptionLetFMDDo: TFMDDo = DO_NOTHING; @@ -244,51 +243,13 @@ procedure FreeNil(var Obj); procedure FreeIniFiles; begin - FreeNil(mangalistfile); FreeNil(configfile); FreeNil(advancedfile); end; -procedure GetAvailableWebsite; -var - l, w: TStringList; - i, j: Integer; -begin - AvailableWebsite.Clear; - AvailableWebsite.BeginUpdate; - try - l := TStringList.Create; - try - mangalistfile.ReadSection('available', l); - if l.Count > 0 then - begin - w := TStringList.Create; - try - for i := 0 to l.Count - 1 do - begin - w.Clear; - w.CommaText := mangalistfile.ReadString('available', l[i], ''); - if w.Count > 0 then - for j := 0 to w.Count - 1 do - AvailableWebsite.Values[w[j]] := l[i]; - end; - finally - w.Free; - end; - end; - finally - l.Free; - end; - finally - AvailableWebsite.EndUpdate; - end; -end; - procedure SetIniFiles; begin FreeIniFiles; - mangalistfile := TIniFile.Create(MANGALIST_FILE); - GetAvailableWebsite; configfile := TIniFileRun.Create(CONFIG_FILE); advancedfile := TIniFileRun.Create(CONFIG_ADVANCED); end; @@ -404,8 +365,8 @@ function GetCurrentBinVersion: String; procedure doInitialization; begin FMD_VERSION_NUMBER := GetCurrentBinVersion; - AvailableWebsite := TStringList.Create; - AvailableWebsite.Sorted := True; + AvailableWebsites := TStringList.Create; + AvailableWebsites.Sorted := False; SetFMDdirectory(ExtractFilePath(Application.ExeName)); SetAppDataDirectory(FMD_DIRECTORY); end; @@ -413,7 +374,7 @@ procedure doInitialization; procedure doFinalization; begin FreeIniFiles; - AvailableWebsite.Free; + AvailableWebsites.Free; end; initialization diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 89f813cdd..273283b34 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4222,12 +4222,9 @@ object MainForm: TMainForm TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] - OnChange = vtOptionMangaSiteSelectionChange - OnFocusChanged = vtOptionMangaSiteSelectionFocusChanged OnFreeNode = vtOptionMangaSiteSelectionFreeNode OnGetText = vtOptionMangaSiteSelectionGetText OnGetNodeDataSize = vtOptionMangaSiteSelectionGetNodeDataSize - OnInitNode = vtOptionMangaSiteSelectionInitNode end object pnlWebsitesTool: TPanel Left = 2 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 3a6992e09..8bc8f9a8b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -651,10 +651,6 @@ TMainForm = class(TForm) procedure tmBackupTimer(Sender: TObject); procedure vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; - Node : PVirtualNode); - procedure vtOptionMangaSiteSelectionFocusChanged(Sender : TBaseVirtualTree; - Node : PVirtualNode; Column : TColumnIndex); procedure vtOptionMangaSiteSelectionFreeNode(Sender : TBaseVirtualTree; Node : PVirtualNode); procedure vtOptionMangaSiteSelectionGetNodeDataSize(Sender: TBaseVirtualTree; @@ -662,8 +658,6 @@ TMainForm = class(TForm) procedure vtOptionMangaSiteSelectionGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure vtOptionMangaSiteSelectionInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); procedure DisableAddToFavorites(webs: String); private PrevWindowState: TWindowState; @@ -672,7 +666,6 @@ TMainForm = class(TForm) procedure FMDInstanceReceiveMsg(Sender: TObject); procedure ClearChapterListState; public - optionMangaSiteSelectionNodes: array of PVirtualNode; LastSearchStr: String; LastSearchWeb: String; LastUserPickedSaveTo: String; @@ -731,8 +724,6 @@ TMainForm = class(TForm) // Load config from mangalist.ini procedure LoadMangaOptions; - function SaveMangaOptions: String; - procedure UpdateVtChapter; procedure UpdateVtDownload; inline; procedure UpdateVtFavorites; @@ -1443,7 +1434,6 @@ procedure TMainForm.FormDestroy(Sender: TObject); RemoveVT(vtFavorites); RemoveVT(vtOptionMangaSiteSelection); - SetLength(optionMangaSiteSelectionNodes, 0); SetLength(ChapterList, 0); FreeAndNil(mangaInfo); @@ -2810,7 +2800,6 @@ procedure TMainForm.edWebsitesSearchChange(Sender: TObject); data: PSingleItem; xNode, lNode: PVirtualNode; begin - if Length(optionMangaSiteSelectionNodes) < 1 then Exit; s := Trim(LowerCase(edWebsitesSearch.Text)); vtOptionMangaSiteSelection.BeginUpdate; try @@ -4868,11 +4857,6 @@ procedure TMainForm.RunGetList; end; procedure TMainForm.LoadOptions; -var - l: TStringList; - i, j: Integer; - s: String; - data: PSingleItem; begin with configfile do begin // general @@ -4981,56 +4965,22 @@ procedure TMainForm.LoadOptions; edLogFileName.Text := ReadString('logger', 'LogFileName', ''); if edLogFileName.Text = '' then edLogFileName.Text := DEFAULT_LOG_FILE; - - // websites - if Length(optionMangaSiteSelectionNodes) > 0 then - for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do - optionMangaSiteSelectionNodes[i]^.CheckState := csUncheckedNormal; - l := TStringList.Create; - try - s := ReadString('general', 'MangaListSelect', - mangalistfile.ReadString('general', 'DefaultSelect', DEFAULT_LIST)); - if Pos(SEPERATOR, s) > 0 then - GetParams(l, s) //for old config - else - ExtractStrings([','], [], PChar(s), l); - if (l.Count > 0) and (Length(optionMangaSiteSelectionNodes) > 0) then - for i := 0 to l.Count - 1 do - for j := 0 to Length(optionMangaSiteSelectionNodes) - 1 do - begin - data := vtOptionMangaSiteSelection.GetNodeData( - optionMangaSiteSelectionNodes[j]); - if SameText(l[i], data^.Text) then - begin - optionMangaSiteSelectionNodes[j]^.CheckState := csCheckedNormal; - Break; - end; - end; - finally - l.Free; - end; end; end; procedure TMainForm.SaveOptions(const AShowDialog: Boolean); -var - s: String; begin - if Length(optionMangaSiteSelectionNodes) > 0 then + if (cbSelectManga.Items.Count = 0) and AShowDialog then begin - s := SaveMangaOptions; - if (s = '') and AShowDialog then - begin - MessageDlg('', RS_DlgMangaListSelect, - mtConfirmation, [mbYes], 0); - Exit; - end; + MessageDlg('', RS_DlgMangaListSelect, + mtConfirmation, [mbYes], 0); + Exit; end; with configfile do try // general - WriteString('general', 'MangaListSelect', s); + WriteString('general', 'MangaListSelect', cbSelectManga.Items.CommaText); WriteBool('general', 'LiveSearch', cbOptionLiveSearch.Checked); WriteBool('general', 'OneInstanceOnly', cbOptionOneInstanceOnly.Checked); if cbLanguages.ItemIndex > -1 then @@ -5136,19 +5086,21 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); procedure TMainForm.ApplyOptions; var i: Integer; - isStillHaveCurrentWebsite: Boolean = False; - data: PSingleItem; + isStillHaveCurrentWebsite: Boolean; + node: PVirtualNode; begin try // general + // selected websites cbSelectManga.Clear; - for i := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + node := vtOptionMangaSiteSelection.GetFirstChecked(); + while node<>nil do begin - data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); - if (optionMangaSiteSelectionNodes[i]^.CheckState = csCheckedNormal) and - (Data^.Text <> '') then - cbSelectManga.Items.Add(data^.Text); + cbSelectManga.Items.Add(PSingleItem(vtOptionMangaSiteSelection.GetNodeData(node))^.Text); + node := vtOptionMangaSiteSelection.GetNextChecked(node); end; + + isStillHaveCurrentWebsite := False; for i := 0 to cbSelectManga.Items.Count - 1 do begin if cbSelectManga.Items[i] = currentWebsite then @@ -5301,124 +5253,139 @@ procedure TMainForm.ApplyOptions; procedure TMainForm.LoadMangaOptions; var - isDeleteUnusedManga: Boolean; - i, j, sel: Integer; - lang: TStringList; - s, currentLanguage: String; - ANode, currentRootNode: PVirtualNode; + categories: TStringList; + categoriesitem: TStringList; + i, j: Integer; + s: String; + module: TModuleContainer; + node: PVirtualNode; + nodei: PVirtualNode; data: PSingleItem; - wName, wLang: TStringList; begin - DBDownloadURL:=mangalistfile.ReadString('general','DBDownloadURL',''); - wName := TStringList.Create; - wLang := TStringList.Create; - lang := TStringList.Create; + categories := TStringList.Create; + categories.OwnsObjects := True; + categories.Sorted := False; try - mangalistfile.ReadSection('available', lang); - TrimStrings(lang); - if lang.Count > 0 then - for i := 0 to lang.Count - 1 do + // read mangalist.ini + with TIniFile.Create(MANGALIST_FILE) do + try + // databases download url + DBDownloadURL := ReadString('general', 'DBDownloadURL', DBDownloadURL); + + // read available websites + ReadSection('available', categories); + for i := 0 to categories.Count - 1 do begin - s := Trim(mangalistfile.ReadString('available', lang[i], '')); + categoriesitem := TStringList.Create; + categories.Objects[i] := categoriesitem; + categoriesitem.Sorted := False; + s := Trim(ReadString('available', categories[i], '')); if s <> '' then - ExtractStrings([','], [], PChar(s), wName); - TrimStrings(wName); - while wlang.Count < wName.Count do - wLang.Add(lang[i]); + categoriesitem.CommaText := s; end; + finally + Free; + end; - // load to option list - if wName.Count > 0 then + // sort all + categories.Duplicates := dupIgnore; + categories.Sorted := True; + for i := 0 to categories.Count - 1 do begin - SetLength(optionMangaSiteSelectionNodes, wName.Count); - currentLanguage := ''; - for i := 0 to wName.Count - 1 do - with vtOptionMangaSiteSelection do - begin - if currentLanguage <> wLang[i] then - begin - currentLanguage := wLang[i]; - currentRootNode := AddChild(nil); - data := GetNodeData(currentRootNode); - data^.Text := currentLanguage; - ValidateNode(currentRootNode, False); - end; - ANode := AddChild(currentRootNode); - ANode^.CheckState := csUncheckedNormal; - data := GetNodeData(ANode); - data^.Text := wName[i]; - ValidateNode(ANode, False); - optionMangaSiteSelectionNodes[i] := ANode; - end; + categoriesitem := TStringList(categories.Objects[i]); + categoriesitem.Duplicates := dupIgnore; + categoriesitem.Sorted := True; end; - // load selected manga list - lang.Clear; - s := configfile.ReadString('general', 'MangaListSelect', DEFAULT_LIST); - if Pos(SEPERATOR, s) <> 0 then - ExtractParam(lang, s, SEPERATOR, False) - else - ExtractParam(lang, s, ',', False); - cbSelectManga.Items.Assign(lang); - - // remove unused manga name - i := 0; - if (lang.Count > 0) and (Length(optionMangaSiteSelectionNodes) > 0) then - while i < lang.Count do + // read websitemodules + for i := 0 to WebsiteModules.Modules.Count - 1 do + begin + module := WebsiteModules.Modules[i]; + if module.Category <> '' then begin - isDeleteUnusedManga := True; - for j := 0 to Length(optionMangaSiteSelectionNodes) - 1 do + j := categories.IndexOf(module.Category); + if j = -1 then begin - Data := vtOptionMangaSiteSelection.GetNodeData( - optionMangaSiteSelectionNodes[j]); - if lang[i] = Data^.Text then - begin - isDeleteUnusedManga := False; - Break; - end; - end; - if isDeleteUnusedManga then - lang.Delete(i) + categoriesitem := TStringList.Create; + categories.AddObject(module.Category, categoriesitem); + categoriesitem.Duplicates := dupIgnore; + categoriesitem.Sorted := True; + end else - Inc(i); + categoriesitem := TStringList(categories.Objects[j]); + categoriesitem.Add(module.Website); end; + end; - // load last selected manga - if cbSelectManga.Items.Count > 0 then + // add them to vt websites selection and availablewebsites + for i := 0 to categories.Count - 1 do begin - sel := configfile.ReadInteger('form', 'SelectManga', 0); - if sel < 0 then - sel := 0; - if sel > cbSelectManga.Items.Count - 1 then - sel := cbSelectManga.Items.Count - 1; - cbSelectManga.ItemIndex := sel; - currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; + node := vtOptionMangaSiteSelection.AddChild(nil, nil); + vtOptionMangaSiteSelection.ValidateNode(node, False); + data := vtOptionMangaSiteSelection.GetNodeData(node); + data^.Text := categories[i]; + categoriesitem := TStringList(categories.Objects[i]); + for j := 0 to categoriesitem.Count - 1 do + begin + s := categoriesitem[j]; + nodei := vtOptionMangaSiteSelection.AddChild(node, nil); + vtOptionMangaSiteSelection.ValidateNode(nodei, False); + nodei^.CheckType := ctCheckBox; + data := vtOptionMangaSiteSelection.GetNodeData(nodei); + data^.Text := s; + AvailableWebsites.Add(s); + end; end; + AvailableWebsites.Duplicates := dupIgnore; + AvailableWebsites.Sorted := True; finally - lang.Free; - wName.Free; - wLang.Free; + categories.Free; end; -end; -function TMainForm.SaveMangaOptions: String; -var - i: Integer; - data: PSingleItem; -begin - Result := ''; - if Length(optionMangaSiteSelectionNodes) > 0 then - for i := Low(optionMangaSiteSelectionNodes) to High(optionMangaSiteSelectionNodes) do + // load selected websites + s := configfile.ReadString('general', 'MangaListSelect', DEFAULT_SELECTED_WEBSITES); + if Pos(SEPERATOR, s) <> 0 then + ExtractParam(cbSelectManga.Items, s, SEPERATOR, False) + else + ExtractParam(cbSelectManga.Items, s, ',', False); + + // remove missing websites from selected websites + for i := cbSelectManga.Items.Count - 1 downto 0 do + begin + if not AvailableWebsites.Find(cbSelectManga.Items[i], j) then + cbSelectManga.Items.Delete(i); + end; + + // set checked vt websites selection + for i := 0 to cbSelectManga.Items.Count - 1 do + begin + node := vtOptionMangaSiteSelection.GetFirst(); + while node <> nil do begin - data := vtOptionMangaSiteSelection.GetNodeData(optionMangaSiteSelectionNodes[i]); - if optionMangaSiteSelectionNodes[i]^.CheckState = csCheckedNormal then + if node^.ChildCount = 0 then begin - if Result = '' then - Result := data^.Text - else - Result := Result + ',' + data^.Text; + data := vtOptionMangaSiteSelection.GetNodeData(node); + if cbSelectManga.Items[i] = data^.Text then + begin + node^.CheckState := csCheckedNormal; + Break; + end; end; + node := vtOptionMangaSiteSelection.GetNext(node); end; + end; + + // load last selected webssite + if cbSelectManga.Items.Count > 0 then + begin + i := configfile.ReadInteger('form', 'SelectManga', 0); + if i < 0 then + i := 0; + if i > cbSelectManga.Items.Count - 1 then + i := cbSelectManga.Items.Count - 1; + cbSelectManga.ItemIndex := i; + currentWebsite := cbSelectManga.Items[cbSelectManga.ItemIndex]; + end; end; procedure TMainForm.edMangaListSearchChange(Sender: TObject); @@ -5953,54 +5920,23 @@ procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, end; end; -procedure TMainForm.vtOptionMangaSiteSelectionChange(Sender : TBaseVirtualTree; - Node : PVirtualNode); -begin - vtOptionMangaSiteSelection.Refresh; -end; - -procedure TMainForm.vtOptionMangaSiteSelectionFocusChanged( - Sender : TBaseVirtualTree; Node : PVirtualNode; Column : TColumnIndex); -begin - vtOptionMangaSiteSelection.Refresh; -end; - procedure TMainForm.vtOptionMangaSiteSelectionFreeNode( Sender : TBaseVirtualTree; Node : PVirtualNode); -var - Data: PSingleItem; begin - Data := vtOptionMangaSiteSelection.GetNodeData(Node); - if Assigned(Data) then - Finalize(Data^); + Finalize(PSingleItem(Sender.GetNodeData(Node))^); end; procedure TMainForm.vtOptionMangaSiteSelectionGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); begin - NodeDataSize := SizeOf(TMangaListItem); + NodeDataSize := SizeOf(TSingleItem); end; procedure TMainForm.vtOptionMangaSiteSelectionGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - Data: PSingleItem; -begin - Data := vtOptionMangaSiteSelection.GetNodeData(Node); - if Assigned(Data) then - CellText := Data^.Text; -end; - -procedure TMainForm.vtOptionMangaSiteSelectionInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Level: Integer; begin - Level := vtOptionMangaSiteSelection.GetNodeLevel(Node); - if Level = 1 then - Node^.CheckType := ctCheckBox; - vtOptionMangaSiteSelection.ValidateNode(Node, False); + CellText := PSingleItem(vtOptionMangaSiteSelection.GetNodeData(Node))^.Text; end; end. diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm index 321c6d16c..4c5dd86b9 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm @@ -7,6 +7,7 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm ClientWidth = 510 OnCreate = FormCreate OnDestroy = FormDestroy + LCLVersion = '1.9.0.0' object pcAdvanced: TPageControl Left = 0 Height = 307 @@ -306,83 +307,11 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm top = 89 object MenuItem1: TMenuItem Caption = 'Add' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 - 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 - 0000000000040000001B0000003000000033024700A6025D00CC025D00CC0247 - 00A600000033000000310000001F0000000600000000FFFFFF00FFFFFF000000 - 0000000000000000000000000000021D0000066D00CC22D811FF22D811FF066D - 00CC021D000000000000000000000000000000000000FFFFFF00FFFFFF000747 - 00000000000000000000032000000A7D00000A7D00CC23CD12FF22CC11FF0A7D - 00CC0A7D000003200000000000000000000000000000FFFFFF00FFFFFF000E8D - 00000E8C00000E8C00000E8A00000C8400000C8400CC25C014FF24C013FF0C84 - 00CC0C8400000E8A00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8D - 00000E8C00000E8C00000E8C00000E8B00000D8900CC29B618FF27B416FF0D89 - 00CC0E8B00000E8C00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8E - 00990E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D - 00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000F92 - 00CC59D048FF50C73FFF50C73FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A9 - 20FF2CA51BFF2BA31AFF2DA51CFF33AB22FF0F9200CCFFFFFF00FFFFFF001096 - 00CC5ED54DFF55CC44FF54CB43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC6 - 3EFF4EC53DFF4DC43CFF4CC33BFF4EC53DFF109600CCFFFFFF00FFFFFF00119A - 0099119A00CC119A00CC119A00CC119A00CC119A00CC54CB43FF52C941FF119A - 00CC119A00CC119A00CC119A00CC119A00CC119A0099FFFFFF00FFFFFF00119A - 0000119B0000119B0000119B0000129C0000129E00CC5AD149FF59D048FF129E - 00CC129C0000119B0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A - 0000119B0000119B0000129D000013A2000013A200CC62D951FF61D850FF13A2 - 00CC13A20000129D0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A - 0000119B0000129E000014A5000014A5000014A500CC69E058FF69E058FF14A5 - 00CC14A5000014A50000129E0000119B0000119A0000FFFFFF00FFFFFF00119A - 0000129F000014A8000014A8000014A8000014A800CC72E961FF71E860FF14A8 - 00CC14A8000014A8000014A80000129F0000119A0000FFFFFF00FFFFFF003B7F - 320015A9000015A9000015A9000015A9000015AA009915AA00CC15AA00CC15AA - 009915A9000015A9000015A9000015A90000094D0000FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 0 OnClick = MenuItem1Click end object MenuItem2: TMenuItem Caption = 'Edit' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 200000000000000400006400000064000000000000000000000000000000014B - 649A012E3C63010A0D350000002D0000002A00000026000000210000001D0000 - 001900000014000000100000000B000000080000000500000002015E7B85C2E6 - F2FF5591A5D1014C649A013141500000001500000013000000110000000F0000 - 000D0000000A0000000800000006000000040000000300000001016B8E3962A5 - BBC0C2E6F2FFA0CEDDF501596FC30060764701343E0000000000000000000000 - 000000000000000000000000000000000000000000000000000000759B060072 - 976CC0E4F1EF44BBCCFF58CEDFFF016379CA01687D47016F8500013C47000000 - 0000000000000000000000000000000000000000000000000000007CA500007C - A527018DA8A688EEFFFF5DD1E2FF5BD0E1FF016B80C80170864601788E000281 - 9700014550000000000000000000000000000000000000000000007CA500007D - A600019AB2400195ADB788EEFFFF63D5E6FF5FD3E4FF017389C701798F450281 - 97000289A0000291A800024D5800000000000000000000000000007CA500007D - A600019BB200019AB2400195ADB788EEFFFF69DAEBFF60D3E4FF027C92C50282 - 98450289A0000291A8000399AF000A0A0A000505050000000000007CA500007D - A600019BB200019BB200019AB2400195ADB788EEFFFF71DEEFFF60D3E4FF0285 - 9BC3028AA1450291A8000399AF000A0A0A000A0A0A000A0A0A00007CA500007D - A600019BB200019BB200019BB200019AB2400195ADB788EEFFFF78E3F4FF5DD2 - E3FF028DA4C20292A9440399AF000A0A0A000A0A0A000A0A0A00007CA500007D - A600019BB200019BB200019BB200019BB200019AB2400195ADB788EEFFFF7EE7 - F8FF5ACFE0FF0395ACC0039AB0430A0A0A000A0A0A000A0A0A00007CA500007D - A600019BB200019BB200019BB200019BB200019BB200019AB2400195ADB788EE - FFFF83EBFCFF56CDDEFF087A8CB00C0C0C2F0A0A0A000A0A0A00001F2A00005E - 7D00019BB200019BB200019BB200019BB200019BB200019BB200019AB2400195 - ADB788EEFFFF33AABBFFDDDDDDFF171717830909312905055500000000000000 - 000001272D0001758600019BB200019BB200019BB200019BB200019BB200019A - B240158395A3F6F6F6FFCCCCCCFFDDDDDDFF060683B50000A032000000000000 - 0000000000000000000001272D0001758600019BB200019BB200019BB200019B - B2005555552450505069F6F6F6FF6868F8FF5C5CF2FF0000A8B1000000000000 - 00000000000000000000000000000000000001272D0001758600019BB200019B - B200555555005555551F1515BC9D8888FFFF0101C5B90101B443000000000000 - 000000000000000000000000000000000000000000000000000001272D000175 - 860055555500555555000101E42B0101E09D0101D23F0101B600 - } ImageIndex = 1 OnClick = MenuItem2Click end @@ -391,42 +320,6 @@ object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm end object MenuItem4: TMenuItem Caption = 'Delete' - Bitmap.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 - 000E00000014000000190000001900000016000000100000000B000000080000 - 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 - 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 - 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 - 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 - 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 - 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 - 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 - 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 - 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 - 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 - 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 - 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 - 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 - 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 - 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 - 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 - 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 - 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F - BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 - 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E - A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 - A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 - 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 - A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 - 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } ImageIndex = 2 OnClick = MenuItem4Click end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 38f41c37c..1f93c8beb 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -295,12 +295,12 @@ procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtual if AVT = nil then Exit; if S = nil then Exit; S.Clear; - if AvailableWebsite.Count > 0 then + if AvailableWebsites.Count > 0 then begin S.BeginUpdate; try - for i := 0 to AvailableWebsite.Count - 1 do - S.Add(AvailableWebsite.Names[i]); + for i := 0 to AvailableWebsites.Count - 1 do + S.Add(AvailableWebsites.Names[i]); if AVT.RootNodeCount > 0 then begin Node := AVT.GetFirst(); From c8fdf211e8388451985d374dfe714448de07211c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 10:01:11 +0300 Subject: [PATCH 2203/2794] add HotChocolateScans [EN-SC] #959 --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index f76214a63..ca5555698 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,Mangaf English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree +English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,HotChocolateScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,NeuManga,PecintaKomik,Subapics diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 48c1520cf..eebe9b36d 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -6,6 +6,7 @@ local dirurlslideU = '/Slide/directory/' local dirurlonline = '/online/directory/' local dirurlhelvetica = '/r/directory/' local dirurllector = '/lector/directory/' +local dirurlfsdir = '/fs/directory/' function getWithCookie(lurl) local needCookie = { @@ -40,7 +41,8 @@ function getdirurl(website) ['SeinagiFansub'] = dirurlonline, ['HelveticaScans'] = dirurlhelvetica, ['RavensScans'] = dirurllector, - ['NoraNoFansub'] = dirurllector + ['NoraNoFansub'] = dirurllector, + ['HotChocolateScans'] = dirurlfsdir } if dirs[website] ~= nil then return dirs[website] @@ -201,6 +203,7 @@ function Init() AddWebsiteModule('ChampionScans', 'http://reader.championscans.com') AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org') AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com') + AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com') -- es-sc AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') From fcd8ae86c669737b20a17282db9ae0738bb3e419 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 10:05:09 +0300 Subject: [PATCH 2204/2794] add LetItGoScans [EN-SC] #959 --- config/mangalist.ini | 2 +- lua/modules/FoOlSlide.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index ca5555698..8a65d632c 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,7 +6,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,Mangaf English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,HotChocolateScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree +English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,HotChocolateScans,LetItGoScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,NeuManga,PecintaKomik,Subapics diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index eebe9b36d..4c6bc13c9 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -204,6 +204,7 @@ function Init() AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org') AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com') AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com') + AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today') -- es-sc AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') From cb35771017f9835dd8600e1eceeccf5e8dd11f1a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 15:25:10 +0800 Subject: [PATCH 2205/2794] luamodule, add runtime option checkbox, edit, spinedit, combobox --- baseunits/WebsiteModules.pas | 10 +- baseunits/lua/LuaWebsiteModules.pas | 171 +++++++++++++++++- mangadownloader/forms/frmMain.pas | 3 + .../forms/frmWebsiteOptionCustom.pas | 2 - 4 files changed, 178 insertions(+), 8 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 8b0e4e174..b38972537 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -79,7 +79,7 @@ TModuleContainer = class function CloudflareHTTPRequest(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject = nil): Boolean; procedure SetTotalDirectory(AValue: Integer); procedure AddOption(const AOptionType: TWebsiteOptionType; - const ABindValue: Pointer; const AName: String; const ACaption: PString); + const ABindValue: Pointer; const AName: String; const ACaption: PString; const AItems: PString = nil); public Tag: Integer; TagPtr: Pointer; @@ -362,9 +362,7 @@ procedure TModuleContainer.AddOptionSpinEdit(const ABindValue: PInteger; procedure TModuleContainer.AddOptionComboBox(const ABindValue: PInteger; const AName: String; const ACaption, AItems: PString); begin - AddOption(woComboBox, ABindValue, AName, ACaption); - with OptionList[High(OptionList)] do - Items := AItems; + AddOption(woComboBox, ABindValue, AName, ACaption, AItems); end; procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); @@ -373,7 +371,8 @@ procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); end; procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; - const ABindValue: Pointer; const AName: String; const ACaption: PString); + const ABindValue: Pointer; const AName: String; const ACaption: PString; + const AItems: PString); begin if ABindValue = nil then Exit; if AName = '' then Exit; @@ -384,6 +383,7 @@ procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; BindValue := ABindValue; Name := CleanOptionName(AName); Caption := ACaption; + Items := AItems; end; end; diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 9baf04677..cd5ad1030 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -9,7 +9,6 @@ interface uDownloadsManager, xquery, httpsendthread; type - TLuaWebsiteModulesContainer = class; { TLuaWebsiteModule } @@ -34,9 +33,18 @@ TLuaWebsiteModule = class Storage: TStringsStorage; LastUpdated: String; Container: TLuaWebsiteModulesContainer; + + Options: TStringList; + constructor Create; destructor Destroy; override; + function AddOption(const AName, ACaption: String; const AClass: TClass): Integer; + procedure AddOptionCheckBox(const AName, ACaption: String; const ADefault: Boolean); + procedure AddOptionEdit(const AName, ACaption: String; const ADefault: String); + procedure AddOptionSpinEdit(const AName, ACaption: String; const ADefault: Integer); + procedure AddOptionComboBox(const AName, ACaption, AItems: String; const ADefault: Integer); + procedure LuaPushMe(L: Plua_State); function LuaDoMe(L: Plua_State): Integer; end; @@ -66,6 +74,27 @@ TLuaWebsiteModulesManager = class destructor Destroy; override; end; + TOptionItem = class + Caption: String; + end; + + TOptionItemCheckBox = class(TOptionItem) + Value: Boolean; + end; + + TOptionItemEdit = class(TOptionItem) + Value: String; + end; + + TOptionItemSpinEdit = class(TOptionItem) + Value: Integer; + end; + + TOptionItemComboBox = class(TOptionItem) + Items: String; + Value: Integer; + end; + procedure ScanLuaWebsiteModulesFile; var @@ -550,16 +579,84 @@ constructor TLuaWebsiteModule.Create; begin LuaWebsiteModulesManager.TempModuleList.Add(Self); Storage := TStringsStorage.Create; + Options := TStringList.Create; + Options.OwnsObjects := True; + Options.Duplicates := dupIgnore; + Options.Sorted := True; Module := Modules.AddModule; Module.TagPtr := Self; end; destructor TLuaWebsiteModule.Destroy; begin + Options.Free; Storage.Free; inherited Destroy; end; +function TLuaWebsiteModule.AddOption(const AName, ACaption: String; const AClass: TClass): Integer; +var + o: TOptionItem; +begin + Result := Options.Add(AName); + if Result = -1 then Exit; + o := TOptionItem(AClass.Create); + o.Caption := ACaption; + Options.Objects[Result] := o; +end; + +procedure TLuaWebsiteModule.AddOptionCheckBox(const AName, ACaption: String; + const ADefault: Boolean); +var + o: TOptionItemCheckBox; + i: Integer; +begin + i := AddOption(AName, ACaption, TOptionItemCheckBox); + if i = -1 then Exit; + o := TOptionItemCheckBox(Options.Objects[i]); + o.Value := ADefault; + Module.AddOptionCheckBox(@o.Value, Options[i], @o.Caption); +end; + +procedure TLuaWebsiteModule.AddOptionEdit(const AName, ACaption: String; const ADefault: String); +var + o: TOptionItemEdit; + i: Integer; +begin + i := AddOption(AName, ACaption, TOptionItemEdit); + if i = -1 then Exit; + o := TOptionItemEdit(Options.Objects[i]); + o.Value := ADefault; + Module.AddOptionEdit(@o.Value, Options[i], @o.Caption); +end; + +procedure TLuaWebsiteModule.AddOptionSpinEdit(const AName, ACaption: String; + const ADefault: Integer); +var + o: TOptionItemSpinEdit; + i: Integer; +begin + i := AddOption(AName, ACaption, TOptionItemSpinEdit); + if i = -1 then Exit; + o := TOptionItemSpinEdit(Options.Objects[i]); + o.Value := ADefault; + Module.AddOptionSpinEdit(@o.Value, Options[i], @o.Caption); +end; + +procedure TLuaWebsiteModule.AddOptionComboBox(const AName, ACaption, AItems: String; + const ADefault: Integer); +var + o: TOptionItemComboBox; + i: Integer; +begin + i := AddOption(AName, ACaption, TOptionItemComboBox); + if i = -1 then Exit; + o := TOptionItemComboBox(Options.Objects[i]); + o.Items := AItems; + o.Value := ADefault; + Module.AddOptionComboBox(@o.Value, Options[i], @o.Caption, @o.Items); +end; + procedure TLuaWebsiteModule.LuaPushMe(L: Plua_State); begin luaPushObject(L, Self, 'module'); @@ -578,6 +675,75 @@ function TLuaWebsiteModule.LuaDoMe(L: Plua_State): Integer; Result := lua_pcall(L, 0, 0, 0); end; +// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- + +function lua_addoptioncheckbox(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TLuaWebsiteModule(luaClassGetObject(L)).AddOptionCheckBox( + lua_tostring(L, 1), lua_tostring(L, 2), lua_toboolean(L, 3)); +end; + +function lua_addoptionedit(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TLuaWebsiteModule(luaClassGetObject(L)).AddOptionEdit( + lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3)); +end; + +function lua_addoptionspinedit(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TLuaWebsiteModule(luaClassGetObject(L)).AddOptionSpinEdit( + lua_tostring(L, 1), lua_tostring(L, 2), lua_tointeger(L, 3)); +end; + +function lua_addoptioncombobox(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TLuaWebsiteModule(luaClassGetObject(L)).AddOptionComboBox( + lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), lua_tointeger(L, 4)); +end; + +function lua_getoption(L: Plua_State): Integer; cdecl; +var + m: TLuaWebsiteModule; + i: Integer; + o: TObject; +begin + m := TLuaWebsiteModule(luaClassGetObject(L)); + i:=m.Options.IndexOf(lua_tostring(L, 1)); + if i = -1 then + Result := 0 + else + begin + o := m.Options.Objects[i]; + if o is TOptionItemCheckBox then + lua_pushboolean(L, TOptionItemCheckBox(o).Value) + else + if o is TOptionItemEdit then + lua_pushstring(L, TOptionItemEdit(o).Value) + else + if o is TOptionItemSpinEdit then + lua_pushinteger(L, TOptionItemSpinEdit(o).Value) + else + if o is TOptionItemComboBox then + lua_pushinteger(L, TOptionItemComboBox(o).Value); + Result := 1; + end; +end; + +const + methods: packed array [0..5] of luaL_Reg = ( + (name: 'AddOptionCheckBox'; func: @lua_addoptioncheckbox), + (name: 'AddOpionEdit'; func: @lua_addoptionedit), + (name: 'AddOptionSpinEdit'; func: @lua_addoptionspinedit), + (name: 'AddOptionCombobox'; func: @lua_addoptioncombobox), + (name: 'GetOption'; func: @lua_getoption), + (name: nil; func: nil) + ); + procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, UserData: Integer; AutoFree: Boolean = False); begin @@ -617,6 +783,9 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'OnAfterImageSaved', @OnAfterImageSaved); luaClassAddStringProperty(L, MetaTable, 'OnLogin', @OnLogin); luaClassAddStringProperty(L, MetaTable, 'LastUpdated', @LastUpdated); + + luaClassAddFunction(L, MetaTable, UserData, methods); + luaClassAddObject(L, MetaTable, Storage, 'Storage'); end; end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8bc8f9a8b..c44e12d93 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1819,6 +1819,9 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); FavoriteManager.Restore; UpdateVtFavorites; + Modules.LoadWebsiteOption; + frmWebsiteOptionCustom.WebsiteOptionCustomForm.CreateWebsiteOption; + if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if OptionAutoCheckLatestVersion then diff --git a/mangadownloader/forms/frmWebsiteOptionCustom.pas b/mangadownloader/forms/frmWebsiteOptionCustom.pas index d265e9277..cbc98789c 100644 --- a/mangadownloader/forms/frmWebsiteOptionCustom.pas +++ b/mangadownloader/forms/frmWebsiteOptionCustom.pas @@ -203,8 +203,6 @@ procedure TCustomOptionForm.FormCreate(Sender: TObject); HorizontalSpacing := hspace; VerticalSpacing := vspace; end; - Modules.LoadWebsiteOption; - CreateWebsiteOption; end; procedure TCustomOptionForm.FormDestroy(Sender: TObject); From e3422205998887f7c5af4341cf604837ab7c9ae8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 15:57:15 +0800 Subject: [PATCH 2206/2794] add category --- config/mangalist.ini | 8 ++++---- lua/modules/EGScans.lua | 3 ++- lua/modules/LHTranslation.lua | 1 + lua/modules/MangaStream.lua | 1 + lua/modules/NeuManga.lua | 1 + lua/modules/myReaderMangaCMS.lua | 17 +++++++++-------- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 8a65d632c..f680ad591 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,19 +6,19 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do Arabic=GManga,MangaAe,Mangaf English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,ChibiManga,DokiFansubs,Dynasty-Scans,EGScans,FallenAngelsScans,GameofScanlation,HelveticaScans,HotChocolateScans,LetItGoScans,LHTranslation,Mangacow,MangaStream,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree +English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,GameofScanlation,HelveticaScans,HotChocolateScans,LetItGoScans,Mangacow,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga -Indonesian=Komikid,Mangacan,MangaDesu,MangaID,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,NeuManga,PecintaKomik,Subapics +Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics Malaysian-Indonesian= Polish= Portugues=CentralDeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU -Spanish=AnimExtremist,KuManga,LeoManga,MangaDoor,NineMangaES,SekaiManga,SubManga,Tumangaonline +Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,NoraNoFansub,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub,YamiTenshiNoFansub Thai=MangaBoom -Turkish=MangaDenizi,MangaOku,Manga-Tr,Puzzmos,WebtoonTr +Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing Webcomics=Tapas H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU diff --git a/lua/modules/EGScans.lua b/lua/modules/EGScans.lua index 7a6628b48..566ffb10f 100644 --- a/lua/modules/EGScans.lua +++ b/lua/modules/EGScans.lua @@ -61,8 +61,9 @@ end function Init() local m = NewModule() + m.category = 'English-Scanlation' m.website = 'EGScans' - m.rooturl = 'http://read.egscans.com' + m.rooturl = 'http://read.egscans.com' m.lastupdated = 'february, 10 2018' m.ongetinfo = 'getinfo' m.OnTaskStart = 'taskstart' diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index 0fb69b6d6..debd732f4 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -44,6 +44,7 @@ end function Init() m=NewModule() + m.category = 'English-Scanlation' m.Website = 'LHTranslation' m.RootURL = 'http://lhtranslation.com' m.OnGetNameAndLink = 'GetNameAndLink' diff --git a/lua/modules/MangaStream.lua b/lua/modules/MangaStream.lua index 1228dff82..4bbf91940 100644 --- a/lua/modules/MangaStream.lua +++ b/lua/modules/MangaStream.lua @@ -43,6 +43,7 @@ end function Init() m=NewModule() + m.category='English-Scanlation' m.website='MangaStream' m.rooturl='https://readms.net' m.lastupdated='February 8, 2018' diff --git a/lua/modules/NeuManga.lua b/lua/modules/NeuManga.lua index 7432ae71c..4ad4ae6f9 100644 --- a/lua/modules/NeuManga.lua +++ b/lua/modules/NeuManga.lua @@ -57,6 +57,7 @@ end function Init() m=NewModule() + m.category='Indonesian' m.website='NeuManga' m.rooturl='http://neumanga.tv' m.lastupdated='February 12, 2018' diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 1297f85a3..27373f1da 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -51,8 +51,9 @@ function GetPageNumber() end end -function AddWebsiteModule(name, url) +function AddWebsiteModule(name, url, cat) local m = NewModule() + m.category = cat m.Website = name m.RootURL = url m.LastUpdated = 'February 12, 2018' @@ -63,11 +64,11 @@ function AddWebsiteModule(name, url) end function Init() - AddWebsiteModule('Komikid', 'http://www.komikid.com'); - AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com'); - AddWebsiteModule('MangaDoor', 'http://mangadoor.com'); - AddWebsiteModule('MangaID', 'http://mangaid.co'); - AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com'); - AddWebsiteModule('MangaDesu','http://mangadesu.net'); - AddWebsiteModule('ChibiManga','http://www.cmreader.info'); + AddWebsiteModule('Komikid', 'http://www.komikid.com', 'Indonesian'); + AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', 'Turkish'); + AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); + AddWebsiteModule('MangaID', 'http://mangaid.co', 'Indonesian'); + AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', 'English-Scanlation'); + AddWebsiteModule('MangaDesu','http://mangadesu.net', 'Indonesian'); + AddWebsiteModule('ChibiManga','http://www.cmreader.info', 'English-Scanlation'); end From 15de4f499ceda21ab7a9b3356d2ed96fa0f1ef84 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 15:59:15 +0800 Subject: [PATCH 2207/2794] luamodulesupdater, only store last message --- mangadownloader/forms/frmLuaModulesUpdater.pas | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index a411411f8..1a936ba78 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -210,9 +210,7 @@ function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean; begin t.sha := sha; t.last_modified := last_modified; - if t.last_message <> '' then - t.last_message := LineEnding + t.last_message; - t.last_message := last_message + t.last_message; + t.last_message := last_message; t.flag := fUpdate; end; end; From be27769be98924e924cda0b49c7d87b003c15818 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 16:04:04 +0800 Subject: [PATCH 2208/2794] update changelog --- changelog.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/changelog.txt b/changelog.txt index cada455a0..9b62c83f5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,15 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.138.0 (--2018) +[+] Added option to delete completed task on close +[+] Added option to convert PNG images to JPEG +[+] Added NeuManga [ID] +[+] Added HotChoholateScans [EN-SC] +[+] Added LetItGoScans [EN-SC] +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.137.0...0.9.138.0 + 0.9.137.0 (12-02-2018) [+] Added ChibiManga [EN-SC] [*] Fixed updater can't find 7za.exe, you need to download this release manually From 6c79bef411faba7a3ffade894c7d2fe00d6bf01a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 10:58:06 +0300 Subject: [PATCH 2209/2794] foolslide, add category --- config/mangalist.ini | 6 ++-- lua/modules/FoOlSlide.lua | 67 ++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index f680ad591..95ff58f37 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,9 +4,9 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,Mangaf -English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd +English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=AtelierDuNoir,ChampionScans,DokiFansubs,Dynasty-Scans,GameofScanlation,HelveticaScans,HotChocolateScans,LetItGoScans,Mangacow,MangaZuki,OneTimeScans,PsychoPlay,S2Scans,SenseScans,Shoujosense,TripleSevenScan,Jaiminisbox,PowerManga,KireiCake,WhiteoutScans,WorldThree +English-Scanlation=Dynasty-Scans,GameofScanlation,Mangacow,MangaZuki,PsychoPlay French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics @@ -16,7 +16,7 @@ Portugues=CentralDeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,Un Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation=DangoOnlineNoFansub,DejameProbar,HoshinoFansub,KirishimaFansub,MenudoFansub,NeoProjectScan,NoraNoFansub,Pzykosis666HFansub,RavensScans,SantosScan,SeinagiFansub,SeinagiAdultoFansub,SolitarioNoFansub,YamiTenshiNoFansub +Spanish-Scanlation= Thai=MangaBoom Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 4c6bc13c9..48a42e23c 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -174,10 +174,11 @@ function getnameandlink() return result end -function AddWebsiteModule(name, url) +function AddWebsiteModule(name, url, category) local m = NewModule() m.website = name m.rooturl = url + m.category = category m.lastupdated = 'february, 6 2018' m.ongetinfo = 'getinfo' m.OnTaskStart = 'taskstart' @@ -189,37 +190,39 @@ function AddWebsiteModule(name, url) end function Init() - AddWebsiteModule('PowerManga', 'http://read.powermanga.org') - AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com') - AddWebsiteModule('GoManga', 'http://gomanga.co') - AddWebsiteModule('OneTimeScans', 'http://otscans.com') - AddWebsiteModule('SenseScans', 'http://reader.sensescans.com') - AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com') - AddWebsiteModule('KireiCake', 'https://reader.kireicake.com') - AddWebsiteModule('HelveticaScans', 'http://helveticascans.com') - AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com') - AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com') - AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org') - AddWebsiteModule('ChampionScans', 'http://reader.championscans.com') - AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org') - AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com') - AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com') - AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today') + local cat = 'English-Scanlation' + AddWebsiteModule('PowerManga', 'http://read.powermanga.org', cat) + AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com', cat) + AddWebsiteModule('GoManga', 'http://gomanga.co', 'English') + AddWebsiteModule('OneTimeScans', 'http://otscans.com', cat) + AddWebsiteModule('SenseScans', 'http://reader.sensescans.com', cat) + AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com', cat) + AddWebsiteModule('KireiCake', 'https://reader.kireicake.com', cat) + AddWebsiteModule('HelveticaScans', 'http://helveticascans.com', cat) + AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com', cat) + AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com', cat) + AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org', cat) + AddWebsiteModule('ChampionScans', 'http://reader.championscans.com', cat) + AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org', cat) + AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com', cat) + AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com', cat) + AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today', cat) + AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com', cat) -- es-sc - AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com') - AddWebsiteModule('DejameProbar', 'http://dejameprobar.es') - AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com') - AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com') - AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net') - AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com') - AddWebsiteModule('SantosScan', 'http://santosfansub.com') - AddWebsiteModule('SeinagiFansub', 'http://seinagi.org') - AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org') - AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net') - AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com') - AddWebsiteModule('RavensScans', 'http://ravens-scans.com') - AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com') - AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com') - AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com') + cat = 'Spanish-Scanlation' + AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com', cat) + AddWebsiteModule('DejameProbar', 'http://dejameprobar.es', cat) + AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) + AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) + AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) + AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com', cat) + AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) + AddWebsiteModule('SeinagiFansub', 'http://seinagi.org', cat) + AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org', cat) + AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net', cat) + AddWebsiteModule('RavensScans', 'http://ravens-scans.com', cat) + AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com', cat) + AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com', cat) + AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com', cat) end From b159c519377a76d1c3c2ef51068b02b7e9fe833d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 16:10:19 +0800 Subject: [PATCH 2210/2794] luawebsitemodule, fix typo --- baseunits/lua/LuaWebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index cd5ad1030..0f4090313 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -737,7 +737,7 @@ function lua_getoption(L: Plua_State): Integer; cdecl; const methods: packed array [0..5] of luaL_Reg = ( (name: 'AddOptionCheckBox'; func: @lua_addoptioncheckbox), - (name: 'AddOpionEdit'; func: @lua_addoptionedit), + (name: 'AddOptionEdit'; func: @lua_addoptionedit), (name: 'AddOptionSpinEdit'; func: @lua_addoptionspinedit), (name: 'AddOptionCombobox'; func: @lua_addoptioncombobox), (name: 'GetOption'; func: @lua_getoption), From bc1c27057daec3c2532acba923da02884da66d82 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 16:21:47 +0800 Subject: [PATCH 2211/2794] Bump version 0.9.138.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9b62c83f5..ff3835050 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.138.0 (--2018) +0.9.138.0 (14-02-2018) [+] Added option to delete completed task on close [+] Added option to convert PNG images to JPEG [+] Added NeuManga [ID] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 868f5c5d3..545af5caf 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="137"/> + <RevisionNr Value="138"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 92d50a212..641305df3 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.137.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.137.0/fmd_0.9.137.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.137.0/fmd_0.9.137.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.137.0/fmd_0.9.137.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.137.0/fmd_0.9.137.0_Win64.7z +VERSION=0.9.138.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.138.0/fmd_0.9.138.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.138.0/fmd_0.9.138.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.138.0/fmd_0.9.138.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.138.0/fmd_0.9.138.0_Win64.7z From 297a13699aec9b39a2b9ab24209bbf74d4a43291 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 10:25:47 +0300 Subject: [PATCH 2212/2794] add SelfMangaRU [RU] --- baseunits/modules/MintMangaRU.pas | 2 ++ config/mangalist.ini | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MintMangaRU.pas b/baseunits/modules/MintMangaRU.pas index da25424e8..6142cb1fb 100644 --- a/baseunits/modules/MintMangaRU.pas +++ b/baseunits/modules/MintMangaRU.pas @@ -170,6 +170,7 @@ procedure RegisterModule; with Result do begin Website := AWebsite; RootURL := ARootURL; + Category := 'Russian'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; @@ -182,6 +183,7 @@ procedure RegisterModule; begin AddWebsiteModule('MintMangaRU', 'http://mintmanga.com'); AddWebsiteModule('ReadMangaRU', 'http://readmanga.me'); + AddWebsiteModule('SelfMangaRU', 'http://selfmanga.ru'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index 95ff58f37..803e6bb8e 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,7 +14,7 @@ Malaysian-Indonesian= Polish= Portugues=CentralDeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws -Russian=MangaChanRU,MintMangaRU,NineMangaRU,ReadMangaRU,MangaHubRU +Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation= Thai=MangaBoom From 66bf8f5ca6df35baf5e420f99f513ca722b9326b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 12:37:47 +0300 Subject: [PATCH 2213/2794] MangaOnlineTo, change domain --- baseunits/modules/MangaOnlineTo.pas | 3 ++- config/mangalist.ini | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaOnlineTo.pas b/baseunits/modules/MangaOnlineTo.pas index f7ccad2a1..1223036c3 100644 --- a/baseunits/modules/MangaOnlineTo.pas +++ b/baseunits/modules/MangaOnlineTo.pas @@ -100,7 +100,8 @@ procedure RegisterModule; with AddModule do begin Website := 'MangaOnlineTo'; - RootURL := 'http://mangaonline.to'; + RootURL := 'http://mangaon.net'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index 803e6bb8e..efe16d4f0 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,7 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,Mangaf -English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaOnlineTo,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd +English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=Dynasty-Scans,GameofScanlation,Mangacow,MangaZuki,PsychoPlay French=AnimeStory,Japan-Shin,Japscan,ScanManga From 20fc0b2fa7d874b131819275821ccf42a29aa8a4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Feb 2018 12:48:51 +0300 Subject: [PATCH 2214/2794] add MerakiScans [EN-SC] fixes #787 --- baseunits/modules/WPManga.pas | 18 ++++++++++-------- config/mangalist.ini | 8 ++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas index 0cadf2df3..8b3e3bc9f 100644 --- a/baseunits/modules/WPManga.pas +++ b/baseunits/modules/WPManga.pas @@ -218,13 +218,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; procedure RegisterModule; - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + function AddWebsiteModule(AWebsite, ARootURL, ACategory: String): TModuleContainer; begin Result := AddModule; with Result do begin Website := AWebsite; RootURL := ARootURL; + Category := ACategory; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; @@ -235,13 +236,14 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com'); - AddWebsiteModule('Authrone', 'http://www.authrone.com'); - AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com'); - AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com'); - AddWebsiteModule('MangaCow', 'http://mngcow.co'); - AddWebsiteModule('HentaiRead', 'http://hentairead.com'); - AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com'); + AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com', 'Thai'); + AddWebsiteModule('Authrone', 'http://www.authrone.com', 'English'); + AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', 'English'); + AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', 'H-Sites'); + AddWebsiteModule('MangaCow', 'http://mngcow.co', 'English-Scanlation'); + AddWebsiteModule('HentaiRead', 'http://hentairead.com', 'H-Sites'); + AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com', 'English'); + AddWebsiteModule('MerakiScans', 'http://merakiscans.com', 'English-Scanlation'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index efe16d4f0..628dd182a 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,9 +4,9 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,Mangaf -English=Authrone,Batoto,EatManga,EyeOnManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,MangaDeep,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd +English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=Dynasty-Scans,GameofScanlation,Mangacow,MangaZuki,PsychoPlay +English-Scanlation=Dynasty-Scans,GameofScanlation,MangaZuki,PsychoPlay French=AnimeStory,Japan-Shin,Japscan,ScanManga German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics @@ -17,9 +17,9 @@ Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewTy Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation= -Thai=MangaBoom +Thai= Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing Webcomics=Tapas -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HentaiRead,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Pururin,ReadHentaiManga,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Pururin,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix From f4dbaa344d891fa7c1048716f0aa343799d3093f Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Tue, 13 Feb 2018 14:47:36 +0300 Subject: [PATCH 2215/2794] Update Turkish localization. - Translated latest additions. - Removed "fuzzy" elements. They are just PoEdit reminders. But if they were notifications for me to rework on them, let me know. I didn't see a problem though. --- mangadownloader/languages/fmd.tr_TR.po | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index faa9a5687..48e09c74c 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -356,11 +356,6 @@ msgid "Today" msgstr "Bugün" #: frmmain.rs_webpconvertto -#, fuzzy -#| msgid "" -#| "WebP\n" -#| "PNG\n" -#| "Jpeg\n" msgid "" "WebP\n" "PNG\n" @@ -368,7 +363,7 @@ msgid "" msgstr "" "WebP\n" "PNG\n" -"Jpeg\n" +"JPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -759,7 +754,7 @@ msgstr "Yolda Unicode karakter varsa bunu açın." #: tmainform.cboptiondeletecompletedtasksonclose.caption msgid "Delete completed tasks on close" -msgstr "" +msgstr "Tamamlanmış görevleri kapatırken sil" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -847,7 +842,6 @@ msgid "Use proxy" msgstr "Proxy kullan" #: tmainform.cbpngcompressionlevel.text -#, fuzzy msgctxt "tmainform.cbpngcompressionlevel.text" msgid "Fastest" msgstr "En hızlı" @@ -865,7 +859,6 @@ msgid "Regular Expression" msgstr "Düzenli İfadeler" #: tmainform.cbwebpsaveas.text -#, fuzzy msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" msgstr "PNG" @@ -1201,7 +1194,7 @@ msgstr "Görevi her zaman başarısız bölümlerden başlat" #: tmainform.ckpngsaveasjpeg.caption msgid "Save PNG as JPEG" -msgstr "" +msgstr "PNGyi JPEG olarak kaydet." #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1315,7 +1308,7 @@ msgstr "İndirme kutusu" #: tmainform.gbimageconversion.caption msgid "Image Conversion" -msgstr "" +msgstr "Resim Dönüştürme" #: tmainform.gboptionexternal.caption msgid "External program" @@ -1399,7 +1392,7 @@ msgstr "Başlık" #: tmainform.lbjpegquality.caption msgid "JPEG quality" -msgstr "" +msgstr "JPEG Kalitesi" #: tmainform.lblogfilename.caption msgid "Log file:" @@ -1590,7 +1583,6 @@ msgid "Username" msgstr "Kullanıcı adı" #: tmainform.lbpngcompressionlevel.caption -#, fuzzy msgctxt "tmainform.lbpngcompressionlevel.caption" msgid "PNG Compression level" msgstr "PNG Sıkıştırma seviyesi" @@ -1601,7 +1593,7 @@ msgstr "Şuraya kaydet:" #: tmainform.lbwebpsaveas.caption msgid "Save WebP as" -msgstr "" +msgstr "WebPyi şöyle kaydet" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" From f2cc76c60e17da22a14da251744817664fa47ec8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 20:43:07 +0800 Subject: [PATCH 2216/2794] luahttpsend, rename threadterminated to terminated --- baseunits/lua/LuaHTTPSend.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index d1b8b6c3c..c6d231bbf 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -76,7 +76,7 @@ function http_document(L: Plua_State): Integer; cdecl; ); props: packed array[0..2] of luaL_Reg_prop = ( (name: 'Document'; funcget: @http_document; funcset: nil), - (name: 'ThreadTerminated'; funcget: @http_threadterminated; funcset: nil), + (name: 'Terminated'; funcget: @http_threadterminated; funcset: nil), (name: nil; funcget: nil; funcset: nil) ); From babf95b5f3dca6c737951a38b8412d8af1c8f882 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 21:07:18 +0800 Subject: [PATCH 2217/2794] websiteoptionadvanced, fix empty websites (fix #963) --- .../forms/frmWebsiteOptionAdvanced.pas | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 1f93c8beb..00b71a490 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -290,31 +290,22 @@ procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtual var Data: PNameValue; Node: PVirtualNode; - i, p: Integer; + p: Integer; begin if AVT = nil then Exit; if S = nil then Exit; - S.Clear; - if AvailableWebsites.Count > 0 then + s.Assign(AvailableWebsites); + TStringList(s).Sorted := True; + if s.Count <> 0 then begin - S.BeginUpdate; - try - for i := 0 to AvailableWebsites.Count - 1 do - S.Add(AvailableWebsites.Names[i]); - if AVT.RootNodeCount > 0 then - begin - Node := AVT.GetFirst(); - while Assigned(Node) do - begin - Data := AVT.GetNodeData(Node); - p := S.IndexOf(Data^.Name); - if p > -1 then - S.Delete(p); - Node := AVT.GetNext(Node); - end; - end; - finally - S.EndUpdate; + Node := AVT.GetFirst(); + while Node <> nil do + begin + Data := AVT.GetNodeData(Node); + p := s.IndexOf(Data^.Name); + if p <> - 1 then + s.Delete(p); + Node := AVT.GetNext(Node); end; end; end; From 2a8f0b16a48e44db418f06f15a48f911c52ec197 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 21:09:55 +0800 Subject: [PATCH 2218/2794] websiteioptionadvanced, doesn't need to sort combobox items, they already sorted --- mangadownloader/forms/frmWebsiteOptionAdvanced.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index 00b71a490..df24a9e6d 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -295,7 +295,6 @@ procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtual if AVT = nil then Exit; if S = nil then Exit; s.Assign(AvailableWebsites); - TStringList(s).Sorted := True; if s.Count <> 0 then begin Node := AVT.GetFirst(); From 3a598abe36935301daf5f78589c3bbc590490be1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 21:13:15 +0800 Subject: [PATCH 2219/2794] cleanup --- mangadownloader/forms/frmWebsiteOptionAdvanced.pas | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas index df24a9e6d..2a95b233b 100644 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas @@ -288,7 +288,6 @@ procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: VirtualTrees.TV procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtualStringTree; const S: TStrings); var - Data: PNameValue; Node: PVirtualNode; p: Integer; begin @@ -300,8 +299,7 @@ procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtual Node := AVT.GetFirst(); while Node <> nil do begin - Data := AVT.GetNodeData(Node); - p := s.IndexOf(Data^.Name); + p := s.IndexOf(PNameValue(AVT.GetNodeData(Node))^.Name); if p <> - 1 then s.Delete(p); Node := AVT.GetNext(Node); From 95335ce865cda2c5422dd388f659695fccca6e54 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 21:38:57 +0800 Subject: [PATCH 2220/2794] mainform, clear finished task on close doesn't update the list and some typo --- mangadownloader/forms/frmMain.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c44e12d93..ba4eda435 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1327,7 +1327,7 @@ procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure TMainForm.CloseNow; begin if OptionDeleteCompletedTasksOnClose then - miDownloadDeleteCompletedClick(miDownloadDeleteCompleted); + miDownloadDeleteCompletedClick(nil); isExiting := True; {$ifdef windows} @@ -1408,7 +1408,7 @@ procedure TMainForm.CloseNow; SaveOptions; SaveFormInformation; - Logger.Send(Self.ClassName+'.CloseNow, closSaveFormInformationing other forms'); + Logger.Send(Self.ClassName+'.CloseNow, close other forms'); //embed form if Assigned(AccountManagerForm) then AccountManagerForm.Close; @@ -3325,6 +3325,7 @@ procedure TMainForm.miDownloadDeleteCompletedClick(Sender: TObject); mtConfirmation, [mbYes, mbNo], 0) = mrYes) then Exit; DLManager.RemoveAllFinishedTasks; + if Sender <> nil then UpdateVtDownload; // the reason we put it in here instead of in DLManager because of the size of // download list will change during this method From 6166c28edae4a69cc5bb5127946d37109e60bab9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 22:46:56 +0800 Subject: [PATCH 2221/2794] luabaseunit, added htmldecode, urldecode --- baseunits/lua/LuaBaseUnit.pas | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 259c006a6..333e535ee 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -84,6 +84,18 @@ function lua_regexprgetmatch(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_htmldecode(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, HTMLDecode(lua_tostring(L, 1))); + Result := 1; +end; + +function lua_urldecode(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, URLDecode(lua_tostring(L, 1))); + Result := 1; +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -96,6 +108,8 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'RemoveURLDelim', @lua_removeurldelim); luaPushFunctionGlobal(L, 'RemoveURLDelimLeft', @lua_removeurldelimleft); luaPushFunctionGlobal(L, 'RegExprGetMatch', @lua_regexprgetmatch); + luaPushFunctionGlobal(L, 'HTMLDecode', @lua_htmldecode); + luaPushFunctionGlobal(L, 'URLDecode', @lua_urldecode); end; end. From 1e29e884a619c91eab2f91f6705027d490621afc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 22:55:29 +0800 Subject: [PATCH 2222/2794] luabaseunit, added incstr --- baseunits/lua/LuaBaseUnit.pas | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 333e535ee..bef1cd137 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -96,6 +96,20 @@ function lua_urldecode(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_incstr(L: Plua_State): Integer; cdecl; +var + n: Integer; +begin + n := 1; + if (lua_gettop(L) = 2) and lua_isinteger(L, 2) then + n := lua_tointeger(L, 2); + if lua_isinteger(L, 1) then + lua_pushstring(L, IncStr(lua_tointeger(L, 1), n)) + else + lua_pushstring(L, IncStr(lua_tostring(L, 1), n)); + Result := 1; +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -110,6 +124,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'RegExprGetMatch', @lua_regexprgetmatch); luaPushFunctionGlobal(L, 'HTMLDecode', @lua_htmldecode); luaPushFunctionGlobal(L, 'URLDecode', @lua_urldecode); + luaPushFunctionGlobal(L, 'IncStr', @lua_incstr); end; end. From 515b0c97f0f72f2f69649a830e38d4928b8a1a37 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 23:28:36 +0800 Subject: [PATCH 2223/2794] translate wpmanga to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/WPManga.pas | 252 ---------------------------------- lua/modules/WPManga.lua | 193 ++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 253 deletions(-) delete mode 100644 baseunits/modules/WPManga.pas create mode 100644 lua/modules/WPManga.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index c1b647635..c169de294 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,5 +1,4 @@ uses - WPManga, MangaFox, Mangacan, PecintaKomik, diff --git a/baseunits/modules/WPManga.pas b/baseunits/modules/WPManga.pas deleted file mode 100644 index 8b3e3bc9f..000000000 --- a/baseunits/modules/WPManga.pas +++ /dev/null @@ -1,252 +0,0 @@ -unit WPManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, synacode, RegExpr; - -implementation - -function GetDirURL(const AModule: TModuleContainer): String; -begin - with AModule do - if StringIn(Website, ['MangaSpy', 'MangaIce']) then - Result := 'manga_list' - else - if Website = 'ReadHentaiManga' then - Result := 'hentai-manga-list' - else if Website = 'HentaiRead' then - Result := 'hentai-list' - else - Result := 'manga-list'; - Result := '/' + Result + '/all/any/last-added/'; -end; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; - const Module: TModuleContainer): Integer; -begin - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + GetDirURL(Module)) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := StrToIntDef(ReplaceRegExpr('^.*\/(\d+)/.*$', - XPathString('//ul[@class="pgg"]/li[last()]/a/@href'), '$1', True), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; - const AURL: String; const Module: TModuleContainer): Integer; -begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + GetDirURL(Module) + IncStr(AURL) + '/') then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - if StringIn(Module.Website, ['MangaSpy', 'MangaIce']) then - XPathHREFAll('//*[contains(@id,"content")]//*[@class="det"]/a', ALinks, ANames) - else - XPathHREFtitleAll('//*[contains(@id,"content")]//a[./img]', ALinks, ANames); - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//img[starts-with(@class,"cvr")]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - title := XPathString('//*[@itemprop="itemreviewed"]'); - authors := XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Author")]/substring-after(.," ")'); - artists := XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Artist")]/substring-after(.," ")'); - status := MangaInfoStatusIfPos(XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Status")]/substring-after(.," ")')); - if StringIn(Module.Website, ['ReadHentaiManga', 'HentaiRead']) then - genres := XPathString('string-join(//*[contains(@class,"mng_det")]//*[self::p or self::li]//a,", ")') - else - genres := XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Category")]/string-join((./*[position()>1]),", ")'); - if Module.Website = 'HentaiRead' then - begin - chapterLinks.Add(XPathString('//a[@class="lst"]/@href')); - chapterName.Add(title); - end - else - begin - while True do - begin - for v in XPath('//a[@class="lst"]') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - s := v.toNode.getAttribute('title'); - if s = '' then - s := XPathString('*[@class="val"]', v.toNode); - if s = '' then - s := XPathString('text()[1]', v.toNode); - chapterName.Add(s); - end; - if Thread.IsTerminated then Break; - s := Trim(XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href')); - if s = '' then Break; - if GET(MaybeFillHost(Module.RootURL, s)) then - ParseHTML(Document) - else - Break; - end; - InvertStrings([chapterLinks, chapterName]); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; - v, x: IXQValue; - allnum: Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - Cookies.Values['viewer'] := '1'; - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + '1') then begin - Result := True; - //multi page - with TXQueryEngineHTML.Create(Document) do - try - s := XPathString('//script[contains(.,"imglist")]/substring-after(substring-before(.,"]"),"[")'); - if s <> '' then - s := '[' + s + ']' - else - begin - s := XPathString('//script[contains(.,"img_lst")]/substring-after(substring-before(.,"'')"),"(''")'); - if s <> '' then - s := DecodeURL(s); - end; - ParseHTML(s); - XPathStringAll('json(*)()("url")', PageLinks); - if PageLinks.Count = 0 then - XPathStringAll('json(*)()', PageLinks); - finally - Free; - end; - //single page - if PageLinks.Count = 0 then - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count; - if PageNumber = 0 then - PageNumber := XPath('(//select[@name="page"])[1]/option').Count; - if PageNumber = 0 then - for v in XPath('//select') do - begin - allnum := True; - for x in XPath('option', v.toNode) do - begin - if StrToIntDef(x.toString, -1) = -1 then - begin - allnum := False; - Break; - end; - end; - if allnum then - begin - PageNumber := XPath('option', v.toNode).Count; - Break; - end; - end; - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do - if GET(AppendURLDelim(FillHost(Module.RootURL, AURL)) + IncStr(DownloadThread.WorkId) + '/') then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - if Module.Website = 'ReadHentaiManga' then - s := HTMLDecode(XPathString('//img[@id="main_img"]/@src')) - else - s := XPathString('//*[contains(@class,"mng_rdr")]//img/@src'); - if s = '' then - s := XPathString('//*[@id="reader"]//img[@id="picture"]/@src'); - PageLinks[DownloadThread.WorkId] := s; - finally - Free; - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(AWebsite, ARootURL, ACategory: String): TModuleContainer; - begin - Result := AddModule; - with Result do - begin - Website := AWebsite; - RootURL := ARootURL; - Category := ACategory; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; - end; - -begin - AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com', 'Thai'); - AddWebsiteModule('Authrone', 'http://www.authrone.com', 'English'); - AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', 'English'); - AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', 'H-Sites'); - AddWebsiteModule('MangaCow', 'http://mngcow.co', 'English-Scanlation'); - AddWebsiteModule('HentaiRead', 'http://hentairead.com', 'H-Sites'); - AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com', 'English'); - AddWebsiteModule('MerakiScans', 'http://merakiscans.com', 'English-Scanlation'); -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua new file mode 100644 index 000000000..1dbc2f5f8 --- /dev/null +++ b/lua/modules/WPManga.lua @@ -0,0 +1,193 @@ +function getinfo() + local s = '' + mangainfo.url = MaybeFillHost(module.rooturl, url) + if http.get(mangainfo.url) then + x = TXQuery.Create(http.document) + mangainfo.coverLink = MaybeFillHost(module.rooturl, x.XPathString('//img[starts-with(@class,"cvr")]/@src')) + mangainfo.title = x.XPathString('//*[@itemprop="itemreviewed"]') + mangainfo.authors = x.XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Author")]/substring-after(normalize-space(.)," ")') + mangainfo.artists = x.XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Artist")]/substring-after(normalize-space(.)," ")') + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Status")]/substring-after(normalize-space(.)," ")')) + mangainfo.summary = x.XPathString('//div[@class="det"]/p[1]') + if (module.website == 'ReadHentaiManga') or (module.website == 'HentaiRead') then + mangainfo.genres = x.XPathString('string-join(//*[contains(@class,"mng_det")]//*[self::p or self::li]//a,", ")') + else + mangainfo.genres = x.XPathString('//*[contains(@class,"mng_det")]//*[self::p or self::li][starts-with(.,"Category")]/string-join((./*[position()>1]),", ")') + end + if module.website == 'HentaiRead' then + mangainfo.chapterLinks.Add(x.XPathString('//a[@class="lst"]/@href')) + mangainfo.chapterNames.Add(mangainfo.title) + else + while true do + v = x.XPath('//a[@class="lst"]') + for i = 1, v.count do + v2 = v.get(i) + mangainfo.chapterLinks.Add(v2.getAttribute('href')) + s = v2.getAttribute('title') + if s == '' then + s = x.XPathString('*[@class="val"]', v2) + end + if s == '' then + s = x.XPathString('text()[1]', v2) + end + mangainfo.chapterNames.Add(s) + end + if http.terminated then break end + s = Trim(x.XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href')) + if s == '' then break end + if http.GET(MaybeFillHost(module.rooturl, s)) then + x.ParseHTML(http.Document) + else + break + end + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + end + return no_error + else + return net_problem + end +end + +function getpagenumber() + local s = '' + local allnum = false + http.Cookies.Values['viewer'] = '1' + if http.GET(AppendURLDelim(MaybeFillHost(module.RootURL, url)) .. '1') then + -- multi page + x = TXQuery.Create(http.Document) + s = x.XPathString('//script[contains(.,"imglist")]/substring-after(substring-before(.,"]"),"[")') + if s ~= '' then + s = '[' .. s .. ']' + else + s = x.XPathString('//script[contains(.,"img_lst")]/substring-after(substring-before(.,"\')"),"(\'")') + if s ~= '' then + s = DecodeURL(s) + end + end + x.ParseHTML(s) + x.XPathStringAll('json(*)()("url")', task.PageLinks) + if task.PageLinks.Count == 0 then + x.XPathStringAll('json(*)()', task.PageLinks) + end + + -- single page + if task.PageLinks.Count == 0 then + x.ParseHTML(http.Document) + task.PageNumber = x.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count + if task.PageNumber == 0 then + task.PageNumber = x.XPath('(//select[@name="page"])[1]/option').Count + end + if task.PageNumber == 0 then + v = x.XPath('//select') + for i = 1, v.count do + allnum = true + v2 = x.XPath('option', v.get(i)) + for i = 1, v2.count do + if tointeger(v2.toString) == -1 then + allnum = false + break + end + end + if allnum then + task.PageNumber = x.XPath('option', v).Count + break + end + end + end + end + return true + else + return false + end +end + +function getimageurl() + local s = '' + if http.GET(AppendURLDelim(MaybeFillHost(module.RootURL, url)) .. IncStr(workid) .. '/') then + x = TXQuery.Create(http.Document) + if module.Website == 'ReadHentaiManga' then + s = HTMLDecode(x.XPathString('//img[@id="main_img"]/@src')) + else + s = x.XPathString('//*[contains(@class,"mng_rdr")]//img/@src') + end + if s == '' then + s = x.XPathString('//*[@id="reader"]//img[@id="picture"]/@src') + end + task.PageLinks[workid] = s + return true + else + return false + end +end + +function getdirurl(website) + if (website == 'MangaSpy') or (website == 'MangaIce') then + return 'manga_list' + elseif (website == 'ReadHentaiManga') then + return 'hentai-manga-list' + elseif (website == 'HentaiRead') then + return 'hentai-list' + else + return 'manga-list' + end +end + +function getdirectorypagenumber() + if http.GET(AppendURLDelim(module.RootURL) .. getdirurl(module.website)) then + x = TXQuery.Create(http.Document) + page = ReplaceRegExpr('^.*\\/(\\d+)/.*$', x.XPathString('//ul[@class="pgg"]/li[last()]/a/@href'), '$1').tointeger + if page == nil then + page = 1 + end + return true + else + return false + end +end + +function getnameandlink() + if http.GET(AppendURLDelim(module.RootURL) .. getdirurl(module.website) .. IncStr(AURL) .. '/') then + x = TXQuery.Create(http.Document) + if (module.website == 'MangaSpy') or (module.website == 'MangaIce') then + x.XPathHREFAll('//*[contains(@id,"content")]//*[@class="det"]/a', links, names) + else + x.XPathHREFtitleAll('//*[contains(@id,"content")]//a[./img]', links, names); + end + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(name, url, category) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = category + m.lastupdated = 'February 13, 2018' + m.sortedlist = true + m.OnGetInfo = 'getinfo' + m.OnGetPageNumber = 'getpagenumber' + m.OnGetImageURL = 'getimageurl' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + m.OnGetNameAndLink = 'getnameandlink' + return m +end + +function Init() + AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com', 'Thai') + + local cat = 'English' + AddWebsiteModule('Authrone', 'http://www.authrone.com', cat) + AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', cat) + AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com', cat) + + cat = 'H-Sites' + AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', cat) + AddWebsiteModule('HentaiRead', 'http://hentairead.com', cat) + + cat = 'English-Scanlation' + AddWebsiteModule('MangaCow', 'http://mngcow.co', cat) + AddWebsiteModule('MerakiScans', 'http://merakiscans.com', cat) +end From df4906f5a61951dc3a318ac536bb72d1c744f784 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 13 Feb 2018 23:35:45 +0800 Subject: [PATCH 2224/2794] Bump version 0.9.139.0 --- changelog.txt | 11 ++++++++++- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index ff3835050..acc085ab8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,16 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.138.0 (14-02-2018) +0.9.139.0 (13-02-2018) +[+] Added SelfMangaRU [RU] +[+] Added MerakiScans [EN-SC] +[*] MangaOnlineTo, change domain +[*] Update Turkish localization +[*] Fixed empty website selection in advanced website options +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.138.0...0.9.139.0 + +0.9.138.0 (13-02-2018) [+] Added option to delete completed task on close [+] Added option to convert PNG images to JPEG [+] Added NeuManga [ID] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 545af5caf..761fb1dd2 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="138"/> + <RevisionNr Value="139"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 641305df3..b768961d0 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.138.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.138.0/fmd_0.9.138.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.138.0/fmd_0.9.138.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.138.0/fmd_0.9.138.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.138.0/fmd_0.9.138.0_Win64.7z +VERSION=0.9.139.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.139.0/fmd_0.9.139.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.139.0/fmd_0.9.139.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.139.0/fmd_0.9.139.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.139.0/fmd_0.9.139.0_Win64.7z From 1c94a4e02ac6e8441351eba22aa83c5d5529ce23 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 07:34:45 +0800 Subject: [PATCH 2225/2794] added seotterscans [EN-SC] (closed #969) --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 48a42e23c..d6619906b 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -208,6 +208,7 @@ function Init() AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com', cat) AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today', cat) AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com', cat) + AddWebsiteModule('SeaOtterScans', 'https://reader.seaotterscans.com', cat) -- es-sc cat = 'Spanish-Scanlation' From ec019cc7b13ea367f34b004d1f6f0c3ee9aa66a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 12:33:13 +0800 Subject: [PATCH 2226/2794] added manga.sh, no manga list yet (#900) --- lua/modules/Manga.sh.lua | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 lua/modules/Manga.sh.lua diff --git a/lua/modules/Manga.sh.lua b/lua/modules/Manga.sh.lua new file mode 100644 index 000000000..c0e9103d8 --- /dev/null +++ b/lua/modules/Manga.sh.lua @@ -0,0 +1,74 @@ +apiurl='https://api.manga.sh/api/v1/' +cdnurl='https://cdn.manga.sh/' + +function getinfo() + local lid=RegExprGetMatch('/(\\d+)',url,1) + local lurl=MaybeFillHost(module.RootURL, apiurl..'series?query=Id:'..lid) + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(lurl) then + x=TXQuery.Create(http.document) + v=x.xpath('json(*).response(1)') + mangainfo.title=x.xpathstring('Name', v) + mangainfo.coverlink=x.xpathstring('CoverImage', v) + if mangainfo.coverlink ~= '' then + mangainfo.coverlink=cdnurl..'covers/'..mangainfo.coverlink + end + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('Status/Name', v)) + mangainfo.genres=x.xpathstring('string-join((TypeName,TypeDemonym,SeriesTags/TagName),", ")', v) + mangainfo.summary=HTMLDecode(x.xpathstring('Description', v)) + if http.get(apiurl..'series_chapters?query=SeriesId.Id:'..lid..'&order=desc&sortby=TimeUploaded&limit=0&offset=0') then + x.parsehtml(http.document) + local s='json(.)("response")()' + local lname='' + local showalllang=module.getoption('showalllang') + local showscangroup=module.getoption('showscangroup') + if not showalllang then + s=s..'[ChapterLanguage/Name = "English"]' + end + v=x.xpath(s) + for i=1,v.count do + v2=v.get(i) + lname=x.xpathstring('concat("Vol.",VolumeNumber," Ch.",ChapterNumberAbsolute," ",ChapterNumberVolume)', v2) + if showalllang then + s=x.xpathstring('ChapterLanguage/Name',v2) + if s~='' then lname=lname..' ['..s..']' end + end + if showscangroup then + s=x.xpathstring('string-join(SeriesChaptersGroups/GroupName,", ")',v2) + if s~='' then lname=lname..' ['..s..']' end + end + mangainfo.chapterlinks.add(x.xpathstring('Hash', v2)) + mangainfo.chapternames.add(lname) + end + return no_error + else + return net_problem + end + else + return net_error + end +end + +function getpagenumber() + if http.get(apiurl..'series_chapters/'..RemoveURLDelimLeft(url)) then + TXQuery.Create(http.Document).xpathstringall('json(.)/response/SeriesChaptersFiles/Name',task.pagelinks) + for i=0,task.pagelinks.count-1 do + task.pagelinks[i]=cdnurl..task.pagelinks[i] + end + return true + else + return false + end + return true +end + +function Init() + m=NewModule() + m.website='Manga.sh' + m.rooturl='https://manga.sh' + m.lastupdated='February 14, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.addoptioncheckbox('showalllang', 'Show all language', false) + m.addoptioncheckbox('showscangroup', 'Show scanlation group', false) +end From 2aa75fd3ce16af25ef9c2108c1664695ac29a514 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 13:01:06 +0800 Subject: [PATCH 2227/2794] fix skip non-existent module (closed #971) --- baseunits/uBaseUnit.pas | 26 +++++++++++++++----------- baseunits/uData.pas | 6 +++++- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index d194f37b3..cfcc38d8d 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -486,12 +486,12 @@ procedure CheckPath(const S: String); function LocateMangaSiteID(const URL: String): Integer; function GetMangaSiteID(const Name: String): Integer; -function GetMangaSiteName(const ID: Cardinal): String; +function GetMangaSiteName(const ID: Integer): String; function GetMangaSiteRoot(const Website: String): String; overload; -function GetMangaSiteRoot(const MangaID: Cardinal): String; overload; +function GetMangaSiteRoot(const MangaID: Integer): String; overload; function GetMangaDatabaseURL(const AWebsite: String): String; -function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; +function SitesMemberOf(const website: String; MangaSiteIDs: array of Integer): Boolean; function SitesWithSortedList(const website: String): Boolean; function SitesWithoutFavorites(const website: String): Boolean; // Return true if the website doesn't contain manga information @@ -503,7 +503,7 @@ function SitesWithSingleChapter(const website: String): Boolean; function FillURLProtocol(const AProtocol, AURL: String): String; // Fill in website host if it's not present -function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; overload; +function FillMangaSiteHost(const MangaID: Integer; URL: String): String; overload; function FillMangaSiteHost(const Website, URL: String): String; overload; // modify url @@ -978,9 +978,10 @@ function GetMangaSiteID(const Name: String): Integer; Result := -1; end; -function GetMangaSiteName(const ID: Cardinal): String; +function GetMangaSiteName(const ID: Integer): String; begin - if ID > High(WebsiteRoots) then Exit(''); + if (ID < Low(WebsiteRoots)) or (ID > High(WebsiteRoots)) then + Exit(''); Result := WebsiteRoots[ID, 0]; end; @@ -994,8 +995,10 @@ function GetMangaSiteRoot(const Website: String): String; Result := ''; end; -function GetMangaSiteRoot(const MangaID: Cardinal): String; +function GetMangaSiteRoot(const MangaID: Integer): String; begin + if (MangaID < Low(WebsiteRoots)) or (MangaID > High(WebsiteRoots)) then + Exit(''); Result := WebsiteRoots[MangaID, 1]; end; @@ -1010,7 +1013,7 @@ function GetMangaDatabaseURL(const AWebsite: String): String; Result := Result + AWebsite; end; -function SitesMemberOf(const website: String; MangaSiteIDs: array of Cardinal): Boolean; +function SitesMemberOf(const website: String; MangaSiteIDs: array of Integer): Boolean; var i: Integer; begin @@ -1093,11 +1096,12 @@ function FillURLProtocol(const AProtocol, AURL: String): String; end; end; -function FillMangaSiteHost(const MangaID: Cardinal; URL: String): String; +function FillMangaSiteHost(const MangaID: Integer; URL: String): String; begin Result := URL; - if MangaID <= High(WebsiteRoots) then - Result := FillHost(WebsiteRoots[MangaID, 1], URL); + if (MangaID < Low(WebsiteRoots)) or (MangaID > High(WebsiteRoots)) then + Exit; + Result := FillHost(WebsiteRoots[MangaID, 1], URL); end; function FillMangaSiteHost(const Website, URL: String): String; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 4a225c133..c093995cb 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -820,6 +820,8 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: else begin MangaSiteID := GetMangaSiteID(AWebsite); + if MangaSiteID = -1 then + Exit(INFORMATION_NOT_FOUND); Source := TStringList.Create; if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber @@ -897,6 +899,8 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; else begin MangaSiteID := GetMangaSiteID(AWebsite); + if MangaSiteID = -1 then + Exit(INFORMATION_NOT_FOUND); Source := TStringList.Create; if MangaSiteID = VNSHARING_ID then Result := VnSharingGetNamesAndLinks @@ -1016,7 +1020,7 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR else begin MangaSiteID := GetMangaSiteID(AWebsite); - if MangaSiteID > High(WebsiteRoots) then + if MangaSiteID = -1 then Exit(INFORMATION_NOT_FOUND); mangaInfo.url := FillMangaSiteHost(MangaSiteID, AURL); Source := TStringList.Create; From 15508017019e78516a8e65703bf01ad063a525f0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 13:05:39 +0800 Subject: [PATCH 2228/2794] Bump version 0.9.140.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index acc085ab8..188755412 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.140.0 (14-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.139.0...0.9.140.0 + 0.9.139.0 (13-02-2018) [+] Added SelfMangaRU [RU] [+] Added MerakiScans [EN-SC] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 761fb1dd2..93ab69cfb 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="139"/> + <RevisionNr Value="140"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index b768961d0..26a03996c 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.139.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.139.0/fmd_0.9.139.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.139.0/fmd_0.9.139.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.139.0/fmd_0.9.139.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.139.0/fmd_0.9.139.0_Win64.7z +VERSION=0.9.140.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0_Win64.7z From 54dbb656f3b485e79e86b948e8eef15bb7f2c62c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 14 Feb 2018 10:22:51 +0300 Subject: [PATCH 2229/2794] cleanup --- .../JapanShin/chapter_page_number.inc | 27 ------- .../JapanShin/directory_page_number.inc | 44 ---------- baseunits/includes/JapanShin/image_url.inc | 37 --------- .../includes/JapanShin/manga_information.inc | 81 ------------------- .../includes/JapanShin/names_and_links.inc | 41 ---------- 5 files changed, 230 deletions(-) delete mode 100644 baseunits/includes/JapanShin/chapter_page_number.inc delete mode 100644 baseunits/includes/JapanShin/directory_page_number.inc delete mode 100644 baseunits/includes/JapanShin/image_url.inc delete mode 100644 baseunits/includes/JapanShin/manga_information.inc delete mode 100644 baseunits/includes/JapanShin/names_and_links.inc diff --git a/baseunits/includes/JapanShin/chapter_page_number.inc b/baseunits/includes/JapanShin/chapter_page_number.inc deleted file mode 100644 index 37da789c1..000000000 --- a/baseunits/includes/JapanShin/chapter_page_number.inc +++ /dev/null @@ -1,27 +0,0 @@ - function GetJapanShinPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(JAPANSHIN_ID, URL), - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - //class="tbtitle dropdown_parent dropdown_right - for i := 0 to parse.Count - 1 do - if (Pos('onClick="changePage', parse[i]) > 0) and - (Pos('return false', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/JapanShin/directory_page_number.inc b/baseunits/includes/JapanShin/directory_page_number.inc deleted file mode 100644 index af4644cf8..000000000 --- a/baseunits/includes/JapanShin/directory_page_number.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetJapanShinDirectoryPageNumber: Byte; - var - i, p: Cardinal; - regx: TRegExpr; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[JAPANSHIN_ID, 1] + - JAPANSHIN_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - APage := 0; - regx := TRegExpr.Create; - regx.Expression := '^.*/reader/list/(\d+)/.*$'; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="gbutton fright"', parse[i]) > 0) and - (Pos('/reader/list/', parse[i]) > 0) then - begin - Result := NO_ERROR; - p := StrToIntDef(regx.Replace(parse[i], '$1', True), 0); - if p > APage then - APage := p; - end; - end; - regx.Free; - Source.Free; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/JapanShin/image_url.inc b/baseunits/includes/JapanShin/image_url.inc deleted file mode 100644 index 323927b74..000000000 --- a/baseunits/includes/JapanShin/image_url.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetJapanShinImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(JAPANSHIN_ID, URL) + '/page/' + IntToStr(WorkId), - Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and - (Pos('class="open"', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := - GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/JapanShin/manga_information.inc b/baseunits/includes/JapanShin/manga_information.inc deleted file mode 100644 index a61208c4f..000000000 --- a/baseunits/includes/JapanShin/manga_information.inc +++ /dev/null @@ -1,81 +0,0 @@ - function GetJapanShinInfoFromURL: Byte; - var - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[JAPANSHIN_ID, 0]; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), FillMangaSiteHost(JAPANSHIN_ID, AURL), AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - mangaInfo.numChapter := 0; - for i := 0 to parse.Count - 1 do - begin - //get title - if (Pos('h1 class="title"', parse[i]) > 0) then - mangaInfo.title := Trim(parse[i + 1]); - - //get coverlink - if (Pos('class="thumbnail"', parse[i]) > 0) then - begin - j := i + 1; - while (Pos('<img', parse[j]) = 0) do - Inc(j); - mangaInfo.coverLink := GetVal(parse[j], 'src'); - end; - - //get authors - if (Pos('Auteur :', parse[i]) > 0) then - mangaInfo.authors := parse[i + 2]; - - //get genre - if (Pos('Genre :', parse[i]) > 0) then - mangaInfo.genres := parse[i + 2]; - - //get summary - if (Pos('Synopsis :', parse[i]) > 0) then - mangaInfo.summary := parse[i + 2]; - - //get chapter name and links - if (Pos('href="', parse[i]) > 0) and - (Pos('title="', parse[i]) > 0) and - (Pos('/reader/read/', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[JAPANSHIN_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(Trim(parse[i + 1])); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/JapanShin/names_and_links.inc b/baseunits/includes/JapanShin/names_and_links.inc deleted file mode 100644 index 994880ee5..000000000 --- a/baseunits/includes/JapanShin/names_and_links.inc +++ /dev/null @@ -1,41 +0,0 @@ - function JapanShinGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), - WebsiteRoots[JAPANSHIN_ID, 1] + JAPANSHIN_BROWSER + - IntToStr(StrToInt(AURL) + 1) + '/', - 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) > 0) and - (Pos('/reader/series/', parse[i]) > 0) and - (Pos('title="', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := GetVal(parse[i], 'href'); - ALinks.Add(StringReplace(s, WebsiteRoots[JAPANSHIN_ID, 1], '', [rfIgnoreCase])); - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - ANames.Add(s); - end; - end; - Source.Free; - end; From 4d4e27aa5a4733be6754a50fd23d72c84919fa54 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 18:06:54 +0800 Subject: [PATCH 2230/2794] fix restore forms --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index ba4eda435..f964a9e9e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1803,11 +1803,11 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); AddToAboutStatus('Modules', IntToStr(Modules.Count)); // load configfile - LoadFormInformation; CollectLanguagesFromFiles; LoadMangaOptions; LoadOptions; ApplyOptions; + LoadFormInformation; if not cbOptionMinimizeOnStart.Checked then Self.Show; From be9eb3273635cef00ea2312bc66a7f9bd51e53b8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 18:16:11 +0800 Subject: [PATCH 2231/2794] cleanup mainform --- mangadownloader/forms/frmMain.lfm | 5 ----- mangadownloader/forms/frmMain.pas | 1 - 2 files changed, 6 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 273283b34..dcc4128f6 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -8,7 +8,6 @@ object MainForm: TMainForm ClientHeight = 587 ClientWidth = 771 Color = clWindow - Menu = MainMenu1 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy @@ -7081,8 +7080,4 @@ object MainForm: TMainForm 0000FFFFFF00FFFFFF00FFFFFF00 } end - object MainMenu1: TMainMenu - left = 224 - top = 323 - end end diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f964a9e9e..69d4adb58 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -98,7 +98,6 @@ TMainForm = class(TForm) lbOptionFilenameCustomRename: TLabel; lbOptionMangaCustomRenameHint: TLabel; lbOptionMangaCustomRename: TLabel; - MainMenu1: TMainMenu; MenuItem10: TMenuItem; MenuItem11: TMenuItem; miFavoritesRename: TMenuItem; From 24f94dbd51bf278261e9d7012cfb189b43fe597b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 14 Feb 2018 13:45:22 +0300 Subject: [PATCH 2232/2794] Pururin, move to lua, change domain --- baseunits/ModuleList.inc | 1 - baseunits/modules/Pururin.pas | 106 ---------------------------------- config/mangalist.ini | 2 +- lua/modules/Pururin.lua | 64 ++++++++++++++++++++ 4 files changed, 65 insertions(+), 108 deletions(-) delete mode 100644 baseunits/modules/Pururin.pas create mode 100644 lua/modules/Pururin.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index c169de294..1cb4d543e 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -81,5 +81,4 @@ uses HentaiCafe, Hentai2Read, HentaiFox, - Pururin, MyReadingManga; diff --git a/baseunits/modules/Pururin.pas b/baseunits/modules/Pururin.pas deleted file mode 100644 index 19abe05cb..000000000 --- a/baseunits/modules/Pururin.pas +++ /dev/null @@ -1,106 +0,0 @@ -unit Pururin; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr; - -implementation - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL) then - begin - Result := NO_ERROR; - Page := StrToIntDef(XPathString('//*[@class="pagination"]/li[last()-1]', MangaInfo.FHTTP.Document), 1); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/browse/newest?page=' + IncStr(AURL)) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//*[@class="gallery-listing"]/*[@class="row"]/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('.//*[@class="title"]/text()[1]', v)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]//img/@src')); - if title = '' then title := XPathString('//*[@class="gallery-info"]//*[@class="title"]'); - artists := XPathString('//*[@class="gallery-info"]//*[@class="table"]//tr/td[starts-with(.,"Artist")]/following-sibling::td[1]/string-join(.//a,", ")'); - genres := XPathString('//*[@class="gallery-info"]//*[@class="table"]/string-join(.//tr/td//a,", ")'); - chapterLinks.Add(XPathString('//a[@class="read-more"]/@href')); - chapterName.Add(title); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - XPathStringAll('json(//script[contains(.,"var chapters")]/substring-before(substring-after(.,"= "),";"))//image', Document, PageLinks); - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'Pururin'; - RootURL := 'https://www.pururin.us'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/config/mangalist.ini b/config/mangalist.ini index 628dd182a..19802d27b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -21,5 +21,5 @@ Thai= Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing Webcomics=Tapas -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Pururin,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix diff --git a/lua/modules/Pururin.lua b/lua/modules/Pururin.lua new file mode 100644 index 000000000..17a95bde0 --- /dev/null +++ b/lua/modules/Pururin.lua @@ -0,0 +1,64 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//*[@class="gallery-info"]//*[@class="title"]') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//*[@class="cover"]//img/@src')) + mangainfo.artists = x.XPathString('//*[@class="gallery-info"]//*[@class="table"]//tr/td[starts-with(.,"Artist")]/following-sibling::td[1]/string-join(.//a,", ")') + mangainfo.genres = x.XPathString('//*[@class="gallery-info"]//*[@class="table"]/string-join(.//tr/td//a,", ")') + mangainfo.chapterlinks.add(x.XPathString('//a[@class="read-more"]/@href')) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_error + end +end + +function GetPageNumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + x.XPathStringAll('json(//script[contains(.,"var chapters")]/substring-before(substring-after(.,"= "),";"))//image', task.pagelinks) + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/browse/newest?page='..IncStr(url)) then + x=TXQuery.Create(http.Document) + v=x.xpath('//*[@class="gallery-listing"]/*[@class="row"]/a') + for i=1,v.count do + v1 = v.get(i) + links.add(v1.getAttribute('href')) + names.add(x.xpathstring('.//*[@class="title"]/text()[1]', v1)) + end + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL) then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//*[@class="pagination"]/li[last()-1]')) + if page == nil then page = 1 end + return true + else + return false + end +end + +function Init() + m=NewModule() + m.category='H-Sites' + m.website='Pururin' + m.rooturl='http://pururin.io' + m.sortedlist=true + m.lastupdated='February 14, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' +end \ No newline at end of file From e1e63dd7508d7437df5055208fa52f5eb868767a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 14 Feb 2018 15:08:50 +0300 Subject: [PATCH 2233/2794] WPManga, fix --- lua/modules/WPManga.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 1dbc2f5f8..bf8ba457b 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -122,21 +122,23 @@ function getimageurl() end function getdirurl(website) + local result = '' if (website == 'MangaSpy') or (website == 'MangaIce') then - return 'manga_list' + result = 'manga_list' elseif (website == 'ReadHentaiManga') then - return 'hentai-manga-list' + result = 'hentai-manga-list' elseif (website == 'HentaiRead') then - return 'hentai-list' + result = 'hentai-list' else - return 'manga-list' + result = 'manga-list' end + return '/' .. result .. '/all/any/last-added/' end function getdirectorypagenumber() if http.GET(AppendURLDelim(module.RootURL) .. getdirurl(module.website)) then x = TXQuery.Create(http.Document) - page = ReplaceRegExpr('^.*\\/(\\d+)/.*$', x.XPathString('//ul[@class="pgg"]/li[last()]/a/@href'), '$1').tointeger + page = tonumber(ReplaceRegExpr('^.*\\/(\\d+)/.*$', x.XPathString('//ul[@class="pgg"]/li[last()]/a/@href'), '$1')) if page == nil then page = 1 end @@ -147,9 +149,9 @@ function getdirectorypagenumber() end function getnameandlink() - if http.GET(AppendURLDelim(module.RootURL) .. getdirurl(module.website) .. IncStr(AURL) .. '/') then + if http.GET(AppendURLDelim(module.RootURL) .. getdirurl(module.website) .. IncStr(url) .. '/') then x = TXQuery.Create(http.Document) - if (module.website == 'MangaSpy') or (module.website == 'MangaIce') then + if (module.website == 'MangaSpy') or (module.website == 'MangaIce') or (module.website == 'MangaDeep') then x.XPathHREFAll('//*[contains(@id,"content")]//*[@class="det"]/a', links, names) else x.XPathHREFtitleAll('//*[contains(@id,"content")]//a[./img]', links, names); From 83c2efae741fa5d23f12c7ddb3894b3e4205b084 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 14 Feb 2018 21:00:33 +0800 Subject: [PATCH 2234/2794] httpsendthread, add common formatbytesize --- baseunits/httpsendthread.pas | 38 +++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 858457efa..406845954 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -110,6 +110,8 @@ function MaybeEncodeURL(const AValue: String): String; procedure SplitURL(const AURL: String; const AHost, APath: PString; const AIncludeProtocol: Boolean = True; const AIncludePort: Boolean = True); +function FormatByteSize(const ABytes: Integer; AShowPerSecond: Boolean = False): String; + const UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; UserAgentCURL = 'curl/7.52.1'; @@ -233,6 +235,40 @@ procedure cleanuri(var u:string); if Assigned(APath) then APath^:=ipath; end; +function FormatByteSize(const ABytes: Integer; AShowPerSecond: Boolean): String; +const + B = 1; + KB = 1024 * B; + MB = 1024 * KB; + GB = 1024 * MB; +begin + if ABytes > GB then + Result := FormatFloat('#.## GB', ABytes / GB) + else + if ABytes > MB then + Result := FormatFloat('#.## MB', ABytes / MB) + else + if ABytes > KB then + Result := FormatFloat('#.## KB', ABytes / KB) + else + if ABytes = 0 then + begin + if AShowPerSecond then + Result := '0 B' + else + Result := '0 Bytes'; + end + else + begin + if AShowPerSecond then + Result := FormatFloat('#.## B', ABytes) + else + Result := FormatFloat('#.## Bytes', ABytes); + end; + if AShowPerSecond then + Result := Result + 'ps'; +end; + function KeyVal(const AKey, AValue: String): TKeyValuePair; begin Result[0] := AKey; @@ -683,4 +719,4 @@ finalization ALLHTTPSendThread.Free; DoneCriticalsection(CS_ALLHTTPSendThread); -end. +end. \ No newline at end of file From 891800a0025353415978501a200887c815f3e0af Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 00:17:13 +0800 Subject: [PATCH 2235/2794] added self databases updater --- baseunits/DBUpdater.pas | 328 +++++++++++++++++++++++++ baseunits/FMDOptions.pas | 3 + baseunits/FMDVars.pas | 5 +- mangadownloader/forms/frmMain.pas | 59 ++--- mangadownloader/languages/fmd.de.po | 40 +++ mangadownloader/languages/fmd.el_GR.po | 40 +++ mangadownloader/languages/fmd.en.po | 40 +++ mangadownloader/languages/fmd.es.po | 40 +++ mangadownloader/languages/fmd.id_ID.po | 40 +++ mangadownloader/languages/fmd.pl_PL.po | 40 +++ mangadownloader/languages/fmd.po | 38 +++ mangadownloader/languages/fmd.pt_BR.po | 40 +++ mangadownloader/languages/fmd.ru_RU.po | 40 +++ mangadownloader/languages/fmd.tr_TR.po | 40 +++ mangadownloader/md.lpi | 6 +- 15 files changed, 768 insertions(+), 31 deletions(-) create mode 100644 baseunits/DBUpdater.pas diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas new file mode 100644 index 000000000..ec869d842 --- /dev/null +++ b/baseunits/DBUpdater.pas @@ -0,0 +1,328 @@ +unit DBUpdater; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, httpsendthread, BaseThread, FMDOptions, process, ComCtrls, Controls, + Dialogs, StdCtrls, Buttons, blcksock; + +type + + { TDBUpdaterThread } + + TDBUpdaterThread = class(TBaseThread) + private + FStatusBar: TStatusBar; + FProgressBar: TProgressBar; + FButtonCancel: TSpeedButton; + FHTTP: THTTPSendThread; + FTotalSize: Integer; + FCurrentSize: Integer; + FCurrentName: String; + FFailedList: TStringList; + FCurrentId: Integer; + protected + procedure ButtonCancelClick(Sender: TObject); + procedure HTTPSockOnStatus(Sender: TObject; Reason: THookSocketReason; + const Value: String); + protected + procedure SyncStart; + procedure SyncFinal; + procedure SyncStartDownload; + procedure SyncUpdateProgress; + procedure SyncUpdateStatus; + procedure SyncUpdateHint; + procedure SyncShowFailed; + procedure SyncCloseUsed; + procedure SyncReopenUsed; + procedure SyncRemoveAttached; + procedure Execute; override; + public + Items: TStringList; + constructor Create; + destructor Destroy; override; + procedure UpdateStatus; // should be called from mainthread + end; + +resourcestring + RS_Downloading = 'Downloading %s'; + RS_FailedItemsTitle = 'Failed'; + RS_FailedItems = 'Failed to finish:'#13#10#13#10'%s'; + RS_FailedDownload = '%s: %d %s'; + RS_FailedToSave = '%s: failed to save'; + RS_MissingZipExe = '%s: Missing %s'; + RS_FailedExtract = '%s: failed to extract, exitstatus = %d'; + RS_ButtonCancel = 'Cancel'; + +implementation + +uses FMDVars; + +function GetDBURL(const AName: String): String; +begin + if Pos('<website>', AnsiLowerCase(DBDownloadURL)) <> -1 then + Result := StringReplace(DBDownloadURL, '<website>', AName, [rfIgnoreCase, rfReplaceAll]) + else + Result := AName; +end; + +{ TDBUpdaterThread } + +procedure TDBUpdaterThread.ButtonCancelClick(Sender: TObject); +begin + Self.Terminate; +end; + +procedure TDBUpdaterThread.HTTPSockOnStatus(Sender: TObject; + Reason: THookSocketReason; const Value: String); +begin + if Terminated then + Exit; + if FHTTP.Headers.IndexOfName('Content-Length') <> -1 then + FTotalSize := StrToIntDef(FHTTP.Headers.Values['Content-Length'], 0); + case Reason of + HR_Connect: FCurrentSize := 0; + HR_ReadCount: + Inc(FCurrentSize, StrToIntDef(Value, 0)); + end; + Synchronize(@SyncUpdateProgress); +end; + +procedure TDBUpdaterThread.SyncStart; +begin + DBUpdaterThread := Self; + + FStatusBar := TStatusBar.Create(FormMain); + with FStatusBar do + begin + Parent := FormMain; + SimplePanel := False; + with Panels.Add do // panel for progress bar + Width := 100; + Panels.Add; // panel for progress text + Panels.Add; // panel for status text + end; + + FProgressBar := TProgressBar.Create(FormMain); + with FProgressBar do + begin + Parent := FStatusBar; + Align := alNone; + Smooth := True; + Style := pbstNormal; + Min := 0; + Width := FStatusBar.Panels[0].Width - 10; + Anchors := [akTop, akLeft, akBottom]; + AnchorSideTop.Control := FStatusBar; + AnchorSideTop.Side := asrTop; + AnchorSideLeft.Control := FStatusBar; + AnchorSideLeft.Side := asrTop; + AnchorSideBottom.Control := FStatusBar; + AnchorSideBottom.Side := asrBottom; + BorderSpacing.Top := 2; + BorderSpacing.Left := 5; + BorderSpacing.Bottom := 2; + end; + + FButtonCancel := TSpeedButton.Create(FormMain); + with FButtonCancel do + begin + Parent := FStatusBar; + Align := alNone; + AutoSize := True; + Caption := RS_ButtonCancel; + ShowCaption := True; + Flat := True; + Anchors := [akTop,akRight,akBottom]; + AnchorSideTop.Control := FStatusBar; + AnchorSideTop.Side := asrTop; + AnchorSideRight.Control := FStatusBar; + AnchorSideRight.Side:= asrRight; + AnchorSideBottom.Control := FStatusBar; + AnchorSideBottom.Side := asrBottom; + BorderSpacing.Top := 2; + BorderSpacing.Right := 5; + BorderSpacing.Bottom := 2; + OnClick := @ButtonCancelClick; + end; +end; + +procedure TDBUpdaterThread.SyncFinal; +begin + FHTTP.Sock.OnStatus := nil; + FreeAndNil(FStatusBar); + FreeAndNil(FProgressBar); + FreeAndNil(FButtonCancel); + DBUpdaterThread := nil; +end; + +procedure TDBUpdaterThread.SyncStartDownload; +begin + FCurrentSize := 0; + FTotalSize := 0; + FProgressBar.Max := 0; + FProgressBar.Position := 0; + FStatusBar.Panels[1].Text := ''; + FStatusBar.Panels[1].Width := 0; + SyncUpdateStatus; +end; + +procedure TDBUpdaterThread.SyncUpdateProgress; +var + s: String; +begin + if FStatusBar = nil then + Exit; + if FProgressBar.Max <> FTotalSize then + FProgressBar.Max := FTotalSize; + if FProgressBar.Position <> FCurrentSize then + FProgressBar.Position := FCurrentSize; + + s := FormatByteSize(FCurrentSize) + '/' + FormatByteSize(FTotalSize); + FStatusBar.Panels[1].Width := FStatusBar.Canvas.TextWidth(s) + 10; + FStatusBar.Panels[1].Text := s; +end; + +procedure TDBUpdaterThread.SyncUpdateStatus; +begin + FStatusBar.Panels[2].Text := + Format('[%d/%d] ' + RS_Downloading, [FCurrentId + 1, Items.Count, + FCurrentName + DBDATA_EXT]); +end; + +procedure TDBUpdaterThread.SyncUpdateHint; +begin + FStatusBar.Hint := Trim(Items.Text); +end; + +procedure TDBUpdaterThread.SyncShowFailed; +begin + MessageDlg(RS_FailedItemsTitle, Format(RS_FailedItems, [FFailedList.Text]), + mtError, [mbOK], 0); +end; + +procedure TDBUpdaterThread.SyncCloseUsed; +begin + FormMain.edMangaListSearch.Clear; + FormMain.vtMangaList.Clear; + dataProcess.Close; +end; + +procedure TDBUpdaterThread.SyncReopenUsed; +begin + FormMain.OpenDataDB(FCurrentName); +end; + +procedure TDBUpdaterThread.SyncRemoveAttached; +begin + dataProcess.RemoveFilter; +end; + +procedure TDBUpdaterThread.Execute; +var + currentfilename: String; + cont: Boolean; + used: Boolean; +begin + FCurrentId := 0; + Synchronize(@SyncUpdateHint); + while FCurrentId < Items.Count do + begin + if Terminated then + Break; + try + FCurrentName := Items[FCurrentId]; + Synchronize(@SyncStartDownload); + if FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300) then // should be success + begin + // save to data folder + currentfilename := DATA_FOLDER + FCurrentName + DBDATA_SERVER_EXT; + if FileExists(currentfilename) then + DeleteFile(currentfilename); + FHTTP.Document.SaveToFile(DATA_FOLDER + FCurrentName + DBDATA_SERVER_EXT); + + cont := True; + if not FileExists(currentfilename) then + begin + FFailedList.Add(Format(RS_FailedToSave, [FCurrentName])); + cont := False; + end; + if not FileExists(CURRENT_ZIP_EXE) then + begin + FFailedList.Add(Format(RS_MissingZipExe, [FCurrentName, ZIP_EXE])); + cont := False; + end; + + // close and reopen current used + used := FCurrentName = FormMain.cbSelectManga.Items[FormMain.cbSelectManga.ItemIndex]; + + if used then + Synchronize(@SyncCloseUsed) + else + if dataProcess.WebsiteLoaded(FCurrentName) then + Synchronize(@SyncRemoveAttached); + + if cont then + with TProcess.Create(nil) do + try + Executable := CURRENT_ZIP_EXE; + CurrentDirectory := FMD_DIRECTORY; + Parameters.Add('x'); // extract + Parameters.Add(currentfilename); // input + Parameters.Add('-o' + AnsiQuotedStr(DATA_FOLDER, '"')); // destination + Parameters.Add('-aoa'); // overwrite all + Options := Options + [poWaitOnExit]; + ShowWindow := swoNone; + Execute; + cont := ExitStatus = 0; + if not cont then + FFailedList.Add(RS_FailedExtract, [FCurrentName, ExitStatus]); + finally + Free; + end; + if cont and used then + Synchronize(@SyncReopenUsed); + end + else + FFailedList.Add(Format(RS_FailedDownload, [FCurrentName, FHTTP.ResultCode, + FHTTP.ResultString])); + except + on E: Exception do + FFailedList.Add(E.Message); + end; + Inc(FCurrentId); + end; +end; + +constructor TDBUpdaterThread.Create; +begin + inherited Create(True); + FreeOnTerminate := True; + FFailedList := TStringList.Create; + FHTTP := THTTPSendThread.Create(Self); + FHTTP.UserAgent := UserAgentCURL; + FHTTP.Sock.OnStatus := @HTTPSockOnStatus; + Items := TStringList.Create; + Synchronize(@SyncStart); +end; + +destructor TDBUpdaterThread.Destroy; +begin + if (not Terminated) and (FFailedList.Count <> 0) then + Synchronize(@SyncShowFailed); + Synchronize(@SyncFinal); + Items.Free; + FHTTP.Free; + FFailedList.Free; + inherited Destroy; +end; + +procedure TDBUpdaterThread.UpdateStatus; +begin + SyncUpdateStatus; + SyncUpdateHint; +end; + +end. diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index dc42273f5..3183830cd 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -40,6 +40,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) DATA_EXT = '.dat'; DBDATA_EXT = '.db'; + DBDATA_SERVER_EXT = '.7z'; UPDATER_EXE = 'updater.exe'; ZIP_EXE = '7za.exe'; RUN_EXE = '.run'; @@ -89,6 +90,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) README_FILE, EXTRAS_FOLDER, MANGAFOXTEMPLATE_FOLDER, + CURRENT_ZIP_EXE, LUA_WEBSITEMODULE_FOLDER, LUA_WEBSITEMODULE_REPOS: String; DEFAULT_SELECTED_WEBSITES: String = 'MangaFox,MangaHere,MangaInn,MangaReader'; @@ -271,6 +273,7 @@ procedure SetFMDdirectory(const ADir: String); EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; DEFAULT_LOG_FILE := FMD_DIRECTORY + FMD_EXENAME + '.log'; + CURRENT_ZIP_EXE := FMD_DIRECTORY + ZIP_EXE; LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; LUA_WEBSITEMODULE_REPOS := CONFIG_FOLDER + 'luamodules.json'; diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas index c90bf07e5..16061bf30 100644 --- a/baseunits/FMDVars.pas +++ b/baseunits/FMDVars.pas @@ -7,7 +7,7 @@ interface uses frmMain, uDownloadsManager, uFavoritesManager, uUpdateThread, DBDataProcess, uUpdateDBThread, uSilentThread, uBaseUnit, uGetMangaInfosThread, CheckUpdate, - FMDOptions, FileChannel, simpleipc; + FMDOptions, DBUpdater, FileChannel, simpleipc; var FormMain: TMainForm; @@ -48,6 +48,9 @@ interface // updateDB thread updateDB: TUpdateDBThread; + // dbupdater thread + DBUpdaterThread: TDBUpdaterThread; + // silent thread for download all or add to favorite SilentThreadManager: TSilentThreadManager; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 69d4adb58..fdc83e431 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -922,7 +922,7 @@ implementation uses frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8, - webp, LuaWebsiteModules; + webp, DBUpdater, LuaWebsiteModules; var // thread for open db @@ -1390,6 +1390,13 @@ procedure TMainForm.CloseNow; updateList.WaitFor; Logger.Send(Self.ClassName+'.CloseNow, UpdateListThread terminated'); end; + if Assigned(DBUpdaterThread) then + begin + Logger.Send(Self.ClassName+'.CloseNow, terminating DBUpdaterThread'); + DBUpdaterThread.Terminate; + DBUpdaterThread.WaitFor; + Logger.Send(Self.ClassName+'.CloseNow, DBUpdaterThread terminated'); + end; Logger.Send(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; @@ -3178,27 +3185,20 @@ procedure TMainForm.miChapterListUncheckAllClick(Sender: TObject); // ----- vtDownload popup menu ----- procedure TMainForm.mnDownload1ClickClick(Sender: TObject); -var - i: Integer; begin - if not isUpdating then + if (DBUpdaterThread = nil) and + (MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = + mrYes) then begin - if (MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = - mrYes) then - begin - // if dataProcess.Title.Count > 1 then - //begin - isUpdating := True; - updateList := TUpdateListManagerThread.Create; - for i := 0 to cbSelectManga.Items.Count - 1 do - updateList.websites.Add(cbSelectManga.Items[i]); - updateList.isDownloadFromServer := True; - updateList.Start; - //end; - end; + DBUpdaterThread := TDBUpdaterThread.Create; + DBUpdaterThread.Items.AddStrings(cbSelectManga.Items); + DBUpdaterThread.Start; end else - MessageDlg('', RS_DlgFavoritesCheckIsRunning, mtInformation, [mbYes], 0); + begin + DBUpdaterThread.Items.AddStrings(cbSelectManga.Items); + DBUpdaterThread.UpdateStatus; + end; end; procedure TMainForm.mnFilterGenreAllCheckClick(Sender: TObject); @@ -3269,10 +3269,7 @@ procedure TMainForm.mnUpdate1ClickClick(Sender: TObject); procedure TMainForm.mnUpdateDownFromServerClick(Sender: TObject); begin - if (not isUpdating) then - RunGetList - else - MessageDlg('', RS_DlgFavoritesCheckIsRunning, mtInformation, [mbYes], 0); + RunGetList; end; procedure TMainForm.mnUpdateListClick(Sender: TObject); @@ -4848,14 +4845,18 @@ procedure TMainForm.ShowInformation; procedure TMainForm.RunGetList; begin - if (MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = - mrYes) and - (not isUpdating) then + if (DBUpdaterThread = nil) and + (MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = + mrYes) then + begin + DBUpdaterThread := TDBUpdaterThread.Create; + DBUpdaterThread.Items.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); + DBUpdaterThread.Start; + end + else begin - isUpdating := True; - updateDB := TUpdateDBThread.Create; - updateDB.websiteName := cbSelectManga.Items[cbSelectManga.ItemIndex]; - updateDB.Start; + DBUpdaterThread.Items.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); + DBUpdaterThread.UpdateStatus; end; end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 20ee9d987..6de015f91 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -12,6 +12,45 @@ msgstr "" "X-Generator: Poedit 2.0.2\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Abbrechen" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Gescheitert" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Download Originalbilder (benötigt ExHentai account)" @@ -2314,6 +2353,7 @@ msgid "Downloading" msgstr "Downloading" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Gescheitert" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index c178b42c0..f4486055d 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -16,6 +16,45 @@ msgstr "" "X-Poedit-Language: Greek\n" "X-Poedit-Country: GREECE\n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Άκυρο" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Απέτυχε" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Λήψη αρχικής εικόνας (απαιτείται λογαριασμός ExHentai)" @@ -2369,6 +2408,7 @@ msgid "Downloading" msgstr "Λήψη" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Απέτυχε" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index d2ebefdd4..6ae68338f 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -1,6 +1,45 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Cancel" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Failed" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Download original image(require ExHentai account)" @@ -2282,6 +2321,7 @@ msgid "Downloading" msgstr "Downloading" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Failed" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 8f8614062..ed32907f2 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -12,6 +12,45 @@ msgstr "" "Last-Translator: Mariolr\n" "Language: es_419\n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Cancelar" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Fallido" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Descargar imagen original (require una cuenta ExHentai)" @@ -2290,6 +2329,7 @@ msgid "Downloading" msgstr "Descargando" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Fallido" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 51db88199..fdf6c1674 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -1,6 +1,45 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Batal" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Gagal" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Unduh gambar asli(membutuhkan akun ExHentai)" @@ -2282,6 +2321,7 @@ msgid "Downloading" msgstr "Mengunduh" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Gagal" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index be44b7a11..a21a17cd9 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -12,6 +12,45 @@ msgstr "" "X-Generator: Poedit 1.8.12\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Anuluj" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Niepowodzenie" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Pobierz oryginalny obraz (wymaga konta ExHentai)" @@ -2316,6 +2355,7 @@ msgid "Downloading" msgstr "Pobieranie" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Niepowodzenie" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 860057312..5203b452a 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -1,6 +1,43 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" +#: dbupdater.rs_buttoncancel +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "" @@ -2211,6 +2248,7 @@ msgid "Downloading" msgstr "" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 412ab1185..f9e39f869 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -12,6 +12,45 @@ msgstr "" "X-Generator: Poedit 2.0.1\n" "Plural-Forms: \n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Cancelar" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Falhou" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Baixar imagem original (exige uma conta ExHentai)" @@ -2310,6 +2349,7 @@ msgid "Downloading" msgstr "Baixando" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Falhou" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 933f72357..1251edfc8 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -11,6 +11,45 @@ msgstr "" "Language: ru_RU\n" "X-Generator: Poedit 2.0.2\n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "Отмена" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Неудачно" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Загрузить оригинальное изображение(треб. аккаунт ExHentai)" @@ -2292,6 +2331,7 @@ msgid "Downloading" msgstr "Загрузка" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Неудачно" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 48e09c74c..546c8bc97 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -13,6 +13,45 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-SourceCharset: UTF-8\n" +#: dbupdater.rs_buttoncancel +#, fuzzy +msgctxt "dbupdater.rs_buttoncancel" +msgid "Cancel" +msgstr "İptal" + +#: dbupdater.rs_downloading +msgid "Downloading %s" +msgstr "" + +#: dbupdater.rs_faileddownload +msgid "%s: %d %s" +msgstr "" + +#: dbupdater.rs_failedextract +msgid "%s: failed to extract, exitstatus = %d" +msgstr "" + +#: dbupdater.rs_faileditems +msgid "" +"Failed to finish:\n" +"\n" +"%s\n" +msgstr "" + +#: dbupdater.rs_faileditemstitle +#, fuzzy +msgctxt "dbupdater.rs_faileditemstitle" +msgid "Failed" +msgstr "Başarısız oldu" + +#: dbupdater.rs_failedtosave +msgid "%s: failed to save" +msgstr "" + +#: dbupdater.rs_missingzipexe +msgid "%s: Missing %s" +msgstr "" + #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Orijinal resmi indir(ExHentai hesabı gerektirir)" @@ -2312,6 +2351,7 @@ msgid "Downloading" msgstr "İndiriliyor" #: udownloadsmanager.rs_failed +msgctxt "udownloadsmanager.rs_failed" msgid "Failed" msgstr "Başarısız oldu" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 93ab69cfb..9805e2102 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -303,7 +303,7 @@ <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item9> </RequiredPackages> - <Units Count="16"> + <Units Count="17"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -412,6 +412,10 @@ <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit15> + <Unit16> + <Filename Value="..\baseunits\DBUpdater.pas"/> + <IsPartOfProject Value="True"/> + </Unit16> </Units> </ProjectOptions> <CompilerOptions> From e2bc3e26c480745318d4fc3a93eaa83032a5c9ac Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 00:30:13 +0800 Subject: [PATCH 2236/2794] dbupdater, fix don't add existing website --- baseunits/DBUpdater.pas | 34 +++++++++++++++++++++++++++++++ mangadownloader/forms/frmMain.pas | 10 ++------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index ec869d842..944699496 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -43,6 +43,8 @@ TDBUpdaterThread = class(TBaseThread) Items: TStringList; constructor Create; destructor Destroy; override; + procedure Add(const S: String); overload; + procedure Add(const S: TStrings); overload; procedure UpdateStatus; // should be called from mainthread end; @@ -319,6 +321,38 @@ destructor TDBUpdaterThread.Destroy; inherited Destroy; end; +procedure TDBUpdaterThread.Add(const S: String); +var + i: Integer; +begin + // search on not sorted + for i := 0 to Items.Count - 1 do + if S = Items[i] then + Exit; + Items.Add(S); + UpdateStatus; +end; + +procedure TDBUpdaterThread.Add(const S: TStrings); +var + i, j, jmax: Integer; +begin + // search on not sorted + jmax := Items.Count; + for i := 0 to S.Count - 1 do + begin + j := 0; + while j < jmax do + if S[i] = Items[j] then + Break + else + Inc(j); + if j = jmax then + Items.Add(S[i]); + end; + UpdateStatus; +end; + procedure TDBUpdaterThread.UpdateStatus; begin SyncUpdateStatus; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index fdc83e431..80d610683 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3195,10 +3195,7 @@ procedure TMainForm.mnDownload1ClickClick(Sender: TObject); DBUpdaterThread.Start; end else - begin - DBUpdaterThread.Items.AddStrings(cbSelectManga.Items); - DBUpdaterThread.UpdateStatus; - end; + DBUpdaterThread.Add(cbSelectManga.Items); end; procedure TMainForm.mnFilterGenreAllCheckClick(Sender: TObject); @@ -4854,10 +4851,7 @@ procedure TMainForm.RunGetList; DBUpdaterThread.Start; end else - begin - DBUpdaterThread.Items.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); - DBUpdaterThread.UpdateStatus; - end; + DBUpdaterThread.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); end; procedure TMainForm.LoadOptions; From 49acb731e1befc5ce8b2ad31b018ac0a8697f92b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 00:31:25 +0800 Subject: [PATCH 2237/2794] change update url to gh --- update | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/update b/update index 26a03996c..46ec58669 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ VERSION=0.9.140.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0_Win64.7z +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0_Win64.7z From d1c3987a7bf461b2c7f0fb3c9ac9191fe846a592 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 00:34:19 +0800 Subject: [PATCH 2238/2794] dbupdater, delete file after extract success --- baseunits/DBUpdater.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 944699496..9b99f9a79 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -279,7 +279,9 @@ procedure TDBUpdaterThread.Execute; ShowWindow := swoNone; Execute; cont := ExitStatus = 0; - if not cont then + if cont then + DeleteFile(currentfilename) + else FFailedList.Add(RS_FailedExtract, [FCurrentName, ExitStatus]); finally Free; From b1f62dbce8f603080384f64c9362c0ef6b1ce456 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 00:36:22 +0800 Subject: [PATCH 2239/2794] cleanup --- baseunits/FMDVars.pas | 5 +- baseunits/uUpdateDBThread.pas | 149 ------------------------------ mangadownloader/forms/frmMain.pas | 2 +- 3 files changed, 2 insertions(+), 154 deletions(-) delete mode 100644 baseunits/uUpdateDBThread.pas diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas index 16061bf30..9afef8af9 100644 --- a/baseunits/FMDVars.pas +++ b/baseunits/FMDVars.pas @@ -6,7 +6,7 @@ interface uses frmMain, uDownloadsManager, uFavoritesManager, uUpdateThread, DBDataProcess, - uUpdateDBThread, uSilentThread, uBaseUnit, uGetMangaInfosThread, CheckUpdate, + uSilentThread, uBaseUnit, uGetMangaInfosThread, CheckUpdate, FMDOptions, DBUpdater, FileChannel, simpleipc; var @@ -45,9 +45,6 @@ interface // update manga list thread manager updateList: TUpdateListManagerThread; - // updateDB thread - updateDB: TUpdateDBThread; - // dbupdater thread DBUpdaterThread: TDBUpdaterThread; diff --git a/baseunits/uUpdateDBThread.pas b/baseunits/uUpdateDBThread.pas deleted file mode 100644 index 1daa19ff8..000000000 --- a/baseunits/uUpdateDBThread.pas +++ /dev/null @@ -1,149 +0,0 @@ -{ - File: uUpdateDBThread.pas - License: GPLv2 - This unit is a part of Free Manga Downloader -} - -unit uUpdateDBThread; - -{$mode delphi} - -interface - -uses - Classes, SysUtils, uBaseUnit, uMisc, SimpleTranslator, FMDOptions, - LazFileUtils; - -type - - { TUpdateDBThread } - - TUpdateDBThread = class(TThread) - protected - procedure MainThreadShowGetting; - procedure MainThreadShowEndGetting; - procedure MainThreadCannotConnectToServer; - procedure MainThreadRefreshList; - procedure ExtractFile; - procedure Execute; override; - public - websiteName: String; - isTerminated, isSuspended: Boolean; - constructor Create; - destructor Destroy; override; - end; - -implementation - -uses - frmMain, FMDVars, Dialogs, ComCtrls; - -procedure TUpdateDBThread.MainThreadRefreshList; -begin - try - if MainForm.cbSelectManga.Items[MainForm.cbSelectManga.ItemIndex] = websiteName then - begin - MainForm.edMangaListSearch.Clear; - MainForm.vtMangaList.Clear; - dataProcess.Close; - ExtractFile; - MainForm.OpenDataDB(websiteName); - end - else - begin - if dataProcess.WebsiteLoaded(websiteName) then - dataProcess.RemoveFilter; - ExtractFile; - end; - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); - end; - - MainThreadShowEndGetting; -end; - -procedure TUpdateDBThread.ExtractFile; -var - Sza, datapath, filepath: String; -begin - Sza := FMD_DIRECTORY + ZIP_EXE; - if not FileExistsUTF8(Sza) then Exit; - - datapath := DATA_FOLDER; - filepath := datapath + websiteName; - if FileExistsUTF8(filepath + '.7z') then - filepath += '.7z' - else - if FileExistsUTF8(filepath + '.zip') then - filepath += '.zip'; - - if FileExistsUTF8(filepath) then - begin - if FileExistsUTF8(datapath + websiteName + DBDATA_EXT) then - DeleteFileUTF8(datapath + websiteName + DBDATA_EXT); - if FileExistsUTF8(datapath + websiteName + DATA_EXT) then - DeleteFileUTF8(datapath + websiteName + DATA_EXT); - RunExternalProcess(Sza, ['x', filepath, '-o' + - AnsiQuotedStr(datapath, '"'), '-aoa'], False, True); - DeleteFileUTF8(filepath); - end -end; - -constructor TUpdateDBThread.Create; -begin - inherited Create(True); -end; - -destructor TUpdateDBThread.Destroy; -begin - isTerminated := True; - inherited Destroy; -end; - -procedure TUpdateDBThread.MainThreadShowGetting; -begin - if MainForm.sbUpdateList.Visible = False then - begin - MainForm.sbUpdateList.Height := 23; - MainForm.sbMain.Hide; - MainForm.sbUpdateList.Show; - mainForm.sbUpdateList.Panels[0].Style := psText; - MainForm.btAbortUpdateList.Hide; - MainForm.sbMain.Show; - end; - MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; - MainForm.sbUpdateList.Panels[0].Text := 'Getting list for ' + websiteName + ' ...'; -end; - -procedure TUpdateDBThread.MainThreadShowEndGetting; -begin - MainForm.sbUpdateList.Panels[0].Text := ''; - MainForm.sbUpdateList.Hide; - MainForm.sbMain.SizeGrip := not MainForm.sbUpdateList.Visible; - isUpdating := False; -end; - -procedure TUpdateDBThread.MainThreadCannotConnectToServer; -begin - MessageDlg('', RS_DlgCannotConnectToServer, mtInformation, [mbYes], 0); -end; - -procedure TUpdateDBThread.Execute; -begin - try - Synchronize(MainThreadShowGetting); - RunExternalProcess(FMD_DIRECTORY + UPDATER_EXE, ['-r' , '3', '-d', - GetMangaDatabaseURL(websiteName), '--lang', SimpleTranslator.LastSelected]); - if FileExistsUTF8(DATA_FOLDER + websiteName + '.7z') or - FileExistsUTF8(DATA_FOLDER + websiteName + '.zip') then - Synchronize(MainThreadRefreshList) - else - Synchronize(MainThreadShowEndGetting); - except - on E: Exception do - MainForm.ExceptionHandler(Self, E); - end; -end; - -end. diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 80d610683..416149bfd 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -20,7 +20,7 @@ interface Buttons, Spin, Menus, VirtualTrees, RichMemo, IniFiles, simpleipc, lclproc, types, LCLIntf, DefaultTranslator, EditBtn, PairSplitter, MultiLog, FileChannel, FileUtil, LazUTF8Classes, TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, - uFavoritesManager, uUpdateThread, uUpdateDBThread, uSilentThread, uMisc, + uFavoritesManager, uUpdateThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, frmTransferFavorites, frmLuaModulesUpdater, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, From cbd57e0f235808fdd4203dad06339df42f999dff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 01:18:13 +0800 Subject: [PATCH 2240/2794] dbupater, cleanup --- baseunits/DBUpdater.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 9b99f9a79..e99674705 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -243,7 +243,7 @@ procedure TDBUpdaterThread.Execute; currentfilename := DATA_FOLDER + FCurrentName + DBDATA_SERVER_EXT; if FileExists(currentfilename) then DeleteFile(currentfilename); - FHTTP.Document.SaveToFile(DATA_FOLDER + FCurrentName + DBDATA_SERVER_EXT); + FHTTP.Document.SaveToFile(currentfilename); cont := True; if not FileExists(currentfilename) then From 61bb50823fc06a6ff92ab438302e4f247252d3a2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 09:29:46 +0800 Subject: [PATCH 2241/2794] dbupdater, fix --- baseunits/DBUpdater.pas | 94 +++++++++++++++++--------- mangadownloader/forms/frmMain.lfm | 8 +-- mangadownloader/forms/frmMain.pas | 13 +++- mangadownloader/languages/fmd.de.po | 8 ++- mangadownloader/languages/fmd.el_GR.po | 8 ++- mangadownloader/languages/fmd.en.po | 8 ++- mangadownloader/languages/fmd.es.po | 8 ++- mangadownloader/languages/fmd.id_ID.po | 8 ++- mangadownloader/languages/fmd.pl_PL.po | 8 ++- mangadownloader/languages/fmd.po | 7 +- mangadownloader/languages/fmd.pt_BR.po | 8 ++- mangadownloader/languages/fmd.ru_RU.po | 8 ++- mangadownloader/languages/fmd.tr_TR.po | 8 ++- 13 files changed, 145 insertions(+), 49 deletions(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index e99674705..68b3e76ed 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -5,8 +5,8 @@ interface uses - Classes, SysUtils, httpsendthread, BaseThread, FMDOptions, process, ComCtrls, Controls, - Dialogs, StdCtrls, Buttons, blcksock; + Classes, SysUtils, httpsendthread, BaseThread, FMDOptions, process, ComCtrls, + Controls, Dialogs, StdCtrls, Buttons, blcksock; type @@ -23,6 +23,7 @@ TDBUpdaterThread = class(TBaseThread) FCurrentName: String; FFailedList: TStringList; FCurrentId: Integer; + FStatusText: String; protected procedure ButtonCancelClick(Sender: TObject); procedure HTTPSockOnStatus(Sender: TObject; Reason: THookSocketReason; @@ -38,6 +39,7 @@ TDBUpdaterThread = class(TBaseThread) procedure SyncCloseUsed; procedure SyncReopenUsed; procedure SyncRemoveAttached; + procedure UpdateStatusText(const S: String); procedure Execute; override; public Items: TStringList; @@ -55,8 +57,9 @@ TDBUpdaterThread = class(TBaseThread) RS_FailedDownload = '%s: %d %s'; RS_FailedToSave = '%s: failed to save'; RS_MissingZipExe = '%s: Missing %s'; + RS_Extracting = 'Extracting %s'; RS_FailedExtract = '%s: failed to extract, exitstatus = %d'; - RS_ButtonCancel = 'Cancel'; + RS_ButtonCancel = 'Abort'; implementation @@ -82,14 +85,19 @@ procedure TDBUpdaterThread.HTTPSockOnStatus(Sender: TObject; begin if Terminated then Exit; - if FHTTP.Headers.IndexOfName('Content-Length') <> -1 then - FTotalSize := StrToIntDef(FHTTP.Headers.Values['Content-Length'], 0); - case Reason of - HR_Connect: FCurrentSize := 0; - HR_ReadCount: - Inc(FCurrentSize, StrToIntDef(Value, 0)); + if Reason = HR_ReadCount then + begin + if FTotalSize = 0 then + FTotalSize := StrToIntDef(Trim(FHTTP.Headers.Values['Content-Length']), 0); + Inc(FCurrentSize, StrToInt(Value)); + Synchronize(@SyncUpdateProgress); + end + else + if Reason = HR_Connect then + begin + FCurrentSize := 0; + FTotalSize := 0; end; - Synchronize(@SyncUpdateProgress); end; procedure TDBUpdaterThread.SyncStart; @@ -137,11 +145,11 @@ procedure TDBUpdaterThread.SyncStart; Caption := RS_ButtonCancel; ShowCaption := True; Flat := True; - Anchors := [akTop,akRight,akBottom]; + Anchors := [akTop, akRight, akBottom]; AnchorSideTop.Control := FStatusBar; AnchorSideTop.Side := asrTop; AnchorSideRight.Control := FStatusBar; - AnchorSideRight.Side:= asrRight; + AnchorSideRight.Side := asrRight; AnchorSideBottom.Control := FStatusBar; AnchorSideBottom.Side := asrBottom; BorderSpacing.Top := 2; @@ -168,7 +176,9 @@ procedure TDBUpdaterThread.SyncStartDownload; FProgressBar.Position := 0; FStatusBar.Panels[1].Text := ''; FStatusBar.Panels[1].Width := 0; - SyncUpdateStatus; + FStatusBar.Panels[2].Text := Format('[%d/%d] ' + RS_Downloading, + [FCurrentId + 1, Items.Count, + FCurrentName + DBDATA_EXT]); end; procedure TDBUpdaterThread.SyncUpdateProgress; @@ -189,9 +199,7 @@ procedure TDBUpdaterThread.SyncUpdateProgress; procedure TDBUpdaterThread.SyncUpdateStatus; begin - FStatusBar.Panels[2].Text := - Format('[%d/%d] ' + RS_Downloading, [FCurrentId + 1, Items.Count, - FCurrentName + DBDATA_EXT]); + FStatusBar.Panels[2].Text := FStatusText; end; procedure TDBUpdaterThread.SyncUpdateHint; @@ -222,6 +230,14 @@ procedure TDBUpdaterThread.SyncRemoveAttached; dataProcess.RemoveFilter; end; +procedure TDBUpdaterThread.UpdateStatusText(const S: String); +begin + if FStatusText = S then + Exit; + FStatusText := S; + Synchronize(@SyncUpdateStatus); +end; + procedure TDBUpdaterThread.Execute; var currentfilename: String; @@ -237,38 +253,51 @@ procedure TDBUpdaterThread.Execute; try FCurrentName := Items[FCurrentId]; Synchronize(@SyncStartDownload); - if FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300) then // should be success + if FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300) then + // should be success begin + cont := True; // save to data folder currentfilename := DATA_FOLDER + FCurrentName + DBDATA_SERVER_EXT; if FileExists(currentfilename) then DeleteFile(currentfilename); - FHTTP.Document.SaveToFile(currentfilename); - - cont := True; if not FileExists(currentfilename) then + begin + FHTTP.Document.SaveToFile(currentfilename); + if not FileExists(currentfilename) then + begin + FFailedList.Add(Format(RS_FailedToSave, [FCurrentName])); + cont := False; + end; + end + else begin FFailedList.Add(Format(RS_FailedToSave, [FCurrentName])); cont := False; end; - if not FileExists(CURRENT_ZIP_EXE) then + + if cont and (not FileExists(CURRENT_ZIP_EXE)) then begin FFailedList.Add(Format(RS_MissingZipExe, [FCurrentName, ZIP_EXE])); cont := False; end; - // close and reopen current used - used := FCurrentName = FormMain.cbSelectManga.Items[FormMain.cbSelectManga.ItemIndex]; - - if used then - Synchronize(@SyncCloseUsed) - else - if dataProcess.WebsiteLoaded(FCurrentName) then - Synchronize(@SyncRemoveAttached); - if cont then + begin + // close and reopen current used + used := FCurrentName = + FormMain.cbSelectManga.Items[FormMain.cbSelectManga.ItemIndex]; + + if used then + Synchronize(@SyncCloseUsed) + else + if dataProcess.WebsiteLoaded(FCurrentName) then + Synchronize(@SyncRemoveAttached); with TProcess.Create(nil) do try + UpdateStatusText(Format('[%d/%d] ' + RS_Extracting, + [FCurrentId + 1, Items.Count, + FCurrentName + DBDATA_EXT])); Executable := CURRENT_ZIP_EXE; CurrentDirectory := FMD_DIRECTORY; Parameters.Add('x'); // extract @@ -286,8 +315,9 @@ procedure TDBUpdaterThread.Execute; finally Free; end; - if cont and used then - Synchronize(@SyncReopenUsed); + if cont and used then + Synchronize(@SyncReopenUsed); + end; end else FFailedList.Add(Format(RS_FailedDownload, [FCurrentName, FHTTP.ResultCode, diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index dcc4128f6..4c3149113 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -4684,8 +4684,8 @@ object MainForm: TMainForm AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btCheckLatestVersion Left = 212 - Height = 40 - Top = 447 + Height = 35 + Top = 452 Width = 40 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 @@ -4733,8 +4733,8 @@ object MainForm: TMainForm AnchorSideLeft.Side = asrBottom AnchorSideTop.Control = btCheckLatestVersion Left = 256 - Height = 40 - Top = 447 + Height = 35 + Top = 452 Width = 208 Anchors = [akTop, akLeft, akBottom] BorderSpacing.Left = 4 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 416149bfd..b5e17e3c2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1397,6 +1397,13 @@ procedure TMainForm.CloseNow; DBUpdaterThread.WaitFor; Logger.Send(Self.ClassName+'.CloseNow, DBUpdaterThread terminated'); end; + if Assigned(SelfUpdaterThread) then + begin + Logger.Send(Self.ClassName+'.CloseNow, terminating SelfUpdaterThread'); + SelfUpdaterThread.Terminate; + SelfUpdaterThread.WaitFor; + Logger.Send(Self.ClassName+'.CloseNow, SelfUpdaterThread terminated'); + end; Logger.Send(Self.ClassName+'.CloseNow, disabling all timer'); tmBackup.Enabled := False; @@ -2169,8 +2176,8 @@ procedure TMainForm.LoadAbout; for i := 0 to st.Count - 1 do if regx.Exec(st[i]) then begin - if regx.Match[2] <> FMD_VERSION_NUMBER then begin - st[i] := regx.Replace(st[i], '$1\' + FMD_VERSION_NUMBER, True); + if regx.Match[2] <> FMD_VERSION_STRING then begin + st[i] := regx.Replace(st[i], '$1\' + FMD_VERSION_STRING, True); if DeleteFileUTF8(README_FILE) then st.SaveToFile(README_FILE); end; @@ -2596,7 +2603,7 @@ procedure TMainForm.btMangaListSearchClearClick(Sender: TObject); procedure TMainForm.btCheckLatestVersionClick(Sender: TObject); begin - if Assigned(CheckUpdateThread) then + if Assigned(CheckUpdateThread) or Assigned(SelfUpdaterThread) then MessageDlg('', RS_DlgUpdaterIsRunning, mtInformation, [mbYes], 0) else CheckUpdateThread := TCheckUpdateThread.Create; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 6de015f91..05ce410ba 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -14,14 +14,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Abbrechen" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1660,6 +1665,7 @@ msgid "Undo" msgstr "Öffnen" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Abbrechen" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index f4486055d..687c8309b 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -18,14 +18,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Άκυρο" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1715,6 +1720,7 @@ msgid "Undo" msgstr "Αναίρεση" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Ματαίωση" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6ae68338f..6fbf5b736 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -3,14 +3,19 @@ msgstr "Content-Type: text/plain; charset=UTF-8" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Cancel" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1636,6 +1641,7 @@ msgid "Undo" msgstr "Undo" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Abort" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index ed32907f2..a2b64571b 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -14,14 +14,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Cancelar" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1638,6 +1643,7 @@ msgid "Undo" msgstr "Deshacer" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Abortar" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index fdf6c1674..94e5d418c 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -3,14 +3,19 @@ msgstr "Content-Type: text/plain; charset=UTF-8" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Batal" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1636,6 +1641,7 @@ msgid "Undo" msgstr "Urungkan" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Batalkan" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index a21a17cd9..e20a1a184 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -14,14 +14,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Anuluj" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1661,6 +1666,7 @@ msgid "Undo" msgstr "Cofnij" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Anuluj" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 5203b452a..c8d5c3b5c 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -3,13 +3,17 @@ msgstr "Content-Type: text/plain; charset=UTF-8" #: dbupdater.rs_buttoncancel msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1565,6 +1569,7 @@ msgid "Undo" msgstr "" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index f9e39f869..f40a4aff9 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -14,14 +14,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Cancelar" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1658,6 +1663,7 @@ msgid "Undo" msgstr "Desfazer" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Abortar" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 1251edfc8..6c1b27de4 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -13,14 +13,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "Отмена" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1646,6 +1651,7 @@ msgid "Undo" msgstr "Отменить" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Отменить" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 546c8bc97..7e095032e 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -15,14 +15,19 @@ msgstr "" #: dbupdater.rs_buttoncancel #, fuzzy +#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" -msgid "Cancel" +msgid "Abort" msgstr "İptal" #: dbupdater.rs_downloading msgid "Downloading %s" msgstr "" +#: dbupdater.rs_extracting +msgid "Extracting %s" +msgstr "" + #: dbupdater.rs_faileddownload msgid "%s: %d %s" msgstr "" @@ -1665,6 +1670,7 @@ msgid "Undo" msgstr "Geri al" #: tmainform.miabortsilentthread.caption +msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" msgstr "Durdur" From d194c4f2ceebeda74217d336bf7db6e4a885d9bd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 10:03:27 +0800 Subject: [PATCH 2242/2794] added self updater --- baseunits/CheckUpdate.pas | 47 ++-- baseunits/DBUpdater.pas | 4 +- baseunits/FMDOptions.pas | 47 +--- baseunits/FMDVars.pas | 6 +- baseunits/SelfUpdater.pas | 310 +++++++++++++++++++++++++ baseunits/uBaseUnit.pas | 2 - mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 20 +- mangadownloader/languages/fmd.de.po | 43 ++++ mangadownloader/languages/fmd.el_GR.po | 43 ++++ mangadownloader/languages/fmd.en.po | 43 ++++ mangadownloader/languages/fmd.es.po | 43 ++++ mangadownloader/languages/fmd.id_ID.po | 43 ++++ mangadownloader/languages/fmd.pl_PL.po | 43 ++++ mangadownloader/languages/fmd.po | 41 ++++ mangadownloader/languages/fmd.pt_BR.po | 43 ++++ mangadownloader/languages/fmd.ru_RU.po | 43 ++++ mangadownloader/languages/fmd.tr_TR.po | 43 ++++ mangadownloader/md.lpi | 8 +- 19 files changed, 799 insertions(+), 74 deletions(-) create mode 100644 baseunits/SelfUpdater.pas diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 7f03e54c1..4acb7bca9 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -11,14 +11,17 @@ interface uses Classes, SysUtils, Forms, Controls, uBaseUnit, FMDOptions, httpsendthread, - BaseThread; + BaseThread, SelfUpdater, fileinfo; type TCheckUpdateThread = class(TBaseThread) private FHTTP: THTTPSendThread; - fNewVersionNumber, fUpdateURL, fChangelog: String; + FNewVersionNumber: TProgramVersion; + FNewVersionString: String; + FUpdateURL: String; + FChangelog: String; procedure MainThreadUpdate; procedure SyncStartUpdate; procedure SyncEndUpdate; @@ -52,18 +55,24 @@ procedure TCheckUpdateThread.MainThreadUpdate; BeginUpdate; try Clear; - Add(RS_CurrentVersion + ' : ' + FMD_VERSION_NUMBER); - Add(RS_LatestVersion + ' : ' + fNewVersionNumber + LineEnding); - AddText(fChangelog); + Add(RS_CurrentVersion + ' : ' + FMD_VERSION_STRING); + Add(RS_LatestVersion + ' : ' + FNewVersionString + LineEnding); + AddText(FChangelog); finally EndUpdate; end; end; if ShowModal = mrYes then begin - UpdateURL := fUpdateURL; - DoAfterFMD := DO_UPDATE; - MainForm.tmExitCommand.Enabled := True; + with TSelfUpdaterThread.Create do + begin + UpdateURL := FUpdateURL; + NewVersionString := FNewVersionString; + Start; + end; + //UpdateURL := FUpdateURL; + //DoAfterFMD := DO_UPDATE; + //MainForm.tmExitCommand.Enabled := True; end else MainForm.btCheckLatestVersion.Caption := RS_BtnCheckUpdates; @@ -94,26 +103,28 @@ procedure TCheckUpdateThread.SyncEndUpdate; procedure TCheckUpdateThread.Execute; begin - fNewVersionNumber := ''; - fUpdateURL := ''; - fChangelog := ''; + FNewVersionString := ''; + FUpdateURL := ''; + FChangelog := ''; Synchronize(@SyncStartUpdate); - if not Terminated and FHTTP.Get(UPDATE_URL + 'update') then + if not Terminated and FHTTP.Get(UPDATE_URL) then with TStringList.Create do try LoadFromStream(FHTTP.Document); if Count <> 0 then begin NameValueSeparator := '='; - fNewVersionNumber := Trim(Values['VERSION']); - if fNewVersionNumber <> FMD_VERSION_NUMBER then - fUpdateURL := Trim(Values[UpperCase(FMD_TARGETOS)]); + FNewVersionString := Trim(Values['VERSION']); + if not TryStrToProgramVersion(FNewVersionString, FNewVersionNumber) then + FNewVersionNumber := StrToProgramVersion('0.0.0.0'); + if NewerVersion(FNewVersionNumber, FMD_VERSION_NUMBER) then + FUpdateURL := Trim(Values[UpperCase(FMD_TARGETOS)]); end; finally Free; end; - if not Terminated and (fUpdateURL <> '') and FHTTP.Get(UPDATE_URL + 'changelog.txt') then - fChangelog := StreamToString(FHTTP.Document); + if not Terminated and (FUpdateURL <> '') and FHTTP.Get(CHANGELOG_URL) then + FChangelog := StreamToString(FHTTP.Document); Synchronize(@SyncEndUpdate); - if not Terminated and (fUpdateURL <> '') and (not isDlgCounter) then + if not Terminated and (FUpdateURL <> '') and (not isDlgCounter) then Synchronize(@MainThreadUpdate); end; diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 68b3e76ed..8f6bc607e 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -192,7 +192,9 @@ procedure TDBUpdaterThread.SyncUpdateProgress; if FProgressBar.Position <> FCurrentSize then FProgressBar.Position := FCurrentSize; - s := FormatByteSize(FCurrentSize) + '/' + FormatByteSize(FTotalSize); + s := FormatByteSize(FCurrentSize); + if FTotalSize <> 0 then + s += '/' + FormatByteSize(FTotalSize); FStatusBar.Panels[1].Width := FStatusBar.Canvas.TextWidth(s) + 10; FStatusBar.Panels[1].Text := s; end; diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 3183830cd..8ffd26ba3 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -25,6 +25,10 @@ TIniFileRun = class(IniFiles.TMemIniFile) TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); const + UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/update'; + CHANGELOG_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/changelog.txt'; + UPDATE_PACKAGE_NAME = 'updatepackage.7z'; + FMD_REVISION = '$WCREV$'; FMD_INSTANCE = '_FreeMangaDownloaderInstance_'; FMD_TARGETOS = {$i %FPCTARGETOS%}; @@ -62,7 +66,8 @@ TIniFileRun = class(IniFiles.TMemIniFile) {$ENDIF} var - FMD_VERSION_NUMBER, + FMD_VERSION_NUMBER: TProgramVersion; + FMD_VERSION_STRING, FMD_DIRECTORY, FMD_EXENAME, APPDATA_DIRECTORY, @@ -328,46 +333,10 @@ procedure DoRestartFMD; end; end; -function GetCurrentBinVersion: String; -var - AppVerInfo: TStringList; - i: Integer; -begin - Result := ''; - AppVerInfo := TStringList.Create; - with TFileVersionInfo.Create(nil) do - try - try - FileName := ParamStrUTF8(0); - if FileName = '' then - FileName := Application.ExeName; - {$IF FPC_FULLVERSION >= 20701} - ReadFileInfo; - {$ENDIF} - if VersionStrings.Count > 0 then - begin - {$IF FPC_FULLVERSION >= 20701} - AppVerInfo.Assign(VersionStrings); - {$ELSE} - for i := 0 to VersionStrings.Count - 1 do - AppVerInfo.Add(VersionCategories.Strings[i] + '=' + - VersionStrings.Strings[i]); - {$ENDIF} - for i := 0 to AppVerInfo.Count - 1 do - AppVerInfo.Strings[i] := LowerCase(AppVerInfo.Names[i]) + '=' + AppVerInfo.ValueFromIndex[i]; - Result := Trim(AppVerInfo.Values['fileversion']); - end; - except - end; - finally - Free; - AppVerInfo.Free; - end; -end; - procedure doInitialization; begin - FMD_VERSION_NUMBER := GetCurrentBinVersion; + GetProgramVersion(FMD_VERSION_NUMBER); + FMD_VERSION_STRING := ProgramversionToStr(FMD_VERSION_NUMBER); AvailableWebsites := TStringList.Create; AvailableWebsites.Sorted := False; SetFMDdirectory(ExtractFilePath(Application.ExeName)); diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas index 9afef8af9..2945af319 100644 --- a/baseunits/FMDVars.pas +++ b/baseunits/FMDVars.pas @@ -7,7 +7,7 @@ interface uses frmMain, uDownloadsManager, uFavoritesManager, uUpdateThread, DBDataProcess, uSilentThread, uBaseUnit, uGetMangaInfosThread, CheckUpdate, - FMDOptions, DBUpdater, FileChannel, simpleipc; + FMDOptions, DBUpdater, SelfUpdater, FileChannel, simpleipc; var FormMain: TMainForm; @@ -24,7 +24,6 @@ interface // update fmd through main thread DoAfterFMD: TFMDDo; IsDlgCounter: Boolean = False; - UpdateURL: String; // file logger FileLogger: TFileChannel; @@ -58,6 +57,9 @@ interface // check update thread CheckUpdateThread: TCheckUpdateThread; + // self updater thread + SelfUpdaterThread: TSelfUpdaterThread; + implementation end. diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas new file mode 100644 index 000000000..c23d6a0f8 --- /dev/null +++ b/baseunits/SelfUpdater.pas @@ -0,0 +1,310 @@ +unit SelfUpdater; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, httpsendthread, BaseThread, FMDOptions, process, ComCtrls, Controls, + Dialogs, StdCtrls, Buttons, blcksock; + +type + + { TSelfUpdaterThread } + + TSelfUpdaterThread = class(TBaseThread) + private + FStatusBar: TStatusBar; + FProgressBar: TProgressBar; + FButtonCancel: TSpeedButton; + FHTTP: THTTPSendThread; + FTotalSize: Integer; + FCurrentSize: Integer; + FFailedMessage: String; + FStatusText: String; + protected + procedure ButtonCancelClick(Sender: TObject); + procedure HTTPSockOnStatus(Sender: TObject; Reason: THookSocketReason; + const Value: String); + protected + procedure SyncStart; + procedure SyncFinal; + procedure SyncStartDownload; + procedure SyncUpdateProgress; + procedure SyncUpdateStatus; + procedure SyncShowFailed; + procedure SyncFinishRestart; + procedure ProceedUpdate; + procedure UpdateStatusText(const S: String); + procedure Execute; override; + public + UpdateURL: String; + NewVersionString: String; + Filename: String; + DownloadSuccess: Boolean; + constructor Create; + destructor Destroy; override; + end; + +resourcestring + RS_Downloading = 'Downloading new version %s'; + RS_FailedTitle = 'Failed'; + RS_FailedDownload = 'Failed to download new version %s'#13#10#13#10'%d %s'; + RS_FailedToSave = 'Failed to save %s'; + RS_MissingZipExe = 'Missing %s'; + RS_FailedExtract = 'Failed to extract %s, exitstatus = %d'; + RS_ButtonCancel = 'Abort'; + RS_FinishRestartTitle = 'Download finished'; + RS_FinishRestart = 'Download update package finished, restart to proceed?'; + +implementation + +uses FMDVars; + +{ TSelfUpdaterThread } + +procedure TSelfUpdaterThread.ButtonCancelClick(Sender: TObject); +begin + Self.Terminate; +end; + +procedure TSelfUpdaterThread.HTTPSockOnStatus(Sender: TObject; + Reason: THookSocketReason; const Value: String); +begin + if Terminated then + Exit; + if Reason = HR_ReadCount then + begin + if FTotalSize = 0 then + FTotalSize := StrToIntDef(Trim(FHTTP.Headers.Values['Content-Length']), 0); + Inc(FCurrentSize, StrToInt(Value)); + Synchronize(@SyncUpdateProgress); + end + else + if Reason = HR_Connect then + begin + FCurrentSize := 0; + FTotalSize := 0; + end; +end; + +procedure TSelfUpdaterThread.SyncStart; +begin + SelfUpdaterThread := Self; + + FStatusBar := TStatusBar.Create(FormMain); + with FStatusBar do + begin + Parent := FormMain; + SimplePanel := False; + with Panels.Add do // panel for progress bar + Width := 100; + Panels.Add; // panel for progress text + Panels.Add; // panel for status text + end; + + FProgressBar := TProgressBar.Create(FormMain); + with FProgressBar do + begin + Parent := FStatusBar; + Align := alNone; + Smooth := True; + Style := pbstNormal; + Min := 0; + Width := FStatusBar.Panels[0].Width - 10; + Anchors := [akTop, akLeft, akBottom]; + AnchorSideTop.Control := FStatusBar; + AnchorSideTop.Side := asrTop; + AnchorSideLeft.Control := FStatusBar; + AnchorSideLeft.Side := asrTop; + AnchorSideBottom.Control := FStatusBar; + AnchorSideBottom.Side := asrBottom; + BorderSpacing.Top := 2; + BorderSpacing.Left := 5; + BorderSpacing.Bottom := 2; + end; + + FButtonCancel := TSpeedButton.Create(FormMain); + with FButtonCancel do + begin + Parent := FStatusBar; + Align := alNone; + AutoSize := True; + Caption := RS_ButtonCancel; + ShowCaption := True; + Flat := True; + Anchors := [akTop, akRight, akBottom]; + AnchorSideTop.Control := FStatusBar; + AnchorSideTop.Side := asrTop; + AnchorSideRight.Control := FStatusBar; + AnchorSideRight.Side := asrRight; + AnchorSideBottom.Control := FStatusBar; + AnchorSideBottom.Side := asrBottom; + BorderSpacing.Top := 2; + BorderSpacing.Right := 5; + BorderSpacing.Bottom := 2; + OnClick := @ButtonCancelClick; + end; +end; + +procedure TSelfUpdaterThread.SyncFinal; +begin + FHTTP.Sock.OnStatus := nil; + FreeAndNil(FStatusBar); + FreeAndNil(FProgressBar); + FreeAndNil(FButtonCancel); + SelfUpdaterThread := nil; +end; + +procedure TSelfUpdaterThread.SyncStartDownload; +begin + FCurrentSize := 0; + FTotalSize := 0; + FProgressBar.Max := 0; + FProgressBar.Position := 0; + FStatusBar.Panels[1].Text := ''; + FStatusBar.Panels[1].Width := 0; + SyncUpdateStatus; +end; + +procedure TSelfUpdaterThread.SyncUpdateProgress; +var + s: String; +begin + if FStatusBar = nil then + Exit; + if FProgressBar.Max <> FTotalSize then + FProgressBar.Max := FTotalSize; + if FProgressBar.Position <> FCurrentSize then + FProgressBar.Position := FCurrentSize; + + s := FormatByteSize(FCurrentSize); + if FTotalSize <> 0 then + s += '/' + FormatByteSize(FTotalSize); + FStatusBar.Panels[1].Width := FStatusBar.Canvas.TextWidth(s) + 10; + FStatusBar.Panels[1].Text := s; +end; + +procedure TSelfUpdaterThread.SyncUpdateStatus; +begin + FStatusBar.Panels[2].Text := FStatusText; +end; + +procedure TSelfUpdaterThread.SyncShowFailed; +begin + MessageDlg(RS_FailedTitle, FFailedMessage, mtError, [mbOK], 0); +end; + +procedure TSelfUpdaterThread.SyncFinishRestart; +begin + if MessageDlg(RS_FinishRestartTitle, RS_FinishRestart, mtConfirmation, mbYesNo, 0) = mrYes then + ProceedUpdate; +end; + +procedure TSelfUpdaterThread.ProceedUpdate; +begin + +end; + +procedure TSelfUpdaterThread.UpdateStatusText(const S: String); +begin + if FStatusText = S then + Exit; + FStatusText := S; + Synchronize(@SyncUpdateStatus); +end; + +procedure TSelfUpdaterThread.Execute; +begin + DownloadSuccess := False; + if UpdateURL = '' then + Exit; + try + FStatusText := Format(RS_Downloading, [UpdateURL]); + Synchronize(@SyncStartDownload); + if FHTTP.GET(UpdateURL) and (FHTTP.ResultCode < 300) then // should be success + begin + DownloadSuccess := True; + Filename := FMD_DIRECTORY + UPDATE_PACKAGE_NAME; + if FileExists(Filename) then + DeleteFile(Filename); + if not FileExists(Filename) then + FHTTP.Document.SaveToFile(Filename); + + if FileExists(Filename) then + DeleteFile(Filename); + if not FileExists(Filename) then + begin + FHTTP.Document.SaveToFile(Filename); + if not FileExists(Filename) then + begin + FFailedMessage := Format(RS_FailedToSave, [Filename]); + DownloadSuccess := False; + end + end + else + begin + FFailedMessage := Format(RS_FailedToSave, [Filename]); + DownloadSuccess := False; + end; + + if DownloadSuccess and (not FileExists(CURRENT_ZIP_EXE)) then + begin + FFailedMessage := Format(RS_MissingZipExe, [CURRENT_ZIP_EXE]); + DownloadSuccess := False; + end; + + //if DownloadSuccess then + // with TProcess.Create(nil) do + // try + // Executable := CURRENT_ZIP_EXE; + // CurrentDirectory := FMD_DIRECTORY; + // Parameters.Add('x'); + // Parameters.Add(Filename); + // Parameters.Add('-o' + AnsiQuotedStr(FMD_DIRECTORY, '"')); + // Parameters.Add('-aoa'); + // Options := Options + [poWaitOnExit]; + // ShowWindow := swoNone; + // Execute; + // DownloadSuccess := ExitStatus = 0; + // if DownloadSuccess then + // DeleteFile(Filename) + // else + // FFailedMessage := Format(RS_FailedExtract, [Filename, ExitStatus]); + // finally + // Free; + // end; + end + else + FFailedMessage := Format(RS_FailedDownload, [NewVersionString, + FHTTP.ResultCode, FHTTP.ResultString]); + except + on E: Exception do + FFailedMessage := E.Message; + end; +end; + +constructor TSelfUpdaterThread.Create; +begin + inherited Create(True); + FreeOnTerminate := True; + FFailedMessage := ''; + FHTTP := THTTPSendThread.Create(Self); + FHTTP.UserAgent := UserAgentCURL; + FHTTP.Sock.OnStatus := @HTTPSockOnStatus; + Synchronize(@SyncStart); +end; + +destructor TSelfUpdaterThread.Destroy; +begin + if (not Terminated) and (FFailedMessage <> '') then + Synchronize(@SyncShowFailed) + else + if DownloadSuccess then + Synchronize(@SyncFinishRestart); + Synchronize(@SyncFinal); + FHTTP.Free; + inherited Destroy; +end; + +end. diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index cfcc38d8d..482a8d551 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -183,8 +183,6 @@ interface ('γ', 'γ') ); - UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/'; - OPTION_MANGALIST = 0; OPTION_RECONNECT = 1; diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 4c3149113..356f83127 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -14,6 +14,7 @@ object MainForm: TMainForm OnWindowStateChange = FormWindowStateChange Position = poScreenCenter ShowHint = True + LCLVersion = '1.9.0.0' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b5e17e3c2..9b9be9f13 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1768,16 +1768,16 @@ procedure TMainForm.tmExitCommandTimer(Sender: TObject); else if DoAfterFMD = DO_UPDATE then begin - if FileExistsUTF8(FMD_DIRECTORY + UPDATER_EXE) then - CopyFile(FMD_DIRECTORY + UPDATER_EXE, FMD_DIRECTORY + 'old_' + UPDATER_EXE); - if FileExistsUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) then - begin - Self.CloseNow; - RunExternalProcess(FMD_DIRECTORY + 'old_' + UPDATER_EXE, - ['-x', '-r', '3', '-a', UpdateURL, '-l', Application.ExeName, - '--lang', SimpleTranslator.LastSelected], True, False); - Self.Close; - end; + //if FileExistsUTF8(FMD_DIRECTORY + UPDATER_EXE) then + // CopyFile(FMD_DIRECTORY + UPDATER_EXE, FMD_DIRECTORY + 'old_' + UPDATER_EXE); + //if FileExistsUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) then + //begin + // Self.CloseNow; + // RunExternalProcess(FMD_DIRECTORY + 'old_' + UPDATER_EXE, + // ['-x', '-r', '3', '-a', UpdateURL, '-l', Application.ExeName, + // '--lang', SimpleTranslator.LastSelected], True, False); + // Self.Close; + //end; end; DoAfterFMD := DO_NOTHING; end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 05ce410ba..e52370579 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -476,6 +476,49 @@ msgstr "Entferne Wasserzeichen" msgid "Save as PNG" msgstr "Speichern als PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Abbrechen" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Gescheitert" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 687c8309b..cf3c714e7 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -480,6 +480,49 @@ msgstr "Αφαίρεση υδατογραφήματος" msgid "Save as PNG" msgstr "Αποθήκευση ως PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Ματαίωση" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Απέτυχε" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6fbf5b736..8a215b8e0 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -472,6 +472,49 @@ msgstr "Remove watermark" msgid "Save as PNG" msgstr "Save as PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Abort" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Failed" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index a2b64571b..b55cc7116 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -474,6 +474,49 @@ msgstr "Quitar Marca de Agua" msgid "Save as PNG" msgstr "Guardar como PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Abortar" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Fallido" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 94e5d418c..b352baec7 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -472,6 +472,49 @@ msgstr "Hapus watermark" msgid "Save as PNG" msgstr "Simpan sebagai PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Batalkan" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Gagal" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index e20a1a184..ecf5cfe3a 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -476,6 +476,49 @@ msgstr "Usuń znak wodny" msgid "Save as PNG" msgstr "Zapisz jako PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Anuluj" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Niepowodzenie" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index c8d5c3b5c..b5665f427 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -434,6 +434,47 @@ msgstr "" msgid "Save as PNG" msgstr "" +#: selfupdater.rs_buttoncancel +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index f40a4aff9..e322a770c 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -475,6 +475,49 @@ msgstr "Remover a marca d'água" msgid "Save as PNG" msgstr "Salvar como PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Abortar" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Falhou" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 6c1b27de4..2be28433b 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -482,6 +482,49 @@ msgstr "Удалить водяные знаки" msgid "Save as PNG" msgstr "Сохранить как PNG" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Отменить" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Неудачно" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 7e095032e..850222c71 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -486,6 +486,49 @@ msgstr "Filigranı kaldır" msgid "Save as PNG" msgstr "PNG olarak kaydet" +#: selfupdater.rs_buttoncancel +#, fuzzy +msgctxt "selfupdater.rs_buttoncancel" +msgid "Abort" +msgstr "Durdur" + +#: selfupdater.rs_downloading +msgid "Downloading new version %s" +msgstr "" + +#: selfupdater.rs_faileddownload +msgid "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" +msgstr "" + +#: selfupdater.rs_failedextract +msgid "Failed to extract %s, exitstatus = %d" +msgstr "" + +#: selfupdater.rs_failedtitle +#, fuzzy +msgctxt "selfupdater.rs_failedtitle" +msgid "Failed" +msgstr "Başarısız oldu" + +#: selfupdater.rs_failedtosave +msgid "Failed to save %s" +msgstr "" + +#: selfupdater.rs_finishrestart +msgid "Download update package finished, restart to proceed?" +msgstr "" + +#: selfupdater.rs_finishrestarttitle +msgid "Download finished" +msgstr "" + +#: selfupdater.rs_missingzipexe +msgid "Missing %s" +msgstr "" + #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" msgid "Add" diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 9805e2102..18c234bc8 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="140"/> + <RevisionNr Value="139"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> @@ -303,7 +303,7 @@ <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> </Item9> </RequiredPackages> - <Units Count="17"> + <Units Count="18"> <Unit0> <Filename Value="md.lpr"/> <IsPartOfProject Value="True"/> @@ -416,6 +416,10 @@ <Filename Value="..\baseunits\DBUpdater.pas"/> <IsPartOfProject Value="True"/> </Unit16> + <Unit17> + <Filename Value="..\baseunits\SelfUpdater.pas"/> + <IsPartOfProject Value="True"/> + </Unit17> </Units> </ProjectOptions> <CompilerOptions> From 97dfed791f87733f416c9b8722a4b4a9512b093b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 11:54:13 +0800 Subject: [PATCH 2243/2794] selfupdater, cleanup and fix --- baseunits/CheckUpdate.pas | 3 --- baseunits/FMDOptions.pas | 7 ++++- baseunits/SelfUpdater.pas | 54 +++++++++++++++++++++------------------ 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/baseunits/CheckUpdate.pas b/baseunits/CheckUpdate.pas index 4acb7bca9..33474b785 100644 --- a/baseunits/CheckUpdate.pas +++ b/baseunits/CheckUpdate.pas @@ -70,9 +70,6 @@ procedure TCheckUpdateThread.MainThreadUpdate; NewVersionString := FNewVersionString; Start; end; - //UpdateURL := FUpdateURL; - //DoAfterFMD := DO_UPDATE; - //MainForm.tmExitCommand.Enabled := True; end else MainForm.btCheckLatestVersion.Caption := RS_BtnCheckUpdates; diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 8ffd26ba3..01f73e658 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -46,6 +46,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) DBDATA_EXT = '.db'; DBDATA_SERVER_EXT = '.7z'; UPDATER_EXE = 'updater.exe'; + OLD_UPDATER_EXE = 'old_' + UPDATER_EXE; ZIP_EXE = '7za.exe'; RUN_EXE = '.run'; @@ -70,6 +71,9 @@ TIniFileRun = class(IniFiles.TMemIniFile) FMD_VERSION_STRING, FMD_DIRECTORY, FMD_EXENAME, + CURRENT_UPDATER_EXE, + OLD_CURRENT_UPDATER_EXE, + CURRENT_ZIP_EXE, APPDATA_DIRECTORY, DEFAULT_PATH, WORK_FOLDER, @@ -95,7 +99,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) README_FILE, EXTRAS_FOLDER, MANGAFOXTEMPLATE_FOLDER, - CURRENT_ZIP_EXE, LUA_WEBSITEMODULE_FOLDER, LUA_WEBSITEMODULE_REPOS: String; DEFAULT_SELECTED_WEBSITES: String = 'MangaFox,MangaHere,MangaInn,MangaReader'; @@ -278,6 +281,8 @@ procedure SetFMDdirectory(const ADir: String); EXTRAS_FOLDER := FMD_DIRECTORY + 'extras' + PathDelim; MANGAFOXTEMPLATE_FOLDER := EXTRAS_FOLDER + 'mangafoxtemplate' + PathDelim; DEFAULT_LOG_FILE := FMD_DIRECTORY + FMD_EXENAME + '.log'; + CURRENT_UPDATER_EXE := FMD_DIRECTORY + UPDATER_EXE; + OLD_CURRENT_UPDATER_EXE := FMD_DIRECTORY + OLD_UPDATER_EXE; CURRENT_ZIP_EXE := FMD_DIRECTORY + ZIP_EXE; LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index c23d6a0f8..9c095c206 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, httpsendthread, BaseThread, FMDOptions, process, ComCtrls, Controls, - Dialogs, StdCtrls, Buttons, blcksock; + Dialogs, StdCtrls, Buttons, Forms, blcksock; type @@ -197,13 +197,38 @@ procedure TSelfUpdaterThread.SyncShowFailed; procedure TSelfUpdaterThread.SyncFinishRestart; begin - if MessageDlg(RS_FinishRestartTitle, RS_FinishRestart, mtConfirmation, mbYesNo, 0) = mrYes then + if MessageDlg(RS_FinishRestartTitle, RS_FinishRestart, mtConfirmation, + mbYesNo, 0) = mrYes then ProceedUpdate; end; procedure TSelfUpdaterThread.ProceedUpdate; begin - + if DownloadSuccess then + begin + if FileExists(OLD_CURRENT_UPDATER_EXE) then + DeleteFile(OLD_CURRENT_UPDATER_EXE); + if FileExists(CURRENT_UPDATER_EXE) then + RenameFile(CURRENT_UPDATER_EXE, OLD_CURRENT_UPDATER_EXE); + if not FileExists(OLD_CURRENT_UPDATER_EXE) then + Exit; + with TProcess.Create(nil) do + try + InheritHandles := False; + CurrentDirectory := FMD_DIRECTORY; + Executable := OLD_CURRENT_UPDATER_EXE; + Parameters.Add(Application.ExeName); + Parameters.Add(CURRENT_ZIP_EXE); + Parameters.Add(Self.Filename); + Parameters.Add(FMD_DIRECTORY); + Execute; + finally + Free; + end; + DoAfterFMD := DO_UPDATE; + FormMain.tmExitCommand.Interval := 32; + FormMain.tmExitCommand.Enabled := True; + end; end; procedure TSelfUpdaterThread.UpdateStatusText(const S: String); @@ -240,7 +265,7 @@ procedure TSelfUpdaterThread.Execute; begin FFailedMessage := Format(RS_FailedToSave, [Filename]); DownloadSuccess := False; - end + end; end else begin @@ -253,27 +278,6 @@ procedure TSelfUpdaterThread.Execute; FFailedMessage := Format(RS_MissingZipExe, [CURRENT_ZIP_EXE]); DownloadSuccess := False; end; - - //if DownloadSuccess then - // with TProcess.Create(nil) do - // try - // Executable := CURRENT_ZIP_EXE; - // CurrentDirectory := FMD_DIRECTORY; - // Parameters.Add('x'); - // Parameters.Add(Filename); - // Parameters.Add('-o' + AnsiQuotedStr(FMD_DIRECTORY, '"')); - // Parameters.Add('-aoa'); - // Options := Options + [poWaitOnExit]; - // ShowWindow := swoNone; - // Execute; - // DownloadSuccess := ExitStatus = 0; - // if DownloadSuccess then - // DeleteFile(Filename) - // else - // FFailedMessage := Format(RS_FailedExtract, [Filename, ExitStatus]); - // finally - // Free; - // end; end else FFailedMessage := Format(RS_FailedDownload, [NewVersionString, From ff2cd6b208ac2abeedad015f099f9b134e8aa7f0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 12:23:20 +0800 Subject: [PATCH 2244/2794] added slim updater --- .gitignore | 1 + mangadownloader/forms/frmMain.pas | 20 ++---- updaterslim/updater.lpi | 103 ++++++++++++++++++++++++++++++ updaterslim/updater.lpr | 70 ++++++++++++++++++++ 4 files changed, 180 insertions(+), 14 deletions(-) create mode 100644 updaterslim/updater.lpi create mode 100644 updaterslim/updater.lpr diff --git a/.gitignore b/.gitignore index f0005bebf..e32cb3801 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ fp.dsk *.res mangadownloader/lib updater/lib +updaterslim/lib bin/ Release/ diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9b9be9f13..422fb8f90 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1132,12 +1132,12 @@ procedure TMainForm.FormCreate(Sender: TObject); LoadAbout; // remove old updater - if FileExistsUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) then + if FileExistsUTF8(OLD_CURRENT_UPDATER_EXE) then begin - if FileExistsUTF8(FMD_DIRECTORY + UPDATER_EXE) then - DeleteFileUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) + if FileExistsUTF8(CURRENT_UPDATER_EXE) then + DeleteFileUTF8(OLD_CURRENT_UPDATER_EXE) else - RenameFileUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE, FMD_DIRECTORY + UPDATER_EXE); + RenameFileUTF8(OLD_CURRENT_UPDATER_EXE, CURRENT_UPDATER_EXE); end; // TrayIcon @@ -1768,16 +1768,8 @@ procedure TMainForm.tmExitCommandTimer(Sender: TObject); else if DoAfterFMD = DO_UPDATE then begin - //if FileExistsUTF8(FMD_DIRECTORY + UPDATER_EXE) then - // CopyFile(FMD_DIRECTORY + UPDATER_EXE, FMD_DIRECTORY + 'old_' + UPDATER_EXE); - //if FileExistsUTF8(FMD_DIRECTORY + 'old_' + UPDATER_EXE) then - //begin - // Self.CloseNow; - // RunExternalProcess(FMD_DIRECTORY + 'old_' + UPDATER_EXE, - // ['-x', '-r', '3', '-a', UpdateURL, '-l', Application.ExeName, - // '--lang', SimpleTranslator.LastSelected], True, False); - // Self.Close; - //end; + Self.CloseNow; + Self.Close; end; DoAfterFMD := DO_NOTHING; end; diff --git a/updaterslim/updater.lpi b/updaterslim/updater.lpi new file mode 100644 index 000000000..10f27a086 --- /dev/null +++ b/updaterslim/updater.lpi @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="updater"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + </General> + <BuildModes Count="2"> + <Item1 Name="Win32" Default="True"/> + <Item2 Name="Win64"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\bin\updater"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + <SmallerCode Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item2> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes Count="0"/> + </RunParams> + <Units Count="1"> + <Unit0> + <Filename Value="updater.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="..\bin\updater"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="i386"/> + <TargetOS Value="win32"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + <SmallerCode Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/updaterslim/updater.lpr b/updaterslim/updater.lpr new file mode 100644 index 000000000..967a3eba2 --- /dev/null +++ b/updaterslim/updater.lpr @@ -0,0 +1,70 @@ +program updater; + +uses sysutils, process; + +var + exefile, zipexefile, updatepackagefile, maindir, ozipexefile: String; + counter: Integer; + +{$R *.res} + +begin + if ParamCount<4 then + begin + writeln('Parameters insuficient, ',ParamCount,' of 4'); + readln; + exit; + end; + exefile:=ParamStr(1); + zipexefile:=ParamStr(2); + updatepackagefile:=ParamStr(3); + maindir:=ParamStr(4); + if not (FileExists(zipexefile) or FileExists(updatepackagefile)) then Exit; + counter:=0; + while true do begin + if DeleteFile(exefile) then Break; + if FileExists(exefile) then + begin + Inc(counter); + writeln('Waiting to close ',counter,'/',10,' ',exefile); + Sleep(1000); + end; + if counter=10 then break; + end; + if not FileExists(exefile) then + begin + with TProcess.Create(nil) do try + ozipexefile := ExtractFilePath(zipexefile)+'old_'+ExtractFileName(zipexefile); + if FileExists(ozipexefile) then + DeleteFile(ozipexefile); + RenameFile(zipexefile,ozipexefile); + Executable:=ozipexefile; + CurrentDirectory:=maindir; + Parameters.Add('x'); + Parameters.Add(updatepackagefile); + Parameters.Add('-o'+AnsiQuotedStr(maindir,'"')); + Parameters.Add('-aoa'); + Options:=Options+[poWaitOnExit]; + Execute; + if ExitStatus=0 then + begin + DeleteFile(ozipexefile); + DeleteFile(updatepackagefile); + Executable:=exefile; + Parameters.Clear; + Options:=Options-[poWaitOnExit]; + Execute; + end + else + ReadLn; + finally + Free; + end; + end + else + begin + writeln('Can''t delete file ',exefile); + readln; + end; +end. + From d662d5a6d792d0d1ab3f925c02bedfe0b00597a7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 12:29:13 +0800 Subject: [PATCH 2245/2794] update changelog --- changelog.txt | 7 +++++++ mangadownloader/md.lpi | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 188755412..62d2ff7ba 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,13 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.141.0 (-02-2018) +[+] Added new updater only to extract update package +[*] Download new version in the background +[*] Download mangalist database(s) in the background +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.140.0...0.9.141.0 + 0.9.140.0 (14-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.139.0...0.9.140.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 18c234bc8..6f0971931 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="139"/> + <RevisionNr Value="140"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> From 475e0baea7cb83c33d8fd7444ad7b8f9360c6143 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 12:34:36 +0800 Subject: [PATCH 2246/2794] add log --- baseunits/uDownloadsManager.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 6622fe7fc..bcc57fff6 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -958,10 +958,11 @@ procedure TTaskThread.Execute; sf += Container.PageLinks[i] + LineEnding; end; if c > 0 then begin - Logger.SendWarning(Format('%s, checkforfinish failed=%d/%d "%s" > "%s"', + Logger.SendWarning(Format('%s, checkforfinish failed=%d/%d [%s]"%s" > "%s"', [Self.ClassName, c, Container.PageLinks.Count, + Container.Website, Container.DownloadInfo.Title, Container.ChapterLinks[Container.CurrentDownloadChapterPtr]]) + LineEnding + Trim(sf)); Result := False; From 863c4b20b2a84873eb9da528dc9e3aea8a389013 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 13:09:41 +0800 Subject: [PATCH 2247/2794] updater, backup and restore failed --- updaterslim/updater.lpr | 51 +++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/updaterslim/updater.lpr b/updaterslim/updater.lpr index 967a3eba2..8ae6583cb 100644 --- a/updaterslim/updater.lpr +++ b/updaterslim/updater.lpr @@ -1,9 +1,15 @@ program updater; -uses sysutils, process; +uses + {$ifdef windows} + windows, + {$else} + fileutil, + {$endif} + sysutils, process; var - exefile, zipexefile, updatepackagefile, maindir, ozipexefile: String; + exefile, zipexefile, updatepackagefile, maindir, ozipexefile, oexefile: String; counter: Integer; {$R *.res} @@ -20,21 +26,25 @@ updatepackagefile:=ParamStr(3); maindir:=ParamStr(4); if not (FileExists(zipexefile) or FileExists(updatepackagefile)) then Exit; + oexefile:=ExtractFilePath(exefile)+'old_'+ExtractFileName(exefile); + if FileExists(oexefile) then DeleteFile(oexefile); counter:=0; - while true do begin - if DeleteFile(exefile) then Break; - if FileExists(exefile) then - begin - Inc(counter); - writeln('Waiting to close ',counter,'/',10,' ',exefile); - Sleep(1000); - end; + {$ifdef windows} + windows.CopyFile(pchar(exefile),pchar(oexefile),false); + {$else} + CopyFile(exefile,oexefile); + {$endif} + while FileExists(exefile) do begin + if DeleteFile(exefile) then break; + Inc(counter); + writeln('Waiting to close ',counter,'/',10,' ',exefile); + Sleep(1000); if counter=10 then break; end; if not FileExists(exefile) then begin with TProcess.Create(nil) do try - ozipexefile := ExtractFilePath(zipexefile)+'old_'+ExtractFileName(zipexefile); + ozipexefile:=ExtractFilePath(zipexefile)+'old_'+ExtractFileName(zipexefile); if FileExists(ozipexefile) then DeleteFile(ozipexefile); RenameFile(zipexefile,ozipexefile); @@ -48,6 +58,7 @@ Execute; if ExitStatus=0 then begin + DeleteFile(oexefile); DeleteFile(ozipexefile); DeleteFile(updatepackagefile); Executable:=exefile; @@ -56,7 +67,23 @@ Execute; end else - ReadLn; + begin + readln; + if FileExists(oexefile) then + begin + if FileExists(exefile) then + DeleteFile(oexefile) + else + RenameFile(oexefile,exefile); + end; + if FileExists(ozipexefile) then + begin + if FileExists(zipexefile) then + DeleteFile(ozipexefile) + else + RenameFile(ozipexefile,zipexefile); + end; + end; finally Free; end; From 44e5b7cdf0ec09866e11846d2362927e5f977e6d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 13:15:23 +0800 Subject: [PATCH 2248/2794] Bump version 0.9.141.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 62d2ff7ba..8b2c4c282 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.141.0 (-02-2018) +0.9.141.0 (15-02-2018) [+] Added new updater only to extract update package [*] Download new version in the background [*] Download mangalist database(s) in the background diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 6f0971931..1996a547a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="140"/> + <RevisionNr Value="141"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 46ec58669..bb675e99d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.140.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.140.0/fmd_0.9.140.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.140.0/fmd_0.9.140.0_Win64.7z +VERSION=0.9.141.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.141.0/fmd_0.9.141.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.141.0/fmd_0.9.141.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.141.0/fmd_0.9.141.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.141.0/fmd_0.9.141.0_Win64.7z From ec05756aa802c1f332ca8698eda28c28bf2b5894 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Thu, 15 Feb 2018 10:21:16 +0300 Subject: [PATCH 2249/2794] Updated Turkish localization Updated Turkish to latest. --- mangadownloader/languages/fmd.tr_TR.po | 37 +++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 850222c71..aaffa7fec 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: Free Manga Downloader 0.9.136\n" +"Project-Id-Version: Free Manga Downloader\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: Tmp341 <tmp341@gmail.com>\n" @@ -14,27 +14,25 @@ msgstr "" "X-Poedit-SourceCharset: UTF-8\n" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" msgstr "İptal" #: dbupdater.rs_downloading msgid "Downloading %s" -msgstr "" +msgstr "%s indiriliyor" #: dbupdater.rs_extracting msgid "Extracting %s" -msgstr "" +msgstr "%s çıkartılıyor" #: dbupdater.rs_faileddownload msgid "%s: %d %s" -msgstr "" +msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "" +msgstr "%s: çıkartma başarısız, çıkış durumu = %d" #: dbupdater.rs_faileditems msgid "" @@ -42,20 +40,22 @@ msgid "" "\n" "%s\n" msgstr "" +"Bitirme başarısız:\n" +"\n" +"%s\n" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Başarısız oldu" #: dbupdater.rs_failedtosave msgid "%s: failed to save" -msgstr "" +msgstr "%s: kaydetme başarısız" #: dbupdater.rs_missingzipexe msgid "%s: Missing %s" -msgstr "" +msgstr "%s: eksik %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" @@ -487,14 +487,13 @@ msgid "Save as PNG" msgstr "PNG olarak kaydet" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Durdur" #: selfupdater.rs_downloading msgid "Downloading new version %s" -msgstr "" +msgstr "%s yeni sürümü indiriliyor" #: selfupdater.rs_faileddownload msgid "" @@ -502,32 +501,34 @@ msgid "" "\n" "%d %s\n" msgstr "" +"%s yeni sürümü indirmesi başarısız\n" +"\n" +"%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" -msgstr "" +msgstr "%s çıkartma başarısız, çıkış durumu = %d" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Başarısız oldu" #: selfupdater.rs_failedtosave msgid "Failed to save %s" -msgstr "" +msgstr "%s kaydetme başarısız" #: selfupdater.rs_finishrestart msgid "Download update package finished, restart to proceed?" -msgstr "" +msgstr "Güncelleme paketi indirme tamamlandı, devam etmek için yeniden başlansın mı?" #: selfupdater.rs_finishrestarttitle msgid "Download finished" -msgstr "" +msgstr "İndirme tamamlandı" #: selfupdater.rs_missingzipexe msgid "Missing %s" -msgstr "" +msgstr "%s eksik" #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" From 23fe6344d37dee81cfa928324c3ec480831a9ae8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Feb 2018 13:53:21 +0300 Subject: [PATCH 2250/2794] LuaWebsiteModules, add TotalDirectory --- baseunits/lua/LuaWebsiteModules.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 0f4090313..97e0cc505 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -755,6 +755,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.MaxTaskLimit); luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', @Module.MaxConnectionLimit); + luaClassAddIntegerProperty(L, MetaTable, 'TotalDirectory', @Module.TotalDirectory); luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', @Module.ActiveTaskCount); luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', @Module.ActiveConnectionCount); From 2a4c27d2a3a47cf36985815c3c9b81a8d2142770 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Feb 2018 13:56:11 +0300 Subject: [PATCH 2251/2794] CentralDeMangas, move to lua --- .../CentralDeMangas/directory_page_number.inc | 35 ------ .../includes/CentralDeMangas/image_url.inc | 40 ------- .../CentralDeMangas/manga_information.inc | 104 ------------------ .../CentralDeMangas/names_and_links.inc | 39 ------- baseunits/uBaseUnit.pas | 28 ++--- baseunits/uData.pas | 15 --- baseunits/uDownloadsManager.pas | 5 - config/mangalist.ini | 2 +- lua/modules/CentralDeMangas.lua | 77 +++++++++++++ 9 files changed, 90 insertions(+), 255 deletions(-) delete mode 100644 baseunits/includes/CentralDeMangas/directory_page_number.inc delete mode 100644 baseunits/includes/CentralDeMangas/image_url.inc delete mode 100644 baseunits/includes/CentralDeMangas/manga_information.inc delete mode 100644 baseunits/includes/CentralDeMangas/names_and_links.inc create mode 100644 lua/modules/CentralDeMangas.lua diff --git a/baseunits/includes/CentralDeMangas/directory_page_number.inc b/baseunits/includes/CentralDeMangas/directory_page_number.inc deleted file mode 100644 index 2c0ea5d56..000000000 --- a/baseunits/includes/CentralDeMangas/directory_page_number.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetCentralDeMangasDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + - CENTRALDEMANGAS_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('/mangas/list/*/', parse[i]) > 0) then - begin - s := TrimRight(TrimLeft(GetString(parse[i], '/mangas/list/*/', '">'))); - APage := StrToInt(s); - Result := NO_ERROR; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/CentralDeMangas/image_url.inc b/baseunits/includes/CentralDeMangas/image_url.inc deleted file mode 100644 index 01da6bafa..000000000 --- a/baseunits/includes/CentralDeMangas/image_url.inc +++ /dev/null @@ -1,40 +0,0 @@ - function GetCentralDeMangasImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := EncodeUrl(FillMangaSiteHost(CENTRALDEMANGAS_ID, URL)); - // + IntToStr(WorkId+1)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('var pages = ', parse[i]) > 0 then - begin - s := StringReplace(parse[i], '\/', '/', [rfReplaceAll]); - repeat - j := Pos('http://', s); - Task.Container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); - s := StringReplace(s, '"', '', []); - s := StringReplace(s, '"', '', []); - Delete(s, j, 10); - j := Pos('http://', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/CentralDeMangas/manga_information.inc b/baseunits/includes/CentralDeMangas/manga_information.inc deleted file mode 100644 index 2a4331ac4..000000000 --- a/baseunits/includes/CentralDeMangas/manga_information.inc +++ /dev/null @@ -1,104 +0,0 @@ - function GetCentralDeMangasInfoFromURL: Byte; - var - isExtractGenres: Boolean = False; - i: Cardinal; - begin - mangaInfo.website := WebsiteRoots[CENTRALDEMANGAS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(CENTRALDEMANGAS_ID, AURL); - if not GetPage(TObject(Source), EncodeURL(mangaInfo.url), AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // convert charset - // source.Text:= ISO_8859_1ToUTF8(source.Text); - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('class="img-thumbnail"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); - - // get summary - if (Pos('class="img-thumbnail"', parse[i]) > 0) then - mangaInfo.summary := parse[i + 6]; - - // get title - if (mangaInfo.title = '') and - (Pos('<title>', parse[i]) <> 0) then - mangaInfo.title := TrimLeft(HTMLEntitiesFilter( - StringFilter(GetString('~!@' + parse[i + 1], '~!@', ' || Central de Mangás')))); - - // get chapter name and links - if Pos('class="col-xs-1 col-sm-1 col-md-1 col-lg-1"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.chapterName.Add(RemoveSymbols(Trim(parse[i + 1]))); - end; - - // get authors - if (i + 12 < parse.Count) and - (Pos('Autor', parse[i]) <> 0) and - (Pos('<h4>', parse[i - 1]) <> 0) then - mangaInfo.authors := TrimLeft(TrimRight(parse[i + 12])); - - // get artists - if (i + 12 < parse.Count) and - (Pos('Arte', parse[i]) <> 0) and - (Pos('<h4>', parse[i - 1]) <> 0) then - mangaInfo.artists := TrimLeft(TrimRight(parse[i + 12])); - - // get genres - if (i + 1 < parse.Count) and - (Pos('Gênero', parse[i]) <> 0) and - (Pos('</h4>', parse[i + 1]) <> 0) and - (Pos('<h4>', parse[i - 1]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if (Pos('<h4>', parse[i]) > 0) and - (Pos('Scantrad', parse[i + 1]) > 0) and - (Pos('</h4>', parse[i + 2]) > 0) then - isExtractGenres := False; - - if Pos('class="btn btn-xs btn-primary"', parse[i]) > 0 then - if mangaInfo.genres = '' then - mangaInfo.genres := parse[i + 1] - else - mangaInfo.genres := mangaInfo.genres + ', ' + parse[i + 1]; - end; - - // get status - if (i + 12 < parse.Count) and - (Pos('Status', parse[i]) <> 0) and - (Pos('<h4>', parse[i - 1]) <> 0) then - begin - if (Pos('Completo', parse[i + 12]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/CentralDeMangas/names_and_links.inc b/baseunits/includes/CentralDeMangas/names_and_links.inc deleted file mode 100644 index 9764a5efd..000000000 --- a/baseunits/includes/CentralDeMangas/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function CentralDeMangasGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[CENTRALDEMANGAS_ID, 1] + - CENTRALDEMANGAS_BROWSER + '/' + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/mangas/info/', parse[i]) > 0) and - (Pos('<td>', parse[i - 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse[i + 1]); - ANames.Add(HTMLEntitiesFilter(s)); - s := StringReplace(GetString(parse[i], 'href="', '"'), - WebsiteRoots[CENTRALDEMANGAS_ID, 1], '', []); - ALinks.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 482a8d551..1372e88b4 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -230,23 +230,21 @@ interface VNSHARING_ID = 0; TURKCRAFT_ID = 1; ANIMEEXTREMIST_ID = 2; - CENTRALDEMANGAS_ID = 3; - ANIMESTORY_ID = 4; - SCANMANGA_ID = 5; - MANGASPROJECT_ID = 6; - MANGAREADER_POR_ID = 7; - MANGATOWN_ID = 8; - MANGAOKU_ID = 9; - NHENTAI_ID = 10; - MANGAHOST_ID = 11; - MANGAKU_ID = 12; - DYNASTYSCANS_ID = 13; - - WebsiteRoots: array [0..13] of array [0..1] of String = ( + ANIMESTORY_ID = 3; + SCANMANGA_ID = 4; + MANGASPROJECT_ID = 5; + MANGAREADER_POR_ID = 6; + MANGATOWN_ID = 7; + MANGAOKU_ID = 8; + NHENTAI_ID = 9; + MANGAHOST_ID = 10; + MANGAKU_ID = 11; + DYNASTYSCANS_ID = 12; + + WebsiteRoots: array [0..12] of array [0..1] of String = ( ('VnSharing', 'http://truyen.vnsharing.net'), ('Turkcraft', 'http://turkcraft.com'), ('AnimExtremist', 'http://www.animextremist.com'), - ('CentralDeMangas', 'http://centraldemangas.com.br'), ('AnimeStory', 'http://www.anime-story.com'), ('ScanManga', 'http://www.scan-manga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), @@ -268,8 +266,6 @@ interface ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; - CENTRALDEMANGAS_BROWSER = '/mangas/list/*'; - ANIMESTORY_BROWSER = '/mangas/'; SCANMANGA_BROWSER = '/scanlation/liste_des_mangas.html'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index c093995cb..ea0aab625 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -786,8 +786,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/VnSharing/directory_page_number.inc} - {$I includes/CentralDeMangas/directory_page_number.inc} - {$I includes/MangaTown/directory_page_number.inc} {$I includes/NHentai/directory_page_number.inc} @@ -826,9 +824,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = VNSHARING_ID then Result := GetVnSharingDirectoryPageNumber else - if MangaSiteID = CENTRALDEMANGAS_ID then - Result := GetCentralDeMangasDirectoryPageNumber - else if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownDirectoryPageNumber else @@ -868,8 +863,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/ScanManga/names_and_links.inc} - {$I includes/CentralDeMangas/names_and_links.inc} - {$I includes/Turkcraft/names_and_links.inc} {$I includes/MangasPROJECT/names_and_links.inc} @@ -914,9 +907,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = SCANMANGA_ID then Result := ScanMangaGetNamesAndLinks else - if MangaSiteID = CENTRALDEMANGAS_ID then - Result := CentralDeMangasGetNamesAndLinks - else if MangaSiteID = TURKCRAFT_ID then Result := TurkcraftGetNamesAndLinks else @@ -978,8 +968,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/Turkcraft/manga_information.inc} - {$I includes/CentralDeMangas/manga_information.inc} - {$I includes/MangasPROJECT/manga_information.inc} {$I includes/MangaREADER_POR/manga_information.inc} @@ -1039,9 +1027,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftInfoFromURL else - if MangaSiteID = CENTRALDEMANGAS_ID then - Result := GetCentralDeMangasInfoFromURL - else if MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index bcc57fff6..7d57fee16 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -473,8 +473,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/image_url.inc} - {$I includes/CentralDeMangas/image_url.inc} - {$I includes/MangaREADER_POR/image_url.inc} {$I includes/MangasPROJECT/image_url.inc} @@ -515,9 +513,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = TURKCRAFT_ID then Result := GetTurkcraftImageURL else - if Task.Container.MangaSiteID = CENTRALDEMANGAS_ID then - Result := GetCentralDeMangasImageURL - else if Task.Container.MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 19802d27b..73739b977 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -12,7 +12,7 @@ German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics Malaysian-Indonesian= Polish= -Portugues=CentralDeMangas,MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas +Portugues=MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline diff --git a/lua/modules/CentralDeMangas.lua b/lua/modules/CentralDeMangas.lua new file mode 100644 index 000000000..90d337858 --- /dev/null +++ b/lua/modules/CentralDeMangas.lua @@ -0,0 +1,77 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//div[@id="main"]//h1') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//div[@id="main"]//div[@class="description"]/img/@src')) + mangainfo.summary = x.XPathStringAll('//div[@id="main"]//div[@class="description"]/div/text()', '') + mangainfo.artists = x.XPathStringAll('//div[@id="main"]//div[@class="content" and contains(div[@class="header"], "Arte")]/div[@class="description"]/a') + mangainfo.authors = x.XPathStringAll('//div[@id="main"]//div[@class="content" and contains(div[@class="header"], "Autor")]/div[@class="description"]/a') + mangainfo.genres = x.XPathStringAll('//div[@id="main"]//div[@class="content" and contains(div[@class="header"], "Gênero")]/div[@class="description"]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@id="main"]//div[@class="content" and contains(div[@class="header"], "Status")]/div[@class="description"]/a'), 'publicação', 'completo') + x.XPathHREFAll('//table/tbody/tr/td/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_error + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl,url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "urlSulfix")]') + local suffix = GetBetween("var urlSulfix = '", "';", s) + local pages = GetBetween("var pages =", ";", s) + x.parsehtml(pages) + local v = x.xpath('json(*)()'); + for i = 1, v.count do + local v1=v.get(i) + task.pagelinks.add(suffix .. v1.ToString .. '.jpg') + end + return true + else + return false + end +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function GetNameAndLink() + if http.get(module.rooturl..'/titulos/filtro/*/p/'..IncStr(url)) then + x=TXQuery.Create(http.Document) + x.XPathHREFAll('//div[contains(@class, "list")]/div[contains(@class, "item")]/div[@class="content"]//a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/titulos') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('(//div[contains(@class, "grid")]/div/a[contains(@class, "button")])[last()]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Portugues' + m.website='CentralDeMangas' + m.rooturl='http://centraldemangas.inf.br' + m.lastupdated='February 15, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' +end \ No newline at end of file From 51e4ecd22d2c6cef8f34cabf194707a5002f7f77 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 19:03:02 +0800 Subject: [PATCH 2252/2794] luawebsitemodule, add totaldirectory --- baseunits/lua/LuaWebsiteModules.pas | 14 ++++++++++++++ mangadownloader/md.lpi | 9 ++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 97e0cc505..5d34ec739 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -706,6 +706,18 @@ function lua_addoptioncombobox(L: Plua_State): Integer; cdecl; lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3), lua_tointeger(L, 4)); end; +function lua_gettotaldirectory(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TLuaWebsiteModule(luaClassGetObject(L)).Module.TotalDirectory); + Result := 1; +end; + +function lua_settotaldirectory(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TLuaWebsiteModule(luaClassGetObject(L)).Module.TotalDirectory := lua_tointeger(L, 1); +end; + function lua_getoption(L: Plua_State): Integer; cdecl; var m: TLuaWebsiteModule; @@ -785,6 +797,8 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'OnLogin', @OnLogin); luaClassAddStringProperty(L, MetaTable, 'LastUpdated', @LastUpdated); + luaClassAddProperty(L, MetaTable, UserData, 'TotalDirectory', @lua_gettotaldirectory, @lua_settotaldirectory); + luaClassAddFunction(L, MetaTable, UserData, methods); luaClassAddObject(L, MetaTable, Storage, 'Storage'); diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1996a547a..e59de09b6 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="11"/> + <Version Value="10"/> <PathDelim Value="\"/> <General> <SessionStorage Value="InProjectDir"/> @@ -267,10 +267,9 @@ <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> - <FormatVersion Value="2"/> - <Modes Count="1"> - <Mode0 Name="default"/> - </Modes> + <local> + <FormatVersion Value="1"/> + </local> </RunParams> <RequiredPackages Count="9"> <Item1> From c46f00ecf5f81d066617223589dd78154e55e968 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 15 Feb 2018 19:20:23 +0800 Subject: [PATCH 2253/2794] luawebsitemodule, add currentdirectoryindex (#909) --- baseunits/lua/LuaWebsiteModules.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 5d34ec739..ab464fd79 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -796,6 +796,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'OnAfterImageSaved', @OnAfterImageSaved); luaClassAddStringProperty(L, MetaTable, 'OnLogin', @OnLogin); luaClassAddStringProperty(L, MetaTable, 'LastUpdated', @LastUpdated); + luaClassAddIntegerProperty(L, MetaTable, 'CurrentDirectoryIndex', @Module.CurrentDirectoryIndex); luaClassAddProperty(L, MetaTable, UserData, 'TotalDirectory', @lua_gettotaldirectory, @lua_settotaldirectory); From d66a3bb86bd50bf67a77cde19e302fe7b8f59ff5 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Feb 2018 14:34:03 +0300 Subject: [PATCH 2254/2794] LuaWebsiteModules, fix erroneous totaldirectory --- baseunits/lua/LuaWebsiteModules.pas | 1 - 1 file changed, 1 deletion(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index ab464fd79..00ef568ef 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -767,7 +767,6 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.MaxTaskLimit); luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', @Module.MaxConnectionLimit); - luaClassAddIntegerProperty(L, MetaTable, 'TotalDirectory', @Module.TotalDirectory); luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', @Module.ActiveTaskCount); luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', @Module.ActiveConnectionCount); From 0f4a3c3ad0b38a44cec6620b6d4c613f69de01a8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Feb 2018 14:39:28 +0300 Subject: [PATCH 2255/2794] update Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 2be28433b..c12265ebe 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -12,27 +12,25 @@ msgstr "" "X-Generator: Poedit 2.0.2\n" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" msgstr "Отмена" #: dbupdater.rs_downloading msgid "Downloading %s" -msgstr "" +msgstr "Скачивание %s" #: dbupdater.rs_extracting msgid "Extracting %s" -msgstr "" +msgstr "Извлечение %s" #: dbupdater.rs_faileddownload msgid "%s: %d %s" -msgstr "" +msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "" +msgstr "%s: ошибка при извлечении, exitstatus = %d" #: dbupdater.rs_faileditems msgid "" @@ -40,6 +38,9 @@ msgid "" "\n" "%s\n" msgstr "" +"Не удалось завершить:\n" +"\n" +"%s\n" #: dbupdater.rs_faileditemstitle #, fuzzy @@ -49,11 +50,11 @@ msgstr "Неудачно" #: dbupdater.rs_failedtosave msgid "%s: failed to save" -msgstr "" +msgstr "%s: ошибка при сохранении" #: dbupdater.rs_missingzipexe msgid "%s: Missing %s" -msgstr "" +msgstr "%s: отсутствует %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" From c116d341ef88c7315881714868c14242cc207391 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Feb 2018 17:20:45 +0300 Subject: [PATCH 2256/2794] add manhwa.co, fixes #792 --- lua/modules/ManhwaCo.lua | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lua/modules/ManhwaCo.lua diff --git a/lua/modules/ManhwaCo.lua b/lua/modules/ManhwaCo.lua new file mode 100644 index 000000000..79ee0abde --- /dev/null +++ b/lua/modules/ManhwaCo.lua @@ -0,0 +1,60 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//h4[@class="card-title"]') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[contains(@class, "card-img-top")]/@src')) + mangainfo.summary = x.XPathString('//p[@class="card-text"]') + mangainfo.genres = x.XPathStringAll('//div[@class="chip"]') + v=x.xpath('//div[contains(@class, "list-group")]/a') + for i=1,v.count do + v1=v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('href')) + mangainfo.chapternames.add(x.xpathstring('./text()', v1)) + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_error + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl,url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="container"]/div/div/img/@src', task.pagelinks) + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/series') then + x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="container"]/div[@class="row"]//h5', names) + x.xpathstringall('//div[@class="container"]//div[contains(@class,"card")]//div/a/@href', links) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + page=1 + return no_error +end + +function Init() + m=NewModule() + m.category='English-Scanlation' + m.website='ManhwaCo' + m.rooturl='https://manhwa.co' + m.lastupdated='February 15, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' +end \ No newline at end of file From 208ba54484420e200ade7120fc77ad47400658c9 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 00:54:32 +0800 Subject: [PATCH 2257/2794] added base.ini and cleanup --- baseunits/DBUpdater.pas | 4 +- baseunits/FMDOptions.pas | 33 ++- baseunits/uBaseUnit.pas | 12 - baseunits/uUpdateThread.pas | 262 ++++++++---------- config/base.ini | 7 + .../forms/frmLuaModulesUpdater.pas | 7 +- mangadownloader/forms/frmMain.pas | 5 - mangadownloader/md.lpi | 9 +- 8 files changed, 164 insertions(+), 175 deletions(-) create mode 100644 config/base.ini diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 8f6bc607e..dfa93f890 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -67,8 +67,8 @@ implementation function GetDBURL(const AName: String): String; begin - if Pos('<website>', AnsiLowerCase(DBDownloadURL)) <> -1 then - Result := StringReplace(DBDownloadURL, '<website>', AName, [rfIgnoreCase, rfReplaceAll]) + if Pos('<website>', AnsiLowerCase(DB_URL)) <> -1 then + Result := StringReplace(DB_URL, '<website>', AName, [rfIgnoreCase, rfReplaceAll]) else Result := AName; end; diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 01f73e658..8bc5737f7 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -25,10 +25,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) TFMDDo = (DO_NOTHING, DO_EXIT, DO_POWEROFF, DO_HIBERNATE, DO_UPDATE); const - UPDATE_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/update'; - CHANGELOG_URL = 'https://raw.githubusercontent.com/riderkick/FMD/master/changelog.txt'; - UPDATE_PACKAGE_NAME = 'updatepackage.7z'; - FMD_REVISION = '$WCREV$'; FMD_INSTANCE = '_FreeMangaDownloaderInstance_'; FMD_TARGETOS = {$i %FPCTARGETOS%}; @@ -89,6 +85,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) REVISION_FILE, UPDATE_FILE, MANGALIST_FILE, + BASE_FILE, ACCOUNTS_FILE, WEBSITE_CONFIG_FILE, DATA_FOLDER, @@ -109,8 +106,13 @@ TIniFileRun = class(IniFiles.TMemIniFile) configfile, advancedfile: TIniFileRun; - // db data download url - DBDownloadURL: String = 'https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download'; + // base url, should be in base.ini + DB_URL: String = 'https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download'; + UPDATE_URL: String = 'https://raw.githubusercontent.com/riderkick/FMD/master/update'; + CHANGELOG_URL: String = 'https://raw.githubusercontent.com/riderkick/FMD/master/changelog.txt'; + UPDATE_PACKAGE_NAME: String = 'updatepackage.7z'; + MODULES_URL: String = 'https://api.github.com/repos/riderkick/FMD/contents/lua/modules'; + MODULES_URL2: String = 'https://github.com/riderkick/FMD/file-list/master/lua/modules'; currentWebsite: String; @@ -264,6 +266,22 @@ procedure SetIniFiles; advancedfile := TIniFileRun.Create(CONFIG_ADVANCED); end; +procedure ReadBaseFile; +begin + if not FileExistsUTF8(BASE_FILE) then Exit; + with TIniFile.Create(BASE_FILE) do + try + DB_URL:=ReadString('base','DB_URL',DB_URL); + UPDATE_URL:=ReadString('base','UPDATE_URL',UPDATE_URL); + CHANGELOG_URL:=ReadString('base','CHANGELOG_URL',CHANGELOG_URL); + UPDATE_PACKAGE_NAME:=ReadString('base','UPDATE_PACKAGE_NAME',UPDATE_PACKAGE_NAME); + MODULES_URL:=ReadString('base','MODULES_URL',MODULES_URL); + MODULES_URL2:=ReadString('base','MODULES_URL2',MODULES_URL2); + finally + Free; + end; +end; + procedure SetFMDdirectory(const ADir: String); begin FMD_DIRECTORY := CleanAndExpandDirectory(ADir); @@ -273,6 +291,7 @@ procedure SetFMDdirectory(const ADir: String); REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; MANGALIST_FILE := CONFIG_FOLDER + 'mangalist.ini'; + BASE_FILE := CONFIG_FOLDER + 'base.ini'; IMAGE_FOLDER := FMD_DIRECTORY + 'images' + PathDelim; LANGUAGE_FILE := FMD_DIRECTORY + 'languages.ini'; @@ -287,6 +306,8 @@ procedure SetFMDdirectory(const ADir: String); LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; LUA_WEBSITEMODULE_REPOS := CONFIG_FOLDER + 'luamodules.json'; + + ReadBaseFile; end; procedure SetAppDataDirectory(const ADir: String); diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 1372e88b4..8d7c77101 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -483,7 +483,6 @@ function GetMangaSiteID(const Name: String): Integer; function GetMangaSiteName(const ID: Integer): String; function GetMangaSiteRoot(const Website: String): String; overload; function GetMangaSiteRoot(const MangaID: Integer): String; overload; -function GetMangaDatabaseURL(const AWebsite: String): String; function SitesMemberOf(const website: String; MangaSiteIDs: array of Integer): Boolean; function SitesWithSortedList(const website: String): Boolean; @@ -996,17 +995,6 @@ function GetMangaSiteRoot(const MangaID: Integer): String; Result := WebsiteRoots[MangaID, 1]; end; -function GetMangaDatabaseURL(const AWebsite: String): String; -begin - if DBDownloadURL = '' then - DBDownloadURL := 'https://bintray.com/artifact/download/riderkick/FMD/db/<website>.7z'; - Result := DBDownloadURL; - if Pos('<website>', LowerCase(Result)) > 0 then - Result := StringReplace(Result, '<website>', AWebsite, [rfIgnoreCase, rfReplaceAll]) - else - Result := Result + AWebsite; -end; - function SitesMemberOf(const website: String; MangaSiteIDs: array of Integer): Boolean; var i: Integer; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 611740850..0b510e4d6 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -64,7 +64,7 @@ TUpdateListManagerThread = class(TBaseThread) CS_Threads, CS_AddInfoToData, CS_AddNamesAndLinks: TRTLCriticalSection; - isFinishSearchingForNewManga, isDownloadFromServer, isDoneUpdateNecessary: Boolean; + isFinishSearchingForNewManga, isDoneUpdateNecessary: Boolean; mainDataProcess: TDBDataProcess; tempDataProcess: TDBDataProcess; websites: TStringList; @@ -361,20 +361,14 @@ procedure TUpdateListManagerThread.RefreshList; dataProcess := TDBDataProcess.Create else dataProcess.Close; - if isDownloadFromServer then - ExtractFile - else - OverwriteDBDataProcess(website, twebsite); + OverwriteDBDataProcess(website, twebsite); OpenDataDB(website); end else begin if dataProcess.WebsiteLoaded(website) then dataProcess.RemoveFilter; - if isDownloadFromServer then - ExtractFile - else - OverwriteDBDataProcess(website, twebsite); + OverwriteDBDataProcess(website, twebsite); end; end; except @@ -547,158 +541,144 @@ procedure TUpdateListManagerThread.Execute; Exit; try websitePtr := 0; - if isDownloadFromServer then + while websitePtr < websites.Count do begin - while websitePtr < websites.Count do - begin - website := websites.Strings[websitePtr]; - Inc(websitePtr); - FStatus := RS_GettingListFor + ' ' + website + ' ...'; - Synchronize(MainThreadShowGetting); - RunExternalProcess(FMD_DIRECTORY + UPDATER_EXE, ['-r' , '3', '-d', - GetMangaDatabaseURL(website), '--lang', SimpleTranslator.LastSelected]); - Synchronize(RefreshList); - end; - end - else - while websitePtr < websites.Count do - begin - FThreadAborted:=True; - website := websites.Strings[websitePtr]; - ModuleId := Modules.LocateModule(website); - SortedList := SitesWithSortedList(website); - NoMangaInfo := SitesWithoutInformation(website); - Inc(websitePtr); - - cloghead:=Self.ClassName+', '+website+': '; - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; - Synchronize(MainThreadShowGetting); + FThreadAborted:=True; + website := websites.Strings[websitePtr]; + ModuleId := Modules.LocateModule(website); + SortedList := SitesWithSortedList(website); + NoMangaInfo := SitesWithoutInformation(website); + Inc(websitePtr); + + cloghead:=Self.ClassName+', '+website+': '; + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; + Synchronize(MainThreadShowGetting); + + twebsite:='__'+website; + twebsitetemp:=twebsite+'_templist'; + try + DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); + if (dataProcess.Website = website) and + (dataProcess.Connected) then + dataProcess.Backup(twebsite) + else + begin + if dataProcess.WebsiteLoaded(website) then + Synchronize(MainThreadRemoveFilter); + CopyDBDataProcess(website, twebsite); + end; - twebsite:='__'+website; - twebsitetemp:=twebsite+'_templist'; - try - DeleteDBDataProcess(twebsite); - DeleteDBDataProcess(twebsitetemp); - if (dataProcess.Website = website) and - (dataProcess.Connected) then - dataProcess.Backup(twebsite) - else - begin - if dataProcess.WebsiteLoaded(website) then - Synchronize(MainThreadRemoveFilter); - CopyDBDataProcess(website, twebsite); - end; + if not mainDataProcess.Connect(twebsite) then + mainDataProcess.CreateDatabase(twebsite); + tempDataProcess.CreateDatabase(twebsitetemp); + + // get directory page count + directoryCount := 0; + workPtr := 0; + if ModuleId <> -1 then begin + Modules.BeforeUpdateList(ModuleId); + GetInfo(Modules[ModuleId].TotalDirectory, CS_DIRECTORY_COUNT); + end + else + GetInfo(1, CS_DIRECTORY_COUNT); - if not mainDataProcess.Connect(twebsite) then - mainDataProcess.CreateDatabase(twebsite); - tempDataProcess.CreateDatabase(twebsitetemp); + if Terminated then begin + if ModuleId <> -1 then + Modules.AfterUpdateList(ModuleId); + Break; + end; - // get directory page count - directoryCount := 0; - workPtr := 0; - if ModuleId <> -1 then begin - Modules.BeforeUpdateList(ModuleId); - GetInfo(Modules[ModuleId].TotalDirectory, CS_DIRECTORY_COUNT); - end - else - GetInfo(1, CS_DIRECTORY_COUNT); + mainDataProcess.OpenTable('',True); + FIsPreListAvailable:=mainDataProcess.RecordCount>0; + mainDataProcess.CloseTable; - if Terminated then begin - if ModuleId <> -1 then - Modules.AfterUpdateList(ModuleId); - Break; + // get names and links + workPtr := 0; + isFinishSearchingForNewManga := False; + if ModuleId <> -1 then + begin + with Modules.Module[ModuleId] do + begin + j := Low(TotalDirectoryPage); + while j <= High(TotalDirectoryPage) do + begin + workPtr := 0; + isFinishSearchingForNewManga := False; + CurrentDirectoryIndex := j; + GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); + Inc(j); + if Terminated then Break; + end; end; + end + else + GetInfo(directoryCount, CS_DIRECTORY_PAGE); - mainDataProcess.OpenTable('',True); - FIsPreListAvailable:=mainDataProcess.RecordCount>0; - mainDataProcess.CloseTable; + if ModuleId <> -1 then + Modules.BeforeUpdateList(ModuleId); + if Terminated then Break; - // get names and links + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; + Synchronize(MainThreadShowGetting); + + tempDataProcess.OpenTable('', True); + // get manga info + if tempDataProcess.RecordCount>0 then + begin workPtr := 0; - isFinishSearchingForNewManga := False; - if ModuleId <> -1 then + FCommitCount := 0; + if NoMangaInfo or + OptionUpdateListNoMangaInfo then begin - with Modules.Module[ModuleId] do + Inc(workPtr); + for k:=0 to tempDataProcess.RecordCount-1 do begin - j := Low(TotalDirectoryPage); - while j <= High(TotalDirectoryPage) do - begin - workPtr := 0; - isFinishSearchingForNewManga := False; - CurrentDirectoryIndex := j; - GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); - Inc(j); - if Terminated then Break; - end; + mainDataProcess.AddData( + tempDataProcess.Value[k,DATA_PARAM_TITLE], + tempDataProcess.Value[k,DATA_PARAM_LINK], + '', + '', + '', + '', + '', + 0, + Now + ); + CheckCommit(5000); end; end else - GetInfo(directoryCount, CS_DIRECTORY_PAGE); - - if ModuleId <> -1 then - Modules.BeforeUpdateList(ModuleId); - if Terminated then Break; - - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; - Synchronize(MainThreadShowGetting); + GetInfo(tempDataProcess.RecordCount, CS_INFO); + mainDataProcess.Commit; - tempDataProcess.OpenTable('', True); - // get manga info - if tempDataProcess.RecordCount>0 then + if (workPtr > 0) and (not (Terminated and SortedList)) then begin - workPtr := 0; - FCommitCount := 0; - if NoMangaInfo or - OptionUpdateListNoMangaInfo then - begin - Inc(workPtr); - for k:=0 to tempDataProcess.RecordCount-1 do - begin - mainDataProcess.AddData( - tempDataProcess.Value[k,DATA_PARAM_TITLE], - tempDataProcess.Value[k,DATA_PARAM_LINK], - '', - '', - '', - '', - '', - 0, - Now - ); - CheckCommit(5000); - end; - end - else - GetInfo(tempDataProcess.RecordCount, CS_INFO); - mainDataProcess.Commit; - - if (workPtr > 0) and (not (Terminated and SortedList)) then - begin - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; - Synchronize(MainThreadShowGetting); - mainDataProcess.Sort; - mainDataProcess.Close; - Synchronize(RefreshList); - end; + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; + Synchronize(MainThreadShowGetting); + mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); end; - except - on E: Exception do - Logger.SendException(cloghead + 'error occured!', E); end; + except + on E: Exception do + Logger.SendException(cloghead + 'error occured!', E); + end; - tempDataProcess.Close; - mainDataProcess.Close; - DeleteDBDataProcess(twebsite); - DeleteDBDataProcess(twebsitetemp); + tempDataProcess.Close; + mainDataProcess.Close; + DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); - if Terminated then - Break; - websites[websitePtr - 1] := UTF8Encode(#$2714) + websites[websitePtr - 1]; - FThreadAborted:=False; - end; + if Terminated then + Break; + websites[websitePtr - 1] := UTF8Encode(#$2714) + websites[websitePtr - 1]; + FThreadAborted:=False; + end; except on E: Exception do MainForm.ExceptionHandler(Self, E); diff --git a/config/base.ini b/config/base.ini new file mode 100644 index 000000000..34e180caf --- /dev/null +++ b/config/base.ini @@ -0,0 +1,7 @@ +[base] +DB_URL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download +UPDATE_URL=https://raw.githubusercontent.com/riderkick/FMD/master/update +CHANGELOG_URL=https://raw.githubusercontent.com/riderkick/FMD/master/changelog.txt +UPDATE_PACKAGE_NAME=updatepackage.7z +MODULES_URL=https://api.github.com/repos/riderkick/FMD/contents/lua/modules +MODULES_URL2=https://github.com/riderkick/FMD/file-list/master/lua/modules diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index 1a936ba78..ee704b293 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -148,9 +148,6 @@ TCheckUpdateThread = class(TBaseThread) var LuaModulesUpdaterForm: TLuaModulesUpdaterForm; - LuaModulesURLJSON: String = - 'https://api.github.com/repos/riderkick/FMD/contents/lua/modules'; - LuaModulesURLHTML: String = 'https://github.com/riderkick/FMD/file-list/master/lua/modules'; resourcestring RS_CheckUpdate = 'Check update'; @@ -690,11 +687,11 @@ procedure TCheckUpdateThread.Execute; trepos: TLuaModulesRepos; begin Synchronize(@SyncStartChecking); - if FHTTP.GET(LuaModulesURLJSON) then + if FHTTP.GET(MODULES_URL) then begin FReposUp := TLuaModulesRepos.Create; FReposUp.LoadFromRemote(FHTTP); - if FHTTP.GET(LuaModulesURLHTML) then + if FHTTP.GET(MODULES_URL2) then FReposUp.LoadFromRemoteHTML(FHTTP); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 422fb8f90..e05b47a0e 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3228,7 +3228,6 @@ procedure TMainForm.mnUpdate1ClickClick(Sender: TObject); updateList := TUpdateListManagerThread.Create; for i := 0 to cbSelectManga.Items.Count - 1 do updateList.websites.Add(cbSelectManga.Items[i]); - updateList.isDownloadFromServer := False; updateList.Start; end; end @@ -3284,7 +3283,6 @@ procedure TMainForm.mnUpdateListClick(Sender: TObject); updateList := TUpdateListManagerThread.Create; updateList.numberOfThreads := 4; updateList.websites.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); - updateList.isDownloadFromServer := False; updateList.Start; end; end @@ -5266,9 +5264,6 @@ procedure TMainForm.LoadMangaOptions; // read mangalist.ini with TIniFile.Create(MANGALIST_FILE) do try - // databases download url - DBDownloadURL := ReadString('general', 'DBDownloadURL', DBDownloadURL); - // read available websites ReadSection('available', categories); for i := 0 to categories.Count - 1 do diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e59de09b6..1996a547a 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="10"/> + <Version Value="11"/> <PathDelim Value="\"/> <General> <SessionStorage Value="InProjectDir"/> @@ -267,9 +267,10 @@ <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> - <local> - <FormatVersion Value="1"/> - </local> + <FormatVersion Value="2"/> + <Modes Count="1"> + <Mode0 Name="default"/> + </Modes> </RunParams> <RequiredPackages Count="9"> <Item1> From 9a4422fceb5ebe7c7e04efa9a1b3e578da25df65 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Feb 2018 20:32:21 +0300 Subject: [PATCH 2258/2794] add HentaiHere --- lua/modules/HentaiHere.lua | 73 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lua/modules/HentaiHere.lua diff --git a/lua/modules/HentaiHere.lua b/lua/modules/HentaiHere.lua new file mode 100644 index 000000000..0814fb6de --- /dev/null +++ b/lua/modules/HentaiHere.lua @@ -0,0 +1,73 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//h4/a/text()') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//div[@id="cover"]//img/@src')) + mangainfo.artists = x.XPathString('//div[@id="info"]/div[contains(span, "Artist")]/a') + mangainfo.genres = x.XPathStringAll('//div[@id="info"]/div[contains(span, "Category")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@id="info"]/div[contains(span, "Status")]/a')) + mangainfo.summary=x.XPathStringall('//div[@id="info"]/div[contains(span, "Summary")]/text()', '') + v=x.xpath('//ul[@class="arf-list"]/li/a') + for i=1,v.count do + v1=v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + mangainfo.chapternames.add(x.xpathstring('./span/text()', v1)) + end + return no_error + else + return net_error + end +end + +function GetPageNumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + s=x.xpathstring('//script[contains(.,"rff_imageList")]') + s=GetBetween('rff_imageList =', ';', s) + x.parsehtml(s) + v=x.xpath('json(*)()') + for i=1,v.count do + v1=v.get(i) + print(v1.toString) + task.pagelinks.add('https://hentaicdn.com/hentai' .. v1.toString) + end + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/directory/newest?page='..IncStr(url)) then + x=TXQuery.Create(http.Document) + v=x.XPathHREFAll('//div[contains(@class, "seriesBlock")]/div/div[2]/a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL..'/directory/newest') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('(//ul[contains(@class,"pagination")]/li/a)[last()-1]')) + if page == nil then page = 1 end + return true + else + return false + end +end + +function Init() + m=NewModule() + m.category='H-Sites' + m.website='HentaiHere' + m.rooturl='https://hentaihere.com' + m.sortedlist=true + m.lastupdated='February 15, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' +end \ No newline at end of file From 4ef364dabc4525f12f20ed5515a3cb9f58f952fb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 02:35:55 +0800 Subject: [PATCH 2259/2794] luamodulesupdater, added more info of changes in dialog --- .../forms/frmLuaModulesUpdater.pas | 67 ++++++++++++++++--- mangadownloader/languages/fmd.de.po | 35 +++++++++- mangadownloader/languages/fmd.el_GR.po | 35 +++++++++- mangadownloader/languages/fmd.en.po | 39 ++++++++++- mangadownloader/languages/fmd.es.po | 35 +++++++++- mangadownloader/languages/fmd.id_ID.po | 39 ++++++++++- mangadownloader/languages/fmd.pl_PL.po | 35 +++++++++- mangadownloader/languages/fmd.po | 35 +++++++++- mangadownloader/languages/fmd.pt_BR.po | 35 +++++++++- mangadownloader/languages/fmd.ru_RU.po | 39 ++++++++++- mangadownloader/languages/fmd.tr_TR.po | 39 ++++++++++- 11 files changed, 402 insertions(+), 31 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index ee704b293..b08404ad8 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -27,6 +27,7 @@ TLuaModuleRepo = class last_modified: TDateTime; last_message: String; flag: TLuaModuleRepoFlag; + oflag: TLuaModuleRepoFlag; function Clone: TLuaModuleRepo; function SyncTo(const t: TLuaModuleRepo): Boolean; end; @@ -129,6 +130,7 @@ TCheckUpdateThread = class(TBaseThread) FThreadsCS: TRTLCriticalSection; FDownloadedCount: Integer; FProceed: Boolean; + FStatusList: TStringList; procedure RemoveThread(const T: TDownloadThread); procedure AddThread(const T: TDownloadThread); protected @@ -144,6 +146,7 @@ TCheckUpdateThread = class(TBaseThread) public constructor Create(const AOwner: TLuaModulesUpdaterForm); destructor Destroy; override; + procedure AddStatus(const S: String); end; var @@ -156,9 +159,14 @@ TCheckUpdateThread = class(TBaseThread) RS_StartDownloading = 'Downloading...'; RS_FinishDownload = 'Finish download'; RS_NewUpdateFoundTitle = 'Modules update found!'; - RS_NewUpdateFoundLostChanges = 'Modules update found, any local changes will be lost, procced?'; + RS_NewUpdateFoundLostChanges = 'Modules update found, any local changes will be lost, procced?'#13#10#13#10'%s'; RS_ModulesUpdatedTitle = 'Modules updated!'; - RS_ModulesUpdatedRestart = 'Modules updated, restart now?'; + RS_ModulesUpdatedRestart = 'Modules updated, restart now?'#13#10#13#10'%s'; + RS_StatusNew = '%s NEW*'; + RS_StatusUpdate = '%s UPDATE*'; + RS_StatusRedownloaded = '%s REDOWNLOAD*'; + RS_StatusFailed = '%s FAILED*'; + RS_StatusDelete = '%s DELETE*'; implementation @@ -196,6 +204,7 @@ function TLuaModuleRepo.Clone: TLuaModuleRepo; Result.last_modified := last_modified; Result.last_message := last_message; Result.flag := flag; + Result.oflag := oflag; end; function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean; @@ -208,6 +217,7 @@ function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean; t.sha := sha; t.last_modified := last_modified; t.last_message := last_message; + t.oflag := t.flag; t.flag := fUpdate; end; end; @@ -420,6 +430,7 @@ procedure TDownloadThread.Execute; f: String; c: Boolean; begin + FModule.oflag := FModule.flag; FModule.flag := fDownloading; FOwner.FOwner.ListDirty; if FHTTP.GET(FModule.download_url) then @@ -435,6 +446,11 @@ procedure TDownloadThread.Execute; FHTTP.Document.SaveToFile(f); if FileExists(f) then begin + case FModule.oflag of + fNew: FOwner.AddStatus(Format(RS_StatusNew, [FModule.name])); + fUpdate: FOwner.AddStatus(Format(RS_StatusUpdate, [FModule.name])); + fFailedDownload: FOwner.AddStatus(Format(RS_StatusRedownloaded, [FModule.name])); + end; FModule.flag := fDownloaded; FOwner.FDownloadedCount := InterLockedIncrement(FOwner.FDownloadedCount); end; @@ -442,7 +458,10 @@ procedure TDownloadThread.Execute; end; end else + begin + FOwner.AddStatus(Format(RS_StatusFailed, [FModule.name])); FModule.flag := fFailedDownload; + end; FOwner.FOwner.ListDirty; end; @@ -506,9 +525,9 @@ procedure TCheckUpdateThread.SyncFinishChecking; procedure TCheckUpdateThread.SyncAskToProceed; begin - FProceed := (not OptionModulesUpdaterShowUpdateWarning) or - (MessageDlg(RS_NewUpdateFoundTitle, RS_NewUpdateFoundLostChanges, - mtWarning, mbYesNo, 0) = mrYes); + FProceed := MessageDlg(RS_NewUpdateFoundTitle, + Format(RS_NewUpdateFoundLostChanges, [Trim(FStatusList.Text)]), + mtWarning, mbYesNo, 0) = mrYes; end; procedure TCheckUpdateThread.SyncStartDownload; @@ -628,8 +647,8 @@ procedure TCheckUpdateThread.Download; f: String; begin Synchronize(@SyncStartDownload); - sleep(2000); + FStatusList.Clear; i := 0; imax := FRepos.Items.Count; while i < imax do @@ -714,13 +733,25 @@ procedure TCheckUpdateThread.Execute; m.flag := fFailedDownload; foundupdate := True; end; + case m.flag of + fNew: FStatusList.Add(Format(RS_StatusNew, [m.name])); + fUpdate: FStatusList.Add(Format(RS_StatusUpdate, [m.name])); + fDelete: FStatusList.Add(Format(RS_StatusDelete, [m.name])); + fFailedDownload: FStatusList.Add(Format(RS_StatusFailed, [m.name])); + end; end; Synchronize(@SyncFinishChecking); if foundupdate and (not Terminated) then begin - Synchronize(@SyncAskToProceed); + if OptionModulesUpdaterShowUpdateWarning then + Synchronize(@SyncAskToProceed) + else + begin + FProceed := True; + Sleep(1500); // delay to show the update status + end; if FProceed then Download; end; @@ -754,10 +785,12 @@ procedure TCheckUpdateThread.Execute; Sleep(1000); Synchronize(@SyncFinal); - if (FDownloadedCount <> 0) and (OptionModulesUpdaterAutoRestart or - (MessageDlg(RS_ModulesUpdatedTitle, RS_ModulesUpdatedRestart, mtConfirmation, - mbYesNo, 0) = mrYes)) then - RestartFMD; + if not Terminated then + if (FDownloadedCount <> 0) and (OptionModulesUpdaterAutoRestart or + (MessageDlg(RS_ModulesUpdatedTitle, + Format(RS_ModulesUpdatedRestart, [Trim(FStatusList.Text)]), + mtConfirmation, mbYesNo, 0) = mrYes)) then + RestartFMD; end; constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); @@ -768,6 +801,7 @@ constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm); FHTTP := THTTPSendThread.Create(Self); FThreads := TFPList.Create; FDownloadedCount := 0; + FStatusList := TStringList.Create; end; destructor TCheckUpdateThread.Destroy; @@ -776,12 +810,23 @@ destructor TCheckUpdateThread.Destroy; FRepos.Free; if Assigned(FReposUp) then FReposUp.Free; + FStatusList.Free; FThreads.Free; FHTTP.Free; DoneCriticalsection(FThreadsCS); inherited Destroy; end; +procedure TCheckUpdateThread.AddStatus(const S: String); +begin + EnterCriticalsection(FThreadsCS); + try + FStatusList.Add(S); + finally + LeaveCriticalsection(FThreadsCS); + end; +end; + {$R *.lfm} { TLuaModulesUpdaterForm } diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index e52370579..3bcf7ee74 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -137,7 +137,10 @@ msgid "Finish download" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -145,7 +148,10 @@ msgid "Modules updated!" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -156,6 +162,31 @@ msgstr "" msgid "Downloading..." msgstr "" +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Alle Downloads" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index cf3c714e7..1ebcc250f 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -141,7 +141,10 @@ msgid "Finish download" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -149,7 +152,10 @@ msgid "Modules updated!" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -160,6 +166,31 @@ msgstr "" msgid "Downloading..." msgstr "" +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Όλες οι λήψεις" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 8a215b8e0..06b30faba 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -124,7 +124,12 @@ msgid "Finish download" msgstr "Finish download" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +#, fuzzy,badformat +#| msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "Modules updated, restart now?" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -132,7 +137,12 @@ msgid "Modules updated!" msgstr "Modules updated!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +#, fuzzy,badformat +#| msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "Modules update found, any local changes will be lost, procced?" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -143,6 +153,31 @@ msgstr "Modules update found!" msgid "Downloading..." msgstr "Downloading..." +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "All downloads" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index b55cc7116..2f01ffbe5 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -136,7 +136,10 @@ msgid "Finish download" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -144,7 +147,10 @@ msgid "Modules updated!" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -155,6 +161,31 @@ msgstr "" msgid "Downloading..." msgstr "" +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Todas las descargas" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index b352baec7..eb54d5a91 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -124,7 +124,12 @@ msgid "Finish download" msgstr "Selesai mengunduh" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +#, fuzzy,badformat +#| msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "Module diperbarui, memulai ulang sekarang?" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -132,7 +137,12 @@ msgid "Modules updated!" msgstr "Modul diperbarui!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +#, fuzzy,badformat +#| msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "Pembaruan modul ditemukan, ubahan lokal akan hilang, lanjutkan?" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -143,6 +153,31 @@ msgstr "Pembaruan modul ditemukan!" msgid "Downloading..." msgstr "Mengunduh..." +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Semua unduhan" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index ecf5cfe3a..64d17f007 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -137,7 +137,10 @@ msgid "Finish download" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -145,7 +148,10 @@ msgid "Modules updated!" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -156,6 +162,31 @@ msgstr "" msgid "Downloading..." msgstr "" +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Wszystkie pobrania" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index b5665f427..716402ead 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -114,7 +114,10 @@ msgid "Finish download" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -122,7 +125,10 @@ msgid "Modules updated!" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -133,6 +139,31 @@ msgstr "" msgid "Downloading..." msgstr "" +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index e322a770c..431eb5f21 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -137,7 +137,10 @@ msgid "Finish download" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -145,7 +148,10 @@ msgid "Modules updated!" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -156,6 +162,31 @@ msgstr "" msgid "Downloading..." msgstr "" +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Todos os downloads" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index c12265ebe..70d1c2e9e 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -135,7 +135,12 @@ msgid "Finish download" msgstr "Скачано" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +#, fuzzy,badformat +#| msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "Модули обновлены, перезапустить программу сейчас?" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -143,7 +148,12 @@ msgid "Modules updated!" msgstr "Модули обновлены!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +#, fuzzy,badformat +#| msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "Найдено обновление модулей, все локальные изменения модулей будут перезаписаны, продолжить?" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -154,6 +164,31 @@ msgstr "Найдено обновление модулей!" msgid "Downloading..." msgstr "Скачивание..." +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Все загрузки" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index aaffa7fec..f826370a8 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -137,7 +137,12 @@ msgid "Finish download" msgstr "İndirmeyi durdur" #: frmluamodulesupdater.rs_modulesupdatedrestart -msgid "Modules updated, restart now?" +#, fuzzy,badformat +#| msgid "Modules updated, restart now?" +msgid "" +"Modules updated, restart now?\n" +"\n" +"%s\n" msgstr "Modüller güncellendi, yeniden başlasın mı?" #: frmluamodulesupdater.rs_modulesupdatedtitle @@ -145,7 +150,12 @@ msgid "Modules updated!" msgstr "Modüller güncellendi!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -msgid "Modules update found, any local changes will be lost, procced?" +#, fuzzy,badformat +#| msgid "Modules update found, any local changes will be lost, procced?" +msgid "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" msgstr "Modül güncellemeleri bulundu, herhangi bir yerel değişim kaybolacaktır, devam edilsin mi?" #: frmluamodulesupdater.rs_newupdatefoundtitle @@ -156,6 +166,31 @@ msgstr "Modül güncellemeleri bulundu!" msgid "Downloading..." msgstr "İndiriliyor..." +#: frmluamodulesupdater.rs_statusdelete +msgctxt "frmluamodulesupdater.rs_statusdelete" +msgid "%s DELETE*" +msgstr "" + +#: frmluamodulesupdater.rs_statusfailed +msgctxt "frmluamodulesupdater.rs_statusfailed" +msgid "%s FAILED*" +msgstr "" + +#: frmluamodulesupdater.rs_statusnew +msgctxt "frmluamodulesupdater.rs_statusnew" +msgid "%s NEW*" +msgstr "" + +#: frmluamodulesupdater.rs_statusredownloaded +msgctxt "frmluamodulesupdater.rs_statusredownloaded" +msgid "%s REDOWNLOAD*" +msgstr "" + +#: frmluamodulesupdater.rs_statusupdate +msgctxt "frmluamodulesupdater.rs_statusupdate" +msgid "%s UPDATE*" +msgstr "" + #: frmmain.rs_alldownloads msgid "All downloads" msgstr "Tüm indirmeler" From 5807b0e2de9b3683789b62b87aa619d679af12e8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 16 Feb 2018 06:04:09 +0300 Subject: [PATCH 2260/2794] VnSharing, move to lua --- .../VnSharing/directory_page_number.inc | 37 ----- baseunits/includes/VnSharing/image_url.inc | 37 ----- .../includes/VnSharing/manga_information.inc | 129 ------------------ .../includes/VnSharing/names_and_links.inc | 48 ------- baseunits/uBaseUnit.pas | 32 ++--- baseunits/uData.pas | 15 -- baseunits/uDownloadsManager.pas | 5 - config/mangalist.ini | 2 +- lua/modules/VnSharing.lua | 63 +++++++++ 9 files changed, 78 insertions(+), 290 deletions(-) delete mode 100644 baseunits/includes/VnSharing/directory_page_number.inc delete mode 100644 baseunits/includes/VnSharing/image_url.inc delete mode 100644 baseunits/includes/VnSharing/manga_information.inc delete mode 100644 baseunits/includes/VnSharing/names_and_links.inc create mode 100644 lua/modules/VnSharing.lua diff --git a/baseunits/includes/VnSharing/directory_page_number.inc b/baseunits/includes/VnSharing/directory_page_number.inc deleted file mode 100644 index ff0330f20..000000000 --- a/baseunits/includes/VnSharing/directory_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetVnSharingDirectoryPageNumber: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + - VNSHARING_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('»', parse[i]) > 0) then - begin - s := GetVal(parse[i - 1], 'page'); - SetLength(s, Length(s) - 1); - APage := StrToInt(s); - Result := NO_ERROR; - Source.Free; - Exit; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/VnSharing/image_url.inc b/baseunits/includes/VnSharing/image_url.inc deleted file mode 100644 index 29e550d29..000000000 --- a/baseunits/includes/VnSharing/image_url.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetVnSharingImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - FillMangaSiteHost(VNSHARING_ID, URL), - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('lstImages.push("', parse[i]) > 0 then - begin - s := parse[i]; - repeat - j := Pos('lstImages.push("', s); - Task.Container.PageLinks.Add( - EncodeUrl(GetString(s, 'lstImages.push("', '");'))); - Delete(s, Pos('lstImages.push("', s), 16); - j := Pos('lstImages.push("', s); - until j = 0; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/VnSharing/manga_information.inc b/baseunits/includes/VnSharing/manga_information.inc deleted file mode 100644 index cb66b8ebf..000000000 --- a/baseunits/includes/VnSharing/manga_information.inc +++ /dev/null @@ -1,129 +0,0 @@ - function GetVnSharingInfoFromURL: Byte; - var - s: String; - isExtractSummary: Boolean = True; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(VNSHARING_ID, AURL) + '&confirm=yes'; - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[VNSHARING_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos('name="title"', parse[i]) > 0) then - mangaInfo.title := TrimLeft(TrimRight(GetString(parse[i], - '"Truyện ', ' | Đọc online'))); - - // get cover - if (GetTagName(parse[i]) = 'img') and - (Pos('img width="190px" height="250px"', parse[i]) > 0) then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i], 'src')); - - // get summary - if (Pos('Sơ lược:', parse[i]) <> 0) and - (isExtractSummary) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := parse[j]; - end; - Inc(j); - end; - isExtractSummary := False; - end; - - // get chapter name and links - if (i + 1 < parse.Count) and - (GetTagName(parse[i]) = 'a') and - (Pos('/Truyen/', parse[i]) > 0) and - (Pos('title="Đọc', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - EncodeUrl(GetVal(parse[i], 'href'))); - parse[i + 1] := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(parse[i + 1]))); - end; - - // get authors - if (i + 4 < parse.Count) and (Pos('Tác giả:', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(parse[i + 4]); - - // get artists - if (i + 4 < parse.Count) and (Pos('Họa sỹ:', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(parse[i + 4]); - - // get genres - if (Pos('Thể loại:', parse[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := ''; - end; - - if isExtractGenres then - begin - if (i + 1 < parse.Count) and (Pos('"/TheLoai/', parse[i]) > 0) then - mangaInfo.genres := mangaInfo.genres + - (TrimLeft(TrimRight(parse[i + 1])) + ', '); - if Pos('</p>', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Tình trạng:', parse[i]) <> 0) then - begin - if Pos('Đang tiến hành', parse[i + 2]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - if (mangaInfo.status = '1') and (mangainfo.ChapterName.Count > 0) then - begin - Dec(mangaInfo.numChapter); - mangainfo.ChapterName.Delete(mangainfo.ChapterName.Count - 1); - mangainfo.ChapterLinks.Delete(mangainfo.ChapterLinks.Count - 1); - end; - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/VnSharing/names_and_links.inc b/baseunits/includes/VnSharing/names_and_links.inc deleted file mode 100644 index dd611a68c..000000000 --- a/baseunits/includes/VnSharing/names_and_links.inc +++ /dev/null @@ -1,48 +0,0 @@ - function VnSharingGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - - begin - Result := INFORMATION_NOT_FOUND; - // bad code - if not GetPage(TObject(Source), WebsiteRoots[VNSHARING_ID, 1] + - VNSHARING_BROWSER + '?page=' + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/Truyen/', parse[i]) > 0) and - (GetVal(parse[i], 'width') <> '') then - begin - { if NOT isGetNamesAndLinks then - isGetNamesAndLinks:= TRUE - else - begin } - Result := NO_ERROR; - s := GetVal(parse[i], 'href'); - // if s <> '/Truyen/Tenki-Yohou-no-Koibito?id=506' then - if s <> '/Truyen/Bakuman-Fantasy-Weirdos?id=6238' then - begin - ALinks.Add(s); - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - ANames.Add(HTMLEntitiesFilter(s)); - end; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8d7c77101..90ed5b287 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -227,22 +227,20 @@ interface // common regex to split host/url REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - VNSHARING_ID = 0; - TURKCRAFT_ID = 1; - ANIMEEXTREMIST_ID = 2; - ANIMESTORY_ID = 3; - SCANMANGA_ID = 4; - MANGASPROJECT_ID = 5; - MANGAREADER_POR_ID = 6; - MANGATOWN_ID = 7; - MANGAOKU_ID = 8; - NHENTAI_ID = 9; - MANGAHOST_ID = 10; - MANGAKU_ID = 11; - DYNASTYSCANS_ID = 12; - - WebsiteRoots: array [0..12] of array [0..1] of String = ( - ('VnSharing', 'http://truyen.vnsharing.net'), + TURKCRAFT_ID = 0; + ANIMEEXTREMIST_ID = 1; + ANIMESTORY_ID = 2; + SCANMANGA_ID = 3; + MANGASPROJECT_ID = 4; + MANGAREADER_POR_ID = 5; + MANGATOWN_ID = 6; + MANGAOKU_ID = 7; + NHENTAI_ID = 8; + MANGAHOST_ID = 9; + MANGAKU_ID = 10; + DYNASTYSCANS_ID = 11; + + WebsiteRoots: array [0..11] of array [0..1] of String = ( ('Turkcraft', 'http://turkcraft.com'), ('AnimExtremist', 'http://www.animextremist.com'), ('AnimeStory', 'http://www.anime-story.com'), @@ -260,8 +258,6 @@ interface ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - VNSHARING_BROWSER = '/DanhSach'; - TURKCRAFT_BROWSER = '/'; ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index ea0aab625..7c247a980 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -784,8 +784,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: Parser: THTMLParser; MangaSiteID: Integer; - {$I includes/VnSharing/directory_page_number.inc} - {$I includes/MangaTown/directory_page_number.inc} {$I includes/NHentai/directory_page_number.inc} @@ -821,9 +819,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: if MangaSiteID = -1 then Exit(INFORMATION_NOT_FOUND); Source := TStringList.Create; - if MangaSiteID = VNSHARING_ID then - Result := GetVnSharingDirectoryPageNumber - else if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownDirectoryPageNumber else @@ -857,8 +852,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/AnimExtremist/names_and_links.inc} - {$I includes/VnSharing/names_and_links.inc} - {$I includes/AnimeStory/names_and_links.inc} {$I includes/ScanManga/names_and_links.inc} @@ -895,9 +888,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = -1 then Exit(INFORMATION_NOT_FOUND); Source := TStringList.Create; - if MangaSiteID = VNSHARING_ID then - Result := VnSharingGetNamesAndLinks - else if MangaSiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks else @@ -960,8 +950,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/AnimExtremist/manga_information.inc} - {$I includes/VnSharing/manga_information.inc} - {$I includes/AnimeStory/manga_information.inc} {$I includes/ScanManga/manga_information.inc} @@ -1012,9 +1000,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR Exit(INFORMATION_NOT_FOUND); mangaInfo.url := FillMangaSiteHost(MangaSiteID, AURL); Source := TStringList.Create; - if MangaSiteID = VNSHARING_ID then - Result := GetVnSharingInfoFromURL - else if MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 7d57fee16..711c01d7d 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -481,8 +481,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/Turkcraft/image_url.inc} - {$I includes/VnSharing/image_url.inc} - {$I includes/MangaTown/image_url.inc} {$I includes/MangaOku/image_url.inc} @@ -498,9 +496,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; Result := Modules.GetImageURL(Self, URL, Task.Container.ModuleId) else begin - if Task.Container.MangaSiteID = VNSHARING_ID then - Result := GetVnSharingImageURL - else if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then Result := GetAnimeExtremistImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 73739b977..11930c85c 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -19,7 +19,7 @@ Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaon Spanish-Scanlation= Thai= Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr -Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan,VnSharing +Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan Webcomics=Tapas H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix diff --git a/lua/modules/VnSharing.lua b/lua/modules/VnSharing.lua new file mode 100644 index 000000000..4f1089ce3 --- /dev/null +++ b/lua/modules/VnSharing.lua @@ -0,0 +1,63 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//p[@class="title"]') + mangainfo.coverLink=MaybeFillHost(module.rooturl, GetBetween("url('", "')", x.XPathString('//div[contains(@class, "info_ava")]/@style'))) + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//div[@class="info"]/span[contains(., "Status")]/a'), 'Đang tiến hành', 'Đang phát hành') + mangainfo.authors = x.XPathStringAll('//div[@id="manga_detail"]/ul/li[contains(b, "Tác giả")]/text()', '') + mangainfo.artists = x.XPathStringAll('//div[@class="info"]/span[contains(., "Artist")]/a') + mangainfo.genres = x.XPathStringAll('//div[@id="manga_detail"]/ul/li[contains(b, "Thể loại")]/a') + mangainfo.summary = x.XPathString('//p[@class="desc"]') + x.xpathhrefall('//ul[@id="manga-info-list"]/li[not(contains(@style, "none"))]/a[1]', mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_error + end +end + +function getdirectorypagenumber() + -- TODO: dynamic page count + if http.GET(module.RootURL .. '/index/KhamPha/newest') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('(//div[@class="pagination_wrap"]/a)[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function GetPageNumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + x.xpathstringall('//img[@id="manga_page"]/@src', task.pagelinks) + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/index/KhamPha/newest/'..IncStr(url)) then + x=TXQuery.Create(http.Document) + x.xpathhrefall('//ul[@id="browse_result_wrap"]/li[@class="browse_result_item"]/a[@class="title"]', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Vietnamese' + m.website='VnSharing' + m.rooturl='http://truyen.vnsharing.site' + m.sortedlist=true + m.lastupdated='February 16, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' +end \ No newline at end of file From 92553872a7353dc7078a2c37c1dda8743a9fdc57 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 13:03:40 +0800 Subject: [PATCH 2261/2794] fix getdirectorypage #909 --- baseunits/uBaseUnit.pas | 7 ++++ baseunits/uData.pas | 79 +++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 90ed5b287..634d01ee0 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -476,6 +476,7 @@ procedure CheckPath(const S: String); function LocateMangaSiteID(const URL: String): Integer; function GetMangaSiteID(const Name: String): Integer; +function GetMangaSiteID(const Name: String; var MangaSiteID: Integer): Boolean; overload; inline; function GetMangaSiteName(const ID: Integer): String; function GetMangaSiteRoot(const Website: String): String; overload; function GetMangaSiteRoot(const MangaID: Integer): String; overload; @@ -967,6 +968,12 @@ function GetMangaSiteID(const Name: String): Integer; Result := -1; end; +function GetMangaSiteID(const Name: String; var MangaSiteID: Integer): Boolean; +begin + MangaSiteID := GetMangaSiteID(Name); + Result := (MangaSiteID <= Low(WebsiteRoots)) and (MangaSiteID >= High(WebsiteRoots)); +end; + function GetMangaSiteName(const ID: Integer): String; begin if (ID < Low(WebsiteRoots)) or (ID > High(WebsiteRoots)) then diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 7c247a980..1204aeff2 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -793,7 +793,7 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: {$I includes/Dynasty-Scans/directory_page_number.inc} begin - APage := 0; + APage := 1; //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, AWebsite); @@ -805,42 +805,41 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: begin APage := p; BROWSER_INVERT := True; - end + Exit(NO_ERROR); + end; + + BROWSER_INVERT := False; + if ModuleId < 0 then + ModuleId := Modules.LocateModule(AWebsite); + if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then + Result := Modules.GetDirectoryPageNumber(Self, APage, TUpdateListThread(Thread).workPtr, ModuleId) else + if GetMangaSiteID(AWebsite, MangaSiteID) then begin - BROWSER_INVERT := False; - if ModuleId < 0 then - ModuleId := Modules.LocateModule(AWebsite); - if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then - Result := Modules.GetDirectoryPageNumber(Self, APage, TUpdateListThread(Thread).workPtr, ModuleId) + Source := TStringList.Create; + if MangaSiteID = MANGATOWN_ID then + Result := GetMangaTownDirectoryPageNumber + else + if MangaSiteID = NHENTAI_ID then + Result := GetNHentaiDirectoryPageNumber + else + if MangaSiteID = MANGAHOST_ID then + Result := GetMangaHostDirectoryPageNumber + else + if MangaSiteID = DYNASTYSCANS_ID then + Result := GetDynastyScansDirectoryPageNumber else begin - MangaSiteID := GetMangaSiteID(AWebsite); - if MangaSiteID = -1 then - Exit(INFORMATION_NOT_FOUND); - Source := TStringList.Create; - if MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownDirectoryPageNumber - else - if MangaSiteID = NHENTAI_ID then - Result := GetNHentaiDirectoryPageNumber - else - if MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostDirectoryPageNumber - else - if MangaSiteID = DYNASTYSCANS_ID then - Result := GetDynastyScansDirectoryPageNumber - else - begin - Result := NO_ERROR; - APage := 1; - Source.Free; - end; + Result := NO_ERROR; + APage := 1; + Source.Free; end; + end + else + Exit(INFORMATION_NOT_FOUND); - if APage < 1 then - APage := 1; - end; + if APage < 1 then + APage := 1; end; function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; @@ -881,12 +880,12 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if ModuleId < 0 then ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetNameAndLink) then + begin Result := Modules.GetNameAndLink(Self, ANames, ALinks, AURL, ModuleId) + end else + if GetMangaSiteID(AWebsite, MangaSiteID) then begin - MangaSiteID := GetMangaSiteID(AWebsite); - if MangaSiteID = -1 then - Exit(INFORMATION_NOT_FOUND); Source := TStringList.Create; if MangaSiteID = ANIMEEXTREMIST_ID then Result := AnimeExtremistGetNamesAndLinks @@ -928,7 +927,9 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; Result := INFORMATION_NOT_FOUND; Source.Free; end; - end; + end + else + Exit(INFORMATION_NOT_FOUND); //remove host from AURL if ALinks.Count > 0 then @@ -994,10 +995,8 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR Result := Modules.GetInfo(Self, AURL, ModuleId); end else + if GetMangaSiteID(AWebsite, MangaSiteID) then begin - MangaSiteID := GetMangaSiteID(AWebsite); - if MangaSiteID = -1 then - Exit(INFORMATION_NOT_FOUND); mangaInfo.url := FillMangaSiteHost(MangaSiteID, AURL); Source := TStringList.Create; if MangaSiteID = ANIMEEXTREMIST_ID then @@ -1041,7 +1040,9 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR Result := INFORMATION_NOT_FOUND; Exit; end; - end; + end + else + Exit(INFORMATION_NOT_FOUND); with mangaInfo do begin if link = '' then From ad49e8d7f2770b1a9aa1a3a70168829833ee2759 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 13:47:09 +0800 Subject: [PATCH 2262/2794] set envrionment varibale path on windows --- mangadownloader/md.lpr | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index a3be1fd33..c59b4f4d6 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -8,9 +8,12 @@ {$IFDEF UNIX} {$IFDEF UseCThreads} cthreads, {$ENDIF} {$ENDIF} + {$ifdef windows} + windows, + {$endif} Interfaces, // this includes the LCL widgetset Forms, LazFileUtils, IniFiles, simpleipc, sqlite3dyn, FMDOptions, uBaseUnit, FMDVars, webp, - LuaWebsiteModules, SimpleException, Classes, windows, sysutils, frmMain, MultiLog, + LuaWebsiteModules, SimpleException, Classes, sysutils, frmMain, MultiLog, FileChannel, ssl_openssl_lib; var @@ -25,9 +28,23 @@ i: Integer; p: String; + {$ifdef windows} + evpathlen: Integer; + evpath: String; + {$endif} + {$R *.res} begin + {$ifdef windows} + // set environment variables + evpathlen:=windows.GetEnvironmentVariable('PATH',nil,0); + setlength(evpath,evpathlen-1); + windows.GetEnvironmentVariable('PATH',pchar(evpath),evpathlen); + evpath:=FMD_DIRECTORY+';'+evpath; + windows.SetEnvironmentVariable('PATH',pchar(evpath)); + {$endif} + for i := 1 to ParamCount do begin p := AnsiLowerCase(ParamStr(i)); From 04ac53d85863dd4e5a4051996dbf19586c1bb82b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 13:57:24 +0800 Subject: [PATCH 2263/2794] update English localization --- mangadownloader/languages/fmd.en.po | 61 +++++++++++++++-------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 06b30faba..e53f751c4 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -2,27 +2,25 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" -msgstr "Cancel" +msgstr "Abort" #: dbupdater.rs_downloading msgid "Downloading %s" -msgstr "" +msgstr "Downloading %s" #: dbupdater.rs_extracting msgid "Extracting %s" -msgstr "" +msgstr "Extracting %s" #: dbupdater.rs_faileddownload msgid "%s: %d %s" -msgstr "" +msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "" +msgstr "%s: failed to extract, exitstatus = %d"\ #: dbupdater.rs_faileditems msgid "" @@ -30,20 +28,22 @@ msgid "" "\n" "%s\n" msgstr "" +"Failed to finish:\n" +"\n" +"%s\n" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Failed" #: dbupdater.rs_failedtosave msgid "%s: failed to save" -msgstr "" +msgstr "%s: failed to save" #: dbupdater.rs_missingzipexe msgid "%s: Missing %s" -msgstr "" +msgstr "%s: Missing %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" @@ -124,26 +124,28 @@ msgid "Finish download" msgstr "Finish download" #: frmluamodulesupdater.rs_modulesupdatedrestart -#, fuzzy,badformat -#| msgid "Modules updated, restart now?" msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "Modules updated, restart now?" +msgstr "" +"Modules updated, restart now?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" msgstr "Modules updated!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -#, fuzzy,badformat -#| msgid "Modules update found, any local changes will be lost, procced?" msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "Modules update found, any local changes will be lost, procced?" +msgstr "" +"Modules update found, any local changes will be lost, procced?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" @@ -156,27 +158,27 @@ msgstr "Downloading..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" msgid "%s DELETE*" -msgstr "" +msgstr "%s DELETE*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" msgid "%s FAILED*" -msgstr "" +msgstr "%s FAILED*" #: frmluamodulesupdater.rs_statusnew msgctxt "frmluamodulesupdater.rs_statusnew" msgid "%s NEW*" -msgstr "" +msgstr "%s NEW*" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "" +msgstr "%s REDOWNLOAD*" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" msgid "%s UPDATE*" -msgstr "" +msgstr "%s UPDATE*" #: frmmain.rs_alldownloads msgid "All downloads" @@ -508,14 +510,13 @@ msgid "Save as PNG" msgstr "Save as PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Abort" #: selfupdater.rs_downloading msgid "Downloading new version %s" -msgstr "" +msgstr "Downloading new version %s" #: selfupdater.rs_faileddownload msgid "" @@ -523,32 +524,34 @@ msgid "" "\n" "%d %s\n" msgstr "" +"Failed to download new version %s\n" +"\n" +"%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" -msgstr "" +msgstr "Failed to extract %s, exitstatus = %d" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Failed" #: selfupdater.rs_failedtosave msgid "Failed to save %s" -msgstr "" +msgstr "Failed to save %s" #: selfupdater.rs_finishrestart msgid "Download update package finished, restart to proceed?" -msgstr "" +msgstr "Download update package finished, restart to proceed?" #: selfupdater.rs_finishrestarttitle msgid "Download finished" -msgstr "" +msgstr "Download finished" #: selfupdater.rs_missingzipexe msgid "Missing %s" -msgstr "" +msgstr "Missing %s" #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" From 4ec7d29a99a7965d00c246a530fd6938f9c232f0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 14:06:07 +0800 Subject: [PATCH 2264/2794] update Indonesian localization --- mangadownloader/languages/fmd.id_ID.po | 69 ++++++++++++++------------ 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index eb54d5a91..967442603 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -2,27 +2,25 @@ msgid "" msgstr "Content-Type: text/plain; charset=UTF-8" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" -msgstr "Batal" +msgstr "Hentikan" #: dbupdater.rs_downloading msgid "Downloading %s" -msgstr "" +msgstr "Mengunduh %d" #: dbupdater.rs_extracting msgid "Extracting %s" -msgstr "" +msgstr "Mengekstrak %s" #: dbupdater.rs_faileddownload msgid "%s: %d %s" -msgstr "" +msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "" +msgstr "%s: gagal mengekstrak, kode = %d" #: dbupdater.rs_faileditems msgid "" @@ -30,20 +28,22 @@ msgid "" "\n" "%s\n" msgstr "" +"Gagal menyelesaikan:\n" +"\n" +"%s\n" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Gagal" #: dbupdater.rs_failedtosave msgid "%s: failed to save" -msgstr "" +msgstr "%s: gagal menyimpan" #: dbupdater.rs_missingzipexe msgid "%s: Missing %s" -msgstr "" +msgstr "%s: Tidak ditemukan %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" @@ -124,26 +124,28 @@ msgid "Finish download" msgstr "Selesai mengunduh" #: frmluamodulesupdater.rs_modulesupdatedrestart -#, fuzzy,badformat -#| msgid "Modules updated, restart now?" msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "Module diperbarui, memulai ulang sekarang?" +msgstr "" +"Modul sudah diperbarui, muat ulang sekarang?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" msgstr "Modul diperbarui!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -#, fuzzy,badformat -#| msgid "Modules update found, any local changes will be lost, procced?" msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "Pembaruan modul ditemukan, ubahan lokal akan hilang, lanjutkan?" +msgstr "" +"Pembaruan modul ditemukan, perubahan lokal akan ditimpa, lanjutkan?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" @@ -156,27 +158,27 @@ msgstr "Mengunduh..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" msgid "%s DELETE*" -msgstr "" +msgstr "%s DIHAPUS*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" msgid "%s FAILED*" -msgstr "" +msgstr "%s GAGAL" #: frmluamodulesupdater.rs_statusnew msgctxt "frmluamodulesupdater.rs_statusnew" msgid "%s NEW*" -msgstr "" +msgstr "%s BARU" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "" +msgstr "%s DOWNLOADULANG" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" msgid "%s UPDATE*" -msgstr "" +msgstr "%s PEMBARUAN*" #: frmmain.rs_alldownloads msgid "All downloads" @@ -508,14 +510,13 @@ msgid "Save as PNG" msgstr "Simpan sebagai PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" -msgstr "Batalkan" +msgstr "Hentikan" #: selfupdater.rs_downloading msgid "Downloading new version %s" -msgstr "" +msgstr "Mengunduh versi baru %s" #: selfupdater.rs_faileddownload msgid "" @@ -523,32 +524,34 @@ msgid "" "\n" "%d %s\n" msgstr "" +"Gagal mengunduh versi baru %s\n" +"\n" +"%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" -msgstr "" +msgstr "Gagal mengekstrak %s, kode = %d" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Gagal" #: selfupdater.rs_failedtosave msgid "Failed to save %s" -msgstr "" +msgstr "Gagal menyimpan %s" #: selfupdater.rs_finishrestart msgid "Download update package finished, restart to proceed?" -msgstr "" +msgstr "Pembaruan selesai diunduh, memuat ulang sekarang?" #: selfupdater.rs_finishrestarttitle msgid "Download finished" -msgstr "" +msgstr "Unduhan selesai" #: selfupdater.rs_missingzipexe msgid "Missing %s" -msgstr "" +msgstr "Tidak ditemukan %s" #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" @@ -723,7 +726,7 @@ msgstr "Pesan terakhir" #: tmainform.btabortupdatelist.hint msgid "Abort update list" -msgstr "Batalkan pembaruan daftar komik" +msgstr "Hentikan pembaruan daftar komik" #: tmainform.btaddtofavorites.caption msgctxt "tmainform.btaddtofavorites.caption" @@ -1721,7 +1724,7 @@ msgstr "Urungkan" #: tmainform.miabortsilentthread.caption msgctxt "tmainform.miabortsilentthread.caption" msgid "Abort" -msgstr "Batalkan" +msgstr "Hentikan" #: tmainform.michapterlistascending.caption msgid "Ascending" @@ -2222,7 +2225,7 @@ msgstr "Pilih direktori" #: tshutdowncounterform.btabort.caption msgid "&Abort" -msgstr "&Batalkan" +msgstr "&Hentikan" #: tshutdowncounterform.btnow.caption msgid "&Now" From e83474e7e34fcc9aa8693cd32e0ab40d3b91f82c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 14:13:24 +0800 Subject: [PATCH 2265/2794] rename mangash --- lua/modules/{Manga.sh.lua => MangaSh.lua} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename lua/modules/{Manga.sh.lua => MangaSh.lua} (96%) diff --git a/lua/modules/Manga.sh.lua b/lua/modules/MangaSh.lua similarity index 96% rename from lua/modules/Manga.sh.lua rename to lua/modules/MangaSh.lua index c0e9103d8..f6ebfa473 100644 --- a/lua/modules/Manga.sh.lua +++ b/lua/modules/MangaSh.lua @@ -1,5 +1,5 @@ -apiurl='https://api.manga.sh/api/v1/' -cdnurl='https://cdn.manga.sh/' +local apiurl='https://api.manga.sh/api/v1/' +local cdnurl='https://cdn.manga.sh/' function getinfo() local lid=RegExprGetMatch('/(\\d+)',url,1) @@ -64,7 +64,7 @@ end function Init() m=NewModule() - m.website='Manga.sh' + m.website='MangaSh' m.rooturl='https://manga.sh' m.lastupdated='February 14, 2018' m.ongetinfo='getinfo' From a6b458edf1523efb58727a79007c171b712653f4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 14:27:10 +0800 Subject: [PATCH 2266/2794] luamodulesupdater, status delete --- mangadownloader/forms/frmLuaModulesUpdater.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index b08404ad8..0443b2d13 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -659,6 +659,7 @@ procedure TCheckUpdateThread.Download; f := LUA_WEBSITEMODULE_FOLDER + m.name; if FileExists(f) then DeleteFile(f); + AddStatus(Format(RS_StatusDelete, [m.name])); m.flag := fDeleted; Inc(i); end From 50f661bea65b3c0da686e7417a5983fdb36a0f87 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Fri, 16 Feb 2018 14:29:27 +0800 Subject: [PATCH 2267/2794] Bump version 0.9.142.0 --- changelog.txt | 12 ++++++++++++ mangadownloader/md.lpi | 11 +++++------ update | 10 +++++----- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8b2c4c282..6c1f3bfc9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,16 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.141.0 (16-02-2018) +[+] Added ManhwaCo [EN-SC] +[+] Added HentaiHere [H] +[*] Fixed update list issue +[*] Update Indonesian localization +[*] Update Russian localization +[*] Update Turkish localization +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.141.0...0.9.142.0 + 0.9.141.0 (15-02-2018) [+] Added new updater only to extract update package [*] Download new version in the background @@ -12,6 +22,8 @@ Changelog: Full changes: https://github.com/riderkick/FMD/compare/0.9.140.0...0.9.141.0 0.9.140.0 (14-02-2018) +[+] Added SeaOtterScans [EN-SC] +[+] Added MangaSh [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.139.0...0.9.140.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1996a547a..7b5d0e90b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectOptions> - <Version Value="11"/> + <Version Value="10"/> <PathDelim Value="\"/> <General> <SessionStorage Value="InProjectDir"/> @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="141"/> + <RevisionNr Value="142"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> @@ -267,10 +267,9 @@ <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/> </PublishOptions> <RunParams> - <FormatVersion Value="2"/> - <Modes Count="1"> - <Mode0 Name="default"/> - </Modes> + <local> + <FormatVersion Value="1"/> + </local> </RunParams> <RequiredPackages Count="9"> <Item1> diff --git a/update b/update index bb675e99d..636e9af84 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.141.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.141.0/fmd_0.9.141.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.141.0/fmd_0.9.141.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.141.0/fmd_0.9.141.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.141.0/fmd_0.9.141.0_Win64.7z +VERSION=0.9.142.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.142.0/fmd_0.9.142.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.142.0/fmd_0.9.142.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.142.0/fmd_0.9.142.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.142.0/fmd_0.9.142.0_Win64.7z From d26452b4aa3b7f3a0cc27d38577cc753db061602 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Fri, 16 Feb 2018 09:54:38 +0300 Subject: [PATCH 2268/2794] Update Turkish localization - Fixed lines 146, 147,160, 161. - Line 245 changed with a more appropriate word. - Translated latest additions. Line 189 is splitted, "download" means "indir" in turkish and "re-" means "tekrar" and they are 2 seperate words. If it is a problem, you can always delete the space between "Tekrar indir". --- mangadownloader/languages/fmd.tr_TR.po | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index f826370a8..b1c4a6075 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -137,26 +137,28 @@ msgid "Finish download" msgstr "İndirmeyi durdur" #: frmluamodulesupdater.rs_modulesupdatedrestart -#, fuzzy,badformat -#| msgid "Modules updated, restart now?" msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "Modüller güncellendi, yeniden başlasın mı?" +msgstr "" +"Modüller güncellendi, yeniden başlasın mı?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" msgstr "Modüller güncellendi!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -#, fuzzy,badformat -#| msgid "Modules update found, any local changes will be lost, procced?" msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "Modül güncellemeleri bulundu, herhangi bir yerel değişim kaybolacaktır, devam edilsin mi?" +msgstr "" +"Modül güncellemeleri bulundu, herhangi bir yerel değişim kaybolacaktır, devam edilsin mi?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" @@ -169,27 +171,27 @@ msgstr "İndiriliyor..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" msgid "%s DELETE*" -msgstr "" +msgstr "%s SİL*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" msgid "%s FAILED*" -msgstr "" +msgstr "%s BAŞARISIZ*" #: frmluamodulesupdater.rs_statusnew msgctxt "frmluamodulesupdater.rs_statusnew" msgid "%s NEW*" -msgstr "" +msgstr "%s YENİ*" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "" +msgstr "%s TEKRAR İNDİR*" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" msgid "%s UPDATE*" -msgstr "" +msgstr "%s GÜNCELLE*" #: frmmain.rs_alldownloads msgid "All downloads" @@ -240,7 +242,7 @@ msgstr "Tamamlanmış indirmeleri silmek istediğine emin misin?" #: frmmain.rs_dlgremoveitem msgid "Are you sure you want to delete this item(s)?" -msgstr "Bu kalemleri silmek istediğine emin misin?" +msgstr "Bu içerikleri silmek istediğine emin misin?" #: frmmain.rs_dlgremovetask msgid "Are you sure you want to delete the task(s)?" From ad6e07b9a573a37b57ce7a047cc5075307e949ee Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 16 Feb 2018 14:34:44 +0300 Subject: [PATCH 2269/2794] update Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 70d1c2e9e..91dea33ca 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -135,26 +135,28 @@ msgid "Finish download" msgstr "Скачано" #: frmluamodulesupdater.rs_modulesupdatedrestart -#, fuzzy,badformat -#| msgid "Modules updated, restart now?" msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "Модули обновлены, перезапустить программу сейчас?" +msgstr "" +"Модули обновлены, перезапустить программу сейчас?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" msgstr "Модули обновлены!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges -#, fuzzy,badformat -#| msgid "Modules update found, any local changes will be lost, procced?" msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "Найдено обновление модулей, все локальные изменения модулей будут перезаписаны, продолжить?" +msgstr "" +"Найдено обновление модулей, все локальные изменения модулей будут перезаписаны, продолжить?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" @@ -167,27 +169,27 @@ msgstr "Скачивание..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" msgid "%s DELETE*" -msgstr "" +msgstr "%s УДАЛЕН*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" msgid "%s FAILED*" -msgstr "" +msgstr "%s ОШИБКА*" #: frmluamodulesupdater.rs_statusnew msgctxt "frmluamodulesupdater.rs_statusnew" msgid "%s NEW*" -msgstr "" +msgstr "%s НОВЫЙ*" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "" +msgstr "%s ПОВТОРНАЯ ЗАГРУЗКА*" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" msgid "%s UPDATE*" -msgstr "" +msgstr "%s ОБНОВЛЕН*" #: frmmain.rs_alldownloads msgid "All downloads" From 72c47b199931648c0eb57916c7fca2abda78a17e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 16 Feb 2018 16:06:46 +0300 Subject: [PATCH 2270/2794] MangaOku, move to lua Turkcraft, move to lua --- .../includes/MangaOku/chapter_page_number.inc | 39 ---------- baseunits/includes/MangaOku/image_url.inc | 44 ----------- .../includes/MangaOku/manga_information.inc | 56 -------------- .../includes/MangaOku/names_and_links.inc | 51 ------------- .../Turkcraft/chapter_page_number.inc | 33 -------- baseunits/includes/Turkcraft/image_url.inc | 32 -------- .../includes/Turkcraft/manga_information.inc | 73 ------------------ .../includes/Turkcraft/names_and_links.inc | 37 --------- baseunits/uBaseUnit.pas | 32 ++++---- baseunits/uData.pas | 20 ----- baseunits/uDownloadsManager.pas | 20 ----- config/mangalist.ini | 2 +- lua/modules/MangaOku.lua | 75 +++++++++++++++++++ 13 files changed, 89 insertions(+), 425 deletions(-) delete mode 100644 baseunits/includes/MangaOku/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaOku/image_url.inc delete mode 100644 baseunits/includes/MangaOku/manga_information.inc delete mode 100644 baseunits/includes/MangaOku/names_and_links.inc delete mode 100644 baseunits/includes/Turkcraft/chapter_page_number.inc delete mode 100644 baseunits/includes/Turkcraft/image_url.inc delete mode 100644 baseunits/includes/Turkcraft/manga_information.inc delete mode 100644 baseunits/includes/Turkcraft/names_and_links.inc create mode 100644 lua/modules/MangaOku.lua diff --git a/baseunits/includes/MangaOku/chapter_page_number.inc b/baseunits/includes/MangaOku/chapter_page_number.inc deleted file mode 100644 index 83fe65492..000000000 --- a/baseunits/includes/MangaOku/chapter_page_number.inc +++ /dev/null @@ -1,39 +0,0 @@ - function GetMangaOkuPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - isExtractPage: Boolean = False; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGAOKU_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('name="page"', parse[i]) > 0) then - isExtractPage := True; - if isExtractPage and (Pos('</select', parse[i]) > 0) then - begin - isExtractPage := False; - Break; - end; - if isExtractPage and (Pos('<option', parse[i]) > 0) then - begin - Inc(Task.Container.PageNumber); - end; - end; - end; - - l.Free; - parse.Free; - end; diff --git a/baseunits/includes/MangaOku/image_url.inc b/baseunits/includes/MangaOku/image_url.inc deleted file mode 100644 index 9147dfc26..000000000 --- a/baseunits/includes/MangaOku/image_url.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetMangaOkuImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(MANGAOKU_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - s := s + IntToStr(WorkId + 1) + '/'; - Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', parse[i]) > 0) and (Pos('id="manga_img"', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'src'); - if Pos(WebsiteRoots[MANGAOKU_ID, 1], s) = 0 then - s := WebsiteRoots[MANGAOKU_ID, 1] + '/' + s; - Task.Container.PageLinks[WorkId] := s; - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/MangaOku/manga_information.inc b/baseunits/includes/MangaOku/manga_information.inc deleted file mode 100644 index 453ee4411..000000000 --- a/baseunits/includes/MangaOku/manga_information.inc +++ /dev/null @@ -1,56 +0,0 @@ - function GetMangaOkuInfoFromURL: Byte; - var - s: String; - i: Cardinal; - isExtractChapters: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAOKU_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAOKU_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - - for i := 0 to parse.Count - 1 do - begin - //get chapters - if (Pos('<select', parse[i]) > 0) and (Pos('name="chapter', parse[i]) > 0) then - isExtractChapters := True; - if isExtractChapters and (Pos('</select', parse[i]) > 0) then - begin - isExtractChapters := False; - Break; - end; - if isExtractChapters and (Pos('<option', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - s := Trim(TrimChar(s, ['-'])); - mangaInfo.chapterName.Add(s); - s := TrimChar(GetVal(parse[i], 'value'), ['/']); - s := AURL + s + '/'; - mangaInfo.chapterLinks.Add(s); - end; - end; - - if mangaInfo.chapterName.Count > 1 then - begin - // invert chapter - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaOku/names_and_links.inc b/baseunits/includes/MangaOku/names_and_links.inc deleted file mode 100644 index 92f7e4c16..000000000 --- a/baseunits/includes/MangaOku/names_and_links.inc +++ /dev/null @@ -1,51 +0,0 @@ - function MangaOkuGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - isExtractMangas: Boolean = False; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAOKU_ID, 1] + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('name="manga"', parse[i]) > 0) then - begin - Result := NO_ERROR; - isExtractMangas := True; - end; - if isExtractMangas and (Pos('</select', parse[i]) > 0) then - begin - isExtractMangas := False; - Break; - end; - if isExtractMangas and (Pos('<option', parse[i]) > 0) then - begin - s := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - ANames.Add(s); - s := TrimChar(GetVal(parse[i], 'value'), ['/']); - s := '/' + s + '/'; - ALinks.Add(s); - end; - end; - // index 0 isn't manga - if ALinks.Count > 0 then - if ALinks[0] = '/0/' then - begin - ALinks.Delete(0); - ANames.Delete(0); - end; - end; diff --git a/baseunits/includes/Turkcraft/chapter_page_number.inc b/baseunits/includes/Turkcraft/chapter_page_number.inc deleted file mode 100644 index de9341377..000000000 --- a/baseunits/includes/Turkcraft/chapter_page_number.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetTurkcraftPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/1'); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.pageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('title="Next Page"', parse[i]) > 0) then - begin - s := parse[i - 5]; - Task.Container.PageNumber := StrToInt(TrimLeft(TrimRight(s))); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Turkcraft/image_url.inc b/baseunits/includes/Turkcraft/image_url.inc deleted file mode 100644 index a9d9c68f4..000000000 --- a/baseunits/includes/Turkcraft/image_url.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetTurkcraftImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(TURKCRAFT_ID, URL) + '/' + IntToStr(WorkId + 1)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('class="picture"', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := - EncodeURL(WebsiteRoots[TURKCRAFT_ID, 1] + TURKCRAFT_BROWSER + - GetVal(parse[i], 'src')); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/Turkcraft/manga_information.inc b/baseunits/includes/Turkcraft/manga_information.inc deleted file mode 100644 index 64b6faafc..000000000 --- a/baseunits/includes/Turkcraft/manga_information.inc +++ /dev/null @@ -1,73 +0,0 @@ - function GetTurkcraftInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(TURKCRAFT_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - mangaInfo.website := WebsiteRoots[TURKCRAFT_ID, 0]; - mangaInfo.status := '1'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get chapter name and links - if (Pos('select name="chapter"', parse[i]) > 0) then - isExtractChapter := True; - - // get manga name - if (mangaInfo.title = '') and (Pos('Mangaturk - ', parse[i]) > 0) then - mangaInfo.title := GetString(parse[i], 'Mangaturk - ', ' - Chapter'); - - if (isExtractChapter) and (Pos('</select>', parse[i]) > 0) then - Break; - - if (isExtractChapter) and (Pos('option value=', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := AURL + '/' + GetVal(parse[i], 'value'); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(StringFilter(HTMLEntitiesFilter(s)))); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Turkcraft/names_and_links.inc b/baseunits/includes/Turkcraft/names_and_links.inc deleted file mode 100644 index 94e48aada..000000000 --- a/baseunits/includes/Turkcraft/names_and_links.inc +++ /dev/null @@ -1,37 +0,0 @@ - function TurkcraftGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[TURKCRAFT_ID, 1] + - TURKCRAFT_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('<option value="', parse[i]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(TrimLeft(TrimRight(parse[i + 1]))); - ANames.Add(HTMLEntitiesFilter(s)); - s := '/' + GetVal(parse[i], 'value'); - ALinks.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 634d01ee0..c576af847 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -227,28 +227,24 @@ interface // common regex to split host/url REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - TURKCRAFT_ID = 0; - ANIMEEXTREMIST_ID = 1; - ANIMESTORY_ID = 2; - SCANMANGA_ID = 3; - MANGASPROJECT_ID = 4; - MANGAREADER_POR_ID = 5; - MANGATOWN_ID = 6; - MANGAOKU_ID = 7; - NHENTAI_ID = 8; - MANGAHOST_ID = 9; - MANGAKU_ID = 10; - DYNASTYSCANS_ID = 11; - - WebsiteRoots: array [0..11] of array [0..1] of String = ( - ('Turkcraft', 'http://turkcraft.com'), + ANIMEEXTREMIST_ID = 0; + ANIMESTORY_ID = 1; + SCANMANGA_ID = 2; + MANGASPROJECT_ID = 3; + MANGAREADER_POR_ID = 4; + MANGATOWN_ID = 5; + NHENTAI_ID = 6; + MANGAHOST_ID = 7; + MANGAKU_ID = 8; + DYNASTYSCANS_ID = 9; + + WebsiteRoots: array [0..9] of array [0..1] of String = ( ('AnimExtremist', 'http://www.animextremist.com'), ('AnimeStory', 'http://www.anime-story.com'), ('ScanManga', 'http://www.scan-manga.com'), ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), ('MangaREADER_POR', 'http://www.mangareader.com.br'), ('MangaTown', 'http://www.mangatown.com'), - ('MangaOku', 'http://www.mangaoku.net'), ('NHentai', 'http://nhentai.net'), ('MangaHost', 'http://br.mangahost.com'), ('MangaKu', 'http://mangaku.web.id'), @@ -1052,9 +1048,7 @@ function SitesWithoutInformation(const website: String): Boolean; Exit; end; Result := SitesMemberOf(website, [ - MANGASPROJECT_ID, - TURKCRAFT_ID, - MANGAOKU_ID + MANGASPROJECT_ID ]); end; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 1204aeff2..5dc890478 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -855,16 +855,12 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; {$I includes/ScanManga/names_and_links.inc} - {$I includes/Turkcraft/names_and_links.inc} - {$I includes/MangasPROJECT/names_and_links.inc} {$I includes/MangaREADER_POR/names_and_links.inc} {$I includes/MangaTown/names_and_links.inc} - {$I includes/MangaOku/names_and_links.inc} - {$I includes/NHentai/names_and_links.inc} {$I includes/MangaHost/names_and_links.inc} @@ -896,9 +892,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = SCANMANGA_ID then Result := ScanMangaGetNamesAndLinks else - if MangaSiteID = TURKCRAFT_ID then - Result := TurkcraftGetNamesAndLinks - else if MangaSiteID = MANGASPROJECT_ID then Result := MangasPROJECTGetNamesAndLinks else @@ -908,9 +901,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; if MangaSiteID = MANGATOWN_ID then Result := MangaTownGetNamesAndLinks else - if MangaSiteID = MANGAOKU_ID then - Result := MangaOkuGetNamesAndLinks - else if MangaSiteID = NHENTAI_ID then Result := NHentaiNamesAndLinks else @@ -955,16 +945,12 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR {$I includes/ScanManga/manga_information.inc} - {$I includes/Turkcraft/manga_information.inc} - {$I includes/MangasPROJECT/manga_information.inc} {$I includes/MangaREADER_POR/manga_information.inc} {$I includes/MangaTown/manga_information.inc} - {$I includes/MangaOku/manga_information.inc} - {$I includes/NHentai/manga_information.inc} {$I includes/MangaHost/manga_information.inc} @@ -1008,9 +994,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = SCANMANGA_ID then Result := GetScanMangaInfoFromURL else - if MangaSiteID = TURKCRAFT_ID then - Result := GetTurkcraftInfoFromURL - else if MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTInfoFromURL else @@ -1020,9 +1003,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR if MangaSiteID = MANGATOWN_ID then Result := GetMangaTownInfoFromURL else - if MangaSiteID = MANGAOKU_ID then - Result := GetMangaOkuInfoFromURL - else if MangaSiteID = NHENTAI_ID then Result := GetNHentaiInfoFromURL else diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 711c01d7d..a2252e89b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -412,12 +412,8 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; {$I includes/AnimExtremist/chapter_page_number.inc} - {$I includes/Turkcraft/chapter_page_number.inc} - {$I includes/MangaTown/chapter_page_number.inc} - {$I includes/MangaOku/chapter_page_number.inc} - {$I includes/NHentai/chapter_page_number.inc} {$I includes/MangaHost/chapter_page_number.inc} @@ -440,15 +436,9 @@ function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = ANIMESTORY_ID then Result := GetAnimeStoryPageNumber else - if Task.Container.MangaSiteID = TURKCRAFT_ID then - Result := GetTurkcraftPageNumber - else if Task.Container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownPageNumber else - if Task.Container.MangaSiteID = MANGAOKU_ID then - Result := GetMangaOkuPageNumber - else if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiPageNumber else @@ -479,12 +469,8 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; {$I includes/ScanManga/image_url.inc} - {$I includes/Turkcraft/image_url.inc} - {$I includes/MangaTown/image_url.inc} - {$I includes/MangaOku/image_url.inc} - {$I includes/NHentai/image_url.inc} {$I includes/MangaHost/image_url.inc} @@ -505,9 +491,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = SCANMANGA_ID then Result := GetScanMangaImageURL else - if Task.Container.MangaSiteID = TURKCRAFT_ID then - Result := GetTurkcraftImageURL - else if Task.Container.MangaSiteID = MANGASPROJECT_ID then Result := GetMangasPROJECTImageURL else @@ -517,9 +500,6 @@ function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; if Task.Container.MangaSiteID = MANGATOWN_ID then Result := GetMangaTownImageURL else - if Task.Container.MangaSiteID = MANGAOKU_ID then - Result := GetMangaOkuImageURL - else if Task.Container.MangaSiteID = NHENTAI_ID then Result := GetNHentaiImageURL else diff --git a/config/mangalist.ini b/config/mangalist.ini index 11930c85c..7f12d0bbe 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -18,7 +18,7 @@ Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation= Thai= -Turkish=MangaOku,Manga-Tr,Puzzmos,WebtoonTr +Turkish=Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan Webcomics=Tapas H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Tsumino,YaoiChanRU diff --git a/lua/modules/MangaOku.lua b/lua/modules/MangaOku.lua new file mode 100644 index 000000000..fcb7a92eb --- /dev/null +++ b/lua/modules/MangaOku.lua @@ -0,0 +1,75 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//select[@name="manga"]/option[@selected]') + s=x.xpathstring('//select[@name="manga"]/option[@selected]/@value') + v=x.xpath('//select[@name="chapter"]/option') + for i = 1, v.count do + v1=v.get(i) + mangainfo.chapternames.add(v1.toString) + mangainfo.chapterlinks.add(module.rooturl .. '/' .. s .. '/' .. v1.getAttribute('value')) + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_error + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + print(MaybeFillHost(module.rooturl,url)) + if http.get(MaybeFillHost(module.rooturl,url)) then + local x=TXQuery.Create(http.Document) + task.pagenumber = x.xpath('//select[@name="page"]/option').count + return true + else + return false + end +end + +function getnameandlink() + if http.get(module.rooturl) then + x=TXQuery.Create(http.Document) + v=x.xpath('//select[@name="manga"]/option[@value!="0"]') + for i = 1, v.count do + v1=v.get(i) + names.add(v1.toString) + links.add(module.rooturl .. '/' .. v1.getAttribute('value')) + end + return no_error + else + return net_problem + end +end + +function getimageurl() + local s = MaybeFillHost(module.rooturl,url) .. '/' .. tostring(workid+1) + if http.get(s) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]=MaybeFillHost(module.rooturl,x.xpathstring('//img[@id="manga_img"]/@src')) + return true + else + return false + end +end + +function AddWebsiteModule(name, url) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = 'Turkish' + m.lastupdated = 'February 16, 2018' + m.OnGetInfo = 'getinfo' + m.OnGetPageNumber = 'getpagenumber' + m.OnGetImageURL = 'getimageurl' + m.OnGetNameAndLink = 'getnameandlink' + return m +end + +function Init() + AddWebsiteModule('MangaOku', 'http://www.mangaoku.net') + AddWebsiteModule('Turkcraft', 'http://turkcraft.com') +end \ No newline at end of file From 068c60c9825821675f707a200e50a1c12f79ea68 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 16 Feb 2018 16:30:39 +0300 Subject: [PATCH 2271/2794] remove BitmapAdv fixes #989 --- mangadownloader/forms/frmTransferFavorites.lfm | 3 --- 1 file changed, 3 deletions(-) diff --git a/mangadownloader/forms/frmTransferFavorites.lfm b/mangadownloader/forms/frmTransferFavorites.lfm index 5e2cd3e59..1f7784d61 100644 --- a/mangadownloader/forms/frmTransferFavorites.lfm +++ b/mangadownloader/forms/frmTransferFavorites.lfm @@ -348,8 +348,5 @@ object TransferFavoritesForm: TTransferFavoritesForm 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 00170000000C00000002FFFFFF00 } - BitmapAdv = { - 4C6900000000 - } end end From e4ebb68044019ee24091c2bdec2b0dcb647ebdc0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 16 Feb 2018 16:33:33 +0300 Subject: [PATCH 2272/2794] baseunit, fix GetMangaSiteID fixes #988 --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c576af847..2d11fd676 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -967,7 +967,7 @@ function GetMangaSiteID(const Name: String): Integer; function GetMangaSiteID(const Name: String; var MangaSiteID: Integer): Boolean; begin MangaSiteID := GetMangaSiteID(Name); - Result := (MangaSiteID <= Low(WebsiteRoots)) and (MangaSiteID >= High(WebsiteRoots)); + Result := (MangaSiteID >= Low(WebsiteRoots)) and (MangaSiteID <= High(WebsiteRoots)); end; function GetMangaSiteName(const ID: Integer): String; From 0bb920c302578dde0b3e8a466899c80c15e9f984 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 03:40:41 +0800 Subject: [PATCH 2273/2794] fix #992 --- baseunits/DBUpdater.pas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index dfa93f890..d57fdc232 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -161,11 +161,11 @@ procedure TDBUpdaterThread.SyncStart; procedure TDBUpdaterThread.SyncFinal; begin + DBUpdaterThread := nil; FHTTP.Sock.OnStatus := nil; FreeAndNil(FStatusBar); FreeAndNil(FProgressBar); FreeAndNil(FButtonCancel); - DBUpdaterThread := nil; end; procedure TDBUpdaterThread.SyncStartDownload; @@ -349,9 +349,9 @@ destructor TDBUpdaterThread.Destroy; if (not Terminated) and (FFailedList.Count <> 0) then Synchronize(@SyncShowFailed); Synchronize(@SyncFinal); - Items.Free; FHTTP.Free; FFailedList.Free; + FreeAndNil(Items); inherited Destroy; end; @@ -359,6 +359,7 @@ procedure TDBUpdaterThread.Add(const S: String); var i: Integer; begin + if Items = nil then Exit; // search on not sorted for i := 0 to Items.Count - 1 do if S = Items[i] then @@ -371,6 +372,7 @@ procedure TDBUpdaterThread.Add(const S: TStrings); var i, j, jmax: Integer; begin + if Items = nil then Exit; // search on not sorted jmax := Items.Count; for i := 0 to S.Count - 1 do From a15d8c004658cf8fc4f8b835aff5be693b7f3f1e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 04:58:35 +0800 Subject: [PATCH 2274/2794] xquery, added overload --- baseunits/XQueryEngineHTML.pas | 55 +++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/baseunits/XQueryEngineHTML.pas b/baseunits/XQueryEngineHTML.pas index 65d9cc372..27d4a802d 100644 --- a/baseunits/XQueryEngineHTML.pas +++ b/baseunits/XQueryEngineHTML.pas @@ -71,11 +71,15 @@ TXQueryEngineHTML = class TTreeNode = simplehtmltreeparser.TTreeNode; function XPathString(const Expression, HTMLString: String): String; overload; -function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; -function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; -procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; const TheStrings: TStrings); -procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); -procedure XPathHREFtitleAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATitles: TStrings); +function XPathString(const Expression: String; const HTMLStream: TStream): String; overload; inline; +function XPathCount(const Expression: String; const HTMLString: String): Integer; overload; +function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; overload; inline; +procedure XPathStringAll(const Expression: String; const HTMLString: String; const TheStrings: TStrings); overload; +procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; const TheStrings: TStrings); overload; inline; +procedure XPathHREFAll(const Expression: String; const HTMLString: String; const ALinks, ATexts: TStrings); overload; +procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATexts: TStrings); overload; inline; +procedure XPathHREFtitleAll(const Expression: String; const HTMLString: String; const ALinks, ATitles: TStrings); overload; +procedure XPathHREFtitleAll(const Expression: String; const HTMLStream: TStream; const ALinks, ATitles: TStrings); overload; inline; implementation @@ -128,10 +132,10 @@ function XPathString(const Expression: String; const HTMLStream: TStream): Strin Result := XPathString(Expression, StreamToString(HTMLStream)); end; -function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; +function XPathCount(const Expression: String; const HTMLString: String): Integer; begin Result := 0; - with TXQueryEngineHTML.Create(HTMLStream) do + with TXQueryEngineHTML.Create(HTMLString) do try Result := XPathCount(Expression); finally @@ -139,10 +143,15 @@ function XPathCount(const Expression: String; const HTMLStream: TStream): Intege end; end; -procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; +function XPathCount(const Expression: String; const HTMLStream: TStream): Integer; +begin + Result := XPathCount(Expression, StreamToString(HTMLStream)); +end; + +procedure XPathStringAll(const Expression: String; const HTMLString: String; const TheStrings: TStrings); begin - with TXQueryEngineHTML.Create(HTMLStream) do + with TXQueryEngineHTML.Create(HTMLString) do try XPathStringAll(Expression, TheStrings); finally @@ -150,10 +159,16 @@ procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; end; end; -procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; +procedure XPathStringAll(const Expression: String; const HTMLStream: TStream; + const TheStrings: TStrings); +begin + XPathStringAll(Expression, StreamToString(HTMLStream), TheStrings); +end; + +procedure XPathHREFAll(const Expression: String; const HTMLString: String; const ALinks, ATexts: TStrings); begin - with TXQueryEngineHTML.Create(HTMLStream) do + with TXQueryEngineHTML.Create(HTMLString) do try XPathHREFAll(Expression, ALinks, ATexts); finally @@ -161,10 +176,16 @@ procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; end; end; -procedure XPathHREFtitleAll(const Expression: String; - const HTMLStream: TStream; const ALinks, ATitles: TStrings); +procedure XPathHREFAll(const Expression: String; const HTMLStream: TStream; + const ALinks, ATexts: TStrings); +begin + XPathHREFAll(Expression, StreamToString(HTMLStream), ALinks, ATexts); +end; + +procedure XPathHREFtitleAll(const Expression: String; const HTMLString: String; + const ALinks, ATitles: TStrings); begin - with TXQueryEngineHTML.Create(HTMLStream) do + with TXQueryEngineHTML.Create(HTMLString) do try XPathHREFtitleAll(Expression, ALinks, ATitles); finally @@ -172,6 +193,12 @@ procedure XPathHREFtitleAll(const Expression: String; end; end; +procedure XPathHREFtitleAll(const Expression: String; + const HTMLStream: TStream; const ALinks, ATitles: TStrings); +begin + XPathHREFtitleAll(Expression, StreamToString(HTMLStream), ALinks, ATitles); +end; + { TXQueryEngineHTML } function TXQueryEngineHTML.Eval(const Expression: String; const isCSS: Boolean; From 9b728560657907e695f350cf134612d4b73bf9ec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 05:03:50 +0800 Subject: [PATCH 2275/2794] cleanup old codes --- baseunits/DBDataProcess.pas | 54 +- .../AnimExtremist/chapter_page_number.inc | 32 - .../includes/AnimExtremist/image_url.inc | 33 - .../AnimExtremist/manga_information.inc | 103 -- .../AnimExtremist/names_and_links.inc | 35 - .../AnimeStory/chapter_page_number.inc | 34 - baseunits/includes/AnimeStory/image_url.inc | 31 - .../includes/AnimeStory/manga_information.inc | 130 --- .../includes/AnimeStory/names_and_links.inc | 38 - .../Dynasty-Scans/chapter_page_number.inc | 44 - .../Dynasty-Scans/directory_page_number.inc | 6 - .../Dynasty-Scans/manga_information.inc | 101 -- .../Dynasty-Scans/names_and_links.inc | 34 - .../MangaHost/chapter_page_number.inc | 32 - .../MangaHost/directory_page_number.inc | 38 - baseunits/includes/MangaHost/image_url.inc | 28 - .../includes/MangaHost/manga_information.inc | 101 -- .../includes/MangaHost/names_and_links.inc | 36 - .../includes/MangaKu/chapter_page_number.inc | 34 - .../includes/MangaKu/manga_information.inc | 103 -- .../includes/MangaKu/names_and_links.inc | 39 - .../includes/MangaREADER_POR/image_url.inc | 45 - .../MangaREADER_POR/manga_information.inc | 191 ---- .../MangaREADER_POR/names_and_links.inc | 55 - .../MangaTown/chapter_page_number.inc | 41 - .../MangaTown/directory_page_number.inc | 41 - baseunits/includes/MangaTown/image_url.inc | 45 - .../includes/MangaTown/manga_information.inc | 109 -- .../includes/MangaTown/names_and_links.inc | 39 - .../includes/MangasPROJECT/image_url.inc | 46 - .../MangasPROJECT/manga_information.inc | 178 ---- .../MangasPROJECT/names_and_links.inc | 46 - .../includes/NHentai/chapter_page_number.inc | 37 - .../NHentai/directory_page_number.inc | 35 - baseunits/includes/NHentai/image_url.inc | 54 - .../includes/NHentai/manga_information.inc | 93 -- .../includes/NHentai/names_and_links.inc | 34 - baseunits/includes/ScanManga/image_url.inc | 45 - .../includes/ScanManga/manga_information.inc | 129 --- .../includes/ScanManga/names_and_links.inc | 47 - baseunits/uBaseUnit.pas | 488 --------- baseunits/uData.pas | 960 +----------------- baseunits/uDownloadsManager.pas | 122 +-- baseunits/uFavoritesManager.pas | 2 +- baseunits/uGetMangaInfosThread.pas | 6 +- baseunits/uSilentThread.pas | 2 +- baseunits/uUpdateThread.pas | 2 +- config/mangalist.ini | 14 +- mangadownloader/forms/frmDropTarget.pas | 36 +- mangadownloader/forms/frmImportFavorites.pas | 6 - mangadownloader/forms/frmMain.pas | 18 +- 51 files changed, 33 insertions(+), 4019 deletions(-) delete mode 100644 baseunits/includes/AnimExtremist/chapter_page_number.inc delete mode 100644 baseunits/includes/AnimExtremist/image_url.inc delete mode 100644 baseunits/includes/AnimExtremist/manga_information.inc delete mode 100644 baseunits/includes/AnimExtremist/names_and_links.inc delete mode 100644 baseunits/includes/AnimeStory/chapter_page_number.inc delete mode 100644 baseunits/includes/AnimeStory/image_url.inc delete mode 100644 baseunits/includes/AnimeStory/manga_information.inc delete mode 100644 baseunits/includes/AnimeStory/names_and_links.inc delete mode 100644 baseunits/includes/Dynasty-Scans/chapter_page_number.inc delete mode 100644 baseunits/includes/Dynasty-Scans/directory_page_number.inc delete mode 100644 baseunits/includes/Dynasty-Scans/manga_information.inc delete mode 100644 baseunits/includes/Dynasty-Scans/names_and_links.inc delete mode 100644 baseunits/includes/MangaHost/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaHost/directory_page_number.inc delete mode 100644 baseunits/includes/MangaHost/image_url.inc delete mode 100644 baseunits/includes/MangaHost/manga_information.inc delete mode 100644 baseunits/includes/MangaHost/names_and_links.inc delete mode 100644 baseunits/includes/MangaKu/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaKu/manga_information.inc delete mode 100644 baseunits/includes/MangaKu/names_and_links.inc delete mode 100644 baseunits/includes/MangaREADER_POR/image_url.inc delete mode 100644 baseunits/includes/MangaREADER_POR/manga_information.inc delete mode 100644 baseunits/includes/MangaREADER_POR/names_and_links.inc delete mode 100644 baseunits/includes/MangaTown/chapter_page_number.inc delete mode 100644 baseunits/includes/MangaTown/directory_page_number.inc delete mode 100644 baseunits/includes/MangaTown/image_url.inc delete mode 100644 baseunits/includes/MangaTown/manga_information.inc delete mode 100644 baseunits/includes/MangaTown/names_and_links.inc delete mode 100644 baseunits/includes/MangasPROJECT/image_url.inc delete mode 100644 baseunits/includes/MangasPROJECT/manga_information.inc delete mode 100644 baseunits/includes/MangasPROJECT/names_and_links.inc delete mode 100644 baseunits/includes/NHentai/chapter_page_number.inc delete mode 100644 baseunits/includes/NHentai/directory_page_number.inc delete mode 100644 baseunits/includes/NHentai/image_url.inc delete mode 100644 baseunits/includes/NHentai/manga_information.inc delete mode 100644 baseunits/includes/NHentai/names_and_links.inc delete mode 100644 baseunits/includes/ScanManga/image_url.inc delete mode 100644 baseunits/includes/ScanManga/manga_information.inc delete mode 100644 baseunits/includes/ScanManga/names_and_links.inc diff --git a/baseunits/DBDataProcess.pas b/baseunits/DBDataProcess.pas index 8f51a0b4d..e3f06d99c 100644 --- a/baseunits/DBDataProcess.pas +++ b/baseunits/DBDataProcess.pas @@ -11,7 +11,7 @@ interface uses Classes, SysUtils, FileUtil, LazFileUtils, FMDOptions, MultiLog, sqlite3conn, - sqlite3backup, sqlite3dyn, sqldb, DB, dateutils, RegExpr; + sqlite3backup, sqlite3dyn, sqldb, DB, RegExpr; type @@ -131,7 +131,6 @@ TDBDataProcess = class(TObject) '"jdn" INTEGER'; function DBDataFilePath(const AWebsite: String): String; -procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean = False); function DataFileExist(const AWebsite: String): Boolean; procedure CopyDBDataProcess(const AWebsite, NWebsite: String); function DeleteDBDataProcess(const AWebsite: String): Boolean; @@ -140,7 +139,7 @@ procedure OverwriteDBDataProcess(const AWebsite, NWebsite: String); implementation uses - uBaseUnit, uData; + uBaseUnit; function NaturalCompareCallback({%H-}user: pointer; len1: longint; data1: pointer; len2: longint; data2: pointer): longint; cdecl; @@ -194,53 +193,6 @@ function DBDataFilePath(const AWebsite: String): String; Result := DATA_FOLDER + AWebsite + DBDATA_EXT; end; -procedure ConvertDataProccessToDB(AWebsite: String; DeleteOriginal: Boolean); -var - filepath: String; - rawdata: TDataProcess; - dbdata: TDBDataProcess; - rcount: Integer; - i: Integer; -begin - filepath := DATA_FOLDER + AWebsite; - if FileExistsUTF8(filepath + DATA_EXT) then - begin - rawdata := TDataProcess.Create; - dbdata := TDBDataProcess.Create; - try - if FileExistsUTF8(filepath + DBDATA_EXT) then - DeleteFileUTF8(filepath + DBDATA_EXT); - rawdata.LoadFromFile(AWebsite); - dbdata.CreateDatabase(AWebsite); - if rawdata.Data.Count > 0 then - with rawdata do - begin - rcount := 0; - for i := 0 to Data.Count - 1 do - begin - dbdata.AddData(Title[i], Link[i], Authors[i], Artists[i], Genres[i], - Status[i], StringBreaks(Summary[i]), - StrToIntDef(Param[i, DATA_PARAM_NUMCHAPTER], 1), - {%H-}integer(JDN[i]) - 3); - Inc(rcount); - if rcount >= 5000 then - begin - rcount := 0; - dbdata.Commit; - end; - end; - dbdata.Commit; - end; - dbdata.Sort; - finally - rawdata.Free; - dbdata.Free; - end; - if DeleteOriginal then - DeleteFileUTF8(filepath + DATA_EXT); - end; -end; - function DataFileExist(const AWebsite: String): Boolean; begin if AWebsite = '' then @@ -682,8 +634,6 @@ function TDBDataProcess.Open(AWebsite: String): Boolean; if FWebsite = '' then Exit; filepath := DATA_FOLDER + FWebsite + DBDATA_EXT; - if not FileExistsUTF8(filepath) then - ConvertDataProccessToDB(AWebsite, True); if not FileExistsUTF8(filepath) then Exit; try diff --git a/baseunits/includes/AnimExtremist/chapter_page_number.inc b/baseunits/includes/AnimExtremist/chapter_page_number.inc deleted file mode 100644 index 7c63df939..000000000 --- a/baseunits/includes/AnimExtremist/chapter_page_number.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetAnimeExtremistPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), - '.html', '', []) + '-1.html', - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if Pos('</select>', parse[i]) > 0 then - begin - Task.Container.PageNumber := - StrToInt(GetString(TrimLeft(TrimRight(parse[i - 3] + '~!@')), 'Pagina ', '~!@')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/AnimExtremist/image_url.inc b/baseunits/includes/AnimExtremist/image_url.inc deleted file mode 100644 index 3a4bd6ac2..000000000 --- a/baseunits/includes/AnimExtremist/image_url.inc +++ /dev/null @@ -1,33 +0,0 @@ - function GetAnimeExtremistImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(StringReplace(FillMangaSiteHost(ANIMEEXTREMIST_ID, URL), - '.html', '', []) + '-' + IntToStr(WorkId + 1) + '.html'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('id="photo"', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'src'); - Task.Container.pageLinks[WorkId] := - GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/AnimExtremist/manga_information.inc b/baseunits/includes/AnimExtremist/manga_information.inc deleted file mode 100644 index fd7cd1f1a..000000000 --- a/baseunits/includes/AnimExtremist/manga_information.inc +++ /dev/null @@ -1,103 +0,0 @@ - function GetAnimeExtremistInfoFromURL: Byte; - var - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(ANIMEEXTREMIST_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[ANIMEEXTREMIST_ID, 0]; - mangaInfo.genres := ''; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get manga title - if (mangaInfo.title = '') and - (Pos(' Manga - Animextremist', parse[i]) > 0) then - mangaInfo.title := GetString('~!@' + parse[i], '~!@', - ' Manga - Animextremist'); - - // get cover link - if (mangaInfo.coverLink = '') and - (GetTagName(parse[i]) = 'img') then - if Pos('src="../', parse[i]) > 0 then - mangaInfo.coverLink := WebsiteRoots[ANIMEEXTREMIST_ID, 1] + - GetString(parse[i], 'src="..', '"'); - - // get summary - if (Pos('align="justify" class="style33"', parse[i])) <> 0 then - begin - j := i + 1; - mangaInfo.summary := ''; - while (Pos('<td height', parse[j]) = 0) and (j < parse.Count - 1) do - begin - s := parse[j]; - if (s <> '') and (s[1] <> '<') then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j] + '\n\r'; - end; - Inc(j); - end; - end; - - // get chapter name and links - if (Pos('/mangas-online/', parse[i]) <> 0) then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add( - StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [rfReplaceAll])); - parse[i + 1] := StringReplace(parse[i + 1], #10, '', [rfReplaceAll]); - parse[i + 1] := StringReplace(parse[i + 1], #13, '', [rfReplaceAll]); - parse[i + 1] := TrimLeft(parse[i + 1]); - parse[i + 1] := TrimRight(parse[i + 1]); - mangaInfo.chapterName.Add(HTMLEntitiesFilter( - StringFilter(TrimRight(RemoveSymbols(parse[i + 1]))))); - end; - - { // get authors - if (Pos('Autor(s):', parse[i])<>0) then - mangaInfo.authors:= parse[i+3]; - - // get artists - if (Pos('Artist(s):', parse[i])<>0) then - mangaInfo.artists:= parse[i+3]; } - - // get genres - if (Pos('ord=genero&id', parse[i]) <> 0) then - begin - mangaInfo.genres := mangaInfo.genres + - (HTMLEntitiesFilter(TrimLeft(TrimRight(parse[i + 1]))) + ', '); - end; - - // get status - if (Pos('class="manga_estado"', parse[i]) <> 0) then - begin - if Pos('Completo', parse[i + 3]) <> 0 then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/AnimExtremist/names_and_links.inc b/baseunits/includes/AnimExtremist/names_and_links.inc deleted file mode 100644 index 8833dde6b..000000000 --- a/baseunits/includes/AnimExtremist/names_and_links.inc +++ /dev/null @@ -1,35 +0,0 @@ - function AnimeExtremistGetNamesAndLinks: Byte; - var - i: Cardinal; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMEEXTREMIST_ID, 1] + - ANIMEEXTREMIST_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('id="manga" style="margin', parse[i]) <> 0 then - begin - Result := NO_ERROR; - ANames.Add(TrimLeft(TrimRight(parse[i + 4]))); - ALinks.Add(StringReplace(GetString(parse[i + 3], 'href="', '">'), - WebsiteRoots[ANIMEEXTREMIST_ID, 1], '', [])); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/AnimeStory/chapter_page_number.inc b/baseunits/includes/AnimeStory/chapter_page_number.inc deleted file mode 100644 index bdc601d9e..000000000 --- a/baseunits/includes/AnimeStory/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetAnimeStoryPageNumber: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + '1'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := parse.Count - 1 downto 5 do - begin - if (Pos('data-page=', parse[i]) > 0) then - begin - s := parse[i]; - Task.Container.pageNumber := - StrToInt(GetVal(s, 'data-page')); - Break; - end; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/AnimeStory/image_url.inc b/baseunits/includes/AnimeStory/image_url.inc deleted file mode 100644 index a85230e9d..000000000 --- a/baseunits/includes/AnimeStory/image_url.inc +++ /dev/null @@ -1,31 +0,0 @@ - function GetAnimeStoryImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(ANIMESTORY_ID, URL) + IntToStr(WorkId + 1)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('id="chpimg"', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := - DecodeURL(GetVal(parse[i], 'src')); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/AnimeStory/manga_information.inc b/baseunits/includes/AnimeStory/manga_information.inc deleted file mode 100644 index 7a1766fed..000000000 --- a/baseunits/includes/AnimeStory/manga_information.inc +++ /dev/null @@ -1,130 +0,0 @@ - function GetAnimeStoryInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.website := WebsiteRoots[ANIMESTORY_ID, 0]; - mangaInfo.url := FillMangaSiteHost(ANIMESTORY_ID, '/' + AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - { if (mangaInfo.coverLink = '') AND - (Pos('imageanchor="1"', parse[i])>0) then - mangaInfo.coverLink:= CorrectURL(GetVal(parse[i], 'href')); - } - // get title - if (Pos('<title>', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft( - TrimRight(HTMLEntitiesFilter(GetString('~!@' + parse[i + 1], - '~!@', ' | Anime-Story')))); - - if (not isExtractChapter) and (Pos('Liste des Chapitres', parse[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('href=', parse[i]) > 0) and - (Pos('Lecture', parse[i + 1]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[ANIMESTORY_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft( - TrimRight(GetVal(parse[i], 'title')))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - - if (isExtractChapter) and - (Pos('class=''comments''', parse[i]) > 0) then - isExtractChapter := False; - - // get summary - if (Pos('Synopsis', parse[i]) <> 0) and - (Pos('<h2>', parse[i - 1]) <> 0) then - begin - j := i + 4; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 5 < parse.Count) and (Pos('Auteur :', parse[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 5]))); - - // get artists - if (i + 5 < parse.Count) and (Pos('Illustrateur :', parse[i]) <> 0) then - mangaInfo.artists := StringFilter(TrimLeft(TrimRight(parse[i + 5]))); - - // get genres - if (Pos('Sous-genre(s) :', parse[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('search?subgenre', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse[i + 1])) + ', '; - if Pos('</td>', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 5 < parse.Count) and (Pos('Statut :', parse[i]) <> 0) then - begin - if (Pos('terminé', parse[i + 5]) <> 0) or - (Pos('one shot', parse[i + 5]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/AnimeStory/names_and_links.inc b/baseunits/includes/AnimeStory/names_and_links.inc deleted file mode 100644 index 93250f303..000000000 --- a/baseunits/includes/AnimeStory/names_and_links.inc +++ /dev/null @@ -1,38 +0,0 @@ - function AnimeStoryGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[ANIMESTORY_ID, 1] + - ANIMESTORY_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('class="left"', parse[i]) > 0) and - (Pos('href=', parse[i + 1]) > 0) then - begin - Result := NO_ERROR; - s := StringFilter(parse[i + 2]); - ANames.Add(HTMLEntitiesFilter(s)); - s := GetVal(parse[i + 1], 'href'); - ALinks.Add(s); - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/includes/Dynasty-Scans/chapter_page_number.inc b/baseunits/includes/Dynasty-Scans/chapter_page_number.inc deleted file mode 100644 index 02d06d6e7..000000000 --- a/baseunits/includes/Dynasty-Scans/chapter_page_number.inc +++ /dev/null @@ -1,44 +0,0 @@ - function GetDynastyScansPageNumber: Boolean; - var - i: Integer; - l: TStringList; - imgs_: string; - begin - l := TStringList.Create; - - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(DYNASTYSCANS_ID, URL)), - Task.Container.manager.retryConnect); - - imgs_ := ''; - if l.Count > 0 then - begin - for i := 0 to l.Count-1 do - if Pos('var pages = [', l[i]) > 0 then - begin - imgs_ := l[i]; - imgs_ := StringReplace(imgs_, 'var pages =', '', [rfIgnoreCase]); - imgs_ := Trim(TrimChar(imgs_, [';', ' '])); - Break; - end; - end; - l.Free; - - with Task.Container do - begin - if imgs_ <> '' then - begin - PageLinks.Clear; - ParseJSONArray(imgs_, 'image', PageLinks); - PageNumber := PageLinks.Count; - end; - - if PageLinks.Count > 0 then - for i := 0 to PageLinks.Count-1 do - begin - if Length(PageLinks[i]) > 0 then - if PageLinks[i][1] = '/' then - PageLinks[i] := WebsiteRoots[DYNASTYSCANS_ID, 1] + PageLinks[i]; - end; - end; - end; diff --git a/baseunits/includes/Dynasty-Scans/directory_page_number.inc b/baseunits/includes/Dynasty-Scans/directory_page_number.inc deleted file mode 100644 index b2f9576b2..000000000 --- a/baseunits/includes/Dynasty-Scans/directory_page_number.inc +++ /dev/null @@ -1,6 +0,0 @@ - function GetDynastyScansDirectoryPageNumber: Byte; - begin - Source.Free; - APage := Length(DYNASTYSCANS_BROWSER); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/Dynasty-Scans/manga_information.inc b/baseunits/includes/Dynasty-Scans/manga_information.inc deleted file mode 100644 index 64858eaf4..000000000 --- a/baseunits/includes/Dynasty-Scans/manga_information.inc +++ /dev/null @@ -1,101 +0,0 @@ - function GetDynastyScansInfoFromURL: Byte; - var - i, j: Integer; - hs: String = ''; - begin - mangaInfo.website := WebsiteRoots[DYNASTYSCANS_ID, 0]; - mangaInfo.url := FillMangaSiteHost(DYNASTYSCANS_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - begin - mangaInfo.genres := ''; - for i := 0 to parse.Count-1 do - begin - //title - if mangaInfo.title = '' then - if GetVal(parse[i], 'class') = 'tag-title' then - mangaInfo.title := CommonStringFilter(parse[i+2]); - - //cover - if mangaInfo.coverLink = '' then - if (GetTagName(parse[i]) = 'img') and - (GetVal(parse[i], 'class') = 'thumbnail') then - begin - mangaInfo.coverLink := GetVal(parse[i], 'src'); - if Length(mangaInfo.coverLink) > 0 then - if mangaInfo.coverLink[1] = '/' then - mangaInfo.coverLink := WebsiteRoots[DYNASTYSCANS_ID, 1] + - mangaInfo.coverLink; - end; - - if (GetTagName(parse[i]) = 'a') then - begin - //authors - if Pos('/authors/', parse[i]) <> 0 then - mangaInfo.authors := CommonStringFilter(parse[i+1]); - - //genre/tags - if GetVal(parse[i], 'class') = 'label' then - AddCommaString(mangaInfo.genres, CommonStringFilter(parse[i+1])); - end; - - //status - if GetTagName(parse[i]) = 'small' then - if Pos('ongoing', LowerCase(parse[i+1])) <> 0 then - mangaInfo.status := '1' - else - if Pos('completed', LowerCase(parse[i+1])) <> 0 then - mangaInfo.status := '0'; - - //genre/tags - if GetVal(parse[i], 'class') = 'doujin_tags' then - AddCommaString(mangaInfo.genres, CommonStringFilter(parse[i+2])); - - //summary - if (GetTagName(parse[i]) = 'div') and - (GetVal(parse[i], 'class') = 'description') then - begin - mangaInfo.summary := ''; - for j := i+1 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/div' then - Break - else - if Pos('<', parse[j]) = 0 then - mangaInfo.summary := mangaInfo.summary + LineEnding + CommonStringFilter(parse[j]); - end; - mangaInfo.summary := Trim(mangaInfo.summary); - end; - - //chapters - if (GetTagName(parse[i]) = 'dl') and - (GetVal(parse[i], 'class') = 'chapter-list') then - begin - for j := i+1 to parse.Count-1 do - begin - if GetTagName(parse[j]) = '/dl' then - Break - else - if (GetTagName(parse[j]) = 'a') and - (GetVal(parse[j], 'class') = 'name') then - begin - mangaInfo.chapterLinks.Add(GetVal(parse[j], 'href')); - mangaInfo.chapterName.Add(Trim(hs + CommonStringFilter(parse[j+1]))); - end - else - if GetTagName(parse[j]) = 'dt' then - hs := CommonStringFilter(parse[j+1]) + ' '; - end; - end; - end; - Result := NO_ERROR; - end; - end; diff --git a/baseunits/includes/Dynasty-Scans/names_and_links.inc b/baseunits/includes/Dynasty-Scans/names_and_links.inc deleted file mode 100644 index 07ef40bd3..000000000 --- a/baseunits/includes/Dynasty-Scans/names_and_links.inc +++ /dev/null @@ -1,34 +0,0 @@ - function DynastyScansGetNamesAndLinks: Byte; - var - i: Integer; - s: string; - begin - Result := INFORMATION_NOT_FOUND; - i := StrToIntDef(AURL, 0); - if i >= Length(DYNASTYSCANS_BROWSER) then - begin - Source.Free; - Exit; - end; - - s := WebsiteRoots[DYNASTYSCANS_ID, 1] + DYNASTYSCANS_BROWSER[i]; - if not GetPage(TObject(Source), s, 1) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - ParseHTML(Source.Text, parse); - Source.Free; - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - if GetTagName(parse[i]) = 'dd' then - if GetTagName(parse[i+1]) = 'a' then - begin - ALinks.Add(GetVal(parse[i+1], 'href')); - ANames.Add(CommonStringFilter(parse[i+2])); - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaHost/chapter_page_number.inc b/baseunits/includes/MangaHost/chapter_page_number.inc deleted file mode 100644 index 4f5721188..000000000 --- a/baseunits/includes/MangaHost/chapter_page_number.inc +++ /dev/null @@ -1,32 +0,0 @@ - function GetMangaHostPageNumber: Boolean; - var - i: Integer; - l: TStringList; - isGetPageNumber: Boolean = False; - begin - l := TStringList.Create; - parse := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL)), - Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and (Pos('class="viewerPage', parse[i]) > 0) then - isGetPageNumber := True; - if isGetPageNumber and (Pos('</select', parse[i]) > 0) then - Break; - if isGetPageNumber and (Pos('<option', parse[i]) > 0) then - Inc(Task.Container.PageNumber); - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaHost/directory_page_number.inc b/baseunits/includes/MangaHost/directory_page_number.inc deleted file mode 100644 index 96547ef97..000000000 --- a/baseunits/includes/MangaHost/directory_page_number.inc +++ /dev/null @@ -1,38 +0,0 @@ - function GetMangaHostDirectoryPageNumber: Byte; - var - i, p: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAHOST_ID, 1] + - MANGAHOST_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - - APage := 1; - for i := parse.Count - 1 downto 2 do - begin - if (Pos('<a', parse[i]) > 0) and (Pos('class="last', parse[i]) > 0) then - begin - p := StrToIntDef(ReplaceRegExpr('^.*/(\d+)$', GetVal(parse[i], 'href'), '$1', True), 0); - if APage < p then - APage := p; - Break; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MangaHost/image_url.inc b/baseunits/includes/MangaHost/image_url.inc deleted file mode 100644 index 77f26a5e4..000000000 --- a/baseunits/includes/MangaHost/image_url.inc +++ /dev/null @@ -1,28 +0,0 @@ - function GetMangaHostImageURL: Boolean; - var - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - Result := GetPage(TObject(l), - DecodeUrl(FillMangaSiteHost(MANGAHOST_ID, URL) + '/' + IntToStr(WorkId + 1)), - Task.Container.manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - if (Pos('<img', parse[i]) > 0) and (Pos('class="open', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaHost/manga_information.inc b/baseunits/includes/MangaHost/manga_information.inc deleted file mode 100644 index f96daa526..000000000 --- a/baseunits/includes/MangaHost/manga_information.inc +++ /dev/null @@ -1,101 +0,0 @@ - function GetMangaHostInfoFromURL: Byte; - var - i: Integer; - isExtractGenres: Boolean = False; - isExtractSummary: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAHOST_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAHOST_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - - mangaInfo.genres := ''; - mangaInfo.summary := ''; - - for i := 0 to parse.Count - 1 do - begin - //cover - if (Pos('<img', parse[i]) > 0) and (Pos('class="pull-left thumbnail', parse[i]) > 0) then - mangaInfo.coverLink := GetVal(parse[i], 'src'); - - //title - if (Pos('<h1' , parse[i]) > 0) and (Pos('class="entry-title', parse[i]) > 0) then - mangaInfo.title := CommonStringFilter(parse[i + 1]); - - //author(s) - if Pos('Autor:', parse[i]) > 0 then - mangaInfo.authors := CommonStringFilter(parse[i + 2]); - - //artist(s) - if Pos('Desenho (Art):', parse[i]) > 0 then - mangaInfo.artists := CommonStringFilter(parse[i + 2]); - - //status - if Pos('Status:', parse[i]) > 0 then - if (Trim(LowerCase(parse[i + 2])) = 'completo') then - mangaInfo.status := '0' - else - mangaInfo.status := '1'; - - //genres - if Pos('Categoria(s):', parse[i]) > 0 then - isExtractGenres := True; - if isExtractGenres and (Pos('</li', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('<', parse[i]) = 0) and - (Pos('Categoria(s):', parse[i]) = 0) then - begin - parse[i] := Trim(parse[i]); - if parse[i] = ',' then - parse[i] := ', '; - mangaInfo.genres := mangaInfo.genres + parse[i]; - end; - - //summary - if (Pos('<div', parse[i]) > 0) and (Pos('id="divSpdInText', parse[i]) > 0) then - isExtractSummary := True; - if isExtractSummary and (Pos('</div', parse[i]) > 0) then - isExtractSummary := False; - if isExtractSummary then - begin - if Trim(parse[i]) = '<p>' then - mangaInfo.summary := mangaInfo.summary + LineEnding; - if (Pos('<', parse[i]) = 0) then - mangaInfo.summary := mangaInfo.summary + Trim(parse[i]); - end; - - //chapter(s) - if Pos('class="capitulo"', parse[i]) > 0 then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[MANGAHOST_ID, 1], '', [rfIgnoreCase])); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - - //invert chapter(s) - if mangaInfo.chapterLinks.Count > 1 then - begin - InvertStrings(mangaInfo.chapterLinks); - InvertStrings(mangaInfo.chapterName); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaHost/names_and_links.inc b/baseunits/includes/MangaHost/names_and_links.inc deleted file mode 100644 index 41f996584..000000000 --- a/baseunits/includes/MangaHost/names_and_links.inc +++ /dev/null @@ -1,36 +0,0 @@ - function MangaHostGetNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAHOST_ID, 1] + - MANGAHOST_BROWSER + '/page/' + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) > 0) and (Pos('class="pull-left', parse[i]) > 0) and - (Pos('title=', parse[i]) > 0) then - begin - ALinks.Add(GetVal(parse[i], 'href')); - //ANames.Add(CommonStringFilter(GetVal(parse[i], 'title'))); - ANames.Add(CommonStringFilter(parse[i + 6])); - end; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/includes/MangaKu/chapter_page_number.inc b/baseunits/includes/MangaKu/chapter_page_number.inc deleted file mode 100644 index 0ab37f7f1..000000000 --- a/baseunits/includes/MangaKu/chapter_page_number.inc +++ /dev/null @@ -1,34 +0,0 @@ - function GetMangaKuPageNumber: Boolean; - var - s: String; - i: Integer; - l: TStringList; - begin - l := TStringList.Create; - parse := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAKU_ID, URL)); - Result := GetPage(TObject(l), - s, - Task.Container.manager.retryConnect); - - Parser := THTMLParser.Create(l.Text); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'imageanchor') = '1') then - if GetTagName(parse[i + 1]) = 'img' then - Task.Container.PageLinks.Add(GetVal(parse[i + 1], 'src')); - Task.Container.PageNumber := Task.container.PageLinks.Count; - end; - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaKu/manga_information.inc b/baseunits/includes/MangaKu/manga_information.inc deleted file mode 100644 index 58ecc6339..000000000 --- a/baseunits/includes/MangaKu/manga_information.inc +++ /dev/null @@ -1,103 +0,0 @@ - function GetMangaKuInfoFromURL: Byte; - var - s: String; - i: Integer; - isExtractChapter: Boolean = False; - begin - mangaInfo.website := WebsiteRoots[MANGAKU_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGAKU_ID, AURL); - if mangaInfo.url <> '' then - if mangaInfo.url[Length(mangaInfo.url)] <> '/' then - mangaInfo.url := mangaInfo.url + '/'; - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - s := FixCommonBrokenHTML(Source.Text); - Source.Free; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(s); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - finally - Parser.Free; - end; - - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - //title - if mangaInfo.title = '' then - if GetTagName(parse[i]) = 'title' then - begin - s := Trim(parse[i + 1]); - if s <> '' then - begin - s := StringReplace(s, '–', '-', [rfReplaceAll]); - s := StringReplace(s, 'Baca', '', [rfIgnoreCase]); - s := StringReplace(s, 'Online Komik', '', [rfIgnoreCase]); - s := StringReplace(s, 'Komik -', '', [rfIgnoreCase]); - s := StringReplace(s, 'Komik', '', [rfIgnoreCase]); - s := StringReplace(s, 'Manga -', '', [rfIgnoreCase]); - s := StringReplace(s, 'Manga', '', [rfIgnoreCase]); - s := StringReplace(s, 'Online -', '', [rfIgnoreCase]); - s := StringReplace(s, 'Terbaru', '', [rfIgnoreCase]); - s := StringReplace(s, 'Bahasa Indonesia', '', [rfIgnoreCase]); - s := TrimLeftChar(Trim(s), ['-', ':', ' ']); - mangaInfo.title := CommonStringFilter(s); - end; - end; - - //cover - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'imageanchor') = '1') then - if GetTagName(parse[i + 1]) = 'img' then - mangaInfo.coverLink := GetVal(parse[i + 1], 'src'); - - //authors/artists/genre/status - if GetTagName(parse[i]) = 'b' then - begin - if Pos('Author(s)', parse[i + 1]) > 0 then - mangaInfo.authors := CommonStringFilter(TrimLeftChar(parse[i + 3], [':'])); - if Pos('Artist(s)', parse[i + 1]) > 0then - mangaInfo.artists := CommonStringFilter(TrimLeftChar(parse[i + 3], [':'])); - if Pos('Genre', parse[i + 1]) > 0 then - mangaInfo.genres := CommonStringFilter(TrimLeftChar(parse[i + 3], [':'])); - if Pos('Episodes', parse[i + 1]) > 0 then - begin - s := Trim(TrimLeftChar(parse[i + 3], [':'])); - if LowerCase(s) = 'ongoing' then - mangaInfo.status := '1' - else - mangaInfo.status := '0'; - end; - end; - - //chapters - if (GetTagName(parse[i]) = 'div') and (Pos('-moz-border-radius', parse[i]) > 0) then - isExtractChapter := True; - if isExtractChapter then - if GetTagName(parse[i]) = '/div' then - isExtractChapter := False - else - if GetTagName(parse[i]) = 'a' then - begin - Inc(mangaInfo.numChapter); - mangaInfo.chapterLinks.Add(GetVal(parse[i], 'href')); - mangaInfo.chapterName.Add(CommonStringFilter(parse[i + 1])); - end; - end; - end; - - //invert chapters - if mangaInfo.chapterLinks.Count > 0 then - InvertStrings([mangaInfo.chapterName, mangaInfo.chapterLinks]); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaKu/names_and_links.inc b/baseunits/includes/MangaKu/names_and_links.inc deleted file mode 100644 index 8a1069402..000000000 --- a/baseunits/includes/MangaKu/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function MangaKuGetNamesAndLinks: Byte; - var - i: Integer; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGAKU_ID, 1] + - '/daftar-komik-bahasa-indonesia/', 3) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - s := FixCommonBrokenHTML(Source.Text); - Source.Free; - - parse.Clear; - Parser := THTMLParser.Create(s); - try - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - finally - Parser.Exec; - end; - Parser.Free; - - if parse.Count > 0 then - for i := 0 to parse.Count - 1 do - begin - if (GetTagName(parse[i]) = 'a') and (GetVal(parse[i], 'class') = 'screenshot') then - begin - ALinks.Add(GetVal(parse[i], 'href')); - ANames.Add(CommonStringFilter(parse[i + 1])); - end; - end; - - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaREADER_POR/image_url.inc b/baseunits/includes/MangaREADER_POR/image_url.inc deleted file mode 100644 index cb8ed0ed1..000000000 --- a/baseunits/includes/MangaREADER_POR/image_url.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetMangaREADER_PORImageURL: Boolean; - var - s: String; - i: Cardinal; - l: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGAREADER_POR_ID, URL) + '/#1'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - Task.Container.pageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('function Proxima()', parse[i]) > 0 then - begin - //s:= GetString(parse[i], 'new Array("",', 'function Proxima'); - s := GetString(parse[i], 'new Array("",', ');'); - s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); - Task.Container.PageLinks.DelimitedText := s; - Break; - //repeat - // j:= Pos('http://', s); - // Task.Container.PageLinks.Add(EncodeURL(GetString(s, '"', '"'))); - // s:= StringReplace(s, '"', '', []); - // s:= StringReplace(s, '"', '', []); - // Delete(s, j, 7); - // j:= Pos('http://', s); - //until j = 0; - end; - end; - end; - - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangaREADER_POR/manga_information.inc b/baseunits/includes/MangaREADER_POR/manga_information.inc deleted file mode 100644 index 37c00716a..000000000 --- a/baseunits/includes/MangaREADER_POR/manga_information.inc +++ /dev/null @@ -1,191 +0,0 @@ - function GetMangaREADER_PORInfoFromURL: Byte; - var - s: String; - isExtractChapter: Boolean = False; - i, j, n: Cardinal; - numberOfPage: Cardinal = 1; - - procedure ExtractChapter; - begin - if (not isExtractChapter) and (Pos('id="listagemCaps', parse[i]) > 0) then - isExtractChapter := True; - - if (isExtractChapter) and - (Pos('paginacao', parse[i]) > 0) then - isExtractChapter := False; //bermasalah - - // get chapter name and links - if (isExtractChapter) and - (Pos('</em>', parse[i]) > 0) and - (i + 6 < parse.Count - 1) then - begin - Inc(mangaInfo.numChapter); - //s:= StringReplace(GetString(parse[i+6], 'href="', '"'), WebsiteRoots[MANGAREADER_POR_ID,1], '', []); - //mangaInfo.chapterLinks.Add(s); - s := GetVal(parse[i + 6], 'href'); - s := StringReplace(s, WebsiteRoots[MANGAREADER_POR_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - end; - - begin - mangaInfo.url := FillMangaSiteHost(MANGAREADER_POR_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //weird stuff - if Source.Count > 1 then - Source.Text := StringReplace(Source.Text, '<3', '❤', [rfReplaceAll, rfIgnoreCase]); - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[MANGAREADER_POR_ID, 0]; - mangaInfo.status := '0'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - - isExtractChapter := False; - for i := 0 to parse.Count - 1 do - begin - // Get number of page. - if Pos('Última Página', parse[i]) > 0 then - numberOfPage := StrToInt(GetString(parse[i - 1], '/page/', '">')); - - // get cover - //if (mangaInfo.coverLink='') AND - // (Pos('img src="', parse[i])>0) AND - // (Pos('class="imgClass"', parse[i])>0) then - // mangaInfo.coverLink:=GetVal(parse[i], 'src'); - - {if (mangaInfo.coverLink = '') AND - (Pos('class="cvr', parse[i])>0) then - mangaInfo.coverLink:= CorrectURL(GetVal(parse[i], 'src'));} - - // get title - if (Pos('Título:', parse[i]) > 0) then - mangaInfo.title := parse[i + 2]; - - ExtractChapter; - - //Not available - // get summary - //if (Pos('class="text', parse[i]) <> 0) then - //begin - // j:= i+9; - // while (j<parse.Count) AND (Pos('</div>', parse[j])=0) do - // begin - // s:= parse[j]; - // if s[1] <> '<' then - // begin - // parse[j]:= HTMLEntitiesFilter(StringFilter(TrimLeft(parse[j]))); - // parse[j]:= StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - // parse[j]:= StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - // mangaInfo.summary:= mangaInfo.summary + parse[j]; - // break; - // end; - // Inc(j); - // end; - // isExtractSummary:= FALSE; - //end; - - // get authors - if (Pos('Autor:', parse[i]) > 0) then - mangaInfo.authors := Trim(StringFilter(parse[i + 2])); - - // get artists - if (Pos('Artista:', parse[i]) > 0) then - mangaInfo.artists := Trim(StringFilter(parse[i + 2])); - - // get genres - if Pos('Categoria:', parse[i]) > 0 then - mangaInfo.genres := parse[i + 4]; - //if (Pos('class="cat', parse[i])<>0) then - //begin - // isExtractGenres:= TRUE; - //end; - - //if isExtractGenres then - //begin - // if Pos('', parse[i]) <> 0 then - // mangaInfo.genres:= mangaInfo.genres + TrimLeft(TrimRight(parse[i+1])) + ', '; - // if Pos('</br>', parse[i]) <> 0 then - // isExtractGenres:= FALSE; - //end; - - // not available - // get status - //if (i+2<parse.Count) AND (Pos('Status', parse[i])<>0) then - //begin - // if Pos('Ongoing', parse[i+3])<>0 then - // mangaInfo.status:= '1' // ongoing - // else - // mangaInfo.status:= '0'; // completed - //end; - end; - - // If there're more than 1 page, we need to continue to scrape for chapters ... - if numberOfPage > 1 then - begin - for n := 2 to numberOfPage do - begin - Source.Clear; - s := mangaInfo.url + '/' + IntToStr(n); - if not GetPage(TObject(Source), mangaInfo.url + '/page/' + - IntToStr(n), AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - //weird stuff - if Source.Count > 1 then - Source.Text := StringReplace(Source.Text, '<3', '❤', [rfReplaceAll, rfIgnoreCase]); - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - isExtractChapter := False; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - ExtractChapter; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaREADER_POR/names_and_links.inc b/baseunits/includes/MangaREADER_POR/names_and_links.inc deleted file mode 100644 index 4bf722d86..000000000 --- a/baseunits/includes/MangaREADER_POR/names_and_links.inc +++ /dev/null @@ -1,55 +0,0 @@ - function MangaREADER_PORGetNamesAndLinks: Byte; - var - i: LongInt; - s: String; - parser: TJSONParser; - Data: TJSONData; - jobject: TJSONObject; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(source), - WebsiteRoots[MANGAREADER_POR_ID, 1] + '/AJAX/listaMangas/all', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - //UTF8BOM:string=#$EF#$BB#$BF - //Remove BOM header, jsonparser can't deal with BOM - s := Source.Text; - if Length(s) > 3 then - begin - if Copy(s, 1, 3) = UTF8BOM then - Delete(s, 1, 3); - end; - {$IF (FPC_FULLVERSION >= 30101)} - parser := TJSONParser.Create(s, [joUTF8]); - {$ELSE} - parser := TJSONParser.Create(s, True); - {$ENDIF} - try - Data := parser.Parse; - try - if Assigned(Data) then - begin - if Data.JSONType = jtArray then - begin - for i := 0 to Data.Count - 1 do - begin - jobject := TJSONObject(Data.Items[i]); - ANames.Add(jobject.Strings['title']); - ALinks.Add(StringReplace(jobject.Strings['serie_url'], - WebsiteRoots[MANGAREADER_POR_ID, 1], '', [])); - end; - end; - end; - finally - Data.Free; - end; - finally - parser.Free; - end; - Result := NO_ERROR; - Source.Free; - end; diff --git a/baseunits/includes/MangaTown/chapter_page_number.inc b/baseunits/includes/MangaTown/chapter_page_number.inc deleted file mode 100644 index 6fe3fc2f6..000000000 --- a/baseunits/includes/MangaTown/chapter_page_number.inc +++ /dev/null @@ -1,41 +0,0 @@ - function GetMangaTownPageNumber: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - isExtractPage: Boolean = False; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(MANGATOWN_ID, URL); - Result := GetPage(TObject(l), s, Task.Container.Manager.retryConnect); - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<select', parse[i]) > 0) and - (Pos('onchange="javascript:location.href=this.value;"', parse[i]) > 0) then - isExtractPage := True; - if isExtractPage and - (Pos('</select', parse[i]) > 0) then - begin - isExtractPage := False; - Break; - end; - if isExtractPage and - (Pos('<option', parse[i]) > 0) and - (Pos('featured', parse[i]) = 0) then - begin - Inc(Task.Container.PageNumber); - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/MangaTown/directory_page_number.inc b/baseunits/includes/MangaTown/directory_page_number.inc deleted file mode 100644 index 9d711acf2..000000000 --- a/baseunits/includes/MangaTown/directory_page_number.inc +++ /dev/null @@ -1,41 +0,0 @@ - function GetMangaTownDirectoryPageNumber: Byte; - var - i: Cardinal; - isExtractPage: Boolean = False; - begin - APage := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGATOWN_ID, 1] + - MANGATOWN_BROWSER + '?name.az', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if Pos('<select onchange="javascript:location.href=this.value;">', parse[i]) > 0 then - isExtractPage := True; - if isExtractPage and - (Pos('</select', parse[i]) > 0) then - isExtractPage := False; - if isExtractPage and - (Pos('<option', parse[i]) > 0) then - begin - Inc(APage); - Result := NO_ERROR; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MangaTown/image_url.inc b/baseunits/includes/MangaTown/image_url.inc deleted file mode 100644 index 141a1e977..000000000 --- a/baseunits/includes/MangaTown/image_url.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetMangaTownImageURL: Boolean; - var - i: Cardinal; - l: TStringList; - s: String; - begin - if (WorkId = Task.Container.PageLinks.Count - 1) and (Pos('/featured.', URL) <> 0) then - begin - Task.Container.PageLinks.Delete(WorkId); - Exit; - end; - - l := TStringList.Create; - s := AppendURLDelim(FillMangaSiteHost(MANGATOWN_ID, URL)); - if WorkId > 0 then - s := s + IncStr(WorkId) + '.html'; - Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if (Pos('<img', parse[i]) > 0) and (Pos('alt=', parse[i]) > 0) then - begin - Task.Container.PageLinks[WorkId] := GetVal(parse[i], 'src'); - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/MangaTown/manga_information.inc b/baseunits/includes/MangaTown/manga_information.inc deleted file mode 100644 index fc23f972c..000000000 --- a/baseunits/includes/MangaTown/manga_information.inc +++ /dev/null @@ -1,109 +0,0 @@ - function GetMangaTownInfoFromURL: Byte; - var - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - s: String; - i: Cardinal; - begin - mangaInfo.website := WebsiteRoots[MANGATOWN_ID, 0]; - mangaInfo.url := FillMangaSiteHost(MANGATOWN_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - - mangaInfo.genres := ''; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (i + 2 < parse.Count - 1) then - if (Pos('class="detail_info clearfix"', parse[i]) > 0) and (Pos('<img', parse[i + 2]) > 0) then - mangaInfo.coverLink := GetVal(parse[i + 2], 'src'); - - // get title - if (i + 1 < parse.Count - 1) then - if (Pos('class="title-top"', parse[i]) > 0) and (mangaInfo.title = '') then - mangaInfo.title := Trim(StringFilter(parse[i + 1])); - - // get genres - if (i + 1 < parse.Count - 1) then - if ((Pos('Demographic:', parse[i]) > 0) or (Pos('Genre(s):', parse[i]) > 0)) and - (Pos('</b', parse[i + 1]) > 0) then - isExtractGenres := True; - if isExtractGenres and - (Pos('</li', parse[i]) > 0) then - isExtractGenres := False; - if isExtractGenres and (Pos('<a ', parse[i]) > 0) then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - if (i + 3 < parse.Count - 1) then - if (Pos('Type:', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 3]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 3]); - end; - - // get authors - if (i + 3 < parse.Count - 1) then - if (Pos('Author(s):', parse[i]) > 0) and (Pos('</b', parse[i + 1]) > 0) then - begin - mangaInfo.authors := Trim(parse[i + 3]); - if Pos(';', mangaInfo.authors) > 0 then - begin - mangaInfo.authors := StringReplace(mangaInfo.authors, ' ; ', ', ', [rfReplaceAll]); - mangaInfo.authors := StringReplace(mangaInfo.authors, '; ', ', ', [rfReplaceAll]); - end; - end; - - // get summary - if (i + 1 < parse.Count - 1) then - if (Pos('<span', parse[i]) > 0) and (Pos('id="show"', parse[i]) > 0) then - mangaInfo.summary := Trim(HTMLEntitiesFilter(StringFilter(parse[i + 1]))); - - //get chapter links and names - if (Pos('<ul', parse[i]) > 0) and - (Pos('class="chapter_list"', parse[i]) > 0) then - isExtractChapter := True; - if isExtractChapter and (Pos('</ul', parse[i]) > 0) then - isExtractChapter := False; - if isExtractChapter and - (i + 9 < parse.Count - 1) then - if (Pos('<a ', parse[i]) > 0) then - begin - s := GetVal(parse[i], 'href'); - s := StringReplace(s, WebsiteRoots[MANGATOWN_ID, 1], '', [rfIgnoreCase]); - mangaInfo.chapterLinks.Add(s); - s := Trim(RemoveSymbols(parse[i + 1])); - //if Pos('class="', parse[i + 4]) = 0 then - if Pos('<span>', parse[i + 4]) > 0 then - s := s + ' ' + Trim(RemoveSymbols(parse[i + 5])); - //if Pos('class="', parse[i + 8]) = 0 then - if Pos('<span>', parse[i + 8]) > 0 then - s := s + ' ' + Trim(RemoveSymbols(parse[i + 9])); - mangaInfo.chapterName.Add(Trim(s)); - end; - end; - - // Since chapter name and link are inverted, we need to invert them - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangaTown/names_and_links.inc b/baseunits/includes/MangaTown/names_and_links.inc deleted file mode 100644 index 625d04846..000000000 --- a/baseunits/includes/MangaTown/names_and_links.inc +++ /dev/null @@ -1,39 +0,0 @@ - function MangaTownGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[MANGATOWN_ID, 1] + - MANGATOWN_BROWSER + IntToStr(StrToInt(AURL) + 1) + '.htm?name.az', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<P class="title"', parse[i]) > 0) and - (i + 2 < parse.Count - 1) then - begin - Result := NO_ERROR; - s := Trim(HTMLEntitiesFilter(StringFilter(GetVal(parse[i + 2], 'title')))); - ANames.Add(s); - s := GetVal(parse[i + 2], 'href'); - s := StringReplace(s, WebsiteRoots[MANGATOWN_ID, 1], '', [rfIgnoreCase]); - ALinks.Add(s); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/MangasPROJECT/image_url.inc b/baseunits/includes/MangasPROJECT/image_url.inc deleted file mode 100644 index 94f75aaff..000000000 --- a/baseunits/includes/MangasPROJECT/image_url.inc +++ /dev/null @@ -1,46 +0,0 @@ - function GetMangasPROJECTImageURL: Boolean; - var - s: String; - j, i: Cardinal; - l, ts: TStringList; - begin - l := TStringList.Create; - s := DecodeUrl(FillMangaSiteHost(MANGASPROJECT_ID, URL) + '/#1'); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - - if parse.Count > 0 then - begin - Task.Container.PageLinks.Clear; - for i := 0 to parse.Count - 1 do - begin - if Pos('{ path: ', parse[i]) > 0 then - begin - s := GetString(parse[i], 'new Array({ path: ', '});'); - s := StringReplace(s, sLineBreak, '', [rfReplaceAll]); - ts := TStringList.Create; - try - ts.DelimitedText := s; - for j := 0 to ts.Count - 1 do - begin - if Pos('http', ts[j]) > 0 then - Task.Container.PageLinks.Add(ts[j]); - end; - finally - ts.Free; - end; - Break; - end; - end; - end; - - parse.Free; - l.Free; - end; diff --git a/baseunits/includes/MangasPROJECT/manga_information.inc b/baseunits/includes/MangasPROJECT/manga_information.inc deleted file mode 100644 index 059e01695..000000000 --- a/baseunits/includes/MangasPROJECT/manga_information.inc +++ /dev/null @@ -1,178 +0,0 @@ - function GetMangasPROJECTInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - isExtractChapter: Boolean = False; - i, j, n: Cardinal; - numberOfPage: Cardinal = 1; - - procedure ExtractChapter; - begin - if (not isExtractChapter) and (Pos('class="chapter_cont', parse[i]) > 0) then - isExtractChapter := True; - - // get chapter name and links - if (isExtractChapter) and - (Pos('class="nome', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetString(parse[i + 22], 'href="', '"'), - WebsiteRoots[MANGASPROJECT_ID, 1], '', []); - mangaInfo.chapterLinks.Add(s); - s := RemoveSymbols(TrimLeft(TrimRight(parse[i + 1]))); - s := StringFilter(HTMLEntitiesFilter(s)); - if Length(s) >= 3 then - begin - s := Copy(s, 1, Length(s) - 2); - s := StringReplace(s, '- ' + #39, '- ', []); - end; - mangaInfo.chapterName.Add(s); - end; - - if (isExtractChapter) and - (Pos('paginacao', parse[i]) > 0) then - isExtractChapter := False; //bermasalah - end; - - begin - mangaInfo.url := FillMangaSiteHost(MANGASPROJECT_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - mangaInfo.website := WebsiteRoots[MANGASPROJECT_ID, 0]; - mangaInfo.status := '0'; - mangaInfo.coverLink := ''; - mangaInfo.summary := ''; - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - //Get number of pages - //Don't know why unicode pos not work here - if (Pos('tima', parse[i]) > 0) and - (Pos('gina', parse[i]) > 0) then - numberOfPage := StrToInt(GetString(parse[i - 1], '/page/', '">')); - - // get cover - if Pos('class="side"', parse[i]) > 0 then - mangaInfo.coverLink := CorrectURL(GetVal(parse[i + 2], 'src')); - - // get title - if (Pos('class="text', parse[i]) > 0) then - mangaInfo.title := parse[i + 3]; - - // get summary - if (Pos('class="text', parse[i]) <> 0) then - begin - j := i + 9; - while (j < parse.Count) and (Pos('</div>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter( - StringFilter(TrimLeft(parse[j]))); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - Break; - end; - Inc(j); - end; - end; - - ExtractChapter; - - // get authors - if (Pos('class="text', parse[i]) <> 0) then - mangaInfo.authors := TrimLeft(StringFilter(parse[i + 7])); - - // get artists - if (Pos('class="text', parse[i]) <> 0) then - mangaInfo.artists := TrimLeft(StringFilter(parse[i + 7])); - - // get genres - if (Pos('class="cat', parse[i]) <> 0) then - begin - isExtractGenres := True; - end; - - if isExtractGenres then - begin - if Pos('', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - TrimLeft(TrimRight(parse[i + 1])) + ', '; - if Pos('</br>', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 2 < parse.Count) and (Pos('Status', parse[i]) <> 0) then - begin - if Pos('Ongoing', parse[i + 3]) <> 0 then - mangaInfo.status := '1' // ongoing - else - mangaInfo.status := '0'; // completed - end; - end; - - //Extract chapter - if numberOfPage > 1 then - begin - for n := 2 to numberOfPage do - begin - Source.Clear; - s := mangaInfo.url + '/' + IntToStr(n); - if not GetPage(TObject(Source), mangaInfo.url + '/page/' + - IntToStr(n), AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - isExtractChapter := False; - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - ExtractChapter; - end; - end; - Source.Free; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/MangasPROJECT/names_and_links.inc b/baseunits/includes/MangasPROJECT/names_and_links.inc deleted file mode 100644 index 533738b41..000000000 --- a/baseunits/includes/MangasPROJECT/names_and_links.inc +++ /dev/null @@ -1,46 +0,0 @@ - function MangasPROJECTGetNamesAndLinks: Byte; - var - i: Cardinal; - url: String; - sstream: TStringStream; - parser: TJSONParser; - Data: TJSONData; - begin - Result := INFORMATION_NOT_FOUND; - url := 'http://www.mangasproject.net/AJAX/listaMangas/all'; - if not GetPage(TObject(Source), url, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - sstream := TStringStream.Create(Source.Text); - {$IF (FPC_FULLVERSION >= 30101)} - parser := TJSONParser.Create(sstream, [joUTF8]); - {$ELSE} - parser := TJSONParser.Create(sstream, True); - {$ENDIF} - try - Data := Parser.Parse; - if Data <> nil then - begin - if Data.Count > 0 then - begin - Result := NO_ERROR; - for i := 0 to Data.Count - 1 do - begin - ANames.Add(Data.Items[i].Items[0].AsString); - ALinks.Add(StringReplace(Data.Items[i].Items[2].AsString, - WebsiteRoots[MangasPROJECT_ID, 1], '', [])); - end; - end; - Data.Free; - end; - except - on E: Exception do - MessageDlg('Exception occured: ', E.Message, mtConfirmation, [mbYes], 0); - end; - sstream.Free; - parser.Free; - Source.Free; - end; diff --git a/baseunits/includes/NHentai/chapter_page_number.inc b/baseunits/includes/NHentai/chapter_page_number.inc deleted file mode 100644 index b939426e5..000000000 --- a/baseunits/includes/NHentai/chapter_page_number.inc +++ /dev/null @@ -1,37 +0,0 @@ - function GetNHentaiPageNumber: Boolean; - var - i: Integer; - l: TStringList; - s: String; - begin - Task.Container.PageNumber := 0; - l := TStringList.Create; - parse := TStringList.Create; - s := FillMangaSiteHost(NHENTAI_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - Result := GetPage(TObject(l), s + '1/', Task.Container.Manager.retryConnect); - - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - Task.Container.PageNumber := 0; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) > 0) and (Pos('class="last"', parse[i]) > 0) and - (Pos('/g/', parse[i]) > 0) then - begin - Task.Container.PageNumber := - StrToIntDef(ReplaceRegExpr('^.*\/(\d+)\/.*$', GetVal(parse[i], 'href'), '$1', True), 1); - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/NHentai/directory_page_number.inc b/baseunits/includes/NHentai/directory_page_number.inc deleted file mode 100644 index 0429fe96a..000000000 --- a/baseunits/includes/NHentai/directory_page_number.inc +++ /dev/null @@ -1,35 +0,0 @@ - function GetNHentaiDirectoryPageNumber: Byte; - var - i: Integer; - begin - APage := 0; - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[NHENTAI_ID, 1] + '/', 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('<a', parse[i]) > 0) and (Pos('?page=', parse[i]) > 0) and - (Pos('class="last"', parse[i]) > 0) then - begin - Result := NO_ERROR; - APage := StrToIntDef(ReplaceRegExpr('^.*\?page=(\d+).*$', GetVal(parse[i], 'href'), '$1', True), 1); - Break; - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/NHentai/image_url.inc b/baseunits/includes/NHentai/image_url.inc deleted file mode 100644 index 6b88a9f06..000000000 --- a/baseunits/includes/NHentai/image_url.inc +++ /dev/null @@ -1,54 +0,0 @@ - function GetNHentaiImageURL: Boolean; - var - i, j: Integer; - l: TStringList; - s: String; - begin - l := TStringList.Create; - s := FillMangaSiteHost(NHENTAI_ID, URL); - if Length(s) > 0 then - if s[Length(s)] <> '/' then - s := s + '/'; - s := s + IntToStr(QWord(WorkId) + 1) + '/'; - Result := GetPage(TObject(l), s , Task.Container.Manager.retryConnect); - - if Self.Terminated then - begin - l.Free; - parse.Free; - Exit; - end; - - parse := TStringList.Create; - Parser := THTMLParser.Create(PChar(l.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - l.Free; - if parse.Count > 0 then - begin - for i := 0 to parse.Count - 1 do - begin - if Pos('id="image-container"', parse[i]) > 0 then - begin - for j := i + 1 to parse.Count - 1 do - begin - if Pos('<img', parse[j]) > 0 then - begin - s := GetVal(parse[j], 'src'); - if (s <> '') and (Pos('http', s) = 0) then - begin - s := TrimLeftChar(s, ['/', ':']); - s := 'http://' + s; - end; - Task.Container.PageLinks[WorkId] := s; - Break; - end; - end; - Break; - end; - end; - end; - parse.Free; - end; diff --git a/baseunits/includes/NHentai/manga_information.inc b/baseunits/includes/NHentai/manga_information.inc deleted file mode 100644 index d0051cf2c..000000000 --- a/baseunits/includes/NHentai/manga_information.inc +++ /dev/null @@ -1,93 +0,0 @@ - function GetNHentaiInfoFromURL: Byte; - var - i: Integer; - begin - mangaInfo.website := WebsiteRoots[NHENTAI_ID, 0]; - mangaInfo.url := FillMangaSiteHost(NHENTAI_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - Source.Free; - - if parse.Count = 0 then - Exit; - - mangaInfo.authors := ''; - mangaInfo.artists := ''; - mangaInfo.genres := ''; - mangaInfo.summary := ''; - for i := 0 to parse.Count - 1 do - begin - //cover - if (Pos('/cover', parse[i]) > 0) and (Pos('<img', parse[i]) > 0) then - begin - mangaInfo.coverLink := GetVal(parse[i], 'src'); - if (mangaInfo.coverLink <> '') and (Pos('http', mangainfo.coverLink) = 0) then - begin - mangaInfo.coverLink := TrimLeftChar(mangaInfo.coverLink, ['/', ':']); - mangaInfo.coverLink := 'http://' + mangaInfo.coverLink; - end; - end; - - //title - if (i + 1 < parse.Count - 1) then - if (Pos('<h1', parse[i]) > 0) then - mangaInfo.title := Trim(StringFilter(parse[i + 1])); - - //artist - if (i + 1 < parse.Count - 1) then - if ((Pos('<a', parse[i]) > 0) and (Pos('class="tagbutton"', parse[i]) > 0)) and - (Pos('/artist/', parse[i]) > 0) then - if mangaInfo.artists = '' then - mangaInfo.artists := Trim(parse[i + 1]) - else - mangaInfo.artists := mangaInfo.artists + ', ' + Trim(parse[i + 1]); - - //tag/genre - if (i + 1 < parse.Count - 1) then - if ((Pos('<a', parse[i]) > 0) and (Pos('class="tagbutton"', parse[i]) > 0)) and - ((Pos('/parody/', parse[i]) > 0) or - (Pos('/character/', parse[i]) > 0) or - (Pos('/tagged/', parse[i]) > 0) or - (Pos('/group/', parse[i]) > 0)) then - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(parse[i + 1]) - else - mangaInfo.genres := mangaInfo.genres + ', ' + Trim(parse[i + 1]); - - //language/genre - if (i + 1 < parse.Count - 1) then - if ((Pos('class="field-name"', parse[i]) > 0) and (Pos('Language:', parse[i + 1]) > 0)) then - begin - if mangaInfo.genres = '' then - mangaInfo.genres := Trim(StringReplace(parse[i + 1], 'Language:', '', [rfIgnoreCase])) - else - mangaInfo.genres := mangaInfo.genres + ', ' + - Trim(StringReplace(parse[i + 1], 'Language:', '', [rfIgnoreCase]));; - end; - end; - - mangaInfo.status := '0'; - mangaInfo.numChapter := 1; - mangaInfo.chapterLinks.Add(AURL); - mangaInfo.chapterName.Add(mangaInfo.title); - - if mangaInfo.chapterName.Count > 1 then - begin - // invert chapter - InvertStrings(mangaInfo.chapterName); - InvertStrings(mangaInfo.chapterLinks); - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/NHentai/names_and_links.inc b/baseunits/includes/NHentai/names_and_links.inc deleted file mode 100644 index 3f552da28..000000000 --- a/baseunits/includes/NHentai/names_and_links.inc +++ /dev/null @@ -1,34 +0,0 @@ - function NHentaiNamesAndLinks: Byte; - var - i: Integer; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[NHENTAI_ID, 1] + - '/?page=' + IntToStr(StrToInt(AURL) + 1), 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (Pos('/g/', parse[i]) > 0) and (Pos('<a', parse[i]) > 0) then - begin - Result := NO_ERROR; - ANames.Add(Trim(HTMLEntitiesFilter(StringFilter(Trim(parse[i + 1]))))); - ALinks.Add(StringReplace(GetVal(parse[i], 'href'), WebsiteRoots[NHENTAI_ID, 1], '', [rfIgnoreCase])); - end; - end; - Source.Free; - end; diff --git a/baseunits/includes/ScanManga/image_url.inc b/baseunits/includes/ScanManga/image_url.inc deleted file mode 100644 index 8ef4c914f..000000000 --- a/baseunits/includes/ScanManga/image_url.inc +++ /dev/null @@ -1,45 +0,0 @@ - function GetScanMangaImageURL: Boolean; - var - s, h: String; - i, j: Cardinal; - l, t: TStringList; - - begin - l := TStringList.Create; - t := TStringList.Create; - - s := DecodeUrl(FillMangaSiteHost(SCANMANGA_ID, URL)); - Result := GetPage(TObject(l), - s, - Task.Container.Manager.retryConnect); - - for i := 0 to l.Count - 1 do - begin - if (Pos('$(''#image_lel'')', l[i]) > 0) and - (Pos('[id_page]', l[i]) > 0) then - begin - s := Trim(l[i]); - s := GetString(s, '''src'',''', '''+'); - h := s; - Break; - end; - end; - Task.Container.PageLinks.Clear; - for i := 0 to l.Count - 1 do - begin - if (Pos('var c = new Array;', l[i]) > 0) and - (Pos(';check = false;', l[i]) > 0) then - begin - s := Trim(l[i]); - s := GetString(s, 'var c = new Array;', ';check = false;'); - t.Delimiter := ';'; - t.DelimitedText := s; - for j := 0 to t.Count - 1 do - if Pos(']="', t[j]) > 0 then - Task.Container.PageLinks.Add(h + GetString(t[j], '="', '"')); - Break; - end; - end; - t.Free; - l.Free; - end; diff --git a/baseunits/includes/ScanManga/manga_information.inc b/baseunits/includes/ScanManga/manga_information.inc deleted file mode 100644 index 031e29163..000000000 --- a/baseunits/includes/ScanManga/manga_information.inc +++ /dev/null @@ -1,129 +0,0 @@ - function GetScanMangaInfoFromURL: Byte; - var - s: String; - isExtractGenres: Boolean = False; - i, j: Cardinal; - begin - mangaInfo.url := FillMangaSiteHost(SCANMANGA_ID, AURL); - if not GetPage(TObject(Source), mangaInfo.url, AReconnect) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - // parsing the HTML source - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - - Parser.Free; - Source.Free; - mangaInfo.website := WebsiteRoots[SCANMANGA_ID, 0]; - // using parser (cover link, summary, chapter name and link) - if parse.Count = 0 then - Exit; - for i := 0 to parse.Count - 1 do - begin - // get cover - if (mangaInfo.coverLink = '') and - (Pos('<img itemprop="image"', parse[i]) > 0) then - begin - mangaInfo.coverLink := - CorrectURL(GetVal(parse[i], 'src')); - //mangaInfo.coverLink:= StringReplace(mangaInfo.coverLink, ':8080/', '/', []); - end; - - // get title - if (Pos('id=''ambubble''', parse[i]) <> 0) and (mangaInfo.title = '') then - mangaInfo.title := TrimLeft(TrimRight(HTMLEntitiesFilter(parse[i]))); - - // get chapter name and links - if (Pos('class=''chapitre_nom''', parse[i]) > 0) and - (Pos('<strong>', parse[i + 1]) > 0) then - begin - s := Trim(RemoveSymbols(parse[i + 2])); - if (Pos('<', parse[i + 6]) = 0) and (Pos('>', parse[i + 6]) = 0) then - s := s + ' ' + Trim(RemoveSymbols(parse[i + 6])); - mangaInfo.chapterName.Add(StringFilter(HTMLEntitiesFilter(s))); - end; - if (Pos('/lecture-en-ligne/', parse[i]) > 0) then - begin - Inc(mangaInfo.numChapter); - s := StringReplace(GetVal(parse[i], 'href'), - WebsiteRoots[SCANMANGA_ID, 1], '', []); - s := StringReplace(TrimLeft(TrimRight(s)), '"', '', [rfReplaceAll]); - mangaInfo.chapterLinks.Add(s); - end; - - // get summary - if (Pos('itemprop="description">', parse[i]) <> 0) then - begin - j := i + 1; - while (j < parse.Count) and (Pos('</p>', parse[j]) = 0) do - begin - s := parse[j]; - if s[1] <> '<' then - begin - parse[j] := HTMLEntitiesFilter(StringFilter(parse[j])); - parse[j] := StringReplace(parse[j], #10, '\n', [rfReplaceAll]); - parse[j] := StringReplace(parse[j], #13, '\r', [rfReplaceAll]); - mangaInfo.summary := mangaInfo.summary + parse[j]; - end; - Inc(j); - end; - end; - - // get authors - if (i + 2 < parse.Count) and - (Pos('itemprop="author"', parse[i]) <> 0) then - mangaInfo.authors := StringFilter(TrimLeft(TrimRight(parse[i + 2]))); - - // get artists - //if (i+5<parse.Count) AND (Pos('Illustrateur :', parse[i])<>0) then - // mangaInfo.artists:= StringFilter(TrimLeft(TrimRight(parse[i+5]))); - - // get genres - if (Pos('itemprop="genre"', parse[i]) <> 0) then - begin - isExtractGenres := True; - mangaInfo.genres := mangaInfo.genres + HTMLEntitiesFilter( - TrimLeft(TrimRight(parse[i + 1]))) + ', '; - end; - - if isExtractGenres then - begin - if Pos('class=''tTip''>', parse[i]) <> 0 then - mangaInfo.genres := mangaInfo.genres + - HTMLEntitiesFilter(TrimLeft(TrimRight(parse[i + 1]))) + ', '; - if Pos('itemprop="editor"', parse[i]) <> 0 then - isExtractGenres := False; - end; - - // get status - if (i + 11 < parse.Count) and (Pos('itemprop="editor"', parse[i]) <> 0) then - begin - if (Pos('Termin', parse[i + 5]) <> 0) or - (Pos('One Shot', parse[i + 5]) <> 0) then - mangaInfo.status := '0' // completed - else - mangaInfo.status := '1'; // ongoing - end; - end; - - // Since chapter name and link are inverted, we need to invert them - if mangainfo.ChapterLinks.Count > 1 then - begin - i := 0; - j := mangainfo.ChapterLinks.Count - 1; - while (i < j) do - begin - mangainfo.ChapterName.Exchange(i, j); - mangainfo.chapterLinks.Exchange(i, j); - Inc(i); - Dec(j); - end; - end; - Result := NO_ERROR; - end; diff --git a/baseunits/includes/ScanManga/names_and_links.inc b/baseunits/includes/ScanManga/names_and_links.inc deleted file mode 100644 index a9a9b45b8..000000000 --- a/baseunits/includes/ScanManga/names_and_links.inc +++ /dev/null @@ -1,47 +0,0 @@ - function ScanMangaGetNamesAndLinks: Byte; - var - i: Cardinal; - s: String; - begin - Result := INFORMATION_NOT_FOUND; - if not GetPage(TObject(Source), WebsiteRoots[SCANMANGA_ID, 1] + - SCANMANGA_BROWSER, 0) then - begin - Result := NET_PROBLEM; - Source.Free; - Exit; - end; - parse.Clear; - Parser := THTMLParser.Create(PChar(Source.Text)); - Parser.OnFoundTag := @OnTag; - Parser.OnFoundText := @OnText; - Parser.Exec; - Parser.Free; - if parse.Count = 0 then - begin - Source.Free; - Exit; - end; - for i := 0 to parse.Count - 1 do - begin - if (i + 4 < parse.Count - 1) and - (Pos('<li>', parse[i]) > 0) and - (Pos('</a>', parse[i + 3]) > 0) and - (Pos('</li>', parse[i + 4]) > 0) then - begin - Result := NO_ERROR; - s := GetVal(parse[i + 1], 'href'); - if (Length(s) > 1) and - (Pos('/scanlation/Shonen.html', s) = 0) and - (Pos('/scanlation/Shojo.html', s) = 0) and - (Pos('/scanlation/Josei.html', s) = 0) and - (Pos('/scanlation/Seinen.html', s) = 0) then - begin - ALinks.Add(StringReplace(s, WebsiteRoots[SCANMANGA_ID, 1], '', [])); - s := StringFilter(parse[i + 2]); - ANames.Add(HTMLEntitiesFilter(s)); - end; - end; - end; - Source.Free; - end; \ No newline at end of file diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2d11fd676..a983103cb 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -227,58 +227,9 @@ interface // common regex to split host/url REGEX_HOST = '(?ig)^(\w+://)?([^/]*\.\w+)?(\:\d+)?(/?.*)$'; - ANIMEEXTREMIST_ID = 0; - ANIMESTORY_ID = 1; - SCANMANGA_ID = 2; - MANGASPROJECT_ID = 3; - MANGAREADER_POR_ID = 4; - MANGATOWN_ID = 5; - NHENTAI_ID = 6; - MANGAHOST_ID = 7; - MANGAKU_ID = 8; - DYNASTYSCANS_ID = 9; - - WebsiteRoots: array [0..9] of array [0..1] of String = ( - ('AnimExtremist', 'http://www.animextremist.com'), - ('AnimeStory', 'http://www.anime-story.com'), - ('ScanManga', 'http://www.scan-manga.com'), - ('MangasPROJECT', 'http://mangaproject.xpg.uol.com.br'), - ('MangaREADER_POR', 'http://www.mangareader.com.br'), - ('MangaTown', 'http://www.mangatown.com'), - ('NHentai', 'http://nhentai.net'), - ('MangaHost', 'http://br.mangahost.com'), - ('MangaKu', 'http://mangaku.web.id'), - ('Dynasty-Scans', 'http://dynasty-scans.com') - ); - ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz'; ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - TURKCRAFT_BROWSER = '/'; - - ANIMEEXTREMIST_BROWSER = '/mangas.htm?ord=todos'; - - ANIMESTORY_BROWSER = '/mangas/'; - - SCANMANGA_BROWSER = '/scanlation/liste_des_mangas.html'; - - MANGASPROJECT_BROWSER = '/AJAX/listaMangas/all'; - - MANGAREADER_POR_BROWSER = '/AJAX/listaMangas/all'; - - MANGATOWN_BROWSER = '/directory/'; - - UNIONMANGAS_BROWSER = '/mangas'; - - MANGAHOST_BROWSER = '/mangas'; - - DYNASTYSCANS_BROWSER: array [0..3] of String = ( - '/anthologies', - '/doujins', - '/issues', - '/series' - ); - MangaInfo_StatusCompleted = '0'; MangaInfo_StatusOngoing = '1'; @@ -429,20 +380,6 @@ TDownloadPageThread = class(TThread) constructor Create(CreateSuspended: Boolean); end; - { TParseHTML } - - TParseHTML = class - private - FRaw: String; - procedure FoundTag(NoCaseTag, ActualTag: String); - procedure FoundText(Text: String); - public - Output: TStrings; - constructor Create(const Raw: String = ''); - function Exec(const Raw: String = ''): String; - property Raw: String read FRaw write FRaw; - end; - { THTMLForm } THTMLForm = class @@ -470,28 +407,14 @@ function CorrectFilePath(const APath: String): String; function CorrectURL(const URL: String): String; procedure CheckPath(const S: String); -function LocateMangaSiteID(const URL: String): Integer; -function GetMangaSiteID(const Name: String): Integer; -function GetMangaSiteID(const Name: String; var MangaSiteID: Integer): Boolean; overload; inline; -function GetMangaSiteName(const ID: Integer): String; -function GetMangaSiteRoot(const Website: String): String; overload; -function GetMangaSiteRoot(const MangaID: Integer): String; overload; - -function SitesMemberOf(const website: String; MangaSiteIDs: array of Integer): Boolean; function SitesWithSortedList(const website: String): Boolean; function SitesWithoutFavorites(const website: String): Boolean; // Return true if the website doesn't contain manga information function SitesWithoutInformation(const website: String): Boolean; -function SitesWithoutReferer(const website: String): Boolean; -function SitesWithSingleChapter(const website: String): Boolean; // url function FillURLProtocol(const AProtocol, AURL: String): String; -// Fill in website host if it's not present -function FillMangaSiteHost(const MangaID: Integer; URL: String): String; overload; -function FillMangaSiteHost(const Website, URL: String): String; overload; - // modify url function FillHost(const Host, URL: String): String; overload; procedure FillHost(const Host: String; const URLs: TStrings); overload; @@ -506,9 +429,6 @@ function EncodeCriticalURLElements(const URL: String): String; //JSON procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); -//HTML -procedure ParseHTML(const aRaw: String; aOutput: TStrings); - // XPath / CSS Selector procedure ParseHTMLTree(var tp: TTreeParser; const S: String); function SelectXPathString(Expression: String; TP: TTreeParser): String; @@ -638,9 +558,6 @@ procedure GoogleResultURLs(const AURLs: TStrings); // deal with sourceforge URL. function SourceForgeURL(URL: String): String; -// Get HTML source code from a URL. -function GetPageAndParse(const AHTTP: THTTPSend; Output: TStrings; URL: String; - const Reconnect: Integer = 0): Integer; function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; const Reconnect: Integer = 0; Method: String = 'GET'): Boolean; overload; function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; @@ -664,15 +581,6 @@ function SaveImageStreamToFile(AHTTP: THTTPSend; Path, FileName: String): String function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; // Download an image from url and save it to a specific location. -function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; - const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; overload; -function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; URL: String; - const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; -function SaveImage(const AHTTP: THTTPSend; URL: String; - const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; -function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name: String; var SavedFilename: String; const Reconnect: Integer = 0): Boolean; - overload; inline; function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String; var ASavedFileName: String): Boolean; overload; function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String): Boolean; overload; @@ -928,85 +836,6 @@ procedure CheckPath(const S: String); end; end; -function LocateMangaSiteID(const URL: String): Integer; - - function PosMangaSite(const s: String): Integer; - var - i: Integer; - begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(s, LowerCase(WebsiteRoots[i, 1])) <> 0 then - Exit(i); - Result := -1; - end; - -var - h: String; -begin - Result := -1; - h := LowerCase(URL); - Result := PosMangaSite(h); - if Result = -1 then - begin - SplitURL(h, @h, nil, False, False); - if h = '' then Exit; - Result := PosMangaSite(h); - end; -end; - -function GetMangaSiteID(const Name: String): Integer; -var - i: Integer; -begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if SameText(Name, WebsiteRoots[i, 0]) then - Exit(i); - Result := -1; -end; - -function GetMangaSiteID(const Name: String; var MangaSiteID: Integer): Boolean; -begin - MangaSiteID := GetMangaSiteID(Name); - Result := (MangaSiteID >= Low(WebsiteRoots)) and (MangaSiteID <= High(WebsiteRoots)); -end; - -function GetMangaSiteName(const ID: Integer): String; -begin - if (ID < Low(WebsiteRoots)) or (ID > High(WebsiteRoots)) then - Exit(''); - Result := WebsiteRoots[ID, 0]; -end; - -function GetMangaSiteRoot(const Website: String): String; -var - i: Integer; -begin - for i := Low(WebsiteRoots) to High(WebsiteRoots) do - if Website = WebsiteRoots[i, 0] then - Exit(WebsiteRoots[i, 1]); - Result := ''; -end; - -function GetMangaSiteRoot(const MangaID: Integer): String; -begin - if (MangaID < Low(WebsiteRoots)) or (MangaID > High(WebsiteRoots)) then - Exit(''); - Result := WebsiteRoots[MangaID, 1]; -end; - -function SitesMemberOf(const website: String; MangaSiteIDs: array of Integer): Boolean; -var - i: Integer; -begin - Result := False; - for i := Low(MangaSiteIDs) to High(MangaSiteIDs) do - if website = WebsiteRoots[MangaSiteIDs[i], 0] then - begin - Result := True; - Break; - end; -end; - function SitesWithSortedList(const website: String): Boolean; var i: Integer = -1; @@ -1017,9 +846,6 @@ function SitesWithSortedList(const website: String): Boolean; Result := Modules.Module[i].SortedList; Exit; end; - Result := SitesMemberOf(website, [ - NHENTAI_ID - ]); end; function SitesWithoutFavorites(const website: String): Boolean; @@ -1032,9 +858,6 @@ function SitesWithoutFavorites(const website: String): Boolean; Result := not Modules.Module[i].FavoriteAvailable; Exit; end; - Result := SitesMemberOf(website, [ - NHENTAI_ID - ]); end; function SitesWithoutInformation(const website: String): Boolean; @@ -1047,22 +870,6 @@ function SitesWithoutInformation(const website: String): Boolean; Result := not Modules.Module[i].InformationAvailable; Exit; end; - Result := SitesMemberOf(website, [ - MANGASPROJECT_ID - ]); -end; - -function SitesWithoutReferer(const website: String): Boolean; -begin - Result := False; -end; - -function SitesWithSingleChapter(const website: String): Boolean; -begin - Result := False; - Result := SitesMemberOf(website, [ - NHENTAI_ID - ]); end; function FillURLProtocol(const AProtocol, AURL: String): String; @@ -1075,21 +882,6 @@ function FillURLProtocol(const AProtocol, AURL: String): String; end; end; -function FillMangaSiteHost(const MangaID: Integer; URL: String): String; -begin - Result := URL; - if (MangaID < Low(WebsiteRoots)) or (MangaID > High(WebsiteRoots)) then - Exit; - Result := FillHost(WebsiteRoots[MangaID, 1], URL); -end; - -function FillMangaSiteHost(const Website, URL: String): String; -begin - Result := URL; - if Website = '' then Exit(URL); - Result := FillMangaSiteHost(GetMangaSiteID(Website), URL); -end; - function FillHost(const Host, URL: String): String; var P: String; @@ -1206,17 +998,6 @@ procedure ParseJSONArray(const S, Path: String; var OutArray: TStringList); OutArray.EndUpdate; end; -procedure ParseHTML(const aRaw: String; aOutput: TStrings); -begin - if not Assigned(aOutput) then Exit; - with TParseHTML.Create(aRaw) do try - Output := aOutput; - Exec; - finally - Free; - end; -end; - procedure ParseHTMLTree(var tp: TTreeParser; const S: String); begin if tp = nil then tp := TTreeParser.Create; @@ -2926,24 +2707,6 @@ function SourceForgeURL(URL: String): String; Result := URL; end; -function GetPageAndParse(const AHTTP: THTTPSend; Output: TStrings; URL: String; - const Reconnect: Integer): Integer; -begin - if Output = nil then Exit(INFORMATION_NOT_FOUND); - if GetPage(AHTTP, TObject(Output), URL, Reconnect) then - begin - if Output.Count > 0 then - begin - Result := NO_ERROR; - ParseHTML(Output.Text, Output); - end - else - Result := INFORMATION_NOT_FOUND; - end - else - Result := NET_PROBLEM; -end; - function GetPage(const AHTTP: THTTPSend; var output: TObject; URL: String; const Reconnect: Integer; Method: String): Boolean; // If AHTTP <> nil, we will use it as http sender. Otherwise we create a new @@ -3376,214 +3139,6 @@ function SaveImageBase64StringToFile(const S, Path, FileName: String): Boolean; end; end; -function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; - URL: String; const Path, Name: String; var SavedFilename: String; - const Reconnect: Integer): Boolean; -var - HTTPHeader: TStringList; - HTTP: THTTPSend; - counter: Integer; - s: String; - - procedure preTerminate; - begin - HTTPHeader.Free; - if AHTTP = nil then - HTTP.Free; - end; - - function checkTerminate: Boolean; - begin - Result := HTTP.Sock.Tag = 1; //terminate via THTTPSendThread - if Result then - begin - HTTP.Sock.Tag := 0; - preTerminate; - end; - end; - -begin - Result := False; - if Trim(URL) = '' then Exit; - - // Check to see if a file with similar name was already exist. If so then we - // skip the download process. - if Trim(URL) = 'D' then Exit(True); - s := CorrectPathSys(Path) + Name; - if ImageFileExist(s) then - Exit(True); - - URL := FixURL(URL); - URL := EncodeURL(DecodeURL(URL)); - - HTTPHeader := TStringList.Create; - HTTPHeader.NameValueSeparator := ':'; - if AHTTP <> nil then - begin - if LeftStr(AHTTP.Headers.Text, 5) <> 'HTTP/' then - HTTPHeader.Text := AHTTP.Headers.Text; - HTTP := AHTTP; - HTTP.Clear; - end - else - begin - HTTP := THTTPSend.Create; - HTTP.Timeout := DefaultTimeout; - // HTTP.Sock.ConnectionTimeout := DefaultTimeout; - HTTP.Sock.SetTimeout(DefaultTimeout); - end; - HTTP.Headers.NameValueSeparator := ':'; - - if DefaultProxyType = 'HTTP' then - begin - HTTP.ProxyHost := DefaultProxyHost; - HTTP.ProxyPort := DefaultProxyPort; - HTTP.ProxyUser := DefaultProxyUser; - HTTP.ProxyPass := DefaultProxyPass; - end - else - if (DefaultProxyType = 'SOCKS4') or (DefaultProxyType = 'SOCKS5') then - begin - if DefaultProxyType = 'SOCKS4' then - HTTP.Sock.SocksType := ST_Socks4 - else - if DefaultProxyType = 'SOCKS5' then - HTTP.Sock.SocksType := ST_Socks5; - HTTP.Sock.SocksIP := DefaultProxyHost; - HTTP.Sock.SocksPort := DefaultProxyPort; - HTTP.Sock.SocksUsername := DefaultProxyUser; - http.Sock.SocksPassword := DefaultProxyPass; - end - else - begin - HTTP.Sock.SocksIP := DefaultProxyHost; - HTTP.Sock.SocksPort := DefaultProxyPort; - HTTP.Sock.SocksUsername := DefaultProxyUser; - http.Sock.SocksPassword := DefaultProxyPass; - HTTP.ProxyHost := DefaultProxyHost; - HTTP.ProxyPort := DefaultProxyPort; - HTTP.ProxyUser := DefaultProxyUser; - HTTP.ProxyPass := DefaultProxyPass; - end; - - HTTPHeader.Values['DNT'] := ' 1'; - HTTPHeader.Values['Accept'] := ' text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; - HTTPHeader.Values['Accept-Charset'] := ' UTF-8'; - HTTPHeader.Values['Accept-Language'] := ' en-US,en;q=0.8'; - HTTP.Protocol := '1.1'; - HTTP.KeepAlive := False; - if (HTTP.UserAgent = '') or (HTTP.UserAgent = UA_SYNAPSE) then - HTTP.UserAgent := DEFAULT_UA; - HTTP.MimeType := 'text/html'; - - //User-Agent - if Trim(HTTPHeader.Values['User-Agent']) <> '' then - begin - HTTP.UserAgent := Trim(HTTPHeader.Values['User-Agent']); - HTTPHeader.Delete(HTTPHeader.IndexOfName('User-Agent')); - end; - //MimeType - if Trim(HTTPHeader.Values['Content-Type']) <> '' then - begin - HTTP.MimeType := Trim(HTTPHeader.Values['Content-Type']); - HTTPHeader.Delete(HTTPHeader.IndexOfName('Content-Type')); - end; - - if Pos('.imgur.com/', LowerCase(URL)) = 0 then - if ((mangaSiteID >= 0) and (mangaSiteID <= High(WebsiteRoots))) then - begin - if HTTPHeader.Values['Referer'] = '' then - if not (SitesWithoutReferer(WebsiteRoots[mangaSiteID, 0])) then - HTTPHeader.Values['Referer'] := ' ' + WebsiteRoots[mangaSiteID, 1]; - end; - - HTTP.Document.Clear; - HTTP.RangeStart := 0; - HTTP.RangeEnd := 0; - - if checkTerminate then Exit; - HTTP.Headers.Text := HTTPHeader.Text; - counter := 0; - while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) do - begin - if checkTerminate then Exit; - if (Reconnect > -1) and (Reconnect <= counter) then - begin - preTerminate; - Exit; - end; - Inc(counter); - HTTP.Clear; - HTTP.Headers.Text := HTTPHeader.Text; - end; - - while (HTTP.ResultCode > 300) and (HTTP.ResultCode < 400) do - begin - if checkTerminate then Exit; - HTTPHeader.Values['Referer'] := ' ' + URL; - s := Trim(HTTP.Headers.Values['Location']); - if s <> '' then - begin - with TRegExpr.Create do - try - Expression := REGEX_HOST; - if Replace(s, '$1', True) = '' then - begin - if s[1] <> '/' then - s := '/' + s; - URL := Replace(URL, '$1$2$3', True) + s; - end - else - URL := s; - finally - Free; - end; - end; - - HTTP.Clear; - HTTP.Headers.Text := HTTPHeader.Text; - counter := 0; - while (not HTTP.HTTPMethod('GET', URL)) or (HTTP.ResultCode > 500) do - begin - if checkTerminate then Exit; - if (Reconnect > -1) and (Reconnect <= counter) then - begin - preTerminate; - Exit; - end; - Inc(counter); - HTTP.Clear; - HTTP.Headers.Text := HTTPHeader.Text; - end; - end; - if checkTerminate then Exit; - SavedFilename := SaveImageStreamToFile(HTTP, Path, Name); - preTerminate; - Result := SavedFilename <> ''; -end; - -function SaveImage(const AHTTP: THTTPSend; const mangaSiteID: Integer; - URL: String; const Path, Name: String; const Reconnect: Integer): Boolean; -var - f: String; -begin - Result := SaveImage(AHTTP, mangaSiteID, URL, Path, Name, f, Reconnect); -end; - -function SaveImage(const AHTTP: THTTPSend; URL: String; const Path, Name: String; const Reconnect: Integer - ): Boolean; -var - f: String; -begin - Result := SaveImage(AHTTP, -1, URL, Path, Name, f, Reconnect); -end; - -function SaveImage(const mangaSiteID: Integer; URL: String; const Path, - Name: String; var SavedFilename: String; const Reconnect: Integer): Boolean; -begin - Result := SaveImage(nil, mangaSiteID, URL, Path, Name, SavedFilename, Reconnect); -end; - function DownloadAndSaveImage(const AHTTP: THTTPSendThread; const AURL, APath, AFileName: String; var ASavedFileName: String): Boolean; begin @@ -4096,49 +3651,6 @@ function THTMLForm.GetData: String; end; end; -{ TParseHTML } - -procedure TParseHTML.FoundTag(NoCaseTag, ActualTag: String); -begin - Output.Add(ActualTag); -end; - -procedure TParseHTML.FoundText(Text: String); -begin - Output.Add(Text); -end; - -constructor TParseHTML.Create(const Raw: String); -begin - inherited Create; - if Raw <> '' then - FRaw := Raw - else - FRaw := ''; -end; - -function TParseHTML.Exec(const Raw: String): String; -var - parser: THTMLParser; -begin - if not Assigned(Output) then Exit; - if Raw <> '' then - FRaw := Raw; - if FRaw = '' then - Exit(''); - Output.Clear; - Output.BeginUpdate; - parser := THTMLParser.Create(PChar(FRaw)); - try - parser.OnFoundTag := @FoundTag; - parser.OnFoundText := @FoundText; - parser.Exec; - finally - parser.Free; - end; - Output.EndUpdate; -end; - { TMangaInfo } constructor TMangaInfo.Create; diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 5dc890478..fe81fb923 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -19,61 +19,6 @@ interface type - { TDataProcess } - - TDataProcess = class(TObject) - private - function GetInfo(const index: Cardinal): TStringList; - function GetParam(const index, paramNo: Integer): String; - public - website, Filename: String; - isFilterAllSites, isFiltered: Boolean; - - site, filterMark: TByteList; - // used by search - searchPos, filterPos: TCardinalList; - Data, - - // parts - Title, Link, Authors, Artists, Genres, Status, Summary: TStringList; - JDN: TList; - - constructor Create; - destructor Destroy; override; - procedure Clear; - - function FirstParam(const index: Cardinal): String; - - // en: Break data into parts... This may be considered as bad coding, but - // it's for faster filter - procedure BreakDataToParts(const i: Cardinal); - - function LoadFromFile(const awebsite: String): Boolean; - function LoadFromAllFiles(const websiteList: TStringList): Boolean; - procedure SaveToFile(const awebsite: String); overload; - procedure SaveToFile; overload; - - function CanFilter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean): Boolean; - - // en: Filter by genres, title, authors, ... - function Filter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; - const minusDay: Cardinal; const haveAllChecked, searchNewManga: Boolean; - useRegExpr: Boolean = False): Boolean; - // realtime search - function Search(AMangaName: String): Boolean; - // get data position - function GetPos(const ANodePos: Integer): Integer; - - // en: Remove filter - procedure RemoveFilter; - procedure Sort; - property Info[index: Cardinal]: TStringList read GetInfo; - property Param[index, paramNo: Integer]: String read GetParam; - end; - { TMangaInformation } TMangaInformation = class(TObject) @@ -90,24 +35,13 @@ TMangaInformation = class(TObject) RemoveHostFromChapterLinks: Boolean; FHTTP: THTTPSendThread; - procedure OnTag(NoCaseTag, ActualTag: String); - procedure OnText(AText: String); constructor Create(AOwnerThread: TBaseThread = nil; ACreateInfo: Boolean = True); destructor Destroy; override; procedure ClearInfo; function GetDirectoryPage(var APage: Integer; const AWebsite: String): Byte; function GetNameAndLink(const ANames, ALinks: TStringList; const AWebsite, AURL: String): Byte; - function GetInfoFromURL(const AWebsite, AURL: String; const AReconnect: Integer = 0): Byte; - procedure SyncInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); overload; + function GetInfoFromURL(const AWebsite, AURL: String): Byte; procedure SyncInfoToData(const ADataProcess: TDBDataProcess); overload; - procedure SyncMinorInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); - - // Only use this function for getting manga infos for the first time - procedure AddInfoToDataWithoutBreak(const AName, ALink: String; const ADataProcess: TDataProcess); - // Only use this function for update manga list - procedure AddInfoToData(const AName, Alink: String; const ADataProcess: TDataProcess); - overload; - // to add data to TDBDataProcess procedure AddInfoToData(const ATitle, ALink: String; const ADataProcess: TDBDataProcess); overload; //wrapper function GetPage(var AOutput: TObject; AURL: String; const AReconnect: Integer = 0): Boolean; inline; @@ -121,600 +55,7 @@ TMangaInformation = class(TObject) implementation uses - Dialogs, fpJSON, JSONParser, jsonscanner, FastHTMLParser, HTMLUtil, - SynaCode, frmMain, WebsiteModules, uUpdateThread; - -// ----- TDataProcess ----- - -constructor TDataProcess.Create; -begin - inherited Create; - isFilterAllSites := False; - isFiltered := False; - Data := TStringList.Create; - - Title := TStringList.Create; - Link := TStringList.Create; - Authors := TStringList.Create; - Artists := TStringList.Create; - Genres := TStringList.Create; - Status := TStringList.Create; - Summary := TStringList.Create; - JDN := TList.Create; - - site := TByteList.Create; - filterMark := TByteList.Create; - filterPos := TCardinalList.Create; - searchPos := TCardinalList.Create; -end; - -destructor TDataProcess.Destroy; -begin - searchPos.Free; - filterMark.Free; - filterPos.Free; - site.Free; - - Title.Free; - Link.Free; - Authors.Free; - Artists.Free; - Genres.Free; - Status.Free; - Summary.Free; - JDN.Free; - - Data.Free; - inherited Destroy; -end; - -procedure TDataProcess.Clear; -begin - isFilterAllSites := False; - isFiltered := False; - - Data.Clear; - Title.Clear; - Link.Clear; - Authors.Clear; - Artists.Clear; - Genres.Clear; - Status.Clear; - Summary.Clear; - - JDN.Clear; - site.Clear; - filterMark.Clear; - filterPos.Clear; - searchPos.Clear; -end; - -function TDataProcess.FirstParam(const index: Cardinal): String; -var - l: Cardinal; -begin - Result := ''; - l := Pos(SEPERATOR, Data.Strings[index]); - if l <> 0 then - Result := LeftStr(Data.Strings[index], l - 1); -end; - -function TDataProcess.GetInfo(const index: Cardinal): TStringList; -begin - GetParams(Result{%H-}, Data.Strings[index]); -end; - -function TDataProcess.GetParam(const index, paramNo: Integer): String; -var - i, p: Integer; - s: String; -begin - Result := ''; - if index < Data.Count then - begin - s := Data.Strings[index]; - i := 0; - p := 0; - repeat - p := Pos(SEPERATOR, s); - if p > 0 then - begin - Inc(i); - Result := LeftStr(s, p - 1); - s := RightStr(s, Length(s) - p - Length(SEPERATOR) + 1); - end; - until (p = 0) or (i > paramNo); - if i <= paramNo then - Result := ''; - end; -end; - -// en: break data - for fast filter -procedure TDataProcess.BreakDataToParts(const i: Cardinal); -begin - if i < Data.Count then - begin - Title.Strings[i] := GetParam(i, DATA_PARAM_TITLE); - Link.Strings[i] := GetParam(i, DATA_PARAM_LINK); - Authors.Strings[i] := GetParam(i, DATA_PARAM_AUTHORS); - Artists.Strings[i] := GetParam(i, DATA_PARAM_ARTISTS); - Genres.Strings[i] := GetParam(i, DATA_PARAM_GENRES); - Status.Strings[i] := GetParam(i, DATA_PARAM_STATUS); - Summary.Strings[i] := GetParam(i, DATA_PARAM_SUMMARY); - JDN.Items[i] := Pointer(StrToIntDef(GetParam(i, DATA_PARAM_JDN), 0)); - end; -end; - -function TDataProcess.LoadFromFile(const awebsite: String): Boolean; -var - id, i: Cardinal; - l: TStringList; - afilename: String; -begin - afilename := DATA_FOLDER + awebsite; - - Data.Clear; - searchPos.Clear; - filterMark.Clear; - filterPos.Clear; - site.Clear; - - title.Clear; - authors.Clear; - artists.Clear; - genres.Clear; - status.Clear; - summary.Clear; - jdn.Clear; - - if not FileExistsUTF8(afilename + DATA_EXT) then - Exit(False); - l := TStringList.Create; - try - Self.Filename := afilename; - - Data.LoadFromFile(afilename + DATA_EXT); - id := GetMangaSiteID(awebsite); - - if Data.Count > 0 then - begin - //QuickSortData(data); - QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_TITLE); //Natural Sorting - for i := 0 to Data.Count - 1 do - begin - filterMark.Add(FILTER_SHOW); - filterPos.Add(i); - site.Add(id); - - l.Clear; - try - GetParams(l, Data.Strings[i]); - while l.Count < 10 do - l.Add(''); - title.Add(l.Strings[DATA_PARAM_TITLE]); - link.Add(l.Strings[DATA_PARAM_LINK]); - authors.Add(l.Strings[DATA_PARAM_AUTHORS]); - artists.Add(l.Strings[DATA_PARAM_ARTISTS]); - genres.Add(l.Strings[DATA_PARAM_GENRES]); - status.Add(l.Strings[DATA_PARAM_STATUS]); - summary.Add(l.Strings[DATA_PARAM_SUMMARY]); - jdn.Add(Pointer(StrToIntDef(l.Strings[DATA_PARAM_JDN], 0))); - except - end; - end; - end; - finally - l.Free; - end; - Result := True; -end; - -function TDataProcess.LoadFromAllFiles(const websiteList: TStringList): Boolean; -var - id, j, i: Cardinal; - l: TStringList; - afilename: String; -begin - if websiteList.Count = 0 then - Exit(False); - Data.Clear; - searchPos.Clear; - filterMark.Clear; - filterPos.Clear; - site.Clear; - - title.Clear; - authors.Clear; - artists.Clear; - genres.Clear; - status.Clear; - summary.Clear; - jdn.Clear; - - l := TStringList.Create; - try - for i := 0 to websiteList.Count - 1 do - begin - afilename := DATA_FOLDER + websiteList.Strings[i]; - id := GetMangaSiteID(websiteList.Strings[i]); - if not FileExistsUTF8(afilename + DATA_EXT) then - continue; - l.Clear; - l.LoadFromFile(afilename + DATA_EXT); - - if l.Count <> 0 then - begin - for j := 0 to l.Count - 1 do - site.Add(id); - Data.Text := Data.Text + l.Text; - end; - end; - - if Data.Count > 0 then - begin - QuickSortDataWithWebID(Data, site); - for i := 0 to Data.Count - 1 do - begin - filterMark.Add(FILTER_SHOW); - filterPos.Add(i); - - l.Clear; - try - GetParams(l, Data.Strings[i]); - while l.Count < 10 do - l.Add(''); - title.Add(l.Strings[DATA_PARAM_TITLE]); - link.Add(l.Strings[DATA_PARAM_LINK]); - authors.Add(l.Strings[DATA_PARAM_AUTHORS]); - artists.Add(l.Strings[DATA_PARAM_ARTISTS]); - genres.Add(l.Strings[DATA_PARAM_GENRES]); - status.Add(l.Strings[DATA_PARAM_STATUS]); - summary.Add(l.Strings[DATA_PARAM_SUMMARY]); - jdn.Add(Pointer(StrToIntDef(l.Strings[DATA_PARAM_JDN], 0))); - except - end; - end; - end; - finally - l.Free; - end; - Result := True; -end; - -procedure TDataProcess.SaveToFile(const awebsite: String); -begin - if Data.Count = 0 then - Exit; - //QuickSortData(Data); - ForceDirectoriesUTF8(DATA_FOLDER); - Data.SaveToFile(DATA_FOLDER + awebsite + DATA_EXT); -end; - -procedure TDataProcess.SaveToFile; -begin - if Data.Count = 0 then - Exit; - //QuickSortData(Data); - ForceDirectoriesUTF8(DATA_FOLDER); - Data.SaveToFile(Filename + DATA_EXT); -end; - -// check if we need to filter or not -function TDataProcess.CanFilter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; - const haveAllChecked, searchNewManga: Boolean): Boolean; -begin - if (filterPos.Count = 0) or - (Data.Count = 0) or - ((stTitle = '') and - (stAuthors = '') and - (stArtists = '') and - (stSummary = '') and - (stStatus = '2') and - (checkedGenres.Count = 0) and - (uncheckedGenres.Count = 0)) and - (not searchNewManga) then - Result := False - else - Result := True; -end; - -function TDataProcess.Filter(const checkedGenres, uncheckedGenres: TStringList; - const stTitle, stAuthors, stArtists, stStatus, stSummary: String; const minusDay: Cardinal; - const haveAllChecked, searchNewManga: Boolean; useRegExpr: Boolean = False): Boolean; -var - currentJDN, i, j, k, fpos, Count: Integer; - s: String; - regx: TRegExpr; - fshow: Boolean; - gen: TStringList; -begin - regx := TRegExpr.Create; - regx.ModifierI := True; - try - Result := False; - searchPos.Clear; - if (filterPos.Count = 0) or - (Data.Count = 0) or - ((stTitle = '') and - (stAuthors = '') and - (stArtists = '') and - (stSummary = '') and - (stStatus = '2') and - (checkedGenres.Count = 0) and - (uncheckedGenres.Count = 0)) and - (not searchNewManga) then - Exit; - - // ugly filter code but quite fast - if searchNewManga then - begin - currentJDN := GetCurrentJDN; - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if (currentJDN - {%H-}Integer(jdn.Items[fpos]) >= minusDay) and - (filterMark.Items[fpos] = FILTER_SHOW) then - filterMark.Items[fpos] := FILTER_HIDE; - end; - end; - - // filter title - if Trim(stTitle) <> '' then - begin - s := LowerCase(stTitle); - if useRegExpr then - regx.Expression := stTitle; - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if useRegExpr then - fshow := not regx.Exec(Title[fpos]) - else - fshow := (Pos(s, LowerCase(Title.Strings[fpos])) = 0); - if fshow and - (filterMark.Items[fpos] = FILTER_SHOW) then - filterMark.Items[fpos] := FILTER_HIDE; - end; - end; - - // filter authors - if stAuthors <> '' then - begin - s := LowerCase(stAuthors); - if useRegExpr then - regx.Expression := stAuthors; - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if useRegExpr then - fshow := not regx.Exec(Authors[fpos]) - else - fshow := (Pos(s, LowerCase(Authors.Strings[fpos])) = 0); - if fshow and - (filterMark.Items[fpos] = FILTER_SHOW) then - filterMark.Items[fpos] := FILTER_HIDE; - end; - end; - - // filter artist - if stArtists <> '' then - begin - s := LowerCase(stArtists); - if useRegExpr then - regx.Expression := stArtists; - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if useRegExpr then - fshow := not regx.Exec(Artists[fpos]) - else - fshow := (Pos(s, LowerCase(Artists.Strings[fpos])) = 0); - if fshow and - (filterMark.Items[fpos] = FILTER_SHOW) then - filterMark.Items[fpos] := FILTER_HIDE; - end; - end; - - // filter summary - if stSummary <> '' then - begin - s := LowerCase(stSummary); - if useRegExpr then - regx.Expression := stSummary; - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if useRegExpr then - fshow := not regx.Exec(Summary[fpos]) - else - fshow := (Pos(s, LowerCase(Summary.Strings[fpos])) = 0); - if fshow and - (filterMark.Items[fpos] = FILTER_SHOW) then - filterMark.Items[fpos] := FILTER_HIDE; - end; - end; - - // filter status - if stStatus <> '2' then - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if (CompareText(stStatus, Status.Strings[fpos]) <> 0) and - (filterMark.Items[fpos] = FILTER_SHOW) then - filterMark.Items[fpos] := FILTER_HIDE; - end; - - // filter genres - if checkedGenres.Count > 0 then - begin - for i := 0 to checkedGenres.Count - 1 do - if useRegExpr then - checkedGenres[i] := Trim(checkedGenres[i]) - else - checkedGenres.Strings[i] := Trim(LowerCase(checkedGenres.Strings[i])); - gen := TStringList.Create; - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if filterMark.Items[fpos] = FILTER_SHOW then - begin - gen.Clear; - ExtractStrings([','], [], PChar(Trim(LowerCase(Genres[fpos]))), gen); - TrimStrings(gen); - if gen.Count > 0 then - begin - if haveAllChecked then - begin - Count := checkedGenres.Count; - for j := 0 to checkedGenres.Count - 1 do - begin - if useRegExpr then - regx.Expression := checkedGenres[j]; - for k := 0 to gen.Count - 1 do - begin - if useRegExpr then - fshow := regx.Exec(gen[k]) - else - fshow := SameText(checkedGenres[j], gen[k]); - if fshow then - begin - Dec(Count); - Break; - end; - end; - end; - if Count > 0 then - filterMark.Items[fpos] := FILTER_HIDE; - end - else - begin - filterMark.Items[fpos] := FILTER_HIDE; - for j := 0 to checkedGenres.Count - 1 do - begin - if useRegExpr then - regx.Expression := checkedGenres[j]; - for k := 0 to gen.Count - 1 do - begin - if useRegExpr then - fshow := regx.Exec(gen[k]) - else - fshow := SameText(checkedGenres[j], gen[k]); - if fshow then - Break; - end; - if fshow then - begin - filterMark.Items[fpos] := FILTER_SHOW; - Break; - end; - end; - end; - end - else - if filterMark.Items[fpos] = FILTER_SHOW then - filterMark.Items[fpos] := FILTER_HIDE; - end; - end; - gen.Free; - end; - - if uncheckedGenres.Count > 0 then - begin - for i := 0 to uncheckedGenres.Count - 1 do - uncheckedGenres.Strings[i] := LowerCase(uncheckedGenres.Strings[i]); - - for i := 0 to filterPos.Count - 1 do - begin - fpos := filterPos.Items[i]; - if (filterMark.Items[fpos] = FILTER_SHOW) then - begin - s := LowerCase(Genres.Strings[fpos]); - if haveAllChecked then - begin - Count := uncheckedGenres.Count; - for j := 0 to uncheckedGenres.Count - 1 do - if Pos((uncheckedGenres.Strings[j] + ','), s) = 0 then - Dec(Count); - if Count > 0 then - filterMark.Items[fpos] := FILTER_HIDE; - end - else - for j := 0 to uncheckedGenres.Count - 1 do - if Pos((uncheckedGenres.Strings[j] + ','), s) <> 0 then - begin - filterMark.Items[fpos] := FILTER_HIDE; - Break; - end; - end; - end; - end; - - fpos := filterPos.Count; - filterPos.Clear; - for i := 0 to Data.Count - 1 do - if filterMark.Items[i] = FILTER_SHOW then - filterPos.Add(i); - - if filterPos.Count <> fpos then - begin - isFiltered := True; - Result := True; - end; - except - on E: Exception do - Logger.SendException(Self.ClassName + '.Filter.Error!', E); - end; - regx.Free; -end; - -function TDataProcess.Search(AMangaName: String): Boolean; -var - i: Cardinal; -begin - Result := False; - searchPos.Clear; - if filterPos.Count <= 0 then - Exit; - AMangaName := Upcase(AMangaName); - for i := 0 to filterPos.Count - 1 do - if Pos(AMangaName, upcase(Title.Strings[filterPos.Items[i]])) > 0 then - begin - searchPos.Add(filterPos.Items[i]); - Result := True; - end; -end; - -// get data position -function TDataProcess.GetPos(const ANodePos: Integer): Integer; -begin - if searchPos.Count = 0 then - Result := filterPos.Items[ANodePos] - else - Result := searchPos.Items[ANodePos]; -end; - -procedure TDataProcess.RemoveFilter; -var - i: Cardinal; -begin - searchPos.Clear; - filterMark.Clear; - filterPos.Clear; - if Data.Count > 0 then - for i := 0 to Data.Count - 1 do - begin - filterMark.Add(FILTER_SHOW); - filterPos.Add(i); - end; - isFiltered := False; -end; - -procedure TDataProcess.Sort; -begin - //QuickSortData(data); - QuickSortNaturalPart(Data, SEPERATOR, DATA_PARAM_TITLE); -end; + Dialogs, frmMain, WebsiteModules, uUpdateThread; { TMangaInformation } @@ -766,32 +107,9 @@ procedure TMangaInformation.SetModuleId(AValue: Integer); WebsiteModules.Modules[FModuleId].PrepareHTTP(FHTTP); end; -procedure TMangaInformation.OnTag(NoCaseTag, ActualTag: String); -begin - parse.Add(ActualTag); -end; - -procedure TMangaInformation.OnText(AText: String); -begin - parse.Add(AText); -end; - function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: String): Byte; var - s: String; p: Integer; - Source: TStringList; - Parser: THTMLParser; - MangaSiteID: Integer; - - {$I includes/MangaTown/directory_page_number.inc} - - {$I includes/NHentai/directory_page_number.inc} - - {$I includes/MangaHost/directory_page_number.inc} - - {$I includes/Dynasty-Scans/directory_page_number.inc} - begin APage := 1; @@ -813,28 +131,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetDirectoryPageNumber) then Result := Modules.GetDirectoryPageNumber(Self, APage, TUpdateListThread(Thread).workPtr, ModuleId) - else - if GetMangaSiteID(AWebsite, MangaSiteID) then - begin - Source := TStringList.Create; - if MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownDirectoryPageNumber - else - if MangaSiteID = NHENTAI_ID then - Result := GetNHentaiDirectoryPageNumber - else - if MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostDirectoryPageNumber - else - if MangaSiteID = DYNASTYSCANS_ID then - Result := GetDynastyScansDirectoryPageNumber - else - begin - Result := NO_ERROR; - APage := 1; - Source.Free; - end; - end else Exit(INFORMATION_NOT_FOUND); @@ -844,31 +140,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; const AWebsite, AURL: String): Byte; -var - Source: TStringList; - Parser: THTMLParser; - MangaSiteID: Integer; - - {$I includes/AnimExtremist/names_and_links.inc} - - {$I includes/AnimeStory/names_and_links.inc} - - {$I includes/ScanManga/names_and_links.inc} - - {$I includes/MangasPROJECT/names_and_links.inc} - - {$I includes/MangaREADER_POR/names_and_links.inc} - - {$I includes/MangaTown/names_and_links.inc} - - {$I includes/NHentai/names_and_links.inc} - - {$I includes/MangaHost/names_and_links.inc} - - {$I includes/MangaKu/names_and_links.inc} - - {$I includes/Dynasty-Scans/names_and_links.inc} - begin //load User-Agent from advancedfile AdvanceLoadHTTPConfig(FHTTP, AWebsite); @@ -879,45 +150,6 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; begin Result := Modules.GetNameAndLink(Self, ANames, ALinks, AURL, ModuleId) end - else - if GetMangaSiteID(AWebsite, MangaSiteID) then - begin - Source := TStringList.Create; - if MangaSiteID = ANIMEEXTREMIST_ID then - Result := AnimeExtremistGetNamesAndLinks - else - if MangaSiteID = ANIMESTORY_ID then - Result := AnimeStoryGetNamesAndLinks - else - if MangaSiteID = SCANMANGA_ID then - Result := ScanMangaGetNamesAndLinks - else - if MangaSiteID = MANGASPROJECT_ID then - Result := MangasPROJECTGetNamesAndLinks - else - if MangaSiteID = MANGAREADER_POR_ID then - Result := MangaREADER_PORGetNamesAndLinks - else - if MangaSiteID = MANGATOWN_ID then - Result := MangaTownGetNamesAndLinks - else - if MangaSiteID = NHENTAI_ID then - Result := NHentaiNamesAndLinks - else - if MangaSiteID = MANGAHOST_ID then - Result := MangaHostGetNamesAndLinks - else - if MangaSiteID = MANGAKU_ID then - Result := MangaKuGetNamesAndLinks - else - if MangaSiteID = DYNASTYSCANS_ID then - Result := DynastyScansGetNamesAndLinks - else - begin - Result := INFORMATION_NOT_FOUND; - Source.Free; - end; - end else Exit(INFORMATION_NOT_FOUND); @@ -926,39 +158,12 @@ function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; RemoveHostFromURLsPair(ALinks, ANames); end; -function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AReconnect: Integer): Byte; +function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String): Byte; var s, s2: String; j, k: Integer; del: Boolean; - Source: TStringList; - Parser: THTMLParser; - MangaSiteID: Integer; bmangaInfo: TBaseMangaInfo; - - // due to its weird designs, this will take a lot of work (and time) for it to - // work property - - {$I includes/AnimExtremist/manga_information.inc} - - {$I includes/AnimeStory/manga_information.inc} - - {$I includes/ScanManga/manga_information.inc} - - {$I includes/MangasPROJECT/manga_information.inc} - - {$I includes/MangaREADER_POR/manga_information.inc} - - {$I includes/MangaTown/manga_information.inc} - - {$I includes/NHentai/manga_information.inc} - - {$I includes/MangaHost/manga_information.inc} - - {$I includes/MangaKu/manga_information.inc} - - {$I includes/Dynasty-Scans/manga_information.inc} - begin if Trim(AURL) = '' then Exit(INFORMATION_NOT_FOUND); @@ -980,47 +185,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR mangaInfo.url := FillHost(Modules.Module[ModuleId].RootURL, AURL); Result := Modules.GetInfo(Self, AURL, ModuleId); end - else - if GetMangaSiteID(AWebsite, MangaSiteID) then - begin - mangaInfo.url := FillMangaSiteHost(MangaSiteID, AURL); - Source := TStringList.Create; - if MangaSiteID = ANIMEEXTREMIST_ID then - Result := GetAnimeExtremistInfoFromURL - else - if MangaSiteID = ANIMESTORY_ID then - Result := GetAnimeStoryInfoFromURL - else - if MangaSiteID = SCANMANGA_ID then - Result := GetScanMangaInfoFromURL - else - if MangaSiteID = MANGASPROJECT_ID then - Result := GetMangasPROJECTInfoFromURL - else - if MangaSiteID = MANGAREADER_POR_ID then - Result := GetMangaREADER_PORInfoFromURL - else - if MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownInfoFromURL - else - if MangaSiteID = NHENTAI_ID then - Result := GetNHentaiInfoFromURL - else - if MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostInfoFromURL - else - if MangaSiteID = MANGAKU_ID then - Result := GetMangaKuInfoFromURL - else - if MangaSiteID = DYNASTYSCANS_ID then - Result := GetDynastyScansInfoFromURL - else - begin - Source.Free; - Result := INFORMATION_NOT_FOUND; - Exit; - end; - end else Exit(INFORMATION_NOT_FOUND); @@ -1119,62 +283,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String; const AR end; end; -procedure TMangaInformation.SyncMinorInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); -begin - // sync info to data - {$IFDEF DOWNLOADER} - if not ADataProcess.isFilterAllSites then - {$ENDIF} - ADataProcess.Data.Strings[AIndex] := SetParams( - [ADataProcess.Param[AIndex, DATA_PARAM_TITLE], - ADataProcess.Param[AIndex, DATA_PARAM_LINK], - ADataProcess.Param[AIndex, DATA_PARAM_AUTHORS], - ADataProcess.Param[AIndex, DATA_PARAM_ARTISTS], - ADataProcess.Param[AIndex, DATA_PARAM_GENRES], - mangaInfo.status, - ADataProcess.Param[AIndex, DATA_PARAM_SUMMARY], - IntToStr(mangaInfo.numChapter), - {$IFDEF DOWNLOADER} - ADataProcess.Param[AIndex, DATA_PARAM_JDN], - {$ELSE} - '0', - {$ENDIF} - '0']); - // then break it into parts - ADataProcess.BreakDataToParts(AIndex); -end; - -procedure TMangaInformation.SyncInfoToData(const ADataProcess: TDataProcess; const AIndex: Cardinal); -begin - // sync info to data - {$IFDEF DOWNLOADER} - if not ADataProcess.isFilterAllSites then - {$ENDIF} - begin - if Trim(mangaInfo.title) = '' then - mangaInfo.title := ADataProcess.Param[AIndex, DATA_PARAM_TITLE]; - ADataProcess.Data.Strings[AIndex] := SetParams( - //[ADataProcess.Param[AIndex, DATA_PARAM_TITLE], - //sync title as well, some site possible to change title or when mangainfo script not work - [mangaInfo.title, - ADataProcess.Param[AIndex, DATA_PARAM_LINK], - mangaInfo.authors, - mangaInfo.artists, - mangaInfo.genres, - mangaInfo.status, - StringFilter(mangaInfo.summary), - IntToStr(mangaInfo.numChapter), - {$IFDEF DOWNLOADER} - ADataProcess.Param[AIndex, DATA_PARAM_JDN], - {$ELSE} - '0', - {$ENDIF} - '0']); - end; - // then break it into parts - ADataProcess.BreakDataToParts(AIndex); -end; - procedure TMangaInformation.SyncInfoToData(const ADataProcess: TDBDataProcess); begin if Assigned(ADataProcess) then @@ -1183,68 +291,6 @@ procedure TMangaInformation.SyncInfoToData(const ADataProcess: TDBDataProcess); numChapter, website); end; -procedure TMangaInformation.AddInfoToDataWithoutBreak(const AName, ALink: String; - const ADataProcess: TDataProcess); -var - S: String; -begin - if mangaInfo.title <> '' then - S := mangaInfo.title - else - S := AName; - - ADataProcess.Data.Add(RemoveStringBreaks(SetParams([ - S, - ALink, - mangaInfo.authors, - mangaInfo.artists, - mangaInfo.genres, - mangaInfo.status, - StringFilter(mangaInfo.summary), - IntToStr(mangaInfo.numChapter), - {$IFDEF DOWNLOADER} - IntToStr(GetCurrentJDN), - {$ELSE} - '0', - {$ENDIF} - '0' - ]))); -end; - -procedure TMangaInformation.AddInfoToData(const AName, Alink: String; const ADataProcess: TDataProcess); -var - l: TStringList; -begin - l := TStringList.Create; - ADataProcess.Data.Add( - RemoveStringBreaks( - SetParams( - [AName, - Alink, - mangaInfo.authors, - mangaInfo.artists, - mangaInfo.genres, - mangaInfo.status, - StringFilter(mangaInfo.summary), - IntToStr(mangaInfo.numChapter), - IntToStr(GetCurrentJDN), - '0']))); - GetParams(l, ADataProcess.Data.Strings[ADataProcess.Data.Count - 1]); - ADataProcess.title.Add(l.Strings[DATA_PARAM_TITLE]); - ADataProcess.link.Add(l.Strings[DATA_PARAM_LINK]); - ADataProcess.authors.Add(l.Strings[DATA_PARAM_AUTHORS]); - ADataProcess.artists.Add(l.Strings[DATA_PARAM_ARTISTS]); - ADataProcess.genres.Add(l.Strings[DATA_PARAM_GENRES]); - ADataProcess.status.Add(l.Strings[DATA_PARAM_STATUS]); - ADataProcess.summary.Add(l.Strings[DATA_PARAM_SUMMARY]); - {$IFDEF DOWNLOADER} - ADataProcess.jdn.Add(Pointer(StrToInt(l.Strings[DATA_PARAM_JDN]))); - {$ELSE} - DataProcess.jdn.Add(Pointer(StrToInt('0'))); - {$ENDIF} - l.Free; -end; - procedure TMangaInformation.AddInfoToData(const ATitle, ALink: String; const ADataProcess: TDBDataProcess); begin if Assigned(ADataProcess) then diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index a2252e89b..221d7344a 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -15,10 +15,9 @@ interface uses - LazFileUtils, FastHTMLParser, HTMLUtil, SynaCode, RegExpr, IniFiles, Classes, - SysUtils, ExtCtrls, typinfo, fgl, blcksock, MultiLog, uBaseUnit, uPacker, - uMisc, DownloadedChaptersDB, FMDOptions, httpsendthread, DownloadsDB, - BaseThread, dateutils, strutils; + LazFileUtils, RegExpr, IniFiles, Classes, SysUtils, ExtCtrls, typinfo, fgl, + blcksock, MultiLog, uBaseUnit, uPacker, uMisc, DownloadedChaptersDB, FMDOptions, + httpsendthread, DownloadsDB, BaseThread, dateutils, strutils; type TDownloadStatusType = ( @@ -42,7 +41,6 @@ TTaskThread = class; TDownloadThread = class(TBaseThread) private - parse: TStringList; FTask: TTaskThread; procedure SetTask(AValue: TTaskThread); public @@ -53,17 +51,11 @@ TDownloadThread = class(TBaseThread) // Download image function DownloadImage: Boolean; - procedure OnTag({%H-}NoCaseTag, ActualTag: String); - procedure OnText(Text: String); - procedure SockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); function GetPage(var output: TObject; URL: String; const Reconnect: Integer = 0): Boolean; inline; - function SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name: String; const Reconnect: Integer = 0): Boolean; overload; - procedure Execute; override; public FHTTP: THTTPSendThread; @@ -148,7 +140,6 @@ TTaskContainer = class WorkCounter, DownCounter, PageNumber: Integer; - MangaSiteID: Integer; ModuleId: Integer; //Status: TDownloadStatusType; ThreadState: Boolean; @@ -296,16 +287,6 @@ procedure TDownloadThread.SetTask(AValue: TTaskThread); WebsiteModules.Modules[ModuleId].PrepareHTTP(FHTTP); end; -procedure TDownloadThread.OnTag(NoCaseTag, ActualTag: String); -begin - parse.Add(ActualTag); -end; - -procedure TDownloadThread.OnText(Text: String); -begin - parse.Add(Text); -end; - procedure TDownloadThread.SockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); begin @@ -342,12 +323,6 @@ function TDownloadThread.GetPage(var output: TObject; URL: String; Result := uBaseUnit.GetPage(FHTTP, output, URL, Reconnect); end; -function TDownloadThread.SaveImage(const mangaSiteID: Integer; URL: String; - const Path, Name: String; const Reconnect: Integer): Boolean; -begin - Result := uBaseUnit.SaveImage(FHTTP, mangaSiteID, URL, Path, Name, Reconnect); -end; - procedure TDownloadThread.Execute; var Reslt: Boolean = False; @@ -405,107 +380,22 @@ procedure TDownloadThread.Execute; end; function TDownloadThread.GetPageNumberFromURL(const URL: String): Boolean; -var - Parser: THTMLParser; - - {$I includes/AnimeStory/chapter_page_number.inc} - - {$I includes/AnimExtremist/chapter_page_number.inc} - - {$I includes/MangaTown/chapter_page_number.inc} - - {$I includes/NHentai/chapter_page_number.inc} - - {$I includes/MangaHost/chapter_page_number.inc} - - {$I includes/MangaKu/chapter_page_number.inc} - - {$I includes/Dynasty-Scans/chapter_page_number.inc} - begin Result := False; Task.Container.PageNumber := 0; if Modules.ModuleAvailable(Task.Container.ModuleId, MMGetPageNumber) then - Result := Modules.GetPageNumber(Self, URL, Task.Container.ModuleId) - else - begin - if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then - Result := GetAnimeExtremistPageNumber - else - if Task.Container.MangaSiteID = ANIMESTORY_ID then - Result := GetAnimeStoryPageNumber - else - if Task.Container.MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownPageNumber - else - if Task.Container.MangaSiteID = NHENTAI_ID then - Result := GetNHentaiPageNumber - else - if Task.Container.MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostPageNumber - else - if Task.Container.MangaSiteID = MANGAKU_ID then - Result := GetMangaKuPageNumber - else - if Task.Container.MangaSiteID = DYNASTYSCANS_ID then - Result := GetDynastyScansPageNumber; - end; + Result := Modules.GetPageNumber(Self, URL, Task.Container.ModuleId); if Task.Container.PageLinks.Count > 0 then TrimStrings(Task.Container.PageLinks); end; function TDownloadThread.GetLinkPageFromURL(const URL: String): Boolean; -var - Parser: THTMLParser; - - {$I includes/AnimeStory/image_url.inc} - - {$I includes/AnimExtremist/image_url.inc} - - {$I includes/MangaREADER_POR/image_url.inc} - - {$I includes/MangasPROJECT/image_url.inc} - - {$I includes/ScanManga/image_url.inc} - - {$I includes/MangaTown/image_url.inc} - - {$I includes/NHentai/image_url.inc} - - {$I includes/MangaHost/image_url.inc} - begin Result := False; if Task.Container.PageLinks[WorkId] <> 'W' then Exit; if Modules.ModuleAvailable(Task.Container.ModuleId, MMGetImageURL) then - Result := Modules.GetImageURL(Self, URL, Task.Container.ModuleId) - else - begin - if Task.Container.MangaSiteID = ANIMEEXTREMIST_ID then - Result := GetAnimeExtremistImageURL - else - if Task.Container.MangaSiteID = ANIMESTORY_ID then - Result := GetAnimeStoryImageURL - else - if Task.Container.MangaSiteID = SCANMANGA_ID then - Result := GetScanMangaImageURL - else - if Task.Container.MangaSiteID = MANGASPROJECT_ID then - Result := GetMangasPROJECTImageURL - else - if Task.Container.MangaSiteID = MANGAREADER_POR_ID then - Result := GetMangaREADER_PORImageURL - else - if Task.Container.MangaSiteID = MANGATOWN_ID then - Result := GetMangaTownImageURL - else - if Task.Container.MangaSiteID = NHENTAI_ID then - Result := GetNHentaiImageURL - else - if Task.Container.MangaSiteID = MANGAHOST_ID then - Result := GetMangaHostImageURL; - end; + Result := Modules.GetImageURL(Self, URL, Task.Container.ModuleId); end; // ----- TTaskThread ----- @@ -1207,7 +1097,6 @@ procedure TTaskContainer.SetWebsite(AValue: String); if FWebsite = AValue then Exit; FWebsite := AValue; DownloadInfo.Website := AValue; - MangaSiteID := GetMangaSiteID(AValue); ModuleId := Modules.LocateModule(AValue); end; @@ -1246,7 +1135,6 @@ constructor TTaskContainer.Create; FileNames := TStringList.Create; FWebsite := ''; ModuleId := -1; - MangaSiteID := High(WebsiteRoots) + 1; ReadCount := 0; WorkCounter := 0; CurrentPageNumber := 0; diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index 26be13731..f94fde611 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -250,7 +250,7 @@ procedure TFavoriteThread.Execute; // get new manga info FMangaInformation.isGetByUpdater := False; FMangaInformation.mangaInfo.title := FavoriteInfo.Title; - FMangaInformation.GetInfoFromURL(FavoriteInfo.Website, FavoriteInfo.Link, DefaultRetryCount); + FMangaInformation.GetInfoFromURL(FavoriteInfo.Website, FavoriteInfo.Link); if not Terminated then begin NewMangaInfo := FMangaInformation.mangaInfo; diff --git a/baseunits/uGetMangaInfosThread.pas b/baseunits/uGetMangaInfosThread.pas index 41ab0bfba..a0eadb5e6 100644 --- a/baseunits/uGetMangaInfosThread.pas +++ b/baseunits/uGetMangaInfosThread.pas @@ -16,8 +16,8 @@ interface uses - SysUtils, Graphics, Dialogs, uBaseUnit, uData, FMDOptions, - BaseThread, VirtualTrees; + SysUtils, Graphics, Dialogs, uBaseUnit, uData, FMDOptions, BaseThread, + VirtualTrees; type @@ -99,7 +99,7 @@ procedure TGetMangaInfosThread.Execute; Modules.IncActiveConnectionCount(FInfo.ModuleId); end; - infob := FInfo.GetInfoFromURL(Website, Link, 0); + infob := FInfo.GetInfoFromURL(Website, Link); if Terminated or isExiting then Exit; if infob <> NO_ERROR then Exit; diff --git a/baseunits/uSilentThread.pas b/baseunits/uSilentThread.pas index 47014bb28..6d7e023c1 100644 --- a/baseunits/uSilentThread.pas +++ b/baseunits/uSilentThread.pas @@ -404,7 +404,7 @@ procedure TSilentThread.Execute; try Info.ModuleId := Self.ModuleId; Info.mangaInfo.title := title; - if Info.GetInfoFromURL(website, URL, DefaultRetryCount) = NO_ERROR then + if Info.GetInfoFromURL(website, URL) = NO_ERROR then if not Terminated then Synchronize(MainThreadAfterChecking); except diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 0b510e4d6..cde0027ce 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -197,7 +197,7 @@ procedure TUpdateListThread.Execute; Info.mangaInfo.title:=title; Info.mangaInfo.link:=link; if link<>'' then begin - Info.GetInfoFromURL(manager.website,link,DefaultRetryCount); + Info.GetInfoFromURL(manager.website,link); // status = '-1' mean it's not exist and shouldn't be saved to database if (not Terminated) and (Info.mangaInfo.status <> '-1') then begin diff --git a/config/mangalist.ini b/config/mangalist.ini index 7f12d0bbe..6ca5b34e9 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,22 +4,22 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] Arabic=GManga,MangaAe,Mangaf -English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTown,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd +English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT -English-Scanlation=Dynasty-Scans,GameofScanlation,MangaZuki,PsychoPlay -French=AnimeStory,Japan-Shin,Japscan,ScanManga +English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay +French=Japan-Shin,Japscan German=MangaTube,NineMangaDE,WieManga -Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaKu,MangaShiro,Mangavy,PecintaKomik,Subapics +Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics Malaysian-Indonesian= Polish= -Portugues=MangaHost,MangaOnlineBR,MangaREADER_POR,NineMangaBR,UnionMangas +Portugues=MangaOnlineBR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,NineMangaRU,MangaHubRU -Spanish=AnimExtremist,KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline +Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Spanish-Scanlation= Thai= Turkish=Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan Webcomics=Tapas -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,NHentai,PervEden,PervEden_IT,Tsumino,YaoiChanRU +H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,PervEden,PervEden_IT,Tsumino,YaoiChanRU Adult=Comic-XXX,FreeAdultComix,PornComix diff --git a/mangadownloader/forms/frmDropTarget.pas b/mangadownloader/forms/frmDropTarget.pas index 9b057709e..5c17cc1bd 100644 --- a/mangadownloader/forms/frmDropTarget.pas +++ b/mangadownloader/forms/frmDropTarget.pas @@ -5,8 +5,8 @@ interface uses - Classes, Windows, SysUtils, ActiveX, comobj, HTMLUtil, Forms, Controls, - ExtCtrls, Menus, LCLType, DefaultTranslator, uBaseUnit; + Classes, Windows, SysUtils, ActiveX, comobj, Forms, Controls, + ExtCtrls, Menus, LCLType, DefaultTranslator, uBaseUnit, XQueryEngineHTML; type @@ -138,37 +138,17 @@ function GetWideTextFromObj(const DataObj: IDataObject; function GetURLsFromHTML(const S: String): String; var - Parse, URls: TStringList; - i: Integer; - url: String; + URls: TStringList; begin Result := S; if S = '' then Exit; - Parse:= TStringList.Create; + URLs := TStringList.Create; try - ParseHTML(S, Parse); - if Parse.Count > 0 then - begin - URls := TStringList.Create; - try - for i := 0 to Parse.Count - 1 do - begin - if LowerCase(GetTagName(Parse[i])) = 'a' then - url := GetVal(Parse[i], 'href'); - if Pos('javascript', url) <> 1 then - URls.Add(url); - end; - if URls.Count > 0 then - begin - RemoveDuplicateStrings(URls); - Result := URls.Text; - end; - finally - URls.Free; - end; - end; + XPathStringAll('//a[not(starts-with(@href,"javascript:"))]/@href', S, URls); + RemoveDuplicateStrings(URls); + Result := URls.Text finally - Parse.Free; + URls.Free; end; end; diff --git a/mangadownloader/forms/frmImportFavorites.pas b/mangadownloader/forms/frmImportFavorites.pas index e5474ad36..c81f08ee9 100644 --- a/mangadownloader/forms/frmImportFavorites.pas +++ b/mangadownloader/forms/frmImportFavorites.pas @@ -101,12 +101,6 @@ procedure TImportFavorites.DMDHandle; m := Modules.LocateModuleByHost(host); if m > -1 then webs := Modules.Module[m].Website; - if webs = '' then - begin - for j := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(host, LowerCase(WebsiteRoots[j, 1])) <> 0 then - webs := WebsiteRoots[j, 0]; - end; end; if webs <> '' then diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index e05b47a0e..d21d90e9c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4639,12 +4639,6 @@ procedure TMainForm.AddSilentThread(URL: string; MetaDataType: TMetaDataType); m := Modules.LocateModuleByHost(host); if m > -1 then webs := Modules.Module[m].Website; - if webs = '' then - begin - for j := Low(WebsiteRoots) to High(WebsiteRoots) do - if Pos(host, LowerCase(WebsiteRoots[j, 1])) <> 0 then - webs := WebsiteRoots[j, 0]; - end; if webs <> '' then begin if not ((MetaDataType = MD_AddToFavorites) and SitesWithoutFavorites(webs)) then @@ -4731,9 +4725,7 @@ procedure TMainForm.ViewMangaInfo(const ALink, AWebsite, ATitle, ASaveTo: String // set the UI i := Modules.LocateModule(AWebsite); if i <> -1 then - edURL.Text := FillHost(Modules.Module[i].RootURL, ALink) - else - edURL.Text := FillMangaSiteHost(AWebsite, ALink); + edURL.Text := FillHost(Modules.Module[i].RootURL, ALink); pcMain.ActivePage := tsInformation; imCover.Picture.Assign(nil); rmInformation.Clear; @@ -5475,13 +5467,7 @@ procedure TMainForm.edURLButtonClick(Sender: TObject); host := LowerCase(host); i := Modules.LocateModuleByHost(host); if i <> -1 then - website := Modules.Module[i].Website - else - begin - i := LocateMangaSiteID(host); - if i <> -1 then - website := WebsiteRoots[i, 0]; - end; + website := Modules.Module[i].Website; end; if (website = '') or (link = '') then From 7fde52b8208bdde048ea2d12ec78206a3dd82152 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 05:11:05 +0800 Subject: [PATCH 2276/2794] mangalist, remove empty --- config/mangalist.ini | 4 ---- 1 file changed, 4 deletions(-) diff --git a/config/mangalist.ini b/config/mangalist.ini index 6ca5b34e9..a39b5ffd4 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -10,14 +10,10 @@ English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay French=Japan-Shin,Japscan German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics -Malaysian-Indonesian= -Polish= Portugues=MangaOnlineBR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline -Spanish-Scanlation= -Thai= Turkish=Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan Webcomics=Tapas From ecc54450431e8e148f3201e2928e6bba29c50248 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 05:21:41 +0800 Subject: [PATCH 2277/2794] update Indonesian localization --- mangadownloader/languages/fmd.id_ID.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 967442603..285993424 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -163,17 +163,17 @@ msgstr "%s DIHAPUS*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" msgid "%s FAILED*" -msgstr "%s GAGAL" +msgstr "%s GAGAL*" #: frmluamodulesupdater.rs_statusnew msgctxt "frmluamodulesupdater.rs_statusnew" msgid "%s NEW*" -msgstr "%s BARU" +msgstr "%s BARU*" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "%s DOWNLOADULANG" +msgstr "%s DOWNLOADULANG*" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" From 02dd5cb58103522f19c6c3b764083b61c5f905a3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 05:34:38 +0800 Subject: [PATCH 2278/2794] cleanup --- baseunits/uBaseUnit.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index a983103cb..8086ac630 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -20,7 +20,7 @@ interface {$endif} SysUtils, Classes, Graphics, lazutf8classes, LazFileUtils, LConvEncoding, LazUtils, strutils, dateutils, variants, base64, fpjson, jsonparser, jsonscanner, - FastHTMLParser, fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, + fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit, MemBitmap, FPWritePNG, zstream; From c9a419f7a7de4b62311777b75df497096e6fd69e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 05:57:17 +0800 Subject: [PATCH 2279/2794] Bump version 0.9.143.0 --- changelog.txt | 7 ++++++- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6c1f3bfc9..a5f12f9c8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,12 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.141.0 (16-02-2018) +0.9.143.0 (17-02-2018) +[*] Update Indonesian localization +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.142.0...0.9.143.0 + +0.9.142.0 (16-02-2018) [+] Added ManhwaCo [EN-SC] [+] Added HentaiHere [H] [*] Fixed update list issue diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 7b5d0e90b..b0ccb200d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="142"/> + <RevisionNr Value="143"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 636e9af84..23c6472f8 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.142.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.142.0/fmd_0.9.142.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.142.0/fmd_0.9.142.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.142.0/fmd_0.9.142.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.142.0/fmd_0.9.142.0_Win64.7z +VERSION=0.9.143.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.143.0/fmd_0.9.143.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.143.0/fmd_0.9.143.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.143.0/fmd_0.9.143.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.143.0/fmd_0.9.143.0_Win64.7z From 5aa7d50409325de94f70b8d20f2cb23fe4a160b3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 07:43:45 +0800 Subject: [PATCH 2280/2794] added dynastyscans --- lua/modules/DynastyScans.lua | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lua/modules/DynastyScans.lua diff --git a/lua/modules/DynastyScans.lua b/lua/modules/DynastyScans.lua new file mode 100644 index 000000000..5660c4a90 --- /dev/null +++ b/lua/modules/DynastyScans.lua @@ -0,0 +1,60 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//*[@class="tag-title"]') + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//img[@class="thumbnail"]/@src')) + mangainfo.authors=x.xpathstring('//a[contains(@href,"/title/")]') + mangainfo.genres=x.xpathstringall('//*[@class="label" or @class="doujin_tags"]') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//small')) + mangainfo.summary=x.xpathstring('//*[@class="description"]') + x.xpathhrefall('//dl[@class="chapter-list"]/dd/a',mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_error + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + TXQuery.Create(http.Document).xpathstringall('json(//script[contains(.,"var pages")]/substring-after(substring-before(.,";")," = "))()/concat("'..module.rooturl..'",./image)',task.pagelinks) + return true + else + return false + end + return true +end + +local diruris={ + '/anthologies', + '/doujins', + '/issues', + '/series' + } + +function getdirectorypagenumber() + page=#diruris + return no_error +end + +function getnameandlink() + print(diruris[tonumber(url)+1]) + if http.get(module.rooturl..diruris[tonumber(url)+1]) then + TXQuery.Create(http.document).xpathhrefall('//dd/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='English-Scanlation' + m.website='DynastyScans' + m.rooturl='https://dynasty-scans.com' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' +end From c0f5d0dc3a175d30798d3aad9120dd758fe79025 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 07:44:59 +0800 Subject: [PATCH 2281/2794] added dynastyscans --- lua/modules/DynastyScans.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/DynastyScans.lua b/lua/modules/DynastyScans.lua index 5660c4a90..7c04b39b5 100644 --- a/lua/modules/DynastyScans.lua +++ b/lua/modules/DynastyScans.lua @@ -38,7 +38,6 @@ function getdirectorypagenumber() end function getnameandlink() - print(diruris[tonumber(url)+1]) if http.get(module.rooturl..diruris[tonumber(url)+1]) then TXQuery.Create(http.document).xpathhrefall('//dd/a',links,names) return no_error From a29d996dcbdf9404e443b4115b9ef57456034949 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 08:35:12 +0800 Subject: [PATCH 2282/2794] fix #992 --- mangadownloader/forms/frmMain.pas | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index d21d90e9c..2b73ef19b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3185,16 +3185,15 @@ procedure TMainForm.miChapterListUncheckAllClick(Sender: TObject); procedure TMainForm.mnDownload1ClickClick(Sender: TObject); begin - if (DBUpdaterThread = nil) and - (MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = - mrYes) then + if DBUpdaterThread <> nil then + DBUpdaterThread.Add(cbSelectManga.Items) + else + if MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = mrYes then begin DBUpdaterThread := TDBUpdaterThread.Create; DBUpdaterThread.Items.AddStrings(cbSelectManga.Items); DBUpdaterThread.Start; - end - else - DBUpdaterThread.Add(cbSelectManga.Items); + end; end; procedure TMainForm.mnFilterGenreAllCheckClick(Sender: TObject); @@ -4831,16 +4830,15 @@ procedure TMainForm.ShowInformation; procedure TMainForm.RunGetList; begin - if (DBUpdaterThread = nil) and - (MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = - mrYes) then + if DBUpdaterThread <> nil then + DBUpdaterThread.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]) + else + if MessageDlg('', RS_DlgUpdaterWantToUpdateDB, mtInformation, [mbYes, mbNo], 0) = mrYes then begin DBUpdaterThread := TDBUpdaterThread.Create; DBUpdaterThread.Items.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); DBUpdaterThread.Start; - end - else - DBUpdaterThread.Add(cbSelectManga.Items[cbSelectManga.ItemIndex]); + end; end; procedure TMainForm.LoadOptions; From 06b1a2ab2cfb49dc89946ef02571f71992a8f3cc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 09:08:31 +0800 Subject: [PATCH 2283/2794] updatelist, store data if nomangainfo and no sortedlist --- baseunits/uUpdateThread.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index cde0027ce..620207890 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -618,7 +618,9 @@ procedure TUpdateListManagerThread.Execute; if ModuleId <> -1 then Modules.BeforeUpdateList(ModuleId); - if Terminated then Break; + if Terminated then + if not (OptionUpdateListNoMangaInfo and not(SortedList)) then + Break; FStatus := RS_UpdatingList + Format(' [%d/%d] %s', [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; From d22d64855ec9b6e8ff221fdd780edd63573e2537 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 10:28:18 +0800 Subject: [PATCH 2284/2794] website module, added some overload and cleanup --- baseunits/WebsiteModules.pas | 208 +++++++++++++++++++++-------------- 1 file changed, 126 insertions(+), 82 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index b38972537..a875fae6e 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -10,8 +10,8 @@ interface uses - Classes, SysUtils, uData, uDownloadsManager, FMDOptions, httpsendthread, LazLogger, - Cloudflare, RegExpr; + Classes, SysUtils, fgl, uData, uDownloadsManager, FMDOptions, httpsendthread, + LazLogger, Cloudflare, RegExpr; const MODULE_NOT_FOUND = -1; @@ -126,14 +126,22 @@ TModuleContainer = class const ACaption, AItems: PString); property CloudflareEnabled: Boolean read FCloudflareEnabled write SetCloudflareEnabled; procedure PrepareHTTP(const AHTTP: THTTPSendThread); + + procedure IncActiveTaskCount; inline; + procedure DecActiveTaskCount; inline; + procedure IncActiveConnectionCount; inline; + procedure DecActiveConnectionCount; inline; end; + TModuleContainers = specialize TFPGList<TModuleContainer>; + { TWebsiteModules } TWebsiteModules = class private FCSModules: TRTLCriticalSection; - FModuleList: TFPList; + FModuleList: TModuleContainers; + function ModuleExist(const ModuleId: Integer): Boolean; inline; function GetModule(const ModuleId: Integer): TModuleContainer; function GetCount: Integer; function GetMaxTaskLimit(const ModuleId: Integer): Integer; @@ -147,6 +155,7 @@ TWebsiteModules = class function AddModule: TModuleContainer; function LocateModule(const AWebsite: String): Integer; + function LocateModule(const AWebsite: String; var M: TModuleContainer): Integer; function LocateModuleByHost(const AHost: String): Integer; function ModuleAvailable(const ModuleId: Integer; const ModuleMethod: TModuleMethod): Boolean; overload; @@ -158,6 +167,7 @@ TWebsiteModules = class function ModuleAvailable(const AWebsite: String): Boolean; overload; function ModuleAvailable(const AWebsite: String; var OutIndex: Integer): Boolean; overload; + function ModuleAvailable(const AWebsite: String; var M: TModuleContainer): Boolean; overload; function BeforeUpdateList(const ModuleId: Integer): Boolean; function AfterUpdateList(const ModuleId: Integer): Boolean; @@ -370,6 +380,26 @@ procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); CheckCloudflareEnabled(AHTTP); end; +procedure TModuleContainer.IncActiveTaskCount; +begin + ActiveTaskCount := InterLockedIncrement(ActiveTaskCount); +end; + +procedure TModuleContainer.DecActiveTaskCount; +begin + ActiveTaskCount := InterLockedDecrement(ActiveTaskCount); +end; + +procedure TModuleContainer.IncActiveConnectionCount; +begin + ActiveConnectionCount := InterLockedIncrement(ActiveConnectionCount); +end; + +procedure TModuleContainer.DecActiveConnectionCount; +begin + ActiveConnectionCount := InterLockedDecrement(ActiveConnectionCount); +end; + procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; const AName: String; const ACaption: PString; const AItems: PString); @@ -392,7 +422,7 @@ procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; constructor TWebsiteModules.Create; begin InitCriticalSection(FCSModules); - FModuleList := TFPList.Create; + FModuleList := TModuleContainers.Create; end; destructor TWebsiteModules.Destroy; @@ -401,7 +431,7 @@ destructor TWebsiteModules.Destroy; begin if FModuleList.Count > 0 then for i := FModuleList.Count - 1 downto 0 do - TModuleContainer(FModuleList[i]).Free; + FModuleList[i].Free; FModuleList.Free; DoneCriticalsection(FCSModules); inherited Destroy; @@ -425,13 +455,21 @@ function TWebsiteModules.LocateModule(const AWebsite: String): Integer; Result := -1; if FModuleList.Count > 0 then for i := FModuleList.Count - 1 downto 0 do - if SameText(TModuleContainer(FModuleList[i]).Website, AWebsite) then + if SameText(FModuleList[i].Website, AWebsite) then begin Result := i; Break; end; end; +function TWebsiteModules.LocateModule(const AWebsite: String; + var M: TModuleContainer): Integer; +begin + Result := LocateModule(AWebsite); + if Result <> -1 then + M := FModuleList[Result]; +end; + function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; function PosModule(const s: String): Integer; @@ -439,7 +477,7 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; i: Integer; begin for i := FModuleList.Count - 1 downto 0 do - if Pos(s, LowerCase(TModuleContainer(FModuleList[i]).RootURL)) <> 0 then + if Pos(s, LowerCase(FModuleList[i].RootURL)) <> 0 then Exit(i); Result := -1; end; @@ -458,12 +496,17 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; end; end; +function TWebsiteModules.ModuleExist(const ModuleId: Integer): Boolean; +begin + Result := (ModuleId > 0) and (ModuleId < FModuleList.Count); +end; + function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; const ModuleMethod: TModuleMethod): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do case ModuleMethod of MMGetDirectoryPageNumber: Result := Assigned(OnGetDirectoryPageNumber); MMGetNameAndLink: Result := Assigned(OnGetNameAndLink); @@ -505,22 +548,29 @@ function TWebsiteModules.ModuleAvailable(const AWebsite: String; Result := OutIndex > -1; end; +function TWebsiteModules.ModuleAvailable(const AWebsite: String; + var M: TModuleContainer): Boolean; +begin + M := GetModule(LocateModule(AWebsite)); + Result := M <> nil; +end; + function TWebsiteModules.BeforeUpdateList(const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnBeforeUpdateList) then - Result := OnBeforeUpdateList(TModuleContainer(FModuleList[ModuleId])); + Result := OnBeforeUpdateList(FModuleList[ModuleId]); end; function TWebsiteModules.AfterUpdateList(const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; + if ModuleExist(ModuleId) then with TModuleContainer(FModuleList[ModuleId]) do if Assigned(OnAfterUpdateList) then - Result := OnAfterUpdateList(TModuleContainer(FModuleList[ModuleId])); + Result := OnAfterUpdateList(FModuleList[ModuleId]); end; function TWebsiteModules.GetDirectoryPageNumber( @@ -529,10 +579,10 @@ function TWebsiteModules.GetDirectoryPageNumber( begin Page := 1; Result := MODULE_NOT_FOUND; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnGetDirectoryPageNumber) then - Result := OnGetDirectoryPageNumber(MangaInfo, Page, WorkPtr,TModuleContainer(FModuleList[ModuleId])); + Result := OnGetDirectoryPageNumber(MangaInfo, Page, WorkPtr, FModuleList[ModuleId]); end; function TWebsiteModules.GetDirectoryPageNumber( @@ -547,10 +597,10 @@ function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; ): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnGetNameAndLink) then - Result := OnGetNameAndLink(MangaInfo, ANames, ALinks, AURL, TModuleContainer(FModuleList[ModuleId])); + Result := OnGetNameAndLink(MangaInfo, ANames, ALinks, AURL, FModuleList[ModuleId]); end; function TWebsiteModules.GetNameAndLink(const MangaInfo: TMangaInformation; @@ -563,10 +613,10 @@ function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const ModuleId: Integer): Integer; begin Result := MODULE_NOT_FOUND; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnGetInfo) then - Result := OnGetInfo(MangaInfo, AURL, TModuleContainer(FModuleList[ModuleId])); + Result := OnGetInfo(MangaInfo, AURL, FModuleList[ModuleId]); end; function TWebsiteModules.GetInfo(const MangaInfo: TMangaInformation; @@ -579,10 +629,11 @@ function TWebsiteModules.TaskStart(const Task: TTaskContainer; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnTaskStart) then - Result := TModuleContainer(FModuleList[ModuleId]).OnTaskStart( - Task, TModuleContainer(FModuleList[ModuleId])); + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do + if Assigned(OnTaskStart) then + Result := FModuleList[ModuleId].OnTaskStart( + Task, FModuleList[ModuleId]); end; function TWebsiteModules.TaskStart(const Task: TTaskContainer; @@ -595,10 +646,11 @@ function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnGetPageNumber) then - Result := OnGetPageNumber(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + Result := OnGetPageNumber(DownloadThread, AURL, FModuleList[ModuleId]); end; function TWebsiteModules.GetPageNumber(const DownloadThread: TDownloadThread; @@ -611,10 +663,10 @@ function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnGetImageURL) then - Result := OnGetImageURL(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + Result := OnGetImageURL(DownloadThread, AURL, FModuleList[ModuleId]); end; function TWebsiteModules.GetImageURL(const DownloadThread: TDownloadThread; @@ -628,10 +680,10 @@ function TWebsiteModules.BeforeDownloadImage( const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnBeforeDownloadImage) then - Result := OnBeforeDownloadImage(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + Result := OnBeforeDownloadImage(DownloadThread, AURL, FModuleList[ModuleId]); end; function TWebsiteModules.BeforeDownloadImage( @@ -644,10 +696,10 @@ function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnDownloadImage) then - Result := OnDownloadImage(DownloadThread, AURL, TModuleContainer(FModuleList[ModuleId])); + Result := OnDownloadImage(DownloadThread, AURL, FModuleList[ModuleId]); end; function TWebsiteModules.DownloadImage(const DownloadThread: TDownloadThread; @@ -660,10 +712,10 @@ function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; const APath, AName: String; const ModuleId: Integer): String; begin Result := ''; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnSaveImage) then - Result := OnSaveImage(AHTTP, APath, AName, TModuleContainer(FModuleList[ModuleId])); + Result := OnSaveImage(AHTTP, APath, AName, FModuleList[ModuleId]); end; function TWebsiteModules.SaveImage(const AHTTP: THTTPSendThread; @@ -676,10 +728,10 @@ function TWebsiteModules.AfterImageSaved(const AFilename: String; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - if Assigned(TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved) then - Result := TModuleContainer(FModuleList[ModuleId]).OnAfterImageSaved(AFilename, - TModuleContainer(FModuleList[ModuleId])); + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do + if Assigned(OnAfterImageSaved) then + Result := OnAfterImageSaved(AFilename, FModuleList[ModuleId]); end; function TWebsiteModules.AfterImageSaved(const AFilename, AWebsite: String @@ -692,10 +744,10 @@ function TWebsiteModules.Login(const AHTTP: THTTPSendThread; const ModuleId: Integer): Boolean; begin Result := False; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if Assigned(OnLogin) then - Result := OnLogin(AHTTP, TModuleContainer(FModuleList[ModuleId])); + Result := OnLogin(AHTTP, FModuleList[ModuleId]); end; function TWebsiteModules.Login(const AHTTP: THTTPSendThread; @@ -716,50 +768,42 @@ procedure TWebsiteModules.UnlockModules; procedure TWebsiteModules.IncActiveTaskCount(ModuleId: Integer); begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do - if MaxTaskLimit > 0 then - ActiveTaskCount := InterLockedIncrement(ActiveTaskCount); + if ModuleExist(ModuleId) then + FModuleList[ModuleId].IncActiveTaskCount; end; procedure TWebsiteModules.DecActiveTaskCount(ModuleId: Integer); begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do - if ActiveTaskCount > 0 then - ActiveTaskCount := InterLockedDecrement(ActiveTaskCount); + if ModuleExist(ModuleId) then + FModuleList[ModuleId].DecActiveTaskCount; end; function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; begin Result := True; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if MaxTaskLimit > 0 then Result := ActiveTaskCount < MaxTaskLimit; end; procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do - if MaxConnectionLimit > 0 then - ActiveConnectionCount := InterLockedIncrement(ActiveConnectionCount); + if ModuleExist(ModuleId) then + FModuleList[ModuleId].IncActiveConnectionCount; end; procedure TWebsiteModules.DecActiveConnectionCount(ModuleId: Integer); begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do - if ActiveConnectionCount > 0 then - ActiveConnectionCount := InterLockedDecrement(ActiveConnectionCount); + if ModuleExist(ModuleId) then + FModuleList[ModuleId].DecActiveConnectionCount; end; function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; begin Result := True; - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit; - with TModuleContainer(FModuleList[ModuleId]) do + if ModuleExist(ModuleId) then + with FModuleList[ModuleId] do if MaxConnectionLimit > 0 then Result := ActiveConnectionCount < MaxConnectionLimit; end; @@ -770,7 +814,7 @@ procedure TWebsiteModules.LoadWebsiteOption; begin if FModuleList.Count = 0 then Exit; for i := 0 to FModuleList.Count - 1 do - with TModuleContainer(FModuleList[i]) do + with FModuleList[i] do if Length(OptionList) > 0 then for j := Low(OptionList) to High(OptionList) do with OptionList[j], configfile do @@ -789,7 +833,7 @@ procedure TWebsiteModules.SaveWebsiteOption; begin if FModuleList.Count = 0 then Exit; for i := 0 to FModuleList.Count - 1 do - with TModuleContainer(FModuleList[i]) do + with FModuleList[i] do if Length(OptionList) > 0 then for j := Low(OptionList) to High(OptionList) do with OptionList[j], configfile do @@ -806,7 +850,7 @@ procedure TWebsiteModules.SaveWebsiteOption; function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; begin if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(nil); - Result := TModuleContainer(FModuleList[ModuleId]); + Result := FModuleList[ModuleId]; end; function TWebsiteModules.GetCount: Integer; @@ -816,32 +860,32 @@ function TWebsiteModules.GetCount: Integer; function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); - Result := TModuleContainer(FModuleList[ModuleId]).MaxTaskLimit; + if not ModuleExist(ModuleId) then Exit(0); + Result := FModuleList[ModuleId].MaxTaskLimit; end; function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); - Result := TModuleContainer(FModuleList[ModuleId]).MaxConnectionLimit; + if not ModuleExist(ModuleId) then Exit(0); + Result := FModuleList[ModuleId].MaxConnectionLimit; end; function TWebsiteModules.GetActiveTaskCount(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); - Result := TModuleContainer(FModuleList[ModuleId]).ActiveTaskCount; + if not ModuleExist(ModuleId) then Exit(0); + Result := FModuleList[ModuleId].ActiveTaskCount; end; function TWebsiteModules.GetActiveConnectionLimit(const ModuleId: Integer): Integer; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(0); - Result := TModuleContainer(FModuleList[ModuleId]).ActiveConnectionCount; + if not ModuleExist(ModuleId) then Exit(0); + Result := FModuleList[ModuleId].ActiveConnectionCount; end; function TWebsiteModules.GetWebsite(const ModuleId: Integer): String; begin - if (ModuleId < 0) or (ModuleId >= FModuleList.Count) then Exit(''); - Result := TModuleContainer(FModuleList[ModuleId]).Website; + if not ModuleExist(ModuleId) then Exit(''); + Result := FModuleList[ModuleId].Website; end; procedure doInitialize; From da6c1c6ec835f064e414adb96b4f753617e5ff4d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 10:28:34 +0800 Subject: [PATCH 2285/2794] updatelistthread, cleanup --- baseunits/uUpdateThread.pas | 292 ++++++++++++++++-------------------- 1 file changed, 132 insertions(+), 160 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 620207890..0a8bb2a12 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -69,13 +69,12 @@ TUpdateListManagerThread = class(TBaseThread) tempDataProcess: TDBDataProcess; websites: TStringList; website, twebsite, twebsitetemp: String; - ModuleId: Integer; + Module: TModuleContainer; directoryCount, workPtr, websitePtr, numberOfThreads: Integer; Threads: TFPList; - SortedList, NoMangaInfo: Boolean; constructor Create; destructor Destroy; override; procedure CheckCommit(const CommitCount: Integer = 32); @@ -112,7 +111,7 @@ constructor TUpdateListThread.Create; destructor TUpdateListThread.Destroy; begin - Modules.DecActiveConnectionCount(manager.ModuleId); + manager.Module.DecActiveConnectionCount; EnterCriticalsection(manager.CS_Threads); try manager.Threads.Remove(Self); @@ -135,16 +134,11 @@ procedure TUpdateListThread.Execute; else Info := TMangaInformation.Create(Self, False); Info.isGetByUpdater := True; - info.ModuleId := manager.ModuleId; + info.ModuleId := manager.Module.ID; case CheckStyle of CS_DIRECTORY_COUNT: - begin - if manager.ModuleId <> -1 then - info.GetDirectoryPage(Modules[manager.ModuleId].TotalDirectoryPage[workPtr], manager.website) - else - info.GetDirectoryPage(manager.directoryCount, manager.website); - end; + info.GetDirectoryPage(manager.Module.TotalDirectoryPage[workPtr], manager.website); //get names and links CS_DIRECTORY_PAGE: @@ -153,14 +147,7 @@ procedure TUpdateListThread.Execute; links := TStringList.Create; try if BROWSER_INVERT then - begin - if manager.ModuleId <> -1 then - with Modules.Module[manager.ModuleId] do - workPtr := TotalDirectoryPage[CurrentDirectoryIndex] - workPtr -1 - else - if checkStyle = CS_DIRECTORY_PAGE then - workPtr := manager.directoryCount - workPtr - 1 - end; + workPtr := manager.Module.TotalDirectoryPage[manager.Module.CurrentDirectoryIndex] - workPtr -1; Info.GetNameAndLink(names, links, manager.website, IntToStr(workPtr)); //if website has sorted list by latest added @@ -173,7 +160,7 @@ procedure TUpdateListThread.Execute; for i:=0 to links.Count-1 do begin if manager.mainDataProcess.AddData(names[i],links[i],'','','','','',0,0) then manager.tempDataProcess.AddData(names[i],links[i],'','','','','',0,0) - else if (manager.isFinishSearchingForNewManga=False) and manager.SortedList and (not BROWSER_INVERT) then + else if (manager.isFinishSearchingForNewManga=False) and manager.Module.SortedList and (not BROWSER_INVERT) then manager.isFinishSearchingForNewManga:=True; end; manager.mainDataProcess.Rollback; @@ -309,9 +296,6 @@ constructor TUpdateListManagerThread.Create; mainDataProcess := TDBDataProcess.Create; tempDataProcess := TDBDataProcess.Create; Threads := TFPList.Create; - SortedList := False; - NoMangaInfo := False; - ModuleId := -1; FThreadEndNormally:=False; FThreadAborted:=False; FIsPreListAvailable:=False; @@ -393,8 +377,9 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end; var - mt, i, plimit: Integer; + mt, plimit: Integer; s: String; + t: TUpdateListThread; begin try FCurrentGetInfoLimit := limit; @@ -411,8 +396,8 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end else begin - if Modules.MaxConnectionLimit[ModuleId] > 0 then - numberOfThreads := Modules.MaxConnectionLimit[ModuleId] + if Module.MaxConnectionLimit > 0 then + numberOfThreads := Module.MaxConnectionLimit else numberOfThreads := OptionMaxThreads; if numberOfThreads > OptionMaxThreads then @@ -430,8 +415,8 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; Exit; end; - if Modules.MaxConnectionLimit[ModuleId] > 0 then - while (not Terminated) and (Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads) do + if Module.MaxConnectionLimit > 0 then + while (not Terminated) and (Module.ActiveConnectionCount >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE) else while (not Terminated) and (Threads.Count >= numberOfThreads) do @@ -442,17 +427,18 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; begin EnterCriticalsection(CS_Threads); try - if Modules.ActiveConnectionCount[ModuleId] >= numberOfThreads then Exit; - Modules.IncActiveConnectionCount(ModuleId); - i:=Threads.Add(TUpdateListThread.Create); + if Module.ActiveConnectionCount >= numberOfThreads then Exit; + Module.IncActiveConnectionCount; + t := TUpdateListThread.Create; + Threads.Add(t); if cs=CS_INFO then begin - TUpdateListThread(Threads[i]).title:=tempDataProcess.Value[workPtr,DATA_PARAM_TITLE]; - TUpdateListThread(Threads[i]).link:=tempDataProcess.Value[workPtr,DATA_PARAM_LINK]; + t.title:=tempDataProcess.Value[workPtr,DATA_PARAM_TITLE]; + t.link:=tempDataProcess.Value[workPtr,DATA_PARAM_LINK]; end; - TUpdateListThread(Threads[i]).checkStyle:=cs; - TUpdateListThread(Threads[i]).manager:=Self; - TUpdateListThread(Threads[i]).workPtr:=Self.workPtr; - TUpdateListThread(Threads[i]).Start; + t.checkStyle:=cs; + t.manager:=Self; + t.workPtr:=Self.workPtr; + t.Start; Inc(workPtr); s := RS_UpdatingList + Format(' [%d/%d] %s | [T:%d] [%d/%d]', [websitePtr, websites.Count, website, Threads.Count, workPtr, FCurrentGetInfoLimit]); @@ -468,11 +454,9 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end; CS_DIRECTORY_PAGE: begin - s += ' | ' + RS_LookingForNewTitle; - if ModuleId <> -1 then - with Modules.Module[ModuleId] do - s += Format(' %d/%d', [CurrentDirectoryIndex + 1, TotalDirectory]); - s += '...'; + s += ' | ' + RS_LookingForNewTitle + + Format(' %d/%d', [Module.CurrentDirectoryIndex + 1, Module.TotalDirectory]) + + '...'; end; CS_INFO: s := Format('%s | %s "%s"', [s, RS_GettingInfo, tempDataProcess.Value[workPtr-1,DATA_PARAM_TITLE]]); @@ -545,141 +529,129 @@ procedure TUpdateListManagerThread.Execute; begin FThreadAborted:=True; website := websites.Strings[websitePtr]; - ModuleId := Modules.LocateModule(website); - SortedList := SitesWithSortedList(website); - NoMangaInfo := SitesWithoutInformation(website); - Inc(websitePtr); - - cloghead:=Self.ClassName+', '+website+': '; - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; - Synchronize(MainThreadShowGetting); - - twebsite:='__'+website; - twebsitetemp:=twebsite+'_templist'; - try - DeleteDBDataProcess(twebsite); - DeleteDBDataProcess(twebsitetemp); - if (dataProcess.Website = website) and - (dataProcess.Connected) then - dataProcess.Backup(twebsite) - else - begin - if dataProcess.WebsiteLoaded(website) then - Synchronize(MainThreadRemoveFilter); - CopyDBDataProcess(website, twebsite); - end; - - if not mainDataProcess.Connect(twebsite) then - mainDataProcess.CreateDatabase(twebsite); - tempDataProcess.CreateDatabase(twebsitetemp); - - // get directory page count - directoryCount := 0; - workPtr := 0; - if ModuleId <> -1 then begin - Modules.BeforeUpdateList(ModuleId); - GetInfo(Modules[ModuleId].TotalDirectory, CS_DIRECTORY_COUNT); - end - else - GetInfo(1, CS_DIRECTORY_COUNT); - - if Terminated then begin - if ModuleId <> -1 then - Modules.AfterUpdateList(ModuleId); - Break; - end; + if Modules.ModuleAvailable(website, Module) then + begin + Inc(websitePtr); - mainDataProcess.OpenTable('',True); - FIsPreListAvailable:=mainDataProcess.RecordCount>0; - mainDataProcess.CloseTable; + cloghead:=Self.ClassName+', '+website+': '; + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_Preparing + '...'; + Synchronize(MainThreadShowGetting); - // get names and links - workPtr := 0; - isFinishSearchingForNewManga := False; - if ModuleId <> -1 then - begin - with Modules.Module[ModuleId] do + twebsite:='__'+website; + twebsitetemp:=twebsite+'_templist'; + try + DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); + if (dataProcess.Website = website) and + (dataProcess.Connected) then + dataProcess.Backup(twebsite) + else begin - j := Low(TotalDirectoryPage); - while j <= High(TotalDirectoryPage) do - begin - workPtr := 0; - isFinishSearchingForNewManga := False; - CurrentDirectoryIndex := j; - GetInfo(TotalDirectoryPage[j], CS_DIRECTORY_PAGE); - Inc(j); - if Terminated then Break; - end; + if dataProcess.WebsiteLoaded(website) then + Synchronize(MainThreadRemoveFilter); + CopyDBDataProcess(website, twebsite); end; - end - else - GetInfo(directoryCount, CS_DIRECTORY_PAGE); - if ModuleId <> -1 then - Modules.BeforeUpdateList(ModuleId); - if Terminated then - if not (OptionUpdateListNoMangaInfo and not(SortedList)) then + if not mainDataProcess.Connect(twebsite) then + mainDataProcess.CreateDatabase(twebsite); + tempDataProcess.CreateDatabase(twebsitetemp); + + // get directory page count + directoryCount := 0; + workPtr := 0; + Modules.AfterUpdateList(Module.ID); + Modules.BeforeUpdateList(Module.ID); + GetInfo(Module.TotalDirectory, CS_DIRECTORY_COUNT); + + if Terminated then + begin + Modules.AfterUpdateList(Module.ID); Break; + end; - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; - Synchronize(MainThreadShowGetting); + mainDataProcess.OpenTable('',True); + FIsPreListAvailable:=mainDataProcess.RecordCount>0; + mainDataProcess.CloseTable; - tempDataProcess.OpenTable('', True); - // get manga info - if tempDataProcess.RecordCount>0 then - begin + // get names and links workPtr := 0; - FCommitCount := 0; - if NoMangaInfo or - OptionUpdateListNoMangaInfo then + isFinishSearchingForNewManga := False; + j := Low(Module.TotalDirectoryPage); + while j <= High(Module.TotalDirectoryPage) do begin - Inc(workPtr); - for k:=0 to tempDataProcess.RecordCount-1 do - begin - mainDataProcess.AddData( - tempDataProcess.Value[k,DATA_PARAM_TITLE], - tempDataProcess.Value[k,DATA_PARAM_LINK], - '', - '', - '', - '', - '', - 0, - Now - ); - CheckCommit(5000); - end; - end - else - GetInfo(tempDataProcess.RecordCount, CS_INFO); - mainDataProcess.Commit; + workPtr := 0; + isFinishSearchingForNewManga := False; + Module.CurrentDirectoryIndex := j; + GetInfo(Module.TotalDirectoryPage[j], CS_DIRECTORY_PAGE); + Inc(j); + if Terminated then Break; + end; + + Modules.BeforeUpdateList(Module.ID); + if Terminated then + if not (OptionUpdateListNoMangaInfo and not(Module.SortedList)) then + Break; + + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_IndexingNewTitle + '...'; + Synchronize(MainThreadShowGetting); - if (workPtr > 0) and (not (Terminated and SortedList)) then + tempDataProcess.OpenTable('', True); + // get manga info + if tempDataProcess.RecordCount>0 then begin - FStatus := RS_UpdatingList + Format(' [%d/%d] %s', - [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; - Synchronize(MainThreadShowGetting); - mainDataProcess.Sort; - mainDataProcess.Close; - Synchronize(RefreshList); + workPtr := 0; + FCommitCount := 0; + if not Module.InformationAvailable or + OptionUpdateListNoMangaInfo then + begin + Inc(workPtr); + for k:=0 to tempDataProcess.RecordCount-1 do + begin + mainDataProcess.AddData( + tempDataProcess.Value[k,DATA_PARAM_TITLE], + tempDataProcess.Value[k,DATA_PARAM_LINK], + '', + '', + '', + '', + '', + 0, + Now + ); + CheckCommit(5000); + end; + end + else + GetInfo(tempDataProcess.RecordCount, CS_INFO); + mainDataProcess.Commit; + + if (workPtr > 0) and (not (Terminated and Module.SortedList)) then + begin + FStatus := RS_UpdatingList + Format(' [%d/%d] %s', + [websitePtr, websites.Count, website]) + ' | ' + RS_SavingData + '...'; + Synchronize(MainThreadShowGetting); + mainDataProcess.Sort; + mainDataProcess.Close; + Synchronize(RefreshList); + end; end; + except + on E: Exception do + Logger.SendException(cloghead + 'error occured!', E); end; - except - on E: Exception do - Logger.SendException(cloghead + 'error occured!', E); - end; - tempDataProcess.Close; - mainDataProcess.Close; - DeleteDBDataProcess(twebsite); - DeleteDBDataProcess(twebsitetemp); + tempDataProcess.Close; + mainDataProcess.Close; + DeleteDBDataProcess(twebsite); + DeleteDBDataProcess(twebsitetemp); - if Terminated then - Break; - websites[websitePtr - 1] := UTF8Encode(#$2714) + websites[websitePtr - 1]; - FThreadAborted:=False; + if Terminated then + Break; + websites[websitePtr - 1] := UTF8Encode(#$2714) + websites[websitePtr - 1]; + FThreadAborted:=False; + end; end; except on E: Exception do From 036a16fc30fde0341307481e4b834ca69dcf237e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 10:32:18 +0800 Subject: [PATCH 2286/2794] added NHentai --- lua/modules/NHentai.lua | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 lua/modules/NHentai.lua diff --git a/lua/modules/NHentai.lua b/lua/modules/NHentai.lua new file mode 100644 index 000000000..fb0312aa6 --- /dev/null +++ b/lua/modules/NHentai.lua @@ -0,0 +1,56 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=x.xpathstring('//*[@id="cover"]//img/@data-src') + mangainfo.artists=x.xpathstringall('//*[@id="tags"]//a[contains(@href,"/artist/")]/text()') + mangainfo.genres=x.xpathstringall('//*[@id="tags"]//a/text()') + mangainfo.chapterlinks.add(url) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_error + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + TXQuery.Create(http.Document).xpathstringall('//*[@class="thumb-container"]//img/@data-src/replace(.,"//t\\.(.+\\d+)t\\.","//i.$1.")',task.pagelinks) + return true + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.get(module.rooturl) then + page=tonumber(TXQuery.Create(http.document).xpathstring('//a[@class="last"]/@href/substring-after(.,"=")')) + return no_error + else + return net_error + end +end + +function getnameandlink() + if http.get(module.rooturl..'/?page='..IncStr(url)) then + TXQuery.Create(http.document).xpathhrefall('//*[@id="content"]/div/div[@class="gallery"]/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='H-Sites' + m.website='NHentai' + m.rooturl='https://nhentai.net' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + m.sortedlist=true +end From 72c88970231af7704c27a21cbb37deae3a59793f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 11:00:06 +0800 Subject: [PATCH 2287/2794] set multilog threadsafe --- baseunits/lua/LuaBase.pas | 18 ++---------------- mangadownloader/md.lpr | 1 + 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 3ac60c337..6d89d545f 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -24,21 +24,13 @@ implementation uses LuaClass, luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog; -var - printcs: TRTLCriticalSection; - function luabase_print(L: Plua_State): Integer; cdecl; var i: Integer; begin Result := 0; - EnterCriticalsection(printcs); - try - for i := 1 to lua_gettop(L) do - Logger.Send(lua_tostring(L, i)); - finally - LeaveCriticalsection(printcs); - end; + for i := 1 to lua_gettop(L) do + Logger.Send(lua_tostring(L, i)); end; procedure LuaBaseRegister(L: Plua_State); @@ -148,10 +140,4 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh Result := lua_load(L, @_luareader, AStream, AName, 'b'); end; -initialization - InitCriticalSection(printcs); - -finalization - DoneCriticalsection(printcs); - end. diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index c59b4f4d6..39f83dae9 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -81,6 +81,7 @@ if AllowedToRun then begin + Logger.ThreadSafe := True; {$IFDEF DEBUGLEAKS} trcfile := FMD_DIRECTORY + FMD_EXENAME + '.trc'; if FileExistsUTF8(trcfile) then From 08955665887bbaa7d2e0e73714f95bda8a818b38 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 11:08:05 +0800 Subject: [PATCH 2288/2794] fix main project order --- mangadownloader/md.lpr | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/mangadownloader/md.lpr b/mangadownloader/md.lpr index 39f83dae9..e7f1cb7ee 100644 --- a/mangadownloader/md.lpr +++ b/mangadownloader/md.lpr @@ -36,33 +36,6 @@ {$R *.res} begin - {$ifdef windows} - // set environment variables - evpathlen:=windows.GetEnvironmentVariable('PATH',nil,0); - setlength(evpath,evpathlen-1); - windows.GetEnvironmentVariable('PATH',pchar(evpath),evpathlen); - evpath:=FMD_DIRECTORY+';'+evpath; - windows.SetEnvironmentVariable('PATH',pchar(evpath)); - {$endif} - - for i := 1 to ParamCount do - begin - p := AnsiLowerCase(ParamStr(i)); - if p = '--lua-dofile' then - LuaWebsiteModules.AlwaysLoadLuaFromFile := True; - end; - - Application.Scaled := True; - with TIniFile.Create(CONFIG_FILE) do - try - CheckInstance := ReadBool('general', 'OneInstanceOnly', True); - EnableLogging := ReadBool('logger', 'Enabled', False); - if EnableLogging then - LogFileName := ExpandFileNameUTF8(ReadString('logger', 'LogFileName', DEFAULT_LOG_FILE), FMD_DIRECTORY); - finally - Free; - end; - if CheckInstance then begin with TSimpleIPCClient.Create(nil) do @@ -81,7 +54,35 @@ if AllowedToRun then begin + {$ifdef windows} + // set environment variables + evpathlen:=windows.GetEnvironmentVariable('PATH',nil,0); + setlength(evpath,evpathlen-1); + windows.GetEnvironmentVariable('PATH',pchar(evpath),evpathlen); + evpath:=FMD_DIRECTORY+';'+evpath; + windows.SetEnvironmentVariable('PATH',pchar(evpath)); + {$endif} + + for i := 1 to ParamCount do + begin + p := AnsiLowerCase(ParamStr(i)); + if p = '--lua-dofile' then + LuaWebsiteModules.AlwaysLoadLuaFromFile := True; + end; + + Application.Scaled := True; + with TIniFile.Create(CONFIG_FILE) do + try + CheckInstance := ReadBool('general', 'OneInstanceOnly', True); + EnableLogging := ReadBool('logger', 'Enabled', False); + if EnableLogging then + LogFileName := ExpandFileNameUTF8(ReadString('logger', 'LogFileName', DEFAULT_LOG_FILE), FMD_DIRECTORY); + finally + Free; + end; + Logger.ThreadSafe := True; + {$IFDEF DEBUGLEAKS} trcfile := FMD_DIRECTORY + FMD_EXENAME + '.trc'; if FileExistsUTF8(trcfile) then From 19f27ee38c7735efcbfa3b780ad529e2340ea953 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 11:11:01 +0800 Subject: [PATCH 2289/2794] Bump version 0.9.144.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index a5f12f9c8..9f4ec5a39 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.144.0 (17-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.143.0...0.9.144.0 + 0.9.143.0 (17-02-2018) [*] Update Indonesian localization [*] Various changes and bug fixes diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b0ccb200d..be3527e61 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="143"/> + <RevisionNr Value="144"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 23c6472f8..9c944f05a 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.143.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.143.0/fmd_0.9.143.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.143.0/fmd_0.9.143.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.143.0/fmd_0.9.143.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.143.0/fmd_0.9.143.0_Win64.7z +VERSION=0.9.144.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.144.0/fmd_0.9.144.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.144.0/fmd_0.9.144.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.144.0/fmd_0.9.144.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.144.0/fmd_0.9.144.0_Win64.7z From 33d792233171f23d1ab3ed535ee163c3a526d32d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 13:07:27 +0800 Subject: [PATCH 2290/2794] added mangatown #993 --- lua/modules/MangaTown.lua | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 lua/modules/MangaTown.lua diff --git a/lua/modules/MangaTown.lua b/lua/modules/MangaTown.lua new file mode 100644 index 000000000..b6b41513e --- /dev/null +++ b/lua/modules/MangaTown.lua @@ -0,0 +1,76 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=x.xpathstring('//*[@class="detail_info clearfix"]/img/@src') + mangainfo.authors=x.xpathstring('//*[@class="detail_info clearfix"]/ul/li[starts-with(.,"Author(s):")]/substring-after(.,":")') + mangainfo.artists=x.xpathstring('//*[@class="detail_info clearfix"]/ul/li[starts-with(.,"Artist(s):")]/substring-after(.,":")') + mangainfo.genres=x.xpathstring('//*[@class="detail_info clearfix"]/ul/li[starts-with(.,"Genre(s):")]/substring-after(.,":")') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//*[@class="detail_info clearfix"]/ul/li[starts-with(.,"Status(s):")]')) + mangainfo.summary=x.xpathstring('//*[@class="detail_info clearfix"]/ul/li/span[@id="show"]/normalize-space(text())') + v=x.xpath('//ul[@class="chapter_list"]/li') + for i=1,v.count do + v2=v.get(i) + mangainfo.chapterlinks.add(x.xpathstring('a/@href',v2)) + mangainfo.chapternames.add(x.xpathstring('string-join((a/text(),span[not(@class)])," ")',v2)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_error + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + task.pagenumber=TXQuery.Create(http.Document).xpathcount('(//select[not(@id)])[1]/option[not(contains(@value,"featured.html"))]') + return true + else + return false + end + return true +end + +function getimageurl() + local s=url + if workid>0 then + s=AppendURLDelim(s)..(workid+1)..'.html' + end + if http.get(MaybeFillHost(module.rooturl,s)) then + task.pagelinks[workid]=TXQuery.create(http.document).xpathstring('//*[@id="viewer"]//img[@alt]/@src') + return true + end + return false +end + +function getdirectorypagenumber() + if http.get(module.rooturl..'/directory/?name.az') then + page=TXQuery.Create(http.document).xpathcount('(//select)[last()]/option') + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl..'/directory/'..IncStr(url)..'.htm?name.az') then + TXQuery.Create(http.document).xpathhreftitleall('//ul[@class="manga_pic_list"]/li/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='English' + m.website='MangaTown' + m.rooturl='http://www.mangatown.com' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetimageurl='getimageurl' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' +end From 1a127244edebd1d6ee14eeb8ec6f4bce8b4a81e2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 13:10:21 +0800 Subject: [PATCH 2291/2794] typo return value --- lua/modules/CentralDeMangas.lua | 2 +- lua/modules/DynastyScans.lua | 2 +- lua/modules/EGScans.lua | 4 ++-- lua/modules/FoOlSlide.lua | 6 +++--- lua/modules/HentaiHere.lua | 2 +- lua/modules/Imgur.lua | 2 +- lua/modules/LHTranslation.lua | 4 ++-- lua/modules/MangaOku.lua | 2 +- lua/modules/MangaSh.lua | 2 +- lua/modules/MangaStream.lua | 2 +- lua/modules/MangaTown.lua | 2 +- lua/modules/ManhwaCo.lua | 2 +- lua/modules/NHentai.lua | 4 ++-- lua/modules/NeuManga.lua | 2 +- lua/modules/Pururin.lua | 2 +- lua/modules/VnSharing.lua | 2 +- 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lua/modules/CentralDeMangas.lua b/lua/modules/CentralDeMangas.lua index 90d337858..d39346740 100644 --- a/lua/modules/CentralDeMangas.lua +++ b/lua/modules/CentralDeMangas.lua @@ -13,7 +13,7 @@ function GetInfo() InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/DynastyScans.lua b/lua/modules/DynastyScans.lua index 7c04b39b5..3c0e623ac 100644 --- a/lua/modules/DynastyScans.lua +++ b/lua/modules/DynastyScans.lua @@ -11,7 +11,7 @@ function getinfo() x.xpathhrefall('//dl[@class="chapter-list"]/dd/a',mangainfo.chapterlinks,mangainfo.chapternames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/EGScans.lua b/lua/modules/EGScans.lua index 566ffb10f..5a5be3532 100644 --- a/lua/modules/EGScans.lua +++ b/lua/modules/EGScans.lua @@ -1,6 +1,6 @@ function getinfo() local lurl = MaybeFillHost(module.rooturl, url) - local result = net_error + local result = net_problem if http.get(lurl) then local x = TXQuery.Create(http.document) if mangainfo.title == '' then @@ -45,7 +45,7 @@ function getdirectorypagenumber() end function getnameandlink() - local result = net_error + local result = net_problem if http.get(module.rooturl) then local x = TXQuery.create(http.document) local v = x.xpath('//select[@name="manga"]/option[@value!="0"]') diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index d6619906b..0de6b59df 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -53,7 +53,7 @@ end function getinfo() local lurl = MaybeFillHost(module.rooturl, url) - local result = net_error + local result = net_problem if getWithCookie(lurl) then x = TXQuery.Create(http.document) mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail"]/img/@src') @@ -135,7 +135,7 @@ function getimageurl() end function getdirectorypagenumber() - local result = net_error + local result = net_problem page = 1 if getWithCookie(module.rooturl .. getdirurl(module.website)) then result = no_error @@ -152,7 +152,7 @@ function getdirectorypagenumber() end function getnameandlink() - local result = net_error + local result = net_problem local s = module.rooturl .. getdirurl(module.website) if url ~= '0' then s = s .. (tonumber(url) + 1) .. '/' diff --git a/lua/modules/HentaiHere.lua b/lua/modules/HentaiHere.lua index 0814fb6de..2a9a022ec 100644 --- a/lua/modules/HentaiHere.lua +++ b/lua/modules/HentaiHere.lua @@ -16,7 +16,7 @@ function GetInfo() end return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/Imgur.lua b/lua/modules/Imgur.lua index b7e287ee5..bc139dcb8 100644 --- a/lua/modules/Imgur.lua +++ b/lua/modules/Imgur.lua @@ -7,7 +7,7 @@ function getinfo() mangainfo.chapternames.add(mangainfo.title) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index debd732f4..4ad41b7db 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -11,7 +11,7 @@ function GetInfo() InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) return no_error else - return net_error + return net_problem end end @@ -38,7 +38,7 @@ function GetNameAndLink() end return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/MangaOku.lua b/lua/modules/MangaOku.lua index fcb7a92eb..3e43c02ac 100644 --- a/lua/modules/MangaOku.lua +++ b/lua/modules/MangaOku.lua @@ -13,7 +13,7 @@ function getinfo() InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/MangaSh.lua b/lua/modules/MangaSh.lua index f6ebfa473..fe2e940e9 100644 --- a/lua/modules/MangaSh.lua +++ b/lua/modules/MangaSh.lua @@ -45,7 +45,7 @@ function getinfo() return net_problem end else - return net_error + return net_problem end end diff --git a/lua/modules/MangaStream.lua b/lua/modules/MangaStream.lua index 4bbf91940..10f636be4 100644 --- a/lua/modules/MangaStream.lua +++ b/lua/modules/MangaStream.lua @@ -7,7 +7,7 @@ function GetInfo() InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/MangaTown.lua b/lua/modules/MangaTown.lua index b6b41513e..052704796 100644 --- a/lua/modules/MangaTown.lua +++ b/lua/modules/MangaTown.lua @@ -18,7 +18,7 @@ function getinfo() InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/ManhwaCo.lua b/lua/modules/ManhwaCo.lua index 79ee0abde..6e97a0418 100644 --- a/lua/modules/ManhwaCo.lua +++ b/lua/modules/ManhwaCo.lua @@ -15,7 +15,7 @@ function GetInfo() InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/NHentai.lua b/lua/modules/NHentai.lua index fb0312aa6..0dd8e97f2 100644 --- a/lua/modules/NHentai.lua +++ b/lua/modules/NHentai.lua @@ -10,7 +10,7 @@ function getinfo() mangainfo.chapternames.add(mangainfo.title) return no_error else - return net_error + return net_problem end end @@ -29,7 +29,7 @@ function getdirectorypagenumber() page=tonumber(TXQuery.Create(http.document).xpathstring('//a[@class="last"]/@href/substring-after(.,"=")')) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/NeuManga.lua b/lua/modules/NeuManga.lua index 4ad4ae6f9..bf2b94c5d 100644 --- a/lua/modules/NeuManga.lua +++ b/lua/modules/NeuManga.lua @@ -18,7 +18,7 @@ function GetInfo() InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/Pururin.lua b/lua/modules/Pururin.lua index 17a95bde0..a217b0ca7 100644 --- a/lua/modules/Pururin.lua +++ b/lua/modules/Pururin.lua @@ -10,7 +10,7 @@ function GetInfo() mangainfo.chapternames.add(mangainfo.title) return no_error else - return net_error + return net_problem end end diff --git a/lua/modules/VnSharing.lua b/lua/modules/VnSharing.lua index 4f1089ce3..97da35481 100644 --- a/lua/modules/VnSharing.lua +++ b/lua/modules/VnSharing.lua @@ -13,7 +13,7 @@ InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error else - return net_error + return net_problem end end From b922a41a3de47a2db18e18ffe4262754ebf74a18 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 13:26:41 +0800 Subject: [PATCH 2292/2794] update Indonesian localizarion --- mangadownloader/languages/fmd.id_ID.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 285993424..a1bea36a2 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -430,7 +430,7 @@ msgid "" msgstr "" "WebP\n" "PNG\n" -"PNG\n" +"JPEG\n" #: frmmain.rs_webppnglevel msgid "" From f85bc4b056a623a9bf84dc7a4c7da9a46d0dd193 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 13:27:03 +0800 Subject: [PATCH 2293/2794] fixed #998 --- mangadownloader/forms/frmMain.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2b73ef19b..c0b715fa4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5031,8 +5031,8 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; WriteString('saveto', 'FilenameCustomRename', edOptionFilenameCustomRename.Text); WriteInteger('saveto', 'ConvertWebP', cbWebPSaveAs.ItemIndex); - WriteInteger('saveto', 'WebPPNGLevel', cbPNGCompressionLevel.ItemIndex); - WriteInteger('saveto', 'WebPJpegQuality', seJPEGQuality.Value); + WriteInteger('saveto', 'PNGCompressionLevel', cbPNGCompressionLevel.ItemIndex); + WriteInteger('saveto', 'JPEGQuality', seJPEGQuality.Value); // update WriteBool('update', 'AutoCheckLatestVersion', cbOptionAutoCheckLatestVersion.Checked); From f8bcc5c38db014015caa077b516fe620a4a62618 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 13:35:41 +0800 Subject: [PATCH 2294/2794] fixed #1000 --- baseunits/uUpdateThread.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 0a8bb2a12..5c0a1808c 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -338,7 +338,7 @@ procedure TUpdateListManagerThread.RefreshList; try with MainForm do begin - if cbSelectManga.Items[cbSelectManga.ItemIndex] = website then + if cbSelectManga.Text = website then begin vtMangaList.Clear; if dataProcess = nil then From b51656145b05dfefa432f23cc70fb706f825e4c6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 13:38:43 +0800 Subject: [PATCH 2295/2794] Bump version 0.9.145.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9f4ec5a39..14de464db 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.145.0 (17-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.144.0...0.9.145.0 + 0.9.144.0 (17-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.143.0...0.9.144.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index be3527e61..1e737fa2d 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="144"/> + <RevisionNr Value="145"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 9c944f05a..11fdf594d 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.144.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.144.0/fmd_0.9.144.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.144.0/fmd_0.9.144.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.144.0/fmd_0.9.144.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.144.0/fmd_0.9.144.0_Win64.7z +VERSION=0.9.145.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.145.0/fmd_0.9.145.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.145.0/fmd_0.9.145.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.145.0/fmd_0.9.145.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.145.0/fmd_0.9.145.0_Win64.7z From 3e1f770d2439327b4b7ac7f05d39dfdcc4c4aae3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 20:43:54 +0800 Subject: [PATCH 2296/2794] fix png save as jpeg option (fixed #1003) --- baseunits/FMDOptions.pas | 1 + baseunits/uBaseUnit.pas | 3 ++- mangadownloader/forms/frmMain.pas | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 8bc5737f7..2fc832b57 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -139,6 +139,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) OptionPDFQuality: Cardinal = 95; + OptionPNGSaveAsJPEG: Boolean = False; OptionWebPSaveAs: Integer = 1; OptionPNGCompressionLevel: Integer = 1; OptionJPEGQuality: Integer = 80; diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 8086ac630..c05972e48 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -3063,7 +3063,8 @@ function SaveImageStreamToFile(Stream: TMemoryStream; Path, FileName: String; Ag f := GetImageStreamExt(Stream); if f = 'png' then begin - if PNGToJPEGStream(Stream, OptionJPEGQuality) then f := 'jpg' + if OptionPNGSaveAsJPEG then + if PNGToJPEGStream(Stream, OptionJPEGQuality) then f := 'jpg' end else if f = 'webp' then diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index c0b715fa4..51a6ccc6b 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4916,6 +4916,7 @@ procedure TMainForm.LoadOptions; edOptionFilenameCustomRename.Text := ReadString('saveto', 'FilenameCustomRename', DEFAULT_FILENAME_CUSTOMRENAME); if Trim(edOptionFilenameCustomRename.Text) = '' then edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; + ckPNGSaveAsJPEG.Checked := ReadBool('saveto', 'PNGSaveAsJPEG', OptionPNGSaveAsJPEG); cbWebPSaveAs.ItemIndex := ReadInteger('saveto', 'ConvertWebP', OptionWebPSaveAs); cbPNGCompressionLevel.ItemIndex := ReadInteger('saveto', 'PNGCompressionLevel', OptionPNGCompressionLevel); seJPEGQuality.Value := ReadInteger('saveto', 'JPEGQuality', OptionJPEGQuality); @@ -5030,6 +5031,7 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); if Trim(edOptionFilenameCustomRename.Text) = '' then edOptionFilenameCustomRename.Text := DEFAULT_FILENAME_CUSTOMRENAME; WriteString('saveto', 'FilenameCustomRename', edOptionFilenameCustomRename.Text); + WriteBool('saveto', 'PNGSaveAsJPEG', ckPNGSaveAsJPEG.Checked); WriteInteger('saveto', 'ConvertWebP', cbWebPSaveAs.ItemIndex); WriteInteger('saveto', 'PNGCompressionLevel', cbPNGCompressionLevel.ItemIndex); WriteInteger('saveto', 'JPEGQuality', seJPEGQuality.Value); @@ -5176,6 +5178,7 @@ procedure TMainForm.ApplyOptions; OptionConvertDigitVolumeLength := seOptionDigitVolume.Value; OptionConvertDigitChapter := cbOptionDigitChapter.Checked; OptionConvertDigitChapterLength := seOptionDigitChapter.Value; + OptionPNGSaveAsJPEG := ckPNGSaveAsJPEG.Checked; OptionWebPSaveAs := cbWebPSaveAs.ItemIndex; OptionPNGCompressionLevel := cbPNGCompressionLevel.ItemIndex; OptionJPEGQuality := seJPEGQuality.Value; From e4f6097b5eb78858495d582438b316397d375e81 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 17 Feb 2018 21:02:49 +0800 Subject: [PATCH 2297/2794] updater, make it infinite retry by user (closed #1005) --- updaterslim/updater.lpr | 132 +++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 57 deletions(-) diff --git a/updaterslim/updater.lpr b/updaterslim/updater.lpr index 8ae6583cb..64f51388a 100644 --- a/updaterslim/updater.lpr +++ b/updaterslim/updater.lpr @@ -14,6 +14,31 @@ {$R *.res} +procedure cleanupsuccess; +begin + DeleteFile(oexefile); + DeleteFile(ozipexefile); + DeleteFile(updatepackagefile); +end; + +procedure cleanupfailed; +begin + if FileExists(oexefile) then + begin + if FileExists(exefile) then + DeleteFile(oexefile) + else + RenameFile(oexefile,exefile); + end; + if FileExists(ozipexefile) then + begin + if FileExists(zipexefile) then + DeleteFile(ozipexefile) + else + RenameFile(ozipexefile,zipexefile); + end; +end; + begin if ParamCount<4 then begin @@ -28,70 +53,63 @@ if not (FileExists(zipexefile) or FileExists(updatepackagefile)) then Exit; oexefile:=ExtractFilePath(exefile)+'old_'+ExtractFileName(exefile); if FileExists(oexefile) then DeleteFile(oexefile); - counter:=0; - {$ifdef windows} - windows.CopyFile(pchar(exefile),pchar(oexefile),false); - {$else} - CopyFile(exefile,oexefile); - {$endif} - while FileExists(exefile) do begin - if DeleteFile(exefile) then break; - Inc(counter); - writeln('Waiting to close ',counter,'/',10,' ',exefile); - Sleep(1000); - if counter=10 then break; - end; - if not FileExists(exefile) then + while true do begin - with TProcess.Create(nil) do try - ozipexefile:=ExtractFilePath(zipexefile)+'old_'+ExtractFileName(zipexefile); - if FileExists(ozipexefile) then - DeleteFile(ozipexefile); - RenameFile(zipexefile,ozipexefile); - Executable:=ozipexefile; - CurrentDirectory:=maindir; - Parameters.Add('x'); - Parameters.Add(updatepackagefile); - Parameters.Add('-o'+AnsiQuotedStr(maindir,'"')); - Parameters.Add('-aoa'); - Options:=Options+[poWaitOnExit]; - Execute; - if ExitStatus=0 then - begin - DeleteFile(oexefile); - DeleteFile(ozipexefile); - DeleteFile(updatepackagefile); - Executable:=exefile; - Parameters.Clear; - Options:=Options-[poWaitOnExit]; + counter:=0; + {$ifdef windows} + windows.CopyFile(pchar(exefile),pchar(oexefile),false); + {$else} + CopyFile(exefile,oexefile); + {$endif} + while FileExists(exefile) do begin + if DeleteFile(exefile) then break; + Inc(counter); + writeln('Waiting to close ',counter,'/',10,' ',exefile); + Sleep(1000); + if counter=10 then break; + end; + if not FileExists(exefile) then + begin + with TProcess.Create(nil) do try + ozipexefile:=ExtractFilePath(zipexefile)+'old_'+ExtractFileName(zipexefile); + if FileExists(ozipexefile) then + DeleteFile(ozipexefile); + RenameFile(zipexefile,ozipexefile); + Executable:=ozipexefile; + CurrentDirectory:=maindir; + Parameters.Add('x'); + Parameters.Add(updatepackagefile); + Parameters.Add('-o'+AnsiQuotedStr(maindir,'"')); + Parameters.Add('-aoa'); + Options:=Options+[poWaitOnExit]; Execute; - end - else - begin - readln; - if FileExists(oexefile) then + if ExitStatus=0 then begin - if FileExists(exefile) then - DeleteFile(oexefile) - else - RenameFile(oexefile,exefile); - end; - if FileExists(ozipexefile) then + cleanupsuccess; + Executable:=exefile; + Parameters.Clear; + Options:=Options-[poWaitOnExit]; + Execute; + Break; + end + else begin - if FileExists(zipexefile) then - DeleteFile(ozipexefile) - else - RenameFile(ozipexefile,zipexefile); + cleanupfailed; + writeln('Extract failed or can'' overwrite some file.'); + writeln('Press enter to retry.'); + readln; end; + finally + Free; end; - finally - Free; + end + else + begin + cleanupfailed; + writeln('Can''t delete file ',exefile); + writeln('Press enter to retry.'); + readln; end; - end - else - begin - writeln('Can''t delete file ',exefile); - readln; end; end. From 8cb55ec5c8c3337b4b2369f0127ef09c301200e0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 17 Feb 2018 19:12:34 +0300 Subject: [PATCH 2298/2794] added mangaku, #993 --- lua/modules/MangaKu.lua | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 lua/modules/MangaKu.lua diff --git a/lua/modules/MangaKu.lua b/lua/modules/MangaKu.lua new file mode 100644 index 000000000..a6ffde8b0 --- /dev/null +++ b/lua/modules/MangaKu.lua @@ -0,0 +1,64 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + + mangainfo.title=x.xpathstring('//title/text()') + :gsub('Baca', ''):gsub('Online Komik', ''):gsub('Komik -', ''):gsub('Komik', '') + :gsub('Manga -', ''):gsub('Manga', ''):gsub('Online -', ''):gsub('Terbaru', '') + :gsub('Bahasa Indonesia', ''):gsub('^%s*[�/]', '') + + mangainfo.coverlink=x.xpathstring('//a[@imageanchor]/img/@src') + mangainfo.authors=x.xpathstring('//*[contains(., "Author")]/following-sibling::text()'):gsub("^:", "") + mangainfo.artists=x.xpathstring('//*[contains(., "Artist")]/following-sibling::text()'):gsub("^:", "") + mangainfo.genres=x.xpathstring('//*[contains(., "Genre")]/following-sibling::text()'):gsub("^:", "") + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//*[contains(., "Episodes")]/following-sibling::text()')) + x.xpathhrefall('//div[contains(@style, "-moz-border-radius")]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="separator"]/a/img/@src', task.pagelinks) + if task.pagelinks.count == 0 then + if http.get(MaybeFillHost('http://mangaku.co',url)) then + x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="separator"]/a/img/@src', task.pagelinks) + return true + else + return false + end + else + return true + end + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl..'/daftar-komik-bahasa-indonesia/') then + TXQuery.Create(http.document).xpathhrefall('//a[@class="screenshot"]',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Indonesian' + m.website='MangaKu' + m.rooturl='http://mangaku.web.id' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end \ No newline at end of file From eff0d68f73fe5d6a49060b5a968d96cb2edbf606 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 17 Feb 2018 22:17:21 +0300 Subject: [PATCH 2299/2794] add XAnimeSeduccion [SP-SC] add JokerFansub [SP-SC] add PatyScans [SP-SC] --- lua/modules/FoOlSlide.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 0de6b59df..c96a5a670 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -15,7 +15,8 @@ function getWithCookie(lurl) ['DokiFansubs'] = true, ['RavensScans'] = true, ['YamiTenshiNoFansub'] = true, - ['S2Scans'] = true + ['S2Scans'] = true, + ['XAnimeSeduccion'] = true } if needCookie[module.website] and Pos(dirurl, lurl) then return http.post(lurl, 'adult=true') @@ -226,4 +227,7 @@ function Init() AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com', cat) AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com', cat) AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com', cat) + AddWebsiteModule('XAnimeSeduccion', 'http://xanime-seduccion.com', cat) + AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) + AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) end From b806565deb4822b24995cb886b2424a51b7e4ac8 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 08:35:35 +0800 Subject: [PATCH 2300/2794] Add animextremist --- lua/modules/AnimExtremist.lua | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 lua/modules/AnimExtremist.lua diff --git a/lua/modules/AnimExtremist.lua b/lua/modules/AnimExtremist.lua new file mode 100644 index 000000000..0fc2f99ac --- /dev/null +++ b/lua/modules/AnimExtremist.lua @@ -0,0 +1,56 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@id="LayerContenido"]/div[@id][1]') + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[@id="LayerContenido"]/div[@id][2]//tr[1]/td[2]//img/@src')) + mangainfo.genres=x.xpathstring('string-join(//div[@id="LayerContenido"]/div[@id][2]//tr[5]//a,", ")') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@id="LayerContenido"]/div[@id][2]//tr[6]/td[1]'),'En proceso','Completo') + mangainfo.summary=x.xpathstring('//div[@id="LayerContenido"]/div[@id][2]//tr[1]/td[1]') + x.xpathstringall('//div[@id="tomo"]//a/@href',mangainfo.chapterlinks) + x.xpathstringall('//div[@id="tomo"]//a/string-join((../b,.)," ")',mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url):gsub('%.html?$','-1%1')) then + task.pagenumber=TXQuery.Create(http.Document).xpathcount('//select[@id="nav-jump"]/option') + return true + else + return false + end + return true +end + +function getimageurl() + if http.get(MaybeFillHost(module.rooturl,url):gsub('%.html?$','-'..(workid+1)..'%1')) then + task.pagelinks[workid]=TXQuery.create(http.document).xpathstring('//img[@id="photo"]/@src') + return true + end + return false +end + +function getnameandlink() + if http.get(module.rooturl..'/mangas.htm?ord=todos') then + TXQuery.Create(http.document).xpathhrefall('//*[@id="manga"]/div/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Spanish' + m.website='AnimExtremist' + m.rooturl='http://www.animextremist.com' + m.lastupdated='February 18, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetimageurl='getimageurl' + m.ongetnameandlink='getnameandlink' +end From 8f6bee04b21c7ae3f0e9db4d8410dd910bdec6fe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 08:58:39 +0800 Subject: [PATCH 2301/2794] Bump version 0.9.146.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 14de464db..c53eb0d21 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.146.0 (18-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.145.0...0.9.146.0 + 0.9.145.0 (17-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.144.0...0.9.145.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 1e737fa2d..b87e99931 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="145"/> + <RevisionNr Value="146"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 11fdf594d..08d6c0801 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.145.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.145.0/fmd_0.9.145.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.145.0/fmd_0.9.145.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.145.0/fmd_0.9.145.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.145.0/fmd_0.9.145.0_Win64.7z +VERSION=0.9.146.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.146.0/fmd_0.9.146.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.146.0/fmd_0.9.146.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.146.0/fmd_0.9.146.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.146.0/fmd_0.9.146.0_Win64.7z From 9f6c8a785796bbd384a6a3dfbc8d755fcc631599 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 10:19:07 +0800 Subject: [PATCH 2302/2794] updater, cleanup messages --- updaterslim/updater.lpr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/updaterslim/updater.lpr b/updaterslim/updater.lpr index 64f51388a..4cbb63542 100644 --- a/updaterslim/updater.lpr +++ b/updaterslim/updater.lpr @@ -95,7 +95,7 @@ procedure cleanupfailed; else begin cleanupfailed; - writeln('Extract failed or can'' overwrite some file.'); + writeln; writeln('Press enter to retry.'); readln; end; @@ -106,6 +106,7 @@ procedure cleanupfailed; else begin cleanupfailed; + writeln; writeln('Can''t delete file ',exefile); writeln('Press enter to retry.'); readln; From 600ea5be6fe1531570931bde69283f6e25b3d2e4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 10:28:36 +0800 Subject: [PATCH 2303/2794] added XAnimeSeduccion, JokerFansub, PatyScans --- lua/modules/FoOlSlide.lua | 382 +++++++++++++++++++------------------- 1 file changed, 192 insertions(+), 190 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index c96a5a670..5bafd01eb 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -9,225 +9,227 @@ local dirurllector = '/lector/directory/' local dirurlfsdir = '/fs/directory/' function getWithCookie(lurl) - local needCookie = { - ['SeinagiAdultoFansub'] = true, - ['TripleSevenScan'] = true, - ['DokiFansubs'] = true, - ['RavensScans'] = true, - ['YamiTenshiNoFansub'] = true, - ['S2Scans'] = true, - ['XAnimeSeduccion'] = true - } - if needCookie[module.website] and Pos(dirurl, lurl) then - return http.post(lurl, 'adult=true') - else - return http.get(lurl) - end + local needCookie = { + ['SeinagiAdultoFansub'] = true, + ['TripleSevenScan'] = true, + ['DokiFansubs'] = true, + ['RavensScans'] = true, + ['YamiTenshiNoFansub'] = true, + ['S2Scans'] = true, + ['Pzykosis666HFansub'] = true, + ['SantosScan'] = true, + ['XAnimeSeduccion'] = true + } + if needCookie[module.website] and Pos(dirurl, lurl) then + return http.post(lurl, 'adult=true') + else + return http.get(lurl) + end end function getdirurl(website) - local dirs = { - ['GoManga'] = dirurlreader, - ['Jaiminisbox'] = dirurlreader, - ['TripleSevenScan'] = dirurlreader, - ['DokiFansubs'] = dirurlreader, - ['AtelierDuNoir'] = dirurlreader, - ['OneTimeScans'] = dirurlfoolslide, - ['DejameProbar'] = dirurlslide, - ['MenudoFansub'] = dirurlslide, - ['NeoProjectScan'] = dirurlslide, - ['SolitarioNoFansub'] = dirurlslide, - ['SantosScan'] = dirurlslideU, - ['Pzykosis666HFansub'] = dirurlonline, - ['SeinagiFansub'] = dirurlonline, - ['HelveticaScans'] = dirurlhelvetica, - ['RavensScans'] = dirurllector, - ['NoraNoFansub'] = dirurllector, - ['HotChocolateScans'] = dirurlfsdir - } - if dirs[website] ~= nil then - return dirs[website] - else - return dirurl - end + local dirs = { + ['GoManga'] = dirurlreader, + ['Jaiminisbox'] = dirurlreader, + ['TripleSevenScan'] = dirurlreader, + ['DokiFansubs'] = dirurlreader, + ['AtelierDuNoir'] = dirurlreader, + ['OneTimeScans'] = dirurlfoolslide, + ['DejameProbar'] = dirurlslide, + ['MenudoFansub'] = dirurlslide, + ['NeoProjectScan'] = dirurlslide, + ['SolitarioNoFansub'] = dirurlslide, + ['SantosScan'] = dirurlslideU, + ['Pzykosis666HFansub'] = dirurlonline, + ['SeinagiFansub'] = dirurlonline, + ['HelveticaScans'] = dirurlhelvetica, + ['RavensScans'] = dirurllector, + ['NoraNoFansub'] = dirurllector, + ['HotChocolateScans'] = dirurlfsdir + } + if dirs[website] ~= nil then + return dirs[website] + else + return dirurl + end end function getinfo() - local lurl = MaybeFillHost(module.rooturl, url) - local result = net_problem - if getWithCookie(lurl) then - x = TXQuery.Create(http.document) - mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail"]/img/@src') - if mangainfo.title == '' then - if module.website == 'AtelierDuNoir' then - mangainfo.title = x.xpathstring('//div[@class="section-headline"]//h3') - else - mangainfo.title = x.xpathstring('//h1[@class="title"]') - end - end - if Pos('emailprotected', mangainfo.title) > 0 then - mangainfo.title = Trim(SeparateLeft(x.xpathstring('//title'), '::')) - end - mangainfo.authors = string.gsub( - x.xpathstring('//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), - '^[%s:]*', '') - mangainfo.artists = string.gsub( - x.xpathstring('//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), - '^[%s:]*', '') - mangainfo.summary = string.gsub( - x.xpathstring('//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), - '^[%s:]*', '') - v = x.xpath('//div[@class="list"]//div[@class="title"]/a') - for i = 1, v.count do - v1 = v.get(i) - mangainfo.chapterlinks.add(v1.getattribute('href')) - if v1.getattribute('title') ~= '' then - mangainfo.chapternames.add(v1.getattribute('title')) - else - mangainfo.chapternames.add(v1.ToString) - end - end - InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) - result = no_error + local lurl = MaybeFillHost(module.rooturl, url) + local result = net_problem + if getWithCookie(lurl) then + x = TXQuery.Create(http.document) + mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail"]/img/@src') + if mangainfo.title == '' then + if module.website == 'AtelierDuNoir' then + mangainfo.title = x.xpathstring('//div[@class="section-headline"]//h3') + else + mangainfo.title = x.xpathstring('//h1[@class="title"]') + end + end + if Pos('emailprotected', mangainfo.title) > 0 then + mangainfo.title = Trim(SeparateLeft(x.xpathstring('//title'), '::')) end - return result + mangainfo.authors = string.gsub( + x.xpathstring('//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), + '^[%s:]*', '') + mangainfo.artists = string.gsub( + x.xpathstring('//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), + '^[%s:]*', '') + mangainfo.summary = string.gsub( + x.xpathstring('//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), + '^[%s:]*', '') + v = x.xpath('//div[@class="list"]//div[@class="title"]/a') + for i = 1, v.count do + v1 = v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + if v1.getattribute('title') ~= '' then + mangainfo.chapternames.add(v1.getattribute('title')) + else + mangainfo.chapternames.add(v1.ToString) + end + end + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + result = no_error + end + return result end function taskstart() - task.pagelinks.clear() - task.pagenumber = 0 - return true + task.pagelinks.clear() + task.pagenumber = 0 + return true end function getpagenumber() - local result = false - if getWithCookie(MaybeFillHost(module.rooturl, url)) then - x = TXQuery.create(http.document) - task.pagenumber = x.xpath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').count - s = x.xpathstring('//script[contains(.,"var pages")]') - if s ~= '' then - s = GetBetween('var pages = ', ';', s) - if Pos('atob("', s) > 0 then - s = GetBetween('atob("', '")', s) - s = DecodeBase64(s) - end - x.parsehtml(s) - v = x.xpath('json(*)()("url")') - for i = 1, v.count do - task.pagelinks.add(v.get(i).ToString) - end - end - result = true + local result = false + if getWithCookie(MaybeFillHost(module.rooturl, url)) then + x = TXQuery.create(http.document) + task.pagenumber = x.xpath('//div[@class="topbar_right"]//ul[@class="dropdown"]/li').count + s = x.xpathstring('//script[contains(.,"var pages")]') + if s ~= '' then + s = GetBetween('var pages = ', ';', s) + if Pos('atob("', s) > 0 then + s = GetBetween('atob("', '")', s) + s = DecodeBase64(s) + end + x.parsehtml(s) + v = x.xpath('json(*)()("url")') + for i = 1, v.count do + task.pagelinks.add(v.get(i).ToString) + end end - return result + result = true + end + return result end function getimageurl() - local result = false - local s = url - if workid > 0 then - s = AppendURLDelim(s) .. 'page/' .. (workid + 1) - end - if getWithCookie(MaybeFillHost(module.rooturl, s)) then - x = TXQuery.create(http.document) - task.pagelinks.set(workid, x.XPathString('//div[@id="page"]//img/@src')) - end - return result + local result = false + local s = url + if workid > 0 then + s = AppendURLDelim(s) .. 'page/' .. (workid + 1) + end + if getWithCookie(MaybeFillHost(module.rooturl, s)) then + x = TXQuery.create(http.document) + task.pagelinks.set(workid, x.XPathString('//div[@id="page"]//img/@src')) + end + return result end function getdirectorypagenumber() - local result = net_problem - page = 1 - if getWithCookie(module.rooturl .. getdirurl(module.website)) then - result = no_error - x = TXQuery.create(http.document) - v = x.xpath('//*[@class="next"]/a/@href') - for i = 1, v.count do - local s = tonumber(string.match(v.get(i).tostring, '/(%d+)/$')) - if (s ~= nil) and (s > page) then - page = s - end - end + local result = net_problem + page = 1 + if getWithCookie(module.rooturl .. getdirurl(module.website)) then + result = no_error + x = TXQuery.create(http.document) + v = x.xpath('//*[@class="next"]/a/@href') + for i = 1, v.count do + local s = tonumber(string.match(v.get(i).tostring, '/(%d+)/$')) + if (s ~= nil) and (s > page) then + page = s + end end - return result + end + return result end function getnameandlink() - local result = net_problem - local s = module.rooturl .. getdirurl(module.website) - if url ~= '0' then - s = s .. (tonumber(url) + 1) .. '/' - end - if getWithCookie(s) then - result = no_error - x = TXQuery.create(http.document) - if module.website == 'AtelierDuNoir' then - v = x.xpath('//div[@class="caption"]') - for i = 1, v.count do - v1 = v.get(i) - links.add(x.xpathstring('div/a/@href', v1)) - names.add(x.xpathstring('h4', v1)) - end - else - x.XpathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', links, names) - end + local result = net_problem + local s = module.rooturl .. getdirurl(module.website) + if url ~= '0' then + s = s .. (tonumber(url) + 1) .. '/' + end + if getWithCookie(s) then + result = no_error + x = TXQuery.create(http.document) + if module.website == 'AtelierDuNoir' then + v = x.xpath('//div[@class="caption"]') + for i = 1, v.count do + v1 = v.get(i) + links.add(x.xpathstring('div/a/@href', v1)) + names.add(x.xpathstring('h4', v1)) + end + else + x.XpathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', links, names) end - return result + end + return result end function AddWebsiteModule(name, url, category) - local m = NewModule() - m.website = name - m.rooturl = url - m.category = category - m.lastupdated = 'february, 6 2018' - m.ongetinfo = 'getinfo' - m.OnTaskStart = 'taskstart' - m.OnGetPageNumber = 'getpagenumber' - m.OnGetImageURL = 'getimageurl' - m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' - m.OnGetNameAndLink = 'getnameandlink' - return m + local m = NewModule() + m.website = name + m.rooturl = url + m.category = category + m.lastupdated = 'february, 6 2018' + m.ongetinfo = 'getinfo' + m.OnTaskStart = 'taskstart' + m.OnGetPageNumber = 'getpagenumber' + m.OnGetImageURL = 'getimageurl' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + m.OnGetNameAndLink = 'getnameandlink' + return m end function Init() - local cat = 'English-Scanlation' - AddWebsiteModule('PowerManga', 'http://read.powermanga.org', cat) - AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com', cat) - AddWebsiteModule('GoManga', 'http://gomanga.co', 'English') - AddWebsiteModule('OneTimeScans', 'http://otscans.com', cat) - AddWebsiteModule('SenseScans', 'http://reader.sensescans.com', cat) - AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com', cat) - AddWebsiteModule('KireiCake', 'https://reader.kireicake.com', cat) - AddWebsiteModule('HelveticaScans', 'http://helveticascans.com', cat) - AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com', cat) - AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com', cat) - AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org', cat) - AddWebsiteModule('ChampionScans', 'http://reader.championscans.com', cat) - AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org', cat) - AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com', cat) - AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com', cat) - AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today', cat) - AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com', cat) - AddWebsiteModule('SeaOtterScans', 'https://reader.seaotterscans.com', cat) - - -- es-sc - cat = 'Spanish-Scanlation' - AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com', cat) - AddWebsiteModule('DejameProbar', 'http://dejameprobar.es', cat) - AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) - AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) - AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) - AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com', cat) - AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) - AddWebsiteModule('SeinagiFansub', 'http://seinagi.org', cat) - AddWebsiteModule('SeinagiAdultoFansub', 'http://adulto.seinagi.org', cat) - AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net', cat) - AddWebsiteModule('RavensScans', 'http://ravens-scans.com', cat) - AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com', cat) - AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com', cat) - AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com', cat) - AddWebsiteModule('XAnimeSeduccion', 'http://xanime-seduccion.com', cat) - AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) - AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) + local cat = 'English-Scanlation' + AddWebsiteModule('PowerManga', 'http://read.powermanga.org', cat) + AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com', cat) + AddWebsiteModule('GoManga', 'http://gomanga.co', 'English') + AddWebsiteModule('OneTimeScans', 'http://otscans.com', cat) + AddWebsiteModule('SenseScans', 'http://reader.sensescans.com', cat) + AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com', cat) + AddWebsiteModule('KireiCake', 'https://reader.kireicake.com', cat) + AddWebsiteModule('HelveticaScans', 'http://helveticascans.com', cat) + AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com', cat) + AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com', cat) + AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org', cat) + AddWebsiteModule('ChampionScans', 'http://reader.championscans.com', cat) + AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org', cat) + AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com', cat) + AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com', cat) + AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today', cat) + AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com', cat) + AddWebsiteModule('SeaOtterScans', 'https://reader.seaotterscans.com', cat) + + -- es-sc + cat = 'Spanish-Scanlation' + AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com', cat) + AddWebsiteModule('DejameProbar', 'http://dejameprobar.es', cat) + AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) + AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) + AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) + AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com', cat) + AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) + AddWebsiteModule('SeinagiFansub', 'http://seinagi.org', cat) + AddWebsiteModule('SeinagiAdultoFansub', 'https://adulto.seinagi.org', cat) + AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net', cat) + AddWebsiteModule('RavensScans', 'http://ravens-scans.com', cat) + AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com', cat) + AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com', cat) + AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com', cat) + AddWebsiteModule('XAnimeSeduccion', 'http://xanime-seduccion.com', cat) + AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) + AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) end From 47e9ed09fdfdf0c85a0deaee767e27c3a1ddc0d7 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 18 Feb 2018 07:58:28 +0300 Subject: [PATCH 2304/2794] LuaStrings, add LoadFromStream --- baseunits/lua/LuaStrings.pas | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas index c27698625..dbb3d6246 100644 --- a/baseunits/lua/LuaStrings.pas +++ b/baseunits/lua/LuaStrings.pas @@ -29,6 +29,12 @@ function strings_loadfromfile(L: Plua_State): Integer; cdecl; TUserData(luaClassGetObject(L)).LoadFromFile(lua_tostring(L, 1)); end; +function strings_loadfromstream(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).LoadFromStream(TStream(lua_touserdata(L, 1))); +end; + function strings_settext(L: Plua_State): Integer; cdecl; begin Result := 0; @@ -128,8 +134,9 @@ function strings_clear(L: Plua_State): Integer; cdecl; (name: 'Create'; func: @strings_create), (name: nil; func: nil) ); - methods: packed array [0..10] of luaL_Reg = ( + methods: packed array [0..11] of luaL_Reg = ( (name: 'LoadFromFile'; func: @strings_loadfromfile), + (name: 'LoadFromStream'; func: @strings_loadfromstream), (name: 'SetText'; func: @strings_settext), (name: 'GetText'; func: @strings_gettext), (name: 'Add'; func: @strings_add), From 5af3462b780b0f5742842bf898de2a3d0436699c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 18 Feb 2018 11:39:08 +0300 Subject: [PATCH 2305/2794] LuaHTTPSend, add MimeType --- baseunits/lua/LuaHTTPSend.pas | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index c6d231bbf..55d924245 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -58,6 +58,18 @@ function http_threadterminated(L: Plua_State): Integer; cdecl; Result := 1; end; +function http_getmimetype(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).MimeType); + Result := 1; +end; + +function http_setmimetype(L: Plua_State): Integer; cdecl; +begin + TUserData(luaClassGetObject(L)).MimeType := lua_tostring(L, 1); + Result := 0; +end; + function http_document(L: Plua_State): Integer; cdecl; begin lua_pushlightuserdata(L, TUserData(luaClassGetObject(L)).Document); @@ -74,9 +86,10 @@ function http_document(L: Plua_State): Integer; cdecl; (name: 'GetCookies'; func: @http_getcookies), (name: nil; func: nil) ); - props: packed array[0..2] of luaL_Reg_prop = ( + props: packed array[0..3] of luaL_Reg_prop = ( (name: 'Document'; funcget: @http_document; funcset: nil), (name: 'Terminated'; funcget: @http_threadterminated; funcset: nil), + (name: 'MimeType'; funcget: @http_getmimetype; funcset: @http_setmimetype), (name: nil; funcget: nil; funcset: nil) ); From 3b38521d68295e396808309c885936ea9c0e9cd3 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 18 Feb 2018 13:40:11 +0300 Subject: [PATCH 2306/2794] add LeitorNet [PT] (no manga list) #993 --- lua/modules/LeitorNet.lua | 79 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 lua/modules/LeitorNet.lua diff --git a/lua/modules/LeitorNet.lua b/lua/modules/LeitorNet.lua new file mode 100644 index 000000000..365162e60 --- /dev/null +++ b/lua/modules/LeitorNet.lua @@ -0,0 +1,79 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//*[@id="series-data"]//*[@class="series-title"]/h1') + mangainfo.coverlink=x.xpathstring('//*[@id="series-data"]//img[@class="cover"]/@src') + mangainfo.authors=x.xpathstring('//*[@id="series-data"]//*[@class="series-author"]/text()') + mangainfo.genres=x.xpathstringall('//*[@id="series-data"]//ul[contains(@class, "tags")]/li/a') + if x.xpathstring('//*[@id="series-data"]//*[@class="complete-series"]') == '' then + mangainfo.status = '1' + else + mangainfo.status = '0' + end + mangainfo.summary=x.xpathstring('//*[@id="series-data"]//*[@class="series-desc"]') + + local id = x.xpathstring('//ul[@data-id-serie]/@data-id-serie') + local page = 1 + while true do + if http.xhr(module.RootURL..'/series/chapters_list.json?page='..tostring(page)..'&id_serie='..id) then + if http.terminated then break end + x=TXQuery.Create(http.document) + if x.xpathstring('json(*).chapters'):lower() == 'false' then break end + v=x.xpath('json(*).chapters()') + for i=1,v.count do + v1=v.get(i) + w=x.xpath('./releases/*', v1) + for j=1,w.count do + w1=w.get(j) + local s = x.xpathstring('./concat(number, " - ", chapter_name)', v1) + local sc = x.xpathstring('./scanlators[1]/name', w1) + if sc ~= '' then + s = s .. ' [' .. sc .. ']' + end + mangainfo.chapternames.add(s) + mangainfo.chapterlinks.add(x.xpathstring('./link', w1)) + end + end + page=page+1 + else + break + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + x=TXQuery.Create(http.Document) + s=x.xpathstring('//script[contains(@src, "token=")]/@src') + local token = s:match('%?token=(%w+)&?') + local id = s:match('&id_release=(%w+)&?') + if http.get(module.rooturl ..'/leitor/pages.json?key='..token..'&id_release='..id) then + x=TXQuery.Create(http.Document) + x.xpathstringall('json(*).images()', task.pagelinks) + else + return false + end + else + return false + end + return true +end + +function Init() + m=NewModule() + m.category='Portugues' + m.website='LeitorNet' + m.rooturl='https://leitor.net' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + --m.ongetdirectorypagenumber='getdirectorypagenumber' + --m.ongetnameandlink='getnameandlink' +end \ No newline at end of file From f7a8f0b9702d0184d5bbd47cf97ef00a960deb6c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 21:43:14 +0800 Subject: [PATCH 2307/2794] luahttpsend, add useragent, setproxy --- baseunits/lua/LuaHTTPSend.pas | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index 55d924245..83a6e6c1b 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -58,38 +58,33 @@ function http_threadterminated(L: Plua_State): Integer; cdecl; Result := 1; end; -function http_getmimetype(L: Plua_State): Integer; cdecl; +function http_document(L: Plua_State): Integer; cdecl; begin - lua_pushstring(L, TUserData(luaClassGetObject(L)).MimeType); + lua_pushlightuserdata(L, TUserData(luaClassGetObject(L)).Document); Result := 1; end; -function http_setmimetype(L: Plua_State): Integer; cdecl; +function http_setproxy(L: Plua_State): Integer; cdecl; begin - TUserData(luaClassGetObject(L)).MimeType := lua_tostring(L, 1); Result := 0; -end; - -function http_document(L: Plua_State): Integer; cdecl; -begin - lua_pushlightuserdata(L, TUserData(luaClassGetObject(L)).Document); - Result := 1; + TUserData(luaClassGetObject(L)).SetProxy(lua_tostring(L, 1), lua_tostring(L, 2), + lua_tostring(L, 3), lua_tostring(L, 4), lua_tostring(L, 5)); end; const - methods: packed array [0..6] of luaL_Reg = ( + methods: packed array [0..7] of luaL_Reg = ( (name: 'GET'; func: @http_get), (name: 'POST'; func: @http_post), (name: 'HEAD'; func: @http_head), (name: 'XHR'; func: @http_xhr), (name: 'Reset'; func: @http_reset), (name: 'GetCookies'; func: @http_getcookies), + (name: 'SetProxy'; func: @http_setproxy), (name: nil; func: nil) ); - props: packed array[0..3] of luaL_Reg_prop = ( + props: packed array[0..2] of luaL_Reg_prop = ( (name: 'Document'; funcget: @http_document; funcset: nil), (name: 'Terminated'; funcget: @http_threadterminated; funcset: nil), - (name: 'MimeType'; funcget: @http_getmimetype; funcset: @http_setmimetype), (name: nil; funcget: nil; funcset: nil) ); @@ -101,6 +96,8 @@ procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, luaClassAddProperty(L, MetaTable, UserData, props); luaClassAddObject(L, MetaTable, Headers, 'Headers'); luaClassAddObject(L, MetaTable, Cookies, 'Cookies'); + luaClassAddStringProperty(L, MetaTable, 'MimeType', @TUserData(Obj).MimeType); + luaClassAddStringProperty(L, MetaTable, 'UserAgent', @TUserData(Obj).UserAgent); end; end; From dd635559e0e3ed7c86457fc6fb3aadb97831838f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 22:12:43 +0800 Subject: [PATCH 2308/2794] luaclass, move luanewuserdata to luautils luapushuserdata --- baseunits/lua/LuaClass.pas | 9 +-------- baseunits/lua/LuaUtils.pas | 7 +++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/baseunits/lua/LuaClass.pas b/baseunits/lua/LuaClass.pas index a825de205..e643a1d41 100644 --- a/baseunits/lua/LuaClass.pas +++ b/baseunits/lua/LuaClass.pas @@ -28,7 +28,6 @@ procedure luaClassRegisterAll(L: Plua_State); procedure luaClassRegister(C: TClass; AddMetaTable: TluaClassAddMetaTable; AddLib: TLuaClassRegisterLib = nil); -function luaNewUserData(L: Plua_State; Obj: Pointer): Integer; procedure luaClassNewUserData(L: Plua_State; var MetaTable, UserData: Integer; Obj: Pointer; AutoFree: Boolean = False); @@ -261,16 +260,10 @@ procedure luaClassRegister(C: TClass; AddMetaTable: TluaClassAddMetaTable; classlist.Add(C, AddMetaTable, AddLib); end; -function luaNewUserData(L: Plua_State; Obj: Pointer): Integer; -begin - PPointer(lua_newuserdata(L, SizeOf(PPointer)))^ := Obj; - Result := lua_gettop(L); -end; - procedure luaClassNewUserData(L: Plua_State; var MetaTable, UserData: Integer; Obj: Pointer; AutoFree: Boolean); begin - UserData := luaNewUserData(L, Obj); + UserData := luaPushUserData(L, Obj); lua_newtable(L); MetaTable := lua_gettop(L); luaClassAddFunction(L, MetaTable, UserData, 'self', @__self); diff --git a/baseunits/lua/LuaUtils.pas b/baseunits/lua/LuaUtils.pas index d565b3aaa..e0d897d0b 100644 --- a/baseunits/lua/LuaUtils.pas +++ b/baseunits/lua/LuaUtils.pas @@ -25,6 +25,7 @@ procedure luaPushStringGlobal(L: Plua_State; Name: PAnsiChar; S: String); procedure luaPushIntegerGlobal(L: Plua_State; Name: PAnsiChar; I: Integer); procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); +function luaPushUserData(L: Plua_State; U: Pointer): Integer; inline; function luaGetUserData(L: Plua_State; idx: Integer): Pointer; inline; function LuaToString(L: Plua_State; Idx: Integer): String; @@ -112,6 +113,12 @@ procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); lua_setglobal(L, Name); end; +function luaPushUserData(L: Plua_State; U: Pointer): Integer; +begin + PPointer(lua_newuserdata(L, SizeOf(PPointer)))^ := U; + Result := lua_gettop(L); +end; + function luaGetUserData(L: Plua_State; idx: Integer): Pointer; begin Result := PPointer(lua_touserdata(L, idx))^; From c936bdfdf03416b52984895f2843cf28715fa4d3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 22:37:33 +0800 Subject: [PATCH 2309/2794] luautils, change pushuserdata method --- baseunits/lua/LuaUtils.pas | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/baseunits/lua/LuaUtils.pas b/baseunits/lua/LuaUtils.pas index e0d897d0b..61fe06d39 100644 --- a/baseunits/lua/LuaUtils.pas +++ b/baseunits/lua/LuaUtils.pas @@ -25,7 +25,8 @@ procedure luaPushStringGlobal(L: Plua_State; Name: PAnsiChar; S: String); procedure luaPushIntegerGlobal(L: Plua_State; Name: PAnsiChar; I: Integer); procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); -function luaPushUserData(L: Plua_State; U: Pointer): Integer; inline; +procedure luaPushUserData(L: Plua_State; U: Pointer); overload; inline; +procedure luaPushUserData(L: Plua_State; U: Pointer; var UIndex: Integer); overload; inline; function luaGetUserData(L: Plua_State; idx: Integer): Pointer; inline; function LuaToString(L: Plua_State; Idx: Integer): String; @@ -113,10 +114,15 @@ procedure luaPushBooleanGlobal(L: Plua_State; Name: PAnsiChar; B: Boolean); lua_setglobal(L, Name); end; -function luaPushUserData(L: Plua_State; U: Pointer): Integer; +procedure luaPushUserData(L: Plua_State; U: Pointer); begin PPointer(lua_newuserdata(L, SizeOf(PPointer)))^ := U; - Result := lua_gettop(L); +end; + +procedure luaPushUserData(L: Plua_State; U: Pointer; var UIndex: Integer); +begin + luaPushUserData(L, U); + UIndex := lua_gettop(L); end; function luaGetUserData(L: Plua_State; idx: Integer): Pointer; From 4568cdcd0081800053dfaa28b2c8c84ab6fd8760 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 22:37:58 +0800 Subject: [PATCH 2310/2794] luaclass, add adduserdata --- baseunits/lua/LuaClass.pas | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaClass.pas b/baseunits/lua/LuaClass.pas index e643a1d41..59cef5d62 100644 --- a/baseunits/lua/LuaClass.pas +++ b/baseunits/lua/LuaClass.pas @@ -63,6 +63,8 @@ procedure luaClassAddBooleanProperty(L: Plua_State; MetaTable: Integer; Name: PAnsiChar; P: Pointer); overload; procedure luaClassAddObject(L: Plua_State; MetaTable: Integer; Obj: TObject; Name: String; AddMetaTable: TluaClassAddMetaTable = nil); +procedure luaClassAddUserData(L: Plua_State; MetaTable: Integer; Obj: TObject; + Name: String); implementation @@ -263,7 +265,7 @@ procedure luaClassRegister(C: TClass; AddMetaTable: TluaClassAddMetaTable; procedure luaClassNewUserData(L: Plua_State; var MetaTable, UserData: Integer; Obj: Pointer; AutoFree: Boolean); begin - UserData := luaPushUserData(L, Obj); + luaPushUserData(L, Obj, UserData); lua_newtable(L); MetaTable := lua_gettop(L); luaClassAddFunction(L, MetaTable, UserData, 'self', @__self); @@ -512,6 +514,14 @@ AddMetaTable := classlist.FindAddMetaTable(Obj.ClassType); lua_rawset(L, MetaTable); end; +procedure luaClassAddUserData(L: Plua_State; MetaTable: Integer; Obj: TObject; + Name: String); +begin + lua_pushstring(L, PAnsiChar(AnsiLowerCase(Name))); + luaPushUserData(L, Obj); + lua_rawset(L, MetaTable); +end; + { TluaClassList } constructor TluaClassList.Create; From 1a8815942d6045e7c8038aa952fc52b6aa4214a1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 22:38:18 +0800 Subject: [PATCH 2311/2794] luahttpsend, document as userdata property --- baseunits/lua/LuaHTTPSend.pas | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index 83a6e6c1b..08613cdb0 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -58,12 +58,6 @@ function http_threadterminated(L: Plua_State): Integer; cdecl; Result := 1; end; -function http_document(L: Plua_State): Integer; cdecl; -begin - lua_pushlightuserdata(L, TUserData(luaClassGetObject(L)).Document); - Result := 1; -end; - function http_setproxy(L: Plua_State): Integer; cdecl; begin Result := 0; @@ -82,8 +76,7 @@ function http_setproxy(L: Plua_State): Integer; cdecl; (name: 'SetProxy'; func: @http_setproxy), (name: nil; func: nil) ); - props: packed array[0..2] of luaL_Reg_prop = ( - (name: 'Document'; funcget: @http_document; funcset: nil), + props: packed array[0..1] of luaL_Reg_prop = ( (name: 'Terminated'; funcget: @http_threadterminated; funcset: nil), (name: nil; funcget: nil; funcset: nil) ); @@ -98,6 +91,7 @@ procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, luaClassAddObject(L, MetaTable, Cookies, 'Cookies'); luaClassAddStringProperty(L, MetaTable, 'MimeType', @TUserData(Obj).MimeType); luaClassAddStringProperty(L, MetaTable, 'UserAgent', @TUserData(Obj).UserAgent); + luaClassAddUserData(L, MetaTable, TUserData(Obj).Document, 'Document'); end; end; From df6b1621d1c6f8ab369958bd83081cc14d1df5ba Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 22:38:37 +0800 Subject: [PATCH 2312/2794] luaxquery, read tsream as userdata --- baseunits/lua/luaXQuery.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index e722a9472..dc1a66fdd 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -26,7 +26,7 @@ function xquery_create(L: Plua_State): Integer; cdecl; luaXQueryPush(L, TXQueryEngineHTML.Create(lua_tostring(L, 1)), '', True) else if lua_isuserdata(L, 1) then - luaXQueryPush(L, TXQueryEngineHTML.Create(TStream(lua_touserdata(L, 1))), + luaXQueryPush(L, TXQueryEngineHTML.Create(TStream(luaGetUserData(L, 1))), '', True); end else From a0c07724e074a06a983f66acbb55bc80299902b1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 22:58:46 +0800 Subject: [PATCH 2313/2794] add luaupdatelistmanager #993 --- baseunits/lua/LuaUpdateListManager.pas | 37 ++++++++++++++++++++++++++ baseunits/lua/LuaWebsiteModules.pas | 8 ++++-- 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 baseunits/lua/LuaUpdateListManager.pas diff --git a/baseunits/lua/LuaUpdateListManager.pas b/baseunits/lua/LuaUpdateListManager.pas new file mode 100644 index 000000000..dd181ac72 --- /dev/null +++ b/baseunits/lua/LuaUpdateListManager.pas @@ -0,0 +1,37 @@ +unit LuaUpdateListManager; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53; + +implementation + +uses + LuaClass, uUpdateThread; + +function lua_GetCurrentDirectoryPageNumber(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUpdateListManagerThread(luaClassGetObject(L)).CurrentDirectoryPageNumber); + Result := 1; +end; + +function lua_SetCurrentDirectoryPageNumber(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUpdateListManagerThread(luaClassGetObject(L)).CurrentDirectoryPageNumber := lua_tointeger(L, 1); +end; + +procedure luaUpdateListManagerAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + luaClassAddProperty(L, MetaTable, UserData, 'CurrentDirectoryPageNumber', @lua_GetCurrentDirectoryPageNumber, @lua_SetCurrentDirectoryPageNumber); +end; + +initialization + luaClassRegister(TUpdateListManagerThread, @luaUpdateListManagerAddMetaTable); + +end. + diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 00ef568ef..9686011a9 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -5,8 +5,8 @@ interface uses - Classes, SysUtils, fgl, lua53, LuaStringsStorage, WebsiteModules, uData, - uDownloadsManager, xquery, httpsendthread; + Classes, SysUtils, fgl, lua53, LuaStringsStorage, LuaUpdateListManager, + WebsiteModules, uData, uDownloadsManager, xquery, httpsendthread, FMDVars; type TLuaWebsiteModulesContainer = class; @@ -117,6 +117,7 @@ function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; l := LuaNewBaseState; try LuaPushMe(l); + luaPushObject(l, updateList, 'updatelist'); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -139,6 +140,7 @@ function DoAfterUpdateList(const Module: TModuleContainer): Boolean; l := LuaNewBaseState; try LuaPushMe(l); + luaPushObject(l, updateList, 'updatelist'); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -166,6 +168,7 @@ function DoGetDirectoryPageNumber(const MangaInfo: TMangaInformation; luaPushIntegerGlobal(l, 'workptr', WorkPtr); luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); luaPushObject(l, MangaInfo.FHTTP, 'http'); + luaPushObject(l, updateList, 'updatelist'); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -199,6 +202,7 @@ function DoGetNameAndLink(const MangaInfo: TMangaInformation; luaPushStringGlobal(L, 'url', AURL); luaPushObject(l, ANames, 'names'); luaPushObject(l, ALinks, 'links'); + luaPushObject(l, updateList, 'updatelist'); if LuaDoMe(l) <> 0 then raise Exception.Create(''); From fef1b5ac730fe872b42c00e3464d5779d22ad587 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 23:21:24 +0800 Subject: [PATCH 2314/2794] luaclass, publish addmetatable use it when pushing known object, faster than looking up the classlist --- baseunits/lua/LuaBase.pas | 11 ++--- baseunits/lua/LuaDownloadTask.pas | 3 ++ baseunits/lua/LuaHTTPSend.pas | 6 ++- baseunits/lua/LuaMangaInfo.pas | 3 ++ baseunits/lua/LuaStrings.pas | 3 ++ baseunits/lua/LuaStringsStorage.pas | 3 ++ baseunits/lua/LuaUpdateListManager.pas | 3 ++ baseunits/lua/LuaWebsiteModules.pas | 59 ++++++++++++++------------ 8 files changed, 57 insertions(+), 34 deletions(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 6d89d545f..99ab8b2e4 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -5,11 +5,11 @@ interface uses - Classes, SysUtils, Lua53; + Classes, SysUtils, Lua53, LuaClass; procedure LuaBaseRegister(L: Plua_State); procedure luaPushObject(L: Plua_State; Obj: TObject; Name: String; - AutoFree: Boolean = False); inline; + AddMetaTable: TluaClassAddMetaTable = nil; AutoFree: Boolean = False); inline; function LuaDoFile(AFilename: String; AFuncName: String = ''): Plua_State; function LuaNewBaseState: Plua_State; @@ -22,7 +22,7 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh implementation uses - LuaClass, luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog; + luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog; function luabase_print(L: Plua_State): Integer; cdecl; var @@ -45,9 +45,10 @@ procedure LuaBaseRegister(L: Plua_State); luaClassRegisterAll(L); end; -procedure luaPushObject(L: Plua_State; Obj: TObject; Name: String; AutoFree: Boolean); +procedure luaPushObject(L: Plua_State; Obj: TObject; Name: String; + AddMetaTable: TluaClassAddMetaTable; AutoFree: Boolean); begin - luaClassPushObject(L, Obj, Name, AutoFree); + luaClassPushObject(L, Obj, Name, AutoFree, AddMetaTable); end; function LuaDoFile(AFilename: String; AFuncName: String): Plua_State; diff --git a/baseunits/lua/LuaDownloadTask.pas b/baseunits/lua/LuaDownloadTask.pas index 081c14497..60dbf9f8f 100644 --- a/baseunits/lua/LuaDownloadTask.pas +++ b/baseunits/lua/LuaDownloadTask.pas @@ -7,6 +7,9 @@ interface uses Classes, SysUtils, lua53; +procedure luaDownloadTaskMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + implementation uses diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index 08613cdb0..ec5aa7320 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -7,6 +7,9 @@ interface uses Classes, SysUtils, lua53; +procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, + UserData: Integer; AutoFree: Boolean = False); + implementation uses @@ -81,7 +84,8 @@ function http_setproxy(L: Plua_State): Integer; cdecl; (name: nil; funcget: nil; funcset: nil) ); -procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, UserData: Integer; AutoFree: Boolean = False); +procedure luaHTTPSendThreadAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, + UserData: Integer; AutoFree: Boolean = False); begin with TUserData(Obj) do begin diff --git a/baseunits/lua/LuaMangaInfo.pas b/baseunits/lua/LuaMangaInfo.pas index 5febdaf00..7d4ef6678 100644 --- a/baseunits/lua/LuaMangaInfo.pas +++ b/baseunits/lua/LuaMangaInfo.pas @@ -7,6 +7,9 @@ interface uses Classes, SysUtils, lua53; +procedure luaMangaInfoAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + implementation uses diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas index dbb3d6246..e2dc4b790 100644 --- a/baseunits/lua/LuaStrings.pas +++ b/baseunits/lua/LuaStrings.pas @@ -10,6 +10,9 @@ interface procedure luaStringsPush(L: Plua_State; Obj: TStrings; Name: String = ''; AutoFree: Boolean = False); inline; +procedure luaStringsAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + implementation uses LuaClass; diff --git a/baseunits/lua/LuaStringsStorage.pas b/baseunits/lua/LuaStringsStorage.pas index 858179d1e..23949907d 100644 --- a/baseunits/lua/LuaStringsStorage.pas +++ b/baseunits/lua/LuaStringsStorage.pas @@ -33,6 +33,9 @@ TStringsStorage = class procedure luaStringsStoragePush(L: Plua_State; Obj: TStringsStorage; Name: PAnsiChar = nil; AutoFree: Boolean = False); inline; +procedure luaStringsStorageAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + implementation uses LuaClass; diff --git a/baseunits/lua/LuaUpdateListManager.pas b/baseunits/lua/LuaUpdateListManager.pas index dd181ac72..f1e0a377e 100644 --- a/baseunits/lua/LuaUpdateListManager.pas +++ b/baseunits/lua/LuaUpdateListManager.pas @@ -7,6 +7,9 @@ interface uses Classes, SysUtils, lua53; +procedure luaUpdateListManagerAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + implementation uses diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 9686011a9..64d81ad34 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -5,8 +5,7 @@ interface uses - Classes, SysUtils, fgl, lua53, LuaStringsStorage, LuaUpdateListManager, - WebsiteModules, uData, uDownloadsManager, xquery, httpsendthread, FMDVars; + Classes, SysUtils, fgl, lua53, LuaStringsStorage, WebsiteModules; type TLuaWebsiteModulesContainer = class; @@ -97,6 +96,9 @@ TOptionItemComboBox = class(TOptionItem) procedure ScanLuaWebsiteModulesFile; +procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); + var LuaWebsiteModulesManager: TLuaWebsiteModulesManager; AlwaysLoadLuaFromFile: Boolean = {$ifdef DEVBUILD}True{$else}False{$endif}; @@ -105,7 +107,8 @@ implementation uses FMDOptions, FileUtil, MultiLog, LuaClass, LuaBase, LuaMangaInfo, LuaHTTPSend, - LuaXQuery, LuaUtils, LuaDownloadTask; + LuaXQuery, LuaUtils, LuaDownloadTask, LuaUpdateListManager, luaStrings, uData, + uDownloadsManager, xquery, httpsendthread, FMDVars; function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; var @@ -117,7 +120,7 @@ function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(l, updateList, 'updatelist'); + luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -140,7 +143,7 @@ function DoAfterUpdateList(const Module: TModuleContainer): Boolean; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(l, updateList, 'updatelist'); + luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -166,9 +169,9 @@ function DoGetDirectoryPageNumber(const MangaInfo: TMangaInformation; LuaPushMe(l); luaPushIntegerGlobal(l, 'page', Page); luaPushIntegerGlobal(l, 'workptr', WorkPtr); - luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); - luaPushObject(l, MangaInfo.FHTTP, 'http'); - luaPushObject(l, updateList, 'updatelist'); + luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo', @luaMangaInfoAddMetaTable); + luaPushObject(l, MangaInfo.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); + luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -197,12 +200,12 @@ function DoGetNameAndLink(const MangaInfo: TMangaInformation; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); - luaPushObject(l, MangaInfo.FHTTP, 'http'); + luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo', @luaMangaInfoAddMetaTable); + luaPushObject(l, MangaInfo.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(L, 'url', AURL); - luaPushObject(l, ANames, 'names'); - luaPushObject(l, ALinks, 'links'); - luaPushObject(l, updateList, 'updatelist'); + luaPushObject(l, ANames, 'names', @luaStringsAddMetaTable); + luaPushObject(l, ALinks, 'links', @luaStringsAddMetaTable); + luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -227,8 +230,8 @@ function DoGetInfo(const MangaInfo: TMangaInformation; const AURL: String; try LuaPushMe(l); luaPushStringGlobal(l, 'url', AURL); - luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo'); - luaPushObject(l, MangaInfo.FHTTP, 'http'); + luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo', @luaMangaInfoAddMetaTable); + luaPushObject(l, MangaInfo.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -250,7 +253,7 @@ function DoTaskStart(const Task: TTaskContainer; const Module: TModuleContainer) l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(l, Task, 'task'); + luaPushObject(l, Task, 'task', @luaDownloadTaskMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -274,8 +277,8 @@ function DoGetPageNumber(const DownloadThread: TDownloadThread; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(L, DownloadThread.Task.Container, 'task'); - luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushObject(L, DownloadThread.Task.Container, 'task', @luaDownloadTaskMetaTable); + luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'url', AURL); if LuaDoMe(l) <> 0 then @@ -300,8 +303,8 @@ function DoGetImageURL(const DownloadThread: TDownloadThread; const AURL: String l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(L, DownloadThread.Task.Container, 'task'); - luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushObject(L, DownloadThread.Task.Container, 'task', @luaDownloadTaskMetaTable); + luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushIntegerGlobal(l, 'workid', DownloadThread.WorkId); luaPushStringGlobal(l, 'url', AURL); @@ -327,8 +330,8 @@ function DoBeforeDownloadImage(const DownloadThread: TDownloadThread; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(L, DownloadThread.Task.Container, 'task'); - luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushObject(L, DownloadThread.Task.Container, 'task', @luaDownloadTaskMetaTable); + luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'url', AURL); if LuaDoMe(l) <> 0 then @@ -353,8 +356,8 @@ function DoDownloadImage(const DownloadThread: TDownloadThread; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(L, DownloadThread.Task.Container, 'task'); - luaPushObject(l, DownloadThread.FHTTP, 'http'); + luaPushObject(L, DownloadThread.Task.Container, 'task', @luaDownloadTaskMetaTable); + luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'url', AURL); if LuaDoMe(l) <> 0 then @@ -379,7 +382,7 @@ function DoSaveImage(const AHTTP: THTTPSendThread; const APath, AName: String; l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(l, AHTTP, 'http'); + luaPushObject(l, AHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'path', APath); luaPushStringGlobal(l, 'name', AName); @@ -427,7 +430,7 @@ function DoLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): l := LuaNewBaseState; try LuaPushMe(l); - luaPushObject(l, AHTTP, 'http'); + luaPushObject(l, AHTTP, 'http', @luaHTTPSendThreadAddMetaTable); if LuaDoMe(l) <> 0 then raise Exception.Create(''); @@ -663,7 +666,7 @@ procedure TLuaWebsiteModule.AddOptionComboBox(const AName, ACaption, AItems: Str procedure TLuaWebsiteModule.LuaPushMe(L: Plua_State); begin - luaPushObject(L, Self, 'module'); + luaPushObject(L, Self, 'module', @luaWebsiteModuleAddMetaTable); luaPushIntegerGlobal(L, 'no_error', NO_ERROR); luaPushIntegerGlobal(L, 'net_problem', NET_PROBLEM); luaPushIntegerGlobal(L, 'information_not_found', INFORMATION_NOT_FOUND); @@ -805,7 +808,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddFunction(L, MetaTable, UserData, methods); - luaClassAddObject(L, MetaTable, Storage, 'Storage'); + luaClassAddObject(L, MetaTable, Storage, 'Storage', @luaStringsStorageAddMetaTable); end; end; From 4d58edbb9c388bf9ccc4246ec199f2e1d0fec12b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 18 Feb 2018 23:29:15 +0800 Subject: [PATCH 2315/2794] luastrings, loadfromstream getuserdata --- baseunits/lua/LuaStrings.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas index e2dc4b790..4b607c589 100644 --- a/baseunits/lua/LuaStrings.pas +++ b/baseunits/lua/LuaStrings.pas @@ -15,7 +15,7 @@ procedure luaStringsAddMetaTable(L: Plua_State; Obj: Pointer; implementation -uses LuaClass; +uses LuaClass, LuaUtils; type TUserData = TStrings; @@ -35,7 +35,7 @@ function strings_loadfromfile(L: Plua_State): Integer; cdecl; function strings_loadfromstream(L: Plua_State): Integer; cdecl; begin Result := 0; - TUserData(luaClassGetObject(L)).LoadFromStream(TStream(lua_touserdata(L, 1))); + TUserData(luaClassGetObject(L)).LoadFromStream(TStream(luaGetUserData(L, 1))); end; function strings_settext(L: Plua_State): Integer; cdecl; From d83bbc4dcb6f22f4fb481d51e475270e42e1e163 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 01:14:14 +0800 Subject: [PATCH 2316/2794] fix restore window (fixed #1012) --- baseunits/FMDVars.pas | 1 - mangadownloader/forms/frmMain.lfm | 619 +++++++++++++++++++++++++++++- mangadownloader/forms/frmMain.pas | 33 +- 3 files changed, 629 insertions(+), 24 deletions(-) diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas index 2945af319..83bdee712 100644 --- a/baseunits/FMDVars.pas +++ b/baseunits/FMDVars.pas @@ -12,7 +12,6 @@ interface var FormMain: TMainForm; - isStartup, isRunDownloadFilter, isUpdating, isPendingExitCounter, diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 356f83127..a9facdd66 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -12,9 +12,8 @@ object MainForm: TMainForm OnCreate = FormCreate OnDestroy = FormDestroy OnWindowStateChange = FormWindowStateChange - Position = poScreenCenter ShowHint = True - LCLVersion = '1.9.0.0' + LCLVersion = '1.8.0.6' object sbUpdateList: TStatusBar AnchorSideBottom.Control = sbMain Left = 0 @@ -114,16 +113,12 @@ object MainForm: TMainForm AllowZoom = False AxisList = < item - Marks.LabelBrush.Style = bsClear Minors = <> Title.LabelFont.Orientation = 900 - Title.LabelBrush.Style = bsClear end item Alignment = calBottom - Marks.LabelBrush.Style = bsClear Minors = <> - Title.LabelBrush.Style = bsClear end> AxisVisible = False BackColor = clDefault @@ -4894,12 +4889,84 @@ object MainForm: TMainForm object miDownloadStop: TMenuItem Caption = 'Stop' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 7 OnClick = miDownloadStopClick end object miDownloadResume: TMenuItem Caption = 'Resume' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000000000001000000070000000E000000150000001A0000001A0000001A0000 + 001A0000001A0000001A000000160000000F0000000800000002000000000000 + 0000000000020000000E0000001C0000002A000000330000003300000033733A + 02A663320274000000330000002B0000001D0000000F00000003000000000000 + 0000000000000000000000000000000000000000000000000000281502009D52 + 06CC9D5206CC763E055C29160300000000000000000000000000B0651400A85D + 0E00A85D0E00553008007F470C00A85D0E007F470C00A85D0E00A65B0D00A358 + 0BCCFFB914FFA3580BCCA4590C5C7F470C002C19050000000000B4691700AA5F + 1000AA5F10CCAB601100AB601199AA5F10CCAB601199AA5F10CCAB601199AA5F + 10CCFFB810FFFFBB1BFFAA5F10CCAB60115CB1661600B96E1C00B76C1A00AF64 + 1400AF641400B3681700B16616CCF8BF3EFFB16616CCF7BC36FFD08613E1F6B4 + 24FFF5AF18FFF5AB0EFFF7B92EFFB16616CCB267175CB96E1C00B96E1CCCBA6F + 1D00BA6F1D99B96E1CCCB96E1CCCB96E1CCCB96E1CCCBD721DCFCB8422E1DA96 + 27F5E19E29FFE19E29FFE19E29FFEAB349FFB96E1CCCBA6F1D5CBF742000C378 + 2300C27722CCF8D084FFC27722CCF7CD81FFC77E2AD2EDC071FFD08D3BE8D396 + 44FFD09341FFD09341FFD39644FFD89B49FFECBB6CFFC27722CCCB802999CA7F + 28CCCA7F28CCCA7F28CCCA7F28CCCC812BCED38C37D7DC9947E3E5A556EFEBAE + 61FAEEB266FFEEB266FFEEB266FFF7CC80FFCA7F28CCC97E275CD2872ECCFBD9 + 8DFFD2872ECCD0852C00D2872ECCFBD68AFFDA933DD7FAD488FFF3C375F7F6C9 + 7DFFF4C175FFF2B96DFFFAD68AFFD2872ECCD1862D5CCA7F2800D88D3399D98E + 33CCD88D3399D78C3200D88D3399D98E33CCD88D3399D98E33CCD98E33CCD98E + 33CCFBD488FFFEDF93FFD98E33CCD88D335CD2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DA8F3400DC913600E095 + 38CCFFE498FFE09538CCDF94385CD98E3300D2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300DD923700E59A3C00E59A + 3CCCE59A3CCCE59A3C5CE0953800D98E3300D2872E00CA7F2800D98E3300DA8F + 3400D98E3300D78C3200D98E3300DA8F3400D98E3300E89D3F00E89D3F00E99E + 4099E99E405CE59A3C00E0953800D98E3300D2872E00CA7F2800FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 12 OnClick = miDownloadResumeClick end @@ -4915,6 +4982,42 @@ object MainForm: TMainForm object miDownloadDelete: TMenuItem Caption = 'Delete' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 9 object miDownloadDeleteTask: TMenuItem Caption = 'Task only' @@ -4942,6 +5045,42 @@ object MainForm: TMainForm object miDownloadMergeCompleted: TMenuItem Caption = 'Merge completed tasks' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000 + 000200000005000000090000000D0000001100000015000000180000001A0000 + 001A0000001A0000001A0000001A000000170000000F00000005000000000000 + 00040000000A0000001100000019000000220000002A00000030000000330000 + 003300000033733B03A6633303740000002E0000001D0000000A532E0700522D + 0600522D0600522D0600522D0600522D0600522D0600522D0600522D0600522D + 0600522D06009F5408CC9F5408CC783F065C2917030000000000A75C0E99A65B + 0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B0DCCA65B + 0DCCA65B0DCCA65B0DCCFFB508FFA65B0DCCA75C0E5C824A0E00AF6414CCF9C6 + 60FFFFBE23FFFFBD1FFFFFBC1CFFFFBB19FFFFBA16FFFFB914FFFFB811FFFFB7 + 0FFFFFB70DFFFFB60BFFFFB200FFFFB609FFAF6414CCAF641448B96E1BCCF6CB + 7FFFF8C051FFF9BD36FFF8B92CFFF5AC10FFF5AB0EFFF5AC10FFF6B11BFFF7B5 + 23FFF7B523FFF7B421FFF5AB0EFFF6B11BFFB96E1BCCB96E1B48C1762199C277 + 22CCC27722CCC27722CCD5973FE0E3A538FEE4A533FFE2A743EFCF8C32D9C57C + 26CFC27722CCC27722CCE6A93CFFC27722CCC176215CBB701C00C2772200C479 + 2400CC812A2BD38E38CEF0BF71FBE0A856FFDCA04CE4CC8129AACB80283FC97E + 270FC77C2600CC8129CCCC8129CCCB80285CC2772200BB701C00CD822A00D58A + 3000D58A307BEBB865E8F7C579FFF0C070EFD58A30AAD0852D13CC812900C97E + 2700D2872E00D4892F99D4892F5CCC812900C2772200BB701C00DD923600DD92 + 3600DD9236AAF8D081F6FCD185FFE7A951D9DC91363FDB903500CC812900C97E + 2700D2872E00D58A3000D58A3000CC812900C2772200BB701C00E4993B00E499 + 3B00E4993BC5FEDF92FDFFDF93FFE69E42CFE4993B0FE4993B00E4993B00D085 + 2D00D2872E00D58A3000D58A3000CC812900C2772200BB701C00E89D3E00E89D + 3E00E99E3F99E99E3FCCE99E3FCCE99E3F85E59A3C00E59A3C00E59A3C00D78C + 3200D2872E00D58A3000D58A3000CC812900C2772200BB701C00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 10 OnClick = miDownloadMergeCompletedClick end @@ -4951,18 +5090,126 @@ object MainForm: TMainForm object miDownloadViewMangaInfo: TMenuItem Caption = 'View manga info' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000030000 + 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B + 0B7A090909650505054200000032000000270000001300000003000000020000 + 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA + DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 + 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 + 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F + 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 + 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 + 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 + 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA + AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 + 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF + CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 + 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC + CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B + 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF + CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 + 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC + DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 + 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF + BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 + 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C + 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F + 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E + 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E + 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 + 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C + 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 + 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA + EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 + 50005252520053535300545454155555553E5555555555555563555555635555 + 55555555553E545454155353530052525200505050004F4F4F00 + } ImageIndex = 0 OnClick = miDownloadViewMangaInfoClick end object miDownloadOpenFolder: TMenuItem Caption = 'Open Folder' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 4 OnClick = miDownloadOpenFolderClick end object miDownloadOpenWith: TMenuItem Caption = 'Open ...' Enabled = False + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000100000001A0000001000000000000000000000 + 00000000000000000000000000000000000000000000000000001007000F220E + 00352A110048000000620000008F000000ED0000008F000000622A110048200D + 003A130800300703002A050200290502002906030023020100095322009A8550 + 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 + 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 + B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 + B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF + FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 + EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B + A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 + DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 + D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE + FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 + F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF + E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F + 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F + 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D + } ImageIndex = 11 OnClick = miDownloadOpenWithClick end @@ -5031,11 +5278,83 @@ object MainForm: TMainForm top = 212 object miFavoritesCheckNewChapter: TMenuItem Caption = 'Check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 002C00000087000000E7702E00C7702E00C7702E00C7702E00C7702E00C7702E + 00C7702E00C72D5500E9175F00F4124A00C40000002C00000000000000090000 + 0016000000DB606060FFCA9764FFC5925FFFC5925FFFC5925FFFC5925FFFC592 + 5FFFC5925FFF318613FF2BDF1AFF1E7700F20000001600000009000000000101 + 0100010101CE626262FFC89562FFBD8A57FFBF8C59FFBF8C59FFBF8C59FF548D + 24FF318C12FF318C11FF3DE22CFF208100F00E8C00CC0E8D0099010101000101 + 0100010101C9646464FFCA9764FFBE8B58FFC18E5BFFC18E5BFFC18E5BFF3394 + 12FF52E741FF52E741FF52E741FF52E741FF52E741FF109500CC010101000101 + 0100010101C5676767FFCD9A67FFBF8C59FFC4915EFFC4915EFFC4915EFF5A98 + 26FF369B13FF359A12FF66EB55FF249000EF129D00CC129C0099010101000101 + 0100010101C16B6B6BFFD19E6BFFBF8C59FFC89562FFC89562FFC89562FFC895 + 62FFC89562FF369F12FF75EE64FF269700EE179E0000129D0000010101000101 + 0100010101BE6E6E6EFFD4A16EFFBF8C59FFCB9865FFCB9865FFCB9865FFCB98 + 65FFCB9865FF599D24FF3BA816FF448700DC6072000056730000010101000101 + 0100010101BB727272FFD8A572FFBF8C59FFCF9C69FFCF9C69FFCF9C69FFCF9C + 69FFCF9C69FFBF8C59FFD8A572FF9B4B00A59B4B00009B4B0000010101000101 + 0100010101B8757575FFDBA875FFBE8B58FFD29F6CFFD29F6CFFD29F6CFFD29F + 6CFFD29F6CFFBE8B58FFDBA875FF9E4D00A39E4D00009E4D0000010101000101 + 0100010101B5797979FFDFAC79FFBE8B58FFD6A370FFD6A370FFD6A370FFD6A3 + 70FFD6A370FFBE8B58FFDFAC79FFA14F00A1A14F0000A14F0000010101000101 + 0100010101B27C7C7CFFE2AF7CFFBC8956FFE3B07DFFE3B07DFFE3B07DFFE3B0 + 7DFFE3B07DFFBC8956FFE2AF7CFFA451009FA4510000A4510000010101000101 + 0100010101B07E7E7EFFE4B17EFFBB8855FFBB8855FFBB8855FFBB8855FFBB88 + 55FFBB8855FFBB8855FFE4B17EFFA653009DA6530000A6530000010101000101 + 0100010101AE808080FFEAB784FFE5B27FFFE5B27FFFE5B27FFFE5B27FFFE5B2 + 7FFFE5B27FFFE5B27FFFEAB784FFA854009BA8540000A8540000010101000101 + 0100010101AC555555FFCC9966FFCC9966FFCC9966FFCC9966FFCC9966FFCC99 + 66FFCC9966FFCC9966FFCC9966FFAA55009AAA550000AA550000040404000404 + 04000404048ABCBCABFFC1C1B1FFC7C7B9FFCFCFC3FFD7D7CDFFDFDFD7FFE8E8 + E2FFEFEFECFFF7F7F4FFFCFCFCFF55552B6655552B0055552B00040404000404 + 0400040404460404048AAA550099AA550099AA550099AA550099AA550099AA55 + 0099AA550099AA550099AA550099AA550073AA550000AA550000 + } ImageIndex = 21 OnClick = miFavoritesCheckNewChapterClick end object miFavoritesStopCheckNewChapter: TMenuItem Caption = 'Stop check for new chapter' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 0003000000110000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001300000004FFFFFF00FFFFFF00FFFFFF000000 + 000306063EA0080860CC080860CC080860CC080860CC080860CC080860CC0808 + 60CC080860CC080860CC06063EA100000004FFFFFF00FFFFFF00FFFFFF00FFFF + FF0009096ACC2727CDFF1C1CC9FF1B1BC9FF1A1AC9FF1919C8FF1717C8FF1717 + C8FF1717C8FF1919C8FF09096ACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000A0A75CC2525CDFF1212C6FF1212C6FF1212C6FF1212C6FF1212C6FF1212 + C6FF1212C6FF1919C8FF0A0A75CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000B0B84CC2C2CCFFF1414C6FF1414C6FF1414C6FF1414C6FF1414C6FF1414 + C6FF1414C6FF1E1ECAFF0B0B84CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000D0D95CC3636D1FF1717C8FF1717C8FF1717C8FF1717C8FF1717C8FF1717 + C8FF1717C8FF2727CDFF0D0D95CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF000F0FA5CC5555DAFF2020CAFF1A1AC9FF1A1AC9FF1A1AC9FF1A1AC9FF1A1A + C9FF1A1AC9FF2E2ED0FF0F0FA5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001010B9CC6767DFFF4B4BD8FF3838D3FF2525CDFF1C1CC9FF1B1BC9FF1B1B + C9FF1B1BC9FF3434D1FF1010B9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001414C6CC6F6FE1FF5555DAFF5555DAFF5555DAFF4D4DD8FF4343D6FF3B3B + D3FF3838D3FF5252DAFF1414C6CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF001C1CC9CC7878E4FF6767DFFF6767DFFF6767DFFF6767DFFF6767DFFF6767 + DFFF6767DFFF7575E2FF1C1CC9CCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002424CCCC8686E6FF8080E5FF8080E5FF8080E5FF8080E5FF8080E5FF8080 + E5FF8080E5FF8484E5FF2424CCCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF002B2BCF992B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2BCFCC2B2B + CFCC2B2BCFCC2B2BCFCC2B2BCF99FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 7 OnClick = miFavoritesStopCheckNewChapterClick end @@ -5049,12 +5368,84 @@ object MainForm: TMainForm end object miFavoritesViewInfos: TMenuItem Caption = 'View manga info' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000030000 + 0013000000260000003205050542090909650B0B0B7A0B0B0B880B0B0B880B0B + 0B7A090909650505054200000032000000270000001300000003000000020000 + 000A0707071C1313135D3D3A3A93B2A6A6DCEBDADAFFEBDADAFFEBDADAFFEBDA + DAFFB2A6A6DC3D3A3A931313135D0707071D0000000A00000002171717002121 + 21092626265C807979AFE4D6D6FFC69689FFAD644EFF943312FF943312FFAD64 + 4EFFC69689FFE3D6D6FF7F7979AF2626265C2121210917171700303030002F2F + 2F48827E7EACDBD1D1FFAC573CFFB6461FFFD6592AFFE56230FFE56230FFD659 + 2AFFB6461FFFAC573CFFDACFCFFF817C7CAC2F2F2F4830303000343434195351 + 5186D4CECEFFB35F44FFC9572FFFE16132FFD3592DFFEDEDEDFFEEEEEEFFD359 + 2DFFE15F30FFC8532AFFB35F44FFD0C9C9FF515050863434341937373747ACAA + AAD7C09789FFBF5631FFD85F33FFD55A2DFFCB542AFFE2E2E2FFEDEDEDFFCB54 + 2AFFD55A2DFFD55A2DFFBC4F29FFBF9588FFA29F9FD7373737473A3A3A61D0CF + CFFFB9745DFFCF643EFFC9542AFFC9542AFFC25028FFD6D6D6FFE2E2E2FFC250 + 28FFC9542AFFC9542AFFC5542CFFB9745DFFC2C0C0FF3A3A3A613E3E3E6ECCCC + CCFFB95737FFD5714DFFBF502AFFBD4E27FFB94B26FFCDCDCDFFD6D6D6FFB94B + 26FFBD4E27FFBD4E27FFC1542EFFB95737FFC0C0C0FF3E3E3E6E4242426CCFCF + CFFFBC5B3BFFDD7D5BFFC96240FFBD5330FFB24925FFCCCCCCFFCDCDCDFFB148 + 24FFB34925FFB34925FFBD5532FFBC5B3BFFC3C3C3FF4242426C4545455CDBDC + DCFFC07C65FFDF805EFFCF6947FFCF6947FFCA6442FFAE4826FFAC4523FFB049 + 27FFAD4624FFAD4624FFC3603EFFC07C65FFCBCCCCFF4545455C48484842BEBF + BFD4C9A295FFD57452FFE2815FFFD87250FFCD6745FFFFFFFFFFFFFFFFFFCD67 + 45FFD87250FFDF7C5AFFD16E4CFFC7A194FFB2B3B3D4484848424B4B4B176C6C + 6C7CDFE0E0FFC8755AFFE28361FFEB8A68FFD56F4DFFFFFFFFFFFFFFFFFFD56F + 4DFFEA8866FFDF7E5CFFC8755AFFD8D8D8FF6969697C4B4B4B174E4E4E004E4E + 4E3F9D9D9DA2DFDFDFFFCB795EFFDB7A58FFEE906EFFF49674FFF49573FFED8E + 6CFFDA7856FFCB795EFFDBDCDCFF999999A24E4E4E3F4E4E4E004F4F4F005050 + 50075151514D9F9F9FA1E6E6E6FFD7B0A3FFD08C75FFCD6C4BFFCD6C4BFFD08C + 75FFD6AFA2FFE3E4E4FF9D9D9DA15151514D505050074F4F4F004F4F4F005050 + 5000525252075353533D73737378C8C8C8D2EAEAEAFFE6E6E6FFE6E6E6FFEAEA + EAFFC7C7C7D2727272785353533D52525207505050004F4F4F004F4F4F005050 + 50005252520053535300545454155555553E5555555555555563555555635555 + 55555555553E545454155353530052525200505050004F4F4F00 + } ImageIndex = 0 SubMenuImages = IconList OnClick = miFavoritesViewInfosClick end object miFavoritesDownloadAll: TMenuItem Caption = 'Download all' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } ImageIndex = 1 OnClick = miFavoritesDownloadAllClick end @@ -5071,6 +5462,42 @@ object MainForm: TMainForm end object miFavoritesDelete: TMenuItem Caption = 'Delete' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000 + 000E00000014000000190000001900000016000000100000000B000000080000 + 0007000000080000000B0000000E0000001100000013FFFFFF00FFFFFF000000 + 001C0000325E000059CC000057BC0000164200000020000000160000000F0000 + 000D00000010000000150000001B00001D3800002D4CFFFFFF00FFFFFF000000 + 180000005FCC1111DBFE0C0CAFEC00005F8B0000190000000000000000000000 + 000000000000000000000000320000005F7300004832FFFFFF00FFFFFF000000 + 66000000668C0A0A9FE51212DDFF030378D30000673300005100000000000000 + 00000000380000006A00000066840000668900006404FFFFFF00FFFFFF000000 + 6C0000006D1F00006ECC1515D1FB1111C3F400006EB400007011000070000000 + 78000000720000006E8200006EB800006D4100006C00FFFFFF00FFFFFF000000 + 700000007000000075670D0D96DC1717CCFF0F0FA2E50000777500007E000000 + 7A000000769104048AD5000076860000730000007200FFFFFF00FFFFFF000000 + 78000000780000007B0000007E911515A6E51D1DBEFD07078AD400007F630000 + 7EAE0A0A94DC00007EB600007A000000780000007800FFFFFF00FFFFFF000000 + 8000000080000000800000008215000086B01A1AA8E72222B4F907078ED21414 + 9FE105058DD20000820000007C000000780000007800FFFFFF00FFFFFF000000 + 9F0000009E00000098000000900000008D3300008ECC3131BCF33333BCFA0909 + 97D400008E0000008F0000008E0000008E000000A500FFFFFF00FFFFFF000000 + 9F0000009E00000098330000968A000096CC4141CDEE5151D9FD2727B7E32F2F + BEE3000096B100009A1800009F000000A4000000A500FFFFFF00FFFFFF000000 + 9F0000009F6600009ECC3737C9E56262EAFF5858E3FA1616AFD600009A330E0E + A99F2828BEDD00009EB400009F1F0000A4000000A500FFFFFF00FFFFFF000000 + A4000000A4CC7474FCFF6B6BF4FE3636CDE50000A4CC0000A10000009A000000 + 9E000000A3890606A8CF0000A4BD0000A54A0000A501FFFFFF00FFFFFF000000 + A8000000A9480000A9CC0000A9CC0000A9930000A7000000A20000009A000000 + 9E000000A4000000A82B0000A97E0000A9B00000A966FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 9 SubMenuImages = IconList OnClick = miFavoritesDeleteClick @@ -5089,12 +5516,84 @@ object MainForm: TMainForm end object miFavoritesOpenFolder: TMenuItem Caption = 'Open Folder' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000060000 + 00160000001A0000001A0000001A0000001A0000001A0000001A0000001A0000 + 001A0000001A0000001A0000001A0000001A000000160000000600476A91005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D + 8CBD005D8CBD005D8CBD005D8CBD005D8CBD005D8CBD00476A9100679AB086CF + F0FF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF82CB + EDFF82CBEDFF82CBEDFF82CBEDFF82CBEDFF86CFF0FF00679AB00070A9A286CF + EEFF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8 + E8FF7DC8E8FF7DC8E8FF7DC8E8FF7DC8E8FF86CFEEFF0070A9A20074AD9D8AD3 + F0FF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF82CC + EBFF82CCEBFF82CCEBFF82CCEBFF82CCEBFF8AD3F0FF0074AD9D0076B2998FD7 + F2FF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF87D0 + EDFF87D0EDFF87D0EDFF87D0EDFF87D0EDFF8FD7F2FF0076B2990079B69594DB + F4FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5 + F0FF8DD5F0FF8DD5F0FF8DD5F0FF8DD5F0FF94DBF4FF0079B695007CBA9299E0 + F6FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF92DA + F3FF92DAF3FF92DAF3FF92DAF3FF92DAF3FF99E0F6FF007CBA92007FBD8E9FE5 + F9FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF98DF + F6FF98DFF6FF98DFF6FF98DFF6FF98DFF6FF9FE5F9FF007FBD8E0081C18BA3E9 + FBFF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FF9DE3F9FFA3E9FAFFA3E9 + FAFFA3E9FAFFA3E9FAFFA3E9FAFFA3E9FAFFA6ECFBFF0081C18B0083C488A8ED + FDFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFA2E7FBFFABF0FDFF85CAE6FF78BC + DEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF78BCDEFF0083C4880085C785AEF3 + FFFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF89CDE9FF89CDE9FFABF0 + FEFFABF0FEFFABF0FEFFABF0FEFFABF0FEFFAEF3FFFF0085C7850087CA630087 + CA830087CA830087CA830087CA830087CA830087CA830087CA83FEFEFDFFF8F8 + F3FFF0F0E6FFE9E9DBFFFEC941FFF4B62EFF0087CA830087CA630087CA000087 + CA000087CA000087CA000087CA000087CA000087CA000088CC2E0088CC810088 + CC810088CC810088CC810088CC810088CC810088CC2E0087CA00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 4 SubMenuImages = IconList OnClick = miFavoritesOpenFolderClick end object miFavoritesOpenWith: TMenuItem Caption = 'Open ...' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000000000 + 00000000000000000000000000100000001A0000001000000000000000000000 + 00000000000000000000000000000000000000000000000000001007000F220E + 00352A110048000000620000008F000000ED0000008F000000622A110048200D + 003A130800300703002A050200290502002906030023020100095322009A8550 + 27D78E623DDF67655AF7ACAA9AFD9B9B8AFFACAA9AFD67655AF78E623DDF8550 + 27D7793D12D0703104CC6F2F02CB6F2F02CB6F2F02CB5322009A793400C0C5C5 + B7FFCECEC1FFDDDDD0FFE7E7D7FF9F9F8EFFEAEAD9FFDCDCCCFFCDCDBDFFC5C5 + B4FFBEBEAEFFBBBBAAFFBBBBAAFFBBBBAAFFBBBBAAFF793400C0873E00B5FFFF + FEFFF9F9F4FFF1F1E7FFE9E9DBFFA4A493FFEFEFDEFFF0F0E1FFF3F3E6FFF6F6 + EAFFF8F8EFFFFBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFF873E00B58D4200B0FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFA9A998FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFF8D4200B0914500ADFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFAFAF9EFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFC4C4B3FFD9D9C8FFDCDCCBFFFFFFFEFF914500AD954700AAFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFB4B4A3FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF954700AA994A00A7FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBABAA9FFEFEFDEFFF0F0E0FF0B7395FF168B + A9FF1EA8C0FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFF994A00A79C4C00A4FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFBFBFAEFFEFEFDEFFF0F0E0FF2F5C7CFF3DC6 + DFFF49E0F1FFF9F9F2FFEAEAD9FFEDEDDCFFFFFFFEFF9C4C00A4A04E00A2FEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC4C4B3FFEFEFDEFFF0F0E0FF17B0D2FF18B1 + D3FF18B2D3FFF9F9F2FFD9D9C8FFD4D4C3FFFFFFFEFFA04E00A2A351009FFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFC8C8B7FFEFEFDEFFF0F0E0FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA351009FA652009DFEFE + FDFFF8F8F3FFF0F0E6FFE9E9DBFFCCCCBBFFEFEFDEFFF0F0E0FFBCBCABFFBEBE + ADFFD2D2C1FFCDCDBCFFFBFBF6FFFDFDFAFFFFFFFEFFA652009DA854009BFEFE + FDFFF8F8F3FFF1F1E7FFE9E9D9F27F7F5566ECECD9F2F1F1E1FFF2F2E4FFF4F4 + E8FFF6F6EDFFF9F9F2FFFBFBF6FFFDFDFAFFFFFFFEFFA854009BAA55009AF6F6 + F3EBE8E8DDD7C9C9B2B49C9C78767F7F55319B9B7776C7C7ADB4E3E3D2D7EFEF + E2EBF6F6ECF9FBFBF4FFFCFCF7FFFEFEFBFFFFFFFEFFAA55009A7F7F55497F7F + 55577F7F55497F7F552E7F7F550E7F7F55007F7F550E7F7F552E7F7F55497F7F + 55577F7F55617F7F55667F7F55667F7F55667F7F55667F7F554D + } ImageIndex = 11 OnClick = miFavoritesOpenWithClick end @@ -5106,18 +5605,126 @@ object MainForm: TMainForm top = 238 object miMangaListViewInfos: TMenuItem Caption = 'View manga infos' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF000000 + 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 + 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 + 0000000000040000001B481F1546B24C3399E96443D4EE6644F5EE6644F5E964 + 43D4B24C3399471F15470000001F0000000600000000FFFFFF00FFFFFF007432 + 210077332200B34D3360EF6F4FEBF5A28FFFFAD1CAFFFCE7E5FFFCE6E5FFF9D1 + C9FFF4A18EFFEF6E4EEBB34D33603C1A110000000000FFFFFF00FFFFFF00E863 + 4100EE664460EF7659F9F7D4CEFFF7E9E9FFF7E8E8FFFCF4F4FFFCF4F4FFF7E8 + E8FFF7E9E9FFF6D1CAFFEF7658F9EE664460E8634100FFFFFF00FFFFFF00E360 + 3E20E66A4AEBF3D3CDFFF0E5E5FFEFE4E4FFEFE4E4FFE5613FFFE5613FFFEFE4 + E4FFEFE4E4FFEFE4E4FFEFCDC7FFE66A4AEBE3603E20FFFFFF00FFFFFF00D659 + 3787E59D8AFFEAE2E2FFE7DFDFFFE7DFDFFFE7DFDFFFD65937FFD65937FFE7DF + DFFFE7DFDFFFE7DFDFFFE8E0E0FFE19784FFD6593787FFFFFF00FFFFFF00C550 + 2ED0EAD0C8FFE1DADAFFE0D9D9FFE0D9D9FFE0D9D9FFC5502EFFC5502EFFE0D9 + D9FFE0D9D9FFE0D9D9FFE0D9D9FFE1C4BDFFC5502ED0FFFFFF00FFFFFF00B748 + 26F5F4EEEDFFE7E5E5FFDAD6D6FFD8D4D4FFD8D4D4FFB74826FFB74826FFD8D4 + D4FFD8D4D4FFD8D4D4FFD8D4D4FFE1D8D6FFB74826F5FFFFFF00FFFFFF00AD44 + 22F5F4EFEDFFEEEEEEFFEAEAEAFFDCDBDBFFD3D1D1FFAD4422FFAD4422FFD2D0 + D0FFD2D0D0FFD2D0D0FFD2D0D0FFDFD8D7FFAD4422F5FFFFFF00FFFFFF00AB46 + 24D0EAD5CDFFF0F0F0FFF0F0F0FFF0F0F0FFEBEBEBFFE9E9E9FFE7E6E6FFD2D1 + D1FFCECECEFFCECECEFFD2D1D1FFDCC7C0FFAB4624D0FFFFFF00FFFFFF00B34F + 2D87D49D8AFFF5F5F5FFF3F3F3FFF3F3F3FFF3F3F3FFB34F2DFFB34F2DFFF3F3 + F3FFF3F3F3FFF3F3F3FFF5F5F5FFD49C89FFB34F2D87FFFFFF00FFFFFF00BF5C + 3A20C56747EBF2DFD9FFF8F8F8FFF7F7F7FFF7F7F7FFC15D3BFFC15D3BFFF7F7 + F7FFF7F7F7FFF8F8F8FFF2DFD9FFC56747EBBF5C3A20FFFFFF00FFFFFF00C461 + 3F00CF6B4960D77F61F9F6E3DCFFFCFCFCFFFBFBFBFFFBFBFBFFFBFBFBFFFBFB + FBFFFCFCFCFFF6E3DCFFD77F61F9CF6B4960C4613F00FFFFFF00FFFFFF00C461 + 3F00D16D4B00DF7A5860E38464EBEFB7A4FFFAE4DDFFFEF9F7FFFEF9F7FFFAE4 + DDFFEFB7A4FFE38464EBDF7A5860D16D4B00C4613F00FFFFFF00FFFFFF00C461 + 3F00D16D4B00E17C5A00EA846220EC866487EC8664D0EC8664F5EC8664F5EC86 + 64D0EC866487EA846220E17C5A00D16D4B00C4613F00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } ImageIndex = 13 SubMenuImages = IconList OnClick = miMangaListViewInfosClick end object miMangaListDownloadAll: TMenuItem Caption = 'Download all' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000120000 + 002C0D0D0D581212128512121285121212851212128512121285121212851212 + 12851212128512121285121212850D0D0D580000002C00000012000000090000 + 00162A2A2A7AB3B3B3DFDBDBDBFFD6D7D7FFCDCFCFFFC7C8C8FFC4C4C4FFC5C4 + C4FFC9C4C4FFC6BBBBFFA59A9ADF2A2A2A7A0000001600000009000000002B2B + 2B0038383873E9E9E9FFB0B0B0FF858585FF7E7F7FFF787979FF787777FF7E77 + 77FF857777FF66FF66FFD7C8C8FF383838732B2B2B0000000000333333004343 + 43004343436EFAFAFAFFF8F8F8FFEFF0F0FFE7E8E8FFE0E1E1FFDDDDDDFFDEDD + DDFFE2DDDDFFD7CCCCFFE8D9D9FF4343436E43434300333333004D4D4D004D4D + 4D004D4D4D5DC3C3C3DAD1D1D1FFC8C9C9FFBEC0C0FFB6B7B7FFB3B3B3FFB4B3 + B3FFB9B3B3FFBFB3B3FFB5A9A9DA4D4D4D5D4D4D4D004D4D4D004F4F4F004F4F + 4F005151510D5454545A54545467545454675454546754545467545454675454 + 546754545467545454675454545A5151510D4F4F4F004F4F4F004F4F4F004F4F + 4F00515151005555550055555500555555006653410075502B1F75502B1F6653 + 4100555555005555550055555500515151004F4F4F004F4F4F004F4F4F004F4F + 4F0051515100555555006A5844008E561D009B50055CA95F07D3A95F06D39B50 + 055C8E561D006A58440055555500515151004F4F4F004F4F4F00855F3600855F + 3600866037009E662800AC611100A3580B5CB0670ED4FFC53AFFFFBD20FFB066 + 0DD4A3580B5CAC6111009E66280086603700855F3600855F3600BA6F1C00BA6F + 1C00BA6F1C00B76C1A00AD62125CB97117D4FECB4DFFFEB714FFFEB102FFFEC0 + 2CFFB86F15D4AD62125CB76C1A00BA6F1C00BA6F1C00BA6F1C00BA6F1C00BA6F + 1C00BA6F1C00B96E1B5CC27B23D5FAD171FFF9CC65FFF5B833FFF1A913FFF6BD + 3FFFF7C554FFC0781FD4B96E1B5CBA6F1C00BA6F1C00BA6F1C00BF752000BF75 + 2000BF752000C177218FC27822B8C27822B8C27822CCEEC26AFFDE9C2CFFC278 + 22CCC27822B8C27822B8C177218FBF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200C57A2400C87D2700CE832BCCF1CA83FFD89B4AFFCE83 + 2BCCC87D2700C57A2400C2782200BF752000BF752000BF752000BF752000BF75 + 2000BF752000C2782200CB802900D98E3300D98E33ABF9D591D5EEB367D5D98E + 33AAD98E3300CB802900C2782200BF752000BF752000BF752000D2872E00D287 + 2E00D2872E00D3892F00E2973A00E2973A00E2973A6AFCDC9884F5BF7385E297 + 3A6AE2973A00E2973A00D3892F00D2872E00D2872E00D2872E00E99E3F00E99E + 3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F33FFE39E40FED18540E99E + 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 + } ImageIndex = 1 SubMenuImages = IconList OnClick = miMangaListDownloadAllClick end object miMangaListAddToFavorites: TMenuItem Caption = 'Add to Favorites' + Bitmap.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000000000050000 + 001E0000003200009CC9000054630000002E0000002B00000026000000220000 + 001D00000018054F00A1056800CF0550009D0000000500000002000000030000 + 000F000000190000A8C50000A8C500006D580000001600000013000000110000 + 000F0000000C0C8200CE2BDF1AFF0C8200CD000000030000000101018F000101 + 5F0001018C000000B6BF6969FFFF0000B6BF0000B84301016000074700000E8D + 00990E8C00CC0E8C00CC3DE22CFF0E8C00CC0E8C00CC0E8D00990101BFBB0101 + BFBB0101BFBB0101BFBB6262F8FF6C6CFFFF0101BFBB0101C042094B61001095 + 00CC52E741FF52E741FF52E741FF52E741FF52E741FF109500CC0101C3410101 + C3B96969FFFF6262F8FF5F5FF5FF5C5CF1FF6E6EFFFF0101C3B90101C441129C + 0099129D00CC129D00CC66EB55FF129D00CC129D00CC129C00990101C3000101 + C7410101C7B86C6CFFFF5C5CF1FF5D5DF2FF5F5FF3FF7171FFFF0101C7B80629 + 96410F79330014A400CC75EE64FF14A400CC13A10000129D00000101C3000101 + C7000101CB400101CBB66E6EFFFF5F5FF3FF6060F4FF6262F4FF7575FFFF0101 + CBB60101CC4015A9009915A900CC15A9009914A80000129D00000101C3000101 + C7000101CB000101CE400101CEB57171FFFF6262F4FF6464F5FF6565F6FF7878 + FFFF0101CEB5062C9B3F1080350015A9000014A80000129D00000101C3000101 + C7000101CB000101CE000101D23F0101D2B37575FFFF6565F6FF6767F7FF6868 + F8FF7B7BFFFF0101D2B30101D33F0101D5000101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D53F0101D5B27878FFFF6868F8FF6A6A + F9FF6C6CF9FF7E7EFFFF0101D5B20101D63E0101D9000101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D93E0101D9B17B7BFFFF6C6C + F9FF6D6DFAFF6F6FFBFF8181FFFF0101D9B10101D93E0101DC000101C3000101 + C7000101CB000101CE000101D2000101D5000101D9000101DC3E0101DCAF7E7E + FFFF6F6FFBFF7070FCFF7171FCFF8484FFFF0101DCAF0101DC3E000000000101 + 64000101CB000101CE000101D2000101D5000101D9000101DC000101DE3E0101 + DEAE8181FFFF7171FCFF7373FDFF7474FDFF8686FFFF0101DEAE000000000000 + 0000000000000101B4000101D2000101D5000101D9000101DC000101DE000101 + E13D0101E1AD8484FFFF7474FDFF8686FFFF0101E1AD0101E13D000000000000 + 0000000000000000990000002B0001016B000101D9000101DC000101DE000101 + E1000101E33C0101E3AC8686FFFF0101E3AC0101E33C0101E100000000000000 + 0000000000000000990000002B00000000000000000001016E000101DE000101 + E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 + } ImageIndex = 2 SubMenuImages = IconList OnClick = miMangaListAddToFavoritesClick diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 51a6ccc6b..2c39407a9 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1296,13 +1296,17 @@ procedure TMainForm.FormCreate(Sender: TObject); TransferRateGraph.Visible := False; // minimize on start - Application.ShowMainForm := False; + if configfile.ReadBool('general', 'MinimizeOnStart', False) then + Application.ShowMainForm := False; + + LoadFormInformation; + CollectLanguagesFromFiles; + ApplyLanguage; - isStartup := False; with TTimer.Create(nil) do begin OnTimer := @tmStartupTimer; - Interval := 16; + Interval := 100; Enabled := True; end; end; @@ -1801,21 +1805,14 @@ procedure TMainForm.tmRefreshDownloadsInfoTimer(Sender: TObject); procedure TMainForm.tmStartupTimer(Sender: TObject); begin - isStartup := True; - //load lua modules ScanLuaWebsiteModulesFile; AddToAboutStatus('Modules', IntToStr(Modules.Count)); // load configfile - CollectLanguagesFromFiles; LoadMangaOptions; LoadOptions; ApplyOptions; - LoadFormInformation; - - if not cbOptionMinimizeOnStart.Checked then - Self.Show; //restore everything after all modules loaded DLManager.Restore; @@ -5235,8 +5232,6 @@ procedure TMainForm.ApplyOptions; on E: Exception do ExceptionHandle(Self, E); end; - if isStartup then - DLManager.CheckAndActiveTask; end; procedure TMainForm.LoadMangaOptions; @@ -5556,15 +5551,15 @@ procedure TMainForm.LoadFormInformation; psDownloads.Position := ReadInteger('form', 'DownloadsSplitter', psDownloads.Position); psInfo.Position := ReadInteger('form', 'MangaInfoSplitter', psInfo.Position); - if cbOptionAutoCheckFavStartup.Checked and cbOptionAutoOpenFavStartup.Checked then + if ReadBool('update', 'AutoCheckFavStartup', True) and ReadBool('update', 'AutoOpenFavStartup', False) then pcMain.ActivePage := tsFavorites else pcMain.PageIndex := ReadInteger('form', 'pcMainPageIndex', 0); - Left := ReadInteger('form', 'MainFormLeft', MainForm.Left); - Top := ReadInteger('form', 'MainFormTop', MainForm.Top); - Width := ReadInteger('form', 'MainFormWidth', 640); - Height := ReadInteger('form', 'MainFormHeight', 480); + Left := ReadInteger('form', 'MainFormLeft', Left); + Top := ReadInteger('form', 'MainFormTop', Top); + Width := ReadInteger('form', 'MainFormWidth', Width); + Height := ReadInteger('form', 'MainFormHeight', Height); if ReadBool('form', 'MainFormMaximized', False) then PrevWindowState := wsMaximized @@ -5572,6 +5567,10 @@ procedure TMainForm.LoadFormInformation; PrevWindowState := wsNormal; WindowState := PrevWindowState; + ToolBarDownload.Visible := ReadBool('view', 'ShowDownloadsToolbar', True); + ToolBarDownloadLeft.Visible := ReadBool('view', 'ShowDownloadsToolbarLeft', True); + tbDownloadDeleteCompleted.Visible := ReadBool('view', 'ShowDownloadsToolbarDeleteAll', False); + restorevt(vtDownload, 'vtDownload'); DLManager.SortColumn := vtDownload.Header.SortColumn; DLManager.SortDirection := Boolean(vtDownload.Header.SortDirection); From b93573f4ccb7191a119f5eee393c3bd0947895c1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 02:29:21 +0800 Subject: [PATCH 2317/2794] Bump version 0.9.147.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index c53eb0d21..9893ce88a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.147.0 (19-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.146.0...0.9.147.0 + 0.9.146.0 (18-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.145.0...0.9.146.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b87e99931..ab41ed218 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="146"/> + <RevisionNr Value="147"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 08d6c0801..821679dbc 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.146.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.146.0/fmd_0.9.146.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.146.0/fmd_0.9.146.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.146.0/fmd_0.9.146.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.146.0/fmd_0.9.146.0_Win64.7z +VERSION=0.9.147.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.147.0/fmd_0.9.147.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.147.0/fmd_0.9.147.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.147.0/fmd_0.9.147.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.147.0/fmd_0.9.147.0_Win64.7z From 1fc0089e3b497a35a0eefd263e7eb8cd8d1845dd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 02:39:49 +0800 Subject: [PATCH 2318/2794] fix missing summary on mangalist hint --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 2c39407a9..7fdcbd6fd 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5892,6 +5892,7 @@ procedure TMainForm.vtMangaListInitNode(Sender: TBaseVirtualTree; ParentNode, numchapter := dataProcess.ValueInt[Node^.Index, DATA_PARAM_NUMCHAPTER]; jdn := dataProcess.ValueInt[Node^.Index, DATA_PARAM_JDN]; website := dataProcess.WebsiteName[Node^.Index]; + summary := dataProcess.Value[Node^.Index, DATA_PARAM_SUMMARY]; titleformat := title + ' (' + IntToStr(numchapter) + ')'; if dataProcess.FilterAllSites then titleformat += ' [' + website + ']'; From 21113b873253848f563ac312f9d0e477019dcbbe Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 10:01:30 +0800 Subject: [PATCH 2319/2794] update Spanish translation --- mangadownloader/languages/fmd.es.po | 147 +++++++++++++++------------- 1 file changed, 78 insertions(+), 69 deletions(-) diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 2f01ffbe5..69b6cb3fc 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1,39 +1,37 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: FMD Español 2.0.2\n" +"Project-Id-Version: FMD Español 2.0.5\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Language-Team: Mariolr\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.3\n" +"X-Generator: Poedit 2.0.6\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "Last-Translator: Mariolr\n" "Language: es_419\n" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" -msgstr "Cancelar" +msgstr "Abortar" #: dbupdater.rs_downloading msgid "Downloading %s" -msgstr "" +msgstr "Descargando %s" #: dbupdater.rs_extracting msgid "Extracting %s" -msgstr "" +msgstr "Extrayendo %s" #: dbupdater.rs_faileddownload msgid "%s: %d %s" -msgstr "" +msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "" +msgstr "%s: falló en extraer, exitstatus = %d" #: dbupdater.rs_faileditems msgid "" @@ -41,20 +39,22 @@ msgid "" "\n" "%s\n" msgstr "" +"Falló en terminar:\n" +"\n" +"%s\n" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Fallido" #: dbupdater.rs_failedtosave msgid "%s: failed to save" -msgstr "" +msgstr "%s: falló en guardar" #: dbupdater.rs_missingzipexe msgid "%s: Missing %s" -msgstr "" +msgstr "%s: Perdido %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" @@ -117,7 +117,6 @@ msgid "List of unimported manga" msgstr "Lista de manga sin importar" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Revisando..." @@ -125,15 +124,15 @@ msgstr "Revisando..." #: frmluamodulesupdater.rs_checkupdate msgctxt "frmluamodulesupdater.rs_checkupdate" msgid "Check update" -msgstr "" +msgstr "Revisar actualización" #: frmluamodulesupdater.rs_finishchecking msgid "Finish checking" -msgstr "" +msgstr "Revisión finalizada" #: frmluamodulesupdater.rs_finishdownload msgid "Finish download" -msgstr "" +msgstr "Descarga terminada" #: frmluamodulesupdater.rs_modulesupdatedrestart msgid "" @@ -141,10 +140,13 @@ msgid "" "\n" "%s\n" msgstr "" +"Módulos Actualizados, Reiniciar Ahora?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "" +msgstr "Módulos Actualizados!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "" @@ -152,14 +154,17 @@ msgid "" "\n" "%s\n" msgstr "" +"Actualización de Módulos Encontrada, Cualquier Cambio Local Será Perdido, Proceder?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "" +msgstr "Actualización de Módulos Encontrada!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." -msgstr "" +msgstr "Descargando..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" @@ -394,6 +399,10 @@ msgid "" "CBZ\n" "PDF\n" msgstr "" +"Ninguno\n" +"ZIP\n" +"CBZ\n" +"PDF\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -430,6 +439,9 @@ msgid "" "PNG\n" "JPEG\n" msgstr "" +"WebP\n" +"PNG\n" +"JPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -438,6 +450,10 @@ msgid "" "Default\n" "Maximum\n" msgstr "" +"Ninguno\n" +"El Más Rápido\n" +"Por Defecto\n" +"Máximo\n" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -462,18 +478,17 @@ msgstr "Sistema se Apagará en %d segundos." #: frmtransferfavorites.rs_all msgctxt "frmtransferfavorites.rs_all" msgid "All" -msgstr "" +msgstr "Todo" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" -msgstr "Inválido" +msgstr "No Valido" #: frmtransferfavorites.rs_valid msgctxt "frmtransferfavorites.rs_valid" msgid "Valid" -msgstr "" +msgstr "Valido" #: kissmanga.rs_kissmanga_initvector msgid "Initialization Vector:" @@ -506,14 +521,13 @@ msgid "Save as PNG" msgstr "Guardar como PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Abortar" #: selfupdater.rs_downloading msgid "Downloading new version %s" -msgstr "" +msgstr "Descargando Nueva Versión %s" #: selfupdater.rs_faileddownload msgid "" @@ -521,32 +535,34 @@ msgid "" "\n" "%d %s\n" msgstr "" +"Ha Fallado En Descargar Nueva Versión %s\n" +"\n" +"%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" -msgstr "" +msgstr "Ha Fallado en Extraer %s, exitstatus = %d" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Fallido" #: selfupdater.rs_failedtosave msgid "Failed to save %s" -msgstr "" +msgstr "Falló en Guardar %s" #: selfupdater.rs_finishrestart msgid "Download update package finished, restart to proceed?" -msgstr "" +msgstr "La Descarga del Paquete ha Terminado, Proceder en Reiniciar?" #: selfupdater.rs_finishrestarttitle msgid "Download finished" -msgstr "" +msgstr "Descarga Finalizada" #: selfupdater.rs_missingzipexe msgid "Missing %s" -msgstr "" +msgstr "Perdido %s" #: taccountmanagerform.btadd.caption msgctxt "taccountmanagerform.btadd.caption" @@ -697,27 +713,27 @@ msgstr "Software:" #: tluamodulesupdaterform.btcheckupdate.caption msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" -msgstr "" +msgstr "Revisar actualización" #: tluamodulesupdaterform.ckautorestart.caption msgid "Auto restart" -msgstr "" +msgstr "Auto Reinicio" #: tluamodulesupdaterform.ckshowupdatewarning.caption msgid "Show update warning" -msgstr "" +msgstr "Mostrar Advertencia de Actualización" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" -msgstr "" +msgstr "Nombre del Archivo" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text msgid "Last modified" -msgstr "" +msgstr "Última Modificación" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text msgid "Last message" -msgstr "" +msgstr "Último Mensaje" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -850,7 +866,7 @@ msgstr "Habilitar Esto si Tienes Algún Problema con Caracteres Unicode en la Ru #: tmainform.cboptiondeletecompletedtasksonclose.caption msgid "Delete completed tasks on close" -msgstr "" +msgstr "Eliminar Las Tareas Completadas Al Cerrar" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -919,7 +935,7 @@ msgstr "Mostrar \"Eliminar Todas las Tareas Completadas\" en la Barra de Herrami #: tmainform.cboptionshowdownloadtoolbarleft.caption msgid "Show left downloads toolbar" -msgstr "" +msgstr "Mostar Barra de Herramientas de Descargas Izquierda" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -940,7 +956,7 @@ msgstr "Usar Proxy" #: tmainform.cbpngcompressionlevel.text msgctxt "tmainform.cbpngcompressionlevel.text" msgid "Fastest" -msgstr "" +msgstr "El Más Rápido" #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" @@ -957,7 +973,7 @@ msgstr "Regular Expresión" #: tmainform.cbwebpsaveas.text msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" -msgstr "" +msgstr "PNG" #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" @@ -1287,11 +1303,11 @@ msgstr "Este trabajo involucra generalmente relaciones íntimas entre mujeres." #: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" -msgstr "" +msgstr "Siempre Empezar Tareas desde Capítulos Fallídos" #: tmainform.ckpngsaveasjpeg.caption msgid "Save PNG as JPEG" -msgstr "" +msgstr "Guardar PNG como JPEG" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" @@ -1401,7 +1417,7 @@ msgstr "Drop Box" #: tmainform.gbimageconversion.caption msgid "Image Conversion" -msgstr "" +msgstr "Conversión de Imagen" #: tmainform.gboptionexternal.caption msgid "External program" @@ -1485,7 +1501,7 @@ msgstr "Título" #: tmainform.lbjpegquality.caption msgid "JPEG quality" -msgstr "" +msgstr "Calidad JPEG" #: tmainform.lblogfilename.caption msgid "Log file:" @@ -1666,7 +1682,7 @@ msgstr "Renombrar Dígitos" #: tmainform.lboptionretryfailedtask.caption msgid "Number of retry times if task failed" -msgstr "" +msgstr "Número de Reintentos si la Tarea ha Fallado" #: tmainform.lboptionuser.caption msgctxt "tmainform.lboptionuser.caption" @@ -1676,7 +1692,7 @@ msgstr "Usuario" #: tmainform.lbpngcompressionlevel.caption msgctxt "tmainform.lbpngcompressionlevel.caption" msgid "PNG Compression level" -msgstr "" +msgstr "Nivel de Compresión PNG" #: tmainform.lbsaveto.caption msgid "Save to:" @@ -1684,7 +1700,7 @@ msgstr "Guardar en:" #: tmainform.lbwebpsaveas.caption msgid "Save WebP as" -msgstr "" +msgstr "Guardar WebP como" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" @@ -1864,7 +1880,7 @@ msgstr "Abrir ..." #: tmainform.mifavoritesrename.caption msgid "Rename" -msgstr "" +msgstr "Renombrar" #: tmainform.mifavoritesstopchecknewchapter.caption msgid "Stop check for new chapter" @@ -1873,7 +1889,7 @@ msgstr "Detener Revisar si hay Nuevo Capitulo" #: tmainform.mifavoritestransferwebsite.caption msgctxt "tmainform.mifavoritestransferwebsite.caption" msgid "Transfer website" -msgstr "" +msgstr "Transferir Sitio Web" #: tmainform.mifavoritesviewinfos.caption msgctxt "TMAINFORM.MIFAVORITESVIEWINFOS.CAPTION" @@ -2012,19 +2028,19 @@ msgstr "Detener Todo" #: tmainform.tbmidownloadmovebottom.hint msgid "Move selected item(s) to bottom" -msgstr "" +msgstr "Mover Ítem(s) Seleccionado(s) al Final" #: tmainform.tbmidownloadmovedown.hint msgid "Move selected item(s) down" -msgstr "" +msgstr "Mover Ítem(s) Seleccionado(s) Abajo" #: tmainform.tbmidownloadmovetop.hint msgid "Move selected item(s) to top" -msgstr "" +msgstr "Mover Ítem(s) Seleccionado(s) al Inicio" #: tmainform.tbmidownloadmoveup.hint msgid "Move selected item(s) up" -msgstr "" +msgstr "Mover Ítem(s) Seleccionado(s) Arriba" #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" @@ -2121,7 +2137,7 @@ msgstr "Avanzado" #: tmainform.tswebsitemodules.caption msgid "Modules" -msgstr "" +msgstr "Módulos" #: tmainform.tswebsiteoptions.caption msgctxt "tmainform.tswebsiteoptions.caption" @@ -2227,55 +2243,49 @@ msgid "&Now" msgstr "&Ahora" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Cancelar" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" #: ttransferfavoritesform.caption msgid "Transfer Favorites" -msgstr "" +msgstr "Transferir Favoritos" #: ttransferfavoritesform.ckcleardownloadedchapters.caption msgid "Clear downloaded chapter list and reload from server" -msgstr "" +msgstr "Limpiar Lista de Capítulos Descargados y Volver a Cargar desde Servidor" #: ttransferfavoritesform.lbtransferto.caption msgctxt "ttransferfavoritesform.lbtransferto.caption" msgid "Transfer to" -msgstr "" +msgstr "Transferir a" #: ttransferfavoritesform.rball.caption msgctxt "ttransferfavoritesform.rball.caption" msgid "All" -msgstr "" +msgstr "Todo" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" -msgstr "Inválido" +msgstr "No Valido" #: ttransferfavoritesform.rbvalid.caption msgctxt "ttransferfavoritesform.rbvalid.caption" msgid "Valid" -msgstr "" +msgstr "Valido" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Sitio Web" +msgstr "Título" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Sitio Web" @@ -2563,4 +2573,3 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" - From 1390ed7f1395b2a764bb27bf9db98ebd3371382c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 10:09:09 +0800 Subject: [PATCH 2320/2794] add mouse click event on cbselectmanga, middle click to confirm the selection --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index a9facdd66..c529353ed 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -552,6 +552,7 @@ object MainForm: TMainForm '' ) OnEditingDone = cbSelectMangaEditingDone + OnMouseDown = cbSelectMangaMouseDown ParentShowHint = False ShowHint = True Sorted = True diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 7fdcbd6fd..482dcd7ea 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -441,6 +441,8 @@ TMainForm = class(TForm) procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderChange(Sender: TObject); procedure cbSelectMangaEditingDone(Sender: TObject); + procedure cbSelectMangaMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); @@ -2579,6 +2581,13 @@ procedure TMainForm.cbSelectMangaEditingDone(Sender: TObject); end; end; +procedure TMainForm.cbSelectMangaMouseDown(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + if Button = mbMiddle then + cbSelectMangaEditingDone(Sender); +end; + procedure TMainForm.btReadOnlineClick(Sender: TObject); begin OpenURL(mangaInfo.url); From 49f80618c7ca036904ca9eb852a7ba2e0178fc9d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 11:24:50 +0800 Subject: [PATCH 2321/2794] httpsendthread, remove owner.oncustomterminate on destroy sometimes there is access violation log --- baseunits/httpsendthread.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 406845954..8909c96b8 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -445,6 +445,8 @@ constructor THTTPSendThread.Create(AOwner: TBaseThread); destructor THTTPSendThread.Destroy; begin + If Assigned(FOwner) then + FOwner.OnCustomTerminate := nil; EnterCriticalsection(CS_ALLHTTPSendThread); try ALLHTTPSendThread.Remove(Self); @@ -719,4 +721,4 @@ finalization ALLHTTPSendThread.Free; DoneCriticalsection(CS_ALLHTTPSendThread); -end. \ No newline at end of file +end. From 210e58da7c4e22fa4815df54258c65b4473f632c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 18 Feb 2018 08:48:17 +0300 Subject: [PATCH 2322/2794] add MyMangaIO [FR] (no manga list) #993 --- lua/modules/MyMangaIO.lua | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 lua/modules/MyMangaIO.lua diff --git a/lua/modules/MyMangaIO.lua b/lua/modules/MyMangaIO.lua new file mode 100644 index 000000000..b4d079c00 --- /dev/null +++ b/lua/modules/MyMangaIO.lua @@ -0,0 +1,84 @@ +local hitmanga = 'http://www.hitmanga.eu' +local hitmangalistener = 'http://www.hitmanga.eu/listener/' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local s=TStrings.Create() + s.loadfromstream(http.document) + local str=string.gsub(s.text, '%-%-!>', '-->') + local x=TXQuery.Create(str) + mangainfo.title=x.xpathstring('//div[@id="picture"]//h2') + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[@id="picture"]/div/img/@src')) + mangainfo.authors=x.xpathstringall('//div[@id="mangafiche"]//table//tr[contains(th, "Auteur")]/td/a') + mangainfo.authors=x.xpathstringall('//div[@id="mangafiche"]//table//tr[contains(th, "Illustrateur")]/td/a') + mangainfo.genres=x.xpathstringall('//div[@id="mangafiche"]//table//tr[contains(th, "Genre")]/td/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@id="mangafiche"]//table//tr[contains(th, "Statut")]/td/a'), 'cours', 'termin') + mangainfo.summary=x.xpathstring('//section[@id="synopsis"]/p') + v=x.xpath('//section[contains(@class, "listchapseries")]/ul/li') + for i=1,v.count do + v1=v.get(i) + mangainfo.chapterlinks.add(x.xpathstring('div/a[contains(i/@class, "fa-book")]/@href', v1)) + mangainfo.chapternames.add(x.xpathstring('p/span[@class="chapter"]', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpath(str) + local path = '' + local i = 1 + for l in string.gmatch(str, "[^/]*") do + if i == 6 then break end + path = path .. l .. '/' + i = i + 1 + end + return path +end + +function getpagenumber() + if http.get(MaybeFillHost(hitmanga,url)) then + local s=TStrings.Create() + s.loadfromstream(http.document) + local str=string.gsub(s.text, '%-%-!>', '-->') + local x=TXQuery.Create(str) + local link = x.xpathstring('//*[@id="loadReadPages"]/@data-permalink') + local num = x.xpathstring('//*[@id="loadReadPages"]/@data-number') + local src = getpath(x.xpathstring('//*[@id="chpimg"]/@src')) + local q = 'type=chap-pages&permalink='..link..'&number='..num + http.reset() + if http.post(hitmangalistener, q) then + local s = TStrings.Create() + s.loadfromstream(http.document) + for l in string.gmatch(s.text, "[^|]+") do + task.pagelinks.add(src .. string.gsub(l, '#', '%%23')) + end + return true + else + return false + end + return true + else + return false + end + return true +end + +function getnameandlink() + -- FIXME: manga directory shows only first 300 titles. + return no_error +end + +function Init() + m=NewModule() + m.category='French' + m.website='MyMangaIO' + m.rooturl='http://www.mymanga.io' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From af0d951155fb03b908d03f70db9ec26d0acc185d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 06:56:21 +0300 Subject: [PATCH 2323/2794] add MangaHub [EN] fixes #823 #1004 --- lua/modules/MangaHubIO.lua | 106 +++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 lua/modules/MangaHubIO.lua diff --git a/lua/modules/MangaHubIO.lua b/lua/modules/MangaHubIO.lua new file mode 100644 index 000000000..07fb49e60 --- /dev/null +++ b/lua/modules/MangaHubIO.lua @@ -0,0 +1,106 @@ +local perpage = 30 +local apiurl = 'https://api.mangahub.io/graphql' +local cdnurl = 'https://cdn.mangahub.io/file/imghub/' + +function getx() + if module.website == 'MangaReaderSite' then + return "mr01" + elseif module.website == 'MangaFoxFun' then + return "mf01" + elseif module.website == 'MangaKakalotFun' then + return "mn01" + else + return "m01" + end +end + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@id="mangadetail"]//h1/text()') + mangainfo.coverlink=x.xpathstring('//div[@id="mangadetail"]//img/@src') + mangainfo.authors=x.xpathstring('//div[@id="mangadetail"]//div/span[contains(., "Author")]/following-sibling::span') + mangainfo.artists=x.xpathstring('//div[@id="mangadetail"]//div/span[contains(., "Artist")]/following-sibling::span') + mangainfo.genres=x.xpathstringall('//div[@id="mangadetail"]//div/p/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@id="mangadetail"]//div/span[contains(., "Status")]/following-sibling::span')) + mangainfo.summary=x.xpathstring('//div[contains(@id, "noanim-content-tab-pane")]/div/p') + v=x.xpath('//div[contains(@id, "noanim-content-tab-pane")]/ul/li/a') + for i=1,v.count do + v1=v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + mangainfo.chapternames.add(x.xpathstring('span', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + local chapter = url:match('/chapter%-(%d+)') + local slug = url:match('/chapter/(.+)/') + local q = '{"query":"{chapter(x:'..getx()..',slug:\\"'..slug..'\\",number:'..chapter..'){id,title,mangaID,number,slug,date,pages,manga{id,title,slug,mainSlug,isWebtoon,isYaoi}}}"}' + http.mimetype = 'application/json' + if http.post(apiurl, q) then + x=TXQuery.Create(http.Document) + v=x.xpath('json(json(*).data.chapter.pages)/*') + for i = 1, v.count do + v1=v.get(i) + task.pagelinks.add(cdnurl .. v1.toString) + end + else + return false + end + return true +end + +function getnameandlink() + local offset = perpage * tonumber(url) + local q = '{"query":"{search(x:'..getx()..',q:\\"\\",genre:\\"all\\",mod:ALPHABET,count:true,offset:'..tostring(offset)..'){rows{id,title, slug},count}}"}' + http.mimetype = 'application/json' + if http.post(apiurl, q) then + x = TXQuery.Create(http.Document) + x.xpathstringall('json(*).data.search.rows()/concat("'..module.rooturl..'/manga/", slug)', links) + x.xpathstringall('json(*).data.search.rows().title', names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + local q = '{"query":"{search(x:'..getx()..',q:\\"\\",genre:\\"all\\",mod:ALPHABET,count:true,offset:0){rows{id,title, slug},count}}"}' + http.mimetype = 'application/json' + if http.post(apiurl, q) then + x = TXQuery.Create(http.Document) + local total = tonumber(x.xpathstring('json(*).data.search.count')) + if total == nil then total = 1 end + page = math.floor(total / perpage) + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(name, url) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = 'English' + m.lastupdated='February 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + return m +end + +function Init() + AddWebsiteModule('MangaHubIO', 'https://mangahub.io') + AddWebsiteModule('MangaReaderSite', 'https://mangareader.site') + AddWebsiteModule('MangaFoxFun', 'https://mangafox.fun') + AddWebsiteModule('MangaKakalotFun', 'https://mangakakalot.fun') +end From a33650ab91bd82428e538c03f5ca701b8970eb70 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 09:27:42 +0300 Subject: [PATCH 2324/2794] fix form scaling --- mangadownloader/forms/frmMain.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 482dcd7ea..6def45ce9 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5570,6 +5570,13 @@ procedure TMainForm.LoadFormInformation; Width := ReadInteger('form', 'MainFormWidth', Width); Height := ReadInteger('form', 'MainFormHeight', Height); + if Screen.PixelsPerInch > 96 then begin + Width := ScaleScreenTo96(Width); + Height := ScaleScreenTo96(Height); + psDownloads.Position := ScaleScreenTo96(psDownloads.Position); + psInfo.Position := ScaleScreenTo96(psInfo.Position); + end; + if ReadBool('form', 'MainFormMaximized', False) then PrevWindowState := wsMaximized else From c3701458b6eaf0cea6bddf1e9a7d7fcb00c83931 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 09:33:30 +0300 Subject: [PATCH 2325/2794] set 'Adult' category in modules #1020 --- baseunits/modules/WPAdultSiteSkins.pas | 1 + config/mangalist.ini | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas index aff7ed295..f94e51c79 100644 --- a/baseunits/modules/WPAdultSiteSkins.pas +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -143,6 +143,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'Adult'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/config/mangalist.ini b/config/mangalist.ini index a39b5ffd4..096921bc2 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -18,4 +18,3 @@ Turkish=Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan Webcomics=Tapas H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,PervEden,PervEden_IT,Tsumino,YaoiChanRU -Adult=Comic-XXX,FreeAdultComix,PornComix From a69f3dce94d584ef53850f49febc2d5cf145dd40 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:02:46 +0300 Subject: [PATCH 2326/2794] set 'H-Sites' category in modules #1020 --- baseunits/modules/Doujinmoeus.pas | 1 + baseunits/modules/EHentai.pas | 1 + baseunits/modules/Hakihome.pas | 1 + baseunits/modules/Hentai2Read.pas | 1 + baseunits/modules/HentaiCafe.pas | 1 + baseunits/modules/HentaiFox.pas | 1 + baseunits/modules/HitomiLa.pas | 1 + baseunits/modules/Luscious.pas | 1 + baseunits/modules/MangaChanRU.pas | 9 +++++---- baseunits/modules/MangaEden.pas | 11 ++++++----- baseunits/modules/MyReadingManga.pas | 1 + baseunits/modules/Tsumino.pas | 1 + config/mangalist.ini | 1 - 13 files changed, 21 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas index c0e40a512..5704f8c57 100644 --- a/baseunits/modules/Doujinmoeus.pas +++ b/baseunits/modules/Doujinmoeus.pas @@ -159,6 +159,7 @@ procedure RegisterModule; begin Website := 'Doujin-Moe'; RootURL := 'http://www.doujin-moe.us'; + Category := 'H-Sites'; SortedList := True; FavoriteAvailable := False; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 84a32478f..eb74af083 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -407,6 +407,7 @@ procedure RegisterModule; with Result do begin Website := AWebsite; RootURL := ARootURL; + Category := 'H-Sites'; MaxTaskLimit := 1; MaxConnectionLimit := 2; SortedList := True; diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas index 8791ece4a..053280bef 100644 --- a/baseunits/modules/Hakihome.pas +++ b/baseunits/modules/Hakihome.pas @@ -158,6 +158,7 @@ procedure RegisterModule; begin Website := 'Hakihome'; RootURL := 'http://hakihome.com'; + Category := 'H-Sites'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 383bd43d9..4ba18d3b8 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -164,6 +164,7 @@ procedure RegisterModule; begin Website := 'Hentai2Read'; RootURL := 'http://hentai2read.com'; + Category := 'H-Sites'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/HentaiCafe.pas b/baseunits/modules/HentaiCafe.pas index fa1089542..fdb2419b1 100644 --- a/baseunits/modules/HentaiCafe.pas +++ b/baseunits/modules/HentaiCafe.pas @@ -133,6 +133,7 @@ procedure RegisterModule; begin Website := 'HentaiCafe'; RootURL := 'https://hentai.cafe'; + Category := 'H-Sites'; SortedList := True; FavoriteAvailable := False; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/baseunits/modules/HentaiFox.pas b/baseunits/modules/HentaiFox.pas index f28a26fe2..bcf67936f 100644 --- a/baseunits/modules/HentaiFox.pas +++ b/baseunits/modules/HentaiFox.pas @@ -93,6 +93,7 @@ procedure RegisterModule; begin Website := 'HentaiFox'; RootURL := 'https://hentaifox.com'; + Category := 'H-Sites'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas index 5098ea854..4e88a7172 100644 --- a/baseunits/modules/HitomiLa.pas +++ b/baseunits/modules/HitomiLa.pas @@ -140,6 +140,7 @@ procedure RegisterModule; begin Website := 'HitomiLa'; RootURL := 'https://hitomi.la'; + Category := 'H-Sites'; SortedList := True; FavoriteAvailable := False; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/baseunits/modules/Luscious.pas b/baseunits/modules/Luscious.pas index 64f4b7f3a..939465854 100644 --- a/baseunits/modules/Luscious.pas +++ b/baseunits/modules/Luscious.pas @@ -112,6 +112,7 @@ procedure RegisterModule; begin Website := 'Luscious'; RootURL := 'https://luscious.net'; + Category := 'H-Sites'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/MangaChanRU.pas b/baseunits/modules/MangaChanRU.pas index 3c8009878..c6f399a7c 100644 --- a/baseunits/modules/MangaChanRU.pas +++ b/baseunits/modules/MangaChanRU.pas @@ -144,12 +144,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; procedure RegisterModule; - procedure AddWebsiteModule(const AWebsite, ARootURL: String); + procedure AddWebsiteModule(const AWebsite, ARootURL, ACategory: String); begin with AddModule do begin Website := AWebsite; RootURL := ARootURL; + Category := ACategory; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; @@ -159,9 +160,9 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaChanRU', 'http://mangachan.me'); - AddWebsiteModule('HentaiChanRU', 'http://hentai-chan.me'); - AddWebsiteModule('YaoiChanRU', 'http://yaoichan.me'); + AddWebsiteModule('MangaChanRU', 'http://mangachan.me', 'Russian'); + AddWebsiteModule('HentaiChanRU', 'http://hentai-chan.me', 'H-Sites'); + AddWebsiteModule('YaoiChanRU', 'http://yaoichan.me', 'H-Sites'); end; initialization diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas index 23df79cd2..2bf3f1b20 100644 --- a/baseunits/modules/MangaEden.pas +++ b/baseunits/modules/MangaEden.pas @@ -191,12 +191,13 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; procedure RegisterModule; - function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; + function AddWebsiteModule(const AWebsite, ARootURL, ACategory: String): TModuleContainer; begin Result := AddModule; with Result do begin Website := AWebsite; RootURL := ARootURL; + Category := ACategory; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; @@ -206,10 +207,10 @@ procedure RegisterModule; end; begin - MMangaEden := AddWebsiteModule('MangaEden', 'http://www.mangaeden.com'); - MMangaEdenIT := AddWebsiteModule('MangaEden_IT', 'http://www.mangaeden.com'); - MPervEden := AddWebsiteModule('PervEden', 'http://www.perveden.com'); - MPervEdenIT := AddWebsiteModule('PervEden_IT', 'http://www.perveden.com'); + MMangaEden := AddWebsiteModule('MangaEden', 'http://www.mangaeden.com', 'English'); + MMangaEdenIT := AddWebsiteModule('MangaEden_IT', 'http://www.mangaeden.com', 'Italian'); + MPervEden := AddWebsiteModule('PervEden', 'http://www.perveden.com', 'H-Sites'); + MPervEdenIT := AddWebsiteModule('PervEden_IT', 'http://www.perveden.com', 'H-Sites'); end; initialization diff --git a/baseunits/modules/MyReadingManga.pas b/baseunits/modules/MyReadingManga.pas index 10a0e084c..311a344c2 100644 --- a/baseunits/modules/MyReadingManga.pas +++ b/baseunits/modules/MyReadingManga.pas @@ -92,6 +92,7 @@ procedure RegisterModule; begin Website := 'MyReadingManga'; RootURL := 'https://myreadingmanga.info'; + Category := 'H-Sites'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/Tsumino.pas b/baseunits/modules/Tsumino.pas index 93f0629c6..ea37826f8 100644 --- a/baseunits/modules/Tsumino.pas +++ b/baseunits/modules/Tsumino.pas @@ -113,6 +113,7 @@ procedure RegisterModule; begin Website := 'Tsumino'; RootURL := 'http://www.tsumino.com'; + Category := 'H-Sites'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/config/mangalist.ini b/config/mangalist.ini index 096921bc2..9893f2826 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -17,4 +17,3 @@ Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Turkish=Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan Webcomics=Tapas -H-Sites=Doujin-Moe,E-Hentai,ExHentai,Hakihome,Hentai2Read,HentaiCafe,HentaiChanRU,HentaiFox,HitomiLa,Luscious,MyReadingManga,PervEden,PervEden_IT,Tsumino,YaoiChanRU From e11010622542bb12d8970032bec2e1448a955500 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:11:10 +0300 Subject: [PATCH 2327/2794] set 'Webcomics' category in modules #1020 --- baseunits/modules/Tapas.pas | 1 + config/mangalist.ini | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index 0326430f7..cb9481d4d 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -139,6 +139,7 @@ procedure RegisterModule; begin Website := 'Tapas'; RootURL := 'https://tapas.io'; + Category := 'Webcomics'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/config/mangalist.ini b/config/mangalist.ini index 9893f2826..1d7a8180f 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -16,4 +16,3 @@ Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Turkish=Manga-Tr,Puzzmos,WebtoonTr Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan -Webcomics=Tapas From 6bf55f447964024d165bc6a1972312103d52e32b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:15:53 +0300 Subject: [PATCH 2328/2794] set 'Vietnamese' category in modules #1020 --- baseunits/modules/AcademyVN.pas | 1 + baseunits/modules/Blogtruyen.pas | 1 + baseunits/modules/TruyenTranhTuan.pas | 1 + config/mangalist.ini | 1 - 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 2cc46fd5b..11a531eeb 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -120,6 +120,7 @@ procedure RegisterModule; begin Website := 'AcademyVN'; RootURL := 'http://truyen.academyvn.com'; + Category := 'Vietnamese'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/Blogtruyen.pas b/baseunits/modules/Blogtruyen.pas index 5dc1bd734..cba47931d 100644 --- a/baseunits/modules/Blogtruyen.pas +++ b/baseunits/modules/Blogtruyen.pas @@ -130,6 +130,7 @@ procedure RegisterModule; begin Website := 'BlogTruyen'; RootURL := 'http://blogtruyen.com'; + Category := 'Vietnamese'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/TruyenTranhTuan.pas b/baseunits/modules/TruyenTranhTuan.pas index 4c8cdd9ea..3a3232942 100644 --- a/baseunits/modules/TruyenTranhTuan.pas +++ b/baseunits/modules/TruyenTranhTuan.pas @@ -97,6 +97,7 @@ procedure RegisterModule; begin Website := 'TruyenTranhTuan'; RootURL := 'http://truyentranhtuan.com'; + Category := 'Vietnamese'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index 1d7a8180f..36eb1cdab 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -15,4 +15,3 @@ Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewTy Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline Turkish=Manga-Tr,Puzzmos,WebtoonTr -Vietnamese=AcademyVN,BlogTruyen,TruyenTranhTuan From 32447c1cef62f253f13313986836e9783577689d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:17:48 +0300 Subject: [PATCH 2329/2794] set 'Turkish' category in modules #1020 --- baseunits/modules/MangaTr.pas | 1 + baseunits/modules/WebtoonTr.pas | 1 + config/mangalist.ini | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaTr.pas b/baseunits/modules/MangaTr.pas index 9121180c4..2a62679c8 100644 --- a/baseunits/modules/MangaTr.pas +++ b/baseunits/modules/MangaTr.pas @@ -226,6 +226,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'Turkish'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/WebtoonTr.pas b/baseunits/modules/WebtoonTr.pas index d5f50f3cf..ecee03911 100644 --- a/baseunits/modules/WebtoonTr.pas +++ b/baseunits/modules/WebtoonTr.pas @@ -117,6 +117,7 @@ procedure RegisterModule; begin Website := 'WebtoonTr'; RootURL := 'http://webtoontr.com'; + Category := 'Turkish'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/config/mangalist.ini b/config/mangalist.ini index 36eb1cdab..f8431f9e9 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -14,4 +14,3 @@ Portugues=MangaOnlineBR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline -Turkish=Manga-Tr,Puzzmos,WebtoonTr From 185be8a56d19cd20c13c68c01d1d2f35acfe63a8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:20:13 +0300 Subject: [PATCH 2330/2794] set 'Arabic' category in modules #1020 --- baseunits/modules/GMangaMe.pas | 1 + baseunits/modules/MangaAe.pas | 1 + baseunits/modules/Mangaf.pas | 1 + config/mangalist.ini | 1 - 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/GMangaMe.pas b/baseunits/modules/GMangaMe.pas index 00b2e47ea..6d5e8a9ff 100644 --- a/baseunits/modules/GMangaMe.pas +++ b/baseunits/modules/GMangaMe.pas @@ -100,6 +100,7 @@ procedure RegisterModule; begin Website := 'GManga'; RootURL := 'http://gmanga.me'; + Category := 'Arabic'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaAe.pas b/baseunits/modules/MangaAe.pas index 2156fdfbf..302b56227 100644 --- a/baseunits/modules/MangaAe.pas +++ b/baseunits/modules/MangaAe.pas @@ -93,6 +93,7 @@ procedure RegisterModule; begin Website := 'MangaAe'; RootURL := 'https://www.manga.ae'; + Category := 'Arabic'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/Mangaf.pas b/baseunits/modules/Mangaf.pas index 9fb95f221..343d821a8 100644 --- a/baseunits/modules/Mangaf.pas +++ b/baseunits/modules/Mangaf.pas @@ -106,6 +106,7 @@ procedure RegisterModule; begin Website := 'Mangaf'; RootURL := 'http://mangaf.co'; + Category := 'Arabic'; TotalDirectory := 3; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/config/mangalist.ini b/config/mangalist.ini index f8431f9e9..c581ad1d9 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,7 +3,6 @@ DefaultSelect=MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] -Arabic=GManga,MangaAe,Mangaf English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Italian=MangaEden_IT,NineMangaIT English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay From 4d7c2f88007885a63bb542262fa9c2197c87c543 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:22:23 +0300 Subject: [PATCH 2331/2794] set 'Italian' category in modules #1020 --- baseunits/modules/NineManga.pas | 15 ++++++++------- config/mangalist.ini | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/baseunits/modules/NineManga.pas b/baseunits/modules/NineManga.pas index b2cde7277..8f938820c 100644 --- a/baseunits/modules/NineManga.pas +++ b/baseunits/modules/NineManga.pas @@ -136,13 +136,14 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; procedure RegisterModule; - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + function AddWebsiteModule(AWebsite, ARootURL, ACategory: String): TModuleContainer; begin Result := AddModule; with Result do begin Website := AWebsite; RootURL := ARootURL; + Category := ACategory; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; @@ -151,12 +152,12 @@ procedure RegisterModule; end; begin - AddWebsiteModule('NineManga', 'http://www.ninemanga.com'); - AddWebsiteModule('NineMangaES', 'http://es.ninemanga.com'); - AddWebsiteModule('NineMangaRU', 'http://ru.ninemanga.com'); - AddWebsiteModule('NineMangaDE', 'http://de.ninemanga.com'); - AddWebsiteModule('NineMangaIT', 'http://it.ninemanga.com'); - AddWebsiteModule('NineMangaBR', 'http://br.ninemanga.com'); + AddWebsiteModule('NineManga', 'http://www.ninemanga.com', 'English'); + AddWebsiteModule('NineMangaES', 'http://es.ninemanga.com', 'Spanish'); + AddWebsiteModule('NineMangaRU', 'http://ru.ninemanga.com', 'Russian'); + AddWebsiteModule('NineMangaDE', 'http://de.ninemanga.com', 'German'); + AddWebsiteModule('NineMangaIT', 'http://it.ninemanga.com', 'Italian'); + AddWebsiteModule('NineMangaBR', 'http://br.ninemanga.com', 'Portugues'); end; initialization diff --git a/config/mangalist.ini b/config/mangalist.ini index c581ad1d9..0d6fd1c71 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,7 +4,6 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd -Italian=MangaEden_IT,NineMangaIT English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay French=Japan-Shin,Japscan German=MangaTube,NineMangaDE,WieManga From 09b5a1d7940cb6cb6080ee4e836fcb8b4cc5165f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:23:37 +0300 Subject: [PATCH 2332/2794] set 'French' category in modules #1020 --- baseunits/modules/JapScan.pas | 1 + config/mangalist.ini | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas index fee35f8a1..bec3c8756 100644 --- a/baseunits/modules/JapScan.pas +++ b/baseunits/modules/JapScan.pas @@ -105,6 +105,7 @@ procedure RegisterModule; begin Website := 'Japscan'; RootURL := 'http://www.japscan.com'; + Category := 'French'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index 0d6fd1c71..76c8f936b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,7 +5,6 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay -French=Japan-Shin,Japscan German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics Portugues=MangaOnlineBR,NineMangaBR,UnionMangas From 5afee89473b7355bfe457337d6e6c876c688cc56 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:27:27 +0300 Subject: [PATCH 2333/2794] set 'Russian' category in modules #1020 --- baseunits/modules/MangaHubRU.pas | 1 + config/mangalist.ini | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHubRU.pas b/baseunits/modules/MangaHubRU.pas index 6113915db..80288da93 100644 --- a/baseunits/modules/MangaHubRU.pas +++ b/baseunits/modules/MangaHubRU.pas @@ -112,6 +112,7 @@ procedure RegisterModule; begin Website := 'MangaHubRU'; RootURL := 'https://mangahub.ru'; + Category := 'Russian'; SortedList := True; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index 76c8f936b..d0dd5896b 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -9,5 +9,4 @@ German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics Portugues=MangaOnlineBR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws -Russian=MangaChanRU,NineMangaRU,MangaHubRU Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline From 45debdf68001a400b689dd5c022bd8d27c959dea Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:28:49 +0300 Subject: [PATCH 2334/2794] set 'German' category in modules #1020 --- baseunits/modules/MangaTube.pas | 1 + baseunits/modules/WieManga.pas | 1 + config/mangalist.ini | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaTube.pas b/baseunits/modules/MangaTube.pas index 75ec85048..8f678a4df 100644 --- a/baseunits/modules/MangaTube.pas +++ b/baseunits/modules/MangaTube.pas @@ -123,6 +123,7 @@ procedure RegisterModule; begin Website := 'MangaTube'; RootURL := 'https://manga-tube.me'; + Category := 'German'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/WieManga.pas b/baseunits/modules/WieManga.pas index 1e5cbe96b..fb9f4ca12 100644 --- a/baseunits/modules/WieManga.pas +++ b/baseunits/modules/WieManga.pas @@ -113,6 +113,7 @@ procedure RegisterModule; begin Website := 'WieManga'; RootURL := 'https://www.wiemanga.com'; + Category := 'German'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index d0dd5896b..24f237378 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,7 +5,6 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay -German=MangaTube,NineMangaDE,WieManga Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics Portugues=MangaOnlineBR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws From 34cf85ed8ad9d05eb19ae6014b2abbde9023a7a6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:30:22 +0300 Subject: [PATCH 2335/2794] set 'Portugues' category in modules #1020 --- baseunits/modules/MangaOnlineBR.pas | 1 + baseunits/modules/UnionMangas.pas | 1 + config/mangalist.ini | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaOnlineBR.pas b/baseunits/modules/MangaOnlineBR.pas index fa791741f..041dc4976 100644 --- a/baseunits/modules/MangaOnlineBR.pas +++ b/baseunits/modules/MangaOnlineBR.pas @@ -106,6 +106,7 @@ procedure RegisterModule; begin Website := 'MangaOnlineBR'; RootURL := 'http://mangaonline.com.br'; + Category := 'Portugues'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas index f76cec866..74d4f1a6c 100644 --- a/baseunits/modules/UnionMangas.pas +++ b/baseunits/modules/UnionMangas.pas @@ -88,6 +88,7 @@ procedure RegisterModule; begin Website := 'UnionMangas'; RootURL := 'http://unionmangas.net'; + Category := 'Portugues'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/config/mangalist.ini b/config/mangalist.ini index 24f237378..1c22a0e77 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -6,6 +6,5 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics -Portugues=MangaOnlineBR,NineMangaBR,UnionMangas Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline From 79441c1a4a6493732edbbafeddcb3bfa4988b8b1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:33:43 +0300 Subject: [PATCH 2336/2794] set 'Spanish' category in modules #1020 --- baseunits/modules/KuManga.pas | 1 + baseunits/modules/LeoManga.pas | 1 + baseunits/modules/SekaiManga.pas | 1 + baseunits/modules/Submanga.pas | 1 + baseunits/modules/Tumangaonline.pas | 1 + config/mangalist.ini | 1 - 6 files changed, 5 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/KuManga.pas b/baseunits/modules/KuManga.pas index ba0e1d42e..c0e4e5ef3 100644 --- a/baseunits/modules/KuManga.pas +++ b/baseunits/modules/KuManga.pas @@ -164,6 +164,7 @@ procedure RegisterModule; begin Website := 'KuManga'; RootURL := 'http://www.kumanga.com'; + Category := 'Spanish'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/LeoManga.pas b/baseunits/modules/LeoManga.pas index 3db55fc48..c21a9e70d 100644 --- a/baseunits/modules/LeoManga.pas +++ b/baseunits/modules/LeoManga.pas @@ -140,6 +140,7 @@ procedure RegisterModule; begin Website := 'LeoManga'; RootURL := 'http://leomanga.com'; + Category := 'Spanish'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/SekaiManga.pas b/baseunits/modules/SekaiManga.pas index 6c4ebec9d..938e767c4 100644 --- a/baseunits/modules/SekaiManga.pas +++ b/baseunits/modules/SekaiManga.pas @@ -121,6 +121,7 @@ procedure RegisterModule; begin Website := 'SekaiManga'; RootURL := 'http://www.sekaimanga.net'; + Category := 'Spanish'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/Submanga.pas index 897c20592..7b3997b78 100644 --- a/baseunits/modules/Submanga.pas +++ b/baseunits/modules/Submanga.pas @@ -147,6 +147,7 @@ procedure RegisterModule; begin Website := 'SubManga'; RootURL := 'http://submanga.com'; + Category := 'Spanish'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 1218b27a5..20cc48462 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -169,6 +169,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Tumangaonline'; RootURL := 'https://www.tumangaonline.com'; + Category := 'Spanish'; MaxTaskLimit := 1; MaxConnectionLimit := 1; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index 1c22a0e77..7b18356cb 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -7,4 +7,3 @@ English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBack English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws -Spanish=KuManga,LeoManga,NineMangaES,SekaiManga,SubManga,Tumangaonline From 2a835817761611f07bb3cdc8a83bffaec93316ee Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:35:54 +0300 Subject: [PATCH 2337/2794] set 'English-Scanlation' category in modules #1020 --- baseunits/modules/GameofScanlation.pas | 1 + baseunits/modules/MangaZuki.pas | 7 ++++--- baseunits/modules/PsychoPlay.pas | 1 + config/mangalist.ini | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas index 0ad865ab3..290114874 100644 --- a/baseunits/modules/GameofScanlation.pas +++ b/baseunits/modules/GameofScanlation.pas @@ -137,6 +137,7 @@ procedure RegisterModule; begin Website := 'GameofScanlation'; RootURL := 'https://gameofscanlation.moe'; + Category := 'English-Scanlation'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaZuki.pas b/baseunits/modules/MangaZuki.pas index 1780f20a6..9f0fd1dd3 100644 --- a/baseunits/modules/MangaZuki.pas +++ b/baseunits/modules/MangaZuki.pas @@ -97,12 +97,13 @@ function GetPageNumber(const DownloadThread: TDownloadThread; procedure RegisterModule; - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + function AddWebsiteModule(AWebsite, ARootURL, ACategory: String): TModuleContainer; begin Result := AddModule; with Result do begin Website := AWebsite; RootURL := ARootURL; + Category := ACategory; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; @@ -111,8 +112,8 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaZuki', 'https://mangazuki.co'); - AddWebsiteModule('MangaZukiRaws', 'https://raws.mangazuki.co'); + AddWebsiteModule('MangaZuki', 'https://mangazuki.co', 'English-Scanlation'); + AddWebsiteModule('MangaZukiRaws', 'https://raws.mangazuki.co', 'Raw'); end; initialization diff --git a/baseunits/modules/PsychoPlay.pas b/baseunits/modules/PsychoPlay.pas index ed48cc2f6..f96f1d436 100644 --- a/baseunits/modules/PsychoPlay.pas +++ b/baseunits/modules/PsychoPlay.pas @@ -114,6 +114,7 @@ procedure RegisterModule; begin Website := 'PsychoPlay'; RootURL := 'https://psychoplay.co'; + Category := 'English-Scanlation'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/config/mangalist.ini b/config/mangalist.ini index 7b18356cb..acf3ed67c 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,6 +4,5 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd -English-Scanlation=GameofScanlation,MangaZuki,PsychoPlay Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws From be25d559d8ada45f843a72e328b73136122dc1af Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:39:28 +0300 Subject: [PATCH 2338/2794] set 'Raw' category in modules #1020 --- baseunits/modules/Comico.pas | 1 + baseunits/modules/Lhscans.pas | 1 + baseunits/modules/NewType.pas | 1 + baseunits/modules/RawSenManga.pas | 1 + baseunits/modules/SundayWebEvery.pas | 1 + baseunits/modules/TonarinoYoungJump.pas | 1 + baseunits/modules/YoungAceUp.pas | 1 + config/mangalist.ini | 1 - 8 files changed, 7 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/Comico.pas b/baseunits/modules/Comico.pas index e4a5cef1c..1b9a02745 100644 --- a/baseunits/modules/Comico.pas +++ b/baseunits/modules/Comico.pas @@ -155,6 +155,7 @@ procedure RegisterModule; begin Website := 'Comico'; RootURL := 'http://www.comico.jp'; + Category := 'Raw'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/Lhscans.pas b/baseunits/modules/Lhscans.pas index 37dc77d2c..8e13bd6c6 100644 --- a/baseunits/modules/Lhscans.pas +++ b/baseunits/modules/Lhscans.pas @@ -81,6 +81,7 @@ procedure RegisterModule; begin Website := 'Lhscans'; RootURL := 'http://lhscans.com'; + Category := 'Raw'; TotalDirectory := 1; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/NewType.pas b/baseunits/modules/NewType.pas index 46e609271..ab6406787 100644 --- a/baseunits/modules/NewType.pas +++ b/baseunits/modules/NewType.pas @@ -127,6 +127,7 @@ procedure RegisterModule; begin Website := 'NewType'; RootURL := 'https://comic.webnewtype.com'; + Category := 'Raw'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index c22894751..5667aeb69 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -174,6 +174,7 @@ procedure RegisterModule; begin Website := 'RawSenManga'; RootURL := 'http://raw.senmanga.com'; + Category := 'Raw'; MaxTaskLimit := 1; MaxConnectionLimit := 4; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/SundayWebEvery.pas b/baseunits/modules/SundayWebEvery.pas index 588db6b9b..ccb0ce25b 100644 --- a/baseunits/modules/SundayWebEvery.pas +++ b/baseunits/modules/SundayWebEvery.pas @@ -146,6 +146,7 @@ procedure RegisterModule; begin Website := 'SundayWebEvery'; RootURL := 'https://www.sunday-webry.com'; + Category := 'Raw'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonarinoYoungJump.pas index 82e4d3ea8..0848a6661 100644 --- a/baseunits/modules/TonarinoYoungJump.pas +++ b/baseunits/modules/TonarinoYoungJump.pas @@ -174,6 +174,7 @@ procedure RegisterModule; begin Website := 'TonarinoYoungJump'; RootURL := 'https://tonarinoyj.jp'; + Category := 'Raw'; TotalDirectory := Length(dirurls); OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/YoungAceUp.pas b/baseunits/modules/YoungAceUp.pas index afa0563c7..33d335c24 100644 --- a/baseunits/modules/YoungAceUp.pas +++ b/baseunits/modules/YoungAceUp.pas @@ -101,6 +101,7 @@ procedure RegisterModule; begin Website := 'YoungAceUp'; RootURL := 'https://web-ace.jp/youngaceup'; + Category := 'Raw'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index acf3ed67c..be39c2df2 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -5,4 +5,3 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics -Raw=Lhscans,RawSenManga,SundayWebEvery,Comico,TonarinoYoungJump,YoungAceUp,NewType,MangaZukiRaws From dfd7f748997b47b71c24669b15b0b5c9c028cd2e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:43:43 +0300 Subject: [PATCH 2339/2794] set 'Indonesian' category in modules #1020 --- baseunits/modules/MangaIndo.pas | 1 + baseunits/modules/MangaShiro.pas | 1 + baseunits/modules/Mangacan.pas | 1 + baseunits/modules/PecintaKomik.pas | 1 + config/mangalist.ini | 1 - 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/MangaIndo.pas b/baseunits/modules/MangaIndo.pas index d83c9c026..3b1643734 100644 --- a/baseunits/modules/MangaIndo.pas +++ b/baseunits/modules/MangaIndo.pas @@ -73,6 +73,7 @@ procedure RegisterModule; begin Website := 'MangaIndo'; RootURL := 'http://mangaindo.web.id'; + Category := 'Indonesian'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas index dbd708fe8..1b021a5a9 100644 --- a/baseunits/modules/MangaShiro.pas +++ b/baseunits/modules/MangaShiro.pas @@ -79,6 +79,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'Indonesian'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/Mangacan.pas b/baseunits/modules/Mangacan.pas index 33bd5fdbe..ad71a4ed4 100644 --- a/baseunits/modules/Mangacan.pas +++ b/baseunits/modules/Mangacan.pas @@ -83,6 +83,7 @@ procedure RegisterModule; begin Website := 'Mangacan'; RootURL := 'http://www.mangacanblog.com'; + Category := 'Indonesian'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas index e2d0a6752..f8251ac98 100644 --- a/baseunits/modules/PecintaKomik.pas +++ b/baseunits/modules/PecintaKomik.pas @@ -130,6 +130,7 @@ procedure RegisterModule; begin Website := 'PecintaKomik'; RootURL := 'http://www.pecintakomik.com'; + Category := 'Indonesian'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index be39c2df2..f89993700 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -4,4 +4,3 @@ DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/do [available] English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd -Indonesian=Komikid,Mangacan,MangaIndo,MangaKita,MangaShiro,Mangavy,PecintaKomik,Subapics From 2675c0c4d250f540140bdcff398a6d2a0b30d1bf Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:53:16 +0300 Subject: [PATCH 2340/2794] set 'English' category in modules #1020 --- baseunits/modules/EatManga.pas | 1 + baseunits/modules/FunManga.pas | 1 + baseunits/modules/GoodManga.pas | 1 + baseunits/modules/HeyMangaXyz.pas | 1 + baseunits/modules/KissManga.pas | 1 + baseunits/modules/Madokami.pas | 1 + baseunits/modules/MangaBackup.pas | 1 + baseunits/modules/MangaCool.pas | 1 + baseunits/modules/MangaFox.pas | 1 + baseunits/modules/MangaGo.pas | 1 + baseunits/modules/MangaHere.pas | 1 + baseunits/modules/MangaHome.pas | 1 + baseunits/modules/MangaInn.pas | 1 + baseunits/modules/MangaLife.pas | 1 + baseunits/modules/MangaPark.pas | 1 + baseunits/modules/MangaReader.pas | 1 + baseunits/modules/MangaRock.pas | 1 + baseunits/modules/MangaSaurus.pas | 1 + baseunits/modules/MangaStreamTo.pas | 1 + baseunits/modules/MangaTail.pas | 1 + baseunits/modules/MangaWindow.pas | 1 + baseunits/modules/Mangadex.pas | 1 + baseunits/modules/Mangakakalot.pas | 1 + baseunits/modules/MyMangaMe.pas | 1 + baseunits/modules/ReadComics.pas | 1 + baseunits/modules/ReadMangaToday.pas | 1 + baseunits/modules/SenManga.pas | 1 + baseunits/modules/Taadd.pas | 1 + baseunits/modules/Webtoons.pas | 1 + config/mangalist.ini | 1 - 30 files changed, 29 insertions(+), 1 deletion(-) diff --git a/baseunits/modules/EatManga.pas b/baseunits/modules/EatManga.pas index 5aae56fac..77ef0b037 100644 --- a/baseunits/modules/EatManga.pas +++ b/baseunits/modules/EatManga.pas @@ -80,6 +80,7 @@ procedure RegisterModule; begin Website := 'EatManga'; RootURL := 'http://eatmanga.me'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/FunManga.pas b/baseunits/modules/FunManga.pas index e8a6fa564..4c32212ea 100644 --- a/baseunits/modules/FunManga.pas +++ b/baseunits/modules/FunManga.pas @@ -118,6 +118,7 @@ procedure RegisterModule; begin Website := 'FunManga'; RootURL := 'http://www.funmanga.com'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/GoodManga.pas b/baseunits/modules/GoodManga.pas index 7c881c48c..c712ad74c 100644 --- a/baseunits/modules/GoodManga.pas +++ b/baseunits/modules/GoodManga.pas @@ -121,6 +121,7 @@ procedure RegisterModule; begin Website := 'GoodManga'; RootURL := 'http://www.goodmanga.net'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas index 802854015..b62dfaa01 100644 --- a/baseunits/modules/HeyMangaXyz.pas +++ b/baseunits/modules/HeyMangaXyz.pas @@ -136,6 +136,7 @@ procedure RegisterModule; begin Website := 'HeyManga'; RootURL := 'https://www.heymanga.me'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 6b6c1c087..13bb6b1ee 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -291,6 +291,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'English'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index fe84c460c..649891618 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -281,6 +281,7 @@ procedure RegisterModule; begin Website := modulename; RootURL := urlroot; + Category := 'English'; AccountSupport := True; //MaxTaskLimit := 1; //MaxConnectionLimit := 4; diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas index 87c2c6cab..2782a4311 100644 --- a/baseunits/modules/MangaBackup.pas +++ b/baseunits/modules/MangaBackup.pas @@ -130,6 +130,7 @@ procedure RegisterModule; begin Website := 'MangaBackup'; RootURL := 'http://mangabackup.com'; + Category := 'English'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/MangaCool.pas b/baseunits/modules/MangaCool.pas index 48cd4be72..6a5def55d 100644 --- a/baseunits/modules/MangaCool.pas +++ b/baseunits/modules/MangaCool.pas @@ -95,6 +95,7 @@ procedure RegisterModule; begin Website := 'MangaCool'; RootURL := 'http://mangacool.se'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index 38c749ac0..f8867db50 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -118,6 +118,7 @@ procedure RegisterModule; begin Website := 'MangaFox'; RootURL := 'http://fanfox.net'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas index 24ed32a0a..17ed8187c 100644 --- a/baseunits/modules/MangaGo.pas +++ b/baseunits/modules/MangaGo.pas @@ -343,6 +343,7 @@ procedure RegisterModule; begin Website := 'MangaGo'; RootURL := 'http://www.mangago.me'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index c9ebce29b..676329a6f 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -136,6 +136,7 @@ procedure RegisterModule; begin Website := 'MangaHere'; RootURL := 'http://www.mangahere.cc'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaHome.pas b/baseunits/modules/MangaHome.pas index 2b5350aa7..5863296b5 100644 --- a/baseunits/modules/MangaHome.pas +++ b/baseunits/modules/MangaHome.pas @@ -159,6 +159,7 @@ procedure RegisterModule; begin Website := 'MangaHome'; RootURL := 'http://www.mangahome.com'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MangaInn.pas b/baseunits/modules/MangaInn.pas index 64f2439c5..d74f6e415 100644 --- a/baseunits/modules/MangaInn.pas +++ b/baseunits/modules/MangaInn.pas @@ -106,6 +106,7 @@ procedure RegisterModule; begin Website := 'MangaInn'; RootURL := 'http://www.mangainn.net'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 015371c4c..30143e0f7 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -232,6 +232,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MangaPark.pas b/baseunits/modules/MangaPark.pas index fd3e0d6ad..0f5af3ad7 100644 --- a/baseunits/modules/MangaPark.pas +++ b/baseunits/modules/MangaPark.pas @@ -143,6 +143,7 @@ procedure RegisterModule; begin Website := 'MangaPark'; RootURL := 'http://mangapark.me'; + Category := 'English'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; diff --git a/baseunits/modules/MangaReader.pas b/baseunits/modules/MangaReader.pas index 840859943..80b4e8268 100644 --- a/baseunits/modules/MangaReader.pas +++ b/baseunits/modules/MangaReader.pas @@ -202,6 +202,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas index 018008ae5..457766348 100644 --- a/baseunits/modules/MangaRock.pas +++ b/baseunits/modules/MangaRock.pas @@ -202,6 +202,7 @@ procedure RegisterModule; begin Website := 'MangaRock'; RootURL := 'https://mangarock.com'; + Category := 'English'; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnDownloadImage := @DownloadImage; diff --git a/baseunits/modules/MangaSaurus.pas b/baseunits/modules/MangaSaurus.pas index d52ad1268..d848f10ab 100644 --- a/baseunits/modules/MangaSaurus.pas +++ b/baseunits/modules/MangaSaurus.pas @@ -190,6 +190,7 @@ procedure RegisterModule; begin Website := 'MangaSaurus'; RootURL := 'http://mangasaurus.com'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas index b26144c92..5c83b083f 100644 --- a/baseunits/modules/MangaStreamTo.pas +++ b/baseunits/modules/MangaStreamTo.pas @@ -118,6 +118,7 @@ procedure RegisterModule; begin Website := 'MangaStreamTo'; RootURL := 'http://www.mangastream.to'; + Category := 'English'; InformationAvailable := False; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MangaTail.pas b/baseunits/modules/MangaTail.pas index 484508ef9..1f53af29e 100644 --- a/baseunits/modules/MangaTail.pas +++ b/baseunits/modules/MangaTail.pas @@ -116,6 +116,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/MangaWindow.pas b/baseunits/modules/MangaWindow.pas index 695844312..93a4a9253 100644 --- a/baseunits/modules/MangaWindow.pas +++ b/baseunits/modules/MangaWindow.pas @@ -142,6 +142,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'English'; SortedList := True; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index 68cdefb0e..f3b0b55bf 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -139,6 +139,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Mangadex'; RootURL := 'https://mangadex.com'; + Category := 'English'; MaxTaskLimit := 4; MaxConnectionLimit := 4; TotalDirectory := Length(ALPHA_LIST_UP); diff --git a/baseunits/modules/Mangakakalot.pas b/baseunits/modules/Mangakakalot.pas index a0710b6ee..0dde11e27 100644 --- a/baseunits/modules/Mangakakalot.pas +++ b/baseunits/modules/Mangakakalot.pas @@ -117,6 +117,7 @@ procedure RegisterModule; begin Website := AWebsite; RootURL := ARootURL; + Category := 'English'; SortedList := True; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/MyMangaMe.pas b/baseunits/modules/MyMangaMe.pas index 0836590a1..be903a3ed 100644 --- a/baseunits/modules/MyMangaMe.pas +++ b/baseunits/modules/MyMangaMe.pas @@ -146,6 +146,7 @@ procedure RegisterModule; begin Website := 'MyMangaMe'; RootURL := 'http://mymanga.me'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/ReadComics.pas b/baseunits/modules/ReadComics.pas index 23a6fb835..8700d1016 100644 --- a/baseunits/modules/ReadComics.pas +++ b/baseunits/modules/ReadComics.pas @@ -107,6 +107,7 @@ procedure RegisterModule; begin Website := 'ReadComics'; RootURL := 'http://readcomics.tv'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/ReadMangaToday.pas b/baseunits/modules/ReadMangaToday.pas index 46683e28a..0ce10d5af 100644 --- a/baseunits/modules/ReadMangaToday.pas +++ b/baseunits/modules/ReadMangaToday.pas @@ -94,6 +94,7 @@ procedure RegisterModule; begin Website := 'ReadMangaToday'; RootURL := 'https://www.readmng.com'; + Category := 'English'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas index 33bf1e147..20f729130 100644 --- a/baseunits/modules/SenManga.pas +++ b/baseunits/modules/SenManga.pas @@ -178,6 +178,7 @@ procedure RegisterModule; begin Website := 'SenManga'; RootURL := 'http://www.senmanga.com'; + Category := 'English'; MaxTaskLimit := 1; MaxConnectionLimit := 4; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/baseunits/modules/Taadd.pas b/baseunits/modules/Taadd.pas index 34ba7eb58..257942db4 100644 --- a/baseunits/modules/Taadd.pas +++ b/baseunits/modules/Taadd.pas @@ -109,6 +109,7 @@ procedure RegisterModule; begin Website := 'Taadd'; RootURL := 'http://www.taadd.com'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/Webtoons.pas b/baseunits/modules/Webtoons.pas index 25dcac8d3..1678519d0 100644 --- a/baseunits/modules/Webtoons.pas +++ b/baseunits/modules/Webtoons.pas @@ -143,6 +143,7 @@ procedure RegisterModule; begin Website := 'Webtoons'; RootURL := 'http://www.webtoons.com'; + Category := 'English'; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/config/mangalist.ini b/config/mangalist.ini index f89993700..41fb7b335 100644 --- a/config/mangalist.ini +++ b/config/mangalist.ini @@ -3,4 +3,3 @@ DefaultSelect=MangaFox,MangaHere,MangaInn,MangaReader DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download [available] -English=Batoto,EatManga,FunManga,GoodManga,HeyManga,KissManga,Madokami,MangaBackup,MangaCool,Mangadex,MangaEden,MangaFox,MangaGo,MangaHere,MangaHome,MangaInn,Mangakakalot,MangaLife,MangaPanda,MangaPark,MangaReader,MangaRock,MangaSaurus,MangaSee,MangaStreamTo,MangaTraders,MangaSail,MangaTail,MangaWindow,MyMangaMe,NineManga,ReadMangaToday,ReadComicOnline,SenManga,Webtoons,ReadComics,Taadd From 6cac36b15935f4d5417adac258be06a1ca542c3e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 12:32:29 +0300 Subject: [PATCH 2341/2794] WieManga, move to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/WieManga.pas | 128 --------------------------------- lua/modules/WieManga.lua | 97 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 129 deletions(-) delete mode 100644 baseunits/modules/WieManga.pas create mode 100644 lua/modules/WieManga.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 1cb4d543e..46f7f9827 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -57,7 +57,6 @@ uses MangaAe, Mangadex, MangaTube, - WieManga, Mangaf, MangaRock, PsychoPlay, diff --git a/baseunits/modules/WieManga.pas b/baseunits/modules/WieManga.pas deleted file mode 100644 index fb9f4ca12..000000000 --- a/baseunits/modules/WieManga.pas +++ /dev/null @@ -1,128 +0,0 @@ -unit WieManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, MangaFoxWatermark, FMDVars; - -implementation - -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if MangaInfo.FHTTP.GET(url) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - title := XPathString('//div[@class="bookmessagebox"]/h1/substring-before(., " Manga")'); - coverLink := XPathString('//div[@class="bookfrontpage"]/a/img/@src'); - summary := XPathString('//h4[text()="Beschreibung"]/following-sibling::text()'); - genres := XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Genre")]/a'); - authors := XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Autor")]/a'); - artists := XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Zeichner")]/a'); - status := MangaInfoStatusIfPos(XPathString('//div[@class="bookmessgae"]//dd[contains(span/text(), "Status")]/a'), 'ongoing', 'finished'); - XPathHREFAll('//div[@class="chapterlist"]/table//td[@class="col1"]/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - url: String; -begin - Result := False; - if DownloadThread = nil then Exit; - url := MaybeFillHost(Module.RootURL, AURL); - url := TrimRightChar(url, ['/']) + '-1.html'; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(url) then begin - Result := True; - PageNumber := XPathCount('(//select[@id="page"])[1]/option', Document); - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - baseurl, url, s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - baseurl := MaybeFillHost(Module.RootURL, AURL); - url := TrimRightChar(baseurl, ['/']) + '-' + IncStr(DownloadThread.WorkId) + '.html'; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - Headers.Values['Referer'] := baseurl; - if GET(url) then begin - Result := True; - s := XPathString('//img[@id="comicpic"]/@src', Document); - PageLinks[DownloadThread.WorkId] := s; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - s: String; - v: IXQValue; - i, x: Integer; -begin - Result := NET_PROBLEM; - if Module.CurrentDirectoryIndex = 0 then - s := '0-9' - else - s := ALPHA_LIST_UP[Module.CurrentDirectoryIndex + 1]; - if MangaInfo.FHTTP.GET(Module.RootURL + '/category/' + s + '_'+ IncStr(AURL) + '.html') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - i := 1; - for v in XPath('//*[@class="booklist"]//span[@class="pagetor"]//text()') do begin - x := StrToIntDef(v.toString, 1); - if x > i then i := x; - end; - updateList.CurrentDirectoryPageNumber := i; - XPathHREFtitleAll('//*[@class="booklist"]/table//dl/dd/a[1]', ALinks, ANames); - finally - Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'WieManga'; - RootURL := 'https://www.wiemanga.com'; - Category := 'German'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - TotalDirectory := Length(ALPHA_LIST_UP); - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/WieManga.lua b/lua/modules/WieManga.lua new file mode 100644 index 000000000..5abf192e0 --- /dev/null +++ b/lua/modules/WieManga.lua @@ -0,0 +1,97 @@ +local ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ' + +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//div[@class="bookfrontpage"]/a/img/@src')) + if module.website == 'WieManga' then + mangainfo.title=x.XPathString('//div[@class="bookmessagebox"]/h1/substring-before(., " Manga")') + mangainfo.summary = x.xpathstring('//h4[text()="Beschreibung"]/following-sibling::text()') + mangainfo.artists = x.XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Zeichner")]/a') + mangainfo.authors = x.XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Autor")]/a') + mangainfo.genres = x.XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="bookmessgae"]//dd[contains(span/text(), "Status")]/a'), 'ongoing', 'finished') + elseif module.website == 'MangaRussia' then + mangainfo.title=x.XPathString('//div[@class="bookmessagebox"]/h1/substring-after(., "Манга ")') + mangainfo.summary = x.xpathstring('//h4[text()="Описание"]/following-sibling::text()') + mangainfo.authors = x.XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Автор")]/a') + mangainfo.genres = x.XPathStringAll('//div[@class="bookmessgae"]//dd[contains(span/text(), "Жанры")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="bookmessgae"]//dd[contains(span/text(), "Перевод")]/a'), 'ongoing', 'finished') + end + x.XPathHREFAll('//div[@class="chapterlist"]/table//td[@class="col1"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_error + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber=0 + local s=MaybeFillHost(module.rooturl,url):gsub('/$', '') .. '-1.html' + if http.get(s) then + x=TXQuery.Create(http.Document) + task.pagenumber=x.xpath('(//select[@id="page"])[1]/option').count + return true + else + return false + end +end + +function GetImageURL() + local baseurl = MaybeFillHost(module.rooturl,url) + local s = baseurl:gsub('/$','') .. '-' .. tostring(workid+1) .. '.html' + http.headers.values['Referer'] = baseurl + if http.get(s) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]=x.xpathstring('//img[@id="comicpic"]/@src') + return true + else + return false + end +end + +function GetNameAndLink() + local s = '0-9' + if module.CurrentDirectoryIndex ~= 0 then + s = ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex,module.CurrentDirectoryIndex) + end + print(s) + if http.get(module.rooturl..'/category/' .. s .. '_'.. IncStr(url) .. '.html') then + x=TXQuery.Create(http.Document) + v=x.xpath('//*[@class="booklist"]//span[@class="pagetor"]//text()') + local i = 1 + for j=1,v.count do + v1 = v.get(j) + local tmp = tonumber(v1.toString) + if (tmp ~= nil) and (tmp > i) then i = tmp end + end + print(i) + updatelist.CurrentDirectoryPageNumber = i + x.XPathHREFtitleAll('//*[@class="booklist"]/table//dl/dd/a[1]', links, names) + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(name, url, category) + local m = NewModule() + m.category=category + m.website=name + m.rooturl=url + m.totaldirectory = ALPHA_LIST_UP:len() + m.lastupdated='February 19, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetImageURL='GetImageURL' + return m +end + +function Init() + AddWebsiteModule('WieManga', 'https://www.wiemanga.com', 'German') + AddWebsiteModule('MangaRussia', 'http://www.mangarussia.com', 'Russian') +end From 972bf58405d37789e4b6092829b635fcf7ed1877 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 15:35:30 +0300 Subject: [PATCH 2342/2794] Tumangaonline, show scanlation group fixes #1007 --- baseunits/modules/Tumangaonline.pas | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 20cc48462..9837be71a 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -69,8 +69,8 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var - v: IXQValue; - s, mangaid, purl: String; + v, w: IXQValue; + s, mangaid, purl, num: String; p, i: Integer; begin Result := NET_PROBLEM; @@ -117,12 +117,16 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; end; for v in XPath('json(*).data()') do begin - chapterLinks.Add(apiurlimagenes + XPathString('"?idManga="||tomo/idManga||"&idScanlation="||subidas/idScan||"&numeroCapitulo="||numCapitulo||"&visto=true"', v)); + mangaid := XPathString('tomo/idManga', v); + num := XPathString('numCapitulo', v); s := v.getProperty('nombre').toString; if s = 'null' then s := ''; if s <> '' then s := ' ' + s; s := v.getProperty('numCapitulo').toString + s; - chapterName.Add(s); + for w in XPath('jn:members(subidas)', v) do begin + chapterLinks.Add(apiurlimagenes + '?idManga=' + mangaid + '&idScanlation=' + XPathString('./idScan', w) + '&numeroCapitulo=' + num + '&visto=true'); + chapterName.Add(s + ' [' + XPathString('./scanlation/nombre', w) + ']'); + end; end; end; InvertStrings([chapterLinks, chapterName]); From 83561e29153176206fcc91d9cd4a19c177fa9f8d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 19 Feb 2018 20:59:31 +0800 Subject: [PATCH 2343/2794] luamodulesupdater, use dumpjson to save the state --- mangadownloader/forms/frmLuaModulesUpdater.lfm | 2 +- mangadownloader/forms/frmLuaModulesUpdater.pas | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lfm b/mangadownloader/forms/frmLuaModulesUpdater.lfm index 74d498947..7aa128ab9 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.lfm +++ b/mangadownloader/forms/frmLuaModulesUpdater.lfm @@ -11,7 +11,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm ClientWidth = 580 OnCreate = FormCreate OnDestroy = FormDestroy - LCLVersion = '1.9.0.0' + LCLVersion = '1.8.0.6' object vtLuaModulesRepos: TVirtualStringTree AnchorSideLeft.Control = Owner AnchorSideTop.Control = btCheckUpdate diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index 0443b2d13..25ccaad23 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -376,7 +376,6 @@ procedure TLuaModulesRepos.SaveToFile(const AFilename: String); i: Integer; m: TLuaModuleRepo; f: TFileStream; - s: TJSONStringType; begin a := TJSONArray.Create; try @@ -398,8 +397,7 @@ procedure TLuaModulesRepos.SaveToFile(const AFilename: String); DeleteFile(AFilename); f := TFileStream.Create(AFilename, fmCreate); try - s := a.FormatJSON(); - f.WriteBuffer(s[1], Length(s)); + a.DumpJSON(f); finally f.Free; end; From 48310e3916d493d495f5ae3a42f0c0d81b674a8f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 16:17:58 +0300 Subject: [PATCH 2344/2794] FoOlSlide, auto detect adult warning --- lua/modules/FoOlSlide.lua | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 5bafd01eb..f8d024287 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -9,21 +9,16 @@ local dirurllector = '/lector/directory/' local dirurlfsdir = '/fs/directory/' function getWithCookie(lurl) - local needCookie = { - ['SeinagiAdultoFansub'] = true, - ['TripleSevenScan'] = true, - ['DokiFansubs'] = true, - ['RavensScans'] = true, - ['YamiTenshiNoFansub'] = true, - ['S2Scans'] = true, - ['Pzykosis666HFansub'] = true, - ['SantosScan'] = true, - ['XAnimeSeduccion'] = true - } - if needCookie[module.website] and Pos(dirurl, lurl) then - return http.post(lurl, 'adult=true') + if http.get(lurl) then + local x = TXQuery.Create(http.document) + local s = x.xpathstring('//form//input[(@type="hidden") and (@name="adult")]/@value') + if s:lower() == 'true' then + http.reset() + return http.post(lurl, 'adult=true') + end + return true else - return http.get(lurl) + return false end end From f765e723b06afde23ba275fbef92f12528c5c076 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 16:20:06 +0300 Subject: [PATCH 2345/2794] add AntisenseScans, TheCatScans, DeathTollScans [EN-SC] --- lua/modules/FoOlSlide.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index f8d024287..26790acd2 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -40,7 +40,8 @@ function getdirurl(website) ['HelveticaScans'] = dirurlhelvetica, ['RavensScans'] = dirurllector, ['NoraNoFansub'] = dirurllector, - ['HotChocolateScans'] = dirurlfsdir + ['HotChocolateScans'] = dirurlfsdir, + ['AntisenseScans'] = dirurlonline } if dirs[website] ~= nil then return dirs[website] @@ -207,6 +208,9 @@ function Init() AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today', cat) AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com', cat) AddWebsiteModule('SeaOtterScans', 'https://reader.seaotterscans.com', cat) + AddWebsiteModule('AntisenseScans', 'http://antisensescans.com', cat) + AddWebsiteModule('TheCatScans', 'https://reader.thecatscans.com', cat) + AddWebsiteModule('DeathTollScans', 'https://reader.deathtollscans.net', cat) -- es-sc cat = 'Spanish-Scanlation' From f1e32ad3c6e02069a96cdc7e7e1b1f6389e48078 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 16:42:54 +0300 Subject: [PATCH 2346/2794] add MangaBB [EN] --- baseunits/modules/GoodManga.pas | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/baseunits/modules/GoodManga.pas b/baseunits/modules/GoodManga.pas index c712ad74c..d3f3022cd 100644 --- a/baseunits/modules/GoodManga.pas +++ b/baseunits/modules/GoodManga.pas @@ -116,17 +116,24 @@ function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; end; procedure RegisterModule; -begin - with AddModule do + + procedure AddWebsiteModule(AWebsite, ARootURL: String); begin - Website := 'GoodManga'; - RootURL := 'http://www.goodmanga.net'; - Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; + with AddModule do + begin + Website := AWebsite; + RootURL := ARootURL; + Category := 'English'; + OnGetNameAndLink := @GetNameAndLink; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnGetImageURL := @GetImageURL; + end; end; + +begin + AddWebsiteModule('GoodManga', 'http://www.goodmanga.net'); + AddWebsiteModule('MangaBB', 'http://mangabb.co'); end; initialization From 0be37d52b44e168e64e9dde366a3677f93b1c26b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 19 Feb 2018 17:56:29 +0300 Subject: [PATCH 2347/2794] WebsiteModules, fix ModuleExist #1023 --- baseunits/WebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index a875fae6e..0ece4f3f5 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -498,7 +498,7 @@ function TWebsiteModules.LocateModuleByHost(const AHost: String): Integer; function TWebsiteModules.ModuleExist(const ModuleId: Integer): Boolean; begin - Result := (ModuleId > 0) and (ModuleId < FModuleList.Count); + Result := (ModuleId >= 0) and (ModuleId < FModuleList.Count); end; function TWebsiteModules.ModuleAvailable(const ModuleId: Integer; From 2267cd4bd47e1d553fa28ca0c113135f62e0b605 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 03:47:52 +0800 Subject: [PATCH 2348/2794] added idkscans --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 26790acd2..3ee53371c 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -231,4 +231,5 @@ function Init() AddWebsiteModule('XAnimeSeduccion', 'http://xanime-seduccion.com', cat) AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) + AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) end From 31f5275211cc09ddc99ab237725c0eb2cc87d52e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 03:52:50 +0800 Subject: [PATCH 2349/2794] Bump version 0.9.148.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9893ce88a..f48623eb4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.148.0 (20-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.147.0...0.9.148.0 + 0.9.147.0 (19-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.146.0...0.9.147.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ab41ed218..ad61a8dc0 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="147"/> + <RevisionNr Value="148"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 821679dbc..ed3727e91 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.147.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.147.0/fmd_0.9.147.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.147.0/fmd_0.9.147.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.147.0/fmd_0.9.147.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.147.0/fmd_0.9.147.0_Win64.7z +VERSION=0.9.148.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.148.0/fmd_0.9.148.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.148.0/fmd_0.9.148.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.148.0/fmd_0.9.148.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.148.0/fmd_0.9.148.0_Win64.7z From 046843b6dff18e19a279695c4986859e2a54de54 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 07:34:35 +0800 Subject: [PATCH 2350/2794] dynastiscans, fix manga info (#1026) --- lua/modules/DynastyScans.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/modules/DynastyScans.lua b/lua/modules/DynastyScans.lua index 3c0e623ac..496c177a3 100644 --- a/lua/modules/DynastyScans.lua +++ b/lua/modules/DynastyScans.lua @@ -2,13 +2,13 @@ function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstring('//*[@class="tag-title"]') + mangainfo.title=x.xpathstring('//h2[@class="tag-title"]/b') mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//img[@class="thumbnail"]/@src')) - mangainfo.authors=x.xpathstring('//a[contains(@href,"/title/")]') + mangainfo.authors=x.xpathstring('string-join(//a[contains(@href,"/authors/")],", ")') mangainfo.genres=x.xpathstringall('//*[@class="label" or @class="doujin_tags"]') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//small')) + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//h2[@class="tag-title"]/small')) mangainfo.summary=x.xpathstring('//*[@class="description"]') - x.xpathhrefall('//dl[@class="chapter-list"]/dd/a',mangainfo.chapterlinks,mangainfo.chapternames) + x.xpathhrefall('//dl[@class="chapter-list"]/dd/a[1]',mangainfo.chapterlinks,mangainfo.chapternames) return no_error else return net_problem From 0e94d58fc7d2a083e6fc179fbb182e6e6588aaa7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 16:18:00 +0800 Subject: [PATCH 2351/2794] luaxquery, fix parsehtml #1027 --- baseunits/lua/luaXQuery.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/luaXQuery.pas index dc1a66fdd..2d53ce9af 100644 --- a/baseunits/lua/luaXQuery.pas +++ b/baseunits/lua/luaXQuery.pas @@ -44,7 +44,7 @@ function xquery_parsehtml(L: Plua_State): Integer; cdecl; u.ParseHTML(lua_tostring(L, 1)) else if lua_isuserdata(L, 1) then - u.ParseHTML(TStream(lua_touserdata(L, 1))); + u.ParseHTML(TStream(luaGetUserData(L, 1))); end; function xquery_xpath(L: Plua_State): Integer; cdecl; From c985dd4dac6de93ebb65d3216673e5aa9c65ef76 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 17:46:08 +0800 Subject: [PATCH 2352/2794] httpsendthread, add redirection code --- baseunits/DBUpdater.pas | 13 ++++++++----- baseunits/httpsendthread.pas | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index d57fdc232..65f858f68 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -63,7 +63,7 @@ TDBUpdaterThread = class(TBaseThread) implementation -uses FMDVars; +uses FMDVars, SourceForge; function GetDBURL(const AName: String): String; begin @@ -242,7 +242,7 @@ procedure TDBUpdaterThread.UpdateStatusText(const S: String); procedure TDBUpdaterThread.Execute; var - currentfilename: String; + currentfilename, lurl: String; cont: Boolean; used: Boolean; begin @@ -255,8 +255,12 @@ procedure TDBUpdaterThread.Execute; try FCurrentName := Items[FCurrentId]; Synchronize(@SyncStartDownload); - if FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300) then - // should be success + lurl := GetDBURL(FCurrentName); + if Pos('sourceforge.net', AnsiLowerCase(lurl)) <> 0 then + cont := SourceForge.Download(FHTTP, lurl) + else + cont := FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300); + if cont then begin cont := True; // save to data folder @@ -338,7 +342,6 @@ constructor TDBUpdaterThread.Create; FreeOnTerminate := True; FFailedList := TStringList.Create; FHTTP := THTTPSendThread.Create(Self); - FHTTP.UserAgent := UserAgentCURL; FHTTP.Sock.OnStatus := @HTTPSockOnStatus; Items := TStringList.Create; Synchronize(@SyncStart); diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 8909c96b8..5ef71fba7 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -503,9 +503,19 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: Headers.Assign(HTTPHeader); end; - // redirection, only 301, 302, 303 + { redirection + 300 Multiple Choices + 301 Moved Permanently + 302 Found (aka Object Moved aka Moved Temporarily) + 303 See Other + 304 Not Modified + 305 Use Proxy + 306 Switch Proxy + 307 Temporary Redirect + who have location 301, 302, 303, 307? + } if FFollowRedirection then - while (ResultCode > 300) and (ResultCode < 304) do begin + while (ResultCode-300) in [1, 2, 3, 7] do begin if CheckTerminate then Exit; // break too many redirect if redirectcounter >= FMaxRedirect then Exit From b0026442ca336ce5727858b8af31239caa2749c6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 18:16:42 +0800 Subject: [PATCH 2353/2794] add sf handle temporary, this may changed in the future by sf --- baseunits/SourceForge.pas | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 baseunits/SourceForge.pas diff --git a/baseunits/SourceForge.pas b/baseunits/SourceForge.pas new file mode 100644 index 000000000..8b2874e5d --- /dev/null +++ b/baseunits/SourceForge.pas @@ -0,0 +1,64 @@ +unit SourceForge; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, httpsendthread; + +function Download(const AHTTP: THTTPSendThread; const AURL: String): Boolean; + +implementation + +uses XQueryEngineHTML, RegExpr, synautil; + +function Download(const AHTTP: THTTPSendThread; const AURL: String): Boolean; +var + s, lurl: String; + ml: TStringList; + fr: Boolean; + i: LongInt; +begin + Result := False; + AHTTP.UserAgent := UserAgentCURL; + if AHTTP.GET(AURL) and (AHTTP.ResultCode < 300) then + begin + // the Sourceforge site is currently in Disaster Recovery mode, and currently requires the use of javascript to function. + if Pos('/#!/', AHTTP.LastURL) <> 0 then + begin + lurl := AHTTP.LastURL; + // load the mirror list + if AHTTP.GET('https://sourceforge.net/js/mirrors.js') then + begin + s := GetBetween('mirror_list = shuffle(',');',ReadStrFromStream(AHTTP.Document, AHTTP.Document.Size)); + ml := TStringList.Create; + try + XPathStringAll('json(.)()("abbr")', s, ml); + fr := AHTTP.FollowRedirection; + AHTTP.FollowRedirection := False; + // 302 means not found? + // keep retry on another mirrors if not found + //while (not Result) and (not AHTTP.ThreadTerminated) and (ml.Count <> 0) do + //begin + i := Random(ml.Count); + Result := AHTTP.GET( + ReplaceRegExpr('^.*/#!/projects/(\w+)/files(/.*?)(/download)?$', lurl, + 'https://' + ml[i] +'.dl.sourceforge.net/project/$1$2', True)) + and (AHTTP.ResultCode < 300); + // if not Result then + // ml.Delete(i); + //end; + AHTTP.FollowRedirection := fr; + finally + ml.Free; + end; + end; + end + else + Result := True; + end; +end; + +end. + From bb96107785ec173668fa76e678899da4d5dd3abb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 21:15:51 +0800 Subject: [PATCH 2354/2794] add websitemodulesettings #1020 --- baseunits/WebsiteModules.pas | 44 +++++++++++++++++++++-------- baseunits/lua/LuaWebsiteModules.pas | 4 +-- baseunits/modules/EHentai.pas | 4 +-- baseunits/modules/Mangadex.pas | 4 +-- baseunits/modules/RawSenManga.pas | 4 +-- baseunits/modules/SenManga.pas | 4 +-- baseunits/modules/Tumangaonline.pas | 4 +-- baseunits/uUpdateThread.pas | 6 ++-- 8 files changed, 47 insertions(+), 27 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 0ece4f3f5..ccb0b69f4 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -66,11 +66,31 @@ TWebsiteOptionItem = record Items: PString; end; + TProxyType = (ptDefault, ptDirect, ptHTTP, ptSOCKS4, ptSOCKS5); + + { TWebsiteModuleSettings } + + TWebsiteModuleSettings = class + public + MaxTaskLimit: Integer; + MaxConnectionLimit: Integer; + UpdateListNumberOfThreads: Integer; + UpdateListDirectoryPageNumber: Integer; + UserAgent: String; + Cookies: String; + ProxyType: TProxyType; + ProxyHost: String; + ProxyPort: String; + ProxyUsername: String; + ProxyPassword: String; + end; + { TModuleContainer } TModuleContainer = class private FID: Integer; + FSettings: TWebsiteModuleSettings; FTotalDirectory: Integer; FCloudflareCF: TCFProps; FCloudflareEnabled: Boolean; @@ -86,8 +106,6 @@ TModuleContainer = class Website: String; RootURL: String; Category: String; - MaxTaskLimit: Integer; - MaxConnectionLimit: Integer; ActiveTaskCount: Integer; ActiveConnectionCount: Integer; AccountSupport: Boolean; @@ -131,6 +149,8 @@ TModuleContainer = class procedure DecActiveTaskCount; inline; procedure IncActiveConnectionCount; inline; procedure DecActiveConnectionCount; inline; + + property Settings: TWebsiteModuleSettings read FSettings write FSettings; end; TModuleContainers = specialize TFPGList<TModuleContainer>; @@ -265,8 +285,6 @@ implementation var CS_Connection: TRTLCriticalSection; -{ TModuleContainer } - function CleanOptionName(const S: String): String; const Alpha = ['A'..'Z', 'a'..'z', '_']; @@ -287,6 +305,8 @@ function CleanOptionName(const S: String): String; Inc(i); end; +{ TModuleContainer } + procedure TModuleContainer.SetCloudflareEnabled(AValue: Boolean); begin if FCloudflareEnabled = AValue then Exit; @@ -327,9 +347,8 @@ procedure TModuleContainer.SetTotalDirectory(AValue: Integer); constructor TModuleContainer.Create; begin + FSettings := TWebsiteModuleSettings.Create; FID := -1; - MaxTaskLimit := 0; - MaxConnectionLimit := 0; ActiveTaskCount := 0; ActiveConnectionCount := 0; AccountSupport := False; @@ -348,6 +367,7 @@ destructor TModuleContainer.Destroy; SetLength(OptionList,0); if Assigned(FCloudflareCF) then FCloudflareCF.Free; + FSettings.Free; inherited Destroy; end; @@ -783,8 +803,8 @@ function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; Result := True; if ModuleExist(ModuleId) then with FModuleList[ModuleId] do - if MaxTaskLimit > 0 then - Result := ActiveTaskCount < MaxTaskLimit; + if Settings.MaxTaskLimit > 0 then + Result := ActiveTaskCount < Settings.MaxTaskLimit; end; procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); @@ -804,8 +824,8 @@ function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; Result := True; if ModuleExist(ModuleId) then with FModuleList[ModuleId] do - if MaxConnectionLimit > 0 then - Result := ActiveConnectionCount < MaxConnectionLimit; + if Settings.MaxConnectionLimit > 0 then + Result := ActiveConnectionCount < Settings.MaxConnectionLimit; end; procedure TWebsiteModules.LoadWebsiteOption; @@ -861,13 +881,13 @@ function TWebsiteModules.GetCount: Integer; function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; begin if not ModuleExist(ModuleId) then Exit(0); - Result := FModuleList[ModuleId].MaxTaskLimit; + Result := FModuleList[ModuleId].Settings.MaxTaskLimit; end; function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin if not ModuleExist(ModuleId) then Exit(0); - Result := FModuleList[ModuleId].MaxConnectionLimit; + Result := FModuleList[ModuleId].Settings.MaxConnectionLimit; end; function TWebsiteModules.GetActiveTaskCount(const ModuleId: Integer): Integer; diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 64d81ad34..de6f92bf4 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -771,9 +771,9 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'Website', @Module.Website); luaClassAddStringProperty(L, MetaTable, 'RootURL', @Module.RootURL); luaClassAddStringProperty(L, MetaTable, 'Category', @Module.Category); - luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.MaxTaskLimit); + luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.Settings.MaxTaskLimit); luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', - @Module.MaxConnectionLimit); + @Module.Settings.MaxConnectionLimit); luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', @Module.ActiveTaskCount); luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', @Module.ActiveConnectionCount); diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index eb74af083..25bd5b0b1 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -408,8 +408,8 @@ procedure RegisterModule; Website := AWebsite; RootURL := ARootURL; Category := 'H-Sites'; - MaxTaskLimit := 1; - MaxConnectionLimit := 2; + Settings.MaxTaskLimit := 1; + Settings.MaxConnectionLimit := 2; SortedList := True; DynamicPageLink := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index f3b0b55bf..bf902b563 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -140,8 +140,8 @@ procedure RegisterModule; Website := 'Mangadex'; RootURL := 'https://mangadex.com'; Category := 'English'; - MaxTaskLimit := 4; - MaxConnectionLimit := 4; + Settings.MaxTaskLimit := 4; + Settings.MaxConnectionLimit := 4; TotalDirectory := Length(ALPHA_LIST_UP); OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index 5667aeb69..c2cda8b97 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -175,8 +175,8 @@ procedure RegisterModule; Website := 'RawSenManga'; RootURL := 'http://raw.senmanga.com'; Category := 'Raw'; - MaxTaskLimit := 1; - MaxConnectionLimit := 4; + Settings.MaxTaskLimit := 1; + Settings.MaxConnectionLimit := 4; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas index 20f729130..6d1ee4981 100644 --- a/baseunits/modules/SenManga.pas +++ b/baseunits/modules/SenManga.pas @@ -179,8 +179,8 @@ procedure RegisterModule; Website := 'SenManga'; RootURL := 'http://www.senmanga.com'; Category := 'English'; - MaxTaskLimit := 1; - MaxConnectionLimit := 4; + Settings.MaxTaskLimit := 1; + Settings.MaxConnectionLimit := 4; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 9837be71a..3aeb11524 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -174,8 +174,8 @@ procedure RegisterModule; Website := 'Tumangaonline'; RootURL := 'https://www.tumangaonline.com'; Category := 'Spanish'; - MaxTaskLimit := 1; - MaxConnectionLimit := 1; + Settings.MaxTaskLimit := 1; + Settings.MaxConnectionLimit := 1; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 5c0a1808c..7433a050a 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -396,8 +396,8 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end else begin - if Module.MaxConnectionLimit > 0 then - numberOfThreads := Module.MaxConnectionLimit + if Module.Settings.MaxConnectionLimit > 0 then + numberOfThreads := Module.Settings.MaxConnectionLimit else numberOfThreads := OptionMaxThreads; if numberOfThreads > OptionMaxThreads then @@ -415,7 +415,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; Exit; end; - if Module.MaxConnectionLimit > 0 then + if Module.Settings.MaxConnectionLimit > 0 then while (not Terminated) and (Module.ActiveConnectionCount >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE) else From af5e133d89688e84a7b522e24db6147c1819fc90 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 20 Feb 2018 21:23:15 +0800 Subject: [PATCH 2355/2794] delete mangalist.ini and move the rest to base.ini #1020 --- baseunits/FMDOptions.pas | 5 ++--- config/base.ini | 1 + config/mangalist.ini | 5 ----- mangadownloader/forms/frmMain.pas | 21 +-------------------- 4 files changed, 4 insertions(+), 28 deletions(-) delete mode 100644 config/mangalist.ini diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 2fc832b57..0b36a130c 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -84,7 +84,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) CONFIG_ADVANCED, REVISION_FILE, UPDATE_FILE, - MANGALIST_FILE, BASE_FILE, ACCOUNTS_FILE, WEBSITE_CONFIG_FILE, @@ -98,7 +97,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) MANGAFOXTEMPLATE_FOLDER, LUA_WEBSITEMODULE_FOLDER, LUA_WEBSITEMODULE_REPOS: String; - DEFAULT_SELECTED_WEBSITES: String = 'MangaFox,MangaHere,MangaInn,MangaReader'; // ini files revisionfile, @@ -107,6 +105,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) advancedfile: TIniFileRun; // base url, should be in base.ini + DEFAULT_SELECTED_WEBSITES: String = 'MangaFox,MangaHere,MangaInn,MangaReader'; DB_URL: String = 'https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download'; UPDATE_URL: String = 'https://raw.githubusercontent.com/riderkick/FMD/master/update'; CHANGELOG_URL: String = 'https://raw.githubusercontent.com/riderkick/FMD/master/changelog.txt'; @@ -272,6 +271,7 @@ procedure ReadBaseFile; if not FileExistsUTF8(BASE_FILE) then Exit; with TIniFile.Create(BASE_FILE) do try + DEFAULT_SELECTED_WEBSITES:=ReadString('base','DEFAULT_SELECTED_WEBSITES',DEFAULT_SELECTED_WEBSITES); DB_URL:=ReadString('base','DB_URL',DB_URL); UPDATE_URL:=ReadString('base','UPDATE_URL',UPDATE_URL); CHANGELOG_URL:=ReadString('base','CHANGELOG_URL',CHANGELOG_URL); @@ -291,7 +291,6 @@ procedure SetFMDdirectory(const ADir: String); CONFIG_FOLDER := FMD_DIRECTORY + 'config' + PathDelim; REVISION_FILE := CONFIG_FOLDER + 'revision.ini'; UPDATE_FILE := CONFIG_FOLDER + 'updates.ini'; - MANGALIST_FILE := CONFIG_FOLDER + 'mangalist.ini'; BASE_FILE := CONFIG_FOLDER + 'base.ini'; IMAGE_FOLDER := FMD_DIRECTORY + 'images' + PathDelim; diff --git a/config/base.ini b/config/base.ini index 34e180caf..844782fce 100644 --- a/config/base.ini +++ b/config/base.ini @@ -1,4 +1,5 @@ [base] +DEFAULT_SELECTED_WEBSITES=MangaFox,MangaHere,MangaInn,MangaReader DB_URL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download UPDATE_URL=https://raw.githubusercontent.com/riderkick/FMD/master/update CHANGELOG_URL=https://raw.githubusercontent.com/riderkick/FMD/master/changelog.txt diff --git a/config/mangalist.ini b/config/mangalist.ini deleted file mode 100644 index 41fb7b335..000000000 --- a/config/mangalist.ini +++ /dev/null @@ -1,5 +0,0 @@ -[general] -DefaultSelect=MangaFox,MangaHere,MangaInn,MangaReader -DBDownloadURL=https://sourceforge.net/projects/newfmd/files/data/<website>.7z/download - -[available] diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 6def45ce9..a834690ce 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -5255,28 +5255,9 @@ procedure TMainForm.LoadMangaOptions; data: PSingleItem; begin categories := TStringList.Create; - categories.OwnsObjects := True; - categories.Sorted := False; try - // read mangalist.ini - with TIniFile.Create(MANGALIST_FILE) do - try - // read available websites - ReadSection('available', categories); - for i := 0 to categories.Count - 1 do - begin - categoriesitem := TStringList.Create; - categories.Objects[i] := categoriesitem; - categoriesitem.Sorted := False; - s := Trim(ReadString('available', categories[i], '')); - if s <> '' then - categoriesitem.CommaText := s; - end; - finally - Free; - end; - // sort all + categories.OwnsObjects := True; categories.Duplicates := dupIgnore; categories.Sorted := True; for i := 0 to categories.Count - 1 do From 4650047089000f75fa6dcc6e8c45354bd3fb76bb Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 20 Feb 2018 17:12:04 +0300 Subject: [PATCH 2356/2794] add MangaichiScan [EN-SC] fixes #1028 --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 3ee53371c..a8c82c8fa 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -41,7 +41,8 @@ function getdirurl(website) ['RavensScans'] = dirurllector, ['NoraNoFansub'] = dirurllector, ['HotChocolateScans'] = dirurlfsdir, - ['AntisenseScans'] = dirurlonline + ['AntisenseScans'] = dirurlonline, + ['MangaichiScan'] = dirurlfsdir } if dirs[website] ~= nil then return dirs[website] @@ -211,6 +212,7 @@ function Init() AddWebsiteModule('AntisenseScans', 'http://antisensescans.com', cat) AddWebsiteModule('TheCatScans', 'https://reader.thecatscans.com', cat) AddWebsiteModule('DeathTollScans', 'https://reader.deathtollscans.net', cat) + AddWebsiteModule('MangaichiScan', 'http://mangaichiscans.mokkori.fr', cat) -- es-sc cat = 'Spanish-Scanlation' From 06bbc75c35ac37a5ffae175a6273b75a0b643203 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 20 Feb 2018 19:06:17 +0300 Subject: [PATCH 2357/2794] WieManga, fix --- lua/modules/WieManga.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/modules/WieManga.lua b/lua/modules/WieManga.lua index 5abf192e0..f72c78618 100644 --- a/lua/modules/WieManga.lua +++ b/lua/modules/WieManga.lua @@ -56,9 +56,8 @@ end function GetNameAndLink() local s = '0-9' if module.CurrentDirectoryIndex ~= 0 then - s = ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex,module.CurrentDirectoryIndex) + s = ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) end - print(s) if http.get(module.rooturl..'/category/' .. s .. '_'.. IncStr(url) .. '.html') then x=TXQuery.Create(http.Document) v=x.xpath('//*[@class="booklist"]//span[@class="pagetor"]//text()') @@ -68,7 +67,6 @@ function GetNameAndLink() local tmp = tonumber(v1.toString) if (tmp ~= nil) and (tmp > i) then i = tmp end end - print(i) updatelist.CurrentDirectoryPageNumber = i x.XPathHREFtitleAll('//*[@class="booklist"]/table//dl/dd/a[1]', links, names) return no_error From b7b0850cdeabb98d8400d242a3c7dcf02a58a668 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 21 Feb 2018 07:48:18 +0300 Subject: [PATCH 2358/2794] fix png to jpg conversion, fixes #1030 --- baseunits/uBaseUnit.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index c05972e48..fdd9ff89e 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -23,7 +23,7 @@ interface fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit, - MemBitmap, FPWritePNG, zstream; + MemBitmap, FPWritePNG, zstream, FPReadPNG; const LineEnding2 = LineEnding + LineEnding; @@ -3030,13 +3030,15 @@ function PNGToJPEGStream(const AStream: TMemoryStream; const AQuality: Integer): var img: TFPCustomImage; writer: TFPWriterJPEG; + reader: TFPReaderPNG; begin Result := False; - img := TFPCustomImage.create(0,0); + img := TFPMemoryImage.create(0,0); + reader := TFPReaderPNG.create; try writer := nil; try - img.LoadFromStream(AStream); + img.LoadFromStream(AStream, reader); writer := TFPWriterJPEG.create; writer.CompressionQuality := AQuality; img.SaveToStream(AStream, writer); @@ -3046,6 +3048,7 @@ function PNGToJPEGStream(const AStream: TMemoryStream; const AQuality: Integer): if writer <> nil then writer.Free; finally + reader.Free; img.Free; end; end; From 211cf1963afe931318caae929fe99b417a8943d6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 21 Feb 2018 09:05:17 +0300 Subject: [PATCH 2359/2794] MangaShiro, move to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaShiro.pas | 99 -------------------------------- lua/modules/MangaShiro.lua | 58 +++++++++++++++++++ 3 files changed, 58 insertions(+), 100 deletions(-) delete mode 100644 baseunits/modules/MangaShiro.pas create mode 100644 lua/modules/MangaShiro.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 46f7f9827..8229d0ebc 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -44,7 +44,6 @@ uses MangaGo, GoodManga, MangaZuki, - MangaShiro, ReadMangaToday, MangaOnlineBR, Tapas, diff --git a/baseunits/modules/MangaShiro.pas b/baseunits/modules/MangaShiro.pas deleted file mode 100644 index 1b021a5a9..000000000 --- a/baseunits/modules/MangaShiro.pas +++ /dev/null @@ -1,99 +0,0 @@ -unit MangaShiro; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; - -implementation - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - dirurl: String; -begin - Result := NET_PROBLEM; - dirurl := '/manga-list/'; - if Module.Website = 'MangaShiro' then dirurl := '/daftar-manga/'; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - XPathHREFAll('//*[@class="soralist"]//a', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="imgdesc"]/img/@src')); - if title = '' then title := XPathString('//h1[@itemprop="name"]'); - authors := XPathString('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")'); - genres := XPathString('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")'); - status := MangaInfoStatusIfPos(XPathString('//div[@class="listinfo"]//li[starts-with(.,"Status")]')); - summary := XPathString('//*[@class="desc"]/string-join(.//text(),"")'); - XPathHREFAll('//div[@class="cl"]//li/span[1]/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - XPathStringAll('//*[@id="readerarea"]//img/@src', Document, PageLinks); - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(const AWebsite, ARootURL: String): TModuleContainer; - begin - Result := AddModule; - with Result do - begin - Website := AWebsite; - RootURL := ARootURL; - Category := 'Indonesian'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; - end; - -begin - AddWebsiteModule('MangaShiro', 'http://mangashiro.net'); - AddWebsiteModule('Subapics', 'http://subapics.com'); - AddWebsiteModule('MangaKita', 'http://www.mangakita.net'); - AddWebsiteModule('Mangavy', 'https://mangavy.com'); -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua new file mode 100644 index 000000000..d2737e720 --- /dev/null +++ b/lua/modules/MangaShiro.lua @@ -0,0 +1,58 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') + mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) + mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') + x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagenumber=0 + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl,url)) then + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + return true + else + return false + end +end + +function getnameandlink() + local dirurl = '/manga-list/' + if module.website == 'MangaShiro' then dirurl = '/daftar-manga/' end + if http.get(module.rooturl..dirurl) then + TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(site, url) + local m=NewModule() + m.category='Indonesian' + m.website=site + m.rooturl=url + m.lastupdated='February 21, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + return m +end + +function Init() + AddWebsiteModule('MangaShiro', 'http://mangashiro.net') + AddWebsiteModule('Subapics', 'http://subapics.com') + AddWebsiteModule('MangaKita', 'http://www.mangakita.net') + AddWebsiteModule('Mangavy', 'https://mangavy.com') +end From ef90fbfc7872b0588edaa5eab0638d6bfd25ddbe Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 21 Feb 2018 09:16:27 +0300 Subject: [PATCH 2360/2794] add komikstation.com [ID] #874 --- lua/modules/MangaShiro.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index d2737e720..ab51600cb 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -29,9 +29,14 @@ end function getnameandlink() local dirurl = '/manga-list/' - if module.website == 'MangaShiro' then dirurl = '/daftar-manga/' end + if module.website == 'MangaShiro' then dirurl = '/daftar-manga/' + elseif module.website == 'KomikStation' then dirurl = '/daftar-komik/' end if http.get(module.rooturl..dirurl) then - TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) + if module.website == 'KomikStation' then + TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) + else + TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) + end return no_error else return net_problem @@ -55,4 +60,5 @@ function Init() AddWebsiteModule('Subapics', 'http://subapics.com') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') AddWebsiteModule('Mangavy', 'https://mangavy.com') + AddWebsiteModule('KomikStation', 'http://www.komikstation.com/') end From 2c7a117b59a963964a6ec86bd086c024bd257a23 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 21 Feb 2018 13:19:39 +0300 Subject: [PATCH 2361/2794] Seemh, move to lua --- baseunits/modules/Seemh.pas | 136 -------------------------- lua/modules/ManHuaGui.lua | 106 +++++++++++++++++++++ lua/modules/jsunpack.lua | 77 +++++++++++++++ lua/modules/lzstring.lua | 184 ++++++++++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+), 136 deletions(-) delete mode 100644 baseunits/modules/Seemh.pas create mode 100644 lua/modules/ManHuaGui.lua create mode 100644 lua/modules/jsunpack.lua create mode 100644 lua/modules/lzstring.lua diff --git a/baseunits/modules/Seemh.pas b/baseunits/modules/Seemh.pas deleted file mode 100644 index 4e038ea85..000000000 --- a/baseunits/modules/Seemh.pas +++ /dev/null @@ -1,136 +0,0 @@ -unit Seemh; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - RegExpr, synautil; - -implementation - -const - dirurl='/list/'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL+dirurl) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - Page:=StrToIntDef(query.XPathString('//div[@class="result-count"]/strong[2]'),1); - finally - query.Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; - s: String; -begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - s:=Module.RootURL+dirurl; - if AURL<>'0' then s+='/index_p'+IncStr(AURL)+'.html'; - if MangaInfo.FHTTP.GET(s) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//ul[@id="contList"]/li/p/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - query.Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result:=NET_PROBLEM; - if MangaInfo=nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP,MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=NO_ERROR; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink:=query.XPathString('//p[@class="hcover"]/img/@src'); - if title=''then title:=query.XPathString('//div[@class="book-title"]/h1'); - genres:=SeparateRight(query.XPathString('//ul[@class="detail-list cf"]/li[2]/span[1]'),':'); - authors:=SeparateRight(query.XPathString('//ul[@class="detail-list cf"]/li[2]/span[2]'),':'); - if Pos('连载中',query.XPathString('//ul[@class="detail-list cf"]/li[@class="status"]'))>0 then status:='1' else status:='0'; - summary:=query.XPathString('//div[@id="intro-all"]'); - for v in query.XPath('//div[@id="chapter-list-0"]/ul/li/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toNode.getAttribute('title')); - end; - InvertStrings([chapterLinks,chapterName]); - finally - query.Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result:=False; - if DownloadThread=nil then Exit; - with DownloadThread.FHTTP,DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL,AURL)) then begin - Result:=True; - query:=TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - for v in query.XPath('//div[@id="image"]/div/img[@class="real img-responsive"][@id!="imagem-forum"]/@data-lazy') do - PageLinks.Add(v.toString); - finally - query.Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website:='Seemh'; - RootURL:='http://www.seemh.com'; - OnGetDirectoryPageNumber:=@GetDirectoryPageNumber; - OnGetNameAndLink:=@GetNameAndLink; - OnGetInfo:=@GetInfo; - OnGetPageNumber:=@GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/ManHuaGui.lua b/lua/modules/ManHuaGui.lua new file mode 100644 index 000000000..6935fab4e --- /dev/null +++ b/lua/modules/ManHuaGui.lua @@ -0,0 +1,106 @@ +local js = require 'modules.jsunpack' +local lz = require 'modules.lzstring' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="book-title"]/h1') + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//p[@class="hcover"]/img/@src')) + mangainfo.authors=SeparateRight(x.xpathstring('//ul[@class="detail-list cf"]/li[2]/span[2]'), ':') + mangainfo.genres=SeparateRight(x.xpathstring('//ul[@class="detail-list cf"]/li[2]/span[1]'), ':') + if Pos('连载中', x.xpathstring('//ul[@class="detail-list cf"]/li[@class="status"]')) > 0 then + mangainfo.status = '1' + else + mangainfo.status = '0' + end + mangainfo.summary=x.xpathstring('//div[@id="intro-all"]') + v=x.xpath('//div[contains(@id,"chapter-list")]/ul') + for i=v.count,1,-1 do + v1=v.get(i) + x.XPathHREFtitleAll('./li/a',mangainfo.chapterlinks,mangainfo.chapternames,v1) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + local servers = { + 'http://i.hamreus.com', + 'http://us.hamreus.com', + 'http://dx.hamreus.com', + 'http://eu.hamreus.com', + 'http://lt.hamreus.com', + } + + math.randomseed(os.time()) + math.random(); math.random(); math.random(); + + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "p,a,c,k")]') + s = SeparateRight(s, "}('") + local text = SeparateLeft(s, "',"); + local a = tonumber(GetBetween("',", ",", s)) + s = SeparateRight(s, "',") + local c = tonumber(GetBetween(",", ",'", s)) + local w = js.splitstr(lz.decompressFromBase64(GetBetween(",'", "'", s)), '|') + s = js.unpack36(text, a, c, w) + s = s:gsub('^var%s+.+=%s*{', '{'):gsub('||{};$', ''):gsub('"status":,', '') + x.parsehtml(s) + local cid = x.xpathstring('json(*).cid') + local md5 = x.xpathstring('json(*).sl.md5') + local path = x.xpathstring('json(*).path') + local srv = servers[math.random(#servers)] + v=x.xpath('json(*).files()') + for i=1,v.count do + v1=v.get(i) + task.pagelinks.add(srv .. path .. v1.toString .. '?cid=' .. cid .. '&md5=' .. md5) + end + return true + else + return false + end +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/list/') then + x = TXQuery.Create(http.Document) + local s = x.XPathString('//div[contains(@id, "AspNetPager")]/a[last()]/@href') + page = tonumber(s:match('%d+')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl..'/list/index_p'..IncStr(url)..'.html') then + TXQuery.Create(http.document).xpathhrefall('//ul[@id="contList"]/li/p/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Raw' + m.website='ManHuaGui' + m.rooturl='http://www.manhuagui.com' + m.lastupdated='February 21, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' +end \ No newline at end of file diff --git a/lua/modules/jsunpack.lua b/lua/modules/jsunpack.lua new file mode 100644 index 000000000..bff9f8f03 --- /dev/null +++ b/lua/modules/jsunpack.lua @@ -0,0 +1,77 @@ +local _M = {} + +local lookup36 = '0123456789abcdefghijklmnopqrstuvwxyz' + +function encode36(code) + local result = '' + local i = 0 + repeat + local digit = math.fmod(math.floor(code / (36^i)), 36) + result = string.char(string.byte(lookup36, digit+1)) .. result + code = code - digit * (36^i) + i = i + 1 + until code <= 0 + return result +end + +function getid(c, a) + local result = '' + if c < a then + result = '' + else + result = getid(math.floor(c / a), a) + end + c = math.fmod(c, a) + if c > 35 then + result = result .. string.char(c + 29) + else + result = result .. encode36(c) + end + return result +end + +function _M.unpack36(text, a, c, words) + if (a == nil) or (c == nil) then return '' end + if type(words) == 'string' then + words = splitstr(words, '|') + end + local dict = {} + while c ~= 0 do + c = c - 1 + dict[getid(c, a)] = words[c+1] + end + return text:gsub('%f[%w](%w+)%f[%W]', + function (w) + if (dict[w] ~= nil) and (dict[w] ~= '') then + return dict[w] + else + return w + end + end) +end + +function _M.replacehex(text) + return text:gsub('(\\x)([%da-f][%da-f]?)', + function (x, w) + return string.char(tonumber(w, 16)) + end + ) +end + +function _M.splitstr(str, delimiter) + local result = { } + local from = 1 + local delim_from, delim_to = string.find(str, delimiter, from) + while delim_from do + table.insert(result, string.sub(str, from , delim_from-1)) + from = delim_to + 1 + delim_from, delim_to = string.find(str, delimiter, from) + end + table.insert(result, string.sub(str, from)) + return result +end + +function Init() +end + +return _M diff --git a/lua/modules/lzstring.lua b/lua/modules/lzstring.lua new file mode 100644 index 000000000..da7d925c1 --- /dev/null +++ b/lua/modules/lzstring.lua @@ -0,0 +1,184 @@ +local _M = {} + +local keyStrBase64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' +local dictBase64 = {} + +function filldict() + for i = 0, string.len(keyStrBase64)-1 do + dictBase64[string.char(string.byte(keyStrBase64, i+1))] = i + end +end + +function getval64(input, index) + return dictBase64[string.char(string.byte(input, index + 1))] +end + +function _M.decompressFromBase64(input) + if (not input) or (input == '') then return '' end + return _decompress(input, 32, getval64) +end + +function codepoint_to_utf8(c) + assert((55296 > c or c > 57343) and c < 1114112, "Bad Unicode code point: "..c..".") + if c < 128 then + return string.char(c) + elseif c < 2048 then + return string.char(math.floor(192 + c/64), 128 + c%64) + elseif c < 55296 or 57343 < c and c < 65536 then + return string.char(math.floor(224 + c/4096), math.floor(128 + c/64%64), 128 + c%64) + elseif c < 1114112 then + return string.char(math.floor(240 + c/262144), math.floor(128 + c/4096%64), math.floor(128 + c/64%64), 128 + c%64) + end +end + +function tochar(i) + return codepoint_to_utf8(i) +end + +function _decompress(input, rst, getval) + local result, enlargeIn, numBits = '', 4, 3 + local maxpower, power, bits = 2^2, 1, 0 + local dictionary = {[0] = '0', [1] = '1', [2] = '2'} + local dataval, datapos, dataindex = getval(input, 0), rst, 1 + local w, c, c2, entry, dsize = '\0', '\0', 0, '', 4 + + while power ~= maxpower do + resb = dataval & datapos + datapos = datapos >> 1 + if datapos == 0 then + datapos = rst + dataval = getval(input, dataindex) + dataindex = dataindex + 1; + end + if resb > 0 then bits = bits | power end + power = power << 1 + end + + if bits == 0 then + maxpower = 2^8 + power, bits = 1, 0 + while power ~= maxpower do + resb = dataval & datapos + datapos = datapos >> 1 + if datapos == 0 then + datapos = rst + dataval = getval(input, dataindex) + dataindex = dataindex + 1; + end + if resb > 0 then bits = bits | power end + power = power << 1 + end + c = tochar(bits) + elseif bits == 1 then + maxpower = 2^16 + power, bits = 1, 0 + while power ~= maxpower do + resb = dataval & datapos + datapos = datapos >> 1 + if datapos == 0 then + datapos = rst + dataval = getval(input, dataindex) + dataindex = dataindex + 1; + end + if resb > 0 then bits = bits | power end + power = power << 1 + end + c = tochar(bits) + elseif bits == 2 then + return '' + end + + dictionary[3] = c + w = c + result = result .. c + + while true do + if dataindex > string.len(input) then + return '' + end + maxpower = 2^numBits + power, bits = 1, 0 + while power ~= maxpower do + resb = dataval & datapos + datapos = datapos >> 1 + if datapos == 0 then + datapos = rst + dataval = getval(input, dataindex) + dataindex = dataindex + 1; + end + if resb > 0 then bits = bits | power end + power = power << 1 + end + + c2 = bits + if bits == 0 then + maxpower = 2^8 + power, bits = 1, 0 + while power ~= maxpower do + resb = dataval & datapos + datapos = datapos >> 1 + if datapos == 0 then + datapos = rst + dataval = getval(input, dataindex) + dataindex = dataindex + 1; + end + if resb > 0 then bits = bits | power end + power = power << 1 + end + dictionary[dsize] = tochar(bits) + c2 = dsize + dsize = dsize + 1 + enlargeIn = enlargeIn - 1; + elseif bits == 1 then + maxpower = 2^16 + power, bits = 1, 0 + while power ~= maxpower do + resb = dataval & datapos + datapos = datapos >> 1 + if datapos == 0 then + datapos = rst + dataval = getval(input, dataindex) + dataindex = dataindex + 1; + end + if resb > 0 then bits = bits | power end + power = power << 1 + end + dictionary[dsize] = tochar(bits) + c2 = dsize + dsize = dsize + 1 + enlargeIn = enlargeIn - 1; + elseif bits == 2 then + return result + end + + if enlargeIn == 0 then + enlargeIn = 2^numBits + numBits = numBits + 1 + end + + if dsize - 1 >= c2 then + entry = dictionary[c2] + elseif c2 == dsize then + entry = w .. string.char(string.byte(w,1)) + else + return '' + end + + result = result .. entry + dictionary[dsize] = w .. string.char(string.byte(entry,1)) + dsize = dsize + 1 + enlargeIn = enlargeIn - 1 + w = entry + if enlargeIn == 0 then + enlargeIn = 2^numBits + numBits = numBits + 1 + end + end +end + +function Init() +end + +filldict() + +return _M From 65a96706d091fcfcddd74a2454d08952aab0254b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 19:10:18 +0800 Subject: [PATCH 2362/2794] add DarkSkyScan, NozominoFansub --- lua/modules/myReaderMangaCMS.lua | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 27373f1da..1b9c0b760 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -64,11 +64,19 @@ function AddWebsiteModule(name, url, cat) end function Init() - AddWebsiteModule('Komikid', 'http://www.komikid.com', 'Indonesian'); - AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', 'Turkish'); AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); - AddWebsiteModule('MangaID', 'http://mangaid.co', 'Indonesian'); - AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', 'English-Scanlation'); - AddWebsiteModule('MangaDesu','http://mangadesu.net', 'Indonesian'); - AddWebsiteModule('ChibiManga','http://www.cmreader.info', 'English-Scanlation'); + AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', 'Turkish'); + + local c='Indonesian' + AddWebsiteModule('Komikid', 'http://www.komikid.com', c); + AddWebsiteModule('MangaDesu','http://mangadesu.net', c); + AddWebsiteModule('MangaID', 'http://mangaid.co', c); + + c='English-Scanlation' + AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); + AddWebsiteModule('ChibiManga','http://www.cmreader.info', c); + + c='Spanish-Scanlation' + AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); + AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com/', c); end From e9aca2145ab6d806efa4f33510a7ad5eaaccaeb4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 19:17:20 +0800 Subject: [PATCH 2363/2794] selfupdater, handle sf --- baseunits/SelfUpdater.pas | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index 9c095c206..cc90a7f27 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -59,7 +59,7 @@ TSelfUpdaterThread = class(TBaseThread) implementation -uses FMDVars; +uses FMDVars, SourceForge; { TSelfUpdaterThread } @@ -247,9 +247,12 @@ procedure TSelfUpdaterThread.Execute; try FStatusText := Format(RS_Downloading, [UpdateURL]); Synchronize(@SyncStartDownload); - if FHTTP.GET(UpdateURL) and (FHTTP.ResultCode < 300) then // should be success + if Pos('sourceforge.net', AnsiLowerCase(UpdateURL)) <> 0 then + DownloadSuccess := SourceForge.Download(FHTTP, UpdateURL) + else + DownloadSuccess := FHTTP.GET(UpdateURL) and (FHTTP.ResultCode < 300); + if DownloadSuccess then begin - DownloadSuccess := True; Filename := FMD_DIRECTORY + UPDATE_PACKAGE_NAME; if FileExists(Filename) then DeleteFile(Filename); From 5b2cd6ad0e0804ba9d0e54e6bd816b4ff104642b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 19:41:09 +0800 Subject: [PATCH 2364/2794] selfupdater, add dialog missing file --- baseunits/SelfUpdater.pas | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index cc90a7f27..1f7332da9 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -51,7 +51,7 @@ TSelfUpdaterThread = class(TBaseThread) RS_FailedTitle = 'Failed'; RS_FailedDownload = 'Failed to download new version %s'#13#10#13#10'%d %s'; RS_FailedToSave = 'Failed to save %s'; - RS_MissingZipExe = 'Missing %s'; + RS_MissingFile = 'Missing %s'; RS_FailedExtract = 'Failed to extract %s, exitstatus = %d'; RS_ButtonCancel = 'Abort'; RS_FinishRestartTitle = 'Download finished'; @@ -204,14 +204,13 @@ procedure TSelfUpdaterThread.SyncFinishRestart; procedure TSelfUpdaterThread.ProceedUpdate; begin - if DownloadSuccess then + if not DownloadSuccess then Exit; + if FileExists(OLD_CURRENT_UPDATER_EXE) then + DeleteFile(OLD_CURRENT_UPDATER_EXE); + if FileExists(CURRENT_UPDATER_EXE) then + RenameFile(CURRENT_UPDATER_EXE, OLD_CURRENT_UPDATER_EXE); + if FileExists(OLD_CURRENT_UPDATER_EXE) then begin - if FileExists(OLD_CURRENT_UPDATER_EXE) then - DeleteFile(OLD_CURRENT_UPDATER_EXE); - if FileExists(CURRENT_UPDATER_EXE) then - RenameFile(CURRENT_UPDATER_EXE, OLD_CURRENT_UPDATER_EXE); - if not FileExists(OLD_CURRENT_UPDATER_EXE) then - Exit; with TProcess.Create(nil) do try InheritHandles := False; @@ -228,7 +227,9 @@ procedure TSelfUpdaterThread.ProceedUpdate; DoAfterFMD := DO_UPDATE; FormMain.tmExitCommand.Interval := 32; FormMain.tmExitCommand.Enabled := True; - end; + end + else + FFailedMessage := Format(RS_MissingFile, [OLD_CURRENT_UPDATER_EXE]); end; procedure TSelfUpdaterThread.UpdateStatusText(const S: String); @@ -278,7 +279,7 @@ procedure TSelfUpdaterThread.Execute; if DownloadSuccess and (not FileExists(CURRENT_ZIP_EXE)) then begin - FFailedMessage := Format(RS_MissingZipExe, [CURRENT_ZIP_EXE]); + FFailedMessage := Format(RS_MissingFile, [CURRENT_ZIP_EXE]); DownloadSuccess := False; end; end From cf2c44331a4815ca03290ebb6b9b47ccb24df76c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 19:41:47 +0800 Subject: [PATCH 2365/2794] cleanup localizations --- mangadownloader/languages/fmd.de.po | 27 +++++--------------------- mangadownloader/languages/fmd.el_GR.po | 25 ++++-------------------- mangadownloader/languages/fmd.en.po | 5 +++-- mangadownloader/languages/fmd.es.po | 4 +++- mangadownloader/languages/fmd.id_ID.po | 3 ++- mangadownloader/languages/fmd.pl_PL.po | 27 +++++--------------------- mangadownloader/languages/fmd.po | 3 ++- mangadownloader/languages/fmd.pt_BR.po | 12 ++---------- mangadownloader/languages/fmd.ru_RU.po | 6 ++---- mangadownloader/languages/fmd.tr_TR.po | 3 ++- 10 files changed, 30 insertions(+), 85 deletions(-) diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 3bcf7ee74..a783a688e 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -13,8 +13,6 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" msgstr "Abbrechen" @@ -43,7 +41,6 @@ msgid "" msgstr "" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Gescheitert" @@ -118,7 +115,6 @@ msgid "List of unimported manga" msgstr "Liste von nicht importierten Manga" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Prüfe..." @@ -467,7 +463,6 @@ msgid "All" msgstr "" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" msgstr "Ungültig" @@ -508,7 +503,6 @@ msgid "Save as PNG" msgstr "Speichern als PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Abbrechen" @@ -529,7 +523,6 @@ msgid "Failed to extract %s, exitstatus = %d" msgstr "" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Gescheitert" @@ -546,7 +539,8 @@ msgstr "" msgid "Download finished" msgstr "" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" @@ -1635,10 +1629,8 @@ msgstr "" "Manga Ordnername muss mindest %MANGA% haben.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" -msgstr "Anzahl von Downloads zur selben Zeit (Max: 8)" +msgstr "Anzahl von Downloads zur selben Zeit" #: tmainform.lboptionmaxretry.caption #| msgid "Number of retry times if tasks have download problems (0 = always retry)" @@ -1646,10 +1638,8 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Anzahl der erneuten Versuche, falls der Download Probleme hat (-1 =immer wiederholen)" #: tmainform.lboptionmaxthread.caption -#, fuzzy -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" -msgstr "Anzahl der Download-Dateien je Aufgabe zur selben Zeit (Max: 32)" +msgstr "Anzahl der Download-Dateien je Aufgabe zur selben Zeit" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -2233,7 +2223,6 @@ msgid "&Add to queue" msgstr "&zur Warteschlage hinzufügen" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" @@ -2251,13 +2240,11 @@ msgid "&Now" msgstr "&Jetzt" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Abbrechen" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" @@ -2281,7 +2268,6 @@ msgid "All" msgstr "" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" msgstr "Ungültig" @@ -2292,14 +2278,11 @@ msgid "Valid" msgstr "" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Webseite" +msgstr "Title" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Webseite" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 1ebcc250f..931c8bd52 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -17,8 +17,6 @@ msgstr "" "X-Poedit-Country: GREECE\n" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" msgstr "Άκυρο" @@ -47,7 +45,6 @@ msgid "" msgstr "" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Απέτυχε" @@ -122,7 +119,6 @@ msgid "List of unimported manga" msgstr "Λίστα μη εισηγμένων manga" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Έλεγχος..." @@ -471,7 +467,6 @@ msgid "All" msgstr "" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" msgstr "Μη έγκυρο" @@ -512,7 +507,6 @@ msgid "Save as PNG" msgstr "Αποθήκευση ως PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Ματαίωση" @@ -533,7 +527,6 @@ msgid "Failed to extract %s, exitstatus = %d" msgstr "" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Απέτυχε" @@ -550,7 +543,8 @@ msgstr "" msgid "Download finished" msgstr "" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" @@ -1690,10 +1684,8 @@ msgstr "" "Το όνομα φακέλου Manga πρέπει να έχει τουλάχιστον %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" -msgstr "Αριθμός ταυτόχρονων εργασιών λήψης (Μέγ.: 8)" +msgstr "Αριθμός ταυτόχρονων εργασιών λήψης" #: tmainform.lboptionmaxretry.caption #| msgid "Number of retry times if tasks have download problems (0 = always retry)" @@ -1701,10 +1693,8 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Αριθμός επαναλήψεων αν οι εργασίες έχουν προβλήματα λήψης (-1 = συνεχής επανάληψη)" #: tmainform.lboptionmaxthread.caption -#, fuzzy -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" -msgstr "Αριθμός ταυτόχρονα ληφθέντων αρχείων ανά εργασία (Μέγ: 32)" +msgstr "Αριθμός ταυτόχρονα ληφθέντων αρχείων ανά εργασία" #: tmainform.lboptionnewmangatime.caption msgid "New manga based on it's update time (days)" @@ -2288,7 +2278,6 @@ msgid "&Add to queue" msgstr "&Προσθήκη στην ουρά" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "Εντάξει" @@ -2306,13 +2295,11 @@ msgid "&Now" msgstr "&Τώρα" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Άκυρο" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "Εντάξει" @@ -2336,7 +2323,6 @@ msgid "All" msgstr "" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" msgstr "Μη έγκυρο" @@ -2347,14 +2333,11 @@ msgid "Valid" msgstr "" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" msgstr "Ιστότοπος" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Ιστότοπος" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index e53f751c4..097305d83 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -20,7 +20,7 @@ msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "%s: failed to extract, exitstatus = %d"\ +msgstr "%s: failed to extract, exitstatus = %d\"" #: dbupdater.rs_faileditems msgid "" @@ -549,7 +549,8 @@ msgstr "Download update package finished, restart to proceed?" msgid "Download finished" msgstr "Download finished" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "Missing %s" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 69b6cb3fc..48d0a404e 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -560,7 +560,8 @@ msgstr "La Descarga del Paquete ha Terminado, Proceder en Reiniciar?" msgid "Download finished" msgstr "Descarga Finalizada" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "Perdido %s" @@ -2573,3 +2574,4 @@ msgstr "Sincronizando Datos" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Actualizando Lista" + diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index a1bea36a2..55e11f015 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -549,7 +549,8 @@ msgstr "Pembaruan selesai diunduh, memuat ulang sekarang?" msgid "Download finished" msgstr "Unduhan selesai" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "Tidak ditemukan %s" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 64d17f007..35524b4c4 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -13,8 +13,6 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: dbupdater.rs_buttoncancel -#, fuzzy -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" msgstr "Anuluj" @@ -43,7 +41,6 @@ msgid "" msgstr "" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Niepowodzenie" @@ -118,7 +115,6 @@ msgid "List of unimported manga" msgstr "Lista niezaimportowanych mang" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Sprawdzanie..." @@ -467,7 +463,6 @@ msgid "All" msgstr "" #: frmtransferfavorites.rs_invalid -#, fuzzy msgctxt "frmtransferfavorites.rs_invalid" msgid "Invalid" msgstr "Niepoprawnie" @@ -508,7 +503,6 @@ msgid "Save as PNG" msgstr "Zapisz jako PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Anuluj" @@ -529,7 +523,6 @@ msgid "Failed to extract %s, exitstatus = %d" msgstr "" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Niepowodzenie" @@ -546,7 +539,8 @@ msgstr "" msgid "Download finished" msgstr "" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" @@ -1635,10 +1629,8 @@ msgstr "" "Nazwa folderu z mangą musi mieć przynajmniej %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#, fuzzy -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" -msgstr "Ilość pobierań w tym samym czasie (max: 8)" +msgstr "Ilość pobierań w tym samym czasie" #: tmainform.lboptionmaxretry.caption #| msgid "Number of retry times if tasks have download problems (0 = always retry)" @@ -1646,10 +1638,8 @@ msgid "Number of retry times if tasks have download problems (-1 = always retry) msgstr "Ilość prób pobierania po nieudanym pobraniu (-1 = zawsze próbuj)" #: tmainform.lboptionmaxthread.caption -#, fuzzy -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" -msgstr "Liczba pobieranych plików na zadanie w tym samym czasie (Max: 32)" +msgstr "Liczba pobieranych plików na zadanie w tym samym czasie" # WTF does that mean? #: tmainform.lboptionnewmangatime.caption @@ -2235,7 +2225,6 @@ msgid "&Add to queue" msgstr "&Dodaj do kolejki" #: tselectdirectoryform.btok.caption -#, fuzzy msgctxt "tselectdirectoryform.btok.caption" msgid "OK" msgstr "OK" @@ -2253,13 +2242,11 @@ msgid "&Now" msgstr "&Teraz" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Anuluj" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" @@ -2283,7 +2270,6 @@ msgid "All" msgstr "" #: ttransferfavoritesform.rbinvalid.caption -#, fuzzy msgctxt "ttransferfavoritesform.rbinvalid.caption" msgid "Invalid" msgstr "Niepoprawnie" @@ -2294,14 +2280,11 @@ msgid "Valid" msgstr "" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" -msgstr "Strona WWW" +msgstr "Tytuł" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Strona WWW" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 716402ead..01666e7f7 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -502,7 +502,8 @@ msgstr "" msgid "Download finished" msgstr "" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 431eb5f21..302517a27 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -13,7 +13,6 @@ msgstr "" "Plural-Forms: \n" #: dbupdater.rs_buttoncancel -#, fuzzy #| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" @@ -43,7 +42,6 @@ msgid "" msgstr "" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Falhou" @@ -118,7 +116,6 @@ msgid "List of unimported manga" msgstr "Lista de mangás não importados" #: frmluamodulesupdater.rs_checking -#, fuzzy msgctxt "frmluamodulesupdater.rs_checking" msgid "Checking..." msgstr "Checando..." @@ -507,7 +504,6 @@ msgid "Save as PNG" msgstr "Salvar como PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Abortar" @@ -528,7 +524,6 @@ msgid "Failed to extract %s, exitstatus = %d" msgstr "" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Falhou" @@ -545,7 +540,8 @@ msgstr "" msgid "Download finished" msgstr "" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" @@ -2248,13 +2244,11 @@ msgid "&Now" msgstr "&Agora" #: ttransferfavoritesform.btcancel.caption -#, fuzzy msgctxt "ttransferfavoritesform.btcancel.caption" msgid "Cancel" msgstr "Cancelar" #: ttransferfavoritesform.btok.caption -#, fuzzy msgctxt "ttransferfavoritesform.btok.caption" msgid "OK" msgstr "OK" @@ -2288,14 +2282,12 @@ msgid "Valid" msgstr "Válido" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#, fuzzy #| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" msgstr "Título" #: ttransferfavoritesform.vtfavs.header.columns[2].text -#, fuzzy msgctxt "ttransferfavoritesform.vtfavs.header.columns[2].text" msgid "Website" msgstr "Website" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 91dea33ca..b55cdeb3a 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -43,7 +43,6 @@ msgstr "" "%s\n" #: dbupdater.rs_faileditemstitle -#, fuzzy msgctxt "dbupdater.rs_faileditemstitle" msgid "Failed" msgstr "Неудачно" @@ -521,7 +520,6 @@ msgid "Save as PNG" msgstr "Сохранить как PNG" #: selfupdater.rs_buttoncancel -#, fuzzy msgctxt "selfupdater.rs_buttoncancel" msgid "Abort" msgstr "Отменить" @@ -542,7 +540,6 @@ msgid "Failed to extract %s, exitstatus = %d" msgstr "" #: selfupdater.rs_failedtitle -#, fuzzy msgctxt "selfupdater.rs_failedtitle" msgid "Failed" msgstr "Неудачно" @@ -559,7 +556,8 @@ msgstr "" msgid "Download finished" msgstr "" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index b1c4a6075..a0a523ba5 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -563,7 +563,8 @@ msgstr "Güncelleme paketi indirme tamamlandı, devam etmek için yeniden başla msgid "Download finished" msgstr "İndirme tamamlandı" -#: selfupdater.rs_missingzipexe +#: selfupdater.rs_missingfile +msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "%s eksik" From b17f1e7210bea55a4bff0b59a69cc2f7253e6d05 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 21:28:01 +0800 Subject: [PATCH 2366/2794] kissmanga, default use googledcp to false --- baseunits/modules/KissManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 13bb6b1ee..b38468ca8 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -18,7 +18,7 @@ implementation var kissmangaiv: String ='a5e8e2e9c2721be0a84ad660c472c1f3'; kissmangakey: String ='mshsdf832nsdbash20asdmnasdbasd612basd'; - kissmangausegoogledcp: Boolean = True; + kissmangausegoogledcp: Boolean = False; resourcestring RS_KissManga_Key = 'Key:'; From 8afa6336ae4b035e8b1d659c82e0e64860f778bc Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 21:29:22 +0800 Subject: [PATCH 2367/2794] websitemodules, save and load website settings #1020 --- baseunits/FMDOptions.pas | 11 +- baseunits/WebsiteModules.pas | 170 +++++++++++++----- .../forms/frmLuaModulesUpdater.pas | 4 +- mangadownloader/forms/frmMain.pas | 4 +- .../forms/frmWebsiteOptionCustom.lfm | 3 +- .../forms/frmWebsiteOptionCustom.pas | 6 - 6 files changed, 138 insertions(+), 60 deletions(-) diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index 0b36a130c..a3b6b98cb 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -86,7 +86,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) UPDATE_FILE, BASE_FILE, ACCOUNTS_FILE, - WEBSITE_CONFIG_FILE, + MODULES_FILE, DATA_FOLDER, IMAGE_FOLDER, LANGUAGE_FILE, @@ -96,7 +96,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) EXTRAS_FOLDER, MANGAFOXTEMPLATE_FOLDER, LUA_WEBSITEMODULE_FOLDER, - LUA_WEBSITEMODULE_REPOS: String; + LUA_WEBSITEMODULE_FILE: String; // ini files revisionfile, @@ -304,8 +304,6 @@ procedure SetFMDdirectory(const ADir: String); OLD_CURRENT_UPDATER_EXE := FMD_DIRECTORY + OLD_UPDATER_EXE; CURRENT_ZIP_EXE := FMD_DIRECTORY + ZIP_EXE; - LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; - LUA_WEBSITEMODULE_REPOS := CONFIG_FOLDER + 'luamodules.json'; ReadBaseFile; end; @@ -320,7 +318,8 @@ procedure SetAppDataDirectory(const ADir: String); CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; CONFIG_ADVANCED := CONFIG_FOLDER + 'advanced.ini'; ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; - WEBSITE_CONFIG_FILE := CONFIG_FOLDER + 'websiteconfig.ini'; + MODULES_FILE := CONFIG_FOLDER + 'modules.json'; + LUA_WEBSITEMODULE_FILE := CONFIG_FOLDER + 'luamodules.json'; DATA_FOLDER := APPDATA_DIRECTORY + 'data' + PathDelim; @@ -332,6 +331,8 @@ procedure SetAppDataDirectory(const ADir: String); FAVORITES_FILE := WORK_FOLDER + 'favorites.ini'; FAVORITESDB_FILE := WORK_FOLDER + 'favorites.db'; + LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim; + SetIniFiles; end; diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index ccb0b69f4..dabb3ded0 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -11,7 +11,7 @@ interface uses Classes, SysUtils, fgl, uData, uDownloadsManager, FMDOptions, httpsendthread, - LazLogger, Cloudflare, RegExpr; + LazLogger, Cloudflare, RegExpr, fpjson, jsonparser, jsonscanner, fpjsonrtti; const MODULE_NOT_FOUND = -1; @@ -71,18 +71,32 @@ TWebsiteOptionItem = record { TWebsiteModuleSettings } TWebsiteModuleSettings = class - public - MaxTaskLimit: Integer; - MaxConnectionLimit: Integer; - UpdateListNumberOfThreads: Integer; - UpdateListDirectoryPageNumber: Integer; - UserAgent: String; - Cookies: String; - ProxyType: TProxyType; - ProxyHost: String; - ProxyPort: String; - ProxyUsername: String; - ProxyPassword: String; + private + FCookies: String; + FMaxConnectionLimit: Integer; + FMaxTaskLimit: Integer; + FMaxThreadPerTaskLimit: Integer; + FProxyHost: String; + FProxyPassword: String; + FProxyPort: String; + FProxyType: TProxyType; + FProxyUsername: String; + FUpdateListDirectoryPageNumber: Integer; + FUpdateListNumberOfThread: Integer; + FUserAgent: String; + published + property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit; + property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit; + property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit; + property UpdateListNumberOfThread: Integer read FUpdateListNumberOfThread write FUpdateListNumberOfThread; + property UpdateListDirectoryPageNumber: Integer read FUpdateListDirectoryPageNumber write FUpdateListDirectoryPageNumber; + property UserAgent: String read FUserAgent write FUserAgent; + property Cookies: String read FCookies write FCookies; + property ProxyType: TProxyType read FProxyType write FProxyType; + property ProxyHost: String read FProxyHost write FProxyHost; + property ProxyPort: String read FProxyPort write FProxyPort; + property ProxyUsername: String read FProxyUsername write FProxyUsername; + property ProxyPassword: String read FProxyPassword write FProxyPassword; end; { TModuleContainer } @@ -262,8 +276,8 @@ TWebsiteModules = class procedure DecActiveConnectionCount(ModuleId: Integer); function CanCreateConnection(ModuleId: Integer): Boolean; - procedure LoadWebsiteOption; - procedure SaveWebsiteOption; + procedure LoadFromFile; + procedure SaveToFile; end; var @@ -828,43 +842,113 @@ function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; Result := ActiveConnectionCount < Settings.MaxConnectionLimit; end; -procedure TWebsiteModules.LoadWebsiteOption; +procedure TWebsiteModules.LoadFromFile; var - i, j: Integer; + i, j, k: Integer; + jd: TJSONDeStreamer; + ja: TJSONArray; + fs: TFileStream; + jp: TJSONParser; + jo, jo2: TJSONObject; begin - if FModuleList.Count = 0 then Exit; - for i := 0 to FModuleList.Count - 1 do - with FModuleList[i] do - if Length(OptionList) > 0 then - for j := Low(OptionList) to High(OptionList) do - with OptionList[j], configfile do + if FModuleList.Count=0 then Exit; + if not FileExists(MODULES_FILE) then Exit; + + ja:=nil; + try + fs:=TFileStream.Create(MODULES_FILE,fmOpenRead or fmShareDenyWrite); + try + jp:=TJSONParser.Create(fs,[joUTF8]); + ja:=TJSONArray(jp.Parse); + finally + jp.Free; + end; + finally + fs.Free; + end; + + if (ja<>nil) and (ja.Count<>0) then + try + jd:=TJSONDeStreamer.Create(nil); + for i:=FModuleList.Count-1 downto 0 do + with FModuleList[i] do + begin + jo:=nil; + for j:=ja.Count-1 downto 0 do + if ja.Objects[j].Get('Website','')=Website then + begin + jo:=ja.Objects[j]; + Break; + end; + if jo<>nil then begin - case OptionType of - woCheckBox: PBoolean(BindValue)^ := ReadBool(Website, Name, PBoolean(BindValue)^); - woEdit: PString(BindValue)^ := ReadString(Website, Name, PString(BindValue)^); - woSpinEdit, woComboBox: PInteger(BindValue)^ := ReadInteger(Website, Name, PInteger(BindValue)^); + jo2:=jo.Get('Settings',TJSONObject(nil)); + if jo2<>nil then + jd.JSONToObject(jo2,Settings); + if Length(OptionList)<>0 then + begin + jo2:=jo.Get('Options',TJSONObject(nil)); + if jo2<>nil then + for k:=Low(OptionList) to High(OptionList) do + with OptionList[k],jo2 do + case OptionType of + woCheckBox:PBoolean(BindValue)^:=Get(Name,PBoolean(BindValue)^); + woEdit:PString(BindValue)^:=Get(Name,PString(BindValue)^); + woSpinEdit,woComboBox:PInteger(BindValue)^:=Get(Name,PInteger(BindValue)^); + end; end; + ja.Delete(j); end; + end; + finally + jd.Free; + ja.Free; + end; end; -procedure TWebsiteModules.SaveWebsiteOption; +procedure TWebsiteModules.SaveToFile; var i, j: Integer; -begin - if FModuleList.Count = 0 then Exit; - for i := 0 to FModuleList.Count - 1 do - with FModuleList[i] do - if Length(OptionList) > 0 then - for j := Low(OptionList) to High(OptionList) do - with OptionList[j], configfile do - begin - case OptionType of - woCheckBox: WriteBool(Website, Name, PBoolean(BindValue)^); - woEdit: WriteString(Website, Name, PString(BindValue)^); - woSpinEdit, woComboBox: WriteInteger(Website, Name, PInteger(BindValue)^); - end; - end; - configfile.UpdateFile; + js: TJSONStreamer; + ja: TJSONArray; + fs: TFileStream; + jo: TJSONObject; + jo2: TJSONObject; +begin + if FModuleList.Count=0 then Exit; + ja:=TJSONArray.Create; + js:=TJSONStreamer.Create(nil); + try + for i:=0 to FModuleList.Count-1 do + with FModuleList[i] do + begin + jo:=TJSONObject.Create; + ja.Add(jo); + jo.Add('Website',Website); + jo.Add('Settings',js.ObjectToJSON(Settings)); + if Length(OptionList) <> 0 then + begin + jo2:=TJSONObject.Create; + jo.Add('Options',jo2); + for j:=Low(OptionList) to High(OptionList) do + with OptionList[j],jo2 do + case OptionType of + woCheckBox:Add(Name,PBoolean(BindValue)^); + woEdit:Add(Name,PString(BindValue)^); + woSpinEdit,woComboBox:Add(Name,PInteger(BindValue)^); + end; + end; + end; + fs:=TFileStream.Create(MODULES_FILE,fmCreate); + try + ja.DumpJSON(fs); + finally + fs.Free; + end; + finally + ja.Free; + js.Free; + end; end; function TWebsiteModules.GetModule(const ModuleId: Integer): TModuleContainer; diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index 25ccaad23..840bfa3e2 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -549,7 +549,7 @@ procedure TCheckUpdateThread.SyncFinal; FOwner.vtLuaModulesRepos.BeginUpdate; FOwner.Repos := FMainRepos; FOwner.ReinitList; - FMainRepos.SaveToFile(LUA_WEBSITEMODULE_REPOS); + FMainRepos.SaveToFile(LUA_WEBSITEMODULE_FILE); finally FOwner.vtLuaModulesRepos.EndUpdate; end; @@ -971,7 +971,7 @@ procedure TLuaModulesUpdaterForm.ListDirty; procedure TLuaModulesUpdaterForm.LoadLocalRepos; begin - Repos.LoadFromFile(LUA_WEBSITEMODULE_REPOS); + Repos.LoadFromFile(LUA_WEBSITEMODULE_FILE); ReinitList(False); end; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a834690ce..9afa84dd8 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1823,7 +1823,7 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); FavoriteManager.Restore; UpdateVtFavorites; - Modules.LoadWebsiteOption; + Modules.LoadFromFile; frmWebsiteOptionCustom.WebsiteOptionCustomForm.CreateWebsiteOption; if cbSelectManga.ItemIndex > -1 then @@ -5073,7 +5073,7 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); UpdateFile; end; advancedfile.UpdateFile; - Modules.SaveWebsiteOption; + Modules.SaveToFile; end; procedure TMainForm.ApplyOptions; diff --git a/mangadownloader/forms/frmWebsiteOptionCustom.lfm b/mangadownloader/forms/frmWebsiteOptionCustom.lfm index 62b5b8d4b..751609833 100644 --- a/mangadownloader/forms/frmWebsiteOptionCustom.lfm +++ b/mangadownloader/forms/frmWebsiteOptionCustom.lfm @@ -5,6 +5,5 @@ object CustomOptionForm: TCustomOptionForm Width = 320 Caption = 'CustomOptionForm' OnCreate = FormCreate - OnDestroy = FormDestroy - LCLVersion = '1.7' + LCLVersion = '1.8.0.6' end diff --git a/mangadownloader/forms/frmWebsiteOptionCustom.pas b/mangadownloader/forms/frmWebsiteOptionCustom.pas index cbc98789c..8458d1a9f 100644 --- a/mangadownloader/forms/frmWebsiteOptionCustom.pas +++ b/mangadownloader/forms/frmWebsiteOptionCustom.pas @@ -65,7 +65,6 @@ TComboBoxBindValue = class(TComboBox) TCustomOptionForm = class(TForm) procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); private { private declarations } function AddOptionItem(const AOptionItemType: TWebsiteOptionType; @@ -205,11 +204,6 @@ procedure TCustomOptionForm.FormCreate(Sender: TObject); end; end; -procedure TCustomOptionForm.FormDestroy(Sender: TObject); -begin - Modules.SaveWebsiteOption; -end; - function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionType; const AName, ACaption, AGroup, AGroupCaption: String): TWinControl; var From b52a1d554e9879626eb40a71d256fa060f0849e3 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 21:47:17 +0800 Subject: [PATCH 2368/2794] websitemodule, add account #1020 --- baseunits/WebsiteModules.pas | 47 +++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index dabb3ded0..228550db2 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -99,15 +99,35 @@ TWebsiteModuleSettings = class property ProxyPassword: String read FProxyPassword write FProxyPassword; end; + TAccountStatus = (asUnknown, asChecking, asValid, asInvalid); + + { TWebsiteModuleAccount } + + TWebsiteModuleAccount = class + private + FCookies: String; + FPassword: String; + FStatus: TAccountStatus; + FUsername: String; + published + property Username: String read FUsername write FUsername; + property Password: String read FPassword write FPassword; + property Cookies: String read FCookies write FCookies; + property Status: TAccountStatus read FStatus write FStatus; + end; + { TModuleContainer } TModuleContainer = class private + FAccount: TWebsiteModuleAccount; + FAccountSupport: Boolean; FID: Integer; FSettings: TWebsiteModuleSettings; FTotalDirectory: Integer; FCloudflareCF: TCFProps; FCloudflareEnabled: Boolean; + procedure SetAccountSupport(AValue: Boolean); procedure SetCloudflareEnabled(AValue: Boolean); procedure CheckCloudflareEnabled(const AHTTP: THTTPSendThread); function CloudflareHTTPRequest(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject = nil): Boolean; @@ -122,7 +142,6 @@ TModuleContainer = class Category: String; ActiveTaskCount: Integer; ActiveConnectionCount: Integer; - AccountSupport: Boolean; SortedList: Boolean; InformationAvailable: Boolean; FavoriteAvailable: Boolean; @@ -165,6 +184,8 @@ TModuleContainer = class procedure DecActiveConnectionCount; inline; property Settings: TWebsiteModuleSettings read FSettings write FSettings; + property AccountSupport: Boolean read FAccountSupport write SetAccountSupport; + property Account: TWebsiteModuleAccount read FAccount write FAccount; end; TModuleContainers = specialize TFPGList<TModuleContainer>; @@ -334,6 +355,20 @@ procedure TModuleContainer.SetCloudflareEnabled(AValue: Boolean); end; end; +procedure TModuleContainer.SetAccountSupport(AValue: Boolean); +begin + if FAccountSupport = AValue then Exit; + FAccountSupport := AValue; + if FAccountSupport then + begin + if FAccount = nil then + FAccount := TWebsiteModuleAccount.Create; + end + else + if FAccount<>nil then + FAccount.Free; +end; + procedure TModuleContainer.CheckCloudflareEnabled(const AHTTP: THTTPSendThread); begin if FCloudflareEnabled then @@ -381,6 +416,8 @@ destructor TModuleContainer.Destroy; SetLength(OptionList,0); if Assigned(FCloudflareCF) then FCloudflareCF.Free; + if Assigned(FAccount) then + FAccount.Free; FSettings.Free; inherited Destroy; end; @@ -897,6 +934,12 @@ procedure TWebsiteModules.LoadFromFile; woSpinEdit,woComboBox:PInteger(BindValue)^:=Get(Name,PInteger(BindValue)^); end; end; + if Account<>nil then + begin + jo2:=jo.Get('Account',TJSONObject(nil)); + if jo2<>nil then + jd.JSONToObject(jo2,Account); + end; ja.Delete(j); end; end; @@ -938,6 +981,8 @@ procedure TWebsiteModules.SaveToFile; woSpinEdit,woComboBox:Add(Name,PInteger(BindValue)^); end; end; + if Account<>nil then + jo.Add('Account',js.ObjectToJSON(Account)); end; fs:=TFileStream.Create(MODULES_FILE,fmCreate); try From a63a0bee5f0262dc9a4337a5e447eb0b552e11c2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 22:05:16 +0800 Subject: [PATCH 2369/2794] downloadmanager, skip/stop task without module --- baseunits/uDownloadsManager.pas | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 221d7344a..592673d93 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1507,7 +1507,8 @@ procedure TDownloadManager.CheckAndActiveTask(const isCheckForFMDDo: Boolean); if tcount < OptionMaxParallel then for i := 0 to Items.Count - 1 do with Items[i] do - if (tcount < OptionMaxParallel) and + if (ModuleId<>-1) and + (tcount < OptionMaxParallel) and (Status = STATUS_WAIT) and Modules.CanCreateTask(ModuleId) then begin @@ -1563,8 +1564,16 @@ procedure TDownloadManager.CheckAndActiveTaskAtStartup; if (tcount < OptionMaxParallel) and Modules.CanCreateTask(ModuleId) then begin - Inc(tcount); - ActiveTask(i); + if ModuleId<>-1 then + begin + Inc(tcount); + ActiveTask(i); + end + else + begin + Status := STATUS_STOP; + DownloadInfo.Status := Format('[%d/%d] %s',[CurrentDownloadChapterPtr+1,ChapterLinks.Count,RS_Stopped]); + end; end else begin From c8fa35f943048853631a905a713cf9f50f7c384c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 21 Feb 2018 22:31:27 +0800 Subject: [PATCH 2370/2794] remove the use of advancedfile #1020 --- baseunits/WebsiteModules.pas | 27 +++++++++++++++++++++++++++ baseunits/uData.pas | 17 ++--------------- baseunits/uDownloadsManager.pas | 25 +++++-------------------- baseunits/uUpdateThread.pas | 22 ++++++---------------- mangadownloader/forms/frmMain.pas | 15 --------------- 5 files changed, 40 insertions(+), 66 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 228550db2..10bb0ef9d 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -200,6 +200,7 @@ TWebsiteModules = class function GetModule(const ModuleId: Integer): TModuleContainer; function GetCount: Integer; function GetMaxTaskLimit(const ModuleId: Integer): Integer; + function GetMaxThreadPerTaskLimit(const ModuleId: Integer): Integer; function GetMaxConnectionLimit(const ModuleId: Integer): Integer; function GetActiveTaskCount(const ModuleId: Integer): Integer; function GetActiveConnectionLimit(const ModuleId: Integer): Integer; @@ -287,6 +288,7 @@ TWebsiteModules = class property Website[const ModuleId: Integer]: String read GetWebsite; property MaxTaskLimit[const ModuleId: Integer]: Integer read GetMaxTaskLimit; + property MaxThreadPerTaskLimit[const ModuleId: Integer]: Integer read GetMaxThreadPerTaskLimit; property MaxConnectionLimit[const ModuleId: Integer]: Integer read GetMaxConnectionLimit; property ActiveTaskCount[const ModuleId: Integer]: Integer read GetActiveTaskCount; property ActiveConnectionCount[const ModuleId: Integer]: Integer read GetActiveConnectionLimit; @@ -447,8 +449,26 @@ procedure TModuleContainer.AddOptionComboBox(const ABindValue: PInteger; end; procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); +var + s: String; begin CheckCloudflareEnabled(AHTTP); + with Settings do + begin + if UserAgent<>'' then + AHTTP.UserAgent:=UserAgent; + if Cookies<>'' then + AHTTP.Cookies.Text:=Cookies; + s:=''; + case Settings.ProxyType of + ptDirect:AHTTP.SetNoProxy; + ptHTTP:s:='HTTP'; + ptSOCKS4:s:='SOCKS4'; + ptSOCKS5:s:='SOCKS5'; + end; + if s<>'' then + AHTTP.SetProxy(s,ProxyHost,ProxyPort,ProxyUsername,ProxyPassword); + end; end; procedure TModuleContainer.IncActiveTaskCount; @@ -1013,6 +1033,13 @@ function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; Result := FModuleList[ModuleId].Settings.MaxTaskLimit; end; +function TWebsiteModules.GetMaxThreadPerTaskLimit(const ModuleId: Integer + ): Integer; +begin + if not ModuleExist(ModuleId) then Exit(0); + Result := FModuleList[ModuleId].Settings.MaxThreadPerTaskLimit; +end; + function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin if not ModuleExist(ModuleId) then Exit(0); diff --git a/baseunits/uData.pas b/baseunits/uData.pas index fe81fb923..09bf71db0 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -108,20 +108,13 @@ procedure TMangaInformation.SetModuleId(AValue: Integer); end; function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: String): Byte; -var - p: Integer; begin APage := 1; - //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, AWebsite); - //load pagenumber_config if available - p := advancedfile.ReadInteger('UpdateListDirectoryPageNumber', AWebsite, -1); - - if p > 0 then + if Modules[ModuleId].Settings.UpdateListDirectoryPageNumber > 0 then begin - APage := p; + APage := Modules[ModuleId].Settings.UpdateListDirectoryPageNumber; BROWSER_INVERT := True; Exit(NO_ERROR); end; @@ -141,9 +134,6 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: function TMangaInformation.GetNameAndLink(const ANames, ALinks: TStringList; const AWebsite, AURL: String): Byte; begin - //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, AWebsite); - if ModuleId < 0 then ModuleId := Modules.LocateModule(AWebsite); if Modules.ModuleAvailable(ModuleId, MMGetNameAndLink) then @@ -168,9 +158,6 @@ function TMangaInformation.GetInfoFromURL(const AWebsite, AURL: String): Byte; if Trim(AURL) = '' then Exit(INFORMATION_NOT_FOUND); - //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, AWebsite); - GetBaseMangaInfo(mangaInfo, bmangaInfo); mangaInfo.website := AWebsite; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 592673d93..161cda3bb 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -704,29 +704,16 @@ procedure TTaskThread.CheckOut; var currentMaxThread: Integer; s: String; - mt: Integer; begin if Terminated then Exit; try - //load advanced config if any - mt := advancedfile.ReadInteger('DownloadMaxThreadsPerTask', - Container.DownloadInfo.Website, -1); - if (mt > 0) then - begin - if mt > MAX_CONNECTIONPERHOSTLIMIT then - mt := MAX_CONNECTIONPERHOSTLIMIT; - currentMaxThread := mt; - end + if Modules.MaxThreadPerTaskLimit[Container.ModuleId] > 0 then + currentMaxThread := Modules.MaxThreadPerTaskLimit[Container.ModuleId] else - begin - if Modules.MaxConnectionLimit[Container.ModuleId] > 0 then - currentMaxThread := Modules.MaxConnectionLimit[Container.ModuleId] - else - currentMaxThread := OptionMaxThreads; - if currentMaxThread > OptionMaxThreads then - currentMaxThread := OptionMaxThreads; - end; + currentMaxThread := OptionMaxThreads; + if currentMaxThread > OptionMaxThreads then + currentMaxThread := OptionMaxThreads; if Container.PageLinks.Count > 0 then begin @@ -760,8 +747,6 @@ procedure TTaskThread.CheckOut; with TDownloadThread(Threads.Last) do begin Task := Self; WorkId := Container.WorkCounter; - //load User-Agent from advancedfile - AdvanceLoadHTTPConfig(FHTTP, Container.DownloadInfo.Website); Start; Container.WorkCounter := InterLockedIncrement(Container.WorkCounter); end; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 7433a050a..e23b03cdf 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -377,7 +377,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end; var - mt, plimit: Integer; + plimit: Integer; s: String; t: TUpdateListThread; begin @@ -387,22 +387,12 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; if Terminated then Break; if ulTotalPtr <> FCurrentGetInfoLimit then ulTotalPtr := FCurrentGetInfoLimit; - mt := advancedfile.ReadInteger('UpdateListNumberOfThreads', website, -1); - if mt > 0 then - begin - if mt > MAX_CONNECTIONPERHOSTLIMIT then //32 is max | be carefull, there's still memory leak problems - mt := MAX_CONNECTIONPERHOSTLIMIT; - numberOfThreads := mt; - end + if Module.Settings.UpdateListNumberOfThread > 0 then + numberOfThreads := Module.Settings.UpdateListNumberOfThread else - begin - if Module.Settings.MaxConnectionLimit > 0 then - numberOfThreads := Module.Settings.MaxConnectionLimit - else - numberOfThreads := OptionMaxThreads; - if numberOfThreads > OptionMaxThreads then - numberOfThreads := OptionMaxThreads; - end; + numberOfThreads := OptionMaxThreads; + if numberOfThreads > OptionMaxThreads then + numberOfThreads := OptionMaxThreads; if numberOfThreads < 1 then numberOfThreads := 1; //default diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 9afa84dd8..024bd0ffb 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -819,8 +819,6 @@ TMangaInfoData = record jdn: Integer; end; - procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); - var MainForm: TMainForm; @@ -965,18 +963,6 @@ procedure ChangeAllCursor(const ParentControl: TWinControl; const Cur: TCursor); ParentControl.Controls[i].Cursor := Cur; end; -procedure AdvanceLoadHTTPConfig(const HTTP: THTTPSendThread; Website: String); -var - s: String; -begin - if HTTP = nil then Exit; - if Website = '' then Exit; - s:=Trim(advancedfile.ReadString('UserAgent',Website,'')); - if s<>'' then HTTP.UserAgent:=s; - s:=Trim(advancedfile.ReadString('Cookies',Website,'')); - if s<>'' then HTTP.Cookies.Text:=s; -end; - { TSearchDBThread } procedure TSearchDBThread.SyncBeforeSearch; @@ -5072,7 +5058,6 @@ procedure TMainForm.SaveOptions(const AShowDialog: Boolean); finally UpdateFile; end; - advancedfile.UpdateFile; Modules.SaveToFile; end; From 916bb89c59209bc1c7d75e9e5e860aef3719aea2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 21 Feb 2018 17:40:21 +0300 Subject: [PATCH 2371/2794] add ManHuaTai [Raw] --- lua/modules/ManHuaTai.lua | 100 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 lua/modules/ManHuaTai.lua diff --git a/lua/modules/ManHuaTai.lua b/lua/modules/ManHuaTai.lua new file mode 100644 index 000000000..ed2b447f2 --- /dev/null +++ b/lua/modules/ManHuaTai.lua @@ -0,0 +1,100 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[contains(@class, "mhjsbody")]/div/ul/li[contains(., "名称")]/substring-after(., "名称:")') + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[@class="comic-cover"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[contains(@class, "mhjsbody")]/div/ul/li[contains(., "作者")]/substring-after(., "作者:")') + mangainfo.genres=x.xpathstring('//div[contains(@class, "mhjsbody")]/div/ul/li[contains(., "类型")]/substring-after(., "类型:")') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(@class, "mhjsbody")]/div/ul/li[contains(., "状态")]/substring-after(., "状态:")'), '连载至', '已完结'); + mangainfo.summary=x.xpathstringall('//div[contains(@class,"wz")]/div/text()', '') + v=x.xpath('//div[@class="mhlistbody"]/ul') + for i=v.count,1,-1 do + v1=v.get(i) + w = x.xpath('./li/a', v1) + for j = 1, w.count do + w1 = w.get(j) + mangainfo.chapterlinks.add(mangainfo.url .. '/' .. w1.getAttribute('href')) + mangainfo.chapternames.add(w1.getAttribute('title')) + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + local servers = { + 'http://mhpic.mh51.com', + 'http://mhpic.manhualang.com', + 'http://mhpic.jumanhua.com', + 'http://mhpic.yyhao.com', + } + + math.randomseed(os.time()) + math.random(); math.random(); math.random(); + + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "mh_info")]') + local imgpath = GetBetween('imgpath:"', '",', s) + imgpath = imgpath:gsub('\\\\', '\\'):gsub("\\'", "'"):gsub('\\"', '"') + local pageid = tonumber(s:match('pageid:%s*(%d+)')) + local start = tonumber(s:match('startimg:%s*(%d+)')) + local total = tonumber(s:match('totalimg:%s*(%d+)')) + local size = GetBetween('comic_size:"', '",', s) + imgpath = imgpath:gsub('(.)', + function (a) + return string.char(string.byte(a) - pageid % 10) + end + ) + local srv = servers[math.random(#servers)] + for i=start,total do + local d = tostring(start+i-1) .. '.jpg' .. size + task.pagelinks.add(srv .. '/comic/' .. imgpath .. d) + end + return true + else + return false + end +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/all.html') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//div[@class="pages"]/a[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl..'/all_p'..IncStr(url)..'.html') then + TXQuery.Create(http.document).XPathHREFtitleAll('//a[contains(div/ul/li/@class, "title")]',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Raw' + m.website='ManHuaTai' + m.rooturl='http://www.manhuatai.com' + m.lastupdated='February 21, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' +end \ No newline at end of file From fbedce286449bd4fa1336c09dc9ff4bb6de76839 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 00:17:49 +0800 Subject: [PATCH 2372/2794] add website settings ui #1020 --- baseunits/FMDOptions.pas | 7 +- baseunits/FMDVars.pas | 1 + baseunits/WebsiteModules.pas | 2 +- mangadownloader/forms/frmMain.pas | 100 ++-- .../forms/frmWebsiteOptionAdvanced.lfm | 431 ------------------ .../forms/frmWebsiteOptionAdvanced.lrj | 22 - .../forms/frmWebsiteOptionAdvanced.pas | 311 ------------- mangadownloader/forms/frmWebsiteSettings.lfm | 133 ++++++ mangadownloader/forms/frmWebsiteSettings.lrj | 4 + mangadownloader/forms/frmWebsiteSettings.pas | 147 ++++++ mangadownloader/languages/fmd.de.po | 8 + mangadownloader/languages/fmd.el_GR.po | 8 + mangadownloader/languages/fmd.en.po | 8 + mangadownloader/languages/fmd.es.po | 8 + mangadownloader/languages/fmd.id_ID.po | 8 + mangadownloader/languages/fmd.pl_PL.po | 8 + mangadownloader/languages/fmd.po | 8 + mangadownloader/languages/fmd.pt_BR.po | 8 + mangadownloader/languages/fmd.ru_RU.po | 8 + mangadownloader/languages/fmd.tr_TR.po | 8 + mangadownloader/md.lpi | 65 +-- 21 files changed, 444 insertions(+), 859 deletions(-) delete mode 100644 mangadownloader/forms/frmWebsiteOptionAdvanced.lfm delete mode 100644 mangadownloader/forms/frmWebsiteOptionAdvanced.lrj delete mode 100644 mangadownloader/forms/frmWebsiteOptionAdvanced.pas create mode 100644 mangadownloader/forms/frmWebsiteSettings.lfm create mode 100644 mangadownloader/forms/frmWebsiteSettings.lrj create mode 100644 mangadownloader/forms/frmWebsiteSettings.pas diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas index a3b6b98cb..17df664b4 100644 --- a/baseunits/FMDOptions.pas +++ b/baseunits/FMDOptions.pas @@ -81,7 +81,6 @@ TIniFileRun = class(IniFiles.TMemIniFile) FAVORITESDB_FILE, CONFIG_FOLDER, CONFIG_FILE, - CONFIG_ADVANCED, REVISION_FILE, UPDATE_FILE, BASE_FILE, @@ -101,8 +100,7 @@ TIniFileRun = class(IniFiles.TMemIniFile) // ini files revisionfile, updatesfile: TIniFile; - configfile, - advancedfile: TIniFileRun; + configfile: TIniFileRun; // base url, should be in base.ini DEFAULT_SELECTED_WEBSITES: String = 'MangaFox,MangaHere,MangaInn,MangaReader'; @@ -256,14 +254,12 @@ procedure FreeNil(var Obj); procedure FreeIniFiles; begin FreeNil(configfile); - FreeNil(advancedfile); end; procedure SetIniFiles; begin FreeIniFiles; configfile := TIniFileRun.Create(CONFIG_FILE); - advancedfile := TIniFileRun.Create(CONFIG_ADVANCED); end; procedure ReadBaseFile; @@ -316,7 +312,6 @@ procedure SetAppDataDirectory(const ADir: String); CONFIG_FOLDER := APPDATA_DIRECTORY + 'config' + PathDelim; CONFIG_FILE := CONFIG_FOLDER + 'config.ini'; - CONFIG_ADVANCED := CONFIG_FOLDER + 'advanced.ini'; ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db'; MODULES_FILE := CONFIG_FOLDER + 'modules.json'; LUA_WEBSITEMODULE_FILE := CONFIG_FOLDER + 'luamodules.json'; diff --git a/baseunits/FMDVars.pas b/baseunits/FMDVars.pas index 83bdee712..adc93738b 100644 --- a/baseunits/FMDVars.pas +++ b/baseunits/FMDVars.pas @@ -16,6 +16,7 @@ interface isUpdating, isPendingExitCounter, isNormalExit: Boolean; + isStartup: Boolean = True; //Instance FMDInstance: TSimpleIPCServer; diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 10bb0ef9d..db97aeefc 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -70,7 +70,7 @@ TWebsiteOptionItem = record { TWebsiteModuleSettings } - TWebsiteModuleSettings = class + TWebsiteModuleSettings = class(TPersistent) private FCookies: String; FMaxConnectionLimit: Integer; diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 024bd0ffb..577c5c6c2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -22,7 +22,7 @@ interface TAGraph, TASources, TASeries, TATools, AnimatedGif, uBaseUnit, uDownloadsManager, uFavoritesManager, uUpdateThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, - frmWebsiteOptionAdvanced, frmCustomColor, frmLogger, frmTransferFavorites, + frmCustomColor, frmLogger, frmTransferFavorites, frmLuaModulesUpdater, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, SimpleException; @@ -679,6 +679,10 @@ TMainForm = class(TForm) gifWaiting: TAnimatedGif; gifWaitingRect: TRect; + + // embed form + procedure EmbedForm(const AForm: TForm; const AParent: TWinControl); + // generate >> nodes procedure GeneratetvDownloadFilterNodes; @@ -920,9 +924,9 @@ implementation {$R *.lfm} uses - frmImportFavorites, frmShutdownCounter, frmSelectDirectory, WebsiteModules, - FMDVars, RegExpr, sqlite3dyn, Clipbrd, ssl_openssl_lib, LazFileUtils, LazUTF8, - webp, DBUpdater, LuaWebsiteModules; + frmImportFavorites, frmShutdownCounter, frmSelectDirectory, + frmWebsiteSettings, WebsiteModules, FMDVars, RegExpr, sqlite3dyn, Clipbrd, + ssl_openssl_lib, LazFileUtils, LazUTF8, webp, DBUpdater, LuaWebsiteModules; var // thread for open db @@ -1208,66 +1212,27 @@ procedure TMainForm.FormCreate(Sender: TObject); end; // embed form + CustomColorForm := TCustomColorForm.Create(Self); + EmbedForm(CustomColorForm, tsCustomColor); + AccountManagerForm := TAccountManagerForm.Create(Self); - with AccountManagerForm do begin - Parent := tsAccounts; - Align := alClient; - ChildSizing.LeftRightSpacing := 0; - ChildSizing.TopBottomSpacing := 0; - Show; - if Screen.PixelsPerInch > 96 then - AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); - end; + EmbedForm(AccountManagerForm, tsAccounts); WebsiteOptionCustomForm := TCustomOptionForm.Create(Self); - with WebsiteOptionCustomForm do - begin - Parent := sbWebsiteOptions; - BorderStyle := bsNone; - Align := alClient; - Show; - if Screen.PixelsPerInch > 96 then - AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); - end; + EmbedForm(WebsiteOptionCustomForm, sbWebsiteOptions); - WebsiteOptionAdvancedForm := TWebsiteOptionAdvancedForm.Create(Self); - with WebsiteOptionAdvancedForm do - begin - Parent := tsWebsiteAdvanced; - BorderStyle := bsNone; - Align := alClient; - Show; - if Screen.PixelsPerInch > 96 then - AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); - end; + WebsiteSettingsForm := TWebsiteSettingsForm.Create(Self); + EmbedForm(WebsiteSettingsForm, tsWebsiteAdvanced); + + LuaModulesUpdaterForm := TLuaModulesUpdaterForm.Create(Self); + EmbedForm(LuaModulesUpdaterForm, tsWebsiteModules); - CustomColorForm := TCustomColorForm.Create(Self); - with CustomColorForm do - begin - Parent := tsCustomColor; - BorderStyle := bsNone; - Align := alClient; - Show; - if Screen.PixelsPerInch > 96 then - AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); - end; AddVT(Self.vtMangaList); AddVT(Self.clbChapterList); AddVT(Self.vtDownload); AddVT(Self.vtFavorites); AddVT(Self.vtOptionMangaSiteSelection); - LuaModulesUpdaterForm := TLuaModulesUpdaterForm.Create(Self); - with LuaModulesUpdaterForm do - begin - Parent := tsWebsiteModules; - BorderStyle := bsNone; - Align := alClient; - Show; - if Screen.PixelsPerInch > 96 then - AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); - end; - // logger FormLogger := TFormLogger.Create(Self); @@ -1797,7 +1762,11 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); ScanLuaWebsiteModulesFile; AddToAboutStatus('Modules', IntToStr(Modules.Count)); - // load configfile + Modules.LoadFromFile; + WebsiteOptionCustomForm.CreateWebsiteOption; + WebsiteSettingsForm.LoadWebsiteSettings; + + //load configfile LoadMangaOptions; LoadOptions; ApplyOptions; @@ -1809,9 +1778,6 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); FavoriteManager.Restore; UpdateVtFavorites; - Modules.LoadFromFile; - frmWebsiteOptionCustom.WebsiteOptionCustomForm.CreateWebsiteOption; - if cbSelectManga.ItemIndex > -1 then OpenDataDB(cbSelectManga.Items[cbSelectManga.ItemIndex]); if OptionAutoCheckLatestVersion then @@ -1828,6 +1794,8 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); if Sender is TTimer then TTimer(Sender).Free; + + isStartup := False; end; procedure TMainForm.medURLCutClick(Sender: TObject); @@ -2499,6 +2467,19 @@ procedure TMainForm.ClearChapterListState; ChapterList[i].Downloaded := False; end; +procedure TMainForm.EmbedForm(const AForm: TForm; const AParent: TWinControl); +begin + with AForm do + begin + Parent := AParent; + BorderStyle := bsNone; + Align := alClient; + Show; + if Screen.PixelsPerInch > 96 then + AutoAdjustLayout(lapAutoAdjustForDPI, Screen.PixelsPerInch, 96, 0, 0); + end; +end; + procedure TMainForm.btVisitMyBlogClick(Sender: TObject); begin OpenURL('http://akarink.wordpress.com/'); @@ -5273,6 +5254,7 @@ procedure TMainForm.LoadMangaOptions; end; // add them to vt websites selection and availablewebsites + vtOptionMangaSiteSelection.BeginUpdate; for i := 0 to categories.Count - 1 do begin node := vtOptionMangaSiteSelection.AddChild(nil, nil); @@ -5291,6 +5273,7 @@ procedure TMainForm.LoadMangaOptions; AvailableWebsites.Add(s); end; end; + vtOptionMangaSiteSelection.EndUpdate; AvailableWebsites.Duplicates := dupIgnore; AvailableWebsites.Sorted := True; finally @@ -5716,7 +5699,8 @@ procedure TMainForm.ApplyLanguage; tvDownloadFilterRefresh(True); // refresh custom option - WebsiteOptionCustomForm.CreateWebsiteOption; + if not isStartup then + WebsiteOptionCustomForm.CreateWebsiteOption; end; end; end; diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm b/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm deleted file mode 100644 index 4c5dd86b9..000000000 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lfm +++ /dev/null @@ -1,431 +0,0 @@ -object WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm - Left = 235 - Height = 307 - Top = 142 - Width = 510 - ClientHeight = 307 - ClientWidth = 510 - OnCreate = FormCreate - OnDestroy = FormDestroy - LCLVersion = '1.9.0.0' - object pcAdvanced: TPageControl - Left = 0 - Height = 307 - Top = 0 - Width = 510 - ActivePage = tsCookies - Align = alClient - TabIndex = 0 - TabOrder = 0 - object tsCookies: TTabSheet - Caption = 'Cookies' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 279 - ClientWidth = 502 - object vtCookies: TVirtualStringTree - Left = 6 - Height = 267 - Top = 6 - Width = 490 - Align = alClient - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Website' - end - item - Position = 1 - Text = 'Cookies' - Width = 400 - end> - Header.DefaultHeight = 23 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] - PopupMenu = pmCookies - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] - OnColumnDblClick = vtCookiesColumnDblClick - OnCompareNodes = vtCookiesCompareNodes - OnEditing = vtCookiesEditing - OnFreeNode = vtCookiesFreeNode - OnGetText = vtCookiesGetText - OnGetNodeDataSize = vtCookiesGetNodeDataSize - OnHeaderClick = vtCookiesHeaderClick - OnKeyDown = vtCookiesKeyDown - OnNewText = vtCookiesNewText - end - end - object tsUserAgent: TTabSheet - Caption = 'User Agent' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 279 - ClientWidth = 502 - object vtUserAgent: TVirtualStringTree - Left = 6 - Height = 267 - Top = 6 - Width = 490 - Align = alClient - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Website' - end - item - Position = 1 - Text = 'User Agent' - Width = 400 - end> - Header.DefaultHeight = 23 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] - PopupMenu = pmCookies - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] - OnColumnDblClick = vtCookiesColumnDblClick - OnCompareNodes = vtCookiesCompareNodes - OnEditing = vtCookiesEditing - OnFreeNode = vtCookiesFreeNode - OnGetText = vtCookiesGetText - OnGetNodeDataSize = vtCookiesGetNodeDataSize - OnHeaderClick = vtCookiesHeaderClick - OnKeyDown = vtCookiesKeyDown - OnNewText = vtCookiesNewText - end - end - object tsDownloads: TTabSheet - Caption = 'Downloads' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 279 - ClientWidth = 502 - object pcDownloads: TPageControl - Left = 6 - Height = 267 - Top = 6 - Width = 490 - ActivePage = tsMaxThreadsPerTask - Align = alClient - TabIndex = 0 - TabOrder = 0 - object tsMaxThreadsPerTask: TTabSheet - Caption = 'Max threads per task' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 239 - ClientWidth = 482 - object vtDownloadMaxThreadsPerTask: TVirtualStringTree - Left = 6 - Height = 227 - Top = 6 - Width = 470 - Align = alClient - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Website' - end - item - Position = 1 - Text = 'Value' - Width = 400 - end> - Header.DefaultHeight = 23 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] - PopupMenu = pmCookies - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] - OnColumnDblClick = vtCookiesColumnDblClick - OnCompareNodes = vtCookiesCompareNodes - OnEditing = vtCookiesEditing - OnFreeNode = vtCookiesFreeNode - OnGetText = vtCookiesGetText - OnGetNodeDataSize = vtCookiesGetNodeDataSize - OnHeaderClick = vtCookiesHeaderClick - OnKeyDown = vtCookiesKeyDown - OnNewText = vtCookiesNewText - end - end - end - end - object tsUpdateList: TTabSheet - Caption = 'Update List' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 279 - ClientWidth = 502 - object pcUpdateList: TPageControl - Left = 6 - Height = 267 - Top = 6 - Width = 490 - ActivePage = tsDirectoryPageNumber - Align = alClient - TabIndex = 0 - TabOrder = 0 - object tsDirectoryPageNumber: TTabSheet - Caption = 'Directory page number' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 239 - ClientWidth = 482 - object vtUpdateListDirectoryPageNumber: TVirtualStringTree - Left = 6 - Height = 227 - Top = 6 - Width = 470 - Align = alClient - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Website' - end - item - Position = 1 - Text = 'Value' - Width = 400 - end> - Header.DefaultHeight = 23 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] - PopupMenu = pmCookies - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] - OnColumnDblClick = vtCookiesColumnDblClick - OnCompareNodes = vtCookiesCompareNodes - OnEditing = vtCookiesEditing - OnFreeNode = vtCookiesFreeNode - OnGetText = vtCookiesGetText - OnGetNodeDataSize = vtCookiesGetNodeDataSize - OnHeaderClick = vtCookiesHeaderClick - OnKeyDown = vtCookiesKeyDown - OnNewText = vtCookiesNewText - end - end - object tsNumberofThreads: TTabSheet - Caption = 'Number of threads' - ChildSizing.LeftRightSpacing = 6 - ChildSizing.TopBottomSpacing = 6 - ChildSizing.HorizontalSpacing = 4 - ChildSizing.VerticalSpacing = 4 - ClientHeight = 239 - ClientWidth = 482 - object vtUpdateListNumberOfThreads: TVirtualStringTree - Left = 6 - Height = 227 - Top = 6 - Width = 470 - Align = alClient - Colors.DropTargetBorderColor = clHotLight - Colors.FocusedSelectionBorderColor = clHotLight - Colors.SelectionRectangleBorderColor = clHotLight - Colors.UnfocusedSelectionBorderColor = clBtnShadow - DefaultText = 'Node' - Header.AutoSizeIndex = 0 - Header.Columns = < - item - Position = 0 - Text = 'Website' - end - item - Position = 1 - Text = 'Value' - Width = 400 - end> - Header.DefaultHeight = 23 - Header.Height = 23 - Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] - PopupMenu = pmCookies - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHideFocusRect, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] - TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] - OnColumnDblClick = vtCookiesColumnDblClick - OnCompareNodes = vtCookiesCompareNodes - OnEditing = vtCookiesEditing - OnFreeNode = vtCookiesFreeNode - OnGetText = vtCookiesGetText - OnGetNodeDataSize = vtCookiesGetNodeDataSize - OnHeaderClick = vtCookiesHeaderClick - OnKeyDown = vtCookiesKeyDown - OnNewText = vtCookiesNewText - end - end - end - end - end - object pmCookies: TPopupMenu - Images = imglstpmCokies - left = 221 - top = 89 - object MenuItem1: TMenuItem - Caption = 'Add' - ImageIndex = 0 - OnClick = MenuItem1Click - end - object MenuItem2: TMenuItem - Caption = 'Edit' - ImageIndex = 1 - OnClick = MenuItem2Click - end - object MenuItem3: TMenuItem - Caption = '-' - end - object MenuItem4: TMenuItem - Caption = 'Delete' - ImageIndex = 2 - OnClick = MenuItem4Click - end - end - object imglstpmCokies: TImageList - AllocBy = 2 - left = 320 - top = 89 - Bitmap = { - 4C69030000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003B7F320015A9000015A9000015A9 - 000015A9000015AA009915AA00CC15AA00CC15AA009915A9000015A9000015A9 - 000015A90000094D0000FFFFFF00FFFFFF00119A0000129F000014A8000014A8 - 000014A8000014A800CC72E961FF71E860FF14A800CC14A8000014A8000014A8 - 0000129F0000119A0000FFFFFF00FFFFFF00119A0000119B0000129E000014A5 - 000014A5000014A500CC69E058FF69E058FF14A500CC14A5000014A50000129E - 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000129D - 000013A2000013A200CC62D951FF61D850FF13A200CC13A20000129D0000119B - 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000119B - 0000129C0000129E00CC5AD149FF59D048FF129E00CC129C0000119B0000119B - 0000119B0000119A0000FFFFFF00FFFFFF00119A0099119A00CC119A00CC119A - 00CC119A00CC119A00CC54CB43FF52C941FF119A00CC119A00CC119A00CC119A - 00CC119A00CC119A0099FFFFFF00FFFFFF00109600CC5ED54DFF55CC44FF54CB - 43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC63EFF4EC53DFF4DC43CFF4CC3 - 3BFF4EC53DFF109600CCFFFFFF00FFFFFF000F9200CC59D048FF50C73FFF50C7 - 3FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A920FF2CA51BFF2BA31AFF2DA5 - 1CFF33AB22FF0F9200CCFFFFFF00FFFFFF000E8E00990E8D00CC0E8D00CC0E8D - 00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D00CC0E8D00CC0E8D00CC0E8D - 00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8C - 00000E8B00000D8900CC29B618FF27B416FF0D8900CC0E8B00000E8C00000E8C - 00000E8C00000E8D0000FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8A - 00000C8400000C8400CC25C014FF24C013FF0C8400CC0C8400000E8A00000E8C - 00000E8C00000E8D0000FFFFFF00FFFFFF000747000000000000000000000320 - 00000A7D00000A7D00CC23CD12FF22CC11FF0A7D00CC0A7D0000032000000000 - 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000 - 0000021D0000066D00CC22D811FF22D811FF066D00CC021D0000000000000000 - 00000000000000000000FFFFFF00FFFFFF0000000000000000040000001B0000 - 003000000033024700A6025D00CC025D00CC024700A600000033000000310000 - 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000 - 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000 - 00100000000300000000FFFFFF00000000000000000000000000000000000000 - 000000000000000000000000000001272D000175860055555500555555000101 - E42B0101E09D0101D23F0101B600000000000000000000000000000000000000 - 00000000000001272D0001758600019BB200019BB200555555005555551F1515 - BC9D8888FFFF0101C5B90101B443000000000000000000000000000000000127 - 2D0001758600019BB200019BB200019BB200019BB2005555552450505069F6F6 - F6FF6868F8FF5C5CF2FF0000A8B1000000000000000001272D0001758600019B - B200019BB200019BB200019BB200019BB200019AB240158395A3F6F6F6FFCCCC - CCFFDDDDDDFF060683B50000A032001F2A00005E7D00019BB200019BB200019B - B200019BB200019BB200019BB200019AB2400195ADB788EEFFFF33AABBFFDDDD - DDFF171717830909312905055500007CA500007DA600019BB200019BB200019B - B200019BB200019BB200019AB2400195ADB788EEFFFF83EBFCFF56CDDEFF087A - 8CB00C0C0C2F0A0A0A000A0A0A00007CA500007DA600019BB200019BB200019B - B200019BB200019AB2400195ADB788EEFFFF7EE7F8FF5ACFE0FF0395ACC0039A - B0430A0A0A000A0A0A000A0A0A00007CA500007DA600019BB200019BB200019B - B200019AB2400195ADB788EEFFFF78E3F4FF5DD2E3FF028DA4C20292A9440399 - AF000A0A0A000A0A0A000A0A0A00007CA500007DA600019BB200019BB200019A - B2400195ADB788EEFFFF71DEEFFF60D3E4FF02859BC3028AA1450291A8000399 - AF000A0A0A000A0A0A000A0A0A00007CA500007DA600019BB200019AB2400195 - ADB788EEFFFF69DAEBFF60D3E4FF027C92C5028298450289A0000291A8000399 - AF000A0A0A000505050000000000007CA500007DA600019AB2400195ADB788EE - FFFF63D5E6FF5FD3E4FF017389C701798F45028197000289A0000291A800024D - 5800000000000000000000000000007CA500007CA527018DA8A688EEFFFF5DD1 - E2FF5BD0E1FF016B80C80170864601788E000281970001455000000000000000 - 000000000000000000000000000000759B060072976CC0E4F1EF44BBCCFF58CE - DFFF016379CA01687D47016F8500013C47000000000000000000000000000000 - 0000000000000000000000000000016B8E3962A5BBC0C2E6F2FFA0CEDDF50159 - 6FC30060764701343E0000000000000000000000000000000000000000000000 - 0000000000000000000000000000015E7B85C2E6F2FF5591A5D1014C649A0131 - 41500000001500000013000000110000000F0000000D0000000A000000080000 - 000600000004000000030000000100000000014B649A012E3C63010A0D350000 - 002D0000002A00000026000000210000001D0000001900000014000000100000 - 000B000000080000000500000002FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A8000000A9480000A9CC0000 - A9CC0000A9930000A7000000A20000009A0000009E000000A4000000A82B0000 - A97E0000A9B00000A966FFFFFF00FFFFFF000000A4000000A4CC7474FCFF6B6B - F4FE3636CDE50000A4CC0000A10000009A0000009E000000A3890606A8CF0000 - A4BD0000A54A0000A501FFFFFF00FFFFFF0000009F0000009F6600009ECC3737 - C9E56262EAFF5858E3FA1616AFD600009A330E0EA99F2828BEDD00009EB40000 - 9F1F0000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098330000 - 968A000096CC4141CDEE5151D9FD2727B7E32F2FBEE3000096B100009A180000 - 9F000000A4000000A500FFFFFF00FFFFFF0000009F0000009E00000098000000 - 900000008D3300008ECC3131BCF33333BCFA090997D400008E0000008F000000 - 8E0000008E000000A500FFFFFF00FFFFFF000000800000008000000080000000 - 8215000086B01A1AA8E72222B4F907078ED214149FE105058DD2000082000000 - 7C000000780000007800FFFFFF00FFFFFF00000078000000780000007B000000 - 7E911515A6E51D1DBEFD07078AD400007F6300007EAE0A0A94DC00007EB60000 - 7A000000780000007800FFFFFF00FFFFFF000000700000007000000075670D0D - 96DC1717CCFF0F0FA2E50000777500007E0000007A000000769104048AD50000 - 76860000730000007200FFFFFF00FFFFFF0000006C0000006D1F00006ECC1515 - D1FB1111C3F400006EB40000701100007000000078000000720000006E820000 - 6EB800006D4100006C00FFFFFF00FFFFFF00000066000000668C0A0A9FE51212 - DDFF030378D3000067330000510000000000000000000000380000006A000000 - 66840000668900006404FFFFFF00FFFFFF000000180000005FCC1111DBFE0C0C - AFEC00005F8B0000190000000000000000000000000000000000000000000000 - 320000005F7300004832FFFFFF00FFFFFF000000001C0000325E000059CC0000 - 57BC0000164200000020000000160000000F0000000D00000010000000150000 - 001B00001D3800002D4CFFFFFF00FFFFFF000000000E00000014000000190000 - 001900000016000000100000000B0000000800000007000000080000000B0000 - 000E0000001100000013FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00 - } - end -end diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.lrj b/mangadownloader/forms/frmWebsiteOptionAdvanced.lrj deleted file mode 100644 index 7f6e482e9..000000000 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.lrj +++ /dev/null @@ -1,22 +0,0 @@ -{"version":1,"strings":[ -{"hash":174464899,"name":"twebsiteoptionadvancedform.tscookies.caption","sourcebytes":[67,111,111,107,105,101,115],"value":"Cookies"}, -{"hash":230269173,"name":"twebsiteoptionadvancedform.vtcookies.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, -{"hash":174464899,"name":"twebsiteoptionadvancedform.vtcookies.header.columns[1].text","sourcebytes":[67,111,111,107,105,101,115],"value":"Cookies"}, -{"hash":71439252,"name":"twebsiteoptionadvancedform.tsuseragent.caption","sourcebytes":[85,115,101,114,32,65,103,101,110,116],"value":"User Agent"}, -{"hash":230269173,"name":"twebsiteoptionadvancedform.vtuseragent.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, -{"hash":71439252,"name":"twebsiteoptionadvancedform.vtuseragent.header.columns[1].text","sourcebytes":[85,115,101,114,32,65,103,101,110,116],"value":"User Agent"}, -{"hash":240327891,"name":"twebsiteoptionadvancedform.tsdownloads.caption","sourcebytes":[68,111,119,110,108,111,97,100,115],"value":"Downloads"}, -{"hash":261838155,"name":"twebsiteoptionadvancedform.tsmaxthreadspertask.caption","sourcebytes":[77,97,120,32,116,104,114,101,97,100,115,32,112,101,114,32,116,97,115,107],"value":"Max threads per task"}, -{"hash":230269173,"name":"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, -{"hash":6063029,"name":"twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[1].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, -{"hash":170482212,"name":"twebsiteoptionadvancedform.tsupdatelist.caption","sourcebytes":[85,112,100,97,116,101,32,76,105,115,116],"value":"Update List"}, -{"hash":110671906,"name":"twebsiteoptionadvancedform.tsdirectorypagenumber.caption","sourcebytes":[68,105,114,101,99,116,111,114,121,32,112,97,103,101,32,110,117,109,98,101,114],"value":"Directory page number"}, -{"hash":230269173,"name":"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, -{"hash":6063029,"name":"twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, -{"hash":116141123,"name":"twebsiteoptionadvancedform.tsnumberofthreads.caption","sourcebytes":[78,117,109,98,101,114,32,111,102,32,116,104,114,101,97,100,115],"value":"Number of threads"}, -{"hash":230269173,"name":"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, -{"hash":6063029,"name":"twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text","sourcebytes":[86,97,108,117,101],"value":"Value"}, -{"hash":18340,"name":"twebsiteoptionadvancedform.menuitem1.caption","sourcebytes":[65,100,100],"value":"Add"}, -{"hash":310020,"name":"twebsiteoptionadvancedform.menuitem2.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, -{"hash":78392485,"name":"twebsiteoptionadvancedform.menuitem4.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"} -]} diff --git a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas b/mangadownloader/forms/frmWebsiteOptionAdvanced.pas deleted file mode 100644 index 2a95b233b..000000000 --- a/mangadownloader/forms/frmWebsiteOptionAdvanced.pas +++ /dev/null @@ -1,311 +0,0 @@ -unit frmWebsiteOptionAdvanced; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, Windows, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls, - LCLProc, Grids, Menus, VirtualTrees, FMDOptions, frmWebsiteSelection; - -type - - TNameValue = record - Name, - Value: String; - end; - PNameValue = ^TNameValue; - - { TWebsiteOptionAdvancedForm } - - TWebsiteOptionAdvancedForm = class(TForm) - imglstpmCokies: TImageList; - MenuItem1: TMenuItem; - MenuItem2: TMenuItem; - MenuItem3: TMenuItem; - MenuItem4: TMenuItem; - pcUpdateList: TPageControl; - pcDownloads: TPageControl; - pcAdvanced: TPageControl; - pmCookies: TPopupMenu; - tsMaxThreadsPerTask: TTabSheet; - tsDirectoryPageNumber: TTabSheet; - tsNumberofThreads: TTabSheet; - tsUpdateList: TTabSheet; - tsDownloads: TTabSheet; - tsCookies: TTabSheet; - tsUserAgent: TTabSheet; - vtCookies: TVirtualStringTree; - vtDownloadMaxThreadsPerTask: TVirtualStringTree; - vtUpdateListDirectoryPageNumber: TVirtualStringTree; - vtUpdateListNumberOfThreads: TVirtualStringTree; - vtUserAgent: TVirtualStringTree; - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure MenuItem1Click(Sender: TObject); - procedure MenuItem2Click(Sender: TObject); - procedure MenuItem4Click(Sender: TObject); - procedure vtCookiesColumnDblClick(Sender: TBaseVirtualTree; Column: TColumnIndex; - Shift: TShiftState); - procedure vtCookiesCompareNodes(Sender: TBaseVirtualTree; Node1, - Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); - procedure vtCookiesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; var Allowed: Boolean); - procedure vtCookiesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure vtCookiesGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); - procedure vtCookiesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - {$if VTMajorVersion < 5} - procedure vtCookiesHeaderClick(Sender: TVTHeader; Column: TColumnIndex; - Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - {$else} - procedure vtCookiesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); - {$endif} - procedure vtCookiesKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure vtCookiesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; const NewText: String); - private - { private declarations } - procedure LoadFromFileToVT(const AVT: VirtualTrees.TVirtualStringTree; const ASection: String); - procedure GetWebsite(const AVT: VirtualTrees.TVirtualStringTree; const S: TStrings); - public - { public declarations } - end; - -var - WebsiteOptionAdvancedForm: TWebsiteOptionAdvancedForm; - -implementation - -uses frmCustomColor; - -{$R *.lfm} - -{ TWebsiteOptionAdvancedForm } - -procedure TWebsiteOptionAdvancedForm.FormCreate(Sender: TObject); -begin - AddVT(vtCookies); - AddVT(vtUserAgent); - AddVT(vtDownloadMaxThreadsPerTask); - AddVT(vtUpdateListDirectoryPageNumber); - AddVT(vtUpdateListNumberOfThreads); - LoadFromFileToVT(vtCookies, 'Cookies'); - LoadFromFileToVT(vtUserAgent, 'UserAgent'); - LoadFromFileToVT(vtDownloadMaxThreadsPerTask, 'DownloadMaxThreadsPerTask'); - LoadFromFileToVT(vtUpdateListDirectoryPageNumber, 'UpdateListDirectoryPageNumber'); - LoadFromFileToVT(vtUpdateListNumberOfThreads, 'UpdateListNumberOfThreads'); -end; - -procedure TWebsiteOptionAdvancedForm.FormDestroy(Sender: TObject); -begin - RemoveVT(vtCookies); - RemoveVT(vtUserAgent); - RemoveVT(vtDownloadMaxThreadsPerTask); - RemoveVT(vtUpdateListDirectoryPageNumber); - RemoveVT(vtUpdateListNumberOfThreads); -end; - -procedure TWebsiteOptionAdvancedForm.MenuItem1Click(Sender: TObject); -var - Data: PNameValue; - Node: PVirtualNode; -begin - if Screen.ActiveControl is VirtualTrees.TVirtualStringTree then - with TWebsiteSelectionForm.Create(Self) do - try - GetWebsite(VirtualTrees.TVirtualStringTree(Screen.ActiveControl), cbWebsites.Items); - if (ShowModal = mrOk) and (cbWebsites.Text <> '') then - with VirtualTrees.TVirtualStringTree(Screen.ActiveControl) do - begin - Node := AddChild(nil); - Data := GetNodeData(Node); - Data^.Name := cbWebsites.Text; - advancedfile.WriteString(DefaultText, cbWebsites.Text, ''); - EditNode(Node, 1); - end; - finally - Free; - end; -end; - -procedure TWebsiteOptionAdvancedForm.MenuItem2Click(Sender: TObject); -begin - if Screen.ActiveControl is VirtualTrees.TVirtualStringTree then - with VirtualTrees.TVirtualStringTree(Screen.ActiveControl) do - EditNode(FocusedNode, 1); -end; - -procedure TWebsiteOptionAdvancedForm.MenuItem4Click(Sender: TObject); -var - Data: PNameValue; -begin - if Screen.ActiveControl is VirtualTrees.TVirtualStringTree then - with VirtualTrees.TVirtualStringTree(Screen.ActiveControl) do - begin - Data := GetNodeData(FocusedNode); - advancedfile.DeleteKey(DefaultText, Data^.Name); - DeleteNode(FocusedNode); - end; -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesColumnDblClick(Sender: TBaseVirtualTree; - Column: TColumnIndex; Shift: TShiftState); -begin - if Column <> 0 then - Sender.EditNode(Sender.FocusedNode, Column); -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesCompareNodes(Sender: TBaseVirtualTree; - Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); -var - Data1, Data2: PNameValue; -begin - Data1 := Sender.GetNodeData(Node1); - Data2 := Sender.GetNodeData(Node2); - case Column of - 0: Result := CompareStr(Data1^.Name, Data2^.Name); - 1: Result := CompareStr(Data1^.Value, Data2^.Value); - end; -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -begin - Allowed := Column <> 0; -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesFreeNode(Sender: TBaseVirtualTree; - Node: PVirtualNode); -var - Data: PNameValue; -begin - Data := Sender.GetNodeData(Node); - if Assigned(Data) then - Finalize(Data^); -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TNameValue); -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - Data: PNameValue; -begin - Data := Sender.GetNodeData(Node); - case Column of - 0: CellText := Data^.Name; - 1: CellText := Data^.Value; - end; -end; - -{$if VTMajorVersion < 5} -procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; - Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer - ); -{$else} -procedure TWebsiteOptionAdvancedForm.vtCookiesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); -var - Column: TColumnIndex; -{$endif} -begin - {$if VTMajorVersion >= 5} - Column := HitInfo.Column; - {$endif} - Sender.SortColumn := Column; - if Sender.SortDirection = sdAscending then - Sender.SortDirection := sdDescending - else - Sender.SortDirection := sdAscending; - Sender.Treeview.SortTree(Sender.SortColumn, Sender.SortDirection); -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); -begin - if not (Sender is VirtualTrees.TVirtualStringTree) then Exit; - with VirtualTrees.TVirtualStringTree(Sender) do - if (Key = VK_RETURN) and (FocusedColumn <> 0) then - EditNode(FocusedNode, FocusedColumn); -end; - -procedure TWebsiteOptionAdvancedForm.vtCookiesNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; const NewText: String); -var - Data: PNameValue; -begin - if Column = 0 then Exit; - Data := Sender.GetNodeData(Node); - if Data^.Value <> NewText then - begin - Data^.Value := NewText; - advancedfile.WriteString(VirtualTrees.TVirtualStringTree(Sender).DefaultText, Data^.Name, NewText); - end; -end; - -procedure TWebsiteOptionAdvancedForm.LoadFromFileToVT(const AVT: VirtualTrees.TVirtualStringTree; const ASection: String); -var - s: TStringList; - i: Integer; - Node: PVirtualNode; - Data: PNameValue; -begin - if AVT = nil then Exit; - if ASection = '' then Exit; - AVT.Clear; - AVT.DefaultText := ASection; - s := TStringList.Create; - try - advancedfile.ReadSectionRaw(ASection, s); - if s.Count > 0 then - begin - AVT.BeginUpdate; - try - for i := 0 to s.Count - 1 do - begin - Node := AVT.AddChild(nil); - Data := AVT.GetNodeData(Node); - Data^.Name := s.Names[i]; - Data^.Value := s.ValueFromIndex[i]; - end; - AVT.Header.AutoFitColumns(False, smaUseColumnOption, 0, 0); - AVT.Header.SortColumn := 0; - AVT.Header.SortDirection := sdAscending; - AVT.SortTree(AVT.Header.SortColumn, AVT.Header.SortDirection); - finally - AVT.EndUpdate; - end; - end; - finally - s.Free; - end; -end; - -procedure TWebsiteOptionAdvancedForm.GetWebsite(const AVT: VirtualTrees.TVirtualStringTree; const S: TStrings); -var - Node: PVirtualNode; - p: Integer; -begin - if AVT = nil then Exit; - if S = nil then Exit; - s.Assign(AvailableWebsites); - if s.Count <> 0 then - begin - Node := AVT.GetFirst(); - while Node <> nil do - begin - p := s.IndexOf(PNameValue(AVT.GetNodeData(Node))^.Name); - if p <> - 1 then - s.Delete(p); - Node := AVT.GetNext(Node); - end; - end; -end; - -end. - diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm new file mode 100644 index 000000000..487d4aa85 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -0,0 +1,133 @@ +object WebsiteSettingsForm: TWebsiteSettingsForm + Left = 280 + Height = 461 + Top = 93 + Width = 572 + Caption = 'WebsiteSettingsForm' + ClientHeight = 461 + ClientWidth = 572 + OnCreate = FormCreate + OnDestroy = FormDestroy + LCLVersion = '1.8.0.6' + object pnTop: TPanel + Left = 0 + Height = 23 + Top = 0 + Width = 572 + Align = alTop + AutoSize = True + BorderSpacing.Bottom = 6 + BevelOuter = bvNone + ClientHeight = 23 + ClientWidth = 572 + TabOrder = 0 + object edSearch: TEditButton + Left = 0 + Height = 23 + Top = 0 + Width = 177 + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edSearchButtonClick + OnChange = edSearchChange + PasswordChar = #0 + TabOrder = 0 + TextHint = 'Website name' + end + end + object spMain: TPairSplitter + Left = 0 + Height = 432 + Top = 29 + Width = 572 + Align = alClient + Position = 150 + object spList: TPairSplitterSide + Cursor = crArrow + Left = 0 + Height = 432 + Top = 0 + Width = 150 + ClientWidth = 150 + ClientHeight = 432 + object vtWebsite: TVirtualStringTree + Left = 0 + Height = 432 + Top = 0 + Width = 150 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.DefaultHeight = 17 + Header.MainColumn = -1 + TabOrder = 0 + TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnClick = vtWebsiteClick + OnCompareNodes = vtWebsiteCompareNodes + OnFreeNode = vtWebsiteFreeNode + OnGetText = vtWebsiteGetText + end + end + object spProps: TPairSplitterSide + Cursor = crArrow + Left = 155 + Height = 432 + Top = 0 + Width = 417 + ClientWidth = 417 + ClientHeight = 432 + object prSettings: TTIPropertyGrid + Left = 0 + Height = 432 + Top = 0 + Width = 417 + Align = alClient + CheckboxForBoolean = True + DefaultValueFont.Color = clWindowText + Filter = [tkInteger, tkChar, tkEnumeration, tkFloat, tkSet, tkMethod, tkSString, tkLString, tkAString, tkWString, tkVariant, tkArray, tkRecord, tkInterface, tkClass, tkObject, tkWChar, tkBool, tkInt64, tkQWord, tkDynArray, tkInterfaceRaw, tkProcVar, tkUString, tkUChar, tkHelper, tkFile, tkClassRef, tkPointer] + Indent = 16 + NameFont.Color = clWindowText + ValueFont.Color = clMaroon + end + end + end +end diff --git a/mangadownloader/forms/frmWebsiteSettings.lrj b/mangadownloader/forms/frmWebsiteSettings.lrj new file mode 100644 index 000000000..680766ca3 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteSettings.lrj @@ -0,0 +1,4 @@ +{"version":1,"strings":[ +{"hash":63106205,"name":"twebsitesettingsform.caption","sourcebytes":[87,101,98,115,105,116,101,83,101,116,116,105,110,103,115,70,111,114,109],"value":"WebsiteSettingsForm"}, +{"hash":263118389,"name":"twebsitesettingsform.edsearch.texthint","sourcebytes":[87,101,98,115,105,116,101,32,110,97,109,101],"value":"Website name"} +]} diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas new file mode 100644 index 000000000..126f0de76 --- /dev/null +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -0,0 +1,147 @@ +unit frmWebsiteSettings; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, FileUtil, ListFilterEdit, RTTIGrids, Forms, Controls, + Graphics, Dialogs, StdCtrls, ExtCtrls, PairSplitter, EditBtn, VirtualTrees; + +type + + { TWebsiteSettingsForm } + + TWebsiteSettingsForm = class(TForm) + edSearch: TEditButton; + spMain: TPairSplitter; + spList: TPairSplitterSide; + spProps: TPairSplitterSide; + pnTop: TPanel; + prSettings: TTIPropertyGrid; + vtWebsite: TVirtualStringTree; + procedure edSearchButtonClick(Sender: TObject); + procedure edSearchChange(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure vtWebsiteClick(Sender: TObject); + procedure vtWebsiteCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure vtWebsiteFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vtWebsiteGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + private + + public + procedure LoadWebsiteSettings; + end; + +var + WebsiteSettingsForm: TWebsiteSettingsForm; + +implementation + +uses WebsiteModules, frmCustomColor; + +type + + PWebsiteSettingsItem = ^TWebsiteSettingsItem; + + TWebsiteSettingsItem = record + Website: String; + Settings: TWebsiteModuleSettings; + end; + + +{$R *.lfm} + +{ TWebsiteSettingsForm } + +procedure TWebsiteSettingsForm.FormCreate(Sender: TObject); +begin + AddVT(vtWebsite); + prSettings.PreferredSplitterX:=200; +end; + +procedure TWebsiteSettingsForm.edSearchChange(Sender: TObject); +var + s: String; + node: PVirtualNode; +begin + s:=AnsiUpperCase(edSearch.Text); + vtWebsite.BeginUpdate; + node:=vtWebsite.GetFirst(); + if s<>'' then + while node<>nil do + begin + vtWebsite.IsVisible[node]:=Pos(s,AnsiUpperCase(PWebsiteSettingsItem(vtWebsite.GetNodeData(node))^.Website))<>0; + node:=vtWebsite.GetNext(node); + end + else + while node<>nil do + begin + vtWebsite.IsVisible[node]:=True; + node:=vtWebsite.GetNext(node); + end; + vtWebsite.EndUpdate; +end; + +procedure TWebsiteSettingsForm.edSearchButtonClick(Sender: TObject); +begin + edSearch.Clear; +end; + +procedure TWebsiteSettingsForm.FormDestroy(Sender: TObject); +begin + RemoveVT(vtWebsite); +end; + +procedure TWebsiteSettingsForm.vtWebsiteClick(Sender: TObject); +begin + if vtWebsite.SelectedCount=0 then Exit; + prSettings.TIObject:=PWebsiteSettingsItem(vtWebsite.GetNodeData(vtWebsite.GetFirstSelected()))^.Settings; +end; + +procedure TWebsiteSettingsForm.vtWebsiteCompareNodes(Sender: TBaseVirtualTree; + Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +begin + Result:=AnsiCompareStr(PWebsiteSettingsItem(Sender.GetNodeData(Node1))^.Website, + PWebsiteSettingsItem(Sender.GetNodeData(Node2))^.Website); +end; + +procedure TWebsiteSettingsForm.vtWebsiteFreeNode(Sender: TBaseVirtualTree; + Node: PVirtualNode); +begin + Finalize(PWebsiteSettingsItem(Sender.GetNodeData(Node))^); +end; + +procedure TWebsiteSettingsForm.vtWebsiteGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +begin + CellText:=PWebsiteSettingsItem(Sender.GetNodeData(Node))^.Website; +end; + +procedure TWebsiteSettingsForm.LoadWebsiteSettings; +var + i: Integer; + node: PVirtualNode; + data: PWebsiteSettingsItem; +begin + vtWebsite.NodeDataSize:=SizeOf(TWebsiteSettingsItem); + vtWebsite.BeginUpdate; + for i:=0 to Modules.Count-1 do + with Modules[i] do + begin + node:=vtWebsite.AddChild(nil); + vtWebsite.ValidateNode(node,False); + data:=vtWebsite.GetNodeData(node); + data^.Website:=Website; + data^.Settings:=Settings; + end; + vtWebsite.Sort(nil,0,sdAscending,false); + vtWebsite.EndUpdate; +end; + +end. + diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index a783a688e..72c835202 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -2403,6 +2403,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Wähle eine Webseite" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 931c8bd52..0d4f853a8 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -2458,6 +2458,14 @@ msgstr "Παράγοντας χρήστη" msgid "Select a website" msgstr "Επιλέξτε έναν ιστότοπο" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Συμπίεση..." diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 097305d83..eee2f1443 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -2396,6 +2396,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Select a website" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 48d0a404e..c7f64edad 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -2407,6 +2407,14 @@ msgstr "Agente de Usuario" msgid "Select a website" msgstr "Seleccionar un Sitio Web" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Comprimiendo..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 55e11f015..ed1ef897e 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -2396,6 +2396,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Pilih situs" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Mengompresi..." diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 35524b4c4..231ab920b 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -2405,6 +2405,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Wybierz stronę internetową" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Kompresja danych..." diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index 01666e7f7..d362d8f36 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -2313,6 +2313,14 @@ msgstr "" msgid "Select a website" msgstr "" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 302517a27..0edbe2389 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -2408,6 +2408,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Selecionar um website" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compactando..." diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index b55cdeb3a..6609166e0 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -2403,6 +2403,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Выбрать сайт" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Сжатие..." diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index a0a523ba5..8eb376462 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -2426,6 +2426,14 @@ msgstr "User Agent" msgid "Select a website" msgstr "Bir websitesi seç" +#: twebsitesettingsform.caption +msgid "WebsiteSettingsForm" +msgstr "" + +#: twebsitesettingsform.edsearch.texthint +msgid "Website name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Sıkıştırılıyor..." diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index ad61a8dc0..180d11d86 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -271,36 +271,42 @@ <FormatVersion Value="1"/> </local> </RunParams> - <RequiredPackages Count="9"> + <RequiredPackages Count="11"> <Item1> - <PackageName Value="LCL"/> + <PackageName Value="RunTimeTypeInfoControls"/> </Item1> <Item2> - <PackageName Value="TAChartLazarusPkg"/> + <PackageName Value="LazControls"/> </Item2> <Item3> - <PackageName Value="richmemopackage"/> + <PackageName Value="LCL"/> </Item3> <Item4> - <PackageName Value="virtualtreeview_package"/> + <PackageName Value="TAChartLazarusPkg"/> </Item4> <Item5> - <PackageName Value="multiloglaz"/> + <PackageName Value="richmemopackage"/> </Item5> <Item6> - <PackageName Value="laz_synapse"/> + <PackageName Value="virtualtreeview_package"/> </Item6> <Item7> - <PackageName Value="dcpcrypt"/> + <PackageName Value="multiloglaz"/> </Item7> <Item8> - <PackageName Value="BESENPkg"/> - <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> + <PackageName Value="laz_synapse"/> </Item8> <Item9> + <PackageName Value="dcpcrypt"/> + </Item9> + <Item10> + <PackageName Value="BESENPkg"/> + <DefaultFilename Value="..\3rd\BESENPkg.lpk" Prefer="True"/> + </Item10> + <Item11> <PackageName Value="internettools"/> <DefaultFilename Value="..\3rd\internettools\internettools.lpk" Prefer="True"/> - </Item9> + </Item11> </RequiredPackages> <Units Count="18"> <Unit0> @@ -364,60 +370,59 @@ <ResourceBaseClass Value="Form"/> </Unit8> <Unit9> - <Filename Value="forms\frmWebsiteOptionAdvanced.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="WebsiteOptionAdvancedForm"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - </Unit9> - <Unit10> <Filename Value="forms\frmWebsiteSelection.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="WebsiteSelectionForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> - </Unit10> - <Unit11> + </Unit9> + <Unit10> <Filename Value="forms\frmCustomColor.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="CustomColorForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> - </Unit11> - <Unit12> + </Unit10> + <Unit11> <Filename Value="forms\frmLogger.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="FormLogger"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> - </Unit12> - <Unit13> + </Unit11> + <Unit12> <Filename Value="forms\frmSelectDirectory.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="SelectDirectoryForm"/> <ResourceBaseClass Value="Form"/> - </Unit13> - <Unit14> + </Unit12> + <Unit13> <Filename Value="forms\frmTransferFavorites.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="TransferFavoritesForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> - </Unit14> - <Unit15> + </Unit13> + <Unit14> <Filename Value="forms\frmLuaModulesUpdater.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="LuaModulesUpdaterForm"/> <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> + </Unit14> + <Unit15> + <Filename Value="..\baseunits\DBUpdater.pas"/> + <IsPartOfProject Value="True"/> </Unit15> <Unit16> - <Filename Value="..\baseunits\DBUpdater.pas"/> + <Filename Value="..\baseunits\SelfUpdater.pas"/> <IsPartOfProject Value="True"/> </Unit16> <Unit17> - <Filename Value="..\baseunits\SelfUpdater.pas"/> + <Filename Value="forms\frmWebsiteSettings.pas"/> <IsPartOfProject Value="True"/> + <ComponentName Value="WebsiteSettingsForm"/> + <ResourceBaseClass Value="Form"/> </Unit17> </Units> </ProjectOptions> From e4b1b674d6394d988ee569162078f0f1252c7051 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 01:02:04 +0800 Subject: [PATCH 2373/2794] frmwebsitesettings, cleanup #1020 --- mangadownloader/forms/frmWebsiteSettings.lfm | 3 +- mangadownloader/forms/frmWebsiteSettings.pas | 50 +++++--------------- mangadownloader/md.lpi | 1 + 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index 487d4aa85..5fcf7fa7d 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -101,9 +101,8 @@ object WebsiteSettingsForm: TWebsiteSettingsForm TabOrder = 0 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] - OnClick = vtWebsiteClick OnCompareNodes = vtWebsiteCompareNodes - OnFreeNode = vtWebsiteFreeNode + OnFocusChanged = vtWebsiteFocusChanged OnGetText = vtWebsiteGetText end end diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 126f0de76..f6c5a458d 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -5,7 +5,7 @@ interface uses - Classes, SysUtils, FileUtil, ListFilterEdit, RTTIGrids, Forms, Controls, + Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, PairSplitter, EditBtn, VirtualTrees; type @@ -24,10 +24,10 @@ TWebsiteSettingsForm = class(TForm) procedure edSearchChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); - procedure vtWebsiteClick(Sender: TObject); procedure vtWebsiteCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); - procedure vtWebsiteFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure vtWebsiteFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); procedure vtWebsiteGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); private @@ -43,16 +43,6 @@ implementation uses WebsiteModules, frmCustomColor; -type - - PWebsiteSettingsItem = ^TWebsiteSettingsItem; - - TWebsiteSettingsItem = record - Website: String; - Settings: TWebsiteModuleSettings; - end; - - {$R *.lfm} { TWebsiteSettingsForm } @@ -74,7 +64,7 @@ procedure TWebsiteSettingsForm.edSearchChange(Sender: TObject); if s<>'' then while node<>nil do begin - vtWebsite.IsVisible[node]:=Pos(s,AnsiUpperCase(PWebsiteSettingsItem(vtWebsite.GetNodeData(node))^.Website))<>0; + vtWebsite.IsVisible[node]:=Pos(s,AnsiUpperCase(PModuleContainer(vtWebsite.GetNodeData(node))^.Website))<>0; node:=vtWebsite.GetNext(node); end else @@ -96,49 +86,35 @@ procedure TWebsiteSettingsForm.FormDestroy(Sender: TObject); RemoveVT(vtWebsite); end; -procedure TWebsiteSettingsForm.vtWebsiteClick(Sender: TObject); -begin - if vtWebsite.SelectedCount=0 then Exit; - prSettings.TIObject:=PWebsiteSettingsItem(vtWebsite.GetNodeData(vtWebsite.GetFirstSelected()))^.Settings; -end; - procedure TWebsiteSettingsForm.vtWebsiteCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); begin - Result:=AnsiCompareStr(PWebsiteSettingsItem(Sender.GetNodeData(Node1))^.Website, - PWebsiteSettingsItem(Sender.GetNodeData(Node2))^.Website); + Result:=AnsiCompareStr(PModuleContainer(Sender.GetNodeData(Node1))^.Website, + PModuleContainer(Sender.GetNodeData(Node2))^.Website); end; -procedure TWebsiteSettingsForm.vtWebsiteFreeNode(Sender: TBaseVirtualTree; - Node: PVirtualNode); +procedure TWebsiteSettingsForm.vtWebsiteFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); begin - Finalize(PWebsiteSettingsItem(Sender.GetNodeData(Node))^); + writeln(PModuleContainer(Sender.GetNodeData(Node))^.Website); + prSettings.TIObject:=PModuleContainer(vtWebsite.GetNodeData(Node))^.Settings; end; procedure TWebsiteSettingsForm.vtWebsiteGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); begin - CellText:=PWebsiteSettingsItem(Sender.GetNodeData(Node))^.Website; + CellText:=PModuleContainer(Sender.GetNodeData(Node))^.Website; end; procedure TWebsiteSettingsForm.LoadWebsiteSettings; var i: Integer; - node: PVirtualNode; - data: PWebsiteSettingsItem; begin - vtWebsite.NodeDataSize:=SizeOf(TWebsiteSettingsItem); + vtWebsite.NodeDataSize:=SizeOf(TModuleContainer); vtWebsite.BeginUpdate; for i:=0 to Modules.Count-1 do - with Modules[i] do - begin - node:=vtWebsite.AddChild(nil); - vtWebsite.ValidateNode(node,False); - data:=vtWebsite.GetNodeData(node); - data^.Website:=Website; - data^.Settings:=Settings; - end; + vtWebsite.AddChild(nil,Modules[i]); vtWebsite.Sort(nil,0,sdAscending,false); vtWebsite.EndUpdate; end; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 180d11d86..e2b196b20 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -422,6 +422,7 @@ <Filename Value="forms\frmWebsiteSettings.pas"/> <IsPartOfProject Value="True"/> <ComponentName Value="WebsiteSettingsForm"/> + <HasResources Value="True"/> <ResourceBaseClass Value="Form"/> </Unit17> </Units> From 11c9344f02abecd620d68e5bfca8bafaca4699ff Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 01:02:26 +0800 Subject: [PATCH 2374/2794] websitemodules, add account enabled property --- baseunits/WebsiteModules.pas | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index db97aeefc..0b0d5c38d 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -106,16 +106,20 @@ TWebsiteModuleSettings = class(TPersistent) TWebsiteModuleAccount = class private FCookies: String; + FEnabled: Boolean; FPassword: String; FStatus: TAccountStatus; FUsername: String; published + property Enabled: Boolean read FEnabled write FEnabled; property Username: String read FUsername write FUsername; property Password: String read FPassword write FPassword; property Cookies: String read FCookies write FCookies; property Status: TAccountStatus read FStatus write FStatus; end; + PModuleContainer = ^TModuleContainer; + { TModuleContainer } TModuleContainer = class From 0f537ff8053e743c7c5fb22d150bdcdc38c406c0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 01:49:44 +0800 Subject: [PATCH 2375/2794] luabase, luawebsitemodules, add error info --- baseunits/lua/LuaBase.pas | 30 ++++-- baseunits/lua/LuaWebsiteModules.pas | 162 ++++++++++++++-------------- 2 files changed, 107 insertions(+), 85 deletions(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 99ab8b2e4..5a7dc1f08 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -13,7 +13,8 @@ procedure luaPushObject(L: Plua_State; Obj: TObject; Name: String; function LuaDoFile(AFilename: String; AFuncName: String = ''): Plua_State; function LuaNewBaseState: Plua_State; -function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; +procedure LuaCallFunction(L: Plua_State; AFuncName: String); +function LuaGetReturnString(const ReturnCode: Integer): String; function LuaDumpFileToStream(L: Plua_State; AFilename: String; AStripDebug: Boolean = False): TMemoryStream; @@ -80,14 +81,31 @@ function LuaNewBaseState: Plua_State; end; end; -function LuaCallFunction(L: Plua_State; AFuncName: String): Boolean; +procedure LuaCallFunction(L: Plua_State; AFuncName: String); +var + r: Integer; begin - Result := False; if lua_getglobal(L, PChar(AFuncName)) = 0 then raise Exception.Create('No function name ' + QuotedStr(AFuncName)); - if lua_pcall(L, 0, -1, 0) <> 0 then - raise Exception.Create(''); - Result := True; + r := lua_pcall(L, 0, LUA_MULTRET, 0); + if r <> 0 then + raise Exception.Create(LuaGetReturnString(r)); +end; + +function LuaGetReturnString(const ReturnCode: Integer): String; +begin + case ReturnCode of + LUA_OK: Result := 'LUA_OK'; + LUA_YIELD_: Result := 'LUA_YIELD_'; + LUA_ERRRUN: Result := 'LUA_ERRRUN'; + LUA_ERRSYNTAX: Result := 'LUA_ERRSYNTAX'; + LUA_ERRMEM: Result := 'LUA_ERRMEM'; + LUA_ERRGCMM: Result := 'LUA_ERRGCMM'; + LUA_ERRERR: Result := 'LUA_ERRERR'; + LUA_ERRFILE: Result := 'LUA_ERRFILE'; + else + Result := IntToStr(ReturnCode); + end; end; function _luawriter(L: Plua_State; const p: Pointer; sz: size_t; ud: Pointer): Integer; cdecl; diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index de6f92bf4..0e1f92922 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -45,7 +45,7 @@ TLuaWebsiteModule = class procedure AddOptionComboBox(const AName, ACaption, AItems: String; const ADefault: Integer); procedure LuaPushMe(L: Plua_State); - function LuaDoMe(L: Plua_State): Integer; + procedure LuaDoMe(L: Plua_State); end; TLuaWebsiteModules = specialize TFPGList<TLuaWebsiteModule>; @@ -122,12 +122,12 @@ function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; LuaPushMe(l); luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnBeforeUpdateList) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnBeforeUpdateList); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -145,12 +145,12 @@ function DoAfterUpdateList(const Module: TModuleContainer): Boolean; LuaPushMe(l); luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnAfterUpdateList) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnAfterUpdateList); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -161,7 +161,7 @@ function DoGetDirectoryPageNumber(const MangaInfo: TMangaInformation; var l: Plua_State; begin - Result := NO_ERROR; + Result := INFORMATION_NOT_FOUND; with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; @@ -173,16 +173,14 @@ function DoGetDirectoryPageNumber(const MangaInfo: TMangaInformation; luaPushObject(l, MangaInfo.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnGetDirectoryPageNumber) then - begin - Result := lua_tointeger(l, -1); - if lua_getglobal(l, 'page') <> 0 then - Page := lua_tointeger(l, -1); - end; + LuaDoMe(l); + LuaCallFunction(l, OnGetDirectoryPageNumber); + Result := lua_tointeger(l, -1); + if lua_getglobal(l, 'page') <> 0 then + Page := lua_tointeger(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -194,7 +192,7 @@ function DoGetNameAndLink(const MangaInfo: TMangaInformation; var l: Plua_State; begin - Result := NO_ERROR; + Result := INFORMATION_NOT_FOUND; with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; @@ -207,12 +205,12 @@ function DoGetNameAndLink(const MangaInfo: TMangaInformation; luaPushObject(l, ALinks, 'links', @luaStringsAddMetaTable); luaPushObject(l, updateList, 'updatelist', @luaUpdateListManagerAddMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnGetNameAndLink) then - Result := lua_tointeger(L, -1); + LuaDoMe(l); + LuaCallFunction(l, OnGetNameAndLink); + Result := lua_tointeger(L, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -223,7 +221,7 @@ function DoGetInfo(const MangaInfo: TMangaInformation; const AURL: String; var l: Plua_State; begin - Result := NO_ERROR; + Result := INFORMATION_NOT_FOUND; with TLuaWebsiteModule(Module.TagPtr) do begin l := LuaNewBaseState; @@ -233,11 +231,11 @@ function DoGetInfo(const MangaInfo: TMangaInformation; const AURL: String; luaPushObject(l, MangaInfo.mangaInfo, 'mangainfo', @luaMangaInfoAddMetaTable); luaPushObject(l, MangaInfo.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); + LuaDoMe(l); LuaCallFunction(l, OnGetInfo); except - Logger.SendError(lua_tostring(L, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -255,12 +253,12 @@ function DoTaskStart(const Task: TTaskContainer; const Module: TModuleContainer) LuaPushMe(l); luaPushObject(l, Task, 'task', @luaDownloadTaskMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnTaskStart) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnTaskStart); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -281,12 +279,12 @@ function DoGetPageNumber(const DownloadThread: TDownloadThread; luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'url', AURL); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnGetPageNumber) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnGetPageNumber); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -308,12 +306,12 @@ function DoGetImageURL(const DownloadThread: TDownloadThread; const AURL: String luaPushIntegerGlobal(l, 'workid', DownloadThread.WorkId); luaPushStringGlobal(l, 'url', AURL); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnGetImageURL) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnGetImageURL); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -334,12 +332,12 @@ function DoBeforeDownloadImage(const DownloadThread: TDownloadThread; luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'url', AURL); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnBeforeDownloadImage) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnBeforeDownloadImage); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -360,12 +358,12 @@ function DoDownloadImage(const DownloadThread: TDownloadThread; luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); luaPushStringGlobal(l, 'url', AURL); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnDownloadImage) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnDownloadImage); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -386,12 +384,12 @@ function DoSaveImage(const AHTTP: THTTPSendThread; const APath, AName: String; luaPushStringGlobal(l, 'path', APath); luaPushStringGlobal(l, 'name', AName); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnSaveImage) then - Result := lua_tostring(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnSaveImage); + Result := lua_tostring(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -409,12 +407,12 @@ function DoAfterImageSaved(const AFilename: String; const Module: TModuleContain LuaPushMe(l); luaPushStringGlobal(l, 'filename', AFilename); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnAfterImageSaved) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnAfterImageSaved); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -432,12 +430,12 @@ function DoLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): LuaPushMe(l); luaPushObject(l, AHTTP, 'http', @luaHTTPSendThreadAddMetaTable); - if LuaDoMe(l) <> 0 then - raise Exception.Create(''); - if LuaCallFunction(l, OnTaskStart) then - Result := lua_toboolean(l, -1); + LuaDoMe(l); + LuaCallFunction(l, OnTaskStart); + Result := lua_toboolean(l, -1); except - Logger.SendError(lua_tostring(l, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); end; lua_close(l); end; @@ -459,12 +457,14 @@ function LoadLuaToWebsiteModules(AFilename: String): Boolean; m := LuaDumpFileToStream(l, AFilename); if m <> nil then begin - if lua_pcall(l, 0, 0, 0) <> 0 then - raise Exception.Create(''); + i := lua_pcall(l, 0, 0, 0); + if i <> 0 then + raise Exception.Create(LuaGetReturnString(i)); LuaCallFunction(l, 'Init'); end; except - Logger.SendError('Error load lua website module. ' + lua_tostring(L, -1)); + on E: Exception do + Logger.SendError(E.Message + ': ' + lua_tostring(L, -1)); end; finally lua_close(l); @@ -672,14 +672,18 @@ procedure TLuaWebsiteModule.LuaPushMe(L: Plua_State); luaPushIntegerGlobal(L, 'information_not_found', INFORMATION_NOT_FOUND); end; -function TLuaWebsiteModule.LuaDoMe(L: Plua_State): Integer; +procedure TLuaWebsiteModule.LuaDoMe(L: Plua_State); +var + r: Integer; begin if AlwaysLoadLuaFromFile then - Result := luaL_loadfile(L, PChar(Container.FileName)) + r := luaL_loadfile(L, PChar(Container.FileName)) else - Result := LuaLoadFromStream(L, Container.ByteCode, PChar(Container.FileName)); - if Result = 0 then - Result := lua_pcall(L, 0, 0, 0); + r := LuaLoadFromStream(L, Container.ByteCode, PChar(Container.FileName)); + if r = 0 then + r := lua_pcall(L, 0, 0, 0); + if r <> 0 then + raise Exception.Create(LuaGetReturnString(r)); end; // ----------------------------------------------------------------------------- From 5a29f86805c0b0801da217472cb8cf600819c67b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 21 Feb 2018 21:21:39 +0300 Subject: [PATCH 2376/2794] add website settings ui --- mangadownloader/forms/frmWebsiteSettings.lfm | 10 +- mangadownloader/forms/frmWebsiteSettings.pas | 178 ++++++++++++++++++- 2 files changed, 173 insertions(+), 15 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index 5fcf7fa7d..f92e45d64 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -114,18 +114,14 @@ object WebsiteSettingsForm: TWebsiteSettingsForm Width = 417 ClientWidth = 417 ClientHeight = 432 - object prSettings: TTIPropertyGrid + object pnProps: TPanel Left = 0 Height = 432 Top = 0 Width = 417 Align = alClient - CheckboxForBoolean = True - DefaultValueFont.Color = clWindowText - Filter = [tkInteger, tkChar, tkEnumeration, tkFloat, tkSet, tkMethod, tkSString, tkLString, tkAString, tkWString, tkVariant, tkArray, tkRecord, tkInterface, tkClass, tkObject, tkWChar, tkBool, tkInt64, tkQWord, tkDynArray, tkInterfaceRaw, tkProcVar, tkUString, tkUChar, tkHelper, tkFile, tkClassRef, tkPointer] - Indent = 16 - NameFont.Color = clWindowText - ValueFont.Color = clMaroon + BevelOuter = bvNone + TabOrder = 0 end end end diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index f6c5a458d..c529d45a6 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -5,20 +5,38 @@ interface uses - Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, - Graphics, Dialogs, StdCtrls, ExtCtrls, PairSplitter, EditBtn, VirtualTrees; + Classes, SysUtils, FileUtil, WebsiteModules, RTTIGrids, Forms, Controls, + Graphics, Dialogs, StdCtrls, ExtCtrls, PairSplitter, EditBtn, VirtualTrees, + contnrs, RTTICtrls; type + { TSettingsView } + + TSettingsView = class + private + FSettings: TWebsiteModuleSettings; + FOwner: TPanel; + FControls: TFPObjectList; + procedure SetData(settings: TWebsiteModuleSettings); + function GetData: TWebsiteModuleSettings; + procedure CreateControls; + procedure UpdateView; + public + constructor Create(owner: TPanel); + destructor Destroy; override; + property Data: TWebsiteModuleSettings read GetData write SetData; + end; + { TWebsiteSettingsForm } TWebsiteSettingsForm = class(TForm) edSearch: TEditButton; + pnProps: TPanel; spMain: TPairSplitter; spList: TPairSplitterSide; spProps: TPairSplitterSide; pnTop: TPanel; - prSettings: TTIPropertyGrid; vtWebsite: TVirtualStringTree; procedure edSearchButtonClick(Sender: TObject); procedure edSearchChange(Sender: TObject); @@ -31,7 +49,7 @@ TWebsiteSettingsForm = class(TForm) procedure vtWebsiteGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); private - + settingsView: TSettingsView; public procedure LoadWebsiteSettings; end; @@ -41,7 +59,7 @@ TWebsiteSettingsForm = class(TForm) implementation -uses WebsiteModules, frmCustomColor; +uses frmCustomColor; {$R *.lfm} @@ -50,7 +68,7 @@ implementation procedure TWebsiteSettingsForm.FormCreate(Sender: TObject); begin AddVT(vtWebsite); - prSettings.PreferredSplitterX:=200; + settingsView := TSettingsView.Create(pnProps); end; procedure TWebsiteSettingsForm.edSearchChange(Sender: TObject); @@ -84,6 +102,7 @@ procedure TWebsiteSettingsForm.edSearchButtonClick(Sender: TObject); procedure TWebsiteSettingsForm.FormDestroy(Sender: TObject); begin RemoveVT(vtWebsite); + settingsView.Free; end; procedure TWebsiteSettingsForm.vtWebsiteCompareNodes(Sender: TBaseVirtualTree; @@ -96,8 +115,7 @@ procedure TWebsiteSettingsForm.vtWebsiteCompareNodes(Sender: TBaseVirtualTree; procedure TWebsiteSettingsForm.vtWebsiteFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); begin - writeln(PModuleContainer(Sender.GetNodeData(Node))^.Website); - prSettings.TIObject:=PModuleContainer(vtWebsite.GetNodeData(Node))^.Settings; + settingsView.Data := PModuleContainer(Sender.GetNodeData(Node))^.Settings; end; procedure TWebsiteSettingsForm.vtWebsiteGetText(Sender: TBaseVirtualTree; @@ -119,5 +137,149 @@ procedure TWebsiteSettingsForm.LoadWebsiteSettings; vtWebsite.EndUpdate; end; +{ TSettingsView } + +constructor TSettingsView.Create(owner: TPanel); +begin + FOwner := owner; + FControls := TFPObjectList.Create(True); + CreateControls; + UpdateView; +end; + +destructor TSettingsView.Destroy; +begin + FControls.Clear; + FControls.Free; + inherited; +end; + +procedure TSettingsView.SetData(settings: TWebsiteModuleSettings); +begin + FSettings := settings; + UpdateView; +end; + +function TSettingsView.GetData: TWebsiteModuleSettings; +begin + Result := FSettings; +end; + +procedure TSettingsView.CreateControls; + +const LEFT_OFFSET = 250; + + function AddLabel(text: String; prev: TControl): TLabel; + begin + Result := TLabel.Create(FOwner); + Result.Parent := FOwner; + Result.Caption := text; + Result.AnchorSide[akLeft].Control := FOwner; + Result.AnchorSide[akLeft].Side := asrLeft; + Result.BorderSpacing.Left := 5; + if prev <> nil then begin + Result.AnchorSide[akTop].Control := prev; + Result.AnchorSide[akTop].Side := asrBottom; + Result.BorderSpacing.Top := 10; + end + else + Result.Top := 5; + FControls.Add(Result); + end; + + procedure SetAnchor(control, lbl, prev: TControl); + begin + control.Left := LEFT_OFFSET; + control.Anchors := [akTop, akLeft, akRight]; + if prev <> nil then begin + control.AnchorSide[akTop].Control := prev; + control.AnchorSide[akTop].Side := asrBottom; + control.BorderSpacing.Top := 10; + end + else begin + control.AnchorSide[akTop].Control := lbl; + control.AnchorSide[akTop].Side := asrCenter; + end; + control.AnchorSide[akRight].Control := FOwner; + control.AnchorSide[akRight].Side := asrRight; + end; + + function AddEdit(name, text: String; prev: TControl): TTIEdit; + var + lbl: TLabel; + begin + lbl := AddLabel(text, prev); + Result := TTIEdit.Create(FOwner); + Result.Parent := FOwner; + Result.Link.TIObject := FSettings; + Result.Link.TIPropertyName := name; + SetAnchor(Result, lbl, prev); + FControls.Add(Result); + end; + + function AddSpinEdit(name, text: String; min, max: Integer; prev: TControl): TTISpinEdit; + var + lbl: TLabel; + begin + lbl := AddLabel(text, prev); + Result := TTISpinEdit.Create(FOwner); + Result.MinValue := min; + Result.MaxValue := max; + Result.Parent := FOwner; + Result.Link.TIObject := FSettings; + Result.Link.TIPropertyName := name; + SetAnchor(Result, lbl, prev); + Result.Anchors := [akTop, akLeft]; + Result.Width := 100; + FControls.Add(Result); + end; + + function AddComboBox(name, text: String; prev: TControl): TTIComboBox; + var + lbl: TLabel; + begin + lbl := AddLabel(text, prev); + Result := TTIComboBox.Create(FOwner); + Result.Parent := FOwner; + Result.Link.TIObject := FSettings; + Result.Link.TIPropertyName := name; + SetAnchor(Result, lbl, prev); + Result.Anchors := [akTop, akLeft]; + Result.Width := 200; + FControls.Add(Result); + end; + +var + prev: TControl; + +begin + // TODO: resources + prev := AddSpinEdit('MaxTaskLimit', 'Max task limit:', 1, 8, nil); + prev := AddSpinEdit('MaxThreadPerTaskLimit', 'Max thread per task limit:', 1, 32, prev); + prev := AddSpinEdit('MaxConnectionLimit', 'Max connection limit:', 1, 32, prev); + prev := AddSpinEdit('UpdateListNumberOfThread', 'Update list number of thread:', 1, 32, prev); + prev := AddSpinEdit('UpdateListDirectoryPageNumber', 'Update list directory page number:', 1, 100000000, prev); + prev := AddEdit('UserAgent', 'User agent:', prev); + prev := AddEdit('Cookies', 'Cookies:', prev); + prev := AddComboBox('ProxyType', 'Proxy type:', prev); + prev := AddEdit('ProxyHost', 'Proxy host:', prev); + prev := AddEdit('ProxyPort', 'Proxy port:', prev); + prev := AddEdit('ProxyUsername', 'Proxy username:', prev); + prev := AddEdit('ProxyPassword', 'Proxy password:', prev); +end; + +procedure TSettingsView.UpdateView; +var + i: Integer; +begin + for i := 0 to FControls.Count-1 do + if FControls[i] is TTIEdit then + TTIEdit(FControls[i]).Link.TIObject := FSettings + else if FControls[i] is TTISpinEdit then + TTISpinEdit(FControls[i]).Link.TIObject := FSettings + else if FControls[i] is TTIComboBox then + TTIComboBox(FControls[i]).Link.TIObject := FSettings; +end; + end. From 60b3efcb8b0a509fd280849a9bcc051b1b12276d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 05:44:50 +0300 Subject: [PATCH 2377/2794] website settings ui, use rtti --- mangadownloader/forms/frmWebsiteSettings.lfm | 7 ++ mangadownloader/forms/frmWebsiteSettings.pas | 82 +++++++------------- 2 files changed, 33 insertions(+), 56 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index f92e45d64..504c20c43 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -122,6 +122,13 @@ object WebsiteSettingsForm: TWebsiteSettingsForm Align = alClient BevelOuter = bvNone TabOrder = 0 + ChildSizing.LeftRightSpacing = 5 + ChildSizing.TopBottomSpacing = 5 + ChildSizing.HorizontalSpacing = 20 + ChildSizing.VerticalSpacing = 7 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 2 end end end diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index c529d45a6..d6a188490 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -59,7 +59,7 @@ TWebsiteSettingsForm = class(TForm) implementation -uses frmCustomColor; +uses frmCustomColor, typinfo; {$R *.lfm} @@ -174,98 +174,68 @@ procedure TSettingsView.CreateControls; Result := TLabel.Create(FOwner); Result.Parent := FOwner; Result.Caption := text; - Result.AnchorSide[akLeft].Control := FOwner; - Result.AnchorSide[akLeft].Side := asrLeft; - Result.BorderSpacing.Left := 5; - if prev <> nil then begin - Result.AnchorSide[akTop].Control := prev; - Result.AnchorSide[akTop].Side := asrBottom; - Result.BorderSpacing.Top := 10; - end - else - Result.Top := 5; FControls.Add(Result); end; - procedure SetAnchor(control, lbl, prev: TControl); - begin - control.Left := LEFT_OFFSET; - control.Anchors := [akTop, akLeft, akRight]; - if prev <> nil then begin - control.AnchorSide[akTop].Control := prev; - control.AnchorSide[akTop].Side := asrBottom; - control.BorderSpacing.Top := 10; - end - else begin - control.AnchorSide[akTop].Control := lbl; - control.AnchorSide[akTop].Side := asrCenter; - end; - control.AnchorSide[akRight].Control := FOwner; - control.AnchorSide[akRight].Side := asrRight; - end; - function AddEdit(name, text: String; prev: TControl): TTIEdit; - var - lbl: TLabel; begin - lbl := AddLabel(text, prev); + AddLabel(text, prev); Result := TTIEdit.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; - SetAnchor(Result, lbl, prev); + Result.Width := 300; FControls.Add(Result); end; function AddSpinEdit(name, text: String; min, max: Integer; prev: TControl): TTISpinEdit; - var - lbl: TLabel; begin - lbl := AddLabel(text, prev); + AddLabel(text, prev); Result := TTISpinEdit.Create(FOwner); Result.MinValue := min; Result.MaxValue := max; Result.Parent := FOwner; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; - SetAnchor(Result, lbl, prev); - Result.Anchors := [akTop, akLeft]; Result.Width := 100; FControls.Add(Result); end; function AddComboBox(name, text: String; prev: TControl): TTIComboBox; - var - lbl: TLabel; begin - lbl := AddLabel(text, prev); + AddLabel(text, prev); Result := TTIComboBox.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; - SetAnchor(Result, lbl, prev); - Result.Anchors := [akTop, akLeft]; Result.Width := 200; FControls.Add(Result); end; var - prev: TControl; + prev: TControl = nil; + propList: PPropList; + typeData: PTypeData; + cnt, i: Integer; begin - // TODO: resources - prev := AddSpinEdit('MaxTaskLimit', 'Max task limit:', 1, 8, nil); - prev := AddSpinEdit('MaxThreadPerTaskLimit', 'Max thread per task limit:', 1, 32, prev); - prev := AddSpinEdit('MaxConnectionLimit', 'Max connection limit:', 1, 32, prev); - prev := AddSpinEdit('UpdateListNumberOfThread', 'Update list number of thread:', 1, 32, prev); - prev := AddSpinEdit('UpdateListDirectoryPageNumber', 'Update list directory page number:', 1, 100000000, prev); - prev := AddEdit('UserAgent', 'User agent:', prev); - prev := AddEdit('Cookies', 'Cookies:', prev); - prev := AddComboBox('ProxyType', 'Proxy type:', prev); - prev := AddEdit('ProxyHost', 'Proxy host:', prev); - prev := AddEdit('ProxyPort', 'Proxy port:', prev); - prev := AddEdit('ProxyUsername', 'Proxy username:', prev); - prev := AddEdit('ProxyPassword', 'Proxy password:', prev); + typeData := GetTypeData(TWebsiteModuleSettings.ClassInfo); + GetMem(propList, typeData^.PropCount * SizeOf(Pointer)); + cnt := GetPropList(TWebsiteModuleSettings.ClassInfo, propList); + for i := 0 to cnt-1 do begin + case propList^[i]^.PropType^.Kind of + tkInteger: begin + prev := AddSpinEdit(propList^[i]^.Name, propList^[i]^.Name, 1, High(Integer), prev); + end; + tkAString: begin + prev := AddEdit(propList^[i]^.Name, propList^[i]^.Name, prev); + end; + tkEnumeration: begin + prev := AddComboBox(propList^[i]^.Name, propList^[i]^.Name, prev); + end; + end; + end; + FreeMem(propList); end; procedure TSettingsView.UpdateView; From 0639fe55604eac0b9a63a458fae3ce76f32fb2dd Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 07:01:34 +0300 Subject: [PATCH 2378/2794] myReaderMangaCMS, fix --- lua/modules/myReaderMangaCMS.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 1b9c0b760..a8a4367ed 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -64,6 +64,7 @@ function AddWebsiteModule(name, url, cat) end function Init() + AddWebsiteModule('MangaForest', 'http://mangaforest.com', 'English') AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', 'Turkish'); @@ -78,5 +79,5 @@ function Init() c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); - AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com/', c); + AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); end From da4820843114223a17e1c2254a95981a4d167cf6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 07:02:52 +0300 Subject: [PATCH 2379/2794] LuaWebsiteModules, fix get info result --- baseunits/lua/LuaWebsiteModules.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 0e1f92922..18fa290b9 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -233,6 +233,7 @@ function DoGetInfo(const MangaInfo: TMangaInformation; const AURL: String; LuaDoMe(l); LuaCallFunction(l, OnGetInfo); + Result := lua_tointeger(L, -1); except on E: Exception do Logger.SendError(E.Message + ': ' + lua_tostring(l, -1)); From c3eeb39ca8b0aa61d038c56d9a5f37a848b13ecb Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 14:14:21 +0800 Subject: [PATCH 2380/2794] rewite account manager to use tmodulecontainer #1020 --- mangadownloader/forms/frmAccountManager.lfm | 136 +------ mangadownloader/forms/frmAccountManager.lrj | 3 +- mangadownloader/forms/frmAccountManager.pas | 409 +++++++------------- mangadownloader/forms/frmAccountSet.lfm | 47 +-- mangadownloader/forms/frmAccountSet.lrj | 2 +- mangadownloader/forms/frmAccountSet.pas | 6 +- mangadownloader/forms/frmMain.pas | 8 + mangadownloader/languages/fmd.de.po | 24 +- mangadownloader/languages/fmd.el_GR.po | 24 +- mangadownloader/languages/fmd.en.po | 23 +- mangadownloader/languages/fmd.es.po | 23 +- mangadownloader/languages/fmd.id_ID.po | 23 +- mangadownloader/languages/fmd.pl_PL.po | 24 +- mangadownloader/languages/fmd.po | 23 +- mangadownloader/languages/fmd.pt_BR.po | 24 +- mangadownloader/languages/fmd.ru_RU.po | 23 +- mangadownloader/languages/fmd.tr_TR.po | 24 +- 17 files changed, 264 insertions(+), 582 deletions(-) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 6dfa9a1eb..6776dc5da 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -6,20 +6,15 @@ object AccountManagerForm: TAccountManagerForm ActiveControl = vtAccountList BorderStyle = bsNone Caption = 'AccountManagerForm' - ChildSizing.LeftRightSpacing = 8 - ChildSizing.TopBottomSpacing = 8 ClientHeight = 316 ClientWidth = 392 - OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy - OnShow = FormShow - LCLVersion = '1.7' - Visible = False + LCLVersion = '1.8.0.6' object pnBtContainer: TPanel - Left = 299 - Height = 300 - Top = 8 + Left = 307 + Height = 316 + Top = 0 Width = 85 Align = alRight AutoSize = True @@ -28,66 +23,17 @@ object AccountManagerForm: TAccountManagerForm ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 ChildSizing.Layout = cclLeftToRightThenTopToBottom - ClientHeight = 300 + ClientHeight = 316 ClientWidth = 85 TabOrder = 1 - object btDelete: TBitBtn - Left = 0 - Height = 26 - Top = 60 - Width = 85 - Align = alTop - AutoSize = True - Caption = 'Delete' - Enabled = False - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000000E0000 - 0012000000170000001A0000001A0000001A0000001A0000001A0000001A0000 - 001A0000001A0000001A0000001A00000017000000120000000E0000001C0000 - 5DA2000078CC000078CC000078CC000078CC000078CC000078CC000078CC0000 - 78CC000078CC000078CC000078CC000078CC00005DA20000001C000025000000 - 8FCC5F5FE7FF5252DAFF4C4CD4FF4646CEFF4141C9FF3E3EC6FF3D3DC5FF3C3C - C4FF3B3BC3FF3A3AC2FF3939C1FF3A3AC2FF00008FCC0000250000009E000000 - 9ECC6666EEFF5B5BE3FF5555DDFF4F4FD7FF4A4AD2FF4545CDFF4343CBFF4141 - C9FF4040C8FF3F3FC7FF3E3EC6FF4040C8FF00009ECC00009E000000A6000000 - A7990000A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000 - A8CC0000A8CC0000A8CC0000A8CC0000A8CC0000A7990000A600FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btDeleteClick - TabOrder = 0 - end object btEdit: TBitBtn Left = 0 Height = 26 - Top = 30 + Top = 0 Width = 85 Align = alTop AutoSize = True Caption = 'Edit' - Enabled = False Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000000000FF014B @@ -125,65 +71,16 @@ object AccountManagerForm: TAccountManagerForm 860055555500555555000101E42B0101E09D0101D23F0101B600 } OnClick = btEditClick - TabOrder = 1 - end - object btAdd: TBitBtn - Left = 0 - Height = 26 - Top = 0 - Width = 85 - Align = alTop - AutoSize = True - Caption = 'Add' - Default = True - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF000000 - 0000000000020000000E000000180000001A0000001A0000001A0000001A0000 - 001A0000001A00000019000000100000000300000000FFFFFF00FFFFFF000000 - 0000000000040000001B0000003000000033024700A6025D00CC025D00CC0247 - 00A600000033000000310000001F0000000600000000FFFFFF00FFFFFF000000 - 0000000000000000000000000000021D0000066D00CC22D811FF22D811FF066D - 00CC021D000000000000000000000000000000000000FFFFFF00FFFFFF000747 - 00000000000000000000032000000A7D00000A7D00CC23CD12FF22CC11FF0A7D - 00CC0A7D000003200000000000000000000000000000FFFFFF00FFFFFF000E8D - 00000E8C00000E8C00000E8A00000C8400000C8400CC25C014FF24C013FF0C84 - 00CC0C8400000E8A00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8D - 00000E8C00000E8C00000E8C00000E8B00000D8900CC29B618FF27B416FF0D89 - 00CC0E8B00000E8C00000E8C00000E8C00000E8D0000FFFFFF00FFFFFF000E8E - 00990E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D - 00CC0E8D00CC0E8D00CC0E8D00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000F92 - 00CC59D048FF50C73FFF50C73FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A9 - 20FF2CA51BFF2BA31AFF2DA51CFF33AB22FF0F9200CCFFFFFF00FFFFFF001096 - 00CC5ED54DFF55CC44FF54CB43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC6 - 3EFF4EC53DFF4DC43CFF4CC33BFF4EC53DFF109600CCFFFFFF00FFFFFF00119A - 0099119A00CC119A00CC119A00CC119A00CC119A00CC54CB43FF52C941FF119A - 00CC119A00CC119A00CC119A00CC119A00CC119A0099FFFFFF00FFFFFF00119A - 0000119B0000119B0000119B0000129C0000129E00CC5AD149FF59D048FF129E - 00CC129C0000119B0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A - 0000119B0000119B0000129D000013A2000013A200CC62D951FF61D850FF13A2 - 00CC13A20000129D0000119B0000119B0000119A0000FFFFFF00FFFFFF00119A - 0000119B0000129E000014A5000014A5000014A500CC69E058FF69E058FF14A5 - 00CC14A5000014A50000129E0000119B0000119A0000FFFFFF00FFFFFF00119A - 0000129F000014A8000014A8000014A8000014A800CC72E961FF71E860FF14A8 - 00CC14A8000014A8000014A80000129F0000119A0000FFFFFF00FFFFFF003B7F - 320015A9000015A9000015A9000015A9000015AA009915AA00CC15AA00CC15AA - 009915A9000015A9000015A9000015A90000094D0000FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - OnClick = btAddClick - TabOrder = 2 + TabOrder = 0 end object btRefresh: TBitBtn Left = 0 Height = 26 - Top = 90 + Top = 30 Width = 85 Align = alTop AutoSize = True Caption = 'Refresh' - Enabled = False Glyph.Data = { 36040000424D3604000000000000360000002800000010000000100000000100 2000000000000004000064000000640000000000000000000000FFFFFF000000 @@ -221,14 +118,14 @@ object AccountManagerForm: TAccountManagerForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btRefreshClick - TabOrder = 3 + TabOrder = 1 end end object vtAccountList: TVirtualStringTree - Left = 8 - Height = 300 - Top = 8 - Width = 287 + Left = 0 + Height = 316 + Top = 0 + Width = 303 Align = alClient Colors.DropTargetBorderColor = clHotLight Colors.FocusedSelectionBorderColor = clHotLight @@ -238,7 +135,7 @@ object AccountManagerForm: TAccountManagerForm Header.Columns = < item MinWidth = 25 - Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coFixed] + Options = [coAllowClick, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coFixed, coAllowFocus] Position = 0 Width = 25 end @@ -264,11 +161,10 @@ object AccountManagerForm: TAccountManagerForm TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect] OnBeforeCellPaint = vtAccountListBeforeCellPaint - OnChange = vtAccountListChange OnChecked = vtAccountListChecked - OnFocusChanged = vtAccountListFocusChanged + OnCompareNodes = vtAccountListCompareNodes OnGetText = vtAccountListGetText OnPaintText = vtAccountListPaintText - OnInitNode = vtAccountListInitNode + OnHeaderClick = vtAccountListHeaderClick end end diff --git a/mangadownloader/forms/frmAccountManager.lrj b/mangadownloader/forms/frmAccountManager.lrj index efdf77b0a..db0f01fb4 100644 --- a/mangadownloader/forms/frmAccountManager.lrj +++ b/mangadownloader/forms/frmAccountManager.lrj @@ -1,7 +1,6 @@ {"version":1,"strings":[ -{"hash":78392485,"name":"taccountmanagerform.btdelete.caption","sourcebytes":[68,101,108,101,116,101],"value":"Delete"}, +{"hash":265040957,"name":"taccountmanagerform.caption","sourcebytes":[65,99,99,111,117,110,116,77,97,110,97,103,101,114,70,111,114,109],"value":"AccountManagerForm"}, {"hash":310020,"name":"taccountmanagerform.btedit.caption","sourcebytes":[69,100,105,116],"value":"Edit"}, -{"hash":18340,"name":"taccountmanagerform.btadd.caption","sourcebytes":[65,100,100],"value":"Add"}, {"hash":146640072,"name":"taccountmanagerform.btrefresh.caption","sourcebytes":[82,101,102,114,101,115,104],"value":"Refresh"}, {"hash":230269173,"name":"taccountmanagerform.vtaccountlist.header.columns[1].text","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, {"hash":164185077,"name":"taccountmanagerform.vtaccountlist.header.columns[2].text","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 5f8b2a5cd..f57d72744 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -14,44 +14,38 @@ interface { TAccountManagerForm } TAccountManagerForm = class(TForm) - btDelete: TBitBtn; btRefresh: TBitBtn; btEdit: TBitBtn; - btAdd: TBitBtn; pnBtContainer: TPanel; vtAccountList: TVirtualStringTree; - procedure btAddClick(Sender: TObject); - procedure btDeleteClick(Sender: TObject); procedure btEditClick(Sender: TObject); procedure btRefreshClick(Sender: TObject); - procedure FormClose(Sender: TObject; var CloseAction: TCloseAction); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender: TObject); procedure vtAccountListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure vtAccountListChange(Sender: TBaseVirtualTree; Node: PVirtualNode); procedure vtAccountListChecked(Sender: TBaseVirtualTree; Node: PVirtualNode ); - procedure vtAccountListFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); + procedure vtAccountListCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); procedure vtAccountListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure vtAccountListInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + {$if VTMajorVersion < 5} + procedure vtAccountListHeaderClick(Sender: TVTHeader; Column: TColumnIndex; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + {$else} + procedure vtAccountListHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + {$endif} procedure vtAccountListPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); private - { private declarations } + public - { public declarations } - procedure RefreshList; - procedure SaveForm; - procedure LoadForm; - procedure RefreshWebsiteAvailable; + procedure LoadAccounts; + procedure SortList; end; TAccountCheck = class; @@ -60,26 +54,20 @@ TAccountCheck = class; TAccountCheckThread = class(TBaseThread) private - fwebsite: String; - fhttp: THTTPSendThread; + fmodule: TModuleContainer; fthreadlist: TAccountCheck; + fhttp: THTTPSendThread; procedure SyncStatus; protected procedure Execute; override; public - constructor Create(const AWebsite: String; ThreadList: TAccountCheck); + constructor Create(const AModule: TModuleContainer; AThreadList: TAccountCheck); destructor Destroy; override; end; - TAccountCheck = class - private - fthreads: TFPList; - fthreadslock: TRTLCriticalSection; + TAccountCheck = class(TThreadList) public - constructor Create; destructor Destroy; override; - procedure AddThread(const t: TAccountCheckThread); - procedure DeleteThread(const t: TAccountCheckThread); procedure StopAll; end; @@ -98,83 +86,51 @@ TAccountCheck = class implementation -uses frmMain, frmCustomColor; +uses frmCustomColor, math; var - Websites, WebsitesAvailable: TStringlist; AccountThreadList: TAccountCheck; {$R *.lfm} { TAccountCheck } -constructor TAccountCheck.Create; -begin - fthreads := TFPList.Create; - InitCriticalSection(fthreadslock); -end; - destructor TAccountCheck.Destroy; begin - if fthreads.Count > 0 then - StopAll; - while fthreads.Count > 0 do Sleep(250); - fthreads.Free; - DoneCriticalsection(fthreadslock); - inherited Destroy; -end; - -procedure TAccountCheck.AddThread(const t: TAccountCheckThread); -begin - EnterCriticalsection(fthreadslock); - try - fthreads.Add(t); - finally - LeaveCriticalsection(fthreadslock); - end; -end; - -procedure TAccountCheck.DeleteThread(const t: TAccountCheckThread); -begin - EnterCriticalsection(fthreadslock); - try - fthreads.Remove(t); - finally - LeaveCriticalsection(fthreadslock); + StopAll; + while LockList.Count <> 0 do + begin + UnlockList; + Sleep(250); end; + inherited Destroy; end; procedure TAccountCheck.StopAll; var i: Integer; begin - EnterCriticalsection(fthreadslock); - try - if fthreads.Count > 0 then - for i := 0 to fthreads.Count - 1 do - TAccountCheckThread(fthreads[i]).Terminate; - finally - LeaveCriticalsection(fthreadslock); - end; + with LockList do + try + for i := 0 to Count - 1 do + TAccountCheckThread(Items[i]).Terminate; + finally + UnlockList; + end; end; { TAccountCheckThread } procedure TAccountCheckThread.SyncStatus; begin - if Assigned(AccountManagerForm) then - AccountManagerForm.vtAccountList.Repaint; + AccountManagerForm.vtAccountList.Repaint; end; procedure TAccountCheckThread.Execute; -var - p: Integer; begin - if fwebsite = '' then Exit; try - p := Modules.LocateModule(fwebsite); - if p > -1 then - Modules.Login(fhttp, p); + if fmodule.OnLogin<>nil then + fmodule.OnLogin(fhttp,fmodule); Synchronize(@SyncStatus); except on E: Exception do @@ -182,114 +138,105 @@ procedure TAccountCheckThread.Execute; end; end; -constructor TAccountCheckThread.Create(const AWebsite: String; - ThreadList: TAccountCheck); +constructor TAccountCheckThread.Create(const AModule: TModuleContainer; + AThreadList: TAccountCheck); begin inherited Create(False); - if AWebsite <> '' then fwebsite := AWebsite - else fwebsite := ''; - fhttp := THTTPSendThread.Create(Self); - if Assigned(ThreadList) then begin - fthreadlist := ThreadList; - fthreadlist.AddThread(Self); - end - else fthreadlist := nil; + FreeOnTerminate:=True; + fmodule:=AModule; + fthreadlist:=AThreadList; + fthreadlist.Add(Self); + fhttp:=THTTPSendThread.Create(Self); end; destructor TAccountCheckThread.Destroy; begin - if Assigned(fthreadlist) then fthreadlist.DeleteThread(Self); - if Assigned(fhttp) then fhttp.Free; + if fthreadlist<>nil then + fthreadlist.Remove(Self); + fhttp.Free; inherited Destroy; end; { TAccountManagerForm } -procedure TAccountManagerForm.vtAccountListInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -begin - if Assigned(Node) then - Node^.CheckType := ctCheckBox; -end; - procedure TAccountManagerForm.vtAccountListPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); begin - if node = nil then Exit; if Node^.CheckState = csUncheckedNormal then TargetCanvas.Font.Color := clGrayText; end; -procedure TAccountManagerForm.RefreshList; -begin - vtAccountList.RootNodeCount := Account.Count; -end; - -procedure TAccountManagerForm.SaveForm; +procedure TAccountManagerForm.LoadAccounts; var i: Integer; + node: PVirtualNode; begin - with configfile, vtAccountList.Header.Columns do begin - if Count > 0 then - for i := 0 to Count - 1 do - WriteInteger('form', 'vtAccountList' + IntToStr(i) + 'Width', Items[i].Width); - end; + vtAccountList.BeginUpdate; + vtAccountList.Clear; + vtAccountList.NodeDataSize:=SizeOf(TModuleContainer); + for i:=0 to Modules.Count-1 do + with Modules[i] do + if Account<>nil then + begin + node:=vtAccountList.AddChild(nil, Modules[i]); + node^.CheckType:=ctCheckBox; + if Account.Enabled then + node^.CheckState:=csCheckedNormal + else + node^.CheckState:=csUncheckedNormal; + end; + vtAccountList.EndUpdate; end; -procedure TAccountManagerForm.LoadForm; -var - i: Integer; +procedure TAccountManagerForm.SortList; begin - with configfile, vtAccountList.Header.Columns do begin - if Count > 0 then - for i := 0 to Count - 1 do - Items[i].Width := ReadInteger('form', 'vtAccountList' + IntToStr(i) + 'Width', 50); - end; -end; - -procedure TAccountManagerForm.RefreshWebsiteAvailable; -var - i, p: Integer; -begin - WebsitesAvailable.Clear; - if Websites.Count = 0 then Exit; - WebsitesAvailable.Assign(Websites); - WebsitesAvailable.Sorted := True; - if Account.Count > 0 then - for i := 0 to Account.Count - 1 do begin - if WebsitesAvailable.Find(Account.ValueStr[i, 1], p) then - WebsitesAvailable.Delete(p); - end; - btAdd.Enabled := WebsitesAvailable.Count > 0; + with vtAccountList do + Sort(nil, Header.SortColumn, Header.SortDirection, False); end; procedure TAccountManagerForm.vtAccountListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + m: TModuleContainer; begin - if Assigned(Node) then begin - case Column of - 0: if Account.ValueBool[Node^.Index, 0] then - Node^.CheckState := csCheckedNormal - else - Node^.CheckState := csUncheckedNormal; - 1: CellText := Account.ValueStr[Node^.Index, 1]; - 2: CellText := Account.ValueStr[Node^.Index, 2]; - 3: case Account.ValueInt[Node^.Index, 5] of - Integer(asUnknown) : CellText := RS_Unknown; - Integer(asChecking): CellText := RS_Checking; - Integer(asValid) : CellText := RS_Valid; - Integer(asInvalid) : CellText := RS_Invalid; - end; - end; + m:=PModuleContainer(Sender.GetNodeData(Node))^; + case Column of + 1:CellText:=m.Website; + 2:CellText:=m.Account.Username; + 3: case m.Account.Status of + asUnknown:CellText:=RS_Unknown; + asChecking:CellText:=RS_Checking; + asValid:CellText:=RS_Valid; + asInvalid:CellText:=RS_Invalid; + end; end; end; -procedure TAccountManagerForm.FormShow(Sender: TObject); +{$if VTMajorVersion < 5} +procedure TAccountManagerForm.vtAccountListHeaderClick(Sender: TVTHeader; + Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +{$else} +procedure TAccountManagerForm.vtAccountListHeaderClick(Sender: TVTHeader; + HitInfo: TVTHeaderHitInfo); +var + Column: TColumnIndex; + Button: TMouseButton; +{$endif} begin - RefreshList; - RefreshWebsiteAvailable; + {$if VTMajorVersion >= 5} + Column := HitInfo.Column; + Button := HitInfo.Button; + {$endif} + if Sender.SortColumn <> Column then + Sender.SortColumn := Column + else + if Sender.SortDirection = sdAscending then + Sender.SortDirection := sdDescending + else + Sender.SortDirection := sdAscending; + SortList; end; procedure TAccountManagerForm.vtAccountListBeforeCellPaint( @@ -297,158 +244,90 @@ procedure TAccountManagerForm.vtAccountListBeforeCellPaint( Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); begin - if Node = nil then Exit; - if Account.ValueInt[Node^.Index, 5] = Integer(asInvalid) then begin - TargetCanvas.Brush.Color := CL_HLRedMarks; + if PModuleContainer(Sender.GetNodeData(Node))^.Account.Status = asInvalid then + begin + TargetCanvas.Brush.Color:=CL_HLRedMarks; TargetCanvas.FillRect(CellRect); end; end; -procedure TAccountManagerForm.vtAccountListChange(Sender: TBaseVirtualTree; - Node: PVirtualNode); -begin - if Sender.SelectedCount > 0 then begin - btEdit.Enabled := True; - btDelete.Enabled := True; - btRefresh.Enabled := True; - end - else begin - btEdit.Enabled := False; - btDelete.Enabled := False; - btRefresh.Enabled := False; - end; -end; - -procedure TAccountManagerForm.FormClose(Sender: TObject; - var CloseAction: TCloseAction); -begin - SaveForm; - AccountThreadList.StopAll; -end; - procedure TAccountManagerForm.FormCreate(Sender: TObject); -var - i: Integer; begin - Websites := TStringList.Create; - WebsitesAvailable := TStringList.Create; - AccountThreadList := TAccountCheck.Create; - if Modules.Count > 0 then begin - for i := 0 to Modules.Count - 1 do - if Modules.Module[i].AccountSupport then - Websites.Add(Modules.Module[i].Website); - Websites.Sorted := True; - end; - LoadForm; AddVT(vtAccountList); + AccountThreadList:=TAccountCheck.Create; end; procedure TAccountManagerForm.FormDestroy(Sender: TObject); begin + if AccountThreadList<>nil then + AccountThreadList.Free; RemoveVT(vtAccountList); - if Assigned(Websites) then Websites.Free; - if Assigned(WebsitesAvailable) then WebsitesAvailable.Free; - if Assigned(AccountThreadList) then AccountThreadList.Free; -end; - -procedure TAccountManagerForm.btDeleteClick(Sender: TObject); -var - node: PVirtualNode; -begin - if vtAccountList.SelectedCount > 0 then - if MessageDlg(RS_AccountDeleteConfirmation, mtConfirmation, mbYesNo, 0, mbNo) = mrYes then - begin - node := vtAccountList.GetFirstSelected; - if Assigned(node) then begin - Account.DeleteAccount(node^.Index); - RefreshList; - RefreshWebsiteAvailable; - vtAccountList.Repaint; - vtAccountListChange(vtAccountList, nil); - end; - end; end; procedure TAccountManagerForm.btEditClick(Sender: TObject); var - node: PVirtualNode; - u, p: String; + m: TModuleContainer; begin - if vtAccountList.SelectedCount > 0 then begin - node := vtAccountList.GetFirstSelected; - if Assigned(node) then begin - with TAccountSetForm.Create(Self) do - try - cbWebsiteName.Items.Add(Account.ValueStr[node^.Index, 1]); - cbWebsiteName.ItemIndex := 0; - cbWebsiteName.Enabled := False; - u := Account.ValueStr[node^.Index, 2]; - p := Account.ValueStr[node^.Index, 3]; - edUsername.Text := u; - edPassword.Text := p; + if vtAccountList.SelectedCount=0 then Exit; + m:=PModuleContainer(vtAccountList.GetNodeData(vtAccountList.GetFirstSelected))^; + with TAccountSetForm.Create(Self) do + try + Caption:=m.Website; + with m.Account do + begin + edUsername.Text:=Username; + edPassword.Text:=Password; if ShowModal = mrOK then - if (edUsername.Text <> u) or (edPassword.Text <> p) then begin - Account.Username[cbWebsiteName.Text] := edUsername.Text; - Account.Password[cbWebsiteName.Text] := edPassword.Text; + begin + if (edUsername.Text <> Username) or (edPassword.Text <> Password) then + begin + Username:=edUsername.Text; + Password:=edPassword.Text; btRefreshClick(btRefresh); end; - finally - Free; + end; end; + finally + Free; end; - end; end; procedure TAccountManagerForm.btRefreshClick(Sender: TObject); var - node: PVirtualNode; - web: String; + m: TModuleContainer; begin if vtAccountList.SelectedCount = 0 then Exit; - node := vtAccountList.GetFirstSelected; - if node = nil then Exit; - if Account.ValueInt[node^.Index, 5] = Integer(asChecking) then Exit; - web := Account.ValueStr[node^.Index, 1]; - if web <> '' then begin - TAccountCheckThread.Create(web, AccountThreadList); - vtAccountList.Repaint; - end; -end; - -procedure TAccountManagerForm.btAddClick(Sender: TObject); -begin - if Websites.Count = 0 then Exit; - with TAccountSetForm.Create(Self) do - try - cbWebsiteName.Items.Assign(WebsitesAvailable); - if cbWebsiteName.Items.Count > 0 then - cbWebsiteName.ItemIndex := 0; - ckShowPassword.Visible:=True; - if ShowModal = mrOK then - if Account.AddAccount(cbWebsiteName.Text, edUsername.Text, edPassword.Text) then - begin - Account.Save; - RefreshList; - RefreshWebsiteAvailable; - vtAccountList.Selected[vtAccountList.GetLast] := True; - btRefreshClick(btRefresh); - end; - finally - Free; - end; + m:=PModuleContainer(vtAccountList.GetNodeData(vtAccountList.GetFirstSelected()))^; + if m.Account.Status=asChecking then Exit; + TAccountCheckThread.Create(m,AccountThreadList); end; procedure TAccountManagerForm.vtAccountListChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); begin - if Assigned(Node) then - Account.ValueBool[Node^.Index, 0] := Node^.CheckState = csCheckedNormal; + PModuleContainer(Sender.GetNodeData(Node))^.Account.Enabled:=Node^.CheckState=csCheckedNormal; end; -procedure TAccountManagerForm.vtAccountListFocusChanged( - Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); +procedure TAccountManagerForm.vtAccountListCompareNodes( + Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; + var Result: Integer); +var + m1, m2: TModuleContainer; begin - Sender.ScrollIntoView(Node, False, False); + m1:=PModuleContainer(Sender.GetNodeData(Node1))^; + m2:=PModuleContainer(Sender.GetNodeData(Node2))^; + case Column of + 0: if m1.Account.Enabled=m2.Account.Enabled then + Result:=AnsiCompareStr(m1.Website,m2.Website) + else + Result:=ifthen(m1.Account.Enabled>m2.Account.Enabled,1,-1); + 1:Result:=AnsiCompareStr(m1.Website,m2.Website); + 2:Result:=AnsiCompareStr(m1.Account.Username,m2.Account.Username); + 3: if m1.Account.Status=m2.Account.Status then + Result:=AnsiCompareStr(m1.Website,m2.Website) + else + Result:=ifthen(m1.Account.Status>m2.Account.Status,1,-1); + end; end; end. diff --git a/mangadownloader/forms/frmAccountSet.lfm b/mangadownloader/forms/frmAccountSet.lfm index 1dc066d5e..82984225a 100644 --- a/mangadownloader/forms/frmAccountSet.lfm +++ b/mangadownloader/forms/frmAccountSet.lfm @@ -4,7 +4,6 @@ object AccountSetForm: TAccountSetForm Top = 229 Width = 269 BorderStyle = bsDialog - ActiveControl = cbWebsiteName Caption = 'Account' ChildSizing.LeftRightSpacing = 8 ChildSizing.TopBottomSpacing = 8 @@ -13,31 +12,11 @@ object AccountSetForm: TAccountSetForm ClientHeight = 234 ClientWidth = 269 Position = poMainFormCenter - LCLVersion = '1.7' - Visible = False - object cbWebsiteName: TComboBox - Left = 8 - Height = 23 - Top = 29 - Width = 253 - Align = alTop - ItemHeight = 15 - Style = csDropDownList - TabOrder = 0 - end - object Label1: TLabel - Left = 8 - Height = 15 - Top = 8 - Width = 253 - Align = alTop - Caption = 'Website' - ParentColor = False - end + LCLVersion = '1.8.0.6' object Label2: TLabel Left = 8 Height = 15 - Top = 58 + Top = 8 Width = 253 Align = alTop Caption = 'Username' @@ -46,7 +25,7 @@ object AccountSetForm: TAccountSetForm object Label3: TLabel Left = 8 Height = 15 - Top = 108 + Top = 58 Width = 253 Align = alTop Caption = 'Password' @@ -55,33 +34,32 @@ object AccountSetForm: TAccountSetForm object edUsername: TEdit Left = 8 Height = 23 - Top = 79 + Top = 29 Width = 253 Align = alTop - TabOrder = 1 + TabOrder = 0 TextHint = 'Username' end object edPassword: TEdit Left = 8 Height = 23 - Top = 129 + Top = 79 Width = 253 Align = alTop EchoMode = emPassword PasswordChar = '*' - TabOrder = 2 + TabOrder = 1 TextHint = 'Password' end object ckShowPassword: TCheckBox Left = 8 Height = 19 - Top = 158 + Top = 108 Width = 253 Align = alTop Caption = 'Show password' - OnChange = ckShowPasswordChange - TabOrder = 3 - Visible = False + OnEditingDone = ckShowPasswordEditingDone + TabOrder = 2 end object btOk: TBitBtn AnchorSideRight.Control = btCancel @@ -132,10 +110,9 @@ object AccountSetForm: TAccountSetForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btOkClick - TabOrder = 4 + TabOrder = 3 end object btCancel: TBitBtn - AnchorSideRight.Control = Label1 AnchorSideRight.Side = asrBottom Left = 179 Height = 26 @@ -181,6 +158,6 @@ object AccountSetForm: TAccountSetForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } ModalResult = 2 - TabOrder = 5 + TabOrder = 4 end end diff --git a/mangadownloader/forms/frmAccountSet.lrj b/mangadownloader/forms/frmAccountSet.lrj index c327d63af..cca69fd24 100644 --- a/mangadownloader/forms/frmAccountSet.lrj +++ b/mangadownloader/forms/frmAccountSet.lrj @@ -1,5 +1,5 @@ {"version":1,"strings":[ -{"hash":230269173,"name":"taccountsetform.label1.caption","sourcebytes":[87,101,98,115,105,116,101],"value":"Website"}, +{"hash":127560724,"name":"taccountsetform.caption","sourcebytes":[65,99,99,111,117,110,116],"value":"Account"}, {"hash":164185077,"name":"taccountsetform.label2.caption","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, {"hash":145417188,"name":"taccountsetform.label3.caption","sourcebytes":[80,97,115,115,119,111,114,100],"value":"Password"}, {"hash":164185077,"name":"taccountsetform.edusername.texthint","sourcebytes":[85,115,101,114,110,97,109,101],"value":"Username"}, diff --git a/mangadownloader/forms/frmAccountSet.pas b/mangadownloader/forms/frmAccountSet.pas index 6630a5940..984911b0f 100644 --- a/mangadownloader/forms/frmAccountSet.pas +++ b/mangadownloader/forms/frmAccountSet.pas @@ -15,15 +15,13 @@ interface TAccountSetForm = class(TForm) btOk: TBitBtn; btCancel: TBitBtn; - cbWebsiteName: TComboBox; ckShowPassword: TCheckBox; edUsername: TEdit; edPassword: TEdit; - Label1: TLabel; Label2: TLabel; Label3: TLabel; procedure btOkClick(Sender: TObject); - procedure ckShowPasswordChange(Sender: TObject); + procedure ckShowPasswordEditingDone(Sender: TObject); private { private declarations } public @@ -53,7 +51,7 @@ procedure TAccountSetForm.btOkClick(Sender: TObject); ModalResult := mrOK; end; -procedure TAccountSetForm.ckShowPasswordChange(Sender: TObject); +procedure TAccountSetForm.ckShowPasswordEditingDone(Sender: TObject); begin if ckShowPassword.Checked then edPassword.PasswordChar:=#0 diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 577c5c6c2..de523868c 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1765,6 +1765,7 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); Modules.LoadFromFile; WebsiteOptionCustomForm.CreateWebsiteOption; WebsiteSettingsForm.LoadWebsiteSettings; + AccountManagerForm.LoadAccounts; //load configfile LoadMangaOptions; @@ -5547,6 +5548,10 @@ procedure TMainForm.LoadFormInformation; // lua website modules list restorevt(LuaModulesUpdaterForm.vtLuaModulesRepos, 'vtLuaModulesRepos'); LuaModulesUpdaterForm.SortList; + + // account + restorevt(AccountManagerForm.vtAccountList, 'vtAccountList'); + AccountManagerForm.SortList; end; end; @@ -5588,6 +5593,9 @@ procedure TMainForm.SaveFormInformation; // lua website modules list savevt(LuaModulesUpdaterForm.vtLuaModulesRepos, 'vtLuaModulesRepos'); + + // account + savevt(AccountManagerForm.vtAccountList, 'vtAccountList'); end; end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 72c835202..3bb4ee22d 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -544,16 +544,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Hinzufügen" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Löschen" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -563,6 +553,10 @@ msgstr "Bearbeiten" msgid "Refresh" msgstr "Aktualisieren" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -590,6 +584,10 @@ msgstr "Abbrechen" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Passwort anzeigen" @@ -605,12 +603,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Benutzername" -#: taccountsetform.label1.caption -#| msgid "Username" -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Webseite" - #: taccountsetform.label2.caption #| msgid "Status" msgctxt "taccountsetform.label2.caption" diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index 0d4f853a8..ffbab0e76 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -548,16 +548,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Προσθήκη" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Διαγραφή" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -567,6 +557,10 @@ msgstr "Επεξεργασία" msgid "Refresh" msgstr "Ανανέωση" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -594,6 +588,10 @@ msgstr "Άκυρο" msgid "Ok" msgstr "Εντάξει" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Εμφάνιση κωδικού" @@ -609,12 +607,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Όνομα χρήστη" -#: taccountsetform.label1.caption -#| msgid "Username" -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Ιστότοπος" - #: taccountsetform.label2.caption #| msgid "Status" msgctxt "taccountsetform.label2.caption" diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index eee2f1443..6b8df0bb2 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -554,16 +554,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "Missing %s" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Add" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Delete" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -573,6 +563,10 @@ msgstr "Edit" msgid "Refresh" msgstr "Refresh" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" @@ -597,6 +591,10 @@ msgstr "Cancel" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Show password" @@ -611,11 +609,6 @@ msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" msgid "Username" msgstr "Username" -#: taccountsetform.label1.caption -msgctxt "TACCOUNTSETFORM.LABEL1.CAPTION" -msgid "Website" -msgstr "Website" - #: taccountsetform.label2.caption msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" msgid "Username" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index c7f64edad..f4e98e35a 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -565,16 +565,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "Perdido %s" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Agregar" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Eliminar" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -584,6 +574,10 @@ msgstr "Editar" msgid "Refresh" msgstr "Actualizar" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" @@ -608,6 +602,10 @@ msgstr "Cancelar" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Mostar Contraseña" @@ -622,11 +620,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Usuario" -#: taccountsetform.label1.caption -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Sitio Web" - #: taccountsetform.label2.caption msgctxt "taccountsetform.label2.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index ed1ef897e..283221bc3 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -554,16 +554,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "Tidak ditemukan %s" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Tambah" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Hapus" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -573,6 +563,10 @@ msgstr "Ubah" msgid "Refresh" msgstr "Segarkan" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" msgid "Website" @@ -597,6 +591,10 @@ msgstr "Batal" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Tampilkan kata kunci" @@ -611,11 +609,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Nama user" -#: taccountsetform.label1.caption -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Situs" - #: taccountsetform.label2.caption msgctxt "taccountsetform.label2.caption" msgid "Username" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 231ab920b..9a7097cc2 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -544,16 +544,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Dodaj" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Usuń" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -563,6 +553,10 @@ msgstr "Edytuj" msgid "Refresh" msgstr "Odśwież" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -590,6 +584,10 @@ msgstr "Anuluj" msgid "Ok" msgstr "OK" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Pokaż hasło" @@ -605,12 +603,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Nazwa użytkownika" -#: taccountsetform.label1.caption -#| msgid "Username" -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Strona WWW" - #: taccountsetform.label2.caption #| msgid "Status" msgctxt "taccountsetform.label2.caption" diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index d362d8f36..b5625c497 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -507,16 +507,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -526,6 +516,10 @@ msgstr "" msgid "Refresh" msgstr "" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" @@ -550,6 +544,10 @@ msgstr "" msgid "Ok" msgstr "" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "" @@ -564,11 +562,6 @@ msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" msgid "Username" msgstr "" -#: taccountsetform.label1.caption -msgctxt "TACCOUNTSETFORM.LABEL1.CAPTION" -msgid "Website" -msgstr "" - #: taccountsetform.label2.caption msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" msgid "Username" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 0edbe2389..ef15264ad 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -545,16 +545,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Adic" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Apagar" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -564,6 +554,10 @@ msgstr "Editar" msgid "Refresh" msgstr "Atualizar" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -591,6 +585,10 @@ msgstr "Cancelar" msgid "Ok" msgstr "Ok" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Exibir senha" @@ -606,12 +604,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Nome de usuário" -#: taccountsetform.label1.caption -#| msgid "Username" -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Website" - #: taccountsetform.label2.caption #| msgid "Status" msgctxt "taccountsetform.label2.caption" diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 6609166e0..afdce417c 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -561,16 +561,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Добавить" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Удалить" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -580,6 +570,10 @@ msgstr "Изменить" msgid "Refresh" msgstr "Обновить" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" @@ -604,6 +598,10 @@ msgstr "Отмена" msgid "Ok" msgstr "OK" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Показать пароль" @@ -618,11 +616,6 @@ msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" msgid "Username" msgstr "Имя пользователя" -#: taccountsetform.label1.caption -msgctxt "TACCOUNTSETFORM.LABEL1.CAPTION" -msgid "Website" -msgstr "Сайт" - #: taccountsetform.label2.caption msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" msgid "Username" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 8eb376462..0c0b6712c 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -568,16 +568,6 @@ msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" msgstr "%s eksik" -#: taccountmanagerform.btadd.caption -msgctxt "taccountmanagerform.btadd.caption" -msgid "Add" -msgstr "Ekle" - -#: taccountmanagerform.btdelete.caption -msgctxt "taccountmanagerform.btdelete.caption" -msgid "Delete" -msgstr "Sil" - #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" msgid "Edit" @@ -587,6 +577,10 @@ msgstr "Düzenle" msgid "Refresh" msgstr "Yenile" +#: taccountmanagerform.caption +msgid "AccountManagerForm" +msgstr "" + #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -614,6 +608,10 @@ msgstr "İptal" msgid "Ok" msgstr "Tamam" +#: taccountsetform.caption +msgid "Account" +msgstr "" + #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Şifreyi göster" @@ -629,12 +627,6 @@ msgctxt "taccountsetform.edusername.texthint" msgid "Username" msgstr "Kullanıcı Adı" -#: taccountsetform.label1.caption -#| msgid "Username" -msgctxt "taccountsetform.label1.caption" -msgid "Website" -msgstr "Site" - #: taccountsetform.label2.caption #| msgid "Status" msgctxt "taccountsetform.label2.caption" From c77e67d907dbf82c8121c0edb4488381d7de5a72 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 14:18:02 +0800 Subject: [PATCH 2381/2794] move accounts page to websites --- mangadownloader/forms/frmMain.lfm | 20 +++++++++----------- mangadownloader/forms/frmMain.lrj | 2 +- mangadownloader/forms/frmMain.pas | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index c529353ed..faf9bb480 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,10 +37,10 @@ object MainForm: TMainForm Height = 526 Top = 8 Width = 769 - ActivePage = tsDownload + ActivePage = tsOption Align = alClient ParentFont = False - TabIndex = 0 + TabIndex = 3 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -2639,11 +2639,11 @@ object MainForm: TMainForm Height = 400 Top = 4 Width = 761 - ActivePage = tsGeneral + ActivePage = tsWebsites Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 0 + TabIndex = 6 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' @@ -4334,6 +4334,9 @@ object MainForm: TMainForm end end end + object tsAccounts: TTabSheet + Caption = 'Accounts' + end object tsWebsiteOptions: TTabSheet Caption = 'Options' ClientHeight = 328 @@ -4366,22 +4369,17 @@ object MainForm: TMainForm end end end - object tsAccounts: TTabSheet - Caption = 'Accounts' - ChildSizing.LeftRightSpacing = 4 - ChildSizing.TopBottomSpacing = 8 - end object tsMisc: TTabSheet Caption = 'Misc' ChildSizing.LeftRightSpacing = 4 ChildSizing.TopBottomSpacing = 8 ChildSizing.HorizontalSpacing = 4 ChildSizing.VerticalSpacing = 4 - ClientHeight = 392 + ClientHeight = 372 ClientWidth = 753 object pcMisc: TPageControl Left = 4 - Height = 376 + Height = 356 Top = 8 Width = 745 ActivePage = tsCustomColor diff --git a/mangadownloader/forms/frmMain.lrj b/mangadownloader/forms/frmMain.lrj index 71d6a0b70..e79f86750 100644 --- a/mangadownloader/forms/frmMain.lrj +++ b/mangadownloader/forms/frmMain.lrj @@ -242,10 +242,10 @@ {"hash":138578252,"name":"tmainform.tbwebsitesexpandall.caption","sourcebytes":[69,120,112,97,110,100,32,65,108,108],"value":"Expand All"}, {"hash":53573292,"name":"tmainform.tbwebsitescollapseall.caption","sourcebytes":[67,111,108,108,97,112,115,101,32,65,108,108],"value":"Collapse All"}, {"hash":32777246,"name":"tmainform.edwebsitessearch.texthint","sourcebytes":[83,101,97,114,99,104,32,119,101,98,115,105,116,101,46,46,46],"value":"Search website..."}, +{"hash":161923523,"name":"tmainform.tsaccounts.caption","sourcebytes":[65,99,99,111,117,110,116,115],"value":"Accounts"}, {"hash":108725763,"name":"tmainform.tswebsiteoptions.caption","sourcebytes":[79,112,116,105,111,110,115],"value":"Options"}, {"hash":197676484,"name":"tmainform.tswebsiteadvanced.caption","sourcebytes":[65,100,118,97,110,99,101,100],"value":"Advanced"}, {"hash":73122451,"name":"tmainform.tswebsitemodules.caption","sourcebytes":[77,111,100,117,108,101,115],"value":"Modules"}, -{"hash":161923523,"name":"tmainform.tsaccounts.caption","sourcebytes":[65,99,99,111,117,110,116,115],"value":"Accounts"}, {"hash":344211,"name":"tmainform.tsmisc.caption","sourcebytes":[77,105,115,99],"value":"Misc"}, {"hash":197593650,"name":"tmainform.tscustomcolor.caption","sourcebytes":[67,117,115,116,111,109,32,99,111,108,111,114],"value":"Custom color"}, {"hash":21335,"name":"tmainform.tslog.caption","sourcebytes":[76,111,103],"value":"Log"}, diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index de523868c..cbaaf385d 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -153,6 +153,7 @@ TMainForm = class(TForm) btDownloadSplit: TSpeedButton; seOptionRetryFailedTask: TSpinEdit; seJPEGQuality: TSpinEdit; + tsAccounts: TTabSheet; tsWebsiteModules: TTabSheet; ToolBarDownloadLeft: TToolBar; tbmiDownloadMoveTop: TToolButton; @@ -170,7 +171,6 @@ TMainForm = class(TForm) tsWebsiteAdvanced: TTabSheet; tsWebsiteSelection: TTabSheet; tsWebsiteOptions: TTabSheet; - tsAccounts: TTabSheet; tsAboutText: TTabSheet; tsChangelogText: TTabSheet; TransferRateToolset: TChartToolset; From 15e56b3e0044b78299348b88b8cc9709d2889b59 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 09:16:07 +0300 Subject: [PATCH 2382/2794] lua, parsehtml temp patch #1027 #1035 --- lua/modules/LHTranslation.lua | 3 ++- lua/modules/MangaSh.lua | 3 ++- lua/modules/WPManga.lua | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index 4ad41b7db..c8380a681 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -19,7 +19,8 @@ function GetPageNumber() if http.GET(MaybeFillHost(module.rooturl, url)) then x=TXQuery.Create(http.document) if http.get(x.xpathstring('//div[@class="commentmetadata"][1]/p/a/@href')) then - x.parsehtml(http.document) + --x.parsehtml(http.document) + x=TXQuery.Create(http.document) x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) return true end diff --git a/lua/modules/MangaSh.lua b/lua/modules/MangaSh.lua index fe2e940e9..1126fc6cb 100644 --- a/lua/modules/MangaSh.lua +++ b/lua/modules/MangaSh.lua @@ -17,7 +17,8 @@ function getinfo() mangainfo.genres=x.xpathstring('string-join((TypeName,TypeDemonym,SeriesTags/TagName),", ")', v) mangainfo.summary=HTMLDecode(x.xpathstring('Description', v)) if http.get(apiurl..'series_chapters?query=SeriesId.Id:'..lid..'&order=desc&sortby=TimeUploaded&limit=0&offset=0') then - x.parsehtml(http.document) + --x.parsehtml(http.document) + x=TXQuery.Create(http.document) local s='json(.)("response")()' local lname='' local showalllang=module.getoption('showalllang') diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index bf8ba457b..0dacedffd 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -36,7 +36,8 @@ function getinfo() s = Trim(x.XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href')) if s == '' then break end if http.GET(MaybeFillHost(module.rooturl, s)) then - x.ParseHTML(http.Document) + x=TXQuery.Create(http.document) + --x.ParseHTML(http.document) else break end @@ -73,7 +74,8 @@ function getpagenumber() -- single page if task.PageLinks.Count == 0 then - x.ParseHTML(http.Document) + --x.ParseHTML(http.Document) + x=TXQuery.Create(http.document) task.PageNumber = x.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count if task.PageNumber == 0 then task.PageNumber = x.XPath('(//select[@name="page"])[1]/option').Count From ada7318b1c73ed02956c636f02c894eae74ea333 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Thu, 22 Feb 2018 10:00:20 +0300 Subject: [PATCH 2383/2794] Update Turkish localization Updated according to [c3eeb39](https://github.com/riderkick/FMD/commit/c3eeb39ca8b0aa61d038c56d9a5f37a848b13ecb) --- mangadownloader/languages/fmd.tr_TR.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 0c0b6712c..dc7d787f5 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -579,7 +579,7 @@ msgstr "Yenile" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "HesapYöneticisiFormu" #: taccountmanagerform.vtaccountlist.header.columns[1].text #| msgid "Username" @@ -610,7 +610,7 @@ msgstr "Tamam" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Hesap" #: taccountsetform.ckshowpassword.caption msgid "Show password" @@ -2420,11 +2420,11 @@ msgstr "Bir websitesi seç" #: twebsitesettingsform.caption msgid "WebsiteSettingsForm" -msgstr "" +msgstr "WebsiteAyarlarıFormu" #: twebsitesettingsform.edsearch.texthint msgid "Website name" -msgstr "" +msgstr "Website Adı" #: udownloadsmanager.rs_compressing msgid "Compressing..." From 225521e63a0a99c7bec4c875eae76f12ad9bdaa7 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 15:02:05 +0800 Subject: [PATCH 2384/2794] remoce accountmanagerdb, modules now using tmodulecontainer.account #1020 --- baseunits/accountmanagerdb.pas | 610 -------------------- baseunits/modules/EHentai.pas | 29 +- baseunits/modules/Madokami.pas | 31 +- baseunits/modules/MangaLife.pas | 30 +- mangadownloader/forms/frmAccountManager.pas | 2 +- mangadownloader/forms/frmMain.pas | 5 +- 6 files changed, 46 insertions(+), 661 deletions(-) delete mode 100644 baseunits/accountmanagerdb.pas diff --git a/baseunits/accountmanagerdb.pas b/baseunits/accountmanagerdb.pas deleted file mode 100644 index fd5626684..000000000 --- a/baseunits/accountmanagerdb.pas +++ /dev/null @@ -1,610 +0,0 @@ -{ - License: GPLv2 - This unit is a part of Free Manga Downloader -} - -unit accountmanagerdb; - -{$mode objfpc}{$H+} - -interface - -uses - SysUtils, LazFileUtils, MultiLog, base64, sqlite3conn, - sqldb, db; - -type - - TAccountStatus = (asUnknown, asChecking, asValid, asInvalid); - - { TAccountManager } - - TAccountManager = class - private - locklocate: TRTLCriticalSection; - fconn: TSQLite3Connection; - ftrans: TSQLTransaction; - fquery: TSQLQuery; - ffilename: String; - frecordcount: Integer; - function CreateDB: Boolean; - function InternalOpenDB: Boolean; - function CreateDBTable: Boolean; - function OpenDBTable: Boolean; - function FixStatus: Boolean; - procedure ConvertNewTable; - function GetValueString(const AName, AField: string): string; - function GetValueBoolean(const AName, AField: string): boolean; - function GetValueInteger(const AName, AField: string): Integer; - function GetValueStr(const RecIndex, FieldIndex: Integer): string; - function GetValueBool(const RecIndex, FieldIndex: Integer): boolean; - function GetValueInt(const RecIndex, FieldIndex: Integer): Integer; - function GetUsername(AName: string): string; - function GetEnabled(AName: string): boolean; - function GetPassword(AName: string): string; - function GetCookies(AName: string): string; - function GetStatus(AName: string): TAccountStatus; - procedure SetUsername(AName: string; AValue: string); - procedure SetEnabled(AName: string; AValue: boolean); - procedure SetPassword(AName: string; AValue: string); - procedure SetCookies(AName: string; AValue: string); - procedure SetStatus(AName: string; AValue: TAccountStatus); - procedure SetValueString(const AName, AField, AValue: string); - procedure SetValueBoolean(const AName, AField: string; AValue: boolean); - procedure SetValueInteger(const AName, AField: string; AValue: Integer); - procedure SetValueStr(const RecIndex, FieldIndex: Integer; AValue: string); - procedure SetValueBool(const RecIndex, FieldIndex: Integer; AValue: boolean); - procedure SetValueInt(const RecIndex, FieldIndex: Integer; AValue: Integer); - procedure GetRecordCount; - procedure Vacuum; - public - constructor Create(const AFilename: string); - destructor Destroy; override; - procedure Save; - function AddAccount(const AName, AUsername, APassword: string): Boolean; - function DeleteAccount(const AName: string): Boolean; - function DeleteAccount(const RecIndex: Integer): Boolean; overload; - property Enabled[AName: string]: boolean read GetEnabled write SetEnabled; - property Username[AName: string]: string read GetUsername write SetUsername; - property Password[AName: string]: string read GetPassword write SetPassword; - property Cookies[AName: string]: string read GetCookies write SetCookies; - property Status[AName: string]: TAccountStatus read GetStatus write SetStatus; - property ValueStr[const RecIndex, FieldIndex: Integer]: string read GetValueStr write SetValueStr; - property ValueBool[const RecIndex, FieldIndex: Integer]: boolean read GetValueBool write SetValueBool; - property ValueInt[const RecIndex, FieldIndex: Integer]: Integer read GetValueInt write SetValueInt; - property Count: Integer read frecordcount; - end; - - procedure InitAccountManager(const AFilename: string); - -var - Account: TAccountManager; - -implementation - -const - ctablename = 'accounts'; - ctbaccountscreateparams = '('#13#10 + - '"enabled" BOOL,'#13#10 + - '"aname" VARCHAR NOT NULL PRIMARY KEY,'#13#10 + - '"username" TEXT,'#13#10 + - '"password" TEXT,'#13#10 + - '"cookies" TEXT,'#13#10 + - '"status" INTEGER'#13#10 + - ');'; - -function QuotedStrd(const S: string): string; -begin - Result := AnsiQuotedStr(S, '"'); -end; - -procedure InitAccountManager(const AFilename: string); -begin - Account := TAccountManager.Create(AFilename); -end; - -function encode(const s: string): string; -begin - if s = '' then Exit(''); - Result := EncodeStringBase64(s); -end; - -function decode(const s: string): string; -begin - if s = '' then Exit(''); - Result := DecodeStringBase64(s); -end; - -{ TAccountManager } - -function TAccountManager.GetUsername(AName: string): string; -begin - Result := GetValueString(AName, 'username'); -end; - -function TAccountManager.GetEnabled(AName: string): boolean; -begin - Result := GetValueBoolean(AName, 'enabled'); -end; - -function TAccountManager.GetPassword(AName: string): string; -begin - Result := decode(GetValueString(AName, 'password')); -end; - -function TAccountManager.GetCookies(AName: string): string; -begin - Result := decode(GetValueString(AName, 'cookies')); -end; - -function TAccountManager.GetStatus(AName: string): TAccountStatus; -begin - Result := TAccountStatus(GetValueInteger(AName, 'status')); -end; - -function TAccountManager.GetValueStr(const RecIndex, FieldIndex: Integer - ): string; -begin - Result := ''; - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - try - fquery.RecNo := RecIndex + 1; - Result := fquery.Fields[FieldIndex].AsString; - if (FieldIndex = 3) or (FieldIndex = 4) then Result := decode(Result); - except - end; -end; - -function TAccountManager.GetValueBool(const RecIndex, FieldIndex: Integer - ): boolean; -begin - Result := False; - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - try - fquery.RecNo := RecIndex + 1; - Result := fquery.Fields[FieldIndex].AsBoolean; - except - end; -end; - -function TAccountManager.GetValueInt(const RecIndex, FieldIndex: Integer - ): Integer; -begin - Result := 0; - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - try - fquery.RecNo := RecIndex + 1; - Result := fquery.Fields[FieldIndex].AsInteger; - except - end; -end; - -procedure TAccountManager.SetUsername(AName: string; AValue: string); -begin - SetValueString(AName, 'username', AValue); -end; - -procedure TAccountManager.SetEnabled(AName: string; AValue: boolean); -begin - SetValueBoolean(AName, 'enabled', AValue); -end; - -procedure TAccountManager.SetPassword(AName: string; AValue: string); -begin - SetValueString(AName, 'password', encode(AValue)); -end; - -procedure TAccountManager.SetCookies(AName: string; AValue: string); -begin - SetValueString(AName, 'cookies', encode(AValue)); -end; - -procedure TAccountManager.SetStatus(AName: string; AValue: TAccountStatus); -begin - SetValueString(AName, 'status', IntToStr(Integer(AValue))); -end; - -function TAccountManager.CreateDB: Boolean; -begin - Result := False; - if ffilename = '' then Exit; - if FileExistsUTF8(ffilename) then DeleteFileUTF8(ffilename); - CreateDBTable; -end; - -function TAccountManager.InternalOpenDB: Boolean; -begin - Result := False; - if ffilename = '' then Exit; - try - fconn.DatabaseName := ffilename; - fconn.Connected := True; - ftrans.Active := True; - Result := fconn.Connected; - except - on E: Exception do - Logger.SendException('TAccountManager.InternalOpenDB.Failed, ' + ffilename, E); - end; -end; - -function TAccountManager.CreateDBTable: Boolean; -begin - Result := False; - if InternalOpenDB = False then Exit; - try - fconn.ExecuteDirect('DROP TABLE IF EXISTS ' + AnsiQuotedStr(ctablename, '"')); - fconn.ExecuteDirect('CREATE TABLE ' + AnsiQuotedStr(ctablename, '"') + #13#10 + ctbaccountscreateparams); - ftrans.Commit; - OpenDBTable; - Result := True; - except - on E: Exception do - Logger.SendException('TAccountManager.CreateDBTable.Failed, ' + ffilename, E); - end; -end; - -function TAccountManager.OpenDBTable: Boolean; -begin - Result := False; - if InternalOpenDB = False then Exit; - try - if fquery.Active then fquery.Close; - fquery.SQL.Text := 'SELECT * FROM ' + AnsiQuotedStr(ctablename, '"'); - fquery.Open; - FixStatus; - GetRecordCount; - Result := fquery.Active; - except - on E: Exception do - Logger.SendException('TAccountManager.OpenDBTable.Failed, ' + ffilename, E); - end; - if Result then ConvertNewTable; -end; - -function TAccountManager.FixStatus: Boolean; -begin - Result := False; - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.RecordCount > 0 then begin - fquery.First; - while not fquery.EOF do begin - if fquery.FieldByName('status').AsInteger = Integer(asChecking) then begin - fquery.Edit; - fquery.FieldByName('status').AsInteger := Integer(asUnknown); - fquery.Post; - end; - fquery.Next; - end; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.ConvertNewTable; -begin - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if (FieldTypeNames[fquery.FieldByName('username').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[fquery.FieldByName('password').DataType] <> Fieldtypenames[ftMemo]) or - (FieldTypeNames[fquery.FieldByName('cookies').DataType] <> Fieldtypenames[ftMemo]) then - try - fquery.Close; - with fconn do begin - ExecuteDirect('DROP TABLE IF EXISTS '+QuotedStr('temp'+ctablename)); - ExecuteDirect('CREATE TABLE '+QuotedStrd('temp'+ctablename)+#13#10+ctbaccountscreateparams); - ExecuteDirect('INSERT INTO '+QuotedStrd('temp'+ctablename)+' SELECT * FROM '+QuotedStrd(ctablename)); - ExecuteDirect('DROP TABLE '+QuotedStrd(ctablename)); - ExecuteDirect('ALTER TABLE '+QuotedStrd('temp'+ctablename)+' RENAME TO '+QuotedStrd(ctablename)); - end; - ftrans.Commit; - fquery.Open; - except - ftrans.Rollback; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -function TAccountManager.GetValueString(const AName, AField: string): string; -begin - Result := ''; - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsString - else Result := ''; - finally - LeaveCriticalsection(locklocate); - end; -end; - -function TAccountManager.GetValueBoolean(const AName, AField: string): boolean; -begin - Result := False; - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsBoolean - else Result := False; - finally - LeaveCriticalsection(locklocate); - end; -end; - -function TAccountManager.GetValueInteger(const AName, AField: string): Integer; -begin - Result := 0; - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.Locate('aname', AName, []) then Result := fquery.FieldByName(AField).AsInteger; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.SetValueStr(const RecIndex, FieldIndex: Integer; - AValue: string); -begin - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - EnterCriticalsection(locklocate); - try - fquery.RecNo := RecIndex + 1; - fquery.Edit; - if (FieldIndex = 3) or (FieldIndex = 4) then - fquery.Fields[FieldIndex].AsString := encode(AValue) - else - fquery.Fields[FieldIndex].AsString := decode(AValue); - try - fquery.Post; - except - fquery.Cancel; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.SetValueBool(const RecIndex, FieldIndex: Integer; - AValue: boolean); -begin - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - EnterCriticalsection(locklocate); - try - fquery.RecNo := RecIndex + 1; - fquery.Edit; - fquery.Fields[FieldIndex].AsBoolean := AValue; - try - fquery.Post; - except - fquery.Cancel; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.SetValueInt(const RecIndex, FieldIndex: Integer; - AValue: Integer); -begin - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - EnterCriticalsection(locklocate); - try - fquery.RecNo := RecIndex + 1; - fquery.Edit; - fquery.Fields[FieldIndex].AsInteger := AValue; - try - fquery.Post; - except - fquery.Cancel; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.SetValueString(const AName, AField, AValue: string); -begin - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.Locate('aname', AName, []) then begin - fquery.Edit; - fquery.FieldByName(AField).AsString := AValue; - try - fquery.Post; - except - fquery.Cancel; - end; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.SetValueBoolean(const AName, AField: string; - AValue: boolean); -begin - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.Locate('aname', AName, []) then begin - fquery.Edit; - fquery.FieldByName(AField).AsBoolean := AValue; - try - fquery.Post; - except - fquery.Cancel; - end; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.SetValueInteger(const AName, AField: string; - AValue: Integer); -begin - if fquery.Active = False then Exit; - EnterCriticalsection(locklocate); - try - if fquery.Locate('aname', AName, []) then begin - fquery.Edit; - fquery.FieldByName(AField).AsInteger := AValue; - try - fquery.Post; - except - fquery.Cancel; - end; - end; - finally - LeaveCriticalsection(locklocate); - end; -end; - -procedure TAccountManager.GetRecordCount; -begin - if fquery.Active then begin - fquery.Last; - frecordcount := fquery.RecordCount; - fquery.Refresh; - end - else frecordcount := 0; -end; - -procedure TAccountManager.Vacuum; -begin - if fconn.Connected = False then Exit; - fquery.Close; - fconn.ExecuteDirect('END TRANSACTION'); - try - fconn.ExecuteDirect('VACUUM'); - except - on E: Exception do - Logger.SendException('TAccountManager.Vacuum.Failed!', E); - end; - fconn.ExecuteDirect('BEGIN TRANSACTION'); - fquery.Open; -end; - -constructor TAccountManager.Create(const AFilename: string); -begin - InitCriticalSection(locklocate); - fconn := TSQLite3Connection.Create(nil); - ftrans := TSQLTransaction.Create(nil); - fquery := TSQLQuery.Create(nil); - fconn.CharSet := 'UTF8'; - fconn.Transaction := ftrans; - fquery.DataBase := ftrans.DataBase; - fquery.Transaction := ftrans; - fquery.Options := fquery.Options + [sqoAutoApplyUpdates]; - frecordcount := 0; - - ffilename := AFilename; - if not FileExistsUTF8(ffilename) then CreateDBTable - else OpenDBTable; -end; - -destructor TAccountManager.Destroy; -begin - if fconn.Connected then begin - Save; - Vacuum; - fquery.Close; - fconn.Close; - end; - fconn.Free; - fquery.Free; - ftrans.Free; - DoneCriticalsection(locklocate); - inherited Destroy; -end; - -procedure TAccountManager.Save; -begin - if fconn.Connected = False then Exit; - try - if fquery.Active then fquery.Close; - ftrans.Commit; - fquery.Open; - GetRecordCount; - except - on E: Exception do - Logger.SendException('TAccountManager.Save.Failed, ' + ffilename, E); - end; -end; - -function TAccountManager.AddAccount(const AName, AUsername, APassword: string - ): Boolean; -begin - Result := False; - if fconn.Connected = False then Exit; - try - with fquery do begin - Append; - FieldByName('enabled').AsBoolean := True; - FieldByName('aname').AsString := AName; - FieldByName('username').AsString := AUsername; - FieldByName('password').AsString := encode(APassword); - FieldByName('status').AsInteger := Integer(asUnknown); - Post; - end; - GetRecordCount; - Result := True; - except - on E: Exception do - Logger.SendException('TAccountManager.AddAccount.Failed, ' + AName, E); - end; -end; - -function TAccountManager.DeleteAccount(const AName: string): Boolean; -begin - Result := False; - if fquery.Active = False then Exit; - try - with fquery do begin - if Locate('aname', AName, []) then begin - Delete; - GetRecordCount; - Result := True; - end; - end; - except - on E: Exception do - Logger.SendException('TAccountManager.DeleteAccount.Failed, ' + AName, E); - end; -end; - -function TAccountManager.DeleteAccount(const RecIndex: Integer): Boolean; -begin - Result := False; - if fquery.Active = False then Exit; - if (RecIndex > frecordcount) and (RecIndex < 0) then Exit; - try - with fquery do begin - RecNo := RecIndex + 1; - Delete; - GetRecordCount; - Result := True; - end; - except - on E: Exception do - Logger.SendException('TAccountManager.DeleteAccount.Failed, ' + IntToStr(RecIndex), E); - end; -end; - -finalization - if Assigned(Account) then Account.Free; - -end. diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 25bd5b0b1..26cc65acf 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, httpsendthread, synautil, synacode, + XQueryEngineHTML, httpsendthread, synautil, synacode, RegExpr, LazFileUtils; implementation @@ -46,38 +46,37 @@ function ExHentaiLogin(const AHTTP: THTTPSendThread; const Module: TModuleContai begin Result := False; if AHTTP = nil then Exit; - if Account.Enabled[accname] = False then Exit; + if Module.Account.Enabled = False then Exit; if TryEnterCriticalsection(locklogin) > 0 then with AHTTP do begin onlogin := True; - Account.Status[accname] := asChecking; + Module.Account.Status := asChecking; Reset; Cookies.Clear; s := 'returntype=8&CookieDate=1&b=d&bt=pone' + - '&UserName=' + EncodeURLElement(Account.Username[accname]) + - '&PassWord=' + EncodeURLElement(Account.Password[accname]) + + '&UserName=' + EncodeURLElement(Module.Account.Username) + + '&PassWord=' + EncodeURLElement(Module.Account.Password) + '&ipb_login_submit=Login%21'; if POST(exhentaiurllogin, s) then begin if ResultCode = 200 then begin Result := Cookies.Values['ipb_pass_hash'] <> ''; if Result then begin - Account.Cookies[accname] := GetCookies; - Account.Status[accname] := asValid; + Module.Account.Cookies := GetCookies; + Module.Account.Status := asValid; end - else Account.Status[accname] := asInvalid; - Account.Save; + else Module.Account.Status := asInvalid; end; end; onlogin := False; - if Account.Status[accname] = asChecking then - Account.Status[accname] := asUnknown; + if Module.Account.Status = asChecking then + Module.Account.Status := asUnknown; LeaveCriticalsection(locklogin); end else begin while onlogin do Sleep(1000); - if Result then AHTTP.Cookies.Text := Account.Cookies[accname]; + if Result then AHTTP.Cookies.Text := Module.Account.Cookies; end; end; @@ -86,7 +85,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String; const Mo ACookies: String; begin Result := False; - if Account.Enabled[accname] then begin + if Module.Account.Enabled then begin AHTTP.FollowRedirection := False; // force no warning AHTTP.Cookies.Values['nw'] := '1'; @@ -94,7 +93,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String; const Mo ACookies := AHTTP.Cookies.Text else ACookies := ''; - AHTTP.Cookies.AddText(Account.Cookies[accname]); + AHTTP.Cookies.AddText(Module.Account.Cookies); Result := AHTTP.GET(AURL); if Result and (AHTTP.ResultCode > 300) then begin Result := ExHentaiLogin(AHTTP, Module); @@ -319,7 +318,7 @@ function DownloadImage(const DownloadThread: TDownloadThread; s := StreamToString(DownloadThread.FHTTP.Document); query.ParseHTML(DownloadThread.FHTTP.Document); iurl := ''; - if (settingsimagesize > High(settingsimagesizestr)) and (Account.Status[accname] = asValid) then + if (settingsimagesize > High(settingsimagesizestr)) and (Module.Account.Status = asValid) then iurl := query.XPathString('//a/@href[contains(.,"/fullimg.php")]'); if iurl = '' then iurl := query.XPathString('//*[@id="img"]/@src'); diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 649891618..435a43ad8 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - accountmanagerdb, XQueryEngineHTML, httpsendthread, synacode, RegExpr, fpjson; + XQueryEngineHTML, httpsendthread, synacode, RegExpr, fpjson; implementation @@ -38,27 +38,26 @@ implementation function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; begin Result := False; - if Account.Enabled[modulename] = False then Exit; - if Account.Username[modulename] = '' then Exit; + if Module.Account.Enabled = False then Exit; + if Module.Account.Username = '' then Exit; if TryEnterCriticalsection(locklogin) > 0 then try - Account.Status[modulename] := asChecking; + Module.Account.Status := asChecking; AHTTP.Reset; AHTTP.Cookies.Clear; - madokamiauth := 'Authorization: Basic ' + Base64Encode(Account.Username[modulename] + ':' + Account.Password[modulename]); + madokamiauth := 'Authorization: Basic ' + Base64Encode(Module.Account.Username); AHTTP.Headers.Add(madokamiauth); if AHTTP.GET(urlroot) then begin //Result := AHTTP.Cookies.Values['laravel_session'] <> ''; Result := (AHTTP.ResultCode < 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ''); if Result then begin - Account.Cookies[modulename] := AHTTP.GetCookies; - Account.Status[modulename] := asValid; + Module.Account.Cookies := AHTTP.GetCookies; + Module.Account.Status := asValid; end else begin - Account.Cookies[modulename] := ''; - Account.Status[modulename] := asInvalid; + Module.Account.Cookies := ''; + Module.Account.Status := asInvalid; end; - Account.Save; end; finally LeaveCriticalsection(locklogin); @@ -67,7 +66,7 @@ function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Bo EnterCriticalsection(locklogin); try if Result then - AHTTP.Cookies.Text := Account.Cookies[modulename]; + AHTTP.Cookies.Text := Module.Account.Cookies; finally LeaveCriticalsection(locklogin); end; @@ -75,13 +74,13 @@ function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Bo AHTTP.Reset; end; -procedure SetAuth(const AHTTP: THTTPSendThread); +procedure SetAuth(const AHTTP: THTTPSendThread; const Module: TModuleContainer); begin - AHTTP.Cookies.Text := Account.Cookies[modulename]; + AHTTP.Cookies.Text := Module.Account.Cookies; if AHTTP.Cookies.Count <> 0 then begin if madokamiauth = '' then - madokamiauth := 'Authorization: Basic ' + Base64Encode(Account.Username[modulename] + ':' + Account.Password[modulename]); + madokamiauth := 'Authorization: Basic ' + Base64Encode(Module.Account.Username); AHTTP.Headers.Add(madokamiauth); end; end; @@ -89,7 +88,7 @@ procedure SetAuth(const AHTTP: THTTPSendThread); function GETWithLogin(const AHTTP: THTTPSendThread; AURL: String; const Module: TModuleContainer): Boolean; begin Result := False; - SetAuth(AHTTP); + SetAuth(AHTTP, Module); AHTTP.FollowRedirection := False; Result := AHTTP.GET(AURL); if ((AHTTP.ResultCode > 400) and (AHTTP.Headers.Values['WWW-Authenticate'] = ' Basic')) or @@ -116,7 +115,7 @@ function BeforeUpdateList(const Module: TModuleContainer): Boolean; i: Integer; begin Result := True; - accountexist := Account.Username[modulename] <> ''; + accountexist := Module.Account.Username <> ''; if not accountexist then Exit; ClearMadokamiUlist; SetLength(madokamiulist, Length(madokamilist)); diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 30143e0f7..781815ab7 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, accountmanagerdb, httpsendthread, synacode; + XQueryEngineHTML, httpsendthread, synacode; implementation @@ -27,15 +27,15 @@ function MangaTradersLogin(const AHTTP: THTTPSendThread; const Module: TModuleCo s: String; begin Result := False; - if Account.Enabled[MMangaTraders.Website] = False then Exit; + if Module.Account.Enabled = False then Exit; if TryEnterCriticalsection(MangaTradersLockLogin) > 0 then try MangaTradersOnLogin := True; - Account.Status[MMangaTraders.Website] := asChecking; + Module.Account.Status := asChecking; SendLog('MangaTraders: post login'); s := - 'EmailAddress=' + EncodeURLElement(Account.Username[MMangaTraders.Website]) + - '&Password=' + EncodeURLElement(Account.Password[MMangaTraders.Website]) + + 'EmailAddress=' + EncodeURLElement(Module.Account.Username) + + '&Password=' + EncodeURLElement(Module.Account.Password) + '&RememberMe=1'; AHTTP.Headers.Clear; if AHTTP.POST(MMangaTraders.RootURL + '/auth/process.login.php', s) then @@ -44,15 +44,15 @@ function MangaTradersLogin(const AHTTP: THTTPSendThread; const Module: TModuleCo SendLog('MangaTraders: login result = ' + s); if LowerCase(s) = 'ok' then begin - Account.Status[MMangaTraders.Website] := asValid; - Account.Cookies[MMangaTraders.Website] := AHTTP.Cookies.Text; + Module.Account.Status := asValid; + Module.Account.Cookies := AHTTP.Cookies.Text; end else - Account.Status[MMangaTraders.Website] := asInvalid; + Module.Account.Status := asInvalid; end else - Account.Status[MMangaTraders.Website] := asUnknown; - Result := Account.Status[MMangaTraders.Website] = asValid; + Module.Account.Status := asUnknown; + Result := Module.Account.Status = asValid; finally MangaTradersOnLogin := False; LeaveCriticalsection(MangaTradersLockLogin); @@ -60,9 +60,9 @@ function MangaTradersLogin(const AHTTP: THTTPSendThread; const Module: TModuleCo else begin while MangaTradersOnLogin do Sleep(1000); - Result := Account.Status[MMangaTraders.Website] = asValid; + Result := Module.Account.Status = asValid; if Result then - AHTTP.Cookies.Text := Account.Cookies[MMangaTraders.Website]; + AHTTP.Cookies.Text := Module.Account.Cookies; end; end; @@ -71,11 +71,11 @@ function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String; const accstat: TAccountStatus; begin Result := False; - if Account.Enabled[MMangaTraders.Website] then + if Module.Account.Enabled then begin - accstat := Account.Status[MMangaTraders.Website]; + accstat := Module.Account.Status; if accstat = asValid then - AHTTP.Cookies.AddText(Account.Cookies[MMangaTraders.Website]) + AHTTP.Cookies.AddText(Module.Account.Cookies) else if accstat in [asChecking, asUnknown] then Result := MangaTradersLogin(AHTTP, Module); diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index f57d72744..16d8e9cdc 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Buttons, - ExtCtrls, VirtualTrees, accountmanagerdb, WebsiteModules, + ExtCtrls, VirtualTrees, WebsiteModules, FMDOptions, HTTPSendThread, BaseThread, frmAccountSet, SimpleException; type diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index cbaaf385d..990b7b1b2 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -23,7 +23,7 @@ interface uFavoritesManager, uUpdateThread, uSilentThread, uMisc, uGetMangaInfosThread, frmDropTarget, frmAccountManager, frmWebsiteOptionCustom, frmCustomColor, frmLogger, frmTransferFavorites, - frmLuaModulesUpdater, CheckUpdate, accountmanagerdb, DBDataProcess, MangaFoxWatermark, + frmLuaModulesUpdater, CheckUpdate, DBDataProcess, MangaFoxWatermark, SimpleTranslator, FMDOptions, httpsendthread, SimpleException; type @@ -1136,9 +1136,6 @@ procedure TMainForm.FormCreate(Sender: TObject); TrayIcon.Icon.Assign(Application.Icon); PrevWindowState := wsNormal; - // account - accountmanagerdb.InitAccountManager(ACCOUNTS_FILE); - // main dataprocess dataProcess := TDBDataProcess.Create; From 9df9d12a63f752f726f15488600c9263bc7afa47 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 09:55:17 +0300 Subject: [PATCH 2385/2794] WebsiteSettings, add scroll box #1020 --- mangadownloader/forms/frmWebsiteSettings.lfm | 9 ++-- mangadownloader/forms/frmWebsiteSettings.pas | 48 +++++++++++--------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index 504c20c43..1f0b9c09a 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -114,14 +114,16 @@ object WebsiteSettingsForm: TWebsiteSettingsForm Width = 417 ClientWidth = 417 ClientHeight = 432 - object pnProps: TPanel + object sbProps: TScrollBox Left = 0 Height = 432 Top = 0 Width = 417 + HorzScrollBar.Page = 1 + HorzScrollBar.Visible = False + VertScrollBar.Page = 1 Align = alClient - BevelOuter = bvNone - TabOrder = 0 + BorderStyle = bsNone ChildSizing.LeftRightSpacing = 5 ChildSizing.TopBottomSpacing = 5 ChildSizing.HorizontalSpacing = 20 @@ -129,6 +131,7 @@ object WebsiteSettingsForm: TWebsiteSettingsForm ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 2 + TabOrder = 0 end end end diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index d6a188490..2805144bf 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -16,14 +16,14 @@ interface TSettingsView = class private FSettings: TWebsiteModuleSettings; - FOwner: TPanel; + FOwner: TWinControl; FControls: TFPObjectList; procedure SetData(settings: TWebsiteModuleSettings); function GetData: TWebsiteModuleSettings; procedure CreateControls; procedure UpdateView; public - constructor Create(owner: TPanel); + constructor Create(owner: TWinControl); destructor Destroy; override; property Data: TWebsiteModuleSettings read GetData write SetData; end; @@ -32,7 +32,7 @@ TSettingsView = class TWebsiteSettingsForm = class(TForm) edSearch: TEditButton; - pnProps: TPanel; + sbProps: TScrollBox; spMain: TPairSplitter; spList: TPairSplitterSide; spProps: TPairSplitterSide; @@ -68,7 +68,7 @@ implementation procedure TWebsiteSettingsForm.FormCreate(Sender: TObject); begin AddVT(vtWebsite); - settingsView := TSettingsView.Create(pnProps); + settingsView := TSettingsView.Create(sbProps); end; procedure TWebsiteSettingsForm.edSearchChange(Sender: TObject); @@ -139,7 +139,7 @@ procedure TWebsiteSettingsForm.LoadWebsiteSettings; { TSettingsView } -constructor TSettingsView.Create(owner: TPanel); +constructor TSettingsView.Create(owner: TWinControl); begin FOwner := owner; FControls := TFPObjectList.Create(True); @@ -169,7 +169,7 @@ procedure TSettingsView.CreateControls; const LEFT_OFFSET = 250; - function AddLabel(text: String; prev: TControl): TLabel; + function AddLabel(text: String): TLabel; begin Result := TLabel.Create(FOwner); Result.Parent := FOwner; @@ -179,18 +179,19 @@ procedure TSettingsView.CreateControls; function AddEdit(name, text: String; prev: TControl): TTIEdit; begin - AddLabel(text, prev); + AddLabel(text); Result := TTIEdit.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; Result.Width := 300; + Result.Enabled := False; FControls.Add(Result); end; function AddSpinEdit(name, text: String; min, max: Integer; prev: TControl): TTISpinEdit; begin - AddLabel(text, prev); + AddLabel(text); Result := TTISpinEdit.Create(FOwner); Result.MinValue := min; Result.MaxValue := max; @@ -198,17 +199,20 @@ procedure TSettingsView.CreateControls; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; Result.Width := 100; + Result.Enabled := False; FControls.Add(Result); end; function AddComboBox(name, text: String; prev: TControl): TTIComboBox; begin - AddLabel(text, prev); + AddLabel(text); Result := TTIComboBox.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; Result.Width := 200; + result.Style := csDropDownList; + Result.Enabled := False; FControls.Add(Result); end; @@ -222,19 +226,16 @@ procedure TSettingsView.CreateControls; typeData := GetTypeData(TWebsiteModuleSettings.ClassInfo); GetMem(propList, typeData^.PropCount * SizeOf(Pointer)); cnt := GetPropList(TWebsiteModuleSettings.ClassInfo, propList); - for i := 0 to cnt-1 do begin - case propList^[i]^.PropType^.Kind of - tkInteger: begin - prev := AddSpinEdit(propList^[i]^.Name, propList^[i]^.Name, 1, High(Integer), prev); + for i := 0 to cnt-1 do + with propList^[i]^ do + case PropType^.Kind of + tkInteger: + prev := AddSpinEdit(Name, Name, 1, High(Integer), prev); + tkAString: + prev := AddEdit(Name, Name, prev); + tkEnumeration: + prev := AddComboBox(Name, Name, prev); end; - tkAString: begin - prev := AddEdit(propList^[i]^.Name, propList^[i]^.Name, prev); - end; - tkEnumeration: begin - prev := AddComboBox(propList^[i]^.Name, propList^[i]^.Name, prev); - end; - end; - end; FreeMem(propList); end; @@ -242,13 +243,16 @@ procedure TSettingsView.UpdateView; var i: Integer; begin - for i := 0 to FControls.Count-1 do + for i := 0 to FControls.Count-1 do begin if FControls[i] is TTIEdit then TTIEdit(FControls[i]).Link.TIObject := FSettings else if FControls[i] is TTISpinEdit then TTISpinEdit(FControls[i]).Link.TIObject := FSettings else if FControls[i] is TTIComboBox then TTIComboBox(FControls[i]).Link.TIObject := FSettings; + if Assigned(FSettings) then + TControl(FControls[i]).Enabled := True; + end; end; end. From a6dcd59ce4789bced832da83e7b8bcde243d430b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 10:47:17 +0300 Subject: [PATCH 2386/2794] MangaHubIO, fix download fixes #1033 --- lua/modules/MangaHubIO.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaHubIO.lua b/lua/modules/MangaHubIO.lua index 07fb49e60..92734bce1 100644 --- a/lua/modules/MangaHubIO.lua +++ b/lua/modules/MangaHubIO.lua @@ -40,7 +40,7 @@ end function getpagenumber() task.pagelinks.clear() - local chapter = url:match('/chapter%-(%d+)') + local chapter = url:match('/chapter%-(.+)$'):gsub('/$', '') local slug = url:match('/chapter/(.+)/') local q = '{"query":"{chapter(x:'..getx()..',slug:\\"'..slug..'\\",number:'..chapter..'){id,title,mangaID,number,slug,date,pages,manga{id,title,slug,mainSlug,isWebtoon,isYaoi}}}"}' http.mimetype = 'application/json' From d991e455340d9fa82fcded3cd02d0c6cdb1d1b22 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 12:36:45 +0300 Subject: [PATCH 2387/2794] WebsiteSettings, use anchors --- mangadownloader/forms/frmWebsiteSettings.lfm | 7 -- mangadownloader/forms/frmWebsiteSettings.pas | 89 ++++++++++++++++++-- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index 1f0b9c09a..60c250872 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -124,13 +124,6 @@ object WebsiteSettingsForm: TWebsiteSettingsForm VertScrollBar.Page = 1 Align = alClient BorderStyle = bsNone - ChildSizing.LeftRightSpacing = 5 - ChildSizing.TopBottomSpacing = 5 - ChildSizing.HorizontalSpacing = 20 - ChildSizing.VerticalSpacing = 7 - ChildSizing.EnlargeHorizontal = crsHomogenousChildResize - ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 2 TabOrder = 0 end end diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 2805144bf..5ae266ccf 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -167,31 +167,67 @@ function TSettingsView.GetData: TWebsiteModuleSettings; procedure TSettingsView.CreateControls; -const LEFT_OFFSET = 250; + procedure SetAnchor(control, lbl, prev: TControl); + begin + control.Anchors := [akTop, akLeft, akRight]; + if prev <> nil then begin + control.AnchorSide[akTop].Control := prev; + control.AnchorSide[akTop].Side := asrBottom; + control.BorderSpacing.Top := 10; + end + else begin + control.AnchorSide[akTop].Control := lbl; + control.AnchorSide[akTop].Side := asrCenter; + end; + control.AnchorSide[akRight].Control := FOwner; + control.AnchorSide[akRight].Side := asrRight; + control.BorderSpacing.Right := 10; + control.BorderSpacing.Left := 50; + end; - function AddLabel(text: String): TLabel; + function AddLabel(text: String; prev: TControl): TLabel; begin Result := TLabel.Create(FOwner); Result.Parent := FOwner; Result.Caption := text; + Result.AnchorSide[akLeft].Control := FOwner; + Result.AnchorSide[akLeft].Side := asrLeft; + Result.BorderSpacing.Left := 5; + if prev <> nil then begin + Result.AnchorSide[akTop].Control := prev; + Result.AnchorSide[akTop].Side := asrBottom; + Result.BorderSpacing.Top := 10; + end + else + Result.Top := 5; FControls.Add(Result); end; function AddEdit(name, text: String; prev: TControl): TTIEdit; + var + lbl: TLabel; + btn: TButton; begin - AddLabel(text); + lbl := AddLabel(text, prev); + {btn := TButton.Create(FOwner); + btn.Parent := FOwner; + btn.Caption := '...'; + btn.AutoSize := True; + btn.Enabled := False;} Result := TTIEdit.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; Result.Link.TIPropertyName := name; Result.Width := 300; Result.Enabled := False; + SetAnchor(Result, lbl, prev); FControls.Add(Result); end; function AddSpinEdit(name, text: String; min, max: Integer; prev: TControl): TTISpinEdit; + var lbl: TLabel; begin - AddLabel(text); + lbl := AddLabel(text, prev); Result := TTISpinEdit.Create(FOwner); Result.MinValue := min; Result.MaxValue := max; @@ -200,12 +236,15 @@ procedure TSettingsView.CreateControls; Result.Link.TIPropertyName := name; Result.Width := 100; Result.Enabled := False; + SetAnchor(Result, lbl, prev); + Result.Anchors := [akTop, akLeft]; FControls.Add(Result); end; function AddComboBox(name, text: String; prev: TControl): TTIComboBox; + var lbl: TLabel; begin - AddLabel(text); + lbl := AddLabel(text, prev); Result := TTIComboBox.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; @@ -213,6 +252,23 @@ procedure TSettingsView.CreateControls; Result.Width := 200; result.Style := csDropDownList; Result.Enabled := False; + SetAnchor(Result, lbl, prev); + Result.Anchors := [akTop, akLeft]; + FControls.Add(Result); + end; + + function AddCheckBox(name, text: String; prev: TControl): TTICheckBox; + var lbl: TLabel; + begin + lbl := AddLabel(text, prev); + Result := TTICheckBox.Create(FOwner); + Result.Parent := FOwner; + Result.Link.TIObject := FSettings; + Result.Link.TIPropertyName := name; + Result.Caption := ''; + Result.Enabled := False; + SetAnchor(Result, lbl, prev); + Result.Anchors := [akTop, akLeft]; FControls.Add(Result); end; @@ -221,6 +277,8 @@ procedure TSettingsView.CreateControls; propList: PPropList; typeData: PTypeData; cnt, i: Integer; + maxLabelWidth: Integer = -1; + maxLabel: TLabel; begin typeData := GetTypeData(TWebsiteModuleSettings.ClassInfo); @@ -235,8 +293,25 @@ procedure TSettingsView.CreateControls; prev := AddEdit(Name, Name, prev); tkEnumeration: prev := AddComboBox(Name, Name, prev); + tkBool: + prev := AddCheckBox(Name, Name, prev); end; FreeMem(propList); + + for i := 0 to FControls.Count - 1 do + if (FControls[i] is TLabel) then + with TLabel(FControls[i]) do + if maxLabelWidth < Canvas.TextWidth(Caption) then begin + maxLabelWidth := Canvas.TextWidth(Caption); + maxLabel := TLabel(FControls[i]); + end; + + for i := 0 to FControls.Count - 1 do + if not (FControls[i] is TLabel) and not (FControls[i] is TButton) then + with TControl(FControls[i]) do begin + AnchorSide[akLeft].Control := maxLabel; + AnchorSide[akLeft].Side := asrRight; + end; end; procedure TSettingsView.UpdateView; @@ -249,7 +324,9 @@ procedure TSettingsView.UpdateView; else if FControls[i] is TTISpinEdit then TTISpinEdit(FControls[i]).Link.TIObject := FSettings else if FControls[i] is TTIComboBox then - TTIComboBox(FControls[i]).Link.TIObject := FSettings; + TTIComboBox(FControls[i]).Link.TIObject := FSettings + else if FControls[i] is TTICheckBox then + TTICheckBox(FControls[i]).Link.TIObject := FSettings; if Assigned(FSettings) then TControl(FControls[i]).Enabled := True; end; From 92826328ddb9360225031cb80d97257e1035e475 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 13:28:03 +0300 Subject: [PATCH 2388/2794] WebsiteSettings, add editor button --- mangadownloader/forms/frmWebsiteSettings.pas | 46 +++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 5ae266ccf..7f3fd6fd1 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -22,6 +22,7 @@ TSettingsView = class function GetData: TWebsiteModuleSettings; procedure CreateControls; procedure UpdateView; + procedure OnEditorButtonClick(Sender: TObject); public constructor Create(owner: TWinControl); destructor Destroy; override; @@ -59,7 +60,7 @@ TWebsiteSettingsForm = class(TForm) implementation -uses frmCustomColor, typinfo; +uses frmCustomColor, typinfo, StringsPropEditDlg; {$R *.lfm} @@ -165,6 +166,32 @@ function TSettingsView.GetData: TWebsiteModuleSettings; Result := FSettings; end; +procedure TSettingsView.OnEditorButtonClick(Sender: TObject); + + function FindEditor: TTIEdit; + var + i: Integer; + begin + for i := 0 to FControls.Count - 2 do + if Sender = FControls[i] then begin + Result := TTIEdit(FControls[i+1]); + Exit; + end; + end; + +var + editor: TTIEdit; + form: TStringsPropEditorFrm; +begin + if not Assigned(FSettings) then Exit; + form := TStringsPropEditorFrm.Create(FOwner); + editor := FindEditor; + form.Memo.Text := editor.Link.GetAsText; + if form.ShowModal = mrOK then + editor.Link.SetAsText(form.Memo.Text); + form.Free; +end; + procedure TSettingsView.CreateControls; procedure SetAnchor(control, lbl, prev: TControl); @@ -179,8 +206,6 @@ procedure TSettingsView.CreateControls; control.AnchorSide[akTop].Control := lbl; control.AnchorSide[akTop].Side := asrCenter; end; - control.AnchorSide[akRight].Control := FOwner; - control.AnchorSide[akRight].Side := asrRight; control.BorderSpacing.Right := 10; control.BorderSpacing.Left := 50; end; @@ -209,11 +234,20 @@ procedure TSettingsView.CreateControls; btn: TButton; begin lbl := AddLabel(text, prev); - {btn := TButton.Create(FOwner); + + btn := TButton.Create(FOwner); btn.Parent := FOwner; btn.Caption := '...'; btn.AutoSize := True; - btn.Enabled := False;} + btn.Enabled := False; + btn.OnClick := @OnEditorButtonClick; + SetAnchor(btn, lbl, prev); + btn.Anchors := [akTop, akRight]; + btn.AnchorSide[akRight].Control := FOwner; + btn.AnchorSide[akRight].Side := asrRight; + btn.BorderSpacing.Left := 0; + FControls.Add(btn); + Result := TTIEdit.Create(FOwner); Result.Parent := FOwner; Result.Link.TIObject := FSettings; @@ -221,6 +255,8 @@ procedure TSettingsView.CreateControls; Result.Width := 300; Result.Enabled := False; SetAnchor(Result, lbl, prev); + Result.AnchorSide[akRight].Control := btn; + Result.AnchorSide[akRight].Side := asrLeft; FControls.Add(Result); end; From 6305c939eea89279aac1e6406da2188552187e1a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 19:36:12 +0800 Subject: [PATCH 2389/2794] accountmanager, double click to edit --- mangadownloader/forms/frmAccountManager.lfm | 1 + mangadownloader/forms/frmAccountManager.pas | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/mangadownloader/forms/frmAccountManager.lfm b/mangadownloader/forms/frmAccountManager.lfm index 6776dc5da..f74e52eda 100644 --- a/mangadownloader/forms/frmAccountManager.lfm +++ b/mangadownloader/forms/frmAccountManager.lfm @@ -163,6 +163,7 @@ object AccountManagerForm: TAccountManagerForm OnBeforeCellPaint = vtAccountListBeforeCellPaint OnChecked = vtAccountListChecked OnCompareNodes = vtAccountListCompareNodes + OnDblClick = vtAccountListDblClick OnGetText = vtAccountListGetText OnPaintText = vtAccountListPaintText OnHeaderClick = vtAccountListHeaderClick diff --git a/mangadownloader/forms/frmAccountManager.pas b/mangadownloader/forms/frmAccountManager.pas index 16d8e9cdc..165bb8424 100644 --- a/mangadownloader/forms/frmAccountManager.pas +++ b/mangadownloader/forms/frmAccountManager.pas @@ -29,6 +29,7 @@ TAccountManagerForm = class(TForm) ); procedure vtAccountListCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure vtAccountListDblClick(Sender: TObject); procedure vtAccountListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); @@ -330,5 +331,11 @@ procedure TAccountManagerForm.vtAccountListCompareNodes( end; end; +procedure TAccountManagerForm.vtAccountListDblClick(Sender: TObject); +begin + if vtAccountList.SelectedCount=0 then Exit; + btEditClick(btEdit); +end; + end. From 3ade65b6ad8f10f1ff0720eddd6460c53128ab55 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 20:03:42 +0800 Subject: [PATCH 2390/2794] websitemodules, add predefined maxtasklimit, maxthreadpertasklimi, maxconnectionlimit to tmodulecontainer the one in the setting is user defined settings. default value is defined by module --- baseunits/WebsiteModules.pas | 43 +++++++++++++++++++++++++---- baseunits/lua/LuaWebsiteModules.pas | 5 ++-- baseunits/modules/EHentai.pas | 4 +-- baseunits/modules/Mangadex.pas | 4 +-- baseunits/modules/RawSenManga.pas | 4 +-- baseunits/modules/SenManga.pas | 4 +-- baseunits/modules/Tumangaonline.pas | 4 +-- baseunits/uUpdateThread.pas | 2 +- 8 files changed, 51 insertions(+), 19 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 0b0d5c38d..e6a9fd388 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -152,6 +152,9 @@ TModuleContainer = class DynamicPageLink: Boolean; TotalDirectoryPage: array of Integer; CurrentDirectoryIndex: Integer; + MaxTaskLimit: Integer; + MaxThreadPerTaskLimit: Integer; + MaxConnectionLimit: Integer; OptionList: array of TWebsiteOptionItem; OnBeforeUpdateList: TOnBeforeUpdateList; OnAfterUpdateList: TOnAfterUpdateList; @@ -187,6 +190,10 @@ TModuleContainer = class procedure IncActiveConnectionCount; inline; procedure DecActiveConnectionCount; inline; + function GetMaxConnectionLimit: Integer; + function GetMaxTaskLimit: Integer; + function GetMaxThreadPerTaskLimit: Integer; + property Settings: TWebsiteModuleSettings read FSettings write FSettings; property AccountSupport: Boolean read FAccountSupport write SetAccountSupport; property Account: TWebsiteModuleAccount read FAccount write FAccount; @@ -495,6 +502,30 @@ procedure TModuleContainer.DecActiveConnectionCount; ActiveConnectionCount := InterLockedDecrement(ActiveConnectionCount); end; +function TModuleContainer.GetMaxConnectionLimit: Integer; +begin + if Settings.MaxConnectionLimit=0 then + Result:=MaxConnectionLimit + else + Result:=Settings.MaxConnectionLimit; +end; + +function TModuleContainer.GetMaxTaskLimit: Integer; +begin + if Settings.MaxTaskLimit=0 then + Result:=MaxTaskLimit + else + Result:=Settings.MaxTaskLimit; +end; + +function TModuleContainer.GetMaxThreadPerTaskLimit: Integer; +begin + if Settings.MaxThreadPerTaskLimit=0 then + Result:=MaxThreadPerTaskLimit + else + Result:=Settings.MaxThreadPerTaskLimit; +end; + procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; const ABindValue: Pointer; const AName: String; const ACaption: PString; const AItems: PString); @@ -878,8 +909,8 @@ function TWebsiteModules.CanCreateTask(ModuleId: Integer): Boolean; Result := True; if ModuleExist(ModuleId) then with FModuleList[ModuleId] do - if Settings.MaxTaskLimit > 0 then - Result := ActiveTaskCount < Settings.MaxTaskLimit; + if GetMaxTaskLimit > 0 then + Result := ActiveTaskCount < GetMaxTaskLimit; end; procedure TWebsiteModules.IncActiveConnectionCount(ModuleId: Integer); @@ -899,8 +930,8 @@ function TWebsiteModules.CanCreateConnection(ModuleId: Integer): Boolean; Result := True; if ModuleExist(ModuleId) then with FModuleList[ModuleId] do - if Settings.MaxConnectionLimit > 0 then - Result := ActiveConnectionCount < Settings.MaxConnectionLimit; + if GetMaxConnectionLimit > 0 then + Result := ActiveConnectionCount < GetMaxConnectionLimit; end; procedure TWebsiteModules.LoadFromFile; @@ -1034,7 +1065,7 @@ function TWebsiteModules.GetCount: Integer; function TWebsiteModules.GetMaxTaskLimit(const ModuleId: Integer): Integer; begin if not ModuleExist(ModuleId) then Exit(0); - Result := FModuleList[ModuleId].Settings.MaxTaskLimit; + Result := FModuleList[ModuleId].GetMaxTaskLimit; end; function TWebsiteModules.GetMaxThreadPerTaskLimit(const ModuleId: Integer @@ -1047,7 +1078,7 @@ function TWebsiteModules.GetMaxThreadPerTaskLimit(const ModuleId: Integer function TWebsiteModules.GetMaxConnectionLimit(const ModuleId: Integer): Integer; begin if not ModuleExist(ModuleId) then Exit(0); - Result := FModuleList[ModuleId].Settings.MaxConnectionLimit; + Result := FModuleList[ModuleId].GetMaxConnectionLimit; end; function TWebsiteModules.GetActiveTaskCount(const ModuleId: Integer): Integer; diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 18fa290b9..98f9648db 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -776,9 +776,10 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddStringProperty(L, MetaTable, 'Website', @Module.Website); luaClassAddStringProperty(L, MetaTable, 'RootURL', @Module.RootURL); luaClassAddStringProperty(L, MetaTable, 'Category', @Module.Category); - luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.Settings.MaxTaskLimit); + luaClassAddIntegerProperty(L, MetaTable, 'MaxTaskLimit', @Module.MaxTaskLimit); + luaClassAddIntegerProperty(L, MetaTable, 'MaxThreadPerTaskLimit', @Module.MaxThreadPerTaskLimit); luaClassAddIntegerProperty(L, MetaTable, 'MaxConnectionLimit', - @Module.Settings.MaxConnectionLimit); + @Module.MaxConnectionLimit); luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', @Module.ActiveTaskCount); luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', @Module.ActiveConnectionCount); diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 26cc65acf..716509410 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -407,8 +407,8 @@ procedure RegisterModule; Website := AWebsite; RootURL := ARootURL; Category := 'H-Sites'; - Settings.MaxTaskLimit := 1; - Settings.MaxConnectionLimit := 2; + MaxTaskLimit := 1; + MaxConnectionLimit := 2; SortedList := True; DynamicPageLink := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index bf902b563..f3b0b55bf 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -140,8 +140,8 @@ procedure RegisterModule; Website := 'Mangadex'; RootURL := 'https://mangadex.com'; Category := 'English'; - Settings.MaxTaskLimit := 4; - Settings.MaxConnectionLimit := 4; + MaxTaskLimit := 4; + MaxConnectionLimit := 4; TotalDirectory := Length(ALPHA_LIST_UP); OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/RawSenManga.pas b/baseunits/modules/RawSenManga.pas index c2cda8b97..5667aeb69 100644 --- a/baseunits/modules/RawSenManga.pas +++ b/baseunits/modules/RawSenManga.pas @@ -175,8 +175,8 @@ procedure RegisterModule; Website := 'RawSenManga'; RootURL := 'http://raw.senmanga.com'; Category := 'Raw'; - Settings.MaxTaskLimit := 1; - Settings.MaxConnectionLimit := 4; + MaxTaskLimit := 1; + MaxConnectionLimit := 4; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; diff --git a/baseunits/modules/SenManga.pas b/baseunits/modules/SenManga.pas index 6d1ee4981..20f729130 100644 --- a/baseunits/modules/SenManga.pas +++ b/baseunits/modules/SenManga.pas @@ -179,8 +179,8 @@ procedure RegisterModule; Website := 'SenManga'; RootURL := 'http://www.senmanga.com'; Category := 'English'; - Settings.MaxTaskLimit := 1; - Settings.MaxConnectionLimit := 4; + MaxTaskLimit := 1; + MaxConnectionLimit := 4; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas index 3aeb11524..9837be71a 100644 --- a/baseunits/modules/Tumangaonline.pas +++ b/baseunits/modules/Tumangaonline.pas @@ -174,8 +174,8 @@ procedure RegisterModule; Website := 'Tumangaonline'; RootURL := 'https://www.tumangaonline.com'; Category := 'Spanish'; - Settings.MaxTaskLimit := 1; - Settings.MaxConnectionLimit := 1; + MaxTaskLimit := 1; + MaxConnectionLimit := 1; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index e23b03cdf..1223ce1e7 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -405,7 +405,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; Exit; end; - if Module.Settings.MaxConnectionLimit > 0 then + if Module.GetMaxConnectionLimit > 0 then while (not Terminated) and (Module.ActiveConnectionCount >= numberOfThreads) do Sleep(SOCKHEARTBEATRATE) else From 951f30e5523705a8b4c8b728874576abe28a77a2 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 20:08:24 +0800 Subject: [PATCH 2391/2794] websitemodulesettings, add default property --- baseunits/WebsiteModules.pas | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index e6a9fd388..8516075d6 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -85,14 +85,14 @@ TWebsiteModuleSettings = class(TPersistent) FUpdateListNumberOfThread: Integer; FUserAgent: String; published - property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit; - property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit; - property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit; - property UpdateListNumberOfThread: Integer read FUpdateListNumberOfThread write FUpdateListNumberOfThread; - property UpdateListDirectoryPageNumber: Integer read FUpdateListDirectoryPageNumber write FUpdateListDirectoryPageNumber; + property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit default 0; + property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit default 0; + property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit default 0; + property UpdateListNumberOfThread: Integer read FUpdateListNumberOfThread write FUpdateListNumberOfThread default 0; + property UpdateListDirectoryPageNumber: Integer read FUpdateListDirectoryPageNumber write FUpdateListDirectoryPageNumber default 0; property UserAgent: String read FUserAgent write FUserAgent; property Cookies: String read FCookies write FCookies; - property ProxyType: TProxyType read FProxyType write FProxyType; + property ProxyType: TProxyType read FProxyType write FProxyType default ptDefault; property ProxyHost: String read FProxyHost write FProxyHost; property ProxyPort: String read FProxyPort write FProxyPort; property ProxyUsername: String read FProxyUsername write FProxyUsername; From 44966019569ab49a38ce3a0a7c38cee0571e9e3c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 20:21:15 +0800 Subject: [PATCH 2392/2794] websitemodules, add http as settings child, and proxy as http child #1020 --- baseunits/WebsiteModules.pas | 99 +++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 8516075d6..9523522a9 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -68,35 +68,59 @@ TWebsiteOptionItem = record TProxyType = (ptDefault, ptDirect, ptHTTP, ptSOCKS4, ptSOCKS5); - { TWebsiteModuleSettings } + { TProxySettings } - TWebsiteModuleSettings = class(TPersistent) + TProxySettings = class private - FCookies: String; - FMaxConnectionLimit: Integer; - FMaxTaskLimit: Integer; - FMaxThreadPerTaskLimit: Integer; FProxyHost: String; FProxyPassword: String; FProxyPort: String; FProxyType: TProxyType; FProxyUsername: String; + published + property ProxyType: TProxyType read FProxyType write FProxyType default ptDefault; + property ProxyHost: String read FProxyHost write FProxyHost; + property ProxyPort: String read FProxyPort write FProxyPort; + property ProxyUsername: String read FProxyUsername write FProxyUsername; + property ProxyPassword: String read FProxyPassword write FProxyPassword; + end; + + { THTTPSettings } + + THTTPSettings = class + private + FCookies: String; + FProxy: TProxySettings; + FUserAgent: String; + public + constructor Create; + destructor Destroy; override; + published + property UserAgent: String read FUserAgent write FUserAgent; + property Cookies: String read FCookies write FCookies; + property Proxy: TProxySettings read FProxy write FProxy; + end; + + { TWebsiteModuleSettings } + + TWebsiteModuleSettings = class(TPersistent) + private + FHTTP: THTTPSettings; + FMaxConnectionLimit: Integer; + FMaxTaskLimit: Integer; + FMaxThreadPerTaskLimit: Integer; FUpdateListDirectoryPageNumber: Integer; FUpdateListNumberOfThread: Integer; - FUserAgent: String; + public + constructor Create; + destructor Destroy; override; published property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit default 0; property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit default 0; property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit default 0; property UpdateListNumberOfThread: Integer read FUpdateListNumberOfThread write FUpdateListNumberOfThread default 0; property UpdateListDirectoryPageNumber: Integer read FUpdateListDirectoryPageNumber write FUpdateListDirectoryPageNumber default 0; - property UserAgent: String read FUserAgent write FUserAgent; - property Cookies: String read FCookies write FCookies; - property ProxyType: TProxyType read FProxyType write FProxyType default ptDefault; - property ProxyHost: String read FProxyHost write FProxyHost; - property ProxyPort: String read FProxyPort write FProxyPort; - property ProxyUsername: String read FProxyUsername write FProxyUsername; - property ProxyPassword: String read FProxyPassword write FProxyPassword; + property HTTP: THTTPSettings read FHTTP write FHTTP; end; TAccountStatus = (asUnknown, asChecking, asValid, asInvalid); @@ -353,6 +377,32 @@ function CleanOptionName(const S: String): String; Inc(i); end; +{ TWebsiteModuleSettings } + +constructor TWebsiteModuleSettings.Create; +begin + HTTP:=THTTPSettings.Create; +end; + +destructor TWebsiteModuleSettings.Destroy; +begin + HTTP.Free; + inherited Destroy; +end; + +{ THTTPSettings } + +constructor THTTPSettings.Create; +begin + Proxy:=TProxySettings.Create; +end; + +destructor THTTPSettings.Destroy; +begin + Proxy.Free; + inherited Destroy; +end; + { TModuleContainer } procedure TModuleContainer.SetCloudflareEnabled(AValue: Boolean); @@ -464,21 +514,24 @@ procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); s: String; begin CheckCloudflareEnabled(AHTTP); - with Settings do + with Settings.HTTP do begin if UserAgent<>'' then AHTTP.UserAgent:=UserAgent; if Cookies<>'' then AHTTP.Cookies.Text:=Cookies; - s:=''; - case Settings.ProxyType of - ptDirect:AHTTP.SetNoProxy; - ptHTTP:s:='HTTP'; - ptSOCKS4:s:='SOCKS4'; - ptSOCKS5:s:='SOCKS5'; + with Proxy do + begin + s:=''; + case Proxy.ProxyType of + ptDirect:AHTTP.SetNoProxy; + ptHTTP:s:='HTTP'; + ptSOCKS4:s:='SOCKS4'; + ptSOCKS5:s:='SOCKS5'; + end; + if s<>'' then + AHTTP.SetProxy(s,ProxyHost,ProxyPort,ProxyUsername,ProxyPassword); end; - if s<>'' then - AHTTP.SetProxy(s,ProxyHost,ProxyPort,ProxyUsername,ProxyPassword); end; end; From a2a9fffe1fa9855b01a84e59caad55f269313a48 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:00:23 +0300 Subject: [PATCH 2393/2794] add ForgottenScans [EN-SC] --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index a8c82c8fa..2750645c5 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -213,6 +213,7 @@ function Init() AddWebsiteModule('TheCatScans', 'https://reader.thecatscans.com', cat) AddWebsiteModule('DeathTollScans', 'https://reader.deathtollscans.net', cat) AddWebsiteModule('MangaichiScan', 'http://mangaichiscans.mokkori.fr', cat) + AddWebsiteModule('ForgottenScans', 'http://reader.fos-scans.com', cat) -- es-sc cat = 'Spanish-Scanlation' From f8cde9cb8a96939de7564454c62c8c099d0f7179 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:05:04 +0300 Subject: [PATCH 2394/2794] add Riceballicious [EN-SC] --- lua/modules/FoOlSlide.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 2750645c5..79143b5a5 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -7,6 +7,7 @@ local dirurlonline = '/online/directory/' local dirurlhelvetica = '/r/directory/' local dirurllector = '/lector/directory/' local dirurlfsdir = '/fs/directory/' +local dirurlreaderlist = '/fs/reader/list/' function getWithCookie(lurl) if http.get(lurl) then @@ -42,7 +43,8 @@ function getdirurl(website) ['NoraNoFansub'] = dirurllector, ['HotChocolateScans'] = dirurlfsdir, ['AntisenseScans'] = dirurlonline, - ['MangaichiScan'] = dirurlfsdir + ['MangaichiScan'] = dirurlfsdir, + ['Riceballicious'] = dirurlreaderlist } if dirs[website] ~= nil then return dirs[website] @@ -214,6 +216,7 @@ function Init() AddWebsiteModule('DeathTollScans', 'https://reader.deathtollscans.net', cat) AddWebsiteModule('MangaichiScan', 'http://mangaichiscans.mokkori.fr', cat) AddWebsiteModule('ForgottenScans', 'http://reader.fos-scans.com', cat) + AddWebsiteModule('Riceballicious', 'http://riceballicious.info', cat) -- es-sc cat = 'Spanish-Scanlation' From 28bdaa2fad13084ffd7f8b4204f14db826133ca0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:06:58 +0300 Subject: [PATCH 2395/2794] add PhoenixSerenade [EN-SC] --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 79143b5a5..57deb3dd3 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -217,6 +217,7 @@ function Init() AddWebsiteModule('MangaichiScan', 'http://mangaichiscans.mokkori.fr', cat) AddWebsiteModule('ForgottenScans', 'http://reader.fos-scans.com', cat) AddWebsiteModule('Riceballicious', 'http://riceballicious.info', cat) + AddWebsiteModule('PhoenixSerenade', 'https://reader.serenade.moe', cat) -- es-sc cat = 'Spanish-Scanlation' From f0d089bc3202b0cc74dad15a2f84c7cec5689e74 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:09:13 +0300 Subject: [PATCH 2396/2794] add VortexScans [EN-SC] --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 57deb3dd3..555b0f91f 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -218,6 +218,7 @@ function Init() AddWebsiteModule('ForgottenScans', 'http://reader.fos-scans.com', cat) AddWebsiteModule('Riceballicious', 'http://riceballicious.info', cat) AddWebsiteModule('PhoenixSerenade', 'https://reader.serenade.moe', cat) + AddWebsiteModule('VortexScans', 'https://reader.vortex-scans.com', cat) -- es-sc cat = 'Spanish-Scanlation' From 1bd02013c4ed64e23f0757511362f4f22ec2a514 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:11:15 +0300 Subject: [PATCH 2397/2794] add RoseliaScanlations [EN-SC] --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 555b0f91f..a35517b29 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -219,6 +219,7 @@ function Init() AddWebsiteModule('Riceballicious', 'http://riceballicious.info', cat) AddWebsiteModule('PhoenixSerenade', 'https://reader.serenade.moe', cat) AddWebsiteModule('VortexScans', 'https://reader.vortex-scans.com', cat) + AddWebsiteModule('RoseliaScanlations', 'http://reader.roseliascans.com', cat) -- es-sc cat = 'Spanish-Scanlation' From d112d418d401eeade74c2eb5f2109c937039e0f2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:15:33 +0300 Subject: [PATCH 2398/2794] add SaikoScans [EN-SC] --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index a35517b29..241c927c8 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -220,6 +220,7 @@ function Init() AddWebsiteModule('PhoenixSerenade', 'https://reader.serenade.moe', cat) AddWebsiteModule('VortexScans', 'https://reader.vortex-scans.com', cat) AddWebsiteModule('RoseliaScanlations', 'http://reader.roseliascans.com', cat) + AddWebsiteModule('SaikoScans', 'http://saikoscans.ml', cat) -- es-sc cat = 'Spanish-Scanlation' From a51cb2d160d937aa0a54da0a5966daa57f65546f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 22 Feb 2018 15:19:51 +0300 Subject: [PATCH 2399/2794] add Yuri-ism [EN-SC] --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 241c927c8..e95a9c9a7 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -44,7 +44,8 @@ function getdirurl(website) ['HotChocolateScans'] = dirurlfsdir, ['AntisenseScans'] = dirurlonline, ['MangaichiScan'] = dirurlfsdir, - ['Riceballicious'] = dirurlreaderlist + ['Riceballicious'] = dirurlreaderlist, + ['Yuri-ism'] = dirurlslide } if dirs[website] ~= nil then return dirs[website] @@ -221,6 +222,7 @@ function Init() AddWebsiteModule('VortexScans', 'https://reader.vortex-scans.com', cat) AddWebsiteModule('RoseliaScanlations', 'http://reader.roseliascans.com', cat) AddWebsiteModule('SaikoScans', 'http://saikoscans.ml', cat) + AddWebsiteModule('Yuri-ism', 'https://www.yuri-ism.net', cat) -- es-sc cat = 'Spanish-Scanlation' From faa2decd9ce2a2a7161ac94fb59ca83716d04b85 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 20:35:04 +0800 Subject: [PATCH 2400/2794] move websitesettings to new unit --- baseunits/WebsiteModules.pas | 86 +---------------- baseunits/WebsiteModulesSettings.pas | 97 ++++++++++++++++++++ mangadownloader/forms/frmWebsiteSettings.pas | 6 +- 3 files changed, 102 insertions(+), 87 deletions(-) create mode 100644 baseunits/WebsiteModulesSettings.pas diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 9523522a9..29ccc6521 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -11,7 +11,8 @@ interface uses Classes, SysUtils, fgl, uData, uDownloadsManager, FMDOptions, httpsendthread, - LazLogger, Cloudflare, RegExpr, fpjson, jsonparser, jsonscanner, fpjsonrtti; + WebsiteModulesSettings, LazLogger, Cloudflare, RegExpr, fpjson, jsonparser, + jsonscanner, fpjsonrtti; const MODULE_NOT_FOUND = -1; @@ -66,63 +67,6 @@ TWebsiteOptionItem = record Items: PString; end; - TProxyType = (ptDefault, ptDirect, ptHTTP, ptSOCKS4, ptSOCKS5); - - { TProxySettings } - - TProxySettings = class - private - FProxyHost: String; - FProxyPassword: String; - FProxyPort: String; - FProxyType: TProxyType; - FProxyUsername: String; - published - property ProxyType: TProxyType read FProxyType write FProxyType default ptDefault; - property ProxyHost: String read FProxyHost write FProxyHost; - property ProxyPort: String read FProxyPort write FProxyPort; - property ProxyUsername: String read FProxyUsername write FProxyUsername; - property ProxyPassword: String read FProxyPassword write FProxyPassword; - end; - - { THTTPSettings } - - THTTPSettings = class - private - FCookies: String; - FProxy: TProxySettings; - FUserAgent: String; - public - constructor Create; - destructor Destroy; override; - published - property UserAgent: String read FUserAgent write FUserAgent; - property Cookies: String read FCookies write FCookies; - property Proxy: TProxySettings read FProxy write FProxy; - end; - - { TWebsiteModuleSettings } - - TWebsiteModuleSettings = class(TPersistent) - private - FHTTP: THTTPSettings; - FMaxConnectionLimit: Integer; - FMaxTaskLimit: Integer; - FMaxThreadPerTaskLimit: Integer; - FUpdateListDirectoryPageNumber: Integer; - FUpdateListNumberOfThread: Integer; - public - constructor Create; - destructor Destroy; override; - published - property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit default 0; - property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit default 0; - property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit default 0; - property UpdateListNumberOfThread: Integer read FUpdateListNumberOfThread write FUpdateListNumberOfThread default 0; - property UpdateListDirectoryPageNumber: Integer read FUpdateListDirectoryPageNumber write FUpdateListDirectoryPageNumber default 0; - property HTTP: THTTPSettings read FHTTP write FHTTP; - end; - TAccountStatus = (asUnknown, asChecking, asValid, asInvalid); { TWebsiteModuleAccount } @@ -377,32 +321,6 @@ function CleanOptionName(const S: String): String; Inc(i); end; -{ TWebsiteModuleSettings } - -constructor TWebsiteModuleSettings.Create; -begin - HTTP:=THTTPSettings.Create; -end; - -destructor TWebsiteModuleSettings.Destroy; -begin - HTTP.Free; - inherited Destroy; -end; - -{ THTTPSettings } - -constructor THTTPSettings.Create; -begin - Proxy:=TProxySettings.Create; -end; - -destructor THTTPSettings.Destroy; -begin - Proxy.Free; - inherited Destroy; -end; - { TModuleContainer } procedure TModuleContainer.SetCloudflareEnabled(AValue: Boolean); diff --git a/baseunits/WebsiteModulesSettings.pas b/baseunits/WebsiteModulesSettings.pas new file mode 100644 index 000000000..af9ea0384 --- /dev/null +++ b/baseunits/WebsiteModulesSettings.pas @@ -0,0 +1,97 @@ +unit WebsiteModulesSettings; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils; + +type + TProxyType = (ptDefault, ptDirect, ptHTTP, ptSOCKS4, ptSOCKS5); + + { TProxySettings } + + TProxySettings = class + private + FProxyHost: String; + FProxyPassword: String; + FProxyPort: String; + FProxyType: TProxyType; + FProxyUsername: String; + published + property ProxyType: TProxyType read FProxyType write FProxyType default ptDefault; + property ProxyHost: String read FProxyHost write FProxyHost; + property ProxyPort: String read FProxyPort write FProxyPort; + property ProxyUsername: String read FProxyUsername write FProxyUsername; + property ProxyPassword: String read FProxyPassword write FProxyPassword; + end; + + { THTTPSettings } + + THTTPSettings = class + private + FCookies: String; + FProxy: TProxySettings; + FUserAgent: String; + public + constructor Create; + destructor Destroy; override; + published + property Cookies: String read FCookies write FCookies; + property UserAgent: String read FUserAgent write FUserAgent; + property Proxy: TProxySettings read FProxy write FProxy; + end; + + { TWebsiteModuleSettings } + + TWebsiteModuleSettings = class(TPersistent) + private + FHTTP: THTTPSettings; + FMaxConnectionLimit: Integer; + FMaxTaskLimit: Integer; + FMaxThreadPerTaskLimit: Integer; + FUpdateListDirectoryPageNumber: Integer; + FUpdateListNumberOfThread: Integer; + public + constructor Create; + destructor Destroy; override; + published + property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit default 0; + property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit default 0; + property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit default 0; + property UpdateListNumberOfThread: Integer read FUpdateListNumberOfThread write FUpdateListNumberOfThread default 0; + property UpdateListDirectoryPageNumber: Integer read FUpdateListDirectoryPageNumber write FUpdateListDirectoryPageNumber default 0; + property HTTP: THTTPSettings read FHTTP write FHTTP; + end; + +implementation + +{ THTTPSettings } + +constructor THTTPSettings.Create; +begin + Proxy:=TProxySettings.Create; +end; + +destructor THTTPSettings.Destroy; +begin + Proxy.Free; + inherited Destroy; +end; + +{ TWebsiteModuleSettings } + +constructor TWebsiteModuleSettings.Create; +begin + HTTP:=THTTPSettings.Create; +end; + +destructor TWebsiteModuleSettings.Destroy; +begin + HTTP.Free; + inherited Destroy; +end; + +end. + diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 7f3fd6fd1..9d4d1738a 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -5,9 +5,9 @@ interface uses - Classes, SysUtils, FileUtil, WebsiteModules, RTTIGrids, Forms, Controls, - Graphics, Dialogs, StdCtrls, ExtCtrls, PairSplitter, EditBtn, VirtualTrees, - contnrs, RTTICtrls; + Classes, SysUtils, FileUtil, WebsiteModules, WebsiteModulesSettings, + RTTIGrids, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, + PairSplitter, EditBtn, VirtualTrees, contnrs, RTTICtrls; type From 03fb8ac49932ee954330998df48cdb5c3dc50fec Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 22:11:20 +0800 Subject: [PATCH 2401/2794] fixed #1039 --- mangadownloader/forms/frmMain.lfm | 10 +++++----- mangadownloader/forms/frmMain.pas | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index faf9bb480..a5471d07f 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -37,10 +37,10 @@ object MainForm: TMainForm Height = 526 Top = 8 Width = 769 - ActivePage = tsOption + ActivePage = tsDownload Align = alClient ParentFont = False - TabIndex = 3 + TabIndex = 0 TabOrder = 0 OnChange = pcMainChange object tsDownload: TTabSheet @@ -545,13 +545,13 @@ object MainForm: TMainForm Anchors = [akTop, akLeft, akRight] AutoComplete = True AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchAscending] - AutoDropDown = True ItemHeight = 15 ItemIndex = 0 Items.Strings = ( '' ) OnEditingDone = cbSelectMangaEditingDone + OnKeyDown = cbSelectMangaKeyDown OnMouseDown = cbSelectMangaMouseDown ParentShowHint = False ShowHint = True @@ -2639,11 +2639,11 @@ object MainForm: TMainForm Height = 400 Top = 4 Width = 761 - ActivePage = tsWebsites + ActivePage = tsGeneral Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] ParentFont = False - TabIndex = 6 + TabIndex = 0 TabOrder = 0 object tsGeneral: TTabSheet Caption = 'General' diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 990b7b1b2..84021b93f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -441,6 +441,8 @@ TMainForm = class(TForm) procedure cbOptionDigitVolumeChange(Sender: TObject); procedure cbOptionGenerateMangaFolderChange(Sender: TObject); procedure cbSelectMangaEditingDone(Sender: TObject); + procedure cbSelectMangaKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); procedure cbSelectMangaMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure clbChapterListBeforeCellPaint(Sender: TBaseVirtualTree; @@ -2546,6 +2548,12 @@ procedure TMainForm.cbSelectMangaEditingDone(Sender: TObject); end; end; +procedure TMainForm.cbSelectMangaKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + cbSelectManga.DroppedDown:=True; +end; + procedure TMainForm.cbSelectMangaMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin From c35c4beb38c279db81a5a334d2607feeef98ddbd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Thu, 22 Feb 2018 22:30:48 +0800 Subject: [PATCH 2402/2794] websitemodulesseting, sub setting as persistent maybe needed to link to rtti control --- baseunits/WebsiteModulesSettings.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/WebsiteModulesSettings.pas b/baseunits/WebsiteModulesSettings.pas index af9ea0384..2b177ed53 100644 --- a/baseunits/WebsiteModulesSettings.pas +++ b/baseunits/WebsiteModulesSettings.pas @@ -12,7 +12,7 @@ interface { TProxySettings } - TProxySettings = class + TProxySettings = class(TPersistent) private FProxyHost: String; FProxyPassword: String; @@ -29,7 +29,7 @@ TProxySettings = class { THTTPSettings } - THTTPSettings = class + THTTPSettings = class(TPersistent) private FCookies: String; FProxy: TProxySettings; From d27bb6e63c35e36d54487de3a188c56f2f5d38ba Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 23 Feb 2018 10:14:31 +0300 Subject: [PATCH 2403/2794] WebsiteSettings, add groupboxes --- baseunits/WebsiteModulesSettings.pas | 5 + mangadownloader/forms/frmWebsiteSettings.pas | 189 +++++++++++++------ 2 files changed, 132 insertions(+), 62 deletions(-) diff --git a/baseunits/WebsiteModulesSettings.pas b/baseunits/WebsiteModulesSettings.pas index 2b177ed53..bb91d641c 100644 --- a/baseunits/WebsiteModulesSettings.pas +++ b/baseunits/WebsiteModulesSettings.pas @@ -93,5 +93,10 @@ destructor TWebsiteModuleSettings.Destroy; inherited Destroy; end; +initialization + RegisterClass(TWebsiteModuleSettings); + RegisterClass(THTTPSettings); + RegisterClass(TProxySettings); + end. diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 9d4d1738a..909a8a396 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -19,14 +19,14 @@ TSettingsView = class FOwner: TWinControl; FControls: TFPObjectList; procedure SetData(settings: TWebsiteModuleSettings); - function GetData: TWebsiteModuleSettings; procedure CreateControls; + procedure CreateControls(ci: Pointer; owner: TWinControl; controls: TFPObjectList); overload; procedure UpdateView; procedure OnEditorButtonClick(Sender: TObject); public constructor Create(owner: TWinControl); destructor Destroy; override; - property Data: TWebsiteModuleSettings read GetData write SetData; + property Data: TWebsiteModuleSettings read FSettings write SetData; end; { TWebsiteSettingsForm } @@ -161,22 +161,23 @@ procedure TSettingsView.SetData(settings: TWebsiteModuleSettings); UpdateView; end; -function TSettingsView.GetData: TWebsiteModuleSettings; -begin - Result := FSettings; -end; - procedure TSettingsView.OnEditorButtonClick(Sender: TObject); - function FindEditor: TTIEdit; + function FindEditor(controls: TFPObjectList): TTIEdit; var i: Integer; begin - for i := 0 to FControls.Count - 2 do - if Sender = FControls[i] then begin - Result := TTIEdit(FControls[i+1]); + Result := nil; + for i := 0 to controls.Count - 1 do begin + if controls[i] is TFPObjectList then begin + Result := FindEditor(TFPObjectList(controls[i])); + if Assigned(Result) then Exit; + end; + if Sender = controls[i] then begin + Result := TTIEdit(controls[i+1]); Exit; end; + end; end; var @@ -185,14 +186,14 @@ procedure TSettingsView.OnEditorButtonClick(Sender: TObject); begin if not Assigned(FSettings) then Exit; form := TStringsPropEditorFrm.Create(FOwner); - editor := FindEditor; + editor := FindEditor(FControls); form.Memo.Text := editor.Link.GetAsText; if form.ShowModal = mrOK then editor.Link.SetAsText(form.Memo.Text); form.Free; end; -procedure TSettingsView.CreateControls; +procedure TSettingsView.CreateControls(ci: Pointer; owner: TWinControl; controls: TFPObjectList); procedure SetAnchor(control, lbl, prev: TControl); begin @@ -200,7 +201,7 @@ procedure TSettingsView.CreateControls; if prev <> nil then begin control.AnchorSide[akTop].Control := prev; control.AnchorSide[akTop].Side := asrBottom; - control.BorderSpacing.Top := 10; + control.BorderSpacing.Top := 5; end else begin control.AnchorSide[akTop].Control := lbl; @@ -212,10 +213,10 @@ procedure TSettingsView.CreateControls; function AddLabel(text: String; prev: TControl): TLabel; begin - Result := TLabel.Create(FOwner); - Result.Parent := FOwner; + Result := TLabel.Create(owner); + Result.Parent := owner; Result.Caption := text; - Result.AnchorSide[akLeft].Control := FOwner; + Result.AnchorSide[akLeft].Control := owner; Result.AnchorSide[akLeft].Side := asrLeft; Result.BorderSpacing.Left := 5; if prev <> nil then begin @@ -225,7 +226,7 @@ procedure TSettingsView.CreateControls; end else Result.Top := 5; - FControls.Add(Result); + controls.Add(Result); end; function AddEdit(name, text: String; prev: TControl): TTIEdit; @@ -234,92 +235,114 @@ procedure TSettingsView.CreateControls; btn: TButton; begin lbl := AddLabel(text, prev); - - btn := TButton.Create(FOwner); - btn.Parent := FOwner; + btn := TButton.Create(owner); + btn.Parent := owner; btn.Caption := '...'; btn.AutoSize := True; btn.Enabled := False; btn.OnClick := @OnEditorButtonClick; SetAnchor(btn, lbl, prev); btn.Anchors := [akTop, akRight]; - btn.AnchorSide[akRight].Control := FOwner; + btn.AnchorSide[akRight].Control := owner; btn.AnchorSide[akRight].Side := asrRight; btn.BorderSpacing.Left := 0; - FControls.Add(btn); + controls.Add(btn); - Result := TTIEdit.Create(FOwner); - Result.Parent := FOwner; - Result.Link.TIObject := FSettings; + Result := TTIEdit.Create(owner); + Result.Parent := owner; + Result.Link.TIObject := nil; Result.Link.TIPropertyName := name; Result.Width := 300; Result.Enabled := False; SetAnchor(Result, lbl, prev); Result.AnchorSide[akRight].Control := btn; Result.AnchorSide[akRight].Side := asrLeft; - FControls.Add(Result); + controls.Add(Result); end; function AddSpinEdit(name, text: String; min, max: Integer; prev: TControl): TTISpinEdit; var lbl: TLabel; begin lbl := AddLabel(text, prev); - Result := TTISpinEdit.Create(FOwner); + Result := TTISpinEdit.Create(owner); Result.MinValue := min; Result.MaxValue := max; - Result.Parent := FOwner; - Result.Link.TIObject := FSettings; + Result.Parent := owner; + Result.Link.TIObject := nil; Result.Link.TIPropertyName := name; Result.Width := 100; Result.Enabled := False; SetAnchor(Result, lbl, prev); Result.Anchors := [akTop, akLeft]; - FControls.Add(Result); + controls.Add(Result); end; function AddComboBox(name, text: String; prev: TControl): TTIComboBox; var lbl: TLabel; begin lbl := AddLabel(text, prev); - Result := TTIComboBox.Create(FOwner); - Result.Parent := FOwner; - Result.Link.TIObject := FSettings; + Result := TTIComboBox.Create(owner); + Result.Parent := owner; + Result.Link.TIObject := nil; Result.Link.TIPropertyName := name; Result.Width := 200; result.Style := csDropDownList; Result.Enabled := False; SetAnchor(Result, lbl, prev); Result.Anchors := [akTop, akLeft]; - FControls.Add(Result); + controls.Add(Result); end; function AddCheckBox(name, text: String; prev: TControl): TTICheckBox; var lbl: TLabel; begin lbl := AddLabel(text, prev); - Result := TTICheckBox.Create(FOwner); - Result.Parent := FOwner; - Result.Link.TIObject := FSettings; + Result := TTICheckBox.Create(owner); + Result.Parent := owner; + Result.Link.TIObject := nil; Result.Link.TIPropertyName := name; Result.Caption := ''; Result.Enabled := False; SetAnchor(Result, lbl, prev); Result.Anchors := [akTop, akLeft]; - FControls.Add(Result); + controls.Add(Result); + end; + + function AddGroupBox(name: String; prev: TControl): TGroupBox; + begin + Result := TGroupBox.Create(owner); + Result.Parent := owner; + Result.Caption := name; + Result.AutoSize:=true; + Result.Anchors := [akTop, akLeft, akRight]; + Result.AnchorSide[akLeft].Control := owner; + Result.AnchorSide[akLeft].Side := asrLeft; + Result.BorderSpacing.Left := 5; + Result.AnchorSide[akTop].Control := prev; + Result.AnchorSide[akTop].Side := asrBottom; + Result.BorderSpacing.Top := 5; + Result.AnchorSide[akRight].Control := owner; + Result.AnchorSide[akRight].Side := asrRight; + Result.BorderSpacing.Right := 10; + result.BorderSpacing.Bottom := 10; + controls.Add(Result); end; var - prev: TControl = nil; + prev: TControl; propList: PPropList; typeData: PTypeData; cnt, i: Integer; - maxLabelWidth: Integer = -1; + maxLabelWidth: Integer; maxLabel: TLabel; + tmp: TFPObjectList; + subci: Pointer; begin - typeData := GetTypeData(TWebsiteModuleSettings.ClassInfo); + typeData := GetTypeData(ci); GetMem(propList, typeData^.PropCount * SizeOf(Pointer)); - cnt := GetPropList(TWebsiteModuleSettings.ClassInfo, propList); + cnt := GetPropList(ci, propList); + prev := nil; for i := 0 to cnt-1 do with propList^[i]^ do case PropType^.Kind of @@ -331,41 +354,83 @@ procedure TSettingsView.CreateControls; prev := AddComboBox(Name, Name, prev); tkBool: prev := AddCheckBox(Name, Name, prev); + tkClass: begin + prev := AddGroupBox(Name, prev); + tmp := TFPObjectList.Create(True); + subci := GetClass(propList^[i]^.PropType^.Name).ClassInfo; + CreateControls(subci, TWinControl(prev), tmp); + controls.Add(tmp); + end; end; + FreeMem(propList); - for i := 0 to FControls.Count - 1 do - if (FControls[i] is TLabel) then - with TLabel(FControls[i]) do + maxLabelWidth := -1; + for i := 0 to controls.Count - 1 do + if (controls[i] is TLabel) then + with TLabel(controls[i]) do if maxLabelWidth < Canvas.TextWidth(Caption) then begin maxLabelWidth := Canvas.TextWidth(Caption); - maxLabel := TLabel(FControls[i]); + maxLabel := TLabel(controls[i]); end; - for i := 0 to FControls.Count - 1 do - if not (FControls[i] is TLabel) and not (FControls[i] is TButton) then - with TControl(FControls[i]) do begin + for i := 0 to controls.Count - 1 do + if not (controls[i] is TLabel) and + not (controls[i] is TButton) and + not (controls[i] is TGroupBox) and + not (controls[i] is TFPObjectList) + then + with TControl(controls[i]) do begin AnchorSide[akLeft].Control := maxLabel; AnchorSide[akLeft].Side := asrRight; end; end; -procedure TSettingsView.UpdateView; +procedure TSettingsView.CreateControls; var + list: TFPObjectList; i: Integer; begin - for i := 0 to FControls.Count-1 do begin - if FControls[i] is TTIEdit then - TTIEdit(FControls[i]).Link.TIObject := FSettings - else if FControls[i] is TTISpinEdit then - TTISpinEdit(FControls[i]).Link.TIObject := FSettings - else if FControls[i] is TTIComboBox then - TTIComboBox(FControls[i]).Link.TIObject := FSettings - else if FControls[i] is TTICheckBox then - TTICheckBox(FControls[i]).Link.TIObject := FSettings; - if Assigned(FSettings) then - TControl(FControls[i]).Enabled := True; + list := TFPObjectList.Create(False); + CreateControls(TWebsiteModuleSettings.ClassInfo, FOwner, list); + for i := 0 to list.Count - 1 do + FControls.Add(list[i]); + list.Free; +end; + +procedure TSettingsView.UpdateView; + + procedure _UpdateView(controls: TFPObjectList; settings: TPersistent); + var + i: Integer; + name: String; + val: TPersistent; + begin + for i := 0 to controls.Count-1 do begin + if controls[i] is TTIEdit then + TTIEdit(controls[i]).Link.TIObject := settings + else if controls[i] is TTISpinEdit then + TTISpinEdit(controls[i]).Link.TIObject := settings + else if controls[i] is TTIComboBox then + TTIComboBox(controls[i]).Link.TIObject := settings + else if controls[i] is TTICheckBox then + TTICheckBox(controls[i]).Link.TIObject := settings + else if controls[i] is TGroupBox then + name := TControl(controls[i]).Caption + else if controls[i] is TFPObjectList then begin + val := nil; + if Assigned(settings) then + val := TPersistent(GetObjectProp(settings, name)); + _UpdateView(TFPObjectList(controls[i]), val); + end; + + if Assigned(settings) and not (controls[i] is TFPObjectList) then + TControl(controls[i]).Enabled := True; + end; end; + +begin + _UpdateView(FControls, FSettings); end; end. From 40d0b4ac611c80a9c07b967669b2204ebd559900 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 23 Feb 2018 10:28:08 +0300 Subject: [PATCH 2404/2794] WebsiteSettings, add bottom spacing --- mangadownloader/forms/frmWebsiteSettings.pas | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 909a8a396..968d0fb13 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -324,7 +324,6 @@ procedure TSettingsView.CreateControls(ci: Pointer; owner: TWinControl; controls Result.AnchorSide[akRight].Control := owner; Result.AnchorSide[akRight].Side := asrRight; Result.BorderSpacing.Right := 10; - result.BorderSpacing.Bottom := 10; controls.Add(Result); end; @@ -337,6 +336,7 @@ procedure TSettingsView.CreateControls(ci: Pointer; owner: TWinControl; controls maxLabel: TLabel; tmp: TFPObjectList; subci: Pointer; + last: TObject; begin typeData := GetTypeData(ci); @@ -347,7 +347,7 @@ procedure TSettingsView.CreateControls(ci: Pointer; owner: TWinControl; controls with propList^[i]^ do case PropType^.Kind of tkInteger: - prev := AddSpinEdit(Name, Name, 1, High(Integer), prev); + prev := AddSpinEdit(Name, Name, 0, High(Integer), prev); tkAString: prev := AddEdit(Name, Name, prev); tkEnumeration: @@ -384,18 +384,16 @@ procedure TSettingsView.CreateControls(ci: Pointer; owner: TWinControl; controls AnchorSide[akLeft].Control := maxLabel; AnchorSide[akLeft].Side := asrRight; end; + + last := controls[controls.Count - 1]; + if last is TFPObjectList then + last := controls[controls.Count - 2]; + TControl(last).BorderSpacing.Bottom := 10; end; procedure TSettingsView.CreateControls; -var - list: TFPObjectList; - i: Integer; begin - list := TFPObjectList.Create(False); - CreateControls(TWebsiteModuleSettings.ClassInfo, FOwner, list); - for i := 0 to list.Count - 1 do - FControls.Add(list[i]); - list.Free; + CreateControls(TWebsiteModuleSettings.ClassInfo, FOwner, FControls); end; procedure TSettingsView.UpdateView; From 59636e4c468eeeed002ec52689978f210f9d9505 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sat, 24 Feb 2018 01:12:37 +0800 Subject: [PATCH 2405/2794] frmmain, fixed cbselectmanga keydown --- mangadownloader/forms/frmMain.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 84021b93f..64931b539 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2551,7 +2551,8 @@ procedure TMainForm.cbSelectMangaEditingDone(Sender: TObject); procedure TMainForm.cbSelectMangaKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin - cbSelectManga.DroppedDown:=True; + if not (Key in [VK_RETURN, VK_TAB]) then + cbSelectManga.DroppedDown:=True; end; procedure TMainForm.cbSelectMangaMouseDown(Sender: TObject; From 5c1bce3def10f0a7d7b2975506257e6179165993 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 23 Feb 2018 22:19:57 +0300 Subject: [PATCH 2406/2794] Mangadex, add getinfo pagination --- baseunits/modules/Mangadex.pas | 89 ++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas index f3b0b55bf..e7908e9e9 100644 --- a/baseunits/modules/Mangadex.pas +++ b/baseunits/modules/Mangadex.pas @@ -23,9 +23,35 @@ implementation function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; + + procedure AddChapters(x: TXQueryEngineHTML); + var + s, lang, group: String; + v: IXQValue; + begin + if showalllang then + s := '//div[contains(@class, "tab-content")]//table/tbody/tr/td[1]/a' + else + s := '//div[contains(@class, "tab-content")]//table/tbody/tr[td[2]/img/@title="English"]/td[1]/a'; + for v in x.XPath(s) do begin + MangaInfo.mangaInfo.chapterLinks.Add(v.toNode().getAttribute('href')); + s := v.toString(); + if showalllang then begin + lang := x.XPathString('parent::td/parent::tr/td[2]/img/@title', v); + if lang <> '' then s := s + ' [' + lang + ']'; + end; + if showscangroup then begin + group := x.XPathString('parent::td/parent::tr/td[3]/a', v); + if group <> '' then s := s + ' [' + group + ']'; + end; + MangaInfo.mangaInfo.chapterName.Add(s); + end; + end; + var - v: IXQValue; - s, lang, group: String; + x: TXQueryEngineHTML; + s: String; + pages, i: Integer; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); @@ -35,38 +61,37 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; Cookies.Values['mangadex_h_toggle'] := '1'; if GET(url) then begin Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - if title = '' then title := XPathString('//h3[@class="panel-title"]/text()'); - if Pos('emailprotected', title) > 0 then - title := Trim(ReplaceString(XPathString('//title'), '(Manga) - MangaDex', '')); - coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@alt="Manga image"]/@src')); - authors := XPathString('//th[contains(., "Author")]/following-sibling::td/a'); - artists := XPathString('//th[contains(., "Artist")]/following-sibling::td/a'); - genres := XPathStringAll('//th[contains(., "Genres")]/following-sibling::td/span'); - summary := XPathString('//th[contains(., "Description")]/following-sibling::td'); - status := MangaInfoStatusIfPos(XPathString('//th[contains(., "Status")]/following-sibling::td')); - if showalllang then - s := '//div[contains(@class, "tab-content")]//table/tbody/tr/td[1]/a' - else - s := '//div[contains(@class, "tab-content")]//table/tbody/tr[td[2]/img/@title="English"]/td[1]/a'; - for v in XPath(s) do begin - chapterLinks.Add(v.toNode().getAttribute('href')); - s := v.toString(); - if showalllang then begin - lang := XPathString('parent::td/parent::tr/td[2]/img/@title', v); - if lang <> '' then s := s + ' [' + lang + ']'; - end; - if showscangroup then begin - group := XPathString('parent::td/parent::tr/td[3]/a', v); - if group <> '' then s := s + ' [' + group + ']'; - end; - chapterName.Add(s); + x := TXQueryEngineHTML.Create(Document); + try + if title = '' then title := x.XPathString('//h3[@class="panel-title"]/text()'); + if Pos('emailprotected', title) > 0 then + title := Trim(ReplaceString(x.XPathString('//title'), '(Manga) - MangaDex', '')); + coverLink := MaybeFillHost(Module.RootURL, x.XPathString('//img[@alt="Manga image"]/@src')); + authors := x.XPathString('//th[contains(., "Author")]/following-sibling::td/a'); + artists := x.XPathString('//th[contains(., "Artist")]/following-sibling::td/a'); + genres := x.XPathStringAll('//th[contains(., "Genres")]/following-sibling::td/span'); + summary := x.XPathString('//th[contains(., "Description")]/following-sibling::td'); + status := MangaInfoStatusIfPos(x.XPathString('//th[contains(., "Status")]/following-sibling::td')); + s := x.XPathString('//ul[@class="pagination"]/li[last()]/a/@href'); + s := RegExprGetMatch('\/(\d+)$', Trim(s), 1); + pages := StrToIntDef(s, 0) div PerPage; + AddChapters(x); + finally + x.Free; + end; + + for i := 1 to pages do + if GET(url + '/' + IntToStr(i * PerPage)) then begin + if MangaInfo.Thread.IsTerminated then Break; + x := TXQueryEngineHTML.Create(Document); + try + AddChapters(x); + finally + x.Free; end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; end; + + InvertStrings([chapterLinks, chapterName]); end; end; end; From 542b492895f1e8c38870082456de3b08df1d0cad Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 24 Feb 2018 07:03:46 +0300 Subject: [PATCH 2407/2794] Add SilentSkyScans [EN-SC] #1044 --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index e95a9c9a7..3ef3c2cf6 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -223,6 +223,7 @@ function Init() AddWebsiteModule('RoseliaScanlations', 'http://reader.roseliascans.com', cat) AddWebsiteModule('SaikoScans', 'http://saikoscans.ml', cat) AddWebsiteModule('Yuri-ism', 'https://www.yuri-ism.net', cat) + AddWebsiteModule('SilentSkyScans', 'http://reader.silentsky-scans.net', cat) -- es-sc cat = 'Spanish-Scanlation' From 1ef105593656dd779f2578ca48af5cf3f450d016 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 24 Feb 2018 16:08:34 +0300 Subject: [PATCH 2408/2794] add rawdevart [raw] --- lua/modules/rawdevart.lua | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 lua/modules/rawdevart.lua diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua new file mode 100644 index 000000000..52690de93 --- /dev/null +++ b/lua/modules/rawdevart.lua @@ -0,0 +1,57 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="post-title"]/h3') + mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@src') + mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') + mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') + mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="summary-heading" and contains(h5, "Status")]/following-sibling::div/div/a')) + mangainfo.summary=x.xpathstring('//div[@class="summary__content"]/p') + x.XPathHREFAll('//li[@class="wp-manga-chapter"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + x=TXQuery.Create(http.Document) + v=x.xpathstringall('//div[@class="page-break"]/img/@src', task.pagelinks) + else + return false + end + return true +end + +local perpage = 100 + +function getnameandlink() + local q = 'action=madara_load_more&page='.. url ..'&template=madara-core%2Fcontent%2Fcontent-archive&vars%5Bpost_type%5D=wp-manga&vars%5Berror%5D=&vars%5Bm%5D=&vars%5Bp%5D=0&vars%5Bpost_parent%5D=&vars%5Bsubpost%5D=&vars%5Bsubpost_id%5D=&vars%5Battachment%5D=&vars%5Battachment_id%5D=0&vars%5Bname%5D=&vars%5Bstatic%5D=&vars%5Bpagename%5D=&vars%5Bpage_id%5D=0&vars%5Bsecond%5D=&vars%5Bminute%5D=&vars%5Bhour%5D=&vars%5Bday%5D=0&vars%5Bmonthnum%5D=0&vars%5Byear%5D=0&vars%5Bw%5D=0&vars%5Bcategory_name%5D=&vars%5Btag%5D=&vars%5Bcat%5D=&vars%5Btag_id%5D=&vars%5Bauthor%5D=&vars%5Bauthor_name%5D=&vars%5Bfeed%5D=&vars%5Btb%5D=&vars%5Bpaged%5D=1&vars%5Bmeta_key%5D=&vars%5Bmeta_value%5D=&vars%5Bpreview%5D=&vars%5Bs%5D=&vars%5Bsentence%5D=&vars%5Btitle%5D=&vars%5Bfields%5D=&vars%5Bmenu_order%5D=&vars%5Bembed%5D=&vars%5Bignore_sticky_posts%5D=false&vars%5Bsuppress_filters%5D=false&vars%5Bcache_results%5D=true&vars%5Bupdate_post_term_cache%5D=true&vars%5Blazy_load_term_meta%5D=true&vars%5Bupdate_post_meta_cache%5D=true&vars%5Bposts_per_page%5D='.. tostring(perpage) ..'&vars%5Bnopaging%5D=false&vars%5Bcomments_per_page%5D=50&vars%5Bno_found_rows%5D=false&vars%5Border%5D=ASC&vars%5Borderby%5D=post_title&vars%5Btemplate%5D=archive&vars%5Bsidebar%5D=full&vars%5Bpost_status%5D=publish' + + if http.post(module.rooturl .. '/wp-admin/admin-ajax.php', q) then + if http.headers.values['Content-Length'] == '0' then return no_error end + x = TXQuery.Create(http.Document) + if x.xpath('//div[contains(@class, "post-title")]/h5/a').count == 0 then return no_error end + x.XPathHREFAll('//div[contains(@class, "post-title")]/h5/a', links, names) + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'Rawdevart' + m.rooturl = 'https://rawdevart.com' + m.category = 'Raw' + m.lastupdated='February 22, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From fc5a82aaae15fe5e3d7e4e6f16b3e1323ab44f8e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 25 Feb 2018 08:52:06 +0300 Subject: [PATCH 2409/2794] VnSharing, fix update list fixes #1048 --- lua/modules/VnSharing.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lua/modules/VnSharing.lua b/lua/modules/VnSharing.lua index 97da35481..5fab304d8 100644 --- a/lua/modules/VnSharing.lua +++ b/lua/modules/VnSharing.lua @@ -40,9 +40,19 @@ function GetPageNumber() end function GetNameAndLink() - if http.get(module.rooturl..'/index/KhamPha/newest/'..IncStr(url)) then - x=TXQuery.Create(http.Document) - x.xpathhrefall('//ul[@id="browse_result_wrap"]/li[@class="browse_result_item"]/a[@class="title"]', links, names) + if http.get(module.rooturl .. '/index/KhamPha/newest/' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//ul[@id="browse_result_wrap"]/li[@class="browse_result_item"]/a[@class="title"]', links, names) + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getattribute('href')) + names.add(v1.toString) + end + if v.count > 0 then + local page = tonumber(x.XPathString('(//div[@class="pagination_wrap"]/a)[last()-1]')) + if page == nil then page = 1 end + updatelist.CurrentDirectoryPageNumber = page + end return no_error else return net_problem @@ -59,5 +69,4 @@ function Init() m.ongetinfo='GetInfo' m.ongetpagenumber='GetPageNumber' m.ongetnameandlink='GetNameAndLink' - m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' end \ No newline at end of file From ec5a0f64d3fe39ecc9e5219e39c80852f38f4c4a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 25 Feb 2018 23:32:05 +0800 Subject: [PATCH 2410/2794] websitemodulessetting, add enabled property --- baseunits/WebsiteModulesSettings.pas | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/baseunits/WebsiteModulesSettings.pas b/baseunits/WebsiteModulesSettings.pas index bb91d641c..1c84a0654 100644 --- a/baseunits/WebsiteModulesSettings.pas +++ b/baseunits/WebsiteModulesSettings.pas @@ -12,7 +12,7 @@ interface { TProxySettings } - TProxySettings = class(TPersistent) + TProxySettings = class private FProxyHost: String; FProxyPassword: String; @@ -29,7 +29,7 @@ TProxySettings = class(TPersistent) { THTTPSettings } - THTTPSettings = class(TPersistent) + THTTPSettings = class private FCookies: String; FProxy: TProxySettings; @@ -45,8 +45,9 @@ THTTPSettings = class(TPersistent) { TWebsiteModuleSettings } - TWebsiteModuleSettings = class(TPersistent) + TWebsiteModuleSettings = class private + FEnabled: Boolean; FHTTP: THTTPSettings; FMaxConnectionLimit: Integer; FMaxTaskLimit: Integer; @@ -57,6 +58,7 @@ TWebsiteModuleSettings = class(TPersistent) constructor Create; destructor Destroy; override; published + property Enabled: Boolean read FEnabled write FEnabled default False; property MaxTaskLimit: Integer read FMaxTaskLimit write FMaxTaskLimit default 0; property MaxThreadPerTaskLimit: Integer read FMaxThreadPerTaskLimit write FMaxThreadPerTaskLimit default 0; property MaxConnectionLimit: Integer read FMaxConnectionLimit write FMaxConnectionLimit default 0; @@ -93,10 +95,5 @@ destructor TWebsiteModuleSettings.Destroy; inherited Destroy; end; -initialization - RegisterClass(TWebsiteModuleSettings); - RegisterClass(THTTPSettings); - RegisterClass(TProxySettings); - end. From 5948fe4d184f060d3af6ed7c7d623e6961f6f57a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Sun, 25 Feb 2018 23:33:00 +0800 Subject: [PATCH 2411/2794] added virtualpropertygrid --- baseunits/VirtualPropertyGrid.pas | 423 ++++++++++++++++++++++ baseunits/VirtualPropertyGridEditLink.pas | 239 ++++++++++++ 2 files changed, 662 insertions(+) create mode 100644 baseunits/VirtualPropertyGrid.pas create mode 100644 baseunits/VirtualPropertyGridEditLink.pas diff --git a/baseunits/VirtualPropertyGrid.pas b/baseunits/VirtualPropertyGrid.pas new file mode 100644 index 000000000..0ff563d9e --- /dev/null +++ b/baseunits/VirtualPropertyGrid.pas @@ -0,0 +1,423 @@ +unit VirtualPropertyGrid; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, typinfo, Types, FPCanvas, VirtualTrees, Graphics, + LMessages, Themes, Controls, LCLIntf; + +type + + PObjectPropInfo = ^TObjectPropInfo; + + TObjectPropInfo = record + Obj: TObject; + PropInfo: PPropInfo; + end; + + { TVirtualPropertyGrid } + + TVirtualPropertyGrid = class(TVirtualStringTree) + private + FAutoFullExpand: Boolean; + FAutoSortTree: Boolean; + FCheckBoxPos: TPoint; + FCheckBoxSize: TSize; + FCheckBoxUncheckedDetails: TThemedElementDetails; + FCheckBoxCheckedDetails: TThemedElementDetails; + FCleanEnumName: Boolean; + FFilter: TTypeKinds; + FHideClassNames: Boolean; + FTIObject: TObject; + FIsSplitResize: Boolean; + procedure BuildProperties; + procedure SetFilter(AValue: TTypeKinds); + procedure SetTIObject(AValue: TObject); + protected + procedure DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; + var Allowed: Boolean); override; + function DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer; + override; + procedure DoFocusChange(Node: PVirtualNode; Column: TColumnIndex); override; + procedure DoGetText(Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); override; + procedure DoFreeNode(Node: PVirtualNode); override; + procedure PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: Integer); + override; + procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override; + procedure DoAfterPaint(TargetCanvas: TCanvas); override; + procedure DoColumnClick(Column: TColumnIndex; Shift: TShiftState); override; + procedure HandleHotTrack(X, Y: Integer); override; + procedure HandleMouseDown(var Message: TLMMouse; var HitInfo: THitInfo); + override; + procedure HandleMouseUp(Keys: PtrUInt; const HitInfo: THitInfo); override; + function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; + override; + procedure DoScroll(DeltaX, DeltaY: Integer); override; + procedure KeyPress(var Key: Char); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + published + property AutoFullExpand: Boolean read FAutoFullExpand write FAutoFullExpand default False; + property AutoSortTree: Boolean read FAutoSortTree write FAutoSortTree default False; + property CleanEnumName: Boolean read FCleanEnumName write FCleanEnumName default False; + property Filter: TTypeKinds read FFilter write SetFilter default tkProperties; + property HideClassNames: Boolean read FHideClassNames write FHideClassNames default False; + property TIObject: TObject read FTIObject write SetTIObject; + end; + +implementation + +uses VirtualPropertyGridEditLink; + +{ TVirtualPropertyGrid } + +procedure TVirtualPropertyGrid.SetTIObject(AValue: TObject); +begin + if FTIObject = AValue then + Exit; + FTIObject := AValue; + BuildProperties; +end; + +procedure TVirtualPropertyGrid.BuildProperties; + + procedure BuildProps(AObj: TObject; Parent: PVirtualNode); + var + tempproplist: PPropList; + i: Integer; + node: PVirtualNode; + Data: PObjectPropInfo; + begin + if AObj = nil then + Exit; + try + GetMem(tempproplist, GetTypeData(AObj.ClassInfo)^.PropCount * SizeOf(Pointer)); + for i := 0 to GetPropList(AObj.ClassInfo, FFilter, tempproplist, False) - 1 do + begin + node := AddChild(Parent); + InitNode(node); + Data := GetNodeData(node); + with Data^ do + begin + Data^.Obj := AObj; + PropInfo := tempproplist^[i]; + if PropInfo^.PropType^.Kind = tkBool then + begin + node^.CheckType := ctCheckBox; + if Boolean(GetOrdProp(Obj, Data^.PropInfo)) then + node^.CheckState := csCheckedNormal; + end + else + if PropInfo^.PropType^.Kind = tkClass then + BuildProps(GetObjectProp(Obj, PropInfo), node); + end; + end; + finally + if tempproplist <> nil then + Freemem(tempproplist); + end; + end; + +begin + BeginUpdate; + try + Clear; + BuildProps(FTIObject, RootNode); + if FAutoSortTree then + SortTree(0, sdAscending, False); + if FAutoFullExpand then + FullExpand(); + finally + EndUpdate; + end; +end; + +procedure TVirtualPropertyGrid.SetFilter(AValue: TTypeKinds); +begin + if FFilter = AValue then + Exit; + FFilter := AValue; +end; + +procedure TVirtualPropertyGrid.DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; + var Allowed: Boolean); +begin + Allowed := False; + if Column = 0 then + Exit; + if PObjectPropInfo(GetNodeData(Node))^.PropInfo^.PropType^.Kind in [tkBool, tkClass] then + Exit; + Allowed := True; + inherited DoCanEdit(Node, Column, Allowed); +end; + +function TVirtualPropertyGrid.DoCompare(Node1, Node2: PVirtualNode; + Column: TColumnIndex): Integer; +begin + if Column = 0 then + Result := AnsiCompareStr(PObjectPropInfo(GetNodeData(node1))^.PropInfo^.Name, + PObjectPropInfo(GetNodeData(node2))^.PropInfo^.Name); + Result := inherited DoCompare(Node1, Node2, Column); +end; + +procedure TVirtualPropertyGrid.DoFocusChange(Node: PVirtualNode; Column: TColumnIndex); +begin + inherited DoFocusChange(Node, Column); + EditNode(Node, Column); +end; + +procedure TVirtualPropertyGrid.DoGetText(Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); +begin + with PObjectPropInfo(GetNodeData(Node))^ do + case Column of + 0: CellText := PropInfo^.Name; + 1: case PropInfo^.PropType^.Kind of + tkSString, + tkLString, + tkAString, + tkWString: + CellText := GetStrProp(Obj, PropInfo); + tkInteger, + tkInt64: + CellText := IntToStr(GetOrdProp(Obj, PropInfo)); + tkBool: + CellText := '(' + BoolToStr(Boolean(GetOrdProp(Obj, PropInfo)), True) + ')'; + tkEnumeration: + CellText := TryCleanEnumName(GetEnumProp(Obj, PropInfo), FCleanEnumName); + tkClass: + if not FHideClassNames then + CellText := '(' + GetObjectPropClass(Obj, PropInfo^.Name).ClassName + ')'; + end; + end; + inherited DoGetText(Node, Column, TextType, CellText); +end; + +procedure TVirtualPropertyGrid.DoFreeNode(Node: PVirtualNode); +begin + Finalize(PObjectPropInfo(GetNodeData(node))^); + inherited DoFreeNode(Node); +end; + +procedure TVirtualPropertyGrid.PrepareCell(var PaintInfo: TVTPaintInfo; + WindowOrgX, MaxWidth: Integer); +var + C: TRect; +begin + with PaintInfo do + begin + C := CellRect; + if Column = 0 then + begin + CellRect := ContentRect; + CellRect.Left := CellRect.Left + 1; + end + else + begin + if PObjectPropInfo(GetNodeData(Node))^.PropInfo^.PropType^.Kind = tkBool then + ContentRect.Left := ContentRect.Left + FCheckBoxSize.Width + TextMargin; + end; + inherited PrepareCell(PaintInfo, WindowOrgX, MaxWidth); + if Column = 0 then + CellRect := C; + end; +end; + +procedure TVirtualPropertyGrid.DoPaintNode(var PaintInfo: TVTPaintInfo); +var + R: TRect; +begin + inherited DoPaintNode(PaintInfo); + with PaintInfo, PObjectPropInfo(GetNodeData(PaintInfo.Node))^ do + if Column = 1 then + begin + if PropInfo^.PropType^.Kind = tkBool then + begin + R := CellRect; + R.Left := R.Left + TextMargin; + R.Width := FCheckBoxSize.Width; + FCheckBoxPos.x := R.Left; + FCheckBoxPos.y := R.Right; + if Boolean(GetOrdProp(Obj, PropInfo)) then + ThemeServices.DrawElement(Canvas.Handle, FCheckBoxCheckedDetails, R) + else + ThemeServices.DrawElement(Canvas.Handle, FCheckBoxUncheckedDetails, R); + end; + end; +end; + +procedure TVirtualPropertyGrid.DoAfterPaint(TargetCanvas: TCanvas); +var + Node, XNode: PVirtualNode; + R, XR: TRect; +begin + inherited DoAfterPaint(TargetCanvas); + R := ClientRect; + with TargetCanvas, R do + begin + Pen.Style := psSolid; + Pen.Color := Self.Colors.GridLineColor; + Node := GetFirstVisible(); + while Node <> nil do + begin + R := GetDisplayRect(Node, 0, True, False, False); + Line(Left, Top, Left, Bottom); + if (GetPreviousVisibleSibling(Node) = nil) and + (Node^.Parent <> nil) and + (Node^.Parent <> RootNode) then + Line(Left, Top, Left - Self.Indent - 1, Top); + if (GetNextVisibleSibling(Node) = nil) then + begin + XNode := GetNextVisible(Node, False); + if (XNode <> nil) and (XNode^.Parent <> Node) then + begin + XR := GetDisplayRect(XNode, 0, True, False, False); + line(Left, Bottom - 1, XR.Left - 1, Bottom - 1); + end; + end; + Node := GetNextVisible(Node); + end; + R := ClientRect; + Left := Header.Columns[0].Left; + Right := Left + Header.Columns[0].Width - 1; + Bottom := Bottom + Header.Height; + Line(Right, Top, Right, Bottom); + Node := GetLastVisible(nil, True); + if Node <> nil then + begin + R := GetDisplayRect(Node, 0, True, False, False); + R.Top := R.Bottom; + R.Bottom := ClientRect.Bottom + Header.Height; + Line(Left, Top, Left, Bottom); + end; + end; +end; + +procedure TVirtualPropertyGrid.HandleHotTrack(X, Y: Integer); +begin + if FIsSplitResize or ((x >= Header.Columns[1].Left - TextMargin) and + (x <= Header.Columns[1].Left + TextMargin)) then + begin + Cursor := crHSplit; + if FIsSplitResize then + Header.Columns[0].Width := x; + end + else + inherited HandleHotTrack(X, Y); +end; + +procedure TVirtualPropertyGrid.HandleMouseDown(var Message: TLMMouse; var HitInfo: THitInfo); +begin + if (Message.XPos >= Header.Columns[1].Left - TextMargin) and + (Message.XPos <= Header.Columns[1].Left + TextMargin) then + FIsSplitResize := True + else + inherited HandleMouseDown(Message, HitInfo); +end; + +procedure TVirtualPropertyGrid.HandleMouseUp(Keys: PtrUInt; const HitInfo: THitInfo); +begin + if FIsSplitResize then + begin + Cursor := crDefault; + FIsSplitResize := False; + end + else + inherited HandleMouseUp(Keys, HitInfo); +end; + +procedure TVirtualPropertyGrid.DoColumnClick(Column: TColumnIndex; Shift: TShiftState); +var + curpos: TPoint; + Node: PVirtualNode; +begin + if Column <> 1 then + Exit; + curpos := ScreenToClient(Mouse.CursorPos); + Node := GetNodeAt(curpos.x, curpos.y); + if Node = nil then + Exit; + if (curpos.x >= FCheckBoxPos.x) and (curpos.x <= FCheckBoxPos.y) then + with PObjectPropInfo(GetNodeData(Node))^ do + begin + if PropInfo^.PropType^.Kind = tkBool then + begin + SetOrdProp(Obj, PropInfo, Integer(not (Boolean(GetOrdProp(Obj, PropInfo))))); + RepaintNode(Node); + end; + end; + inherited DoColumnClick(Column, Shift); +end; + +function TVirtualPropertyGrid.DoCreateEditor(Node: PVirtualNode; + Column: TColumnIndex): IVTEditLink; +var + L: TVirtualPropertyGridEditLink; +begin + L := TVirtualPropertyGridEditLink.Create; + L.CleanEnumName := FCleanEnumName; + Result := L; + L := nil; +end; + +procedure TVirtualPropertyGrid.DoScroll(DeltaX, DeltaY: Integer); +begin + if tsEditing in TreeStates then + EndEditNode; + inherited DoScroll(DeltaX, DeltaY); +end; + +procedure TVirtualPropertyGrid.KeyPress(var Key: Char); +begin + if (FocusedColumn = 1) and (FocusedNode <> nil) and (Key in [#13, #32]) then + with PObjectPropInfo(GetNodeData(FocusedNode))^ do + if PropInfo^.PropType^.Kind = tkBool then + begin + SetOrdProp(Obj, PropInfo, Integer(not (Boolean(GetOrdProp(Obj, PropInfo))))); + RepaintNode(FocusedNode); + end; + inherited KeyPress(Key); +end; + +constructor TVirtualPropertyGrid.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FFilter := tkProperties; + DoubleBuffered := True; + NodeDataSize := SizeOf(TObjectPropInfo); + Color := clBtnFace; + EditDelay := 0; + Margin := 0; + TextMargin := 4; + Indent := 18; + Colors.GridLineColor := clBtnShadow; + DrawSelectionMode := smBlendedRectangle; + FCheckBoxUncheckedDetails := ThemeServices.GetElementDetails(tbCheckBoxUncheckedNormal); + FCheckBoxCheckedDetails := ThemeServices.GetElementDetails(tbCheckBoxCheckedNormal); + FCheckBoxSize := ThemeServices.GetDetailSize(FCheckBoxUncheckedDetails); + with TreeOptions do + begin + PaintOptions := PaintOptions - [toShowTreeLines] + [toHideFocusRect, toPopupMode]; + SelectionOptions := SelectionOptions + [toExtendedFocus]; + MiscOptions := MiscOptions + [toEditable, toGridExtensions]; + end; + with Header do + begin + Options := Options - [hoVisible] + [hoAutoResize]; + Columns.Add; + Columns.Add; + Columns[0].Width := 200; + AutoSizeIndex := 1; + end; +end; + +destructor TVirtualPropertyGrid.Destroy; +begin + inherited Destroy; +end; + +end. diff --git a/baseunits/VirtualPropertyGridEditLink.pas b/baseunits/VirtualPropertyGridEditLink.pas new file mode 100644 index 000000000..cbab3fd42 --- /dev/null +++ b/baseunits/VirtualPropertyGridEditLink.pas @@ -0,0 +1,239 @@ +unit VirtualPropertyGridEditLink; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, Windows, SysUtils, Messages, typinfo, VirtualPropertyGrid, VirtualTrees, + Controls, StdCtrls, LMessages, LCLType, Spin, EditBtn, Forms, StringsPropEditDlg; + +type + + TEditLinkKind = (ekString, ekInteger, ekEnum); + + { TVirtualPropertyGridEditLink } + + TVirtualPropertyGridEditLink = class(TInterfacedObject, IVTEditLink) + private + FCleanEnumName: Boolean; + FColumn: TColumnIndex; + FEdit: TWinControl; + FKind: TEditLinkKind; + FNode: PVirtualNode; + FPObjectProp: PObjectPropInfo; + FTree: TVirtualStringTree; + protected + procedure EditButtonStringClick(Sender: TObject); + procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure EditExit(Sender: TObject); + public + destructor Destroy; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex): Boolean; stdcall; + function BeginEdit: Boolean; stdcall; + function CancelEdit: Boolean; stdcall; + function EndEdit: Boolean; stdcall; + function GetBounds: TRect; stdcall; + procedure SetBounds(R: TRect); stdcall; + procedure ProcessMessage(var Message: TLMessage); stdcall; + published + property CleanEnumName: Boolean read FCleanEnumName write FCleanEnumName default False; + end; + + + { TEditButtonHelper } + + TEditButtonHelper = class helper for TEditButton + public + function GetEdit: TEbEdit; + end; + +function TryCleanEnumName(const EnumName: String; Clean: Boolean = True): String; + +implementation + +function TryCleanEnumName(const EnumName: String; Clean: Boolean): String; +var + i: Integer; +begin + if not Clean then + Exit(EnumName); + Result := ''; + for i := 1 to Length(EnumName) do + begin + if EnumName[i] in ['A'..'Z'] then + begin + Result := Copy(EnumName, i, Length(EnumName) - i + 1); + Break; + end; + end; + if Result = '' then + Result := EnumName; +end; + +{ TEditButtonHelper } + +function TEditButtonHelper.GetEdit: TEbEdit; +begin + Result := Edit; +end; + +{ TVirtualPropertyGridEditLink } + +procedure TVirtualPropertyGridEditLink.EditButtonStringClick(Sender: TObject); +begin + with TStringsPropEditorFrm.Create(nil) do + try + with TEditButton(FEdit) do + begin + Memo.Lines.Text := Text; + if ShowModal = mrOk then + Text := Memo.Lines.Text; + end; + finally + Free; + end; +end; + +procedure TVirtualPropertyGridEditLink.EditKeyDown(Sender: TObject; + var Key: Word; Shift: TShiftState); +begin + case Key of + VK_ESCAPE: + begin + FTree.CancelEditNode; + Key := 0; + end; + VK_RETURN: + begin + FTree.EndEditNode; + Key := 0; + end; + VK_UP, VK_DOWN: + begin + PostMessage(FTree.Handle, WM_KEYDOWN, Key, 0); + Key := 0; + end; + end; +end; + +procedure TVirtualPropertyGridEditLink.EditExit(Sender: TObject); +begin + FTree.EndEditNode; +end; + +destructor TVirtualPropertyGridEditLink.Destroy; +begin + Application.ReleaseComponent(FEdit); + inherited Destroy; +end; + +function TVirtualPropertyGridEditLink.PrepareEdit(Tree: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +var + i: Integer; +begin + Result := True; + FTree := Tree as TVirtualStringTree; + FNode := Node; + FColumn := Column; + FPObjectProp := FTree.GetNodeData(Node); + FEdit.Free; + FEdit := nil; + with FPObjectProp^ do + case PropInfo^.PropType^.Kind of + tkSString, tkLString, tkAString, tkWString: + begin + FKind := ekString; + FEdit := TEditButton.Create(nil); + with TEditButton(FEdit) do + begin + Text := GetStrProp(Obj, PropInfo); + ButtonCaption := '...'; + OnButtonClick := @EditButtonStringClick; + GetEdit.OnKeyDown := @EditKeyDown; + end; + end; + tkInteger, tkInt64: + begin + FKind := ekInteger; + FEdit := TSpinEdit.Create(nil); + with TSpinEdit(FEdit) do + begin + MinValue := 0; + MaxValue := MaxInt; + Value := GetOrdProp(Obj, PropInfo); + end; + end; + tkEnumeration: + begin + FKind := ekEnum; + FEdit := TComboBox.Create(nil); + with TComboBox(FEdit) do + begin + for i := 0 to GetEnumNameCount(PropInfo^.PropType) - 1 do + Items.Add(TryCleanEnumName(GetEnumName(PropInfo^.PropType, i), FCleanEnumName)); + ItemIndex := GetOrdProp(Obj, PropInfo); + end; + end; + else + Result := False; + end; + + if Result then + with FEdit do + begin + Visible := False; + Parent := FTree; + OnKeyDown := @EditKeyDown; + end; +end; + +function TVirtualPropertyGridEditLink.BeginEdit: Boolean; stdcall; +begin + Result := True; + FEdit.Visible := True; + FEdit.SetFocus; +end; + +function TVirtualPropertyGridEditLink.CancelEdit: Boolean; stdcall; +begin + Result := True; + FEdit.Hide; +end; + +function TVirtualPropertyGridEditLink.EndEdit: Boolean; stdcall; +begin + Result := True; + with FPObjectProp^ do + case FKind of + ekString: SetStrProp(Obj, PropInfo, TEditButton(FEdit).Text); + ekInteger: SetOrdProp(Obj, PropInfo, TSpinEdit(FEdit).Value); + ekEnum: SetOrdProp(Obj, PropInfo, TComboBox(FEdit).ItemIndex); + end; + FTree.InvalidateNode(FNode); + FEdit.Hide; + FTree.SetFocus; +end; + +function TVirtualPropertyGridEditLink.GetBounds: TRect; stdcall; +begin + Result := FEdit.BoundsRect; +end; + +procedure TVirtualPropertyGridEditLink.SetBounds(R: TRect); stdcall; +var + i: Integer; +begin + FTree.Header.Columns.GetColumnBounds(FColumn, i, R.Right); + FEdit.BoundsRect := R; +end; + +procedure TVirtualPropertyGridEditLink.ProcessMessage(var Message: TLMessage); + stdcall; +begin + FEdit.WindowProc(Message); +end; + +end. From 4bc41e867318dd1a13f0a397890bb97a51c88928 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:03:48 +0800 Subject: [PATCH 2412/2794] baseunit, added common searchonvt --- baseunits/uBaseUnit.pas | 49 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index fdd9ff89e..f164164d2 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -23,7 +23,7 @@ interface fgl, RegExpr, synautil, httpsend, blcksock, ssl_openssl, synacode, MultiLog, FPimage, GZIPUtils, uMisc, httpsendthread, FMDOptions, simplehtmltreeparser, xquery, xquery_json, ImgInfos, NaturalSortUnit, - MemBitmap, FPWritePNG, zstream, FPReadPNG; + MemBitmap, FPWritePNG, zstream, FPReadPNG, VirtualTrees; const LineEnding2 = LineEnding + LineEnding; @@ -398,6 +398,9 @@ THTMLForm = class property Data: TStringList read fdata; end; +// VT extras +procedure SearchOnVT(Tree: TVirtualStringTree; Key: String; Column: Integer = 0); + // Remove Unicode function ReplaceUnicodeChar(const S, ReplaceStr: String): String; // Check a directory to see if it's empty (return TRUE) or not @@ -737,6 +740,50 @@ function NTSetPrivilege(sPrivilege: String; bEnabled: Boolean): Boolean; {$ENDIF} +procedure SearchOnVT(Tree: TVirtualStringTree; Key: String; Column: Integer); +var + s: String; + node, xnode: PVirtualNode; + v: Boolean; +begin + if Tree.TotalCount = 0 then + Exit; + s := AnsiUpperCase(Key); + Tree.BeginUpdate; + try + node := Tree.GetFirst(); + if s <> '' then + begin + while node <> nil do + begin + v := Pos(s, AnsiUpperCase(Tree.Text[node, Column])) <> 0; + Tree.IsVisible[node] := v; + if v then + begin + xnode := node^.Parent; + while xnode <> nil do + begin + if not (vsVisible in xnode^.States) then + Tree.IsVisible[xnode] := v; + xnode := xnode^.Parent; + end; + end; + node := Tree.GetNext(node); + end; + end + else + begin + while node <> nil do + begin + Tree.IsVisible[node] := True; + node := Tree.GetNext(node); + end; + end; + finally + Tree.EndUpdate; + end; +end; + function ReplaceUnicodeChar(const S, ReplaceStr: String): String; var i: Integer; From 250d0f051a27bf9e6c7acff2067edfd7e4fa8b8b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:04:24 +0800 Subject: [PATCH 2413/2794] websitesettings, cleanup and use vt as property editor --- mangadownloader/forms/frmWebsiteSettings.lfm | 183 +++++---- mangadownloader/forms/frmWebsiteSettings.lrj | 3 +- mangadownloader/forms/frmWebsiteSettings.pas | 388 ++----------------- mangadownloader/languages/fmd.de.po | 4 + mangadownloader/languages/fmd.el_GR.po | 4 + mangadownloader/languages/fmd.en.po | 4 + mangadownloader/languages/fmd.es.po | 4 + mangadownloader/languages/fmd.id_ID.po | 4 + mangadownloader/languages/fmd.pl_PL.po | 4 + mangadownloader/languages/fmd.po | 4 + mangadownloader/languages/fmd.pt_BR.po | 4 + mangadownloader/languages/fmd.ru_RU.po | 4 + mangadownloader/languages/fmd.tr_TR.po | 4 + 13 files changed, 185 insertions(+), 429 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index 60c250872..c648737d0 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -9,88 +9,26 @@ object WebsiteSettingsForm: TWebsiteSettingsForm OnCreate = FormCreate OnDestroy = FormDestroy LCLVersion = '1.8.0.6' - object pnTop: TPanel - Left = 0 - Height = 23 - Top = 0 - Width = 572 - Align = alTop - AutoSize = True - BorderSpacing.Bottom = 6 - BevelOuter = bvNone - ClientHeight = 23 - ClientWidth = 572 - TabOrder = 0 - object edSearch: TEditButton - Left = 0 - Height = 23 - Top = 0 - Width = 177 - ButtonWidth = 23 - Glyph.Data = { - 36040000424D3604000000000000360000002800000010000000100000000100 - 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 - 00070000000E00000014000000190000001A0000001900000017000000150000 - 00120000000E0000000B00000008000000050000000200000001000000020000 - 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 - 305D0000001C000000160000000F0000000A0000000400000001000000000000 - 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 - 5ACA00224248000D170000000000000000000000000000000000000000000000 - 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 - ABFF003763C600356046002D4E00010101000000000000000000013048000021 - 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA - C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B - 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 - C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B - 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 - CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E - 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA - D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D - 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 - 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 - 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 - D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 - 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 - 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 - 94000162930001619200016293000162930001639400000000240000006788CC - DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 - 940001629300016192000162930001629300016394000000000001334C390165 - 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 - 940001629300016192000162930001629300016394000000000001334C000165 - 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF - FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 - } - MaxLength = 0 - NumGlyphs = 1 - OnButtonClick = edSearchButtonClick - OnChange = edSearchChange - PasswordChar = #0 - TabOrder = 0 - TextHint = 'Website name' - end - end object spMain: TPairSplitter Left = 0 - Height = 432 - Top = 29 + Height = 461 + Top = 0 Width = 572 Align = alClient Position = 150 object spList: TPairSplitterSide Cursor = crArrow Left = 0 - Height = 432 + Height = 461 Top = 0 Width = 150 + ChildSizing.VerticalSpacing = 6 ClientWidth = 150 - ClientHeight = 432 + ClientHeight = 461 object vtWebsite: TVirtualStringTree Left = 0 Height = 432 - Top = 0 + Top = 29 Width = 150 Align = alClient DefaultText = 'Node' @@ -105,26 +43,117 @@ object WebsiteSettingsForm: TWebsiteSettingsForm OnFocusChanged = vtWebsiteFocusChanged OnGetText = vtWebsiteGetText end + object edSearch: TEditButton + Left = 0 + Height = 23 + Top = 0 + Width = 150 + Align = alTop + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edSearchButtonClick + OnChange = edSearchChange + PasswordChar = #0 + TabOrder = 1 + TextHint = 'Website name' + end end object spProps: TPairSplitterSide Cursor = crArrow Left = 155 - Height = 432 + Height = 461 Top = 0 Width = 417 + ChildSizing.VerticalSpacing = 6 ClientWidth = 417 - ClientHeight = 432 - object sbProps: TScrollBox + ClientHeight = 461 + object edSearchProperty: TEditButton Left = 0 - Height = 432 + Height = 23 Top = 0 Width = 417 - HorzScrollBar.Page = 1 - HorzScrollBar.Visible = False - VertScrollBar.Page = 1 - Align = alClient - BorderStyle = bsNone + Align = alTop + ButtonWidth = 23 + Glyph.Data = { + 36040000424D3604000000000000360000002800000010000000100000000100 + 2000000000000004000064000000640000000000000000000000FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000010000 + 00070000000E00000014000000190000001A0000001900000017000000150000 + 00120000000E0000000B00000008000000050000000200000001000000020000 + 000D0000001B000000280000003100000033001A3064002D57CC002C56CC0018 + 305D0000001C000000160000000F0000000A0000000400000001000000000000 + 0000000000000000000001131F0000214048002B55CC5494B7FF34679AFF0030 + 5ACA00224248000D170000000000000000000000000000000000000000000000 + 00000116210000214000014D7C41014B79BB3A719FFF386F9DFF5F9FC0FF4578 + ABFF003763C600356046002D4E00010101000000000000000000013048000021 + 400001568600002B5548002B55CC4F8DB3FF68ACC8FF4880ACFF5087B3FF6AAA + C8FF5588BBFF00416EC1003E6A440101010001385B0001263D00015F9000002B + 55000157873F015585B65FA1C0FF3F79A3FF4278A7FF66A6C5FF619DC2FF5E95 + C1FF74B4D1FF6598CBFF010101AB0101013C014B7900014B7A00015F9000002B + 5548002B55CC336898FF508CB3FF69ABC8FF67A7C6FF4D80B3FF71B1CEFF6EA9 + CDFF6CA3CEFF6D6D6DFFAA9999FF010101A5014C7A42014B7A000160913E015E + 8FB16AAEC9FF66A8C5FF5692B8FF4B80AFFF5D97BFFF77B9D2FF669DC8FF7BBA + D5FF7E7E7EFFCEC0C0FF797979FF5588BBFF014F7EA6014E7D0001629383126D + 9BB82078A2C33385ABD058A2C0E774B9D1FB6EACCCFF669DC8FF83C7DAFF8888 + 88FFD3CACAFF838383FF60A4C6FF63A7C9FF015382A501528100016395050163 + 9414016293280161924101619277106C9AAB4B9BBADB79B9D5FC919191FFD9D4 + D4FF8D8D8DFF68ACCEFF74B8D4FF015887B40156864001558400016395000163 + 9400016293000161920001629300016293100162936D00000069DDDCDCFF9494 + 94FF70B4D6FF80C4DBFF015C8DB2001A63CC0013584800226E00016395000163 + 94000162930001619200016293000162930001639400000000240000006788CC + DDFF87CBDDFF016091AF003080CC3F72B6FF002774CC00247048016395000163 + 940001629300016192000162930001629300016394000000000001334C390165 + 969C0164959C0163943E00398B48003688CC5285C9FF002E7ECC016395000163 + 940001629300016192000162930001629300016394000000000001334C000165 + 97000164960001639400003A8C00003E9248003C8FCC00378A48FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 + } + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = edSearchPropertyButtonClick + OnChange = edSearchPropertyChange + PasswordChar = #0 TabOrder = 0 + TextHint = 'Setting name' end end end diff --git a/mangadownloader/forms/frmWebsiteSettings.lrj b/mangadownloader/forms/frmWebsiteSettings.lrj index 680766ca3..3d95548fa 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lrj +++ b/mangadownloader/forms/frmWebsiteSettings.lrj @@ -1,4 +1,5 @@ {"version":1,"strings":[ {"hash":63106205,"name":"twebsitesettingsform.caption","sourcebytes":[87,101,98,115,105,116,101,83,101,116,116,105,110,103,115,70,111,114,109],"value":"WebsiteSettingsForm"}, -{"hash":263118389,"name":"twebsitesettingsform.edsearch.texthint","sourcebytes":[87,101,98,115,105,116,101,32,110,97,109,101],"value":"Website name"} +{"hash":263118389,"name":"twebsitesettingsform.edsearch.texthint","sourcebytes":[87,101,98,115,105,116,101,32,110,97,109,101],"value":"Website name"}, +{"hash":17562933,"name":"twebsitesettingsform.edsearchproperty.texthint","sourcebytes":[83,101,116,116,105,110,103,32,110,97,109,101],"value":"Setting name"} ]} diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 968d0fb13..b4d211a4e 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -5,53 +5,35 @@ interface uses - Classes, SysUtils, FileUtil, WebsiteModules, WebsiteModulesSettings, - RTTIGrids, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, - PairSplitter, EditBtn, VirtualTrees, contnrs, RTTICtrls; + Classes, SysUtils, WebsiteModules, VirtualPropertyGrid, frmCustomColor, Forms, + Controls, PairSplitter, EditBtn, VirtualTrees, uBaseUnit; type - { TSettingsView } - - TSettingsView = class - private - FSettings: TWebsiteModuleSettings; - FOwner: TWinControl; - FControls: TFPObjectList; - procedure SetData(settings: TWebsiteModuleSettings); - procedure CreateControls; - procedure CreateControls(ci: Pointer; owner: TWinControl; controls: TFPObjectList); overload; - procedure UpdateView; - procedure OnEditorButtonClick(Sender: TObject); - public - constructor Create(owner: TWinControl); - destructor Destroy; override; - property Data: TWebsiteModuleSettings read FSettings write SetData; - end; - { TWebsiteSettingsForm } TWebsiteSettingsForm = class(TForm) edSearch: TEditButton; - sbProps: TScrollBox; + edSearchProperty: TEditButton; spMain: TPairSplitter; spList: TPairSplitterSide; spProps: TPairSplitterSide; - pnTop: TPanel; vtWebsite: TVirtualStringTree; procedure edSearchButtonClick(Sender: TObject); procedure edSearchChange(Sender: TObject); + procedure edSearchPropertyButtonClick(Sender: TObject); + procedure edSearchPropertyChange(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); - procedure vtWebsiteCompareNodes(Sender: TBaseVirtualTree; Node1, - Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure vtWebsiteCompareNodes(Sender: TBaseVirtualTree; + Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); procedure vtWebsiteFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); procedure vtWebsiteGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); private - settingsView: TSettingsView; public + SettingsView: TVirtualPropertyGrid; procedure LoadWebsiteSettings; end; @@ -60,8 +42,6 @@ TWebsiteSettingsForm = class(TForm) implementation -uses frmCustomColor, typinfo, StringsPropEditDlg; - {$R *.lfm} { TWebsiteSettingsForm } @@ -69,30 +49,31 @@ implementation procedure TWebsiteSettingsForm.FormCreate(Sender: TObject); begin AddVT(vtWebsite); - settingsView := TSettingsView.Create(sbProps); + SettingsView := TVirtualPropertyGrid.Create(Self); + with SettingsView do + begin + Parent := spProps; + Align := alClient; + AutoFullExpand := True; + CleanEnumName := True; + Header.Columns[0].Width := 300; + TreeOptions.PaintOptions := TreeOptions.PaintOptions + [toThemeAware, toUseExplorerTheme]; + end; end; procedure TWebsiteSettingsForm.edSearchChange(Sender: TObject); -var - s: String; - node: PVirtualNode; begin - s:=AnsiUpperCase(edSearch.Text); - vtWebsite.BeginUpdate; - node:=vtWebsite.GetFirst(); - if s<>'' then - while node<>nil do - begin - vtWebsite.IsVisible[node]:=Pos(s,AnsiUpperCase(PModuleContainer(vtWebsite.GetNodeData(node))^.Website))<>0; - node:=vtWebsite.GetNext(node); - end - else - while node<>nil do - begin - vtWebsite.IsVisible[node]:=True; - node:=vtWebsite.GetNext(node); - end; - vtWebsite.EndUpdate; + SearchOnVT(vtWebsite, edSearch.Text); +end; + +procedure TWebsiteSettingsForm.edSearchPropertyButtonClick(Sender: TObject); +begin + edSearchProperty.Clear; +end; + +procedure TWebsiteSettingsForm.edSearchPropertyChange(Sender: TObject); +begin + SearchOnVT(SettingsView, edSearchProperty.Text); end; procedure TWebsiteSettingsForm.edSearchButtonClick(Sender: TObject); @@ -103,333 +84,38 @@ procedure TWebsiteSettingsForm.edSearchButtonClick(Sender: TObject); procedure TWebsiteSettingsForm.FormDestroy(Sender: TObject); begin RemoveVT(vtWebsite); - settingsView.Free; end; procedure TWebsiteSettingsForm.vtWebsiteCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); begin - Result:=AnsiCompareStr(PModuleContainer(Sender.GetNodeData(Node1))^.Website, + Result := AnsiCompareStr(PModuleContainer(Sender.GetNodeData(Node1))^.Website, PModuleContainer(Sender.GetNodeData(Node2))^.Website); end; procedure TWebsiteSettingsForm.vtWebsiteFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); begin - settingsView.Data := PModuleContainer(Sender.GetNodeData(Node))^.Settings; + SettingsView.TIObject := PModuleContainer(Sender.GetNodeData(Node))^.Settings; end; procedure TWebsiteSettingsForm.vtWebsiteGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); begin - CellText:=PModuleContainer(Sender.GetNodeData(Node))^.Website; + CellText := PModuleContainer(Sender.GetNodeData(Node))^.Website; end; procedure TWebsiteSettingsForm.LoadWebsiteSettings; var i: Integer; begin - vtWebsite.NodeDataSize:=SizeOf(TModuleContainer); + vtWebsite.NodeDataSize := SizeOf(TModuleContainer); vtWebsite.BeginUpdate; - for i:=0 to Modules.Count-1 do - vtWebsite.AddChild(nil,Modules[i]); - vtWebsite.Sort(nil,0,sdAscending,false); + for i := 0 to Modules.Count - 1 do + vtWebsite.AddChild(nil, Modules[i]); + vtWebsite.Sort(nil, 0, sdAscending, False); vtWebsite.EndUpdate; end; -{ TSettingsView } - -constructor TSettingsView.Create(owner: TWinControl); -begin - FOwner := owner; - FControls := TFPObjectList.Create(True); - CreateControls; - UpdateView; -end; - -destructor TSettingsView.Destroy; -begin - FControls.Clear; - FControls.Free; - inherited; -end; - -procedure TSettingsView.SetData(settings: TWebsiteModuleSettings); -begin - FSettings := settings; - UpdateView; -end; - -procedure TSettingsView.OnEditorButtonClick(Sender: TObject); - - function FindEditor(controls: TFPObjectList): TTIEdit; - var - i: Integer; - begin - Result := nil; - for i := 0 to controls.Count - 1 do begin - if controls[i] is TFPObjectList then begin - Result := FindEditor(TFPObjectList(controls[i])); - if Assigned(Result) then Exit; - end; - if Sender = controls[i] then begin - Result := TTIEdit(controls[i+1]); - Exit; - end; - end; - end; - -var - editor: TTIEdit; - form: TStringsPropEditorFrm; -begin - if not Assigned(FSettings) then Exit; - form := TStringsPropEditorFrm.Create(FOwner); - editor := FindEditor(FControls); - form.Memo.Text := editor.Link.GetAsText; - if form.ShowModal = mrOK then - editor.Link.SetAsText(form.Memo.Text); - form.Free; -end; - -procedure TSettingsView.CreateControls(ci: Pointer; owner: TWinControl; controls: TFPObjectList); - - procedure SetAnchor(control, lbl, prev: TControl); - begin - control.Anchors := [akTop, akLeft, akRight]; - if prev <> nil then begin - control.AnchorSide[akTop].Control := prev; - control.AnchorSide[akTop].Side := asrBottom; - control.BorderSpacing.Top := 5; - end - else begin - control.AnchorSide[akTop].Control := lbl; - control.AnchorSide[akTop].Side := asrCenter; - end; - control.BorderSpacing.Right := 10; - control.BorderSpacing.Left := 50; - end; - - function AddLabel(text: String; prev: TControl): TLabel; - begin - Result := TLabel.Create(owner); - Result.Parent := owner; - Result.Caption := text; - Result.AnchorSide[akLeft].Control := owner; - Result.AnchorSide[akLeft].Side := asrLeft; - Result.BorderSpacing.Left := 5; - if prev <> nil then begin - Result.AnchorSide[akTop].Control := prev; - Result.AnchorSide[akTop].Side := asrBottom; - Result.BorderSpacing.Top := 10; - end - else - Result.Top := 5; - controls.Add(Result); - end; - - function AddEdit(name, text: String; prev: TControl): TTIEdit; - var - lbl: TLabel; - btn: TButton; - begin - lbl := AddLabel(text, prev); - btn := TButton.Create(owner); - btn.Parent := owner; - btn.Caption := '...'; - btn.AutoSize := True; - btn.Enabled := False; - btn.OnClick := @OnEditorButtonClick; - SetAnchor(btn, lbl, prev); - btn.Anchors := [akTop, akRight]; - btn.AnchorSide[akRight].Control := owner; - btn.AnchorSide[akRight].Side := asrRight; - btn.BorderSpacing.Left := 0; - controls.Add(btn); - - Result := TTIEdit.Create(owner); - Result.Parent := owner; - Result.Link.TIObject := nil; - Result.Link.TIPropertyName := name; - Result.Width := 300; - Result.Enabled := False; - SetAnchor(Result, lbl, prev); - Result.AnchorSide[akRight].Control := btn; - Result.AnchorSide[akRight].Side := asrLeft; - controls.Add(Result); - end; - - function AddSpinEdit(name, text: String; min, max: Integer; prev: TControl): TTISpinEdit; - var lbl: TLabel; - begin - lbl := AddLabel(text, prev); - Result := TTISpinEdit.Create(owner); - Result.MinValue := min; - Result.MaxValue := max; - Result.Parent := owner; - Result.Link.TIObject := nil; - Result.Link.TIPropertyName := name; - Result.Width := 100; - Result.Enabled := False; - SetAnchor(Result, lbl, prev); - Result.Anchors := [akTop, akLeft]; - controls.Add(Result); - end; - - function AddComboBox(name, text: String; prev: TControl): TTIComboBox; - var lbl: TLabel; - begin - lbl := AddLabel(text, prev); - Result := TTIComboBox.Create(owner); - Result.Parent := owner; - Result.Link.TIObject := nil; - Result.Link.TIPropertyName := name; - Result.Width := 200; - result.Style := csDropDownList; - Result.Enabled := False; - SetAnchor(Result, lbl, prev); - Result.Anchors := [akTop, akLeft]; - controls.Add(Result); - end; - - function AddCheckBox(name, text: String; prev: TControl): TTICheckBox; - var lbl: TLabel; - begin - lbl := AddLabel(text, prev); - Result := TTICheckBox.Create(owner); - Result.Parent := owner; - Result.Link.TIObject := nil; - Result.Link.TIPropertyName := name; - Result.Caption := ''; - Result.Enabled := False; - SetAnchor(Result, lbl, prev); - Result.Anchors := [akTop, akLeft]; - controls.Add(Result); - end; - - function AddGroupBox(name: String; prev: TControl): TGroupBox; - begin - Result := TGroupBox.Create(owner); - Result.Parent := owner; - Result.Caption := name; - Result.AutoSize:=true; - Result.Anchors := [akTop, akLeft, akRight]; - Result.AnchorSide[akLeft].Control := owner; - Result.AnchorSide[akLeft].Side := asrLeft; - Result.BorderSpacing.Left := 5; - Result.AnchorSide[akTop].Control := prev; - Result.AnchorSide[akTop].Side := asrBottom; - Result.BorderSpacing.Top := 5; - Result.AnchorSide[akRight].Control := owner; - Result.AnchorSide[akRight].Side := asrRight; - Result.BorderSpacing.Right := 10; - controls.Add(Result); - end; - -var - prev: TControl; - propList: PPropList; - typeData: PTypeData; - cnt, i: Integer; - maxLabelWidth: Integer; - maxLabel: TLabel; - tmp: TFPObjectList; - subci: Pointer; - last: TObject; - -begin - typeData := GetTypeData(ci); - GetMem(propList, typeData^.PropCount * SizeOf(Pointer)); - cnt := GetPropList(ci, propList); - prev := nil; - for i := 0 to cnt-1 do - with propList^[i]^ do - case PropType^.Kind of - tkInteger: - prev := AddSpinEdit(Name, Name, 0, High(Integer), prev); - tkAString: - prev := AddEdit(Name, Name, prev); - tkEnumeration: - prev := AddComboBox(Name, Name, prev); - tkBool: - prev := AddCheckBox(Name, Name, prev); - tkClass: begin - prev := AddGroupBox(Name, prev); - tmp := TFPObjectList.Create(True); - subci := GetClass(propList^[i]^.PropType^.Name).ClassInfo; - CreateControls(subci, TWinControl(prev), tmp); - controls.Add(tmp); - end; - end; - - FreeMem(propList); - - maxLabelWidth := -1; - for i := 0 to controls.Count - 1 do - if (controls[i] is TLabel) then - with TLabel(controls[i]) do - if maxLabelWidth < Canvas.TextWidth(Caption) then begin - maxLabelWidth := Canvas.TextWidth(Caption); - maxLabel := TLabel(controls[i]); - end; - - for i := 0 to controls.Count - 1 do - if not (controls[i] is TLabel) and - not (controls[i] is TButton) and - not (controls[i] is TGroupBox) and - not (controls[i] is TFPObjectList) - then - with TControl(controls[i]) do begin - AnchorSide[akLeft].Control := maxLabel; - AnchorSide[akLeft].Side := asrRight; - end; - - last := controls[controls.Count - 1]; - if last is TFPObjectList then - last := controls[controls.Count - 2]; - TControl(last).BorderSpacing.Bottom := 10; -end; - -procedure TSettingsView.CreateControls; -begin - CreateControls(TWebsiteModuleSettings.ClassInfo, FOwner, FControls); -end; - -procedure TSettingsView.UpdateView; - - procedure _UpdateView(controls: TFPObjectList; settings: TPersistent); - var - i: Integer; - name: String; - val: TPersistent; - begin - for i := 0 to controls.Count-1 do begin - if controls[i] is TTIEdit then - TTIEdit(controls[i]).Link.TIObject := settings - else if controls[i] is TTISpinEdit then - TTISpinEdit(controls[i]).Link.TIObject := settings - else if controls[i] is TTIComboBox then - TTIComboBox(controls[i]).Link.TIObject := settings - else if controls[i] is TTICheckBox then - TTICheckBox(controls[i]).Link.TIObject := settings - else if controls[i] is TGroupBox then - name := TControl(controls[i]).Caption - else if controls[i] is TFPObjectList then begin - val := nil; - if Assigned(settings) then - val := TPersistent(GetObjectProp(settings, name)); - _UpdateView(TFPObjectList(controls[i]), val); - end; - - if Assigned(settings) and not (controls[i] is TFPObjectList) then - TControl(controls[i]).Enabled := True; - end; - end; - -begin - _UpdateView(FControls, FSettings); -end; end. - diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 3bb4ee22d..83cae997c 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -2403,6 +2403,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index ffbab0e76..d71bc0b14 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -2458,6 +2458,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Συμπίεση..." diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6b8df0bb2..6573d8ef7 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -2397,6 +2397,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compressing..." diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index f4e98e35a..a73a9f4c5 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -2408,6 +2408,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Comprimiendo..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 283221bc3..848ca96d1 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -2397,6 +2397,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Mengompresi..." diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 9a7097cc2..53109fbfb 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -2405,6 +2405,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Kompresja danych..." diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index b5625c497..d25db0b61 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -2314,6 +2314,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "" diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index ef15264ad..7dd25ce79 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -2408,6 +2408,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Compactando..." diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index afdce417c..f17c9f3fa 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -2404,6 +2404,10 @@ msgstr "" msgid "Website name" msgstr "" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Сжатие..." diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index dc7d787f5..4609e3350 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -2426,6 +2426,10 @@ msgstr "WebsiteAyarlarıFormu" msgid "Website name" msgstr "Website Adı" +#: twebsitesettingsform.edsearchproperty.texthint +msgid "Setting name" +msgstr "" + #: udownloadsmanager.rs_compressing msgid "Compressing..." msgstr "Sıkıştırılıyor..." From c44e716f3f626819de6c61b3a616b5ff74b7d764 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:25:41 +0800 Subject: [PATCH 2414/2794] websitemodules, respect settings enabled property --- baseunits/WebsiteModules.pas | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/baseunits/WebsiteModules.pas b/baseunits/WebsiteModules.pas index 29ccc6521..48654d25c 100644 --- a/baseunits/WebsiteModules.pas +++ b/baseunits/WebsiteModules.pas @@ -432,6 +432,7 @@ procedure TModuleContainer.PrepareHTTP(const AHTTP: THTTPSendThread); s: String; begin CheckCloudflareEnabled(AHTTP); + if not Settings.Enabled then Exit; with Settings.HTTP do begin if UserAgent<>'' then @@ -475,26 +476,26 @@ procedure TModuleContainer.DecActiveConnectionCount; function TModuleContainer.GetMaxConnectionLimit: Integer; begin - if Settings.MaxConnectionLimit=0 then - Result:=MaxConnectionLimit + if (Settings.Enabled) and (Settings.MaxConnectionLimit <> 0) then + Result:=Settings.MaxConnectionLimit else - Result:=Settings.MaxConnectionLimit; + Result:=MaxConnectionLimit; end; function TModuleContainer.GetMaxTaskLimit: Integer; begin - if Settings.MaxTaskLimit=0 then - Result:=MaxTaskLimit + if (Settings.Enabled) and (Settings.MaxTaskLimit <> 0) then + Result:=Settings.MaxTaskLimit else - Result:=Settings.MaxTaskLimit; + Result:=MaxTaskLimit; end; function TModuleContainer.GetMaxThreadPerTaskLimit: Integer; begin - if Settings.MaxThreadPerTaskLimit=0 then - Result:=MaxThreadPerTaskLimit + if (Settings.Enabled) and (Settings.MaxThreadPerTaskLimit <> 0) then + Result:=Settings.MaxThreadPerTaskLimit else - Result:=Settings.MaxThreadPerTaskLimit; + Result:=MaxThreadPerTaskLimit; end; procedure TModuleContainer.AddOption(const AOptionType: TWebsiteOptionType; From 44a534366cd1bfc70c8560d404ef9d8c3ee19d28 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:36:06 +0800 Subject: [PATCH 2415/2794] luawebsitemodules, add account object if available --- baseunits/lua/LuaWebsiteModules.pas | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 98f9648db..27c8e0e66 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -671,6 +671,12 @@ procedure TLuaWebsiteModule.LuaPushMe(L: Plua_State); luaPushIntegerGlobal(L, 'no_error', NO_ERROR); luaPushIntegerGlobal(L, 'net_problem', NET_PROBLEM); luaPushIntegerGlobal(L, 'information_not_found', INFORMATION_NOT_FOUND); + + // account status + luaPushIntegerGlobal(L, 'asUnknown', Integer(asUnknown)); + luaPushIntegerGlobal(L, 'asChecking', Integer(asChecking)); + luaPushIntegerGlobal(L, 'asValid', Integer(asValid)); + luaPushIntegerGlobal(L, 'asInvalid', Integer(asInvalid)); end; procedure TLuaWebsiteModule.LuaDoMe(L: Plua_State); @@ -768,6 +774,19 @@ function lua_getoption(L: Plua_State): Integer; cdecl; (name: nil; func: nil) ); +procedure luaWebsiteModuleAccountAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + with TWebsiteModuleAccount(Obj) do + begin + luaClassAddBooleanProperty(L, MetaTable, 'Enabled', @Enabled); + luaClassAddStringProperty(L, MetaTable, 'Username', @Username); + luaClassAddStringProperty(L, MetaTable, 'Password', @Password); + luaClassAddStringProperty(L, MetaTable, 'Cookies', @Cookies); + luaClassAddIntegerProperty(L, MetaTable, 'Status', @Status); + end; +end; + procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; MetaTable, UserData: Integer; AutoFree: Boolean = False); begin @@ -815,6 +834,9 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddFunction(L, MetaTable, UserData, methods); luaClassAddObject(L, MetaTable, Storage, 'Storage', @luaStringsStorageAddMetaTable); + + if Module.Account<>nil then + luaClassAddObject(L, MetaTable, Module.Account, 'Account', @luaWebsiteModuleAccountAddMetaTable); end; end; From 908cc5da2646316b5348aa2fb3a74e3a3c5f890c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:45:11 +0800 Subject: [PATCH 2416/2794] websitesettings, some flag --- mangadownloader/forms/frmWebsiteSettings.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index b4d211a4e..46ff8734c 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -57,7 +57,9 @@ procedure TWebsiteSettingsForm.FormCreate(Sender: TObject); AutoFullExpand := True; CleanEnumName := True; Header.Columns[0].Width := 300; - TreeOptions.PaintOptions := TreeOptions.PaintOptions + [toThemeAware, toUseExplorerTheme]; + {$if VTMajorVersion < 5} + TreeOptions.PaintOptions := TreeOptions.PaintOptions + [toThemeAware, toUseExplorerTheme, toHotTrack]; + {$endif} end; end; From 6de66e5b1d6d201e06cbd4a8200802eaddb4b4a0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:49:42 +0800 Subject: [PATCH 2417/2794] updatelist, read module settings --- baseunits/uUpdateThread.pas | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 1223ce1e7..735e24fc5 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -387,12 +387,10 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; if Terminated then Break; if ulTotalPtr <> FCurrentGetInfoLimit then ulTotalPtr := FCurrentGetInfoLimit; - if Module.Settings.UpdateListNumberOfThread > 0 then + if Module.Settings.Enabled and (Module.Settings.UpdateListNumberOfThread > 0) then numberOfThreads := Module.Settings.UpdateListNumberOfThread else numberOfThreads := OptionMaxThreads; - if numberOfThreads > OptionMaxThreads then - numberOfThreads := OptionMaxThreads; if numberOfThreads < 1 then numberOfThreads := 1; //default From 7f553e3a28153f710ff6fe5be6eaebb32302140a Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 00:54:29 +0800 Subject: [PATCH 2418/2794] updatelist, udata respect settings enabled --- baseunits/uData.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uData.pas b/baseunits/uData.pas index 09bf71db0..5b4c28313 100644 --- a/baseunits/uData.pas +++ b/baseunits/uData.pas @@ -112,7 +112,7 @@ function TMangaInformation.GetDirectoryPage(var APage: Integer; const AWebsite: APage := 1; //load pagenumber_config if available - if Modules[ModuleId].Settings.UpdateListDirectoryPageNumber > 0 then + if Modules[ModuleId].Settings.Enabled and (Modules[ModuleId].Settings.UpdateListDirectoryPageNumber > 0) then begin APage := Modules[ModuleId].Settings.UpdateListDirectoryPageNumber; BROWSER_INVERT := True; From bba3a9a85d49336cbea0307eb4725be2aa590e86 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Sun, 25 Feb 2018 21:41:07 +0300 Subject: [PATCH 2419/2794] Update Turkish localization Translation updated according to [250d0f0](https://github.com/riderkick/FMD/commit/250d0f051a27bf9e6c7acff2067edfd7e4fa8b8b). --- mangadownloader/languages/fmd.tr_TR.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 4609e3350..c0658a3e7 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -2428,7 +2428,7 @@ msgstr "Website Adı" #: twebsitesettingsform.edsearchproperty.texthint msgid "Setting name" -msgstr "" +msgstr "Ayar ismi" #: udownloadsmanager.rs_compressing msgid "Compressing..." From 841ca62ee5d11e842e8c8ff20fb3e53cf99850ae Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 06:42:16 +0800 Subject: [PATCH 2420/2794] update localization --- mangadownloader/languages/fmd.en.po | 10 +++++----- mangadownloader/languages/fmd.id_ID.po | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 6573d8ef7..1a98a6221 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -565,7 +565,7 @@ msgstr "Refresh" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "AccountManagerForm" #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" @@ -593,7 +593,7 @@ msgstr "Ok" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Account" #: taccountsetform.ckshowpassword.caption msgid "Show password" @@ -2391,15 +2391,15 @@ msgstr "Select a website" #: twebsitesettingsform.caption msgid "WebsiteSettingsForm" -msgstr "" +msgstr "WebsiteSettingsForm" #: twebsitesettingsform.edsearch.texthint msgid "Website name" -msgstr "" +msgstr "Website name" #: twebsitesettingsform.edsearchproperty.texthint msgid "Setting name" -msgstr "" +msgstr "Setting name" #: udownloadsmanager.rs_compressing msgid "Compressing..." diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index 848ca96d1..aabf09417 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -565,7 +565,7 @@ msgstr "Segarkan" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "AccountManagerForm" #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" @@ -593,7 +593,7 @@ msgstr "Ok" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Akun" #: taccountsetform.ckshowpassword.caption msgid "Show password" @@ -2391,15 +2391,15 @@ msgstr "Pilih situs" #: twebsitesettingsform.caption msgid "WebsiteSettingsForm" -msgstr "" +msgstr "WebsiteSettingsForm" #: twebsitesettingsform.edsearch.texthint msgid "Website name" -msgstr "" +msgstr "Nama situs" #: twebsitesettingsform.edsearchproperty.texthint msgid "Setting name" -msgstr "" +msgstr "Nama pengaturan" #: udownloadsmanager.rs_compressing msgid "Compressing..." From a8b4e0820dad0a14662f9beae49a203c07e5624c Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 06:49:47 +0800 Subject: [PATCH 2421/2794] remove temprorary sf handle sf server seems working fine now --- baseunits/DBUpdater.pas | 9 ++--- baseunits/SelfUpdater.pas | 8 ++--- baseunits/SourceForge.pas | 64 ------------------------------------ baseunits/httpsendthread.pas | 2 +- 4 files changed, 6 insertions(+), 77 deletions(-) delete mode 100644 baseunits/SourceForge.pas diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 65f858f68..d70885f96 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -63,7 +63,7 @@ TDBUpdaterThread = class(TBaseThread) implementation -uses FMDVars, SourceForge; +uses FMDVars; function GetDBURL(const AName: String): String; begin @@ -256,11 +256,7 @@ procedure TDBUpdaterThread.Execute; FCurrentName := Items[FCurrentId]; Synchronize(@SyncStartDownload); lurl := GetDBURL(FCurrentName); - if Pos('sourceforge.net', AnsiLowerCase(lurl)) <> 0 then - cont := SourceForge.Download(FHTTP, lurl) - else - cont := FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300); - if cont then + if FHTTP.GET(GetDBURL(FCurrentName)) and (FHTTP.ResultCode < 300) then begin cont := True; // save to data folder @@ -342,6 +338,7 @@ constructor TDBUpdaterThread.Create; FreeOnTerminate := True; FFailedList := TStringList.Create; FHTTP := THTTPSendThread.Create(Self); + FHTTP.UserAgent := UserAgentCURL; FHTTP.Sock.OnStatus := @HTTPSockOnStatus; Items := TStringList.Create; Synchronize(@SyncStart); diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index 1f7332da9..e6f19fa70 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -59,7 +59,7 @@ TSelfUpdaterThread = class(TBaseThread) implementation -uses FMDVars, SourceForge; +uses FMDVars; { TSelfUpdaterThread } @@ -248,11 +248,7 @@ procedure TSelfUpdaterThread.Execute; try FStatusText := Format(RS_Downloading, [UpdateURL]); Synchronize(@SyncStartDownload); - if Pos('sourceforge.net', AnsiLowerCase(UpdateURL)) <> 0 then - DownloadSuccess := SourceForge.Download(FHTTP, UpdateURL) - else - DownloadSuccess := FHTTP.GET(UpdateURL) and (FHTTP.ResultCode < 300); - if DownloadSuccess then + if FHTTP.GET(UpdateURL) and (FHTTP.ResultCode < 300) then begin Filename := FMD_DIRECTORY + UPDATE_PACKAGE_NAME; if FileExists(Filename) then diff --git a/baseunits/SourceForge.pas b/baseunits/SourceForge.pas deleted file mode 100644 index 8b2874e5d..000000000 --- a/baseunits/SourceForge.pas +++ /dev/null @@ -1,64 +0,0 @@ -unit SourceForge; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, httpsendthread; - -function Download(const AHTTP: THTTPSendThread; const AURL: String): Boolean; - -implementation - -uses XQueryEngineHTML, RegExpr, synautil; - -function Download(const AHTTP: THTTPSendThread; const AURL: String): Boolean; -var - s, lurl: String; - ml: TStringList; - fr: Boolean; - i: LongInt; -begin - Result := False; - AHTTP.UserAgent := UserAgentCURL; - if AHTTP.GET(AURL) and (AHTTP.ResultCode < 300) then - begin - // the Sourceforge site is currently in Disaster Recovery mode, and currently requires the use of javascript to function. - if Pos('/#!/', AHTTP.LastURL) <> 0 then - begin - lurl := AHTTP.LastURL; - // load the mirror list - if AHTTP.GET('https://sourceforge.net/js/mirrors.js') then - begin - s := GetBetween('mirror_list = shuffle(',');',ReadStrFromStream(AHTTP.Document, AHTTP.Document.Size)); - ml := TStringList.Create; - try - XPathStringAll('json(.)()("abbr")', s, ml); - fr := AHTTP.FollowRedirection; - AHTTP.FollowRedirection := False; - // 302 means not found? - // keep retry on another mirrors if not found - //while (not Result) and (not AHTTP.ThreadTerminated) and (ml.Count <> 0) do - //begin - i := Random(ml.Count); - Result := AHTTP.GET( - ReplaceRegExpr('^.*/#!/projects/(\w+)/files(/.*?)(/download)?$', lurl, - 'https://' + ml[i] +'.dl.sourceforge.net/project/$1$2', True)) - and (AHTTP.ResultCode < 300); - // if not Result then - // ml.Delete(i); - //end; - AHTTP.FollowRedirection := fr; - finally - ml.Free; - end; - end; - end - else - Result := True; - end; -end; - -end. - diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 5ef71fba7..b076525e5 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -114,7 +114,7 @@ function FormatByteSize(const ABytes: Integer; AShowPerSecond: Boolean = False): const UserAgentSynapse = 'Mozilla/4.0 (compatible; Synapse)'; - UserAgentCURL = 'curl/7.52.1'; + UserAgentCURL = 'curl/7.58.0'; UserAgentGooglebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; http://www.google.com/bot.html)'; UserAgentMSIE = 'Mozilla/5.0 (Windows NT 10.0; Win64; Trident/7.0; rv:11.0) like Gecko'; UserAgentFirefox = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0'; From 6bc70cffded24963efee95b47297822ed4570b65 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 06:53:23 +0800 Subject: [PATCH 2422/2794] Bump version 0.9.149.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index f48623eb4..15b17c1ee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.149.0 (26-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.148.0...0.9.149.0 + 0.9.148.0 (20-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.147.0...0.9.148.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e2b196b20..0d4836f87 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="148"/> + <RevisionNr Value="149"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index ed3727e91..589912e11 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.148.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.148.0/fmd_0.9.148.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.148.0/fmd_0.9.148.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.148.0/fmd_0.9.148.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.148.0/fmd_0.9.148.0_Win64.7z +VERSION=0.9.149.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.149.0/fmd_0.9.149.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.149.0/fmd_0.9.149.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.149.0/fmd_0.9.149.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.149.0/fmd_0.9.149.0_Win64.7z From b84f1c2961450cc85c68e5ccdde156794c04d3d1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 08:29:20 +0800 Subject: [PATCH 2423/2794] destroy startup timer immedietly, may repeat the ontimer if process take longer than the timer interval --- mangadownloader/forms/frmMain.pas | 38 ++++++++++++++++--------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 64931b539..b32774a05 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1757,19 +1757,26 @@ procedure TMainForm.tmRefreshDownloadsInfoTimer(Sender: TObject); procedure TMainForm.tmStartupTimer(Sender: TObject); begin - //load lua modules - ScanLuaWebsiteModulesFile; - AddToAboutStatus('Modules', IntToStr(Modules.Count)); - - Modules.LoadFromFile; - WebsiteOptionCustomForm.CreateWebsiteOption; - WebsiteSettingsForm.LoadWebsiteSettings; - AccountManagerForm.LoadAccounts; - - //load configfile - LoadMangaOptions; - LoadOptions; - ApplyOptions; + try + if Sender is TTimer then + TTimer(Sender).Free; + + //load lua modules + ScanLuaWebsiteModulesFile; + AddToAboutStatus('Modules', IntToStr(Modules.Count)); + + Modules.LoadFromFile; + WebsiteOptionCustomForm.CreateWebsiteOption; + WebsiteSettingsForm.LoadWebsiteSettings; + AccountManagerForm.LoadAccounts; + + //load configfile + LoadMangaOptions; + LoadOptions; + ApplyOptions; + finally + isStartup := False; + end; //restore everything after all modules loaded DLManager.Restore; @@ -1791,11 +1798,6 @@ procedure TMainForm.tmStartupTimer(Sender: TObject); FavoriteManager.CheckForNewChapter; end; DLManager.CheckAndActiveTaskAtStartup; - - if Sender is TTimer then - TTimer(Sender).Free; - - isStartup := False; end; procedure TMainForm.medURLCutClick(Sender: TObject); From 5c54533c6eb6071663c929b2d3a00da90f0ff95e Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 10:00:44 +0800 Subject: [PATCH 2424/2794] webstiteoptions, fix ui --- .../forms/frmWebsiteOptionCustom.pas | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteOptionCustom.pas b/mangadownloader/forms/frmWebsiteOptionCustom.pas index 8458d1a9f..089939d5f 100644 --- a/mangadownloader/forms/frmWebsiteOptionCustom.pas +++ b/mangadownloader/forms/frmWebsiteOptionCustom.pas @@ -84,6 +84,7 @@ TCustomOptionForm = class(TForm) var WebsiteOptionCustomForm: TCustomOptionForm; + downer: TComponent; dparent: TWinControl; tbspace: Cardinal = 6; lrspace: Cardinal = 6; @@ -194,6 +195,7 @@ constructor TComboBoxBindValue.Create(TheOwner: TComponent); procedure TCustomOptionForm.FormCreate(Sender: TObject); begin + downer := self; dparent := Self; with dparent.ChildSizing do begin @@ -269,11 +271,11 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy begin compparent := TGroupBox(Components[i]); with compparent do - if ComponentCount > 0 then + if ControlCount > 0 then begin - compsibling := TControl(Components[ComponentCount - 1]); - for j := ComponentCount - 1 downto 0 do - if SameText(Components[j].Name, lcomp) then + compsibling := TControl(Controls[ControlCount - 1]); + for j := ControlCount - 1 downto 0 do + if SameText(Controls[j].Name, lcomp) then Exit; end; end; @@ -294,7 +296,7 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy if compparent = nil then if lgroup <> '' then begin - compparent := TGroupBox.Create(dparent); + compparent := TGroupBox.Create(downer); SetControlProp(compparent, compparentsibling, dparent, lgroup, lgroupcaption); with compparent.ChildSizing do begin @@ -315,18 +317,18 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy case AOptionItemType of woCheckBox: begin - Result := TCheckBoxBindValue.Create(compparent); + Result := TCheckBoxBindValue.Create(downer); SetControlProp(Result, compsibling, compparent, lcomp, lcompcaption); end; woEdit, woComboBox: begin - lb := TLabel.Create(compparent); + lb := TLabel.Create(downer); SetControlProp(lb, compsibling, compparent, lcomp + 'Lbl', lcompcaption); compsibling := lb; case AOptionItemType of - woEdit : Result := TEditBindValue.Create(compparent); - woComboBox: Result := TComboBoxBindValue.Create(compparent); + woEdit : Result := TEditBindValue.Create(downer); + woComboBox: Result := TComboBoxBindValue.Create(downer); end; SetControlProp(Result, compsibling, compparent, lcomp, ''); with Result do @@ -339,10 +341,10 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy woSpinEdit: begin - Result := TSpinEditBindValue.Create(compparent); + Result := TSpinEditBindValue.Create(downer); SetControlProp(Result, compsibling, compparent, lcomp, lcompcaption); Result.Width := Result.Width + (Result.Width div 4); - lb := TLabel.Create(compparent); + lb := TLabel.Create(downer); SetControlProp(lb, Result, compparent, lcomp + 'Lbl', lcompcaption); with lb do begin @@ -361,6 +363,7 @@ function TCustomOptionForm.AddCheckbox(const ABindValue: PBoolean; ): TWinControl; begin Result := AddOptionItem(woCheckBox, AName, ACaption, AGroup, AGroupCaption); + if Result = nil then Exit; TCheckBoxBindValue(Result).BindValue := ABindValue; end; @@ -369,6 +372,7 @@ function TCustomOptionForm.AddEdit(const ABindValue: PString; ): TWinControl; begin Result := AddOptionItem(woEdit, AName, ACaption, AGroup, AGroupCaption); + if Result = nil then Exit; TEditBindValue(Result).BindValue := ABindValue; end; @@ -377,6 +381,7 @@ function TCustomOptionForm.AddSpinEdit(const ABindValue: PInteger; ): TWinControl; begin Result := AddOptionItem(woSpinEdit, AName, ACaption, AGroup, AGroupCaption); + if Result = nil then Exit; TSpinEditBindValue(Result).BindValue := ABindValue; end; @@ -384,6 +389,7 @@ function TCustomOptionForm.AddComboBox(const ABindValue: PInteger; AName, ACapti AGroup, AGroupCaption, AItems: String): TWinControl; begin Result := AddOptionItem(woComboBox, AName, ACaption, AGroup, AGroupCaption); + if Result = nil then Exit; with TComboBoxBindValue(Result) do begin Items.Text := AItems; @@ -394,18 +400,10 @@ function TCustomOptionForm.AddComboBox(const ABindValue: PInteger; AName, ACapti procedure TCustomOptionForm.CreateWebsiteOption; var i, j: Integer; - c: TComponent; cap: String; begin - while dparent.ComponentCount > 0 do - for i := 0 to dparent.ComponentCount - 1 do - begin - c := dparent.Components[dparent.ComponentCount - 1]; - dparent.RemoveComponent(c); - c.Free; - end; - if Modules = nil then Exit; + dparent.DestroyComponents; if Modules.Count > 0 then for i := 0 to Modules.Count - 1 do with Modules.Module[i] do From a59f29575dab52d0203b084cda03261b3c56d096 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 10:30:39 +0800 Subject: [PATCH 2425/2794] luawebsitemodules, pushnil for non exist option --- baseunits/lua/LuaWebsiteModules.pas | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 27c8e0e66..6da4d8975 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -744,8 +744,9 @@ function lua_getoption(L: Plua_State): Integer; cdecl; begin m := TLuaWebsiteModule(luaClassGetObject(L)); i:=m.Options.IndexOf(lua_tostring(L, 1)); + Result := 1; if i = -1 then - Result := 0 + lua_pushnil(L) else begin o := m.Options.Objects[i]; @@ -759,8 +760,9 @@ function lua_getoption(L: Plua_State): Integer; cdecl; lua_pushinteger(L, TOptionItemSpinEdit(o).Value) else if o is TOptionItemComboBox then - lua_pushinteger(L, TOptionItemComboBox(o).Value); - Result := 1; + lua_pushinteger(L, TOptionItemComboBox(o).Value) + else + lua_pushnil(L); end; end; From ebfd3af46c68533de38b84ce4602d365871e5c54 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 10:36:08 +0800 Subject: [PATCH 2426/2794] websiteoptions, replace exisiting option with the latest added --- .../forms/frmWebsiteOptionCustom.pas | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteOptionCustom.pas b/mangadownloader/forms/frmWebsiteOptionCustom.pas index 089939d5f..597f0b238 100644 --- a/mangadownloader/forms/frmWebsiteOptionCustom.pas +++ b/mangadownloader/forms/frmWebsiteOptionCustom.pas @@ -265,19 +265,17 @@ function TCustomOptionForm.AddOptionItem(const AOptionItemType: TWebsiteOptionTy for i := ComponentCount - 1 downto 0 do begin if SameText(Components[i].Name, lcomp) then - Exit + begin + Result := TWinControl(Components[i]); + Exit; + end else if (Components[i] is TGroupBox) and SameText(Components[i].Name, lgroup) then begin compparent := TGroupBox(Components[i]); with compparent do if ControlCount > 0 then - begin compsibling := TControl(Controls[ControlCount - 1]); - for j := ControlCount - 1 downto 0 do - if SameText(Controls[j].Name, lcomp) then - Exit; - end; end; end; @@ -363,8 +361,8 @@ function TCustomOptionForm.AddCheckbox(const ABindValue: PBoolean; ): TWinControl; begin Result := AddOptionItem(woCheckBox, AName, ACaption, AGroup, AGroupCaption); - if Result = nil then Exit; - TCheckBoxBindValue(Result).BindValue := ABindValue; + if (Result <> nil) and (Result is TCheckBoxBindValue) then + TCheckBoxBindValue(Result).BindValue := ABindValue; end; function TCustomOptionForm.AddEdit(const ABindValue: PString; @@ -372,8 +370,8 @@ function TCustomOptionForm.AddEdit(const ABindValue: PString; ): TWinControl; begin Result := AddOptionItem(woEdit, AName, ACaption, AGroup, AGroupCaption); - if Result = nil then Exit; - TEditBindValue(Result).BindValue := ABindValue; + if (Result <> nil) and (Result is TEditBindValue) then + TEditBindValue(Result).BindValue := ABindValue; end; function TCustomOptionForm.AddSpinEdit(const ABindValue: PInteger; @@ -381,20 +379,20 @@ function TCustomOptionForm.AddSpinEdit(const ABindValue: PInteger; ): TWinControl; begin Result := AddOptionItem(woSpinEdit, AName, ACaption, AGroup, AGroupCaption); - if Result = nil then Exit; - TSpinEditBindValue(Result).BindValue := ABindValue; + if (Result <> nil) and (Result is TSpinEditBindValue) then + TSpinEditBindValue(Result).BindValue := ABindValue; end; function TCustomOptionForm.AddComboBox(const ABindValue: PInteger; AName, ACaption, AGroup, AGroupCaption, AItems: String): TWinControl; begin Result := AddOptionItem(woComboBox, AName, ACaption, AGroup, AGroupCaption); - if Result = nil then Exit; - with TComboBoxBindValue(Result) do - begin - Items.Text := AItems; - TComboBoxBindValue(Result).BindValue := ABindValue; - end; + if (Result <> nil) and (Result is TComboBoxBindValue) then + with TComboBoxBindValue(Result) do + begin + Items.Text := AItems; + TComboBoxBindValue(Result).BindValue := ABindValue; + end; end; procedure TCustomOptionForm.CreateWebsiteOption; From 103cb278de3679e6cba2d9061e27fecccb65970b Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 12:10:31 +0800 Subject: [PATCH 2427/2794] httpsendthread added onredirected event can be used to update progress on ui --- baseunits/httpsendthread.pas | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index b076525e5..289fef6ab 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -48,6 +48,8 @@ THTTPSendThread = class; THTTPRequestEvent = function(const AHTTP: THTTPSendThread; const Method, URL: String; const Response: TObject = nil): Boolean of object; + THTTPMethodRedirectEvent = procedure(const AHTTP: THTTPSendThread; const URL: String) of object; + { THTTPSendThread } THTTPSendThread = class(THTTPSend) @@ -94,6 +96,7 @@ THTTPSendThread = class(THTTPSend) BeforeHTTPMethod: THTTPMethodEvent; AfterHTTPMethod: THTTPMethodEvent; OnHTTPRequest: THTTPRequestEvent; + OnRedirected: THTTPMethodRedirectEvent; property LastURL: String read FURL; end; @@ -531,6 +534,9 @@ function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: FURL:=h+s; end; + if OnRedirected<>nil then + OnRedirected(Self, FURL); + Clear; Headers.Assign(HTTPHeader); counter := 0; From 5c51bc867512ae049487de37e6c9c16dbe7198d0 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 12:11:03 +0800 Subject: [PATCH 2428/2794] dbupdater, selfupdate, show redirected url --- baseunits/DBUpdater.pas | 9 +++++++++ baseunits/SelfUpdater.pas | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index d70885f96..8517c0bbd 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -28,6 +28,7 @@ TDBUpdaterThread = class(TBaseThread) procedure ButtonCancelClick(Sender: TObject); procedure HTTPSockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); + procedure HTTPRedirected(const AHTTP: THTTPSendThread; const URL: String); protected procedure SyncStart; procedure SyncFinal; @@ -100,6 +101,13 @@ procedure TDBUpdaterThread.HTTPSockOnStatus(Sender: TObject; end; end; +procedure TDBUpdaterThread.HTTPRedirected(const AHTTP: THTTPSendThread; + const URL: String); +begin + UpdateStatusText(Format('[%d/%d] ' + RS_Downloading, + [FCurrentId + 1, Items.Count, FCurrentName + DBDATA_EXT + ' ' + URL])); +end; + procedure TDBUpdaterThread.SyncStart; begin DBUpdaterThread := Self; @@ -340,6 +348,7 @@ constructor TDBUpdaterThread.Create; FHTTP := THTTPSendThread.Create(Self); FHTTP.UserAgent := UserAgentCURL; FHTTP.Sock.OnStatus := @HTTPSockOnStatus; + FHTTP.OnRedirected:=@HTTPRedirected; Items := TStringList.Create; Synchronize(@SyncStart); end; diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index e6f19fa70..0757e328e 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -26,6 +26,7 @@ TSelfUpdaterThread = class(TBaseThread) procedure ButtonCancelClick(Sender: TObject); procedure HTTPSockOnStatus(Sender: TObject; Reason: THookSocketReason; const Value: String); + procedure HTTPRedirected(const AHTTP: THTTPSendThread; const URL: String); protected procedure SyncStart; procedure SyncFinal; @@ -88,6 +89,12 @@ procedure TSelfUpdaterThread.HTTPSockOnStatus(Sender: TObject; end; end; +procedure TSelfUpdaterThread.HTTPRedirected(const AHTTP: THTTPSendThread; + const URL: String); +begin + UpdateStatusText(Format(RS_Downloading, [URL])); +end; + procedure TSelfUpdaterThread.SyncStart; begin SelfUpdaterThread := Self; @@ -296,6 +303,7 @@ constructor TSelfUpdaterThread.Create; FHTTP := THTTPSendThread.Create(Self); FHTTP.UserAgent := UserAgentCURL; FHTTP.Sock.OnStatus := @HTTPSockOnStatus; + FHTTP.OnRedirected := @HTTPRedirected; Synchronize(@SyncStart); end; From 2de92cd93ecc3da528e5328ef841f62b4ae3a444 Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Sun, 25 Feb 2018 23:38:13 -0500 Subject: [PATCH 2429/2794] add Nightow, TrueColors & change Seinagi to https (#1052) * add Nightow, TrueColors & change Seinagi to https --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 3ef3c2cf6..68f680f05 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -234,7 +234,7 @@ function Init() AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com', cat) AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) - AddWebsiteModule('SeinagiFansub', 'http://seinagi.org', cat) + AddWebsiteModule('SeinagiFansub', 'https://seinagi.org', cat) AddWebsiteModule('SeinagiAdultoFansub', 'https://adulto.seinagi.org', cat) AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net', cat) AddWebsiteModule('RavensScans', 'http://ravens-scans.com', cat) @@ -245,4 +245,6 @@ function Init() AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) + AddWebsiteModule('Nightow', 'http://nightow.net', cat) + AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) end From f84e2ad4df1beffd07768255e007fbda827fe180 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 14:44:59 +0800 Subject: [PATCH 2430/2794] luabaseunit, register streamtostring method --- baseunits/lua/LuaBaseUnit.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index bef1cd137..8be3c5cb3 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -110,6 +110,17 @@ function lua_incstr(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_streamtostring(L: Plua_State): Integer; cdecl; +begin + if lua_isuserdata(L, 1) then + begin + lua_pushstring(L, StreamToString(TStream(luaGetUserData(L,1)))); + Result := 1; + end + else + Result := 0; +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -125,6 +136,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'HTMLDecode', @lua_htmldecode); luaPushFunctionGlobal(L, 'URLDecode', @lua_urldecode); luaPushFunctionGlobal(L, 'IncStr', @lua_incstr); + luaPushFunctionGlobal(L, 'StreamToString', @lua_streamtostring); end; end. From dafb01c5a601155fdbe8988fc21064f9507d7a3b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 26 Feb 2018 10:50:44 +0300 Subject: [PATCH 2431/2794] add HeavenManga [EN] fixes #1043 --- lua/modules/HeavenManga.lua | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 lua/modules/HeavenManga.lua diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua new file mode 100644 index 000000000..a402debcc --- /dev/null +++ b/lua/modules/HeavenManga.lua @@ -0,0 +1,78 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="comic-info"]/div/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="comic-info"]/div/img/@src')) + mangainfo.authors=x.xpathstringall('//div[@class="comic-info"]//div[@class="author"]/a') + mangainfo.genres=x.xpathstringall('//div[@class="comic-info"]//div[@class="genre"]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="comic-info"]//div[@class="update"]/span[last()]')) + mangainfo.summary=x.xpathstring('//div[@class="comic-description"]/p') + local pages = tonumber(x.xpathstring('(//div[@class="pagination"]/a[contains(@class, "page-numbers")])[last()]/substring-after(@href, "/page-")')) + if pages == nil then pages = 1 end + local p = 1 + while true do + local v=x.xpath('//div[contains(@class, "chapters-wrapper")]//h2[@class="chap"]/a') + for i=1,v.count do + local v1=v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + mangainfo.chapternames.add(x.xpathstring('text()', v1)) + end + p = p + 1 + if p > pages then break end + if http.get(mangainfo.url .. '/page-' .. tostring(p)) then + x=TXQuery.Create(http.document) + else + break + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + x=TXQuery.Create(http.Document) + v=x.xpathstringall('//div[@class="chapter-content"]//img/@src', task.pagelinks) + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/manga-list/') then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('(//div[@class="pagination"]/a[contains(@class, "page-numbers")])[last()]/substring-after(@href, "/page-")')) + if page == nil then pages = 1 end + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl .. '/manga-list/page-' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@class="comics-grid"]/div/div/h3/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'HeavenManga' + m.rooturl = 'http://heavenmanga.club' + m.category = 'English' + m.lastupdated='February 26, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end From aaa7588f50b357d9ea437eb5e1342dbedc493542 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 16:05:19 +0800 Subject: [PATCH 2432/2794] luabaseunit, register round --- baseunits/lua/LuaBaseUnit.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 8be3c5cb3..795d3fa54 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -121,6 +121,12 @@ function lua_streamtostring(L: Plua_State): Integer; cdecl; Result := 0; end; +function lua_round(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, round(lua_tonumber(L, 1))); + Result := 1; +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -137,6 +143,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'URLDecode', @lua_urldecode); luaPushFunctionGlobal(L, 'IncStr', @lua_incstr); luaPushFunctionGlobal(L, 'StreamToString', @lua_streamtostring); + luaPushFunctionGlobal(L, 'Round', @lua_round); end; end. From ca09cbaee0cd45c5d39e64c38aecde9d148bcf00 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 16:05:35 +0800 Subject: [PATCH 2433/2794] luawebsitemodules, register tag --- baseunits/lua/LuaWebsiteModules.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 6da4d8975..ae894117e 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -839,6 +839,8 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; if Module.Account<>nil then luaClassAddObject(L, MetaTable, Module.Account, 'Account', @luaWebsiteModuleAccountAddMetaTable); + + luaClassAddIntegerProperty(L, MetaTable, 'Tag', @Module.Tag); end; end; From 28f9e8a0d360766bdc444c5427ae0d05424d8525 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 18:45:13 +0800 Subject: [PATCH 2434/2794] remove mangadex --- baseunits/ModuleList.inc | 1 - baseunits/modules/Mangadex.pas | 183 --------------------------------- 2 files changed, 184 deletions(-) delete mode 100644 baseunits/modules/Mangadex.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 8229d0ebc..5307f7c4e 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -54,7 +54,6 @@ uses TruyenTranhTuan, BlogTruyen, MangaAe, - Mangadex, MangaTube, Mangaf, MangaRock, diff --git a/baseunits/modules/Mangadex.pas b/baseunits/modules/Mangadex.pas deleted file mode 100644 index e7908e9e9..000000000 --- a/baseunits/modules/Mangadex.pas +++ /dev/null @@ -1,183 +0,0 @@ -unit Mangadex; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr, FMDVars; - -implementation - -const - PerPage = 100; - -var - showalllang: Boolean = False; - showscangroup: Boolean = False; - -resourcestring - RS_ShowAllLang = 'Show all language'; - RS_ShowScanGroup = 'Show scanlation group'; - -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; - - procedure AddChapters(x: TXQueryEngineHTML); - var - s, lang, group: String; - v: IXQValue; - begin - if showalllang then - s := '//div[contains(@class, "tab-content")]//table/tbody/tr/td[1]/a' - else - s := '//div[contains(@class, "tab-content")]//table/tbody/tr[td[2]/img/@title="English"]/td[1]/a'; - for v in x.XPath(s) do begin - MangaInfo.mangaInfo.chapterLinks.Add(v.toNode().getAttribute('href')); - s := v.toString(); - if showalllang then begin - lang := x.XPathString('parent::td/parent::tr/td[2]/img/@title', v); - if lang <> '' then s := s + ' [' + lang + ']'; - end; - if showscangroup then begin - group := x.XPathString('parent::td/parent::tr/td[3]/a', v); - if group <> '' then s := s + ' [' + group + ']'; - end; - MangaInfo.mangaInfo.chapterName.Add(s); - end; - end; - -var - x: TXQueryEngineHTML; - s: String; - pages, i: Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - Cookies.Values['mangadex_h_toggle'] := '1'; - if GET(url) then begin - Result := NO_ERROR; - x := TXQueryEngineHTML.Create(Document); - try - if title = '' then title := x.XPathString('//h3[@class="panel-title"]/text()'); - if Pos('emailprotected', title) > 0 then - title := Trim(ReplaceString(x.XPathString('//title'), '(Manga) - MangaDex', '')); - coverLink := MaybeFillHost(Module.RootURL, x.XPathString('//img[@alt="Manga image"]/@src')); - authors := x.XPathString('//th[contains(., "Author")]/following-sibling::td/a'); - artists := x.XPathString('//th[contains(., "Artist")]/following-sibling::td/a'); - genres := x.XPathStringAll('//th[contains(., "Genres")]/following-sibling::td/span'); - summary := x.XPathString('//th[contains(., "Description")]/following-sibling::td'); - status := MangaInfoStatusIfPos(x.XPathString('//th[contains(., "Status")]/following-sibling::td')); - s := x.XPathString('//ul[@class="pagination"]/li[last()]/a/@href'); - s := RegExprGetMatch('\/(\d+)$', Trim(s), 1); - pages := StrToIntDef(s, 0) div PerPage; - AddChapters(x); - finally - x.Free; - end; - - for i := 1 to pages do - if GET(url + '/' + IntToStr(i * PerPage)) then begin - if MangaInfo.Thread.IsTerminated then Break; - x := TXQueryEngineHTML.Create(Document); - try - AddChapters(x); - finally - x.Free; - end; - end; - - InvertStrings([chapterLinks, chapterName]); - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s, dataurl, server, pages: String; - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - Cookies.Values['mangadex_h_toggle'] := '1'; - if GET(MaybeFillHost(Module.RootURL, AURL)) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - s := XPathString('//script[contains(., "var page_array")]'); - dataurl := GetBetween('var dataurl = ''', ''';', s); - server := GetBetween('var server = ''', ''';', s); - pages := '[' + GetBetween('var page_array = [', '];', s) + ']'; - ParseHTML(pages); - for v in XPath('json(*)()') do - PageLinks.Add(MaybeFillHost(Module.RootURL, server + dataurl + '/' + v.toString)); - finally - Free; - end; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - s, p: String; -begin - Result := NET_PROBLEM; - if Module.CurrentDirectoryIndex = 0 then - s := '~' - else - s := ALPHA_LIST_UP[Module.CurrentDirectoryIndex + 1]; - p := IntToStr(StrToInt(AURL) * PerPage); - MangaInfo.FHTTP.Cookies.Values['mangadex_h_toggle'] := '1'; - if MangaInfo.FHTTP.GET(Module.RootURL + '/titles/' + s + '/' + p) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - if AURL = '0' then begin - updateList.CurrentDirectoryPageNumber := 1; - s := XPathString('//li[@class="paging"]/a[contains(span/@title, "last")]/@href'); - if s <> '' then begin - s := ReplaceRegExpr('^.+\/(\d+)$', s, '$1', True); - updateList.CurrentDirectoryPageNumber := (StrToIntDef(s, 0) div PerPage) + 1; - end; - end; - XPathHREFAll('//table/tbody/tr/td[2]/a', ALinks, ANames); - finally - Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do begin - Website := 'Mangadex'; - RootURL := 'https://mangadex.com'; - Category := 'English'; - MaxTaskLimit := 4; - MaxConnectionLimit := 4; - TotalDirectory := Length(ALPHA_LIST_UP); - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetNameAndLink := @GetNameAndLink; - AddOptionCheckBox(@showalllang,'ShowAllLang', @RS_ShowAllLang); - AddOptionCheckBox(@showscangroup,'ShowScanGroup', @RS_ShowScanGroup); - end; -end; - -initialization - RegisterModule; - -end. - From ba184dca10392f0e344279e5723c12733d57c2d6 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 19:29:50 +0800 Subject: [PATCH 2435/2794] retrieve orinal title from downloads / favorites so custom rename can remove them #1049 --- baseunits/uFavoritesManager.pas | 2 +- mangadownloader/forms/frmMain.pas | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index f94fde611..d0cd128ac 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -249,7 +249,7 @@ procedure TFavoriteThread.Execute; try // get new manga info FMangaInformation.isGetByUpdater := False; - FMangaInformation.mangaInfo.title := FavoriteInfo.Title; + //FMangaInformation.mangaInfo.title := FavoriteInfo.Title; // retrieve the original title so custom rename can remove them FMangaInformation.GetInfoFromURL(FavoriteInfo.Website, FavoriteInfo.Link); if not Terminated then begin diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index b32774a05..898f7f339 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4746,7 +4746,10 @@ procedure TMainForm.ViewMangaInfo(const ALink, AWebsite, ATitle, ASaveTo: String // start the thread GetInfosThread := TGetMangaInfosThread.Create; GetInfosThread.MangaListNode := AMangaListNode; - GetInfosThread.Title := ATitle; + if (ASender = miDownloadViewMangaInfo) or (ASender = miFavoritesViewInfos) then + GetInfosThread.Title := '' // retrieve the original title so custom rename can remove them + else + GetInfosThread.Title := ATitle; GetInfosThread.Website := AWebsite; GetInfosThread.Link := ALink; GetInfosThread.Start; From 69ee281336c864524bea42325f42fe20367f3644 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 19:36:21 +0800 Subject: [PATCH 2436/2794] Bump version 0.9.150.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 15b17c1ee..db0224f7c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.150.0 (26-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.149.0...0.9.150.0 + 0.9.149.0 (26-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.148.0...0.9.149.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 0d4836f87..e9244c415 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="149"/> + <RevisionNr Value="150"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 589912e11..7bd58129e 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.149.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.149.0/fmd_0.9.149.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.149.0/fmd_0.9.149.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.149.0/fmd_0.9.149.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.149.0/fmd_0.9.149.0_Win64.7z +VERSION=0.9.150.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.150.0/fmd_0.9.150.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.150.0/fmd_0.9.150.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.150.0/fmd_0.9.150.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.150.0/fmd_0.9.150.0_Win64.7z From a321cf6475ddd396e94e7c9e3002fe34cbbf1a7f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 20:59:45 +0800 Subject: [PATCH 2437/2794] Revert "lua, parsehtml temp patch #1027 #1035" This reverts commit 15e56b3e0044b78299348b88b8cc9709d2889b59. --- lua/modules/LHTranslation.lua | 3 +-- lua/modules/MangaSh.lua | 3 +-- lua/modules/WPManga.lua | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index c8380a681..4ad41b7db 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -19,8 +19,7 @@ function GetPageNumber() if http.GET(MaybeFillHost(module.rooturl, url)) then x=TXQuery.Create(http.document) if http.get(x.xpathstring('//div[@class="commentmetadata"][1]/p/a/@href')) then - --x.parsehtml(http.document) - x=TXQuery.Create(http.document) + x.parsehtml(http.document) x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) return true end diff --git a/lua/modules/MangaSh.lua b/lua/modules/MangaSh.lua index 1126fc6cb..fe2e940e9 100644 --- a/lua/modules/MangaSh.lua +++ b/lua/modules/MangaSh.lua @@ -17,8 +17,7 @@ function getinfo() mangainfo.genres=x.xpathstring('string-join((TypeName,TypeDemonym,SeriesTags/TagName),", ")', v) mangainfo.summary=HTMLDecode(x.xpathstring('Description', v)) if http.get(apiurl..'series_chapters?query=SeriesId.Id:'..lid..'&order=desc&sortby=TimeUploaded&limit=0&offset=0') then - --x.parsehtml(http.document) - x=TXQuery.Create(http.document) + x.parsehtml(http.document) local s='json(.)("response")()' local lname='' local showalllang=module.getoption('showalllang') diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 0dacedffd..bf8ba457b 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -36,8 +36,7 @@ function getinfo() s = Trim(x.XPathString('//*[@class="pgg"]//*[./a[@class="sel"]]/following-sibling::*[./a]/a/@href')) if s == '' then break end if http.GET(MaybeFillHost(module.rooturl, s)) then - x=TXQuery.Create(http.document) - --x.ParseHTML(http.document) + x.ParseHTML(http.Document) else break end @@ -74,8 +73,7 @@ function getpagenumber() -- single page if task.PageLinks.Count == 0 then - --x.ParseHTML(http.Document) - x=TXQuery.Create(http.document) + x.ParseHTML(http.Document) task.PageNumber = x.XPath('(//select[@class="cbo_wpm_pag"])[1]/option').Count if task.PageNumber == 0 then task.PageNumber = x.XPath('(//select[@name="page"])[1]/option').Count From 3d28fa66933b044f27120b3559d5fbc4cddaaf31 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 21:01:57 +0800 Subject: [PATCH 2438/2794] add mangadex --- lua/modules/MangaDex.lua | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 lua/modules/MangaDex.lua diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua new file mode 100644 index 000000000..ef7547b14 --- /dev/null +++ b/lua/modules/MangaDex.lua @@ -0,0 +1,105 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + if mangainfo.title=='' then mangainfo.title=x.xpathstring('//meta[@property="og:title"]/replace(@content,"\\s\\(\\w+\\)\\s-\\sMangaDex$","")') end + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//img[@title="Manga image"]/@src')) + mangainfo.authors=x.xpathstring('//tr[./th="Author:"]/string-join(./td,", ")') + mangainfo.artists=x.xpathstring('//tr[./th="Artist:"]/string-join(./td,", ")') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[./th="Status:"]')) + mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') + local l='//*[@id="chapters"]//tr[@id]' + local n='' + if module.getoption('showalllang') then + n='/concat(.," [",../td[2]/img/@title,"]"' + else + l=l..'[./td/img[@title="English"]]' + end + if module.getoption('showscangroup') then + if n=='' then n='/concat(.' end + n=n..'," [",../td[3],"]"' + end + l=l..'/td[1]' + if n~='' then n=n..')' end + n=l..n + l=l..'/a/@href' + local nurl='' + while true do + x.xpathstringall(l,mangainfo.chapterlinks) + x.xpathstringall(n,mangainfo.chapternames) + if http.terminated then break end + nurl=x.xpathstring('//ul[@class="pagination"]/li[@class="active"]/following-sibling::li[@class="paging"]/a/@href') + if nurl=='' then break end + if http.get(MaybeFillHost(module.rooturl,nurl)) then + x.parsehtml(http.document) + else + break + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + local s=StreamToString(http.document) + local lurl=AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/' + local page_array=GetBetween('var page_array = [','];',s) + task.pagelinks.commatext=GetBetween('var page_array = [','];',s):gsub('\'','') + for i=0,task.pagelinks.count-1 do + task.pagelinks[i]=lurl..task.pagelinks[i] + end + return true + else + return false + end + return true +end + +local dirurl='/titles' + +function getdirectorypagenumber() + if http.get(module.rooturl..dirurl) then + x=TXQuery.Create(http.document) + local perpage=tonumber(RegExprGetMatch('/(\\d+)$',x.xpathstring('//ul[@class="pagination"]/li[@class="active"]/following-sibling::li[@class="paging"]/a/@href'),1)) + local lastpage=tonumber(RegExprGetMatch('/(\\d+)$',x.xpathstring('//ul[@class="pagination"]/li[@class="paging"][last()]/a/@href'),1)) + if perpage==nil then perpage=100 end + if lastpage==nil then lastpage=perpage end + module.tag=perpage + page=Round(lastpage/perpage)+1 + return true + else + return false + end +end + +function getnameandlink() + local lurl=dirurl + if url~='0' then + lurl=lurl..'/'..tostring(module.tag*tonumber(url)) + end + if http.GET(module.rooturl..lurl) then + TXQuery.Create(http.document).xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='English' + m.website='MangaDex' + m.rooturl='https://mangadex.com' + m.lastupdated='February 26, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + + m.addoptioncheckbox('showalllang', 'Show all language', false) + m.addoptioncheckbox('showscangroup', 'Show scanlation group', false) +end From 4bc80dd1f761b9c4184817bef0286507d96027bd Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Mon, 26 Feb 2018 21:09:56 +0800 Subject: [PATCH 2439/2794] mangadex, default task limit 1, connection 2 --- lua/modules/MangaDex.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index ef7547b14..17663f171 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -99,6 +99,9 @@ function Init() m.ongetpagenumber='getpagenumber' m.ongetdirectorypagenumber='getdirectorypagenumber' m.ongetnameandlink='getnameandlink' + + m.maxtasklimit=1 + m.maxconnectionlimit=2 m.addoptioncheckbox('showalllang', 'Show all language', false) m.addoptioncheckbox('showscangroup', 'Show scanlation group', false) From faa93c3eff534c9fb822e5a868f24576c85f9215 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 26 Feb 2018 15:59:57 +0300 Subject: [PATCH 2440/2794] add TenManga [EN] --- lua/modules/TenManga.lua | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 lua/modules/TenManga.lua diff --git a/lua/modules/TenManga.lua b/lua/modules/TenManga.lua new file mode 100644 index 000000000..45a977a62 --- /dev/null +++ b/lua/modules/TenManga.lua @@ -0,0 +1,85 @@ +local ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if Pos('waring', url) == 0 then mangainfo.url = mangainfo.url .. '?waring=1' end + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="book-info"]/h1/substring-before(., " Manga")') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="book-info"]//img/@src')) + mangainfo.authors=x.xpathstringall('//dd[@class="about-book"]/p[contains(span, "Author")]/a') + mangainfo.genres=x.xpathstringall('//div[@class="book-info"]/ul/li[position()>1]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//dd[@class="about-book"]/p[contains(span, "Status")]/a')) + mangainfo.summary=x.xpathstring('//dd[@class="short-info"]/p/span') + local v=x.xpath('//ul[@class="chapter-box"]/li/div[@class="chapter-name long"]/a') + for i=1,v.count do + local v1=v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + mangainfo.chapternames.add(x.xpathstring('text()', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + task.pagenumber=TXQuery.Create(http.Document).xpathcount('(//select[@class="sl-page"])[1]/option') + module.storage.text = http.cookies.text + print(module.storage.text) + else + return false + end + return true +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getimageurl() + http.headers.values['Referer'] = module.rooturl + http.cookies.text = module.storage.text + if http.get(MaybeFillHost(module.rooturl,url):gsub('/?$','-'..(workid+1)..'.html')) then + task.pagelinks[workid]=TXQuery.create(http.document).xpathstring('//img[contains(@class, "manga_pic")]/@src') + return true + end + return false +end + +function getnameandlink() + local s = '0-9' + if module.CurrentDirectoryIndex ~= 0 then + s = ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) + end + if http.get(module.rooturl .. '/category/' .. s .. '_views_' .. IncStr(url) .. '.html') then + local x = TXQuery.Create(http.Document) + local q = '//ul[@id="list_container"]/li/dl/dt/a' + x.XPathHREFtitleAll(q, links, names) + if x.xpathcount(q) > 0 then + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'TenManga' + m.rooturl = 'http://www.tenmanga.com' + m.category = 'English' + m.lastupdated='February 26, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetimageurl='getimageurl' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' + m.totaldirectory = ALPHA_LIST_UP:len() +end From 84901879efcc6f1f5988dd6f804e8db2be3d2008 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 27 Feb 2018 06:36:52 +0800 Subject: [PATCH 2441/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index e3c04bba8..2bef77944 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit e3c04bba823f294834675ad9c9095552c72194f8 +Subproject commit 2bef7794450ec27c25530fa0e502edf14ab69e7d From eb1a1d32557cb96cd70e7627114f5edf1d0dc4fe Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 27 Feb 2018 06:24:23 +0300 Subject: [PATCH 2442/2794] Madokami, fix Login fixes #1056 --- baseunits/modules/Madokami.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/Madokami.pas b/baseunits/modules/Madokami.pas index 435a43ad8..d5b9e6434 100644 --- a/baseunits/modules/Madokami.pas +++ b/baseunits/modules/Madokami.pas @@ -39,13 +39,14 @@ function Login(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Bo begin Result := False; if Module.Account.Enabled = False then Exit; - if Module.Account.Username = '' then Exit; + if (Module.Account.Username = '') or (Module.Account.Password = '') then Exit; if TryEnterCriticalsection(locklogin) > 0 then try Module.Account.Status := asChecking; AHTTP.Reset; AHTTP.Cookies.Clear; - madokamiauth := 'Authorization: Basic ' + Base64Encode(Module.Account.Username); + madokamiauth := 'Authorization: Basic ' + + Base64Encode(Module.Account.Username + ':' + Module.Account.Password); AHTTP.Headers.Add(madokamiauth); if AHTTP.GET(urlroot) then begin //Result := AHTTP.Cookies.Values['laravel_session'] <> ''; From acf71925ff75c9e7874368286146bb85b1c42246 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 27 Feb 2018 13:52:12 +0800 Subject: [PATCH 2443/2794] mangadex, change option name to avoid error with previous version --- lua/modules/MangaDex.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 17663f171..1a921d6a0 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -10,12 +10,12 @@ function getinfo() mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') local l='//*[@id="chapters"]//tr[@id]' local n='' - if module.getoption('showalllang') then + if module.getoption('luashowalllang') then n='/concat(.," [",../td[2]/img/@title,"]"' else l=l..'[./td/img[@title="English"]]' end - if module.getoption('showscangroup') then + if module.getoption('luashowscangroup') then if n=='' then n='/concat(.' end n=n..'," [",../td[3],"]"' end @@ -103,6 +103,6 @@ function Init() m.maxtasklimit=1 m.maxconnectionlimit=2 - m.addoptioncheckbox('showalllang', 'Show all language', false) - m.addoptioncheckbox('showscangroup', 'Show scanlation group', false) + m.addoptioncheckbox('luashowalllang', 'Show all language', false) + m.addoptioncheckbox('luashowscangroup', 'Show scanlation group', false) end From e4f94b641e005afae83c4866ee985239ac9fd9a4 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 27 Feb 2018 14:28:47 +0800 Subject: [PATCH 2444/2794] favoritelist, disable coloring on disabled item (closed #1061) --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 898f7f339..261483e05 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -4183,6 +4183,7 @@ procedure TMainForm.vtFavoritesBeforeCellPaint(Sender: TBaseVirtualTree; if CellPaintMode <> cpmPaint then Exit; with TargetCanvas, FavoriteManager.Items[Node^.Index] do begin + if not Enabled then Exit; C := Brush.Color; Brush.Color := clNone; if Trim(FavoriteInfo.Link) = '' then From e3e997f275f945d934a98bb1e50ed078f8b52a0f Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Tue, 27 Feb 2018 14:36:19 +0800 Subject: [PATCH 2445/2794] luabase, register sleep --- baseunits/lua/LuaBase.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 5a7dc1f08..bc9a04e31 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -34,9 +34,16 @@ function luabase_print(L: Plua_State): Integer; cdecl; Logger.Send(lua_tostring(L, i)); end; +function luabase_sleep(L: Plua_State): Integer; cdecl; +begin + Result := 0; + Sleep(lua_tointeger(L, 1)); +end; + procedure LuaBaseRegister(L: Plua_State); begin lua_register(L, 'print', @luabase_print); + lua_register(L, 'Sleep', @luabase_sleep); luaBaseUnitRegister(L); luaRegExprRegister(L); From 7032f0086d946d1c46a5dbfb7acd249ba82276e1 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Tue, 27 Feb 2018 10:09:57 +0300 Subject: [PATCH 2446/2794] Improve Turkish localization Improved translation, made them more generic. --- mangadownloader/languages/fmd.tr_TR.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index c0658a3e7..3b612d3ed 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -171,7 +171,7 @@ msgstr "İndiriliyor..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" msgid "%s DELETE*" -msgstr "%s SİL*" +msgstr "%s SİLİNDİ*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" @@ -186,12 +186,12 @@ msgstr "%s YENİ*" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "%s TEKRAR İNDİR*" +msgstr "%s TEKRAR İNDİRME*" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" msgid "%s UPDATE*" -msgstr "%s GÜNCELLE*" +msgstr "%s GÜNCELLENDİ*" #: frmmain.rs_alldownloads msgid "All downloads" @@ -295,9 +295,9 @@ msgid "" "Ongoing\n" "<none>\n" msgstr "" -"Tamamlanmış\n" -"Devam eden\n" -"<hiçbiri>\n" +"Tamamlandı\n" +"Devam Ediyor\n" +"<Hiçbiri>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" From 8087f599bdde54ad55cdeda598d565228fe53e0d Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Tue, 27 Feb 2018 05:01:07 -0500 Subject: [PATCH 2447/2794] Update FoOlSlide.lua Add Scan MangajinNoFansub --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 68f680f05..e6531b9e4 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -45,7 +45,8 @@ function getdirurl(website) ['AntisenseScans'] = dirurlonline, ['MangaichiScan'] = dirurlfsdir, ['Riceballicious'] = dirurlreaderlist, - ['Yuri-ism'] = dirurlslide + ['Yuri-ism'] = dirurlslide, + ['MangajinNoFansub'] = dirurllector } if dirs[website] ~= nil then return dirs[website] @@ -247,4 +248,5 @@ function Init() AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) AddWebsiteModule('Nightow', 'http://nightow.net', cat) AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) + AddWebsiteModule('MangajinNoFansub', 'https://www.mangajinnofansub.com', cat) end From 87399d5ac89033558ccad8695dbf7e885bbb47a7 Mon Sep 17 00:00:00 2001 From: Havokdan <havokdan@yahoo.com.br> Date: Tue, 27 Feb 2018 08:11:08 -0300 Subject: [PATCH 2448/2794] Update fmd.pt_BR.po --- mangadownloader/languages/fmd.pt_BR.po | 341 +++++++++---------------- 1 file changed, 124 insertions(+), 217 deletions(-) diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 7dd25ce79..0099c9de2 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -1,45 +1,35 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=utf-8\n" -"Project-Id-Version: \n" -"POT-Creation-Date: \n" -"PO-Revision-Date: \n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Transfer-Encoding: 8bit\n" -"Language: pt-BR\n" -"X-Generator: Poedit 2.0.1\n" -"Plural-Forms: \n" +"Last-Translator: Havokdan <havokdan@yahoo.com.br>\n" #: dbupdater.rs_buttoncancel -#| msgid "Cancel" msgctxt "dbupdater.rs_buttoncancel" msgid "Abort" -msgstr "Cancelar" +msgstr "Abortar" #: dbupdater.rs_downloading msgid "Downloading %s" -msgstr "" +msgstr "Baixando %s" #: dbupdater.rs_extracting msgid "Extracting %s" -msgstr "" +msgstr "Extraindo %s" #: dbupdater.rs_faileddownload msgid "%s: %d %s" -msgstr "" +msgstr "%s: %d %s" #: dbupdater.rs_failedextract msgid "%s: failed to extract, exitstatus = %d" -msgstr "" +msgstr "%s: falhou ao extrair, exitstatus = %d" #: dbupdater.rs_faileditems msgid "" "Failed to finish:\n" "\n" "%s\n" -msgstr "" +msgstr "Falha ao terminar:\n\n%s\n" #: dbupdater.rs_faileditemstitle msgctxt "dbupdater.rs_faileditemstitle" @@ -48,18 +38,17 @@ msgstr "Falhou" #: dbupdater.rs_failedtosave msgid "%s: failed to save" -msgstr "" +msgstr "%s: falhou ao salvar" #: dbupdater.rs_missingzipexe msgid "%s: Missing %s" -msgstr "" +msgstr "%s: Faltando %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" msgstr "Baixar imagem original (exige uma conta ExHentai)" #: ehentai.rs_settingsimagesize -#| msgid "Image size" msgid "Image size:" msgstr "Tam. da imagem:" @@ -72,14 +61,7 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "" -"Auto\n" -"780x\n" -"980x\n" -"1280x\n" -"1600x\n" -"2400x\n" -"Original\n" +msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -123,66 +105,66 @@ msgstr "Checando..." #: frmluamodulesupdater.rs_checkupdate msgctxt "frmluamodulesupdater.rs_checkupdate" msgid "Check update" -msgstr "" +msgstr "Checar por atualização" #: frmluamodulesupdater.rs_finishchecking msgid "Finish checking" -msgstr "" +msgstr "Terminar de checar" #: frmluamodulesupdater.rs_finishdownload msgid "Finish download" -msgstr "" +msgstr "Terminar donwload" #: frmluamodulesupdater.rs_modulesupdatedrestart msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "" +msgstr "Módulos atualizados, reiniciar agora?\n\n%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "" +msgstr "Módulos atualizados!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "" +msgstr "Atualização de módulos encontrada, todas as mudanças locais serão perdidas, continuar?\n\n%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "" +msgstr "Atualização de módulos encontrada!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." -msgstr "" +msgstr "Baixando..." #: frmluamodulesupdater.rs_statusdelete msgctxt "frmluamodulesupdater.rs_statusdelete" msgid "%s DELETE*" -msgstr "" +msgstr "%s EXCLUIR*" #: frmluamodulesupdater.rs_statusfailed msgctxt "frmluamodulesupdater.rs_statusfailed" msgid "%s FAILED*" -msgstr "" +msgstr "%s FALHOU*" #: frmluamodulesupdater.rs_statusnew msgctxt "frmluamodulesupdater.rs_statusnew" msgid "%s NEW*" -msgstr "" +msgstr "%s NOVO*" #: frmluamodulesupdater.rs_statusredownloaded msgctxt "frmluamodulesupdater.rs_statusredownloaded" msgid "%s REDOWNLOAD*" -msgstr "" +msgstr "%s BAIXAR_NOVAMENTE*" #: frmluamodulesupdater.rs_statusupdate msgctxt "frmluamodulesupdater.rs_statusupdate" msgid "%s UPDATE*" -msgstr "" +msgstr "%s ATUALIZAR*" #: frmmain.rs_alldownloads msgid "All downloads" @@ -248,9 +230,7 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "" -"Este título já está na lista de download.\n" -"Você quer baixá-lo mesmo assim?\n" +msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -276,19 +256,14 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "" -"Baixar tudo\n" -"Adicionar aos favoritos\n" +msgstr "Baixar tudo\nAdicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "<none>\n" -msgstr "" -"Completo\n" -"Em Andamento\n" -"<vazio>\n" +msgstr "Completo\nEm Andamento\n<vazio>\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -298,9 +273,7 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "" -"Há um problema com estes dados!\n" -"Removendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -354,11 +327,7 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "" -"%s : Caminho para o mangá\n" -"%s : Nome do capítulo\n" -"\n" -"Examplo : \"%s%s\"\n" +msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -373,7 +342,6 @@ msgid "Mode: Filtered (%d)" msgstr "Modo: Filtrado (%d)" #: frmmain.rs_modesearching -#| msgid "Searching..." msgctxt "frmmain.rs_modesearching" msgid "Mode: Searching..." msgstr "Modo: Buscando..." @@ -392,7 +360,7 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" -msgstr "" +msgstr "Nada\nZIP\nCBZ\nPDF\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -400,11 +368,7 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "" -"Nada\n" -"Sair\n" -"Desligar\n" -"Hibernar\n" +msgstr "Nada\nSair\nDesligar\nHibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -428,7 +392,7 @@ msgid "" "WebP\n" "PNG\n" "JPEG\n" -msgstr "" +msgstr "WebP\nPNG\nJPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -436,7 +400,7 @@ msgid "" "Fastest\n" "Default\n" "Maximum\n" -msgstr "" +msgstr "Nenhum\r\nO mais rápido\r\nPadrão\r\nMáximo" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -510,18 +474,18 @@ msgstr "Abortar" #: selfupdater.rs_downloading msgid "Downloading new version %s" -msgstr "" +msgstr "Baixar nova versão %s" #: selfupdater.rs_faileddownload msgid "" "Failed to download new version %s\n" "\n" "%d %s\n" -msgstr "" +msgstr "Falha ao baixar a nova versão %s\n\n%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" -msgstr "" +msgstr "Falha ao extrair %s, exitstatus = %d" #: selfupdater.rs_failedtitle msgctxt "selfupdater.rs_failedtitle" @@ -530,20 +494,20 @@ msgstr "Falhou" #: selfupdater.rs_failedtosave msgid "Failed to save %s" -msgstr "" +msgstr "Falha ao salvar %s" #: selfupdater.rs_finishrestart msgid "Download update package finished, restart to proceed?" -msgstr "" +msgstr "Download do pacote de atualização finalizado, reiniciar para prosseguir?" #: selfupdater.rs_finishrestarttitle msgid "Download finished" -msgstr "" +msgstr "Download concluído" #: selfupdater.rs_missingfile msgctxt "selfupdater.rs_missingfile" msgid "Missing %s" -msgstr "" +msgstr "Faltando %s" #: taccountmanagerform.btedit.caption msgctxt "taccountmanagerform.btedit.caption" @@ -556,28 +520,25 @@ msgstr "Atualizar" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "AccountManagerForm" #: taccountmanagerform.vtaccountlist.header.columns[1].text -#| msgid "Username" -msgctxt "taccountmanagerform.vtaccountlist.header.columns[1].text" +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" msgid "Website" msgstr "Website" #: taccountmanagerform.vtaccountlist.header.columns[2].text -#| msgid "Status" -msgctxt "taccountmanagerform.vtaccountlist.header.columns[2].text" +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[2].TEXT" msgid "Username" msgstr "Nome de usuário" #: taccountmanagerform.vtaccountlist.header.columns[3].text -#| msgid "Status" -msgctxt "taccountmanagerform.vtaccountlist.header.columns[3].text" +msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[3].TEXT" msgid "Status" msgstr "Status" #: taccountsetform.btcancel.caption -msgctxt "taccountsetform.btcancel.caption" +msgctxt "TACCOUNTSETFORM.BTCANCEL.CAPTION" msgid "Cancel" msgstr "Cancelar" @@ -587,31 +548,29 @@ msgstr "Ok" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Conta" #: taccountsetform.ckshowpassword.caption msgid "Show password" msgstr "Exibir senha" #: taccountsetform.edpassword.texthint -msgctxt "taccountsetform.edpassword.texthint" +msgctxt "TACCOUNTSETFORM.EDPASSWORD.TEXTHINT" msgid "Password" msgstr "Senha" #: taccountsetform.edusername.texthint -#| msgid "Status" -msgctxt "taccountsetform.edusername.texthint" +msgctxt "TACCOUNTSETFORM.EDUSERNAME.TEXTHINT" msgid "Username" msgstr "Nome de usuário" #: taccountsetform.label2.caption -#| msgid "Status" -msgctxt "taccountsetform.label2.caption" +msgctxt "TACCOUNTSETFORM.LABEL2.CAPTION" msgid "Username" msgstr "Nome de usuário" #: taccountsetform.label3.caption -msgctxt "taccountsetform.label3.caption" +msgctxt "TACCOUNTSETFORM.LABEL3.CAPTION" msgid "Password" msgstr "Senha" @@ -636,7 +595,7 @@ msgid "Manga list" msgstr "Lista de mangás" #: tformdroptarget.miaddtofavorites.caption -msgctxt "tformdroptarget.miaddtofavorites.caption" +msgctxt "TFORMDROPTARGET.MIADDTOFAVORITES.CAPTION" msgid "Add to favorites" msgstr "Adicionar aos favoritos" @@ -645,7 +604,7 @@ msgid "&Close" msgstr "&Fechar" #: tformdroptarget.midownloadall.caption -msgctxt "tformdroptarget.midownloadall.caption" +msgctxt "TFORMDROPTARGET.MIDOWNLOADALL.CAPTION" msgid "Download all" msgstr "Baixar tudo" @@ -681,7 +640,7 @@ msgid "Domdomsoft Manga Downloader" msgstr "Domdomsoft Manga Downloader" #: timportfavorites.edpath.texthint -msgctxt "timportfavorites.edpath.texthint" +msgctxt "TIMPORTFAVORITES.EDPATH.TEXTHINT" msgid "Path to the software (e.g. C:\\MangaDownloader)" msgstr "Caminho para o software (e.g. C:\\MangaDownloader)" @@ -692,27 +651,27 @@ msgstr "Software:" #: tluamodulesupdaterform.btcheckupdate.caption msgctxt "tluamodulesupdaterform.btcheckupdate.caption" msgid "Check update" -msgstr "" +msgstr "Checar por atualização" #: tluamodulesupdaterform.ckautorestart.caption msgid "Auto restart" -msgstr "" +msgstr "Reinício automático" #: tluamodulesupdaterform.ckshowupdatewarning.caption msgid "Show update warning" -msgstr "" +msgstr "Mostrar aviso de atualização" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[0].text msgid "Filename" -msgstr "" +msgstr "Nome do arquivo" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[1].text msgid "Last modified" -msgstr "" +msgstr "Última modificação" #: tluamodulesupdaterform.vtluamodulesrepos.header.columns[2].text msgid "Last message" -msgstr "" +msgstr "Última mensagem" #: tmainform.btabortupdatelist.hint msgid "Abort update list" @@ -724,8 +683,7 @@ msgid "Add to favorites" msgstr "Adicionar aos favoritos" #: tmainform.btchecklatestversion.caption -#| msgid "Check for new version" -msgctxt "tmainform.btchecklatestversion.caption" +msgctxt "TMAINFORM.BTCHECKLATESTVERSION.CAPTION" msgid "Check for latest version" msgstr "Checar pela última versão" @@ -809,7 +767,7 @@ msgid "Search only new manga" msgstr "Buscar somente novos mangás" #: tmainform.cboptionautocheckfavdownload.caption -msgctxt "tmainform.cboptionautocheckfavdownload.caption" +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVDOWNLOAD.CAPTION" msgid "Automatic download after finish checking" msgstr "Download automático após terminar de checar" @@ -818,18 +776,16 @@ msgid "Auto check for new chapter in an interval" msgstr "Auto-checar por novos capítulos em um intervalo" #: tmainform.cboptionautocheckfavremovecompletedmanga.caption -msgctxt "tmainform.cboptionautocheckfavremovecompletedmanga.caption" +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKFAVREMOVECOMPLETEDMANGA.CAPTION" msgid "Automatic remove completed manga from Favorites" msgstr "Remover automaticamente mangás completados dos Favoritos" #: tmainform.cboptionautocheckfavstartup.caption -#| msgid "Automatic check for new chapter at startup" msgid "Auto check for new chapter at startup" msgstr "Auto-checar por novos capítulos ao iniciar" #: tmainform.cboptionautochecklatestversion.caption -#| msgid "Check for new version " -msgctxt "tmainform.cboptionautochecklatestversion.caption" +msgctxt "TMAINFORM.CBOPTIONAUTOCHECKLATESTVERSION.CAPTION" msgid "Auto check for latest version " msgstr "Auto-checar pela última versão " @@ -838,8 +794,7 @@ msgid "Open Favorites at startup" msgstr "Abrir os Favoritos ao iniciar" #: tmainform.cboptionchangeunicodecharacter.caption -#| msgid "Change all all character to" -msgctxt "tmainform.cboptionchangeunicodecharacter.caption" +msgctxt "TMAINFORM.CBOPTIONCHANGEUNICODECHARACTER.CAPTION" msgid "Replace all unicode character with" msgstr "Substituir todos caracteres unidcode com" @@ -849,7 +804,7 @@ msgstr "Habilite isto se você tem problemas com caminhos com caracteres unicode #: tmainform.cboptiondeletecompletedtasksonclose.caption msgid "Delete completed tasks on close" -msgstr "" +msgstr "Excluir tarefas completas ao fechar" #: tmainform.cboptiondigitchapter.caption msgid "Chapter" @@ -868,7 +823,7 @@ msgid "Auto generate chapter folder" msgstr "Auto-gerar pasta de capítulo" #: tmainform.cboptiongeneratemangafolder.caption -msgctxt "tmainform.cboptiongeneratemangafolder.caption" +msgctxt "TMAINFORM.CBOPTIONGENERATEMANGAFOLDER.CAPTION" msgid "Auto generate folder based on manga's name" msgstr "Auto-gerar pasta com o nome do mangá" @@ -918,7 +873,7 @@ msgstr "Exibir \"Apagar todas tarefas concluídas\" na barra de ferramentas" #: tmainform.cboptionshowdownloadtoolbarleft.caption msgid "Show left downloads toolbar" -msgstr "" +msgstr "Mostrar barra de ferramentas de downloads à esquerda" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -939,7 +894,7 @@ msgstr "Usar proxy" #: tmainform.cbpngcompressionlevel.text msgctxt "tmainform.cbpngcompressionlevel.text" msgid "Fastest" -msgstr "" +msgstr "Mais Rápido" #: tmainform.cbsearchfromallsites.caption msgid "Search in all manga sites" @@ -956,7 +911,7 @@ msgstr "Expressão Regular" #: tmainform.cbwebpsaveas.text msgctxt "tmainform.cbwebpsaveas.text" msgid "PNG" -msgstr "" +msgstr "PNG" #: tmainform.ckdroptarget.caption msgctxt "tmainform.ckdroptarget.caption" @@ -1039,9 +994,7 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "" -"Meninas vestindo-se como caras, caras vestir-se como meninas.\n" -"Rapazes se transformando em garotas, garotas se transformando em caras.\n" +msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1284,21 +1237,19 @@ msgid "This work usually involves intimate relationships between women." msgstr "Este trabalho geralmente envolve relações íntimas entre as mulheres." #: tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption -#| msgid "Always start from failed chapters when task start" msgctxt "tmainform.ckoptionsalwaysstarttaskfromfailedchapters.caption" msgid "Always start task from failed chapters" msgstr "Sempre iniciar tarefa dos capítulos que falharam" #: tmainform.ckpngsaveasjpeg.caption msgid "Save PNG as JPEG" -msgstr "" +msgstr "Salvar PNG como JPEG" #: tmainform.edcustomgenres.texthint msgid "Input custom genres, separated by comma" msgstr "Entrar gêneros personalizados, separados por vírgula" #: tmainform.eddownloadssearch.texthint -#| msgid "Search favorites..." msgctxt "tmainform.eddownloadssearch.texthint" msgid "Search downloads..." msgstr "Pesquisar downloads..." @@ -1319,7 +1270,7 @@ msgid "Author" msgstr "Autor" #: tmainform.edfiltermangainfochapters.texthint -msgctxt "tmainform.edfiltermangainfochapters.texthint" +msgctxt "TMAINFORM.EDFILTERMANGAINFOCHAPTERS.TEXTHINT" msgid "Filter" msgstr "Filtros" @@ -1338,7 +1289,7 @@ msgid "Search title..." msgstr "Pesquisar pelo título..." #: tmainform.edoptionchaptercustomrename.texthint -msgctxt "tmainform.edoptionchaptercustomrename.texthint" +msgctxt "TMAINFORM.EDOPTIONCHAPTERCUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "Renomear personalizado" @@ -1347,19 +1298,17 @@ msgid "Default download path" msgstr "Caminho de download padrão" #: tmainform.edoptionexternalparams.texthint -#| msgid "External program parameters" -msgctxt "tmainform.edoptionexternalparams.texthint" +msgctxt "TMAINFORM.EDOPTIONEXTERNALPARAMS.TEXTHINT" msgid "External program parameters" msgstr "Parâmetros externos do programa" #: tmainform.edoptionexternalpath.texthint -#| msgid "External program parameters" -msgctxt "tmainform.edoptionexternalpath.texthint" +msgctxt "TMAINFORM.EDOPTIONEXTERNALPATH.TEXTHINT" msgid "External program path" msgstr "Caminho do programa externo" #: tmainform.edoptionfilenamecustomrename.texthint -msgctxt "tmainform.edoptionfilenamecustomrename.texthint" +msgctxt "TMAINFORM.EDOPTIONFILENAMECUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "Renomear personalizado" @@ -1368,7 +1317,7 @@ msgid "Proxy host/IP" msgstr "Proxy host/IP" #: tmainform.edoptionmangacustomrename.texthint -msgctxt "tmainform.edoptionmangacustomrename.texthint" +msgctxt "TMAINFORM.EDOPTIONMANGACUSTOMRENAME.TEXTHINT" msgid "Custom rename" msgstr "Renomear personalizado" @@ -1390,8 +1339,7 @@ msgid "Input URL here" msgstr "Introduza a URL aqui" #: tmainform.edwebsitessearch.texthint -#| msgid "Search..." -msgctxt "tmainform.edwebsitessearch.texthint" +msgctxt "TMAINFORM.EDWEBSITESSEARCH.TEXTHINT" msgid "Search website..." msgstr "Pesquisar no site ..." @@ -1405,7 +1353,7 @@ msgstr "Caixa de Seleção" #: tmainform.gbimageconversion.caption msgid "Image Conversion" -msgstr "" +msgstr "Conversão de imagem" #: tmainform.gboptionexternal.caption msgid "External program" @@ -1462,16 +1410,7 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "" -"Géneros:\n" -"- Marcado: Inclua este gênero.\n" -"- Desmarcado: exclua esse gênero.\n" -"- Cinzento: Não importa.\n" -"\n" -"Géneros Personalizados:\n" -"- Separar vários gêneros com ','.\n" -"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n" -"- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1489,7 +1428,7 @@ msgstr "Título" #: tmainform.lbjpegquality.caption msgid "JPEG quality" -msgstr "" +msgstr "Qualidade JPEG" #: tmainform.lblogfilename.caption msgid "Log file:" @@ -1500,23 +1439,22 @@ msgid "Mode: Show all (0)" msgstr "Modo: Exibir Tudo (0)" #: tmainform.lboptionautocheckfavintervalminutes.caption -msgctxt "tmainform.lboptionautocheckfavintervalminutes.caption" +msgctxt "TMAINFORM.LBOPTIONAUTOCHECKFAVINTERVALMINUTES.CAPTION" msgid "Auto check for new chapter every %d minutes" msgstr "Auto checar por novos capítulos a cada %d minutos" #: tmainform.lboptionchaptercustomrename.caption -#| msgid "Chapter folder name:" -msgctxt "tmainform.lboptionchaptercustomrename.caption" +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAME.CAPTION" msgid "Chapter name:" msgstr "Nome do capítulo:" #: tmainform.lboptionchaptercustomrenamehint.caption -msgctxt "tmainform.lboptionchaptercustomrenamehint.caption" +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "[?]" #: tmainform.lboptionchaptercustomrenamehint.hint -msgctxt "tmainform.lboptionchaptercustomrenamehint.hint" +msgctxt "TMAINFORM.LBOPTIONCHAPTERCUSTOMRENAMEHINT.HINT" msgid "" "%WEBSITE% : Website name\n" "%MANGA% : Manga title\n" @@ -1527,16 +1465,7 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "" -"%WEBSITE% : Nome doWebsite\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do capítulo\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"%NUMBERING% : Número\n" -"\n" -"Nota:\n" -"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1551,7 +1480,7 @@ msgid "Parameters:" msgstr "Parâmetros:" #: tmainform.lboptionexternalparamshint.caption -msgctxt "tmainform.lboptionexternalparamshint.caption" +msgctxt "TMAINFORM.LBOPTIONEXTERNALPARAMSHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1560,7 +1489,7 @@ msgid "Filename:" msgstr "Nome do arquivo:" #: tmainform.lboptionfilenamecustomrenamehint.caption -msgctxt "tmainform.lboptionfilenamecustomrenamehint.caption" +msgctxt "TMAINFORM.LBOPTIONFILENAMECUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1573,14 +1502,7 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do Capítulo\n" -"%FILENAME% : Nome do arquivo\n" -"\n" -"Nota:\n" -"Nome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1595,12 +1517,12 @@ msgid "After download finish:" msgstr "Depois do download terminar:" #: tmainform.lboptionmangacustomrename.caption -msgctxt "tmainform.lboptionmangacustomrename.caption" +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAME.CAPTION" msgid "Manga folder name:" msgstr "Nome da pasta do mangá:" #: tmainform.lboptionmangacustomrenamehint.caption -msgctxt "tmainform.lboptionmangacustomrenamehint.caption" +msgctxt "TMAINFORM.LBOPTIONMANGACUSTOMRENAMEHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1613,27 +1535,17 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"\n" -"Nota:\n" -"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption -#| msgid "Number of downloaded tasks at the same time (Max: 8)" msgid "Number of downloaded tasks at the same time" msgstr "Número de tarefas baixadas ao mesmo tempo" #: tmainform.lboptionmaxretry.caption -#| msgid "Number of retry times if tasks have download problems (0 = always retry)" msgid "Number of retry times if tasks have download problems (-1 = always retry)" msgstr "Número de tentativas de repetição se as tarefas tiverem problemas de download (-1 = sempre tentar novamente)" #: tmainform.lboptionmaxthread.caption -#| msgid "Number of downloaded files per task at the same time (Max: 32)" msgid "Number of downloaded files per task at the same time" msgstr "Número de arquivos baixados por tarefa ao mesmo tempo" @@ -1656,7 +1568,7 @@ msgid "100 = FlateEncode (lossless), lower = DCTEncode (lossy)" msgstr "100 = FlateEncode (lossless), baixo = DCTEncode (lossy)" #: tmainform.lboptionpdfqualityhint.caption -msgctxt "tmainform.lboptionpdfqualityhint.caption" +msgctxt "TMAINFORM.LBOPTIONPDFQUALITYHINT.CAPTION" msgid "[?]" msgstr "[?]" @@ -1684,7 +1596,7 @@ msgstr "Nome de usuário" #: tmainform.lbpngcompressionlevel.caption msgctxt "tmainform.lbpngcompressionlevel.caption" msgid "PNG Compression level" -msgstr "" +msgstr "Nível de compressão PNG" #: tmainform.lbsaveto.caption msgid "Save to:" @@ -1692,7 +1604,7 @@ msgstr "Salvar em:" #: tmainform.lbwebpsaveas.caption msgid "Save WebP as" -msgstr "" +msgstr "Salvar WebP como" #: tmainform.medturldelete.caption msgctxt "TMAINFORM.MEDTURLDELETE.CAPTION" @@ -1747,7 +1659,7 @@ msgid "Descending" msgstr "Descendente" #: tmainform.michapterlistfilter.caption -msgctxt "tmainform.michapterlistfilter.caption" +msgctxt "TMAINFORM.MICHAPTERLISTFILTER.CAPTION" msgid "Filter" msgstr "Filtros" @@ -1756,7 +1668,6 @@ msgid "Hide downloaded chapters" msgstr "Ocultar capítulos baixados" #: tmainform.michapterlisthighlight.caption -#| msgid "Highlight download chapters" msgid "Highlight downloaded chapters" msgstr "Realçar capítulos baixados" @@ -1837,7 +1748,7 @@ msgid "Change \"Save to\"" msgstr "Alterar \"Salvar em\"" #: tmainform.mifavoriteschecknewchapter.caption -msgctxt "tmainform.mifavoriteschecknewchapter.caption" +msgctxt "TMAINFORM.MIFAVORITESCHECKNEWCHAPTER.CAPTION" msgid "Check for new chapter" msgstr "Checar por novos capítulos" @@ -1916,7 +1827,7 @@ msgid "After download finish" msgstr "Depois do download terminar" #: tmainform.mitrayexit.caption -msgctxt "tmainform.mitrayexit.caption" +msgctxt "TMAINFORM.MITRAYEXIT.CAPTION" msgid "Exit" msgstr "Sair" @@ -1946,7 +1857,7 @@ msgid "Resume all" msgstr "Resumir Todos" #: tmainform.mitrayshowdropbox.caption -msgctxt "tmainform.mitrayshowdropbox.caption" +msgctxt "TMAINFORM.MITRAYSHOWDROPBOX.CAPTION" msgid "Show Drop Box" msgstr "Exibir Caixa de Seleção" @@ -1959,7 +1870,7 @@ msgid "Download all lists from server at once" msgstr "Faça o download de todas as listas do servidor de uma vez" #: tmainform.mnfiltergenreallcheck.caption -msgctxt "tmainform.mnfiltergenreallcheck.caption" +msgctxt "TMAINFORM.MNFILTERGENREALLCHECK.CAPTION" msgid "Check all" msgstr "Marca tudo" @@ -1968,7 +1879,7 @@ msgid "Indeterminate all" msgstr "Indeterminar tudo" #: tmainform.mnfiltergenrealluncheck.caption -msgctxt "tmainform.mnfiltergenrealluncheck.caption" +msgctxt "TMAINFORM.MNFILTERGENREALLUNCHECK.CAPTION" msgid "Uncheck all" msgstr "Desmarcar Tudo" @@ -2021,19 +1932,19 @@ msgstr "Parar Tudo" #: tmainform.tbmidownloadmovebottom.hint msgid "Move selected item(s) to bottom" -msgstr "" +msgstr "Mover item(ns) selecionado(s) para o final" #: tmainform.tbmidownloadmovedown.hint msgid "Move selected item(s) down" -msgstr "" +msgstr "Mover item(ns) selecionado(s) para baixo" #: tmainform.tbmidownloadmovetop.hint msgid "Move selected item(s) to top" -msgstr "" +msgstr "Mover item(ns) selecionado(s) para o topo" #: tmainform.tbmidownloadmoveup.hint msgid "Move selected item(s) up" -msgstr "" +msgstr "Mover item(ns) selecionado(s) para cima" #: tmainform.tbwebsitescollapseall.caption msgid "Collapse All" @@ -2130,10 +2041,10 @@ msgstr "Avançado" #: tmainform.tswebsitemodules.caption msgid "Modules" -msgstr "" +msgstr "Módulos" #: tmainform.tswebsiteoptions.caption -msgctxt "tmainform.tswebsiteoptions.caption" +msgctxt "TMAINFORM.TSWEBSITEOPTIONS.CAPTION" msgid "Options" msgstr "Opções" @@ -2143,7 +2054,7 @@ msgid "Websites" msgstr "Websites" #: tmainform.tswebsiteselection.caption -msgctxt "tmainform.tswebsiteselection.caption" +msgctxt "TMAINFORM.TSWEBSITESELECTION.CAPTION" msgid "Websites" msgstr "Websites" @@ -2274,7 +2185,6 @@ msgid "Valid" msgstr "Válido" #: ttransferfavoritesform.vtfavs.header.columns[1].text -#| msgid "Website" msgctxt "ttransferfavoritesform.vtfavs.header.columns[1].text" msgid "Title" msgstr "Título" @@ -2296,22 +2206,20 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "" -"Nova versão encontrada! Você quer atualizar agora?\n" -"FMD irá fechar para terminar a atualização.\n" +msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption -msgctxt "twebsiteoptionadvancedform.menuitem1.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM1.CAPTION" msgid "Add" msgstr "Adic" #: twebsiteoptionadvancedform.menuitem2.caption -msgctxt "twebsiteoptionadvancedform.menuitem2.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM2.CAPTION" msgid "Edit" msgstr "Editar" #: twebsiteoptionadvancedform.menuitem4.caption -msgctxt "twebsiteoptionadvancedform.menuitem4.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM4.CAPTION" msgid "Delete" msgstr "Apagar" @@ -2325,7 +2233,7 @@ msgid "Directory page number" msgstr "Número de páginas do diretório" #: twebsiteoptionadvancedform.tsdownloads.caption -msgctxt "twebsiteoptionadvancedform.tsdownloads.caption" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.TSDOWNLOADS.CAPTION" msgid "Downloads" msgstr "Downloads" @@ -2347,17 +2255,17 @@ msgid "User Agent" msgstr "User Agent" #: twebsiteoptionadvancedform.vtcookies.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtcookies.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtcookies.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTCOOKIES.HEADER.COLUMNS[1].TEXT" msgid "Cookies" msgstr "Cookies" #: twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtdownloadmaxthreadspertask.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTDOWNLOADMAXTHREADSPERTASK.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" @@ -2367,32 +2275,32 @@ msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistdirectorypagenumber.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTDIRECTORYPAGENUMBER.HEADER.COLUMNS[1].TEXT" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtupdatelistnumberofthreads.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUPDATELISTNUMBEROFTHREADS.HEADER.COLUMNS[1].TEXT" msgid "Value" msgstr "Valor" #: twebsiteoptionadvancedform.vtuseragent.header.columns[0].text -msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[0].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[0].TEXT" msgid "Website" msgstr "Website" #: twebsiteoptionadvancedform.vtuseragent.header.columns[1].text -msgctxt "twebsiteoptionadvancedform.vtuseragent.header.columns[1].text" +msgctxt "TWEBSITEOPTIONADVANCEDFORM.VTUSERAGENT.HEADER.COLUMNS[1].TEXT" msgid "User Agent" msgstr "User Agent" @@ -2402,15 +2310,15 @@ msgstr "Selecionar um website" #: twebsitesettingsform.caption msgid "WebsiteSettingsForm" -msgstr "" +msgstr "WebsiteSettingsForm" #: twebsitesettingsform.edsearch.texthint msgid "Website name" -msgstr "" +msgstr "Nome do site" #: twebsitesettingsform.edsearchproperty.texthint msgid "Setting name" -msgstr "" +msgstr "Nome da configuração" #: udownloadsmanager.rs_compressing msgid "Compressing..." @@ -2579,4 +2487,3 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" - From 5bc1ffa961798265a1451f336ad4190328a42ad2 Mon Sep 17 00:00:00 2001 From: Havokdan <havokdan@yahoo.com.br> Date: Tue, 27 Feb 2018 08:13:07 -0300 Subject: [PATCH 2449/2794] Update updater.pt_BR.po --- updater/languages/updater.pt_BR.po | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/updater/languages/updater.pt_BR.po b/updater/languages/updater.pt_BR.po index 6807f784f..1fefe84d3 100644 --- a/updater/languages/updater.pt_BR.po +++ b/updater/languages/updater.pt_BR.po @@ -13,7 +13,7 @@ msgstr "" #: tfrmmain.caption msgid "Free Manga Downloader - Updater" -msgstr "" +msgstr "Free Manga Downloader - Atualizador" #: tfrmmain.lbfilesize.caption msgid "File size" @@ -106,4 +106,3 @@ msgstr "Descompactar arquivo [%s]..." #: umain.rs_waitmainapp msgid "Waiting main app to close..." msgstr "Esperando o aplicativo principal para fechar..." - From 65d147fab18ec16183f7a042924f2eec1a30d36d Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Tue, 27 Feb 2018 07:40:24 -0500 Subject: [PATCH 2450/2794] Update fmd.es.po Many minor changes --- mangadownloader/languages/fmd.es.po | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index a73a9f4c5..82f9003e2 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" -"Project-Id-Version: FMD Español 2.0.5\n" +"Project-Id-Version: FMD\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Language-Team: Mariolr\n" @@ -58,7 +58,7 @@ msgstr "%s: Perdido %s" #: ehentai.rs_downloadoriginalimage msgid "Download original image(require ExHentai account)" -msgstr "Descargar imagen original (require una cuenta ExHentai)" +msgstr "Descargar imagen original (require una cuenta en ExHentai)" #: ehentai.rs_settingsimagesize msgid "Image size:" @@ -84,7 +84,7 @@ msgstr "" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" -msgstr "Estás seguro que deseas eliminar esta cuenta?" +msgstr "¿Estás seguro que deseas eliminar esta cuenta?" #: frmaccountmanager.rs_checking msgid "Checking" @@ -106,7 +106,7 @@ msgstr "OK" #: frmaccountset.rs_cantbeempty msgid "Username or password can't be empty!" -msgstr "Nombre de usuario o contraseña no puede estar vacio!" +msgstr "¡Nombre de usuario o contraseña no puede estar vacio!" #: frmimportfavorites.rs_importcompleted msgid "Import completed." @@ -140,13 +140,13 @@ msgid "" "\n" "%s\n" msgstr "" -"Módulos Actualizados, Reiniciar Ahora?\n" +"Módulos Actualizados, ¿Reiniciar Ahora?\n" "\n" "%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" -msgstr "Módulos Actualizados!" +msgstr "¡Módulos Actualizados!" #: frmluamodulesupdater.rs_newupdatefoundlostchanges msgid "" @@ -154,13 +154,13 @@ msgid "" "\n" "%s\n" msgstr "" -"Actualización de Módulos Encontrada, Cualquier Cambio Local Será Perdido, Proceder?\n" +"Actualización de módulos encontrada, cualquier cambio local será perdido, ¿Quiere hacerlo?\n" "\n" "%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" -msgstr "Actualización de Módulos Encontrada!" +msgstr "¡Actualización de Módulos Encontrada!" #: frmluamodulesupdater.rs_startdownloading msgid "Downloading..." @@ -224,27 +224,27 @@ msgstr "Cuenta de Descarga:" #: frmmain.rs_dlgmangalistselect msgid "You must choose at least 1 manga website!" -msgstr "Debes escoger al menos 1 sitio web de manga!" +msgstr "¡Debes escoger al menos 1 sitio web manga!" #: frmmain.rs_dlgquit msgid "Are you sure you want to exit?" -msgstr "Estás seguro que quieres salir?" +msgstr "¿Estás seguro que quieres salir?" #: frmmain.rs_dlgremovefavorite msgid "Are you sure you want to delete the favorite(s)?" -msgstr "Estás seguro de que quieres eliminar los favoritos?" +msgstr "¿Estás seguro de eliminar los favoritos?" #: frmmain.rs_dlgremovefinishtasks msgid "Are you sure you want to delete all finished tasks?" -msgstr "Estás seguro de que quieres eliminar todas las tareas terminadas?" +msgstr "¿Estás seguro de eliminar todas las tareas terminadas?" #: frmmain.rs_dlgremoveitem msgid "Are you sure you want to delete this item(s)?" -msgstr "Estás seguro de querer eliminar este(os) ítem(s)?" +msgstr "¿Estás seguro de querer eliminar este(os) ítem(s)?" #: frmmain.rs_dlgremovetask msgid "Are you sure you want to delete the task(s)?" -msgstr "Estás seguro de desear eliminar la(s) tarea(s)?" +msgstr "¿Estás seguro de desear eliminar la(s) tarea(s)?" #: frmmain.rs_dlgsplitdownload msgctxt "frmmain.rs_dlgsplitdownload" @@ -257,11 +257,11 @@ msgid "" "Do you want to download it anyway?\n" msgstr "" "Este título ya se encuentra en la lista de descarga\n" -"Deseas descargarlo de todos modos?\n" +"¿Deseas descargarlo de todos modos?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" -msgstr "Ingresar Nuevo Capitulo?" +msgstr "¿Ingresar Nuevo Capitulo?" #: frmmain.rs_dlgtypeinnewsavepath msgid "Type in new save path:" @@ -269,15 +269,15 @@ msgstr "Ingresar Nueva Ruta de Guardado :" #: frmmain.rs_dlgupdaterisrunning msgid "Updater is running!" -msgstr "Actualizador está Ejecutandose!" +msgstr "¡Actualizador está Ejecutandose!" #: frmmain.rs_dlgupdaterwanttoupdatedb msgid "Do you want to download manga list from the server?" -msgstr "Quieres Descargar la Lista de Manga del Servidor?" +msgstr "¿Quieres Descargar la Lista de Manga del Servidor?" #: frmmain.rs_dlgurlnotsupport msgid "URL not supported!" -msgstr "URL no Soportada!" +msgstr "¡URL no Soportada!" #: frmmain.rs_droptargetmodeitems msgid "" @@ -299,15 +299,15 @@ msgstr "" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" -msgstr "Free Manga Downloader está ya ejecutandose!" +msgstr "¡Free Manga Downloader está ya ejecutandose!" #: frmmain.rs_hintfavoriteproblem msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" msgstr "" -"Hay un Problema con estos Datos!\n" -"Quitarlo y Volviendolo a Agregar Podría Resolver el Problema.\n" +"¡Hay un problema con estos datos!\n" +"Quitarlo y volviendolo a agregar podría resolver el problema.\n" #: frmmain.rs_history msgid "History" @@ -535,7 +535,7 @@ msgid "" "\n" "%d %s\n" msgstr "" -"Ha Fallado En Descargar Nueva Versión %s\n" +"Fallo al descargar nueva versión %s\n" "\n" "%d %s\n" @@ -554,7 +554,7 @@ msgstr "Falló en Guardar %s" #: selfupdater.rs_finishrestart msgid "Download update package finished, restart to proceed?" -msgstr "La Descarga del Paquete ha Terminado, Proceder en Reiniciar?" +msgstr "La Descarga del Paquete ha terminado, ¿proceder en reiniciar?" #: selfupdater.rs_finishrestarttitle msgid "Download finished" @@ -905,11 +905,11 @@ msgstr "HTTP" #: tmainform.cboptionremovemanganamefromchapter.caption msgid "Remove manga name from chapter" -msgstr "Remover Nombre del Manga del Capitulo" +msgstr "Remover nombre del Manga del capitulo" #: tmainform.cboptionshowballoonhint.caption msgid "Show balloon hint" -msgstr "Mostrar Globo de Sugerencia" +msgstr "Mostrar globo de sugerencia" #: tmainform.cboptionshowdeletetaskdialog.caption msgid "Delete task/favorite" @@ -925,11 +925,11 @@ msgstr "Mostrar Barra de Herramientas de Descargas" #: tmainform.cboptionshowdownloadtoolbardeleteall.caption msgid "Show \"Delete all completed tasks\" in downloads toolbar" -msgstr "Mostrar \"Eliminar Todas las Tareas Completadas\" en la Barra de Herramientas de Descargas" +msgstr "Mostrar \"eliminar todas las tareas completadas\" en la barra de herramientas de descargas" #: tmainform.cboptionshowdownloadtoolbarleft.caption msgid "Show left downloads toolbar" -msgstr "Mostar Barra de Herramientas de Descargas Izquierda" +msgstr "Mostar barra de herramientas de descargas en la izquierda" #: tmainform.cboptionshowquitdialog.caption msgid "Exit FMD" @@ -1040,11 +1040,11 @@ msgstr "Fantasía" #: tmainform.ckfilterfantasy.hint msgid "Anything that involves, but not limited to, magic, dream world, and fairy tales." -msgstr "Cualquier cosa que involucre, pero no limitado a, magia, mundo de ensueño, y cuentos de hadas." +msgstr "Cualquier cosa que involucre, pero no limitado a: magia, mundo de ensueño, y cuentos de hadas." #: tmainform.ckfiltergenderbender.caption msgid "Gender Bender" -msgstr "Transgénero" +msgstr "Cambio de sexo" #: tmainform.ckfiltergenderbender.hint msgid "" @@ -1209,7 +1209,7 @@ msgstr "Shoujo Ai" #: tmainform.ckfiltershoujoai.hint msgctxt "TMAINFORM.CKFILTERSHOUJOAI.HINT" msgid "Often synonymous with yuri, this can be thought of as somewhat less extreme. \"Girl''s Love\", so to speak." -msgstr "A menudo sinónimo de yuri, esto puede ser considerado como algo menos extremo. \"Amor de Chicas\", por así decirlo." +msgstr "A menudo sinónimo de yuri, esto puede ser considerado como algo menos extremo. \"Amor entre Chicas\", por así decirlo." #: tmainform.ckfiltershounen.caption msgid "Shounen" @@ -1226,7 +1226,7 @@ msgstr "Shounen Ai" #: tmainform.ckfiltershounenai.hint msgid "Often synonymous with yaoi, this can be thought of as somewhat less extreme. \"Boy''s Love\", so to speak" -msgstr "A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. \"Amor de Chicos\", por así decirlo" +msgstr "A menudo sinónimo de yaoi, esto puede ser pensado como algo menos extremo. \"Amor entre Chicos\", por así decirlo" #: tmainform.ckfiltersliceoflife.caption msgid "Slice of Life" From 36c11ab80a1dfbb935dd3f5c78e6e7572c5233ab Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 05:37:39 +0800 Subject: [PATCH 2451/2794] Bump version 0.9.151.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index db0224f7c..19969120c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.151.0 (28-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.150.0...0.9.151.0 + 0.9.150.0 (26-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.149.0...0.9.150.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e9244c415..4d9d906ba 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="150"/> + <RevisionNr Value="151"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 7bd58129e..c6feb7fe6 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.150.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.150.0/fmd_0.9.150.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.150.0/fmd_0.9.150.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.150.0/fmd_0.9.150.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.150.0/fmd_0.9.150.0_Win64.7z +VERSION=0.9.151.0 +WIN32=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0.7z/download +WIN64=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0_Win64.7z/download +; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0.7z +; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0_Win64.7z From 3dc2be2e6afd52b2a846a0843001854ced2bd223 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 06:09:17 +0800 Subject: [PATCH 2452/2794] change update url to gh sf not stabe right now. --- update | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/update b/update index c6feb7fe6..a010bab37 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ VERSION=0.9.151.0 -WIN32=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0.7z/download -WIN64=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0_Win64.7z/download -; WIN32=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0.7z -; WIN64=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0_Win64.7z +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0_Win64.7z From 9e1f5f82edfd86dc2f4059360ad1a923405936ed Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 06:34:17 +0800 Subject: [PATCH 2453/2794] fix update --- baseunits/SelfUpdater.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index 0757e328e..02c7d01ac 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -211,6 +211,7 @@ procedure TSelfUpdaterThread.SyncFinishRestart; procedure TSelfUpdaterThread.ProceedUpdate; begin + writeln('proced update?'); if not DownloadSuccess then Exit; if FileExists(OLD_CURRENT_UPDATER_EXE) then DeleteFile(OLD_CURRENT_UPDATER_EXE); @@ -257,6 +258,7 @@ procedure TSelfUpdaterThread.Execute; Synchronize(@SyncStartDownload); if FHTTP.GET(UpdateURL) and (FHTTP.ResultCode < 300) then begin + DownloadSuccess := True; Filename := FMD_DIRECTORY + UPDATE_PACKAGE_NAME; if FileExists(Filename) then DeleteFile(Filename); From 89b4537be5011a9dc32da358144b8546e25f6333 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 06:37:51 +0800 Subject: [PATCH 2454/2794] Bump version 0.9.152.0 --- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 19969120c..be1055815 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.152.0 (28-02-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.151.0...0.9.152.0 + 0.9.151.0 (28-02-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.150.0...0.9.151.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 4d9d906ba..8448a8572 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="151"/> + <RevisionNr Value="152"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index a010bab37..57660d7c4 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.151.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.151.0/fmd_0.9.151.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.151.0/fmd_0.9.151.0_Win64.7z +VERSION=0.9.152.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.152.0/fmd_0.9.152.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.152.0/fmd_0.9.152.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.152.0/fmd_0.9.152.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.152.0/fmd_0.9.152.0_Win64.7z From a6367e2c1533542dbbde91e4e249a071731aea03 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 06:47:56 +0800 Subject: [PATCH 2455/2794] update changelog and cleanup --- baseunits/SelfUpdater.pas | 1 - changelog.txt | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/SelfUpdater.pas b/baseunits/SelfUpdater.pas index 02c7d01ac..aad9ecbf1 100644 --- a/baseunits/SelfUpdater.pas +++ b/baseunits/SelfUpdater.pas @@ -211,7 +211,6 @@ procedure TSelfUpdaterThread.SyncFinishRestart; procedure TSelfUpdaterThread.ProceedUpdate; begin - writeln('proced update?'); if not DownloadSuccess then Exit; if FileExists(OLD_CURRENT_UPDATER_EXE) then DeleteFile(OLD_CURRENT_UPDATER_EXE); diff --git a/changelog.txt b/changelog.txt index be1055815..7a1b0cdb7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,7 +5,8 @@ Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) 0.9.152.0 (28-02-2018) -[*] Various changes and bug fixes +[*] Fix updater doesn't extract the update package after download. + You have to download this version manually or extract updatepakage.7z Full changes: https://github.com/riderkick/FMD/compare/0.9.151.0...0.9.152.0 0.9.151.0 (28-02-2018) From 87ff8d1f0965ccc2739ee93bfa9dccd8517eb178 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 07:18:35 +0800 Subject: [PATCH 2456/2794] fix mangadex download --- lua/modules/MangaDex.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 1a921d6a0..46703f187 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -46,7 +46,7 @@ end function getpagenumber() if http.get(MaybeFillHost(module.rooturl,url)) then local s=StreamToString(http.document) - local lurl=AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/' + local lurl=MaybeFillHost(module.rooturl,AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/') local page_array=GetBetween('var page_array = [','];',s) task.pagelinks.commatext=GetBetween('var page_array = [','];',s):gsub('\'','') for i=0,task.pagelinks.count-1 do @@ -94,7 +94,7 @@ function Init() m.category='English' m.website='MangaDex' m.rooturl='https://mangadex.com' - m.lastupdated='February 26, 2018' + m.lastupdated='February 28, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetdirectorypagenumber='getdirectorypagenumber' From 2cb643706d7808e8a27aab0724d4b462825cb983 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 07:28:22 +0800 Subject: [PATCH 2457/2794] luawebsitemodule, push workid to some event --- baseunits/lua/LuaWebsiteModules.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index ae894117e..be3988c62 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -331,6 +331,7 @@ function DoBeforeDownloadImage(const DownloadThread: TDownloadThread; LuaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task', @luaDownloadTaskMetaTable); luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); + luaPushIntegerGlobal(l, 'workid', DownloadThread.WorkId); luaPushStringGlobal(l, 'url', AURL); LuaDoMe(l); @@ -357,6 +358,7 @@ function DoDownloadImage(const DownloadThread: TDownloadThread; LuaPushMe(l); luaPushObject(L, DownloadThread.Task.Container, 'task', @luaDownloadTaskMetaTable); luaPushObject(l, DownloadThread.FHTTP, 'http', @luaHTTPSendThreadAddMetaTable); + luaPushIntegerGlobal(l, 'workid', DownloadThread.WorkId); luaPushStringGlobal(l, 'url', AURL); LuaDoMe(l); From 1517a2847e94941b71cf947e7ef31b7e6a99ff77 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 08:22:29 +0800 Subject: [PATCH 2458/2794] mangadex, fix download missing host (fixed #1063) --- lua/modules/MangaDex.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 46703f187..397adcf03 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -59,6 +59,13 @@ function getpagenumber() return true end +function taskstart() + for i=0, task.pagelinks.count-1 do + task.pagelinks[i]=MaybeFillHost(module.rooturl,task.pagelinks[i]) + end + return true +end + local dirurl='/titles' function getdirectorypagenumber() @@ -96,6 +103,7 @@ function Init() m.rooturl='https://mangadex.com' m.lastupdated='February 28, 2018' m.ongetinfo='getinfo' + m.ontaskstart='taskstart' m.ongetpagenumber='getpagenumber' m.ongetdirectorypagenumber='getdirectorypagenumber' m.ongetnameandlink='getnameandlink' From 0f7cbd70560287ea8f4da5c85e55177ec1b4422d Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 09:14:20 +0800 Subject: [PATCH 2459/2794] added SKSubs (closed #1046) --- lua/modules/SKSubs.lua | 74 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 lua/modules/SKSubs.lua diff --git a/lua/modules/SKSubs.lua b/lua/modules/SKSubs.lua new file mode 100644 index 000000000..f49f2238f --- /dev/null +++ b/lua/modules/SKSubs.lua @@ -0,0 +1,74 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[contains(@class,"thumbnail")]/div[1]/img/@src')) + mangainfo.title=x.xpathstring('//div[contains(@class,"thumbnail")]/div[2]/div[1]/h1') + mangainfo.genres=x.xpathstring('//div[contains(@class,"thumbnail")]/div[2]/div[1]/string-join(./a,", ")') + mangainfo.summary=x.xpathstring('//div[contains(@class,"thumbnail")]/div[2]/div[1]/p/substring-after(.,"Sinopsis: ")') + local lurl='' + while true do + x.xpathstringall('//ul[contains(@class,"list-group")]/a/@href',mangainfo.chapterlinks) + x.xpathstringall('//ul[contains(@class,"list-group")]/a/text()[1]',mangainfo.chapternames) + lurl=x.xpathstring('//ul[@class="pagination"]/li[@class="active"]/following-sibling::li[not(@class)]/a/@href') + if http.terminated then break end; + if lurl~='' then + if http.get(MaybeFillHost(module.rooturl,lurl)) then + x.parsehtml(http.document) + else + break + end + else + break + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + task.pagenumber=tonumber(x.xpathstring('//ul[@class="pagination"]/li[not(./a/@rel)][last()]')) + return true + else + return false + end +end + +function getimageurl() + local lurl=MaybeFillHost(module.rooturl,url) + if workid~=0 then lurl=lurl..'/?page='..workid+1 end + if http.get(lurl) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]=MaybeFillHost(module.rooturl,x.xpathstring('//div[@class="card-body"]//img/@src')) + return true + else + return false + end +end + +function getnameandlink() + if http.get(module.rooturl..'/novelas') then + x=TXQuery.Create(http.Document) + x.xpathhrefall('//div[contains(@class,"thumbnail")]/div[2]/div[1]/a[1]', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Spanish-Scanlation' + m.website='SKSubs' + m.rooturl='http://sksubs.com' + m.lastupdated='February 28, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetimageurl='getimageurl' + m.ongetnameandlink='getnameandlink' +end From 8c5e6f3cc2aa732923a6a01403e934ab67dd2058 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 10:59:42 +0800 Subject: [PATCH 2460/2794] luabaseunit, register trimstrings --- baseunits/lua/LuaBaseUnit.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 795d3fa54..cf716f626 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -127,6 +127,12 @@ function lua_round(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_trimstrings(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TrimStrings(TStrings(luaGetUserData(L, 1))); +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -144,6 +150,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'IncStr', @lua_incstr); luaPushFunctionGlobal(L, 'StreamToString', @lua_streamtostring); luaPushFunctionGlobal(L, 'Round', @lua_round); + luaPushFunctionGlobal(L, 'TrimStrings', @lua_trimstrings); end; end. From 07c720a1ef848a369f3595e3b9b580a19f096656 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 11:10:23 +0800 Subject: [PATCH 2461/2794] mangadex, trim last empty uri (fixed #1054) --- lua/modules/MangaDex.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 397adcf03..b5f0bae61 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -44,11 +44,13 @@ function getinfo() end function getpagenumber() + print('mangadex get') if http.get(MaybeFillHost(module.rooturl,url)) then local s=StreamToString(http.document) local lurl=MaybeFillHost(module.rooturl,AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/') local page_array=GetBetween('var page_array = [','];',s) task.pagelinks.commatext=GetBetween('var page_array = [','];',s):gsub('\'','') + task.pagelinks.text=Trim(task.pagelinks.text) for i=0,task.pagelinks.count-1 do task.pagelinks[i]=lurl..task.pagelinks[i] end From b961ed09d3b979825a5583a9b1091bc07f5a0e09 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 11:16:04 +0800 Subject: [PATCH 2462/2794] luastrings, register delete, indexof, indexofname --- baseunits/lua/LuaStrings.pas | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas index 4b607c589..31aa26569 100644 --- a/baseunits/lua/LuaStrings.pas +++ b/baseunits/lua/LuaStrings.pas @@ -131,13 +131,31 @@ function strings_clear(L: Plua_State): Integer; cdecl; TUserData(luaClassGetObject(L)).Clear; end; +function strings_delete(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Delete(lua_tointeger(L, 1)); +end; + +function strings_indexof(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).IndexOf(lua_tostring(L, 1))); + Result := 1; +end; + +function strings_indexofname(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).IndexOfName(lua_tostring(L, 1))); + Result := 1; +end; + const constructs: packed array [0..2] of luaL_Reg = ( (name: 'New'; func: @strings_create), (name: 'Create'; func: @strings_create), (name: nil; func: nil) ); - methods: packed array [0..11] of luaL_Reg = ( + methods: packed array [0..14] of luaL_Reg = ( (name: 'LoadFromFile'; func: @strings_loadfromfile), (name: 'LoadFromStream'; func: @strings_loadfromstream), (name: 'SetText'; func: @strings_settext), @@ -149,6 +167,9 @@ function strings_clear(L: Plua_State): Integer; cdecl; (name: 'GetCount'; func: @strings_getcount), (name: 'Sort'; func: @strings_sort), (name: 'Clear'; func: @strings_clear), + (name: 'Delete'; func: @strings_delete), + (name: 'IndexOf'; func: @strings_indexof), + (name: 'IndexOfName'; func: @strings_indexofname), (name: nil; func: nil) ); props: packed array[0..4] of lual_Reg_prop = ( From 0fcde01b92b0801af0ae9cceea68b6b51ae61ee1 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 16:47:34 +0800 Subject: [PATCH 2463/2794] baseunit, fix searchonvt (fixed #1072) --- baseunits/uBaseUnit.pas | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index f164164d2..aaaeea12f 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -761,10 +761,10 @@ procedure SearchOnVT(Tree: TVirtualStringTree; Key: String; Column: Integer); if v then begin xnode := node^.Parent; - while xnode <> nil do + while (xnode <> nil) and (xnode <> Tree.RootNode) do begin if not (vsVisible in xnode^.States) then - Tree.IsVisible[xnode] := v; + Tree.IsVisible[xnode] := True; xnode := xnode^.Parent; end; end; @@ -775,7 +775,8 @@ procedure SearchOnVT(Tree: TVirtualStringTree; Key: String; Column: Integer); begin while node <> nil do begin - Tree.IsVisible[node] := True; + if not (vsVisible in node^.States) then + Tree.IsVisible[node] := True; node := Tree.GetNext(node); end; end; From 52cbb4655846986a6c084a6db520dacc6e197605 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 16:55:50 +0800 Subject: [PATCH 2464/2794] remove mangatraders (closed #1079) --- baseunits/modules/MangaLife.pas | 126 ++------------------------------ 1 file changed, 8 insertions(+), 118 deletions(-) diff --git a/baseunits/modules/MangaLife.pas b/baseunits/modules/MangaLife.pas index 781815ab7..1fe6e8d34 100644 --- a/baseunits/modules/MangaLife.pas +++ b/baseunits/modules/MangaLife.pas @@ -17,82 +17,6 @@ implementation dirURL = '/directory/'; diralpha = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'; -var - MMangaTraders: TModuleContainer; - MangaTradersLockLogin: TRTLCriticalSection; - MangaTradersOnLogin: Boolean; - -function MangaTradersLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if Module.Account.Enabled = False then Exit; - if TryEnterCriticalsection(MangaTradersLockLogin) > 0 then - try - MangaTradersOnLogin := True; - Module.Account.Status := asChecking; - SendLog('MangaTraders: post login'); - s := - 'EmailAddress=' + EncodeURLElement(Module.Account.Username) + - '&Password=' + EncodeURLElement(Module.Account.Password) + - '&RememberMe=1'; - AHTTP.Headers.Clear; - if AHTTP.POST(MMangaTraders.RootURL + '/auth/process.login.php', s) then - begin - s := StreamToString(AHTTP.Document); - SendLog('MangaTraders: login result = ' + s); - if LowerCase(s) = 'ok' then - begin - Module.Account.Status := asValid; - Module.Account.Cookies := AHTTP.Cookies.Text; - end - else - Module.Account.Status := asInvalid; - end - else - Module.Account.Status := asUnknown; - Result := Module.Account.Status = asValid; - finally - MangaTradersOnLogin := False; - LeaveCriticalsection(MangaTradersLockLogin); - end - else - begin - while MangaTradersOnLogin do Sleep(1000); - Result := Module.Account.Status = asValid; - if Result then - AHTTP.Cookies.Text := Module.Account.Cookies; - end; -end; - -function GETMangaTraders(const AHTTP: THTTPSendThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - accstat: TAccountStatus; -begin - Result := False; - if Module.Account.Enabled then - begin - accstat := Module.Account.Status; - if accstat = asValid then - AHTTP.Cookies.AddText(Module.Account.Cookies) - else - if accstat in [asChecking, asUnknown] then - Result := MangaTradersLogin(AHTTP, Module); - end; - Result := AHTTP.GET(AURL); -end; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - if Module = MMangaTraders then - Page := Length(diralpha) - else - page := 1; -end; - function fixcleanurl(const u: string): string; begin Result := u; @@ -111,11 +35,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; s := Module.RootURL + dirURL; if AURL <> '0' then - begin - if Module = MMangaTraders then - s += '?q='; s += diralpha[StrToIntDef(AURL, 0) + 1]; - end; if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; @@ -136,7 +56,6 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; const Module: TModuleContainer): Integer; var v: IXQValue; - r: Boolean; s: String; begin Result := NET_PROBLEM; @@ -144,11 +63,7 @@ function GetInfo(const MangaInfo: TMangaInformation; with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - if Module = MMangaTraders then - r := GETMangaTraders(MangaInfo.FHTTP, url, Module) - else - r := GET(url); - if r then begin + if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try @@ -158,20 +73,6 @@ function GetInfo(const MangaInfo: TMangaInformation; status := '-1'; Exit; end; - if (Module = MMangaTraders) and (Pos('/series/', url) <> 0) then - begin - s := XPathString('//div[@class="alert alert-success startReading"]/a/@href'); - if Pos('/manga/', s) <> 0 then - begin - s := MaybeFillHost(Module.RootURL, s); - if GET(s) then - ParseHTML(Document) - else - r := False; - end - else - r := False; - end; coverLink := MaybeFillHost(Module.RootURL, XPathString('//meta[@property="og:image"]/@content')); authors := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Author")]'), ':'); artists := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Artist")]'), ':'); @@ -182,18 +83,15 @@ function GetInfo(const MangaInfo: TMangaInformation; status := MangaInfoStatusIfPos(status); genres := SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Genre")]'), ':'); summary := Trim(SeparateRight(XPathString('//*[@class="row"][starts-with(.,"Description")]'), ':')); - if r then + for v in XPath('//div[@class="list chapter-list"]//a') do begin - for v in XPath('//div[@class="list chapter-list"]//a') do - begin - s := v.toNode.getAttribute('href'); - if Pos('-page-1', s) <> 0 then - s := StringReplace(s, '-page-1', '', []); - chapterLinks.Add(s); - chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); - end; - InvertStrings([chapterLinks, chapterName]); + s := v.toNode.getAttribute('href'); + if Pos('-page-1', s) <> 0 then + s := StringReplace(s, '-page-1', '', []); + chapterLinks.Add(s); + chapterName.Add(XPathString('span[@class="chapterLabel"]', v)); end; + InvertStrings([chapterLinks, chapterName]); finally Free; end; @@ -233,7 +131,6 @@ procedure RegisterModule; Website := AWebsite; RootURL := ARootURL; Category := 'English'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; @@ -243,16 +140,9 @@ procedure RegisterModule; begin AddWebsiteModule('MangaLife', 'http://mangalife.us'); AddWebsiteModule('MangaSee', 'http://mangaseeonline.us'); - MMangaTraders := AddWebsiteModule('MangaTraders', 'http://mangatraders.biz'); - MMangaTraders.AccountSupport := True; - MMangaTraders.OnLogin := @MangaTradersLogin; end; initialization - InitCriticalSection(MangaTradersLockLogin); RegisterModule; -finalization - DoneCriticalsection(MangaTradersLockLogin); - end. From 3b95c6d9c9ec1676e862b5633ea4ab04207da2c5 Mon Sep 17 00:00:00 2001 From: riderkick <colivaja@gmail.com> Date: Wed, 28 Feb 2018 17:08:56 +0800 Subject: [PATCH 2465/2794] frmmain, cleanup and use searchonvt for general search --- mangadownloader/forms/frmMain.pas | 142 +----------------------------- 1 file changed, 4 insertions(+), 138 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 261483e05..74a6f21f0 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2679,37 +2679,8 @@ procedure TMainForm.edDownloadsSearchButtonClick(Sender: TObject); end; procedure TMainForm.edDownloadsSearchChange(Sender: TObject); -var - Node: PVirtualNode; - S: String; begin - if vtDownload.RootNodeCount = 0 then Exit; - with vtDownload do - try - BeginUpdate; - if (edDownloadsSearch.Text = '') and (VisibleCount <> RootNodeCount) then - begin - Node := GetFirst(); - while Assigned(Node) do - begin - IsVisible[Node] := DLManager[Node^.Index].Visible; - Node := GetNext(Node); - end; - end - else - begin - S := AnsiUpperCase(edDownloadsSearch.Text); - Node := GetFirst(); - while Assigned(Node) do - begin - if DLManager[Node^.Index].Visible then - IsVisible[Node] := Pos(S, AnsiUpperCase(DLManager[Node^.Index].DownloadInfo.Title)) > 0; - Node := GetNext(Node); - end; - end; - finally - EndUpdate; - end; + SearchOnVT(vtDownload, edDownloadsSearch.Text); end; procedure TMainForm.edFavoritesSearchButtonClick(Sender: TObject); @@ -2718,36 +2689,8 @@ procedure TMainForm.edFavoritesSearchButtonClick(Sender: TObject); end; procedure TMainForm.edFavoritesSearchChange(Sender: TObject); -var - Node: PVirtualNode; - S: String; begin - if vtFavorites.RootNodeCount = 0 then Exit; - with vtFavorites do - try - BeginUpdate; - if (edFavoritesSearch.Text = '') and (VisibleCount <> RootNodeCount) then - begin - Node := GetFirst(); - while Assigned(Node) do - begin - IsVisible[Node] := True; - Node := GetNext(Node); - end; - end - else - begin - S := AnsiUpperCase(edFavoritesSearch.Text); - Node := GetFirst(); - while Assigned(Node) do - begin - IsVisible[Node] := Pos(S, AnsiUpperCase(FavoriteManager[Node^.Index].FavoriteInfo.Title)) > 0; - Node := GetNext(Node); - end; - end; - finally - EndUpdate; - end; + SearchOnVT(vtFavorites, edFavoritesSearch.Text, 1); end; procedure TMainForm.edFilterMangaInfoChaptersButtonClick(Sender: TObject); @@ -2784,85 +2727,8 @@ procedure TMainForm.edWebsitesSearchButtonClick(Sender: TObject); end; procedure TMainForm.edWebsitesSearchChange(Sender: TObject); -var - s: String; - lcount: Integer; - data: PSingleItem; - xNode, lNode: PVirtualNode; begin - s := Trim(LowerCase(edWebsitesSearch.Text)); - vtOptionMangaSiteSelection.BeginUpdate; - try - lNode := nil; - lcount := 0; - vtOptionMangaSiteSelection.RootNode^.TotalHeight := vtOptionMangaSiteSelection.DefaultNodeHeight; - if s = '' then - begin - xNode := vtOptionMangaSiteSelection.GetFirst; - while Assigned(xNode) do - begin - Include(xNode^.States, vsVisible); - if xNode^.ChildCount > 0 then - begin - lNode := xNode; - Inc(vtOptionMangaSiteSelection.RootNode^.TotalHeight, xNode^.NodeHeight); - end - else - if Assigned(lNode) then - if vsExpanded in lNode^.States then - Inc(vtOptionMangaSiteSelection.RootNode^.TotalHeight, xNode^.NodeHeight); - xNode := vtOptionMangaSiteSelection.GetNext(xNode); - end; - end - else - begin - xNode := vtOptionMangaSiteSelection.GetFirst; - while Assigned(xNode) do - begin - Include(xNode^.States, vsVisible); - if xNode^.ChildCount > 0 then - begin - if Assigned(lNode) then - begin - if lcount > 0 then - Inc(vtOptionMangaSiteSelection.RootNode^.TotalHeight, lNode^.NodeHeight) - else - Exclude(lNode^.States, vsVisible); - end; - lNode := xNode; - lcount := 0; - end - else - begin - data := vtOptionMangaSiteSelection.GetNodeData(xNode); - if Assigned(data) then - begin - if Pos(s, LowerCase(data^.Text)) <> 0 then - begin - Inc(lcount); - if Assigned(lNode) then - begin - if vsExpanded in lNode^.States then - Inc(vtOptionMangaSiteSelection.RootNode^.TotalHeight, xNode^.NodeHeight); - end; - end - else - Exclude(xNode^.States, vsVisible); - end; - end; - xNode := vtOptionMangaSiteSelection.GetNext(xNode); - end; - if Assigned(lNode) then - begin - if lcount > 0 then - Inc(vtOptionMangaSiteSelection.RootNode^.TotalHeight, lNode^.NodeHeight) - else - Exclude(lNode^.States, vsVisible); - end; - end; - finally - vtOptionMangaSiteSelection.EndUpdate; - end; + SearchOnVT(vtOptionMangaSiteSelection, edWebsitesSearch.Text); end; procedure TMainForm.btRemoveFilterClick(Sender: TObject); @@ -4594,7 +4460,7 @@ procedure TMainForm.AddChapterNameToList; procedure TMainForm.AddSilentThread(URL: string; MetaDataType: TMetaDataType); var - i, j, m: Integer; + i, m: Integer; host, link, webs: String; URls: TStringList; begin From 41d1181e64ea2f89436e2a6843d36c7f525f8555 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 28 Feb 2018 15:41:11 +0300 Subject: [PATCH 2466/2794] add HatigarmScans [EN-SC] #1080 --- lua/modules/FoOlSlide.lua | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index e6531b9e4..aa65753e0 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -46,7 +46,7 @@ function getdirurl(website) ['MangaichiScan'] = dirurlfsdir, ['Riceballicious'] = dirurlreaderlist, ['Yuri-ism'] = dirurlslide, - ['MangajinNoFansub'] = dirurllector + ['HatigarmScans'] = '/hs/directory/' } if dirs[website] ~= nil then return dirs[website] @@ -60,7 +60,7 @@ function getinfo() local result = net_problem if getWithCookie(lurl) then x = TXQuery.Create(http.document) - mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail"]/img/@src') + mangainfo.coverlink = x.xpathstring('//div[@class="thumbnail" or contains(@class, "thumb")]/img/@src') if mangainfo.title == '' then if module.website == 'AtelierDuNoir' then mangainfo.title = x.xpathstring('//div[@class="section-headline"]//h3') @@ -71,14 +71,18 @@ function getinfo() if Pos('emailprotected', mangainfo.title) > 0 then mangainfo.title = Trim(SeparateLeft(x.xpathstring('//title'), '::')) end + local cls = 'info' + if module.website == 'HatigarmScans' then + cls = 'well' + end mangainfo.authors = string.gsub( - x.xpathstring('//div[@class="info"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), + x.xpathstring('//div[@class="'..cls..'"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), '^[%s:]*', '') mangainfo.artists = string.gsub( - x.xpathstring('//div[@class="info"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), + x.xpathstring('//div[@class="'..cls..'"]/*[contains(text(),"Artist")]/following-sibling::text()[1]'), '^[%s:]*', '') mangainfo.summary = string.gsub( - x.xpathstring('//div[@class="info"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), + x.xpathstring('//div[@class="'..cls..'"]/*[contains(text(),"Synopsis")]/following-sibling::text()[1]'), '^[%s:]*', '') v = x.xpath('//div[@class="list"]//div[@class="title"]/a') for i = 1, v.count do @@ -171,6 +175,8 @@ function getnameandlink() links.add(x.xpathstring('div/a/@href', v1)) names.add(x.xpathstring('h4', v1)) end + elseif module.website == 'HatigarmScans' then + x.XpathHREFAll('//div[@class="grid"]/div/a', links, names) else x.XpathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', links, names) end @@ -225,6 +231,7 @@ function Init() AddWebsiteModule('SaikoScans', 'http://saikoscans.ml', cat) AddWebsiteModule('Yuri-ism', 'https://www.yuri-ism.net', cat) AddWebsiteModule('SilentSkyScans', 'http://reader.silentsky-scans.net', cat) + AddWebsiteModule('HatigarmScans', 'http://hatigarmscans.eu', cat) -- es-sc cat = 'Spanish-Scanlation' @@ -248,5 +255,4 @@ function Init() AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) AddWebsiteModule('Nightow', 'http://nightow.net', cat) AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) - AddWebsiteModule('MangajinNoFansub', 'https://www.mangajinnofansub.com', cat) end From dba20289bda665c9a2651fb0b838d5bedd373e79 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 28 Feb 2018 15:44:47 +0300 Subject: [PATCH 2467/2794] FoOlSlide, fix --- lua/modules/FoOlSlide.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index aa65753e0..b8fece380 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -46,6 +46,7 @@ function getdirurl(website) ['MangaichiScan'] = dirurlfsdir, ['Riceballicious'] = dirurlreaderlist, ['Yuri-ism'] = dirurlslide, + ['MangajinNoFansub'] = dirurllector, ['HatigarmScans'] = '/hs/directory/' } if dirs[website] ~= nil then @@ -255,4 +256,5 @@ function Init() AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) AddWebsiteModule('Nightow', 'http://nightow.net', cat) AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) + AddWebsiteModule('MangajinNoFansub', 'https://www.mangajinnofansub.com', cat) end From 32b9f52c29d480ac656e22a3a2634afee68e5e42 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 06:02:08 +0300 Subject: [PATCH 2468/2794] mangadex, change domain fixes #1083 --- lua/modules/MangaDex.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index b5f0bae61..c82458078 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -44,11 +44,9 @@ function getinfo() end function getpagenumber() - print('mangadex get') if http.get(MaybeFillHost(module.rooturl,url)) then local s=StreamToString(http.document) local lurl=MaybeFillHost(module.rooturl,AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/') - local page_array=GetBetween('var page_array = [','];',s) task.pagelinks.commatext=GetBetween('var page_array = [','];',s):gsub('\'','') task.pagelinks.text=Trim(task.pagelinks.text) for i=0,task.pagelinks.count-1 do @@ -102,7 +100,7 @@ function Init() m=NewModule() m.category='English' m.website='MangaDex' - m.rooturl='https://mangadex.com' + m.rooturl='https://mangadex.org' m.lastupdated='February 28, 2018' m.ongetinfo='getinfo' m.ontaskstart='taskstart' From 780f716661df443dd99d1558b13e80e5c89604d2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 28 Feb 2018 11:42:04 +0300 Subject: [PATCH 2469/2794] BaseCrypto, add MD5Hex, AESDecryptCBC --- baseunits/BaseCrypto.pas | 51 +++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/baseunits/BaseCrypto.pas b/baseunits/BaseCrypto.pas index 7b1731ba1..25c651bca 100644 --- a/baseunits/BaseCrypto.pas +++ b/baseunits/BaseCrypto.pas @@ -19,6 +19,8 @@ function Pkcs7RemovePad(const s: String): String; function AESEncrpytCBCSHA256Base64Pkcs7(const s, key, iv: String): string; function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; +function MD5Hex(const s: String): String; +function AESDecryptCBC(const s, key, iv: String): String; implementation @@ -133,28 +135,16 @@ function AESDecryptCBCSHA256Base64Pkcs7(const s, key, iv: String): string; end; end; -function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; +function AESDecryptCBC(const s, key, iv: String): String; var - keyHash: array[0 .. 15] of Byte; ivBytes: array[0 .. 15] of Byte; - keyBytes: array[0 .. 31] of Byte; + keyBytes: TBytes; i: Integer; - data: String; begin Result := ''; - - with TDCP_md5.Create(nil) do - try - Init; - UpdateStr(key); - Final(keyHash); - finally - Free; - end; - - data := LowerCase(StrToHexStr(BytesToString(keyHash))); - for i := 0 to 31 do - keyBytes[i] := Byte(data[i + 1]); + SetLength(keyBytes, Length(key)); + for i := 0 to Length(key)-1 do + keyBytes[i] := Byte(key[i + 1]); FillChar(ivBytes, 16, 0); for i := 0 to Min(16, Length(iv)) - 1 do @@ -162,15 +152,34 @@ function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; with TDCP_rijndael.Create(nil) do try - Init(keyBytes, 32*8, @ivBytes[0]); - data := DecodeStringBase64(s); - SetLength(Result,Length(data)); - DecryptCBC(data[1],Result[1],Length(data)); + Init(keyBytes, Length(key) * 8, @ivBytes[0]); + SetLength(Result,Length(s)); + DecryptCBC(s[1],Result[1],Length(s)); Burn; finally Free; end; end; +function AESDecryptCBCMD5Base64ZerosPadding(const s, key, iv: String): String; +begin + Result := AESDecryptCBC(DecodeStringBase64(s), MD5Hex(key), iv); +end; + +function MD5Hex(const s: String): String; +var + h: array[0 .. 15] of Byte; +begin + with TDCP_md5.Create(nil) do + try + Init; + UpdateStr(s); + Final(h); + finally + Free; + end; + Result := LowerCase(StrToHexStr(BytesToString(h))); +end; + end. From 3e8cffc1ee8a66e352e475133aca416ff6496ea0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 28 Feb 2018 12:33:40 +0300 Subject: [PATCH 2470/2794] register crypto function to lua --- baseunits/lua/LuaBase.pas | 4 ++- baseunits/lua/LuaCrypto.pas | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 baseunits/lua/LuaCrypto.pas diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index bc9a04e31..388e07f76 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -23,7 +23,8 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh implementation uses - luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog; + luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog, + LuaCrypto; function luabase_print(L: Plua_State): Integer; cdecl; var @@ -49,6 +50,7 @@ procedure LuaBaseRegister(L: Plua_State); luaRegExprRegister(L); luaSynaUtilRegister(L); luaSynaCodeRegister(L); + luaCryptoRegister(L); luaClassRegisterAll(L); end; diff --git a/baseunits/lua/LuaCrypto.pas b/baseunits/lua/LuaCrypto.pas new file mode 100644 index 000000000..ca3b65fbb --- /dev/null +++ b/baseunits/lua/LuaCrypto.pas @@ -0,0 +1,50 @@ +unit LuaCrypto; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, BaseCrypto; + +procedure luaCryptoRegister(L: Plua_State); + +implementation + +uses + LuaUtils; + +function crypto_hextostr(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, HexToStr(lua_tostring(L, 1))); + Result := 1; +end; + +function crypto_strtohexstr(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, StrToHexStr(lua_tostring(L, 1))); + Result := 1; +end; + +function crypto_md5hex(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, MD5Hex(lua_tostring(L, 1))); + Result := 1; +end; + +function crypto_aesdecryptcbc(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, AESDecryptCBC(lua_tostring(L, 1), lua_tostring(L, 2), lua_tostring(L, 3))); + Result := 1; +end; + +procedure luaCryptoRegister(L: Plua_State); +begin + luaPushFunctionGlobal(L, 'HexToStr', @crypto_hextostr); + luaPushFunctionGlobal(L, 'StrToHexStr', @crypto_strtohexstr); + luaPushFunctionGlobal(L, 'MD5Hex', @crypto_md5hex); + luaPushFunctionGlobal(L, 'AESDecryptCBC', @crypto_aesdecryptcbc); +end; + +end. + From 70cd673e9f7c5dda8ab9477ab7bd95e00630ca4c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 27 Feb 2018 09:34:49 +0300 Subject: [PATCH 2471/2794] add ImagePuzzle --- baseunits/ImagePuzzle.pas | 87 +++++++++++++++++++++++++ baseunits/modules/TonarinoYoungJump.pas | 71 +++++++------------- 2 files changed, 110 insertions(+), 48 deletions(-) create mode 100644 baseunits/ImagePuzzle.pas diff --git a/baseunits/ImagePuzzle.pas b/baseunits/ImagePuzzle.pas new file mode 100644 index 000000000..1629dd1c2 --- /dev/null +++ b/baseunits/ImagePuzzle.pas @@ -0,0 +1,87 @@ +unit ImagePuzzle; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Graphics, Types; + +type + TImagePuzzle = class + private + FHorBlock, FVerBlock, FMultiply: Integer; + FMatrix: TIntegerDynArray; + public + constructor Create(horBlockCount, verBlockCount: Integer); + procedure DeScramble(input, output: TStream); + property HorBlock: Integer read FHorBlock; + property VerBlock: Integer read FVerBlock; + property Multiply: Integer read FMultiply write FMultiply default 1; + property Matrix: TIntegerDynArray read FMatrix; + end; + +implementation + +uses Math; + +constructor TImagePuzzle.Create(horBlockCount, verBlockCount: Integer); +var i: Integer; +begin + FHorBlock := horBlockCount; + FVerBlock := verBlockCount; + SetLength(FMatrix, FHorBlock * FVerBlock); + for i := 0 to High(FMatrix) do + FMatrix[i] := i; +end; + +procedure TImagePuzzle.DeScramble(input, output: TStream); +var + image, result: TPicture; + blockWidth, blockHeight: Extended; + i, row, col: Integer; + x1, y1: Integer; + dstrect, srcrect: TRect; + ext: String = 'jpg'; +begin + if not Assigned(input) or not Assigned(output) then Exit; + Assert(Assigned(Matrix), 'Matrix is not set'); + Assert(Length(Matrix) >= HorBlock * VerBlock, 'Invalid matrix size'); + image := TPicture.Create; + result := TPicture.Create; + try + image.LoadFromStream(input); + if image.Graphic is TPortableNetworkGraphic then ext := 'png'; + result.Bitmap.SetSize(image.Width, image.Height); + if Multiply <= 1 then begin + blockWidth := float(image.Width) / HorBlock; + blockHeight := float(image.Height) / VerBlock; + end + else begin + blockWidth := trunc(float(image.Width) / (HorBlock * Multiply)) * Multiply; + blockHeight := trunc(float(image.Height) / (VerBlock * Multiply)) * Multiply; + end; + for i := 0 to HorBlock * VerBlock - 1 do begin + row := floor(float(Matrix[i]) / VerBlock); + col := Matrix[i] - row * HorBlock; + x1 := trunc(col * blockWidth); + y1 := trunc(row * blockHeight); + dstrect := Rect(x1, y1, Trunc(x1 + blockWidth), Trunc(y1 + blockHeight)); + row := floor(float(i) / HorBlock); + col := i - row * HorBlock; + x1 := trunc(col * blockWidth); + y1 := trunc(row * blockHeight); + srcrect := Rect(x1, y1, Trunc(x1 + blockWidth), Trunc(y1 + blockHeight)); + result.Bitmap.Canvas.CopyRect(dstrect, image.Bitmap.Canvas, srcrect); + end; + output.Position := 0; + output.Size := 0; + result.SaveToStreamWithFileExt(output, ext); + finally + result.Free; + image.Free; + end; +end; + +end. + diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonarinoYoungJump.pas index 0848a6661..7d7821608 100644 --- a/baseunits/modules/TonarinoYoungJump.pas +++ b/baseunits/modules/TonarinoYoungJump.pas @@ -2,18 +2,18 @@ interface -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; - implementation -uses Graphics, Math, synautil; +uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, Math, synautil, ImagePuzzle; const chapterListQuery = '/api/viewer/readable_products?current_readable_product_id=%s&number_since=%d&number_until=-1&read_more_num=50&type=episode'; dirurls: array[0..2] of String = ('/series', '/series/finished', '/series/oneshot'); +var + puzzle: TImagePuzzle; + function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; @@ -116,58 +116,29 @@ function GetPageNumber(const DownloadThread: TDownloadThread; end; end; -function DeScramble(AURL: String; image: TPicture): TPicture; -const - DIVIDE_NUM = 4; - MULTIPLE = 8; -var - cell_width, cell_height, e, sx, sy, dx, dy, a: Integer; - srcrect, destrect: TRect; - r: TPicture; -begin - Result := nil; - cell_width := Trunc(Real(image.Width) / Real(DIVIDE_NUM * MULTIPLE)) * MULTIPLE; - cell_height := Trunc(Real(image.Height) / Real(DIVIDE_NUM * MULTIPLE)) * MULTIPLE; - r := TPicture.Create; - r.Bitmap.SetSize(image.Width, image.Height); - for e := 0 to DIVIDE_NUM * DIVIDE_NUM - 1 do begin - sy := Trunc(Real(e) / Real(DIVIDE_NUM)) * cell_height; - sx := (e mod DIVIDE_NUM) * cell_width; - a := (e mod DIVIDE_NUM) * DIVIDE_NUM + Trunc(Real(e) / Real(DIVIDE_NUM)); - dx := (a mod DIVIDE_NUM) * cell_width; - dy := Trunc(Real(a) / Real(DIVIDE_NUM)) * cell_height; - srcrect := Rect(sx, sy, sx + cell_width, sy + cell_height); - destrect := Rect(dx, dy, dx + cell_width, dy + cell_height); - r.Bitmap.Canvas.CopyRect(destrect, image.Bitmap.Canvas, srcrect); - end; - Result := r; -end; - function DownloadImage(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; -var - image, r: TPicture; begin Result := False; if DownloadThread = nil then Exit; if DownloadThread.FHTTP.GET(AURL) then begin - image := TPicture.Create; - r := nil; - try - image.LoadFromStream(DownloadThread.FHTTP.Document); - r := DeScramble(AURL, image); - if r <> nil then begin - DownloadThread.FHTTP.Document.Clear; - r.SaveToStreamWithFileExt(DownloadThread.FHTTP.Document, 'jpg'); - Result := True; - end; - finally - r.Free; - image.Free; - end; + puzzle.DeScramble(DownloadThread.FHTTP.Document, DownloadThread.FHTTP.Document); + Result := True; end; end; +procedure CreateImagePuzzle; +const + DIVIDE_NUM = 4; +var + i: Integer; +begin + puzzle := TImagePuzzle.Create(DIVIDE_NUM, DIVIDE_NUM); + puzzle.Multiply := 8; + for i := 0 to DIVIDE_NUM * DIVIDE_NUM - 1 do + puzzle.Matrix[i] := (i mod DIVIDE_NUM) * DIVIDE_NUM + trunc(float(i) / DIVIDE_NUM); +end; + procedure RegisterModule; begin with AddModule do @@ -184,6 +155,10 @@ procedure RegisterModule; end; initialization + CreateImagePuzzle; RegisterModule; +finalization + puzzle.Free; + end. From 91fc0701c683569f2fe5d56a0397cefc4b72eb35 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 28 Feb 2018 12:37:51 +0300 Subject: [PATCH 2472/2794] register imagepuzzle to lua --- baseunits/lua/LuaBase.pas | 2 +- baseunits/lua/LuaImagePuzzle.pas | 104 +++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 baseunits/lua/LuaImagePuzzle.pas diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 388e07f76..77725a02f 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -24,7 +24,7 @@ implementation uses luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog, - LuaCrypto; + LuaCrypto, LuaImagePuzzle; function luabase_print(L: Plua_State): Integer; cdecl; var diff --git a/baseunits/lua/LuaImagePuzzle.pas b/baseunits/lua/LuaImagePuzzle.pas new file mode 100644 index 000000000..43afc43de --- /dev/null +++ b/baseunits/lua/LuaImagePuzzle.pas @@ -0,0 +1,104 @@ +unit LuaImagePuzzle; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, ImagePuzzle; + +procedure luaImagePuzzlePush(L: Plua_State; Obj: TImagePuzzle; Name: String = ''; + AutoFree: Boolean = False); inline; + +implementation + +uses LuaClass, LuaUtils; + +type + TUserData = TImagePuzzle; + +function imagepuzzle_create(L: Plua_State): Integer; cdecl; +begin + if lua_gettop(L) = 2 then + if lua_isinteger(L, 1) and lua_isinteger(L, 2) then + luaImagePuzzlePush(L, TImagePuzzle.Create(lua_tointeger(L, 1), lua_tointeger(L, 2)), '', True); + Result := 1; +end; + +function imagepuzzle_descramble(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).DeScramble( + TStream(luaGetUserData(L, 1)), + TStream(luaGetUserData(L, 2))); +end; + +function imagepuzzle_matrixget(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).Matrix[lua_tointeger(L, 1)]); + Result := 1; +end; + +function imagepuzzle_matrixset(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TUserData(luaClassGetObject(L)).Matrix[lua_tointeger(L, 1)] := lua_tointeger(L, 2); +end; + +function imagepuzzle_gethorblock(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).HorBlock); + Result := 1; +end; + +function imagepuzzle_getverblock(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).VerBlock); + Result := 1; +end; + +const + constructs: packed array [0..2] of luaL_Reg = ( + (name: 'New'; func: @imagepuzzle_create), + (name: 'Create'; func: @imagepuzzle_create), + (name: nil; func: nil) + ); + props: packed array[0..2] of lual_Reg_prop = ( + (name: 'HorBlock'; funcget: @imagepuzzle_gethorblock; funcset: nil), + (name: 'VerBlock'; funcget: @imagepuzzle_getverblock; funcset: nil), + (name: nil; funcget: nil; funcset: nil) + ); + arrprops: packed array[0..1] of luaL_Reg_prop = ( + (name: 'Matrix'; funcget: @imagepuzzle_matrixget; funcset: @imagepuzzle_matrixset), + (name: nil; funcget: nil; funcset: nil) + ); + methods: packed array [0..1] of luaL_Reg = ( + (name: 'DeScramble'; func: @imagepuzzle_descramble), + (name: nil; func: nil) + ); + +procedure luaImagePuzzleAddMetaTable(L: Plua_State; Obj: Pointer; + MetaTable, UserData: Integer; AutoFree: Boolean = False); +begin + luaClassAddFunction(L, MetaTable, UserData, methods); + luaClassAddProperty(L, MetaTable, UserData, props); + luaClassAddArrayProperty(L, MetaTable, UserData, arrprops); + luaClassAddIntegerProperty(L, MetaTable, 'Multiply', @TUserData(Obj).Multiply); +end; + +procedure luaImagePuzzlePush(L: Plua_State; Obj: TImagePuzzle; Name: String; + AutoFree: Boolean); +begin + luaClassPushObject(L, Obj, Name, AutoFree, @luaImagePuzzleAddMetaTable); +end; + +procedure luaImagePuzzleRegister(L: Plua_State); +begin + luaClassNewLib(L, 'TImagePuzzle', constructs); +end; + +initialization + luaClassRegister(TUserData, @luaImagePuzzleAddMetaTable, @luaImagePuzzleRegister); + +end. + From 8d591e14e61159a823d782e0a9d4bb86a241bec3 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 12:52:39 +0300 Subject: [PATCH 2473/2794] add TrashScanlations [EN-SC] fixes #1041 --- lua/modules/rawdevart.lua | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 52690de93..6f69e22b5 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -19,7 +19,11 @@ end function getpagenumber() task.pagelinks.clear() - if http.get(MaybeFillHost(module.rooturl, url)) then + local aurl = MaybeFillHost(module.rooturl, url) + if Pos('style=list', aurl) == 0 then + aurl = aurl .. '?style=list' + end + if http.get(aurl) then x=TXQuery.Create(http.Document) v=x.xpathstringall('//div[@class="page-break"]/img/@src', task.pagelinks) else @@ -32,7 +36,6 @@ local perpage = 100 function getnameandlink() local q = 'action=madara_load_more&page='.. url ..'&template=madara-core%2Fcontent%2Fcontent-archive&vars%5Bpost_type%5D=wp-manga&vars%5Berror%5D=&vars%5Bm%5D=&vars%5Bp%5D=0&vars%5Bpost_parent%5D=&vars%5Bsubpost%5D=&vars%5Bsubpost_id%5D=&vars%5Battachment%5D=&vars%5Battachment_id%5D=0&vars%5Bname%5D=&vars%5Bstatic%5D=&vars%5Bpagename%5D=&vars%5Bpage_id%5D=0&vars%5Bsecond%5D=&vars%5Bminute%5D=&vars%5Bhour%5D=&vars%5Bday%5D=0&vars%5Bmonthnum%5D=0&vars%5Byear%5D=0&vars%5Bw%5D=0&vars%5Bcategory_name%5D=&vars%5Btag%5D=&vars%5Bcat%5D=&vars%5Btag_id%5D=&vars%5Bauthor%5D=&vars%5Bauthor_name%5D=&vars%5Bfeed%5D=&vars%5Btb%5D=&vars%5Bpaged%5D=1&vars%5Bmeta_key%5D=&vars%5Bmeta_value%5D=&vars%5Bpreview%5D=&vars%5Bs%5D=&vars%5Bsentence%5D=&vars%5Btitle%5D=&vars%5Bfields%5D=&vars%5Bmenu_order%5D=&vars%5Bembed%5D=&vars%5Bignore_sticky_posts%5D=false&vars%5Bsuppress_filters%5D=false&vars%5Bcache_results%5D=true&vars%5Bupdate_post_term_cache%5D=true&vars%5Blazy_load_term_meta%5D=true&vars%5Bupdate_post_meta_cache%5D=true&vars%5Bposts_per_page%5D='.. tostring(perpage) ..'&vars%5Bnopaging%5D=false&vars%5Bcomments_per_page%5D=50&vars%5Bno_found_rows%5D=false&vars%5Border%5D=ASC&vars%5Borderby%5D=post_title&vars%5Btemplate%5D=archive&vars%5Bsidebar%5D=full&vars%5Bpost_status%5D=publish' - if http.post(module.rooturl .. '/wp-admin/admin-ajax.php', q) then if http.headers.values['Content-Length'] == '0' then return no_error end x = TXQuery.Create(http.Document) @@ -45,13 +48,19 @@ function getnameandlink() end end -function Init() +function AddWebsiteModule(name, url, category) local m = NewModule() - m.website = 'Rawdevart' - m.rooturl = 'https://rawdevart.com' - m.category = 'Raw' - m.lastupdated='February 22, 2018' + m.website = name + m.rooturl = url + m.category = category + m.lastupdated = 'March 1, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' + return m +end + +function Init() + AddWebsiteModule('Rawdevart', 'https://rawdevart.com', 'Raw') + AddWebsiteModule('TrashScanlations', 'http://trashscanlations.com', 'English-Scanlation') end From 824e486d9090012b3b66a2b8e8694b1ea56d001b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 15:50:31 +0300 Subject: [PATCH 2474/2794] lua modules, remove print --- lua/modules/HentaiHere.lua | 1 - lua/modules/MangaOku.lua | 1 - lua/modules/TenManga.lua | 1 - 3 files changed, 3 deletions(-) diff --git a/lua/modules/HentaiHere.lua b/lua/modules/HentaiHere.lua index 2a9a022ec..46ed1528c 100644 --- a/lua/modules/HentaiHere.lua +++ b/lua/modules/HentaiHere.lua @@ -29,7 +29,6 @@ function GetPageNumber() v=x.xpath('json(*)()') for i=1,v.count do v1=v.get(i) - print(v1.toString) task.pagelinks.add('https://hentaicdn.com/hentai' .. v1.toString) end return true diff --git a/lua/modules/MangaOku.lua b/lua/modules/MangaOku.lua index 3e43c02ac..3bb518e1e 100644 --- a/lua/modules/MangaOku.lua +++ b/lua/modules/MangaOku.lua @@ -20,7 +20,6 @@ end function getpagenumber() task.pagelinks.clear() task.pagenumber=0 - print(MaybeFillHost(module.rooturl,url)) if http.get(MaybeFillHost(module.rooturl,url)) then local x=TXQuery.Create(http.Document) task.pagenumber = x.xpath('//select[@name="page"]/option').count diff --git a/lua/modules/TenManga.lua b/lua/modules/TenManga.lua index 45a977a62..b64b2a03d 100644 --- a/lua/modules/TenManga.lua +++ b/lua/modules/TenManga.lua @@ -30,7 +30,6 @@ function getpagenumber() if http.get(MaybeFillHost(module.rooturl, url)) then task.pagenumber=TXQuery.Create(http.Document).xpathcount('(//select[@class="sl-page"])[1]/option') module.storage.text = http.cookies.text - print(module.storage.text) else return false end From e40d93d53e1ff777a9619d08fbee94ab90a9821a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 16:07:50 +0300 Subject: [PATCH 2475/2794] add somanga [PT] --- lua/modules/SoManga.lua | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 lua/modules/SoManga.lua diff --git a/lua/modules/SoManga.lua b/lua/modules/SoManga.lua new file mode 100644 index 000000000..a38ad4296 --- /dev/null +++ b/lua/modules/SoManga.lua @@ -0,0 +1,62 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[contains(@class, "manga")]//img/@src')) + mangainfo.authors=x.xpathstringall('//div[contains(@class, "manga")]//h5[contains(*, "Autor")]/text()', '') + mangainfo.artists=x.xpathstringall('//div[contains(@class, "manga")]//h5[contains(*, "Artista")]/text()', '') + mangainfo.genres=x.xpathstringall('//div[contains(@class, "manga")]//h5[contains(*, "Genero")]/span') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(@class, "manga")]//h5[contains(*, "Status")]/text()', 'Ativo', 'Completo')) + mangainfo.summary=x.xpathstring('//div[contains(@class, "manga")]//div[contains(@style, "justify")]') + local v=x.xpath('//ul[@class="capitulos"]/li/a') + for i=1,v.count do + local v1=v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + mangainfo.chapternames.add(x.xpathstring('div/text()', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[contains(@class, "img-manga")]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/php/busca-mangas.php') then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//ul/li[@class="mangas"]/div/a', links, names) + for i=1,v.count do + local v1=v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('div/h3', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'SoManga' + m.rooturl = 'http://somangas.net' + m.category = 'Portugues' + m.lastupdated='March 1, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetimageurl='getimageurl' +end From 4032758bdbe77915ad037aef1927e28450d2dbc1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 16:27:20 +0300 Subject: [PATCH 2476/2794] SoManga, fix --- lua/modules/SoManga.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/SoManga.lua b/lua/modules/SoManga.lua index a38ad4296..282a9b5a3 100644 --- a/lua/modules/SoManga.lua +++ b/lua/modules/SoManga.lua @@ -58,5 +58,4 @@ function Init() m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' - m.ongetimageurl='getimageurl' end From 3820330cf20855e22e96bfbaa23ef012f642c1af Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 16:43:20 +0300 Subject: [PATCH 2477/2794] add ReadMangaEU [EN] --- lua/modules/ReadMangaEU.lua | 60 +++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lua/modules/ReadMangaEU.lua diff --git a/lua/modules/ReadMangaEU.lua b/lua/modules/ReadMangaEU.lua new file mode 100644 index 000000000..439c0b693 --- /dev/null +++ b/lua/modules/ReadMangaEU.lua @@ -0,0 +1,60 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1[@class="ebook_title"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[contains(@class, "ebook_cover")]/@src')) + mangainfo.authors=x.xpathstring('//table[@class="details_table"]/tbody/tr[contains(td, "Author")]/td[2]') + mangainfo.genres=x.xpathstringall('//table[@class="details_table"]/tbody/tr[contains(td, "Genres")]/td[2]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="details_table"]/tbody/tr[contains(td, "Status")]/td[2]')) + mangainfo.summary=x.xpathstring('//*[@class="ebook_description"]') + x.xpathhrefall('//div[contains(@class,"chapters")]/span[not(@id="show_all")]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + task.pagenumber=TXQuery.Create(http.Document).xpathcount('//select[@id="jumpto"]/option') + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/manga-list') then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//ul[@class="ul_list"]/li/a', links, names) + return no_error + else + return net_problem + end +end + +function getimageurl() + if http.get(MaybeFillHost(module.rooturl,url):gsub('%d+$',tostring(workid+1))) then + local x = TXQuery.create(http.document) + local s = x.xpathstring('//img[contains(@class, "ebook_img")]/@src') + task.pagelinks[workid] = MaybeFillHost(module.rooturl, s) + return true + end + return false +end + +function Init() + local m = NewModule() + m.website = 'ReadMangaEU' + m.rooturl = 'http://www.readmanga.eu' + m.category = 'English' + m.lastupdated='March 1, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetimageurl='getimageurl' +end From a9b61c432b4ded53a0710df894d4a96afed136cc Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 19:37:43 +0300 Subject: [PATCH 2478/2794] FunManga, move to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/FunManga.pas | 132 --------------------------------- lua/modules/FunManga.lua | 65 ++++++++++++++++ 3 files changed, 65 insertions(+), 133 deletions(-) delete mode 100644 baseunits/modules/FunManga.pas create mode 100644 lua/modules/FunManga.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 5307f7c4e..e853993f2 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -35,7 +35,6 @@ uses LeoManga, MangaPark, MangaIndo, - FunManga, MangaOnlineTo, MyMangaMe, ReadComics, diff --git a/baseunits/modules/FunManga.pas b/baseunits/modules/FunManga.pas deleted file mode 100644 index 4c32212ea..000000000 --- a/baseunits/modules/FunManga.pas +++ /dev/null @@ -1,132 +0,0 @@ -unit FunManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/manga-list'; - diralpha = '#abcdefghijklmnopqrstuvwxyz'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NO_ERROR; - Page := Length(diralpha); -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - s: String; - v: IXQValue; -begin - Result := NET_PROBLEM; - s := Module.RootURL + dirurl; - if AURL <> '0' then - s := s + '/' + diralpha[StrToIntDef(AURL, 0) + 1] ; - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="content"]/div/div[@class="row"]//li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="content"]//img/@src')); - if title = '' then title := XPathString('//div[@class="content"]//h5'); - authors := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Author")]/following-sibling::dd[1]/a'); - artists := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Artist")]/following-sibling::dd[1]/a'); - genres := XPathStringAll('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Categories")]/following-sibling::dd[1]/a'); - status := MangaInfoStatusIfPos(XPathString( - '//dl[@class="dl-horizontal"]/dt[starts-with(.,"Status")]/following-sibling::dd[1]'), - 'Ongoing', - 'Completed'); - summary := XPathString('//div[@class="content"]/div/div[contains(@class,"note")]'); - for v in XPath('//ul[@class="chapter-list"]/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathString('span[1]', v)); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - s := MaybeFillHost(Module.RootURL, AURL); - if Pos('/all-pages', s) = 0 then - s := s + '/all-pages'; - if GET(s) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('//div[contains(@class,"content-inner")]/img/@src', PageLinks); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'FunManga'; - RootURL := 'http://www.funmanga.com'; - Category := 'English'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/FunManga.lua b/lua/modules/FunManga.lua new file mode 100644 index 000000000..e862f974b --- /dev/null +++ b/lua/modules/FunManga.lua @@ -0,0 +1,65 @@ +local ALPHA_LIST = '#abcdefghijklmnopqrstuvwxyz' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="content"]//h5') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="content"]//img/@src')) + mangainfo.authors=x.xpathstringall('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Author")]/following-sibling::dd[1]/a') + mangainfo.artists=x.xpathstringall('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Artist")]/following-sibling::dd[1]/a') + mangainfo.genres=x.xpathstringall('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Categories")]/following-sibling::dd[1]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//dl[@class="dl-horizontal"]/dt[starts-with(.,"Status")]/following-sibling::dd[1]')) + mangainfo.summary=x.xpathstring('//div[@class="content"]/div/div[contains(@class,"note")]') + local v=x.xpath('//ul[@class="chapter-list"]/li/a') + for i=1,v.count do + local v1=v.get(i) + mangainfo.chapterlinks.add(v1.getattribute('href')) + mangainfo.chapternames.add(x.xpathstring('span[1]', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + local s = MaybeFillHost(module.rooturl, url) + if Pos('/all-pages', s) == 0 then s = s .. '/all-pages' end + if http.get(s) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[contains(@class,"content-inner")]/img/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + local s = '' + if module.CurrentDirectoryIndex ~= 0 then + s = '/'..ALPHA_LIST:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) + end + if http.get(module.rooturl .. '/manga-list' .. s) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@class="content"]/div/div[@class="row"]//li/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'FunManga' + m.rooturl = 'http://www.funmanga.com' + m.category = 'English' + m.lastupdated='March 1, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.totaldirectory = ALPHA_LIST:len() +end From 49eb72767435ffa6982b1a356cbc75e687f44690 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 1 Mar 2018 20:04:01 +0300 Subject: [PATCH 2479/2794] add MangaDoom [EN] --- lua/modules/FunManga.lua | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lua/modules/FunManga.lua b/lua/modules/FunManga.lua index e862f974b..f1f6fcf35 100644 --- a/lua/modules/FunManga.lua +++ b/lua/modules/FunManga.lua @@ -31,7 +31,7 @@ function getpagenumber() if Pos('/all-pages', s) == 0 then s = s .. '/all-pages' end if http.get(s) then local x=TXQuery.Create(http.Document) - x.xpathstringall('//div[contains(@class,"content-inner")]/img/@src', task.pagelinks) + x.xpathstringall('//div[contains(@class,"content-inner")]//img/@src', task.pagelinks) else return false end @@ -43,7 +43,9 @@ function getnameandlink() if module.CurrentDirectoryIndex ~= 0 then s = '/'..ALPHA_LIST:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) end - if http.get(module.rooturl .. '/manga-list' .. s) then + local dirurl = '/manga-list' + if module.website == 'MangaDoom' then dirurl = '/manga-directory' end + if http.get(module.rooturl .. dirurl .. s) then local x = TXQuery.Create(http.Document) x.XPathHREFAll('//div[@class="content"]/div/div[@class="row"]//li/a', links, names) return no_error @@ -52,14 +54,20 @@ function getnameandlink() end end -function Init() +function AddWebsiteModule(name, url) local m = NewModule() - m.website = 'FunManga' - m.rooturl = 'http://www.funmanga.com' + m.website = name + m.rooturl = url m.category = 'English' - m.lastupdated='March 1, 2018' + m.lastupdated = 'March 1, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.totaldirectory = ALPHA_LIST:len() + return m +end + +function Init() + AddWebsiteModule('FunManga', 'http://www.funmanga.com') + AddWebsiteModule('MangaDoom', 'http://www.mngdoom.com') end From aa28d09a924c25336abf6a9a77a1a730b8df90d3 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 2 Mar 2018 16:11:52 +0300 Subject: [PATCH 2480/2794] Update Russian localization --- mangadownloader/languages/fmd.ru_RU.po | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index f17c9f3fa..6b7042e72 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -572,7 +572,7 @@ msgstr "Обновить" #: taccountmanagerform.caption msgid "AccountManagerForm" -msgstr "" +msgstr "AccountManagerForm" #: taccountmanagerform.vtaccountlist.header.columns[1].text msgctxt "TACCOUNTMANAGERFORM.VTACCOUNTLIST.HEADER.COLUMNS[1].TEXT" @@ -600,7 +600,7 @@ msgstr "OK" #: taccountsetform.caption msgid "Account" -msgstr "" +msgstr "Учетная запись" #: taccountsetform.ckshowpassword.caption msgid "Show password" @@ -2398,15 +2398,15 @@ msgstr "Выбрать сайт" #: twebsitesettingsform.caption msgid "WebsiteSettingsForm" -msgstr "" +msgstr "WebsiteSettingsForm" #: twebsitesettingsform.edsearch.texthint msgid "Website name" -msgstr "" +msgstr "Название сайта" #: twebsitesettingsform.edsearchproperty.texthint msgid "Setting name" -msgstr "" +msgstr "Название параметра" #: udownloadsmanager.rs_compressing msgid "Compressing..." From 42c5bbea23a1949d0ab1e11f9ab21ed6880e7697 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 07:17:17 +0300 Subject: [PATCH 2481/2794] add rawmangaupdate [raw] --- lua/modules/myReaderMangaCMS.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index a8a4367ed..c7284dd12 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -67,6 +67,7 @@ function Init() AddWebsiteModule('MangaForest', 'http://mangaforest.com', 'English') AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', 'Turkish'); + AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', 'Raw'); local c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); From 76c8a4701a3e92fc76301478e3b1df43afe43d64 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 07:25:32 +0300 Subject: [PATCH 2482/2794] add ManhuaTr [Turkish] --- lua/modules/myReaderMangaCMS.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index c7284dd12..9aafac7eb 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -66,13 +66,16 @@ end function Init() AddWebsiteModule('MangaForest', 'http://mangaforest.com', 'English') AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); - AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', 'Turkish'); AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', 'Raw'); local c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); AddWebsiteModule('MangaDesu','http://mangadesu.net', c); AddWebsiteModule('MangaID', 'http://mangaid.co', c); + + c='Turkish' + AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', c); + AddWebsiteModule('ManhuaTr', 'http://manhua-tr.com', c); c='English-Scanlation' AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); From e1e4c25b64371f424d97996b650296e6768d83f2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 07:27:58 +0300 Subject: [PATCH 2483/2794] add MangaVadisi [Turkish] --- lua/modules/myReaderMangaCMS.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 9aafac7eb..aa30ba5ba 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -14,7 +14,7 @@ function GetInfo(); x = TXQuery.Create(http.Document) mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) if mangainfo.title == '' then - mangainfo.title = x.XPathString('//h2[@class="widget-title"]') + mangainfo.title = x.XPathString('//h2[contains(@class,"widget-title")]') end if module.Website == 'MangaDenizi' then mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') @@ -76,6 +76,7 @@ function Init() c='Turkish' AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', c); AddWebsiteModule('ManhuaTr', 'http://manhua-tr.com', c); + AddWebsiteModule('MangaVadisi', 'http://manga-v2.mangavadisi.org/', c); c='English-Scanlation' AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); From 14b444436287174f67681c24a41b22b43b8f74fa Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 07:45:55 +0300 Subject: [PATCH 2484/2794] add Manga99 [en] --- lua/modules/WPManga.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index bf8ba457b..06296265b 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -149,9 +149,15 @@ function getdirectorypagenumber() end function getnameandlink() + local w = { + ['MangaSpy'] = true, + ['MangaIce'] = true, + ['MangaDeep'] = true, + ['Manga99'] = true + } if http.GET(AppendURLDelim(module.RootURL) .. getdirurl(module.website) .. IncStr(url) .. '/') then x = TXQuery.Create(http.Document) - if (module.website == 'MangaSpy') or (module.website == 'MangaIce') or (module.website == 'MangaDeep') then + if w[module.website] then x.XPathHREFAll('//*[contains(@id,"content")]//*[@class="det"]/a', links, names) else x.XPathHREFtitleAll('//*[contains(@id,"content")]//a[./img]', links, names); @@ -184,6 +190,7 @@ function Init() AddWebsiteModule('Authrone', 'http://www.authrone.com', cat) AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', cat) AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com', cat) + AddWebsiteModule('Manga99', 'http://www.manga99.com', cat) cat = 'H-Sites' AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', cat) From f29339fcec25f371095a526654074928845f3344 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 09:55:45 +0300 Subject: [PATCH 2485/2794] add MangaRawOnline [Raw] fixes #1093 --- lua/modules/myReaderMangaCMS.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index aa30ba5ba..f0d3f7810 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -15,6 +15,9 @@ function GetInfo(); mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) if mangainfo.title == '' then mangainfo.title = x.XPathString('//h2[contains(@class,"widget-title")]') + if mangainfo.title == '' then + mangainfo.title = mangainfo.url:match('/([^/]+)$') + end end if module.Website == 'MangaDenizi' then mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') @@ -66,13 +69,16 @@ end function Init() AddWebsiteModule('MangaForest', 'http://mangaforest.com', 'English') AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); - AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', 'Raw'); local c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); AddWebsiteModule('MangaDesu','http://mangadesu.net', c); AddWebsiteModule('MangaID', 'http://mangaid.co', c); + c='Raw' + AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', c); + AddWebsiteModule('MangaRawOnline', 'http://mangaraw.online', c); + c='Turkish' AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', c); AddWebsiteModule('ManhuaTr', 'http://manhua-tr.com', c); From 17d04ead49877af2a131131ac95bef3903e2979b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 14:41:49 +0300 Subject: [PATCH 2486/2794] add mangalib [ru] --- lua/modules/MangaLib.lua | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 lua/modules/MangaLib.lua diff --git a/lua/modules/MangaLib.lua b/lua/modules/MangaLib.lua new file mode 100644 index 000000000..8fe93d6df --- /dev/null +++ b/lua/modules/MangaLib.lua @@ -0,0 +1,68 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//*[@class="manga__title"]/h2') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@class="manga__cover"]/@src')) + mangainfo.authors=x.xpathstringall('//div[@class="manga-info"]//p[contains(*, "Автор")]/a') + mangainfo.artists=x.xpathstringall('//div[@class="manga-info"]//p[contains(*, "Художник")]/a') + mangainfo.genres=x.xpathstringall('//div[@class="manga-info"]//p[contains(*, "Жанры")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="manga-info"]//p[contains(*, "Перевод")]/span', 'продолжается', 'завершен')) + mangainfo.summary=x.xpathstringall('//div[contains(@class, "manga__desc")]/blockquote/text()', '') + x.xpathhrefall('//div[@class="chapters-list"]/div/div[@class="chapter-item__name"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "var pages")]') + local base = s:match('%.scan%-page.+src\'%s*,%s*\'([^\']+)\'') + s = GetBetween('var pages =', ';', s) + x.parsehtml(s) + local v = x.xpath('json(*)().page_image') + for i = 1,v.count do + local v1=v.get(i) + task.pagelinks.add(base .. '/' .. v1.tostring) + end + else + return false + end + return true +end + +function getnameandlink() + if tonumber(url) < 0 then return no_error end + if http.get(module.rooturl .. '/filterlist?page='..IncStr(url)..'&cat=&alpha=&sortBy=name&asc=true&author=&artist=') then + local x = TXQuery.Create(http.Document) + if x.xpathstring('//div/p[contains(., "Ничего не найдено")]') == '' then + local v = x.xpath('//ul[contains(@class, "manga-list")]/li/div/div[@class="heading"]/a[@class="ttl"]') + for i=1,v.count do + local v1=v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstringall('h2/text()', '', v1)) + end + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'MangaLib' + m.rooturl = 'https://mangalib.me' + m.category = 'Russian' + m.lastupdated='March 3, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end \ No newline at end of file From 2f39c76bf0fc82832a1cacba3dedaac9acfc3dde Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 3 Mar 2018 20:09:15 +0300 Subject: [PATCH 2487/2794] add desu.me [ru] --- lua/modules/DesuMe.lua | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 lua/modules/DesuMe.lua diff --git a/lua/modules/DesuMe.lua b/lua/modules/DesuMe.lua new file mode 100644 index 000000000..e5a7bea27 --- /dev/null +++ b/lua/modules/DesuMe.lua @@ -0,0 +1,70 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1/span[@class="name"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@itemprop="image"]/@src')) + mangainfo.genres=x.xpathstringall('//ul[@class="tagList"]/li/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//span[contains(@class, "status_tag")]', 'выходит', 'издано')) + mangainfo.summary=x.xpathstring('//div[@itemprop="description"]') + x.xpathhrefall('//ul[@class="chlist"]/li/h4/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "Reader.init")]') + s = GetBetween('.init(', ');', s) + x.parsehtml(s) + local dir = x.xpathstring('json(*).dir') + local v = x.xpath('json(*).images()()') + for i = 1,v.count,3 do + local v1=v.get(i) + task.pagelinks.add(dir .. v1.tostring) + end + else + return false + end + return true +end + +local dirurl = '/manga/?order_by=name&page=' +function getnameandlink() + if http.get(module.rooturl .. dirurl .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//div[@class="animeList"]/ol/li/div/h3/a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. dirurl .. '1') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//div[@class="PageNav"]/nav/a[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'DesuMe' + m.rooturl = 'https://desu.me' + m.category = 'Russian' + m.lastupdated='March 3, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end \ No newline at end of file From af9a025959ba21f51d577d86733b2913b5e5d07c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 4 Mar 2018 09:07:29 +0300 Subject: [PATCH 2488/2794] add MangaOnlineToday [en] --- lua/modules/WPManga.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 06296265b..2779b5a27 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -17,6 +17,9 @@ function getinfo() if module.website == 'HentaiRead' then mangainfo.chapterLinks.Add(x.XPathString('//a[@class="lst"]/@href')) mangainfo.chapterNames.Add(mangainfo.title) + elseif module.website == 'MangaOnlineToday' then + mangainfo.summary = x.XPathString('//div[contains(@class,"mng_det")]/p[1]') + x.xpathhrefall('//ul[@class="chp_lst"]/li/a', mangainfo.chapterLinks, mangainfo.chapterNames) else while true do v = x.XPath('//a[@class="lst"]') @@ -159,6 +162,8 @@ function getnameandlink() x = TXQuery.Create(http.Document) if w[module.website] then x.XPathHREFAll('//*[contains(@id,"content")]//*[@class="det"]/a', links, names) + elseif module.website == 'MangaOnlineToday' then + x.XPathHREFAll('//*[contains(@id,"content")]//div[@class="box"]/ul/li/a', links, names) else x.XPathHREFtitleAll('//*[contains(@id,"content")]//a[./img]', links, names); end @@ -191,6 +196,7 @@ function Init() AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', cat) AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com', cat) AddWebsiteModule('Manga99', 'http://www.manga99.com', cat) + AddWebsiteModule('MangaOnlineToday', 'http://www.mangaonline.today', cat) cat = 'H-Sites' AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', cat) From 1ae7c39a9aed4968a1028eeede7b8e93d184961f Mon Sep 17 00:00:00 2001 From: dusty <adustyspectacle@gmail.com> Date: Sun, 4 Mar 2018 19:26:34 +0800 Subject: [PATCH 2489/2794] Adds 5 new scanlation sites No idea if these are the only things I have to add so I'll be happy to revise if otherwise ^^ --- lua/modules/FoOlSlide.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index b8fece380..e7d957325 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -47,7 +47,12 @@ function getdirurl(website) ['Riceballicious'] = dirurlreaderlist, ['Yuri-ism'] = dirurlslide, ['MangajinNoFansub'] = dirurllector, - ['HatigarmScans'] = '/hs/directory/' + ['HatigarmScans'] = '/hs/directory/', + ['BunnysScans'] = '/read/directory/', + ['CanisMajorScans'] = dirurlreader, + ['HoshikuzuuScans'] = dirurl, + ['YaoiIsLife'] = dirurlreader, + ['FujoshiBitches'] = dirurlreader } if dirs[website] ~= nil then return dirs[website] @@ -233,6 +238,11 @@ function Init() AddWebsiteModule('Yuri-ism', 'https://www.yuri-ism.net', cat) AddWebsiteModule('SilentSkyScans', 'http://reader.silentsky-scans.net', cat) AddWebsiteModule('HatigarmScans', 'http://hatigarmscans.eu', cat) + AddWebsiteModule('BunnysScans', 'http://bns.shounen-ai.net', cat) + AddWebsiteModule('CanisMajorScans', 'http://cm-scans.shounen-ai.net', cat) + AddWebsiteModule('HoshikuzuuScans', 'http://hoshiscans.shounen-ai.net', cat) + AddWebsiteModule('YaoiIsLife', 'http://yaoislife.shounen-ai.net', cat) + AddWebsiteModule('FujoshiBitches', 'http://fujoshibitches.shounen-ai.net', cat) -- es-sc cat = 'Spanish-Scanlation' From 974cae32be02badfd76651dcfdbf3c203a8297c9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 6 Mar 2018 08:58:06 +0300 Subject: [PATCH 2490/2794] h2r, http -> https #1097 --- baseunits/modules/Hentai2Read.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Hentai2Read.pas b/baseunits/modules/Hentai2Read.pas index 4ba18d3b8..0314f5cf4 100644 --- a/baseunits/modules/Hentai2Read.pas +++ b/baseunits/modules/Hentai2Read.pas @@ -163,7 +163,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Hentai2Read'; - RootURL := 'http://hentai2read.com'; + RootURL := 'https://hentai2read.com'; Category := 'H-Sites'; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; From ce6760eec908aadc664455132707fc52aa7e6d9e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 6 Mar 2018 15:44:45 +0300 Subject: [PATCH 2491/2794] add Shakai [ru] --- lua/modules/Shakai.lua | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 lua/modules/Shakai.lua diff --git a/lua/modules/Shakai.lua b/lua/modules/Shakai.lua new file mode 100644 index 000000000..a8e7ca13f --- /dev/null +++ b/lua/modules/Shakai.lua @@ -0,0 +1,101 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if Pos('/element-list', mangainfo.url) > 0 then + mangainfo.url = mangainfo.url:gsub('/element%-list$', '') + end + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//*[@class="wrapper__heading"]/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="make__cover"]/img/@src')) + mangainfo.authors=x.xpathstringall('//table[@class="make__table-info"]//tr[contains(td, "Автор")]/td/a') + print(x.xpathstringall('//table[@class="make__table-info"]//tr[contains(td, "Автор")]/td/a')) + mangainfo.genres=x.xpathstringall('//table[@class="make__table-info"]//tr[contains(td, "Жанры")]/td/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="make__table-info"]//tr[contains(td, "Выпуск")]/td', 'продолжается', 'завершен')) + mangainfo.summary=x.xpathstring('//div[@class="make__description"]') + if http.get(mangainfo.url .. '/element-list') then + x.parsehtml(http.document) + local v = x.xpath('//div[@class="post-element__description"]') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(x.xpathstring('div[@class="post-element__action"]/a/@href', v1)) + mangainfo.chapternames.add(x.xpathstring('div[@class="post-element__meta"]', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + local id, chapter = url:match('read/([^/]+)/([^/]+)/') + local data = 'dataRun=api-manga&dataRequest=' .. id + if http.post(module.rooturl .. '/take/api-manga/request/shakai', data) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('json(*).data()[data-first="' .. chapter .. '"].data-second()') + for i = 1, v.count do + local v1 = v.get(i) + task.pagelinks.add(v1.tostring) + end + else + return false + end + return true +end + +local cataloguri = '/take/catalog/request/shakai' +function getquery(page) + local query = 'dataRun=catalog&selectCatalog=manga&searchData=&' .. + 'selectPage=%s&' .. + '&itemMarker=%s&' .. + 'dataModeration=&dataSorting=po-alfavitu,false,false,false,false,false,false&' .. + 'dataType=false,false,false,false,false,false,false,false&dataStatus=false,false,false,false&' .. + 'dataList=&dataGenre=false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false&dataSeason=false,false,false,false,false,false' + return string.format(query, page, os.date("!%Y-%m-%d %X")) +end + +function getnameandlink() + if tonumber(url) < 0 then return no_error end + if http.post(module.RootURL .. cataloguri, getquery(IncStr(url))) then + local s = StreamToString(http.document):gsub('"', '\\"') + local x = TXQuery.Create(s) + local v = x.xpath('json(*).result()') + for i = 1, v.count do + local v1 = v.get(i) + links.add(x.xpathstring('output-link', v1)) + names.add(x.xpathstring('output-name', v1)) + end + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.post(module.RootURL .. cataloguri, getquery('1')) then + local s = StreamToString(http.document):gsub('"', '\\"') + local x = TXQuery.Create(s) + page = tonumber(x.xpathstring('json(*).create')) + if page == nil then page = 1; end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'Shakai' + m.rooturl = 'http://shakai.ru' + m.category = 'Russian' + m.lastupdated='March 6, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end \ No newline at end of file From 0e9b90d7da6e3122faf7e262dfadbb89ec0bc10b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 6 Mar 2018 16:36:05 +0300 Subject: [PATCH 2492/2794] add MangaOnlineBiz [ru] --- lua/modules/MangaOnlineBiz.lua | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 lua/modules/MangaOnlineBiz.lua diff --git a/lua/modules/MangaOnlineBiz.lua b/lua/modules/MangaOnlineBiz.lua new file mode 100644 index 000000000..332c02294 --- /dev/null +++ b/lua/modules/MangaOnlineBiz.lua @@ -0,0 +1,76 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="item"]/div[@class="image"]/img/@src')) + mangainfo.genres=x.xpathstringall('//div[@class="extra"]/a') + mangainfo.summary=x.xpathstring('//div[@id="description"]') + local s = x.xpathstring('//script[contains(., "mangaChapterCollection")]') + local name = GetBetween('View.Manga(', ');', s) + name = name:match('mangaName:%s*[\'"]([^\'"]+)[\'"]') + s = GetBetween('MangaChapter(', ');', s) + x.parsehtml(s) + local v = x.xpath('json(*)()') + for i = 1, v.count do + local v1 = v.get(i) + s = string.format('/%s/%s/%s/1/', name, x.xpathstring('volume', v1), x.xpathstring('number', v1)) + mangainfo.chapterlinks.add(s) + mangainfo.chapternames.add(x.xpathstring('title', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "chapterRouter")]') + s = GetBetween('Chapter(', ');', s) + x.parsehtml(s) + local base = x.xpathstring('json(*).srcBaseUrl') + local v = x.xpath('json(*).pages/*/src') + for i = 1,v.count do + local v1=v.get(i) + task.pagelinks.add(base .. '/' .. v1.tostring) + end + else + return false + end + return true +end + +function getnameandlink() + if tonumber(url) < 0 then return no_error end + if http.get(module.rooturl .. '/genre/all/page/'..IncStr(url)) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//div[@class="genres"]/a[@class="genre"]') + for i=1,v.count do + local v1=v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('div/h2', v1)) + end + local page = tonumber(x.xpathstring('(//a[@class="ui button"])[last()]')) + if page == nil then page = 1; end + updatelist.CurrentDirectoryPageNumber = page + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'MangaOnlineBiz' + m.rooturl = 'https://manga-online.biz' + m.category = 'Russian' + m.lastupdated='March 3, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From e94750d0d8fef40c81f4610cbe75b71c69bacee6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 6 Mar 2018 19:19:58 +0300 Subject: [PATCH 2493/2794] MangaDex, fix cookies fixes #1100 --- lua/modules/MangaDex.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index c82458078..0fb25d75d 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -1,5 +1,6 @@ function getinfo() mangainfo.url=MaybeFillHost(module.rooturl,url) + http.cookies.values['mangadex_h_toggle'] = '1' if http.get(mangainfo.url) then x=TXQuery.Create(http.document) if mangainfo.title=='' then mangainfo.title=x.xpathstring('//meta[@property="og:title"]/replace(@content,"\\s\\(\\w+\\)\\s-\\sMangaDex$","")') end @@ -44,6 +45,7 @@ function getinfo() end function getpagenumber() + http.cookies.values['mangadex_h_toggle'] = '1' if http.get(MaybeFillHost(module.rooturl,url)) then local s=StreamToString(http.document) local lurl=MaybeFillHost(module.rooturl,AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/') @@ -69,6 +71,7 @@ end local dirurl='/titles' function getdirectorypagenumber() + http.cookies.values['mangadex_h_toggle'] = '1' if http.get(module.rooturl..dirurl) then x=TXQuery.Create(http.document) local perpage=tonumber(RegExprGetMatch('/(\\d+)$',x.xpathstring('//ul[@class="pagination"]/li[@class="active"]/following-sibling::li[@class="paging"]/a/@href'),1)) @@ -88,6 +91,7 @@ function getnameandlink() if url~='0' then lurl=lurl..'/'..tostring(module.tag*tonumber(url)) end + http.cookies.values['mangadex_h_toggle'] = '1' if http.GET(module.rooturl..lurl) then TXQuery.Create(http.document).xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) return no_error From 1c53e74b26bf463a3d391e9514f4eb062bbfa0e9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 6 Mar 2018 19:40:34 +0300 Subject: [PATCH 2494/2794] MangaDex, fix get list --- lua/modules/MangaDex.lua | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 0fb25d75d..63a75157e 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -68,32 +68,21 @@ function taskstart() return true end -local dirurl='/titles' - -function getdirectorypagenumber() - http.cookies.values['mangadex_h_toggle'] = '1' - if http.get(module.rooturl..dirurl) then - x=TXQuery.Create(http.document) - local perpage=tonumber(RegExprGetMatch('/(\\d+)$',x.xpathstring('//ul[@class="pagination"]/li[@class="active"]/following-sibling::li[@class="paging"]/a/@href'),1)) - local lastpage=tonumber(RegExprGetMatch('/(\\d+)$',x.xpathstring('//ul[@class="pagination"]/li[@class="paging"][last()]/a/@href'),1)) - if perpage==nil then perpage=100 end - if lastpage==nil then lastpage=perpage end - module.tag=perpage - page=Round(lastpage/perpage)+1 - return true - else - return false - end -end - +local dirurl='/titles/' +local ALPHA_LIST_UP = '~ABCDEFGHIJKLMNOPQRSTUVWXYZ' function getnameandlink() local lurl=dirurl - if url~='0' then - lurl=lurl..'/'..tostring(module.tag*tonumber(url)) - end + lurl = lurl .. ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) + lurl = lurl .. '/' .. IncStr(url) http.cookies.values['mangadex_h_toggle'] = '1' if http.GET(module.rooturl..lurl) then - TXQuery.Create(http.document).xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) + local x = TXQuery.Create(http.document) + x.xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) + local page = x.xpathstring('//ul[@class="pagination"]/li[last()]/a/@href') + page = page:match('/(%d+)/?$') + page = tonumber(page) + if page == nil then page = 1; end + updatelist.CurrentDirectoryPageNumber = page return no_error else return net_problem @@ -109,8 +98,8 @@ function Init() m.ongetinfo='getinfo' m.ontaskstart='taskstart' m.ongetpagenumber='getpagenumber' - m.ongetdirectorypagenumber='getdirectorypagenumber' m.ongetnameandlink='getnameandlink' + m.totaldirectory = ALPHA_LIST_UP:len() m.maxtasklimit=1 m.maxconnectionlimit=2 From 239cf3bf8c53e04dfe78780e3200693270316186 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Mar 2018 06:23:22 +0300 Subject: [PATCH 2495/2794] MangaDex, fix get info --- lua/modules/MangaDex.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 63a75157e..87dc67205 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -12,15 +12,15 @@ function getinfo() local l='//*[@id="chapters"]//tr[@id]' local n='' if module.getoption('luashowalllang') then - n='/concat(.," [",../td[2]/img/@title,"]"' + n='/concat(.," [",../td[3]/img/@title,"]"' else l=l..'[./td/img[@title="English"]]' end if module.getoption('luashowscangroup') then if n=='' then n='/concat(.' end - n=n..'," [",../td[3],"]"' + n=n..'," [",../td[4],"]"' end - l=l..'/td[1]' + l=l..'/td[2]' if n~='' then n=n..')' end n=l..n l=l..'/a/@href' @@ -48,6 +48,7 @@ function getpagenumber() http.cookies.values['mangadex_h_toggle'] = '1' if http.get(MaybeFillHost(module.rooturl,url)) then local s=StreamToString(http.document) + if Pos('var page_array', s) == 0 then return false; end local lurl=MaybeFillHost(module.rooturl,AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/') task.pagelinks.commatext=GetBetween('var page_array = [','];',s):gsub('\'','') task.pagelinks.text=Trim(task.pagelinks.text) From 48f2fa9cd9c1e468d35e2209ef82317e4c3ad649 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Mar 2018 11:46:42 +0300 Subject: [PATCH 2496/2794] add twistedhelscans [en-sc] --- lua/modules/FoOlSlide.lua | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index e7d957325..2eea1e942 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -106,6 +106,25 @@ function getinfo() return result end +function getinfo_ths() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if getWithCookie(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@id="series_right"]/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@class="series_img"]/@src')) + mangainfo.authors = x.xpathstring('//ul[@class="series_left_data"]/li[contains(span, "Author")]/span[@class="value"]') + mangainfo.artists = x.xpathstring('//ul[@class="series_left_data"]/li[contains(span, "Artist")]/span[@class="value"]') + mangainfo.genres=x.xpathstringall('//ul[@class="series_left_data"]/li[contains(span, "Genre")]/span[@class="value"]/text()') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//ul[@class="series_left_data"]/li[contains(span, "Status")]/span[@class="value"]')) + mangainfo.summary = x.xpathstring('//div[@id="series_des"]') + x.xpathhreftitleall('//div[@id="staff"]/div/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + function taskstart() task.pagelinks.clear() task.pagenumber = 0 @@ -173,14 +192,21 @@ function getnameandlink() end if getWithCookie(s) then result = no_error - x = TXQuery.create(http.document) + local x = TXQuery.create(http.document) if module.website == 'AtelierDuNoir' then - v = x.xpath('//div[@class="caption"]') + local v = x.xpath('//div[@class="caption"]') for i = 1, v.count do v1 = v.get(i) links.add(x.xpathstring('div/a/@href', v1)) names.add(x.xpathstring('h4', v1)) end + elseif module.website == 'TwistedHelScans' then + local v = x.xpath('//div[contains(@class, "series_card")]/a') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('span', v1)) + end elseif module.website == 'HatigarmScans' then x.XpathHREFAll('//div[@class="grid"]/div/a', links, names) else @@ -202,6 +228,7 @@ function AddWebsiteModule(name, url, category) m.OnGetImageURL = 'getimageurl' m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' m.OnGetNameAndLink = 'getnameandlink' + if name == 'TwistedHelScans' then m.ongetinfo = 'getinfo_ths'; end return m end @@ -243,6 +270,7 @@ function Init() AddWebsiteModule('HoshikuzuuScans', 'http://hoshiscans.shounen-ai.net', cat) AddWebsiteModule('YaoiIsLife', 'http://yaoislife.shounen-ai.net', cat) AddWebsiteModule('FujoshiBitches', 'http://fujoshibitches.shounen-ai.net', cat) + AddWebsiteModule('TwistedHelScans', 'http://www.twistedhelscans.com', cat) -- es-sc cat = 'Spanish-Scanlation' From 0ac87a3d2f2c476c6123809bb93645259848ee7f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Mar 2018 11:50:08 +0300 Subject: [PATCH 2497/2794] add tap-trans [en-sc] --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 2eea1e942..5efb6da0f 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -52,7 +52,8 @@ function getdirurl(website) ['CanisMajorScans'] = dirurlreader, ['HoshikuzuuScans'] = dirurl, ['YaoiIsLife'] = dirurlreader, - ['FujoshiBitches'] = dirurlreader + ['FujoshiBitches'] = dirurlreader, + ['TapTrans'] = dirurlfsdir } if dirs[website] ~= nil then return dirs[website] @@ -271,6 +272,7 @@ function Init() AddWebsiteModule('YaoiIsLife', 'http://yaoislife.shounen-ai.net', cat) AddWebsiteModule('FujoshiBitches', 'http://fujoshibitches.shounen-ai.net', cat) AddWebsiteModule('TwistedHelScans', 'http://www.twistedhelscans.com', cat) + AddWebsiteModule('TapTrans', 'https://taptaptaptaptap.net', cat) -- es-sc cat = 'Spanish-Scanlation' From d5436f1b5216ecadc47492365f5dce0cd848ebc6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Mar 2018 15:52:58 +0300 Subject: [PATCH 2498/2794] modules, fix --- lua/modules/DesuMe.lua | 2 +- lua/modules/MangaLib.lua | 2 +- lua/modules/Shakai.lua | 3 +-- lua/modules/SoManga.lua | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lua/modules/DesuMe.lua b/lua/modules/DesuMe.lua index e5a7bea27..deed43f61 100644 --- a/lua/modules/DesuMe.lua +++ b/lua/modules/DesuMe.lua @@ -5,7 +5,7 @@ function getinfo() mangainfo.title=x.xpathstring('//h1/span[@class="name"]') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@itemprop="image"]/@src')) mangainfo.genres=x.xpathstringall('//ul[@class="tagList"]/li/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//span[contains(@class, "status_tag")]', 'выходит', 'издано')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//span[contains(@class, "status_tag")]'), 'выходит', 'издано') mangainfo.summary=x.xpathstring('//div[@itemprop="description"]') x.xpathhrefall('//ul[@class="chlist"]/li/h4/a', mangainfo.chapterlinks, mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) diff --git a/lua/modules/MangaLib.lua b/lua/modules/MangaLib.lua index 8fe93d6df..a34467f28 100644 --- a/lua/modules/MangaLib.lua +++ b/lua/modules/MangaLib.lua @@ -7,7 +7,7 @@ function getinfo() mangainfo.authors=x.xpathstringall('//div[@class="manga-info"]//p[contains(*, "Автор")]/a') mangainfo.artists=x.xpathstringall('//div[@class="manga-info"]//p[contains(*, "Художник")]/a') mangainfo.genres=x.xpathstringall('//div[@class="manga-info"]//p[contains(*, "Жанры")]/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="manga-info"]//p[contains(*, "Перевод")]/span', 'продолжается', 'завершен')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="manga-info"]//p[contains(*, "Перевод")]/span'), 'продолжается', 'завершен') mangainfo.summary=x.xpathstringall('//div[contains(@class, "manga__desc")]/blockquote/text()', '') x.xpathhrefall('//div[@class="chapters-list"]/div/div[@class="chapter-item__name"]/a', mangainfo.chapterlinks, mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) diff --git a/lua/modules/Shakai.lua b/lua/modules/Shakai.lua index a8e7ca13f..aa0057598 100644 --- a/lua/modules/Shakai.lua +++ b/lua/modules/Shakai.lua @@ -8,9 +8,8 @@ mangainfo.title=x.xpathstring('//*[@class="wrapper__heading"]/h1') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="make__cover"]/img/@src')) mangainfo.authors=x.xpathstringall('//table[@class="make__table-info"]//tr[contains(td, "Автор")]/td/a') - print(x.xpathstringall('//table[@class="make__table-info"]//tr[contains(td, "Автор")]/td/a')) mangainfo.genres=x.xpathstringall('//table[@class="make__table-info"]//tr[contains(td, "Жанры")]/td/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="make__table-info"]//tr[contains(td, "Выпуск")]/td', 'продолжается', 'завершен')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="make__table-info"]//tr[contains(td, "Выпуск")]/td'), 'продолжается', 'завершен') mangainfo.summary=x.xpathstring('//div[@class="make__description"]') if http.get(mangainfo.url .. '/element-list') then x.parsehtml(http.document) diff --git a/lua/modules/SoManga.lua b/lua/modules/SoManga.lua index 282a9b5a3..30ec826e5 100644 --- a/lua/modules/SoManga.lua +++ b/lua/modules/SoManga.lua @@ -7,7 +7,7 @@ mangainfo.authors=x.xpathstringall('//div[contains(@class, "manga")]//h5[contains(*, "Autor")]/text()', '') mangainfo.artists=x.xpathstringall('//div[contains(@class, "manga")]//h5[contains(*, "Artista")]/text()', '') mangainfo.genres=x.xpathstringall('//div[contains(@class, "manga")]//h5[contains(*, "Genero")]/span') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(@class, "manga")]//h5[contains(*, "Status")]/text()', 'Ativo', 'Completo')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(@class, "manga")]//h5[contains(*, "Status")]/text()'), 'Ativo', 'Completo') mangainfo.summary=x.xpathstring('//div[contains(@class, "manga")]//div[contains(@style, "justify")]') local v=x.xpath('//ul[@class="capitulos"]/li/a') for i=1,v.count do From 6b83950ee1a4e876112ab10c17ab1ec3f5cc8fa3 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Mar 2018 16:22:33 +0300 Subject: [PATCH 2499/2794] add comicvn [vi] fixes #702 --- lua/modules/ComicVn.lua | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 lua/modules/ComicVn.lua diff --git a/lua/modules/ComicVn.lua b/lua/modules/ComicVn.lua new file mode 100644 index 000000000..9c51cb4ae --- /dev/null +++ b/lua/modules/ComicVn.lua @@ -0,0 +1,61 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="manga-info"]//h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="manga-info"]/div[contains(@class, "manga-detail")]//img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="manga-info"]/div[contains(@class, "manga-detail")]//ul/li[contains(span, "Tác giả")]/span[2]') + mangainfo.artists=x.xpathstring('//div[@class="manga-info"]/div[contains(@class, "manga-detail")]//ul/li[contains(span, "Họa sĩ")]/span[2]') + mangainfo.genres=x.xpathstringall('//div[@class="manga-info"]/div[contains(@class, "manga-detail")]//ul/li[contains(span, "Thể loại")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="manga-info"]/div[contains(@class, "manga-detail")]//ul/li[contains(span, "Trạng thái")]'), 'Đang thực hiện', 'Đã hoàn thành') + mangainfo.summary=x.xpathstring('//div[contains(@class, "manga-summary")]') + x.xpathhrefall('//div[contains(@class,"manga-chapter")]//ul/li/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[contains(@class, "manga-chapter-image")]/textarea/img/@src', task.pagelinks) + else + return false + end + return true +end + +local dirurl = '/noi-bat/' +local perpage = 30 + +function getnameandlink() + if tonumber(url) < 0 then return no_error end + if http.get(module.rooturl .. dirurl .. tostring(tonumber(url) * perpage)) then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//div[contains(@class, "manga-list")]//div[contains(@class,"tit")]/a', links, names) + local s = x.xpathstring('(//ul[@class="pagination"])[1]/li[last()-1]/a/@href') + s = tonumber(s:match('(%d+)/?$')) + if s ~= nil then + s = s / perpage + updatelist.CurrentDirectoryPageNumber = s + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'ComicVn' + m.rooturl = 'http://comicvn.net' + m.category = 'Vietnamese' + m.lastupdated='March 7, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end \ No newline at end of file From dbda35a868b8a85d812808753a3ee992e76d19c9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 7 Mar 2018 19:51:41 +0300 Subject: [PATCH 2500/2794] MangaDex, add genres --- lua/modules/MangaDex.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 87dc67205..229f86f74 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -7,6 +7,7 @@ function getinfo() mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//img[@title="Manga image"]/@src')) mangainfo.authors=x.xpathstring('//tr[./th="Author:"]/string-join(./td,", ")') mangainfo.artists=x.xpathstring('//tr[./th="Artist:"]/string-join(./td,", ")') + mangainfo.genres = x.xpathstringall('//tr[./th="Genres:"]/td/span/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[./th="Status:"]')) mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') local l='//*[@id="chapters"]//tr[@id]' From b3fe07bcbdf29aa736c07c1a107d4504b9d77f1b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 9 Mar 2018 06:52:43 +0300 Subject: [PATCH 2501/2794] dbupdater, create data folder if not exists (#1092) --- baseunits/DBUpdater.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 8517c0bbd..3176f2add 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -64,7 +64,7 @@ TDBUpdaterThread = class(TBaseThread) implementation -uses FMDVars; +uses FMDVars, LazFileUtils; function GetDBURL(const AName: String): String; begin @@ -268,6 +268,7 @@ procedure TDBUpdaterThread.Execute; begin cont := True; // save to data folder + ForceDirectoriesUTF8(DATA_FOLDER); currentfilename := DATA_FOLDER + FCurrentName + DBDATA_SERVER_EXT; if FileExists(currentfilename) then DeleteFile(currentfilename); From 3141ecf004a42d143d72a1844bef9f0f4d33bf31 Mon Sep 17 00:00:00 2001 From: Tmp341 <tmp341@gmail.com> Date: Sat, 10 Mar 2018 11:07:31 +0300 Subject: [PATCH 2502/2794] Update LHTranslation.lua --- lua/modules/LHTranslation.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index 4ad41b7db..4c38fc5c5 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -46,7 +46,7 @@ function Init() m=NewModule() m.category = 'English-Scanlation' m.Website = 'LHTranslation' - m.RootURL = 'http://lhtranslation.com' + m.RootURL = 'http://lhtranslation.net' m.OnGetNameAndLink = 'GetNameAndLink' m.OnGetInfo = 'GetInfo' m.OnGetPageNumber = 'GetPageNumber' From e6df5ba83373cab2377929bcf8e1fe998d59053f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 11 Mar 2018 07:50:48 +0300 Subject: [PATCH 2503/2794] imgur, fix download fixes #1114 --- lua/modules/Imgur.lua | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/lua/modules/Imgur.lua b/lua/modules/Imgur.lua index bc139dcb8..b6dd684d0 100644 --- a/lua/modules/Imgur.lua +++ b/lua/modules/Imgur.lua @@ -17,14 +17,30 @@ function taskstart() end function getpagenumber() - if http.get(MaybeFillHost(module.rooturl,url)) then - x=TXQuery.Create(http.Document) - x.xpathStringAll('//div[contains(@class,"post-image")]/a/img/concat("https:",@src)', task.pagelinks) - return true + local hash = url:match('/a/(.+)/?') + if hash ~= nil then + -- album + if http.get(module.rooturl .. '/ajaxalbums/getimages/' .. hash .. '/hit.json') then + local x = TXQuery.Create(http.Document) + local v = x.xpath('json(*).data.images()') + for i = 1, v.count do + local v1 = v.get(i) + task.pagelinks.add('https://i.imgur.com/' .. x.xpathstring('hash', v1) .. x.xpathstring('ext', v1)) + end + return true + else + return false + end else - return false + -- single image + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + x.xpathStringAll('//div[contains(@class,"post-image")]/a/img/concat("https:",@src)', task.pagelinks) + return true + else + return false + end end - return true end function Init() From 854eaa51ca2c9ae8775079e41f2f83194ed292b5 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 12 Mar 2018 11:30:18 +0300 Subject: [PATCH 2504/2794] Mangakakalot, move to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/Mangakakalot.pas | 138 ----------------------------- lua/modules/Mangakakalot.lua | 106 ++++++++++++++++++++++ 3 files changed, 106 insertions(+), 139 deletions(-) delete mode 100644 baseunits/modules/Mangakakalot.pas create mode 100644 lua/modules/Mangakakalot.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e853993f2..d75dd007c 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -57,7 +57,6 @@ uses Mangaf, MangaRock, PsychoPlay, - Mangakakalot, Lhscans, MangaWindow, // Raw Official diff --git a/baseunits/modules/Mangakakalot.pas b/baseunits/modules/Mangakakalot.pas deleted file mode 100644 index 0dde11e27..000000000 --- a/baseunits/modules/Mangakakalot.pas +++ /dev/null @@ -1,138 +0,0 @@ -unit Mangakakalot; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/manga_list?type=newest&category=all&state=all&page='; - -function GetRedirectUrl(Document: TMemoryStream): String; -var s: String; -begin - Result := ''; - s := XPathString('//script[contains(., "window.location.assign")]', Document); - if s <> '' then - Result := GetBetween('("', '")', s); -end; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then begin - Result := NO_ERROR; - s := XPathString('//div[@class="group-page"]/a[contains(., "Last")]/@href', MangaInfo.FHTTP.Document); - Page := StrToInt(RegExprGetMatch('page\=(\d+)', s, 1)); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then begin - Result := NO_ERROR; - XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', - MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - s := GetRedirectUrl(Document); - if s <> '' then begin - url := s; - if not GET(url) then Exit; - end; - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="manga-info-pic"]/img/@src')); - if title = '' then title := XPathString('//ul[@class="manga-info-text"]/li/h1'); - if (Pos('email', title) > 0) and (Pos('protected', title) > 0) then - title := Trim(XPathString('//title/substring-after(substring-before(., "Manga Online"), "Read")')); - authors := XPathStringAll('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a'); - genres := XPathStringAll('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a'); - status := MangaInfoStatusIfPos(XPathString('//ul[@class="manga-info-text"]/li[contains(., "Status")]')); - summary := XPathStringAll('//div[@id="noidungm"]/text()', ''); - XPathHREFAll('//div[@class="chapter-list"]/div[@class="row"]/span/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var s, url, path, host: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - s := GetRedirectUrl(Document); - if s <> '' then begin - SplitURL(s, @host, nil); - SplitURL(url, nil, @path); - if not GET(host + path) then Exit; - end; - Result := True; - XPathStringAll('//div[@id="vungdoc"]/img/@src', Document, PageLinks); - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; - begin - Result := AddModule; - with Result do - begin - Website := AWebsite; - RootURL := ARootURL; - Category := 'English'; - SortedList := True; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - end; - end; - -begin - AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com'); - AddWebsiteModule('Manganelo', 'http://manganelo.com'); -end; - -initialization - RegisterModule; - -end. - diff --git a/lua/modules/Mangakakalot.lua b/lua/modules/Mangakakalot.lua new file mode 100644 index 000000000..1c93a1ebe --- /dev/null +++ b/lua/modules/Mangakakalot.lua @@ -0,0 +1,106 @@ +local dirurl = '/manga_list?type=newest&category=all&state=all&page=' + +function GetRedirectUrl(document) + local x = TXQuery.Create(document) + local s = x.xpathstring('//script[contains(., "window.location.assign")]') + if (s ~= '') and (s ~= nil) then + return GetBetween('("', '")', s) + end + return '' +end + +function getinfo() + local u = MaybeFillHost(module.rooturl, url) + if http.get(u) then + local s = GetRedirectUrl(http.Document) + if (s ~= '') and (s ~= nil) then + u = s + if not http.GET(u) then return false; end + end + mangainfo.url=u + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//ul[@class="manga-info-text"]/li/h1') + if (Pos('email', mangainfo.title) > 0) and (Pos('protected', mangainfo.title) > 0) then + mangainfo.title = Trim(x.xpathstring('//title/substring-after(substring-before(., "Manga Online"), "Read")')) + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="manga-info-pic"]/img/@src')) + mangainfo.authors=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a') + mangainfo.genres=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info-text"]/li[contains(., "Status")]')) + mangainfo.summary=x.xpathstringall('//div[@id="noidungm"]/text()', '') + x.xpathhrefall('//div[@class="chapter-list"]/div[@class="row"]/span/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + function spliturl(u) + local pos = 0 + for i = 1, 3 do + local p = string.find(u, '/', pos+1, true) + if p == nil then break; end + pos = p + end + return string.sub(u, 1, pos-1), string.sub(u, pos) + end + task.pagelinks.clear() + task.pagenumber=0 + local u = MaybeFillHost(module.rooturl, url) + if http.get(u) then + local s = GetRedirectUrl(http.document) + if (s ~= '') and (s ~= nil) then + local host, _ = spliturl(s) + local _, path = spliturl(u) + if not http.get(host .. path) then return false; end + end + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@id="vungdoc"]/img/@src', task.pagelinks) + return true + else + return false + end +end + +function getnameandlink() + if http.get(module.rooturl .. dirurl .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. dirurl .. '1') then + x = TXQuery.Create(http.Document) + local s = x.xpathstring('//div[@class="group-page"]/a[contains(., "Last")]/@href') + page = tonumber(s:match('page=(%d+)')) + if page == nil then page = 1; end + return true + else + return false + end +end + +function AddWebsiteModule(name, url) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = 'English' + m.lastupdated = 'March 12, 2018' + m.sortedlist = true + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' + return m +end + +function Init() + AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com') + AddWebsiteModule('Manganelo', 'http://manganelo.com') +end From 370e29d34068e03d15ecb8625c90aa8ab780041e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 12 Mar 2018 11:56:43 +0300 Subject: [PATCH 2505/2794] add mangasupa [en] --- lua/modules/Mangakakalot.lua | 41 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/lua/modules/Mangakakalot.lua b/lua/modules/Mangakakalot.lua index 1c93a1ebe..410dfcb1e 100644 --- a/lua/modules/Mangakakalot.lua +++ b/lua/modules/Mangakakalot.lua @@ -19,14 +19,22 @@ function getinfo() end mangainfo.url=u local x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstring('//ul[@class="manga-info-text"]/li/h1') + if Pos('mangasupa', u:lower()) > 0 then + mangainfo.title=x.xpathstring('//h1[@class="entry-title"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//span[@class="info_image"]/img/@src')) + mangainfo.authors=x.xpathstringall('//ul[@class="truyen_info_right"]/li[contains(., "Author")]/a') + mangainfo.genres=x.xpathstringall('//ul[@class="truyen_info_right"]/li[contains(., "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="truyen_info_right"]/li[contains(., "Status")]')) + else + mangainfo.title=x.xpathstring('//ul[@class="manga-info-text"]/li/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="manga-info-pic"]/img/@src')) + mangainfo.authors=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a') + mangainfo.genres=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info-text"]/li[contains(., "Status")]')) + end if (Pos('email', mangainfo.title) > 0) and (Pos('protected', mangainfo.title) > 0) then mangainfo.title = Trim(x.xpathstring('//title/substring-after(substring-before(., "Manga Online"), "Read")')) end - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="manga-info-pic"]/img/@src')) - mangainfo.authors=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a') - mangainfo.genres=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info-text"]/li[contains(., "Status")]')) mangainfo.summary=x.xpathstringall('//div[@id="noidungm"]/text()', '') x.xpathhrefall('//div[@class="chapter-list"]/div[@class="row"]/span/a', mangainfo.chapterlinks, mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) @@ -54,10 +62,15 @@ function getpagenumber() if (s ~= '') and (s ~= nil) then local host, _ = spliturl(s) local _, path = spliturl(u) - if not http.get(host .. path) then return false; end + u = host .. path + if not http.get(u) then return false; end end local x=TXQuery.Create(http.Document) - x.xpathstringall('//div[@id="vungdoc"]/img/@src', task.pagelinks) + if Pos('mangasupa', u:lower()) > 0 then + x.xpathstringall('//div[@class="vung_doc"]/img/@src', task.pagelinks) + else + x.xpathstringall('//div[@id="vungdoc"]/img/@src', task.pagelinks) + end return true else return false @@ -67,7 +80,11 @@ end function getnameandlink() if http.get(module.rooturl .. dirurl .. IncStr(url)) then local x = TXQuery.Create(http.Document) - x.XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', links, names) + if module.website == 'Mangasupa' then + x.XPathHREFAll('//div[contains(@class,"danh_sach")]/div[contains(@class,"list_category")]/h3/a', links, names) + else + x.XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', links, names) + end return no_error else return net_problem @@ -77,7 +94,12 @@ end function getdirectorypagenumber() if http.GET(module.RootURL .. dirurl .. '1') then x = TXQuery.Create(http.Document) - local s = x.xpathstring('//div[@class="group-page"]/a[contains(., "Last")]/@href') + local s = nil + if module.website == 'Mangasupa' then + s = x.xpathstring('//div[@class="phan-trang"]/a[contains(., "Last")]/@href') + else + s = x.xpathstring('//div[@class="group-page"]/a[contains(., "Last")]/@href') + end page = tonumber(s:match('page=(%d+)')) if page == nil then page = 1; end return true @@ -103,4 +125,5 @@ end function Init() AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com') AddWebsiteModule('Manganelo', 'http://manganelo.com') + AddWebsiteModule('Mangasupa', 'http://mangasupa.com') end From f694adca3590809ce7c3c40541ec9298632a52c1 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Mar 2018 09:30:01 +0300 Subject: [PATCH 2506/2794] add mangafoxcom [en] fixes #1116 --- lua/modules/Mangakakalot.lua | 39 ++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/lua/modules/Mangakakalot.lua b/lua/modules/Mangakakalot.lua index 410dfcb1e..4c0695a76 100644 --- a/lua/modules/Mangakakalot.lua +++ b/lua/modules/Mangakakalot.lua @@ -1,5 +1,3 @@ -local dirurl = '/manga_list?type=newest&category=all&state=all&page=' - function GetRedirectUrl(document) local x = TXQuery.Create(document) local s = x.xpathstring('//script[contains(., "window.location.assign")]') @@ -19,7 +17,7 @@ function getinfo() end mangainfo.url=u local x=TXQuery.Create(http.document) - if Pos('mangasupa', u:lower()) > 0 then + if (Pos('mangasupa', u:lower()) > 0) or module.website == 'MangaFoxCom' then mangainfo.title=x.xpathstring('//h1[@class="entry-title"]') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//span[@class="info_image"]/img/@src')) mangainfo.authors=x.xpathstringall('//ul[@class="truyen_info_right"]/li[contains(., "Author")]/a') @@ -66,10 +64,12 @@ function getpagenumber() if not http.get(u) then return false; end end local x=TXQuery.Create(http.Document) - if Pos('mangasupa', u:lower()) > 0 then + x.xpathstringall('//div[@id="vungdoc"]/img/@src', task.pagelinks) + if task.pagelinks.count == 0 then x.xpathstringall('//div[@class="vung_doc"]/img/@src', task.pagelinks) - else - x.xpathstringall('//div[@id="vungdoc"]/img/@src', task.pagelinks) + end + if task.pagelinks.count == 0 then + x.xpathstringall('//div[@id="list_chapter"]//img/@src', task.pagelinks) end return true else @@ -77,13 +77,25 @@ function getpagenumber() end end +local dirurl = '/manga_list?type=newest&category=all&state=all&page=' function getnameandlink() - if http.get(module.rooturl .. dirurl .. IncStr(url)) then + local dir = dirurl + if module.website == 'MangaFoxCom' then + dir = '/manga-list?view=list&sort=date_added&page=' + end + if http.get(module.rooturl .. dir .. IncStr(url)) then local x = TXQuery.Create(http.Document) - if module.website == 'Mangasupa' then - x.XPathHREFAll('//div[contains(@class,"danh_sach")]/div[contains(@class,"list_category")]/h3/a', links, names) + if module.website == 'MangaFoxCom' then + local q = '//div[contains(@class,"wrap_update")]/div[@class="update_item"]/h3/a' + if x.xpathcount(q) > 0 then + x.XPathHREFAll(q, links, names) + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + end else x.XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', links, names) + if links.count == 0 then + x.XPathHREFAll('//div[contains(@class,"danh_sach")]/div[contains(@class,"list_category")]/h3/a', links, names) + end end return no_error else @@ -92,13 +104,13 @@ function getnameandlink() end function getdirectorypagenumber() + page = 1 + if module.website == 'MangaFoxCom' then return true; end if http.GET(module.RootURL .. dirurl .. '1') then x = TXQuery.Create(http.Document) - local s = nil - if module.website == 'Mangasupa' then + local s = x.xpathstring('//div[@class="group-page"]/a[contains(., "Last")]/@href') + if s == '' then s = x.xpathstring('//div[@class="phan-trang"]/a[contains(., "Last")]/@href') - else - s = x.xpathstring('//div[@class="group-page"]/a[contains(., "Last")]/@href') end page = tonumber(s:match('page=(%d+)')) if page == nil then page = 1; end @@ -126,4 +138,5 @@ function Init() AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com') AddWebsiteModule('Manganelo', 'http://manganelo.com') AddWebsiteModule('Mangasupa', 'http://mangasupa.com') + AddWebsiteModule('MangaFoxCom', 'https://manga-fox.com') end From 15a98e8ea675f41430032c653bd8756ec5fe0825 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Mar 2018 10:49:04 +0300 Subject: [PATCH 2507/2794] LHTranslation, fix get info, improve download --- lua/modules/LHTranslation.lua | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index 4c38fc5c5..a377c8e30 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -1,13 +1,22 @@ function GetInfo() mangainfo.url = MaybeFillHost(module.RootURL, url) if http.GET(mangainfo.url) then - x=TXQuery.Create(http.document) + local x=TXQuery.Create(http.document) if mangainfo.title == '' then mangainfo.title = x.XPathString('//h1[@class="postsby"]/substring-after(.,":")') end mangainfo.title = Trim(mangainfo.title) - mangainfo.coverLink = x.XPathString('(//div[@class="featured-thumbnail"])[1]/img/@src') - x.xpathhreftitleall('//h2[@class="title"]/a',mangainfo.chapterlinks,mangainfo.chapternames) + mangainfo.coverLink = x.XPathString('(//div[@class="featured-thumbnail"])[1]/img/@src') + while true do + x.xpathhreftitleall('//h2[@class="title"]/a',mangainfo.chapterlinks,mangainfo.chapternames) + local nextpage = x.xpathstring('//nav/div[@class="nav-links"]/*[contains(@class, "current")]/following-sibling::a[1]/@href') + if nextpage == '' then break; end + if http.get(nextpage) then + x.parsehtml(http.document) + else + break + end + end InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) return no_error else @@ -15,13 +24,19 @@ function GetInfo() end end +local readrooturl = 'http://read.lhtranslation.com' function GetPageNumber() - if http.GET(MaybeFillHost(module.rooturl, url)) then - x=TXQuery.Create(http.document) + if http.get(MaybeFillHost(readrooturl, '/read-' .. url:gsub('/', '') .. '.html')) then + local x=TXQuery.Create(http.document) + x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) + if task.pagelinks.count > 0 then return true; end + end + if http.get(MaybeFillHost(module.rooturl, url)) then + local x = TXQuery.Create(http.document) if http.get(x.xpathstring('//div[@class="commentmetadata"][1]/p/a/@href')) then x.parsehtml(http.document) x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) - return true + if task.pagelinks.count > 0 then return true; end end end return false @@ -29,10 +44,10 @@ end function GetNameAndLink() if http.GET(module.rooturl) then - x=TXQuery.Create(http.document) - v=x.xpath('//select[@id="cat"]/option[@value!="-1"]') + local x=TXQuery.Create(http.document) + local v=x.xpath('//select[@id="cat"]/option[@value!="-1"]') for i=1,v.count do - v1=v.get(i) + local v1=v.get(i) links.add(module.rooturl..'/?cat='..v1.getattribute('value')) names.add(v1.tostring) end @@ -43,7 +58,7 @@ function GetNameAndLink() end function Init() - m=NewModule() + local m=NewModule() m.category = 'English-Scanlation' m.Website = 'LHTranslation' m.RootURL = 'http://lhtranslation.net' From 5dff3cce563b209e8709839f200abd089fb9ff4f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Mar 2018 11:14:42 +0300 Subject: [PATCH 2508/2794] add ZeroScans [en-sc] --- lua/modules/rawdevart.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 6f69e22b5..86b47779a 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -61,6 +61,10 @@ function AddWebsiteModule(name, url, category) end function Init() - AddWebsiteModule('Rawdevart', 'https://rawdevart.com', 'Raw') - AddWebsiteModule('TrashScanlations', 'http://trashscanlations.com', 'English-Scanlation') + local cat = 'Raw' + AddWebsiteModule('Rawdevart', 'https://rawdevart.com', cat) + + cat = 'English-Scanlation' + AddWebsiteModule('TrashScanlations', 'http://trashscanlations.com', cat) + AddWebsiteModule('ZeroScans', 'https://zeroscans.com', cat) end From 4ec26098a06c6fe1f2cf2e97b5473605892d1e76 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 13 Mar 2018 11:23:18 +0300 Subject: [PATCH 2509/2794] add mangakid [id] fixes #1110 --- lua/modules/MangaShiro.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index ab51600cb..ef85452f5 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -30,7 +30,9 @@ end function getnameandlink() local dirurl = '/manga-list/' if module.website == 'MangaShiro' then dirurl = '/daftar-manga/' - elseif module.website == 'KomikStation' then dirurl = '/daftar-komik/' end + elseif module.website == 'KomikStation' then dirurl = '/daftar-komik/' + elseif module.website == 'MangaKid' then dirurl = '/manga-lists/' + end if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) @@ -60,5 +62,6 @@ function Init() AddWebsiteModule('Subapics', 'http://subapics.com') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') AddWebsiteModule('Mangavy', 'https://mangavy.com') - AddWebsiteModule('KomikStation', 'http://www.komikstation.com/') + AddWebsiteModule('KomikStation', 'http://www.komikstation.com') + AddWebsiteModule('MangaKid', 'http://mangakid.net') end From 6aebfe41a7dbd4b8607528a4768e31462d075667 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Mar 2018 08:55:50 +0300 Subject: [PATCH 2510/2794] HeavenManga, change domain fixes #1121 --- lua/modules/HeavenManga.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index a402debcc..30812ad80 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -68,7 +68,7 @@ end function Init() local m = NewModule() m.website = 'HeavenManga' - m.rooturl = 'http://heavenmanga.club' + m.rooturl = 'http://heavenmanga.biz' m.category = 'English' m.lastupdated='February 26, 2018' m.ongetinfo='getinfo' From 92a76ae0ae05f660c2ebe35bc0dc824a7c1b9934 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 29 Mar 2018 08:48:00 +0300 Subject: [PATCH 2511/2794] favoritesmanager, skip disabled items fixes #1143 --- baseunits/uFavoritesManager.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index d0cd128ac..d6572f702 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -590,7 +590,7 @@ procedure TFavoriteManager.CheckForNewChapter(FavoriteIndex: Integer); if FavoriteIndex > -1 then begin with Items[FavoriteIndex] do - if Status = STATUS_IDLE then + if FEnabled and (Status = STATUS_IDLE) then begin Status := STATUS_CHECK; if Assigned(TaskThread) then From 4fce7ac98671f726ec6ea83d4b5edaf4b0939459 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 29 Mar 2018 09:29:00 +0300 Subject: [PATCH 2512/2794] add WhiteCloudPavilion [en-sc] fixes #1128 --- lua/modules/myReaderMangaCMS.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index f0d3f7810..69a8cd1e9 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -1,5 +1,10 @@ function GetNameAndLink() - if http.GET(module.RootURL .. '/changeMangaList?type=text') then + local u = module.RootURL + if module.Website == 'WhiteCloudPavilion' then + u = u .. '/manga/free' + end + u = u .. '/changeMangaList?type=text' + if http.GET(u) then x = TXQuery.Create(http.Document) x.XPathHREFAll('//li/a', links, names) return no_error @@ -87,6 +92,7 @@ function Init() c='English-Scanlation' AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); AddWebsiteModule('ChibiManga','http://www.cmreader.info', c); + AddWebsiteModule('WhiteCloudPavilion','https://whitecloudpavilion.com', c); c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); From aca0eeb322faa2a373a092bd277ca6989bb24dfc Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 29 Mar 2018 09:42:10 +0300 Subject: [PATCH 2513/2794] add KomikCast [id] #874 #1139 --- lua/modules/MangaShiro.lua | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index ef85452f5..86712721c 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -1,13 +1,22 @@ function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then - x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) - mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') - mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) - mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') + x=TXQuery.Create(http.document) + if module.website == 'KomikCast' then + mangainfo.title=x.xpathstring('//div[@class="mangainfo"]/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="topinfo"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Author")]/td') + mangainfo.genres=x.xpathstringall('//div[@class="topinfo"]//tr[contains(th, "Genres")]/td/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Status")]/td')) + mangainfo.summary=x.xpathstringall('//*[@class="sin"]/p/text()', '') + else + mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') + mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) + mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') + end x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error @@ -31,6 +40,7 @@ function getnameandlink() local dirurl = '/manga-list/' if module.website == 'MangaShiro' then dirurl = '/daftar-manga/' elseif module.website == 'KomikStation' then dirurl = '/daftar-komik/' + elseif module.website == 'KomikCast' then dirurl = '/daftar-komik/?list' elseif module.website == 'MangaKid' then dirurl = '/manga-lists/' end if http.get(module.rooturl..dirurl) then @@ -64,4 +74,5 @@ function Init() AddWebsiteModule('Mangavy', 'https://mangavy.com') AddWebsiteModule('KomikStation', 'http://www.komikstation.com') AddWebsiteModule('MangaKid', 'http://mangakid.net') + AddWebsiteModule('KomikCast', 'https://komikcast.com') end From ed511c92935100ff909aab40d2d2f51752a88137 Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Thu, 29 Mar 2018 02:33:11 -0500 Subject: [PATCH 2514/2794] add scan CoYuHi --- lua/modules/myReaderMangaCMS.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 69a8cd1e9..129ab38af 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -97,4 +97,5 @@ function Init() c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); + AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com/', c); end From f3dfd57c89ac9cd633d0661b7e09f7eb1e05aed6 Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Thu, 29 Mar 2018 02:35:19 -0500 Subject: [PATCH 2515/2794] Add scan LoliVault --- lua/modules/FoOlSlide.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 5efb6da0f..bd6b167e0 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -53,7 +53,8 @@ function getdirurl(website) ['HoshikuzuuScans'] = dirurl, ['YaoiIsLife'] = dirurlreader, ['FujoshiBitches'] = dirurlreader, - ['TapTrans'] = dirurlfsdir + ['TapTrans'] = dirurlfsdir, + ['LoliVault'] = dirurlonline } if dirs[website] ~= nil then return dirs[website] @@ -297,4 +298,5 @@ function Init() AddWebsiteModule('Nightow', 'http://nightow.net', cat) AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) AddWebsiteModule('MangajinNoFansub', 'https://www.mangajinnofansub.com', cat) + AddWebsiteModule('LoliVault', 'https://lolivault.net', cat) end From 8aef9ce6595c5ad79c169c0bd2cbf8ea9cd1dee8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 29 Mar 2018 14:12:30 +0300 Subject: [PATCH 2516/2794] LeitorNet, add list update fixes #607 --- lua/modules/LeitorNet.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lua/modules/LeitorNet.lua b/lua/modules/LeitorNet.lua index 365162e60..5082743c2 100644 --- a/lua/modules/LeitorNet.lua +++ b/lua/modules/LeitorNet.lua @@ -66,6 +66,21 @@ function getpagenumber() return true end +function getnameandlink() + if http.get(module.rooturl..'/lista-de-mangas/ordenar-por-nome/todos?page=' .. IncStr(url)) then + local x=TXQuery.Create(http.Document) + local p=x.xpathstring('//ul[contains(@class,"content-pagination")]/li[last()-1]/a') + p = tonumber(p) + if p ~= nil then + updatelist.CurrentDirectoryPageNumber = p + end + x.XPathHREFtitleAll('//ul[@class="seriesList"]/li/a', links, names) + return no_error + else + return net_problem + end +end + function Init() m=NewModule() m.category='Portugues' @@ -74,6 +89,5 @@ function Init() m.lastupdated='February 17, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' - --m.ongetdirectorypagenumber='getdirectorypagenumber' - --m.ongetnameandlink='getnameandlink' + m.ongetnameandlink='getnameandlink' end \ No newline at end of file From da2d2ad3ce0d7dfbeb5afe1d084a32d5ef843eab Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 29 Mar 2018 15:50:51 +0300 Subject: [PATCH 2517/2794] mangadex, mark delayed chapters #1124 --- lua/modules/MangaDex.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 229f86f74..b513f513f 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -11,18 +11,17 @@ function getinfo() mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[./th="Status:"]')) mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') local l='//*[@id="chapters"]//tr[@id]' - local n='' + local n='/concat(., (if (starts-with(../td/time, "in ")) then " [DELAYED]" else "")' if module.getoption('luashowalllang') then - n='/concat(.," [",../td[3]/img/@title,"]"' + n=n..'," [",../td[3]/img/@title,"]"' else l=l..'[./td/img[@title="English"]]' end if module.getoption('luashowscangroup') then - if n=='' then n='/concat(.' end n=n..'," [",../td[4],"]"' end l=l..'/td[2]' - if n~='' then n=n..')' end + n=n..')' n=l..n l=l..'/a/@href' local nurl='' From af9953ea7ec89f3c6cf2c9423a8d67eb66f1c101 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 15 Mar 2018 15:18:43 +0300 Subject: [PATCH 2518/2794] add digitalteam [it-sc] # Conflicts: # lua/modules/myReaderMangaCMS.lua --- lua/modules/FoOlSlide.lua | 3 +++ lua/modules/myReaderMangaCMS.lua | 3 +++ 2 files changed, 6 insertions(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index bd6b167e0..062f0a8bb 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -275,6 +275,9 @@ function Init() AddWebsiteModule('TwistedHelScans', 'http://www.twistedhelscans.com', cat) AddWebsiteModule('TapTrans', 'https://taptaptaptaptap.net', cat) + cat = 'Italian-Scanlation' + AddWebsiteModule('DigitalTeam', 'http://digitalteamreader.netsons.org', cat) + -- es-sc cat = 'Spanish-Scanlation' AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com', cat) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 129ab38af..5ad6f5dec 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -98,4 +98,7 @@ function Init() AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com/', c); + + c='Italian-Scanlation' + AddWebsiteModule('DigitalTeamAltervista', 'http://digitalteam1.altervista.org', c) end From 0ff5cabe82c8e4da45e255e9b8dc60dce3e61f96 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 3 Apr 2018 10:39:49 +0300 Subject: [PATCH 2519/2794] MangaDex, don't show delayed chapters fixes #1124 --- lua/modules/MangaDex.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index b513f513f..85e468813 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -10,18 +10,19 @@ function getinfo() mangainfo.genres = x.xpathstringall('//tr[./th="Genres:"]/td/span/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[./th="Status:"]')) mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') - local l='//*[@id="chapters"]//tr[@id]' - local n='/concat(., (if (starts-with(../td/time, "in ")) then " [DELAYED]" else "")' + local l='//*[@id="chapters"]//tr[@id and not(starts-with(./td/time, "in "))]' + local n='' if module.getoption('luashowalllang') then - n=n..'," [",../td[3]/img/@title,"]"' + n='/concat(.," [",../td[3]/img/@title,"]"' else l=l..'[./td/img[@title="English"]]' end if module.getoption('luashowscangroup') then + if n=='' then n='/concat(.' end n=n..'," [",../td[4],"]"' end l=l..'/td[2]' - n=n..')' + if n~='' then n=n..')' end n=l..n l=l..'/a/@href' local nurl='' From 5fa000c8d7b31bf34f5ddccd5a757192b2486ea7 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 3 Apr 2018 11:30:56 +0300 Subject: [PATCH 2520/2794] add ac.qq.com [raw] #1148 --- lua/modules/acqqcom.lua | 109 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 lua/modules/acqqcom.lua diff --git a/lua/modules/acqqcom.lua b/lua/modules/acqqcom.lua new file mode 100644 index 000000000..fb61e18ea --- /dev/null +++ b/lua/modules/acqqcom.lua @@ -0,0 +1,109 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h2[contains(@class, "works-intro-title")]') + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[contains(@class,"works-cover")]/a/img/@src')) + mangainfo.authors=x.xpathstring('//p[@class="works-intro-digi"]/span[contains(., "作者")]/em/substring-before(., " ")') + mangainfo.summary=x.xpathstring('//p[contains(@class,"works-intro-short")]') + x.xpathhrefall('//div[@id="chapter"]//ol[contains(@class, "chapter-page-all")]/li//a', mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function decode1(str) + local _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + str = str:gsub('[^A-Za-z0-9%+/=]', '') + local a = '' + local b, d, h, f, g, e = 0, 0, 0, 0, 0, 0 + while e < str:len() do + e = e + 1; b = string.find(_keyStr, str:sub(e, e)); if b == nil then b = -1 else b = b - 1 end; + e = e + 1; d = string.find(_keyStr, str:sub(e, e)); if d == nil then d = -1 else d = d - 1 end; + e = e + 1; f = string.find(_keyStr, str:sub(e, e)); if f == nil then f = -1 else f = f - 1 end; + e = e + 1; g = string.find(_keyStr, str:sub(e, e)); if g == nil then g = -1 else g = g - 1 end; + b = b << 2 | d >> 4 + d = (d & 15) << 4 | f >> 2 + h = (f & 3) << 6 | g + a = a .. string.char(b) + if f ~= 64 then a = a .. string.char(d); end + if g ~= 64 then a = a .. string.char(h); end + end + function utf8_decode(c) + local a, b, d, c1, c2 = '', 0, 0, 0, 0 + while b < c:len() do + d = c:byte(b+1) + if 128 > d then + a = a .. string.char(d) + b = b + 1 + else + if (191 < d) and (224 > d) then + c2 = c:byte(b+2) + a = a .. string.char((d & 31) << 6 | c2 & 63) + b = b + 2 + else + c2 = c:byte(b+2) + c3 = c:byte(b+3) + a = a .. string.char((d & 15) << 12 | (c2 & 63) << 6 | c3 & 63) + b = b + 3 + end + end + end + return a + end + return utf8_decode(a) +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "var DATA")]') + s = GetBetween("= '", "',", s) + s = decode1(s:sub(2)) + x.parsehtml(s) + x.xpathstringall('json(*).picture().url', task.pagelinks) + return true + else + return false + end +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/Comic/all/search/hot/page/1') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//span[contains(@class,"ret-result-num")]/em')) + if page == nil then page = 1 end + page = math.ceil(page / 12) + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl..'/Comic/all/search/hot/page/'..IncStr(url)) then + TXQuery.Create(http.document).XPathHREFAll('//ul[contains(@class, "ret-search-list")]/li//h3/a',links,names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Raw' + m.website='AcQQCom' + m.rooturl='http://ac.qq.com' + m.lastupdated='April 2, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' +end From 7d341d6518796537fbcef57674763035c3913bf8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 5 Apr 2018 17:10:28 +0300 Subject: [PATCH 2521/2794] add EvilFlowers [en-sc] #1136 --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 062f0a8bb..c91c214b8 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -274,6 +274,7 @@ function Init() AddWebsiteModule('FujoshiBitches', 'http://fujoshibitches.shounen-ai.net', cat) AddWebsiteModule('TwistedHelScans', 'http://www.twistedhelscans.com', cat) AddWebsiteModule('TapTrans', 'https://taptaptaptaptap.net', cat) + AddWebsiteModule('EvilFlowers', 'http://reader.evilflowers.com', cat) cat = 'Italian-Scanlation' AddWebsiteModule('DigitalTeam', 'http://digitalteamreader.netsons.org', cat) From 90fb13cab8fc1fd3a443ea5ef7210564e7f0fc5d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 6 Apr 2018 07:10:29 +0300 Subject: [PATCH 2522/2794] mangadex, fix --- lua/modules/MangaDex.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 85e468813..d210ccb60 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -10,7 +10,7 @@ function getinfo() mangainfo.genres = x.xpathstringall('//tr[./th="Genres:"]/td/span/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[./th="Status:"]')) mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') - local l='//*[@id="chapters"]//tr[@id and not(starts-with(./td/time, "in "))]' + local l='//table//tr[@id and not(starts-with(./td/time, "in "))]' local n='' if module.getoption('luashowalllang') then n='/concat(.," [",../td[3]/img/@title,"]"' From 5ad88554850c37ff9372f75a1babd1582c57db56 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 6 Apr 2018 11:53:44 +0300 Subject: [PATCH 2523/2794] JapScan, move to lua --- baseunits/ModuleList.inc | 1 - lua/modules/JapScan.lua | 71 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 lua/modules/JapScan.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index d75dd007c..7c23742c7 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -39,7 +39,6 @@ uses MyMangaMe, ReadComics, MangaCool, - JapScan, MangaGo, GoodManga, MangaZuki, diff --git a/lua/modules/JapScan.lua b/lua/modules/JapScan.lua new file mode 100644 index 000000000..b66976905 --- /dev/null +++ b/lua/modules/JapScan.lua @@ -0,0 +1,71 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//h1[@class="bg-header"]') + mangainfo.title = string.gsub(mangainfo.title, '^Manga ', '') + mangainfo.title = string.gsub(mangainfo.title, ' VF$', '') + end + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="table"]/div[@class="row"]/div[6]'), 'En Cours', 'Termine') + mangainfo.authors=x.xpathstring('//div[@class="table"]/div[@class="row"]/div[1]') + mangainfo.genres=x.xpathstring('//div[@class="table"]/div[@class="row"]/div[4]') + mangainfo.summary=x.xpathstring('//div[@id="synopsis"]/string-join(text(),codepoints-to-string(10))') + local v = x.xpath('//*[@id="liste_chapitres"]/ul/li/a') + for i = 1,v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('href')) + local s = v1.toString + if Pos('[email protected]', s) ~= 0 then + s = mangainfo.title .. ' ' .. x.xpathstring('text()[2]', v1) + end + s = string.gsub(s, '^Scan ', '') + mangainfo.chapternames.add(s) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//select[@id="pages"]/option/@value', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/mangas/') then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//*[@id="liste_mangas"]/div[@class="row"]/div[@class="cell"][1]/a', links, names) + return no_error + else + return net_problem + end +end + +function downloadimage() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x = TXQuery.Create(http.document) + return http.get(x.xpathstring('//img[@id="image"]/@src')) + end + return false +end + +function Init() + local m=NewModule() + m.category='French' + m.website='Japscan' + m.rooturl='http://www.japscan.cc' + m.lastupdated='April 6, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ondownloadimage='downloadimage' +end From 8f5505d09233fc177e77509cc0f898e0ed7b7d81 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 6 Apr 2018 11:56:44 +0300 Subject: [PATCH 2524/2794] cleanup --- baseunits/modules/JapScan.pas | 119 ---------------------------------- 1 file changed, 119 deletions(-) delete mode 100644 baseunits/modules/JapScan.pas diff --git a/baseunits/modules/JapScan.pas b/baseunits/modules/JapScan.pas deleted file mode 100644 index bec3c8756..000000000 --- a/baseunits/modules/JapScan.pas +++ /dev/null @@ -1,119 +0,0 @@ -unit JapScan; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; - -implementation - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/mangas/') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - XPathHREFAll('//*[@id="liste_mangas"]/div[@class="row"]/div[@class="cell"]/a', ALinks, ANames); - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - title := XPathString('//title'); - if Pos(' | Japscan.Com', title) <> 0 then - title := GetString(title, 'Lecture En Ligne Des Chapitres ', ' | Japscan.Com'); - authors := XPathString('//div[@class="table"]/div[@class="row"]/div[1]'); - genres := XPathString('//div[@class="table"]/div[@class="row"]/div[4]'); - summary := XPathString('//div[@id="synopsis"]/string-join(text(),codepoints-to-string(10))'); - status := MangaInfoStatusIfPos(XPathString('//div[@class="table"]/div[@class="row"]/div[6]'), 'En Cours', 'Terminé'); - for v in XPath('//*[@id="liste_chapitres"]/ul/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - s := v.toString; - if Pos('[email protected]', s) <> 0 then - s := title + ' ' + XPathString('text()[2]', v) - else - if Pos('Scan ', s) = 1 then - Delete(s, 1, 5); - chapterName.Add(s); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - dataimg, imgurl: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - XPathStringAll('//select[@id="pages"]/option/@data-img', Document, PageLinks); - end; - end; -end; - -function DownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - with DownloadThread, DownloadThread.FHTTP, DownloadThread.Task.Container do - begin - if GET(AppendURLDelim(FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr])) + IncStr(WorkId) + '.html') then - Result := GET(XPathString('//img[@id="image"]/@src', Document)); - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'Japscan'; - RootURL := 'http://www.japscan.com'; - Category := 'French'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnDownloadImage := @DownloadImage; - end; -end; - -initialization - RegisterModule; - -end. From 09bf6c1570cb1e3a9857fe705fa05004b5b53441 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 6 Apr 2018 11:59:40 +0300 Subject: [PATCH 2525/2794] HeavenManga, change domain --- lua/modules/HeavenManga.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index 30812ad80..8c9a79c7c 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -68,7 +68,7 @@ end function Init() local m = NewModule() m.website = 'HeavenManga' - m.rooturl = 'http://heavenmanga.biz' + m.rooturl = 'http://heavenmanga.site' m.category = 'English' m.lastupdated='February 26, 2018' m.ongetinfo='getinfo' From a1e912d13c4e99ddd8ef2193608141399f6602ac Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 6 Apr 2018 12:18:13 +0300 Subject: [PATCH 2526/2794] UnionMangas, move to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/UnionMangas.pas | 102 ------------------------------ lua/modules/UnionMangas.lua | 70 ++++++++++++++++++++ 3 files changed, 70 insertions(+), 103 deletions(-) delete mode 100644 baseunits/modules/UnionMangas.pas create mode 100644 lua/modules/UnionMangas.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 7c23742c7..fcc8168cd 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -9,7 +9,6 @@ uses Madokami, RawSenManga, KissManga, - UnionMangas, MangaStreamTo, MangaHome, GameofScanlation, diff --git a/baseunits/modules/UnionMangas.pas b/baseunits/modules/UnionMangas.pas deleted file mode 100644 index 74d4f1a6c..000000000 --- a/baseunits/modules/UnionMangas.pas +++ /dev/null @@ -1,102 +0,0 @@ -unit UnionMangas; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil; - -implementation - -const - dirurl = '/mangas'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin - Result := NO_ERROR; - Page := StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()]/a/substring-before(substring-after(@href,"a-z/"),"/")', MangaInfo.FHTTP.Document), 1); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if AURL <> '0' then s += '/a-z/' + IncStr(AURL) + '/*'; - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - XPathHREFAll('//*[@class="row"]/div/a[2]', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@class="img-thumbnail"]/@src')); - title := XPathString('//title/substring-before(.," - Union Mangás")'); - genres := XPathString('//h4[starts-with(./label,"Gênero")]/substring-after(.,":")'); - authors := XPathString('//h4[starts-with(./label,"Autor")]/substring-after(.,":")'); - artists := XPathString('//h4[starts-with(./label,"Artista")]/substring-after(.,":")'); - status := MangaInfoStatusIfPos(XPathString('//h4[starts-with(./label,"Status")]/substring-after(.,":")'), 'Ativo', 'Completo'); - summary := XPathString('//*[@class="panel-body"]'); - XPathHREFAll('//*[contains(@class,"lancamento-linha")]/div[1]/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - XPathStringAll('//img[contains(@class, "img-manga") and contains(@src, "/leitor/")]/@src', Document, PageLinks); - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'UnionMangas'; - RootURL := 'http://unionmangas.net'; - Category := 'Portugues'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/UnionMangas.lua b/lua/modules/UnionMangas.lua new file mode 100644 index 000000000..8f8fe6a72 --- /dev/null +++ b/lua/modules/UnionMangas.lua @@ -0,0 +1,70 @@ +local dirurl = '/mangas' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//title/substring-before(.," - Union Mangás")') + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//img[@class="img-thumbnail"]/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="table"]/div[@class="row"]/div[6]'), 'En Cours', 'Termine') + mangainfo.authors=x.xpathstring('//h4[starts-with(./label,"Autor")]/substring-after(.,":")') + mangainfo.artists=x.xpathstring('//h4[starts-with(./label,"Artista")]/substring-after(.,":")') + mangainfo.genres=x.xpathstring('//h4[starts-with(./label,"Gênero")]/substring-after(.,":")') + mangainfo.summary=x.xpathstring('//*[@class="panel-body"]') + x.xpathhrefall('//*[contains(@class,"lancamento-linha")]/div[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[contains(@class, "img-manga") and contains(@src, "/leitor/")]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + local s = module.RootURL .. dirurl + if url ~= '0' then + s = s .. '/a-z/' + IncStr(url) + '/*' + end + if http.get(s) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//*[@class="row"]/div/a[2]', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. dirurl) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('//ul[@class="pagination"]/li[last()]/a/substring-before(substring-after(@href,"a-z/"),"/")')) + if page == nil then pages = 1 end + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='Portugues' + m.website='UnionMangas' + m.rooturl='http://unionmangas.cc' + m.lastupdated='April 6, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber='getdirectorypagenumber' +end From 81e0c1216bd0984f446235d950b63fa45f4883d2 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 09:09:31 +0300 Subject: [PATCH 2527/2794] fix CF --- baseunits/modules/Cloudflare.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 24ea096ef..44fe51c1b 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -94,7 +94,7 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; try v := Execute(s); if v.ValueType = bvtNUMBER then - jschl_answer := FloatToStr(v.Num); + jschl_answer := FloatToStr(v.Num, FMDFormatSettings); finally Free; end; From fd29eaea20198d751559ed8c8c060f7518042b8b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 09:14:44 +0300 Subject: [PATCH 2528/2794] NeuManga, fix title fixes #1137 --- lua/modules/NeuManga.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/NeuManga.lua b/lua/modules/NeuManga.lua index bf2b94c5d..5fa1b7fb8 100644 --- a/lua/modules/NeuManga.lua +++ b/lua/modules/NeuManga.lua @@ -2,13 +2,13 @@ function GetInfo() mangainfo.url=MaybeFillHost(module.rooturl,url) if http.get(mangainfo.url) then x=TXQuery.Create(http.Document) - mangainfo.title=x.XPathString('//h1[@class="manga1"]/text()') + mangainfo.title=x.XPathString('//h1[contains(@class,"manga1")]/text()') mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[@class="imagemg"]/@src')) mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//div[@class="info"]/span[contains(., "Status")]/a')) mangainfo.authors = x.XPathStringAll('//div[@class="info"]/span[contains(., "Author")]/a') mangainfo.artists = x.XPathStringAll('//div[@class="info"]/span[contains(., "Artist")]/a') mangainfo.genres = x.XPathStringAll('//div[@class="info"]/span[contains(., "Genre")]/a') - mangainfo.summary = x.XPathStringAll('//div[@class="summary"]/text()', '') + mangainfo.summary = x.XPathStringAll('//div[contains(@class,"summary")]/text()', '') v=x.xpath('//div[@id="scans"]/div[1]/div[@class="item-content"]/a') for i=1, v.count do v1=v.get(i) From 47ecde4488abb7c4812b00192e3f6e18c37fc0df Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 10:06:24 +0300 Subject: [PATCH 2529/2794] update changelog --- changelog.txt | 108 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7a1b0cdb7..9c4222c71 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,36 +4,137 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.153.0 (xx-xx-2018) +[+] Added SoManga [PT] +[+] Added ReadMangaEU [EN] +[+] Added MangaDoom [EN] +[+] Added RawMangaUpdate [RAW] +[+] Added ManhuaTr [TR] +[+] Added MangaVadisi [TR] +[+] Added Manga99 [EN] +[+] Added MangaRawOnline [RAW] +[+] Added AcQQCom [RAW] +[+] Added MangaLib [RU] +[+] Added DesuMe [RU] +[+] Added Shakai [RU] +[+] Added MangaOnlineBiz [RU] +[+] Added MangaOnlineToday [EN] +[+] Added TrashScanlations [EN-SC] +[+] Added HatigarmScans [EN-SC] +[+] Added BunnysScans [EN-SC] +[+] Added CanisMajorScans [EN-SC] +[+] Added HoshikuzuuScans [EN-SC] +[+] Added YaoiIsLife [EN-SC] +[+] Added FujoshiBitches [EN-SC] +[+] Added TwistedHelScans [EN-SC] +[+] Added TapTrans [EN-SC] +[+] Added ZeroScans [EN-SC] +[+] Added WhiteCloudPavilion [EN-SC] +[+] Added EvilFlowers [EN-SC] +[+] Added LoliVault [SP-SC] +[+] Added CoYuHi [SP-SC] +[+] Added SKSubs [SP-SC] +[+] Added ComicVn [VI] +[+] Added MangaSupa [EN] +[+] Added MangaFoxCom [EN] +[+] Added MangaKid [ID] +[+] Added MangaCast [ID] +[-] Removed MangaTraders +[*] MangaDex, fixed all +[*] Hentai2Read, fix domain +[*] Imgur, fix download +[*] LHTranslation, fixed all +[*] HeavenManga, change domain +[*] LeitorNet, added manga list update +[*] JapScan, change domain +[*] UnionMangas, change domain +[*] NeuManga, fix manga info +[*] Updated Russian localization +[*] Cloudflare, fix bypass +[*] Fixed crash when searching website by name +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.152.0...0.9.153.0 + 0.9.152.0 (28-02-2018) -[*] Fix updater doesn't extract the update package after download. +[!] Fix updater doesn't extract the update package after download. You have to download this version manually or extract updatepakage.7z Full changes: https://github.com/riderkick/FMD/compare/0.9.151.0...0.9.152.0 0.9.151.0 (28-02-2018) +[+] Added MangajinNoFansub [SP-SC] +[+] Added TenManga [EN] +[*] Updated Portuguese (Brazil) translation by Havokdan +[*] Updated Spanish translation by rs3mk +[*] Updated Turkish translation by Tmp341 +[*] Madokami, fixed login +[*] MangaDex, fixed all +[*] Disable coloring on disabled item in favorites list [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.150.0...0.9.151.0 0.9.150.0 (26-02-2018) +[+] Added HeavenManga [EN] +[+] Added Nightow [SP-SC] +[+] Added TrueColorsScan [SP-SC] +[*] SeinagiFansub, fixed domain [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.149.0...0.9.150.0 0.9.149.0 (26-02-2018) +[!] Separated settings for each website +[+] Added KomikStation [ID] +[+] Added SilentSkyScans [EN-SC] +[+] Added Yuri-ism [EN-SC] +[+] Added SaikoScans [EN-SC] +[+] Added RoseliaScanlations [EN-SC] +[+] Added VortexScans [EN-SC] +[+] Added PhoenixSerenade [EN-SC] +[+] Added Riceballicious [EN-SC] +[+] Added ForgottenScans [EN-SC] +[+] Added MangaichiScan [EN-SC] +[+] Added DarkSkyScan [SP-SC] +[+] Added NozominoFansub [SP-SC] +[+] Added add ManHuaTai [Raw] +[+] Added add Rawdevart [Raw] +[*] Updated Indonesian localization +[*] Updated Turkish localization +[*] Fix JPG to PNG conversion +[*] MangaHubIO, fix download +[*] MangaDex, add chapter list pagination +[*] VnSharing, fix update list [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.148.0...0.9.149.0 0.9.148.0 (20-02-2018) +[+] Added MyMangaIO [FR] +[+] Added MangaHub [EN] +[+] Added MangaBB [EN] +[+] Added AntisenseScans [EN-SC] +[+] Added TheCatScans [EN-SC] +[+] Added DeathTollScans [EN-SC] +[+] Added IdkScans [SP-SC] +[*] Tumangaonline, show scanlation group +[*] Updated Spanish translation +[*] Added summary to manga list hint [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.147.0...0.9.148.0 0.9.147.0 (19-02-2018) +[+] Added LeitorNet [PT] +[*] Restore window size on startup [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.146.0...0.9.147.0 0.9.146.0 (18-02-2018) +[+] Added XAnimeSeduccion [SP-SC] +[+] Added JokerFansub [SP-SC] +[+] Added PatyScans [SP-SC] +[*] MangaKu, fixed all [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.145.0...0.9.146.0 0.9.145.0 (17-02-2018) +[*] Update Indonesian localization [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.144.0...0.9.145.0 @@ -43,6 +144,8 @@ Full changes: https://github.com/riderkick/FMD/compare/0.9.143.0...0.9.144.0 0.9.143.0 (17-02-2018) [*] Update Indonesian localization +[*] Update Turkish localization +[*] Update Russian localization [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.142.0...0.9.143.0 @@ -60,6 +163,7 @@ Full changes: https://github.com/riderkick/FMD/compare/0.9.141.0...0.9.142.0 [+] Added new updater only to extract update package [*] Download new version in the background [*] Download mangalist database(s) in the background +[*] Pururin, change domain [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.140.0...0.9.141.0 @@ -137,8 +241,8 @@ Full changes: https://github.com/riderkick/FMD/compare/0.9.134.0...0.9.135.0 Full changes: https://github.com/riderkick/FMD/compare/0.9.133.0...0.9.134.0 0.9.133.0 (07-02-2018) +[!] Added Lua support to add website module at runtime [+] Added left download toolbar to move selected download(s). Options > View -[+] Added Lua support to add website module at runtime [+] Added WorldThree [EN-SC] [+] Added PsychoPlay [EN-SC] [+] Added MangaZukiRaws [Raws] From dfac8c62fea42124b41ee7bdab752b579b79322d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 12:44:47 +0300 Subject: [PATCH 2530/2794] Bump version 0.9.153.0 --- changelog.txt | 2 +- mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9c4222c71..4c260bd98 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,7 +4,7 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) -0.9.153.0 (xx-xx-2018) +0.9.153.0 (08-04-2018) [+] Added SoManga [PT] [+] Added ReadMangaEU [EN] [+] Added MangaDoom [EN] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 8448a8572..b3a3d31f7 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="152"/> + <RevisionNr Value="153"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index 57660d7c4..d916687c9 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.152.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.152.0/fmd_0.9.152.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.152.0/fmd_0.9.152.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.152.0/fmd_0.9.152.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.152.0/fmd_0.9.152.0_Win64.7z +VERSION=0.9.153.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.153.0/fmd_0.9.153.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.153.0/fmd_0.9.153.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.153.0/fmd_0.9.153.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.153.0/fmd_0.9.153.0_Win64.7z From 30f7182e00cc94d6f549777372c84571728bc143 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 15:54:03 +0300 Subject: [PATCH 2531/2794] mangago, cleanup --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaGo.pas | 366 ---------------------------------- lua/modules/MangaGo.lua | 265 ++++++++++++++++++++++++ 3 files changed, 265 insertions(+), 367 deletions(-) delete mode 100644 baseunits/modules/MangaGo.pas create mode 100644 lua/modules/MangaGo.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index fcc8168cd..f161b56c4 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -38,7 +38,6 @@ uses MyMangaMe, ReadComics, MangaCool, - MangaGo, GoodManga, MangaZuki, ReadMangaToday, diff --git a/baseunits/modules/MangaGo.pas b/baseunits/modules/MangaGo.pas deleted file mode 100644 index 17ed8187c..000000000 --- a/baseunits/modules/MangaGo.pas +++ /dev/null @@ -1,366 +0,0 @@ -unit MangaGo; - -{$mode objfpc}{$H+} - -interface - -implementation - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, BaseCrypto, synautil, Graphics, - Interfaces, Math, RegExpr, strutils, JSUnpack, syncobjs; - -var - initstr: String; - cs: TCriticalSection; - ks: TStringList; - -const - dirurl= '/list/directory/all/'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - MangaInfo.FHTTP.Headers.Values['Referer'] := Module.RootURL; - if Mangainfo.FHTTP.GET(Module.RootURL + dirurl + '1/') then - begin - Result := NO_ERROR; - Page := StrToIntDef(XPathString('count(//div[@class="pagination"]//ol/li//select/option)', MangaInfo.FHTTP.Document), 1); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - ref: String; -begin - Result := NET_PROBLEM; - if AURL = '0' then ref := Module.RootURL - else ref := Module.RootURL + dirurl + AURL + '/'; - MangaInfo.FHTTP.Headers.Values['Referer'] := ref; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL) + '/') then - begin - Result := NO_ERROR; - XPathHREFtitleAll('//div[@class="directory_left"]//li/h3/a', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="left cover"]/img/@src')); - title := XPathString('//h1'); - if RightStr(title, 6) = ' manga' then SetLength(title, Length(title) - 6); - status := MangaInfoStatusIfPos(XPathString('//div[@class="manga_right"]//td/label[.="Status:"]/following-sibling::*/text()')); - authors := XPathString('//div[@class="manga_right"]//td/label[.="Author:"]/string-join(following-sibling::*/text(),", ")'); - genres := XPathString('//div[@class="manga_right"]//td/label[.="Genre(s):"]/string-join(following-sibling::*/text(),", ")'); - summary := XPathString('//div[@class="manga_summary"]/string-join(text(),codepoints-to-string(10))'); - XPathHREFAll('//table[@id="chapter_table"]//td//a[not(@style)]', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - Reset; - Headers.Values['Referer'] := url; - end; - end; -end; - -function ReplaceHex(script: String): String; -var - rg: TRegExpr; - c: Char; - s: String; -begin - Result := Copy(script, 1, Length(script)); - rg := TRegExpr.Create('\\x[\da-f]{1,2}'); - try - if rg.Exec(script) then begin - s := SeparateRight(rg.Match[0], '\x'); - c := Chr(Byte(Hex2Dec(s) and $ff)); - Result := ReplaceString(Result, rg.Match[0], c); - while rg.ExecNext do begin - s := SeparateRight(rg.Match[0], '\x'); - c := Chr(Byte(Hex2Dec(s) and $ff)); - Result := ReplaceString(Result, rg.Match[0], c); - end; - end; - finally - rg.Free; - end; -end; - -function GetScriptText(script: String): String; -begin - Result := SeparateRight(script, '('''); - Result := SeparateLeft(Result, ''','); -end; - -function GetA(script: String): Integer; -var s: String; -begin - s := SeparateRight(script, ''','); - s := SeparateLeft(s, ','); - Result := StrToIntDef(s, 1); -end; - -function GetC(script: String): Integer; -var s: String; -begin - s := SeparateRight(script, ''','); - s := SeparateRight(s, ','); - s := SeparateLeft(s, ','); - Result := StrToIntDef(s, 1); -end; - -function GetWords(script: String): String; -var s: String; -begin - s := SeparateRight(script, '('''); - s := SeparateRight(s, ',"'); - Result := SeparateLeft(s, '"'); -end; - -function GetSeparator(script: String): String; -var - s: String; -begin - s := ReplaceHex(script); - s := s.Substring(RPos('split', s)); - Result := GetBetween('(', ')', s); - Result := ReplaceString(Result, '''', ''); - Result := ReplaceString(Result, '"', ''); -end; - -function DecryptScript(script: String): String; -var - u: TJSUnpack36; - words, sep, text: String; -begin - Result := ''; - u := TJSUnpack36.Create; - try - text := ReplaceHex(GetScriptText(script)); - words := ReplaceHex(GetWords(script)); - sep := GetSeparator(script); - Result := u.Unpack(text, GetA(script), GetC(script), words.Split(sep)); - finally - u.Free; - end; -end; - -function GetKey(script: String): String; -var - rg: TRegExpr; -begin - Result := ''; - rg := TRegExpr.Create('\=\s*["'']@(.+?)!["'']'); - try - if rg.Exec(script) then - Result := '@' + rg.Match[1] + '!'; - finally - rg.Free; - end; -end; - -function GetIV(script: String): String; -begin - Result := GetKey(script); -end; - -procedure FillK(script: String); -var - rg1, rg2: TRegExpr; -begin - if ks.Count > 0 then Exit; - cs.Enter; - rg1 := TRegExpr.Create('\[\s*["'']([0-9a-f]+)["'']\s*\]\s*\=\s*["'']([a\d]+)["'']'); - rg2 := TRegExpr.Create('\w\s*\=\s*["'']([a\d]+)["'']'); - try - if ks.Count > 0 then Exit; - if rg1.Exec(script) then begin - ks.Values[rg1.Match[1]] := rg1.Match[2]; - while rg1.ExecNext do - ks.Values[rg1.Match[1]] := rg1.Match[2]; - end; - if rg2.Exec(script) then - initstr := rg2.Match[1]; - finally - rg1.Free; - rg2.Free; - cs.Leave; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s, rurl, script: String; - i, cnt: Integer; - a: TStringArray; - t: TStringList; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - rurl := MaybeFillHost(Module.RootURL, AURL); - if not GET(rurl) then Exit; - - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - cnt := XPathCount('//ul[@id="dropdown-menu-page"]/li/a'); - s := XPathString('//script[contains(.,"imgsrcs")]'); - finally - Free; - end; - - if s = '' then Exit; - if Pos('imgsrcs = new Array', s) <> 0 then - s := GetString(s, '(', ')') - else - s := GetString(s, ' = ''', ''';'); - s := StringReplace(s, '''', '', [rfReplaceAll]); - script := XPathString('//script[contains(@src, "chapter.js")]/@src', Document); - - Reset; - Headers.Values['Referer'] := rurl; - if GET(script) then begin - t := TStringList.Create; - try - t.LoadFromStream(Document); - script := DecryptScript(t.Text); - if Pos(',', s) = 0 then - s := AESDecryptCBCMD5Base64ZerosPadding(s, GetKey(script), GetIV(script)); - FillK(script); - finally - t.Free; - end; - end; - - a := s.Split([',']); - for i := 0 to Math.min(cnt - 1, Length(a) - 1) do - PageLinks.Add(SeparateRight(a[i], '//')); - end; -end; - -function BeforeDownloadImage(const DownloadThread: TDownloadThread; - var AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := True; - if DownloadThread = nil then Exit; - DownloadThread.FHTTP.Headers.Values['Referer'] := ' ' + Module.RootURL; -end; - -function DeScramble(AURL: String; image: TPicture): TPicture; -var - a: TStringArray; - i, size, heightnum, aint: Integer; - sw, h, j, y, rxpos, py, canvasx: float; - r: TPicture; - rect1, rect2: TRect; - tmp: String; -begin - tmp := initstr; - for i := 0 to ks.Count - 1 do - if Pos(ks.Names[i], AURL) > 0 then begin - tmp := ks.Values[ks.Names[i]]; - Break; - end; - - a := tmp.Split(['a']); - r := TPicture.Create; - r.Bitmap.SetSize(image.Width, image.Height); - - size := 9; - heightnum := 9; - sw := float(image.Width) / size; - h := float(image.Height) / heightnum; - for i := 0 to size * heightnum - 1 do begin - aint := StrToIntDef(a[i], 0); - j := Floor(float(aint) / float(heightnum)); - y := j * h; - rxpos := (aint - j * size) * sw; - j := Floor(float(i) / float(size)); - py := j * h; - canvasX := (i - j * size) * sw; - rect1 := Rect(Trunc(rxpos), Trunc(y), Trunc(rxpos) + Trunc(sw), Trunc(y) + Trunc(h)); - rect2 := Rect(Trunc(canvasX), Trunc(py), Trunc(canvasX) + Trunc(sw), Trunc(py) + Trunc(h)) ; - r.Bitmap.Canvas.CopyRect(rect1, image.Bitmap.Canvas, rect2); - end; - - Result := r; -end; - -function DownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - image, r: TPicture; -begin - Result := False; - if DownloadThread = nil then Exit; - if DownloadThread.FHTTP.GET(AURL) then begin - if (Pos('mangapicgallery.com/r/cspiclink', LowerCase(AURL))) = 0 then begin - Result := True; - Exit; - end; - image := TPicture.Create; - r := nil; - try - image.LoadFromStream(DownloadThread.FHTTP.Document); - r := DeScramble(AURL, image); - DownloadThread.FHTTP.Document.Position := 0; - r.SaveToStreamWithFileExt(DownloadThread.FHTTP.Document, 'jpg'); - Result := True; - finally - r.Free; - image.Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaGo'; - RootURL := 'http://www.mangago.me'; - Category := 'English'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnBeforeDownloadImage := @BeforeDownloadImage; - OnDownloadImage := @DownloadImage; - end; -end; - -initialization - cs := TCriticalSection.Create; - initstr := ''; - ks := TStringList.Create; - RegisterModule; - -finalization - ks.Free; - cs.Free; - -end. diff --git a/lua/modules/MangaGo.lua b/lua/modules/MangaGo.lua new file mode 100644 index 000000000..114431bd5 --- /dev/null +++ b/lua/modules/MangaGo.lua @@ -0,0 +1,265 @@ +local mgdirurl = '/list/directory/all/' +local rdirurl = '/directory/?gid=all&sindex=all&status=all&page=' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then mangainfo.title=x.xpathstring('//h1'):gsub(' manga$', ''); end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="left cover"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="manga_right"]//td/label[.="Author:"]/string-join(following-sibling::*/text(),", ")') + mangainfo.genres=x.xpathstring('//div[@class="manga_right"]//td/label[.="Genre(s):"]/string-join(following-sibling::*/text(),", ")') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="manga_right"]//td/label[.="Status:"]/following-sibling::*/text()')) + mangainfo.summary=x.xpathstring('//div[@class="manga_summary"]/string-join(text(),codepoints-to-string(10))') + x.xpathhrefall('//table[@id="chapter_table"]//td//a[not(@style)]', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + http.reset() + http.headers.values['Referer'] = mangainfo.url + return no_error + else + return net_problem + end +end + +function r_getinfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.Document) + if mangainfo.title == '' then mangainfo.title=x.XPathString('//div[@class="title"]/h1'); end + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[@class="pic"]/@src')) + mangainfo.authors = x.xpathstring('//div[@class="cartoon-intro"]//p[contains(span, "Author")]/text()') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="cartoon-intro"]//p/span[contains(., "Status")]/following-sibling::span[1]')) + mangainfo.genres = x.XPathStringAll('//div[@class="cartoon-intro"]//p[contains(span, "Author")]/a') + mangainfo.summary = x.xpathstring('//div[@class="summary"]') + x.XPathHREFAll('//table[@class="list_table"]//tr/td[@class="chapter_name_td"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + http.get(module.rooturl .. '/ywz.ico') + http.reset() + http.headers.values['Referer'] = mangainfo.url + return no_error + else + return net_error + end +end + +function getdirectorypagenumber() + http.headers.values['Referer'] = module.rooturl + local s = module.rooturl .. mgdirurl .. '1/' + if http.get(s) then + x=TXQuery.Create(http.document) + page=x.xpathcount('//div[@class="pagination"]//ol/li//select/option') + return true + else + return false + end +end + +function r_getdirectorypagenumber() + http.headers.values['Referer'] = module.rooturl + local s = module.rooturl .. rdirurl .. '1' + if http.get(s) then + x=TXQuery.Create(http.document) + page=x.xpathcount('//div[@class="pagination"]//ol/li//select/option') + return true + else + return false + end +end + +local js = require 'modules.jsunpack' +function getpagenumber() + task.pagelinks.clear() + task.pagenumber=0 + local rurl = MaybeFillHost(module.rooturl, url) + if http.get(rurl) then + x=TXQuery.Create(http.Document) + local cnt = x.xpathcount('//ul[@id="dropdown-menu-page"]/li/a') + local s = x.xpathstring('//script[contains(.,"imgsrcs")]') + if s == '' then return false; end + if Pos(' imgsrcs = new Array', s) > 0 then + s = GetBetween('(', ')', s) + else + s = GetBetween(' imgsrcs = \'', '\';', s) + end + s = s:gsub('\'', '') + local script = x.xpathstring('//script[contains(@src, "chapter.js")]/@src') + http.reset() + http.headers.values['Referer'] = rurl + if http.get(script) then + local function unp(script) + script = js.replacehex(script) + local a, c = script:match('[\'"]%s*,%s*(%d+)%s*,%s*(%d+)%s*,%s*[\'"]') + a, c = tonumber(a), tonumber(c) + local d = script:match('[\'"]%s*,%s*%d+%s*,%s*%d+%s*,%s*[\'"].+[\'"].+split.+%([\'"](.+)[\'"]%)') + local w = script:match('[\'"]%s*,%s*%d+%s*,%s*%d+%s*,%s*[\'"](.+)[\'"].+split') + w = js.splitstr(w, d) + local txt = script:match('}%s*%(%s*[\'"](.+)[\'"]%s*,%s*%d+%s*,%s*%d+%s*,%s*[\'"](.+)[\'"].+split') + return js.unpack36(txt, a, c, w) + end + local function d3(script, u) + local function _d(a, b) + local function rp(a, b, c) return a:sub(1, b) .. c .. a:sub(b+2); end + local c = a:len() + for j = 4,1,-1 do + for i = c-1,b[j],-1 do + if i%2 ~= 0 then + local tmp = string.char(a:byte(i-b[j]+1)) + a = rp(a, i-b[j], string.char(a:byte(i+1))) + a = rp(a, i, tmp) + end + end + end + return a + end + local bstr = script:match('%d+', script:find('dorder%s*%(%s*img')) + local b = {} + for i=1,bstr:len() do b[i] = bstr:byte(i) - 48; end + return _d(u, b) + end + if Pos(',', s) == 0 then + script = unp(StreamToString(http.document)) + elseif Pos('http', s) == 0 then + script = unp(StreamToString(http.document)) + s = d3(script, s) + else + end + local a = js.splitstr(s, ',') + for i = 1, math.min(cnt, #a) do + task.pagelinks.add(SeparateRight(a[i], '//')) + end + if module.storage['loaded'] == '0' then filldict(script) end + end + else + return false + end + return true +end + +function beforedownloadimage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function filldef(m) + local dict = TStrings.create() + dict.values['60a2b0ed56cd458c4633d04b1b76b7e9'] = '18a72a69a64a13a1a43a3aa42a23a66a26a19a51a54a78a34a17a31a35a15a58a29a61a48a73a74a44a52a60a24a63a20a32a7a45a53a75a55a62a59a41a76a68a2a36a21a10a38a33a71a40a67a22a4a50a80a65a27a37a47a70a14a28a16a6a56a30a57a5a11a79a9a77a46a39a25a49a8a12' + dict.values['400df5e8817565e28b2e141c533ed7db'] = '61a74a10a45a3a37a72a22a57a39a25a56a52a29a70a60a67a41a63a55a27a28a43a18a5a9a8a40a17a48a44a79a38a47a32a73a4a6a13a34a33a49a2a42a50a76a54a36a35a14a58a7a69a46a16a30a21a11aa51a53a77a26a31a1a19a20a80a24a62a68a59a66a75a12a64a78a71a15a65a23' + dict.values['84ba0d8098f405b14f4dbbcc04c93bac'] = '61a26a35a16a55a10a72a37a2a60a66a65a33a44a7a28a70a62a32a56a30a40a58a15a74a47aa36a78a75a11a6a77a67a39a23a9a31a64a59a13a24a80a14a38a45a21a63a19a51a17a34a50a46a5a29a73a8a57a69a48a68a49a71a41a12a52a18a79a76a54a42a22a4a1a3a53a20a25a43a27' + dict.values['56665708741979f716e5bd64bf733c33'] = '23a7a41a48a57a27a69a36a76a62a40a75a26a2a51a6a10a65a43a24a1aa20a71a28a30a13a38a79a78a72a14a49a55a56a58a25a70a12a80a3a66a11a39a42a17a15a54a45a34a74a31a8a61a46a73a63a22a64a19a77a50a9a59a37a68a52a18a32a16a33a60a67a21a44a53a5a35a4a29a47' + dict.values['37abcb7424ce8df47ccb1d2dd9144b49'] = '67a45a39a72a35a38a61a11a51a60a13a22a31a25a75a30a74a43a69a50a6a26a16a49a77a68a59a64a17a56a18a1a10a54a44a62a53a80a5a23a48a32a29a79a24a70a28a58a71a3a52a42a55a9a14a36a73a34a2a27a57a0a21a41a33a37a76a8a40a65a7a20a12a19a47a4a78a15a63a66a46' + dict.values['874b83ba76a7e783d13abc2dabc08d76'] = '26a59a42a43a4a20a61a28a12a64a37a52a2a77a34a13a46a74a70a0a44a29a73a66a55a38a69a67a62a9a63a6a54a79a21a33a8a58a40a47a71a49a22a50a57a78a56a25a17a15a36a16a48a32a5a10a14a80a24a72a76a45a3a53a23a41a60a11a65a19a27a51a68a35a31a1a75a39a30a7a18' + dict.values['930b87ad89c2e2501f90d0f0e92a6b97'] = '9a29a49a67a62a40a28a50a64a77a46a31a16a73a14a45a51a44a7a76a22a78a68a37a74a69a25a65a41a11a52aa18a36a10a38a12a15a2a58a48a8a27a75a20a4a80a61a55a42a13a43a47a39a35a60a26a30a63a66a57a33a72a24a71a34a23a3a70a54a56a32a79a5a21a6a59a53a17a1a19' + dict.values['1269606c6c3d8bb6508426468216d6b1'] = '49a15a0a60a14a26a34a69a61a24a35a4a77a80a70a40a39a6a68a17a41a56a28a46a79a16a21a1a37a42a44a58a78a18a52a73a32a9a12a50a8a13a20a19a67a36a45a75a48a10a65a7a38a66a3a2a43a27a29a31a72a74a55a23a54a22a59a57a11a62a47a53a30a5a64a25a76a71a51a33a63' + dict.values['33a3b21bb2d14a09d15f995224ae4284'] = '30a59a35a34a42a8a10a56a70a64a48a69a26a18a6a16a54a24a73a79a68a33a32a2a63a53a31a14a17a57a41a80a76a40a60a12a43a29a39a4a77a58a66a36a38a52a13a19a0a75a28a55a25a61a71a11a67a49a23a45a5a15a1a50a51a9a44a47a65a74a72a27a7a37a46a20a22a62a78a21a3' + dict.values['9ae6640761b947e61624671ef841ee78'] = '62a25a21a75a42a61a73a59a23a19a66a38a71a70a6a55a3a16a43a32a53a37a41a28a49a63a47a17a7a30a78a46a20a67a56a79a65a14a69a60a8a52a22a9a24a2a4a13a36a27a0a18a33a12a44a5a76a26a29a40a1a11a64a48a39a51a80a72a68a10a58a35a77a54a34a74a57a31a50a45a15' + dict.values['a67e15ed870fe4aab0a502478a5c720f'] = '8a12a59a52a24a13a37a21a55a56a41a71a65a43a40a66a11a79a67a44a33a20a72a2a31a42a29a34a58a60a27a48a28a15a35a51a76a80a0a63a69a53a39a46a64a50a75a1a57a9a62a74a18a16a73a14a17a6a19a61a23a38a10a3a32a26a36a54a4a30a45a47a70a22a7a68a49a77a5a25a78' + dict.values['b6a2f75185754b691e4dfe50f84db57c'] = '47a63a76a58a37a4a56a21a1a48a62a2a36a44a34a42a23a9a60a72a11a74a70a20a77a16a15a35a69a0a55a46a24a6a32a75a68a43a41a78a31a71a52a33a67a25a80a30a5a28a40a65a39a14a29a64a3a53a49a59a12a66a38a27a79a45a18a22a8a61a50a17a51a10a26a13a57a19a7a54a73' + dict.values['db99689c5a26a09d126c7089aedc0d86'] = '57a31a46a61a55a41a26a2a39a24a75a4a45a13a23a51a15a8a64a37a72a34a12a3a79a42a80a17a62a49a19a77a48a68a78a65a14a10a29a16a20a76a38a36a54a30a53a40a33a21a44a22a32a5a1a7a70a67a58a0a71a74a43a66a6a63a35a56a73a9a27a25a59a47a52a11a50a18a28a60a69' + dict.values['d320d2647d70c068b89853e1a269c609'] = '77a38a53a40a16a3a20a18a63a9a24a64a50a61a45a59a27a37a8a34a11a55a79a13a47a68a12a22a46a33a1a69a52a54a31a23a62a43a0a2a35a28a57a36a51a78a70a5a32a75a41a30a4a80a19a21a42a71a49a10a56a74a17a7a25a6a14a73a29a44a48a39a60a58a15a66a67a72a65a76a26' + dict.values['c587e77362502aaedad5b7cddfbe3a0d'] = '50aa59a70a68a30a56a10a49a43a45a29a23a28a61a15a40a71a14a44a32a34a17a26a63a76a75a33a74a12a11a21a67a31a19a80a7a64a8a3a51a53a38a18a6a42a27a9a52a20a41a60a1a22a77a16a54a47a79a24a78a2a46a37a73a65a36a35a39a5a4a25a72a13a62a55a57a58a69a66a48' + dict.values['f4ab0903149b5d94baba796a5cf05938'] = '40a37a55a73a18a42a15a59a50a13a22a63a52a58a6a80a47a17a38a71a74a70a30a11a10a19a0a31a36a21a51a68a1a3a14a66a45a2a79a7a76a75a8a67a20a78a25a69a43a28a35a60a4a23a65a54a34a9a5a39a27a57a26a33a12a24a46a72a56a44a49a61a64a29a53a48a32a62a41a16a77' + dict.values['f5baf770212313f5e9532ec5e6103b61'] = '55a69a78a75a38a25a20a60a6a80a46a5a48a18a23a24a17a67a64a70a63a57a22a10a49a19a8a16a11a12a61a76a34a27a54a73a44a0a56a3a15a29a28a13a4a2a7a77a74a35a37a26a30a58a9a71a50a1a43a79a47a32a14a53a52a66a72a59a68a31a42a45a62a51a40a39a33a65a41a36a21' + dict.values['e2169a4bfd805e9aa21d3112d498d68c'] = '54a34a68a69a26a20a66a1a67a74a22a39a63a70a5a37a75a15a6a14a62a50a46a35a44a45a28a8a40a25a29a76a51a77a17a47a0a42a2a9a48a27a13a64a58a57a18a30a80a23a61a36a60a59a71a32a7a38a41a78a12a49a43a79a24a31a52a19a3a53a72a10a73a11a33a16a4a55a65a21a56' + m.storage['ik'] = '18a72a69a64a13a1a43a3aa42a23a66a26a19a51a54a78a34a17a31a35a15a58a29a61a48a73a74a44a52a60a24a63a20a32a7a45a53a75a55a62a59a41a76a68a2a36a21a10a38a33a71a40a67a22a4a50a80a65a27a37a47a70a14a28a16a6a56a30a57a5a11a79a9a77a46a39a25a49a8a12' + m.storage['dict'] = dict.text + m.storage['loaded'] = '0' +end + +function filldict(script) + local dict = TStrings.create() + dict.text = module.storage['dict'] + local dkvar = 'deskeys' + local function fill(p) + for k, v in script:gmatch(p) do + if (k ~= nil) and (v ~= nil) then dict.values[k] = v; end + end + end + fill(dkvar..'%s*%[%s*[\'"]([^"\']+)[\'"]%s*%]%s*=%s*["\']([^"\']+)["\']') + fill(dkvar..'%s*%.%s*([^"\']+)%s*=%s*["\']([^"\']+)["\']') + module.storage['dict'] = dict.text + local ik = module.storage['ik'] + local s = script:match('[%s;,][fg]%s*=%s*["\']([^\'"]+)["\']') + if s ~= nil then ik = s; end + module.storage['ik'] = ik + module.storage['loaded'] = '1' +end + +function downloadimage() + if http.get(url) then + if Pos('mangapicgallery.com/r/cspiclink', url:lower()) > 0 then + local ik = module.storage['ik'] + local dict = TStrings.create() + dict.text = module.storage['dict'] + for i = 0,dict.count-1 do + local t = js.splitstr(dict.get(i), dict.NameValueSeparator) + if Pos(t[1], url) > 0 then ik = t[2]; break; end + end + local a = js.splitstr(ik, 'a') + local s = TImagePuzzle.Create(9, 9) + for i = 1, #a do + local n = tonumber(a[i]) + if n == nil then n = 0 end + s.matrix[i-1] = n; + end + s.descramble(http.document, http.document) + end + else + return false + end + return true +end + +function getnameandlink() + local ref = module.rooturl + local s = module.rooturl + s = s .. mgdirurl .. IncStr(url) .. '/' + if url ~= '0' then ref = ref .. mgdirurl .. url .. '/'; end + http.headers.values['Referer'] = ref + if http.get(s) then + local x = TXQuery.Create(http.Document) + x.XPathHREFtitleAll('//div[@class="directory_left"]//li/h3/a', links, names) + return no_error + else + return net_problem + end +end + +function r_getnameandlink() + local ref = module.rooturl + local s = module.rooturl + s = s .. rdirurl .. IncStr(url) + if url ~= '0' then ref = ref .. rdirurl .. url; end + http.headers.values['Referer'] = ref + if http.get(s) then + local x = TXQuery.Create(http.Document) + x.XPathHREFtitleAll('//div[@id="sa-comic_show_list"]/ul/li/p/a[not(@class)]', links, names) + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(name, url) + local m = NewModule() + filldef(m) + m.website = name + m.rooturl = url + m.category = 'English' + m.lastupdated='March 2, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber = 'getpagenumber' + m.ongetnameandlink = 'getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' + m.onbeforedownloadimage = 'beforedownloadimage' + m.ondownloadimage = 'downloadimage' + if name == 'Rocaca' then + m.ongetinfo = 'r_getinfo' + m.ongetnameandlink = 'r_getnameandlink' + m.ongetdirectorypagenumber = 'r_getdirectorypagenumber' + end + return m +end + +function Init() + AddWebsiteModule('MangaGo', 'http://www.mangago.me') + AddWebsiteModule('Rocaca', 'http://www.rocaca.com') +end From ac0c85bd28cfd392bb978736959299e1d739013f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 15:55:08 +0300 Subject: [PATCH 2532/2794] MangaTail, change domain --- baseunits/modules/MangaTail.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaTail.pas b/baseunits/modules/MangaTail.pas index 1f53af29e..45187e2d9 100644 --- a/baseunits/modules/MangaTail.pas +++ b/baseunits/modules/MangaTail.pas @@ -124,7 +124,7 @@ procedure RegisterModule; end; begin - AddWebsiteModule('MangaTail', 'http://www.mangatail.com'); + AddWebsiteModule('MangaTail', 'https://www.mangatail.me'); AddWebsiteModule('MangaSail', 'http://www.mangasail.com'); end; From 6b701bb4c4fa8f931af9fb5b681675465e0a6fa8 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 16:00:08 +0300 Subject: [PATCH 2533/2794] MangaBackup, remove (doesn't work) --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaBackup.pas | 145 ------------------------------ 2 files changed, 146 deletions(-) delete mode 100644 baseunits/modules/MangaBackup.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index f161b56c4..8f13a1081 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -20,7 +20,6 @@ uses Webtoons, Tsumino, SubManga, - MangaBackup, Tumangaonline, MangaEden, HeyMangaXyz, diff --git a/baseunits/modules/MangaBackup.pas b/baseunits/modules/MangaBackup.pas deleted file mode 100644 index 2782a4311..000000000 --- a/baseunits/modules/MangaBackup.pas +++ /dev/null @@ -1,145 +0,0 @@ -unit MangaBackup; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr; - -implementation - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/genre/?add') then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := XPath('(//select)[1]/option').Count; - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL; - if AURL = '0' then - s := s + '/genre/?add' - else - s := s + '/genre/' + IncStr(AURL) + '?add'; - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="ls1"]/div//h3/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('text()', v.toNode)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//div[@class="cover"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h1/a'); - authors := XPathString('//table[@class="attr"]/tbody/tr[5]/td'); - artists := XPathString('//table[@class="attr"]/tbody/tr[6]/td'); - genres := ''; - for v in XPath('//table[@class="attr"]/tbody/tr[7]/td/a') do - AddCommaString(genres, v.toString); - summary := XPathString('//p[@class="summary"]'); - s := XPathString('//table[@class="attr"]/tbody/tr[9]/td'); - if s <> '' then begin - s := LowerCase(s); - if Pos('ongoing', s) > 0 then - status := '1' - else if Pos('completed', s) > 0 then - status := '0'; - end; - for v in XPath('//ul[@class="chapter"]/li/span/a') do begin - s := v.toNode.getAttribute('href'); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - chapterLinks.Add(s); - chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//section[@id="viewer"]/div[@class="canvas"]/a[@class="img-link"]/img') do - PageLinks.Add(v.toNode.getAttribute('src')); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaBackup'; - RootURL := 'http://mangabackup.com'; - Category := 'English'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 2507e8d23957bcc8c65a273153fd71dadf5bf1c9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 16:48:05 +0300 Subject: [PATCH 2534/2794] Tapas, fix update list #1171 --- baseunits/modules/Tapas.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Tapas.pas b/baseunits/modules/Tapas.pas index cb9481d4d..c6d80935c 100644 --- a/baseunits/modules/Tapas.pas +++ b/baseunits/modules/Tapas.pas @@ -48,7 +48,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for v in XPath('//ul[@class="content-list-wrap"]//li//a[@class="preferred title"]') do begin + for v in XPath('//ul[contains(@class,"content-list-wrap")]//li//a[@class="preferred title"]') do begin ALinks.Add(v.toNode.getAttribute('href')); ANames.Add(v.toString); end; From 43de51ecfab77252d0fb1559a85b4f4b866f1ff9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 8 Apr 2018 19:23:48 +0300 Subject: [PATCH 2535/2794] fix typo --- lua/modules/HeavenManga.lua | 2 +- lua/modules/UnionMangas.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index 8c9a79c7c..b6f405c67 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -48,7 +48,7 @@ function getdirectorypagenumber() if http.GET(module.RootURL .. '/manga-list/') then local x = TXQuery.Create(http.Document) page = tonumber(x.xpathstring('(//div[@class="pagination"]/a[contains(@class, "page-numbers")])[last()]/substring-after(@href, "/page-")')) - if page == nil then pages = 1 end + if page == nil then page = 1 end return no_error else return net_problem diff --git a/lua/modules/UnionMangas.lua b/lua/modules/UnionMangas.lua index 8f8fe6a72..9eb5ae266 100644 --- a/lua/modules/UnionMangas.lua +++ b/lua/modules/UnionMangas.lua @@ -50,7 +50,7 @@ function getdirectorypagenumber() if http.GET(module.RootURL .. dirurl) then local x = TXQuery.Create(http.Document) page = tonumber(x.xpathstring('//ul[@class="pagination"]/li[last()]/a/substring-before(substring-after(@href,"a-z/"),"/")')) - if page == nil then pages = 1 end + if page == nil then page = 1 end return no_error else return net_problem From 146dba3baf74e4a1ce42b00fc94045c19be42bfa Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 07:02:44 +0300 Subject: [PATCH 2536/2794] TrashScanlations, fix --- lua/modules/rawdevart.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 86b47779a..181ab2ff2 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -65,6 +65,6 @@ function Init() AddWebsiteModule('Rawdevart', 'https://rawdevart.com', cat) cat = 'English-Scanlation' - AddWebsiteModule('TrashScanlations', 'http://trashscanlations.com', cat) + AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) AddWebsiteModule('ZeroScans', 'https://zeroscans.com', cat) end From f8165ae4fa22be0db650f2443c71bbe8a60d942d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 09:38:28 +0300 Subject: [PATCH 2537/2794] fix MaxConnectionLimit bug --- baseunits/uDownloadsManager.pas | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 161cda3bb..1b833b35b 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -702,7 +702,7 @@ procedure TTaskThread.SyncShowBallonHint; procedure TTaskThread.CheckOut; var - currentMaxThread: Integer; + currentMaxThread, currentMaxConnections: Integer; s: String; begin if Terminated then Exit; @@ -732,16 +732,20 @@ procedure TTaskThread.CheckOut; end; if Modules.MaxConnectionLimit[Container.ModuleId] > 0 then - while (not Terminated) and (Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxThread) do + while (not Terminated) and (not Modules.CanCreateConnection(Container.ModuleId)) do Sleep(SOCKHEARTBEATRATE) else while (not Terminated) and (Threads.Count >= currentMaxThread) do Sleep(SOCKHEARTBEATRATE); + currentMaxConnections := Modules.MaxConnectionLimit[Container.ModuleId]; + if currentMaxConnections <= 0 then + currentMaxConnections := currentMaxThread; + if (not Terminated) and (Threads.Count < currentMaxThread) then try EnterCriticalsection(FCS_THREADS); - if Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxThread then Exit; + if Modules.ActiveConnectionCount[Container.ModuleId] >= currentMaxConnections then Exit; Modules.IncActiveConnectionCount(Container.ModuleId); Threads.Add(TDownloadThread.Create); with TDownloadThread(Threads.Last) do begin From 487a8fac181e12e43c4074dd84bb41ea2e1428d4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 09:52:34 +0300 Subject: [PATCH 2538/2794] Lhscans, move to lua fixes #1174 --- baseunits/ModuleList.inc | 1 - baseunits/modules/Lhscans.pas | 96 ----------------------------------- lua/modules/Lhscans.lua | 57 +++++++++++++++++++++ 3 files changed, 57 insertions(+), 97 deletions(-) delete mode 100644 baseunits/modules/Lhscans.pas create mode 100644 lua/modules/Lhscans.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 8f13a1081..dd72f4583 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -53,7 +53,6 @@ uses Mangaf, MangaRock, PsychoPlay, - Lhscans, MangaWindow, // Raw Official SundayWebEvery, diff --git a/baseunits/modules/Lhscans.pas b/baseunits/modules/Lhscans.pas deleted file mode 100644 index 8e13bd6c6..000000000 --- a/baseunits/modules/Lhscans.pas +++ /dev/null @@ -1,96 +0,0 @@ -unit Lhscans; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//img[@class="thumbnail"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := Trim(SeparateLeft(XPathString('//title'), '- Raw')); - authors := XPathString('//ul[@class="manga-info"]/li[contains(., "Author")]//a'); - genres := XPathStringAll('//ul[@class="manga-info"]/li[contains(., "Genre")]//a'); - status := MangaInfoStatusIfPos(XPathString('//ul[@class="manga-info"]/li[contains(., "Status")]//a')); - summary := XPathString('//h3[text()="Description"]/following-sibling::p'); - XPathHREFAll('//div[@id="tab-chapper"]//table/tbody/tr/td/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(RemoveURLDelim(FillHost(Module.RootURL, AURL))) then - begin - Result := True; - XPathStringAll('//img[@class="chapter-img"]/@src', Document, PageLinks); - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/manga-list.html?listType=allABC') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//span[@manga-slug]//a') do begin - ANames.Add(Trim(SeparateLeft(v.toString, '- Raw'))); - ALinks.Add(v.toNode.getAttribute('href')); - end; - finally - Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'Lhscans'; - RootURL := 'http://lhscans.com'; - Category := 'Raw'; - TotalDirectory := 1; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetNameAndLink := @GetNameAndLink; - end; -end; - -initialization - RegisterModule; - -end. - diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua new file mode 100644 index 000000000..5ecd41d2f --- /dev/null +++ b/lua/modules/Lhscans.lua @@ -0,0 +1,57 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = Trim(SeparateLeft(x.XPathString('//title'), '- Raw')) + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//img[@class="thumbnail"]/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info"]/li[contains(., "Status")]//a')) + mangainfo.authors=x.xpathstring('//ul[@class="manga-info"]/li[contains(., "Author")]//a') + mangainfo.genres=x.xpathstringall('//ul[@class="manga-info"]/li[contains(., "Genre")]//a') + mangainfo.summary=x.xpathstring('//h3[text()="Description"]/following-sibling::p') + x.xpathhrefall('//div[@id="tab-chapper"]//table/tbody/tr/td/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[@class="chapter-img"]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.RootURL .. '/manga-list.html?listType=allABC') then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//span[@manga-slug]//a') + for i = 1, v.count do + local v1 = v.get(i) + names.Add(Trim(SeparateLeft(v1.toString, '- Raw'))); + links.Add(v1.getAttribute('href')); + end + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='Raw' + m.website='Lhscans' + m.rooturl='http://rawlh.com' + m.lastupdated='April 9, 2018' + m.totaldirectory=1 + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 698ea98e715fc6a773d1a7961b439b54d9395724 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 16:52:12 +0300 Subject: [PATCH 2539/2794] ehentai, fix crash on login fixes #1090 --- baseunits/modules/EHentai.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/EHentai.pas b/baseunits/modules/EHentai.pas index 716509410..22009ee09 100644 --- a/baseunits/modules/EHentai.pas +++ b/baseunits/modules/EHentai.pas @@ -85,7 +85,7 @@ function GETWithLogin(const AHTTP: THTTPSendThread; const AURL: String; const Mo ACookies: String; begin Result := False; - if Module.Account.Enabled then begin + if Assigned(Module.Account) and Module.Account.Enabled then begin AHTTP.FollowRedirection := False; // force no warning AHTTP.Cookies.Values['nw'] := '1'; From 3159ee389452711b6b388887ccc5254d4262490d Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Tue, 10 Apr 2018 02:24:56 -0500 Subject: [PATCH 2540/2794] add scan GodsRealmScan --- lua/modules/myReaderMangaCMS.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 5ad6f5dec..ee2835a31 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -3,6 +3,9 @@ function GetNameAndLink() if module.Website == 'WhiteCloudPavilion' then u = u .. '/manga/free' end + if module.Website == 'GodsRealmScan' then + u = u .. '/public/' + end u = u .. '/changeMangaList?type=text' if http.GET(u) then x = TXQuery.Create(http.Document) @@ -97,6 +100,7 @@ function Init() c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); + AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com/', c); c='Italian-Scanlation' From 0d0249c82af17119f18d62144d998e810aa3b830 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 10 Apr 2018 10:33:31 +0300 Subject: [PATCH 2541/2794] MangaDex, fix group and lang display fixes #1177 --- lua/modules/MangaDex.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index d210ccb60..3a9ab0711 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -13,13 +13,13 @@ function getinfo() local l='//table//tr[@id and not(starts-with(./td/time, "in "))]' local n='' if module.getoption('luashowalllang') then - n='/concat(.," [",../td[3]/img/@title,"]"' + n='/concat(.," [",../td[4]/img/@title,"]"' else l=l..'[./td/img[@title="English"]]' end if module.getoption('luashowscangroup') then if n=='' then n='/concat(.' end - n=n..'," [",../td[4],"]"' + n=n..'," [",../td[5],"]"' end l=l..'/td[2]' if n~='' then n=n..')' end From dea0b74e13dc2124bd3ff6b1a2e4ef498783cb5b Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 10 Apr 2018 10:54:25 +0300 Subject: [PATCH 2542/2794] MangaHere, limit connections --- baseunits/modules/MangaHere.pas | 2 ++ 1 file changed, 2 insertions(+) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 676329a6f..e1d941816 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -141,6 +141,8 @@ procedure RegisterModule; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; OnGetImageURL := @GetImageURL; + MaxConnectionLimit := 1; + MaxTaskLimit := 1; end; end; From 351617df135c0e9da4cfbbc4475569f662fc0fac Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 10 Apr 2018 20:55:22 +0300 Subject: [PATCH 2543/2794] fix duplicates in websites list --- mangadownloader/forms/frmWebsiteSettings.pas | 24 +++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/mangadownloader/forms/frmWebsiteSettings.pas b/mangadownloader/forms/frmWebsiteSettings.pas index 46ff8734c..8be8ee0b7 100644 --- a/mangadownloader/forms/frmWebsiteSettings.pas +++ b/mangadownloader/forms/frmWebsiteSettings.pas @@ -110,13 +110,25 @@ procedure TWebsiteSettingsForm.vtWebsiteGetText(Sender: TBaseVirtualTree; procedure TWebsiteSettingsForm.LoadWebsiteSettings; var i: Integer; + items: TStringList; begin - vtWebsite.NodeDataSize := SizeOf(TModuleContainer); - vtWebsite.BeginUpdate; - for i := 0 to Modules.Count - 1 do - vtWebsite.AddChild(nil, Modules[i]); - vtWebsite.Sort(nil, 0, sdAscending, False); - vtWebsite.EndUpdate; + items := TStringList.Create; + try + items.OwnsObjects := False; + items.Duplicates := dupIgnore; + for i := Modules.Count - 1 downto 0 do + if items.IndexOf(Modules[i].Website) = -1 then + items.AddObject(Modules[i].Website, Modules[i]); + + vtWebsite.NodeDataSize := SizeOf(TModuleContainer); + vtWebsite.BeginUpdate; + for i := 0 to items.Count - 1 do + vtWebsite.AddChild(nil, items.Objects[i]); + vtWebsite.Sort(nil, 0, sdAscending, False); + vtWebsite.EndUpdate; + finally + items.Free; + end; end; From 4387d814af5b00b5711ca3af9c48f77efbb1b97c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 10 Apr 2018 20:56:03 +0300 Subject: [PATCH 2544/2794] MyReadingManga, move to lua fixes #1180 --- baseunits/ModuleList.inc | 3 +- baseunits/modules/MyReadingManga.pas | 107 --------------------------- lua/modules/MyReadingManga.lua | 79 ++++++++++++++++++++ 3 files changed, 80 insertions(+), 109 deletions(-) delete mode 100644 baseunits/modules/MyReadingManga.pas create mode 100644 lua/modules/MyReadingManga.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index dd72f4583..09b4c8a6a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -70,5 +70,4 @@ uses HitomiLa, HentaiCafe, Hentai2Read, - HentaiFox, - MyReadingManga; + HentaiFox; diff --git a/baseunits/modules/MyReadingManga.pas b/baseunits/modules/MyReadingManga.pas deleted file mode 100644 index 311a344c2..000000000 --- a/baseunits/modules/MyReadingManga.pas +++ /dev/null @@ -1,107 +0,0 @@ -unit MyReadingManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; - -implementation - -uses httpsendthread; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL) then begin - Result := NO_ERROR; - Page := StrToIntDef(XPathString('//*[contains(@class,"archive-pagination")]/ul/li[last()-1]', MangaInfo.FHTTP.Document), 1); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/page/' + IncStr(AURL) + '/') then - begin - Result := NO_ERROR; - XPathHREFAll('//h2[@class="entry-title"]/a', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do try - title := XPathString('//*[contains(@class,"entry-content")]/h2'); - if title = '' then title := Trim(XPathString('//*[contains(@class,"entry-content")]/p[starts-with(.,"Title")]/substring-after(.,":")')); - if title = '' then title := XPathString('//*[contains(@class,"entry-content")]/p[1]/strong'); - if title = '' then title := XPathString('//h1[@class="entry-title"]'); - genres := XPathString('//header[@class="entry-header"]/string-join(./p[position()>1]//a,", ")'); - authors := Trim(XPathString('//*[contains(@class,"entry-content")]/p[starts-with(.,"Author")]/substring-after(.,":")')); - chapterLinks.Add(url); - chapterName.Add(title); - for v in XPath('//*[contains(@class,"entry-pagination")]/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(title + ' - ' + v.toString); - end; - if chapterName.Count > 1 then - chapterName[0] := chapterName[0] + ' - 1'; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - XPathStringAll('//*[contains(@class,"entry-content")]//div//img/@src', Document, PageLinks); - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MyReadingManga'; - RootURL := 'https://myreadingmanga.info'; - Category := 'H-Sites'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/MyReadingManga.lua b/lua/modules/MyReadingManga.lua new file mode 100644 index 000000000..f7e4b4eb1 --- /dev/null +++ b/lua/modules/MyReadingManga.lua @@ -0,0 +1,79 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//*[contains(@class,"entry-content")]/h2') + if mangainfo.title == '' then + mangainfo.title = Trim(x.XPathString('//*[contains(@class,"entry-content")]/p[starts-with(.,"Title")]/substring-after(.,":")')) + end + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//*[contains(@class,"entry-content")]/p[1]/strong') + end + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//h1[@class="entry-title"]') + end + mangainfo.authors=Trim(x.xpathstring('//*[contains(@class,"entry-content")]/p[starts-with(.,"Author")]/substring-after(.,":")')) + mangainfo.genres=x.xpathstring('//header[@class="entry-header"]/string-join(./p[position()>1]//a,", ")') + mangainfo.chapterlinks.add(mangainfo.url) + mangainfo.chapternames.add(mangainfo.title) + local v = x.xpath('//*[contains(@class,"entry-pagination")]/a') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('href')); + mangainfo.chapternames.add(mangainfo.title .. ' - ' .. v1.toString); + end + if mangainfo.chapternames.count > 1 then + mangainfo.chapternames[0] = mangainfo.chapternames[0] .. ' - 1' + end + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//*[contains(@class,"entry-content")]//div//img/@src', task.pagelinks) + if task.pagelinks.count == 0 then + x.xpathstringall('//div[@class="separator" and @style]//img/@src', task.pagelinks) + end + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('//*[contains(@class,"archive-pagination")]/ul/li[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl .. '/page/' .. IncStr(AURL) .. '/') then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//h2[@class="entry-title"]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'MyReadingManga' + m.rooturl = 'https://myreadingmanga.info' + m.category = 'H-Sites' + m.lastupdated='April 10, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end From 875cd784991c2c0e843eafb30a9282e22e6748cc Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 11 Apr 2018 06:57:02 +0300 Subject: [PATCH 2545/2794] ignore if waiting.gif is not accessible fixes #1154 --- mangadownloader/forms/frmMain.pas | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 74a6f21f0..5dde3b713 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1182,15 +1182,16 @@ procedure TMainForm.FormCreate(Sender: TObject); // waiting gif if FileExistsUTF8(IMAGE_FOLDER + 'waiting.gif') then - begin - gifWaiting := TAnimatedGif.Create(IMAGE_FOLDER + 'waiting.gif'); - gifWaiting.EraseColor := Self.Color; - gifWaiting.BackgroundMode := gbmSaveBackgroundOnce; - gifWaitingRect.Left := 53; - gifWaitingRect.Top := 84; - gifWaitingRect.Right := 101; - gifWaitingRect.Bottom := 131; - end; + try + gifWaiting := TAnimatedGif.Create(IMAGE_FOLDER + 'waiting.gif'); + gifWaiting.EraseColor := Self.Color; + gifWaiting.BackgroundMode := gbmSaveBackgroundOnce; + gifWaitingRect.Left := 53; + gifWaitingRect.Top := 84; + gifWaitingRect.Right := 101; + gifWaitingRect.Bottom := 131; + except + end; mangaCover := TPicture.Create; From db7adfc7ba341396e3ab16f59355b0bf222b8b98 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 10:50:15 +0300 Subject: [PATCH 2546/2794] add MangaAll, MangaTrue [RAW] --- lua/modules/MangaAll.lua | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 lua/modules/MangaAll.lua diff --git a/lua/modules/MangaAll.lua b/lua/modules/MangaAll.lua new file mode 100644 index 000000000..d98744866 --- /dev/null +++ b/lua/modules/MangaAll.lua @@ -0,0 +1,75 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = Trim(x.XPathString('//div[@class="post-title"]/h3')) + if string.match(mangainfo.title:upper(), ' RAW$') ~= nil then + mangainfo.title = mangainfo.title:sub(1, -5) + end + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//div[@class="summary_image"]/a/img/@data-src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(div[@class="summary-heading"]/h5, "Status")]/div[@class="summary-content"]')) + mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') + mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') + mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') + mangainfo.summary=x.xpathstring('//div[@class="description-summary"]/div/p') + x.xpathhrefall('//div[contains(@class, "listing-chapters")]/ul/li/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[contains(@class, "wp-manga-chapter-img")]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.RootURL .. '/manga/page/' .. IncStr(url) .. '/?m_orderby=alphabet') then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//div[@class="page-item-detail"]/div/a') + for i = 1, v.count do + local v1 = v.get(i) + local s = v1.getAttribute('title') + if string.match(s:upper(), ' RAW$') ~= nil then + s = s:sub(1, -5) + end + names.add(s) + links.add(v1.getAttribute('href')) + end + local p = x.xpathstring('//div[contains(@class, "nav-previous")]/a/@href') + p = tonumber(p:match('page/(%d+)/')) + if p ~= nil then + updatelist.CurrentDirectoryPageNumber = p; + end + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(name, url) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = 'Raw' + m.lastupdated = 'April 9, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + return m +end + +function Init() + AddWebsiteModule('MangaAll', 'http://mangaall.com') + AddWebsiteModule('MangaTrue', 'http://mangatrue.com') +end From 2f6523c471e5b8ff92b4c81b0e91e49c0dd2cfde Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 12:30:21 +0300 Subject: [PATCH 2547/2794] add MangaHereFun [EN] --- lua/modules/MangaHubIO.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/modules/MangaHubIO.lua b/lua/modules/MangaHubIO.lua index 92734bce1..c77ce692c 100644 --- a/lua/modules/MangaHubIO.lua +++ b/lua/modules/MangaHubIO.lua @@ -9,6 +9,8 @@ function getx() return "mf01" elseif module.website == 'MangaKakalotFun' then return "mn01" + elseif module.website == 'MangaHereFun' then + return "mh01" else return "m01" end @@ -103,4 +105,5 @@ function Init() AddWebsiteModule('MangaReaderSite', 'https://mangareader.site') AddWebsiteModule('MangaFoxFun', 'https://mangafox.fun') AddWebsiteModule('MangaKakalotFun', 'https://mangakakalot.fun') + AddWebsiteModule('MangaHereFun', 'https://mangahere.onl') end From ce06ede7bac47eb4cf578fb552eaf1a6752a6795 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 9 Apr 2018 14:59:20 +0300 Subject: [PATCH 2548/2794] add MangaFreak [EN] --- lua/modules/MangaFreak.lua | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 lua/modules/MangaFreak.lua diff --git a/lua/modules/MangaFreak.lua b/lua/modules/MangaFreak.lua new file mode 100644 index 000000000..2910cf415 --- /dev/null +++ b/lua/modules/MangaFreak.lua @@ -0,0 +1,65 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//div[@class="manga_series_data"]/h5') + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//div[@class="manga_series_image"]/img/@src')) + --mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info"]/li[contains(., "Status")]//a')) + --mangainfo.authors=x.xpathstring('//ul[@class="manga-info"]/li[contains(., "Author")]//a') + mangainfo.genres=x.xpathstringall('//div[@class="series_sub_genre_list"]/a') + --mangainfo.summary=x.xpathstring('//h3[text()="Description"]/following-sibling::p') + x.xpathhrefall('//div[@class="manga_series_list"]/table/tbody/tr/td[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getimageurl() + local lurl=MaybeFillHost(module.rooturl,url) + if workid~=0 then lurl=lurl..'_'..workid+1 end + if http.get(lurl) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]=x.xpathstring('//div[@class="read_image"]//img/@src') + return true + else + return false + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + task.pagenumber = x.xpathcount('//div[@class="read_selector"]/select/option') + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.RootURL .. '/Mangalist') then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//div[@class="manga_list"]/div/div[@class="manga_item"]/div/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='English' + m.website='MangaFreak' + m.rooturl='http://www.mangafreak.net' + m.lastupdated='April 9, 2018' + m.totaldirectory=1 + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetimageurl='getimageurl' +end From 1b9b0e83e08a2f8464e0d623ef4766b38b235b07 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 10 Apr 2018 11:12:50 +0300 Subject: [PATCH 2549/2794] add IlluminatiManga [en-sc] --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index c91c214b8..1ab2ba9b3 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -275,6 +275,7 @@ function Init() AddWebsiteModule('TwistedHelScans', 'http://www.twistedhelscans.com', cat) AddWebsiteModule('TapTrans', 'https://taptaptaptaptap.net', cat) AddWebsiteModule('EvilFlowers', 'http://reader.evilflowers.com', cat) + AddWebsiteModule('IlluminatiManga', 'http://reader.manga-download.org', cat) cat = 'Italian-Scanlation' AddWebsiteModule('DigitalTeam', 'http://digitalteamreader.netsons.org', cat) From a8015d1b34eaebc6869d467c21d6684159a41b72 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 11 Apr 2018 10:36:41 +0300 Subject: [PATCH 2550/2794] MangaTail, move to lua fixes #1146 --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaTail.pas | 134 -------------------------------- lua/modules/MangaTail.lua | 104 +++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 135 deletions(-) delete mode 100644 baseunits/modules/MangaTail.pas create mode 100644 lua/modules/MangaTail.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 09b4c8a6a..d6cf5255f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -45,7 +45,6 @@ uses EatManga, Taadd, NineManga, - MangaTail, TruyenTranhTuan, BlogTruyen, MangaAe, diff --git a/baseunits/modules/MangaTail.pas b/baseunits/modules/MangaTail.pas deleted file mode 100644 index 45187e2d9..000000000 --- a/baseunits/modules/MangaTail.pas +++ /dev/null @@ -1,134 +0,0 @@ -unit MangaTail; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; - -implementation - -uses FMDVars; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - s: String; - v: IXQValue; - i, x: Integer; -begin - Result := NET_PROBLEM; - s := Module.RootURL + '/directory'; - if AURL <> '0' then - s += '?page=' + AURL; - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - i := 1; - for v in XPath('//ul[@class="pagination"]/li') do begin - x := StrToIntDef(v.toString, 1); - if x > i then i := x; - end; - updateList.CurrentDirectoryPageNumber := i - 1; - XPathHREFAll('//table[contains(@class,"directory_list")]//tr/td[1]/a', ALinks, ANames); - for i := 0 to ANames.Count - 1 do - begin - s := ANames[i]; - if RightStr(s, 6) = ' Manga' then - begin - SetLength(s, Length(s) - 6); - ANames[i] := s; - end; - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//*[@class="bookface"]/img/@src'); - if title = '' then begin - title := XPathString('//h1'); - if RightStr(title, 6) = ' Manga' then - SetLength(title, Length(title) - 6); - end; - status := MangaInfoStatusIfPos(XPathString('//*[contains(@class,"field-status")]')); - XPathHREFAll('//table[contains(@class,"chlist")]//tr/td[1]/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - s := XPathStringAll('//iframe[contains(.,"field-name")]/substring-after(substring-before(.,"""}}"),":en"":""")', LineEnding); - if s <> '' then begin - s := StringReplace(s, '\n', LineEnding, [rfReplaceAll]); - s := StringReplace(s, '\', '', [rfReplaceAll]); - ParseHTML(s); - coverLink := XPathString('//img/@src'); - authors := XPathString('//*[contains(@class,"author")]/*[@class="field-items"]/string-join(.//text(),", ")'); - artists := XPathString('//*[contains(@class,"artist")]/*[@class="field-items"]/string-join(.//text(),", ")'); - genres := XPathString('//*[contains(@class,"genres")]/*[@class="field-items"]/string-join(.//text(),", ")'); - summary := XPathString('//*[contains(@class,"summary")]/*[@class="field-items"]//text()'); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL + '?page=all')) then - begin - Result := True; - XPathStringAll('//*[@id="images"]//img[not(contains(@src,"adsense"))]/@src', Document, PageLinks); - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; - begin - Result := AddModule; - with Result do - begin - Website := AWebsite; - RootURL := ARootURL; - Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; - end; - -begin - AddWebsiteModule('MangaTail', 'https://www.mangatail.me'); - AddWebsiteModule('MangaSail', 'http://www.mangasail.com'); -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/MangaTail.lua b/lua/modules/MangaTail.lua new file mode 100644 index 000000000..5855f4c6e --- /dev/null +++ b/lua/modules/MangaTail.lua @@ -0,0 +1,104 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + http.cookies.values['has_js'] = '1' + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = string.gsub(x.xpathstring('//h1[@class="page-header"]'), ' Manga$', '') + end + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//*[contains(@class,"field-status")]')) + x.xpathhrefall('//table[contains(@class,"chlist")]//tr/td[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + + local s = x.xpathstring('//script[contains(., "jQuery.extend(Drupal")]') + s = GetBetween('settings,', ');', s) + x.parsehtml(s) + local v = x.xpath('json(*)/authcacheP13nAjaxAssemblies') + local summaryQuery = x.xpathstring('./span.authcache-p13n-asm-field-node-body', v) + local artistQuery = x.xpathstring('./span.authcache-p13n-asm-field-node-field-artist', v) + local authorQuery = x.xpathstring('./span.authcache-p13n-asm-field-node-field-author', v) + local genresQuery = x.xpathstring('./span.authcache-p13n-asm-field-node-field-genres', v) + local coverQuery = x.xpathstring('./span.authcache-p13n-asm-field-node-field-image2', v) + local statusQuery = x.xpathstring('./span.authcache-p13n-asm-field-node-field-status', v) + + function getField(aurl, query) + if aurl ~= '' then + http.reset() + http.headers.values['X-Authcache'] = '1' + if http.xhr(module.rooturl .. aurl) then + local s = GetBetween(':"', '"}', StreamToString(http.document)) + x.parsehtml(s:gsub('\\"', '"'):gsub('\\/', '/')) + return x.xpathstring(query) + end + end + return '' + end + + mangainfo.summary = getField(summaryQuery, '*') + mangainfo.authors = getField(authorQuery, '//div[contains(@class, "field-item")]') + mangainfo.artists = getField(artistQuery, '//div[contains(@class, "field-item")]') + mangainfo.coverlink = getField(coverQuery, '//img/@src') + mangainfo.genres = getField(genresQuery, 'string-join(//a, ", ")') + + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url .. '?page=all')) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//*[@id="images"]//img[not(contains(@src,"adsense"))]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + local s = module.rooturl .. '/directory' + if url ~= '0' then s = s .. '?page=' .. url; end + if http.get(s) then + local x = TXQuery.Create(http.Document) + local i = 1 + local v = x.xpath('//ul[@class="pagination"]/li') + for j = 1, v.count do + local v1 = v.get(j) + local x = tonumber(v1.toString) + if (x ~= nil) and (x > i) then i = x; end + end + updatelist.CurrentDirectoryPageNumber = i - 1 + v = x.xpath('//table[contains(@class,"directory_list")]//tr/td[1]/a') + for j = 1, v.count do + local v1 = v.get(j) + local s = v1.toString + if string.match(s:upper(), ' MANGA$') ~= nil then + s = s:sub(1, -7) + end + links.add(v1.getAttribute('href')) + names.add(s) + end + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(site, url) + local m=NewModule() + m.category='English' + m.website=site + m.rooturl=url + m.lastupdated='April 5, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + return m +end + +function Init() + AddWebsiteModule('MangaTail', 'https://www.mangatail.me') + AddWebsiteModule('MangaSail', 'http://www.mangasail.com') +end \ No newline at end of file From ef829172d11fd004effa649793a754a806174fe4 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 11 Apr 2018 19:25:19 +0300 Subject: [PATCH 2551/2794] cleanup --- lua/modules/acqqcom.lua | 44 +---------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/lua/modules/acqqcom.lua b/lua/modules/acqqcom.lua index fb61e18ea..1c96ab603 100644 --- a/lua/modules/acqqcom.lua +++ b/lua/modules/acqqcom.lua @@ -13,54 +13,12 @@ end end -function decode1(str) - local _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" - str = str:gsub('[^A-Za-z0-9%+/=]', '') - local a = '' - local b, d, h, f, g, e = 0, 0, 0, 0, 0, 0 - while e < str:len() do - e = e + 1; b = string.find(_keyStr, str:sub(e, e)); if b == nil then b = -1 else b = b - 1 end; - e = e + 1; d = string.find(_keyStr, str:sub(e, e)); if d == nil then d = -1 else d = d - 1 end; - e = e + 1; f = string.find(_keyStr, str:sub(e, e)); if f == nil then f = -1 else f = f - 1 end; - e = e + 1; g = string.find(_keyStr, str:sub(e, e)); if g == nil then g = -1 else g = g - 1 end; - b = b << 2 | d >> 4 - d = (d & 15) << 4 | f >> 2 - h = (f & 3) << 6 | g - a = a .. string.char(b) - if f ~= 64 then a = a .. string.char(d); end - if g ~= 64 then a = a .. string.char(h); end - end - function utf8_decode(c) - local a, b, d, c1, c2 = '', 0, 0, 0, 0 - while b < c:len() do - d = c:byte(b+1) - if 128 > d then - a = a .. string.char(d) - b = b + 1 - else - if (191 < d) and (224 > d) then - c2 = c:byte(b+2) - a = a .. string.char((d & 31) << 6 | c2 & 63) - b = b + 2 - else - c2 = c:byte(b+2) - c3 = c:byte(b+3) - a = a .. string.char((d & 15) << 12 | (c2 & 63) << 6 | c3 & 63) - b = b + 3 - end - end - end - return a - end - return utf8_decode(a) -end - function getpagenumber() if http.get(MaybeFillHost(module.rooturl,url)) then x=TXQuery.Create(http.Document) local s = x.xpathstring('//script[contains(., "var DATA")]') s = GetBetween("= '", "',", s) - s = decode1(s:sub(2)) + s = DecodeBase64(s:sub(2)) x.parsehtml(s) x.xpathstringall('json(*).picture().url', task.pagelinks) return true From 4ccb31f095c921bc66d476f1f90d9544ca3c1a39 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 13 Apr 2018 19:13:06 +0300 Subject: [PATCH 2552/2794] MangaDex, fix list update fixes #1183 --- lua/modules/MangaDex.lua | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 3a9ab0711..e5bf3a762 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -70,21 +70,27 @@ function taskstart() return true end -local dirurl='/titles/' -local ALPHA_LIST_UP = '~ABCDEFGHIJKLMNOPQRSTUVWXYZ' +local dirurl='/titles/2' + +function getdirectorypagenumber() + http.cookies.values['mangadex_h_toggle'] = '1' + http.cookies.values['mangadex_title_mode'] = '1' + if http.GET(module.RootURL .. dirurl) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('(//ul[@class="pagination"]/li/a)[last()]/@href'):match('/2/(%d+)')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + function getnameandlink() - local lurl=dirurl - lurl = lurl .. ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) - lurl = lurl .. '/' .. IncStr(url) http.cookies.values['mangadex_h_toggle'] = '1' - if http.GET(module.rooturl..lurl) then + http.cookies.values['mangadex_title_mode'] = '1' + if http.GET(module.rooturl .. dirurl .. '/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.document) x.xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) - local page = x.xpathstring('//ul[@class="pagination"]/li[last()]/a/@href') - page = page:match('/(%d+)/?$') - page = tonumber(page) - if page == nil then page = 1; end - updatelist.CurrentDirectoryPageNumber = page return no_error else return net_problem @@ -101,7 +107,7 @@ function Init() m.ontaskstart='taskstart' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' - m.totaldirectory = ALPHA_LIST_UP:len() + m.ongetdirectorypagenumber = 'getdirectorypagenumber' m.maxtasklimit=1 m.maxconnectionlimit=2 From 5d66a6672de61a16608bd812065e4439cf739d10 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 14 Apr 2018 08:54:19 +0300 Subject: [PATCH 2553/2794] uUpdateThread, fix connection limit --- baseunits/uUpdateThread.pas | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/baseunits/uUpdateThread.pas b/baseunits/uUpdateThread.pas index 735e24fc5..243c24d84 100644 --- a/baseunits/uUpdateThread.pas +++ b/baseunits/uUpdateThread.pas @@ -377,7 +377,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end; var - plimit: Integer; + plimit, conlimit: Integer; s: String; t: TUpdateListThread; begin @@ -394,6 +394,10 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; if numberOfThreads < 1 then numberOfThreads := 1; //default + conlimit := Module.GetMaxConnectionLimit; + if conlimit < 1 then + conlimit := numberOfThreads; + // Finish searching for new series if (cs = CS_DIRECTORY_PAGE) and (isFinishSearchingForNewManga) then @@ -404,7 +408,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; end; if Module.GetMaxConnectionLimit > 0 then - while (not Terminated) and (Module.ActiveConnectionCount >= numberOfThreads) do + while (not Terminated) and (Module.ActiveConnectionCount >= conlimit) do Sleep(SOCKHEARTBEATRATE) else while (not Terminated) and (Threads.Count >= numberOfThreads) do @@ -415,7 +419,7 @@ procedure TUpdateListManagerThread.GetInfo(const limit: Integer; begin EnterCriticalsection(CS_Threads); try - if Module.ActiveConnectionCount >= numberOfThreads then Exit; + if Module.ActiveConnectionCount >= conlimit then Exit; Module.IncActiveConnectionCount; t := TUpdateListThread.Create; Threads.Add(t); From 797d06d0309e9257db3fee735834d5b4579f2c37 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 14 Apr 2018 09:50:46 +0300 Subject: [PATCH 2554/2794] MangaHere, fix title --- baseunits/modules/MangaHere.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index e1d941816..4d64ca0f0 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -30,7 +30,7 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; for v in XPath('//a[@class="manga_info"]') do begin ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); + ANames.Add(v.toNode.getAttribute('rel')); end; finally Free; From 3490c8f49209436be4bcee5fd41e1235c1bc8d4f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 15 Apr 2018 07:54:45 +0300 Subject: [PATCH 2555/2794] Bump version 0.9.154.0 --- changelog.txt | 16 ++++++++++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 4c260bd98..de15c2ea6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,22 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.154.0 (15-04-2018) +[+] Added GodsRealmScan [SP-SC] +[+] Added IlluminatiManga [EN-SC] +[+] Added MangaFreak [EN] +[+] Added MangaHereFun [EN] +[+] Added MangaAll [RAW] +[+] Added MangaTrue [RAW] +[-] Removed MangaBackup +[*] MangaTail, changed domain +[*] MangaDex, fixed all +[*] Tapas, fixed manga list update +[*] MyReadingManga, fixed download +[*] MangaHere, fixed manga list update +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.153.0...0.9.154.0 + 0.9.153.0 (08-04-2018) [+] Added SoManga [PT] [+] Added ReadMangaEU [EN] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index b3a3d31f7..5360f30ff 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ <VersionInfo> <UseVersionInfo Value="True"/> <MinorVersionNr Value="9"/> - <RevisionNr Value="153"/> + <RevisionNr Value="154"/> <Attributes pvaPrivateBuild="True"/> <StringTable Comments="https://github.com/riderkick/FMD" FileDescription="Free Manga Downloader" LegalCopyright="©2015-2018" OriginalFilename="fmd.exe" ProductName="Free Manga Downloader" ProductVersion="$BuildMode()" PrivateBuild="riderkick"/> </VersionInfo> diff --git a/update b/update index d916687c9..5a6c6eeea 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.153.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.153.0/fmd_0.9.153.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.153.0/fmd_0.9.153.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.153.0/fmd_0.9.153.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.153.0/fmd_0.9.153.0_Win64.7z +VERSION=0.9.154.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.154.0/fmd_0.9.154.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.154.0/fmd_0.9.154.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0_Win64.7z From f43ab647eb356daa4454077a3308c79cf46f299c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 16 Apr 2018 10:17:59 +0300 Subject: [PATCH 2556/2794] AcademyVN, change domain --- baseunits/modules/AcademyVN.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/AcademyVN.pas b/baseunits/modules/AcademyVN.pas index 11a531eeb..61b80afb6 100644 --- a/baseunits/modules/AcademyVN.pas +++ b/baseunits/modules/AcademyVN.pas @@ -119,7 +119,7 @@ procedure RegisterModule; with AddModule do begin Website := 'AcademyVN'; - RootURL := 'http://truyen.academyvn.com'; + RootURL := 'http://hocvientruyentranh.com'; Category := 'Vietnamese'; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; From 7b405208cac8a0dbfc5af4fab85689282d741d4d Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 16 Apr 2018 10:23:30 +0300 Subject: [PATCH 2557/2794] Mangaf, change domain --- baseunits/modules/Mangaf.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/Mangaf.pas b/baseunits/modules/Mangaf.pas index 343d821a8..9540a4de0 100644 --- a/baseunits/modules/Mangaf.pas +++ b/baseunits/modules/Mangaf.pas @@ -105,7 +105,7 @@ procedure RegisterModule; with AddModule do begin Website := 'Mangaf'; - RootURL := 'http://mangaf.co'; + RootURL := 'https://mangaforall.com'; Category := 'Arabic'; TotalDirectory := 3; OnGetNameAndLink := @GetNameAndLink; From 3bbc1c6c6dd31cae83f0aa150be04513615e1721 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 16 Apr 2018 18:54:49 +0300 Subject: [PATCH 2558/2794] add InManga [sp] --- lua/modules/InManga.lua | 73 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lua/modules/InManga.lua diff --git a/lua/modules/InManga.lua b/lua/modules/InManga.lua new file mode 100644 index 000000000..74f22fd84 --- /dev/null +++ b/lua/modules/InManga.lua @@ -0,0 +1,73 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=x.xpathstring('//meta[@property="og:image"]/@content') + mangainfo.summary=x.xpathstring('//div/div[h1]/following-sibling::div[@class="panel-body"]') + local id = x.xpathstring('//input[@id="Identification"]/@value') + local base = x.xpathstring('//script[contains(., "var chapterUrl")]') + base = GetBetween("'", "'", base) + if http.get(module.RootURL .. '/chapter/getall?mangaIdentification=' .. id) then + x.parsehtml(http.document) + local root = x.xpath('json(json(*).data)') + local v = x.xpath('jn:members(result)', root) + local t = {} + for i = 1, v.count do + table.insert(t, tonumber(x.xpathstring('Number', v.get(i)))) + end + table.sort(t) + for _, k in ipairs(t) do + local chid = x.xpathstring('jn:members(result)[Number='..k..']/Identification', root) + local chnum = x.xpathstring('jn:members(result)[Number='..k..']/FriendlyChapterNumber', root) + mangainfo.chapterlinks.add(module.rooturl .. base:gsub('chapterNumber', chnum):gsub('identification', chid)) + mangainfo.chapternames.add('Capítulo: ' .. chnum) + end + end + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local v=x.xpath('//div[contains(@class,"PagesContainer")]/a/img/@id') + for i = 1, v.count do + local id = v.get(i).toString + task.pagelinks.add(MaybeFillHost(module.rooturl, '/page/getPageImage/?identification='..id)); + end + else + return false + end + return true +end + +function getnameandlink() + local data = 'filter%5Bgeneres%5D%5B%5D=-1&filter%5BqueryString%5D=&filter%5Bskip%5D=0&filter%5Btake%5D=10000&filter%5Bsortby%5D=5&filter%5BbroadcastStatus%5D=0' + if http.post(module.rooturl .. '/manga/getMangasConsultResult', data) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//a[contains(@class,"manga-result")]') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('.//h4', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'InManga' + m.rooturl = 'https://inmanga.com' + m.category = 'Spanish' + m.lastupdated='April 16, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 7a55eb8fcfe424442ab87a59f67f883688143722 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 13 Apr 2018 14:37:35 +0300 Subject: [PATCH 2559/2794] add IMangaScans [en-sc] --- lua/modules/IMangaScans.lua | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lua/modules/IMangaScans.lua diff --git a/lua/modules/IMangaScans.lua b/lua/modules/IMangaScans.lua new file mode 100644 index 000000000..f90ed14ff --- /dev/null +++ b/lua/modules/IMangaScans.lua @@ -0,0 +1,50 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//title'):gsub(' | Imangascans Reader', '') + x.xpathhrefall('//ul[@class="dropdown-menu"]/li/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "var pages")]') + x.parsehtml(SeparateRight(s, '=')) + local v = x.xpath('json(*)()') + local base = v.get(1).toString + for i = 2, v.count do + task.pagelinks.add(MaybeFillHost(module.RootURL, base .. '/' .. v.get(i).toString)) + end + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/series-list') then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//h4[@class="series-title"]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'IMangaScans' + m.rooturl = 'https://reader.imangascans.org' + m.category = 'English-Scanlation' + m.lastupdated='April 13, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 8f5e9b894fdee645b8301a8ca3ea5c4e77403544 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 13 Apr 2018 15:03:30 +0300 Subject: [PATCH 2560/2794] add ComicoCoID [id] --- lua/modules/ComicoCoID.lua | 65 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 lua/modules/ComicoCoID.lua diff --git a/lua/modules/ComicoCoID.lua b/lua/modules/ComicoCoID.lua new file mode 100644 index 000000000..beea20600 --- /dev/null +++ b/lua/modules/ComicoCoID.lua @@ -0,0 +1,65 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="con"]/h2') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//*[@class="bg_img_small"]/img/@src')) + mangainfo.authors=x.xpathstringall('//div[@class="con"]/dl/dd[@class="name"]/span[@class="aln"]') + mangainfo.genres=x.xpathstring('//div[@class="con"]/dl/dd[@class="name"]/p'):gsub('%s+', ''):gsub(',', ', ') + mangainfo.summary=x.xpathstring('//div[@class="con"]/dl/dd[@class="dsc"]') + if http.get(mangainfo.url .. '/chapters') then + x.parsehtml(http.document) + local v = x.xpath('json(*).data.list()') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(mangainfo.url .. '/chapters/' .. x.xpathstring('id', v1)) + local s = x.xpathstring('name', v1) + if x.xpathstring('./salePolicy/isFree', v1) == 'false' then + s = s .. ' [LOCKED]' + end + mangainfo.chapternames.add(s) + end + end + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + x=TXQuery.Create(http.Document) + v=x.xpathstringall('//div[contains(@class,"_view")]/img/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/weekly/list?page=' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + if x.xpathcount('json(*).data()') > 0 then + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + end + local v = x.xpath('json(*).data().list()') + for i = 1, v.count do + local v1 = v.get(i) + links.add(module.rooturl..'/titles/'..x.xpathstring('id', v1)) + names.add(x.xpathstring('name', v1)) + end + end + return net_problem +end + +function Init() + local m = NewModule() + m.website = 'ComicoCoID' + m.rooturl = 'http://www.comico.co.id' + m.category = 'Indonesian' + m.lastupdated='April 13, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From fc241c2a525fd00f0e683c3fd8d63fa6f98322d7 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 13 Apr 2018 15:29:25 +0300 Subject: [PATCH 2561/2794] add SiberOwl [en-sc] --- lua/modules/SiberOwl.lua | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 lua/modules/SiberOwl.lua diff --git a/lua/modules/SiberOwl.lua b/lua/modules/SiberOwl.lua new file mode 100644 index 000000000..3dbbd4e39 --- /dev/null +++ b/lua/modules/SiberOwl.lua @@ -0,0 +1,64 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + local s = x.xpathstring('//script[contains(., "var description")]') + mangainfo.title = GetBetween('title="', '";', s) + mangainfo.coverlink = MaybeFillHost(module.rooturl, GetBetween('imageUrl="', '";', s)) + mangainfo.summary = GetBetween('description="', '";', s) + s = GetBetween('chapString="', '";', s) + x.parsehtml(s) + local v = x.xpath('//a') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(mangainfo.url .. '/' .. v1.getattribute('href')) + mangainfo.chapternames.add(v1.toString) + end + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "imageUrls")]') + x.parsehtml(GetBetween('imageUrls =', ';', s)) + local v = x.xpath('json(*)()') + for i = 1, v.count do + task.pagelinks.add(MaybeFillHost(module.rooturl, v.get(i).toString)) + end + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//div[@class="index-mangas"]/div/a') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('.//div[@class="index-manga-title"]', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'SiberOwl' + m.rooturl = 'http://siberowl.com' + m.category = 'English-Scanlation' + m.lastupdated='April 10, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 66053e40c39e3996930f1a5d9d7b367b98858ac9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 16 Apr 2018 10:11:26 +0300 Subject: [PATCH 2562/2794] CentralDeMangas, change domain --- lua/modules/CentralDeMangas.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/CentralDeMangas.lua b/lua/modules/CentralDeMangas.lua index d39346740..c7005cb69 100644 --- a/lua/modules/CentralDeMangas.lua +++ b/lua/modules/CentralDeMangas.lua @@ -67,7 +67,7 @@ function Init() m=NewModule() m.category='Portugues' m.website='CentralDeMangas' - m.rooturl='http://centraldemangas.inf.br' + m.rooturl='http://cdmnet.com.br' m.lastupdated='February 15, 2018' m.ongetinfo='GetInfo' m.ongetpagenumber='GetPageNumber' From 4d748e786c0f31e3c5e44061a031f7347526c9b0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 18 Apr 2018 06:31:58 +0300 Subject: [PATCH 2563/2794] add Bamtoki --- lua/modules/Bamtoki.lua | 61 +++++++++++++++++++++++++++++++++++++++++ lua/modules/MangaGo.lua | 8 +++++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 lua/modules/Bamtoki.lua diff --git a/lua/modules/Bamtoki.lua b/lua/modules/Bamtoki.lua new file mode 100644 index 000000000..c9dcac199 --- /dev/null +++ b/lua/modules/Bamtoki.lua @@ -0,0 +1,61 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="title-section-inner"]/div/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="title-section-inner"]/div/img/@src')) + mangainfo.genres=x.xpathstringall('//div[@class="title-section-inner"]//div[@class="toon-section"]/a') + mangainfo.summary=x.xpathstring('//div[@class="title-section-inner"]//div[@class="toon-section"]/following-sibling::div') + x.xpathhrefall('//ul[@class="list-container"]/li/div[@class="list-item"]/div[contains(@class, "list-details")]//a', mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = DecodeBase64(x.xpathstring('//*[@id="tooncontentdata"]')) + x.parsehtml(s) + x.xpathstringall('//img/@src', task.pagelinks) + else + return false + end + return true +end + +local dirurls = { + '/%EC%9B%B9%ED%88%B0/%EC%9E%91%ED%92%88?sort=%EC%A0%9C%EB%AA%A9', + '/%EB%A7%9D%EA%B0%80/%EC%9E%91%ED%92%88?sort=%EC%A0%9C%EB%AA%A9' +} + +function getnameandlink() + local lurl = dirurls[module.CurrentDirectoryIndex+1] + if http.get(module.rooturl .. lurl) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//div[@class="list-container"]/div/div') + for i = 1, v.count do + local v1 = v.get(i) + links.add(x.xpathstring('./a/@href', v1)) + names.add(x.xpathstring('./div/h3', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'Bamtoki' + m.rooturl = 'https://webtoon.bamtoki.com' + m.category = 'Raw' + m.lastupdated='April 11, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.totaldirectory = #dirurls +end diff --git a/lua/modules/MangaGo.lua b/lua/modules/MangaGo.lua index 114431bd5..1b39b8e68 100644 --- a/lua/modules/MangaGo.lua +++ b/lua/modules/MangaGo.lua @@ -115,10 +115,14 @@ function getpagenumber() for i=1,bstr:len() do b[i] = bstr:byte(i) - 48; end return _d(u, b) end + module.storage['r'] = '1' if Pos(',', s) == 0 then script = unp(StreamToString(http.document)) elseif Pos('http', s) == 0 then script = unp(StreamToString(http.document)) + if script:match('referrerPolicy:"no%-referrer"') ~= nil then + module.storage['r'] = '0' + end s = d3(script, s) else end @@ -135,7 +139,9 @@ function getpagenumber() end function beforedownloadimage() - http.headers.values['Referer'] = module.rooturl + if module.storage['r'] == '1' then + http.headers.values['Referer'] = module.rooturl + end return true end From be5e18cd997abcb8b19f69f341998fc43573bd61 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 18 Apr 2018 18:48:27 +0300 Subject: [PATCH 2564/2794] MangaDex, fix list update --- lua/modules/MangaDex.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index e5bf3a762..5bb04cfe3 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -90,7 +90,7 @@ function getnameandlink() http.cookies.values['mangadex_title_mode'] = '1' if http.GET(module.rooturl .. dirurl .. '/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.document) - x.xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) + x.xpathhrefall('//*[@id="content"]//tr/td/a[@class="manga_title"]',links,names) return no_error else return net_problem From afcbd772a9bce739953b1a9afe05cc5f7f29a917 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 18 Apr 2018 18:59:56 +0300 Subject: [PATCH 2565/2794] MangaDex, use simple list view --- lua/modules/MangaDex.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 5bb04cfe3..f002440a1 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -74,7 +74,7 @@ local dirurl='/titles/2' function getdirectorypagenumber() http.cookies.values['mangadex_h_toggle'] = '1' - http.cookies.values['mangadex_title_mode'] = '1' + http.cookies.values['mangadex_title_mode'] = '2' if http.GET(module.RootURL .. dirurl) then local x = TXQuery.Create(http.Document) page = tonumber(x.xpathstring('(//ul[@class="pagination"]/li/a)[last()]/@href'):match('/2/(%d+)')) @@ -87,10 +87,10 @@ end function getnameandlink() http.cookies.values['mangadex_h_toggle'] = '1' - http.cookies.values['mangadex_title_mode'] = '1' + http.cookies.values['mangadex_title_mode'] = '2' if http.GET(module.rooturl .. dirurl .. '/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.document) - x.xpathhrefall('//*[@id="content"]//tr/td/a[@class="manga_title"]',links,names) + x.xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) return no_error else return net_problem From 471699ccd178c945ef46feb2321d7c18c08b2f86 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 21 Apr 2018 09:33:25 +0300 Subject: [PATCH 2566/2794] MangaDex, fix status fixes #1198 --- lua/modules/MangaDex.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index f002440a1..b97759017 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -8,7 +8,7 @@ function getinfo() mangainfo.authors=x.xpathstring('//tr[./th="Author:"]/string-join(./td,", ")') mangainfo.artists=x.xpathstring('//tr[./th="Artist:"]/string-join(./td,", ")') mangainfo.genres = x.xpathstringall('//tr[./th="Genres:"]/td/span/a') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[./th="Status:"]')) + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[contains(./th,"status")]')) mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') local l='//table//tr[@id and not(starts-with(./td/time, "in "))]' local n='' From 9eaff45d9697e883d155ea3d770ff5d6ad1f90df Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 21 Apr 2018 15:44:53 +0300 Subject: [PATCH 2567/2794] readcomiconline, set high image quality fixes #1197 --- baseunits/modules/KissManga.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index b38468ca8..e0401c71a 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -152,6 +152,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; + Cookies.Values['rco_quality'] := 'hq'; if GETWithCookie(DownloadThread.FHTTP, FillHost(Module.RootURL, AURL), Module) then try Result := True; From e78eaba94b0839fbf39b053885a60c8946dc6311 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 25 Apr 2018 17:25:31 +0300 Subject: [PATCH 2568/2794] add MangaHereIO [en] --- lua/modules/Mangakakalot.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lua/modules/Mangakakalot.lua b/lua/modules/Mangakakalot.lua index 4c0695a76..67d0bcb7f 100644 --- a/lua/modules/Mangakakalot.lua +++ b/lua/modules/Mangakakalot.lua @@ -17,7 +17,7 @@ function getinfo() end mangainfo.url=u local x=TXQuery.Create(http.document) - if (Pos('mangasupa', u:lower()) > 0) or module.website == 'MangaFoxCom' then + if (Pos('mangasupa', u:lower()) > 0) or module.website == 'MangaFoxCom' or module.website == 'MangaHereIO' then mangainfo.title=x.xpathstring('//h1[@class="entry-title"]') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//span[@class="info_image"]/img/@src')) mangainfo.authors=x.xpathstringall('//ul[@class="truyen_info_right"]/li[contains(., "Author")]/a') @@ -80,12 +80,12 @@ end local dirurl = '/manga_list?type=newest&category=all&state=all&page=' function getnameandlink() local dir = dirurl - if module.website == 'MangaFoxCom' then + if module.website == 'MangaFoxCom' or module.website == 'MangaHereIO' then dir = '/manga-list?view=list&sort=date_added&page=' end if http.get(module.rooturl .. dir .. IncStr(url)) then local x = TXQuery.Create(http.Document) - if module.website == 'MangaFoxCom' then + if module.website == 'MangaFoxCom' or module.website == 'MangaHereIO' then local q = '//div[contains(@class,"wrap_update")]/div[@class="update_item"]/h3/a' if x.xpathcount(q) > 0 then x.XPathHREFAll(q, links, names) @@ -138,5 +138,6 @@ function Init() AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com') AddWebsiteModule('Manganelo', 'http://manganelo.com') AddWebsiteModule('Mangasupa', 'http://mangasupa.com') + AddWebsiteModule('MangaHereIO', 'https://manga-here.io') AddWebsiteModule('MangaFoxCom', 'https://manga-fox.com') end From 4e4ef16d252d12697d0ffea7f9bd3fba199c5366 Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Wed, 25 Apr 2018 22:01:11 -0500 Subject: [PATCH 2569/2794] Pzykosis666HFansub http -> https --- lua/modules/FoOlSlide.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 1ab2ba9b3..758934f59 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -287,7 +287,7 @@ function Init() AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) - AddWebsiteModule('Pzykosis666HFansub', 'http://pzykosis666hfansub.com', cat) + AddWebsiteModule('Pzykosis666HFansub', 'https://pzykosis666hfansub.com', cat) AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) AddWebsiteModule('SeinagiFansub', 'https://seinagi.org', cat) AddWebsiteModule('SeinagiAdultoFansub', 'https://adulto.seinagi.org', cat) From 5e5c5e050f20e9c2577563e41d8bbdc941b87d25 Mon Sep 17 00:00:00 2001 From: rs3mk <rs3mk@eyepaste.com> Date: Wed, 25 Apr 2018 22:02:40 -0500 Subject: [PATCH 2570/2794] add SOS Scanlation --- lua/modules/myReaderMangaCMS.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index ee2835a31..e98a88bc7 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -102,6 +102,7 @@ function Init() AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com/', c); + AddWebsiteModule('SOS_Scanlation', 'http://sosscanlation.com', c); c='Italian-Scanlation' AddWebsiteModule('DigitalTeamAltervista', 'http://digitalteam1.altervista.org', c) From 1a57fcd96fe5c32dd17a2f77dbf9abe36d89a60c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 26 Apr 2018 09:00:36 +0300 Subject: [PATCH 2571/2794] fix name --- lua/modules/myReaderMangaCMS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index e98a88bc7..187dac19b 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -102,7 +102,7 @@ function Init() AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com/', c); - AddWebsiteModule('SOS_Scanlation', 'http://sosscanlation.com', c); + AddWebsiteModule('SOSScanlation', 'http://sosscanlation.com', c); c='Italian-Scanlation' AddWebsiteModule('DigitalTeamAltervista', 'http://digitalteam1.altervista.org', c) From 2de839fb68ddb545dd5d10d38848ef070cd3580c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 26 Apr 2018 12:41:29 +0300 Subject: [PATCH 2572/2794] forms, fix tab order --- mangadownloader/forms/frmImportFavorites.lfm | 6 +- mangadownloader/forms/frmLogger.lfm | 6 +- .../forms/frmLuaModulesUpdater.lfm | 8 +- mangadownloader/forms/frmMain.lfm | 152 +++++++++--------- mangadownloader/forms/frmNewChapter.lfm | 4 +- .../forms/frmTransferFavorites.lfm | 14 +- mangadownloader/forms/frmWebsiteSettings.lfm | 4 +- 7 files changed, 97 insertions(+), 97 deletions(-) diff --git a/mangadownloader/forms/frmImportFavorites.lfm b/mangadownloader/forms/frmImportFavorites.lfm index 1ce7653f0..2d7c179d5 100644 --- a/mangadownloader/forms/frmImportFavorites.lfm +++ b/mangadownloader/forms/frmImportFavorites.lfm @@ -85,7 +85,7 @@ object ImportFavorites: TImportFavorites NumGlyphs = 1 Align = alTop MaxLength = 0 - TabOrder = 3 + TabOrder = 1 TextHint = 'Path to the software (e.g. C:\MangaDownloader)' end object btImport: TBitBtn @@ -136,7 +136,7 @@ object ImportFavorites: TImportFavorites } ModalResult = 1 OnClick = btImportClick - TabOrder = 1 + TabOrder = 2 end object btCancel: TBitBtn AnchorSideLeft.Control = btImport @@ -185,6 +185,6 @@ object ImportFavorites: TImportFavorites FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } ModalResult = 2 - TabOrder = 2 + TabOrder = 3 end end diff --git a/mangadownloader/forms/frmLogger.lfm b/mangadownloader/forms/frmLogger.lfm index 0c1f6a96f..28b2cf3d8 100644 --- a/mangadownloader/forms/frmLogger.lfm +++ b/mangadownloader/forms/frmLogger.lfm @@ -30,7 +30,7 @@ object FormLogger: TFormLogger ReadOnly = True ScrollBars = ssAutoBoth ShowTime = True - TabOrder = 0 + TabOrder = 3 TimeFormat = 'hh:nn:ss:zzz' Options = [tvoAllowMultiselect, tvoAutoItemHeight, tvoHideSelection, tvoHotTrack, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] end @@ -41,7 +41,7 @@ object FormLogger: TFormLogger Width = 80 Caption = 'Stay on top' OnChange = ckStayOnTopChange - TabOrder = 1 + TabOrder = 0 end object seLogLimit: TSpinEdit Left = 373 @@ -115,7 +115,7 @@ object FormLogger: TFormLogger FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btnClearLogClick - TabOrder = 3 + TabOrder = 1 end object tmClearLog: TTimer Interval = 2000 diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lfm b/mangadownloader/forms/frmLuaModulesUpdater.lfm index 7aa128ab9..fac4dd8ad 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.lfm +++ b/mangadownloader/forms/frmLuaModulesUpdater.lfm @@ -49,7 +49,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm Images = imStates ParentShowHint = False ShowHint = True - TabOrder = 0 + TabOrder = 3 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] OnCompareNodes = vtLuaModulesReposCompareNodes @@ -104,7 +104,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btCheckUpdateClick - TabOrder = 1 + TabOrder = 0 end object btCheckUpdateTerminate: TSpeedButton AnchorSideLeft.Control = btCheckUpdate @@ -169,7 +169,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm Caption = 'Show update warning' Checked = True State = cbChecked - TabOrder = 2 + TabOrder = 1 end object ckAutoRestart: TCheckBox AnchorSideLeft.Control = ckShowUpdateWarning @@ -180,7 +180,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm Top = 8 Width = 82 Caption = 'Auto restart' - TabOrder = 3 + TabOrder = 2 end object imStates: TImageList left = 200 diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index a5471d07f..6f7933b35 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -473,7 +473,7 @@ object MainForm: TMainForm ParentShowHint = False PopupMenu = pmMangaList ShowHint = True - TabOrder = 0 + TabOrder = 2 TextMargin = 3 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toThemeAware, toUseBlendedImages] @@ -556,7 +556,7 @@ object MainForm: TMainForm ParentShowHint = False ShowHint = True Sorted = True - TabOrder = 1 + TabOrder = 0 end object btUpdateList: TSpeedButton AnchorSideLeft.Side = asrBottom @@ -621,7 +621,7 @@ object MainForm: TMainForm Anchors = [akTop, akLeft, akRight] OnChange = edMangaListSearchChange OnKeyDown = edMangaListSearchKeyDown - TabOrder = 2 + TabOrder = 1 TextHint = 'Search title...' end object btMangaListSearchClear: TSpeedButton @@ -838,7 +838,7 @@ object MainForm: TMainForm OnKeyPress = edURLKeyPress PasswordChar = #0 PopupMenu = pmEditURL - TabOrder = 2 + TabOrder = 0 TextHint = 'Input URL here' end object rmInformation: TRichMemo @@ -856,7 +856,7 @@ object MainForm: TMainForm HideSelection = False ReadOnly = True ScrollBars = ssAutoVertical - TabOrder = 0 + TabOrder = 2 ZoomFactor = 1 end object btDonate: TImage @@ -1008,7 +1008,7 @@ object MainForm: TMainForm 3F33E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00E99E3F00 } OnClick = btDownloadClick - TabOrder = 1 + TabOrder = 3 end object cbAddAsStopped: TCheckBox AnchorSideLeft.Control = edSaveTo @@ -1025,7 +1025,7 @@ object MainForm: TMainForm Caption = 'Add to download list as stopped task' OnChange = cbAddAsStoppedChange ParentFont = False - TabOrder = 3 + TabOrder = 2 end object btReadOnline: TBitBtn AnchorSideLeft.Control = btAddToFavorites @@ -1077,7 +1077,7 @@ object MainForm: TMainForm 80668080806680808066808080668080804D7F7F7F007F7F7F00 } OnClick = btReadOnlineClick - TabOrder = 2 + TabOrder = 4 end object btChecks: TSpeedButton AnchorSideLeft.Control = clbChapterList @@ -1176,7 +1176,7 @@ object MainForm: TMainForm E1000101E3000101E53C0101E5AB0101E53C0101E3000101E100 } OnClick = btAddToFavoritesClick - TabOrder = 4 + TabOrder = 5 end object lbSaveTo: TLabel AnchorSideLeft.Control = clbChapterList @@ -1294,7 +1294,7 @@ object MainForm: TMainForm OnButtonClick = edSaveToButtonClick ParentFont = False PasswordChar = #0 - TabOrder = 6 + TabOrder = 1 TextHint = 'Save to' end object btDownloadSplit: TSpeedButton @@ -1382,7 +1382,7 @@ object MainForm: TMainForm ChildSizing.ControlsPerLine = 3 ClientHeight = 23 ClientWidth = 528 - TabOrder = 2 + TabOrder = 1 object lbFilterCustomGenres: TLabel Left = 0 Height = 23 @@ -1437,7 +1437,7 @@ object MainForm: TMainForm ClientHeight = 136 ClientWidth = 528 ParentFont = False - TabOrder = 1 + TabOrder = 2 object Panel1: TPanel Left = 0 Height = 136 @@ -1490,7 +1490,7 @@ object MainForm: TMainForm Height = 23 Top = 27 Width = 185 - TabOrder = 2 + TabOrder = 1 TextHint = 'Author' end object lbFilterArtists: TLabel @@ -1510,7 +1510,7 @@ object MainForm: TMainForm Height = 23 Top = 54 Width = 185 - TabOrder = 1 + TabOrder = 2 TextHint = 'Artist' end object lbFilterStatus: TLabel @@ -2239,7 +2239,7 @@ object MainForm: TMainForm } OnClick = btFilterClick ParentFont = False - TabOrder = 1 + TabOrder = 0 end object btRemoveFilterLarge: TBitBtn AnchorSideLeft.Side = asrBottom @@ -2292,7 +2292,7 @@ object MainForm: TMainForm ParentFont = False ParentShowHint = False ShowHint = True - TabOrder = 0 + TabOrder = 1 end object btFilterReset: TBitBtn Left = 219 @@ -2407,7 +2407,7 @@ object MainForm: TMainForm ParentShowHint = False PopupMenu = pmFavorites ShowHint = True - TabOrder = 0 + TabOrder = 3 TextMargin = 2 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toDisableAutoscrollOnFocus] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] @@ -2625,7 +2625,7 @@ object MainForm: TMainForm OnButtonClick = edFavoritesSearchButtonClick OnChange = edFavoritesSearchChange PasswordChar = #0 - TabOrder = 3 + TabOrder = 0 TextHint = 'Search favorites...' end end @@ -2663,7 +2663,7 @@ object MainForm: TMainForm Width = 106 Caption = 'Minimize to tray' ParentFont = False - TabOrder = 0 + TabOrder = 4 end object cbOptionOneInstanceOnly: TCheckBox AnchorSideLeft.Control = cbOptionMinimizeToTray @@ -2675,7 +2675,7 @@ object MainForm: TMainForm Width = 177 Caption = 'Permit only one FMD running' ParentFont = False - TabOrder = 2 + TabOrder = 5 end object cbOptionLiveSearch: TCheckBox AnchorSideLeft.Control = cbOptionOneInstanceOnly @@ -2687,7 +2687,7 @@ object MainForm: TMainForm Width = 210 Caption = 'Enable live search (slow on long list)' ParentFont = False - TabOrder = 3 + TabOrder = 6 end object gbOptionExternal: TGroupBox AnchorSideLeft.Control = cbOptionLiveSearch @@ -2707,7 +2707,7 @@ object MainForm: TMainForm ClientHeight = 98 ClientWidth = 738 ParentFont = False - TabOrder = 1 + TabOrder = 8 object lbOptionExternal: TLabel Left = 4 Height = 15 @@ -2735,7 +2735,7 @@ object MainForm: TMainForm Top = 69 Width = 703 Anchors = [akTop, akLeft, akRight] - TabOrder = 0 + TabOrder = 1 TextHint = 'External program parameters' end object lbOptionExternalParamsHint: TLabel @@ -2801,7 +2801,7 @@ object MainForm: TMainForm NumGlyphs = 1 OnButtonClick = edOptionExternalPathButtonClick PasswordChar = #0 - TabOrder = 1 + TabOrder = 0 TextHint = 'External program path' end end @@ -2828,7 +2828,7 @@ object MainForm: TMainForm ) ParentFont = False Style = csDropDownList - TabOrder = 4 + TabOrder = 0 end object lbOptionLetFMDDo: TLabel AnchorSideLeft.Control = cbLanguages @@ -2858,7 +2858,7 @@ object MainForm: TMainForm ) ParentFont = False Style = csDropDownList - TabOrder = 5 + TabOrder = 1 end object seOptionNewMangaTime: TSpinEdit AnchorSideLeft.Control = cbOptionLetFMDDo @@ -2872,7 +2872,7 @@ object MainForm: TMainForm MaxValue = 365 MinValue = 1 ParentFont = False - TabOrder = 6 + TabOrder = 2 Value = 1 end object lbOptionNewMangaTime: TLabel @@ -2899,7 +2899,7 @@ object MainForm: TMainForm BorderSpacing.Top = 20 Caption = 'Minimize on start' ParentFont = False - TabOrder = 7 + TabOrder = 3 end object cbOptionDeleteCompletedTasksOnClose: TCheckBox AnchorSideLeft.Control = tsGeneral @@ -2910,7 +2910,7 @@ object MainForm: TMainForm Top = 251 Width = 189 Caption = 'Delete completed tasks on close' - TabOrder = 8 + TabOrder = 7 end end object tsView: TTabSheet @@ -2929,7 +2929,7 @@ object MainForm: TMainForm Align = alTop Caption = 'Show downloads toolbar' ParentFont = False - TabOrder = 0 + TabOrder = 1 end object gbDropTarget: TGroupBox Left = 4 @@ -2945,7 +2945,7 @@ object MainForm: TMainForm ChildSizing.VerticalSpacing = 4 ClientHeight = 145 ClientWidth = 741 - TabOrder = 1 + TabOrder = 0 object ckDropTarget: TCheckBox Left = 4 Height = 19 @@ -2969,7 +2969,7 @@ object MainForm: TMainForm Min = 5 OnChange = tbDropTargetOpacityChange Position = 200 - TabOrder = 1 + TabOrder = 2 end object lbDropTargetOpacity: TLabel AnchorSideLeft.Control = rgDropTargetMode @@ -3009,7 +3009,7 @@ object MainForm: TMainForm 'Add to favorites' ) ParentFont = False - TabOrder = 2 + TabOrder = 1 end end object cbOptionEnableLoadCover: TCheckBox @@ -3020,7 +3020,7 @@ object MainForm: TMainForm Align = alTop Caption = 'Enable load manga cover' ParentFont = False - TabOrder = 2 + TabOrder = 4 end object cbOptionShowDownloadToolbarDeleteAll: TCheckBox Left = 4 @@ -3030,7 +3030,7 @@ object MainForm: TMainForm Align = alTop Caption = 'Show "Delete all completed tasks" in downloads toolbar' ParentFont = False - TabOrder = 3 + TabOrder = 2 end object cbOptionShowBalloonHint: TCheckBox Left = 4 @@ -3040,7 +3040,7 @@ object MainForm: TMainForm Align = alTop Caption = 'Show balloon hint' ParentFont = False - TabOrder = 4 + TabOrder = 5 end object cbOptionShowDownloadToolbarLeft: TCheckBox Left = 4 @@ -3050,7 +3050,7 @@ object MainForm: TMainForm Align = alTop Caption = 'Show left downloads toolbar' ParentFont = False - TabOrder = 5 + TabOrder = 3 end end object tsConnections: TTabSheet @@ -3085,7 +3085,7 @@ object MainForm: TMainForm Caption = 'Use proxy' OnChange = cbOptionUseProxyChange ParentFont = False - TabOrder = 0 + TabOrder = 6 end object gbOptionProxy: TGroupBox AnchorSideLeft.Control = cbOptionUseProxy @@ -3105,7 +3105,7 @@ object MainForm: TMainForm ClientWidth = 422 Enabled = False ParentFont = False - TabOrder = 1 + TabOrder = 7 object lbOptionHost: TLabel AnchorSideLeft.Control = lbOptionProxyType AnchorSideTop.Control = lbOptionProxyType @@ -3134,7 +3134,7 @@ object MainForm: TMainForm Font.Height = -12 Font.Name = 'Default' ParentFont = False - TabOrder = 0 + TabOrder = 1 TextHint = 'Proxy host/IP' end object lbOptionUser: TLabel @@ -3161,7 +3161,7 @@ object MainForm: TMainForm Font.Height = -12 Font.Name = 'Default' ParentFont = False - TabOrder = 1 + TabOrder = 3 TextHint = 'Proxy username' end object lbOptionPort: TLabel @@ -3201,7 +3201,7 @@ object MainForm: TMainForm Font.Height = -12 Font.Name = 'Default' ParentFont = False - TabOrder = 2 + TabOrder = 4 TextHint = 'Proxy password' end object lbOptionProxyType: TLabel @@ -3229,7 +3229,7 @@ object MainForm: TMainForm 'SOCKS5' ) Style = csDropDownList - TabOrder = 3 + TabOrder = 0 Text = 'HTTP' end object edOptionPort: TSpinEdit @@ -3246,7 +3246,7 @@ object MainForm: TMainForm MaxValue = 999999 MinValue = 1 ParentFont = False - TabOrder = 4 + TabOrder = 2 Value = 8080 end end @@ -3259,7 +3259,7 @@ object MainForm: TMainForm MinValue = 1 ParentFont = False ParentShowHint = False - TabOrder = 2 + TabOrder = 0 Value = 1 end object lbOptionMaxParallel: TLabel @@ -3290,7 +3290,7 @@ object MainForm: TMainForm MinValue = 1 ParentFont = False ParentShowHint = False - TabOrder = 3 + TabOrder = 1 Value = 1 end object lbOptionMaxThread: TLabel @@ -3320,7 +3320,7 @@ object MainForm: TMainForm MinValue = -1 ParentFont = False ParentShowHint = False - TabOrder = 4 + TabOrder = 2 end object lbOptionMaxRetry: TLabel AnchorSideLeft.Control = seOptionMaxRetry @@ -3350,7 +3350,7 @@ object MainForm: TMainForm MinValue = 1 ParentFont = False ParentShowHint = False - TabOrder = 5 + TabOrder = 3 Value = 30 end object lbOptionConnectionTimeout: TLabel @@ -3392,7 +3392,7 @@ object MainForm: TMainForm Anchors = [akTop, akLeft, akRight] ParentFont = False ParentShowHint = False - TabOrder = 6 + TabOrder = 4 Value = 1 end object ckOptionsAlwaysStartTaskFromFailedChapters: TCheckBox @@ -3405,7 +3405,7 @@ object MainForm: TMainForm Width = 216 BorderSpacing.Top = 20 Caption = 'Always start task from failed chapters' - TabOrder = 7 + TabOrder = 5 end end end @@ -3463,7 +3463,7 @@ object MainForm: TMainForm ) OnSelectionChanged = rgOptionCompressSelectionChanged ParentFont = False - TabOrder = 1 + TabOrder = 2 end object gbOptionRenaming: TGroupBox AnchorSideLeft.Control = lbDefaultDownloadPath @@ -3486,7 +3486,7 @@ object MainForm: TMainForm ClientHeight = 282 ClientWidth = 724 ParentFont = False - TabOrder = 3 + TabOrder = 5 object cbOptionChangeUnicodeCharacter: TCheckBox Left = 4 Height = 19 @@ -3509,7 +3509,7 @@ object MainForm: TMainForm Caption = 'Auto generate folder based on manga''s name' OnChange = cbOptionGenerateMangaFolderChange ParentFont = False - TabOrder = 1 + TabOrder = 2 end object lbOptionMangaCustomRename: TLabel AnchorSideLeft.Control = cbOptionGenerateMangaFolder @@ -3565,7 +3565,7 @@ object MainForm: TMainForm Width = 208 Caption = 'Remove manga name from chapter' ParentFont = False - TabOrder = 2 + TabOrder = 4 end object cbOptionGenerateChapterFolder: TCheckBox AnchorSideLeft.Control = cbOptionRemoveMangaNameFromChapter @@ -3579,7 +3579,7 @@ object MainForm: TMainForm Checked = True ParentFont = False State = cbChecked - TabOrder = 4 + TabOrder = 5 end object lbOptionChapterCustomRename: TLabel AnchorSideLeft.Control = cbOptionGenerateChapterFolder @@ -3600,7 +3600,7 @@ object MainForm: TMainForm Height = 23 Top = 161 Width = 308 - TabOrder = 5 + TabOrder = 6 TextHint = 'Custom rename' end object lbOptionChapterCustomRenameHint: TLabel @@ -3641,7 +3641,7 @@ object MainForm: TMainForm Width = 61 Caption = 'Volume' OnChange = cbOptionDigitVolumeChange - TabOrder = 8 + TabOrder = 7 end object seOptionDigitVolume: TSpinEdit AnchorSideLeft.Control = cbOptionDigitVolume @@ -3654,7 +3654,7 @@ object MainForm: TMainForm BorderSpacing.Left = 4 MaxValue = 10 MinValue = 1 - TabOrder = 6 + TabOrder = 8 Value = 1 end object cbOptionDigitChapter: TCheckBox @@ -3681,7 +3681,7 @@ object MainForm: TMainForm BorderSpacing.Left = 4 MaxValue = 10 MinValue = 1 - TabOrder = 7 + TabOrder = 10 Value = 1 end object lbOptionFilenameCustomRenameHint: TLabel @@ -3709,7 +3709,7 @@ object MainForm: TMainForm Height = 23 Top = 255 Width = 308 - TabOrder = 10 + TabOrder = 11 TextHint = 'Custom rename' end object lbOptionFilenameCustomRename: TLabel @@ -3733,7 +3733,7 @@ object MainForm: TMainForm Top = 4 Width = 80 Enabled = False - TabOrder = 11 + TabOrder = 1 end end object lbDefaultDownloadPath: TLabel @@ -3788,7 +3788,7 @@ object MainForm: TMainForm ParentFont = False ParentShowHint = False ShowHint = True - TabOrder = 2 + TabOrder = 3 Value = 100 end object lbOptionPDFQuality: TLabel @@ -3857,7 +3857,7 @@ object MainForm: TMainForm OnButtonClick = edOptionDefaultPathButtonClick ParentFont = False PasswordChar = #0 - TabOrder = 4 + TabOrder = 1 TextHint = 'Default download path' end object gbImageConversion: TGroupBox @@ -3879,7 +3879,7 @@ object MainForm: TMainForm ChildSizing.VerticalSpacing = 6 ClientHeight = 102 ClientWidth = 724 - TabOrder = 5 + TabOrder = 4 object lbWebPSaveAs: TLabel AnchorSideLeft.Control = gbImageConversion AnchorSideTop.Control = ckPNGSaveAsJPEG @@ -3908,7 +3908,7 @@ object MainForm: TMainForm 'JPEG' ) Style = csDropDownList - TabOrder = 0 + TabOrder = 1 Text = 'PNG' end object lbPNGCompressionLevel: TLabel @@ -3941,7 +3941,7 @@ object MainForm: TMainForm 'Maximum' ) Style = csDropDownList - TabOrder = 1 + TabOrder = 2 Text = 'Fastest' end object lbJPEGQuality: TLabel @@ -3966,7 +3966,7 @@ object MainForm: TMainForm Top = 75 Width = 47 MinValue = 1 - TabOrder = 2 + TabOrder = 3 Value = 80 end object ckPNGSaveAsJPEG: TCheckBox @@ -3977,7 +3977,7 @@ object MainForm: TMainForm Top = 4 Width = 113 Caption = 'Save PNG as JPEG' - TabOrder = 3 + TabOrder = 0 end end end @@ -4214,7 +4214,7 @@ object MainForm: TMainForm Header.MainColumn = -1 Margin = 1 ParentFont = False - TabOrder = 0 + TabOrder = 1 TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking] TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages] @@ -4237,7 +4237,7 @@ object MainForm: TMainForm ChildSizing.VerticalSpacing = 4 ClientHeight = 23 ClientWidth = 731 - TabOrder = 1 + TabOrder = 0 object pnlWebsitesToolRight: TPanel Left = 561 Height = 23 @@ -4454,7 +4454,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btClearLogFileClick - TabOrder = 1 + TabOrder = 2 end object lbLogFileName: TLabel AnchorSideLeft.Control = ckEnableLogging @@ -4514,7 +4514,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btOpenLogClick - TabOrder = 2 + TabOrder = 3 end object edLogFileName: TEditButton AnchorSideLeft.Control = ckEnableLogging @@ -4566,7 +4566,7 @@ object MainForm: TMainForm NumGlyphs = 1 OnButtonClick = edLogFileNameButtonClick PasswordChar = #0 - TabOrder = 3 + TabOrder = 1 end end end @@ -4672,7 +4672,7 @@ object MainForm: TMainForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btCheckLatestVersionClick - TabOrder = 0 + TabOrder = 1 end object btAbortCheckLatestVersion: TSpeedButton AnchorSideLeft.Control = btCheckLatestVersion @@ -4771,7 +4771,7 @@ object MainForm: TMainForm 80668080806680808066808080668080804D7F7F7F007F7F7F00 } OnClick = btVisitMyBlogClick - TabOrder = 1 + TabOrder = 2 Visible = False end object pcAbout: TPageControl @@ -4783,7 +4783,7 @@ object MainForm: TMainForm Align = alTop Anchors = [akTop, akLeft, akRight, akBottom] TabIndex = 0 - TabOrder = 2 + TabOrder = 0 object tsAboutText: TTabSheet Caption = 'About FMD' ClientHeight = 404 diff --git a/mangadownloader/forms/frmNewChapter.lfm b/mangadownloader/forms/frmNewChapter.lfm index 0722ca2dd..26f36a196 100644 --- a/mangadownloader/forms/frmNewChapter.lfm +++ b/mangadownloader/forms/frmNewChapter.lfm @@ -146,7 +146,7 @@ object NewChapter: TNewChapter } ModalResult = 4 OnClick = btQueueClick - TabOrder = 2 + TabOrder = 1 end object btCancel: TBitBtn Left = 296 @@ -194,7 +194,7 @@ object NewChapter: TNewChapter } ModalResult = 2 OnClick = btCancelClick - TabOrder = 1 + TabOrder = 2 end end end diff --git a/mangadownloader/forms/frmTransferFavorites.lfm b/mangadownloader/forms/frmTransferFavorites.lfm index 1f7784d61..fe7833449 100644 --- a/mangadownloader/forms/frmTransferFavorites.lfm +++ b/mangadownloader/forms/frmTransferFavorites.lfm @@ -73,7 +73,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Header.Height = 23 Header.Options = [hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible] Images = imgsState - TabOrder = 1 + TabOrder = 5 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines] TreeOptions.SelectionOptions = [toFullRowSelect] WantTabs = True @@ -131,7 +131,7 @@ object TransferFavoritesForm: TTransferFavoritesForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btOKClick - TabOrder = 2 + TabOrder = 7 end object btCancel: TBitBtn AnchorSideTop.Control = btOK @@ -180,7 +180,7 @@ object TransferFavoritesForm: TTransferFavoritesForm FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00 } OnClick = btCancelClick - TabOrder = 3 + TabOrder = 6 end object rbAll: TRadioButton AnchorSideLeft.Control = ckClearDownloadedChapters @@ -193,7 +193,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Caption = 'All' Checked = True OnChange = rbAllChange - TabOrder = 6 + TabOrder = 2 TabStop = True end object rbValid: TRadioButton @@ -207,7 +207,7 @@ object TransferFavoritesForm: TTransferFavoritesForm BorderSpacing.Left = 8 Caption = 'Valid' OnChange = rbAllChange - TabOrder = 4 + TabOrder = 3 end object rbInvalid: TRadioButton AnchorSideLeft.Control = rbValid @@ -220,7 +220,7 @@ object TransferFavoritesForm: TTransferFavoritesForm BorderSpacing.Left = 8 Caption = 'Invalid' OnChange = rbAllChange - TabOrder = 5 + TabOrder = 4 end object ckClearDownloadedChapters: TCheckBox AnchorSideLeft.Control = lbTransferTo @@ -234,7 +234,7 @@ object TransferFavoritesForm: TTransferFavoritesForm Caption = 'Clear downloaded chapter list and reload from server' Checked = True State = cbChecked - TabOrder = 7 + TabOrder = 1 end object imgState: TImage AnchorSideLeft.Control = cbWebsites diff --git a/mangadownloader/forms/frmWebsiteSettings.lfm b/mangadownloader/forms/frmWebsiteSettings.lfm index c648737d0..a3c220f84 100644 --- a/mangadownloader/forms/frmWebsiteSettings.lfm +++ b/mangadownloader/forms/frmWebsiteSettings.lfm @@ -36,7 +36,7 @@ object WebsiteSettingsForm: TWebsiteSettingsForm Header.Columns = <> Header.DefaultHeight = 17 Header.MainColumn = -1 - TabOrder = 0 + TabOrder = 1 TreeOptions.PaintOptions = [toHideFocusRect, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages] TreeOptions.SelectionOptions = [toFullRowSelect] OnCompareNodes = vtWebsiteCompareNodes @@ -91,7 +91,7 @@ object WebsiteSettingsForm: TWebsiteSettingsForm OnButtonClick = edSearchButtonClick OnChange = edSearchChange PasswordChar = #0 - TabOrder = 1 + TabOrder = 0 TextHint = 'Website name' end end From e882e82d4ff07851eec9ed6f25d7e27bdf7fb1c0 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 26 Apr 2018 13:46:23 +0300 Subject: [PATCH 2573/2794] activate Info tab when manga info is loaded --- mangadownloader/forms/frmMain.pas | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 5dde3b713..8095f68a4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3304,9 +3304,12 @@ procedure TMainForm.miMangaListDownloadAllClick(Sender: TObject); procedure TMainForm.miMangaListViewInfosClick(Sender: TObject); begin - if Assigned(vtMangaList.FocusedNode) then + if Assigned(vtMangaList.FocusedNode) then begin with PMangaInfoData(vtMangaList.GetNodeData(vtMangaList.FocusedNode))^ do ViewMangaInfo(link, website, title, '', miMangaListViewInfos, vtMangaList.FocusedNode); + if pcInfo.ActivePage <> tsInfoManga then + pcInfo.ActivePage := tsInfoManga; + end; end; procedure TMainForm.miFavoritesOpenFolderClick(Sender: TObject); From 13668fcc358ae61ac6a4b40570feff4e1553bef5 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 26 Apr 2018 17:18:55 +0300 Subject: [PATCH 2574/2794] add ReadComicBooksOnline [en] --- lua/modules/ReadComicBooksOnline.lua | 72 ++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 lua/modules/ReadComicBooksOnline.lua diff --git a/lua/modules/ReadComicBooksOnline.lua b/lua/modules/ReadComicBooksOnline.lua new file mode 100644 index 000000000..d3905ad40 --- /dev/null +++ b/lua/modules/ReadComicBooksOnline.lua @@ -0,0 +1,72 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Comic Title")]/td[@class="info"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@class="thispic"]/@src')) + mangainfo.authors=x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Author")]/td[@class="info"]') + mangainfo.genres=x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Genre")]/td[@class="info"]') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Status")]/td[@class="info"]')) + mangainfo.summary=x.xpathstringall('//div[@id="summary"]/text()', '') + x.xpathhrefall('//div[@id="chapterlist"]/li/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + http.reset() + http.headers.values['Referer'] = mangainfo.url + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + task.pagenumber = x.xpathcount('(//select[@name="page"])[1]/option') + else + return false + end + return true +end + +function getimageurl() + local lurl=MaybeFillHost(module.rooturl,url) + if workid~=0 then lurl=lurl..'/'..(workid+1) end + if http.get(lurl) then + local x=TXQuery.Create(http.Document) + local base = x.xpathstring("//base/@href") + task.pagelinks[workid]=MaybeFillHost(base, x.xpathstring('//img[@class="picture"]/@src')) + return true + else + return false + end +end + +function beforedownloadimage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/comics-list') then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@id="content-wrap"]//table//tr/td/div/span/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'ReadComicBooksOnline' + m.rooturl = 'https://readcomicbooksonline.org' + m.category = 'English' + m.lastupdated='April 26, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetimageurl='getimageurl' + m.onbeforedownloadimage = 'beforedownloadimage' +end From 52111efb0ff089599b64d7316952874e184e3755 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Thu, 26 Apr 2018 17:44:43 +0300 Subject: [PATCH 2575/2794] add ComicExtra [en] --- lua/modules/ComicExtra.lua | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 lua/modules/ComicExtra.lua diff --git a/lua/modules/ComicExtra.lua b/lua/modules/ComicExtra.lua new file mode 100644 index 000000000..4f1ca61e0 --- /dev/null +++ b/lua/modules/ComicExtra.lua @@ -0,0 +1,50 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1[1]/span') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="movie-l-img"]/img/@src')) + mangainfo.authors=x.xpathstring('//dt[contains(., "Author")]/following-sibling::dd') + mangainfo.genres=x.xpathstringall('//dt[contains(., "Genre")]/following-sibling::dd/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//dt[contains(., "Status")]/following-sibling::dd')) + mangainfo.summary=x.xpathstring('//div[@id="film-content"]') + x.xpathhrefall('//tbody[@id="list"]/tr/td/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url .. '/full')) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[@class="chapter_img"]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/comic-list') then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@class="serie-box"]/ul/li/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'ComicExtra' + m.rooturl = 'http://www.comicextra.com' + m.category = 'English' + m.lastupdated='April 26, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 9ef786b76b2f18adf62a1626827a21b5240d32a9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 27 Apr 2018 07:24:44 +0300 Subject: [PATCH 2576/2794] add AllHentai [ru] fixes #1205 --- lua/modules/AllHentai.lua | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 lua/modules/AllHentai.lua diff --git a/lua/modules/AllHentai.lua b/lua/modules/AllHentai.lua new file mode 100644 index 000000000..1847ad931 --- /dev/null +++ b/lua/modules/AllHentai.lua @@ -0,0 +1,90 @@ +local dirurl = '/list?type=&sortType=DATE_CREATE' +local perpage = 60 + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + local rname = x.xpathstring('//meta[@itemprop="name"]/@content') + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//meta[@itemprop="alternativeHeadline"]/@content') + end + if mangainfo.title == '' then + mangainfo.title = rname + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@itemprop="image"]/@src')) + mangainfo.authors=x.xpathstringall('//p[@class="elementList" and contains(b, "Автор")]/a') + mangainfo.genres=x.xpathstringall('//p[@class="elementList" and (contains(b, "Жанры") or contains(b, "Категории"))]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//p[contains(b, "Перевод")]'), 'продолжается', 'завершен') + mangainfo.summary=x.xpathstring('//div[@class="mangaDescription"]/div[@itemprop="description"]') + -- TODO: remove manga name from chapter name + x.xpathhrefall('//div[@class="expandable"]/table[@class="cTable"]/tbody/tr/td/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function beforedownloadimage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "var pictures")]') + s = GetBetween('pictures =', ';', s) + x.parsehtml(s) + x.xpathstringall('json(*)().url', task.pagelinks) + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. dirurl) then + local x = TXQuery.Create(http.Document) + local s = x.xpathstring('//*[@class="pagination"]/a[@class="step"][last()]/@href') + page = tonumber(s:match('offset=(%d+)')) + if page == nil then page = 1 end + if page > 1 then page = math.ceil(page / perpage) + 1; end + return no_error + else + return net_problem + end +end + +function getnameandlink() + local s = module.rooturl .. dirurl + if url ~= '0' then s = s .. '&offset=' .. (tonumber(url) * perpage) .. '&max=' .. perpage; end + if http.get(s) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//table[@class="cTable"]//tr/td/a[not(@class)]') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('./text()', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'AllHentai' + m.rooturl = 'http://allhentai.ru' + m.category = 'Russian' + m.lastupdated='April 26, 2018' + m.sortedlist = true + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' + m.onbeforedownloadimage = 'beforedownloadimage' +end From cb60919c5a59bf11599a6fb9c8dde5f7adc4623a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 27 Apr 2018 10:37:06 +0300 Subject: [PATCH 2577/2794] updater, increase retry count --- updaterslim/updater.lpr | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/updaterslim/updater.lpr b/updaterslim/updater.lpr index 4cbb63542..38c938db9 100644 --- a/updaterslim/updater.lpr +++ b/updaterslim/updater.lpr @@ -8,6 +8,9 @@ {$endif} sysutils, process; +const + RetryCount = 30; + var exefile, zipexefile, updatepackagefile, maindir, ozipexefile, oexefile: String; counter: Integer; @@ -64,9 +67,9 @@ procedure cleanupfailed; while FileExists(exefile) do begin if DeleteFile(exefile) then break; Inc(counter); - writeln('Waiting to close ',counter,'/',10,' ',exefile); + writeln('Waiting to close ',counter,'/',RetryCount,' ',exefile); Sleep(1000); - if counter=10 then break; + if counter=RetryCount then break; end; if not FileExists(exefile) then begin From 7bdc06fa1d497f10cf083d9f9d55d029400e6715 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Mon, 30 Apr 2018 09:49:39 +0300 Subject: [PATCH 2578/2794] frmMain, use space key to check/uncheck chapters --- mangadownloader/forms/frmMain.lfm | 1 + mangadownloader/forms/frmMain.pas | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index 6f7933b35..f784e3712 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -958,6 +958,7 @@ object MainForm: TMainForm OnBeforeCellPaint = clbChapterListBeforeCellPaint OnGetText = clbChapterListGetText OnInitNode = clbChapterListInitNode + OnKeyDown = clbChapterListKeyDown end object btDownload: TBitBtn AnchorSideLeft.Control = btAddToFavorites diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 8095f68a4..f8c66db5f 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -453,6 +453,8 @@ TMainForm = class(TForm) var CellText: String); procedure clbChapterListInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure clbChapterListKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); procedure edDownloadsSearchButtonClick(Sender: TObject); procedure edDownloadsSearchChange(Sender: TObject); procedure edFavoritesSearchButtonClick(Sender: TObject); @@ -2674,6 +2676,29 @@ procedure TMainForm.clbChapterListInitNode(Sender: TBaseVirtualTree; if Assigned(Node) then Node^.CheckType:=ctCheckBox; end; +procedure TMainForm.clbChapterListKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +var + i: Cardinal; + xNode: PVirtualNode; +begin + if (Key = VK_SPACE) and (clbChapterList.SelectedCount > 0) then + begin + xNode := clbChapterList.GetFirstSelected; + for i := 0 to clbChapterList.SelectedCount - 1 do + begin + if clbChapterList.Selected[xNode] then + if xNode^.CheckState = csUncheckedNormal then + xNode^.CheckState := csCheckedNormal + else if xNode^.CheckState = csCheckedNormal then + xNode^.CheckState := csUncheckedNormal; + clbChapterList.InvalidateNode(xNode); + xNode := clbChapterList.GetNextSelected(xNode); + end; + Key := VK_UNKNOWN; + end; +end; + procedure TMainForm.edDownloadsSearchButtonClick(Sender: TObject); begin edDownloadsSearch.Clear; From c26007f61a18a673029faebcfc094ba83b62ea86 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sat, 5 May 2018 09:42:12 +0300 Subject: [PATCH 2579/2794] don't switch to Modules tab on startup --- mangadownloader/forms/frmLuaModulesUpdater.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index 840bfa3e2..bd7ea7fdb 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -504,7 +504,7 @@ procedure TCheckUpdateThread.AddThread(const T: TDownloadThread); procedure TCheckUpdateThread.SyncStartChecking; begin FOwner.btCheckUpdate.Caption := RS_Checking; - FOwner.btCheckUpdateTerminate.Show; + FOwner.btCheckUpdateTerminate.Visible := True; FOwner.tmRepaintList.Enabled := True; end; @@ -540,7 +540,7 @@ procedure TCheckUpdateThread.SyncFinishDownload; procedure TCheckUpdateThread.SyncFinal; begin - FOwner.btCheckUpdateTerminate.Hide; + FOwner.btCheckUpdateTerminate.Visible := False; FOwner.btCheckUpdate.Caption := RS_CheckUpdate; FOwner.ThreadCheck := nil; FOwner.tmRepaintList.Enabled := False; @@ -842,7 +842,7 @@ procedure TLuaModulesUpdaterForm.FormCreate(Sender: TObject); InitCriticalSection(FListCS); Repos := TLuaModulesRepos.Create; btCheckUpdate.Caption := RS_CheckUpdate; - btCheckUpdateTerminate.Hide; + btCheckUpdateTerminate.Visible := False; vtLuaModulesRepos.NodeDataSize := SizeOf(TLuaModuleRepo); LoadLocalRepos; end; From db777d5fec31690d877d891602c75b0810bdb36a Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Wed, 9 May 2018 09:03:59 +0300 Subject: [PATCH 2580/2794] MangaRock, fix GetNameAndLink --- baseunits/modules/MangaRock.pas | 43 +++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas index 457766348..a3249f049 100644 --- a/baseunits/modules/MangaRock.pas +++ b/baseunits/modules/MangaRock.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, webp, MemBitmap, Math, xquery; + XQueryEngineHTML, httpsendthread, synautil, webp, fpjson, Math, xquery; implementation @@ -143,30 +143,39 @@ function DownloadImage(const DownloadThread: TDownloadThread; function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; + + function GetRequest(const AURL: String): String; + var + offset, i, ubound: Integer; + begin + Result := '[]'; + offset := StrToInt(AURL) * PerPage; + ubound := Min(offset + PerPage - 1, mangaList.Count - 1); + with TJSONArray.Create do + try + for i := offset to ubound do + Add(mangaList[i]); + Result := FormatJSON([foSkipWhiteSpace, foSingleLineArray]); + finally + Free; + end; + end; + var - offset, i, ubound: Integer; - request, name: String; + v: IXQValue; begin Result := NET_PROBLEM; if (MangaInfo = nil) or (mangaList = nil) then Exit(UNKNOWN_ERROR); - offset := StrToInt(AURL) * PerPage; - ubound := Min(offset + PerPage - 1, mangaList.Count - 1); - request := '["' + mangaList[offset] + '"'; - for i := offset + 1 to ubound do - request += ',"' + mangaList[i] + '"'; - request += ']'; - MangaInfo.FHTTP.MimeType := 'application/json'; - if MangaInfo.FHTTP.POST(ModuleApiUrl + '/meta', request) then + if MangaInfo.FHTTP.POST(ModuleApiUrl + '/meta', GetRequest(AURL)) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - for i := offset to ubound do begin - name := XPathString('json(*).data("' + mangaList[i] + '").name'); - ANames.Add(name); - ALinks.Add(Module.RootURL + '/manga/' + mangaList[i]); + for v in XPath('json(*)/data/*') do begin + ANames.Add(XPathString('name', v)); + ALinks.Add(Module.RootURL + '/manga/' + XPathString('oid', v)); end; finally Free; @@ -187,9 +196,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try XPathStringAll('json(*).data()', mangaList); - Page := mangaList.Count div PerPage; - if mangaList.Count mod PerPage <> 0 then - Inc(Page); + Page := round(ceil(double(mangaList.Count) / PerPage)); finally Free; end; From eebc88d2d2ae6828e4a46b11f3f38ad816137286 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 07:38:53 +0300 Subject: [PATCH 2581/2794] add RawQQ [raw] fixes #1224 --- lua/modules/Lhscans.lua | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua index 5ecd41d2f..43c16b1f3 100644 --- a/lua/modules/Lhscans.lua +++ b/lua/modules/Lhscans.lua @@ -10,7 +10,13 @@ mangainfo.authors=x.xpathstring('//ul[@class="manga-info"]/li[contains(., "Author")]//a') mangainfo.genres=x.xpathstringall('//ul[@class="manga-info"]/li[contains(., "Genre")]//a') mangainfo.summary=x.xpathstring('//h3[text()="Description"]/following-sibling::p') + if mangainfo.summary == '' then + mangainfo.summary=x.xpathstring('//div[@class="detail"]/div[@class="content"]') + end x.xpathhrefall('//div[@id="tab-chapper"]//table/tbody/tr/td/a', mangainfo.chapterlinks, mangainfo.chapternames) + if mangainfo.chapterlinks.count == 0 then + x.xpathhrefall('//div[@id="list-chapters"]//a[@class="chapter"]', mangainfo.chapterlinks, mangainfo.chapternames) + end InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error else @@ -44,14 +50,21 @@ function getnameandlink() end end -function Init() - local m=NewModule() - m.category='Raw' - m.website='Lhscans' - m.rooturl='http://rawlh.com' - m.lastupdated='April 9, 2018' +function AddWebsiteModule(name, url, cat) + local m = NewModule() + m.category = cat + m.Website = name + m.RootURL = url + m.LastUpdated = 'April 9, 2018' m.totaldirectory=1 m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' + return m +end + +function Init() + local cat = 'Raw' + AddWebsiteModule('Lhscans', 'http://rawlh.com', cat) + AddWebsiteModule('RawQQ', 'https://rawqq.com', cat) end From 81a10a2810488d217f2acbd1d512c915bdc7bbba Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 07:40:01 +0300 Subject: [PATCH 2582/2794] uBaseUnit, fix CleanURL should be able to handle urls like '¶m=http://<url>' --- baseunits/uBaseUnit.pas | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index aaaeea12f..2625d17e3 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -2276,8 +2276,7 @@ function CleanURL(const URL: String): String; while Pos('/', Result) = 1 do Delete(Result, 1, 1); end; - while Pos('//', Result) > 0 do - Result := StringReplace(Result, '//', '/', [rfReplaceAll]); + Result := ReplaceRegExpr('([^:])[\/]{2,}', Result, '$1/', True); Result := p + Result; end; From 6a51cfdd4f0483c3ae360f5e617fb0f7cffdd45e Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 09:12:13 +0300 Subject: [PATCH 2583/2794] JapScan, fix download --- lua/modules/JapScan.lua | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/lua/modules/JapScan.lua b/lua/modules/JapScan.lua index b66976905..f681233e4 100644 --- a/lua/modules/JapScan.lua +++ b/lua/modules/JapScan.lua @@ -34,6 +34,7 @@ function getpagenumber() if http.get(MaybeFillHost(module.rooturl, url)) then local x=TXQuery.Create(http.Document) x.xpathstringall('//select[@id="pages"]/option/@value', task.pagelinks) + task.pagecontainerlinks.text = http.cookies.text else return false end @@ -51,9 +52,40 @@ function getnameandlink() end function downloadimage() + http.reset() + http.cookies.text = task.pagecontainerlinks.text if http.get(MaybeFillHost(module.rooturl, url)) then local x = TXQuery.Create(http.document) - return http.get(x.xpathstring('//img[@id="image"]/@src')) + local img = x.xpathstring('//img[@id="image"]/@src') + if img ~= '' then + return http.get(img) + end + local nom = x.xpathstring('//*[@id="mangas"]/@data-nom'):gsub('/', '_'):gsub('%?', '') + local mangauri = x.xpathstring('//*[@id="mangas"]/@data-uri') + local chapnom = x.xpathstring('//*[@id="chapitres"]/@data-nom') + local chapuri = x.xpathstring('//*[@id="chapitres"]/@data-uri') + local imgnom = x.xpathstring('//select[@id="pages"]/option[@value="'..url..'"]/@data-img') + local imgurl = 'http://cdn.japscan.cc/cr_images/' .. nom .. '/' + if chapnom == '' then + imgurl = imgurl .. chapuri + else + imgurl = imgurl .. chapnom + end + imgurl = imgurl .. '/' .. imgnom + if http.get(imgurl) then + local s = TImagePuzzle.Create(5, 5) + local n = 0 + local x = {2,4,0,3,1} + local y = {4,3,2,1,0} + for i = 1, 5 do + for j = 1, 5 do + s.matrix[y[i]*5+x[j]] = n + n = n + 1 + end + end + s.descramble(http.document, http.document) + return true + end end return false end From 64030ded201683e3a09c6555b7c488089850f8c6 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 8 May 2018 11:31:25 +0300 Subject: [PATCH 2584/2794] LuaHTTPSend, register LastURL, ResultCode, ResultString properties --- baseunits/lua/LuaHTTPSend.pas | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaHTTPSend.pas b/baseunits/lua/LuaHTTPSend.pas index ec5aa7320..bbccc9aee 100644 --- a/baseunits/lua/LuaHTTPSend.pas +++ b/baseunits/lua/LuaHTTPSend.pas @@ -68,6 +68,24 @@ function http_setproxy(L: Plua_State): Integer; cdecl; lua_tostring(L, 3), lua_tostring(L, 4), lua_tostring(L, 5)); end; +function http_threadlasturl(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).LastURL); + Result := 1; +end; + +function http_threadresultcode(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, TUserData(luaClassGetObject(L)).ResultCode); + Result := 1; +end; + +function http_threadresultstring(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, TUserData(luaClassGetObject(L)).ResultString); + Result := 1; +end; + const methods: packed array [0..7] of luaL_Reg = ( (name: 'GET'; func: @http_get), @@ -79,8 +97,11 @@ function http_setproxy(L: Plua_State): Integer; cdecl; (name: 'SetProxy'; func: @http_setproxy), (name: nil; func: nil) ); - props: packed array[0..1] of luaL_Reg_prop = ( + props: packed array[0..4] of luaL_Reg_prop = ( (name: 'Terminated'; funcget: @http_threadterminated; funcset: nil), + (name: 'LastURL'; funcget: @http_threadlasturl; funcset: nil), + (name: 'ResultCode'; funcget: @http_threadresultcode; funcset: nil), + (name: 'ResultString'; funcget: @http_threadresultstring; funcset: nil), (name: nil; funcget: nil; funcset: nil) ); From 9a6ccebb8641d6b06365378f3bdc2d7c2b6e51fe Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Tue, 8 May 2018 15:53:26 +0300 Subject: [PATCH 2585/2794] ComicoCoID, fix manga list update --- lua/modules/ComicoCoID.lua | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lua/modules/ComicoCoID.lua b/lua/modules/ComicoCoID.lua index beea20600..947cdd6d7 100644 --- a/lua/modules/ComicoCoID.lua +++ b/lua/modules/ComicoCoID.lua @@ -37,17 +37,29 @@ function getpagenumber() return true end +local dirurls = { + '/weekly/list?page=', + '/titles/completed?page=' +} + function getnameandlink() - if http.get(module.rooturl .. '/weekly/list?page=' .. IncStr(url)) then + local lurl = dirurls[module.CurrentDirectoryIndex+1] + if http.get(module.rooturl .. lurl .. IncStr(url)) then local x = TXQuery.Create(http.Document) - if x.xpathcount('json(*).data()') > 0 then - updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + local s = 'json(*).data().list()' + if module.CurrentDirectoryIndex == 1 then + s = 'json(*).data.list()' end - local v = x.xpath('json(*).data().list()') + local v = x.xpath(s) + local hasTitles = false for i = 1, v.count do local v1 = v.get(i) links.add(module.rooturl..'/titles/'..x.xpathstring('id', v1)) names.add(x.xpathstring('name', v1)) + hasTitles = true + end + if hasTitles then + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 end end return net_problem @@ -62,4 +74,5 @@ function Init() m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' + m.totaldirectory = 2 end From f526a992aec5aacd95734aaced0d9fedb26c84b5 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 09:28:16 +0300 Subject: [PATCH 2586/2794] update readme --- README.md | 35 +++++++++++++++++++++++++++++++++++ readme.txt | 38 -------------------------------------- 2 files changed, 35 insertions(+), 38 deletions(-) create mode 100644 README.md delete mode 100644 readme.txt diff --git a/README.md b/README.md new file mode 100644 index 000000000..dcc5d1068 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# The Free Manga Downloader (FMD) + +<sup>(Forked from https://sf.net/p/fmd)</sup> + +## Download the latest release + +[![GitHub release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.154.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0.7z) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.154.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0_Win64.7z) + +## Content + +- [About FMD](#about-fmd) +- [Build instructions](#build-instructions) +- [Localization](#localization) + +## About FMD + +The Free Manga Downloader is a free open source application written in Object Pascal for managing and downloading manga from various websites. The source code was released under the GPLv2 license. FMD homesite is at https://github.com/riderkick/FMD or http://sf.net/p/newfmd. + +## Build instructions + +In order to build FMD from the source code, you must install the latest version of Lazarus and Free Pascal Compiler from http://www.lazarus-ide.org/. Then you must install the following 3rd party libraries and components: + + - [RichMemo](https://sourceforge.net/projects/lazarus-ccr/) + - [Virtual TreeView](https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4) + - [Synapse](http://synapse.ararat.cz/) + - [InternetTools](https://github.com/benibela/internettools) + - [BESEN](https://github.com/BeRo1985/besen) + - [MultiLog](https://github.com/blikblum/multilog) + - [DCPCypt](https://sourceforge.net/projects/lazarus-ccr/) + +After everything is installed, open the file `md.lpi` by using Lazarus IDE, select `Run -> Build` to build the source code. If everything is ok, the binary file should be in `FMD_source_code_folder/bin`. + +## Localization + +Translations are stored inside `languages` folder with `.po` extension. In order to translate FMD to your native languages you can copy `fmd.po` and rename it to `fmd.xx.po`, where `xx` stand for two-letter language code. Additionally you can add country code at the end of language code. For reference you can look at http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes and http://en.wikipedia.org/wiki/ISO_3166-1. For example `id_ID` will be recognized as `Bahasa Indonesia (Indonesia)`. To translate the content of the file you need to use translation tools like [Poedit](https://poedit.net). Once you have finished translating all of its content you can launch FMD and it will automatically detect your new languages upon startup. diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 96662b853..000000000 --- a/readme.txt +++ /dev/null @@ -1,38 +0,0 @@ -FMD -The Free Manga Downloader. - ---------------------------------- - -Content: -1.) About FMD -2.) Build instructions -3.) Localization - ---------------------------------- - -FMD homesite is at http://sourceforge.net/projects/fmd/ or http://akarink.wordpress.com - ---------------------------------- - -1.) About FMD - -The Free Manga Downloader is a free open source application written in Object Pascal for managing and downloading manga from various websites. The source code was released under the GPLv2 license. - -2.) Build instructions - -In order to build FMD from the source code, you must install the latest version of Lazarus and Free Pascal Compiler from http://www.lazarus-ide.org/. Then you must install the following 3rd party libraries and components: - - RichMemo, https://sourceforge.net/projects/lazarus-ccr/ - - Virtual TreeView, https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4 - - Synapse, http://synapse.ararat.cz/ - - InternetTools, https://github.com/benibela/internettools - - BESEN, https://github.com/BeRo1985/besen - - MultiLog, https://github.com/blikblum/multilog - - DCPCypt, https://sourceforge.net/projects/lazarus-ccr/ - -After everything is installed, open the file md.lpi by using Lazarus IDE, select Run->Build to build the source code. If everything is ok, the binary file should be in FMD_source_code_folder/bin - -3.) Localization - -Translations are stored inside "languages" folder with .po extension. In order to translate FMD to your native languages you can copy "fmd.po" and rename it to "fmd.xx.po", where xx stand for two-letter language code. Additionally you can add country code at the end of language code. For reference you can look at http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes and http://en.wikipedia.org/wiki/ISO_3166-1. For example "id_ID" will be recognized as "Bahasa Indonesia (Indonesia)". To translate the content of the file you need to use translation tools like Poedit. Once you have finished translating all of its content you can launch FMD and it will automatically detect your new languages upon startup. - ---------------------------------- From 6dd14975bcc1245cd1513e04eee276dff66f452f Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 11:41:39 +0300 Subject: [PATCH 2587/2794] Bamtoki, fix download --- lua/modules/Bamtoki.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lua/modules/Bamtoki.lua b/lua/modules/Bamtoki.lua index c9dcac199..01c9daa83 100644 --- a/lua/modules/Bamtoki.lua +++ b/lua/modules/Bamtoki.lua @@ -21,6 +21,7 @@ function getpagenumber() local s = DecodeBase64(x.xpathstring('//*[@id="tooncontentdata"]')) x.parsehtml(s) x.xpathstringall('//img/@src', task.pagelinks) + task.pagecontainerlinks.values[0] = http.cookies.text else return false end @@ -48,14 +49,22 @@ function getnameandlink() end end +function beforedownloadimage() + http.reset() + http.cookies.text = task.pagecontainerlinks.values[0] + http.headers.values['Referer'] = module.rooturl + return true +end + function Init() local m = NewModule() m.website = 'Bamtoki' - m.rooturl = 'https://webtoon.bamtoki.com' + m.rooturl = 'https://webtoon.bamtoki.se' m.category = 'Raw' m.lastupdated='April 11, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' + m.onbeforedownloadimage='beforedownloadimage' m.totaldirectory = #dirurls end From 141028ebc6e156fcd9c08c7532263501dfd69e07 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 17:53:49 +0300 Subject: [PATCH 2588/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index 2bef77944..c9c5cc3a8 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit 2bef7794450ec27c25530fa0e502edf14ab69e7d +Subproject commit c9c5cc3a87271180d4fb5bb0b17040763d2cfe06 From e1b48aa1f10b5ae5f26baead54e9a29cf0199ba9 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 21:06:24 +0300 Subject: [PATCH 2589/2794] rename units to respect case sensitivity --- baseunits/ModuleList.inc | 2 +- baseunits/lua/LuaBase.pas | 2 +- baseunits/lua/LuaStrings.pas | 2 +- baseunits/lua/LuaWebsiteModules.pas | 2 +- baseunits/lua/{luaXQuery.pas => LuaXQuery.pas} | 0 baseunits/modules/{Blogtruyen.pas => BlogTruyen.pas} | 0 baseunits/modules/{Submanga.pas => SubManga.pas} | 0 .../modules/{TonarinoYoungJump.pas => TonariNoYoungJump.pas} | 0 8 files changed, 4 insertions(+), 4 deletions(-) rename baseunits/lua/{luaXQuery.pas => LuaXQuery.pas} (100%) rename baseunits/modules/{Blogtruyen.pas => BlogTruyen.pas} (100%) rename baseunits/modules/{Submanga.pas => SubManga.pas} (100%) rename baseunits/modules/{TonarinoYoungJump.pas => TonariNoYoungJump.pas} (100%) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index d6cf5255f..4e84f6a4a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -55,7 +55,7 @@ uses MangaWindow, // Raw Official SundayWebEvery, - TonarinoYoungJump, + TonariNoYoungJump, YoungAceUp, NewType, Comico, diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 77725a02f..18b57a117 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -23,7 +23,7 @@ function LuaLoadFromStream(L: Plua_State; AStream: TMemoryStream; AName: PAnsiCh implementation uses - luaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog, + LuaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog, LuaCrypto, LuaImagePuzzle; function luabase_print(L: Plua_State): Integer; cdecl; diff --git a/baseunits/lua/LuaStrings.pas b/baseunits/lua/LuaStrings.pas index 31aa26569..23b52c7dc 100644 --- a/baseunits/lua/LuaStrings.pas +++ b/baseunits/lua/LuaStrings.pas @@ -1,4 +1,4 @@ -unit luaStrings; +unit LuaStrings; {$mode objfpc}{$H+} diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index be3988c62..d5e9b0838 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -107,7 +107,7 @@ implementation uses FMDOptions, FileUtil, MultiLog, LuaClass, LuaBase, LuaMangaInfo, LuaHTTPSend, - LuaXQuery, LuaUtils, LuaDownloadTask, LuaUpdateListManager, luaStrings, uData, + LuaXQuery, LuaUtils, LuaDownloadTask, LuaUpdateListManager, LuaStrings, uData, uDownloadsManager, xquery, httpsendthread, FMDVars; function DoBeforeUpdateList(const Module: TModuleContainer): Boolean; diff --git a/baseunits/lua/luaXQuery.pas b/baseunits/lua/LuaXQuery.pas similarity index 100% rename from baseunits/lua/luaXQuery.pas rename to baseunits/lua/LuaXQuery.pas diff --git a/baseunits/modules/Blogtruyen.pas b/baseunits/modules/BlogTruyen.pas similarity index 100% rename from baseunits/modules/Blogtruyen.pas rename to baseunits/modules/BlogTruyen.pas diff --git a/baseunits/modules/Submanga.pas b/baseunits/modules/SubManga.pas similarity index 100% rename from baseunits/modules/Submanga.pas rename to baseunits/modules/SubManga.pas diff --git a/baseunits/modules/TonarinoYoungJump.pas b/baseunits/modules/TonariNoYoungJump.pas similarity index 100% rename from baseunits/modules/TonarinoYoungJump.pas rename to baseunits/modules/TonariNoYoungJump.pas From dbd1dbec509b7e8306572276896f91fdd0970b08 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 21:08:04 +0300 Subject: [PATCH 2590/2794] rename lua lib --- baseunits/lua/lua53.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/lua53.pas b/baseunits/lua/lua53.pas index 417ec796a..ab293cd3c 100644 --- a/baseunits/lua/lua53.pas +++ b/baseunits/lua/lua53.pas @@ -103,7 +103,7 @@ interface {$IFDEF MSWINDOWS} LUA_LIB_NAME = 'lua53.dll'; {$ELSE} - LUA_LIB_NAME = 'liblua53.so'; + LUA_LIB_NAME = 'liblua5.3.so'; {$ENDIF} const From 2246c8b9ba6fd4d73e59d9d321fdb8418b2e523c Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Fri, 11 May 2018 21:08:51 +0300 Subject: [PATCH 2591/2794] fix webp --- baseunits/webp.pas | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/baseunits/webp.pas b/baseunits/webp.pas index a270860f2..de7aaf1be 100644 --- a/baseunits/webp.pas +++ b/baseunits/webp.pas @@ -5,11 +5,11 @@ interface uses - Classes, SysUtils, Windows, MemBitmap, Dynlibs; + Classes, SysUtils, MemBitmap, Dynlibs; var WebPLibHandle: TLibHandle = 0; - DLLWebPName: String = 'libwebp.dll'; + DLLWebPName: String = {$IFDEF LINUX} 'libwebp.so' {$ELSE} 'libwebp.dll' {$ENDIF}; function IsWebPModuleLoaded: Boolean; procedure InitWebPModule; @@ -23,8 +23,8 @@ implementation FMDOptions, SyncObjs; type - TWebPGetInfo = function (data: LPVOID; data_size: UInt32; width, height: pInt32): Int32; cdecl; - TWebPDecodeBGRAInto = function (data: LPVOID; data_size: UInt32; output: LPVOID; output_size: UInt32; stride: Int32): pInt32; cdecl; + TWebPGetInfo = function (data: Pointer; data_size: UInt32; width, height: pInt32): Int32; cdecl; + TWebPDecodeBGRAInto = function (data: Pointer; data_size: UInt32; output: Pointer; output_size: UInt32; stride: Int32): pInt32; cdecl; TWebPGetDecoderVersion = function (): Int32; cdecl; var @@ -81,7 +81,7 @@ procedure DestroyWebPModule; end; end; -function WebPGetInfo(data: LPVOID; data_size: UInt32; width, height: pInt32): Int32; +function WebPGetInfo(data: Pointer; data_size: UInt32; width, height: pInt32): Int32; begin if IsWebPModuleLoaded and Assigned(pWebPGetInfo) then Result := pWebPGetInfo(data, data_size, width, height) @@ -89,7 +89,7 @@ function WebPGetInfo(data: LPVOID; data_size: UInt32; width, height: pInt32): In Result := 0; end; -function WebPDecodeBGRAInto(data: LPVOID; data_size: UInt32; output: LPVOID; output_size: UInt32; stride: Int32): pInt32; +function WebPDecodeBGRAInto(data: Pointer; data_size: UInt32; output: Pointer; output_size: UInt32; stride: Int32): pInt32; begin if IsWebPModuleLoaded and Assigned(pWebPDecodeBGRAInto) then Result := pWebPDecodeBGRAInto(data, data_size, output, output_size, stride) @@ -135,7 +135,7 @@ function WebPToMemBitmap(webp: TMemoryStream): TMemBitmap; scan := WebPDecodeBGRAInto(webp.Memory, webp.Size, r.ScanLine[0], stride * height, stride); - if scan <> PLONG(r.ScanLine[0]) then begin + if scan <> PLongint(r.ScanLine[0]) then begin r.Free; Exit; end; From 438438063f1a89fe9db688e25488b174fcdfb7e5 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 13 May 2018 06:57:53 +0300 Subject: [PATCH 2592/2794] MangaKu, change domain, fix download fixes #1226 --- lua/modules/MangaKu.lua | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lua/modules/MangaKu.lua b/lua/modules/MangaKu.lua index a6ffde8b0..e169257ee 100644 --- a/lua/modules/MangaKu.lua +++ b/lua/modules/MangaKu.lua @@ -25,22 +25,24 @@ function getpagenumber() task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl,url)) then x=TXQuery.Create(http.Document) - x.xpathstringall('//div[@class="separator"]/a/img/@src', task.pagelinks) - if task.pagelinks.count == 0 then - if http.get(MaybeFillHost('http://mangaku.co',url)) then - x=TXQuery.Create(http.Document) - x.xpathstringall('//div[@class="separator"]/a/img/@src', task.pagelinks) - return true - else - return false - end - else - return true - end + x.xpathstringall('//div[@class="separator"]/a/img/@src', task.pagelinks) + if task.pagelinks.count == 0 then + x.xpathstringall('//img[./@*[starts-with(name(), "data-original")]]/@src', task.pagelinks) + end + if task.pagelinks.count == 0 then + if http.get(MaybeFillHost('http://mangaku.co',url)) then + x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="separator"]/a/img/@src', task.pagelinks) + return true + else + return false + end + else + return true + end else return false end - return true end function getnameandlink() @@ -56,7 +58,7 @@ function Init() m=NewModule() m.category='Indonesian' m.website='MangaKu' - m.rooturl='http://mangaku.web.id' + m.rooturl='http://mangaku.in' m.lastupdated='February 17, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' From 18c867f4349c4a59c5621776db1dd91773b99795 Mon Sep 17 00:00:00 2001 From: kmvi <kmvi@users.noreply.github.com> Date: Sun, 13 May 2018 09:44:33 +0300 Subject: [PATCH 2593/2794] initial epub support #1227 --- baseunits/uBaseUnit.pas | 16 +- baseunits/uDownloadsManager.pas | 1 + baseunits/uEpub.pas | 243 +++++++++++++++++++++++++ baseunits/uPacker.pas | 43 ++++- mangadownloader/forms/frmMain.lfm | 5 +- mangadownloader/forms/frmMain.pas | 4 +- mangadownloader/languages/fmd.de.po | 1 + mangadownloader/languages/fmd.el_GR.po | 1 + mangadownloader/languages/fmd.en.po | 8 + mangadownloader/languages/fmd.es.po | 7 + mangadownloader/languages/fmd.id_ID.po | 2 + mangadownloader/languages/fmd.pl_PL.po | 1 + mangadownloader/languages/fmd.po | 1 + mangadownloader/languages/fmd.pt_BR.po | 126 +++++++++++-- mangadownloader/languages/fmd.ru_RU.po | 2 + mangadownloader/languages/fmd.tr_TR.po | 2 + 16 files changed, 437 insertions(+), 26 deletions(-) create mode 100644 baseunits/uEpub.pas diff --git a/baseunits/uBaseUnit.pas b/baseunits/uBaseUnit.pas index 2625d17e3..eb7120eaa 100644 --- a/baseunits/uBaseUnit.pas +++ b/baseunits/uBaseUnit.pas @@ -233,7 +233,7 @@ interface MangaInfo_StatusCompleted = '0'; MangaInfo_StatusOngoing = '1'; - FMDSupportedOutputExt: array[0..2] of ShortString = ('.zip', '.cbz', '.pdf'); + FMDSupportedOutputExt: array[0..3] of ShortString = ('.zip', '.cbz', '.pdf', '.epub'); FMDImageFileExt: array[0..3] of ShortString = ('.png', '.gif', '.jpg', '.webp'); {$ifdef windows} // MAX_PATH = 260 @@ -600,6 +600,8 @@ procedure CopyImageRect(const Source, Dest: TFPCustomImage; const DestX, DestY: // merge 2 images to one function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; const Landscape: Boolean = False): Boolean; +function GetMimeType(const imgFileName: String): String; + // sort procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QuickSortData(var merge: TStringList); @@ -3333,6 +3335,18 @@ function Merge2Image(const Directory, ImgName1, ImgName2, FinalName: String; con end; end; +function GetMimeType(const imgFileName: String): String; +begin + case ExtractFileExt(imgFileName) of + '.jpeg', '.jpg': Result := 'image/jpeg'; + '.png': Result := 'image/png'; + '.gif': Result := 'image/gif'; + '.bmp': Result := 'image/bmp'; + '.webp': Result := 'image/webp'; + else Result := ''; + end; +end; + procedure QuickSortChapters(var chapterList, linkList: TStringList); procedure QSort(L, R: Integer); diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 1b833b35b..08672f0d1 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -510,6 +510,7 @@ function TTaskThread.Compress: Boolean; 1: uPacker.Format := pfZIP; 2: uPacker.Format := pfCBZ; 3: uPacker.Format := pfPDF; + 4: uPacker.Format := pfEPUB; end; uPacker.CompressionQuality := OptionPDFQuality; uPacker.Path := CurrentWorkingDir; diff --git a/baseunits/uEpub.pas b/baseunits/uEpub.pas new file mode 100644 index 000000000..43c4714cc --- /dev/null +++ b/baseunits/uEpub.pas @@ -0,0 +1,243 @@ +unit uEpub; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, fgl; + +type + TStreams = specialize TFPGList<TStream>; + + TEpubBuilder = class + private + FTitle, FUuid: String; + FMimeType, FContainer, FStyle, FContent, FToc: TStringStream; + FImageNames: TStringList; + FPages: TStreams; + function CreateXHTMLPage(const imageName, pageTitle: String): TStringStream; + function CreateContent: TStringStream; + function CreateToc: TStringStream; + public + constructor Create; + destructor Destroy; override; + procedure AddImage(const path: String); + procedure SaveToStream(const stream: TStream); + property Title: String read FTitle write FTitle; + end; + +implementation + +uses Zipper, htmlelements, uBaseUnit; + +const + CONTAINER: String = + '<?xml version="1.0" encoding="UTF-8" ?>' + LineEnding + + '<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">' + LineEnding + + ' <rootfiles>' + LineEnding + + ' <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>' + LineEnding + + ' </rootfiles>' + LineEnding + + '</container>' + LineEnding; + + CONTENT: String = + '<?xml version="1.0" encoding="UTF-8"?>' + LineEnding + + '<package xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/" ' + + 'xmlns:opf="http://www.idpf.org/2007/opf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' + + 'xmlns:dcterms="http://purl.org/dc/terms/" unique-identifier="bookid" version="2.0">' + LineEnding + + ' <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">' + LineEnding + + ' <dc:title>%s</dc:title>' + LineEnding + + ' <dc:language>und</dc:language>' + LineEnding + + ' <dc:identifier id="bookid" opf:scheme="UUID">urn:uuid:%s</dc:identifier>' + LineEnding + + ' </metadata>' + LineEnding + + ' <manifest>' + LineEnding + + ' <item id="_toc" href="toc.ncx" media-type="application/x-dtbncx+xml"/>' + LineEnding + + ' <item id="_style" href="style.css" media-type="text/css"/>' + LineEnding + + '%s' + LineEnding + + ' </manifest>' + LineEnding + + ' <spine toc="_toc">' + LineEnding + + '%s' + LineEnding + + ' </spine>' + LineEnding + + '</package>'; + + CONTENT_ITEM: String = + ' <item id="%s" href="%s" media-type="%s"/>' + LineEnding; + + CONTENT_ITEMREF: String = + ' <itemref idref="%s"/>' + LineEnding; + + TOC: String = + '<?xml version="1.0" encoding="UTF-8"?>' + LineEnding + + '<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">' + LineEnding + + ' <head>' + LineEnding + + ' <meta name="dtb:uid" content="urn:uuid:%s"/>' + LineEnding + + ' </head>' + LineEnding + + ' <docTitle>' + LineEnding + + ' <text>%s</text>' + LineEnding + + ' </docTitle>' + LineEnding + + ' <navMap>' + LineEnding + + '%s' + LineEnding + + ' </navMap>' + LineEnding + + '</ncx>' + LineEnding; + + NAV_POINT: String = + ' <navPoint id="toc_%d" playOrder="%d">' + LineEnding + + ' <navLabel>' + LineEnding + + ' <text>Page %d</text>' + LineEnding + + ' </navLabel>' + LineEnding + + ' <content src="%s"/>' + LineEnding + + ' </navPoint>' + LineEnding; + + PAGE: String = + '<?xml version="1.0" encoding="utf-8"?>' + LineEnding + + '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' + LineEnding + + '<html xmlns="http://www.w3.org/1999/xhtml">' + LineEnding + + '<head>' + LineEnding + + ' <link href="style.css" rel="stylesheet" type="text/css"/>' + LineEnding + + ' <title>%s' + LineEnding + + '' + LineEnding + + '' + LineEnding + + '
    ' + LineEnding + + '' + LineEnding + + '' + LineEnding; + + STYLE: String = + 'body {' + LineEnding + + '}' + LineEnding; + +function NewUUID: String; +var + guid: TGuid; +begin + CreateGUID(guid); + SetLength(Result, 36); + StrLFmt(PChar(Result), 36, '%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x', + [ + Longint(GUID.D1), GUID.D2, GUID.D3, + GUID.D4[0], GUID.D4[1], GUID.D4[2], GUID.D4[3], + GUID.D4[4], GUID.D4[5], GUID.D4[6], GUID.D4[7] + ]); + Result := LowerCase(Result); +end; + +function GetImageName(const index: Integer; const fileName: String): String; +begin + Result := Format('%.4d%s', [index+1, ExtractFileExt(fileName)]); +end; + +function TEpubBuilder.CreateXHTMLPage(const imageName, pageTitle: String): TStringStream; +begin + Result := TStringStream.Create(Format(PAGE, [EscapeHTML(pageTitle), imageName])); +end; + +function TEpubBuilder.CreateContent: TStringStream; +var + pageId, imageId, imageName, pageName: String; + items: String = ''; + refs: String = ''; + i: Integer; +begin + for i := 0 to FImageNames.Count-1 do begin + pageId := Format('page%.4d', [i+1]); + imageId := Format('image%.4d', [i+1]); + imageName := 'images/' + GetImageName(i, FImageNames[i]); + pageName := Format('%.4d.xhtml', [i+1]); + items += Format(CONTENT_ITEM, [imageId, imageName, GetMimeType(FImageNames[i])]); + items += Format(CONTENT_ITEM, [pageId, pageName, 'application/xhtml+xml']); + refs += Format(CONTENT_ITEMREF, [pageId]); + end; + Result := TStringStream.Create(Format(CONTENT, [EscapeHTML(Title), FUuid, items, refs])); +end; + +function TEpubBuilder.CreateToc: TStringStream; +var + navPoints: String = ''; + i: Integer; +begin + for i := 0 to FImageNames.Count-1 do begin + navPoints += Format(NAV_POINT, [i+1, i+1, i+1, Format('%.4d.xhtml', [i+1])]); + end; + Result := TStringStream.Create(Format(TOC, [FUuid, Title, navPoints])); +end; + +procedure TEpubBuilder.AddImage(const path: String); +begin + FImageNames.Add(path); +end; + +procedure TEpubBuilder.SaveToStream(const stream: TStream); +var + zip: TZipper; + i: Integer; + tmp: TStream; + imageName: String; +begin + zip := TZipper.Create; + try + // add mimetype + FMimeType := TStringStream.Create('application/epub+zip'); + zip.Entries.AddFileEntry(FMimeType, 'mimetype'); + + // add META-INF/container.xml + FContainer := TStringStream.Create(CONTAINER); + zip.Entries.AddFileEntry(FContainer, 'META-INF/container.xml'); + + // add css + FStyle := TStringStream.Create(STYLE); + zip.Entries.AddFileEntry(FStyle, 'OEBPS/style.css'); + + for i := 0 to FImageNames.Count-1 do begin + // add image file + imageName := GetImageName(i, FImageNames[i]); + zip.Entries.AddFileEntry(FImageNames[i], 'OEBPS/images/' + imageName); + + // add xhtml file + tmp := CreateXHTMLPage(imageName, Format('%s - %.4d', [Title, i+1])); + zip.Entries.AddFileEntry(tmp, Format('OEBPS/%.4d.xhtml', [i+1])); + FPages.Add(tmp); + end; + + // add content.opf + FContent := CreateContent(); + zip.Entries.AddFileEntry(FContent, 'OEBPS/content.opf'); + + // add toc.ncx + FToc := CreateToc(); + zip.Entries.AddFileEntry(FToc, 'OEBPS/toc.ncx'); + + zip.SaveToStream(stream); + finally + zip.Free; + end; +end; + +constructor TEpubBuilder.Create; +begin + FMimeType := nil; + FContainer := nil; + FStyle := nil; + FContent := nil; + FToc := nil; + FImageNames := TStringList.Create; + FPages := TStreams.Create; + FUuid := NewUUID; +end; + +destructor TEpubBuilder.Destroy; +var + i: Integer; +begin + for i := 0 to FPages.Count-1 do + FPages[i].Free; + FreeAndNil(FPages); + FreeAndNil(FMimeType); + FreeAndNil(FContainer); + FreeAndNil(FImageNames); + FreeAndNil(FStyle); + FreeAndNil(FContent); + FreeAndNil(FToc); + inherited; +end; + +end. + diff --git a/baseunits/uPacker.pas b/baseunits/uPacker.pas index ed200cd79..782a6820e 100644 --- a/baseunits/uPacker.pas +++ b/baseunits/uPacker.pas @@ -12,10 +12,10 @@ interface uses Classes, Zipper, zstream, SysUtils, uBaseUnit, Img2Pdf, FileUtil, lazutf8classes, - LazFileUtils, SimpleException; + LazFileUtils, SimpleException, uEpub; type - TPackerFormat = (pfZIP, pfCBZ, pfPDF); + TPackerFormat = (pfZIP, pfCBZ, pfPDF, pfEPUB); { TPacker } @@ -26,6 +26,7 @@ TPacker = class procedure FileFound(FileIterator: TFileIterator); procedure DoZipCbz; procedure DoPdf; + procedure DoEpub; public Path, FileName: String; @@ -112,6 +113,42 @@ procedure TPacker.DoPdf; end; end; +procedure TPacker.DoEpub; +var + epub: TEpubBuilder; + i: Integer; + fstream: TFileStreamUTF8; +begin + try + epub := TEpubBuilder.Create; + try + epub.Title := GetLastDir(Path); + for i := 0 to FFileList.Count - 1 do + begin + try + epub.AddImage(FFileList[i]); + except + end; + end; + + fstream := TFileStreamUTF8.Create(FSavedFileName, fmCreate); + try + epub.SaveToStream(fstream); + finally + fstream.Free; + end; + finally + epub.Free; + end; + except + on E: Exception do + begin + E.Message := 'DoEpub.Exception'#13#10 + E.Message; + SimpleException.ExceptionHandleSaveLogOnly(Self, E); + end; + end; +end; + function TPacker.Execute: Boolean; var i: Integer; @@ -138,6 +175,7 @@ function TPacker.Execute: Boolean; pfZIP: FExt := '.zip'; pfCBZ: FExt := '.cbz'; pfPDF: FExt := '.pdf'; + pfEPUB: FExt := '.epub'; end; if FileName <> '' then FSavedFileName := FileName + FExt @@ -149,6 +187,7 @@ function TPacker.Execute: Boolean; case Format of pfZIP, pfCBZ: DoZipCbz; pfPDF: DoPdf; + pfEPUB: DoEpub; end; Result := FileExistsUTF8(FSavedFileName); if Result then diff --git a/mangadownloader/forms/frmMain.lfm b/mangadownloader/forms/frmMain.lfm index f784e3712..2eeb0e2a7 100644 --- a/mangadownloader/forms/frmMain.lfm +++ b/mangadownloader/forms/frmMain.lfm @@ -3451,16 +3451,17 @@ object MainForm: TMainForm ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom - ChildSizing.ControlsPerLine = 4 + ChildSizing.ControlsPerLine = 5 ClientHeight = 40 ClientWidth = 724 - Columns = 4 + Columns = 5 ItemIndex = 0 Items.Strings = ( 'None' 'ZIP' 'CBZ' 'PDF' + 'EPUB' ) OnSelectionChanged = rgOptionCompressSelectionChanged ParentFont = False diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index f8c66db5f..35f8e10fe 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -867,7 +867,7 @@ TMangaInfoData = record RS_FilterStatusItems = 'Completed'#13#10'Ongoing'#13#10''; RS_OptionFMDDoItems = 'Nothing'#13#10'Exit'#13#10'Shutdown'#13#10'Hibernate'; RS_DropTargetModeItems = 'Download all'#13#10'Add to favorites'; - RS_OptionCompress = 'None'#13#10'ZIP'#13#10'CBZ'#13#10'PDF'; + RS_OptionCompress = 'None'#13#10'ZIP'#13#10'CBZ'#13#10'PDF'#13#10'EPUB'; RS_WebPConvertTo = 'WebP'#13#10'PNG'#13#10'JPEG'; RS_WebPPNGLevel = 'None'#13#10'Fastest'#13#10'Default'#13#10'Maximum'; @@ -1967,6 +1967,8 @@ procedure TMainForm.miDownloadDeleteTaskClick(Sender: TObject); DeleteFileUTF8(f + '.cbz') else if FileExistsUTF8(f + '.pdf') then DeleteFileUTF8(f + '.pdf') + else if FileExistsUTF8(f + '.epub') then + DeleteFileUTF8(f + '.epub') else if DirectoryExistsUTF8(f) then DeleteDirectory(f, False); end; diff --git a/mangadownloader/languages/fmd.de.po b/mangadownloader/languages/fmd.de.po index 83cae997c..4ddb2abc0 100644 --- a/mangadownloader/languages/fmd.de.po +++ b/mangadownloader/languages/fmd.de.po @@ -391,6 +391,7 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" #: frmmain.rs_optionfmddoitems diff --git a/mangadownloader/languages/fmd.el_GR.po b/mangadownloader/languages/fmd.el_GR.po index d71bc0b14..a3d6b8518 100644 --- a/mangadownloader/languages/fmd.el_GR.po +++ b/mangadownloader/languages/fmd.el_GR.po @@ -395,6 +395,7 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" #: frmmain.rs_optionfmddoitems diff --git a/mangadownloader/languages/fmd.en.po b/mangadownloader/languages/fmd.en.po index 1a98a6221..1d1f7bf7a 100644 --- a/mangadownloader/languages/fmd.en.po +++ b/mangadownloader/languages/fmd.en.po @@ -382,16 +382,24 @@ msgid "One week" msgstr "One week" #: frmmain.rs_optioncompress +#, fuzzy +#| msgid "" +#| "None\n" +#| "ZIP\n" +#| "CBZ\n" +#| "PDF\n" msgid "" "None\n" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" "None\n" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" #: frmmain.rs_optionfmddoitems msgid "" diff --git a/mangadownloader/languages/fmd.es.po b/mangadownloader/languages/fmd.es.po index 82f9003e2..a8fc4fbd4 100644 --- a/mangadownloader/languages/fmd.es.po +++ b/mangadownloader/languages/fmd.es.po @@ -393,11 +393,18 @@ msgid "One week" msgstr "Una Semana" #: frmmain.rs_optioncompress +#, fuzzy +#| msgid "" +#| "None\n" +#| "ZIP\n" +#| "CBZ\n" +#| "PDF\n" msgid "" "None\n" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" "Ninguno\n" "ZIP\n" diff --git a/mangadownloader/languages/fmd.id_ID.po b/mangadownloader/languages/fmd.id_ID.po index aabf09417..3342cb4ad 100644 --- a/mangadownloader/languages/fmd.id_ID.po +++ b/mangadownloader/languages/fmd.id_ID.po @@ -387,11 +387,13 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" "Tidak ada\n" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" #: frmmain.rs_optionfmddoitems msgid "" diff --git a/mangadownloader/languages/fmd.pl_PL.po b/mangadownloader/languages/fmd.pl_PL.po index 53109fbfb..f14130823 100644 --- a/mangadownloader/languages/fmd.pl_PL.po +++ b/mangadownloader/languages/fmd.pl_PL.po @@ -391,6 +391,7 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" #: frmmain.rs_optionfmddoitems diff --git a/mangadownloader/languages/fmd.po b/mangadownloader/languages/fmd.po index d25db0b61..6ee1f747b 100644 --- a/mangadownloader/languages/fmd.po +++ b/mangadownloader/languages/fmd.po @@ -358,6 +358,7 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" #: frmmain.rs_optionfmddoitems diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 0099c9de2..99c8cf987 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -29,7 +29,10 @@ msgid "" "Failed to finish:\n" "\n" "%s\n" -msgstr "Falha ao terminar:\n\n%s\n" +msgstr "" +"Falha ao terminar:\n" +"\n" +"%s\n" #: dbupdater.rs_faileditemstitle msgctxt "dbupdater.rs_faileditemstitle" @@ -61,7 +64,14 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" +msgstr "" +"Auto\n" +"780x\n" +"980x\n" +"1280x\n" +"1600x\n" +"2400x\n" +"Original\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -120,7 +130,10 @@ msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "Módulos atualizados, reiniciar agora?\n\n%s\n" +msgstr "" +"Módulos atualizados, reiniciar agora?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" @@ -131,7 +144,10 @@ msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "Atualização de módulos encontrada, todas as mudanças locais serão perdidas, continuar?\n\n%s\n" +msgstr "" +"Atualização de módulos encontrada, todas as mudanças locais serão perdidas, continuar?\n" +"\n" +"%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" @@ -230,7 +246,9 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" +msgstr "" +"Este título já está na lista de download.\n" +"Você quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -256,14 +274,19 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "Baixar tudo\nAdicionar aos favoritos\n" +msgstr "" +"Baixar tudo\n" +"Adicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "\n" -msgstr "Completo\nEm Andamento\n\n" +msgstr "" +"Completo\n" +"Em Andamento\n" +"\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -273,7 +296,9 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "" +"Há um problema com estes dados!\n" +"Removendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -327,7 +352,11 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" +msgstr "" +"%s : Caminho para o mangá\n" +"%s : Nome do capítulo\n" +"\n" +"Examplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -360,7 +389,13 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" -msgstr "Nada\nZIP\nCBZ\nPDF\n" +"EPUB\n" +msgstr "" +"Nada\n" +"ZIP\n" +"CBZ\n" +"PDF\n" +"EPUB\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -368,7 +403,11 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "Nada\nSair\nDesligar\nHibernar\n" +msgstr "" +"Nada\n" +"Sair\n" +"Desligar\n" +"Hibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -392,7 +431,10 @@ msgid "" "WebP\n" "PNG\n" "JPEG\n" -msgstr "WebP\nPNG\nJPEG\n" +msgstr "" +"WebP\n" +"PNG\n" +"JPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -400,7 +442,11 @@ msgid "" "Fastest\n" "Default\n" "Maximum\n" -msgstr "Nenhum\r\nO mais rápido\r\nPadrão\r\nMáximo" +msgstr "" +"Nenhumr\n" +"O mais rápidor\n" +"Padrãor\n" +"Máximo\n" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -481,7 +527,10 @@ msgid "" "Failed to download new version %s\n" "\n" "%d %s\n" -msgstr "Falha ao baixar a nova versão %s\n\n%d %s\n" +msgstr "" +"Falha ao baixar a nova versão %s\n" +"\n" +"%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" @@ -994,7 +1043,9 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" +msgstr "" +"Meninas vestindo-se como caras, caras vestir-se como meninas.\n" +"Rapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1410,7 +1461,16 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "" +"Géneros:\n" +"- Marcado: Inclua este gênero.\n" +"- Desmarcado: exclua esse gênero.\n" +"- Cinzento: Não importa.\n" +"\n" +"Géneros Personalizados:\n" +"- Separar vários gêneros com ','.\n" +"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n" +"- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1465,7 +1525,16 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "" +"%WEBSITE% : Nome doWebsite\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do capítulo\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"%NUMBERING% : Número\n" +"\n" +"Nota:\n" +"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1502,7 +1571,14 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%CHAPTER% : Título do Capítulo\n" +"%FILENAME% : Nome do arquivo\n" +"\n" +"Nota:\n" +"Nome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1535,7 +1611,14 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "" +"%WEBSITE% : Nome do Website\n" +"%MANGA% : Título do Mangá\n" +"%AUTHOR% : Autor\n" +"%ARTIST% : Artista\n" +"\n" +"Nota:\n" +"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time" @@ -2206,7 +2289,9 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" +msgstr "" +"Nova versão encontrada! Você quer atualizar agora?\n" +"FMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM1.CAPTION" @@ -2487,3 +2572,4 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" + diff --git a/mangadownloader/languages/fmd.ru_RU.po b/mangadownloader/languages/fmd.ru_RU.po index 6b7042e72..7e30684f1 100644 --- a/mangadownloader/languages/fmd.ru_RU.po +++ b/mangadownloader/languages/fmd.ru_RU.po @@ -397,11 +397,13 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" "Как есть\n" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" #: frmmain.rs_optionfmddoitems msgid "" diff --git a/mangadownloader/languages/fmd.tr_TR.po b/mangadownloader/languages/fmd.tr_TR.po index 3b612d3ed..40dec3362 100644 --- a/mangadownloader/languages/fmd.tr_TR.po +++ b/mangadownloader/languages/fmd.tr_TR.po @@ -401,11 +401,13 @@ msgid "" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" msgstr "" "Hiçbiri\n" "ZIP\n" "CBZ\n" "PDF\n" +"EPUB\n" #: frmmain.rs_optionfmddoitems msgid "" From c4f5f66c165a1b194c6ff9508c5a27939ec9df1e Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 May 2018 06:59:05 +0300 Subject: [PATCH 2594/2794] frmLuaModulesUpdater, fix crash --- mangadownloader/forms/frmLuaModulesUpdater.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas index bd7ea7fdb..0c269fd95 100644 --- a/mangadownloader/forms/frmLuaModulesUpdater.pas +++ b/mangadownloader/forms/frmLuaModulesUpdater.pas @@ -705,9 +705,9 @@ procedure TCheckUpdateThread.Execute; trepos: TLuaModulesRepos; begin Synchronize(@SyncStartChecking); + FReposUp := TLuaModulesRepos.Create; if FHTTP.GET(MODULES_URL) then begin - FReposUp := TLuaModulesRepos.Create; FReposUp.LoadFromRemote(FHTTP); if FHTTP.GET(MODULES_URL2) then FReposUp.LoadFromRemoteHTML(FHTTP); From 83d26106033370a0de50815d9c0743ad037dc12a Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 May 2018 07:40:00 +0300 Subject: [PATCH 2595/2794] uEpub, update --- baseunits/uEpub.pas | 179 ++++++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 49 deletions(-) diff --git a/baseunits/uEpub.pas b/baseunits/uEpub.pas index 43c4714cc..2a7ed8267 100644 --- a/baseunits/uEpub.pas +++ b/baseunits/uEpub.pas @@ -8,17 +8,19 @@ interface Classes, SysUtils, fgl; type + TPage = class; + TPages = specialize TFPGList; TStreams = specialize TFPGList; + { TEpubBuilder } + TEpubBuilder = class private FTitle, FUuid: String; FMimeType, FContainer, FStyle, FContent, FToc: TStringStream; - FImageNames: TStringList; - FPages: TStreams; - function CreateXHTMLPage(const imageName, pageTitle: String): TStringStream; - function CreateContent: TStringStream; - function CreateToc: TStringStream; + FPages: TPages; + function CreateContent: String; + function CreateToc: String; public constructor Create; destructor Destroy; override; @@ -27,13 +29,44 @@ TEpubBuilder = class property Title: String read FTitle write FTitle; end; + { TPage } + + TPage = class + private + FIndex: Integer; + FImagePath, FPageTitle: String; + FPage: TStringStream; + function GetContentItem: String; + function GetPageId: String; + function GetImageId: String; + function GetImageName: String; + function GetPageName: String; + function GetPageRef: String; + function GetPage: String; + function GetPageStream: TStringStream; + function GetNavPoint: String; + public + constructor Create(const index: Integer; const imagePath, pageTitle: String); + destructor Destroy; override; + property ImagePath: String read FImagePath; + property Index: Integer read FIndex; + property ContentItem: String read GetContentItem; + property PageId: String read GetPageId; + property ImageId: String read GetImageId; + property ImageName: String read GetImageName; + property PageName: String read GetPageName; + property PageRef: String read GetPageRef; + property PageStream: TStringStream read GetPageStream; + property NavPoint: String read GetNavPoint; + end; + implementation uses Zipper, htmlelements, uBaseUnit; const CONTAINER: String = - '' + LineEnding + + '' + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + @@ -41,7 +74,7 @@ implementation '' + LineEnding; CONTENT: String = - '' + LineEnding + + '' + LineEnding + '' + LineEnding + @@ -67,7 +100,7 @@ implementation ' ' + LineEnding; TOC: String = - '' + LineEnding + + '' + LineEnding + '' + LineEnding + ' ' + LineEnding + ' ' + LineEnding + @@ -97,7 +130,7 @@ implementation ' %s' + LineEnding + '' + LineEnding + '' + LineEnding + - '
    ' + LineEnding + + '
    ' + LineEnding + '' + LineEnding + '' + LineEnding; @@ -120,57 +153,46 @@ function NewUUID: String; Result := LowerCase(Result); end; -function GetImageName(const index: Integer; const fileName: String): String; -begin - Result := Format('%.4d%s', [index+1, ExtractFileExt(fileName)]); -end; +{ TEpubBuilder } -function TEpubBuilder.CreateXHTMLPage(const imageName, pageTitle: String): TStringStream; -begin - Result := TStringStream.Create(Format(PAGE, [EscapeHTML(pageTitle), imageName])); -end; - -function TEpubBuilder.CreateContent: TStringStream; +function TEpubBuilder.CreateContent: String; var - pageId, imageId, imageName, pageName: String; items: String = ''; refs: String = ''; i: Integer; begin - for i := 0 to FImageNames.Count-1 do begin - pageId := Format('page%.4d', [i+1]); - imageId := Format('image%.4d', [i+1]); - imageName := 'images/' + GetImageName(i, FImageNames[i]); - pageName := Format('%.4d.xhtml', [i+1]); - items += Format(CONTENT_ITEM, [imageId, imageName, GetMimeType(FImageNames[i])]); - items += Format(CONTENT_ITEM, [pageId, pageName, 'application/xhtml+xml']); - refs += Format(CONTENT_ITEMREF, [pageId]); + for i := 0 to FPages.Count-1 do begin + items += FPages[i].ContentItem; + refs += FPages[i].PageRef; end; - Result := TStringStream.Create(Format(CONTENT, [EscapeHTML(Title), FUuid, items, refs])); + Result := Format(CONTENT, [EscapeHTML(Title), FUuid, items, refs]); end; -function TEpubBuilder.CreateToc: TStringStream; +function TEpubBuilder.CreateToc: String; var navPoints: String = ''; i: Integer; begin - for i := 0 to FImageNames.Count-1 do begin - navPoints += Format(NAV_POINT, [i+1, i+1, i+1, Format('%.4d.xhtml', [i+1])]); - end; - Result := TStringStream.Create(Format(TOC, [FUuid, Title, navPoints])); + for i := 0 to FPages.Count-1 do + navPoints += FPages[i].NavPoint; + Result := Format(TOC, [FUuid, Title, navPoints]); end; procedure TEpubBuilder.AddImage(const path: String); +var + index: Integer; + pageTitle: String; begin - FImageNames.Add(path); + index := FPages.Count + 1; + pageTitle := Format('%s - %.4d', [Title, index]); + FPages.Add(TPage.Create(index, path, pageTitle)); end; procedure TEpubBuilder.SaveToStream(const stream: TStream); var zip: TZipper; i: Integer; - tmp: TStream; - imageName: String; + page: TPage; begin zip := TZipper.Create; try @@ -186,23 +208,20 @@ procedure TEpubBuilder.SaveToStream(const stream: TStream); FStyle := TStringStream.Create(STYLE); zip.Entries.AddFileEntry(FStyle, 'OEBPS/style.css'); - for i := 0 to FImageNames.Count-1 do begin + for i := 0 to FPages.Count-1 do begin + page := FPages[i]; // add image file - imageName := GetImageName(i, FImageNames[i]); - zip.Entries.AddFileEntry(FImageNames[i], 'OEBPS/images/' + imageName); - + zip.Entries.AddFileEntry(page.ImagePath, 'OEBPS/images/' + page.ImageName); // add xhtml file - tmp := CreateXHTMLPage(imageName, Format('%s - %.4d', [Title, i+1])); - zip.Entries.AddFileEntry(tmp, Format('OEBPS/%.4d.xhtml', [i+1])); - FPages.Add(tmp); + zip.Entries.AddFileEntry(page.PageStream, 'OEBPS/' + page.PageName); end; // add content.opf - FContent := CreateContent(); + FContent := TStringStream.Create(CreateContent); zip.Entries.AddFileEntry(FContent, 'OEBPS/content.opf'); // add toc.ncx - FToc := CreateToc(); + FToc := TStringStream.Create(CreateToc); zip.Entries.AddFileEntry(FToc, 'OEBPS/toc.ncx'); zip.SaveToStream(stream); @@ -218,8 +237,7 @@ constructor TEpubBuilder.Create; FStyle := nil; FContent := nil; FToc := nil; - FImageNames := TStringList.Create; - FPages := TStreams.Create; + FPages := TPages.Create; FUuid := NewUUID; end; @@ -232,12 +250,75 @@ destructor TEpubBuilder.Destroy; FreeAndNil(FPages); FreeAndNil(FMimeType); FreeAndNil(FContainer); - FreeAndNil(FImageNames); FreeAndNil(FStyle); FreeAndNil(FContent); FreeAndNil(FToc); inherited; end; +{ TPage } + +function TPage.GetContentItem: String; +begin + Result := Format(CONTENT_ITEM, [ImageId, 'images/' + ImageName, GetMimeType(FImagePath)]); + Result += Format(CONTENT_ITEM, [PageId, PageName, 'application/xhtml+xml']); +end; + +function TPage.GetPageId: String; +begin + Result := Format('page%.4d', [FIndex]); +end; + +function TPage.GetImageId: String; +begin + Result := Format('image%.4d', [FIndex]); +end; + +function TPage.GetImageName: String; +begin + Result := Format('%.4d%s', [FIndex, ExtractFileExt(FImagePath)]); +end; + +function TPage.GetPageName: String; +begin + Result := Format('%.4d.xhtml', [FIndex]) +end; + +function TPage.GetPageRef: String; +begin + Result := Format(CONTENT_ITEMREF, [PageId]); +end; + +function TPage.GetPage: String; +begin + Result := Format(PAGE, [EscapeHTML(FPageTitle), 'images/' + ImageName]); +end; + +function TPage.GetPageStream: TStringStream; +begin + if not Assigned(FPage) then + FPage := TStringStream.Create(GetPage); + Result := FPage; +end; + +function TPage.GetNavPoint: String; +begin + Result := Format(NAV_POINT, [FIndex, FIndex, FIndex, PageName]); +end; + +constructor TPage.Create(const index: Integer; const imagePath, pageTitle: String); +begin + FPage := nil; + FIndex := index; + FImagePath := imagePath; + FPageTitle := pageTitle; +end; + +destructor TPage.Destroy; +begin + FreeAndNil(FPage); + inherited Destroy; +end; + end. From ad8160a770f8f78e9bc91097e7dbb041f8ccce14 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 May 2018 09:43:00 +0300 Subject: [PATCH 2596/2794] remove Doujinmoeus --- baseunits/ModuleList.inc | 1 - baseunits/modules/Doujinmoeus.pas | 176 ------------------------------ 2 files changed, 177 deletions(-) delete mode 100644 baseunits/modules/Doujinmoeus.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 4e84f6a4a..ba7a6d994 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -63,7 +63,6 @@ uses // Adult WPAdultSiteSkins, EHentai, - Doujinmoeus, Luscious, EightMuses, HitomiLa, diff --git a/baseunits/modules/Doujinmoeus.pas b/baseunits/modules/Doujinmoeus.pas deleted file mode 100644 index 5704f8c57..000000000 --- a/baseunits/modules/Doujinmoeus.pas +++ /dev/null @@ -1,176 +0,0 @@ -unit Doujinmoeus; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, WebsiteModules, uData, uBaseUnit, uDownloadsManager, httpsendthread; - -implementation - -uses - simplehtmltreeparser, xquery; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Page := 100; - Result := NO_ERROR; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - Source: TStringList; - Parser: TTreeParser; - s: String; - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - Source := TStringList.Create; - try - s := 'get=' + IncStr(AURL); - with MangaInfo.FHTTP.Document do begin - Clear; - Write(PChar(s)^, Length(s)); - end; - if GetPage(MangaInfo.FHTTP, TObject(Source), Module.RootURL + '/ajax/newest.php', - 3, 'POST') then - begin - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - if SelectXPathString('json(*)("success")', Parser) = 'true' then - begin - for v in SelectXPathIX('json(*)("newest")()("token")', Parser) do - ALinks.Add(v.toString); - for v in SelectXPathIX('json(*)("newest")()("name")', Parser) do - ANames.Add(v.toString); - end; - finally - Parser.Free; - end; - end; - finally - Source.Free; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - info: TMangaInfo; - Source: TStringList; - Parser: TTreeParser; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit; - info := MangaInfo.mangaInfo; - info.website := Module.Website; - info.url := FillHost(Module.RootURL, AURL); - Source := TStringList.Create; - try - if MangaInfo.FHTTP.GET(info.url, TObject(Source)) then - if Source.Count > 0 then - begin - Result := NO_ERROR; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - with info do - begin - //title - title := SelectXPathString('//div[@class="title"]/a[last()]', Parser); - //cover - coverLink := SelectXPathString('//div[@id="gallery"]/djm/@thumb', Parser); - //artist - artists := SelectXPathString( - '//*[@id="page_info"]/div[@class="right"]/table/tbody/tr/td/a', Parser); - //summary - summary := SelectXPathString( - '//*[@id="page_info"]/div/div[@class="message"]', Parser); - //chapter - if coverLink <> '' then - begin - chapterLinks.Add(info.url); - chapterName.Add(title); - end; - end; - finally - Parser.Free; - end; - end - else - Result := INFORMATION_NOT_FOUND; - finally - Source.Free; - end; -end; - -function TaskStart(const Task: TTaskContainer; const Module: TModuleContainer): Boolean; -begin - Result := True; - if Task = nil then Exit; - Task.PageLinks.Clear; - Task.PageNumber := 0; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - Container: TTaskContainer; - Source: TStringList; - Parser: TTreeParser; - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - Container := DownloadThread.Task.Container; - Container.PageLinks.Clear; - Container.PageContainerLinks.Clear; - Container.PageNumber := 0; - Source := TStringList.Create; - try - if DownloadThread.GetPage(TObject(Source), FillHost(Module.RootURL, AURL), - Container.Manager.retryConnect) then - if Source.Count > 0 then - begin - Result := True; - Parser := TTreeParser.Create; - try - ParseHTMLTree(Parser, Source.Text); - for v in SelectXPathIX('//div[@id="gallery"]/djm/@file', Parser) do - Container.PageLinks.Add(v.toString); - finally - Parser.Free; - end; - end; - finally - Source.Free; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'Doujin-Moe'; - RootURL := 'http://www.doujin-moe.us'; - Category := 'H-Sites'; - SortedList := True; - FavoriteAvailable := False; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnTaskStart := @TaskStart; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 691dd4dd96667b1cbbfd12495c5587c8aa73fdbb Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 May 2018 13:39:01 +0300 Subject: [PATCH 2597/2794] remove manga.sh fixes #900 --- lua/modules/MangaSh.lua | 74 ----------------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 lua/modules/MangaSh.lua diff --git a/lua/modules/MangaSh.lua b/lua/modules/MangaSh.lua deleted file mode 100644 index fe2e940e9..000000000 --- a/lua/modules/MangaSh.lua +++ /dev/null @@ -1,74 +0,0 @@ -local apiurl='https://api.manga.sh/api/v1/' -local cdnurl='https://cdn.manga.sh/' - -function getinfo() - local lid=RegExprGetMatch('/(\\d+)',url,1) - local lurl=MaybeFillHost(module.RootURL, apiurl..'series?query=Id:'..lid) - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(lurl) then - x=TXQuery.Create(http.document) - v=x.xpath('json(*).response(1)') - mangainfo.title=x.xpathstring('Name', v) - mangainfo.coverlink=x.xpathstring('CoverImage', v) - if mangainfo.coverlink ~= '' then - mangainfo.coverlink=cdnurl..'covers/'..mangainfo.coverlink - end - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('Status/Name', v)) - mangainfo.genres=x.xpathstring('string-join((TypeName,TypeDemonym,SeriesTags/TagName),", ")', v) - mangainfo.summary=HTMLDecode(x.xpathstring('Description', v)) - if http.get(apiurl..'series_chapters?query=SeriesId.Id:'..lid..'&order=desc&sortby=TimeUploaded&limit=0&offset=0') then - x.parsehtml(http.document) - local s='json(.)("response")()' - local lname='' - local showalllang=module.getoption('showalllang') - local showscangroup=module.getoption('showscangroup') - if not showalllang then - s=s..'[ChapterLanguage/Name = "English"]' - end - v=x.xpath(s) - for i=1,v.count do - v2=v.get(i) - lname=x.xpathstring('concat("Vol.",VolumeNumber," Ch.",ChapterNumberAbsolute," ",ChapterNumberVolume)', v2) - if showalllang then - s=x.xpathstring('ChapterLanguage/Name',v2) - if s~='' then lname=lname..' ['..s..']' end - end - if showscangroup then - s=x.xpathstring('string-join(SeriesChaptersGroups/GroupName,", ")',v2) - if s~='' then lname=lname..' ['..s..']' end - end - mangainfo.chapterlinks.add(x.xpathstring('Hash', v2)) - mangainfo.chapternames.add(lname) - end - return no_error - else - return net_problem - end - else - return net_problem - end -end - -function getpagenumber() - if http.get(apiurl..'series_chapters/'..RemoveURLDelimLeft(url)) then - TXQuery.Create(http.Document).xpathstringall('json(.)/response/SeriesChaptersFiles/Name',task.pagelinks) - for i=0,task.pagelinks.count-1 do - task.pagelinks[i]=cdnurl..task.pagelinks[i] - end - return true - else - return false - end - return true -end - -function Init() - m=NewModule() - m.website='MangaSh' - m.rooturl='https://manga.sh' - m.lastupdated='February 14, 2018' - m.ongetinfo='getinfo' - m.ongetpagenumber='getpagenumber' - m.addoptioncheckbox('showalllang', 'Show all language', false) - m.addoptioncheckbox('showscangroup', 'Show scanlation group', false) -end From 3f06b803c6544e2bacb9fa52ea072b1b3d5a9a7b Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 May 2018 17:06:37 +0300 Subject: [PATCH 2598/2794] remove host from url during conversion (fixes #802) --- baseunits/DownloadedChaptersDB.pas | 13 ++++++------- baseunits/uDownloadsManager.pas | 2 +- baseunits/uFavoritesManager.pas | 30 ++++++++++++++++-------------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/baseunits/DownloadedChaptersDB.pas b/baseunits/DownloadedChaptersDB.pas index 84be7898b..3c0604a14 100644 --- a/baseunits/DownloadedChaptersDB.pas +++ b/baseunits/DownloadedChaptersDB.pas @@ -116,7 +116,7 @@ procedure TDownloadedChaptersDB.Delete(const AWebsiteLink: String); function TDownloadedChaptersDB.ImportFromIni(const AFilename: String): Boolean; var dc: TStringList; - i: Integer; + i: Integer = 0; begin Result := False; if not Connected then Exit; @@ -125,12 +125,11 @@ function TDownloadedChaptersDB.ImportFromIni(const AFilename: String): Boolean; try dc.LoadFromFile(AFilename); if dc.Count > 0 then - i := 0; - while i < dc.Count - 2 do - begin - Chapters[dc[i]] := GetParams(dc[i + 1]); - Inc(i, 2); - end; + while i <= dc.Count - 2 do + begin + Chapters[dc[i]] := RemoveHostFromURL(GetParams(dc[i + 1])); + Inc(i, 2); + end; Result := True; finally dc.Free; diff --git a/baseunits/uDownloadsManager.pas b/baseunits/uDownloadsManager.pas index 08672f0d1..6c8abdd10 100644 --- a/baseunits/uDownloadsManager.pas +++ b/baseunits/uDownloadsManager.pas @@ -1353,7 +1353,7 @@ function TDownloadManager.ConvertToDB: Boolean; ReadInteger(s, 'NumberOfPages', 0), ReadInteger(s, 'CurrentPage', 0), ReadString(s, 'Website', ''), - ReadString(s, 'Link', ''), + RemoveHostFromURL(ReadString(s, 'Link', '')), ReadString(s, 'Title', ''), ReadString(s, 'Status', ''), ReadString(s, 'Progress', ''), diff --git a/baseunits/uFavoritesManager.pas b/baseunits/uFavoritesManager.pas index d6572f702..623a89b47 100644 --- a/baseunits/uFavoritesManager.pas +++ b/baseunits/uFavoritesManager.pas @@ -529,22 +529,24 @@ function TFavoriteManager.ConvertToDB: Boolean; with TIniFile.Create(FAVORITES_FILE) do try i := ReadInteger('general', 'NumberOfFavorites', 0); - if i = 0 then Exit; - for i := 0 to i - 1 do + if i > 0 then begin - s := IntToStr(i); - FFavoritesDB.Add( - i, - True, - ReadString(s, 'Website', ''), - ReadString(s, 'Link', ''), - ReadString(s, 'Title', ''), - ReadString(s, 'CurrentChapter', ''), - GetParams(ReadString(s, 'DownloadedChapterList', '')), - ReadString(s, 'SaveTo', '') - ); + for i := 0 to i - 1 do + begin + s := IntToStr(i); + FFavoritesDB.Add( + i, + True, + ReadString(s, 'Website', ''), + RemoveHostFromURL(ReadString(s, 'Link', '')), + ReadString(s, 'Title', ''), + ReadString(s, 'CurrentChapter', ''), + GetParams(ReadString(s, 'DownloadedChapterList', '')), + ReadString(s, 'SaveTo', '') + ); + end; + FFavoritesDB.Commit; end; - FFavoritesDB.Commit; Result := True; finally Free; From a62836d142fb78aef9e1e46bc3fb6365378effb1 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 May 2018 20:38:22 +0300 Subject: [PATCH 2599/2794] Bump version 0.9.155.0 --- README.md | 2 +- changelog.txt | 25 +++++++++++++++++++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dcc5d1068..51faf1300 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Download the latest release -[![GitHub release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.154.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0.7z) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.154.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0_Win64.7z) +[![GitHub release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0.7z) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0_Win64.7z) ## Content diff --git a/changelog.txt b/changelog.txt index de15c2ea6..700d83dff 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,31 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.155.0 (14-05-2018) +[+] Added ePub support +[+] Added Bamtoki [RAW] +[+] Added RawQQ [RAW] +[+] Added AllHentai [RU] +[+] Added ComicExtra [EN] +[+] Added ReadComicBooksOnline [EN] +[+] Added SOSScanlation [SP-SC] +[+] Added MangaHereIO [EN] +[+] Added SiberOwl [EN-SC] +[+] Added ComicoCoID [ID] +[+] Added IMangaScans [EN-SC] +[+] Added InManga [SP] +[-] Removed MangaSh +[*] MangaKu, fixed domain name +[*] JapScan, fixed download +[*] Pzykosis666HFansub, fixed domain name +[*] ReadComicOnline, set high image quality +[*] MangaDex, fixed all +[*] CentralDeMangas, fixed domain name +[*] Mangaf, fixed domain name +[*] AcademyVN, fixed domain name +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.154.0...0.9.155.0 + 0.9.154.0 (15-04-2018) [+] Added GodsRealmScan [SP-SC] [+] Added IlluminatiManga [EN-SC] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5360f30ff..e0f87b1bd 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ - + diff --git a/update b/update index 5a6c6eeea..09db9dcf2 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.154.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.154.0/fmd_0.9.154.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.154.0/fmd_0.9.154.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.154.0/fmd_0.9.154.0_Win64.7z +VERSION=0.9.155.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.155.0/fmd_0.9.155.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.155.0/fmd_0.9.155.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0_Win64.7z From c783ed9d4502fb3a2fed1a8ae2d531e5bc5db07c Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 May 2018 05:46:13 +0300 Subject: [PATCH 2600/2794] JapScan, don't fetch last page fixes #1230 --- lua/modules/JapScan.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/JapScan.lua b/lua/modules/JapScan.lua index f681233e4..1c21bb5bb 100644 --- a/lua/modules/JapScan.lua +++ b/lua/modules/JapScan.lua @@ -33,7 +33,7 @@ function getpagenumber() task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl, url)) then local x=TXQuery.Create(http.Document) - x.xpathstringall('//select[@id="pages"]/option/@value', task.pagelinks) + x.xpathstringall('//select[@id="pages"]/option[position() < last()]/@value', task.pagelinks) task.pagecontainerlinks.text = http.cookies.text else return false From 72646b62fc9055625ffa0fec13b5faf77d7a4045 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 May 2018 08:14:58 +0300 Subject: [PATCH 2601/2794] add doujins.com (no manga list) --- lua/modules/DoujinsCom.lua | 78 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 lua/modules/DoujinsCom.lua diff --git a/lua/modules/DoujinsCom.lua b/lua/modules/DoujinsCom.lua new file mode 100644 index 000000000..fe3c02b31 --- /dev/null +++ b/lua/modules/DoujinsCom.lua @@ -0,0 +1,78 @@ +local dirurl = '/list?type=&sortType=DATE_CREATE' +local perpage = 60 + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//div[@class="folder-title"]/a[last()]') + end + mangainfo.coverlink = x.xpathstring('(//img[@class="doujin"])[1]/@data-thumb') + print(x.xpathstring('(//img[@class="doujin"])[1]/@data-thumb')) + mangainfo.authors=x.xpathstringall('//div[@class="gallery-artist"]/a') + mangainfo.artists=x.xpathstringall('//div[@class="gallery-artist"]/a') + mangainfo.genres=x.xpathstringall('//li[@class="tag-area"]/a') + mangainfo.chapterlinks.add(mangainfo.url) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[@class="doujin"]/@data-file', task.pagelinks) + else + return false + end + return true +end + +--[[ +function getdirectorypagenumber() + if http.GET(module.RootURL .. dirurl) then + local x = TXQuery.Create(http.Document) + local s = x.xpathstring('//*[@class="pagination"]/a[@class="step"][last()]/@href') + page = tonumber(s:match('offset=(%d+)')) + if page == nil then page = 1 end + if page > 1 then page = math.ceil(page / perpage) + 1; end + return no_error + else + return net_problem + end +end + +function getnameandlink() + local s = module.rooturl .. dirurl + if url ~= '0' then s = s .. '&offset=' .. (tonumber(url) * perpage) .. '&max=' .. perpage; end + if http.get(s) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//table[@class="cTable"]//tr/td/a[not(@class)]') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getattribute('href')) + names.add(x.xpathstring('./text()', v1)) + end + return no_error + else + return net_problem + end +end +]]-- + +function Init() + local m = NewModule() + m.website = 'DoujinsCom' + m.rooturl = 'https://doujins.com/' + m.category = 'H-Sites' + m.lastupdated='May 14, 2018' + m.sortedlist = true + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + --m.ongetnameandlink='getnameandlink' + --m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end \ No newline at end of file From 6c5931454f099cd4084fc1f8aecc5bba571bd38e Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 May 2018 09:34:21 +0300 Subject: [PATCH 2602/2794] DoujinsCom, add list --- lua/modules/DoujinsCom.lua | 42 ++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/lua/modules/DoujinsCom.lua b/lua/modules/DoujinsCom.lua index fe3c02b31..3236b034e 100644 --- a/lua/modules/DoujinsCom.lua +++ b/lua/modules/DoujinsCom.lua @@ -9,7 +9,6 @@ function getinfo() mangainfo.title = x.xpathstring('//div[@class="folder-title"]/a[last()]') end mangainfo.coverlink = x.xpathstring('(//img[@class="doujin"])[1]/@data-thumb') - print(x.xpathstring('(//img[@class="doujin"])[1]/@data-thumb')) mangainfo.authors=x.xpathstringall('//div[@class="gallery-artist"]/a') mangainfo.artists=x.xpathstringall('//div[@class="gallery-artist"]/a') mangainfo.genres=x.xpathstringall('//li[@class="tag-area"]/a') @@ -32,47 +31,46 @@ function getpagenumber() return true end ---[[ +function today() + local now = os.date('*t'); + return os.time({year=now.year, month=now.month, day=now.day}) +end + +local endDate = os.time({year=2007, month=9, day=30}) +local step = 30 * 24 * 60 * 60 + function getdirectorypagenumber() - if http.GET(module.RootURL .. dirurl) then - local x = TXQuery.Create(http.Document) - local s = x.xpathstring('//*[@class="pagination"]/a[@class="step"][last()]/@href') - page = tonumber(s:match('offset=(%d+)')) - if page == nil then page = 1 end - if page > 1 then page = math.ceil(page / perpage) + 1; end - return no_error - else - return net_problem - end + page = math.ceil((today() - endDate) / step) + return no_error end function getnameandlink() - local s = module.rooturl .. dirurl - if url ~= '0' then s = s .. '&offset=' .. (tonumber(url) * perpage) .. '&max=' .. perpage; end - if http.get(s) then + local to = today() - tonumber(url) * step + local from = to - step + 1 + if from < endDate then return no_error; end + if http.xhr(module.rooturl .. string.format('/folders?start=%d&end=%d', from, to)) then local x = TXQuery.Create(http.Document) - local v = x.xpath('//table[@class="cTable"]//tr/td/a[not(@class)]') + local v = x.xpath('json(*).folders()') for i = 1, v.count do local v1 = v.get(i) - links.add(v1.getattribute('href')) - names.add(x.xpathstring('./text()', v1)) + links.add(x.xpathstring('link', v1)) + names.add(x.xpathstring('name', v1)) end return no_error else return net_problem end end -]]-- function Init() local m = NewModule() m.website = 'DoujinsCom' - m.rooturl = 'https://doujins.com/' + m.rooturl = 'https://doujins.com' m.category = 'H-Sites' m.lastupdated='May 14, 2018' m.sortedlist = true m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' - --m.ongetnameandlink='getnameandlink' - --m.ongetdirectorypagenumber = 'getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' end \ No newline at end of file From 796badcdc3de4d3d5b63ec8a449ce23eed8b7708 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 May 2018 10:15:08 +0300 Subject: [PATCH 2603/2794] TrashScanlations, fix title fixes #1232 --- lua/modules/rawdevart.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 181ab2ff2..ed19f5f91 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -2,7 +2,7 @@ function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstring('//div[@class="post-title"]/h3') + mangainfo.title=x.xpathstringall('//div[@class="post-title"]/h3/text()', '') mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@src') mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') From 594c2620b5b5276c80a72ed92960a1adb7cdad7d Mon Sep 17 00:00:00 2001 From: Havokdan Date: Tue, 15 May 2018 07:23:18 -0300 Subject: [PATCH 2604/2794] Update fmd.pt_BR.po --- mangadownloader/languages/fmd.pt_BR.po | 132 +++++-------------------- 1 file changed, 27 insertions(+), 105 deletions(-) diff --git a/mangadownloader/languages/fmd.pt_BR.po b/mangadownloader/languages/fmd.pt_BR.po index 99c8cf987..3b66ea692 100644 --- a/mangadownloader/languages/fmd.pt_BR.po +++ b/mangadownloader/languages/fmd.pt_BR.po @@ -2,6 +2,7 @@ msgid "" msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Last-Translator: Havokdan \n" +"Language-Team: Havokdan \n" #: dbupdater.rs_buttoncancel msgctxt "dbupdater.rs_buttoncancel" @@ -29,10 +30,7 @@ msgid "" "Failed to finish:\n" "\n" "%s\n" -msgstr "" -"Falha ao terminar:\n" -"\n" -"%s\n" +msgstr "Falha ao terminar:\n\n%s\n" #: dbupdater.rs_faileditemstitle msgctxt "dbupdater.rs_faileditemstitle" @@ -64,14 +62,7 @@ msgid "" "1600x\n" "2400x\n" "Original\n" -msgstr "" -"Auto\n" -"780x\n" -"980x\n" -"1280x\n" -"1600x\n" -"2400x\n" -"Original\n" +msgstr "Auto\n780x\n980x\n1280x\n1600x\n2400x\nOriginal\n" #: frmaccountmanager.rs_accountdeleteconfirmation msgid "Are you sure you want to delete this account?" @@ -130,10 +121,7 @@ msgid "" "Modules updated, restart now?\n" "\n" "%s\n" -msgstr "" -"Módulos atualizados, reiniciar agora?\n" -"\n" -"%s\n" +msgstr "Módulos atualizados, reiniciar agora?\n\n%s\n" #: frmluamodulesupdater.rs_modulesupdatedtitle msgid "Modules updated!" @@ -144,10 +132,7 @@ msgid "" "Modules update found, any local changes will be lost, procced?\n" "\n" "%s\n" -msgstr "" -"Atualização de módulos encontrada, todas as mudanças locais serão perdidas, continuar?\n" -"\n" -"%s\n" +msgstr "Atualização de módulos encontrada, todas as mudanças locais serão perdidas, continuar?\n\n%s\n" #: frmluamodulesupdater.rs_newupdatefoundtitle msgid "Modules update found!" @@ -246,9 +231,7 @@ msgstr "Dividir download" msgid "" "This title are already in download list.\n" "Do you want to download it anyway?\n" -msgstr "" -"Este título já está na lista de download.\n" -"Você quer baixá-lo mesmo assim?\n" +msgstr "Este título já está na lista de download.\nVocê quer baixá-lo mesmo assim?\n" #: frmmain.rs_dlgtypeinnewchapter msgid "Type in new chapter:" @@ -274,19 +257,14 @@ msgstr "URL não suportada!" msgid "" "Download all\n" "Add to favorites\n" -msgstr "" -"Baixar tudo\n" -"Adicionar aos favoritos\n" +msgstr "Baixar tudo\nAdicionar aos favoritos\n" #: frmmain.rs_filterstatusitems msgid "" "Completed\n" "Ongoing\n" "\n" -msgstr "" -"Completo\n" -"Em Andamento\n" -"\n" +msgstr "Completo\nEm Andamento\n\n" #: frmmain.rs_fmdalreadyrunning msgid "Free Manga Downloader already running!" @@ -296,9 +274,7 @@ msgstr "Free Manga Downloader já está em execução!" msgid "" "There is a problem with this data!\n" "Removing and re-adding this data may fix the problem.\n" -msgstr "" -"Há um problema com estes dados!\n" -"Removendo e re-adicionando estes dados pode corrigir o problema.\n" +msgstr "Há um problema com estes dados!\nRemovendo e re-adicionando estes dados pode corrigir o problema.\n" #: frmmain.rs_history msgid "History" @@ -352,11 +328,7 @@ msgid "" "%s : Chapter filename\n" "\n" "Example : \"%s%s\"\n" -msgstr "" -"%s : Caminho para o mangá\n" -"%s : Nome do capítulo\n" -"\n" -"Examplo : \"%s%s\"\n" +msgstr "%s : Caminho para o mangá\n%s : Nome do capítulo\n\nExamplo : \"%s%s\"\n" #: frmmain.rs_loading msgid "Loading ..." @@ -384,18 +356,19 @@ msgid "One week" msgstr "Uma semana" #: frmmain.rs_optioncompress +#, fuzzy +#| msgid "" +#| "None\n" +#| "ZIP\n" +#| "CBZ\n" +#| "PDF\n" msgid "" "None\n" "ZIP\n" "CBZ\n" "PDF\n" "EPUB\n" -msgstr "" -"Nada\n" -"ZIP\n" -"CBZ\n" -"PDF\n" -"EPUB\n" +msgstr "Nenhum\nZIP\nCBZ\nPDF\nEPUB\n" #: frmmain.rs_optionfmddoitems msgid "" @@ -403,11 +376,7 @@ msgid "" "Exit\n" "Shutdown\n" "Hibernate\n" -msgstr "" -"Nada\n" -"Sair\n" -"Desligar\n" -"Hibernar\n" +msgstr "Nada\nSair\nDesligar\nHibernar\n" #: frmmain.rs_selected msgid "Selected: %d" @@ -431,10 +400,7 @@ msgid "" "WebP\n" "PNG\n" "JPEG\n" -msgstr "" -"WebP\n" -"PNG\n" -"JPEG\n" +msgstr "WebP\nPNG\nJPEG\n" #: frmmain.rs_webppnglevel msgid "" @@ -442,11 +408,7 @@ msgid "" "Fastest\n" "Default\n" "Maximum\n" -msgstr "" -"Nenhumr\n" -"O mais rápidor\n" -"Padrãor\n" -"Máximo\n" +msgstr "Nenhum\nO mais rápido\nPadrão\nMáximo" #: frmmain.rs_wronginput msgid "Invalid input!" @@ -527,10 +489,7 @@ msgid "" "Failed to download new version %s\n" "\n" "%d %s\n" -msgstr "" -"Falha ao baixar a nova versão %s\n" -"\n" -"%d %s\n" +msgstr "Falha ao baixar a nova versão %s\n\n%d %s\n" #: selfupdater.rs_failedextract msgid "Failed to extract %s, exitstatus = %d" @@ -1043,9 +1002,7 @@ msgstr "Troca de Sexo" msgid "" "Girls dressing up as guys, guys dressing up as girls.\n" "Guys turning into girls, girls turning into guys.\n" -msgstr "" -"Meninas vestindo-se como caras, caras vestir-se como meninas.\n" -"Rapazes se transformando em garotas, garotas se transformando em caras.\n" +msgstr "Meninas vestindo-se como caras, caras vestir-se como meninas.\nRapazes se transformando em garotas, garotas se transformando em caras.\n" #: tmainform.ckfilterharem.caption msgid "Harem" @@ -1461,16 +1418,7 @@ msgid "" "- Separate multiple genres with ','.\n" "- Exclude a genre by placing '!' or '-' at the beginning of a genre.\n" "- Example: Adventure,!Ecchi,Comedy.\n" -msgstr "" -"Géneros:\n" -"- Marcado: Inclua este gênero.\n" -"- Desmarcado: exclua esse gênero.\n" -"- Cinzento: Não importa.\n" -"\n" -"Géneros Personalizados:\n" -"- Separar vários gêneros com ','.\n" -"- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n" -"- Exemplo: Aventura, Ecchi, Comédia.\n" +msgstr "Géneros:\n- Marcado: Inclua este gênero.\n- Desmarcado: exclua esse gênero.\n- Cinzento: Não importa.\n\nGéneros Personalizados:\n- Separar vários gêneros com ','.\n- Excluir um gênero colocando '!' Ou '-' no início de um gênero.\n- Exemplo: Aventura, Ecchi, Comédia.\n" #: tmainform.lbfilterstatus.caption msgctxt "TMAINFORM.LBFILTERSTATUS.CAPTION" @@ -1525,16 +1473,7 @@ msgid "" "\n" "Note:\n" "Chapter folder name must have at least %CHAPTER% or %NUMBERING%.\n" -msgstr "" -"%WEBSITE% : Nome doWebsite\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do capítulo\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"%NUMBERING% : Número\n" -"\n" -"Nota:\n" -"O nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" +msgstr "%WEBSITE% : Nome doWebsite\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do capítulo\n%AUTHOR% : Autor\n%ARTIST% : Artista\n%NUMBERING% : Número\n\nNota:\nO nome da pasta do capítulo deve ter pelo menos %CHAPTER% ou %NUMBERING%.\n" #: tmainform.lboptionconnectiontimeout.caption msgid "Connection timeout (seconds)" @@ -1571,14 +1510,7 @@ msgid "" "\n" "Note:\n" "Filename must have at least %FILENAME%\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%CHAPTER% : Título do Capítulo\n" -"%FILENAME% : Nome do arquivo\n" -"\n" -"Nota:\n" -"Nome do arquivo deve ter pelo menos %FILENAME%\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%CHAPTER% : Título do Capítulo\n%FILENAME% : Nome do arquivo\n\nNota:\nNome do arquivo deve ter pelo menos %FILENAME%\n" #: tmainform.lboptionhost.caption msgid "Host" @@ -1611,14 +1543,7 @@ msgid "" "\n" "Note:\n" "Manga folder name must have at least %MANGA%.\n" -msgstr "" -"%WEBSITE% : Nome do Website\n" -"%MANGA% : Título do Mangá\n" -"%AUTHOR% : Autor\n" -"%ARTIST% : Artista\n" -"\n" -"Nota:\n" -"Nome da pasta Manga deve ter pelo menos %MANGA%.\n" +msgstr "%WEBSITE% : Nome do Website\n%MANGA% : Título do Mangá\n%AUTHOR% : Autor\n%ARTIST% : Artista\n\nNota:\nNome da pasta Manga deve ter pelo menos %MANGA%.\n" #: tmainform.lboptionmaxparallel.caption msgid "Number of downloaded tasks at the same time" @@ -2289,9 +2214,7 @@ msgstr "&Atualizar" msgid "" "New version found! Do you want to update now?\n" "FMD will be closed to finish the update.\n" -msgstr "" -"Nova versão encontrada! Você quer atualizar agora?\n" -"FMD irá fechar para terminar a atualização.\n" +msgstr "Nova versão encontrada! Você quer atualizar agora?\nFMD irá fechar para terminar a atualização.\n" #: twebsiteoptionadvancedform.menuitem1.caption msgctxt "TWEBSITEOPTIONADVANCEDFORM.MENUITEM1.CAPTION" @@ -2572,4 +2495,3 @@ msgstr "Sincronizando dados" #: uupdatethread.rs_updatinglist msgid "Updating list" msgstr "Atualizando a lista" - From 1e98e9e7d42f74addade4a0d5c498b50b94bc4ec Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 May 2018 13:56:02 +0300 Subject: [PATCH 2605/2794] add PlusComico [raw] --- lua/modules/PlusComico.lua | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 lua/modules/PlusComico.lua diff --git a/lua/modules/PlusComico.lua b/lua/modules/PlusComico.lua new file mode 100644 index 000000000..da3061019 --- /dev/null +++ b/lua/modules/PlusComico.lua @@ -0,0 +1,169 @@ +function getinfo_store() + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="_title"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//meta[@property="og:image"]/@content')) + mangainfo.authors=x.xpathstring('//*[contains(@class,"__author")]') + mangainfo.genres=x.xpathstringall('//li[contains(@class,"__list-genre-item")]/p/a') + mangainfo.summary=x.xpathstring('//p[@class="_description"]') + local id = mangainfo.url:match('/(%d+)/?$') + http.reset() + if http.post(module.rooturl .. '/store/api/getTitleArticles.nhn', 'titleNo='..id) then + x.parsehtml(http.document) + local v = x.xpath('json(*).result.list().articleList()') + for i = 1, v.count do + local v1 = v.get(i) + if x.xpathstring('./freeFlg', v1) == 'Y' then + mangainfo.chapterlinks.add(x.xpathstring('./articleDetailUrl', v1)) + mangainfo.chapternames.add(x.xpathstring('./subtitle', v1)) + end + end + end +end + +function getinfo_manga() + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//*[contains(@class,"__ttl")]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//meta[@property="og:image"]/@content')) + mangainfo.authors=x.xpathstring('//*[contains(@class,"__author")]') + mangainfo.genres=x.xpathstringall('//*[contains(@class,"__meta")]//a') + mangainfo.summary=x.xpathstring('//*[contains(@class,"__description")]') + local id = mangainfo.url:match('/(%d+)/?$') + http.reset() + if http.post(module.rooturl .. '/api/getArticleList.nhn', 'titleNo='..id) then + x.parsehtml(http.document) + local v = x.xpath('json(*).result.list()') + for i = 1, v.count do + local v1 = v.get(i) + if x.xpathstring('./freeFlg', v1) == 'Y' then + mangainfo.chapterlinks.add(x.xpathstring('./articleDetailUrl', v1)) + mangainfo.chapternames.add(x.xpathstring('./subtitle', v1)) + end + end + end +end + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + if mangainfo.url:match('/store/') ~= nil then + getinfo_store() + else + getinfo_manga() + end + return no_error + else + return net_problem + end +end + +function getpagenumber_manga() + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "imageData:")]') + s = GetBetween('imageData:', ']', s) .. ']' + x.parsehtml(s) + x.xpathstringall('json(*)()', task.pagelinks) + return true +end + +function getpagenumber_store() + if http.lasturl:match('param=') == nil then return false; end + local base = SeparateLeft(http.lasturl, 'index.php') + local param = GetBetween('param=', '&', http.lasturl) + local ts = os.time() * 1000 + base = base .. string.format('diazepam_hybrid.php?reqtype=0¶m=%s&ts=%d&_=%d', param, ts, ts+1500) + math.randomseed(os.time()) + math.random(); math.random(); math.random(); + local tpurl = string.format('&mode=7&file=face.xml&callback=jQ%d_%d', math.random(1000), math.random(1000)) + if http.get(base .. tpurl) then + if http.terminated then return false; end + local s = GetBetween('("', '")', StreamToString(http.document)) + local x=TXQuery.Create(s) + local total_pages = tonumber(x.xpathstring('//TotalPage')) + if total_pages == nil then return false; end + for i = 0, total_pages-1 do + task.pagelinks.add(base .. string.format('&mode=8&file=%04d.xml', i)) + end + task.pagecontainerlinks.text = http.cookies.text + else + return false + end + return false +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + if url:match('/store/') ~= nil then + return getpagenumber_store() + else + return getpagenumber_manga() + end + else + return false + end +end + +local js = require 'modules.jsunpack' +function downloadimage() + if url:match('%.xml') == nil then return http.get(url); end + http.cookies.text = task.pagecontainerlinks.text + if http.get(url) then + local x = TXQuery.Create(http.Document) + local a = js.splitstr(x.xpathstring('//Scramble'), ',') + local imgurl = SeparateLeft(url, '&mode=') + imgurl = imgurl .. string.format('&mode=1&file=%04d_0000.bin', workid) + if http.get(imgurl) then + local s = TImagePuzzle.Create(4, 4) + s.multiply = 8 + local n = 0 + for i, v in ipairs(a) do + local j = tonumber(v) + if j == nil then j = 0 end + s.matrix[j] = n; + n = n + 1 + end + s.descramble(http.document, http.document) + return true + end + return false + end + return false +end + +local dirurls = { +-- '/store/ranking/list.nhn', + '/manga/ranking/list.nhn' +} + +function getnameandlink() + local lurl = dirurls[module.CurrentDirectoryIndex+1] + local data = 'page='..IncStr(url)..'&rankingType=original' + if http.post(module.rooturl .. lurl, data) then + local x = TXQuery.Create(http.Document) + local total = tonumber(x.xpathstring('json(*).result.totalPageCnt')) + if total == nil then total = 1 end + updatelist.CurrentDirectoryPageNumber = total + local v = x.xpath('json(*).result.list()') + for i = 1, v.count do + local v1 = v.get(i) + links.add(x.xpathstring('title_url', v1)) + names.add(x.xpathstring('title_name', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'PlusComico' + m.rooturl = 'http://plus.comico.jp' + m.category = 'Raw' + m.lastupdated='May 1, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.totaldirectory = #dirurls + m.ondownloadimage = 'downloadimage' +end From bc1314efed572414e909786ec961b105e2e06b28 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 May 2018 16:03:12 +0300 Subject: [PATCH 2606/2794] ReadComicBooksOnline, fix getinfo fixes #1235 --- lua/modules/ReadComicBooksOnline.lua | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lua/modules/ReadComicBooksOnline.lua b/lua/modules/ReadComicBooksOnline.lua index d3905ad40..3f6098e85 100644 --- a/lua/modules/ReadComicBooksOnline.lua +++ b/lua/modules/ReadComicBooksOnline.lua @@ -2,12 +2,15 @@ mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then local x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Comic Title")]/td[@class="info"]') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@class="thispic"]/@src')) - mangainfo.authors=x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Author")]/td[@class="info"]') - mangainfo.genres=x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Genre")]/td[@class="info"]') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="info"]//tr[contains(td[@class="title"], "Status")]/td[@class="info"]')) - mangainfo.summary=x.xpathstringall('//div[@id="summary"]/text()', '') + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1[@class="page-title"]') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@class="series"]/@src')) + mangainfo.authors=x.xpathstringall('//li[@class="info" and contains(*, "Author")]/text()', '') + mangainfo.artists = mangainfo.authors + mangainfo.genres=x.xpathstringall('//li[@class="info" and contains(*, "Genre")]/text()', '') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstringall('//li[@class="info" and contains(*, "Status")]/text()', '')) + mangainfo.summary=x.xpathstringall('//li[@class="summary"]/text()', '') x.xpathhrefall('//div[@id="chapterlist"]/li/a',mangainfo.chapterlinks,mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) http.reset() From 1b91e31f2e366c1beea881caea77ceb167c83cac Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 16 May 2018 20:12:53 +0300 Subject: [PATCH 2607/2794] HeavenManga, change domain --- lua/modules/HeavenManga.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index b6f405c67..3ca4b2a42 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -68,7 +68,7 @@ end function Init() local m = NewModule() m.website = 'HeavenManga' - m.rooturl = 'http://heavenmanga.site' + m.rooturl = 'http://heavenmanga.world' m.category = 'English' m.lastupdated='February 26, 2018' m.ongetinfo='getinfo' From a0703b5c1e730d7d02660affff5674bb51a8ad8b Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 May 2018 07:11:29 +0300 Subject: [PATCH 2608/2794] rename MangaKakalot --- lua/modules/{Mangakakalot.lua => MangaKakalot.lua} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename lua/modules/{Mangakakalot.lua => MangaKakalot.lua} (96%) diff --git a/lua/modules/Mangakakalot.lua b/lua/modules/MangaKakalot.lua similarity index 96% rename from lua/modules/Mangakakalot.lua rename to lua/modules/MangaKakalot.lua index 67d0bcb7f..b4fa4c5f1 100644 --- a/lua/modules/Mangakakalot.lua +++ b/lua/modules/MangaKakalot.lua @@ -135,9 +135,9 @@ function AddWebsiteModule(name, url) end function Init() - AddWebsiteModule('Mangakakalot', 'http://mangakakalot.com') - AddWebsiteModule('Manganelo', 'http://manganelo.com') - AddWebsiteModule('Mangasupa', 'http://mangasupa.com') + AddWebsiteModule('MangaKakalot', 'http://mangakakalot.com') + AddWebsiteModule('MangaNelo', 'http://manganelo.com') + AddWebsiteModule('MangaSupa', 'http://mangasupa.com') AddWebsiteModule('MangaHereIO', 'https://manga-here.io') AddWebsiteModule('MangaFoxCom', 'https://manga-fox.com') end From 1e35d65b2a6b98dc1950c4b6d1ca5fc42d921eda Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 May 2018 10:28:15 +0300 Subject: [PATCH 2609/2794] add ZingBox [en] fixes #1239 --- lua/modules/ZingBox.lua | 89 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 lua/modules/ZingBox.lua diff --git a/lua/modules/ZingBox.lua b/lua/modules/ZingBox.lua new file mode 100644 index 000000000..fef52d85c --- /dev/null +++ b/lua/modules/ZingBox.lua @@ -0,0 +1,89 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + local id = RegExprGetMatch('(manga|comicDetail)\\/(.+?)\\/', url, 2) + local data = string.format('url=/manga/getBookDetail/%s&method=GET', id) + if url:match('comicDetail') == nil then + data = data .. '&api=/mangaheatapi/web' + end + if http.post(module.rooturl .. '/api', data) then + local x=TXQuery.Create(http.document) + local json = x.xpath('json(*)') + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('./title',json) + end + mangainfo.coverlink=x.xpathstring('./cover',json) + mangainfo.authors=x.xpathstring('./author',json) + mangainfo.genres=x.xpathstring('./tags',json) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('./updateStatus',json)) + mangainfo.summary=x.xpathstring('./summary',json) + local v = x.xpath('jn:members(child)', json) + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(x.xpathstring('./chapterId', v1)) + mangainfo.chapternames.add(x.xpathstring('./title', v1) .. ' - ' .. x.xpathstring('./summary', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + url = url:gsub('/', '') + local data = string.format('url=/manga/getChapterImages/%s&method=GET', url) + if tonumber(url) ~= nil then + data = data .. '&api=/mangaheatapi/web' + end + if http.post(module.rooturl .. '/api', data) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('json(*).images()', task.pagelinks) + else + return false + end + return true +end + +local dirdata = { + 'url=/manga/getBookRecommend/%s?tag=&method=GET', + 'url=/manga/getAZ/%s?tag=&method=GET&api=/mangaheatapi/web' +} + +function getnameandlink() + local data = string.format(dirdata[module.CurrentDirectoryIndex+1], IncStr(url)) + local d = 'manga' + if module.CurrentDirectoryIndex == 0 then + d = 'comicDetail' + end + if http.post(module.rooturl .. '/api', data) then + local x = TXQuery.Create(http.Document) + local hasTitles = false + local v = x.xpath('json(*).child()') + for i = 1, v.count do + local v1 = v.get(i) + links.add(module.rooturl .. string.format('/%s/%s/%s', d, x.xpathstring('bookId', v1), x.xpathstring('title', v1))) + names.add(x.xpathstring('title', v1)) + hasTitles = true + end + if hasTitles then + updatelist.CurrentDirectoryPageNumber = 2 --updatelist.CurrentDirectoryPageNumber + 1 + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'ZingBox' + m.rooturl = 'http://www.zingbox.me' + m.category = 'English' + m.lastupdated='May 17, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.totaldirectory = #dirdata +end From 381615752718fe66722c70ec91f851b3d6b69ea7 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 May 2018 10:29:49 +0300 Subject: [PATCH 2610/2794] ZingBox, fix --- lua/modules/ZingBox.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/ZingBox.lua b/lua/modules/ZingBox.lua index fef52d85c..51c5eee4e 100644 --- a/lua/modules/ZingBox.lua +++ b/lua/modules/ZingBox.lua @@ -68,7 +68,7 @@ function getnameandlink() hasTitles = true end if hasTitles then - updatelist.CurrentDirectoryPageNumber = 2 --updatelist.CurrentDirectoryPageNumber + 1 + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 end return no_error else From 3545836a869dd8243f05e63ef9d662a5e97cc213 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 19 May 2018 07:45:22 +0300 Subject: [PATCH 2611/2794] add MangaRoom [en] --- lua/modules/MangaRoom.lua | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lua/modules/MangaRoom.lua diff --git a/lua/modules/MangaRoom.lua b/lua/modules/MangaRoom.lua new file mode 100644 index 000000000..6784dcf64 --- /dev/null +++ b/lua/modules/MangaRoom.lua @@ -0,0 +1,60 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//div[@class="col-md-12"]/h3') + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//div[@class="col-md-12"]/div/img[contains(@class, "img")]/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[contains(@class, "info_list")]//tr[contains(td, "Status")]/td[2]')) + mangainfo.authors=x.xpathstring('//table[contains(@class, "info_list")]//tr[contains(td, "Author")]/td[2]') + mangainfo.artists=x.xpathstring('//table[contains(@class, "info_list")]//tr[contains(td, "Artist")]/td[2]') + mangainfo.genres=x.xpathstringall('//table[contains(@class, "info_list")]//tr[contains(td, "Genres")]/td[2]/a') + mangainfo.summary=x.xpathstring('//div[contains(@class, "summary")]/p') + x.xpathhrefall('//table[contains(@class,"chapter-list")]//tr/td[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, '/manga' .. url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="page_container"]/img[contains(@class, "manga_page")]/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + local dirurl = string.format('/search?search-words=&status=%d-page-%s', module.CurrentDirectoryIndex, IncStr(url)) + if http.get(module.rooturl..dirurl) then + local x = TXQuery.Create(http.document) + if updatelist.CurrentDirectoryPageNumber <= 1 then + local page = x.xpathstring('//ul[contains(@class,"pagination")]/li[last()-1]/a/@href') + page = tonumber(page:match('page%-(%d+)')) + if page == nil then page = 1 end + updatelist.CurrentDirectoryPageNumber = page + end + x.xpathhrefall('//div[@id="content_item"]//div[@class="manga_title"]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='English' + m.website='MangaRoom' + m.rooturl='http://manga-room.com' + m.lastupdated='April 8, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.totaldirectory=2 +end From 00eb69dbe318576caeaa9f9544b047a507417465 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 21 May 2018 17:07:15 +0300 Subject: [PATCH 2612/2794] add RawNeko [raw] --- lua/modules/rawdevart.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index ed19f5f91..47ca0a28a 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -3,7 +3,13 @@ function getinfo() if http.get(mangainfo.url) then x=TXQuery.Create(http.document) mangainfo.title=x.xpathstringall('//div[@class="post-title"]/h3/text()', '') - mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@src') + if string.match(mangainfo.title:upper(), ' RAW$') ~= nil then + mangainfo.title = mangainfo.title:sub(1, -5) + end + mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@data-src') + if mangainfo.coverlink == '' then + mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@src') + end mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') @@ -63,6 +69,7 @@ end function Init() local cat = 'Raw' AddWebsiteModule('Rawdevart', 'https://rawdevart.com', cat) + AddWebsiteModule('RawNeko', 'http://rawneko.com', cat) cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) From 050fb16f42ea420fd60696daf1e90bc3aed23e7e Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 21 May 2018 17:14:39 +0300 Subject: [PATCH 2613/2794] add MangaHispano [sp] --- lua/modules/myReaderMangaCMS.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 187dac19b..86eea7ffc 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -75,13 +75,17 @@ function AddWebsiteModule(name, url, cat) end function Init() - AddWebsiteModule('MangaForest', 'http://mangaforest.com', 'English') - AddWebsiteModule('MangaDoor', 'http://mangadoor.com', 'Spanish'); + local c='English' + AddWebsiteModule('MangaForest', 'http://mangaforest.com', c) - local c='Indonesian' + c='Spanish' + AddWebsiteModule('MangaDoor', 'http://mangadoor.com', c); + AddWebsiteModule('MangaHispano', 'https://mangahis.com', c); + + c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); AddWebsiteModule('MangaDesu','http://mangadesu.net', c); - AddWebsiteModule('MangaID', 'http://mangaid.co', c); + AddWebsiteModule('MangaID', 'http://mangaid.co', c); c='Raw' AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', c); From 6aae49ef1f58fa399b64715df837ea0be8634373 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 22 May 2018 16:57:41 +0300 Subject: [PATCH 2614/2794] add WestManga [id] --- lua/modules/MangaShiro.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 86712721c..ee90b965c 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -9,6 +9,13 @@ function getinfo() mangainfo.genres=x.xpathstringall('//div[@class="topinfo"]//tr[contains(th, "Genres")]/td/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstringall('//*[@class="sin"]/p/text()', '') + elseif module.website == 'WestManga' then + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="naru"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="infozin"]//li[starts-with(.,"Author")]/substring-after(.,":")') + mangainfo.genres=x.xpathstringall('//div[@class="infozin"]//li[starts-with(.,"Genre")]/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="infozin"]//li[starts-with(.,"Status")]'), "Publishing", "Finished") + mangainfo.summary=x.xpathstringall('//*[@class="sinopc"]/p/text()', '') else mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) @@ -29,7 +36,11 @@ function getpagenumber() task.pagenumber=0 task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl,url)) then - TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + if module.website == 'WestManga' then + TXQuery.Create(http.Document).xpathstringall('//*[@class="lexot"]//img/@src', task.pagelinks) + else + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + end return true else return false @@ -46,6 +57,8 @@ function getnameandlink() if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) + elseif module.website == 'WestManga' then + TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) else TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) end @@ -75,4 +88,5 @@ function Init() AddWebsiteModule('KomikStation', 'http://www.komikstation.com') AddWebsiteModule('MangaKid', 'http://mangakid.net') AddWebsiteModule('KomikCast', 'https://komikcast.com') + AddWebsiteModule('WestManga', 'https://westmanga.info') end From be26998d67498323aa602b0eb9285e0a89bbea5b Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 23 May 2018 10:34:47 +0300 Subject: [PATCH 2615/2794] add dm5 [raw] --- lua/modules/dm5.lua | 150 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 lua/modules/dm5.lua diff --git a/lua/modules/dm5.lua b/lua/modules/dm5.lua new file mode 100644 index 000000000..95cb4809e --- /dev/null +++ b/lua/modules/dm5.lua @@ -0,0 +1,150 @@ +function getinfo() + mangainfo.url = MaybeFillHost(module.RootURL, url) + http.cookies.values['isAdult'] = '1' + if http.get(mangainfo.url) then + local x = TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//p[@class="title"]') + end + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[@class="cover"]/img/@src')) + mangainfo.authors=x.xpathstringall('//div[@class="info"]/p[@class="subtitle"]/a') + mangainfo.genres=x.xpathstringall('//div[@class="info"]/p[@class="tip"]/span[contains(., "题材")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="info"]/p[@class="tip"]/span[contains(., "状态")]/span'), '连载中', '已完结'); + mangainfo.summary=x.xpathstring('//div[@class="info"]/p[@class="content"]') + v=x.xpath('//div[@id="chapterlistload"]/ul') + for i = 1, v.count do + local v1 = v.get(i) + local w = x.xpath('.//li/a', v1) + for j = 1, w.count do + local w1 = w.get(j) + mangainfo.chapterlinks.add(module.RootURL .. w1.getAttribute('href')) + mangainfo.chapternames.add(w1.toString) + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function urlencode(str) + if (str) then + str = string.gsub (str, "\n", "\r\n") + str = string.gsub (str, "([^%w ])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub (str, " ", "+") + end + return str +end + +local js = require 'modules.jsunpack' +function gettext(s) + s = SeparateRight(s, "}('") + local text = SeparateLeft(s, "',") + local a = tonumber(GetBetween("',", ",", s)) + s = SeparateRight(s, "',") + local c = tonumber(GetBetween(",", ",'", s)) + local w = js.splitstr(GetBetween(",'", "'", s), '|') + return js.unpack36(text, a, c, w) +end + +function getpagenumber() + local u = MaybeFillHost(module.rooturl,url) + if http.get(u) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "DM5_MID")]') + local dm5mid = GetBetween('DM5_MID=', ';', s) + local dm5cid = GetBetween('DM5_CID=', ';', s) + local dm5viewsign = GetBetween('DM5_VIEWSIGN="', '";', s) + local dm5viewsigndt = GetBetween('DM5_VIEWSIGN_DT="', '";', s) + local dm5key = x.xpathstring('//*[@id="dm5_key"]/@value') + local dm5page, cnt = 1, 0 + + task.pagenumber = tonumber(x.xpathstring('(//div[@id="chapterpager"])[1]/a[last()]')) + if task.pagenumber == nil then task.pagenumber = 0 end + + while (cnt < task.pagenumber) and (dm5page < task.pagenumber) do + local xhrurl = string.format('%s/chapterfun.ashx?cid=%s&page=%d&key=%s&language=1>k=6&_cid=%s&_mid=%s&_dt=%s&_sign=%s', + RemoveURLDelim(u), dm5cid, dm5page, dm5key, dm5cid, dm5mid, urlencode(dm5viewsigndt), dm5viewsign) + if http.terminated then break end + http.reset() + http.headers.values['Referer'] = u + if http.xhr(xhrurl) then + local s = gettext(StreamToString(http.document)) + local cid = GetBetween('cid=', ';', s) + local key = GetBetween("key=\\'", "\\';", s) + local pix = GetBetween('pix="', '";', s) + local pvalue = '[' .. GetBetween('pvalue=[', '];', s) .. ']' + x.parsehtml(pvalue) + local v = x.xpath('json(*)()') + for i = 1, v.count do + local v1 = v.get(i) + task.pagelinks.add(pix .. v1.toString .. string.format('?cid=%s&key=%s', cid, key)) + cnt = cnt + 1 + end + dm5page = dm5page + v.count + else + return false + end + end + task.pagecontainerlinks.text = u + return true + else + return false + end +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = task.pagecontainerlinks.text + return true +end + +local perpage = 100 +function getdirectorypagenumber() + local u = string.format('%s/dm5.ashx?t=%d', module.rooturl, os.time()*1000) + local data = 'pagesize=1&pageindex=1&tagid=0&areaid=0&status=0&usergroup=0&pay=-1&char=&sort=18&action=getclasscomics' + if http.POST(u, data) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('json(*).Count')) + if page == nil then + page = 1 + else + page = math.ceil(page / perpage) + end + return no_error + else + return net_problem + end +end + +function getnameandlink() + local u = string.format('%s/dm5.ashx?t=%d', module.rooturl, os.time()*1000) + local data = string.format('pagesize=%d&pageindex=%d&tagid=0&areaid=0&status=0&usergroup=0&pay=-1&char=&sort=18&action=getclasscomics', perpage, IncStr(url)) + if http.post(u, data) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('json(*).UpdateComicItems()') + for i = 1, v.count do + local v1 = v.get(i) + links.add(module.rooturl .. '/' .. x.xpathstring('UrlKey', v1) .. '/') + names.add(x.xpathstring('Title', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Raw' + m.website='DM5' + m.rooturl='http://www.dm5.com' + m.lastupdated='May 23, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetdirectorypagenumber='getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' + m.sortedlist = true +end From dff2bfd74d3288c8aad7e0c5977d2371367b056c Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 23 May 2018 11:17:09 +0300 Subject: [PATCH 2616/2794] fix --- lua/modules/dm5.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lua/modules/dm5.lua b/lua/modules/dm5.lua index 95cb4809e..a603b5cd0 100644 --- a/lua/modules/dm5.lua +++ b/lua/modules/dm5.lua @@ -4,7 +4,7 @@ if http.get(mangainfo.url) then local x = TXQuery.Create(http.document) if mangainfo.title == '' then - mangainfo.title=x.xpathstring('//p[@class="title"]') + mangainfo.title=x.xpathstring('//div[@class="banner_detail_form"]//p[@class="title"]/text()') end mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[@class="cover"]/img/@src')) mangainfo.authors=x.xpathstringall('//div[@class="info"]/p[@class="subtitle"]/a') @@ -61,10 +61,10 @@ function getpagenumber() local dm5key = x.xpathstring('//*[@id="dm5_key"]/@value') local dm5page, cnt = 1, 0 - task.pagenumber = tonumber(x.xpathstring('(//div[@id="chapterpager"])[1]/a[last()]')) - if task.pagenumber == nil then task.pagenumber = 0 end + local total = tonumber(x.xpathstring('(//div[@id="chapterpager"])[1]/a[last()]')) + if total == nil then total = 0 end - while (cnt < task.pagenumber) and (dm5page < task.pagenumber) do + while (cnt < total) and (dm5page <= total) do local xhrurl = string.format('%s/chapterfun.ashx?cid=%s&page=%d&key=%s&language=1>k=6&_cid=%s&_mid=%s&_dt=%s&_sign=%s', RemoveURLDelim(u), dm5cid, dm5page, dm5key, dm5cid, dm5mid, urlencode(dm5viewsigndt), dm5viewsign) if http.terminated then break end From f915831230b9013aec16e366d0bcd01b94f27cc7 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 25 May 2018 16:35:38 +0300 Subject: [PATCH 2617/2794] add TranslateWebtoon (no list) fixes #879 fixes #874 --- baseunits/ModuleList.inc | 1 + baseunits/modules/TranslateWebtoon.pas | 170 +++++++++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 baseunits/modules/TranslateWebtoon.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ba7a6d994..3cf4aaf16 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -53,6 +53,7 @@ uses MangaRock, PsychoPlay, MangaWindow, + TranslateWebtoon, // Raw Official SundayWebEvery, TonariNoYoungJump, diff --git a/baseunits/modules/TranslateWebtoon.pas b/baseunits/modules/TranslateWebtoon.pas new file mode 100644 index 000000000..bc58f6b48 --- /dev/null +++ b/baseunits/modules/TranslateWebtoon.pas @@ -0,0 +1,170 @@ +unit TranslateWebtoon; + +interface + +implementation + +uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, + XQueryEngineHTML, synautil, RegExpr, Graphics, Interfaces; + +function GetInfo(const MangaInfo: TMangaInformation; + const AURL: String; const Module: TModuleContainer): Integer; +var + v: IXQValue; + rate, nextpage: Integer; + s: String; +begin + Result := NET_PROBLEM; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + with MangaInfo.mangaInfo, MangaInfo.FHTTP do + begin + url := ReplaceRegExpr('&page=\d+', MaybeFillHost(Module.RootURL, AURL), '', False); + if GET(url) then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(Document) do + try + coverLink := XPathString('//meta[@property="og:image"]/@content'); + if title = '' then + title := XPathString('//h3[@class="subj"]') + ' [' + + XPathString('//div[@class="info"]/p[contains(@class, "flag")]') + ']'; + authors := XPathString('//span[@class="author"]'); + while True do + begin + for v in XPath('//div[@class="detail_lst"]/ul/li/a') do + begin + s := XPathString('./span[@class="rate"]/em', v); + s := RegExprGetMatch('(\d+)', s, 1); + rate := StrToIntDef(s, 0); + if rate >= 100 then + begin + chapterLinks.Add(v.toNode.getAttribute('href')); + chapterName.Add(XPathString('./span[@class="subj"]', v)); + end; + end; + if ThreadTerminated then Break; + s := XPathString('//div[@class="paginate"]/a[contains(@class, "epipage")]/following-sibling::a[1]/@href'); + s := RegExprGetMatch('page=(\d+)', s, 1); + nextpage := StrToIntDef(s, 0); + if nextpage = 0 then Break; + if not GET(Format('%s&page=%d', [url, nextpage])) then Break; + ParseHTML(Document); + end; + finally + Free; + end; + InvertStrings([chapterLinks, chapterName]); + end; + end; +end; + +function GetPageNumber(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + v, w: IXQValue; + s: String; + tmp: TStringList; +begin + Result := False; + if DownloadThread = nil then Exit; + with DownloadThread.FHTTP, DownloadThread.Task.Container do + begin + PageLinks.Clear; + PageNumber := 0; + if GET(MaybeFillHost(Module.RootURL, AURL)) then + begin + Result := True; + with TXQueryEngineHTML.Create(Document) do + try + tmp := TStringList.Create; + try + for v in XPath('//div[@class="viewer_img"]/ul/li/div[@class="img_info"]') do + begin + tmp.Clear; + for w in XPath('span[@class="ly_img_text"]', v) do + begin + tmp.Add(XPathString('img/@src', w)); + tmp.Add(w.toNode.getAttribute('style')); + end; + PageContainerLinks.Add(tmp.Text); + PageLinks.Add(XPathString('img/@src', v)); + end; + // FIXME: PageContainerLinks.Count shouldn't be equal to PageNumber + PageContainerLinks.Add('$$$'); + finally + tmp.Free; + end; + finally + Free; + end; + end; + end; +end; + +function DownloadImage(const DownloadThread: TDownloadThread; + const AURL: String; const Module: TModuleContainer): Boolean; +var + back, text: TPicture; + tmp: TStringList; + i, left, top: Integer; + src, dst: TRect; + ext: String = 'jpg'; +begin + i := 0; + Result := False; + if DownloadThread = nil then Exit; + if DownloadThread.FHTTP.GET(AURL) then + begin + back := TPicture.Create; + tmp := TStringList.Create; + try + back.LoadFromStream(DownloadThread.FHTTP.Document); + if back.Graphic is TPortableNetworkGraphic then ext := 'png'; + tmp.Text := DownloadThread.Task.Container.PageContainerLinks[DownloadThread.WorkId]; + while i < tmp.Count-1 do + begin + if DownloadThread.FHTTP.GET(tmp[i]) then + begin + text := TPicture.Create; + try + text.LoadFromStream(DownloadThread.FHTTP.Document); + src := Rect(0, 0, text.Width, text.Height); + left := StrToIntDef(RegExprGetMatch('left\s*:\s*(\d+)', tmp[i+1], 1), 0); + top := StrToIntDef(RegExprGetMatch('top\s*:\s*(\d+)', tmp[i+1], 1), 0); + dst := Rect(left, top, left + text.Width, top + text.Height); + back.Bitmap.Canvas.CopyRect(dst, text.Bitmap.Canvas, src); + finally + text.Free; + end; + end; + i := i + 2; + if DownloadThread.CheckTerminated then Break; + end; + DownloadThread.FHTTP.Document.Position := 0; + DownloadThread.FHTTP.Document.Size := 0; + back.SaveToStreamWithFileExt(DownloadThread.FHTTP.Document, ext); + finally + back.Free; + tmp.Free; + end; + Result := True; + end; +end; + +procedure RegisterModule; +begin + with AddModule do + begin + Website := 'TranslateWebtoon'; + RootURL := 'https://translate.webtoons.com'; + OnGetInfo := @GetInfo; + OnGetPageNumber := @GetPageNumber; + OnDownloadImage := @DownloadImage; + end; +end; + +initialization + RegisterModule; + +end. + From a266427c5081183cfd65d0e5d32566f59f328e0d Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 25 May 2018 16:37:05 +0300 Subject: [PATCH 2618/2794] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51faf1300..95272f9c5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Download the latest release -[![GitHub release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0.7z) [![Github Releases (by Asset)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0_Win64.7z) +[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0_Win64.7z) ## Content From 83e25fc95befda0f078d4d5894640766f14606e4 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 26 May 2018 07:22:43 +0300 Subject: [PATCH 2619/2794] MyReadingManga, fix get list fixes #1258 fixes #1221 --- lua/modules/MyReadingManga.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/modules/MyReadingManga.lua b/lua/modules/MyReadingManga.lua index f7e4b4eb1..b93776ba8 100644 --- a/lua/modules/MyReadingManga.lua +++ b/lua/modules/MyReadingManga.lua @@ -57,7 +57,7 @@ function getdirectorypagenumber() end function getnameandlink() - if http.get(module.rooturl .. '/page/' .. IncStr(AURL) .. '/') then + if http.get(module.rooturl .. '/page/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.Document) x.XPathHREFAll('//h2[@class="entry-title"]/a', links, names) return no_error @@ -76,4 +76,5 @@ function Init() m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.ongetdirectorypagenumber = 'getdirectorypagenumber' + m.sortedlist = true end From 19c748c0841b2e223cc67d2b0fd86201da34ee9b Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 26 May 2018 08:07:40 +0300 Subject: [PATCH 2620/2794] SubManga, move to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/SubManga.pas | 161 --------------------------------- lua/modules/SubManga.lua | 61 +++++++++++++ 3 files changed, 61 insertions(+), 162 deletions(-) delete mode 100644 baseunits/modules/SubManga.pas create mode 100644 lua/modules/SubManga.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 3cf4aaf16..96b574577 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -19,7 +19,6 @@ uses AcademyVN, Webtoons, Tsumino, - SubManga, Tumangaonline, MangaEden, HeyMangaXyz, diff --git a/baseunits/modules/SubManga.pas b/baseunits/modules/SubManga.pas deleted file mode 100644 index 7b3997b78..000000000 --- a/baseunits/modules/SubManga.pas +++ /dev/null @@ -1,161 +0,0 @@ -unit SubManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr; - -implementation - -const - dirurl = '/series'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '10000000') then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - page := StrToIntDef(XPathString('//ul[@class="pagination"]/li[last()-1]'), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//table[@class="caps"]/tbody/tr/td[1]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('text()', v.toNode)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//p[@class="cb"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//div[@id="b"]//h1/a'); - summary := XPathString('//div[@id="b"]/div[2]/p[3]'); - genres := XPathString('//div[@id="b"]/div[2]/p[4]'); - authors := XPathString('//div[@id="b"]/div[2]/p[5]/a'); - if XPath('//table[@class="caps"]/tbody/tr').Count > 0 then - if GET(AppendURLDelim(url) + 'completa') then begin - ParseHTML(Document); - with TRegExpr.Create do - try - Expression := '^.*/(\d+)/?$'; - for v in XPath('//table[@class="caps"]/tbody/tr/td[@class="s"]/a') do begin - s := v.toNode.getAttribute('href'); - if s <> '' then begin - s := Replace(s, '/c/$1', True); - chapterLinks.Add(s); - chapterName.Add(v.toString); - end; - end; - finally - Free; - end; - InvertStrings([chapterLinks, chapterName]); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('//table[1]/tbody//select/option').Count; - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := FillHost(Module.RootURL, AURL); - if DownloadThread.WorkId > 0 then - s := s + '/' + IncStr(DownloadThread.WorkId); - if GET(s) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := XPathString('//div[@id="ab"]/a/img/@src'); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'SubManga'; - RootURL := 'http://submanga.com'; - Category := 'Spanish'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/SubManga.lua b/lua/modules/SubManga.lua new file mode 100644 index 000000000..6bdab9b3b --- /dev/null +++ b/lua/modules/SubManga.lua @@ -0,0 +1,61 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = Trim(x.XPathString('//div[contains(@class, "col-md-3")]//h3/text()')) + end + mangainfo.coverlink = x.xpathstring('//div[contains(@class, "col-md-3")]//img[@class="img-responsive"]/@src') + mangainfo.authors=Trim(x.xpathstring('//span[@class="list-group-item" and contains(., "Autor")]/a')) + mangainfo.artists=Trim(x.xpathstring('//span[@class="list-group-item" and contains(., "Artist")]/a')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//span[@class="list-group-item" and contains(., "Estado")]')) + mangainfo.summary = x.xpathstringall('//span[@class="list-group-item" and contains(., "Resumen")]/text()', '') + x.xpathhrefall('//table//tr/td[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + http.reset() + http.headers.values['Referer'] = mangainfo.url + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagecontainerlinks.clear() + local url = MaybeFillHost(module.rooturl, url); + if http.get(url) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//*[@id="all"]/img/@data-src', task.pagelinks) + task.pagecontainerlinks.text = url + else + return false + end + return true +end + +function BeforeDownloadImage() + http.headers.values['Referer'] = task.pagecontainerlinks.text + return true +end + +function getnameandlink() + if http.GET(module.RootURL .. '/changeMangaList?type=text') then + TXQuery.Create(http.Document).XPathHREFAll('//li/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'SubManga' + m.rooturl = 'https://submanga.online' + m.category = 'Spanish' + m.lastupdated='May 26, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' +end From 39a1ec07f98f50d287d6366214e6cc9d7ae271fa Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 26 May 2018 08:55:43 +0300 Subject: [PATCH 2621/2794] HatigarmScans, change domain fixes #1259 --- lua/modules/FoOlSlide.lua | 7 ------- lua/modules/myReaderMangaCMS.lua | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 758934f59..fd1e7f7b0 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -47,7 +47,6 @@ function getdirurl(website) ['Riceballicious'] = dirurlreaderlist, ['Yuri-ism'] = dirurlslide, ['MangajinNoFansub'] = dirurllector, - ['HatigarmScans'] = '/hs/directory/', ['BunnysScans'] = '/read/directory/', ['CanisMajorScans'] = dirurlreader, ['HoshikuzuuScans'] = dirurl, @@ -80,9 +79,6 @@ function getinfo() mangainfo.title = Trim(SeparateLeft(x.xpathstring('//title'), '::')) end local cls = 'info' - if module.website == 'HatigarmScans' then - cls = 'well' - end mangainfo.authors = string.gsub( x.xpathstring('//div[@class="'..cls..'"]/*[contains(text(),"Author")]/following-sibling::text()[1]'), '^[%s:]*', '') @@ -209,8 +205,6 @@ function getnameandlink() links.add(v1.getattribute('href')) names.add(x.xpathstring('span', v1)) end - elseif module.website == 'HatigarmScans' then - x.XpathHREFAll('//div[@class="grid"]/div/a', links, names) else x.XpathHREFAll('//div[@class="list series"]/div/div[@class="title"]/a', links, names) end @@ -266,7 +260,6 @@ function Init() AddWebsiteModule('SaikoScans', 'http://saikoscans.ml', cat) AddWebsiteModule('Yuri-ism', 'https://www.yuri-ism.net', cat) AddWebsiteModule('SilentSkyScans', 'http://reader.silentsky-scans.net', cat) - AddWebsiteModule('HatigarmScans', 'http://hatigarmscans.eu', cat) AddWebsiteModule('BunnysScans', 'http://bns.shounen-ai.net', cat) AddWebsiteModule('CanisMajorScans', 'http://cm-scans.shounen-ai.net', cat) AddWebsiteModule('HoshikuzuuScans', 'http://hoshiscans.shounen-ai.net', cat) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 86eea7ffc..beb5901fa 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -100,6 +100,7 @@ function Init() AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); AddWebsiteModule('ChibiManga','http://www.cmreader.info', c); AddWebsiteModule('WhiteCloudPavilion','https://whitecloudpavilion.com', c); + AddWebsiteModule('HatigarmScans', 'https://www.hatigarmscans.net', c) c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); From 26d6f07570dc196f8e2f0a301410a11d63be74ee Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 30 May 2018 07:31:20 +0300 Subject: [PATCH 2622/2794] add RawQV [raw] --- lua/modules/Lhscans.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua index 43c16b1f3..786aea751 100644 --- a/lua/modules/Lhscans.lua +++ b/lua/modules/Lhscans.lua @@ -67,4 +67,5 @@ function Init() local cat = 'Raw' AddWebsiteModule('Lhscans', 'http://rawlh.com', cat) AddWebsiteModule('RawQQ', 'https://rawqq.com', cat) + AddWebsiteModule('RawQV', 'http://rawqv.com', cat) end From ee0f9e8c3a595c9faece7019c693a0c69dc53e44 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 31 May 2018 19:31:37 +0300 Subject: [PATCH 2623/2794] add AsmHentai fixes #1268 --- lua/modules/AsmHentai.lua | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 lua/modules/AsmHentai.lua diff --git a/lua/modules/AsmHentai.lua b/lua/modules/AsmHentai.lua new file mode 100644 index 000000000..41547a7a1 --- /dev/null +++ b/lua/modules/AsmHentai.lua @@ -0,0 +1,67 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//div[@class="info"]/h1') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="cover"]/a/img/@src')) + mangainfo.authors=x.xpathstringall('//div[@class="tags" and contains(h3, "Artist")]/div/a/span/text()') + mangainfo.genres=x.xpathstringall('//div[@class="tags" and (contains(h3, "Tags") or contains(h3, "Category"))]/div/a/span/text()') + mangainfo.chapterlinks.add(mangainfo.url) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local v = x.xpath('//*[@class="gallery"]//img/@data-src') + for i = 1, v.count do + local s = v.get(i).toString; + s = s:gsub('^//', 'https://'):gsub('(/%d+)[tT]%.', '%1.') + task.pagelinks.add(s) + end + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('//*[@class="pagination"]/a[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl .. '/pag/' .. IncStr(url) .. '/') then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//*[@class="preview_item"]/*[@class="caption"]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'AsmHentai' + m.rooturl = 'https://asmhentai.com' + m.category = 'H-Sites' + m.lastupdated='May 31, 2018' + m.sortedlist = true + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end From d5f62db07d248b2e4a728431e776de94912b78a6 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 3 Jun 2018 16:19:18 +0300 Subject: [PATCH 2624/2794] HentaiFox, move to lua --- baseunits/ModuleList.inc | 3 +- baseunits/modules/HentaiFox.pas | 108 ------------------- lua/modules/{AsmHentai.lua => HentaiFox.lua} | 29 +++-- 3 files changed, 23 insertions(+), 117 deletions(-) delete mode 100644 baseunits/modules/HentaiFox.pas rename lua/modules/{AsmHentai.lua => HentaiFox.lua} (62%) diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 96b574577..0fa2dcbf9 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -67,5 +67,4 @@ uses EightMuses, HitomiLa, HentaiCafe, - Hentai2Read, - HentaiFox; + Hentai2Read; diff --git a/baseunits/modules/HentaiFox.pas b/baseunits/modules/HentaiFox.pas deleted file mode 100644 index bcf67936f..000000000 --- a/baseunits/modules/HentaiFox.pas +++ /dev/null @@ -1,108 +0,0 @@ -unit HentaiFox; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, RegExpr; - -implementation - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL) then - begin - Result := NO_ERROR; - Page := StrToIntDef(XPathString('//*[@class="pagination"]/a[last()-1]', MangaInfo.FHTTP.Document), 1); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/pag/' + IncStr(AURL) + '/') then - begin - Result := NO_ERROR; - XPathHREFAll('//*[@class="galleries_overview"]//*[contains(@class,"item")]/a', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); - if title = '' then title := XPathString('//*[@class="info"]/h1'); - artists := XPathString('//*[@class="info"]/span[starts-with(.,"Artist")]/substring-after(.,": ")'); - genres := XPathString('//*[@class="info"]/string-join(./span/a,", ")'); - chapterLinks.Add(url); - chapterName.Add(title); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; - i: Integer; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - XPathStringAll('//*[@class="gallery"]//img/@data-src', Document, PageLinks); - if PageLinks.Count <> 0 then - begin - for i := 0 to PageLinks.Count - 1 do - begin - if LeftStr(PageLinks[i], 2) = '//' then - PageLinks[i] := 'https:' + PageLinks[i]; - end; - PageLinks.Text := ReplaceRegExpr('(?i)(/\d+)t\.', PageLinks.Text, '$1.', True); - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'HentaiFox'; - RootURL := 'https://hentaifox.com'; - Category := 'H-Sites'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/AsmHentai.lua b/lua/modules/HentaiFox.lua similarity index 62% rename from lua/modules/AsmHentai.lua rename to lua/modules/HentaiFox.lua index 41547a7a1..9f0c0b4b1 100644 --- a/lua/modules/AsmHentai.lua +++ b/lua/modules/HentaiFox.lua @@ -5,9 +5,14 @@ function getinfo() if mangainfo.title == '' then mangainfo.title = x.xpathstring('//div[@class="info"]/h1') end - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="cover"]/a/img/@src')) - mangainfo.authors=x.xpathstringall('//div[@class="tags" and contains(h3, "Artist")]/div/a/span/text()') - mangainfo.genres=x.xpathstringall('//div[@class="tags" and (contains(h3, "Tags") or contains(h3, "Category"))]/div/a/span/text()') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="cover"]//img/@src')) + if module.website == 'HentaiFox' then + mangainfo.artists=x.xpathstringall('//*[@class="info"]/span[starts-with(.,"Artist")]/substring-after(.,": ")') + mangainfo.genres=x.xpathstringall('//*[@class="info"]/string-join(./span/a,", ")') + else + mangainfo.artists=x.xpathstringall('//div[@class="tags" and contains(h3, "Artist")]/div/a/span/text()') + mangainfo.genres=x.xpathstringall('//div[@class="tags" and (contains(h3, "Tags") or contains(h3, "Category"))]/div/a/span/text()') + end mangainfo.chapterlinks.add(mangainfo.url) mangainfo.chapternames.add(mangainfo.title) return no_error @@ -46,17 +51,21 @@ end function getnameandlink() if http.get(module.rooturl .. '/pag/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.Document) - x.xpathhrefall('//*[@class="preview_item"]/*[@class="caption"]/a', links, names) + if module.website == 'HentaiFox' then + x.xpathhrefall('//*[@class="galleries_overview"]//*[contains(@class,"item")]/a', links, names) + else + x.xpathhrefall('//*[@class="preview_item"]/*[@class="caption"]/a', links, names) + end return no_error else return net_problem end end -function Init() +function AddWebsiteModule(name, url) local m = NewModule() - m.website = 'AsmHentai' - m.rooturl = 'https://asmhentai.com' + m.website = name + m.rooturl = url m.category = 'H-Sites' m.lastupdated='May 31, 2018' m.sortedlist = true @@ -64,4 +73,10 @@ function Init() m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.ongetdirectorypagenumber = 'getdirectorypagenumber' + return m +end + +function Init() + AddWebsiteModule('HentaiFox', 'https://hentaifox.com') + AddWebsiteModule('AsmHentai', 'https://asmhentai.com') end From b0c901b268b2f2a301531d83dfe7b59a3af7b4e6 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 3 Jun 2018 16:41:34 +0300 Subject: [PATCH 2625/2794] LuaWebsiteModules, fix account support --- baseunits/lua/LuaWebsiteModules.pas | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index d5e9b0838..acc493e3f 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -434,7 +434,7 @@ function DoLogin(const AHTTP: THTTPSendThread; const Module: TModuleContainer): luaPushObject(l, AHTTP, 'http', @luaHTTPSendThreadAddMetaTable); LuaDoMe(l); - LuaCallFunction(l, OnTaskStart); + LuaCallFunction(l, OnLogin); Result := lua_toboolean(l, -1); except on E: Exception do @@ -768,6 +768,18 @@ function lua_getoption(L: Plua_State): Integer; cdecl; end; end; +function lua_getaccountsupport(L: Plua_State): Integer; cdecl; +begin + lua_pushboolean(L, TLuaWebsiteModule(luaClassGetObject(L)).Module.AccountSupport); + Result := 1; +end; + +function lua_setaccountsupport(L: Plua_State): Integer; cdecl; +begin + Result := 0; + TLuaWebsiteModule(luaClassGetObject(L)).Module.AccountSupport := lua_toboolean(L, 1); +end; + const methods: packed array [0..5] of luaL_Reg = ( (name: 'AddOptionCheckBox'; func: @lua_addoptioncheckbox), @@ -806,7 +818,6 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddIntegerProperty(L, MetaTable, 'ActiveTaskCount', @Module.ActiveTaskCount); luaClassAddIntegerProperty(L, MetaTable, 'ActiveConnectionCount', @Module.ActiveConnectionCount); - luaClassAddBooleanProperty(L, MetaTable, 'AccountSupport', @Module.AccountSupport); luaClassAddBooleanProperty(L, MetaTable, 'SortedList', @Module.SortedList); luaClassAddBooleanProperty(L, MetaTable, 'InformationAvailable', @Module.InformationAvailable); @@ -834,6 +845,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddIntegerProperty(L, MetaTable, 'CurrentDirectoryIndex', @Module.CurrentDirectoryIndex); luaClassAddProperty(L, MetaTable, UserData, 'TotalDirectory', @lua_gettotaldirectory, @lua_settotaldirectory); + luaClassAddProperty(L, MetaTable, UserData, 'AccountSupport', @lua_getaccountsupport, @lua_setaccountsupport); luaClassAddFunction(L, MetaTable, UserData, methods); From b3821708b3dff5158bec139e46fcc9734dcd739e Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 3 Jun 2018 17:58:05 +0300 Subject: [PATCH 2626/2794] add KomikGue [id] --- lua/modules/myReaderMangaCMS.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index beb5901fa..ab0a65c9b 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -86,6 +86,7 @@ function Init() AddWebsiteModule('Komikid', 'http://www.komikid.com', c); AddWebsiteModule('MangaDesu','http://mangadesu.net', c); AddWebsiteModule('MangaID', 'http://mangaid.co', c); + AddWebsiteModule('KomikGue', 'https://www.komikgue.com', c); c='Raw' AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', c); @@ -94,7 +95,7 @@ function Init() c='Turkish' AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', c); AddWebsiteModule('ManhuaTr', 'http://manhua-tr.com', c); - AddWebsiteModule('MangaVadisi', 'http://manga-v2.mangavadisi.org/', c); + AddWebsiteModule('MangaVadisi', 'http://manga-v2.mangavadisi.org', c); c='English-Scanlation' AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); @@ -106,7 +107,7 @@ function Init() AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); - AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com/', c); + AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com', c); AddWebsiteModule('SOSScanlation', 'http://sosscanlation.com', c); c='Italian-Scanlation' From 4a5337a9ca16ef50dbdd4df72e5473018686adb0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 6 Jun 2018 12:27:24 +0300 Subject: [PATCH 2627/2794] add Toonkor [raw] --- lua/modules/Toonkor.lua | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 lua/modules/Toonkor.lua diff --git a/lua/modules/Toonkor.lua b/lua/modules/Toonkor.lua new file mode 100644 index 000000000..a239e83d1 --- /dev/null +++ b/lua/modules/Toonkor.lua @@ -0,0 +1,72 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//table[@class="bt_view1"]//td[@class="bt_title"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//table[@class="bt_view1"]//td[@class="bt_thumb"]//img/@src')) + mangainfo.authors=x.xpathstring('//table[@class="bt_view1"]//span[.="작가"]/following-sibling::span[@class="bt_data"]') + mangainfo.summary=x.xpathstring('//table[@class="bt_view1"]//td[@class="bt_over"]') + local v = x.xpath('//table[@class="web_list"]//tr/td[@class="content__title"]') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('data-role')) + mangainfo.chapternames.add(v1.toString) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "toon_img")]') + x.parsehtml(DecodeBase64(GetBetween("toon_img = '", "';", s))) + local v = x.xpath('//img/@src') + for i = 1, v.count do + task.pagelinks.add(MaybeFillHost(module.RootURL, v.get(i).toString)) + end + task.pagecontainerlinks.values[0] = http.cookies.text + else + return false + end + return true +end + +local dirurls = { + '/%EC%9B%B9%ED%88%B0' +} + +function getnameandlink() + local lurl = dirurls[module.CurrentDirectoryIndex+1] + if http.get(module.rooturl .. lurl) then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//ul[contains(@class, "homelist")]/li/div//a[@id="title"]', links, names) + return no_error + else + return net_problem + end +end + +function beforedownloadimage() + http.reset() + http.cookies.text = task.pagecontainerlinks.values[0] + http.headers.values['Referer'] = module.rooturl + return true +end + +function Init() + local m = NewModule() + m.category = 'Raw' + m.Website = 'Toonkor' + m.RootURL = 'https://toonkor.co' + m.lastupdated='June 6, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.onbeforedownloadimage='beforedownloadimage' + m.totaldirectory = #dirurls +end From db15548d995ced89259a7111fc0ef9adb9cfbd59 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 6 Jun 2018 11:46:26 +0300 Subject: [PATCH 2628/2794] remove bamtoki --- lua/modules/Bamtoki.lua | 70 ----------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 lua/modules/Bamtoki.lua diff --git a/lua/modules/Bamtoki.lua b/lua/modules/Bamtoki.lua deleted file mode 100644 index 01c9daa83..000000000 --- a/lua/modules/Bamtoki.lua +++ /dev/null @@ -1,70 +0,0 @@ -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(mangainfo.url) then - local x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstring('//div[@class="title-section-inner"]/div/h1') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="title-section-inner"]/div/img/@src')) - mangainfo.genres=x.xpathstringall('//div[@class="title-section-inner"]//div[@class="toon-section"]/a') - mangainfo.summary=x.xpathstring('//div[@class="title-section-inner"]//div[@class="toon-section"]/following-sibling::div') - x.xpathhrefall('//ul[@class="list-container"]/li/div[@class="list-item"]/div[contains(@class, "list-details")]//a', mangainfo.chapterlinks,mangainfo.chapternames) - InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) - return no_error - else - return net_problem - end -end - -function getpagenumber() - task.pagelinks.clear() - if http.get(MaybeFillHost(module.rooturl, url)) then - local x=TXQuery.Create(http.Document) - local s = DecodeBase64(x.xpathstring('//*[@id="tooncontentdata"]')) - x.parsehtml(s) - x.xpathstringall('//img/@src', task.pagelinks) - task.pagecontainerlinks.values[0] = http.cookies.text - else - return false - end - return true -end - -local dirurls = { - '/%EC%9B%B9%ED%88%B0/%EC%9E%91%ED%92%88?sort=%EC%A0%9C%EB%AA%A9', - '/%EB%A7%9D%EA%B0%80/%EC%9E%91%ED%92%88?sort=%EC%A0%9C%EB%AA%A9' -} - -function getnameandlink() - local lurl = dirurls[module.CurrentDirectoryIndex+1] - if http.get(module.rooturl .. lurl) then - local x = TXQuery.Create(http.Document) - local v = x.xpath('//div[@class="list-container"]/div/div') - for i = 1, v.count do - local v1 = v.get(i) - links.add(x.xpathstring('./a/@href', v1)) - names.add(x.xpathstring('./div/h3', v1)) - end - return no_error - else - return net_problem - end -end - -function beforedownloadimage() - http.reset() - http.cookies.text = task.pagecontainerlinks.values[0] - http.headers.values['Referer'] = module.rooturl - return true -end - -function Init() - local m = NewModule() - m.website = 'Bamtoki' - m.rooturl = 'https://webtoon.bamtoki.se' - m.category = 'Raw' - m.lastupdated='April 11, 2018' - m.ongetinfo='getinfo' - m.ongetpagenumber='getpagenumber' - m.ongetnameandlink='getnameandlink' - m.onbeforedownloadimage='beforedownloadimage' - m.totaldirectory = #dirurls -end From b154df1616455d4f2fb1e74f9f7122573e93365d Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 7 Jun 2018 16:16:40 +0300 Subject: [PATCH 2629/2794] add 3asq [ar-sc] fixes #1280 --- lua/modules/WPManga.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 2779b5a27..bb5bee08c 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -205,4 +205,7 @@ function Init() cat = 'English-Scanlation' AddWebsiteModule('MangaCow', 'http://mngcow.co', cat) AddWebsiteModule('MerakiScans', 'http://merakiscans.com', cat) + + cat = "Arabic-Scanlation" + AddWebsiteModule('3asq', 'http://www.3asq.info', cat) end From cfdfa66e8e2c441fb26bf875fdaf141bf01d6b80 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 14 Jun 2018 09:08:04 +0300 Subject: [PATCH 2630/2794] fix MangaHispano #1285 --- lua/modules/MangaHispano.lua | 59 ++++++++++++++++++++++++++++++++ lua/modules/myReaderMangaCMS.lua | 1 - 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 lua/modules/MangaHispano.lua diff --git a/lua/modules/MangaHispano.lua b/lua/modules/MangaHispano.lua new file mode 100644 index 000000000..f3e96891c --- /dev/null +++ b/lua/modules/MangaHispano.lua @@ -0,0 +1,59 @@ +function getinfo() + mangainfo.url = MaybeFillHost(module.RootURL, url) + if http.GET(mangainfo.url) then + x = TXQuery.Create(http.Document) + mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//h1[contains(@class,"widget-title")]') + end + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//span[contains(., "Estado")]/span'), 'progres', 'final') + mangainfo.authors = x.XPathStringAll('//span[contains(., "Autor")]/span') + mangainfo.genres = x.XPathStringAll('//dd[@class="sintesis-cat"]/a') + mangainfo.summary = x.XPathString('//div[@class="well"]/p') + v = x.Xpath('//ul/li/*[self::h5 or self::h3 and contains(@class, "chapter-title")]') + for i = 1, v.Count do + v2 = v.Get(i) + mangainfo.chapterLinks.Add(x.XPathString('a/@href', v2)) + mangainfo.chapterNames.Add(x.XPathString('a||": "||em', v2)) + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + x = TXQuery.Create(http.Document) + s = x.xpathstring('//script[contains(., "var pages")]') + s = GetBetween('pages =', ';', s) + x.parsehtml(s) + x.XPathStringAll('json(*)().page_image', task.PageLinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/mangas') then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//div[@class="caption"]/h3/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.category = 'Spanish' + m.Website = 'MangaHispano' + m.RootURL = 'https://mangahis.com' + m.lastupdated='June 14, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end \ No newline at end of file diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index ab0a65c9b..759f874f9 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -80,7 +80,6 @@ function Init() c='Spanish' AddWebsiteModule('MangaDoor', 'http://mangadoor.com', c); - AddWebsiteModule('MangaHispano', 'https://mangahis.com', c); c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); From 56854a4ea70fb27618353b047c0f6e14f1f0aa30 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 14 Jun 2018 17:27:19 +0300 Subject: [PATCH 2631/2794] UnionMangas, fix list update fixes #1287 --- lua/modules/UnionMangas.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lua/modules/UnionMangas.lua b/lua/modules/UnionMangas.lua index 9eb5ae266..4afdb2dcb 100644 --- a/lua/modules/UnionMangas.lua +++ b/lua/modules/UnionMangas.lua @@ -34,12 +34,10 @@ end function getnameandlink() local s = module.RootURL .. dirurl - if url ~= '0' then - s = s .. '/a-z/' + IncStr(url) + '/*' - end + s = s .. '/a-z/' .. IncStr(url) .. '/*' if http.get(s) then local x = TXQuery.Create(http.Document) - x.XPathHREFAll('//*[@class="row"]/div/a[2]', links, names) + x.XPathHREFAll('//div[contains(@class,"bloco-manga")]/a[2]', links, names) return no_error else return net_problem @@ -61,7 +59,7 @@ function Init() local m=NewModule() m.category='Portugues' m.website='UnionMangas' - m.rooturl='http://unionmangas.cc' + m.rooturl='http://unionmangas.site' m.lastupdated='April 6, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' From 5397f8be21a4e77a0573719f188a24642da91dc0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 14 Jun 2018 20:07:09 +0300 Subject: [PATCH 2632/2794] [wip] Tumangaonline, move to lua (no manga list yet) #1285 #1283 --- baseunits/ModuleList.inc | 1 - baseunits/modules/Tumangaonline.pas | 189 ---------------------------- lua/modules/TuMangaOnline.lua | 81 ++++++++++++ 3 files changed, 81 insertions(+), 190 deletions(-) delete mode 100644 baseunits/modules/Tumangaonline.pas create mode 100644 lua/modules/TuMangaOnline.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 0fa2dcbf9..a311c9519 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -19,7 +19,6 @@ uses AcademyVN, Webtoons, Tsumino, - Tumangaonline, MangaEden, HeyMangaXyz, WebtoonTr, diff --git a/baseunits/modules/Tumangaonline.pas b/baseunits/modules/Tumangaonline.pas deleted file mode 100644 index 9837be71a..000000000 --- a/baseunits/modules/Tumangaonline.pas +++ /dev/null @@ -1,189 +0,0 @@ -unit Tumangaonline; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, math, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; - -implementation - -const - apiurl = '/api/v1/'; - apiurlmangas = apiurl + 'mangas'; - apiurlimagenes = apiurl + 'imagenes'; - dirurl = apiurlmangas + '?searchBy=nombre&sortDir=asc&sortedBy=nombre&itemsPerPage='; - perpage = '1000'; - mangaurl = '/biblioteca/mangas/'; - imgurl = 'https://img1.tumangaonline.com'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - MangaInfo.FHTTP.Headers.Values['Referer'] := Module.RootURL; - MangaInfo.FHTTP.Headers.Values['Cache-Mode'] := 'no-cache'; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1&page=1') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := ceil(StrToIntDef(XPathString('json(*).total'), 1) / StrToInt(perpage)); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - MangaInfo.FHTTP.Headers.Values['Referer'] := Module.RootURL; - MangaInfo.FHTTP.Headers.Values['Cache-Mode'] := 'no-cache'; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + perpage + '&page=' + IncStr(AURL)) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('json(*).data()/string-join((id,"/",nombreUrl,codepoints-to-string(10),nombre),"")') do - begin - s := v.toString; - ALinks.Add(mangaurl + SeparateLeft(s, #10)); - ANames.Add(Trim(SeparateRight(s, #10))); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; -var - v, w: IXQValue; - s, mangaid, purl, num: String; - p, i: Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := FillHost(Module.RootURL, AURL); - mangaid := RegExprGetMatch('/\w+/(\d+)/\w+', url, 1); - if mangaid = '' then Exit; - Headers.Values['Referer'] := url; - Headers.Values['Cache-Mode'] := 'no-cache'; - if GET(Module.RootURL + apiurlmangas + '/' + mangaid) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('json(*).imageUrl'); - if coverLink <> '' then coverLink := MaybeFillHost(imgurl, coverLink); - if title = '' then title := XPathString('json(*).nombre'); - status := MangaInfoStatusIfPos(XPathString('json(*).estado'), 'Activo', 'Finalizado'); - summary := XPathString('json(*).info.sinopsis'); - genres := XPathStringAll('json(*).generos().genero'); - AddCommaString(genres, XPathStringAll('json(*).categorias().categoria')); - artists := XPathStringAll('json(*).artistas().artista'); - authors := XPathStringAll('json(*).autores().autor'); - purl := Module.RootURL + apiurlmangas + '/' + mangaid + '/capitulos?tomo=-1&page='; - Reset; - Headers.Values['Referer'] := url; - Headers.Values['Cache-Mode'] := 'no-cache'; - if GET(purl + '1') then - begin - ParseHTML(Document); - p := StrToIntDef(XPathString('json(*).last_page'), 1); - for i := 1 to p do - begin - if i > 1 then begin - Reset; - Headers.Values['Referer'] := url; - Headers.Values['Cache-Mode'] := 'no-cache'; - if GET(purl + IntToStr(i)) then - ParseHTML(Document) - else - Break; - end; - for v in XPath('json(*).data()') do - begin - mangaid := XPathString('tomo/idManga', v); - num := XPathString('numCapitulo', v); - s := v.getProperty('nombre').toString; - if s = 'null' then s := ''; - if s <> '' then s := ' ' + s; - s := v.getProperty('numCapitulo').toString + s; - for w in XPath('jn:members(subidas)', v) do begin - chapterLinks.Add(apiurlimagenes + '?idManga=' + mangaid + '&idScanlation=' + XPathString('./idScan', w) + '&numeroCapitulo=' + num + '&visto=true'); - chapterName.Add(s + ' [' + XPathString('./scanlation/nombre', w) + ']'); - end; - end; - end; - InvertStrings([chapterLinks, chapterName]); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do - begin - PageLinks.Clear; - PageNumber := 0; - Headers.Values['Referer'] := Module.RootURL; - Headers.Values['Cache-Mode'] := 'no-cache'; - if GET(FillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - s := imgurl + '/subidas/' + - XPathString('json(*)/string-join((capitulo/tomo/idManga,capitulo/numCapitulo,idScan),"/")') + '/'; - for v in XPath('json((json(*).imagenes))()') do - PageLinks.Add(s + v.toString); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do begin - Website := 'Tumangaonline'; - RootURL := 'https://www.tumangaonline.com'; - Category := 'Spanish'; - MaxTaskLimit := 1; - MaxConnectionLimit := 1; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/TuMangaOnline.lua b/lua/modules/TuMangaOnline.lua new file mode 100644 index 000000000..b797139be --- /dev/null +++ b/lua/modules/TuMangaOnline.lua @@ -0,0 +1,81 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = Trim(x.XPathString('//h1[contains(@class, "element-title")]/text()')) + end + mangainfo.coverlink = x.xpathstring('//img[contains(@class,"book-thumbnail")]/@src') + mangainfo.genres=x.xpathstringall('//a[contains(@class, "badge")]') + mangainfo.authors=Trim(x.xpathstring('//span[@class="list-group-item" and contains(., "Autor")]/a')) + mangainfo.artists=Trim(x.xpathstring('//span[@class="list-group-item" and contains(., "Artist")]/a')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//span[contains(@class, "book-status")]'), 'public', 'final') + mangainfo.summary = x.xpathstringall('//*[@class="element-description"]/text()', '') + local v = x.xpath('//div[contains(@class, "chapters")]/ul//li') + for i = 1, v.count do + local v1 = v.get(i) + local name = x.xpathstring('h4', v1) + local w = x.xpath('div//ul/li/div', v1) + for j = 1, w.count do + local w1 = w.get(j) + local scan = '[' .. x.xpathstring('div[1]//a', w1) .. ']' + mangainfo.chapterlinks.add(x.xpathstring('div[contains(@class, "text-right")]/a/@href', w1)) + mangainfo.chapternames.add(name .. ' ' .. scan) + end + end + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagecontainerlinks.clear() + http.headers.values['Referer'] = module.rooturl + if not http.get(MaybeFillHost(module.rooturl, url)) then return false; end + if http.lasturl:match('paginated$') ~= nil then + if not http.get(http.lasturl:gsub('paginated$', 'cascade')) then return false; end + end + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[contains(@class, "viewer-image")]/@data-original', task.pagelinks) + task.pagecontainerlinks.text = http.lasturl + return true +end + +--[[ +function getnameandlink() + if http.GET(module.RootURL .. '/changeMangaList?type=text') then + TXQuery.Create(http.Document).XPathHREFAll('//li/a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('//*[@class="pagination"]/a[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end +--]] + +function Init() + local m = NewModule() + m.website = 'Tumangaonline' + m.rooturl = 'https://tumangaonline.me' + m.category = 'Spanish' + m.lastupdated='June 14, 2018' + m.maxtasklimit = 1 + m.maxconnectionlimit = 1 + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + --m.ongetnameandlink='getnameandlink' + --m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end From d9196427165b23e5825be9b6e9bcc937bf5aebf9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 15 Jun 2018 15:10:51 +0300 Subject: [PATCH 2633/2794] add TruyenChon [vi] --- lua/modules/TruyenChon.lua | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 lua/modules/TruyenChon.lua diff --git a/lua/modules/TruyenChon.lua b/lua/modules/TruyenChon.lua new file mode 100644 index 000000000..c5cb99a46 --- /dev/null +++ b/lua/modules/TruyenChon.lua @@ -0,0 +1,68 @@ +local dirurl = '/the-loai?status=-1&sort=15&page=%s' + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//h1[@class="title-detail"]') + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//div[contains(@class, "col-image")]/img/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//li[contains(@class, "status")]/p[2]'), 'Đang tiến hành', 'Hoàn thành') + mangainfo.authors=x.xpathstring('//li[contains(@class, "author")]/p[2]') + mangainfo.artists=x.xpathstring('//h4[starts-with(./label,"Artista")]/substring-after(.,":")') + mangainfo.genres=x.xpathstringall('//li[contains(@class, "kind")]/p[2]/a') + mangainfo.summary=x.xpathstring('//div[@class="detail-content"]/p') + x.xpathhrefall('//div[@class="list-chapter"]//ul/li/div[contains(@class, "chapter")]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="page-chapter"]/img/@data-original', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.RootURL .. dirurl:format(IncStr(url))) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@class="item"]//h3/a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. dirurl:format('1')) then + local x = TXQuery.Create(http.Document) + local s = x.xpathstring('//ul[@class="pagination"]/li[last()]/a/@href') + page = tonumber(s:match('&page=(%d+)')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='Vietnamese' + m.website='TruyenChon' + m.rooturl='http://truyenchon.com/' + m.lastupdated='June 15, 2018' + m.sortedlist = true + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber='getdirectorypagenumber' +end From 87246569b16f91d0b8d3fdac103d351c35504ced Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 15 Jun 2018 15:18:50 +0300 Subject: [PATCH 2634/2794] add NetTruyen [vi] --- lua/modules/TruyenChon.lua | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/lua/modules/TruyenChon.lua b/lua/modules/TruyenChon.lua index c5cb99a46..c72536ab2 100644 --- a/lua/modules/TruyenChon.lua +++ b/lua/modules/TruyenChon.lua @@ -1,4 +1,7 @@ -local dirurl = '/the-loai?status=-1&sort=15&page=%s' +local dirurl = { + ['TruyenChon'] = '/the-loai?status=-1&sort=15&page=%s', + ['NetTruyen'] = '/tim-truyen?status=-1&sort=15&page=%s' +} function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) @@ -33,7 +36,7 @@ function getpagenumber() end function getnameandlink() - if http.get(module.RootURL .. dirurl:format(IncStr(url))) then + if http.get(module.RootURL .. dirurl[module.website]:format(IncStr(url))) then local x = TXQuery.Create(http.Document) x.XPathHREFAll('//div[@class="item"]//h3/a', links, names) return no_error @@ -43,7 +46,7 @@ function getnameandlink() end function getdirectorypagenumber() - if http.GET(module.RootURL .. dirurl:format('1')) then + if http.GET(module.RootURL .. dirurl[module.website]:format('1')) then local x = TXQuery.Create(http.Document) local s = x.xpathstring('//ul[@class="pagination"]/li[last()]/a/@href') page = tonumber(s:match('&page=(%d+)')) @@ -54,15 +57,21 @@ function getdirectorypagenumber() end end -function Init() +function AddWebsiteModule(name, url) local m=NewModule() m.category='Vietnamese' - m.website='TruyenChon' - m.rooturl='http://truyenchon.com/' + m.website=name + m.rooturl=url m.lastupdated='June 15, 2018' m.sortedlist = true m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.ongetdirectorypagenumber='getdirectorypagenumber' + return m +end + +function Init() + AddWebsiteModule('TruyenChon', 'http://truyenchon.com') + AddWebsiteModule('NetTruyen', 'http://www.nettruyen.com') end From 60317798658a6cdfb5ba1b22a58850d209db7d44 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 15 Jun 2018 16:21:05 +0300 Subject: [PATCH 2635/2794] don't show a confirmation dialog when fmd is restarted --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index 35f8e10fe..aa66fef65 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -1269,7 +1269,7 @@ procedure TMainForm.FormCreate(Sender: TObject); procedure TMainForm.FormClose(Sender: TObject; var CloseAction: TCloseAction); begin Logger.Send(Self.ClassName+'.FormClose'); - if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) then + if cbOptionShowQuitDialog.Checked and (DoAfterFMD = DO_NOTHING) and (not OptionRestartFMD) then begin if MessageDlg('', RS_DlgQuit, mtConfirmation, [mbYes, mbNo], 0) <> mrYes then begin From ef5deca668a2f1037e0a82b75fbaba3425fda09e Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 19 Jun 2018 18:01:41 +0300 Subject: [PATCH 2636/2794] MangaID, change domain --- lua/modules/myReaderMangaCMS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 759f874f9..28629c785 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -84,7 +84,7 @@ function Init() c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); AddWebsiteModule('MangaDesu','http://mangadesu.net', c); - AddWebsiteModule('MangaID', 'http://mangaid.co', c); + AddWebsiteModule('MangaID', 'http://mangaid.net', c); AddWebsiteModule('KomikGue', 'https://www.komikgue.com', c); c='Raw' From 5cd19c102921eab74b422cb5784277eeab0b318d Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 19 Jun 2018 18:49:06 +0300 Subject: [PATCH 2637/2794] TuMangaOnline, fix getinfo, add manga list fixes #1291 fixes #1285 fixes #1283 --- lua/modules/TuMangaOnline.lua | 41 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/lua/modules/TuMangaOnline.lua b/lua/modules/TuMangaOnline.lua index b797139be..65239f53d 100644 --- a/lua/modules/TuMangaOnline.lua +++ b/lua/modules/TuMangaOnline.lua @@ -18,11 +18,20 @@ function getinfo() local w = x.xpath('div//ul/li/div', v1) for j = 1, w.count do local w1 = w.get(j) - local scan = '[' .. x.xpathstring('div[1]//a', w1) .. ']' + local scan = '[' .. x.xpathstring('div[1]', w1) .. ']' mangainfo.chapterlinks.add(x.xpathstring('div[contains(@class, "text-right")]/a/@href', w1)) mangainfo.chapternames.add(name .. ' ' .. scan) end end + if mangainfo.chapterlinks.count == 0 then + local w = x.xpath('//ul[contains(@class, "chapter-list")]/li/div') + for j = 1, w.count do + local w1 = w.get(j) + local scan = '[' .. x.xpathstring('div[1]', w1) .. ']' + mangainfo.chapterlinks.add(x.xpathstring('div[contains(@class, "text-right")]/a/@href', w1)) + mangainfo.chapternames.add(mangainfo.title .. ' ' .. scan) + end + end InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error else @@ -44,27 +53,26 @@ function getpagenumber() return true end ---[[ function getnameandlink() - if http.GET(module.RootURL .. '/changeMangaList?type=text') then - TXQuery.Create(http.Document).XPathHREFAll('//li/a', links, names) - return no_error - else - return net_problem - end -end - -function getdirectorypagenumber() - if http.GET(module.RootURL) then + local s = '/library?order_item=alphabetically&order_dir=asc&filter_by=title&page='..IncStr(url) + if http.GET(module.RootURL .. s) then local x = TXQuery.Create(http.Document) - page = tonumber(x.xpathstring('//*[@class="pagination"]/a[last()-1]')) - if page == nil then page = 1 end + local v = x.xpath('//*[@data-identifier]/a') + local hasTitles = false + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getAttribute('href')) + names.add(x.xpathstring('div/div[@class="thumbnail-title"]', v1)) + hasTitles = true + end + if hasTitles then + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + end return no_error else return net_problem end end ---]] function Init() local m = NewModule() @@ -76,6 +84,5 @@ function Init() m.maxconnectionlimit = 1 m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' - --m.ongetnameandlink='getnameandlink' - --m.ongetdirectorypagenumber = 'getdirectorypagenumber' + m.ongetnameandlink='getnameandlink' end From d629bd204533cc321570e7cc585f677fac2393aa Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 20 Jun 2018 15:42:17 +0300 Subject: [PATCH 2638/2794] TruyenTranhTuan, fix page order fixes #1293 --- baseunits/ModuleList.inc | 1 - baseunits/modules/TruyenTranhTuan.pas | 110 -------------------------- lua/modules/TruyenTranhTuan.lua | 79 ++++++++++++++++++ 3 files changed, 79 insertions(+), 111 deletions(-) delete mode 100644 baseunits/modules/TruyenTranhTuan.pas create mode 100644 lua/modules/TruyenTranhTuan.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index a311c9519..e636f3ad5 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -43,7 +43,6 @@ uses EatManga, Taadd, NineManga, - TruyenTranhTuan, BlogTruyen, MangaAe, MangaTube, diff --git a/baseunits/modules/TruyenTranhTuan.pas b/baseunits/modules/TruyenTranhTuan.pas deleted file mode 100644 index 3a3232942..000000000 --- a/baseunits/modules/TruyenTranhTuan.pas +++ /dev/null @@ -1,110 +0,0 @@ -unit TruyenTranhTuan; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; - -implementation - -uses FMDVars; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - i, x: Integer; - s: String; -begin - Result := NET_PROBLEM; - s := Module.RootURL; - if AURL <> '0' then - s += '/page/' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - i := 1; - for v in XPath('//*[@id="page-nav"]//li') do begin - x := StrToIntDef(v.toString, 1); - if x > i then i := x; - end; - updateList.CurrentDirectoryPageNumber := i; - XPathHREFAll('//*[@id="story-list"]/div/span[1]/a', ALinks, ANames); - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do try - coverLink := XPathString('//*[@class="manga-cover"]/img/@src'); - if title = '' then title := XPathString('//h1[@itemprop="name"]'); - authors := XPathString('//p[@class="misc-infor" and starts-with(.,"Tác giả")]/string-join(./a,", ")'); - genres := XPathString('//p[@class="misc-infor" and starts-with(.,"Thể loại")]/string-join(./a,", ")'); - summary := XPathString('//*[@id="manga-summary"]/p'); - XPathHREFAll('//*[@id="manga-chapter"]//*[@class="chapter-name"]/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - s := XPathString('//script[contains(.,"var slides_page_path")]/substring-before(substring-after(substring-after(.,"var slides_page_path"),"["),"]")', Document); - if s = '' then - s := XPathString('//script[contains(.,"var slides_page_url_path")]/substring-before(substring-after(substring-after(.,"var slides_page_url_path"),"["),"]")', Document); - if s <> '' then begin - s := StringReplace(s, '"', '', [rfReplaceAll]); - PageLinks.CommaText := s; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'TruyenTranhTuan'; - RootURL := 'http://truyentranhtuan.com'; - Category := 'Vietnamese'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/TruyenTranhTuan.lua b/lua/modules/TruyenTranhTuan.lua new file mode 100644 index 000000000..6d8d08dc4 --- /dev/null +++ b/lua/modules/TruyenTranhTuan.lua @@ -0,0 +1,79 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//h1[@itemprop="name"]') + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//*[@class="manga-cover"]/img/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//li[contains(@class, "status")]/p[2]'), 'Đang tiến hành', 'Hoàn thành') + mangainfo.authors=x.xpathstringall('//p[@class="misc-infor" and starts-with(.,"Tác giả")]/a') + mangainfo.genres=x.xpathstringall('//p[@class="misc-infor" and starts-with(.,"Thể loại")]/a') + mangainfo.summary=x.xpathstring('//*[@id="manga-summary"]/p') + x.xpathhrefall('//*[@id="manga-chapter"]//*[@class="chapter-name"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x = TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(.,"var slides_page")]') + x.parsehtml(GetBetween('slides_page_path = ', ';', s)) + local v = x.xpath('json(*)()') + if v.count > 0 then + local tmp = {} + for i = 1, v.count do + table.insert(tmp, v.get(i).toString) + end + table.sort(tmp) + for i, link in ipairs(tmp) do + task.pagelinks.add(link) + end + else + x.parsehtml(GetBetween('slides_page_url_path = ', ';', s)) + local v = x.xpathstringall('json(*)()', task.pagelinks) + end + else + return false + end + return true +end + +function getnameandlink() + local s = module.RootURL + if url ~= '0' then + s = s .. '/page/' .. IncStr(url) + end + if http.get(s) then + local x = TXQuery.Create(http.Document) + local p = 1 + local v = x.xpath('//*[@id="page-nav"]//li') + for i = 1, v.count do + print(v.get(i).toString) + local tmp = tonumber(v.get(i).toString) + if tmp == nil then tmp = 1; end + if tmp > p then p = tmp; end + end + updatelist.CurrentDirectoryPageNumber = p + x.XPathHREFAll('//*[@id="story-list"]/div/span[1]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='Vietnamese' + m.website='TruyenTranhTuan' + m.rooturl='http://truyentranhtuan.com' + m.lastupdated='June 20, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 872637640c371e0021af5d6912730eca677b4db4 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 20 Jun 2018 16:04:12 +0300 Subject: [PATCH 2639/2794] Lhscans, temp fix (SplitURL bug) fixes #1294 --- lua/modules/Lhscans.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua index 786aea751..6192c3fce 100644 --- a/lua/modules/Lhscans.lua +++ b/lua/modules/Lhscans.lua @@ -17,6 +17,9 @@ if mangainfo.chapterlinks.count == 0 then x.xpathhrefall('//div[@id="list-chapters"]//a[@class="chapter"]', mangainfo.chapterlinks, mangainfo.chapternames) end + for i = 0, mangainfo.chapterlinks.count-1 do + mangainfo.chapterlinks[i] = string.gsub(mangainfo.chapterlinks[i], '%.', '%%2E') + end InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error else From 945431b727c69304e9d6b07dc035689179fa2b19 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 20 Jun 2018 16:20:08 +0300 Subject: [PATCH 2640/2794] lhscans, fix chapter urls --- lua/modules/Lhscans.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua index 6192c3fce..ae7784f2c 100644 --- a/lua/modules/Lhscans.lua +++ b/lua/modules/Lhscans.lua @@ -18,7 +18,7 @@ x.xpathhrefall('//div[@id="list-chapters"]//a[@class="chapter"]', mangainfo.chapterlinks, mangainfo.chapternames) end for i = 0, mangainfo.chapterlinks.count-1 do - mangainfo.chapterlinks[i] = string.gsub(mangainfo.chapterlinks[i], '%.', '%%2E') + mangainfo.chapterlinks[i] = module.RootURL .. '/' .. mangainfo.chapterlinks[i] end InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error From 7a8cafa089e721ae724c07687c96b6e88fa6dfa8 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 21 Jun 2018 07:25:51 +0300 Subject: [PATCH 2641/2794] TuMangaOnline, fix download --- lua/modules/TuMangaOnline.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/TuMangaOnline.lua b/lua/modules/TuMangaOnline.lua index 65239f53d..333e056df 100644 --- a/lua/modules/TuMangaOnline.lua +++ b/lua/modules/TuMangaOnline.lua @@ -48,7 +48,7 @@ function getpagenumber() if not http.get(http.lasturl:gsub('paginated$', 'cascade')) then return false; end end local x=TXQuery.Create(http.Document) - x.xpathstringall('//img[contains(@class, "viewer-image")]/@data-original', task.pagelinks) + x.xpathstringall('//img[contains(@class, "viewer-image")]/@src', task.pagelinks) task.pagecontainerlinks.text = http.lasturl return true end From 90d4da390989eb5a33f02496cbc4b6ed5c020b6a Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 21 Jun 2018 07:26:36 +0300 Subject: [PATCH 2642/2794] remove print call --- lua/modules/TruyenTranhTuan.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/TruyenTranhTuan.lua b/lua/modules/TruyenTranhTuan.lua index 6d8d08dc4..6ca7370b0 100644 --- a/lua/modules/TruyenTranhTuan.lua +++ b/lua/modules/TruyenTranhTuan.lua @@ -54,7 +54,6 @@ function getnameandlink() local p = 1 local v = x.xpath('//*[@id="page-nav"]//li') for i = 1, v.count do - print(v.get(i).toString) local tmp = tonumber(v.get(i).toString) if tmp == nil then tmp = 1; end if tmp > p then p = tmp; end From 57f0d958cfe9f3a23f47798d2eb62fc5ce5a5d6d Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 21 Jun 2018 07:31:56 +0300 Subject: [PATCH 2643/2794] DigitalTeamAltervista, rewrite fixes #1297 --- lua/modules/DigitalTeamAltervista.lua | 77 +++++++++++++++++++++++++++ lua/modules/myReaderMangaCMS.lua | 3 -- 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 lua/modules/DigitalTeamAltervista.lua diff --git a/lua/modules/DigitalTeamAltervista.lua b/lua/modules/DigitalTeamAltervista.lua new file mode 100644 index 000000000..c20398ba7 --- /dev/null +++ b/lua/modules/DigitalTeamAltervista.lua @@ -0,0 +1,77 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//div[contains(@class, "nomob")]') + end + mangainfo.coverlink = MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="cover"]/img/@src')) + mangainfo.genres=x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Genere")]/span[@class="info_content"]') + mangainfo.authors=x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Autore")]/span[@class="info_content"]') + mangainfo.artists=x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Artista")]/span[@class="info_content"]') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Status")]/span[@class="info_content"]'), 'In corso', 'Completo') + mangainfo.summary = x.xpathstringall('//div[@class="plot"]/text()', '') + x.xpathhrefall('//div[@class="chapter_list"]/ul/li/div[@class="ch_top"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function urlencode(str) + if (str) then + str = string.gsub (str, "\n", "\r\n") + str = string.gsub (str, "([^%w ])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub (str, " ", "+") + end + return str +end + +function getpagenumber() + task.pagelinks.clear() + task.pagecontainerlinks.clear() + if not http.get(MaybeFillHost(module.rooturl, url)) then return false; end + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "a_url")]') + local a_url = '/reader' + local m = GetBetween("m='", "'", s) + local ch = GetBetween("ch='", "'", s) + local chs = GetBetween("chs='", "'", s) + local title = urlencode(x.xpathstring('//title')) + local data = string.format("info%%5Bmanga%%5D=%s&info%%5Bchapter%%5D=%s&info%%5Bch_sub%%5D=%s&info%%5Btitle%%5D=%s", m, ch, chs, title) + http.reset() + if not http.post(module.rooturl .. a_url .. '/c_i', data) then return false; end + s = StreamToString(http.Document):gsub('\\"', '"'):gsub('^"', ''):gsub('"$', '') + x.parsehtml(s) + s = x.xpathstring('json(*)()[3]') + local cnt = x.xpathcount('json(*)()[1]()') + for i = 1, cnt do + local name = x.xpathstring('json(*)()[1]()['..i..']/name') .. x.xpathstring('json(*)()[2]()['..i..']') + local ex = x.xpathstring('json(*)()[1]()['..i..']/ex') + task.pagelinks.add(module.rooturl .. a_url .. s .. name .. ex) + end + return true +end + +function getnameandlink() + if http.GET(module.RootURL .. '/reader/series') then + local x = TXQuery.Create(http.Document) + x.xpathhrefall('//div[@class="manga_title"]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'DigitalTeamAltervista' + m.rooturl = 'http://digitalteam1.altervista.org' + m.category = 'Italian-Scanlation' + m.lastupdated='June 21, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 28629c785..6e6091454 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -108,7 +108,4 @@ function Init() AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com', c); AddWebsiteModule('SOSScanlation', 'http://sosscanlation.com', c); - - c='Italian-Scanlation' - AddWebsiteModule('DigitalTeamAltervista', 'http://digitalteam1.altervista.org', c) end From cdb77fd39f0e397142f43939dce1c7dbf76102f8 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 22 Jun 2018 18:06:47 +0300 Subject: [PATCH 2644/2794] epub, set image style fixes #1255 fixes #1231 --- baseunits/uEpub.pas | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/baseunits/uEpub.pas b/baseunits/uEpub.pas index 2a7ed8267..ddc9376c3 100644 --- a/baseunits/uEpub.pas +++ b/baseunits/uEpub.pas @@ -135,7 +135,9 @@ implementation '' + LineEnding; STYLE: String = - 'body {' + LineEnding + + 'img {' + LineEnding + + ' max-width: 100%;' + LineEnding + + ' max-height: 100%;' + LineEnding + '}' + LineEnding; function NewUUID: String; From e3ace90e556ef4ee53bafa6be8564934c24f2c24 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 24 Jun 2018 07:23:58 +0300 Subject: [PATCH 2645/2794] add Mexat [ar-sc] fixes #1296 --- lua/modules/Mexat.lua | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lua/modules/Mexat.lua diff --git a/lua/modules/Mexat.lua b/lua/modules/Mexat.lua new file mode 100644 index 000000000..3cac90655 --- /dev/null +++ b/lua/modules/Mexat.lua @@ -0,0 +1,60 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//h1[@class="page-title"]') + end + mangainfo.summary = x.xpathstring('//div[@class="archive-meta"]') + x.xpathhrefall('//div[@class="entry"]/table//tr/td[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagecontainerlinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//select[@id="manga_pid"]/option/@value', task.pagecontainerlinks) + task.pagenumber = task.pagecontainerlinks.count + else + return false + end + return true +end + +function getimageurl() + if http.GET(AppendURLDelim(MaybeFillHost(module.RootURL, url)) .. '?pid=' .. task.pagecontainerlinks[workid]) then + local x = TXQuery.Create(http.Document) + task.PageLinks[workid] = x.xpathstring('//div[@class="pic"]/a/img/@src') + return true + else + return false + end +end + +function getnameandlink() + if http.GET(module.RootURL .. '/%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D8%A7%D9%84%D9%85%D8%A7%D9%86%D8%AC%D8%A7/') then + TXQuery.Create(http.Document).XPathHREFAll('//ul[@class="MangaList"]/li//div[@class="SeriesName"]/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'Mexat' + m.rooturl = 'http://manga.mexat.com' + m.category = 'Arabic-Scanlation' + m.lastupdated='June 23, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.OnGetImageURL = 'getimageurl' +end From 30b3021757661c99262e266489bbb20955c20ed6 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 28 Jun 2018 20:54:21 +0300 Subject: [PATCH 2646/2794] LuaDownloadTask, add manga link --- baseunits/lua/LuaDownloadTask.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/baseunits/lua/LuaDownloadTask.pas b/baseunits/lua/LuaDownloadTask.pas index 60dbf9f8f..85e1ab8d1 100644 --- a/baseunits/lua/LuaDownloadTask.pas +++ b/baseunits/lua/LuaDownloadTask.pas @@ -23,6 +23,7 @@ procedure luaDownloadTaskMetaTable(L: Plua_State; Obj: Pointer; luaClassAddObject(L, MetaTable, PageLinks, 'PageLinks'); luaClassAddObject(L, MetaTable, PageContainerLinks, 'PageContainerLinks'); luaClassAddIntegerProperty(L, MetaTable, 'PageNumber', @PageNumber); + luaClassAddStringProperty(L, MetaTable, 'Link', @DownloadInfo.Link); end; end; From 09f205b73c1dd029b40afa079d0e9a776a3110ea Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 29 Jun 2018 09:46:50 +0300 Subject: [PATCH 2647/2794] httpsendthread, remove dup BeforeHTTPMethod --- baseunits/httpsendthread.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseunits/httpsendthread.pas b/baseunits/httpsendthread.pas index 289fef6ab..377cbfc6e 100644 --- a/baseunits/httpsendthread.pas +++ b/baseunits/httpsendthread.pas @@ -470,8 +470,8 @@ function THTTPSendThread.HTTPMethod(const Method, URL: string): Boolean; FCookiesExpires := 0.0; Result := inherited HTTPMethod(amethod, aurl); ParseCookiesExpires; - if Assigned(BeforeHTTPMethod) then - BeforeHTTPMethod(Self, amethod, aurl); + if Assigned(AfterHTTPMethod) then + AfterHTTPMethod(Self, amethod, aurl); end; function THTTPSendThread.HTTPRequest(const Method, URL: String; const Response: TObject): Boolean; From 5b13310eab7ba95de7673d580a33e5cd84c58af2 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 2 Jul 2018 14:43:36 +0300 Subject: [PATCH 2648/2794] Mangavy, fix all fixes #1314 --- lua/modules/MangaShiro.lua | 1 - lua/modules/rawdevart.lua | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index ee90b965c..65cccdea3 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -84,7 +84,6 @@ function Init() AddWebsiteModule('MangaShiro', 'http://mangashiro.net') AddWebsiteModule('Subapics', 'http://subapics.com') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') - AddWebsiteModule('Mangavy', 'https://mangavy.com') AddWebsiteModule('KomikStation', 'http://www.komikstation.com') AddWebsiteModule('MangaKid', 'http://mangakid.net') AddWebsiteModule('KomikCast', 'https://komikcast.com') diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 47ca0a28a..e925b25fa 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -31,7 +31,7 @@ function getpagenumber() end if http.get(aurl) then x=TXQuery.Create(http.Document) - v=x.xpathstringall('//div[@class="page-break"]/img/@src', task.pagelinks) + v=x.xpathstringall('//div[contains(@class, "page-break")]/img/@src', task.pagelinks) else return false end @@ -74,4 +74,7 @@ function Init() cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) AddWebsiteModule('ZeroScans', 'https://zeroscans.com', cat) + + cat = 'Indonesian' + AddWebsiteModule('Mangavy', 'https://mangavy.com', cat) end From 562a164a7c0bf08344d412f41149676039b79db7 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 2 Jul 2018 14:51:15 +0300 Subject: [PATCH 2649/2794] MyReadingManga, ignore next links fixes #1313 --- lua/modules/MyReadingManga.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/modules/MyReadingManga.lua b/lua/modules/MyReadingManga.lua index b93776ba8..70c9d7d50 100644 --- a/lua/modules/MyReadingManga.lua +++ b/lua/modules/MyReadingManga.lua @@ -19,8 +19,10 @@ function getinfo() local v = x.xpath('//*[contains(@class,"entry-pagination")]/a') for i = 1, v.count do local v1 = v.get(i) - mangainfo.chapterlinks.add(v1.getAttribute('href')); - mangainfo.chapternames.add(mangainfo.title .. ' - ' .. v1.toString); + if string.match(v1.toString, '^Next') == nil then + mangainfo.chapterlinks.add(v1.getAttribute('href')); + mangainfo.chapternames.add(mangainfo.title .. ' - ' .. v1.toString); + end end if mangainfo.chapternames.count > 1 then mangainfo.chapternames[0] = mangainfo.chapternames[0] .. ' - 1' From ba038752afd3daaad6801d55037731547e6a1a5a Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 2 Jul 2018 15:05:53 +0300 Subject: [PATCH 2650/2794] add HamTruyen [vi] fixes #1279 --- lua/modules/HamTruyen.lua | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 lua/modules/HamTruyen.lua diff --git a/lua/modules/HamTruyen.lua b/lua/modules/HamTruyen.lua new file mode 100644 index 000000000..a0e92e9c6 --- /dev/null +++ b/lua/modules/HamTruyen.lua @@ -0,0 +1,59 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//h1[@class="tentruyen"]') + end + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//div[contains(@class, "wrapper_image")]/img/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(@class, "wrapper_info")]/p[contains(., "Trạng thái")]'), 'Đang tiến hành', 'Hoàn thành') + mangainfo.authors=x.xpathstring('//div[contains(@class, "wrapper_info")]/p[contains(., "Tác giả")]/substring-after(.,":")') + mangainfo.genres=x.xpathstringall('//div[contains(@class, "wrapper_info")]/p[contains(., "Thể loại")]/a') + mangainfo.summary=x.xpathstring('//p[@id="tomtattruyen"]') + x.xpathhrefall('//div[@id="wrapper_listchap"]//section/div/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@id="content_chap"]/img/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + local s = module.RootURL .. string.format('/danhsach/P%s/index.html?sort=1', IncStr(url)) + if http.get(s) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//a[h5[@class="tentruyen_slide"]]', links, names) + local maxp = -1 + local v = x.xpath('//ul[@class="pagination"]/li/a/@href') + for i = 1, v.count do + local p = tonumber(string.match(v.get(i).toString, '/P(%d+)/')) + if (p ~= nil) and (p > maxp) then maxp = p; end + end + if maxp > 0 then updatelist.CurrentDirectoryPageNumber = maxp; end + return no_error + else + return net_problem + end +end + +function Init() + local m=NewModule() + m.category='Vietnamese' + m.website='HamTruyen' + m.rooturl='https://hamtruyen.com' + m.lastupdated='June 15, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From 9e5128050d6dae5375742684f2b823507f964c02 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 2 Jul 2018 20:47:48 +0300 Subject: [PATCH 2651/2794] Bump version 0.9.156.0 --- README.md | 2 +- changelog.txt | 31 +++++++++++++++++++++++++++++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 95272f9c5..c4d3f9aa5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Download the latest release -[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.155.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0_Win64.7z) +[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.156.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.156.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0_Win64.7z) ## Content diff --git a/changelog.txt b/changelog.txt index 700d83dff..5c1d615c8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,37 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.156.0 (02-07-2018) +[+] Added DoujinsCom [H-Sites] +[+] Added PlusComico [RAW] +[+] Added ZingBox [EN] +[+] Added MangaRoom [EN] +[+] Added RawNeko [RAW] +[+] Added MangaHispano [SP] +[+] Added WestManga [ID] +[+] Added DM5 [RAW] +[+] Added TranslateWebtoon +[+] Added RawQV [RAW] +[+] Added AsmHentai [H-Sites] +[+] Added KomikGue [ID] +[+] Added Toonkor [RAW] +[+] Added 3asq [AR-SC] +[+] Added TruyenChon [VI] +[+] Added NetTruyen [VI] +[+] Added Mexat [AR-SC] +[-] Removed Bamtoki +[*] Tumangaonline, fixed all +[*] Mangavy, fixed all +[*] MyReadingManga, fixed manga info +[*] Lhscans, fixed manga info +[*] TruyenTranhTuan, fixed page order +[*] MangaID, fixed domain name +[*] UnionMangas, fixed list update +[*] HatigarmScans, fixed domain name +[*] HeavenManga, fixed domain name +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.155.0...0.9.156.0 + 0.9.155.0 (14-05-2018) [+] Added ePub support [+] Added Bamtoki [RAW] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index e0f87b1bd..5ba55347b 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ - + diff --git a/update b/update index 09db9dcf2..c3cde3a5b 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.155.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.155.0/fmd_0.9.155.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.155.0/fmd_0.9.155.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.155.0/fmd_0.9.155.0_Win64.7z +VERSION=0.9.156.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.156.0/fmd_0.9.156.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.156.0/fmd_0.9.156.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0_Win64.7z From 7ddc2bd9efc48edd9d9919084b0d0f652768a70d Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 2 Jul 2018 21:17:19 +0300 Subject: [PATCH 2652/2794] add HoduComics [raw] fixes #1303 --- lua/modules/HoduComics.lua | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 lua/modules/HoduComics.lua diff --git a/lua/modules/HoduComics.lua b/lua/modules/HoduComics.lua new file mode 100644 index 000000000..0700fd75e --- /dev/null +++ b/lua/modules/HoduComics.lua @@ -0,0 +1,80 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//p[@class="title"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="episode_bnr"]/img/@src')) + mangainfo.genres=x.xpathstringall('//p[@class="category"]/span'):gsub('#', '') + mangainfo.summary=x.xpathstring('//p[@class="synop"]') + local v = x.xpath('//table[@class="episode_list"]//tr[contains(@class, "episode_tr") and contains(@class, "not_need_pay")]') + for i = 1, v.count do + local v1 = v.get(i) + local s = MaybeFillHost(module.RootURL, GetBetween('=\'', '\'', v1.getAttribute('onclick'))) + mangainfo.chapterlinks.add(s) + s = x.xpathstring('td[@class="toon_title"]/div[@class="episode_subtitle"]', v1) + mangainfo.chapternames.add(s) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + http.headers.values['Referer'] = module.rooturl .. task.link + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "toon_img")]') + x.parsehtml(DecodeBase64(GetBetween("toon_img = \"", "\";", s))) + local v = x.xpath('//img/@src') + for i = 1, v.count do + task.pagelinks.add(MaybeFillHost(module.RootURL, v.get(i).toString)) + end + task.pagecontainerlinks.values[0] = http.cookies.text + else + return false + end + return true +end + +local dirurls = { + '/manga', '/complete' +} + +function getnameandlink() + local lurl = dirurls[module.CurrentDirectoryIndex+1] + if http.get(module.rooturl .. lurl) then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//ul[@id="comic_item_list"]/li/a') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getAttribute('href')) + names.add(x.xpathstring('div/div/span[@class="title"]', v1)) + end + return no_error + else + return net_problem + end +end + +function beforedownloadimage() + http.reset() + http.cookies.text = task.pagecontainerlinks.values[0] + http.headers.values['Referer'] = module.rooturl + return true +end + +function Init() + local m = NewModule() + m.category = 'Raw' + m.Website = 'HoduComics' + m.RootURL = 'https://hoducomics.com' + m.lastupdated='June 24, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.onbeforedownloadimage='beforedownloadimage' + m.totaldirectory = #dirurls +end From 8af971a6a87d91b1616d5d9f1dc64bb20b6977a5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 2 Jul 2018 21:22:51 +0300 Subject: [PATCH 2653/2794] MangaShiro, fix list update fixes #1315 --- lua/modules/MangaShiro.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 65cccdea3..32b01a136 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -57,7 +57,7 @@ function getnameandlink() if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) - elseif module.website == 'WestManga' then + elseif module.website == 'WestManga' or module.website == 'MangaShiro' then TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) else TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) From 58b628ee6df2f418ee7dc9cad732166e75273bd6 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 17 Jul 2018 07:51:48 +0300 Subject: [PATCH 2654/2794] Lhscans, change domain fixes #1329 fixes #1336 --- lua/modules/Lhscans.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua index ae7784f2c..af987acba 100644 --- a/lua/modules/Lhscans.lua +++ b/lua/modules/Lhscans.lua @@ -68,7 +68,7 @@ end function Init() local cat = 'Raw' - AddWebsiteModule('Lhscans', 'http://rawlh.com', cat) + AddWebsiteModule('Lhscans', 'http://lhscan.net', cat) AddWebsiteModule('RawQQ', 'https://rawqq.com', cat) AddWebsiteModule('RawQV', 'http://rawqv.com', cat) end From 5065c9ecbb00d3c7cb3bf54eafa671322b6c7e05 Mon Sep 17 00:00:00 2001 From: rs3mk Date: Sun, 5 Aug 2018 02:23:19 -0500 Subject: [PATCH 2655/2794] add PCNet --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index fd1e7f7b0..7175546e7 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -292,6 +292,7 @@ function Init() AddWebsiteModule('XAnimeSeduccion', 'http://xanime-seduccion.com', cat) AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) + AddWebsiteModule('PCNet', 'http://pcnet.patyscans.com', cat) AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) AddWebsiteModule('Nightow', 'http://nightow.net', cat) AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) From 60dee8c7bcb8e9f6518196b872f47fb90a68e35d Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 8 Aug 2018 15:48:29 +0300 Subject: [PATCH 2656/2794] mangadex, fix all --- lua/modules/MangaDex.lua | 54 ++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index b97759017..3c3f1fbc5 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -4,24 +4,24 @@ function getinfo() if http.get(mangainfo.url) then x=TXQuery.Create(http.document) if mangainfo.title=='' then mangainfo.title=x.xpathstring('//meta[@property="og:title"]/replace(@content,"\\s\\(\\w+\\)\\s-\\sMangaDex$","")') end - mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//img[@title="Manga image"]/@src')) - mangainfo.authors=x.xpathstring('//tr[./th="Author:"]/string-join(./td,", ")') - mangainfo.artists=x.xpathstring('//tr[./th="Artist:"]/string-join(./td,", ")') - mangainfo.genres = x.xpathstringall('//tr[./th="Genres:"]/td/span/a') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//tr[contains(./th,"status")]')) - mangainfo.summary=x.xpathstring('//tr[./th="Description:"]/td') - local l='//table//tr[@id and not(starts-with(./td/time, "in "))]' + mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[contains(@class, "card-body")]//img[@class]/@src')) + mangainfo.authors=x.xpathstring('//div[./text()="Author:"]/string-join(./following-sibling::div,", ")') + mangainfo.artists=x.xpathstring('//div[./text()="Artist:"]/string-join(./following-sibling::div,", ")') + mangainfo.genres = x.xpathstringall('//div[./text()="Genres:"]/following-sibling::div//a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[contains(./text(),"status")]/following-sibling::div')) + mangainfo.summary=x.xpathstring('//div[./text()="Description:"]/following-sibling::div') + local l='//div[contains(@class, "chapter-container")]//div[@data-id and not(starts-with(./div[contains(@class, "text-warning")], "in "))]' local n='' if module.getoption('luashowalllang') then - n='/concat(.," [",../td[4]/img/@title,"]"' + n='/concat(.," [",../div[6]/img/@title,"]"' else - l=l..'[./td/img[@title="English"]]' + l=l..'[./div/img[@title="English"]]' end if module.getoption('luashowscangroup') then if n=='' then n='/concat(.' end - n=n..'," [",../td[5],"]"' + n=n..'," [",../div[7],"]"' end - l=l..'/td[2]' + l=l..'/div[2]' if n~='' then n=n..')' end n=l..n l=l..'/a/@href' @@ -30,7 +30,7 @@ function getinfo() x.xpathstringall(l,mangainfo.chapterlinks) x.xpathstringall(n,mangainfo.chapternames) if http.terminated then break end - nurl=x.xpathstring('//ul[@class="pagination"]/li[@class="active"]/following-sibling::li[@class="paging"]/a/@href') + nurl=x.xpathstring('//ul[contains(@class,"pagination")]/li[contains(@class,"active")]/following-sibling::li[@class="page-item"]/a/@href') if nurl=='' then break end if http.get(MaybeFillHost(module.rooturl,nurl)) then x.parsehtml(http.document) @@ -47,14 +47,16 @@ end function getpagenumber() http.cookies.values['mangadex_h_toggle'] = '1' - if http.get(MaybeFillHost(module.rooturl,url)) then - local s=StreamToString(http.document) - if Pos('var page_array', s) == 0 then return false; end - local lurl=MaybeFillHost(module.rooturl,AppendURLDelim(GetBetween('var server = \'','\';',s))..GetBetween('var dataurl = \'','\';',s)..'/') - task.pagelinks.commatext=GetBetween('var page_array = [','];',s):gsub('\'','') - task.pagelinks.text=Trim(task.pagelinks.text) - for i=0,task.pagelinks.count-1 do - task.pagelinks[i]=lurl..task.pagelinks[i] + local chapterid = url:match('chapter/(%d+)') + if http.get(MaybeFillHost(module.rooturl,'/api/chapter/'..chapterid)) then + local x=TXQuery.Create(http.Document) + local hash = x.xpathstring('json(*).hash') + local srv = x.xpathstring('json(*).server') + local v = x.xpath('json(*).page_array()') + for i = 1, v.count do + local v1 = v.get(i) + local s = MaybeFillHost(module.rooturl, srv .. '/' .. hash .. '/' .. v1.toString) + task.pagelinks.add(s) end return true else @@ -63,13 +65,6 @@ function getpagenumber() return true end -function taskstart() - for i=0, task.pagelinks.count-1 do - task.pagelinks[i]=MaybeFillHost(module.rooturl,task.pagelinks[i]) - end - return true -end - local dirurl='/titles/2' function getdirectorypagenumber() @@ -77,7 +72,7 @@ function getdirectorypagenumber() http.cookies.values['mangadex_title_mode'] = '2' if http.GET(module.RootURL .. dirurl) then local x = TXQuery.Create(http.Document) - page = tonumber(x.xpathstring('(//ul[@class="pagination"]/li/a)[last()]/@href'):match('/2/(%d+)')) + page = tonumber(x.xpathstring('(//ul[contains(@class,"pagination")]/li/a)[last()]/@href'):match('/2/(%d+)')) if page == nil then page = 1 end return no_error else @@ -90,7 +85,7 @@ function getnameandlink() http.cookies.values['mangadex_title_mode'] = '2' if http.GET(module.rooturl .. dirurl .. '/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.document) - x.xpathhrefall('//*[@id="content"]//tr/td[2]/a',links,names) + x.xpathhrefall('//a[contains(@class, "manga_title")]',links,names) return no_error else return net_problem @@ -104,7 +99,6 @@ function Init() m.rooturl='https://mangadex.org' m.lastupdated='February 28, 2018' m.ongetinfo='getinfo' - m.ontaskstart='taskstart' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.ongetdirectorypagenumber = 'getdirectorypagenumber' From 8142f0b6c769c907d11aeef78913d7f5577dec71 Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Aug 2018 21:03:06 +0800 Subject: [PATCH 2657/2794] luawebsitemodules, also scan for luac file closed #1203 --- baseunits/lua/LuaWebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index acc493e3f..273b45d05 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -532,7 +532,7 @@ procedure ScanLuaWebsiteModulesFile; begin d := LUA_WEBSITEMODULE_FOLDER; try - f := FindAllFiles(d, '*.lua', False, faAnyFile); + f := FindAllFiles(d, '*.lua;*.luac', False, faAnyFile); if f.Count > 0 then for i := 0 to f.Count - 1 do LoadLuaToWebsiteModules(f[i]); From 3d9646729649253bc6389d4ac54731977839909c Mon Sep 17 00:00:00 2001 From: riderkick Date: Mon, 20 Aug 2018 22:46:29 +0800 Subject: [PATCH 2658/2794] dbupdater, hide extract window closed #1377 --- baseunits/DBUpdater.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/DBUpdater.pas b/baseunits/DBUpdater.pas index 3176f2add..80f90fd15 100644 --- a/baseunits/DBUpdater.pas +++ b/baseunits/DBUpdater.pas @@ -316,7 +316,7 @@ procedure TDBUpdaterThread.Execute; Parameters.Add('-o' + AnsiQuotedStr(DATA_FOLDER, '"')); // destination Parameters.Add('-aoa'); // overwrite all Options := Options + [poWaitOnExit]; - ShowWindow := swoNone; + ShowWindow := swoHIDE; Execute; cont := ExitStatus = 0; if cont then From 2825316123101990c86c3dd4d822f54e9a6db6c1 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 4 Sep 2018 15:50:48 +0300 Subject: [PATCH 2659/2794] InManga, fix download fixes #1458 --- lua/modules/InManga.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/InManga.lua b/lua/modules/InManga.lua index 74f22fd84..fbe72a78d 100644 --- a/lua/modules/InManga.lua +++ b/lua/modules/InManga.lua @@ -3,7 +3,7 @@ function getinfo() if http.get(mangainfo.url) then local x=TXQuery.Create(http.document) mangainfo.title=x.xpathstring('//h1') - mangainfo.coverlink=x.xpathstring('//meta[@property="og:image"]/@content') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//meta[@property="og:image"]/@content')) mangainfo.summary=x.xpathstring('//div/div[h1]/following-sibling::div[@class="panel-body"]') local id = x.xpathstring('//input[@id="Identification"]/@value') local base = x.xpathstring('//script[contains(., "var chapterUrl")]') @@ -20,7 +20,7 @@ function getinfo() for _, k in ipairs(t) do local chid = x.xpathstring('jn:members(result)[Number='..k..']/Identification', root) local chnum = x.xpathstring('jn:members(result)[Number='..k..']/FriendlyChapterNumber', root) - mangainfo.chapterlinks.add(module.rooturl .. base:gsub('chapterNumber', chnum):gsub('identification', chid)) + mangainfo.chapterlinks.add(module.rooturl .. '/chapter/chapterIndexControls?identification=' .. chid) mangainfo.chapternames.add('Capítulo: ' .. chnum) end end From 8bfdd9c017ef892a5fe0391172a13850d4b7beb8 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 4 Sep 2018 16:05:46 +0300 Subject: [PATCH 2660/2794] ZingBox, remove closes #1434 --- lua/modules/ZingBox.lua | 89 ----------------------------------------- 1 file changed, 89 deletions(-) delete mode 100644 lua/modules/ZingBox.lua diff --git a/lua/modules/ZingBox.lua b/lua/modules/ZingBox.lua deleted file mode 100644 index 51c5eee4e..000000000 --- a/lua/modules/ZingBox.lua +++ /dev/null @@ -1,89 +0,0 @@ -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - local id = RegExprGetMatch('(manga|comicDetail)\\/(.+?)\\/', url, 2) - local data = string.format('url=/manga/getBookDetail/%s&method=GET', id) - if url:match('comicDetail') == nil then - data = data .. '&api=/mangaheatapi/web' - end - if http.post(module.rooturl .. '/api', data) then - local x=TXQuery.Create(http.document) - local json = x.xpath('json(*)') - if mangainfo.title == '' then - mangainfo.title=x.xpathstring('./title',json) - end - mangainfo.coverlink=x.xpathstring('./cover',json) - mangainfo.authors=x.xpathstring('./author',json) - mangainfo.genres=x.xpathstring('./tags',json) - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('./updateStatus',json)) - mangainfo.summary=x.xpathstring('./summary',json) - local v = x.xpath('jn:members(child)', json) - for i = 1, v.count do - local v1 = v.get(i) - mangainfo.chapterlinks.add(x.xpathstring('./chapterId', v1)) - mangainfo.chapternames.add(x.xpathstring('./title', v1) .. ' - ' .. x.xpathstring('./summary', v1)) - end - InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) - return no_error - else - return net_problem - end -end - -function getpagenumber() - task.pagelinks.clear() - task.pagenumber = 0 - url = url:gsub('/', '') - local data = string.format('url=/manga/getChapterImages/%s&method=GET', url) - if tonumber(url) ~= nil then - data = data .. '&api=/mangaheatapi/web' - end - if http.post(module.rooturl .. '/api', data) then - local x=TXQuery.Create(http.Document) - x.xpathstringall('json(*).images()', task.pagelinks) - else - return false - end - return true -end - -local dirdata = { - 'url=/manga/getBookRecommend/%s?tag=&method=GET', - 'url=/manga/getAZ/%s?tag=&method=GET&api=/mangaheatapi/web' -} - -function getnameandlink() - local data = string.format(dirdata[module.CurrentDirectoryIndex+1], IncStr(url)) - local d = 'manga' - if module.CurrentDirectoryIndex == 0 then - d = 'comicDetail' - end - if http.post(module.rooturl .. '/api', data) then - local x = TXQuery.Create(http.Document) - local hasTitles = false - local v = x.xpath('json(*).child()') - for i = 1, v.count do - local v1 = v.get(i) - links.add(module.rooturl .. string.format('/%s/%s/%s', d, x.xpathstring('bookId', v1), x.xpathstring('title', v1))) - names.add(x.xpathstring('title', v1)) - hasTitles = true - end - if hasTitles then - updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 - end - return no_error - else - return net_problem - end -end - -function Init() - local m = NewModule() - m.website = 'ZingBox' - m.rooturl = 'http://www.zingbox.me' - m.category = 'English' - m.lastupdated='May 17, 2018' - m.ongetinfo='getinfo' - m.ongetpagenumber='getpagenumber' - m.ongetnameandlink='getnameandlink' - m.totaldirectory = #dirdata -end From 9e34df7a7c626eb32f257d0a686a0dc1216a5900 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 15 Sep 2018 07:33:22 +0300 Subject: [PATCH 2661/2794] MangaShiro, fix GetInfo fixes #1418 --- lua/modules/MangaShiro.lua | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 32b01a136..c60b5d697 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -2,6 +2,7 @@ function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then x=TXQuery.Create(http.document) + x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) if module.website == 'KomikCast' then mangainfo.title=x.xpathstring('//div[@class="mangainfo"]/h1') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="topinfo"]/img/@src')) @@ -16,6 +17,16 @@ function getinfo() mangainfo.genres=x.xpathstringall('//div[@class="infozin"]//li[starts-with(.,"Genre")]/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="infozin"]//li[starts-with(.,"Status")]'), "Publishing", "Finished") mangainfo.summary=x.xpathstringall('//*[@class="sinopc"]/p/text()', '') + elseif module.website == 'MangaShiro' then + mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@itemprop="image"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') + mangainfo.genres=x.xpathstringall('//div[contains(@class,"animeinfo")]/div[@class="gnr"]/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) + mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') + mangainfo.chapterlinks.clear() + mangainfo.chapternames.clear() + x.xpathhrefall('//div[@class="bxcl"]//li//div[@class="lch"]/a', mangainfo.chapterlinks, mangainfo.chapternames) else mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) @@ -23,8 +34,7 @@ function getinfo() mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') - end - x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + end InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error else @@ -49,7 +59,7 @@ end function getnameandlink() local dirurl = '/manga-list/' - if module.website == 'MangaShiro' then dirurl = '/daftar-manga/' + if module.website == 'MangaShiro' then dirurl = '/daftar-manga/?list' elseif module.website == 'KomikStation' then dirurl = '/daftar-komik/' elseif module.website == 'KomikCast' then dirurl = '/daftar-komik/?list' elseif module.website == 'MangaKid' then dirurl = '/manga-lists/' @@ -57,7 +67,7 @@ function getnameandlink() if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) - elseif module.website == 'WestManga' or module.website == 'MangaShiro' then + elseif module.website == 'WestManga' then TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) else TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) From 51cc95a052301ae1d81a617e865c277db5e879b5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 18 Sep 2018 16:31:23 +0300 Subject: [PATCH 2662/2794] LHTranslation, fix download fixes #1471 --- lua/modules/LHTranslation.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index a377c8e30..ab649ffb9 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -28,14 +28,14 @@ local readrooturl = 'http://read.lhtranslation.com' function GetPageNumber() if http.get(MaybeFillHost(readrooturl, '/read-' .. url:gsub('/', '') .. '.html')) then local x=TXQuery.Create(http.document) - x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) + x.xpathstringall('//img[contains(@class,"chapter-img")]/@src',task.pagelinks) if task.pagelinks.count > 0 then return true; end end if http.get(MaybeFillHost(module.rooturl, url)) then local x = TXQuery.Create(http.document) if http.get(x.xpathstring('//div[@class="commentmetadata"][1]/p/a/@href')) then x.parsehtml(http.document) - x.xpathstringall('//img[@class="chapter-img"]/@src',task.pagelinks) + x.xpathstringall('//img[contains(@class,"chapter-img")]/@src',task.pagelinks) if task.pagelinks.count > 0 then return true; end end end From e8a668f1a664451f02feb803c4f38d3d803d4ae9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 10:37:53 +0300 Subject: [PATCH 2663/2794] Lhscans, fix download fixes #1461 fixes #1463 --- lua/modules/Lhscans.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lua/modules/Lhscans.lua b/lua/modules/Lhscans.lua index af987acba..fe7c4b50b 100644 --- a/lua/modules/Lhscans.lua +++ b/lua/modules/Lhscans.lua @@ -29,9 +29,11 @@ end function getpagenumber() task.pagelinks.clear() - if http.get(MaybeFillHost(module.rooturl, url)) then + local u = MaybeFillHost(module.rooturl, url) + if http.get(u) then local x=TXQuery.Create(http.Document) x.xpathstringall('//img[@class="chapter-img"]/@src', task.pagelinks) + task.pagecontainerlinks.text = u else return false end @@ -53,6 +55,11 @@ function getnameandlink() end end +function BeforeDownloadImage() + http.headers.values['Referer'] = task.pagecontainerlinks.text + return true +end + function AddWebsiteModule(name, url, cat) local m = NewModule() m.category = cat @@ -63,6 +70,7 @@ function AddWebsiteModule(name, url, cat) m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' + m.OnBeforeDownloadImage = 'BeforeDownloadImage' return m end From 666f581b888c45e3c9132df07cd839e3ea90bf1c Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 12:50:55 +0300 Subject: [PATCH 2664/2794] TripleSevenScan, removed fixes #1432 --- lua/modules/FoOlSlide.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 7175546e7..e436beb25 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -27,7 +27,6 @@ function getdirurl(website) local dirs = { ['GoManga'] = dirurlreader, ['Jaiminisbox'] = dirurlreader, - ['TripleSevenScan'] = dirurlreader, ['DokiFansubs'] = dirurlreader, ['AtelierDuNoir'] = dirurlreader, ['OneTimeScans'] = dirurlfoolslide, @@ -246,7 +245,6 @@ function Init() AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com', cat) AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com', cat) AddWebsiteModule('LetItGoScans', 'http://reader.letitgo.scans.today', cat) - AddWebsiteModule('TripleSevenScan', 'http://triplesevenscans.com', cat) AddWebsiteModule('SeaOtterScans', 'https://reader.seaotterscans.com', cat) AddWebsiteModule('AntisenseScans', 'http://antisensescans.com', cat) AddWebsiteModule('TheCatScans', 'https://reader.thecatscans.com', cat) From c6e6427fcf73685d3aa8ca78b8e3553bf4747992 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 12:52:07 +0300 Subject: [PATCH 2665/2794] Subapics, removed fixes #1429 --- lua/modules/MangaShiro.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index c60b5d697..dd5a8e76e 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -92,7 +92,6 @@ end function Init() AddWebsiteModule('MangaShiro', 'http://mangashiro.net') - AddWebsiteModule('Subapics', 'http://subapics.com') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') AddWebsiteModule('KomikStation', 'http://www.komikstation.com') AddWebsiteModule('MangaKid', 'http://mangakid.net') From a2b91454742e214e8a4a8677423ec81ad93857e6 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 12:53:50 +0300 Subject: [PATCH 2666/2794] SekaiManga, removed fixes #1428 --- baseunits/ModuleList.inc | 1 - baseunits/modules/SekaiManga.pas | 134 ------------------------------- 2 files changed, 135 deletions(-) delete mode 100644 baseunits/modules/SekaiManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e636f3ad5..86baaabc0 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -24,7 +24,6 @@ uses WebtoonTr, MangaSaurus, GMangaMe, - SekaiManga, KuManga, SenManga, MangaInn, diff --git a/baseunits/modules/SekaiManga.pas b/baseunits/modules/SekaiManga.pas deleted file mode 100644 index 938e767c4..000000000 --- a/baseunits/modules/SekaiManga.pas +++ /dev/null @@ -1,134 +0,0 @@ -unit SekaiManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/Sekai/manga-list.html'; - urllead = '/Sekai/'; - -function FixURLLead(const S: String): String; -begin - Result := S; - if Result = '' then Exit; - if Pos(urllead, Result) = 0 then - begin - if Result[1] = '/' then - Delete(Result, 1, 1); - Result := urllead + Result; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in CSS('div.char>span a') do - begin - s := Trim(v.toString); - if s <> '' then - begin - ALinks.Add(FixURLLead(v.toNode.getAttribute('href'))); - ANames.Add(s); - end; - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v, x: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := CSS('img.img-rounded').toNode.getAttribute('src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := SeparateLeft(XPathString('//title'), ' - '#10); - authors := XPathString('//div[@id="info"]//table/tbody/tr/td[.="Autor(s):"]/following-sibling::td'); - artists := XPathString('//div[@id="info"]//table/tbody/tr/td[.="Artista(s):"]/following-sibling::td'); - status := MangaInfoStatusIfPos(XPathString('//div[@id="info"]//table/tbody/tr/td[.="Estado en SekaiManga:"]/following-sibling::td'), 'En curso', 'Terminado'); - genres := XPathString('//div[@id="info"]//table/tbody/tr/td[.="Género(s):"]/following-sibling::td'); - for v in XPath('//table[@id="example"]/tbody/tr') do - begin - x := XPath('td[2]//a', v.toNode); - s := XPathString('td[3]', v.toNode); - if s <> '' then s := ' ' + s; - chapterLinks.Add(FixURLLead(x.toNode.getAttribute('href'))); - chapterName.Add(x.toString + s); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - Cookies.Add('read_type=1'); - if GET(FillHost(Module.RootURL, AURL)) then - begin - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('//div[@class="chapter-content"]//img/@src', PageLinks); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'SekaiManga'; - RootURL := 'http://www.sekaimanga.net'; - Category := 'Spanish'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 6b3f6b785526f54ddcaa32c908b31c4e569152cb Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 12:56:19 +0300 Subject: [PATCH 2667/2794] ReadComics, removed fixes #1427 --- baseunits/ModuleList.inc | 1 - baseunits/modules/ReadComics.pas | 120 ------------------------------- 2 files changed, 121 deletions(-) delete mode 100644 baseunits/modules/ReadComics.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 86baaabc0..81d5543e0 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -32,7 +32,6 @@ uses MangaIndo, MangaOnlineTo, MyMangaMe, - ReadComics, MangaCool, GoodManga, MangaZuki, diff --git a/baseunits/modules/ReadComics.pas b/baseunits/modules/ReadComics.pas deleted file mode 100644 index 8700d1016..000000000 --- a/baseunits/modules/ReadComics.pas +++ /dev/null @@ -1,120 +0,0 @@ -unit ReadComics; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil,Dialogs; - -implementation - -const - dirurl = '/comic-list'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="serie-box"]/*/li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := RemoveURLDelim(FillHost(Module.RootURL, AURL)); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//img[@id="series_image"]/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h1[@class="manga-title"]'); - status := MangaInfoStatusIfPos( - XPathString('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Status:")]/following-sibling::*[@class="desc"][1]'), - 'Ongoing', - 'Complete'); - artists := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Artist:")]/following-sibling::*[@class="desc"][1]/a'); - authors := XPathStringAll('//*[@class="info"]/p/*[@class="data"][starts-with(.,"Author:")]/following-sibling::*[@class="desc"][1]/a'); - for v in XPath('//ul[@class="basic-list"]/li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s,url: String; - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - url := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL))+'full'; - if GET(url) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//img[@class="chapter_img"]') do - PageLinks.Add(v.toNode.getAttribute('src')); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'ReadComics'; - RootURL := 'http://readcomics.tv'; - Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 9c89ed352a1449f5cc62e67534a3a24ee3dff793 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:04:40 +0300 Subject: [PATCH 2668/2794] Rawdevart, removed fixes #1426 --- lua/modules/rawdevart.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index e925b25fa..da46d9eb9 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -68,7 +68,6 @@ end function Init() local cat = 'Raw' - AddWebsiteModule('Rawdevart', 'https://rawdevart.com', cat) AddWebsiteModule('RawNeko', 'http://rawneko.com', cat) cat = 'English-Scanlation' From 0bfe4a32b09802cc99efab1bb000ef303501f7e0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:12:18 +0300 Subject: [PATCH 2669/2794] add RawMangaSite [raw] --- lua/modules/myReaderMangaCMS.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 6e6091454..350d7fe60 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -90,6 +90,7 @@ function Init() c='Raw' AddWebsiteModule('RawMangaUpdate', 'http://rawmangaupdate.com', c); AddWebsiteModule('MangaRawOnline', 'http://mangaraw.online', c); + AddWebsiteModule('RawMangaSite', 'https://rawmanga.site', c); c='Turkish' AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', c); From cc4b2fbaa15193a3c4b00c8aec02c377f0d7b834 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:15:12 +0300 Subject: [PATCH 2670/2794] add MangAs [sp] fixes #1453 --- lua/modules/myReaderMangaCMS.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 350d7fe60..bd1bcedb3 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -50,18 +50,27 @@ function GetInfo(); end function GetPageNumber() - if http.GET(MaybeFillHost(module.RootURL, url)) then + local u = MaybeFillHost(module.RootURL, url) + if http.GET(u) then x = TXQuery.Create(http.Document) x.XPathStringAll('//div[@id="all"]/img/@data-src', task.PageLinks) if task.PageLinks.Count == 0 then x.XPathStringAll('//div[@id="all"]/img/@src', task.PageLinks) end + task.pagecontainerlinks.text = u return true else return false end end +function beforedownloadimage() + http.reset() + http.headers.values['Referer'] = task.pagecontainerlinks.text + print(http.headers.values['Referer']) + return true +end + function AddWebsiteModule(name, url, cat) local m = NewModule() m.category = cat @@ -71,6 +80,7 @@ function AddWebsiteModule(name, url, cat) m.OnGetNameAndLink = 'GetNameAndLink' m.OnGetInfo = 'GetInfo' m.OnGetPageNumber = 'GetPageNumber' + m.onbeforedownloadimage='beforedownloadimage' return m end @@ -80,6 +90,7 @@ function Init() c='Spanish' AddWebsiteModule('MangaDoor', 'http://mangadoor.com', c); + AddWebsiteModule('MangAs', 'https://mang.as', c); c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); From 136ca548478f79417cc1e6bef94bff45f3b7fbfe Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:17:48 +0300 Subject: [PATCH 2671/2794] Mangavy, removed fixes #1421 --- lua/modules/rawdevart.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index da46d9eb9..38d538070 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -73,7 +73,4 @@ function Init() cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) AddWebsiteModule('ZeroScans', 'https://zeroscans.com', cat) - - cat = 'Indonesian' - AddWebsiteModule('Mangavy', 'https://mangavy.com', cat) end From 30fc366aeebb38969e314dfb37fdd15e772d4abb Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:18:52 +0300 Subject: [PATCH 2672/2794] MangaTrue, removed fixes #1420 --- lua/modules/MangaAll.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/MangaAll.lua b/lua/modules/MangaAll.lua index d98744866..3e2304301 100644 --- a/lua/modules/MangaAll.lua +++ b/lua/modules/MangaAll.lua @@ -71,5 +71,4 @@ end function Init() AddWebsiteModule('MangaAll', 'http://mangaall.com') - AddWebsiteModule('MangaTrue', 'http://mangatrue.com') end From 700cae4e7c871d9e078b53998fa1ae7b7d4717ef Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:20:22 +0300 Subject: [PATCH 2673/2794] MangaSaurus, removed fixes #1417 --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaSaurus.pas | 204 ------------------------------ 2 files changed, 205 deletions(-) delete mode 100644 baseunits/modules/MangaSaurus.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 81d5543e0..42664de9f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -22,7 +22,6 @@ uses MangaEden, HeyMangaXyz, WebtoonTr, - MangaSaurus, GMangaMe, KuManga, SenManga, diff --git a/baseunits/modules/MangaSaurus.pas b/baseunits/modules/MangaSaurus.pas deleted file mode 100644 index d848f10ab..000000000 --- a/baseunits/modules/MangaSaurus.pas +++ /dev/null @@ -1,204 +0,0 @@ -unit MangaSaurus; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; - -implementation - -const - dirurl = '/browse/added/'; - domainImage = 'http://img.mangasaurus.com'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - s := XPathString('//span[@class="pager__jumpLast"]/a/@href'); - if s <> '' then - begin - s := ReplaceRegExpr('^.+/(\d+$)', s, '$1', True); - Page := StrToIntDef(s, 1); - end; - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//span[@class="comicInfo__comicTitle"]/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//div[@class="gallery-info__cover"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//h1[@class="title"]'); - authors := XPathStringAll( - '//table[@class="table--info"]/tbody/tr/td[.="Author"]/following-sibling::td/ul[@class="tag-list"]/li/a'); - artists := XPathStringAll( - '//table[@class="table--info"]/tbody/tr/td[.="Artist"]/following-sibling::td/ul[@class="tag-list"]/li/a'); - genres := XPathStringAll( - '//table[@class="table--info"]/tbody/tr/td[.="Genres" or .="Contents" or .="Category"]/following-sibling::td/ul[@class="tag-list"]/li/a'); - summary := XPathString( - '//table[@class="table--info"]/tbody/tr/td[.="Description"]/following-sibling::td'); - s := XPathString('//table[@class="table--info"]/tbody/tr/td[.="Status"]/following-sibling::td/span'); - if s <> '' then - begin - s := LowerCase(s); - if Pos('ongoing', s) <> 0 then - status := MangaInfo_StatusOngoing - else if Pos('completed', s) <> 0 then - status := MangaInfo_StatusCompleted; - end; - for v in XPath('//table[@class="table--data table--chapters js-chapterList"]/tbody/tr/td/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathString('text()', v.toNode)); - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - source: TStringList; - v: IXQValue; - i: Integer; - comicA, imagesA, slug, key, ext: String; - images: array of String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then - begin - Result := True; - comicA := ''; - imagesA := ''; - source := TStringList.Create; - try - source.LoadFromStream(Document); - if source.Count > 0 then - for i := 0 to source.Count - 1 do - begin - if Pos('Mangasaurus.ImageReader.setComic(', source[i]) <> 0 then - comicA := TrimRightChar(Trim(SeparateRight(source[i], '{')), [')', ';']) - else - if Pos('Mangasaurus.ImageReader.setImages(', source[i]) <> 0 then - begin - imagesA := TrimRightChar(Trim(SeparateRight(source[i], '{')), [')', ';']); - Break; - end; - end; - finally - source.Free; - end; - if (comicA <> '') and (imagesA <> '') then - with TXQueryEngineHTML.Create('{' + comicA) do - try - slug := XPathString('json(*).slug'); - if slug <> '' then - begin - ParseHTML('{' + imagesA); - SetLength(images, 0); - for v in XPath('json(*)()') do - begin - SetLength(images, Length(images) + 1); - images[High(images)] := v.toString; - end; - if Length(images) <> 0 then - begin - for i := Low(images) to High(images) do - begin - key := XPathString('json(*)(' + images[i] + ').original.file'); - if key <> '' then - begin - ext := SeparateRight(key, '.'); - key := SeparateLeft(key, '.'); - if ext <> '' then - PageLinks.Add(domainImage + '/original/' + key + '/' + slug + '-' + images[i] + '.' + ext); - end; - end; - SetLength(images, 0); - end; - end; - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaSaurus'; - RootURL := 'http://mangasaurus.com'; - Category := 'English'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 87656671149788ebb0a14c78006126d0a7bc21c5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:23:04 +0300 Subject: [PATCH 2674/2794] MangaOnlineToday, removed fixes #1415 --- lua/modules/WPManga.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index bb5bee08c..9f2464c1a 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -196,7 +196,6 @@ function Init() AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', cat) AddWebsiteModule('MangaDeep', 'http://www.mangadeep.com', cat) AddWebsiteModule('Manga99', 'http://www.manga99.com', cat) - AddWebsiteModule('MangaOnlineToday', 'http://www.mangaonline.today', cat) cat = 'H-Sites' AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', cat) From b9b268018a9b5ed3c4492cfe4dcf58a6882781b9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:25:00 +0300 Subject: [PATCH 2675/2794] MangaOnlineTo, removed fixes #1414 --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaOnlineTo.pas | 114 ---------------------------- 2 files changed, 115 deletions(-) delete mode 100644 baseunits/modules/MangaOnlineTo.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 42664de9f..cd8c3ff7a 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -29,7 +29,6 @@ uses LeoManga, MangaPark, MangaIndo, - MangaOnlineTo, MyMangaMe, MangaCool, GoodManga, diff --git a/baseunits/modules/MangaOnlineTo.pas b/baseunits/modules/MangaOnlineTo.pas deleted file mode 100644 index 1223036c3..000000000 --- a/baseunits/modules/MangaOnlineTo.pas +++ /dev/null @@ -1,114 +0,0 @@ -unit MangaOnlineTo; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; - -implementation - -const - dirurl = '/manga-list.html'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="content-l"]//li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('text()[last()]', v)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="image-info"]/img/@src')); - if title = '' then title := XPathString('//div[@class="info"]/h2/text()[last()]'); - authors := XPathString('//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Author")]/following-sibling::*'); - artists := XPathString('//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Artist")]/following-sibling::*'); - genres := XPathString('//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Genre")]/string-join(following-sibling::*//a,", ")'); - status := MangaInfoStatusIfPos(XPathString( - '//div[@class="info"]/div[@class="row-info"]/p/span[starts-with(.,"Status")]/following-sibling::*'), - 'Ongoing', - 'Completed'); - summary := XPathString('//div[@class="info"]/div[@class="row-info"]/p[starts-with(.,"Plot Summary")]/following-sibling::p/text()'); - for v in XPath('//div[@class="list-chapter"]//li/a') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathString('string-join(text(),"")', v)); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('//*[@id="list-img"]/img/@src', PageLinks); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaOnlineTo'; - RootURL := 'http://mangaon.net'; - Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 52ca8a49c9a564d967a37cb7cf017eac27244037 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:26:39 +0300 Subject: [PATCH 2676/2794] MangaForest, removed fixes #1412 --- lua/modules/myReaderMangaCMS.lua | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index bd1bcedb3..2ed0f0dea 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -85,10 +85,7 @@ function AddWebsiteModule(name, url, cat) end function Init() - local c='English' - AddWebsiteModule('MangaForest', 'http://mangaforest.com', c) - - c='Spanish' + local c='Spanish' AddWebsiteModule('MangaDoor', 'http://mangadoor.com', c); AddWebsiteModule('MangAs', 'https://mang.as', c); From f9c35405a1aa4df36f2342bcced1b50baa0a755c Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:27:36 +0300 Subject: [PATCH 2677/2794] MangaDesu, removed fixes #1411 --- lua/modules/myReaderMangaCMS.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 2ed0f0dea..6e7e4915b 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -91,7 +91,6 @@ function Init() c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); - AddWebsiteModule('MangaDesu','http://mangadesu.net', c); AddWebsiteModule('MangaID', 'http://mangaid.net', c); AddWebsiteModule('KomikGue', 'https://www.komikgue.com', c); From 373e82f0f9afe377051cdb7c426e0fd3ede79cb4 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:32:28 +0300 Subject: [PATCH 2678/2794] MangaCool, removed fixes #1409 --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaCool.pas | 108 -------------------------------- 2 files changed, 109 deletions(-) delete mode 100644 baseunits/modules/MangaCool.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index cd8c3ff7a..cebae85a7 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -30,7 +30,6 @@ uses MangaPark, MangaIndo, MyMangaMe, - MangaCool, GoodManga, MangaZuki, ReadMangaToday, diff --git a/baseunits/modules/MangaCool.pas b/baseunits/modules/MangaCool.pas deleted file mode 100644 index 6a5def55d..000000000 --- a/baseunits/modules/MangaCool.pas +++ /dev/null @@ -1,108 +0,0 @@ -unit MangaCool; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; - -implementation - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/list') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('/html/body/div/div/div/ul/li/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('/html/body/div/div/div/img/@src')); - title := XPathString('//h1/a/@title'); - genres := XPathString('string-join(/html/body/div/div/div/span/a,", ")'); - for v in XPath('/html/body/div/div/div[not(@id="ShowAllEpisodes")]/div/a') do - begin - s := v.toNode.getAttribute('href'); - if Pos('/page-1', s) > 0 then - s := StringReplace(s, '/page-1', '', []); - chapterLinks.Add(s); - chapterName.Add(v.toNode.getAttribute('title')); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('/html/body/div/div/img/@src', PageLinks); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaCool'; - RootURL := 'http://mangacool.se'; - Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. From 0fac823f17bd440e7cfb953f9ea6b1c02d1edf11 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:43:43 +0300 Subject: [PATCH 2679/2794] MangaBoom, removed fixes #1408 --- lua/modules/WPManga.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 9f2464c1a..41c78aef1 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -189,8 +189,6 @@ function AddWebsiteModule(name, url, category) end function Init() - AddWebsiteModule('MangaBoom', 'http://www.mangaboom.com', 'Thai') - local cat = 'English' AddWebsiteModule('Authrone', 'http://www.authrone.com', cat) AddWebsiteModule('EyeOnManga', 'http://www.eyeonmanga.com', cat) From beca411aec378499fb3de3178f27835a2ccd2081 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:47:26 +0300 Subject: [PATCH 2680/2794] rawneko.com -> mangaall.com fixes #1407 --- lua/modules/MangaAll.lua | 74 --------------------------------------- lua/modules/rawdevart.lua | 2 +- 2 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 lua/modules/MangaAll.lua diff --git a/lua/modules/MangaAll.lua b/lua/modules/MangaAll.lua deleted file mode 100644 index 3e2304301..000000000 --- a/lua/modules/MangaAll.lua +++ /dev/null @@ -1,74 +0,0 @@ -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(mangainfo.url) then - local x=TXQuery.Create(http.document) - if mangainfo.title == '' then - mangainfo.title = Trim(x.XPathString('//div[@class="post-title"]/h3')) - if string.match(mangainfo.title:upper(), ' RAW$') ~= nil then - mangainfo.title = mangainfo.title:sub(1, -5) - end - end - mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('//div[@class="summary_image"]/a/img/@data-src')) - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[contains(div[@class="summary-heading"]/h5, "Status")]/div[@class="summary-content"]')) - mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') - mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') - mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') - mangainfo.summary=x.xpathstring('//div[@class="description-summary"]/div/p') - x.xpathhrefall('//div[contains(@class, "listing-chapters")]/ul/li/a', mangainfo.chapterlinks, mangainfo.chapternames) - InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) - return no_error - else - return net_problem - end -end - -function getpagenumber() - task.pagelinks.clear() - if http.get(MaybeFillHost(module.rooturl, url)) then - local x=TXQuery.Create(http.Document) - x.xpathstringall('//img[contains(@class, "wp-manga-chapter-img")]/@src', task.pagelinks) - else - return false - end - return true -end - -function getnameandlink() - if http.get(module.RootURL .. '/manga/page/' .. IncStr(url) .. '/?m_orderby=alphabet') then - local x = TXQuery.Create(http.Document) - local v = x.xpath('//div[@class="page-item-detail"]/div/a') - for i = 1, v.count do - local v1 = v.get(i) - local s = v1.getAttribute('title') - if string.match(s:upper(), ' RAW$') ~= nil then - s = s:sub(1, -5) - end - names.add(s) - links.add(v1.getAttribute('href')) - end - local p = x.xpathstring('//div[contains(@class, "nav-previous")]/a/@href') - p = tonumber(p:match('page/(%d+)/')) - if p ~= nil then - updatelist.CurrentDirectoryPageNumber = p; - end - return no_error - else - return net_problem - end -end - -function AddWebsiteModule(name, url) - local m = NewModule() - m.website = name - m.rooturl = url - m.category = 'Raw' - m.lastupdated = 'April 9, 2018' - m.ongetinfo='getinfo' - m.ongetpagenumber='getpagenumber' - m.ongetnameandlink='getnameandlink' - return m -end - -function Init() - AddWebsiteModule('MangaAll', 'http://mangaall.com') -end diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 38d538070..de3b48cb7 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -68,7 +68,7 @@ end function Init() local cat = 'Raw' - AddWebsiteModule('RawNeko', 'http://rawneko.com', cat) + AddWebsiteModule('RawNeko', 'http://mangaall.com', cat) cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) From 77de7e47488b74d3cf808868980f2761f2177805 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:49:24 +0300 Subject: [PATCH 2681/2794] IdkScans, removed fixes #1404 --- lua/modules/FoOlSlide.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index e436beb25..faf8dc423 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -291,7 +291,6 @@ function Init() AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) AddWebsiteModule('PatyScans', 'http://lector.patyscans.com', cat) AddWebsiteModule('PCNet', 'http://pcnet.patyscans.com', cat) - AddWebsiteModule('IdkScans', 'http://reader.idkscans.com', cat) AddWebsiteModule('Nightow', 'http://nightow.net', cat) AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) AddWebsiteModule('MangajinNoFansub', 'https://www.mangajinnofansub.com', cat) From d251e29c50344334e0d22baf9a58950b9dadca99 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 19 Sep 2018 13:50:30 +0300 Subject: [PATCH 2682/2794] HeyManga, removed fixes #1402 --- baseunits/ModuleList.inc | 1 - baseunits/modules/HeyMangaXyz.pas | 151 ------------------------------ 2 files changed, 152 deletions(-) delete mode 100644 baseunits/modules/HeyMangaXyz.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index cebae85a7..9ad575715 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -20,7 +20,6 @@ uses Webtoons, Tsumino, MangaEden, - HeyMangaXyz, WebtoonTr, GMangaMe, KuManga, diff --git a/baseunits/modules/HeyMangaXyz.pas b/baseunits/modules/HeyMangaXyz.pas deleted file mode 100644 index b62dfaa01..000000000 --- a/baseunits/modules/HeyMangaXyz.pas +++ /dev/null @@ -1,151 +0,0 @@ -unit HeyMangaXyz; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/manga-series/new/'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + '1') then - begin - Result := NO_ERROR; - Page := XPathCount('//div/a[@class="btn btn-sm btn-icon"]', MangaInfo.FHTTP.Document); - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl + IncStr(AURL)) then - begin - Result := NO_ERROR; - XPathHREFAll('//div[@class="row"]/div/div/a', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do - begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//div[@class="mangas"]/div[@class="manga"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if (coverLink <> '') and (LeftStr(coverLink, 2) = '//') then - coverLink := 'https:' + coverLink; - if title = '' then title := SeparateRight(XPathString('//ul[@class="lead"]/li[starts-with(.,"Name: ")]'), ': '); - s := XPathString('//ul[@class="lead"]/li[starts-with(.,"Status: ")]'); - if Pos('Ongoing', s) > 0 then - status := '1' - else if Pos('Completed', s) > 0 then - status := '0'; - genres := XPathStringAll('//ul[@class="lead"]/li[starts-with(.,"Genre: ")]/a'); - summary := SeparateRight(XPathString('//ul[@class="lead"]/li[starts-with(.,"Plot: ")]'), ': '); - for v in XPath('//div[@id="chapters"]/ul//li//a') do - begin - s := v.toNode.getAttribute('href'); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 1); - chapterLinks.Add(s); - chapterName.Add(v.toString); - end; - if chapterLinks.Count > 0 then - begin - s := XPathString('//div[@id="chapters"]/ul/p[starts-with(.,"Next Chapter:")]/following-sibling::li//a/@href'); - if s <> '' then - begin - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 1); - if SameText(s, chapterLinks[chapterLinks.Count-1]) then - begin - chapterLinks.Delete(chapterLinks.Count - 1); - chapterName.Delete(chapterName.Count - 1); - end; - end; - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - with DownloadThread, DownloadThread.Task.Container do begin - PageLinks.Clear; - Result := FHTTP.GET(FillHost(Module.RootURL, AURL) + '1'); - if not Result then Exit; - XPathStringAll('//select[@id="fuzetsu_list"]/option[@value]/concat('+ QuotedStr(AURL) +',@value)', FHTTP.Document, PageLinks); - end; -end; - -function DownloadImage(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; - - function downloadandsave(u: String): Boolean; - begin - if u = '' then Exit(False); - if LeftStr(u, 2) = '//' then u := 'https:' + u; - Result := DownloadThread.FHTTP.GET(u); - end; - -begin - Result := False; - if not DownloadThread.FHTTP.GET(FillHost(Module.RootURL, AURL)) then Exit; - with TXQueryEngineHTML.Create(DownloadThread.FHTTP.Document) do - try - Result := downloadandsave(XPathString('//img[@id="img-content"]/@src')); - if (Result = False) and (DownloadThread.IsTerminated = False) then - Result := downloadandsave(XPathString('//img[@id="img-content"]/@onerror/substring-before(substring-after(.,"''"),"''")')); - finally - Free; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'HeyManga'; - RootURL := 'https://www.heymanga.me'; - Category := 'English'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnDownloadImage := @DownloadImage; - end; -end; - -initialization - RegisterModule; - -end. From 8be3e7850f753a006855e3a569373b79a9aa1692 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 20 Sep 2018 08:04:49 +0300 Subject: [PATCH 2683/2794] SaikoScans, removed fixes #1379 --- lua/modules/FoOlSlide.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index faf8dc423..2b4ae2a5a 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -255,7 +255,6 @@ function Init() AddWebsiteModule('PhoenixSerenade', 'https://reader.serenade.moe', cat) AddWebsiteModule('VortexScans', 'https://reader.vortex-scans.com', cat) AddWebsiteModule('RoseliaScanlations', 'http://reader.roseliascans.com', cat) - AddWebsiteModule('SaikoScans', 'http://saikoscans.ml', cat) AddWebsiteModule('Yuri-ism', 'https://www.yuri-ism.net', cat) AddWebsiteModule('SilentSkyScans', 'http://reader.silentsky-scans.net', cat) AddWebsiteModule('BunnysScans', 'http://bns.shounen-ai.net', cat) From 6cc8659d0880a8cf076630f65fdb50e6d103faee Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 20 Sep 2018 08:06:30 +0300 Subject: [PATCH 2684/2794] NeoProjectScan, removed fixes #1382 --- lua/modules/FoOlSlide.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 2b4ae2a5a..8c2f61ca7 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -32,7 +32,6 @@ function getdirurl(website) ['OneTimeScans'] = dirurlfoolslide, ['DejameProbar'] = dirurlslide, ['MenudoFansub'] = dirurlslide, - ['NeoProjectScan'] = dirurlslide, ['SolitarioNoFansub'] = dirurlslide, ['SantosScan'] = dirurlslideU, ['Pzykosis666HFansub'] = dirurlonline, @@ -276,7 +275,6 @@ function Init() AddWebsiteModule('DejameProbar', 'http://dejameprobar.es', cat) AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) - AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) AddWebsiteModule('Pzykosis666HFansub', 'https://pzykosis666hfansub.com', cat) AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) AddWebsiteModule('SeinagiFansub', 'https://seinagi.org', cat) From a9865019d43bb93839de386d6d7de8372afb5926 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 20 Sep 2018 08:07:31 +0300 Subject: [PATCH 2685/2794] SantosScan, removed fixes #1384 --- lua/modules/FoOlSlide.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 8c2f61ca7..6956ad592 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -33,7 +33,6 @@ function getdirurl(website) ['DejameProbar'] = dirurlslide, ['MenudoFansub'] = dirurlslide, ['SolitarioNoFansub'] = dirurlslide, - ['SantosScan'] = dirurlslideU, ['Pzykosis666HFansub'] = dirurlonline, ['SeinagiFansub'] = dirurlonline, ['HelveticaScans'] = dirurlhelvetica, @@ -276,7 +275,6 @@ function Init() AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) AddWebsiteModule('Pzykosis666HFansub', 'https://pzykosis666hfansub.com', cat) - AddWebsiteModule('SantosScan', 'http://santosfansub.com', cat) AddWebsiteModule('SeinagiFansub', 'https://seinagi.org', cat) AddWebsiteModule('SeinagiAdultoFansub', 'https://adulto.seinagi.org', cat) AddWebsiteModule('SolitarioNoFansub', 'http://snf.mangaea.net', cat) From b3a0589206fd967e6a23d65f1338aef77f9cdcd1 Mon Sep 17 00:00:00 2001 From: rs3mk Date: Fri, 21 Sep 2018 20:11:05 -0500 Subject: [PATCH 2686/2794] update domain NeoProjectScan --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 6956ad592..69ea6a800 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -281,6 +281,7 @@ function Init() AddWebsiteModule('RavensScans', 'http://ravens-scans.com', cat) AddWebsiteModule('KirishimaFansub', 'http://lector.kirishimafansub.com', cat) AddWebsiteModule('NoraNoFansub', 'https://www.noranofansub.com', cat) + AddWebsiteModule('NeoProjectScan', 'http://npscan.mangaea.net', cat) AddWebsiteModule('YamiTenshiNoFansub', 'http://lector.ytnofan.com', cat) AddWebsiteModule('XAnimeSeduccion', 'http://xanime-seduccion.com', cat) AddWebsiteModule('JokerFansub', 'http://reader.jokerfansub.com', cat) From 1b781e06b42497b44e305828e42631a8e776a902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Ko=C5=A1ir?= Date: Fri, 5 Oct 2018 20:33:43 +0900 Subject: [PATCH 2687/2794] Update build instructions --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c4d3f9aa5..3cb667e85 100644 --- a/README.md +++ b/README.md @@ -20,15 +20,18 @@ The Free Manga Downloader is a free open source application written in Object Pa In order to build FMD from the source code, you must install the latest version of Lazarus and Free Pascal Compiler from http://www.lazarus-ide.org/. Then you must install the following 3rd party libraries and components: - - [RichMemo](https://sourceforge.net/projects/lazarus-ccr/) - - [Virtual TreeView](https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4) - - [Synapse](http://synapse.ararat.cz/) + - [RichMemo](https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/richmemo/) + - [Virtual TreeView](https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4) (and `lclextensions` from the Releases page) + - [Synapse](https://sourceforge.net/p/synalist/code/HEAD/tree/trunk/) (at least revision `r160`) - [InternetTools](https://github.com/benibela/internettools) - [BESEN](https://github.com/BeRo1985/besen) - [MultiLog](https://github.com/blikblum/multilog) - [DCPCypt](https://sourceforge.net/projects/lazarus-ccr/) -After everything is installed, open the file `md.lpi` by using Lazarus IDE, select `Run -> Build` to build the source code. If everything is ok, the binary file should be in `FMD_source_code_folder/bin`. +After everything is installed, open the file `md.lpi` by using Lazarus IDE. Make sure to add `ssl_openssl` to uses list of the `laz_synapse` package. +Then select `Run -> Build` to build the source code. If everything is ok, the binary file should be in `FMD_source_code_folder/bin`. + +If InternetTools or BESEN fail to compile (incompatible PPU), make sure to compile them individually first. ## Localization From 919c3e4ccb928290aadfd9ddf40103ca228390df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klemen=20Ko=C5=A1ir?= Date: Sat, 6 Oct 2018 00:42:40 +0900 Subject: [PATCH 2688/2794] Remove download directory trailing periods --- mangadownloader/forms/frmMain.pas | 1 + 1 file changed, 1 insertion(+) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index aa66fef65..cc6c492cf 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2275,6 +2275,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); '', OptionChangeUnicodeCharacter, OptionChangeUnicodeCharacterStr); + s:=ReplaceRegExpr('\.*$', s, ''); c:=1; p:=links.Count; r:=0; From f4ad6844581cbc6e84d48b25745142ddb225d3b2 Mon Sep 17 00:00:00 2001 From: dusty Date: Sat, 13 Oct 2018 09:57:44 +0800 Subject: [PATCH 2689/2794] Update MyReadingManga.lua The site is using lazy load now, so just updating the xpath so downloads work again. --- lua/modules/MyReadingManga.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/MyReadingManga.lua b/lua/modules/MyReadingManga.lua index 70c9d7d50..e215ce6ed 100644 --- a/lua/modules/MyReadingManga.lua +++ b/lua/modules/MyReadingManga.lua @@ -37,9 +37,9 @@ function getpagenumber() task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl, url)) then local x=TXQuery.Create(http.Document) - x.xpathstringall('//*[contains(@class,"entry-content")]//div//img/@src', task.pagelinks) + x.xpathstringall('//*[contains(@class,"entry-content")]//img/@data-lazy-src', task.pagelinks) if task.pagelinks.count == 0 then - x.xpathstringall('//div[@class="separator" and @style]//img/@src', task.pagelinks) + x.xpathstringall('//div[@class="separator" and @style]//img/@data-lazy-src', task.pagelinks) end else return false From 20b250323e8ea286f8888c846f9630eb365b7e3b Mon Sep 17 00:00:00 2001 From: rs3mk Date: Sun, 18 Nov 2018 23:13:45 -0500 Subject: [PATCH 2690/2794] change domain change domain to https://tmofans.com --- lua/modules/TuMangaOnline.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/TuMangaOnline.lua b/lua/modules/TuMangaOnline.lua index 333e056df..b9488c593 100644 --- a/lua/modules/TuMangaOnline.lua +++ b/lua/modules/TuMangaOnline.lua @@ -77,7 +77,7 @@ end function Init() local m = NewModule() m.website = 'Tumangaonline' - m.rooturl = 'https://tumangaonline.me' + m.rooturl = 'https://tmofans.com' m.category = 'Spanish' m.lastupdated='June 14, 2018' m.maxtasklimit = 1 From f00c6e5d6db93d6eed30270098d2f4180bde9175 Mon Sep 17 00:00:00 2001 From: kevin01523 Date: Thu, 22 Nov 2018 20:41:56 +0800 Subject: [PATCH 2691/2794] Update MangaRock.pas update fix api --- baseunits/modules/MangaRock.pas | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/baseunits/modules/MangaRock.pas b/baseunits/modules/MangaRock.pas index a3249f049..b029afef7 100644 --- a/baseunits/modules/MangaRock.pas +++ b/baseunits/modules/MangaRock.pas @@ -64,7 +64,7 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); mangaId := TrimRightChar(SeparateRight(AURL, 'manga/'), ['/']); - if MangaInfo.FHTTP.GET(ModuleApiUrl + '/query/web400/info?oid=' + mangaId) then + if MangaInfo.FHTTP.GET(ModuleApiUrl + '/query/web401/info?oid=' + mangaId) then begin Result := NO_ERROR; query := TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document); @@ -111,7 +111,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; DownloadThread.Task.Container.PageLinks.Clear; DownloadThread.Task.Container.PageNumber := 0; chapterId := TrimLeftChar(AURL, ['/']); - if DownloadThread.FHTTP.GET(ModuleApiUrl + '/query/web400/pages?oid=' + chapterId) then + if DownloadThread.FHTTP.GET(ModuleApiUrl + '/query/web401/pages?oid=' + chapterId) then begin Result := True; XPathStringAll('json(*).data()', @@ -189,7 +189,7 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); MangaInfo.FHTTP.MimeType := 'application/json'; - if MangaInfo.FHTTP.POST(ModuleApiUrl + '/query/web400/mrs_filter', DirRequest) then + if MangaInfo.FHTTP.POST(ModuleApiUrl + '/query/web401/mrs_filter', DirRequest) then begin Result := NO_ERROR; mangaList.Clear; From ad1193d6ae9fbbd44d6b6224752aadb7c24dc749 Mon Sep 17 00:00:00 2001 From: Ghost Writer TNCS Date: Sun, 2 Dec 2018 09:00:37 +0100 Subject: [PATCH 2692/2794] Added MangaEden.lua --- lua/modules/MangaEden.lua | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 lua/modules/MangaEden.lua diff --git a/lua/modules/MangaEden.lua b/lua/modules/MangaEden.lua new file mode 100644 index 000000000..f918b1690 --- /dev/null +++ b/lua/modules/MangaEden.lua @@ -0,0 +1,97 @@ +local diren = '/en/en-directory/' +local dirit = '/en/it-directory/' + +function GetInfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//*[@class="manga-title"]') + end + mangainfo.coverlink='http:'..MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="mangaImage2"]//img/@src')) + mangainfo.authors=x.xpathstringall('//*[@class="rightBox"]/a[contains(@href,"/?author=")]') + mangainfo.artists=x.xpathstringall('//*[@class="rightBox"]/a[contains(@href,"/?artist=")]') + mangainfo.genres=x.xpathstringall('//*[@class="rightBox"]/a[contains(@href,"/?categories")]') + mangainfo.summary=x.xpathstring('//*[@id="mangaDescription"]') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//*[@class="rightBox"]'), 'Ongoing', 'Completed') + x.xpathhrefall('//table//tr/td/a[@class="chapterLink"]', mangainfo.chapterlinks, mangainfo.chapternames) + for i = 0, mangainfo.chapternames.count-1 do + mangainfo.chapternames[i] = mangainfo.chapternames[i]:gsub("Chapter", "") + end + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + if http.get(MaybeFillHost(module.rooturl,url)) then + x=TXQuery.Create(http.Document) + task.pagenumber=tonumber(x.xpathstring('count(//select[@id="pageSelect"]/option)')) + return true + else + return false + end +end + +function GetImageURL() + if http.get(MaybeFillHost(module.rooturl,url):gsub("(.*)/1.*$","%1")..'/'..tostring(workid+1)) then + x=TXQuery.Create(http.Document) + task.pagelinks[workid]='https:'..x.xpathstring('//img[@id="mainImg"]/@src') + return true + else + return false + end +end + +function GetDirUrl(website) + if module.website == 'MangaEden_IT' or module.website == 'PervEden_IT' then + return dirit + else + return diren + end +end + +function GetDirectoryPageNumber() + if http.GET(AppendURLDelim(module.RootURL)..GetDirUrl(module.website)) then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//*[@class="pagination pagination_bottom"]/a[last()-1]')) + if page == nil then + page = 1 + end + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..GetDirUrl(module.website).."?page="..IncStr(url)) then + x=TXQuery.Create(http.Document) + x.xpathhrefall('//table[@id="mangaList"]//tr/td[1]/a', links, names) + return no_error + else + return net_problem + end +end + +function InitModule(website, rooturl, category) + m=NewModule() + m.category=category + m.website=website + m.rooturl=rooturl + m.lastupdated='November 25, 2018' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetimageurl='GetImageURL' + m.OnGetDirectoryPageNumber = 'GetDirectoryPageNumber' + m.ongetnameandlink='GetNameAndLink' +end + +function Init() + InitModule('MangaEden', 'http://www.mangaeden.com', 'English') + InitModule('MangaEden_IT', 'http://www.mangaeden.com', 'Italian') + InitModule('PervEden', 'http://www.perveden.com', 'H-Sites') + InitModule('PervEden_IT', 'http://www.perveden.com', 'H-Sites') +end From 31c49dd788c35e7d1f8a179a81f35215d6113b79 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 4 Dec 2018 09:45:37 +0300 Subject: [PATCH 2693/2794] MangaEden, fix --- lua/modules/MangaEden.lua | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lua/modules/MangaEden.lua b/lua/modules/MangaEden.lua index f918b1690..f8e52eb04 100644 --- a/lua/modules/MangaEden.lua +++ b/lua/modules/MangaEden.lua @@ -1,5 +1,5 @@ -local diren = '/en/en-directory/' -local dirit = '/en/it-directory/' +local diren = '/en/en-directory/?order=-0' +local dirit = '/en/it-directory/?order=-0' function GetInfo() mangainfo.url=MaybeFillHost(module.RootURL, url) @@ -8,7 +8,11 @@ function GetInfo() if mangainfo.title == '' then mangainfo.title = x.xpathstring('//*[@class="manga-title"]') end - mangainfo.coverlink='http:'..MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="mangaImage2"]//img/@src')) + local coverlink = x.xpathstring('//div[@class="mangaImage2"]//img/@src') + if coverlink ~= '' then + if coverlink:find('^//') then coverlink = 'https:' .. coverlink; end + mangainfo.coverlink=MaybeFillHost(module.RootURL, coverlink) + end mangainfo.authors=x.xpathstringall('//*[@class="rightBox"]/a[contains(@href,"/?author=")]') mangainfo.artists=x.xpathstringall('//*[@class="rightBox"]/a[contains(@href,"/?artist=")]') mangainfo.genres=x.xpathstringall('//*[@class="rightBox"]/a[contains(@href,"/?categories")]') @@ -16,7 +20,7 @@ function GetInfo() mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//*[@class="rightBox"]'), 'Ongoing', 'Completed') x.xpathhrefall('//table//tr/td/a[@class="chapterLink"]', mangainfo.chapterlinks, mangainfo.chapternames) for i = 0, mangainfo.chapternames.count-1 do - mangainfo.chapternames[i] = mangainfo.chapternames[i]:gsub("Chapter", "") + mangainfo.chapternames[i] = mangainfo.chapternames[i]:gsub("Chapter", " ") end InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error @@ -28,17 +32,15 @@ end function GetPageNumber() if http.get(MaybeFillHost(module.rooturl,url)) then x=TXQuery.Create(http.Document) - task.pagenumber=tonumber(x.xpathstring('count(//select[@id="pageSelect"]/option)')) - return true - else - return false - end -end - -function GetImageURL() - if http.get(MaybeFillHost(module.rooturl,url):gsub("(.*)/1.*$","%1")..'/'..tostring(workid+1)) then - x=TXQuery.Create(http.Document) - task.pagelinks[workid]='https:'..x.xpathstring('//img[@id="mainImg"]/@src') + local s = x.xpathstring('//script[contains(., "var pages")]') + s = GetBetween('=', ';', s) + x.parsehtml(s) + x.xpathstringall('json(*)().fs', task.PageLinks) + for i = 0, task.PageLinks.count-1 do + if string.find(task.PageLinks[i], '^//') then + task.PageLinks[i] = 'https:' .. task.PageLinks[i] + end; + end return true else return false @@ -84,7 +86,6 @@ function InitModule(website, rooturl, category) m.lastupdated='November 25, 2018' m.ongetinfo='GetInfo' m.ongetpagenumber='GetPageNumber' - m.ongetimageurl='GetImageURL' m.OnGetDirectoryPageNumber = 'GetDirectoryPageNumber' m.ongetnameandlink='GetNameAndLink' end From 056ddcd71709e30ee9c687a99429279f2e4f3159 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 23 Nov 2018 09:04:36 +0300 Subject: [PATCH 2694/2794] fix ReplaceRegExpr args --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index cc6c492cf..a2ba353c4 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -2275,7 +2275,7 @@ procedure TMainForm.btDownloadClick(Sender: TObject); '', OptionChangeUnicodeCharacter, OptionChangeUnicodeCharacterStr); - s:=ReplaceRegExpr('\.*$', s, ''); + s:=ReplaceRegExpr('\.*$', s, '', False); c:=1; p:=links.Count; r:=0; From 9d53e86248ee5eebac2c149d9bdb06b83012dd32 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 23 Nov 2018 08:54:28 +0300 Subject: [PATCH 2695/2794] register HTMLEncode to lua --- baseunits/lua/LuaBaseUnit.pas | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index cf716f626..2d336c3e0 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -12,7 +12,7 @@ procedure luaBaseUnitRegister(L: Plua_State); implementation uses - LuaUtils, MultiLog; + LuaUtils, MultiLog, htmlelements; function lua_pos(L: Plua_State): Integer; cdecl; begin @@ -90,6 +90,12 @@ function lua_htmldecode(L: Plua_State): Integer; cdecl; Result := 1; end; +function lua_htmlencode(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, EscapeHTML(lua_tostring(L, 1))); + Result := 1; +end; + function lua_urldecode(L: Plua_State): Integer; cdecl; begin lua_pushstring(L, URLDecode(lua_tostring(L, 1))); @@ -146,6 +152,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'RemoveURLDelimLeft', @lua_removeurldelimleft); luaPushFunctionGlobal(L, 'RegExprGetMatch', @lua_regexprgetmatch); luaPushFunctionGlobal(L, 'HTMLDecode', @lua_htmldecode); + luaPushFunctionGlobal(L, 'HTMLEncode', @lua_htmlencode); luaPushFunctionGlobal(L, 'URLDecode', @lua_urldecode); luaPushFunctionGlobal(L, 'IncStr', @lua_incstr); luaPushFunctionGlobal(L, 'StreamToString', @lua_streamtostring); From 0a67c4900993f924ca0470cc4ccbb0b55b02596c Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 4 Dec 2018 09:47:20 +0300 Subject: [PATCH 2696/2794] update internettools --- 3rd/internettools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd/internettools b/3rd/internettools index c9c5cc3a8..4f7490dd0 160000 --- a/3rd/internettools +++ b/3rd/internettools @@ -1 +1 @@ -Subproject commit c9c5cc3a87271180d4fb5bb0b17040763d2cfe06 +Subproject commit 4f7490dd05ed6f2eeffa157f7921f46ae835ce53 From 08690ad4f5a841eba773bcde375a8ca7f58fd047 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 2 Dec 2018 12:59:56 +0300 Subject: [PATCH 2697/2794] remove BESEN and add duktape --- .gitmodules | 5 - 3rd/BESEN | 1 - 3rd/BESENPkg.lpk | 428 -------- 3rd/BESENPkg.pas | 44 - README.md | 3 +- baseunits/Duktape.Api.pas | 1745 ++++++++++++++++++++++++++++++ baseunits/JSUtils.pas | 35 + baseunits/modules/Cloudflare.pas | 13 +- mangadownloader/md.lpi | 8 +- 9 files changed, 1785 insertions(+), 497 deletions(-) delete mode 160000 3rd/BESEN delete mode 100644 3rd/BESENPkg.lpk delete mode 100644 3rd/BESENPkg.pas create mode 100644 baseunits/Duktape.Api.pas create mode 100644 baseunits/JSUtils.pas diff --git a/.gitmodules b/.gitmodules index ab2cc44b0..0876d0aa3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,3 @@ -[submodule "3rd/BESEN"] - path = 3rd/BESEN - url = https://github.com/BeRo1985/besen.git - ignore = dirty - shallow = true [submodule "3rd/internettools"] path = 3rd/internettools url = https://github.com/benibela/internettools.git diff --git a/3rd/BESEN b/3rd/BESEN deleted file mode 160000 index 4d55f34fb..000000000 --- a/3rd/BESEN +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4d55f34fb3b0e9aa7e18ca0b18dd40d813d4d23c diff --git a/3rd/BESENPkg.lpk b/3rd/BESENPkg.lpk deleted file mode 100644 index 1921be4fd..000000000 --- a/3rd/BESENPkg.lpk +++ /dev/null @@ -1,428 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/3rd/BESENPkg.pas b/3rd/BESENPkg.pas deleted file mode 100644 index f96093a53..000000000 --- a/3rd/BESENPkg.pas +++ /dev/null @@ -1,44 +0,0 @@ -{ This file was automatically created by Lazarus. Do not edit! - This source is only used to compile and install the package. - } - -unit BESENPkg; - -interface - -uses - BESEN, BESENArrayUtils, BESENASTNodes, BESENBaseObject, BESENCharset, - BESENCode, BESENCodeContext, BESENCodeGeneratorContext, BESENCodeJIT, - BESENCodeJITx64, BESENCodeJITx86, BESENCodeSnapshot, BESENCollector, - BESENCollectorObject, BESENCompiler, BESENConstants, BESENContext, - BESENDateUtils, BESENDeclarativeEnvironmentRecord, BESENDecompiler, - BESENDoubleList, BESENEnvironmentRecord, BESENErrors, BESENEvalCache, - BESENEvalCacheItem, BESENGarbageCollector, BESENGlobals, BESENHashMap, - BESENHashUtils, BESENInt64SelfBalancedTree, BESENIntegerList, - BESENKeyIDManager, BESENLexer, BESENLexicalEnvironment, BESENLocale, - BESENNativeCodeMemoryManager, BESENNativeObject, BESENNumberUtils, - BESENObject, BESENObjectArgGetterFunction, BESENObjectArgSetterFunction, - BESENObjectArray, BESENObjectArrayConstructor, BESENObjectArrayPrototype, - BESENObjectBindingFunction, BESENObjectBoolean, - BESENObjectBooleanConstructor, BESENObjectBooleanPrototype, - BESENObjectConsole, BESENObjectConstructor, BESENObjectDate, - BESENObjectDateConstructor, BESENObjectDatePrototype, - BESENObjectDeclaredFunction, BESENObjectEnvironmentRecord, BESENObjectError, - BESENObjectErrorConstructor, BESENObjectErrorPrototype, BESENObjectFunction, - BESENObjectFunctionArguments, BESENObjectFunctionConstructor, - BESENObjectFunctionPrototype, BESENObjectGlobal, BESENObjectJSON, - BESENObjectMath, BESENObjectNativeFunction, BESENObjectNumber, - BESENObjectNumberConstructor, BESENObjectNumberPrototype, - BESENObjectPropertyDescriptor, BESENObjectPrototype, BESENObjectRegExp, - BESENObjectRegExpConstructor, BESENObjectRegExpPrototype, BESENObjectString, - BESENObjectStringConstructor, BESENObjectStringPrototype, - BESENObjectThrowTypeErrorFunction, BESENOpcodes, BESENParser, - BESENPointerList, BESENPointerSelfBalancedTree, BESENRandomGenerator, - BESENRegExp, BESENRegExpCache, BESENScope, BESENSelfBalancedTree, - BESENStringList, BESENStringTree, BESENStringUtils, BESENTypes, - BESENUnicodeTables, BESENUtils, BESENValue, BESENValueContainer, - BESENVersionConstants; - -implementation - -end. diff --git a/README.md b/README.md index 3cb667e85..c7b8350df 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,13 @@ In order to build FMD from the source code, you must install the latest version - [Virtual TreeView](https://github.com/blikblum/VirtualTreeView-Lazarus/tree/lazarus-v4) (and `lclextensions` from the Releases page) - [Synapse](https://sourceforge.net/p/synalist/code/HEAD/tree/trunk/) (at least revision `r160`) - [InternetTools](https://github.com/benibela/internettools) - - [BESEN](https://github.com/BeRo1985/besen) - [MultiLog](https://github.com/blikblum/multilog) - [DCPCypt](https://sourceforge.net/projects/lazarus-ccr/) After everything is installed, open the file `md.lpi` by using Lazarus IDE. Make sure to add `ssl_openssl` to uses list of the `laz_synapse` package. Then select `Run -> Build` to build the source code. If everything is ok, the binary file should be in `FMD_source_code_folder/bin`. -If InternetTools or BESEN fail to compile (incompatible PPU), make sure to compile them individually first. +If InternetTools fail to compile (incompatible PPU), make sure to compile them individually first. ## Localization diff --git a/baseunits/Duktape.Api.pas b/baseunits/Duktape.Api.pas new file mode 100644 index 000000000..67a1cc3a9 --- /dev/null +++ b/baseunits/Duktape.Api.pas @@ -0,0 +1,1745 @@ +{ + +https://github.com/grijjy/DelphiDuktape + +DelphiDuktape is licensed under the Simplified BSD License. + +------------------------------------------------------------------------------- + +Copyright (c) 2018 by Grijjy, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +} + +unit Duktape.Api; + +interface + +const + {$IF Defined(WIN32)} + LIB_DUKTAPE = 'duktape32.dll'; + PREFIX = ''; + {$ELSEIF Defined(WIN64)} + LIB_DUKTAPE = 'duktape64.dll'; + PREFIX = ''; + {$ELSEIF Defined(ANDROID)} + LIB_DUKTAPE = 'libduktape_android.a'; + PREFIX = ''; + {$ELSEIF Defined(IOS)} + LIB_DUKTAPE = 'libduktape_ios.a'; + PREFIX = ''; + {$ELSEIF Defined(MACOS)} + LIB_DUKTAPE = 'libduktape_osx32.dylib'; + PREFIX = '_'; + {$ELSEIF Defined(LINUX)} + LIB_DUKTAPE = 'libduktape_linux64.so'; + PREFIX = ''; + {$ELSE} + {$MESSAGE Error 'Unsupported platform'} + {$ENDIF} + +(* + * duk_config.h configuration header generated by genconfig.py. + * + * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0). + * Git branch: master + * + * Supported platforms: + * - Mac OSX, iPhone, Darwin + * - Orbis + * - OpenBSD + * - Generic BSD + * - Atari ST TOS + * - AmigaOS + * - Durango (XboxOne) + * - Windows + * - Flashplayer (Crossbridge) + * - QNX + * - TI-Nspire + * - Emscripten + * - Linux + * - Solaris + * - AIX + * - HPUX + * - Generic POSIX + * - Cygwin + * - Generic UNIX + * - Generic fallback + * + * Supported architectures: + * - x86 + * - x64 + * - x32 + * - ARM 32-bit + * - ARM 64-bit + * - MIPS 32-bit + * - MIPS 64-bit + * - PowerPC 32-bit + * - PowerPC 64-bit + * - SPARC 32-bit + * - SPARC 64-bit + * - SuperH + * - Motorola 68k + * - Emscripten + * - Generic + * + * Supported compilers: + * - Clang + * - GCC + * - MSVC + * - Emscripten + * - TinyC + * - VBCC + * - Bruce's C compiler + * - Generic + * + *) + +type MarshaledAString = ^AnsiChar; + +type + TDukUInt8 = UInt8; + TDukInt8 = Int8; + TDukUInt16 = UInt16; + TDukInt16 = Int16; + TDukUInt32 = UInt32; + TDukInt32 = Int32; + TDukUInt64 = UInt32; + TDukInt64 = Int32; + TDukUInt = Cardinal; + TDukInt = Integer; + TDukSize = NativeUInt; + TDukPtrDiff = NativeInt; + TDukSmallUInt = Cardinal; + TDukSmallInt = Integer; + TDukBool = TDukSmallUInt; + TDukIdx = TDukInt; + TDukUIdx = TDukUInt; + TDukUArrIdx = TDukUInt; + TDukRet = TDukSmallInt; + TDukErrCode = TDukInt; + TDukCodepoint = TDukInt; + TDukUCodepoint = TDukUInt; + TDukFloat = Single; + TDukDouble = Double; + +type + PDukUInt8 = ^TDukUInt8; + PDukInt8 = ^TDukInt8; + PDukUInt16 = ^TDukUInt16; + PDukInt16 = ^TDukInt16; + PDukUInt32 = ^TDukUInt32; + PDukInt32 = ^TDukInt32; + PDukUInt64 = ^TDukUInt64; + PDukInt64 = ^TDukInt64; + PDukUInt = ^TDukUInt; + PDukInt = ^TDukInt; + PDukSize = ^TDukSize; + PDukPtrDiff = ^TDukPtrDiff; + PDukSmallUInt = ^TDukSmallUInt; + PDukSmallInt = ^TDukSmallInt; + PDukBool = ^TDukBool; + PDukIdx = ^TDukIdx; + PDukUIdx = ^TDukUIdx; + PDukUArrIdx = ^TDukUArrIdx; + PDukRet = ^TDukRet; + PDukErrCode = ^TDukErrCode; + PDukCodepoint = ^TDukCodepoint; + PDukUCodepoint = ^TDukUCodepoint; + PDukFloat = ^TDukFloat; + PDukDouble = ^TDukDouble; + +type + TDukUIntLeast8 = TDukUInt8; + TDukIntLeast8 = TDukInt8; + TDukUIntLeast16 = TDukUInt16; + TDukIntLeast16 = TDukInt16; + TDukUIntLeast32 = TDukUInt32; + TDukIntLeast32 = TDukInt32; + TDukUIntLeast64 = TDukUInt64; + TDukIntLeast64 = TDukInt64; + +type + TDukUIntFast8 = TDukUInt8; + TDukIntFast8 = TDukInt8; + TDukUIntFast16 = TDukUInt16; + TDukIntFast16 = TDukInt16; + TDukUIntFast32 = TDukUInt32; + TDukIntFast32 = TDukInt32; + TDukUIntFast64 = TDukUInt64; + TDukIntFast64 = TDukInt64; + TDukUIntFast = TDukUIntFast32; + TDukIntFast = TDukIntFast32; + TDukSmallUIntFast = TDukUIntFast16; + TDukSmallIntFast = TDukIntFast16; + +type + TDukUIntMax = TDukUInt64; + TDukIntMax = TDukInt64; + +const + DUK_UINT8_MIN = $00; + DUK_UINT8_MAX = $FF; + DUK_INT8_MIN = -$80; + DUK_INT8_MAX = $7F; + DUK_UINT_LEAST8_MIN = $00; + DUK_UINT_LEAST8_MAX = $FF; + DUK_INT_LEAST8_MIN = -$80; + DUK_INT_LEAST8_MAX = $7F; + DUK_UINT_FAST8_MIN = $00; + DUK_UINT_FAST8_MAX = $FF; + DUK_INT_FAST8_MIN = -$80; + DUK_INT_FAST8_MAX = $7F; + DUK_UINT16_MIN = $0000; + DUK_UINT16_MAX = $FFFF; + DUK_INT16_MIN = -$8000; + DUK_INT16_MAX = $7FFF; + DUK_UINT_LEAST16_MIN = $0000; + DUK_UINT_LEAST16_MAX = $FFFF; + DUK_INT_LEAST16_MIN = -$8000; + DUK_INT_LEAST16_MAX = $7FFF; + DUK_UINT_FAST16_MIN = $0000; + DUK_UINT_FAST16_MAX = $FFFF; + DUK_INT_FAST16_MIN = -$8000; + DUK_INT_FAST16_MAX = $7FFF; + DUK_UINT32_MIN = $00000000; + DUK_UINT32_MAX = $FFFFFFFF; + DUK_INT32_MIN = -$80000000; + DUK_INT32_MAX = $7FFFFFFF; + DUK_UINT_LEAST32_MIN = $00000000; + DUK_UINT_LEAST32_MAX = $FFFFFFFF; + DUK_INT_LEAST32_MIN = -$80000000; + DUK_INT_LEAST32_MAX = $7FFFFFFF; + DUK_UINT_FAST32_MIN = $00000000; + DUK_UINT_FAST32_MAX = $FFFFFFFF; + DUK_INT_FAST32_MIN = -$80000000; + DUK_INT_FAST32_MAX = $7FFFFFFF; + DUK_UINT64_MIN = $0000000000000000; + DUK_UINT64_MAX = $FFFFFFFFFFFFFFFF; + DUK_INT64_MIN = -$8000000000000000; + DUK_INT64_MAX = $7FFFFFFFFFFFFFFF; + DUK_UINT_LEAST64_MIN = $0000000000000000; + DUK_UINT_LEAST64_MAX = $FFFFFFFFFFFFFFFF; + DUK_INT_LEAST64_MIN = -$8000000000000000; + DUK_INT_LEAST64_MAX = $7FFFFFFFFFFFFFFF; + DUK_UINT_FAST64_MIN = $0000000000000000; + DUK_UINT_FAST64_MAX = $FFFFFFFFFFFFFFFF; + DUK_INT_FAST64_MIN = -$8000000000000000; + DUK_INT_FAST64_MAX = $7FFFFFFFFFFFFFFF; + +const + DUK_UINTMAX_MIN = DUK_UINT64_MIN; + DUK_UINTMAX_MAX = DUK_UINT64_MAX; + DUK_INTMAX_MIN = DUK_INT64_MIN; + DUK_INTMAX_MAX = DUK_INT64_MAX; + +const + DUK_UINT_MIN = DUK_UINT32_MIN; + DUK_UINT_MAX = DUK_UINT32_MAX; + DUK_INT_MIN = DUK_INT32_MIN; + DUK_INT_MAX = DUK_INT32_MAX; + DUK_UINT_FAST_MIN = DUK_UINT_FAST32_MIN; + DUK_UINT_FAST_MAX = DUK_UINT_FAST32_MAX; + DUK_INT_FAST_MIN = DUK_INT_FAST32_MIN; + DUK_INT_FAST_MAX = DUK_INT_FAST32_MAX; + DUK_SMALL_UINT_MIN = DUK_UINT32_MIN; + DUK_SMALL_UINT_MAX = DUK_UINT32_MAX; + DUK_SMALL_INT_MIN = DUK_INT32_MIN; + DUK_SMALL_INT_MAX = DUK_INT32_MAX; + DUK_SMALL_UINT_FAST_MIN = DUK_UINT16_MIN; + DUK_SMALL_UINT_FAST_MAX = DUK_UINT16_MAX; + DUK_SMALL_INT_FAST_MIN = DUK_INT16_MIN; + DUK_SMALL_INT_FAST_MAX = DUK_INT16_MAX; + DUK_BOOL_MIN = DUK_SMALL_INT_MIN; + DUK_BOOL_MAX = DUK_SMALL_INT_MAX; + DUK_IDX_MIN = DUK_INT_MIN; + DUK_IDX_MAX = DUK_INT_MAX; + DUK_UIDX_MIN = DUK_UINT_MIN; + DUK_UIDX_MAX = DUK_UINT_MAX; + DUK_UARRIDX_MIN = DUK_UINT_MIN; + DUK_UARRIDX_MAX = DUK_UINT_MAX; + DUK_ERRCODE_MIN = DUK_INT_MIN; + DUK_ERRCODE_MAX = DUK_INT_MAX; + DUK_CODEPOINT_MIN = DUK_INT_MIN; + DUK_CODEPOINT_MAX = DUK_INT_MAX; + DUK_UCODEPOINT_MIN = DUK_UINT_MIN; + DUK_UCODEPOINT_MAX = DUK_UINT_MAX; + DUK_RET_MIN = DUK_SMALL_INT_MIN; + DUK_RET_MAX = DUK_SMALL_INT_MAX; + +(* + * Duktape public API for Duktape 2.1.0. + * + * See the API reference for documentation on call semantics. The exposed, + * supported API is between the "BEGIN PUBLIC API" and "END PUBLIC API" + * comments. Other parts of the header are Duktape internal and related to + * e.g. platform/compiler/feature detection. + * + * Git commit a459cf3c9bd1779fc01b435d69302b742675a08f (v2.2.0). + * Git branch master. + * + * See Duktape AUTHORS.rst and LICENSE.txt for copyright and + * licensing information. + *) + +(* + * =============== + * Duktape license + * =============== + * + * (http://opensource.org/licenses/MIT) + * + * Copyright (c) 2013-2017 by Duktape authors (see AUTHORS.rst) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + *) + +(* + * =============== + * Duktape authors + * =============== + * + * Copyright + * ========= + * + * Duktape copyrights are held by its authors. Each author has a copyright + * to their contribution, and agrees to irrevocably license the contribution + * under the Duktape ``LICENSE.txt``. + * + * Authors + * ======= + * + * Please include an e-mail address, a link to your GitHub profile, or something + * similar to allow your contribution to be identified accurately. + * + * The following people have contributed code, website contents, or Wiki contents, + * and agreed to irrevocably license their contributions under the Duktape + * ``LICENSE.txt`` (in order of appearance): + * + * * Sami Vaarala + * * Niki Dobrev + * * Andreas \u00d6man + * * L\u00e1szl\u00f3 Lang\u00f3 + * * Legimet + * * Karl Skomski + * * Bruce Pascoe + * * Ren\u00e9 Hollander + * * Julien Hamaide (https://github.com/crazyjul) + * * Sebastian G\u00f6tte (https://github.com/jaseg) + * * Tomasz Magulski (https://github.com/magul) + * * \D. Bohdan (https://github.com/dbohdan) + * * Ond\u0159ej Jirman (https://github.com/megous) + * * Sa\u00fal Ibarra Corretg\u00e9 + * * Jeremy HU + * * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr) + * * Harold Brenes (https://github.com/harold-b) + * * Oliver Crow (https://github.com/ocrow) + * * Jakub Ch\u0142api\u0144ski (https://github.com/jchlapinski) + * * Brett Vickers (https://github.com/beevik) + * * Dominik Okwieka (https://github.com/okitec) + * * Remko Tron\u00e7on (https://el-tramo.be) + * * Romero Malaquias (rbsm@ic.ufal.br) + * * Michael Drake + * * Steven Don (https://github.com/shdon) + * * Simon Stone (https://github.com/sstone1) + * * \J. McC. (https://github.com/jmhmccr) + * + * Other contributions + * =================== + * + * The following people have contributed something other than code (e.g. reported + * bugs, provided ideas, etc; roughly in order of appearance): + * + * * Greg Burns + * * Anthony Rabine + * * Carlos Costa + * * Aur\u00e9lien Bouilland + * * Preet Desai (Pris Matic) + * * judofyr (http://www.reddit.com/user/judofyr) + * * Jason Woofenden + * * Micha\u0142 Przyby\u015b + * * Anthony Howe + * * Conrad Pankoff + * * Jim Schimpf + * * Rajaran Gaunker (https://github.com/zimbabao) + * * Andreas \u00d6man + * * Doug Sanden + * * Josh Engebretson (https://github.com/JoshEngebretson) + * * Remo Eichenberger (https://github.com/remoe) + * * Mamod Mehyar (https://github.com/mamod) + * * David Demelier (https://github.com/markand) + * * Tim Caswell (https://github.com/creationix) + * * Mitchell Blank Jr (https://github.com/mitchblank) + * * https://github.com/yushli + * * Seo Sanghyeon (https://github.com/sanxiyn) + * * Han ChoongWoo (https://github.com/tunz) + * * Joshua Peek (https://github.com/josh) + * * Bruce E. Pascoe (https://github.com/fatcerberus) + * * https://github.com/Kelledin + * * https://github.com/sstruchtrup + * * Michael Drake (https://github.com/tlsa) + * * https://github.com/chris-y + * * Laurent Zubiaur (https://github.com/lzubiaur) + * * Neil Kolban (https://github.com/nkolban) + * + * If you are accidentally missing from this list, send me an e-mail + * (``sami.vaarala@iki.fi``) and I'll fix the omission. + *) + +(* + * BEGIN PUBLIC API + *) + +(* + * Version and Git commit identification + *) + +(* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code + * to #if (DUK_VERSION >= NNN) against Duktape API version. The same value + * is also available to Ecmascript code in Duktape.version. Unofficial + * development snapshots have 99 for patch level (e.g. 0.10.99 would be a + * development version after 0.10.0 but before the next official release). + *) +const + DUK_VERSION = 20200; + +(* Git commit, describe, and branch for Duktape build. Useful for + * non-official snapshot builds so that application code can easily log + * which Duktape snapshot was used. Not available in the Ecmascript + * environment. + *) +const + DUK_GIT_COMMIT = 'a459cf3c9bd1779fc01b435d69302b742675a08f'; + DUK_GIT_DESCRIBE = 'v2.2.0'; + DUK_GIT_BRANCH = 'master'; + +(* + * Public API specific typedefs + * + * Many types are wrapped by Duktape for portability to rare platforms + * where e.g. 'int' is a 16-bit type. See practical typing discussion + * in Duktape web documentation. + *) + +type + PDukContext = Pointer; + +type + TDukAllocFunction = function(udata: Pointer; size: TDukSize): Pointer; cdecl; + TDukReallocFunction = function(udata: Pointer; ptr: Pointer; size: TDukSize): Pointer; cdecl; + TDukFreeFunction = procedure(udata: Pointer; ptr: Pointer); cdecl; + TDukCFunction = function(ctx: PDukContext): TDukRet; cdecl; + TDukFatalFunction = procedure(udata: Pointer; const msg: MarshaledAString); cdecl; + TDukDecodeCharFunction = procedure(udata: Pointer; codepoint: TDukCodepoint); cdecl; + TDukMapCharFunction = function(udata: Pointer; codepoint: TDukCodepoint): TDukCodepoint; cdecl; + TDukSafeCallFunction = function(ctx: PDukContext; udata: Pointer): TDukRet; cdecl; + TDukDebugReadFunction = function(udata: Pointer; buffer: MarshaledAString; length: TDukSize): TDukSize; cdecl; + TDukDebugWriteFunction = function(udata: Pointer; const buffer: MarshaledAString; length: TDukSize): TDukSize; cdecl; + TDukDebugPeekFunction = function(udata: Pointer): TDukSize; cdecl; + TDukDebugReadFlushFunction = procedure(udata: Pointer); cdecl; + TDukDebugWriteFlushFunction = procedure(udata: Pointer); cdecl; + TDukDebugRequestFunction = function(ctx: PDukContext; udata: Pointer; nvalues: TDukIdx): TDukIdx; cdecl; + TDukDebugDetachedFunction = procedure(ctx: PDukContext; udata: Pointer); cdecl; + +type + PDukThreadState = ^TDukThreadState; + TDukThreadState = record + { Enough space to hold internal suspend/resume structure. + This is rather awkward and to be fixed when the internal + structure is visible for the public API header. } + Data: array [0..127] of Byte; + end; + +type + PDukMemoryFunctions = ^TDukMemoryFunctions; + TDukMemoryFunctions = record + AllocFunc: TDukAllocFunction; + ReallocFunc: TDukReallocFunction; + FreeFunc: TDukFreeFunction; + UserData: Pointer; + end; + +type + PDukFunctionListEntry = ^TDukFunctionListEntry; + TDukFunctionListEntry = record + Key: MarshaledAString; + Value: TDukCFunction; + NumArgs: TDukIdx; + end; + +type + PDukNumberListEntry = ^TDukNumberListEntry; + TDukNumberListEntry = record + Key: MarshaledAString; + Value: TDukDouble; + end; + +type + PDukTimeComponents = ^TDukTimeComponents; + TDukTimeComponents = record + Year: TDukDouble; + Month: TDukDouble; + Day: TDukDouble; + Hours: TDukDouble; + Minutes: TDukDouble; + Seconds: TDukDouble; + Milliseconds: TDukDouble; + Weekday: TDukDouble; + end; + +(* + * Constants + *) + +(* Duktape debug protocol version used by this build. *) +const + DUK_DEBUG_PROTOCOL_VERSION = 2; + +(* Used to represent invalid index; if caller uses this without checking, + * this index will map to a non-existent stack entry. Also used in some + * API calls as a marker to denote "no value". + *) +const + DUK_INVALID_INDEX = DUK_IDX_MIN; + +(* Indicates that a native function does not have a fixed number of args, + * and the argument stack should not be capped/extended at all. + *) +const + DUK_VARARGS = -1; + +(* Number of value stack entries (in addition to actual call arguments) + * guaranteed to be allocated on entry to a Duktape/C function. + *) +const + DUK_API_ENTRY_STACK = 64; + +(* Value types, used by e.g. duk_get_type() *) +const + DUK_TYPE_MIN = 0; + DUK_TYPE_NONE = 0; (* no value, e.g. invalid index *) + DUK_TYPE_UNDEFINED = 1; (* Ecmascript undefined *) + DUK_TYPE_NULL = 2; (* Ecmascript null *) + DUK_TYPE_BOOLEAN = 3; (* Ecmascript boolean: 0 or 1 *) + DUK_TYPE_NUMBER = 4; (* Ecmascript number: double *) + DUK_TYPE_STRING = 5; (* Ecmascript string: CESU-8 / extended UTF-8 encoded *) + DUK_TYPE_OBJECT = 6; (* Ecmascript object: includes objects, arrays, functions, threads *) + DUK_TYPE_BUFFER = 7; (* fixed or dynamic, garbage collected byte buffer *) + DUK_TYPE_POINTER = 8; (* raw void pointer *) + DUK_TYPE_LIGHTFUNC = 9; (* lightweight function pointer *) + DUK_TYPE_MAX = 9; + +(* Value mask types, used by e.g. duk_get_type_mask() *) +const + DUK_TYPE_MASK_NONE = 1 shl DUK_TYPE_NONE; + DUK_TYPE_MASK_UNDEFINED = 1 shl DUK_TYPE_UNDEFINED; + DUK_TYPE_MASK_NULL = 1 shl DUK_TYPE_NULL; + DUK_TYPE_MASK_BOOLEAN = 1 shl DUK_TYPE_BOOLEAN; + DUK_TYPE_MASK_NUMBER = 1 shl DUK_TYPE_NUMBER; + DUK_TYPE_MASK_STRING = 1 shl DUK_TYPE_STRING; + DUK_TYPE_MASK_OBJECT = 1 shl DUK_TYPE_OBJECT; + DUK_TYPE_MASK_BUFFER = 1 shl DUK_TYPE_BUFFER; + DUK_TYPE_MASK_POINTER = 1 shl DUK_TYPE_POINTER; + DUK_TYPE_MASK_LIGHTFUNC = 1 shl DUK_TYPE_LIGHTFUNC; + DUK_TYPE_MASK_THROW = 1 shl 10; (* internal flag value: throw if mask doesn't match *) + DUK_TYPE_MASK_PROMOTE = 1 shl 11; (* internal flag value: promote to object if mask matches *) + +(* Coercion hints *) +const + DUK_HINT_NONE = 0; (* prefer number, unless input is a Date, in which + * case prefer string (E5 Section 8.12.8) *) + DUK_HINT_STRING = 1; (* prefer string *) + DUK_HINT_NUMBER = 2; (* prefer number *) + +(* Enumeration flags for duk_enum() *) +const + DUK_ENUM_INCLUDE_NONENUMERABLE = 1 shl 0; (* enumerate non-numerable properties in addition to enumerable *) + DUK_ENUM_INCLUDE_HIDDEN = 1 shl 1; (* enumerate hidden symbols too (in Duktape 1.x called internal properties) *) + DUK_ENUM_INCLUDE_SYMBOLS = 1 shl 2; (* enumerate symbols *) + DUK_ENUM_EXCLUDE_STRINGS = 1 shl 3; (* exclude strings *) + DUK_ENUM_OWN_PROPERTIES_ONLY = 1 shl 4; (* don't walk prototype chain, only check own properties *) + DUK_ENUM_ARRAY_INDICES_ONLY = 1 shl 5; (* only enumerate array indices *) + DUK_ENUM_SORT_ARRAY_INDICES = 1 shl 6; (* sort array indices (applied to full enumeration result, including inherited array indices) *) + DUK_ENUM_NO_PROXY_BEHAVIOR = 1 shl 7; (* enumerate a proxy object itself without invoking proxy behavior *) + +(* Compilation flags for duk_compile() and duk_eval() *) +(* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument. + *) +const + DUK_COMPILE_EVAL = 1 shl 3; (* compile eval code (instead of global code) *) + DUK_COMPILE_FUNCTION = 1 shl 4; (* compile function code (instead of global code) *) + DUK_COMPILE_STRICT = 1 shl 5; (* use strict (outer) context for global, eval, or function code *) + DUK_COMPILE_SHEBANG = 1 shl 6; (* allow shebang ('#! ...') comment on first line of source *) + DUK_COMPILE_SAFE = 1 shl 7; (* (internal) catch compilation errors *) + DUK_COMPILE_NORESULT = 1 shl 8; (* (internal) omit eval result *) + DUK_COMPILE_NOSOURCE = 1 shl 9; (* (internal) no source string on stack *) + DUK_COMPILE_STRLEN = 1 shl 10; (* (internal) take strlen() of src_buffer (avoids double evaluation in macro) *) + DUK_COMPILE_NOFILENAME = 1 shl 11; (* (internal) no filename on stack *) + DUK_COMPILE_FUNCEXPR = 1 shl 12; (* (internal) source is a function expression (used for Function constructor) *) + +(* Flags for duk_def_prop() and its variants *) +const + DUK_DEFPROP_WRITABLE = 1 shl 0; (* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) *) + DUK_DEFPROP_ENUMERABLE = 1 shl 1; (* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) *) + DUK_DEFPROP_CONFIGURABLE = 1 shl 2; (* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) *) + DUK_DEFPROP_HAVE_WRITABLE = 1 shl 3; (* set/clear writable *) + DUK_DEFPROP_HAVE_ENUMERABLE = 1 shl 4; (* set/clear enumerable *) + DUK_DEFPROP_HAVE_CONFIGURABLE = 1 shl 5; (* set/clear configurable *) + DUK_DEFPROP_HAVE_VALUE = 1 shl 6; (* set value (given on value stack) *) + DUK_DEFPROP_HAVE_GETTER = 1 shl 7; (* set getter (given on value stack) *) + DUK_DEFPROP_HAVE_SETTER = 1 shl 8; (* set setter (given on value stack) *) + DUK_DEFPROP_FORCE = 1 shl 9; (* force change if possible, may still fail for e.g. virtual properties *) + DUK_DEFPROP_SET_WRITABLE = DUK_DEFPROP_HAVE_WRITABLE or DUK_DEFPROP_WRITABLE; + DUK_DEFPROP_CLEAR_WRITABLE = DUK_DEFPROP_HAVE_WRITABLE; + DUK_DEFPROP_SET_ENUMERABLE = DUK_DEFPROP_HAVE_ENUMERABLE or DUK_DEFPROP_ENUMERABLE; + DUK_DEFPROP_CLEAR_ENUMERABLE = DUK_DEFPROP_HAVE_ENUMERABLE; + DUK_DEFPROP_SET_CONFIGURABLE = DUK_DEFPROP_HAVE_CONFIGURABLE or DUK_DEFPROP_CONFIGURABLE; + DUK_DEFPROP_CLEAR_CONFIGURABLE = DUK_DEFPROP_HAVE_CONFIGURABLE; + DUK_DEFPROP_W = DUK_DEFPROP_WRITABLE; + DUK_DEFPROP_E = DUK_DEFPROP_ENUMERABLE; + DUK_DEFPROP_C = DUK_DEFPROP_CONFIGURABLE; + DUK_DEFPROP_WE = DUK_DEFPROP_WRITABLE or DUK_DEFPROP_ENUMERABLE; + DUK_DEFPROP_WC = DUK_DEFPROP_WRITABLE or DUK_DEFPROP_CONFIGURABLE; + DUK_DEFPROP_WEC = DUK_DEFPROP_WRITABLE or DUK_DEFPROP_ENUMERABLE or DUK_DEFPROP_CONFIGURABLE; + DUK_DEFPROP_HAVE_W = DUK_DEFPROP_HAVE_WRITABLE; + DUK_DEFPROP_HAVE_E = DUK_DEFPROP_HAVE_ENUMERABLE; + DUK_DEFPROP_HAVE_C = DUK_DEFPROP_HAVE_CONFIGURABLE; + DUK_DEFPROP_HAVE_WE = DUK_DEFPROP_HAVE_WRITABLE or DUK_DEFPROP_HAVE_ENUMERABLE; + DUK_DEFPROP_HAVE_WC = DUK_DEFPROP_HAVE_WRITABLE or DUK_DEFPROP_HAVE_CONFIGURABLE; + DUK_DEFPROP_HAVE_WEC = DUK_DEFPROP_HAVE_WRITABLE or DUK_DEFPROP_HAVE_ENUMERABLE or DUK_DEFPROP_HAVE_CONFIGURABLE; + DUK_DEFPROP_SET_W = DUK_DEFPROP_SET_WRITABLE; + DUK_DEFPROP_SET_E = DUK_DEFPROP_SET_ENUMERABLE; + DUK_DEFPROP_SET_C = DUK_DEFPROP_SET_CONFIGURABLE; + DUK_DEFPROP_SET_WE = DUK_DEFPROP_SET_WRITABLE or DUK_DEFPROP_SET_ENUMERABLE; + DUK_DEFPROP_SET_WC = DUK_DEFPROP_SET_WRITABLE or DUK_DEFPROP_SET_CONFIGURABLE; + DUK_DEFPROP_SET_WEC = DUK_DEFPROP_SET_WRITABLE or DUK_DEFPROP_SET_ENUMERABLE or DUK_DEFPROP_SET_CONFIGURABLE; + DUK_DEFPROP_CLEAR_W = DUK_DEFPROP_CLEAR_WRITABLE; + DUK_DEFPROP_CLEAR_E = DUK_DEFPROP_CLEAR_ENUMERABLE; + DUK_DEFPROP_CLEAR_C = DUK_DEFPROP_CLEAR_CONFIGURABLE; + DUK_DEFPROP_CLEAR_WE = DUK_DEFPROP_CLEAR_WRITABLE or DUK_DEFPROP_CLEAR_ENUMERABLE; + DUK_DEFPROP_CLEAR_WC = DUK_DEFPROP_CLEAR_WRITABLE or DUK_DEFPROP_CLEAR_CONFIGURABLE; + DUK_DEFPROP_CLEAR_WEC = DUK_DEFPROP_CLEAR_WRITABLE or DUK_DEFPROP_CLEAR_ENUMERABLE or DUK_DEFPROP_CLEAR_CONFIGURABLE; + DUK_DEFPROP_ATTR_W = DUK_DEFPROP_HAVE_WEC or DUK_DEFPROP_W; + DUK_DEFPROP_ATTR_E = DUK_DEFPROP_HAVE_WEC or DUK_DEFPROP_E; + DUK_DEFPROP_ATTR_C = DUK_DEFPROP_HAVE_WEC or DUK_DEFPROP_C; + DUK_DEFPROP_ATTR_WE = DUK_DEFPROP_HAVE_WEC or DUK_DEFPROP_WE; + DUK_DEFPROP_ATTR_WC = DUK_DEFPROP_HAVE_WEC or DUK_DEFPROP_WC; + DUK_DEFPROP_ATTR_WEC = DUK_DEFPROP_HAVE_WEC or DUK_DEFPROP_WEC; + +(* Flags for duk_push_thread_raw() *) +const + DUK_THREAD_NEW_GLOBAL_ENV = 1 shl 0; (* create a new global environment *) + +(* Flags for duk_gc() *) +const + DUK_GC_COMPACT = 1 shl 0; (* compact heap objects *) + +(* Error codes (must be 8 bits at most, see duk_error.h) *) +const + DUK_ERR_NONE = 0; (* no error (e.g. from duk_get_error_code()) *) + DUK_ERR_ERROR = 1; (* Error *) + DUK_ERR_EVAL_ERROR = 2; (* EvalError *) + DUK_ERR_RANGE_ERROR = 3; (* RangeError *) + DUK_ERR_REFERENCE_ERROR = 4; (* ReferenceError *) + DUK_ERR_SYNTAX_ERROR = 5; (* SyntaxError *) + DUK_ERR_TYPE_ERROR = 6; (* TypeError *) + DUK_ERR_URI_ERROR = 7; (* URIError *) + +(* Return codes for C functions (shortcut for throwing an error) *) +const + DUK_RET_ERROR = -DUK_ERR_ERROR; + DUK_RET_EVAL_ERROR = -DUK_ERR_EVAL_ERROR; + DUK_RET_RANGE_ERROR = -DUK_ERR_RANGE_ERROR; + DUK_RET_REFERENCE_ERROR = -DUK_ERR_REFERENCE_ERROR; + DUK_RET_SYNTAX_ERROR = -DUK_ERR_SYNTAX_ERROR; + DUK_RET_TYPE_ERROR = -DUK_ERR_TYPE_ERROR; + DUK_RET_URI_ERROR = -DUK_ERR_URI_ERROR; + +(* Return codes for protected calls (duk_safe_call(), duk_pcall()) *) +const + DUK_EXEC_SUCCESS = 0; + DUK_EXEC_ERROR = 1; + +(* Debug levels for DUK_USE_DEBUG_WRITE(). *) +const + DUK_LEVEL_DEBUG = 0; + DUK_LEVEL_DDEBUG = 1; + DUK_LEVEL_DDDEBUG = 2; + +(* + * Macros to create Symbols as C statically constructed strings. + * + * Call e.g. as DUK_HIDDEN_SYMBOL("myProperty") <=> ("\xFF" "myProperty"). + * Local symbols have a unique suffix, caller should take care to avoid + * conflicting with the Duktape internal representation by e.g. prepending + * a '!' character: DUK_LOCAL_SYMBOL("myLocal", "!123"). + * + * Note that these can only be used for string constants, not dynamically + * created strings. + *) + +function DUK_HIDDEN_SYMBOL(const AX: UTF8String): UTF8String; inline; +function DUK_GLOBAL_SYMBOL(const AX: UTF8String): UTF8String; inline; +function DUK_LOCAL_SYMBOL(const AX, AUniq: UTF8String): UTF8String; inline; +function DUK_WELLKNOWN_SYMBOL(const AX: UTF8String): UTF8String; inline; + +(* + * Context management + *) + +function duk_create_heap(alloc_func: TDukAllocFunction; realloc_func: TDukReallocFunction; free_func: TDukFreeFunction; heap_udata: Pointer; fatal_handler: TDukFatalFunction): PDukContext; cdecl external LIB_DUKTAPE name PREFIX + 'duk_create_heap'; +procedure duk_destroy_heap(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_destroy_heap'; + +procedure duk_suspend(ctx: PDukContext; state: PDukThreadState); cdecl external LIB_DUKTAPE name PREFIX + 'duk_suspend'; +procedure duk_resume(ctx: PDukContext; const state: PDukThreadState); cdecl external LIB_DUKTAPE name PREFIX + 'duk_resume'; + +function duk_create_heap_default: PDukContext; inline; + +(* + * Memory management + * + * Raw functions have no side effects (cannot trigger GC). + *) + +function duk_alloc_raw(ctx: PDukContext; size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_alloc_raw'; +procedure duk_free_raw(ctx: PDukContext; ptr: Pointer); cdecl external LIB_DUKTAPE name PREFIX + 'duk_free_raw'; +function duk_realloc_raw(ctx: PDukContext; ptr: Pointer; size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_realloc_raw'; +function duk_alloc(ctx: PDukContext; size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_alloc'; +procedure duk_free(ctx: PDukContext; ptr: Pointer); cdecl external LIB_DUKTAPE name PREFIX + 'duk_free'; +function duk_realloc(ctx: PDukContext; ptr: Pointer; size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_realloc'; +procedure duk_get_memory_functions(ctx: PDukContext; out_funcs: PDukMemoryFunctions); cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_memory_functions'; +procedure duk_gc(ctx: PDukContext; flags: TDukUInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_gc'; + +(* + * Error handling + *) + +procedure duk_throw_raw(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_throw_raw'; +procedure duk_throw(ctx: PDukContext); inline; + +procedure duk_fatal_raw(ctx: PDukContext; const err_msg: MarshaledAString); cdecl external LIB_DUKTAPE name PREFIX + 'duk_fatal_raw'; +procedure duk_fatal(ctx: PDukContext; const err_msg: MarshaledAString); inline; + +procedure duk_error_raw(ctx: PDukContext; err_code: TDukErrCode; const filename: MarshaledAString; const line: TDukInt; const fmt: MarshaledAString); varargs; cdecl external LIB_DUKTAPE name PREFIX + 'duk_error_raw'; +procedure duk_error(ctx: PDukContext; err_code: TDukErrCode; const fmt: MarshaledAString); inline; +procedure duk_generic_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +procedure duk_eval_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +procedure duk_range_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +procedure duk_reference_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +procedure duk_syntax_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +procedure duk_type_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +procedure duk_uri_error(ctx: PDukContext; const fmt: MarshaledAString); inline; + +(* + * Other state related functions + *) + +function duk_is_strict_call(ctx: PDukContext): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_strict_call'; +function duk_is_constructor_call(ctx: PDukContext): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_constructor_call'; + +(* + * Stack management + *) + +function duk_normalize_index(ctx: PDukContext; idx: TDukIdx): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_normalize_index'; +function duk_require_normalize_index(ctx: PDukContext; idx: TDukIdx): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_normalize_index'; +function duk_is_valid_index(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_valid_index'; +procedure duk_require_valid_index(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_valid_index'; + +function duk_get_top(ctx: PDukContext): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_top'; +procedure duk_set_top(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_set_top'; +function duk_get_top_index(ctx: PDukContext): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_top_index'; +function duk_require_top_index(ctx: PDukContext): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_top_index'; + +(* Although extra/top could be an unsigned type here, using a signed type + * makes the API more robust to calling code calculation errors or corner + * cases (where caller might occasionally come up with negative values). + * Negative values are treated as zero, which is better than casting them + * to a large unsigned number. (This principle is used elsewhere in the + * API too.) + *) +function duk_check_stack(ctx: PDukContext; extra: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_check_stack'; +procedure duk_require_stack(ctx: PDukContext; extra: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_stack'; +function duk_check_stack_top(ctx: PDukContext; top: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_check_stack_top'; +procedure duk_require_stack_top(ctx: PDukContext; top: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_stack_top'; + +(* + * Stack manipulation (other than push/pop) + *) + +procedure duk_swap(ctx: PDukContext; idx1: TDukIdx; idx2: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_swap'; +procedure duk_swap_top(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_swap_top'; +procedure duk_dup(ctx: PDukContext; from_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_dup'; +procedure duk_dup_top(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_dup_top'; +procedure duk_insert(ctx: PDukContext; to_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_insert'; +procedure duk_replace(ctx: PDukContext; to_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_replace'; +procedure duk_copy(ctx: PDukContext; from_idx: TDukIdx; to_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_copy'; +procedure duk_remove(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_remove'; +procedure duk_xcopymove_raw(to_ctx: PDukContext; from_ctx: PDukContext; count: TDukIdx; is_copy: TDukBool); cdecl external LIB_DUKTAPE name PREFIX + 'duk_xcopymove_raw'; + +procedure duk_xmove_top(to_ctx: PDukContext; from_ctx: PDukContext; count: TDukIdx); inline; +procedure duk_xcopy_top(to_ctx: PDukContext; from_ctx: PDukContext; count: TDukIdx); inline; + +(* + * Push operations + * + * Push functions return the absolute (relative to bottom of frame) + * position of the pushed value for convenience. + * + * Note: duk_dup() is technically a push. + *) + +procedure duk_push_undefined(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_undefined'; +procedure duk_push_null(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_null'; +procedure duk_push_boolean(ctx: PDukContext; val: TDukBool); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_boolean'; +procedure duk_push_true(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_true'; +procedure duk_push_false(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_false'; +procedure duk_push_number(ctx: PDukContext; val: TDukDouble); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_number'; +procedure duk_push_nan(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_nan'; +procedure duk_push_int(ctx: PDukContext; val: TDukInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_int'; +procedure duk_push_uint(ctx: PDukContext; val: TDukUInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_uint'; +function duk_push_string(ctx: PDukContext; const str: MarshaledAString): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_string'; +function duk_push_lstring(ctx: PDukContext; const str: MarshaledAString; len: TDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_lstring'; +procedure duk_push_pointer(ctx: PDukContext; p: Pointer); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_pointer'; +function duk_push_sprintf(ctx: PDukContext; const fmt: MarshaledAString): MarshaledAString; cdecl; varargs external LIB_DUKTAPE name PREFIX + 'duk_push_sprintf'; + +procedure duk_push_this(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_this'; +procedure duk_push_current_function(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_current_function'; +procedure duk_push_current_thread(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_current_thread'; +procedure duk_push_global_object(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_global_object'; +procedure duk_push_heap_stash(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_heap_stash'; +procedure duk_push_global_stash(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_global_stash'; +procedure duk_push_thread_stash(ctx: PDukContext; target_ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_thread_stash'; + +function duk_push_object(ctx: PDukContext): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_object'; +function duk_push_bare_object(ctx: PDukContext): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_bare_object'; +function duk_push_array(ctx: PDukContext): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_array'; +function duk_push_c_function(ctx: PDukContext; func: TDukCFunction; nargs: TDukIdx): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_c_function'; +function duk_push_c_lightfunc(ctx: PDukContext; func: TDukCFunction; nargs: TDukIdx; length: TDukIdx; magic: TDukInt): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_c_lightfunc'; +function duk_push_thread_raw(ctx: PDukContext; flags: TDukUInt): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_thread_raw'; +function duk_push_proxy(ctx: PDukContext; proxy_flags: TDukUInt): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_proxy'; + +function duk_push_thread(ctx: PDukContext): TDukIdx; inline; +function duk_push_thread_new_globalenv(ctx: PDukContext): TDukIdx; inline; + +function duk_push_error_object_raw(ctx: PDukContext; err_code: TDukErrcode; const filename: MarshaledAString; line: TDukInt; const fmt: MarshaledAString): TDukIdx; cdecl; varargs external LIB_DUKTAPE name PREFIX + 'duk_push_error_object_raw'; +function duk_push_error_object(ctx: PDukContext; err_code: TDukErrcode; const fmt: MarshaledAString): TDukIdx; inline; + +const + DUK_BUF_FLAG_DYNAMIC = 1 shl 0; (* internal flag: dynamic buffer *) + DUK_BUF_FLAG_EXTERNAL = 1 shl 1; (* internal flag: external buffer *) + DUK_BUF_FLAG_NOZERO = 1 shl 2; (* internal flag: don't zero allocated buffer *) + +function duk_push_buffer_raw(ctx: PDukContext; size: TDukSize; flags: TDukSmallUInt): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_buffer_raw'; +function duk_push_buffer(ctx: PDukContext; size: TDukSize; dynamic: Boolean): Pointer; inline; +function duk_push_fixed_buffer(ctx: PDukContext; size: TDukSize): Pointer; inline; +function duk_push_dynamic_buffer(ctx: PDukContext; size: TDukSize): Pointer; inline; +function duk_push_external_buffer(ctx: PDukContext): Pointer; inline; + +const + DUK_BUFOBJ_ARRAYBUFFER = 0; + DUK_BUFOBJ_NODEJS_BUFFER = 1; + DUK_BUFOBJ_DATAVIEW = 2; + DUK_BUFOBJ_INT8ARRAY = 3; + DUK_BUFOBJ_UINT8ARRAY = 4; + DUK_BUFOBJ_UINT8CLAMPEDARRAY = 5; + DUK_BUFOBJ_INT16ARRAY = 6; + DUK_BUFOBJ_UINT16ARRAY = 7; + DUK_BUFOBJ_INT32ARRAY = 8; + DUK_BUFOBJ_UINT32ARRAY = 9; + DUK_BUFOBJ_FLOAT32ARRAY = 10; + DUK_BUFOBJ_FLOAT64ARRAY = 11; + +procedure duk_push_buffer_object(ctx: PDukContext; idx_buffer: TDukIdx; byte_offset: TDukSize; byte_length: TDukSize; flags: TDukUInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_buffer_object'; + +function duk_push_heapptr(ctx: PDukContext; ptr: Pointer): TDukIdx; cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_heapptr'; + +(* + * Pop operations + *) + +procedure duk_pop(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_pop'; +procedure duk_pop_n(ctx: PDukContext; count: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_pop_n'; +procedure duk_pop_2(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_pop_2'; +procedure duk_pop_3(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_pop_3'; + +(* + * Type checks + * + * duk_is_none(), which would indicate whether index it outside of stack, + * is not needed; duk_is_valid_index() gives the same information. + *) + +function duk_get_type(ctx: PDukContext; idx: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_type'; +function duk_check_type(ctx: PDukContext; idx: TDukIdx; _type: TDukInt): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_check_type'; +function duk_get_type_mask(ctx: PDukContext; idx: TDukIdx): TDukUInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_type_mask'; +function duk_check_type_mask(ctx: PDukContext; idx: TDukIdx; mask: TDukUInt): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_check_type_mask'; + +function duk_is_undefined(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_undefined'; +function duk_is_null(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_null'; +function duk_is_null_or_undefined(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; + +function duk_is_boolean(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_boolean'; +function duk_is_number(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_number'; +function duk_is_nan(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_nan'; +function duk_is_string(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_string'; +function duk_is_object(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_object'; +function duk_is_buffer(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_buffer'; +function duk_is_buffer_data(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_buffer_data'; +function duk_is_pointer(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_pointer'; +function duk_is_lightfunc(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_lightfunc'; + +function duk_is_symbol(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_symbol'; +function duk_is_array(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_array'; +function duk_is_function(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_function'; +function duk_is_c_function(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_c_function'; +function duk_is_ecmascript_function(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_ecmascript_function'; +function duk_is_bound_function(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_bound_function'; +function duk_is_thread(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_thread'; +function duk_is_callable(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; +function duk_is_constructable(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_constructable'; + +function duk_is_dynamic_buffer(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_dynamic_buffer'; +function duk_is_fixed_buffer(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_fixed_buffer'; +function duk_is_external_buffer(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_is_external_buffer'; + +(* Buffers and lightfuncs are not considered primitive because they mimic + * objects and e.g. duk_to_primitive() will coerce them instead of returning + * them as is. Symbols are represented as strings internally. + *) +function duk_is_primitive(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; + +(* Symbols are object coercible, covered by DUK_TYPE_MASK_STRING. *) +function duk_is_object_coercible(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; + +function duk_get_error_code(ctx: PDukContext; idx: TDukIdx): TDukErrcode; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_error_code'; +function duk_is_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +function duk_is_eval_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +function duk_is_range_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +function duk_is_reference_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +function duk_is_syntax_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +function duk_is_type_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +function duk_is_uri_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; + +(* + * Get operations: no coercion, returns default value for invalid + * indices and invalid value types. + * + * duk_get_undefined() and duk_get_null() would be pointless and + * are not included. + *) + +function duk_get_boolean(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_boolean'; +function duk_get_number(ctx: PDukContext; idx: TDukIdx): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_number'; +function duk_get_int(ctx: PDukContext; idx: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_int'; +function duk_get_uint(ctx: PDukContext; idx: TDukIdx): TDukUInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_uint'; +function duk_get_string(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_string'; +function duk_get_lstring(ctx: PDukContext; idx: TDukIdx; out_len: PDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_lstring'; +function duk_get_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_buffer'; +function duk_get_buffer_data(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_buffer_data'; +function duk_get_pointer(ctx: PDukContext; idx: TDukIdx): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_pointer'; +function duk_get_c_function(ctx: PDukContext; idx: TDukIdx): TDukCFunction; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_c_function'; +function duk_get_context(ctx: PDukContext; idx: TDukIdx): PDukContext; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_context'; +function duk_get_heapptr(ctx: PDukContext; idx: TDukIdx): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_heapptr'; + +(* + * Get-with-explicit default operations: like get operations but with an + * explicit default value. + *) + +function duk_get_boolean_default(ctx: PDukContext; idx: TDukIdx; def_value: TDukBool): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_boolean_default'; +function duk_get_number_default(ctx: PDukContext; idx: TDukIdx; def_value: TDukDouble): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_number_default'; +function duk_get_int_default(ctx: PDukContext; idx: TDukIdx; def_value: TDukInt): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_int_default'; +function duk_get_uint_default(ctx: PDukContext; idx: TDukIdx; def_value: TDukUInt): TDukUInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_uint_default'; +function duk_get_string_default(ctx: PDukContext; idx: TDukIdx; const def_value: MarshaledAString): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_string_default'; +function duk_get_lstring_default(ctx: PDukContext; idx: TDukIdx; out_len: PDukSize; const def_ptr: MarshaledAString; def_len: TDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_lstring_default'; +function duk_get_buffer_default(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize; def_ptr: Pointer; def_len: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_buffer_default'; +function duk_get_buffer_data_default(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize; def_ptr: Pointer; def_len: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_buffer_data_default'; +function duk_get_pointer_default(ctx: PDukContext; idx: TDukIdx; def_value: Pointer): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_pointer_default'; +function duk_get_c_function_default(ctx: PDukContext; idx: TDukIdx; def_value: TDukCFunction): TDukCFunction; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_c_function_default'; +function duk_get_context_default(ctx: PDukContext; idx: TDukIdx; def_value: PDukContext): PDukContext; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_context_default'; +function duk_get_heapptr_default(ctx: PDukContext; idx: TDukIdx; def_value: Pointer): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_heapptr_default'; + +(* + * Opt operations: like require operations but with an explicit default value + * when value is undefined or index is invalid, null and non-matching types + * cause a TypeError. + *) + +function duk_opt_boolean(ctx: PDukContext; idx: TDukIdx; def_value: TDukBool): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_boolean'; +function duk_opt_number(ctx: PDukContext; idx: TDukIdx; def_value: TDukDouble): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_number'; +function duk_opt_int(ctx: PDukContext; idx: TDukIdx; def_value: TDukInt): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_int'; +function duk_opt_uint(ctx: PDukContext; idx: TDukIdx; def_value: TDukUInt): TDukUInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_uint'; +function duk_opt_string(ctx: PDukContext; idx: TDukIdx; const def_ptr: MarshaledAString): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_string'; +function duk_opt_lstring(ctx: PDukContext; idx: TDukIdx; out_len: PDukSize; const def_ptr: MarshaledAString; def_len: TDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_lstring'; +function duk_opt_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize; def_ptr: Pointer; def_size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_buffer'; +function duk_opt_buffer_data(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize; def_ptr: Pointer; def_size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_buffer_data'; +function duk_opt_pointer(ctx: PDukContext; idx: TDukIdx; def_value: Pointer): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_pointer'; +function duk_opt_c_function(ctx: PDukContext; idx: TDukIdx; def_value: TDukCFunction): TDukCFunction; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_c_function'; +function duk_opt_context(ctx: PDukContext; idx: TDukIdx; def_value: PDukContext): PDukContext; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_context'; +function duk_opt_heapptr(ctx: PDukContext; idx: TDukIdx; def_value: Pointer): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_opt_heapptr'; + +(* + * Require operations: no coercion, throw error if index or type + * is incorrect. No defaulting. + *) + +procedure duk_require_type_mask(ctx: PDukContext; idx: TDukIdx; mask: TDukUInt); inline; + +procedure duk_require_undefined(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_undefined'; +procedure duk_require_null(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_null'; +function duk_require_boolean(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_boolean'; +function duk_require_number(ctx: PDukContext; idx: TDukIdx): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_number'; +function duk_require_int(ctx: PDukContext; idx: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_int'; +function duk_require_uint(ctx: PDukContext; idx: TDukIdx): TDukUInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_uint'; +function duk_require_string(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_string'; +function duk_require_lstring(ctx: PDukContext; idx: TDukIdx; out_len: PDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_lstring'; +procedure duk_require_object(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_object'; +function duk_require_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_buffer'; +function duk_require_buffer_data(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_buffer_data'; +function duk_require_pointer(ctx: PDukContext; idx: TDukIdx): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_pointer'; +function duk_require_c_function(ctx: PDukContext; idx: TDukIdx): TDukCFunction; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_c_function'; +function duk_require_context(ctx: PDukContext; idx: TDukIdx): PDukContext; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_context'; +procedure duk_require_function(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_function'; +procedure duk_require_callable(ctx: PDukContext; idx: TDukIdx); inline; +function duk_require_heapptr(ctx: PDukContext; idx: TDukIdx): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_require_heapptr'; + +(* Symbols are object coercible and covered by DUK_TYPE_MASK_STRING. *) +procedure duk_require_object_coercible(ctx: PDukContext; idx: TDukIdx); inline; + +(* + * Coercion operations: in-place coercion, return coerced value where + * applicable. If index is invalid, throw error. Some coercions may + * throw an expected error (e.g. from a toString() or valueOf() call) + * or an internal error (e.g. from out of memory). + *) + +procedure duk_to_undefined(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_undefined'; +procedure duk_to_null(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_null'; +function duk_to_boolean(ctx: PDukContext; idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_boolean'; +function duk_to_number(ctx: PDukContext; idx: TDukIdx): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_number'; +function duk_to_int(ctx: PDukContext; idx: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_int'; +function duk_to_uint(ctx: PDukContext; idx: TDukIdx): TDukUInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_uint'; +function duk_to_int32(ctx: PDukContext; idx: TDukIdx): TDukInt32; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_int32'; +function duk_to_uint32(ctx: PDukContext; idx: TDukIdx): TDukUInt32; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_uint32'; +function duk_to_uint16(ctx: PDukContext; idx: TDukIdx): TDukUInt16; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_uint16'; +function duk_to_string(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_string'; +function duk_to_lstring(ctx: PDukContext; idx: TDukIdx; out_len: PDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_lstring'; +function duk_to_buffer_raw(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize; flags: TDukUInt): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_buffer_raw'; +function duk_to_pointer(ctx: PDukContext; idx: TDukIdx): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_pointer'; +procedure duk_to_object(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_object'; +procedure duk_to_primitive(ctx: PDukContext; idx: TDukIdx; hint: TDukInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_to_primitive'; + +const + DUK_BUF_MODE_FIXED = 0; (* internal: request fixed buffer result *) + DUK_BUF_MODE_DYNAMIC = 1; (* internal: request dynamic buffer result *) + DUK_BUF_MODE_DONTCARE = 2; (* internal: don't care about fixed/dynamic nature *) + +function duk_to_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; inline; +function duk_to_fixed_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; inline; +function duk_to_dynamic_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; inline; + +(* safe variants of a few coercion operations *) +function duk_safe_to_lstring(ctx: PDukContext; idx: TDukIdx; out_len: PDukSize): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_safe_to_lstring'; +function duk_safe_to_string(ctx: PDukContext; idx: TDukIdx): MarshaledAString; inline; + +(* + * Value length + *) + +function duk_get_length(ctx: PDukContext; idx: TDukIdx): TDukSize; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_length'; +procedure duk_set_length(ctx: PDukContext; idx: TDukIdx; len: TDukSize); cdecl external LIB_DUKTAPE name PREFIX + 'duk_set_length'; + +(* + * Misc conversion + *) + +function duk_base64_encode(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_base64_encode'; +procedure duk_base64_decode(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_base64_decode'; +function duk_hex_encode(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_hex_encode'; +procedure duk_hex_decode(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_hex_decode'; +function duk_json_encode(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_json_encode'; +procedure duk_json_decode(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_json_decode'; + +function duk_buffer_to_string(ctx: PDukContext; idx: TDukIdx): MarshaledAString; cdecl external LIB_DUKTAPE name PREFIX + 'duk_buffer_to_string'; + +(* + * Buffer + *) + +function duk_resize_buffer(ctx: PDukContext; idx: TDukIdx; new_size: TDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_resize_buffer'; +function duk_steal_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; cdecl external LIB_DUKTAPE name PREFIX + 'duk_steal_buffer'; +procedure duk_config_buffer(ctx: PDukContext; idx: TDukIdx; ptr: Pointer; len: TDukSize); cdecl external LIB_DUKTAPE name PREFIX + 'duk_config_buffer'; + +(* + * Property access + * + * The basic function assumes key is on stack. The _string variant takes + * a C string as a property name, while the _index variant takes an array + * index as a property name (e.g. 123 is equivalent to the key "123"). + *) + +function duk_get_prop(ctx: PDukContext; obj_idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prop'; +function duk_get_prop_string(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prop_string'; +function duk_get_prop_lstring(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString; key_len: TDukSize): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prop_lstring'; +function duk_get_prop_index(ctx: PDukContext; obj_idx: TDukIdx; arr_idx: TDukUArrIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prop_index'; +function duk_get_prop_heapptr(ctx: PDukContext; obj_idx: TDukIdx; ptr: Pointer): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prop_heapptr'; +function duk_put_prop(ctx: PDukContext; obj_idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_prop'; +function duk_put_prop_string(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_prop_string'; +function duk_put_prop_lstring(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString; key_len: TDukSize): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_prop_lstring'; +function duk_put_prop_index(ctx: PDukContext; obj_idx: TDukIdx; arr_idx: TDukUArrIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_prop_index'; +function duk_put_prop_heapptr(ctx: PDukContext; obj_idx: TDukIdx; ptr: Pointer): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_prop_heapptr'; +function duk_del_prop(ctx: PDukContext; obj_idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_del_prop'; +function duk_del_prop_string(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_del_prop_string'; +function duk_del_prop_lstring(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString; key_len: TDukSize): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_del_prop_lstring'; +function duk_del_prop_index(ctx: PDukContext; obj_idx: TDukIdx; arr_idx: TDukUArrIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_del_prop_index'; +function duk_del_prop_heapptr(ctx: PDukContext; obj_idx: TDukIdx; ptr: Pointer): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_del_prop_heapptr'; +function duk_has_prop(ctx: PDukContext; obj_idx: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_has_prop'; +function duk_has_prop_string(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_has_prop_string'; +function duk_has_prop_lstring(ctx: PDukContext; obj_idx: TDukIdx; const key: MarshaledAString; key_len: TDukSize): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_has_prop_lstring'; +function duk_has_prop_index(ctx: PDukContext; obj_idx: TDukIdx; arr_idx: TDukUArrIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_has_prop_index'; +function duk_has_prop_heapptr(ctx: PDukContext; obj_idx: TDukIdx; ptr: Pointer): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_has_prop_heapptr'; + +procedure duk_get_prop_desc(ctx: PDukContext; obj_idx: TDukIdx; flags: TDukUInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prop_desc'; +procedure duk_def_prop(ctx: PDukContext; obj_idx: TDukIdx; flags: TDukUInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_def_prop'; + +function duk_get_global_string(ctx: PDukContext; const key: MarshaledAString): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_global_string'; +function duk_get_global_lstring(ctx: PDukContext; const key: MarshaledAString; key_len: TDukSize): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_global_lstring'; +function duk_put_global_string(ctx: PDukContext; const key: MarshaledAString): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_global_string'; +function duk_put_global_lstring(ctx: PDukContext; const key: MarshaledAString; key_len: TDukSize): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_global_lstring'; + +(* + * Inspection + *) + +procedure duk_inspect_value(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_inspect_value'; +procedure duk_inspect_callstack_entry(ctx: PDukContext; level: TDukInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_inspect_callstack_entry'; + +(* + * Object prototype + *) + +procedure duk_get_prototype(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_prototype'; +procedure duk_set_prototype(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_set_prototype'; + +(* + * Object finalizer + *) + +procedure duk_get_finalizer(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_finalizer'; +procedure duk_set_finalizer(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_set_finalizer'; + +(* + * Global object + *) + +procedure duk_set_global_object(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_set_global_object'; + +(* + * Duktape/C function magic value + *) + +function duk_get_magic(ctx: PDukContext; idx: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_magic'; +procedure duk_set_magic(ctx: PDukContext; idx: TDukIdx; magic: TDukInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_set_magic'; +function duk_get_current_magic(ctx: PDukContext): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_current_magic'; + +(* + * Module helpers: put multiple function or constant properties + *) + +procedure duk_put_function_list(ctx: PDukContext; obj_idx: TDukIdx; const funcs: PDukFunctionListEntry); cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_function_list'; +procedure duk_put_number_list(ctx: PDukContext; obj_idx: TDukIdx; const numbers: PDukNumberListEntry); cdecl external LIB_DUKTAPE name PREFIX + 'duk_put_number_list'; + +(* + * Object operations + *) + +procedure duk_compact(ctx: PDukContext; obj_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_compact'; +procedure duk_enum(ctx: PDukContext; obj_idx: TDukIdx; enum_flags: TDukUInt); cdecl external LIB_DUKTAPE name PREFIX + 'duk_enum'; +function duk_next(ctx: PDukContext; enum_idx: TDukIdx; get_value: TDukBool): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_next'; +procedure duk_seal(ctx: PDukContext; obj_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_seal'; +procedure duk_freeze(ctx: PDukContext; obj_idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_freeze'; + +(* + * String manipulation + *) + +procedure duk_concat(ctx: PDukContext; count: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_concat'; +procedure duk_join(ctx: PDukContext; count: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_join'; +procedure duk_decode_string(ctx: PDukContext; idx: TDukIdx; callback: TDukDecodeCharFunction; udata: Pointer); cdecl external LIB_DUKTAPE name PREFIX + 'duk_decode_string'; +procedure duk_map_string(ctx: PDukContext; idx: TDukIdx; callback: TDukMapCharFunction; udata: Pointer); cdecl external LIB_DUKTAPE name PREFIX + 'duk_map_string'; +procedure duk_substring(ctx: PDukContext; idx: TDukIdx; start_char_offset: TDukSize; end_char_offset: TDukSize); cdecl external LIB_DUKTAPE name PREFIX + 'duk_substring'; +procedure duk_trim(ctx: PDukContext; idx: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_trim'; +function duk_char_code_at(ctx: PDukContext; idx: TDukIdx; char_offset: TDukSize): TDukCodepoint; cdecl external LIB_DUKTAPE name PREFIX + 'duk_char_code_at'; + +(* + * Ecmascript operators + *) + +function duk_equals(ctx: PDukContext; idx1: TDukIdx; idx2: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_equals'; +function duk_strict_equals(ctx: PDukContext; idx1: TDukIdx; idx2: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_strict_equals'; +function duk_samevalue(ctx: PDukContext; idx1: TDukIdx; idx2: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_samevalue'; +function duk_instanceof(ctx: PDukContext; idx1: TDukIdx; idx2: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_instanceof'; + +(* + * Function (method) calls + *) + +procedure duk_call(ctx: PDukContext; nargs: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_call'; +procedure duk_call_method(ctx: PDukContext; nargs: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_call_method'; +procedure duk_call_prop(ctx: PDukContext; obj_idx: TDukIdx; nargs: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_call_prop'; +function duk_pcall(ctx: PDukContext; nargs: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_pcall'; +function duk_pcall_method(ctx: PDukContext; nargs: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_pcall_method'; +function duk_pcall_prop(ctx: PDukContext; obj_idx: TDukIdx; nargs: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_pcall_prop'; +procedure duk_new(ctx: PDukContext; nargs: TDukIdx); cdecl external LIB_DUKTAPE name PREFIX + 'duk_new'; +function duk_pnew(ctx: PDukContext; nargs: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_pnew'; +function duk_safe_call(ctx: PDukContext; func: TDukSafeCallFunction; udata: Pointer; nargs: TDukIdx; nrets: TDukIdx): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_safe_call'; + +(* + * Thread management + *) + +(* There are currently no native functions to yield/resume, due to the internal + * limitations on coroutine handling. These will be added later. + *) + +(* + * Compilation and evaluation + *) + +function duk_eval_raw(ctx: PDukContext; const src_buffer: MarshaledAString; src_length: TDukSize; flags: TDukUInt): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_eval_raw'; +function duk_compile_raw(ctx: PDukContext; const src_buffer: MarshaledAString; src_length: TDukSize; flags: TDukUInt): TDukInt; cdecl external LIB_DUKTAPE name PREFIX + 'duk_compile_raw'; + +(* plain *) +function duk_eval(ctx: PDukContext): TDukInt; inline; +function duk_eval_noresult(ctx: PDukContext): TDukInt; inline; +function duk_peval(ctx: PDukContext): TDukInt; inline; +function duk_peval_noresult(ctx: PDukContext): TDukInt; inline; +function duk_compile(ctx: PDukContext; flags: TDukUInt): TDukInt; inline; +function duk_pcompile(ctx: PDukContext; flags: TDukUInt): TDukInt; inline; + +(* string *) +function duk_eval_string(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +function duk_eval_string_noresult(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +function duk_peval_string(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +function duk_peval_string_noresult(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +function duk_compile_string(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +function duk_compile_string_filename(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +function duk_pcompile_string(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +function duk_pcompile_string_filename(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; + +(* lstring *) +function duk_eval_lstring(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_eval_lstring_noresult(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_peval_lstring(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_peval_lstring_noresult(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_compile_lstring(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_compile_lstring_filename(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_pcompile_lstring(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +function duk_pcompile_lstring_filename(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; + +(* + * Bytecode load/dump + *) + +procedure duk_dump_function(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_dump_function'; +procedure duk_load_function(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_load_function'; + +(* + * Debugging + *) + +procedure duk_push_context_dump(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_push_context_dump'; + +(* + * Debugger (debug protocol) + *) + +procedure duk_debugger_attach(ctx: PDukContext; read_cb: TDukDebugReadFunction; write_cb: TDukDebugWriteFunction; peek_cb: TDukDebugPeekFunction; read_flush_cb: TDukDebugReadFlushFunction; write_flush_cb: TDukDebugWriteFlushFunction; request_cb: TDukDebugRequestFunction; detached_cb: TDukDebugDetachedFunction; udata: Pointer); cdecl external LIB_DUKTAPE name PREFIX + 'duk_debugger_attach'; +procedure duk_debugger_detach(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_debugger_detach'; +procedure duk_debugger_cooperate(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_debugger_cooperate'; +function duk_debugger_notify(ctx: PDukContext; nvalues: TDukIdx): TDukBool; cdecl external LIB_DUKTAPE name PREFIX + 'duk_debugger_notify'; +procedure duk_debugger_pause(ctx: PDukContext); cdecl external LIB_DUKTAPE name PREFIX + 'duk_debugger_pause'; + +(* + * Time handling + *) + +function duk_get_now(ctx: PDukContext): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_get_now'; +procedure duk_time_to_components(ctx: PDukContext; timeval: TDukDouble; comp: PDukTimeComponents); cdecl external LIB_DUKTAPE name PREFIX + 'duk_time_to_components'; +function duk_components_to_time(ctx: PDukContext; comp: PDukTimeComponents): TDukDouble; cdecl external LIB_DUKTAPE name PREFIX + 'duk_components_to_time'; + +(* + * Date provider related constants + * + * NOTE: These are "semi public" - you should only use these if you write + * your own platform specific Date provider, see doc/datetime.rst. + *) + +(* Millisecond count constants. *) +const + DUK_DATE_MSEC_SECOND = 1000; + DUK_DATE_MSEC_MINUTE = 60 * 1000; + DUK_DATE_MSEC_HOUR = 60 * 60 * 1000; + DUK_DATE_MSEC_DAY = 24 * 60 * 60 * 1000; + +(* Ecmascript date range is 100 million days from Epoch: + * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs + * 8640000000000000 + * (= 8.64e15) + *) +const + DUK_DATE_MSEC_100M_DAYS = 8.64e15; + DUK_DATE_MSEC_100M_DAYS_LEEWAY = 8.64e15 + 24 * 3600e3; + +(* Ecmascript year range: + * > new Date(100e6 * 24 * 3600e3).toISOString() + * '+275760-09-13T00:00:00.000Z' + * > new Date(-100e6 * 24 * 3600e3).toISOString() + * '-271821-04-20T00:00:00.000Z' + *) +const + DUK_DATE_MIN_ECMA_YEAR = -271821; + DUK_DATE_MAX_ECMA_YEAR = 275760; + +(* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR + * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API + * calls (like Date constructor call). Some functions in duk_bi_date.c + * depend on the specific ordering, so change with care. 16 bits are not + * enough for all parts (year, specifically). + * + * Must be in-sync with genbuiltins.py. + *) +const + DUK_DATE_IDX_YEAR = 0; (* year *) + DUK_DATE_IDX_MONTH = 1; (* month: 0 to 11 *) + DUK_DATE_IDX_DAY = 2; (* day within month: 0 to 30 *) + DUK_DATE_IDX_HOUR = 3; + DUK_DATE_IDX_MINUTE = 4; + DUK_DATE_IDX_SECOND = 5; + DUK_DATE_IDX_MILLISECOND = 6; + DUK_DATE_IDX_WEEKDAY = 7; (* weekday: 0 to 6, 0=sunday, 1=monday, etc *) + DUK_DATE_IDX_NUM_PARTS = 8; + +(* Internal API call flags, used for various functions in duk_bi_date.c. + * Certain flags are used by only certain functions, but since the flags + * don't overlap, a single flags value can be passed around to multiple + * functions. + * + * The unused top bits of the flags field are also used to pass values + * to helpers (duk__get_part_helper() and duk__set_part_helper()). + * + * Must be in-sync with genbuiltins.py. + *) + +(* NOTE: when writing a Date provider you only need a few specific + * flags from here, the rest are internal. Avoid using anything you + * don't need. + *) +const + DUK_DATE_FLAG_NAN_TO_ZERO = 1 shl 0; (* timeval breakdown: internal time value NaN -> zero *) + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR = 1 shl 1; (* timeval breakdown: internal time value NaN -> RangeError (toISOString) *) + DUK_DATE_FLAG_ONEBASED = 1 shl 2; (* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) *) + DUK_DATE_FLAG_EQUIVYEAR = 1 shl 3; (* timeval breakdown: replace year with equivalent year in the [1971,2037] range for DST calculations *) + DUK_DATE_FLAG_LOCALTIME = 1 shl 4; (* convert time value to local time *) + DUK_DATE_FLAG_SUB1900 = 1 shl 5; (* getter: subtract 1900 from year when getting year part *) + DUK_DATE_FLAG_TOSTRING_DATE = 1 shl 6; (* include date part in string conversion result *) + DUK_DATE_FLAG_TOSTRING_TIME = 1 shl 7; (* include time part in string conversion result *) + DUK_DATE_FLAG_TOSTRING_LOCALE = 1 shl 8; (* use locale specific formatting if available *) + DUK_DATE_FLAG_TIMESETTER = 1 shl 9; (* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) *) + DUK_DATE_FLAG_YEAR_FIXUP = 1 shl 10; (* setter: perform 2-digit year fixup (00...99 -> 1900...1999) *) + DUK_DATE_FLAG_SEP_T = 1 shl 11; (* string conversion: use 'T' instead of ' ' as a separator *) + DUK_DATE_FLAG_VALUE_SHIFT = 12; (* additional values begin at bit 12 *) + +(* + * END PUBLIC API + *) + +implementation + +function DUK_HIDDEN_SYMBOL(const AX: UTF8String): UTF8String; inline; +begin + Result := #$FF + AX; +end; + +function DUK_GLOBAL_SYMBOL(const AX: UTF8String): UTF8String; inline; +begin + Result := #$80 + AX; +end; + +function DUK_LOCAL_SYMBOL(const AX, AUniq: UTF8String): UTF8String; inline; +begin + Result := #$81 + AX + #$FF + AUniq; +end; + +function DUK_WELLKNOWN_SYMBOL(const AX: UTF8String): UTF8String; inline; +begin + Result := #$81 + AX + #$FF; +end; + +function duk_create_heap_default: PDukContext; inline; +begin + Result := duk_create_heap(nil, nil, nil, nil, nil); +end; + +procedure duk_throw(ctx: PDukContext); inline; +begin + duk_throw_raw(ctx); +end; + +procedure duk_fatal(ctx: PDukContext; const err_msg: MarshaledAString); inline; +begin + duk_fatal_raw(ctx, err_msg); +end; + +procedure duk_error(ctx: PDukContext; err_code: TDukErrCode; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, err_code, nil, 0, fmt); +end; + +procedure duk_generic_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_ERROR, nil, 0, fmt); +end; + +procedure duk_eval_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_EVAL_ERROR, nil, 0, fmt); +end; + +procedure duk_range_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_RANGE_ERROR, nil, 0, fmt); +end; + +procedure duk_reference_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_REFERENCE_ERROR, nil, 0, fmt); +end; + +procedure duk_syntax_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_SYNTAX_ERROR, nil, 0, fmt); +end; + +procedure duk_type_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_TYPE_ERROR, nil, 0, fmt); +end; + +procedure duk_uri_error(ctx: PDukContext; const fmt: MarshaledAString); inline; +begin + duk_error_raw(ctx, DUK_ERR_URI_ERROR, nil, 0, fmt); +end; + +procedure duk_xmove_top(to_ctx: PDukContext; from_ctx: PDukContext; count: TDukIdx); inline; +begin + duk_xcopymove_raw(to_ctx, from_ctx, count, 0); +end; + +procedure duk_xcopy_top(to_ctx: PDukContext; from_ctx: PDukContext; count: TDukIdx); inline; +begin + duk_xcopymove_raw(to_ctx, from_ctx, count, 1); +end; + +function duk_push_thread(ctx: PDukContext): TDukIdx; inline; +begin + Result := duk_push_thread_raw(ctx, 0); +end; + +function duk_push_thread_new_globalenv(ctx: PDukContext): TDukIdx; inline; +begin + Result := duk_push_thread_raw(ctx, DUK_THREAD_NEW_GLOBAL_ENV); +end; + +function duk_push_error_object(ctx: PDukContext; err_code: TDukErrcode; const fmt: MarshaledAString): TDukIdx; inline; +begin + Result := duk_push_error_object_raw(ctx, err_code, nil, 0, fmt); +end; + +function duk_push_buffer(ctx: PDukContext; size: TDukSize; dynamic: Boolean): Pointer; inline; +begin + if (dynamic) then + Result := duk_push_buffer_raw(ctx, size, DUK_BUF_FLAG_DYNAMIC) + else + Result := duk_push_buffer_raw(ctx, size, 0); +end; + +function duk_push_fixed_buffer(ctx: PDukContext; size: TDukSize): Pointer; inline; +begin + Result := duk_push_buffer_raw(ctx, size, 0); +end; + +function duk_push_dynamic_buffer(ctx: PDukContext; size: TDukSize): Pointer; inline; +begin + Result := duk_push_buffer_raw(ctx, size, DUK_BUF_FLAG_DYNAMIC); +end; + +function duk_push_external_buffer(ctx: PDukContext): Pointer; inline; +begin + Result := duk_push_buffer_raw(ctx, 0, DUK_BUF_FLAG_DYNAMIC or DUK_BUF_FLAG_EXTERNAL); +end; + +function duk_is_null_or_undefined(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; +begin + Result := Ord((duk_get_type_mask(ctx, idx) and (DUK_TYPE_MASK_NULL or DUK_TYPE_MASK_UNDEFINED)) <> 0); +end; + +function duk_is_callable(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; +begin + Result := duk_is_function(ctx, idx); +end; + +function duk_is_primitive(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; +begin + Result := duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_UNDEFINED or + DUK_TYPE_MASK_NULL or DUK_TYPE_MASK_BOOLEAN or DUK_TYPE_MASK_NUMBER or + DUK_TYPE_MASK_STRING or DUK_TYPE_MASK_POINTER); +end; + +function duk_is_object_coercible(ctx: PDukContext; idx: TDukIdx): TDukBool; inline; +begin + Result := duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_BOOLEAN or + DUK_TYPE_MASK_NUMBER or DUK_TYPE_MASK_STRING or DUK_TYPE_MASK_OBJECT or + DUK_TYPE_MASK_BUFFER or DUK_TYPE_MASK_POINTER or DUK_TYPE_MASK_LIGHTFUNC); +end; + +function duk_is_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) <> 0); +end; + +function duk_is_eval_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) = DUK_ERR_EVAL_ERROR); +end; + +function duk_is_range_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) = DUK_ERR_RANGE_ERROR); +end; + +function duk_is_reference_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) = DUK_ERR_REFERENCE_ERROR); +end; + +function duk_is_syntax_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) = DUK_ERR_SYNTAX_ERROR); +end; + +function duk_is_type_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) = DUK_ERR_TYPE_ERROR); +end; + +function duk_is_uri_error(ctx: PDukContext; idx: TDukIdx): Boolean; inline; +begin + Result := (duk_get_error_code(ctx, idx) = DUK_ERR_URI_ERROR); +end; + +procedure duk_require_type_mask(ctx: PDukContext; idx: TDukIdx; mask: TDukUInt); inline; +begin + duk_check_type_mask(ctx, idx, mask or DUK_TYPE_MASK_THROW); +end; + +procedure duk_require_callable(ctx: PDukContext; idx: TDukIdx); inline; +begin + duk_require_function(ctx, idx); +end; + +procedure duk_require_object_coercible(ctx: PDukContext; idx: TDukIdx); inline; +begin + duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_BOOLEAN or DUK_TYPE_MASK_NUMBER or + DUK_TYPE_MASK_STRING or DUK_TYPE_MASK_OBJECT or DUK_TYPE_MASK_BUFFER or + DUK_TYPE_MASK_POINTER or DUK_TYPE_MASK_LIGHTFUNC or DUK_TYPE_MASK_THROW); +end; + +function duk_to_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; inline; +begin + Result := duk_to_buffer_raw(ctx, idx, out_size, DUK_BUF_MODE_DONTCARE); +end; + +function duk_to_fixed_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; inline; +begin + Result := duk_to_buffer_raw(ctx, idx, out_size, DUK_BUF_MODE_FIXED); +end; + +function duk_to_dynamic_buffer(ctx: PDukContext; idx: TDukIdx; out_size: PDukSize): Pointer; inline; +begin + Result := duk_to_buffer_raw(ctx, idx, out_size, DUK_BUF_MODE_DYNAMIC); +end; + +function duk_safe_to_string(ctx: PDukContext; idx: TDukIdx): MarshaledAString; inline; +begin + Result := duk_safe_to_lstring(ctx, idx, nil); +end; + +function duk_eval(ctx: PDukContext): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, nil, 0, 1 or DUK_COMPILE_EVAL + or DUK_COMPILE_NOFILENAME); +end; + +function duk_eval_noresult(ctx: PDukContext): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, nil, 0, 1 or DUK_COMPILE_EVAL + or DUK_COMPILE_NOFILENAME or DUK_COMPILE_NORESULT); +end; + +function duk_peval(ctx: PDukContext): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, nil, 0, 1 or DUK_COMPILE_EVAL + or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE); +end; + +function duk_peval_noresult(ctx: PDukContext): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, nil, 0, 1 or DUK_COMPILE_EVAL + or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE or DUK_COMPILE_NORESULT); +end; + +function duk_compile(ctx: PDukContext; flags: TDukUInt): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, nil, 0, 2 or flags); +end; + +function duk_pcompile(ctx: PDukContext; flags: TDukUInt): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, nil, 0, 2 or flags or DUK_COMPILE_SAFE); +end; + +function duk_eval_string(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, src, 0, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_STRLEN or DUK_COMPILE_NOFILENAME); +end; + +function duk_eval_string_noresult(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, src, 0, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_STRLEN or DUK_COMPILE_NOFILENAME or DUK_COMPILE_NORESULT); +end; + +function duk_peval_string(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, src, 0, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_STRLEN or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE); +end; + +function duk_peval_string_noresult(ctx: PDukContext; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, src, 0, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_STRLEN or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE + or DUK_COMPILE_NORESULT); +end; + +function duk_compile_string(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, nil, 0, flags or DUK_COMPILE_NOSOURCE or + DUK_COMPILE_STRLEN or DUK_COMPILE_NOFILENAME); +end; + +function duk_compile_string_filename(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, nil, 0, 1 or flags or DUK_COMPILE_NOSOURCE or + DUK_COMPILE_STRLEN); +end; + +function duk_pcompile_string(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, nil, 0, flags or DUK_COMPILE_NOSOURCE or + DUK_COMPILE_STRLEN or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE); +end; + +function duk_pcompile_string_filename(ctx: PDukContext; flags: TDukUInt; const src: MarshaledAString): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, nil, 0, 1 or flags or DUK_COMPILE_NOSOURCE or + DUK_COMPILE_STRLEN or DUK_COMPILE_SAFE); +end; + +function duk_eval_lstring(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, buf, len, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_NOFILENAME); +end; + +function duk_eval_lstring_noresult(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, buf, len, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_NOFILENAME or DUK_COMPILE_NORESULT); +end; + +function duk_peval_lstring(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, buf, len, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE); +end; + +function duk_peval_lstring_noresult(ctx: PDukContext; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_eval_raw(ctx, buf, len, DUK_COMPILE_EVAL or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE or DUK_COMPILE_NORESULT); +end; + +function duk_compile_lstring(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, buf, len, flags or DUK_COMPILE_NOSOURCE or + DUK_COMPILE_NOFILENAME); +end; + +function duk_compile_lstring_filename(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, buf, len, 1 or flags or DUK_COMPILE_NOSOURCE); +end; + +function duk_pcompile_lstring(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, buf, len, flags or DUK_COMPILE_NOSOURCE or + DUK_COMPILE_NOFILENAME or DUK_COMPILE_SAFE); +end; + +function duk_pcompile_lstring_filename(ctx: PDukContext; flags: TDukUInt; const buf: MarshaledAString; len: TDukSize): TDukInt; inline; +begin + Result := duk_compile_raw(ctx, buf, len, 1 or flags or DUK_COMPILE_NOSOURCE + or DUK_COMPILE_SAFE); +end; + +end. diff --git a/baseunits/JSUtils.pas b/baseunits/JSUtils.pas new file mode 100644 index 000000000..4c6e87714 --- /dev/null +++ b/baseunits/JSUtils.pas @@ -0,0 +1,35 @@ +unit JSUtils; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Duktape.Api, MultiLog; + +function ExecJS(const text: String): String; + +implementation + +function ExecJS(const text: String): String; +var + ctx: PDukContext; + r: TDukInt; + s: String; +begin + Result := ''; + ctx := duk_create_heap_default; + if ctx = nil then begin + Logger.SendError('Failed to create a Duktape heap.'); + Exit; + end; + duk_push_string(ctx, PAnsiChar(text)); + r := duk_peval(ctx); + s := duk_safe_to_string(ctx, -1); + if r <> 0 then Logger.SendError('Error: ' + s) + else Result := s; + duk_destroy_heap(ctx); +end; + +end. + diff --git a/baseunits/modules/Cloudflare.pas b/baseunits/modules/Cloudflare.pas index 44fe51c1b..2255ff358 100644 --- a/baseunits/modules/Cloudflare.pas +++ b/baseunits/modules/Cloudflare.pas @@ -6,7 +6,7 @@ interface uses Classes, SysUtils, uBaseUnit, XQueryEngineHTML, httpsendthread, synautil, - BESEN, BESENValue, RegExpr, dateutils; + JSUtils, RegExpr, dateutils; type @@ -47,7 +47,6 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; var OSleepTime: Integer): Boolean; var s, meth, surl, jschl_vc, pass, jschl_answer: String; - v: TBESENValue; begin Result := False; if (Source = '') or (URL = '') then Exit; @@ -89,15 +88,7 @@ function JSGetAnsweredURL(const Source, URL: String; var OMethod, OURL: String; s := Replace(s, 'a =', False); Expression := '^.*\.submit\(.*\},\s*(\d{4,})\).*$'; OSleepTime := StrToIntDef(Replace(Source, '$1', True), MIN_WAIT_TIME); - - with TBESEN.Create do - try - v := Execute(s); - if v.ValueType = bvtNUMBER then - jschl_answer := FloatToStr(v.Num, FMDFormatSettings); - finally - Free; - end; + jschl_answer := ExecJS(s); end; finally Free; diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5ba55347b..5d2269567 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -271,7 +271,7 @@ - + @@ -300,13 +300,9 @@ - - - - - + From 4e0b438aad8da6c6f0ce2d58e5cd3472ace296dc Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 4 Dec 2018 10:14:58 +0300 Subject: [PATCH 2698/2794] remove old MangaEden module --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaEden.pas | 219 -------------------------------- 2 files changed, 220 deletions(-) delete mode 100644 baseunits/modules/MangaEden.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 9ad575715..1eefd2052 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -19,7 +19,6 @@ uses AcademyVN, Webtoons, Tsumino, - MangaEden, WebtoonTr, GMangaMe, KuManga, diff --git a/baseunits/modules/MangaEden.pas b/baseunits/modules/MangaEden.pas deleted file mode 100644 index 2bf3f1b20..000000000 --- a/baseunits/modules/MangaEden.pas +++ /dev/null @@ -1,219 +0,0 @@ -unit MangaEden; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - diren = '/en/en-directory/'; - dirit = '/en/it-directory/'; -var - MMangaEden, MMangaEdenIT, - MPervEden, MPervEdenIT: TModuleContainer; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; var Page: Integer; const WorkPtr: Integer; - const Module: TModuleContainer): Integer; -var - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL; - if (Module = MMangaEden) or (Module = MPervEden) then - s += diren - else - s += dirit; - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := StrToIntDef(XPathString('//*[@class="pagination pagination_bottom"]/a[last()-1]'), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL; - if (Module = MMangaEden) or (Module = MPervEden) then - s += diren - else - s += dirit; - if AURL <> '0' then - s := s + '?page=' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//table[@id="mangaList"]//tr/td[1]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := XPathString('//*[starts-with(@class,"mangaImage")]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := XPathString('//*[@class="manga-title"]'); - authors := XPathStringAll('//*[@class="rightBox"]/a[contains(@href,"/?author=")]'); - artists := XPathStringAll('//*[@class="rightBox"]/a[contains(@href,"/?artist=")]'); - genres := XPathStringAll('//*[@class="rightBox"]/a[contains(@href,"/?categories")]'); - summary := XPathString('//*[@id="mangaDescription"]'); - s := CleanString(XPathString('//*[@class="rightBox"]')); - AddCommaString(genres, Trim(GetBetween('Type ', ' Status', s))); - s := AnsiLowerCase(s); - if Pos('status ongoing', s) > 0 then - status := '1' - else if Pos('status completed', s) > 0 then - status := '0'; - for v in XPath('//table//tr/td/a[@class="chapterLink"]') do - begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(XPathStringAll('*', ' ', v)); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; - source: TStringList; - i: Integer; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then begin - Result := True; - - s := ''; - source := TStringList.Create; - try - source.LoadFromStream(Document); - if source.Count > 0 then - for i := 0 to source.Count - 1 do - if Pos('var pages = ', source[i]) > 0 then - begin - s := source[i]; - s := GetBetween('[', ']', s); - if s <> '' then - s := '[' + s + ']'; - Break; - end; - finally - source.Free; - end; - - with TXQueryEngineHTML.Create do - try - if s <> '' then - begin - ParseHTML(s); - PageLinks.AddText(XPathStringAll('json(*)()("fs")', LineEnding)); - end; - - if PageLinks.Count = 0 then - begin - ParseHTML(Document); - PageNumber := XPath('//select[@id="pageSelect"]/option').Count; - end; - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - s := RemoveURLDelim(AURL); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 1); - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AppendURLDelim(s) + IncStr(DownloadThread.WorkId) + '/'; - if GET(FillHost(Module.RootURL, s)) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[DownloadThread.WorkId] := - XPathString('//img[@id="mainImg"]/@src'); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; - - function AddWebsiteModule(const AWebsite, ARootURL, ACategory: String): TModuleContainer; - begin - Result := AddModule; - with Result do begin - Website := AWebsite; - RootURL := ARootURL; - Category := ACategory; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; - end; - -begin - MMangaEden := AddWebsiteModule('MangaEden', 'http://www.mangaeden.com', 'English'); - MMangaEdenIT := AddWebsiteModule('MangaEden_IT', 'http://www.mangaeden.com', 'Italian'); - MPervEden := AddWebsiteModule('PervEden', 'http://www.perveden.com', 'H-Sites'); - MPervEdenIT := AddWebsiteModule('PervEden_IT', 'http://www.perveden.com', 'H-Sites'); -end; - -initialization - RegisterModule; - -end. From f4300ab9077ff0166ce2f2360de5bfb3b4031a7f Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 6 Dec 2018 17:28:43 +0300 Subject: [PATCH 2699/2794] GMangaMe, rewrite closes #1526 --- baseunits/ModuleList.inc | 1 - baseunits/modules/GMangaMe.pas | 113 --------------------------------- lua/modules/GMangaMe.lua | 106 +++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 114 deletions(-) delete mode 100644 baseunits/modules/GMangaMe.pas create mode 100644 lua/modules/GMangaMe.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 1eefd2052..e452a2227 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -20,7 +20,6 @@ uses Webtoons, Tsumino, WebtoonTr, - GMangaMe, KuManga, SenManga, MangaInn, diff --git a/baseunits/modules/GMangaMe.pas b/baseunits/modules/GMangaMe.pas deleted file mode 100644 index 6d5e8a9ff..000000000 --- a/baseunits/modules/GMangaMe.pas +++ /dev/null @@ -1,113 +0,0 @@ -unit GMangaMe; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/mangas') then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="row"]//a[./div[@class="manga-cover-container"]]') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('div/span[@class="info-item info-title"]', v)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := FillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div/img[starts-with(@class,"img-responsive")]/@src')); - if title = '' then title := XPathString('//div[@class="content-div"]/h2'); - summary := XPathString('//div[@class="content-div"]/div[@class="summary"]/text()'); - authors := XPathString('//label[starts-with(.,"المؤلفون")]/following-sibling::*'); - artists := XPathString('//label[starts-with(.,"الرسامون")]/following-sibling::*'); - genres := XPathStringAll('//label[starts-with(.,"التصنيفات")]/following-sibling::*//a'); - status := MangaInfoStatusIfPos(XPathString('//label[starts-with(.,"حالة القصة")]/following-sibling::*'), - 'مستمرة', - 'منتهية'); - for v in XPath('//tr/td[./a[@class="chapter-link"]]') do - begin - chapterLinks.Add(XPathString('./a/@href', v)); - chapterName.Add(XPathString('../td[1]', v)); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then - begin - Result := True; - s := XPathString('//script[contains(.,"var release_pages")]/substring-before(substring-after(substring-after(.,"var release_pages"), "(["), "]")', Document); - if s <> '' then - begin - s := StringReplace(s, '"', '', [rfReplaceAll]); - PageLinks.CommaText := s; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'GManga'; - RootURL := 'http://gmanga.me'; - Category := 'Arabic'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/GMangaMe.lua b/lua/modules/GMangaMe.lua new file mode 100644 index 000000000..ea34eedf8 --- /dev/null +++ b/lua/modules/GMangaMe.lua @@ -0,0 +1,106 @@ +local domain = 'gmanga.me' +local mediaUrl = 'http://media.' .. domain .. '/uploads' + +function getinfo() + function urlencode(str) + if (str) then + str = string.gsub(str, "\n", "\r\n") + str = string.gsub(str, "([^%w ])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + str = string.gsub(str, " ", "_") + str = string.gsub(str, '%.', '') + end + return str + end + + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + local s = x.xpathstring('//script[@type="application/json" and @class]') + x.parsehtml(s) + local pageurl = x.xpathstring('json(*).globals.page_url') + local id = x.xpathstring('json(*).mangaDataAction.mangaData.id') + local cover = x.xpathstring('json(*).mangaDataAction.mangaData.cover') + mangainfo.coverlink = mediaUrl .. '/manga/cover/' .. id .. '/' .. cover + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('json(*).mangaDataAction.mangaData.title') + end + mangainfo.authors=x.xpathstringall('json(*).mangaDataAction.mangaData.authors().name') + mangainfo.artists=x.xpathstringall('json(*).mangaDataAction.mangaData.artists().name') + mangainfo.genres=x.xpathstringall('json(*).mangaDataAction.mangaData.categories().name') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('json(*).mangaDataAction.mangaData.status'),'publish','finish') + mangainfo.summary=x.xpathstring('json(*).mangaDataAction.mangaData.summary') + if http.xhr(MaybeFillHost(module.RootURL, '/api/mangas/' .. id)) then + x = TXQuery.Create(http.document) + local v = x.xpath('json(*).mangaReleases()') + local t = {} + local data = {} + for i = 1, v.count do + local v1 = v.get(i) + local ch = tonumber(x.xpathstring('chapter', v1)) + local team = x.xpathstring('team_name', v1) + local key = string.format('%08.2f %s', ch, team) + table.insert(t, key) + data[key] = { + name = string.format('%s - %s [%s]', tostring(ch), x.xpathstring('title', v1), team), + link = MaybeFillHost(module.rooturl, pageurl .. '/' .. tostring(ch) .. '/' .. urlencode(team)) + } + end + table.sort(t) + for _, k in ipairs(t) do + mangainfo.chapterlinks.add(data[k].link) + mangainfo.chapternames.add(data[k].name) + end + return no_error + else + return net_problem + end + else + return net_problem + end +end + +function getpagenumber() + local js = require 'modules.jsunpack' + if http.get(MaybeFillHost(module.rooturl,url)) then + local x = TXQuery.Create(http.Document); + local s = x.xpathstring('//script[@type="application/json" and @class]') + x.parsehtml(s) + local pages = js.splitstr(x.xpathstring('json(*).readerDataAction.readerData.release.hq_pages'), '\r\n') + for _, k in ipairs(pages) do + task.pagelinks.add(mediaUrl .. '/releases/' .. k) + end + return true + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl..'/mangas') then + local x = TXQuery.Create(http.Document); + local s = HTMLDecode(x.xpathstring('//*[@data-store-name="mangasIndexStore"]/@data-props')) + x.parsehtml(s) + local v = x.xpath('json(*).mangas()') + for i = 1, v.count do + local v1 = v.get(i) + names.add(x.xpathstring('title', v1)) + links.add(MaybeFillHost(module.rooturl, '/mangas/' .. x.xpathstring('id', v1) .. '/' .. x.xpathstring('slug', v1))) + end + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Arabic' + m.website='GManga' + m.rooturl='http://' .. domain + m.lastupdated='December 6, 2018' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end From e2042945e782fc82514ae0e233cb282902d0b8f0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 10 Dec 2018 17:26:02 +0300 Subject: [PATCH 2700/2794] JapScan, fix --- lua/modules/JapScan.lua | 99 +++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 63 deletions(-) diff --git a/lua/modules/JapScan.lua b/lua/modules/JapScan.lua index 1c21bb5bb..c190a24ab 100644 --- a/lua/modules/JapScan.lua +++ b/lua/modules/JapScan.lua @@ -1,28 +1,22 @@ -function getinfo() +local ALPHA_LIST_UP = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ' + +function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then local x=TXQuery.Create(http.document) if mangainfo.title == '' then - mangainfo.title = x.xpathstring('//h1[@class="bg-header"]') + mangainfo.title = x.xpathstring('//h1') mangainfo.title = string.gsub(mangainfo.title, '^Manga ', '') mangainfo.title = string.gsub(mangainfo.title, ' VF$', '') end - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="table"]/div[@class="row"]/div[6]'), 'En Cours', 'Termine') - mangainfo.authors=x.xpathstring('//div[@class="table"]/div[@class="row"]/div[1]') - mangainfo.genres=x.xpathstring('//div[@class="table"]/div[@class="row"]/div[4]') - mangainfo.summary=x.xpathstring('//div[@id="synopsis"]/string-join(text(),codepoints-to-string(10))') - local v = x.xpath('//*[@id="liste_chapitres"]/ul/li/a') - for i = 1,v.count do - local v1 = v.get(i) - mangainfo.chapterlinks.add(v1.getAttribute('href')) - local s = v1.toString - if Pos('[email protected]', s) ~= 0 then - s = mangainfo.title .. ' ' .. x.xpathstring('text()[2]', v1) - end - s = string.gsub(s, '^Scan ', '') - mangainfo.chapternames.add(s) - end - InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@id="main"]//img/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstringall('//div[@id="main"]//p[contains(span, "Statut")]/text()', ''), 'En Cours', 'Termine') + mangainfo.authors=x.xpathstringall('//div[@id="main"]//p[contains(span, "Auteur")]/text()', '') + mangainfo.artists=x.xpathstringall('//div[@id="main"]//p[contains(span, "Artiste")]/text()', '') + mangainfo.genres=x.xpathstringall('//div[@id="main"]//p[contains(span, "Type(s)")]/text()', '') + mangainfo.summary=x.xpathstring('//div[@id="main"]//div[contains(text(), "Synopsis")]/following-sibling::*') + x.xpathhrefall('//div[@id="chapters_list"]//div[@class="chapters_list"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error else return net_problem @@ -33,71 +27,50 @@ function getpagenumber() task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl, url)) then local x=TXQuery.Create(http.Document) - x.xpathstringall('//select[@id="pages"]/option[position() < last()]/@value', task.pagelinks) - task.pagecontainerlinks.text = http.cookies.text + task.pagenumber = x.xpathcount('//select[@id="pages"]/option[position() < last()]/@value') else return false end return true end +function getimageurl() + local s = AppendURLDelim(url)..(workid+1)..'.html' + if http.get(MaybeFillHost(module.rooturl,s)) then + task.pagelinks[workid]=TXQuery.create(http.document).xpathstring('//div[@id="image"]/@data-src') + return true + end + return false +end + function getnameandlink() - if http.get(module.rooturl .. '/mangas/') then + local s = '0-9' + if module.CurrentDirectoryIndex ~= 0 then + s = ALPHA_LIST_UP:sub(module.CurrentDirectoryIndex+1,module.CurrentDirectoryIndex+1) + end + if http.get(MaybeFillHost(module.rooturl, '/mangas/' .. s .. '/' .. IncStr(url))) then local x = TXQuery.Create(http.Document) - x.XPathHREFAll('//*[@id="liste_mangas"]/div[@class="row"]/div[@class="cell"][1]/a', links, names) + x.XPathHREFAll('//div[@id="main"]//p/a[contains(@href, "/manga/")]', links, names) + local page = tonumber(x.XPathString('//ul[contains(@class, "pagination")]/li[last()]/a')) + if page == nil then + page = 1 + end + updatelist.CurrentDirectoryPageNumber = page return no_error else return net_problem end end -function downloadimage() - http.reset() - http.cookies.text = task.pagecontainerlinks.text - if http.get(MaybeFillHost(module.rooturl, url)) then - local x = TXQuery.Create(http.document) - local img = x.xpathstring('//img[@id="image"]/@src') - if img ~= '' then - return http.get(img) - end - local nom = x.xpathstring('//*[@id="mangas"]/@data-nom'):gsub('/', '_'):gsub('%?', '') - local mangauri = x.xpathstring('//*[@id="mangas"]/@data-uri') - local chapnom = x.xpathstring('//*[@id="chapitres"]/@data-nom') - local chapuri = x.xpathstring('//*[@id="chapitres"]/@data-uri') - local imgnom = x.xpathstring('//select[@id="pages"]/option[@value="'..url..'"]/@data-img') - local imgurl = 'http://cdn.japscan.cc/cr_images/' .. nom .. '/' - if chapnom == '' then - imgurl = imgurl .. chapuri - else - imgurl = imgurl .. chapnom - end - imgurl = imgurl .. '/' .. imgnom - if http.get(imgurl) then - local s = TImagePuzzle.Create(5, 5) - local n = 0 - local x = {2,4,0,3,1} - local y = {4,3,2,1,0} - for i = 1, 5 do - for j = 1, 5 do - s.matrix[y[i]*5+x[j]] = n - n = n + 1 - end - end - s.descramble(http.document, http.document) - return true - end - end - return false -end - function Init() local m=NewModule() m.category='French' m.website='Japscan' - m.rooturl='http://www.japscan.cc' + m.rooturl='http://www.japscan.to' m.lastupdated='April 6, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' - m.ondownloadimage='downloadimage' + m.ongetimageurl='getimageurl' + m.totaldirectory=ALPHA_LIST_UP:len() end From 13406032ade6b29d032046d83bb51eef7a61b932 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 10 Dec 2018 19:33:24 +0300 Subject: [PATCH 2701/2794] LHTranslation, fix download --- lua/modules/LHTranslation.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index ab649ffb9..20480fd3c 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -26,7 +26,14 @@ end local readrooturl = 'http://read.lhtranslation.com' function GetPageNumber() - if http.get(MaybeFillHost(readrooturl, '/read-' .. url:gsub('/', '') .. '.html')) then + local s = '/read-' .. url:gsub('/', '') .. '.html' + if http.get(MaybeFillHost(readrooturl, s)) then + local x=TXQuery.Create(http.document) + x.xpathstringall('//img[contains(@class,"chapter-img")]/@src',task.pagelinks) + if task.pagelinks.count > 0 then return true; end + end + s = s:gsub('(%d+)-(%d+)%.html$', '%1.%2.html') + if http.get(MaybeFillHost(readrooturl, s)) then local x=TXQuery.Create(http.document) x.xpathstringall('//img[contains(@class,"chapter-img")]/@src',task.pagelinks) if task.pagelinks.count > 0 then return true; end From 10405f78f4b803db6c10316bb49e4994bacb32f0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 12 Dec 2018 20:28:12 +0300 Subject: [PATCH 2702/2794] JapScan, fix page count --- lua/modules/JapScan.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lua/modules/JapScan.lua b/lua/modules/JapScan.lua index c190a24ab..3f8037902 100644 --- a/lua/modules/JapScan.lua +++ b/lua/modules/JapScan.lua @@ -7,6 +7,8 @@ function getinfo() if mangainfo.title == '' then mangainfo.title = x.xpathstring('//h1') mangainfo.title = string.gsub(mangainfo.title, '^Manga ', '') + mangainfo.title = string.gsub(mangainfo.title, '^Manhua ', '') + mangainfo.title = string.gsub(mangainfo.title, '^Manhwa ', '') mangainfo.title = string.gsub(mangainfo.title, ' VF$', '') end mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@id="main"]//img/@src')) @@ -27,7 +29,7 @@ function getpagenumber() task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl, url)) then local x=TXQuery.Create(http.Document) - task.pagenumber = x.xpathcount('//select[@id="pages"]/option[position() < last()]/@value') + task.pagenumber = x.xpathcount('//select[@id="pages"]/option/@value') else return false end From dad1685bd0ff22b1800809588500f2f2aa9c290c Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 12 Dec 2018 20:29:30 +0300 Subject: [PATCH 2703/2794] HeavenManga, change domain closes #1564 --- lua/modules/HeavenManga.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index 3ca4b2a42..d84a37f9e 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -68,7 +68,7 @@ end function Init() local m = NewModule() m.website = 'HeavenManga' - m.rooturl = 'http://heavenmanga.world' + m.rooturl = 'http://heavenmanga.ca' m.category = 'English' m.lastupdated='February 26, 2018' m.ongetinfo='getinfo' From 221e294311b14608b860bbccc0f6c124ffcb13a3 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 7 Dec 2018 14:43:26 +0300 Subject: [PATCH 2704/2794] register execjs to lua --- baseunits/lua/LuaBase.pas | 3 ++- baseunits/lua/LuaDuktape.pas | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 baseunits/lua/LuaDuktape.pas diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 18b57a117..76e1eda1d 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -24,7 +24,7 @@ implementation uses LuaStrings, LuaBaseUnit, LuaRegExpr, LuaSynaUtil, LuaSynaCode, MultiLog, - LuaCrypto, LuaImagePuzzle; + LuaCrypto, LuaImagePuzzle, LuaDuktape; function luabase_print(L: Plua_State): Integer; cdecl; var @@ -51,6 +51,7 @@ procedure LuaBaseRegister(L: Plua_State); luaSynaUtilRegister(L); luaSynaCodeRegister(L); luaCryptoRegister(L); + luaDuktapeRegister(L); luaClassRegisterAll(L); end; diff --git a/baseunits/lua/LuaDuktape.pas b/baseunits/lua/LuaDuktape.pas new file mode 100644 index 000000000..bb0e50f9e --- /dev/null +++ b/baseunits/lua/LuaDuktape.pas @@ -0,0 +1,28 @@ +unit LuaDuktape; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, lua53, uBaseUnit; + +procedure luaDuktapeRegister(L: Plua_State); + +implementation + +uses JSUtils, LuaUtils; + +function lua_execjs(L: Plua_State): Integer; cdecl; +begin + lua_pushstring(L, ExecJS(lua_tostring(L, 1))); + Result := 1; +end; + +procedure luaDuktapeRegister(L: Plua_State); +begin + luaPushFunctionGlobal(L, 'ExecJS', @lua_execjs); +end; + +end. + From 1107b8f9bfeb45deae046a043b322d9742f3396d Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 7 Dec 2018 14:31:12 +0300 Subject: [PATCH 2705/2794] MangaFox, fix --- baseunits/modules/MangaFox.pas | 123 ++++++++++++++++++++++----------- 1 file changed, 81 insertions(+), 42 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index f8867db50..b9a863a50 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -4,11 +4,11 @@ interface +implementation + uses Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, MangaFoxWatermark; - -implementation + XQueryEngineHTML, httpsendthread, MangaFoxWatermark, JSUtils, synautil; var removewatermark: Boolean = True; @@ -20,13 +20,16 @@ implementation function GetNameAndLink(const MangaInfo: TMangaInformation; const ANames, ALinks: TStringList; const AURL: String; const Module: TModuleContainer): Integer; +var + s: string; begin Result := NET_PROBLEM; if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + '/manga/') then + s := Module.RootURL + '/directory/' + IncStr(AURL) + '.html?az'; + if MangaInfo.FHTTP.GET(s) then begin Result := NO_ERROR; - XPathHREFAll('//*[@class="manga_list"]/ul/li/a', MangaInfo.FHTTP.Document, ALinks, ANames); + XPathHREFtitleAll('//ul[contains(@class, "manga-list")]/li/a', MangaInfo.FHTTP.Document, ALinks, ANames); end; end; @@ -39,21 +42,21 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; if MangaInfo = nil then Exit(UNKNOWN_ERROR); with MangaInfo.mangaInfo, MangaInfo.FHTTP do begin url := MaybeFillHost(Module.RootURL, AURL); + Cookies.Values['isAdult'] := '1'; if GET(url) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(Document) do try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); - if title = '' then title := XPathString('//title/substring-before(.," Manga - Read")'); - authors := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[2]'); - artists := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[3]'); - genres := XPathString('//div[@id="title"]/table/tbody/tr[2]/td[4]'); - summary := XPathString('//p[@class="summary"]'); - status := MangaInfoStatusIfPos(XPathString('//div[@id="series_info"]/div[5]/span')); - for v in XPath('//ul[@class="chlist"]/li/div/*[self::h3 or self::h4]') do + coverLink := MaybeFillHost(Module.RootURL, XPathString('//img[@class="detail-info-cover-img"]/@src')); + if title = '' then title := XPathString('//span[@class="detail-info-right-title-font"]'); + authors := XPathStringAll('//p[@class="detail-info-right-say"]/a'); + genres := XPathStringAll('//p[@class="detail-info-right-tag-list"]/a'); + summary := XPathString('//p[@class="fullcontent"]'); + status := MangaInfoStatusIfPos(XPathString('//span[@class="detail-info-right-title-tip"]')); + for v in XPath('//ul[@class="detail-main-list"]/li/a') do begin - chapterLinks.Add(StringReplace(XPathString('a/@href', v), '1.html', '', [rfReplaceAll])); - chapterName.Add(XPathString('string-join(.//*[not(contains(@class,"newch"))]/text()," ")', v)); + chapterLinks.Add(StringReplace(v.toNode.getAttribute('href'), '1.html', '', [rfReplaceAll])); + chapterName.Add(XPathString('./div/p[@class="title3"]', v)); end; InvertStrings([chapterLinks, chapterName]); finally @@ -65,41 +68,59 @@ function GetInfo(const MangaInfo: TMangaInformation; const AURL: String; function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String; const Module: TModuleContainer): Boolean; +var + s, key, cid: string; + query: TXQueryEngineHTML; + page: Integer; + v: IXQValue; + lst: TStringList; begin Result := False; if DownloadThread = nil then Exit; with DownloadThread.FHTTP, DownloadThread.Task.Container do begin PageLinks.Clear; PageNumber := 0; + Cookies.Values['isAdult'] := '1'; if GET(MaybeFillHost(Module.RootURL, AURL) + '1.html') then begin Result := True; - PageNumber := XPathCount('//*[@id="top_bar"]//select[@onchange="change_page(this)"]/option[@value!="0"]', Document); - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(MaybeFillHost(Module.RootURL, AURL) + IncStr(DownloadThread.WorkId) + '.html') then begin - Result := True; - s := XPathString('//div[@class="read_img"]//img[@id="image"]/@src', Document); - PageLinks[DownloadThread.WorkId] := s; - // remove invalid last page - if DownloadThread.WorkId = PageLinks.Count - 1 then - begin - s := LowerCase(RemovePathDelim(s)); - if (RightStr(s, 10) = 'compressed') or - (Pos('/compressed?', s) <> 0) then - begin - PageLinks.Delete(DownloadThread.WorkId); - PageNumber := PageLinks.Count; + query := TXQueryEngineHTML.Create(Document); + try + s := query.XPathString('//script[contains(., "eval")]'); + s := 'var $=function(){return{val:function(){}}},newImgs,guidkey;' + s; + s := s + ';newImgs||guidkey;'; + key := ExecJS(s); + if Length(key) > 16 then + PageLinks.CommaText := key + else if Length(key) > 0 then begin + s := query.XPathString('//script[contains(., "chapterid")]'); + cid := Trim(ReplaceString(GetBetween('chapterid', ';', s), '=', '')); + PageNumber := StrToIntDef(Trim(ReplaceString(GetBetween('imagecount', ';', s), '=', '')), 0); + page := 1; + while (PageLinks.Count < PageNumber) and (page <= PageNumber) do begin + Reset; + Headers.Values['Pragma'] := 'no-cache'; + Headers.Values['Cache-Control'] := 'no-cache'; + Headers.Values['Referer'] := MaybeFillHost(Module.RootURL, AURL) + '1.html'; + s := 'chapterfun.ashx?cid=' + cid + '&page=' + IntToStr(page) + '&key=' + key; + if XHR(MaybeFillHost(Module.RootURL, AURL) + s) then begin + s := Trim(StreamToString(Document)); + if s <> '' then begin + s := ExecJS(s); + lst := TStringList.Create; + try + lst.CommaText := s; + if page > 1 then lst.Delete(0); + PageLinks.AddStrings(lst); + finally + lst.Free; + end; + end; + end; + Inc(page); Sleep(3000); + end; end; + finally + query.Free; end; end; end; @@ -112,6 +133,24 @@ function AfterImageSaved(const AFilename: String; const Module: TModuleContainer Result := MangaFoxWatermark.RemoveWatermark(AFilename, saveaspng); end; +function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; + var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; +begin + Result := NET_PROBLEM; + Page := 1; + if MangaInfo = nil then Exit(UNKNOWN_ERROR); + if MangaInfo.FHTTP.GET(Module.RootURL + '/directory/?az') then + begin + Result := NO_ERROR; + with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do + try + Page := StrToIntDef(XPathString('//div[@class="pager-list"]//a[last()-1]'), 1); + finally + Free; + end; + end; +end; + procedure RegisterModule; begin with AddModule do @@ -122,8 +161,8 @@ procedure RegisterModule; OnGetNameAndLink := @GetNameAndLink; OnGetInfo := @GetInfo; OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; OnAfterImageSaved := @AfterImageSaved; + OnGetDirectoryPageNumber := @GetDirectoryPageNumber; AddOptionCheckBox(@removewatermark, 'RemoveWatermark', @RS_RemoveWatermark); AddOptionCheckBox(@saveaspng, 'SaveAsPNG', @RS_SaveAsPNG); end; From 1093b3dbbae2873f5085b0bb5df141853fc2494b Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 29 Dec 2018 09:51:05 +0300 Subject: [PATCH 2706/2794] Bump version 0.9.157.0 --- README.md | 2 +- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c7b8350df..564e94286 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Download the latest release -[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.156.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.156.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0_Win64.7z) +[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.157.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.157.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0_Win64.7z) ## Content diff --git a/changelog.txt b/changelog.txt index 5c1d615c8..e69b7397d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.157.0 (29-12-2018) +[*] Various changes and bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.156.0...0.9.157.0 + 0.9.156.0 (02-07-2018) [+] Added DoujinsCom [H-Sites] [+] Added PlusComico [RAW] diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index 5d2269567..edb15e2d0 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ - + diff --git a/update b/update index c3cde3a5b..15a5f9550 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.156.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.156.0/fmd_0.9.156.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.156.0/fmd_0.9.156.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.156.0/fmd_0.9.156.0_Win64.7z +VERSION=0.9.157.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.157.0/fmd_0.9.157.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.157.0/fmd_0.9.157.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0_Win64.7z From 61b9d1a384c7ee2ddad05bfa4fc314acecb528f9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 7 Dec 2018 13:54:00 +0300 Subject: [PATCH 2707/2794] MangaDex, use api --- lua/modules/MangaDex.lua | 186 ++++++++++++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 34 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 3c3f1fbc5..93b4ca2cc 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -1,43 +1,63 @@ function getinfo() mangainfo.url=MaybeFillHost(module.rooturl,url) http.cookies.values['mangadex_h_toggle'] = '1' - if http.get(mangainfo.url) then - x=TXQuery.Create(http.document) - if mangainfo.title=='' then mangainfo.title=x.xpathstring('//meta[@property="og:title"]/replace(@content,"\\s\\(\\w+\\)\\s-\\sMangaDex$","")') end - mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[contains(@class, "card-body")]//img[@class]/@src')) - mangainfo.authors=x.xpathstring('//div[./text()="Author:"]/string-join(./following-sibling::div,", ")') - mangainfo.artists=x.xpathstring('//div[./text()="Artist:"]/string-join(./following-sibling::div,", ")') - mangainfo.genres = x.xpathstringall('//div[./text()="Genres:"]/following-sibling::div//a') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[contains(./text(),"status")]/following-sibling::div')) - mangainfo.summary=x.xpathstring('//div[./text()="Description:"]/following-sibling::div') - local l='//div[contains(@class, "chapter-container")]//div[@data-id and not(starts-with(./div[contains(@class, "text-warning")], "in "))]' - local n='' - if module.getoption('luashowalllang') then - n='/concat(.," [",../div[6]/img/@title,"]"' - else - l=l..'[./div/img[@title="English"]]' + local id = url:match('title/(%d+)') + if http.get(MaybeFillHost(module.rooturl, '/api/manga/' .. id)) then + local resp = HTMLEncode(StreamToString(http.document)) + local x = TXQuery.Create(resp) + + local info = x.xpath('json(*)') + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('manga/title', info) end - if module.getoption('luashowscangroup') then - if n=='' then n='/concat(.' end - n=n..'," [",../div[7],"]"' + mangainfo.coverlink = MaybeFillHost(module.rooturl, x.xpathstring('manga/cover_url', info)) + mangainfo.authors = x.xpathstring('manga/author', info) + mangainfo.artists = x.xpathstring('manga/artist', info) + mangainfo.summary = x.xpathstring('manga/description', info) + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('manga/status', info), '1', '0') + + local genres = '' + local v = x.xpath('jn:members(manga/genres)', info) + if v.count > 0 then genres = getgenre(v.get(1).toString); end + for i = 2, v.count do + local v1 = v.get(i) + genres = genres .. ', ' .. getgenre(v1.toString) end - l=l..'/div[2]' - if n~='' then n=n..')' end - n=l..n - l=l..'/a/@href' - local nurl='' - while true do - x.xpathstringall(l,mangainfo.chapterlinks) - x.xpathstringall(n,mangainfo.chapternames) - if http.terminated then break end - nurl=x.xpathstring('//ul[contains(@class,"pagination")]/li[contains(@class,"active")]/following-sibling::li[@class="page-item"]/a/@href') - if nurl=='' then break end - if http.get(MaybeFillHost(module.rooturl,nurl)) then - x.parsehtml(http.document) - else - break - end + mangainfo.genres = genres + + local chapters = x.xpath('let $c := json(*).chapter return for $k in jn:keys($c) ' .. + 'return jn:object(object(("chapter_id", $k)), $c($k))') + for i = 1, chapters.count do + local v1 = chapters.get(i) + local lang = x.xpathstring('lang_code', v1) + if module.getoption('luashowalllang') or lang == 'gb' then + mangainfo.chapterlinks.add('/chapter/' .. x.xpathstring('chapter_id', v1)) + local s = string.format('Vol. %s Ch. %s', x.xpathstring('volume', v1), + x.xpathstring('chapter', v1)) + + local title = x.xpathstring('title', v1) + if title ~= '' then s = string.format('%s - %s', s, title); end + if module.getoption('luashowalllang') then + s = string.format('%s [%s]', s, getlang(lang)) + end + + if module.getoption('luashowscangroup') then + local group = x.xpathstring('group_name', v1) + local group2 = x.xpathstring('group_name_2', v1) + local group3 = x.xpathstring('group_name_3', v1) + if group2:len() > 0 and group2 ~= 'null' then + group = group .. ' | ' .. group2 + end + if group3:len() > 0 and group3 ~= 'null' then + group = group .. ' | ' .. group3 + end + s = string.format('%s [%s]', s, group) + end + + mangainfo.chapternames.add(s) + end end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error else @@ -45,6 +65,104 @@ function getinfo() end end +function getgenre(genre) + local genres = { + ["1"] = "4-koma", + ["2"] = "Action", + ["3"] = "Adventure", + ["4"] = "Award Winning", + ["5"] = "Comedy", + ["6"] = "Cooking", + ["7"] = "Doujinshi", + ["8"] = "Drama", + ["9"] = "Ecchi", + ["10"] = "Fantasy", + ["11"] = "Gender Bender", + ["12"] = "Harem", + ["13"] = "Historical", + ["14"] = "Horror", + ["15"] = "Josei", + ["16"] = "Martial Arts", + ["17"] = "Mecha", + ["18"] = "Medical", + ["19"] = "Music", + ["20"] = "Mystery", + ["21"] = "Oneshot", + ["22"] = "Psychological", + ["23"] = "Romance", + ["24"] = "School Life", + ["25"] = "Sci-Fi", + ["26"] = "Seinen", + ["27"] = "Shoujo", + ["28"] = "Shoujo Ai", + ["29"] = "Shounen", + ["30"] = "Shounen Ai", + ["31"] = "Slice of Life", + ["32"] = "Smut", + ["33"] = "Sports", + ["34"] = "Supernatural", + ["35"] = "Tragedy", + ["36"] = "Webtoon", + ["37"] = "Yaoi", + ["38"] = "Yuri", + ["39"] = "[no chapters]", + ["40"] = "Game", + ["41"] = "Isekai" + } + if genres[genre] ~= nil then + return genres[genre] + else + return genre + end +end + +function getlang(lang) + local langs = { + ["sa"] = "Arabic", + ["bd"] = "Bengali", + ["bg"] = "Bulgarian", + ["mm"] = "Burmese", + ["ct"] = "Catalan", + ["cn"] = "Chinese (Simp)", + ["hk"] = "Chinese (Trad)", + ["cz"] = "Czech", + ["dk"] = "Danish", + ["nl"] = "Dutch", + ["gb"] = "English", + ["ph"] = "Filipino", + ["fi"] = "Finnish", + ["fr"] = "French", + ["de"] = "German", + ["gr"] = "Greek", + ["hu"] = "Hungarian", + ["id"] = "Indonesian", + ["it"] = "Italian", + ["jp"] = "Japanese", + ["kr"] = "Korean", + ["my"] = "Malay", + ["mn"] = "Mongolian", + ["ir"] = "Persian", + ["pl"] = "Polish", + ["br"] = "Portuguese (Br)", + ["pt"] = "Portuguese (Pt)", + ["ro"] = "Romanian", + ["ru"] = "Russian", + ["rs"] = "Serbo-Croatian", + ["es"] = "Spanish (Es)", + ["mx"] = "Spanish (LATAM)", + ["se"] = "Swedish", + ["th"] = "Thai", + ["tr"] = "Turkish", + ["ua"] = "Ukrainian", + ["vn"] = "Vietnamese" + } + if langs[lang] ~= nil then + return langs[lang] + else + return langs + end +end + function getpagenumber() http.cookies.values['mangadex_h_toggle'] = '1' local chapterid = url:match('chapter/(%d+)') From 3a63747a5514d972fe9b3582b3c5024158cd2c62 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 29 Dec 2018 10:16:06 +0300 Subject: [PATCH 2708/2794] MangaDex, fix --- lua/modules/MangaDex.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 93b4ca2cc..d6b5bf04b 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -2,6 +2,7 @@ function getinfo() mangainfo.url=MaybeFillHost(module.rooturl,url) http.cookies.values['mangadex_h_toggle'] = '1' local id = url:match('title/(%d+)') + if id == nil then id = url:match('manga/(%d+)'); end if http.get(MaybeFillHost(module.rooturl, '/api/manga/' .. id)) then local resp = HTMLEncode(StreamToString(http.document)) local x = TXQuery.Create(resp) @@ -14,7 +15,7 @@ function getinfo() mangainfo.authors = x.xpathstring('manga/author', info) mangainfo.artists = x.xpathstring('manga/artist', info) mangainfo.summary = x.xpathstring('manga/description', info) - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('manga/status', info), '1', '0') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('manga/status', info), '1', '2') local genres = '' local v = x.xpath('jn:members(manga/genres)', info) From 8c8bd4f386b55f68c5577e740046347d02ed273b Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 30 Dec 2018 06:22:03 +0300 Subject: [PATCH 2709/2794] MangaDex, don't show delayed chapters fixes #1587 --- lua/modules/MangaDex.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index d6b5bf04b..9c82c918b 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -31,7 +31,8 @@ function getinfo() for i = 1, chapters.count do local v1 = chapters.get(i) local lang = x.xpathstring('lang_code', v1) - if module.getoption('luashowalllang') or lang == 'gb' then + local ts = tonumber(x.xpathstring('timestamp', v1)) + if (module.getoption('luashowalllang') or lang == 'gb') and (ts <= os.time()) then mangainfo.chapterlinks.add('/chapter/' .. x.xpathstring('chapter_id', v1)) local s = string.format('Vol. %s Ch. %s', x.xpathstring('volume', v1), x.xpathstring('chapter', v1)) From f354680061b9e94807f0c82675c2f70feece09a8 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 30 Dec 2018 07:14:56 +0300 Subject: [PATCH 2710/2794] MangaPark, rewrite to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaPark.pas | 158 -------------------------------- lua/modules/MangaPark.lua | 76 +++++++++++++++ 3 files changed, 76 insertions(+), 159 deletions(-) delete mode 100644 baseunits/modules/MangaPark.pas create mode 100644 lua/modules/MangaPark.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index e452a2227..9a30a0ff3 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -24,7 +24,6 @@ uses SenManga, MangaInn, LeoManga, - MangaPark, MangaIndo, MyMangaMe, GoodManga, diff --git a/baseunits/modules/MangaPark.pas b/baseunits/modules/MangaPark.pas deleted file mode 100644 index 0f5af3ad7..000000000 --- a/baseunits/modules/MangaPark.pas +++ /dev/null @@ -1,158 +0,0 @@ -unit MangaPark; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, strutils; - -implementation - -const - dirurl = '/search?orderby=add'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := StrToIntDef(SeparateRight( - XPathString('//ul[@class="paging full"]/li[last()-2]/a/@href'), 'page='), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - s := Module.RootURL + dirurl; - if AURL <> '0' then - s += '&page=' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//*[@class="manga-list"]/div//td/h2/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v, x: IXQValue; - s, t: String; - i: Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="cover"]/img/@src')); - if title = '' then title := Trim(XPathString('//*[@class="content"]//h1')); - if AnsiEndsStr(' Manga', title) then title := LeftStr(title, Length(title) - 6) - else if AnsiEndsStr(' Manhwa', title) then title := LeftStr(title, Length(title) - 7); - authors := XPathStringAll('//table[@class="attr"]//tr/th[.="Author(s)"]/following-sibling::td/a'); - artists := XPathStringAll('//table[@class="attr"]//tr/th[.="Artist(s)"]/following-sibling::td/a'); - genres := XPathStringAll('//table[@class="attr"]//tr/th[.="Genre(s)"]/following-sibling::td/a'); - status := MangaInfoStatusIfPos(XPathString( - '//table[@class="attr"]//tr/th[.="Status"]/following-sibling::td'), - 'Ongoing', - 'Completed'); - summary := XPathString('//*[@class="content"]/p[@class="summary"]'); - for v in XPath('//*[@id="list"]/*[contains(@id,"stream")]') do - begin - s := Trim(XPathString('h3', v.toNode)); - x := XPath('div/ul/li/span', v.toNode); - for i := x.Count downto 1 do - begin - t := XPathString('a/@href', x.get(i).toNode); - if RightStr(t, 2) = '/1' then - SetLength(t, Length(t) - 2); - chapterLinks.Add(t); - t := x.get(i).toString; - if s <> '' then - t := s + ' ' + t; - chapterName.Add(t); - end; - end; - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - s := MaybeFillHost(Module.RootURL, AURL); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - if GET(s) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - XPathStringAll('//img[@class="img"]/@src', PageLinks); - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaPark'; - RootURL := 'http://mangapark.me'; - Category := 'English'; - SortedList := True; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/MangaPark.lua b/lua/modules/MangaPark.lua new file mode 100644 index 000000000..bdf31400b --- /dev/null +++ b/lua/modules/MangaPark.lua @@ -0,0 +1,76 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h2'):gsub(' Manga$', '') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[contains(@class, "cover")]/img/@src')) + mangainfo.authors=x.xpathstringall('//table[@class="attr"]//tr[contains(th,"Author")]/td/a') + mangainfo.artists=x.xpathstringall('//table[@class="attr"]//tr[contains(th,"Artist")]/td/a') + mangainfo.genres=x.xpathstringall('//table[@class="attr"]//tr[contains(th,"Genre")]/td/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//table[@class="attr"]//tr[contains(th,"Status")]/td')) + mangainfo.summary=x.xpathstring('//p[@class="summary"]') + local v = x.xpath('//div[@id="list"]/div[contains(@class, "stream")]') + for i = 1, v.count do + local v1 = v.get(i) + local stream = ' [' .. x.xpathstring('div[@id]//a/span', v1) .. ']' + local w = x.xpath('div/ul[@class="chapter"]/li', v1) + for j = 1, w.count do + local w1 = w.get(j) + local link = x.xpathstring('div/a/@href', w1) + local title = x.xpathstring('div/a', w1) .. x.xpathstring('div[contains(@class, "txt")]', w1) + mangainfo.chapterlinks.add(link:gsub('/%d+$', '')) + mangainfo.chapternames.add(title .. stream) + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//a[@class="img-link"]/img[@class="img"]/@src', task.pagelinks) + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/search?orderby=create') then + local x = TXQuery.Create(http.Document) + page = tonumber(x.xpathstring('(//div[@id="paging-bar"])[2]/ul/li[last()-2]/a/substring-after(@href, "page=")')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl .. '/search?orderby=create&page=' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//div[@class="manga-list"]//table//h2/a', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'MangaPark' + m.rooturl = 'https://mangapark.me' + m.category = 'English' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' + m.sortedlist = true +end \ No newline at end of file From 3afd2df613051686e81766ac98f5dfbd5fab0384 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 30 Dec 2018 13:25:24 +0300 Subject: [PATCH 2711/2794] ChibiManga, update fixes #1578 --- lua/modules/myReaderMangaCMS.lua | 1 - lua/modules/rawdevart.lua | 27 ++++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 6e7e4915b..d6f19c7d7 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -106,7 +106,6 @@ function Init() c='English-Scanlation' AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); - AddWebsiteModule('ChibiManga','http://www.cmreader.info', c); AddWebsiteModule('WhiteCloudPavilion','https://whitecloudpavilion.com', c); AddWebsiteModule('HatigarmScans', 'https://www.hatigarmscans.net', c) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index de3b48cb7..ae42cb588 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -26,14 +26,26 @@ end function getpagenumber() task.pagelinks.clear() local aurl = MaybeFillHost(module.rooturl, url) - if Pos('style=list', aurl) == 0 then - aurl = aurl .. '?style=list' - end - if http.get(aurl) then - x=TXQuery.Create(http.Document) - v=x.xpathstringall('//div[contains(@class, "page-break")]/img/@src', task.pagelinks) + if module.website == 'ChibiManga' then + if http.get(aurl) then + local x = TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "chapter_preloaded_images")]', task.pagelinks) + s = "{"..GetBetween("{", "}", s).."}" + x.parsehtml(s) + x.xpathstringall('let $c := json(*) return for $k in jn:keys($c) return $c($k)', task.pagelinks) + else + return false + end else - return false + if Pos('style=list', aurl) == 0 then + aurl = aurl .. '?style=list' + end + if http.get(aurl) then + local x = TXQuery.Create(http.Document) + x.xpathstringall('//div[contains(@class, "page-break")]/img/@src', task.pagelinks) + else + return false + end end return true end @@ -73,4 +85,5 @@ function Init() cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) AddWebsiteModule('ZeroScans', 'https://zeroscans.com', cat) + AddWebsiteModule('ChibiManga','http://www.cmreader.info', cat); end From 762377030b8d385c38f67302255636ef9ce98931 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 30 Dec 2018 14:37:58 +0300 Subject: [PATCH 2712/2794] add scan-fr.io [fr] fixes #1565 --- lua/modules/myReaderMangaCMS.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index d6f19c7d7..2624c95d5 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -30,11 +30,11 @@ function GetInfo(); if module.Website == 'MangaDenizi' then mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') else - mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.=("Status","Estado")]/following-sibling::dd[1]')) + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.=("Status","Estado","Statut")]/following-sibling::dd[1]')) end - mangainfo.authors = x.XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)")]/following-sibling::dd[1]/string-join(*,", ")') - mangainfo.artists = x.XPathStringAll('//dt[.="Artist(s)"]/following-sibling::dd[1]/string-join(*,", ")') - mangainfo.genres = x.XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.authors = x.XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)","Auteur(s)")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.artists = x.XPathStringAll('//dt[.=("Artist(s)","Artiste(s)")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.genres = x.XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías","Catégories")]/following-sibling::dd[1]/string-join(*,", ")') mangainfo.summary = x.XPathString('//div[@class="well"]/p') v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') for i = 1, v.Count do @@ -115,4 +115,7 @@ function Init() AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com', c); AddWebsiteModule('SOSScanlation', 'http://sosscanlation.com', c); + + c='French' + AddWebsiteModule('ScanFR', 'https://www.scan-fr.io', c); end From eae88b712344bd7c1cdf7bfa636f08e0ee427240 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 1 Jan 2019 07:46:32 +0300 Subject: [PATCH 2713/2794] ac.qq.com, fix download fixes #1525 --- lua/modules/acqqcom.lua | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lua/modules/acqqcom.lua b/lua/modules/acqqcom.lua index 1c96ab603..07b32619b 100644 --- a/lua/modules/acqqcom.lua +++ b/lua/modules/acqqcom.lua @@ -16,12 +16,22 @@ end function getpagenumber() if http.get(MaybeFillHost(module.rooturl,url)) then x=TXQuery.Create(http.Document) - local s = x.xpathstring('//script[contains(., "var DATA")]') - s = GetBetween("= '", "',", s) - s = DecodeBase64(s:sub(2)) - x.parsehtml(s) - x.xpathstringall('json(*).picture().url', task.pagelinks) - return true + local s = x.xpathstring('//script[contains(., "window") and contains(., "eval")]') + local nonce = ExecJS('var window={};'..s..';window.nonce;'); + s = x.xpathstring('//script[contains(., "var DATA")]') + local data = ExecJS(s..';DATA;'); + local script = x.xpathstring('//script[contains(@src, "chapter")]/@src') + if http.get(script) then + s = StreamToString(http.document) + s = '!function(){eval'..GetBetween('!function(){eval', '))}();', s)..'))}();' + s = 'var W={nonce:"'..nonce..'",DATA:"'..data..'"};'..s..';JSON.stringify(_v);' + s = ExecJS(s) + x.parsehtml(s) + x.xpathstringall('json(*).picture().url', task.pagelinks) + return true + else + return false + end else return false end @@ -57,7 +67,7 @@ function Init() m=NewModule() m.category='Raw' m.website='AcQQCom' - m.rooturl='http://ac.qq.com' + m.rooturl='https://ac.qq.com' m.lastupdated='April 2, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' From 8ceaea38d7af989236c87e800fa135f933a117b3 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 1 Jan 2019 09:54:59 +0300 Subject: [PATCH 2714/2794] RawNeko, change domain --- lua/modules/rawdevart.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index ae42cb588..678693f32 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -80,7 +80,7 @@ end function Init() local cat = 'Raw' - AddWebsiteModule('RawNeko', 'http://mangaall.com', cat) + AddWebsiteModule('RawNeko', 'http://trueneko.online', cat) cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) From 8831a15358077541ee4e14ccb896ee7eada7975f Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 2 Jan 2019 09:29:18 +0300 Subject: [PATCH 2715/2794] ChampionScans, update fixes #1593 --- lua/modules/ComiCake.lua | 63 +++++++++++++++++++++++++++++++++++++++ lua/modules/FoOlSlide.lua | 1 - 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 lua/modules/ComiCake.lua diff --git a/lua/modules/ComiCake.lua b/lua/modules/ComiCake.lua new file mode 100644 index 000000000..d8627bd85 --- /dev/null +++ b/lua/modules/ComiCake.lua @@ -0,0 +1,63 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1/text()') + mangainfo.coverlink=x.xpathstring('//main//img/@src') + mangainfo.artists=x.xpathstringall('//main//table//tr[td="Artist:"]/td/a') + mangainfo.authors=x.xpathstringall('//main//table//tr[td="Author:"]/td/a') + mangainfo.genres=x.xpathstringall('//main//table//tr[td="Tags:"]/td/a') + mangainfo.summary=x.xpathstring('//main//pre') + x.xpathhrefall('//main//ul/li/span/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + if http.get(MaybeFillHost(module.rooturl,url..'/manifest.json')) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('json(*).readingOrder().href',task.pagelinks) + else + return false + end + return true +end + +function getdirectorypagenumber() + if http.get(module.rooturl..'/directory/') then + page=tonumber(TXQuery.Create(http.document).xpathstring('//div[@class="pagination"]//a[contains(., "last")]/@href'):match('/(%d+)/')) + return no_error + else + return net_problem + end +end + +function getnameandlink() + if http.get(module.rooturl..'/directory/'..IncStr(url)) then + TXQuery.Create(http.document).xpathhrefall('//div[@class="mdc-card__media-title"]/a',links,names) + return no_error + else + return net_problem + end +end + +function AddWebsiteModule(name, url, category) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = category + m.ongetinfo = 'getinfo' + m.OnGetPageNumber = 'getpagenumber' + m.OnGetImageURL = 'getimageurl' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' + m.OnGetNameAndLink = 'getnameandlink' + return m +end + +function Init() + local cat = 'English-Scanlation' + AddWebsiteModule('ChampionScans', 'https://reader.championscans.com', cat) +end diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 69ea6a800..33f0ab225 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -238,7 +238,6 @@ function Init() AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com', cat) AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com', cat) AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org', cat) - AddWebsiteModule('ChampionScans', 'http://reader.championscans.com', cat) AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org', cat) AddWebsiteModule('S2Scans', 'https://reader.s2smanga.com', cat) AddWebsiteModule('HotChocolateScans', 'http://hotchocolatescans.com', cat) From 99d05d94f4fc888989618de144cec36e105edf26 Mon Sep 17 00:00:00 2001 From: rs3mk Date: Wed, 2 Jan 2019 02:38:44 -0500 Subject: [PATCH 2716/2794] add scan Mangasubes --- lua/modules/FoOlSlide.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 33f0ab225..07f6eff7d 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -290,4 +290,5 @@ function Init() AddWebsiteModule('TrueColorsScan', 'https://truecolorsscans.miocio.org', cat) AddWebsiteModule('MangajinNoFansub', 'https://www.mangajinnofansub.com', cat) AddWebsiteModule('LoliVault', 'https://lolivault.net', cat) + AddWebsiteModule('Mangasubes', 'http://mangasubes.patyscans.com', cat) end From d0ff5352faf2e8b7c6bbb16ac662cc18fd8a6873 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 2 Jan 2019 19:26:07 +0300 Subject: [PATCH 2717/2794] HitomiLa, rewrite to lua --- baseunits/ModuleList.inc | 1 - baseunits/modules/HitomiLa.pas | 156 --------------------------------- lua/modules/HitomiLa.lua | 80 +++++++++++++++++ 3 files changed, 80 insertions(+), 157 deletions(-) delete mode 100644 baseunits/modules/HitomiLa.pas create mode 100644 lua/modules/HitomiLa.lua diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 9a30a0ff3..ee93b01e4 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -54,6 +54,5 @@ uses EHentai, Luscious, EightMuses, - HitomiLa, HentaiCafe, Hentai2Read; diff --git a/baseunits/modules/HitomiLa.pas b/baseunits/modules/HitomiLa.pas deleted file mode 100644 index 4e88a7172..000000000 --- a/baseunits/modules/HitomiLa.pas +++ /dev/null @@ -1,156 +0,0 @@ -unit HitomiLa; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil, RegExpr; - -implementation - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - source: TStringList; - i: Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL) then begin - Result := NO_ERROR; - source := TStringList.Create; - try - source.LoadFromStream(MangaInfo.FHTTP.Document); - if source.Count > 0 then - for i := 0 to source.Count - 1 do begin - if Pos('insert_paging(', source[i]) > 0 then begin - Page := StrToIntDef(GetString(source[i], ', 1, ', ');'), 1); - Break; - end; - end; - finally - source.Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL; - if AURL <> '0' then - s := s + '/index-all-' + IncStr(AURL) + '.html'; - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="gallery-content"]/div/h1/a') do - begin - ANames.Add(v.toString); - ALinks.Add(v.toNode.getAttribute('href')); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - MangaInfo.mangaInfo.website := Module.Website; - if MangaInfo.FHTTP.GET(FillHost(Module.RootURL, AURL)) then begin - Result := NO_ERROR; - with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - coverLink := FillURLProtocol('https://', XPathString('//div[@class="cover"]//img/@src')); - title := Trim(ReplaceRegExpr('( by.*)?- Read Online.*$', XPathString('//title'), '', False)); - if title = '' then - title := GetBetween('/galleries/', '.html', AnsiLowerCase(AURL)); - artists := TitleCase(XPathString('//div[starts-with(@class,"gallery")]/h2/ul/li/a')); - genres := ''; - for v in XPath('//div[@class="gallery-info"]/table//tr/td//a') do - AddCommaString(genres, TitleCase(v.toString)); - s := XPathString('//div[@class="cover-column"]/a/@href'); - if (s <> '') and (title <> '') then begin - chapterLinks.Add(s); - chapterName.Add(title); - end; - finally - Free; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - galleryid: Integer; - subdomain: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//div[@class="img-url"]') do - PageLinks.Add(FillURLProtocol('https://', v.toString)); - PageNumber := PageLinks.Count; - // https://ltn.hitomi.la/reader.js - if PageLinks.Count <> 0 then - begin - galleryid := -1; - subdomain := ''; - galleryid := StrToIntDef(ReplaceRegExpr('(?i)^.*reader/(\d+).*$', AURL, '$1', True), -1); - if galleryid <> -1 then - begin - subdomain := 'https://' + Char(97 + (galleryid mod 2)) + 'a.hitomi.la'; - FillHost(subdomain, PageLinks); - end; - end; - finally - Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'HitomiLa'; - RootURL := 'https://hitomi.la'; - Category := 'H-Sites'; - SortedList := True; - FavoriteAvailable := False; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/HitomiLa.lua b/lua/modules/HitomiLa.lua new file mode 100644 index 000000000..8fffff66a --- /dev/null +++ b/lua/modules/HitomiLa.lua @@ -0,0 +1,80 @@ +local domain = 'hitomi.la' + +function set_https(s) + if s:match('^//') then + return 'https:' .. s + else + return s + end +end + +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title = x.xpathstring('//div[starts-with(@class,"gallery")]/h1') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="cover"]//img/@src')) + mangainfo.coverlink = set_https(mangainfo.coverlink) + mangainfo.authors=x.xpathstringall('//div[starts-with(@class,"gallery")]/h2/ul/li/a') + mangainfo.genres=x.xpathstringall('//div[@class="gallery-info"]/table//tr/td//a') + mangainfo.chapterlinks.add(x.xpathstring('//div[contains(@class,"cover-column")]/a/@href')) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local subdomain = nil + local galleryid = tonumber(ReplaceRegExpr('(?i)^.*reader/(\\d+).*$', url, '$1')) + if galleryid ~= nil then + subdomain = string.char(97 + (galleryid % 2)) .. 'a.' ..domain + end + local x=TXQuery.Create(http.Document) + local v=x.xpath('//div[@class="img-url"]') + for i=1,v.count do + local s=v.get(i).toString + if subdomain ~= nil then + s=s:gsub('//[^/]+/', '//'..subdomain..'/') + end + s = set_https(s) + task.pagelinks.add(s) + end + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl) then + local x = TXQuery.Create(http.Document) + if http.get('https://ltn.'..domain..'/index-all.nozomi') then + local s = StreamToString(http.document) + for i=1,s:len(),4 do + local b1,b2,b3,b4=s:byte(i),s:byte(i+1),s:byte(i+2),s:byte(i+3) + local n = b4 + (b3 << 8) + (b2 << 16) + (b1 << 24) + links.add('https://'..domain..'/galleries/'..n..'.html') + names.add('') + end + return no_error + end + end + return net_problem +end + +function Init() + local m = NewModule() + m.website = 'HitomiLa' + m.rooturl = 'https://'..domain + m.category = 'H-Sites' + m.sortedlist=true + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end \ No newline at end of file From d9a3df1fd237c51c0608ca6c8836eaec263b4e7b Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 09:01:50 +0300 Subject: [PATCH 2718/2794] MerakiScans, rewrite fixes #1598 --- lua/modules/MerakiScans.lua | 71 +++++++++++++++++++++++++++++++++++++ lua/modules/WPManga.lua | 1 - 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 lua/modules/MerakiScans.lua diff --git a/lua/modules/MerakiScans.lua b/lua/modules/MerakiScans.lua new file mode 100644 index 000000000..8fae86d3e --- /dev/null +++ b/lua/modules/MerakiScans.lua @@ -0,0 +1,71 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//*[@id="manga_name"]') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//img[@id="cover_img"]/@src')) + mangainfo.authors=x.xpathstring('//ul[@id="detail_list"]/li[contains(., "Author")]/substring-after(., ":")') + mangainfo.artists=x.xpathstring('//ul[@id="detail_list"]/li[contains(., "Artist")]/substring-after(., ":")') + mangainfo.genres=x.xpathstringall('//ul[@id="detail_list"]/li[contains(., "Genres")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@id="detail_list"]/li[contains(., "Status")]')) + mangainfo.summary=x.xpathstring('//ul[@id="detail_list"]/span') + local v = x.xpath('//table[@id="chapter_table"]//tr') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(MaybeFillHost(module.RootURL, v1.getAttribute("data-href"))) + mangainfo.chapternames.add(x.xpathstring("./td[1]", v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x = TXQuery.Create(http.Document) + local curCh = x.xpathstring('//select[@id="chapter_select"]/option[@selected]/@value') + local s = x.xpathstring('//script[contains(., "images")]') + local slug = Trim(GetBetween("var manga_slug =", ";", s):gsub('"', '')) + s = GetBetween("var images =", ";", s) + x.parsehtml(s) + local v = x.xpath('json(*)()') + for i = 1, v.count do + s = string.format("/manga/%s/%s/%s", slug, curCh, v.get(i).toString) + task.pagelinks.add(MaybeFillHost(module.rooturl, s)) + end + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/manga/') then + local x = TXQuery.Create(http.Document) + local v = x.xpath('//div[@id="all"]/div[@id="listitem"]/a') + for i = 1, v.count do + local v1 = v.get(i) + links.add(v1.getAttribute('href')) + names.add(x.xpathstring('./h1', v1)) + end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'MerakiScans' + m.rooturl = 'https://merakiscans.com' + m.category = 'English-Scanlation' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 41c78aef1..1c1dea52f 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -201,7 +201,6 @@ function Init() cat = 'English-Scanlation' AddWebsiteModule('MangaCow', 'http://mngcow.co', cat) - AddWebsiteModule('MerakiScans', 'http://merakiscans.com', cat) cat = "Arabic-Scanlation" AddWebsiteModule('3asq', 'http://www.3asq.info', cat) From 62a89c0dac0de4aa8a5ecc813fdb7511ff0fc4da Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 09:40:31 +0300 Subject: [PATCH 2719/2794] MangaID, change domain --- lua/modules/myReaderMangaCMS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 2624c95d5..de8352bae 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -91,7 +91,7 @@ function Init() c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); - AddWebsiteModule('MangaID', 'http://mangaid.net', c); + AddWebsiteModule('MangaID', 'https://mangaid.me', c); AddWebsiteModule('KomikGue', 'https://www.komikgue.com', c); c='Raw' From 0786a694476d292db6eeb379298e8bbf0f086f8b Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 09:41:01 +0300 Subject: [PATCH 2720/2794] add MangaYosh [id] --- lua/modules/rawdevart.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 678693f32..6b2e19204 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -14,7 +14,7 @@ function getinfo() mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="summary-heading" and contains(h5, "Status")]/following-sibling::div/div/a')) - mangainfo.summary=x.xpathstring('//div[@class="summary__content"]/p') + mangainfo.summary=x.xpathstring('//div[contains(@class,"summary__content")]/p') x.XPathHREFAll('//li[@class="wp-manga-chapter"]/a', mangainfo.chapterlinks, mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error @@ -85,5 +85,8 @@ function Init() cat = 'English-Scanlation' AddWebsiteModule('TrashScanlations', 'https://trashscanlations.com', cat) AddWebsiteModule('ZeroScans', 'https://zeroscans.com', cat) - AddWebsiteModule('ChibiManga','http://www.cmreader.info', cat); + AddWebsiteModule('ChibiManga','http://www.cmreader.info', cat) + + cat = 'Indonesian' + AddWebsiteModule('MangaYosh', 'https://mangayosh.com', cat) end From a5e8e4c1c8270c1198313ac67489dffe0fa302aa Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 09:57:44 +0300 Subject: [PATCH 2721/2794] add Kiryuu [id] --- lua/modules/MangaShiro.lua | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index dd5a8e76e..e2e9da063 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -17,9 +17,13 @@ function getinfo() mangainfo.genres=x.xpathstringall('//div[@class="infozin"]//li[starts-with(.,"Genre")]/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="infozin"]//li[starts-with(.,"Status")]'), "Publishing", "Finished") mangainfo.summary=x.xpathstringall('//*[@class="sinopc"]/p/text()', '') - elseif module.website == 'MangaShiro' then + elseif module.website == 'MangaShiro' or module.website == 'Kiryuu' then mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@itemprop="image"]/img/@src')) + local img = x.xpathstring('//div[@itemprop="image"]/img/@data-lazy-src') + if img == '' then + img = x.xpathstring('//div[@itemprop="image"]/img/@src') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, img) mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') mangainfo.genres=x.xpathstringall('//div[contains(@class,"animeinfo")]/div[@class="gnr"]/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) @@ -49,7 +53,10 @@ function getpagenumber() if module.website == 'WestManga' then TXQuery.Create(http.Document).xpathstringall('//*[@class="lexot"]//img/@src', task.pagelinks) else - TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@data-lazy-src', task.pagelinks) + if task.pagelinks.count < 1 then + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + end end return true else @@ -58,11 +65,16 @@ function getpagenumber() end function getnameandlink() + local dirs = { + ['MangaShiro'] = '/daftar-manga/?list', + ['KomikStation'] = '/daftar-komik/', + ['KomikCast'] = '/daftar-komik/?list', + ['MangaKid'] = '/manga-lists/', + ['Kiryuu'] = '/manga-lists/?list', + } local dirurl = '/manga-list/' - if module.website == 'MangaShiro' then dirurl = '/daftar-manga/?list' - elseif module.website == 'KomikStation' then dirurl = '/daftar-komik/' - elseif module.website == 'KomikCast' then dirurl = '/daftar-komik/?list' - elseif module.website == 'MangaKid' then dirurl = '/manga-lists/' + if dirs[module.website] ~= nil then + dirurl = dirs[module.website] end if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then @@ -97,4 +109,5 @@ function Init() AddWebsiteModule('MangaKid', 'http://mangakid.net') AddWebsiteModule('KomikCast', 'https://komikcast.com') AddWebsiteModule('WestManga', 'https://westmanga.info') + AddWebsiteModule('Kiryuu', 'https://kiryuu.co') end From a3f280b1d1cce075f86bba745193eb4e39bf0d08 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 09:58:49 +0300 Subject: [PATCH 2722/2794] MangaShiro, use https --- lua/modules/MangaShiro.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index e2e9da063..39dd8e617 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -103,7 +103,7 @@ function AddWebsiteModule(site, url) end function Init() - AddWebsiteModule('MangaShiro', 'http://mangashiro.net') + AddWebsiteModule('MangaShiro', 'https://mangashiro.net') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') AddWebsiteModule('KomikStation', 'http://www.komikstation.com') AddWebsiteModule('MangaKid', 'http://mangakid.net') From 9f7d7c81bb2363d17cb100e41e9c5ab2af775c43 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 10:00:32 +0300 Subject: [PATCH 2723/2794] KomikStation, use https --- lua/modules/MangaShiro.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 39dd8e617..2bcf3309f 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -105,7 +105,7 @@ end function Init() AddWebsiteModule('MangaShiro', 'https://mangashiro.net') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') - AddWebsiteModule('KomikStation', 'http://www.komikstation.com') + AddWebsiteModule('KomikStation', 'https://www.komikstation.com') AddWebsiteModule('MangaKid', 'http://mangakid.net') AddWebsiteModule('KomikCast', 'https://komikcast.com') AddWebsiteModule('WestManga', 'https://westmanga.info') From 8a3da373dc2788ab62a8049574d4fe1e06e032fd Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 10:02:07 +0300 Subject: [PATCH 2724/2794] MangaKid, change domain --- lua/modules/MangaShiro.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 2bcf3309f..d03eafe18 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -106,7 +106,7 @@ function Init() AddWebsiteModule('MangaShiro', 'https://mangashiro.net') AddWebsiteModule('MangaKita', 'http://www.mangakita.net') AddWebsiteModule('KomikStation', 'https://www.komikstation.com') - AddWebsiteModule('MangaKid', 'http://mangakid.net') + AddWebsiteModule('MangaKid', 'http://mgku.net') AddWebsiteModule('KomikCast', 'https://komikcast.com') AddWebsiteModule('WestManga', 'https://westmanga.info') AddWebsiteModule('Kiryuu', 'https://kiryuu.co') From be00cc78a982ad4e164dcf5242d94e8512d0cb00 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 10:12:28 +0300 Subject: [PATCH 2725/2794] add KomikOtaku [id] --- lua/modules/MangaShiro.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index d03eafe18..38de088a1 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -33,6 +33,9 @@ function getinfo() x.xpathhrefall('//div[@class="bxcl"]//li//div[@class="lch"]/a', mangainfo.chapterlinks, mangainfo.chapternames) else mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1'):gsub('Bahasa Indonesia$', '') + end mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') @@ -110,4 +113,5 @@ function Init() AddWebsiteModule('KomikCast', 'https://komikcast.com') AddWebsiteModule('WestManga', 'https://westmanga.info') AddWebsiteModule('Kiryuu', 'https://kiryuu.co') + AddWebsiteModule('KomikOtaku', 'https://komikotaku.net') end From 7fbfe92b06d6f16f332d3a96075f4b695edfca6b Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 10:39:12 +0300 Subject: [PATCH 2726/2794] MangaKita, fix get info --- lua/modules/MangaShiro.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 38de088a1..568db5195 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -31,6 +31,21 @@ function getinfo() mangainfo.chapterlinks.clear() mangainfo.chapternames.clear() x.xpathhrefall('//div[@class="bxcl"]//li//div[@class="lch"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + elseif module.website == 'MangaKita' then + mangainfo.title=x.xpathstring('//h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[contains(@class,"leftImage")]/img/@src')) + mangainfo.authors=x.xpathstring('//span[@class="details"]//div[starts-with(.,"Author")]/substring-after(.,":")') + mangainfo.genres=x.xpathstringall('//span[@class="details"]//div[starts-with(.,"Genre")]/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//span[@class="details"]//div[starts-with(.,"Status")]')) + mangainfo.summary=x.xpathstringall('//*[@class="description"]/text()', '') + mangainfo.chapterlinks.clear() + mangainfo.chapternames.clear() + local v = x.xpath('//div[contains(@class, "chapter-list")]/a') + for i = 1, v.count do + local v1 = v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('href')) + mangainfo.chapternames.add(x.xpathstring('./span', v1)) + end else mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') if mangainfo.title == '' then @@ -82,7 +97,7 @@ function getnameandlink() if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) - elseif module.website == 'WestManga' then + elseif module.website == 'WestManga' or module.website == 'MangaKita' then TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) else TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) From 61be16b19b38e848b3e5306edacdcb33d4d04229 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 10:44:56 +0300 Subject: [PATCH 2727/2794] WestManga, fix all --- lua/modules/MangaShiro.lua | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 568db5195..a103e827e 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -3,20 +3,13 @@ function getinfo() if http.get(mangainfo.url) then x=TXQuery.Create(http.document) x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) - if module.website == 'KomikCast' then + if module.website == 'KomikCast' or module.website == 'WestManga' then mangainfo.title=x.xpathstring('//div[@class="mangainfo"]/h1') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="topinfo"]/img/@src')) mangainfo.authors=x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Author")]/td') mangainfo.genres=x.xpathstringall('//div[@class="topinfo"]//tr[contains(th, "Genres")]/td/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstringall('//*[@class="sin"]/p/text()', '') - elseif module.website == 'WestManga' then - mangainfo.title=x.xpathstring('//h1') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="naru"]/img/@src')) - mangainfo.authors=x.xpathstring('//div[@class="infozin"]//li[starts-with(.,"Author")]/substring-after(.,":")') - mangainfo.genres=x.xpathstringall('//div[@class="infozin"]//li[starts-with(.,"Genre")]/a') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="infozin"]//li[starts-with(.,"Status")]'), "Publishing", "Finished") - mangainfo.summary=x.xpathstringall('//*[@class="sinopc"]/p/text()', '') elseif module.website == 'MangaShiro' or module.website == 'Kiryuu' then mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') local img = x.xpathstring('//div[@itemprop="image"]/img/@data-lazy-src') @@ -68,13 +61,9 @@ function getpagenumber() task.pagenumber=0 task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl,url)) then - if module.website == 'WestManga' then - TXQuery.Create(http.Document).xpathstringall('//*[@class="lexot"]//img/@src', task.pagelinks) - else - TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@data-lazy-src', task.pagelinks) - if task.pagelinks.count < 1 then - TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) - end + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@data-lazy-src', task.pagelinks) + if task.pagelinks.count < 1 then + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) end return true else @@ -89,6 +78,7 @@ function getnameandlink() ['KomikCast'] = '/daftar-komik/?list', ['MangaKid'] = '/manga-lists/', ['Kiryuu'] = '/manga-lists/?list', + ['WestManga'] = '/manga-list/?list', } local dirurl = '/manga-list/' if dirs[module.website] ~= nil then From 04f9348a544da1dee9e0f597b535e41fc003d48c Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 10:56:38 +0300 Subject: [PATCH 2728/2794] PecintaKomik, rewrite closes #1583 --- baseunits/ModuleList.inc | 1 - baseunits/modules/PecintaKomik.pas | 144 ----------------------------- lua/modules/MangaShiro.lua | 12 +++ 3 files changed, 12 insertions(+), 145 deletions(-) delete mode 100644 baseunits/modules/PecintaKomik.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ee93b01e4..478cf6d4e 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -1,7 +1,6 @@ uses MangaFox, Mangacan, - PecintaKomik, MangaReader, MangaLife, MangaHere, diff --git a/baseunits/modules/PecintaKomik.pas b/baseunits/modules/PecintaKomik.pas deleted file mode 100644 index f8251ac98..000000000 --- a/baseunits/modules/PecintaKomik.pas +++ /dev/null @@ -1,144 +0,0 @@ -unit PecintaKomik; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/directory/'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//section[@class="cols"]//div[@class="col-cnt"]/ul/li/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - query.Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink := query.XPathString('//section[@class="post"]/img/@src'); - if coverLink <> '' then coverLink := MaybeFillHost(Module.RootURL, coverLink); - if title = '' then title := query.XPathString('//div[@class="post-cnt"]/h2'); - for v in query.XPath('(//div[@class="post-cnt"])[1]/ul/li') do begin - s := v.toString; - if Pos('Author(s):', s) = 1 then authors := SeparateRight(s, ':') else - if Pos('Artist(s):', s) = 1 then artists := SeparateRight(s, ':') else - if Pos('Genre:', s) = 1 then genres := SeparateRight(s, ':') else - if Pos('Sinopsis:', s) = 1 then summary := SeparateRight(s, ':'); - end; - for v in query.XPath('(//div[@class="post-cnt"])[2]/ul/li/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(query.XPathString('text()', v.toNode)); - end; - InvertStrings([chapterLinks, chapterName]) - finally - query.Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber := query.XPath('//select[@name="page"]/option').Count; - finally - query.Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - s, b: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := RemoveURLDelim(AURL); - if DownloadThread.WorkId > 0 then s += '/' + IncStr(DownloadThread.WorkId); - if GET(FillHost(Module.RootURL, s)) then begin - Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - b := query.XPathString('//base/@href'); - if b = '' then b := Module.RootURL; - s := query.XPathString('//img[@class="picture"]/@src'); - if s <> '' then PageLinks[DownloadThread.WorkId] := MaybeFillHost(b, s); - finally - query.Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'PecintaKomik'; - RootURL := 'http://www.pecintakomik.com'; - Category := 'Indonesian'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index a103e827e..9072aee80 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -24,6 +24,16 @@ function getinfo() mangainfo.chapterlinks.clear() mangainfo.chapternames.clear() x.xpathhrefall('//div[@class="bxcl"]//li//div[@class="lch"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + elseif module.website == 'PecintaKomik' then + mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]/*') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@itemprop="image"]/img/@src')) + mangainfo.authors=x.xpathstring('//table[@class="listinfo"]//tr[contains(th, "Penulis")]/td') + mangainfo.genres=x.xpathstringall('//table[@class="listinfo"]//tr[contains(th, "Genre")]/td/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//table[@class="listinfo"]//tr[contains(th, "Status")]/td')) + mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') + mangainfo.chapterlinks.clear() + mangainfo.chapternames.clear() + x.xpathhrefall('//div[@class="bxcl"]//li//*[@class="lchx"]/a', mangainfo.chapterlinks, mangainfo.chapternames) elseif module.website == 'MangaKita' then mangainfo.title=x.xpathstring('//h1') mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[contains(@class,"leftImage")]/img/@src')) @@ -79,6 +89,7 @@ function getnameandlink() ['MangaKid'] = '/manga-lists/', ['Kiryuu'] = '/manga-lists/?list', ['WestManga'] = '/manga-list/?list', + ['PecintaKomik'] = '/daftar-manga/?list', } local dirurl = '/manga-list/' if dirs[module.website] ~= nil then @@ -119,4 +130,5 @@ function Init() AddWebsiteModule('WestManga', 'https://westmanga.info') AddWebsiteModule('Kiryuu', 'https://kiryuu.co') AddWebsiteModule('KomikOtaku', 'https://komikotaku.net') + AddWebsiteModule('PecintaKomik', 'https://www.pecintakomik.com') end From e746e2ad5592d19a724aa979e77f0abc445d76ee Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 19:53:54 +0300 Subject: [PATCH 2729/2794] add KomikGo [id] --- lua/modules/rawdevart.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 6b2e19204..21a9cbf9a 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -89,4 +89,5 @@ function Init() cat = 'Indonesian' AddWebsiteModule('MangaYosh', 'https://mangayosh.com', cat) + AddWebsiteModule('KomikGo', 'https://komikgo.com', cat) end From 5b03e8205fd1e824ab1b445125f21f6b45be9fda Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 20:06:16 +0300 Subject: [PATCH 2730/2794] add ManhwaHentai [H] closes #1580 closes #1601 --- lua/modules/rawdevart.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 21a9cbf9a..71d021990 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -2,7 +2,7 @@ function getinfo() mangainfo.url=MaybeFillHost(module.RootURL, url) if http.get(mangainfo.url) then x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstringall('//div[@class="post-title"]/h3/text()', '') + mangainfo.title=x.xpathstringall('//div[@class="post-title"]/*[self::h1 or self::h2 or self::h3]/text()', '') if string.match(mangainfo.title:upper(), ' RAW$') ~= nil then mangainfo.title = mangainfo.title:sub(1, -5) end @@ -90,4 +90,7 @@ function Init() cat = 'Indonesian' AddWebsiteModule('MangaYosh', 'https://mangayosh.com', cat) AddWebsiteModule('KomikGo', 'https://komikgo.com', cat) + + cat = 'H-Sites' + AddWebsiteModule('ManhwaHentai', 'https://manhwahentai.com', cat) end From b71b3c83aea156083ce17ac87ac49574faa75b6c Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 20:35:28 +0300 Subject: [PATCH 2731/2794] add TimelessLeaf [en-sc] closes #1533 closes #1497 --- lua/modules/TimelessLeaf.lua | 45 ++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 lua/modules/TimelessLeaf.lua diff --git a/lua/modules/TimelessLeaf.lua b/lua/modules/TimelessLeaf.lua new file mode 100644 index 000000000..15ea47072 --- /dev/null +++ b/lua/modules/TimelessLeaf.lua @@ -0,0 +1,45 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1[@class="entry-title"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//article//img/@src')) + mangainfo.summary=x.xpathstringall('//div[@class="entry-content page-content"]/p[not(contains(., "Chapter"))]/text()', '') + x.xpathhrefall('//div[@class="entry-content page-content"]/p/a',mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//figure[@class="gallery-item"]//img/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/comic-list') then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//a[.="Manga"]/following-sibling::ul//li/a[not(contains(@href,"more"))]', links, names) + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'TimelessLeaf' + m.rooturl = 'https://timelessleaf.com' + m.category = 'English-Scanlation' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' +end \ No newline at end of file From 80a2f7e877145a40f8950779d5b7bae6c435e5d5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 4 Jan 2019 20:53:43 +0300 Subject: [PATCH 2732/2794] add MangaHasu [en] closes #1460 closes #1592 --- lua/modules/MangaHasu.lua | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 lua/modules/MangaHasu.lua diff --git a/lua/modules/MangaHasu.lua b/lua/modules/MangaHasu.lua new file mode 100644 index 000000000..ba3ca70bf --- /dev/null +++ b/lua/modules/MangaHasu.lua @@ -0,0 +1,68 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//div[@class="info-title"]/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[contains(@class, "info-img")]/img/@src')) + mangainfo.authors=x.xpathstringall('//div[contains(b, "Author")]/span/a') + mangainfo.artists=x.xpathstringall('//div[contains(b, "Artist")]/span/a') + mangainfo.genres=x.xpathstringall('//div[contains(b, "Genre")]/span/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[contains(b, "Status")]/span/a')) + mangainfo.summary=x.xpathstring('//h3[contains(.,"Summary")]/following-sibling::*') + x.xpathhrefall('//div[@class="list-chapter"]/table//td[@class="name"]/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function beforedownloadimage() + http.headers.values['Referer'] = module.rooturl + return true +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="img"]/img/@src', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/directory.html?page=' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('//ul[@class="list_manga"]/li//a[@class="name-manga"]', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/directory.html') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//div[@class="pagination-ct"]/a[last()]/substring-after(@href,"=")')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'MangaHasu' + m.rooturl = 'http://mangahasu.se' + m.category = 'English' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.onbeforedownloadimage='beforedownloadimage' + m.ongetdirectorypagenumber='getdirectorypagenumber' +end \ No newline at end of file From c2266fe3e0d23f94c771267e91eb65d5e224ff0d Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 5 Jan 2019 13:06:25 +0300 Subject: [PATCH 2733/2794] ReadComicOnline, fix cover link fixes #1603 --- baseunits/modules/KissManga.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index e0401c71a..7fa2fc27d 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -103,7 +103,7 @@ function GetInfo(const MangaInfo: TMangaInformation; Result := NO_ERROR; with MangaInfo.mangaInfo, TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do try - coverLink := XPathString('//div[@id="rightside"]//img/@src'); + coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@id="rightside"]//img/@src')); if title = '' then begin title := XPathString('//title'); From 34fceda64bc8ff98cbe5f6eb9461a4686494387a Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 5 Jan 2019 14:40:38 +0300 Subject: [PATCH 2734/2794] MangaDex, fix chapter names fixes #1604 --- lua/modules/MangaDex.lua | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 9c82c918b..9b07e2db9 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -34,11 +34,20 @@ function getinfo() local ts = tonumber(x.xpathstring('timestamp', v1)) if (module.getoption('luashowalllang') or lang == 'gb') and (ts <= os.time()) then mangainfo.chapterlinks.add('/chapter/' .. x.xpathstring('chapter_id', v1)) - local s = string.format('Vol. %s Ch. %s', x.xpathstring('volume', v1), - x.xpathstring('chapter', v1)) + + local s = '' + local vol = x.xpathstring('volume', v1) + local ch = x.xpathstring('chapter', v1) + if vol ~= '' then s = s .. string.format('Vol. %s', vol); end + if s ~= '' then s = s .. ' '; end + if ch ~= '' then s = s .. string.format('Ch. %s', ch); end local title = x.xpathstring('title', v1) - if title ~= '' then s = string.format('%s - %s', s, title); end + if title ~= '' then + if s ~= '' then s = s .. ' - '; end + s = s .. title + end + if module.getoption('luashowalllang') then s = string.format('%s [%s]', s, getlang(lang)) end @@ -225,6 +234,8 @@ function Init() m.maxtasklimit=1 m.maxconnectionlimit=2 + m.getinfodelay=5000 + m.getinfodelayafter=10 m.addoptioncheckbox('luashowalllang', 'Show all language', false) m.addoptioncheckbox('luashowscangroup', 'Show scanlation group', false) From 9844dc6028721830bba590b476a0ff2758bf99ae Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 5 Jan 2019 14:51:38 +0300 Subject: [PATCH 2735/2794] fix typo --- baseunits/lua/LuaWebsiteModules.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseunits/lua/LuaWebsiteModules.pas b/baseunits/lua/LuaWebsiteModules.pas index 273b45d05..65bbe4e73 100644 --- a/baseunits/lua/LuaWebsiteModules.pas +++ b/baseunits/lua/LuaWebsiteModules.pas @@ -824,7 +824,7 @@ procedure luaWebsiteModuleAddMetaTable(L: Plua_State; Obj: Pointer; luaClassAddBooleanProperty(L, MetaTable, 'FavoriteAvailable', @Module.FavoriteAvailable); luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', @Module.DynamicPageLink); - luaClassAddBooleanProperty(L, MetaTable, 'DynamicPageLink', + luaClassAddBooleanProperty(L, MetaTable, 'CloudflareEnabled', @Module.CloudflareEnabled); luaClassAddStringProperty(L, MetaTable, 'OnBeforeUpdateList', @OnBeforeUpdateList); luaClassAddStringProperty(L, MetaTable, 'OnAfterUpdateList', @OnAfterUpdateList); From e7e81612926bf961845a4966c8c10abab4801867 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 5 Jan 2019 20:10:08 +0300 Subject: [PATCH 2736/2794] add BoredomSociety [en-sc] closes #1577 --- lua/modules/BoredomSociety.lua | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 lua/modules/BoredomSociety.lua diff --git a/lua/modules/BoredomSociety.lua b/lua/modules/BoredomSociety.lua new file mode 100644 index 000000000..97effc8f5 --- /dev/null +++ b/lua/modules/BoredomSociety.lua @@ -0,0 +1,60 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('css("div.titlesinfo_top > h2")') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('css("img.titlesinfo_coverimage")/@src')) + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[contains(span, "Status")]/span[@class="titleinfo_infovalue"]')) + mangainfo.summary=x.xpathstringall('//div[contains(span, "Description")]/*[@class="titlesinfo_description"]/text()', '') + x.xpathhrefall('//table[@class="titlesinfo_chaptertable"]//td[3]/a',mangainfo.chapterlinks,mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + http.post(module.rooturl .. '/module/reader/ajax.php', 'readingtype=all') + http.reset() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="reader_mangaimagebox"]/img/@src', task.pagelinks) + return true + end + return false +end + +function getnameandlink() + if http.get(module.rooturl .. '/titles/page/' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('css("div.titlelist_name > a")', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/titles') then + x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//div[@class="titles_pages"]/a[last()-1]')) + if page == nil then page = 1 end + return no_error + else + return net_problem + end +end + +function Init() + local m = NewModule() + m.website = 'BoredomSociety' + m.rooturl = 'https://www.boredomsociety.xyz' + m.category = 'English-Scanlation' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber='getdirectorypagenumber' +end \ No newline at end of file From 897dae6fbea361cdcc312340572f94100f6c4e61 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 5 Jan 2019 22:42:23 +0300 Subject: [PATCH 2737/2794] register GetCurrentTime (in ms) to lua --- baseunits/lua/LuaBaseUnit.pas | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaBaseUnit.pas b/baseunits/lua/LuaBaseUnit.pas index 2d336c3e0..74480e510 100644 --- a/baseunits/lua/LuaBaseUnit.pas +++ b/baseunits/lua/LuaBaseUnit.pas @@ -12,7 +12,7 @@ procedure luaBaseUnitRegister(L: Plua_State); implementation uses - LuaUtils, MultiLog, htmlelements; + LuaUtils, MultiLog, htmlelements, dateutils; function lua_pos(L: Plua_State): Integer; cdecl; begin @@ -139,6 +139,12 @@ function lua_trimstrings(L: Plua_State): Integer; cdecl; TrimStrings(TStrings(luaGetUserData(L, 1))); end; +function lua_getcurrenttime(L: Plua_State): Integer; cdecl; +begin + lua_pushinteger(L, MilliSecondsBetween(Now, 0)); + Result := 1; +end; + procedure luaBaseUnitRegister(L: Plua_State); begin luaPushFunctionGlobal(L, 'Pos', @lua_pos); @@ -158,6 +164,7 @@ procedure luaBaseUnitRegister(L: Plua_State); luaPushFunctionGlobal(L, 'StreamToString', @lua_streamtostring); luaPushFunctionGlobal(L, 'Round', @lua_round); luaPushFunctionGlobal(L, 'TrimStrings', @lua_trimstrings); + luaPushFunctionGlobal(L, 'GetCurrentTime', @lua_getcurrenttime); end; end. From 1db552107451722289cb4276643416db2fa264c4 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 5 Jan 2019 22:52:46 +0300 Subject: [PATCH 2738/2794] ManhwaCo, change domain fixes #1605 --- lua/modules/ManhwaCo.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/ManhwaCo.lua b/lua/modules/ManhwaCo.lua index 6e97a0418..e8579c36a 100644 --- a/lua/modules/ManhwaCo.lua +++ b/lua/modules/ManhwaCo.lua @@ -6,7 +6,7 @@ function GetInfo() mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[contains(@class, "card-img-top")]/@src')) mangainfo.summary = x.XPathString('//p[@class="card-text"]') mangainfo.genres = x.XPathStringAll('//div[@class="chip"]') - v=x.xpath('//div[contains(@class, "list-group")]/a') + v=x.xpath('//ul[contains(@class, "list-group")]/li/a') for i=1,v.count do v1=v.get(i) mangainfo.chapterlinks.add(v1.getAttribute('href')) @@ -51,7 +51,7 @@ function Init() m=NewModule() m.category='English-Scanlation' m.website='ManhwaCo' - m.rooturl='https://manhwa.co' + m.rooturl='https://sleepypandascans.co' m.lastupdated='February 15, 2018' m.ongetinfo='GetInfo' m.ongetpagenumber='GetPageNumber' From 732d90ac0a9cef5d31551f23f80b339f1cc8903f Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 6 Jan 2019 08:57:40 +0300 Subject: [PATCH 2739/2794] MangaDex, select language option --- lua/modules/MangaDex.lua | 116 ++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 45 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 9b07e2db9..c6b2f0d33 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -26,13 +26,15 @@ function getinfo() end mangainfo.genres = genres + local selLang = module.getoption('lualang') + local selLangId = findlang(selLang) local chapters = x.xpath('let $c := json(*).chapter return for $k in jn:keys($c) ' .. 'return jn:object(object(("chapter_id", $k)), $c($k))') for i = 1, chapters.count do local v1 = chapters.get(i) local lang = x.xpathstring('lang_code', v1) local ts = tonumber(x.xpathstring('timestamp', v1)) - if (module.getoption('luashowalllang') or lang == 'gb') and (ts <= os.time()) then + if (selLang == 0 or lang == selLangId) and (ts <= os.time()) then mangainfo.chapterlinks.add('/chapter/' .. x.xpathstring('chapter_id', v1)) local s = '' @@ -48,7 +50,7 @@ function getinfo() s = s .. title end - if module.getoption('luashowalllang') then + if selLang == 0 then s = string.format('%s [%s]', s, getlang(lang)) end @@ -127,51 +129,73 @@ function getgenre(genre) end end +local langs = { + ["sa"] = "Arabic", + ["bd"] = "Bengali", + ["bg"] = "Bulgarian", + ["mm"] = "Burmese", + ["ct"] = "Catalan", + ["cn"] = "Chinese (Simp)", + ["hk"] = "Chinese (Trad)", + ["cz"] = "Czech", + ["dk"] = "Danish", + ["nl"] = "Dutch", + ["gb"] = "English", + ["ph"] = "Filipino", + ["fi"] = "Finnish", + ["fr"] = "French", + ["de"] = "German", + ["gr"] = "Greek", + ["hu"] = "Hungarian", + ["id"] = "Indonesian", + ["it"] = "Italian", + ["jp"] = "Japanese", + ["kr"] = "Korean", + ["my"] = "Malay", + ["mn"] = "Mongolian", + ["ir"] = "Persian", + ["pl"] = "Polish", + ["br"] = "Portuguese (Br)", + ["pt"] = "Portuguese (Pt)", + ["ro"] = "Romanian", + ["ru"] = "Russian", + ["rs"] = "Serbo-Croatian", + ["es"] = "Spanish (Es)", + ["mx"] = "Spanish (LATAM)", + ["se"] = "Swedish", + ["th"] = "Thai", + ["tr"] = "Turkish", + ["ua"] = "Ukrainian", + ["vn"] = "Vietnamese" +} + function getlang(lang) - local langs = { - ["sa"] = "Arabic", - ["bd"] = "Bengali", - ["bg"] = "Bulgarian", - ["mm"] = "Burmese", - ["ct"] = "Catalan", - ["cn"] = "Chinese (Simp)", - ["hk"] = "Chinese (Trad)", - ["cz"] = "Czech", - ["dk"] = "Danish", - ["nl"] = "Dutch", - ["gb"] = "English", - ["ph"] = "Filipino", - ["fi"] = "Finnish", - ["fr"] = "French", - ["de"] = "German", - ["gr"] = "Greek", - ["hu"] = "Hungarian", - ["id"] = "Indonesian", - ["it"] = "Italian", - ["jp"] = "Japanese", - ["kr"] = "Korean", - ["my"] = "Malay", - ["mn"] = "Mongolian", - ["ir"] = "Persian", - ["pl"] = "Polish", - ["br"] = "Portuguese (Br)", - ["pt"] = "Portuguese (Pt)", - ["ro"] = "Romanian", - ["ru"] = "Russian", - ["rs"] = "Serbo-Croatian", - ["es"] = "Spanish (Es)", - ["mx"] = "Spanish (LATAM)", - ["se"] = "Swedish", - ["th"] = "Thai", - ["tr"] = "Turkish", - ["ua"] = "Ukrainian", - ["vn"] = "Vietnamese" - } if langs[lang] ~= nil then return langs[lang] else - return langs + return 'Unknown' + end +end + +function getlanglist() + local t = {} + for k, v in pairs(langs) do table.insert(t, v); end + table.sort(t) + return t +end + +function findlang(lang) + local t = getlanglist() + for i, v in ipairs(t) do + if i == lang then + lang = v + break + end end + for k, v in pairs(langs) do + if v == lang then return k; end + end + return nil end function getpagenumber() @@ -234,9 +258,11 @@ function Init() m.maxtasklimit=1 m.maxconnectionlimit=2 - m.getinfodelay=5000 - m.getinfodelayafter=10 - m.addoptioncheckbox('luashowalllang', 'Show all language', false) m.addoptioncheckbox('luashowscangroup', 'Show scanlation group', false) + + local items = 'All' + local t = getlanglist() + for k, v in ipairs(t) do items = items .. '\r\n' .. v; end + m.addoptioncombobox('lualang', 'Language:', items, 0) end From da8a6fc6044d07dc5e4d040c23c850b6868be949 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 6 Jan 2019 09:50:46 +0300 Subject: [PATCH 2740/2794] MangaDex, set default lang --- lua/modules/MangaDex.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index c6b2f0d33..394dab81e 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -264,5 +264,5 @@ function Init() local items = 'All' local t = getlanglist() for k, v in ipairs(t) do items = items .. '\r\n' .. v; end - m.addoptioncombobox('lualang', 'Language:', items, 0) + m.addoptioncombobox('lualang', 'Language:', items, 11) end From 589883eb3e7d86b90033593968f1b7dffc3c19c8 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 6 Jan 2019 11:00:32 +0300 Subject: [PATCH 2741/2794] Bump version 0.9.158.0 --- README.md | 2 +- changelog.txt | 4 ++++ mangadownloader/md.lpi | 2 +- update | 10 +++++----- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 564e94286..2948a7ed5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Download the latest release -[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.157.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.157.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0_Win64.7z) +[![Latest release](https://img.shields.io/github/release/riderkick/FMD.svg)](https://github.com/riderkick/FMD/releases/latest) [![Download latest release (Win32)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.158.0.7z.svg?label=Win32)](https://github.com/riderkick/FMD/releases/download/0.9.158.0/fmd_0.9.158.0.7z) [![Download latest release (Win64)](https://img.shields.io/github/downloads/riderkick/FMD/latest/fmd_0.9.158.0_Win64.7z.svg?label=Win64)](https://github.com/riderkick/FMD/releases/download/0.9.158.0/fmd_0.9.158.0_Win64.7z) ## Content diff --git a/changelog.txt b/changelog.txt index e69b7397d..3e06e2b3d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,10 @@ Project page: https://github.com/riderkick/FMD Changelog: (! = Important, + = Addition, - = Removal, * = Bug fix/Change/Edit, ? = Require feedback) +0.9.158.0 (06-01-2018) +[*] Minor bug fixes +Full changes: https://github.com/riderkick/FMD/compare/0.9.157.0...0.9.158.0 + 0.9.157.0 (29-12-2018) [*] Various changes and bug fixes Full changes: https://github.com/riderkick/FMD/compare/0.9.156.0...0.9.157.0 diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi index edb15e2d0..20b87d1f5 100644 --- a/mangadownloader/md.lpi +++ b/mangadownloader/md.lpi @@ -22,7 +22,7 @@ - + diff --git a/update b/update index 15a5f9550..e4f0f2460 100644 --- a/update +++ b/update @@ -1,5 +1,5 @@ -VERSION=0.9.157.0 -; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.157.0/fmd_0.9.157.0.7z/download -; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.157.0/fmd_0.9.157.0_Win64.7z/download -WIN32=https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0.7z -WIN64=https://github.com/riderkick/FMD/releases/download/0.9.157.0/fmd_0.9.157.0_Win64.7z +VERSION=0.9.158.0 +; WIN32=https://sourceforge.net/projects/newfmd/files/0.9.158.0/fmd_0.9.158.0.7z/download +; WIN64=https://sourceforge.net/projects/newfmd/files/0.9.158.0/fmd_0.9.158.0_Win64.7z/download +WIN32=https://github.com/riderkick/FMD/releases/download/0.9.158.0/fmd_0.9.158.0.7z +WIN64=https://github.com/riderkick/FMD/releases/download/0.9.158.0/fmd_0.9.158.0_Win64.7z From 102e6c0775befc76eee839b7b131b8810de99627 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 6 Jan 2019 14:55:09 +0300 Subject: [PATCH 2742/2794] MangaDex, add delay option --- lua/modules/MangaDex.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 394dab81e..24140dea8 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -3,6 +3,7 @@ function getinfo() http.cookies.values['mangadex_h_toggle'] = '1' local id = url:match('title/(%d+)') if id == nil then id = url:match('manga/(%d+)'); end + delay() if http.get(MaybeFillHost(module.rooturl, '/api/manga/' .. id)) then local resp = HTMLEncode(StreamToString(http.document)) local x = TXQuery.Create(resp) @@ -201,6 +202,7 @@ end function getpagenumber() http.cookies.values['mangadex_h_toggle'] = '1' local chapterid = url:match('chapter/(%d+)') + delay() if http.get(MaybeFillHost(module.rooturl,'/api/chapter/'..chapterid)) then local x=TXQuery.Create(http.Document) local hash = x.xpathstring('json(*).hash') @@ -223,6 +225,7 @@ local dirurl='/titles/2' function getdirectorypagenumber() http.cookies.values['mangadex_h_toggle'] = '1' http.cookies.values['mangadex_title_mode'] = '2' + delay() if http.GET(module.RootURL .. dirurl) then local x = TXQuery.Create(http.Document) page = tonumber(x.xpathstring('(//ul[contains(@class,"pagination")]/li/a)[last()]/@href'):match('/2/(%d+)')) @@ -236,6 +239,7 @@ end function getnameandlink() http.cookies.values['mangadex_h_toggle'] = '1' http.cookies.values['mangadex_title_mode'] = '2' + delay() if http.GET(module.rooturl .. dirurl .. '/' .. IncStr(url) .. '/') then local x = TXQuery.Create(http.document) x.xpathhrefall('//a[contains(@class, "manga_title")]',links,names) @@ -245,6 +249,25 @@ function getnameandlink() end end +function delay() + local interval = tonumber(module.getoption('luainterval')) + local delay = tonumber(module.getoption('luadelay')) -- * module.ActiveConnectionCount + + if (interval == nil) or (interval < 0) then interval = 1000; end + if (delay == nil) or (delay < 0) then delay = 1000; end + + local lastDelay = module.storage['lastDelay'] + if lastDelay ~= '' then + lastDelay = tonumber(lastDelay) + if GetCurrentTime() - lastDelay < interval then + print(GetCurrentTime() - lastDelay) + Sleep(delay) + end + end + + module.storage['lastDelay'] = tostring(GetCurrentTime()) +end + function Init() m=NewModule() m.category='English' @@ -259,6 +282,8 @@ function Init() m.maxtasklimit=1 m.maxconnectionlimit=2 + m.addoptionspinedit('luainterval', 'Min. interval between requests (ms)', 1000) + m.addoptionspinedit('luadelay', 'Delay (ms)', 1000) m.addoptioncheckbox('luashowscangroup', 'Show scanlation group', false) local items = 'All' From bd42082e26fef8b7d181166763b021b3d27a5beb Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 7 Jan 2019 08:12:28 +0300 Subject: [PATCH 2743/2794] add KazeManga [id] closes #1483 --- lua/modules/KazeManga.lua | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 lua/modules/KazeManga.lua diff --git a/lua/modules/KazeManga.lua b/lua/modules/KazeManga.lua new file mode 100644 index 000000000..236016339 --- /dev/null +++ b/lua/modules/KazeManga.lua @@ -0,0 +1,49 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('//h1[@itemprop="headline"]'):gsub(' Bahasa Indonesia$', '') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('css("div.animeinfo img")/@src')) + mangainfo.authors = x.XPathStringAll('css("div.animeinfo > span")//span[contains(b, "Author")]/substring-after(text(),":")','') + mangainfo.summary = x.XPathString('css("div.sinopx > p")') + mangainfo.genres = x.XPathStringAll('css("div.animeinfo > span")//span[contains(b, "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('css("div.animeinfo > span")//span[contains(b, "Status")]')) + x.xpathhrefall('css("div.epl > ul > li a")', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber=0 + if http.get(MaybeFillHost(module.rooturl,url)) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('css("div.badan img")/@src', task.pagelinks) + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/komik-list/') then + local x=TXQuery.Create(http.Document) + x.xpathhrefall('css(".anime-list2 .a-z > li > a")', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Indonesian' + m.website='KazeManga' + m.rooturl='https://kazemanga.xyz' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' +end From 2d103794a38b401bf9c982b383f455e5848a6c23 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 7 Jan 2019 08:25:06 +0300 Subject: [PATCH 2744/2794] remove erroneous mangastream.to fixes #1334 --- baseunits/ModuleList.inc | 1 - baseunits/modules/MangaStreamTo.pas | 133 ---------------------------- 2 files changed, 134 deletions(-) delete mode 100644 baseunits/modules/MangaStreamTo.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 478cf6d4e..05e67d472 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -8,7 +8,6 @@ uses Madokami, RawSenManga, KissManga, - MangaStreamTo, MangaHome, GameofScanlation, Hakihome, diff --git a/baseunits/modules/MangaStreamTo.pas b/baseunits/modules/MangaStreamTo.pas deleted file mode 100644 index 5c83b083f..000000000 --- a/baseunits/modules/MangaStreamTo.pas +++ /dev/null @@ -1,133 +0,0 @@ -unit MangaStreamTo; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil; - -implementation - -const - dirurl = '/series.html'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@id="page-list"]//tr/td/p/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - query.Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - if title = '' then title := query.XPathString('//div[@id="content-main"]/h1'); - for v in query.XPath('//table[@class="ch-table"]/tbody/tr/td/a') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(v.toString); - end; - finally - query.Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber := query.XPath('//select[@id="id_page"]/option').Count; - finally - query.Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AURL; - s := ReplaceRegExpr('\.html?$', s, '', False); - s += '-page-' + IncStr(DownloadThread.WorkId) + '.html'; - if GET(FillHost(Module.RootURL, s)) then begin - Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.WorkId] := - query.XPathString('//img[@class="manga-page center-block"]/@src'); - finally - query.Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MangaStreamTo'; - RootURL := 'http://www.mangastream.to'; - Category := 'English'; - InformationAvailable := False; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. From cbc067d0d366d291e218ccc34cfc2785738e17e5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 7 Jan 2019 08:47:08 +0300 Subject: [PATCH 2745/2794] MangaPark, add net/com domains --- lua/modules/MangaPark.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lua/modules/MangaPark.lua b/lua/modules/MangaPark.lua index bdf31400b..0bbc67cd9 100644 --- a/lua/modules/MangaPark.lua +++ b/lua/modules/MangaPark.lua @@ -63,14 +63,20 @@ function getnameandlink() end end -function Init() +function AddWebsiteModule(name, url) local m = NewModule() - m.website = 'MangaPark' - m.rooturl = 'https://mangapark.me' + m.website = name + m.rooturl = url m.category = 'English' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.ongetdirectorypagenumber = 'getdirectorypagenumber' m.sortedlist = true +end + +function Init() + AddWebsiteModule('MangaPark', 'https://mangapark.me') + AddWebsiteModule('MangaParkNet', 'https://mangapark.net') + AddWebsiteModule('MangaParkCom', 'https://mangapark.com') end \ No newline at end of file From af1431b90c885062267c54adcda89682bd849e62 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 8 Jan 2019 07:11:01 +0300 Subject: [PATCH 2746/2794] add NiAdd [en] --- lua/modules/NiAdd.lua | 75 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 lua/modules/NiAdd.lua diff --git a/lua/modules/NiAdd.lua b/lua/modules/NiAdd.lua new file mode 100644 index 000000000..40e75e640 --- /dev/null +++ b/lua/modules/NiAdd.lua @@ -0,0 +1,75 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('css("h1.manga-title")') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('css("img.detail-cover")/@src')) + mangainfo.authors=x.xpathstringall('//*[@itemprop="author" and contains(span, "Author")]/a') + mangainfo.artists=x.xpathstringall('//*[@itemprop="author" and contains(span, "Artist")]/a') + mangainfo.genres=x.xpathstringall('//*[contains(span, "Genres")]/a') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('css(".status-tag")')) + mangainfo.summary=x.xpathstring('css(".summary-box")/span[@itemprop]') + x.xpathhreftitleall('css("ul.detail-chlist > a")', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + task.pagenumber = x.xpathcount('(//div[contains(@class, "mangaread-pagenav")])[1]/select[@class="sl-page"]/option') + else + return false + end + return true +end + +function getnameandlink() + local s = string.format("/category/index_%s.html?sort=name", IncStr(url)) + if http.get(module.rooturl .. s) then + local x = TXQuery.Create(http.Document) + local p=x.xpathstring('//div[@class="page-nav"]/a[last()-1]') + p = tonumber(p) + if p ~= nil then + updatelist.CurrentDirectoryPageNumber = p + end + x.XPathHREFAll('css("p.title > a")', links, names) + return no_error + else + return net_problem + end +end + +function getimageurl() + local s = MaybeFillHost(module.RootURL, url) + s = string.format('%s-%s.html', s:gsub('/$', ''), IncStr(workid)) + if http.GET(s) then + local x = TXQuery.Create(http.Document) + task.pagelinks[workid] = x.xpathstring('css("img.manga_pic")/@src') + return true + else + return false + end +end + +function AddWebsiteModule(name, url, cat) + local m = NewModule() + m.website = name + m.rooturl = url + m.category = cat + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetimageurl = 'getimageurl' +end + +function Init() + AddWebsiteModule('NiAdd', 'https://www.niadd.com', 'English') +end \ No newline at end of file From 0bc62cebbfa946efe4a935fed7d668b9de782eec Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 8 Jan 2019 07:18:00 +0300 Subject: [PATCH 2747/2794] ComiCake, cleanup --- lua/modules/ComiCake.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/ComiCake.lua b/lua/modules/ComiCake.lua index d8627bd85..d211c4a40 100644 --- a/lua/modules/ComiCake.lua +++ b/lua/modules/ComiCake.lua @@ -51,7 +51,6 @@ function AddWebsiteModule(name, url, category) m.category = category m.ongetinfo = 'getinfo' m.OnGetPageNumber = 'getpagenumber' - m.OnGetImageURL = 'getimageurl' m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' m.OnGetNameAndLink = 'getnameandlink' return m From f2ef67cf02d60a0c6e370c93c890381dfd35fadd Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 8 Jan 2019 07:39:07 +0300 Subject: [PATCH 2748/2794] NeuManga, fix all fixes #1345 --- lua/modules/NeuManga.lua | 47 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/lua/modules/NeuManga.lua b/lua/modules/NeuManga.lua index 5fa1b7fb8..d8505cf1c 100644 --- a/lua/modules/NeuManga.lua +++ b/lua/modules/NeuManga.lua @@ -1,19 +1,23 @@ function GetInfo() mangainfo.url=MaybeFillHost(module.rooturl,url) if http.get(mangainfo.url) then - x=TXQuery.Create(http.Document) - mangainfo.title=x.XPathString('//h1[contains(@class,"manga1")]/text()') + local x=TXQuery.Create(http.Document) + if mangainfo.title == '' then + mangainfo.title=x.XPathString('//h1[@itemprop="headline"]') + mangainfo.title=mangainfo.title:gsub('^Baca Manga','') + mangainfo.title=mangainfo.title:gsub('Bahasa Indonesia$','') + end mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[@class="imagemg"]/@src')) - mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//div[@class="info"]/span[contains(., "Status")]/a')) - mangainfo.authors = x.XPathStringAll('//div[@class="info"]/span[contains(., "Author")]/a') - mangainfo.artists = x.XPathStringAll('//div[@class="info"]/span[contains(., "Artist")]/a') - mangainfo.genres = x.XPathStringAll('//div[@class="info"]/span[contains(., "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//span[@class="hentry"]/span[contains(., "Status")]/a')) + mangainfo.authors = x.XPathStringAll('//span[@class="hentry"]/span[contains(., "Author")]/a') + mangainfo.artists = x.XPathStringAll('//span[@class="hentry"]/span[contains(., "Artist")]/a') + mangainfo.genres = x.XPathStringAll('//span[@class="hentry"]/span[contains(., "Genre")]/a') mangainfo.summary = x.XPathStringAll('//div[contains(@class,"summary")]/text()', '') - v=x.xpath('//div[@id="scans"]/div[1]/div[@class="item-content"]/a') + local v=x.xpath('//div[@id="scans"]//div[@class="item-content"]/a') for i=1, v.count do - v1=v.get(i) + local v1=v.get(i) mangainfo.chapterlinks.add(v1.getAttribute('href')) - mangainfo.chapternames.add(x.xpathstringall('text()', '', v1)) + mangainfo.chapternames.add(x.xpathstring('h3', v1)) end InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error @@ -23,22 +27,13 @@ function GetInfo() end function GetPageNumber() + task.pagelinks.clear() + task.pagenumber = 0 http.cookies.values['age_confirmed'] = '1' - if http.get(MaybeFillHost(module.rooturl,url)) then - x=TXQuery.Create(http.Document) - task.pagenumber=x.xpath('(//select[@class="page"])[1]/option').count - return true - else - return false - end -end - -function GetImageURL() - s=url:gsub('%?.+$','')..'/'..tostring(workid+1) - http.cookies.values['age_confirmed'] = '1' - if http.get(MaybeFillHost(module.rooturl,s)) then - x=TXQuery.Create(http.Document) - task.pagelinks[workid]=x.xpathstring('//img[@class="imagechap"]/@src') + local u = AppendURLDelim(MaybeFillHost(module.rooturl,url)) .. '_/1' + if http.get(u) then + local x=TXQuery.Create(http.Document) + x.xpathstringall('//img[@class="imagechap"]/@data-src', task.pagelinks) return true else return false @@ -59,10 +54,8 @@ function Init() m=NewModule() m.category='Indonesian' m.website='NeuManga' - m.rooturl='http://neumanga.tv' - m.lastupdated='February 12, 2018' + m.rooturl='https://neumanga.tv' m.ongetinfo='GetInfo' m.ongetpagenumber='GetPageNumber' - m.ongetimageurl='GetImageURL' m.ongetnameandlink='GetNameAndLink' end \ No newline at end of file From efa4a7f360a9d79e07ffc0291678e0355090e130 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 8 Jan 2019 07:48:23 +0300 Subject: [PATCH 2749/2794] KomikCast, fix list update --- lua/modules/MangaShiro.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 9072aee80..1eef5ff1e 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -85,7 +85,7 @@ function getnameandlink() local dirs = { ['MangaShiro'] = '/daftar-manga/?list', ['KomikStation'] = '/daftar-komik/', - ['KomikCast'] = '/daftar-komik/?list', + ['KomikCast'] = '/list/', ['MangaKid'] = '/manga-lists/', ['Kiryuu'] = '/manga-lists/?list', ['WestManga'] = '/manga-list/?list', @@ -98,7 +98,7 @@ function getnameandlink() if http.get(module.rooturl..dirurl) then if module.website == 'KomikStation' then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) - elseif module.website == 'WestManga' or module.website == 'MangaKita' then + elseif module.website == 'WestManga' or module.website == 'MangaKita' or module.website == 'KomikCast' then TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) else TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) From c2d79a1645569a3f9a4d85a2e3a57ae1a81dac5d Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 8 Jan 2019 11:19:38 +0300 Subject: [PATCH 2750/2794] MangaDex, add more genres fixes #1615 --- lua/modules/MangaDex.lua | 54 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/lua/modules/MangaDex.lua b/lua/modules/MangaDex.lua index 24140dea8..6bfbb94de 100644 --- a/lua/modules/MangaDex.lua +++ b/lua/modules/MangaDex.lua @@ -25,6 +25,10 @@ function getinfo() local v1 = v.get(i) genres = genres .. ', ' .. getgenre(v1.toString) end + if x.xpathstring('manga/hentai', info) == '1' then + if genres ~= '' then genres = genres .. ', ' end + genres = genres .. 'Hentai' + end mangainfo.genres = genres local selLang = module.getoption('lualang') @@ -91,7 +95,7 @@ function getgenre(genre) ["8"] = "Drama", ["9"] = "Ecchi", ["10"] = "Fantasy", - ["11"] = "Gender Bender", + ["11"] = "Gyaru", ["12"] = "Harem", ["13"] = "Historical", ["14"] = "Horror", @@ -116,12 +120,54 @@ function getgenre(genre) ["33"] = "Sports", ["34"] = "Supernatural", ["35"] = "Tragedy", - ["36"] = "Webtoon", + ["36"] = "Long Strip", ["37"] = "Yaoi", ["38"] = "Yuri", ["39"] = "[no chapters]", - ["40"] = "Game", - ["41"] = "Isekai" + ["40"] = "Video Games", + ["41"] = "Isekai", + ["42"] = "Adaptation", + ["43"] = "Anthology", + ["44"] = "Web Comic", + ["45"] = "Full Color", + ["46"] = "User Created", + ["47"] = "Official Colored", + ["48"] = "Fan Colored", + ["49"] = "Gore", + ["50"] = "Sexual Violence", + ["51"] = "Crime", + ["52"] = "Magical Girls", + ["53"] = "Philosophical", + ["54"] = "Superhero", + ["55"] = "Thriller", + ["56"] = "Wuxia", + ["57"] = "Aliens", + ["58"] = "Animals", + ["59"] = "Crossdressing", + ["60"] = "Demons", + ["61"] = "Delinquents", + ["62"] = "Genderswap", + ["63"] = "Ghosts", + ["64"] = "Monster Girls", + ["65"] = "Loli", + ["66"] = "Magic", + ["67"] = "Military", + ["68"] = "Monsters", + ["69"] = "Ninja", + ["70"] = "Office Workers", + ["71"] = "Police", + ["72"] = "Post-Apocalyptic", + ["73"] = "Reincarnation", + ["74"] = "Reverse Harem", + ["75"] = "Samurai", + ["76"] = "Shota", + ["77"] = "Survival", + ["78"] = "Time Travel", + ["79"] = "Vampires", + ["80"] = "Traditional Games", + ["81"] = "Virtual Reality", + ["82"] = "Zombies", + ["83"] = "Incest" } if genres[genre] ~= nil then return genres[genre] From 46b9005bff5435b0eb78427c4f6326cef54aefad Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 9 Jan 2019 07:18:28 +0300 Subject: [PATCH 2751/2794] Pururin, fix all closes #1425 closes #1355 --- lua/modules/Pururin.lua | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/lua/modules/Pururin.lua b/lua/modules/Pururin.lua index a217b0ca7..33ab55f95 100644 --- a/lua/modules/Pururin.lua +++ b/lua/modules/Pururin.lua @@ -1,12 +1,14 @@ +local domain = 'pururin.io' + function GetInfo() mangainfo.url=MaybeFillHost(module.rooturl,url) if http.get(mangainfo.url) then x=TXQuery.Create(http.Document) - mangainfo.title=x.XPathString('//*[@class="gallery-info"]//*[@class="title"]') - mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//*[@class="cover"]//img/@src')) - mangainfo.artists = x.XPathString('//*[@class="gallery-info"]//*[@class="table"]//tr/td[starts-with(.,"Artist")]/following-sibling::td[1]/string-join(.//a,", ")') - mangainfo.genres = x.XPathString('//*[@class="gallery-info"]//*[@class="table"]/string-join(.//tr/td//a,", ")') - mangainfo.chapterlinks.add(x.XPathString('//a[@class="read-more"]/@href')) + mangainfo.title=x.XPathString('//*[@class="title"]/h1') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//*[@class="cover-wrapper"]//v-lazy-image/@src')) + mangainfo.artists = x.XPathStringAll('//table[contains(@class,"table-gallery-info")]//tr/td[contains(.,"Artist")]/following-sibling::td//a') + mangainfo.genres = x.XPathStringAll('//table[contains(@class,"table-gallery-info")]//tr/td[contains(.,"Contents")]/following-sibling::td//a') + mangainfo.chapterlinks.add(x.XPathString('//*[@class="gallery-action"]/a/@href')) mangainfo.chapternames.add(mangainfo.title) return no_error else @@ -15,9 +17,17 @@ function GetInfo() end function GetPageNumber() + local path = 'https://api.' .. domain .. '/images' if http.get(MaybeFillHost(module.rooturl,url)) then - x=TXQuery.Create(http.Document) - x.XPathStringAll('json(//script[contains(.,"var chapters")]/substring-before(substring-after(.,"= "),";"))//image', task.pagelinks) + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//gallery-read/@gallery') + x.parsehtml(s) + local ext = x.xpathstring('json(*).image_extension') + local cnt = x.xpathstring('json(*).total_pages') + local id = x.xpathstring('json(*).id') + for i = 1, cnt do + task.pagelinks.add(string.format('%s/%s/%d.%s', path, id, i, ext)) + end return true else return false @@ -26,10 +36,10 @@ end function GetNameAndLink() if http.get(module.rooturl..'/browse/newest?page='..IncStr(url)) then - x=TXQuery.Create(http.Document) - v=x.xpath('//*[@class="gallery-listing"]/*[@class="row"]/a') + local x=TXQuery.Create(http.Document) + local v=x.xpath('//*[@class="row-gallery"]/a') for i=1,v.count do - v1 = v.get(i) + local v1 = v.get(i) links.add(v1.getAttribute('href')) names.add(x.xpathstring('.//*[@class="title"]/text()[1]', v1)) end @@ -41,8 +51,8 @@ end function getdirectorypagenumber() if http.GET(module.RootURL) then - x = TXQuery.Create(http.Document) - page = tonumber(x.XPathString('//*[@class="pagination"]/li[last()-1]')) + local x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//ul[contains(@class,"pagination")]/li[last()-1]')) if page == nil then page = 1 end return true else @@ -54,9 +64,8 @@ function Init() m=NewModule() m.category='H-Sites' m.website='Pururin' - m.rooturl='http://pururin.io' + m.rooturl='https://' .. domain m.sortedlist=true - m.lastupdated='February 14, 2018' m.ongetinfo='GetInfo' m.ongetpagenumber='GetPageNumber' m.ongetnameandlink='GetNameAndLink' From 3ca45995c423a9bff2060e317d5023bd1212009b Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 9 Jan 2019 07:18:42 +0300 Subject: [PATCH 2752/2794] add MangaShow [raw] --- lua/modules/MangaShow.lua | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 lua/modules/MangaShow.lua diff --git a/lua/modules/MangaShow.lua b/lua/modules/MangaShow.lua new file mode 100644 index 000000000..764a30a79 --- /dev/null +++ b/lua/modules/MangaShow.lua @@ -0,0 +1,68 @@ +function getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('css("div.manga-subject")') + end + local img = x.xpathstring('css("div.manga-thumbnail")/@style') + img = GetBetween('url(', ')', img) + mangainfo.coverlink=MaybeFillHost(module.RootURL, img) + mangainfo.authors=x.xpathstringall('css("a.author")') + mangainfo.genres=x.xpathstringall('css("div.manga-tags > a")') + x.xpathhrefall('css("div.chapter-list > div.slot > a")', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function getpagenumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local s=x.xpathstring('//script[contains(., "img_list")]') + s = GetBetween('var img_list =', ';', s) + x.parsehtml(s) + x.xpathstringall('json(*)()', task.pagelinks) + else + return false + end + return true +end + +function getnameandlink() + if http.get(module.rooturl .. '/bbs/page.php?hid=manga_list&page=' .. IncStr(url)) then + local x = TXQuery.Create(http.Document) + x.XPathHREFAll('css("div.manga-list-gallery div.manga-subject > a")', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/bbs/page.php?hid=manga_list') then + local x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('//ul[@class="pagination"]/li[last()]/a/@href'):match('%((%d+)%)$')) + if page == nil then + page = 1 + end + return true + else + return false + end +end + +function Init() + local m = NewModule() + m.website = 'MangaShow' + m.rooturl = 'https://mangashow.me' + m.category = 'Raw' + m.ongetinfo='getinfo' + m.ongetpagenumber='getpagenumber' + m.ongetnameandlink='getnameandlink' + m.ongetdirectorypagenumber = 'getdirectorypagenumber' +end From 5f363c8328bf71d52653b69a1ac56989fb928406 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 9 Jan 2019 07:18:53 +0300 Subject: [PATCH 2753/2794] HeavenManga, use https --- lua/modules/HeavenManga.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index d84a37f9e..3d8db2ec3 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -68,7 +68,7 @@ end function Init() local m = NewModule() m.website = 'HeavenManga' - m.rooturl = 'http://heavenmanga.ca' + m.rooturl = 'https://heavenmanga.ca' m.category = 'English' m.lastupdated='February 26, 2018' m.ongetinfo='getinfo' From 0f837afccbd4e656c4376a391fbd0dd2eee2fb05 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 9 Jan 2019 11:18:57 +0300 Subject: [PATCH 2754/2794] add MangaIndoNet [id] closes #1391 --- lua/modules/MangaShiro.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 1eef5ff1e..b1c1854b1 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -10,7 +10,7 @@ function getinfo() mangainfo.genres=x.xpathstringall('//div[@class="topinfo"]//tr[contains(th, "Genres")]/td/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstringall('//*[@class="sin"]/p/text()', '') - elseif module.website == 'MangaShiro' or module.website == 'Kiryuu' then + elseif module.website == 'MangaShiro' or module.website == 'Kiryuu' or module.website == 'MangaIndoNet' then mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') local img = x.xpathstring('//div[@itemprop="image"]/img/@data-lazy-src') if img == '' then @@ -90,6 +90,7 @@ function getnameandlink() ['Kiryuu'] = '/manga-lists/?list', ['WestManga'] = '/manga-list/?list', ['PecintaKomik'] = '/daftar-manga/?list', + ['MangaIndoNet'] = '/manga-list/?list', } local dirurl = '/manga-list/' if dirs[module.website] ~= nil then @@ -114,7 +115,6 @@ function AddWebsiteModule(site, url) m.category='Indonesian' m.website=site m.rooturl=url - m.lastupdated='February 21, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' @@ -131,4 +131,5 @@ function Init() AddWebsiteModule('Kiryuu', 'https://kiryuu.co') AddWebsiteModule('KomikOtaku', 'https://komikotaku.net') AddWebsiteModule('PecintaKomik', 'https://www.pecintakomik.com') + AddWebsiteModule('MangaIndoNet', 'https://mangaindo.net') end From 316deae49835a310b86c6e7d28f00dbb980db3cf Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 9 Jan 2019 11:22:44 +0300 Subject: [PATCH 2755/2794] add KomikIndo [id] #1391 --- lua/modules/MangaShiro.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index b1c1854b1..8ae510377 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -10,7 +10,11 @@ function getinfo() mangainfo.genres=x.xpathstringall('//div[@class="topinfo"]//tr[contains(th, "Genres")]/td/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstringall('//*[@class="sin"]/p/text()', '') - elseif module.website == 'MangaShiro' or module.website == 'Kiryuu' or module.website == 'MangaIndoNet' then + elseif module.website == 'MangaShiro' + or module.website == 'Kiryuu' + or module.website == 'MangaIndoNet' + or module.website == 'KomikIndo' + then mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') local img = x.xpathstring('//div[@itemprop="image"]/img/@data-lazy-src') if img == '' then @@ -91,6 +95,7 @@ function getnameandlink() ['WestManga'] = '/manga-list/?list', ['PecintaKomik'] = '/daftar-manga/?list', ['MangaIndoNet'] = '/manga-list/?list', + ['KomikIndo'] = '/manga-list/?list', } local dirurl = '/manga-list/' if dirs[module.website] ~= nil then @@ -132,4 +137,5 @@ function Init() AddWebsiteModule('KomikOtaku', 'https://komikotaku.net') AddWebsiteModule('PecintaKomik', 'https://www.pecintakomik.com') AddWebsiteModule('MangaIndoNet', 'https://mangaindo.net') + AddWebsiteModule('KomikIndo', 'https://komikindo.co') end From f55137100b73b97f27647e8d098ff3626fed02c5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 9 Jan 2019 11:23:42 +0300 Subject: [PATCH 2756/2794] fix NPE --- mangadownloader/forms/frmMain.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mangadownloader/forms/frmMain.pas b/mangadownloader/forms/frmMain.pas index a2ba353c4..ab84ad427 100644 --- a/mangadownloader/forms/frmMain.pas +++ b/mangadownloader/forms/frmMain.pas @@ -3540,7 +3540,7 @@ procedure TMainForm.pmFavoritesPopup(Sender: TObject); miFavoritesEnable.Enabled := iEnable; miFavoritesDisable.Enabled := iDisable; miFavoritesTransferWebsite.Enabled := True; - if vtFavorites.SelectedCount = 1 then + if (vtFavorites.SelectedCount = 1) and Assigned(vtFavorites.FocusedNode) then begin miFavoritesViewInfos.Enabled := True; miFavoritesDownloadAll.Enabled := (Trim(FavoriteManager[vtFavorites.FocusedNode^.Index].FavoriteInfo.Link) <> ''); From 19f3c25305b9281b9b5bcaf8be66ee2524e41ccc Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 10 Jan 2019 17:52:43 +0300 Subject: [PATCH 2757/2794] add mangapark.org [en] closes #1459 --- lua/modules/MangaParkOrg.lua | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 lua/modules/MangaParkOrg.lua diff --git a/lua/modules/MangaParkOrg.lua b/lua/modules/MangaParkOrg.lua new file mode 100644 index 000000000..0d65b7ff5 --- /dev/null +++ b/lua/modules/MangaParkOrg.lua @@ -0,0 +1,81 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.Document) + if mangainfo.title == '' then + mangainfo.title=x.XPathString('//h3') + end + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('css("img.img-fluid")/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('css("table.table-borderless")//tr[th="Status"]/td')) + mangainfo.authors = x.XPathString('css("table.table-borderless")//tr[th="Author(s)"]/td') + mangainfo.artists = x.XPathString('css("table.table-borderless")//tr[th="Artist(s)"]/td') + mangainfo.genres = x.XPathStringAll('css("table.table-borderless")//tr[th="Genre(s)"]/td') + mangainfo.genres = mangainfo.genres:gsub('%s+/%s+', ', ') + mangainfo.summary = x.XPathString('//h4[.="Summary"]/following-sibling::p') + local v=x.xpath('css("div.card-header")') + for i=1, v.count do + local v1=v.get(i) + local src = x.xpathstring('./div/a', v1) + local w = x.xpath('./following-sibling::div/ul/li//a', v1) + for j = 1, w.count do + local w1 = w.get(j) + mangainfo.chapterlinks.add(w1.getAttribute('href')) + mangainfo.chapternames.add(string.format('%s (%s)', w1.toString, src)) + end + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl,url)) then + local x=TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "var images")]') + s = GetBetween("var images =", ";", s) + x.parsehtml(s) + x.xpathstringall('json(*)()', task.pagelinks) + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/browse?order_by=create&page='..IncStr(url)) then + x=TXQuery.Create(http.Document) + x.xpathhrefall('css("#browse h6")/a', links, names) + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + if http.GET(module.RootURL .. '/browse?order_by=create') then + local x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('css("#paging nav.d-none ul.pagination")/li[last()-1]/a')) + if page == nil then + page = 1 + end + return true + else + return false + end +end + +function Init() + m=NewModule() + m.category='English' + m.website='MangaParkOrg' + m.rooturl='https://mangapark.org' + m.sortedlist = true + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.ongetdirectorypagenumber='getdirectorypagenumber' +end From 82218c16b9506d4e2d6b746c35da8c5dcab421cc Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 11 Jan 2019 09:17:51 +0300 Subject: [PATCH 2758/2794] MangaShiro, refactoring --- lua/modules/MangaShiro.lua | 324 +++++++++++++++++++++++++++++-------- 1 file changed, 254 insertions(+), 70 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 8ae510377..25adcf61a 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -1,21 +1,125 @@ -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(mangainfo.url) then - x=TXQuery.Create(http.document) - x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) - if module.website == 'KomikCast' or module.website == 'WestManga' then - mangainfo.title=x.xpathstring('//div[@class="mangainfo"]/h1') +Modules = {} + +function Modules.MangaShiroBase() + local MangaShiroBase = {} + + function MangaShiroBase:new() + local obj = {} + setmetatable(obj, self) + self.__index = self + return obj + end + + function MangaShiroBase:getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1') + end + mangainfo.title = mangainfo.title:gsub('Bahasa Indonesia$', '') + end + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) + mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') + mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') + mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) + mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') + x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + end + return net_problem + end + + function MangaShiroBase:getpagenumber() + task.pagenumber=0 + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl,url)) then + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@data-lazy-src', task.pagelinks) + if task.pagelinks.count < 1 then + TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + end + return true + end + end + + function MangaShiroBase:getnameandlink() + if http.get(module.rooturl .. self.getdirurl()) then + TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a', links, names) + return no_error + end + return net_problem + end + + function MangaShiroBase:getdirurl() + return '/manga-list/' + end + + return MangaShiroBase; +end + +function Modules.KomikCast() + local KomikCast = {} + setmetatable(KomikCast, { __index = Modules.MangaShiroBase() }) + + function KomikCast:getdirurl() + return '/list/' + end + + function KomikCast:getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//div[@class="mangainfo"]/h1') + end mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="topinfo"]/img/@src')) mangainfo.authors=x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Author")]/td') mangainfo.genres=x.xpathstringall('//div[@class="topinfo"]//tr[contains(th, "Genres")]/td/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="topinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstringall('//*[@class="sin"]/p/text()', '') - elseif module.website == 'MangaShiro' - or module.website == 'Kiryuu' - or module.website == 'MangaIndoNet' - or module.website == 'KomikIndo' - then - mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') + x.xpathhrefall('//div[@class="cl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + end + return net_problem + end + + function KomikCast:getnameandlink() + if http.get(module.rooturl .. self.getdirurl()) then + TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) + return no_error + end + return net_problem + end + + return KomikCast +end + +function Modules.WestManga() + local WestManga = {} + setmetatable(WestManga, { __index = Modules.KomikCast() }) + + function WestManga:getdirurl() + return '/manga-list/?list' + end + + return WestManga +end + +function Modules.MangaShiro() + local MangaShiro = {} + setmetatable(MangaShiro, { __index = Modules.MangaShiroBase() }) + + function MangaShiro:getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') + end local img = x.xpathstring('//div[@itemprop="image"]/img/@data-lazy-src') if img == '' then img = x.xpathstring('//div[@itemprop="image"]/img/@src') @@ -28,91 +132,171 @@ function getinfo() mangainfo.chapterlinks.clear() mangainfo.chapternames.clear() x.xpathhrefall('//div[@class="bxcl"]//li//div[@class="lch"]/a', mangainfo.chapterlinks, mangainfo.chapternames) - elseif module.website == 'PecintaKomik' then - mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]/*') + return no_error + end + return net_problem + end + + function MangaShiro:getdirurl() + return '/daftar-manga/?list' + end + + return MangaShiro +end + +function Modules.Kiryuu() + local Kiryuu = {} + setmetatable(Kiryuu, { __index = Modules.MangaShiro() }) + + function Kiryuu:getdirurl() + return '/manga-lists/?list' + end + + return Kiryuu +end + +function Modules.MangaIndoNet() + local MangaIndoNet = {} + setmetatable(MangaIndoNet, { __index = Modules.MangaShiro() }) + + function MangaIndoNet:getdirurl() + return '/manga-list/?list' + end + + return MangaIndoNet +end + +function Modules.KomikIndo() + local KomikIndo = {} + setmetatable(KomikIndo, { __index = Modules.MangaShiro() }) + + function KomikIndo:getdirurl() + return '/manga-list/?list' + end + + return KomikIndo +end + +function Modules.PecintaKomik() + local PecintaKomik = {} + setmetatable(PecintaKomik, { __index = Modules.MangaShiroBase() }) + + function PecintaKomik:getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]/*') + end mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@itemprop="image"]/img/@src')) mangainfo.authors=x.xpathstring('//table[@class="listinfo"]//tr[contains(th, "Penulis")]/td') mangainfo.genres=x.xpathstringall('//table[@class="listinfo"]//tr[contains(th, "Genre")]/td/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//table[@class="listinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') - mangainfo.chapterlinks.clear() - mangainfo.chapternames.clear() x.xpathhrefall('//div[@class="bxcl"]//li//*[@class="lchx"]/a', mangainfo.chapterlinks, mangainfo.chapternames) - elseif module.website == 'MangaKita' then - mangainfo.title=x.xpathstring('//h1') + return no_error + end + return net_problem + end + + function PecintaKomik:getdirurl() + return '/daftar-manga/?list' + end + + return PecintaKomik +end + +function Modules.MangaKita() + local MangaKita = {} + setmetatable(MangaKita, { __index = Modules.MangaShiroBase() }) + + function MangaKita:getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1') + end mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[contains(@class,"leftImage")]/img/@src')) mangainfo.authors=x.xpathstring('//span[@class="details"]//div[starts-with(.,"Author")]/substring-after(.,":")') mangainfo.genres=x.xpathstringall('//span[@class="details"]//div[starts-with(.,"Genre")]/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//span[@class="details"]//div[starts-with(.,"Status")]')) mangainfo.summary=x.xpathstringall('//*[@class="description"]/text()', '') - mangainfo.chapterlinks.clear() - mangainfo.chapternames.clear() local v = x.xpath('//div[contains(@class, "chapter-list")]/a') for i = 1, v.count do local v1 = v.get(i) mangainfo.chapterlinks.add(v1.getAttribute('href')) mangainfo.chapternames.add(x.xpathstring('./span', v1)) end - else - mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') - if mangainfo.title == '' then - mangainfo.title=x.xpathstring('//h1'):gsub('Bahasa Indonesia$', '') - end - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/img/@src')) - mangainfo.authors=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Author")]/substring-after(.,":")') - mangainfo.genres=x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Genre")]/substring-after(.,":")') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) - mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') - end - InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) - return no_error - else + return no_error + end return net_problem end -end -function getpagenumber() - task.pagenumber=0 - task.pagelinks.clear() - if http.get(MaybeFillHost(module.rooturl,url)) then - TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@data-lazy-src', task.pagelinks) - if task.pagelinks.count < 1 then - TXQuery.Create(http.Document).xpathstringall('//*[@id="readerarea"]//img/@src', task.pagelinks) + function MangaKita:getnameandlink() + if http.get(module.rooturl .. self.getdirurl()) then + TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) + return no_error end - return true - else - return false + return net_problem end + + return MangaKita end -function getnameandlink() - local dirs = { - ['MangaShiro'] = '/daftar-manga/?list', - ['KomikStation'] = '/daftar-komik/', - ['KomikCast'] = '/list/', - ['MangaKid'] = '/manga-lists/', - ['Kiryuu'] = '/manga-lists/?list', - ['WestManga'] = '/manga-list/?list', - ['PecintaKomik'] = '/daftar-manga/?list', - ['MangaIndoNet'] = '/manga-list/?list', - ['KomikIndo'] = '/manga-list/?list', - } - local dirurl = '/manga-list/' - if dirs[module.website] ~= nil then - dirurl = dirs[module.website] - end - if http.get(module.rooturl..dirurl) then - if module.website == 'KomikStation' then +function Modules.KomikStation() + local KomikStation = {} + setmetatable(KomikStation, { __index = Modules.MangaShiroBase() }) + + function KomikStation:getnameandlink() + if http.get(module.rooturl .. self.getdirurl()) then TXQuery.Create(http.document).xpathhrefall('//*[@class="daftarkomik"]//a',links,names) - elseif module.website == 'WestManga' or module.website == 'MangaKita' or module.website == 'KomikCast' then - TXQuery.Create(http.document).xpathhrefall('//*[@class="jdlbar"]//a',links,names) - else - TXQuery.Create(http.document).xpathhrefall('//*[@class="soralist"]//a',links,names) + return no_error end - return no_error - else return net_problem end + + function KomikStation:getdirurl() + return '/daftar-komik/' + end + + return KomikStation +end + +function Modules.MangaKid() + local MangaKid = {} + setmetatable(MangaKid, { __index = Modules.MangaShiroBase() }) + + function KomikStation:getdirurl() + return '/manga-lists/' + end + + return MangaKid +end + +------------------------------------------------------------------------------- + +function createInstance() + local m = Modules[module.website] + if m ~= nil then + return m():new() + else + return Modules.MangaShiroBase():new() + end +end + +------------------------------------------------------------------------------- + +function getinfo() + return createInstance():getinfo() +end + +function getpagenumber() + return createInstance():getpagenumber() +end + +function getnameandlink() + return createInstance():getnameandlink() end function AddWebsiteModule(site, url) From 15ee845a7872663e5f0d1dabfd276a4cc7e295a3 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 11 Jan 2019 09:57:43 +0300 Subject: [PATCH 2759/2794] LuaBase, print bools --- baseunits/lua/LuaBase.pas | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/baseunits/lua/LuaBase.pas b/baseunits/lua/LuaBase.pas index 76e1eda1d..14b087b19 100644 --- a/baseunits/lua/LuaBase.pas +++ b/baseunits/lua/LuaBase.pas @@ -32,7 +32,12 @@ function luabase_print(L: Plua_State): Integer; cdecl; begin Result := 0; for i := 1 to lua_gettop(L) do - Logger.Send(lua_tostring(L, i)); + case lua_type(L, i) of + LUA_TBOOLEAN: + Logger.Send(BoolToStr(lua_toboolean(L, i), 'true', 'false')); + else + Logger.Send(lua_tostring(L, i)); + end; end; function luabase_sleep(L: Plua_State): Integer; cdecl; From 8f0d23d3b3bca4d0ce2707078d8e7498bf7959db Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 11 Jan 2019 18:32:18 +0300 Subject: [PATCH 2760/2794] MangaID, fix --- lua/modules/MangaShiro.lua | 30 +++++++++++++++++++++++++++--- lua/modules/myReaderMangaCMS.lua | 1 - 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 25adcf61a..5c271173b 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -119,6 +119,7 @@ function Modules.MangaShiro() local x=TXQuery.Create(http.document) if mangainfo.title == '' then mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') + mangainfo.title=mangainfo.title:gsub('Bahasa Indonesia$', '') end local img = x.xpathstring('//div[@itemprop="image"]/img/@data-lazy-src') if img == '' then @@ -129,9 +130,8 @@ function Modules.MangaShiro() mangainfo.genres=x.xpathstringall('//div[contains(@class,"animeinfo")]/div[@class="gnr"]/a') mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@class="listinfo"]//li[starts-with(.,"Status")]')) mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') - mangainfo.chapterlinks.clear() - mangainfo.chapternames.clear() x.xpathhrefall('//div[@class="bxcl"]//li//div[@class="lch"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error end return net_problem @@ -194,6 +194,7 @@ function Modules.PecintaKomik() mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//table[@class="listinfo"]//tr[contains(th, "Status")]/td')) mangainfo.summary=x.xpathstring('//*[@class="desc"]/string-join(.//text(),"")') x.xpathhrefall('//div[@class="bxcl"]//li//*[@class="lchx"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error end return net_problem @@ -228,6 +229,7 @@ function Modules.MangaKita() mangainfo.chapterlinks.add(v1.getAttribute('href')) mangainfo.chapternames.add(x.xpathstring('./span', v1)) end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) return no_error end return net_problem @@ -267,13 +269,34 @@ function Modules.MangaKid() local MangaKid = {} setmetatable(MangaKid, { __index = Modules.MangaShiroBase() }) - function KomikStation:getdirurl() + function MangaKid:getdirurl() return '/manga-lists/' end return MangaKid end +function Modules.MangaID() + local MangaID = {} + setmetatable(MangaID, { __index = Modules.PecintaKomik() }) + + function MangaID:getinfo() + Modules.PecintaKomik().getinfo() + local x=TXQuery.Create(http.document) + if mangainfo.title == '' then + mangainfo.title=x.xpathstring('//h1[@itemprop="headline"]') + mangainfo.title=mangainfo.title:gsub('Bahasa Indonesia$', '') + end + mangainfo.authors=x.xpathstring('//table[@class="listinfo"]//tr[contains(th, "Author")]/td') + end + + function MangaID:getdirurl() + return '/daftar-manga/?list' + end + + return MangaID +end + ------------------------------------------------------------------------------- function createInstance() @@ -322,4 +345,5 @@ function Init() AddWebsiteModule('PecintaKomik', 'https://www.pecintakomik.com') AddWebsiteModule('MangaIndoNet', 'https://mangaindo.net') AddWebsiteModule('KomikIndo', 'https://komikindo.co') + AddWebsiteModule('MangaID', 'https://mangaid.me') end diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index de8352bae..90b82d06b 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -91,7 +91,6 @@ function Init() c='Indonesian' AddWebsiteModule('Komikid', 'http://www.komikid.com', c); - AddWebsiteModule('MangaID', 'https://mangaid.me', c); AddWebsiteModule('KomikGue', 'https://www.komikgue.com', c); c='Raw' From 6a14a478d87ca5139bb799096a7ba29176f27543 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 07:58:53 +0300 Subject: [PATCH 2761/2794] myReaderMangaCMS, refactoring --- lua/modules/myReaderMangaCMS.lua | 190 +++++++++++++++++++++---------- 1 file changed, 128 insertions(+), 62 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 90b82d06b..660224e97 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -1,85 +1,151 @@ -function GetNameAndLink() - local u = module.RootURL - if module.Website == 'WhiteCloudPavilion' then - u = u .. '/manga/free' +Modules = {} + +function Modules.myReaderMangaCMS() + local myReaderMangaCMS = {} + + function myReaderMangaCMS:new() + local obj = {} + setmetatable(obj, self) + self.__index = self + return obj end - if module.Website == 'GodsRealmScan' then - u = u .. '/public/' - end - u = u .. '/changeMangaList?type=text' - if http.GET(u) then - x = TXQuery.Create(http.Document) - x.XPathHREFAll('//li/a', links, names) - return no_error - else + + function myReaderMangaCMS:getinfo() + mangainfo.url = MaybeFillHost(module.RootURL, url) + if http.GET(mangainfo.url) then + x = TXQuery.Create(http.Document) + mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) + if mangainfo.title == '' then + mangainfo.title = x.XPathString('//h2[contains(@class,"widget-title")]') + if mangainfo.title == '' then + mangainfo.title = mangainfo.url:match('/([^/]+)$') + end + end + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.=("Status","Estado","Statut")]/following-sibling::dd[1]')) + mangainfo.authors = x.XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)","Auteur(s)")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.artists = x.XPathStringAll('//dt[.=("Artist(s)","Artiste(s)")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.genres = x.XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías","Catégories")]/following-sibling::dd[1]/string-join(*,", ")') + mangainfo.summary = x.XPathString('//div[@class="well"]/p') + v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') + for i = 1, v.Count do + v2 = v.Get(i) + mangainfo.chapterLinks.Add(x.XPathString('a/@href', v2)) + mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v2)) + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + return no_error + end return net_problem end -end - -function GetInfo(); - mangainfo.url = MaybeFillHost(module.RootURL, url) - if http.GET(mangainfo.url) then - x = TXQuery.Create(http.Document) - mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) - if mangainfo.title == '' then - mangainfo.title = x.XPathString('//h2[contains(@class,"widget-title")]') - if mangainfo.title == '' then - mangainfo.title = mangainfo.url:match('/([^/]+)$') + + function myReaderMangaCMS:getpagenumber() + local u = MaybeFillHost(module.RootURL, url) + if http.get(u) then + x = TXQuery.Create(http.document) + x.xpathstringall('//div[@id="all"]/img/@data-src', task.pagelinks) + if task.pagelinks.Count == 0 then + x.xpathstringall('//div[@id="all"]/img/@src', task.pagelinks) end + task.pagecontainerlinks.text = u + return true end - if module.Website == 'MangaDenizi' then - mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') - else - mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.=("Status","Estado","Statut")]/following-sibling::dd[1]')) - end - mangainfo.authors = x.XPathStringAll('//dt[.=("Author(s)","Yazar & Çizer:","Autor(es)","Auteur(s)")]/following-sibling::dd[1]/string-join(*,", ")') - mangainfo.artists = x.XPathStringAll('//dt[.=("Artist(s)","Artiste(s)")]/following-sibling::dd[1]/string-join(*,", ")') - mangainfo.genres = x.XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías","Catégories")]/following-sibling::dd[1]/string-join(*,", ")') - mangainfo.summary = x.XPathString('//div[@class="well"]/p') - v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') - for i = 1, v.Count do - v2 = v.Get(i) - mangainfo.chapterLinks.Add(x.XPathString('a/@href', v2)) - mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v2)) + return false + end + + function myReaderMangaCMS:getnameandlink() + if http.get(module.rooturl .. self.getdirurl()) then + x = TXQuery.create(http.document) + x.xpathhrefall('//li/a', links, names) + return no_error end - InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) - return no_error - else return net_problem end + + function myReaderMangaCMS:getdirurl() + return '/changeMangaList?type=text' + end + + function myReaderMangaCMS:beforedownloadimage() + http.reset() + http.headers.values['Referer'] = task.pagecontainerlinks.text + return true + end + + return myReaderMangaCMS end -function GetPageNumber() - local u = MaybeFillHost(module.RootURL, url) - if http.GET(u) then - x = TXQuery.Create(http.Document) - x.XPathStringAll('//div[@id="all"]/img/@data-src', task.PageLinks) - if task.PageLinks.Count == 0 then - x.XPathStringAll('//div[@id="all"]/img/@src', task.PageLinks) - end - task.pagecontainerlinks.text = u - return true +function Modules.WhiteCloudPavilion() + local WhiteCloudPavilion = {} + setmetatable(WhiteCloudPavilion, { __index = Modules.myReaderMangaCMS() }) + + function WhiteCloudPavilion:getdirurl() + return '/manga/free' .. Modules.myReaderMangaCMS().getdirurl() + end + + return WhiteCloudPavilion +end + +function Modules.GodsRealmScan() + local GodsRealmScan = {} + setmetatable(GodsRealmScan, { __index = Modules.myReaderMangaCMS() }) + + function GodsRealmScan:getdirurl() + return '/public' .. Modules.myReaderMangaCMS().getdirurl() + end + + return GodsRealmScan +end + +function Modules.MangaDenizi() + local MangaDenizi = {} + setmetatable(MangaDenizi, { __index = Modules.myReaderMangaCMS() }) + + function MangaDenizi:getinfo() + Modules.myReaderMangaCMS().getinfo() + local x=TXQuery.Create(http.document) + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//dt[.="Durum:"]/following-sibling::dd[1]'), 'Devam Ediyor', 'Tamamlandı') + end + + return MangaDenizi +end + +------------------------------------------------------------------------------- + +function createInstance() + local m = Modules[module.website] + if m ~= nil then + return m():new() else - return false + return Modules.myReaderMangaCMS():new() end end +------------------------------------------------------------------------------- + +function getinfo() + return createInstance():getinfo() +end + +function getpagenumber() + return createInstance():getpagenumber() +end + +function getnameandlink() + return createInstance():getnameandlink() +end + function beforedownloadimage() - http.reset() - http.headers.values['Referer'] = task.pagecontainerlinks.text - print(http.headers.values['Referer']) - return true + return createInstance():beforedownloadimage() end function AddWebsiteModule(name, url, cat) local m = NewModule() m.category = cat - m.Website = name - m.RootURL = url - m.LastUpdated = 'February 12, 2018' - m.OnGetNameAndLink = 'GetNameAndLink' - m.OnGetInfo = 'GetInfo' - m.OnGetPageNumber = 'GetPageNumber' + m.website = name + m.rooturl = url + m.ongetnameandlink = 'getnameandlink' + m.ongetinfo = 'getinfo' + m.ongetpagenumber = 'getpagenumber' m.onbeforedownloadimage='beforedownloadimage' return m end From 89f63d8b83dfcfe316fe3449e002adb42cef51d9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 07:59:10 +0300 Subject: [PATCH 2762/2794] Komikid, use https --- lua/modules/myReaderMangaCMS.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 660224e97..611740b74 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -156,7 +156,7 @@ function Init() AddWebsiteModule('MangAs', 'https://mang.as', c); c='Indonesian' - AddWebsiteModule('Komikid', 'http://www.komikid.com', c); + AddWebsiteModule('Komikid', 'https://www.komikid.com', c); AddWebsiteModule('KomikGue', 'https://www.komikgue.com', c); c='Raw' From d2589a29ce4868ae286d8e3aaea66545eda24bbf Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 08:11:59 +0300 Subject: [PATCH 2763/2794] FallenAngelsScans, fix cover link --- lua/modules/myReaderMangaCMS.lua | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 611740b74..e80e4599d 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -109,6 +109,21 @@ function Modules.MangaDenizi() return MangaDenizi end +function Modules.FallenAngelsScans() + local FallenAngelsScans = {} + setmetatable(FallenAngelsScans, { __index = Modules.myReaderMangaCMS() }) + + function FallenAngelsScans:getinfo() + Modules.myReaderMangaCMS().getinfo() + if mangainfo.coverLink:match('^//') ~= nil then + mangainfo.coverLink = 'https:' .. mangainfo.coverLink + end + end + + return FallenAngelsScans +end + + ------------------------------------------------------------------------------- function createInstance() @@ -170,7 +185,7 @@ function Init() AddWebsiteModule('MangaVadisi', 'http://manga-v2.mangavadisi.org', c); c='English-Scanlation' - AddWebsiteModule('FallenAngelsScans','http://manga.fascans.com', c); + AddWebsiteModule('FallenAngelsScans','https://manga.fascans.com', c); AddWebsiteModule('WhiteCloudPavilion','https://whitecloudpavilion.com', c); AddWebsiteModule('HatigarmScans', 'https://www.hatigarmscans.net', c) From f4de37b4143d5a9c3a0e8c8b20b49e78d9a9fb10 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 08:19:09 +0300 Subject: [PATCH 2764/2794] GodsRealmScan, fix --- lua/modules/myReaderMangaCMS.lua | 3 +-- lua/modules/rawdevart.lua | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index e80e4599d..fddce970f 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -190,9 +190,8 @@ function Init() AddWebsiteModule('HatigarmScans', 'https://www.hatigarmscans.net', c) c='Spanish-Scanlation' - AddWebsiteModule('DarkSkyScan', 'http://darkskyprojects.org', c); + AddWebsiteModule('DarkSkyScan', 'https://darkskyprojects.org', c); AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); - AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com', c); AddWebsiteModule('SOSScanlation', 'http://sosscanlation.com', c); diff --git a/lua/modules/rawdevart.lua b/lua/modules/rawdevart.lua index 71d021990..3dc722323 100644 --- a/lua/modules/rawdevart.lua +++ b/lua/modules/rawdevart.lua @@ -93,4 +93,7 @@ function Init() cat = 'H-Sites' AddWebsiteModule('ManhwaHentai', 'https://manhwahentai.com', cat) + + cat = 'Spanish-Scanlation' + AddWebsiteModule('GodsRealmScan', 'https://godsrealmscan.com', cat) end From 2c553556962d68e2b7d56b12931fea7217906b8b Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 08:23:29 +0300 Subject: [PATCH 2765/2794] remove ManhuaTr (doesn't work) --- lua/modules/myReaderMangaCMS.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index fddce970f..cda4b21ed 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -181,7 +181,6 @@ function Init() c='Turkish' AddWebsiteModule('MangaDenizi', 'http://www.mangadenizi.com', c); - AddWebsiteModule('ManhuaTr', 'http://manhua-tr.com', c); AddWebsiteModule('MangaVadisi', 'http://manga-v2.mangavadisi.org', c); c='English-Scanlation' @@ -193,7 +192,7 @@ function Init() AddWebsiteModule('DarkSkyScan', 'https://darkskyprojects.org', c); AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com', c); - AddWebsiteModule('SOSScanlation', 'http://sosscanlation.com', c); + AddWebsiteModule('SOSScanlation', 'https://sosscanlation.com', c); c='French' AddWebsiteModule('ScanFR', 'https://www.scan-fr.io', c); From f4b0f0cda5bebfffec79ad56f53417dcba3ab484 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 08:24:06 +0300 Subject: [PATCH 2766/2794] remove NozominoFansub (doesn't work) --- lua/modules/myReaderMangaCMS.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index cda4b21ed..23d02fbdf 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -190,7 +190,6 @@ function Init() c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'https://darkskyprojects.org', c); - AddWebsiteModule('NozominoFansub', 'https://nozominofansub.com', c); AddWebsiteModule('CoYuHi', 'http://www.universoyuri.com', c); AddWebsiteModule('SOSScanlation', 'https://sosscanlation.com', c); From 90d01268d502e8d6b14cd2b85bfaf5dad87f05c9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 08:33:49 +0300 Subject: [PATCH 2767/2794] KomikGue, fix closes #1619 --- lua/modules/myReaderMangaCMS.lua | 33 ++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 23d02fbdf..903324637 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -13,10 +13,10 @@ function Modules.myReaderMangaCMS() function myReaderMangaCMS:getinfo() mangainfo.url = MaybeFillHost(module.RootURL, url) if http.GET(mangainfo.url) then - x = TXQuery.Create(http.Document) + local x = TXQuery.Create(http.Document) mangainfo.coverLink = MaybeFillHost(module.RootURL, x.XPathString('//div[@class="boxed"]/img/@src')) if mangainfo.title == '' then - mangainfo.title = x.XPathString('//h2[contains(@class,"widget-title")]') + mangainfo.title = x.XPathString('//*[(self::h2 or self::h1) and contains(@class,"widget-title")]') if mangainfo.title == '' then mangainfo.title = mangainfo.url:match('/([^/]+)$') end @@ -26,9 +26,9 @@ function Modules.myReaderMangaCMS() mangainfo.artists = x.XPathStringAll('//dt[.=("Artist(s)","Artiste(s)")]/following-sibling::dd[1]/string-join(*,", ")') mangainfo.genres = x.XPathStringAll('//dt[.=("Categories","Kategoriler:","Categorías","Catégories")]/following-sibling::dd[1]/string-join(*,", ")') mangainfo.summary = x.XPathString('//div[@class="well"]/p') - v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') + local v = x.Xpath('//ul[@class="chapters"]/li/*[self::h5 or self::h3]') for i = 1, v.Count do - v2 = v.Get(i) + local v2 = v.Get(i) mangainfo.chapterLinks.Add(x.XPathString('a/@href', v2)) mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v2)) end @@ -41,7 +41,7 @@ function Modules.myReaderMangaCMS() function myReaderMangaCMS:getpagenumber() local u = MaybeFillHost(module.RootURL, url) if http.get(u) then - x = TXQuery.Create(http.document) + local x = TXQuery.Create(http.document) x.xpathstringall('//div[@id="all"]/img/@data-src', task.pagelinks) if task.pagelinks.Count == 0 then x.xpathstringall('//div[@id="all"]/img/@src', task.pagelinks) @@ -54,7 +54,7 @@ function Modules.myReaderMangaCMS() function myReaderMangaCMS:getnameandlink() if http.get(module.rooturl .. self.getdirurl()) then - x = TXQuery.create(http.document) + local x = TXQuery.create(http.document) x.xpathhrefall('//li/a', links, names) return no_error end @@ -123,6 +123,27 @@ function Modules.FallenAngelsScans() return FallenAngelsScans end +function Modules.KomikGue() + local KomikGue = {} + setmetatable(KomikGue, { __index = Modules.myReaderMangaCMS() }) + + function KomikGue:getinfo() + Modules.myReaderMangaCMS().getinfo() + local x=TXQuery.Create(http.document) + mangainfo.artists = x.XPathStringAll('//dt[.="Artist(s)"]/following-sibling::dd[1]') + mangainfo.summary = x.XPathString('//div[@class="well"]/div') + local v = x.xpath('//div[@class="chapter-wrapper"]/table//td[@class="chapter"]/a') + for i = 1, v.Count do + local v2 = v.Get(i) + mangainfo.chapterLinks.Add(v2.getAttribute('href')) + mangainfo.chapterNames.Add(x.XPathString('normalize-space(.)', v2)) + end + InvertStrings(mangainfo.chapterLinks, mangainfo.chapterNames) + end + + return KomikGue +end + ------------------------------------------------------------------------------- From 0f3e68f319844d297d5e06a9f2778b0bca74b9f9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 11:53:05 +0300 Subject: [PATCH 2768/2794] add OtakuFile [id] closes #1618 --- lua/modules/MangaShiro.lua | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lua/modules/MangaShiro.lua b/lua/modules/MangaShiro.lua index 5c271173b..ec24f03dd 100644 --- a/lua/modules/MangaShiro.lua +++ b/lua/modules/MangaShiro.lua @@ -297,6 +297,43 @@ function Modules.MangaID() return MangaID end +function Modules.OtakuFile() + local OtakuFile = {} + setmetatable(OtakuFile, { __index = Modules.MangaShiroBase() }) + + function OtakuFile:getinfo() + Modules.MangaShiroBase().getinfo() + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstring('//h1[@itemprop="name"]') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="imgdesc"]/a/img/@src')) + x.xpathhrefall('//div[@class="epl"]//li/span[1]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + end + + function OtakuFile:getpagenumber() + task.pagenumber=0 + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl,url)) then + TXQuery.Create(http.Document).xpathstringall('//*[@id="wrap"]/p//img/@src', task.pagelinks) + return true + end + end + + function OtakuFile:getnameandlink() + if http.get(module.rooturl .. self.getdirurl()) then + TXQuery.Create(http.document).xpathhrefall('//*[@class="anilist-diatur"]//a',links,names) + return no_error + end + return net_problem + end + + function OtakuFile:getdirurl() + return '/daftar-komik/' + end + + return OtakuFile +end + ------------------------------------------------------------------------------- function createInstance() @@ -346,4 +383,5 @@ function Init() AddWebsiteModule('MangaIndoNet', 'https://mangaindo.net') AddWebsiteModule('KomikIndo', 'https://komikindo.co') AddWebsiteModule('MangaID', 'https://mangaid.me') + AddWebsiteModule('OtakuFile', 'https://otakufile.com') end From be8e8961c7de9e91bb225d601de76d107220f7bd Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 12:18:17 +0300 Subject: [PATCH 2769/2794] add KissDoujin [H] --- baseunits/modules/KissManga.pas | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/baseunits/modules/KissManga.pas b/baseunits/modules/KissManga.pas index 7fa2fc27d..746dc60c3 100644 --- a/baseunits/modules/KissManga.pas +++ b/baseunits/modules/KissManga.pas @@ -14,6 +14,7 @@ implementation const kissmangadirurl = '/MangaList/Newest'; readcomiconlinedirurl = '/ComicList/Newest'; + kissdoujindirurl = '/HentaiList/NewDoujinshi'; var kissmangaiv: String ='a5e8e2e9c2721be0a84ad660c472c1f3'; @@ -45,7 +46,9 @@ function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; if Module.Website = 'KissManga' then s := s + kissmangadirurl else if Module.Website = 'ReadComicOnline' then - s := s + readcomiconlinedirurl; + s := s + readcomiconlinedirurl + else if Module.Website = 'KissDoujin' then + s := s + kissdoujindirurl; if GETWithCookie(MangaInfo.FHTTP, s, Module) then begin Result := NO_ERROR; with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do @@ -74,7 +77,9 @@ function GetNameAndLink(const MangaInfo: TMangaInformation; if Module.Website = 'KissManga' then s := s + kissmangadirurl else if Module.Website = 'ReadComicOnline' then - s := s + readcomiconlinedirurl; + s := s + readcomiconlinedirurl + else if Module.Website = 'KissDoujin' then + s := s + kissdoujindirurl; if AURL <> '0' then s := s + '?page=' + IncStr(AURL); if GETWithCookie(MangaInfo.FHTTP, s, Module) then begin @@ -115,9 +120,9 @@ function GetInfo(const MangaInfo: TMangaInformation; title := SeparateLeft(title, 'comic | Read'); end; end; - genres := SeparateRight(XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Genres:")]'), ':'); - authors := SeparateRight(XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Author:")]'), ':'); - artists := SeparateRight(XPathString('//div[@class="barContent"]/div/p[starts-with(.,"Artist:")]'), ':'); + genres := XPathStringAll('//div[@class="barContent"]//span[starts-with(., "Genre")]/parent::*/a'); + authors := XPathStringAll('//div[@class="barContent"]//span[starts-with(., "Author") or starts-with(., "Writer")]/parent::*/a'); + artists := XPathStringAll('//div[@class="barContent"]//span[starts-with(., "Artist")]/parent::*/a'); status := MangaInfoStatusIfPos(XPathString( '//div[@class="barContent"]/div/p[starts-with(.,"Status:")]'), 'Ongoing', @@ -131,7 +136,9 @@ function GetInfo(const MangaInfo: TMangaInformation; if RightStr(s, 7) = ' online' then SetLength(s, Length(s) - 7) else if RightStr(s, 29) = ' comic online in high quality' then - SetLength(s, Length(s) - 29); + SetLength(s, Length(s) - 29) + else if RightStr(s, 23) = ' online in high quality' then + SetLength(s, Length(s) - 23); chapterName.Add(s); end; InvertStrings([chapterLinks, chapterName]); @@ -285,14 +292,14 @@ function KissMangaGetPageNumber(const DownloadThread: TDownloadThread; procedure RegisterModule; - function AddWebsiteModule(AWebsite, ARootURL: String): TModuleContainer; + function AddWebsiteModule(AWebsite, ARootURL, ACategory: String): TModuleContainer; begin Result := AddModule; with Result do begin Website := AWebsite; RootURL := ARootURL; - Category := 'English'; + Category := ACategory; SortedList := True; OnGetDirectoryPageNumber := @GetDirectoryPageNumber; OnGetNameAndLink := @GetNameAndLink; @@ -302,14 +309,15 @@ procedure RegisterModule; end; begin - with AddWebsiteModule('KissManga', 'http://kissmanga.com') do + with AddWebsiteModule('KissManga', 'http://kissmanga.com', 'English') do begin OnGetPageNumber := @KissMangaGetPageNumber; AddOptionEdit(@kissmangakey,'Key',@RS_KissManga_Key); AddOptionEdit(@kissmangaiv,'IV',@RS_KissManga_InitVector); AddOptionCheckBox(@kissmangausegoogledcp,'UseGoogleDCP',@RS_KissManga_UseGoogleDCP); end; - AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.to'); + AddWebsiteModule('ReadComicOnline', 'http://readcomiconline.to', 'English'); + AddWebsiteModule('KissDoujin', 'http://kissdoujin.com', 'H-Sites'); end; initialization From 69b9307e7bf4b23aec30eed3b3188bc36b304d92 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 13:46:12 +0300 Subject: [PATCH 2770/2794] add 9hentai [H] closes #1621 --- lua/modules/9hentai.lua | 74 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 lua/modules/9hentai.lua diff --git a/lua/modules/9hentai.lua b/lua/modules/9hentai.lua new file mode 100644 index 000000000..a6301e2ad --- /dev/null +++ b/lua/modules/9hentai.lua @@ -0,0 +1,74 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.Document) + mangainfo.title=x.XPathString('css("div#info > h1")') + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//div[@id="cover"]//v-lazy-image/@src')) + mangainfo.artists = x.XPathStringAll('//section[@id="tags"]/div[contains(text(), "Artist")]//a') + mangainfo.genres = x.XPathStringAll('//section[@id="tags"]/div[contains(text(), "Tag")]//a') + mangainfo.chapterlinks.add(mangainfo.url) + mangainfo.chapternames.add(mangainfo.title) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + local id = url:match('g/(%d+)') + http.mimetype = 'application/json' + if http.post(module.rooturl..'/api/getBookByID', string.format('{"id":%s}', id)) then + local x=TXQuery.Create(http.Document) + local srv=x.xpathstring('json(*).results.image_server') + local pages=tonumber(x.xpathstring('json(*).results.total_page')) + for i = 1, pages do + task.pagelinks.add(string.format('%s%s/%d.jpg', srv, id, i)) + end + return true + else + return false + end +end + +query = '{"search":{"text":"","page":%s,"sort":0,"pages":{"range":[0,10000]},"tag":{"text":"","type":1,"tags":[],"items":{"included":[],"excluded":[]}}}}' + +function GetNameAndLink() + http.mimetype = 'application/json' + if http.post(module.rooturl..'/api/getBook', string.format(query, url)) then + local x=TXQuery.Create(http.Document) + local v = x.xpath('json(*).results()') + for i = 1, v.count do + local v1 = v.get(i) + links.add(string.format('%s/g/%s', module.rooturl, x.xpathstring('id', v1))) + names.add(x.xpathstring('title', v1)) + end + return no_error + else + return net_problem + end +end + +function getdirectorypagenumber() + http.mimetype = 'application/json' + if http.post(module.RootURL..'/api/getBook', string.format(query, '0')) then + local x = TXQuery.Create(http.Document) + page = tonumber(x.XPathString('json(*).total_count')) + if page == nil then page = 1 end + print(page) + return true + else + return false + end +end + +function Init() + m=NewModule() + m.category='H-Sites' + m.website='9hentai' + m.rooturl='https://9hentai.com' + m.sortedlist=true + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' + m.OnGetDirectoryPageNumber = 'getdirectorypagenumber' +end \ No newline at end of file From 2634550f76bc673bf6a56e72e1f51bc1273acd5c Mon Sep 17 00:00:00 2001 From: kmvi Date: Sat, 12 Jan 2019 13:53:15 +0300 Subject: [PATCH 2771/2794] remove MyMangaIO closes #1423 closes #1376 closes #1386 --- lua/modules/MyMangaIO.lua | 84 --------------------------------------- 1 file changed, 84 deletions(-) delete mode 100644 lua/modules/MyMangaIO.lua diff --git a/lua/modules/MyMangaIO.lua b/lua/modules/MyMangaIO.lua deleted file mode 100644 index b4d079c00..000000000 --- a/lua/modules/MyMangaIO.lua +++ /dev/null @@ -1,84 +0,0 @@ -local hitmanga = 'http://www.hitmanga.eu' -local hitmangalistener = 'http://www.hitmanga.eu/listener/' - -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(mangainfo.url) then - local s=TStrings.Create() - s.loadfromstream(http.document) - local str=string.gsub(s.text, '%-%-!>', '-->') - local x=TXQuery.Create(str) - mangainfo.title=x.xpathstring('//div[@id="picture"]//h2') - mangainfo.coverlink=MaybeFillHost(module.rooturl,x.xpathstring('//div[@id="picture"]/div/img/@src')) - mangainfo.authors=x.xpathstringall('//div[@id="mangafiche"]//table//tr[contains(th, "Auteur")]/td/a') - mangainfo.authors=x.xpathstringall('//div[@id="mangafiche"]//table//tr[contains(th, "Illustrateur")]/td/a') - mangainfo.genres=x.xpathstringall('//div[@id="mangafiche"]//table//tr[contains(th, "Genre")]/td/a') - mangainfo.status=MangaInfoStatusIfPos(x.xpathstring('//div[@id="mangafiche"]//table//tr[contains(th, "Statut")]/td/a'), 'cours', 'termin') - mangainfo.summary=x.xpathstring('//section[@id="synopsis"]/p') - v=x.xpath('//section[contains(@class, "listchapseries")]/ul/li') - for i=1,v.count do - v1=v.get(i) - mangainfo.chapterlinks.add(x.xpathstring('div/a[contains(i/@class, "fa-book")]/@href', v1)) - mangainfo.chapternames.add(x.xpathstring('p/span[@class="chapter"]', v1)) - end - InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) - return no_error - else - return net_problem - end -end - -function getpath(str) - local path = '' - local i = 1 - for l in string.gmatch(str, "[^/]*") do - if i == 6 then break end - path = path .. l .. '/' - i = i + 1 - end - return path -end - -function getpagenumber() - if http.get(MaybeFillHost(hitmanga,url)) then - local s=TStrings.Create() - s.loadfromstream(http.document) - local str=string.gsub(s.text, '%-%-!>', '-->') - local x=TXQuery.Create(str) - local link = x.xpathstring('//*[@id="loadReadPages"]/@data-permalink') - local num = x.xpathstring('//*[@id="loadReadPages"]/@data-number') - local src = getpath(x.xpathstring('//*[@id="chpimg"]/@src')) - local q = 'type=chap-pages&permalink='..link..'&number='..num - http.reset() - if http.post(hitmangalistener, q) then - local s = TStrings.Create() - s.loadfromstream(http.document) - for l in string.gmatch(s.text, "[^|]+") do - task.pagelinks.add(src .. string.gsub(l, '#', '%%23')) - end - return true - else - return false - end - return true - else - return false - end - return true -end - -function getnameandlink() - -- FIXME: manga directory shows only first 300 titles. - return no_error -end - -function Init() - m=NewModule() - m.category='French' - m.website='MyMangaIO' - m.rooturl='http://www.mymanga.io' - m.lastupdated='February 17, 2018' - m.ongetinfo='getinfo' - m.ongetpagenumber='getpagenumber' - m.ongetnameandlink='getnameandlink' -end From 6c9c2c6bd170685a451a60132ced1a158dcad356 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 13 Jan 2019 17:21:45 +0300 Subject: [PATCH 2772/2794] LHTranslation, fix list update --- lua/modules/LHTranslation.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/LHTranslation.lua b/lua/modules/LHTranslation.lua index 20480fd3c..553a50a7d 100644 --- a/lua/modules/LHTranslation.lua +++ b/lua/modules/LHTranslation.lua @@ -56,7 +56,7 @@ function GetNameAndLink() for i=1,v.count do local v1=v.get(i) links.add(module.rooturl..'/?cat='..v1.getattribute('value')) - names.add(v1.tostring) + names.add(Trim(v1.tostring:gsub('%(%d+%)%s*$', ''))) end return no_error else From 746abc112a7cefe0878f5dc6c9cd18cb9c4bdce4 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 13 Jan 2019 17:24:07 +0300 Subject: [PATCH 2773/2794] remove DigitalTeamAltervista --- lua/modules/DigitalTeamAltervista.lua | 77 --------------------------- 1 file changed, 77 deletions(-) delete mode 100644 lua/modules/DigitalTeamAltervista.lua diff --git a/lua/modules/DigitalTeamAltervista.lua b/lua/modules/DigitalTeamAltervista.lua deleted file mode 100644 index c20398ba7..000000000 --- a/lua/modules/DigitalTeamAltervista.lua +++ /dev/null @@ -1,77 +0,0 @@ -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(mangainfo.url) then - local x=TXQuery.Create(http.document) - if mangainfo.title == '' then - mangainfo.title = x.XPathString('//div[contains(@class, "nomob")]') - end - mangainfo.coverlink = MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="cover"]/img/@src')) - mangainfo.genres=x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Genere")]/span[@class="info_content"]') - mangainfo.authors=x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Autore")]/span[@class="info_content"]') - mangainfo.artists=x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Artista")]/span[@class="info_content"]') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="info"]/ul/li[contains(span[@class="info_name"], "Status")]/span[@class="info_content"]'), 'In corso', 'Completo') - mangainfo.summary = x.xpathstringall('//div[@class="plot"]/text()', '') - x.xpathhrefall('//div[@class="chapter_list"]/ul/li/div[@class="ch_top"]/a', mangainfo.chapterlinks, mangainfo.chapternames) - InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) - return no_error - else - return net_problem - end -end - -function urlencode(str) - if (str) then - str = string.gsub (str, "\n", "\r\n") - str = string.gsub (str, "([^%w ])", - function (c) return string.format ("%%%02X", string.byte(c)) end) - str = string.gsub (str, " ", "+") - end - return str -end - -function getpagenumber() - task.pagelinks.clear() - task.pagecontainerlinks.clear() - if not http.get(MaybeFillHost(module.rooturl, url)) then return false; end - local x=TXQuery.Create(http.Document) - local s = x.xpathstring('//script[contains(., "a_url")]') - local a_url = '/reader' - local m = GetBetween("m='", "'", s) - local ch = GetBetween("ch='", "'", s) - local chs = GetBetween("chs='", "'", s) - local title = urlencode(x.xpathstring('//title')) - local data = string.format("info%%5Bmanga%%5D=%s&info%%5Bchapter%%5D=%s&info%%5Bch_sub%%5D=%s&info%%5Btitle%%5D=%s", m, ch, chs, title) - http.reset() - if not http.post(module.rooturl .. a_url .. '/c_i', data) then return false; end - s = StreamToString(http.Document):gsub('\\"', '"'):gsub('^"', ''):gsub('"$', '') - x.parsehtml(s) - s = x.xpathstring('json(*)()[3]') - local cnt = x.xpathcount('json(*)()[1]()') - for i = 1, cnt do - local name = x.xpathstring('json(*)()[1]()['..i..']/name') .. x.xpathstring('json(*)()[2]()['..i..']') - local ex = x.xpathstring('json(*)()[1]()['..i..']/ex') - task.pagelinks.add(module.rooturl .. a_url .. s .. name .. ex) - end - return true -end - -function getnameandlink() - if http.GET(module.RootURL .. '/reader/series') then - local x = TXQuery.Create(http.Document) - x.xpathhrefall('//div[@class="manga_title"]/a', links, names) - return no_error - else - return net_problem - end -end - -function Init() - local m = NewModule() - m.website = 'DigitalTeamAltervista' - m.rooturl = 'http://digitalteam1.altervista.org' - m.category = 'Italian-Scanlation' - m.lastupdated='June 21, 2018' - m.ongetinfo='getinfo' - m.ongetpagenumber='getpagenumber' - m.ongetnameandlink='getnameandlink' -end From 2fb71340fe070e30ba575dec8e0ed6fb0f069251 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 13 Jan 2019 17:40:10 +0300 Subject: [PATCH 2774/2794] LeitorNet, fix download closes #1405 --- lua/modules/LeitorNet.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/modules/LeitorNet.lua b/lua/modules/LeitorNet.lua index 5082743c2..ab61c0213 100644 --- a/lua/modules/LeitorNet.lua +++ b/lua/modules/LeitorNet.lua @@ -4,7 +4,7 @@ function getinfo() x=TXQuery.Create(http.document) mangainfo.title=x.xpathstring('//*[@id="series-data"]//*[@class="series-title"]/h1') mangainfo.coverlink=x.xpathstring('//*[@id="series-data"]//img[@class="cover"]/@src') - mangainfo.authors=x.xpathstring('//*[@id="series-data"]//*[@class="series-author"]/text()') + mangainfo.authors=x.xpathstring('//*[@id="series-data"]//*[@class="series-author"]/normalize-space(text())') mangainfo.genres=x.xpathstringall('//*[@id="series-data"]//ul[contains(@class, "tags")]/li/a') if x.xpathstring('//*[@id="series-data"]//*[@class="complete-series"]') == '' then mangainfo.status = '1' @@ -54,7 +54,7 @@ function getpagenumber() s=x.xpathstring('//script[contains(@src, "token=")]/@src') local token = s:match('%?token=(%w+)&?') local id = s:match('&id_release=(%w+)&?') - if http.get(module.rooturl ..'/leitor/pages.json?key='..token..'&id_release='..id) then + if http.get(module.rooturl .. string.format('/leitor/pages/%s.json?key=%s', id, token)) then x=TXQuery.Create(http.Document) x.xpathstringall('json(*).images()', task.pagelinks) else From b36ef82b35d07550a0db6c683091acfe449ba1c0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Sun, 13 Jan 2019 17:42:25 +0300 Subject: [PATCH 2775/2794] remove MangaCow closes #1410 --- lua/modules/WPManga.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/lua/modules/WPManga.lua b/lua/modules/WPManga.lua index 1c1dea52f..d33e8a23c 100644 --- a/lua/modules/WPManga.lua +++ b/lua/modules/WPManga.lua @@ -199,9 +199,6 @@ function Init() AddWebsiteModule('ReadHentaiManga', 'http://readhentaimanga.com', cat) AddWebsiteModule('HentaiRead', 'http://hentairead.com', cat) - cat = 'English-Scanlation' - AddWebsiteModule('MangaCow', 'http://mngcow.co', cat) - cat = "Arabic-Scanlation" AddWebsiteModule('3asq', 'http://www.3asq.info', cat) end From 309e23277fe5ecf995fcf7ab23a8c171cb2169b8 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 Jan 2019 12:16:43 +0300 Subject: [PATCH 2776/2794] remove GoManga closes #1399 --- lua/modules/FoOlSlide.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 07f6eff7d..8cdff61da 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -25,7 +25,6 @@ end function getdirurl(website) local dirs = { - ['GoManga'] = dirurlreader, ['Jaiminisbox'] = dirurlreader, ['DokiFansubs'] = dirurlreader, ['AtelierDuNoir'] = dirurlreader, @@ -229,7 +228,6 @@ function Init() local cat = 'English-Scanlation' AddWebsiteModule('PowerManga', 'http://read.powermanga.org', cat) AddWebsiteModule('Shoujosense', 'http://reader.shoujosense.com', cat) - AddWebsiteModule('GoManga', 'http://gomanga.co', 'English') AddWebsiteModule('OneTimeScans', 'http://otscans.com', cat) AddWebsiteModule('SenseScans', 'http://reader.sensescans.com', cat) AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com', cat) From 3ce50cdaa03dd094d7a4e2e190fe76736d7f60c9 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 Jan 2019 12:18:28 +0300 Subject: [PATCH 2777/2794] remove GameofScanlation closes #1398 --- baseunits/ModuleList.inc | 1 - baseunits/modules/GameofScanlation.pas | 151 ------------------------- 2 files changed, 152 deletions(-) delete mode 100644 baseunits/modules/GameofScanlation.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 05e67d472..c02fe2d32 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -9,7 +9,6 @@ uses RawSenManga, KissManga, MangaHome, - GameofScanlation, Hakihome, MangaChanRU, MintMangaRU, diff --git a/baseunits/modules/GameofScanlation.pas b/baseunits/modules/GameofScanlation.pas deleted file mode 100644 index 290114874..000000000 --- a/baseunits/modules/GameofScanlation.pas +++ /dev/null @@ -1,151 +0,0 @@ -unit GameofScanlation; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, RegExpr, synautil; - -implementation - -const - dirurl = '/projects/'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="info"]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; - i, p: Integer; - s: String; - - procedure GetChapters; - begin - for v in query.XPath('//div[@class="list_press_text"]/p[@class="text_work"]/a') do begin - MangaInfo.mangaInfo.chapterLinks.Add(v.toNode.getAttribute('href')); - MangaInfo.mangaInfo.chapterName.Add(v.toString); - end; - end; - -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - url := AppendURLDelim(FillHost(Module.RootURL, AURL)); - if MangaInfo.FHTTP.GET(url) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create(Document); - try - if title = '' then title := query.XPathString('//div[@class="con"]/h2'); - summary := query.XPathString('//dd[@class="dsc"]'); - s := query.XPathString('//div[@class="con"]/dl/span[@class="aln"]'); - if s <> '' then begin - s := LowerCase(s); - if Pos('ongoing', s) > 0 then - status := '1' - else if Pos('completed', s) > 0 then - status := '0'; - end; - GetChapters; - p := StrToIntDef(query.XPathString('//nav/a[last()-1]'), 1); - if p > 1 then - for i := 2 to p do - if GET(AppendURLDelim(url) + 'page-' + IntToStr(i)) then begin - query.ParseHTML(Document); - GetChapters; - end; - InvertStrings([chapterLinks, chapterName]); - finally - query.Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - v: IXQValue; - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - s := ReplaceRegExpr('/\?\w+.*$', AURL, '/', False); - s := AppendURLDelim(FillHost(Module.RootURL, s)) + '?chapter_view=fullstrip'; - if DownloadThread.FHTTP.GET(s) then begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - for v in XPath('//div[@class="chapterPages"]//img/@src') do - begin - s := v.toString; - if SaveImageBase64StringToFile(s, - DownloadThread.Task.CurrentWorkingDir, - DownloadThread.Task.GetFileName(PageLinks.Count)) then - PageLinks.Add('D') - else - PageLinks.Add(MaybeFillHost(Module.RootURL, s)); - end; - finally - Free; - end; - end; - end; -end; - -function BeforeDownloadImage(const DownloadThread: TDownloadThread; - var AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - if CurrentDownloadChapterPtr < ChapterLinks.Count then begin - Headers.Values['Referer'] := ' ' + FillHost(Module.RootURL, ChapterLinks[CurrentDownloadChapterPtr]); - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'GameofScanlation'; - RootURL := 'https://gameofscanlation.moe'; - Category := 'English-Scanlation'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnBeforeDownloadImage := @BeforeDownloadImage; - end; -end; - -initialization - RegisterModule; - -end. From 550c7c98027c883a5cfd8e06faa77b8a682410f5 Mon Sep 17 00:00:00 2001 From: kmvi Date: Mon, 14 Jan 2019 12:19:31 +0300 Subject: [PATCH 2778/2794] remove EatManga closes #1397 --- baseunits/ModuleList.inc | 1 - baseunits/modules/EatManga.pas | 94 ---------------------------------- 2 files changed, 95 deletions(-) delete mode 100644 baseunits/modules/EatManga.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index c02fe2d32..63b2e9530 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -28,7 +28,6 @@ uses ReadMangaToday, MangaOnlineBR, Tapas, - EatManga, Taadd, NineManga, BlogTruyen, diff --git a/baseunits/modules/EatManga.pas b/baseunits/modules/EatManga.pas deleted file mode 100644 index 77ef0b037..000000000 --- a/baseunits/modules/EatManga.pas +++ /dev/null @@ -1,94 +0,0 @@ -unit EatManga; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML; - -implementation - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + '/Manga-Scan/') then - begin - Result := NO_ERROR; - XPathHREFAll('//li[@class="item-dr"]/div[1]/a', MangaInfo.FHTTP.Document, ALinks, ANames); - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do try - if title = '' then title := XPathString('//title/substring-before(.," Manga Releases - Read ")'); - XPathHREFAll('//ul[@id="updates"]/li[not(./div[2]/span[starts-with(.,"in ")])]/div[1]/a', chapterLinks, chapterName); - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - PageNumber := XPathCount('//select[@id="pages"]/option', Document); - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; const AURL: String; - const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - if GET(AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)) + 'page-' + IncStr(DownloadThread.WorkId)) then - begin - Result := True; - PageLinks[DownloadThread.WorkId] := XPathString('//img[contains(@id,"eatmanga_image")]/@src', Document); - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'EatManga'; - RootURL := 'http://eatmanga.me'; - Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. From 954a8524578afee13849f0abf49449c287450e06 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 Jan 2019 07:08:16 +0300 Subject: [PATCH 2779/2794] remove Hakihome closes #1400 --- baseunits/ModuleList.inc | 1 - baseunits/modules/Hakihome.pas | 173 --------------------------------- 2 files changed, 174 deletions(-) delete mode 100644 baseunits/modules/Hakihome.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index 63b2e9530..ada12c18f 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -9,7 +9,6 @@ uses RawSenManga, KissManga, MangaHome, - Hakihome, MangaChanRU, MintMangaRU, MangaHubRU, diff --git a/baseunits/modules/Hakihome.pas b/baseunits/modules/Hakihome.pas deleted file mode 100644 index 053280bef..000000000 --- a/baseunits/modules/Hakihome.pas +++ /dev/null @@ -1,173 +0,0 @@ -unit Hakihome; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; - -implementation - -const - dirurl = '/listmangahentai.html'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - s: String; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - s := query.XPathString('//*[@class="nav"]/li[last()-1]/a/@href'); - if s <> '' then Page := StrToIntDef(GetBetween('/pagel/', '/', s), 1); - finally - query.Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - s := Module.RootURL + dirurl; - if AURL <> '0' then s += '/pagel/' + IncStr(AURL) + '/'; - if MangaInfo.FHTTP.GET(s) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(MangaInfo.FHTTP.Document)); - for v in query.XPath('//table[@class="listing"]/tbody/tr/td[2]/a') do begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toString); - end; - finally - query.Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - query: TXQueryEngineHTML; - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.FHTTP, MangaInfo.mangaInfo do begin - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := NO_ERROR; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - coverLink := query.XPathString('//*[@class="noidung"]//img/@src'); - if title = '' then title := query.XPathString('//*[@class="tuade"]'); - artists := SeparateRight(query.XPathString('//*[@class="art lefts"]'), ':'); - genres := SeparateRight(query.XPathString('//*[@class="category lefts"]'), ':'); - AddCommaString(genres, SeparateRight(query.XPathString('//*[@class="tag"]'), ':')); - AddCommaString(genres, SeparateRight(query.XPathString('//*[@class="lan rights"]'), ':')); - for v in query.XPath('//table[@class="listing"]//a[@class="readchap"]') do begin - chapterLinks.Add(v.toNode.getAttribute('href')); - chapterName.Add(Trim(title + ' ' + v.toString)); - end; - if (chapterName.Count = 1) and (title <> '') then - chapterName[0] := title; - InvertStrings([chapterLinks, chapterName]); - finally - query.Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - s: String; - v: IXQValue; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.FHTTP, DownloadThread.Task.Container do begin - PageLinks.Clear; - PageNumber := 0; - Cookies.Values['ReadType'] := '2'; - if GET(FillHost(Module.RootURL, AURL)) then begin - Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageNumber := query.XPath('(//*[@id="topn"]/span/select)[last()]/option').Count; - s := query.XPathString('//*[@id="contentchap"]//script[contains(.,"var jsondata")]'); - if s <> '' then begin - s := Trim(GetBetween('=', ';', s)); - query.ParseHTML(s); - for v in query.XPath('json(*)()') do - PageLinks.Add(v.toString); - end; - finally - query.Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - query: TXQueryEngineHTML; - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do begin - s := AppendURLDelim(AURL) + IncStr(DownloadThread.WorkId) + '/'; - if GET(FillHost(Module.RootURL, s)) then begin - Result := True; - query := TXQueryEngineHTML.Create; - try - query.ParseHTML(StreamToString(Document)); - PageLinks[DownloadThread.WorkId] := query.XPathString('//*[@id="con"]//img/@src'); - finally - query.Free; - end; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'Hakihome'; - RootURL := 'http://hakihome.com'; - Category := 'H-Sites'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. From c0f15461fa3ab74a071895b544b4d32fb3d8fbe0 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 Jan 2019 09:00:47 +0300 Subject: [PATCH 2780/2794] add HolyManga [en] --- lua/modules/HeavenManga.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lua/modules/HeavenManga.lua b/lua/modules/HeavenManga.lua index 3d8db2ec3..15b5dce51 100644 --- a/lua/modules/HeavenManga.lua +++ b/lua/modules/HeavenManga.lua @@ -36,8 +36,8 @@ end function getpagenumber() task.pagelinks.clear() if http.get(MaybeFillHost(module.rooturl, url)) then - x=TXQuery.Create(http.Document) - v=x.xpathstringall('//div[@class="chapter-content"]//img/@src', task.pagelinks) + local x=TXQuery.Create(http.Document) + x.xpathstringall('//div[@class="chapter-content"]//img/@src', task.pagelinks) else return false end @@ -65,14 +65,19 @@ function getnameandlink() end end -function Init() +function AddWebsiteModule(name, url) local m = NewModule() - m.website = 'HeavenManga' - m.rooturl = 'https://heavenmanga.ca' + m.website = name + m.rooturl = url m.category = 'English' - m.lastupdated='February 26, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' m.ongetdirectorypagenumber = 'getdirectorypagenumber' + return m +end + +function Init() + AddWebsiteModule('HeavenManga', 'https://heavenmanga.ca') + AddWebsiteModule('HolyManga', 'http://holymanga.ca') end From 93390c57f23065d6891dbf986c76996e5b807c60 Mon Sep 17 00:00:00 2001 From: kmvi Date: Tue, 15 Jan 2019 09:09:32 +0300 Subject: [PATCH 2781/2794] rawdevart -> Madara --- lua/modules/{rawdevart.lua => Madara.lua} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lua/modules/{rawdevart.lua => Madara.lua} (100%) diff --git a/lua/modules/rawdevart.lua b/lua/modules/Madara.lua similarity index 100% rename from lua/modules/rawdevart.lua rename to lua/modules/Madara.lua From 005f041491399c28afd93e8c2c6ed7d40efd65c2 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 16 Jan 2019 07:24:39 +0300 Subject: [PATCH 2782/2794] Madara, refactoring --- lua/modules/Madara.lua | 144 +++++++++++++++++++++++++++-------------- 1 file changed, 94 insertions(+), 50 deletions(-) diff --git a/lua/modules/Madara.lua b/lua/modules/Madara.lua index 3dc722323..78291ae06 100644 --- a/lua/modules/Madara.lua +++ b/lua/modules/Madara.lua @@ -1,77 +1,121 @@ -function getinfo() - mangainfo.url=MaybeFillHost(module.RootURL, url) - if http.get(mangainfo.url) then - x=TXQuery.Create(http.document) - mangainfo.title=x.xpathstringall('//div[@class="post-title"]/*[self::h1 or self::h2 or self::h3]/text()', '') - if string.match(mangainfo.title:upper(), ' RAW$') ~= nil then - mangainfo.title = mangainfo.title:sub(1, -5) - end - mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@data-src') - if mangainfo.coverlink == '' then - mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@src') +Modules = {} + +function Modules.Madara() + local Madara = {} + + function Madara:new() + local obj = {} + setmetatable(obj, self) + self.__index = self + return obj + end + + function Madara:getinfo() + mangainfo.url=MaybeFillHost(module.RootURL, url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.document) + mangainfo.title=x.xpathstringall('//div[@class="post-title"]/*[self::h1 or self::h2 or self::h3]/text()', '') + if string.match(mangainfo.title:upper(), ' RAW$') ~= nil then + mangainfo.title = mangainfo.title:sub(1, -5) + end + mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@data-src') + if mangainfo.coverlink == '' then + mangainfo.coverlink=x.xpathstring('//div[@class="summary_image"]/a/img/@src') + end + mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') + mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') + mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="summary-heading" and contains(h5, "Status")]/following-sibling::div/div/a')) + mangainfo.summary=x.xpathstring('//div[contains(@class,"summary__content")]/*') + x.XPathHREFAll('//li[@class="wp-manga-chapter"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error end - mangainfo.authors=x.xpathstringall('//div[@class="author-content"]/a') - mangainfo.artists=x.xpathstringall('//div[@class="artist-content"]/a') - mangainfo.genres=x.xpathstringall('//div[@class="genres-content"]/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//div[@class="summary-heading" and contains(h5, "Status")]/following-sibling::div/div/a')) - mangainfo.summary=x.xpathstring('//div[contains(@class,"summary__content")]/p') - x.XPathHREFAll('//li[@class="wp-manga-chapter"]/a', mangainfo.chapterlinks, mangainfo.chapternames) - InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) - return no_error - else return net_problem end -end - -function getpagenumber() - task.pagelinks.clear() - local aurl = MaybeFillHost(module.rooturl, url) - if module.website == 'ChibiManga' then - if http.get(aurl) then - local x = TXQuery.Create(http.Document) - local s = x.xpathstring('//script[contains(., "chapter_preloaded_images")]', task.pagelinks) - s = "{"..GetBetween("{", "}", s).."}" - x.parsehtml(s) - x.xpathstringall('let $c := json(*) return for $k in jn:keys($c) return $c($k)', task.pagelinks) - else - return false - end - else + + function Madara:getpagenumber() + task.pagelinks.clear() + local aurl = MaybeFillHost(module.rooturl, url) if Pos('style=list', aurl) == 0 then aurl = aurl .. '?style=list' end if http.get(aurl) then local x = TXQuery.Create(http.Document) x.xpathstringall('//div[contains(@class, "page-break")]/img/@src', task.pagelinks) + return true + end + return false + end + + function Madara:getnameandlink() + local perpage = 100 + local q = 'action=madara_load_more&page='.. url ..'&template=madara-core%2Fcontent%2Fcontent-archive&vars%5Bpost_type%5D=wp-manga&vars%5Berror%5D=&vars%5Bm%5D=&vars%5Bp%5D=0&vars%5Bpost_parent%5D=&vars%5Bsubpost%5D=&vars%5Bsubpost_id%5D=&vars%5Battachment%5D=&vars%5Battachment_id%5D=0&vars%5Bname%5D=&vars%5Bstatic%5D=&vars%5Bpagename%5D=&vars%5Bpage_id%5D=0&vars%5Bsecond%5D=&vars%5Bminute%5D=&vars%5Bhour%5D=&vars%5Bday%5D=0&vars%5Bmonthnum%5D=0&vars%5Byear%5D=0&vars%5Bw%5D=0&vars%5Bcategory_name%5D=&vars%5Btag%5D=&vars%5Bcat%5D=&vars%5Btag_id%5D=&vars%5Bauthor%5D=&vars%5Bauthor_name%5D=&vars%5Bfeed%5D=&vars%5Btb%5D=&vars%5Bpaged%5D=1&vars%5Bmeta_key%5D=&vars%5Bmeta_value%5D=&vars%5Bpreview%5D=&vars%5Bs%5D=&vars%5Bsentence%5D=&vars%5Btitle%5D=&vars%5Bfields%5D=&vars%5Bmenu_order%5D=&vars%5Bembed%5D=&vars%5Bignore_sticky_posts%5D=false&vars%5Bsuppress_filters%5D=false&vars%5Bcache_results%5D=true&vars%5Bupdate_post_term_cache%5D=true&vars%5Blazy_load_term_meta%5D=true&vars%5Bupdate_post_meta_cache%5D=true&vars%5Bposts_per_page%5D='.. tostring(perpage) ..'&vars%5Bnopaging%5D=false&vars%5Bcomments_per_page%5D=50&vars%5Bno_found_rows%5D=false&vars%5Border%5D=ASC&vars%5Borderby%5D=post_title&vars%5Btemplate%5D=archive&vars%5Bsidebar%5D=full&vars%5Bpost_status%5D=publish' + if http.post(module.rooturl .. '/wp-admin/admin-ajax.php', q) then + if http.headers.values['Content-Length'] == '0' then return no_error end + local x = TXQuery.Create(http.Document) + if x.xpath('//div[contains(@class, "post-title")]/h5/a').count == 0 then return no_error end + x.XPathHREFAll('//div[contains(@class, "post-title")]/h5/a', links, names) + updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 + return no_error else - return false + return net_problem end end - return true + + return Madara end -local perpage = 100 +function Modules.ChibiManga() + local ChibiManga = {} + setmetatable(ChibiManga, { __index = Modules.Madara() }) + + function ChibiManga:getpagenumber() + task.pagelinks.clear() + if http.get(MaybeFillHost(module.rooturl, url)) then + local x = TXQuery.Create(http.Document) + local s = x.xpathstring('//script[contains(., "chapter_preloaded_images")]', task.pagelinks) + s = "{"..GetBetween("{", "}", s).."}" + x.parsehtml(s) + x.xpathstringall('let $c := json(*) return for $k in jn:keys($c) return $c($k)', task.pagelinks) + return true + end + return false + end + + return ChibiManga +end -function getnameandlink() - local q = 'action=madara_load_more&page='.. url ..'&template=madara-core%2Fcontent%2Fcontent-archive&vars%5Bpost_type%5D=wp-manga&vars%5Berror%5D=&vars%5Bm%5D=&vars%5Bp%5D=0&vars%5Bpost_parent%5D=&vars%5Bsubpost%5D=&vars%5Bsubpost_id%5D=&vars%5Battachment%5D=&vars%5Battachment_id%5D=0&vars%5Bname%5D=&vars%5Bstatic%5D=&vars%5Bpagename%5D=&vars%5Bpage_id%5D=0&vars%5Bsecond%5D=&vars%5Bminute%5D=&vars%5Bhour%5D=&vars%5Bday%5D=0&vars%5Bmonthnum%5D=0&vars%5Byear%5D=0&vars%5Bw%5D=0&vars%5Bcategory_name%5D=&vars%5Btag%5D=&vars%5Bcat%5D=&vars%5Btag_id%5D=&vars%5Bauthor%5D=&vars%5Bauthor_name%5D=&vars%5Bfeed%5D=&vars%5Btb%5D=&vars%5Bpaged%5D=1&vars%5Bmeta_key%5D=&vars%5Bmeta_value%5D=&vars%5Bpreview%5D=&vars%5Bs%5D=&vars%5Bsentence%5D=&vars%5Btitle%5D=&vars%5Bfields%5D=&vars%5Bmenu_order%5D=&vars%5Bembed%5D=&vars%5Bignore_sticky_posts%5D=false&vars%5Bsuppress_filters%5D=false&vars%5Bcache_results%5D=true&vars%5Bupdate_post_term_cache%5D=true&vars%5Blazy_load_term_meta%5D=true&vars%5Bupdate_post_meta_cache%5D=true&vars%5Bposts_per_page%5D='.. tostring(perpage) ..'&vars%5Bnopaging%5D=false&vars%5Bcomments_per_page%5D=50&vars%5Bno_found_rows%5D=false&vars%5Border%5D=ASC&vars%5Borderby%5D=post_title&vars%5Btemplate%5D=archive&vars%5Bsidebar%5D=full&vars%5Bpost_status%5D=publish' - if http.post(module.rooturl .. '/wp-admin/admin-ajax.php', q) then - if http.headers.values['Content-Length'] == '0' then return no_error end - x = TXQuery.Create(http.Document) - if x.xpath('//div[contains(@class, "post-title")]/h5/a').count == 0 then return no_error end - x.XPathHREFAll('//div[contains(@class, "post-title")]/h5/a', links, names) - updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 - return no_error +------------------------------------------------------------------------------- + +function createInstance() + local m = Modules[module.website] + if m ~= nil then + return m():new() else - return net_problem + return Modules.Madara():new() end end +------------------------------------------------------------------------------- + +function getinfo() + return createInstance():getinfo() +end + +function getpagenumber() + return createInstance():getpagenumber() +end + +function getnameandlink() + return createInstance():getnameandlink() +end + function AddWebsiteModule(name, url, category) local m = NewModule() m.website = name m.rooturl = url m.category = category - m.lastupdated = 'March 1, 2018' m.ongetinfo='getinfo' m.ongetpagenumber='getpagenumber' m.ongetnameandlink='getnameandlink' From cef1137ff8a320bc657f50e002ac28da6bb34070 Mon Sep 17 00:00:00 2001 From: kmvi Date: Wed, 16 Jan 2019 19:30:15 +0300 Subject: [PATCH 2783/2794] add WoweScans [en-sc] closes #1342 --- lua/modules/myReaderMangaCMS.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/modules/myReaderMangaCMS.lua b/lua/modules/myReaderMangaCMS.lua index 903324637..03a2d061e 100644 --- a/lua/modules/myReaderMangaCMS.lua +++ b/lua/modules/myReaderMangaCMS.lua @@ -208,6 +208,7 @@ function Init() AddWebsiteModule('FallenAngelsScans','https://manga.fascans.com', c); AddWebsiteModule('WhiteCloudPavilion','https://whitecloudpavilion.com', c); AddWebsiteModule('HatigarmScans', 'https://www.hatigarmscans.net', c) + AddWebsiteModule('WoweScans', 'https://wowescans.net', c) c='Spanish-Scanlation' AddWebsiteModule('DarkSkyScan', 'https://darkskyprojects.org', c); From 7e4fc6e64171ea59af6c5c8c2b6719c57cad0c6b Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 Jan 2019 07:13:24 +0300 Subject: [PATCH 2784/2794] remove DangoOnlineNoFansub (403 error) closes #1395 --- lua/modules/FoOlSlide.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 8cdff61da..e987744d8 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -267,7 +267,6 @@ function Init() -- es-sc cat = 'Spanish-Scanlation' - AddWebsiteModule('DangoOnlineNoFansub', 'http://lector.dangolinenofansub.com', cat) AddWebsiteModule('DejameProbar', 'http://dejameprobar.es', cat) AddWebsiteModule('HoshinoFansub', 'http://manga.animefrontline.com', cat) AddWebsiteModule('MenudoFansub', 'http://www.menudo-fansub.com', cat) From a8646bc6a5fb44d7aceaf6044944f8a607bfa5ba Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 Jan 2019 07:16:02 +0300 Subject: [PATCH 2785/2794] remove Comic-XXX, FreeAdultComix, AsianHotties closes #1394 closes #1392 --- baseunits/modules/WPAdultSiteSkins.pas | 3 --- 1 file changed, 3 deletions(-) diff --git a/baseunits/modules/WPAdultSiteSkins.pas b/baseunits/modules/WPAdultSiteSkins.pas index f94e51c79..c1c5ad894 100644 --- a/baseunits/modules/WPAdultSiteSkins.pas +++ b/baseunits/modules/WPAdultSiteSkins.pas @@ -154,9 +154,6 @@ procedure RegisterModule; end; begin AddWebsiteModule('PornComix', 'http://www.porncomix.info'); - AddWebsiteModule('Comic-XXX', 'http://comics-xxx.com'); - AddWebsiteModule('FreeAdultComix', 'http://freeadultcomix.com'); - AddWebsiteModule('AsianHotties', 'http://tits.asianhotties.me'); end; initialization From 19c03da74bb9525f996df062d1a3834c118b6625 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 Jan 2019 07:19:23 +0300 Subject: [PATCH 2786/2794] remove MangaSupa, MangaHereIO, MangaFoxCom does not work --- lua/modules/MangaKakalot.lua | 39 ++++++++---------------------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/lua/modules/MangaKakalot.lua b/lua/modules/MangaKakalot.lua index b4fa4c5f1..ec864a990 100644 --- a/lua/modules/MangaKakalot.lua +++ b/lua/modules/MangaKakalot.lua @@ -17,19 +17,11 @@ function getinfo() end mangainfo.url=u local x=TXQuery.Create(http.document) - if (Pos('mangasupa', u:lower()) > 0) or module.website == 'MangaFoxCom' or module.website == 'MangaHereIO' then - mangainfo.title=x.xpathstring('//h1[@class="entry-title"]') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//span[@class="info_image"]/img/@src')) - mangainfo.authors=x.xpathstringall('//ul[@class="truyen_info_right"]/li[contains(., "Author")]/a') - mangainfo.genres=x.xpathstringall('//ul[@class="truyen_info_right"]/li[contains(., "Genre")]/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="truyen_info_right"]/li[contains(., "Status")]')) - else - mangainfo.title=x.xpathstring('//ul[@class="manga-info-text"]/li/h1') - mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="manga-info-pic"]/img/@src')) - mangainfo.authors=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a') - mangainfo.genres=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a') - mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info-text"]/li[contains(., "Status")]')) - end + mangainfo.title=x.xpathstring('//ul[@class="manga-info-text"]/li/h1') + mangainfo.coverlink=MaybeFillHost(module.RootURL, x.xpathstring('//div[@class="manga-info-pic"]/img/@src')) + mangainfo.authors=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Author")]/a') + mangainfo.genres=x.xpathstringall('//ul[@class="manga-info-text"]/li[contains(., "Genre")]/a') + mangainfo.status = MangaInfoStatusIfPos(x.xpathstring('//ul[@class="manga-info-text"]/li[contains(., "Status")]')) if (Pos('email', mangainfo.title) > 0) and (Pos('protected', mangainfo.title) > 0) then mangainfo.title = Trim(x.xpathstring('//title/substring-after(substring-before(., "Manga Online"), "Read")')) end @@ -80,22 +72,11 @@ end local dirurl = '/manga_list?type=newest&category=all&state=all&page=' function getnameandlink() local dir = dirurl - if module.website == 'MangaFoxCom' or module.website == 'MangaHereIO' then - dir = '/manga-list?view=list&sort=date_added&page=' - end if http.get(module.rooturl .. dir .. IncStr(url)) then local x = TXQuery.Create(http.Document) - if module.website == 'MangaFoxCom' or module.website == 'MangaHereIO' then - local q = '//div[contains(@class,"wrap_update")]/div[@class="update_item"]/h3/a' - if x.xpathcount(q) > 0 then - x.XPathHREFAll(q, links, names) - updatelist.CurrentDirectoryPageNumber = updatelist.CurrentDirectoryPageNumber + 1 - end - else - x.XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', links, names) - if links.count == 0 then - x.XPathHREFAll('//div[contains(@class,"danh_sach")]/div[contains(@class,"list_category")]/h3/a', links, names) - end + x.XPathHREFAll('//div[@class="truyen-list"]/div[@class="list-truyen-item-wrap"]/h3/a', links, names) + if links.count == 0 then + x.XPathHREFAll('//div[contains(@class,"danh_sach")]/div[contains(@class,"list_category")]/h3/a', links, names) end return no_error else @@ -105,7 +86,6 @@ end function getdirectorypagenumber() page = 1 - if module.website == 'MangaFoxCom' then return true; end if http.GET(module.RootURL .. dirurl .. '1') then x = TXQuery.Create(http.Document) local s = x.xpathstring('//div[@class="group-page"]/a[contains(., "Last")]/@href') @@ -137,7 +117,4 @@ end function Init() AddWebsiteModule('MangaKakalot', 'http://mangakakalot.com') AddWebsiteModule('MangaNelo', 'http://manganelo.com') - AddWebsiteModule('MangaSupa', 'http://mangasupa.com') - AddWebsiteModule('MangaHereIO', 'https://manga-here.io') - AddWebsiteModule('MangaFoxCom', 'https://manga-fox.com') end From 86c701fbc4c24c6e7227498308e9d9b7a175fd88 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 Jan 2019 07:21:35 +0300 Subject: [PATCH 2787/2794] remove WhiteoutScans --- lua/modules/FoOlSlide.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index e987744d8..9ce614369 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -233,7 +233,6 @@ function Init() AddWebsiteModule('Jaiminisbox', 'https://jaiminisbox.com', cat) AddWebsiteModule('KireiCake', 'https://reader.kireicake.com', cat) AddWebsiteModule('HelveticaScans', 'http://helveticascans.com', cat) - AddWebsiteModule('WhiteoutScans', 'http://reader.whiteoutscans.com', cat) AddWebsiteModule('DokiFansubs', 'https://kobato.hologfx.com', cat) AddWebsiteModule('AtelierDuNoir', 'http://atelierdunoir.org', cat) AddWebsiteModule('WorldThree', 'http://www.slide.world-three.org', cat) From 6a8735d6cd8efc2a8a0d566eb074ce7196ea2353 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 Jan 2019 07:24:17 +0300 Subject: [PATCH 2788/2794] remove MyMangaMe closes #1499 --- baseunits/ModuleList.inc | 1 - baseunits/modules/MyMangaMe.pas | 161 -------------------------------- 2 files changed, 162 deletions(-) delete mode 100644 baseunits/modules/MyMangaMe.pas diff --git a/baseunits/ModuleList.inc b/baseunits/ModuleList.inc index ada12c18f..a20acb166 100644 --- a/baseunits/ModuleList.inc +++ b/baseunits/ModuleList.inc @@ -21,7 +21,6 @@ uses MangaInn, LeoManga, MangaIndo, - MyMangaMe, GoodManga, MangaZuki, ReadMangaToday, diff --git a/baseunits/modules/MyMangaMe.pas b/baseunits/modules/MyMangaMe.pas deleted file mode 100644 index be903a3ed..000000000 --- a/baseunits/modules/MyMangaMe.pas +++ /dev/null @@ -1,161 +0,0 @@ -unit MyMangaMe; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread; - -implementation - -const - dirurl = '/manga-directory/'; - -function GetDirectoryPageNumber(const MangaInfo: TMangaInformation; - var Page: Integer; const WorkPtr: Integer; const Module: TModuleContainer): Integer; -begin - Result := NET_PROBLEM; - Page := 1; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - Page := StrToIntDef(XPathString('//script[contains(.,"totalPages")]/substring-before(substring-after(.,"totalPages: "),",")'), 1); - finally - Free; - end; - end; -end; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - s := Module.RootURL + dirurl; - if AURL <> '0' then - s := s + 'all/az/' + IncStr(AURL); - if MangaInfo.FHTTP.GET(s) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//div[@class="manga-hover-wrapper"]/a') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(XPathString('div[@class="manga-details directory"]', v)); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; - s: String; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//div[@class="manga-cover"]//img/@src')); - if title = '' then title := XPathString('//h1'); - v := XPath('//div[@class="manga-data"]'); - authors := XPathString('b[starts-with(.,"Author:")]/following-sibling::text()[1]', v); - artists := XPathString('b[starts-with(.,"Artist:")]/following-sibling::text()[1]', v); - genres := XPathString('b[starts-with(.,"Genre:")]/string-join(following-sibling::a[preceding::b[1][starts-with(.,"Genre:")]],", ")', v); - status := MangaInfoStatusIfPos(XPathString( - 'b[starts-with(.,"Status:")]/following-sibling::text()[1]', v), - 'Ongoing', - 'Completed'); - summary := XPathStringAll('b[starts-with(.,"Sypnosis:")]/following-sibling::text()[preceding::b[1][[starts-with(.,"Sypnosis:")]]]', LineEnding, v); - for v in XPath('//section[@class="section-chapter"]/div/div[@class="row"]//a') do - begin - s := v.toNode.getAttribute('href'); - if RightStr(s, 2) = '/1' then - SetLength(s, Length(s) - 2); - chapterLinks.Add(s); - chapterName.Add(v.toString); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread.FHTTP do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL) + '/1') then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('(//select[@id="page-dropdown"])[1]/option').Count; - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread.Task.Container, DownloadThread, FHTTP do - if GET(MaybeFillHost(Module.RootURL, AURL) + '/' + IncStr(WorkId)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[WorkId] := XPathString('//script[contains(.,"my_image0.src")]/substring-before(substring-after(.,"my_image0.src = ''"),"'';")'); - finally - Free; - end; - end; -end; - -procedure RegisterModule; -begin - with AddModule do - begin - Website := 'MyMangaMe'; - RootURL := 'http://mymanga.me'; - Category := 'English'; - OnGetDirectoryPageNumber := @GetDirectoryPageNumber; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - end; -end; - -initialization - RegisterModule; - -end. From 9ec6c7d805ecc50428d39ad19e735a8e6fefd123 Mon Sep 17 00:00:00 2001 From: kmvi Date: Thu, 17 Jan 2019 09:33:46 +0300 Subject: [PATCH 2789/2794] JapScan, fix chapter list fixes #1627 --- lua/modules/JapScan.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/modules/JapScan.lua b/lua/modules/JapScan.lua index 3f8037902..bb941538f 100644 --- a/lua/modules/JapScan.lua +++ b/lua/modules/JapScan.lua @@ -17,7 +17,7 @@ function getinfo() mangainfo.artists=x.xpathstringall('//div[@id="main"]//p[contains(span, "Artiste")]/text()', '') mangainfo.genres=x.xpathstringall('//div[@id="main"]//p[contains(span, "Type(s)")]/text()', '') mangainfo.summary=x.xpathstring('//div[@id="main"]//div[contains(text(), "Synopsis")]/following-sibling::*') - x.xpathhrefall('//div[@id="chapters_list"]//div[@class="chapters_list"]/a', mangainfo.chapterlinks, mangainfo.chapternames) + x.xpathhrefall('css("div#chapters_list div.chapters_list > a")', mangainfo.chapterlinks, mangainfo.chapternames) InvertStrings(mangainfo.chapterlinks, mangainfo.chapternames) return no_error else From f7344e381a7f18a1fb4f6f869ffc1c8f98b6d7bb Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 18 Jan 2019 06:30:53 +0300 Subject: [PATCH 2790/2794] remove JSUnpack --- baseunits/JSUnpack.pas | 90 ------------------------------------------ 1 file changed, 90 deletions(-) delete mode 100644 baseunits/JSUnpack.pas diff --git a/baseunits/JSUnpack.pas b/baseunits/JSUnpack.pas deleted file mode 100644 index c62fafd54..000000000 --- a/baseunits/JSUnpack.pas +++ /dev/null @@ -1,90 +0,0 @@ -unit JSUnpack; - -{$mode objfpc}{$H+} - -interface - -uses - Classes, SysUtils, fgl, RegExpr, math; - -type - TStringMap = specialize TFPGMap; - TJSUnpack36 = class - FDict: TStringMap; - function Encode36(code: Integer): String; - function GetIdentifier(c, a: Integer): String; - function Replace(ARegExpr : TRegExpr): String; - public - constructor Create; - destructor Destroy; override; - function Unpack(text: String; a, c: Integer; words: TStringArray): String; - end; - -implementation - -const - lookup36 = '0123456789abcdefghijklmnopqrstuvwxyz'; - -function TJSUnpack36.Encode36(code: Integer): String; -var - digit: Integer; - i: Integer = 0; -begin - Result := ''; - repeat - digit := (code div Trunc(power(36, i))) mod 36; - Result := Char(lookup36[digit + 1]) + Result; - code -= digit * Trunc(power(36, i)); - Inc(i); - until code <= 0; -end; - -constructor TJSUnpack36.Create; -begin - inherited; - FDict := TStringMap.Create; -end; - -destructor TJSUnpack36.Destroy; -begin - FDict.Free; - inherited; -end; - -function TJSUnpack36.GetIdentifier(c, a: Integer): String; -begin - if c < a then Result := '' - else Result := GetIdentifier(c div a, a); - c := c mod a; - if c > 35 then Result += Chr(Byte(c + 29)) - else Result += Encode36(c); -end; - -function TJSUnpack36.Replace(ARegExpr : TRegExpr): String; -var - s: String; -begin - Result := ARegExpr.Match[0]; - if FDict.TryGetData(ARegExpr.Match[0], s) and (s <> '') then - Result := s; -end; - -function TJSUnpack36.Unpack(text: String; a, c: Integer; words: TStringArray): String; -var - rg: TRegExpr; -begin - FDict.Clear; - rg := TRegExpr.Create('\b\w+\b'); - try - while c <> 0 do begin - Dec(c); - FDict.Add(GetIdentifier(c, a), words[c]); - end; - Result := rg.Replace(text, @Replace); - finally - rg.Free; - end; -end; - -end. - From 8ca9a0fdb6b2c70b0e7a6eec0c866740131fbf0e Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 18 Jan 2019 06:31:39 +0300 Subject: [PATCH 2791/2794] MangaFox, fix getting page links --- baseunits/modules/MangaFox.pas | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/baseunits/modules/MangaFox.pas b/baseunits/modules/MangaFox.pas index b9a863a50..67b7b0ee6 100644 --- a/baseunits/modules/MangaFox.pas +++ b/baseunits/modules/MangaFox.pas @@ -96,7 +96,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String cid := Trim(ReplaceString(GetBetween('chapterid', ';', s), '=', '')); PageNumber := StrToIntDef(Trim(ReplaceString(GetBetween('imagecount', ';', s), '=', '')), 0); page := 1; - while (PageLinks.Count < PageNumber) and (page <= PageNumber) do begin + while page <= PageNumber do begin Reset; Headers.Values['Pragma'] := 'no-cache'; Headers.Values['Cache-Control'] := 'no-cache'; @@ -105,7 +105,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String if XHR(MaybeFillHost(Module.RootURL, AURL) + s) then begin s := Trim(StreamToString(Document)); if s <> '' then begin - s := ExecJS(s); + s := ExecJS(s + ';d;'); lst := TStringList.Create; try lst.CommaText := s; @@ -116,6 +116,7 @@ function GetPageNumber(const DownloadThread: TDownloadThread; const AURL: String end; end; end; + if PageLinks.Count >= PageNumber then Break; Inc(page); Sleep(3000); end; end; From 8ccf7b1c00ae2c74fefcb34d4c9a360e6c328a58 Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 18 Jan 2019 06:33:41 +0300 Subject: [PATCH 2792/2794] MangaHere, rewrite fixes #1636 --- baseunits/modules/MangaHere.pas | 129 +------------------------------- lua/modules/MangaHere.lua | 93 +++++++++++++++++++++++ 2 files changed, 94 insertions(+), 128 deletions(-) create mode 100644 lua/modules/MangaHere.lua diff --git a/baseunits/modules/MangaHere.pas b/baseunits/modules/MangaHere.pas index 4d64ca0f0..eaa16f6bd 100644 --- a/baseunits/modules/MangaHere.pas +++ b/baseunits/modules/MangaHere.pas @@ -5,131 +5,10 @@ interface uses - Classes, SysUtils, WebsiteModules, uData, uBaseUnit, uDownloadsManager, - XQueryEngineHTML, httpsendthread, synautil; + Classes, SysUtils, WebsiteModules; implementation -const - dirurl = '/mangalist/'; - imagepath = '//*[@id="viewer"]//img[@id="image"]/@src'; - -function GetNameAndLink(const MangaInfo: TMangaInformation; - const ANames, ALinks: TStringList; const AURL: String; - const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - Result := NET_PROBLEM; - if MangaInfo.FHTTP.GET(Module.RootURL + dirurl) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(MangaInfo.FHTTP.Document) do - try - for v in XPath('//a[@class="manga_info"]') do - begin - ALinks.Add(v.toNode.getAttribute('href')); - ANames.Add(v.toNode.getAttribute('rel')); - end; - finally - Free; - end; - end; -end; - -function GetInfo(const MangaInfo: TMangaInformation; - const AURL: String; const Module: TModuleContainer): Integer; -var - v: IXQValue; -begin - Result := NET_PROBLEM; - if MangaInfo = nil then Exit(UNKNOWN_ERROR); - with MangaInfo.mangaInfo, MangaInfo.FHTTP do - begin - url := MaybeFillHost(Module.RootURL, AURL); - if GET(url) then - begin - Result := NO_ERROR; - with TXQueryEngineHTML.Create(Document) do - try - coverLink := MaybeFillHost(Module.RootURL, XPathString('//*[@class="manga_detail"]//img[@class="img"]/@src')); - if title = '' then title := XPathString('//meta[@property="og:title"]/@content'); - authors := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Author")]'), ':'); - artists := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Artist")]'), ':'); - genres := SeparateRight(XPathString('//*[@class="detail_topText"]/li[starts-with(.,"Genre")]'), ':'); - status := MangaInfoStatusIfPos(XPathString( - '//*[@class="detail_topText"]/li[starts-with(.,"Status")]'), - 'Ongoing', - 'Completed'); - summary := XPathString('//*[@class="detail_topText"]/li/p[@id="show"]/text()'); - for v in XPath('//*[@class="detail_list"]/ul/li/span[@class="left"]') do - begin - chapterLinks.Add(XPathString('a/@href', v)); - chapterName.Add(XPathString('string-join((a,span,text()[3])," ")', v)); - end; - InvertStrings([chapterLinks, chapterName]); - finally - Free; - end; - end; - end; -end; - -function GetPageNumber(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread, FHTTP, Task.Container do - begin - PageLinks.Clear; - PageNumber := 0; - if GET(MaybeFillHost(Module.RootURL, AURL)) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageNumber := XPath('(//span[@class="right"]/select)[1]/option[not(.="Featured")]').Count; - PageLinks.Add(XPathString(imagepath)); - finally - Free; - end; - end; - end; -end; - -function GetImageURL(const DownloadThread: TDownloadThread; - const AURL: String; const Module: TModuleContainer): Boolean; -var - s: String; -begin - Result := False; - if DownloadThread = nil then Exit; - with DownloadThread, FHTTP, Task.Container do - begin - if (WorkId = PageLinks.Count - 1) and (Pos('/featured.', AURL) <> 0) then - begin - PageLinks.Delete(WorkId); - Exit; - end; - - s := AppendURLDelim(MaybeFillHost(Module.RootURL, AURL)); - if WorkId > 0 then - s := s + IncStr(WorkId) + '.html'; - if GET(s) then - begin - Result := True; - with TXQueryEngineHTML.Create(Document) do - try - PageLinks[WorkId] := XPathString(imagepath); - finally - Free; - end; - end; - end; -end; - procedure RegisterModule; begin with AddModule do @@ -137,12 +16,6 @@ procedure RegisterModule; Website := 'MangaHere'; RootURL := 'http://www.mangahere.cc'; Category := 'English'; - OnGetNameAndLink := @GetNameAndLink; - OnGetInfo := @GetInfo; - OnGetPageNumber := @GetPageNumber; - OnGetImageURL := @GetImageURL; - MaxConnectionLimit := 1; - MaxTaskLimit := 1; end; end; diff --git a/lua/modules/MangaHere.lua b/lua/modules/MangaHere.lua new file mode 100644 index 000000000..003393f32 --- /dev/null +++ b/lua/modules/MangaHere.lua @@ -0,0 +1,93 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + http.cookies.values['isAdult'] = '1' + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.Document) + if mangainfo.title == '' then + mangainfo.title=x.XPathString('//span[@class="detail-info-right-title-font"]') + end + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('//img[@class="detail-info-cover-img"]/@src')) + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('css("table.table-borderless")//tr[th="Status"]/td')) + mangainfo.authors = x.XPathString('//p[@class="detail-info-right-say"]/a') + mangainfo.genres = x.XPathStringAll('//p[@class="detail-info-right-tag-list"]/a') + mangainfo.summary = x.XPathString('//p[@class="fullcontent"]') + mangainfo.status = MangaInfoStatusIfPos(x.XPathString('//span[@class="detail-info-right-title-tip"]')) + local v=x.xpath('//ul[@class="detail-main-list"]/li/a') + for i=1, v.count do + local v1=v.get(i) + mangainfo.chapterlinks.add(v1.getAttribute('href'):gsub('1%.html', '')) + mangainfo.chapternames.add(x.xpathstring('./div/p[@class="title3"]', v1)) + end + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber = 0 + http.cookies.values['isAdult'] = '1' + local aurl = MaybeFillHost(module.rooturl, url) .. '1.html' + if http.get(aurl) then + local x=TXQuery.Create(http.Document) + local s = x.XPathString('//script[contains(., "eval")]') + s = 'var $=function(){return{val:function(){}}},newImgs,guidkey;' .. s + s = s .. ';newImgs||guidkey;' + local key = ExecJS(s) + if string.len(key) > 16 then + task.pagelinks.commatext = key + else + s = x.XPathString('//script[contains(., "chapterid")]'); + local cid = Trim(GetBetween('chapterid', ';', s):gsub('=', '')) + task.pagenumber = tonumber(Trim(GetBetween('imagecount', ';', s):gsub('=', ''))) + if task.pagenumber == nil then task.pagenumber = 1 end + local page = 1 + while page <= task.pagenumber do + http.reset() + http.headers.values['Pragma'] = 'no-cache' + http.headers.values['Cache-Control'] = 'no-cache' + http.headers.values['Referer'] = aurl + s = string.format('chapterfun.ashx?cid=%s&page=%d&key=%s', cid, page, key) + if http.xhr(MaybeFillHost(module.rooturl, url) .. s) then + s = Trim(StreamToString(http.document)) + if s ~= '' then + s = ExecJS(s .. ';d;') + local lst = TStrings.Create() + lst.commatext = s + if page > 1 then lst.delete(0) end + task.pagelinks.addtext(lst.text) + lst = nil + end + end + if task.pagelinks.count >= task.pagenumber then break end + page = page + 1 + Sleep(3000) + end + end + return true + else + return false + end +end + +function GetNameAndLink() + if http.get(module.rooturl..'/mangalist/') then + local x=TXQuery.Create(http.Document) + x.xpathhrefall('css(".browse-new-block > .browse-new-block-content > a")', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='English' + m.website='MangaHere' + m.rooturl='https://www.mangahere.cc' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' +end From 19f8dc922d55fc98a87b3dec14d10728982ba6da Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 18 Jan 2019 07:44:10 +0300 Subject: [PATCH 2793/2794] DigitalTeam, rewrite closes #1629 --- lua/modules/DigitalTeam.lua | 76 +++++++++++++++++++++++++++++++++++++ lua/modules/FoOlSlide.lua | 3 -- 2 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 lua/modules/DigitalTeam.lua diff --git a/lua/modules/DigitalTeam.lua b/lua/modules/DigitalTeam.lua new file mode 100644 index 000000000..e9159531b --- /dev/null +++ b/lua/modules/DigitalTeam.lua @@ -0,0 +1,76 @@ +function GetInfo() + mangainfo.url=MaybeFillHost(module.rooturl,url) + if http.get(mangainfo.url) then + local x=TXQuery.Create(http.Document) + if mangainfo.title == '' then + mangainfo.title=x.XPathString('css("div.title")') + end + mangainfo.coverLink=MaybeFillHost(module.rooturl, x.XPathString('css(".cover > img")/@src')) + local status = x.XPathString('//li[@class="info_block" and contains(span, "Status")]/span[@class="info_content"]') + mangainfo.status = MangaInfoStatusIfPos(status, "In corso", "Completo") + mangainfo.authors = x.XPathString('//li[@class="info_block" and contains(span, "Autore")]/span[@class="info_content"]') + mangainfo.artists = x.XPathString('//li[@class="info_block" and contains(span, "Artista")]/span[@class="info_content"]') + mangainfo.genres = x.XPathString('//li[@class="info_block" and contains(span, "Genere")]/span[@class="info_content"]') + mangainfo.summary = x.XPathString('//div[@class="plot"]') + x.xpathhrefall('css("div.chapter_list > ul > li > .ch_top > a")', mangainfo.chapterlinks, mangainfo.chapternames) + InvertStrings(mangainfo.chapterlinks,mangainfo.chapternames) + return no_error + else + return net_problem + end +end + +function GetPageNumber() + task.pagelinks.clear() + task.pagenumber = 0 + if http.get(MaybeFillHost(module.rooturl, url)) then + local x=TXQuery.Create(http.Document) + local title=x.xpathstring('//title') + local s=x.xpathstring('//script[contains(., "current_page")]') + s=ExecJS(s .. ';JSON.stringify({m:m,ch:ch,chs:chs});') + x.parsehtml(s) + local m=x.xpathstring('json(*).m') + local ch=x.xpathstring('json(*).ch') + local chs=x.xpathstring('json(*).chs') + local data=EncodeURL(string.format('info[manga]=%s&info[chapter]=%s&info[ch_sub]=%s&info[title]=%s', m, ch, chs, title)) + http.reset() + if http.post(MaybeFillHost(module.rooturl, '/reader/c_i'), data) then + x.parsehtml(ExecJS(StreamToString(http.document))) + local path = x.xpathstring('json(*)()[3]') + local v=x.xpath('json(*)()[2]()') + local t={} + for i = 1, v.count do + local v1 = v.get(i) + table.insert(t, v1.toString) + end + v=x.xpath('json(*)()[1]()') + for i = 1, v.count do + local v1=v.get(i) + s = string.format('/reader/%s/%s', path, x.xpathstring('./name', v1)..t[i]..x.xpathstring('./ex', v1)) + task.pagelinks.add(MaybeFillHost(module.rooturl, s)) + end + return true + end + end + return false +end + +function GetNameAndLink() + if http.get(module.rooturl..'/reader/series') then + local x=TXQuery.Create(http.Document) + x.xpathhrefall('css(".manga_title > a")', links, names) + return no_error + else + return net_problem + end +end + +function Init() + m=NewModule() + m.category='Italian-Scanlation' + m.website='DigitalTeam' + m.rooturl='https://dgtread.com' + m.ongetinfo='GetInfo' + m.ongetpagenumber='GetPageNumber' + m.ongetnameandlink='GetNameAndLink' +end diff --git a/lua/modules/FoOlSlide.lua b/lua/modules/FoOlSlide.lua index 9ce614369..830510ce7 100644 --- a/lua/modules/FoOlSlide.lua +++ b/lua/modules/FoOlSlide.lua @@ -261,9 +261,6 @@ function Init() AddWebsiteModule('EvilFlowers', 'http://reader.evilflowers.com', cat) AddWebsiteModule('IlluminatiManga', 'http://reader.manga-download.org', cat) - cat = 'Italian-Scanlation' - AddWebsiteModule('DigitalTeam', 'http://digitalteamreader.netsons.org', cat) - -- es-sc cat = 'Spanish-Scanlation' AddWebsiteModule('DejameProbar', 'http://dejameprobar.es', cat) From 04f9d021fedab3e2b5222aeca650301b3946881f Mon Sep 17 00:00:00 2001 From: kmvi Date: Fri, 18 Jan 2019 09:27:19 +0300 Subject: [PATCH 2794/2794] DigitalTeam, add external sources fixes #1637 --- lua/modules/DigitalTeam.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lua/modules/DigitalTeam.lua b/lua/modules/DigitalTeam.lua index e9159531b..2b7846925 100644 --- a/lua/modules/DigitalTeam.lua +++ b/lua/modules/DigitalTeam.lua @@ -25,6 +25,7 @@ function GetPageNumber() task.pagenumber = 0 if http.get(MaybeFillHost(module.rooturl, url)) then local x=TXQuery.Create(http.Document) + local isExt = (x.xpathstring('//script[contains(@src, "rext.js")]/@src') ~= '') local title=x.xpathstring('//title') local s=x.xpathstring('//script[contains(., "current_page")]') s=ExecJS(s .. ';JSON.stringify({m:m,ch:ch,chs:chs});') @@ -32,9 +33,10 @@ function GetPageNumber() local m=x.xpathstring('json(*).m') local ch=x.xpathstring('json(*).ch') local chs=x.xpathstring('json(*).chs') - local data=EncodeURL(string.format('info[manga]=%s&info[chapter]=%s&info[ch_sub]=%s&info[title]=%s', m, ch, chs, title)) + local data=string.format('info[manga]=%s&info[chapter]=%s&info[ch_sub]=%s&info[title]=%s', m, ch, chs, title) + if isExt then data = data .. '&info[external]=1' end http.reset() - if http.post(MaybeFillHost(module.rooturl, '/reader/c_i'), data) then + if http.post(MaybeFillHost(module.rooturl, '/reader/c_i'), EncodeURL(data)) then x.parsehtml(ExecJS(StreamToString(http.document))) local path = x.xpathstring('json(*)()[3]') local v=x.xpath('json(*)()[2]()') @@ -46,7 +48,11 @@ function GetPageNumber() v=x.xpath('json(*)()[1]()') for i = 1, v.count do local v1=v.get(i) - s = string.format('/reader/%s/%s', path, x.xpathstring('./name', v1)..t[i]..x.xpathstring('./ex', v1)) + if isExt then + s = string.format('%s/%s%s', t[i], x.xpathstring('./name', v1), x.xpathstring('./ex', v1)) + else + s = string.format('/reader/%s/%s%s%s', path, x.xpathstring('./name', v1), t[i], x.xpathstring('./ex', v1)) + end task.pagelinks.add(MaybeFillHost(module.rooturl, s)) end return true